summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/obsolete/dv13949
-rw-r--r--Documentation/ABI/removed/dv139414
-rw-r--r--Documentation/ABI/removed/raw139415
-rw-r--r--Documentation/ABI/removed/raw1394_legacy_isochronous16
-rw-r--r--Documentation/ABI/removed/video139416
-rw-r--r--Documentation/ABI/testing/sysfs-devices-system-ibm-rtl22
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra98
-rw-r--r--Documentation/DocBook/80211.tmpl495
-rw-r--r--Documentation/DocBook/Makefile2
-rw-r--r--Documentation/DocBook/device-drivers.tmpl5
-rw-r--r--Documentation/DocBook/kernel-api.tmpl6
-rw-r--r--Documentation/DocBook/mac80211.tmpl337
-rw-r--r--Documentation/accounting/getdelays.c38
-rw-r--r--Documentation/arm/SA1100/FreeBird4
-rw-r--r--Documentation/cgroups/cgroups.txt14
-rw-r--r--Documentation/fb/viafb.txt48
-rw-r--r--Documentation/feature-removal-schedule.txt46
-rw-r--r--Documentation/filesystems/9p.txt4
-rw-r--r--Documentation/filesystems/Locking31
-rw-r--r--Documentation/filesystems/ext4.txt14
-rw-r--r--Documentation/filesystems/nfs/00-INDEX4
-rw-r--r--Documentation/filesystems/nfs/idmapper.txt67
-rw-r--r--Documentation/filesystems/nfs/nfsroot.txt22
-rw-r--r--Documentation/filesystems/nfs/pnfs.txt48
-rw-r--r--Documentation/filesystems/proc.txt57
-rw-r--r--Documentation/filesystems/sharedsubtree.txt4
-rw-r--r--Documentation/hwmon/ltc426163
-rw-r--r--Documentation/input/ntrig.txt126
-rw-r--r--Documentation/kernel-parameters.txt17
-rw-r--r--Documentation/kvm/api.txt61
-rw-r--r--Documentation/kvm/ppc-pv.txt196
-rw-r--r--Documentation/kvm/timekeeping.txt612
-rw-r--r--Documentation/misc-devices/apds990x.txt111
-rw-r--r--Documentation/misc-devices/bh1770glc.txt116
-rw-r--r--Documentation/networking/bonding.txt8
-rw-r--r--Documentation/networking/can.txt12
-rw-r--r--Documentation/networking/dccp.txt29
-rw-r--r--Documentation/networking/ip-sysctl.txt27
-rw-r--r--Documentation/networking/phonet.txt56
-rw-r--r--Documentation/networking/phy.txt18
-rw-r--r--Documentation/networking/timestamping.txt22
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt82
-rw-r--r--Documentation/sound/alsa/HD-Audio.txt8
-rw-r--r--Documentation/sysctl/vm.txt12
-rw-r--r--Documentation/sysrq.txt7
-rw-r--r--Documentation/timers/hpet_example.c27
-rw-r--r--Documentation/trace/postprocess/trace-vmscan-postprocess.pl39
-rw-r--r--Documentation/vm/highmem.txt162
-rw-r--r--Documentation/vm/numa_memory_policy.txt2
-rw-r--r--Kbuild1
-rw-r--r--MAINTAINERS228
-rw-r--r--arch/alpha/Kconfig3
-rw-r--r--arch/alpha/include/asm/core_mcpcia.h2
-rw-r--r--arch/alpha/include/asm/core_t2.h54
-rw-r--r--arch/alpha/include/asm/pgtable.h2
-rw-r--r--arch/alpha/kernel/core_t2.c11
-rw-r--r--arch/alpha/kernel/machvec_impl.h3
-rw-r--r--arch/alpha/kernel/pci_iommu.c4
-rw-r--r--arch/alpha/kernel/ptrace.c7
-rw-r--r--arch/arm/Kconfig5
-rw-r--r--arch/arm/common/icst.c2
-rw-r--r--arch/arm/common/scoop.c12
-rw-r--r--arch/arm/common/uengine.c18
-rw-r--r--arch/arm/configs/da8xx_omapl_defconfig3
-rw-r--r--arch/arm/configs/n8x0_defconfig94
-rw-r--r--arch/arm/configs/omap2plus_defconfig (renamed from arch/arm/configs/omap3_defconfig)51
-rw-r--r--arch/arm/configs/omap_4430sdp_defconfig125
-rw-r--r--arch/arm/configs/omap_generic_2420_defconfig37
-rw-r--r--arch/arm/configs/pcontrol_g20_defconfig175
-rw-r--r--arch/arm/include/asm/hardware/icst.h2
-rw-r--r--arch/arm/include/asm/highmem.h6
-rw-r--r--arch/arm/include/asm/pgtable.h14
-rw-r--r--arch/arm/kernel/ptrace.c28
-rw-r--r--arch/arm/mach-at91/Kconfig12
-rw-r--r--arch/arm/mach-at91/Makefile13
-rw-r--r--arch/arm/mach-at91/at91sam9260.c7
-rw-r--r--arch/arm/mach-at91/at91sam9261.c7
-rw-r--r--arch/arm/mach-at91/at91sam9263.c7
-rw-r--r--arch/arm/mach-at91/at91sam9_alt_reset.S48
-rw-r--r--arch/arm/mach-at91/at91sam9g45_devices.c165
-rw-r--r--arch/arm/mach-at91/at91sam9rl.c7
-rw-r--r--arch/arm/mach-at91/board-pcontrol-g20.c322
-rw-r--r--arch/arm/mach-at91/board-sam9m10g45ek.c24
-rw-r--r--arch/arm/mach-at91/generic.h3
-rw-r--r--arch/arm/mach-at91/pm.c15
-rw-r--r--arch/arm/mach-at91/pm.h5
-rw-r--r--arch/arm/mach-at91/pm_slowclock.S1
-rw-r--r--arch/arm/mach-davinci/Kconfig76
-rw-r--r--arch/arm/mach-davinci/Makefile4
-rw-r--r--arch/arm/mach-davinci/aemif.c133
-rw-r--r--arch/arm/mach-davinci/board-da830-evm.c24
-rw-r--r--arch/arm/mach-davinci/board-da850-evm.c92
-rw-r--r--arch/arm/mach-davinci/board-dm365-evm.c11
-rw-r--r--arch/arm/mach-davinci/board-dm644x-evm.c20
-rw-r--r--arch/arm/mach-davinci/board-dm646x-evm.c21
-rw-r--r--arch/arm/mach-davinci/board-mityomapl138.c422
-rw-r--r--arch/arm/mach-davinci/board-neuros-osd2.c7
-rw-r--r--arch/arm/mach-davinci/board-omapl138-hawk.c62
-rw-r--r--arch/arm/mach-davinci/board-sffsdr.c7
-rw-r--r--arch/arm/mach-davinci/board-tnetv107x-evm.c56
-rw-r--r--arch/arm/mach-davinci/clock.c75
-rw-r--r--arch/arm/mach-davinci/clock.h5
-rw-r--r--arch/arm/mach-davinci/cpufreq.c28
-rw-r--r--arch/arm/mach-davinci/da850.c76
-rw-r--r--arch/arm/mach-davinci/devices-da8xx.c70
-rw-r--r--arch/arm/mach-davinci/devices-tnetv107x.c50
-rw-r--r--arch/arm/mach-davinci/devices.c15
-rw-r--r--arch/arm/mach-davinci/dm365.c23
-rw-r--r--arch/arm/mach-davinci/dm644x.c23
-rw-r--r--arch/arm/mach-davinci/dm646x.c22
-rw-r--r--arch/arm/mach-davinci/dma.c8
-rw-r--r--arch/arm/mach-davinci/include/mach/aemif.h36
-rw-r--r--arch/arm/mach-davinci/include/mach/da8xx.h7
-rw-r--r--arch/arm/mach-davinci/include/mach/dm365.h2
-rw-r--r--arch/arm/mach-davinci/include/mach/dm644x.h2
-rw-r--r--arch/arm/mach-davinci/include/mach/dm646x.h2
-rw-r--r--arch/arm/mach-davinci/include/mach/nand.h6
-rw-r--r--arch/arm/mach-davinci/include/mach/psc.h1
-rw-r--r--arch/arm/mach-davinci/include/mach/tnetv107x.h3
-rw-r--r--arch/arm/mach-davinci/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-davinci/tnetv107x.c11
-rw-r--r--arch/arm/mach-ep93xx/clock.c3
-rw-r--r--arch/arm/mach-ep93xx/core.c40
-rw-r--r--arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h1
-rw-r--r--arch/arm/mach-ep93xx/include/mach/platform.h1
-rw-r--r--arch/arm/mach-ep93xx/simone.c1
-rw-r--r--arch/arm/mach-imx/include/mach/dma-v1.h8
-rw-r--r--arch/arm/mach-kirkwood/common.c6
-rw-r--r--arch/arm/mach-kirkwood/netspace_v2-setup.c43
-rw-r--r--arch/arm/mach-omap1/Kconfig2
-rw-r--r--arch/arm/mach-omap1/Makefile2
-rw-r--r--arch/arm/mach-omap1/board-ams-delta.c69
-rw-r--r--arch/arm/mach-omap1/board-h2-mmc.c3
-rw-r--r--arch/arm/mach-omap1/board-h3-mmc.c3
-rw-r--r--arch/arm/mach-omap1/board-htcherald.c321
-rw-r--r--arch/arm/mach-omap1/board-sx1-mmc.c3
-rw-r--r--arch/arm/mach-omap1/devices.c96
-rw-r--r--arch/arm/mach-omap1/include/mach/camera.h11
-rw-r--r--arch/arm/mach-omap1/pm_bus.c98
-rw-r--r--arch/arm/mach-omap2/Kconfig54
-rw-r--r--arch/arm/mach-omap2/Makefile28
-rw-r--r--arch/arm/mach-omap2/board-2430sdp.c3
-rw-r--r--arch/arm/mach-omap2/board-3430sdp.c12
-rw-r--r--arch/arm/mach-omap2/board-3630sdp.c3
-rw-r--r--arch/arm/mach-omap2/board-4430sdp.c87
-rw-r--r--arch/arm/mach-omap2/board-am3517evm.c38
-rw-r--r--arch/arm/mach-omap2/board-apollon.c2
-rw-r--r--arch/arm/mach-omap2/board-cm-t35.c9
-rw-r--r--arch/arm/mach-omap2/board-cm-t3517.c292
-rw-r--r--arch/arm/mach-omap2/board-devkit8000.c7
-rw-r--r--arch/arm/mach-omap2/board-flash.c3
-rw-r--r--arch/arm/mach-omap2/board-flash.h (renamed from arch/arm/mach-omap2/include/mach/board-flash.h)2
-rw-r--r--arch/arm/mach-omap2/board-generic.c16
-rw-r--r--arch/arm/mach-omap2/board-h4.c2
-rw-r--r--arch/arm/mach-omap2/board-igep0020.c369
-rw-r--r--arch/arm/mach-omap2/board-igep0030.c400
-rw-r--r--arch/arm/mach-omap2/board-ldp.c8
-rw-r--r--arch/arm/mach-omap2/board-n8x0.c65
-rw-r--r--arch/arm/mach-omap2/board-omap3beagle.c106
-rw-r--r--arch/arm/mach-omap2/board-omap3evm.c9
-rw-r--r--arch/arm/mach-omap2/board-omap3logic.c241
-rw-r--r--arch/arm/mach-omap2/board-omap3pandora.c55
-rw-r--r--arch/arm/mach-omap2/board-omap3stalker.c9
-rw-r--r--arch/arm/mach-omap2/board-omap3touchbook.c7
-rw-r--r--arch/arm/mach-omap2/board-omap4panda.c109
-rw-r--r--arch/arm/mach-omap2/board-overo.c5
-rw-r--r--arch/arm/mach-omap2/board-rx51-peripherals.c33
-rw-r--r--arch/arm/mach-omap2/board-rx51-sdram.c2
-rw-r--r--arch/arm/mach-omap2/board-rx51-video.c2
-rw-r--r--arch/arm/mach-omap2/board-zoom-debugboard.c2
-rw-r--r--arch/arm/mach-omap2/board-zoom-peripherals.c74
-rw-r--r--arch/arm/mach-omap2/board-zoom2.c37
-rw-r--r--arch/arm/mach-omap2/board-zoom3.c1
-rw-r--r--arch/arm/mach-omap2/clock.c2
-rw-r--r--arch/arm/mach-omap2/clock2420_data.c42
-rw-r--r--arch/arm/mach-omap2/clock2430_data.c66
-rw-r--r--arch/arm/mach-omap2/clock3xxx_data.c36
-rw-r--r--arch/arm/mach-omap2/clock44xx_data.c1312
-rw-r--r--arch/arm/mach-omap2/clockdomain.c110
-rw-r--r--arch/arm/mach-omap2/cm-regbits-34xx.h2
-rw-r--r--arch/arm/mach-omap2/cm-regbits-44xx.h1287
-rw-r--r--arch/arm/mach-omap2/cm44xx.h90
-rw-r--r--arch/arm/mach-omap2/cm4xxx.c9
-rw-r--r--arch/arm/mach-omap2/common.c135
-rw-r--r--arch/arm/mach-omap2/control.c33
-rw-r--r--arch/arm/mach-omap2/control.h (renamed from arch/arm/plat-omap/include/plat/control.h)49
-rw-r--r--arch/arm/mach-omap2/cpuidle34xx.c58
-rw-r--r--arch/arm/mach-omap2/devices.c237
-rw-r--r--arch/arm/mach-omap2/gpmc-smsc911x.c113
-rw-r--r--arch/arm/mach-omap2/hsmmc.c92
-rw-r--r--arch/arm/mach-omap2/hsmmc.h5
-rw-r--r--arch/arm/mach-omap2/id.c115
-rw-r--r--arch/arm/mach-omap2/include/mach/board-rx51.h11
-rw-r--r--arch/arm/mach-omap2/include/mach/board-zoom.h6
-rw-r--r--arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h391
-rw-r--r--arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h1409
-rw-r--r--arch/arm/mach-omap2/include/mach/ctrl_module_pad_wkup_44xx.h236
-rw-r--r--arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h92
-rw-r--r--arch/arm/mach-omap2/io.c8
-rw-r--r--arch/arm/mach-omap2/io.h7
-rw-r--r--arch/arm/mach-omap2/irq.c1
-rw-r--r--arch/arm/mach-omap2/mailbox.c8
-rw-r--r--arch/arm/mach-omap2/mcbsp.c105
-rw-r--r--arch/arm/mach-omap2/mux.c23
-rw-r--r--arch/arm/mach-omap2/mux.h2
-rw-r--r--arch/arm/mach-omap2/mux2420.c2
-rw-r--r--arch/arm/mach-omap2/mux2430.c2
-rw-r--r--arch/arm/mach-omap2/mux34xx.c12
-rw-r--r--arch/arm/mach-omap2/omap4-common.c10
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c599
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2420_data.c257
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2430_data.c257
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_3xxx_data.c319
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_44xx_data.c850
-rw-r--r--arch/arm/mach-omap2/pm-debug.c44
-rw-r--r--arch/arm/mach-omap2/pm.c75
-rw-r--r--arch/arm/mach-omap2/pm.h11
-rw-r--r--arch/arm/mach-omap2/pm24xx.c4
-rw-r--r--arch/arm/mach-omap2/pm34xx.c126
-rw-r--r--arch/arm/mach-omap2/pm_bus.c85
-rw-r--r--arch/arm/mach-omap2/powerdomains44xx.h2
-rw-r--r--arch/arm/mach-omap2/prcm-common.h5
-rw-r--r--arch/arm/mach-omap2/prcm.c33
-rw-r--r--arch/arm/mach-omap2/prm-regbits-34xx.h1
-rw-r--r--arch/arm/mach-omap2/prm-regbits-44xx.h1314
-rw-r--r--arch/arm/mach-omap2/prm.h18
-rw-r--r--arch/arm/mach-omap2/prm2xxx_3xxx.c110
-rw-r--r--arch/arm/mach-omap2/prm44xx.c116
-rw-r--r--arch/arm/mach-omap2/prm44xx.h14
-rw-r--r--arch/arm/mach-omap2/serial.c578
-rw-r--r--arch/arm/mach-omap2/sleep34xx.S2
-rw-r--r--arch/arm/mach-omap2/sram34xx.S6
-rw-r--r--arch/arm/mach-omap2/timer-gp.c8
-rw-r--r--arch/arm/mach-omap2/timer-gp.h (renamed from arch/arm/plat-omap/include/plat/timer-gp.h)3
-rw-r--r--arch/arm/mach-omap2/usb-fs.c6
-rw-r--r--arch/arm/mach-pxa/devices.c25
-rw-r--r--arch/arm/mach-pxa/devices.h6
-rw-r--r--arch/arm/mach-pxa/pxa27x.c4
-rw-r--r--arch/arm/mach-pxa/pxa3xx.c5
-rw-r--r--arch/arm/mach-pxa/zylonite.c11
-rw-r--r--arch/arm/mach-s3c2440/mach-at2440evb.c2
-rw-r--r--arch/arm/mach-s3c64xx/dev-audio.c20
-rw-r--r--arch/arm/mach-s3c64xx/mach-smdk6410.c1
-rw-r--r--arch/arm/mach-sa1100/Kconfig6
-rw-r--r--arch/arm/mach-sa1100/cpu-sa1100.c2
-rw-r--r--arch/arm/mach-tegra/Kconfig11
-rw-r--r--arch/arm/mach-tegra/Makefile9
-rw-r--r--arch/arm/mach-tegra/board-harmony-pcie.c57
-rw-r--r--arch/arm/mach-tegra/board.h1
-rw-r--r--arch/arm/mach-tegra/clock.c267
-rw-r--r--arch/arm/mach-tegra/clock.h58
-rw-r--r--arch/arm/mach-tegra/common.c13
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c185
-rw-r--r--arch/arm/mach-tegra/dma.c752
-rw-r--r--arch/arm/mach-tegra/fuse.c84
-rw-r--r--arch/arm/mach-tegra/fuse.h24
-rw-r--r--arch/arm/mach-tegra/gpio.c104
-rw-r--r--arch/arm/mach-tegra/include/mach/clk.h5
-rw-r--r--arch/arm/mach-tegra/include/mach/dma.h155
-rw-r--r--arch/arm/mach-tegra/include/mach/gpio.h4
-rw-r--r--arch/arm/mach-tegra/include/mach/hardware.h4
-rw-r--r--arch/arm/mach-tegra/include/mach/io.h18
-rw-r--r--arch/arm/mach-tegra/include/mach/iomap.h33
-rw-r--r--arch/arm/mach-tegra/include/mach/irqs.h2
-rw-r--r--arch/arm/mach-tegra/include/mach/legacy_irq.h31
-rw-r--r--arch/arm/mach-tegra/include/mach/pinmux-t2.h174
-rw-r--r--arch/arm/mach-tegra/include/mach/pinmux.h210
-rw-r--r--arch/arm/mach-tegra/io.c6
-rw-r--r--arch/arm/mach-tegra/irq.c137
-rw-r--r--arch/arm/mach-tegra/legacy_irq.c114
-rw-r--r--arch/arm/mach-tegra/pcie.c915
-rw-r--r--arch/arm/mach-tegra/pinmux-t2-tables.c260
-rw-r--r--arch/arm/mach-tegra/pinmux.c354
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c826
-rw-r--r--arch/arm/mach-tegra/tegra2_dvfs.c86
-rw-r--r--arch/arm/mach-tegra/tegra2_dvfs.h20
-rw-r--r--arch/arm/mach-tegra/timer.c1
-rw-r--r--arch/arm/mach-ux500/board-mop500.c129
-rw-r--r--arch/arm/mach-ux500/clock.c1
-rw-r--r--arch/arm/mach-ux500/devices-db8500.c33
-rw-r--r--arch/arm/mach-ux500/include/mach/devices.h1
-rw-r--r--arch/arm/mach-ux500/pins-db8500.h32
-rw-r--r--arch/arm/mm/fault-armv.c4
-rw-r--r--arch/arm/mm/highmem.c24
-rw-r--r--arch/arm/mm/pgd.c4
-rw-r--r--arch/arm/nwfpe/milieu.h4
-rw-r--r--arch/arm/nwfpe/softfloat-macros4
-rw-r--r--arch/arm/nwfpe/softfloat-specialize4
-rw-r--r--arch/arm/nwfpe/softfloat.c4
-rw-r--r--arch/arm/nwfpe/softfloat.h4
-rw-r--r--arch/arm/plat-mxc/include/mach/dma.h67
-rw-r--r--arch/arm/plat-mxc/include/mach/sdma.h17
-rw-r--r--arch/arm/plat-nomadik/include/plat/ske.h50
-rw-r--r--arch/arm/plat-nomadik/include/plat/ste_dma40.h135
-rw-r--r--arch/arm/plat-omap/Kconfig2
-rw-r--r--arch/arm/plat-omap/Makefile4
-rw-r--r--arch/arm/plat-omap/clock.c5
-rw-r--r--arch/arm/plat-omap/common.c290
-rw-r--r--arch/arm/plat-omap/counter_32k.c183
-rw-r--r--arch/arm/plat-omap/cpu-omap.c4
-rw-r--r--arch/arm/plat-omap/devices.c42
-rw-r--r--arch/arm/plat-omap/dma.c50
-rw-r--r--arch/arm/plat-omap/dmtimer.c2
-rw-r--r--arch/arm/plat-omap/fb.c16
-rw-r--r--arch/arm/plat-omap/fb.h10
-rw-r--r--arch/arm/plat-omap/gpio.c10
-rw-r--r--arch/arm/plat-omap/include/plat/common.h5
-rw-r--r--arch/arm/plat-omap/include/plat/cpu.h41
-rw-r--r--arch/arm/plat-omap/include/plat/display.h31
-rw-r--r--arch/arm/plat-omap/include/plat/dma.h6
-rw-r--r--arch/arm/plat-omap/include/plat/dmtimer.h2
-rw-r--r--arch/arm/plat-omap/include/plat/gpmc-smsc911x.h35
-rw-r--r--arch/arm/plat-omap/include/plat/i2c.h4
-rw-r--r--arch/arm/plat-omap/include/plat/irqs.h2
-rw-r--r--arch/arm/plat-omap/include/plat/mcbsp.h29
-rw-r--r--arch/arm/plat-omap/include/plat/mmc.h12
-rw-r--r--arch/arm/plat-omap/include/plat/omap-serial.h128
-rw-r--r--arch/arm/plat-omap/include/plat/omap24xx.h2
-rw-r--r--arch/arm/plat-omap/include/plat/omap4-keypad.h14
-rw-r--r--arch/arm/plat-omap/include/plat/omap_device.h4
-rw-r--r--arch/arm/plat-omap/include/plat/omap_hwmod.h62
-rw-r--r--arch/arm/plat-omap/include/plat/powerdomain.h2
-rw-r--r--arch/arm/plat-omap/include/plat/prcm.h2
-rw-r--r--arch/arm/plat-omap/include/plat/sdrc.h1
-rw-r--r--arch/arm/plat-omap/include/plat/sram.h1
-rw-r--r--arch/arm/plat-omap/include/plat/uncompress.h5
-rw-r--r--arch/arm/plat-omap/include/plat/usb.h2
-rw-r--r--arch/arm/plat-omap/include/plat/vrfb.h16
-rw-r--r--arch/arm/plat-omap/mcbsp.c26
-rw-r--r--arch/arm/plat-omap/omap_device.c110
-rw-r--r--arch/arm/plat-omap/sram.c37
-rw-r--r--arch/arm/plat-omap/sram.h6
-rw-r--r--arch/arm/plat-s3c24xx/devs.c34
-rw-r--r--arch/arm/plat-samsung/include/plat/adc.h2
-rw-r--r--arch/arm/plat-samsung/include/plat/devs.h2
-rw-r--r--arch/avr32/Kconfig2
-rw-r--r--arch/avr32/include/asm/pgtable.h2
-rw-r--r--arch/avr32/kernel/ptrace.c11
-rw-r--r--arch/blackfin/Kconfig.debug11
-rw-r--r--arch/blackfin/configs/BF518F-EZBRD_defconfig2
-rw-r--r--arch/blackfin/configs/BF526-EZBRD_defconfig2
-rw-r--r--arch/blackfin/configs/BF527-AD7160-EVAL_defconfig2
-rw-r--r--arch/blackfin/configs/BF527-EZKIT-V2_defconfig3
-rw-r--r--arch/blackfin/configs/BF527-EZKIT_defconfig3
-rw-r--r--arch/blackfin/configs/BF527-TLL6527M_defconfig1
-rw-r--r--arch/blackfin/configs/BF533-EZKIT_defconfig2
-rw-r--r--arch/blackfin/configs/BF533-STAMP_defconfig2
-rw-r--r--arch/blackfin/configs/BF537-STAMP_defconfig3
-rw-r--r--arch/blackfin/configs/BF538-EZKIT_defconfig3
-rw-r--r--arch/blackfin/configs/BF548-EZKIT_defconfig4
-rw-r--r--arch/blackfin/configs/BF561-ACVILON_defconfig4
-rw-r--r--arch/blackfin/configs/BF561-EZKIT_defconfig1
-rw-r--r--arch/blackfin/configs/BlackStamp_defconfig3
-rw-r--r--arch/blackfin/configs/CM-BF527_defconfig4
-rw-r--r--arch/blackfin/configs/CM-BF533_defconfig3
-rw-r--r--arch/blackfin/configs/CM-BF537E_defconfig3
-rw-r--r--arch/blackfin/configs/CM-BF537U_defconfig3
-rw-r--r--arch/blackfin/configs/CM-BF548_defconfig3
-rw-r--r--arch/blackfin/configs/CM-BF561_defconfig3
-rw-r--r--arch/blackfin/configs/H8606_defconfig3
-rw-r--r--arch/blackfin/configs/IP0X_defconfig3
-rw-r--r--arch/blackfin/configs/PNAV-10_defconfig2
-rw-r--r--arch/blackfin/configs/SRV1_defconfig3
-rw-r--r--arch/blackfin/configs/TCM-BF518_defconfig1
-rw-r--r--arch/blackfin/configs/TCM-BF537_defconfig2
-rw-r--r--arch/blackfin/include/asm/bfin5xx_spi.h2
-rw-r--r--arch/blackfin/include/asm/bfin_ppi.h2
-rw-r--r--arch/blackfin/include/asm/bfin_twi.h45
-rw-r--r--arch/blackfin/include/asm/cdef_LPBlackfin.h2
-rw-r--r--arch/blackfin/include/asm/entry.h8
-rw-r--r--arch/blackfin/kernel/ptrace.c16
-rw-r--r--arch/blackfin/mach-bf518/boards/ezbrd.c44
-rw-r--r--arch/blackfin/mach-bf518/boards/tcm-bf518.c24
-rw-r--r--arch/blackfin/mach-bf527/boards/cm_bf527.c24
-rw-r--r--arch/blackfin/mach-bf527/boards/ezbrd.c24
-rw-r--r--arch/blackfin/mach-bf527/boards/ezkit.c26
-rw-r--r--arch/blackfin/mach-bf527/boards/tll6527m.c24
-rw-r--r--arch/blackfin/mach-bf537/boards/cm_bf537e.c24
-rw-r--r--arch/blackfin/mach-bf537/boards/cm_bf537u.c24
-rw-r--r--arch/blackfin/mach-bf537/boards/minotaur.c24
-rw-r--r--arch/blackfin/mach-bf537/boards/pnav10.c24
-rw-r--r--arch/blackfin/mach-bf537/boards/stamp.c26
-rw-r--r--arch/blackfin/mach-bf537/boards/tcm_bf537.c24
-rw-r--r--arch/blackfin/mach-common/Makefile1
-rw-r--r--arch/blackfin/mach-common/irqpanic.c106
-rw-r--r--arch/cris/arch-v10/kernel/ptrace.c20
-rw-r--r--arch/cris/arch-v32/kernel/ptrace.c16
-rw-r--r--arch/cris/include/asm/pgtable.h2
-rw-r--r--arch/frv/include/asm/highmem.h25
-rw-r--r--arch/frv/include/asm/pgtable.h9
-rw-r--r--arch/frv/kernel/ptrace.c32
-rw-r--r--arch/frv/mb93090-mb00/pci-dma.c4
-rw-r--r--arch/frv/mm/cache-page.c8
-rw-r--r--arch/frv/mm/highmem.c51
-rw-r--r--arch/h8300/Kconfig.cpu8
-rw-r--r--arch/h8300/README1
-rw-r--r--arch/h8300/kernel/ptrace.c33
-rw-r--r--arch/ia64/include/asm/cputime.h6
-rw-r--r--arch/ia64/include/asm/pgtable.h2
-rw-r--r--arch/ia64/include/asm/siginfo.h1
-rw-r--r--arch/ia64/kernel/ptrace.c3
-rw-r--r--arch/ia64/kvm/lapic.h1
-rw-r--r--arch/m32r/Kconfig2
-rw-r--r--arch/m32r/include/asm/pgtable.h2
-rw-r--r--arch/m32r/kernel/ptrace.c11
-rw-r--r--arch/m68k/include/asm/cacheflush_no.h2
-rw-r--r--arch/m68k/include/asm/coldfire.h4
-rw-r--r--arch/m68k/include/asm/entry_mm.h8
-rw-r--r--arch/m68k/include/asm/entry_no.h10
-rw-r--r--arch/m68k/include/asm/gpio.h7
-rw-r--r--arch/m68k/include/asm/m548xgpt.h88
-rw-r--r--arch/m68k/include/asm/m548xsim.h55
-rw-r--r--arch/m68k/include/asm/mcfcache.h2
-rw-r--r--arch/m68k/include/asm/mcfsim.h2
-rw-r--r--arch/m68k/include/asm/mcfslt.h44
-rw-r--r--arch/m68k/include/asm/mcfuart.h9
-rw-r--r--arch/m68k/include/asm/motorola_pgtable.h2
-rw-r--r--arch/m68k/include/asm/sun3_pgtable.h2
-rw-r--r--arch/m68k/kernel/asm-offsets.c12
-rw-r--r--arch/m68k/kernel/ptrace.c51
-rw-r--r--arch/m68k/mac/macboing.c3
-rw-r--r--arch/m68k/q40/README2
-rw-r--r--arch/m68knommu/Kconfig11
-rw-r--r--arch/m68knommu/Makefile3
-rw-r--r--arch/m68knommu/kernel/.gitignore1
-rw-r--r--arch/m68knommu/kernel/asm-offsets.c11
-rw-r--r--arch/m68knommu/kernel/ptrace.c104
-rw-r--r--arch/m68knommu/kernel/setup.c3
-rw-r--r--arch/m68knommu/kernel/time.c13
-rw-r--r--arch/m68knommu/kernel/traps.c26
-rw-r--r--arch/m68knommu/platform/5206/Makefile4
-rw-r--r--arch/m68knommu/platform/5206e/Makefile4
-rw-r--r--arch/m68knommu/platform/520x/Makefile4
-rw-r--r--arch/m68knommu/platform/523x/Makefile4
-rw-r--r--arch/m68knommu/platform/5249/Makefile4
-rw-r--r--arch/m68knommu/platform/5272/Makefile4
-rw-r--r--arch/m68knommu/platform/5272/config.c16
-rw-r--r--arch/m68knommu/platform/5272/intc.c60
-rw-r--r--arch/m68knommu/platform/527x/Makefile4
-rw-r--r--arch/m68knommu/platform/528x/Makefile4
-rw-r--r--arch/m68knommu/platform/5307/Makefile4
-rw-r--r--arch/m68knommu/platform/532x/Makefile4
-rw-r--r--arch/m68knommu/platform/5407/Makefile4
-rw-r--r--arch/m68knommu/platform/548x/Makefile18
-rw-r--r--arch/m68knommu/platform/548x/config.c115
-rw-r--r--arch/m68knommu/platform/68328/entry.S36
-rw-r--r--arch/m68knommu/platform/68328/head-de2.S6
-rw-r--r--arch/m68knommu/platform/68328/head-ram.S27
-rw-r--r--arch/m68knommu/platform/68328/ints.c6
-rw-r--r--arch/m68knommu/platform/68360/entry.S13
-rw-r--r--arch/m68knommu/platform/68360/ints.c6
-rw-r--r--arch/m68knommu/platform/68VZ328/config.c5
-rw-r--r--arch/m68knommu/platform/coldfire/Makefile5
-rw-r--r--arch/m68knommu/platform/coldfire/entry.S4
-rw-r--r--arch/m68knommu/platform/coldfire/intc-2.c53
-rw-r--r--arch/m68knommu/platform/coldfire/intc-simr.c10
-rw-r--r--arch/m68knommu/platform/coldfire/intc.c8
-rw-r--r--arch/m68knommu/platform/coldfire/sltimers.c145
-rw-r--r--arch/microblaze/Kconfig17
-rw-r--r--arch/microblaze/Kconfig.debug2
-rw-r--r--arch/microblaze/Makefile11
-rw-r--r--arch/microblaze/include/asm/byteorder.h4
-rw-r--r--arch/microblaze/include/asm/checksum.h9
-rw-r--r--arch/microblaze/include/asm/cpuinfo.h5
-rw-r--r--arch/microblaze/include/asm/elf.h2
-rw-r--r--arch/microblaze/include/asm/gpio.h5
-rw-r--r--arch/microblaze/include/asm/io.h2
-rw-r--r--arch/microblaze/include/asm/page.h3
-rw-r--r--arch/microblaze/include/asm/pci.h2
-rw-r--r--arch/microblaze/include/asm/pgalloc.h3
-rw-r--r--arch/microblaze/include/asm/pgtable.h14
-rw-r--r--arch/microblaze/include/asm/prom.h1
-rw-r--r--arch/microblaze/include/asm/pvr.h14
-rw-r--r--arch/microblaze/include/asm/seccomp.h16
-rw-r--r--arch/microblaze/include/asm/setup.h6
-rw-r--r--arch/microblaze/include/asm/thread_info.h20
-rw-r--r--arch/microblaze/include/asm/unaligned.h12
-rw-r--r--arch/microblaze/include/asm/unistd.h5
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c1
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo-static.c1
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo.c2
-rw-r--r--arch/microblaze/kernel/cpu/mb.c3
-rw-r--r--arch/microblaze/kernel/cpu/pvr.c2
-rw-r--r--arch/microblaze/kernel/early_printk.c87
-rw-r--r--arch/microblaze/kernel/entry.S21
-rw-r--r--arch/microblaze/kernel/exceptions.c25
-rw-r--r--arch/microblaze/kernel/heartbeat.c11
-rw-r--r--arch/microblaze/kernel/intc.c14
-rw-r--r--arch/microblaze/kernel/kgdb.c7
-rw-r--r--arch/microblaze/kernel/microblaze_ksyms.c32
-rw-r--r--arch/microblaze/kernel/prom.c44
-rw-r--r--arch/microblaze/kernel/ptrace.c5
-rw-r--r--arch/microblaze/kernel/setup.c6
-rw-r--r--arch/microblaze/kernel/syscall_table.S3
-rw-r--r--arch/microblaze/kernel/timer.c41
-rw-r--r--arch/microblaze/kernel/vmlinux.lds.S5
-rw-r--r--arch/microblaze/lib/Makefile10
-rw-r--r--arch/microblaze/lib/ashldi3.c29
-rw-r--r--arch/microblaze/lib/ashrdi3.c31
-rw-r--r--arch/microblaze/lib/divsi3.S73
-rw-r--r--arch/microblaze/lib/libgcc.h25
-rw-r--r--arch/microblaze/lib/lshrdi3.c29
-rw-r--r--arch/microblaze/lib/memcpy.c46
-rw-r--r--arch/microblaze/lib/memmove.c59
-rw-r--r--arch/microblaze/lib/memset.c22
-rw-r--r--arch/microblaze/lib/modsi3.S73
-rw-r--r--arch/microblaze/lib/muldi3.S121
-rw-r--r--arch/microblaze/lib/mulsi3.S46
-rw-r--r--arch/microblaze/lib/udivsi3.S84
-rw-r--r--arch/microblaze/lib/umodsi3.S86
-rw-r--r--arch/microblaze/pci/pci-common.c21
-rw-r--r--arch/microblaze/platform/generic/system.dts3
-rw-r--r--arch/microblaze/platform/platform.c3
-rw-r--r--arch/mips/Kconfig19
-rw-r--r--arch/mips/alchemy/devboards/db1200/platform.c6
-rw-r--r--arch/mips/include/asm/highmem.h18
-rw-r--r--arch/mips/include/asm/irq.h5
-rw-r--r--arch/mips/include/asm/pci/bridge.h2
-rw-r--r--arch/mips/include/asm/pgtable-32.h3
-rw-r--r--arch/mips/include/asm/pgtable-64.h3
-rw-r--r--arch/mips/include/asm/prom.h31
-rw-r--r--arch/mips/kernel/Makefile2
-rw-r--r--arch/mips/kernel/mips-mt-fpaff.c2
-rw-r--r--arch/mips/kernel/prom.c112
-rw-r--r--arch/mips/kernel/ptrace.c25
-rw-r--r--arch/mips/kernel/setup.c2
-rw-r--r--arch/mips/math-emu/cp1emu.c1
-rw-r--r--arch/mips/math-emu/dp_add.c1
-rw-r--r--arch/mips/math-emu/dp_cmp.c1
-rw-r--r--arch/mips/math-emu/dp_div.c1
-rw-r--r--arch/mips/math-emu/dp_fint.c1
-rw-r--r--arch/mips/math-emu/dp_flong.c1
-rw-r--r--arch/mips/math-emu/dp_frexp.c1
-rw-r--r--arch/mips/math-emu/dp_fsp.c1
-rw-r--r--arch/mips/math-emu/dp_logb.c1
-rw-r--r--arch/mips/math-emu/dp_modf.c1
-rw-r--r--arch/mips/math-emu/dp_mul.c1
-rw-r--r--arch/mips/math-emu/dp_scalb.c1
-rw-r--r--arch/mips/math-emu/dp_simple.c1
-rw-r--r--arch/mips/math-emu/dp_sqrt.c1
-rw-r--r--arch/mips/math-emu/dp_sub.c1
-rw-r--r--arch/mips/math-emu/dp_tint.c1
-rw-r--r--arch/mips/math-emu/dp_tlong.c1
-rw-r--r--arch/mips/math-emu/ieee754.c1
-rw-r--r--arch/mips/math-emu/ieee754.h1
-rw-r--r--arch/mips/math-emu/ieee754d.c1
-rw-r--r--arch/mips/math-emu/ieee754dp.c1
-rw-r--r--arch/mips/math-emu/ieee754dp.h1
-rw-r--r--arch/mips/math-emu/ieee754int.h1
-rw-r--r--arch/mips/math-emu/ieee754m.c1
-rw-r--r--arch/mips/math-emu/ieee754sp.c1
-rw-r--r--arch/mips/math-emu/ieee754sp.h1
-rw-r--r--arch/mips/math-emu/ieee754xcpt.c1
-rw-r--r--arch/mips/math-emu/sp_add.c1
-rw-r--r--arch/mips/math-emu/sp_cmp.c1
-rw-r--r--arch/mips/math-emu/sp_div.c1
-rw-r--r--arch/mips/math-emu/sp_fdp.c1
-rw-r--r--arch/mips/math-emu/sp_fint.c1
-rw-r--r--arch/mips/math-emu/sp_flong.c1
-rw-r--r--arch/mips/math-emu/sp_frexp.c1
-rw-r--r--arch/mips/math-emu/sp_logb.c1
-rw-r--r--arch/mips/math-emu/sp_modf.c1
-rw-r--r--arch/mips/math-emu/sp_mul.c1
-rw-r--r--arch/mips/math-emu/sp_scalb.c1
-rw-r--r--arch/mips/math-emu/sp_simple.c1
-rw-r--r--arch/mips/math-emu/sp_sqrt.c1
-rw-r--r--arch/mips/math-emu/sp_sub.c1
-rw-r--r--arch/mips/math-emu/sp_tint.c1
-rw-r--r--arch/mips/math-emu/sp_tlong.c1
-rw-r--r--arch/mips/mm/highmem.c51
-rw-r--r--arch/mips/pci/fixup-fuloong2e.c2
-rw-r--r--arch/mips/sibyte/common/sb_tbprof.c2
-rw-r--r--arch/mn10300/Kconfig279
-rw-r--r--arch/mn10300/Makefile6
-rw-r--r--arch/mn10300/boot/compressed/head.S69
-rw-r--r--arch/mn10300/configs/asb2303_defconfig2
-rw-r--r--arch/mn10300/configs/asb2364_defconfig98
-rw-r--r--arch/mn10300/include/asm/atomic.h350
-rw-r--r--arch/mn10300/include/asm/bitops.h14
-rw-r--r--arch/mn10300/include/asm/cache.h14
-rw-r--r--arch/mn10300/include/asm/cacheflush.h164
-rw-r--r--arch/mn10300/include/asm/cpu-regs.h91
-rw-r--r--arch/mn10300/include/asm/dmactl-regs.h87
-rw-r--r--arch/mn10300/include/asm/elf.h12
-rw-r--r--arch/mn10300/include/asm/exceptions.h8
-rw-r--r--arch/mn10300/include/asm/fpu.h157
-rw-r--r--arch/mn10300/include/asm/frame.inc20
-rw-r--r--arch/mn10300/include/asm/gdb-stub.h2
-rw-r--r--arch/mn10300/include/asm/hardirq.h3
-rw-r--r--arch/mn10300/include/asm/highmem.h46
-rw-r--r--arch/mn10300/include/asm/intctl-regs.h37
-rw-r--r--arch/mn10300/include/asm/io.h13
-rw-r--r--arch/mn10300/include/asm/irq.h12
-rw-r--r--arch/mn10300/include/asm/irq_regs.h6
-rw-r--r--arch/mn10300/include/asm/irqflags.h111
-rw-r--r--arch/mn10300/include/asm/mmu_context.h73
-rw-r--r--arch/mn10300/include/asm/pgalloc.h1
-rw-r--r--arch/mn10300/include/asm/pgtable.h90
-rw-r--r--arch/mn10300/include/asm/processor.h66
-rw-r--r--arch/mn10300/include/asm/ptrace.h13
-rw-r--r--arch/mn10300/include/asm/reset-regs.h2
-rw-r--r--arch/mn10300/include/asm/rtc.h11
-rw-r--r--arch/mn10300/include/asm/rwlock.h125
-rw-r--r--arch/mn10300/include/asm/serial-regs.h51
-rw-r--r--arch/mn10300/include/asm/serial.h8
-rw-r--r--arch/mn10300/include/asm/smp.h91
-rw-r--r--arch/mn10300/include/asm/smsc911x.h1
-rw-r--r--arch/mn10300/include/asm/spinlock.h179
-rw-r--r--arch/mn10300/include/asm/spinlock_types.h20
-rw-r--r--arch/mn10300/include/asm/system.h73
-rw-r--r--arch/mn10300/include/asm/thread_info.h18
-rw-r--r--arch/mn10300/include/asm/timer-regs.h191
-rw-r--r--arch/mn10300/include/asm/timex.h20
-rw-r--r--arch/mn10300/include/asm/tlbflush.h174
-rw-r--r--arch/mn10300/include/asm/uaccess.h6
-rw-r--r--arch/mn10300/kernel/Makefile15
-rw-r--r--arch/mn10300/kernel/asm-offsets.c11
-rw-r--r--arch/mn10300/kernel/cevt-mn10300.c131
-rw-r--r--arch/mn10300/kernel/csrc-mn10300.c35
-rw-r--r--arch/mn10300/kernel/entry.S146
-rw-r--r--arch/mn10300/kernel/fpu-low.S265
-rw-r--r--arch/mn10300/kernel/fpu-nofpu-low.S39
-rw-r--r--arch/mn10300/kernel/fpu-nofpu.c30
-rw-r--r--arch/mn10300/kernel/fpu.c141
-rw-r--r--arch/mn10300/kernel/gdb-io-serial-low.S5
-rw-r--r--arch/mn10300/kernel/gdb-io-serial.c37
-rw-r--r--arch/mn10300/kernel/gdb-io-ttysm.c24
-rw-r--r--arch/mn10300/kernel/gdb-stub.c17
-rw-r--r--arch/mn10300/kernel/head.S202
-rw-r--r--arch/mn10300/kernel/internal.h25
-rw-r--r--arch/mn10300/kernel/irq.c276
-rw-r--r--arch/mn10300/kernel/kprobes.c4
-rw-r--r--arch/mn10300/kernel/mn10300-serial-low.S6
-rw-r--r--arch/mn10300/kernel/mn10300-serial.c210
-rw-r--r--arch/mn10300/kernel/mn10300-watchdog-low.S9
-rw-r--r--arch/mn10300/kernel/mn10300-watchdog.c100
-rw-r--r--arch/mn10300/kernel/process.c61
-rw-r--r--arch/mn10300/kernel/profile.c2
-rw-r--r--arch/mn10300/kernel/ptrace.c20
-rw-r--r--arch/mn10300/kernel/rtc.c41
-rw-r--r--arch/mn10300/kernel/setup.c79
-rw-r--r--arch/mn10300/kernel/signal.c20
-rw-r--r--arch/mn10300/kernel/smp-low.S97
-rw-r--r--arch/mn10300/kernel/smp.c1152
-rw-r--r--arch/mn10300/kernel/switch_to.S7
-rw-r--r--arch/mn10300/kernel/time.c112
-rw-r--r--arch/mn10300/kernel/traps.c42
-rw-r--r--arch/mn10300/kernel/vmlinux.lds.S2
-rw-r--r--arch/mn10300/lib/bitops.c4
-rw-r--r--arch/mn10300/lib/delay.c8
-rw-r--r--arch/mn10300/lib/do_csum.S49
-rw-r--r--arch/mn10300/mm/Kconfig.cache101
-rw-r--r--arch/mn10300/mm/Makefile14
-rw-r--r--arch/mn10300/mm/cache-flush-by-reg.S308
-rw-r--r--arch/mn10300/mm/cache-flush-by-tag.S251
-rw-r--r--arch/mn10300/mm/cache-flush-icache.c155
-rw-r--r--arch/mn10300/mm/cache-flush-mn10300.S192
-rw-r--r--arch/mn10300/mm/cache-inv-by-reg.S356
-rw-r--r--arch/mn10300/mm/cache-inv-by-tag.S348
-rw-r--r--arch/mn10300/mm/cache-inv-icache.c129
-rw-r--r--arch/mn10300/mm/cache-mn10300.S289
-rw-r--r--arch/mn10300/mm/cache-smp-flush.c156
-rw-r--r--arch/mn10300/mm/cache-smp-inv.c153
-rw-r--r--arch/mn10300/mm/cache-smp.c105
-rw-r--r--arch/mn10300/mm/cache-smp.h69
-rw-r--r--arch/mn10300/mm/cache.c95
-rw-r--r--arch/mn10300/mm/fault.c17
-rw-r--r--arch/mn10300/mm/init.c26
-rw-r--r--arch/mn10300/mm/misalignment.c3
-rw-r--r--arch/mn10300/mm/mmu-context.c41
-rw-r--r--arch/mn10300/mm/pgtable.c2
-rw-r--r--arch/mn10300/mm/tlb-mn10300.S59
-rw-r--r--arch/mn10300/mm/tlb-smp.c214
-rw-r--r--arch/mn10300/proc-mn103e010/include/proc/cache.h9
-rw-r--r--arch/mn10300/proc-mn103e010/include/proc/clock.h2
-rw-r--r--arch/mn10300/proc-mn103e010/include/proc/dmactl-regs.h102
-rw-r--r--arch/mn10300/proc-mn103e010/include/proc/intctl-regs.h29
-rw-r--r--arch/mn10300/proc-mn103e010/include/proc/proc.h2
-rw-r--r--arch/mn10300/proc-mn103e010/proc-init.c37
-rw-r--r--arch/mn10300/proc-mn2ws0050/Makefile5
-rw-r--r--arch/mn10300/proc-mn2ws0050/include/proc/cache.h48
-rw-r--r--arch/mn10300/proc-mn2ws0050/include/proc/clock.h20
-rw-r--r--arch/mn10300/proc-mn2ws0050/include/proc/dmactl-regs.h103
-rw-r--r--arch/mn10300/proc-mn2ws0050/include/proc/intctl-regs.h29
-rw-r--r--arch/mn10300/proc-mn2ws0050/include/proc/irq.h49
-rw-r--r--arch/mn10300/proc-mn2ws0050/include/proc/nand-regs.h120
-rw-r--r--arch/mn10300/proc-mn2ws0050/include/proc/proc.h18
-rw-r--r--arch/mn10300/proc-mn2ws0050/include/proc/smp-regs.h51
-rw-r--r--arch/mn10300/proc-mn2ws0050/proc-init.c134
-rw-r--r--arch/mn10300/unit-asb2303/include/unit/clock.h25
-rw-r--r--arch/mn10300/unit-asb2303/include/unit/serial.h5
-rw-r--r--arch/mn10300/unit-asb2303/include/unit/timex.h109
-rw-r--r--arch/mn10300/unit-asb2303/unit-init.c10
-rw-r--r--arch/mn10300/unit-asb2305/include/unit/clock.h25
-rw-r--r--arch/mn10300/unit-asb2305/include/unit/serial.h5
-rw-r--r--arch/mn10300/unit-asb2305/include/unit/timex.h109
-rw-r--r--arch/mn10300/unit-asb2305/pci-asb2305.c16
-rw-r--r--arch/mn10300/unit-asb2305/pci.c2
-rw-r--r--arch/mn10300/unit-asb2305/unit-init.c6
-rw-r--r--arch/mn10300/unit-asb2364/Makefile12
-rw-r--r--arch/mn10300/unit-asb2364/include/unit/clock.h29
-rw-r--r--arch/mn10300/unit-asb2364/include/unit/fpga-regs.h52
-rw-r--r--arch/mn10300/unit-asb2364/include/unit/irq.h35
-rw-r--r--arch/mn10300/unit-asb2364/include/unit/leds.h54
-rw-r--r--arch/mn10300/unit-asb2364/include/unit/serial.h151
-rw-r--r--arch/mn10300/unit-asb2364/include/unit/smsc911x.h171
-rw-r--r--arch/mn10300/unit-asb2364/include/unit/timex.h159
-rw-r--r--arch/mn10300/unit-asb2364/irq-fpga.c96
-rw-r--r--arch/mn10300/unit-asb2364/leds.c98
-rw-r--r--arch/mn10300/unit-asb2364/smsc911x.c58
-rw-r--r--arch/mn10300/unit-asb2364/unit-init.c88
-rw-r--r--arch/parisc/Kconfig4
-rw-r--r--arch/parisc/include/asm/cache.h2
-rw-r--r--arch/parisc/include/asm/cacheflush.h8
-rw-r--r--arch/parisc/include/asm/irq.h2
-rw-r--r--arch/parisc/include/asm/pgtable.h2
-rw-r--r--arch/parisc/include/asm/unistd.h3
-rw-r--r--arch/parisc/kernel/irq.c41
-rw-r--r--arch/parisc/kernel/pdc_cons.c141
-rw-r--r--arch/parisc/kernel/ptrace.c13
-rw-r--r--arch/parisc/kernel/syscall_table.S1
-rw-r--r--arch/parisc/kernel/unaligned.c3
-rw-r--r--arch/parisc/kernel/unwind.c5
-rw-r--r--arch/parisc/math-emu/Makefile2
-rw-r--r--arch/powerpc/boot/dts/mpc8610_hpcd.dts1
-rw-r--r--arch/powerpc/configs/mpc85xx_defconfig3
-rw-r--r--arch/powerpc/configs/mpc85xx_smp_defconfig3
-rw-r--r--arch/powerpc/include/asm/cputime.h12
-rw-r--r--arch/powerpc/include/asm/fsl_guts.h (renamed from arch/powerpc/include/asm/immap_86xx.h)111
-rw-r--r--arch/powerpc/include/asm/fsldma.h137
-rw-r--r--arch/powerpc/include/asm/highmem.h9
-rw-r--r--arch/powerpc/include/asm/hydra.h2
-rw-r--r--arch/powerpc/include/asm/kvm.h1
-rw-r--r--arch/powerpc/include/asm/kvm_asm.h4
-rw-r--r--arch/powerpc/include/asm/kvm_book3s.h31
-rw-r--r--arch/powerpc/include/asm/kvm_host.h21
-rw-r--r--arch/powerpc/include/asm/kvm_para.h139
-rw-r--r--arch/powerpc/include/asm/kvm_ppc.h1
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc32.h8
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc64.h2
-rw-r--r--arch/powerpc/kernel/Makefile2
-rw-r--r--arch/powerpc/kernel/asm-offsets.c25
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S6
-rw-r--r--arch/powerpc/kernel/head_64.S6
-rw-r--r--arch/powerpc/kernel/ibmebus.c11
-rw-r--r--arch/powerpc/kernel/kvm.c596
-rw-r--r--arch/powerpc/kernel/kvm_emul.S302
-rw-r--r--arch/powerpc/kernel/legacy_serial.c22
-rw-r--r--arch/powerpc/kernel/prom.c12
-rw-r--r--arch/powerpc/kernel/ptrace.c66
-rw-r--r--arch/powerpc/kernel/vio.c4
-rw-r--r--arch/powerpc/kvm/44x.c10
-rw-r--r--arch/powerpc/kvm/44x_tlb.c9
-rw-r--r--arch/powerpc/kvm/book3s.c272
-rw-r--r--arch/powerpc/kvm/book3s_32_mmu.c111
-rw-r--r--arch/powerpc/kvm/book3s_32_mmu_host.c75
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu.c42
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu_host.c74
-rw-r--r--arch/powerpc/kvm/book3s_emulate.c73
-rw-r--r--arch/powerpc/kvm/book3s_mmu_hpte.c140
-rw-r--r--arch/powerpc/kvm/book3s_paired_singles.c11
-rw-r--r--arch/powerpc/kvm/book3s_rmhandlers.S32
-rw-r--r--arch/powerpc/kvm/booke.c108
-rw-r--r--arch/powerpc/kvm/booke.h10
-rw-r--r--arch/powerpc/kvm/booke_emulate.c14
-rw-r--r--arch/powerpc/kvm/booke_interrupts.S3
-rw-r--r--arch/powerpc/kvm/e500.c7
-rw-r--r--arch/powerpc/kvm/e500_tlb.c18
-rw-r--r--arch/powerpc/kvm/e500_tlb.h2
-rw-r--r--arch/powerpc/kvm/emulate.c36
-rw-r--r--arch/powerpc/kvm/powerpc.c88
-rw-r--r--arch/powerpc/kvm/trace.h239
-rw-r--r--arch/powerpc/mm/highmem.c37
-rw-r--r--arch/powerpc/platforms/85xx/p1022_ds.c211
-rw-r--r--arch/powerpc/platforms/Kconfig10
-rw-r--r--arch/powerpc/sysdev/fsl_rio.c76
-rw-r--r--arch/s390/Kbuild6
-rw-r--r--arch/s390/Kconfig12
-rw-r--r--arch/s390/Makefile5
-rw-r--r--arch/s390/crypto/crypt_s390.h2
-rw-r--r--arch/s390/include/asm/Kbuild1
-rw-r--r--arch/s390/include/asm/ccwdev.h12
-rw-r--r--arch/s390/include/asm/cpu.h2
-rw-r--r--arch/s390/include/asm/cputime.h10
-rw-r--r--arch/s390/include/asm/hugetlb.h26
-rw-r--r--arch/s390/include/asm/kvm_virtio.h7
-rw-r--r--arch/s390/include/asm/lowcore.h11
-rw-r--r--arch/s390/include/asm/page.h8
-rw-r--r--arch/s390/include/asm/pgalloc.h4
-rw-r--r--arch/s390/include/asm/pgtable.h62
-rw-r--r--arch/s390/include/asm/processor.h2
-rw-r--r--arch/s390/include/asm/ptrace.h3
-rw-r--r--arch/s390/include/asm/qdio.h13
-rw-r--r--arch/s390/include/asm/s390_ext.h2
-rw-r--r--arch/s390/include/asm/scatterlist.h2
-rw-r--r--arch/s390/include/asm/setup.h3
-rw-r--r--arch/s390/include/asm/syscall.h4
-rw-r--r--arch/s390/include/asm/sysinfo.h40
-rw-r--r--arch/s390/include/asm/system.h51
-rw-r--r--arch/s390/include/asm/tlb.h13
-rw-r--r--arch/s390/include/asm/topology.h2
-rw-r--r--arch/s390/kernel/asm-offsets.c3
-rw-r--r--arch/s390/kernel/compat_ptrace.h3
-rw-r--r--arch/s390/kernel/dis.c145
-rw-r--r--arch/s390/kernel/early.c45
-rw-r--r--arch/s390/kernel/entry.S44
-rw-r--r--arch/s390/kernel/entry.h4
-rw-r--r--arch/s390/kernel/entry64.S45
-rw-r--r--arch/s390/kernel/head.S8
-rw-r--r--arch/s390/kernel/process.c10
-rw-r--r--arch/s390/kernel/processor.c2
-rw-r--r--arch/s390/kernel/ptrace.c3
-rw-r--r--arch/s390/kernel/s390_ext.c9
-rw-r--r--arch/s390/kernel/setup.c22
-rw-r--r--arch/s390/kernel/smp.c5
-rw-r--r--arch/s390/kernel/sysinfo.c41
-rw-r--r--arch/s390/kernel/time.c17
-rw-r--r--arch/s390/kernel/topology.c101
-rw-r--r--arch/s390/kernel/traps.c173
-rw-r--r--arch/s390/kernel/vdso.c6
-rw-r--r--arch/s390/kernel/vtime.c3
-rw-r--r--arch/s390/kvm/kvm-s390.c4
-rw-r--r--arch/s390/kvm/priv.c4
-rw-r--r--arch/s390/mm/Makefile2
-rw-r--r--arch/s390/mm/cmm.c7
-rw-r--r--arch/s390/mm/fault.c77
-rw-r--r--arch/s390/mm/gup.c225
-rw-r--r--arch/s390/mm/hugetlbpage.c2
-rw-r--r--arch/s390/mm/init.c52
-rw-r--r--arch/s390/mm/pgtable.c173
-rw-r--r--arch/score/include/asm/pgtable.h3
-rw-r--r--arch/score/kernel/ptrace.c7
-rw-r--r--arch/sh/Kconfig6
-rw-r--r--arch/sh/boards/Kconfig18
-rw-r--r--arch/sh/boards/Makefile2
-rw-r--r--arch/sh/boards/board-sh2007.c133
-rw-r--r--arch/sh/boards/board-sh7757lcr.c374
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c6
-rw-r--r--arch/sh/boards/mach-sdk7786/Makefile5
-rw-r--r--arch/sh/boards/mach-sdk7786/gpio.c49
-rw-r--r--arch/sh/boards/mach-sdk7786/setup.c54
-rw-r--r--arch/sh/boards/mach-sdk7786/sram.c72
-rw-r--r--arch/sh/boards/mach-x3proto/Makefile2
-rw-r--r--arch/sh/boards/mach-x3proto/gpio.c135
-rw-r--r--arch/sh/boards/mach-x3proto/ilsel.c18
-rw-r--r--arch/sh/boards/mach-x3proto/setup.c132
-rw-r--r--arch/sh/boot/compressed/head_32.S4
-rw-r--r--arch/sh/cchips/hd6446x/Makefile2
-rw-r--r--arch/sh/configs/ap325rxa_defconfig1
-rw-r--r--arch/sh/configs/cayman_defconfig1
-rw-r--r--arch/sh/configs/dreamcast_defconfig1
-rw-r--r--arch/sh/configs/ecovec24-romimage_defconfig1
-rw-r--r--arch/sh/configs/edosk7760_defconfig1
-rw-r--r--arch/sh/configs/espt_defconfig1
-rw-r--r--arch/sh/configs/hp6xx_defconfig1
-rw-r--r--arch/sh/configs/kfr2r09-romimage_defconfig1
-rw-r--r--arch/sh/configs/kfr2r09_defconfig1
-rw-r--r--arch/sh/configs/landisk_defconfig1
-rw-r--r--arch/sh/configs/lboxre2_defconfig1
-rw-r--r--arch/sh/configs/magicpanelr2_defconfig1
-rw-r--r--arch/sh/configs/microdev_defconfig1
-rw-r--r--arch/sh/configs/migor_defconfig1
-rw-r--r--arch/sh/configs/polaris_defconfig1
-rw-r--r--arch/sh/configs/r7780mp_defconfig1
-rw-r--r--arch/sh/configs/r7785rp_defconfig1
-rw-r--r--arch/sh/configs/rts7751r2d1_defconfig1
-rw-r--r--arch/sh/configs/rts7751r2dplus_defconfig1
-rw-r--r--arch/sh/configs/sdk7780_defconfig1
-rw-r--r--arch/sh/configs/se7343_defconfig1
-rw-r--r--arch/sh/configs/se7712_defconfig1
-rw-r--r--arch/sh/configs/se7721_defconfig1
-rw-r--r--arch/sh/configs/se7722_defconfig1
-rw-r--r--arch/sh/configs/se7724_defconfig1
-rw-r--r--arch/sh/configs/se7750_defconfig1
-rw-r--r--arch/sh/configs/se7751_defconfig1
-rw-r--r--arch/sh/configs/se7780_defconfig1
-rw-r--r--arch/sh/configs/sh03_defconfig1
-rw-r--r--arch/sh/configs/sh2007_defconfig212
-rw-r--r--arch/sh/configs/sh7710voipgw_defconfig1
-rw-r--r--arch/sh/configs/sh7757lcr_defconfig85
-rw-r--r--arch/sh/configs/sh7763rdp_defconfig1
-rw-r--r--arch/sh/configs/sh7785lcr_defconfig1
-rw-r--r--arch/sh/configs/shx3_defconfig1
-rw-r--r--arch/sh/configs/snapgear_defconfig1
-rw-r--r--arch/sh/configs/systemh_defconfig1
-rw-r--r--arch/sh/configs/titan_defconfig1
-rw-r--r--arch/sh/configs/ul2_defconfig1
-rw-r--r--arch/sh/drivers/dma/dma-api.c4
-rw-r--r--arch/sh/drivers/pci/Makefile1
-rw-r--r--arch/sh/drivers/pci/fixups-sdk7786.c67
-rw-r--r--arch/sh/drivers/pci/ops-sh4.c11
-rw-r--r--arch/sh/drivers/pci/ops-sh7786.c69
-rw-r--r--arch/sh/drivers/pci/pci-sh7751.c2
-rw-r--r--arch/sh/drivers/pci/pci-sh7780.c2
-rw-r--r--arch/sh/drivers/pci/pci-sh7780.h6
-rw-r--r--arch/sh/drivers/pci/pci.c43
-rw-r--r--arch/sh/drivers/pci/pcie-sh7786.c251
-rw-r--r--arch/sh/drivers/pci/pcie-sh7786.h56
-rw-r--r--arch/sh/include/asm/Kbuild2
-rw-r--r--arch/sh/include/asm/elf.h27
-rw-r--r--arch/sh/include/asm/fixmap.h4
-rw-r--r--arch/sh/include/asm/gpio.h6
-rw-r--r--arch/sh/include/asm/irq.h2
-rw-r--r--arch/sh/include/asm/kprobes.h1
-rw-r--r--arch/sh/include/asm/pci.h2
-rw-r--r--arch/sh/include/asm/pgtable_32.h3
-rw-r--r--arch/sh/include/asm/pgtable_64.h2
-rw-r--r--arch/sh/include/asm/processor_32.h3
-rw-r--r--arch/sh/include/asm/processor_64.h3
-rw-r--r--arch/sh/include/asm/ptrace.h169
-rw-r--r--arch/sh/include/asm/ptrace_32.h83
-rw-r--r--arch/sh/include/asm/ptrace_64.h20
-rw-r--r--arch/sh/include/asm/sizes.h1
-rw-r--r--arch/sh/include/asm/sram.h38
-rw-r--r--arch/sh/include/asm/system.h2
-rw-r--r--arch/sh/include/asm/system_32.h15
-rw-r--r--arch/sh/include/asm/tlbflush.h2
-rw-r--r--arch/sh/include/asm/unistd_32.h27
-rw-r--r--arch/sh/include/asm/unistd_64.h5
-rw-r--r--arch/sh/include/cpu-sh3/cpu/mmu_context.h1
-rw-r--r--arch/sh/include/cpu-sh4/cpu/freq.h4
-rw-r--r--arch/sh/include/cpu-sh4/cpu/sh7757.h301
-rw-r--r--arch/sh/include/cpu-sh4/cpu/shx3.h64
-rw-r--r--arch/sh/include/mach-common/mach/sh2007.h117
-rw-r--r--arch/sh/include/mach-sdk7786/mach/fpga.h26
-rw-r--r--arch/sh/include/mach-x3proto/mach/hardware.h12
-rw-r--r--arch/sh/include/mach-x3proto/mach/ilsel.h (renamed from arch/sh/include/asm/ilsel.h)0
-rw-r--r--arch/sh/kernel/Makefile8
-rw-r--r--arch/sh/kernel/clkdev.c4
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/Makefile5
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7757.c199
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-shx3.c225
-rw-r--r--arch/sh/kernel/cpu/sh4a/intc-shx3.c34
-rw-r--r--arch/sh/kernel/cpu/sh4a/perf_event.c20
-rw-r--r--arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c1582
-rw-r--r--arch/sh/kernel/cpu/sh4a/pinmux-shx3.c587
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7722.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7724.c66
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7757.c222
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7786.c126
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-shx3.c42
-rw-r--r--arch/sh/kernel/head_32.S2
-rw-r--r--arch/sh/kernel/io_trapped.c2
-rw-r--r--arch/sh/kernel/irq.c2
-rw-r--r--arch/sh/kernel/kdebugfs.c16
-rw-r--r--arch/sh/kernel/kprobes.c100
-rw-r--r--arch/sh/kernel/ptrace.c33
-rw-r--r--arch/sh/kernel/ptrace_32.c72
-rw-r--r--arch/sh/kernel/ptrace_64.c113
-rw-r--r--arch/sh/kernel/reboot.c4
-rw-r--r--arch/sh/kernel/setup.c22
-rw-r--r--arch/sh/kernel/syscalls_32.S22
-rw-r--r--arch/sh/kernel/syscalls_64.S3
-rw-r--r--arch/sh/kernel/traps_32.c29
-rw-r--r--arch/sh/kernel/traps_64.c11
-rw-r--r--arch/sh/lib/Makefile2
-rw-r--r--arch/sh/math-emu/math.c3
-rw-r--r--arch/sh/mm/Kconfig4
-rw-r--r--arch/sh/mm/Makefile3
-rw-r--r--arch/sh/mm/asids-debugfs.c2
-rw-r--r--arch/sh/mm/cache-debugfs.c10
-rw-r--r--arch/sh/mm/consistent.c3
-rw-r--r--arch/sh/mm/init.c52
-rw-r--r--arch/sh/mm/nommu.c4
-rw-r--r--arch/sh/mm/pmb.c35
-rw-r--r--arch/sh/mm/sram.c34
-rw-r--r--arch/sh/mm/tlb-debugfs.c11
-rw-r--r--arch/sh/mm/tlbflush_32.c16
-rw-r--r--arch/sh/mm/tlbflush_64.c5
-rw-r--r--arch/sh/tools/mach-types2
-rw-r--r--arch/sparc/Kconfig1
-rw-r--r--arch/sparc/include/asm/Kbuild1
-rw-r--r--arch/sparc/include/asm/floppy_32.h3
-rw-r--r--arch/sparc/include/asm/highmem.h4
-rw-r--r--arch/sparc/include/asm/io_32.h31
-rw-r--r--arch/sparc/include/asm/io_64.h31
-rw-r--r--arch/sparc/include/asm/openprom.h16
-rw-r--r--arch/sparc/include/asm/oplib_32.h44
-rw-r--r--arch/sparc/include/asm/oplib_64.h39
-rw-r--r--arch/sparc/include/asm/pci_64.h2
-rw-r--r--arch/sparc/include/asm/pgtable_32.h3
-rw-r--r--arch/sparc/include/asm/pgtable_64.h2
-rw-r--r--arch/sparc/include/asm/prom.h5
-rw-r--r--arch/sparc/kernel/auxio_32.c4
-rw-r--r--arch/sparc/kernel/btext.c4
-rw-r--r--arch/sparc/kernel/devices.c23
-rw-r--r--arch/sparc/kernel/leon_kernel.c2
-rw-r--r--arch/sparc/kernel/pcic.c4
-rw-r--r--arch/sparc/kernel/prom.h6
-rw-r--r--arch/sparc/kernel/prom_common.c202
-rw-r--r--arch/sparc/kernel/ptrace_32.c57
-rw-r--r--arch/sparc/kernel/ptrace_64.c15
-rw-r--r--arch/sparc/kernel/setup_64.c2
-rw-r--r--arch/sparc/kernel/starfire.c2
-rw-r--r--arch/sparc/kernel/tadpole.c2
-rw-r--r--arch/sparc/mm/highmem.c48
-rw-r--r--arch/sparc/mm/init_64.c2
-rw-r--r--arch/sparc/mm/srmmu.c8
-rw-r--r--arch/sparc/mm/sun4c.c2
-rw-r--r--arch/sparc/prom/init_32.c2
-rw-r--r--arch/sparc/prom/init_64.c4
-rw-r--r--arch/sparc/prom/memory.c3
-rw-r--r--arch/sparc/prom/misc_64.c6
-rw-r--r--arch/sparc/prom/ranges.c6
-rw-r--r--arch/sparc/prom/tree_32.c58
-rw-r--r--arch/sparc/prom/tree_64.c62
-rw-r--r--arch/tile/Kconfig23
-rw-r--r--arch/tile/Makefile19
-rw-r--r--arch/tile/include/arch/sim.h619
-rw-r--r--arch/tile/include/arch/sim_def.h548
-rw-r--r--arch/tile/include/arch/spr_def.h85
-rw-r--r--arch/tile/include/arch/spr_def_32.h39
-rw-r--r--arch/tile/include/asm/backtrace.h5
-rw-r--r--arch/tile/include/asm/compat.h15
-rw-r--r--arch/tile/include/asm/highmem.h10
-rw-r--r--arch/tile/include/asm/irqflags.h64
-rw-r--r--arch/tile/include/asm/mman.h1
-rw-r--r--arch/tile/include/asm/page.h27
-rw-r--r--arch/tile/include/asm/pgtable.h5
-rw-r--r--arch/tile/include/asm/processor.h11
-rw-r--r--arch/tile/include/asm/ptrace.h4
-rw-r--r--arch/tile/include/asm/syscalls.h73
-rw-r--r--arch/tile/include/asm/system.h14
-rw-r--r--arch/tile/include/asm/traps.h4
-rw-r--r--arch/tile/include/hv/hypervisor.h30
-rw-r--r--arch/tile/kernel/backtrace.c4
-rw-r--r--arch/tile/kernel/compat.c10
-rw-r--r--arch/tile/kernel/compat_signal.c10
-rw-r--r--arch/tile/kernel/entry.S34
-rw-r--r--arch/tile/kernel/head_32.S5
-rw-r--r--arch/tile/kernel/intvec_32.S101
-rw-r--r--arch/tile/kernel/irq.c16
-rw-r--r--arch/tile/kernel/messaging.c2
-rw-r--r--arch/tile/kernel/process.c50
-rw-r--r--arch/tile/kernel/ptrace.c87
-rw-r--r--arch/tile/kernel/regs_32.S2
-rw-r--r--arch/tile/kernel/setup.c36
-rw-r--r--arch/tile/kernel/signal.c6
-rw-r--r--arch/tile/kernel/single_step.c73
-rw-r--r--arch/tile/kernel/smp.c2
-rw-r--r--arch/tile/kernel/stack.c35
-rw-r--r--arch/tile/kernel/sys.c9
-rw-r--r--arch/tile/kernel/traps.c4
-rw-r--r--arch/tile/kvm/Kconfig38
-rw-r--r--arch/tile/lib/Makefile4
-rw-r--r--arch/tile/lib/atomic_32.c8
-rw-r--r--arch/tile/lib/exports.c3
-rw-r--r--arch/tile/lib/memcpy_32.S206
-rw-r--r--arch/tile/lib/memmove.c (renamed from arch/tile/lib/memmove_32.c)0
-rw-r--r--arch/tile/lib/memset_32.c1
-rw-r--r--arch/tile/lib/strlen_32.c2
-rw-r--r--arch/tile/mm/fault.c12
-rw-r--r--arch/tile/mm/highmem.c86
-rw-r--r--arch/tile/mm/homecache.c11
-rw-r--r--arch/tile/mm/init.c2
-rw-r--r--arch/um/Kconfig.um6
-rw-r--r--arch/um/defconfig1
-rw-r--r--arch/um/include/asm/dma-mapping.h112
-rw-r--r--arch/um/include/asm/pgtable.h2
-rw-r--r--arch/um/include/asm/system.h49
-rw-r--r--arch/um/kernel/dyn.lds.S14
-rw-r--r--arch/um/kernel/irq.c15
-rw-r--r--arch/um/kernel/ptrace.c23
-rw-r--r--arch/um/kernel/uml.lds.S19
-rw-r--r--arch/um/os-Linux/time.c2
-rw-r--r--arch/um/sys-i386/ptrace.c4
-rw-r--r--arch/um/sys-x86_64/ptrace.c11
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/boot/compressed/misc.c29
-rw-r--r--arch/x86/include/asm/calling.h52
-rw-r--r--arch/x86/include/asm/entry_arch.h19
-rw-r--r--arch/x86/include/asm/highmem.h11
-rw-r--r--arch/x86/include/asm/iomap.h4
-rw-r--r--arch/x86/include/asm/irq.h2
-rw-r--r--arch/x86/include/asm/kvm_emulate.h30
-rw-r--r--arch/x86/include/asm/kvm_host.h81
-rw-r--r--arch/x86/include/asm/kvm_para.h6
-rw-r--r--arch/x86/include/asm/msr-index.h2
-rw-r--r--arch/x86/include/asm/olpc.h2
-rw-r--r--arch/x86/include/asm/perf_event.h19
-rw-r--r--arch/x86/include/asm/pgtable_32.h14
-rw-r--r--arch/x86/include/asm/pgtable_64.h2
-rw-r--r--arch/x86/include/asm/pvclock.h38
-rw-r--r--arch/x86/include/asm/segment.h32
-rw-r--r--arch/x86/include/asm/smp.h9
-rw-r--r--arch/x86/include/asm/xen/hypercall.h17
-rw-r--r--arch/x86/include/asm/xen/page.h12
-rw-r--r--arch/x86/kernel/acpi/sleep.c1
-rw-r--r--arch/x86/kernel/apm_32.c4
-rw-r--r--arch/x86/kernel/asm-offsets_32.c4
-rw-r--r--arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c1
-rw-r--r--arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c2
-rw-r--r--arch/x86/kernel/cpu/cpufreq/longrun.c4
-rw-r--r--arch/x86/kernel/cpu/intel.c4
-rw-r--r--arch/x86/kernel/cpu/intel_cacheinfo.c1
-rw-r--r--arch/x86/kernel/cpu/perf_event.c26
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_ds.c216
-rw-r--r--arch/x86/kernel/crash_dump_32.c2
-rw-r--r--arch/x86/kernel/dumpstack_32.c6
-rw-r--r--arch/x86/kernel/dumpstack_64.c8
-rw-r--r--arch/x86/kernel/entry_32.S6
-rw-r--r--arch/x86/kernel/entry_64.S20
-rw-r--r--arch/x86/kernel/hpet.c2
-rw-r--r--arch/x86/kernel/irq_32.c12
-rw-r--r--arch/x86/kernel/kvmclock.c6
-rw-r--r--arch/x86/kernel/microcode_core.c2
-rw-r--r--arch/x86/kernel/microcode_intel.c2
-rw-r--r--arch/x86/kernel/ptrace.c17
-rw-r--r--arch/x86/kernel/pvclock.c3
-rw-r--r--arch/x86/kernel/quirks.c2
-rw-r--r--arch/x86/kernel/reboot.c2
-rw-r--r--arch/x86/kernel/smp.c15
-rw-r--r--arch/x86/kernel/smpboot.c3
-rw-r--r--arch/x86/kernel/tlb_uv.c11
-rw-r--r--arch/x86/kernel/traps.c1
-rw-r--r--arch/x86/kernel/vm86_32.c10
-rw-r--r--arch/x86/kvm/Kconfig7
-rw-r--r--arch/x86/kvm/emulate.c2262
-rw-r--r--arch/x86/kvm/i8254.c11
-rw-r--r--arch/x86/kvm/i8259.c25
-rw-r--r--arch/x86/kvm/irq.c9
-rw-r--r--arch/x86/kvm/irq.h2
-rw-r--r--arch/x86/kvm/kvm_cache_regs.h9
-rw-r--r--arch/x86/kvm/lapic.c15
-rw-r--r--arch/x86/kvm/mmu.c918
-rw-r--r--arch/x86/kvm/mmu.h9
-rw-r--r--arch/x86/kvm/mmu_audit.c299
-rw-r--r--arch/x86/kvm/mmutrace.h19
-rw-r--r--arch/x86/kvm/paging_tmpl.h202
-rw-r--r--arch/x86/kvm/svm.c283
-rw-r--r--arch/x86/kvm/timer.c2
-rw-r--r--arch/x86/kvm/vmx.c219
-rw-r--r--arch/x86/kvm/x86.c780
-rw-r--r--arch/x86/kvm/x86.h8
-rw-r--r--arch/x86/mm/fault.c63
-rw-r--r--arch/x86/mm/highmem_32.c76
-rw-r--r--arch/x86/mm/init_64.c1
-rw-r--r--arch/x86/mm/iomap_32.c43
-rw-r--r--arch/x86/oprofile/nmi_int.c6
-rw-r--r--arch/x86/oprofile/op_model_amd.c146
-rw-r--r--arch/x86/xen/Kconfig11
-rw-r--r--arch/x86/xen/enlighten.c19
-rw-r--r--arch/x86/xen/mmu.c501
-rw-r--r--arch/x86/xen/mmu.h1
-rw-r--r--arch/x86/xen/setup.c112
-rw-r--r--arch/x86/xen/smp.c6
-rw-r--r--arch/x86/xen/xen-ops.h3
-rw-r--r--arch/xtensa/include/asm/pgtable.h3
-rw-r--r--arch/xtensa/include/asm/uaccess.h2
-rw-r--r--arch/xtensa/kernel/ptrace.c14
-rw-r--r--block/blk-core.c28
-rw-r--r--block/blk-merge.c2
-rw-r--r--block/blk-sysfs.c2
-rw-r--r--block/blk.h4
-rw-r--r--block/genhd.c14
-rw-r--r--crypto/Kconfig21
-rw-r--r--crypto/async_tx/Kconfig13
-rw-r--r--crypto/async_tx/async_memcpy.c2
-rw-r--r--crypto/blkcipher.c2
-rw-r--r--crypto/cryptd.c206
-rw-r--r--drivers/Makefile3
-rw-r--r--drivers/acpi/Kconfig13
-rw-r--r--drivers/acpi/ac.c14
-rw-r--r--drivers/acpi/acpica/Makefile5
-rw-r--r--drivers/acpi/acpica/acdebug.h2
-rw-r--r--drivers/acpi/acpica/acevents.h5
-rw-r--r--drivers/acpi/acpica/acglobal.h9
-rw-r--r--drivers/acpi/acpica/achware.h7
-rw-r--r--drivers/acpi/acpica/aclocal.h15
-rw-r--r--drivers/acpi/acpica/acmacros.h4
-rw-r--r--drivers/acpi/acpica/acnamesp.h12
-rw-r--r--drivers/acpi/acpica/acobject.h2
-rw-r--r--drivers/acpi/acpica/acutils.h56
-rw-r--r--drivers/acpi/acpica/dsmethod.c2
-rw-r--r--drivers/acpi/acpica/dswexec.c19
-rw-r--r--drivers/acpi/acpica/evevent.c41
-rw-r--r--drivers/acpi/acpica/evgpeblk.c47
-rw-r--r--drivers/acpi/acpica/evgpeinit.c31
-rw-r--r--drivers/acpi/acpica/evmisc.c2
-rw-r--r--drivers/acpi/acpica/evrgnini.c14
-rw-r--r--drivers/acpi/acpica/evxface.c19
-rw-r--r--drivers/acpi/acpica/evxfevnt.c61
-rw-r--r--drivers/acpi/acpica/evxfregn.c6
-rw-r--r--drivers/acpi/acpica/exfldio.c75
-rw-r--r--drivers/acpi/acpica/exmutex.c10
-rw-r--r--drivers/acpi/acpica/exprep.c45
-rw-r--r--drivers/acpi/acpica/exregion.c4
-rw-r--r--drivers/acpi/acpica/hwpci.c412
-rw-r--r--drivers/acpi/acpica/nsrepair2.c163
-rw-r--r--drivers/acpi/acpica/nsutils.c98
-rw-r--r--drivers/acpi/acpica/tbfadt.c4
-rw-r--r--drivers/acpi/acpica/utdebug.c7
-rw-r--r--drivers/acpi/acpica/uteval.c147
-rw-r--r--drivers/acpi/acpica/utglobal.c9
-rw-r--r--drivers/acpi/acpica/utids.c45
-rw-r--r--drivers/acpi/acpica/utinit.c4
-rw-r--r--drivers/acpi/acpica/utmath.c23
-rw-r--r--drivers/acpi/acpica/utmisc.c162
-rw-r--r--drivers/acpi/acpica/utmutex.c37
-rw-r--r--drivers/acpi/acpica/utosi.c380
-rw-r--r--drivers/acpi/acpica/utxface.c138
-rw-r--r--drivers/acpi/acpica/utxferror.c415
-rw-r--r--drivers/acpi/battery.c94
-rw-r--r--drivers/acpi/bus.c7
-rw-r--r--drivers/acpi/button.c4
-rw-r--r--drivers/acpi/dock.c7
-rw-r--r--drivers/acpi/ec.c9
-rw-r--r--drivers/acpi/fan.c139
-rw-r--r--drivers/acpi/osl.c463
-rw-r--r--drivers/acpi/pci_irq.c1
-rw-r--r--drivers/acpi/pci_link.c1
-rw-r--r--drivers/acpi/pci_root.c1
-rw-r--r--drivers/acpi/power.c167
-rw-r--r--drivers/acpi/processor_driver.c22
-rw-r--r--drivers/acpi/processor_idle.c2
-rw-r--r--drivers/acpi/processor_thermal.c178
-rw-r--r--drivers/acpi/processor_throttling.c4
-rw-r--r--drivers/acpi/sbs.c25
-rw-r--r--drivers/acpi/scan.c46
-rw-r--r--drivers/acpi/sleep.c28
-rw-r--r--drivers/acpi/sleep.h1
-rw-r--r--drivers/acpi/thermal.c436
-rw-r--r--drivers/acpi/video.c771
-rw-r--r--drivers/ata/pata_bf54x.c2
-rw-r--r--drivers/ata/pata_it821x.c4
-rw-r--r--drivers/atm/Kconfig2
-rw-r--r--drivers/atm/Makefile2
-rw-r--r--drivers/atm/eni.c7
-rw-r--r--drivers/atm/firestream.c4
-rw-r--r--drivers/atm/horizon.c6
-rw-r--r--drivers/atm/idt77252.c6
-rw-r--r--drivers/atm/iphase.c2
-rw-r--r--drivers/base/core.c2
-rw-r--r--drivers/base/node.c14
-rw-r--r--drivers/base/platform.c1
-rw-r--r--drivers/base/power/runtime.c2
-rw-r--r--drivers/block/aoe/aoeblk.c4
-rw-r--r--drivers/block/aoe/aoedev.c4
-rw-r--r--drivers/block/cciss.c37
-rw-r--r--drivers/block/drbd/drbd_main.c2
-rw-r--r--drivers/block/loop.c6
-rw-r--r--drivers/block/xsysace.c3
-rw-r--r--drivers/block/z2ram.c6
-rw-r--r--drivers/bluetooth/btmrvl_main.c4
-rw-r--r--drivers/bluetooth/btsdio.c8
-rw-r--r--drivers/bluetooth/btusb.c6
-rw-r--r--drivers/bluetooth/hci_ldisc.c2
-rw-r--r--drivers/char/agp/Kconfig2
-rw-r--r--drivers/char/agp/Makefile1
-rw-r--r--drivers/char/agp/agp.h5
-rw-r--r--drivers/char/agp/amd-k7-agp.c6
-rw-r--r--drivers/char/agp/backend.c22
-rw-r--r--drivers/char/agp/generic.c8
-rw-r--r--drivers/char/agp/i460-agp.c2
-rw-r--r--drivers/char/agp/intel-agp.c201
-rw-r--r--drivers/char/agp/intel-agp.h43
-rw-r--r--drivers/char/agp/intel-gtt.c1612
-rw-r--r--drivers/char/agp/parisc-agp.c4
-rw-r--r--drivers/char/apm-emulation.c4
-rw-r--r--drivers/char/applicom.c1
-rw-r--r--drivers/char/hpet.c40
-rw-r--r--drivers/char/hvc_console.c1
-rw-r--r--drivers/char/hvc_iucv.c4
-rw-r--r--drivers/char/hvc_tile.c5
-rw-r--r--drivers/char/hvc_xen.c3
-rw-r--r--drivers/char/ip2/Makefile2
-rw-r--r--drivers/char/ipmi/Makefile2
-rw-r--r--drivers/char/ipmi/ipmi_bt_sm.c2
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c4
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c4
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c47
-rw-r--r--drivers/char/keyboard.c31
-rw-r--r--drivers/char/mem.c4
-rw-r--r--drivers/char/mmtimer.c60
-rw-r--r--drivers/char/mwave/Makefile4
-rw-r--r--drivers/char/mxser.c4
-rw-r--r--drivers/char/n_r3964.c1
-rw-r--r--drivers/char/pcmcia/Kconfig4
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c2
-rw-r--r--drivers/char/pcmcia/ipwireless/Makefile2
-rw-r--r--drivers/char/ppdev.c1
-rw-r--r--drivers/char/ramoops.c30
-rw-r--r--drivers/char/rio/Makefile2
-rw-r--r--drivers/char/rocket.c5
-rw-r--r--drivers/char/stallion.c4
-rw-r--r--drivers/char/synclink_gt.c142
-rw-r--r--drivers/char/sysrq.c15
-rw-r--r--drivers/char/tpm/Kconfig2
-rw-r--r--drivers/char/tpm/tpm_infineon.c2
-rw-r--r--drivers/char/vt_ioctl.c11
-rw-r--r--drivers/clocksource/sh_cmt.c12
-rw-r--r--drivers/connector/cn_queue.c75
-rw-r--r--drivers/connector/connector.c9
-rw-r--r--drivers/cpufreq/cpufreq.c4
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c42
-rw-r--r--drivers/crypto/Kconfig9
-rw-r--r--drivers/crypto/Makefile3
-rw-r--r--drivers/crypto/amcc/Makefile2
-rw-r--r--drivers/crypto/hifn_795x.c7
-rw-r--r--drivers/crypto/omap-aes.c948
-rw-r--r--drivers/crypto/omap-sham.c6
-rw-r--r--drivers/crypto/talitos.c29
-rw-r--r--drivers/dma/Kconfig31
-rw-r--r--drivers/dma/Makefile3
-rw-r--r--drivers/dma/amba-pl08x.c2167
-rw-r--r--drivers/dma/coh901318.c2
-rw-r--r--drivers/dma/dmaengine.c8
-rw-r--r--drivers/dma/fsldma.c328
-rw-r--r--drivers/dma/imx-dma.c424
-rw-r--r--drivers/dma/imx-sdma.c1392
-rw-r--r--drivers/dma/intel_mid_dma.c476
-rw-r--r--drivers/dma/intel_mid_dma_regs.h53
-rw-r--r--drivers/dma/pch_dma.c1
-rw-r--r--drivers/dma/ste_dma40.c1023
-rw-r--r--drivers/dma/ste_dma40_ll.c180
-rw-r--r--drivers/dma/ste_dma40_ll.h86
-rw-r--r--drivers/dma/timb_dma.c2
-rw-r--r--drivers/edac/Kconfig7
-rw-r--r--drivers/edac/Makefile1
-rw-r--r--drivers/edac/edac_core.h11
-rw-r--r--drivers/edac/edac_device_sysfs.c2
-rw-r--r--drivers/edac/edac_mc.c12
-rw-r--r--drivers/edac/edac_mc_sysfs.c82
-rw-r--r--drivers/edac/i7300_edac.c1247
-rw-r--r--drivers/edac/i7core_edac.c432
-rw-r--r--drivers/edac/i82443bxgx_edac.c2
-rw-r--r--drivers/firewire/Kconfig5
-rw-r--r--drivers/firewire/Makefile1
-rw-r--r--drivers/firewire/init_ohci1394_dma.c (renamed from drivers/ieee1394/init_ohci1394_dma.c)76
-rw-r--r--drivers/firewire/net.c13
-rw-r--r--drivers/firmware/Kconfig3
-rw-r--r--drivers/firmware/dmi_scan.c32
-rw-r--r--drivers/firmware/edd.c2
-rw-r--r--drivers/firmware/pcdp.h4
-rw-r--r--drivers/gpio/74x164.c182
-rw-r--r--drivers/gpio/Kconfig28
-rw-r--r--drivers/gpio/Makefile3
-rw-r--r--drivers/gpio/adp5588-gpio.c277
-rw-r--r--drivers/gpio/basic_mmio_gpio.c297
-rw-r--r--drivers/gpio/langwell_gpio.c89
-rw-r--r--drivers/gpio/pca953x.c13
-rw-r--r--drivers/gpio/pch_gpio.c312
-rw-r--r--drivers/gpio/timbgpio.c21
-rw-r--r--drivers/gpio/xilinx_gpio.c6
-rw-r--r--drivers/gpu/Makefile2
-rw-r--r--drivers/gpu/drm/Makefile2
-rw-r--r--drivers/gpu/drm/drm_agpsupport.c40
-rw-r--r--drivers/gpu/drm/drm_context.c8
-rw-r--r--drivers/gpu/drm/drm_crtc.c3
-rw-r--r--drivers/gpu/drm/drm_debugfs.c1
-rw-r--r--drivers/gpu/drm/drm_drawable.c198
-rw-r--r--drivers/gpu/drm/drm_drv.c10
-rw-r--r--drivers/gpu/drm/drm_edid.c93
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c32
-rw-r--r--drivers/gpu/drm/drm_gem.c14
-rw-r--r--drivers/gpu/drm/drm_info.c14
-rw-r--r--drivers/gpu/drm/drm_lock.c30
-rw-r--r--drivers/gpu/drm/drm_memory.c14
-rw-r--r--drivers/gpu/drm/drm_modes.c2
-rw-r--r--drivers/gpu/drm/drm_proc.c14
-rw-r--r--drivers/gpu/drm/drm_scatter.c2
-rw-r--r--drivers/gpu/drm/drm_stub.c4
-rw-r--r--drivers/gpu/drm/drm_vm.c13
-rw-r--r--drivers/gpu/drm/i810/i810_drv.c2
-rw-r--r--drivers/gpu/drm/i830/i830_drv.c2
-rw-r--r--drivers/gpu/drm/i915/Makefile4
-rw-r--r--drivers/gpu/drm/i915/dvo_ch7017.c66
-rw-r--r--drivers/gpu/drm/i915/dvo_ch7xxx.c10
-rw-r--r--drivers/gpu/drm/i915/dvo_ivch.c10
-rw-r--r--drivers/gpu/drm/i915/dvo_sil164.c10
-rw-r--r--drivers/gpu/drm/i915/dvo_tfp410.c10
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c336
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c360
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c214
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h271
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c2230
-rw-r--r--drivers/gpu/drm/i915/i915_gem_debug.c148
-rw-r--r--drivers/gpu/drm/i915/i915_gem_evict.c72
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c54
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c264
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h335
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c28
-rw-r--r--drivers/gpu/drm/i915/intel_acpi.c286
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c234
-rw-r--r--drivers/gpu/drm/i915/intel_bios.h6
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c127
-rw-r--r--drivers/gpu/drm/i915/intel_display.c2357
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c658
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h160
-rw-r--r--drivers/gpu/drm/i915/intel_dvo.c69
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c29
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c193
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c484
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c435
-rw-r--r--drivers/gpu/drm/i915/intel_modes.c16
-rw-r--r--drivers/gpu/drm/i915/intel_opregion.c (renamed from drivers/gpu/drm/i915/i915_opregion.c)181
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c1001
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c109
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c457
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h81
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c1076
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c165
-rw-r--r--drivers/gpu/drm/mga/mga_drv.c2
-rw-r--r--drivers/gpu/drm/nouveau/Kconfig1
-rw-r--r--drivers/gpu/drm/nouveau/Makefile6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c374
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.h43
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c290
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_calc.c10
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_channel.c23
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c54
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_debugfs.c16
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.c32
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c10
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c23
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h253
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_encoder.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c318
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_grctx.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_hw.c45
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_i2c.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_i2c.h6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_irq.c123
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c363
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_notifier.c9
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_object.c776
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_perf.c205
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.c518
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.h74
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ramht.c289
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ramht.h55
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_reg.h9
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_sgdma.c68
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c123
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_temp.c309
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_volt.c212
-rw-r--r--drivers/gpu/drm/nouveau/nv04_crtc.c60
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dac.c11
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dfp.c39
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fbcon.c9
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fifo.c68
-rw-r--r--drivers/gpu/drm/nouveau/nv04_instmem.c140
-rw-r--r--drivers/gpu/drm/nouveau/nv04_pm.c81
-rw-r--r--drivers/gpu/drm/nouveau/nv04_tv.c10
-rw-r--r--drivers/gpu/drm/nouveau/nv10_fifo.c19
-rw-r--r--drivers/gpu/drm/nouveau/nv10_graph.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv17_tv.c110
-rw-r--r--drivers/gpu/drm/nouveau/nv17_tv.h15
-rw-r--r--drivers/gpu/drm/nouveau/nv17_tv_modes.c48
-rw-r--r--drivers/gpu/drm/nouveau/nv20_graph.c506
-rw-r--r--drivers/gpu/drm/nouveau/nv40_fifo.c20
-rw-r--r--drivers/gpu/drm/nouveau/nv40_graph.c16
-rw-r--r--drivers/gpu/drm/nouveau/nv40_grctx.c6
-rw-r--r--drivers/gpu/drm/nouveau/nv50_crtc.c87
-rw-r--r--drivers/gpu/drm/nouveau/nv50_cursor.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_dac.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c92
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fb.c40
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fbcon.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fifo.c286
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c51
-rw-r--r--drivers/gpu/drm/nouveau/nv50_grctx.c3305
-rw-r--r--drivers/gpu/drm/nouveau/nv50_instmem.c418
-rw-r--r--drivers/gpu/drm/nouveau/nv50_pm.c131
-rw-r--r--drivers/gpu/drm/nouveau/nv50_sor.c4
-rw-r--r--drivers/gpu/drm/nouveau/nva3_pm.c95
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_fifo.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_instmem.c13
-rw-r--r--drivers/gpu/drm/nouveau/nvreg.h1
-rw-r--r--drivers/gpu/drm/r128/r128_drv.c2
-rw-r--r--drivers/gpu/drm/radeon/Makefile2
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c406
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c564
-rw-r--r--drivers/gpu/drm/radeon/evergreen_blit_kms.c774
-rw-r--r--drivers/gpu/drm/radeon/evergreen_blit_shaders.c348
-rw-r--r--drivers/gpu/drm/radeon/evergreen_blit_shaders.h35
-rw-r--r--drivers/gpu/drm/radeon/evergreend.h20
-rw-r--r--drivers/gpu/drm/radeon/r100.c103
-rw-r--r--drivers/gpu/drm/radeon/r100_track.h1
-rw-r--r--drivers/gpu/drm/radeon/r200.c2
-rw-r--r--drivers/gpu/drm/radeon/r300.c15
-rw-r--r--drivers/gpu/drm/radeon/r420.c16
-rw-r--r--drivers/gpu/drm/radeon/r520.c11
-rw-r--r--drivers/gpu/drm/radeon/r600.c179
-rw-r--r--drivers/gpu/drm/radeon/r600_blit_kms.c51
-rw-r--r--drivers/gpu/drm/radeon/r600_cs.c50
-rw-r--r--drivers/gpu/drm/radeon/r600d.h21
-rw-r--r--drivers/gpu/drm/radeon/radeon.h23
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h11
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c129
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c65
-rw-r--r--drivers/gpu/drm/radeon/radeon_cs.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_cursor.c15
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c83
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c405
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c11
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c16
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_fence.c10
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_crtc.c49
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h54
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c70
-rw-r--r--drivers/gpu/drm/radeon/radeon_reg.h1
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c12
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c36
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/evergreen8
-rw-r--r--drivers/gpu/drm/radeon/rs400.c15
-rw-r--r--drivers/gpu/drm/radeon/rs600.c15
-rw-r--r--drivers/gpu/drm/radeon/rs690.c15
-rw-r--r--drivers/gpu/drm/radeon/rv515.c15
-rw-r--r--drivers/gpu/drm/radeon/rv770.c38
-rw-r--r--drivers/gpu/drm/savage/savage_drv.c2
-rw-r--r--drivers/gpu/drm/sis/sis_drv.c3
-rw-r--r--drivers/gpu/drm/tdfx/tdfx_drv.c2
-rw-r--r--drivers/gpu/drm/ttm/Makefile3
-rw-r--r--drivers/gpu/drm/ttm/ttm_agp_backend.c3
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c305
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_manager.c148
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c20
-rw-r--r--drivers/gpu/drm/via/via_drv.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/Makefile2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c84
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c130
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h40
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c29
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fb.c13
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c38
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c137
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c200
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c28
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c75
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c2
-rw-r--r--drivers/gpu/stub/Kconfig13
-rw-r--r--drivers/gpu/stub/Makefile1
-rw-r--r--drivers/gpu/stub/poulsbo.c64
-rw-r--r--drivers/hid/Kconfig91
-rw-r--r--drivers/hid/Makefile6
-rw-r--r--drivers/hid/hid-3m-pct.c127
-rw-r--r--drivers/hid/hid-a4tech.c2
-rw-r--r--drivers/hid/hid-apple.c7
-rw-r--r--drivers/hid/hid-cherry.c7
-rw-r--r--drivers/hid/hid-core.c28
-rw-r--r--drivers/hid/hid-cypress.c9
-rw-r--r--drivers/hid/hid-debug.c2
-rw-r--r--drivers/hid/hid-egalax.c16
-rw-r--r--drivers/hid/hid-elecom.c7
-rw-r--r--drivers/hid/hid-ids.h27
-rw-r--r--drivers/hid/hid-input.c195
-rw-r--r--drivers/hid/hid-kye.c7
-rw-r--r--drivers/hid/hid-lg.c49
-rw-r--r--drivers/hid/hid-lg.h6
-rw-r--r--drivers/hid/hid-lg2ff.c4
-rw-r--r--drivers/hid/hid-lg4ff.c136
-rw-r--r--drivers/hid/hid-magicmouse.c325
-rw-r--r--drivers/hid/hid-microsoft.c7
-rw-r--r--drivers/hid/hid-monterey.c7
-rw-r--r--drivers/hid/hid-ntrig.c69
-rw-r--r--drivers/hid/hid-ortek.c7
-rw-r--r--drivers/hid/hid-petalynx.c7
-rw-r--r--drivers/hid/hid-prodikeys.c7
-rw-r--r--drivers/hid/hid-roccat-pyra.c968
-rw-r--r--drivers/hid/hid-roccat-pyra.h186
-rw-r--r--drivers/hid/hid-samsung.c20
-rw-r--r--drivers/hid/hid-sony.c56
-rw-r--r--drivers/hid/hid-stantum.c2
-rw-r--r--drivers/hid/hid-sunplus.c7
-rw-r--r--drivers/hid/hid-uclogic.c623
-rw-r--r--drivers/hid/hid-waltop.c1099
-rw-r--r--drivers/hid/hid-zydacron.c7
-rw-r--r--drivers/hid/hidraw.c14
-rw-r--r--drivers/hid/usbhid/hid-core.c9
-rw-r--r--drivers/hid/usbhid/hid-quirks.c6
-rw-r--r--drivers/hid/usbhid/hiddev.c40
-rw-r--r--drivers/hwmon/Kconfig40
-rw-r--r--drivers/hwmon/Makefile3
-rw-r--r--drivers/hwmon/adm1025.c2
-rw-r--r--drivers/hwmon/adm1026.c2
-rw-r--r--drivers/hwmon/coretemp.c28
-rw-r--r--drivers/hwmon/f75375s.c4
-rw-r--r--drivers/hwmon/g760a.c2
-rw-r--r--drivers/hwmon/gpio-fan.c558
-rw-r--r--drivers/hwmon/hp_accel.c32
-rw-r--r--drivers/hwmon/hwmon-vid.c2
-rw-r--r--drivers/hwmon/lis3lv02d.c364
-rw-r--r--drivers/hwmon/lis3lv02d.h47
-rw-r--r--drivers/hwmon/lis3lv02d_i2c.c132
-rw-r--r--drivers/hwmon/lis3lv02d_spi.c5
-rw-r--r--drivers/hwmon/ltc4261.c315
-rw-r--r--drivers/hwmon/pkgtemp.c32
-rw-r--r--drivers/hwmon/via-cputemp.c11
-rw-r--r--drivers/i2c/Kconfig3
-rw-r--r--drivers/i2c/Makefile4
-rw-r--r--drivers/i2c/algos/Kconfig12
-rw-r--r--drivers/i2c/algos/Makefile4
-rw-r--r--drivers/i2c/busses/Makefile4
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c163
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c1
-rw-r--r--drivers/i2c/busses/i2c-nuc900.c1
-rw-r--r--drivers/i2c/busses/i2c-pca-platform.c2
-rw-r--r--drivers/i2c/busses/i2c-pxa.c1
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c1
-rw-r--r--drivers/i2c/busses/i2c-sh7760.c4
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c23
-rw-r--r--drivers/i2c/busses/i2c-viapro.c8
-rw-r--r--drivers/i2c/busses/scx200_acb.c3
-rw-r--r--drivers/i2c/i2c-core.c45
-rw-r--r--drivers/i2c/i2c-dev.c13
-rw-r--r--drivers/i2c/muxes/Kconfig10
-rw-r--r--drivers/i2c/muxes/Makefile5
-rw-r--r--drivers/i2c/muxes/pca9541.c411
-rw-r--r--drivers/i2c/muxes/pca954x.c8
-rw-r--r--drivers/ide/hpt366.c2
-rw-r--r--drivers/ide/ht6560b.c1
-rw-r--r--drivers/ide/ide-disk.c3
-rw-r--r--drivers/idle/intel_idle.c61
-rw-r--r--drivers/ieee1394/Kconfig182
-rw-r--r--drivers/ieee1394/Makefile18
-rw-r--r--drivers/ieee1394/config_roms.c194
-rw-r--r--drivers/ieee1394/config_roms.h19
-rw-r--r--drivers/ieee1394/csr.c843
-rw-r--r--drivers/ieee1394/csr.h99
-rw-r--r--drivers/ieee1394/csr1212.c1467
-rw-r--r--drivers/ieee1394/csr1212.h383
-rw-r--r--drivers/ieee1394/dma.c289
-rw-r--r--drivers/ieee1394/dma.h89
-rw-r--r--drivers/ieee1394/dv1394-private.h587
-rw-r--r--drivers/ieee1394/dv1394.c2584
-rw-r--r--drivers/ieee1394/dv1394.h305
-rw-r--r--drivers/ieee1394/eth1394.c1736
-rw-r--r--drivers/ieee1394/eth1394.h234
-rw-r--r--drivers/ieee1394/highlevel.c691
-rw-r--r--drivers/ieee1394/highlevel.h141
-rw-r--r--drivers/ieee1394/hosts.c249
-rw-r--r--drivers/ieee1394/hosts.h201
-rw-r--r--drivers/ieee1394/ieee1394-ioctl.h106
-rw-r--r--drivers/ieee1394/ieee1394.h220
-rw-r--r--drivers/ieee1394/ieee1394_core.c1380
-rw-r--r--drivers/ieee1394/ieee1394_core.h172
-rw-r--r--drivers/ieee1394/ieee1394_hotplug.h19
-rw-r--r--drivers/ieee1394/ieee1394_transactions.c595
-rw-r--r--drivers/ieee1394/ieee1394_transactions.h40
-rw-r--r--drivers/ieee1394/ieee1394_types.h69
-rw-r--r--drivers/ieee1394/iso.c568
-rw-r--r--drivers/ieee1394/iso.h195
-rw-r--r--drivers/ieee1394/nodemgr.c1901
-rw-r--r--drivers/ieee1394/nodemgr.h186
-rw-r--r--drivers/ieee1394/ohci1394.c3590
-rw-r--r--drivers/ieee1394/ohci1394.h453
-rw-r--r--drivers/ieee1394/pcilynx.c1554
-rw-r--r--drivers/ieee1394/pcilynx.h468
-rw-r--r--drivers/ieee1394/raw1394-private.h81
-rw-r--r--drivers/ieee1394/raw1394.c3096
-rw-r--r--drivers/ieee1394/raw1394.h191
-rw-r--r--drivers/ieee1394/sbp2.c2138
-rw-r--r--drivers/ieee1394/sbp2.h346
-rw-r--r--drivers/ieee1394/video1394.c1528
-rw-r--r--drivers/ieee1394/video1394.h67
-rw-r--r--drivers/infiniband/Kconfig4
-rw-r--r--drivers/infiniband/core/agent.c29
-rw-r--r--drivers/infiniband/core/cma.c313
-rw-r--r--drivers/infiniband/core/iwcm.c4
-rw-r--r--drivers/infiniband/core/mad.c27
-rw-r--r--drivers/infiniband/core/multicast.c23
-rw-r--r--drivers/infiniband/core/sa_query.c30
-rw-r--r--drivers/infiniband/core/sysfs.c15
-rw-r--r--drivers/infiniband/core/ucma.c92
-rw-r--r--drivers/infiniband/core/ud_header.c140
-rw-r--r--drivers/infiniband/core/user_mad.c2
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c2
-rw-r--r--drivers/infiniband/core/verbs.c16
-rw-r--r--drivers/infiniband/hw/amso1100/Kbuild4
-rw-r--r--drivers/infiniband/hw/amso1100/c2_intr.c4
-rw-r--r--drivers/infiniband/hw/cxgb3/Kconfig2
-rw-r--r--drivers/infiniband/hw/cxgb3/Makefile6
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c1
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_wr.h16
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c4
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_ev.c17
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c24
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c25
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_user.h8
-rw-r--r--drivers/infiniband/hw/cxgb4/Kconfig2
-rw-r--r--drivers/infiniband/hw/cxgb4/Makefile2
-rw-r--r--drivers/infiniband/hw/cxgb4/cm.c178
-rw-r--r--drivers/infiniband/hw/cxgb4/cq.c28
-rw-r--r--drivers/infiniband/hw/cxgb4/device.c191
-rw-r--r--drivers/infiniband/hw/cxgb4/ev.c2
-rw-r--r--drivers/infiniband/hw/cxgb4/iw_cxgb4.h68
-rw-r--r--drivers/infiniband/hw/cxgb4/mem.c11
-rw-r--r--drivers/infiniband/hw/cxgb4/provider.c44
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c283
-rw-r--r--drivers/infiniband/hw/cxgb4/resource.c62
-rw-r--r--drivers/infiniband/hw/cxgb4/t4.h44
-rw-r--r--drivers/infiniband/hw/cxgb4/user.h7
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.c6
-rw-r--r--drivers/infiniband/hw/ipath/Makefile2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_fs.c1
-rw-r--r--drivers/infiniband/hw/mlx4/Kconfig1
-rw-r--r--drivers/infiniband/hw/mlx4/ah.c163
-rw-r--r--drivers/infiniband/hw/mlx4/mad.c32
-rw-r--r--drivers/infiniband/hw/mlx4/main.c553
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h32
-rw-r--r--drivers/infiniband/hw/mlx4/mr.c2
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c195
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c2
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c7
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c1
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c20
-rw-r--r--drivers/infiniband/hw/qib/qib.h2
-rw-r--r--drivers/infiniband/hw/qib/qib_file_ops.c4
-rw-r--r--drivers/infiniband/hw/qib/qib_fs.c1
-rw-r--r--drivers/infiniband/hw/qib/qib_init.c1
-rw-r--r--drivers/infiniband/hw/qib/qib_pcie.c8
-rw-r--r--drivers/infiniband/hw/qib/qib_rc.c5
-rw-r--r--drivers/infiniband/hw/qib/qib_uc.c6
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c14
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c6
-rw-r--r--drivers/infiniband/ulp/iser/Kconfig2
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c236
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h21
-rw-r--r--drivers/input/evdev.c100
-rw-r--r--drivers/input/gameport/emu10k1-gp.c44
-rw-r--r--drivers/input/gameport/fm801-gp.c10
-rw-r--r--drivers/input/input.c198
-rw-r--r--drivers/input/joystick/gamecon.c3
-rw-r--r--drivers/input/keyboard/Kconfig28
-rw-r--r--drivers/input/keyboard/Makefile3
-rw-r--r--drivers/input/keyboard/adp5588-keys.c2
-rw-r--r--drivers/input/keyboard/hil_kbd.c2
-rw-r--r--drivers/input/keyboard/nomadik-ske-keypad.c408
-rw-r--r--drivers/input/keyboard/omap4-keypad.c318
-rw-r--r--drivers/input/keyboard/tnetv107x-keypad.c340
-rw-r--r--drivers/input/keyboard/twl4030_keypad.c7
-rw-r--r--drivers/input/misc/Kconfig10
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/ab8500-ponkey.c157
-rw-r--r--drivers/input/misc/ati_remote2.c93
-rw-r--r--drivers/input/misc/cm109.c2
-rw-r--r--drivers/input/misc/powermate.c2
-rw-r--r--drivers/input/misc/twl4030-vibra.c4
-rw-r--r--drivers/input/mouse/Kconfig1
-rw-r--r--drivers/input/mouse/elantech.c2
-rw-r--r--drivers/input/mouse/psmouse-base.c4
-rw-r--r--drivers/input/mouse/synaptics.c38
-rw-r--r--drivers/input/mouse/synaptics.h2
-rw-r--r--drivers/input/mouse/touchkit_ps2.c4
-rw-r--r--drivers/input/mouse/trackpoint.c2
-rw-r--r--drivers/input/mousedev.c2
-rw-r--r--drivers/input/serio/Kconfig9
-rw-r--r--drivers/input/serio/Makefile1
-rw-r--r--drivers/input/serio/i8042.c2
-rw-r--r--drivers/input/serio/ps2mult.c318
-rw-r--r--drivers/input/serio/serio.c125
-rw-r--r--drivers/input/sparse-keymap.c81
-rw-r--r--drivers/input/tablet/Kconfig11
-rw-r--r--drivers/input/tablet/Makefile1
-rw-r--r--drivers/input/tablet/hanwang.c446
-rw-r--r--drivers/input/tablet/wacom.h1
-rw-r--r--drivers/input/tablet/wacom_sys.c77
-rw-r--r--drivers/input/tablet/wacom_wac.c253
-rw-r--r--drivers/input/tablet/wacom_wac.h15
-rw-r--r--drivers/input/touchscreen/Kconfig43
-rw-r--r--drivers/input/touchscreen/Makefile4
-rw-r--r--drivers/input/touchscreen/ad7877.c144
-rw-r--r--drivers/input/touchscreen/ads7846.c886
-rw-r--r--drivers/input/touchscreen/bu21013_ts.c648
-rw-r--r--drivers/input/touchscreen/cy8ctmg110_ts.c4
-rw-r--r--drivers/input/touchscreen/hp680_ts_input.c6
-rw-r--r--drivers/input/touchscreen/intel-mid-touch.c687
-rw-r--r--drivers/input/touchscreen/lpc32xx_ts.c411
-rw-r--r--drivers/input/touchscreen/mk712.c2
-rw-r--r--drivers/input/touchscreen/s3c2410_ts.c2
-rw-r--r--drivers/input/touchscreen/stmpe-ts.c11
-rw-r--r--drivers/input/touchscreen/tnetv107x-ts.c396
-rw-r--r--drivers/input/touchscreen/tps6507x-ts.c3
-rw-r--r--drivers/input/touchscreen/tsc2007.c2
-rw-r--r--drivers/input/touchscreen/wacom_w8001.c185
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c18
-rw-r--r--drivers/isdn/capi/capidrv.c17
-rw-r--r--drivers/isdn/capi/kcapi.c19
-rw-r--r--drivers/isdn/divert/isdn_divert.c6
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c400
-rw-r--r--drivers/isdn/gigaset/common.c26
-rw-r--r--drivers/isdn/gigaset/gigaset.h3
-rw-r--r--drivers/isdn/gigaset/i4l.c2
-rw-r--r--drivers/isdn/gigaset/isocdata.c8
-rw-r--r--drivers/isdn/hardware/eicon/debug.c2
-rw-r--r--drivers/isdn/hardware/eicon/debuglib.h2
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNinfineon.c2
-rw-r--r--drivers/isdn/hisax/hfc_sx.c13
-rw-r--r--drivers/isdn/hisax/l3_1tr6.c6
-rw-r--r--drivers/isdn/i4l/isdn_audio.c2
-rw-r--r--drivers/isdn/i4l/isdn_tty.c15
-rw-r--r--drivers/isdn/mISDN/dsp_cmx.c1
-rw-r--r--drivers/isdn/mISDN/l1oip_core.c2
-rw-r--r--drivers/isdn/mISDN/stack.c7
-rw-r--r--drivers/isdn/pcbit/edss1.c2
-rw-r--r--drivers/isdn/pcbit/edss1.h2
-rw-r--r--drivers/macintosh/therm_adt746x.c6
-rw-r--r--drivers/macintosh/windfarm_pm121.c2
-rw-r--r--drivers/md/dm-snap-persistent.c2
-rw-r--r--drivers/media/IR/ir-keytable.c393
-rw-r--r--drivers/media/IR/keymaps/rc-manli.c1
-rw-r--r--drivers/media/IR/lirc_dev.c1
-rw-r--r--drivers/media/dvb/ttpci/av7110.c9
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c2
-rw-r--r--drivers/media/dvb/ttpci/av7110_ca.c2
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.c2
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c2
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c2
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c2
-rw-r--r--drivers/media/dvb/ttpci/budget-core.c2
-rw-r--r--drivers/media/dvb/ttpci/budget-patch.c2
-rw-r--r--drivers/media/dvb/ttpci/budget.c2
-rw-r--r--drivers/media/radio/radio-maxiradio.c2
-rw-r--r--drivers/media/radio/radio-typhoon.c3
-rw-r--r--drivers/media/video/Kconfig2
-rw-r--r--drivers/media/video/cafe_ccic.c2
-rw-r--r--drivers/media/video/cx18/cx18-cards.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-417.c2
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c2
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.c2
-rw-r--r--drivers/media/video/mxb.c2
-rw-r--r--drivers/media/video/sn9c102/sn9c102_pas202bcb.c1
-rw-r--r--drivers/media/video/zoran/videocodec.h2
-rw-r--r--drivers/media/video/zoran/zoran_driver.c2
-rw-r--r--drivers/mfd/ab8500-core.c20
-rw-r--r--drivers/mfd/sh_mobile_sdhi.c2
-rw-r--r--drivers/mfd/twl-core.c6
-rw-r--r--drivers/mfd/twl4030-codec.c8
-rw-r--r--drivers/misc/Kconfig51
-rw-r--r--drivers/misc/Makefile4
-rw-r--r--drivers/misc/ad525x_dpot-i2c.c2
-rw-r--r--drivers/misc/ad525x_dpot-spi.c6
-rw-r--r--drivers/misc/ad525x_dpot.c117
-rw-r--r--drivers/misc/ad525x_dpot.h37
-rw-r--r--drivers/misc/apds9802als.c347
-rw-r--r--drivers/misc/apds990x.c1295
-rw-r--r--drivers/misc/bh1770glc.c1413
-rw-r--r--drivers/misc/ibmasm/ibmasmfs.c1
-rw-r--r--drivers/misc/isl29020.c248
-rw-r--r--drivers/misc/lkdtm.c128
-rw-r--r--drivers/misc/phantom.c8
-rw-r--r--drivers/misc/sgi-xp/xpc_uv.c17
-rw-r--r--drivers/mmc/host/Kconfig2
-rw-r--r--drivers/mmc/host/omap_hsmmc.c43
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c4
-rw-r--r--drivers/mtd/devices/lart.c2
-rw-r--r--drivers/mtd/devices/m25p80.c7
-rw-r--r--drivers/mtd/ftl.c2
-rw-r--r--drivers/mtd/maps/Kconfig4
-rw-r--r--drivers/mtd/maps/physmap_of.c2
-rw-r--r--drivers/mtd/nand/cafe_nand.c2
-rw-r--r--drivers/mtd/nand/davinci_nand.c61
-rw-r--r--drivers/mtd/ofpart.c4
-rw-r--r--drivers/net/3c503.c8
-rw-r--r--drivers/net/3c515.c6
-rw-r--r--drivers/net/3c523.c4
-rw-r--r--drivers/net/3c527.c2
-rw-r--r--drivers/net/3c59x.c2
-rw-r--r--drivers/net/8139cp.c4
-rw-r--r--drivers/net/Kconfig113
-rw-r--r--drivers/net/Makefile5
-rw-r--r--drivers/net/acenic.c2
-rw-r--r--drivers/net/amd8111e.c20
-rw-r--r--drivers/net/amd8111e.h1
-rw-r--r--drivers/net/appletalk/Kconfig2
-rw-r--r--drivers/net/appletalk/ipddp.c10
-rw-r--r--drivers/net/appletalk/ltpc.c2
-rw-r--r--drivers/net/arm/am79c961a.c35
-rw-r--r--drivers/net/arm/am79c961a.h1
-rw-r--r--drivers/net/arm/ep93xx_eth.c39
-rw-r--r--drivers/net/arm/ether1.c34
-rw-r--r--drivers/net/arm/ether1.h1
-rw-r--r--drivers/net/arm/ether3.c33
-rw-r--r--drivers/net/arm/ether3.h1
-rw-r--r--drivers/net/atarilance.c24
-rw-r--r--drivers/net/atl1c/atl1c.h3
-rw-r--r--drivers/net/atl1c/atl1c_hw.c2
-rw-r--r--drivers/net/atl1c/atl1c_main.c16
-rw-r--r--drivers/net/atl1e/atl1e_main.c6
-rw-r--r--drivers/net/atlx/atl1.c22
-rw-r--r--drivers/net/atlx/atl1.h9
-rw-r--r--drivers/net/atlx/atl2.c12
-rw-r--r--drivers/net/atlx/atlx.c4
-rw-r--r--drivers/net/atp.c4
-rw-r--r--drivers/net/au1000_eth.c313
-rw-r--r--drivers/net/au1000_eth.h42
-rw-r--r--drivers/net/ax88796.c1
-rw-r--r--drivers/net/b44.c21
-rw-r--r--drivers/net/bcm63xx_enet.c62
-rw-r--r--drivers/net/bcm63xx_enet.h1
-rw-r--r--drivers/net/benet/be.h100
-rw-r--r--drivers/net/benet/be_cmds.c139
-rw-r--r--drivers/net/benet/be_cmds.h67
-rw-r--r--drivers/net/benet/be_ethtool.c177
-rw-r--r--drivers/net/benet/be_main.c691
-rw-r--r--drivers/net/bfin_mac.c155
-rw-r--r--drivers/net/bfin_mac.h2
-rw-r--r--drivers/net/bmac.c9
-rw-r--r--drivers/net/bna/Makefile11
-rw-r--r--drivers/net/bna/bfa_cee.c291
-rw-r--r--drivers/net/bna/bfa_cee.h64
-rw-r--r--drivers/net/bna/bfa_defs.h243
-rw-r--r--drivers/net/bna/bfa_defs_cna.h223
-rw-r--r--drivers/net/bna/bfa_defs_mfg_comm.h244
-rw-r--r--drivers/net/bna/bfa_defs_status.h216
-rw-r--r--drivers/net/bna/bfa_ioc.c1732
-rw-r--r--drivers/net/bna/bfa_ioc.h300
-rw-r--r--drivers/net/bna/bfa_ioc_ct.c392
-rw-r--r--drivers/net/bna/bfa_sm.h88
-rw-r--r--drivers/net/bna/bfa_wc.h69
-rw-r--r--drivers/net/bna/bfi.h392
-rw-r--r--drivers/net/bna/bfi_cna.h199
-rw-r--r--drivers/net/bna/bfi_ctreg.h637
-rw-r--r--drivers/net/bna/bfi_ll.h438
-rw-r--r--drivers/net/bna/bna.h550
-rw-r--r--drivers/net/bna/bna_ctrl.c3261
-rw-r--r--drivers/net/bna/bna_hw.h1490
-rw-r--r--drivers/net/bna/bna_txrx.c4172
-rw-r--r--drivers/net/bna/bna_types.h1128
-rw-r--r--drivers/net/bna/bnad.c3264
-rw-r--r--drivers/net/bna/bnad.h332
-rw-r--r--drivers/net/bna/bnad_ethtool.c1277
-rw-r--r--drivers/net/bna/cna.h81
-rw-r--r--drivers/net/bna/cna_fwimg.c64
-rw-r--r--drivers/net/bnx2.c253
-rw-r--r--drivers/net/bnx2.h25
-rw-r--r--drivers/net/bnx2x/bnx2x.h707
-rw-r--r--drivers/net/bnx2x/bnx2x_cmn.c1018
-rw-r--r--drivers/net/bnx2x/bnx2x_cmn.h590
-rw-r--r--drivers/net/bnx2x/bnx2x_dump.h35
-rw-r--r--drivers/net/bnx2x/bnx2x_ethtool.c432
-rw-r--r--drivers/net/bnx2x/bnx2x_fw_defs.h819
-rw-r--r--drivers/net/bnx2x/bnx2x_fw_file_hdr.h1
-rw-r--r--drivers/net/bnx2x/bnx2x_hsi.h1778
-rw-r--r--drivers/net/bnx2x/bnx2x_init.h44
-rw-r--r--drivers/net/bnx2x/bnx2x_init_ops.h372
-rw-r--r--drivers/net/bnx2x/bnx2x_link.c8758
-rw-r--r--drivers/net/bnx2x/bnx2x_link.h235
-rw-r--r--drivers/net/bnx2x/bnx2x_main.c6035
-rw-r--r--drivers/net/bnx2x/bnx2x_reg.h938
-rw-r--r--drivers/net/bnx2x/bnx2x_stats.c305
-rw-r--r--drivers/net/bnx2x/bnx2x_stats.h8
-rw-r--r--drivers/net/bonding/bond_3ad.c276
-rw-r--r--drivers/net/bonding/bond_main.c185
-rw-r--r--drivers/net/bonding/bond_sysfs.c52
-rw-r--r--drivers/net/bonding/bonding.h34
-rw-r--r--drivers/net/bsd_comp.c2
-rw-r--r--drivers/net/caif/Kconfig7
-rw-r--r--drivers/net/caif/Makefile4
-rw-r--r--drivers/net/caif/caif_shm_u5500.c129
-rw-r--r--drivers/net/caif/caif_shmcore.c744
-rw-r--r--drivers/net/can/Kconfig8
-rw-r--r--drivers/net/can/Makefile1
-rw-r--r--drivers/net/can/at91_can.c95
-rw-r--r--drivers/net/can/flexcan.c3
-rw-r--r--drivers/net/can/mcp251x.c106
-rw-r--r--drivers/net/can/mscan/mpc5xxx_can.c8
-rw-r--r--drivers/net/can/pch_can.c1463
-rw-r--r--drivers/net/can/sja1000/Kconfig12
-rw-r--r--drivers/net/can/sja1000/Makefile1
-rw-r--r--drivers/net/can/sja1000/tscan1.c216
-rw-r--r--drivers/net/cassini.c6
-rw-r--r--drivers/net/chelsio/sge.c6
-rw-r--r--drivers/net/chelsio/subr.c2
-rw-r--r--drivers/net/chelsio/vsc7326.c2
-rw-r--r--drivers/net/cnic.c955
-rw-r--r--drivers/net/cnic.h118
-rw-r--r--drivers/net/cnic_defs.h456
-rw-r--r--drivers/net/cnic_if.h23
-rw-r--r--drivers/net/cpmac.c39
-rw-r--r--drivers/net/cxgb3/adapter.h3
-rw-r--r--drivers/net/cxgb3/common.h18
-rw-r--r--drivers/net/cxgb3/cxgb3_defs.h3
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c37
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.c11
-rw-r--r--drivers/net/cxgb3/mc5.c38
-rw-r--r--drivers/net/cxgb3/regs.h4
-rw-r--r--drivers/net/cxgb3/sge.c45
-rw-r--r--drivers/net/cxgb3/t3_hw.c204
-rw-r--r--drivers/net/cxgb4/cxgb4.h18
-rw-r--r--drivers/net/cxgb4/cxgb4_main.c200
-rw-r--r--drivers/net/cxgb4/cxgb4_uld.h6
-rw-r--r--drivers/net/cxgb4/l2t.c34
-rw-r--r--drivers/net/cxgb4/l2t.h3
-rw-r--r--drivers/net/cxgb4/sge.c42
-rw-r--r--drivers/net/cxgb4/t4_hw.c332
-rw-r--r--drivers/net/cxgb4/t4_hw.h1
-rw-r--r--drivers/net/cxgb4/t4fw_api.h5
-rw-r--r--drivers/net/cxgb4vf/cxgb4vf_main.c5
-rw-r--r--drivers/net/cxgb4vf/sge.c3
-rw-r--r--drivers/net/cxgb4vf/t4vf_common.h26
-rw-r--r--drivers/net/davinci_cpdma.c965
-rw-r--r--drivers/net/davinci_cpdma.h108
-rw-r--r--drivers/net/davinci_emac.c1338
-rw-r--r--drivers/net/davinci_mdio.c475
-rw-r--r--drivers/net/de620.c2
-rw-r--r--drivers/net/declance.c2
-rw-r--r--drivers/net/defxx.c66
-rw-r--r--drivers/net/depca.c2
-rw-r--r--drivers/net/dl2k.c2
-rw-r--r--drivers/net/dm9000.c2
-rw-r--r--drivers/net/dnet.c18
-rw-r--r--drivers/net/dummy.c58
-rw-r--r--drivers/net/e100.c4
-rw-r--r--drivers/net/e1000/e1000.h3
-rw-r--r--drivers/net/e1000/e1000_main.c245
-rw-r--r--drivers/net/e1000e/82571.c6
-rw-r--r--drivers/net/e1000e/defines.h2
-rw-r--r--drivers/net/e1000e/e1000.h29
-rw-r--r--drivers/net/e1000e/es2lan.c1
-rw-r--r--drivers/net/e1000e/ethtool.c23
-rw-r--r--drivers/net/e1000e/ich8lan.c2
-rw-r--r--drivers/net/e1000e/netdev.c149
-rw-r--r--drivers/net/e1000e/param.c2
-rw-r--r--drivers/net/eepro.c8
-rw-r--r--drivers/net/ehea/ehea.h4
-rw-r--r--drivers/net/ehea/ehea_main.c93
-rw-r--r--drivers/net/enic/enic.h27
-rw-r--r--drivers/net/enic/enic_main.c415
-rw-r--r--drivers/net/enic/enic_res.c32
-rw-r--r--drivers/net/enic/enic_res.h2
-rw-r--r--drivers/net/enic/vnic_dev.c133
-rw-r--r--drivers/net/enic/vnic_dev.h19
-rw-r--r--drivers/net/enic/vnic_devcmd.h12
-rw-r--r--drivers/net/enic/vnic_enet.h2
-rw-r--r--drivers/net/enic/vnic_intr.c5
-rw-r--r--drivers/net/enic/vnic_resource.h13
-rw-r--r--drivers/net/enic/vnic_rq.c8
-rw-r--r--drivers/net/enic/vnic_rq.h6
-rw-r--r--drivers/net/enic/vnic_rss.h5
-rw-r--r--drivers/net/enic/vnic_vic.c7
-rw-r--r--drivers/net/enic/vnic_wq.c8
-rw-r--r--drivers/net/enic/vnic_wq.h4
-rw-r--r--drivers/net/epic100.c6
-rw-r--r--drivers/net/eth16i.c16
-rw-r--r--drivers/net/ethoc.c6
-rw-r--r--drivers/net/fealnx.c4
-rw-r--r--drivers/net/fec_mpc52xx.c6
-rw-r--r--drivers/net/forcedeth.c19
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c3
-rw-r--r--drivers/net/fsl_pq_mdio.c4
-rw-r--r--drivers/net/gianfar.c32
-rw-r--r--drivers/net/gianfar_ethtool.c6
-rw-r--r--drivers/net/greth.c6
-rw-r--r--drivers/net/hamachi.c2
-rw-r--r--drivers/net/hamradio/Kconfig2
-rw-r--r--drivers/net/hamradio/bpqether.c2
-rw-r--r--drivers/net/hamradio/hdlcdrv.c2
-rw-r--r--drivers/net/hamradio/scc.c3
-rw-r--r--drivers/net/hp.c8
-rw-r--r--drivers/net/hp100.c6
-rw-r--r--drivers/net/hydra.c13
-rw-r--r--drivers/net/ibm_newemac/core.c6
-rw-r--r--drivers/net/ibm_newemac/core.h6
-rw-r--r--drivers/net/ibmlana.c4
-rw-r--r--drivers/net/ibmveth.c999
-rw-r--r--drivers/net/ibmveth.h59
-rw-r--r--drivers/net/igb/e1000_82575.c18
-rw-r--r--drivers/net/igb/e1000_defines.h31
-rw-r--r--drivers/net/igb/e1000_hw.h2
-rw-r--r--drivers/net/igb/e1000_phy.c206
-rw-r--r--drivers/net/igb/e1000_phy.h2
-rw-r--r--drivers/net/igb/igb.h11
-rw-r--r--drivers/net/igb/igb_ethtool.c52
-rw-r--r--drivers/net/igb/igb_main.c166
-rw-r--r--drivers/net/igbvf/ethtool.c2
-rw-r--r--drivers/net/igbvf/netdev.c11
-rw-r--r--drivers/net/ioc3-eth.c2
-rw-r--r--drivers/net/ipg.c6
-rw-r--r--drivers/net/irda/ali-ircc.c2
-rw-r--r--drivers/net/irda/donauboe.c4
-rw-r--r--drivers/net/irda/donauboe.h2
-rw-r--r--drivers/net/irda/irda-usb.c10
-rw-r--r--drivers/net/irda/mcs7780.c2
-rw-r--r--drivers/net/irda/nsc-ircc.c2
-rw-r--r--drivers/net/irda/sir_dev.c2
-rw-r--r--drivers/net/irda/smsc-ircc2.c2
-rw-r--r--drivers/net/irda/stir4200.c2
-rw-r--r--drivers/net/irda/via-ircc.c3
-rw-r--r--drivers/net/irda/via-ircc.h2
-rw-r--r--drivers/net/irda/vlsi_ir.h2
-rw-r--r--drivers/net/iseries_veth.c2
-rw-r--r--drivers/net/ixgb/ixgb_ee.c32
-rw-r--r--drivers/net/ixgb/ixgb_ethtool.c2
-rw-r--r--drivers/net/ixgb/ixgb_hw.c14
-rw-r--r--drivers/net/ixgb/ixgb_main.c12
-rw-r--r--drivers/net/ixgbe/ixgbe.h39
-rw-r--r--drivers/net/ixgbe/ixgbe_82599.c234
-rw-r--r--drivers/net/ixgbe/ixgbe_common.c50
-rw-r--r--drivers/net/ixgbe/ixgbe_common.h1
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb.c219
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb.h18
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_82598.c67
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_82598.h15
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_82599.c69
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_82599.h18
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c428
-rw-r--r--drivers/net/ixgbe/ixgbe_fcoe.c13
-rw-r--r--drivers/net/ixgbe/ixgbe_fcoe.h1
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c1972
-rw-r--r--drivers/net/ixgbe/ixgbe_mbx.c21
-rw-r--r--drivers/net/ixgbe/ixgbe_mbx.h5
-rw-r--r--drivers/net/ixgbe/ixgbe_sriov.c19
-rw-r--r--drivers/net/ixgbe/ixgbe_sriov.h10
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h2
-rw-r--r--drivers/net/ixgbevf/ethtool.c153
-rw-r--r--drivers/net/ixgbevf/ixgbevf.h1
-rw-r--r--drivers/net/ixgbevf/ixgbevf_main.c36
-rw-r--r--drivers/net/ixgbevf/mbx.c2
-rw-r--r--drivers/net/ixgbevf/mbx.h2
-rw-r--r--drivers/net/ixgbevf/vf.c2
-rw-r--r--drivers/net/ixgbevf/vf.h2
-rw-r--r--drivers/net/jme.c212
-rw-r--r--drivers/net/jme.h6
-rw-r--r--drivers/net/ll_temac_main.c4
-rw-r--r--drivers/net/loopback.c28
-rw-r--r--drivers/net/lp486e.c2
-rw-r--r--drivers/net/mac8390.c48
-rw-r--r--drivers/net/macb.c29
-rw-r--r--drivers/net/macvlan.c4
-rw-r--r--drivers/net/macvtap.c99
-rw-r--r--drivers/net/meth.c2
-rw-r--r--drivers/net/mlx4/Makefile2
-rw-r--r--drivers/net/mlx4/alloc.c17
-rw-r--r--drivers/net/mlx4/en_ethtool.c173
-rw-r--r--drivers/net/mlx4/en_main.c39
-rw-r--r--drivers/net/mlx4/en_netdev.c41
-rw-r--r--drivers/net/mlx4/en_port.c36
-rw-r--r--drivers/net/mlx4/en_port.h17
-rw-r--r--drivers/net/mlx4/en_rx.c104
-rw-r--r--drivers/net/mlx4/en_selftest.c179
-rw-r--r--drivers/net/mlx4/en_tx.c24
-rw-r--r--drivers/net/mlx4/eq.c44
-rw-r--r--drivers/net/mlx4/fw.c18
-rw-r--r--drivers/net/mlx4/fw.h6
-rw-r--r--drivers/net/mlx4/icm.c28
-rw-r--r--drivers/net/mlx4/icm.h2
-rw-r--r--drivers/net/mlx4/intf.c21
-rw-r--r--drivers/net/mlx4/main.c10
-rw-r--r--drivers/net/mlx4/mlx4_en.h40
-rw-r--r--drivers/net/mlx4/port.c30
-rw-r--r--drivers/net/mlx4/profile.c2
-rw-r--r--drivers/net/mv643xx_eth.c3
-rw-r--r--drivers/net/myri10ge/myri10ge.c49
-rw-r--r--drivers/net/myri_sbus.c2
-rw-r--r--drivers/net/natsemi.c2
-rw-r--r--drivers/net/netconsole.c9
-rw-r--r--drivers/net/netxen/netxen_nic.h23
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c43
-rw-r--r--drivers/net/netxen/netxen_nic_init.c14
-rw-r--r--drivers/net/netxen/netxen_nic_main.c49
-rw-r--r--drivers/net/niu.c133
-rw-r--r--drivers/net/ns83820.c55
-rw-r--r--drivers/net/pasemi_mac.c2
-rw-r--r--drivers/net/pasemi_mac_ethtool.c16
-rw-r--r--drivers/net/pch_gbe/Makefile4
-rw-r--r--drivers/net/pch_gbe/pch_gbe.h659
-rw-r--r--drivers/net/pch_gbe/pch_gbe_api.c245
-rw-r--r--drivers/net/pch_gbe/pch_gbe_api.h36
-rw-r--r--drivers/net/pch_gbe/pch_gbe_ethtool.c585
-rw-r--r--drivers/net/pch_gbe/pch_gbe_main.c2477
-rw-r--r--drivers/net/pch_gbe/pch_gbe_param.c499
-rw-r--r--drivers/net/pch_gbe/pch_gbe_phy.c274
-rw-r--r--drivers/net/pch_gbe/pch_gbe_phy.h37
-rw-r--r--drivers/net/pci-skeleton.c4
-rw-r--r--drivers/net/pcmcia/3c574_cs.c90
-rw-r--r--drivers/net/pcmcia/3c589_cs.c17
-rw-r--r--drivers/net/pcmcia/axnet_cs.c187
-rw-r--r--drivers/net/pcmcia/com20020_cs.c32
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c60
-rw-r--r--drivers/net/pcmcia/ibmtr_cs.c26
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c56
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c106
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c105
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c104
-rw-r--r--drivers/net/pcnet32.c4
-rw-r--r--drivers/net/phy/Kconfig1
-rw-r--r--drivers/net/phy/bcm63xx.c2
-rw-r--r--drivers/net/phy/broadcom.c2
-rw-r--r--drivers/net/phy/cicada.c2
-rw-r--r--drivers/net/phy/davicom.c2
-rw-r--r--drivers/net/phy/et1011c.c2
-rw-r--r--drivers/net/phy/icplus.c2
-rw-r--r--drivers/net/phy/lxt.c2
-rw-r--r--drivers/net/phy/marvell.c33
-rw-r--r--drivers/net/phy/micrel.c2
-rw-r--r--drivers/net/phy/national.c2
-rw-r--r--drivers/net/phy/phy.c13
-rw-r--r--drivers/net/phy/phy_device.c19
-rw-r--r--drivers/net/phy/qsemi.c2
-rw-r--r--drivers/net/phy/realtek.c2
-rw-r--r--drivers/net/phy/smsc.c2
-rw-r--r--drivers/net/phy/ste10Xp.c2
-rw-r--r--drivers/net/phy/vitesse.c2
-rw-r--r--drivers/net/plip.c9
-rw-r--r--drivers/net/ppp_generic.c46
-rw-r--r--drivers/net/pppoe.c2
-rw-r--r--drivers/net/pppox.c4
-rw-r--r--drivers/net/pptp.c726
-rw-r--r--drivers/net/ps3_gelic_net.c8
-rw-r--r--drivers/net/ps3_gelic_wireless.c6
-rw-r--r--drivers/net/pxa168_eth.c4
-rw-r--r--drivers/net/qla3xxx.c4
-rw-r--r--drivers/net/qlcnic/qlcnic.h186
-rw-r--r--drivers/net/qlcnic/qlcnic_ctx.c411
-rw-r--r--drivers/net/qlcnic/qlcnic_ethtool.c249
-rw-r--r--drivers/net/qlcnic/qlcnic_hdr.h47
-rw-r--r--drivers/net/qlcnic/qlcnic_hw.c131
-rw-r--r--drivers/net/qlcnic/qlcnic_init.c332
-rw-r--r--drivers/net/qlcnic/qlcnic_main.c1329
-rw-r--r--drivers/net/qlge/qlge.h12
-rw-r--r--drivers/net/qlge/qlge_main.c60
-rw-r--r--drivers/net/qlge/qlge_mpi.c6
-rw-r--r--drivers/net/r6040.c92
-rw-r--r--drivers/net/r8169.c400
-rw-r--r--drivers/net/rrunner.c2
-rw-r--r--drivers/net/s2io.c39
-rw-r--r--drivers/net/s2io.h9
-rw-r--r--drivers/net/sb1000.c6
-rw-r--r--drivers/net/sb1250-mac.c8
-rw-r--r--drivers/net/sc92031.c13
-rw-r--r--drivers/net/sfc/Makefile7
-rw-r--r--drivers/net/sfc/efx.c353
-rw-r--r--drivers/net/sfc/efx.h46
-rw-r--r--drivers/net/sfc/ethtool.c181
-rw-r--r--drivers/net/sfc/falcon.c136
-rw-r--r--drivers/net/sfc/falcon_boards.c203
-rw-r--r--drivers/net/sfc/falcon_gmac.c230
-rw-r--r--drivers/net/sfc/falcon_xmac.c2
-rw-r--r--drivers/net/sfc/filter.c454
-rw-r--r--drivers/net/sfc/filter.h189
-rw-r--r--drivers/net/sfc/mac.h2
-rw-r--r--drivers/net/sfc/mcdi.c4
-rw-r--r--drivers/net/sfc/mcdi.h2
-rw-r--r--drivers/net/sfc/mcdi_phy.c3
-rw-r--r--drivers/net/sfc/mdio_10g.c30
-rw-r--r--drivers/net/sfc/net_driver.h117
-rw-r--r--drivers/net/sfc/nic.c199
-rw-r--r--drivers/net/sfc/phy.h18
-rw-r--r--drivers/net/sfc/regs.h14
-rw-r--r--drivers/net/sfc/rx.c73
-rw-r--r--drivers/net/sfc/selftest.c17
-rw-r--r--drivers/net/sfc/siena.c6
-rw-r--r--drivers/net/sfc/tenxpress.c424
-rw-r--r--drivers/net/sfc/tx.c78
-rw-r--r--drivers/net/sfc/txc43128_phy.c560
-rw-r--r--drivers/net/sfc/workarounds.h9
-rw-r--r--drivers/net/sgiseeq.c2
-rw-r--r--drivers/net/sh_eth.c4
-rw-r--r--drivers/net/sis900.c8
-rw-r--r--drivers/net/skfp/cfm.c10
-rw-r--r--drivers/net/skfp/drvfbi.c16
-rw-r--r--drivers/net/skfp/ess.c46
-rw-r--r--drivers/net/skfp/fplustm.c24
-rw-r--r--drivers/net/skfp/hwmtm.c30
-rw-r--r--drivers/net/skfp/hwt.c6
-rw-r--r--drivers/net/skfp/pcmplc.c22
-rw-r--r--drivers/net/skfp/pmf.c62
-rw-r--r--drivers/net/skfp/queue.c2
-rw-r--r--drivers/net/skfp/skfddi.c118
-rw-r--r--drivers/net/skfp/smt.c78
-rw-r--r--drivers/net/skfp/smtdef.c4
-rw-r--r--drivers/net/skfp/smtinit.c2
-rw-r--r--drivers/net/skfp/srf.c2
-rw-r--r--drivers/net/skge.c5
-rw-r--r--drivers/net/sky2.c5
-rw-r--r--drivers/net/slhc.c15
-rw-r--r--drivers/net/slip.c93
-rw-r--r--drivers/net/slip.h9
-rw-r--r--drivers/net/smsc911x.c5
-rw-r--r--drivers/net/smsc911x.h11
-rw-r--r--drivers/net/spider_net.c4
-rw-r--r--drivers/net/starfire.c10
-rw-r--r--drivers/net/stmmac/Kconfig5
-rw-r--r--drivers/net/stmmac/common.h61
-rw-r--r--drivers/net/stmmac/dwmac100.h2
-rw-r--r--drivers/net/stmmac/dwmac1000.h4
-rw-r--r--drivers/net/stmmac/dwmac1000_core.c36
-rw-r--r--drivers/net/stmmac/dwmac1000_dma.c20
-rw-r--r--drivers/net/stmmac/dwmac100_core.c31
-rw-r--r--drivers/net/stmmac/dwmac100_dma.c20
-rw-r--r--drivers/net/stmmac/dwmac_dma.h16
-rw-r--r--drivers/net/stmmac/dwmac_lib.c22
-rw-r--r--drivers/net/stmmac/enh_desc.c6
-rw-r--r--drivers/net/stmmac/norm_desc.c21
-rw-r--r--drivers/net/stmmac/stmmac.h13
-rw-r--r--drivers/net/stmmac/stmmac_ethtool.c63
-rw-r--r--drivers/net/stmmac/stmmac_main.c216
-rw-r--r--drivers/net/stmmac/stmmac_mdio.c26
-rw-r--r--drivers/net/sun3lance.c4
-rw-r--r--drivers/net/sunbmac.c2
-rw-r--r--drivers/net/sundance.c275
-rw-r--r--drivers/net/sungem.c211
-rw-r--r--drivers/net/sungem_phy.c5
-rw-r--r--drivers/net/sunhme.c10
-rw-r--r--drivers/net/sunlance.c2
-rw-r--r--drivers/net/sunqe.c2
-rw-r--r--drivers/net/sunvnet.c50
-rw-r--r--drivers/net/tc35815.c2
-rw-r--r--drivers/net/tehuti.c34
-rw-r--r--drivers/net/tehuti.h1
-rw-r--r--drivers/net/tg3.c744
-rw-r--r--drivers/net/tg3.h73
-rw-r--r--drivers/net/tlan.c12
-rw-r--r--drivers/net/tlan.h8
-rw-r--r--drivers/net/tokenring/proteon.c2
-rw-r--r--drivers/net/tokenring/smctr.c500
-rw-r--r--drivers/net/tokenring/tms380tr.c68
-rw-r--r--drivers/net/tokenring/tmspci.c10
-rw-r--r--drivers/net/tsi108_eth.c2
-rw-r--r--drivers/net/tulip/Kconfig6
-rw-r--r--drivers/net/tulip/de2104x.c3
-rw-r--r--drivers/net/tulip/de4x5.c57
-rw-r--r--drivers/net/tulip/dmfe.c2
-rw-r--r--drivers/net/tulip/interrupt.c77
-rw-r--r--drivers/net/tulip/pnic2.c2
-rw-r--r--drivers/net/tulip/tulip.h3
-rw-r--r--drivers/net/tulip/tulip_core.c10
-rw-r--r--drivers/net/tulip/uli526x.c4
-rw-r--r--drivers/net/tulip/winbond-840.c2
-rw-r--r--drivers/net/tulip/xircom_cb.c15
-rw-r--r--drivers/net/typhoon.c142
-rw-r--r--drivers/net/usb/Kconfig8
-rw-r--r--drivers/net/usb/Makefile1
-rw-r--r--drivers/net/usb/cx82310_eth.c346
-rw-r--r--drivers/net/usb/hso.c9
-rw-r--r--drivers/net/usb/kaweth.c9
-rw-r--r--drivers/net/usb/plusb.c2
-rw-r--r--drivers/net/usb/sierra_net.c4
-rw-r--r--drivers/net/usb/smsc95xx.c4
-rw-r--r--drivers/net/veth.c2
-rw-r--r--drivers/net/via-velocity.c86
-rw-r--r--drivers/net/via-velocity.h16
-rw-r--r--drivers/net/virtio_net.c14
-rw-r--r--drivers/net/vmxnet3/upt1_defs.h8
-rw-r--r--drivers/net/vmxnet3/vmxnet3_defs.h6
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c45
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c14
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h8
-rw-r--r--drivers/net/vxge/vxge-config.c332
-rw-r--r--drivers/net/vxge/vxge-config.h227
-rw-r--r--drivers/net/vxge/vxge-ethtool.c2
-rw-r--r--drivers/net/vxge/vxge-main.c102
-rw-r--r--drivers/net/vxge/vxge-main.h60
-rw-r--r--drivers/net/vxge/vxge-traffic.c101
-rw-r--r--drivers/net/vxge/vxge-traffic.h134
-rw-r--r--drivers/net/wan/Kconfig2
-rw-r--r--drivers/net/wan/c101.c2
-rw-r--r--drivers/net/wan/cycx_drv.c14
-rw-r--r--drivers/net/wan/cycx_main.c6
-rw-r--r--drivers/net/wan/dlci.c42
-rw-r--r--drivers/net/wan/hdlc.c2
-rw-r--r--drivers/net/wan/hdlc_cisco.c4
-rw-r--r--drivers/net/wan/lapbether.c2
-rw-r--r--drivers/net/wan/lmc/lmc_main.c6
-rw-r--r--drivers/net/wan/n2.c6
-rw-r--r--drivers/net/wan/pc300_drv.c20
-rw-r--r--drivers/net/wan/pc300_tty.c2
-rw-r--r--drivers/net/wan/pci200syn.c2
-rw-r--r--drivers/net/wan/sdla.c108
-rw-r--r--drivers/net/wan/x25_asy.c2
-rw-r--r--drivers/net/wan/z85230.c4
-rw-r--r--drivers/net/wd.c8
-rw-r--r--drivers/net/wimax/i2400m/control.c18
-rw-r--r--drivers/net/wimax/i2400m/driver.c2
-rw-r--r--drivers/net/wimax/i2400m/i2400m-sdio.h1
-rw-r--r--drivers/net/wimax/i2400m/i2400m.h9
-rw-r--r--drivers/net/wimax/i2400m/rx.c2
-rw-r--r--drivers/net/wimax/i2400m/sdio-rx.c2
-rw-r--r--drivers/net/wireless/Kconfig1
-rw-r--r--drivers/net/wireless/Makefile2
-rw-r--r--drivers/net/wireless/airo.c24
-rw-r--r--drivers/net/wireless/at76c50x-usb.c10
-rw-r--r--drivers/net/wireless/ath/Kconfig1
-rw-r--r--drivers/net/wireless/ath/Makefile4
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c31
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c2
-rw-r--r--drivers/net/wireless/ath/ath.h56
-rw-r--r--drivers/net/wireless/ath/ath5k/ani.c47
-rw-r--r--drivers/net/wireless/ath/ath5k/ani.h5
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h33
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c23
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c2374
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h33
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c121
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.h15
-rw-r--r--drivers/net/wireless/ath/ath5k/dma.c8
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c4
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c297
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c26
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c99
-rw-r--r--drivers/net/wireless/ath/ath5k/reg.h74
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c34
-rw-r--r--drivers/net/wireless/ath/ath5k/rfbuffer.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig8
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile5
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c655
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.h13
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c50
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_calib.c89
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_hw.c55
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_phy.c36
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_phy.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h1784
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h191
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c37
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_hw.c164
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_paprd.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c20
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h86
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c30
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.c7
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c152
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h11
-rw-r--r--drivers/net/wireless/ath/ath9k/common.c290
-rw-r--r--drivers/net/wireless/ath/ath9k/common.h16
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c171
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h33
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h7
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c28
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c22
-rw-r--r--drivers/net/wireless/ath/ath9k/gpio.c40
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c35
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h42
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_beacon.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_gpio.c134
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c74
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c51
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/hw-ops.h22
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c418
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h116
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c77
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c13
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h21
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c317
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c200
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.h37
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c602
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h48
-rw-r--r--drivers/net/wireless/ath/ath9k/virtual.c63
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.c74
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.h7
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c192
-rw-r--r--drivers/net/wireless/ath/carl9170/Kconfig41
-rw-r--r--drivers/net/wireless/ath/carl9170/Makefile4
-rw-r--r--drivers/net/wireless/ath/carl9170/carl9170.h628
-rw-r--r--drivers/net/wireless/ath/carl9170/cmd.c188
-rw-r--r--drivers/net/wireless/ath/carl9170/cmd.h173
-rw-r--r--drivers/net/wireless/ath/carl9170/debug.c902
-rw-r--r--drivers/net/wireless/ath/carl9170/debug.h134
-rw-r--r--drivers/net/wireless/ath/carl9170/eeprom.h216
-rw-r--r--drivers/net/wireless/ath/carl9170/fw.c402
-rw-r--r--drivers/net/wireless/ath/carl9170/fwcmd.h284
-rw-r--r--drivers/net/wireless/ath/carl9170/fwdesc.h241
-rw-r--r--drivers/net/wireless/ath/carl9170/hw.h739
-rw-r--r--drivers/net/wireless/ath/carl9170/led.c190
-rw-r--r--drivers/net/wireless/ath/carl9170/mac.c604
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c1891
-rw-r--r--drivers/net/wireless/ath/carl9170/phy.c1810
-rw-r--r--drivers/net/wireless/ath/carl9170/phy.h564
-rw-r--r--drivers/net/wireless/ath/carl9170/rx.c938
-rw-r--r--drivers/net/wireless/ath/carl9170/tx.c1335
-rw-r--r--drivers/net/wireless/ath/carl9170/usb.c1149
-rw-r--r--drivers/net/wireless/ath/carl9170/version.h7
-rw-r--r--drivers/net/wireless/ath/carl9170/wlan.h420
-rw-r--r--drivers/net/wireless/ath/debug.c29
-rw-r--r--drivers/net/wireless/ath/debug.h12
-rw-r--r--drivers/net/wireless/ath/hw.c59
-rw-r--r--drivers/net/wireless/ath/key.c568
-rw-r--r--drivers/net/wireless/ath/reg.h34
-rw-r--r--drivers/net/wireless/b43/Makefile2
-rw-r--r--drivers/net/wireless/b43/b43.h3
-rw-r--r--drivers/net/wireless/b43/main.c30
-rw-r--r--drivers/net/wireless/b43/phy_common.c6
-rw-r--r--drivers/net/wireless/b43/phy_common.h5
-rw-r--r--drivers/net/wireless/b43/phy_n.c213
-rw-r--r--drivers/net/wireless/b43/phy_n.h218
-rw-r--r--drivers/net/wireless/b43/radio_2055.c1332
-rw-r--r--drivers/net/wireless/b43/radio_2055.h254
-rw-r--r--drivers/net/wireless/b43/radio_2056.c43
-rw-r--r--drivers/net/wireless/b43/radio_2056.h42
-rw-r--r--drivers/net/wireless/b43/tables_nphy.c1311
-rw-r--r--drivers/net/wireless/b43/tables_nphy.h59
-rw-r--r--drivers/net/wireless/b43legacy/main.c5
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_ioctl.c2
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c10
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c20
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig10
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c119
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.c7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c191
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c134
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000-hw.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c245
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000-hw.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c754
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-calib.c58
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-calib.h (renamed from drivers/net/wireless/iwlwifi/iwl-calib.h)4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c515
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c454
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c157
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-ict.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c1121
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c404
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.h21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rx.c35
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-sta.c716
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tt.c699
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tt.h129
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c211
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-ucode.c118
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c890
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h96
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h585
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c1451
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h261
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c209
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h257
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c393
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hcmd.c13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c642
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h93
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h9
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c441
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c759
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.h69
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c81
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c434
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c7
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c7
-rw-r--r--drivers/net/wireless/libertas/cfg.c72
-rw-r--r--drivers/net/wireless/libertas/decl.h13
-rw-r--r--drivers/net/wireless/libertas/if_cs.c129
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c161
-rw-r--r--drivers/net/wireless/libertas/if_sdio.h4
-rw-r--r--drivers/net/wireless/libertas/if_spi.c150
-rw-r--r--drivers/net/wireless/libertas/if_spi.h5
-rw-r--r--drivers/net/wireless/libertas/if_usb.c64
-rw-r--r--drivers/net/wireless/libertas/if_usb.h1
-rw-r--r--drivers/net/wireless/libertas/main.c105
-rw-r--r--drivers/net/wireless/libertas/mesh.c2
-rw-r--r--drivers/net/wireless/libertas_tf/if_usb.c57
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c31
-rw-r--r--drivers/net/wireless/orinoco/hw.c9
-rw-r--r--drivers/net/wireless/orinoco/wext.c11
-rw-r--r--drivers/net/wireless/p54/Kconfig24
-rw-r--r--drivers/net/wireless/p54/eeprom.c25
-rw-r--r--drivers/net/wireless/p54/fwio.c6
-rw-r--r--drivers/net/wireless/p54/main.c9
-rw-r--r--drivers/net/wireless/p54/p54spi.c9
-rw-r--r--drivers/net/wireless/p54/p54spi_eeprom.h2
-rw-r--r--drivers/net/wireless/p54/p54usb.c15
-rw-r--r--drivers/net/wireless/p54/txrx.c25
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c2
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c2
-rw-r--r--drivers/net/wireless/ray_cs.c44
-rw-r--r--drivers/net/wireless/rndis_wlan.c12
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c149
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c156
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c78
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h109
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c625
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.h28
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c400
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c159
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h70
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c24
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00crypto.c17
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c13
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c194
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00firmware.c3
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00ht.c25
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h14
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00link.c24
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c6
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c138
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h56
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c320
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.h12
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c123
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c96
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_dev.c15
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_dev.c9
-rw-r--r--drivers/net/wireless/wl1251/Kconfig33
-rw-r--r--drivers/net/wireless/wl1251/Makefile8
-rw-r--r--drivers/net/wireless/wl1251/acx.c (renamed from drivers/net/wireless/wl12xx/wl1251_acx.c)10
-rw-r--r--drivers/net/wireless/wl1251/acx.h (renamed from drivers/net/wireless/wl12xx/wl1251_acx.h)12
-rw-r--r--drivers/net/wireless/wl1251/boot.c (renamed from drivers/net/wireless/wl12xx/wl1251_boot.c)16
-rw-r--r--drivers/net/wireless/wl1251/boot.h (renamed from drivers/net/wireless/wl12xx/wl1251_boot.h)2
-rw-r--r--drivers/net/wireless/wl1251/cmd.c (renamed from drivers/net/wireless/wl12xx/wl1251_cmd.c)12
-rw-r--r--drivers/net/wireless/wl1251/cmd.h (renamed from drivers/net/wireless/wl12xx/wl1251_cmd.h)8
-rw-r--r--drivers/net/wireless/wl1251/debugfs.c (renamed from drivers/net/wireless/wl12xx/wl1251_debugfs.c)8
-rw-r--r--drivers/net/wireless/wl1251/debugfs.h (renamed from drivers/net/wireless/wl12xx/wl1251_debugfs.h)2
-rw-r--r--drivers/net/wireless/wl1251/event.c (renamed from drivers/net/wireless/wl12xx/wl1251_event.c)41
-rw-r--r--drivers/net/wireless/wl1251/event.h (renamed from drivers/net/wireless/wl12xx/wl1251_event.h)3
-rw-r--r--drivers/net/wireless/wl1251/init.c (renamed from drivers/net/wireless/wl12xx/wl1251_init.c)10
-rw-r--r--drivers/net/wireless/wl1251/init.h (renamed from drivers/net/wireless/wl12xx/wl1251_init.h)2
-rw-r--r--drivers/net/wireless/wl1251/io.c (renamed from drivers/net/wireless/wl12xx/wl1251_io.c)6
-rw-r--r--drivers/net/wireless/wl1251/io.h (renamed from drivers/net/wireless/wl12xx/wl1251_io.h)0
-rw-r--r--drivers/net/wireless/wl1251/main.c (renamed from drivers/net/wireless/wl12xx/wl1251_main.c)75
-rw-r--r--drivers/net/wireless/wl1251/ps.c (renamed from drivers/net/wireless/wl12xx/wl1251_ps.c)10
-rw-r--r--drivers/net/wireless/wl1251/ps.h (renamed from drivers/net/wireless/wl12xx/wl1251_ps.h)10
-rw-r--r--drivers/net/wireless/wl1251/reg.h (renamed from drivers/net/wireless/wl12xx/wl1251_reg.h)2
-rw-r--r--drivers/net/wireless/wl1251/rx.c (renamed from drivers/net/wireless/wl12xx/wl1251_rx.c)12
-rw-r--r--drivers/net/wireless/wl1251/rx.h (renamed from drivers/net/wireless/wl12xx/wl1251_rx.h)2
-rw-r--r--drivers/net/wireless/wl1251/sdio.c (renamed from drivers/net/wireless/wl12xx/wl1251_sdio.c)4
-rw-r--r--drivers/net/wireless/wl1251/spi.c (renamed from drivers/net/wireless/wl12xx/wl1251_spi.c)10
-rw-r--r--drivers/net/wireless/wl1251/spi.h (renamed from drivers/net/wireless/wl12xx/wl1251_spi.h)8
-rw-r--r--drivers/net/wireless/wl1251/tx.c (renamed from drivers/net/wireless/wl12xx/wl1251_tx.c)34
-rw-r--r--drivers/net/wireless/wl1251/tx.h (renamed from drivers/net/wireless/wl12xx/wl1251_tx.h)4
-rw-r--r--drivers/net/wireless/wl1251/wl1251.h (renamed from drivers/net/wireless/wl12xx/wl1251.h)7
-rw-r--r--drivers/net/wireless/wl1251/wl12xx_80211.h156
-rw-r--r--drivers/net/wireless/wl12xx/Kconfig39
-rw-r--r--drivers/net/wireless/wl12xx/Makefile12
-rw-r--r--drivers/net/wireless/wl12xx/wl1271.h32
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_acx.c36
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_acx.h31
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_boot.c67
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_boot.h1
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.c143
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.h73
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_conf.h78
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.c15
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_init.c39
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_io.h9
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c416
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ps.c20
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ps.h2
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_rx.c67
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_scan.c83
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_scan.h6
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_sdio.c98
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_spi.c151
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_testmode.c14
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.c109
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.h17
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx_platform_data.c28
-rw-r--r--drivers/net/wireless/wl3501_cs.c11
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c5
-rw-r--r--drivers/net/xen-netfront.c14
-rw-r--r--drivers/net/xilinx_emaclite.c23
-rw-r--r--drivers/net/yellowfin.c2
-rw-r--r--drivers/of/Kconfig5
-rw-r--r--drivers/of/Makefile1
-rw-r--r--drivers/of/address.c2
-rw-r--r--drivers/of/base.c4
-rw-r--r--drivers/of/device.c27
-rw-r--r--drivers/of/fdt.c2
-rw-r--r--drivers/of/irq.c39
-rw-r--r--drivers/of/of_i2c.c1
-rw-r--r--drivers/of/pdt.c276
-rw-r--r--drivers/of/platform.c34
-rw-r--r--drivers/oprofile/oprofilefs.c1
-rw-r--r--drivers/parisc/README.dino3
-rw-r--r--drivers/parisc/dino.c29
-rw-r--r--drivers/parisc/eisa.c29
-rw-r--r--drivers/parisc/gsc.c36
-rw-r--r--drivers/parisc/iosapic.c56
-rw-r--r--drivers/parisc/led.c6
-rw-r--r--drivers/parisc/superio.c25
-rw-r--r--drivers/parport/parport_pc.c2
-rw-r--r--drivers/pci/proc.c3
-rw-r--r--drivers/pci/quirks.c3
-rw-r--r--drivers/pcmcia/yenta_socket.c2
-rw-r--r--drivers/platform/x86/Kconfig53
-rw-r--r--drivers/platform/x86/Makefile6
-rw-r--r--drivers/platform/x86/acer-wmi.c2
-rw-r--r--drivers/platform/x86/asus-laptop.c171
-rw-r--r--drivers/platform/x86/dell-laptop.c77
-rw-r--r--drivers/platform/x86/dell-wmi.c256
-rw-r--r--drivers/platform/x86/eeepc-laptop.c16
-rw-r--r--drivers/platform/x86/eeepc-wmi.c56
-rw-r--r--drivers/platform/x86/hdaps.c (renamed from drivers/hwmon/hdaps.c)2
-rw-r--r--drivers/platform/x86/hp-wmi.c172
-rw-r--r--drivers/platform/x86/ibm_rtl.c341
-rw-r--r--drivers/platform/x86/ideapad-laptop.c (renamed from drivers/platform/x86/ideapad_acpi.c)238
-rw-r--r--drivers/platform/x86/intel_pmic_gpio.c27
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c1
-rw-r--r--drivers/platform/x86/panasonic-laptop.c194
-rw-r--r--drivers/platform/x86/topstar-laptop.c161
-rw-r--r--drivers/platform/x86/toshiba_acpi.c191
-rw-r--r--drivers/platform/x86/wmi.c308
-rw-r--r--drivers/platform/x86/xo1-rfkill.c85
-rw-r--r--drivers/pnp/base.h5
-rw-r--r--drivers/pnp/core.c8
-rw-r--r--drivers/pnp/driver.c2
-rw-r--r--drivers/pnp/pnpacpi/core.c31
-rw-r--r--drivers/pnp/pnpbios/proc.c1
-rw-r--r--drivers/pnp/resource.c10
-rw-r--r--drivers/power/Kconfig24
-rw-r--r--drivers/power/Makefile19
-rw-r--r--drivers/power/bq20z75.c493
-rw-r--r--drivers/power/bq27x00_battery.c1
-rw-r--r--drivers/power/ds2760_battery.c1
-rw-r--r--drivers/power/ds2782_battery.c12
-rw-r--r--drivers/power/isp1704_charger.c369
-rw-r--r--drivers/power/jz4740-battery.c1
-rw-r--r--drivers/power/olpc_battery.c8
-rw-r--r--drivers/power/pcf50633-charger.c1
-rw-r--r--drivers/power/power_supply_sysfs.c4
-rw-r--r--drivers/power/twl4030_charger.c565
-rw-r--r--drivers/power/wm831x_power.c2
-rw-r--r--drivers/rapidio/rio-driver.c2
-rw-r--r--drivers/rapidio/rio-scan.c187
-rw-r--r--drivers/rapidio/rio-sysfs.c26
-rw-r--r--drivers/rapidio/rio.c330
-rw-r--r--drivers/rapidio/rio.h5
-rw-r--r--drivers/rapidio/switches/Kconfig7
-rw-r--r--drivers/rapidio/switches/Makefile1
-rw-r--r--drivers/rapidio/switches/idt_gen2.c447
-rw-r--r--drivers/rapidio/switches/idtcps.c10
-rw-r--r--drivers/rapidio/switches/tsi568.c15
-rw-r--r--drivers/rapidio/switches/tsi57x.c7
-rw-r--r--drivers/rtc/Kconfig24
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/class.c4
-rw-r--r--drivers/rtc/rtc-bfin.c43
-rw-r--r--drivers/rtc/rtc-ds3232.c181
-rw-r--r--drivers/rtc/rtc-jz4740.c45
-rw-r--r--drivers/rtc/rtc-lpc32xx.c414
-rw-r--r--drivers/rtc/rtc-nuc900.c2
-rw-r--r--drivers/rtc/rtc-omap.c12
-rw-r--r--drivers/rtc/rtc-s3c.c92
-rw-r--r--drivers/s390/block/dasd.c24
-rw-r--r--drivers/s390/block/dasd_3990_erp.c5
-rw-r--r--drivers/s390/block/dasd_diag.c19
-rw-r--r--drivers/s390/block/dasd_diag.h4
-rw-r--r--drivers/s390/block/dasd_eckd.c72
-rw-r--r--drivers/s390/block/dasd_proc.c1
-rw-r--r--drivers/s390/char/sclp.c14
-rw-r--r--drivers/s390/char/tape_3590.c6
-rw-r--r--drivers/s390/char/vmcp.c6
-rw-r--r--drivers/s390/char/vmlogrdr.c4
-rw-r--r--drivers/s390/cio/blacklist.c10
-rw-r--r--drivers/s390/cio/chp.c41
-rw-r--r--drivers/s390/cio/chp.h12
-rw-r--r--drivers/s390/cio/chsc.c291
-rw-r--r--drivers/s390/cio/chsc.h28
-rw-r--r--drivers/s390/cio/chsc_sch.c12
-rw-r--r--drivers/s390/cio/css.c50
-rw-r--r--drivers/s390/cio/device.c18
-rw-r--r--drivers/s390/cio/device_fsm.c41
-rw-r--r--drivers/s390/cio/device_pgid.c23
-rw-r--r--drivers/s390/cio/io_sch.h7
-rw-r--r--drivers/s390/cio/qdio.h29
-rw-r--r--drivers/s390/cio/qdio_debug.c33
-rw-r--r--drivers/s390/cio/qdio_main.c138
-rw-r--r--drivers/s390/cio/qdio_setup.c1
-rw-r--r--drivers/s390/cio/qdio_thinint.c66
-rw-r--r--drivers/s390/crypto/ap_bus.c9
-rw-r--r--drivers/s390/kvm/kvm_virtio.c73
-rw-r--r--drivers/s390/net/Kconfig2
-rw-r--r--drivers/s390/net/ctcm_mpc.c2
-rw-r--r--drivers/s390/net/qeth_core.h17
-rw-r--r--drivers/s390/net/qeth_core_main.c26
-rw-r--r--drivers/s390/net/qeth_l2_main.c175
-rw-r--r--drivers/s390/net/qeth_l3_main.c218
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c6
-rw-r--r--drivers/sbus/char/jsflash.c2
-rw-r--r--drivers/scsi/Kconfig9
-rw-r--r--drivers/scsi/aacraid/linit.c2
-rw-r--r--drivers/scsi/bnx2i/57xx_iscsi_constants.h2
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c3
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c2
-rw-r--r--drivers/scsi/sg.c2
-rw-r--r--drivers/serial/68328serial.h5
-rw-r--r--drivers/serial/8250.c2
-rw-r--r--drivers/serial/Kconfig27
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/bfin_sport_uart.c2
-rw-r--r--drivers/serial/bfin_sport_uart.h2
-rw-r--r--drivers/serial/of_serial.c12
-rw-r--r--drivers/serial/omap-serial.c1333
-rw-r--r--drivers/serial/sh-sci.h17
-rw-r--r--drivers/serial/uartlite.c2
-rw-r--r--drivers/sh/Kconfig25
-rw-r--r--drivers/sh/Makefile7
-rw-r--r--drivers/sh/clk/Makefile3
-rw-r--r--drivers/sh/clk/core.c (renamed from drivers/sh/clk.c)203
-rw-r--r--drivers/sh/clk/cpg.c (renamed from drivers/sh/clk-cpg.c)11
-rw-r--r--drivers/sh/intc.c1390
-rw-r--r--drivers/sh/intc/Kconfig35
-rw-r--r--drivers/sh/intc/Makefile5
-rw-r--r--drivers/sh/intc/access.c237
-rw-r--r--drivers/sh/intc/balancing.c97
-rw-r--r--drivers/sh/intc/chip.c215
-rw-r--r--drivers/sh/intc/core.c469
-rw-r--r--drivers/sh/intc/dynamic.c135
-rw-r--r--drivers/sh/intc/handle.c307
-rw-r--r--drivers/sh/intc/internals.h186
-rw-r--r--drivers/sh/intc/userimask.c83
-rw-r--r--drivers/sh/intc/virq-debugfs.c64
-rw-r--r--drivers/sh/intc/virq.c255
-rw-r--r--drivers/sh/pfc.c17
-rw-r--r--drivers/spi/Kconfig7
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi_tegra.c618
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/asus_oled/README2
-rw-r--r--drivers/staging/asus_oled/asus_oled.c2
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c2
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c4
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c2
-rw-r--r--drivers/staging/comedi/drivers/plx9080.h2
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c2
-rw-r--r--drivers/staging/mrst-touchscreen/Kconfig7
-rw-r--r--drivers/staging/mrst-touchscreen/Makefile3
-rw-r--r--drivers/staging/mrst-touchscreen/TODO2
-rw-r--r--drivers/staging/mrst-touchscreen/intel-mid-touch.c864
-rw-r--r--drivers/staging/pohmelfs/inode.c6
-rw-r--r--drivers/staging/quickstart/quickstart.c3
-rw-r--r--drivers/staging/xgifb/TODO2
-rw-r--r--drivers/uio/Kconfig6
-rw-r--r--drivers/usb/atm/cxacru.c18
-rw-r--r--drivers/usb/core/inode.c1
-rw-r--r--drivers/usb/gadget/at91_udc.c1
-rw-r--r--drivers/usb/gadget/f_audio.c2
-rw-r--r--drivers/usb/gadget/f_fs.c1
-rw-r--r--drivers/usb/gadget/f_hid.c4
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c6
-rw-r--r--drivers/usb/gadget/inode.c1
-rw-r--r--drivers/usb/gadget/omap_udc.c18
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c2
-rw-r--r--drivers/usb/gadget/rndis.c2
-rw-r--r--drivers/usb/host/ehci-hcd.c1
-rw-r--r--drivers/usb/host/imx21-hcd.c4
-rw-r--r--drivers/usb/host/ohci-hcd.c1
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c9
-rw-r--r--drivers/usb/host/pci-quirks.c2
-rw-r--r--drivers/usb/host/r8a66597-hcd.c4
-rw-r--r--drivers/usb/host/u132-hcd.c8
-rw-r--r--drivers/usb/image/microtek.c9
-rw-r--r--drivers/usb/misc/ftdi-elan.c2
-rw-r--r--drivers/usb/mon/mon_main.c2
-rw-r--r--drivers/usb/serial/Kconfig4
-rw-r--r--drivers/usb/serial/cypress_m8.c2
-rw-r--r--drivers/usb/serial/ftdi_sio.c1
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h12
-rw-r--r--drivers/usb/serial/garmin_gps.c1
-rw-r--r--drivers/usb/serial/io_edgeport.c11
-rw-r--r--drivers/usb/serial/io_ti.c4
-rw-r--r--drivers/usb/serial/iuu_phoenix.c1
-rw-r--r--drivers/usb/serial/keyspan.c2
-rw-r--r--drivers/usb/serial/keyspan.h2
-rw-r--r--drivers/usb/serial/keyspan_pda.c1
-rw-r--r--drivers/usb/serial/mct_u232.h9
-rw-r--r--drivers/usb/serial/mos7720.c6
-rw-r--r--drivers/usb/serial/mos7840.c7
-rw-r--r--drivers/usb/serial/omninet.c2
-rw-r--r--drivers/usb/serial/sierra.c2
-rw-r--r--drivers/usb/serial/spcp8x5.c1
-rw-r--r--drivers/usb/serial/usb_wwan.c1
-rw-r--r--drivers/usb/serial/whiteheat.c6
-rw-r--r--drivers/usb/storage/Kconfig2
-rw-r--r--drivers/uwb/Kconfig20
-rw-r--r--drivers/uwb/Makefile1
-rw-r--r--drivers/uwb/i1480/Makefile1
-rw-r--r--drivers/uwb/i1480/i1480-wlp.h200
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/Makefile8
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h283
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/lc.c424
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/netdev.c331
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/rx.c474
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/sysfs.c407
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/tx.c584
-rw-r--r--drivers/uwb/wlp/Makefile10
-rw-r--r--drivers/uwb/wlp/driver.c43
-rw-r--r--drivers/uwb/wlp/eda.c415
-rw-r--r--drivers/uwb/wlp/messages.c1798
-rw-r--r--drivers/uwb/wlp/sysfs.c708
-rw-r--r--drivers/uwb/wlp/txrx.c354
-rw-r--r--drivers/uwb/wlp/wlp-internal.h224
-rw-r--r--drivers/uwb/wlp/wlp-lc.c560
-rw-r--r--drivers/uwb/wlp/wss-lc.c959
-rw-r--r--drivers/vhost/net.c2
-rw-r--r--drivers/vhost/vhost.c51
-rw-r--r--drivers/vhost/vhost.h18
-rw-r--r--drivers/video/Kconfig15
-rw-r--r--drivers/video/arcfb.c1
-rw-r--r--drivers/video/aty/atyfb_base.c3
-rw-r--r--drivers/video/aty/radeon_i2c.c1
-rw-r--r--drivers/video/au1200fb.c2
-rw-r--r--drivers/video/bf54x-lq043fb.c6
-rw-r--r--drivers/video/bfin-t350mcqb-fb.c2
-rw-r--r--drivers/video/epson1355fb.c2
-rw-r--r--drivers/video/fbcvt.c2
-rw-r--r--drivers/video/fbmem.c60
-rw-r--r--drivers/video/gbefb.c6
-rw-r--r--drivers/video/i810/i810.h1
-rw-r--r--drivers/video/intelfb/intelfb_i2c.c1
-rw-r--r--drivers/video/matrox/matroxfb_DAC1064.c5
-rw-r--r--drivers/video/matrox/matroxfb_maven.c2
-rw-r--r--drivers/video/metronomefb.c2
-rw-r--r--drivers/video/omap/blizzard.c2
-rw-r--r--drivers/video/omap/lcd_omap3beagle.c2
-rw-r--r--drivers/video/omap2/displays/Kconfig2
-rw-r--r--drivers/video/omap2/displays/panel-acx565akm.c6
-rw-r--r--drivers/video/omap2/displays/panel-generic.c6
-rw-r--r--drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c6
-rw-r--r--drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c6
-rw-r--r--drivers/video/omap2/displays/panel-toppoly-tdo35s.c6
-rw-r--r--drivers/video/omap2/displays/panel-tpo-td043mtea1.c6
-rw-r--r--drivers/video/omap2/dss/Makefile2
-rw-r--r--drivers/video/omap2/dss/core.c3
-rw-r--r--drivers/video/omap2/dss/dispc.c270
-rw-r--r--drivers/video/omap2/dss/dsi.c1
-rw-r--r--drivers/video/omap2/dss/dss_features.c191
-rw-r--r--drivers/video/omap2/dss/dss_features.h50
-rw-r--r--drivers/video/omap2/dss/manager.c33
-rw-r--r--drivers/video/omap2/dss/overlay.c24
-rw-r--r--drivers/video/omap2/omapfb/Kconfig2
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c26
-rw-r--r--drivers/video/savage/savagefb-i2c.c9
-rw-r--r--drivers/video/savage/savagefb.h1
-rw-r--r--drivers/video/sh_mobile_hdmi.c84
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c6
-rw-r--r--drivers/video/vesafb.c2
-rw-r--r--drivers/video/via/Makefile2
-rw-r--r--drivers/video/via/accel.c53
-rw-r--r--drivers/video/via/accel.h3
-rw-r--r--drivers/video/via/chip.h3
-rw-r--r--drivers/video/via/dvi.c189
-rw-r--r--drivers/video/via/dvi.h4
-rw-r--r--drivers/video/via/global.h1
-rw-r--r--drivers/video/via/hw.c648
-rw-r--r--drivers/video/via/hw.h53
-rw-r--r--drivers/video/via/ioctl.c2
-rw-r--r--drivers/video/via/lcd.c90
-rw-r--r--drivers/video/via/lcd.h6
-rw-r--r--drivers/video/via/lcdtbl.h591
-rw-r--r--drivers/video/via/tbl1636.c71
-rw-r--r--drivers/video/via/tbl1636.h34
-rw-r--r--drivers/video/via/via-core.c16
-rw-r--r--drivers/video/via/via_i2c.c31
-rw-r--r--drivers/video/via/viafbdev.c294
-rw-r--r--drivers/video/via/viafbdev.h7
-rw-r--r--drivers/video/via/vt1636.c121
-rw-r--r--drivers/video/xilinxfb.c24
-rw-r--r--drivers/w1/w1.c8
-rw-r--r--drivers/watchdog/omap_wdt.c42
-rw-r--r--drivers/xen/events.c101
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c4
-rw-r--r--drivers/xen/xenfs/Makefile3
-rw-r--r--drivers/xen/xenfs/privcmd.c404
-rw-r--r--drivers/xen/xenfs/super.c95
-rw-r--r--drivers/xen/xenfs/xenfs.h3
-rw-r--r--drivers/xen/xenfs/xenstored.c68
-rw-r--r--firmware/Makefile14
-rw-r--r--firmware/WHENCE15
-rw-r--r--firmware/bnx2/bnx2-mips-06-5.0.0.j6.fw.ihex5908
-rw-r--r--firmware/bnx2/bnx2-mips-06-6.0.15.fw.ihex5815
-rw-r--r--firmware/bnx2/bnx2-mips-09-5.0.0.j15.fw.ihex6081
-rw-r--r--firmware/bnx2/bnx2-mips-09-6.0.17.fw.ihex6488
-rw-r--r--firmware/bnx2/bnx2-rv2p-06-5.0.0.j3.fw.ihex424
-rw-r--r--firmware/bnx2/bnx2-rv2p-06-6.0.15.fw.ihex366
-rw-r--r--firmware/bnx2/bnx2-rv2p-09-5.0.0.j10.fw.ihex462
-rw-r--r--firmware/bnx2/bnx2-rv2p-09-6.0.17.fw.ihex392
-rw-r--r--firmware/bnx2/bnx2-rv2p-09ax-5.0.0.j10.fw.ihex499
-rw-r--r--firmware/bnx2/bnx2-rv2p-09ax-6.0.17.fw.ihex425
-rw-r--r--firmware/bnx2x-e1-5.2.13.0.fw.ihex10191
-rw-r--r--firmware/bnx2x-e1h-5.2.13.0.fw.ihex12849
-rw-r--r--firmware/bnx2x/bnx2x-e1-6.0.34.0.fw.ihex9476
-rw-r--r--firmware/bnx2x/bnx2x-e1h-6.0.34.0.fw.ihex13178
-rw-r--r--firmware/bnx2x/bnx2x-e2-6.0.34.0.fw.ihex15442
-rw-r--r--firmware/ihex2fw.c17
-rw-r--r--firmware/keyspan_pda/keyspan_pda.S2
-rw-r--r--firmware/keyspan_pda/xircom_pgs.S2
-rw-r--r--fs/9p/Kconfig13
-rw-r--r--fs/9p/Makefile1
-rw-r--r--fs/9p/acl.c392
-rw-r--r--fs/9p/acl.h49
-rw-r--r--fs/9p/fid.c1
-rw-r--r--fs/9p/v9fs.c22
-rw-r--r--fs/9p/v9fs.h10
-rw-r--r--fs/9p/v9fs_vfs.h4
-rw-r--r--fs/9p/vfs_addr.c30
-rw-r--r--fs/9p/vfs_dir.c4
-rw-r--r--fs/9p/vfs_file.c265
-rw-r--r--fs/9p/vfs_inode.c258
-rw-r--r--fs/9p/vfs_super.c14
-rw-r--r--fs/9p/xattr.c52
-rw-r--r--fs/9p/xattr.h6
-rw-r--r--fs/Kconfig7
-rw-r--r--fs/Kconfig.binfmt4
-rw-r--r--fs/Makefile5
-rw-r--r--fs/affs/file.c4
-rw-r--r--fs/affs/inode.c2
-rw-r--r--fs/afs/dir.c2
-rw-r--r--fs/afs/write.c19
-rw-r--r--fs/aio.c14
-rw-r--r--fs/anon_inodes.c6
-rw-r--r--fs/autofs4/inode.c1
-rw-r--r--fs/bfs/dir.c2
-rw-r--r--fs/binfmt_misc.c1
-rw-r--r--fs/block_dev.c34
-rw-r--r--fs/btrfs/inode.c4
-rw-r--r--fs/buffer.c29
-rw-r--r--fs/ceph/addr.c9
-rw-r--r--fs/cifs/file.c10
-rw-r--r--fs/coda/cache.c17
-rw-r--r--fs/coda/cnode.c19
-rw-r--r--fs/coda/dir.c157
-rw-r--r--fs/coda/file.c31
-rw-r--r--fs/coda/inode.c61
-rw-r--r--fs/coda/pioctl.c22
-rw-r--r--fs/coda/psdev.c41
-rw-r--r--fs/coda/symlink.c3
-rw-r--r--fs/coda/upcall.c89
-rw-r--r--fs/compat.c2
-rw-r--r--fs/configfs/inode.c1
-rw-r--r--fs/dcache.c277
-rw-r--r--fs/debugfs/inode.c1
-rw-r--r--fs/direct-io.c2
-rw-r--r--fs/ecryptfs/ecryptfs_kernel.h2
-rw-r--r--fs/eventpoll.c35
-rw-r--r--fs/exec.c173
-rw-r--r--fs/exofs/dir.c4
-rw-r--r--fs/exofs/file.c6
-rw-r--r--fs/exofs/inode.c78
-rw-r--r--fs/exofs/ios.c10
-rw-r--r--fs/exofs/namei.c2
-rw-r--r--fs/exportfs/expfs.c17
-rw-r--r--fs/ext2/balloc.c3
-rw-r--r--fs/ext2/dir.c2
-rw-r--r--fs/ext2/ext2.h1
-rw-r--r--fs/ext2/inode.c15
-rw-r--r--fs/ext2/namei.c2
-rw-r--r--fs/ext2/super.c4
-rw-r--r--fs/ext2/xattr.c2
-rw-r--r--fs/ext3/balloc.c17
-rw-r--r--fs/ext3/ialloc.c11
-rw-r--r--fs/ext3/inode.c24
-rw-r--r--fs/ext3/namei.c2
-rw-r--r--fs/ext3/resize.c13
-rw-r--r--fs/ext3/super.c41
-rw-r--r--fs/ext4/Makefile2
-rw-r--r--fs/ext4/balloc.c5
-rw-r--r--fs/ext4/block_validity.c7
-rw-r--r--fs/ext4/dir.c2
-rw-r--r--fs/ext4/ext4.h110
-rw-r--r--fs/ext4/ext4_extents.h65
-rw-r--r--fs/ext4/extents.c368
-rw-r--r--fs/ext4/file.c44
-rw-r--r--fs/ext4/fsync.c83
-rw-r--r--fs/ext4/ialloc.c135
-rw-r--r--fs/ext4/inode.c596
-rw-r--r--fs/ext4/mballoc.c555
-rw-r--r--fs/ext4/migrate.c2
-rw-r--r--fs/ext4/move_extent.c22
-rw-r--r--fs/ext4/namei.c65
-rw-r--r--fs/ext4/page-io.c430
-rw-r--r--fs/ext4/resize.c52
-rw-r--r--fs/ext4/super.c531
-rw-r--r--fs/ext4/xattr.c4
-rw-r--r--fs/ext4/xattr.h10
-rw-r--r--fs/fcntl.c62
-rw-r--r--fs/file_table.c17
-rw-r--r--fs/freevxfs/vxfs_inode.c1
-rw-r--r--fs/fs-writeback.c88
-rw-r--r--fs/fuse/control.c1
-rw-r--r--fs/fuse/dev.c19
-rw-r--r--fs/gfs2/aops.c3
-rw-r--r--fs/gfs2/meta_io.c2
-rw-r--r--fs/gfs2/ops_fstype.c1
-rw-r--r--fs/gfs2/ops_inode.c8
-rw-r--r--fs/gfs2/super.c1
-rw-r--r--fs/hfs/hfs_fs.h13
-rw-r--r--fs/hfs/inode.c2
-rw-r--r--fs/hfs/mdb.c4
-rw-r--r--fs/hfs/super.c1
-rw-r--r--fs/hfsplus/dir.c6
-rw-r--r--fs/hfsplus/inode.c2
-rw-r--r--fs/hfsplus/ioctl.c2
-rw-r--r--fs/hostfs/hostfs.h10
-rw-r--r--fs/hostfs/hostfs_kern.c2
-rw-r--r--fs/hostfs/hostfs_user.c14
-rw-r--r--fs/hugetlbfs/inode.c16
-rw-r--r--fs/inode.c527
-rw-r--r--fs/internal.h7
-rw-r--r--fs/ioctl.c39
-rw-r--r--fs/isofs/inode.c57
-rw-r--r--fs/jbd/checkpoint.c4
-rw-r--r--fs/jbd/commit.c8
-rw-r--r--fs/jbd/journal.c44
-rw-r--r--fs/jbd/recovery.c2
-rw-r--r--fs/jbd/transaction.c6
-rw-r--r--fs/jbd2/checkpoint.c10
-rw-r--r--fs/jbd2/commit.c12
-rw-r--r--fs/jbd2/journal.c6
-rw-r--r--fs/jbd2/transaction.c1
-rw-r--r--fs/jffs2/dir.c4
-rw-r--r--fs/jfs/jfs_imap.c2
-rw-r--r--fs/jfs/jfs_logmgr.c6
-rw-r--r--fs/jfs/jfs_mount.c4
-rw-r--r--fs/jfs/jfs_txnmgr.c2
-rw-r--r--fs/jfs/namei.c2
-rw-r--r--fs/libfs.c8
-rw-r--r--fs/lockd/clntlock.c15
-rw-r--r--fs/lockd/clntproc.c13
-rw-r--r--fs/lockd/host.c1
-rw-r--r--fs/lockd/mon.c1
-rw-r--r--fs/lockd/svc.c13
-rw-r--r--fs/lockd/svc4proc.c2
-rw-r--r--fs/lockd/svclock.c37
-rw-r--r--fs/lockd/svcproc.c2
-rw-r--r--fs/lockd/svcsubs.c9
-rw-r--r--fs/locks.c76
-rw-r--r--fs/logfs/dir.c2
-rw-r--r--fs/minix/namei.c2
-rw-r--r--fs/namei.c16
-rw-r--r--fs/namespace.c2
-rw-r--r--fs/nfs/Kconfig20
-rw-r--r--fs/nfs/Makefile4
-rw-r--r--fs/nfs/callback.c4
-rw-r--r--fs/nfs/callback_proc.c8
-rw-r--r--fs/nfs/client.c28
-rw-r--r--fs/nfs/dir.c1015
-rw-r--r--fs/nfs/dns_resolve.c6
-rw-r--r--fs/nfs/file.c86
-rw-r--r--fs/nfs/getroot.c3
-rw-r--r--fs/nfs/idmap.c211
-rw-r--r--fs/nfs/inode.c39
-rw-r--r--fs/nfs/internal.h12
-rw-r--r--fs/nfs/mount_clnt.c4
-rw-r--r--fs/nfs/nfs2xdr.c107
-rw-r--r--fs/nfs/nfs3proc.c62
-rw-r--r--fs/nfs/nfs3xdr.c196
-rw-r--r--fs/nfs/nfs4_fs.h4
-rw-r--r--fs/nfs/nfs4filelayout.c280
-rw-r--r--fs/nfs/nfs4filelayout.h94
-rw-r--r--fs/nfs/nfs4filelayoutdev.c448
-rw-r--r--fs/nfs/nfs4proc.c497
-rw-r--r--fs/nfs/nfs4state.c42
-rw-r--r--fs/nfs/nfs4xdr.c700
-rw-r--r--fs/nfs/nfsroot.c568
-rw-r--r--fs/nfs/pnfs.c783
-rw-r--r--fs/nfs/pnfs.h189
-rw-r--r--fs/nfs/proc.c35
-rw-r--r--fs/nfs/read.c4
-rw-r--r--fs/nfs/super.c72
-rw-r--r--fs/nfs/sysctl.c2
-rw-r--r--fs/nfs/unlink.c259
-rw-r--r--fs/nfs/write.c22
-rw-r--r--fs/nfsd/Kconfig13
-rw-r--r--fs/nfsd/export.c73
-rw-r--r--fs/nfsd/nfs4callback.c245
-rw-r--r--fs/nfsd/nfs4idmap.c105
-rw-r--r--fs/nfsd/nfs4proc.c7
-rw-r--r--fs/nfsd/nfs4state.c519
-rw-r--r--fs/nfsd/nfs4xdr.c18
-rw-r--r--fs/nfsd/nfsctl.c26
-rw-r--r--fs/nfsd/nfsd.h2
-rw-r--r--fs/nfsd/nfssvc.c5
-rw-r--r--fs/nfsd/state.h52
-rw-r--r--fs/nfsd/vfs.c16
-rw-r--r--fs/nilfs2/namei.c2
-rw-r--r--fs/nilfs2/segment.c2
-rw-r--r--fs/notify/fsnotify.c33
-rw-r--r--fs/notify/inode_mark.c2
-rw-r--r--fs/ntfs/super.c19
-rw-r--r--fs/ocfs2/aops.c19
-rw-r--r--fs/ocfs2/aops.h3
-rw-r--r--fs/ocfs2/cluster/tcp_internal.h2
-rw-r--r--fs/ocfs2/dlmfs/dlmfs.c2
-rw-r--r--fs/ocfs2/file.c9
-rw-r--r--fs/ocfs2/namei.c2
-rw-r--r--fs/partitions/check.c12
-rw-r--r--fs/partitions/ldm.c2
-rw-r--r--fs/partitions/ldm.h2
-rw-r--r--fs/pipe.c2
-rw-r--r--fs/proc/Kconfig4
-rw-r--r--fs/proc/base.c111
-rw-r--r--fs/proc/proc_sysctl.c2
-rw-r--r--fs/proc/proc_tty.c158
-rw-r--r--fs/proc/softirqs.c4
-rw-r--r--fs/proc/stat.c14
-rw-r--r--fs/proc/task_mmu.c6
-rw-r--r--fs/quota/Kconfig4
-rw-r--r--fs/quota/dquot.c30
-rw-r--r--fs/ramfs/inode.c1
-rw-r--r--fs/read_write.c28
-rw-r--r--fs/reiserfs/Kconfig6
-rw-r--r--fs/reiserfs/README2
-rw-r--r--fs/reiserfs/inode.c26
-rw-r--r--fs/reiserfs/ioctl.c6
-rw-r--r--fs/reiserfs/namei.c2
-rw-r--r--fs/reiserfs/xattr.c7
-rw-r--r--fs/select.c6
-rw-r--r--fs/seq_file.c8
-rw-r--r--fs/signalfd.c10
-rw-r--r--fs/smbfs/dir.c16
-rw-r--r--fs/smbfs/inode.c1
-rw-r--r--fs/smbfs/proc.c10
-rw-r--r--fs/super.c8
-rw-r--r--fs/sysv/namei.c2
-rw-r--r--fs/ubifs/dir.c2
-rw-r--r--fs/udf/namei.c2
-rw-r--r--fs/ufs/namei.c2
-rw-r--r--fs/xfs/Kconfig1
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c3
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.c1
-rw-r--r--fs/xfs/linux-2.6/xfs_iops.c6
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c2
-rw-r--r--fs/xfs/xfs_inode.h2
-rw-r--r--include/acpi/acpi_bus.h14
-rw-r--r--include/acpi/acpi_drivers.h2
-rw-r--r--include/acpi/acpiosxf.h14
-rw-r--r--include/acpi/acpixf.h11
-rw-r--r--include/acpi/actypes.h30
-rw-r--r--include/acpi/platform/acenv.h6
-rw-r--r--include/acpi/platform/acgcc.h2
-rw-r--r--include/acpi/platform/aclinux.h7
-rw-r--r--include/asm-generic/cputime.h6
-rw-r--r--include/asm-generic/gpio.h4
-rw-r--r--include/asm-generic/pgtable.h2
-rw-r--r--include/asm-generic/vmlinux.lds.h3
-rw-r--r--include/crypto/cryptd.h24
-rw-r--r--include/crypto/gf128mul.h4
-rw-r--r--include/drm/drmP.h45
-rw-r--r--include/drm/drm_crtc.h4
-rw-r--r--include/drm/drm_crtc_helper.h8
-rw-r--r--include/drm/drm_dp_helper.h3
-rw-r--r--include/drm/i915_drm.h6
-rw-r--r--include/drm/intel-gtt.h18
-rw-r--r--include/drm/ttm/ttm_bo_api.h3
-rw-r--r--include/drm/ttm/ttm_bo_driver.h27
-rw-r--r--include/drm/vmwgfx_drm.h1
-rw-r--r--include/linux/Kbuild1
-rw-r--r--include/linux/acpi.h11
-rw-r--r--include/linux/amba/pl08x.h222
-rw-r--r--include/linux/atmdev.h2
-rw-r--r--include/linux/backing-dev.h3
-rw-r--r--include/linux/basic_mmio_gpio.h20
-rw-r--r--include/linux/bfin_mac.h29
-rw-r--r--include/linux/blkdev.h9
-rw-r--r--include/linux/buffer_head.h1
-rw-r--r--include/linux/can/platform/mcp251x.h4
-rw-r--r--include/linux/cgroup.h4
-rw-r--r--include/linux/coda_fs_i.h13
-rw-r--r--include/linux/coda_linux.h6
-rw-r--r--include/linux/coda_psdev.h4
-rw-r--r--include/linux/completion.h10
-rw-r--r--include/linux/connector.h8
-rw-r--r--include/linux/davinci_emac.h16
-rw-r--r--include/linux/dccp.h6
-rw-r--r--include/linux/dmaengine.h60
-rw-r--r--include/linux/elevator.h2
-rw-r--r--include/linux/etherdevice.h22
-rw-r--r--include/linux/ethtool.h190
-rw-r--r--include/linux/fb.h6
-rw-r--r--include/linux/fdreg.h2
-rw-r--r--include/linux/fs.h68
-rw-r--r--include/linux/gameport.h4
-rw-r--r--include/linux/genhd.h1
-rw-r--r--include/linux/gfp.h105
-rw-r--r--include/linux/gpio-fan.h36
-rw-r--r--include/linux/hid.h5
-rw-r--r--include/linux/hiddev.h4
-rw-r--r--include/linux/highmem.h74
-rw-r--r--include/linux/hugetlb.h17
-rw-r--r--include/linux/i2c.h12
-rw-r--r--include/linux/i2c/adp5588.h21
-rw-r--r--include/linux/i2c/apds990x.h79
-rw-r--r--include/linux/i2c/bh1770glc.h53
-rw-r--r--include/linux/i2c/twl.h6
-rw-r--r--include/linux/idr.h8
-rw-r--r--include/linux/ieee80211.h71
-rw-r--r--include/linux/if.h2
-rw-r--r--include/linux/if_bonding.h3
-rw-r--r--include/linux/if_ether.h2
-rw-r--r--include/linux/if_infiniband.h2
-rw-r--r--include/linux/if_macvlan.h9
-rw-r--r--include/linux/if_pppox.h52
-rw-r--r--include/linux/if_vlan.h31
-rw-r--r--include/linux/in.h19
-rw-r--r--include/linux/in6.h4
-rw-r--r--include/linux/inetdevice.h21
-rw-r--r--include/linux/init_task.h4
-rw-r--r--include/linux/input.h57
-rw-r--r--include/linux/input/bu21013.h44
-rw-r--r--include/linux/intel_mid_dma.h16
-rw-r--r--include/linux/interrupt.h3
-rw-r--r--include/linux/io-mapping.h14
-rw-r--r--include/linux/ip_vs.h15
-rw-r--r--include/linux/ipv6.h4
-rw-r--r--include/linux/jbd2.h2
-rw-r--r--include/linux/jhash.h2
-rw-r--r--include/linux/kernel.h36
-rw-r--r--include/linux/kernel_stat.h18
-rw-r--r--include/linux/kfifo.h28
-rw-r--r--include/linux/kvm.h12
-rw-r--r--include/linux/kvm_host.h22
-rw-r--r--include/linux/kvm_para.h7
-rw-r--r--include/linux/lis3lv02d.h55
-rw-r--r--include/linux/list.h6
-rw-r--r--include/linux/magic.h1
-rw-r--r--include/linux/math64.h12
-rw-r--r--include/linux/memory_hotplug.h4
-rw-r--r--include/linux/migrate.h16
-rw-r--r--include/linux/mlx4/cmd.h3
-rw-r--r--include/linux/mlx4/device.h42
-rw-r--r--include/linux/mlx4/driver.h9
-rw-r--r--include/linux/mlx4/qp.h9
-rw-r--r--include/linux/mm.h29
-rw-r--r--include/linux/mm_types.h2
-rw-r--r--include/linux/mmc/sdio_ids.h1
-rw-r--r--include/linux/mmu_notifier.h2
-rw-r--r--include/linux/mmzone.h10
-rw-r--r--include/linux/moduleparam.h4
-rw-r--r--include/linux/mroute.h1
-rw-r--r--include/linux/n_r3964.h1
-rw-r--r--include/linux/net.h2
-rw-r--r--include/linux/netdevice.h136
-rw-r--r--include/linux/netfilter/nf_conntrack_common.h6
-rw-r--r--include/linux/netfilter/nf_conntrack_sip.h1
-rw-r--r--include/linux/netfilter/nfnetlink_conntrack.h1
-rw-r--r--include/linux/netfilter/x_tables.h5
-rw-r--r--include/linux/netfilter/xt_TPROXY.h13
-rw-r--r--include/linux/netfilter_arp/arp_tables.h68
-rw-r--r--include/linux/netfilter_bridge/Kbuild2
-rw-r--r--include/linux/netfilter_ipv4/ip_tables.h107
-rw-r--r--include/linux/netfilter_ipv6/ip6_tables.h110
-rw-r--r--include/linux/netpoll.h9
-rw-r--r--include/linux/nfs4.h65
-rw-r--r--include/linux/nfs_fs.h19
-rw-r--r--include/linux/nfs_fs_sb.h4
-rw-r--r--include/linux/nfs_idmap.h31
-rw-r--r--include/linux/nfs_mount.h3
-rw-r--r--include/linux/nfs_xdr.h128
-rw-r--r--include/linux/nl80211.h210
-rw-r--r--include/linux/of_device.h13
-rw-r--r--include/linux/of_fdt.h2
-rw-r--r--include/linux/of_irq.h4
-rw-r--r--include/linux/of_pdt.h45
-rw-r--r--include/linux/padata.h4
-rw-r--r--include/linux/page-flags.h2
-rw-r--r--include/linux/pageblock-flags.h5
-rw-r--r--include/linux/pagemap.h13
-rw-r--r--include/linux/pci_ids.h29
-rw-r--r--include/linux/percpu-defs.h12
-rw-r--r--include/linux/percpu_counter.h10
-rw-r--r--include/linux/phonet.h5
-rw-r--r--include/linux/phy.h16
-rw-r--r--include/linux/pkt_cls.h1
-rw-r--r--include/linux/poll.h2
-rw-r--r--include/linux/power_supply.h6
-rw-r--r--include/linux/ptrace.h12
-rw-r--r--include/linux/ramoops.h15
-rw-r--r--include/linux/ratelimit.h2
-rw-r--r--include/linux/rds.h115
-rw-r--r--include/linux/reiserfs_fs.h2
-rw-r--r--include/linux/ring_buffer.h12
-rw-r--r--include/linux/rio.h17
-rw-r--r--include/linux/rio_ids.h2
-rw-r--r--include/linux/rio_regs.h18
-rw-r--r--include/linux/rmap.h30
-rw-r--r--include/linux/rtnetlink.h30
-rw-r--r--include/linux/sched.h17
-rw-r--r--include/linux/serial_core.h3
-rw-r--r--include/linux/serio.h10
-rw-r--r--include/linux/sfi.h24
-rw-r--r--include/linux/sh_clk.h17
-rw-r--r--include/linux/sh_intc.h16
-rw-r--r--include/linux/sh_pfc.h1
-rw-r--r--include/linux/signalfd.h3
-rw-r--r--include/linux/skbuff.h117
-rw-r--r--include/linux/slub_def.h14
-rw-r--r--include/linux/smp.h19
-rw-r--r--include/linux/socket.h1
-rw-r--r--include/linux/spi/74x164.h11
-rw-r--r--include/linux/ssb/ssb_regs.h1
-rw-r--r--include/linux/stmmac.h6
-rw-r--r--include/linux/sunrpc/auth.h4
-rw-r--r--include/linux/sunrpc/cache.h37
-rw-r--r--include/linux/sunrpc/clnt.h2
-rw-r--r--include/linux/sunrpc/gss_spkm3.h55
-rw-r--r--include/linux/sunrpc/stats.h23
-rw-r--r--include/linux/sunrpc/svc_xprt.h32
-rw-r--r--include/linux/sunrpc/svcauth.h17
-rw-r--r--include/linux/sunrpc/xdr.h9
-rw-r--r--include/linux/sunrpc/xprt.h4
-rw-r--r--include/linux/swap.h10
-rw-r--r--include/linux/synclink.h5
-rw-r--r--include/linux/syscalls.h3
-rw-r--r--include/linux/tc_act/Kbuild1
-rw-r--r--include/linux/tc_act/tc_csum.h32
-rw-r--r--include/linux/tc_ematch/tc_em_meta.h1
-rw-r--r--include/linux/tcp.h1
-rw-r--r--include/linux/tipc.h30
-rw-r--r--include/linux/tracehook.h2
-rw-r--r--include/linux/types.h20
-rw-r--r--include/linux/virtio_9p.h1
-rw-r--r--include/linux/vmalloc.h2
-rw-r--r--include/linux/wireless.h2
-rw-r--r--include/linux/wl12xx.h (renamed from include/linux/spi/wl12xx.h)23
-rw-r--r--include/linux/wlp.h736
-rw-r--r--include/linux/workqueue.h6
-rw-r--r--include/linux/writeback.h6
-rw-r--r--include/media/rc-map.h2
-rw-r--r--include/net/9p/9p.h54
-rw-r--r--include/net/9p/client.h7
-rw-r--r--include/net/addrconf.h65
-rw-r--r--include/net/arp.h2
-rw-r--r--include/net/bluetooth/bluetooth.h2
-rw-r--r--include/net/bluetooth/hci.h2
-rw-r--r--include/net/bluetooth/hci_core.h2
-rw-r--r--include/net/bluetooth/l2cap.h2
-rw-r--r--include/net/bluetooth/rfcomm.h5
-rw-r--r--include/net/caif/caif_shm.h26
-rw-r--r--include/net/cfg80211.h296
-rw-r--r--include/net/dst.h35
-rw-r--r--include/net/dst_ops.h37
-rw-r--r--include/net/fib_rules.h5
-rw-r--r--include/net/flow.h1
-rw-r--r--include/net/garp.h2
-rw-r--r--include/net/genetlink.h18
-rw-r--r--include/net/gre.h18
-rw-r--r--include/net/inet_connection_sock.h1
-rw-r--r--include/net/inet_ecn.h2
-rw-r--r--include/net/inet_hashtables.h2
-rw-r--r--include/net/inetpeer.h2
-rw-r--r--include/net/ip.h10
-rw-r--r--include/net/ip6_tunnel.h2
-rw-r--r--include/net/ip_fib.h17
-rw-r--r--include/net/ip_vs.h180
-rw-r--r--include/net/ipip.h18
-rw-r--r--include/net/ipv6.h35
-rw-r--r--include/net/irda/irlan_common.h1
-rw-r--r--include/net/irda/irlan_event.h2
-rw-r--r--include/net/irda/irlap.h2
-rw-r--r--include/net/irda/irlmp.h2
-rw-r--r--include/net/irda/irttp.h2
-rw-r--r--include/net/mac80211.h195
-rw-r--r--include/net/neighbour.h47
-rw-r--r--include/net/net_namespace.h19
-rw-r--r--include/net/netfilter/ipv6/nf_defrag_ipv6.h6
-rw-r--r--include/net/netfilter/nf_conntrack_expect.h12
-rw-r--r--include/net/netfilter/nf_nat_protocol.h3
-rw-r--r--include/net/netfilter/nf_tproxy_core.h192
-rw-r--r--include/net/netfilter/xt_log.h54
-rw-r--r--include/net/netns/xfrm.h9
-rw-r--r--include/net/phonet/pep.h26
-rw-r--r--include/net/phonet/phonet.h5
-rw-r--r--include/net/phonet/pn_dev.h1
-rw-r--r--include/net/protocol.h4
-rw-r--r--include/net/raw.h5
-rw-r--r--include/net/rtnetlink.h1
-rw-r--r--include/net/sch_generic.h5
-rw-r--r--include/net/sctp/sctp.h60
-rw-r--r--include/net/sctp/sm.h10
-rw-r--r--include/net/sctp/structs.h2
-rw-r--r--include/net/sctp/tsnmap.h2
-rw-r--r--include/net/sock.h16
-rw-r--r--include/net/tc_act/tc_csum.h15
-rw-r--r--include/net/tcp.h11
-rw-r--r--include/net/tipc/tipc.h71
-rw-r--r--include/net/tipc/tipc_msg.h10
-rw-r--r--include/net/tipc/tipc_port.h2
-rw-r--r--include/net/udp.h3
-rw-r--r--include/net/xfrm.h7
-rw-r--r--include/rdma/ib_addr.h134
-rw-r--r--include/rdma/ib_pack.h39
-rw-r--r--include/rdma/ib_user_verbs.h3
-rw-r--r--include/rdma/ib_verbs.h11
-rw-r--r--include/scsi/srp.h38
-rw-r--r--include/sound/core.h2
-rw-r--r--include/sound/emu10k1.h2
-rw-r--r--include/sound/jack.h5
-rw-r--r--include/sound/max98088.h50
-rw-r--r--include/sound/pcm.h1
-rw-r--r--include/sound/sh_fsi.h3
-rw-r--r--include/sound/soc-dai.h98
-rw-r--r--include/sound/soc-dapm.h18
-rw-r--r--include/sound/soc-of-simple.h25
-rw-r--r--include/sound/soc.h245
-rw-r--r--include/sound/tlv.h4
-rw-r--r--include/sound/tlv320aic3x.h43
-rw-r--r--include/sound/wm8962.h32
-rw-r--r--include/trace/events/ext4.h385
-rw-r--r--include/trace/events/irq.h54
-rw-r--r--include/trace/events/jbd2.h78
-rw-r--r--include/trace/events/vmscan.h44
-rw-r--r--include/trace/events/writeback.h37
-rw-r--r--include/video/sh_mobile_hdmi.h16
-rw-r--r--include/video/vga.h2
-rw-r--r--include/xen/Kbuild1
-rw-r--r--include/xen/interface/memory.h29
-rw-r--r--include/xen/privcmd.h80
-rw-r--r--include/xen/xen-ops.h5
-rw-r--r--init/Kconfig119
-rw-r--r--init/do_mounts.c16
-rw-r--r--init/do_mounts_md.c2
-rw-r--r--init/do_mounts_rd.c4
-rw-r--r--init/initramfs.c5
-rw-r--r--init/noinitramfs.c6
-rw-r--r--ipc/compat.c6
-rw-r--r--ipc/compat_mq.c5
-rw-r--r--ipc/mqueue.c3
-rw-r--r--ipc/shm.c63
-rw-r--r--kernel/cgroup.c130
-rw-r--r--kernel/cgroup_freezer.c72
-rw-r--r--kernel/cred.c4
-rw-r--r--kernel/exit.c5
-rw-r--r--kernel/fork.c17
-rw-r--r--kernel/futex.c2
-rw-r--r--kernel/irq/irqdesc.c15
-rw-r--r--kernel/kexec.c2
-rw-r--r--kernel/kprobes.c7
-rw-r--r--kernel/module.c2
-rw-r--r--kernel/ns_cgroup.c8
-rw-r--r--kernel/perf_event.c94
-rw-r--r--kernel/pm_qos_params.c2
-rw-r--r--kernel/power/snapshot.c18
-rw-r--r--kernel/power/swap.c6
-rw-r--r--kernel/printk.c5
-rw-r--r--kernel/ptrace.c36
-rw-r--r--kernel/resource.c2
-rw-r--r--kernel/signal.c5
-rw-r--r--kernel/smp.c8
-rw-r--r--kernel/softirq.c18
-rw-r--r--kernel/stop_machine.c6
-rw-r--r--kernel/sysctl.c14
-rw-r--r--kernel/taskstats.c172
-rw-r--r--kernel/trace/ring_buffer.c335
-rw-r--r--kernel/trace/trace.c8
-rw-r--r--kernel/trace/trace_kprobe.c3
-rw-r--r--kernel/tsacct.c10
-rw-r--r--kernel/user.c1
-rw-r--r--kernel/wait.c6
-rw-r--r--kernel/workqueue.c6
-rw-r--r--lib/Kconfig.debug34
-rw-r--r--lib/bitmap.c3
-rw-r--r--lib/div64.c52
-rw-r--r--lib/idr.c78
-rw-r--r--lib/list_sort.c172
-rw-r--r--lib/parser.c7
-rw-r--r--lib/percpu_counter.c55
-rw-r--r--lib/vsprintf.c19
-rw-r--r--mm/backing-dev.c74
-rw-r--r--mm/dmapool.c2
-rw-r--r--mm/filemap.c42
-rw-r--r--mm/highmem.c66
-rw-r--r--mm/hugetlb.c238
-rw-r--r--mm/internal.h2
-rw-r--r--mm/maccess.c2
-rw-r--r--mm/memcontrol.c406
-rw-r--r--mm/memory-failure.c176
-rw-r--r--mm/memory.c35
-rw-r--r--mm/memory_hotplug.c48
-rw-r--r--mm/mempolicy.c15
-rw-r--r--mm/migrate.c249
-rw-r--r--mm/mremap.c4
-rw-r--r--mm/nommu.c49
-rw-r--r--mm/oom_kill.c33
-rw-r--r--mm/page-writeback.c31
-rw-r--r--mm/page_alloc.c99
-rw-r--r--mm/page_isolation.c3
-rw-r--r--mm/percpu.c2
-rw-r--r--mm/rmap.c37
-rw-r--r--mm/shmem.c7
-rw-r--r--mm/slab.c2
-rw-r--r--mm/slob.c4
-rw-r--r--mm/slub.c788
-rw-r--r--mm/swap.c1
-rw-r--r--mm/swapfile.c49
-rw-r--r--mm/util.c13
-rw-r--r--mm/vmalloc.c56
-rw-r--r--mm/vmscan.c222
-rw-r--r--mm/vmstat.c44
-rw-r--r--net/802/fc.c2
-rw-r--r--net/802/fddi.c12
-rw-r--r--net/802/garp.c18
-rw-r--r--net/802/hippi.c2
-rw-r--r--net/802/stp.c4
-rw-r--r--net/802/tr.c2
-rw-r--r--net/8021q/vlan.c93
-rw-r--r--net/8021q/vlan.h17
-rw-r--r--net/8021q/vlan_core.c121
-rw-r--r--net/8021q/vlan_dev.c10
-rw-r--r--net/9p/client.c233
-rw-r--r--net/9p/protocol.c5
-rw-r--r--net/9p/trans_fd.c2
-rw-r--r--net/9p/trans_virtio.c76
-rw-r--r--net/atm/clip.c4
-rw-r--r--net/atm/common.c2
-rw-r--r--net/atm/lec.c1
-rw-r--r--net/ax25/Kconfig8
-rw-r--r--net/ax25/af_ax25.c2
-rw-r--r--net/ax25/ax25_route.c4
-rw-r--r--net/bluetooth/af_bluetooth.c114
-rw-r--r--net/bluetooth/cmtp/core.c6
-rw-r--r--net/bluetooth/hci_core.c1
-rw-r--r--net/bluetooth/hci_sysfs.c21
-rw-r--r--net/bluetooth/hidp/core.c8
-rw-r--r--net/bluetooth/l2cap.c60
-rw-r--r--net/bluetooth/lib.c4
-rw-r--r--net/bluetooth/rfcomm/core.c43
-rw-r--r--net/bluetooth/rfcomm/sock.c104
-rw-r--r--net/bluetooth/rfcomm/tty.c4
-rw-r--r--net/bridge/br_device.c8
-rw-r--r--net/bridge/br_if.c29
-rw-r--r--net/bridge/br_input.c4
-rw-r--r--net/bridge/br_netfilter.c134
-rw-r--r--net/bridge/netfilter/ebt_vlan.c25
-rw-r--r--net/bridge/netfilter/ebtables.c15
-rw-r--r--net/caif/caif_dev.c24
-rw-r--r--net/caif/caif_socket.c27
-rw-r--r--net/caif/cfcnfg.c49
-rw-r--r--net/caif/cfctrl.c59
-rw-r--r--net/caif/cfdbgl.c4
-rw-r--r--net/caif/cfdgml.c11
-rw-r--r--net/caif/cffrml.c14
-rw-r--r--net/caif/cfmuxl.c14
-rw-r--r--net/caif/cfpkt_skbuff.c48
-rw-r--r--net/caif/cfrfml.c12
-rw-r--r--net/caif/cfserl.c4
-rw-r--r--net/caif/cfsrvl.c17
-rw-r--r--net/caif/cfutill.c12
-rw-r--r--net/caif/cfveil.c11
-rw-r--r--net/caif/cfvidl.c6
-rw-r--r--net/caif/chnl_net.c47
-rw-r--r--net/can/raw.c37
-rw-r--r--net/core/datagram.c5
-rw-r--r--net/core/dev.c613
-rw-r--r--net/core/dst.c39
-rw-r--r--net/core/ethtool.c91
-rw-r--r--net/core/fib_rules.c37
-rw-r--r--net/core/filter.c14
-rw-r--r--net/core/flow.c82
-rw-r--r--net/core/gen_estimator.c4
-rw-r--r--net/core/iovec.c6
-rw-r--r--net/core/neighbour.c486
-rw-r--r--net/core/net-sysfs.c59
-rw-r--r--net/core/net-sysfs.h4
-rw-r--r--net/core/net_namespace.c4
-rw-r--r--net/core/netpoll.c6
-rw-r--r--net/core/pktgen.c42
-rw-r--r--net/core/rtnetlink.c39
-rw-r--r--net/core/skbuff.c105
-rw-r--r--net/core/sock.c6
-rw-r--r--net/core/sysctl_net_core.c3
-rw-r--r--net/core/utils.c15
-rw-r--r--net/dccp/ccid.h52
-rw-r--r--net/dccp/ccids/Kconfig31
-rw-r--r--net/dccp/ccids/ccid2.c289
-rw-r--r--net/dccp/ccids/ccid2.h35
-rw-r--r--net/dccp/ccids/ccid3.c256
-rw-r--r--net/dccp/ccids/ccid3.h51
-rw-r--r--net/dccp/ccids/lib/loss_interval.c2
-rw-r--r--net/dccp/ccids/lib/packet_history.c39
-rw-r--r--net/dccp/ccids/lib/packet_history.h22
-rw-r--r--net/dccp/ccids/lib/tfrc.h1
-rw-r--r--net/dccp/ccids/lib/tfrc_equation.c14
-rw-r--r--net/dccp/dccp.h46
-rw-r--r--net/dccp/feat.c10
-rw-r--r--net/dccp/feat.h1
-rw-r--r--net/dccp/input.c20
-rw-r--r--net/dccp/ipv4.c10
-rw-r--r--net/dccp/ipv6.c10
-rw-r--r--net/dccp/minisocks.c30
-rw-r--r--net/dccp/options.c31
-rw-r--r--net/dccp/output.c20
-rw-r--r--net/dccp/proto.c50
-rw-r--r--net/decnet/dn_neigh.c13
-rw-r--r--net/decnet/dn_nsp_out.c8
-rw-r--r--net/decnet/dn_route.c3
-rw-r--r--net/econet/af_econet.c6
-rw-r--r--net/ethernet/eth.c8
-rw-r--r--net/ipv4/Kconfig12
-rw-r--r--net/ipv4/Makefile1
-rw-r--r--net/ipv4/af_inet.c8
-rw-r--r--net/ipv4/arp.c245
-rw-r--r--net/ipv4/cipso_ipv4.c2
-rw-r--r--net/ipv4/datagram.c2
-rw-r--r--net/ipv4/devinet.c11
-rw-r--r--net/ipv4/fib_frontend.c192
-rw-r--r--net/ipv4/fib_hash.c311
-rw-r--r--net/ipv4/fib_lookup.h11
-rw-r--r--net/ipv4/fib_rules.c13
-rw-r--r--net/ipv4/fib_semantics.c297
-rw-r--r--net/ipv4/fib_trie.c86
-rw-r--r--net/ipv4/gre.c152
-rw-r--r--net/ipv4/icmp.c4
-rw-r--r--net/ipv4/igmp.c22
-rw-r--r--net/ipv4/inet_diag.c2
-rw-r--r--net/ipv4/inet_hashtables.c28
-rw-r--r--net/ipv4/inetpeer.c138
-rw-r--r--net/ipv4/ip_fragment.c6
-rw-r--r--net/ipv4/ip_gre.c238
-rw-r--r--net/ipv4/ip_options.c3
-rw-r--r--net/ipv4/ip_output.c24
-rw-r--r--net/ipv4/ip_sockglue.c10
-rw-r--r--net/ipv4/ipip.c213
-rw-r--r--net/ipv4/ipmr.c428
-rw-r--r--net/ipv4/netfilter/Kconfig6
-rw-r--r--net/ipv4/netfilter/arp_tables.c64
-rw-r--r--net/ipv4/netfilter/arpt_mangle.c2
-rw-r--r--net/ipv4/netfilter/ip_tables.c84
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c31
-rw-r--r--net/ipv4/netfilter/ipt_LOG.c145
-rw-r--r--net/ipv4/netfilter/nf_nat_amanda.c9
-rw-r--r--net/ipv4/netfilter/nf_nat_core.c51
-rw-r--r--net/ipv4/netfilter/nf_nat_ftp.c9
-rw-r--r--net/ipv4/netfilter/nf_nat_h323.c53
-rw-r--r--net/ipv4/netfilter/nf_nat_helper.c76
-rw-r--r--net/ipv4/netfilter/nf_nat_irc.c9
-rw-r--r--net/ipv4/netfilter/nf_nat_rule.c17
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c27
-rw-r--r--net/ipv4/protocol.c33
-rw-r--r--net/ipv4/raw.c2
-rw-r--r--net/ipv4/route.c265
-rw-r--r--net/ipv4/tcp.c11
-rw-r--r--net/ipv4/tcp_illinois.c2
-rw-r--r--net/ipv4/tcp_input.c59
-rw-r--r--net/ipv4/tcp_ipv4.c12
-rw-r--r--net/ipv4/tcp_minisocks.c2
-rw-r--r--net/ipv4/tcp_output.c31
-rw-r--r--net/ipv4/tcp_timer.c50
-rw-r--r--net/ipv4/tcp_veno.c2
-rw-r--r--net/ipv4/tcp_westwood.c2
-rw-r--r--net/ipv4/tunnel4.c44
-rw-r--r--net/ipv4/udp.c6
-rw-r--r--net/ipv4/xfrm4_policy.c4
-rw-r--r--net/ipv4/xfrm4_tunnel.c4
-rw-r--r--net/ipv6/addrconf.c24
-rw-r--r--net/ipv6/addrlabel.c5
-rw-r--r--net/ipv6/af_inet6.c9
-rw-r--r--net/ipv6/datagram.c19
-rw-r--r--net/ipv6/exthdrs_core.c4
-rw-r--r--net/ipv6/fib6_rules.c3
-rw-r--r--net/ipv6/ip6_fib.c9
-rw-r--r--net/ipv6/ip6_output.c6
-rw-r--r--net/ipv6/ip6_tunnel.c159
-rw-r--r--net/ipv6/ip6mr.c1
-rw-r--r--net/ipv6/ipv6_sockglue.c27
-rw-r--r--net/ipv6/ndisc.c36
-rw-r--r--net/ipv6/netfilter/Kconfig9
-rw-r--r--net/ipv6/netfilter/Makefile8
-rw-r--r--net/ipv6/netfilter/ip6_tables.c98
-rw-r--r--net/ipv6/netfilter/ip6t_LOG.c157
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c78
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c19
-rw-r--r--net/ipv6/netfilter/nf_defrag_ipv6_hooks.c131
-rw-r--r--net/ipv6/protocol.c34
-rw-r--r--net/ipv6/raw.c14
-rw-r--r--net/ipv6/reassembly.c2
-rw-r--r--net/ipv6/route.c50
-rw-r--r--net/ipv6/sit.c166
-rw-r--r--net/ipv6/tcp_ipv6.c14
-rw-r--r--net/ipv6/tunnel6.c37
-rw-r--r--net/ipv6/udp.c18
-rw-r--r--net/ipv6/xfrm6_policy.c10
-rw-r--r--net/ipv6/xfrm6_tunnel.c8
-rw-r--r--net/irda/af_irda.c380
-rw-r--r--net/irda/discovery.c2
-rw-r--r--net/irda/ircomm/ircomm_tty.c4
-rw-r--r--net/irda/iriap.c3
-rw-r--r--net/irda/irlan/irlan_eth.c32
-rw-r--r--net/irda/irlan/irlan_event.c2
-rw-r--r--net/irda/irlmp.c2
-rw-r--r--net/irda/irlmp_frame.c2
-rw-r--r--net/irda/irnet/irnet.h2
-rw-r--r--net/irda/irnet/irnet_irda.c22
-rw-r--r--net/irda/irnet/irnet_ppp.c71
-rw-r--r--net/irda/irnet/irnet_ppp.h3
-rw-r--r--net/irda/parameters.c4
-rw-r--r--net/iucv/iucv.c3
-rw-r--r--net/key/af_key.c4
-rw-r--r--net/l2tp/l2tp_core.c53
-rw-r--r--net/l2tp/l2tp_core.h33
-rw-r--r--net/l2tp/l2tp_eth.c1
-rw-r--r--net/l2tp/l2tp_ip.c6
-rw-r--r--net/l2tp/l2tp_ppp.c2
-rw-r--r--net/mac80211/aes_ccm.c6
-rw-r--r--net/mac80211/aes_cmac.c6
-rw-r--r--net/mac80211/agg-rx.c30
-rw-r--r--net/mac80211/agg-tx.c14
-rw-r--r--net/mac80211/cfg.c244
-rw-r--r--net/mac80211/chan.c2
-rw-r--r--net/mac80211/debugfs.c7
-rw-r--r--net/mac80211/debugfs_key.c55
-rw-r--r--net/mac80211/debugfs_netdev.c3
-rw-r--r--net/mac80211/debugfs_sta.c5
-rw-r--r--net/mac80211/driver-ops.h14
-rw-r--r--net/mac80211/driver-trace.h42
-rw-r--r--net/mac80211/ht.c47
-rw-r--r--net/mac80211/ibss.c78
-rw-r--r--net/mac80211/ieee80211_i.h133
-rw-r--r--net/mac80211/iface.c460
-rw-r--r--net/mac80211/key.c168
-rw-r--r--net/mac80211/key.h13
-rw-r--r--net/mac80211/main.c202
-rw-r--r--net/mac80211/mesh.h2
-rw-r--r--net/mac80211/mesh_plink.c17
-rw-r--r--net/mac80211/mlme.c173
-rw-r--r--net/mac80211/offchannel.c26
-rw-r--r--net/mac80211/pm.c2
-rw-r--r--net/mac80211/rate.c14
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c7
-rw-r--r--net/mac80211/rc80211_pid_debugfs.c2
-rw-r--r--net/mac80211/rx.c819
-rw-r--r--net/mac80211/scan.c179
-rw-r--r--net/mac80211/sta_info.c52
-rw-r--r--net/mac80211/sta_info.h24
-rw-r--r--net/mac80211/status.c14
-rw-r--r--net/mac80211/tx.c73
-rw-r--r--net/mac80211/util.c102
-rw-r--r--net/mac80211/wep.c10
-rw-r--r--net/mac80211/work.c39
-rw-r--r--net/mac80211/wpa.c34
-rw-r--r--net/netfilter/Kconfig2
-rw-r--r--net/netfilter/core.c6
-rw-r--r--net/netfilter/ipvs/Kconfig20
-rw-r--r--net/netfilter/ipvs/Makefile10
-rw-r--r--net/netfilter/ipvs/ip_vs_app.c6
-rw-r--r--net/netfilter/ipvs/ip_vs_conn.c286
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c819
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c392
-rw-r--r--net/netfilter/ipvs/ip_vs_ftp.c194
-rw-r--r--net/netfilter/ipvs/ip_vs_nfct.c292
-rw-r--r--net/netfilter/ipvs/ip_vs_pe.c147
-rw-r--r--net/netfilter/ipvs/ip_vs_pe_sip.c169
-rw-r--r--net/netfilter/ipvs/ip_vs_proto.c8
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_ah_esp.c99
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_sctp.c27
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_tcp.c52
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_udp.c51
-rw-r--r--net/netfilter/ipvs/ip_vs_sched.c47
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c46
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c696
-rw-r--r--net/netfilter/nf_conntrack_core.c131
-rw-r--r--net/netfilter/nf_conntrack_expect.c68
-rw-r--r--net/netfilter/nf_conntrack_netlink.c77
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c4
-rw-r--r--net/netfilter/nf_conntrack_sip.c42
-rw-r--r--net/netfilter/nf_tproxy_core.c35
-rw-r--r--net/netfilter/x_tables.c12
-rw-r--r--net/netfilter/xt_TPROXY.c368
-rw-r--r--net/netfilter/xt_hashlimit.c15
-rw-r--r--net/netfilter/xt_ipvs.c1
-rw-r--r--net/netfilter/xt_socket.c171
-rw-r--r--net/netlink/af_netlink.c65
-rw-r--r--net/netlink/genetlink.c14
-rw-r--r--net/packet/af_packet.c4
-rw-r--r--net/phonet/Kconfig12
-rw-r--r--net/phonet/af_phonet.c17
-rw-r--r--net/phonet/datagram.c13
-rw-r--r--net/phonet/pep.c388
-rw-r--r--net/phonet/pn_dev.c5
-rw-r--r--net/phonet/socket.c289
-rw-r--r--net/rds/af_rds.c26
-rw-r--r--net/rds/bind.c82
-rw-r--r--net/rds/cong.c8
-rw-r--r--net/rds/connection.c159
-rw-r--r--net/rds/ib.c200
-rw-r--r--net/rds/ib.h104
-rw-r--r--net/rds/ib_cm.c184
-rw-r--r--net/rds/ib_rdma.c318
-rw-r--r--net/rds/ib_recv.c549
-rw-r--r--net/rds/ib_send.c682
-rw-r--r--net/rds/ib_stats.c2
-rw-r--r--net/rds/ib_sysctl.c19
-rw-r--r--net/rds/info.c12
-rw-r--r--net/rds/iw.c8
-rw-r--r--net/rds/iw.h15
-rw-r--r--net/rds/iw_cm.c14
-rw-r--r--net/rds/iw_rdma.c8
-rw-r--r--net/rds/iw_recv.c24
-rw-r--r--net/rds/iw_send.c93
-rw-r--r--net/rds/iw_sysctl.c6
-rw-r--r--net/rds/loop.c31
-rw-r--r--net/rds/message.c142
-rw-r--r--net/rds/page.c8
-rw-r--r--net/rds/rdma.c339
-rw-r--r--net/rds/rdma.h85
-rw-r--r--net/rds/rdma_transport.c44
-rw-r--r--net/rds/rdma_transport.h4
-rw-r--r--net/rds/rds.h192
-rw-r--r--net/rds/recv.c12
-rw-r--r--net/rds/send.c548
-rw-r--r--net/rds/stats.c6
-rw-r--r--net/rds/sysctl.c4
-rw-r--r--net/rds/tcp.c12
-rw-r--r--net/rds/tcp.h9
-rw-r--r--net/rds/tcp_connect.c2
-rw-r--r--net/rds/tcp_listen.c6
-rw-r--r--net/rds/tcp_recv.c17
-rw-r--r--net/rds/tcp_send.c68
-rw-r--r--net/rds/threads.c69
-rw-r--r--net/rds/transport.c19
-rw-r--r--net/rds/xlist.h80
-rw-r--r--net/rfkill/input.c2
-rw-r--r--net/rose/rose_link.c4
-rw-r--r--net/sched/Kconfig10
-rw-r--r--net/sched/Makefile1
-rw-r--r--net/sched/act_csum.c595
-rw-r--r--net/sched/act_ipt.c14
-rw-r--r--net/sched/cls_flow.c74
-rw-r--r--net/sched/em_meta.c6
-rw-r--r--net/sched/sch_api.c44
-rw-r--r--net/sched/sch_atm.c5
-rw-r--r--net/sched/sch_cbq.c12
-rw-r--r--net/sched/sch_drr.c4
-rw-r--r--net/sched/sch_dsmark.c6
-rw-r--r--net/sched/sch_fifo.c3
-rw-r--r--net/sched/sch_generic.c24
-rw-r--r--net/sched/sch_hfsc.c8
-rw-r--r--net/sched/sch_htb.c12
-rw-r--r--net/sched/sch_mq.c2
-rw-r--r--net/sched/sch_multiq.c3
-rw-r--r--net/sched/sch_netem.c3
-rw-r--r--net/sched/sch_prio.c2
-rw-r--r--net/sched/sch_sfq.c33
-rw-r--r--net/sched/sch_teql.c8
-rw-r--r--net/sctp/associola.c2
-rw-r--r--net/sctp/chunk.c2
-rw-r--r--net/sctp/inqueue.c2
-rw-r--r--net/sctp/ipv6.c4
-rw-r--r--net/sctp/objcnt.c5
-rw-r--r--net/sctp/output.c2
-rw-r--r--net/sctp/outqueue.c34
-rw-r--r--net/sctp/probe.c4
-rw-r--r--net/sctp/protocol.c19
-rw-r--r--net/sctp/sm_make_chunk.c2
-rw-r--r--net/sctp/sm_sideeffect.c21
-rw-r--r--net/sctp/sm_statefuns.c20
-rw-r--r--net/sctp/sm_statetable.c42
-rw-r--r--net/sctp/socket.c85
-rw-r--r--net/sctp/transport.c9
-rw-r--r--net/socket.c43
-rw-r--r--net/sunrpc/Kconfig19
-rw-r--r--net/sunrpc/auth.c4
-rw-r--r--net/sunrpc/auth_generic.c2
-rw-r--r--net/sunrpc/auth_gss/Makefile5
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c2
-rw-r--r--net/sunrpc/auth_gss/gss_generic_token.c44
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_mech.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_seqnum.c2
-rw-r--r--net/sunrpc/auth_gss/gss_mech_switch.c2
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_mech.c247
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_seal.c186
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_token.c267
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_unseal.c127
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c51
-rw-r--r--net/sunrpc/cache.c288
-rw-r--r--net/sunrpc/clnt.c3
-rw-r--r--net/sunrpc/netns.h19
-rw-r--r--net/sunrpc/rpc_pipe.c5
-rw-r--r--net/sunrpc/rpcb_clnt.c60
-rw-r--r--net/sunrpc/sched.c4
-rw-r--r--net/sunrpc/stats.c43
-rw-r--r--net/sunrpc/sunrpc_syms.c58
-rw-r--r--net/sunrpc/svc.c3
-rw-r--r--net/sunrpc/svc_xprt.c59
-rw-r--r--net/sunrpc/svcauth_unix.c194
-rw-r--r--net/sunrpc/svcsock.c27
-rw-r--r--net/sunrpc/xdr.c61
-rw-r--r--net/sunrpc/xprt.c39
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma.c11
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_recvfrom.c19
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_sendto.c82
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_transport.c49
-rw-r--r--net/sunrpc/xprtrdma/transport.c25
-rw-r--r--net/sunrpc/xprtsock.c358
-rw-r--r--net/tipc/addr.c7
-rw-r--r--net/tipc/bcast.c51
-rw-r--r--net/tipc/bcast.h3
-rw-r--r--net/tipc/bearer.c42
-rw-r--r--net/tipc/cluster.c21
-rw-r--r--net/tipc/cluster.h2
-rw-r--r--net/tipc/config.c148
-rw-r--r--net/tipc/config.h6
-rw-r--r--net/tipc/core.c38
-rw-r--r--net/tipc/core.h9
-rw-r--r--net/tipc/dbg.c17
-rw-r--r--net/tipc/dbg.h3
-rw-r--r--net/tipc/discover.c44
-rw-r--r--net/tipc/discover.h5
-rw-r--r--net/tipc/eth_media.c48
-rw-r--r--net/tipc/link.c188
-rw-r--r--net/tipc/link.h24
-rw-r--r--net/tipc/msg.c2
-rw-r--r--net/tipc/msg.h6
-rw-r--r--net/tipc/name_distr.c2
-rw-r--r--net/tipc/name_table.c67
-rw-r--r--net/tipc/net.c10
-rw-r--r--net/tipc/node.c73
-rw-r--r--net/tipc/node.h3
-rw-r--r--net/tipc/port.c295
-rw-r--r--net/tipc/port.h4
-rw-r--r--net/tipc/ref.c17
-rw-r--r--net/tipc/ref.h1
-rw-r--r--net/tipc/socket.c83
-rw-r--r--net/tipc/subscr.c77
-rw-r--r--net/tipc/subscr.h2
-rw-r--r--net/tipc/zone.c11
-rw-r--r--net/tipc/zone.h1
-rw-r--r--net/unix/af_unix.c24
-rw-r--r--net/wanrouter/wanmain.c4
-rw-r--r--net/wireless/core.c66
-rw-r--r--net/wireless/core.h34
-rw-r--r--net/wireless/ibss.c21
-rw-r--r--net/wireless/mlme.c225
-rw-r--r--net/wireless/nl80211.c2189
-rw-r--r--net/wireless/nl80211.h14
-rw-r--r--net/wireless/radiotap.c61
-rw-r--r--net/wireless/reg.c24
-rw-r--r--net/wireless/scan.c12
-rw-r--r--net/wireless/sme.c11
-rw-r--r--net/wireless/sysfs.c18
-rw-r--r--net/wireless/util.c40
-rw-r--r--net/wireless/wext-compat.c42
-rw-r--r--net/wireless/wext-core.c2
-rw-r--r--net/wireless/wext-sme.c2
-rw-r--r--net/x25/af_x25.c34
-rw-r--r--net/xfrm/xfrm_policy.c7
-rwxr-xr-xscripts/checkpatch.pl150
-rwxr-xr-xscripts/get_maintainer.pl1162
-rw-r--r--security/apparmor/path.c2
-rw-r--r--security/inode.c1
-rw-r--r--security/integrity/ima/ima.h18
-rw-r--r--security/integrity/ima/ima_api.c2
-rw-r--r--security/integrity/ima/ima_iint.c158
-rw-r--r--security/integrity/ima/ima_main.c184
-rw-r--r--security/keys/process_keys.c2
-rw-r--r--security/security.c10
-rw-r--r--security/selinux/selinuxfs.c1
-rw-r--r--security/tomoyo/realpath.c2
-rw-r--r--sound/core/init.c9
-rw-r--r--sound/core/oss/mixer_oss.c34
-rw-r--r--sound/core/pcm.c3
-rw-r--r--sound/core/pcm_lib.c14
-rw-r--r--sound/core/pcm_native.c4
-rw-r--r--sound/drivers/Kconfig19
-rw-r--r--sound/drivers/Makefile2
-rw-r--r--sound/drivers/aloop.c1258
-rw-r--r--sound/drivers/virmidi.c2
-rw-r--r--sound/i2c/other/ak4xxx-adda.c2
-rw-r--r--sound/isa/Kconfig36
-rw-r--r--sound/isa/Makefile4
-rw-r--r--sound/isa/ad1816a/ad1816a.c2
-rw-r--r--sound/isa/azt2320.c2
-rw-r--r--sound/isa/galaxy/Makefile10
-rw-r--r--sound/isa/galaxy/azt1605.c91
-rw-r--r--sound/isa/galaxy/azt2316.c111
-rw-r--r--sound/isa/galaxy/galaxy.c652
-rw-r--r--sound/isa/gus/gusmax.c4
-rw-r--r--sound/isa/sb/sb8.c2
-rw-r--r--sound/isa/sgalaxy.c369
-rw-r--r--sound/oss/Kconfig8
-rw-r--r--sound/oss/Makefile1
-rw-r--r--sound/oss/ac97_codec.c7
-rw-r--r--sound/oss/au1550_ac97.c48
-rw-r--r--sound/oss/dmasound/dmasound_core.c41
-rw-r--r--sound/oss/msnd_pinnacle.c15
-rw-r--r--sound/oss/sb_ess.c1
-rw-r--r--sound/oss/sh_dac_audio.c325
-rw-r--r--sound/oss/soundcard.c43
-rw-r--r--sound/oss/swarm_cs4297a.c20
-rw-r--r--sound/oss/vwsnd.c30
-rw-r--r--sound/pci/Kconfig17
-rw-r--r--sound/pci/au88x0/au88x0_mixer.c2
-rw-r--r--sound/pci/ca0106/ca0106.h5
-rw-r--r--sound/pci/ca0106/ca0106_main.c136
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c93
-rw-r--r--sound/pci/emu10k1/emumpu401.c2
-rw-r--r--sound/pci/ens1370.c2
-rw-r--r--sound/pci/hda/Kconfig39
-rw-r--r--sound/pci/hda/Makefile15
-rw-r--r--sound/pci/hda/hda_codec.c271
-rw-r--r--sound/pci/hda/hda_codec.h13
-rw-r--r--sound/pci/hda/hda_eld.c7
-rw-r--r--sound/pci/hda/hda_generic.c41
-rw-r--r--sound/pci/hda/hda_intel.c101
-rw-r--r--sound/pci/hda/hda_local.h51
-rw-r--r--sound/pci/hda/patch_analog.c48
-rw-r--r--sound/pci/hda/patch_atihdmi.c224
-rw-r--r--sound/pci/hda/patch_ca0110.c10
-rw-r--r--sound/pci/hda/patch_cirrus.c94
-rw-r--r--sound/pci/hda/patch_conexant.c651
-rw-r--r--sound/pci/hda/patch_hdmi.c797
-rw-r--r--sound/pci/hda/patch_intelhdmi.c220
-rw-r--r--sound/pci/hda/patch_nvhdmi.c608
-rw-r--r--sound/pci/hda/patch_realtek.c908
-rw-r--r--sound/pci/hda/patch_sigmatel.c457
-rw-r--r--sound/pci/hda/patch_via.c587
-rw-r--r--sound/pci/ice1712/delta.c10
-rw-r--r--sound/pci/ice1712/delta.h4
-rw-r--r--sound/pci/ice1712/pontis.c6
-rw-r--r--sound/pci/ice1712/prodigy192.c2
-rw-r--r--sound/pci/intel8x0.c2
-rw-r--r--sound/pci/oxygen/oxygen.c4
-rw-r--r--sound/pci/oxygen/oxygen.h1
-rw-r--r--sound/pci/oxygen/oxygen_lib.c55
-rw-r--r--sound/pci/oxygen/oxygen_mixer.c5
-rw-r--r--sound/pci/oxygen/oxygen_pcm.c12
-rw-r--r--sound/pci/oxygen/oxygen_regs.h10
-rw-r--r--sound/pci/oxygen/virtuoso.c5
-rw-r--r--sound/pci/oxygen/xonar_cs43xx.c8
-rw-r--r--sound/pci/oxygen/xonar_pcm179x.c29
-rw-r--r--sound/pci/oxygen/xonar_wm87x6.c121
-rw-r--r--sound/pci/rme96.c8
-rw-r--r--sound/pci/rme9652/hdsp.c8
-rw-r--r--sound/ppc/tumbler.c2
-rw-r--r--sound/soc/atmel/atmel-pcm.c59
-rw-r--r--sound/soc/atmel/atmel-pcm.h3
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c148
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.h3
-rw-r--r--sound/soc/atmel/playpaq_wm8510.c65
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c59
-rw-r--r--sound/soc/atmel/snd-soc-afeb9260.c35
-rw-r--r--sound/soc/au1x/db1200.c39
-rw-r--r--sound/soc/au1x/dbdma2.c95
-rw-r--r--sound/soc/au1x/psc-ac97.c71
-rw-r--r--sound/soc/au1x/psc-i2s.c53
-rw-r--r--sound/soc/au1x/psc.h10
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c43
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.h3
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c41
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.h2
-rw-r--r--sound/soc/blackfin/bf5xx-ad1836.c23
-rw-r--r--sound/soc/blackfin/bf5xx-ad193x.c23
-rw-r--r--sound/soc/blackfin/bf5xx-ad1980.c19
-rw-r--r--sound/soc/blackfin/bf5xx-ad73311.c22
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.c44
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.h3
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.c45
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.h14
-rw-r--r--sound/soc/blackfin/bf5xx-ssm2602.c38
-rw-r--r--sound/soc/blackfin/bf5xx-tdm-pcm.c43
-rw-r--r--sound/soc/blackfin/bf5xx-tdm-pcm.h3
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.c15
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.h2
-rw-r--r--sound/soc/codecs/88pm860x-codec.c1486
-rw-r--r--sound/soc/codecs/88pm860x-codec.h97
-rw-r--r--sound/soc/codecs/Kconfig24
-rw-r--r--sound/soc/codecs/Makefile12
-rw-r--r--sound/soc/codecs/ac97.c125
-rw-r--r--sound/soc/codecs/ac97.h19
-rw-r--r--sound/soc/codecs/ad1836.c191
-rw-r--r--sound/soc/codecs/ad1836.h2
-rw-r--r--sound/soc/codecs/ad193x.c217
-rw-r--r--sound/soc/codecs/ad193x.h3
-rw-r--r--sound/soc/codecs/ad1980.c113
-rw-r--r--sound/soc/codecs/ad1980.h3
-rw-r--r--sound/soc/codecs/ad73311.c66
-rw-r--r--sound/soc/codecs/ad73311.h2
-rw-r--r--sound/soc/codecs/ads117x.c72
-rw-r--r--sound/soc/codecs/ads117x.h4
-rw-r--r--sound/soc/codecs/ak4104.c149
-rw-r--r--sound/soc/codecs/ak4104.h7
-rw-r--r--sound/soc/codecs/ak4535.c236
-rw-r--r--sound/soc/codecs/ak4535.h8
-rw-r--r--sound/soc/codecs/ak4642.c235
-rw-r--r--sound/soc/codecs/ak4642.h20
-rw-r--r--sound/soc/codecs/ak4671.c140
-rw-r--r--sound/soc/codecs/ak4671.h3
-rw-r--r--sound/soc/codecs/cq93vc.c132
-rw-r--r--sound/soc/codecs/cq93vc.h29
-rw-r--r--sound/soc/codecs/cs4270.c394
-rw-r--r--sound/soc/codecs/cs4270.h28
-rw-r--r--sound/soc/codecs/cs42l51.c295
-rw-r--r--sound/soc/codecs/cs42l51.h2
-rw-r--r--sound/soc/codecs/cx20442.c173
-rw-r--r--sound/soc/codecs/cx20442.h2
-rw-r--r--sound/soc/codecs/da7210.c163
-rw-r--r--sound/soc/codecs/da7210.h24
-rw-r--r--sound/soc/codecs/jz4740.c116
-rw-r--r--sound/soc/codecs/jz4740.h20
-rw-r--r--sound/soc/codecs/max98088.c2097
-rw-r--r--sound/soc/codecs/max98088.h193
-rw-r--r--sound/soc/codecs/pcm3008.c92
-rw-r--r--sound/soc/codecs/pcm3008.h3
-rw-r--r--sound/soc/codecs/spdif_transciever.c102
-rw-r--r--sound/soc/codecs/spdif_transciever.h18
-rw-r--r--sound/soc/codecs/ssm2602.c218
-rw-r--r--sound/soc/codecs/ssm2602.h3
-rw-r--r--sound/soc/codecs/stac9766.c118
-rw-r--r--sound/soc/codecs/stac9766.h4
-rw-r--r--sound/soc/codecs/tlv320aic23.c182
-rw-r--r--sound/soc/codecs/tlv320aic23.h3
-rw-r--r--sound/soc/codecs/tlv320aic26.c180
-rw-r--r--sound/soc/codecs/tlv320aic26.h3
-rw-r--r--sound/soc/codecs/tlv320aic3x.c1230
-rw-r--r--sound/soc/codecs/tlv320aic3x.h100
-rw-r--r--sound/soc/codecs/tlv320dac33.c276
-rw-r--r--sound/soc/codecs/tlv320dac33.h3
-rw-r--r--sound/soc/codecs/tpa6130a2.c28
-rw-r--r--sound/soc/codecs/twl4030.c228
-rw-r--r--sound/soc/codecs/twl4030.h55
-rw-r--r--sound/soc/codecs/twl6040.c170
-rw-r--r--sound/soc/codecs/twl6040.h3
-rw-r--r--sound/soc/codecs/uda134x.c154
-rw-r--r--sound/soc/codecs/uda134x.h3
-rw-r--r--sound/soc/codecs/uda1380.c331
-rw-r--r--sound/soc/codecs/uda1380.h3
-rw-r--r--sound/soc/codecs/wl1273.c528
-rw-r--r--sound/soc/codecs/wl1273.h101
-rw-r--r--sound/soc/codecs/wm2000.h3
-rw-r--r--sound/soc/codecs/wm8350.c231
-rw-r--r--sound/soc/codecs/wm8350.h3
-rw-r--r--sound/soc/codecs/wm8400.c181
-rw-r--r--sound/soc/codecs/wm8400.h3
-rw-r--r--sound/soc/codecs/wm8510.c288
-rw-r--r--sound/soc/codecs/wm8510.h3
-rw-r--r--sound/soc/codecs/wm8523.c177
-rw-r--r--sound/soc/codecs/wm8523.h3
-rw-r--r--sound/soc/codecs/wm8580.c321
-rw-r--r--sound/soc/codecs/wm8580.h17
-rw-r--r--sound/soc/codecs/wm8711.c203
-rw-r--r--sound/soc/codecs/wm8711.h3
-rw-r--r--sound/soc/codecs/wm8727.c106
-rw-r--r--sound/soc/codecs/wm8727.h21
-rw-r--r--sound/soc/codecs/wm8728.c289
-rw-r--r--sound/soc/codecs/wm8728.h9
-rw-r--r--sound/soc/codecs/wm8731.c245
-rw-r--r--sound/soc/codecs/wm8731.h7
-rw-r--r--sound/soc/codecs/wm8741.c378
-rw-r--r--sound/soc/codecs/wm8741.h3
-rw-r--r--sound/soc/codecs/wm8750.c264
-rw-r--r--sound/soc/codecs/wm8750.h9
-rw-r--r--sound/soc/codecs/wm8753.c404
-rw-r--r--sound/soc/codecs/wm8753.h3
-rw-r--r--sound/soc/codecs/wm8776.c248
-rw-r--r--sound/soc/codecs/wm8776.h3
-rw-r--r--sound/soc/codecs/wm8804.c833
-rw-r--r--sound/soc/codecs/wm8804.h61
-rw-r--r--sound/soc/codecs/wm8900.c246
-rw-r--r--sound/soc/codecs/wm8900.h3
-rw-r--r--sound/soc/codecs/wm8903.c265
-rw-r--r--sound/soc/codecs/wm8903.h3
-rw-r--r--sound/soc/codecs/wm8904.c208
-rw-r--r--sound/soc/codecs/wm8904.h3
-rw-r--r--sound/soc/codecs/wm8940.c199
-rw-r--r--sound/soc/codecs/wm8940.h2
-rw-r--r--sound/soc/codecs/wm8955.c181
-rw-r--r--sound/soc/codecs/wm8955.h3
-rw-r--r--sound/soc/codecs/wm8960.c209
-rw-r--r--sound/soc/codecs/wm8960.h3
-rw-r--r--sound/soc/codecs/wm8961.c237
-rw-r--r--sound/soc/codecs/wm8961.h3
-rw-r--r--sound/soc/codecs/wm8962.c3977
-rw-r--r--sound/soc/codecs/wm8962.h3780
-rw-r--r--sound/soc/codecs/wm8971.c247
-rw-r--r--sound/soc/codecs/wm8971.h8
-rw-r--r--sound/soc/codecs/wm8974.c167
-rw-r--r--sound/soc/codecs/wm8974.h3
-rw-r--r--sound/soc/codecs/wm8978.c190
-rw-r--r--sound/soc/codecs/wm8978.h3
-rw-r--r--sound/soc/codecs/wm8985.c1192
-rw-r--r--sound/soc/codecs/wm8985.h1045
-rw-r--r--sound/soc/codecs/wm8988.c261
-rw-r--r--sound/soc/codecs/wm8988.h3
-rw-r--r--sound/soc/codecs/wm8990.c223
-rw-r--r--sound/soc/codecs/wm8990.h8
-rw-r--r--sound/soc/codecs/wm8993.c304
-rw-r--r--sound/soc/codecs/wm8993.h3
-rw-r--r--sound/soc/codecs/wm8994.c3410
-rw-r--r--sound/soc/codecs/wm8994.h3
-rw-r--r--sound/soc/codecs/wm9081.c208
-rw-r--r--sound/soc/codecs/wm9081.h3
-rw-r--r--sound/soc/codecs/wm9090.c185
-rw-r--r--sound/soc/codecs/wm9090.h2
-rw-r--r--sound/soc/codecs/wm9705.c116
-rw-r--r--sound/soc/codecs/wm9705.h3
-rw-r--r--sound/soc/codecs/wm9712.c124
-rw-r--r--sound/soc/codecs/wm9712.h3
-rw-r--r--sound/soc/codecs/wm9713.c131
-rw-r--r--sound/soc/codecs/wm9713.h3
-rw-r--r--sound/soc/davinci/davinci-evm.c109
-rw-r--r--sound/soc/davinci/davinci-i2s.c50
-rw-r--r--sound/soc/davinci/davinci-i2s.h2
-rw-r--r--sound/soc/davinci/davinci-mcasp.c34
-rw-r--r--sound/soc/davinci/davinci-mcasp.h2
-rw-r--r--sound/soc/davinci/davinci-pcm.c45
-rw-r--r--sound/soc/davinci/davinci-pcm.h3
-rw-r--r--sound/soc/davinci/davinci-sffsdr.c29
-rw-r--r--sound/soc/davinci/davinci-vcif.c25
-rw-r--r--sound/soc/davinci/davinci-vcif.h28
-rw-r--r--sound/soc/ep93xx/Kconfig16
-rw-r--r--sound/soc/ep93xx/Makefile4
-rw-r--r--sound/soc/ep93xx/ep93xx-ac97.c468
-rw-r--r--sound/soc/ep93xx/ep93xx-i2s.c34
-rw-r--r--sound/soc/ep93xx/ep93xx-i2s.h18
-rw-r--r--sound/soc/ep93xx/ep93xx-pcm.c37
-rw-r--r--sound/soc/ep93xx/ep93xx-pcm.h2
-rw-r--r--sound/soc/ep93xx/simone.c89
-rw-r--r--sound/soc/ep93xx/snappercl15.c24
-rw-r--r--sound/soc/fsl/Kconfig27
-rw-r--r--sound/soc/fsl/Makefile11
-rw-r--r--sound/soc/fsl/efika-audio-fabric.c20
-rw-r--r--sound/soc/fsl/fsl_dma.c458
-rw-r--r--sound/soc/fsl/fsl_dma.h20
-rw-r--r--sound/soc/fsl/fsl_ssi.c298
-rw-r--r--sound/soc/fsl/fsl_ssi.h26
-rw-r--r--sound/soc/fsl/mpc5200_dma.c66
-rw-r--r--sound/soc/fsl/mpc5200_dma.h5
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c34
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.h2
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.c19
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c660
-rw-r--r--sound/soc/fsl/p1022_ds.c591
-rw-r--r--sound/soc/fsl/pcm030-audio-fabric.c22
-rw-r--r--sound/soc/fsl/soc-of-simple.c172
-rw-r--r--sound/soc/imx/Kconfig16
-rw-r--r--sound/soc/imx/Makefile10
-rw-r--r--sound/soc/imx/eukrea-tlv320.c16
-rw-r--r--sound/soc/imx/imx-pcm-dma-mx2.c43
-rw-r--r--sound/soc/imx/imx-pcm-fiq.c68
-rw-r--r--sound/soc/imx/imx-ssi.c148
-rw-r--r--sound/soc/imx/imx-ssi.h7
-rw-r--r--sound/soc/imx/phycore-ac97.c19
-rw-r--r--sound/soc/imx/wm1133-ev1.c27
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c104
-rw-r--r--sound/soc/jz4740/jz4740-i2s.h2
-rw-r--r--sound/soc/jz4740/jz4740-pcm.c18
-rw-r--r--sound/soc/jz4740/jz4740-pcm.h2
-rw-r--r--sound/soc/jz4740/qi_lb60.c25
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c69
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.h17
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c55
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.h17
-rw-r--r--sound/soc/kirkwood/kirkwood-openrd.c24
-rw-r--r--sound/soc/nuc900/nuc900-ac97.c13
-rw-r--r--sound/soc/nuc900/nuc900-audio.c16
-rw-r--r--sound/soc/nuc900/nuc900-audio.h4
-rw-r--r--sound/soc/nuc900/nuc900-pcm.c38
-rw-r--r--sound/soc/omap/am3517evm.c29
-rw-r--r--sound/soc/omap/ams-delta.c98
-rw-r--r--sound/soc/omap/igep0020.c26
-rw-r--r--sound/soc/omap/mcpdm.c19
-rw-r--r--sound/soc/omap/mcpdm.h2
-rw-r--r--sound/soc/omap/n810.c42
-rw-r--r--sound/soc/omap/omap-mcbsp.c244
-rw-r--r--sound/soc/omap/omap-mcbsp.h2
-rw-r--r--sound/soc/omap/omap-mcpdm.c72
-rw-r--r--sound/soc/omap/omap-mcpdm.h29
-rw-r--r--sound/soc/omap/omap-pcm.c47
-rw-r--r--sound/soc/omap/omap-pcm.h2
-rw-r--r--sound/soc/omap/omap2evm.c29
-rw-r--r--sound/soc/omap/omap3beagle.c27
-rw-r--r--sound/soc/omap/omap3evm.c34
-rw-r--r--sound/soc/omap/omap3pandora.c36
-rw-r--r--sound/soc/omap/osk5912.c24
-rw-r--r--sound/soc/omap/overo.c22
-rw-r--r--sound/soc/omap/rx51.c41
-rw-r--r--sound/soc/omap/sdp3430.c60
-rw-r--r--sound/soc/omap/sdp4430.c27
-rw-r--r--sound/soc/omap/zoom2.c68
-rw-r--r--sound/soc/pxa/Kconfig18
-rw-r--r--sound/soc/pxa/Makefile4
-rw-r--r--sound/soc/pxa/corgi.c28
-rw-r--r--sound/soc/pxa/e740_wm9705.c29
-rw-r--r--sound/soc/pxa/e750_wm9705.c26
-rw-r--r--sound/soc/pxa/e800_wm9712.c26
-rw-r--r--sound/soc/pxa/em-x270.c22
-rw-r--r--sound/soc/pxa/imote2.c20
-rw-r--r--sound/soc/pxa/magician.c35
-rw-r--r--sound/soc/pxa/mioa701_wm9713.c33
-rw-r--r--sound/soc/pxa/palm27x.c27
-rw-r--r--sound/soc/pxa/poodle.c29
-rw-r--r--sound/soc/pxa/pxa-ssp.c174
-rw-r--r--sound/soc/pxa/pxa-ssp.h2
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c46
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.h2
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c91
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.h2
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c46
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.h19
-rw-r--r--sound/soc/pxa/raumfeld.c114
-rw-r--r--sound/soc/pxa/saarb.c200
-rw-r--r--sound/soc/pxa/spitz.c26
-rw-r--r--sound/soc/pxa/tavorevb3.c200
-rw-r--r--sound/soc/pxa/tosa.c27
-rw-r--r--sound/soc/pxa/z2.c26
-rw-r--r--sound/soc/pxa/zylonite.c40
-rw-r--r--sound/soc/s3c24xx/Kconfig37
-rw-r--r--sound/soc/s3c24xx/Makefile10
-rw-r--r--sound/soc/s3c24xx/aquila_wm8994.c295
-rw-r--r--sound/soc/s3c24xx/goni_wm8994.c298
-rw-r--r--sound/soc/s3c24xx/jive_wm8750.c23
-rw-r--r--sound/soc/s3c24xx/ln2440sbc_alc650.c17
-rw-r--r--sound/soc/s3c24xx/neo1973_gta02_wm8753.c60
-rw-r--r--sound/soc/s3c24xx/neo1973_wm8753.c39
-rw-r--r--sound/soc/s3c24xx/rx1950_uda1380.c333
-rw-r--r--sound/soc/s3c24xx/s3c-ac97.c36
-rw-r--r--sound/soc/s3c24xx/s3c-ac97.h2
-rw-r--r--sound/soc/s3c24xx/s3c-dma.c46
-rw-r--r--sound/soc/s3c24xx/s3c-dma.h1
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.c50
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.h13
-rw-r--r--sound/soc/s3c24xx/s3c-pcm.c54
-rw-r--r--sound/soc/s3c24xx/s3c-pcm.h3
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.c54
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.h2
-rw-r--r--sound/soc/s3c24xx/s3c24xx-i2s.c40
-rw-r--r--sound/soc/s3c24xx/s3c24xx-i2s.h2
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec.c15
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec.h4
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec_hermes.c25
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c21
-rw-r--r--sound/soc/s3c24xx/s3c24xx_uda134x.c21
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s-v4.c135
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.c206
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.h3
-rw-r--r--sound/soc/s3c24xx/smartq_wm8987.c15
-rw-r--r--sound/soc/s3c24xx/smdk2443_wm9710.c17
-rw-r--r--sound/soc/s3c24xx/smdk64xx_wm8580.c68
-rw-r--r--sound/soc/s3c24xx/smdk_spdif.c223
-rw-r--r--sound/soc/s3c24xx/smdk_wm9713.c42
-rw-r--r--sound/soc/s3c24xx/spdif.c501
-rw-r--r--sound/soc/s3c24xx/spdif.h19
-rw-r--r--sound/soc/s6000/s6000-i2s.c56
-rw-r--r--sound/soc/s6000/s6000-i2s.h2
-rw-r--r--sound/soc/s6000/s6000-pcm.c100
-rw-r--r--sound/soc/s6000/s6000-pcm.h2
-rw-r--r--sound/soc/s6000/s6105-ipcam.c31
-rw-r--r--sound/soc/sh/Kconfig11
-rw-r--r--sound/soc/sh/Makefile2
-rw-r--r--sound/soc/sh/dma-sh7760.c53
-rw-r--r--sound/soc/sh/fsi-ak4642.c31
-rw-r--r--sound/soc/sh/fsi-da7210.c24
-rw-r--r--sound/soc/sh/fsi-hdmi.c60
-rw-r--r--sound/soc/sh/fsi.c606
-rw-r--r--sound/soc/sh/hac.c46
-rw-r--r--sound/soc/sh/migor.c29
-rw-r--r--sound/soc/sh/sh7760-ac97.c25
-rw-r--r--sound/soc/sh/siu.h6
-rw-r--r--sound/soc/sh/siu_dai.c97
-rw-r--r--sound/soc/sh/siu_pcm.c34
-rw-r--r--sound/soc/sh/ssi.c55
-rw-r--r--sound/soc/soc-cache.c198
-rw-r--r--sound/soc/soc-core.c1821
-rw-r--r--sound/soc/soc-dapm.c88
-rw-r--r--sound/soc/soc-jack.c21
-rw-r--r--sound/soc/txx9/txx9aclc-ac97.c55
-rw-r--r--sound/soc/txx9/txx9aclc-generic.c24
-rw-r--r--sound/soc/txx9/txx9aclc.c141
-rw-r--r--sound/soc/txx9/txx9aclc.h13
-rw-r--r--sound/synth/emux/emux_hwdep.c3
-rw-r--r--sound/usb/Kconfig2
-rw-r--r--sound/usb/caiaq/audio.c175
-rw-r--r--sound/usb/caiaq/control.c208
-rw-r--r--sound/usb/caiaq/device.c10
-rw-r--r--sound/usb/caiaq/device.h6
-rw-r--r--sound/usb/caiaq/input.c248
-rw-r--r--sound/usb/card.c31
-rw-r--r--sound/usb/card.h2
-rw-r--r--sound/usb/endpoint.c2
-rw-r--r--sound/usb/helper.c17
-rw-r--r--sound/usb/midi.c16
-rw-r--r--sound/usb/mixer.c9
-rw-r--r--sound/usb/mixer_quirks.c1
-rw-r--r--sound/usb/pcm.c6
-rw-r--r--sound/usb/proc.c7
-rw-r--r--sound/usb/quirks-table.h184
-rw-r--r--sound/usb/quirks.c2
-rw-r--r--sound/usb/urb.c172
-rw-r--r--sound/usb/usbaudio.h2
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.c6
-rw-r--r--tools/perf/Documentation/perf-list.txt17
-rw-r--r--tools/perf/Documentation/perf-probe.txt18
-rw-r--r--tools/perf/Documentation/perf-record.txt4
-rw-r--r--tools/perf/builtin-probe.c78
-rw-r--r--tools/perf/builtin-record.c8
-rw-r--r--tools/perf/builtin-trace.c17
-rw-r--r--tools/perf/scripts/perl/bin/failed-syscalls-report2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-report2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-report2
-rw-r--r--tools/perf/scripts/perl/bin/rwtop-report2
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-report2
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-report2
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py58
-rw-r--r--tools/perf/scripts/python/bin/failed-syscalls-by-pid-report2
-rw-r--r--tools/perf/scripts/python/bin/futex-contention-record2
-rw-r--r--tools/perf/scripts/python/bin/futex-contention-report4
-rw-r--r--tools/perf/scripts/python/bin/netdev-times-report2
-rw-r--r--tools/perf/scripts/python/bin/sched-migration-report2
-rw-r--r--tools/perf/scripts/python/bin/sctop-report2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-by-pid-report2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-report2
-rw-r--r--tools/perf/scripts/python/failed-syscalls-by-pid.py21
-rw-r--r--tools/perf/scripts/python/futex-contention.py50
-rw-r--r--tools/perf/scripts/python/sctop.py9
-rw-r--r--tools/perf/scripts/python/syscall-counts-by-pid.py21
-rw-r--r--tools/perf/scripts/python/syscall-counts.py5
-rw-r--r--tools/perf/util/debug.c4
-rw-r--r--tools/perf/util/debug.h2
-rw-r--r--tools/perf/util/map.h10
-rw-r--r--tools/perf/util/probe-event.c189
-rw-r--r--tools/perf/util/probe-event.h16
-rw-r--r--tools/perf/util/probe-finder.c645
-rw-r--r--tools/perf/util/probe-finder.h31
-rw-r--r--tools/perf/util/ui/browser.c1
-rw-r--r--usr/Kconfig2
-rw-r--r--virt/kvm/irq_comm.c2
-rw-r--r--virt/kvm/kvm_main.c84
4530 files changed, 327006 insertions, 190952 deletions
diff --git a/Documentation/ABI/obsolete/dv1394 b/Documentation/ABI/obsolete/dv1394
deleted file mode 100644
index 2ee36864ca10..000000000000
--- a/Documentation/ABI/obsolete/dv1394
+++ /dev/null
@@ -1,9 +0,0 @@
-What: dv1394 (a.k.a. "OHCI-DV I/O support" for FireWire)
-Contact: linux1394-devel@lists.sourceforge.net
-Description:
- New application development should use raw1394 + userspace libraries
- instead, notably libiec61883 which is functionally equivalent.
-
-Users:
- ffmpeg/libavformat (used by a variety of media players)
- dvgrab v1.x (replaced by dvgrab2 on top of raw1394 and resp. libraries)
diff --git a/Documentation/ABI/removed/dv1394 b/Documentation/ABI/removed/dv1394
new file mode 100644
index 000000000000..c2310b6676f4
--- /dev/null
+++ b/Documentation/ABI/removed/dv1394
@@ -0,0 +1,14 @@
+What: dv1394 (a.k.a. "OHCI-DV I/O support" for FireWire)
+Date: May 2010 (scheduled), finally removed in kernel v2.6.37
+Contact: linux1394-devel@lists.sourceforge.net
+Description:
+ /dev/dv1394/* were character device files, one for each FireWire
+ controller and for NTSC and PAL respectively, from which DV data
+ could be received by read() or transmitted by write(). A few
+ ioctl()s allowed limited control.
+ This special-purpose interface has been superseded by libraw1394 +
+ libiec61883 which are functionally equivalent, support HDV, and
+ transparently work on top of the newer firewire kernel drivers.
+
+Users:
+ ffmpeg/libavformat (if configured for DV1394)
diff --git a/Documentation/ABI/removed/raw1394 b/Documentation/ABI/removed/raw1394
new file mode 100644
index 000000000000..490aa1efc4ae
--- /dev/null
+++ b/Documentation/ABI/removed/raw1394
@@ -0,0 +1,15 @@
+What: raw1394 (a.k.a. "Raw IEEE1394 I/O support" for FireWire)
+Date: May 2010 (scheduled), finally removed in kernel v2.6.37
+Contact: linux1394-devel@lists.sourceforge.net
+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 the kernel's ieee1394 core functionality.
+ Replaced by /dev/fw*, i.e. the <linux/firewire-cdev.h> ABI of
+ firewire-core.
+
+Users:
+ libraw1394 (works with firewire-cdev too, transparent to library ABI
+ users)
diff --git a/Documentation/ABI/removed/raw1394_legacy_isochronous b/Documentation/ABI/removed/raw1394_legacy_isochronous
deleted file mode 100644
index 1b629622d883..000000000000
--- a/Documentation/ABI/removed/raw1394_legacy_isochronous
+++ /dev/null
@@ -1,16 +0,0 @@
-What: legacy isochronous ABI of raw1394 (1st generation iso ABI)
-Date: June 2007 (scheduled), removed in kernel v2.6.23
-Contact: linux1394-devel@lists.sourceforge.net
-Description:
- The two request types RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN have
- been deprecated for quite some time. They are very inefficient as they
- come with high interrupt load and several layers of callbacks for each
- packet. Because of these deficiencies, the video1394 and dv1394 drivers
- and the 3rd-generation isochronous ABI in raw1394 (rawiso) were created.
-
-Users:
- libraw1394 users via the long deprecated API raw1394_iso_write,
- raw1394_start_iso_write, raw1394_start_iso_rcv, raw1394_stop_iso_rcv
-
- libdc1394, which optionally uses these old libraw1394 calls
- alternatively to the more efficient video1394 ABI
diff --git a/Documentation/ABI/removed/video1394 b/Documentation/ABI/removed/video1394
new file mode 100644
index 000000000000..c39c25aee77b
--- /dev/null
+++ b/Documentation/ABI/removed/video1394
@@ -0,0 +1,16 @@
+What: video1394 (a.k.a. "OHCI-1394 Video support" for FireWire)
+Date: May 2010 (scheduled), finally removed in kernel v2.6.37
+Contact: linux1394-devel@lists.sourceforge.net
+Description:
+ /dev/video1394/* were character device files, one for each FireWire
+ controller, which were used for isochronous I/O. It was added as an
+ alternative to raw1394's isochronous I/O functionality which had
+ performance issues in its first generation. Any video1394 user had
+ to use raw1394 + libraw1394 too because video1394 did not provide
+ asynchronous I/O for device discovery and configuration.
+ Replaced by /dev/fw*, i.e. the <linux/firewire-cdev.h> ABI of
+ firewire-core.
+
+Users:
+ libdc1394 (works with firewire-cdev too, transparent to library ABI
+ users)
diff --git a/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl b/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl
new file mode 100644
index 000000000000..b82deeaec314
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl
@@ -0,0 +1,22 @@
+What: state
+Date: Sep 2010
+KernelVersion: 2.6.37
+Contact: Vernon Mauery <vernux@us.ibm.com>
+Description: The state file allows a means by which to change in and
+ out of Premium Real-Time Mode (PRTM), as well as the
+ ability to query the current state.
+ 0 => PRTM off
+ 1 => PRTM enabled
+Users: The ibm-prtm userspace daemon uses this interface.
+
+
+What: version
+Date: Sep 2010
+KernelVersion: 2.6.37
+Contact: Vernon Mauery <vernux@us.ibm.com>
+Description: The version file provides a means by which to query
+ the RTL table version that lives in the Extended
+ BIOS Data Area (EBDA).
+Users: The ibm-prtm userspace daemon uses this interface.
+
+
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra b/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra
new file mode 100644
index 000000000000..ad1125b02ff4
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra
@@ -0,0 +1,98 @@
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_cpi
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: It is possible to switch the cpi setting of the mouse with the
+ press of a button.
+ When read, this file returns the raw number of the actual cpi
+ setting reported by the mouse. This number has to be further
+ processed to receive the real dpi value.
+
+ VALUE DPI
+ 1 400
+ 2 800
+ 4 1600
+
+ This file is readonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_profile
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: When read, this file returns the number of the actual profile in
+ range 0-4.
+ This file is readonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/firmware_version
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: When read, this file returns the raw integer version number of the
+ firmware reported by the mouse. Using the integer value eases
+ further usage in other programs. To receive the real version
+ number the decimal point has to be shifted 2 positions to the
+ left. E.g. a returned value of 138 means 1.38
+ This file is readonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile_settings
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The mouse can store 5 profiles which can be switched by the
+ press of a button. A profile is split in settings and buttons.
+ profile_settings holds informations like resolution, sensitivity
+ and light effects.
+ When written, this file lets one write the respective profile
+ settings back to the mouse. The data has to be 13 bytes long.
+ The mouse will reject invalid data.
+ Which profile to write is determined by the profile number
+ contained in the data.
+ This file is writeonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]_settings
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The mouse can store 5 profiles which can be switched by the
+ press of a button. A profile is split in settings and buttons.
+ profile_settings holds informations like resolution, sensitivity
+ and light effects.
+ When read, these files return the respective profile settings.
+ The returned data is 13 bytes in size.
+ This file is readonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile_buttons
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The mouse can store 5 profiles which can be switched by the
+ press of a button. A profile is split in settings and buttons.
+ profile_buttons holds informations about button layout.
+ When written, this file lets one write the respective profile
+ buttons back to the mouse. The data has to be 19 bytes long.
+ The mouse will reject invalid data.
+ Which profile to write is determined by the profile number
+ contained in the data.
+ This file is writeonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]_buttons
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The mouse can store 5 profiles which can be switched by the
+ press of a button. A profile is split in settings and buttons.
+ profile_buttons holds informations about button layout.
+ When read, these files return the respective profile buttons.
+ The returned data is 19 bytes in size.
+ This file is readonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/startup_profile
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The integer value of this attribute ranges from 0-4.
+ When read, this attribute returns the number of the profile
+ that's active when the mouse is powered on.
+ This file is readonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/settings
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: When read, this file returns the settings stored in the mouse.
+ The size of the data is 3 bytes and holds information on the
+ startup_profile.
+ When written, this file lets write settings back to the mouse.
+ The data has to be 3 bytes long. The mouse will reject invalid
+ data.
diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl
new file mode 100644
index 000000000000..19a1210c2530
--- /dev/null
+++ b/Documentation/DocBook/80211.tmpl
@@ -0,0 +1,495 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE set PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+<set>
+ <setinfo>
+ <title>The 802.11 subsystems &ndash; for kernel developers</title>
+ <subtitle>
+ Explaining wireless 802.11 networking in the Linux kernel
+ </subtitle>
+
+ <copyright>
+ <year>2007-2009</year>
+ <holder>Johannes Berg</holder>
+ </copyright>
+
+ <authorgroup>
+ <author>
+ <firstname>Johannes</firstname>
+ <surname>Berg</surname>
+ <affiliation>
+ <address><email>johannes@sipsolutions.net</email></address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <legalnotice>
+ <para>
+ This documentation 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.
+ </para>
+ <para>
+ This documentation is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+ </para>
+ <para>
+ You should have received a copy of the GNU General Public
+ License along with this documentation; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ MA 02111-1307 USA
+ </para>
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+
+ <abstract>
+ <para>
+ These books attempt to give a description of the
+ various subsystems that play a role in 802.11 wireless
+ networking in Linux. Since these books are for kernel
+ developers they attempts to document the structures
+ and functions used in the kernel as well as giving a
+ higher-level overview.
+ </para>
+ <para>
+ The reader is expected to be familiar with the 802.11
+ standard as published by the IEEE in 802.11-2007 (or
+ possibly later versions). References to this standard
+ will be given as "802.11-2007 8.1.5".
+ </para>
+ </abstract>
+ </setinfo>
+ <book id="cfg80211-developers-guide">
+ <bookinfo>
+ <title>The cfg80211 subsystem</title>
+
+ <abstract>
+!Pinclude/net/cfg80211.h Introduction
+ </abstract>
+ </bookinfo>
+ <chapter>
+ <title>Device registration</title>
+!Pinclude/net/cfg80211.h Device registration
+!Finclude/net/cfg80211.h ieee80211_band
+!Finclude/net/cfg80211.h ieee80211_channel_flags
+!Finclude/net/cfg80211.h ieee80211_channel
+!Finclude/net/cfg80211.h ieee80211_rate_flags
+!Finclude/net/cfg80211.h ieee80211_rate
+!Finclude/net/cfg80211.h ieee80211_sta_ht_cap
+!Finclude/net/cfg80211.h ieee80211_supported_band
+!Finclude/net/cfg80211.h cfg80211_signal_type
+!Finclude/net/cfg80211.h wiphy_params_flags
+!Finclude/net/cfg80211.h wiphy_flags
+!Finclude/net/cfg80211.h wiphy
+!Finclude/net/cfg80211.h wireless_dev
+!Finclude/net/cfg80211.h wiphy_new
+!Finclude/net/cfg80211.h wiphy_register
+!Finclude/net/cfg80211.h wiphy_unregister
+!Finclude/net/cfg80211.h wiphy_free
+
+!Finclude/net/cfg80211.h wiphy_name
+!Finclude/net/cfg80211.h wiphy_dev
+!Finclude/net/cfg80211.h wiphy_priv
+!Finclude/net/cfg80211.h priv_to_wiphy
+!Finclude/net/cfg80211.h set_wiphy_dev
+!Finclude/net/cfg80211.h wdev_priv
+ </chapter>
+ <chapter>
+ <title>Actions and configuration</title>
+!Pinclude/net/cfg80211.h Actions and configuration
+!Finclude/net/cfg80211.h cfg80211_ops
+!Finclude/net/cfg80211.h vif_params
+!Finclude/net/cfg80211.h key_params
+!Finclude/net/cfg80211.h survey_info_flags
+!Finclude/net/cfg80211.h survey_info
+!Finclude/net/cfg80211.h beacon_parameters
+!Finclude/net/cfg80211.h plink_actions
+!Finclude/net/cfg80211.h station_parameters
+!Finclude/net/cfg80211.h station_info_flags
+!Finclude/net/cfg80211.h rate_info_flags
+!Finclude/net/cfg80211.h rate_info
+!Finclude/net/cfg80211.h station_info
+!Finclude/net/cfg80211.h monitor_flags
+!Finclude/net/cfg80211.h mpath_info_flags
+!Finclude/net/cfg80211.h mpath_info
+!Finclude/net/cfg80211.h bss_parameters
+!Finclude/net/cfg80211.h ieee80211_txq_params
+!Finclude/net/cfg80211.h cfg80211_crypto_settings
+!Finclude/net/cfg80211.h cfg80211_auth_request
+!Finclude/net/cfg80211.h cfg80211_assoc_request
+!Finclude/net/cfg80211.h cfg80211_deauth_request
+!Finclude/net/cfg80211.h cfg80211_disassoc_request
+!Finclude/net/cfg80211.h cfg80211_ibss_params
+!Finclude/net/cfg80211.h cfg80211_connect_params
+!Finclude/net/cfg80211.h cfg80211_pmksa
+!Finclude/net/cfg80211.h cfg80211_send_rx_auth
+!Finclude/net/cfg80211.h cfg80211_send_auth_timeout
+!Finclude/net/cfg80211.h __cfg80211_auth_canceled
+!Finclude/net/cfg80211.h cfg80211_send_rx_assoc
+!Finclude/net/cfg80211.h cfg80211_send_assoc_timeout
+!Finclude/net/cfg80211.h cfg80211_send_deauth
+!Finclude/net/cfg80211.h __cfg80211_send_deauth
+!Finclude/net/cfg80211.h cfg80211_send_disassoc
+!Finclude/net/cfg80211.h __cfg80211_send_disassoc
+!Finclude/net/cfg80211.h cfg80211_ibss_joined
+!Finclude/net/cfg80211.h cfg80211_connect_result
+!Finclude/net/cfg80211.h cfg80211_roamed
+!Finclude/net/cfg80211.h cfg80211_disconnected
+!Finclude/net/cfg80211.h cfg80211_ready_on_channel
+!Finclude/net/cfg80211.h cfg80211_remain_on_channel_expired
+!Finclude/net/cfg80211.h cfg80211_new_sta
+!Finclude/net/cfg80211.h cfg80211_rx_mgmt
+!Finclude/net/cfg80211.h cfg80211_mgmt_tx_status
+!Finclude/net/cfg80211.h cfg80211_cqm_rssi_notify
+!Finclude/net/cfg80211.h cfg80211_michael_mic_failure
+ </chapter>
+ <chapter>
+ <title>Scanning and BSS list handling</title>
+!Pinclude/net/cfg80211.h Scanning and BSS list handling
+!Finclude/net/cfg80211.h cfg80211_ssid
+!Finclude/net/cfg80211.h cfg80211_scan_request
+!Finclude/net/cfg80211.h cfg80211_scan_done
+!Finclude/net/cfg80211.h cfg80211_bss
+!Finclude/net/cfg80211.h cfg80211_inform_bss_frame
+!Finclude/net/cfg80211.h cfg80211_inform_bss
+!Finclude/net/cfg80211.h cfg80211_unlink_bss
+!Finclude/net/cfg80211.h cfg80211_find_ie
+!Finclude/net/cfg80211.h ieee80211_bss_get_ie
+ </chapter>
+ <chapter>
+ <title>Utility functions</title>
+!Pinclude/net/cfg80211.h Utility functions
+!Finclude/net/cfg80211.h ieee80211_channel_to_frequency
+!Finclude/net/cfg80211.h ieee80211_frequency_to_channel
+!Finclude/net/cfg80211.h ieee80211_get_channel
+!Finclude/net/cfg80211.h ieee80211_get_response_rate
+!Finclude/net/cfg80211.h ieee80211_hdrlen
+!Finclude/net/cfg80211.h ieee80211_get_hdrlen_from_skb
+!Finclude/net/cfg80211.h ieee80211_radiotap_iterator
+ </chapter>
+ <chapter>
+ <title>Data path helpers</title>
+!Pinclude/net/cfg80211.h Data path helpers
+!Finclude/net/cfg80211.h ieee80211_data_to_8023
+!Finclude/net/cfg80211.h ieee80211_data_from_8023
+!Finclude/net/cfg80211.h ieee80211_amsdu_to_8023s
+!Finclude/net/cfg80211.h cfg80211_classify8021d
+ </chapter>
+ <chapter>
+ <title>Regulatory enforcement infrastructure</title>
+!Pinclude/net/cfg80211.h Regulatory enforcement infrastructure
+!Finclude/net/cfg80211.h regulatory_hint
+!Finclude/net/cfg80211.h wiphy_apply_custom_regulatory
+!Finclude/net/cfg80211.h freq_reg_info
+ </chapter>
+ <chapter>
+ <title>RFkill integration</title>
+!Pinclude/net/cfg80211.h RFkill integration
+!Finclude/net/cfg80211.h wiphy_rfkill_set_hw_state
+!Finclude/net/cfg80211.h wiphy_rfkill_start_polling
+!Finclude/net/cfg80211.h wiphy_rfkill_stop_polling
+ </chapter>
+ <chapter>
+ <title>Test mode</title>
+!Pinclude/net/cfg80211.h Test mode
+!Finclude/net/cfg80211.h cfg80211_testmode_alloc_reply_skb
+!Finclude/net/cfg80211.h cfg80211_testmode_reply
+!Finclude/net/cfg80211.h cfg80211_testmode_alloc_event_skb
+!Finclude/net/cfg80211.h cfg80211_testmode_event
+ </chapter>
+ </book>
+ <book id="mac80211-developers-guide">
+ <bookinfo>
+ <title>The mac80211 subsystem</title>
+ <abstract>
+!Pinclude/net/mac80211.h Introduction
+!Pinclude/net/mac80211.h Warning
+ </abstract>
+ </bookinfo>
+
+ <toc></toc>
+
+ <!--
+ Generally, this document shall be ordered by increasing complexity.
+ It is important to note that readers should be able to read only
+ the first few sections to get a working driver and only advanced
+ usage should require reading the full document.
+ -->
+
+ <part>
+ <title>The basic mac80211 driver interface</title>
+ <partintro>
+ <para>
+ You should read and understand the information contained
+ within this part of the book while implementing a driver.
+ In some chapters, advanced usage is noted, that may be
+ skipped at first.
+ </para>
+ <para>
+ This part of the book only covers station and monitor mode
+ functionality, additional information required to implement
+ the other modes is covered in the second part of the book.
+ </para>
+ </partintro>
+
+ <chapter id="basics">
+ <title>Basic hardware handling</title>
+ <para>TBD</para>
+ <para>
+ This chapter shall contain information on getting a hw
+ struct allocated and registered with mac80211.
+ </para>
+ <para>
+ Since it is required to allocate rates/modes before registering
+ a hw struct, this chapter shall also contain information on setting
+ up the rate/mode structs.
+ </para>
+ <para>
+ Additionally, some discussion about the callbacks and
+ the general programming model should be in here, including
+ the definition of ieee80211_ops which will be referred to
+ a lot.
+ </para>
+ <para>
+ Finally, a discussion of hardware capabilities should be done
+ with references to other parts of the book.
+ </para>
+ <!-- intentionally multiple !F lines to get proper order -->
+!Finclude/net/mac80211.h ieee80211_hw
+!Finclude/net/mac80211.h ieee80211_hw_flags
+!Finclude/net/mac80211.h SET_IEEE80211_DEV
+!Finclude/net/mac80211.h SET_IEEE80211_PERM_ADDR
+!Finclude/net/mac80211.h ieee80211_ops
+!Finclude/net/mac80211.h ieee80211_alloc_hw
+!Finclude/net/mac80211.h ieee80211_register_hw
+!Finclude/net/mac80211.h ieee80211_get_tx_led_name
+!Finclude/net/mac80211.h ieee80211_get_rx_led_name
+!Finclude/net/mac80211.h ieee80211_get_assoc_led_name
+!Finclude/net/mac80211.h ieee80211_get_radio_led_name
+!Finclude/net/mac80211.h ieee80211_unregister_hw
+!Finclude/net/mac80211.h ieee80211_free_hw
+ </chapter>
+
+ <chapter id="phy-handling">
+ <title>PHY configuration</title>
+ <para>TBD</para>
+ <para>
+ This chapter should describe PHY handling including
+ start/stop callbacks and the various structures used.
+ </para>
+!Finclude/net/mac80211.h ieee80211_conf
+!Finclude/net/mac80211.h ieee80211_conf_flags
+ </chapter>
+
+ <chapter id="iface-handling">
+ <title>Virtual interfaces</title>
+ <para>TBD</para>
+ <para>
+ This chapter should describe virtual interface basics
+ that are relevant to the driver (VLANs, MGMT etc are not.)
+ It should explain the use of the add_iface/remove_iface
+ callbacks as well as the interface configuration callbacks.
+ </para>
+ <para>Things related to AP mode should be discussed there.</para>
+ <para>
+ Things related to supporting multiple interfaces should be
+ in the appropriate chapter, a BIG FAT note should be here about
+ this though and the recommendation to allow only a single
+ interface in STA mode at first!
+ </para>
+!Finclude/net/mac80211.h ieee80211_vif
+ </chapter>
+
+ <chapter id="rx-tx">
+ <title>Receive and transmit processing</title>
+ <sect1>
+ <title>what should be here</title>
+ <para>TBD</para>
+ <para>
+ This should describe the receive and transmit
+ paths in mac80211/the drivers as well as
+ transmit status handling.
+ </para>
+ </sect1>
+ <sect1>
+ <title>Frame format</title>
+!Pinclude/net/mac80211.h Frame format
+ </sect1>
+ <sect1>
+ <title>Packet alignment</title>
+!Pnet/mac80211/rx.c Packet alignment
+ </sect1>
+ <sect1>
+ <title>Calling into mac80211 from interrupts</title>
+!Pinclude/net/mac80211.h Calling mac80211 from interrupts
+ </sect1>
+ <sect1>
+ <title>functions/definitions</title>
+!Finclude/net/mac80211.h ieee80211_rx_status
+!Finclude/net/mac80211.h mac80211_rx_flags
+!Finclude/net/mac80211.h ieee80211_tx_info
+!Finclude/net/mac80211.h ieee80211_rx
+!Finclude/net/mac80211.h ieee80211_rx_irqsafe
+!Finclude/net/mac80211.h ieee80211_tx_status
+!Finclude/net/mac80211.h ieee80211_tx_status_irqsafe
+!Finclude/net/mac80211.h ieee80211_rts_get
+!Finclude/net/mac80211.h ieee80211_rts_duration
+!Finclude/net/mac80211.h ieee80211_ctstoself_get
+!Finclude/net/mac80211.h ieee80211_ctstoself_duration
+!Finclude/net/mac80211.h ieee80211_generic_frame_duration
+!Finclude/net/mac80211.h ieee80211_wake_queue
+!Finclude/net/mac80211.h ieee80211_stop_queue
+!Finclude/net/mac80211.h ieee80211_wake_queues
+!Finclude/net/mac80211.h ieee80211_stop_queues
+ </sect1>
+ </chapter>
+
+ <chapter id="filters">
+ <title>Frame filtering</title>
+!Pinclude/net/mac80211.h Frame filtering
+!Finclude/net/mac80211.h ieee80211_filter_flags
+ </chapter>
+ </part>
+
+ <part id="advanced">
+ <title>Advanced driver interface</title>
+ <partintro>
+ <para>
+ Information contained within this part of the book is
+ of interest only for advanced interaction of mac80211
+ with drivers to exploit more hardware capabilities and
+ improve performance.
+ </para>
+ </partintro>
+
+ <chapter id="hardware-crypto-offload">
+ <title>Hardware crypto acceleration</title>
+!Pinclude/net/mac80211.h Hardware crypto acceleration
+ <!-- intentionally multiple !F lines to get proper order -->
+!Finclude/net/mac80211.h set_key_cmd
+!Finclude/net/mac80211.h ieee80211_key_conf
+!Finclude/net/mac80211.h ieee80211_key_flags
+ </chapter>
+
+ <chapter id="powersave">
+ <title>Powersave support</title>
+!Pinclude/net/mac80211.h Powersave support
+ </chapter>
+
+ <chapter id="beacon-filter">
+ <title>Beacon filter support</title>
+!Pinclude/net/mac80211.h Beacon filter support
+!Finclude/net/mac80211.h ieee80211_beacon_loss
+ </chapter>
+
+ <chapter id="qos">
+ <title>Multiple queues and QoS support</title>
+ <para>TBD</para>
+!Finclude/net/mac80211.h ieee80211_tx_queue_params
+ </chapter>
+
+ <chapter id="AP">
+ <title>Access point mode support</title>
+ <para>TBD</para>
+ <para>Some parts of the if_conf should be discussed here instead</para>
+ <para>
+ Insert notes about VLAN interfaces with hw crypto here or
+ in the hw crypto chapter.
+ </para>
+!Finclude/net/mac80211.h ieee80211_get_buffered_bc
+!Finclude/net/mac80211.h ieee80211_beacon_get
+ </chapter>
+
+ <chapter id="multi-iface">
+ <title>Supporting multiple virtual interfaces</title>
+ <para>TBD</para>
+ <para>
+ Note: WDS with identical MAC address should almost always be OK
+ </para>
+ <para>
+ Insert notes about having multiple virtual interfaces with
+ different MAC addresses here, note which configurations are
+ supported by mac80211, add notes about supporting hw crypto
+ with it.
+ </para>
+ </chapter>
+
+ <chapter id="hardware-scan-offload">
+ <title>Hardware scan offload</title>
+ <para>TBD</para>
+!Finclude/net/mac80211.h ieee80211_scan_completed
+ </chapter>
+ </part>
+
+ <part id="rate-control">
+ <title>Rate control interface</title>
+ <partintro>
+ <para>TBD</para>
+ <para>
+ This part of the book describes the rate control algorithm
+ interface and how it relates to mac80211 and drivers.
+ </para>
+ </partintro>
+ <chapter id="dummy">
+ <title>dummy chapter</title>
+ <para>TBD</para>
+ </chapter>
+ </part>
+
+ <part id="internal">
+ <title>Internals</title>
+ <partintro>
+ <para>TBD</para>
+ <para>
+ This part of the book describes mac80211 internals.
+ </para>
+ </partintro>
+
+ <chapter id="key-handling">
+ <title>Key handling</title>
+ <sect1>
+ <title>Key handling basics</title>
+!Pnet/mac80211/key.c Key handling basics
+ </sect1>
+ <sect1>
+ <title>MORE TBD</title>
+ <para>TBD</para>
+ </sect1>
+ </chapter>
+
+ <chapter id="rx-processing">
+ <title>Receive processing</title>
+ <para>TBD</para>
+ </chapter>
+
+ <chapter id="tx-processing">
+ <title>Transmit processing</title>
+ <para>TBD</para>
+ </chapter>
+
+ <chapter id="sta-info">
+ <title>Station info handling</title>
+ <sect1>
+ <title>Programming information</title>
+!Fnet/mac80211/sta_info.h sta_info
+!Fnet/mac80211/sta_info.h ieee80211_sta_info_flags
+ </sect1>
+ <sect1>
+ <title>STA information lifetime rules</title>
+!Pnet/mac80211/sta_info.c STA information lifetime rules
+ </sect1>
+ </chapter>
+
+ <chapter id="synchronisation">
+ <title>Synchronisation</title>
+ <para>TBD</para>
+ <para>Locking, lots of RCU</para>
+ </chapter>
+ </part>
+ </book>
+</set>
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 34929f24c284..8b6e00a71034 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -12,7 +12,7 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
- mac80211.xml debugobjects.xml sh.xml regulator.xml \
+ 80211.xml debugobjects.xml sh.xml regulator.xml \
alsa-driver-api.xml writing-an-alsa-driver.xml \
tracepoint.xml media.xml drm.xml
diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl
index feca0758391e..22edcbb9ddaf 100644
--- a/Documentation/DocBook/device-drivers.tmpl
+++ b/Documentation/DocBook/device-drivers.tmpl
@@ -51,8 +51,13 @@
<sect1><title>Delaying, scheduling, and timer routines</title>
!Iinclude/linux/sched.h
!Ekernel/sched.c
+!Iinclude/linux/completion.h
!Ekernel/timer.c
</sect1>
+ <sect1><title>Wait queues and Wake events</title>
+!Iinclude/linux/wait.h
+!Ekernel/wait.c
+ </sect1>
<sect1><title>High-resolution timers</title>
!Iinclude/linux/ktime.h
!Iinclude/linux/hrtimer.h
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 6b4e07f28b69..7160652a8736 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -93,6 +93,12 @@ X!Ilib/string.c
!Elib/crc32.c
!Elib/crc-ccitt.c
</sect1>
+
+ <sect1 id="idr"><title>idr/ida Functions</title>
+!Pinclude/linux/idr.h idr sync
+!Plib/idr.c IDA description
+!Elib/idr.c
+ </sect1>
</chapter>
<chapter id="mm">
diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl
deleted file mode 100644
index affb15a344a1..000000000000
--- a/Documentation/DocBook/mac80211.tmpl
+++ /dev/null
@@ -1,337 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
-
-<book id="mac80211-developers-guide">
- <bookinfo>
- <title>The mac80211 subsystem for kernel developers</title>
-
- <authorgroup>
- <author>
- <firstname>Johannes</firstname>
- <surname>Berg</surname>
- <affiliation>
- <address><email>johannes@sipsolutions.net</email></address>
- </affiliation>
- </author>
- </authorgroup>
-
- <copyright>
- <year>2007-2009</year>
- <holder>Johannes Berg</holder>
- </copyright>
-
- <legalnotice>
- <para>
- This documentation 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.
- </para>
-
- <para>
- This documentation is distributed in the hope that it will be
- useful, but WITHOUT ANY WARRANTY; without even the implied
- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- </para>
-
- <para>
- You should have received a copy of the GNU General Public
- License along with this documentation; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- </para>
-
- <para>
- For more details see the file COPYING in the source
- distribution of Linux.
- </para>
- </legalnotice>
-
- <abstract>
-!Pinclude/net/mac80211.h Introduction
-!Pinclude/net/mac80211.h Warning
- </abstract>
- </bookinfo>
-
- <toc></toc>
-
-<!--
-Generally, this document shall be ordered by increasing complexity.
-It is important to note that readers should be able to read only
-the first few sections to get a working driver and only advanced
-usage should require reading the full document.
--->
-
- <part>
- <title>The basic mac80211 driver interface</title>
- <partintro>
- <para>
- You should read and understand the information contained
- within this part of the book while implementing a driver.
- In some chapters, advanced usage is noted, that may be
- skipped at first.
- </para>
- <para>
- This part of the book only covers station and monitor mode
- functionality, additional information required to implement
- the other modes is covered in the second part of the book.
- </para>
- </partintro>
-
- <chapter id="basics">
- <title>Basic hardware handling</title>
- <para>TBD</para>
- <para>
- This chapter shall contain information on getting a hw
- struct allocated and registered with mac80211.
- </para>
- <para>
- Since it is required to allocate rates/modes before registering
- a hw struct, this chapter shall also contain information on setting
- up the rate/mode structs.
- </para>
- <para>
- Additionally, some discussion about the callbacks and
- the general programming model should be in here, including
- the definition of ieee80211_ops which will be referred to
- a lot.
- </para>
- <para>
- Finally, a discussion of hardware capabilities should be done
- with references to other parts of the book.
- </para>
-<!-- intentionally multiple !F lines to get proper order -->
-!Finclude/net/mac80211.h ieee80211_hw
-!Finclude/net/mac80211.h ieee80211_hw_flags
-!Finclude/net/mac80211.h SET_IEEE80211_DEV
-!Finclude/net/mac80211.h SET_IEEE80211_PERM_ADDR
-!Finclude/net/mac80211.h ieee80211_ops
-!Finclude/net/mac80211.h ieee80211_alloc_hw
-!Finclude/net/mac80211.h ieee80211_register_hw
-!Finclude/net/mac80211.h ieee80211_get_tx_led_name
-!Finclude/net/mac80211.h ieee80211_get_rx_led_name
-!Finclude/net/mac80211.h ieee80211_get_assoc_led_name
-!Finclude/net/mac80211.h ieee80211_get_radio_led_name
-!Finclude/net/mac80211.h ieee80211_unregister_hw
-!Finclude/net/mac80211.h ieee80211_free_hw
- </chapter>
-
- <chapter id="phy-handling">
- <title>PHY configuration</title>
- <para>TBD</para>
- <para>
- This chapter should describe PHY handling including
- start/stop callbacks and the various structures used.
- </para>
-!Finclude/net/mac80211.h ieee80211_conf
-!Finclude/net/mac80211.h ieee80211_conf_flags
- </chapter>
-
- <chapter id="iface-handling">
- <title>Virtual interfaces</title>
- <para>TBD</para>
- <para>
- This chapter should describe virtual interface basics
- that are relevant to the driver (VLANs, MGMT etc are not.)
- It should explain the use of the add_iface/remove_iface
- callbacks as well as the interface configuration callbacks.
- </para>
- <para>Things related to AP mode should be discussed there.</para>
- <para>
- Things related to supporting multiple interfaces should be
- in the appropriate chapter, a BIG FAT note should be here about
- this though and the recommendation to allow only a single
- interface in STA mode at first!
- </para>
-!Finclude/net/mac80211.h ieee80211_vif
- </chapter>
-
- <chapter id="rx-tx">
- <title>Receive and transmit processing</title>
- <sect1>
- <title>what should be here</title>
- <para>TBD</para>
- <para>
- This should describe the receive and transmit
- paths in mac80211/the drivers as well as
- transmit status handling.
- </para>
- </sect1>
- <sect1>
- <title>Frame format</title>
-!Pinclude/net/mac80211.h Frame format
- </sect1>
- <sect1>
- <title>Packet alignment</title>
-!Pnet/mac80211/rx.c Packet alignment
- </sect1>
- <sect1>
- <title>Calling into mac80211 from interrupts</title>
-!Pinclude/net/mac80211.h Calling mac80211 from interrupts
- </sect1>
- <sect1>
- <title>functions/definitions</title>
-!Finclude/net/mac80211.h ieee80211_rx_status
-!Finclude/net/mac80211.h mac80211_rx_flags
-!Finclude/net/mac80211.h ieee80211_tx_info
-!Finclude/net/mac80211.h ieee80211_rx
-!Finclude/net/mac80211.h ieee80211_rx_irqsafe
-!Finclude/net/mac80211.h ieee80211_tx_status
-!Finclude/net/mac80211.h ieee80211_tx_status_irqsafe
-!Finclude/net/mac80211.h ieee80211_rts_get
-!Finclude/net/mac80211.h ieee80211_rts_duration
-!Finclude/net/mac80211.h ieee80211_ctstoself_get
-!Finclude/net/mac80211.h ieee80211_ctstoself_duration
-!Finclude/net/mac80211.h ieee80211_generic_frame_duration
-!Finclude/net/mac80211.h ieee80211_wake_queue
-!Finclude/net/mac80211.h ieee80211_stop_queue
-!Finclude/net/mac80211.h ieee80211_wake_queues
-!Finclude/net/mac80211.h ieee80211_stop_queues
- </sect1>
- </chapter>
-
- <chapter id="filters">
- <title>Frame filtering</title>
-!Pinclude/net/mac80211.h Frame filtering
-!Finclude/net/mac80211.h ieee80211_filter_flags
- </chapter>
- </part>
-
- <part id="advanced">
- <title>Advanced driver interface</title>
- <partintro>
- <para>
- Information contained within this part of the book is
- of interest only for advanced interaction of mac80211
- with drivers to exploit more hardware capabilities and
- improve performance.
- </para>
- </partintro>
-
- <chapter id="hardware-crypto-offload">
- <title>Hardware crypto acceleration</title>
-!Pinclude/net/mac80211.h Hardware crypto acceleration
-<!-- intentionally multiple !F lines to get proper order -->
-!Finclude/net/mac80211.h set_key_cmd
-!Finclude/net/mac80211.h ieee80211_key_conf
-!Finclude/net/mac80211.h ieee80211_key_alg
-!Finclude/net/mac80211.h ieee80211_key_flags
- </chapter>
-
- <chapter id="powersave">
- <title>Powersave support</title>
-!Pinclude/net/mac80211.h Powersave support
- </chapter>
-
- <chapter id="beacon-filter">
- <title>Beacon filter support</title>
-!Pinclude/net/mac80211.h Beacon filter support
-!Finclude/net/mac80211.h ieee80211_beacon_loss
- </chapter>
-
- <chapter id="qos">
- <title>Multiple queues and QoS support</title>
- <para>TBD</para>
-!Finclude/net/mac80211.h ieee80211_tx_queue_params
- </chapter>
-
- <chapter id="AP">
- <title>Access point mode support</title>
- <para>TBD</para>
- <para>Some parts of the if_conf should be discussed here instead</para>
- <para>
- Insert notes about VLAN interfaces with hw crypto here or
- in the hw crypto chapter.
- </para>
-!Finclude/net/mac80211.h ieee80211_get_buffered_bc
-!Finclude/net/mac80211.h ieee80211_beacon_get
- </chapter>
-
- <chapter id="multi-iface">
- <title>Supporting multiple virtual interfaces</title>
- <para>TBD</para>
- <para>
- Note: WDS with identical MAC address should almost always be OK
- </para>
- <para>
- Insert notes about having multiple virtual interfaces with
- different MAC addresses here, note which configurations are
- supported by mac80211, add notes about supporting hw crypto
- with it.
- </para>
- </chapter>
-
- <chapter id="hardware-scan-offload">
- <title>Hardware scan offload</title>
- <para>TBD</para>
-!Finclude/net/mac80211.h ieee80211_scan_completed
- </chapter>
- </part>
-
- <part id="rate-control">
- <title>Rate control interface</title>
- <partintro>
- <para>TBD</para>
- <para>
- This part of the book describes the rate control algorithm
- interface and how it relates to mac80211 and drivers.
- </para>
- </partintro>
- <chapter id="dummy">
- <title>dummy chapter</title>
- <para>TBD</para>
- </chapter>
- </part>
-
- <part id="internal">
- <title>Internals</title>
- <partintro>
- <para>TBD</para>
- <para>
- This part of the book describes mac80211 internals.
- </para>
- </partintro>
-
- <chapter id="key-handling">
- <title>Key handling</title>
- <sect1>
- <title>Key handling basics</title>
-!Pnet/mac80211/key.c Key handling basics
- </sect1>
- <sect1>
- <title>MORE TBD</title>
- <para>TBD</para>
- </sect1>
- </chapter>
-
- <chapter id="rx-processing">
- <title>Receive processing</title>
- <para>TBD</para>
- </chapter>
-
- <chapter id="tx-processing">
- <title>Transmit processing</title>
- <para>TBD</para>
- </chapter>
-
- <chapter id="sta-info">
- <title>Station info handling</title>
- <sect1>
- <title>Programming information</title>
-!Fnet/mac80211/sta_info.h sta_info
-!Fnet/mac80211/sta_info.h ieee80211_sta_info_flags
- </sect1>
- <sect1>
- <title>STA information lifetime rules</title>
-!Pnet/mac80211/sta_info.c STA information lifetime rules
- </sect1>
- </chapter>
-
- <chapter id="synchronisation">
- <title>Synchronisation</title>
- <para>TBD</para>
- <para>Locking, lots of RCU</para>
- </chapter>
- </part>
-</book>
diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c
index 6e25c2659e0a..a2976a6de033 100644
--- a/Documentation/accounting/getdelays.c
+++ b/Documentation/accounting/getdelays.c
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
+#include <sys/wait.h>
#include <signal.h>
#include <linux/genetlink.h>
@@ -266,11 +267,13 @@ int main(int argc, char *argv[])
int containerset = 0;
char containerpath[1024];
int cfd = 0;
+ int forking = 0;
+ sigset_t sigset;
struct msgtemplate msg;
- while (1) {
- c = getopt(argc, argv, "qdiw:r:m:t:p:vlC:");
+ while (!forking) {
+ c = getopt(argc, argv, "qdiw:r:m:t:p:vlC:c:");
if (c < 0)
break;
@@ -319,6 +322,28 @@ int main(int argc, char *argv[])
err(1, "Invalid pid\n");
cmd_type = TASKSTATS_CMD_ATTR_PID;
break;
+ case 'c':
+
+ /* Block SIGCHLD for sigwait() later */
+ if (sigemptyset(&sigset) == -1)
+ err(1, "Failed to empty sigset");
+ if (sigaddset(&sigset, SIGCHLD))
+ err(1, "Failed to set sigchld in sigset");
+ sigprocmask(SIG_BLOCK, &sigset, NULL);
+
+ /* fork/exec a child */
+ tid = fork();
+ if (tid < 0)
+ err(1, "Fork failed\n");
+ if (tid == 0)
+ if (execvp(argv[optind - 1],
+ &argv[optind - 1]) < 0)
+ exit(-1);
+
+ /* Set the command type and avoid further processing */
+ cmd_type = TASKSTATS_CMD_ATTR_PID;
+ forking = 1;
+ break;
case 'v':
printf("debug on\n");
dbg = 1;
@@ -370,6 +395,15 @@ int main(int argc, char *argv[])
goto err;
}
+ /*
+ * If we forked a child, wait for it to exit. Cannot use waitpid()
+ * as all the delicious data would be reaped as part of the wait
+ */
+ if (tid && forking) {
+ int sig_received;
+ sigwait(&sigset, &sig_received);
+ }
+
if (tid) {
rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
cmd_type, &tid, sizeof(__u32));
diff --git a/Documentation/arm/SA1100/FreeBird b/Documentation/arm/SA1100/FreeBird
index fb23b770aaf4..ab9193663b2b 100644
--- a/Documentation/arm/SA1100/FreeBird
+++ b/Documentation/arm/SA1100/FreeBird
@@ -1,6 +1,6 @@
-Freebird-1.1 is produced by Legned(C) ,Inc.
+Freebird-1.1 is produced by Legend(C), Inc.
http://web.archive.org/web/*/http://www.legend.com.cn
-and software/linux mainatined by Coventive(C),Inc.
+and software/linux maintained by Coventive(C), Inc.
(http://www.coventive.com)
Based on the Nicolas's strongarm kernel tree.
diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt
index b34823ff1646..190018b0c649 100644
--- a/Documentation/cgroups/cgroups.txt
+++ b/Documentation/cgroups/cgroups.txt
@@ -18,7 +18,8 @@ CONTENTS:
1.2 Why are cgroups needed ?
1.3 How are cgroups implemented ?
1.4 What does notify_on_release do ?
- 1.5 How do I use cgroups ?
+ 1.5 What does clone_children do ?
+ 1.6 How do I use cgroups ?
2. Usage Examples and Syntax
2.1 Basic Usage
2.2 Attaching processes
@@ -293,7 +294,16 @@ notify_on_release in the root cgroup at system boot is disabled
value of their parents notify_on_release setting. The default value of
a cgroup hierarchy's release_agent path is empty.
-1.5 How do I use cgroups ?
+1.5 What does clone_children do ?
+---------------------------------
+
+If the clone_children flag is enabled (1) in a cgroup, then all
+cgroups created beneath will call the post_clone callbacks for each
+subsystem of the newly created cgroup. Usually when this callback is
+implemented for a subsystem, it copies the values of the parent
+subsystem, this is the case for the cpuset.
+
+1.6 How do I use cgroups ?
--------------------------
To start a new job that is to be contained within a cgroup, using
diff --git a/Documentation/fb/viafb.txt b/Documentation/fb/viafb.txt
index f3e046a6a987..1a2e8aa3fbb1 100644
--- a/Documentation/fb/viafb.txt
+++ b/Documentation/fb/viafb.txt
@@ -197,6 +197,54 @@ Notes:
example,
# fbset -depth 16
+
+[Configure viafb via /proc]
+---------------------------
+ The following files exist in /proc/viafb
+
+ supported_output_devices
+
+ This read-only file contains a full ',' seperated list containing all
+ output devices that could be available on your platform. It is likely
+ that not all of those have a connector on your hardware but it should
+ provide a good starting point to figure out which of those names match
+ a real connector.
+ Example:
+ # cat /proc/viafb/supported_output_devices
+
+ iga1/output_devices
+ iga2/output_devices
+
+ These two files are readable and writable. iga1 and iga2 are the two
+ independent units that produce the screen image. Those images can be
+ forwarded to one or more output devices. Reading those files is a way
+ to query which output devices are currently used by an iga.
+ Example:
+ # cat /proc/viafb/iga1/output_devices
+ If there are no output devices printed the output of this iga is lost.
+ This can happen for example if only one (the other) iga is used.
+ Writing to these files allows adjusting the output devices during
+ runtime. One can add new devices, remove existing ones or switch
+ between igas. Essentially you can write a ',' seperated list of device
+ names (or a single one) in the same format as the output to those
+ files. You can add a '+' or '-' as a prefix allowing simple addition
+ and removal of devices. So a prefix '+' adds the devices from your list
+ to the already existing ones, '-' removes the listed devices from the
+ existing ones and if no prefix is given it replaces all existing ones
+ with the listed ones. If you remove devices they are expected to turn
+ off. If you add devices that are already part of the other iga they are
+ removed there and added to the new one.
+ Examples:
+ Add CRT as output device to iga1
+ # echo +CRT > /proc/viafb/iga1/output_devices
+
+ Remove (turn off) DVP1 and LVDS1 as output devices of iga2
+ # echo -DVP1,LVDS1 > /proc/viafb/iga2/output_devices
+
+ Replace all iga1 output devices by CRT
+ # echo CRT > /proc/viafb/iga1/output_devices
+
+
[Bootup with viafb]:
--------------------
Add the following line to your grub.conf:
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 5e2bc4ab897a..f3da8c0a3af2 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -502,16 +502,6 @@ Who: Thomas Gleixner <tglx@linutronix.de>
----------------------------
-What: old ieee1394 subsystem (CONFIG_IEEE1394)
-When: 2.6.37
-Files: drivers/ieee1394/ except init_ohci1394_dma.c
-Why: superseded by drivers/firewire/ (CONFIG_FIREWIRE) which offers more
- features, better performance, and better security, all with smaller
- and more modern code base
-Who: Stefan Richter <stefanr@s5r6.in-berlin.de>
-
-----------------------------
-
What: The acpi_sleep=s4_nonvs command line option
When: 2.6.37
Files: arch/x86/kernel/acpi/sleep.c
@@ -536,3 +526,39 @@ Who: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
----------------------------
+What: namespace cgroup (ns_cgroup)
+When: 2.6.38
+Why: The ns_cgroup leads to some problems:
+ * cgroup creation is out-of-control
+ * cgroup name can conflict when pids are looping
+ * it is not possible to have a single process handling
+ a lot of namespaces without falling in a exponential creation time
+ * we may want to create a namespace without creating a cgroup
+
+ The ns_cgroup is replaced by a compatibility flag 'clone_children',
+ where a newly created cgroup will copy the parent cgroup values.
+ The userspace has to manually create a cgroup and add a task to
+ the 'tasks' file.
+Who: Daniel Lezcano <daniel.lezcano@free.fr>
+
+----------------------------
+
+What: iwlwifi disable_hw_scan module parameters
+When: 2.6.40
+Why: Hareware scan is the prefer method for iwlwifi devices for
+ scanning operation. Remove software scan support for all the
+ iwlwifi devices.
+
+Who: Wey-Yi Guy <wey-yi.w.guy@intel.com>
+
+----------------------------
+
+What: access to nfsd auth cache through sys_nfsservctl or '.' files
+ in the 'nfsd' filesystem.
+When: 2.6.40
+Why: This is a legacy interface which have been replaced by a more
+ dynamic cache. Continuing to maintain this interface is an
+ unnecessary burden.
+Who: NeilBrown <neilb@suse.de>
+
+----------------------------
diff --git a/Documentation/filesystems/9p.txt b/Documentation/filesystems/9p.txt
index f9765e8cf086..b22abba78fed 100644
--- a/Documentation/filesystems/9p.txt
+++ b/Documentation/filesystems/9p.txt
@@ -111,7 +111,7 @@ OPTIONS
This can be used to share devices/named pipes/sockets between
hosts. This functionality will be expanded in later versions.
- access there are three access modes.
+ access there are four access modes.
user = if a user tries to access a file on v9fs
filesystem for the first time, v9fs sends an
attach command (Tattach) for that user.
@@ -120,6 +120,8 @@ OPTIONS
the files on the mounted filesystem
any = v9fs does single attach and performs all
operations as one user
+ client = ACL based access check on the 9p client
+ side for access validation
cachetag cache tag to use the specified persistent cache.
cache tags for existing cache sessions can be listed at
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 2db4283efa8d..8a817f656f0a 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -349,21 +349,36 @@ call this method upon the IO completion.
--------------------------- block_device_operations -----------------------
prototypes:
- int (*open) (struct inode *, struct file *);
- int (*release) (struct inode *, struct file *);
- int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
+ int (*open) (struct block_device *, fmode_t);
+ int (*release) (struct gendisk *, fmode_t);
+ int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
+ int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
+ int (*direct_access) (struct block_device *, sector_t, void **, unsigned long *);
int (*media_changed) (struct gendisk *);
+ void (*unlock_native_capacity) (struct gendisk *);
int (*revalidate_disk) (struct gendisk *);
+ int (*getgeo)(struct block_device *, struct hd_geometry *);
+ void (*swap_slot_free_notify) (struct block_device *, unsigned long);
locking rules:
- BKL bd_sem
-open: yes yes
-release: yes yes
-ioctl: yes no
+ BKL bd_mutex
+open: no yes
+release: no yes
+ioctl: no no
+compat_ioctl: no no
+direct_access: no no
media_changed: no no
+unlock_native_capacity: no no
revalidate_disk: no no
+getgeo: no no
+swap_slot_free_notify: no no (see below)
+
+media_changed, unlock_native_capacity and revalidate_disk are called only from
+check_disk_change().
+
+swap_slot_free_notify is called with swap_lock and sometimes the page lock
+held.
-The last two are called only from check_disk_change().
--------------------------- file_operations -------------------------------
prototypes:
diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt
index e1def1786e50..6ab9442d7eeb 100644
--- a/Documentation/filesystems/ext4.txt
+++ b/Documentation/filesystems/ext4.txt
@@ -353,6 +353,20 @@ noauto_da_alloc replacing existing files via patterns such as
system crashes before the delayed allocation
blocks are forced to disk.
+noinit_itable Do not initialize any uninitialized inode table
+ blocks in the background. This feature may be
+ used by installation CD's so that the install
+ process can complete as quickly as possible; the
+ inode table initialization process would then be
+ deferred until the next time the file system
+ is unmounted.
+
+init_itable=n The lazy itable init code will wait n times the
+ number of milliseconds it took to zero out the
+ previous block group's inode table. This
+ minimizes the impact on the systme performance
+ while file system's inode table is being initialized.
+
discard Controls whether ext4 should issue discard/TRIM
nodiscard(*) commands to the underlying block device when
blocks are freed. This is useful for SSD devices
diff --git a/Documentation/filesystems/nfs/00-INDEX b/Documentation/filesystems/nfs/00-INDEX
index 2f68cd688769..a57e12411d2a 100644
--- a/Documentation/filesystems/nfs/00-INDEX
+++ b/Documentation/filesystems/nfs/00-INDEX
@@ -12,5 +12,9 @@ nfs-rdma.txt
- how to install and setup the Linux NFS/RDMA client and server software
nfsroot.txt
- short guide on setting up a diskless box with NFS root filesystem.
+pnfs.txt
+ - short explanation of some of the internals of the pnfs client code
rpc-cache.txt
- introduction to the caching mechanisms in the sunrpc layer.
+idmapper.txt
+ - information for configuring request-keys to be used by idmapper
diff --git a/Documentation/filesystems/nfs/idmapper.txt b/Documentation/filesystems/nfs/idmapper.txt
new file mode 100644
index 000000000000..b9b4192ea8b5
--- /dev/null
+++ b/Documentation/filesystems/nfs/idmapper.txt
@@ -0,0 +1,67 @@
+
+=========
+ID Mapper
+=========
+Id mapper is used by NFS to translate user and group ids into names, and to
+translate user and group names into ids. Part of this translation involves
+performing an upcall to userspace to request the information. Id mapper will
+user request-key to perform this upcall and cache the result. The program
+/usr/sbin/nfs.idmap should be called by request-key, and will perform the
+translation and initialize a key with the resulting information.
+
+ NFS_USE_NEW_IDMAPPER must be selected when configuring the kernel to use this
+ feature.
+
+===========
+Configuring
+===========
+The file /etc/request-key.conf will need to be modified so /sbin/request-key can
+direct the upcall. The following line should be added:
+
+#OP TYPE DESCRIPTION CALLOUT INFO PROGRAM ARG1 ARG2 ARG3 ...
+#====== ======= =============== =============== ===============================
+create id_resolver * * /usr/sbin/nfs.idmap %k %d 600
+
+This will direct all id_resolver requests to the program /usr/sbin/nfs.idmap.
+The last parameter, 600, defines how many seconds into the future the key will
+expire. This parameter is optional for /usr/sbin/nfs.idmap. When the timeout
+is not specified, nfs.idmap will default to 600 seconds.
+
+id mapper uses for key descriptions:
+ uid: Find the UID for the given user
+ gid: Find the GID for the given group
+ user: Find the user name for the given UID
+ group: Find the group name for the given GID
+
+You can handle any of these individually, rather than using the generic upcall
+program. If you would like to use your own program for a uid lookup then you
+would edit your request-key.conf so it look similar to this:
+
+#OP TYPE DESCRIPTION CALLOUT INFO PROGRAM ARG1 ARG2 ARG3 ...
+#====== ======= =============== =============== ===============================
+create id_resolver uid:* * /some/other/program %k %d 600
+create id_resolver * * /usr/sbin/nfs.idmap %k %d 600
+
+Notice that the new line was added above the line for the generic program.
+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/keys-request-keys.txt> for more information about the
+request-key function.
+
+
+=========
+nfs.idmap
+=========
+nfs.idmap is designed to be called by request-key, and should not be run "by
+hand". This program takes two arguments, a serialized key and a key
+description. The serialized key is first converted into a key_serial_t, and
+then passed as an argument to keyctl_instantiate (both are part of keyutils.h).
+
+The actual lookups are performed by functions found in nfsidmap.h. nfs.idmap
+determines the correct function to call by looking at the first part of the
+description string. For example, a uid lookup description will appear as
+"uid:user@domain".
+
+nfs.idmap will return 0 if the key was instantiated, and non-zero otherwise.
diff --git a/Documentation/filesystems/nfs/nfsroot.txt b/Documentation/filesystems/nfs/nfsroot.txt
index f2430a7974e1..90c71c6f0d00 100644
--- a/Documentation/filesystems/nfs/nfsroot.txt
+++ b/Documentation/filesystems/nfs/nfsroot.txt
@@ -159,6 +159,28 @@ ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>
Default: any
+nfsrootdebug
+
+ This parameter enables debugging messages to appear in the kernel
+ log at boot time so that administrators can verify that the correct
+ NFS mount options, server address, and root path are passed to the
+ NFS client.
+
+
+rdinit=<executable file>
+
+ To specify which file contains the program that starts system
+ initialization, administrators can use this command line parameter.
+ The default value of this parameter is "/init". If the specified
+ file exists and the kernel can execute it, root filesystem related
+ kernel command line parameters, including `nfsroot=', are ignored.
+
+ A description of the process of mounting the root file system can be
+ found in:
+
+ Documentation/early-userspace/README
+
+
3.) Boot Loader
diff --git a/Documentation/filesystems/nfs/pnfs.txt b/Documentation/filesystems/nfs/pnfs.txt
new file mode 100644
index 000000000000..bc0b9cfe095b
--- /dev/null
+++ b/Documentation/filesystems/nfs/pnfs.txt
@@ -0,0 +1,48 @@
+Reference counting in pnfs:
+==========================
+
+The are several inter-related caches. We have layouts which can
+reference multiple devices, each of which can reference multiple data servers.
+Each data server can be referenced by multiple devices. Each device
+can be referenced by multiple layouts. To keep all of this straight,
+we need to reference count.
+
+
+struct pnfs_layout_hdr
+----------------------
+The on-the-wire command LAYOUTGET corresponds to struct
+pnfs_layout_segment, usually referred to by the variable name lseg.
+Each nfs_inode may hold a pointer to a cache of of these layout
+segments in nfsi->layout, of type struct pnfs_layout_hdr.
+
+We reference the header for the inode pointing to it, across each
+outstanding RPC call that references it (LAYOUTGET, LAYOUTRETURN,
+LAYOUTCOMMIT), and for each lseg held within.
+
+Each header is also (when non-empty) put on a list associated with
+struct nfs_client (cl_layouts). Being put on this list does not bump
+the reference count, as the layout is kept around by the lseg that
+keeps it in the list.
+
+deviceid_cache
+--------------
+lsegs reference device ids, which are resolved per nfs_client and
+layout driver type. The device ids are held in a RCU cache (struct
+nfs4_deviceid_cache). The cache itself is referenced across each
+mount. The entries (struct nfs4_deviceid) themselves are held across
+the lifetime of each lseg referencing them.
+
+RCU is used because the deviceid is basically a write once, read many
+data structure. The hlist size of 32 buckets needs better
+justification, but seems reasonable given that we can have multiple
+deviceid's per filesystem, and multiple filesystems per nfs_client.
+
+The hash code is copied from the nfsd code base. A discussion of
+hashing and variations of this algorithm can be found at:
+http://groups.google.com/group/comp.lang.c/browse_thread/thread/9522965e2b8d3809
+
+data server cache
+-----------------
+file driver devices refer to data servers, which are kept in a module
+level cache. Its reference is held over the lifetime of the deviceid
+pointing to it.
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 98223a676940..e73df2722ff3 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -136,6 +136,7 @@ Table 1-1: Process specific entries in /proc
statm Process memory status information
status Process status in human readable form
wchan If CONFIG_KALLSYMS is set, a pre-decoded wchan
+ pagemap Page table
stack Report full stack trace, enable via CONFIG_STACKTRACE
smaps a extension based on maps, showing the memory consumption of
each mapping
@@ -370,17 +371,24 @@ Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 892 kB
+Anonymous: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
-The first of these lines shows the same information as is displayed for the
-mapping in /proc/PID/maps. The remaining lines show the size of the mapping,
-the amount of the mapping that is currently resident in RAM, the "proportional
-set size” (divide each shared page by the number of processes sharing it), the
-number of clean and dirty shared pages in the mapping, and the number of clean
-and dirty private pages in the mapping. The "Referenced" indicates the amount
-of memory currently marked as referenced or accessed.
+The first of these lines shows the same information as is displayed for the
+mapping in /proc/PID/maps. The remaining lines show the size of the mapping
+(size), the amount of the mapping that is currently resident in RAM (RSS), the
+process' proportional share of this mapping (PSS), the number of clean and
+dirty private pages in the mapping. Note that even a page which is part of a
+MAP_SHARED mapping, but has only a single pte mapped, i.e. is currently used
+by only one process, is accounted as private and not as shared. "Referenced"
+indicates the amount of memory currently marked as referenced or accessed.
+"Anonymous" shows the amount of memory that does not belong to any file. Even
+a mapping associated with a file may contain anonymous pages: when MAP_PRIVATE
+and a page is modified, the file page is replaced by a private anonymous copy.
+"Swap" shows how much would-be-anonymous memory is also used, but out on
+swap.
This file is only present if the CONFIG_MMU kernel configuration option is
enabled.
@@ -397,6 +405,9 @@ To clear the bits for the file mapped pages associated with the process
> echo 3 > /proc/PID/clear_refs
Any other value written to /proc/PID/clear_refs will have no effect.
+The /proc/pid/pagemap gives the PFN, which can be used to find the pageflags
+using /proc/kpageflags and number of times a page is mapped using
+/proc/kpagecount. For detailed explanation, see Documentation/vm/pagemap.txt.
1.2 Kernel data
---------------
@@ -1075,7 +1086,6 @@ Table 1-11: Files in /proc/tty
drivers list of drivers and their usage
ldiscs registered line disciplines
driver/serial usage statistic and status of single tty lines
- consoles registered system console lines
..............................................................................
To see which tty's are currently in use, you can simply look into the file
@@ -1094,37 +1104,6 @@ To see which tty's are currently in use, you can simply look into the file
/dev/tty /dev/tty 5 0 system:/dev/tty
unknown /dev/tty 4 1-63 console
-To see which character device lines are currently used for the system console
-/dev/console, you may simply look into the file /proc/tty/consoles:
-
- > cat /proc/tty/consoles
- tty0 -WU (ECp) 4:7
- ttyS0 -W- (Ep) 4:64
-
-The columns are:
-
- device name of the device
- operations R = can do read operations
- W = can do write operations
- U = can do unblank
- flags E = it is enabled
- C = it is prefered console
- B = it is primary boot console
- p = it is used for printk buffer
- b = it is not a TTY but a Braille device
- a = it is safe to use when cpu is offline
- * = it is standard input of the reading process
- major:minor major and minor number of the device separated by a colon
-
-If the reading process holds /dev/console open at the regular standard input
-stream the active device will be marked by an asterisk:
-
- > cat /proc/tty/consoles < /dev/console
- tty0 -WU (ECp*) 4:7
- ttyS0 -W- (Ep) 4:64
- > tty
- /dev/pts/3
-
1.8 Miscellaneous kernel statistics in /proc/stat
-------------------------------------------------
diff --git a/Documentation/filesystems/sharedsubtree.txt b/Documentation/filesystems/sharedsubtree.txt
index fc0e39af43c3..4ede421c9687 100644
--- a/Documentation/filesystems/sharedsubtree.txt
+++ b/Documentation/filesystems/sharedsubtree.txt
@@ -62,10 +62,10 @@ replicas continue to be exactly same.
# mount /dev/sd0 /tmp/a
#ls /tmp/a
- t1 t2 t2
+ t1 t2 t3
#ls /mnt/a
- t1 t2 t2
+ t1 t2 t3
Note that the mount has propagated to the mount at /mnt as well.
diff --git a/Documentation/hwmon/ltc4261 b/Documentation/hwmon/ltc4261
new file mode 100644
index 000000000000..eba2e2c4b94d
--- /dev/null
+++ b/Documentation/hwmon/ltc4261
@@ -0,0 +1,63 @@
+Kernel driver ltc4261
+=====================
+
+Supported chips:
+ * Linear Technology LTC4261
+ Prefix: 'ltc4261'
+ Addresses scanned: -
+ Datasheet:
+ http://cds.linear.com/docs/Datasheet/42612fb.pdf
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+The LTC4261/LTC4261-2 negative voltage Hot Swap controllers allow a board
+to be safely inserted and removed from a live backplane.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for LTC4261 devices, since there is no register
+which can be safely used to identify the chip. You will have to instantiate
+the devices explicitly.
+
+Example: the following will load the driver for an LTC4261 at address 0x10
+on I2C bus #1:
+$ modprobe ltc4261
+$ echo ltc4261 0x10 > /sys/bus/i2c/devices/i2c-1/new_device
+
+
+Sysfs entries
+-------------
+
+Voltage readings provided by this driver are reported as obtained from the ADC
+registers. If a set of voltage divider resistors is installed, calculate the
+real voltage by multiplying the reported value with (R1+R2)/R2, where R1 is the
+value of the divider resistor against the measured voltage and R2 is the value
+of the divider resistor against Ground.
+
+Current reading provided by this driver is reported as obtained from the ADC
+Current Sense register. The reported value assumes that a 1 mOhm sense resistor
+is installed. If a different sense resistor is installed, calculate the real
+current by dividing the reported value by the sense resistor value in mOhm.
+
+The chip has two voltage sensors, but only one set of voltage alarm status bits.
+In many many designs, those alarms are associated with the ADIN2 sensor, due to
+the proximity of the ADIN2 pin to the OV pin. ADIN2 is, however, not available
+on all chip variants. To ensure that the alarm condition is reported to the user,
+report it with both voltage sensors.
+
+in1_input ADIN2 voltage (mV)
+in1_min_alarm ADIN/ADIN2 Undervoltage alarm
+in1_max_alarm ADIN/ADIN2 Overvoltage alarm
+
+in2_input ADIN voltage (mV)
+in2_min_alarm ADIN/ADIN2 Undervoltage alarm
+in2_max_alarm ADIN/ADIN2 Overvoltage alarm
+
+curr1_input SENSE current (mA)
+curr1_alarm SENSE overcurrent alarm
diff --git a/Documentation/input/ntrig.txt b/Documentation/input/ntrig.txt
new file mode 100644
index 000000000000..be1fd981f73f
--- /dev/null
+++ b/Documentation/input/ntrig.txt
@@ -0,0 +1,126 @@
+N-Trig touchscreen Driver
+-------------------------
+ Copyright (c) 2008-2010 Rafi Rubin <rafi@seas.upenn.edu>
+ Copyright (c) 2009-2010 Stephane Chatty
+
+This driver provides support for N-Trig pen and multi-touch sensors. Single
+and multi-touch events are translated to the appropriate protocols for
+the hid and input systems. Pen events are sufficiently hid compliant and
+are left to the hid core. The driver also provides additional filtering
+and utility functions accessible with sysfs and module parameters.
+
+This driver has been reported to work properly with multiple N-Trig devices
+attached.
+
+
+Parameters
+----------
+
+Note: values set at load time are global and will apply to all applicable
+devices. Adjusting parameters with sysfs will override the load time values,
+but only for that one device.
+
+The following parameters are used to configure filters to reduce noise:
+
+activate_slack number of fingers to ignore before processing events
+
+activation_height size threshold to activate immediately
+activation_width
+
+min_height size threshold bellow which fingers are ignored
+min_width both to decide activation and during activity
+
+deactivate_slack the number of "no contact" frames to ignore before
+ propagating the end of activity events
+
+When the last finger is removed from the device, it sends a number of empty
+frames. By holding off on deactivation for a few frames we can tolerate false
+erroneous disconnects, where the sensor may mistakenly not detect a finger that
+is still present. Thus deactivate_slack addresses problems where a users might
+see breaks in lines during drawing, or drop an object during a long drag.
+
+
+Additional sysfs items
+----------------------
+
+These nodes just provide easy access to the ranges reported by the device.
+sensor_logical_height the range for positions reported during activity
+sensor_logical_width
+
+sensor_physical_height internal ranges not used for normal events but
+sensor_physical_width useful for tuning
+
+All N-Trig devices with product id of 1 report events in the ranges of
+X: 0-9600
+Y: 0-7200
+However not all of these devices have the same physical dimensions. Most
+seem to be 12" sensors (Dell Latitude XT and XT2 and the HP TX2), and
+at least one model (Dell Studio 17) has a 17" sensor. The ratio of physical
+to logical sizes is used to adjust the size based filter parameters.
+
+
+Filtering
+---------
+
+With the release of the early multi-touch firmwares it became increasingly
+obvious that these sensors were prone to erroneous events. Users reported
+seeing both inappropriately dropped contact and ghosts, contacts reported
+where no finger was actually touching the screen.
+
+Deactivation slack helps prevent dropped contact for single touch use, but does
+not address the problem of dropping one of more contacts while other contacts
+are still active. Drops in the multi-touch context require additional
+processing and should be handled in tandem with tacking.
+
+As observed ghost contacts are similar to actual use of the sensor, but they
+seem to have different profiles. Ghost activity typically shows up as small
+short lived touches. As such, I assume that the longer the continuous stream
+of events the more likely those events are from a real contact, and that the
+larger the size of each contact the more likely it is real. Balancing the
+goals of preventing ghosts and accepting real events quickly (to minimize
+user observable latency), the filter accumulates confidence for incoming
+events until it hits thresholds and begins propagating. In the interest in
+minimizing stored state as well as the cost of operations to make a decision,
+I've kept that decision simple.
+
+Time is measured in terms of the number of fingers reported, not frames since
+the probability of multiple simultaneous ghosts is expected to drop off
+dramatically with increasing numbers. Rather than accumulate weight as a
+function of size, I just use it as a binary threshold. A sufficiently large
+contact immediately overrides the waiting period and leads to activation.
+
+Setting the activation size thresholds to large values will result in deciding
+primarily on activation slack. If you see longer lived ghosts, turning up the
+activation slack while reducing the size thresholds may suffice to eliminate
+the ghosts while keeping the screen quite responsive to firm taps.
+
+Contacts continue to be filtered with min_height and min_width even after
+the initial activation filter is satisfied. The intent is to provide
+a mechanism for filtering out ghosts in the form of an extra finger while
+you actually are using the screen. In practice this sort of ghost has
+been far less problematic or relatively rare and I've left the defaults
+set to 0 for both parameters, effectively turning off that filter.
+
+I don't know what the optimal values are for these filters. If the defaults
+don't work for you, please play with the parameters. If you do find other
+values more comfortable, I would appreciate feedback.
+
+The calibration of these devices does drift over time. If ghosts or contact
+dropping worsen and interfere with the normal usage of your device, try
+recalibrating it.
+
+
+Calibration
+-----------
+
+The N-Trig windows tools provide calibration and testing routines. Also an
+unofficial unsupported set of user space tools including a calibrator is
+available at:
+http://code.launchpad.net/~rafi-seas/+junk/ntrig_calib
+
+
+Tracking
+--------
+
+As of yet, all tested N-Trig firmwares do not track fingers. When multiple
+contacts are active they seem to be sorted primarily by Y position.
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 4cd8b86e00ea..4bc2f3c3da5b 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1131,9 +1131,13 @@ and is between 256 and 4096 characters. It is defined in the file
kvm.oos_shadow= [KVM] Disable out-of-sync shadow paging.
Default is 1 (enabled)
- kvm-amd.nested= [KVM,AMD] Allow nested virtualization in KVM/SVM.
+ kvm.mmu_audit= [KVM] This is a R/W parameter which allows audit
+ KVM MMU at runtime.
Default is 0 (off)
+ kvm-amd.nested= [KVM,AMD] Allow nested virtualization in KVM/SVM.
+ Default is 1 (enabled)
+
kvm-amd.npt= [KVM,AMD] Disable nested paging (virtualized MMU)
for all guests.
Default is 1 (enabled) if in 64bit or 32bit-PAE mode
@@ -1537,12 +1541,15 @@ and is between 256 and 4096 characters. It is defined in the file
1 to enable accounting
Default value is 0.
- nfsaddrs= [NFS]
+ nfsaddrs= [NFS] Deprecated. Use ip= instead.
See Documentation/filesystems/nfs/nfsroot.txt.
nfsroot= [NFS] nfs root filesystem for disk-less boxes.
See Documentation/filesystems/nfs/nfsroot.txt.
+ nfsrootdebug [NFS] enable nfsroot debugging messages.
+ See Documentation/filesystems/nfs/nfsroot.txt.
+
nfs.callback_tcpport=
[NFS] set the TCP port on which the NFSv4 callback
channel should listen.
@@ -1698,6 +1705,8 @@ and is between 256 and 4096 characters. It is defined in the file
nojitter [IA64] Disables jitter checking for ITC timers.
+ no-kvmclock [X86,KVM] Disable paravirtualized KVM clock driver
+
nolapic [X86-32,APIC] Do not enable or use the local APIC.
nolapic_timer [X86-32,APIC] Do not use the local APIC timer.
@@ -1718,7 +1727,7 @@ and is between 256 and 4096 characters. It is defined in the file
norandmaps Don't use address space randomization. Equivalent to
echo 0 > /proc/sys/kernel/randomize_va_space
- noreplace-paravirt [X86-32,PV_OPS] Don't patch paravirt_ops
+ noreplace-paravirt [X86,IA-64,PV_OPS] Don't patch paravirt_ops
noreplace-smp [X86-32,SMP] Don't replace SMP instructions
with UP alternatives
@@ -2432,7 +2441,7 @@ and is between 256 and 4096 characters. It is defined in the file
topology informations if the hardware supports these.
The scheduler will make use of these informations and
e.g. base its process migration decisions on it.
- Default is off.
+ Default is on.
tp720= [HW,PS2]
diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt
index 5f5b64982b1a..b336266bea5e 100644
--- a/Documentation/kvm/api.txt
+++ b/Documentation/kvm/api.txt
@@ -320,13 +320,13 @@ struct kvm_translation {
4.15 KVM_INTERRUPT
Capability: basic
-Architectures: x86
+Architectures: x86, ppc
Type: vcpu ioctl
Parameters: struct kvm_interrupt (in)
Returns: 0 on success, -1 on error
Queues a hardware interrupt vector to be injected. This is only
-useful if in-kernel local APIC is not used.
+useful if in-kernel local APIC or equivalent is not used.
/* for KVM_INTERRUPT */
struct kvm_interrupt {
@@ -334,8 +334,37 @@ struct kvm_interrupt {
__u32 irq;
};
+X86:
+
Note 'irq' is an interrupt vector, not an interrupt pin or line.
+PPC:
+
+Queues an external interrupt to be injected. This ioctl is overleaded
+with 3 different irq values:
+
+a) KVM_INTERRUPT_SET
+
+ This injects an edge type external interrupt into the guest once it's ready
+ to receive interrupts. When injected, the interrupt is done.
+
+b) KVM_INTERRUPT_UNSET
+
+ This unsets any pending interrupt.
+
+ Only available with KVM_CAP_PPC_UNSET_IRQ.
+
+c) KVM_INTERRUPT_SET_LEVEL
+
+ This injects a level type external interrupt into the guest context. The
+ interrupt stays pending until a specific ioctl with KVM_INTERRUPT_UNSET
+ is triggered.
+
+ Only available with KVM_CAP_PPC_IRQ_LEVEL.
+
+Note that any value for 'irq' other than the ones stated above is invalid
+and incurs unexpected behavior.
+
4.16 KVM_DEBUG_GUEST
Capability: basic
@@ -1013,8 +1042,9 @@ number is just right, the 'nent' field is adjusted to the number of valid
entries in the 'entries' array, which is then filled.
The entries returned are the host cpuid as returned by the cpuid instruction,
-with unknown or unsupported features masked out. The fields in each entry
-are defined as follows:
+with unknown or unsupported features masked out. Some features (for example,
+x2apic), may not be present in the host cpu, but are exposed by kvm if it can
+emulate them efficiently. The fields in each entry are defined as follows:
function: the eax value used to obtain the entry
index: the ecx value used to obtain the entry (for entries that are
@@ -1032,6 +1062,29 @@ are defined as follows:
eax, ebx, ecx, edx: the values returned by the cpuid instruction for
this function/index combination
+4.46 KVM_PPC_GET_PVINFO
+
+Capability: KVM_CAP_PPC_GET_PVINFO
+Architectures: ppc
+Type: vm ioctl
+Parameters: struct kvm_ppc_pvinfo (out)
+Returns: 0 on success, !0 on error
+
+struct kvm_ppc_pvinfo {
+ __u32 flags;
+ __u32 hcall[4];
+ __u8 pad[108];
+};
+
+This ioctl fetches PV specific information that need to be passed to the guest
+using the device tree or other means from vm context.
+
+For now the only implemented piece of information distributed here is an array
+of 4 instructions that make up a hypercall.
+
+If any additional field gets added to this structure later on, a bit for that
+additional piece of information will be set in the flags bitmap.
+
5. The kvm_run structure
Application code obtains a pointer to the kvm_run structure by
diff --git a/Documentation/kvm/ppc-pv.txt b/Documentation/kvm/ppc-pv.txt
new file mode 100644
index 000000000000..a7f2244b3be9
--- /dev/null
+++ b/Documentation/kvm/ppc-pv.txt
@@ -0,0 +1,196 @@
+The PPC KVM paravirtual interface
+=================================
+
+The basic execution principle by which KVM on PowerPC works is to run all kernel
+space code in PR=1 which is user space. This way we trap all privileged
+instructions and can emulate them accordingly.
+
+Unfortunately that is also the downfall. There are quite some privileged
+instructions that needlessly return us to the hypervisor even though they
+could be handled differently.
+
+This is what the PPC PV interface helps with. It takes privileged instructions
+and transforms them into unprivileged ones with some help from the hypervisor.
+This cuts down virtualization costs by about 50% on some of my benchmarks.
+
+The code for that interface can be found in arch/powerpc/kernel/kvm*
+
+Querying for existence
+======================
+
+To find out if we're running on KVM or not, we leverage the device tree. When
+Linux is running on KVM, a node /hypervisor exists. That node contains a
+compatible property with the value "linux,kvm".
+
+Once you determined you're running under a PV capable KVM, you can now use
+hypercalls as described below.
+
+KVM hypercalls
+==============
+
+Inside the device tree's /hypervisor node there's a property called
+'hypercall-instructions'. This property contains at most 4 opcodes that make
+up the hypercall. To call a hypercall, just call these instructions.
+
+The parameters are as follows:
+
+ Register IN OUT
+
+ r0 - volatile
+ r3 1st parameter Return code
+ r4 2nd parameter 1st output value
+ r5 3rd parameter 2nd output value
+ r6 4th parameter 3rd output value
+ r7 5th parameter 4th output value
+ r8 6th parameter 5th output value
+ r9 7th parameter 6th output value
+ r10 8th parameter 7th output value
+ r11 hypercall number 8th output value
+ r12 - volatile
+
+Hypercall definitions are shared in generic code, so the same hypercall numbers
+apply for x86 and powerpc alike with the exception that each KVM hypercall
+also needs to be ORed with the KVM vendor code which is (42 << 16).
+
+Return codes can be as follows:
+
+ Code Meaning
+
+ 0 Success
+ 12 Hypercall not implemented
+ <0 Error
+
+The magic page
+==============
+
+To enable communication between the hypervisor and guest there is a new shared
+page that contains parts of supervisor visible register state. The guest can
+map this shared page using the KVM hypercall KVM_HC_PPC_MAP_MAGIC_PAGE.
+
+With this hypercall issued the guest always gets the magic page mapped at the
+desired location in effective and physical address space. For now, we always
+map the page to -4096. This way we can access it using absolute load and store
+functions. The following instruction reads the first field of the magic page:
+
+ ld rX, -4096(0)
+
+The interface is designed to be extensible should there be need later to add
+additional registers to the magic page. If you add fields to the magic page,
+also define a new hypercall feature to indicate that the host can give you more
+registers. Only if the host supports the additional features, make use of them.
+
+The magic page has the following layout as described in
+arch/powerpc/include/asm/kvm_para.h:
+
+struct kvm_vcpu_arch_shared {
+ __u64 scratch1;
+ __u64 scratch2;
+ __u64 scratch3;
+ __u64 critical; /* Guest may not get interrupts if == r1 */
+ __u64 sprg0;
+ __u64 sprg1;
+ __u64 sprg2;
+ __u64 sprg3;
+ __u64 srr0;
+ __u64 srr1;
+ __u64 dar;
+ __u64 msr;
+ __u32 dsisr;
+ __u32 int_pending; /* Tells the guest if we have an interrupt */
+};
+
+Additions to the page must only occur at the end. Struct fields are always 32
+or 64 bit aligned, depending on them being 32 or 64 bit wide respectively.
+
+Magic page features
+===================
+
+When mapping the magic page using the KVM hypercall KVM_HC_PPC_MAP_MAGIC_PAGE,
+a second return value is passed to the guest. This second return value contains
+a bitmap of available features inside the magic page.
+
+The following enhancements to the magic page are currently available:
+
+ KVM_MAGIC_FEAT_SR Maps SR registers r/w in the magic page
+
+For enhanced features in the magic page, please check for the existence of the
+feature before using them!
+
+MSR bits
+========
+
+The MSR contains bits that require hypervisor intervention and bits that do
+not require direct hypervisor intervention because they only get interpreted
+when entering the guest or don't have any impact on the hypervisor's behavior.
+
+The following bits are safe to be set inside the guest:
+
+ MSR_EE
+ MSR_RI
+ MSR_CR
+ MSR_ME
+
+If any other bit changes in the MSR, please still use mtmsr(d).
+
+Patched instructions
+====================
+
+The "ld" and "std" instructions are transormed to "lwz" and "stw" instructions
+respectively on 32 bit systems with an added offset of 4 to accomodate for big
+endianness.
+
+The following is a list of mapping the Linux kernel performs when running as
+guest. Implementing any of those mappings is optional, as the instruction traps
+also act on the shared page. So calling privileged instructions still works as
+before.
+
+From To
+==== ==
+
+mfmsr rX ld rX, magic_page->msr
+mfsprg rX, 0 ld rX, magic_page->sprg0
+mfsprg rX, 1 ld rX, magic_page->sprg1
+mfsprg rX, 2 ld rX, magic_page->sprg2
+mfsprg rX, 3 ld rX, magic_page->sprg3
+mfsrr0 rX ld rX, magic_page->srr0
+mfsrr1 rX ld rX, magic_page->srr1
+mfdar rX ld rX, magic_page->dar
+mfdsisr rX lwz rX, magic_page->dsisr
+
+mtmsr rX std rX, magic_page->msr
+mtsprg 0, rX std rX, magic_page->sprg0
+mtsprg 1, rX std rX, magic_page->sprg1
+mtsprg 2, rX std rX, magic_page->sprg2
+mtsprg 3, rX std rX, magic_page->sprg3
+mtsrr0 rX std rX, magic_page->srr0
+mtsrr1 rX std rX, magic_page->srr1
+mtdar rX std rX, magic_page->dar
+mtdsisr rX stw rX, magic_page->dsisr
+
+tlbsync nop
+
+mtmsrd rX, 0 b <special mtmsr section>
+mtmsr rX b <special mtmsr section>
+
+mtmsrd rX, 1 b <special mtmsrd section>
+
+[Book3S only]
+mtsrin rX, rY b <special mtsrin section>
+
+[BookE only]
+wrteei [0|1] b <special wrteei section>
+
+
+Some instructions require more logic to determine what's going on than a load
+or store instruction can deliver. To enable patching of those, we keep some
+RAM around where we can live translate instructions to. What happens is the
+following:
+
+ 1) copy emulation code to memory
+ 2) patch that code to fit the emulated instruction
+ 3) patch that code to return to the original pc + 4
+ 4) patch the original instruction to branch to the new code
+
+That way we can inject an arbitrary amount of code as replacement for a single
+instruction. This allows us to check for pending interrupts when setting EE=1
+for example.
diff --git a/Documentation/kvm/timekeeping.txt b/Documentation/kvm/timekeeping.txt
new file mode 100644
index 000000000000..0c5033a58c9e
--- /dev/null
+++ b/Documentation/kvm/timekeeping.txt
@@ -0,0 +1,612 @@
+
+ Timekeeping Virtualization for X86-Based Architectures
+
+ Zachary Amsden <zamsden@redhat.com>
+ Copyright (c) 2010, Red Hat. All rights reserved.
+
+1) Overview
+2) Timing Devices
+3) TSC Hardware
+4) Virtualization Problems
+
+=========================================================================
+
+1) Overview
+
+One of the most complicated parts of the X86 platform, and specifically,
+the virtualization of this platform is the plethora of timing devices available
+and the complexity of emulating those devices. In addition, virtualization of
+time introduces a new set of challenges because it introduces a multiplexed
+division of time beyond the control of the guest CPU.
+
+First, we will describe the various timekeeping hardware available, then
+present some of the problems which arise and solutions available, giving
+specific recommendations for certain classes of KVM guests.
+
+The purpose of this document is to collect data and information relevant to
+timekeeping which may be difficult to find elsewhere, specifically,
+information relevant to KVM and hardware-based virtualization.
+
+=========================================================================
+
+2) Timing Devices
+
+First we discuss the basic hardware devices available. TSC and the related
+KVM clock are special enough to warrant a full exposition and are described in
+the following section.
+
+2.1) i8254 - PIT
+
+One of the first timer devices available is the programmable interrupt timer,
+or PIT. The PIT has a fixed frequency 1.193182 MHz base clock and three
+channels which can be programmed to deliver periodic or one-shot interrupts.
+These three channels can be configured in different modes and have individual
+counters. Channel 1 and 2 were not available for general use in the original
+IBM PC, and historically were connected to control RAM refresh and the PC
+speaker. Now the PIT is typically integrated as part of an emulated chipset
+and a separate physical PIT is not used.
+
+The PIT uses I/O ports 0x40 - 0x43. Access to the 16-bit counters is done
+using single or multiple byte access to the I/O ports. There are 6 modes
+available, but not all modes are available to all timers, as only timer 2
+has a connected gate input, required for modes 1 and 5. The gate line is
+controlled by port 61h, bit 0, as illustrated in the following diagram.
+
+ -------------- ----------------
+| | | |
+| 1.1932 MHz |---------->| CLOCK OUT | ---------> IRQ 0
+| Clock | | | |
+ -------------- | +->| GATE TIMER 0 |
+ | ----------------
+ |
+ | ----------------
+ | | |
+ |------>| CLOCK OUT | ---------> 66.3 KHZ DRAM
+ | | | (aka /dev/null)
+ | +->| GATE TIMER 1 |
+ | ----------------
+ |
+ | ----------------
+ | | |
+ |------>| CLOCK OUT | ---------> Port 61h, bit 5
+ | | |
+Port 61h, bit 0 ---------->| GATE TIMER 2 | \_.---- ____
+ ---------------- _| )--|LPF|---Speaker
+ / *---- \___/
+Port 61h, bit 1 -----------------------------------/
+
+The timer modes are now described.
+
+Mode 0: Single Timeout. This is a one-shot software timeout that counts down
+ when the gate is high (always true for timers 0 and 1). When the count
+ reaches zero, the output goes high.
+
+Mode 1: Triggered One-shot. The output is intially set high. When the gate
+ line is set high, a countdown is initiated (which does not stop if the gate is
+ lowered), during which the output is set low. When the count reaches zero,
+ the output goes high.
+
+Mode 2: Rate Generator. The output is initially set high. When the countdown
+ reaches 1, the output goes low for one count and then returns high. The value
+ is reloaded and the countdown automatically resumes. If the gate line goes
+ low, the count is halted. If the output is low when the gate is lowered, the
+ output automatically goes high (this only affects timer 2).
+
+Mode 3: Square Wave. This generates a high / low square wave. The count
+ determines the length of the pulse, which alternates between high and low
+ when zero is reached. The count only proceeds when gate is high and is
+ automatically reloaded on reaching zero. The count is decremented twice at
+ each clock to generate a full high / low cycle at the full periodic rate.
+ If the count is even, the clock remains high for N/2 counts and low for N/2
+ counts; if the clock is odd, the clock is high for (N+1)/2 counts and low
+ for (N-1)/2 counts. Only even values are latched by the counter, so odd
+ values are not observed when reading. This is the intended mode for timer 2,
+ which generates sine-like tones by low-pass filtering the square wave output.
+
+Mode 4: Software Strobe. After programming this mode and loading the counter,
+ the output remains high until the counter reaches zero. Then the output
+ goes low for 1 clock cycle and returns high. The counter is not reloaded.
+ Counting only occurs when gate is high.
+
+Mode 5: Hardware Strobe. After programming and loading the counter, the
+ output remains high. When the gate is raised, a countdown is initiated
+ (which does not stop if the gate is lowered). When the counter reaches zero,
+ the output goes low for 1 clock cycle and then returns high. The counter is
+ not reloaded.
+
+In addition to normal binary counting, the PIT supports BCD counting. The
+command port, 0x43 is used to set the counter and mode for each of the three
+timers.
+
+PIT commands, issued to port 0x43, using the following bit encoding:
+
+Bit 7-4: Command (See table below)
+Bit 3-1: Mode (000 = Mode 0, 101 = Mode 5, 11X = undefined)
+Bit 0 : Binary (0) / BCD (1)
+
+Command table:
+
+0000 - Latch Timer 0 count for port 0x40
+ sample and hold the count to be read in port 0x40;
+ additional commands ignored until counter is read;
+ mode bits ignored.
+
+0001 - Set Timer 0 LSB mode for port 0x40
+ set timer to read LSB only and force MSB to zero;
+ mode bits set timer mode
+
+0010 - Set Timer 0 MSB mode for port 0x40
+ set timer to read MSB only and force LSB to zero;
+ mode bits set timer mode
+
+0011 - Set Timer 0 16-bit mode for port 0x40
+ set timer to read / write LSB first, then MSB;
+ mode bits set timer mode
+
+0100 - Latch Timer 1 count for port 0x41 - as described above
+0101 - Set Timer 1 LSB mode for port 0x41 - as described above
+0110 - Set Timer 1 MSB mode for port 0x41 - as described above
+0111 - Set Timer 1 16-bit mode for port 0x41 - as described above
+
+1000 - Latch Timer 2 count for port 0x42 - as described above
+1001 - Set Timer 2 LSB mode for port 0x42 - as described above
+1010 - Set Timer 2 MSB mode for port 0x42 - as described above
+1011 - Set Timer 2 16-bit mode for port 0x42 as described above
+
+1101 - General counter latch
+ Latch combination of counters into corresponding ports
+ Bit 3 = Counter 2
+ Bit 2 = Counter 1
+ Bit 1 = Counter 0
+ Bit 0 = Unused
+
+1110 - Latch timer status
+ Latch combination of counter mode into corresponding ports
+ Bit 3 = Counter 2
+ Bit 2 = Counter 1
+ Bit 1 = Counter 0
+
+ The output of ports 0x40-0x42 following this command will be:
+
+ Bit 7 = Output pin
+ Bit 6 = Count loaded (0 if timer has expired)
+ Bit 5-4 = Read / Write mode
+ 01 = MSB only
+ 10 = LSB only
+ 11 = LSB / MSB (16-bit)
+ Bit 3-1 = Mode
+ Bit 0 = Binary (0) / BCD mode (1)
+
+2.2) RTC
+
+The second device which was available in the original PC was the MC146818 real
+time clock. The original device is now obsolete, and usually emulated by the
+system chipset, sometimes by an HPET and some frankenstein IRQ routing.
+
+The RTC is accessed through CMOS variables, which uses an index register to
+control which bytes are read. Since there is only one index register, read
+of the CMOS and read of the RTC require lock protection (in addition, it is
+dangerous to allow userspace utilities such as hwclock to have direct RTC
+access, as they could corrupt kernel reads and writes of CMOS memory).
+
+The RTC generates an interrupt which is usually routed to IRQ 8. The interrupt
+can function as a periodic timer, an additional once a day alarm, and can issue
+interrupts after an update of the CMOS registers by the MC146818 is complete.
+The type of interrupt is signalled in the RTC status registers.
+
+The RTC will update the current time fields by battery power even while the
+system is off. The current time fields should not be read while an update is
+in progress, as indicated in the status register.
+
+The clock uses a 32.768kHz crystal, so bits 6-4 of register A should be
+programmed to a 32kHz divider if the RTC is to count seconds.
+
+This is the RAM map originally used for the RTC/CMOS:
+
+Location Size Description
+------------------------------------------
+00h byte Current second (BCD)
+01h byte Seconds alarm (BCD)
+02h byte Current minute (BCD)
+03h byte Minutes alarm (BCD)
+04h byte Current hour (BCD)
+05h byte Hours alarm (BCD)
+06h byte Current day of week (BCD)
+07h byte Current day of month (BCD)
+08h byte Current month (BCD)
+09h byte Current year (BCD)
+0Ah byte Register A
+ bit 7 = Update in progress
+ bit 6-4 = Divider for clock
+ 000 = 4.194 MHz
+ 001 = 1.049 MHz
+ 010 = 32 kHz
+ 10X = test modes
+ 110 = reset / disable
+ 111 = reset / disable
+ bit 3-0 = Rate selection for periodic interrupt
+ 000 = periodic timer disabled
+ 001 = 3.90625 uS
+ 010 = 7.8125 uS
+ 011 = .122070 mS
+ 100 = .244141 mS
+ ...
+ 1101 = 125 mS
+ 1110 = 250 mS
+ 1111 = 500 mS
+0Bh byte Register B
+ bit 7 = Run (0) / Halt (1)
+ bit 6 = Periodic interrupt enable
+ bit 5 = Alarm interrupt enable
+ bit 4 = Update-ended interrupt enable
+ bit 3 = Square wave interrupt enable
+ bit 2 = BCD calendar (0) / Binary (1)
+ bit 1 = 12-hour mode (0) / 24-hour mode (1)
+ bit 0 = 0 (DST off) / 1 (DST enabled)
+OCh byte Register C (read only)
+ bit 7 = interrupt request flag (IRQF)
+ bit 6 = periodic interrupt flag (PF)
+ bit 5 = alarm interrupt flag (AF)
+ bit 4 = update interrupt flag (UF)
+ bit 3-0 = reserved
+ODh byte Register D (read only)
+ bit 7 = RTC has power
+ bit 6-0 = reserved
+32h byte Current century BCD (*)
+ (*) location vendor specific and now determined from ACPI global tables
+
+2.3) APIC
+
+On Pentium and later processors, an on-board timer is available to each CPU
+as part of the Advanced Programmable Interrupt Controller. The APIC is
+accessed through memory-mapped registers and provides interrupt service to each
+CPU, used for IPIs and local timer interrupts.
+
+Although in theory the APIC is a safe and stable source for local interrupts,
+in practice, many bugs and glitches have occurred due to the special nature of
+the APIC CPU-local memory-mapped hardware. Beware that CPU errata may affect
+the use of the APIC and that workarounds may be required. In addition, some of
+these workarounds pose unique constraints for virtualization - requiring either
+extra overhead incurred from extra reads of memory-mapped I/O or additional
+functionality that may be more computationally expensive to implement.
+
+Since the APIC is documented quite well in the Intel and AMD manuals, we will
+avoid repetition of the detail here. It should be pointed out that the APIC
+timer is programmed through the LVT (local vector timer) register, is capable
+of one-shot or periodic operation, and is based on the bus clock divided down
+by the programmable divider register.
+
+2.4) HPET
+
+HPET is quite complex, and was originally intended to replace the PIT / RTC
+support of the X86 PC. It remains to be seen whether that will be the case, as
+the de facto standard of PC hardware is to emulate these older devices. Some
+systems designated as legacy free may support only the HPET as a hardware timer
+device.
+
+The HPET spec is rather loose and vague, requiring at least 3 hardware timers,
+but allowing implementation freedom to support many more. It also imposes no
+fixed rate on the timer frequency, but does impose some extremal values on
+frequency, error and slew.
+
+In general, the HPET is recommended as a high precision (compared to PIT /RTC)
+time source which is independent of local variation (as there is only one HPET
+in any given system). The HPET is also memory-mapped, and its presence is
+indicated through ACPI tables by the BIOS.
+
+Detailed specification of the HPET is beyond the current scope of this
+document, as it is also very well documented elsewhere.
+
+2.5) Offboard Timers
+
+Several cards, both proprietary (watchdog boards) and commonplace (e1000) have
+timing chips built into the cards which may have registers which are accessible
+to kernel or user drivers. To the author's knowledge, using these to generate
+a clocksource for a Linux or other kernel has not yet been attempted and is in
+general frowned upon as not playing by the agreed rules of the game. Such a
+timer device would require additional support to be virtualized properly and is
+not considered important at this time as no known operating system does this.
+
+=========================================================================
+
+3) TSC Hardware
+
+The TSC or time stamp counter is relatively simple in theory; it counts
+instruction cycles issued by the processor, which can be used as a measure of
+time. In practice, due to a number of problems, it is the most complicated
+timekeeping device to use.
+
+The TSC is represented internally as a 64-bit MSR which can be read with the
+RDMSR, RDTSC, or RDTSCP (when available) instructions. In the past, hardware
+limitations made it possible to write the TSC, but generally on old hardware it
+was only possible to write the low 32-bits of the 64-bit counter, and the upper
+32-bits of the counter were cleared. Now, however, on Intel processors family
+0Fh, for models 3, 4 and 6, and family 06h, models e and f, this restriction
+has been lifted and all 64-bits are writable. On AMD systems, the ability to
+write the TSC MSR is not an architectural guarantee.
+
+The TSC is accessible from CPL-0 and conditionally, for CPL > 0 software by
+means of the CR4.TSD bit, which when enabled, disables CPL > 0 TSC access.
+
+Some vendors have implemented an additional instruction, RDTSCP, which returns
+atomically not just the TSC, but an indicator which corresponds to the
+processor number. This can be used to index into an array of TSC variables to
+determine offset information in SMP systems where TSCs are not synchronized.
+The presence of this instruction must be determined by consulting CPUID feature
+bits.
+
+Both VMX and SVM provide extension fields in the virtualization hardware which
+allows the guest visible TSC to be offset by a constant. Newer implementations
+promise to allow the TSC to additionally be scaled, but this hardware is not
+yet widely available.
+
+3.1) TSC synchronization
+
+The TSC is a CPU-local clock in most implementations. This means, on SMP
+platforms, the TSCs of different CPUs may start at different times depending
+on when the CPUs are powered on. Generally, CPUs on the same die will share
+the same clock, however, this is not always the case.
+
+The BIOS may attempt to resynchronize the TSCs during the poweron process and
+the operating system or other system software may attempt to do this as well.
+Several hardware limitations make the problem worse - if it is not possible to
+write the full 64-bits of the TSC, it may be impossible to match the TSC in
+newly arriving CPUs to that of the rest of the system, resulting in
+unsynchronized TSCs. This may be done by BIOS or system software, but in
+practice, getting a perfectly synchronized TSC will not be possible unless all
+values are read from the same clock, which generally only is possible on single
+socket systems or those with special hardware support.
+
+3.2) TSC and CPU hotplug
+
+As touched on already, CPUs which arrive later than the boot time of the system
+may not have a TSC value that is synchronized with the rest of the system.
+Either system software, BIOS, or SMM code may actually try to establish the TSC
+to a value matching the rest of the system, but a perfect match is usually not
+a guarantee. This can have the effect of bringing a system from a state where
+TSC is synchronized back to a state where TSC synchronization flaws, however
+small, may be exposed to the OS and any virtualization environment.
+
+3.3) TSC and multi-socket / NUMA
+
+Multi-socket systems, especially large multi-socket systems are likely to have
+individual clocksources rather than a single, universally distributed clock.
+Since these clocks are driven by different crystals, they will not have
+perfectly matched frequency, and temperature and electrical variations will
+cause the CPU clocks, and thus the TSCs to drift over time. Depending on the
+exact clock and bus design, the drift may or may not be fixed in absolute
+error, and may accumulate over time.
+
+In addition, very large systems may deliberately slew the clocks of individual
+cores. This technique, known as spread-spectrum clocking, reduces EMI at the
+clock frequency and harmonics of it, which may be required to pass FCC
+standards for telecommunications and computer equipment.
+
+It is recommended not to trust the TSCs to remain synchronized on NUMA or
+multiple socket systems for these reasons.
+
+3.4) TSC and C-states
+
+C-states, or idling states of the processor, especially C1E and deeper sleep
+states may be problematic for TSC as well. The TSC may stop advancing in such
+a state, resulting in a TSC which is behind that of other CPUs when execution
+is resumed. Such CPUs must be detected and flagged by the operating system
+based on CPU and chipset identifications.
+
+The TSC in such a case may be corrected by catching it up to a known external
+clocksource.
+
+3.5) TSC frequency change / P-states
+
+To make things slightly more interesting, some CPUs may change frequency. They
+may or may not run the TSC at the same rate, and because the frequency change
+may be staggered or slewed, at some points in time, the TSC rate may not be
+known other than falling within a range of values. In this case, the TSC will
+not be a stable time source, and must be calibrated against a known, stable,
+external clock to be a usable source of time.
+
+Whether the TSC runs at a constant rate or scales with the P-state is model
+dependent and must be determined by inspecting CPUID, chipset or vendor
+specific MSR fields.
+
+In addition, some vendors have known bugs where the P-state is actually
+compensated for properly during normal operation, but when the processor is
+inactive, the P-state may be raised temporarily to service cache misses from
+other processors. In such cases, the TSC on halted CPUs could advance faster
+than that of non-halted processors. AMD Turion processors are known to have
+this problem.
+
+3.6) TSC and STPCLK / T-states
+
+External signals given to the processor may also have the effect of stopping
+the TSC. This is typically done for thermal emergency power control to prevent
+an overheating condition, and typically, there is no way to detect that this
+condition has happened.
+
+3.7) TSC virtualization - VMX
+
+VMX provides conditional trapping of RDTSC, RDMSR, WRMSR and RDTSCP
+instructions, which is enough for full virtualization of TSC in any manner. In
+addition, VMX allows passing through the host TSC plus an additional TSC_OFFSET
+field specified in the VMCS. Special instructions must be used to read and
+write the VMCS field.
+
+3.8) TSC virtualization - SVM
+
+SVM provides conditional trapping of RDTSC, RDMSR, WRMSR and RDTSCP
+instructions, which is enough for full virtualization of TSC in any manner. In
+addition, SVM allows passing through the host TSC plus an additional offset
+field specified in the SVM control block.
+
+3.9) TSC feature bits in Linux
+
+In summary, there is no way to guarantee the TSC remains in perfect
+synchronization unless it is explicitly guaranteed by the architecture. Even
+if so, the TSCs in multi-sockets or NUMA systems may still run independently
+despite being locally consistent.
+
+The following feature bits are used by Linux to signal various TSC attributes,
+but they can only be taken to be meaningful for UP or single node systems.
+
+X86_FEATURE_TSC : The TSC is available in hardware
+X86_FEATURE_RDTSCP : The RDTSCP instruction is available
+X86_FEATURE_CONSTANT_TSC : The TSC rate is unchanged with P-states
+X86_FEATURE_NONSTOP_TSC : The TSC does not stop in C-states
+X86_FEATURE_TSC_RELIABLE : TSC sync checks are skipped (VMware)
+
+4) Virtualization Problems
+
+Timekeeping is especially problematic for virtualization because a number of
+challenges arise. The most obvious problem is that time is now shared between
+the host and, potentially, a number of virtual machines. Thus the virtual
+operating system does not run with 100% usage of the CPU, despite the fact that
+it may very well make that assumption. It may expect it to remain true to very
+exacting bounds when interrupt sources are disabled, but in reality only its
+virtual interrupt sources are disabled, and the machine may still be preempted
+at any time. This causes problems as the passage of real time, the injection
+of machine interrupts and the associated clock sources are no longer completely
+synchronized with real time.
+
+This same problem can occur on native harware to a degree, as SMM mode may
+steal cycles from the naturally on X86 systems when SMM mode is used by the
+BIOS, but not in such an extreme fashion. However, the fact that SMM mode may
+cause similar problems to virtualization makes it a good justification for
+solving many of these problems on bare metal.
+
+4.1) Interrupt clocking
+
+One of the most immediate problems that occurs with legacy operating systems
+is that the system timekeeping routines are often designed to keep track of
+time by counting periodic interrupts. These interrupts may come from the PIT
+or the RTC, but the problem is the same: the host virtualization engine may not
+be able to deliver the proper number of interrupts per second, and so guest
+time may fall behind. This is especially problematic if a high interrupt rate
+is selected, such as 1000 HZ, which is unfortunately the default for many Linux
+guests.
+
+There are three approaches to solving this problem; first, it may be possible
+to simply ignore it. Guests which have a separate time source for tracking
+'wall clock' or 'real time' may not need any adjustment of their interrupts to
+maintain proper time. If this is not sufficient, it may be necessary to inject
+additional interrupts into the guest in order to increase the effective
+interrupt rate. This approach leads to complications in extreme conditions,
+where host load or guest lag is too much to compensate for, and thus another
+solution to the problem has risen: the guest may need to become aware of lost
+ticks and compensate for them internally. Although promising in theory, the
+implementation of this policy in Linux has been extremely error prone, and a
+number of buggy variants of lost tick compensation are distributed across
+commonly used Linux systems.
+
+Windows uses periodic RTC clocking as a means of keeping time internally, and
+thus requires interrupt slewing to keep proper time. It does use a low enough
+rate (ed: is it 18.2 Hz?) however that it has not yet been a problem in
+practice.
+
+4.2) TSC sampling and serialization
+
+As the highest precision time source available, the cycle counter of the CPU
+has aroused much interest from developers. As explained above, this timer has
+many problems unique to its nature as a local, potentially unstable and
+potentially unsynchronized source. One issue which is not unique to the TSC,
+but is highlighted because of its very precise nature is sampling delay. By
+definition, the counter, once read is already old. However, it is also
+possible for the counter to be read ahead of the actual use of the result.
+This is a consequence of the superscalar execution of the instruction stream,
+which may execute instructions out of order. Such execution is called
+non-serialized. Forcing serialized execution is necessary for precise
+measurement with the TSC, and requires a serializing instruction, such as CPUID
+or an MSR read.
+
+Since CPUID may actually be virtualized by a trap and emulate mechanism, this
+serialization can pose a performance issue for hardware virtualization. An
+accurate time stamp counter reading may therefore not always be available, and
+it may be necessary for an implementation to guard against "backwards" reads of
+the TSC as seen from other CPUs, even in an otherwise perfectly synchronized
+system.
+
+4.3) Timespec aliasing
+
+Additionally, this lack of serialization from the TSC poses another challenge
+when using results of the TSC when measured against another time source. As
+the TSC is much higher precision, many possible values of the TSC may be read
+while another clock is still expressing the same value.
+
+That is, you may read (T,T+10) while external clock C maintains the same value.
+Due to non-serialized reads, you may actually end up with a range which
+fluctuates - from (T-1.. T+10). Thus, any time calculated from a TSC, but
+calibrated against an external value may have a range of valid values.
+Re-calibrating this computation may actually cause time, as computed after the
+calibration, to go backwards, compared with time computed before the
+calibration.
+
+This problem is particularly pronounced with an internal time source in Linux,
+the kernel time, which is expressed in the theoretically high resolution
+timespec - but which advances in much larger granularity intervals, sometimes
+at the rate of jiffies, and possibly in catchup modes, at a much larger step.
+
+This aliasing requires care in the computation and recalibration of kvmclock
+and any other values derived from TSC computation (such as TSC virtualization
+itself).
+
+4.4) Migration
+
+Migration of a virtual machine raises problems for timekeeping in two ways.
+First, the migration itself may take time, during which interrupts cannot be
+delivered, and after which, the guest time may need to be caught up. NTP may
+be able to help to some degree here, as the clock correction required is
+typically small enough to fall in the NTP-correctable window.
+
+An additional concern is that timers based off the TSC (or HPET, if the raw bus
+clock is exposed) may now be running at different rates, requiring compensation
+in some way in the hypervisor by virtualizing these timers. In addition,
+migrating to a faster machine may preclude the use of a passthrough TSC, as a
+faster clock cannot be made visible to a guest without the potential of time
+advancing faster than usual. A slower clock is less of a problem, as it can
+always be caught up to the original rate. KVM clock avoids these problems by
+simply storing multipliers and offsets against the TSC for the guest to convert
+back into nanosecond resolution values.
+
+4.5) Scheduling
+
+Since scheduling may be based on precise timing and firing of interrupts, the
+scheduling algorithms of an operating system may be adversely affected by
+virtualization. In theory, the effect is random and should be universally
+distributed, but in contrived as well as real scenarios (guest device access,
+causes of virtualization exits, possible context switch), this may not always
+be the case. The effect of this has not been well studied.
+
+In an attempt to work around this, several implementations have provided a
+paravirtualized scheduler clock, which reveals the true amount of CPU time for
+which a virtual machine has been running.
+
+4.6) Watchdogs
+
+Watchdog timers, such as the lock detector in Linux may fire accidentally when
+running under hardware virtualization due to timer interrupts being delayed or
+misinterpretation of the passage of real time. Usually, these warnings are
+spurious and can be ignored, but in some circumstances it may be necessary to
+disable such detection.
+
+4.7) Delays and precision timing
+
+Precise timing and delays may not be possible in a virtualized system. This
+can happen if the system is controlling physical hardware, or issues delays to
+compensate for slower I/O to and from devices. The first issue is not solvable
+in general for a virtualized system; hardware control software can't be
+adequately virtualized without a full real-time operating system, which would
+require an RT aware virtualization platform.
+
+The second issue may cause performance problems, but this is unlikely to be a
+significant issue. In many cases these delays may be eliminated through
+configuration or paravirtualization.
+
+4.8) Covert channels and leaks
+
+In addition to the above problems, time information will inevitably leak to the
+guest about the host in anything but a perfect implementation of virtualized
+time. This may allow the guest to infer the presence of a hypervisor (as in a
+red-pill type detection), and it may allow information to leak between guests
+by using CPU utilization itself as a signalling channel. Preventing such
+problems would require completely isolated virtual time which may not track
+real time any longer. This may be useful in certain security or QA contexts,
+but in general isn't recommended for real-world deployment scenarios.
diff --git a/Documentation/misc-devices/apds990x.txt b/Documentation/misc-devices/apds990x.txt
new file mode 100644
index 000000000000..d5408cade32f
--- /dev/null
+++ b/Documentation/misc-devices/apds990x.txt
@@ -0,0 +1,111 @@
+Kernel driver apds990x
+======================
+
+Supported chips:
+Avago APDS990X
+
+Data sheet:
+Not freely available
+
+Author:
+Samu Onkalo <samu.p.onkalo@nokia.com>
+
+Description
+-----------
+
+APDS990x is a combined ambient light and proximity sensor. ALS and proximity
+functionality are highly connected. ALS measurement path must be running
+while the proximity functionality is enabled.
+
+ALS produces raw measurement values for two channels: Clear channel
+(infrared + visible light) and IR only. However, threshold comparisons happen
+using clear channel only. Lux value and the threshold level on the HW
+might vary quite much depending the spectrum of the light source.
+
+Driver makes necessary conversions to both directions so that user handles
+only lux values. Lux value is calculated using information from the both
+channels. HW threshold level is calculated from the given lux value to match
+with current type of the lightning. Sometimes inaccuracy of the estimations
+lead to false interrupt, but that doesn't harm.
+
+ALS contains 4 different gain steps. Driver automatically
+selects suitable gain step. After each measurement, reliability of the results
+is estimated and new measurement is trigged if necessary.
+
+Platform data can provide tuned values to the conversion formulas if
+values are known. Otherwise plain sensor default values are used.
+
+Proximity side is little bit simpler. There is no need for complex conversions.
+It produces directly usable values.
+
+Driver controls chip operational state using pm_runtime framework.
+Voltage regulators are controlled based on chip operational state.
+
+SYSFS
+-----
+
+
+chip_id
+ RO - shows detected chip type and version
+
+power_state
+ RW - enable / disable chip. Uses counting logic
+ 1 enables the chip
+ 0 disables the chip
+lux0_input
+ RO - measured lux value
+ sysfs_notify called when threshold interrupt occurs
+
+lux0_sensor_range
+ RO - lux0_input max value. Actually never reaches since sensor tends
+ to saturate much before that. Real max value varies depending
+ on the light spectrum etc.
+
+lux0_rate
+ RW - measurement rate in Hz
+
+lux0_rate_avail
+ RO - supported measurement rates
+
+lux0_calibscale
+ RW - calibration value. Set to neutral value by default.
+ Output results are multiplied with calibscale / calibscale_default
+ value.
+
+lux0_calibscale_default
+ RO - neutral calibration value
+
+lux0_thresh_above_value
+ RW - HI level threshold value. All results above the value
+ trigs an interrupt. 65535 (i.e. sensor_range) disables the above
+ interrupt.
+
+lux0_thresh_below_value
+ RW - LO level threshold value. All results below the value
+ trigs an interrupt. 0 disables the below interrupt.
+
+prox0_raw
+ RO - measured proximity value
+ sysfs_notify called when threshold interrupt occurs
+
+prox0_sensor_range
+ RO - prox0_raw max value (1023)
+
+prox0_raw_en
+ RW - enable / disable proximity - uses counting logic
+ 1 enables the proximity
+ 0 disables the proximity
+
+prox0_reporting_mode
+ RW - trigger / periodic. In "trigger" mode the driver tells two possible
+ values: 0 or prox0_sensor_range value. 0 means no proximity,
+ 1023 means proximity. This causes minimal number of interrupts.
+ In "periodic" mode the driver reports all values above
+ prox0_thresh_above. This causes more interrupts, but it can give
+ _rough_ estimate about the distance.
+
+prox0_reporting_mode_avail
+ RO - accepted values to prox0_reporting_mode (trigger, periodic)
+
+prox0_thresh_above_value
+ RW - threshold level which trigs proximity events.
diff --git a/Documentation/misc-devices/bh1770glc.txt b/Documentation/misc-devices/bh1770glc.txt
new file mode 100644
index 000000000000..7d64c014dc70
--- /dev/null
+++ b/Documentation/misc-devices/bh1770glc.txt
@@ -0,0 +1,116 @@
+Kernel driver bh1770glc
+=======================
+
+Supported chips:
+ROHM BH1770GLC
+OSRAM SFH7770
+
+Data sheet:
+Not freely available
+
+Author:
+Samu Onkalo <samu.p.onkalo@nokia.com>
+
+Description
+-----------
+BH1770GLC and SFH7770 are combined ambient light and proximity sensors.
+ALS and proximity parts operates on their own, but they shares common I2C
+interface and interrupt logic. In principle they can run on their own,
+but ALS side results are used to estimate reliability of the proximity sensor.
+
+ALS produces 16 bit lux values. The chip contains interrupt logic to produce
+low and high threshold interrupts.
+
+Proximity part contains IR-led driver up to 3 IR leds. The chip measures
+amount of reflected IR light and produces proximity result. Resolution is
+8 bit. Driver supports only one channel. Driver uses ALS results to estimate
+reliability of the proximity results. Thus ALS is always running while
+proximity detection is needed.
+
+Driver uses threshold interrupts to avoid need for polling the values.
+Proximity low interrupt doesn't exists in the chip. This is simulated
+by using a delayed work. As long as there is proximity threshold above
+interrupts the delayed work is pushed forward. So, when proximity level goes
+below the threshold value, there is no interrupt and the delayed work will
+finally run. This is handled as no proximity indication.
+
+Chip state is controlled via runtime pm framework when enabled in config.
+
+Calibscale factor is used to hide differences between the chips. By default
+value set to neutral state meaning factor of 1.00. To get proper values,
+calibrated source of light is needed as a reference. Calibscale factor is set
+so that measurement produces about the expected lux value.
+
+SYSFS
+-----
+
+chip_id
+ RO - shows detected chip type and version
+
+power_state
+ RW - enable / disable chip. Uses counting logic
+ 1 enables the chip
+ 0 disables the chip
+
+lux0_input
+ RO - measured lux value
+ sysfs_notify called when threshold interrupt occurs
+
+lux0_sensor_range
+ RO - lux0_input max value
+
+lux0_rate
+ RW - measurement rate in Hz
+
+lux0_rate_avail
+ RO - supported measurement rates
+
+lux0_thresh_above_value
+ RW - HI level threshold value. All results above the value
+ trigs an interrupt. 65535 (i.e. sensor_range) disables the above
+ interrupt.
+
+lux0_thresh_below_value
+ RW - LO level threshold value. All results below the value
+ trigs an interrupt. 0 disables the below interrupt.
+
+lux0_calibscale
+ RW - calibration value. Set to neutral value by default.
+ Output results are multiplied with calibscale / calibscale_default
+ value.
+
+lux0_calibscale_default
+ RO - neutral calibration value
+
+prox0_raw
+ RO - measured proximity value
+ sysfs_notify called when threshold interrupt occurs
+
+prox0_sensor_range
+ RO - prox0_raw max value
+
+prox0_raw_en
+ RW - enable / disable proximity - uses counting logic
+ 1 enables the proximity
+ 0 disables the proximity
+
+prox0_thresh_above_count
+ RW - number of proximity interrupts needed before triggering the event
+
+prox0_rate_above
+ RW - Measurement rate (in Hz) when the level is above threshold
+ i.e. when proximity on has been reported.
+
+prox0_rate_below
+ RW - Measurement rate (in Hz) when the level is below threshold
+ i.e. when proximity off has been reported.
+
+prox0_rate_avail
+ RO - Supported proximity measurement rates in Hz
+
+prox0_thresh_above0_value
+ RW - threshold level which trigs proximity events.
+ Filtered by persistence filter (prox0_thresh_above_count)
+
+prox0_thresh_above1_value
+ RW - threshold level which trigs event immediately
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index d2b62b71b617..5dc638791d97 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -765,6 +765,14 @@ xmit_hash_policy
does not exist, and the layer2 policy is the only policy. The
layer2+3 value was added for bonding version 3.2.2.
+resend_igmp
+
+ Specifies the number of IGMP membership reports to be issued after
+ a failover event. One membership report is issued immediately after
+ the failover, subsequent packets are sent in each 200ms interval.
+
+ The valid range is 0 - 255; the default value is 1. This option
+ was added for bonding version 3.7.0.
3. Configuring Bonding Devices
==============================
diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt
index cd79735013f9..5b04b67ddca2 100644
--- a/Documentation/networking/can.txt
+++ b/Documentation/networking/can.txt
@@ -22,6 +22,7 @@ This file contains
4.1.2 RAW socket option CAN_RAW_ERR_FILTER
4.1.3 RAW socket option CAN_RAW_LOOPBACK
4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS
+ 4.1.5 RAW socket returned message flags
4.2 Broadcast Manager protocol sockets (SOCK_DGRAM)
4.3 connected transport protocols (SOCK_SEQPACKET)
4.4 unconnected transport protocols (SOCK_DGRAM)
@@ -471,6 +472,17 @@ solution for a couple of reasons:
setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
&recv_own_msgs, sizeof(recv_own_msgs));
+ 4.1.5 RAW socket returned message flags
+
+ When using recvmsg() call, the msg->msg_flags may contain following flags:
+
+ MSG_DONTROUTE: set when the received frame was created on the local host.
+
+ MSG_CONFIRM: set when the frame was sent via the socket it is received on.
+ This flag can be interpreted as a 'transmission confirmation' when the
+ CAN driver supports the echo of frames on driver level, see 3.2 and 6.2.
+ In order to receive such messages, CAN_RAW_RECV_OWN_MSGS must be set.
+
4.2 Broadcast Manager protocol sockets (SOCK_DGRAM)
4.3 connected transport protocols (SOCK_SEQPACKET)
4.4 unconnected transport protocols (SOCK_DGRAM)
diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt
index a62fdf7a6bff..271d524a4c8d 100644
--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -1,18 +1,20 @@
DCCP protocol
-============
+=============
Contents
========
-
- Introduction
- Missing features
- Socket options
+- Sysctl variables
+- IOCTLs
+- Other tunables
- Notes
+
Introduction
============
-
Datagram Congestion Control Protocol (DCCP) is an unreliable, connection
oriented protocol designed to solve issues present in UDP and TCP, particularly
for real-time and multimedia (streaming) traffic.
@@ -29,9 +31,9 @@ It has a base protocol and pluggable congestion control IDs (CCIDs).
DCCP is a Proposed Standard (RFC 2026), and the homepage for DCCP as a protocol
is at http://www.ietf.org/html.charters/dccp-charter.html
+
Missing features
================
-
The Linux DCCP implementation does not currently support all the features that are
specified in RFCs 4340...42.
@@ -45,7 +47,6 @@ http://linux-net.osdl.org/index.php/DCCP_Testing#Experimental_DCCP_source_tree
Socket options
==============
-
DCCP_SOCKOPT_SERVICE sets the service. The specification mandates use of
service codes (RFC 4340, sec. 8.1.2); if this socket option is not set,
the socket will fall back to 0 (which means that no meaningful service code
@@ -112,6 +113,7 @@ DCCP_SOCKOPT_CCID_TX_INFO
On unidirectional connections it is useful to close the unused half-connection
via shutdown (SHUT_WR or SHUT_RD): this will reduce per-packet processing costs.
+
Sysctl variables
================
Several DCCP default parameters can be managed by the following sysctls
@@ -155,15 +157,30 @@ sync_ratelimit = 125 ms
sequence-invalid packets on the same socket (RFC 4340, 7.5.4). The unit
of this parameter is milliseconds; a value of 0 disables rate-limiting.
+
IOCTLS
======
FIONREAD
Works as in udp(7): returns in the `int' argument pointer the size of
the next pending datagram in bytes, or 0 when no datagram is pending.
+
+Other tunables
+==============
+Per-route rto_min support
+ CCID-2 supports the RTAX_RTO_MIN per-route setting for the minimum value
+ of the RTO timer. This setting can be modified via the 'rto_min' option
+ of iproute2; for example:
+ > ip route change 10.0.0.0/24 rto_min 250j dev wlan0
+ > ip route add 10.0.0.254/32 rto_min 800j dev wlan0
+ > ip route show dev wlan0
+ CCID-3 also supports the rto_min setting: it is used to define the lower
+ bound for the expiry of the nofeedback timer. This can be useful on LANs
+ with very low RTTs (e.g., loopback, Gbit ethernet).
+
+
Notes
=====
-
DCCP does not travel through NAT successfully at present on many boxes. This is
because the checksum covers the pseudo-header as per TCP and UDP. Linux NAT
support for DCCP has been added.
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index f350c69b2bb4..c7165f4cb792 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1014,6 +1014,12 @@ conf/interface/*:
accept_ra - BOOLEAN
Accept Router Advertisements; autoconfigure using them.
+ Possible values are:
+ 0 Do not accept Router Advertisements.
+ 1 Accept Router Advertisements if forwarding is disabled.
+ 2 Overrule forwarding behaviour. Accept Router Advertisements
+ even if forwarding is enabled.
+
Functional default: enabled if local forwarding is disabled.
disabled if local forwarding is enabled.
@@ -1075,7 +1081,12 @@ forwarding - BOOLEAN
Note: It is recommended to have the same setting on all
interfaces; mixed router/host scenarios are rather uncommon.
- FALSE:
+ Possible values are:
+ 0 Forwarding disabled
+ 1 Forwarding enabled
+ 2 Forwarding enabled (Hybrid Mode)
+
+ FALSE (0):
By default, Host behaviour is assumed. This means:
@@ -1085,18 +1096,24 @@ forwarding - BOOLEAN
Advertisements (and do autoconfiguration).
4. If accept_redirects is TRUE (default), accept Redirects.
- TRUE:
+ TRUE (1):
If local forwarding is enabled, Router behaviour is assumed.
This means exactly the reverse from the above:
1. IsRouter flag is set in Neighbour Advertisements.
2. Router Solicitations are not sent.
- 3. Router Advertisements are ignored.
+ 3. Router Advertisements are ignored unless accept_ra is 2.
4. Redirects are ignored.
- Default: FALSE if global forwarding is disabled (default),
- otherwise TRUE.
+ 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).
hop_limit - INTEGER
Default Hop Limit to set.
diff --git a/Documentation/networking/phonet.txt b/Documentation/networking/phonet.txt
index 6e8ce09f9c73..24ad2adba6e5 100644
--- a/Documentation/networking/phonet.txt
+++ b/Documentation/networking/phonet.txt
@@ -112,6 +112,22 @@ However, connect() and getpeername() are not supported, as they did
not seem useful with Phonet usages (could be added easily).
+Resource subscription
+---------------------
+
+A Phonet datagram socket can be subscribed to any number of 8-bits
+Phonet resources, as follow:
+
+ uint32_t res = 0xXX;
+ ioctl(fd, SIOCPNADDRESOURCE, &res);
+
+Subscription is similarly cancelled using the SIOCPNDELRESOURCE I/O
+control request, or when the socket is closed.
+
+Note that no more than one socket can be subcribed to any given
+resource at a time. If not, ioctl() will return EBUSY.
+
+
Phonet Pipe protocol
--------------------
@@ -166,6 +182,46 @@ The pipe protocol provides two socket options at the SOL_PNPIPE level:
or zero if encapsulation is off.
+Phonet Pipe-controller Implementation
+-------------------------------------
+
+Phonet Pipe-controller is enabled by selecting the CONFIG_PHONET_PIPECTRLR Kconfig
+option. It is useful when communicating with those Nokia Modems which do not
+implement Pipe controller in them e.g. Nokia Slim Modem used in ST-Ericsson
+U8500 platform.
+
+The implementation is based on the Data Connection Establishment Sequence
+depicted in 'Nokia Wireless Modem API - Wireless_modem_user_guide.pdf'
+document.
+
+It allows a phonet sequenced socket (host-pep) to initiate a Pipe connection
+between itself and a remote pipe-end point (e.g. modem).
+
+The implementation adds socket options at SOL_PNPIPE level:
+
+ PNPIPE_PIPE_HANDLE
+ It accepts an integer argument for setting value of pipe handle.
+
+ PNPIPE_ENABLE accepts one integer value (int). If set to zero, the pipe
+ is disabled. If the value is non-zero, the pipe is enabled. If the pipe
+ is not (yet) connected, ENOTCONN is error is returned.
+
+The implementation also adds socket 'connect'. On calling the 'connect', pipe
+will be created between the source socket and the destination, and the pipe
+state will be set to PIPE_DISABLED.
+
+After a pipe has been created and enabled successfully, the Pipe data can be
+exchanged between the host-pep and remote-pep (modem).
+
+User-space would typically follow below sequence with Pipe controller:-
+-socket
+-bind
+-setsockopt for PNPIPE_PIPE_HANDLE
+-connect
+-setsockopt for PNPIPE_ENCAP_IP
+-setsockopt for PNPIPE_ENABLE
+
+
Authors
-------
diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt
index 88bb71b46da4..9eb1ba52013d 100644
--- a/Documentation/networking/phy.txt
+++ b/Documentation/networking/phy.txt
@@ -177,18 +177,6 @@ Doing it all yourself
A convenience function to print out the PHY status neatly.
- int phy_clear_interrupt(struct phy_device *phydev);
- int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
-
- Clear the PHY's interrupt, and configure which ones are allowed,
- respectively. Currently only supports all on, or all off.
-
- int phy_enable_interrupts(struct phy_device *phydev);
- int phy_disable_interrupts(struct phy_device *phydev);
-
- Functions which enable/disable PHY interrupts, clearing them
- before and after, respectively.
-
int phy_start_interrupts(struct phy_device *phydev);
int phy_stop_interrupts(struct phy_device *phydev);
@@ -213,12 +201,6 @@ Doing it all yourself
Fills the phydev structure with up-to-date information about the current
settings in the PHY.
- void phy_sanitize_settings(struct phy_device *phydev)
-
- Resolves differences between currently desired settings, and
- supported settings for the given PHY device. Does not make
- the changes in the hardware, though.
-
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt
index e8c8f4f06c67..98097d8cb910 100644
--- a/Documentation/networking/timestamping.txt
+++ b/Documentation/networking/timestamping.txt
@@ -172,15 +172,19 @@ struct skb_shared_hwtstamps {
};
Time stamps for outgoing packets are to be generated as follows:
-- In hard_start_xmit(), check if skb_tx(skb)->hardware is set no-zero.
- If yes, then the driver is expected to do hardware time stamping.
+- In hard_start_xmit(), check if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
+ is set no-zero. If yes, then the driver is expected to do hardware time
+ stamping.
- If this is possible for the skb and requested, then declare
- that the driver is doing the time stamping by setting the field
- skb_tx(skb)->in_progress non-zero. You might want to keep a pointer
- to the associated skb for the next step and not free the skb. A driver
- not supporting hardware time stamping doesn't do that. A driver must
- never touch sk_buff::tstamp! It is used to store software generated
- time stamps by the network subsystem.
+ that the driver is doing the time stamping by setting the flag
+ SKBTX_IN_PROGRESS in skb_shinfo(skb)->tx_flags , e.g. with
+
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+
+ You might want to keep a pointer to the associated skb for the next step
+ and not free the skb. A driver not supporting hardware time stamping doesn't
+ do that. A driver must never touch sk_buff::tstamp! It is used to store
+ software generated time stamps by the network subsystem.
- As soon as the driver has sent the packet and/or obtained a
hardware time stamp for it, it passes the time stamp back by
calling skb_hwtstamp_tx() with the original skb, the raw
@@ -191,6 +195,6 @@ Time stamps for outgoing packets are to be generated as follows:
this would occur at a later time in the processing pipeline than other
software time stamping and therefore could lead to unexpected deltas
between time stamps.
-- If the driver did not call set skb_tx(skb)->in_progress, then
+- If the driver did not set the SKBTX_IN_PROGRESS flag (see above), then
dev_hard_start_xmit() checks whether software time stamping
is wanted as fallback and potentially generates the time stamp.
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 7f4dcebda9c6..d0eb696d32e8 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -300,6 +300,74 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
control correctly. If you have problems regarding this, try
another ALSA compliant mixer (alsamixer works).
+ Module snd-azt1605
+ ------------------
+
+ Module for Aztech Sound Galaxy soundcards based on the Aztech AZT1605
+ chipset.
+
+ port - port # for BASE (0x220,0x240,0x260,0x280)
+ wss_port - port # for WSS (0x530,0x604,0xe80,0xf40)
+ irq - IRQ # for WSS (7,9,10,11)
+ dma1 - DMA # for WSS playback (0,1,3)
+ dma2 - DMA # for WSS capture (0,1), -1 = disabled (default)
+ mpu_port - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default)
+ mpu_irq - IRQ # for MPU-401 UART (3,5,7,9), -1 = disabled (default)
+ fm_port - port # for OPL3 (0x388), -1 = disabled (default)
+
+ This module supports multiple cards. It does not support autoprobe: port,
+ wss_port, irq and dma1 have to be specified. The other values are
+ optional.
+
+ "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240)
+ or the value stored in the card's EEPROM for cards that have an EEPROM and
+ their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can
+ be choosen freely from the options enumerated above.
+
+ If dma2 is specified and different from dma1, the card will operate in
+ full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to
+ enable capture since only channels 0 and 1 are available for capture.
+
+ Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0
+ mpu_port=0x330 mpu_irq=9 fm_port=0x388".
+
+ Whatever IRQ and DMA channels you pick, be sure to reserve them for
+ legacy ISA in your BIOS.
+
+ Module snd-azt2316
+ ------------------
+
+ Module for Aztech Sound Galaxy soundcards based on the Aztech AZT2316
+ chipset.
+
+ port - port # for BASE (0x220,0x240,0x260,0x280)
+ wss_port - port # for WSS (0x530,0x604,0xe80,0xf40)
+ irq - IRQ # for WSS (7,9,10,11)
+ dma1 - DMA # for WSS playback (0,1,3)
+ dma2 - DMA # for WSS capture (0,1), -1 = disabled (default)
+ mpu_port - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default)
+ mpu_irq - IRQ # for MPU-401 UART (5,7,9,10), -1 = disabled (default)
+ fm_port - port # for OPL3 (0x388), -1 = disabled (default)
+
+ This module supports multiple cards. It does not support autoprobe: port,
+ wss_port, irq and dma1 have to be specified. The other values are
+ optional.
+
+ "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240)
+ or the value stored in the card's EEPROM for cards that have an EEPROM and
+ their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can
+ be choosen freely from the options enumerated above.
+
+ If dma2 is specified and different from dma1, the card will operate in
+ full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to
+ enable capture since only channels 0 and 1 are available for capture.
+
+ Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0
+ mpu_port=0x330 mpu_irq=9 fm_port=0x388".
+
+ Whatever IRQ and DMA channels you pick, be sure to reserve them for
+ legacy ISA in your BIOS.
+
Module snd-aw2
--------------
@@ -1641,20 +1709,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
This card is also known as Audio Excel DSP 16 or Zoltrix AV302.
- Module snd-sgalaxy
- ------------------
-
- Module for Aztech Sound Galaxy sound card.
-
- sbport - Port # for SB16 interface (0x220,0x240)
- wssport - Port # for WSS interface (0x530,0xe80,0xf40,0x604)
- irq - IRQ # (7,9,10,11)
- dma1 - DMA #
-
- This module supports multiple cards.
-
- The power-management is supported.
-
Module snd-sscape
-----------------
diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt
index 278cc2122ea0..c82beb007634 100644
--- a/Documentation/sound/alsa/HD-Audio.txt
+++ b/Documentation/sound/alsa/HD-Audio.txt
@@ -57,9 +57,11 @@ dead. However, this detection isn't perfect on some devices. In such
a case, you can change the default method via `position_fix` option.
`position_fix=1` means to use LPIB method explicitly.
-`position_fix=2` means to use the position-buffer. 0 is the default
-value, the automatic check and fallback to LPIB as described in the
-above. If you get a problem of repeated sounds, this option might
+`position_fix=2` means to use the position-buffer.
+`position_fix=3` means to use a combination of both methods, needed
+for some VIA and ATI controllers. 0 is the default value for all other
+controllers, the automatic check and fallback to LPIB as described in
+the above. If you get a problem of repeated sounds, this option might
help.
In addition to that, every controller is known to be broken regarding
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index b606c2c4dd37..30289fab86eb 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -80,8 +80,10 @@ dirty_background_bytes
Contains the amount of dirty memory at which the pdflush background writeback
daemon will start writeback.
-If dirty_background_bytes is written, dirty_background_ratio becomes a function
-of its value (dirty_background_bytes / the amount of dirtyable system memory).
+Note: dirty_background_bytes is the counterpart of dirty_background_ratio. Only
+one of them may be specified at a time. When one sysctl is written it is
+immediately taken into account to evaluate the dirty memory limits and the
+other appears as 0 when read.
==============================================================
@@ -97,8 +99,10 @@ dirty_bytes
Contains the amount of dirty memory at which a process generating disk writes
will itself start writeback.
-If dirty_bytes is written, dirty_ratio becomes a function of its value
-(dirty_bytes / the amount of dirtyable system memory).
+Note: dirty_bytes is the counterpart of dirty_ratio. Only one of them may be
+specified at a time. When one sysctl is written it is immediately taken into
+account to evaluate the dirty memory limits and the other appears as 0 when
+read.
Note: the minimum value allowed for dirty_bytes is two pages (in bytes); any
value lower than this limit will be ignored and the old configuration will be
diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt
index 5c17196c8fe9..312e3754e8c5 100644
--- a/Documentation/sysrq.txt
+++ b/Documentation/sysrq.txt
@@ -75,7 +75,7 @@ On all - write a character to /proc/sysrq-trigger. e.g.:
'f' - Will call oom_kill to kill a memory hog process.
-'g' - Used by kgdb on ppc and sh platforms.
+'g' - Used by kgdb (kernel debugger)
'h' - Will display help (actually any other key than those listed
here will display help. but 'h' is easy to remember :-)
@@ -110,12 +110,15 @@ On all - write a character to /proc/sysrq-trigger. e.g.:
'u' - Will attempt to remount all mounted filesystems read-only.
-'v' - Dumps Voyager SMP processor info to your console.
+'v' - Forcefully restores framebuffer console
+'v' - Causes ETM buffer dump [ARM-specific]
'w' - Dumps tasks that are in uninterruptable (blocked) state.
'x' - Used by xmon interface on ppc/powerpc platforms.
+'y' - Show global CPU Registers [SPARC-64 specific]
+
'z' - Dump the ftrace buffer
'0'-'9' - Sets the console log level, controlling which kernel messages
diff --git a/Documentation/timers/hpet_example.c b/Documentation/timers/hpet_example.c
index 4bfafb7bc4c5..9a3e7012c190 100644
--- a/Documentation/timers/hpet_example.c
+++ b/Documentation/timers/hpet_example.c
@@ -97,6 +97,33 @@ hpet_open_close(int argc, const char **argv)
void
hpet_info(int argc, const char **argv)
{
+ struct hpet_info info;
+ int fd;
+
+ if (argc != 1) {
+ fprintf(stderr, "hpet_info: device-name\n");
+ return;
+ }
+
+ fd = open(argv[0], O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "hpet_info: open of %s failed\n", argv[0]);
+ return;
+ }
+
+ if (ioctl(fd, HPET_INFO, &info) < 0) {
+ fprintf(stderr, "hpet_info: failed to get info\n");
+ goto out;
+ }
+
+ fprintf(stderr, "hpet_info: hi_irqfreq 0x%lx hi_flags 0x%lx ",
+ info.hi_ireqfreq, info.hi_flags);
+ fprintf(stderr, "hi_hpet %d hi_timer %d\n",
+ info.hi_hpet, info.hi_timer);
+
+out:
+ close(fd);
+ return;
}
void
diff --git a/Documentation/trace/postprocess/trace-vmscan-postprocess.pl b/Documentation/trace/postprocess/trace-vmscan-postprocess.pl
index 1b55146d1c8d..b3e73ddb1567 100644
--- a/Documentation/trace/postprocess/trace-vmscan-postprocess.pl
+++ b/Documentation/trace/postprocess/trace-vmscan-postprocess.pl
@@ -46,7 +46,7 @@ use constant HIGH_KSWAPD_LATENCY => 20;
use constant HIGH_KSWAPD_REWAKEUP => 21;
use constant HIGH_NR_SCANNED => 22;
use constant HIGH_NR_TAKEN => 23;
-use constant HIGH_NR_RECLAIM => 24;
+use constant HIGH_NR_RECLAIMED => 24;
use constant HIGH_NR_CONTIG_DIRTY => 25;
my %perprocesspid;
@@ -58,11 +58,13 @@ my $opt_read_procstat;
my $total_wakeup_kswapd;
my ($total_direct_reclaim, $total_direct_nr_scanned);
my ($total_direct_latency, $total_kswapd_latency);
+my ($total_direct_nr_reclaimed);
my ($total_direct_writepage_file_sync, $total_direct_writepage_file_async);
my ($total_direct_writepage_anon_sync, $total_direct_writepage_anon_async);
my ($total_kswapd_nr_scanned, $total_kswapd_wake);
my ($total_kswapd_writepage_file_sync, $total_kswapd_writepage_file_async);
my ($total_kswapd_writepage_anon_sync, $total_kswapd_writepage_anon_async);
+my ($total_kswapd_nr_reclaimed);
# Catch sigint and exit on request
my $sigint_report = 0;
@@ -104,7 +106,7 @@ my $regex_kswapd_wake_default = 'nid=([0-9]*) order=([0-9]*)';
my $regex_kswapd_sleep_default = 'nid=([0-9]*)';
my $regex_wakeup_kswapd_default = 'nid=([0-9]*) zid=([0-9]*) order=([0-9]*)';
my $regex_lru_isolate_default = 'isolate_mode=([0-9]*) order=([0-9]*) nr_requested=([0-9]*) nr_scanned=([0-9]*) nr_taken=([0-9]*) contig_taken=([0-9]*) contig_dirty=([0-9]*) contig_failed=([0-9]*)';
-my $regex_lru_shrink_inactive_default = 'lru=([A-Z_]*) nr_scanned=([0-9]*) nr_reclaimed=([0-9]*) priority=([0-9]*)';
+my $regex_lru_shrink_inactive_default = 'nid=([0-9]*) zid=([0-9]*) nr_scanned=([0-9]*) nr_reclaimed=([0-9]*) priority=([0-9]*) flags=([A-Z_|]*)';
my $regex_lru_shrink_active_default = 'lru=([A-Z_]*) nr_scanned=([0-9]*) nr_rotated=([0-9]*) priority=([0-9]*)';
my $regex_writepage_default = 'page=([0-9a-f]*) pfn=([0-9]*) flags=([A-Z_|]*)';
@@ -203,8 +205,8 @@ $regex_lru_shrink_inactive = generate_traceevent_regex(
"vmscan/mm_vmscan_lru_shrink_inactive",
$regex_lru_shrink_inactive_default,
"nid", "zid",
- "lru",
- "nr_scanned", "nr_reclaimed", "priority");
+ "nr_scanned", "nr_reclaimed", "priority",
+ "flags");
$regex_lru_shrink_active = generate_traceevent_regex(
"vmscan/mm_vmscan_lru_shrink_active",
$regex_lru_shrink_active_default,
@@ -375,6 +377,16 @@ EVENT_PROCESS:
my $nr_contig_dirty = $7;
$perprocesspid{$process_pid}->{HIGH_NR_SCANNED} += $nr_scanned;
$perprocesspid{$process_pid}->{HIGH_NR_CONTIG_DIRTY} += $nr_contig_dirty;
+ } elsif ($tracepoint eq "mm_vmscan_lru_shrink_inactive") {
+ $details = $5;
+ if ($details !~ /$regex_lru_shrink_inactive/o) {
+ print "WARNING: Failed to parse mm_vmscan_lru_shrink_inactive as expected\n";
+ print " $details\n";
+ print " $regex_lru_shrink_inactive/o\n";
+ next;
+ }
+ my $nr_reclaimed = $4;
+ $perprocesspid{$process_pid}->{HIGH_NR_RECLAIMED} += $nr_reclaimed;
} elsif ($tracepoint eq "mm_vmscan_writepage") {
$details = $5;
if ($details !~ /$regex_writepage/o) {
@@ -464,8 +476,8 @@ sub dump_stats {
# Print out process activity
printf("\n");
- printf("%-" . $max_strlen . "s %8s %10s %8s %8s %8s %8s %8s\n", "Process", "Direct", "Wokeup", "Pages", "Pages", "Pages", "Time");
- printf("%-" . $max_strlen . "s %8s %10s %8s %8s %8s %8s %8s\n", "details", "Rclms", "Kswapd", "Scanned", "Sync-IO", "ASync-IO", "Stalled");
+ printf("%-" . $max_strlen . "s %8s %10s %8s %8s %8s %8s %8s %8s\n", "Process", "Direct", "Wokeup", "Pages", "Pages", "Pages", "Pages", "Time");
+ printf("%-" . $max_strlen . "s %8s %10s %8s %8s %8s %8s %8s %8s\n", "details", "Rclms", "Kswapd", "Scanned", "Rclmed", "Sync-IO", "ASync-IO", "Stalled");
foreach $process_pid (keys %stats) {
if (!$stats{$process_pid}->{MM_VMSCAN_DIRECT_RECLAIM_BEGIN}) {
@@ -475,6 +487,7 @@ sub dump_stats {
$total_direct_reclaim += $stats{$process_pid}->{MM_VMSCAN_DIRECT_RECLAIM_BEGIN};
$total_wakeup_kswapd += $stats{$process_pid}->{MM_VMSCAN_WAKEUP_KSWAPD};
$total_direct_nr_scanned += $stats{$process_pid}->{HIGH_NR_SCANNED};
+ $total_direct_nr_reclaimed += $stats{$process_pid}->{HIGH_NR_RECLAIMED};
$total_direct_writepage_file_sync += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC};
$total_direct_writepage_anon_sync += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC};
$total_direct_writepage_file_async += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC};
@@ -489,11 +502,12 @@ sub dump_stats {
$index++;
}
- printf("%-" . $max_strlen . "s %8d %10d %8u %8u %8u %8.3f",
+ printf("%-" . $max_strlen . "s %8d %10d %8u %8u %8u %8u %8.3f",
$process_pid,
$stats{$process_pid}->{MM_VMSCAN_DIRECT_RECLAIM_BEGIN},
$stats{$process_pid}->{MM_VMSCAN_WAKEUP_KSWAPD},
$stats{$process_pid}->{HIGH_NR_SCANNED},
+ $stats{$process_pid}->{HIGH_NR_RECLAIMED},
$stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC} + $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC},
$stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC} + $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_ASYNC},
$this_reclaim_delay / 1000);
@@ -529,8 +543,8 @@ sub dump_stats {
# Print out kswapd activity
printf("\n");
- printf("%-" . $max_strlen . "s %8s %10s %8s %8s %8s %8s\n", "Kswapd", "Kswapd", "Order", "Pages", "Pages", "Pages");
- printf("%-" . $max_strlen . "s %8s %10s %8s %8s %8s %8s\n", "Instance", "Wakeups", "Re-wakeup", "Scanned", "Sync-IO", "ASync-IO");
+ printf("%-" . $max_strlen . "s %8s %10s %8s %8s %8s %8s\n", "Kswapd", "Kswapd", "Order", "Pages", "Pages", "Pages", "Pages");
+ printf("%-" . $max_strlen . "s %8s %10s %8s %8s %8s %8s\n", "Instance", "Wakeups", "Re-wakeup", "Scanned", "Rclmed", "Sync-IO", "ASync-IO");
foreach $process_pid (keys %stats) {
if (!$stats{$process_pid}->{MM_VMSCAN_KSWAPD_WAKE}) {
@@ -539,16 +553,18 @@ sub dump_stats {
$total_kswapd_wake += $stats{$process_pid}->{MM_VMSCAN_KSWAPD_WAKE};
$total_kswapd_nr_scanned += $stats{$process_pid}->{HIGH_NR_SCANNED};
+ $total_kswapd_nr_reclaimed += $stats{$process_pid}->{HIGH_NR_RECLAIMED};
$total_kswapd_writepage_file_sync += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC};
$total_kswapd_writepage_anon_sync += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC};
$total_kswapd_writepage_file_async += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC};
$total_kswapd_writepage_anon_async += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_ASYNC};
- printf("%-" . $max_strlen . "s %8d %10d %8u %8i %8u",
+ printf("%-" . $max_strlen . "s %8d %10d %8u %8u %8i %8u",
$process_pid,
$stats{$process_pid}->{MM_VMSCAN_KSWAPD_WAKE},
$stats{$process_pid}->{HIGH_KSWAPD_REWAKEUP},
$stats{$process_pid}->{HIGH_NR_SCANNED},
+ $stats{$process_pid}->{HIGH_NR_RECLAIMED},
$stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC} + $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC},
$stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC} + $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_ASYNC});
@@ -579,6 +595,7 @@ sub dump_stats {
print "\nSummary\n";
print "Direct reclaims: $total_direct_reclaim\n";
print "Direct reclaim pages scanned: $total_direct_nr_scanned\n";
+ print "Direct reclaim pages reclaimed: $total_direct_nr_reclaimed\n";
print "Direct reclaim write file sync I/O: $total_direct_writepage_file_sync\n";
print "Direct reclaim write anon sync I/O: $total_direct_writepage_anon_sync\n";
print "Direct reclaim write file async I/O: $total_direct_writepage_file_async\n";
@@ -588,6 +605,7 @@ sub dump_stats {
print "\n";
print "Kswapd wakeups: $total_kswapd_wake\n";
print "Kswapd pages scanned: $total_kswapd_nr_scanned\n";
+ print "Kswapd pages reclaimed: $total_kswapd_nr_reclaimed\n";
print "Kswapd reclaim write file sync I/O: $total_kswapd_writepage_file_sync\n";
print "Kswapd reclaim write anon sync I/O: $total_kswapd_writepage_anon_sync\n";
print "Kswapd reclaim write file async I/O: $total_kswapd_writepage_file_async\n";
@@ -612,6 +630,7 @@ sub aggregate_perprocesspid() {
$perprocess{$process}->{MM_VMSCAN_WAKEUP_KSWAPD} += $perprocesspid{$process_pid}->{MM_VMSCAN_WAKEUP_KSWAPD};
$perprocess{$process}->{HIGH_KSWAPD_REWAKEUP} += $perprocesspid{$process_pid}->{HIGH_KSWAPD_REWAKEUP};
$perprocess{$process}->{HIGH_NR_SCANNED} += $perprocesspid{$process_pid}->{HIGH_NR_SCANNED};
+ $perprocess{$process}->{HIGH_NR_RECLAIMED} += $perprocesspid{$process_pid}->{HIGH_NR_RECLAIMED};
$perprocess{$process}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC} += $perprocesspid{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC};
$perprocess{$process}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC} += $perprocesspid{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC};
$perprocess{$process}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC} += $perprocesspid{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC};
diff --git a/Documentation/vm/highmem.txt b/Documentation/vm/highmem.txt
new file mode 100644
index 000000000000..4324d24ffacd
--- /dev/null
+++ b/Documentation/vm/highmem.txt
@@ -0,0 +1,162 @@
+
+ ====================
+ HIGH MEMORY HANDLING
+ ====================
+
+By: Peter Zijlstra <a.p.zijlstra@chello.nl>
+
+Contents:
+
+ (*) What is high memory?
+
+ (*) Temporary virtual mappings.
+
+ (*) Using kmap_atomic.
+
+ (*) Cost of temporary mappings.
+
+ (*) i386 PAE.
+
+
+====================
+WHAT IS HIGH MEMORY?
+====================
+
+High memory (highmem) is used when the size of physical memory approaches or
+exceeds the maximum size of virtual memory. At that point it becomes
+impossible for the kernel to keep all of the available physical memory mapped
+at all times. This means the kernel needs to start using temporary mappings of
+the pieces of physical memory that it wants to access.
+
+The part of (physical) memory not covered by a permanent mapping is what we
+refer to as 'highmem'. There are various architecture dependent constraints on
+where exactly that border lies.
+
+In the i386 arch, for example, we choose to map the kernel into every process's
+VM space so that we don't have to pay the full TLB invalidation costs for
+kernel entry/exit. This means the available virtual memory space (4GiB on
+i386) has to be divided between user and kernel space.
+
+The traditional split for architectures using this approach is 3:1, 3GiB for
+userspace and the top 1GiB for kernel space:
+
+ +--------+ 0xffffffff
+ | Kernel |
+ +--------+ 0xc0000000
+ | |
+ | User |
+ | |
+ +--------+ 0x00000000
+
+This means that the kernel can at most map 1GiB of physical memory at any one
+time, but because we need virtual address space for other things - including
+temporary maps to access the rest of the physical memory - the actual direct
+map will typically be less (usually around ~896MiB).
+
+Other architectures that have mm context tagged TLBs can have separate kernel
+and user maps. Some hardware (like some ARMs), however, have limited virtual
+space when they use mm context tags.
+
+
+==========================
+TEMPORARY VIRTUAL MAPPINGS
+==========================
+
+The kernel contains several ways of creating temporary mappings:
+
+ (*) vmap(). This can be used to make a long duration mapping of multiple
+ physical pages into a contiguous virtual space. It needs global
+ synchronization to unmap.
+
+ (*) kmap(). This permits a short duration mapping of a single page. It needs
+ global synchronization, but is amortized somewhat. It is also prone to
+ deadlocks when using in a nested fashion, and so it is not recommended for
+ new code.
+
+ (*) kmap_atomic(). This permits a very short duration mapping of a single
+ page. Since the mapping is restricted to the CPU that issued it, it
+ performs well, but the issuing task is therefore required to stay on that
+ CPU until it has finished, lest some other task displace its mappings.
+
+ kmap_atomic() may also be used by interrupt contexts, since it is does not
+ sleep and the caller may not sleep until after kunmap_atomic() is called.
+
+ It may be assumed that k[un]map_atomic() won't fail.
+
+
+=================
+USING KMAP_ATOMIC
+=================
+
+When and where to use kmap_atomic() is straightforward. It is used when code
+wants to access the contents of a page that might be allocated from high memory
+(see __GFP_HIGHMEM), for example a page in the pagecache. The API has two
+functions, and they can be used in a manner similar to the following:
+
+ /* Find the page of interest. */
+ struct page *page = find_get_page(mapping, offset);
+
+ /* Gain access to the contents of that page. */
+ void *vaddr = kmap_atomic(page);
+
+ /* Do something to the contents of that page. */
+ memset(vaddr, 0, PAGE_SIZE);
+
+ /* Unmap that page. */
+ kunmap_atomic(vaddr);
+
+Note that the kunmap_atomic() call takes the result of the kmap_atomic() call
+not the argument.
+
+If you need to map two pages because you want to copy from one page to
+another you need to keep the kmap_atomic calls strictly nested, like:
+
+ vaddr1 = kmap_atomic(page1);
+ vaddr2 = kmap_atomic(page2);
+
+ memcpy(vaddr1, vaddr2, PAGE_SIZE);
+
+ kunmap_atomic(vaddr2);
+ kunmap_atomic(vaddr1);
+
+
+==========================
+COST OF TEMPORARY MAPPINGS
+==========================
+
+The cost of creating temporary mappings can be quite high. The arch has to
+manipulate the kernel's page tables, the data TLB and/or the MMU's registers.
+
+If CONFIG_HIGHMEM is not set, then the kernel will try and create a mapping
+simply with a bit of arithmetic that will convert the page struct address into
+a pointer to the page contents rather than juggling mappings about. In such a
+case, the unmap operation may be a null operation.
+
+If CONFIG_MMU is not set, then there can be no temporary mappings and no
+highmem. In such a case, the arithmetic approach will also be used.
+
+
+========
+i386 PAE
+========
+
+The i386 arch, under some circumstances, will permit you to stick up to 64GiB
+of RAM into your 32-bit machine. This has a number of consequences:
+
+ (*) Linux needs a page-frame structure for each page in the system and the
+ pageframes need to live in the permanent mapping, which means:
+
+ (*) you can have 896M/sizeof(struct page) page-frames at most; with struct
+ page being 32-bytes that would end up being something in the order of 112G
+ worth of pages; the kernel, however, needs to store more than just
+ page-frames in that memory...
+
+ (*) PAE makes your page tables larger - which slows the system down as more
+ data has to be accessed to traverse in TLB fills and the like. One
+ advantage is that PAE has more PTE bits and can provide advanced features
+ like NX and PAT.
+
+The general recommendation is that you don't use more than 8GiB on a 32-bit
+machine - although more might work for you and your workload, you're pretty
+much on your own - don't expect kernel developers to really care much if things
+come apart.
diff --git a/Documentation/vm/numa_memory_policy.txt b/Documentation/vm/numa_memory_policy.txt
index 6690fc34ef6d..4e7da6543424 100644
--- a/Documentation/vm/numa_memory_policy.txt
+++ b/Documentation/vm/numa_memory_policy.txt
@@ -424,7 +424,7 @@ a command line tool, numactl(8), exists that allows one to:
+ set the shared policy for a shared memory segment via mbind(2)
-The numactl(8) tool is packages with the run-time version of the library
+The numactl(8) tool is packaged with the run-time version of the library
containing the memory policy system call wrappers. Some distributions
package the headers and compile-time libraries in a separate development
package.
diff --git a/Kbuild b/Kbuild
index e3737ad72b5a..b00037ad7e03 100644
--- a/Kbuild
+++ b/Kbuild
@@ -53,6 +53,7 @@ targets += arch/$(SRCARCH)/kernel/asm-offsets.s
# Default sed regexp - multiline due to syntax constraints
define sed-y
"/^->/{s:->#\(.*\):/* \1 */:; \
+ s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \
s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
s:->::; p;}"
endef
diff --git a/MAINTAINERS b/MAINTAINERS
index 9a0432de9141..1e6b6bdf6340 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -243,21 +243,6 @@ F: drivers/pnp/pnpacpi/
F: include/linux/acpi.h
F: include/acpi/
-ACPI BATTERY DRIVERS
-M: Alexey Starikovskiy <astarikovskiy@suse.de>
-L: linux-acpi@vger.kernel.org
-W: http://www.lesswatts.org/projects/acpi/
-S: Supported
-F: drivers/acpi/battery.c
-F: drivers/acpi/*sbs*
-
-ACPI EC DRIVER
-M: Alexey Starikovskiy <astarikovskiy@suse.de>
-L: linux-acpi@vger.kernel.org
-W: http://www.lesswatts.org/projects/acpi/
-S: Supported
-F: drivers/acpi/ec.c
-
ACPI FAN DRIVER
M: Zhang Rui <rui.zhang@intel.com>
L: linux-acpi@vger.kernel.org
@@ -657,7 +642,7 @@ ARM/FARADAY FA526 PORT
M: Hans Ulli Kroll <ulli.kroll@googlemail.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
-T: git://git.berlios.de/gemini-board
+T: git git://git.berlios.de/gemini-board
F: arch/arm/mm/*-fa*
ARM/FOOTBRIDGE ARCHITECTURE
@@ -672,7 +657,7 @@ ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
M: Sascha Hauer <kernel@pengutronix.de>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
-T: git://git.pengutronix.de/git/imx/linux-2.6.git
+T: git git://git.pengutronix.de/git/imx/linux-2.6.git
F: arch/arm/mach-mx*/
F: arch/arm/plat-mxc/
@@ -710,8 +695,7 @@ ARM/INCOME PXA270 SUPPORT
M: Marek Vasut <marek.vasut@gmail.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
-F: arch/arm/mach-pxa/income.c
-F: arch/arm/mach-pxa/include/mach-pxa/income.h
+F: arch/arm/mach-pxa/colibri-pxa270-income.c
ARM/INTEL IOP32X ARM ARCHITECTURE
M: Lennert Buytenhek <kernel@wantstofly.org>
@@ -758,13 +742,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/mach-ixp4xx/
-ARM/INTEL RESEARCH IMOTE 2 MACHINE SUPPORT
-M: Jonathan Cameron <jic23@cam.ac.uk>
-L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S: Maintained
-F: arch/arm/mach-pxa/imote2.c
-
-ARM/INTEL RESEARCH STARGATE 2 MACHINE SUPPORT
+ARM/INTEL RESEARCH IMOTE/STARGATE 2 MACHINE SUPPORT
M: Jonathan Cameron <jic23@cam.ac.uk>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
@@ -929,40 +907,20 @@ W: http://www.fluff.org/ben/linux/
S: Maintained
F: arch/arm/mach-s3c2410/
-ARM/S3C2440 ARM ARCHITECTURE
+ARM/S3C244x ARM ARCHITECTURE
M: Ben Dooks <ben-linux@fluff.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://www.fluff.org/ben/linux/
S: Maintained
F: arch/arm/mach-s3c2440/
-
-ARM/S3C2442 ARM ARCHITECTURE
-M: Ben Dooks <ben-linux@fluff.org>
-L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W: http://www.fluff.org/ben/linux/
-S: Maintained
-F: arch/arm/mach-s3c2442/
-
-ARM/S3C2443 ARM ARCHITECTURE
-M: Ben Dooks <ben-linux@fluff.org>
-L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W: http://www.fluff.org/ben/linux/
-S: Maintained
F: arch/arm/mach-s3c2443/
-ARM/S3C6400 ARM ARCHITECTURE
+ARM/S3C64xx ARM ARCHITECTURE
M: Ben Dooks <ben-linux@fluff.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://www.fluff.org/ben/linux/
S: Maintained
-F: arch/arm/mach-s3c6400/
-
-ARM/S3C6410 ARM ARCHITECTURE
-M: Ben Dooks <ben-linux@fluff.org>
-L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W: http://www.fluff.org/ben/linux/
-S: Maintained
-F: arch/arm/mach-s3c6410/
+F: arch/arm/mach-s3c64xx/
ARM/S5P ARM ARCHITECTURES
M: Kukjin Kim <kgene.kim@samsung.com>
@@ -1151,6 +1109,13 @@ W: http://wireless.kernel.org/en/users/Drivers/ar9170
S: Maintained
F: drivers/net/wireless/ath/ar9170/
+CARL9170 LINUX COMMUNITY WIRELESS DRIVER
+M: Christian Lamparter <chunkeey@googlemail.com>
+L: linux-wireless@vger.kernel.org
+W: http://wireless.kernel.org/en/users/Drivers/carl9170
+S: Maintained
+F: drivers/net/wireless/ath/carl9170/
+
ATK0110 HWMON DRIVER
M: Luca Tettamanti <kronos.it@gmail.com>
L: lm-sensors@lm-sensors.org
@@ -1375,16 +1340,19 @@ F: drivers/mtd/devices/block2mtd.c
BLUETOOTH DRIVERS
M: Marcel Holtmann <marcel@holtmann.org>
+M: Gustavo F. Padovan <padovan@profusion.mobi>
L: linux-bluetooth@vger.kernel.org
W: http://www.bluez.org/
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-2.6.git
S: Maintained
F: drivers/bluetooth/
BLUETOOTH SUBSYSTEM
M: Marcel Holtmann <marcel@holtmann.org>
+M: Gustavo F. Padovan <padovan@profusion.mobi>
L: linux-bluetooth@vger.kernel.org
W: http://www.bluez.org/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/holtmann/bluetooth-2.6.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-2.6.git
S: Maintained
F: net/bluetooth/
F: include/net/bluetooth/
@@ -1429,6 +1397,13 @@ L: linux-scsi@vger.kernel.org
S: Supported
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/
+
BSG (block layer generic sg v4 driver)
M: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
L: linux-scsi@vger.kernel.org
@@ -1545,9 +1520,8 @@ F: net/ceph
F: include/linux/ceph
CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
-M: David Vrabel <david.vrabel@csr.com>
L: linux-usb@vger.kernel.org
-S: Supported
+S: Orphan
F: Documentation/usb/WUSB-Design-overview.txt
F: Documentation/usb/wusb-cbaf
F: drivers/usb/host/hwa-hc.c
@@ -1586,9 +1560,9 @@ S: Supported
F: scripts/checkpatch.pl
CISCO VIC ETHERNET NIC DRIVER
-M: Scott Feldman <scofeldm@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/
@@ -2086,6 +2060,15 @@ S: Maintained
F: drivers/gpu/drm/
F: include/drm/
+INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
+M: Chris Wilson <chris@chris-wilson.co.uk>
+L: intel-gfx@lists.freedesktop.org
+L: dri-devel@lists.freedesktop.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/ickle/drm-intel.git
+S: Supported
+F: drivers/gpu/drm/i915
+F: include/drm/i915*
+
DSCC4 DRIVER
M: Francois Romieu <romieu@fr.zoreil.com>
L: netdev@vger.kernel.org
@@ -2195,6 +2178,13 @@ W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i5400_edac.c
+EDAC-I7300
+M: Mauro Carvalho Chehab <mchehab@redhat.com>
+L: linux-edac@vger.kernel.org
+W: bluesmoke.sourceforge.net
+S: Maintained
+F: drivers/edac/i7300_edac.c
+
EDAC-I7CORE
M: Mauro Carvalho Chehab <mchehab@redhat.com>
L: linux-edac@vger.kernel.org
@@ -2622,10 +2612,10 @@ F: drivers/net/greth*
HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
M: Frank Seidel <frank@f-seidel.de>
-L: lm-sensors@lm-sensors.org
+L: platform-driver-x86@vger.kernel.org
W: http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
S: Maintained
-F: drivers/hwmon/hdaps.c
+F: drivers/platform/x86/hdaps.c
HWPOISON MEMORY FAILURE HANDLING
M: Andi Kleen <andi@firstfloor.org>
@@ -2922,6 +2912,12 @@ M: Brian King <brking@us.ibm.com>
S: Supported
F: drivers/scsi/ipr.*
+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.*
+
IBM ServeRAID RAID DRIVER
P: Jack Hammer
M: Dave Jeffery <ipslinux@adaptec.com>
@@ -2986,7 +2982,7 @@ M: Roland Dreier <rolandd@cisco.com>
M: Sean Hefty <sean.hefty@intel.com>
M: Hal Rosenstock <hal.rosenstock@gmail.com>
L: linux-rdma@vger.kernel.org
-W: http://www.openib.org/
+W: http://www.openfabrics.org/
Q: http://patchwork.kernel.org/project/linux-rdma/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband.git
S: Supported
@@ -3411,7 +3407,7 @@ F: scripts/package/
KERNEL JANITORS
L: kernel-janitors@vger.kernel.org
-W: http://janitor.kernelnewbies.org/
+W: http://kernelnewbies.org/KernelJanitors
S: Odd Fixes
KERNEL NFSD, SUNRPC, AND LOCKD SERVERS
@@ -3736,6 +3732,13 @@ L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/sym53c8xx_2/
+LTC4261 HARDWARE MONITOR DRIVER
+M: Guenter Roeck <linux@roeck-us.net>
+L: lm-sensors@lm-sensors.org
+S: Maintained
+F: Documentation/hwmon/ltc4261
+F: drivers/hwmon/ltc4261.c
+
LTP (Linux Test Project)
M: Rishikesh K Rajak <risrajak@linux.vnet.ibm.com>
M: Garrett Cooper <yanegomi@gmail.com>
@@ -3831,7 +3834,7 @@ F: drivers/net/wireless/mwl8k.c
MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
M: Nicolas Pitre <nico@fluxnic.net>
S: Odd Fixes
-F: drivers/mmc/host/mvsdio.*
+F: drivers/mmc/host/mvsdio.*
MARVELL YUKON / SYSKONNECT DRIVER
M: Mirko Lindner <mlindner@syskonnect.de>
@@ -4392,13 +4395,12 @@ F: Documentation/filesystems/dlmfs.txt
F: fs/ocfs2/
ORINOCO DRIVER
-M: Pavel Roskin <proski@gnu.org>
-M: David Gibson <hermes@gibson.dropbear.id.au>
L: linux-wireless@vger.kernel.org
L: orinoco-users@lists.sourceforge.net
L: orinoco-devel@lists.sourceforge.net
+W: http://linuxwireless.org/en/users/Drivers/orinoco
W: http://www.nongnu.org/orinoco/
-S: Maintained
+S: Orphan
F: drivers/net/wireless/orinoco/
OSD LIBRARY and FILESYSTEM
@@ -4431,13 +4433,22 @@ L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/i2c/busses/i2c-pasemi.c
+PADATA PARALLEL EXECUTION MECHANISM
+M: Steffen Klassert <steffen.klassert@secunet.com>
+L: linux-kernel@vger.kernel.org
+L: linux-crypto@vger.kernel.org
+S: Maintained
+F: kernel/padata.c
+F: include/linux/padata.h
+F: Documentation/padata.txt
+
PANASONIC LAPTOP ACPI EXTRAS DRIVER
M: Harald Welte <laforge@gnumonks.org>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/panasonic-laptop.c
-PANASONIC MN10300/AM33 PORT
+PANASONIC MN10300/AM33/AM34 PORT
M: David Howells <dhowells@redhat.com>
M: Koichi Yasutake <yasutake.koichi@jp.panasonic.com>
L: linux-am33-list@redhat.com (moderated for non-subscribers)
@@ -4510,6 +4521,12 @@ S: Maintained
F: drivers/leds/leds-pca9532.c
F: include/linux/leds-pca9532.h
+PCA9541 I2C BUS MASTER SELECTOR DRIVER
+M: Guenter Roeck <guenter.roeck@ericsson.com>
+L: linux-i2c@vger.kernel.org
+S: Maintained
+F: drivers/i2c/muxes/pca9541.c
+
PCA9564/PCA9665 I2C BUS DRIVER
M: Wolfram Sang <w.sang@pengutronix.de>
L: linux-i2c@vger.kernel.org
@@ -4558,6 +4575,13 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/pcnet32.c
+PCRYPT PARALLEL CRYPTO ENGINE
+M: Steffen Klassert <steffen.klassert@secunet.com>
+L: linux-crypto@vger.kernel.org
+S: Maintained
+F: crypto/pcrypt.c
+F: include/crypto/pcrypt.h
+
PER-TASK DELAY ACCOUNTING
M: Balbir Singh <balbir@linux.vnet.ibm.com>
S: Maintained
@@ -4586,6 +4610,14 @@ L: linux-abi-devel@lists.sourceforge.net
S: Maintained
F: include/linux/personality.h
+PHONET PROTOCOL
+M: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
+S: Supported
+F: Documentation/networking/phonet.txt
+F: include/linux/phonet.h
+F: include/net/phonet/
+F: net/phonet/
+
PHRAM MTD DRIVER
M: Joern Engel <joern@lazybastard.org>
L: linux-mtd@lists.infradead.org
@@ -4893,7 +4925,7 @@ RCUTORTURE MODULE
M: Josh Triplett <josh@freedesktop.org>
M: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
S: Supported
-T: git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu.git
F: Documentation/RCU/torture.txt
F: kernel/rcutorture.c
@@ -4918,7 +4950,7 @@ M: Dipankar Sarma <dipankar@in.ibm.com>
M: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
W: http://www.rdrop.com/users/paulmck/rclock/
S: Supported
-T: git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu.git
F: Documentation/RCU/
F: include/linux/rcu*
F: include/linux/srcu*
@@ -5108,6 +5140,16 @@ W: http://www.kernel.dk
S: Maintained
F: drivers/scsi/sr*
+SCSI RDMA PROTOCOL (SRP) INITIATOR
+M: David Dillow <dillowda@ornl.gov>
+L: linux-rdma@vger.kernel.org
+S: Supported
+W: http://www.openfabrics.org
+Q: http://patchwork.kernel.org/project/linux-rdma/list/
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/dad/srp-initiator.git
+F: drivers/infiniband/ulp/srp/
+F: include/scsi/srp.h
+
SCSI SG DRIVER
M: Doug Gilbert <dgilbert@interlog.com>
L: linux-scsi@vger.kernel.org
@@ -5330,8 +5372,8 @@ F: drivers/*/*s3c2410*
F: drivers/*/*/*s3c2410*
TI DAVINCI MACHINE SUPPORT
-P: Kevin Hilman
-M: davinci-linux-open-source@linux.davincidsp.com
+M: Kevin Hilman <khilman@deeprootsystems.com>
+L: davinci-linux-open-source@linux.davincidsp.com (subscribers-only)
Q: http://patchwork.kernel.org/project/linux-davinci/list/
S: Supported
F: arch/arm/mach-davinci
@@ -5932,13 +5974,9 @@ F: Documentation/filesystems/ufs.txt
F: fs/ufs/
ULTRA-WIDEBAND (UWB) SUBSYSTEM:
-M: David Vrabel <david.vrabel@csr.com>
L: linux-usb@vger.kernel.org
-S: Supported
+S: Orphan
F: drivers/uwb/
-X: drivers/uwb/wlp/
-X: drivers/uwb/i1480/i1480u-wlp/
-X: drivers/uwb/i1480/i1480-wlp.h
F: include/linux/uwb.h
F: include/linux/uwb/
@@ -6080,13 +6118,6 @@ L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/serial/option.c
-USB OV511 DRIVER
-M: Mark McClelland <mmcclell@bigfoot.com>
-L: linux-usb@vger.kernel.org
-W: http://alpha.dyndns.org/ov511/
-S: Maintained
-F: drivers/media/video/ov511.*
-
USB PEGASUS DRIVER
M: Petko Manolov <petkan@users.sourceforge.net>
L: linux-usb@vger.kernel.org
@@ -6247,16 +6278,6 @@ S: Supported
F: drivers/usb/host/xhci*
F: drivers/usb/host/pci-quirks*
-USB ZC0301 DRIVER
-M: Luca Risolia <luca.risolia@studio.unibo.it>
-L: linux-usb@vger.kernel.org
-L: linux-media@vger.kernel.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
-W: http://www.linux-projects.org
-S: Maintained
-F: Documentation/video4linux/zc0301.txt
-F: drivers/media/video/zc0301/
-
USB ZD1201 DRIVER
L: linux-wireless@vger.kernel.org
W: http://linux-lc100020.sourceforge.net
@@ -6474,36 +6495,27 @@ F: include/linux/wimax/debug.h
F: include/net/wimax.h
F: net/wimax/
-WIMEDIA LLC PROTOCOL (WLP) SUBSYSTEM
-M: David Vrabel <david.vrabel@csr.com>
-L: netdev@vger.kernel.org
-S: Maintained
-F: include/linux/wlp.h
-F: drivers/uwb/wlp/
-F: drivers/uwb/i1480/i1480u-wlp/
-F: drivers/uwb/i1480/i1480-wlp.h
-
WISTRON LAPTOP BUTTON DRIVER
M: Miloslav Trmac <mitr@volny.cz>
S: Maintained
F: drivers/input/misc/wistron_btns.c
WL1251 WIRELESS DRIVER
-M: Kalle Valo <kalle.valo@iki.fi>
+M: Kalle Valo <kvalo@adurom.com>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained
-F: drivers/net/wireless/wl12xx/*
-X: drivers/net/wireless/wl12xx/wl1271*
+F: drivers/net/wireless/wl1251/*
WL1271 WIRELESS DRIVER
M: Luciano Coelho <luciano.coelho@nokia.com>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
S: Maintained
F: drivers/net/wireless/wl12xx/wl1271*
+F: include/linux/wl12xx.h
WL3501 WIRELESS PCMCIA CARD DRIVER
M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
@@ -6650,6 +6662,20 @@ M: "Maciej W. Rozycki" <macro@linux-mips.org>
S: Maintained
F: drivers/serial/zs.*
+GRE DEMULTIPLEXER DRIVER
+M: Dmitry Kozlov <xeb@mail.ru>
+L: netdev@vger.kernel.org
+S: Maintained
+F: net/ipv4/gre.c
+F: include/net/gre.h
+
+PPTP DRIVER
+M: Dmitry Kozlov <xeb@mail.ru>
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/net/pptp.c
+W: http://sourceforge.net/projects/accel-pptp
+
THE REST
M: Linus Torvalds <torvalds@linux-foundation.org>
L: linux-kernel@vger.kernel.org
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index d04ccd73af45..28f93a6c0fde 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -55,6 +55,9 @@ config ZONE_DMA
bool
default y
+config ARCH_DMA_ADDR_T_64BIT
+ def_bool y
+
config NEED_DMA_MAP_STATE
def_bool y
diff --git a/arch/alpha/include/asm/core_mcpcia.h b/arch/alpha/include/asm/core_mcpcia.h
index 21ac53383b37..9f67a056b461 100644
--- a/arch/alpha/include/asm/core_mcpcia.h
+++ b/arch/alpha/include/asm/core_mcpcia.h
@@ -247,7 +247,7 @@ struct el_MCPCIA_uncorrected_frame_mcheck {
#define vip volatile int __force *
#define vuip volatile unsigned int __force *
-#ifdef MCPCIA_ONE_HAE_WINDOW
+#ifndef MCPCIA_ONE_HAE_WINDOW
#define MCPCIA_FROB_MMIO \
if (__mcpcia_is_mmio(hose)) { \
set_hae(hose & 0xffffffff); \
diff --git a/arch/alpha/include/asm/core_t2.h b/arch/alpha/include/asm/core_t2.h
index 471c07292e0b..91b46801b290 100644
--- a/arch/alpha/include/asm/core_t2.h
+++ b/arch/alpha/include/asm/core_t2.h
@@ -1,6 +1,9 @@
#ifndef __ALPHA_T2__H__
#define __ALPHA_T2__H__
+/* Fit everything into one 128MB HAE window. */
+#define T2_ONE_HAE_WINDOW 1
+
#include <linux/types.h>
#include <linux/spinlock.h>
#include <asm/compiler.h>
@@ -19,7 +22,7 @@
*
*/
-#define T2_MEM_R1_MASK 0x07ffffff /* Mem sparse region 1 mask is 26 bits */
+#define T2_MEM_R1_MASK 0x07ffffff /* Mem sparse region 1 mask is 27 bits */
/* GAMMA-SABLE is a SABLE with EV5-based CPUs */
/* All LYNX machines, EV4 or EV5, use the GAMMA bias also */
@@ -85,7 +88,9 @@
#define T2_DIR (IDENT_ADDR + GAMMA_BIAS + 0x38e0004a0UL)
#define T2_ICE (IDENT_ADDR + GAMMA_BIAS + 0x38e0004c0UL)
+#ifndef T2_ONE_HAE_WINDOW
#define T2_HAE_ADDRESS T2_HAE_1
+#endif
/* T2 CSRs are in the non-cachable primary IO space from 3.8000.0000 to
3.8fff.ffff
@@ -429,13 +434,15 @@ extern inline void t2_outl(u32 b, unsigned long addr)
*
*/
+#ifdef T2_ONE_HAE_WINDOW
+#define t2_set_hae
+#else
#define t2_set_hae { \
- msb = addr >> 27; \
+ unsigned long msb = addr >> 27; \
addr &= T2_MEM_R1_MASK; \
set_hae(msb); \
}
-
-extern raw_spinlock_t t2_hae_lock;
+#endif
/*
* NOTE: take T2_DENSE_MEM off in each readX/writeX routine, since
@@ -446,28 +453,22 @@ extern raw_spinlock_t t2_hae_lock;
__EXTERN_INLINE u8 t2_readb(const volatile void __iomem *xaddr)
{
unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
- unsigned long result, msb;
- unsigned long flags;
- raw_spin_lock_irqsave(&t2_hae_lock, flags);
+ unsigned long result;
t2_set_hae;
result = *(vip) ((addr << 5) + T2_SPARSE_MEM + 0x00);
- raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
return __kernel_extbl(result, addr & 3);
}
__EXTERN_INLINE u16 t2_readw(const volatile void __iomem *xaddr)
{
unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
- unsigned long result, msb;
- unsigned long flags;
- raw_spin_lock_irqsave(&t2_hae_lock, flags);
+ unsigned long result;
t2_set_hae;
result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08);
- raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
return __kernel_extwl(result, addr & 3);
}
@@ -478,59 +479,47 @@ __EXTERN_INLINE u16 t2_readw(const volatile void __iomem *xaddr)
__EXTERN_INLINE u32 t2_readl(const volatile void __iomem *xaddr)
{
unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
- unsigned long result, msb;
- unsigned long flags;
- raw_spin_lock_irqsave(&t2_hae_lock, flags);
+ unsigned long result;
t2_set_hae;
result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18);
- raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
return result & 0xffffffffUL;
}
__EXTERN_INLINE u64 t2_readq(const volatile void __iomem *xaddr)
{
unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
- unsigned long r0, r1, work, msb;
- unsigned long flags;
- raw_spin_lock_irqsave(&t2_hae_lock, flags);
+ unsigned long r0, r1, work;
t2_set_hae;
work = (addr << 5) + T2_SPARSE_MEM + 0x18;
r0 = *(vuip)(work);
r1 = *(vuip)(work + (4 << 5));
- raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
return r1 << 32 | r0;
}
__EXTERN_INLINE void t2_writeb(u8 b, volatile void __iomem *xaddr)
{
unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
- unsigned long msb, w;
- unsigned long flags;
- raw_spin_lock_irqsave(&t2_hae_lock, flags);
+ unsigned long w;
t2_set_hae;
w = __kernel_insbl(b, addr & 3);
*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x00) = w;
- raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
}
__EXTERN_INLINE void t2_writew(u16 b, volatile void __iomem *xaddr)
{
unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
- unsigned long msb, w;
- unsigned long flags;
- raw_spin_lock_irqsave(&t2_hae_lock, flags);
+ unsigned long w;
t2_set_hae;
w = __kernel_inswl(b, addr & 3);
*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08) = w;
- raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
}
/*
@@ -540,29 +529,22 @@ __EXTERN_INLINE void t2_writew(u16 b, volatile void __iomem *xaddr)
__EXTERN_INLINE void t2_writel(u32 b, volatile void __iomem *xaddr)
{
unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
- unsigned long msb;
- unsigned long flags;
- raw_spin_lock_irqsave(&t2_hae_lock, flags);
t2_set_hae;
*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18) = b;
- raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
}
__EXTERN_INLINE void t2_writeq(u64 b, volatile void __iomem *xaddr)
{
unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
- unsigned long msb, work;
- unsigned long flags;
- raw_spin_lock_irqsave(&t2_hae_lock, flags);
+ unsigned long work;
t2_set_hae;
work = (addr << 5) + T2_SPARSE_MEM + 0x18;
*(vuip)work = b;
*(vuip)(work + (4 << 5)) = b >> 32;
- raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
}
__EXTERN_INLINE void __iomem *t2_ioportmap(unsigned long addr)
diff --git a/arch/alpha/include/asm/pgtable.h b/arch/alpha/include/asm/pgtable.h
index 71a243294142..de98a732683d 100644
--- a/arch/alpha/include/asm/pgtable.h
+++ b/arch/alpha/include/asm/pgtable.h
@@ -318,9 +318,7 @@ extern inline pte_t * pte_offset_kernel(pmd_t * dir, unsigned long address)
}
#define pte_offset_map(dir,addr) pte_offset_kernel((dir),(addr))
-#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir),(addr))
#define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
extern pgd_t swapper_pg_dir[1024];
diff --git a/arch/alpha/kernel/core_t2.c b/arch/alpha/kernel/core_t2.c
index e6d90568b65d..2f770e994289 100644
--- a/arch/alpha/kernel/core_t2.c
+++ b/arch/alpha/kernel/core_t2.c
@@ -74,8 +74,6 @@
# define DBG(args)
#endif
-DEFINE_RAW_SPINLOCK(t2_hae_lock);
-
static volatile unsigned int t2_mcheck_any_expected;
static volatile unsigned int t2_mcheck_last_taken;
@@ -406,6 +404,7 @@ void __init
t2_init_arch(void)
{
struct pci_controller *hose;
+ struct resource *hae_mem;
unsigned long temp;
unsigned int i;
@@ -433,7 +432,13 @@ t2_init_arch(void)
*/
pci_isa_hose = hose = alloc_pci_controller();
hose->io_space = &ioport_resource;
- hose->mem_space = &iomem_resource;
+ hae_mem = alloc_resource();
+ hae_mem->start = 0;
+ hae_mem->end = T2_MEM_R1_MASK;
+ hae_mem->name = pci_hae0_name;
+ if (request_resource(&iomem_resource, hae_mem) < 0)
+ printk(KERN_ERR "Failed to request HAE_MEM\n");
+ hose->mem_space = hae_mem;
hose->index = 0;
hose->sparse_mem_base = T2_SPARSE_MEM - IDENT_ADDR;
diff --git a/arch/alpha/kernel/machvec_impl.h b/arch/alpha/kernel/machvec_impl.h
index 512685f78097..7fa62488bd16 100644
--- a/arch/alpha/kernel/machvec_impl.h
+++ b/arch/alpha/kernel/machvec_impl.h
@@ -25,6 +25,9 @@
#ifdef MCPCIA_ONE_HAE_WINDOW
#define MCPCIA_HAE_ADDRESS (&alpha_mv.hae_cache)
#endif
+#ifdef T2_ONE_HAE_WINDOW
+#define T2_HAE_ADDRESS (&alpha_mv.hae_cache)
+#endif
/* Only a few systems don't define IACK_SC, handling all interrupts through
the SRM console. But splitting out that one case from IO() below
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
index d1dbd9acd1df..022c2748fa41 100644
--- a/arch/alpha/kernel/pci_iommu.c
+++ b/arch/alpha/kernel/pci_iommu.c
@@ -223,7 +223,7 @@ iommu_arena_free(struct pci_iommu_arena *arena, long ofs, long n)
*/
static int pci_dac_dma_supported(struct pci_dev *dev, u64 mask)
{
- dma64_addr_t dac_offset = alpha_mv.pci_dac_offset;
+ dma_addr_t dac_offset = alpha_mv.pci_dac_offset;
int ok = 1;
/* If this is not set, the machine doesn't support DAC at all. */
@@ -756,7 +756,7 @@ static void alpha_pci_unmap_sg(struct device *dev, struct scatterlist *sg,
spin_lock_irqsave(&arena->lock, flags);
for (end = sg + nents; sg < end; ++sg) {
- dma64_addr_t addr;
+ dma_addr_t addr;
size_t size;
long npages, ofs;
dma_addr_t tend;
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index baa903602f6a..e2af5eb59bb4 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -269,7 +269,8 @@ void ptrace_disable(struct task_struct *child)
user_disable_single_step(child);
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
unsigned long tmp;
size_t copied;
@@ -292,7 +293,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_PEEKUSR:
force_successful_syscall_return();
ret = get_reg(child, addr);
- DBG(DBG_MEM, ("peek $%ld->%#lx\n", addr, ret));
+ DBG(DBG_MEM, ("peek $%lu->%#lx\n", addr, ret));
break;
/* When I and D space are separate, this will have to be fixed. */
@@ -302,7 +303,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
case PTRACE_POKEUSR: /* write the specified register */
- DBG(DBG_MEM, ("poke $%ld<-%#lx\n", addr, data));
+ DBG(DBG_MEM, ("poke $%lu<-%#lx\n", addr, data));
ret = put_reg(child, addr, data);
break;
default:
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 3849887157e7..bf7273f3dc64 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -573,6 +573,7 @@ config ARCH_TEGRA
select HAVE_CLK
select COMMON_CLKDEV
select ARCH_HAS_BARRIERS if CACHE_L2X0
+ select ARCH_HAS_CPUFREQ
help
This enables support for NVIDIA Tegra based systems (Tegra APX,
Tegra 6xx and Tegra 2 series).
@@ -831,7 +832,7 @@ config ARCH_OMAP
select GENERIC_CLOCKEVENTS
select ARCH_HAS_HOLES_MEMORYMODEL
help
- Support for TI's OMAP platform (OMAP1 and OMAP2).
+ Support for TI's OMAP platform (OMAP1/2/3/4).
config PLAT_SPEAR
bool "ST SPEAr"
@@ -1222,7 +1223,7 @@ config SMP
See also <file:Documentation/i386/IO-APIC.txt>,
<file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
- <http://www.linuxdoc.org/docs.html#howto>.
+ <http://tldp.org/HOWTO/SMP-HOWTO.html>.
If you don't know what to do here, say N.
diff --git a/arch/arm/common/icst.c b/arch/arm/common/icst.c
index 9a7f09cff300..2dc6da70ae59 100644
--- a/arch/arm/common/icst.c
+++ b/arch/arm/common/icst.c
@@ -8,7 +8,7 @@
* published by the Free Software Foundation.
*
* Support functions for calculating clocks/divisors for the ICST307
- * clock generators. See http://www.icst.com/ for more information
+ * clock generators. See http://www.idt.com/ for more information
* on these devices.
*
* This is an almost identical implementation to the ICST525 clock generator.
diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c
index 9012004321dd..c11af1e4bad3 100644
--- a/arch/arm/common/scoop.c
+++ b/arch/arm/common/scoop.c
@@ -44,12 +44,12 @@ void reset_scoop(struct device *dev)
{
struct scoop_dev *sdev = dev_get_drvdata(dev);
- iowrite16(0x0100, sdev->base + SCOOP_MCR); // 00
- iowrite16(0x0000, sdev->base + SCOOP_CDR); // 04
- iowrite16(0x0000, sdev->base + SCOOP_CCR); // 10
- iowrite16(0x0000, sdev->base + SCOOP_IMR); // 18
- iowrite16(0x00FF, sdev->base + SCOOP_IRM); // 14
- iowrite16(0x0000, sdev->base + SCOOP_ISR); // 1C
+ iowrite16(0x0100, sdev->base + SCOOP_MCR); /* 00 */
+ iowrite16(0x0000, sdev->base + SCOOP_CDR); /* 04 */
+ iowrite16(0x0000, sdev->base + SCOOP_CCR); /* 10 */
+ iowrite16(0x0000, sdev->base + SCOOP_IMR); /* 18 */
+ iowrite16(0x00FF, sdev->base + SCOOP_IRM); /* 14 */
+ iowrite16(0x0000, sdev->base + SCOOP_ISR); /* 1C */
iowrite16(0x0000, sdev->base + SCOOP_IRM);
}
diff --git a/arch/arm/common/uengine.c b/arch/arm/common/uengine.c
index b520e56216a9..bef408f3d76c 100644
--- a/arch/arm/common/uengine.c
+++ b/arch/arm/common/uengine.c
@@ -312,16 +312,16 @@ static void generate_ucode(u8 *ucode, u32 *gpr_a, u32 *gpr_b)
b1 = (gpr_a[i] >> 8) & 0xff;
b0 = gpr_a[i] & 0xff;
- // immed[@ai, (b1 << 8) | b0]
- // 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII
+ /* immed[@ai, (b1 << 8) | b0] */
+ /* 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII */
ucode[offset++] = 0xf0;
ucode[offset++] = (b1 >> 4);
ucode[offset++] = (b1 << 4) | 0x0c | (b0 >> 6);
ucode[offset++] = (b0 << 2);
ucode[offset++] = 0x80 | i;
- // immed_w1[@ai, (b3 << 8) | b2]
- // 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII
+ /* immed_w1[@ai, (b3 << 8) | b2] */
+ /* 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII */
ucode[offset++] = 0xf4;
ucode[offset++] = 0x40 | (b3 >> 4);
ucode[offset++] = (b3 << 4) | 0x0c | (b2 >> 6);
@@ -340,16 +340,16 @@ static void generate_ucode(u8 *ucode, u32 *gpr_a, u32 *gpr_b)
b1 = (gpr_b[i] >> 8) & 0xff;
b0 = gpr_b[i] & 0xff;
- // immed[@bi, (b1 << 8) | b0]
- // 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV
+ /* immed[@bi, (b1 << 8) | b0] */
+ /* 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV */
ucode[offset++] = 0xf0;
ucode[offset++] = (b1 >> 4);
ucode[offset++] = (b1 << 4) | 0x02 | (i >> 6);
ucode[offset++] = (i << 2) | 0x03;
ucode[offset++] = b0;
- // immed_w1[@bi, (b3 << 8) | b2]
- // 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV
+ /* immed_w1[@bi, (b3 << 8) | b2] */
+ /* 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV */
ucode[offset++] = 0xf4;
ucode[offset++] = 0x40 | (b3 >> 4);
ucode[offset++] = (b3 << 4) | 0x02 | (i >> 6);
@@ -357,7 +357,7 @@ static void generate_ucode(u8 *ucode, u32 *gpr_a, u32 *gpr_b)
ucode[offset++] = b2;
}
- // ctx_arb[kill]
+ /* ctx_arb[kill] */
ucode[offset++] = 0xe0;
ucode[offset++] = 0x00;
ucode[offset++] = 0x01;
diff --git a/arch/arm/configs/da8xx_omapl_defconfig b/arch/arm/configs/da8xx_omapl_defconfig
index ba6670556f78..cdc40c4b8c48 100644
--- a/arch/arm/configs/da8xx_omapl_defconfig
+++ b/arch/arm/configs/da8xx_omapl_defconfig
@@ -17,6 +17,8 @@ CONFIG_MODVERSIONS=y
CONFIG_ARCH_DAVINCI=y
CONFIG_ARCH_DAVINCI_DA830=y
CONFIG_ARCH_DAVINCI_DA850=y
+CONFIG_MACH_MITYOMAPL138=y
+CONFIG_MACH_OMAPL138_HAWKBOARD=y
CONFIG_DAVINCI_RESET_CLOCKS=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
@@ -79,6 +81,7 @@ CONFIG_I2C_DAVINCI=y
# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DUMMY=y
CONFIG_REGULATOR_TPS6507X=y
CONFIG_FB=y
CONFIG_FB_DA8XX=y
diff --git a/arch/arm/configs/n8x0_defconfig b/arch/arm/configs/n8x0_defconfig
deleted file mode 100644
index 56aebb69411d..000000000000
--- a/arch/arm/configs/n8x0_defconfig
+++ /dev/null
@@ -1,94 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_LBDAF is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_ARCH_OMAP=y
-CONFIG_ARCH_OMAP2=y
-CONFIG_OMAP_RESET_CLOCKS=y
-# CONFIG_OMAP_MUX is not set
-# CONFIG_OMAP_MCBSP is not set
-CONFIG_OMAP_MBOX_FWK=y
-CONFIG_OMAP_32K_TIMER=y
-CONFIG_ARCH_OMAP2420=y
-CONFIG_MACH_NOKIA_N8X0=y
-CONFIG_AEABI=y
-CONFIG_LEDS=y
-CONFIG_ZBOOT_ROM_TEXT=0x10C08000
-CONFIG_ZBOOT_ROM_BSS=0x10200000
-CONFIG_CMDLINE="root=/dev/mmcblk0p2 console=ttyS2,115200n8 debug earlyprintk rootwait"
-CONFIG_FPE_NWFPE=y
-CONFIG_VFP=y
-CONFIG_PM=y
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_ONENAND=y
-CONFIG_MTD_ONENAND_OMAP2=y
-CONFIG_MTD_ONENAND_OTP=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-# CONFIG_I2C_COMPAT is not set
-# CONFIG_I2C_HELPER_AUTO is not set
-CONFIG_I2C_OMAP=y
-CONFIG_SPI=y
-CONFIG_SPI_OMAP24XX=y
-# CONFIG_HWMON is not set
-CONFIG_MENELAUS=y
-CONFIG_REGULATOR=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_SUSPEND=y
-# CONFIG_USB_OTG_WHITELIST is not set
-CONFIG_USB_MUSB_HDRC=y
-CONFIG_USB_MUSB_OTG=y
-CONFIG_USB_GADGET_MUSB_HDRC=y
-# CONFIG_MUSB_PIO_ONLY is not set
-CONFIG_USB_MUSB_DEBUG=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_DEBUG=y
-CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_ETH=m
-CONFIG_USB_ETH_EEM=y
-CONFIG_MMC=y
-CONFIG_MMC_OMAP=y
-CONFIG_EXT3_FS=y
-CONFIG_INOTIFY=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_LZO=y
-CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/omap3_defconfig b/arch/arm/configs/omap2plus_defconfig
index 5db9a6be2054..ccedde1371c3 100644
--- a/arch/arm/configs/omap3_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -53,18 +53,18 @@ CONFIG_MACH_SBC3530=y
CONFIG_MACH_OMAP_3630SDP=y
CONFIG_MACH_OMAP_4430SDP=y
CONFIG_ARM_THUMBEE=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_ERRATA_411920=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_LOCAL_TIMERS is not set
CONFIG_AEABI=y
CONFIG_LEDS=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyS2,115200"
+CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200"
CONFIG_KEXEC=y
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_STAT_DETAILS=y
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_FPE_NWFPE=y
CONFIG_VFP=y
CONFIG_NEON=y
@@ -87,23 +87,23 @@ CONFIG_IP_PNP_RARP=y
# CONFIG_INET_LRO is not set
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
-CONFIG_BT=y
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
CONFIG_BT_RFCOMM=y
CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP=m
CONFIG_BT_BNEP_MC_FILTER=y
CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_BT_HCIUART=y
+CONFIG_BT_HIDP=m
+CONFIG_BT_HCIUART=m
CONFIG_BT_HCIUART_H4=y
CONFIG_BT_HCIUART_BCSP=y
CONFIG_BT_HCIUART_LL=y
-CONFIG_BT_HCIBCM203X=y
-CONFIG_BT_HCIBPA10X=y
-CONFIG_CFG80211=y
-CONFIG_MAC80211=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_CFG80211=m
+CONFIG_MAC80211=m
CONFIG_MAC80211_RC_PID=y
CONFIG_MAC80211_RC_DEFAULT_PID=y
CONFIG_MAC80211_LEDS=y
@@ -137,9 +137,11 @@ CONFIG_SMSC_PHY=y
CONFIG_NET_ETHERNET=y
CONFIG_SMC91X=y
CONFIG_SMSC911X=y
-CONFIG_LIBERTAS=y
-CONFIG_LIBERTAS_USB=y
-CONFIG_LIBERTAS_SDIO=y
+CONFIG_KS8851=y
+CONFIG_KS8851_MLL=y
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
CONFIG_LIBERTAS_DEBUG=y
CONFIG_USB_USBNET=y
CONFIG_USB_ALI_M5632=y
@@ -201,8 +203,8 @@ CONFIG_FONTS=y
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
CONFIG_LOGO=y
-CONFIG_SOUND=y
-CONFIG_SND=y
+CONFIG_SOUND=m
+CONFIG_SND=m
CONFIG_SND_MIXER_OSS=y
CONFIG_SND_PCM_OSS=y
CONFIG_SND_VERBOSE_PRINTK=y
@@ -218,9 +220,9 @@ CONFIG_USB_DEVICEFS=y
CONFIG_USB_SUSPEND=y
# CONFIG_USB_OTG_WHITELIST is not set
CONFIG_USB_MON=y
-CONFIG_USB_MUSB_HDRC=y
-CONFIG_USB_MUSB_OTG=y
-CONFIG_USB_GADGET_MUSB_HDRC=y
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_MUSB_OTG is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
CONFIG_USB_MUSB_DEBUG=y
CONFIG_USB_WDM=y
CONFIG_USB_STORAGE=y
@@ -276,12 +278,11 @@ CONFIG_DEBUG_KERNEL=y
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
CONFIG_PROVE_LOCKING=y
-CONFIG_LOCK_STAT=y
+# CONFIG_LOCK_STAT is not set
CONFIG_DEBUG_SPINLOCK_SLEEP=y
# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_DEBUG_INFO=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_DEBUG_LL=y
CONFIG_SECURITY=y
CONFIG_CRYPTO_MICHAEL_MIC=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/arm/configs/omap_4430sdp_defconfig b/arch/arm/configs/omap_4430sdp_defconfig
deleted file mode 100644
index 14c1e18c648f..000000000000
--- a/arch/arm/configs/omap_4430sdp_defconfig
+++ /dev/null
@@ -1,125 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_ELF_CORE is not set
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_OMAP=y
-CONFIG_ARCH_OMAP4=y
-# CONFIG_ARCH_OMAP2PLUS_TYPICAL is not set
-# CONFIG_ARCH_OMAP2 is not set
-# CONFIG_ARCH_OMAP3 is not set
-# CONFIG_OMAP_MUX is not set
-CONFIG_OMAP_32K_TIMER=y
-CONFIG_OMAP_DM_TIMER=y
-CONFIG_MACH_OMAP_4430SDP=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_PL310_ERRATA_588369=y
-CONFIG_SMP=y
-CONFIG_NR_CPUS=2
-# CONFIG_LOCAL_TIMERS is not set
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="root=/dev/ram0 rw mem=128M console=ttyS2,115200n8 initrd=0x81600000,20M ramdisk_size=20480"
-CONFIG_VFP=y
-CONFIG_NEON=y
-CONFIG_BINFMT_MISC=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_IPV6 is not set
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_FW_LOADER is not set
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=16384
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_KS8851=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_WLAN is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=32
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_8250_DETECT_IRQ=y
-CONFIG_SERIAL_8250_RSA=y
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_OMAP=y
-CONFIG_SPI=y
-CONFIG_SPI_OMAP24XX=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_OMAP_WATCHDOG=y
-CONFIG_TWL4030_CORE=y
-CONFIG_REGULATOR=y
-CONFIG_REGULATOR_TWL4030=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_MMC=y
-CONFIG_MMC_OMAP_HS=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_TWL4030=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_INOTIFY=y
-CONFIG_QUOTA=y
-CONFIG_QFMT_V2=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ISO8859_1=y
-# CONFIG_ENABLE_WARN_DEPRECATED is not set
-# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_DETECT_SOFTLOCKUP is not set
-CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_SCHED_DEBUG is not set
-# CONFIG_DEBUG_PREEMPT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_FTRACE is not set
-# CONFIG_ARM_UNWIND is not set
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_PCBC=m
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRC_CCITT=y
-CONFIG_CRC_T10DIF=y
-CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/omap_generic_2420_defconfig b/arch/arm/configs/omap_generic_2420_defconfig
deleted file mode 100644
index ac08e51180dd..000000000000
--- a/arch/arm/configs/omap_generic_2420_defconfig
+++ /dev/null
@@ -1,37 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_OMAP=y
-CONFIG_ARCH_OMAP2=y
-# CONFIG_OMAP_MUX is not set
-CONFIG_MACH_OMAP_GENERIC=y
-CONFIG_ARCH_OMAP2420=y
-CONFIG_LEDS=y
-CONFIG_ZBOOT_ROM_TEXT=0x10C08000
-CONFIG_ZBOOT_ROM_BSS=0x10200000
-CONFIG_FPE_NWFPE=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_VIDEO_OUTPUT_CONTROL=m
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_INOTIFY=y
-CONFIG_ROMFS_FS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
-CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/pcontrol_g20_defconfig b/arch/arm/configs/pcontrol_g20_defconfig
new file mode 100644
index 000000000000..b42ee62c4d77
--- /dev/null
+++ b/arch/arm/configs/pcontrol_g20_defconfig
@@ -0,0 +1,175 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_CROSS_COMPILE="/opt/arm-2010q1/bin/arm-none-linux-gnueabi-"
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_KALLSYMS is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_DEFAULT_DEADLINE=y
+CONFIG_ARCH_AT91=y
+CONFIG_ARCH_AT91SAM9G20=y
+CONFIG_MACH_PCONTROL_G20=y
+CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,115200 mem=128M mtdparts=atmel_nand:128k(bootstrap)ro,256k(uboot)ro,128k(env1)ro,128k(env2)ro,2M(linux),-(root) root=/dev/mmcblk0p1 rootwait rw"
+CONFIG_VFP=y
+CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_IPV6 is not set
+CONFIG_VLAN_8021Q=y
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHRAM=m
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ATMEL=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_ATMEL_TCLIB=y
+CONFIG_EEPROM_AT24=m
+CONFIG_SCSI=m
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=m
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_MACVLAN=m
+CONFIG_TUN=m
+CONFIG_SMSC_PHY=m
+CONFIG_BROADCOM_PHY=m
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_MACB=y
+CONFIG_SMSC911X=m
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+CONFIG_PPP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_MPPE=m
+CONFIG_INPUT_POLLDEV=y
+CONFIG_INPUT_SPARSEKMAP=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_EVBUG=m
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_KEYBOARD_MATRIX=m
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=m
+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
+# CONFIG_SERIO is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_MAX3100=m
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_R3964=m
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_GPIO=m
+CONFIG_SPI=y
+CONFIG_SPI_ATMEL=m
+CONFIG_SPI_SPIDEV=m
+CONFIG_GPIO_SYSFS=y
+CONFIG_W1=m
+CONFIG_W1_MASTER_GPIO=m
+CONFIG_W1_SLAVE_DS2431=m
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_AT91SAM9X_WATCHDOG=y
+# CONFIG_MFD_SUPPORT is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=m
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_GADGET=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_FILE_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_G_HID=m
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_ATMELMCI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_AT91SAM9=y
+CONFIG_AUXDISPLAY=y
+CONFIG_UIO=y
+CONFIG_UIO_PDRV=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_IIO=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_UTF8=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/include/asm/hardware/icst.h b/arch/arm/include/asm/hardware/icst.h
index 10382a3dcec9..794220b087d2 100644
--- a/arch/arm/include/asm/hardware/icst.h
+++ b/arch/arm/include/asm/hardware/icst.h
@@ -8,7 +8,7 @@
* published by the Free Software Foundation.
*
* Support functions for calculating clocks/divisors for the ICST
- * clock generators. See http://www.icst.com/ for more information
+ * clock generators. See http://www.idt.com/ for more information
* on these devices.
*/
#ifndef ASMARM_HARDWARE_ICST_H
diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h
index 5aff58126602..1fc684e70ab6 100644
--- a/arch/arm/include/asm/highmem.h
+++ b/arch/arm/include/asm/highmem.h
@@ -35,9 +35,9 @@ extern void kunmap_high_l1_vipt(struct page *page, pte_t saved_pte);
#ifdef CONFIG_HIGHMEM
extern void *kmap(struct page *page);
extern void kunmap(struct page *page);
-extern void *kmap_atomic(struct page *page, enum km_type type);
-extern void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
-extern void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
+extern void *__kmap_atomic(struct page *page);
+extern void __kunmap_atomic(void *kvaddr);
+extern void *kmap_atomic_pfn(unsigned long pfn);
extern struct page *kmap_atomic_to_page(const void *ptr);
#endif
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index a9672e8406a3..b155414192da 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -263,17 +263,15 @@ extern struct page *empty_zero_page;
#define pte_page(pte) (pfn_to_page(pte_pfn(pte)))
#define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr))
-#define pte_offset_map(dir,addr) (__pte_map(dir, KM_PTE0) + __pte_index(addr))
-#define pte_offset_map_nested(dir,addr) (__pte_map(dir, KM_PTE1) + __pte_index(addr))
-#define pte_unmap(pte) __pte_unmap(pte, KM_PTE0)
-#define pte_unmap_nested(pte) __pte_unmap(pte, KM_PTE1)
+#define pte_offset_map(dir,addr) (__pte_map(dir) + __pte_index(addr))
+#define pte_unmap(pte) __pte_unmap(pte)
#ifndef CONFIG_HIGHPTE
-#define __pte_map(dir,km) pmd_page_vaddr(*(dir))
-#define __pte_unmap(pte,km) do { } while (0)
+#define __pte_map(dir) pmd_page_vaddr(*(dir))
+#define __pte_unmap(pte) do { } while (0)
#else
-#define __pte_map(dir,km) ((pte_t *)kmap_atomic(pmd_page(*(dir)), km) + PTRS_PER_PTE)
-#define __pte_unmap(pte,km) kunmap_atomic((pte - PTRS_PER_PTE), km)
+#define __pte_map(dir) ((pte_t *)kmap_atomic(pmd_page(*(dir))) + PTRS_PER_PTE)
+#define __pte_unmap(pte) kunmap_atomic((pte - PTRS_PER_PTE))
#endif
#define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext)
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index e0cb6370ed14..3e97483abcf0 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -1075,13 +1075,15 @@ out:
}
#endif
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret;
+ unsigned long __user *datap = (unsigned long __user *) data;
switch (request) {
case PTRACE_PEEKUSR:
- ret = ptrace_read_user(child, addr, (unsigned long __user *)data);
+ ret = ptrace_read_user(child, addr, datap);
break;
case PTRACE_POKEUSR:
@@ -1089,34 +1091,34 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
case PTRACE_GETREGS:
- ret = ptrace_getregs(child, (void __user *)data);
+ ret = ptrace_getregs(child, datap);
break;
case PTRACE_SETREGS:
- ret = ptrace_setregs(child, (void __user *)data);
+ ret = ptrace_setregs(child, datap);
break;
case PTRACE_GETFPREGS:
- ret = ptrace_getfpregs(child, (void __user *)data);
+ ret = ptrace_getfpregs(child, datap);
break;
case PTRACE_SETFPREGS:
- ret = ptrace_setfpregs(child, (void __user *)data);
+ ret = ptrace_setfpregs(child, datap);
break;
#ifdef CONFIG_IWMMXT
case PTRACE_GETWMMXREGS:
- ret = ptrace_getwmmxregs(child, (void __user *)data);
+ ret = ptrace_getwmmxregs(child, datap);
break;
case PTRACE_SETWMMXREGS:
- ret = ptrace_setwmmxregs(child, (void __user *)data);
+ ret = ptrace_setwmmxregs(child, datap);
break;
#endif
case PTRACE_GET_THREAD_AREA:
ret = put_user(task_thread_info(child)->tp_value,
- (unsigned long __user *) data);
+ datap);
break;
case PTRACE_SET_SYSCALL:
@@ -1126,21 +1128,21 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
#ifdef CONFIG_CRUNCH
case PTRACE_GETCRUNCHREGS:
- ret = ptrace_getcrunchregs(child, (void __user *)data);
+ ret = ptrace_getcrunchregs(child, datap);
break;
case PTRACE_SETCRUNCHREGS:
- ret = ptrace_setcrunchregs(child, (void __user *)data);
+ ret = ptrace_setcrunchregs(child, datap);
break;
#endif
#ifdef CONFIG_VFP
case PTRACE_GETVFPREGS:
- ret = ptrace_getvfpregs(child, (void __user *)data);
+ ret = ptrace_getvfpregs(child, datap);
break;
case PTRACE_SETVFPREGS:
- ret = ptrace_setvfpregs(child, (void __user *)data);
+ ret = ptrace_setvfpregs(child, datap);
break;
#endif
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 851e8139ef9d..c015b684b4fe 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -109,7 +109,7 @@ config MACH_ONEARM
bool "Ajeco 1ARM Single Board Computer"
help
Select this if you are using Ajeco's 1ARM Single Board Computer.
- <http://www.ajeco.fi/products.htm>
+ <http://www.ajeco.fi/>
config ARCH_AT91RM9200DK
bool "Atmel AT91RM9200-DK Development board"
@@ -141,7 +141,7 @@ config MACH_CARMEVA
bool "Conitec ARM&EVA"
help
Select this if you are using Conitec's AT91RM9200-MCU-Module.
- <http://www.conitec.net/english/linuxboard.htm>
+ <http://www.conitec.net/english/linuxboard.php>
config MACH_ATEB9200
bool "Embest ATEB9200"
@@ -153,7 +153,7 @@ config MACH_KB9200
bool "KwikByte KB920x"
help
Select this if you are using KwikByte's KB920x board.
- <http://kwikbyte.com/KB9202_description_new.htm>
+ <http://www.kwikbyte.com/KB9202.html>
config MACH_PICOTUX2XX
bool "picotux 200"
@@ -375,6 +375,12 @@ config MACH_STAMP9G20
evaluation board.
<http://www.taskit.de/en/>
+config MACH_PCONTROL_G20
+ bool "PControl G20 CPU module"
+ help
+ Select this if you are using taskit's Stamp9G20 CPU module on this
+ carrier board, beeing the decentralized unit of a building automation
+ system; featuring nvram, eth-switch, iso-rs485, display, io
endif
if (ARCH_AT91SAM9260 || ARCH_AT91SAM9G20)
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 412b3a471a4b..821eb842795f 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -11,12 +11,12 @@ obj-$(CONFIG_AT91_PMC_UNIT) += clock.o
# CPU-specific support
obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200.o at91rm9200_time.o at91rm9200_devices.o
-obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
+obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o at91sam9_alt_reset.o
+obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o at91sam9_alt_reset.o
+obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o at91sam9_alt_reset.o
+obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_devices.o sam9_smc.o at91sam9_alt_reset.o
+obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o at91sam9_alt_reset.o
+obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o at91sam9_alt_reset.o
obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91CAP9) += at91cap9.o at91sam926x_time.o at91cap9_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT572D940HF) += at572d940hf.o at91sam926x_time.o at572d940hf_devices.o sam9_smc.o
@@ -65,6 +65,7 @@ obj-$(CONFIG_MACH_AT91SAM9G20EK) += board-sam9g20ek.o
obj-$(CONFIG_MACH_CPU9G20) += board-cpu9krea.o
obj-$(CONFIG_MACH_STAMP9G20) += board-stamp9g20.o
obj-$(CONFIG_MACH_PORTUXG20) += board-stamp9g20.o
+obj-$(CONFIG_MACH_PCONTROL_G20) += board-pcontrol-g20.o
# AT91SAM9260/AT91SAM9G20 board-specific support
obj-$(CONFIG_MACH_SNAPPER_9260) += board-snapper9260.o
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index 0894f1077be7..195208b30024 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -279,11 +279,6 @@ static struct at91_gpio_bank at91sam9260_gpio[] = {
}
};
-static void at91sam9260_reset(void)
-{
- at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
-}
-
static void at91sam9260_poweroff(void)
{
at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
@@ -327,7 +322,7 @@ void __init at91sam9260_initialize(unsigned long main_clock)
else
iotable_init(at91sam9260_sram_desc, ARRAY_SIZE(at91sam9260_sram_desc));
- at91_arch_reset = at91sam9260_reset;
+ at91_arch_reset = at91sam9_alt_reset;
pm_power_off = at91sam9260_poweroff;
at91_extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1)
| (1 << AT91SAM9260_ID_IRQ2);
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 4ecf37996c77..fcad88668504 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -257,11 +257,6 @@ static struct at91_gpio_bank at91sam9261_gpio[] = {
}
};
-static void at91sam9261_reset(void)
-{
- at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
-}
-
static void at91sam9261_poweroff(void)
{
at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
@@ -283,7 +278,7 @@ void __init at91sam9261_initialize(unsigned long main_clock)
iotable_init(at91sam9261_sram_desc, ARRAY_SIZE(at91sam9261_sram_desc));
- at91_arch_reset = at91sam9261_reset;
+ at91_arch_reset = at91sam9_alt_reset;
pm_power_off = at91sam9261_poweroff;
at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1)
| (1 << AT91SAM9261_ID_IRQ2);
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index 942792d630d8..249f900954d8 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -269,11 +269,6 @@ static struct at91_gpio_bank at91sam9263_gpio[] = {
}
};
-static void at91sam9263_reset(void)
-{
- at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
-}
-
static void at91sam9263_poweroff(void)
{
at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
@@ -289,7 +284,7 @@ void __init at91sam9263_initialize(unsigned long main_clock)
/* Map peripherals */
iotable_init(at91sam9263_io_desc, ARRAY_SIZE(at91sam9263_io_desc));
- at91_arch_reset = at91sam9263_reset;
+ at91_arch_reset = at91sam9_alt_reset;
pm_power_off = at91sam9263_poweroff;
at91_extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1);
diff --git a/arch/arm/mach-at91/at91sam9_alt_reset.S b/arch/arm/mach-at91/at91sam9_alt_reset.S
new file mode 100644
index 000000000000..e0256deb91fb
--- /dev/null
+++ b/arch/arm/mach-at91/at91sam9_alt_reset.S
@@ -0,0 +1,48 @@
+/*
+ * reset AT91SAM9G20 as per errata
+ *
+ * (C) BitBox Ltd 2010
+ *
+ * unless the SDRAM is cleanly shutdown before we hit the
+ * reset register it can be left driving the data bus and
+ * killing the chance of a subsequent boot from NAND
+ *
+ * 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/linkage.h>
+#include <asm/system.h>
+#include <mach/hardware.h>
+#include <mach/at91sam9_sdramc.h>
+#include <mach/at91_rstc.h>
+
+ .arm
+
+ .globl at91sam9_alt_reset
+
+at91sam9_alt_reset: mrc p15, 0, r0, c1, c0, 0
+ orr r0, r0, #CR_I
+ mcr p15, 0, r0, c1, c0, 0 @ enable I-cache
+
+ ldr r0, .at91_va_base_sdramc @ preload constants
+ ldr r1, .at91_va_base_rstc_cr
+
+ mov r2, #1
+ mov r3, #AT91_SDRAMC_LPCB_POWER_DOWN
+ ldr r4, =AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST
+
+ .balign 32 @ align to cache line
+
+ str r2, [r0, #AT91_SDRAMC_TR] @ disable SDRAM access
+ str r3, [r0, #AT91_SDRAMC_LPR] @ power down SDRAM
+ str r4, [r1] @ reset processor
+
+ b .
+
+.at91_va_base_sdramc:
+ .word AT91_VA_BASE_SYS + AT91_SDRAMC0
+.at91_va_base_rstc_cr:
+ .word AT91_VA_BASE_SYS + AT91_RSTC_CR
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 1276babf84d5..1e8f275c17f6 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -15,6 +15,7 @@
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/i2c-gpio.h>
+#include <linux/atmel-mci.h>
#include <linux/fb.h>
#include <video/atmel_lcdc.h>
@@ -25,6 +26,7 @@
#include <mach/at91sam9g45_matrix.h>
#include <mach/at91sam9_smc.h>
#include <mach/at_hdmac.h>
+#include <mach/atmel-mci.h>
#include "generic.h"
@@ -350,6 +352,169 @@ void __init at91_add_device_eth(struct at91_eth_data *data) {}
/* --------------------------------------------------------------------
+ * MMC / SD
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+static u64 mmc_dmamask = DMA_BIT_MASK(32);
+static struct mci_platform_data mmc0_data, mmc1_data;
+
+static struct resource mmc0_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_MCI0,
+ .end = AT91SAM9G45_BASE_MCI0 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_MCI0,
+ .end = AT91SAM9G45_ID_MCI0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_mmc0_device = {
+ .name = "atmel_mci",
+ .id = 0,
+ .dev = {
+ .dma_mask = &mmc_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &mmc0_data,
+ },
+ .resource = mmc0_resources,
+ .num_resources = ARRAY_SIZE(mmc0_resources),
+};
+
+static struct resource mmc1_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_MCI1,
+ .end = AT91SAM9G45_BASE_MCI1 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_MCI1,
+ .end = AT91SAM9G45_ID_MCI1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_mmc1_device = {
+ .name = "atmel_mci",
+ .id = 1,
+ .dev = {
+ .dma_mask = &mmc_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &mmc1_data,
+ },
+ .resource = mmc1_resources,
+ .num_resources = ARRAY_SIZE(mmc1_resources),
+};
+
+/* Consider only one slot : slot 0 */
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
+{
+
+ if (!data)
+ return;
+
+ /* Must have at least one usable slot */
+ if (!data->slot[0].bus_width)
+ return;
+
+#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
+ {
+ struct at_dma_slave *atslave;
+ struct mci_dma_data *alt_atslave;
+
+ alt_atslave = kzalloc(sizeof(struct mci_dma_data), GFP_KERNEL);
+ atslave = &alt_atslave->sdata;
+
+ /* DMA slave channel configuration */
+ atslave->dma_dev = &at_hdmac_device.dev;
+ atslave->reg_width = AT_DMA_SLAVE_WIDTH_32BIT;
+ atslave->cfg = ATC_FIFOCFG_HALFFIFO
+ | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW;
+ atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16;
+ if (mmc_id == 0) /* MCI0 */
+ atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI0)
+ | ATC_DST_PER(AT_DMA_ID_MCI0);
+
+ else /* MCI1 */
+ atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI1)
+ | ATC_DST_PER(AT_DMA_ID_MCI1);
+
+ data->dma_slave = alt_atslave;
+ }
+#endif
+
+
+ /* input/irq */
+ if (data->slot[0].detect_pin) {
+ at91_set_gpio_input(data->slot[0].detect_pin, 1);
+ at91_set_deglitch(data->slot[0].detect_pin, 1);
+ }
+ if (data->slot[0].wp_pin)
+ at91_set_gpio_input(data->slot[0].wp_pin, 1);
+
+ if (mmc_id == 0) { /* MCI0 */
+
+ /* CLK */
+ at91_set_A_periph(AT91_PIN_PA0, 0);
+
+ /* CMD */
+ at91_set_A_periph(AT91_PIN_PA1, 1);
+
+ /* DAT0, maybe DAT1..DAT3 and maybe DAT4..DAT7 */
+ at91_set_A_periph(AT91_PIN_PA2, 1);
+ if (data->slot[0].bus_width == 4) {
+ at91_set_A_periph(AT91_PIN_PA3, 1);
+ at91_set_A_periph(AT91_PIN_PA4, 1);
+ at91_set_A_periph(AT91_PIN_PA5, 1);
+ if (data->slot[0].bus_width == 8) {
+ at91_set_A_periph(AT91_PIN_PA6, 1);
+ at91_set_A_periph(AT91_PIN_PA7, 1);
+ at91_set_A_periph(AT91_PIN_PA8, 1);
+ at91_set_A_periph(AT91_PIN_PA9, 1);
+ }
+ }
+
+ mmc0_data = *data;
+ at91_clock_associate("mci0_clk", &at91sam9g45_mmc0_device.dev, "mci_clk");
+ platform_device_register(&at91sam9g45_mmc0_device);
+
+ } else { /* MCI1 */
+
+ /* CLK */
+ at91_set_A_periph(AT91_PIN_PA31, 0);
+
+ /* CMD */
+ at91_set_A_periph(AT91_PIN_PA22, 1);
+
+ /* DAT0, maybe DAT1..DAT3 and maybe DAT4..DAT7 */
+ at91_set_A_periph(AT91_PIN_PA23, 1);
+ if (data->slot[0].bus_width == 4) {
+ at91_set_A_periph(AT91_PIN_PA24, 1);
+ at91_set_A_periph(AT91_PIN_PA25, 1);
+ at91_set_A_periph(AT91_PIN_PA26, 1);
+ if (data->slot[0].bus_width == 8) {
+ at91_set_A_periph(AT91_PIN_PA27, 1);
+ at91_set_A_periph(AT91_PIN_PA28, 1);
+ at91_set_A_periph(AT91_PIN_PA29, 1);
+ at91_set_A_periph(AT91_PIN_PA30, 1);
+ }
+ }
+
+ mmc1_data = *data;
+ at91_clock_associate("mci1_clk", &at91sam9g45_mmc1_device.dev, "mci_clk");
+ platform_device_register(&at91sam9g45_mmc1_device);
+
+ }
+}
+#else
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
* NAND / SmartMedia
* -------------------------------------------------------------------- */
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index 211c5c14a1e6..6a9d24e5ed8e 100644
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ b/arch/arm/mach-at91/at91sam9rl.c
@@ -242,11 +242,6 @@ static struct at91_gpio_bank at91sam9rl_gpio[] = {
}
};
-static void at91sam9rl_reset(void)
-{
- at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
-}
-
static void at91sam9rl_poweroff(void)
{
at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
@@ -281,7 +276,7 @@ void __init at91sam9rl_initialize(unsigned long main_clock)
/* Map SRAM */
iotable_init(at91sam9rl_sram_desc, ARRAY_SIZE(at91sam9rl_sram_desc));
- at91_arch_reset = at91sam9rl_reset;
+ at91_arch_reset = at91sam9_alt_reset;
pm_power_off = at91sam9rl_poweroff;
at91_extern_irq = (1 << AT91SAM9RL_ID_IRQ0);
diff --git a/arch/arm/mach-at91/board-pcontrol-g20.c b/arch/arm/mach-at91/board-pcontrol-g20.c
new file mode 100644
index 000000000000..bba5a560e02b
--- /dev/null
+++ b/arch/arm/mach-at91/board-pcontrol-g20.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2010 Christian Glindkamp <christian.glindkamp@taskit.de>
+ * taskit GmbH
+ *
+ * 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
+ */
+/*
+ * copied and adjusted from board-stamp9g20.c
+ * by Peter Gsellmann <pgsellmann@portner-elektronik.at>
+ */
+
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/w1-gpio.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/board.h>
+#include <mach/at91sam9_smc.h>
+
+#include "sam9_smc.h"
+#include "generic.h"
+
+
+static void __init pcontrol_g20_map_io(void)
+{
+ /* Initialize processor: 18.432 MHz crystal */
+ at91sam9260_initialize(18432000);
+
+ /* DGBU on ttyS0. (Rx, Tx) only TTL -> JTAG connector X7 17,19 ) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback A2 */
+ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS
+ | ATMEL_UART_RTS);
+
+ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) isolated RS485 X5 */
+ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS
+ | ATMEL_UART_RTS);
+
+ /* USART2 on ttyS3. (Rx, Tx) 9bit-Bus Multidrop-mode X4 */
+ at91_register_uart(AT91SAM9260_ID_US4, 3, 0);
+
+ /* set serial console to ttyS0 (ie, DBGU) */
+ at91_set_serial_console(0);
+}
+
+
+static void __init init_irq(void)
+{
+ at91sam9260_init_interrupts(NULL);
+}
+
+
+/*
+ * NAND flash 512MiB 1,8V 8-bit, sector size 128 KiB
+ */
+static struct atmel_nand_data __initdata nand_data = {
+ .ale = 21,
+ .cle = 22,
+ .rdy_pin = AT91_PIN_PC13,
+ .enable_pin = AT91_PIN_PC14,
+};
+
+/*
+ * Bus timings; unit = 7.57ns
+ */
+static struct sam9_smc_config __initdata nand_smc_config = {
+ .ncs_read_setup = 0,
+ .nrd_setup = 2,
+ .ncs_write_setup = 0,
+ .nwe_setup = 2,
+
+ .ncs_read_pulse = 4,
+ .nrd_pulse = 4,
+ .ncs_write_pulse = 4,
+ .nwe_pulse = 4,
+
+ .read_cycle = 7,
+ .write_cycle = 7,
+
+ .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
+ | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
+ .tdf_cycles = 3,
+};
+
+static struct sam9_smc_config __initdata pcontrol_smc_config[2] = { {
+ .ncs_read_setup = 16,
+ .nrd_setup = 18,
+ .ncs_write_setup = 16,
+ .nwe_setup = 18,
+
+ .ncs_read_pulse = 63,
+ .nrd_pulse = 55,
+ .ncs_write_pulse = 63,
+ .nwe_pulse = 55,
+
+ .read_cycle = 127,
+ .write_cycle = 127,
+
+ .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
+ | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_SELECT
+ | AT91_SMC_DBW_8 | AT91_SMC_PS_4
+ | AT91_SMC_TDFMODE,
+ .tdf_cycles = 3,
+}, {
+ .ncs_read_setup = 0,
+ .nrd_setup = 0,
+ .ncs_write_setup = 0,
+ .nwe_setup = 1,
+
+ .ncs_read_pulse = 8,
+ .nrd_pulse = 8,
+ .ncs_write_pulse = 5,
+ .nwe_pulse = 4,
+
+ .read_cycle = 8,
+ .write_cycle = 7,
+
+ .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
+ | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_SELECT
+ | AT91_SMC_DBW_16 | AT91_SMC_PS_8
+ | AT91_SMC_TDFMODE,
+ .tdf_cycles = 1,
+} };
+
+static void __init add_device_nand(void)
+{
+ /* configure chip-select 3 (NAND) */
+ sam9_smc_configure(3, &nand_smc_config);
+ at91_add_device_nand(&nand_data);
+}
+
+
+static void __init add_device_pcontrol(void)
+{
+ /* configure chip-select 4 (IO compatible to 8051 X4 ) */
+ sam9_smc_configure(4, &pcontrol_smc_config[0]);
+ /* configure chip-select 7 (FerroRAM 256KiBx16bit MR2A16A D4 ) */
+ sam9_smc_configure(7, &pcontrol_smc_config[1]);
+}
+
+
+/*
+ * MCI (SD/MMC)
+ * det_pin, wp_pin and vcc_pin are not connected
+ */
+#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+static struct mci_platform_data __initdata mmc_data = {
+ .slot[0] = {
+ .bus_width = 4,
+ },
+};
+#else
+static struct at91_mmc_data __initdata mmc_data = {
+ .wire4 = 1,
+};
+#endif
+
+
+/*
+ * USB Host port
+ */
+static struct at91_usbh_data __initdata usbh_data = {
+ .ports = 2,
+};
+
+
+/*
+ * USB Device port
+ */
+static struct at91_udc_data __initdata pcontrol_g20_udc_data = {
+ .vbus_pin = AT91_PIN_PA22, /* Detect +5V bus voltage */
+ .pullup_pin = AT91_PIN_PA4, /* K-state, active low */
+};
+
+
+/*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata macb_data = {
+ .phy_irq_pin = AT91_PIN_PA28,
+ .is_rmii = 1,
+};
+
+
+/*
+ * I2C devices: eeprom and phy/switch
+ */
+static struct i2c_board_info __initdata pcontrol_g20_i2c_devices[] = {
+{ /* D7 address width=2, 8KiB */
+ I2C_BOARD_INFO("24c64", 0x50)
+}, { /* D8 address width=1, 1 byte has 32 bits! */
+ I2C_BOARD_INFO("lan9303", 0x0a)
+}, };
+
+
+/*
+ * LEDs
+ */
+static struct gpio_led pcontrol_g20_leds[] = {
+ {
+ .name = "LED1", /* red H5 */
+ .gpio = AT91_PIN_PB18,
+ .active_low = 1,
+ .default_trigger = "none", /* supervisor */
+ }, {
+ .name = "LED2", /* yellow H7 */
+ .gpio = AT91_PIN_PB19,
+ .active_low = 1,
+ .default_trigger = "mmc0", /* SD-card activity */
+ }, {
+ .name = "LED3", /* green H2 */
+ .gpio = AT91_PIN_PB20,
+ .active_low = 1,
+ .default_trigger = "heartbeat", /* blinky */
+ }, {
+ .name = "LED4", /* red H3 */
+ .gpio = AT91_PIN_PC6,
+ .active_low = 1,
+ .default_trigger = "none", /* connection lost */
+ }, {
+ .name = "LED5", /* yellow H6 */
+ .gpio = AT91_PIN_PC7,
+ .active_low = 1,
+ .default_trigger = "none", /* unsent data */
+ }, {
+ .name = "LED6", /* green H1 */
+ .gpio = AT91_PIN_PC9,
+ .active_low = 1,
+ .default_trigger = "none", /* snafu */
+ }
+};
+
+
+/*
+ * SPI devices
+ */
+static struct spi_board_info pcontrol_g20_spi_devices[] = {
+ {
+ .modalias = "spidev", /* HMI port X4 */
+ .chip_select = 1,
+ .max_speed_hz = 50 * 1000 * 1000,
+ .bus_num = 0,
+ }, {
+ .modalias = "spidev", /* piggyback A2 */
+ .chip_select = 0,
+ .max_speed_hz = 50 * 1000 * 1000,
+ .bus_num = 1,
+ },
+};
+
+
+/*
+ * Dallas 1-Wire DS2431
+ */
+static struct w1_gpio_platform_data w1_gpio_pdata = {
+ .pin = AT91_PIN_PA29,
+ .is_open_drain = 1,
+};
+
+static struct platform_device w1_device = {
+ .name = "w1-gpio",
+ .id = -1,
+ .dev.platform_data = &w1_gpio_pdata,
+};
+
+static void add_wire1(void)
+{
+ at91_set_GPIO_periph(w1_gpio_pdata.pin, 1);
+ at91_set_multi_drive(w1_gpio_pdata.pin, 1);
+ platform_device_register(&w1_device);
+}
+
+
+static void __init pcontrol_g20_board_init(void)
+{
+ at91_add_device_serial();
+ add_device_nand();
+#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+ at91_add_device_mci(0, &mmc_data);
+#else
+ at91_add_device_mmc(0, &mmc_data);
+#endif
+ at91_add_device_usbh(&usbh_data);
+ at91_add_device_eth(&macb_data);
+ at91_add_device_i2c(pcontrol_g20_i2c_devices,
+ ARRAY_SIZE(pcontrol_g20_i2c_devices));
+ add_wire1();
+ add_device_pcontrol();
+ at91_add_device_spi(pcontrol_g20_spi_devices,
+ ARRAY_SIZE(pcontrol_g20_spi_devices));
+ at91_add_device_udc(&pcontrol_g20_udc_data);
+ at91_gpio_leds(pcontrol_g20_leds,
+ ARRAY_SIZE(pcontrol_g20_leds));
+ /* piggyback A2 */
+ at91_set_gpio_output(AT91_PIN_PB31, 1);
+}
+
+
+MACHINE_START(PCONTROL_G20, "PControl G20")
+ /* Maintainer: pgsellmann@portner-elektronik.at */
+ .boot_params = AT91_SDRAM_BASE + 0x100,
+ .timer = &at91sam926x_timer,
+ .map_io = pcontrol_g20_map_io,
+ .init_irq = init_irq,
+ .init_machine = pcontrol_g20_board_init,
+MACHINE_END
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
index 7913984f6de9..86ff4b52db32 100644
--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
+++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
@@ -24,7 +24,9 @@
#include <linux/input.h>
#include <linux/leds.h>
#include <linux/clk.h>
+#include <linux/atmel-mci.h>
+#include <mach/hardware.h>
#include <video/atmel_lcdc.h>
#include <asm/setup.h>
@@ -98,6 +100,25 @@ static struct spi_board_info ek_spi_devices[] = {
/*
+ * MCI (SD/MMC)
+ */
+static struct mci_platform_data __initdata mci0_data = {
+ .slot[0] = {
+ .bus_width = 4,
+ .detect_pin = AT91_PIN_PD10,
+ },
+};
+
+static struct mci_platform_data __initdata mci1_data = {
+ .slot[0] = {
+ .bus_width = 4,
+ .detect_pin = AT91_PIN_PD11,
+ .wp_pin = AT91_PIN_PD29,
+ },
+};
+
+
+/*
* MACB Ethernet device
*/
static struct at91_eth_data __initdata ek_macb_data = {
@@ -380,6 +401,9 @@ static void __init ek_board_init(void)
at91_add_device_usba(&ek_usba_udc_data);
/* SPI */
at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+ /* MMC */
+ at91_add_device_mci(0, &mci0_data);
+ at91_add_device_mci(1, &mci1_data);
/* Ethernet */
at91_add_device_eth(&ek_macb_data);
/* NAND */
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index 65c3dc5ba0d0..0c66deb2db39 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -46,6 +46,9 @@ extern void __init at91_clock_associate(const char *id, struct device *dev, cons
extern void at91_irq_suspend(void);
extern void at91_irq_resume(void);
+/* reset */
+extern void at91sam9_alt_reset(void);
+
/* GPIO */
#define AT91RM9200_PQFP 3 /* AT91RM9200 PQFP package has 3 banks */
#define AT91RM9200_BGA 4 /* AT91RM9200 BGA package has 4 banks */
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 615668986480..dafbacc25eb1 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -258,16 +258,23 @@ static int at91_pm_enter(suspend_state_t state)
* NOTE: the Wait-for-Interrupt instruction needs to be
* in icache so no SDRAM accesses are needed until the
* wakeup IRQ occurs and self-refresh is terminated.
+ * For ARM 926 based chips, this requirement is weaker
+ * as at91sam9 can access a RAM in self-refresh mode.
*/
- asm("b 1f; .align 5; 1:");
- asm("mcr p15, 0, r0, c7, c10, 4"); /* drain write buffer */
+ asm volatile ( "mov r0, #0\n\t"
+ "b 1f\n\t"
+ ".align 5\n\t"
+ "1: mcr p15, 0, r0, c7, c10, 4\n\t"
+ : /* no output */
+ : /* no input */
+ : "r0");
saved_lpr = sdram_selfrefresh_enable();
- asm("mcr p15, 0, r0, c7, c0, 4"); /* wait for interrupt */
+ wait_for_interrupt_enable();
sdram_selfrefresh_disable(saved_lpr);
break;
case PM_SUSPEND_ON:
- asm("mcr p15, 0, r0, c7, c0, 4"); /* wait for interrupt */
+ cpu_do_idle();
break;
default:
diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h
index 8c87d0c1b8f8..ce9a20699111 100644
--- a/arch/arm/mach-at91/pm.h
+++ b/arch/arm/mach-at91/pm.h
@@ -21,6 +21,8 @@ static inline u32 sdram_selfrefresh_enable(void)
}
#define sdram_selfrefresh_disable(saved_lpr) at91_sys_write(AT91_SDRAMC_LPR, saved_lpr)
+#define wait_for_interrupt_enable() asm volatile ("mcr p15, 0, %0, c7, c0, 4" \
+ : : "r" (0))
#elif defined(CONFIG_ARCH_AT91CAP9)
#include <mach/at91cap9_ddrsdr.h>
@@ -38,6 +40,7 @@ static inline u32 sdram_selfrefresh_enable(void)
}
#define sdram_selfrefresh_disable(saved_lpr) at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr)
+#define wait_for_interrupt_enable() cpu_do_idle()
#elif defined(CONFIG_ARCH_AT91SAM9G45)
#include <mach/at91sam9_ddrsdr.h>
@@ -74,6 +77,7 @@ static inline u32 sdram_selfrefresh_enable(void)
at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0); \
at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); \
} while (0)
+#define wait_for_interrupt_enable() cpu_do_idle()
#else
#include <mach/at91sam9_sdramc.h>
@@ -98,5 +102,6 @@ static inline u32 sdram_selfrefresh_enable(void)
}
#define sdram_selfrefresh_disable(saved_lpr) at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr)
+#define wait_for_interrupt_enable() cpu_do_idle()
#endif
diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S
index b6b00a1f6125..f7922a436172 100644
--- a/arch/arm/mach-at91/pm_slowclock.S
+++ b/arch/arm/mach-at91/pm_slowclock.S
@@ -124,6 +124,7 @@ ENTRY(at91_slow_clock)
ldr r5, .at91_va_base_ramc1
/* Drain write buffer */
+ mov r0, #0
mcr p15, 0, r0, c7, c10, 4
#ifdef CONFIG_ARCH_AT91RM9200
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig
index 71f90f864748..b77b860b36d7 100644
--- a/arch/arm/mach-davinci/Kconfig
+++ b/arch/arm/mach-davinci/Kconfig
@@ -20,23 +20,23 @@ config ARCH_DAVINCI_DM644x
select ARCH_DAVINCI_DMx
config ARCH_DAVINCI_DM355
- bool "DaVinci 355 based system"
+ bool "DaVinci 355 based system"
select AINTC
select ARCH_DAVINCI_DMx
config ARCH_DAVINCI_DM646x
- bool "DaVinci 646x based system"
+ bool "DaVinci 646x based system"
select AINTC
select ARCH_DAVINCI_DMx
config ARCH_DAVINCI_DA830
- bool "DA830/OMAP-L137 based system"
+ bool "DA830/OMAP-L137/AM17x based system"
select CP_INTC
select ARCH_DAVINCI_DA8XX
select CPU_DCACHE_WRITETHROUGH # needed on silicon revs 1.0, 1.1
config ARCH_DAVINCI_DA850
- bool "DA850/OMAP-L138 based system"
+ bool "DA850/OMAP-L138/AM18x based system"
select CP_INTC
select ARCH_DAVINCI_DA8XX
select ARCH_HAS_CPUFREQ
@@ -115,21 +115,21 @@ config MACH_DAVINCI_DM365_EVM
for development is a DM365 EVM
config MACH_DAVINCI_DA830_EVM
- bool "TI DA830/OMAP-L137 Reference Platform"
+ bool "TI DA830/OMAP-L137/AM17x Reference Platform"
default ARCH_DAVINCI_DA830
depends on ARCH_DAVINCI_DA830
select GPIO_PCF857X
help
- Say Y here to select the TI DA830/OMAP-L137 Evaluation Module.
+ Say Y here to select the TI DA830/OMAP-L137/AM17x Evaluation Module.
choice
- prompt "Select DA830/OMAP-L137 UI board peripheral"
+ prompt "Select DA830/OMAP-L137/AM17x UI board peripheral"
depends on MACH_DAVINCI_DA830_EVM
help
- The presence of UI card on the DA830/OMAP-L137 EVM is detected
- automatically based on successful probe of the I2C based GPIO
- expander on that board. This option selected in this menu has
- an effect only in case of a successful UI card detection.
+ The presence of UI card on the DA830/OMAP-L137/AM17x EVM is
+ detected automatically based on successful probe of the I2C
+ based GPIO expander on that board. This option selected in this
+ menu has an effect only in case of a successful UI card detection.
config DA830_UI_LCD
bool "LCD"
@@ -140,23 +140,23 @@ config DA830_UI_LCD
config DA830_UI_NAND
bool "NAND flash"
help
- Say Y here to use the NAND flash. Do not forget to setup
+ Say Y here to use the NAND flash. Do not forget to setup
the switch correctly.
endchoice
config MACH_DAVINCI_DA850_EVM
- bool "TI DA850/OMAP-L138 Reference Platform"
+ bool "TI DA850/OMAP-L138/AM18x Reference Platform"
default ARCH_DAVINCI_DA850
depends on ARCH_DAVINCI_DA850
select GPIO_PCA953X
help
- Say Y here to select the TI DA850/OMAP-L138 Evaluation Module.
+ Say Y here to select the TI DA850/OMAP-L138/AM18x Evaluation Module.
choice
prompt "Select peripherals connected to expander on UI board"
depends on MACH_DAVINCI_DA850_EVM
help
- The presence of User Interface (UI) card on the DA850/OMAP-L138
+ The presence of User Interface (UI) card on the DA850/OMAP-L138/AM18x
EVM is detected automatically based on successful probe of the I2C
based GPIO expander on that card. This option selected in this
menu has an effect only in case of a successful UI card detection.
@@ -165,13 +165,13 @@ config DA850_UI_NONE
bool "No peripheral is enabled"
help
Say Y if you do not want to enable any of the peripherals connected
- to TCA6416 expander on DA850/OMAP-L138 EVM UI card
+ to TCA6416 expander on DA850/OMAP-L138/AM18x EVM UI card
config DA850_UI_RMII
bool "RMII Ethernet PHY"
help
- Say Y if you want to use the RMII PHY on the DA850/OMAP-L138 EVM.
- This PHY is found on the UI daughter card that is supplied with
+ Say Y if you want to use the RMII PHY on the DA850/OMAP-L138/AM18x
+ EVM. This PHY is found on the UI daughter card that is supplied with
the EVM.
NOTE: Please take care while choosing this option, MII PHY will
not be functional if RMII mode is selected.
@@ -185,6 +185,22 @@ config MACH_TNETV107X
help
Say Y here to select the TI TNETV107X Evaluation Module.
+config MACH_MITYOMAPL138
+ bool "Critical Link MityDSP-L138/MityARM-1808 SoM"
+ depends on ARCH_DAVINCI_DA850
+ help
+ Say Y here to select the Critical Link MityDSP-L138/MityARM-1808
+ System on Module. Information on this SoM may be found at
+ http://www.mitydsp.com
+
+config MACH_OMAPL138_HAWKBOARD
+ bool "TI AM1808 / OMAPL-138 Hawkboard platform"
+ depends on ARCH_DAVINCI_DA850
+ help
+ Say Y here to select the TI AM1808 / OMAPL-138 Hawkboard platform .
+ Information of this board may be found at
+ http://www.hawkboard.org/
+
config DAVINCI_MUX
bool "DAVINCI multiplexing support"
depends on ARCH_DAVINCI
@@ -195,20 +211,20 @@ config DAVINCI_MUX
say Y.
config DAVINCI_MUX_DEBUG
- bool "Multiplexing debug output"
- depends on DAVINCI_MUX
- help
- Makes the multiplexing functions print out a lot of debug info.
- This is useful if you want to find out the correct values of the
- multiplexing registers.
+ bool "Multiplexing debug output"
+ depends on DAVINCI_MUX
+ help
+ Makes the multiplexing functions print out a lot of debug info.
+ This is useful if you want to find out the correct values of the
+ multiplexing registers.
config DAVINCI_MUX_WARNINGS
- bool "Warn about pins the bootloader didn't set up"
- depends on DAVINCI_MUX
- help
- Choose Y here to warn whenever driver initialization logic needs
- to change the pin multiplexing setup. When there are no warnings
- printed, it's safe to deselect DAVINCI_MUX for your product.
+ bool "Warn about pins the bootloader didn't set up"
+ depends on DAVINCI_MUX
+ help
+ Choose Y here to warn whenever driver initialization logic needs
+ to change the pin multiplexing setup. When there are no warnings
+ printed, it's safe to deselect DAVINCI_MUX for your product.
config DAVINCI_RESET_CLOCKS
bool "Reset unused clocks during boot"
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index eab4c0fd667a..0b87a1ca2bb3 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -5,7 +5,7 @@
# Common objects
obj-y := time.o clock.o serial.o io.o psc.o \
- gpio.o dma.o usb.o common.o sram.o
+ gpio.o dma.o usb.o common.o sram.o aemif.o
obj-$(CONFIG_DAVINCI_MUX) += mux.o
@@ -33,6 +33,8 @@ obj-$(CONFIG_MACH_DAVINCI_DM365_EVM) += board-dm365-evm.o
obj-$(CONFIG_MACH_DAVINCI_DA830_EVM) += board-da830-evm.o
obj-$(CONFIG_MACH_DAVINCI_DA850_EVM) += board-da850-evm.o
obj-$(CONFIG_MACH_TNETV107X) += board-tnetv107x-evm.o
+obj-$(CONFIG_MACH_MITYOMAPL138) += board-mityomapl138.o
+obj-$(CONFIG_MACH_OMAPL138_HAWKBOARD) += board-omapl138-hawk.o
# Power Management
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
diff --git a/arch/arm/mach-davinci/aemif.c b/arch/arm/mach-davinci/aemif.c
new file mode 100644
index 000000000000..9c3f500fc12f
--- /dev/null
+++ b/arch/arm/mach-davinci/aemif.c
@@ -0,0 +1,133 @@
+/*
+ * AEMIF support for DaVinci SoCs
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated. http://www.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/time.h>
+
+#include <mach/aemif.h>
+
+/* Timing value configuration */
+
+#define TA(x) ((x) << 2)
+#define RHOLD(x) ((x) << 4)
+#define RSTROBE(x) ((x) << 7)
+#define RSETUP(x) ((x) << 13)
+#define WHOLD(x) ((x) << 17)
+#define WSTROBE(x) ((x) << 20)
+#define WSETUP(x) ((x) << 26)
+
+#define TA_MAX 0x3
+#define RHOLD_MAX 0x7
+#define RSTROBE_MAX 0x3f
+#define RSETUP_MAX 0xf
+#define WHOLD_MAX 0x7
+#define WSTROBE_MAX 0x3f
+#define WSETUP_MAX 0xf
+
+#define TIMING_MASK (TA(TA_MAX) | \
+ RHOLD(RHOLD_MAX) | \
+ RSTROBE(RSTROBE_MAX) | \
+ RSETUP(RSETUP_MAX) | \
+ WHOLD(WHOLD_MAX) | \
+ WSTROBE(WSTROBE_MAX) | \
+ WSETUP(WSETUP_MAX))
+
+/*
+ * aemif_calc_rate - calculate timing data.
+ * @wanted: The cycle time needed in nanoseconds.
+ * @clk: The input clock rate in kHz.
+ * @max: The maximum divider value that can be programmed.
+ *
+ * On success, returns the calculated timing value minus 1 for easy
+ * programming into AEMIF timing registers, else negative errno.
+ */
+static int aemif_calc_rate(int wanted, unsigned long clk, int max)
+{
+ int result;
+
+ result = DIV_ROUND_UP((wanted * clk), NSEC_PER_MSEC) - 1;
+
+ pr_debug("%s: result %d from %ld, %d\n", __func__, result, clk, wanted);
+
+ /* It is generally OK to have a more relaxed timing than requested... */
+ if (result < 0)
+ result = 0;
+
+ /* ... But configuring tighter timings is not an option. */
+ else if (result > max)
+ result = -EINVAL;
+
+ return result;
+}
+
+/**
+ * davinci_aemif_setup_timing - setup timing values for a given AEMIF interface
+ * @t: timing values to be progammed
+ * @base: The virtual base address of the AEMIF interface
+ * @cs: chip-select to program the timing values for
+ *
+ * This function programs the given timing values (in real clock) into the
+ * AEMIF registers taking the AEMIF clock into account.
+ *
+ * This function does not use any locking while programming the AEMIF
+ * because it is expected that there is only one user of a given
+ * chip-select.
+ *
+ * Returns 0 on success, else negative errno.
+ */
+int davinci_aemif_setup_timing(struct davinci_aemif_timing *t,
+ void __iomem *base, unsigned cs)
+{
+ unsigned set, val;
+ unsigned ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
+ unsigned offset = A1CR_OFFSET + cs * 4;
+ struct clk *aemif_clk;
+ unsigned long clkrate;
+
+ if (!t)
+ return 0; /* Nothing to do */
+
+ aemif_clk = clk_get(NULL, "aemif");
+ if (IS_ERR(aemif_clk))
+ return PTR_ERR(aemif_clk);
+
+ clkrate = clk_get_rate(aemif_clk);
+
+ clkrate /= 1000; /* turn clock into kHz for ease of use */
+
+ ta = aemif_calc_rate(t->ta, clkrate, TA_MAX);
+ rhold = aemif_calc_rate(t->rhold, clkrate, RHOLD_MAX);
+ rstrobe = aemif_calc_rate(t->rstrobe, clkrate, RSTROBE_MAX);
+ rsetup = aemif_calc_rate(t->rsetup, clkrate, RSETUP_MAX);
+ whold = aemif_calc_rate(t->whold, clkrate, WHOLD_MAX);
+ wstrobe = aemif_calc_rate(t->wstrobe, clkrate, WSTROBE_MAX);
+ wsetup = aemif_calc_rate(t->wsetup, clkrate, WSETUP_MAX);
+
+ if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
+ whold < 0 || wstrobe < 0 || wsetup < 0) {
+ pr_err("%s: cannot get suitable timings\n", __func__);
+ return -EINVAL;
+ }
+
+ set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
+ WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
+
+ val = __raw_readl(base + offset);
+ val &= ~TIMING_MASK;
+ val |= set;
+ __raw_writel(val, base + offset);
+
+ return 0;
+}
+EXPORT_SYMBOL(davinci_aemif_setup_timing);
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index 7f3cdbfc0fbb..b52a3a1abd94 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -29,10 +29,9 @@
#include <mach/nand.h>
#include <mach/da8xx.h>
#include <mach/usb.h>
+#include <mach/aemif.h>
-#define DA830_EVM_PHY_MASK 0x0
-#define DA830_EVM_MDIO_FREQUENCY 2200000 /* PHY bus frequency */
-
+#define DA830_EVM_PHY_ID ""
/*
* USB1 VBUS is controlled by GPIO1[15], over-current is reported on GPIO2[4].
*/
@@ -360,6 +359,16 @@ static struct nand_bbt_descr da830_evm_nand_bbt_mirror_descr = {
.pattern = da830_evm_nand_mirror_pattern
};
+static struct davinci_aemif_timing da830_evm_nandflash_timing = {
+ .wsetup = 24,
+ .wstrobe = 21,
+ .whold = 14,
+ .rsetup = 19,
+ .rstrobe = 50,
+ .rhold = 0,
+ .ta = 20,
+};
+
static struct davinci_nand_pdata da830_evm_nand_pdata = {
.parts = da830_evm_nand_partitions,
.nr_parts = ARRAY_SIZE(da830_evm_nand_partitions),
@@ -368,6 +377,7 @@ static struct davinci_nand_pdata da830_evm_nand_pdata = {
.options = NAND_USE_FLASH_BBT,
.bbt_td = &da830_evm_nand_bbt_main_descr,
.bbt_md = &da830_evm_nand_bbt_mirror_descr,
+ .timing = &da830_evm_nandflash_timing,
};
static struct resource da830_evm_nand_resources[] = {
@@ -546,9 +556,8 @@ static __init void da830_evm_init(void)
da830_evm_usb_init();
- soc_info->emac_pdata->phy_mask = DA830_EVM_PHY_MASK;
- soc_info->emac_pdata->mdio_max_freq = DA830_EVM_MDIO_FREQUENCY;
soc_info->emac_pdata->rmii_en = 1;
+ soc_info->emac_pdata->phy_id = DA830_EVM_PHY_ID;
ret = davinci_cfg_reg_list(da830_cpgmac_pins);
if (ret)
@@ -586,6 +595,9 @@ static __init void da830_evm_init(void)
#ifdef CONFIG_SERIAL_8250_CONSOLE
static int __init da830_evm_console_init(void)
{
+ if (!machine_is_davinci_da830_evm())
+ return 0;
+
return add_preferred_console("ttyS", 2, "115200");
}
console_initcall(da830_evm_console_init);
@@ -596,7 +608,7 @@ static void __init da830_evm_map_io(void)
da830_init();
}
-MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP-L137 EVM")
+MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP-L137/AM17x EVM")
.boot_params = (DA8XX_DDR_BASE + 0x100),
.map_io = da830_evm_map_io,
.init_irq = cp_intc_init,
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index b26f5cbfce3e..c6e11c682e4c 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -26,7 +26,6 @@
#include <linux/mtd/physmap.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/tps6507x.h>
-#include <linux/mfd/tps6507x.h>
#include <linux/input/tps6507x-ts.h>
#include <asm/mach-types.h>
@@ -36,10 +35,9 @@
#include <mach/da8xx.h>
#include <mach/nand.h>
#include <mach/mux.h>
+#include <mach/aemif.h>
-#define DA850_EVM_PHY_MASK 0x1
-#define DA850_EVM_MDIO_FREQUENCY 2200000 /* PHY bus frequency */
-
+#define DA850_EVM_PHY_ID "0:00"
#define DA850_LCD_PWR_PIN GPIO_TO_PIN(2, 8)
#define DA850_LCD_BL_PIN GPIO_TO_PIN(2, 15)
@@ -110,7 +108,7 @@ static struct platform_device da850_pm_device = {
* to boot, using TI's tools to install the secondary boot loader
* (UBL) and U-Boot.
*/
-struct mtd_partition da850_evm_nandflash_partition[] = {
+static struct mtd_partition da850_evm_nandflash_partition[] = {
{
.name = "u-boot env",
.offset = 0,
@@ -143,12 +141,23 @@ struct mtd_partition da850_evm_nandflash_partition[] = {
},
};
+static struct davinci_aemif_timing da850_evm_nandflash_timing = {
+ .wsetup = 24,
+ .wstrobe = 21,
+ .whold = 14,
+ .rsetup = 19,
+ .rstrobe = 50,
+ .rhold = 0,
+ .ta = 20,
+};
+
static struct davinci_nand_pdata da850_evm_nandflash_data = {
.parts = da850_evm_nandflash_partition,
.nr_parts = ARRAY_SIZE(da850_evm_nandflash_partition),
.ecc_mode = NAND_ECC_HW,
.ecc_bits = 4,
.options = NAND_USE_FLASH_BBT,
+ .timing = &da850_evm_nandflash_timing,
};
static struct resource da850_evm_nandflash_resource[] = {
@@ -196,6 +205,30 @@ static void __init da850_evm_init_nor(void)
iounmap(aemif_addr);
}
+static const short da850_evm_nand_pins[] = {
+ DA850_EMA_D_0, DA850_EMA_D_1, DA850_EMA_D_2, DA850_EMA_D_3,
+ DA850_EMA_D_4, DA850_EMA_D_5, DA850_EMA_D_6, DA850_EMA_D_7,
+ DA850_EMA_A_1, DA850_EMA_A_2, DA850_NEMA_CS_3, DA850_NEMA_CS_4,
+ DA850_NEMA_WE, DA850_NEMA_OE,
+ -1
+};
+
+static const short da850_evm_nor_pins[] = {
+ DA850_EMA_BA_1, DA850_EMA_CLK, DA850_EMA_WAIT_1, DA850_NEMA_CS_2,
+ DA850_NEMA_WE, DA850_NEMA_OE, DA850_EMA_D_0, DA850_EMA_D_1,
+ DA850_EMA_D_2, DA850_EMA_D_3, DA850_EMA_D_4, DA850_EMA_D_5,
+ DA850_EMA_D_6, DA850_EMA_D_7, DA850_EMA_D_8, DA850_EMA_D_9,
+ DA850_EMA_D_10, DA850_EMA_D_11, DA850_EMA_D_12, DA850_EMA_D_13,
+ DA850_EMA_D_14, DA850_EMA_D_15, DA850_EMA_A_0, DA850_EMA_A_1,
+ DA850_EMA_A_2, DA850_EMA_A_3, DA850_EMA_A_4, DA850_EMA_A_5,
+ DA850_EMA_A_6, DA850_EMA_A_7, DA850_EMA_A_8, DA850_EMA_A_9,
+ DA850_EMA_A_10, DA850_EMA_A_11, DA850_EMA_A_12, DA850_EMA_A_13,
+ DA850_EMA_A_14, DA850_EMA_A_15, DA850_EMA_A_16, DA850_EMA_A_17,
+ DA850_EMA_A_18, DA850_EMA_A_19, DA850_EMA_A_20, DA850_EMA_A_21,
+ DA850_EMA_A_22, DA850_EMA_A_23,
+ -1
+};
+
static u32 ui_card_detected;
#if defined(CONFIG_MMC_DAVINCI) || \
@@ -205,17 +238,17 @@ static u32 ui_card_detected;
#define HAS_MMC 0
#endif
-static __init void da850_evm_setup_nor_nand(void)
+static inline void da850_evm_setup_nor_nand(void)
{
int ret = 0;
if (ui_card_detected & !HAS_MMC) {
- ret = davinci_cfg_reg_list(da850_nand_pins);
+ ret = davinci_cfg_reg_list(da850_evm_nand_pins);
if (ret)
pr_warning("da850_evm_init: nand mux setup failed: "
"%d\n", ret);
- ret = davinci_cfg_reg_list(da850_nor_pins);
+ ret = davinci_cfg_reg_list(da850_evm_nor_pins);
if (ret)
pr_warning("da850_evm_init: nor mux setup failed: %d\n",
ret);
@@ -406,7 +439,7 @@ static int da850_lcd_hw_init(void)
/* TPS65070 voltage regulator support */
/* 3.3V */
-struct regulator_consumer_supply tps65070_dcdc1_consumers[] = {
+static struct regulator_consumer_supply tps65070_dcdc1_consumers[] = {
{
.supply = "usb0_vdda33",
},
@@ -416,7 +449,7 @@ struct regulator_consumer_supply tps65070_dcdc1_consumers[] = {
};
/* 3.3V or 1.8V */
-struct regulator_consumer_supply tps65070_dcdc2_consumers[] = {
+static struct regulator_consumer_supply tps65070_dcdc2_consumers[] = {
{
.supply = "dvdd3318_a",
},
@@ -429,14 +462,14 @@ struct regulator_consumer_supply tps65070_dcdc2_consumers[] = {
};
/* 1.2V */
-struct regulator_consumer_supply tps65070_dcdc3_consumers[] = {
+static struct regulator_consumer_supply tps65070_dcdc3_consumers[] = {
{
.supply = "cvdd",
},
};
/* 1.8V LDO */
-struct regulator_consumer_supply tps65070_ldo1_consumers[] = {
+static struct regulator_consumer_supply tps65070_ldo1_consumers[] = {
{
.supply = "sata_vddr",
},
@@ -452,7 +485,7 @@ struct regulator_consumer_supply tps65070_ldo1_consumers[] = {
};
/* 1.2V LDO */
-struct regulator_consumer_supply tps65070_ldo2_consumers[] = {
+static struct regulator_consumer_supply tps65070_ldo2_consumers[] = {
{
.supply = "sata_vdd",
},
@@ -475,7 +508,7 @@ static struct tps6507x_reg_platform_data tps6507x_platform_data = {
.defdcdc_default = true,
};
-struct regulator_init_data tps65070_regulator_data[] = {
+static struct regulator_init_data tps65070_regulator_data[] = {
/* dcdc1 */
{
.constraints = {
@@ -576,6 +609,23 @@ static const short da850_evm_lcdc_pins[] = {
-1
};
+static const short da850_evm_mii_pins[] = {
+ DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
+ DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
+ DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
+ DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
+ DA850_MDIO_D,
+ -1
+};
+
+static const short da850_evm_rmii_pins[] = {
+ DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
+ DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1,
+ DA850_RMII_RXER, DA850_RMII_MHZ_50_CLK, DA850_MDIO_CLK,
+ DA850_MDIO_D,
+ -1
+};
+
static int __init da850_evm_config_emac(void)
{
void __iomem *cfg_chip3_base;
@@ -593,12 +643,12 @@ static int __init da850_evm_config_emac(void)
if (rmii_en) {
val |= BIT(8);
- ret = davinci_cfg_reg_list(da850_rmii_pins);
+ ret = davinci_cfg_reg_list(da850_evm_rmii_pins);
pr_info("EMAC: RMII PHY configured, MII PHY will not be"
" functional\n");
} else {
val &= ~BIT(8);
- ret = davinci_cfg_reg_list(da850_cpgmac_pins);
+ ret = davinci_cfg_reg_list(da850_evm_mii_pins);
pr_info("EMAC: MII PHY configured, RMII PHY will not be"
" functional\n");
}
@@ -625,8 +675,7 @@ static int __init da850_evm_config_emac(void)
/* Enable/Disable MII MDIO clock */
gpio_direction_output(DA850_MII_MDIO_CLKEN_PIN, rmii_en);
- soc_info->emac_pdata->phy_mask = DA850_EVM_PHY_MASK;
- soc_info->emac_pdata->mdio_max_freq = DA850_EVM_MDIO_FREQUENCY;
+ soc_info->emac_pdata->phy_id = DA850_EVM_PHY_ID;
ret = da8xx_register_emac();
if (ret)
@@ -787,7 +836,7 @@ static __init void da850_evm_init(void)
if (ret)
pr_warning("da850_evm_init: rtc setup failed: %d\n", ret);
- ret = da850_register_cpufreq();
+ ret = da850_register_cpufreq("pll0_sysclk3");
if (ret)
pr_warning("da850_evm_init: cpufreq registration failed: %d\n",
ret);
@@ -806,6 +855,9 @@ static __init void da850_evm_init(void)
#ifdef CONFIG_SERIAL_8250_CONSOLE
static int __init da850_evm_console_init(void)
{
+ if (!machine_is_davinci_da850_evm())
+ return 0;
+
return add_preferred_console("ttyS", 2, "115200");
}
console_initcall(da850_evm_console_init);
@@ -816,7 +868,7 @@ static void __init da850_evm_map_io(void)
da850_init();
}
-MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138 EVM")
+MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138/AM18x EVM")
.boot_params = (DA8XX_DDR_BASE + 0x100),
.map_io = da850_evm_map_io,
.init_irq = cp_intc_init,
diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c
index 944a0cbaf5cb..c67f684ee3e5 100644
--- a/arch/arm/mach-davinci/board-dm365-evm.c
+++ b/arch/arm/mach-davinci/board-dm365-evm.c
@@ -54,9 +54,7 @@ static inline int have_tvp7002(void)
return 0;
}
-#define DM365_EVM_PHY_MASK (0x2)
-#define DM365_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
-
+#define DM365_EVM_PHY_ID "0:01"
/*
* A MAX-II CPLD is used for various board control functions.
*/
@@ -175,7 +173,9 @@ static struct at24_platform_data eeprom_info = {
.context = (void *)0x7f00,
};
-static struct snd_platform_data dm365_evm_snd_data;
+static struct snd_platform_data dm365_evm_snd_data = {
+ .asp_chan_q = EVENTQ_3,
+};
static struct i2c_board_info i2c_info[] = {
{
@@ -533,8 +533,7 @@ fail:
/* ... and ENET ... */
dm365evm_emac_configure();
- soc_info->emac_pdata->phy_mask = DM365_EVM_PHY_MASK;
- soc_info->emac_pdata->mdio_max_freq = DM365_EVM_MDIO_FREQUENCY;
+ soc_info->emac_pdata->phy_id = DM365_EVM_PHY_ID;
resets &= ~BIT(3);
/* ... and AIC33 */
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index d59fba15ba8d..0ca90b834586 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -37,10 +37,9 @@
#include <mach/nand.h>
#include <mach/mmc.h>
#include <mach/usb.h>
+#include <mach/aemif.h>
-#define DM644X_EVM_PHY_MASK (0x2)
-#define DM644X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
-
+#define DM644X_EVM_PHY_ID "0:01"
#define LXT971_PHY_ID (0x001378e2)
#define LXT971_PHY_MASK (0xfffffff0)
@@ -137,11 +136,22 @@ static struct mtd_partition davinci_evm_nandflash_partition[] = {
*/
};
+static struct davinci_aemif_timing davinci_evm_nandflash_timing = {
+ .wsetup = 20,
+ .wstrobe = 40,
+ .whold = 20,
+ .rsetup = 10,
+ .rstrobe = 40,
+ .rhold = 10,
+ .ta = 40,
+};
+
static struct davinci_nand_pdata davinci_evm_nandflash_data = {
.parts = davinci_evm_nandflash_partition,
.nr_parts = ARRAY_SIZE(davinci_evm_nandflash_partition),
.ecc_mode = NAND_ECC_HW,
.options = NAND_USE_FLASH_BBT,
+ .timing = &davinci_evm_nandflash_timing,
};
static struct resource davinci_evm_nandflash_resource[] = {
@@ -695,9 +705,7 @@ static __init void davinci_evm_init(void)
davinci_serial_init(&uart_config);
dm644x_init_asp(&dm644x_evm_snd_data);
- soc_info->emac_pdata->phy_mask = DM644X_EVM_PHY_MASK;
- soc_info->emac_pdata->mdio_max_freq = DM644X_EVM_MDIO_FREQUENCY;
-
+ soc_info->emac_pdata->phy_id = DM644X_EVM_PHY_ID;
/* Register the fixup for PHY on DaVinci */
phy_register_fixup_for_uid(LXT971_PHY_ID, LXT971_PHY_MASK,
davinci_phy_fixup);
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
index 6890488fb92b..f6ac9ba74878 100644
--- a/arch/arm/mach-davinci/board-dm646x-evm.c
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -42,6 +42,7 @@
#include <mach/nand.h>
#include <mach/clock.h>
#include <mach/cdce949.h>
+#include <mach/aemif.h>
#include "clock.h"
@@ -71,6 +72,16 @@ static struct mtd_partition davinci_nand_partitions[] = {
}
};
+static struct davinci_aemif_timing dm6467tevm_nandflash_timing = {
+ .wsetup = 29,
+ .wstrobe = 24,
+ .whold = 14,
+ .rsetup = 19,
+ .rstrobe = 33,
+ .rhold = 0,
+ .ta = 29,
+};
+
static struct davinci_nand_pdata davinci_nand_data = {
.mask_cle = 0x80000,
.mask_ale = 0x40000,
@@ -718,9 +729,7 @@ static struct davinci_uart_config uart_config __initdata = {
.enabled_uarts = (1 << 0),
};
-#define DM646X_EVM_PHY_MASK (0x2)
-#define DM646X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
-
+#define DM646X_EVM_PHY_ID "0:01"
/*
* The following EDMA channels/slots are not being used by drivers (for
* example: Timer, GPIO, UART events etc) on dm646x, hence they are being
@@ -763,6 +772,9 @@ static __init void evm_init(void)
dm646x_init_mcasp0(&dm646x_evm_snd_data[0]);
dm646x_init_mcasp1(&dm646x_evm_snd_data[1]);
+ if (machine_is_davinci_dm6467tevm())
+ davinci_nand_data.timing = &dm6467tevm_nandflash_timing;
+
platform_device_register(&davinci_nand_device);
dm646x_init_edma(dm646x_edma_rsv);
@@ -770,8 +782,7 @@ static __init void evm_init(void)
if (HAS_ATA)
davinci_init_ide();
- soc_info->emac_pdata->phy_mask = DM646X_EVM_PHY_MASK;
- soc_info->emac_pdata->mdio_max_freq = DM646X_EVM_MDIO_FREQUENCY;
+ soc_info->emac_pdata->phy_id = DM646X_EVM_PHY_ID;
}
#define DM646X_EVM_REF_FREQ 27000000
diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c
new file mode 100644
index 000000000000..0bb5f0ce4fdc
--- /dev/null
+++ b/arch/arm/mach-davinci/board-mityomapl138.c
@@ -0,0 +1,422 @@
+/*
+ * Critical Link MityOMAP-L138 SoM
+ *
+ * Copyright (C) 2010 Critical Link LLC - http://www.criticallink.com
+ *
+ * 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/init.h>
+#include <linux/console.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/partitions.h>
+#include <linux/regulator/machine.h>
+#include <linux/i2c.h>
+#include <linux/i2c/at24.h>
+#include <linux/etherdevice.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/common.h>
+#include <mach/cp_intc.h>
+#include <mach/da8xx.h>
+#include <mach/nand.h>
+#include <mach/mux.h>
+
+#define MITYOMAPL138_PHY_ID "0:03"
+
+#define FACTORY_CONFIG_MAGIC 0x012C0138
+#define FACTORY_CONFIG_VERSION 0x00010001
+
+/* Data Held in On-Board I2C device */
+struct factory_config {
+ u32 magic;
+ u32 version;
+ u8 mac[6];
+ u32 fpga_type;
+ u32 spare;
+ u32 serialnumber;
+ char partnum[32];
+};
+
+static struct factory_config factory_config;
+
+static void read_factory_config(struct memory_accessor *a, void *context)
+{
+ int ret;
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+ ret = a->read(a, (char *)&factory_config, 0, sizeof(factory_config));
+ if (ret != sizeof(struct factory_config)) {
+ pr_warning("MityOMAPL138: Read Factory Config Failed: %d\n",
+ ret);
+ return;
+ }
+
+ if (factory_config.magic != FACTORY_CONFIG_MAGIC) {
+ pr_warning("MityOMAPL138: Factory Config Magic Wrong (%X)\n",
+ factory_config.magic);
+ return;
+ }
+
+ if (factory_config.version != FACTORY_CONFIG_VERSION) {
+ pr_warning("MityOMAPL138: Factory Config Version Wrong (%X)\n",
+ factory_config.version);
+ return;
+ }
+
+ pr_info("MityOMAPL138: Found MAC = %pM\n", factory_config.mac);
+ pr_info("MityOMAPL138: Part Number = %s\n", factory_config.partnum);
+ if (is_valid_ether_addr(factory_config.mac))
+ memcpy(soc_info->emac_pdata->mac_addr,
+ factory_config.mac, ETH_ALEN);
+ else
+ pr_warning("MityOMAPL138: Invalid MAC found "
+ "in factory config block\n");
+}
+
+static struct at24_platform_data mityomapl138_fd_chip = {
+ .byte_len = 256,
+ .page_size = 8,
+ .flags = AT24_FLAG_READONLY | AT24_FLAG_IRUGO,
+ .setup = read_factory_config,
+ .context = NULL,
+};
+
+static struct davinci_i2c_platform_data mityomap_i2c_0_pdata = {
+ .bus_freq = 100, /* kHz */
+ .bus_delay = 0, /* usec */
+};
+
+/* TPS65023 voltage regulator support */
+/* 1.2V Core */
+static struct regulator_consumer_supply tps65023_dcdc1_consumers[] = {
+ {
+ .supply = "cvdd",
+ },
+};
+
+/* 1.8V */
+static struct regulator_consumer_supply tps65023_dcdc2_consumers[] = {
+ {
+ .supply = "usb0_vdda18",
+ },
+ {
+ .supply = "usb1_vdda18",
+ },
+ {
+ .supply = "ddr_dvdd18",
+ },
+ {
+ .supply = "sata_vddr",
+ },
+};
+
+/* 1.2V */
+static struct regulator_consumer_supply tps65023_dcdc3_consumers[] = {
+ {
+ .supply = "sata_vdd",
+ },
+ {
+ .supply = "usb_cvdd",
+ },
+ {
+ .supply = "pll0_vdda",
+ },
+ {
+ .supply = "pll1_vdda",
+ },
+};
+
+/* 1.8V Aux LDO, not used */
+static struct regulator_consumer_supply tps65023_ldo1_consumers[] = {
+ {
+ .supply = "1.8v_aux",
+ },
+};
+
+/* FPGA VCC Aux (2.5 or 3.3) LDO */
+static struct regulator_consumer_supply tps65023_ldo2_consumers[] = {
+ {
+ .supply = "vccaux",
+ },
+};
+
+static struct regulator_init_data tps65023_regulator_data[] = {
+ /* dcdc1 */
+ {
+ .constraints = {
+ .min_uV = 1150000,
+ .max_uV = 1350000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc1_consumers),
+ .consumer_supplies = tps65023_dcdc1_consumers,
+ },
+ /* dcdc2 */
+ {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc2_consumers),
+ .consumer_supplies = tps65023_dcdc2_consumers,
+ },
+ /* dcdc3 */
+ {
+ .constraints = {
+ .min_uV = 1200000,
+ .max_uV = 1200000,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc3_consumers),
+ .consumer_supplies = tps65023_dcdc3_consumers,
+ },
+ /* ldo1 */
+ {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps65023_ldo1_consumers),
+ .consumer_supplies = tps65023_ldo1_consumers,
+ },
+ /* ldo2 */
+ {
+ .constraints = {
+ .min_uV = 2500000,
+ .max_uV = 3300000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps65023_ldo2_consumers),
+ .consumer_supplies = tps65023_ldo2_consumers,
+ },
+};
+
+static struct i2c_board_info __initdata mityomap_tps65023_info[] = {
+ {
+ I2C_BOARD_INFO("tps65023", 0x48),
+ .platform_data = &tps65023_regulator_data[0],
+ },
+ {
+ I2C_BOARD_INFO("24c02", 0x50),
+ .platform_data = &mityomapl138_fd_chip,
+ },
+};
+
+static int __init pmic_tps65023_init(void)
+{
+ return i2c_register_board_info(1, mityomap_tps65023_info,
+ ARRAY_SIZE(mityomap_tps65023_info));
+}
+
+/*
+ * MityDSP-L138 includes a 256 MByte large-page NAND flash
+ * (128K blocks).
+ */
+static struct mtd_partition mityomapl138_nandflash_partition[] = {
+ {
+ .name = "rootfs",
+ .offset = 0,
+ .size = SZ_128M,
+ .mask_flags = 0, /* MTD_WRITEABLE, */
+ },
+ {
+ .name = "homefs",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ .mask_flags = 0,
+ },
+};
+
+static struct davinci_nand_pdata mityomapl138_nandflash_data = {
+ .parts = mityomapl138_nandflash_partition,
+ .nr_parts = ARRAY_SIZE(mityomapl138_nandflash_partition),
+ .ecc_mode = NAND_ECC_HW,
+ .options = NAND_USE_FLASH_BBT | NAND_BUSWIDTH_16,
+ .ecc_bits = 1, /* 4 bit mode is not supported with 16 bit NAND */
+};
+
+static struct resource mityomapl138_nandflash_resource[] = {
+ {
+ .start = DA8XX_AEMIF_CS3_BASE,
+ .end = DA8XX_AEMIF_CS3_BASE + SZ_512K + 2 * SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = DA8XX_AEMIF_CTL_BASE,
+ .end = DA8XX_AEMIF_CTL_BASE + SZ_32K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device mityomapl138_nandflash_device = {
+ .name = "davinci_nand",
+ .id = 0,
+ .dev = {
+ .platform_data = &mityomapl138_nandflash_data,
+ },
+ .num_resources = ARRAY_SIZE(mityomapl138_nandflash_resource),
+ .resource = mityomapl138_nandflash_resource,
+};
+
+static struct platform_device *mityomapl138_devices[] __initdata = {
+ &mityomapl138_nandflash_device,
+};
+
+static void __init mityomapl138_setup_nand(void)
+{
+ platform_add_devices(mityomapl138_devices,
+ ARRAY_SIZE(mityomapl138_devices));
+}
+
+static struct davinci_uart_config mityomapl138_uart_config __initdata = {
+ .enabled_uarts = 0x7,
+};
+
+static const short mityomap_mii_pins[] = {
+ DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
+ DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
+ DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
+ DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
+ DA850_MDIO_D,
+ -1
+};
+
+static const short mityomap_rmii_pins[] = {
+ DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
+ DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1,
+ DA850_RMII_RXER, DA850_RMII_MHZ_50_CLK, DA850_MDIO_CLK,
+ DA850_MDIO_D,
+ -1
+};
+
+static void __init mityomapl138_config_emac(void)
+{
+ void __iomem *cfg_chip3_base;
+ int ret;
+ u32 val;
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+ soc_info->emac_pdata->rmii_en = 0; /* hardcoded for now */
+
+ cfg_chip3_base = DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG);
+ val = __raw_readl(cfg_chip3_base);
+
+ if (soc_info->emac_pdata->rmii_en) {
+ val |= BIT(8);
+ ret = davinci_cfg_reg_list(mityomap_rmii_pins);
+ pr_info("RMII PHY configured\n");
+ } else {
+ val &= ~BIT(8);
+ ret = davinci_cfg_reg_list(mityomap_mii_pins);
+ pr_info("MII PHY configured\n");
+ }
+
+ if (ret) {
+ pr_warning("mii/rmii mux setup failed: %d\n", ret);
+ return;
+ }
+
+ /* configure the CFGCHIP3 register for RMII or MII */
+ __raw_writel(val, cfg_chip3_base);
+
+ soc_info->emac_pdata->phy_id = MITYOMAPL138_PHY_ID;
+
+ ret = da8xx_register_emac();
+ if (ret)
+ pr_warning("emac registration failed: %d\n", ret);
+}
+
+static struct davinci_pm_config da850_pm_pdata = {
+ .sleepcount = 128,
+};
+
+static struct platform_device da850_pm_device = {
+ .name = "pm-davinci",
+ .dev = {
+ .platform_data = &da850_pm_pdata,
+ },
+ .id = -1,
+};
+
+static void __init mityomapl138_init(void)
+{
+ int ret;
+
+ /* for now, no special EDMA channels are reserved */
+ ret = da850_register_edma(NULL);
+ if (ret)
+ pr_warning("edma registration failed: %d\n", ret);
+
+ ret = da8xx_register_watchdog();
+ if (ret)
+ pr_warning("watchdog registration failed: %d\n", ret);
+
+ davinci_serial_init(&mityomapl138_uart_config);
+
+ ret = da8xx_register_i2c(0, &mityomap_i2c_0_pdata);
+ if (ret)
+ pr_warning("i2c0 registration failed: %d\n", ret);
+
+ ret = pmic_tps65023_init();
+ if (ret)
+ pr_warning("TPS65023 PMIC init failed: %d\n", ret);
+
+ mityomapl138_setup_nand();
+
+ mityomapl138_config_emac();
+
+ ret = da8xx_register_rtc();
+ if (ret)
+ pr_warning("rtc setup failed: %d\n", ret);
+
+ ret = da850_register_cpufreq("pll0_sysclk3");
+ if (ret)
+ pr_warning("cpufreq registration failed: %d\n", ret);
+
+ ret = da8xx_register_cpuidle();
+ if (ret)
+ pr_warning("cpuidle registration failed: %d\n", ret);
+
+ ret = da850_register_pm(&da850_pm_device);
+ if (ret)
+ pr_warning("da850_evm_init: suspend registration failed: %d\n",
+ ret);
+}
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static int __init mityomapl138_console_init(void)
+{
+ if (!machine_is_mityomapl138())
+ return 0;
+
+ return add_preferred_console("ttyS", 1, "115200");
+}
+console_initcall(mityomapl138_console_init);
+#endif
+
+static void __init mityomapl138_map_io(void)
+{
+ da850_init();
+}
+
+MACHINE_START(MITYOMAPL138, "MityDSP-L138/MityARM-1808")
+ .boot_params = (DA8XX_DDR_BASE + 0x100),
+ .map_io = mityomapl138_map_io,
+ .init_irq = cp_intc_init,
+ .timer = &davinci_timer,
+ .init_machine = mityomapl138_init,
+MACHINE_END
diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c
index a4def889275c..6c389ff1020e 100644
--- a/arch/arm/mach-davinci/board-neuros-osd2.c
+++ b/arch/arm/mach-davinci/board-neuros-osd2.c
@@ -39,9 +39,7 @@
#include <mach/mmc.h>
#include <mach/usb.h>
-#define NEUROS_OSD2_PHY_MASK 0x2
-#define NEUROS_OSD2_MDIO_FREQUENCY 2200000 /* PHY bus frequency */
-
+#define NEUROS_OSD2_PHY_ID "0:01"
#define LXT971_PHY_ID 0x001378e2
#define LXT971_PHY_MASK 0xfffffff0
@@ -252,8 +250,7 @@ static __init void davinci_ntosd2_init(void)
davinci_serial_init(&uart_config);
dm644x_init_asp(&dm644x_ntosd2_snd_data);
- soc_info->emac_pdata->phy_mask = NEUROS_OSD2_PHY_MASK;
- soc_info->emac_pdata->mdio_max_freq = NEUROS_OSD2_MDIO_FREQUENCY;
+ soc_info->emac_pdata->phy_id = NEUROS_OSD2_PHY_ID;
davinci_setup_usb(1000, 8);
/*
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
new file mode 100644
index 000000000000..0b8dbdb79fe0
--- /dev/null
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -0,0 +1,62 @@
+/*
+ * Hawkboard.org based on TI's OMAP-L138 Platform
+ *
+ * Initial code: Syed Mohammed Khasim
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * 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/init.h>
+#include <linux/console.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/cp_intc.h>
+#include <mach/da8xx.h>
+
+static struct davinci_uart_config omapl138_hawk_uart_config __initdata = {
+ .enabled_uarts = 0x7,
+};
+
+static __init void omapl138_hawk_init(void)
+{
+ int ret;
+
+ davinci_serial_init(&omapl138_hawk_uart_config);
+
+ ret = da8xx_register_watchdog();
+ if (ret)
+ pr_warning("omapl138_hawk_init: "
+ "watchdog registration failed: %d\n",
+ ret);
+}
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static int __init omapl138_hawk_console_init(void)
+{
+ if (!machine_is_omapl138_hawkboard())
+ return 0;
+
+ return add_preferred_console("ttyS", 2, "115200");
+}
+console_initcall(omapl138_hawk_console_init);
+#endif
+
+static void __init omapl138_hawk_map_io(void)
+{
+ da850_init();
+}
+
+MACHINE_START(OMAPL138_HAWKBOARD, "AM18x/OMAP-L138 Hawkboard")
+ .boot_params = (DA8XX_DDR_BASE + 0x100),
+ .map_io = omapl138_hawk_map_io,
+ .init_irq = cp_intc_init,
+ .timer = &davinci_timer,
+ .init_machine = omapl138_hawk_init,
+MACHINE_END
diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c
index 9bdf8aafcc84..61ac96d8f00d 100644
--- a/arch/arm/mach-davinci/board-sffsdr.c
+++ b/arch/arm/mach-davinci/board-sffsdr.c
@@ -42,9 +42,7 @@
#include <mach/mux.h>
#include <mach/usb.h>
-#define SFFSDR_PHY_MASK (0x2)
-#define SFFSDR_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
-
+#define SFFSDR_PHY_ID "0:01"
static struct mtd_partition davinci_sffsdr_nandflash_partition[] = {
/* U-Boot Environment: Block 0
* UBL: Block 1
@@ -143,8 +141,7 @@ static __init void davinci_sffsdr_init(void)
ARRAY_SIZE(davinci_sffsdr_devices));
sffsdr_init_i2c();
davinci_serial_init(&uart_config);
- soc_info->emac_pdata->phy_mask = SFFSDR_PHY_MASK;
- soc_info->emac_pdata->mdio_max_freq = SFFSDR_MDIO_FREQUENCY;
+ soc_info->emac_pdata->phy_id = SFFSDR_PHY_ID;
davinci_setup_usb(0, 0); /* We support only peripheral mode. */
/* mux VLYNQ pins */
diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index b4de35b78904..a6db85460227 100644
--- a/arch/arm/mach-davinci/board-tnetv107x-evm.c
+++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c
@@ -23,6 +23,9 @@
#include <linux/ratelimit.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
@@ -141,10 +144,63 @@ static struct davinci_uart_config serial_config __initconst = {
.enabled_uarts = BIT(1),
};
+static const uint32_t keymap[] = {
+ KEY(0, 0, KEY_NUMERIC_1),
+ KEY(0, 1, KEY_NUMERIC_2),
+ KEY(0, 2, KEY_NUMERIC_3),
+ KEY(0, 3, KEY_FN_F1),
+ KEY(0, 4, KEY_MENU),
+
+ KEY(1, 0, KEY_NUMERIC_4),
+ KEY(1, 1, KEY_NUMERIC_5),
+ KEY(1, 2, KEY_NUMERIC_6),
+ KEY(1, 3, KEY_UP),
+ KEY(1, 4, KEY_FN_F2),
+
+ KEY(2, 0, KEY_NUMERIC_7),
+ KEY(2, 1, KEY_NUMERIC_8),
+ KEY(2, 2, KEY_NUMERIC_9),
+ KEY(2, 3, KEY_LEFT),
+ KEY(2, 4, KEY_ENTER),
+
+ KEY(3, 0, KEY_NUMERIC_STAR),
+ KEY(3, 1, KEY_NUMERIC_0),
+ KEY(3, 2, KEY_NUMERIC_POUND),
+ KEY(3, 3, KEY_DOWN),
+ KEY(3, 4, KEY_RIGHT),
+
+ KEY(4, 0, KEY_FN_F3),
+ KEY(4, 1, KEY_FN_F4),
+ KEY(4, 2, KEY_MUTE),
+ KEY(4, 3, KEY_HOME),
+ KEY(4, 4, KEY_BACK),
+
+ KEY(5, 0, KEY_VOLUMEDOWN),
+ KEY(5, 1, KEY_VOLUMEUP),
+ KEY(5, 2, KEY_F1),
+ KEY(5, 3, KEY_F2),
+ KEY(5, 4, KEY_F3),
+};
+
+static const struct matrix_keymap_data keymap_data = {
+ .keymap = keymap,
+ .keymap_size = ARRAY_SIZE(keymap),
+};
+
+static struct matrix_keypad_platform_data keypad_config = {
+ .keymap_data = &keymap_data,
+ .num_row_gpios = 6,
+ .num_col_gpios = 5,
+ .debounce_ms = 0, /* minimum */
+ .active_low = 0, /* pull up realization */
+ .no_autorepeat = 0,
+};
+
static struct tnetv107x_device_info evm_device_info __initconst = {
.serial_config = &serial_config,
.mmc_config[1] = &mmc_config, /* controller 1 */
.nand_config[0] = &nand_config, /* chip select 0 */
+ .keypad_config = &keypad_config,
};
static __init void tnetv107x_evm_board_init(void)
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index 054c303caead..01ba080433db 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -236,7 +236,7 @@ static int __init clk_disable_unused(void)
if (!davinci_psc_is_clk_active(ck->gpsc, ck->lpsc))
continue;
- pr_info("Clocks: disable unused %s\n", ck->name);
+ pr_debug("Clocks: disable unused %s\n", ck->name);
davinci_psc_config(psc_domain(ck), ck->gpsc, ck->lpsc,
(ck->flags & PSC_SWRSTDISABLE) ?
@@ -287,6 +287,79 @@ static unsigned long clk_sysclk_recalc(struct clk *clk)
return rate;
}
+int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned v;
+ struct pll_data *pll;
+ unsigned long input;
+ unsigned ratio = 0;
+
+ /* If this is the PLL base clock, wrong function to call */
+ if (clk->pll_data)
+ return -EINVAL;
+
+ /* There must be a parent... */
+ if (WARN_ON(!clk->parent))
+ return -EINVAL;
+
+ /* ... the parent must be a PLL... */
+ if (WARN_ON(!clk->parent->pll_data))
+ return -EINVAL;
+
+ /* ... and this clock must have a divider. */
+ if (WARN_ON(!clk->div_reg))
+ return -EINVAL;
+
+ pll = clk->parent->pll_data;
+
+ input = clk->parent->rate;
+
+ /* If pre-PLL, source clock is before the multiplier and divider(s) */
+ if (clk->flags & PRE_PLL)
+ input = pll->input_rate;
+
+ if (input > rate) {
+ /*
+ * Can afford to provide an output little higher than requested
+ * only if maximum rate supported by hardware on this sysclk
+ * is known.
+ */
+ if (clk->maxrate) {
+ ratio = DIV_ROUND_CLOSEST(input, rate);
+ if (input / ratio > clk->maxrate)
+ ratio = 0;
+ }
+
+ if (ratio == 0)
+ ratio = DIV_ROUND_UP(input, rate);
+
+ ratio--;
+ }
+
+ if (ratio > PLLDIV_RATIO_MASK)
+ return -EINVAL;
+
+ do {
+ v = __raw_readl(pll->base + PLLSTAT);
+ } while (v & PLLSTAT_GOSTAT);
+
+ v = __raw_readl(pll->base + clk->div_reg);
+ v &= ~PLLDIV_RATIO_MASK;
+ v |= ratio | PLLDIV_EN;
+ __raw_writel(v, pll->base + clk->div_reg);
+
+ v = __raw_readl(pll->base + PLLCMD);
+ v |= PLLCMD_GOSET;
+ __raw_writel(v, pll->base + PLLCMD);
+
+ do {
+ v = __raw_readl(pll->base + PLLSTAT);
+ } while (v & PLLSTAT_GOSTAT);
+
+ return 0;
+}
+EXPORT_SYMBOL(davinci_set_sysclk_rate);
+
static unsigned long clk_leafclk_recalc(struct clk *clk)
{
if (WARN_ON(!clk->parent))
diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h
index 01e36483ac3d..11099980b58b 100644
--- a/arch/arm/mach-davinci/clock.h
+++ b/arch/arm/mach-davinci/clock.h
@@ -70,6 +70,9 @@
#include <linux/list.h>
#include <asm/clkdev.h>
+#define PLLSTAT_GOSTAT BIT(0)
+#define PLLCMD_GOSET BIT(0)
+
struct pll_data {
u32 phys_base;
void __iomem *base;
@@ -86,6 +89,7 @@ struct clk {
struct module *owner;
const char *name;
unsigned long rate;
+ unsigned long maxrate; /* H/W supported max rate */
u8 usecount;
u8 lpsc;
u8 gpsc;
@@ -118,6 +122,7 @@ struct clk {
int davinci_clk_init(struct clk_lookup *clocks);
int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
unsigned int mult, unsigned int postdiv);
+int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate);
extern struct platform_device davinci_wdt_device;
extern void davinci_watchdog_reset(struct platform_device *);
diff --git a/arch/arm/mach-davinci/cpufreq.c b/arch/arm/mach-davinci/cpufreq.c
index d3fa6de1e20f..343de73161fa 100644
--- a/arch/arm/mach-davinci/cpufreq.c
+++ b/arch/arm/mach-davinci/cpufreq.c
@@ -34,6 +34,8 @@
struct davinci_cpufreq {
struct device *dev;
struct clk *armclk;
+ struct clk *asyncclk;
+ unsigned long asyncrate;
};
static struct davinci_cpufreq cpufreq;
@@ -104,15 +106,27 @@ static int davinci_target(struct cpufreq_policy *policy,
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
/* if moving to higher frequency, up the voltage beforehand */
- if (pdata->set_voltage && freqs.new > freqs.old)
- pdata->set_voltage(idx);
+ if (pdata->set_voltage && freqs.new > freqs.old) {
+ ret = pdata->set_voltage(idx);
+ if (ret)
+ goto out;
+ }
ret = clk_set_rate(armclk, idx);
+ if (ret)
+ goto out;
+
+ if (cpufreq.asyncclk) {
+ ret = clk_set_rate(cpufreq.asyncclk, cpufreq.asyncrate);
+ if (ret)
+ goto out;
+ }
/* if moving to lower freq, lower the voltage after lowering freq */
if (pdata->set_voltage && freqs.new < freqs.old)
pdata->set_voltage(idx);
+out:
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return ret;
@@ -185,6 +199,7 @@ static struct cpufreq_driver davinci_driver = {
static int __init davinci_cpufreq_probe(struct platform_device *pdev)
{
struct davinci_cpufreq_config *pdata = pdev->dev.platform_data;
+ struct clk *asyncclk;
if (!pdata)
return -EINVAL;
@@ -199,6 +214,12 @@ static int __init davinci_cpufreq_probe(struct platform_device *pdev)
return PTR_ERR(cpufreq.armclk);
}
+ asyncclk = clk_get(cpufreq.dev, "async");
+ if (!IS_ERR(asyncclk)) {
+ cpufreq.asyncclk = asyncclk;
+ cpufreq.asyncrate = clk_get_rate(asyncclk);
+ }
+
return cpufreq_register_driver(&davinci_driver);
}
@@ -206,6 +227,9 @@ static int __exit davinci_cpufreq_remove(struct platform_device *pdev)
{
clk_put(cpufreq.armclk);
+ if (cpufreq.asyncclk)
+ clk_put(cpufreq.asyncclk);
+
return cpufreq_unregister_driver(&davinci_driver);
}
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 68ed58a48252..63916b902760 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -86,6 +86,8 @@ static struct clk pll0_sysclk3 = {
.parent = &pll0_clk,
.flags = CLK_PLL,
.div_reg = PLLDIV3,
+ .set_rate = davinci_set_sysclk_rate,
+ .maxrate = 100000000,
};
static struct clk pll0_sysclk4 = {
@@ -323,12 +325,19 @@ static struct clk lcdc_clk = {
.gpsc = 1,
};
-static struct clk mmcsd_clk = {
- .name = "mmcsd",
+static struct clk mmcsd0_clk = {
+ .name = "mmcsd0",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC0_MMC_SD,
};
+static struct clk mmcsd1_clk = {
+ .name = "mmcsd1",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA850_LPSC1_MMC_SD1,
+ .gpsc = 1,
+};
+
static struct clk aemif_clk = {
.name = "aemif",
.parent = &pll0_sysclk3,
@@ -375,7 +384,8 @@ static struct clk_lookup da850_clks[] = {
CLK("davinci_emac.1", NULL, &emac_clk),
CLK("davinci-mcasp.0", NULL, &mcasp_clk),
CLK("da8xx_lcdc.0", NULL, &lcdc_clk),
- CLK("davinci_mmc.0", NULL, &mmcsd_clk),
+ CLK("davinci_mmc.0", NULL, &mmcsd0_clk),
+ CLK("davinci_mmc.1", NULL, &mmcsd1_clk),
CLK(NULL, "aemif", &aemif_clk),
CLK(NULL, NULL, NULL),
};
@@ -572,15 +582,9 @@ const short da850_cpgmac_pins[] __initdata = {
DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
- DA850_MDIO_D,
- -1
-};
-
-const short da850_rmii_pins[] __initdata = {
- DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
- DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1,
- DA850_RMII_RXER, DA850_RMII_MHZ_50_CLK, DA850_MDIO_CLK,
- DA850_MDIO_D,
+ DA850_MDIO_D, DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
+ DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1, DA850_RMII_RXER,
+ DA850_RMII_MHZ_50_CLK,
-1
};
@@ -607,27 +611,19 @@ const short da850_mmcsd0_pins[] __initdata = {
-1
};
-const short da850_nand_pins[] __initdata = {
- DA850_EMA_D_7, DA850_EMA_D_6, DA850_EMA_D_5, DA850_EMA_D_4,
- DA850_EMA_D_3, DA850_EMA_D_2, DA850_EMA_D_1, DA850_EMA_D_0,
- DA850_EMA_A_1, DA850_EMA_A_2, DA850_NEMA_CS_3, DA850_NEMA_CS_4,
- DA850_NEMA_WE, DA850_NEMA_OE,
- -1
-};
-
-const short da850_nor_pins[] __initdata = {
+const short da850_emif25_pins[] __initdata = {
DA850_EMA_BA_1, DA850_EMA_CLK, DA850_EMA_WAIT_1, DA850_NEMA_CS_2,
- DA850_NEMA_WE, DA850_NEMA_OE, DA850_EMA_D_0, DA850_EMA_D_1,
- DA850_EMA_D_2, DA850_EMA_D_3, DA850_EMA_D_4, DA850_EMA_D_5,
- DA850_EMA_D_6, DA850_EMA_D_7, DA850_EMA_D_8, DA850_EMA_D_9,
- DA850_EMA_D_10, DA850_EMA_D_11, DA850_EMA_D_12, DA850_EMA_D_13,
- DA850_EMA_D_14, DA850_EMA_D_15, DA850_EMA_A_0, DA850_EMA_A_1,
- DA850_EMA_A_2, DA850_EMA_A_3, DA850_EMA_A_4, DA850_EMA_A_5,
- DA850_EMA_A_6, DA850_EMA_A_7, DA850_EMA_A_8, DA850_EMA_A_9,
- DA850_EMA_A_10, DA850_EMA_A_11, DA850_EMA_A_12, DA850_EMA_A_13,
- DA850_EMA_A_14, DA850_EMA_A_15, DA850_EMA_A_16, DA850_EMA_A_17,
- DA850_EMA_A_18, DA850_EMA_A_19, DA850_EMA_A_20, DA850_EMA_A_21,
- DA850_EMA_A_22, DA850_EMA_A_23,
+ DA850_NEMA_CS_3, DA850_NEMA_CS_4, DA850_NEMA_WE, DA850_NEMA_OE,
+ DA850_EMA_D_0, DA850_EMA_D_1, DA850_EMA_D_2, DA850_EMA_D_3,
+ DA850_EMA_D_4, DA850_EMA_D_5, DA850_EMA_D_6, DA850_EMA_D_7,
+ DA850_EMA_D_8, DA850_EMA_D_9, DA850_EMA_D_10, DA850_EMA_D_11,
+ DA850_EMA_D_12, DA850_EMA_D_13, DA850_EMA_D_14, DA850_EMA_D_15,
+ DA850_EMA_A_0, DA850_EMA_A_1, DA850_EMA_A_2, DA850_EMA_A_3,
+ DA850_EMA_A_4, DA850_EMA_A_5, DA850_EMA_A_6, DA850_EMA_A_7,
+ DA850_EMA_A_8, DA850_EMA_A_9, DA850_EMA_A_10, DA850_EMA_A_11,
+ DA850_EMA_A_12, DA850_EMA_A_13, DA850_EMA_A_14, DA850_EMA_A_15,
+ DA850_EMA_A_16, DA850_EMA_A_17, DA850_EMA_A_18, DA850_EMA_A_19,
+ DA850_EMA_A_20, DA850_EMA_A_21, DA850_EMA_A_22, DA850_EMA_A_23,
-1
};
@@ -851,7 +847,7 @@ static const struct da850_opp da850_opp_300 = {
.prediv = 1,
.mult = 25,
.postdiv = 2,
- .cvdd_min = 1140000,
+ .cvdd_min = 1200000,
.cvdd_max = 1320000,
};
@@ -860,7 +856,7 @@ static const struct da850_opp da850_opp_200 = {
.prediv = 1,
.mult = 25,
.postdiv = 3,
- .cvdd_min = 1050000,
+ .cvdd_min = 1100000,
.cvdd_max = 1160000,
};
@@ -869,7 +865,7 @@ static const struct da850_opp da850_opp_96 = {
.prediv = 1,
.mult = 20,
.postdiv = 5,
- .cvdd_min = 950000,
+ .cvdd_min = 1000000,
.cvdd_max = 1050000,
};
@@ -929,10 +925,16 @@ static struct platform_device da850_cpufreq_device = {
.dev = {
.platform_data = &cpufreq_info,
},
+ .id = -1,
};
-int __init da850_register_cpufreq(void)
+int __init da850_register_cpufreq(char *async_clk)
{
+ /* cpufreq driver can help keep an "async" clock constant */
+ if (async_clk)
+ clk_add_alias("async", da850_cpufreq_device.name,
+ async_clk, NULL);
+
return platform_device_register(&da850_cpufreq_device);
}
@@ -983,7 +985,7 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long index)
return 0;
}
#else
-int __init da850_register_cpufreq(void)
+int __init da850_register_cpufreq(char *async_clk)
{
return 0;
}
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 52bc7b1c6ca3..9eec63070e0c 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -24,6 +24,7 @@
#include "clock.h"
#define DA8XX_TPCC_BASE 0x01c00000
+#define DA850_MMCSD1_BASE 0x01e1b000
#define DA850_TPCC1_BASE 0x01e30000
#define DA8XX_TPTC0_BASE 0x01c08000
#define DA8XX_TPTC1_BASE 0x01c08400
@@ -41,7 +42,6 @@
#define DA8XX_EMAC_CTRL_REG_OFFSET 0x3000
#define DA8XX_EMAC_MOD_REG_OFFSET 0x2000
#define DA8XX_EMAC_RAM_OFFSET 0x0000
-#define DA8XX_MDIO_REG_OFFSET 0x4000
#define DA8XX_EMAC_CTRL_RAM_SIZE SZ_8K
void __iomem *da8xx_syscfg0_base;
@@ -351,7 +351,7 @@ int __init da8xx_register_watchdog(void)
static struct resource da8xx_emac_resources[] = {
{
.start = DA8XX_EMAC_CPPI_PORT_BASE,
- .end = DA8XX_EMAC_CPPI_PORT_BASE + 0x5000 - 1,
+ .end = DA8XX_EMAC_CPPI_PORT_BASE + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
{
@@ -380,7 +380,6 @@ struct emac_platform_data da8xx_emac_pdata = {
.ctrl_reg_offset = DA8XX_EMAC_CTRL_REG_OFFSET,
.ctrl_mod_reg_offset = DA8XX_EMAC_MOD_REG_OFFSET,
.ctrl_ram_offset = DA8XX_EMAC_RAM_OFFSET,
- .mdio_reg_offset = DA8XX_MDIO_REG_OFFSET,
.ctrl_ram_size = DA8XX_EMAC_CTRL_RAM_SIZE,
.version = EMAC_VERSION_2,
};
@@ -395,9 +394,34 @@ static struct platform_device da8xx_emac_device = {
.resource = da8xx_emac_resources,
};
+static struct resource da8xx_mdio_resources[] = {
+ {
+ .start = DA8XX_EMAC_MDIO_BASE,
+ .end = DA8XX_EMAC_MDIO_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device da8xx_mdio_device = {
+ .name = "davinci_mdio",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(da8xx_mdio_resources),
+ .resource = da8xx_mdio_resources,
+};
+
int __init da8xx_register_emac(void)
{
- return platform_device_register(&da8xx_emac_device);
+ int ret;
+
+ ret = platform_device_register(&da8xx_mdio_device);
+ if (ret < 0)
+ return ret;
+ ret = platform_device_register(&da8xx_emac_device);
+ if (ret < 0)
+ return ret;
+ ret = clk_add_alias(NULL, dev_name(&da8xx_mdio_device.dev),
+ NULL, &da8xx_emac_device.dev);
+ return ret;
}
static struct resource da830_mcasp1_resources[] = {
@@ -566,6 +590,44 @@ int __init da8xx_register_mmcsd0(struct davinci_mmc_config *config)
return platform_device_register(&da8xx_mmcsd0_device);
}
+#ifdef CONFIG_ARCH_DAVINCI_DA850
+static struct resource da850_mmcsd1_resources[] = {
+ { /* registers */
+ .start = DA850_MMCSD1_BASE,
+ .end = DA850_MMCSD1_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ { /* interrupt */
+ .start = IRQ_DA850_MMCSDINT0_1,
+ .end = IRQ_DA850_MMCSDINT0_1,
+ .flags = IORESOURCE_IRQ,
+ },
+ { /* DMA RX */
+ .start = EDMA_CTLR_CHAN(1, 28),
+ .end = EDMA_CTLR_CHAN(1, 28),
+ .flags = IORESOURCE_DMA,
+ },
+ { /* DMA TX */
+ .start = EDMA_CTLR_CHAN(1, 29),
+ .end = EDMA_CTLR_CHAN(1, 29),
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct platform_device da850_mmcsd1_device = {
+ .name = "davinci_mmc",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(da850_mmcsd1_resources),
+ .resource = da850_mmcsd1_resources,
+};
+
+int __init da850_register_mmcsd1(struct davinci_mmc_config *config)
+{
+ da850_mmcsd1_device.dev.platform_data = config;
+ return platform_device_register(&da850_mmcsd1_device);
+}
+#endif
+
static struct resource da8xx_rtc_resources[] = {
{
.start = DA8XX_RTC_BASE,
diff --git a/arch/arm/mach-davinci/devices-tnetv107x.c b/arch/arm/mach-davinci/devices-tnetv107x.c
index 2718a3a90dff..c9a86d8130d1 100644
--- a/arch/arm/mach-davinci/devices-tnetv107x.c
+++ b/arch/arm/mach-davinci/devices-tnetv107x.c
@@ -31,8 +31,10 @@
#define TNETV107X_TPTC0_BASE 0x01c10000
#define TNETV107X_TPTC1_BASE 0x01c10400
#define TNETV107X_WDOG_BASE 0x08086700
+#define TNETV107X_TSC_BASE 0x08088500
#define TNETV107X_SDIO0_BASE 0x08088700
#define TNETV107X_SDIO1_BASE 0x08088800
+#define TNETV107X_KEYPAD_BASE 0x08088a00
#define TNETV107X_ASYNC_EMIF_CNTRL_BASE 0x08200000
#define TNETV107X_ASYNC_EMIF_DATA_CE0_BASE 0x30000000
#define TNETV107X_ASYNC_EMIF_DATA_CE1_BASE 0x40000000
@@ -298,12 +300,55 @@ static int __init nand_init(int chipsel, struct davinci_nand_pdata *data)
return platform_device_register(pdev);
}
+static struct resource keypad_resources[] = {
+ {
+ .start = TNETV107X_KEYPAD_BASE,
+ .end = TNETV107X_KEYPAD_BASE + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_TNETV107X_KEYPAD,
+ .flags = IORESOURCE_IRQ,
+ .name = "press",
+ },
+ {
+ .start = IRQ_TNETV107X_KEYPAD_FREE,
+ .flags = IORESOURCE_IRQ,
+ .name = "release",
+ },
+};
+
+static struct platform_device keypad_device = {
+ .name = "tnetv107x-keypad",
+ .num_resources = ARRAY_SIZE(keypad_resources),
+ .resource = keypad_resources,
+};
+
+static struct resource tsc_resources[] = {
+ {
+ .start = TNETV107X_TSC_BASE,
+ .end = TNETV107X_TSC_BASE + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_TNETV107X_TSC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tsc_device = {
+ .name = "tnetv107x-ts",
+ .num_resources = ARRAY_SIZE(tsc_resources),
+ .resource = tsc_resources,
+};
+
void __init tnetv107x_devices_init(struct tnetv107x_device_info *info)
{
int i;
platform_device_register(&edma_device);
platform_device_register(&tnetv107x_wdt_device);
+ platform_device_register(&tsc_device);
if (info->serial_config)
davinci_serial_init(info->serial_config);
@@ -317,4 +362,9 @@ void __init tnetv107x_devices_init(struct tnetv107x_device_info *info)
for (i = 0; i < 4; i++)
if (info->nand_config[i])
nand_init(i, info->nand_config[i]);
+
+ if (info->keypad_config) {
+ keypad_device.dev.platform_data = info->keypad_config;
+ platform_device_register(&keypad_device);
+ }
}
diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c
index 8b7201e4c79c..22ebc64bc9d9 100644
--- a/arch/arm/mach-davinci/devices.c
+++ b/arch/arm/mach-davinci/devices.c
@@ -213,7 +213,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE + 0x7c);
/* Configure pull down control */
- __raw_writel((__raw_readl(pupdctl1) & ~0x400),
+ __raw_writel((__raw_readl(pupdctl1) & ~0xfc0),
pupdctl1);
mmcsd1_resources[0].start = DM365_MMCSD1_BASE;
@@ -295,6 +295,18 @@ static void davinci_init_wdt(void)
/*-------------------------------------------------------------------------*/
+struct platform_device davinci_pcm_device = {
+ .name = "davinci-pcm-audio",
+ .id = -1,
+};
+
+static void davinci_init_pcm(void)
+{
+ platform_device_register(&davinci_pcm_device);
+}
+
+/*-------------------------------------------------------------------------*/
+
struct davinci_timer_instance davinci_timer_instance[2] = {
{
.base = DAVINCI_TIMER0_BASE,
@@ -315,6 +327,7 @@ static int __init davinci_init_devices(void)
/* please keep these calls, and their implementations above,
* in alphabetical order so they're easier to sort through.
*/
+ davinci_init_pcm();
davinci_init_wdt();
return 0;
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index 7781e35daec3..a12065e87266 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -691,7 +691,6 @@ static struct emac_platform_data dm365_emac_pdata = {
.ctrl_reg_offset = DM365_EMAC_CNTRL_OFFSET,
.ctrl_mod_reg_offset = DM365_EMAC_CNTRL_MOD_OFFSET,
.ctrl_ram_offset = DM365_EMAC_CNTRL_RAM_OFFSET,
- .mdio_reg_offset = DM365_EMAC_MDIO_OFFSET,
.ctrl_ram_size = DM365_EMAC_CNTRL_RAM_SIZE,
.version = EMAC_VERSION_2,
};
@@ -699,7 +698,7 @@ static struct emac_platform_data dm365_emac_pdata = {
static struct resource dm365_emac_resources[] = {
{
.start = DM365_EMAC_BASE,
- .end = DM365_EMAC_BASE + 0x47ff,
+ .end = DM365_EMAC_BASE + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
{
@@ -734,6 +733,21 @@ static struct platform_device dm365_emac_device = {
.resource = dm365_emac_resources,
};
+static struct resource dm365_mdio_resources[] = {
+ {
+ .start = DM365_EMAC_MDIO_BASE,
+ .end = DM365_EMAC_MDIO_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device dm365_mdio_device = {
+ .name = "davinci_mdio",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(dm365_mdio_resources),
+ .resource = dm365_mdio_resources,
+};
+
static u8 dm365_default_priorities[DAVINCI_N_AINTC_IRQ] = {
[IRQ_VDINT0] = 2,
[IRQ_VDINT1] = 6,
@@ -1219,7 +1233,12 @@ static int __init dm365_init_devices(void)
davinci_cfg_reg(DM365_INT_EDMA_CC);
platform_device_register(&dm365_edma_device);
+
+ platform_device_register(&dm365_mdio_device);
platform_device_register(&dm365_emac_device);
+ clk_add_alias(NULL, dev_name(&dm365_mdio_device.dev),
+ NULL, &dm365_emac_device.dev);
+
/* Add isif clock alias */
clk_add_alias("master", dm365_isif_dev.name, "vpss_master", NULL);
platform_device_register(&dm365_vpss_device);
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index 5e5b0a7831fb..0608dd776a16 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -322,7 +322,6 @@ static struct emac_platform_data dm644x_emac_pdata = {
.ctrl_reg_offset = DM644X_EMAC_CNTRL_OFFSET,
.ctrl_mod_reg_offset = DM644X_EMAC_CNTRL_MOD_OFFSET,
.ctrl_ram_offset = DM644X_EMAC_CNTRL_RAM_OFFSET,
- .mdio_reg_offset = DM644X_EMAC_MDIO_OFFSET,
.ctrl_ram_size = DM644X_EMAC_CNTRL_RAM_SIZE,
.version = EMAC_VERSION_1,
};
@@ -330,7 +329,7 @@ static struct emac_platform_data dm644x_emac_pdata = {
static struct resource dm644x_emac_resources[] = {
{
.start = DM644X_EMAC_BASE,
- .end = DM644X_EMAC_BASE + 0x47ff,
+ .end = DM644X_EMAC_BASE + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
{
@@ -350,6 +349,21 @@ static struct platform_device dm644x_emac_device = {
.resource = dm644x_emac_resources,
};
+static struct resource dm644x_mdio_resources[] = {
+ {
+ .start = DM644X_EMAC_MDIO_BASE,
+ .end = DM644X_EMAC_MDIO_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device dm644x_mdio_device = {
+ .name = "davinci_mdio",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(dm644x_mdio_resources),
+ .resource = dm644x_mdio_resources,
+};
+
/*
* Device specific mux setup
*
@@ -776,7 +790,12 @@ static int __init dm644x_init_devices(void)
clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL);
clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL);
platform_device_register(&dm644x_edma_device);
+
+ platform_device_register(&dm644x_mdio_device);
platform_device_register(&dm644x_emac_device);
+ clk_add_alias(NULL, dev_name(&dm644x_mdio_device.dev),
+ NULL, &dm644x_emac_device.dev);
+
platform_device_register(&dm644x_vpss_device);
platform_device_register(&dm644x_ccdc_dev);
platform_device_register(&vpfe_capture_dev);
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
index 26e8a9c7f50b..1e0f809644bb 100644
--- a/arch/arm/mach-davinci/dm646x.c
+++ b/arch/arm/mach-davinci/dm646x.c
@@ -358,7 +358,6 @@ static struct emac_platform_data dm646x_emac_pdata = {
.ctrl_reg_offset = DM646X_EMAC_CNTRL_OFFSET,
.ctrl_mod_reg_offset = DM646X_EMAC_CNTRL_MOD_OFFSET,
.ctrl_ram_offset = DM646X_EMAC_CNTRL_RAM_OFFSET,
- .mdio_reg_offset = DM646X_EMAC_MDIO_OFFSET,
.ctrl_ram_size = DM646X_EMAC_CNTRL_RAM_SIZE,
.version = EMAC_VERSION_2,
};
@@ -366,7 +365,7 @@ static struct emac_platform_data dm646x_emac_pdata = {
static struct resource dm646x_emac_resources[] = {
{
.start = DM646X_EMAC_BASE,
- .end = DM646X_EMAC_BASE + 0x47ff,
+ .end = DM646X_EMAC_BASE + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
{
@@ -401,6 +400,21 @@ static struct platform_device dm646x_emac_device = {
.resource = dm646x_emac_resources,
};
+static struct resource dm646x_mdio_resources[] = {
+ {
+ .start = DM646X_EMAC_MDIO_BASE,
+ .end = DM646X_EMAC_MDIO_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device dm646x_mdio_device = {
+ .name = "davinci_mdio",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(dm646x_mdio_resources),
+ .resource = dm646x_mdio_resources,
+};
+
/*
* Device specific mux setup
*
@@ -896,7 +910,11 @@ static int __init dm646x_init_devices(void)
if (!cpu_is_davinci_dm646x())
return 0;
+ platform_device_register(&dm646x_mdio_device);
platform_device_register(&dm646x_emac_device);
+ clk_add_alias(NULL, dev_name(&dm646x_mdio_device.dev),
+ NULL, &dm646x_emac_device.dev);
+
return 0;
}
postcore_initcall(dm646x_init_devices);
diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c
index 2ede598b77dd..6b9669869c46 100644
--- a/arch/arm/mach-davinci/dma.c
+++ b/arch/arm/mach-davinci/dma.c
@@ -354,10 +354,12 @@ static int irq2ctlr(int irq)
static irqreturn_t dma_irq_handler(int irq, void *data)
{
int i;
- unsigned ctlr;
+ int ctlr;
unsigned int cnt = 0;
ctlr = irq2ctlr(irq);
+ if (ctlr < 0)
+ return IRQ_NONE;
dev_dbg(data, "dma_irq_handler\n");
@@ -408,10 +410,12 @@ static irqreturn_t dma_irq_handler(int irq, void *data)
static irqreturn_t dma_ccerr_handler(int irq, void *data)
{
int i;
- unsigned ctlr;
+ int ctlr;
unsigned int cnt = 0;
ctlr = irq2ctlr(irq);
+ if (ctlr < 0)
+ return IRQ_NONE;
dev_dbg(data, "dma_ccerr_handler\n");
diff --git a/arch/arm/mach-davinci/include/mach/aemif.h b/arch/arm/mach-davinci/include/mach/aemif.h
new file mode 100644
index 000000000000..05b293443097
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/aemif.h
@@ -0,0 +1,36 @@
+/*
+ * TI DaVinci AEMIF support
+ *
+ * Copyright 2010 (C) Texas Instruments, Inc. http://www.ti.com/
+ *
+ * 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.
+ */
+#ifndef _MACH_DAVINCI_AEMIF_H
+#define _MACH_DAVINCI_AEMIF_H
+
+#define NRCSR_OFFSET 0x00
+#define AWCCR_OFFSET 0x04
+#define A1CR_OFFSET 0x10
+
+#define ACR_ASIZE_MASK 0x3
+#define ACR_EW_MASK BIT(30)
+#define ACR_SS_MASK BIT(31)
+
+/* All timings in nanoseconds */
+struct davinci_aemif_timing {
+ u8 wsetup;
+ u8 wstrobe;
+ u8 whold;
+
+ u8 rsetup;
+ u8 rstrobe;
+ u8 rhold;
+
+ u8 ta;
+};
+
+int davinci_aemif_setup_timing(struct davinci_aemif_timing *t,
+ void __iomem *base, unsigned cs);
+#endif
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index 3c07059f526e..4247b3f53b33 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -76,9 +76,10 @@ int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
int da8xx_register_emac(void);
int da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata);
int da8xx_register_mmcsd0(struct davinci_mmc_config *config);
+int da850_register_mmcsd1(struct davinci_mmc_config *config);
void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata);
int da8xx_register_rtc(void);
-int da850_register_cpufreq(void);
+int da850_register_cpufreq(char *async_clk);
int da8xx_register_cpuidle(void);
void __iomem * __init da8xx_get_mem_ctlr(void);
int da850_register_pm(struct platform_device *pdev);
@@ -121,11 +122,9 @@ extern const short da850_uart2_pins[];
extern const short da850_i2c0_pins[];
extern const short da850_i2c1_pins[];
extern const short da850_cpgmac_pins[];
-extern const short da850_rmii_pins[];
extern const short da850_mcasp_pins[];
extern const short da850_lcdcntl_pins[];
extern const short da850_mmcsd0_pins[];
-extern const short da850_nand_pins[];
-extern const short da850_nor_pins[];
+extern const short da850_emif25_pins[];
#endif /* __ASM_ARCH_DAVINCI_DA8XX_H */
diff --git a/arch/arm/mach-davinci/include/mach/dm365.h b/arch/arm/mach-davinci/include/mach/dm365.h
index ea5df3b49ec4..2563bf4e93a1 100644
--- a/arch/arm/mach-davinci/include/mach/dm365.h
+++ b/arch/arm/mach-davinci/include/mach/dm365.h
@@ -21,10 +21,10 @@
#include <media/davinci/vpfe_capture.h>
#define DM365_EMAC_BASE (0x01D07000)
+#define DM365_EMAC_MDIO_BASE (DM365_EMAC_BASE + 0x4000)
#define DM365_EMAC_CNTRL_OFFSET (0x0000)
#define DM365_EMAC_CNTRL_MOD_OFFSET (0x3000)
#define DM365_EMAC_CNTRL_RAM_OFFSET (0x1000)
-#define DM365_EMAC_MDIO_OFFSET (0x4000)
#define DM365_EMAC_CNTRL_RAM_SIZE (0x2000)
/* Base of key scan register bank */
diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h
index 6fca568a0fd2..5a1b26d4e68b 100644
--- a/arch/arm/mach-davinci/include/mach/dm644x.h
+++ b/arch/arm/mach-davinci/include/mach/dm644x.h
@@ -28,10 +28,10 @@
#include <media/davinci/vpfe_capture.h>
#define DM644X_EMAC_BASE (0x01C80000)
+#define DM644X_EMAC_MDIO_BASE (DM644X_EMAC_BASE + 0x4000)
#define DM644X_EMAC_CNTRL_OFFSET (0x0000)
#define DM644X_EMAC_CNTRL_MOD_OFFSET (0x1000)
#define DM644X_EMAC_CNTRL_RAM_OFFSET (0x2000)
-#define DM644X_EMAC_MDIO_OFFSET (0x4000)
#define DM644X_EMAC_CNTRL_RAM_SIZE (0x2000)
#define DM644X_ASYNC_EMIF_CONTROL_BASE 0x01E00000
diff --git a/arch/arm/mach-davinci/include/mach/dm646x.h b/arch/arm/mach-davinci/include/mach/dm646x.h
index 0a27ee9a70e1..7a27f3f13913 100644
--- a/arch/arm/mach-davinci/include/mach/dm646x.h
+++ b/arch/arm/mach-davinci/include/mach/dm646x.h
@@ -19,10 +19,10 @@
#include <linux/davinci_emac.h>
#define DM646X_EMAC_BASE (0x01C80000)
+#define DM646X_EMAC_MDIO_BASE (DM646X_EMAC_BASE + 0x4000)
#define DM646X_EMAC_CNTRL_OFFSET (0x0000)
#define DM646X_EMAC_CNTRL_MOD_OFFSET (0x1000)
#define DM646X_EMAC_CNTRL_RAM_OFFSET (0x2000)
-#define DM646X_EMAC_MDIO_OFFSET (0x4000)
#define DM646X_EMAC_CNTRL_RAM_SIZE (0x2000)
#define DM646X_ASYNC_EMIF_CONTROL_BASE 0x20008000
diff --git a/arch/arm/mach-davinci/include/mach/nand.h b/arch/arm/mach-davinci/include/mach/nand.h
index b2ad8090bd10..025151049f05 100644
--- a/arch/arm/mach-davinci/include/mach/nand.h
+++ b/arch/arm/mach-davinci/include/mach/nand.h
@@ -30,9 +30,6 @@
#include <linux/mtd/nand.h>
-#define NRCSR_OFFSET 0x00
-#define AWCCR_OFFSET 0x04
-#define A1CR_OFFSET 0x10
#define NANDFCR_OFFSET 0x60
#define NANDFSR_OFFSET 0x64
#define NANDF1ECC_OFFSET 0x70
@@ -83,6 +80,9 @@ struct davinci_nand_pdata { /* platform_data */
/* Main and mirror bbt descriptor overrides */
struct nand_bbt_descr *bbt_td;
struct nand_bbt_descr *bbt_md;
+
+ /* Access timings */
+ struct davinci_aemif_timing *timing;
};
#endif /* __ARCH_ARM_DAVINCI_NAND_H */
diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h
index 983da6e4554c..62b0858f68ca 100644
--- a/arch/arm/mach-davinci/include/mach/psc.h
+++ b/arch/arm/mach-davinci/include/mach/psc.h
@@ -172,6 +172,7 @@
#define DA8XX_LPSC1_UART2 13
#define DA8XX_LPSC1_LCDC 16
#define DA8XX_LPSC1_PWM 17
+#define DA850_LPSC1_MMC_SD1 18
#define DA8XX_LPSC1_ECAP 20
#define DA830_LPSC1_EQEP 21
#define DA850_LPSC1_TPTC2 21
diff --git a/arch/arm/mach-davinci/include/mach/tnetv107x.h b/arch/arm/mach-davinci/include/mach/tnetv107x.h
index c72064733123..5a681d880dcb 100644
--- a/arch/arm/mach-davinci/include/mach/tnetv107x.h
+++ b/arch/arm/mach-davinci/include/mach/tnetv107x.h
@@ -33,6 +33,8 @@
#ifndef __ASSEMBLY__
#include <linux/serial_8250.h>
+#include <linux/input/matrix_keypad.h>
+
#include <mach/mmc.h>
#include <mach/nand.h>
#include <mach/serial.h>
@@ -41,6 +43,7 @@ struct tnetv107x_device_info {
struct davinci_uart_config *serial_config;
struct davinci_mmc_config *mmc_config[2]; /* 2 controllers */
struct davinci_nand_pdata *nand_config[4]; /* 4 chipsels */
+ struct matrix_keypad_platform_data *keypad_config;
};
extern struct platform_device tnetv107x_wdt_device;
diff --git a/arch/arm/mach-davinci/include/mach/uncompress.h b/arch/arm/mach-davinci/include/mach/uncompress.h
index 15a6192ad6eb..47723e8d75a4 100644
--- a/arch/arm/mach-davinci/include/mach/uncompress.h
+++ b/arch/arm/mach-davinci/include/mach/uncompress.h
@@ -88,6 +88,8 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
/* DA8xx boards */
DEBUG_LL_DA8XX(davinci_da830_evm, 2);
DEBUG_LL_DA8XX(davinci_da850_evm, 2);
+ DEBUG_LL_DA8XX(mityomapl138, 1);
+ DEBUG_LL_DA8XX(omapl138_hawkboard, 2);
/* TNETV107x boards */
DEBUG_LL_TNETV107X(tnetv107x, 1);
diff --git a/arch/arm/mach-davinci/tnetv107x.c b/arch/arm/mach-davinci/tnetv107x.c
index 864e60482c53..daeae06430b9 100644
--- a/arch/arm/mach-davinci/tnetv107x.c
+++ b/arch/arm/mach-davinci/tnetv107x.c
@@ -104,7 +104,7 @@ static u32 pll_ext_freq[] = {
};
/* PSC control registers */
-static u32 psc_regs[] __initconst = { TNETV107X_PSC_BASE };
+static u32 psc_regs[] = { TNETV107X_PSC_BASE };
/* Host map for interrupt controller */
static u32 intc_host_map[] = { 0x01010000, 0x01010101, -1 };
@@ -581,7 +581,14 @@ static struct davinci_id ids[] = {
.part_no = 0xb8a1,
.manufacturer = 0x017,
.cpu_id = DAVINCI_CPU_ID_TNETV107X,
- .name = "tnetv107x rev1.0",
+ .name = "tnetv107x rev 1.0",
+ },
+ {
+ .variant = 0x1,
+ .part_no = 0xb8a1,
+ .manufacturer = 0x017,
+ .cpu_id = DAVINCI_CPU_ID_TNETV107X,
+ .name = "tnetv107x rev 1.1/1.2",
},
};
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index 4566bd1c8660..ef06c66a6f16 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -358,8 +358,7 @@ static int calc_clk_div(struct clk *clk, unsigned long rate,
int i, found = 0, __div = 0, __pdiv = 0;
/* Don't exceed the maximum rate */
- max_rate = max(max(clk_pll1.rate / 4, clk_pll2.rate / 4),
- clk_xtali.rate / 4);
+ max_rate = max3(clk_pll1.rate / 4, clk_pll2.rate / 4, clk_xtali.rate / 4);
rate = min(rate, max_rate);
/*
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 4cb55d3902ff..ffdf87be2958 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -776,9 +776,15 @@ static struct platform_device ep93xx_i2s_device = {
.resource = ep93xx_i2s_resource,
};
+static struct platform_device ep93xx_pcm_device = {
+ .name = "ep93xx-pcm-audio",
+ .id = -1,
+};
+
void __init ep93xx_register_i2s(void)
{
platform_device_register(&ep93xx_i2s_device);
+ platform_device_register(&ep93xx_pcm_device);
}
#define EP93XX_SYSCON_DEVCFG_I2S_MASK (EP93XX_SYSCON_DEVCFG_I2SONSSP | \
@@ -826,6 +832,40 @@ void ep93xx_i2s_release(void)
}
EXPORT_SYMBOL(ep93xx_i2s_release);
+/*************************************************************************
+ * EP93xx AC97 audio peripheral handling
+ *************************************************************************/
+static struct resource ep93xx_ac97_resources[] = {
+ {
+ .start = EP93XX_AAC_PHYS_BASE,
+ .end = EP93XX_AAC_PHYS_BASE + 0xb0 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_EP93XX_AACINTR,
+ .end = IRQ_EP93XX_AACINTR,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device ep93xx_ac97_device = {
+ .name = "ep93xx-ac97",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(ep93xx_ac97_resources),
+ .resource = ep93xx_ac97_resources,
+};
+
+void __init ep93xx_register_ac97(void)
+{
+ /*
+ * Make sure that the AC97 pins are not used by I2S.
+ */
+ ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONAC97);
+
+ platform_device_register(&ep93xx_ac97_device);
+ platform_device_register(&ep93xx_pcm_device);
+}
+
extern void ep93xx_gpio_init(void);
void __init ep93xx_init_devices(void)
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index c54b3e56ba63..9ac4d1055097 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -105,6 +105,7 @@
#define EP93XX_GPIO_B_INT_STATUS EP93XX_GPIO_REG(0xbc)
#define EP93XX_GPIO_EEDRIVE EP93XX_GPIO_REG(0xc8)
+#define EP93XX_AAC_PHYS_BASE EP93XX_APB_PHYS(0x00080000)
#define EP93XX_AAC_BASE EP93XX_APB_IOMEM(0x00080000)
#define EP93XX_SPI_PHYS_BASE EP93XX_APB_PHYS(0x000a0000)
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index 3330b36d79e6..50660455b1d8 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -61,6 +61,7 @@ void ep93xx_keypad_release_gpio(struct platform_device *pdev);
void ep93xx_register_i2s(void);
int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config);
void ep93xx_i2s_release(void);
+void ep93xx_register_ac97(void);
void ep93xx_init_devices(void);
extern struct sys_timer ep93xx_timer;
diff --git a/arch/arm/mach-ep93xx/simone.c b/arch/arm/mach-ep93xx/simone.c
index f22ce8db7947..d96dc1c5da20 100644
--- a/arch/arm/mach-ep93xx/simone.c
+++ b/arch/arm/mach-ep93xx/simone.c
@@ -61,6 +61,7 @@ static void __init simone_init_machine(void)
ep93xx_register_fb(&simone_fb_info);
ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info,
ARRAY_SIZE(simone_i2c_board_info));
+ ep93xx_register_ac97();
}
MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board")
diff --git a/arch/arm/mach-imx/include/mach/dma-v1.h b/arch/arm/mach-imx/include/mach/dma-v1.h
index 287431cc13e5..ac6fd713828a 100644
--- a/arch/arm/mach-imx/include/mach/dma-v1.h
+++ b/arch/arm/mach-imx/include/mach/dma-v1.h
@@ -27,6 +27,8 @@
#define imx_has_dma_v1() (cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27())
+#include <mach/dma.h>
+
#define IMX_DMA_CHANNELS 16
#define DMA_MODE_READ 0
@@ -96,12 +98,6 @@ int imx_dma_request(int channel, const char *name);
void imx_dma_free(int channel);
-enum imx_dma_prio {
- DMA_PRIO_HIGH = 0,
- DMA_PRIO_MEDIUM = 1,
- DMA_PRIO_LOW = 2
-};
-
int imx_dma_request_by_prio(const char *name, enum imx_dma_prio prio);
#endif /* __MACH_DMA_V1_H__ */
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index 1c82d4290dad..51ff23b72d3a 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -903,10 +903,16 @@ static struct platform_device kirkwood_i2s_device = {
},
};
+static struct platform_device kirkwood_pcm_device = {
+ .name = "kirkwood-pcm-audio",
+ .id = -1,
+};
+
void __init kirkwood_audio_init(void)
{
kirkwood_clk_ctrl |= CGC_AUDIO;
platform_device_register(&kirkwood_i2s_device);
+ platform_device_register(&kirkwood_pcm_device);
}
/*****************************************************************************
diff --git a/arch/arm/mach-kirkwood/netspace_v2-setup.c b/arch/arm/mach-kirkwood/netspace_v2-setup.c
index 5e286441b8f4..5ea66f1f4178 100644
--- a/arch/arm/mach-kirkwood/netspace_v2-setup.c
+++ b/arch/arm/mach-kirkwood/netspace_v2-setup.c
@@ -30,6 +30,7 @@
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
#include <linux/leds.h>
+#include <linux/gpio-fan.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/kirkwood.h>
@@ -137,6 +138,46 @@ static struct platform_device netspace_v2_leds = {
};
/*****************************************************************************
+ * GPIO fan
+ ****************************************************************************/
+
+/* Designed for fan 40x40x16: ADDA AD0412LB-D50 6000rpm@12v */
+static struct gpio_fan_speed netspace_max_v2_fan_speed[] = {
+ { 0, 0 },
+ { 1500, 15 },
+ { 1700, 14 },
+ { 1800, 13 },
+ { 2100, 12 },
+ { 3100, 11 },
+ { 3300, 10 },
+ { 4300, 9 },
+ { 5500, 8 },
+};
+
+static unsigned netspace_max_v2_fan_ctrl[] = { 22, 7, 33, 23 };
+
+static struct gpio_fan_alarm netspace_max_v2_fan_alarm = {
+ .gpio = 25,
+ .active_low = 1,
+};
+
+static struct gpio_fan_platform_data netspace_max_v2_fan_data = {
+ .num_ctrl = ARRAY_SIZE(netspace_max_v2_fan_ctrl),
+ .ctrl = netspace_max_v2_fan_ctrl,
+ .alarm = &netspace_max_v2_fan_alarm,
+ .num_speed = ARRAY_SIZE(netspace_max_v2_fan_speed),
+ .speed = netspace_max_v2_fan_speed,
+};
+
+static struct platform_device netspace_max_v2_gpio_fan = {
+ .name = "gpio-fan",
+ .id = -1,
+ .dev = {
+ .platform_data = &netspace_max_v2_fan_data,
+ },
+};
+
+/*****************************************************************************
* General Setup
****************************************************************************/
@@ -205,6 +246,8 @@ static void __init netspace_v2_init(void)
platform_device_register(&netspace_v2_leds);
platform_device_register(&netspace_v2_gpio_leds);
platform_device_register(&netspace_v2_gpio_buttons);
+ if (machine_is_netspace_max_v2())
+ platform_device_register(&netspace_max_v2_gpio_fan);
if (gpio_request(NETSPACE_V2_GPIO_POWER_OFF, "power-off") == 0 &&
gpio_direction_output(NETSPACE_V2_GPIO_POWER_OFF, 0) == 0)
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index 3b02d3b944af..5f6496375404 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -128,7 +128,7 @@ config MACH_OMAP_PALMTT
help
Support for the Palm Tungsten|T PDA. To boot the kernel, you'll
need a PalmOS compatible bootloader (Garux); check out
- http://www.hackndev.com/palm/tt/ for more information.
+ http://garux.sourceforge.net/ for more information.
Say Y here if you have this PDA model, say N otherwise.
config MACH_SX1
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index facfaeb1ae5c..9a304d854e33 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -12,7 +12,7 @@ obj-$(CONFIG_OMAP_MPU_TIMER) += time.o
obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o
# Power Management
-obj-$(CONFIG_PM) += pm.o sleep.o
+obj-$(CONFIG_PM) += pm.o sleep.o pm_bus.o
# DSP
obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
index 73c86392fcd3..1d4163b9f0b7 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -16,9 +16,12 @@
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
+#include <linux/leds.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
+#include <media/soc_camera.h>
+
#include <asm/serial.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
@@ -32,6 +35,7 @@
#include <plat/usb.h>
#include <plat/board.h>
#include <plat/common.h>
+#include <mach/camera.h>
#include <mach/ams-delta-fiq.h>
@@ -213,10 +217,56 @@ static struct platform_device ams_delta_led_device = {
.id = -1
};
+static struct i2c_board_info ams_delta_camera_board_info[] = {
+ {
+ I2C_BOARD_INFO("ov6650", 0x60),
+ },
+};
+
+#ifdef CONFIG_LEDS_TRIGGERS
+DEFINE_LED_TRIGGER(ams_delta_camera_led_trigger);
+
+static int ams_delta_camera_power(struct device *dev, int power)
+{
+ /*
+ * turn on camera LED
+ */
+ if (power)
+ led_trigger_event(ams_delta_camera_led_trigger, LED_FULL);
+ else
+ led_trigger_event(ams_delta_camera_led_trigger, LED_OFF);
+ return 0;
+}
+#else
+#define ams_delta_camera_power NULL
+#endif
+
+static struct soc_camera_link __initdata ams_delta_iclink = {
+ .bus_id = 0, /* OMAP1 SoC camera bus */
+ .i2c_adapter_id = 1,
+ .board_info = &ams_delta_camera_board_info[0],
+ .module_name = "ov6650",
+ .power = ams_delta_camera_power,
+};
+
+static struct platform_device ams_delta_camera_device = {
+ .name = "soc-camera-pdrv",
+ .id = 0,
+ .dev = {
+ .platform_data = &ams_delta_iclink,
+ },
+};
+
+static struct omap1_cam_platform_data ams_delta_camera_platform_data = {
+ .camexclk_khz = 12000, /* default 12MHz clock, no extra DPLL */
+ .lclk_khz_max = 1334, /* results in 5fps CIF, 10fps QCIF */
+};
+
static struct platform_device *ams_delta_devices[] __initdata = {
&ams_delta_kp_device,
&ams_delta_lcd_device,
&ams_delta_led_device,
+ &ams_delta_camera_device,
};
static void __init ams_delta_init(void)
@@ -225,6 +275,20 @@ static void __init ams_delta_init(void)
omap_cfg_reg(UART1_TX);
omap_cfg_reg(UART1_RTS);
+ /* parallel camera interface */
+ omap_cfg_reg(H19_1610_CAM_EXCLK);
+ omap_cfg_reg(J15_1610_CAM_LCLK);
+ omap_cfg_reg(L18_1610_CAM_VS);
+ omap_cfg_reg(L15_1610_CAM_HS);
+ omap_cfg_reg(L19_1610_CAM_D0);
+ omap_cfg_reg(K14_1610_CAM_D1);
+ omap_cfg_reg(K15_1610_CAM_D2);
+ omap_cfg_reg(K19_1610_CAM_D3);
+ omap_cfg_reg(K18_1610_CAM_D4);
+ omap_cfg_reg(J14_1610_CAM_D5);
+ omap_cfg_reg(J19_1610_CAM_D6);
+ omap_cfg_reg(J18_1610_CAM_D7);
+
iotable_init(ams_delta_io_desc, ARRAY_SIZE(ams_delta_io_desc));
omap_board_config = ams_delta_config;
@@ -236,6 +300,11 @@ static void __init ams_delta_init(void)
ams_delta_latch2_write(~0, 0);
omap1_usb_init(&ams_delta_usb_config);
+ omap1_set_camera_info(&ams_delta_camera_platform_data);
+#ifdef CONFIG_LEDS_TRIGGERS
+ led_trigger_register_simple("ams_delta_camera",
+ &ams_delta_camera_led_trigger);
+#endif
platform_add_devices(ams_delta_devices, ARRAY_SIZE(ams_delta_devices));
#ifdef CONFIG_AMS_DELTA_FIQ
diff --git a/arch/arm/mach-omap1/board-h2-mmc.c b/arch/arm/mach-omap1/board-h2-mmc.c
index b30c4990744d..f2fc43d8382b 100644
--- a/arch/arm/mach-omap1/board-h2-mmc.c
+++ b/arch/arm/mach-omap1/board-h2-mmc.c
@@ -58,8 +58,7 @@ static struct omap_mmc_platform_data mmc1_data = {
.dma_mask = 0xffffffff,
.slots[0] = {
.set_power = mmc_set_power,
- .ocr_mask = MMC_VDD_28_29 | MMC_VDD_30_31 |
- MMC_VDD_32_33 | MMC_VDD_33_34,
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.name = "mmcblk",
},
};
diff --git a/arch/arm/mach-omap1/board-h3-mmc.c b/arch/arm/mach-omap1/board-h3-mmc.c
index 54b0f063e263..2098525e7cc5 100644
--- a/arch/arm/mach-omap1/board-h3-mmc.c
+++ b/arch/arm/mach-omap1/board-h3-mmc.c
@@ -40,8 +40,7 @@ static struct omap_mmc_platform_data mmc1_data = {
.dma_mask = 0xffffffff,
.slots[0] = {
.set_power = mmc_set_power,
- .ocr_mask = MMC_VDD_28_29 | MMC_VDD_30_31 |
- MMC_VDD_32_33 | MMC_VDD_33_34,
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.name = "mmcblk",
},
};
diff --git a/arch/arm/mach-omap1/board-htcherald.c b/arch/arm/mach-omap1/board-htcherald.c
index 86afb2952225..071af3e47789 100644
--- a/arch/arm/mach-omap1/board-htcherald.c
+++ b/arch/arm/mach-omap1/board-htcherald.c
@@ -30,6 +30,13 @@
#include <linux/input.h>
#include <linux/io.h>
#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/htcpld.h>
+#include <linux/leds.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -39,6 +46,7 @@
#include <plat/board.h>
#include <plat/keypad.h>
#include <plat/usb.h>
+#include <plat/mmc.h>
#include <mach/irqs.h>
@@ -52,13 +60,123 @@
#define OMAP_LCDC_CTRL_LCD_EN (1 << 0)
#define OMAP_LCDC_STAT_DONE (1 << 0)
-static struct omap_lcd_config htcherald_lcd_config __initdata = {
- .ctrl_name = "internal",
-};
+/* GPIO definitions for the power button and keyboard slide switch */
+#define HTCHERALD_GPIO_POWER 139
+#define HTCHERALD_GPIO_SLIDE 174
+#define HTCHERALD_GIRQ_BTNS 141
-static struct omap_board_config_kernel htcherald_config[] __initdata = {
- { OMAP_TAG_LCD, &htcherald_lcd_config },
-};
+/* GPIO definitions for the touchscreen */
+#define HTCHERALD_GPIO_TS 76
+
+/* HTCPLD definitions */
+
+/*
+ * CPLD Logic
+ *
+ * Chip 3 - 0x03
+ *
+ * Function 7 6 5 4 3 2 1 0
+ * ------------------------------------
+ * DPAD light x x x x x x x 1
+ * SoundDev x x x x 1 x x x
+ * Screen white 1 x x x x x x x
+ * MMC power on x x x x x 1 x x
+ * Happy times (n) 0 x x x x 1 x x
+ *
+ * Chip 4 - 0x04
+ *
+ * Function 7 6 5 4 3 2 1 0
+ * ------------------------------------
+ * Keyboard light x x x x x x x 1
+ * LCD Bright (4) x x x x x 1 1 x
+ * LCD Bright (3) x x x x x 0 1 x
+ * LCD Bright (2) x x x x x 1 0 x
+ * LCD Bright (1) x x x x x 0 0 x
+ * LCD Off x x x x 0 x x x
+ * LCD image (fb) 1 x x x x x x x
+ * LCD image (white) 0 x x x x x x x
+ * Caps lock LED x x 1 x x x x x
+ *
+ * Chip 5 - 0x05
+ *
+ * Function 7 6 5 4 3 2 1 0
+ * ------------------------------------
+ * Red (solid) x x x x x 1 x x
+ * Red (flash) x x x x x x 1 x
+ * Green (GSM flash) x x x x 1 x x x
+ * Green (GSM solid) x x x 1 x x x x
+ * Green (wifi flash) x x 1 x x x x x
+ * Blue (bt flash) x 1 x x x x x x
+ * DPAD Int Enable 1 x x x x x x 0
+ *
+ * (Combinations of the above can be made for different colors.)
+ * The direction pad interrupt enable must be set each time the
+ * interrupt is handled.
+ *
+ * Chip 6 - 0x06
+ *
+ * Function 7 6 5 4 3 2 1 0
+ * ------------------------------------
+ * Vibrator x x x x 1 x x x
+ * Alt LED x x x 1 x x x x
+ * Screen white 1 x x x x x x x
+ * Screen white x x 1 x x x x x
+ * Screen white x 0 x x x x x x
+ * Enable kbd dpad x x x x x x 0 x
+ * Happy Times 0 1 0 x x x 0 x
+ */
+
+/*
+ * HTCPLD GPIO lines start 16 after OMAP_MAX_GPIO_LINES to account
+ * for the 16 MPUIO lines.
+ */
+#define HTCPLD_GPIO_START_OFFSET (OMAP_MAX_GPIO_LINES + 16)
+#define HTCPLD_IRQ(chip, offset) (OMAP_IRQ_END + 8 * (chip) + (offset))
+#define HTCPLD_BASE(chip, offset) \
+ (HTCPLD_GPIO_START_OFFSET + 8 * (chip) + (offset))
+
+#define HTCPLD_GPIO_LED_DPAD HTCPLD_BASE(0, 0)
+#define HTCPLD_GPIO_LED_KBD HTCPLD_BASE(1, 0)
+#define HTCPLD_GPIO_LED_CAPS HTCPLD_BASE(1, 5)
+#define HTCPLD_GPIO_LED_RED_FLASH HTCPLD_BASE(2, 1)
+#define HTCPLD_GPIO_LED_RED_SOLID HTCPLD_BASE(2, 2)
+#define HTCPLD_GPIO_LED_GREEN_FLASH HTCPLD_BASE(2, 3)
+#define HTCPLD_GPIO_LED_GREEN_SOLID HTCPLD_BASE(2, 4)
+#define HTCPLD_GPIO_LED_WIFI HTCPLD_BASE(2, 5)
+#define HTCPLD_GPIO_LED_BT HTCPLD_BASE(2, 6)
+#define HTCPLD_GPIO_LED_VIBRATE HTCPLD_BASE(3, 3)
+#define HTCPLD_GPIO_LED_ALT HTCPLD_BASE(3, 4)
+
+#define HTCPLD_GPIO_RIGHT_KBD HTCPLD_BASE(6, 7)
+#define HTCPLD_GPIO_UP_KBD HTCPLD_BASE(6, 6)
+#define HTCPLD_GPIO_LEFT_KBD HTCPLD_BASE(6, 5)
+#define HTCPLD_GPIO_DOWN_KBD HTCPLD_BASE(6, 4)
+
+#define HTCPLD_GPIO_RIGHT_DPAD HTCPLD_BASE(7, 7)
+#define HTCPLD_GPIO_UP_DPAD HTCPLD_BASE(7, 6)
+#define HTCPLD_GPIO_LEFT_DPAD HTCPLD_BASE(7, 5)
+#define HTCPLD_GPIO_DOWN_DPAD HTCPLD_BASE(7, 4)
+#define HTCPLD_GPIO_ENTER_DPAD HTCPLD_BASE(7, 3)
+
+/*
+ * The htcpld chip requires a gpio write to a specific line
+ * to re-enable interrupts after one has occurred.
+ */
+#define HTCPLD_GPIO_INT_RESET_HI HTCPLD_BASE(2, 7)
+#define HTCPLD_GPIO_INT_RESET_LO HTCPLD_BASE(2, 0)
+
+/* Chip 5 */
+#define HTCPLD_IRQ_RIGHT_KBD HTCPLD_IRQ(0, 7)
+#define HTCPLD_IRQ_UP_KBD HTCPLD_IRQ(0, 6)
+#define HTCPLD_IRQ_LEFT_KBD HTCPLD_IRQ(0, 5)
+#define HTCPLD_IRQ_DOWN_KBD HTCPLD_IRQ(0, 4)
+
+/* Chip 6 */
+#define HTCPLD_IRQ_RIGHT_DPAD HTCPLD_IRQ(1, 7)
+#define HTCPLD_IRQ_UP_DPAD HTCPLD_IRQ(1, 6)
+#define HTCPLD_IRQ_LEFT_DPAD HTCPLD_IRQ(1, 5)
+#define HTCPLD_IRQ_DOWN_DPAD HTCPLD_IRQ(1, 4)
+#define HTCPLD_IRQ_ENTER_DPAD HTCPLD_IRQ(1, 3)
/* Keyboard definition */
@@ -140,6 +258,129 @@ static struct platform_device kp_device = {
.resource = kp_resources,
};
+/* GPIO buttons for keyboard slide and power button */
+static struct gpio_keys_button herald_gpio_keys_table[] = {
+ {BTN_0, HTCHERALD_GPIO_POWER, 1, "POWER", EV_KEY, 1, 20},
+ {SW_LID, HTCHERALD_GPIO_SLIDE, 0, "SLIDE", EV_SW, 1, 20},
+
+ {KEY_LEFT, HTCPLD_GPIO_LEFT_KBD, 1, "LEFT", EV_KEY, 1, 20},
+ {KEY_RIGHT, HTCPLD_GPIO_RIGHT_KBD, 1, "RIGHT", EV_KEY, 1, 20},
+ {KEY_UP, HTCPLD_GPIO_UP_KBD, 1, "UP", EV_KEY, 1, 20},
+ {KEY_DOWN, HTCPLD_GPIO_DOWN_KBD, 1, "DOWN", EV_KEY, 1, 20},
+
+ {KEY_LEFT, HTCPLD_GPIO_LEFT_DPAD, 1, "DLEFT", EV_KEY, 1, 20},
+ {KEY_RIGHT, HTCPLD_GPIO_RIGHT_DPAD, 1, "DRIGHT", EV_KEY, 1, 20},
+ {KEY_UP, HTCPLD_GPIO_UP_DPAD, 1, "DUP", EV_KEY, 1, 20},
+ {KEY_DOWN, HTCPLD_GPIO_DOWN_DPAD, 1, "DDOWN", EV_KEY, 1, 20},
+ {KEY_ENTER, HTCPLD_GPIO_ENTER_DPAD, 1, "DENTER", EV_KEY, 1, 20},
+};
+
+static struct gpio_keys_platform_data herald_gpio_keys_data = {
+ .buttons = herald_gpio_keys_table,
+ .nbuttons = ARRAY_SIZE(herald_gpio_keys_table),
+ .rep = 1,
+};
+
+static struct platform_device herald_gpiokeys_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &herald_gpio_keys_data,
+ },
+};
+
+/* LEDs for the Herald. These connect to the HTCPLD GPIO device. */
+static struct gpio_led gpio_leds[] = {
+ {"dpad", NULL, HTCPLD_GPIO_LED_DPAD, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+ {"kbd", NULL, HTCPLD_GPIO_LED_KBD, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+ {"vibrate", NULL, HTCPLD_GPIO_LED_VIBRATE, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+ {"green_solid", NULL, HTCPLD_GPIO_LED_GREEN_SOLID, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+ {"green_flash", NULL, HTCPLD_GPIO_LED_GREEN_FLASH, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+ {"red_solid", "mmc0", HTCPLD_GPIO_LED_RED_SOLID, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+ {"red_flash", NULL, HTCPLD_GPIO_LED_RED_FLASH, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+ {"wifi", NULL, HTCPLD_GPIO_LED_WIFI, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+ {"bt", NULL, HTCPLD_GPIO_LED_BT, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+ {"caps", NULL, HTCPLD_GPIO_LED_CAPS, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+ {"alt", NULL, HTCPLD_GPIO_LED_ALT, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+};
+
+static struct gpio_led_platform_data gpio_leds_data = {
+ .leds = gpio_leds,
+ .num_leds = ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device gpio_leds_device = {
+ .name = "leds-gpio",
+ .id = 0,
+ .dev = {
+ .platform_data = &gpio_leds_data,
+ },
+};
+
+/* HTC PLD chips */
+
+static struct resource htcpld_resources[] = {
+ [0] = {
+ .start = OMAP_GPIO_IRQ(HTCHERALD_GIRQ_BTNS),
+ .end = OMAP_GPIO_IRQ(HTCHERALD_GIRQ_BTNS),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct htcpld_chip_platform_data htcpld_chips[] = {
+ [0] = {
+ .addr = 0x03,
+ .reset = 0x04,
+ .num_gpios = 8,
+ .gpio_out_base = HTCPLD_BASE(0, 0),
+ .gpio_in_base = HTCPLD_BASE(4, 0),
+ },
+ [1] = {
+ .addr = 0x04,
+ .reset = 0x8e,
+ .num_gpios = 8,
+ .gpio_out_base = HTCPLD_BASE(1, 0),
+ .gpio_in_base = HTCPLD_BASE(5, 0),
+ },
+ [2] = {
+ .addr = 0x05,
+ .reset = 0x80,
+ .num_gpios = 8,
+ .gpio_out_base = HTCPLD_BASE(2, 0),
+ .gpio_in_base = HTCPLD_BASE(6, 0),
+ .irq_base = HTCPLD_IRQ(0, 0),
+ .num_irqs = 8,
+ },
+ [3] = {
+ .addr = 0x06,
+ .reset = 0x40,
+ .num_gpios = 8,
+ .gpio_out_base = HTCPLD_BASE(3, 0),
+ .gpio_in_base = HTCPLD_BASE(7, 0),
+ .irq_base = HTCPLD_IRQ(1, 0),
+ .num_irqs = 8,
+ },
+};
+
+struct htcpld_core_platform_data htcpld_pfdata = {
+ .int_reset_gpio_hi = HTCPLD_GPIO_INT_RESET_HI,
+ .int_reset_gpio_lo = HTCPLD_GPIO_INT_RESET_LO,
+ .i2c_adapter_id = 1,
+
+ .chip = htcpld_chips,
+ .num_chip = ARRAY_SIZE(htcpld_chips),
+};
+
+static struct platform_device htcpld_device = {
+ .name = "i2c-htcpld",
+ .id = -1,
+ .resource = htcpld_resources,
+ .num_resources = ARRAY_SIZE(htcpld_resources),
+ .dev = {
+ .platform_data = &htcpld_pfdata,
+ },
+};
+
/* USB Device */
static struct omap_usb_config htcherald_usb_config __initdata = {
.otg = 0,
@@ -150,14 +391,71 @@ static struct omap_usb_config htcherald_usb_config __initdata = {
};
/* LCD Device resources */
+static struct omap_lcd_config htcherald_lcd_config __initdata = {
+ .ctrl_name = "internal",
+};
+
+static struct omap_board_config_kernel htcherald_config[] __initdata = {
+ { OMAP_TAG_LCD, &htcherald_lcd_config },
+};
+
static struct platform_device lcd_device = {
.name = "lcd_htcherald",
.id = -1,
};
+/* MMC Card */
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+static struct omap_mmc_platform_data htc_mmc1_data = {
+ .nr_slots = 1,
+ .switch_slot = NULL,
+ .slots[0] = {
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .name = "mmcblk",
+ .nomux = 1,
+ .wires = 4,
+ .switch_pin = -1,
+ },
+};
+
+static struct omap_mmc_platform_data *htc_mmc_data[1];
+#endif
+
+
+/* Platform devices for the Herald */
static struct platform_device *devices[] __initdata = {
&kp_device,
&lcd_device,
+ &htcpld_device,
+ &gpio_leds_device,
+ &herald_gpiokeys_device,
+};
+
+/*
+ * Touchscreen
+ */
+static const struct ads7846_platform_data htcherald_ts_platform_data = {
+ .model = 7846,
+ .keep_vref_on = 1,
+ .x_plate_ohms = 496,
+ .gpio_pendown = HTCHERALD_GPIO_TS,
+ .pressure_max = 100000,
+ .pressure_min = 5000,
+ .x_min = 528,
+ .x_max = 3760,
+ .y_min = 624,
+ .y_max = 3760,
+};
+
+static struct spi_board_info __initdata htcherald_spi_board_info[] = {
+ {
+ .modalias = "ads7846",
+ .platform_data = &htcherald_ts_platform_data,
+ .irq = OMAP_GPIO_IRQ(HTCHERALD_GPIO_TS),
+ .max_speed_hz = 2500000,
+ .bus_num = 2,
+ .chip_select = 1,
+ }
};
/*
@@ -278,6 +576,7 @@ static void __init htcherald_init(void)
{
printk(KERN_INFO "HTC Herald init.\n");
+ /* Do board initialization before we register all the devices */
omap_gpio_init();
omap_board_config = htcherald_config;
@@ -288,6 +587,16 @@ static void __init htcherald_init(void)
htcherald_usb_enable();
omap1_usb_init(&htcherald_usb_config);
+
+ spi_register_board_info(htcherald_spi_board_info,
+ ARRAY_SIZE(htcherald_spi_board_info));
+
+ omap_register_i2c_bus(1, 100, NULL, 0);
+
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+ htc_mmc_data[0] = &htc_mmc1_data;
+ omap1_init_mmc(htc_mmc_data, 1);
+#endif
}
static void __init htcherald_init_irq(void)
diff --git a/arch/arm/mach-omap1/board-sx1-mmc.c b/arch/arm/mach-omap1/board-sx1-mmc.c
index 5b33ae8141bc..e8ddd86e3fda 100644
--- a/arch/arm/mach-omap1/board-sx1-mmc.c
+++ b/arch/arm/mach-omap1/board-sx1-mmc.c
@@ -44,8 +44,7 @@ static struct omap_mmc_platform_data mmc1_data = {
.nr_slots = 1,
.slots[0] = {
.set_power = mmc_set_power,
- .ocr_mask = MMC_VDD_28_29 | MMC_VDD_30_31 |
- MMC_VDD_32_33 | MMC_VDD_33_34,
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.name = "mmcblk",
},
};
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index aa0725608fb1..ea0d80a89da7 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -9,6 +9,7 @@
* (at your option) any later version.
*/
+#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -25,6 +26,7 @@
#include <mach/gpio.h>
#include <plat/mmc.h>
#include <plat/omap7xx.h>
+#include <plat/mcbsp.h>
/*-------------------------------------------------------------------------*/
@@ -191,10 +193,76 @@ static inline void omap_init_spi100k(void)
}
#endif
+
+#define OMAP1_CAMERA_BASE 0xfffb6800
+#define OMAP1_CAMERA_IOSIZE 0x1c
+
+static struct resource omap1_camera_resources[] = {
+ [0] = {
+ .start = OMAP1_CAMERA_BASE,
+ .end = OMAP1_CAMERA_BASE + OMAP1_CAMERA_IOSIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = INT_CAMERA,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 omap1_camera_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device omap1_camera_device = {
+ .name = "omap1-camera",
+ .id = 0, /* This is used to put cameras on this interface */
+ .dev = {
+ .dma_mask = &omap1_camera_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .num_resources = ARRAY_SIZE(omap1_camera_resources),
+ .resource = omap1_camera_resources,
+};
+
+void __init omap1_camera_init(void *info)
+{
+ struct platform_device *dev = &omap1_camera_device;
+ int ret;
+
+ dev->dev.platform_data = info;
+
+ ret = platform_device_register(dev);
+ if (ret)
+ dev_err(&dev->dev, "unable to register device: %d\n", ret);
+}
+
+
/*-------------------------------------------------------------------------*/
static inline void omap_init_sti(void) {}
+#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
+
+static struct platform_device omap_pcm = {
+ .name = "omap-pcm-audio",
+ .id = -1,
+};
+
+OMAP_MCBSP_PLATFORM_DEVICE(1);
+OMAP_MCBSP_PLATFORM_DEVICE(2);
+OMAP_MCBSP_PLATFORM_DEVICE(3);
+
+static void omap_init_audio(void)
+{
+ platform_device_register(&omap_mcbsp1);
+ platform_device_register(&omap_mcbsp2);
+ if (!cpu_is_omap7xx())
+ platform_device_register(&omap_mcbsp3);
+ platform_device_register(&omap_pcm);
+}
+
+#else
+static inline void omap_init_audio(void) {}
+#endif
+
/*-------------------------------------------------------------------------*/
/*
@@ -227,8 +295,36 @@ static int __init omap1_init_devices(void)
omap_init_rtc();
omap_init_spi100k();
omap_init_sti();
+ omap_init_audio();
return 0;
}
arch_initcall(omap1_init_devices);
+#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
+
+static struct resource wdt_resources[] = {
+ {
+ .start = 0xfffeb000,
+ .end = 0xfffeb07F,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device omap_wdt_device = {
+ .name = "omap_wdt",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(wdt_resources),
+ .resource = wdt_resources,
+};
+
+static int __init omap_init_wdt(void)
+{
+ if (!cpu_is_omap16xx())
+ return;
+
+ platform_device_register(&omap_wdt_device);
+ return 0;
+}
+subsys_initcall(omap_init_wdt);
+#endif
diff --git a/arch/arm/mach-omap1/include/mach/camera.h b/arch/arm/mach-omap1/include/mach/camera.h
new file mode 100644
index 000000000000..fd54b452eb22
--- /dev/null
+++ b/arch/arm/mach-omap1/include/mach/camera.h
@@ -0,0 +1,11 @@
+#ifndef __ASM_ARCH_CAMERA_H_
+#define __ASM_ARCH_CAMERA_H_
+
+void omap1_camera_init(void *);
+
+static inline void omap1_set_camera_info(struct omap1_cam_platform_data *info)
+{
+ omap1_camera_init(info);
+}
+
+#endif /* __ASM_ARCH_CAMERA_H_ */
diff --git a/arch/arm/mach-omap1/pm_bus.c b/arch/arm/mach-omap1/pm_bus.c
new file mode 100644
index 000000000000..8b66392be745
--- /dev/null
+++ b/arch/arm/mach-omap1/pm_bus.c
@@ -0,0 +1,98 @@
+/*
+ * Runtime PM support code for OMAP1
+ *
+ * Author: Kevin Hilman, Deep Root Systems, LLC
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <plat/omap_device.h>
+#include <plat/omap-pm.h>
+
+#ifdef CONFIG_PM_RUNTIME
+static int omap1_pm_runtime_suspend(struct device *dev)
+{
+ struct clk *iclk, *fclk;
+ int ret = 0;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ ret = pm_generic_runtime_suspend(dev);
+
+ fclk = clk_get(dev, "fck");
+ if (!IS_ERR(fclk)) {
+ clk_disable(fclk);
+ clk_put(fclk);
+ }
+
+ iclk = clk_get(dev, "ick");
+ if (!IS_ERR(iclk)) {
+ clk_disable(iclk);
+ clk_put(iclk);
+ }
+
+ return 0;
+};
+
+static int omap1_pm_runtime_resume(struct device *dev)
+{
+ int ret = 0;
+ struct clk *iclk, *fclk;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ iclk = clk_get(dev, "ick");
+ if (!IS_ERR(iclk)) {
+ clk_enable(iclk);
+ clk_put(iclk);
+ }
+
+ fclk = clk_get(dev, "fck");
+ if (!IS_ERR(fclk)) {
+ clk_enable(fclk);
+ clk_put(fclk);
+ }
+
+ return pm_generic_runtime_resume(dev);
+};
+
+static int __init omap1_pm_runtime_init(void)
+{
+ const struct dev_pm_ops *pm;
+ struct dev_pm_ops *omap_pm;
+
+ pm = platform_bus_get_pm_ops();
+ if (!pm) {
+ pr_err("%s: unable to get dev_pm_ops from platform_bus\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ omap_pm = kmemdup(pm, sizeof(struct dev_pm_ops), GFP_KERNEL);
+ if (!omap_pm) {
+ pr_err("%s: unable to alloc memory for new dev_pm_ops\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ omap_pm->runtime_suspend = omap1_pm_runtime_suspend;
+ omap_pm->runtime_resume = omap1_pm_runtime_resume;
+
+ platform_bus_set_pm_ops(omap_pm);
+
+ return 0;
+}
+core_initcall(omap1_pm_runtime_init);
+#endif /* CONFIG_PM_RUNTIME */
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index b48bacf0a7aa..ab784bfde908 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -11,9 +11,8 @@ config ARCH_OMAP2PLUS_TYPICAL
select PM_RUNTIME
select VFP
select NEON if ARCH_OMAP3 || ARCH_OMAP4
- select SERIAL_8250
- select SERIAL_CORE_CONSOLE
- select SERIAL_8250_CONSOLE
+ select SERIAL_OMAP
+ select SERIAL_OMAP_CONSOLE
select I2C
select I2C_OMAP
select MFD
@@ -35,7 +34,7 @@ config ARCH_OMAP3
default y
select CPU_V7
select USB_ARCH_HAS_EHCI
- select ARM_L1_CACHE_SHIFT_6
+ select ARM_L1_CACHE_SHIFT_6 if !ARCH_OMAP4
config ARCH_OMAP4
bool "TI OMAP4"
@@ -43,6 +42,8 @@ config ARCH_OMAP4
depends on ARCH_OMAP2PLUS
select CPU_V7
select ARM_GIC
+ select PL310_ERRATA_588369
+ select ARM_ERRATA_720789
comment "OMAP Core Type"
depends on ARCH_OMAP2
@@ -99,20 +100,20 @@ config MACH_OMAP2_TUSB6010
config MACH_OMAP_H4
bool "OMAP 2420 H4 board"
- depends on ARCH_OMAP2
+ depends on ARCH_OMAP2420
default y
select OMAP_PACKAGE_ZAF
select OMAP_DEBUG_DEVICES
config MACH_OMAP_APOLLON
bool "OMAP 2420 Apollon board"
- depends on ARCH_OMAP2
+ depends on ARCH_OMAP2420
default y
select OMAP_PACKAGE_ZAC
config MACH_OMAP_2430SDP
bool "OMAP 2430 SDP board"
- depends on ARCH_OMAP2
+ depends on ARCH_OMAP2430
default y
select OMAP_PACKAGE_ZAC
@@ -135,6 +136,26 @@ config MACH_OMAP_LDP
default y
select OMAP_PACKAGE_CBB
+config MACH_OMAP3530_LV_SOM
+ bool "OMAP3 Logic 3530 LV SOM board"
+ depends on ARCH_OMAP3
+ select OMAP_PACKAGE_CBB
+ default y
+ help
+ Support for the LogicPD OMAP3530 SOM Development kit
+ for full description please see the products webpage at
+ http://www.logicpd.com/products/development-kits/texas-instruments-zoom%E2%84%A2-omap35x-development-kit
+
+config MACH_OMAP3_TORPEDO
+ bool "OMAP3 Logic 35x Torpedo board"
+ depends on ARCH_OMAP3
+ select OMAP_PACKAGE_CBB
+ default y
+ help
+ Support for the LogicPD OMAP35x Torpedo Development kit
+ for full description please see the products webpage at
+ http://www.logicpd.com/products/development-kits/zoom-omap35x-torpedo-development-kit
+
config MACH_OVERO
bool "Gumstix Overo board"
depends on ARCH_OMAP3
@@ -200,12 +221,18 @@ config MACH_OMAP_ZOOM2
depends on ARCH_OMAP3
default y
select OMAP_PACKAGE_CBB
+ select SERIAL_8250
+ select SERIAL_CORE_CONSOLE
+ select SERIAL_8250_CONSOLE
config MACH_OMAP_ZOOM3
bool "OMAP3630 Zoom3 board"
depends on ARCH_OMAP3
default y
select OMAP_PACKAGE_CBP
+ select SERIAL_8250
+ select SERIAL_CORE_CONSOLE
+ select SERIAL_8250_CONSOLE
config MACH_CM_T35
bool "CompuLab CM-T35 module"
@@ -214,12 +241,25 @@ config MACH_CM_T35
select OMAP_PACKAGE_CUS
select OMAP_MUX
+config MACH_CM_T3517
+ bool "CompuLab CM-T3517 module"
+ depends on ARCH_OMAP3
+ default y
+ select OMAP_PACKAGE_CBB
+ select OMAP_MUX
+
config MACH_IGEP0020
bool "IGEP v2 board"
depends on ARCH_OMAP3
default y
select OMAP_PACKAGE_CBB
+config MACH_IGEP0030
+ bool "IGEP OMAP3 module"
+ depends on ARCH_OMAP3
+ default y
+ select OMAP_PACKAGE_CBB
+
config MACH_SBC3530
bool "OMAP3 SBC STALKER board"
depends on ARCH_OMAP3
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 88d3a1e920f5..7352412e4917 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -3,9 +3,10 @@
#
# Common support
-obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o pm.o
+obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o pm.o \
+ common.o
-omap-2-3-common = irq.o sdrc.o
+omap-2-3-common = irq.o sdrc.o prm2xxx_3xxx.o
hwmod-common = omap_hwmod.o \
omap_hwmod_common_data.o
prcm-common = prcm.o powerdomain.o
@@ -15,7 +16,7 @@ clock-common = clock.o clock_common_data.o \
obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(hwmod-common)
obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(hwmod-common)
-obj-$(CONFIG_ARCH_OMAP4) += $(prcm-common) $(hwmod-common)
+obj-$(CONFIG_ARCH_OMAP4) += $(prcm-common) prm44xx.o $(hwmod-common)
obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
@@ -49,14 +50,18 @@ obj-$(CONFIG_ARCH_OMAP2) += sdrc2xxx.o
# Power Management
ifeq ($(CONFIG_PM),y)
obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o
-obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o
-obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o cpuidle34xx.o
-obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o
+obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o pm_bus.o
+obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o cpuidle34xx.o pm_bus.o
+obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o pm_bus.o
obj-$(CONFIG_PM_DEBUG) += pm-debug.o
AFLAGS_sleep24xx.o :=-Wa,-march=armv6
AFLAGS_sleep34xx.o :=-Wa,-march=armv7-a
+ifeq ($(CONFIG_PM_VERBOSE),y)
+CFLAGS_pm_bus.o += -DDEBUG
+endif
+
endif
# PRCM
@@ -87,6 +92,7 @@ obj-$(CONFIG_ARCH_OMAP2430) += opp2430_data.o
obj-$(CONFIG_ARCH_OMAP2420) += omap_hwmod_2420_data.o
obj-$(CONFIG_ARCH_OMAP2430) += omap_hwmod_2430_data.o
obj-$(CONFIG_ARCH_OMAP3) += omap_hwmod_3xxx_data.o
+obj-$(CONFIG_ARCH_OMAP4) += omap_hwmod_44xx_data.o
# EMU peripherals
obj-$(CONFIG_OMAP3_EMU) += emu.o
@@ -115,6 +121,10 @@ obj-$(CONFIG_MACH_DEVKIT8000) += board-devkit8000.o \
obj-$(CONFIG_MACH_OMAP_LDP) += board-ldp.o \
board-flash.o \
hsmmc.o
+obj-$(CONFIG_MACH_OMAP3530_LV_SOM) += board-omap3logic.o \
+ hsmmc.o
+obj-$(CONFIG_MACH_OMAP3_TORPEDO) += board-omap3logic.o \
+ hsmmc.o
obj-$(CONFIG_MACH_OVERO) += board-overo.o \
hsmmc.o
obj-$(CONFIG_MACH_OMAP3EVM) += board-omap3evm.o \
@@ -146,8 +156,11 @@ obj-$(CONFIG_MACH_OMAP_3630SDP) += board-3630sdp.o \
hsmmc.o
obj-$(CONFIG_MACH_CM_T35) += board-cm-t35.o \
hsmmc.o
+obj-$(CONFIG_MACH_CM_T3517) += board-cm-t3517.o
obj-$(CONFIG_MACH_IGEP0020) += board-igep0020.o \
hsmmc.o
+obj-$(CONFIG_MACH_IGEP0030) += board-igep0030.o \
+ hsmmc.o
obj-$(CONFIG_MACH_OMAP3_TOUCHBOOK) += board-omap3touchbook.o \
hsmmc.o
obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o \
@@ -174,3 +187,6 @@ obj-y += $(nand-m) $(nand-y)
smc91x-$(CONFIG_SMC91X) := gpmc-smc91x.o
obj-y += $(smc91x-m) $(smc91x-y)
+
+smsc911x-$(CONFIG_SMSC911X) := gpmc-smsc911x.o
+obj-y += $(smsc911x-m) $(smsc911x-y)
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index b857ce484510..b527f8d187ad 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -19,6 +19,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
+#include <linux/mmc/host.h>
#include <linux/delay.h>
#include <linux/i2c/twl.h>
#include <linux/err.h>
@@ -190,7 +191,7 @@ static int __init omap2430_i2c_init(void)
static struct omap2_hsmmc_info mmc[] __initdata = {
{
.mmc = 1,
- .wires = 4,
+ .caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.ext_clock = 1,
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index a5b095cf2adc..4e3742c512b8 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -24,6 +24,7 @@
#include <linux/regulator/machine.h>
#include <linux/io.h>
#include <linux/gpio.h>
+#include <linux/mmc/host.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
@@ -38,15 +39,14 @@
#include <plat/gpmc.h>
#include <plat/display.h>
-#include <plat/control.h>
#include <plat/gpmc-smc91x.h>
-#include <mach/board-flash.h>
-
+#include "board-flash.h"
#include "mux.h"
#include "sdram-qimonda-hyb18m512160af-6.h"
#include "hsmmc.h"
#include "pm.h"
+#include "control.h"
#define CONFIG_DISABLE_HFCLK 1
@@ -76,7 +76,7 @@ static struct cpuidle_params omap3_cpuidle_params_table[] = {
{1, 10000, 30000, 300000},
};
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
KEY(0, 0, KEY_LEFT),
KEY(0, 1, KEY_RIGHT),
KEY(0, 2, KEY_A),
@@ -353,12 +353,12 @@ static struct omap2_hsmmc_info mmc[] = {
/* 8 bits (default) requires S6.3 == ON,
* so the SIM card isn't used; else 4 bits.
*/
- .wires = 8,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
.gpio_wp = 4,
},
{
.mmc = 2,
- .wires = 8,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
.gpio_wp = 7,
},
{} /* Terminator */
diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c
index fd27ac0860b0..bbcf580fa097 100644
--- a/arch/arm/mach-omap2/board-3630sdp.c
+++ b/arch/arm/mach-omap2/board-3630sdp.c
@@ -21,8 +21,8 @@
#include <plat/usb.h>
#include <mach/board-zoom.h>
-#include <mach/board-flash.h>
+#include "board-flash.h"
#include "mux.h"
#include "sdram-hynix-h8mbx00u0mer-0em.h"
@@ -208,7 +208,6 @@ static struct flash_partitions sdp_flash_partitions[] = {
static void __init omap_sdp_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBP);
- omap_serial_init();
zoom_peripherals_init();
board_smc91x_init();
board_flash_init(sdp_flash_partitions, chip_sel_sdp);
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index 0b6a65f3a10a..69a4ae971e41 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -20,6 +20,7 @@
#include <linux/usb/otg.h>
#include <linux/spi/spi.h>
#include <linux/i2c/twl.h>
+#include <linux/gpio_keys.h>
#include <linux/regulator/machine.h>
#include <linux/leds.h>
@@ -31,15 +32,18 @@
#include <plat/board.h>
#include <plat/common.h>
-#include <plat/control.h>
-#include <plat/timer-gp.h>
#include <plat/usb.h>
#include <plat/mmc.h>
+
#include "hsmmc.h"
+#include "timer-gp.h"
+#include "control.h"
#define ETH_KS8851_IRQ 34
#define ETH_KS8851_POWER_ON 48
#define ETH_KS8851_QUART 138
+#define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO 184
+#define OMAP4_SFH7741_ENABLE_GPIO 188
static struct gpio_led sdp4430_gpio_leds[] = {
{
@@ -77,11 +81,47 @@ static struct gpio_led sdp4430_gpio_leds[] = {
};
+static struct gpio_keys_button sdp4430_gpio_keys[] = {
+ {
+ .desc = "Proximity Sensor",
+ .type = EV_SW,
+ .code = SW_FRONT_PROXIMITY,
+ .gpio = OMAP4_SFH7741_SENSOR_OUTPUT_GPIO,
+ .active_low = 0,
+ }
+};
+
static struct gpio_led_platform_data sdp4430_led_data = {
.leds = sdp4430_gpio_leds,
.num_leds = ARRAY_SIZE(sdp4430_gpio_leds),
};
+static int omap_prox_activate(struct device *dev)
+{
+ gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 1);
+ return 0;
+}
+
+static void omap_prox_deactivate(struct device *dev)
+{
+ gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 0);
+}
+
+static struct gpio_keys_platform_data sdp4430_gpio_keys_data = {
+ .buttons = sdp4430_gpio_keys,
+ .nbuttons = ARRAY_SIZE(sdp4430_gpio_keys),
+ .enable = omap_prox_activate,
+ .disable = omap_prox_deactivate,
+};
+
+static struct platform_device sdp4430_gpio_keys_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &sdp4430_gpio_keys_data,
+ },
+};
+
static struct platform_device sdp4430_leds_gpio = {
.name = "leds-gpio",
.id = -1,
@@ -161,6 +201,7 @@ static struct platform_device sdp4430_lcd_device = {
static struct platform_device *sdp4430_devices[] __initdata = {
&sdp4430_lcd_device,
+ &sdp4430_gpio_keys_device,
&sdp4430_leds_gpio,
};
@@ -193,15 +234,16 @@ static struct omap_musb_board_data musb_board_data = {
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
- .wires = 8,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
.gpio_wp = -EINVAL,
},
{
.mmc = 2,
- .wires = 8,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.nonremovable = true,
+ .ocr_mask = MMC_VDD_29_30,
},
{} /* Terminator */
};
@@ -235,8 +277,14 @@ static int omap4_twl6030_hsmmc_late_init(struct device *dev)
static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
{
- struct omap_mmc_platform_data *pdata = dev->platform_data;
+ struct omap_mmc_platform_data *pdata;
+ /* dev can be null if CONFIG_MMC_OMAP_HS is not set */
+ if (!dev) {
+ pr_err("Failed %s\n", __func__);
+ return;
+ }
+ pdata = dev->platform_data;
pdata->init = omap4_twl6030_hsmmc_late_init;
}
@@ -412,6 +460,11 @@ static struct i2c_board_info __initdata sdp4430_i2c_3_boardinfo[] = {
I2C_BOARD_INFO("tmp105", 0x48),
},
};
+static struct i2c_board_info __initdata sdp4430_i2c_4_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("hmc5843", 0x1e),
+ },
+};
static int __init omap4_i2c_init(void)
{
/*
@@ -423,14 +476,36 @@ static int __init omap4_i2c_init(void)
omap_register_i2c_bus(2, 400, NULL, 0);
omap_register_i2c_bus(3, 400, sdp4430_i2c_3_boardinfo,
ARRAY_SIZE(sdp4430_i2c_3_boardinfo));
- omap_register_i2c_bus(4, 400, NULL, 0);
+ omap_register_i2c_bus(4, 400, sdp4430_i2c_4_boardinfo,
+ ARRAY_SIZE(sdp4430_i2c_4_boardinfo));
return 0;
}
+
+static void __init omap_sfh7741prox_init(void)
+{
+ int error;
+
+ error = gpio_request(OMAP4_SFH7741_ENABLE_GPIO, "sfh7741");
+ if (error < 0) {
+ pr_err("%s:failed to request GPIO %d, error %d\n",
+ __func__, OMAP4_SFH7741_ENABLE_GPIO, error);
+ return;
+ }
+
+ error = gpio_direction_output(OMAP4_SFH7741_ENABLE_GPIO , 0);
+ if (error < 0) {
+ pr_err("%s: GPIO configuration failed: GPIO %d,error %d\n",
+ __func__, OMAP4_SFH7741_ENABLE_GPIO, error);
+ gpio_free(OMAP4_SFH7741_ENABLE_GPIO);
+ }
+}
+
static void __init omap_4430sdp_init(void)
{
int status;
omap4_i2c_init();
+ omap_sfh7741prox_init();
platform_add_devices(sdp4430_devices, ARRAY_SIZE(sdp4430_devices));
omap_serial_init();
omap4_twl6030_hsmmc_init(mmc);
diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c
index d547036aff3f..07399505312b 100644
--- a/arch/arm/mach-omap2/board-am3517evm.c
+++ b/arch/arm/mach-omap2/board-am3517evm.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/i2c/pca953x.h>
@@ -32,25 +33,43 @@
#include <plat/board.h>
#include <plat/common.h>
-#include <plat/control.h>
#include <plat/usb.h>
#include <plat/display.h>
#include "mux.h"
+#include "control.h"
-#define AM35XX_EVM_PHY_MASK (0xF)
#define AM35XX_EVM_MDIO_FREQUENCY (1000000)
+static struct mdio_platform_data am3517_evm_mdio_pdata = {
+ .bus_freq = AM35XX_EVM_MDIO_FREQUENCY,
+};
+
+static struct resource am3517_mdio_resources[] = {
+ {
+ .start = AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET,
+ .end = AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET +
+ SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device am3517_mdio_device = {
+ .name = "davinci_mdio",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(am3517_mdio_resources),
+ .resource = am3517_mdio_resources,
+ .dev.platform_data = &am3517_evm_mdio_pdata,
+};
+
static struct emac_platform_data am3517_evm_emac_pdata = {
- .phy_mask = AM35XX_EVM_PHY_MASK,
- .mdio_max_freq = AM35XX_EVM_MDIO_FREQUENCY,
.rmii_en = 1,
};
static struct resource am3517_emac_resources[] = {
{
.start = AM35XX_IPSS_EMAC_BASE,
- .end = AM35XX_IPSS_EMAC_BASE + 0x3FFFF,
+ .end = AM35XX_IPSS_EMAC_BASE + 0x2FFFF,
.flags = IORESOURCE_MEM,
},
{
@@ -106,14 +125,13 @@ static void am3517_disable_ethernet_int(void)
regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
}
-void am3517_evm_ethernet_init(struct emac_platform_data *pdata)
+static void am3517_evm_ethernet_init(struct emac_platform_data *pdata)
{
unsigned int regval;
pdata->ctrl_reg_offset = AM35XX_EMAC_CNTRL_OFFSET;
pdata->ctrl_mod_reg_offset = AM35XX_EMAC_CNTRL_MOD_OFFSET;
pdata->ctrl_ram_offset = AM35XX_EMAC_CNTRL_RAM_OFFSET;
- pdata->mdio_reg_offset = AM35XX_EMAC_MDIO_OFFSET;
pdata->ctrl_ram_size = AM35XX_EMAC_CNTRL_RAM_SIZE;
pdata->version = EMAC_VERSION_2;
pdata->hw_ram_addr = AM35XX_EMAC_HW_RAM_ADDR;
@@ -121,6 +139,9 @@ void am3517_evm_ethernet_init(struct emac_platform_data *pdata)
pdata->interrupt_disable = am3517_disable_ethernet_int;
am3517_emac_device.dev.platform_data = pdata;
platform_device_register(&am3517_emac_device);
+ platform_device_register(&am3517_mdio_device);
+ clk_add_alias(NULL, dev_name(&am3517_mdio_device.dev),
+ NULL, &am3517_emac_device.dev);
regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
regval = regval & (~(AM35XX_CPGMACSS_SW_RST));
@@ -139,7 +160,6 @@ void am3517_evm_ethernet_init(struct emac_platform_data *pdata)
static struct i2c_board_info __initdata am3517evm_i2c1_boardinfo[] = {
{
I2C_BOARD_INFO("s35390a", 0x30),
- .type = "s35390a",
},
};
@@ -347,7 +367,7 @@ static struct omap_dss_board_info am3517_evm_dss_data = {
.default_device = &am3517_evm_lcd_device,
};
-struct platform_device am3517_evm_dss_device = {
+static struct platform_device am3517_evm_dss_device = {
.name = "omapdss",
.id = -1,
.dev = {
diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c
index 68f07f5f441a..2c6db1aaeb29 100644
--- a/arch/arm/mach-omap2/board-apollon.c
+++ b/arch/arm/mach-omap2/board-apollon.c
@@ -39,9 +39,9 @@
#include <plat/board.h>
#include <plat/common.h>
#include <plat/gpmc.h>
-#include <plat/control.h>
#include "mux.h"
+#include "control.h"
/* LED & Switch macros */
#define LED0_GPIO13 13
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index 934d9380c372..63f764e2af3f 100644
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -31,6 +31,7 @@
#include <linux/i2c/at24.h>
#include <linux/i2c/twl.h>
#include <linux/regulator/machine.h>
+#include <linux/mmc/host.h>
#include <linux/spi/spi.h>
#include <linux/spi/tdo24m.h>
@@ -237,8 +238,6 @@ static inline void cm_t35_init_nand(void) {}
defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
#include <linux/spi/ads7846.h>
-#include <plat/mcspi.h>
-
static struct omap2_mcspi_device_config ads7846_mcspi_config = {
.turbo_mode = 0,
.single_channel = 1, /* 0: slave, 1: master */
@@ -558,7 +557,7 @@ static struct twl4030_usb_data cm_t35_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
-static int cm_t35_keymap[] = {
+static uint32_t cm_t35_keymap[] = {
KEY(0, 0, KEY_A), KEY(0, 1, KEY_B), KEY(0, 2, KEY_LEFT),
KEY(1, 0, KEY_UP), KEY(1, 1, KEY_ENTER), KEY(1, 2, KEY_DOWN),
KEY(2, 0, KEY_RIGHT), KEY(2, 1, KEY_C), KEY(2, 2, KEY_D),
@@ -579,14 +578,14 @@ static struct twl4030_keypad_data cm_t35_kp_data = {
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
- .wires = 4,
+ .caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
},
{
.mmc = 2,
- .wires = 4,
+ .caps = MMC_CAP_4_BIT_DATA,
.transceiver = 1,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
diff --git a/arch/arm/mach-omap2/board-cm-t3517.c b/arch/arm/mach-omap2/board-cm-t3517.c
new file mode 100644
index 000000000000..1dd303e9a267
--- /dev/null
+++ b/arch/arm/mach-omap2/board-cm-t3517.c
@@ -0,0 +1,292 @@
+/*
+ * linux/arch/arm/mach-omap2/board-cm-t3517.c
+ *
+ * Support for the CompuLab CM-T3517 modules
+ *
+ * Copyright (C) 2010 CompuLab, Ltd.
+ * Author: Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/rtc-v3020.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/can/platform/ti_hecc.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/usb.h>
+#include <plat/nand.h>
+#include <plat/gpmc.h>
+
+#include <mach/am35xx.h>
+
+#include "mux.h"
+#include "control.h"
+
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+static struct gpio_led cm_t3517_leds[] = {
+ [0] = {
+ .gpio = 186,
+ .name = "cm-t3517:green",
+ .default_trigger = "heartbeat",
+ .active_low = 0,
+ },
+};
+
+static struct gpio_led_platform_data cm_t3517_led_pdata = {
+ .num_leds = ARRAY_SIZE(cm_t3517_leds),
+ .leds = cm_t3517_leds,
+};
+
+static struct platform_device cm_t3517_led_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &cm_t3517_led_pdata,
+ },
+};
+
+static void __init cm_t3517_init_leds(void)
+{
+ platform_device_register(&cm_t3517_led_device);
+}
+#else
+static inline void cm_t3517_init_leds(void) {}
+#endif
+
+#if defined(CONFIG_CAN_TI_HECC) || defined(CONFIG_CAN_TI_HECC_MODULE)
+static struct resource cm_t3517_hecc_resources[] = {
+ {
+ .start = AM35XX_IPSS_HECC_BASE,
+ .end = AM35XX_IPSS_HECC_BASE + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_35XX_HECC0_IRQ,
+ .end = INT_35XX_HECC0_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct ti_hecc_platform_data cm_t3517_hecc_pdata = {
+ .scc_hecc_offset = AM35XX_HECC_SCC_HECC_OFFSET,
+ .scc_ram_offset = AM35XX_HECC_SCC_RAM_OFFSET,
+ .hecc_ram_offset = AM35XX_HECC_RAM_OFFSET,
+ .mbx_offset = AM35XX_HECC_MBOX_OFFSET,
+ .int_line = AM35XX_HECC_INT_LINE,
+ .version = AM35XX_HECC_VERSION,
+};
+
+static struct platform_device cm_t3517_hecc_device = {
+ .name = "ti_hecc",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(cm_t3517_hecc_resources),
+ .resource = cm_t3517_hecc_resources,
+ .dev = {
+ .platform_data = &cm_t3517_hecc_pdata,
+ },
+};
+
+static void cm_t3517_init_hecc(void)
+{
+ platform_device_register(&cm_t3517_hecc_device);
+}
+#else
+static inline void cm_t3517_init_hecc(void) {}
+#endif
+
+#if defined(CONFIG_RTC_DRV_V3020) || defined(CONFIG_RTC_DRV_V3020_MODULE)
+#define RTC_IO_GPIO (153)
+#define RTC_WR_GPIO (154)
+#define RTC_RD_GPIO (160)
+#define RTC_CS_GPIO (163)
+
+struct v3020_platform_data cm_t3517_v3020_pdata = {
+ .use_gpio = 1,
+ .gpio_cs = RTC_CS_GPIO,
+ .gpio_wr = RTC_WR_GPIO,
+ .gpio_rd = RTC_RD_GPIO,
+ .gpio_io = RTC_IO_GPIO,
+};
+
+static struct platform_device cm_t3517_rtc_device = {
+ .name = "v3020",
+ .id = -1,
+ .dev = {
+ .platform_data = &cm_t3517_v3020_pdata,
+ }
+};
+
+static void __init cm_t3517_init_rtc(void)
+{
+ platform_device_register(&cm_t3517_rtc_device);
+}
+#else
+static inline void cm_t3517_init_rtc(void) {}
+#endif
+
+#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
+#define HSUSB1_RESET_GPIO (146)
+#define HSUSB2_RESET_GPIO (147)
+#define USB_HUB_RESET_GPIO (152)
+
+static struct ehci_hcd_omap_platform_data cm_t3517_ehci_pdata __initdata = {
+ .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+ .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+ .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+ .phy_reset = true,
+ .reset_gpio_port[0] = HSUSB1_RESET_GPIO,
+ .reset_gpio_port[1] = HSUSB2_RESET_GPIO,
+ .reset_gpio_port[2] = -EINVAL,
+};
+
+static int cm_t3517_init_usbh(void)
+{
+ int err;
+
+ err = gpio_request(USB_HUB_RESET_GPIO, "usb hub rst");
+ if (err) {
+ pr_err("CM-T3517: usb hub rst gpio request failed: %d\n", err);
+ } else {
+ gpio_direction_output(USB_HUB_RESET_GPIO, 0);
+ udelay(10);
+ gpio_set_value(USB_HUB_RESET_GPIO, 1);
+ msleep(1);
+ }
+
+ usb_ehci_init(&cm_t3517_ehci_pdata);
+
+ return 0;
+}
+#else
+static inline int cm_t3517_init_usbh(void)
+{
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
+#define NAND_BLOCK_SIZE SZ_128K
+
+static struct mtd_partition cm_t3517_nand_partitions[] = {
+ {
+ .name = "xloader",
+ .offset = 0, /* Offset = 0x00000 */
+ .size = 4 * NAND_BLOCK_SIZE,
+ .mask_flags = MTD_WRITEABLE
+ },
+ {
+ .name = "uboot",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */
+ .size = 15 * NAND_BLOCK_SIZE,
+ },
+ {
+ .name = "uboot environment",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x260000 */
+ .size = 2 * NAND_BLOCK_SIZE,
+ },
+ {
+ .name = "linux",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */
+ .size = 32 * NAND_BLOCK_SIZE,
+ },
+ {
+ .name = "rootfs",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x680000 */
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct omap_nand_platform_data cm_t3517_nand_data = {
+ .parts = cm_t3517_nand_partitions,
+ .nr_parts = ARRAY_SIZE(cm_t3517_nand_partitions),
+ .dma_channel = -1, /* disable DMA in OMAP NAND driver */
+ .cs = 0,
+};
+
+static void __init cm_t3517_init_nand(void)
+{
+ if (gpmc_nand_init(&cm_t3517_nand_data) < 0)
+ pr_err("CM-T3517: NAND initialization failed\n");
+}
+#else
+static inline void cm_t3517_init_nand(void) {}
+#endif
+
+static struct omap_board_config_kernel cm_t3517_config[] __initdata = {
+};
+
+static void __init cm_t3517_init_irq(void)
+{
+ omap_board_config = cm_t3517_config;
+ omap_board_config_size = ARRAY_SIZE(cm_t3517_config);
+
+ omap2_init_common_hw(NULL, NULL);
+ omap_init_irq();
+ omap_gpio_init();
+}
+
+static struct omap_board_mux board_mux[] __initdata = {
+ /* GPIO186 - Green LED */
+ OMAP3_MUX(SYS_CLKOUT2, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+ /* RTC GPIOs: IO, WR#, RD#, CS# */
+ OMAP3_MUX(MCBSP4_DR, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+ OMAP3_MUX(MCBSP4_DX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+ OMAP3_MUX(MCBSP_CLKS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+ OMAP3_MUX(UART3_CTS_RCTX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+ /* HSUSB1 RESET */
+ OMAP3_MUX(UART2_TX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+ /* HSUSB2 RESET */
+ OMAP3_MUX(UART2_RX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+ /* CM-T3517 USB HUB nRESET */
+ OMAP3_MUX(MCBSP4_CLKX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+
+ { .reg_offset = OMAP_MUX_TERMINATOR },
+};
+
+static void __init cm_t3517_init(void)
+{
+ omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+ omap_serial_init();
+ cm_t3517_init_leds();
+ cm_t3517_init_nand();
+ cm_t3517_init_rtc();
+ cm_t3517_init_usbh();
+ cm_t3517_init_hecc();
+}
+
+MACHINE_START(CM_T3517, "Compulab CM-T3517")
+ .boot_params = 0x80000100,
+ .map_io = omap3_map_io,
+ .reserve = omap_reserve,
+ .init_irq = cm_t3517_init_irq,
+ .init_machine = cm_t3517_init,
+ .timer = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index 2205c20a4cdb..067f4379c87f 100644
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -28,6 +28,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
+#include <linux/mmc/host.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
@@ -44,7 +45,6 @@
#include <plat/gpmc.h>
#include <plat/nand.h>
#include <plat/usb.h>
-#include <plat/timer-gp.h>
#include <plat/display.h>
#include <plat/mcspi.h>
@@ -58,6 +58,7 @@
#include "mux.h"
#include "hsmmc.h"
+#include "timer-gp.h"
#define NAND_BLOCK_SIZE SZ_128K
@@ -105,7 +106,7 @@ static struct omap_nand_platform_data devkit8000_nand_data = {
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
- .wires = 8,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
.gpio_wp = 29,
},
{} /* Terminator */
@@ -198,7 +199,7 @@ static struct platform_device devkit8000_dss_device = {
static struct regulator_consumer_supply devkit8000_vdda_dac_supply =
REGULATOR_SUPPLY("vdda_dac", "omapdss");
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
KEY(0, 0, KEY_1),
KEY(1, 0, KEY_2),
KEY(2, 0, KEY_3),
diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c
index ac834aa7abf6..fd38c05bb47f 100644
--- a/arch/arm/mach-omap2/board-flash.c
+++ b/arch/arm/mach-omap2/board-flash.c
@@ -21,7 +21,8 @@
#include <plat/nand.h>
#include <plat/onenand.h>
#include <plat/tc.h>
-#include <mach/board-flash.h>
+
+#include "board-flash.h"
#define REG_FPGA_REV 0x10
#define REG_FPGA_DIP_SWITCH_INPUT2 0x60
diff --git a/arch/arm/mach-omap2/include/mach/board-flash.h b/arch/arm/mach-omap2/board-flash.h
index b2242ae2bb6f..69befe00dd2f 100644
--- a/arch/arm/mach-omap2/include/mach/board-flash.h
+++ b/arch/arm/mach-omap2/board-flash.h
@@ -26,3 +26,5 @@ struct flash_partitions {
extern void board_flash_init(struct flash_partitions [],
char chip_sel[][GPMC_CS_NUM]);
+extern void board_nand_init(struct mtd_partition *nand_parts,
+ u8 nr_parts, u8 cs);
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
index 69064b1c6a75..b1c2c9a11c38 100644
--- a/arch/arm/mach-omap2/board-generic.c
+++ b/arch/arm/mach-omap2/board-generic.c
@@ -48,10 +48,22 @@ static void __init omap_generic_init(void)
static void __init omap_generic_map_io(void)
{
- omap2_set_globals_242x(); /* should be 242x, 243x, or 343x */
- omap242x_map_common_io();
+ if (cpu_is_omap242x()) {
+ omap2_set_globals_242x();
+ omap242x_map_common_io();
+ } else if (cpu_is_omap243x()) {
+ omap2_set_globals_243x();
+ omap243x_map_common_io();
+ } else if (cpu_is_omap34xx()) {
+ omap2_set_globals_3xxx();
+ omap34xx_map_common_io();
+ } else if (cpu_is_omap44xx()) {
+ omap2_set_globals_443x();
+ omap44xx_map_common_io();
+ }
}
+/* XXX This machine entry name should be updated */
MACHINE_START(OMAP_GENERIC, "Generic OMAP24xx")
/* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
.boot_params = 0x80000100,
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index cc39fc866524..929993b4bf26 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -31,7 +31,6 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <plat/control.h>
#include <mach/gpio.h>
#include <plat/usb.h>
#include <plat/board.h>
@@ -42,6 +41,7 @@
#include <plat/gpmc.h>
#include "mux.h"
+#include "control.h"
#define H4_FLASH_CS 0
#define H4_SMC91X_CS 1
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
index b62a68ba069b..5e035a58b809 100644
--- a/arch/arm/mach-omap2/board-igep0020.c
+++ b/arch/arm/mach-omap2/board-igep0020.c
@@ -20,6 +20,7 @@
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
+#include <linux/mmc/host.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -38,12 +39,61 @@
#define IGEP2_SMSC911X_CS 5
#define IGEP2_SMSC911X_GPIO 176
#define IGEP2_GPIO_USBH_NRESET 24
-#define IGEP2_GPIO_LED0_GREEN 26
-#define IGEP2_GPIO_LED0_RED 27
-#define IGEP2_GPIO_LED1_RED 28
-#define IGEP2_GPIO_DVI_PUP 170
-#define IGEP2_GPIO_WIFI_NPD 94
-#define IGEP2_GPIO_WIFI_NRESET 95
+#define IGEP2_GPIO_LED0_GREEN 26
+#define IGEP2_GPIO_LED0_RED 27
+#define IGEP2_GPIO_LED1_RED 28
+#define IGEP2_GPIO_DVI_PUP 170
+
+#define IGEP2_RB_GPIO_WIFI_NPD 94
+#define IGEP2_RB_GPIO_WIFI_NRESET 95
+#define IGEP2_RB_GPIO_BT_NRESET 137
+#define IGEP2_RC_GPIO_WIFI_NPD 138
+#define IGEP2_RC_GPIO_WIFI_NRESET 139
+#define IGEP2_RC_GPIO_BT_NRESET 137
+
+/*
+ * IGEP2 Hardware Revision Table
+ *
+ * --------------------------------------------------------------------------
+ * | Id. | Hw Rev. | HW0 (28) | WIFI_NPD | WIFI_NRESET | BT_NRESET |
+ * --------------------------------------------------------------------------
+ * | 0 | B | high | gpio94 | gpio95 | - |
+ * | 0 | B/C (B-compatible) | high | gpio94 | gpio95 | gpio137 |
+ * | 1 | C | low | gpio138 | gpio139 | gpio137 |
+ * --------------------------------------------------------------------------
+ */
+
+#define IGEP2_BOARD_HWREV_B 0
+#define IGEP2_BOARD_HWREV_C 1
+
+static u8 hwrev;
+
+static void __init igep2_get_revision(void)
+{
+ u8 ret;
+
+ omap_mux_init_gpio(IGEP2_GPIO_LED1_RED, OMAP_PIN_INPUT);
+
+ if ((gpio_request(IGEP2_GPIO_LED1_RED, "GPIO_HW0_REV") == 0) &&
+ (gpio_direction_input(IGEP2_GPIO_LED1_RED) == 0)) {
+ ret = gpio_get_value(IGEP2_GPIO_LED1_RED);
+ if (ret == 0) {
+ pr_info("IGEP2: Hardware Revision C (B-NON compatible)\n");
+ hwrev = IGEP2_BOARD_HWREV_C;
+ } else if (ret == 1) {
+ pr_info("IGEP2: Hardware Revision B/C (B compatible)\n");
+ hwrev = IGEP2_BOARD_HWREV_B;
+ } else {
+ pr_err("IGEP2: Unknown Hardware Revision\n");
+ hwrev = -1;
+ }
+ } else {
+ pr_warning("IGEP2: Could not obtain gpio GPIO_HW0_REV\n");
+ pr_err("IGEP2: Unknown Hardware Revision\n");
+ }
+
+ gpio_free(IGEP2_GPIO_LED1_RED);
+}
#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
@@ -107,7 +157,7 @@ static struct platform_device igep2_onenand_device = {
},
};
-void __init igep2_flash_init(void)
+static void __init igep2_flash_init(void)
{
u8 cs = 0;
u8 onenandcs = GPMC_CS_NUM + 1;
@@ -141,7 +191,7 @@ void __init igep2_flash_init(void)
}
#else
-void __init igep2_flash_init(void) {}
+static void __init igep2_flash_init(void) {}
#endif
#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
@@ -211,10 +261,6 @@ static struct regulator_consumer_supply igep2_vmmc1_supply = {
.supply = "vmmc",
};
-static struct regulator_consumer_supply igep2_vmmc2_supply = {
- .supply = "vmmc",
-};
-
/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
static struct regulator_init_data igep2_vmmc1 = {
.constraints = {
@@ -230,37 +276,95 @@ static struct regulator_init_data igep2_vmmc1 = {
.consumer_supplies = &igep2_vmmc1_supply,
};
-/* VMMC2 for OMAP VDD_MMC2 (i/o) and MMC2 WIFI */
-static struct regulator_init_data igep2_vmmc2 = {
- .constraints = {
- .min_uV = 1850000,
- .max_uV = 3150000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = 1,
- .consumer_supplies = &igep2_vmmc2_supply,
-};
-
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
- .wires = 4,
+ .caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
},
+#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
{
.mmc = 2,
- .wires = 4,
+ .caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
},
+#endif
{} /* Terminator */
};
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#include <linux/leds.h>
+
+static struct gpio_led igep2_gpio_leds[] = {
+ [0] = {
+ .name = "gpio-led:red:d0",
+ .gpio = IGEP2_GPIO_LED0_RED,
+ .default_trigger = "default-off"
+ },
+ [1] = {
+ .name = "gpio-led:green:d0",
+ .gpio = IGEP2_GPIO_LED0_GREEN,
+ .default_trigger = "default-off",
+ },
+ [2] = {
+ .name = "gpio-led:red:d1",
+ .gpio = IGEP2_GPIO_LED1_RED,
+ .default_trigger = "default-off",
+ },
+ [3] = {
+ .name = "gpio-led:green:d1",
+ .default_trigger = "heartbeat",
+ .gpio = -EINVAL, /* gets replaced */
+ },
+};
+
+static struct gpio_led_platform_data igep2_led_pdata = {
+ .leds = igep2_gpio_leds,
+ .num_leds = ARRAY_SIZE(igep2_gpio_leds),
+};
+
+static struct platform_device igep2_led_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &igep2_led_pdata,
+ },
+};
+
+static void __init igep2_leds_init(void)
+{
+ platform_device_register(&igep2_led_device);
+}
+
+#else
+static inline void igep2_leds_init(void)
+{
+ if ((gpio_request(IGEP2_GPIO_LED0_RED, "gpio-led:red:d0") == 0) &&
+ (gpio_direction_output(IGEP2_GPIO_LED0_RED, 1) == 0)) {
+ gpio_export(IGEP2_GPIO_LED0_RED, 0);
+ gpio_set_value(IGEP2_GPIO_LED0_RED, 0);
+ } else
+ pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_RED\n");
+
+ if ((gpio_request(IGEP2_GPIO_LED0_GREEN, "gpio-led:green:d0") == 0) &&
+ (gpio_direction_output(IGEP2_GPIO_LED0_GREEN, 1) == 0)) {
+ gpio_export(IGEP2_GPIO_LED0_GREEN, 0);
+ gpio_set_value(IGEP2_GPIO_LED0_GREEN, 0);
+ } else
+ pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_GREEN\n");
+
+ if ((gpio_request(IGEP2_GPIO_LED1_RED, "gpio-led:red:d1") == 0) &&
+ (gpio_direction_output(IGEP2_GPIO_LED1_RED, 1) == 0)) {
+ gpio_export(IGEP2_GPIO_LED1_RED, 0);
+ gpio_set_value(IGEP2_GPIO_LED1_RED, 0);
+ } else
+ pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_RED\n");
+
+}
+#endif
+
static int igep2_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
@@ -268,20 +372,48 @@ static int igep2_twl_gpio_setup(struct device *dev,
mmc[0].gpio_cd = gpio + 0;
omap2_hsmmc_init(mmc);
- /* link regulators to MMC adapters ... we "know" the
+ /*
+ * link regulators to MMC adapters ... we "know" the
* regulators will be set up only *after* we return.
- */
+ */
igep2_vmmc1_supply.dev = mmc[0].dev;
- igep2_vmmc2_supply.dev = mmc[1].dev;
+
+ /*
+ * REVISIT: need ehci-omap hooks for external VBUS
+ * power switch and overcurrent detect
+ */
+ if ((gpio_request(gpio + 1, "GPIO_EHCI_NOC") < 0) ||
+ (gpio_direction_input(gpio + 1) < 0))
+ pr_err("IGEP2: Could not obtain gpio for EHCI NOC");
+
+ /*
+ * TWL4030_GPIO_MAX + 0 == ledA, GPIO_USBH_CPEN
+ * (out, active low)
+ */
+ if ((gpio_request(gpio + TWL4030_GPIO_MAX, "GPIO_USBH_CPEN") < 0) ||
+ (gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0) < 0))
+ pr_err("IGEP2: Could not obtain gpio for USBH_CPEN");
+
+ /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
+#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
+ if ((gpio_request(gpio+TWL4030_GPIO_MAX+1, "gpio-led:green:d1") == 0)
+ && (gpio_direction_output(gpio + TWL4030_GPIO_MAX + 1, 1) == 0)) {
+ gpio_export(gpio + TWL4030_GPIO_MAX + 1, 0);
+ gpio_set_value(gpio + TWL4030_GPIO_MAX + 1, 0);
+ } else
+ pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_GREEN\n");
+#else
+ igep2_gpio_leds[3].gpio = gpio + TWL4030_GPIO_MAX + 1;
+#endif
return 0;
};
-static struct twl4030_gpio_platform_data igep2_gpio_data = {
+static struct twl4030_gpio_platform_data igep2_twl4030_gpio_pdata = {
.gpio_base = OMAP_MAX_GPIO_LINES,
.irq_base = TWL4030_GPIO_IRQ_BASE,
.irq_end = TWL4030_GPIO_IRQ_END,
- .use_leds = false,
+ .use_leds = true,
.setup = igep2_twl_gpio_setup,
};
@@ -355,47 +487,6 @@ static void __init igep2_display_init(void)
pr_err("IGEP v2: Could not obtain gpio GPIO_DVI_PUP\n");
}
-#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
-#include <linux/leds.h>
-
-static struct gpio_led igep2_gpio_leds[] = {
- {
- .name = "led0:red",
- .gpio = IGEP2_GPIO_LED0_RED,
- },
- {
- .name = "led0:green",
- .default_trigger = "heartbeat",
- .gpio = IGEP2_GPIO_LED0_GREEN,
- },
- {
- .name = "led1:red",
- .gpio = IGEP2_GPIO_LED1_RED,
- },
-};
-
-static struct gpio_led_platform_data igep2_led_pdata = {
- .leds = igep2_gpio_leds,
- .num_leds = ARRAY_SIZE(igep2_gpio_leds),
-};
-
-static struct platform_device igep2_led_device = {
- .name = "leds-gpio",
- .id = -1,
- .dev = {
- .platform_data = &igep2_led_pdata,
- },
-};
-
-static void __init igep2_init_led(void)
-{
- platform_device_register(&igep2_led_device);
-}
-
-#else
-static inline void igep2_init_led(void) {}
-#endif
-
static struct platform_device *igep2_devices[] __initdata = {
&igep2_dss_device,
};
@@ -425,14 +516,13 @@ static struct twl4030_platform_data igep2_twldata = {
/* platform_data for children goes here */
.usb = &igep2_usb_data,
.codec = &igep2_codec_data,
- .gpio = &igep2_gpio_data,
+ .gpio = &igep2_twl4030_gpio_pdata,
.vmmc1 = &igep2_vmmc1,
- .vmmc2 = &igep2_vmmc2,
.vpll2 = &igep2_vpll2,
};
-static struct i2c_board_info __initdata igep2_i2c_boardinfo[] = {
+static struct i2c_board_info __initdata igep2_i2c1_boardinfo[] = {
{
I2C_BOARD_INFO("twl4030", 0x48),
.flags = I2C_CLIENT_WAKE,
@@ -441,14 +531,29 @@ static struct i2c_board_info __initdata igep2_i2c_boardinfo[] = {
},
};
-static int __init igep2_i2c_init(void)
+static struct i2c_board_info __initdata igep2_i2c3_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("eeprom", 0x50),
+ },
+};
+
+static void __init igep2_i2c_init(void)
{
- omap_register_i2c_bus(1, 2600, igep2_i2c_boardinfo,
- ARRAY_SIZE(igep2_i2c_boardinfo));
- /* Bus 3 is attached to the DVI port where devices like the pico DLP
- * projector don't work reliably with 400kHz */
- omap_register_i2c_bus(3, 100, NULL, 0);
- return 0;
+ int ret;
+
+ ret = omap_register_i2c_bus(1, 2600, igep2_i2c1_boardinfo,
+ ARRAY_SIZE(igep2_i2c1_boardinfo));
+ if (ret)
+ pr_warning("IGEP2: Could not register I2C1 bus (%d)\n", ret);
+
+ /*
+ * Bus 3 is attached to the DVI port where devices like the pico DLP
+ * projector don't work reliably with 400kHz
+ */
+ ret = omap_register_i2c_bus(3, 100, igep2_i2c3_boardinfo,
+ ARRAY_SIZE(igep2_i2c3_boardinfo));
+ if (ret)
+ pr_warning("IGEP2: Could not register I2C3 bus (%d)\n", ret);
}
static struct omap_musb_board_data musb_board_data = {
@@ -476,9 +581,57 @@ static struct omap_board_mux board_mux[] __initdata = {
#define board_mux NULL
#endif
+#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
+
+static void __init igep2_wlan_bt_init(void)
+{
+ unsigned npd, wreset, btreset;
+
+ /* GPIO's for WLAN-BT combo depends on hardware revision */
+ if (hwrev == IGEP2_BOARD_HWREV_B) {
+ npd = IGEP2_RB_GPIO_WIFI_NPD;
+ wreset = IGEP2_RB_GPIO_WIFI_NRESET;
+ btreset = IGEP2_RB_GPIO_BT_NRESET;
+ } else if (hwrev == IGEP2_BOARD_HWREV_C) {
+ npd = IGEP2_RC_GPIO_WIFI_NPD;
+ wreset = IGEP2_RC_GPIO_WIFI_NRESET;
+ btreset = IGEP2_RC_GPIO_BT_NRESET;
+ } else
+ return;
+
+ /* Set GPIO's for WLAN-BT combo module */
+ if ((gpio_request(npd, "GPIO_WIFI_NPD") == 0) &&
+ (gpio_direction_output(npd, 1) == 0)) {
+ gpio_export(npd, 0);
+ } else
+ pr_warning("IGEP2: Could not obtain gpio GPIO_WIFI_NPD\n");
+
+ if ((gpio_request(wreset, "GPIO_WIFI_NRESET") == 0) &&
+ (gpio_direction_output(wreset, 1) == 0)) {
+ gpio_export(wreset, 0);
+ gpio_set_value(wreset, 0);
+ udelay(10);
+ gpio_set_value(wreset, 1);
+ } else
+ pr_warning("IGEP2: Could not obtain gpio GPIO_WIFI_NRESET\n");
+
+ if ((gpio_request(btreset, "GPIO_BT_NRESET") == 0) &&
+ (gpio_direction_output(btreset, 1) == 0)) {
+ gpio_export(btreset, 0);
+ } else
+ pr_warning("IGEP2: Could not obtain gpio GPIO_BT_NRESET\n");
+}
+#else
+static inline void __init igep2_wlan_bt_init(void) { }
+#endif
+
static void __init igep2_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+
+ /* Get IGEP2 hardware revision */
+ igep2_get_revision();
+ /* Register I2C busses and drivers */
igep2_i2c_init();
platform_add_devices(igep2_devices, ARRAY_SIZE(igep2_devices));
omap_serial_init();
@@ -486,50 +639,16 @@ static void __init igep2_init(void)
usb_ehci_init(&ehci_pdata);
igep2_flash_init();
- igep2_init_led();
+ igep2_leds_init();
igep2_display_init();
igep2_init_smsc911x();
- /* GPIO userspace leds */
-#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
- if ((gpio_request(IGEP2_GPIO_LED0_RED, "led0:red") == 0) &&
- (gpio_direction_output(IGEP2_GPIO_LED0_RED, 1) == 0)) {
- gpio_export(IGEP2_GPIO_LED0_RED, 0);
- gpio_set_value(IGEP2_GPIO_LED0_RED, 0);
- } else
- pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_RED\n");
-
- if ((gpio_request(IGEP2_GPIO_LED0_GREEN, "led0:green") == 0) &&
- (gpio_direction_output(IGEP2_GPIO_LED0_GREEN, 1) == 0)) {
- gpio_export(IGEP2_GPIO_LED0_GREEN, 0);
- gpio_set_value(IGEP2_GPIO_LED0_GREEN, 0);
- } else
- pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_GREEN\n");
-
- if ((gpio_request(IGEP2_GPIO_LED1_RED, "led1:red") == 0) &&
- (gpio_direction_output(IGEP2_GPIO_LED1_RED, 1) == 0)) {
- gpio_export(IGEP2_GPIO_LED1_RED, 0);
- gpio_set_value(IGEP2_GPIO_LED1_RED, 0);
- } else
- pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_RED\n");
-#endif
-
- /* GPIO W-LAN + Bluetooth combo module */
- if ((gpio_request(IGEP2_GPIO_WIFI_NPD, "GPIO_WIFI_NPD") == 0) &&
- (gpio_direction_output(IGEP2_GPIO_WIFI_NPD, 1) == 0)) {
- gpio_export(IGEP2_GPIO_WIFI_NPD, 0);
-/* gpio_set_value(IGEP2_GPIO_WIFI_NPD, 0); */
- } else
- pr_warning("IGEP v2: Could not obtain gpio GPIO_WIFI_NPD\n");
+ /*
+ * WLAN-BT combo module from MuRata wich has a Marvell WLAN
+ * (88W8686) + CSR Bluetooth chipset. Uses SDIO interface.
+ */
+ igep2_wlan_bt_init();
- if ((gpio_request(IGEP2_GPIO_WIFI_NRESET, "GPIO_WIFI_NRESET") == 0) &&
- (gpio_direction_output(IGEP2_GPIO_WIFI_NRESET, 1) == 0)) {
- gpio_export(IGEP2_GPIO_WIFI_NRESET, 0);
- gpio_set_value(IGEP2_GPIO_WIFI_NRESET, 0);
- udelay(10);
- gpio_set_value(IGEP2_GPIO_WIFI_NRESET, 1);
- } else
- pr_warning("IGEP v2: Could not obtain gpio GPIO_WIFI_NRESET\n");
}
MACHINE_START(IGEP0020, "IGEP v2 board")
diff --git a/arch/arm/mach-omap2/board-igep0030.c b/arch/arm/mach-omap2/board-igep0030.c
new file mode 100644
index 000000000000..22b0b253e16b
--- /dev/null
+++ b/arch/arm/mach-omap2/board-igep0030.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2010 - ISEE 2007 SL
+ *
+ * Modified from mach-omap2/board-generic.c
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+
+#include <linux/regulator/machine.h>
+#include <linux/i2c/twl.h>
+#include <linux/mmc/host.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/gpmc.h>
+#include <plat/usb.h>
+#include <plat/onenand.h>
+
+#include "mux.h"
+#include "hsmmc.h"
+#include "sdram-numonyx-m65kxxxxam.h"
+
+#define IGEP3_GPIO_LED0_GREEN 54
+#define IGEP3_GPIO_LED0_RED 53
+#define IGEP3_GPIO_LED1_RED 16
+
+#define IGEP3_GPIO_WIFI_NPD 138
+#define IGEP3_GPIO_WIFI_NRESET 139
+#define IGEP3_GPIO_BT_NRESET 137
+
+#define IGEP3_GPIO_USBH_NRESET 115
+
+
+#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
+ defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
+
+#define ONENAND_MAP 0x20000000
+
+/*
+ * x2 Flash built-in COMBO POP MEMORY
+ * Since the device is equipped with two DataRAMs, and two-plane NAND
+ * Flash memory array, these two component enables simultaneous program
+ * of 4KiB. Plane1 has only even blocks such as block0, block2, block4
+ * while Plane2 has only odd blocks such as block1, block3, block5.
+ * So MTD regards it as 4KiB page size and 256KiB block size 64*(2*2048)
+ */
+
+static struct mtd_partition igep3_onenand_partitions[] = {
+ {
+ .name = "X-Loader",
+ .offset = 0,
+ .size = 2 * (64*(2*2048))
+ },
+ {
+ .name = "U-Boot",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 6 * (64*(2*2048)),
+ },
+ {
+ .name = "Environment",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 2 * (64*(2*2048)),
+ },
+ {
+ .name = "Kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 12 * (64*(2*2048)),
+ },
+ {
+ .name = "File System",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct omap_onenand_platform_data igep3_onenand_pdata = {
+ .parts = igep3_onenand_partitions,
+ .nr_parts = ARRAY_SIZE(igep3_onenand_partitions),
+ .onenand_setup = NULL,
+ .dma_channel = -1, /* disable DMA in OMAP OneNAND driver */
+};
+
+static struct platform_device igep3_onenand_device = {
+ .name = "omap2-onenand",
+ .id = -1,
+ .dev = {
+ .platform_data = &igep3_onenand_pdata,
+ },
+};
+
+void __init igep3_flash_init(void)
+{
+ u8 cs = 0;
+ u8 onenandcs = GPMC_CS_NUM + 1;
+
+ for (cs = 0; cs < GPMC_CS_NUM; cs++) {
+ u32 ret;
+ ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+ /* Check if NAND/oneNAND is configured */
+ if ((ret & 0xC00) == 0x800)
+ /* NAND found */
+ pr_err("IGEP3: Unsupported NAND found\n");
+ else {
+ ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+
+ if ((ret & 0x3F) == (ONENAND_MAP >> 24))
+ /* OneNAND found */
+ onenandcs = cs;
+ }
+ }
+
+ if (onenandcs > GPMC_CS_NUM) {
+ pr_err("IGEP3: Unable to find configuration in GPMC\n");
+ return;
+ }
+
+ igep3_onenand_pdata.cs = onenandcs;
+
+ if (platform_device_register(&igep3_onenand_device) < 0)
+ pr_err("IGEP3: Unable to register OneNAND device\n");
+}
+
+#else
+void __init igep3_flash_init(void) {}
+#endif
+
+static struct regulator_consumer_supply igep3_vmmc1_supply = {
+ .supply = "vmmc",
+};
+
+/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
+static struct regulator_init_data igep3_vmmc1 = {
+ .constraints = {
+ .min_uV = 1850000,
+ .max_uV = 3150000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &igep3_vmmc1_supply,
+};
+
+static struct omap2_hsmmc_info mmc[] = {
+ [0] = {
+ .mmc = 1,
+ .caps = MMC_CAP_4_BIT_DATA,
+ .gpio_cd = -EINVAL,
+ .gpio_wp = -EINVAL,
+ },
+#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
+ [1] = {
+ .mmc = 2,
+ .caps = MMC_CAP_4_BIT_DATA,
+ .gpio_cd = -EINVAL,
+ .gpio_wp = -EINVAL,
+ },
+#endif
+ {} /* Terminator */
+};
+
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#include <linux/leds.h>
+
+static struct gpio_led igep3_gpio_leds[] = {
+ [0] = {
+ .name = "gpio-led:red:d0",
+ .gpio = IGEP3_GPIO_LED0_RED,
+ .default_trigger = "default-off"
+ },
+ [1] = {
+ .name = "gpio-led:green:d0",
+ .gpio = IGEP3_GPIO_LED0_GREEN,
+ .default_trigger = "default-off",
+ },
+ [2] = {
+ .name = "gpio-led:red:d1",
+ .gpio = IGEP3_GPIO_LED1_RED,
+ .default_trigger = "default-off",
+ },
+ [3] = {
+ .name = "gpio-led:green:d1",
+ .default_trigger = "heartbeat",
+ .gpio = -EINVAL, /* gets replaced */
+ },
+};
+
+static struct gpio_led_platform_data igep3_led_pdata = {
+ .leds = igep3_gpio_leds,
+ .num_leds = ARRAY_SIZE(igep3_gpio_leds),
+};
+
+static struct platform_device igep3_led_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &igep3_led_pdata,
+ },
+};
+
+static void __init igep3_leds_init(void)
+{
+ platform_device_register(&igep3_led_device);
+}
+
+#else
+static inline void igep3_leds_init(void)
+{
+ if ((gpio_request(IGEP3_GPIO_LED0_RED, "gpio-led:red:d0") == 0) &&
+ (gpio_direction_output(IGEP3_GPIO_LED0_RED, 1) == 0)) {
+ gpio_export(IGEP3_GPIO_LED0_RED, 0);
+ gpio_set_value(IGEP3_GPIO_LED0_RED, 1);
+ } else
+ pr_warning("IGEP3: Could not obtain gpio GPIO_LED0_RED\n");
+
+ if ((gpio_request(IGEP3_GPIO_LED0_GREEN, "gpio-led:green:d0") == 0) &&
+ (gpio_direction_output(IGEP3_GPIO_LED0_GREEN, 1) == 0)) {
+ gpio_export(IGEP3_GPIO_LED0_GREEN, 0);
+ gpio_set_value(IGEP3_GPIO_LED0_GREEN, 1);
+ } else
+ pr_warning("IGEP3: Could not obtain gpio GPIO_LED0_GREEN\n");
+
+ if ((gpio_request(IGEP3_GPIO_LED1_RED, "gpio-led:red:d1") == 0) &&
+ (gpio_direction_output(IGEP3_GPIO_LED1_RED, 1) == 0)) {
+ gpio_export(IGEP3_GPIO_LED1_RED, 0);
+ gpio_set_value(IGEP3_GPIO_LED1_RED, 1);
+ } else
+ pr_warning("IGEP3: Could not obtain gpio GPIO_LED1_RED\n");
+}
+#endif
+
+static int igep3_twl4030_gpio_setup(struct device *dev,
+ unsigned gpio, unsigned ngpio)
+{
+ /* gpio + 0 is "mmc0_cd" (input/IRQ) */
+ mmc[0].gpio_cd = gpio + 0;
+ omap2_hsmmc_init(mmc);
+
+ /*
+ * link regulators to MMC adapters ... we "know" the
+ * regulators will be set up only *after* we return.
+ */
+ igep3_vmmc1_supply.dev = mmc[0].dev;
+
+ /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
+#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
+ if ((gpio_request(gpio+TWL4030_GPIO_MAX+1, "gpio-led:green:d1") == 0)
+ && (gpio_direction_output(gpio + TWL4030_GPIO_MAX + 1, 1) == 0)) {
+ gpio_export(gpio + TWL4030_GPIO_MAX + 1, 0);
+ gpio_set_value(gpio + TWL4030_GPIO_MAX + 1, 0);
+ } else
+ pr_warning("IGEP3: Could not obtain gpio GPIO_LED1_GREEN\n");
+#else
+ igep3_gpio_leds[3].gpio = gpio + TWL4030_GPIO_MAX + 1;
+#endif
+
+ return 0;
+};
+
+static struct twl4030_gpio_platform_data igep3_twl4030_gpio_pdata = {
+ .gpio_base = OMAP_MAX_GPIO_LINES,
+ .irq_base = TWL4030_GPIO_IRQ_BASE,
+ .irq_end = TWL4030_GPIO_IRQ_END,
+ .use_leds = true,
+ .setup = igep3_twl4030_gpio_setup,
+};
+
+static struct twl4030_usb_data igep3_twl4030_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
+static void __init igep3_init_irq(void)
+{
+ omap2_init_common_hw(m65kxxxxam_sdrc_params, m65kxxxxam_sdrc_params);
+ omap_init_irq();
+ omap_gpio_init();
+}
+
+static struct twl4030_platform_data igep3_twl4030_pdata = {
+ .irq_base = TWL4030_IRQ_BASE,
+ .irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .usb = &igep3_twl4030_usb_data,
+ .gpio = &igep3_twl4030_gpio_pdata,
+ .vmmc1 = &igep3_vmmc1,
+};
+
+static struct i2c_board_info __initdata igep3_i2c_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("twl4030", 0x48),
+ .flags = I2C_CLIENT_WAKE,
+ .irq = INT_34XX_SYS_NIRQ,
+ .platform_data = &igep3_twl4030_pdata,
+ },
+};
+
+static int __init igep3_i2c_init(void)
+{
+ omap_register_i2c_bus(1, 2600, igep3_i2c_boardinfo,
+ ARRAY_SIZE(igep3_i2c_boardinfo));
+
+ return 0;
+}
+
+static struct omap_musb_board_data musb_board_data = {
+ .interface_type = MUSB_INTERFACE_ULPI,
+ .mode = MUSB_OTG,
+ .power = 100,
+};
+
+#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
+
+static void __init igep3_wifi_bt_init(void)
+{
+ /* Configure MUX values for W-LAN + Bluetooth GPIO's */
+ omap_mux_init_gpio(IGEP3_GPIO_WIFI_NPD, OMAP_PIN_OUTPUT);
+ omap_mux_init_gpio(IGEP3_GPIO_WIFI_NRESET, OMAP_PIN_OUTPUT);
+ omap_mux_init_gpio(IGEP3_GPIO_BT_NRESET, OMAP_PIN_OUTPUT);
+
+ /* Set GPIO's for W-LAN + Bluetooth combo module */
+ if ((gpio_request(IGEP3_GPIO_WIFI_NPD, "GPIO_WIFI_NPD") == 0) &&
+ (gpio_direction_output(IGEP3_GPIO_WIFI_NPD, 1) == 0)) {
+ gpio_export(IGEP3_GPIO_WIFI_NPD, 0);
+ } else
+ pr_warning("IGEP3: Could not obtain gpio GPIO_WIFI_NPD\n");
+
+ if ((gpio_request(IGEP3_GPIO_WIFI_NRESET, "GPIO_WIFI_NRESET") == 0) &&
+ (gpio_direction_output(IGEP3_GPIO_WIFI_NRESET, 1) == 0)) {
+ gpio_export(IGEP3_GPIO_WIFI_NRESET, 0);
+ gpio_set_value(IGEP3_GPIO_WIFI_NRESET, 0);
+ udelay(10);
+ gpio_set_value(IGEP3_GPIO_WIFI_NRESET, 1);
+ } else
+ pr_warning("IGEP3: Could not obtain gpio GPIO_WIFI_NRESET\n");
+
+ if ((gpio_request(IGEP3_GPIO_BT_NRESET, "GPIO_BT_NRESET") == 0) &&
+ (gpio_direction_output(IGEP3_GPIO_BT_NRESET, 1) == 0)) {
+ gpio_export(IGEP3_GPIO_BT_NRESET, 0);
+ } else
+ pr_warning("IGEP3: Could not obtain gpio GPIO_BT_NRESET\n");
+}
+#else
+void __init igep3_wifi_bt_init(void) {}
+#endif
+
+#ifdef CONFIG_OMAP_MUX
+static struct omap_board_mux board_mux[] __initdata = {
+ { .reg_offset = OMAP_MUX_TERMINATOR },
+};
+#else
+#define board_mux NULL
+#endif
+
+static void __init igep3_init(void)
+{
+ omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+
+ /* Register I2C busses and drivers */
+ igep3_i2c_init();
+
+ omap_serial_init();
+ usb_musb_init(&musb_board_data);
+
+ igep3_flash_init();
+ igep3_leds_init();
+
+ /*
+ * WLAN-BT combo module from MuRata wich has a Marvell WLAN
+ * (88W8686) + CSR Bluetooth chipset. Uses SDIO interface.
+ */
+ igep3_wifi_bt_init();
+
+}
+
+MACHINE_START(IGEP0030, "IGEP OMAP3 module")
+ .boot_params = 0x80000100,
+ .map_io = omap3_map_io,
+ .init_irq = igep3_init_irq,
+ .init_machine = igep3_init,
+ .timer = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index f28fd77bceb3..001fd9713f39 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -27,6 +27,7 @@
#include <linux/i2c/twl.h>
#include <linux/io.h>
#include <linux/smsc911x.h>
+#include <linux/mmc/host.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
@@ -41,11 +42,12 @@
#include <mach/board-zoom.h>
#include <asm/delay.h>
-#include <plat/control.h>
#include <plat/usb.h>
+#include "board-flash.h"
#include "mux.h"
#include "hsmmc.h"
+#include "control.h"
#define LDP_SMSC911X_CS 1
#define LDP_SMSC911X_GPIO 152
@@ -82,7 +84,7 @@ static struct platform_device ldp_smsc911x_device = {
},
};
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
KEY(0, 0, KEY_1),
KEY(1, 0, KEY_2),
KEY(2, 0, KEY_3),
@@ -362,7 +364,7 @@ static int __init omap_i2c_init(void)
static struct omap2_hsmmc_info mmc[] __initdata = {
{
.mmc = 1,
- .wires = 4,
+ .caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
},
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
index 3f7966873507..e823c7042ab3 100644
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -20,6 +20,7 @@
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/usb/musb.h>
+#include <sound/tlv320aic3x.h>
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
@@ -383,15 +384,6 @@ static void n8x0_mmc_callback(void *data, u8 card_mask)
omap_mmc_notify_cover_event(mmc_device, index, *openp);
}
-void n8x0_mmc_slot1_cover_handler(void *arg, int closed_state)
-{
- if (mmc_device == NULL)
- return;
-
- slot1_cover_open = !closed_state;
- omap_mmc_notify_cover_event(mmc_device, 0, closed_state);
-}
-
static int n8x0_mmc_late_init(struct device *dev)
{
int r, bit, *openp;
@@ -511,7 +503,7 @@ static struct omap_mmc_platform_data mmc1_data = {
static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC];
-void __init n8x0_mmc_init(void)
+static void __init n8x0_mmc_init(void)
{
int err;
@@ -560,11 +552,6 @@ void __init n8x0_mmc_init(void)
void __init n8x0_mmc_init(void)
{
}
-
-void n8x0_mmc_slot1_cover_handler(void *arg, int state)
-{
-}
-
#endif /* CONFIG_MMC_OMAP */
#ifdef CONFIG_MENELAUS
@@ -614,29 +601,35 @@ static int n8x0_menelaus_late_init(struct device *dev)
return 0;
}
-static struct i2c_board_info __initdata n8x0_i2c_board_info_1[] = {
+#else
+static int n8x0_menelaus_late_init(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+static struct menelaus_platform_data n8x0_menelaus_platform_data __initdata = {
+ .late_init = n8x0_menelaus_late_init,
+};
+
+static struct i2c_board_info __initdata n8x0_i2c_board_info_1[] __initdata = {
{
I2C_BOARD_INFO("menelaus", 0x72),
.irq = INT_24XX_SYS_NIRQ,
+ .platform_data = &n8x0_menelaus_platform_data,
},
};
-static struct menelaus_platform_data n8x0_menelaus_platform_data = {
- .late_init = n8x0_menelaus_late_init,
+static struct aic3x_pdata n810_aic33_data __initdata = {
+ .gpio_reset = 118,
};
-static void __init n8x0_menelaus_init(void)
-{
- n8x0_i2c_board_info_1[0].platform_data = &n8x0_menelaus_platform_data;
- omap_register_i2c_bus(1, 400, n8x0_i2c_board_info_1,
- ARRAY_SIZE(n8x0_i2c_board_info_1));
-}
-
-#else
-static inline void __init n8x0_menelaus_init(void)
-{
-}
-#endif
+static struct i2c_board_info n810_i2c_board_info_2[] __initdata = {
+ {
+ I2C_BOARD_INFO("tlv320aic3x", 0x18),
+ .platform_data = &n810_aic33_data,
+ },
+};
static void __init n8x0_map_io(void)
{
@@ -653,6 +646,11 @@ static void __init n8x0_init_irq(void)
#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
+ /* I2S codec port pins for McBSP block */
+ OMAP2420_MUX(EAC_AC_SCLK, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),
+ OMAP2420_MUX(EAC_AC_FS, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),
+ OMAP2420_MUX(EAC_AC_DIN, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),
+ OMAP2420_MUX(EAC_AC_DOUT, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT),
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
#else
@@ -665,9 +663,14 @@ static void __init n8x0_init_machine(void)
/* FIXME: add n810 spi devices */
spi_register_board_info(n800_spi_board_info,
ARRAY_SIZE(n800_spi_board_info));
+ omap_register_i2c_bus(1, 400, n8x0_i2c_board_info_1,
+ ARRAY_SIZE(n8x0_i2c_board_info_1));
+ omap_register_i2c_bus(2, 400, NULL, 0);
+ if (machine_is_nokia_n810())
+ i2c_register_board_info(2, n810_i2c_board_info_2,
+ ARRAY_SIZE(n810_i2c_board_info_2));
omap_serial_init();
- n8x0_menelaus_init();
n8x0_onenand_init();
n8x0_mmc_init();
n8x0_usb_init();
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 9d9f5b881ee8..14f42240ae79 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -27,6 +27,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
+#include <linux/mmc/host.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
@@ -43,13 +44,100 @@
#include <plat/gpmc.h>
#include <plat/nand.h>
#include <plat/usb.h>
-#include <plat/timer-gp.h>
#include "mux.h"
#include "hsmmc.h"
+#include "timer-gp.h"
#define NAND_BLOCK_SIZE SZ_128K
+/*
+ * OMAP3 Beagle revision
+ * Run time detection of Beagle revision is done by reading GPIO.
+ * GPIO ID -
+ * AXBX = GPIO173, GPIO172, GPIO171: 1 1 1
+ * C1_3 = GPIO173, GPIO172, GPIO171: 1 1 0
+ * C4 = GPIO173, GPIO172, GPIO171: 1 0 1
+ * XM = GPIO173, GPIO172, GPIO171: 0 0 0
+ */
+enum {
+ OMAP3BEAGLE_BOARD_UNKN = 0,
+ OMAP3BEAGLE_BOARD_AXBX,
+ OMAP3BEAGLE_BOARD_C1_3,
+ OMAP3BEAGLE_BOARD_C4,
+ OMAP3BEAGLE_BOARD_XM,
+};
+
+static u8 omap3_beagle_version;
+
+static u8 omap3_beagle_get_rev(void)
+{
+ return omap3_beagle_version;
+}
+
+static void __init omap3_beagle_init_rev(void)
+{
+ int ret;
+ u16 beagle_rev = 0;
+
+ omap_mux_init_gpio(171, OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_gpio(172, OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_gpio(173, OMAP_PIN_INPUT_PULLUP);
+
+ ret = gpio_request(171, "rev_id_0");
+ if (ret < 0)
+ goto fail0;
+
+ ret = gpio_request(172, "rev_id_1");
+ if (ret < 0)
+ goto fail1;
+
+ ret = gpio_request(173, "rev_id_2");
+ if (ret < 0)
+ goto fail2;
+
+ gpio_direction_input(171);
+ gpio_direction_input(172);
+ gpio_direction_input(173);
+
+ beagle_rev = gpio_get_value(171) | (gpio_get_value(172) << 1)
+ | (gpio_get_value(173) << 2);
+
+ switch (beagle_rev) {
+ case 7:
+ printk(KERN_INFO "OMAP3 Beagle Rev: Ax/Bx\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_AXBX;
+ break;
+ case 6:
+ printk(KERN_INFO "OMAP3 Beagle Rev: C1/C2/C3\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_C1_3;
+ break;
+ case 5:
+ printk(KERN_INFO "OMAP3 Beagle Rev: C4\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_C4;
+ break;
+ case 0:
+ printk(KERN_INFO "OMAP3 Beagle Rev: xM\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_XM;
+ break;
+ default:
+ printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev);
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
+ }
+
+ return;
+
+fail2:
+ gpio_free(172);
+fail1:
+ gpio_free(171);
+fail0:
+ printk(KERN_ERR "Unable to get revision detection GPIO pins\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
+
+ return;
+}
+
static struct mtd_partition omap3beagle_nand_partitions[] = {
/* All the partition sizes are listed in terms of NAND block size */
{
@@ -166,7 +254,7 @@ static void __init beagle_display_init(void)
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
- .wires = 8,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
.gpio_wp = 29,
},
{} /* Terminator */
@@ -185,7 +273,10 @@ static struct gpio_led gpio_leds[];
static int beagle_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
- if (system_rev >= 0x20 && system_rev <= 0x34301000) {
+ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
+ mmc[0].gpio_wp = -EINVAL;
+ } else if ((omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C1_3) ||
+ (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C4)) {
omap_mux_init_gpio(23, OMAP_PIN_INPUT);
mmc[0].gpio_wp = 23;
} else {
@@ -322,13 +413,19 @@ static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
},
};
+static struct i2c_board_info __initdata beagle_i2c_eeprom[] = {
+ {
+ I2C_BOARD_INFO("eeprom", 0x50),
+ },
+};
+
static int __init omap3_beagle_i2c_init(void)
{
omap_register_i2c_bus(1, 2600, beagle_i2c_boardinfo,
ARRAY_SIZE(beagle_i2c_boardinfo));
/* Bus 3 is attached to the DVI port where devices like the pico DLP
* projector don't work reliably with 400kHz */
- omap_register_i2c_bus(3, 100, NULL, 0);
+ omap_register_i2c_bus(3, 100, beagle_i2c_eeprom, ARRAY_SIZE(beagle_i2c_eeprom));
return 0;
}
@@ -464,6 +561,7 @@ static struct omap_musb_board_data musb_board_data = {
static void __init omap3_beagle_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+ omap3_beagle_init_rev();
omap3_beagle_i2c_init();
platform_add_devices(omap3_beagle_devices,
ARRAY_SIZE(omap3_beagle_devices));
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 8936e4fba334..b04365c6bb10 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -31,6 +31,7 @@
#include <linux/smsc911x.h>
#include <linux/regulator/machine.h>
+#include <linux/mmc/host.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
@@ -370,7 +371,7 @@ static struct regulator_init_data omap3evm_vsim = {
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
- .wires = 4,
+ .caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = 63,
},
@@ -446,7 +447,7 @@ static struct twl4030_usb_data omap3evm_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
KEY(0, 0, KEY_LEFT),
KEY(0, 1, KEY_DOWN),
KEY(0, 2, KEY_ENTER),
@@ -584,7 +585,7 @@ static int ads7846_get_pendown_state(void)
return !gpio_get_value(OMAP3_EVM_TS_GPIO);
}
-struct ads7846_platform_data ads7846_config = {
+static struct ads7846_platform_data ads7846_config = {
.x_max = 0x0fff,
.y_max = 0x0fff,
.x_plate_ohms = 180,
@@ -603,7 +604,7 @@ static struct omap2_mcspi_device_config ads7846_mcspi_config = {
.single_channel = 1, /* 0: slave, 1: master */
};
-struct spi_board_info omap3evm_spi_board_info[] = {
+static struct spi_board_info omap3evm_spi_board_info[] = {
[0] = {
.modalias = "ads7846",
.bus_num = 1,
diff --git a/arch/arm/mach-omap2/board-omap3logic.c b/arch/arm/mach-omap2/board-omap3logic.c
new file mode 100644
index 000000000000..5f7d2c1e7ef5
--- /dev/null
+++ b/arch/arm/mach-omap2/board-omap3logic.c
@@ -0,0 +1,241 @@
+/*
+ * linux/arch/arm/mach-omap2/board-omap3logic.c
+ *
+ * Copyright (C) 2010 Li-Pro.Net
+ * Stephan Linz <linz@li-pro.net>
+ *
+ * Copyright (C) 2010 Logic Product Development, Inc.
+ * Peter Barada <peter.barada@logicpd.com>
+ *
+ * Modified from Beagle, EVM, and RX51
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <linux/regulator/machine.h>
+
+#include <linux/i2c/twl.h>
+#include <linux/mmc/host.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include "mux.h"
+#include "hsmmc.h"
+#include "timer-gp.h"
+#include "control.h"
+
+#include <plat/mux.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/gpmc-smsc911x.h>
+#include <plat/gpmc.h>
+#include <plat/sdrc.h>
+
+#define OMAP3LOGIC_SMSC911X_CS 1
+
+#define OMAP3530_LV_SOM_MMC_GPIO_CD 110
+#define OMAP3530_LV_SOM_MMC_GPIO_WP 126
+#define OMAP3530_LV_SOM_SMSC911X_GPIO_IRQ 152
+
+#define OMAP3_TORPEDO_MMC_GPIO_CD 127
+#define OMAP3_TORPEDO_SMSC911X_GPIO_IRQ 129
+
+static struct regulator_consumer_supply omap3logic_vmmc1_supply = {
+ .supply = "vmmc",
+};
+
+/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
+static struct regulator_init_data omap3logic_vmmc1 = {
+ .constraints = {
+ .name = "VMMC1",
+ .min_uV = 1850000,
+ .max_uV = 3150000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &omap3logic_vmmc1_supply,
+};
+
+static struct twl4030_gpio_platform_data omap3logic_gpio_data = {
+ .gpio_base = OMAP_MAX_GPIO_LINES,
+ .irq_base = TWL4030_GPIO_IRQ_BASE,
+ .irq_end = TWL4030_GPIO_IRQ_END,
+ .use_leds = true,
+ .pullups = BIT(1),
+ .pulldowns = BIT(2) | BIT(6) | BIT(7) | BIT(8)
+ | BIT(13) | BIT(15) | BIT(16) | BIT(17),
+};
+
+static struct twl4030_platform_data omap3logic_twldata = {
+ .irq_base = TWL4030_IRQ_BASE,
+ .irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .gpio = &omap3logic_gpio_data,
+ .vmmc1 = &omap3logic_vmmc1,
+};
+
+static struct i2c_board_info __initdata omap3logic_i2c_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("twl4030", 0x48),
+ .flags = I2C_CLIENT_WAKE,
+ .irq = INT_34XX_SYS_NIRQ,
+ .platform_data = &omap3logic_twldata,
+ },
+};
+
+static int __init omap3logic_i2c_init(void)
+{
+ omap_register_i2c_bus(1, 2600, omap3logic_i2c_boardinfo,
+ ARRAY_SIZE(omap3logic_i2c_boardinfo));
+ return 0;
+}
+
+static struct omap2_hsmmc_info __initdata board_mmc_info[] = {
+ {
+ .name = "external",
+ .mmc = 1,
+ .caps = MMC_CAP_4_BIT_DATA,
+ .gpio_cd = -EINVAL,
+ .gpio_wp = -EINVAL,
+ },
+ {} /* Terminator */
+};
+
+static void __init board_mmc_init(void)
+{
+ if (machine_is_omap3530_lv_som()) {
+ /* OMAP3530 LV SOM board */
+ board_mmc_info[0].gpio_cd = OMAP3530_LV_SOM_MMC_GPIO_CD;
+ board_mmc_info[0].gpio_wp = OMAP3530_LV_SOM_MMC_GPIO_WP;
+ omap_mux_init_signal("gpio_110", OMAP_PIN_OUTPUT);
+ omap_mux_init_signal("gpio_126", OMAP_PIN_OUTPUT);
+ } else if (machine_is_omap3_torpedo()) {
+ /* OMAP3 Torpedo board */
+ board_mmc_info[0].gpio_cd = OMAP3_TORPEDO_MMC_GPIO_CD;
+ omap_mux_init_signal("gpio_127", OMAP_PIN_OUTPUT);
+ } else {
+ /* unsupported board */
+ printk(KERN_ERR "%s(): unknown machine type\n", __func__);
+ return;
+ }
+
+ omap2_hsmmc_init(board_mmc_info);
+ /* link regulators to MMC adapters */
+ omap3logic_vmmc1_supply.dev = board_mmc_info[0].dev;
+}
+
+static struct omap_smsc911x_platform_data __initdata board_smsc911x_data = {
+ .cs = OMAP3LOGIC_SMSC911X_CS,
+ .gpio_irq = -EINVAL,
+ .gpio_reset = -EINVAL,
+ .flags = IORESOURCE_IRQ_LOWLEVEL,
+};
+
+/* TODO/FIXME (comment by Peter Barada, LogicPD):
+ * Fix the PBIAS voltage for Torpedo MMC1 pins that
+ * are used for other needs (IRQs, etc). */
+static void omap3torpedo_fix_pbias_voltage(void)
+{
+ u16 control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE;
+ u32 reg;
+
+ if (machine_is_omap3_torpedo())
+ {
+ /* Set the bias for the pin */
+ reg = omap_ctrl_readl(control_pbias_offset);
+
+ reg &= ~OMAP343X_PBIASLITEPWRDNZ1;
+ omap_ctrl_writel(reg, control_pbias_offset);
+
+ /* 100ms delay required for PBIAS configuration */
+ msleep(100);
+
+ reg |= OMAP343X_PBIASLITEVMODE1;
+ reg |= OMAP343X_PBIASLITEPWRDNZ1;
+ omap_ctrl_writel(reg | 0x300, control_pbias_offset);
+ }
+}
+
+static inline void __init board_smsc911x_init(void)
+{
+ if (machine_is_omap3530_lv_som()) {
+ /* OMAP3530 LV SOM board */
+ board_smsc911x_data.gpio_irq =
+ OMAP3530_LV_SOM_SMSC911X_GPIO_IRQ;
+ omap_mux_init_signal("gpio_152", OMAP_PIN_INPUT);
+ } else if (machine_is_omap3_torpedo()) {
+ /* OMAP3 Torpedo board */
+ board_smsc911x_data.gpio_irq = OMAP3_TORPEDO_SMSC911X_GPIO_IRQ;
+ omap_mux_init_signal("gpio_129", OMAP_PIN_INPUT);
+ } else {
+ /* unsupported board */
+ printk(KERN_ERR "%s(): unknown machine type\n", __func__);
+ return;
+ }
+
+ gpmc_smsc911x_init(&board_smsc911x_data);
+}
+
+static void __init omap3logic_init_irq(void)
+{
+ omap2_init_common_hw(NULL, NULL);
+ omap_init_irq();
+ omap_gpio_init();
+}
+
+#ifdef CONFIG_OMAP_MUX
+static struct omap_board_mux board_mux[] __initdata = {
+ { .reg_offset = OMAP_MUX_TERMINATOR },
+};
+#else
+#define board_mux NULL
+#endif
+
+static void __init omap3logic_init(void)
+{
+ omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+ omap3torpedo_fix_pbias_voltage();
+ omap3logic_i2c_init();
+ omap_serial_init();
+ board_mmc_init();
+ board_smsc911x_init();
+
+ /* Ensure SDRC pins are mux'd for self-refresh */
+ omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
+ omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
+}
+
+MACHINE_START(OMAP3_TORPEDO, "Logic OMAP3 Torpedo board")
+ .boot_params = 0x80000100,
+ .map_io = omap3_map_io,
+ .init_irq = omap3logic_init_irq,
+ .init_machine = omap3logic_init,
+ .timer = &omap_timer,
+MACHINE_END
+
+MACHINE_START(OMAP3530_LV_SOM, "OMAP Logic 3530 LV SOM board")
+ .boot_params = 0x80000100,
+ .map_io = omap3_map_io,
+ .init_irq = omap3logic_init_irq,
+ .init_machine = omap3logic_init,
+ .timer = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index b7d6df4e3cf9..89ed1be2d62e 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -25,14 +25,16 @@
#include <linux/spi/ads7846.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
-#include <linux/spi/wl12xx.h>
+#include <linux/wl12xx.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <linux/leds.h>
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/gpio_keys.h>
+#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
+#include <linux/regulator/fixed.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -276,14 +278,14 @@ static void pandora_wl1251_init_card(struct mmc_card *card)
static struct omap2_hsmmc_info omap3pandora_mmc[] = {
{
.mmc = 1,
- .wires = 4,
+ .caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = 126,
.ext_clock = 0,
},
{
.mmc = 2,
- .wires = 4,
+ .caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = 127,
.ext_clock = 1,
@@ -291,7 +293,7 @@ static struct omap2_hsmmc_info omap3pandora_mmc[] = {
},
{
.mmc = 3,
- .wires = 4,
+ .caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.init_card = pandora_wl1251_init_card,
@@ -344,6 +346,9 @@ static struct regulator_consumer_supply pandora_vmmc1_supply =
static struct regulator_consumer_supply pandora_vmmc2_supply =
REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.1");
+static struct regulator_consumer_supply pandora_vmmc3_supply =
+ REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.2");
+
static struct regulator_consumer_supply pandora_vdda_dac_supply =
REGULATOR_SUPPLY("vdda_dac", "omapdss");
@@ -488,6 +493,33 @@ static struct regulator_init_data pandora_vsim = {
.consumer_supplies = &pandora_adac_supply,
};
+/* Fixed regulator internal to Wifi module */
+static struct regulator_init_data pandora_vmmc3 = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &pandora_vmmc3_supply,
+};
+
+static struct fixed_voltage_config pandora_vwlan = {
+ .supply_name = "vwlan",
+ .microvolts = 1800000, /* 1.8V */
+ .gpio = PANDORA_WIFI_NRESET_GPIO,
+ .startup_delay = 50000, /* 50ms */
+ .enable_high = 1,
+ .enabled_at_boot = 0,
+ .init_data = &pandora_vmmc3,
+};
+
+static struct platform_device pandora_vwlan_device = {
+ .name = "reg-fixed-voltage",
+ .id = 1,
+ .dev = {
+ .platform_data = &pandora_vwlan,
+ },
+};
+
static struct twl4030_usb_data omap3pandora_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
@@ -501,6 +533,8 @@ static struct twl4030_codec_data omap3pandora_codec_data = {
.audio = &omap3pandora_audio_data,
};
+static struct twl4030_bci_platform_data pandora_bci_data;
+
static struct twl4030_platform_data omap3pandora_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
@@ -516,6 +550,7 @@ static struct twl4030_platform_data omap3pandora_twldata = {
.vaux4 = &pandora_vaux4,
.vsim = &pandora_vsim,
.keypad = &pandora_kp_data,
+ .bci = &pandora_bci_data,
};
static struct i2c_board_info __initdata omap3pandora_i2c_boardinfo[] = {
@@ -644,19 +679,8 @@ static void pandora_wl1251_init(void)
if (pandora_wl1251_pdata.irq < 0)
goto fail_irq;
- ret = gpio_request(PANDORA_WIFI_NRESET_GPIO, "wl1251 nreset");
- if (ret < 0)
- goto fail_irq;
-
- /* start powered so that it probes with MMC subsystem */
- ret = gpio_direction_output(PANDORA_WIFI_NRESET_GPIO, 1);
- if (ret < 0)
- goto fail_nreset;
-
return;
-fail_nreset:
- gpio_free(PANDORA_WIFI_NRESET_GPIO);
fail_irq:
gpio_free(PANDORA_WIFI_IRQ_GPIO);
fail:
@@ -668,6 +692,7 @@ static struct platform_device *omap3pandora_devices[] __initdata = {
&pandora_keys_gpio,
&pandora_dss_device,
&pandora_wl1251_data,
+ &pandora_vwlan_device,
};
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c
index bc5ac83bd4cf..f25272125413 100644
--- a/arch/arm/mach-omap2/board-omap3stalker.c
+++ b/arch/arm/mach-omap2/board-omap3stalker.c
@@ -26,6 +26,7 @@
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
+#include <linux/mmc/host.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
@@ -38,7 +39,6 @@
#include <plat/gpmc.h>
#include <plat/nand.h>
#include <plat/usb.h>
-#include <plat/timer-gp.h>
#include <plat/display.h>
#include <plat/mcspi.h>
@@ -52,6 +52,7 @@
#include "sdram-micron-mt46h32m32lf-6.h"
#include "mux.h"
#include "hsmmc.h"
+#include "timer-gp.h"
#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
#define OMAP3STALKER_ETHR_START 0x2c000000
@@ -275,7 +276,7 @@ static struct regulator_init_data omap3stalker_vsim = {
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
- .wires = 4,
+ .caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = 23,
},
@@ -389,7 +390,7 @@ static struct twl4030_usb_data omap3stalker_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
KEY(0, 0, KEY_LEFT),
KEY(0, 1, KEY_DOWN),
KEY(0, 2, KEY_ENTER),
@@ -564,7 +565,7 @@ static struct omap2_mcspi_device_config ads7846_mcspi_config = {
.single_channel = 1, /* 0: slave, 1: master */
};
-struct spi_board_info omap3stalker_spi_board_info[] = {
+static struct spi_board_info omap3stalker_spi_board_info[] = {
[0] = {
.modalias = "ads7846",
.bus_num = 1,
diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c
index 0e99ce584dbf..41104bb8774c 100644
--- a/arch/arm/mach-omap2/board-omap3touchbook.c
+++ b/arch/arm/mach-omap2/board-omap3touchbook.c
@@ -27,6 +27,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
+#include <linux/mmc/host.h>
#include <plat/mcspi.h>
#include <linux/spi/spi.h>
@@ -47,10 +48,10 @@
#include <plat/gpmc.h>
#include <plat/nand.h>
#include <plat/usb.h>
-#include <plat/timer-gp.h>
#include "mux.h"
#include "hsmmc.h"
+#include "timer-gp.h"
#include <asm/setup.h>
@@ -61,7 +62,7 @@
#define TB_BL_PWM_TIMER 9
#define TB_KILL_POWER_GPIO 168
-unsigned long touchbook_revision;
+static unsigned long touchbook_revision;
static struct mtd_partition omap3touchbook_nand_partitions[] = {
/* All the partition sizes are listed in terms of NAND block size */
@@ -108,7 +109,7 @@ static struct omap_nand_platform_data omap3touchbook_nand_data = {
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
- .wires = 8,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
.gpio_wp = 29,
},
{} /* Terminator */
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index db69bcadf4c7..702f2a63f2c1 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -20,6 +20,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/leds.h>
#include <linux/gpio.h>
#include <linux/usb/otg.h>
#include <linux/i2c/twl.h>
@@ -33,12 +34,45 @@
#include <plat/board.h>
#include <plat/common.h>
-#include <plat/control.h>
-#include <plat/timer-gp.h>
#include <plat/usb.h>
#include <plat/mmc.h>
+#include "timer-gp.h"
+
#include "hsmmc.h"
+#include "control.h"
+
+#define GPIO_HUB_POWER 1
+#define GPIO_HUB_NRESET 62
+
+static struct gpio_led gpio_leds[] = {
+ {
+ .name = "pandaboard::status1",
+ .default_trigger = "heartbeat",
+ .gpio = 7,
+ },
+ {
+ .name = "pandaboard::status2",
+ .default_trigger = "mmc0",
+ .gpio = 8,
+ },
+};
+static struct gpio_led_platform_data gpio_led_info = {
+ .leds = gpio_leds,
+ .num_leds = ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device leds_gpio = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &gpio_led_info,
+ },
+};
+
+static struct platform_device *panda_devices[] __initdata = {
+ &leds_gpio,
+};
static void __init omap4_panda_init_irq(void)
{
@@ -47,6 +81,56 @@ static void __init omap4_panda_init_irq(void)
omap_gpio_init();
}
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+ .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+ .port_mode[1] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+ .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+ .phy_reset = false,
+ .reset_gpio_port[0] = -EINVAL,
+ .reset_gpio_port[1] = -EINVAL,
+ .reset_gpio_port[2] = -EINVAL
+};
+
+static void __init omap4_ehci_init(void)
+{
+ int ret;
+
+
+ /* disable the power to the usb hub prior to init */
+ ret = gpio_request(GPIO_HUB_POWER, "hub_power");
+ if (ret) {
+ pr_err("Cannot request GPIO %d\n", GPIO_HUB_POWER);
+ goto error1;
+ }
+ gpio_export(GPIO_HUB_POWER, 0);
+ gpio_direction_output(GPIO_HUB_POWER, 0);
+ gpio_set_value(GPIO_HUB_POWER, 0);
+
+ /* reset phy+hub */
+ ret = gpio_request(GPIO_HUB_NRESET, "hub_nreset");
+ if (ret) {
+ pr_err("Cannot request GPIO %d\n", GPIO_HUB_NRESET);
+ goto error2;
+ }
+ gpio_export(GPIO_HUB_NRESET, 0);
+ gpio_direction_output(GPIO_HUB_NRESET, 0);
+ gpio_set_value(GPIO_HUB_NRESET, 0);
+ gpio_set_value(GPIO_HUB_NRESET, 1);
+
+ usb_ehci_init(&ehci_pdata);
+
+ /* enable power to hub */
+ gpio_set_value(GPIO_HUB_POWER, 1);
+ return;
+
+error2:
+ gpio_free(GPIO_HUB_POWER);
+error1:
+ pr_err("Unable to initialize EHCI power/reset\n");
+ return;
+
+}
+
static struct omap_musb_board_data musb_board_data = {
.interface_type = MUSB_INTERFACE_UTMI,
.mode = MUSB_PERIPHERAL,
@@ -56,7 +140,7 @@ static struct omap_musb_board_data musb_board_data = {
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
- .wires = 8,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
.gpio_wp = -EINVAL,
},
{} /* Terminator */
@@ -67,10 +151,6 @@ static struct regulator_consumer_supply omap4_panda_vmmc_supply[] = {
.supply = "vmmc",
.dev_name = "mmci-omap-hs.0",
},
- {
- .supply = "vmmc",
- .dev_name = "mmci-omap-hs.1",
- },
};
static int omap4_twl6030_hsmmc_late_init(struct device *dev)
@@ -89,7 +169,14 @@ static int omap4_twl6030_hsmmc_late_init(struct device *dev)
static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
{
- struct omap_mmc_platform_data *pdata = dev->platform_data;
+ struct omap_mmc_platform_data *pdata;
+
+ /* dev can be null if CONFIG_MMC_OMAP_HS is not set */
+ if (!dev) {
+ pr_err("Failed omap4_twl6030_hsmmc_set_late_init\n");
+ return;
+ }
+ pdata = dev->platform_data;
pdata->init = omap4_twl6030_hsmmc_late_init;
}
@@ -156,7 +243,7 @@ static struct regulator_init_data omap4_panda_vmmc = {
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
- .num_consumer_supplies = 2,
+ .num_consumer_supplies = 1,
.consumer_supplies = omap4_panda_vmmc_supply,
};
@@ -274,13 +361,13 @@ static int __init omap4_panda_i2c_init(void)
}
static void __init omap4_panda_init(void)
{
- int status;
-
omap4_panda_i2c_init();
+ platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices));
omap_serial_init();
omap4_twl6030_hsmmc_init(mmc);
/* OMAP4 Panda uses internal transceiver so register nop transceiver */
usb_nop_xceiv_register();
+ omap4_ehci_init();
/* FIXME: allow multi-omap to boot until musb is updated for omap4 */
if (!cpu_is_omap44xx())
usb_musb_init(&musb_board_data);
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 5e528ca015a1..7053bc0b46db 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -32,6 +32,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/mmc/host.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -303,13 +304,13 @@ static void __init overo_flash_init(void)
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
- .wires = 4,
+ .caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
},
{
.mmc = 2,
- .wires = 4,
+ .caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.transceiver = true,
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index 9a5eb87425fc..3fec4d62a91a 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -14,7 +14,7 @@
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/spi/spi.h>
-#include <linux/spi/wl12xx.h>
+#include <linux/wl12xx.h>
#include <linux/i2c.h>
#include <linux/i2c/twl.h>
#include <linux/clk.h>
@@ -23,6 +23,7 @@
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
#include <linux/mmc/host.h>
+#include <sound/tlv320aic3x.h>
#include <plat/mcspi.h>
#include <plat/board.h>
@@ -32,6 +33,8 @@
#include <plat/onenand.h>
#include <plat/gpmc-smc91x.h>
+#include <mach/board-rx51.h>
+
#include <sound/tlv320aic3x.h>
#include <sound/tpa6130a2-plat.h>
@@ -104,6 +107,10 @@ static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = {
},
};
+static struct platform_device rx51_charger_device = {
+ .name = "isp1704_charger",
+};
+
#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
#define RX51_GPIO_CAMERA_LENS_COVER 110
@@ -184,7 +191,7 @@ static void __init rx51_add_gpio_keys(void)
}
#endif /* CONFIG_KEYBOARD_GPIO || CONFIG_KEYBOARD_GPIO_MODULE */
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
/*
* Note that KEY(x, 8, KEY_XXX) entries represent "entrire row
* connected to the ground" matrix state.
@@ -302,7 +309,7 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
{
.name = "external",
.mmc = 1,
- .wires = 4,
+ .caps = MMC_CAP_4_BIT_DATA,
.cover_only = true,
.gpio_cd = 160,
.gpio_wp = -EINVAL,
@@ -311,7 +318,8 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
{
.name = "internal",
.mmc = 2,
- .wires = 8, /* See also rx51_mmc2_remux */
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+ /* See also rx51_mmc2_remux */
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.nonremovable = true,
@@ -689,7 +697,6 @@ static struct twl4030_power_data rx51_t2scripts_data __initdata = {
};
-
static struct twl4030_platform_data rx51_twldata __initdata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
@@ -710,10 +717,6 @@ static struct twl4030_platform_data rx51_twldata __initdata = {
.vio = &rx51_vio,
};
-static struct aic3x_pdata rx51_aic3x_data __initdata = {
- .gpio_reset = 60,
-};
-
static struct tpa6130a2_platform_data rx51_tpa6130a2_data __initdata = {
.id = TPA6130A2,
.power_gpio = 98,
@@ -728,6 +731,17 @@ static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_1[] = {
},
};
+/* Audio setup data */
+static struct aic3x_setup_data rx51_aic34_setup = {
+ .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
+ .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
+};
+
+static struct aic3x_pdata rx51_aic3x_data = {
+ .setup = &rx51_aic34_setup,
+ .gpio_reset = 60,
+};
+
static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = {
{
I2C_BOARD_INFO("tlv320aic3x", 0x18),
@@ -909,5 +923,6 @@ void __init rx51_peripherals_init(void)
spi_register_board_info(rx51_peripherals_spi_board_info,
ARRAY_SIZE(rx51_peripherals_spi_board_info));
omap2_hsmmc_init(mmc);
+ platform_device_register(&rx51_charger_device);
}
diff --git a/arch/arm/mach-omap2/board-rx51-sdram.c b/arch/arm/mach-omap2/board-rx51-sdram.c
index f392844195d2..a43b2c5c838b 100644
--- a/arch/arm/mach-omap2/board-rx51-sdram.c
+++ b/arch/arm/mach-omap2/board-rx51-sdram.c
@@ -43,7 +43,7 @@ struct sdram_timings {
u32 tWTR;
};
-struct omap_sdrc_params rx51_sdrc_params[4];
+static struct omap_sdrc_params rx51_sdrc_params[4];
static const struct sdram_timings rx51_timings[] = {
{
diff --git a/arch/arm/mach-omap2/board-rx51-video.c b/arch/arm/mach-omap2/board-rx51-video.c
index 5a1005ba9815..85503fed4e13 100644
--- a/arch/arm/mach-omap2/board-rx51-video.c
+++ b/arch/arm/mach-omap2/board-rx51-video.c
@@ -20,6 +20,8 @@
#include <plat/vram.h>
#include <plat/mcspi.h>
+#include <mach/board-rx51.h>
+
#include "mux.h"
#define RX51_LCD_RESET_GPIO 90
diff --git a/arch/arm/mach-omap2/board-zoom-debugboard.c b/arch/arm/mach-omap2/board-zoom-debugboard.c
index 1d7f827b0408..007ebdc6c993 100644
--- a/arch/arm/mach-omap2/board-zoom-debugboard.c
+++ b/arch/arm/mach-omap2/board-zoom-debugboard.c
@@ -16,6 +16,8 @@
#include <plat/gpmc.h>
+#include <mach/board-zoom.h>
+
#define ZOOM_SMSC911X_CS 7
#define ZOOM_SMSC911X_GPIO 158
#define ZOOM_QUADUART_CS 3
diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c
index 6b3984964cc5..86c9b2102952 100644
--- a/arch/arm/mach-omap2/board-zoom-peripherals.c
+++ b/arch/arm/mach-omap2/board-zoom-peripherals.c
@@ -16,6 +16,9 @@
#include <linux/gpio.h>
#include <linux/i2c/twl.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/wl12xx.h>
+#include <linux/mmc/host.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -24,11 +27,16 @@
#include <plat/common.h>
#include <plat/usb.h>
+#include <mach/board-zoom.h>
+
#include "mux.h"
#include "hsmmc.h"
+#define OMAP_ZOOM_WLAN_PMENA_GPIO (101)
+#define OMAP_ZOOM_WLAN_IRQ_GPIO (162)
+
/* Zoom2 has Qwerty keyboard*/
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
KEY(0, 0, KEY_E),
KEY(0, 1, KEY_R),
KEY(0, 2, KEY_T),
@@ -106,6 +114,11 @@ static struct regulator_consumer_supply zoom_vmmc2_supply = {
.supply = "vmmc",
};
+static struct regulator_consumer_supply zoom_vmmc3_supply = {
+ .supply = "vmmc",
+ .dev_name = "mmci-omap-hs.2",
+};
+
/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
static struct regulator_init_data zoom_vmmc1 = {
.constraints = {
@@ -151,23 +164,63 @@ static struct regulator_init_data zoom_vsim = {
.consumer_supplies = &zoom_vsim_supply,
};
+static struct regulator_init_data zoom_vmmc3 = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &zoom_vmmc3_supply,
+};
+
+static struct fixed_voltage_config zoom_vwlan = {
+ .supply_name = "vwl1271",
+ .microvolts = 1800000, /* 1.8V */
+ .gpio = OMAP_ZOOM_WLAN_PMENA_GPIO,
+ .startup_delay = 70000, /* 70msec */
+ .enable_high = 1,
+ .enabled_at_boot = 0,
+ .init_data = &zoom_vmmc3,
+};
+
+static struct platform_device omap_vwlan_device = {
+ .name = "reg-fixed-voltage",
+ .id = 1,
+ .dev = {
+ .platform_data = &zoom_vwlan,
+ },
+};
+
+struct wl12xx_platform_data omap_zoom_wlan_data __initdata = {
+ .irq = OMAP_GPIO_IRQ(OMAP_ZOOM_WLAN_IRQ_GPIO),
+ /* ZOOM ref clock is 26 MHz */
+ .board_ref_clock = 1,
+};
+
static struct omap2_hsmmc_info mmc[] __initdata = {
{
.name = "external",
.mmc = 1,
- .wires = 4,
+ .caps = MMC_CAP_4_BIT_DATA,
.gpio_wp = -EINVAL,
.power_saving = true,
},
{
.name = "internal",
.mmc = 2,
- .wires = 8,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.nonremovable = true,
.power_saving = true,
},
+ {
+ .name = "wl1271",
+ .mmc = 3,
+ .caps = MMC_CAP_4_BIT_DATA,
+ .gpio_wp = -EINVAL,
+ .gpio_cd = -EINVAL,
+ .nonremovable = true,
+ },
{} /* Terminator */
};
@@ -188,6 +241,11 @@ static int zoom_twl_gpio_setup(struct device *dev,
return 0;
}
+/* EXTMUTE callback function */
+void zoom2_set_hs_extmute(int mute)
+{
+ gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
+}
static int zoom_batt_table[] = {
/* 0 C*/
@@ -257,6 +315,11 @@ static struct i2c_board_info __initdata zoom_i2c_boardinfo[] = {
static int __init omap_i2c_init(void)
{
+ if (machine_is_omap_zoom2()) {
+ zoom_audio_data.ramp_delay_value = 3; /* 161 ms */
+ zoom_audio_data.hs_extmute = 1;
+ zoom_audio_data.set_hs_extmute = zoom2_set_hs_extmute;
+ }
omap_register_i2c_bus(1, 2400, zoom_i2c_boardinfo,
ARRAY_SIZE(zoom_i2c_boardinfo));
omap_register_i2c_bus(2, 400, NULL, 0);
@@ -279,7 +342,12 @@ static void enable_board_wakeup_source(void)
void __init zoom_peripherals_init(void)
{
+ if (wl12xx_set_platform_data(&omap_zoom_wlan_data))
+ pr_err("error setting wl12xx data\n");
+
omap_i2c_init();
+ platform_device_register(&omap_vwlan_device);
usb_musb_init(&musb_board_data);
enable_board_wakeup_source();
+ omap_serial_init();
}
diff --git a/arch/arm/mach-omap2/board-zoom2.c b/arch/arm/mach-omap2/board-zoom2.c
index 24bbd0def64f..2992a9f3a585 100644
--- a/arch/arm/mach-omap2/board-zoom2.c
+++ b/arch/arm/mach-omap2/board-zoom2.c
@@ -14,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/gpio.h>
+#include <linux/i2c/twl.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -23,6 +24,7 @@
#include <mach/board-zoom.h>
+#include "board-flash.h"
#include "mux.h"
#include "sdram-micron-mt46h32m32lf-6.h"
@@ -34,41 +36,6 @@ static void __init omap_zoom2_init_irq(void)
omap_gpio_init();
}
-/* REVISIT: These audio entries can be removed once MFD code is merged */
-#if 0
-
-static struct twl4030_madc_platform_data zoom2_madc_data = {
- .irq_line = 1,
-};
-
-static struct twl4030_codec_audio_data zoom2_audio_data = {
- .audio_mclk = 26000000,
-};
-
-static struct twl4030_codec_data zoom2_codec_data = {
- .audio_mclk = 26000000,
- .audio = &zoom2_audio_data,
-};
-
-static struct twl4030_platform_data zoom2_twldata = {
- .irq_base = TWL4030_IRQ_BASE,
- .irq_end = TWL4030_IRQ_END,
-
- /* platform_data for children goes here */
- .bci = &zoom2_bci_data,
- .madc = &zoom2_madc_data,
- .usb = &zoom2_usb_data,
- .gpio = &zoom2_gpio_data,
- .keypad = &zoom2_kp_twl4030_data,
- .codec = &zoom2_codec_data,
- .vmmc1 = &zoom2_vmmc1,
- .vmmc2 = &zoom2_vmmc2,
- .vsim = &zoom2_vsim,
-
-};
-
-#endif
-
#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
/* WLAN IRQ - GPIO 162 */
diff --git a/arch/arm/mach-omap2/board-zoom3.c b/arch/arm/mach-omap2/board-zoom3.c
index b2bb3ff971ac..5adde12c0395 100644
--- a/arch/arm/mach-omap2/board-zoom3.c
+++ b/arch/arm/mach-omap2/board-zoom3.c
@@ -22,6 +22,7 @@
#include <plat/board.h>
#include <plat/usb.h>
+#include "board-flash.h"
#include "mux.h"
#include "sdram-hynix-h8mbx00u0mer-0em.h"
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 605f531783a8..b5babf5440e4 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -395,7 +395,7 @@ void omap2_clk_disable_unused(struct clk *clk)
if ((regval32 & (1 << clk->enable_bit)) == v)
return;
- printk(KERN_DEBUG "Disabling unused clock \"%s\"\n", clk->name);
+ pr_debug("Disabling unused clock \"%s\"\n", clk->name);
if (cpu_is_omap34xx()) {
omap2_clk_enable(clk);
omap2_clk_disable(clk);
diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c
index 37d65d62ed8f..21f856252ad8 100644
--- a/arch/arm/mach-omap2/clock2420_data.c
+++ b/arch/arm/mach-omap2/clock2420_data.c
@@ -27,6 +27,7 @@
#include "prm-regbits-24xx.h"
#include "cm-regbits-24xx.h"
#include "sdrc.h"
+#include "control.h"
#define OMAP_CM_REGADDR OMAP2420_CM_REGADDR
@@ -89,6 +90,12 @@ static struct clk alt_ck = { /* Typical 54M or 48M, may not exist */
.clkdm_name = "wkup_clkdm",
};
+/* Optional external clock input for McBSP CLKS */
+static struct clk mcbsp_clks = {
+ .name = "mcbsp_clks",
+ .ops = &clkops_null,
+};
+
/*
* Analog domain root source clocks
*/
@@ -1135,14 +1142,34 @@ static struct clk mcbsp1_ick = {
.recalc = &followparent_recalc,
};
+static const struct clksel_rate common_mcbsp_96m_rates[] = {
+ { .div = 1, .val = 0, .flags = RATE_IN_24XX },
+ { .div = 0 }
+};
+
+static const struct clksel_rate common_mcbsp_mcbsp_rates[] = {
+ { .div = 1, .val = 1, .flags = RATE_IN_24XX },
+ { .div = 0 }
+};
+
+static const struct clksel mcbsp_fck_clksel[] = {
+ { .parent = &func_96m_ck, .rates = common_mcbsp_96m_rates },
+ { .parent = &mcbsp_clks, .rates = common_mcbsp_mcbsp_rates },
+ { .parent = NULL }
+};
+
static struct clk mcbsp1_fck = {
.name = "mcbsp1_fck",
.ops = &clkops_omap2_dflt_wait,
.parent = &func_96m_ck,
+ .init = &omap2_init_clksel_parent,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP24XX_EN_MCBSP1_SHIFT,
- .recalc = &followparent_recalc,
+ .clksel_reg = OMAP242X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+ .clksel_mask = OMAP2_MCBSP1_CLKS_MASK,
+ .clksel = mcbsp_fck_clksel,
+ .recalc = &omap2_clksel_recalc,
};
static struct clk mcbsp2_ick = {
@@ -1159,10 +1186,14 @@ static struct clk mcbsp2_fck = {
.name = "mcbsp2_fck",
.ops = &clkops_omap2_dflt_wait,
.parent = &func_96m_ck,
+ .init = &omap2_init_clksel_parent,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP24XX_EN_MCBSP2_SHIFT,
- .recalc = &followparent_recalc,
+ .clksel_reg = OMAP242X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+ .clksel_mask = OMAP2_MCBSP2_CLKS_MASK,
+ .clksel = mcbsp_fck_clksel,
+ .recalc = &omap2_clksel_recalc,
};
static struct clk mcspi1_ick = {
@@ -1721,6 +1752,9 @@ static struct omap_clk omap2420_clks[] = {
CLK(NULL, "osc_ck", &osc_ck, CK_242X),
CLK(NULL, "sys_ck", &sys_ck, CK_242X),
CLK(NULL, "alt_ck", &alt_ck, CK_242X),
+ CLK("omap-mcbsp.1", "pad_fck", &mcbsp_clks, CK_242X),
+ CLK("omap-mcbsp.2", "pad_fck", &mcbsp_clks, CK_242X),
+ CLK(NULL, "mcbsp_clks", &mcbsp_clks, CK_242X),
/* internal analog sources */
CLK(NULL, "dpll_ck", &dpll_ck, CK_242X),
CLK(NULL, "apll96_ck", &apll96_ck, CK_242X),
@@ -1728,6 +1762,8 @@ static struct omap_clk omap2420_clks[] = {
/* internal prcm root sources */
CLK(NULL, "func_54m_ck", &func_54m_ck, CK_242X),
CLK(NULL, "core_ck", &core_ck, CK_242X),
+ CLK("omap-mcbsp.1", "prcm_fck", &func_96m_ck, CK_242X),
+ CLK("omap-mcbsp.2", "prcm_fck", &func_96m_ck, CK_242X),
CLK(NULL, "func_96m_ck", &func_96m_ck, CK_242X),
CLK(NULL, "func_48m_ck", &func_48m_ck, CK_242X),
CLK(NULL, "func_12m_ck", &func_12m_ck, CK_242X),
@@ -1838,7 +1874,7 @@ static struct omap_clk omap2420_clks[] = {
CLK(NULL, "des_ick", &des_ick, CK_242X),
CLK("omap-sham", "ick", &sha_ick, CK_242X),
CLK("omap_rng", "ick", &rng_ick, CK_242X),
- CLK(NULL, "aes_ick", &aes_ick, CK_242X),
+ CLK("omap-aes", "ick", &aes_ick, CK_242X),
CLK(NULL, "pka_ick", &pka_ick, CK_242X),
CLK(NULL, "usb_fck", &usb_fck, CK_242X),
CLK("musb_hdrc", "fck", &osc_ck, CK_242X),
diff --git a/arch/arm/mach-omap2/clock2430_data.c b/arch/arm/mach-omap2/clock2430_data.c
index b33118fb6a87..e32afcbdfb88 100644
--- a/arch/arm/mach-omap2/clock2430_data.c
+++ b/arch/arm/mach-omap2/clock2430_data.c
@@ -27,6 +27,7 @@
#include "prm-regbits-24xx.h"
#include "cm-regbits-24xx.h"
#include "sdrc.h"
+#include "control.h"
#define OMAP_CM_REGADDR OMAP2430_CM_REGADDR
@@ -89,6 +90,12 @@ static struct clk alt_ck = { /* Typical 54M or 48M, may not exist */
.clkdm_name = "wkup_clkdm",
};
+/* Optional external clock input for McBSP CLKS */
+static struct clk mcbsp_clks = {
+ .name = "mcbsp_clks",
+ .ops = &clkops_null,
+};
+
/*
* Analog domain root source clocks
*/
@@ -1123,14 +1130,34 @@ static struct clk mcbsp1_ick = {
.recalc = &followparent_recalc,
};
+static const struct clksel_rate common_mcbsp_96m_rates[] = {
+ { .div = 1, .val = 0, .flags = RATE_IN_24XX },
+ { .div = 0 }
+};
+
+static const struct clksel_rate common_mcbsp_mcbsp_rates[] = {
+ { .div = 1, .val = 1, .flags = RATE_IN_24XX },
+ { .div = 0 }
+};
+
+static const struct clksel mcbsp_fck_clksel[] = {
+ { .parent = &func_96m_ck, .rates = common_mcbsp_96m_rates },
+ { .parent = &mcbsp_clks, .rates = common_mcbsp_mcbsp_rates },
+ { .parent = NULL }
+};
+
static struct clk mcbsp1_fck = {
.name = "mcbsp1_fck",
.ops = &clkops_omap2_dflt_wait,
.parent = &func_96m_ck,
+ .init = &omap2_init_clksel_parent,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP24XX_EN_MCBSP1_SHIFT,
- .recalc = &followparent_recalc,
+ .clksel_reg = OMAP243X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+ .clksel_mask = OMAP2_MCBSP1_CLKS_MASK,
+ .clksel = mcbsp_fck_clksel,
+ .recalc = &omap2_clksel_recalc,
};
static struct clk mcbsp2_ick = {
@@ -1147,10 +1174,14 @@ static struct clk mcbsp2_fck = {
.name = "mcbsp2_fck",
.ops = &clkops_omap2_dflt_wait,
.parent = &func_96m_ck,
+ .init = &omap2_init_clksel_parent,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP24XX_EN_MCBSP2_SHIFT,
- .recalc = &followparent_recalc,
+ .clksel_reg = OMAP243X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+ .clksel_mask = OMAP2_MCBSP2_CLKS_MASK,
+ .clksel = mcbsp_fck_clksel,
+ .recalc = &omap2_clksel_recalc,
};
static struct clk mcbsp3_ick = {
@@ -1167,10 +1198,14 @@ static struct clk mcbsp3_fck = {
.name = "mcbsp3_fck",
.ops = &clkops_omap2_dflt_wait,
.parent = &func_96m_ck,
+ .init = &omap2_init_clksel_parent,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
.enable_bit = OMAP2430_EN_MCBSP3_SHIFT,
- .recalc = &followparent_recalc,
+ .clksel_reg = OMAP243X_CTRL_REGADDR(OMAP243X_CONTROL_DEVCONF1),
+ .clksel_mask = OMAP2_MCBSP3_CLKS_MASK,
+ .clksel = mcbsp_fck_clksel,
+ .recalc = &omap2_clksel_recalc,
};
static struct clk mcbsp4_ick = {
@@ -1187,10 +1222,14 @@ static struct clk mcbsp4_fck = {
.name = "mcbsp4_fck",
.ops = &clkops_omap2_dflt_wait,
.parent = &func_96m_ck,
+ .init = &omap2_init_clksel_parent,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
.enable_bit = OMAP2430_EN_MCBSP4_SHIFT,
- .recalc = &followparent_recalc,
+ .clksel_reg = OMAP243X_CTRL_REGADDR(OMAP243X_CONTROL_DEVCONF1),
+ .clksel_mask = OMAP2_MCBSP4_CLKS_MASK,
+ .clksel = mcbsp_fck_clksel,
+ .recalc = &omap2_clksel_recalc,
};
static struct clk mcbsp5_ick = {
@@ -1207,10 +1246,14 @@ static struct clk mcbsp5_fck = {
.name = "mcbsp5_fck",
.ops = &clkops_omap2_dflt_wait,
.parent = &func_96m_ck,
+ .init = &omap2_init_clksel_parent,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
.enable_bit = OMAP2430_EN_MCBSP5_SHIFT,
- .recalc = &followparent_recalc,
+ .clksel_reg = OMAP243X_CTRL_REGADDR(OMAP243X_CONTROL_DEVCONF1),
+ .clksel_mask = OMAP2_MCBSP5_CLKS_MASK,
+ .clksel = mcbsp_fck_clksel,
+ .recalc = &omap2_clksel_recalc,
};
static struct clk mcspi1_ick = {
@@ -1808,6 +1851,12 @@ static struct omap_clk omap2430_clks[] = {
CLK(NULL, "osc_ck", &osc_ck, CK_243X),
CLK(NULL, "sys_ck", &sys_ck, CK_243X),
CLK(NULL, "alt_ck", &alt_ck, CK_243X),
+ CLK("omap-mcbsp.1", "pad_fck", &mcbsp_clks, CK_243X),
+ CLK("omap-mcbsp.2", "pad_fck", &mcbsp_clks, CK_243X),
+ CLK("omap-mcbsp.3", "pad_fck", &mcbsp_clks, CK_243X),
+ CLK("omap-mcbsp.4", "pad_fck", &mcbsp_clks, CK_243X),
+ CLK("omap-mcbsp.5", "pad_fck", &mcbsp_clks, CK_243X),
+ CLK(NULL, "mcbsp_clks", &mcbsp_clks, CK_243X),
/* internal analog sources */
CLK(NULL, "dpll_ck", &dpll_ck, CK_243X),
CLK(NULL, "apll96_ck", &apll96_ck, CK_243X),
@@ -1815,6 +1864,11 @@ static struct omap_clk omap2430_clks[] = {
/* internal prcm root sources */
CLK(NULL, "func_54m_ck", &func_54m_ck, CK_243X),
CLK(NULL, "core_ck", &core_ck, CK_243X),
+ CLK("omap-mcbsp.1", "prcm_fck", &func_96m_ck, CK_243X),
+ CLK("omap-mcbsp.2", "prcm_fck", &func_96m_ck, CK_243X),
+ CLK("omap-mcbsp.3", "prcm_fck", &func_96m_ck, CK_243X),
+ CLK("omap-mcbsp.4", "prcm_fck", &func_96m_ck, CK_243X),
+ CLK("omap-mcbsp.5", "prcm_fck", &func_96m_ck, CK_243X),
CLK(NULL, "func_96m_ck", &func_96m_ck, CK_243X),
CLK(NULL, "func_48m_ck", &func_48m_ck, CK_243X),
CLK(NULL, "func_12m_ck", &func_12m_ck, CK_243X),
@@ -1926,7 +1980,7 @@ static struct omap_clk omap2430_clks[] = {
CLK(NULL, "des_ick", &des_ick, CK_243X),
CLK("omap-sham", "ick", &sha_ick, CK_243X),
CLK("omap_rng", "ick", &rng_ick, CK_243X),
- CLK(NULL, "aes_ick", &aes_ick, CK_243X),
+ CLK("omap-aes", "ick", &aes_ick, CK_243X),
CLK(NULL, "pka_ick", &pka_ick, CK_243X),
CLK(NULL, "usb_fck", &usb_fck, CK_243X),
CLK("musb_hdrc", "ick", &usbhs_ick, CK_243X),
diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index dfdce2d82779..d85ecd5aebfd 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -20,7 +20,6 @@
#include <linux/clk.h>
#include <linux/list.h>
-#include <plat/control.h>
#include <plat/clkdev_omap.h>
#include "clock.h"
@@ -33,6 +32,7 @@
#include "cm-regbits-34xx.h"
#include "prm.h"
#include "prm-regbits-34xx.h"
+#include "control.h"
/*
* clocks
@@ -2465,6 +2465,16 @@ static struct clk uart3_fck = {
.recalc = &followparent_recalc,
};
+static struct clk uart4_fck = {
+ .name = "uart4_fck",
+ .ops = &clkops_omap2_dflt_wait,
+ .parent = &per_48m_fck,
+ .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+ .enable_bit = OMAP3630_EN_UART4_SHIFT,
+ .clkdm_name = "per_clkdm",
+ .recalc = &followparent_recalc,
+};
+
static struct clk gpt2_fck = {
.name = "gpt2_fck",
.ops = &clkops_omap2_dflt_wait,
@@ -2715,6 +2725,16 @@ static struct clk uart3_ick = {
.recalc = &followparent_recalc,
};
+static struct clk uart4_ick = {
+ .name = "uart4_ick",
+ .ops = &clkops_omap2_dflt_wait,
+ .parent = &per_l4_ick,
+ .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+ .enable_bit = OMAP3630_EN_UART4_SHIFT,
+ .clkdm_name = "per_clkdm",
+ .recalc = &followparent_recalc,
+};
+
static struct clk gpt9_ick = {
.name = "gpt9_ick",
.ops = &clkops_omap2_dflt_wait,
@@ -3188,6 +3208,11 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "osc_sys_ck", &osc_sys_ck, CK_3XXX),
CLK(NULL, "sys_ck", &sys_ck, CK_3XXX),
CLK(NULL, "sys_altclk", &sys_altclk, CK_3XXX),
+ CLK("omap-mcbsp.1", "pad_fck", &mcbsp_clks, CK_3XXX),
+ CLK("omap-mcbsp.2", "pad_fck", &mcbsp_clks, CK_3XXX),
+ CLK("omap-mcbsp.3", "pad_fck", &mcbsp_clks, CK_3XXX),
+ CLK("omap-mcbsp.4", "pad_fck", &mcbsp_clks, CK_3XXX),
+ CLK("omap-mcbsp.5", "pad_fck", &mcbsp_clks, CK_3XXX),
CLK(NULL, "mcbsp_clks", &mcbsp_clks, CK_3XXX),
CLK(NULL, "sys_clkout1", &sys_clkout1, CK_3XXX),
CLK(NULL, "dpll1_ck", &dpll1_ck, CK_3XXX),
@@ -3253,6 +3278,8 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "cpefuse_fck", &cpefuse_fck, CK_3430ES2 | CK_AM35XX),
CLK(NULL, "ts_fck", &ts_fck, CK_3430ES2 | CK_AM35XX),
CLK(NULL, "usbtll_fck", &usbtll_fck, CK_3430ES2 | CK_AM35XX),
+ CLK("omap-mcbsp.1", "prcm_fck", &core_96m_fck, CK_3XXX),
+ CLK("omap-mcbsp.5", "prcm_fck", &core_96m_fck, CK_3XXX),
CLK(NULL, "core_96m_fck", &core_96m_fck, CK_3XXX),
CLK("mmci-omap-hs.2", "fck", &mmchs3_fck, CK_3430ES2 | CK_AM35XX),
CLK("mmci-omap-hs.1", "fck", &mmchs2_fck, CK_3XXX),
@@ -3288,7 +3315,7 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "usbtll_ick", &usbtll_ick, CK_3430ES2 | CK_AM35XX),
CLK("mmci-omap-hs.2", "ick", &mmchs3_ick, CK_3430ES2 | CK_AM35XX),
CLK(NULL, "icr_ick", &icr_ick, CK_343X),
- CLK(NULL, "aes2_ick", &aes2_ick, CK_343X),
+ CLK("omap-aes", "ick", &aes2_ick, CK_343X),
CLK("omap-sham", "ick", &sha12_ick, CK_343X),
CLK(NULL, "des2_ick", &des2_ick, CK_343X),
CLK("mmci-omap-hs.1", "ick", &mmchs2_ick, CK_3XXX),
@@ -3346,9 +3373,13 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "omap_32ksync_ick", &omap_32ksync_ick, CK_3XXX),
CLK(NULL, "gpt12_ick", &gpt12_ick, CK_3XXX),
CLK(NULL, "gpt1_ick", &gpt1_ick, CK_3XXX),
+ CLK("omap-mcbsp.2", "prcm_fck", &per_96m_fck, CK_3XXX),
+ CLK("omap-mcbsp.3", "prcm_fck", &per_96m_fck, CK_3XXX),
+ CLK("omap-mcbsp.4", "prcm_fck", &per_96m_fck, CK_3XXX),
CLK(NULL, "per_96m_fck", &per_96m_fck, CK_3XXX),
CLK(NULL, "per_48m_fck", &per_48m_fck, CK_3XXX),
CLK(NULL, "uart3_fck", &uart3_fck, CK_3XXX),
+ CLK(NULL, "uart4_fck", &uart4_fck, CK_36XX),
CLK(NULL, "gpt2_fck", &gpt2_fck, CK_3XXX),
CLK(NULL, "gpt3_fck", &gpt3_fck, CK_3XXX),
CLK(NULL, "gpt4_fck", &gpt4_fck, CK_3XXX),
@@ -3372,6 +3403,7 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "gpio2_ick", &gpio2_ick, CK_3XXX),
CLK(NULL, "wdt3_ick", &wdt3_ick, CK_3XXX),
CLK(NULL, "uart3_ick", &uart3_ick, CK_3XXX),
+ CLK(NULL, "uart4_ick", &uart4_ick, CK_36XX),
CLK(NULL, "gpt9_ick", &gpt9_ick, CK_3XXX),
CLK(NULL, "gpt8_ick", &gpt8_ick, CK_3XXX),
CLK(NULL, "gpt7_ick", &gpt7_ick, CK_3XXX),
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index e10db7a90cb2..1599836ba3d9 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -17,13 +17,15 @@
* 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.
+ *
+ * XXX Some of the ES1 clocks have been removed/changed; once support
+ * is added for discriminating clocks by ES level, these should be added back
+ * in.
*/
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/clk.h>
-
-#include <plat/control.h>
#include <plat/clkdev_omap.h>
#include "clock.h"
@@ -32,6 +34,7 @@
#include "cm-regbits-44xx.h"
#include "prm.h"
#include "prm-regbits-44xx.h"
+#include "control.h"
/* Root clocks */
@@ -175,21 +178,27 @@ static struct clk sys_clkin_ck = {
.recalc = &omap2_clksel_recalc,
};
+static struct clk tie_low_clock_ck = {
+ .name = "tie_low_clock_ck",
+ .rate = 0,
+ .ops = &clkops_null,
+};
+
static struct clk utmi_phy_clkout_ck = {
.name = "utmi_phy_clkout_ck",
- .rate = 12000000,
+ .rate = 60000000,
.ops = &clkops_null,
};
static struct clk xclk60mhsp1_ck = {
.name = "xclk60mhsp1_ck",
- .rate = 12000000,
+ .rate = 60000000,
.ops = &clkops_null,
};
static struct clk xclk60mhsp2_ck = {
.name = "xclk60mhsp2_ck",
- .rate = 12000000,
+ .rate = 60000000,
.ops = &clkops_null,
};
@@ -201,39 +210,23 @@ static struct clk xclk60motg_ck = {
/* Module clocks and DPLL outputs */
-static const struct clksel_rate div2_1to2_rates[] = {
- { .div = 1, .val = 0, .flags = RATE_IN_4430 },
- { .div = 2, .val = 1, .flags = RATE_IN_4430 },
- { .div = 0 },
-};
-
-static const struct clksel dpll_sys_ref_clk_div[] = {
- { .parent = &sys_clkin_ck, .rates = div2_1to2_rates },
+static const struct clksel abe_dpll_bypass_clk_mux_sel[] = {
+ { .parent = &sys_clkin_ck, .rates = div_1_0_rates },
+ { .parent = &sys_32k_ck, .rates = div_1_1_rates },
{ .parent = NULL },
};
-static struct clk dpll_sys_ref_clk = {
- .name = "dpll_sys_ref_clk",
+static struct clk abe_dpll_bypass_clk_mux_ck = {
+ .name = "abe_dpll_bypass_clk_mux_ck",
.parent = &sys_clkin_ck,
- .clksel = dpll_sys_ref_clk_div,
- .clksel_reg = OMAP4430_CM_DPLL_SYS_REF_CLKSEL,
- .clksel_mask = OMAP4430_CLKSEL_0_0_MASK,
.ops = &clkops_null,
- .recalc = &omap2_clksel_recalc,
- .round_rate = &omap2_clksel_round_rate,
- .set_rate = &omap2_clksel_set_rate,
-};
-
-static const struct clksel abe_dpll_refclk_mux_sel[] = {
- { .parent = &dpll_sys_ref_clk, .rates = div_1_0_rates },
- { .parent = &sys_32k_ck, .rates = div_1_1_rates },
- { .parent = NULL },
+ .recalc = &followparent_recalc,
};
static struct clk abe_dpll_refclk_mux_ck = {
.name = "abe_dpll_refclk_mux_ck",
- .parent = &dpll_sys_ref_clk,
- .clksel = abe_dpll_refclk_mux_sel,
+ .parent = &sys_clkin_ck,
+ .clksel = abe_dpll_bypass_clk_mux_sel,
.init = &omap2_init_clksel_parent,
.clksel_reg = OMAP4430_CM_ABE_PLL_REF_CLKSEL,
.clksel_mask = OMAP4430_CLKSEL_0_0_MASK,
@@ -244,7 +237,7 @@ static struct clk abe_dpll_refclk_mux_ck = {
/* DPLL_ABE */
static struct dpll_data dpll_abe_dd = {
.mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_ABE,
- .clk_bypass = &sys_clkin_ck,
+ .clk_bypass = &abe_dpll_bypass_clk_mux_ck,
.clk_ref = &abe_dpll_refclk_mux_ck,
.control_reg = OMAP4430_CM_CLKMODE_DPLL_ABE,
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
@@ -310,6 +303,12 @@ static struct clk abe_clk = {
.set_rate = &omap2_clksel_set_rate,
};
+static const struct clksel_rate div2_1to2_rates[] = {
+ { .div = 1, .val = 0, .flags = RATE_IN_4430 },
+ { .div = 2, .val = 1, .flags = RATE_IN_4430 },
+ { .div = 0 },
+};
+
static const struct clksel aess_fclk_div[] = {
{ .parent = &abe_clk, .rates = div2_1to2_rates },
{ .parent = NULL },
@@ -380,14 +379,14 @@ static struct clk dpll_abe_m3_ck = {
};
static const struct clksel core_hsd_byp_clk_mux_sel[] = {
- { .parent = &dpll_sys_ref_clk, .rates = div_1_0_rates },
+ { .parent = &sys_clkin_ck, .rates = div_1_0_rates },
{ .parent = &dpll_abe_m3_ck, .rates = div_1_1_rates },
{ .parent = NULL },
};
static struct clk core_hsd_byp_clk_mux_ck = {
.name = "core_hsd_byp_clk_mux_ck",
- .parent = &dpll_sys_ref_clk,
+ .parent = &sys_clkin_ck,
.clksel = core_hsd_byp_clk_mux_sel,
.init = &omap2_init_clksel_parent,
.clksel_reg = OMAP4430_CM_CLKSEL_DPLL_CORE,
@@ -400,7 +399,7 @@ static struct clk core_hsd_byp_clk_mux_ck = {
static struct dpll_data dpll_core_dd = {
.mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_CORE,
.clk_bypass = &core_hsd_byp_clk_mux_ck,
- .clk_ref = &dpll_sys_ref_clk,
+ .clk_ref = &sys_clkin_ck,
.control_reg = OMAP4430_CM_CLKMODE_DPLL_CORE,
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
.autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_CORE,
@@ -418,7 +417,7 @@ static struct dpll_data dpll_core_dd = {
static struct clk dpll_core_ck = {
.name = "dpll_core_ck",
- .parent = &dpll_sys_ref_clk,
+ .parent = &sys_clkin_ck,
.dpll_data = &dpll_core_dd,
.init = &omap2_init_dpll_parent,
.ops = &clkops_null,
@@ -596,14 +595,14 @@ static struct clk dpll_core_m7_ck = {
};
static const struct clksel iva_hsd_byp_clk_mux_sel[] = {
- { .parent = &dpll_sys_ref_clk, .rates = div_1_0_rates },
+ { .parent = &sys_clkin_ck, .rates = div_1_0_rates },
{ .parent = &div_iva_hs_clk, .rates = div_1_1_rates },
{ .parent = NULL },
};
static struct clk iva_hsd_byp_clk_mux_ck = {
.name = "iva_hsd_byp_clk_mux_ck",
- .parent = &dpll_sys_ref_clk,
+ .parent = &sys_clkin_ck,
.ops = &clkops_null,
.recalc = &followparent_recalc,
};
@@ -612,7 +611,7 @@ static struct clk iva_hsd_byp_clk_mux_ck = {
static struct dpll_data dpll_iva_dd = {
.mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_IVA,
.clk_bypass = &iva_hsd_byp_clk_mux_ck,
- .clk_ref = &dpll_sys_ref_clk,
+ .clk_ref = &sys_clkin_ck,
.control_reg = OMAP4430_CM_CLKMODE_DPLL_IVA,
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
.autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_IVA,
@@ -630,7 +629,7 @@ static struct dpll_data dpll_iva_dd = {
static struct clk dpll_iva_ck = {
.name = "dpll_iva_ck",
- .parent = &dpll_sys_ref_clk,
+ .parent = &sys_clkin_ck,
.dpll_data = &dpll_iva_dd,
.init = &omap2_init_dpll_parent,
.ops = &clkops_omap3_noncore_dpll_ops,
@@ -672,7 +671,7 @@ static struct clk dpll_iva_m5_ck = {
static struct dpll_data dpll_mpu_dd = {
.mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_MPU,
.clk_bypass = &div_mpu_hs_clk,
- .clk_ref = &dpll_sys_ref_clk,
+ .clk_ref = &sys_clkin_ck,
.control_reg = OMAP4430_CM_CLKMODE_DPLL_MPU,
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
.autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_MPU,
@@ -690,7 +689,7 @@ static struct dpll_data dpll_mpu_dd = {
static struct clk dpll_mpu_ck = {
.name = "dpll_mpu_ck",
- .parent = &dpll_sys_ref_clk,
+ .parent = &sys_clkin_ck,
.dpll_data = &dpll_mpu_dd,
.init = &omap2_init_dpll_parent,
.ops = &clkops_omap3_noncore_dpll_ops,
@@ -724,14 +723,14 @@ static struct clk per_hs_clk_div_ck = {
};
static const struct clksel per_hsd_byp_clk_mux_sel[] = {
- { .parent = &dpll_sys_ref_clk, .rates = div_1_0_rates },
+ { .parent = &sys_clkin_ck, .rates = div_1_0_rates },
{ .parent = &per_hs_clk_div_ck, .rates = div_1_1_rates },
{ .parent = NULL },
};
static struct clk per_hsd_byp_clk_mux_ck = {
.name = "per_hsd_byp_clk_mux_ck",
- .parent = &dpll_sys_ref_clk,
+ .parent = &sys_clkin_ck,
.clksel = per_hsd_byp_clk_mux_sel,
.init = &omap2_init_clksel_parent,
.clksel_reg = OMAP4430_CM_CLKSEL_DPLL_PER,
@@ -744,7 +743,7 @@ static struct clk per_hsd_byp_clk_mux_ck = {
static struct dpll_data dpll_per_dd = {
.mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_PER,
.clk_bypass = &per_hsd_byp_clk_mux_ck,
- .clk_ref = &dpll_sys_ref_clk,
+ .clk_ref = &sys_clkin_ck,
.control_reg = OMAP4430_CM_CLKMODE_DPLL_PER,
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
.autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_PER,
@@ -762,7 +761,7 @@ static struct dpll_data dpll_per_dd = {
static struct clk dpll_per_ck = {
.name = "dpll_per_ck",
- .parent = &dpll_sys_ref_clk,
+ .parent = &sys_clkin_ck,
.dpll_data = &dpll_per_dd,
.init = &omap2_init_dpll_parent,
.ops = &clkops_omap3_noncore_dpll_ops,
@@ -858,8 +857,8 @@ static struct clk dpll_per_m7_ck = {
/* DPLL_UNIPRO */
static struct dpll_data dpll_unipro_dd = {
.mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_UNIPRO,
- .clk_bypass = &dpll_sys_ref_clk,
- .clk_ref = &dpll_sys_ref_clk,
+ .clk_bypass = &sys_clkin_ck,
+ .clk_ref = &sys_clkin_ck,
.control_reg = OMAP4430_CM_CLKMODE_DPLL_UNIPRO,
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
.autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_UNIPRO,
@@ -877,7 +876,7 @@ static struct dpll_data dpll_unipro_dd = {
static struct clk dpll_unipro_ck = {
.name = "dpll_unipro_ck",
- .parent = &dpll_sys_ref_clk,
+ .parent = &sys_clkin_ck,
.dpll_data = &dpll_unipro_dd,
.init = &omap2_init_dpll_parent,
.ops = &clkops_omap3_noncore_dpll_ops,
@@ -914,7 +913,8 @@ static struct clk usb_hs_clk_div_ck = {
static struct dpll_data dpll_usb_dd = {
.mult_div1_reg = OMAP4430_CM_CLKSEL_DPLL_USB,
.clk_bypass = &usb_hs_clk_div_ck,
- .clk_ref = &dpll_sys_ref_clk,
+ .flags = DPLL_J_TYPE | DPLL_NO_DCO_SEL,
+ .clk_ref = &sys_clkin_ck,
.control_reg = OMAP4430_CM_CLKMODE_DPLL_USB,
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
.autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_USB,
@@ -927,13 +927,12 @@ static struct dpll_data dpll_usb_dd = {
.max_multiplier = OMAP4430_MAX_DPLL_MULT,
.max_divider = OMAP4430_MAX_DPLL_DIV,
.min_divider = 1,
- .flags = DPLL_J_TYPE | DPLL_NO_DCO_SEL
};
static struct clk dpll_usb_ck = {
.name = "dpll_usb_ck",
- .parent = &dpll_sys_ref_clk,
+ .parent = &sys_clkin_ck,
.dpll_data = &dpll_usb_dd,
.init = &omap2_init_dpll_parent,
.ops = &clkops_omap3_noncore_dpll_ops,
@@ -1222,7 +1221,7 @@ static struct clk per_abe_24m_fclk = {
static const struct clksel pmd_stm_clock_mux_sel[] = {
{ .parent = &sys_clkin_ck, .rates = div_1_0_rates },
{ .parent = &dpll_core_m6_ck, .rates = div_1_1_rates },
- { .parent = &dpll_per_m7_ck, .rates = div_1_2_rates },
+ { .parent = &tie_low_clock_ck, .rates = div_1_2_rates },
{ .parent = NULL },
};
@@ -1240,10 +1239,15 @@ static struct clk pmd_trace_clk_mux_ck = {
.recalc = &followparent_recalc,
};
+static const struct clksel syc_clk_div_div[] = {
+ { .parent = &sys_clkin_ck, .rates = div2_1to2_rates },
+ { .parent = NULL },
+};
+
static struct clk syc_clk_div_ck = {
.name = "syc_clk_div_ck",
.parent = &sys_clkin_ck,
- .clksel = dpll_sys_ref_clk_div,
+ .clksel = syc_clk_div_div,
.clksel_reg = OMAP4430_CM_ABE_DSS_SYS_CLKSEL,
.clksel_mask = OMAP4430_CLKSEL_0_0_MASK,
.ops = &clkops_null,
@@ -1284,13 +1288,13 @@ static struct clk aess_fck = {
.recalc = &followparent_recalc,
};
-static struct clk cust_efuse_fck = {
- .name = "cust_efuse_fck",
+static struct clk bandgap_fclk = {
+ .name = "bandgap_fclk",
.ops = &clkops_omap2_dflt,
- .enable_reg = OMAP4430_CM_CEFUSE_CEFUSE_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "l4_cefuse_clkdm",
- .parent = &sys_clkin_ck,
+ .enable_reg = OMAP4430_CM_WKUP_BANDGAP_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_BGAP_32K_SHIFT,
+ .clkdm_name = "l4_wkup_clkdm",
+ .parent = &sys_32k_ck,
.recalc = &followparent_recalc,
};
@@ -1344,6 +1348,56 @@ static struct clk dmic_fck = {
.clkdm_name = "abe_clkdm",
};
+static struct clk dsp_fck = {
+ .name = "dsp_fck",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_TESLA_TESLA_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_HWCTRL,
+ .clkdm_name = "tesla_clkdm",
+ .parent = &dpll_iva_m4_ck,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk dss_sys_clk = {
+ .name = "dss_sys_clk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_SYS_CLK_SHIFT,
+ .clkdm_name = "l3_dss_clkdm",
+ .parent = &syc_clk_div_ck,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk dss_tv_clk = {
+ .name = "dss_tv_clk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_TV_CLK_SHIFT,
+ .clkdm_name = "l3_dss_clkdm",
+ .parent = &extalt_clkin_ck,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk dss_dss_clk = {
+ .name = "dss_dss_clk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_DSSCLK_SHIFT,
+ .clkdm_name = "l3_dss_clkdm",
+ .parent = &dpll_per_m5_ck,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk dss_48mhz_clk = {
+ .name = "dss_48mhz_clk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_48MHZ_CLK_SHIFT,
+ .clkdm_name = "l3_dss_clkdm",
+ .parent = &func_48mc_fclk,
+ .recalc = &followparent_recalc,
+};
+
static struct clk dss_fck = {
.name = "dss_fck",
.ops = &clkops_omap2_dflt,
@@ -1354,18 +1408,18 @@ static struct clk dss_fck = {
.recalc = &followparent_recalc,
};
-static struct clk ducati_ick = {
- .name = "ducati_ick",
+static struct clk efuse_ctrl_cust_fck = {
+ .name = "efuse_ctrl_cust_fck",
.ops = &clkops_omap2_dflt,
- .enable_reg = OMAP4430_CM_DUCATI_DUCATI_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_HWCTRL,
- .clkdm_name = "ducati_clkdm",
- .parent = &ducati_clk_mux_ck,
+ .enable_reg = OMAP4430_CM_CEFUSE_CEFUSE_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "l4_cefuse_clkdm",
+ .parent = &sys_clkin_ck,
.recalc = &followparent_recalc,
};
-static struct clk emif1_ick = {
- .name = "emif1_ick",
+static struct clk emif1_fck = {
+ .name = "emif1_fck",
.ops = &clkops_omap2_dflt,
.enable_reg = OMAP4430_CM_MEMIF_EMIF_1_CLKCTRL,
.enable_bit = OMAP4430_MODULEMODE_HWCTRL,
@@ -1375,8 +1429,8 @@ static struct clk emif1_ick = {
.recalc = &followparent_recalc,
};
-static struct clk emif2_ick = {
- .name = "emif2_ick",
+static struct clk emif2_fck = {
+ .name = "emif2_fck",
.ops = &clkops_omap2_dflt,
.enable_reg = OMAP4430_CM_MEMIF_EMIF_2_CLKCTRL,
.enable_bit = OMAP4430_MODULEMODE_HWCTRL,
@@ -1407,42 +1461,24 @@ static struct clk fdif_fck = {
.clkdm_name = "iss_clkdm",
};
-static const struct clksel per_sgx_fclk_div[] = {
- { .parent = &dpll_per_m2x2_ck, .rates = div3_1to4_rates },
- { .parent = NULL },
-};
-
-static struct clk per_sgx_fclk = {
- .name = "per_sgx_fclk",
- .parent = &dpll_per_m2x2_ck,
- .clksel = per_sgx_fclk_div,
- .clksel_reg = OMAP4430_CM_GFX_GFX_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_PER_192M_MASK,
- .ops = &clkops_null,
- .recalc = &omap2_clksel_recalc,
- .round_rate = &omap2_clksel_round_rate,
- .set_rate = &omap2_clksel_set_rate,
-};
-
-static const struct clksel sgx_clk_mux_sel[] = {
- { .parent = &dpll_core_m7_ck, .rates = div_1_0_rates },
- { .parent = &per_sgx_fclk, .rates = div_1_1_rates },
- { .parent = NULL },
+static struct clk fpka_fck = {
+ .name = "fpka_fck",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L4SEC_PKAEIP29_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "l4_secure_clkdm",
+ .parent = &l4_div_ck,
+ .recalc = &followparent_recalc,
};
-/* Merged sgx_clk_mux into gfx */
-static struct clk gfx_fck = {
- .name = "gfx_fck",
- .parent = &dpll_core_m7_ck,
- .clksel = sgx_clk_mux_sel,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP4430_CM_GFX_GFX_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_SGX_FCLK_MASK,
+static struct clk gpio1_dbclk = {
+ .name = "gpio1_dbclk",
.ops = &clkops_omap2_dflt,
- .recalc = &omap2_clksel_recalc,
- .enable_reg = OMAP4430_CM_GFX_GFX_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "l3_gfx_clkdm",
+ .enable_reg = OMAP4430_CM_WKUP_GPIO1_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+ .clkdm_name = "l4_wkup_clkdm",
+ .parent = &sys_32k_ck,
+ .recalc = &followparent_recalc,
};
static struct clk gpio1_ick = {
@@ -1455,6 +1491,16 @@ static struct clk gpio1_ick = {
.recalc = &followparent_recalc,
};
+static struct clk gpio2_dbclk = {
+ .name = "gpio2_dbclk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L4PER_GPIO2_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+ .clkdm_name = "l4_per_clkdm",
+ .parent = &sys_32k_ck,
+ .recalc = &followparent_recalc,
+};
+
static struct clk gpio2_ick = {
.name = "gpio2_ick",
.ops = &clkops_omap2_dflt,
@@ -1465,6 +1511,16 @@ static struct clk gpio2_ick = {
.recalc = &followparent_recalc,
};
+static struct clk gpio3_dbclk = {
+ .name = "gpio3_dbclk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L4PER_GPIO3_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+ .clkdm_name = "l4_per_clkdm",
+ .parent = &sys_32k_ck,
+ .recalc = &followparent_recalc,
+};
+
static struct clk gpio3_ick = {
.name = "gpio3_ick",
.ops = &clkops_omap2_dflt,
@@ -1475,6 +1531,16 @@ static struct clk gpio3_ick = {
.recalc = &followparent_recalc,
};
+static struct clk gpio4_dbclk = {
+ .name = "gpio4_dbclk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L4PER_GPIO4_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+ .clkdm_name = "l4_per_clkdm",
+ .parent = &sys_32k_ck,
+ .recalc = &followparent_recalc,
+};
+
static struct clk gpio4_ick = {
.name = "gpio4_ick",
.ops = &clkops_omap2_dflt,
@@ -1485,6 +1551,16 @@ static struct clk gpio4_ick = {
.recalc = &followparent_recalc,
};
+static struct clk gpio5_dbclk = {
+ .name = "gpio5_dbclk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L4PER_GPIO5_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+ .clkdm_name = "l4_per_clkdm",
+ .parent = &sys_32k_ck,
+ .recalc = &followparent_recalc,
+};
+
static struct clk gpio5_ick = {
.name = "gpio5_ick",
.ops = &clkops_omap2_dflt,
@@ -1495,6 +1571,16 @@ static struct clk gpio5_ick = {
.recalc = &followparent_recalc,
};
+static struct clk gpio6_dbclk = {
+ .name = "gpio6_dbclk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L4PER_GPIO6_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+ .clkdm_name = "l4_per_clkdm",
+ .parent = &sys_32k_ck,
+ .recalc = &followparent_recalc,
+};
+
static struct clk gpio6_ick = {
.name = "gpio6_ick",
.ops = &clkops_omap2_dflt,
@@ -1515,214 +1601,25 @@ static struct clk gpmc_ick = {
.recalc = &followparent_recalc,
};
-static const struct clksel dmt1_clk_mux_sel[] = {
- { .parent = &sys_clkin_ck, .rates = div_1_0_rates },
- { .parent = &sys_32k_ck, .rates = div_1_1_rates },
- { .parent = NULL },
-};
-
-/*
- * Merged dmt1_clk_mux into gptimer1
- * gptimer1 renamed temporarily into gpt1 to match OMAP3 convention
- */
-static struct clk gpt1_fck = {
- .name = "gpt1_fck",
- .parent = &sys_clkin_ck,
- .clksel = dmt1_clk_mux_sel,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP4430_CM_WKUP_TIMER1_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_MASK,
- .ops = &clkops_omap2_dflt,
- .recalc = &omap2_clksel_recalc,
- .enable_reg = OMAP4430_CM_WKUP_TIMER1_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "l4_wkup_clkdm",
-};
-
-/*
- * Merged cm2_dm10_mux into gptimer10
- * gptimer10 renamed temporarily into gpt10 to match OMAP3 convention
- */
-static struct clk gpt10_fck = {
- .name = "gpt10_fck",
- .parent = &sys_clkin_ck,
- .clksel = dmt1_clk_mux_sel,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_MASK,
- .ops = &clkops_omap2_dflt,
- .recalc = &omap2_clksel_recalc,
- .enable_reg = OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "l4_per_clkdm",
-};
-
-/*
- * Merged cm2_dm11_mux into gptimer11
- * gptimer11 renamed temporarily into gpt11 to match OMAP3 convention
- */
-static struct clk gpt11_fck = {
- .name = "gpt11_fck",
- .parent = &sys_clkin_ck,
- .clksel = dmt1_clk_mux_sel,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_MASK,
- .ops = &clkops_omap2_dflt,
- .recalc = &omap2_clksel_recalc,
- .enable_reg = OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "l4_per_clkdm",
-};
-
-/*
- * Merged cm2_dm2_mux into gptimer2
- * gptimer2 renamed temporarily into gpt2 to match OMAP3 convention
- */
-static struct clk gpt2_fck = {
- .name = "gpt2_fck",
- .parent = &sys_clkin_ck,
- .clksel = dmt1_clk_mux_sel,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_MASK,
- .ops = &clkops_omap2_dflt,
- .recalc = &omap2_clksel_recalc,
- .enable_reg = OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "l4_per_clkdm",
-};
-
-/*
- * Merged cm2_dm3_mux into gptimer3
- * gptimer3 renamed temporarily into gpt3 to match OMAP3 convention
- */
-static struct clk gpt3_fck = {
- .name = "gpt3_fck",
- .parent = &sys_clkin_ck,
- .clksel = dmt1_clk_mux_sel,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_MASK,
- .ops = &clkops_omap2_dflt,
- .recalc = &omap2_clksel_recalc,
- .enable_reg = OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "l4_per_clkdm",
-};
-
-/*
- * Merged cm2_dm4_mux into gptimer4
- * gptimer4 renamed temporarily into gpt4 to match OMAP3 convention
- */
-static struct clk gpt4_fck = {
- .name = "gpt4_fck",
- .parent = &sys_clkin_ck,
- .clksel = dmt1_clk_mux_sel,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_MASK,
- .ops = &clkops_omap2_dflt,
- .recalc = &omap2_clksel_recalc,
- .enable_reg = OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "l4_per_clkdm",
-};
-
-static const struct clksel timer5_sync_mux_sel[] = {
- { .parent = &syc_clk_div_ck, .rates = div_1_0_rates },
- { .parent = &sys_32k_ck, .rates = div_1_1_rates },
+static const struct clksel sgx_clk_mux_sel[] = {
+ { .parent = &dpll_core_m7_ck, .rates = div_1_0_rates },
+ { .parent = &dpll_per_m7_ck, .rates = div_1_1_rates },
{ .parent = NULL },
};
-/*
- * Merged timer5_sync_mux into gptimer5
- * gptimer5 renamed temporarily into gpt5 to match OMAP3 convention
- */
-static struct clk gpt5_fck = {
- .name = "gpt5_fck",
- .parent = &syc_clk_div_ck,
- .clksel = timer5_sync_mux_sel,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP4430_CM1_ABE_TIMER5_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_MASK,
- .ops = &clkops_omap2_dflt,
- .recalc = &omap2_clksel_recalc,
- .enable_reg = OMAP4430_CM1_ABE_TIMER5_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "abe_clkdm",
-};
-
-/*
- * Merged timer6_sync_mux into gptimer6
- * gptimer6 renamed temporarily into gpt6 to match OMAP3 convention
- */
-static struct clk gpt6_fck = {
- .name = "gpt6_fck",
- .parent = &syc_clk_div_ck,
- .clksel = timer5_sync_mux_sel,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP4430_CM1_ABE_TIMER6_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_MASK,
- .ops = &clkops_omap2_dflt,
- .recalc = &omap2_clksel_recalc,
- .enable_reg = OMAP4430_CM1_ABE_TIMER6_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "abe_clkdm",
-};
-
-/*
- * Merged timer7_sync_mux into gptimer7
- * gptimer7 renamed temporarily into gpt7 to match OMAP3 convention
- */
-static struct clk gpt7_fck = {
- .name = "gpt7_fck",
- .parent = &syc_clk_div_ck,
- .clksel = timer5_sync_mux_sel,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP4430_CM1_ABE_TIMER7_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_MASK,
- .ops = &clkops_omap2_dflt,
- .recalc = &omap2_clksel_recalc,
- .enable_reg = OMAP4430_CM1_ABE_TIMER7_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "abe_clkdm",
-};
-
-/*
- * Merged timer8_sync_mux into gptimer8
- * gptimer8 renamed temporarily into gpt8 to match OMAP3 convention
- */
-static struct clk gpt8_fck = {
- .name = "gpt8_fck",
- .parent = &syc_clk_div_ck,
- .clksel = timer5_sync_mux_sel,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP4430_CM1_ABE_TIMER8_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_MASK,
- .ops = &clkops_omap2_dflt,
- .recalc = &omap2_clksel_recalc,
- .enable_reg = OMAP4430_CM1_ABE_TIMER8_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "abe_clkdm",
-};
-
-/*
- * Merged cm2_dm9_mux into gptimer9
- * gptimer9 renamed temporarily into gpt9 to match OMAP3 convention
- */
-static struct clk gpt9_fck = {
- .name = "gpt9_fck",
- .parent = &sys_clkin_ck,
- .clksel = dmt1_clk_mux_sel,
+/* Merged sgx_clk_mux into gpu */
+static struct clk gpu_fck = {
+ .name = "gpu_fck",
+ .parent = &dpll_core_m7_ck,
+ .clksel = sgx_clk_mux_sel,
.init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_MASK,
+ .clksel_reg = OMAP4430_CM_GFX_GFX_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_SGX_FCLK_MASK,
.ops = &clkops_omap2_dflt,
.recalc = &omap2_clksel_recalc,
- .enable_reg = OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
+ .enable_reg = OMAP4430_CM_GFX_GFX_CLKCTRL,
.enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "l4_per_clkdm",
+ .clkdm_name = "l3_gfx_clkdm",
};
static struct clk hdq1w_fck = {
@@ -1735,11 +1632,16 @@ static struct clk hdq1w_fck = {
.recalc = &followparent_recalc,
};
+static const struct clksel hsi_fclk_div[] = {
+ { .parent = &dpll_per_m2x2_ck, .rates = div3_1to4_rates },
+ { .parent = NULL },
+};
+
/* Merged hsi_fclk into hsi */
-static struct clk hsi_ick = {
- .name = "hsi_ick",
+static struct clk hsi_fck = {
+ .name = "hsi_fck",
.parent = &dpll_per_m2x2_ck,
- .clksel = per_sgx_fclk_div,
+ .clksel = hsi_fclk_div,
.clksel_reg = OMAP4430_CM_L3INIT_HSI_CLKCTRL,
.clksel_mask = OMAP4430_CLKSEL_24_25_MASK,
.ops = &clkops_omap2_dflt,
@@ -1791,6 +1693,26 @@ static struct clk i2c4_fck = {
.recalc = &followparent_recalc,
};
+static struct clk ipu_fck = {
+ .name = "ipu_fck",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_DUCATI_DUCATI_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_HWCTRL,
+ .clkdm_name = "ducati_clkdm",
+ .parent = &ducati_clk_mux_ck,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk iss_ctrlclk = {
+ .name = "iss_ctrlclk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_CAM_ISS_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_CTRLCLK_SHIFT,
+ .clkdm_name = "iss_clkdm",
+ .parent = &func_96m_fclk,
+ .recalc = &followparent_recalc,
+};
+
static struct clk iss_fck = {
.name = "iss_fck",
.ops = &clkops_omap2_dflt,
@@ -1801,8 +1723,8 @@ static struct clk iss_fck = {
.recalc = &followparent_recalc,
};
-static struct clk ivahd_ick = {
- .name = "ivahd_ick",
+static struct clk iva_fck = {
+ .name = "iva_fck",
.ops = &clkops_omap2_dflt,
.enable_reg = OMAP4430_CM_IVAHD_IVAHD_CLKCTRL,
.enable_bit = OMAP4430_MODULEMODE_HWCTRL,
@@ -1811,8 +1733,8 @@ static struct clk ivahd_ick = {
.recalc = &followparent_recalc,
};
-static struct clk keyboard_fck = {
- .name = "keyboard_fck",
+static struct clk kbd_fck = {
+ .name = "kbd_fck",
.ops = &clkops_omap2_dflt,
.enable_reg = OMAP4430_CM_WKUP_KEYBOARD_CLKCTRL,
.enable_bit = OMAP4430_MODULEMODE_SWCTRL,
@@ -1821,8 +1743,8 @@ static struct clk keyboard_fck = {
.recalc = &followparent_recalc,
};
-static struct clk l3_instr_interconnect_ick = {
- .name = "l3_instr_interconnect_ick",
+static struct clk l3_instr_ick = {
+ .name = "l3_instr_ick",
.ops = &clkops_omap2_dflt,
.enable_reg = OMAP4430_CM_L3INSTR_L3_INSTR_CLKCTRL,
.enable_bit = OMAP4430_MODULEMODE_HWCTRL,
@@ -1831,8 +1753,8 @@ static struct clk l3_instr_interconnect_ick = {
.recalc = &followparent_recalc,
};
-static struct clk l3_interconnect_3_ick = {
- .name = "l3_interconnect_3_ick",
+static struct clk l3_main_3_ick = {
+ .name = "l3_main_3_ick",
.ops = &clkops_omap2_dflt,
.enable_reg = OMAP4430_CM_L3INSTR_L3_3_CLKCTRL,
.enable_bit = OMAP4430_MODULEMODE_HWCTRL,
@@ -2005,6 +1927,16 @@ static struct clk mcbsp4_fck = {
.clkdm_name = "l4_per_clkdm",
};
+static struct clk mcpdm_fck = {
+ .name = "mcpdm_fck",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM1_ABE_PDM_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "abe_clkdm",
+ .parent = &pad_clks_ck,
+ .recalc = &followparent_recalc,
+};
+
static struct clk mcspi1_fck = {
.name = "mcspi1_fck",
.ops = &clkops_omap2_dflt,
@@ -2105,33 +2037,33 @@ static struct clk mmc5_fck = {
.recalc = &followparent_recalc,
};
-static struct clk ocp_wp1_ick = {
- .name = "ocp_wp1_ick",
+static struct clk ocp2scp_usb_phy_phy_48m = {
+ .name = "ocp2scp_usb_phy_phy_48m",
.ops = &clkops_omap2_dflt,
- .enable_reg = OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_HWCTRL,
- .clkdm_name = "l3_instr_clkdm",
- .parent = &l3_div_ck,
+ .enable_reg = OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_PHY_48M_SHIFT,
+ .clkdm_name = "l3_init_clkdm",
+ .parent = &func_48m_fclk,
.recalc = &followparent_recalc,
};
-static struct clk pdm_fck = {
- .name = "pdm_fck",
+static struct clk ocp2scp_usb_phy_ick = {
+ .name = "ocp2scp_usb_phy_ick",
.ops = &clkops_omap2_dflt,
- .enable_reg = OMAP4430_CM1_ABE_PDM_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "abe_clkdm",
- .parent = &pad_clks_ck,
+ .enable_reg = OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_HWCTRL,
+ .clkdm_name = "l3_init_clkdm",
+ .parent = &l4_div_ck,
.recalc = &followparent_recalc,
};
-static struct clk pkaeip29_fck = {
- .name = "pkaeip29_fck",
+static struct clk ocp_wp_noc_ick = {
+ .name = "ocp_wp_noc_ick",
.ops = &clkops_omap2_dflt,
- .enable_reg = OMAP4430_CM_L4SEC_PKAEIP29_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "l4_secure_clkdm",
- .parent = &l4_div_ck,
+ .enable_reg = OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_HWCTRL,
+ .clkdm_name = "l3_instr_clkdm",
+ .parent = &l3_div_ck,
.recalc = &followparent_recalc,
};
@@ -2145,8 +2077,8 @@ static struct clk rng_ick = {
.recalc = &followparent_recalc,
};
-static struct clk sha2md51_fck = {
- .name = "sha2md51_fck",
+static struct clk sha2md5_fck = {
+ .name = "sha2md5_fck",
.ops = &clkops_omap2_dflt,
.enable_reg = OMAP4430_CM_L4SEC_SHA2MD51_CLKCTRL,
.enable_bit = OMAP4430_MODULEMODE_SWCTRL,
@@ -2155,8 +2087,8 @@ static struct clk sha2md51_fck = {
.recalc = &followparent_recalc,
};
-static struct clk sl2_ick = {
- .name = "sl2_ick",
+static struct clk sl2if_ick = {
+ .name = "sl2if_ick",
.ops = &clkops_omap2_dflt,
.enable_reg = OMAP4430_CM_IVAHD_SL2_CLKCTRL,
.enable_bit = OMAP4430_MODULEMODE_HWCTRL,
@@ -2165,6 +2097,46 @@ static struct clk sl2_ick = {
.recalc = &followparent_recalc,
};
+static struct clk slimbus1_fclk_1 = {
+ .name = "slimbus1_fclk_1",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_FCLK1_SHIFT,
+ .clkdm_name = "abe_clkdm",
+ .parent = &func_24m_clk,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk slimbus1_fclk_0 = {
+ .name = "slimbus1_fclk_0",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_FCLK0_SHIFT,
+ .clkdm_name = "abe_clkdm",
+ .parent = &abe_24m_fclk,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk slimbus1_fclk_2 = {
+ .name = "slimbus1_fclk_2",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_FCLK2_SHIFT,
+ .clkdm_name = "abe_clkdm",
+ .parent = &pad_clks_ck,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk slimbus1_slimbus_clk = {
+ .name = "slimbus1_slimbus_clk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_SHIFT,
+ .clkdm_name = "abe_clkdm",
+ .parent = &slimbus_clk,
+ .recalc = &followparent_recalc,
+};
+
static struct clk slimbus1_fck = {
.name = "slimbus1_fck",
.ops = &clkops_omap2_dflt,
@@ -2175,6 +2147,36 @@ static struct clk slimbus1_fck = {
.recalc = &followparent_recalc,
};
+static struct clk slimbus2_fclk_1 = {
+ .name = "slimbus2_fclk_1",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_SHIFT,
+ .clkdm_name = "l4_per_clkdm",
+ .parent = &per_abe_24m_fclk,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk slimbus2_fclk_0 = {
+ .name = "slimbus2_fclk_0",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_PER24MC_GFCLK_SHIFT,
+ .clkdm_name = "l4_per_clkdm",
+ .parent = &func_24mc_fclk,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk slimbus2_slimbus_clk = {
+ .name = "slimbus2_slimbus_clk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_SLIMBUS_CLK_SHIFT,
+ .clkdm_name = "l4_per_clkdm",
+ .parent = &pad_slimbus_core_clks_ck,
+ .recalc = &followparent_recalc,
+};
+
static struct clk slimbus2_fck = {
.name = "slimbus2_fck",
.ops = &clkops_omap2_dflt,
@@ -2185,8 +2187,8 @@ static struct clk slimbus2_fck = {
.recalc = &followparent_recalc,
};
-static struct clk sr_core_fck = {
- .name = "sr_core_fck",
+static struct clk smartreflex_core_fck = {
+ .name = "smartreflex_core_fck",
.ops = &clkops_omap2_dflt,
.enable_reg = OMAP4430_CM_ALWON_SR_CORE_CLKCTRL,
.enable_bit = OMAP4430_MODULEMODE_SWCTRL,
@@ -2195,8 +2197,8 @@ static struct clk sr_core_fck = {
.recalc = &followparent_recalc,
};
-static struct clk sr_iva_fck = {
- .name = "sr_iva_fck",
+static struct clk smartreflex_iva_fck = {
+ .name = "smartreflex_iva_fck",
.ops = &clkops_omap2_dflt,
.enable_reg = OMAP4430_CM_ALWON_SR_IVA_CLKCTRL,
.enable_bit = OMAP4430_MODULEMODE_SWCTRL,
@@ -2205,8 +2207,8 @@ static struct clk sr_iva_fck = {
.recalc = &followparent_recalc,
};
-static struct clk sr_mpu_fck = {
- .name = "sr_mpu_fck",
+static struct clk smartreflex_mpu_fck = {
+ .name = "smartreflex_mpu_fck",
.ops = &clkops_omap2_dflt,
.enable_reg = OMAP4430_CM_ALWON_SR_MPU_CLKCTRL,
.enable_bit = OMAP4430_MODULEMODE_SWCTRL,
@@ -2215,14 +2217,175 @@ static struct clk sr_mpu_fck = {
.recalc = &followparent_recalc,
};
-static struct clk tesla_ick = {
- .name = "tesla_ick",
+/* Merged dmt1_clk_mux into timer1 */
+static struct clk timer1_fck = {
+ .name = "timer1_fck",
+ .parent = &sys_clkin_ck,
+ .clksel = abe_dpll_bypass_clk_mux_sel,
+ .init = &omap2_init_clksel_parent,
+ .clksel_reg = OMAP4430_CM_WKUP_TIMER1_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_MASK,
.ops = &clkops_omap2_dflt,
- .enable_reg = OMAP4430_CM_TESLA_TESLA_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_HWCTRL,
- .clkdm_name = "tesla_clkdm",
- .parent = &dpll_iva_m4_ck,
- .recalc = &followparent_recalc,
+ .recalc = &omap2_clksel_recalc,
+ .enable_reg = OMAP4430_CM_WKUP_TIMER1_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "l4_wkup_clkdm",
+};
+
+/* Merged cm2_dm10_mux into timer10 */
+static struct clk timer10_fck = {
+ .name = "timer10_fck",
+ .parent = &sys_clkin_ck,
+ .clksel = abe_dpll_bypass_clk_mux_sel,
+ .init = &omap2_init_clksel_parent,
+ .clksel_reg = OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_MASK,
+ .ops = &clkops_omap2_dflt,
+ .recalc = &omap2_clksel_recalc,
+ .enable_reg = OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "l4_per_clkdm",
+};
+
+/* Merged cm2_dm11_mux into timer11 */
+static struct clk timer11_fck = {
+ .name = "timer11_fck",
+ .parent = &sys_clkin_ck,
+ .clksel = abe_dpll_bypass_clk_mux_sel,
+ .init = &omap2_init_clksel_parent,
+ .clksel_reg = OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_MASK,
+ .ops = &clkops_omap2_dflt,
+ .recalc = &omap2_clksel_recalc,
+ .enable_reg = OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "l4_per_clkdm",
+};
+
+/* Merged cm2_dm2_mux into timer2 */
+static struct clk timer2_fck = {
+ .name = "timer2_fck",
+ .parent = &sys_clkin_ck,
+ .clksel = abe_dpll_bypass_clk_mux_sel,
+ .init = &omap2_init_clksel_parent,
+ .clksel_reg = OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_MASK,
+ .ops = &clkops_omap2_dflt,
+ .recalc = &omap2_clksel_recalc,
+ .enable_reg = OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "l4_per_clkdm",
+};
+
+/* Merged cm2_dm3_mux into timer3 */
+static struct clk timer3_fck = {
+ .name = "timer3_fck",
+ .parent = &sys_clkin_ck,
+ .clksel = abe_dpll_bypass_clk_mux_sel,
+ .init = &omap2_init_clksel_parent,
+ .clksel_reg = OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_MASK,
+ .ops = &clkops_omap2_dflt,
+ .recalc = &omap2_clksel_recalc,
+ .enable_reg = OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "l4_per_clkdm",
+};
+
+/* Merged cm2_dm4_mux into timer4 */
+static struct clk timer4_fck = {
+ .name = "timer4_fck",
+ .parent = &sys_clkin_ck,
+ .clksel = abe_dpll_bypass_clk_mux_sel,
+ .init = &omap2_init_clksel_parent,
+ .clksel_reg = OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_MASK,
+ .ops = &clkops_omap2_dflt,
+ .recalc = &omap2_clksel_recalc,
+ .enable_reg = OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "l4_per_clkdm",
+};
+
+static const struct clksel timer5_sync_mux_sel[] = {
+ { .parent = &syc_clk_div_ck, .rates = div_1_0_rates },
+ { .parent = &sys_32k_ck, .rates = div_1_1_rates },
+ { .parent = NULL },
+};
+
+/* Merged timer5_sync_mux into timer5 */
+static struct clk timer5_fck = {
+ .name = "timer5_fck",
+ .parent = &syc_clk_div_ck,
+ .clksel = timer5_sync_mux_sel,
+ .init = &omap2_init_clksel_parent,
+ .clksel_reg = OMAP4430_CM1_ABE_TIMER5_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_MASK,
+ .ops = &clkops_omap2_dflt,
+ .recalc = &omap2_clksel_recalc,
+ .enable_reg = OMAP4430_CM1_ABE_TIMER5_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "abe_clkdm",
+};
+
+/* Merged timer6_sync_mux into timer6 */
+static struct clk timer6_fck = {
+ .name = "timer6_fck",
+ .parent = &syc_clk_div_ck,
+ .clksel = timer5_sync_mux_sel,
+ .init = &omap2_init_clksel_parent,
+ .clksel_reg = OMAP4430_CM1_ABE_TIMER6_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_MASK,
+ .ops = &clkops_omap2_dflt,
+ .recalc = &omap2_clksel_recalc,
+ .enable_reg = OMAP4430_CM1_ABE_TIMER6_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "abe_clkdm",
+};
+
+/* Merged timer7_sync_mux into timer7 */
+static struct clk timer7_fck = {
+ .name = "timer7_fck",
+ .parent = &syc_clk_div_ck,
+ .clksel = timer5_sync_mux_sel,
+ .init = &omap2_init_clksel_parent,
+ .clksel_reg = OMAP4430_CM1_ABE_TIMER7_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_MASK,
+ .ops = &clkops_omap2_dflt,
+ .recalc = &omap2_clksel_recalc,
+ .enable_reg = OMAP4430_CM1_ABE_TIMER7_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "abe_clkdm",
+};
+
+/* Merged timer8_sync_mux into timer8 */
+static struct clk timer8_fck = {
+ .name = "timer8_fck",
+ .parent = &syc_clk_div_ck,
+ .clksel = timer5_sync_mux_sel,
+ .init = &omap2_init_clksel_parent,
+ .clksel_reg = OMAP4430_CM1_ABE_TIMER8_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_MASK,
+ .ops = &clkops_omap2_dflt,
+ .recalc = &omap2_clksel_recalc,
+ .enable_reg = OMAP4430_CM1_ABE_TIMER8_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "abe_clkdm",
+};
+
+/* Merged cm2_dm9_mux into timer9 */
+static struct clk timer9_fck = {
+ .name = "timer9_fck",
+ .parent = &sys_clkin_ck,
+ .clksel = abe_dpll_bypass_clk_mux_sel,
+ .init = &omap2_init_clksel_parent,
+ .clksel_reg = OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_MASK,
+ .ops = &clkops_omap2_dflt,
+ .recalc = &omap2_clksel_recalc,
+ .enable_reg = OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "l4_per_clkdm",
};
static struct clk uart1_fck = {
@@ -2265,105 +2428,148 @@ static struct clk uart4_fck = {
.recalc = &followparent_recalc,
};
-static struct clk unipro1_fck = {
- .name = "unipro1_fck",
+static struct clk usb_host_fs_fck = {
+ .name = "usb_host_fs_fck",
.ops = &clkops_omap2_dflt,
- .enable_reg = OMAP4430_CM_L3INIT_UNIPRO1_CLKCTRL,
+ .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_FS_CLKCTRL,
.enable_bit = OMAP4430_MODULEMODE_SWCTRL,
.clkdm_name = "l3_init_clkdm",
- .parent = &func_96m_fclk,
+ .parent = &func_48mc_fclk,
.recalc = &followparent_recalc,
};
-static struct clk usb_host_fck = {
- .name = "usb_host_fck",
+static struct clk usb_host_hs_utmi_p3_clk = {
+ .name = "usb_host_hs_utmi_p3_clk",
.ops = &clkops_omap2_dflt,
.enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_UTMI_P3_CLK_SHIFT,
.clkdm_name = "l3_init_clkdm",
.parent = &init_60m_fclk,
.recalc = &followparent_recalc,
};
-static struct clk usb_host_fs_fck = {
- .name = "usb_host_fs_fck",
+static struct clk usb_host_hs_hsic60m_p1_clk = {
+ .name = "usb_host_hs_hsic60m_p1_clk",
.ops = &clkops_omap2_dflt,
- .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_FS_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_SHIFT,
.clkdm_name = "l3_init_clkdm",
- .parent = &func_48mc_fclk,
+ .parent = &init_60m_fclk,
.recalc = &followparent_recalc,
};
-static struct clk usb_otg_ick = {
- .name = "usb_otg_ick",
+static struct clk usb_host_hs_hsic60m_p2_clk = {
+ .name = "usb_host_hs_hsic60m_p2_clk",
.ops = &clkops_omap2_dflt,
- .enable_reg = OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_HWCTRL,
+ .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_SHIFT,
.clkdm_name = "l3_init_clkdm",
- .parent = &l3_div_ck,
+ .parent = &init_60m_fclk,
.recalc = &followparent_recalc,
};
-static struct clk usb_tll_ick = {
- .name = "usb_tll_ick",
+static const struct clksel utmi_p1_gfclk_sel[] = {
+ { .parent = &init_60m_fclk, .rates = div_1_0_rates },
+ { .parent = &xclk60mhsp1_ck, .rates = div_1_1_rates },
+ { .parent = NULL },
+};
+
+static struct clk utmi_p1_gfclk = {
+ .name = "utmi_p1_gfclk",
+ .parent = &init_60m_fclk,
+ .clksel = utmi_p1_gfclk_sel,
+ .init = &omap2_init_clksel_parent,
+ .clksel_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_UTMI_P1_MASK,
+ .ops = &clkops_null,
+ .recalc = &omap2_clksel_recalc,
+};
+
+static struct clk usb_host_hs_utmi_p1_clk = {
+ .name = "usb_host_hs_utmi_p1_clk",
.ops = &clkops_omap2_dflt,
- .enable_reg = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_HWCTRL,
+ .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_UTMI_P1_CLK_SHIFT,
.clkdm_name = "l3_init_clkdm",
- .parent = &l4_div_ck,
+ .parent = &utmi_p1_gfclk,
.recalc = &followparent_recalc,
};
-static struct clk usbphyocp2scp_ick = {
- .name = "usbphyocp2scp_ick",
+static const struct clksel utmi_p2_gfclk_sel[] = {
+ { .parent = &init_60m_fclk, .rates = div_1_0_rates },
+ { .parent = &xclk60mhsp2_ck, .rates = div_1_1_rates },
+ { .parent = NULL },
+};
+
+static struct clk utmi_p2_gfclk = {
+ .name = "utmi_p2_gfclk",
+ .parent = &init_60m_fclk,
+ .clksel = utmi_p2_gfclk_sel,
+ .init = &omap2_init_clksel_parent,
+ .clksel_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_UTMI_P2_MASK,
+ .ops = &clkops_null,
+ .recalc = &omap2_clksel_recalc,
+};
+
+static struct clk usb_host_hs_utmi_p2_clk = {
+ .name = "usb_host_hs_utmi_p2_clk",
.ops = &clkops_omap2_dflt,
- .enable_reg = OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_HWCTRL,
+ .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_UTMI_P2_CLK_SHIFT,
.clkdm_name = "l3_init_clkdm",
- .parent = &l4_div_ck,
+ .parent = &utmi_p2_gfclk,
.recalc = &followparent_recalc,
};
-static struct clk usim_fck = {
- .name = "usim_fck",
+static struct clk usb_host_hs_hsic480m_p1_clk = {
+ .name = "usb_host_hs_hsic480m_p1_clk",
.ops = &clkops_omap2_dflt,
- .enable_reg = OMAP4430_CM_WKUP_USIM_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "l4_wkup_clkdm",
- .parent = &sys_32k_ck,
+ .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_SHIFT,
+ .clkdm_name = "l3_init_clkdm",
+ .parent = &dpll_usb_m2_ck,
.recalc = &followparent_recalc,
};
-static struct clk wdt2_fck = {
- .name = "wdt2_fck",
+static struct clk usb_host_hs_hsic480m_p2_clk = {
+ .name = "usb_host_hs_hsic480m_p2_clk",
.ops = &clkops_omap2_dflt,
- .enable_reg = OMAP4430_CM_WKUP_WDT2_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "l4_wkup_clkdm",
- .parent = &sys_32k_ck,
+ .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_SHIFT,
+ .clkdm_name = "l3_init_clkdm",
+ .parent = &dpll_usb_m2_ck,
.recalc = &followparent_recalc,
};
-static struct clk wdt3_fck = {
- .name = "wdt3_fck",
+static struct clk usb_host_hs_func48mclk = {
+ .name = "usb_host_hs_func48mclk",
.ops = &clkops_omap2_dflt,
- .enable_reg = OMAP4430_CM1_ABE_WDT3_CLKCTRL,
+ .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_FUNC48MCLK_SHIFT,
+ .clkdm_name = "l3_init_clkdm",
+ .parent = &func_48mc_fclk,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk usb_host_hs_fck = {
+ .name = "usb_host_hs_fck",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
.enable_bit = OMAP4430_MODULEMODE_SWCTRL,
- .clkdm_name = "abe_clkdm",
- .parent = &sys_32k_ck,
+ .clkdm_name = "l3_init_clkdm",
+ .parent = &init_60m_fclk,
.recalc = &followparent_recalc,
};
-/* Remaining optional clocks */
static const struct clksel otg_60m_gfclk_sel[] = {
{ .parent = &utmi_phy_clkout_ck, .rates = div_1_0_rates },
{ .parent = &xclk60motg_ck, .rates = div_1_1_rates },
{ .parent = NULL },
};
-static struct clk otg_60m_gfclk_ck = {
- .name = "otg_60m_gfclk_ck",
+static struct clk otg_60m_gfclk = {
+ .name = "otg_60m_gfclk",
.parent = &utmi_phy_clkout_ck,
.clksel = otg_60m_gfclk_sel,
.init = &omap2_init_clksel_parent,
@@ -2373,38 +2579,74 @@ static struct clk otg_60m_gfclk_ck = {
.recalc = &omap2_clksel_recalc,
};
-static const struct clksel stm_clk_div_div[] = {
- { .parent = &pmd_stm_clock_mux_ck, .rates = div3_1to4_rates },
- { .parent = NULL },
+static struct clk usb_otg_hs_xclk = {
+ .name = "usb_otg_hs_xclk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_XCLK_SHIFT,
+ .clkdm_name = "l3_init_clkdm",
+ .parent = &otg_60m_gfclk,
+ .recalc = &followparent_recalc,
};
-static struct clk stm_clk_div_ck = {
- .name = "stm_clk_div_ck",
- .parent = &pmd_stm_clock_mux_ck,
- .clksel = stm_clk_div_div,
- .clksel_reg = OMAP4430_CM_EMU_DEBUGSS_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_PMD_STM_CLK_MASK,
- .ops = &clkops_null,
- .recalc = &omap2_clksel_recalc,
- .round_rate = &omap2_clksel_round_rate,
- .set_rate = &omap2_clksel_set_rate,
+static struct clk usb_otg_hs_ick = {
+ .name = "usb_otg_hs_ick",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_HWCTRL,
+ .clkdm_name = "l3_init_clkdm",
+ .parent = &l3_div_ck,
+ .recalc = &followparent_recalc,
};
-static const struct clksel trace_clk_div_div[] = {
- { .parent = &pmd_trace_clk_mux_ck, .rates = div3_1to4_rates },
- { .parent = NULL },
+static struct clk usb_phy_cm_clk32k = {
+ .name = "usb_phy_cm_clk32k",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_ALWON_USBPHY_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_CLK32K_SHIFT,
+ .clkdm_name = "l4_ao_clkdm",
+ .parent = &sys_32k_ck,
+ .recalc = &followparent_recalc,
};
-static struct clk trace_clk_div_ck = {
- .name = "trace_clk_div_ck",
- .parent = &pmd_trace_clk_mux_ck,
- .clksel = trace_clk_div_div,
- .clksel_reg = OMAP4430_CM_EMU_DEBUGSS_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK,
- .ops = &clkops_null,
- .recalc = &omap2_clksel_recalc,
- .round_rate = &omap2_clksel_round_rate,
- .set_rate = &omap2_clksel_set_rate,
+static struct clk usb_tll_hs_usb_ch2_clk = {
+ .name = "usb_tll_hs_usb_ch2_clk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_USB_CH2_CLK_SHIFT,
+ .clkdm_name = "l3_init_clkdm",
+ .parent = &init_60m_fclk,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk usb_tll_hs_usb_ch0_clk = {
+ .name = "usb_tll_hs_usb_ch0_clk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_USB_CH0_CLK_SHIFT,
+ .clkdm_name = "l3_init_clkdm",
+ .parent = &init_60m_fclk,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk usb_tll_hs_usb_ch1_clk = {
+ .name = "usb_tll_hs_usb_ch1_clk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_USB_CH1_CLK_SHIFT,
+ .clkdm_name = "l3_init_clkdm",
+ .parent = &init_60m_fclk,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk usb_tll_hs_ick = {
+ .name = "usb_tll_hs_ick",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_HWCTRL,
+ .clkdm_name = "l3_init_clkdm",
+ .parent = &l4_div_ck,
+ .recalc = &followparent_recalc,
};
static const struct clksel_rate div2_14to18_rates[] = {
@@ -2418,8 +2660,8 @@ static const struct clksel usim_fclk_div[] = {
{ .parent = NULL },
};
-static struct clk usim_fclk = {
- .name = "usim_fclk",
+static struct clk usim_ck = {
+ .name = "usim_ck",
.parent = &dpll_per_m4_ck,
.clksel = usim_fclk_div,
.clksel_reg = OMAP4430_CM_WKUP_USIM_CLKCTRL,
@@ -2430,38 +2672,79 @@ static struct clk usim_fclk = {
.set_rate = &omap2_clksel_set_rate,
};
-static const struct clksel utmi_p1_gfclk_sel[] = {
- { .parent = &init_60m_fclk, .rates = div_1_0_rates },
- { .parent = &xclk60mhsp1_ck, .rates = div_1_1_rates },
+static struct clk usim_fclk = {
+ .name = "usim_fclk",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_WKUP_USIM_CLKCTRL,
+ .enable_bit = OMAP4430_OPTFCLKEN_FCLK_SHIFT,
+ .clkdm_name = "l4_wkup_clkdm",
+ .parent = &usim_ck,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk usim_fck = {
+ .name = "usim_fck",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_WKUP_USIM_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_HWCTRL,
+ .clkdm_name = "l4_wkup_clkdm",
+ .parent = &sys_32k_ck,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk wd_timer2_fck = {
+ .name = "wd_timer2_fck",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM_WKUP_WDT2_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "l4_wkup_clkdm",
+ .parent = &sys_32k_ck,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk wd_timer3_fck = {
+ .name = "wd_timer3_fck",
+ .ops = &clkops_omap2_dflt,
+ .enable_reg = OMAP4430_CM1_ABE_WDT3_CLKCTRL,
+ .enable_bit = OMAP4430_MODULEMODE_SWCTRL,
+ .clkdm_name = "abe_clkdm",
+ .parent = &sys_32k_ck,
+ .recalc = &followparent_recalc,
+};
+
+/* Remaining optional clocks */
+static const struct clksel stm_clk_div_div[] = {
+ { .parent = &pmd_stm_clock_mux_ck, .rates = div3_1to4_rates },
{ .parent = NULL },
};
-static struct clk utmi_p1_gfclk_ck = {
- .name = "utmi_p1_gfclk_ck",
- .parent = &init_60m_fclk,
- .clksel = utmi_p1_gfclk_sel,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_UTMI_P1_MASK,
+static struct clk stm_clk_div_ck = {
+ .name = "stm_clk_div_ck",
+ .parent = &pmd_stm_clock_mux_ck,
+ .clksel = stm_clk_div_div,
+ .clksel_reg = OMAP4430_CM_EMU_DEBUGSS_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_PMD_STM_CLK_MASK,
.ops = &clkops_null,
.recalc = &omap2_clksel_recalc,
+ .round_rate = &omap2_clksel_round_rate,
+ .set_rate = &omap2_clksel_set_rate,
};
-static const struct clksel utmi_p2_gfclk_sel[] = {
- { .parent = &init_60m_fclk, .rates = div_1_0_rates },
- { .parent = &xclk60mhsp2_ck, .rates = div_1_1_rates },
+static const struct clksel trace_clk_div_div[] = {
+ { .parent = &pmd_trace_clk_mux_ck, .rates = div3_1to4_rates },
{ .parent = NULL },
};
-static struct clk utmi_p2_gfclk_ck = {
- .name = "utmi_p2_gfclk_ck",
- .parent = &init_60m_fclk,
- .clksel = utmi_p2_gfclk_sel,
- .init = &omap2_init_clksel_parent,
- .clksel_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
- .clksel_mask = OMAP4430_CLKSEL_UTMI_P2_MASK,
+static struct clk trace_clk_div_ck = {
+ .name = "trace_clk_div_ck",
+ .parent = &pmd_trace_clk_mux_ck,
+ .clksel = trace_clk_div_div,
+ .clksel_reg = OMAP4430_CM_EMU_DEBUGSS_CLKCTRL,
+ .clksel_mask = OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK,
.ops = &clkops_null,
.recalc = &omap2_clksel_recalc,
+ .round_rate = &omap2_clksel_round_rate,
+ .set_rate = &omap2_clksel_set_rate,
};
/*
@@ -2483,11 +2766,12 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "virt_27000000_ck", &virt_27000000_ck, CK_443X),
CLK(NULL, "virt_38400000_ck", &virt_38400000_ck, CK_443X),
CLK(NULL, "sys_clkin_ck", &sys_clkin_ck, CK_443X),
+ CLK(NULL, "tie_low_clock_ck", &tie_low_clock_ck, CK_443X),
CLK(NULL, "utmi_phy_clkout_ck", &utmi_phy_clkout_ck, CK_443X),
CLK(NULL, "xclk60mhsp1_ck", &xclk60mhsp1_ck, CK_443X),
CLK(NULL, "xclk60mhsp2_ck", &xclk60mhsp2_ck, CK_443X),
CLK(NULL, "xclk60motg_ck", &xclk60motg_ck, CK_443X),
- CLK(NULL, "dpll_sys_ref_clk", &dpll_sys_ref_clk, CK_443X),
+ CLK(NULL, "abe_dpll_bypass_clk_mux_ck", &abe_dpll_bypass_clk_mux_ck, CK_443X),
CLK(NULL, "abe_dpll_refclk_mux_ck", &abe_dpll_refclk_mux_ck, CK_443X),
CLK(NULL, "dpll_abe_ck", &dpll_abe_ck, CK_443X),
CLK(NULL, "dpll_abe_m2x2_ck", &dpll_abe_m2x2_ck, CK_443X),
@@ -2557,46 +2841,48 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "aes1_fck", &aes1_fck, CK_443X),
CLK(NULL, "aes2_fck", &aes2_fck, CK_443X),
CLK(NULL, "aess_fck", &aess_fck, CK_443X),
- CLK(NULL, "cust_efuse_fck", &cust_efuse_fck, CK_443X),
+ CLK(NULL, "bandgap_fclk", &bandgap_fclk, CK_443X),
CLK(NULL, "des3des_fck", &des3des_fck, CK_443X),
CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck, CK_443X),
CLK(NULL, "dmic_fck", &dmic_fck, CK_443X),
+ CLK(NULL, "dsp_fck", &dsp_fck, CK_443X),
+ CLK(NULL, "dss_sys_clk", &dss_sys_clk, CK_443X),
+ CLK(NULL, "dss_tv_clk", &dss_tv_clk, CK_443X),
+ CLK(NULL, "dss_dss_clk", &dss_dss_clk, CK_443X),
+ CLK(NULL, "dss_48mhz_clk", &dss_48mhz_clk, CK_443X),
CLK(NULL, "dss_fck", &dss_fck, CK_443X),
- CLK(NULL, "ducati_ick", &ducati_ick, CK_443X),
- CLK(NULL, "emif1_ick", &emif1_ick, CK_443X),
- CLK(NULL, "emif2_ick", &emif2_ick, CK_443X),
+ CLK(NULL, "efuse_ctrl_cust_fck", &efuse_ctrl_cust_fck, CK_443X),
+ CLK(NULL, "emif1_fck", &emif1_fck, CK_443X),
+ CLK(NULL, "emif2_fck", &emif2_fck, CK_443X),
CLK(NULL, "fdif_fck", &fdif_fck, CK_443X),
- CLK(NULL, "per_sgx_fclk", &per_sgx_fclk, CK_443X),
- CLK(NULL, "gfx_fck", &gfx_fck, CK_443X),
+ CLK(NULL, "fpka_fck", &fpka_fck, CK_443X),
+ CLK(NULL, "gpio1_dbck", &gpio1_dbclk, CK_443X),
CLK(NULL, "gpio1_ick", &gpio1_ick, CK_443X),
+ CLK(NULL, "gpio2_dbck", &gpio2_dbclk, CK_443X),
CLK(NULL, "gpio2_ick", &gpio2_ick, CK_443X),
+ CLK(NULL, "gpio3_dbck", &gpio3_dbclk, CK_443X),
CLK(NULL, "gpio3_ick", &gpio3_ick, CK_443X),
+ CLK(NULL, "gpio4_dbck", &gpio4_dbclk, CK_443X),
CLK(NULL, "gpio4_ick", &gpio4_ick, CK_443X),
+ CLK(NULL, "gpio5_dbck", &gpio5_dbclk, CK_443X),
CLK(NULL, "gpio5_ick", &gpio5_ick, CK_443X),
+ CLK(NULL, "gpio6_dbck", &gpio6_dbclk, CK_443X),
CLK(NULL, "gpio6_ick", &gpio6_ick, CK_443X),
CLK(NULL, "gpmc_ick", &gpmc_ick, CK_443X),
- CLK(NULL, "gpt1_fck", &gpt1_fck, CK_443X),
- CLK(NULL, "gpt10_fck", &gpt10_fck, CK_443X),
- CLK(NULL, "gpt11_fck", &gpt11_fck, CK_443X),
- CLK(NULL, "gpt2_fck", &gpt2_fck, CK_443X),
- CLK(NULL, "gpt3_fck", &gpt3_fck, CK_443X),
- CLK(NULL, "gpt4_fck", &gpt4_fck, CK_443X),
- CLK(NULL, "gpt5_fck", &gpt5_fck, CK_443X),
- CLK(NULL, "gpt6_fck", &gpt6_fck, CK_443X),
- CLK(NULL, "gpt7_fck", &gpt7_fck, CK_443X),
- CLK(NULL, "gpt8_fck", &gpt8_fck, CK_443X),
- CLK(NULL, "gpt9_fck", &gpt9_fck, CK_443X),
+ CLK(NULL, "gpu_fck", &gpu_fck, CK_443X),
CLK("omap2_hdq.0", "fck", &hdq1w_fck, CK_443X),
- CLK(NULL, "hsi_ick", &hsi_ick, CK_443X),
+ CLK(NULL, "hsi_fck", &hsi_fck, CK_443X),
CLK("i2c_omap.1", "fck", &i2c1_fck, CK_443X),
CLK("i2c_omap.2", "fck", &i2c2_fck, CK_443X),
CLK("i2c_omap.3", "fck", &i2c3_fck, CK_443X),
CLK("i2c_omap.4", "fck", &i2c4_fck, CK_443X),
+ CLK(NULL, "ipu_fck", &ipu_fck, CK_443X),
+ CLK(NULL, "iss_ctrlclk", &iss_ctrlclk, CK_443X),
CLK(NULL, "iss_fck", &iss_fck, CK_443X),
- CLK(NULL, "ivahd_ick", &ivahd_ick, CK_443X),
- CLK(NULL, "keyboard_fck", &keyboard_fck, CK_443X),
- CLK(NULL, "l3_instr_interconnect_ick", &l3_instr_interconnect_ick, CK_443X),
- CLK(NULL, "l3_interconnect_3_ick", &l3_interconnect_3_ick, CK_443X),
+ CLK(NULL, "iva_fck", &iva_fck, CK_443X),
+ CLK(NULL, "kbd_fck", &kbd_fck, CK_443X),
+ CLK(NULL, "l3_instr_ick", &l3_instr_ick, CK_443X),
+ CLK(NULL, "l3_main_3_ick", &l3_main_3_ick, CK_443X),
CLK(NULL, "mcasp_sync_mux_ck", &mcasp_sync_mux_ck, CK_443X),
CLK(NULL, "mcasp_fck", &mcasp_fck, CK_443X),
CLK(NULL, "mcbsp1_sync_mux_ck", &mcbsp1_sync_mux_ck, CK_443X),
@@ -2607,6 +2893,7 @@ static struct omap_clk omap44xx_clks[] = {
CLK("omap-mcbsp.3", "fck", &mcbsp3_fck, CK_443X),
CLK(NULL, "mcbsp4_sync_mux_ck", &mcbsp4_sync_mux_ck, CK_443X),
CLK("omap-mcbsp.4", "fck", &mcbsp4_fck, CK_443X),
+ CLK(NULL, "mcpdm_fck", &mcpdm_fck, CK_443X),
CLK("omap2_mcspi.1", "fck", &mcspi1_fck, CK_443X),
CLK("omap2_mcspi.2", "fck", &mcspi2_fck, CK_443X),
CLK("omap2_mcspi.3", "fck", &mcspi3_fck, CK_443X),
@@ -2616,43 +2903,66 @@ static struct omap_clk omap44xx_clks[] = {
CLK("mmci-omap-hs.2", "fck", &mmc3_fck, CK_443X),
CLK("mmci-omap-hs.3", "fck", &mmc4_fck, CK_443X),
CLK("mmci-omap-hs.4", "fck", &mmc5_fck, CK_443X),
- CLK(NULL, "ocp_wp1_ick", &ocp_wp1_ick, CK_443X),
- CLK(NULL, "pdm_fck", &pdm_fck, CK_443X),
- CLK(NULL, "pkaeip29_fck", &pkaeip29_fck, CK_443X),
+ CLK(NULL, "ocp2scp_usb_phy_phy_48m", &ocp2scp_usb_phy_phy_48m, CK_443X),
+ CLK(NULL, "ocp2scp_usb_phy_ick", &ocp2scp_usb_phy_ick, CK_443X),
+ CLK(NULL, "ocp_wp_noc_ick", &ocp_wp_noc_ick, CK_443X),
CLK("omap_rng", "ick", &rng_ick, CK_443X),
- CLK(NULL, "sha2md51_fck", &sha2md51_fck, CK_443X),
- CLK(NULL, "sl2_ick", &sl2_ick, CK_443X),
+ CLK(NULL, "sha2md5_fck", &sha2md5_fck, CK_443X),
+ CLK(NULL, "sl2if_ick", &sl2if_ick, CK_443X),
+ CLK(NULL, "slimbus1_fclk_1", &slimbus1_fclk_1, CK_443X),
+ CLK(NULL, "slimbus1_fclk_0", &slimbus1_fclk_0, CK_443X),
+ CLK(NULL, "slimbus1_fclk_2", &slimbus1_fclk_2, CK_443X),
+ CLK(NULL, "slimbus1_slimbus_clk", &slimbus1_slimbus_clk, CK_443X),
CLK(NULL, "slimbus1_fck", &slimbus1_fck, CK_443X),
+ CLK(NULL, "slimbus2_fclk_1", &slimbus2_fclk_1, CK_443X),
+ CLK(NULL, "slimbus2_fclk_0", &slimbus2_fclk_0, CK_443X),
+ CLK(NULL, "slimbus2_slimbus_clk", &slimbus2_slimbus_clk, CK_443X),
CLK(NULL, "slimbus2_fck", &slimbus2_fck, CK_443X),
- CLK(NULL, "sr_core_fck", &sr_core_fck, CK_443X),
- CLK(NULL, "sr_iva_fck", &sr_iva_fck, CK_443X),
- CLK(NULL, "sr_mpu_fck", &sr_mpu_fck, CK_443X),
- CLK(NULL, "tesla_ick", &tesla_ick, CK_443X),
+ CLK(NULL, "smartreflex_core_fck", &smartreflex_core_fck, CK_443X),
+ CLK(NULL, "smartreflex_iva_fck", &smartreflex_iva_fck, CK_443X),
+ CLK(NULL, "smartreflex_mpu_fck", &smartreflex_mpu_fck, CK_443X),
+ CLK(NULL, "gpt1_fck", &timer1_fck, CK_443X),
+ CLK(NULL, "gpt10_fck", &timer10_fck, CK_443X),
+ CLK(NULL, "gpt11_fck", &timer11_fck, CK_443X),
+ CLK(NULL, "gpt2_fck", &timer2_fck, CK_443X),
+ CLK(NULL, "gpt3_fck", &timer3_fck, CK_443X),
+ CLK(NULL, "gpt4_fck", &timer4_fck, CK_443X),
+ CLK(NULL, "gpt5_fck", &timer5_fck, CK_443X),
+ CLK(NULL, "gpt6_fck", &timer6_fck, CK_443X),
+ CLK(NULL, "gpt7_fck", &timer7_fck, CK_443X),
+ CLK(NULL, "gpt8_fck", &timer8_fck, CK_443X),
+ CLK(NULL, "gpt9_fck", &timer9_fck, CK_443X),
CLK(NULL, "uart1_fck", &uart1_fck, CK_443X),
CLK(NULL, "uart2_fck", &uart2_fck, CK_443X),
CLK(NULL, "uart3_fck", &uart3_fck, CK_443X),
CLK(NULL, "uart4_fck", &uart4_fck, CK_443X),
- CLK(NULL, "unipro1_fck", &unipro1_fck, CK_443X),
- CLK(NULL, "usb_host_fck", &usb_host_fck, CK_443X),
CLK(NULL, "usb_host_fs_fck", &usb_host_fs_fck, CK_443X),
- CLK("musb_hdrc", "ick", &usb_otg_ick, CK_443X),
- CLK(NULL, "usb_tll_ick", &usb_tll_ick, CK_443X),
- CLK(NULL, "usbphyocp2scp_ick", &usbphyocp2scp_ick, CK_443X),
+ CLK(NULL, "usb_host_hs_utmi_p3_clk", &usb_host_hs_utmi_p3_clk, CK_443X),
+ CLK(NULL, "usb_host_hs_hsic60m_p1_clk", &usb_host_hs_hsic60m_p1_clk, CK_443X),
+ CLK(NULL, "usb_host_hs_hsic60m_p2_clk", &usb_host_hs_hsic60m_p2_clk, CK_443X),
+ CLK(NULL, "utmi_p1_gfclk", &utmi_p1_gfclk, CK_443X),
+ CLK(NULL, "usb_host_hs_utmi_p1_clk", &usb_host_hs_utmi_p1_clk, CK_443X),
+ CLK(NULL, "utmi_p2_gfclk", &utmi_p2_gfclk, CK_443X),
+ CLK(NULL, "usb_host_hs_utmi_p2_clk", &usb_host_hs_utmi_p2_clk, CK_443X),
+ CLK(NULL, "usb_host_hs_hsic480m_p1_clk", &usb_host_hs_hsic480m_p1_clk, CK_443X),
+ CLK(NULL, "usb_host_hs_hsic480m_p2_clk", &usb_host_hs_hsic480m_p2_clk, CK_443X),
+ CLK(NULL, "usb_host_hs_func48mclk", &usb_host_hs_func48mclk, CK_443X),
+ CLK(NULL, "usb_host_hs_fck", &usb_host_hs_fck, CK_443X),
+ CLK(NULL, "otg_60m_gfclk", &otg_60m_gfclk, CK_443X),
+ CLK(NULL, "usb_otg_hs_xclk", &usb_otg_hs_xclk, CK_443X),
+ CLK("musb_hdrc", "ick", &usb_otg_hs_ick, CK_443X),
+ CLK(NULL, "usb_phy_cm_clk32k", &usb_phy_cm_clk32k, CK_443X),
+ CLK(NULL, "usb_tll_hs_usb_ch2_clk", &usb_tll_hs_usb_ch2_clk, CK_443X),
+ CLK(NULL, "usb_tll_hs_usb_ch0_clk", &usb_tll_hs_usb_ch0_clk, CK_443X),
+ CLK(NULL, "usb_tll_hs_usb_ch1_clk", &usb_tll_hs_usb_ch1_clk, CK_443X),
+ CLK(NULL, "usb_tll_hs_ick", &usb_tll_hs_ick, CK_443X),
+ CLK(NULL, "usim_ck", &usim_ck, CK_443X),
+ CLK(NULL, "usim_fclk", &usim_fclk, CK_443X),
CLK(NULL, "usim_fck", &usim_fck, CK_443X),
- CLK("omap_wdt", "fck", &wdt2_fck, CK_443X),
- CLK(NULL, "wdt3_fck", &wdt3_fck, CK_443X),
- CLK(NULL, "otg_60m_gfclk_ck", &otg_60m_gfclk_ck, CK_443X),
+ CLK("omap_wdt", "fck", &wd_timer2_fck, CK_443X),
+ CLK(NULL, "wd_timer3_fck", &wd_timer3_fck, CK_443X),
CLK(NULL, "stm_clk_div_ck", &stm_clk_div_ck, CK_443X),
CLK(NULL, "trace_clk_div_ck", &trace_clk_div_ck, CK_443X),
- CLK(NULL, "usim_fclk", &usim_fclk, CK_443X),
- CLK(NULL, "utmi_p1_gfclk_ck", &utmi_p1_gfclk_ck, CK_443X),
- CLK(NULL, "utmi_p2_gfclk_ck", &utmi_p2_gfclk_ck, CK_443X),
- CLK(NULL, "gpio1_dbck", &dummy_ck, CK_443X),
- CLK(NULL, "gpio2_dbck", &dummy_ck, CK_443X),
- CLK(NULL, "gpio3_dbck", &dummy_ck, CK_443X),
- CLK(NULL, "gpio4_dbck", &dummy_ck, CK_443X),
- CLK(NULL, "gpio5_dbck", &dummy_ck, CK_443X),
- CLK(NULL, "gpio6_dbck", &dummy_ck, CK_443X),
CLK(NULL, "gpmc_ck", &dummy_ck, CK_443X),
CLK(NULL, "gpt1_ick", &dummy_ck, CK_443X),
CLK(NULL, "gpt2_ick", &dummy_ck, CK_443X),
@@ -2669,19 +2979,19 @@ static struct omap_clk omap44xx_clks[] = {
CLK("i2c_omap.2", "ick", &dummy_ck, CK_443X),
CLK("i2c_omap.3", "ick", &dummy_ck, CK_443X),
CLK("i2c_omap.4", "ick", &dummy_ck, CK_443X),
+ CLK("mmci-omap-hs.0", "ick", &dummy_ck, CK_443X),
+ CLK("mmci-omap-hs.1", "ick", &dummy_ck, CK_443X),
+ CLK("mmci-omap-hs.2", "ick", &dummy_ck, CK_443X),
+ CLK("mmci-omap-hs.3", "ick", &dummy_ck, CK_443X),
+ CLK("mmci-omap-hs.4", "ick", &dummy_ck, CK_443X),
CLK("omap-mcbsp.1", "ick", &dummy_ck, CK_443X),
CLK("omap-mcbsp.2", "ick", &dummy_ck, CK_443X),
CLK("omap-mcbsp.3", "ick", &dummy_ck, CK_443X),
CLK("omap-mcbsp.4", "ick", &dummy_ck, CK_443X),
- CLK("omap2_mcspi.1", "ick", &dummy_ck, CK_443X),
- CLK("omap2_mcspi.2", "ick", &dummy_ck, CK_443X),
- CLK("omap2_mcspi.3", "ick", &dummy_ck, CK_443X),
- CLK("omap2_mcspi.4", "ick", &dummy_ck, CK_443X),
- CLK("mmci-omap-hs.0", "ick", &dummy_ck, CK_443X),
- CLK("mmci-omap-hs.1", "ick", &dummy_ck, CK_443X),
- CLK("mmci-omap-hs.2", "ick", &dummy_ck, CK_443X),
- CLK("mmci-omap-hs.3", "ick", &dummy_ck, CK_443X),
- CLK("mmci-omap-hs.4", "ick", &dummy_ck, CK_443X),
+ CLK("omap2_mcspi.1", "ick", &dummy_ck, CK_443X),
+ CLK("omap2_mcspi.2", "ick", &dummy_ck, CK_443X),
+ CLK("omap2_mcspi.3", "ick", &dummy_ck, CK_443X),
+ CLK("omap2_mcspi.4", "ick", &dummy_ck, CK_443X),
CLK(NULL, "uart1_ick", &dummy_ck, CK_443X),
CLK(NULL, "uart2_ick", &dummy_ck, CK_443X),
CLK(NULL, "uart3_ick", &dummy_ck, CK_443X),
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index 5d80cb897489..6fb61b1a0d46 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -258,97 +258,6 @@ static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable)
}
-/**
- * _init_wkdep_usecount - initialize wkdep usecounts to match hardware
- * @clkdm: clockdomain to initialize wkdep usecounts
- *
- * Initialize the wakeup dependency usecount variables for clockdomain @clkdm.
- * If a wakeup dependency is present in the hardware, the usecount will be
- * set to 1; otherwise, it will be set to 0. Software should clear all
- * software wakeup dependencies prior to calling this function if it wishes
- * to ensure that all usecounts start at 0. No return value.
- */
-static void _init_wkdep_usecount(struct clockdomain *clkdm)
-{
- u32 v;
- struct clkdm_dep *cd;
-
- if (!clkdm->wkdep_srcs)
- return;
-
- for (cd = clkdm->wkdep_srcs; cd->clkdm_name; cd++) {
- if (!omap_chip_is(cd->omap_chip))
- continue;
-
- if (!cd->clkdm && cd->clkdm_name)
- cd->clkdm = _clkdm_lookup(cd->clkdm_name);
-
- if (!cd->clkdm) {
- WARN(!cd->clkdm, "clockdomain: %s: wkdep clkdm %s not "
- "found\n", clkdm->name, cd->clkdm_name);
- continue;
- }
-
- v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs,
- PM_WKDEP,
- (1 << cd->clkdm->dep_bit));
-
- if (v)
- pr_debug("clockdomain: %s: wakeup dependency already "
- "set to wake up when %s wakes\n",
- clkdm->name, cd->clkdm->name);
-
- atomic_set(&cd->wkdep_usecount, (v) ? 1 : 0);
- }
-}
-
-/**
- * _init_sleepdep_usecount - initialize sleepdep usecounts to match hardware
- * @clkdm: clockdomain to initialize sleepdep usecounts
- *
- * Initialize the sleep dependency usecount variables for clockdomain @clkdm.
- * If a sleep dependency is present in the hardware, the usecount will be
- * set to 1; otherwise, it will be set to 0. Software should clear all
- * software sleep dependencies prior to calling this function if it wishes
- * to ensure that all usecounts start at 0. No return value.
- */
-static void _init_sleepdep_usecount(struct clockdomain *clkdm)
-{
- u32 v;
- struct clkdm_dep *cd;
-
- if (!cpu_is_omap34xx())
- return;
-
- if (!clkdm->sleepdep_srcs)
- return;
-
- for (cd = clkdm->sleepdep_srcs; cd->clkdm_name; cd++) {
- if (!omap_chip_is(cd->omap_chip))
- continue;
-
- if (!cd->clkdm && cd->clkdm_name)
- cd->clkdm = _clkdm_lookup(cd->clkdm_name);
-
- if (!cd->clkdm) {
- WARN(!cd->clkdm, "clockdomain: %s: sleepdep clkdm %s "
- "not found\n", clkdm->name, cd->clkdm_name);
- continue;
- }
-
- v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs,
- OMAP3430_CM_SLEEPDEP,
- (1 << cd->clkdm->dep_bit));
-
- if (v)
- pr_debug("clockdomain: %s: sleep dependency already "
- "set to prevent from idling until %s "
- "idles\n", clkdm->name, cd->clkdm->name);
-
- atomic_set(&cd->sleepdep_usecount, (v) ? 1 : 0);
- }
-};
-
/* Public functions */
/**
@@ -379,12 +288,17 @@ void clkdm_init(struct clockdomain **clkdms,
_autodep_lookup(autodep);
/*
- * Ensure that the *dep_usecount registers reflect the current
- * state of the PRCM.
+ * Put all clockdomains into software-supervised mode; PM code
+ * should later enable hardware-supervised mode as appropriate
*/
list_for_each_entry(clkdm, &clkdm_list, node) {
- _init_wkdep_usecount(clkdm);
- _init_sleepdep_usecount(clkdm);
+ if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
+ omap2_clkdm_wakeup(clkdm);
+ else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO)
+ omap2_clkdm_deny_idle(clkdm);
+
+ clkdm_clear_all_wkdeps(clkdm);
+ clkdm_clear_all_sleepdeps(clkdm);
}
}
@@ -592,6 +506,9 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
if (!omap_chip_is(cd->omap_chip))
continue;
+ if (!cd->clkdm && cd->clkdm_name)
+ cd->clkdm = _clkdm_lookup(cd->clkdm_name);
+
/* PRM accesses are slow, so minimize them */
mask |= 1 << cd->clkdm->dep_bit;
atomic_set(&cd->wkdep_usecount, 0);
@@ -752,6 +669,9 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
if (!omap_chip_is(cd->omap_chip))
continue;
+ if (!cd->clkdm && cd->clkdm_name)
+ cd->clkdm = _clkdm_lookup(cd->clkdm_name);
+
/* PRM accesses are slow, so minimize them */
mask |= 1 << cd->clkdm->dep_bit;
atomic_set(&cd->sleepdep_usecount, 0);
diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h
index fe82b79d5f3b..4f959a7d881c 100644
--- a/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -649,6 +649,8 @@
#define OMAP3430_ST_MCBSP2_MASK (1 << 0)
/* CM_AUTOIDLE_PER */
+#define OMAP3630_AUTO_UART4_MASK (1 << 18)
+#define OMAP3630_AUTO_UART4_SHIFT 18
#define OMAP3430_AUTO_GPIO6_MASK (1 << 17)
#define OMAP3430_AUTO_GPIO6_SHIFT 17
#define OMAP3430_AUTO_GPIO5_MASK (1 << 16)
diff --git a/arch/arm/mach-omap2/cm-regbits-44xx.h b/arch/arm/mach-omap2/cm-regbits-44xx.h
index ac8458e43252..0b72be433776 100644
--- a/arch/arm/mach-omap2/cm-regbits-44xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-44xx.h
@@ -1,8 +1,8 @@
/*
* OMAP44xx Clock Management register bits
*
- * Copyright (C) 2009 Texas Instruments, Inc.
- * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ * Copyright (C) 2009-2010 Nokia Corporation
*
* Paul Walmsley (paul@pwsan.com)
* Rajendra Nayak (rnayak@ti.com)
@@ -25,453 +25,459 @@
#include "cm.h"
-/* Used by CM_L3_1_DYNAMICDEP, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP */
+/*
+ * Used by CM_L3_1_DYNAMICDEP, CM_L3_1_DYNAMICDEP_RESTORE, CM_MPU_DYNAMICDEP,
+ * CM_TESLA_DYNAMICDEP
+ */
#define OMAP4430_ABE_DYNDEP_SHIFT 3
-#define OMAP4430_ABE_DYNDEP_MASK BITFIELD(3, 3)
+#define OMAP4430_ABE_DYNDEP_MASK (1 << 3)
/*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_L3INIT_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP,
- * CM_TESLA_STATICDEP
+ * Used by CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE, CM_DUCATI_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_MPU_STATICDEP, CM_SDMA_STATICDEP,
+ * CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
*/
#define OMAP4430_ABE_STATDEP_SHIFT 3
-#define OMAP4430_ABE_STATDEP_MASK BITFIELD(3, 3)
+#define OMAP4430_ABE_STATDEP_MASK (1 << 3)
-/* Used by CM_L4CFG_DYNAMICDEP */
+/* Used by CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE */
#define OMAP4430_ALWONCORE_DYNDEP_SHIFT 16
-#define OMAP4430_ALWONCORE_DYNDEP_MASK BITFIELD(16, 16)
+#define OMAP4430_ALWONCORE_DYNDEP_MASK (1 << 16)
/* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP, CM_TESLA_STATICDEP */
#define OMAP4430_ALWONCORE_STATDEP_SHIFT 16
-#define OMAP4430_ALWONCORE_STATDEP_MASK BITFIELD(16, 16)
+#define OMAP4430_ALWONCORE_STATDEP_MASK (1 << 16)
/*
- * Used by CM_AUTOIDLE_DPLL_PER, CM_AUTOIDLE_DPLL_UNIPRO, CM_AUTOIDLE_DPLL_USB,
- * CM_AUTOIDLE_DPLL_CORE_RESTORE, CM_AUTOIDLE_DPLL_ABE, CM_AUTOIDLE_DPLL_CORE,
- * CM_AUTOIDLE_DPLL_DDRPHY, CM_AUTOIDLE_DPLL_IVA, CM_AUTOIDLE_DPLL_MPU
+ * Used by CM_AUTOIDLE_DPLL_ABE, CM_AUTOIDLE_DPLL_CORE,
+ * CM_AUTOIDLE_DPLL_CORE_RESTORE, CM_AUTOIDLE_DPLL_DDRPHY,
+ * CM_AUTOIDLE_DPLL_IVA, CM_AUTOIDLE_DPLL_MPU, CM_AUTOIDLE_DPLL_PER,
+ * CM_AUTOIDLE_DPLL_UNIPRO, CM_AUTOIDLE_DPLL_USB
*/
#define OMAP4430_AUTO_DPLL_MODE_SHIFT 0
-#define OMAP4430_AUTO_DPLL_MODE_MASK BITFIELD(0, 2)
+#define OMAP4430_AUTO_DPLL_MODE_MASK (0x7 << 0)
-/* Used by CM_L4CFG_DYNAMICDEP */
+/* Used by CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE */
#define OMAP4430_CEFUSE_DYNDEP_SHIFT 17
-#define OMAP4430_CEFUSE_DYNDEP_MASK BITFIELD(17, 17)
+#define OMAP4430_CEFUSE_DYNDEP_MASK (1 << 17)
/* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP, CM_TESLA_STATICDEP */
#define OMAP4430_CEFUSE_STATDEP_SHIFT 17
-#define OMAP4430_CEFUSE_STATDEP_MASK BITFIELD(17, 17)
+#define OMAP4430_CEFUSE_STATDEP_MASK (1 << 17)
/* Used by CM1_ABE_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_ABE_24M_GFCLK_SHIFT 13
-#define OMAP4430_CLKACTIVITY_ABE_24M_GFCLK_MASK BITFIELD(13, 13)
+#define OMAP4430_CLKACTIVITY_ABE_24M_GFCLK_MASK (1 << 13)
/* Used by CM1_ABE_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_ABE_ALWON_32K_CLK_SHIFT 12
-#define OMAP4430_CLKACTIVITY_ABE_ALWON_32K_CLK_MASK BITFIELD(12, 12)
+#define OMAP4430_CLKACTIVITY_ABE_ALWON_32K_CLK_MASK (1 << 12)
/* Used by CM_WKUP_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_ABE_LP_CLK_SHIFT 9
-#define OMAP4430_CLKACTIVITY_ABE_LP_CLK_MASK BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_ABE_LP_CLK_MASK (1 << 9)
/* Used by CM1_ABE_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_ABE_SYSCLK_SHIFT 11
-#define OMAP4430_CLKACTIVITY_ABE_SYSCLK_MASK BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_ABE_SYSCLK_MASK (1 << 11)
/* Used by CM1_ABE_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_ABE_X2_CLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_ABE_X2_CLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_ABE_X2_CLK_MASK (1 << 8)
/* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_ASYNC_DLL_CLK_SHIFT 11
-#define OMAP4430_CLKACTIVITY_ASYNC_DLL_CLK_MASK BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_ASYNC_DLL_CLK_MASK (1 << 11)
/* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_ASYNC_PHY1_CLK_SHIFT 12
-#define OMAP4430_CLKACTIVITY_ASYNC_PHY1_CLK_MASK BITFIELD(12, 12)
+#define OMAP4430_CLKACTIVITY_ASYNC_PHY1_CLK_MASK (1 << 12)
/* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_ASYNC_PHY2_CLK_SHIFT 13
-#define OMAP4430_CLKACTIVITY_ASYNC_PHY2_CLK_MASK BITFIELD(13, 13)
+#define OMAP4430_CLKACTIVITY_ASYNC_PHY2_CLK_MASK (1 << 13)
/* Used by CM_CAM_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_CAM_PHY_CTRL_GCLK_SHIFT 9
-#define OMAP4430_CLKACTIVITY_CAM_PHY_CTRL_GCLK_MASK BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_CAM_PHY_CTRL_GCLK_MASK (1 << 9)
+
+/* Used by CM_ALWON_CLKSTCTRL */
+#define OMAP4430_CLKACTIVITY_CORE_ALWON_32K_GFCLK_SHIFT 12
+#define OMAP4430_CLKACTIVITY_CORE_ALWON_32K_GFCLK_MASK (1 << 12)
/* Used by CM_EMU_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_SHIFT 9
-#define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_MASK BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_MASK (1 << 9)
/* Used by CM_CEFUSE_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_SHIFT 9
-#define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_MASK BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_MASK (1 << 9)
/* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_DLL_CLK_SHIFT 9
-#define OMAP4430_CLKACTIVITY_DLL_CLK_MASK BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_DLL_CLK_MASK (1 << 9)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_DMT10_GFCLK_SHIFT 9
-#define OMAP4430_CLKACTIVITY_DMT10_GFCLK_MASK BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_DMT10_GFCLK_MASK (1 << 9)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_DMT11_GFCLK_SHIFT 10
-#define OMAP4430_CLKACTIVITY_DMT11_GFCLK_MASK BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_DMT11_GFCLK_MASK (1 << 10)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_DMT2_GFCLK_SHIFT 11
-#define OMAP4430_CLKACTIVITY_DMT2_GFCLK_MASK BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_DMT2_GFCLK_MASK (1 << 11)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_DMT3_GFCLK_SHIFT 12
-#define OMAP4430_CLKACTIVITY_DMT3_GFCLK_MASK BITFIELD(12, 12)
+#define OMAP4430_CLKACTIVITY_DMT3_GFCLK_MASK (1 << 12)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_DMT4_GFCLK_SHIFT 13
-#define OMAP4430_CLKACTIVITY_DMT4_GFCLK_MASK BITFIELD(13, 13)
+#define OMAP4430_CLKACTIVITY_DMT4_GFCLK_MASK (1 << 13)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_DMT9_GFCLK_SHIFT 14
-#define OMAP4430_CLKACTIVITY_DMT9_GFCLK_MASK BITFIELD(14, 14)
+#define OMAP4430_CLKACTIVITY_DMT9_GFCLK_MASK (1 << 14)
/* Used by CM_DSS_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_DSS_ALWON_SYS_CLK_SHIFT 10
-#define OMAP4430_CLKACTIVITY_DSS_ALWON_SYS_CLK_MASK BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_DSS_ALWON_SYS_CLK_MASK (1 << 10)
/* Used by CM_DSS_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_DSS_FCLK_SHIFT 9
-#define OMAP4430_CLKACTIVITY_DSS_FCLK_MASK BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_DSS_FCLK_MASK (1 << 9)
/* Used by CM_DUCATI_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_DUCATI_GCLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_DUCATI_GCLK_MASK BITFIELD(8, 8)
-
-/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
-#define OMAP4430_CLKACTIVITY_EMAC_50MHZ_CLK_SHIFT 10
-#define OMAP4430_CLKACTIVITY_EMAC_50MHZ_CLK_MASK BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_DUCATI_GCLK_MASK (1 << 8)
/* Used by CM_EMU_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_EMU_SYS_CLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_EMU_SYS_CLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_EMU_SYS_CLK_MASK (1 << 8)
/* Used by CM_CAM_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_FDIF_GFCLK_SHIFT 10
-#define OMAP4430_CLKACTIVITY_FDIF_GFCLK_MASK BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_FDIF_GFCLK_MASK (1 << 10)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_FUNC_12M_GFCLK_SHIFT 15
-#define OMAP4430_CLKACTIVITY_FUNC_12M_GFCLK_MASK BITFIELD(15, 15)
+#define OMAP4430_CLKACTIVITY_FUNC_12M_GFCLK_MASK (1 << 15)
/* Used by CM1_ABE_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_FUNC_24M_GFCLK_SHIFT 10
-#define OMAP4430_CLKACTIVITY_FUNC_24M_GFCLK_MASK BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_FUNC_24M_GFCLK_MASK (1 << 10)
/* Used by CM_DSS_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_HDMI_PHY_48MHZ_GFCLK_SHIFT 11
-#define OMAP4430_CLKACTIVITY_HDMI_PHY_48MHZ_GFCLK_MASK BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_HDMI_PHY_48MHZ_GFCLK_MASK (1 << 11)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_HSIC_P1_480M_GFCLK_SHIFT 20
-#define OMAP4430_CLKACTIVITY_HSIC_P1_480M_GFCLK_MASK BITFIELD(20, 20)
+#define OMAP4430_CLKACTIVITY_HSIC_P1_480M_GFCLK_MASK (1 << 20)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_HSIC_P1_GFCLK_SHIFT 26
-#define OMAP4430_CLKACTIVITY_HSIC_P1_GFCLK_MASK BITFIELD(26, 26)
+#define OMAP4430_CLKACTIVITY_HSIC_P1_GFCLK_MASK (1 << 26)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_HSIC_P2_480M_GFCLK_SHIFT 21
-#define OMAP4430_CLKACTIVITY_HSIC_P2_480M_GFCLK_MASK BITFIELD(21, 21)
+#define OMAP4430_CLKACTIVITY_HSIC_P2_480M_GFCLK_MASK (1 << 21)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_HSIC_P2_GFCLK_SHIFT 27
-#define OMAP4430_CLKACTIVITY_HSIC_P2_GFCLK_MASK BITFIELD(27, 27)
-
-/* Used by CM_L3INIT_CLKSTCTRL */
-#define OMAP4430_CLKACTIVITY_INIT_32K_GFCLK_SHIFT 31
-#define OMAP4430_CLKACTIVITY_INIT_32K_GFCLK_MASK BITFIELD(31, 31)
+#define OMAP4430_CLKACTIVITY_HSIC_P2_GFCLK_MASK (1 << 27)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_INIT_48MC_GFCLK_SHIFT 13
-#define OMAP4430_CLKACTIVITY_INIT_48MC_GFCLK_MASK BITFIELD(13, 13)
+#define OMAP4430_CLKACTIVITY_INIT_48MC_GFCLK_MASK (1 << 13)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_INIT_48M_GFCLK_SHIFT 12
-#define OMAP4430_CLKACTIVITY_INIT_48M_GFCLK_MASK BITFIELD(12, 12)
+#define OMAP4430_CLKACTIVITY_INIT_48M_GFCLK_MASK (1 << 12)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_INIT_60M_P1_GFCLK_SHIFT 28
-#define OMAP4430_CLKACTIVITY_INIT_60M_P1_GFCLK_MASK BITFIELD(28, 28)
+#define OMAP4430_CLKACTIVITY_INIT_60M_P1_GFCLK_MASK (1 << 28)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_INIT_60M_P2_GFCLK_SHIFT 29
-#define OMAP4430_CLKACTIVITY_INIT_60M_P2_GFCLK_MASK BITFIELD(29, 29)
+#define OMAP4430_CLKACTIVITY_INIT_60M_P2_GFCLK_MASK (1 << 29)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_INIT_96M_GFCLK_SHIFT 11
-#define OMAP4430_CLKACTIVITY_INIT_96M_GFCLK_MASK BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_INIT_96M_GFCLK_MASK (1 << 11)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_INIT_HSI_GFCLK_SHIFT 16
-#define OMAP4430_CLKACTIVITY_INIT_HSI_GFCLK_MASK BITFIELD(16, 16)
+#define OMAP4430_CLKACTIVITY_INIT_HSI_GFCLK_MASK (1 << 16)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_INIT_HSMMC1_GFCLK_SHIFT 17
-#define OMAP4430_CLKACTIVITY_INIT_HSMMC1_GFCLK_MASK BITFIELD(17, 17)
+#define OMAP4430_CLKACTIVITY_INIT_HSMMC1_GFCLK_MASK (1 << 17)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_INIT_HSMMC2_GFCLK_SHIFT 18
-#define OMAP4430_CLKACTIVITY_INIT_HSMMC2_GFCLK_MASK BITFIELD(18, 18)
+#define OMAP4430_CLKACTIVITY_INIT_HSMMC2_GFCLK_MASK (1 << 18)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_INIT_HSMMC6_GFCLK_SHIFT 19
-#define OMAP4430_CLKACTIVITY_INIT_HSMMC6_GFCLK_MASK BITFIELD(19, 19)
+#define OMAP4430_CLKACTIVITY_INIT_HSMMC6_GFCLK_MASK (1 << 19)
/* Used by CM_CAM_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_ISS_GCLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_ISS_GCLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_ISS_GCLK_MASK (1 << 8)
/* Used by CM_IVAHD_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_IVAHD_ROOT_CLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_IVAHD_ROOT_CLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_IVAHD_ROOT_CLK_MASK (1 << 8)
-/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
-#define OMAP4430_CLKACTIVITY_L3INIT_DPLL_ALWON_CLK_SHIFT 14
-#define OMAP4430_CLKACTIVITY_L3INIT_DPLL_ALWON_CLK_MASK BITFIELD(14, 14)
+/* Used by CM_D2D_CLKSTCTRL */
+#define OMAP4430_CLKACTIVITY_L3X2_D2D_GICLK_SHIFT 10
+#define OMAP4430_CLKACTIVITY_L3X2_D2D_GICLK_MASK (1 << 10)
/* Used by CM_L3_1_CLKSTCTRL, CM_L3_1_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_L3_1_GICLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_L3_1_GICLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_1_GICLK_MASK (1 << 8)
/* Used by CM_L3_2_CLKSTCTRL, CM_L3_2_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_L3_2_GICLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_L3_2_GICLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_2_GICLK_MASK (1 << 8)
/* Used by CM_D2D_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_L3_D2D_GICLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_L3_D2D_GICLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_D2D_GICLK_MASK (1 << 8)
/* Used by CM_SDMA_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_L3_DMA_GICLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_L3_DMA_GICLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_DMA_GICLK_MASK (1 << 8)
/* Used by CM_DSS_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_L3_DSS_GICLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_L3_DSS_GICLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_DSS_GICLK_MASK (1 << 8)
/* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_L3_EMIF_GICLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_L3_EMIF_GICLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_EMIF_GICLK_MASK (1 << 8)
/* Used by CM_GFX_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_L3_GFX_GICLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_L3_GFX_GICLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_GFX_GICLK_MASK (1 << 8)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_L3_INIT_GICLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_L3_INIT_GICLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_INIT_GICLK_MASK (1 << 8)
/* Used by CM_L3INSTR_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_L3_INSTR_GICLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_L3_INSTR_GICLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_INSTR_GICLK_MASK (1 << 8)
/* Used by CM_L4SEC_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_L3_SECURE_GICLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_L3_SECURE_GICLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_SECURE_GICLK_MASK (1 << 8)
/* Used by CM_ALWON_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_L4_AO_ICLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_L4_AO_ICLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L4_AO_ICLK_MASK (1 << 8)
/* Used by CM_CEFUSE_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_L4_CEFUSE_GICLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_L4_CEFUSE_GICLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L4_CEFUSE_GICLK_MASK (1 << 8)
/* Used by CM_L4CFG_CLKSTCTRL, CM_L4CFG_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_L4_CFG_GICLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_L4_CFG_GICLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L4_CFG_GICLK_MASK (1 << 8)
/* Used by CM_D2D_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_L4_D2D_GICLK_SHIFT 9
-#define OMAP4430_CLKACTIVITY_L4_D2D_GICLK_MASK BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_L4_D2D_GICLK_MASK (1 << 9)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_L4_INIT_GICLK_SHIFT 9
-#define OMAP4430_CLKACTIVITY_L4_INIT_GICLK_MASK BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_L4_INIT_GICLK_MASK (1 << 9)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_L4_PER_GICLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_L4_PER_GICLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L4_PER_GICLK_MASK (1 << 8)
/* Used by CM_L4SEC_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_L4_SECURE_GICLK_SHIFT 9
-#define OMAP4430_CLKACTIVITY_L4_SECURE_GICLK_MASK BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_L4_SECURE_GICLK_MASK (1 << 9)
/* Used by CM_WKUP_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_L4_WKUP_GICLK_SHIFT 12
-#define OMAP4430_CLKACTIVITY_L4_WKUP_GICLK_MASK BITFIELD(12, 12)
+#define OMAP4430_CLKACTIVITY_L4_WKUP_GICLK_MASK (1 << 12)
/* Used by CM_MPU_CLKSTCTRL, CM_MPU_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_MPU_DPLL_CLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_MPU_DPLL_CLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_MPU_DPLL_CLK_MASK (1 << 8)
/* Used by CM1_ABE_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_OCP_ABE_GICLK_SHIFT 9
-#define OMAP4430_CLKACTIVITY_OCP_ABE_GICLK_MASK BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_OCP_ABE_GICLK_MASK (1 << 9)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_PER_24MC_GFCLK_SHIFT 16
-#define OMAP4430_CLKACTIVITY_PER_24MC_GFCLK_MASK BITFIELD(16, 16)
+#define OMAP4430_CLKACTIVITY_PER_24MC_GFCLK_MASK (1 << 16)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_PER_32K_GFCLK_SHIFT 17
-#define OMAP4430_CLKACTIVITY_PER_32K_GFCLK_MASK BITFIELD(17, 17)
+#define OMAP4430_CLKACTIVITY_PER_32K_GFCLK_MASK (1 << 17)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_PER_48M_GFCLK_SHIFT 18
-#define OMAP4430_CLKACTIVITY_PER_48M_GFCLK_MASK BITFIELD(18, 18)
+#define OMAP4430_CLKACTIVITY_PER_48M_GFCLK_MASK (1 << 18)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_PER_96M_GFCLK_SHIFT 19
-#define OMAP4430_CLKACTIVITY_PER_96M_GFCLK_MASK BITFIELD(19, 19)
+#define OMAP4430_CLKACTIVITY_PER_96M_GFCLK_MASK (1 << 19)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_PER_ABE_24M_GFCLK_SHIFT 25
-#define OMAP4430_CLKACTIVITY_PER_ABE_24M_GFCLK_MASK BITFIELD(25, 25)
-
-/* Used by CM_EMU_CLKSTCTRL */
-#define OMAP4430_CLKACTIVITY_PER_DPLL_EMU_CLK_SHIFT 10
-#define OMAP4430_CLKACTIVITY_PER_DPLL_EMU_CLK_MASK BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_PER_ABE_24M_GFCLK_MASK (1 << 25)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_PER_MCASP2_GFCLK_SHIFT 20
-#define OMAP4430_CLKACTIVITY_PER_MCASP2_GFCLK_MASK BITFIELD(20, 20)
+#define OMAP4430_CLKACTIVITY_PER_MCASP2_GFCLK_MASK (1 << 20)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_PER_MCASP3_GFCLK_SHIFT 21
-#define OMAP4430_CLKACTIVITY_PER_MCASP3_GFCLK_MASK BITFIELD(21, 21)
+#define OMAP4430_CLKACTIVITY_PER_MCASP3_GFCLK_MASK (1 << 21)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_PER_MCBSP4_GFCLK_SHIFT 22
-#define OMAP4430_CLKACTIVITY_PER_MCBSP4_GFCLK_MASK BITFIELD(22, 22)
+#define OMAP4430_CLKACTIVITY_PER_MCBSP4_GFCLK_MASK (1 << 22)
/* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_PER_SYS_GFCLK_SHIFT 24
-#define OMAP4430_CLKACTIVITY_PER_SYS_GFCLK_MASK BITFIELD(24, 24)
+#define OMAP4430_CLKACTIVITY_PER_SYS_GFCLK_MASK (1 << 24)
/* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_PHY_ROOT_CLK_SHIFT 10
-#define OMAP4430_CLKACTIVITY_PHY_ROOT_CLK_MASK BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_PHY_ROOT_CLK_MASK (1 << 10)
/* Used by CM_GFX_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_SGX_GFCLK_SHIFT 9
-#define OMAP4430_CLKACTIVITY_SGX_GFCLK_MASK BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_SGX_GFCLK_MASK (1 << 9)
/* Used by CM_ALWON_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_SR_CORE_SYSCLK_SHIFT 11
-#define OMAP4430_CLKACTIVITY_SR_CORE_SYSCLK_MASK BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_SR_CORE_SYSCLK_MASK (1 << 11)
/* Used by CM_ALWON_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_SR_IVA_SYSCLK_SHIFT 10
-#define OMAP4430_CLKACTIVITY_SR_IVA_SYSCLK_MASK BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_SR_IVA_SYSCLK_MASK (1 << 10)
/* Used by CM_ALWON_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_SR_MPU_SYSCLK_SHIFT 9
-#define OMAP4430_CLKACTIVITY_SR_MPU_SYSCLK_MASK BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_SR_MPU_SYSCLK_MASK (1 << 9)
/* Used by CM_WKUP_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_SYS_CLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_SYS_CLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_SYS_CLK_MASK (1 << 8)
/* Used by CM_TESLA_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_TESLA_ROOT_CLK_SHIFT 8
-#define OMAP4430_CLKACTIVITY_TESLA_ROOT_CLK_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_TESLA_ROOT_CLK_MASK (1 << 8)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_TLL_CH0_GFCLK_SHIFT 22
-#define OMAP4430_CLKACTIVITY_TLL_CH0_GFCLK_MASK BITFIELD(22, 22)
+#define OMAP4430_CLKACTIVITY_TLL_CH0_GFCLK_MASK (1 << 22)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_TLL_CH1_GFCLK_SHIFT 23
-#define OMAP4430_CLKACTIVITY_TLL_CH1_GFCLK_MASK BITFIELD(23, 23)
+#define OMAP4430_CLKACTIVITY_TLL_CH1_GFCLK_MASK (1 << 23)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_TLL_CH2_GFCLK_SHIFT 24
-#define OMAP4430_CLKACTIVITY_TLL_CH2_GFCLK_MASK BITFIELD(24, 24)
+#define OMAP4430_CLKACTIVITY_TLL_CH2_GFCLK_MASK (1 << 24)
+
+/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
+#define OMAP4430_CLKACTIVITY_UNIPRO_DPLL_CLK_SHIFT 10
+#define OMAP4430_CLKACTIVITY_UNIPRO_DPLL_CLK_MASK (1 << 10)
+
+/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
+#define OMAP4430_CLKACTIVITY_USB_DPLL_CLK_SHIFT 14
+#define OMAP4430_CLKACTIVITY_USB_DPLL_CLK_MASK (1 << 14)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_USB_DPLL_HS_CLK_SHIFT 15
-#define OMAP4430_CLKACTIVITY_USB_DPLL_HS_CLK_MASK BITFIELD(15, 15)
+#define OMAP4430_CLKACTIVITY_USB_DPLL_HS_CLK_MASK (1 << 15)
/* Used by CM_WKUP_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_USIM_GFCLK_SHIFT 10
-#define OMAP4430_CLKACTIVITY_USIM_GFCLK_MASK BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_USIM_GFCLK_MASK (1 << 10)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_UTMI_P3_GFCLK_SHIFT 30
-#define OMAP4430_CLKACTIVITY_UTMI_P3_GFCLK_MASK BITFIELD(30, 30)
+#define OMAP4430_CLKACTIVITY_UTMI_P3_GFCLK_MASK (1 << 30)
/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
#define OMAP4430_CLKACTIVITY_UTMI_ROOT_GFCLK_SHIFT 25
-#define OMAP4430_CLKACTIVITY_UTMI_ROOT_GFCLK_MASK BITFIELD(25, 25)
+#define OMAP4430_CLKACTIVITY_UTMI_ROOT_GFCLK_MASK (1 << 25)
/* Used by CM_WKUP_CLKSTCTRL */
#define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_SHIFT 11
-#define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_MASK BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_MASK (1 << 11)
/*
- * Used by CM_WKUP_TIMER1_CLKCTRL, CM_L4PER_DMTIMER10_CLKCTRL,
+ * Used by CM1_ABE_TIMER5_CLKCTRL, CM1_ABE_TIMER6_CLKCTRL,
+ * CM1_ABE_TIMER7_CLKCTRL, CM1_ABE_TIMER8_CLKCTRL, CM_L3INIT_MMC1_CLKCTRL,
+ * CM_L3INIT_MMC2_CLKCTRL, CM_L3INIT_MMC6_CLKCTRL, CM_L4PER_DMTIMER10_CLKCTRL,
* CM_L4PER_DMTIMER11_CLKCTRL, CM_L4PER_DMTIMER2_CLKCTRL,
* CM_L4PER_DMTIMER3_CLKCTRL, CM_L4PER_DMTIMER4_CLKCTRL,
* CM_L4PER_DMTIMER9_CLKCTRL, CM_L4PER_MCASP2_CLKCTRL, CM_L4PER_MCASP3_CLKCTRL,
- * CM_L3INIT_MMC1_CLKCTRL, CM_L3INIT_MMC2_CLKCTRL, CM_L3INIT_MMC6_CLKCTRL,
- * CM1_ABE_TIMER5_CLKCTRL, CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL,
- * CM1_ABE_TIMER8_CLKCTRL
+ * CM_WKUP_TIMER1_CLKCTRL
*/
#define OMAP4430_CLKSEL_SHIFT 24
-#define OMAP4430_CLKSEL_MASK BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_MASK (1 << 24)
/*
* Renamed from CLKSEL Used by CM_ABE_DSS_SYS_CLKSEL, CM_ABE_PLL_REF_CLKSEL,
- * CM_DPLL_SYS_REF_CLKSEL, CM_L4_WKUP_CLKSEL, CM_CLKSEL_DUCATI_ISS_ROOT,
- * CM_CLKSEL_USB_60MHZ
+ * CM_L4_WKUP_CLKSEL, CM_CLKSEL_DUCATI_ISS_ROOT, CM_CLKSEL_USB_60MHZ
*/
#define OMAP4430_CLKSEL_0_0_SHIFT 0
-#define OMAP4430_CLKSEL_0_0_MASK BITFIELD(0, 0)
+#define OMAP4430_CLKSEL_0_0_MASK (1 << 0)
/* Renamed from CLKSEL Used by CM_BYPCLK_DPLL_IVA, CM_BYPCLK_DPLL_MPU */
#define OMAP4430_CLKSEL_0_1_SHIFT 0
-#define OMAP4430_CLKSEL_0_1_MASK BITFIELD(0, 1)
+#define OMAP4430_CLKSEL_0_1_MASK (0x3 << 0)
/* Renamed from CLKSEL Used by CM_L3INIT_HSI_CLKCTRL */
#define OMAP4430_CLKSEL_24_25_SHIFT 24
-#define OMAP4430_CLKSEL_24_25_MASK BITFIELD(24, 25)
+#define OMAP4430_CLKSEL_24_25_MASK (0x3 << 24)
/* Used by CM_L3INIT_USB_OTG_CLKCTRL */
#define OMAP4430_CLKSEL_60M_SHIFT 24
-#define OMAP4430_CLKSEL_60M_MASK BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_60M_MASK (1 << 24)
/* Used by CM1_ABE_AESS_CLKCTRL */
#define OMAP4430_CLKSEL_AESS_FCLK_SHIFT 24
-#define OMAP4430_CLKSEL_AESS_FCLK_MASK BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_AESS_FCLK_MASK (1 << 24)
-/* Used by CM_CLKSEL_CORE_RESTORE, CM_CLKSEL_CORE */
+/* Used by CM_CLKSEL_CORE, CM_CLKSEL_CORE_RESTORE */
#define OMAP4430_CLKSEL_CORE_SHIFT 0
-#define OMAP4430_CLKSEL_CORE_MASK BITFIELD(0, 0)
+#define OMAP4430_CLKSEL_CORE_MASK (1 << 0)
-/* Renamed from CLKSEL_CORE Used by CM_SHADOW_FREQ_CONFIG2 */
+/*
+ * Renamed from CLKSEL_CORE Used by CM_SHADOW_FREQ_CONFIG2_RESTORE,
+ * CM_SHADOW_FREQ_CONFIG2
+ */
#define OMAP4430_CLKSEL_CORE_1_1_SHIFT 1
-#define OMAP4430_CLKSEL_CORE_1_1_MASK BITFIELD(1, 1)
+#define OMAP4430_CLKSEL_CORE_1_1_MASK (1 << 1)
/* Used by CM_WKUP_USIM_CLKCTRL */
#define OMAP4430_CLKSEL_DIV_SHIFT 24
-#define OMAP4430_CLKSEL_DIV_MASK BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_DIV_MASK (1 << 24)
/* Used by CM_CAM_FDIF_CLKCTRL */
#define OMAP4430_CLKSEL_FCLK_SHIFT 24
-#define OMAP4430_CLKSEL_FCLK_MASK BITFIELD(24, 25)
+#define OMAP4430_CLKSEL_FCLK_MASK (0x3 << 24)
/* Used by CM_L4PER_MCBSP4_CLKCTRL */
#define OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT 25
-#define OMAP4430_CLKSEL_INTERNAL_SOURCE_MASK BITFIELD(25, 25)
+#define OMAP4430_CLKSEL_INTERNAL_SOURCE_MASK (1 << 25)
/*
* Renamed from CLKSEL_INTERNAL_SOURCE Used by CM1_ABE_DMIC_CLKCTRL,
@@ -479,836 +485,869 @@
* CM1_ABE_MCBSP3_CLKCTRL
*/
#define OMAP4430_CLKSEL_INTERNAL_SOURCE_CM1_ABE_DMIC_SHIFT 26
-#define OMAP4430_CLKSEL_INTERNAL_SOURCE_CM1_ABE_DMIC_MASK BITFIELD(26, 27)
+#define OMAP4430_CLKSEL_INTERNAL_SOURCE_CM1_ABE_DMIC_MASK (0x3 << 26)
-/* Used by CM_CLKSEL_CORE_RESTORE, CM_CLKSEL_CORE */
+/* Used by CM_CLKSEL_CORE, CM_CLKSEL_CORE_RESTORE */
#define OMAP4430_CLKSEL_L3_SHIFT 4
-#define OMAP4430_CLKSEL_L3_MASK BITFIELD(4, 4)
+#define OMAP4430_CLKSEL_L3_MASK (1 << 4)
-/* Renamed from CLKSEL_L3 Used by CM_SHADOW_FREQ_CONFIG2 */
+/*
+ * Renamed from CLKSEL_L3 Used by CM_SHADOW_FREQ_CONFIG2_RESTORE,
+ * CM_SHADOW_FREQ_CONFIG2
+ */
#define OMAP4430_CLKSEL_L3_SHADOW_SHIFT 2
-#define OMAP4430_CLKSEL_L3_SHADOW_MASK BITFIELD(2, 2)
+#define OMAP4430_CLKSEL_L3_SHADOW_MASK (1 << 2)
-/* Used by CM_CLKSEL_CORE_RESTORE, CM_CLKSEL_CORE */
+/* Used by CM_CLKSEL_CORE, CM_CLKSEL_CORE_RESTORE */
#define OMAP4430_CLKSEL_L4_SHIFT 8
-#define OMAP4430_CLKSEL_L4_MASK BITFIELD(8, 8)
+#define OMAP4430_CLKSEL_L4_MASK (1 << 8)
/* Used by CM_CLKSEL_ABE */
#define OMAP4430_CLKSEL_OPP_SHIFT 0
-#define OMAP4430_CLKSEL_OPP_MASK BITFIELD(0, 1)
-
-/* Used by CM_GFX_GFX_CLKCTRL */
-#define OMAP4430_CLKSEL_PER_192M_SHIFT 25
-#define OMAP4430_CLKSEL_PER_192M_MASK BITFIELD(25, 26)
+#define OMAP4430_CLKSEL_OPP_MASK (0x3 << 0)
/* Used by CM_EMU_DEBUGSS_CLKCTRL */
#define OMAP4430_CLKSEL_PMD_STM_CLK_SHIFT 27
-#define OMAP4430_CLKSEL_PMD_STM_CLK_MASK BITFIELD(27, 29)
+#define OMAP4430_CLKSEL_PMD_STM_CLK_MASK (0x7 << 27)
/* Used by CM_EMU_DEBUGSS_CLKCTRL */
#define OMAP4430_CLKSEL_PMD_TRACE_CLK_SHIFT 24
-#define OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK BITFIELD(24, 26)
+#define OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK (0x7 << 24)
/* Used by CM_GFX_GFX_CLKCTRL */
#define OMAP4430_CLKSEL_SGX_FCLK_SHIFT 24
-#define OMAP4430_CLKSEL_SGX_FCLK_MASK BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_SGX_FCLK_MASK (1 << 24)
/*
* Used by CM1_ABE_DMIC_CLKCTRL, CM1_ABE_MCASP_CLKCTRL, CM1_ABE_MCBSP1_CLKCTRL,
* CM1_ABE_MCBSP2_CLKCTRL, CM1_ABE_MCBSP3_CLKCTRL
*/
#define OMAP4430_CLKSEL_SOURCE_SHIFT 24
-#define OMAP4430_CLKSEL_SOURCE_MASK BITFIELD(24, 25)
+#define OMAP4430_CLKSEL_SOURCE_MASK (0x3 << 24)
/* Renamed from CLKSEL_SOURCE Used by CM_L4PER_MCBSP4_CLKCTRL */
#define OMAP4430_CLKSEL_SOURCE_24_24_SHIFT 24
-#define OMAP4430_CLKSEL_SOURCE_24_24_MASK BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_SOURCE_24_24_MASK (1 << 24)
/* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
#define OMAP4430_CLKSEL_UTMI_P1_SHIFT 24
-#define OMAP4430_CLKSEL_UTMI_P1_MASK BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_UTMI_P1_MASK (1 << 24)
/* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
#define OMAP4430_CLKSEL_UTMI_P2_SHIFT 25
-#define OMAP4430_CLKSEL_UTMI_P2_MASK BITFIELD(25, 25)
+#define OMAP4430_CLKSEL_UTMI_P2_MASK (1 << 25)
/*
- * Used by CM_WKUP_CLKSTCTRL, CM_EMU_CLKSTCTRL, CM_D2D_CLKSTCTRL,
- * CM_DUCATI_CLKSTCTRL, CM_L3INSTR_CLKSTCTRL, CM_L3_1_CLKSTCTRL,
- * CM_L3_2_CLKSTCTRL, CM_L4CFG_CLKSTCTRL, CM_MEMIF_CLKSTCTRL,
- * CM_SDMA_CLKSTCTRL, CM_GFX_CLKSTCTRL, CM_L4PER_CLKSTCTRL, CM_L4SEC_CLKSTCTRL,
- * CM_L3INIT_CLKSTCTRL, CM_CAM_CLKSTCTRL, CM_CEFUSE_CLKSTCTRL,
- * CM_L3INIT_CLKSTCTRL_RESTORE, CM_L3_1_CLKSTCTRL_RESTORE,
- * CM_L3_2_CLKSTCTRL_RESTORE, CM_L4CFG_CLKSTCTRL_RESTORE,
- * CM_L4PER_CLKSTCTRL_RESTORE, CM_MEMIF_CLKSTCTRL_RESTORE, CM_ALWON_CLKSTCTRL,
- * CM_IVAHD_CLKSTCTRL, CM_DSS_CLKSTCTRL, CM_MPU_CLKSTCTRL, CM_TESLA_CLKSTCTRL,
- * CM1_ABE_CLKSTCTRL, CM_MPU_CLKSTCTRL_RESTORE
+ * Used by CM1_ABE_CLKSTCTRL, CM_ALWON_CLKSTCTRL, CM_CAM_CLKSTCTRL,
+ * CM_CEFUSE_CLKSTCTRL, CM_D2D_CLKSTCTRL, CM_DSS_CLKSTCTRL,
+ * CM_DUCATI_CLKSTCTRL, CM_EMU_CLKSTCTRL, CM_GFX_CLKSTCTRL, CM_IVAHD_CLKSTCTRL,
+ * CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE, CM_L3INSTR_CLKSTCTRL,
+ * CM_L3_1_CLKSTCTRL, CM_L3_1_CLKSTCTRL_RESTORE, CM_L3_2_CLKSTCTRL,
+ * CM_L3_2_CLKSTCTRL_RESTORE, CM_L4CFG_CLKSTCTRL, CM_L4CFG_CLKSTCTRL_RESTORE,
+ * CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE, CM_L4SEC_CLKSTCTRL,
+ * CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE, CM_MPU_CLKSTCTRL,
+ * CM_MPU_CLKSTCTRL_RESTORE, CM_SDMA_CLKSTCTRL, CM_TESLA_CLKSTCTRL,
+ * CM_WKUP_CLKSTCTRL
*/
#define OMAP4430_CLKTRCTRL_SHIFT 0
-#define OMAP4430_CLKTRCTRL_MASK BITFIELD(0, 1)
+#define OMAP4430_CLKTRCTRL_MASK (0x3 << 0)
/* Used by CM_EMU_OVERRIDE_DPLL_CORE */
#define OMAP4430_CORE_DPLL_EMU_DIV_SHIFT 0
-#define OMAP4430_CORE_DPLL_EMU_DIV_MASK BITFIELD(0, 6)
+#define OMAP4430_CORE_DPLL_EMU_DIV_MASK (0x7f << 0)
/* Used by CM_EMU_OVERRIDE_DPLL_CORE */
#define OMAP4430_CORE_DPLL_EMU_MULT_SHIFT 8
-#define OMAP4430_CORE_DPLL_EMU_MULT_MASK BITFIELD(8, 18)
+#define OMAP4430_CORE_DPLL_EMU_MULT_MASK (0x7ff << 8)
+
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_CUSTOM_SHIFT 6
+#define OMAP4430_CUSTOM_MASK (0x3 << 6)
-/* Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP */
+/*
+ * Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE
+ */
#define OMAP4430_D2D_DYNDEP_SHIFT 18
-#define OMAP4430_D2D_DYNDEP_MASK BITFIELD(18, 18)
+#define OMAP4430_D2D_DYNDEP_MASK (1 << 18)
/* Used by CM_MPU_STATICDEP */
#define OMAP4430_D2D_STATDEP_SHIFT 18
-#define OMAP4430_D2D_STATDEP_MASK BITFIELD(18, 18)
+#define OMAP4430_D2D_STATDEP_MASK (1 << 18)
/*
- * Used by CM_SSC_DELTAMSTEP_DPLL_PER, CM_SSC_DELTAMSTEP_DPLL_UNIPRO,
- * CM_SSC_DELTAMSTEP_DPLL_USB, CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE,
- * CM_SSC_DELTAMSTEP_DPLL_ABE, CM_SSC_DELTAMSTEP_DPLL_CORE,
- * CM_SSC_DELTAMSTEP_DPLL_DDRPHY, CM_SSC_DELTAMSTEP_DPLL_IVA,
- * CM_SSC_DELTAMSTEP_DPLL_MPU
+ * Used by CM_SSC_DELTAMSTEP_DPLL_ABE, CM_SSC_DELTAMSTEP_DPLL_CORE,
+ * CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE, CM_SSC_DELTAMSTEP_DPLL_DDRPHY,
+ * CM_SSC_DELTAMSTEP_DPLL_IVA, CM_SSC_DELTAMSTEP_DPLL_MPU,
+ * CM_SSC_DELTAMSTEP_DPLL_PER, CM_SSC_DELTAMSTEP_DPLL_UNIPRO,
+ * CM_SSC_DELTAMSTEP_DPLL_USB
*/
#define OMAP4430_DELTAMSTEP_SHIFT 0
-#define OMAP4430_DELTAMSTEP_MASK BITFIELD(0, 19)
+#define OMAP4430_DELTAMSTEP_MASK (0xfffff << 0)
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
+/* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */
#define OMAP4430_DLL_OVERRIDE_SHIFT 2
-#define OMAP4430_DLL_OVERRIDE_MASK BITFIELD(2, 2)
+#define OMAP4430_DLL_OVERRIDE_MASK (1 << 2)
/* Renamed from DLL_OVERRIDE Used by CM_DLL_CTRL */
#define OMAP4430_DLL_OVERRIDE_0_0_SHIFT 0
-#define OMAP4430_DLL_OVERRIDE_0_0_MASK BITFIELD(0, 0)
+#define OMAP4430_DLL_OVERRIDE_0_0_MASK (1 << 0)
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
+/* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */
#define OMAP4430_DLL_RESET_SHIFT 3
-#define OMAP4430_DLL_RESET_MASK BITFIELD(3, 3)
+#define OMAP4430_DLL_RESET_MASK (1 << 3)
/*
- * Used by CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO, CM_CLKSEL_DPLL_USB,
- * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
- * CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA, CM_CLKSEL_DPLL_MPU
+ * Used by CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
+ * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA,
+ * CM_CLKSEL_DPLL_MPU, CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO,
+ * CM_CLKSEL_DPLL_USB
*/
#define OMAP4430_DPLL_BYP_CLKSEL_SHIFT 23
-#define OMAP4430_DPLL_BYP_CLKSEL_MASK BITFIELD(23, 23)
+#define OMAP4430_DPLL_BYP_CLKSEL_MASK (1 << 23)
/* Used by CM_CLKDCOLDO_DPLL_USB */
#define OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_SHIFT 8
-#define OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_MASK BITFIELD(8, 8)
+#define OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_MASK (1 << 8)
-/* Used by CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_CORE */
+/* Used by CM_CLKSEL_DPLL_CORE, CM_CLKSEL_DPLL_CORE_RESTORE */
#define OMAP4430_DPLL_CLKOUTHIF_CLKSEL_SHIFT 20
-#define OMAP4430_DPLL_CLKOUTHIF_CLKSEL_MASK BITFIELD(20, 20)
+#define OMAP4430_DPLL_CLKOUTHIF_CLKSEL_MASK (1 << 20)
/*
- * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE,
- * CM_DIV_M3_DPLL_CORE
+ * Used by CM_DIV_M3_DPLL_ABE, CM_DIV_M3_DPLL_CORE,
+ * CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_PER
*/
#define OMAP4430_DPLL_CLKOUTHIF_DIV_SHIFT 0
-#define OMAP4430_DPLL_CLKOUTHIF_DIV_MASK BITFIELD(0, 4)
+#define OMAP4430_DPLL_CLKOUTHIF_DIV_MASK (0x1f << 0)
/*
- * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE,
- * CM_DIV_M3_DPLL_CORE
+ * Used by CM_DIV_M3_DPLL_ABE, CM_DIV_M3_DPLL_CORE,
+ * CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_PER
*/
#define OMAP4430_DPLL_CLKOUTHIF_DIVCHACK_SHIFT 5
-#define OMAP4430_DPLL_CLKOUTHIF_DIVCHACK_MASK BITFIELD(5, 5)
+#define OMAP4430_DPLL_CLKOUTHIF_DIVCHACK_MASK (1 << 5)
/*
- * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE,
- * CM_DIV_M3_DPLL_CORE
+ * Used by CM_DIV_M3_DPLL_ABE, CM_DIV_M3_DPLL_CORE,
+ * CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_PER
*/
#define OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT 8
-#define OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_MASK BITFIELD(8, 8)
+#define OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_MASK (1 << 8)
-/* Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO, CM_DIV_M2_DPLL_ABE */
+/* Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO */
#define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_SHIFT 10
-#define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK BITFIELD(10, 10)
+#define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK (1 << 10)
/*
- * Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO,
- * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
- * CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU
+ * Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
+ * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU,
+ * CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO
*/
#define OMAP4430_DPLL_CLKOUT_DIV_SHIFT 0
-#define OMAP4430_DPLL_CLKOUT_DIV_MASK BITFIELD(0, 4)
+#define OMAP4430_DPLL_CLKOUT_DIV_MASK (0x1f << 0)
/* Renamed from DPLL_CLKOUT_DIV Used by CM_DIV_M2_DPLL_USB */
#define OMAP4430_DPLL_CLKOUT_DIV_0_6_SHIFT 0
-#define OMAP4430_DPLL_CLKOUT_DIV_0_6_MASK BITFIELD(0, 6)
+#define OMAP4430_DPLL_CLKOUT_DIV_0_6_MASK (0x7f << 0)
/*
- * Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO,
- * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
- * CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU
+ * Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
+ * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU,
+ * CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO
*/
#define OMAP4430_DPLL_CLKOUT_DIVCHACK_SHIFT 5
-#define OMAP4430_DPLL_CLKOUT_DIVCHACK_MASK BITFIELD(5, 5)
+#define OMAP4430_DPLL_CLKOUT_DIVCHACK_MASK (1 << 5)
/* Renamed from DPLL_CLKOUT_DIVCHACK Used by CM_DIV_M2_DPLL_USB */
#define OMAP4430_DPLL_CLKOUT_DIVCHACK_M2_USB_SHIFT 7
-#define OMAP4430_DPLL_CLKOUT_DIVCHACK_M2_USB_MASK BITFIELD(7, 7)
+#define OMAP4430_DPLL_CLKOUT_DIVCHACK_M2_USB_MASK (1 << 7)
/*
- * Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_USB, CM_DIV_M2_DPLL_CORE_RESTORE,
- * CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE, CM_DIV_M2_DPLL_DDRPHY,
- * CM_DIV_M2_DPLL_MPU
+ * Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
+ * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU,
+ * CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_USB
*/
#define OMAP4430_DPLL_CLKOUT_GATE_CTRL_SHIFT 8
-#define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK BITFIELD(8, 8)
+#define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK (1 << 8)
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
+/* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */
#define OMAP4430_DPLL_CORE_DPLL_EN_SHIFT 8
-#define OMAP4430_DPLL_CORE_DPLL_EN_MASK BITFIELD(8, 10)
+#define OMAP4430_DPLL_CORE_DPLL_EN_MASK (0x7 << 8)
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
+/* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */
#define OMAP4430_DPLL_CORE_M2_DIV_SHIFT 11
-#define OMAP4430_DPLL_CORE_M2_DIV_MASK BITFIELD(11, 15)
+#define OMAP4430_DPLL_CORE_M2_DIV_MASK (0x1f << 11)
-/* Used by CM_SHADOW_FREQ_CONFIG2 */
+/* Used by CM_SHADOW_FREQ_CONFIG2, CM_SHADOW_FREQ_CONFIG2_RESTORE */
#define OMAP4430_DPLL_CORE_M5_DIV_SHIFT 3
-#define OMAP4430_DPLL_CORE_M5_DIV_MASK BITFIELD(3, 7)
-
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
-#define OMAP4430_DPLL_CORE_SYS_REF_CLKSEL_SHIFT 1
-#define OMAP4430_DPLL_CORE_SYS_REF_CLKSEL_MASK BITFIELD(1, 1)
+#define OMAP4430_DPLL_CORE_M5_DIV_MASK (0x1f << 3)
/*
- * Used by CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO,
- * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
- * CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA, CM_CLKSEL_DPLL_MPU
+ * Used by CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
+ * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA,
+ * CM_CLKSEL_DPLL_MPU, CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO
*/
#define OMAP4430_DPLL_DIV_SHIFT 0
-#define OMAP4430_DPLL_DIV_MASK BITFIELD(0, 6)
+#define OMAP4430_DPLL_DIV_MASK (0x7f << 0)
/* Renamed from DPLL_DIV Used by CM_CLKSEL_DPLL_USB */
#define OMAP4430_DPLL_DIV_0_7_SHIFT 0
-#define OMAP4430_DPLL_DIV_0_7_MASK BITFIELD(0, 7)
+#define OMAP4430_DPLL_DIV_0_7_MASK (0xff << 0)
/*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_USB,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER
*/
#define OMAP4430_DPLL_DRIFTGUARD_EN_SHIFT 8
-#define OMAP4430_DPLL_DRIFTGUARD_EN_MASK BITFIELD(8, 8)
+#define OMAP4430_DPLL_DRIFTGUARD_EN_MASK (1 << 8)
/* Renamed from DPLL_DRIFTGUARD_EN Used by CM_CLKMODE_DPLL_UNIPRO */
#define OMAP4430_DPLL_DRIFTGUARD_EN_3_3_SHIFT 3
-#define OMAP4430_DPLL_DRIFTGUARD_EN_3_3_MASK BITFIELD(3, 3)
+#define OMAP4430_DPLL_DRIFTGUARD_EN_3_3_MASK (1 << 3)
/*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO, CM_CLKMODE_DPLL_USB,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
+ * CM_CLKMODE_DPLL_USB
*/
#define OMAP4430_DPLL_EN_SHIFT 0
-#define OMAP4430_DPLL_EN_MASK BITFIELD(0, 2)
+#define OMAP4430_DPLL_EN_MASK (0x7 << 0)
/*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO
*/
#define OMAP4430_DPLL_LPMODE_EN_SHIFT 10
-#define OMAP4430_DPLL_LPMODE_EN_MASK BITFIELD(10, 10)
+#define OMAP4430_DPLL_LPMODE_EN_MASK (1 << 10)
/*
- * Used by CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO,
- * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
- * CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA, CM_CLKSEL_DPLL_MPU
+ * Used by CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
+ * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA,
+ * CM_CLKSEL_DPLL_MPU, CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO
*/
#define OMAP4430_DPLL_MULT_SHIFT 8
-#define OMAP4430_DPLL_MULT_MASK BITFIELD(8, 18)
+#define OMAP4430_DPLL_MULT_MASK (0x7ff << 8)
/* Renamed from DPLL_MULT Used by CM_CLKSEL_DPLL_USB */
#define OMAP4430_DPLL_MULT_USB_SHIFT 8
-#define OMAP4430_DPLL_MULT_USB_MASK BITFIELD(8, 19)
+#define OMAP4430_DPLL_MULT_USB_MASK (0xfff << 8)
/*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO
*/
#define OMAP4430_DPLL_REGM4XEN_SHIFT 11
-#define OMAP4430_DPLL_REGM4XEN_MASK BITFIELD(11, 11)
+#define OMAP4430_DPLL_REGM4XEN_MASK (1 << 11)
/* Used by CM_CLKSEL_DPLL_USB */
#define OMAP4430_DPLL_SD_DIV_SHIFT 24
-#define OMAP4430_DPLL_SD_DIV_MASK BITFIELD(24, 31)
+#define OMAP4430_DPLL_SD_DIV_MASK (0xff << 24)
/*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO, CM_CLKMODE_DPLL_USB,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
+ * CM_CLKMODE_DPLL_USB
*/
#define OMAP4430_DPLL_SSC_ACK_SHIFT 13
-#define OMAP4430_DPLL_SSC_ACK_MASK BITFIELD(13, 13)
+#define OMAP4430_DPLL_SSC_ACK_MASK (1 << 13)
/*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO, CM_CLKMODE_DPLL_USB,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
+ * CM_CLKMODE_DPLL_USB
*/
#define OMAP4430_DPLL_SSC_DOWNSPREAD_SHIFT 14
-#define OMAP4430_DPLL_SSC_DOWNSPREAD_MASK BITFIELD(14, 14)
+#define OMAP4430_DPLL_SSC_DOWNSPREAD_MASK (1 << 14)
/*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO, CM_CLKMODE_DPLL_USB,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
+ * CM_CLKMODE_DPLL_USB
*/
#define OMAP4430_DPLL_SSC_EN_SHIFT 12
-#define OMAP4430_DPLL_SSC_EN_MASK BITFIELD(12, 12)
+#define OMAP4430_DPLL_SSC_EN_MASK (1 << 12)
-/* Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, CM_L4PER_DYNAMICDEP */
+/*
+ * Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_L4PER_DYNAMICDEP, CM_L4PER_DYNAMICDEP_RESTORE
+ */
#define OMAP4430_DSS_DYNDEP_SHIFT 8
-#define OMAP4430_DSS_DYNDEP_MASK BITFIELD(8, 8)
+#define OMAP4430_DSS_DYNDEP_MASK (1 << 8)
/*
- * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE,
- * CM_MPU_STATICDEP
+ * Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP, CM_SDMA_STATICDEP,
+ * CM_SDMA_STATICDEP_RESTORE
*/
#define OMAP4430_DSS_STATDEP_SHIFT 8
-#define OMAP4430_DSS_STATDEP_MASK BITFIELD(8, 8)
+#define OMAP4430_DSS_STATDEP_MASK (1 << 8)
-/* Used by CM_L3_2_DYNAMICDEP */
+/* Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE */
#define OMAP4430_DUCATI_DYNDEP_SHIFT 0
-#define OMAP4430_DUCATI_DYNDEP_MASK BITFIELD(0, 0)
+#define OMAP4430_DUCATI_DYNDEP_MASK (1 << 0)
-/* Used by CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP */
+/* Used by CM_MPU_STATICDEP, CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE */
#define OMAP4430_DUCATI_STATDEP_SHIFT 0
-#define OMAP4430_DUCATI_STATDEP_MASK BITFIELD(0, 0)
+#define OMAP4430_DUCATI_STATDEP_MASK (1 << 0)
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
+/* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */
#define OMAP4430_FREQ_UPDATE_SHIFT 0
-#define OMAP4430_FREQ_UPDATE_MASK BITFIELD(0, 0)
+#define OMAP4430_FREQ_UPDATE_MASK (1 << 0)
+
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_FUNC_SHIFT 16
+#define OMAP4430_FUNC_MASK (0xfff << 16)
-/* Used by CM_L3_2_DYNAMICDEP */
+/* Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE */
#define OMAP4430_GFX_DYNDEP_SHIFT 10
-#define OMAP4430_GFX_DYNDEP_MASK BITFIELD(10, 10)
+#define OMAP4430_GFX_DYNDEP_MASK (1 << 10)
/* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP */
#define OMAP4430_GFX_STATDEP_SHIFT 10
-#define OMAP4430_GFX_STATDEP_MASK BITFIELD(10, 10)
+#define OMAP4430_GFX_STATDEP_MASK (1 << 10)
-/* Used by CM_SHADOW_FREQ_CONFIG2 */
+/* Used by CM_SHADOW_FREQ_CONFIG2, CM_SHADOW_FREQ_CONFIG2_RESTORE */
#define OMAP4430_GPMC_FREQ_UPDATE_SHIFT 0
-#define OMAP4430_GPMC_FREQ_UPDATE_MASK BITFIELD(0, 0)
+#define OMAP4430_GPMC_FREQ_UPDATE_MASK (1 << 0)
/*
- * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE,
- * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA
+ * Used by CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_CORE_RESTORE,
+ * CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA, CM_DIV_M4_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT1_DIV_SHIFT 0
-#define OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK BITFIELD(0, 4)
+#define OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK (0x1f << 0)
/*
- * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE,
- * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA
+ * Used by CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_CORE_RESTORE,
+ * CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA, CM_DIV_M4_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT1_DIVCHACK_SHIFT 5
-#define OMAP4430_HSDIVIDER_CLKOUT1_DIVCHACK_MASK BITFIELD(5, 5)
+#define OMAP4430_HSDIVIDER_CLKOUT1_DIVCHACK_MASK (1 << 5)
/*
- * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE,
- * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA
+ * Used by CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_CORE_RESTORE,
+ * CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA, CM_DIV_M4_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT1_GATE_CTRL_SHIFT 8
-#define OMAP4430_HSDIVIDER_CLKOUT1_GATE_CTRL_MASK BITFIELD(8, 8)
+#define OMAP4430_HSDIVIDER_CLKOUT1_GATE_CTRL_MASK (1 << 8)
/*
- * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE,
- * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA
+ * Used by CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_CORE_RESTORE,
+ * CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA, CM_DIV_M4_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT1_PWDN_SHIFT 12
-#define OMAP4430_HSDIVIDER_CLKOUT1_PWDN_MASK BITFIELD(12, 12)
+#define OMAP4430_HSDIVIDER_CLKOUT1_PWDN_MASK (1 << 12)
/*
- * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE,
- * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA
+ * Used by CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_CORE_RESTORE,
+ * CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA, CM_DIV_M5_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT2_DIV_SHIFT 0
-#define OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK BITFIELD(0, 4)
+#define OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK (0x1f << 0)
/*
- * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE,
- * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA
+ * Used by CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_CORE_RESTORE,
+ * CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA, CM_DIV_M5_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT2_DIVCHACK_SHIFT 5
-#define OMAP4430_HSDIVIDER_CLKOUT2_DIVCHACK_MASK BITFIELD(5, 5)
+#define OMAP4430_HSDIVIDER_CLKOUT2_DIVCHACK_MASK (1 << 5)
/*
- * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE,
- * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA
+ * Used by CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_CORE_RESTORE,
+ * CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA, CM_DIV_M5_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT2_GATE_CTRL_SHIFT 8
-#define OMAP4430_HSDIVIDER_CLKOUT2_GATE_CTRL_MASK BITFIELD(8, 8)
+#define OMAP4430_HSDIVIDER_CLKOUT2_GATE_CTRL_MASK (1 << 8)
/*
- * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE,
- * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA
+ * Used by CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_CORE_RESTORE,
+ * CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA, CM_DIV_M5_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT2_PWDN_SHIFT 12
-#define OMAP4430_HSDIVIDER_CLKOUT2_PWDN_MASK BITFIELD(12, 12)
+#define OMAP4430_HSDIVIDER_CLKOUT2_PWDN_MASK (1 << 12)
/*
- * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE,
- * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY
+ * Used by CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_CORE_RESTORE,
+ * CM_DIV_M6_DPLL_DDRPHY, CM_DIV_M6_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT3_DIV_SHIFT 0
-#define OMAP4430_HSDIVIDER_CLKOUT3_DIV_MASK BITFIELD(0, 4)
+#define OMAP4430_HSDIVIDER_CLKOUT3_DIV_MASK (0x1f << 0)
/*
- * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE,
- * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY
+ * Used by CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_CORE_RESTORE,
+ * CM_DIV_M6_DPLL_DDRPHY, CM_DIV_M6_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT3_DIVCHACK_SHIFT 5
-#define OMAP4430_HSDIVIDER_CLKOUT3_DIVCHACK_MASK BITFIELD(5, 5)
+#define OMAP4430_HSDIVIDER_CLKOUT3_DIVCHACK_MASK (1 << 5)
/*
- * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE,
- * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY
+ * Used by CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_CORE_RESTORE,
+ * CM_DIV_M6_DPLL_DDRPHY, CM_DIV_M6_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT3_GATE_CTRL_SHIFT 8
-#define OMAP4430_HSDIVIDER_CLKOUT3_GATE_CTRL_MASK BITFIELD(8, 8)
+#define OMAP4430_HSDIVIDER_CLKOUT3_GATE_CTRL_MASK (1 << 8)
/*
- * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE,
- * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY
+ * Used by CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_CORE_RESTORE,
+ * CM_DIV_M6_DPLL_DDRPHY, CM_DIV_M6_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT3_PWDN_SHIFT 12
-#define OMAP4430_HSDIVIDER_CLKOUT3_PWDN_MASK BITFIELD(12, 12)
+#define OMAP4430_HSDIVIDER_CLKOUT3_PWDN_MASK (1 << 12)
/*
- * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE,
- * CM_DIV_M7_DPLL_CORE
+ * Used by CM_DIV_M7_DPLL_CORE, CM_DIV_M7_DPLL_CORE_RESTORE,
+ * CM_DIV_M7_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT4_DIV_SHIFT 0
-#define OMAP4430_HSDIVIDER_CLKOUT4_DIV_MASK BITFIELD(0, 4)
+#define OMAP4430_HSDIVIDER_CLKOUT4_DIV_MASK (0x1f << 0)
/*
- * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE,
- * CM_DIV_M7_DPLL_CORE
+ * Used by CM_DIV_M7_DPLL_CORE, CM_DIV_M7_DPLL_CORE_RESTORE,
+ * CM_DIV_M7_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT4_DIVCHACK_SHIFT 5
-#define OMAP4430_HSDIVIDER_CLKOUT4_DIVCHACK_MASK BITFIELD(5, 5)
+#define OMAP4430_HSDIVIDER_CLKOUT4_DIVCHACK_MASK (1 << 5)
/*
- * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE,
- * CM_DIV_M7_DPLL_CORE
+ * Used by CM_DIV_M7_DPLL_CORE, CM_DIV_M7_DPLL_CORE_RESTORE,
+ * CM_DIV_M7_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT4_GATE_CTRL_SHIFT 8
-#define OMAP4430_HSDIVIDER_CLKOUT4_GATE_CTRL_MASK BITFIELD(8, 8)
+#define OMAP4430_HSDIVIDER_CLKOUT4_GATE_CTRL_MASK (1 << 8)
/*
- * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE,
- * CM_DIV_M7_DPLL_CORE
+ * Used by CM_DIV_M7_DPLL_CORE, CM_DIV_M7_DPLL_CORE_RESTORE,
+ * CM_DIV_M7_DPLL_PER
*/
#define OMAP4430_HSDIVIDER_CLKOUT4_PWDN_SHIFT 12
-#define OMAP4430_HSDIVIDER_CLKOUT4_PWDN_MASK BITFIELD(12, 12)
-
-/*
- * Used by PRM_PRM_PROFILING_CLKCTRL, CM_WKUP_GPIO1_CLKCTRL,
- * CM_WKUP_KEYBOARD_CLKCTRL, CM_WKUP_L4WKUP_CLKCTRL, CM_WKUP_RTC_CLKCTRL,
- * CM_WKUP_SARRAM_CLKCTRL, CM_WKUP_SYNCTIMER_CLKCTRL, CM_WKUP_TIMER12_CLKCTRL,
- * CM_WKUP_TIMER1_CLKCTRL, CM_WKUP_USIM_CLKCTRL, CM_WKUP_WDT1_CLKCTRL,
- * CM_WKUP_WDT2_CLKCTRL, CM_EMU_DEBUGSS_CLKCTRL, CM_D2D_MODEM_ICR_CLKCTRL,
- * CM_D2D_SAD2D_CLKCTRL, CM_D2D_SAD2D_FW_CLKCTRL, CM_DUCATI_DUCATI_CLKCTRL,
- * CM_L3INSTR_L3_3_CLKCTRL, CM_L3INSTR_L3_INSTR_CLKCTRL,
- * CM_L3INSTR_OCP_WP1_CLKCTRL, CM_L3_1_L3_1_CLKCTRL, CM_L3_2_GPMC_CLKCTRL,
- * CM_L3_2_L3_2_CLKCTRL, CM_L3_2_OCMC_RAM_CLKCTRL, CM_L4CFG_HW_SEM_CLKCTRL,
- * CM_L4CFG_L4_CFG_CLKCTRL, CM_L4CFG_MAILBOX_CLKCTRL, CM_L4CFG_SAR_ROM_CLKCTRL,
- * CM_MEMIF_DMM_CLKCTRL, CM_MEMIF_EMIF_1_CLKCTRL, CM_MEMIF_EMIF_2_CLKCTRL,
- * CM_MEMIF_EMIF_FW_CLKCTRL, CM_MEMIF_EMIF_H1_CLKCTRL,
- * CM_MEMIF_EMIF_H2_CLKCTRL, CM_SDMA_SDMA_CLKCTRL, CM_GFX_GFX_CLKCTRL,
- * CM_L4PER_ADC_CLKCTRL, CM_L4PER_DMTIMER10_CLKCTRL,
- * CM_L4PER_DMTIMER11_CLKCTRL, CM_L4PER_DMTIMER2_CLKCTRL,
- * CM_L4PER_DMTIMER3_CLKCTRL, CM_L4PER_DMTIMER4_CLKCTRL,
- * CM_L4PER_DMTIMER9_CLKCTRL, CM_L4PER_ELM_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL,
- * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL,
- * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_HDQ1W_CLKCTRL, CM_L4PER_HECC1_CLKCTRL,
- * CM_L4PER_HECC2_CLKCTRL, CM_L4PER_I2C1_CLKCTRL, CM_L4PER_I2C2_CLKCTRL,
- * CM_L4PER_I2C3_CLKCTRL, CM_L4PER_I2C4_CLKCTRL, CM_L4PER_I2C5_CLKCTRL,
- * CM_L4PER_L4PER_CLKCTRL, CM_L4PER_MCASP2_CLKCTRL, CM_L4PER_MCASP3_CLKCTRL,
- * CM_L4PER_MCBSP4_CLKCTRL, CM_L4PER_MCSPI1_CLKCTRL, CM_L4PER_MCSPI2_CLKCTRL,
- * CM_L4PER_MCSPI3_CLKCTRL, CM_L4PER_MCSPI4_CLKCTRL, CM_L4PER_MGATE_CLKCTRL,
- * CM_L4PER_MMCSD3_CLKCTRL, CM_L4PER_MMCSD4_CLKCTRL, CM_L4PER_MMCSD5_CLKCTRL,
- * CM_L4PER_MSPROHG_CLKCTRL, CM_L4PER_SLIMBUS2_CLKCTRL, CM_L4PER_UART1_CLKCTRL,
- * CM_L4PER_UART2_CLKCTRL, CM_L4PER_UART3_CLKCTRL, CM_L4PER_UART4_CLKCTRL,
- * CM_L4SEC_AES1_CLKCTRL, CM_L4SEC_AES2_CLKCTRL, CM_L4SEC_CRYPTODMA_CLKCTRL,
- * CM_L4SEC_DES3DES_CLKCTRL, CM_L4SEC_PKAEIP29_CLKCTRL, CM_L4SEC_RNG_CLKCTRL,
- * CM_L4SEC_SHA2MD51_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
+#define OMAP4430_HSDIVIDER_CLKOUT4_PWDN_MASK (1 << 12)
+
+/*
+ * Used by CM1_ABE_AESS_CLKCTRL, CM1_ABE_DMIC_CLKCTRL, CM1_ABE_L4ABE_CLKCTRL,
+ * CM1_ABE_MCASP_CLKCTRL, CM1_ABE_MCBSP1_CLKCTRL, CM1_ABE_MCBSP2_CLKCTRL,
+ * CM1_ABE_MCBSP3_CLKCTRL, CM1_ABE_PDM_CLKCTRL, CM1_ABE_SLIMBUS_CLKCTRL,
+ * CM1_ABE_TIMER5_CLKCTRL, CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL,
+ * CM1_ABE_TIMER8_CLKCTRL, CM1_ABE_WDT3_CLKCTRL, CM_ALWON_MDMINTC_CLKCTRL,
+ * CM_ALWON_SR_CORE_CLKCTRL, CM_ALWON_SR_IVA_CLKCTRL, CM_ALWON_SR_MPU_CLKCTRL,
+ * CM_CAM_FDIF_CLKCTRL, CM_CAM_ISS_CLKCTRL, CM_CEFUSE_CEFUSE_CLKCTRL,
+ * CM_CM1_PROFILING_CLKCTRL, CM_CM1_PROFILING_CLKCTRL_RESTORE,
+ * CM_CM2_PROFILING_CLKCTRL, CM_CM2_PROFILING_CLKCTRL_RESTORE,
+ * CM_D2D_MODEM_ICR_CLKCTRL, CM_D2D_SAD2D_CLKCTRL, CM_D2D_SAD2D_FW_CLKCTRL,
+ * CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL, CM_DUCATI_DUCATI_CLKCTRL,
+ * CM_EMU_DEBUGSS_CLKCTRL, CM_GFX_GFX_CLKCTRL, CM_IVAHD_IVAHD_CLKCTRL,
+ * CM_IVAHD_SL2_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
* CM_L3INIT_HSI_CLKCTRL, CM_L3INIT_MMC1_CLKCTRL, CM_L3INIT_MMC2_CLKCTRL,
* CM_L3INIT_MMC6_CLKCTRL, CM_L3INIT_P1500_CLKCTRL, CM_L3INIT_PCIESS_CLKCTRL,
* CM_L3INIT_SATA_CLKCTRL, CM_L3INIT_TPPSS_CLKCTRL, CM_L3INIT_UNIPRO1_CLKCTRL,
* CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL,
- * CM_L3INIT_USB_HOST_FS_CLKCTRL, CM_L3INIT_USB_OTG_CLKCTRL,
- * CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_XHPI_CLKCTRL, CM_CAM_FDIF_CLKCTRL,
- * CM_CAM_ISS_CLKCTRL, CM_CEFUSE_CEFUSE_CLKCTRL,
- * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE,
- * CM_L3INSTR_L3_3_CLKCTRL_RESTORE, CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE,
- * CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO3_CLKCTRL_RESTORE, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO5_CLKCTRL_RESTORE, CM_L4PER_GPIO6_CLKCTRL_RESTORE,
- * CM_ALWON_MDMINTC_CLKCTRL, CM_ALWON_SR_CORE_CLKCTRL, CM_ALWON_SR_IVA_CLKCTRL,
- * CM_ALWON_SR_MPU_CLKCTRL, CM_IVAHD_IVAHD_CLKCTRL, CM_IVAHD_SL2_CLKCTRL,
- * CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL, CM_CM2_PROFILING_CLKCTRL,
- * CM_MPU_MPU_CLKCTRL, CM_TESLA_TESLA_CLKCTRL, CM1_ABE_AESS_CLKCTRL,
- * CM1_ABE_DMIC_CLKCTRL, CM1_ABE_L4ABE_CLKCTRL, CM1_ABE_MCASP_CLKCTRL,
- * CM1_ABE_MCBSP1_CLKCTRL, CM1_ABE_MCBSP2_CLKCTRL, CM1_ABE_MCBSP3_CLKCTRL,
- * CM1_ABE_PDM_CLKCTRL, CM1_ABE_SLIMBUS_CLKCTRL, CM1_ABE_TIMER5_CLKCTRL,
- * CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL, CM1_ABE_TIMER8_CLKCTRL,
- * CM1_ABE_WDT3_CLKCTRL, CM_CM1_PROFILING_CLKCTRL
+ * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_HOST_FS_CLKCTRL,
+ * CM_L3INIT_USB_OTG_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL,
+ * CM_L3INIT_USB_TLL_CLKCTRL_RESTORE, CM_L3INIT_XHPI_CLKCTRL,
+ * CM_L3INSTR_L3_3_CLKCTRL, CM_L3INSTR_L3_3_CLKCTRL_RESTORE,
+ * CM_L3INSTR_L3_INSTR_CLKCTRL, CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE,
+ * CM_L3INSTR_OCP_WP1_CLKCTRL, CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE,
+ * CM_L3_1_L3_1_CLKCTRL, CM_L3_2_GPMC_CLKCTRL, CM_L3_2_L3_2_CLKCTRL,
+ * CM_L3_2_OCMC_RAM_CLKCTRL, CM_L4CFG_HW_SEM_CLKCTRL, CM_L4CFG_L4_CFG_CLKCTRL,
+ * CM_L4CFG_MAILBOX_CLKCTRL, CM_L4CFG_SAR_ROM_CLKCTRL, CM_L4PER_ADC_CLKCTRL,
+ * CM_L4PER_DMTIMER10_CLKCTRL, CM_L4PER_DMTIMER11_CLKCTRL,
+ * CM_L4PER_DMTIMER2_CLKCTRL, CM_L4PER_DMTIMER3_CLKCTRL,
+ * CM_L4PER_DMTIMER4_CLKCTRL, CM_L4PER_DMTIMER9_CLKCTRL, CM_L4PER_ELM_CLKCTRL,
+ * CM_L4PER_GPIO2_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO3_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO5_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_GPIO6_CLKCTRL_RESTORE,
+ * CM_L4PER_HDQ1W_CLKCTRL, CM_L4PER_HECC1_CLKCTRL, CM_L4PER_HECC2_CLKCTRL,
+ * CM_L4PER_I2C1_CLKCTRL, CM_L4PER_I2C2_CLKCTRL, CM_L4PER_I2C3_CLKCTRL,
+ * CM_L4PER_I2C4_CLKCTRL, CM_L4PER_I2C5_CLKCTRL, CM_L4PER_L4PER_CLKCTRL,
+ * CM_L4PER_MCASP2_CLKCTRL, CM_L4PER_MCASP3_CLKCTRL, CM_L4PER_MCBSP4_CLKCTRL,
+ * CM_L4PER_MCSPI1_CLKCTRL, CM_L4PER_MCSPI2_CLKCTRL, CM_L4PER_MCSPI3_CLKCTRL,
+ * CM_L4PER_MCSPI4_CLKCTRL, CM_L4PER_MGATE_CLKCTRL, CM_L4PER_MMCSD3_CLKCTRL,
+ * CM_L4PER_MMCSD4_CLKCTRL, CM_L4PER_MMCSD5_CLKCTRL, CM_L4PER_MSPROHG_CLKCTRL,
+ * CM_L4PER_SLIMBUS2_CLKCTRL, CM_L4PER_UART1_CLKCTRL, CM_L4PER_UART2_CLKCTRL,
+ * CM_L4PER_UART3_CLKCTRL, CM_L4PER_UART4_CLKCTRL, CM_L4SEC_AES1_CLKCTRL,
+ * CM_L4SEC_AES2_CLKCTRL, CM_L4SEC_CRYPTODMA_CLKCTRL, CM_L4SEC_DES3DES_CLKCTRL,
+ * CM_L4SEC_PKAEIP29_CLKCTRL, CM_L4SEC_RNG_CLKCTRL, CM_L4SEC_SHA2MD51_CLKCTRL,
+ * CM_MEMIF_DMM_CLKCTRL, CM_MEMIF_EMIF_1_CLKCTRL, CM_MEMIF_EMIF_2_CLKCTRL,
+ * CM_MEMIF_EMIF_FW_CLKCTRL, CM_MEMIF_EMIF_H1_CLKCTRL,
+ * CM_MEMIF_EMIF_H2_CLKCTRL, CM_MPU_MPU_CLKCTRL, CM_SDMA_SDMA_CLKCTRL,
+ * CM_TESLA_TESLA_CLKCTRL, CM_WKUP_GPIO1_CLKCTRL, CM_WKUP_KEYBOARD_CLKCTRL,
+ * CM_WKUP_L4WKUP_CLKCTRL, CM_WKUP_RTC_CLKCTRL, CM_WKUP_SARRAM_CLKCTRL,
+ * CM_WKUP_SYNCTIMER_CLKCTRL, CM_WKUP_TIMER12_CLKCTRL, CM_WKUP_TIMER1_CLKCTRL,
+ * CM_WKUP_USIM_CLKCTRL, CM_WKUP_WDT1_CLKCTRL, CM_WKUP_WDT2_CLKCTRL
*/
#define OMAP4430_IDLEST_SHIFT 16
-#define OMAP4430_IDLEST_MASK BITFIELD(16, 17)
+#define OMAP4430_IDLEST_MASK (0x3 << 16)
-/* Used by CM_DUCATI_DYNAMICDEP, CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP */
+/*
+ * Used by CM_DUCATI_DYNAMICDEP, CM_L3_2_DYNAMICDEP,
+ * CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE
+ */
#define OMAP4430_ISS_DYNDEP_SHIFT 9
-#define OMAP4430_ISS_DYNDEP_MASK BITFIELD(9, 9)
+#define OMAP4430_ISS_DYNDEP_MASK (1 << 9)
/*
- * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE,
- * CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP, CM_SDMA_STATICDEP,
+ * CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
*/
#define OMAP4430_ISS_STATDEP_SHIFT 9
-#define OMAP4430_ISS_STATDEP_MASK BITFIELD(9, 9)
+#define OMAP4430_ISS_STATDEP_MASK (1 << 9)
-/* Used by CM_L3_2_DYNAMICDEP, CM_TESLA_DYNAMICDEP */
+/* Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_TESLA_DYNAMICDEP */
#define OMAP4430_IVAHD_DYNDEP_SHIFT 2
-#define OMAP4430_IVAHD_DYNDEP_MASK BITFIELD(2, 2)
+#define OMAP4430_IVAHD_DYNDEP_MASK (1 << 2)
/*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_GFX_STATICDEP, CM_L3INIT_STATICDEP, CM_CAM_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_DSS_STATICDEP, CM_MPU_STATICDEP,
- * CM_TESLA_STATICDEP
+ * Used by CM_CAM_STATICDEP, CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE,
+ * CM_DSS_STATICDEP, CM_DUCATI_STATICDEP, CM_GFX_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_MPU_STATICDEP, CM_SDMA_STATICDEP,
+ * CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
*/
#define OMAP4430_IVAHD_STATDEP_SHIFT 2
-#define OMAP4430_IVAHD_STATDEP_MASK BITFIELD(2, 2)
+#define OMAP4430_IVAHD_STATDEP_MASK (1 << 2)
-/* Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, CM_L4PER_DYNAMICDEP */
+/*
+ * Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_L4PER_DYNAMICDEP, CM_L4PER_DYNAMICDEP_RESTORE
+ */
#define OMAP4430_L3INIT_DYNDEP_SHIFT 7
-#define OMAP4430_L3INIT_DYNDEP_MASK BITFIELD(7, 7)
+#define OMAP4430_L3INIT_DYNDEP_MASK (1 << 7)
/*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE, CM_DUCATI_STATICDEP,
+ * CM_MPU_STATICDEP, CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE,
+ * CM_TESLA_STATICDEP
*/
#define OMAP4430_L3INIT_STATDEP_SHIFT 7
-#define OMAP4430_L3INIT_STATDEP_MASK BITFIELD(7, 7)
+#define OMAP4430_L3INIT_STATDEP_MASK (1 << 7)
/*
- * Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, CM_L3INIT_DYNAMICDEP,
- * CM_DSS_DYNAMICDEP, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP
+ * Used by CM_DSS_DYNAMICDEP, CM_L3INIT_DYNAMICDEP, CM_L3_2_DYNAMICDEP,
+ * CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP
*/
#define OMAP4430_L3_1_DYNDEP_SHIFT 5
-#define OMAP4430_L3_1_DYNDEP_MASK BITFIELD(5, 5)
+#define OMAP4430_L3_1_DYNDEP_MASK (1 << 5)
/*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_GFX_STATICDEP, CM_L4SEC_STATICDEP, CM_L3INIT_STATICDEP, CM_CAM_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_IVAHD_STATICDEP, CM_DSS_STATICDEP,
- * CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_CAM_STATICDEP, CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE,
+ * CM_DSS_STATICDEP, CM_DUCATI_STATICDEP, CM_GFX_STATICDEP, CM_IVAHD_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_L4SEC_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
*/
#define OMAP4430_L3_1_STATDEP_SHIFT 5
-#define OMAP4430_L3_1_STATDEP_MASK BITFIELD(5, 5)
+#define OMAP4430_L3_1_STATDEP_MASK (1 << 5)
/*
- * Used by CM_EMU_DYNAMICDEP, CM_D2D_DYNAMICDEP, CM_DUCATI_DYNAMICDEP,
- * CM_L3_1_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, CM_SDMA_DYNAMICDEP,
- * CM_GFX_DYNAMICDEP, CM_L4SEC_DYNAMICDEP, CM_L3INIT_DYNAMICDEP,
- * CM_CAM_DYNAMICDEP, CM_IVAHD_DYNAMICDEP
+ * Used by CM_CAM_DYNAMICDEP, CM_D2D_DYNAMICDEP, CM_D2D_DYNAMICDEP_RESTORE,
+ * CM_DUCATI_DYNAMICDEP, CM_EMU_DYNAMICDEP, CM_GFX_DYNAMICDEP,
+ * CM_IVAHD_DYNAMICDEP, CM_L3INIT_DYNAMICDEP, CM_L3_1_DYNAMICDEP,
+ * CM_L3_1_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_L4SEC_DYNAMICDEP, CM_SDMA_DYNAMICDEP
*/
#define OMAP4430_L3_2_DYNDEP_SHIFT 6
-#define OMAP4430_L3_2_DYNDEP_MASK BITFIELD(6, 6)
+#define OMAP4430_L3_2_DYNDEP_MASK (1 << 6)
/*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_GFX_STATICDEP, CM_L4SEC_STATICDEP, CM_L3INIT_STATICDEP, CM_CAM_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_IVAHD_STATICDEP, CM_DSS_STATICDEP,
- * CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_CAM_STATICDEP, CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE,
+ * CM_DSS_STATICDEP, CM_DUCATI_STATICDEP, CM_GFX_STATICDEP, CM_IVAHD_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_L4SEC_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
*/
#define OMAP4430_L3_2_STATDEP_SHIFT 6
-#define OMAP4430_L3_2_STATDEP_MASK BITFIELD(6, 6)
+#define OMAP4430_L3_2_STATDEP_MASK (1 << 6)
-/* Used by CM_L3_1_DYNAMICDEP */
+/* Used by CM_L3_1_DYNAMICDEP, CM_L3_1_DYNAMICDEP_RESTORE */
#define OMAP4430_L4CFG_DYNDEP_SHIFT 12
-#define OMAP4430_L4CFG_DYNDEP_MASK BITFIELD(12, 12)
+#define OMAP4430_L4CFG_DYNDEP_MASK (1 << 12)
/*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_L3INIT_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP,
- * CM_TESLA_STATICDEP
+ * Used by CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE, CM_DUCATI_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_MPU_STATICDEP, CM_SDMA_STATICDEP,
+ * CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
*/
#define OMAP4430_L4CFG_STATDEP_SHIFT 12
-#define OMAP4430_L4CFG_STATDEP_MASK BITFIELD(12, 12)
+#define OMAP4430_L4CFG_STATDEP_MASK (1 << 12)
-/* Used by CM_L3_2_DYNAMICDEP */
+/* Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE */
#define OMAP4430_L4PER_DYNDEP_SHIFT 13
-#define OMAP4430_L4PER_DYNDEP_MASK BITFIELD(13, 13)
+#define OMAP4430_L4PER_DYNDEP_MASK (1 << 13)
/*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_L4SEC_STATICDEP, CM_L3INIT_STATICDEP, CM_SDMA_STATICDEP_RESTORE,
- * CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE, CM_DUCATI_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_L4SEC_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
*/
#define OMAP4430_L4PER_STATDEP_SHIFT 13
-#define OMAP4430_L4PER_STATDEP_MASK BITFIELD(13, 13)
+#define OMAP4430_L4PER_STATDEP_MASK (1 << 13)
-/* Used by CM_L3_2_DYNAMICDEP, CM_L4PER_DYNAMICDEP */
+/*
+ * Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_L4PER_DYNAMICDEP,
+ * CM_L4PER_DYNAMICDEP_RESTORE
+ */
#define OMAP4430_L4SEC_DYNDEP_SHIFT 14
-#define OMAP4430_L4SEC_DYNDEP_MASK BITFIELD(14, 14)
+#define OMAP4430_L4SEC_DYNDEP_MASK (1 << 14)
/*
- * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_L3INIT_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP
+ * Used by CM_DUCATI_STATICDEP, CM_L3INIT_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE
*/
#define OMAP4430_L4SEC_STATDEP_SHIFT 14
-#define OMAP4430_L4SEC_STATDEP_MASK BITFIELD(14, 14)
+#define OMAP4430_L4SEC_STATDEP_MASK (1 << 14)
-/* Used by CM_L4CFG_DYNAMICDEP */
+/* Used by CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE */
#define OMAP4430_L4WKUP_DYNDEP_SHIFT 15
-#define OMAP4430_L4WKUP_DYNDEP_MASK BITFIELD(15, 15)
+#define OMAP4430_L4WKUP_DYNDEP_MASK (1 << 15)
/*
- * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_L3INIT_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_DUCATI_STATICDEP, CM_L3INIT_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
*/
#define OMAP4430_L4WKUP_STATDEP_SHIFT 15
-#define OMAP4430_L4WKUP_STATDEP_MASK BITFIELD(15, 15)
+#define OMAP4430_L4WKUP_STATDEP_MASK (1 << 15)
/*
- * Used by CM_D2D_DYNAMICDEP, CM_L3_1_DYNAMICDEP, CM_L4CFG_DYNAMICDEP,
- * CM_MPU_DYNAMICDEP
+ * Used by CM_D2D_DYNAMICDEP, CM_D2D_DYNAMICDEP_RESTORE, CM_L3_1_DYNAMICDEP,
+ * CM_L3_1_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_MPU_DYNAMICDEP
*/
#define OMAP4430_MEMIF_DYNDEP_SHIFT 4
-#define OMAP4430_MEMIF_DYNDEP_MASK BITFIELD(4, 4)
+#define OMAP4430_MEMIF_DYNDEP_MASK (1 << 4)
/*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_GFX_STATICDEP, CM_L4SEC_STATICDEP, CM_L3INIT_STATICDEP, CM_CAM_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_IVAHD_STATICDEP, CM_DSS_STATICDEP,
- * CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_CAM_STATICDEP, CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE,
+ * CM_DSS_STATICDEP, CM_DUCATI_STATICDEP, CM_GFX_STATICDEP, CM_IVAHD_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_L4SEC_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
*/
#define OMAP4430_MEMIF_STATDEP_SHIFT 4
-#define OMAP4430_MEMIF_STATDEP_MASK BITFIELD(4, 4)
+#define OMAP4430_MEMIF_STATDEP_MASK (1 << 4)
/*
- * Used by CM_SSC_MODFREQDIV_DPLL_PER, CM_SSC_MODFREQDIV_DPLL_UNIPRO,
- * CM_SSC_MODFREQDIV_DPLL_USB, CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE,
- * CM_SSC_MODFREQDIV_DPLL_ABE, CM_SSC_MODFREQDIV_DPLL_CORE,
- * CM_SSC_MODFREQDIV_DPLL_DDRPHY, CM_SSC_MODFREQDIV_DPLL_IVA,
- * CM_SSC_MODFREQDIV_DPLL_MPU
+ * Used by CM_SSC_MODFREQDIV_DPLL_ABE, CM_SSC_MODFREQDIV_DPLL_CORE,
+ * CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE, CM_SSC_MODFREQDIV_DPLL_DDRPHY,
+ * CM_SSC_MODFREQDIV_DPLL_IVA, CM_SSC_MODFREQDIV_DPLL_MPU,
+ * CM_SSC_MODFREQDIV_DPLL_PER, CM_SSC_MODFREQDIV_DPLL_UNIPRO,
+ * CM_SSC_MODFREQDIV_DPLL_USB
*/
#define OMAP4430_MODFREQDIV_EXPONENT_SHIFT 8
-#define OMAP4430_MODFREQDIV_EXPONENT_MASK BITFIELD(8, 10)
+#define OMAP4430_MODFREQDIV_EXPONENT_MASK (0x7 << 8)
/*
- * Used by CM_SSC_MODFREQDIV_DPLL_PER, CM_SSC_MODFREQDIV_DPLL_UNIPRO,
- * CM_SSC_MODFREQDIV_DPLL_USB, CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE,
- * CM_SSC_MODFREQDIV_DPLL_ABE, CM_SSC_MODFREQDIV_DPLL_CORE,
- * CM_SSC_MODFREQDIV_DPLL_DDRPHY, CM_SSC_MODFREQDIV_DPLL_IVA,
- * CM_SSC_MODFREQDIV_DPLL_MPU
+ * Used by CM_SSC_MODFREQDIV_DPLL_ABE, CM_SSC_MODFREQDIV_DPLL_CORE,
+ * CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE, CM_SSC_MODFREQDIV_DPLL_DDRPHY,
+ * CM_SSC_MODFREQDIV_DPLL_IVA, CM_SSC_MODFREQDIV_DPLL_MPU,
+ * CM_SSC_MODFREQDIV_DPLL_PER, CM_SSC_MODFREQDIV_DPLL_UNIPRO,
+ * CM_SSC_MODFREQDIV_DPLL_USB
*/
#define OMAP4430_MODFREQDIV_MANTISSA_SHIFT 0
-#define OMAP4430_MODFREQDIV_MANTISSA_MASK BITFIELD(0, 6)
-
-/*
- * Used by PRM_PRM_PROFILING_CLKCTRL, CM_WKUP_GPIO1_CLKCTRL,
- * CM_WKUP_KEYBOARD_CLKCTRL, CM_WKUP_L4WKUP_CLKCTRL, CM_WKUP_RTC_CLKCTRL,
- * CM_WKUP_SARRAM_CLKCTRL, CM_WKUP_SYNCTIMER_CLKCTRL, CM_WKUP_TIMER12_CLKCTRL,
- * CM_WKUP_TIMER1_CLKCTRL, CM_WKUP_USIM_CLKCTRL, CM_WKUP_WDT1_CLKCTRL,
- * CM_WKUP_WDT2_CLKCTRL, CM_EMU_DEBUGSS_CLKCTRL, CM_D2D_MODEM_ICR_CLKCTRL,
- * CM_D2D_SAD2D_CLKCTRL, CM_D2D_SAD2D_FW_CLKCTRL, CM_DUCATI_DUCATI_CLKCTRL,
- * CM_L3INSTR_L3_3_CLKCTRL, CM_L3INSTR_L3_INSTR_CLKCTRL,
- * CM_L3INSTR_OCP_WP1_CLKCTRL, CM_L3_1_L3_1_CLKCTRL, CM_L3_2_GPMC_CLKCTRL,
- * CM_L3_2_L3_2_CLKCTRL, CM_L3_2_OCMC_RAM_CLKCTRL, CM_L4CFG_HW_SEM_CLKCTRL,
- * CM_L4CFG_L4_CFG_CLKCTRL, CM_L4CFG_MAILBOX_CLKCTRL, CM_L4CFG_SAR_ROM_CLKCTRL,
- * CM_MEMIF_DMM_CLKCTRL, CM_MEMIF_EMIF_1_CLKCTRL, CM_MEMIF_EMIF_2_CLKCTRL,
- * CM_MEMIF_EMIF_FW_CLKCTRL, CM_MEMIF_EMIF_H1_CLKCTRL,
- * CM_MEMIF_EMIF_H2_CLKCTRL, CM_SDMA_SDMA_CLKCTRL, CM_GFX_GFX_CLKCTRL,
- * CM_L4PER_ADC_CLKCTRL, CM_L4PER_DMTIMER10_CLKCTRL,
- * CM_L4PER_DMTIMER11_CLKCTRL, CM_L4PER_DMTIMER2_CLKCTRL,
- * CM_L4PER_DMTIMER3_CLKCTRL, CM_L4PER_DMTIMER4_CLKCTRL,
- * CM_L4PER_DMTIMER9_CLKCTRL, CM_L4PER_ELM_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL,
- * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL,
- * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_HDQ1W_CLKCTRL, CM_L4PER_HECC1_CLKCTRL,
- * CM_L4PER_HECC2_CLKCTRL, CM_L4PER_I2C1_CLKCTRL, CM_L4PER_I2C2_CLKCTRL,
- * CM_L4PER_I2C3_CLKCTRL, CM_L4PER_I2C4_CLKCTRL, CM_L4PER_I2C5_CLKCTRL,
- * CM_L4PER_L4PER_CLKCTRL, CM_L4PER_MCASP2_CLKCTRL, CM_L4PER_MCASP3_CLKCTRL,
- * CM_L4PER_MCBSP4_CLKCTRL, CM_L4PER_MCSPI1_CLKCTRL, CM_L4PER_MCSPI2_CLKCTRL,
- * CM_L4PER_MCSPI3_CLKCTRL, CM_L4PER_MCSPI4_CLKCTRL, CM_L4PER_MGATE_CLKCTRL,
- * CM_L4PER_MMCSD3_CLKCTRL, CM_L4PER_MMCSD4_CLKCTRL, CM_L4PER_MMCSD5_CLKCTRL,
- * CM_L4PER_MSPROHG_CLKCTRL, CM_L4PER_SLIMBUS2_CLKCTRL, CM_L4PER_UART1_CLKCTRL,
- * CM_L4PER_UART2_CLKCTRL, CM_L4PER_UART3_CLKCTRL, CM_L4PER_UART4_CLKCTRL,
- * CM_L4SEC_AES1_CLKCTRL, CM_L4SEC_AES2_CLKCTRL, CM_L4SEC_CRYPTODMA_CLKCTRL,
- * CM_L4SEC_DES3DES_CLKCTRL, CM_L4SEC_PKAEIP29_CLKCTRL, CM_L4SEC_RNG_CLKCTRL,
- * CM_L4SEC_SHA2MD51_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
+#define OMAP4430_MODFREQDIV_MANTISSA_MASK (0x7f << 0)
+
+/*
+ * Used by CM1_ABE_AESS_CLKCTRL, CM1_ABE_DMIC_CLKCTRL, CM1_ABE_L4ABE_CLKCTRL,
+ * CM1_ABE_MCASP_CLKCTRL, CM1_ABE_MCBSP1_CLKCTRL, CM1_ABE_MCBSP2_CLKCTRL,
+ * CM1_ABE_MCBSP3_CLKCTRL, CM1_ABE_PDM_CLKCTRL, CM1_ABE_SLIMBUS_CLKCTRL,
+ * CM1_ABE_TIMER5_CLKCTRL, CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL,
+ * CM1_ABE_TIMER8_CLKCTRL, CM1_ABE_WDT3_CLKCTRL, CM_ALWON_MDMINTC_CLKCTRL,
+ * CM_ALWON_SR_CORE_CLKCTRL, CM_ALWON_SR_IVA_CLKCTRL, CM_ALWON_SR_MPU_CLKCTRL,
+ * CM_CAM_FDIF_CLKCTRL, CM_CAM_ISS_CLKCTRL, CM_CEFUSE_CEFUSE_CLKCTRL,
+ * CM_CM1_PROFILING_CLKCTRL, CM_CM1_PROFILING_CLKCTRL_RESTORE,
+ * CM_CM2_PROFILING_CLKCTRL, CM_CM2_PROFILING_CLKCTRL_RESTORE,
+ * CM_D2D_MODEM_ICR_CLKCTRL, CM_D2D_SAD2D_CLKCTRL, CM_D2D_SAD2D_FW_CLKCTRL,
+ * CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL, CM_DUCATI_DUCATI_CLKCTRL,
+ * CM_EMU_DEBUGSS_CLKCTRL, CM_GFX_GFX_CLKCTRL, CM_IVAHD_IVAHD_CLKCTRL,
+ * CM_IVAHD_SL2_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
* CM_L3INIT_HSI_CLKCTRL, CM_L3INIT_MMC1_CLKCTRL, CM_L3INIT_MMC2_CLKCTRL,
* CM_L3INIT_MMC6_CLKCTRL, CM_L3INIT_P1500_CLKCTRL, CM_L3INIT_PCIESS_CLKCTRL,
* CM_L3INIT_SATA_CLKCTRL, CM_L3INIT_TPPSS_CLKCTRL, CM_L3INIT_UNIPRO1_CLKCTRL,
* CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL,
- * CM_L3INIT_USB_HOST_FS_CLKCTRL, CM_L3INIT_USB_OTG_CLKCTRL,
- * CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_XHPI_CLKCTRL, CM_CAM_FDIF_CLKCTRL,
- * CM_CAM_ISS_CLKCTRL, CM_CEFUSE_CEFUSE_CLKCTRL,
- * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE,
- * CM_L3INSTR_L3_3_CLKCTRL_RESTORE, CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE,
- * CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO3_CLKCTRL_RESTORE, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO5_CLKCTRL_RESTORE, CM_L4PER_GPIO6_CLKCTRL_RESTORE,
- * CM_ALWON_MDMINTC_CLKCTRL, CM_ALWON_SR_CORE_CLKCTRL, CM_ALWON_SR_IVA_CLKCTRL,
- * CM_ALWON_SR_MPU_CLKCTRL, CM_IVAHD_IVAHD_CLKCTRL, CM_IVAHD_SL2_CLKCTRL,
- * CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL, CM_CM2_PROFILING_CLKCTRL,
- * CM_MPU_MPU_CLKCTRL, CM_TESLA_TESLA_CLKCTRL, CM1_ABE_AESS_CLKCTRL,
- * CM1_ABE_DMIC_CLKCTRL, CM1_ABE_L4ABE_CLKCTRL, CM1_ABE_MCASP_CLKCTRL,
- * CM1_ABE_MCBSP1_CLKCTRL, CM1_ABE_MCBSP2_CLKCTRL, CM1_ABE_MCBSP3_CLKCTRL,
- * CM1_ABE_PDM_CLKCTRL, CM1_ABE_SLIMBUS_CLKCTRL, CM1_ABE_TIMER5_CLKCTRL,
- * CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL, CM1_ABE_TIMER8_CLKCTRL,
- * CM1_ABE_WDT3_CLKCTRL, CM_CM1_PROFILING_CLKCTRL
+ * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_HOST_FS_CLKCTRL,
+ * CM_L3INIT_USB_OTG_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL,
+ * CM_L3INIT_USB_TLL_CLKCTRL_RESTORE, CM_L3INIT_XHPI_CLKCTRL,
+ * CM_L3INSTR_L3_3_CLKCTRL, CM_L3INSTR_L3_3_CLKCTRL_RESTORE,
+ * CM_L3INSTR_L3_INSTR_CLKCTRL, CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE,
+ * CM_L3INSTR_OCP_WP1_CLKCTRL, CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE,
+ * CM_L3_1_L3_1_CLKCTRL, CM_L3_2_GPMC_CLKCTRL, CM_L3_2_L3_2_CLKCTRL,
+ * CM_L3_2_OCMC_RAM_CLKCTRL, CM_L4CFG_HW_SEM_CLKCTRL, CM_L4CFG_L4_CFG_CLKCTRL,
+ * CM_L4CFG_MAILBOX_CLKCTRL, CM_L4CFG_SAR_ROM_CLKCTRL, CM_L4PER_ADC_CLKCTRL,
+ * CM_L4PER_DMTIMER10_CLKCTRL, CM_L4PER_DMTIMER11_CLKCTRL,
+ * CM_L4PER_DMTIMER2_CLKCTRL, CM_L4PER_DMTIMER3_CLKCTRL,
+ * CM_L4PER_DMTIMER4_CLKCTRL, CM_L4PER_DMTIMER9_CLKCTRL, CM_L4PER_ELM_CLKCTRL,
+ * CM_L4PER_GPIO2_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO3_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO5_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_GPIO6_CLKCTRL_RESTORE,
+ * CM_L4PER_HDQ1W_CLKCTRL, CM_L4PER_HECC1_CLKCTRL, CM_L4PER_HECC2_CLKCTRL,
+ * CM_L4PER_I2C1_CLKCTRL, CM_L4PER_I2C2_CLKCTRL, CM_L4PER_I2C3_CLKCTRL,
+ * CM_L4PER_I2C4_CLKCTRL, CM_L4PER_I2C5_CLKCTRL, CM_L4PER_L4PER_CLKCTRL,
+ * CM_L4PER_MCASP2_CLKCTRL, CM_L4PER_MCASP3_CLKCTRL, CM_L4PER_MCBSP4_CLKCTRL,
+ * CM_L4PER_MCSPI1_CLKCTRL, CM_L4PER_MCSPI2_CLKCTRL, CM_L4PER_MCSPI3_CLKCTRL,
+ * CM_L4PER_MCSPI4_CLKCTRL, CM_L4PER_MGATE_CLKCTRL, CM_L4PER_MMCSD3_CLKCTRL,
+ * CM_L4PER_MMCSD4_CLKCTRL, CM_L4PER_MMCSD5_CLKCTRL, CM_L4PER_MSPROHG_CLKCTRL,
+ * CM_L4PER_SLIMBUS2_CLKCTRL, CM_L4PER_UART1_CLKCTRL, CM_L4PER_UART2_CLKCTRL,
+ * CM_L4PER_UART3_CLKCTRL, CM_L4PER_UART4_CLKCTRL, CM_L4SEC_AES1_CLKCTRL,
+ * CM_L4SEC_AES2_CLKCTRL, CM_L4SEC_CRYPTODMA_CLKCTRL, CM_L4SEC_DES3DES_CLKCTRL,
+ * CM_L4SEC_PKAEIP29_CLKCTRL, CM_L4SEC_RNG_CLKCTRL, CM_L4SEC_SHA2MD51_CLKCTRL,
+ * CM_MEMIF_DMM_CLKCTRL, CM_MEMIF_EMIF_1_CLKCTRL, CM_MEMIF_EMIF_2_CLKCTRL,
+ * CM_MEMIF_EMIF_FW_CLKCTRL, CM_MEMIF_EMIF_H1_CLKCTRL,
+ * CM_MEMIF_EMIF_H2_CLKCTRL, CM_MPU_MPU_CLKCTRL, CM_SDMA_SDMA_CLKCTRL,
+ * CM_TESLA_TESLA_CLKCTRL, CM_WKUP_GPIO1_CLKCTRL, CM_WKUP_KEYBOARD_CLKCTRL,
+ * CM_WKUP_L4WKUP_CLKCTRL, CM_WKUP_RTC_CLKCTRL, CM_WKUP_SARRAM_CLKCTRL,
+ * CM_WKUP_SYNCTIMER_CLKCTRL, CM_WKUP_TIMER12_CLKCTRL, CM_WKUP_TIMER1_CLKCTRL,
+ * CM_WKUP_USIM_CLKCTRL, CM_WKUP_WDT1_CLKCTRL, CM_WKUP_WDT2_CLKCTRL
*/
#define OMAP4430_MODULEMODE_SHIFT 0
-#define OMAP4430_MODULEMODE_MASK BITFIELD(0, 1)
+#define OMAP4430_MODULEMODE_MASK (0x3 << 0)
/* Used by CM_DSS_DSS_CLKCTRL */
#define OMAP4430_OPTFCLKEN_48MHZ_CLK_SHIFT 9
-#define OMAP4430_OPTFCLKEN_48MHZ_CLK_MASK BITFIELD(9, 9)
+#define OMAP4430_OPTFCLKEN_48MHZ_CLK_MASK (1 << 9)
/* Used by CM_WKUP_BANDGAP_CLKCTRL */
#define OMAP4430_OPTFCLKEN_BGAP_32K_SHIFT 8
-#define OMAP4430_OPTFCLKEN_BGAP_32K_MASK BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_BGAP_32K_MASK (1 << 8)
-/* Used by CM_L3INIT_USBPHYOCP2SCP_CLKCTRL */
-#define OMAP4430_OPTFCLKEN_CLK32K_SHIFT 9
-#define OMAP4430_OPTFCLKEN_CLK32K_MASK BITFIELD(9, 9)
+/* Used by CM_ALWON_USBPHY_CLKCTRL */
+#define OMAP4430_OPTFCLKEN_CLK32K_SHIFT 8
+#define OMAP4430_OPTFCLKEN_CLK32K_MASK (1 << 8)
/* Used by CM_CAM_ISS_CLKCTRL */
#define OMAP4430_OPTFCLKEN_CTRLCLK_SHIFT 8
-#define OMAP4430_OPTFCLKEN_CTRLCLK_MASK BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_CTRLCLK_MASK (1 << 8)
/*
- * Used by CM_WKUP_GPIO1_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL,
- * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL,
- * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO3_CLKCTRL_RESTORE, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO5_CLKCTRL_RESTORE, CM_L4PER_GPIO6_CLKCTRL_RESTORE
+ * Used by CM_L4PER_GPIO2_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO3_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO5_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_GPIO6_CLKCTRL_RESTORE, CM_WKUP_GPIO1_CLKCTRL
*/
#define OMAP4430_OPTFCLKEN_DBCLK_SHIFT 8
-#define OMAP4430_OPTFCLKEN_DBCLK_MASK BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_DBCLK_MASK (1 << 8)
/* Used by CM_MEMIF_DLL_CLKCTRL, CM_MEMIF_DLL_H_CLKCTRL */
#define OMAP4430_OPTFCLKEN_DLL_CLK_SHIFT 8
-#define OMAP4430_OPTFCLKEN_DLL_CLK_MASK BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_DLL_CLK_MASK (1 << 8)
/* Used by CM_DSS_DSS_CLKCTRL */
#define OMAP4430_OPTFCLKEN_DSSCLK_SHIFT 8
-#define OMAP4430_OPTFCLKEN_DSSCLK_MASK BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_DSSCLK_MASK (1 << 8)
+
+/* Used by CM_WKUP_USIM_CLKCTRL */
+#define OMAP4430_OPTFCLKEN_FCLK_SHIFT 8
+#define OMAP4430_OPTFCLKEN_FCLK_MASK (1 << 8)
/* Used by CM1_ABE_SLIMBUS_CLKCTRL */
#define OMAP4430_OPTFCLKEN_FCLK0_SHIFT 8
-#define OMAP4430_OPTFCLKEN_FCLK0_MASK BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_FCLK0_MASK (1 << 8)
/* Used by CM1_ABE_SLIMBUS_CLKCTRL */
#define OMAP4430_OPTFCLKEN_FCLK1_SHIFT 9
-#define OMAP4430_OPTFCLKEN_FCLK1_MASK BITFIELD(9, 9)
+#define OMAP4430_OPTFCLKEN_FCLK1_MASK (1 << 9)
/* Used by CM1_ABE_SLIMBUS_CLKCTRL */
#define OMAP4430_OPTFCLKEN_FCLK2_SHIFT 10
-#define OMAP4430_OPTFCLKEN_FCLK2_MASK BITFIELD(10, 10)
+#define OMAP4430_OPTFCLKEN_FCLK2_MASK (1 << 10)
/* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
#define OMAP4430_OPTFCLKEN_FUNC48MCLK_SHIFT 15
-#define OMAP4430_OPTFCLKEN_FUNC48MCLK_MASK BITFIELD(15, 15)
+#define OMAP4430_OPTFCLKEN_FUNC48MCLK_MASK (1 << 15)
/* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
#define OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_SHIFT 13
-#define OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_MASK BITFIELD(13, 13)
+#define OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_MASK (1 << 13)
/* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
#define OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_SHIFT 14
-#define OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_MASK BITFIELD(14, 14)
+#define OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_MASK (1 << 14)
/* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
#define OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_SHIFT 11
-#define OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_MASK BITFIELD(11, 11)
+#define OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_MASK (1 << 11)
/* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
#define OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_SHIFT 12
-#define OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_MASK BITFIELD(12, 12)
+#define OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_MASK (1 << 12)
/* Used by CM_L4PER_SLIMBUS2_CLKCTRL */
#define OMAP4430_OPTFCLKEN_PER24MC_GFCLK_SHIFT 8
-#define OMAP4430_OPTFCLKEN_PER24MC_GFCLK_MASK BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_PER24MC_GFCLK_MASK (1 << 8)
/* Used by CM_L4PER_SLIMBUS2_CLKCTRL */
#define OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_SHIFT 9
-#define OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_MASK BITFIELD(9, 9)
+#define OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_MASK (1 << 9)
/* Used by CM_L3INIT_USBPHYOCP2SCP_CLKCTRL */
#define OMAP4430_OPTFCLKEN_PHY_48M_SHIFT 8
-#define OMAP4430_OPTFCLKEN_PHY_48M_MASK BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_PHY_48M_MASK (1 << 8)
/* Used by CM_L4PER_SLIMBUS2_CLKCTRL */
#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_SHIFT 10
-#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_MASK BITFIELD(10, 10)
+#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_MASK (1 << 10)
/* Renamed from OPTFCLKEN_SLIMBUS_CLK Used by CM1_ABE_SLIMBUS_CLKCTRL */
#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_SHIFT 11
-#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_MASK BITFIELD(11, 11)
+#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_MASK (1 << 11)
/* Used by CM_DSS_DSS_CLKCTRL */
#define OMAP4430_OPTFCLKEN_SYS_CLK_SHIFT 10
-#define OMAP4430_OPTFCLKEN_SYS_CLK_MASK BITFIELD(10, 10)
+#define OMAP4430_OPTFCLKEN_SYS_CLK_MASK (1 << 10)
/* Used by CM_DSS_DSS_CLKCTRL */
#define OMAP4430_OPTFCLKEN_TV_CLK_SHIFT 11
-#define OMAP4430_OPTFCLKEN_TV_CLK_MASK BITFIELD(11, 11)
+#define OMAP4430_OPTFCLKEN_TV_CLK_MASK (1 << 11)
/* Used by CM_L3INIT_UNIPRO1_CLKCTRL */
#define OMAP4430_OPTFCLKEN_TXPHYCLK_SHIFT 8
-#define OMAP4430_OPTFCLKEN_TXPHYCLK_MASK BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_TXPHYCLK_MASK (1 << 8)
/* Used by CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE */
#define OMAP4430_OPTFCLKEN_USB_CH0_CLK_SHIFT 8
-#define OMAP4430_OPTFCLKEN_USB_CH0_CLK_MASK BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_USB_CH0_CLK_MASK (1 << 8)
/* Used by CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE */
#define OMAP4430_OPTFCLKEN_USB_CH1_CLK_SHIFT 9
-#define OMAP4430_OPTFCLKEN_USB_CH1_CLK_MASK BITFIELD(9, 9)
+#define OMAP4430_OPTFCLKEN_USB_CH1_CLK_MASK (1 << 9)
/* Used by CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE */
#define OMAP4430_OPTFCLKEN_USB_CH2_CLK_SHIFT 10
-#define OMAP4430_OPTFCLKEN_USB_CH2_CLK_MASK BITFIELD(10, 10)
+#define OMAP4430_OPTFCLKEN_USB_CH2_CLK_MASK (1 << 10)
/* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
#define OMAP4430_OPTFCLKEN_UTMI_P1_CLK_SHIFT 8
-#define OMAP4430_OPTFCLKEN_UTMI_P1_CLK_MASK BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_UTMI_P1_CLK_MASK (1 << 8)
/* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
#define OMAP4430_OPTFCLKEN_UTMI_P2_CLK_SHIFT 9
-#define OMAP4430_OPTFCLKEN_UTMI_P2_CLK_MASK BITFIELD(9, 9)
+#define OMAP4430_OPTFCLKEN_UTMI_P2_CLK_MASK (1 << 9)
/* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
#define OMAP4430_OPTFCLKEN_UTMI_P3_CLK_SHIFT 10
-#define OMAP4430_OPTFCLKEN_UTMI_P3_CLK_MASK BITFIELD(10, 10)
+#define OMAP4430_OPTFCLKEN_UTMI_P3_CLK_MASK (1 << 10)
/* Used by CM_L3INIT_USB_OTG_CLKCTRL */
#define OMAP4430_OPTFCLKEN_XCLK_SHIFT 8
-#define OMAP4430_OPTFCLKEN_XCLK_MASK BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_XCLK_MASK (1 << 8)
-/* Used by CM_EMU_OVERRIDE_DPLL_PER, CM_EMU_OVERRIDE_DPLL_CORE */
+/* Used by CM_EMU_OVERRIDE_DPLL_CORE */
#define OMAP4430_OVERRIDE_ENABLE_SHIFT 19
-#define OMAP4430_OVERRIDE_ENABLE_MASK BITFIELD(19, 19)
+#define OMAP4430_OVERRIDE_ENABLE_MASK (1 << 19)
/* Used by CM_CLKSEL_ABE */
#define OMAP4430_PAD_CLKS_GATE_SHIFT 8
-#define OMAP4430_PAD_CLKS_GATE_MASK BITFIELD(8, 8)
+#define OMAP4430_PAD_CLKS_GATE_MASK (1 << 8)
/* Used by CM_CORE_DVFS_CURRENT, CM_IVA_DVFS_CURRENT */
#define OMAP4430_PERF_CURRENT_SHIFT 0
-#define OMAP4430_PERF_CURRENT_MASK BITFIELD(0, 7)
+#define OMAP4430_PERF_CURRENT_MASK (0xff << 0)
/*
* Used by CM_CORE_DVFS_PERF1, CM_CORE_DVFS_PERF2, CM_CORE_DVFS_PERF3,
@@ -1316,159 +1355,173 @@
* CM_IVA_DVFS_PERF_TESLA
*/
#define OMAP4430_PERF_REQ_SHIFT 0
-#define OMAP4430_PERF_REQ_MASK BITFIELD(0, 7)
-
-/* Used by CM_EMU_OVERRIDE_DPLL_PER */
-#define OMAP4430_PER_DPLL_EMU_DIV_SHIFT 0
-#define OMAP4430_PER_DPLL_EMU_DIV_MASK BITFIELD(0, 6)
-
-/* Used by CM_EMU_OVERRIDE_DPLL_PER */
-#define OMAP4430_PER_DPLL_EMU_MULT_SHIFT 8
-#define OMAP4430_PER_DPLL_EMU_MULT_MASK BITFIELD(8, 18)
+#define OMAP4430_PERF_REQ_MASK (0xff << 0)
/* Used by CM_RESTORE_ST */
#define OMAP4430_PHASE1_COMPLETED_SHIFT 0
-#define OMAP4430_PHASE1_COMPLETED_MASK BITFIELD(0, 0)
+#define OMAP4430_PHASE1_COMPLETED_MASK (1 << 0)
/* Used by CM_RESTORE_ST */
#define OMAP4430_PHASE2A_COMPLETED_SHIFT 1
-#define OMAP4430_PHASE2A_COMPLETED_MASK BITFIELD(1, 1)
+#define OMAP4430_PHASE2A_COMPLETED_MASK (1 << 1)
/* Used by CM_RESTORE_ST */
#define OMAP4430_PHASE2B_COMPLETED_SHIFT 2
-#define OMAP4430_PHASE2B_COMPLETED_MASK BITFIELD(2, 2)
+#define OMAP4430_PHASE2B_COMPLETED_MASK (1 << 2)
/* Used by CM_EMU_DEBUGSS_CLKCTRL */
#define OMAP4430_PMD_STM_MUX_CTRL_SHIFT 20
-#define OMAP4430_PMD_STM_MUX_CTRL_MASK BITFIELD(20, 21)
+#define OMAP4430_PMD_STM_MUX_CTRL_MASK (0x3 << 20)
/* Used by CM_EMU_DEBUGSS_CLKCTRL */
#define OMAP4430_PMD_TRACE_MUX_CTRL_SHIFT 22
-#define OMAP4430_PMD_TRACE_MUX_CTRL_MASK BITFIELD(22, 23)
+#define OMAP4430_PMD_TRACE_MUX_CTRL_MASK (0x3 << 22)
-/* Used by CM_DYN_DEP_PRESCAL */
+/* Used by CM_DYN_DEP_PRESCAL, CM_DYN_DEP_PRESCAL_RESTORE */
#define OMAP4430_PRESCAL_SHIFT 0
-#define OMAP4430_PRESCAL_MASK BITFIELD(0, 5)
+#define OMAP4430_PRESCAL_MASK (0x3f << 0)
-/* Used by REVISION_CM2, REVISION_CM1 */
-#define OMAP4430_REV_SHIFT 0
-#define OMAP4430_REV_MASK BITFIELD(0, 7)
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_R_RTL_SHIFT 11
+#define OMAP4430_R_RTL_MASK (0x1f << 11)
/*
- * Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL,
- * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE
+ * Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE,
+ * CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE
*/
#define OMAP4430_SAR_MODE_SHIFT 4
-#define OMAP4430_SAR_MODE_MASK BITFIELD(4, 4)
+#define OMAP4430_SAR_MODE_MASK (1 << 4)
/* Used by CM_SCALE_FCLK */
#define OMAP4430_SCALE_FCLK_SHIFT 0
-#define OMAP4430_SCALE_FCLK_MASK BITFIELD(0, 0)
+#define OMAP4430_SCALE_FCLK_MASK (1 << 0)
+
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_SCHEME_SHIFT 30
+#define OMAP4430_SCHEME_MASK (0x3 << 30)
-/* Used by CM_L4CFG_DYNAMICDEP */
+/* Used by CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE */
#define OMAP4430_SDMA_DYNDEP_SHIFT 11
-#define OMAP4430_SDMA_DYNDEP_MASK BITFIELD(11, 11)
+#define OMAP4430_SDMA_DYNDEP_MASK (1 << 11)
/* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP */
#define OMAP4430_SDMA_STATDEP_SHIFT 11
-#define OMAP4430_SDMA_STATDEP_MASK BITFIELD(11, 11)
+#define OMAP4430_SDMA_STATDEP_MASK (1 << 11)
/* Used by CM_CLKSEL_ABE */
#define OMAP4430_SLIMBUS_CLK_GATE_SHIFT 10
-#define OMAP4430_SLIMBUS_CLK_GATE_MASK BITFIELD(10, 10)
+#define OMAP4430_SLIMBUS_CLK_GATE_MASK (1 << 10)
/*
- * Used by CM_EMU_DEBUGSS_CLKCTRL, CM_D2D_SAD2D_CLKCTRL,
- * CM_DUCATI_DUCATI_CLKCTRL, CM_SDMA_SDMA_CLKCTRL, CM_GFX_GFX_CLKCTRL,
- * CM_L4SEC_CRYPTODMA_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
+ * Used by CM1_ABE_AESS_CLKCTRL, CM_CAM_FDIF_CLKCTRL, CM_CAM_ISS_CLKCTRL,
+ * CM_D2D_SAD2D_CLKCTRL, CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL,
+ * CM_DUCATI_DUCATI_CLKCTRL, CM_EMU_DEBUGSS_CLKCTRL, CM_GFX_GFX_CLKCTRL,
+ * CM_IVAHD_IVAHD_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
* CM_L3INIT_HSI_CLKCTRL, CM_L3INIT_MMC1_CLKCTRL, CM_L3INIT_MMC2_CLKCTRL,
* CM_L3INIT_MMC6_CLKCTRL, CM_L3INIT_P1500_CLKCTRL, CM_L3INIT_PCIESS_CLKCTRL,
* CM_L3INIT_SATA_CLKCTRL, CM_L3INIT_TPPSS_CLKCTRL, CM_L3INIT_UNIPRO1_CLKCTRL,
- * CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_FS_CLKCTRL,
- * CM_L3INIT_USB_OTG_CLKCTRL, CM_L3INIT_XHPI_CLKCTRL, CM_CAM_FDIF_CLKCTRL,
- * CM_CAM_ISS_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE,
- * CM_IVAHD_IVAHD_CLKCTRL, CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL,
- * CM_MPU_MPU_CLKCTRL, CM_TESLA_TESLA_CLKCTRL, CM1_ABE_AESS_CLKCTRL
+ * CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE,
+ * CM_L3INIT_USB_HOST_FS_CLKCTRL, CM_L3INIT_USB_OTG_CLKCTRL,
+ * CM_L3INIT_XHPI_CLKCTRL, CM_L4SEC_CRYPTODMA_CLKCTRL, CM_MPU_MPU_CLKCTRL,
+ * CM_SDMA_SDMA_CLKCTRL, CM_TESLA_TESLA_CLKCTRL
*/
#define OMAP4430_STBYST_SHIFT 18
-#define OMAP4430_STBYST_MASK BITFIELD(18, 18)
+#define OMAP4430_STBYST_MASK (1 << 18)
/*
- * Used by CM_IDLEST_DPLL_PER, CM_IDLEST_DPLL_UNIPRO, CM_IDLEST_DPLL_USB,
- * CM_IDLEST_DPLL_ABE, CM_IDLEST_DPLL_CORE, CM_IDLEST_DPLL_DDRPHY,
- * CM_IDLEST_DPLL_IVA, CM_IDLEST_DPLL_MPU
+ * Used by CM_IDLEST_DPLL_ABE, CM_IDLEST_DPLL_CORE, CM_IDLEST_DPLL_DDRPHY,
+ * CM_IDLEST_DPLL_IVA, CM_IDLEST_DPLL_MPU, CM_IDLEST_DPLL_PER,
+ * CM_IDLEST_DPLL_UNIPRO, CM_IDLEST_DPLL_USB
*/
#define OMAP4430_ST_DPLL_CLK_SHIFT 0
-#define OMAP4430_ST_DPLL_CLK_MASK BITFIELD(0, 0)
+#define OMAP4430_ST_DPLL_CLK_MASK (1 << 0)
/* Used by CM_CLKDCOLDO_DPLL_USB */
#define OMAP4430_ST_DPLL_CLKDCOLDO_SHIFT 9
-#define OMAP4430_ST_DPLL_CLKDCOLDO_MASK BITFIELD(9, 9)
+#define OMAP4430_ST_DPLL_CLKDCOLDO_MASK (1 << 9)
/*
- * Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_USB, CM_DIV_M2_DPLL_CORE_RESTORE,
- * CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE, CM_DIV_M2_DPLL_DDRPHY,
- * CM_DIV_M2_DPLL_MPU
+ * Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
+ * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU,
+ * CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_USB
*/
#define OMAP4430_ST_DPLL_CLKOUT_SHIFT 9
-#define OMAP4430_ST_DPLL_CLKOUT_MASK BITFIELD(9, 9)
+#define OMAP4430_ST_DPLL_CLKOUT_MASK (1 << 9)
/*
- * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE,
- * CM_DIV_M3_DPLL_CORE
+ * Used by CM_DIV_M3_DPLL_ABE, CM_DIV_M3_DPLL_CORE,
+ * CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_PER
*/
#define OMAP4430_ST_DPLL_CLKOUTHIF_SHIFT 9
-#define OMAP4430_ST_DPLL_CLKOUTHIF_MASK BITFIELD(9, 9)
+#define OMAP4430_ST_DPLL_CLKOUTHIF_MASK (1 << 9)
-/* Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO, CM_DIV_M2_DPLL_ABE */
+/* Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO */
#define OMAP4430_ST_DPLL_CLKOUTX2_SHIFT 11
-#define OMAP4430_ST_DPLL_CLKOUTX2_MASK BITFIELD(11, 11)
+#define OMAP4430_ST_DPLL_CLKOUTX2_MASK (1 << 11)
/*
- * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE,
- * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA
+ * Used by CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_CORE_RESTORE,
+ * CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA, CM_DIV_M4_DPLL_PER
*/
#define OMAP4430_ST_HSDIVIDER_CLKOUT1_SHIFT 9
-#define OMAP4430_ST_HSDIVIDER_CLKOUT1_MASK BITFIELD(9, 9)
+#define OMAP4430_ST_HSDIVIDER_CLKOUT1_MASK (1 << 9)
/*
- * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE,
- * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA
+ * Used by CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_CORE_RESTORE,
+ * CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA, CM_DIV_M5_DPLL_PER
*/
#define OMAP4430_ST_HSDIVIDER_CLKOUT2_SHIFT 9
-#define OMAP4430_ST_HSDIVIDER_CLKOUT2_MASK BITFIELD(9, 9)
+#define OMAP4430_ST_HSDIVIDER_CLKOUT2_MASK (1 << 9)
/*
- * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE,
- * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY
+ * Used by CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_CORE_RESTORE,
+ * CM_DIV_M6_DPLL_DDRPHY, CM_DIV_M6_DPLL_PER
*/
#define OMAP4430_ST_HSDIVIDER_CLKOUT3_SHIFT 9
-#define OMAP4430_ST_HSDIVIDER_CLKOUT3_MASK BITFIELD(9, 9)
+#define OMAP4430_ST_HSDIVIDER_CLKOUT3_MASK (1 << 9)
/*
- * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE,
- * CM_DIV_M7_DPLL_CORE
+ * Used by CM_DIV_M7_DPLL_CORE, CM_DIV_M7_DPLL_CORE_RESTORE,
+ * CM_DIV_M7_DPLL_PER
*/
#define OMAP4430_ST_HSDIVIDER_CLKOUT4_SHIFT 9
-#define OMAP4430_ST_HSDIVIDER_CLKOUT4_MASK BITFIELD(9, 9)
+#define OMAP4430_ST_HSDIVIDER_CLKOUT4_MASK (1 << 9)
+
+/*
+ * Used by CM_IDLEST_DPLL_ABE, CM_IDLEST_DPLL_CORE, CM_IDLEST_DPLL_DDRPHY,
+ * CM_IDLEST_DPLL_IVA, CM_IDLEST_DPLL_MPU, CM_IDLEST_DPLL_PER,
+ * CM_IDLEST_DPLL_UNIPRO, CM_IDLEST_DPLL_USB
+ */
+#define OMAP4430_ST_MN_BYPASS_SHIFT 8
+#define OMAP4430_ST_MN_BYPASS_MASK (1 << 8)
/* Used by CM_SYS_CLKSEL */
#define OMAP4430_SYS_CLKSEL_SHIFT 0
-#define OMAP4430_SYS_CLKSEL_MASK BITFIELD(0, 2)
+#define OMAP4430_SYS_CLKSEL_MASK (0x7 << 0)
-/* Used by CM_L4CFG_DYNAMICDEP */
+/* Used by CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE */
#define OMAP4430_TESLA_DYNDEP_SHIFT 1
-#define OMAP4430_TESLA_DYNDEP_MASK BITFIELD(1, 1)
+#define OMAP4430_TESLA_DYNDEP_MASK (1 << 1)
/* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP */
#define OMAP4430_TESLA_STATDEP_SHIFT 1
-#define OMAP4430_TESLA_STATDEP_MASK BITFIELD(1, 1)
+#define OMAP4430_TESLA_STATDEP_MASK (1 << 1)
/*
- * Used by CM_EMU_DYNAMICDEP, CM_D2D_DYNAMICDEP, CM_DUCATI_DYNAMICDEP,
- * CM_L3_1_DYNAMICDEP, CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP,
- * CM_L4PER_DYNAMICDEP, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP
+ * Used by CM_D2D_DYNAMICDEP, CM_D2D_DYNAMICDEP_RESTORE, CM_DUCATI_DYNAMICDEP,
+ * CM_EMU_DYNAMICDEP, CM_L3_1_DYNAMICDEP, CM_L3_1_DYNAMICDEP_RESTORE,
+ * CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_L4PER_DYNAMICDEP,
+ * CM_L4PER_DYNAMICDEP_RESTORE, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP
*/
#define OMAP4430_WINDOWSIZE_SHIFT 24
-#define OMAP4430_WINDOWSIZE_MASK BITFIELD(24, 27)
+#define OMAP4430_WINDOWSIZE_MASK (0xf << 24)
+
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_X_MAJOR_SHIFT 8
+#define OMAP4430_X_MAJOR_MASK (0x7 << 8)
+
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_Y_MINOR_SHIFT 0
+#define OMAP4430_Y_MINOR_MASK (0x3f << 0)
#endif
diff --git a/arch/arm/mach-omap2/cm44xx.h b/arch/arm/mach-omap2/cm44xx.h
index 336d94889e5b..3c35a87cb90c 100644
--- a/arch/arm/mach-omap2/cm44xx.h
+++ b/arch/arm/mach-omap2/cm44xx.h
@@ -195,6 +195,42 @@
#define OMAP4_CM1_ABE_WDT3_CLKCTRL_OFFSET 0x0088
#define OMAP4430_CM1_ABE_WDT3_CLKCTRL OMAP44XX_CM1_REGADDR(OMAP4430_CM1_ABE_MOD, 0x0088)
+/* CM1.RESTORE_CM1 register offsets */
+#define OMAP4_CM_CLKSEL_CORE_RESTORE_OFFSET 0x0000
+#define OMAP4430_CM_CLKSEL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0000)
+#define OMAP4_CM_DIV_M2_DPLL_CORE_RESTORE_OFFSET 0x0004
+#define OMAP4430_CM_DIV_M2_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0004)
+#define OMAP4_CM_DIV_M3_DPLL_CORE_RESTORE_OFFSET 0x0008
+#define OMAP4430_CM_DIV_M3_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0008)
+#define OMAP4_CM_DIV_M4_DPLL_CORE_RESTORE_OFFSET 0x000c
+#define OMAP4430_CM_DIV_M4_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x000c)
+#define OMAP4_CM_DIV_M5_DPLL_CORE_RESTORE_OFFSET 0x0010
+#define OMAP4430_CM_DIV_M5_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0010)
+#define OMAP4_CM_DIV_M6_DPLL_CORE_RESTORE_OFFSET 0x0014
+#define OMAP4430_CM_DIV_M6_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0014)
+#define OMAP4_CM_DIV_M7_DPLL_CORE_RESTORE_OFFSET 0x0018
+#define OMAP4430_CM_DIV_M7_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0018)
+#define OMAP4_CM_CLKSEL_DPLL_CORE_RESTORE_OFFSET 0x001c
+#define OMAP4430_CM_CLKSEL_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x001c)
+#define OMAP4_CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE_OFFSET 0x0020
+#define OMAP4430_CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0020)
+#define OMAP4_CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE_OFFSET 0x0024
+#define OMAP4430_CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0024)
+#define OMAP4_CM_CLKMODE_DPLL_CORE_RESTORE_OFFSET 0x0028
+#define OMAP4430_CM_CLKMODE_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0028)
+#define OMAP4_CM_SHADOW_FREQ_CONFIG2_RESTORE_OFFSET 0x002c
+#define OMAP4430_CM_SHADOW_FREQ_CONFIG2_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x002c)
+#define OMAP4_CM_SHADOW_FREQ_CONFIG1_RESTORE_OFFSET 0x0030
+#define OMAP4430_CM_SHADOW_FREQ_CONFIG1_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0030)
+#define OMAP4_CM_AUTOIDLE_DPLL_CORE_RESTORE_OFFSET 0x0034
+#define OMAP4430_CM_AUTOIDLE_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0034)
+#define OMAP4_CM_MPU_CLKSTCTRL_RESTORE_OFFSET 0x0038
+#define OMAP4430_CM_MPU_CLKSTCTRL_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0038)
+#define OMAP4_CM_CM1_PROFILING_CLKCTRL_RESTORE_OFFSET 0x003c
+#define OMAP4430_CM_CM1_PROFILING_CLKCTRL_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x003c)
+#define OMAP4_CM_DYN_DEP_PRESCAL_RESTORE_OFFSET 0x0040
+#define OMAP4430_CM_DYN_DEP_PRESCAL_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0040)
+
/* CM2 */
/* CM2.OCP_SOCKET_CM2 register offsets */
@@ -252,8 +288,6 @@
#define OMAP4430_CM_SSC_DELTAMSTEP_DPLL_PER OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_MOD, 0x0068)
#define OMAP4_CM_SSC_MODFREQDIV_DPLL_PER_OFFSET 0x006c
#define OMAP4430_CM_SSC_MODFREQDIV_DPLL_PER OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_MOD, 0x006c)
-#define OMAP4_CM_EMU_OVERRIDE_DPLL_PER_OFFSET 0x0070
-#define OMAP4430_CM_EMU_OVERRIDE_DPLL_PER OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_MOD, 0x0070)
#define OMAP4_CM_CLKMODE_DPLL_USB_OFFSET 0x0080
#define OMAP4430_CM_CLKMODE_DPLL_USB OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_MOD, 0x0080)
#define OMAP4_CM_IDLEST_DPLL_USB_OFFSET 0x0084
@@ -296,6 +330,8 @@
#define OMAP4430_CM_ALWON_SR_IVA_CLKCTRL OMAP44XX_CM2_REGADDR(OMAP4430_CM2_ALWAYS_ON_MOD, 0x0030)
#define OMAP4_CM_ALWON_SR_CORE_CLKCTRL_OFFSET 0x0038
#define OMAP4430_CM_ALWON_SR_CORE_CLKCTRL OMAP44XX_CM2_REGADDR(OMAP4430_CM2_ALWAYS_ON_MOD, 0x0038)
+#define OMAP4_CM_ALWON_USBPHY_CLKCTRL_OFFSET 0x0040
+#define OMAP4430_CM_ALWON_USBPHY_CLKCTRL OMAP44XX_CM2_REGADDR(OMAP4430_CM2_ALWAYS_ON_MOD, 0x0040)
/* CM2.CORE_CM2 register offsets */
#define OMAP4_CM_L3_1_CLKSTCTRL_OFFSET 0x0000
@@ -578,4 +614,54 @@
#define OMAP4430_CM_CEFUSE_CLKSTCTRL OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CEFUSE_MOD, 0x0000)
#define OMAP4_CM_CEFUSE_CEFUSE_CLKCTRL_OFFSET 0x0020
#define OMAP4430_CM_CEFUSE_CEFUSE_CLKCTRL OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CEFUSE_MOD, 0x0020)
+
+/* CM2.RESTORE_CM2 register offsets */
+#define OMAP4_CM_L3_1_CLKSTCTRL_RESTORE_OFFSET 0x0000
+#define OMAP4430_CM_L3_1_CLKSTCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0000)
+#define OMAP4_CM_L3_2_CLKSTCTRL_RESTORE_OFFSET 0x0004
+#define OMAP4430_CM_L3_2_CLKSTCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0004)
+#define OMAP4_CM_L4CFG_CLKSTCTRL_RESTORE_OFFSET 0x0008
+#define OMAP4430_CM_L4CFG_CLKSTCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0008)
+#define OMAP4_CM_MEMIF_CLKSTCTRL_RESTORE_OFFSET 0x000c
+#define OMAP4430_CM_MEMIF_CLKSTCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x000c)
+#define OMAP4_CM_L4PER_CLKSTCTRL_RESTORE_OFFSET 0x0010
+#define OMAP4430_CM_L4PER_CLKSTCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0010)
+#define OMAP4_CM_L3INIT_CLKSTCTRL_RESTORE_OFFSET 0x0014
+#define OMAP4430_CM_L3INIT_CLKSTCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0014)
+#define OMAP4_CM_L3INSTR_L3_3_CLKCTRL_RESTORE_OFFSET 0x0018
+#define OMAP4430_CM_L3INSTR_L3_3_CLKCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0018)
+#define OMAP4_CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE_OFFSET 0x001c
+#define OMAP4430_CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x001c)
+#define OMAP4_CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE_OFFSET 0x0020
+#define OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0020)
+#define OMAP4_CM_CM2_PROFILING_CLKCTRL_RESTORE_OFFSET 0x0024
+#define OMAP4430_CM_CM2_PROFILING_CLKCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0024)
+#define OMAP4_CM_D2D_STATICDEP_RESTORE_OFFSET 0x0028
+#define OMAP4430_CM_D2D_STATICDEP_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0028)
+#define OMAP4_CM_L3_1_DYNAMICDEP_RESTORE_OFFSET 0x002c
+#define OMAP4430_CM_L3_1_DYNAMICDEP_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x002c)
+#define OMAP4_CM_L3_2_DYNAMICDEP_RESTORE_OFFSET 0x0030
+#define OMAP4430_CM_L3_2_DYNAMICDEP_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0030)
+#define OMAP4_CM_D2D_DYNAMICDEP_RESTORE_OFFSET 0x0034
+#define OMAP4430_CM_D2D_DYNAMICDEP_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0034)
+#define OMAP4_CM_L4CFG_DYNAMICDEP_RESTORE_OFFSET 0x0038
+#define OMAP4430_CM_L4CFG_DYNAMICDEP_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0038)
+#define OMAP4_CM_L4PER_DYNAMICDEP_RESTORE_OFFSET 0x003c
+#define OMAP4430_CM_L4PER_DYNAMICDEP_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x003c)
+#define OMAP4_CM_L4PER_GPIO2_CLKCTRL_RESTORE_OFFSET 0x0040
+#define OMAP4430_CM_L4PER_GPIO2_CLKCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0040)
+#define OMAP4_CM_L4PER_GPIO3_CLKCTRL_RESTORE_OFFSET 0x0044
+#define OMAP4430_CM_L4PER_GPIO3_CLKCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0044)
+#define OMAP4_CM_L4PER_GPIO4_CLKCTRL_RESTORE_OFFSET 0x0048
+#define OMAP4430_CM_L4PER_GPIO4_CLKCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0048)
+#define OMAP4_CM_L4PER_GPIO5_CLKCTRL_RESTORE_OFFSET 0x004c
+#define OMAP4430_CM_L4PER_GPIO5_CLKCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x004c)
+#define OMAP4_CM_L4PER_GPIO6_CLKCTRL_RESTORE_OFFSET 0x0050
+#define OMAP4430_CM_L4PER_GPIO6_CLKCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0050)
+#define OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_RESTORE_OFFSET 0x0054
+#define OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0054)
+#define OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_RESTORE_OFFSET 0x0058
+#define OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0058)
+#define OMAP4_CM_SDMA_STATICDEP_RESTORE_OFFSET 0x005c
+#define OMAP4430_CM_SDMA_STATICDEP_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x005c)
#endif
diff --git a/arch/arm/mach-omap2/cm4xxx.c b/arch/arm/mach-omap2/cm4xxx.c
index b101091e95d6..f8a660a1a4a6 100644
--- a/arch/arm/mach-omap2/cm4xxx.c
+++ b/arch/arm/mach-omap2/cm4xxx.c
@@ -43,7 +43,6 @@
* using separate functional clock
* 0x3 disabled: Module is disabled and cannot be accessed
*
- * TODO: Need to handle module accessible in idle state
*/
int omap4_cm_wait_module_ready(void __iomem *clkctrl_reg)
{
@@ -52,9 +51,11 @@ int omap4_cm_wait_module_ready(void __iomem *clkctrl_reg)
if (!clkctrl_reg)
return 0;
- omap_test_timeout(((__raw_readl(clkctrl_reg) &
- OMAP4430_IDLEST_MASK) == 0),
- MAX_MODULE_READY_TIME, i);
+ omap_test_timeout((
+ ((__raw_readl(clkctrl_reg) & OMAP4430_IDLEST_MASK) == 0) ||
+ (((__raw_readl(clkctrl_reg) & OMAP4430_IDLEST_MASK) >>
+ OMAP4430_IDLEST_SHIFT) == 0x2)),
+ MAX_MODULE_READY_TIME, i);
return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
}
diff --git a/arch/arm/mach-omap2/common.c b/arch/arm/mach-omap2/common.c
new file mode 100644
index 000000000000..778929f7e92d
--- /dev/null
+++ b/arch/arm/mach-omap2/common.c
@@ -0,0 +1,135 @@
+/*
+ * linux/arch/arm/mach-omap2/common.c
+ *
+ * Code common to all OMAP2+ machines.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Copyright (C) 2010 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@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.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <plat/common.h>
+#include <plat/board.h>
+#include <plat/mux.h>
+
+#include <plat/clock.h>
+
+#include "sdrc.h"
+#include "control.h"
+
+/* Global address base setup code */
+
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+
+static void __init __omap2_set_globals(struct omap_globals *omap2_globals)
+{
+ omap2_set_globals_tap(omap2_globals);
+ omap2_set_globals_sdrc(omap2_globals);
+ omap2_set_globals_control(omap2_globals);
+ omap2_set_globals_prcm(omap2_globals);
+}
+
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2420)
+
+static struct omap_globals omap242x_globals = {
+ .class = OMAP242X_CLASS,
+ .tap = OMAP2_L4_IO_ADDRESS(0x48014000),
+ .sdrc = OMAP2420_SDRC_BASE,
+ .sms = OMAP2420_SMS_BASE,
+ .ctrl = OMAP242X_CTRL_BASE,
+ .prm = OMAP2420_PRM_BASE,
+ .cm = OMAP2420_CM_BASE,
+ .uart1_phys = OMAP2_UART1_BASE,
+ .uart2_phys = OMAP2_UART2_BASE,
+ .uart3_phys = OMAP2_UART3_BASE,
+};
+
+void __init omap2_set_globals_242x(void)
+{
+ __omap2_set_globals(&omap242x_globals);
+}
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2430)
+
+static struct omap_globals omap243x_globals = {
+ .class = OMAP243X_CLASS,
+ .tap = OMAP2_L4_IO_ADDRESS(0x4900a000),
+ .sdrc = OMAP243X_SDRC_BASE,
+ .sms = OMAP243X_SMS_BASE,
+ .ctrl = OMAP243X_CTRL_BASE,
+ .prm = OMAP2430_PRM_BASE,
+ .cm = OMAP2430_CM_BASE,
+ .uart1_phys = OMAP2_UART1_BASE,
+ .uart2_phys = OMAP2_UART2_BASE,
+ .uart3_phys = OMAP2_UART3_BASE,
+};
+
+void __init omap2_set_globals_243x(void)
+{
+ __omap2_set_globals(&omap243x_globals);
+}
+#endif
+
+#if defined(CONFIG_ARCH_OMAP3)
+
+static struct omap_globals omap3_globals = {
+ .class = OMAP343X_CLASS,
+ .tap = OMAP2_L4_IO_ADDRESS(0x4830A000),
+ .sdrc = OMAP343X_SDRC_BASE,
+ .sms = OMAP343X_SMS_BASE,
+ .ctrl = OMAP343X_CTRL_BASE,
+ .prm = OMAP3430_PRM_BASE,
+ .cm = OMAP3430_CM_BASE,
+ .uart1_phys = OMAP3_UART1_BASE,
+ .uart2_phys = OMAP3_UART2_BASE,
+ .uart3_phys = OMAP3_UART3_BASE,
+ .uart4_phys = OMAP3_UART4_BASE, /* Only on 3630 */
+};
+
+void __init omap2_set_globals_3xxx(void)
+{
+ __omap2_set_globals(&omap3_globals);
+}
+
+void __init omap3_map_io(void)
+{
+ omap2_set_globals_3xxx();
+ omap34xx_map_common_io();
+}
+#endif
+
+#if defined(CONFIG_ARCH_OMAP4)
+static struct omap_globals omap4_globals = {
+ .class = OMAP443X_CLASS,
+ .tap = OMAP2_L4_IO_ADDRESS(OMAP443X_SCM_BASE),
+ .ctrl = OMAP443X_SCM_BASE,
+ .ctrl_pad = OMAP443X_CTRL_BASE,
+ .prm = OMAP4430_PRM_BASE,
+ .cm = OMAP4430_CM_BASE,
+ .cm2 = OMAP4430_CM2_BASE,
+ .uart1_phys = OMAP4_UART1_BASE,
+ .uart2_phys = OMAP4_UART2_BASE,
+ .uart3_phys = OMAP4_UART3_BASE,
+ .uart4_phys = OMAP4_UART4_BASE,
+};
+
+void __init omap2_set_globals_443x(void)
+{
+ omap2_set_globals_tap(&omap4_globals);
+ omap2_set_globals_control(&omap4_globals);
+ omap2_set_globals_prcm(&omap4_globals);
+}
+#endif
+
diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
index a8d20eef2306..1fa3294b6048 100644
--- a/arch/arm/mach-omap2/control.c
+++ b/arch/arm/mach-omap2/control.c
@@ -16,15 +16,18 @@
#include <linux/io.h>
#include <plat/common.h>
-#include <plat/control.h>
#include <plat/sdrc.h>
+
#include "cm-regbits-34xx.h"
#include "prm-regbits-34xx.h"
#include "cm.h"
#include "prm.h"
#include "sdrc.h"
+#include "pm.h"
+#include "control.h"
static void __iomem *omap2_ctrl_base;
+static void __iomem *omap4_ctrl_pad_base;
#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
struct omap3_scratchpad {
@@ -137,6 +140,7 @@ static struct omap3_control_regs control_context;
#endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */
#define OMAP_CTRL_REGADDR(reg) (omap2_ctrl_base + (reg))
+#define OMAP4_CTRL_PAD_REGADDR(reg) (omap4_ctrl_pad_base + (reg))
void __init omap2_set_globals_control(struct omap_globals *omap2_globals)
{
@@ -145,6 +149,12 @@ void __init omap2_set_globals_control(struct omap_globals *omap2_globals)
omap2_ctrl_base = ioremap(omap2_globals->ctrl, SZ_4K);
WARN_ON(!omap2_ctrl_base);
}
+
+ /* Static mapping, never released */
+ if (omap2_globals->ctrl_pad) {
+ omap4_ctrl_pad_base = ioremap(omap2_globals->ctrl_pad, SZ_4K);
+ WARN_ON(!omap4_ctrl_pad_base);
+ }
}
void __iomem *omap_ctrl_base_get(void)
@@ -182,6 +192,23 @@ void omap_ctrl_writel(u32 val, u16 offset)
__raw_writel(val, OMAP_CTRL_REGADDR(offset));
}
+/*
+ * On OMAP4 control pad are not addressable from control
+ * core base. So the common omap_ctrl_read/write APIs breaks
+ * Hence export separate APIs to manage the omap4 pad control
+ * registers. This APIs will work only for OMAP4
+ */
+
+u32 omap4_ctrl_pad_readl(u16 offset)
+{
+ return __raw_readl(OMAP4_CTRL_PAD_REGADDR(offset));
+}
+
+void omap4_ctrl_pad_writel(u32 val, u16 offset)
+{
+ __raw_writel(val, OMAP4_CTRL_PAD_REGADDR(offset));
+}
+
#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
/*
* Clears the scratchpad contents in case of cold boot-
@@ -190,7 +217,7 @@ void omap_ctrl_writel(u32 val, u16 offset)
void omap3_clear_scratchpad_contents(void)
{
u32 max_offset = OMAP343X_SCRATCHPAD_ROM_OFFSET;
- u32 *v_addr;
+ void __iomem *v_addr;
u32 offset = 0;
v_addr = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD_ROM);
if (prm_read_mod_reg(OMAP3430_GR_MOD, OMAP3_PRM_RSTST_OFFSET) &
@@ -206,7 +233,7 @@ void omap3_clear_scratchpad_contents(void)
/* Populate the scratchpad structure with restore structure */
void omap3_save_scratchpad_contents(void)
{
- void * __iomem scratchpad_address;
+ void __iomem *scratchpad_address;
u32 arm_context_addr;
struct omap3_scratchpad scratchpad_contents;
struct omap3_scratchpad_prcm_block prcm_block_contents;
diff --git a/arch/arm/plat-omap/include/plat/control.h b/arch/arm/mach-omap2/control.h
index 131bf405c2f6..b6c6b7c450b3 100644
--- a/arch/arm/plat-omap/include/plat/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -1,10 +1,10 @@
/*
- * arch/arm/plat-omap/include/mach/control.h
+ * arch/arm/mach-omap2/control.h
*
* OMAP2/3/4 System Control Module definitions
*
- * Copyright (C) 2007-2009 Texas Instruments, Inc.
- * Copyright (C) 2007-2008 Nokia Corporation
+ * Copyright (C) 2007-2010 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008, 2010 Nokia Corporation
*
* Written by Paul Walmsley
*
@@ -13,10 +13,14 @@
* the Free Software Foundation.
*/
-#ifndef __ASM_ARCH_CONTROL_H
-#define __ASM_ARCH_CONTROL_H
+#ifndef __ARCH_ARM_MACH_OMAP2_CONTROL_H
+#define __ARCH_ARM_MACH_OMAP2_CONTROL_H
#include <mach/io.h>
+#include <mach/ctrl_module_core_44xx.h>
+#include <mach/ctrl_module_wkup_44xx.h>
+#include <mach/ctrl_module_pad_core_44xx.h>
+#include <mach/ctrl_module_pad_wkup_44xx.h>
#ifndef __ASSEMBLY__
#define OMAP242X_CTRL_REGADDR(reg) \
@@ -204,12 +208,6 @@
#define OMAP3_PADCONF_SAD2D_MSTANDBY 0x250
#define OMAP3_PADCONF_SAD2D_IDLEACK 0x254
-/* 44xx control status register offset */
-#define OMAP44XX_CONTROL_STATUS 0x2c4
-
-/* 44xx-only CONTROL_GENERAL register offsets */
-#define OMAP44XX_CONTROL_MMC1 0x628
-#define OMAP44XX_CONTROL_PBIAS_LITE 0x600
/*
* REVISIT: This list of registers is not comprehensive - there are more
* that should be added.
@@ -225,6 +223,8 @@
#define OMAP2_MMCSDIO1ADPCLKISEL (1 << 24) /* MMC1 loop back clock */
#define OMAP24XX_USBSTANDBYCTRL (1 << 15)
#define OMAP2_MCBSP2_CLKS_MASK (1 << 6)
+#define OMAP2_MCBSP1_FSR_MASK (1 << 4)
+#define OMAP2_MCBSP1_CLKR_MASK (1 << 3)
#define OMAP2_MCBSP1_CLKS_MASK (1 << 2)
/* CONTROL_DEVCONF1 bits */
@@ -255,23 +255,6 @@
#define OMAP2_PBIASLITEPWRDNZ0 (1 << 1)
#define OMAP2_PBIASLITEVMODE0 (1 << 0)
-/* CONTROL_PBIAS_LITE bits for OMAP4 */
-#define OMAP4_MMC1_PWRDNZ (1 << 26)
-#define OMAP4_MMC1_PBIASLITE_HIZ_MODE (1 << 25)
-#define OMAP4_MMC1_PBIASLITE_SUPPLY_HI_OUT (1 << 24)
-#define OMAP4_MMC1_PBIASLITE_VMODE_ERROR (1 << 23)
-#define OMAP4_MMC1_PBIASLITE_PWRDNZ (1 << 22)
-#define OMAP4_MMC1_PBIASLITE_VMODE (1 << 21)
-#define OMAP4_USBC1_ICUSB_PWRDNZ (1 << 20)
-
-#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP0 (1 << 31)
-#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP1 (1 << 30)
-#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP2 (1 << 29)
-#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP3 (1 << 28)
-#define OMAP4_CONTROL_SDMMC1_DR0_SPEEDCTRL (1 << 27)
-#define OMAP4_CONTROL_SDMMC1_DR1_SPEEDCTRL (1 << 26)
-#define OMAP4_CONTROL_SDMMC1_DR2_SPEEDCTRL (1 << 25)
-
/* CONTROL_PROG_IO1 bits */
#define OMAP3630_PRG_SDMMC1_SPEEDCTRL (1 << 20)
@@ -338,12 +321,12 @@
#define FEAT_L2CACHE_256KB 3
#define OMAP3_ISP_SHIFT 5
-#define OMAP3_ISP_MASK (1<< OMAP3_ISP_SHIFT)
+#define OMAP3_ISP_MASK (1 << OMAP3_ISP_SHIFT)
#define FEAT_ISP 0
#define FEAT_ISP_NONE 1
#define OMAP3_NEON_SHIFT 4
-#define OMAP3_NEON_MASK (1<< OMAP3_NEON_SHIFT)
+#define OMAP3_NEON_MASK (1 << OMAP3_NEON_SHIFT)
#define FEAT_NEON 0
#define FEAT_NEON_NONE 1
@@ -354,9 +337,11 @@ extern void __iomem *omap_ctrl_base_get(void);
extern u8 omap_ctrl_readb(u16 offset);
extern u16 omap_ctrl_readw(u16 offset);
extern u32 omap_ctrl_readl(u16 offset);
+extern u32 omap4_ctrl_pad_readl(u16 offset);
extern void omap_ctrl_writeb(u8 val, u16 offset);
extern void omap_ctrl_writew(u16 val, u16 offset);
extern void omap_ctrl_writel(u32 val, u16 offset);
+extern void omap4_ctrl_pad_writel(u32 val, u16 offset);
extern void omap3_save_scratchpad_contents(void);
extern void omap3_clear_scratchpad_contents(void);
@@ -371,11 +356,13 @@ extern void omap3_control_restore_context(void);
#define omap_ctrl_readb(x) 0
#define omap_ctrl_readw(x) 0
#define omap_ctrl_readl(x) 0
+#define omap4_ctrl_pad_readl(x) 0
#define omap_ctrl_writeb(x, y) WARN_ON(1)
#define omap_ctrl_writew(x, y) WARN_ON(1)
#define omap_ctrl_writel(x, y) WARN_ON(1)
+#define omap4_ctrl_pad_writel(x, y) WARN_ON(1)
#endif
#endif /* __ASSEMBLY__ */
-#endif /* __ASM_ARCH_CONTROL_H */
+#endif /* __ARCH_ARM_MACH_OMAP2_CONTROL_H */
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 3d3d035db9af..0d50b45d041c 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -29,10 +29,10 @@
#include <plat/irqs.h>
#include <plat/powerdomain.h>
#include <plat/clockdomain.h>
-#include <plat/control.h>
#include <plat/serial.h>
#include "pm.h"
+#include "control.h"
#ifdef CONFIG_CPU_IDLE
@@ -60,7 +60,8 @@ struct omap3_processor_cx {
struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES];
struct omap3_processor_cx current_cx_state;
-struct powerdomain *mpu_pd, *core_pd;
+struct powerdomain *mpu_pd, *core_pd, *per_pd;
+struct powerdomain *cam_pd;
/*
* The latencies/thresholds for various C states have
@@ -233,14 +234,60 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
struct cpuidle_state *state)
{
struct cpuidle_state *new_state = next_valid_state(dev, state);
+ u32 core_next_state, per_next_state = 0, per_saved_state = 0;
+ u32 cam_state;
+ struct omap3_processor_cx *cx;
+ int ret;
if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) {
BUG_ON(!dev->safe_state);
new_state = dev->safe_state;
+ goto select_state;
}
+ cx = cpuidle_get_statedata(state);
+ core_next_state = cx->core_state;
+
+ /*
+ * FIXME: we currently manage device-specific idle states
+ * for PER and CORE in combination with CPU-specific
+ * idle states. This is wrong, and device-specific
+ * idle managment needs to be separated out into
+ * its own code.
+ */
+
+ /*
+ * Prevent idle completely if CAM is active.
+ * CAM does not have wakeup capability in OMAP3.
+ */
+ cam_state = pwrdm_read_pwrst(cam_pd);
+ if (cam_state == PWRDM_POWER_ON) {
+ new_state = dev->safe_state;
+ goto select_state;
+ }
+
+ /*
+ * Prevent PER off if CORE is not in retention or off as this
+ * would disable PER wakeups completely.
+ */
+ per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
+ if ((per_next_state == PWRDM_POWER_OFF) &&
+ (core_next_state > PWRDM_POWER_RET))
+ per_next_state = PWRDM_POWER_RET;
+
+ /* Are we changing PER target state? */
+ if (per_next_state != per_saved_state)
+ pwrdm_set_next_pwrst(per_pd, per_next_state);
+
+select_state:
dev->last_state = new_state;
- return omap3_enter_idle(dev, new_state);
+ ret = omap3_enter_idle(dev, new_state);
+
+ /* Restore original PER state if it was modified */
+ if (per_next_state != per_saved_state)
+ pwrdm_set_next_pwrst(per_pd, per_saved_state);
+
+ return ret;
}
DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
@@ -328,7 +375,8 @@ void omap_init_power_states(void)
cpuidle_params_table[OMAP3_STATE_C2].threshold;
omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON;
omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON;
- omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID;
+ omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID |
+ CPUIDLE_FLAG_CHECK_BM;
/* C3 . MPU CSWR + Core inactive */
omap3_power_states[OMAP3_STATE_C3].valid =
@@ -426,6 +474,8 @@ int __init omap3_idle_init(void)
mpu_pd = pwrdm_lookup("mpu_pwrdm");
core_pd = pwrdm_lookup("core_pwrdm");
+ per_pd = pwrdm_lookup("per_pwrdm");
+ cam_pd = pwrdm_lookup("cam_pwrdm");
omap_init_power_states();
cpuidle_register_driver(&omap3_idle_driver);
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 2dbb265bedd4..5a0c148e23bc 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -9,12 +9,12 @@
* (at your option) any later version.
*/
-#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/clk.h>
+#include <linux/err.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
@@ -22,14 +22,17 @@
#include <asm/mach/map.h>
#include <asm/pmu.h>
-#include <plat/control.h>
#include <plat/tc.h>
#include <plat/board.h>
+#include <plat/mcbsp.h>
#include <mach/gpio.h>
#include <plat/mmc.h>
#include <plat/dma.h>
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
#include "mux.h"
+#include "control.h"
#if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
@@ -235,6 +238,43 @@ static inline void omap_init_mbox(void) { }
static inline void omap_init_sti(void) {}
+#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
+
+static struct platform_device omap_pcm = {
+ .name = "omap-pcm-audio",
+ .id = -1,
+};
+
+/*
+ * OMAP2420 has 2 McBSP ports
+ * OMAP2430 has 5 McBSP ports
+ * OMAP3 has 5 McBSP ports
+ * OMAP4 has 4 McBSP ports
+ */
+OMAP_MCBSP_PLATFORM_DEVICE(1);
+OMAP_MCBSP_PLATFORM_DEVICE(2);
+OMAP_MCBSP_PLATFORM_DEVICE(3);
+OMAP_MCBSP_PLATFORM_DEVICE(4);
+OMAP_MCBSP_PLATFORM_DEVICE(5);
+
+static void omap_init_audio(void)
+{
+ platform_device_register(&omap_mcbsp1);
+ platform_device_register(&omap_mcbsp2);
+ if (cpu_is_omap243x() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
+ platform_device_register(&omap_mcbsp3);
+ platform_device_register(&omap_mcbsp4);
+ }
+ if (cpu_is_omap243x() || cpu_is_omap34xx())
+ platform_device_register(&omap_mcbsp5);
+
+ platform_device_register(&omap_pcm);
+}
+
+#else
+static inline void omap_init_audio(void) {}
+#endif
+
#if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
#include <plat/mcspi.h>
@@ -498,6 +538,76 @@ static void omap_init_sham(void)
static inline void omap_init_sham(void) { }
#endif
+#if defined(CONFIG_CRYPTO_DEV_OMAP_AES) || defined(CONFIG_CRYPTO_DEV_OMAP_AES_MODULE)
+
+#ifdef CONFIG_ARCH_OMAP2
+static struct resource omap2_aes_resources[] = {
+ {
+ .start = OMAP24XX_SEC_AES_BASE,
+ .end = OMAP24XX_SEC_AES_BASE + 0x4C,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = OMAP24XX_DMA_AES_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .start = OMAP24XX_DMA_AES_RX,
+ .flags = IORESOURCE_DMA,
+ }
+};
+static int omap2_aes_resources_sz = ARRAY_SIZE(omap2_aes_resources);
+#else
+#define omap2_aes_resources NULL
+#define omap2_aes_resources_sz 0
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+static struct resource omap3_aes_resources[] = {
+ {
+ .start = OMAP34XX_SEC_AES_BASE,
+ .end = OMAP34XX_SEC_AES_BASE + 0x4C,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = OMAP34XX_DMA_AES2_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .start = OMAP34XX_DMA_AES2_RX,
+ .flags = IORESOURCE_DMA,
+ }
+};
+static int omap3_aes_resources_sz = ARRAY_SIZE(omap3_aes_resources);
+#else
+#define omap3_aes_resources NULL
+#define omap3_aes_resources_sz 0
+#endif
+
+static struct platform_device aes_device = {
+ .name = "omap-aes",
+ .id = -1,
+};
+
+static void omap_init_aes(void)
+{
+ if (cpu_is_omap24xx()) {
+ aes_device.resource = omap2_aes_resources;
+ aes_device.num_resources = omap2_aes_resources_sz;
+ } else if (cpu_is_omap34xx()) {
+ aes_device.resource = omap3_aes_resources;
+ aes_device.num_resources = omap3_aes_resources_sz;
+ } else {
+ pr_err("%s: platform not supported\n", __func__);
+ return;
+ }
+ platform_device_register(&aes_device);
+}
+
+#else
+static inline void omap_init_aes(void) { }
+#endif
+
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
@@ -624,7 +734,7 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
omap_mux_init_signal("sdmmc_dat0", 0);
omap_mux_init_signal("sdmmc_dat_dir0", 0);
omap_mux_init_signal("sdmmc_cmd_dir", 0);
- if (mmc_controller->slots[0].wires == 4) {
+ if (mmc_controller->slots[0].caps & MMC_CAP_4_BIT_DATA) {
omap_mux_init_signal("sdmmc_dat1", 0);
omap_mux_init_signal("sdmmc_dat2", 0);
omap_mux_init_signal("sdmmc_dat3", 0);
@@ -652,8 +762,8 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("sdmmc1_dat0",
OMAP_PIN_INPUT_PULLUP);
- if (mmc_controller->slots[0].wires == 4 ||
- mmc_controller->slots[0].wires == 8) {
+ if (mmc_controller->slots[0].caps &
+ (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) {
omap_mux_init_signal("sdmmc1_dat1",
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("sdmmc1_dat2",
@@ -661,7 +771,8 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
omap_mux_init_signal("sdmmc1_dat3",
OMAP_PIN_INPUT_PULLUP);
}
- if (mmc_controller->slots[0].wires == 8) {
+ if (mmc_controller->slots[0].caps &
+ MMC_CAP_8_BIT_DATA) {
omap_mux_init_signal("sdmmc1_dat4",
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("sdmmc1_dat5",
@@ -685,8 +796,8 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
* For 8 wire configurations, Lines DAT4, 5, 6 and 7 need to be muxed
* in the board-*.c files
*/
- if (mmc_controller->slots[0].wires == 4 ||
- mmc_controller->slots[0].wires == 8) {
+ if (mmc_controller->slots[0].caps &
+ (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) {
omap_mux_init_signal("sdmmc2_dat1",
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("sdmmc2_dat2",
@@ -694,7 +805,8 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
omap_mux_init_signal("sdmmc2_dat3",
OMAP_PIN_INPUT_PULLUP);
}
- if (mmc_controller->slots[0].wires == 8) {
+ if (mmc_controller->slots[0].caps &
+ MMC_CAP_8_BIT_DATA) {
omap_mux_init_signal("sdmmc2_dat4.sdmmc2_dat4",
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("sdmmc2_dat5.sdmmc2_dat5",
@@ -745,13 +857,13 @@ void __init omap2_init_mmc(struct omap_mmc_platform_data **mmc_data,
case 3:
if (!cpu_is_omap44xx())
return;
- base = OMAP4_MMC4_BASE + OMAP4_MMC_REG_OFFSET;
+ base = OMAP4_MMC4_BASE;
irq = OMAP44XX_IRQ_MMC4;
break;
case 4:
if (!cpu_is_omap44xx())
return;
- base = OMAP4_MMC5_BASE + OMAP4_MMC_REG_OFFSET;
+ base = OMAP4_MMC5_BASE;
irq = OMAP44XX_IRQ_MMC5;
break;
default:
@@ -762,10 +874,8 @@ void __init omap2_init_mmc(struct omap_mmc_platform_data **mmc_data,
size = OMAP2420_MMC_SIZE;
name = "mmci-omap";
} else if (cpu_is_omap44xx()) {
- if (i < 3) {
- base += OMAP4_MMC_REG_OFFSET;
+ if (i < 3)
irq += OMAP44XX_IRQ_GIC_START;
- }
size = OMAP4_HSMMC_SIZE;
name = "mmci-omap-hs";
} else {
@@ -841,12 +951,74 @@ static inline void omap_init_vout(void) {}
/*-------------------------------------------------------------------------*/
+/*
+ * Inorder to avoid any assumptions from bootloader regarding WDT
+ * settings, WDT module is reset during init. This enables the watchdog
+ * timer. Hence it is required to disable the watchdog after the WDT reset
+ * during init. Otherwise the system would reboot as per the default
+ * watchdog timer registers settings.
+ */
+#define OMAP_WDT_WPS (0x34)
+#define OMAP_WDT_SPR (0x48)
+
+static int omap2_disable_wdt(struct omap_hwmod *oh, void *unused)
+{
+ void __iomem *base;
+ int ret;
+
+ if (!oh) {
+ pr_err("%s: Could not look up wdtimer_hwmod\n", __func__);
+ return -EINVAL;
+ }
+
+ base = omap_hwmod_get_mpu_rt_va(oh);
+ if (!base) {
+ pr_err("%s: Could not get the base address for %s\n",
+ oh->name, __func__);
+ return -EINVAL;
+ }
+
+ /* Enable the clocks before accessing the WDT registers */
+ ret = omap_hwmod_enable(oh);
+ if (ret) {
+ pr_err("%s: Could not enable clocks for %s\n",
+ oh->name, __func__);
+ return ret;
+ }
+
+ /* sequence required to disable watchdog */
+ __raw_writel(0xAAAA, base + OMAP_WDT_SPR);
+ while (__raw_readl(base + OMAP_WDT_WPS) & 0x10)
+ cpu_relax();
+
+ __raw_writel(0x5555, base + OMAP_WDT_SPR);
+ while (__raw_readl(base + OMAP_WDT_WPS) & 0x10)
+ cpu_relax();
+
+ ret = omap_hwmod_idle(oh);
+ if (ret)
+ pr_err("%s: Could not disable clocks for %s\n",
+ oh->name, __func__);
+
+ return ret;
+}
+
+static void __init omap_disable_wdt(void)
+{
+ if (cpu_class_is_omap2())
+ omap_hwmod_for_each_by_class("wd_timer",
+ omap2_disable_wdt, NULL);
+ return;
+}
+
static int __init omap2_init_devices(void)
{
/* please keep these calls, and their implementations above,
* in alphabetical order so they're easier to sort through.
*/
+ omap_disable_wdt();
omap_hsmmc_reset();
+ omap_init_audio();
omap_init_camera();
omap_init_mbox();
omap_init_mcspi();
@@ -854,8 +1026,45 @@ static int __init omap2_init_devices(void)
omap_hdq_init();
omap_init_sti();
omap_init_sham();
+ omap_init_aes();
omap_init_vout();
return 0;
}
arch_initcall(omap2_init_devices);
+
+#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
+struct omap_device_pm_latency omap_wdt_latency[] = {
+ [0] = {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ },
+};
+
+static int __init omap_init_wdt(void)
+{
+ int id = -1;
+ struct omap_device *od;
+ struct omap_hwmod *oh;
+ char *oh_name = "wd_timer2";
+ char *dev_name = "omap_wdt";
+
+ if (!cpu_class_is_omap2())
+ return 0;
+
+ oh = omap_hwmod_lookup(oh_name);
+ if (!oh) {
+ pr_err("Could not look up wd_timer%d hwmod\n", id);
+ return -EINVAL;
+ }
+
+ od = omap_device_build(dev_name, id, oh, NULL, 0,
+ omap_wdt_latency,
+ ARRAY_SIZE(omap_wdt_latency), 0);
+ WARN(IS_ERR(od), "Cant build omap_device for %s:%s.\n",
+ dev_name, oh->name);
+ return 0;
+}
+subsys_initcall(omap_init_wdt);
+#endif
diff --git a/arch/arm/mach-omap2/gpmc-smsc911x.c b/arch/arm/mach-omap2/gpmc-smsc911x.c
new file mode 100644
index 000000000000..703f150dd01d
--- /dev/null
+++ b/arch/arm/mach-omap2/gpmc-smsc911x.c
@@ -0,0 +1,113 @@
+/*
+ * linux/arch/arm/mach-omap2/gpmc-smsc911x.c
+ *
+ * Copyright (C) 2009 Li-Pro.Net
+ * Stephan Linz <linz@li-pro.net>
+ *
+ * Modified from linux/arch/arm/mach-omap2/gpmc-smc91x.c
+ *
+ * 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/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/smsc911x.h>
+
+#include <plat/board.h>
+#include <plat/gpmc.h>
+#include <plat/gpmc-smsc911x.h>
+
+static struct omap_smsc911x_platform_data *gpmc_cfg;
+
+static struct resource gpmc_smsc911x_resources[] = {
+ [0] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct smsc911x_platform_config gpmc_smsc911x_config = {
+ .phy_interface = PHY_INTERFACE_MODE_MII,
+ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+ .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+ .flags = SMSC911X_USE_16BIT,
+};
+
+static struct platform_device gpmc_smsc911x_device = {
+ .name = "smsc911x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(gpmc_smsc911x_resources),
+ .resource = gpmc_smsc911x_resources,
+ .dev = {
+ .platform_data = &gpmc_smsc911x_config,
+ },
+};
+
+/*
+ * Initialize smsc911x device connected to the GPMC. Note that we
+ * assume that pin multiplexing is done in the board-*.c file,
+ * or in the bootloader.
+ */
+void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *board_data)
+{
+ unsigned long cs_mem_base;
+ int ret;
+
+ gpmc_cfg = board_data;
+
+ if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
+ printk(KERN_ERR "Failed to request GPMC mem for smsc911x\n");
+ return;
+ }
+
+ gpmc_smsc911x_resources[0].start = cs_mem_base + 0x0;
+ gpmc_smsc911x_resources[0].end = cs_mem_base + 0xff;
+
+ if (gpio_request(gpmc_cfg->gpio_irq, "smsc911x irq") < 0) {
+ printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
+ gpmc_cfg->gpio_irq);
+ goto free1;
+ }
+
+ gpio_direction_input(gpmc_cfg->gpio_irq);
+ gpmc_smsc911x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
+ gpmc_smsc911x_resources[1].flags |=
+ (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
+
+ if (gpio_is_valid(gpmc_cfg->gpio_reset)) {
+ ret = gpio_request(gpmc_cfg->gpio_reset, "smsc911x reset");
+ if (ret) {
+ printk(KERN_ERR "Failed to request GPIO%d for smsc911x reset\n",
+ gpmc_cfg->gpio_reset);
+ goto free2;
+ }
+
+ gpio_direction_output(gpmc_cfg->gpio_reset, 1);
+ gpio_set_value(gpmc_cfg->gpio_reset, 0);
+ msleep(100);
+ gpio_set_value(gpmc_cfg->gpio_reset, 1);
+ }
+
+ if (platform_device_register(&gpmc_smsc911x_device) < 0) {
+ printk(KERN_ERR "Unable to register smsc911x device\n");
+ gpio_free(gpmc_cfg->gpio_reset);
+ goto free2;
+ }
+
+ return;
+
+free2:
+ gpio_free(gpmc_cfg->gpio_irq);
+free1:
+ gpmc_cs_free(gpmc_cfg->cs);
+
+ printk(KERN_ERR "Could not initialize smsc911x\n");
+}
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index c8f647b6205e..34272e4863fd 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -14,11 +14,11 @@
#include <linux/string.h>
#include <linux/delay.h>
#include <mach/hardware.h>
-#include <plat/control.h>
#include <plat/mmc.h>
#include <plat/omap-pm.h>
#include "hsmmc.h"
+#include "control.h"
#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
@@ -135,10 +135,11 @@ static void omap4_hsmmc1_before_set_reg(struct device *dev, int slot,
*
* FIXME handle VMMC1A as needed ...
*/
- reg = omap_ctrl_readl(control_pbias_offset);
- reg &= ~(OMAP4_MMC1_PBIASLITE_PWRDNZ | OMAP4_MMC1_PWRDNZ |
- OMAP4_USBC1_ICUSB_PWRDNZ);
- omap_ctrl_writel(reg, control_pbias_offset);
+ reg = omap4_ctrl_pad_readl(control_pbias_offset);
+ reg &= ~(OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK |
+ OMAP4_MMC1_PWRDNZ_MASK |
+ OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
+ omap4_ctrl_pad_writel(reg, control_pbias_offset);
}
static void omap4_hsmmc1_after_set_reg(struct device *dev, int slot,
@@ -147,30 +148,33 @@ static void omap4_hsmmc1_after_set_reg(struct device *dev, int slot,
u32 reg;
if (power_on) {
- reg = omap_ctrl_readl(control_pbias_offset);
- reg |= OMAP4_MMC1_PBIASLITE_PWRDNZ;
+ reg = omap4_ctrl_pad_readl(control_pbias_offset);
+ reg |= OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK;
if ((1 << vdd) <= MMC_VDD_165_195)
- reg &= ~OMAP4_MMC1_PBIASLITE_VMODE;
+ reg &= ~OMAP4_MMC1_PBIASLITE_VMODE_MASK;
else
- reg |= OMAP4_MMC1_PBIASLITE_VMODE;
- reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ | OMAP4_MMC1_PWRDNZ |
- OMAP4_USBC1_ICUSB_PWRDNZ);
- omap_ctrl_writel(reg, control_pbias_offset);
+ reg |= OMAP4_MMC1_PBIASLITE_VMODE_MASK;
+ reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK |
+ OMAP4_MMC1_PWRDNZ_MASK |
+ OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
+ omap4_ctrl_pad_writel(reg, control_pbias_offset);
/* 4 microsec delay for comparator to generate an error*/
udelay(4);
- reg = omap_ctrl_readl(control_pbias_offset);
- if (reg & OMAP4_MMC1_PBIASLITE_VMODE_ERROR) {
+ reg = omap4_ctrl_pad_readl(control_pbias_offset);
+ 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 | OMAP4_USBC1_ICUSB_PWRDNZ);
- omap_ctrl_writel(reg, control_pbias_offset);
+ reg &= ~(OMAP4_MMC1_PWRDNZ_MASK |
+ OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
+ omap4_ctrl_pad_writel(reg, control_pbias_offset);
}
} else {
- reg = omap_ctrl_readl(control_pbias_offset);
- reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ |
- OMAP4_MMC1_PBIASLITE_VMODE | OMAP4_MMC1_PWRDNZ |
- OMAP4_USBC1_ICUSB_PWRDNZ);
- omap_ctrl_writel(reg, control_pbias_offset);
+ 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_ctrl_pad_writel(reg, control_pbias_offset);
}
}
@@ -218,17 +222,18 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1;
}
} else {
- control_pbias_offset = OMAP44XX_CONTROL_PBIAS_LITE;
- control_mmc1 = OMAP44XX_CONTROL_MMC1;
- reg = omap_ctrl_readl(control_mmc1);
- reg |= (OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP0 |
- OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP1);
- reg &= ~(OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP2 |
- OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP3);
- reg |= (OMAP4_CONTROL_SDMMC1_DR0_SPEEDCTRL |
- OMAP4_CONTROL_SDMMC1_DR1_SPEEDCTRL |
- OMAP4_CONTROL_SDMMC1_DR2_SPEEDCTRL);
- omap_ctrl_writel(reg, control_mmc1);
+ control_pbias_offset =
+ OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PBIASLITE;
+ control_mmc1 = OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MMC1;
+ reg = omap4_ctrl_pad_readl(control_mmc1);
+ reg |= (OMAP4_SDMMC1_PUSTRENGTH_GRP0_MASK |
+ OMAP4_SDMMC1_PUSTRENGTH_GRP1_MASK);
+ reg &= ~(OMAP4_SDMMC1_PUSTRENGTH_GRP2_MASK |
+ OMAP4_SDMMC1_PUSTRENGTH_GRP3_MASK);
+ reg |= (OMAP4_USBC1_DR0_SPEEDCTRL_MASK|
+ OMAP4_SDMMC1_DR1_SPEEDCTRL_MASK |
+ OMAP4_SDMMC1_DR2_SPEEDCTRL_MASK);
+ omap4_ctrl_pad_writel(reg, control_mmc1);
}
for (c = controllers; c->mmc; c++) {
@@ -258,9 +263,13 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
"mmc%islot%i", c->mmc, 1);
mmc->slots[0].name = hc->name;
mmc->nr_slots = 1;
- mmc->slots[0].wires = c->wires;
+ mmc->slots[0].caps = c->caps;
mmc->slots[0].internal_clock = !c->ext_clock;
mmc->dma_mask = 0xffffffff;
+ if (cpu_is_omap44xx())
+ mmc->reg_offset = OMAP4_MMC_REG_OFFSET;
+ else
+ mmc->reg_offset = 0;
mmc->get_context_loss_count = hsmmc_get_context_loss;
@@ -298,6 +307,9 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
else
mmc->slots[0].features |= HSMMC_HAS_PBIAS;
+ if (cpu_is_omap44xx() && (omap_rev() > OMAP4430_REV_ES1_0))
+ mmc->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
+
switch (c->mmc) {
case 1:
if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
@@ -316,16 +328,20 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
}
/* Omap3630 HSMMC1 supports only 4-bit */
- if (cpu_is_omap3630() && c->wires > 4) {
- c->wires = 4;
- mmc->slots[0].wires = c->wires;
+ if (cpu_is_omap3630() &&
+ (c->caps & MMC_CAP_8_BIT_DATA)) {
+ c->caps &= ~MMC_CAP_8_BIT_DATA;
+ c->caps |= MMC_CAP_4_BIT_DATA;
+ mmc->slots[0].caps = c->caps;
}
break;
case 2:
if (c->ext_clock)
c->transceiver = 1;
- if (c->transceiver && c->wires > 4)
- c->wires = 4;
+ if (c->transceiver && (c->caps & MMC_CAP_8_BIT_DATA)) {
+ c->caps &= ~MMC_CAP_8_BIT_DATA;
+ c->caps |= MMC_CAP_4_BIT_DATA;
+ }
/* FALLTHROUGH */
case 3:
if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h
index 1fe6f0187177..f119348827d4 100644
--- a/arch/arm/mach-omap2/hsmmc.h
+++ b/arch/arm/mach-omap2/hsmmc.h
@@ -10,7 +10,8 @@ struct mmc_card;
struct omap2_hsmmc_info {
u8 mmc; /* controller 1/2/3 */
- u8 wires; /* 1/4/8 wires */
+ u32 caps; /* 4/8 wires and any additional host
+ * capabilities OR'd (ref. linux/mmc/host.h) */
bool transceiver; /* MMC-2 option */
bool ext_clock; /* use external pin for input clock */
bool cover_only; /* No card detect - just cover switch */
@@ -23,7 +24,7 @@ struct omap2_hsmmc_info {
char *name; /* or NULL for default */
struct device *dev; /* returned: pointer to mmc adapter */
int ocr_mask; /* temporary HACK */
- /* Remux (pad configuation) when powering on/off */
+ /* Remux (pad configuration) when powering on/off */
void (*remux)(struct device *dev, int slot, int power_on);
/* init some special card */
void (*init_card)(struct mmc_card *card);
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index 9a879f959509..5f9086c65e48 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -22,11 +22,12 @@
#include <asm/cputype.h>
#include <plat/common.h>
-#include <plat/control.h>
#include <plat/cpu.h>
#include <mach/id.h>
+#include "control.h"
+
static struct omap_chip_id omap_chip;
static unsigned int omap_revision;
@@ -60,7 +61,7 @@ int omap_type(void)
} else if (cpu_is_omap34xx()) {
val = omap_ctrl_readl(OMAP343X_CONTROL_STATUS);
} else if (cpu_is_omap44xx()) {
- val = omap_ctrl_readl(OMAP44XX_CONTROL_STATUS);
+ val = omap_ctrl_readl(OMAP4_CTRL_MODULE_CORE_STATUS);
} else {
pr_err("Cannot detect omap type!\n");
goto out;
@@ -298,7 +299,6 @@ static void __init omap4_check_revision(void)
u32 idcode;
u16 hawkeye;
u8 rev;
- char *rev_name = "ES1.0";
/*
* The IC rev detection is done with hawkeye and rev.
@@ -309,14 +309,39 @@ static void __init omap4_check_revision(void)
hawkeye = (idcode >> 12) & 0xffff;
rev = (idcode >> 28) & 0xff;
- if ((hawkeye == 0xb852) && (rev == 0x0)) {
- omap_revision = OMAP4430_REV_ES1_0;
- omap_chip.oc |= CHIP_IS_OMAP4430ES1;
- pr_info("OMAP%04x %s\n", omap_rev() >> 16, rev_name);
- return;
+ /*
+ * Few initial ES2.0 samples IDCODE is same as ES1.0
+ * Use ARM register to detect the correct ES version
+ */
+ if (!rev) {
+ idcode = read_cpuid(CPUID_ID);
+ rev = (idcode & 0xf) - 1;
+ }
+
+ switch (hawkeye) {
+ case 0xb852:
+ switch (rev) {
+ case 0:
+ omap_revision = OMAP4430_REV_ES1_0;
+ omap_chip.oc |= CHIP_IS_OMAP4430ES1;
+ break;
+ case 1:
+ omap_revision = OMAP4430_REV_ES2_0;
+ omap_chip.oc |= CHIP_IS_OMAP4430ES2;
+ break;
+ default:
+ omap_revision = OMAP4430_REV_ES2_0;
+ omap_chip.oc |= CHIP_IS_OMAP4430ES2;
+ }
+ break;
+ default:
+ /* Unknown default to latest silicon rev as default*/
+ omap_revision = OMAP4430_REV_ES2_0;
+ omap_chip.oc |= CHIP_IS_OMAP4430ES2;
}
- pr_err("Unknown OMAP4 CPU id\n");
+ pr_info("OMAP%04x ES%d.0\n",
+ omap_rev() >> 16, ((omap_rev() >> 12) & 0xf) + 1);
}
#define OMAP3_SHOW_FEATURE(feat) \
@@ -361,30 +386,54 @@ static void __init omap3_cpuinfo(void)
strcpy(cpu_name, "OMAP3503");
}
- switch (rev) {
- case OMAP_REVBITS_00:
- strcpy(cpu_rev, "1.0");
- break;
- case OMAP_REVBITS_01:
- strcpy(cpu_rev, "1.1");
- break;
- case OMAP_REVBITS_02:
- strcpy(cpu_rev, "1.2");
- break;
- case OMAP_REVBITS_10:
- strcpy(cpu_rev, "2.0");
- break;
- case OMAP_REVBITS_20:
- strcpy(cpu_rev, "2.1");
- break;
- case OMAP_REVBITS_30:
- strcpy(cpu_rev, "3.0");
- break;
- case OMAP_REVBITS_40:
- /* FALLTHROUGH */
- default:
- /* Use the latest known revision as default */
- strcpy(cpu_rev, "3.1");
+ if (cpu_is_omap3630()) {
+ switch (rev) {
+ case OMAP_REVBITS_00:
+ strcpy(cpu_rev, "1.0");
+ break;
+ case OMAP_REVBITS_01:
+ strcpy(cpu_rev, "1.1");
+ break;
+ case OMAP_REVBITS_02:
+ /* FALLTHROUGH */
+ default:
+ /* Use the latest known revision as default */
+ strcpy(cpu_rev, "1.2");
+ }
+ } else if (cpu_is_omap3505() || cpu_is_omap3517()) {
+ switch (rev) {
+ case OMAP_REVBITS_00:
+ strcpy(cpu_rev, "1.0");
+ break;
+ case OMAP_REVBITS_01:
+ /* FALLTHROUGH */
+ default:
+ /* Use the latest known revision as default */
+ strcpy(cpu_rev, "1.1");
+ }
+ } else {
+ switch (rev) {
+ case OMAP_REVBITS_00:
+ strcpy(cpu_rev, "1.0");
+ break;
+ case OMAP_REVBITS_01:
+ strcpy(cpu_rev, "2.0");
+ break;
+ case OMAP_REVBITS_02:
+ strcpy(cpu_rev, "2.1");
+ break;
+ case OMAP_REVBITS_03:
+ strcpy(cpu_rev, "3.0");
+ break;
+ case OMAP_REVBITS_04:
+ strcpy(cpu_rev, "3.1");
+ break;
+ case OMAP_REVBITS_05:
+ /* FALLTHROUGH */
+ default:
+ /* Use the latest known revision as default */
+ strcpy(cpu_rev, "3.1.2");
+ }
}
/* Print verbose information */
diff --git a/arch/arm/mach-omap2/include/mach/board-rx51.h b/arch/arm/mach-omap2/include/mach/board-rx51.h
new file mode 100644
index 000000000000..b76f49e7eed5
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/board-rx51.h
@@ -0,0 +1,11 @@
+/*
+ * Defines for rx51 boards
+ */
+
+#ifndef _OMAP_BOARD_RX51_H
+#define _OMAP_BOARD_RX51_H
+
+extern void __init rx51_peripherals_init(void);
+extern void __init rx51_video_mem_init(void);
+
+#endif
diff --git a/arch/arm/mach-omap2/include/mach/board-zoom.h b/arch/arm/mach-omap2/include/mach/board-zoom.h
index 3af69d2c3dcd..f93ca3928c3b 100644
--- a/arch/arm/mach-omap2/include/mach/board-zoom.h
+++ b/arch/arm/mach-omap2/include/mach/board-zoom.h
@@ -1,11 +1,9 @@
/*
* Defines for zoom boards
*/
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-
#define ZOOM_NAND_CS 0
-extern void __init board_nand_init(struct mtd_partition *, u8 nr_parts, u8 cs);
extern int __init zoom_debugboard_init(void);
extern void __init zoom_peripherals_init(void);
+
+#define ZOOM2_HEADSET_EXTMUTE_GPIO 153
diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h b/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h
new file mode 100644
index 000000000000..2f7ac70a20d8
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h
@@ -0,0 +1,391 @@
+/*
+ * OMAP44xx CTRL_MODULE_CORE registers and bitfields
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@ti.com)
+ * Santosh Shilimkar (santosh.shilimkar@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * 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 __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_CORE_44XX_H
+#define __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_CORE_44XX_H
+
+
+/* Base address */
+#define OMAP4_CTRL_MODULE_CORE 0x4a002000
+
+/* Registers offset */
+#define OMAP4_CTRL_MODULE_CORE_IP_REVISION 0x0000
+#define OMAP4_CTRL_MODULE_CORE_IP_HWINFO 0x0004
+#define OMAP4_CTRL_MODULE_CORE_IP_SYSCONFIG 0x0010
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_DIE_ID_0 0x0200
+#define OMAP4_CTRL_MODULE_CORE_ID_CODE 0x0204
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_DIE_ID_1 0x0208
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_DIE_ID_2 0x020c
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_DIE_ID_3 0x0210
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_PROD_ID_0 0x0214
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_PROD_ID_1 0x0218
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_USB_CONF 0x021c
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_VDD_WKUP 0x0228
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_BGAP 0x0260
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_DPLL_0 0x0264
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_DPLL_1 0x0268
+#define OMAP4_CTRL_MODULE_CORE_STATUS 0x02c4
+#define OMAP4_CTRL_MODULE_CORE_DEV_CONF 0x0300
+#define OMAP4_CTRL_MODULE_CORE_LDOVBB_IVA_VOLTAGE_CTRL 0x0314
+#define OMAP4_CTRL_MODULE_CORE_LDOVBB_MPU_VOLTAGE_CTRL 0x0318
+#define OMAP4_CTRL_MODULE_CORE_LDOSRAM_IVA_VOLTAGE_CTRL 0x0320
+#define OMAP4_CTRL_MODULE_CORE_LDOSRAM_MPU_VOLTAGE_CTRL 0x0324
+#define OMAP4_CTRL_MODULE_CORE_LDOSRAM_CORE_VOLTAGE_CTRL 0x0328
+#define OMAP4_CTRL_MODULE_CORE_TEMP_SENSOR 0x032c
+#define OMAP4_CTRL_MODULE_CORE_DPLL_NWELL_TRIM_0 0x0330
+#define OMAP4_CTRL_MODULE_CORE_DPLL_NWELL_TRIM_1 0x0334
+#define OMAP4_CTRL_MODULE_CORE_USBOTGHS_CONTROL 0x033c
+#define OMAP4_CTRL_MODULE_CORE_DSS_CONTROL 0x0340
+#define OMAP4_CTRL_MODULE_CORE_HWOBS_CONTROL 0x0350
+#define OMAP4_CTRL_MODULE_CORE_DEBOBS_FINAL_MUX_SEL 0x0400
+#define OMAP4_CTRL_MODULE_CORE_DEBOBS_MMR_MPU 0x0408
+#define OMAP4_CTRL_MODULE_CORE_CONF_SDMA_REQ_SEL0 0x042c
+#define OMAP4_CTRL_MODULE_CORE_CONF_SDMA_REQ_SEL1 0x0430
+#define OMAP4_CTRL_MODULE_CORE_CONF_SDMA_REQ_SEL2 0x0434
+#define OMAP4_CTRL_MODULE_CORE_CONF_SDMA_REQ_SEL3 0x0438
+#define OMAP4_CTRL_MODULE_CORE_CONF_CLK_SEL0 0x0440
+#define OMAP4_CTRL_MODULE_CORE_CONF_CLK_SEL1 0x0444
+#define OMAP4_CTRL_MODULE_CORE_CONF_CLK_SEL2 0x0448
+#define OMAP4_CTRL_MODULE_CORE_CONF_DPLL_FREQLOCK_SEL 0x044c
+#define OMAP4_CTRL_MODULE_CORE_CONF_DPLL_TINITZ_SEL 0x0450
+#define OMAP4_CTRL_MODULE_CORE_CONF_DPLL_PHASELOCK_SEL 0x0454
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_0 0x0480
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_1 0x0484
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_2 0x0488
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_3 0x048c
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_4 0x0490
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_5 0x0494
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_6 0x0498
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_7 0x049c
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_8 0x04a0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_9 0x04a4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_10 0x04a8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_11 0x04ac
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_12 0x04b0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_13 0x04b4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_14 0x04b8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_15 0x04bc
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_16 0x04c0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_17 0x04c4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_18 0x04c8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_19 0x04cc
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_20 0x04d0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_21 0x04d4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_22 0x04d8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_23 0x04dc
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_24 0x04e0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_25 0x04e4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_26 0x04e8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_27 0x04ec
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_28 0x04f0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_29 0x04f4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_30 0x04f8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_31 0x04fc
+
+/* Registers shifts and masks */
+
+/* IP_REVISION */
+#define OMAP4_IP_REV_SCHEME_SHIFT 30
+#define OMAP4_IP_REV_SCHEME_MASK (0x3 << 30)
+#define OMAP4_IP_REV_FUNC_SHIFT 16
+#define OMAP4_IP_REV_FUNC_MASK (0xfff << 16)
+#define OMAP4_IP_REV_RTL_SHIFT 11
+#define OMAP4_IP_REV_RTL_MASK (0x1f << 11)
+#define OMAP4_IP_REV_MAJOR_SHIFT 8
+#define OMAP4_IP_REV_MAJOR_MASK (0x7 << 8)
+#define OMAP4_IP_REV_CUSTOM_SHIFT 6
+#define OMAP4_IP_REV_CUSTOM_MASK (0x3 << 6)
+#define OMAP4_IP_REV_MINOR_SHIFT 0
+#define OMAP4_IP_REV_MINOR_MASK (0x3f << 0)
+
+/* IP_HWINFO */
+#define OMAP4_IP_HWINFO_SHIFT 0
+#define OMAP4_IP_HWINFO_MASK (0xffffffff << 0)
+
+/* IP_SYSCONFIG */
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_SHIFT 2
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_MASK (0x3 << 2)
+
+/* STD_FUSE_DIE_ID_0 */
+#define OMAP4_STD_FUSE_DIE_ID_0_SHIFT 0
+#define OMAP4_STD_FUSE_DIE_ID_0_MASK (0xffffffff << 0)
+
+/* ID_CODE */
+#define OMAP4_STD_FUSE_IDCODE_SHIFT 0
+#define OMAP4_STD_FUSE_IDCODE_MASK (0xffffffff << 0)
+
+/* STD_FUSE_DIE_ID_1 */
+#define OMAP4_STD_FUSE_DIE_ID_1_SHIFT 0
+#define OMAP4_STD_FUSE_DIE_ID_1_MASK (0xffffffff << 0)
+
+/* STD_FUSE_DIE_ID_2 */
+#define OMAP4_STD_FUSE_DIE_ID_2_SHIFT 0
+#define OMAP4_STD_FUSE_DIE_ID_2_MASK (0xffffffff << 0)
+
+/* STD_FUSE_DIE_ID_3 */
+#define OMAP4_STD_FUSE_DIE_ID_3_SHIFT 0
+#define OMAP4_STD_FUSE_DIE_ID_3_MASK (0xffffffff << 0)
+
+/* STD_FUSE_PROD_ID_0 */
+#define OMAP4_STD_FUSE_PROD_ID_0_SHIFT 0
+#define OMAP4_STD_FUSE_PROD_ID_0_MASK (0xffffffff << 0)
+
+/* STD_FUSE_PROD_ID_1 */
+#define OMAP4_STD_FUSE_PROD_ID_1_SHIFT 0
+#define OMAP4_STD_FUSE_PROD_ID_1_MASK (0xffffffff << 0)
+
+/* STD_FUSE_USB_CONF */
+#define OMAP4_USB_PROD_ID_SHIFT 16
+#define OMAP4_USB_PROD_ID_MASK (0xffff << 16)
+#define OMAP4_USB_VENDOR_ID_SHIFT 0
+#define OMAP4_USB_VENDOR_ID_MASK (0xffff << 0)
+
+/* STD_FUSE_OPP_VDD_WKUP */
+#define OMAP4_STD_FUSE_OPP_VDD_WKUP_SHIFT 0
+#define OMAP4_STD_FUSE_OPP_VDD_WKUP_MASK (0xffffffff << 0)
+
+/* STD_FUSE_OPP_BGAP */
+#define OMAP4_STD_FUSE_OPP_BGAP_SHIFT 0
+#define OMAP4_STD_FUSE_OPP_BGAP_MASK (0xffffffff << 0)
+
+/* STD_FUSE_OPP_DPLL_0 */
+#define OMAP4_STD_FUSE_OPP_DPLL_0_SHIFT 0
+#define OMAP4_STD_FUSE_OPP_DPLL_0_MASK (0xffffffff << 0)
+
+/* STD_FUSE_OPP_DPLL_1 */
+#define OMAP4_STD_FUSE_OPP_DPLL_1_SHIFT 0
+#define OMAP4_STD_FUSE_OPP_DPLL_1_MASK (0xffffffff << 0)
+
+/* STATUS */
+#define OMAP4_ATTILA_CONF_SHIFT 11
+#define OMAP4_ATTILA_CONF_MASK (0x3 << 11)
+#define OMAP4_DEVICE_TYPE_SHIFT 8
+#define OMAP4_DEVICE_TYPE_MASK (0x7 << 8)
+#define OMAP4_SYS_BOOT_SHIFT 0
+#define OMAP4_SYS_BOOT_MASK (0xff << 0)
+
+/* DEV_CONF */
+#define OMAP4_DEV_CONF_SHIFT 1
+#define OMAP4_DEV_CONF_MASK (0x7fffffff << 1)
+#define OMAP4_USBPHY_PD_SHIFT 0
+#define OMAP4_USBPHY_PD_MASK (1 << 0)
+
+/* LDOVBB_IVA_VOLTAGE_CTRL */
+#define OMAP4_LDOVBBIVA_RBB_MUX_CTRL_SHIFT 26
+#define OMAP4_LDOVBBIVA_RBB_MUX_CTRL_MASK (1 << 26)
+#define OMAP4_LDOVBBIVA_RBB_VSET_IN_SHIFT 21
+#define OMAP4_LDOVBBIVA_RBB_VSET_IN_MASK (0x1f << 21)
+#define OMAP4_LDOVBBIVA_RBB_VSET_OUT_SHIFT 16
+#define OMAP4_LDOVBBIVA_RBB_VSET_OUT_MASK (0x1f << 16)
+#define OMAP4_LDOVBBIVA_FBB_MUX_CTRL_SHIFT 10
+#define OMAP4_LDOVBBIVA_FBB_MUX_CTRL_MASK (1 << 10)
+#define OMAP4_LDOVBBIVA_FBB_VSET_IN_SHIFT 5
+#define OMAP4_LDOVBBIVA_FBB_VSET_IN_MASK (0x1f << 5)
+#define OMAP4_LDOVBBIVA_FBB_VSET_OUT_SHIFT 0
+#define OMAP4_LDOVBBIVA_FBB_VSET_OUT_MASK (0x1f << 0)
+
+/* LDOVBB_MPU_VOLTAGE_CTRL */
+#define OMAP4_LDOVBBMPU_RBB_MUX_CTRL_SHIFT 26
+#define OMAP4_LDOVBBMPU_RBB_MUX_CTRL_MASK (1 << 26)
+#define OMAP4_LDOVBBMPU_RBB_VSET_IN_SHIFT 21
+#define OMAP4_LDOVBBMPU_RBB_VSET_IN_MASK (0x1f << 21)
+#define OMAP4_LDOVBBMPU_RBB_VSET_OUT_SHIFT 16
+#define OMAP4_LDOVBBMPU_RBB_VSET_OUT_MASK (0x1f << 16)
+#define OMAP4_LDOVBBMPU_FBB_MUX_CTRL_SHIFT 10
+#define OMAP4_LDOVBBMPU_FBB_MUX_CTRL_MASK (1 << 10)
+#define OMAP4_LDOVBBMPU_FBB_VSET_IN_SHIFT 5
+#define OMAP4_LDOVBBMPU_FBB_VSET_IN_MASK (0x1f << 5)
+#define OMAP4_LDOVBBMPU_FBB_VSET_OUT_SHIFT 0
+#define OMAP4_LDOVBBMPU_FBB_VSET_OUT_MASK (0x1f << 0)
+
+/* LDOSRAM_IVA_VOLTAGE_CTRL */
+#define OMAP4_LDOSRAMIVA_RETMODE_MUX_CTRL_SHIFT 26
+#define OMAP4_LDOSRAMIVA_RETMODE_MUX_CTRL_MASK (1 << 26)
+#define OMAP4_LDOSRAMIVA_RETMODE_VSET_IN_SHIFT 21
+#define OMAP4_LDOSRAMIVA_RETMODE_VSET_IN_MASK (0x1f << 21)
+#define OMAP4_LDOSRAMIVA_RETMODE_VSET_OUT_SHIFT 16
+#define OMAP4_LDOSRAMIVA_RETMODE_VSET_OUT_MASK (0x1f << 16)
+#define OMAP4_LDOSRAMIVA_ACTMODE_MUX_CTRL_SHIFT 10
+#define OMAP4_LDOSRAMIVA_ACTMODE_MUX_CTRL_MASK (1 << 10)
+#define OMAP4_LDOSRAMIVA_ACTMODE_VSET_IN_SHIFT 5
+#define OMAP4_LDOSRAMIVA_ACTMODE_VSET_IN_MASK (0x1f << 5)
+#define OMAP4_LDOSRAMIVA_ACTMODE_VSET_OUT_SHIFT 0
+#define OMAP4_LDOSRAMIVA_ACTMODE_VSET_OUT_MASK (0x1f << 0)
+
+/* LDOSRAM_MPU_VOLTAGE_CTRL */
+#define OMAP4_LDOSRAMMPU_RETMODE_MUX_CTRL_SHIFT 26
+#define OMAP4_LDOSRAMMPU_RETMODE_MUX_CTRL_MASK (1 << 26)
+#define OMAP4_LDOSRAMMPU_RETMODE_VSET_IN_SHIFT 21
+#define OMAP4_LDOSRAMMPU_RETMODE_VSET_IN_MASK (0x1f << 21)
+#define OMAP4_LDOSRAMMPU_RETMODE_VSET_OUT_SHIFT 16
+#define OMAP4_LDOSRAMMPU_RETMODE_VSET_OUT_MASK (0x1f << 16)
+#define OMAP4_LDOSRAMMPU_ACTMODE_MUX_CTRL_SHIFT 10
+#define OMAP4_LDOSRAMMPU_ACTMODE_MUX_CTRL_MASK (1 << 10)
+#define OMAP4_LDOSRAMMPU_ACTMODE_VSET_IN_SHIFT 5
+#define OMAP4_LDOSRAMMPU_ACTMODE_VSET_IN_MASK (0x1f << 5)
+#define OMAP4_LDOSRAMMPU_ACTMODE_VSET_OUT_SHIFT 0
+#define OMAP4_LDOSRAMMPU_ACTMODE_VSET_OUT_MASK (0x1f << 0)
+
+/* LDOSRAM_CORE_VOLTAGE_CTRL */
+#define OMAP4_LDOSRAMCORE_RETMODE_MUX_CTRL_SHIFT 26
+#define OMAP4_LDOSRAMCORE_RETMODE_MUX_CTRL_MASK (1 << 26)
+#define OMAP4_LDOSRAMCORE_RETMODE_VSET_IN_SHIFT 21
+#define OMAP4_LDOSRAMCORE_RETMODE_VSET_IN_MASK (0x1f << 21)
+#define OMAP4_LDOSRAMCORE_RETMODE_VSET_OUT_SHIFT 16
+#define OMAP4_LDOSRAMCORE_RETMODE_VSET_OUT_MASK (0x1f << 16)
+#define OMAP4_LDOSRAMCORE_ACTMODE_MUX_CTRL_SHIFT 10
+#define OMAP4_LDOSRAMCORE_ACTMODE_MUX_CTRL_MASK (1 << 10)
+#define OMAP4_LDOSRAMCORE_ACTMODE_VSET_IN_SHIFT 5
+#define OMAP4_LDOSRAMCORE_ACTMODE_VSET_IN_MASK (0x1f << 5)
+#define OMAP4_LDOSRAMCORE_ACTMODE_VSET_OUT_SHIFT 0
+#define OMAP4_LDOSRAMCORE_ACTMODE_VSET_OUT_MASK (0x1f << 0)
+
+/* TEMP_SENSOR */
+#define OMAP4_BGAP_TEMPSOFF_SHIFT 12
+#define OMAP4_BGAP_TEMPSOFF_MASK (1 << 12)
+#define OMAP4_BGAP_TSHUT_SHIFT 11
+#define OMAP4_BGAP_TSHUT_MASK (1 << 11)
+#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_SHIFT 10
+#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_MASK (1 << 10)
+#define OMAP4_BGAP_TEMP_SENSOR_SOC_SHIFT 9
+#define OMAP4_BGAP_TEMP_SENSOR_SOC_MASK (1 << 9)
+#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_SHIFT 8
+#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 8)
+#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0
+#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_MASK (0xff << 0)
+
+/* DPLL_NWELL_TRIM_0 */
+#define OMAP4_DPLL_ABE_NWELL_TRIM_MUX_CTRL_SHIFT 29
+#define OMAP4_DPLL_ABE_NWELL_TRIM_MUX_CTRL_MASK (1 << 29)
+#define OMAP4_DPLL_ABE_NWELL_TRIM_SHIFT 24
+#define OMAP4_DPLL_ABE_NWELL_TRIM_MASK (0x1f << 24)
+#define OMAP4_DPLL_PER_NWELL_TRIM_MUX_CTRL_SHIFT 23
+#define OMAP4_DPLL_PER_NWELL_TRIM_MUX_CTRL_MASK (1 << 23)
+#define OMAP4_DPLL_PER_NWELL_TRIM_SHIFT 18
+#define OMAP4_DPLL_PER_NWELL_TRIM_MASK (0x1f << 18)
+#define OMAP4_DPLL_CORE_NWELL_TRIM_MUX_CTRL_SHIFT 17
+#define OMAP4_DPLL_CORE_NWELL_TRIM_MUX_CTRL_MASK (1 << 17)
+#define OMAP4_DPLL_CORE_NWELL_TRIM_SHIFT 12
+#define OMAP4_DPLL_CORE_NWELL_TRIM_MASK (0x1f << 12)
+#define OMAP4_DPLL_IVA_NWELL_TRIM_MUX_CTRL_SHIFT 11
+#define OMAP4_DPLL_IVA_NWELL_TRIM_MUX_CTRL_MASK (1 << 11)
+#define OMAP4_DPLL_IVA_NWELL_TRIM_SHIFT 6
+#define OMAP4_DPLL_IVA_NWELL_TRIM_MASK (0x1f << 6)
+#define OMAP4_DPLL_MPU_NWELL_TRIM_MUX_CTRL_SHIFT 5
+#define OMAP4_DPLL_MPU_NWELL_TRIM_MUX_CTRL_MASK (1 << 5)
+#define OMAP4_DPLL_MPU_NWELL_TRIM_SHIFT 0
+#define OMAP4_DPLL_MPU_NWELL_TRIM_MASK (0x1f << 0)
+
+/* DPLL_NWELL_TRIM_1 */
+#define OMAP4_DPLL_UNIPRO_NWELL_TRIM_MUX_CTRL_SHIFT 29
+#define OMAP4_DPLL_UNIPRO_NWELL_TRIM_MUX_CTRL_MASK (1 << 29)
+#define OMAP4_DPLL_UNIPRO_NWELL_TRIM_SHIFT 24
+#define OMAP4_DPLL_UNIPRO_NWELL_TRIM_MASK (0x1f << 24)
+#define OMAP4_DPLL_USB_NWELL_TRIM_MUX_CTRL_SHIFT 23
+#define OMAP4_DPLL_USB_NWELL_TRIM_MUX_CTRL_MASK (1 << 23)
+#define OMAP4_DPLL_USB_NWELL_TRIM_SHIFT 18
+#define OMAP4_DPLL_USB_NWELL_TRIM_MASK (0x1f << 18)
+#define OMAP4_DPLL_HDMI_NWELL_TRIM_MUX_CTRL_SHIFT 17
+#define OMAP4_DPLL_HDMI_NWELL_TRIM_MUX_CTRL_MASK (1 << 17)
+#define OMAP4_DPLL_HDMI_NWELL_TRIM_SHIFT 12
+#define OMAP4_DPLL_HDMI_NWELL_TRIM_MASK (0x1f << 12)
+#define OMAP4_DPLL_DSI2_NWELL_TRIM_MUX_CTRL_SHIFT 11
+#define OMAP4_DPLL_DSI2_NWELL_TRIM_MUX_CTRL_MASK (1 << 11)
+#define OMAP4_DPLL_DSI2_NWELL_TRIM_SHIFT 6
+#define OMAP4_DPLL_DSI2_NWELL_TRIM_MASK (0x1f << 6)
+#define OMAP4_DPLL_DSI1_NWELL_TRIM_MUX_CTRL_SHIFT 5
+#define OMAP4_DPLL_DSI1_NWELL_TRIM_MUX_CTRL_MASK (1 << 5)
+#define OMAP4_DPLL_DSI1_NWELL_TRIM_SHIFT 0
+#define OMAP4_DPLL_DSI1_NWELL_TRIM_MASK (0x1f << 0)
+
+/* USBOTGHS_CONTROL */
+#define OMAP4_DISCHRGVBUS_SHIFT 8
+#define OMAP4_DISCHRGVBUS_MASK (1 << 8)
+#define OMAP4_CHRGVBUS_SHIFT 7
+#define OMAP4_CHRGVBUS_MASK (1 << 7)
+#define OMAP4_DRVVBUS_SHIFT 6
+#define OMAP4_DRVVBUS_MASK (1 << 6)
+#define OMAP4_IDPULLUP_SHIFT 5
+#define OMAP4_IDPULLUP_MASK (1 << 5)
+#define OMAP4_IDDIG_SHIFT 4
+#define OMAP4_IDDIG_MASK (1 << 4)
+#define OMAP4_SESSEND_SHIFT 3
+#define OMAP4_SESSEND_MASK (1 << 3)
+#define OMAP4_VBUSVALID_SHIFT 2
+#define OMAP4_VBUSVALID_MASK (1 << 2)
+#define OMAP4_BVALID_SHIFT 1
+#define OMAP4_BVALID_MASK (1 << 1)
+#define OMAP4_AVALID_SHIFT 0
+#define OMAP4_AVALID_MASK (1 << 0)
+
+/* DSS_CONTROL */
+#define OMAP4_DSS_MUX6_SELECT_SHIFT 0
+#define OMAP4_DSS_MUX6_SELECT_MASK (1 << 0)
+
+/* HWOBS_CONTROL */
+#define OMAP4_HWOBS_CLKDIV_SEL_SHIFT 3
+#define OMAP4_HWOBS_CLKDIV_SEL_MASK (0x1f << 3)
+#define OMAP4_HWOBS_ALL_ZERO_MODE_SHIFT 2
+#define OMAP4_HWOBS_ALL_ZERO_MODE_MASK (1 << 2)
+#define OMAP4_HWOBS_ALL_ONE_MODE_SHIFT 1
+#define OMAP4_HWOBS_ALL_ONE_MODE_MASK (1 << 1)
+#define OMAP4_HWOBS_MACRO_ENABLE_SHIFT 0
+#define OMAP4_HWOBS_MACRO_ENABLE_MASK (1 << 0)
+
+/* DEBOBS_FINAL_MUX_SEL */
+#define OMAP4_SELECT_SHIFT 0
+#define OMAP4_SELECT_MASK (0xffffffff << 0)
+
+/* DEBOBS_MMR_MPU */
+#define OMAP4_SELECT_DEBOBS_MMR_MPU_SHIFT 0
+#define OMAP4_SELECT_DEBOBS_MMR_MPU_MASK (0xf << 0)
+
+/* CONF_SDMA_REQ_SEL0 */
+#define OMAP4_MULT_SHIFT 0
+#define OMAP4_MULT_MASK (0x7f << 0)
+
+/* CONF_CLK_SEL0 */
+#define OMAP4_MULT_CONF_CLK_SEL0_SHIFT 0
+#define OMAP4_MULT_CONF_CLK_SEL0_MASK (0x7 << 0)
+
+/* CONF_CLK_SEL1 */
+#define OMAP4_MULT_CONF_CLK_SEL1_SHIFT 0
+#define OMAP4_MULT_CONF_CLK_SEL1_MASK (0x7 << 0)
+
+/* CONF_CLK_SEL2 */
+#define OMAP4_MULT_CONF_CLK_SEL2_SHIFT 0
+#define OMAP4_MULT_CONF_CLK_SEL2_MASK (0x7 << 0)
+
+/* CONF_DPLL_FREQLOCK_SEL */
+#define OMAP4_MULT_CONF_DPLL_FREQLOCK_SEL_SHIFT 0
+#define OMAP4_MULT_CONF_DPLL_FREQLOCK_SEL_MASK (0x7 << 0)
+
+/* CONF_DPLL_TINITZ_SEL */
+#define OMAP4_MULT_CONF_DPLL_TINITZ_SEL_SHIFT 0
+#define OMAP4_MULT_CONF_DPLL_TINITZ_SEL_MASK (0x7 << 0)
+
+/* CONF_DPLL_PHASELOCK_SEL */
+#define OMAP4_MULT_CONF_DPLL_PHASELOCK_SEL_SHIFT 0
+#define OMAP4_MULT_CONF_DPLL_PHASELOCK_SEL_MASK (0x7 << 0)
+
+/* CONF_DEBUG_SEL_TST_0 */
+#define OMAP4_MODE_SHIFT 0
+#define OMAP4_MODE_MASK (0xf << 0)
+
+#endif
diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h b/arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h
new file mode 100644
index 000000000000..c88420de1151
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h
@@ -0,0 +1,1409 @@
+/*
+ * OMAP44xx CTRL_MODULE_PAD_CORE registers and bitfields
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@ti.com)
+ * Santosh Shilimkar (santosh.shilimkar@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * 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 __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_PAD_CORE_44XX_H
+#define __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_PAD_CORE_44XX_H
+
+
+/* Base address */
+#define OMAP4_CTRL_MODULE_PAD_CORE 0x4a100000
+
+/* Registers offset */
+#define OMAP4_CTRL_MODULE_PAD_CORE_IP_REVISION 0x0000
+#define OMAP4_CTRL_MODULE_PAD_CORE_IP_HWINFO 0x0004
+#define OMAP4_CTRL_MODULE_PAD_CORE_IP_SYSCONFIG 0x0010
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_0 0x01d8
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_1 0x01dc
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_2 0x01e0
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_3 0x01e4
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_4 0x01e8
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_5 0x01ec
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_6 0x01f0
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PADCONF_GLOBAL 0x05a0
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PADCONF_MODE 0x05a4
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART1IO_PADCONF_0 0x05a8
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART1IO_PADCONF_1 0x05ac
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART2IO_PADCONF_0 0x05b0
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART2IO_PADCONF_1 0x05b4
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART3IO_PADCONF_0 0x05b8
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART3IO_PADCONF_1 0x05bc
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART3IO_PADCONF_2 0x05c0
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_USBB_HSIC 0x05c4
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SLIMBUS 0x05c8
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PBIASLITE 0x0600
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_0 0x0604
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_CAMERA_RX 0x0608
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_AVDAC 0x060c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_HDMI_TX_PHY 0x0610
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MMC2 0x0614
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY 0x0618
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MCBSPLP 0x061c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_USB2PHYCORE 0x0620
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_1 0x0624
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MMC1 0x0628
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_HSI 0x062c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_USB 0x0630
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_HDQ 0x0634
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_0 0x0638
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_1 0x063c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_2 0x0640
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_3 0x0644
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_0 0x0648
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_1 0x064c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_2 0x0650
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_3 0x0654
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_BUS_HOLD 0x0658
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_C2C 0x065c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CORE_CONTROL_SPARE_RW 0x0660
+#define OMAP4_CTRL_MODULE_PAD_CORE_CORE_CONTROL_SPARE_R 0x0664
+#define OMAP4_CTRL_MODULE_PAD_CORE_CORE_CONTROL_SPARE_R_C0 0x0668
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_1 0x0700
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_2 0x0704
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_3 0x0708
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_4 0x070c
+
+/* Registers shifts and masks */
+
+/* IP_REVISION */
+#define OMAP4_IP_REV_SCHEME_SHIFT 30
+#define OMAP4_IP_REV_SCHEME_MASK (0x3 << 30)
+#define OMAP4_IP_REV_FUNC_SHIFT 16
+#define OMAP4_IP_REV_FUNC_MASK (0xfff << 16)
+#define OMAP4_IP_REV_RTL_SHIFT 11
+#define OMAP4_IP_REV_RTL_MASK (0x1f << 11)
+#define OMAP4_IP_REV_MAJOR_SHIFT 8
+#define OMAP4_IP_REV_MAJOR_MASK (0x7 << 8)
+#define OMAP4_IP_REV_CUSTOM_SHIFT 6
+#define OMAP4_IP_REV_CUSTOM_MASK (0x3 << 6)
+#define OMAP4_IP_REV_MINOR_SHIFT 0
+#define OMAP4_IP_REV_MINOR_MASK (0x3f << 0)
+
+/* IP_HWINFO */
+#define OMAP4_IP_HWINFO_SHIFT 0
+#define OMAP4_IP_HWINFO_MASK (0xffffffff << 0)
+
+/* IP_SYSCONFIG */
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_SHIFT 2
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_MASK (0x3 << 2)
+
+/* PADCONF_WAKEUPEVENT_0 */
+#define OMAP4_GPMC_CLK_DUPLICATEWAKEUPEVENT_SHIFT 31
+#define OMAP4_GPMC_CLK_DUPLICATEWAKEUPEVENT_MASK (1 << 31)
+#define OMAP4_GPMC_NWP_DUPLICATEWAKEUPEVENT_SHIFT 30
+#define OMAP4_GPMC_NWP_DUPLICATEWAKEUPEVENT_MASK (1 << 30)
+#define OMAP4_GPMC_NCS3_DUPLICATEWAKEUPEVENT_SHIFT 29
+#define OMAP4_GPMC_NCS3_DUPLICATEWAKEUPEVENT_MASK (1 << 29)
+#define OMAP4_GPMC_NCS2_DUPLICATEWAKEUPEVENT_SHIFT 28
+#define OMAP4_GPMC_NCS2_DUPLICATEWAKEUPEVENT_MASK (1 << 28)
+#define OMAP4_GPMC_NCS1_DUPLICATEWAKEUPEVENT_SHIFT 27
+#define OMAP4_GPMC_NCS1_DUPLICATEWAKEUPEVENT_MASK (1 << 27)
+#define OMAP4_GPMC_NCS0_DUPLICATEWAKEUPEVENT_SHIFT 26
+#define OMAP4_GPMC_NCS0_DUPLICATEWAKEUPEVENT_MASK (1 << 26)
+#define OMAP4_GPMC_A25_DUPLICATEWAKEUPEVENT_SHIFT 25
+#define OMAP4_GPMC_A25_DUPLICATEWAKEUPEVENT_MASK (1 << 25)
+#define OMAP4_GPMC_A24_DUPLICATEWAKEUPEVENT_SHIFT 24
+#define OMAP4_GPMC_A24_DUPLICATEWAKEUPEVENT_MASK (1 << 24)
+#define OMAP4_GPMC_A23_DUPLICATEWAKEUPEVENT_SHIFT 23
+#define OMAP4_GPMC_A23_DUPLICATEWAKEUPEVENT_MASK (1 << 23)
+#define OMAP4_GPMC_A22_DUPLICATEWAKEUPEVENT_SHIFT 22
+#define OMAP4_GPMC_A22_DUPLICATEWAKEUPEVENT_MASK (1 << 22)
+#define OMAP4_GPMC_A21_DUPLICATEWAKEUPEVENT_SHIFT 21
+#define OMAP4_GPMC_A21_DUPLICATEWAKEUPEVENT_MASK (1 << 21)
+#define OMAP4_GPMC_A20_DUPLICATEWAKEUPEVENT_SHIFT 20
+#define OMAP4_GPMC_A20_DUPLICATEWAKEUPEVENT_MASK (1 << 20)
+#define OMAP4_GPMC_A19_DUPLICATEWAKEUPEVENT_SHIFT 19
+#define OMAP4_GPMC_A19_DUPLICATEWAKEUPEVENT_MASK (1 << 19)
+#define OMAP4_GPMC_A18_DUPLICATEWAKEUPEVENT_SHIFT 18
+#define OMAP4_GPMC_A18_DUPLICATEWAKEUPEVENT_MASK (1 << 18)
+#define OMAP4_GPMC_A17_DUPLICATEWAKEUPEVENT_SHIFT 17
+#define OMAP4_GPMC_A17_DUPLICATEWAKEUPEVENT_MASK (1 << 17)
+#define OMAP4_GPMC_A16_DUPLICATEWAKEUPEVENT_SHIFT 16
+#define OMAP4_GPMC_A16_DUPLICATEWAKEUPEVENT_MASK (1 << 16)
+#define OMAP4_GPMC_AD15_DUPLICATEWAKEUPEVENT_SHIFT 15
+#define OMAP4_GPMC_AD15_DUPLICATEWAKEUPEVENT_MASK (1 << 15)
+#define OMAP4_GPMC_AD14_DUPLICATEWAKEUPEVENT_SHIFT 14
+#define OMAP4_GPMC_AD14_DUPLICATEWAKEUPEVENT_MASK (1 << 14)
+#define OMAP4_GPMC_AD13_DUPLICATEWAKEUPEVENT_SHIFT 13
+#define OMAP4_GPMC_AD13_DUPLICATEWAKEUPEVENT_MASK (1 << 13)
+#define OMAP4_GPMC_AD12_DUPLICATEWAKEUPEVENT_SHIFT 12
+#define OMAP4_GPMC_AD12_DUPLICATEWAKEUPEVENT_MASK (1 << 12)
+#define OMAP4_GPMC_AD11_DUPLICATEWAKEUPEVENT_SHIFT 11
+#define OMAP4_GPMC_AD11_DUPLICATEWAKEUPEVENT_MASK (1 << 11)
+#define OMAP4_GPMC_AD10_DUPLICATEWAKEUPEVENT_SHIFT 10
+#define OMAP4_GPMC_AD10_DUPLICATEWAKEUPEVENT_MASK (1 << 10)
+#define OMAP4_GPMC_AD9_DUPLICATEWAKEUPEVENT_SHIFT 9
+#define OMAP4_GPMC_AD9_DUPLICATEWAKEUPEVENT_MASK (1 << 9)
+#define OMAP4_GPMC_AD8_DUPLICATEWAKEUPEVENT_SHIFT 8
+#define OMAP4_GPMC_AD8_DUPLICATEWAKEUPEVENT_MASK (1 << 8)
+#define OMAP4_GPMC_AD7_DUPLICATEWAKEUPEVENT_SHIFT 7
+#define OMAP4_GPMC_AD7_DUPLICATEWAKEUPEVENT_MASK (1 << 7)
+#define OMAP4_GPMC_AD6_DUPLICATEWAKEUPEVENT_SHIFT 6
+#define OMAP4_GPMC_AD6_DUPLICATEWAKEUPEVENT_MASK (1 << 6)
+#define OMAP4_GPMC_AD5_DUPLICATEWAKEUPEVENT_SHIFT 5
+#define OMAP4_GPMC_AD5_DUPLICATEWAKEUPEVENT_MASK (1 << 5)
+#define OMAP4_GPMC_AD4_DUPLICATEWAKEUPEVENT_SHIFT 4
+#define OMAP4_GPMC_AD4_DUPLICATEWAKEUPEVENT_MASK (1 << 4)
+#define OMAP4_GPMC_AD3_DUPLICATEWAKEUPEVENT_SHIFT 3
+#define OMAP4_GPMC_AD3_DUPLICATEWAKEUPEVENT_MASK (1 << 3)
+#define OMAP4_GPMC_AD2_DUPLICATEWAKEUPEVENT_SHIFT 2
+#define OMAP4_GPMC_AD2_DUPLICATEWAKEUPEVENT_MASK (1 << 2)
+#define OMAP4_GPMC_AD1_DUPLICATEWAKEUPEVENT_SHIFT 1
+#define OMAP4_GPMC_AD1_DUPLICATEWAKEUPEVENT_MASK (1 << 1)
+#define OMAP4_GPMC_AD0_DUPLICATEWAKEUPEVENT_SHIFT 0
+#define OMAP4_GPMC_AD0_DUPLICATEWAKEUPEVENT_MASK (1 << 0)
+
+/* PADCONF_WAKEUPEVENT_1 */
+#define OMAP4_CAM_STROBE_DUPLICATEWAKEUPEVENT_SHIFT 31
+#define OMAP4_CAM_STROBE_DUPLICATEWAKEUPEVENT_MASK (1 << 31)
+#define OMAP4_CAM_SHUTTER_DUPLICATEWAKEUPEVENT_SHIFT 30
+#define OMAP4_CAM_SHUTTER_DUPLICATEWAKEUPEVENT_MASK (1 << 30)
+#define OMAP4_CSI22_DY1_DUPLICATEWAKEUPEVENT_SHIFT 29
+#define OMAP4_CSI22_DY1_DUPLICATEWAKEUPEVENT_MASK (1 << 29)
+#define OMAP4_CSI22_DX1_DUPLICATEWAKEUPEVENT_SHIFT 28
+#define OMAP4_CSI22_DX1_DUPLICATEWAKEUPEVENT_MASK (1 << 28)
+#define OMAP4_CSI22_DY0_DUPLICATEWAKEUPEVENT_SHIFT 27
+#define OMAP4_CSI22_DY0_DUPLICATEWAKEUPEVENT_MASK (1 << 27)
+#define OMAP4_CSI22_DX0_DUPLICATEWAKEUPEVENT_SHIFT 26
+#define OMAP4_CSI22_DX0_DUPLICATEWAKEUPEVENT_MASK (1 << 26)
+#define OMAP4_CSI21_DY4_DUPLICATEWAKEUPEVENT_SHIFT 25
+#define OMAP4_CSI21_DY4_DUPLICATEWAKEUPEVENT_MASK (1 << 25)
+#define OMAP4_CSI21_DX4_DUPLICATEWAKEUPEVENT_SHIFT 24
+#define OMAP4_CSI21_DX4_DUPLICATEWAKEUPEVENT_MASK (1 << 24)
+#define OMAP4_CSI21_DY3_DUPLICATEWAKEUPEVENT_SHIFT 23
+#define OMAP4_CSI21_DY3_DUPLICATEWAKEUPEVENT_MASK (1 << 23)
+#define OMAP4_CSI21_DX3_DUPLICATEWAKEUPEVENT_SHIFT 22
+#define OMAP4_CSI21_DX3_DUPLICATEWAKEUPEVENT_MASK (1 << 22)
+#define OMAP4_CSI21_DY2_DUPLICATEWAKEUPEVENT_SHIFT 21
+#define OMAP4_CSI21_DY2_DUPLICATEWAKEUPEVENT_MASK (1 << 21)
+#define OMAP4_CSI21_DX2_DUPLICATEWAKEUPEVENT_SHIFT 20
+#define OMAP4_CSI21_DX2_DUPLICATEWAKEUPEVENT_MASK (1 << 20)
+#define OMAP4_CSI21_DY1_DUPLICATEWAKEUPEVENT_SHIFT 19
+#define OMAP4_CSI21_DY1_DUPLICATEWAKEUPEVENT_MASK (1 << 19)
+#define OMAP4_CSI21_DX1_DUPLICATEWAKEUPEVENT_SHIFT 18
+#define OMAP4_CSI21_DX1_DUPLICATEWAKEUPEVENT_MASK (1 << 18)
+#define OMAP4_CSI21_DY0_DUPLICATEWAKEUPEVENT_SHIFT 17
+#define OMAP4_CSI21_DY0_DUPLICATEWAKEUPEVENT_MASK (1 << 17)
+#define OMAP4_CSI21_DX0_DUPLICATEWAKEUPEVENT_SHIFT 16
+#define OMAP4_CSI21_DX0_DUPLICATEWAKEUPEVENT_MASK (1 << 16)
+#define OMAP4_HDMI_DDC_SDA_DUPLICATEWAKEUPEVENT_SHIFT 15
+#define OMAP4_HDMI_DDC_SDA_DUPLICATEWAKEUPEVENT_MASK (1 << 15)
+#define OMAP4_HDMI_DDC_SCL_DUPLICATEWAKEUPEVENT_SHIFT 14
+#define OMAP4_HDMI_DDC_SCL_DUPLICATEWAKEUPEVENT_MASK (1 << 14)
+#define OMAP4_HDMI_CEC_DUPLICATEWAKEUPEVENT_SHIFT 13
+#define OMAP4_HDMI_CEC_DUPLICATEWAKEUPEVENT_MASK (1 << 13)
+#define OMAP4_HDMI_HPD_DUPLICATEWAKEUPEVENT_SHIFT 12
+#define OMAP4_HDMI_HPD_DUPLICATEWAKEUPEVENT_MASK (1 << 12)
+#define OMAP4_C2C_DATA15_DUPLICATEWAKEUPEVENT_SHIFT 11
+#define OMAP4_C2C_DATA15_DUPLICATEWAKEUPEVENT_MASK (1 << 11)
+#define OMAP4_C2C_DATA14_DUPLICATEWAKEUPEVENT_SHIFT 10
+#define OMAP4_C2C_DATA14_DUPLICATEWAKEUPEVENT_MASK (1 << 10)
+#define OMAP4_C2C_DATA13_DUPLICATEWAKEUPEVENT_SHIFT 9
+#define OMAP4_C2C_DATA13_DUPLICATEWAKEUPEVENT_MASK (1 << 9)
+#define OMAP4_C2C_DATA12_DUPLICATEWAKEUPEVENT_SHIFT 8
+#define OMAP4_C2C_DATA12_DUPLICATEWAKEUPEVENT_MASK (1 << 8)
+#define OMAP4_C2C_DATA11_DUPLICATEWAKEUPEVENT_SHIFT 7
+#define OMAP4_C2C_DATA11_DUPLICATEWAKEUPEVENT_MASK (1 << 7)
+#define OMAP4_GPMC_WAIT1_DUPLICATEWAKEUPEVENT_SHIFT 6
+#define OMAP4_GPMC_WAIT1_DUPLICATEWAKEUPEVENT_MASK (1 << 6)
+#define OMAP4_GPMC_WAIT0_DUPLICATEWAKEUPEVENT_SHIFT 5
+#define OMAP4_GPMC_WAIT0_DUPLICATEWAKEUPEVENT_MASK (1 << 5)
+#define OMAP4_GPMC_NBE1_DUPLICATEWAKEUPEVENT_SHIFT 4
+#define OMAP4_GPMC_NBE1_DUPLICATEWAKEUPEVENT_MASK (1 << 4)
+#define OMAP4_GPMC_NBE0_CLE_DUPLICATEWAKEUPEVENT_SHIFT 3
+#define OMAP4_GPMC_NBE0_CLE_DUPLICATEWAKEUPEVENT_MASK (1 << 3)
+#define OMAP4_GPMC_NWE_DUPLICATEWAKEUPEVENT_SHIFT 2
+#define OMAP4_GPMC_NWE_DUPLICATEWAKEUPEVENT_MASK (1 << 2)
+#define OMAP4_GPMC_NOE_DUPLICATEWAKEUPEVENT_SHIFT 1
+#define OMAP4_GPMC_NOE_DUPLICATEWAKEUPEVENT_MASK (1 << 1)
+#define OMAP4_GPMC_NADV_ALE_DUPLICATEWAKEUPEVENT_SHIFT 0
+#define OMAP4_GPMC_NADV_ALE_DUPLICATEWAKEUPEVENT_MASK (1 << 0)
+
+/* PADCONF_WAKEUPEVENT_2 */
+#define OMAP4_ABE_MCBSP1_CLKX_DUPLICATEWAKEUPEVENT_SHIFT 31
+#define OMAP4_ABE_MCBSP1_CLKX_DUPLICATEWAKEUPEVENT_MASK (1 << 31)
+#define OMAP4_ABE_MCBSP2_FSX_DUPLICATEWAKEUPEVENT_SHIFT 30
+#define OMAP4_ABE_MCBSP2_FSX_DUPLICATEWAKEUPEVENT_MASK (1 << 30)
+#define OMAP4_ABE_MCBSP2_DX_DUPLICATEWAKEUPEVENT_SHIFT 29
+#define OMAP4_ABE_MCBSP2_DX_DUPLICATEWAKEUPEVENT_MASK (1 << 29)
+#define OMAP4_ABE_MCBSP2_DR_DUPLICATEWAKEUPEVENT_SHIFT 28
+#define OMAP4_ABE_MCBSP2_DR_DUPLICATEWAKEUPEVENT_MASK (1 << 28)
+#define OMAP4_ABE_MCBSP2_CLKX_DUPLICATEWAKEUPEVENT_SHIFT 27
+#define OMAP4_ABE_MCBSP2_CLKX_DUPLICATEWAKEUPEVENT_MASK (1 << 27)
+#define OMAP4_SDMMC1_DAT7_DUPLICATEWAKEUPEVENT_SHIFT 26
+#define OMAP4_SDMMC1_DAT7_DUPLICATEWAKEUPEVENT_MASK (1 << 26)
+#define OMAP4_SDMMC1_DAT6_DUPLICATEWAKEUPEVENT_SHIFT 25
+#define OMAP4_SDMMC1_DAT6_DUPLICATEWAKEUPEVENT_MASK (1 << 25)
+#define OMAP4_SDMMC1_DAT5_DUPLICATEWAKEUPEVENT_SHIFT 24
+#define OMAP4_SDMMC1_DAT5_DUPLICATEWAKEUPEVENT_MASK (1 << 24)
+#define OMAP4_SDMMC1_DAT4_DUPLICATEWAKEUPEVENT_SHIFT 23
+#define OMAP4_SDMMC1_DAT4_DUPLICATEWAKEUPEVENT_MASK (1 << 23)
+#define OMAP4_SDMMC1_DAT3_DUPLICATEWAKEUPEVENT_SHIFT 22
+#define OMAP4_SDMMC1_DAT3_DUPLICATEWAKEUPEVENT_MASK (1 << 22)
+#define OMAP4_SDMMC1_DAT2_DUPLICATEWAKEUPEVENT_SHIFT 21
+#define OMAP4_SDMMC1_DAT2_DUPLICATEWAKEUPEVENT_MASK (1 << 21)
+#define OMAP4_SDMMC1_DAT1_DUPLICATEWAKEUPEVENT_SHIFT 20
+#define OMAP4_SDMMC1_DAT1_DUPLICATEWAKEUPEVENT_MASK (1 << 20)
+#define OMAP4_SDMMC1_DAT0_DUPLICATEWAKEUPEVENT_SHIFT 19
+#define OMAP4_SDMMC1_DAT0_DUPLICATEWAKEUPEVENT_MASK (1 << 19)
+#define OMAP4_SDMMC1_CMD_DUPLICATEWAKEUPEVENT_SHIFT 18
+#define OMAP4_SDMMC1_CMD_DUPLICATEWAKEUPEVENT_MASK (1 << 18)
+#define OMAP4_SDMMC1_CLK_DUPLICATEWAKEUPEVENT_SHIFT 17
+#define OMAP4_SDMMC1_CLK_DUPLICATEWAKEUPEVENT_MASK (1 << 17)
+#define OMAP4_USBC1_ICUSB_DM_DUPLICATEWAKEUPEVENT_SHIFT 16
+#define OMAP4_USBC1_ICUSB_DM_DUPLICATEWAKEUPEVENT_MASK (1 << 16)
+#define OMAP4_USBC1_ICUSB_DP_DUPLICATEWAKEUPEVENT_SHIFT 15
+#define OMAP4_USBC1_ICUSB_DP_DUPLICATEWAKEUPEVENT_MASK (1 << 15)
+#define OMAP4_USBB1_HSIC_STROBE_DUPLICATEWAKEUPEVENT_SHIFT 14
+#define OMAP4_USBB1_HSIC_STROBE_DUPLICATEWAKEUPEVENT_MASK (1 << 14)
+#define OMAP4_USBB1_HSIC_DATA_DUPLICATEWAKEUPEVENT_SHIFT 13
+#define OMAP4_USBB1_HSIC_DATA_DUPLICATEWAKEUPEVENT_MASK (1 << 13)
+#define OMAP4_USBB1_ULPITLL_DAT7_DUPLICATEWAKEUPEVENT_SHIFT 12
+#define OMAP4_USBB1_ULPITLL_DAT7_DUPLICATEWAKEUPEVENT_MASK (1 << 12)
+#define OMAP4_USBB1_ULPITLL_DAT6_DUPLICATEWAKEUPEVENT_SHIFT 11
+#define OMAP4_USBB1_ULPITLL_DAT6_DUPLICATEWAKEUPEVENT_MASK (1 << 11)
+#define OMAP4_USBB1_ULPITLL_DAT5_DUPLICATEWAKEUPEVENT_SHIFT 10
+#define OMAP4_USBB1_ULPITLL_DAT5_DUPLICATEWAKEUPEVENT_MASK (1 << 10)
+#define OMAP4_USBB1_ULPITLL_DAT4_DUPLICATEWAKEUPEVENT_SHIFT 9
+#define OMAP4_USBB1_ULPITLL_DAT4_DUPLICATEWAKEUPEVENT_MASK (1 << 9)
+#define OMAP4_USBB1_ULPITLL_DAT3_DUPLICATEWAKEUPEVENT_SHIFT 8
+#define OMAP4_USBB1_ULPITLL_DAT3_DUPLICATEWAKEUPEVENT_MASK (1 << 8)
+#define OMAP4_USBB1_ULPITLL_DAT2_DUPLICATEWAKEUPEVENT_SHIFT 7
+#define OMAP4_USBB1_ULPITLL_DAT2_DUPLICATEWAKEUPEVENT_MASK (1 << 7)
+#define OMAP4_USBB1_ULPITLL_DAT1_DUPLICATEWAKEUPEVENT_SHIFT 6
+#define OMAP4_USBB1_ULPITLL_DAT1_DUPLICATEWAKEUPEVENT_MASK (1 << 6)
+#define OMAP4_USBB1_ULPITLL_DAT0_DUPLICATEWAKEUPEVENT_SHIFT 5
+#define OMAP4_USBB1_ULPITLL_DAT0_DUPLICATEWAKEUPEVENT_MASK (1 << 5)
+#define OMAP4_USBB1_ULPITLL_NXT_DUPLICATEWAKEUPEVENT_SHIFT 4
+#define OMAP4_USBB1_ULPITLL_NXT_DUPLICATEWAKEUPEVENT_MASK (1 << 4)
+#define OMAP4_USBB1_ULPITLL_DIR_DUPLICATEWAKEUPEVENT_SHIFT 3
+#define OMAP4_USBB1_ULPITLL_DIR_DUPLICATEWAKEUPEVENT_MASK (1 << 3)
+#define OMAP4_USBB1_ULPITLL_STP_DUPLICATEWAKEUPEVENT_SHIFT 2
+#define OMAP4_USBB1_ULPITLL_STP_DUPLICATEWAKEUPEVENT_MASK (1 << 2)
+#define OMAP4_USBB1_ULPITLL_CLK_DUPLICATEWAKEUPEVENT_SHIFT 1
+#define OMAP4_USBB1_ULPITLL_CLK_DUPLICATEWAKEUPEVENT_MASK (1 << 1)
+#define OMAP4_CAM_GLOBALRESET_DUPLICATEWAKEUPEVENT_SHIFT 0
+#define OMAP4_CAM_GLOBALRESET_DUPLICATEWAKEUPEVENT_MASK (1 << 0)
+
+/* PADCONF_WAKEUPEVENT_3 */
+#define OMAP4_MCSPI1_CS3_DUPLICATEWAKEUPEVENT_SHIFT 31
+#define OMAP4_MCSPI1_CS3_DUPLICATEWAKEUPEVENT_MASK (1 << 31)
+#define OMAP4_MCSPI1_CS2_DUPLICATEWAKEUPEVENT_SHIFT 30
+#define OMAP4_MCSPI1_CS2_DUPLICATEWAKEUPEVENT_MASK (1 << 30)
+#define OMAP4_MCSPI1_CS1_DUPLICATEWAKEUPEVENT_SHIFT 29
+#define OMAP4_MCSPI1_CS1_DUPLICATEWAKEUPEVENT_MASK (1 << 29)
+#define OMAP4_MCSPI1_CS0_DUPLICATEWAKEUPEVENT_SHIFT 28
+#define OMAP4_MCSPI1_CS0_DUPLICATEWAKEUPEVENT_MASK (1 << 28)
+#define OMAP4_MCSPI1_SIMO_DUPLICATEWAKEUPEVENT_SHIFT 27
+#define OMAP4_MCSPI1_SIMO_DUPLICATEWAKEUPEVENT_MASK (1 << 27)
+#define OMAP4_MCSPI1_SOMI_DUPLICATEWAKEUPEVENT_SHIFT 26
+#define OMAP4_MCSPI1_SOMI_DUPLICATEWAKEUPEVENT_MASK (1 << 26)
+#define OMAP4_MCSPI1_CLK_DUPLICATEWAKEUPEVENT_SHIFT 25
+#define OMAP4_MCSPI1_CLK_DUPLICATEWAKEUPEVENT_MASK (1 << 25)
+#define OMAP4_I2C4_SDA_DUPLICATEWAKEUPEVENT_SHIFT 24
+#define OMAP4_I2C4_SDA_DUPLICATEWAKEUPEVENT_MASK (1 << 24)
+#define OMAP4_I2C4_SCL_DUPLICATEWAKEUPEVENT_SHIFT 23
+#define OMAP4_I2C4_SCL_DUPLICATEWAKEUPEVENT_MASK (1 << 23)
+#define OMAP4_I2C3_SDA_DUPLICATEWAKEUPEVENT_SHIFT 22
+#define OMAP4_I2C3_SDA_DUPLICATEWAKEUPEVENT_MASK (1 << 22)
+#define OMAP4_I2C3_SCL_DUPLICATEWAKEUPEVENT_SHIFT 21
+#define OMAP4_I2C3_SCL_DUPLICATEWAKEUPEVENT_MASK (1 << 21)
+#define OMAP4_I2C2_SDA_DUPLICATEWAKEUPEVENT_SHIFT 20
+#define OMAP4_I2C2_SDA_DUPLICATEWAKEUPEVENT_MASK (1 << 20)
+#define OMAP4_I2C2_SCL_DUPLICATEWAKEUPEVENT_SHIFT 19
+#define OMAP4_I2C2_SCL_DUPLICATEWAKEUPEVENT_MASK (1 << 19)
+#define OMAP4_I2C1_SDA_DUPLICATEWAKEUPEVENT_SHIFT 18
+#define OMAP4_I2C1_SDA_DUPLICATEWAKEUPEVENT_MASK (1 << 18)
+#define OMAP4_I2C1_SCL_DUPLICATEWAKEUPEVENT_SHIFT 17
+#define OMAP4_I2C1_SCL_DUPLICATEWAKEUPEVENT_MASK (1 << 17)
+#define OMAP4_HDQ_SIO_DUPLICATEWAKEUPEVENT_SHIFT 16
+#define OMAP4_HDQ_SIO_DUPLICATEWAKEUPEVENT_MASK (1 << 16)
+#define OMAP4_UART2_TX_DUPLICATEWAKEUPEVENT_SHIFT 15
+#define OMAP4_UART2_TX_DUPLICATEWAKEUPEVENT_MASK (1 << 15)
+#define OMAP4_UART2_RX_DUPLICATEWAKEUPEVENT_SHIFT 14
+#define OMAP4_UART2_RX_DUPLICATEWAKEUPEVENT_MASK (1 << 14)
+#define OMAP4_UART2_RTS_DUPLICATEWAKEUPEVENT_SHIFT 13
+#define OMAP4_UART2_RTS_DUPLICATEWAKEUPEVENT_MASK (1 << 13)
+#define OMAP4_UART2_CTS_DUPLICATEWAKEUPEVENT_SHIFT 12
+#define OMAP4_UART2_CTS_DUPLICATEWAKEUPEVENT_MASK (1 << 12)
+#define OMAP4_ABE_DMIC_DIN3_DUPLICATEWAKEUPEVENT_SHIFT 11
+#define OMAP4_ABE_DMIC_DIN3_DUPLICATEWAKEUPEVENT_MASK (1 << 11)
+#define OMAP4_ABE_DMIC_DIN2_DUPLICATEWAKEUPEVENT_SHIFT 10
+#define OMAP4_ABE_DMIC_DIN2_DUPLICATEWAKEUPEVENT_MASK (1 << 10)
+#define OMAP4_ABE_DMIC_DIN1_DUPLICATEWAKEUPEVENT_SHIFT 9
+#define OMAP4_ABE_DMIC_DIN1_DUPLICATEWAKEUPEVENT_MASK (1 << 9)
+#define OMAP4_ABE_DMIC_CLK1_DUPLICATEWAKEUPEVENT_SHIFT 8
+#define OMAP4_ABE_DMIC_CLK1_DUPLICATEWAKEUPEVENT_MASK (1 << 8)
+#define OMAP4_ABE_CLKS_DUPLICATEWAKEUPEVENT_SHIFT 7
+#define OMAP4_ABE_CLKS_DUPLICATEWAKEUPEVENT_MASK (1 << 7)
+#define OMAP4_ABE_PDM_LB_CLK_DUPLICATEWAKEUPEVENT_SHIFT 6
+#define OMAP4_ABE_PDM_LB_CLK_DUPLICATEWAKEUPEVENT_MASK (1 << 6)
+#define OMAP4_ABE_PDM_FRAME_DUPLICATEWAKEUPEVENT_SHIFT 5
+#define OMAP4_ABE_PDM_FRAME_DUPLICATEWAKEUPEVENT_MASK (1 << 5)
+#define OMAP4_ABE_PDM_DL_DATA_DUPLICATEWAKEUPEVENT_SHIFT 4
+#define OMAP4_ABE_PDM_DL_DATA_DUPLICATEWAKEUPEVENT_MASK (1 << 4)
+#define OMAP4_ABE_PDM_UL_DATA_DUPLICATEWAKEUPEVENT_SHIFT 3
+#define OMAP4_ABE_PDM_UL_DATA_DUPLICATEWAKEUPEVENT_MASK (1 << 3)
+#define OMAP4_ABE_MCBSP1_FSX_DUPLICATEWAKEUPEVENT_SHIFT 2
+#define OMAP4_ABE_MCBSP1_FSX_DUPLICATEWAKEUPEVENT_MASK (1 << 2)
+#define OMAP4_ABE_MCBSP1_DX_DUPLICATEWAKEUPEVENT_SHIFT 1
+#define OMAP4_ABE_MCBSP1_DX_DUPLICATEWAKEUPEVENT_MASK (1 << 1)
+#define OMAP4_ABE_MCBSP1_DR_DUPLICATEWAKEUPEVENT_SHIFT 0
+#define OMAP4_ABE_MCBSP1_DR_DUPLICATEWAKEUPEVENT_MASK (1 << 0)
+
+/* PADCONF_WAKEUPEVENT_4 */
+#define OMAP4_UNIPRO_TY0_DUPLICATEWAKEUPEVENT_SHIFT 31
+#define OMAP4_UNIPRO_TY0_DUPLICATEWAKEUPEVENT_MASK (1 << 31)
+#define OMAP4_UNIPRO_TX0_DUPLICATEWAKEUPEVENT_SHIFT 30
+#define OMAP4_UNIPRO_TX0_DUPLICATEWAKEUPEVENT_MASK (1 << 30)
+#define OMAP4_USBB2_HSIC_STROBE_DUPLICATEWAKEUPEVENT_SHIFT 29
+#define OMAP4_USBB2_HSIC_STROBE_DUPLICATEWAKEUPEVENT_MASK (1 << 29)
+#define OMAP4_USBB2_HSIC_DATA_DUPLICATEWAKEUPEVENT_SHIFT 28
+#define OMAP4_USBB2_HSIC_DATA_DUPLICATEWAKEUPEVENT_MASK (1 << 28)
+#define OMAP4_USBB2_ULPITLL_DAT7_DUPLICATEWAKEUPEVENT_SHIFT 27
+#define OMAP4_USBB2_ULPITLL_DAT7_DUPLICATEWAKEUPEVENT_MASK (1 << 27)
+#define OMAP4_USBB2_ULPITLL_DAT6_DUPLICATEWAKEUPEVENT_SHIFT 26
+#define OMAP4_USBB2_ULPITLL_DAT6_DUPLICATEWAKEUPEVENT_MASK (1 << 26)
+#define OMAP4_USBB2_ULPITLL_DAT5_DUPLICATEWAKEUPEVENT_SHIFT 25
+#define OMAP4_USBB2_ULPITLL_DAT5_DUPLICATEWAKEUPEVENT_MASK (1 << 25)
+#define OMAP4_USBB2_ULPITLL_DAT4_DUPLICATEWAKEUPEVENT_SHIFT 24
+#define OMAP4_USBB2_ULPITLL_DAT4_DUPLICATEWAKEUPEVENT_MASK (1 << 24)
+#define OMAP4_USBB2_ULPITLL_DAT3_DUPLICATEWAKEUPEVENT_SHIFT 23
+#define OMAP4_USBB2_ULPITLL_DAT3_DUPLICATEWAKEUPEVENT_MASK (1 << 23)
+#define OMAP4_USBB2_ULPITLL_DAT2_DUPLICATEWAKEUPEVENT_SHIFT 22
+#define OMAP4_USBB2_ULPITLL_DAT2_DUPLICATEWAKEUPEVENT_MASK (1 << 22)
+#define OMAP4_USBB2_ULPITLL_DAT1_DUPLICATEWAKEUPEVENT_SHIFT 21
+#define OMAP4_USBB2_ULPITLL_DAT1_DUPLICATEWAKEUPEVENT_MASK (1 << 21)
+#define OMAP4_USBB2_ULPITLL_DAT0_DUPLICATEWAKEUPEVENT_SHIFT 20
+#define OMAP4_USBB2_ULPITLL_DAT0_DUPLICATEWAKEUPEVENT_MASK (1 << 20)
+#define OMAP4_USBB2_ULPITLL_NXT_DUPLICATEWAKEUPEVENT_SHIFT 19
+#define OMAP4_USBB2_ULPITLL_NXT_DUPLICATEWAKEUPEVENT_MASK (1 << 19)
+#define OMAP4_USBB2_ULPITLL_DIR_DUPLICATEWAKEUPEVENT_SHIFT 18
+#define OMAP4_USBB2_ULPITLL_DIR_DUPLICATEWAKEUPEVENT_MASK (1 << 18)
+#define OMAP4_USBB2_ULPITLL_STP_DUPLICATEWAKEUPEVENT_SHIFT 17
+#define OMAP4_USBB2_ULPITLL_STP_DUPLICATEWAKEUPEVENT_MASK (1 << 17)
+#define OMAP4_USBB2_ULPITLL_CLK_DUPLICATEWAKEUPEVENT_SHIFT 16
+#define OMAP4_USBB2_ULPITLL_CLK_DUPLICATEWAKEUPEVENT_MASK (1 << 16)
+#define OMAP4_UART4_TX_DUPLICATEWAKEUPEVENT_SHIFT 15
+#define OMAP4_UART4_TX_DUPLICATEWAKEUPEVENT_MASK (1 << 15)
+#define OMAP4_UART4_RX_DUPLICATEWAKEUPEVENT_SHIFT 14
+#define OMAP4_UART4_RX_DUPLICATEWAKEUPEVENT_MASK (1 << 14)
+#define OMAP4_MCSPI4_CS0_DUPLICATEWAKEUPEVENT_SHIFT 13
+#define OMAP4_MCSPI4_CS0_DUPLICATEWAKEUPEVENT_MASK (1 << 13)
+#define OMAP4_MCSPI4_SOMI_DUPLICATEWAKEUPEVENT_SHIFT 12
+#define OMAP4_MCSPI4_SOMI_DUPLICATEWAKEUPEVENT_MASK (1 << 12)
+#define OMAP4_MCSPI4_SIMO_DUPLICATEWAKEUPEVENT_SHIFT 11
+#define OMAP4_MCSPI4_SIMO_DUPLICATEWAKEUPEVENT_MASK (1 << 11)
+#define OMAP4_MCSPI4_CLK_DUPLICATEWAKEUPEVENT_SHIFT 10
+#define OMAP4_MCSPI4_CLK_DUPLICATEWAKEUPEVENT_MASK (1 << 10)
+#define OMAP4_SDMMC5_DAT3_DUPLICATEWAKEUPEVENT_SHIFT 9
+#define OMAP4_SDMMC5_DAT3_DUPLICATEWAKEUPEVENT_MASK (1 << 9)
+#define OMAP4_SDMMC5_DAT2_DUPLICATEWAKEUPEVENT_SHIFT 8
+#define OMAP4_SDMMC5_DAT2_DUPLICATEWAKEUPEVENT_MASK (1 << 8)
+#define OMAP4_SDMMC5_DAT1_DUPLICATEWAKEUPEVENT_SHIFT 7
+#define OMAP4_SDMMC5_DAT1_DUPLICATEWAKEUPEVENT_MASK (1 << 7)
+#define OMAP4_SDMMC5_DAT0_DUPLICATEWAKEUPEVENT_SHIFT 6
+#define OMAP4_SDMMC5_DAT0_DUPLICATEWAKEUPEVENT_MASK (1 << 6)
+#define OMAP4_SDMMC5_CMD_DUPLICATEWAKEUPEVENT_SHIFT 5
+#define OMAP4_SDMMC5_CMD_DUPLICATEWAKEUPEVENT_MASK (1 << 5)
+#define OMAP4_SDMMC5_CLK_DUPLICATEWAKEUPEVENT_SHIFT 4
+#define OMAP4_SDMMC5_CLK_DUPLICATEWAKEUPEVENT_MASK (1 << 4)
+#define OMAP4_UART3_TX_IRTX_DUPLICATEWAKEUPEVENT_SHIFT 3
+#define OMAP4_UART3_TX_IRTX_DUPLICATEWAKEUPEVENT_MASK (1 << 3)
+#define OMAP4_UART3_RX_IRRX_DUPLICATEWAKEUPEVENT_SHIFT 2
+#define OMAP4_UART3_RX_IRRX_DUPLICATEWAKEUPEVENT_MASK (1 << 2)
+#define OMAP4_UART3_RTS_SD_DUPLICATEWAKEUPEVENT_SHIFT 1
+#define OMAP4_UART3_RTS_SD_DUPLICATEWAKEUPEVENT_MASK (1 << 1)
+#define OMAP4_UART3_CTS_RCTX_DUPLICATEWAKEUPEVENT_SHIFT 0
+#define OMAP4_UART3_CTS_RCTX_DUPLICATEWAKEUPEVENT_MASK (1 << 0)
+
+/* PADCONF_WAKEUPEVENT_5 */
+#define OMAP4_DPM_EMU11_DUPLICATEWAKEUPEVENT_SHIFT 31
+#define OMAP4_DPM_EMU11_DUPLICATEWAKEUPEVENT_MASK (1 << 31)
+#define OMAP4_DPM_EMU10_DUPLICATEWAKEUPEVENT_SHIFT 30
+#define OMAP4_DPM_EMU10_DUPLICATEWAKEUPEVENT_MASK (1 << 30)
+#define OMAP4_DPM_EMU9_DUPLICATEWAKEUPEVENT_SHIFT 29
+#define OMAP4_DPM_EMU9_DUPLICATEWAKEUPEVENT_MASK (1 << 29)
+#define OMAP4_DPM_EMU8_DUPLICATEWAKEUPEVENT_SHIFT 28
+#define OMAP4_DPM_EMU8_DUPLICATEWAKEUPEVENT_MASK (1 << 28)
+#define OMAP4_DPM_EMU7_DUPLICATEWAKEUPEVENT_SHIFT 27
+#define OMAP4_DPM_EMU7_DUPLICATEWAKEUPEVENT_MASK (1 << 27)
+#define OMAP4_DPM_EMU6_DUPLICATEWAKEUPEVENT_SHIFT 26
+#define OMAP4_DPM_EMU6_DUPLICATEWAKEUPEVENT_MASK (1 << 26)
+#define OMAP4_DPM_EMU5_DUPLICATEWAKEUPEVENT_SHIFT 25
+#define OMAP4_DPM_EMU5_DUPLICATEWAKEUPEVENT_MASK (1 << 25)
+#define OMAP4_DPM_EMU4_DUPLICATEWAKEUPEVENT_SHIFT 24
+#define OMAP4_DPM_EMU4_DUPLICATEWAKEUPEVENT_MASK (1 << 24)
+#define OMAP4_DPM_EMU3_DUPLICATEWAKEUPEVENT_SHIFT 23
+#define OMAP4_DPM_EMU3_DUPLICATEWAKEUPEVENT_MASK (1 << 23)
+#define OMAP4_DPM_EMU2_DUPLICATEWAKEUPEVENT_SHIFT 22
+#define OMAP4_DPM_EMU2_DUPLICATEWAKEUPEVENT_MASK (1 << 22)
+#define OMAP4_DPM_EMU1_DUPLICATEWAKEUPEVENT_SHIFT 21
+#define OMAP4_DPM_EMU1_DUPLICATEWAKEUPEVENT_MASK (1 << 21)
+#define OMAP4_DPM_EMU0_DUPLICATEWAKEUPEVENT_SHIFT 20
+#define OMAP4_DPM_EMU0_DUPLICATEWAKEUPEVENT_MASK (1 << 20)
+#define OMAP4_SYS_BOOT5_DUPLICATEWAKEUPEVENT_SHIFT 19
+#define OMAP4_SYS_BOOT5_DUPLICATEWAKEUPEVENT_MASK (1 << 19)
+#define OMAP4_SYS_BOOT4_DUPLICATEWAKEUPEVENT_SHIFT 18
+#define OMAP4_SYS_BOOT4_DUPLICATEWAKEUPEVENT_MASK (1 << 18)
+#define OMAP4_SYS_BOOT3_DUPLICATEWAKEUPEVENT_SHIFT 17
+#define OMAP4_SYS_BOOT3_DUPLICATEWAKEUPEVENT_MASK (1 << 17)
+#define OMAP4_SYS_BOOT2_DUPLICATEWAKEUPEVENT_SHIFT 16
+#define OMAP4_SYS_BOOT2_DUPLICATEWAKEUPEVENT_MASK (1 << 16)
+#define OMAP4_SYS_BOOT1_DUPLICATEWAKEUPEVENT_SHIFT 15
+#define OMAP4_SYS_BOOT1_DUPLICATEWAKEUPEVENT_MASK (1 << 15)
+#define OMAP4_SYS_BOOT0_DUPLICATEWAKEUPEVENT_SHIFT 14
+#define OMAP4_SYS_BOOT0_DUPLICATEWAKEUPEVENT_MASK (1 << 14)
+#define OMAP4_SYS_NIRQ2_DUPLICATEWAKEUPEVENT_SHIFT 13
+#define OMAP4_SYS_NIRQ2_DUPLICATEWAKEUPEVENT_MASK (1 << 13)
+#define OMAP4_SYS_NIRQ1_DUPLICATEWAKEUPEVENT_SHIFT 12
+#define OMAP4_SYS_NIRQ1_DUPLICATEWAKEUPEVENT_MASK (1 << 12)
+#define OMAP4_FREF_CLK2_OUT_DUPLICATEWAKEUPEVENT_SHIFT 11
+#define OMAP4_FREF_CLK2_OUT_DUPLICATEWAKEUPEVENT_MASK (1 << 11)
+#define OMAP4_FREF_CLK1_OUT_DUPLICATEWAKEUPEVENT_SHIFT 10
+#define OMAP4_FREF_CLK1_OUT_DUPLICATEWAKEUPEVENT_MASK (1 << 10)
+#define OMAP4_UNIPRO_RY2_DUPLICATEWAKEUPEVENT_SHIFT 9
+#define OMAP4_UNIPRO_RY2_DUPLICATEWAKEUPEVENT_MASK (1 << 9)
+#define OMAP4_UNIPRO_RX2_DUPLICATEWAKEUPEVENT_SHIFT 8
+#define OMAP4_UNIPRO_RX2_DUPLICATEWAKEUPEVENT_MASK (1 << 8)
+#define OMAP4_UNIPRO_RY1_DUPLICATEWAKEUPEVENT_SHIFT 7
+#define OMAP4_UNIPRO_RY1_DUPLICATEWAKEUPEVENT_MASK (1 << 7)
+#define OMAP4_UNIPRO_RX1_DUPLICATEWAKEUPEVENT_SHIFT 6
+#define OMAP4_UNIPRO_RX1_DUPLICATEWAKEUPEVENT_MASK (1 << 6)
+#define OMAP4_UNIPRO_RY0_DUPLICATEWAKEUPEVENT_SHIFT 5
+#define OMAP4_UNIPRO_RY0_DUPLICATEWAKEUPEVENT_MASK (1 << 5)
+#define OMAP4_UNIPRO_RX0_DUPLICATEWAKEUPEVENT_SHIFT 4
+#define OMAP4_UNIPRO_RX0_DUPLICATEWAKEUPEVENT_MASK (1 << 4)
+#define OMAP4_UNIPRO_TY2_DUPLICATEWAKEUPEVENT_SHIFT 3
+#define OMAP4_UNIPRO_TY2_DUPLICATEWAKEUPEVENT_MASK (1 << 3)
+#define OMAP4_UNIPRO_TX2_DUPLICATEWAKEUPEVENT_SHIFT 2
+#define OMAP4_UNIPRO_TX2_DUPLICATEWAKEUPEVENT_MASK (1 << 2)
+#define OMAP4_UNIPRO_TY1_DUPLICATEWAKEUPEVENT_SHIFT 1
+#define OMAP4_UNIPRO_TY1_DUPLICATEWAKEUPEVENT_MASK (1 << 1)
+#define OMAP4_UNIPRO_TX1_DUPLICATEWAKEUPEVENT_SHIFT 0
+#define OMAP4_UNIPRO_TX1_DUPLICATEWAKEUPEVENT_MASK (1 << 0)
+
+/* PADCONF_WAKEUPEVENT_6 */
+#define OMAP4_DPM_EMU19_DUPLICATEWAKEUPEVENT_SHIFT 7
+#define OMAP4_DPM_EMU19_DUPLICATEWAKEUPEVENT_MASK (1 << 7)
+#define OMAP4_DPM_EMU18_DUPLICATEWAKEUPEVENT_SHIFT 6
+#define OMAP4_DPM_EMU18_DUPLICATEWAKEUPEVENT_MASK (1 << 6)
+#define OMAP4_DPM_EMU17_DUPLICATEWAKEUPEVENT_SHIFT 5
+#define OMAP4_DPM_EMU17_DUPLICATEWAKEUPEVENT_MASK (1 << 5)
+#define OMAP4_DPM_EMU16_DUPLICATEWAKEUPEVENT_SHIFT 4
+#define OMAP4_DPM_EMU16_DUPLICATEWAKEUPEVENT_MASK (1 << 4)
+#define OMAP4_DPM_EMU15_DUPLICATEWAKEUPEVENT_SHIFT 3
+#define OMAP4_DPM_EMU15_DUPLICATEWAKEUPEVENT_MASK (1 << 3)
+#define OMAP4_DPM_EMU14_DUPLICATEWAKEUPEVENT_SHIFT 2
+#define OMAP4_DPM_EMU14_DUPLICATEWAKEUPEVENT_MASK (1 << 2)
+#define OMAP4_DPM_EMU13_DUPLICATEWAKEUPEVENT_SHIFT 1
+#define OMAP4_DPM_EMU13_DUPLICATEWAKEUPEVENT_MASK (1 << 1)
+#define OMAP4_DPM_EMU12_DUPLICATEWAKEUPEVENT_SHIFT 0
+#define OMAP4_DPM_EMU12_DUPLICATEWAKEUPEVENT_MASK (1 << 0)
+
+/* CONTROL_PADCONF_GLOBAL */
+#define OMAP4_FORCE_OFFMODE_EN_SHIFT 31
+#define OMAP4_FORCE_OFFMODE_EN_MASK (1 << 31)
+
+/* CONTROL_PADCONF_MODE */
+#define OMAP4_VDDS_DV_BANK0_SHIFT 31
+#define OMAP4_VDDS_DV_BANK0_MASK (1 << 31)
+#define OMAP4_VDDS_DV_BANK1_SHIFT 30
+#define OMAP4_VDDS_DV_BANK1_MASK (1 << 30)
+#define OMAP4_VDDS_DV_BANK3_SHIFT 29
+#define OMAP4_VDDS_DV_BANK3_MASK (1 << 29)
+#define OMAP4_VDDS_DV_BANK4_SHIFT 28
+#define OMAP4_VDDS_DV_BANK4_MASK (1 << 28)
+#define OMAP4_VDDS_DV_BANK5_SHIFT 27
+#define OMAP4_VDDS_DV_BANK5_MASK (1 << 27)
+#define OMAP4_VDDS_DV_BANK6_SHIFT 26
+#define OMAP4_VDDS_DV_BANK6_MASK (1 << 26)
+#define OMAP4_VDDS_DV_C2C_SHIFT 25
+#define OMAP4_VDDS_DV_C2C_MASK (1 << 25)
+#define OMAP4_VDDS_DV_CAM_SHIFT 24
+#define OMAP4_VDDS_DV_CAM_MASK (1 << 24)
+#define OMAP4_VDDS_DV_GPMC_SHIFT 23
+#define OMAP4_VDDS_DV_GPMC_MASK (1 << 23)
+#define OMAP4_VDDS_DV_SDMMC2_SHIFT 22
+#define OMAP4_VDDS_DV_SDMMC2_MASK (1 << 22)
+
+/* CONTROL_SMART1IO_PADCONF_0 */
+#define OMAP4_ABE_DR0_SC_SHIFT 30
+#define OMAP4_ABE_DR0_SC_MASK (0x3 << 30)
+#define OMAP4_CAM_DR0_SC_SHIFT 28
+#define OMAP4_CAM_DR0_SC_MASK (0x3 << 28)
+#define OMAP4_FREF_DR2_SC_SHIFT 26
+#define OMAP4_FREF_DR2_SC_MASK (0x3 << 26)
+#define OMAP4_FREF_DR3_SC_SHIFT 24
+#define OMAP4_FREF_DR3_SC_MASK (0x3 << 24)
+#define OMAP4_GPIO_DR8_SC_SHIFT 22
+#define OMAP4_GPIO_DR8_SC_MASK (0x3 << 22)
+#define OMAP4_GPIO_DR9_SC_SHIFT 20
+#define OMAP4_GPIO_DR9_SC_MASK (0x3 << 20)
+#define OMAP4_GPMC_DR2_SC_SHIFT 18
+#define OMAP4_GPMC_DR2_SC_MASK (0x3 << 18)
+#define OMAP4_GPMC_DR3_SC_SHIFT 16
+#define OMAP4_GPMC_DR3_SC_MASK (0x3 << 16)
+#define OMAP4_GPMC_DR6_SC_SHIFT 14
+#define OMAP4_GPMC_DR6_SC_MASK (0x3 << 14)
+#define OMAP4_HDMI_DR0_SC_SHIFT 12
+#define OMAP4_HDMI_DR0_SC_MASK (0x3 << 12)
+#define OMAP4_MCSPI1_DR0_SC_SHIFT 10
+#define OMAP4_MCSPI1_DR0_SC_MASK (0x3 << 10)
+#define OMAP4_UART1_DR0_SC_SHIFT 8
+#define OMAP4_UART1_DR0_SC_MASK (0x3 << 8)
+#define OMAP4_UART3_DR0_SC_SHIFT 6
+#define OMAP4_UART3_DR0_SC_MASK (0x3 << 6)
+#define OMAP4_UART3_DR1_SC_SHIFT 4
+#define OMAP4_UART3_DR1_SC_MASK (0x3 << 4)
+#define OMAP4_UNIPRO_DR0_SC_SHIFT 2
+#define OMAP4_UNIPRO_DR0_SC_MASK (0x3 << 2)
+#define OMAP4_UNIPRO_DR1_SC_SHIFT 0
+#define OMAP4_UNIPRO_DR1_SC_MASK (0x3 << 0)
+
+/* CONTROL_SMART1IO_PADCONF_1 */
+#define OMAP4_ABE_DR0_LB_SHIFT 30
+#define OMAP4_ABE_DR0_LB_MASK (0x3 << 30)
+#define OMAP4_CAM_DR0_LB_SHIFT 28
+#define OMAP4_CAM_DR0_LB_MASK (0x3 << 28)
+#define OMAP4_FREF_DR2_LB_SHIFT 26
+#define OMAP4_FREF_DR2_LB_MASK (0x3 << 26)
+#define OMAP4_FREF_DR3_LB_SHIFT 24
+#define OMAP4_FREF_DR3_LB_MASK (0x3 << 24)
+#define OMAP4_GPIO_DR8_LB_SHIFT 22
+#define OMAP4_GPIO_DR8_LB_MASK (0x3 << 22)
+#define OMAP4_GPIO_DR9_LB_SHIFT 20
+#define OMAP4_GPIO_DR9_LB_MASK (0x3 << 20)
+#define OMAP4_GPMC_DR2_LB_SHIFT 18
+#define OMAP4_GPMC_DR2_LB_MASK (0x3 << 18)
+#define OMAP4_GPMC_DR3_LB_SHIFT 16
+#define OMAP4_GPMC_DR3_LB_MASK (0x3 << 16)
+#define OMAP4_GPMC_DR6_LB_SHIFT 14
+#define OMAP4_GPMC_DR6_LB_MASK (0x3 << 14)
+#define OMAP4_HDMI_DR0_LB_SHIFT 12
+#define OMAP4_HDMI_DR0_LB_MASK (0x3 << 12)
+#define OMAP4_MCSPI1_DR0_LB_SHIFT 10
+#define OMAP4_MCSPI1_DR0_LB_MASK (0x3 << 10)
+#define OMAP4_UART1_DR0_LB_SHIFT 8
+#define OMAP4_UART1_DR0_LB_MASK (0x3 << 8)
+#define OMAP4_UART3_DR0_LB_SHIFT 6
+#define OMAP4_UART3_DR0_LB_MASK (0x3 << 6)
+#define OMAP4_UART3_DR1_LB_SHIFT 4
+#define OMAP4_UART3_DR1_LB_MASK (0x3 << 4)
+#define OMAP4_UNIPRO_DR0_LB_SHIFT 2
+#define OMAP4_UNIPRO_DR0_LB_MASK (0x3 << 2)
+#define OMAP4_UNIPRO_DR1_LB_SHIFT 0
+#define OMAP4_UNIPRO_DR1_LB_MASK (0x3 << 0)
+
+/* CONTROL_SMART2IO_PADCONF_0 */
+#define OMAP4_C2C_DR0_LB_SHIFT 31
+#define OMAP4_C2C_DR0_LB_MASK (1 << 31)
+#define OMAP4_DPM_DR1_LB_SHIFT 30
+#define OMAP4_DPM_DR1_LB_MASK (1 << 30)
+#define OMAP4_DPM_DR2_LB_SHIFT 29
+#define OMAP4_DPM_DR2_LB_MASK (1 << 29)
+#define OMAP4_DPM_DR3_LB_SHIFT 28
+#define OMAP4_DPM_DR3_LB_MASK (1 << 28)
+#define OMAP4_GPIO_DR0_LB_SHIFT 27
+#define OMAP4_GPIO_DR0_LB_MASK (1 << 27)
+#define OMAP4_GPIO_DR1_LB_SHIFT 26
+#define OMAP4_GPIO_DR1_LB_MASK (1 << 26)
+#define OMAP4_GPIO_DR10_LB_SHIFT 25
+#define OMAP4_GPIO_DR10_LB_MASK (1 << 25)
+#define OMAP4_GPIO_DR2_LB_SHIFT 24
+#define OMAP4_GPIO_DR2_LB_MASK (1 << 24)
+#define OMAP4_GPMC_DR0_LB_SHIFT 23
+#define OMAP4_GPMC_DR0_LB_MASK (1 << 23)
+#define OMAP4_GPMC_DR1_LB_SHIFT 22
+#define OMAP4_GPMC_DR1_LB_MASK (1 << 22)
+#define OMAP4_GPMC_DR4_LB_SHIFT 21
+#define OMAP4_GPMC_DR4_LB_MASK (1 << 21)
+#define OMAP4_GPMC_DR5_LB_SHIFT 20
+#define OMAP4_GPMC_DR5_LB_MASK (1 << 20)
+#define OMAP4_GPMC_DR7_LB_SHIFT 19
+#define OMAP4_GPMC_DR7_LB_MASK (1 << 19)
+#define OMAP4_HSI2_DR0_LB_SHIFT 18
+#define OMAP4_HSI2_DR0_LB_MASK (1 << 18)
+#define OMAP4_HSI2_DR1_LB_SHIFT 17
+#define OMAP4_HSI2_DR1_LB_MASK (1 << 17)
+#define OMAP4_HSI2_DR2_LB_SHIFT 16
+#define OMAP4_HSI2_DR2_LB_MASK (1 << 16)
+#define OMAP4_KPD_DR0_LB_SHIFT 15
+#define OMAP4_KPD_DR0_LB_MASK (1 << 15)
+#define OMAP4_KPD_DR1_LB_SHIFT 14
+#define OMAP4_KPD_DR1_LB_MASK (1 << 14)
+#define OMAP4_PDM_DR0_LB_SHIFT 13
+#define OMAP4_PDM_DR0_LB_MASK (1 << 13)
+#define OMAP4_SDMMC2_DR0_LB_SHIFT 12
+#define OMAP4_SDMMC2_DR0_LB_MASK (1 << 12)
+#define OMAP4_SDMMC3_DR0_LB_SHIFT 11
+#define OMAP4_SDMMC3_DR0_LB_MASK (1 << 11)
+#define OMAP4_SDMMC4_DR0_LB_SHIFT 10
+#define OMAP4_SDMMC4_DR0_LB_MASK (1 << 10)
+#define OMAP4_SDMMC4_DR1_LB_SHIFT 9
+#define OMAP4_SDMMC4_DR1_LB_MASK (1 << 9)
+#define OMAP4_SPI3_DR0_LB_SHIFT 8
+#define OMAP4_SPI3_DR0_LB_MASK (1 << 8)
+#define OMAP4_SPI3_DR1_LB_SHIFT 7
+#define OMAP4_SPI3_DR1_LB_MASK (1 << 7)
+#define OMAP4_UART3_DR2_LB_SHIFT 6
+#define OMAP4_UART3_DR2_LB_MASK (1 << 6)
+#define OMAP4_UART3_DR3_LB_SHIFT 5
+#define OMAP4_UART3_DR3_LB_MASK (1 << 5)
+#define OMAP4_UART3_DR4_LB_SHIFT 4
+#define OMAP4_UART3_DR4_LB_MASK (1 << 4)
+#define OMAP4_UART3_DR5_LB_SHIFT 3
+#define OMAP4_UART3_DR5_LB_MASK (1 << 3)
+#define OMAP4_USBA0_DR1_LB_SHIFT 2
+#define OMAP4_USBA0_DR1_LB_MASK (1 << 2)
+#define OMAP4_USBA_DR2_LB_SHIFT 1
+#define OMAP4_USBA_DR2_LB_MASK (1 << 1)
+
+/* CONTROL_SMART2IO_PADCONF_1 */
+#define OMAP4_USBB1_DR0_LB_SHIFT 31
+#define OMAP4_USBB1_DR0_LB_MASK (1 << 31)
+#define OMAP4_USBB2_DR0_LB_SHIFT 30
+#define OMAP4_USBB2_DR0_LB_MASK (1 << 30)
+#define OMAP4_USBA0_DR0_LB_SHIFT 29
+#define OMAP4_USBA0_DR0_LB_MASK (1 << 29)
+
+/* CONTROL_SMART3IO_PADCONF_0 */
+#define OMAP4_DMIC_DR0_MB_SHIFT 30
+#define OMAP4_DMIC_DR0_MB_MASK (0x3 << 30)
+#define OMAP4_GPIO_DR3_MB_SHIFT 28
+#define OMAP4_GPIO_DR3_MB_MASK (0x3 << 28)
+#define OMAP4_GPIO_DR4_MB_SHIFT 26
+#define OMAP4_GPIO_DR4_MB_MASK (0x3 << 26)
+#define OMAP4_GPIO_DR5_MB_SHIFT 24
+#define OMAP4_GPIO_DR5_MB_MASK (0x3 << 24)
+#define OMAP4_GPIO_DR6_MB_SHIFT 22
+#define OMAP4_GPIO_DR6_MB_MASK (0x3 << 22)
+#define OMAP4_HSI_DR1_MB_SHIFT 20
+#define OMAP4_HSI_DR1_MB_MASK (0x3 << 20)
+#define OMAP4_HSI_DR2_MB_SHIFT 18
+#define OMAP4_HSI_DR2_MB_MASK (0x3 << 18)
+#define OMAP4_HSI_DR3_MB_SHIFT 16
+#define OMAP4_HSI_DR3_MB_MASK (0x3 << 16)
+#define OMAP4_MCBSP2_DR0_MB_SHIFT 14
+#define OMAP4_MCBSP2_DR0_MB_MASK (0x3 << 14)
+#define OMAP4_MCSPI4_DR0_MB_SHIFT 12
+#define OMAP4_MCSPI4_DR0_MB_MASK (0x3 << 12)
+#define OMAP4_MCSPI4_DR1_MB_SHIFT 10
+#define OMAP4_MCSPI4_DR1_MB_MASK (0x3 << 10)
+#define OMAP4_SDMMC3_DR0_MB_SHIFT 8
+#define OMAP4_SDMMC3_DR0_MB_MASK (0x3 << 8)
+#define OMAP4_SPI2_DR0_MB_SHIFT 0
+#define OMAP4_SPI2_DR0_MB_MASK (0x3 << 0)
+
+/* CONTROL_SMART3IO_PADCONF_1 */
+#define OMAP4_SPI2_DR1_MB_SHIFT 30
+#define OMAP4_SPI2_DR1_MB_MASK (0x3 << 30)
+#define OMAP4_SPI2_DR2_MB_SHIFT 28
+#define OMAP4_SPI2_DR2_MB_MASK (0x3 << 28)
+#define OMAP4_UART2_DR0_MB_SHIFT 26
+#define OMAP4_UART2_DR0_MB_MASK (0x3 << 26)
+#define OMAP4_UART2_DR1_MB_SHIFT 24
+#define OMAP4_UART2_DR1_MB_MASK (0x3 << 24)
+#define OMAP4_UART4_DR0_MB_SHIFT 22
+#define OMAP4_UART4_DR0_MB_MASK (0x3 << 22)
+#define OMAP4_HSI_DR0_MB_SHIFT 20
+#define OMAP4_HSI_DR0_MB_MASK (0x3 << 20)
+
+/* CONTROL_SMART3IO_PADCONF_2 */
+#define OMAP4_DMIC_DR0_LB_SHIFT 31
+#define OMAP4_DMIC_DR0_LB_MASK (1 << 31)
+#define OMAP4_GPIO_DR3_LB_SHIFT 30
+#define OMAP4_GPIO_DR3_LB_MASK (1 << 30)
+#define OMAP4_GPIO_DR4_LB_SHIFT 29
+#define OMAP4_GPIO_DR4_LB_MASK (1 << 29)
+#define OMAP4_GPIO_DR5_LB_SHIFT 28
+#define OMAP4_GPIO_DR5_LB_MASK (1 << 28)
+#define OMAP4_GPIO_DR6_LB_SHIFT 27
+#define OMAP4_GPIO_DR6_LB_MASK (1 << 27)
+#define OMAP4_HSI_DR1_LB_SHIFT 26
+#define OMAP4_HSI_DR1_LB_MASK (1 << 26)
+#define OMAP4_HSI_DR2_LB_SHIFT 25
+#define OMAP4_HSI_DR2_LB_MASK (1 << 25)
+#define OMAP4_HSI_DR3_LB_SHIFT 24
+#define OMAP4_HSI_DR3_LB_MASK (1 << 24)
+#define OMAP4_MCBSP2_DR0_LB_SHIFT 23
+#define OMAP4_MCBSP2_DR0_LB_MASK (1 << 23)
+#define OMAP4_MCSPI4_DR0_LB_SHIFT 22
+#define OMAP4_MCSPI4_DR0_LB_MASK (1 << 22)
+#define OMAP4_MCSPI4_DR1_LB_SHIFT 21
+#define OMAP4_MCSPI4_DR1_LB_MASK (1 << 21)
+#define OMAP4_SLIMBUS2_DR0_LB_SHIFT 18
+#define OMAP4_SLIMBUS2_DR0_LB_MASK (1 << 18)
+#define OMAP4_SPI2_DR0_LB_SHIFT 16
+#define OMAP4_SPI2_DR0_LB_MASK (1 << 16)
+#define OMAP4_SPI2_DR1_LB_SHIFT 15
+#define OMAP4_SPI2_DR1_LB_MASK (1 << 15)
+#define OMAP4_SPI2_DR2_LB_SHIFT 14
+#define OMAP4_SPI2_DR2_LB_MASK (1 << 14)
+#define OMAP4_UART2_DR0_LB_SHIFT 13
+#define OMAP4_UART2_DR0_LB_MASK (1 << 13)
+#define OMAP4_UART2_DR1_LB_SHIFT 12
+#define OMAP4_UART2_DR1_LB_MASK (1 << 12)
+#define OMAP4_UART4_DR0_LB_SHIFT 11
+#define OMAP4_UART4_DR0_LB_MASK (1 << 11)
+#define OMAP4_HSI_DR0_LB_SHIFT 10
+#define OMAP4_HSI_DR0_LB_MASK (1 << 10)
+
+/* CONTROL_USBB_HSIC */
+#define OMAP4_USBB2_DR1_SR_SHIFT 30
+#define OMAP4_USBB2_DR1_SR_MASK (0x3 << 30)
+#define OMAP4_USBB2_DR1_I_SHIFT 27
+#define OMAP4_USBB2_DR1_I_MASK (0x7 << 27)
+#define OMAP4_USBB1_DR1_SR_SHIFT 25
+#define OMAP4_USBB1_DR1_SR_MASK (0x3 << 25)
+#define OMAP4_USBB1_DR1_I_SHIFT 22
+#define OMAP4_USBB1_DR1_I_MASK (0x7 << 22)
+#define OMAP4_USBB1_HSIC_DATA_WD_SHIFT 20
+#define OMAP4_USBB1_HSIC_DATA_WD_MASK (0x3 << 20)
+#define OMAP4_USBB1_HSIC_STROBE_WD_SHIFT 18
+#define OMAP4_USBB1_HSIC_STROBE_WD_MASK (0x3 << 18)
+#define OMAP4_USBB2_HSIC_DATA_WD_SHIFT 16
+#define OMAP4_USBB2_HSIC_DATA_WD_MASK (0x3 << 16)
+#define OMAP4_USBB2_HSIC_STROBE_WD_SHIFT 14
+#define OMAP4_USBB2_HSIC_STROBE_WD_MASK (0x3 << 14)
+#define OMAP4_USBB1_HSIC_DATA_OFFMODE_WD_ENABLE_SHIFT 13
+#define OMAP4_USBB1_HSIC_DATA_OFFMODE_WD_ENABLE_MASK (1 << 13)
+#define OMAP4_USBB1_HSIC_DATA_OFFMODE_WD_SHIFT 11
+#define OMAP4_USBB1_HSIC_DATA_OFFMODE_WD_MASK (0x3 << 11)
+#define OMAP4_USBB1_HSIC_STROBE_OFFMODE_WD_ENABLE_SHIFT 10
+#define OMAP4_USBB1_HSIC_STROBE_OFFMODE_WD_ENABLE_MASK (1 << 10)
+#define OMAP4_USBB1_HSIC_STROBE_OFFMODE_WD_SHIFT 8
+#define OMAP4_USBB1_HSIC_STROBE_OFFMODE_WD_MASK (0x3 << 8)
+#define OMAP4_USBB2_HSIC_DATA_OFFMODE_WD_ENABLE_SHIFT 7
+#define OMAP4_USBB2_HSIC_DATA_OFFMODE_WD_ENABLE_MASK (1 << 7)
+#define OMAP4_USBB2_HSIC_DATA_OFFMODE_WD_SHIFT 5
+#define OMAP4_USBB2_HSIC_DATA_OFFMODE_WD_MASK (0x3 << 5)
+#define OMAP4_USBB2_HSIC_STROBE_OFFMODE_WD_ENABLE_SHIFT 4
+#define OMAP4_USBB2_HSIC_STROBE_OFFMODE_WD_ENABLE_MASK (1 << 4)
+#define OMAP4_USBB2_HSIC_STROBE_OFFMODE_WD_SHIFT 2
+#define OMAP4_USBB2_HSIC_STROBE_OFFMODE_WD_MASK (0x3 << 2)
+
+/* CONTROL_SLIMBUS */
+#define OMAP4_SLIMBUS1_DR0_MB_SHIFT 30
+#define OMAP4_SLIMBUS1_DR0_MB_MASK (0x3 << 30)
+#define OMAP4_SLIMBUS1_DR1_MB_SHIFT 28
+#define OMAP4_SLIMBUS1_DR1_MB_MASK (0x3 << 28)
+#define OMAP4_SLIMBUS2_DR0_MB_SHIFT 26
+#define OMAP4_SLIMBUS2_DR0_MB_MASK (0x3 << 26)
+#define OMAP4_SLIMBUS2_DR1_MB_SHIFT 24
+#define OMAP4_SLIMBUS2_DR1_MB_MASK (0x3 << 24)
+#define OMAP4_SLIMBUS2_DR2_MB_SHIFT 22
+#define OMAP4_SLIMBUS2_DR2_MB_MASK (0x3 << 22)
+#define OMAP4_SLIMBUS2_DR3_MB_SHIFT 20
+#define OMAP4_SLIMBUS2_DR3_MB_MASK (0x3 << 20)
+#define OMAP4_SLIMBUS1_DR0_LB_SHIFT 19
+#define OMAP4_SLIMBUS1_DR0_LB_MASK (1 << 19)
+#define OMAP4_SLIMBUS2_DR1_LB_SHIFT 18
+#define OMAP4_SLIMBUS2_DR1_LB_MASK (1 << 18)
+
+/* CONTROL_PBIASLITE */
+#define OMAP4_USIM_PBIASLITE_HIZ_MODE_SHIFT 31
+#define OMAP4_USIM_PBIASLITE_HIZ_MODE_MASK (1 << 31)
+#define OMAP4_USIM_PBIASLITE_SUPPLY_HI_OUT_SHIFT 30
+#define OMAP4_USIM_PBIASLITE_SUPPLY_HI_OUT_MASK (1 << 30)
+#define OMAP4_USIM_PBIASLITE_VMODE_ERROR_SHIFT 29
+#define OMAP4_USIM_PBIASLITE_VMODE_ERROR_MASK (1 << 29)
+#define OMAP4_USIM_PBIASLITE_PWRDNZ_SHIFT 28
+#define OMAP4_USIM_PBIASLITE_PWRDNZ_MASK (1 << 28)
+#define OMAP4_USIM_PBIASLITE_VMODE_SHIFT 27
+#define OMAP4_USIM_PBIASLITE_VMODE_MASK (1 << 27)
+#define OMAP4_MMC1_PWRDNZ_SHIFT 26
+#define OMAP4_MMC1_PWRDNZ_MASK (1 << 26)
+#define OMAP4_MMC1_PBIASLITE_HIZ_MODE_SHIFT 25
+#define OMAP4_MMC1_PBIASLITE_HIZ_MODE_MASK (1 << 25)
+#define OMAP4_MMC1_PBIASLITE_SUPPLY_HI_OUT_SHIFT 24
+#define OMAP4_MMC1_PBIASLITE_SUPPLY_HI_OUT_MASK (1 << 24)
+#define OMAP4_MMC1_PBIASLITE_VMODE_ERROR_SHIFT 23
+#define OMAP4_MMC1_PBIASLITE_VMODE_ERROR_MASK (1 << 23)
+#define OMAP4_MMC1_PBIASLITE_PWRDNZ_SHIFT 22
+#define OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK (1 << 22)
+#define OMAP4_MMC1_PBIASLITE_VMODE_SHIFT 21
+#define OMAP4_MMC1_PBIASLITE_VMODE_MASK (1 << 21)
+#define OMAP4_USBC1_ICUSB_PWRDNZ_SHIFT 20
+#define OMAP4_USBC1_ICUSB_PWRDNZ_MASK (1 << 20)
+
+/* CONTROL_I2C_0 */
+#define OMAP4_I2C4_SDA_GLFENB_SHIFT 31
+#define OMAP4_I2C4_SDA_GLFENB_MASK (1 << 31)
+#define OMAP4_I2C4_SDA_LOAD_BITS_SHIFT 29
+#define OMAP4_I2C4_SDA_LOAD_BITS_MASK (0x3 << 29)
+#define OMAP4_I2C4_SDA_PULLUPRESX_SHIFT 28
+#define OMAP4_I2C4_SDA_PULLUPRESX_MASK (1 << 28)
+#define OMAP4_I2C3_SDA_GLFENB_SHIFT 27
+#define OMAP4_I2C3_SDA_GLFENB_MASK (1 << 27)
+#define OMAP4_I2C3_SDA_LOAD_BITS_SHIFT 25
+#define OMAP4_I2C3_SDA_LOAD_BITS_MASK (0x3 << 25)
+#define OMAP4_I2C3_SDA_PULLUPRESX_SHIFT 24
+#define OMAP4_I2C3_SDA_PULLUPRESX_MASK (1 << 24)
+#define OMAP4_I2C2_SDA_GLFENB_SHIFT 23
+#define OMAP4_I2C2_SDA_GLFENB_MASK (1 << 23)
+#define OMAP4_I2C2_SDA_LOAD_BITS_SHIFT 21
+#define OMAP4_I2C2_SDA_LOAD_BITS_MASK (0x3 << 21)
+#define OMAP4_I2C2_SDA_PULLUPRESX_SHIFT 20
+#define OMAP4_I2C2_SDA_PULLUPRESX_MASK (1 << 20)
+#define OMAP4_I2C1_SDA_GLFENB_SHIFT 19
+#define OMAP4_I2C1_SDA_GLFENB_MASK (1 << 19)
+#define OMAP4_I2C1_SDA_LOAD_BITS_SHIFT 17
+#define OMAP4_I2C1_SDA_LOAD_BITS_MASK (0x3 << 17)
+#define OMAP4_I2C1_SDA_PULLUPRESX_SHIFT 16
+#define OMAP4_I2C1_SDA_PULLUPRESX_MASK (1 << 16)
+#define OMAP4_I2C4_SCL_GLFENB_SHIFT 15
+#define OMAP4_I2C4_SCL_GLFENB_MASK (1 << 15)
+#define OMAP4_I2C4_SCL_LOAD_BITS_SHIFT 13
+#define OMAP4_I2C4_SCL_LOAD_BITS_MASK (0x3 << 13)
+#define OMAP4_I2C4_SCL_PULLUPRESX_SHIFT 12
+#define OMAP4_I2C4_SCL_PULLUPRESX_MASK (1 << 12)
+#define OMAP4_I2C3_SCL_GLFENB_SHIFT 11
+#define OMAP4_I2C3_SCL_GLFENB_MASK (1 << 11)
+#define OMAP4_I2C3_SCL_LOAD_BITS_SHIFT 9
+#define OMAP4_I2C3_SCL_LOAD_BITS_MASK (0x3 << 9)
+#define OMAP4_I2C3_SCL_PULLUPRESX_SHIFT 8
+#define OMAP4_I2C3_SCL_PULLUPRESX_MASK (1 << 8)
+#define OMAP4_I2C2_SCL_GLFENB_SHIFT 7
+#define OMAP4_I2C2_SCL_GLFENB_MASK (1 << 7)
+#define OMAP4_I2C2_SCL_LOAD_BITS_SHIFT 5
+#define OMAP4_I2C2_SCL_LOAD_BITS_MASK (0x3 << 5)
+#define OMAP4_I2C2_SCL_PULLUPRESX_SHIFT 4
+#define OMAP4_I2C2_SCL_PULLUPRESX_MASK (1 << 4)
+#define OMAP4_I2C1_SCL_GLFENB_SHIFT 3
+#define OMAP4_I2C1_SCL_GLFENB_MASK (1 << 3)
+#define OMAP4_I2C1_SCL_LOAD_BITS_SHIFT 1
+#define OMAP4_I2C1_SCL_LOAD_BITS_MASK (0x3 << 1)
+#define OMAP4_I2C1_SCL_PULLUPRESX_SHIFT 0
+#define OMAP4_I2C1_SCL_PULLUPRESX_MASK (1 << 0)
+
+/* CONTROL_CAMERA_RX */
+#define OMAP4_CAMERARX_UNIPRO_CTRLCLKEN_SHIFT 31
+#define OMAP4_CAMERARX_UNIPRO_CTRLCLKEN_MASK (1 << 31)
+#define OMAP4_CAMERARX_CSI22_LANEENABLE_SHIFT 29
+#define OMAP4_CAMERARX_CSI22_LANEENABLE_MASK (0x3 << 29)
+#define OMAP4_CAMERARX_CSI21_LANEENABLE_SHIFT 24
+#define OMAP4_CAMERARX_CSI21_LANEENABLE_MASK (0x1f << 24)
+#define OMAP4_CAMERARX_UNIPRO_CAMMODE_SHIFT 22
+#define OMAP4_CAMERARX_UNIPRO_CAMMODE_MASK (0x3 << 22)
+#define OMAP4_CAMERARX_CSI22_CTRLCLKEN_SHIFT 21
+#define OMAP4_CAMERARX_CSI22_CTRLCLKEN_MASK (1 << 21)
+#define OMAP4_CAMERARX_CSI22_CAMMODE_SHIFT 19
+#define OMAP4_CAMERARX_CSI22_CAMMODE_MASK (0x3 << 19)
+#define OMAP4_CAMERARX_CSI21_CTRLCLKEN_SHIFT 18
+#define OMAP4_CAMERARX_CSI21_CTRLCLKEN_MASK (1 << 18)
+#define OMAP4_CAMERARX_CSI21_CAMMODE_SHIFT 16
+#define OMAP4_CAMERARX_CSI21_CAMMODE_MASK (0x3 << 16)
+
+/* CONTROL_AVDAC */
+#define OMAP4_AVDAC_ACEN_SHIFT 31
+#define OMAP4_AVDAC_ACEN_MASK (1 << 31)
+#define OMAP4_AVDAC_TVOUTBYPASS_SHIFT 30
+#define OMAP4_AVDAC_TVOUTBYPASS_MASK (1 << 30)
+#define OMAP4_AVDAC_INPUTINV_SHIFT 29
+#define OMAP4_AVDAC_INPUTINV_MASK (1 << 29)
+#define OMAP4_AVDAC_CTL_SHIFT 13
+#define OMAP4_AVDAC_CTL_MASK (0xffff << 13)
+#define OMAP4_AVDAC_CTL_WR_ACK_SHIFT 12
+#define OMAP4_AVDAC_CTL_WR_ACK_MASK (1 << 12)
+
+/* CONTROL_HDMI_TX_PHY */
+#define OMAP4_HDMITXPHY_PADORDER_SHIFT 31
+#define OMAP4_HDMITXPHY_PADORDER_MASK (1 << 31)
+#define OMAP4_HDMITXPHY_TXVALID_SHIFT 30
+#define OMAP4_HDMITXPHY_TXVALID_MASK (1 << 30)
+#define OMAP4_HDMITXPHY_ENBYPASSCLK_SHIFT 29
+#define OMAP4_HDMITXPHY_ENBYPASSCLK_MASK (1 << 29)
+#define OMAP4_HDMITXPHY_PD_PULLUPDET_SHIFT 28
+#define OMAP4_HDMITXPHY_PD_PULLUPDET_MASK (1 << 28)
+
+/* CONTROL_MMC2 */
+#define OMAP4_MMC2_FEEDBACK_CLK_SEL_SHIFT 31
+#define OMAP4_MMC2_FEEDBACK_CLK_SEL_MASK (1 << 31)
+
+/* CONTROL_DSIPHY */
+#define OMAP4_DSI2_LANEENABLE_SHIFT 29
+#define OMAP4_DSI2_LANEENABLE_MASK (0x7 << 29)
+#define OMAP4_DSI1_LANEENABLE_SHIFT 24
+#define OMAP4_DSI1_LANEENABLE_MASK (0x1f << 24)
+#define OMAP4_DSI1_PIPD_SHIFT 19
+#define OMAP4_DSI1_PIPD_MASK (0x1f << 19)
+#define OMAP4_DSI2_PIPD_SHIFT 14
+#define OMAP4_DSI2_PIPD_MASK (0x1f << 14)
+
+/* CONTROL_MCBSPLP */
+#define OMAP4_ALBCTRLRX_FSX_SHIFT 31
+#define OMAP4_ALBCTRLRX_FSX_MASK (1 << 31)
+#define OMAP4_ALBCTRLRX_CLKX_SHIFT 30
+#define OMAP4_ALBCTRLRX_CLKX_MASK (1 << 30)
+#define OMAP4_ABE_MCBSP1_DR_EN_SHIFT 29
+#define OMAP4_ABE_MCBSP1_DR_EN_MASK (1 << 29)
+
+/* CONTROL_USB2PHYCORE */
+#define OMAP4_USB2PHY_AUTORESUME_EN_SHIFT 31
+#define OMAP4_USB2PHY_AUTORESUME_EN_MASK (1 << 31)
+#define OMAP4_USB2PHY_DISCHGDET_SHIFT 30
+#define OMAP4_USB2PHY_DISCHGDET_MASK (1 << 30)
+#define OMAP4_USB2PHY_GPIOMODE_SHIFT 29
+#define OMAP4_USB2PHY_GPIOMODE_MASK (1 << 29)
+#define OMAP4_USB2PHY_CHG_DET_EXT_CTL_SHIFT 28
+#define OMAP4_USB2PHY_CHG_DET_EXT_CTL_MASK (1 << 28)
+#define OMAP4_USB2PHY_RDM_PD_CHGDET_EN_SHIFT 27
+#define OMAP4_USB2PHY_RDM_PD_CHGDET_EN_MASK (1 << 27)
+#define OMAP4_USB2PHY_RDP_PU_CHGDET_EN_SHIFT 26
+#define OMAP4_USB2PHY_RDP_PU_CHGDET_EN_MASK (1 << 26)
+#define OMAP4_USB2PHY_CHG_VSRC_EN_SHIFT 25
+#define OMAP4_USB2PHY_CHG_VSRC_EN_MASK (1 << 25)
+#define OMAP4_USB2PHY_CHG_ISINK_EN_SHIFT 24
+#define OMAP4_USB2PHY_CHG_ISINK_EN_MASK (1 << 24)
+#define OMAP4_USB2PHY_CHG_DET_STATUS_SHIFT 21
+#define OMAP4_USB2PHY_CHG_DET_STATUS_MASK (0x7 << 21)
+#define OMAP4_USB2PHY_CHG_DET_DM_COMP_SHIFT 20
+#define OMAP4_USB2PHY_CHG_DET_DM_COMP_MASK (1 << 20)
+#define OMAP4_USB2PHY_CHG_DET_DP_COMP_SHIFT 19
+#define OMAP4_USB2PHY_CHG_DET_DP_COMP_MASK (1 << 19)
+#define OMAP4_USB2PHY_DATADET_SHIFT 18
+#define OMAP4_USB2PHY_DATADET_MASK (1 << 18)
+#define OMAP4_USB2PHY_SINKONDP_SHIFT 17
+#define OMAP4_USB2PHY_SINKONDP_MASK (1 << 17)
+#define OMAP4_USB2PHY_SRCONDM_SHIFT 16
+#define OMAP4_USB2PHY_SRCONDM_MASK (1 << 16)
+#define OMAP4_USB2PHY_RESTARTCHGDET_SHIFT 15
+#define OMAP4_USB2PHY_RESTARTCHGDET_MASK (1 << 15)
+#define OMAP4_USB2PHY_CHGDETDONE_SHIFT 14
+#define OMAP4_USB2PHY_CHGDETDONE_MASK (1 << 14)
+#define OMAP4_USB2PHY_CHGDETECTED_SHIFT 13
+#define OMAP4_USB2PHY_CHGDETECTED_MASK (1 << 13)
+#define OMAP4_USB2PHY_MCPCPUEN_SHIFT 12
+#define OMAP4_USB2PHY_MCPCPUEN_MASK (1 << 12)
+#define OMAP4_USB2PHY_MCPCMODEEN_SHIFT 11
+#define OMAP4_USB2PHY_MCPCMODEEN_MASK (1 << 11)
+#define OMAP4_USB2PHY_RESETDONEMCLK_SHIFT 10
+#define OMAP4_USB2PHY_RESETDONEMCLK_MASK (1 << 10)
+#define OMAP4_USB2PHY_UTMIRESETDONE_SHIFT 9
+#define OMAP4_USB2PHY_UTMIRESETDONE_MASK (1 << 9)
+#define OMAP4_USB2PHY_TXBITSTUFFENABLE_SHIFT 8
+#define OMAP4_USB2PHY_TXBITSTUFFENABLE_MASK (1 << 8)
+#define OMAP4_USB2PHY_DATAPOLARITYN_SHIFT 7
+#define OMAP4_USB2PHY_DATAPOLARITYN_MASK (1 << 7)
+#define OMAP4_USBDPLL_FREQLOCK_SHIFT 6
+#define OMAP4_USBDPLL_FREQLOCK_MASK (1 << 6)
+#define OMAP4_USB2PHY_RESETDONETCLK_SHIFT 5
+#define OMAP4_USB2PHY_RESETDONETCLK_MASK (1 << 5)
+
+/* CONTROL_I2C_1 */
+#define OMAP4_HDMI_DDC_SDA_GLFENB_SHIFT 31
+#define OMAP4_HDMI_DDC_SDA_GLFENB_MASK (1 << 31)
+#define OMAP4_HDMI_DDC_SDA_LOAD_BITS_SHIFT 29
+#define OMAP4_HDMI_DDC_SDA_LOAD_BITS_MASK (0x3 << 29)
+#define OMAP4_HDMI_DDC_SDA_PULLUPRESX_SHIFT 28
+#define OMAP4_HDMI_DDC_SDA_PULLUPRESX_MASK (1 << 28)
+#define OMAP4_HDMI_DDC_SCL_GLFENB_SHIFT 27
+#define OMAP4_HDMI_DDC_SCL_GLFENB_MASK (1 << 27)
+#define OMAP4_HDMI_DDC_SCL_LOAD_BITS_SHIFT 25
+#define OMAP4_HDMI_DDC_SCL_LOAD_BITS_MASK (0x3 << 25)
+#define OMAP4_HDMI_DDC_SCL_PULLUPRESX_SHIFT 24
+#define OMAP4_HDMI_DDC_SCL_PULLUPRESX_MASK (1 << 24)
+#define OMAP4_HDMI_DDC_SDA_HSMODE_SHIFT 23
+#define OMAP4_HDMI_DDC_SDA_HSMODE_MASK (1 << 23)
+#define OMAP4_HDMI_DDC_SDA_NMODE_SHIFT 22
+#define OMAP4_HDMI_DDC_SDA_NMODE_MASK (1 << 22)
+#define OMAP4_HDMI_DDC_SCL_HSMODE_SHIFT 21
+#define OMAP4_HDMI_DDC_SCL_HSMODE_MASK (1 << 21)
+#define OMAP4_HDMI_DDC_SCL_NMODE_SHIFT 20
+#define OMAP4_HDMI_DDC_SCL_NMODE_MASK (1 << 20)
+
+/* CONTROL_MMC1 */
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP0_SHIFT 31
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP0_MASK (1 << 31)
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP1_SHIFT 30
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP1_MASK (1 << 30)
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP2_SHIFT 29
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP2_MASK (1 << 29)
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP3_SHIFT 28
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP3_MASK (1 << 28)
+#define OMAP4_SDMMC1_DR0_SPEEDCTRL_SHIFT 27
+#define OMAP4_SDMMC1_DR0_SPEEDCTRL_MASK (1 << 27)
+#define OMAP4_SDMMC1_DR1_SPEEDCTRL_SHIFT 26
+#define OMAP4_SDMMC1_DR1_SPEEDCTRL_MASK (1 << 26)
+#define OMAP4_SDMMC1_DR2_SPEEDCTRL_SHIFT 25
+#define OMAP4_SDMMC1_DR2_SPEEDCTRL_MASK (1 << 25)
+#define OMAP4_USBC1_DR0_SPEEDCTRL_SHIFT 24
+#define OMAP4_USBC1_DR0_SPEEDCTRL_MASK (1 << 24)
+#define OMAP4_USB_FD_CDEN_SHIFT 23
+#define OMAP4_USB_FD_CDEN_MASK (1 << 23)
+#define OMAP4_USBC1_ICUSB_DP_PDDIS_SHIFT 22
+#define OMAP4_USBC1_ICUSB_DP_PDDIS_MASK (1 << 22)
+#define OMAP4_USBC1_ICUSB_DM_PDDIS_SHIFT 21
+#define OMAP4_USBC1_ICUSB_DM_PDDIS_MASK (1 << 21)
+
+/* CONTROL_HSI */
+#define OMAP4_HSI1_CALLOOP_SEL_SHIFT 31
+#define OMAP4_HSI1_CALLOOP_SEL_MASK (1 << 31)
+#define OMAP4_HSI1_CALMUX_SEL_SHIFT 30
+#define OMAP4_HSI1_CALMUX_SEL_MASK (1 << 30)
+#define OMAP4_HSI2_CALLOOP_SEL_SHIFT 29
+#define OMAP4_HSI2_CALLOOP_SEL_MASK (1 << 29)
+#define OMAP4_HSI2_CALMUX_SEL_SHIFT 28
+#define OMAP4_HSI2_CALMUX_SEL_MASK (1 << 28)
+
+/* CONTROL_USB */
+#define OMAP4_CARKIT_USBA0_ULPIPHY_DAT0_AUTO_EN_SHIFT 31
+#define OMAP4_CARKIT_USBA0_ULPIPHY_DAT0_AUTO_EN_MASK (1 << 31)
+#define OMAP4_CARKIT_USBA0_ULPIPHY_DAT1_AUTO_EN_SHIFT 30
+#define OMAP4_CARKIT_USBA0_ULPIPHY_DAT1_AUTO_EN_MASK (1 << 30)
+
+/* CONTROL_HDQ */
+#define OMAP4_HDQ_SIO_PWRDNZ_SHIFT 31
+#define OMAP4_HDQ_SIO_PWRDNZ_MASK (1 << 31)
+
+/* CONTROL_LPDDR2IO1_0 */
+#define OMAP4_LPDDR2IO1_GR4_SR_SHIFT 30
+#define OMAP4_LPDDR2IO1_GR4_SR_MASK (0x3 << 30)
+#define OMAP4_LPDDR2IO1_GR4_I_SHIFT 27
+#define OMAP4_LPDDR2IO1_GR4_I_MASK (0x7 << 27)
+#define OMAP4_LPDDR2IO1_GR4_WD_SHIFT 25
+#define OMAP4_LPDDR2IO1_GR4_WD_MASK (0x3 << 25)
+#define OMAP4_LPDDR2IO1_GR3_SR_SHIFT 22
+#define OMAP4_LPDDR2IO1_GR3_SR_MASK (0x3 << 22)
+#define OMAP4_LPDDR2IO1_GR3_I_SHIFT 19
+#define OMAP4_LPDDR2IO1_GR3_I_MASK (0x7 << 19)
+#define OMAP4_LPDDR2IO1_GR3_WD_SHIFT 17
+#define OMAP4_LPDDR2IO1_GR3_WD_MASK (0x3 << 17)
+#define OMAP4_LPDDR2IO1_GR2_SR_SHIFT 14
+#define OMAP4_LPDDR2IO1_GR2_SR_MASK (0x3 << 14)
+#define OMAP4_LPDDR2IO1_GR2_I_SHIFT 11
+#define OMAP4_LPDDR2IO1_GR2_I_MASK (0x7 << 11)
+#define OMAP4_LPDDR2IO1_GR2_WD_SHIFT 9
+#define OMAP4_LPDDR2IO1_GR2_WD_MASK (0x3 << 9)
+#define OMAP4_LPDDR2IO1_GR1_SR_SHIFT 6
+#define OMAP4_LPDDR2IO1_GR1_SR_MASK (0x3 << 6)
+#define OMAP4_LPDDR2IO1_GR1_I_SHIFT 3
+#define OMAP4_LPDDR2IO1_GR1_I_MASK (0x7 << 3)
+#define OMAP4_LPDDR2IO1_GR1_WD_SHIFT 1
+#define OMAP4_LPDDR2IO1_GR1_WD_MASK (0x3 << 1)
+
+/* CONTROL_LPDDR2IO1_1 */
+#define OMAP4_LPDDR2IO1_GR8_SR_SHIFT 30
+#define OMAP4_LPDDR2IO1_GR8_SR_MASK (0x3 << 30)
+#define OMAP4_LPDDR2IO1_GR8_I_SHIFT 27
+#define OMAP4_LPDDR2IO1_GR8_I_MASK (0x7 << 27)
+#define OMAP4_LPDDR2IO1_GR8_WD_SHIFT 25
+#define OMAP4_LPDDR2IO1_GR8_WD_MASK (0x3 << 25)
+#define OMAP4_LPDDR2IO1_GR7_SR_SHIFT 22
+#define OMAP4_LPDDR2IO1_GR7_SR_MASK (0x3 << 22)
+#define OMAP4_LPDDR2IO1_GR7_I_SHIFT 19
+#define OMAP4_LPDDR2IO1_GR7_I_MASK (0x7 << 19)
+#define OMAP4_LPDDR2IO1_GR7_WD_SHIFT 17
+#define OMAP4_LPDDR2IO1_GR7_WD_MASK (0x3 << 17)
+#define OMAP4_LPDDR2IO1_GR6_SR_SHIFT 14
+#define OMAP4_LPDDR2IO1_GR6_SR_MASK (0x3 << 14)
+#define OMAP4_LPDDR2IO1_GR6_I_SHIFT 11
+#define OMAP4_LPDDR2IO1_GR6_I_MASK (0x7 << 11)
+#define OMAP4_LPDDR2IO1_GR6_WD_SHIFT 9
+#define OMAP4_LPDDR2IO1_GR6_WD_MASK (0x3 << 9)
+#define OMAP4_LPDDR2IO1_GR5_SR_SHIFT 6
+#define OMAP4_LPDDR2IO1_GR5_SR_MASK (0x3 << 6)
+#define OMAP4_LPDDR2IO1_GR5_I_SHIFT 3
+#define OMAP4_LPDDR2IO1_GR5_I_MASK (0x7 << 3)
+#define OMAP4_LPDDR2IO1_GR5_WD_SHIFT 1
+#define OMAP4_LPDDR2IO1_GR5_WD_MASK (0x3 << 1)
+
+/* CONTROL_LPDDR2IO1_2 */
+#define OMAP4_LPDDR2IO1_GR11_SR_SHIFT 30
+#define OMAP4_LPDDR2IO1_GR11_SR_MASK (0x3 << 30)
+#define OMAP4_LPDDR2IO1_GR11_I_SHIFT 27
+#define OMAP4_LPDDR2IO1_GR11_I_MASK (0x7 << 27)
+#define OMAP4_LPDDR2IO1_GR11_WD_SHIFT 25
+#define OMAP4_LPDDR2IO1_GR11_WD_MASK (0x3 << 25)
+#define OMAP4_LPDDR2IO1_GR10_SR_SHIFT 22
+#define OMAP4_LPDDR2IO1_GR10_SR_MASK (0x3 << 22)
+#define OMAP4_LPDDR2IO1_GR10_I_SHIFT 19
+#define OMAP4_LPDDR2IO1_GR10_I_MASK (0x7 << 19)
+#define OMAP4_LPDDR2IO1_GR10_WD_SHIFT 17
+#define OMAP4_LPDDR2IO1_GR10_WD_MASK (0x3 << 17)
+#define OMAP4_LPDDR2IO1_GR9_SR_SHIFT 14
+#define OMAP4_LPDDR2IO1_GR9_SR_MASK (0x3 << 14)
+#define OMAP4_LPDDR2IO1_GR9_I_SHIFT 11
+#define OMAP4_LPDDR2IO1_GR9_I_MASK (0x7 << 11)
+#define OMAP4_LPDDR2IO1_GR9_WD_SHIFT 9
+#define OMAP4_LPDDR2IO1_GR9_WD_MASK (0x3 << 9)
+
+/* CONTROL_LPDDR2IO1_3 */
+#define OMAP4_LPDDR21_VREF_CA_CCAP0_SHIFT 31
+#define OMAP4_LPDDR21_VREF_CA_CCAP0_MASK (1 << 31)
+#define OMAP4_LPDDR21_VREF_CA_CCAP1_SHIFT 30
+#define OMAP4_LPDDR21_VREF_CA_CCAP1_MASK (1 << 30)
+#define OMAP4_LPDDR21_VREF_CA_INT_CCAP0_SHIFT 29
+#define OMAP4_LPDDR21_VREF_CA_INT_CCAP0_MASK (1 << 29)
+#define OMAP4_LPDDR21_VREF_CA_INT_CCAP1_SHIFT 28
+#define OMAP4_LPDDR21_VREF_CA_INT_CCAP1_MASK (1 << 28)
+#define OMAP4_LPDDR21_VREF_CA_INT_TAP0_SHIFT 27
+#define OMAP4_LPDDR21_VREF_CA_INT_TAP0_MASK (1 << 27)
+#define OMAP4_LPDDR21_VREF_CA_INT_TAP1_SHIFT 26
+#define OMAP4_LPDDR21_VREF_CA_INT_TAP1_MASK (1 << 26)
+#define OMAP4_LPDDR21_VREF_CA_TAP0_SHIFT 25
+#define OMAP4_LPDDR21_VREF_CA_TAP0_MASK (1 << 25)
+#define OMAP4_LPDDR21_VREF_CA_TAP1_SHIFT 24
+#define OMAP4_LPDDR21_VREF_CA_TAP1_MASK (1 << 24)
+#define OMAP4_LPDDR21_VREF_DQ0_INT_CCAP0_SHIFT 23
+#define OMAP4_LPDDR21_VREF_DQ0_INT_CCAP0_MASK (1 << 23)
+#define OMAP4_LPDDR21_VREF_DQ0_INT_CCAP1_SHIFT 22
+#define OMAP4_LPDDR21_VREF_DQ0_INT_CCAP1_MASK (1 << 22)
+#define OMAP4_LPDDR21_VREF_DQ0_INT_TAP0_SHIFT 21
+#define OMAP4_LPDDR21_VREF_DQ0_INT_TAP0_MASK (1 << 21)
+#define OMAP4_LPDDR21_VREF_DQ0_INT_TAP1_SHIFT 20
+#define OMAP4_LPDDR21_VREF_DQ0_INT_TAP1_MASK (1 << 20)
+#define OMAP4_LPDDR21_VREF_DQ1_INT_CCAP0_SHIFT 19
+#define OMAP4_LPDDR21_VREF_DQ1_INT_CCAP0_MASK (1 << 19)
+#define OMAP4_LPDDR21_VREF_DQ1_INT_CCAP1_SHIFT 18
+#define OMAP4_LPDDR21_VREF_DQ1_INT_CCAP1_MASK (1 << 18)
+#define OMAP4_LPDDR21_VREF_DQ1_INT_TAP0_SHIFT 17
+#define OMAP4_LPDDR21_VREF_DQ1_INT_TAP0_MASK (1 << 17)
+#define OMAP4_LPDDR21_VREF_DQ1_INT_TAP1_SHIFT 16
+#define OMAP4_LPDDR21_VREF_DQ1_INT_TAP1_MASK (1 << 16)
+#define OMAP4_LPDDR21_VREF_DQ_CCAP0_SHIFT 15
+#define OMAP4_LPDDR21_VREF_DQ_CCAP0_MASK (1 << 15)
+#define OMAP4_LPDDR21_VREF_DQ_CCAP1_SHIFT 14
+#define OMAP4_LPDDR21_VREF_DQ_CCAP1_MASK (1 << 14)
+#define OMAP4_LPDDR21_VREF_DQ_TAP0_SHIFT 13
+#define OMAP4_LPDDR21_VREF_DQ_TAP0_MASK (1 << 13)
+#define OMAP4_LPDDR21_VREF_DQ_TAP1_SHIFT 12
+#define OMAP4_LPDDR21_VREF_DQ_TAP1_MASK (1 << 12)
+
+/* CONTROL_LPDDR2IO2_0 */
+#define OMAP4_LPDDR2IO2_GR4_SR_SHIFT 30
+#define OMAP4_LPDDR2IO2_GR4_SR_MASK (0x3 << 30)
+#define OMAP4_LPDDR2IO2_GR4_I_SHIFT 27
+#define OMAP4_LPDDR2IO2_GR4_I_MASK (0x7 << 27)
+#define OMAP4_LPDDR2IO2_GR4_WD_SHIFT 25
+#define OMAP4_LPDDR2IO2_GR4_WD_MASK (0x3 << 25)
+#define OMAP4_LPDDR2IO2_GR3_SR_SHIFT 22
+#define OMAP4_LPDDR2IO2_GR3_SR_MASK (0x3 << 22)
+#define OMAP4_LPDDR2IO2_GR3_I_SHIFT 19
+#define OMAP4_LPDDR2IO2_GR3_I_MASK (0x7 << 19)
+#define OMAP4_LPDDR2IO2_GR3_WD_SHIFT 17
+#define OMAP4_LPDDR2IO2_GR3_WD_MASK (0x3 << 17)
+#define OMAP4_LPDDR2IO2_GR2_SR_SHIFT 14
+#define OMAP4_LPDDR2IO2_GR2_SR_MASK (0x3 << 14)
+#define OMAP4_LPDDR2IO2_GR2_I_SHIFT 11
+#define OMAP4_LPDDR2IO2_GR2_I_MASK (0x7 << 11)
+#define OMAP4_LPDDR2IO2_GR2_WD_SHIFT 9
+#define OMAP4_LPDDR2IO2_GR2_WD_MASK (0x3 << 9)
+#define OMAP4_LPDDR2IO2_GR1_SR_SHIFT 6
+#define OMAP4_LPDDR2IO2_GR1_SR_MASK (0x3 << 6)
+#define OMAP4_LPDDR2IO2_GR1_I_SHIFT 3
+#define OMAP4_LPDDR2IO2_GR1_I_MASK (0x7 << 3)
+#define OMAP4_LPDDR2IO2_GR1_WD_SHIFT 1
+#define OMAP4_LPDDR2IO2_GR1_WD_MASK (0x3 << 1)
+
+/* CONTROL_LPDDR2IO2_1 */
+#define OMAP4_LPDDR2IO2_GR8_SR_SHIFT 30
+#define OMAP4_LPDDR2IO2_GR8_SR_MASK (0x3 << 30)
+#define OMAP4_LPDDR2IO2_GR8_I_SHIFT 27
+#define OMAP4_LPDDR2IO2_GR8_I_MASK (0x7 << 27)
+#define OMAP4_LPDDR2IO2_GR8_WD_SHIFT 25
+#define OMAP4_LPDDR2IO2_GR8_WD_MASK (0x3 << 25)
+#define OMAP4_LPDDR2IO2_GR7_SR_SHIFT 22
+#define OMAP4_LPDDR2IO2_GR7_SR_MASK (0x3 << 22)
+#define OMAP4_LPDDR2IO2_GR7_I_SHIFT 19
+#define OMAP4_LPDDR2IO2_GR7_I_MASK (0x7 << 19)
+#define OMAP4_LPDDR2IO2_GR7_WD_SHIFT 17
+#define OMAP4_LPDDR2IO2_GR7_WD_MASK (0x3 << 17)
+#define OMAP4_LPDDR2IO2_GR6_SR_SHIFT 14
+#define OMAP4_LPDDR2IO2_GR6_SR_MASK (0x3 << 14)
+#define OMAP4_LPDDR2IO2_GR6_I_SHIFT 11
+#define OMAP4_LPDDR2IO2_GR6_I_MASK (0x7 << 11)
+#define OMAP4_LPDDR2IO2_GR6_WD_SHIFT 9
+#define OMAP4_LPDDR2IO2_GR6_WD_MASK (0x3 << 9)
+#define OMAP4_LPDDR2IO2_GR5_SR_SHIFT 6
+#define OMAP4_LPDDR2IO2_GR5_SR_MASK (0x3 << 6)
+#define OMAP4_LPDDR2IO2_GR5_I_SHIFT 3
+#define OMAP4_LPDDR2IO2_GR5_I_MASK (0x7 << 3)
+#define OMAP4_LPDDR2IO2_GR5_WD_SHIFT 1
+#define OMAP4_LPDDR2IO2_GR5_WD_MASK (0x3 << 1)
+
+/* CONTROL_LPDDR2IO2_2 */
+#define OMAP4_LPDDR2IO2_GR11_SR_SHIFT 30
+#define OMAP4_LPDDR2IO2_GR11_SR_MASK (0x3 << 30)
+#define OMAP4_LPDDR2IO2_GR11_I_SHIFT 27
+#define OMAP4_LPDDR2IO2_GR11_I_MASK (0x7 << 27)
+#define OMAP4_LPDDR2IO2_GR11_WD_SHIFT 25
+#define OMAP4_LPDDR2IO2_GR11_WD_MASK (0x3 << 25)
+#define OMAP4_LPDDR2IO2_GR10_SR_SHIFT 22
+#define OMAP4_LPDDR2IO2_GR10_SR_MASK (0x3 << 22)
+#define OMAP4_LPDDR2IO2_GR10_I_SHIFT 19
+#define OMAP4_LPDDR2IO2_GR10_I_MASK (0x7 << 19)
+#define OMAP4_LPDDR2IO2_GR10_WD_SHIFT 17
+#define OMAP4_LPDDR2IO2_GR10_WD_MASK (0x3 << 17)
+#define OMAP4_LPDDR2IO2_GR9_SR_SHIFT 14
+#define OMAP4_LPDDR2IO2_GR9_SR_MASK (0x3 << 14)
+#define OMAP4_LPDDR2IO2_GR9_I_SHIFT 11
+#define OMAP4_LPDDR2IO2_GR9_I_MASK (0x7 << 11)
+#define OMAP4_LPDDR2IO2_GR9_WD_SHIFT 9
+#define OMAP4_LPDDR2IO2_GR9_WD_MASK (0x3 << 9)
+
+/* CONTROL_LPDDR2IO2_3 */
+#define OMAP4_LPDDR22_VREF_CA_CCAP0_SHIFT 31
+#define OMAP4_LPDDR22_VREF_CA_CCAP0_MASK (1 << 31)
+#define OMAP4_LPDDR22_VREF_CA_CCAP1_SHIFT 30
+#define OMAP4_LPDDR22_VREF_CA_CCAP1_MASK (1 << 30)
+#define OMAP4_LPDDR22_VREF_CA_INT_CCAP0_SHIFT 29
+#define OMAP4_LPDDR22_VREF_CA_INT_CCAP0_MASK (1 << 29)
+#define OMAP4_LPDDR22_VREF_CA_INT_CCAP1_SHIFT 28
+#define OMAP4_LPDDR22_VREF_CA_INT_CCAP1_MASK (1 << 28)
+#define OMAP4_LPDDR22_VREF_CA_INT_TAP0_SHIFT 27
+#define OMAP4_LPDDR22_VREF_CA_INT_TAP0_MASK (1 << 27)
+#define OMAP4_LPDDR22_VREF_CA_INT_TAP1_SHIFT 26
+#define OMAP4_LPDDR22_VREF_CA_INT_TAP1_MASK (1 << 26)
+#define OMAP4_LPDDR22_VREF_CA_TAP0_SHIFT 25
+#define OMAP4_LPDDR22_VREF_CA_TAP0_MASK (1 << 25)
+#define OMAP4_LPDDR22_VREF_CA_TAP1_SHIFT 24
+#define OMAP4_LPDDR22_VREF_CA_TAP1_MASK (1 << 24)
+#define OMAP4_LPDDR22_VREF_DQ0_INT_CCAP0_SHIFT 23
+#define OMAP4_LPDDR22_VREF_DQ0_INT_CCAP0_MASK (1 << 23)
+#define OMAP4_LPDDR22_VREF_DQ0_INT_CCAP1_SHIFT 22
+#define OMAP4_LPDDR22_VREF_DQ0_INT_CCAP1_MASK (1 << 22)
+#define OMAP4_LPDDR22_VREF_DQ0_INT_TAP0_SHIFT 21
+#define OMAP4_LPDDR22_VREF_DQ0_INT_TAP0_MASK (1 << 21)
+#define OMAP4_LPDDR22_VREF_DQ0_INT_TAP1_SHIFT 20
+#define OMAP4_LPDDR22_VREF_DQ0_INT_TAP1_MASK (1 << 20)
+#define OMAP4_LPDDR22_VREF_DQ1_INT_CCAP0_SHIFT 19
+#define OMAP4_LPDDR22_VREF_DQ1_INT_CCAP0_MASK (1 << 19)
+#define OMAP4_LPDDR22_VREF_DQ1_INT_CCAP1_SHIFT 18
+#define OMAP4_LPDDR22_VREF_DQ1_INT_CCAP1_MASK (1 << 18)
+#define OMAP4_LPDDR22_VREF_DQ1_INT_TAP0_SHIFT 17
+#define OMAP4_LPDDR22_VREF_DQ1_INT_TAP0_MASK (1 << 17)
+#define OMAP4_LPDDR22_VREF_DQ1_INT_TAP1_SHIFT 16
+#define OMAP4_LPDDR22_VREF_DQ1_INT_TAP1_MASK (1 << 16)
+#define OMAP4_LPDDR22_VREF_DQ_CCAP0_SHIFT 15
+#define OMAP4_LPDDR22_VREF_DQ_CCAP0_MASK (1 << 15)
+#define OMAP4_LPDDR22_VREF_DQ_CCAP1_SHIFT 14
+#define OMAP4_LPDDR22_VREF_DQ_CCAP1_MASK (1 << 14)
+#define OMAP4_LPDDR22_VREF_DQ_TAP0_SHIFT 13
+#define OMAP4_LPDDR22_VREF_DQ_TAP0_MASK (1 << 13)
+#define OMAP4_LPDDR22_VREF_DQ_TAP1_SHIFT 12
+#define OMAP4_LPDDR22_VREF_DQ_TAP1_MASK (1 << 12)
+
+/* CONTROL_BUS_HOLD */
+#define OMAP4_ABE_DMIC_DIN3_EN_SHIFT 31
+#define OMAP4_ABE_DMIC_DIN3_EN_MASK (1 << 31)
+#define OMAP4_MCSPI1_CS3_EN_SHIFT 30
+#define OMAP4_MCSPI1_CS3_EN_MASK (1 << 30)
+
+/* CONTROL_C2C */
+#define OMAP4_MIRROR_MODE_EN_SHIFT 31
+#define OMAP4_MIRROR_MODE_EN_MASK (1 << 31)
+#define OMAP4_C2C_SPARE_SHIFT 24
+#define OMAP4_C2C_SPARE_MASK (0x7f << 24)
+
+/* CORE_CONTROL_SPARE_RW */
+#define OMAP4_CORE_CONTROL_SPARE_RW_SHIFT 0
+#define OMAP4_CORE_CONTROL_SPARE_RW_MASK (0xffffffff << 0)
+
+/* CORE_CONTROL_SPARE_R */
+#define OMAP4_CORE_CONTROL_SPARE_R_SHIFT 0
+#define OMAP4_CORE_CONTROL_SPARE_R_MASK (0xffffffff << 0)
+
+/* CORE_CONTROL_SPARE_R_C0 */
+#define OMAP4_CORE_CONTROL_SPARE_R_C0_SHIFT 31
+#define OMAP4_CORE_CONTROL_SPARE_R_C0_MASK (1 << 31)
+#define OMAP4_CORE_CONTROL_SPARE_R_C1_SHIFT 30
+#define OMAP4_CORE_CONTROL_SPARE_R_C1_MASK (1 << 30)
+#define OMAP4_CORE_CONTROL_SPARE_R_C2_SHIFT 29
+#define OMAP4_CORE_CONTROL_SPARE_R_C2_MASK (1 << 29)
+#define OMAP4_CORE_CONTROL_SPARE_R_C3_SHIFT 28
+#define OMAP4_CORE_CONTROL_SPARE_R_C3_MASK (1 << 28)
+#define OMAP4_CORE_CONTROL_SPARE_R_C4_SHIFT 27
+#define OMAP4_CORE_CONTROL_SPARE_R_C4_MASK (1 << 27)
+#define OMAP4_CORE_CONTROL_SPARE_R_C5_SHIFT 26
+#define OMAP4_CORE_CONTROL_SPARE_R_C5_MASK (1 << 26)
+#define OMAP4_CORE_CONTROL_SPARE_R_C6_SHIFT 25
+#define OMAP4_CORE_CONTROL_SPARE_R_C6_MASK (1 << 25)
+#define OMAP4_CORE_CONTROL_SPARE_R_C7_SHIFT 24
+#define OMAP4_CORE_CONTROL_SPARE_R_C7_MASK (1 << 24)
+
+/* CONTROL_EFUSE_1 */
+#define OMAP4_AVDAC_TRIM_BYTE3_SHIFT 24
+#define OMAP4_AVDAC_TRIM_BYTE3_MASK (0x7f << 24)
+#define OMAP4_AVDAC_TRIM_BYTE2_SHIFT 16
+#define OMAP4_AVDAC_TRIM_BYTE2_MASK (0xff << 16)
+#define OMAP4_AVDAC_TRIM_BYTE1_SHIFT 8
+#define OMAP4_AVDAC_TRIM_BYTE1_MASK (0xff << 8)
+#define OMAP4_AVDAC_TRIM_BYTE0_SHIFT 0
+#define OMAP4_AVDAC_TRIM_BYTE0_MASK (0xff << 0)
+
+/* CONTROL_EFUSE_2 */
+#define OMAP4_EFUSE_SMART2TEST_P0_SHIFT 31
+#define OMAP4_EFUSE_SMART2TEST_P0_MASK (1 << 31)
+#define OMAP4_EFUSE_SMART2TEST_P1_SHIFT 30
+#define OMAP4_EFUSE_SMART2TEST_P1_MASK (1 << 30)
+#define OMAP4_EFUSE_SMART2TEST_P2_SHIFT 29
+#define OMAP4_EFUSE_SMART2TEST_P2_MASK (1 << 29)
+#define OMAP4_EFUSE_SMART2TEST_P3_SHIFT 28
+#define OMAP4_EFUSE_SMART2TEST_P3_MASK (1 << 28)
+#define OMAP4_EFUSE_SMART2TEST_N0_SHIFT 27
+#define OMAP4_EFUSE_SMART2TEST_N0_MASK (1 << 27)
+#define OMAP4_EFUSE_SMART2TEST_N1_SHIFT 26
+#define OMAP4_EFUSE_SMART2TEST_N1_MASK (1 << 26)
+#define OMAP4_EFUSE_SMART2TEST_N2_SHIFT 25
+#define OMAP4_EFUSE_SMART2TEST_N2_MASK (1 << 25)
+#define OMAP4_EFUSE_SMART2TEST_N3_SHIFT 24
+#define OMAP4_EFUSE_SMART2TEST_N3_MASK (1 << 24)
+#define OMAP4_LPDDR2_PTV_N1_SHIFT 23
+#define OMAP4_LPDDR2_PTV_N1_MASK (1 << 23)
+#define OMAP4_LPDDR2_PTV_N2_SHIFT 22
+#define OMAP4_LPDDR2_PTV_N2_MASK (1 << 22)
+#define OMAP4_LPDDR2_PTV_N3_SHIFT 21
+#define OMAP4_LPDDR2_PTV_N3_MASK (1 << 21)
+#define OMAP4_LPDDR2_PTV_N4_SHIFT 20
+#define OMAP4_LPDDR2_PTV_N4_MASK (1 << 20)
+#define OMAP4_LPDDR2_PTV_N5_SHIFT 19
+#define OMAP4_LPDDR2_PTV_N5_MASK (1 << 19)
+#define OMAP4_LPDDR2_PTV_P1_SHIFT 18
+#define OMAP4_LPDDR2_PTV_P1_MASK (1 << 18)
+#define OMAP4_LPDDR2_PTV_P2_SHIFT 17
+#define OMAP4_LPDDR2_PTV_P2_MASK (1 << 17)
+#define OMAP4_LPDDR2_PTV_P3_SHIFT 16
+#define OMAP4_LPDDR2_PTV_P3_MASK (1 << 16)
+#define OMAP4_LPDDR2_PTV_P4_SHIFT 15
+#define OMAP4_LPDDR2_PTV_P4_MASK (1 << 15)
+#define OMAP4_LPDDR2_PTV_P5_SHIFT 14
+#define OMAP4_LPDDR2_PTV_P5_MASK (1 << 14)
+
+/* CONTROL_EFUSE_3 */
+#define OMAP4_STD_FUSE_SPARE_1_SHIFT 24
+#define OMAP4_STD_FUSE_SPARE_1_MASK (0xff << 24)
+#define OMAP4_STD_FUSE_SPARE_2_SHIFT 16
+#define OMAP4_STD_FUSE_SPARE_2_MASK (0xff << 16)
+#define OMAP4_STD_FUSE_SPARE_3_SHIFT 8
+#define OMAP4_STD_FUSE_SPARE_3_MASK (0xff << 8)
+#define OMAP4_STD_FUSE_SPARE_4_SHIFT 0
+#define OMAP4_STD_FUSE_SPARE_4_MASK (0xff << 0)
+
+/* CONTROL_EFUSE_4 */
+#define OMAP4_STD_FUSE_SPARE_5_SHIFT 24
+#define OMAP4_STD_FUSE_SPARE_5_MASK (0xff << 24)
+#define OMAP4_STD_FUSE_SPARE_6_SHIFT 16
+#define OMAP4_STD_FUSE_SPARE_6_MASK (0xff << 16)
+#define OMAP4_STD_FUSE_SPARE_7_SHIFT 8
+#define OMAP4_STD_FUSE_SPARE_7_MASK (0xff << 8)
+#define OMAP4_STD_FUSE_SPARE_8_SHIFT 0
+#define OMAP4_STD_FUSE_SPARE_8_MASK (0xff << 0)
+
+#endif
diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_pad_wkup_44xx.h b/arch/arm/mach-omap2/include/mach/ctrl_module_pad_wkup_44xx.h
new file mode 100644
index 000000000000..17c9b37042c0
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/ctrl_module_pad_wkup_44xx.h
@@ -0,0 +1,236 @@
+/*
+ * OMAP44xx CTRL_MODULE_PAD_WKUP registers and bitfields
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@ti.com)
+ * Santosh Shilimkar (santosh.shilimkar@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * 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 __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_PAD_WKUP_44XX_H
+#define __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_PAD_WKUP_44XX_H
+
+
+/* Base address */
+#define OMAP4_CTRL_MODULE_PAD_WKUP 0x4a31e000
+
+/* Registers offset */
+#define OMAP4_CTRL_MODULE_PAD_WKUP_IP_REVISION 0x0000
+#define OMAP4_CTRL_MODULE_PAD_WKUP_IP_HWINFO 0x0004
+#define OMAP4_CTRL_MODULE_PAD_WKUP_IP_SYSCONFIG 0x0010
+#define OMAP4_CTRL_MODULE_PAD_WKUP_PADCONF_WAKEUPEVENT_0 0x007c
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_SMART1NOPMIO_PADCONF_0 0x05a0
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_SMART1NOPMIO_PADCONF_1 0x05a4
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_PADCONF_MODE 0x05a8
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_XTAL_OSCILLATOR 0x05ac
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_USIMIO 0x0600
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_I2C_2 0x0604
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_JTAG 0x0608
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_SYS 0x060c
+#define OMAP4_CTRL_MODULE_PAD_WKUP_WKUP_CONTROL_SPARE_RW 0x0614
+#define OMAP4_CTRL_MODULE_PAD_WKUP_WKUP_CONTROL_SPARE_R 0x0618
+#define OMAP4_CTRL_MODULE_PAD_WKUP_WKUP_CONTROL_SPARE_R_C0 0x061c
+
+/* Registers shifts and masks */
+
+/* IP_REVISION */
+#define OMAP4_IP_REV_SCHEME_SHIFT 30
+#define OMAP4_IP_REV_SCHEME_MASK (0x3 << 30)
+#define OMAP4_IP_REV_FUNC_SHIFT 16
+#define OMAP4_IP_REV_FUNC_MASK (0xfff << 16)
+#define OMAP4_IP_REV_RTL_SHIFT 11
+#define OMAP4_IP_REV_RTL_MASK (0x1f << 11)
+#define OMAP4_IP_REV_MAJOR_SHIFT 8
+#define OMAP4_IP_REV_MAJOR_MASK (0x7 << 8)
+#define OMAP4_IP_REV_CUSTOM_SHIFT 6
+#define OMAP4_IP_REV_CUSTOM_MASK (0x3 << 6)
+#define OMAP4_IP_REV_MINOR_SHIFT 0
+#define OMAP4_IP_REV_MINOR_MASK (0x3f << 0)
+
+/* IP_HWINFO */
+#define OMAP4_IP_HWINFO_SHIFT 0
+#define OMAP4_IP_HWINFO_MASK (0xffffffff << 0)
+
+/* IP_SYSCONFIG */
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_SHIFT 2
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_MASK (0x3 << 2)
+
+/* PADCONF_WAKEUPEVENT_0 */
+#define OMAP4_JTAG_TDO_DUPLICATEWAKEUPEVENT_SHIFT 24
+#define OMAP4_JTAG_TDO_DUPLICATEWAKEUPEVENT_MASK (1 << 24)
+#define OMAP4_JTAG_TDI_DUPLICATEWAKEUPEVENT_SHIFT 23
+#define OMAP4_JTAG_TDI_DUPLICATEWAKEUPEVENT_MASK (1 << 23)
+#define OMAP4_JTAG_TMS_TMSC_DUPLICATEWAKEUPEVENT_SHIFT 22
+#define OMAP4_JTAG_TMS_TMSC_DUPLICATEWAKEUPEVENT_MASK (1 << 22)
+#define OMAP4_JTAG_RTCK_DUPLICATEWAKEUPEVENT_SHIFT 21
+#define OMAP4_JTAG_RTCK_DUPLICATEWAKEUPEVENT_MASK (1 << 21)
+#define OMAP4_JTAG_TCK_DUPLICATEWAKEUPEVENT_SHIFT 20
+#define OMAP4_JTAG_TCK_DUPLICATEWAKEUPEVENT_MASK (1 << 20)
+#define OMAP4_JTAG_NTRST_DUPLICATEWAKEUPEVENT_SHIFT 19
+#define OMAP4_JTAG_NTRST_DUPLICATEWAKEUPEVENT_MASK (1 << 19)
+#define OMAP4_SYS_BOOT7_DUPLICATEWAKEUPEVENT_SHIFT 18
+#define OMAP4_SYS_BOOT7_DUPLICATEWAKEUPEVENT_MASK (1 << 18)
+#define OMAP4_SYS_BOOT6_DUPLICATEWAKEUPEVENT_SHIFT 17
+#define OMAP4_SYS_BOOT6_DUPLICATEWAKEUPEVENT_MASK (1 << 17)
+#define OMAP4_SYS_PWRON_RESET_OUT_DUPLICATEWAKEUPEVENT_SHIFT 16
+#define OMAP4_SYS_PWRON_RESET_OUT_DUPLICATEWAKEUPEVENT_MASK (1 << 16)
+#define OMAP4_SYS_PWR_REQ_DUPLICATEWAKEUPEVENT_SHIFT 15
+#define OMAP4_SYS_PWR_REQ_DUPLICATEWAKEUPEVENT_MASK (1 << 15)
+#define OMAP4_SYS_NRESWARM_DUPLICATEWAKEUPEVENT_SHIFT 14
+#define OMAP4_SYS_NRESWARM_DUPLICATEWAKEUPEVENT_MASK (1 << 14)
+#define OMAP4_SYS_32K_DUPLICATEWAKEUPEVENT_SHIFT 13
+#define OMAP4_SYS_32K_DUPLICATEWAKEUPEVENT_MASK (1 << 13)
+#define OMAP4_FREF_CLK4_OUT_DUPLICATEWAKEUPEVENT_SHIFT 12
+#define OMAP4_FREF_CLK4_OUT_DUPLICATEWAKEUPEVENT_MASK (1 << 12)
+#define OMAP4_FREF_CLK4_REQ_DUPLICATEWAKEUPEVENT_SHIFT 11
+#define OMAP4_FREF_CLK4_REQ_DUPLICATEWAKEUPEVENT_MASK (1 << 11)
+#define OMAP4_FREF_CLK3_OUT_DUPLICATEWAKEUPEVENT_SHIFT 10
+#define OMAP4_FREF_CLK3_OUT_DUPLICATEWAKEUPEVENT_MASK (1 << 10)
+#define OMAP4_FREF_CLK3_REQ_DUPLICATEWAKEUPEVENT_SHIFT 9
+#define OMAP4_FREF_CLK3_REQ_DUPLICATEWAKEUPEVENT_MASK (1 << 9)
+#define OMAP4_FREF_CLK0_OUT_DUPLICATEWAKEUPEVENT_SHIFT 8
+#define OMAP4_FREF_CLK0_OUT_DUPLICATEWAKEUPEVENT_MASK (1 << 8)
+#define OMAP4_FREF_CLK_IOREQ_DUPLICATEWAKEUPEVENT_SHIFT 7
+#define OMAP4_FREF_CLK_IOREQ_DUPLICATEWAKEUPEVENT_MASK (1 << 7)
+#define OMAP4_SR_SDA_DUPLICATEWAKEUPEVENT_SHIFT 6
+#define OMAP4_SR_SDA_DUPLICATEWAKEUPEVENT_MASK (1 << 6)
+#define OMAP4_SR_SCL_DUPLICATEWAKEUPEVENT_SHIFT 5
+#define OMAP4_SR_SCL_DUPLICATEWAKEUPEVENT_MASK (1 << 5)
+#define OMAP4_SIM_PWRCTRL_DUPLICATEWAKEUPEVENT_SHIFT 4
+#define OMAP4_SIM_PWRCTRL_DUPLICATEWAKEUPEVENT_MASK (1 << 4)
+#define OMAP4_SIM_CD_DUPLICATEWAKEUPEVENT_SHIFT 3
+#define OMAP4_SIM_CD_DUPLICATEWAKEUPEVENT_MASK (1 << 3)
+#define OMAP4_SIM_RESET_DUPLICATEWAKEUPEVENT_SHIFT 2
+#define OMAP4_SIM_RESET_DUPLICATEWAKEUPEVENT_MASK (1 << 2)
+#define OMAP4_SIM_CLK_DUPLICATEWAKEUPEVENT_SHIFT 1
+#define OMAP4_SIM_CLK_DUPLICATEWAKEUPEVENT_MASK (1 << 1)
+#define OMAP4_SIM_IO_DUPLICATEWAKEUPEVENT_SHIFT 0
+#define OMAP4_SIM_IO_DUPLICATEWAKEUPEVENT_MASK (1 << 0)
+
+/* CONTROL_SMART1NOPMIO_PADCONF_0 */
+#define OMAP4_FREF_DR0_SC_SHIFT 30
+#define OMAP4_FREF_DR0_SC_MASK (0x3 << 30)
+#define OMAP4_FREF_DR1_SC_SHIFT 28
+#define OMAP4_FREF_DR1_SC_MASK (0x3 << 28)
+#define OMAP4_FREF_DR4_SC_SHIFT 26
+#define OMAP4_FREF_DR4_SC_MASK (0x3 << 26)
+#define OMAP4_FREF_DR5_SC_SHIFT 24
+#define OMAP4_FREF_DR5_SC_MASK (0x3 << 24)
+#define OMAP4_FREF_DR6_SC_SHIFT 22
+#define OMAP4_FREF_DR6_SC_MASK (0x3 << 22)
+#define OMAP4_FREF_DR7_SC_SHIFT 20
+#define OMAP4_FREF_DR7_SC_MASK (0x3 << 20)
+#define OMAP4_GPIO_DR7_SC_SHIFT 18
+#define OMAP4_GPIO_DR7_SC_MASK (0x3 << 18)
+#define OMAP4_DPM_DR0_SC_SHIFT 14
+#define OMAP4_DPM_DR0_SC_MASK (0x3 << 14)
+#define OMAP4_SIM_DR0_SC_SHIFT 12
+#define OMAP4_SIM_DR0_SC_MASK (0x3 << 12)
+
+/* CONTROL_SMART1NOPMIO_PADCONF_1 */
+#define OMAP4_FREF_DR0_LB_SHIFT 30
+#define OMAP4_FREF_DR0_LB_MASK (0x3 << 30)
+#define OMAP4_FREF_DR1_LB_SHIFT 28
+#define OMAP4_FREF_DR1_LB_MASK (0x3 << 28)
+#define OMAP4_FREF_DR4_LB_SHIFT 26
+#define OMAP4_FREF_DR4_LB_MASK (0x3 << 26)
+#define OMAP4_FREF_DR5_LB_SHIFT 24
+#define OMAP4_FREF_DR5_LB_MASK (0x3 << 24)
+#define OMAP4_FREF_DR6_LB_SHIFT 22
+#define OMAP4_FREF_DR6_LB_MASK (0x3 << 22)
+#define OMAP4_FREF_DR7_LB_SHIFT 20
+#define OMAP4_FREF_DR7_LB_MASK (0x3 << 20)
+#define OMAP4_GPIO_DR7_LB_SHIFT 18
+#define OMAP4_GPIO_DR7_LB_MASK (0x3 << 18)
+#define OMAP4_DPM_DR0_LB_SHIFT 14
+#define OMAP4_DPM_DR0_LB_MASK (0x3 << 14)
+#define OMAP4_SIM_DR0_LB_SHIFT 12
+#define OMAP4_SIM_DR0_LB_MASK (0x3 << 12)
+
+/* CONTROL_PADCONF_MODE */
+#define OMAP4_VDDS_DV_FREF_SHIFT 31
+#define OMAP4_VDDS_DV_FREF_MASK (1 << 31)
+#define OMAP4_VDDS_DV_BANK2_SHIFT 30
+#define OMAP4_VDDS_DV_BANK2_MASK (1 << 30)
+
+/* CONTROL_XTAL_OSCILLATOR */
+#define OMAP4_OSCILLATOR_BOOST_SHIFT 31
+#define OMAP4_OSCILLATOR_BOOST_MASK (1 << 31)
+#define OMAP4_OSCILLATOR_OS_OUT_SHIFT 30
+#define OMAP4_OSCILLATOR_OS_OUT_MASK (1 << 30)
+
+/* CONTROL_USIMIO */
+#define OMAP4_PAD_USIM_CLK_LOW_SHIFT 31
+#define OMAP4_PAD_USIM_CLK_LOW_MASK (1 << 31)
+#define OMAP4_PAD_USIM_RST_LOW_SHIFT 29
+#define OMAP4_PAD_USIM_RST_LOW_MASK (1 << 29)
+#define OMAP4_USIM_PWRDNZ_SHIFT 28
+#define OMAP4_USIM_PWRDNZ_MASK (1 << 28)
+
+/* CONTROL_I2C_2 */
+#define OMAP4_SR_SDA_GLFENB_SHIFT 31
+#define OMAP4_SR_SDA_GLFENB_MASK (1 << 31)
+#define OMAP4_SR_SDA_LOAD_BITS_SHIFT 29
+#define OMAP4_SR_SDA_LOAD_BITS_MASK (0x3 << 29)
+#define OMAP4_SR_SDA_PULLUPRESX_SHIFT 28
+#define OMAP4_SR_SDA_PULLUPRESX_MASK (1 << 28)
+#define OMAP4_SR_SCL_GLFENB_SHIFT 27
+#define OMAP4_SR_SCL_GLFENB_MASK (1 << 27)
+#define OMAP4_SR_SCL_LOAD_BITS_SHIFT 25
+#define OMAP4_SR_SCL_LOAD_BITS_MASK (0x3 << 25)
+#define OMAP4_SR_SCL_PULLUPRESX_SHIFT 24
+#define OMAP4_SR_SCL_PULLUPRESX_MASK (1 << 24)
+
+/* CONTROL_JTAG */
+#define OMAP4_JTAG_NTRST_EN_SHIFT 31
+#define OMAP4_JTAG_NTRST_EN_MASK (1 << 31)
+#define OMAP4_JTAG_TCK_EN_SHIFT 30
+#define OMAP4_JTAG_TCK_EN_MASK (1 << 30)
+#define OMAP4_JTAG_RTCK_EN_SHIFT 29
+#define OMAP4_JTAG_RTCK_EN_MASK (1 << 29)
+#define OMAP4_JTAG_TDI_EN_SHIFT 28
+#define OMAP4_JTAG_TDI_EN_MASK (1 << 28)
+#define OMAP4_JTAG_TDO_EN_SHIFT 27
+#define OMAP4_JTAG_TDO_EN_MASK (1 << 27)
+
+/* CONTROL_SYS */
+#define OMAP4_SYS_NRESWARM_PIPU_SHIFT 31
+#define OMAP4_SYS_NRESWARM_PIPU_MASK (1 << 31)
+
+/* WKUP_CONTROL_SPARE_RW */
+#define OMAP4_WKUP_CONTROL_SPARE_RW_SHIFT 0
+#define OMAP4_WKUP_CONTROL_SPARE_RW_MASK (0xffffffff << 0)
+
+/* WKUP_CONTROL_SPARE_R */
+#define OMAP4_WKUP_CONTROL_SPARE_R_SHIFT 0
+#define OMAP4_WKUP_CONTROL_SPARE_R_MASK (0xffffffff << 0)
+
+/* WKUP_CONTROL_SPARE_R_C0 */
+#define OMAP4_WKUP_CONTROL_SPARE_R_C0_SHIFT 31
+#define OMAP4_WKUP_CONTROL_SPARE_R_C0_MASK (1 << 31)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C1_SHIFT 30
+#define OMAP4_WKUP_CONTROL_SPARE_R_C1_MASK (1 << 30)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C2_SHIFT 29
+#define OMAP4_WKUP_CONTROL_SPARE_R_C2_MASK (1 << 29)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C3_SHIFT 28
+#define OMAP4_WKUP_CONTROL_SPARE_R_C3_MASK (1 << 28)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C4_SHIFT 27
+#define OMAP4_WKUP_CONTROL_SPARE_R_C4_MASK (1 << 27)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C5_SHIFT 26
+#define OMAP4_WKUP_CONTROL_SPARE_R_C5_MASK (1 << 26)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C6_SHIFT 25
+#define OMAP4_WKUP_CONTROL_SPARE_R_C6_MASK (1 << 25)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C7_SHIFT 24
+#define OMAP4_WKUP_CONTROL_SPARE_R_C7_MASK (1 << 24)
+
+#endif
diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h b/arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h
new file mode 100644
index 000000000000..a0af9baec3f7
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h
@@ -0,0 +1,92 @@
+/*
+ * OMAP44xx CTRL_MODULE_WKUP registers and bitfields
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@ti.com)
+ * Santosh Shilimkar (santosh.shilimkar@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * 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 __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_WKUP_44XX_H
+#define __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_WKUP_44XX_H
+
+
+/* Base address */
+#define OMAP4_CTRL_MODULE_WKUP 0x4a30c000
+
+/* Registers offset */
+#define OMAP4_CTRL_MODULE_WKUP_IP_REVISION 0x0000
+#define OMAP4_CTRL_MODULE_WKUP_IP_HWINFO 0x0004
+#define OMAP4_CTRL_MODULE_WKUP_IP_SYSCONFIG 0x0010
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_0 0x0460
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_1 0x0464
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_2 0x0468
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_3 0x046c
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_4 0x0470
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_5 0x0474
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_6 0x0478
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_7 0x047c
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_8 0x0480
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_9 0x0484
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_10 0x0488
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_11 0x048c
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_12 0x0490
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_13 0x0494
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_14 0x0498
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_15 0x049c
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_16 0x04a0
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_17 0x04a4
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_18 0x04a8
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_19 0x04ac
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_20 0x04b0
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_21 0x04b4
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_22 0x04b8
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_23 0x04bc
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_24 0x04c0
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_25 0x04c4
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_26 0x04c8
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_27 0x04cc
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_28 0x04d0
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_29 0x04d4
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_30 0x04d8
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_31 0x04dc
+
+/* Registers shifts and masks */
+
+/* IP_REVISION */
+#define OMAP4_IP_REV_SCHEME_SHIFT 30
+#define OMAP4_IP_REV_SCHEME_MASK (0x3 << 30)
+#define OMAP4_IP_REV_FUNC_SHIFT 16
+#define OMAP4_IP_REV_FUNC_MASK (0xfff << 16)
+#define OMAP4_IP_REV_RTL_SHIFT 11
+#define OMAP4_IP_REV_RTL_MASK (0x1f << 11)
+#define OMAP4_IP_REV_MAJOR_SHIFT 8
+#define OMAP4_IP_REV_MAJOR_MASK (0x7 << 8)
+#define OMAP4_IP_REV_CUSTOM_SHIFT 6
+#define OMAP4_IP_REV_CUSTOM_MASK (0x3 << 6)
+#define OMAP4_IP_REV_MINOR_SHIFT 0
+#define OMAP4_IP_REV_MINOR_MASK (0x3f << 0)
+
+/* IP_HWINFO */
+#define OMAP4_IP_HWINFO_SHIFT 0
+#define OMAP4_IP_HWINFO_MASK (0xffffffff << 0)
+
+/* IP_SYSCONFIG */
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_SHIFT 2
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_MASK (0x3 << 2)
+
+/* CONF_DEBUG_SEL_TST_0 */
+#define OMAP4_WKUP_MODE_SHIFT 0
+#define OMAP4_WKUP_MODE_MASK (1 << 0)
+
+#endif
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index b9ea70bce563..40562ddd3ee4 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -36,6 +36,7 @@
#include "clock2xxx.h"
#include "clock3xxx.h"
#include "clock44xx.h"
+#include "io.h"
#include <plat/omap-pm.h>
#include <plat/powerdomain.h>
@@ -323,6 +324,9 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0,
omap2430_hwmod_init();
else if (cpu_is_omap34xx())
omap3xxx_hwmod_init();
+ else if (cpu_is_omap44xx())
+ omap44xx_hwmod_init();
+
/* The OPP tables have to be registered before a clk init */
omap_pm_if_early_init(mpu_opps, dsp_opps, l3_opps);
@@ -342,9 +346,7 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0,
#ifndef CONFIG_PM_RUNTIME
skip_setup_idle = 1;
#endif
- if (cpu_is_omap24xx() || cpu_is_omap34xx()) /* FIXME: OMAP4 */
- omap_hwmod_late_init(skip_setup_idle);
-
+ omap_hwmod_late_init(skip_setup_idle);
if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
omap2_sdrc_init(sdrc_cs0, sdrc_cs1);
_omap2_init_reprogram_sdrc();
diff --git a/arch/arm/mach-omap2/io.h b/arch/arm/mach-omap2/io.h
new file mode 100644
index 000000000000..fd230c6cded5
--- /dev/null
+++ b/arch/arm/mach-omap2/io.h
@@ -0,0 +1,7 @@
+
+#ifndef __MACH_OMAP2_IO_H__
+#define __MACH_OMAP2_IO_H__
+
+extern int __init omap_sram_init(void);
+
+#endif /* __MACH_OMAP2_IO_H__ */
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 26aeef560aa3..32eeabe9d2ab 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -47,7 +47,6 @@ static struct omap_irq_bank {
} __attribute__ ((aligned(4))) irq_banks[] = {
{
/* MPU INTC */
- .base_reg = 0,
.nr_irqs = 96,
},
};
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
index 42dbfa46e656..40ddecab93a9 100644
--- a/arch/arm/mach-omap2/mailbox.c
+++ b/arch/arm/mach-omap2/mailbox.c
@@ -181,7 +181,7 @@ static int omap2_mbox_fifo_full(struct omap_mbox *mbox)
static void omap2_mbox_enable_irq(struct omap_mbox *mbox,
omap_mbox_type_t irq)
{
- struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+ struct omap_mbox2_priv *p = mbox->priv;
u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
l = mbox_read_reg(p->irqenable);
@@ -192,7 +192,7 @@ static void omap2_mbox_enable_irq(struct omap_mbox *mbox,
static void omap2_mbox_disable_irq(struct omap_mbox *mbox,
omap_mbox_type_t irq)
{
- struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+ struct omap_mbox2_priv *p = mbox->priv;
u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
l = mbox_read_reg(p->irqdisable);
l &= ~bit;
@@ -202,7 +202,7 @@ static void omap2_mbox_disable_irq(struct omap_mbox *mbox,
static void omap2_mbox_ack_irq(struct omap_mbox *mbox,
omap_mbox_type_t irq)
{
- struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+ struct omap_mbox2_priv *p = mbox->priv;
u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
mbox_write_reg(bit, p->irqstatus);
@@ -214,7 +214,7 @@ static void omap2_mbox_ack_irq(struct omap_mbox *mbox,
static int omap2_mbox_is_irq(struct omap_mbox *mbox,
omap_mbox_type_t irq)
{
- struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+ struct omap_mbox2_priv *p = mbox->priv;
u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
u32 enable = mbox_read_reg(p->irqenable);
u32 status = mbox_read_reg(p->irqstatus);
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c
index 467aae245781..f9c9df5b5ff1 100644
--- a/arch/arm/mach-omap2/mcbsp.c
+++ b/arch/arm/mach-omap2/mcbsp.c
@@ -23,29 +23,86 @@
#include <plat/cpu.h>
#include <plat/mcbsp.h>
-#include "mux.h"
+#include "control.h"
-static void omap2_mcbsp2_mux_setup(void)
+
+/* McBSP internal signal muxing functions */
+
+void omap2_mcbsp1_mux_clkr_src(u8 mux)
{
- omap_mux_init_signal("eac_ac_sclk.mcbsp2_clkx", OMAP_PULL_ENA);
- omap_mux_init_signal("eac_ac_fs.mcbsp2_fsx", OMAP_PULL_ENA);
- omap_mux_init_signal("eac_ac_din.mcbsp2_dr", OMAP_PULL_ENA);
- omap_mux_init_signal("eac_ac_dout.mcbsp2_dx", OMAP_PULL_ENA);
- omap_mux_init_gpio(117, OMAP_PULL_ENA);
- /*
- * TODO: Need to add MUX settings for OMAP 2430 SDP
- */
+ u32 v;
+
+ v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
+ if (mux == CLKR_SRC_CLKR)
+ v &= ~OMAP2_MCBSP1_CLKR_MASK;
+ else if (mux == CLKR_SRC_CLKX)
+ v |= OMAP2_MCBSP1_CLKR_MASK;
+ omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
}
+EXPORT_SYMBOL(omap2_mcbsp1_mux_clkr_src);
-static void omap2_mcbsp_request(unsigned int id)
+void omap2_mcbsp1_mux_fsr_src(u8 mux)
{
- if (cpu_is_omap2420() && (id == OMAP_MCBSP2))
- omap2_mcbsp2_mux_setup();
+ u32 v;
+
+ v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
+ if (mux == FSR_SRC_FSR)
+ v &= ~OMAP2_MCBSP1_FSR_MASK;
+ else if (mux == FSR_SRC_FSX)
+ v |= OMAP2_MCBSP1_FSR_MASK;
+ omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
}
+EXPORT_SYMBOL(omap2_mcbsp1_mux_fsr_src);
-static struct omap_mcbsp_ops omap2_mcbsp_ops = {
- .request = omap2_mcbsp_request,
-};
+/* McBSP CLKS source switching function */
+
+int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id)
+{
+ struct omap_mcbsp *mcbsp;
+ struct clk *fck_src;
+ char *fck_src_name;
+ int r;
+
+ if (!omap_mcbsp_check_valid_id(id)) {
+ pr_err("%s: Invalid id (%d)\n", __func__, id + 1);
+ return -EINVAL;
+ }
+ mcbsp = id_to_mcbsp_ptr(id);
+
+ if (fck_src_id == MCBSP_CLKS_PAD_SRC)
+ fck_src_name = "pad_fck";
+ else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
+ fck_src_name = "prcm_fck";
+ else
+ return -EINVAL;
+
+ fck_src = clk_get(mcbsp->dev, fck_src_name);
+ if (IS_ERR_OR_NULL(fck_src)) {
+ pr_err("omap-mcbsp: %s: could not clk_get() %s\n", "clks",
+ fck_src_name);
+ return -EINVAL;
+ }
+
+ clk_disable(mcbsp->fclk);
+
+ r = clk_set_parent(mcbsp->fclk, fck_src);
+ if (IS_ERR_VALUE(r)) {
+ pr_err("omap-mcbsp: %s: could not clk_set_parent() to %s\n",
+ "clks", fck_src_name);
+ clk_put(fck_src);
+ return -EINVAL;
+ }
+
+ clk_enable(mcbsp->fclk);
+
+ clk_put(fck_src);
+
+ return 0;
+}
+EXPORT_SYMBOL(omap2_mcbsp_set_clks_src);
+
+
+/* Platform data */
#ifdef CONFIG_ARCH_OMAP2420
static struct omap_mcbsp_platform_data omap2420_mcbsp_pdata[] = {
@@ -55,7 +112,6 @@ static struct omap_mcbsp_platform_data omap2420_mcbsp_pdata[] = {
.dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX,
.rx_irq = INT_24XX_MCBSP1_IRQ_RX,
.tx_irq = INT_24XX_MCBSP1_IRQ_TX,
- .ops = &omap2_mcbsp_ops,
},
{
.phys_base = OMAP24XX_MCBSP2_BASE,
@@ -63,7 +119,6 @@ static struct omap_mcbsp_platform_data omap2420_mcbsp_pdata[] = {
.dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX,
.rx_irq = INT_24XX_MCBSP2_IRQ_RX,
.tx_irq = INT_24XX_MCBSP2_IRQ_TX,
- .ops = &omap2_mcbsp_ops,
},
};
#define OMAP2420_MCBSP_PDATA_SZ ARRAY_SIZE(omap2420_mcbsp_pdata)
@@ -82,7 +137,6 @@ static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = {
.dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX,
.rx_irq = INT_24XX_MCBSP1_IRQ_RX,
.tx_irq = INT_24XX_MCBSP1_IRQ_TX,
- .ops = &omap2_mcbsp_ops,
},
{
.phys_base = OMAP24XX_MCBSP2_BASE,
@@ -90,7 +144,6 @@ static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = {
.dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX,
.rx_irq = INT_24XX_MCBSP2_IRQ_RX,
.tx_irq = INT_24XX_MCBSP2_IRQ_TX,
- .ops = &omap2_mcbsp_ops,
},
{
.phys_base = OMAP2430_MCBSP3_BASE,
@@ -98,7 +151,6 @@ static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = {
.dma_tx_sync = OMAP24XX_DMA_MCBSP3_TX,
.rx_irq = INT_24XX_MCBSP3_IRQ_RX,
.tx_irq = INT_24XX_MCBSP3_IRQ_TX,
- .ops = &omap2_mcbsp_ops,
},
{
.phys_base = OMAP2430_MCBSP4_BASE,
@@ -106,7 +158,6 @@ static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = {
.dma_tx_sync = OMAP24XX_DMA_MCBSP4_TX,
.rx_irq = INT_24XX_MCBSP4_IRQ_RX,
.tx_irq = INT_24XX_MCBSP4_IRQ_TX,
- .ops = &omap2_mcbsp_ops,
},
{
.phys_base = OMAP2430_MCBSP5_BASE,
@@ -114,7 +165,6 @@ static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = {
.dma_tx_sync = OMAP24XX_DMA_MCBSP5_TX,
.rx_irq = INT_24XX_MCBSP5_IRQ_RX,
.tx_irq = INT_24XX_MCBSP5_IRQ_TX,
- .ops = &omap2_mcbsp_ops,
},
};
#define OMAP2430_MCBSP_PDATA_SZ ARRAY_SIZE(omap2430_mcbsp_pdata)
@@ -133,7 +183,6 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX,
.rx_irq = INT_24XX_MCBSP1_IRQ_RX,
.tx_irq = INT_24XX_MCBSP1_IRQ_TX,
- .ops = &omap2_mcbsp_ops,
.buffer_size = 0x80, /* The FIFO has 128 locations */
},
{
@@ -143,7 +192,6 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX,
.rx_irq = INT_24XX_MCBSP2_IRQ_RX,
.tx_irq = INT_24XX_MCBSP2_IRQ_TX,
- .ops = &omap2_mcbsp_ops,
.buffer_size = 0x500, /* The FIFO has 1024 + 256 locations */
},
{
@@ -153,7 +201,6 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.dma_tx_sync = OMAP24XX_DMA_MCBSP3_TX,
.rx_irq = INT_24XX_MCBSP3_IRQ_RX,
.tx_irq = INT_24XX_MCBSP3_IRQ_TX,
- .ops = &omap2_mcbsp_ops,
.buffer_size = 0x80, /* The FIFO has 128 locations */
},
{
@@ -162,7 +209,6 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.dma_tx_sync = OMAP24XX_DMA_MCBSP4_TX,
.rx_irq = INT_24XX_MCBSP4_IRQ_RX,
.tx_irq = INT_24XX_MCBSP4_IRQ_TX,
- .ops = &omap2_mcbsp_ops,
.buffer_size = 0x80, /* The FIFO has 128 locations */
},
{
@@ -171,7 +217,6 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.dma_tx_sync = OMAP24XX_DMA_MCBSP5_TX,
.rx_irq = INT_24XX_MCBSP5_IRQ_RX,
.tx_irq = INT_24XX_MCBSP5_IRQ_TX,
- .ops = &omap2_mcbsp_ops,
.buffer_size = 0x80, /* The FIFO has 128 locations */
},
};
@@ -189,28 +234,24 @@ static struct omap_mcbsp_platform_data omap44xx_mcbsp_pdata[] = {
.dma_rx_sync = OMAP44XX_DMA_MCBSP1_RX,
.dma_tx_sync = OMAP44XX_DMA_MCBSP1_TX,
.tx_irq = OMAP44XX_IRQ_MCBSP1,
- .ops = &omap2_mcbsp_ops,
},
{
.phys_base = OMAP44XX_MCBSP2_BASE,
.dma_rx_sync = OMAP44XX_DMA_MCBSP2_RX,
.dma_tx_sync = OMAP44XX_DMA_MCBSP2_TX,
.tx_irq = OMAP44XX_IRQ_MCBSP2,
- .ops = &omap2_mcbsp_ops,
},
{
.phys_base = OMAP44XX_MCBSP3_BASE,
.dma_rx_sync = OMAP44XX_DMA_MCBSP3_RX,
.dma_tx_sync = OMAP44XX_DMA_MCBSP3_TX,
.tx_irq = OMAP44XX_IRQ_MCBSP3,
- .ops = &omap2_mcbsp_ops,
},
{
.phys_base = OMAP44XX_MCBSP4_BASE,
.dma_rx_sync = OMAP44XX_DMA_MCBSP4_RX,
.dma_tx_sync = OMAP44XX_DMA_MCBSP4_TX,
.tx_irq = OMAP44XX_IRQ_MCBSP4,
- .ops = &omap2_mcbsp_ops,
},
};
#define OMAP44XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap44xx_mcbsp_pdata)
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index ab403b2ed26b..074536ae401f 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -23,12 +23,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
#include <linux/list.h>
+#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
@@ -36,8 +35,7 @@
#include <asm/system.h>
-#include <plat/control.h>
-
+#include "control.h"
#include "mux.h"
#define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */
@@ -87,7 +85,7 @@ static char *omap_mux_options;
int __init omap_mux_init_gpio(int gpio, int val)
{
struct omap_mux_entry *e;
- struct omap_mux *gpio_mux;
+ struct omap_mux *gpio_mux = NULL;
u16 old_mode;
u16 mux_mode;
int found = 0;
@@ -127,17 +125,16 @@ int __init omap_mux_init_gpio(int gpio, int val)
return 0;
}
-int __init omap_mux_init_signal(char *muxname, int val)
+int __init omap_mux_init_signal(const char *muxname, int val)
{
struct omap_mux_entry *e;
- char *m0_name = NULL, *mode_name = NULL;
- int found = 0;
+ const char *mode_name;
+ int found = 0, mode0_len = 0;
mode_name = strchr(muxname, '.');
if (mode_name) {
- *mode_name = '\0';
+ mode0_len = strlen(muxname) - strlen(mode_name);
mode_name++;
- m0_name = muxname;
} else {
mode_name = muxname;
}
@@ -147,9 +144,11 @@ int __init omap_mux_init_signal(char *muxname, int val)
char *m0_entry = m->muxnames[0];
int i;
- if (m0_name && strcmp(m0_name, m0_entry))
+ /* First check for full name in mode0.muxmode format */
+ if (mode0_len && strncmp(muxname, m0_entry, mode0_len))
continue;
+ /* Then check for muxmode only */
for (i = 0; i < OMAP_MUX_NR_MODES; i++) {
char *mode_cur = m->muxnames[i];
diff --git a/arch/arm/mach-omap2/mux.h b/arch/arm/mach-omap2/mux.h
index a8e040c2c7e9..350c04f27383 100644
--- a/arch/arm/mach-omap2/mux.h
+++ b/arch/arm/mach-omap2/mux.h
@@ -120,7 +120,7 @@ int omap_mux_init_gpio(int gpio, int val);
* @muxname: Mux name in mode0_name.signal_name format
* @val: Options for the mux register value
*/
-int omap_mux_init_signal(char *muxname, int val);
+int omap_mux_init_signal(const char *muxname, int val);
#else
diff --git a/arch/arm/mach-omap2/mux2420.c b/arch/arm/mach-omap2/mux2420.c
index fdb04a7eb8aa..414af5434456 100644
--- a/arch/arm/mach-omap2/mux2420.c
+++ b/arch/arm/mach-omap2/mux2420.c
@@ -507,7 +507,7 @@ static struct omap_mux __initdata omap2420_muxmodes[] = {
* Balls for 447-pin POP package
*/
#ifdef CONFIG_DEBUG_FS
-struct omap_ball __initdata omap2420_pop_ball[] = {
+static struct omap_ball __initdata omap2420_pop_ball[] = {
_OMAP2420_BALLENTRY(CAM_D0, "y4", NULL),
_OMAP2420_BALLENTRY(CAM_D1, "y3", NULL),
_OMAP2420_BALLENTRY(CAM_D2, "u7", NULL),
diff --git a/arch/arm/mach-omap2/mux2430.c b/arch/arm/mach-omap2/mux2430.c
index 7dcaaa8af32a..84d2c5a7ecd7 100644
--- a/arch/arm/mach-omap2/mux2430.c
+++ b/arch/arm/mach-omap2/mux2430.c
@@ -586,7 +586,7 @@ static struct omap_mux __initdata omap2430_muxmodes[] = {
* 447-pin s-PBGA Package, 0.00mm Ball Pitch (Bottom)
*/
#ifdef CONFIG_DEBUG_FS
-struct omap_ball __initdata omap2430_pop_ball[] = {
+static struct omap_ball __initdata omap2430_pop_ball[] = {
_OMAP2430_BALLENTRY(CAM_D0, "t8", NULL),
_OMAP2430_BALLENTRY(CAM_D1, "t4", NULL),
_OMAP2430_BALLENTRY(CAM_D10, "r4", NULL),
diff --git a/arch/arm/mach-omap2/mux34xx.c b/arch/arm/mach-omap2/mux34xx.c
index f64d7eea3451..574e54ea3ab7 100644
--- a/arch/arm/mach-omap2/mux34xx.c
+++ b/arch/arm/mach-omap2/mux34xx.c
@@ -931,7 +931,7 @@ struct omap_ball __initdata omap3_cbc_ball[] = {
* Signals different on CUS package compared to superset
*/
#if defined(CONFIG_OMAP_MUX) && defined(CONFIG_OMAP_PACKAGE_CUS)
-struct omap_mux __initdata omap3_cus_subset[] = {
+static struct omap_mux __initdata omap3_cus_subset[] = {
_OMAP3_MUXENTRY(CAM_D10, 109,
"cam_d10", NULL, NULL, NULL,
"gpio_109", NULL, NULL, "safe_mode"),
@@ -1077,7 +1077,7 @@ struct omap_mux __initdata omap3_cus_subset[] = {
*/
#if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS) \
&& defined(CONFIG_OMAP_PACKAGE_CUS)
-struct omap_ball __initdata omap3_cus_ball[] = {
+static struct omap_ball __initdata omap3_cus_ball[] = {
_OMAP3_BALLENTRY(CAM_D0, "ab18", NULL),
_OMAP3_BALLENTRY(CAM_D1, "ac18", NULL),
_OMAP3_BALLENTRY(CAM_D10, "f21", NULL),
@@ -1269,7 +1269,7 @@ struct omap_ball __initdata omap3_cus_ball[] = {
* Signals different on CBB package comapared to superset
*/
#if defined(CONFIG_OMAP_MUX) && defined(CONFIG_OMAP_PACKAGE_CBB)
-struct omap_mux __initdata omap3_cbb_subset[] = {
+static struct omap_mux __initdata omap3_cbb_subset[] = {
_OMAP3_MUXENTRY(CAM_D10, 109,
"cam_d10", NULL, NULL, NULL,
"gpio_109", NULL, NULL, "safe_mode"),
@@ -1390,7 +1390,7 @@ struct omap_mux __initdata omap3_cbb_subset[] = {
*/
#if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS) \
&& defined(CONFIG_OMAP_PACKAGE_CBB)
-struct omap_ball __initdata omap3_cbb_ball[] = {
+static struct omap_ball __initdata omap3_cbb_ball[] = {
_OMAP3_BALLENTRY(CAM_D0, "ag17", NULL),
_OMAP3_BALLENTRY(CAM_D1, "ah17", NULL),
_OMAP3_BALLENTRY(CAM_D10, "b25", NULL),
@@ -1600,7 +1600,7 @@ struct omap_ball __initdata omap3_cbb_ball[] = {
* Signals different on 36XX CBP package comapared to 34XX CBC package
*/
#if defined(CONFIG_OMAP_MUX) && defined(CONFIG_OMAP_PACKAGE_CBP)
-struct omap_mux __initdata omap36xx_cbp_subset[] = {
+static struct omap_mux __initdata omap36xx_cbp_subset[] = {
_OMAP3_MUXENTRY(CAM_D0, 99,
"cam_d0", NULL, "csi2_dx2", NULL,
"gpio_99", NULL, NULL, "safe_mode"),
@@ -1818,7 +1818,7 @@ struct omap_mux __initdata omap36xx_cbp_subset[] = {
*/
#if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS) \
&& defined (CONFIG_OMAP_PACKAGE_CBP)
-struct omap_ball __initdata omap36xx_cbp_ball[] = {
+static struct omap_ball __initdata omap36xx_cbp_ball[] = {
_OMAP3_BALLENTRY(CAM_D0, "ag17", NULL),
_OMAP3_BALLENTRY(CAM_D1, "ah17", NULL),
_OMAP3_BALLENTRY(CAM_D10, "b25", NULL),
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 13dc9794dcc2..923f9f5f91ce 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -61,10 +61,14 @@ static int __init omap_l2_cache_init(void)
omap_smc1(0x102, 0x1);
/*
- * 32KB way size, 16-way associativity,
- * parity disabled
+ * 16-way associativity, parity disabled
+ * Way size - 32KB (es1.0)
+ * Way size - 64KB (es2.0 +)
*/
- l2x0_init(l2cache_base, 0x0e050000, 0xc0000fff);
+ if (omap_rev() == OMAP4430_REV_ES1_0)
+ l2x0_init(l2cache_base, 0x0e050000, 0xc0000fff);
+ else
+ l2x0_init(l2cache_base, 0x0e070000, 0xc0000fff);
return 0;
}
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index cb911d7d1a3c..5a30658444d0 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -13,10 +13,102 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * This code manages "OMAP modules" (on-chip devices) and their
- * integration with Linux device driver and bus code.
- *
- * References:
+ * Introduction
+ * ------------
+ * One way to view an OMAP SoC is as a collection of largely unrelated
+ * IP blocks connected by interconnects. The IP blocks include
+ * devices such as ARM processors, audio serial interfaces, UARTs,
+ * etc. Some of these devices, like the DSP, are created by TI;
+ * others, like the SGX, largely originate from external vendors. In
+ * TI's documentation, on-chip devices are referred to as "OMAP
+ * modules." Some of these IP blocks are identical across several
+ * OMAP versions. Others are revised frequently.
+ *
+ * These OMAP modules are tied together by various interconnects.
+ * Most of the address and data flow between modules is via OCP-based
+ * interconnects such as the L3 and L4 buses; but there are other
+ * interconnects that distribute the hardware clock tree, handle idle
+ * and reset signaling, supply power, and connect the modules to
+ * various pads or balls on the OMAP package.
+ *
+ * OMAP hwmod provides a consistent way to describe the on-chip
+ * hardware blocks and their integration into the rest of the chip.
+ * This description can be automatically generated from the TI
+ * hardware database. OMAP hwmod provides a standard, consistent API
+ * to reset, enable, idle, and disable these hardware blocks. And
+ * hwmod provides a way for other core code, such as the Linux device
+ * code or the OMAP power management and address space mapping code,
+ * to query the hardware database.
+ *
+ * Using hwmod
+ * -----------
+ * Drivers won't call hwmod functions directly. That is done by the
+ * omap_device code, and in rare occasions, by custom integration code
+ * in arch/arm/ *omap*. The omap_device code includes functions to
+ * build a struct platform_device using omap_hwmod data, and that is
+ * currently how hwmod data is communicated to drivers and to the
+ * Linux driver model. Most drivers will call omap_hwmod functions only
+ * indirectly, via pm_runtime*() functions.
+ *
+ * From a layering perspective, here is where the OMAP hwmod code
+ * fits into the kernel software stack:
+ *
+ * +-------------------------------+
+ * | Device driver code |
+ * | (e.g., drivers/) |
+ * +-------------------------------+
+ * | Linux driver model |
+ * | (platform_device / |
+ * | platform_driver data/code) |
+ * +-------------------------------+
+ * | OMAP core-driver integration |
+ * |(arch/arm/mach-omap2/devices.c)|
+ * +-------------------------------+
+ * | omap_device code |
+ * | (../plat-omap/omap_device.c) |
+ * +-------------------------------+
+ * ----> | omap_hwmod code/data | <-----
+ * | (../mach-omap2/omap_hwmod*) |
+ * +-------------------------------+
+ * | OMAP clock/PRCM/register fns |
+ * | (__raw_{read,write}l, clk*) |
+ * +-------------------------------+
+ *
+ * Device drivers should not contain any OMAP-specific code or data in
+ * them. They should only contain code to operate the IP block that
+ * the driver is responsible for. This is because these IP blocks can
+ * also appear in other SoCs, either from TI (such as DaVinci) or from
+ * other manufacturers; and drivers should be reusable across other
+ * platforms.
+ *
+ * The OMAP hwmod code also will attempt to reset and idle all on-chip
+ * devices upon boot. The goal here is for the kernel to be
+ * completely self-reliant and independent from bootloaders. This is
+ * to ensure a repeatable configuration, both to ensure consistent
+ * runtime behavior, and to make it easier for others to reproduce
+ * bugs.
+ *
+ * OMAP module activity states
+ * ---------------------------
+ * The hwmod code considers modules to be in one of several activity
+ * states. IP blocks start out in an UNKNOWN state, then once they
+ * are registered via the hwmod code, proceed to the REGISTERED state.
+ * Once their clock names are resolved to clock pointers, the module
+ * enters the CLKS_INITED state; and finally, once the module has been
+ * reset and the integration registers programmed, the INITIALIZED state
+ * is entered. The hwmod code will then place the module into either
+ * the IDLE state to save power, or in the case of a critical system
+ * module, the ENABLED state.
+ *
+ * OMAP core integration code can then call omap_hwmod*() functions
+ * directly to move the module between the IDLE, ENABLED, and DISABLED
+ * states, as needed. This is done during both the PM idle loop, and
+ * in the OMAP core integration code's implementation of the PM runtime
+ * functions.
+ *
+ * References
+ * ----------
+ * This is a partial list.
* - OMAP2420 Multimedia Processor Silicon Revision 2.1.1, 2.2 (SWPU064)
* - OMAP2430 Multimedia Device POP Silicon Revision 2.1 (SWPU090)
* - OMAP34xx Multimedia Device Silicon Revision 3.1 (SWPU108)
@@ -50,11 +142,13 @@
#include <plat/powerdomain.h>
#include <plat/clock.h>
#include <plat/omap_hwmod.h>
+#include <plat/prcm.h>
#include "cm.h"
+#include "prm.h"
-/* Maximum microseconds to wait for OMAP module to reset */
-#define MAX_MODULE_RESET_WAIT 10000
+/* Maximum microseconds to wait for OMAP module to softreset */
+#define MAX_MODULE_SOFTRESET_WAIT 10000
/* Name of the OMAP hwmod for the MPU */
#define MPU_INITIATOR_NAME "mpu"
@@ -90,7 +184,7 @@ static int _update_sysc_cache(struct omap_hwmod *oh)
/* XXX ensure module interface clock is up */
- oh->_sysc_cache = omap_hwmod_readl(oh, oh->class->sysc->sysc_offs);
+ oh->_sysc_cache = omap_hwmod_read(oh, oh->class->sysc->sysc_offs);
if (!(oh->class->sysc->sysc_flags & SYSC_NO_CACHE))
oh->_int_flags |= _HWMOD_SYSCONFIG_LOADED;
@@ -117,7 +211,7 @@ static void _write_sysconfig(u32 v, struct omap_hwmod *oh)
if (oh->_sysc_cache != v) {
oh->_sysc_cache = v;
- omap_hwmod_writel(v, oh, oh->class->sysc->sysc_offs);
+ omap_hwmod_write(v, oh, oh->class->sysc->sysc_offs);
}
}
@@ -544,6 +638,36 @@ static int _disable_clocks(struct omap_hwmod *oh)
return 0;
}
+static void _enable_optional_clocks(struct omap_hwmod *oh)
+{
+ struct omap_hwmod_opt_clk *oc;
+ int i;
+
+ pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name);
+
+ for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
+ if (oc->_clk) {
+ pr_debug("omap_hwmod: enable %s:%s\n", oc->role,
+ oc->_clk->name);
+ clk_enable(oc->_clk);
+ }
+}
+
+static void _disable_optional_clocks(struct omap_hwmod *oh)
+{
+ struct omap_hwmod_opt_clk *oc;
+ int i;
+
+ pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name);
+
+ for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
+ if (oc->_clk) {
+ pr_debug("omap_hwmod: disable %s:%s\n", oc->role,
+ oc->_clk->name);
+ clk_disable(oc->_clk);
+ }
+}
+
/**
* _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use
* @oh: struct omap_hwmod *
@@ -622,7 +746,7 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index)
}
/**
- * _sysc_enable - try to bring a module out of idle via OCP_SYSCONFIG
+ * _enable_sysc - try to bring a module out of idle via OCP_SYSCONFIG
* @oh: struct omap_hwmod *
*
* If module is marked as SWSUP_SIDLE, force the module out of slave
@@ -630,7 +754,7 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index)
* as SWSUP_MSUSPEND, force the module out of master standby;
* otherwise, configure it for smart-standby. No return value.
*/
-static void _sysc_enable(struct omap_hwmod *oh)
+static void _enable_sysc(struct omap_hwmod *oh)
{
u8 idlemode, sf;
u32 v;
@@ -653,14 +777,6 @@ static void _sysc_enable(struct omap_hwmod *oh)
_set_master_standbymode(oh, idlemode, &v);
}
- if (sf & SYSC_HAS_AUTOIDLE) {
- idlemode = (oh->flags & HWMOD_NO_OCP_AUTOIDLE) ?
- 0 : 1;
- _set_module_autoidle(oh, idlemode, &v);
- }
-
- /* XXX OCP ENAWAKEUP bit? */
-
/*
* XXX The clock framework should handle this, by
* calling into this code. But this must wait until the
@@ -671,10 +787,25 @@ static void _sysc_enable(struct omap_hwmod *oh)
_set_clockactivity(oh, oh->class->sysc->clockact, &v);
_write_sysconfig(v, oh);
+
+ /* If slave is in SMARTIDLE, also enable wakeup */
+ if ((sf & SYSC_HAS_SIDLEMODE) && !(oh->flags & HWMOD_SWSUP_SIDLE))
+ _enable_wakeup(oh);
+
+ /*
+ * Set the autoidle bit only after setting the smartidle bit
+ * Setting this will not have any impact on the other modules.
+ */
+ if (sf & SYSC_HAS_AUTOIDLE) {
+ idlemode = (oh->flags & HWMOD_NO_OCP_AUTOIDLE) ?
+ 0 : 1;
+ _set_module_autoidle(oh, idlemode, &v);
+ _write_sysconfig(v, oh);
+ }
}
/**
- * _sysc_idle - try to put a module into idle via OCP_SYSCONFIG
+ * _idle_sysc - try to put a module into idle via OCP_SYSCONFIG
* @oh: struct omap_hwmod *
*
* If module is marked as SWSUP_SIDLE, force the module into slave
@@ -682,7 +813,7 @@ static void _sysc_enable(struct omap_hwmod *oh)
* as SWSUP_MSUSPEND, force the module into master standby; otherwise,
* configure it for smart-standby. No return value.
*/
-static void _sysc_idle(struct omap_hwmod *oh)
+static void _idle_sysc(struct omap_hwmod *oh)
{
u8 idlemode, sf;
u32 v;
@@ -709,13 +840,13 @@ static void _sysc_idle(struct omap_hwmod *oh)
}
/**
- * _sysc_shutdown - force a module into idle via OCP_SYSCONFIG
+ * _shutdown_sysc - force a module into idle via OCP_SYSCONFIG
* @oh: struct omap_hwmod *
*
* Force the module into slave idle and master suspend. No return
* value.
*/
-static void _sysc_shutdown(struct omap_hwmod *oh)
+static void _shutdown_sysc(struct omap_hwmod *oh)
{
u32 v;
u8 sf;
@@ -767,10 +898,10 @@ static struct omap_hwmod *_lookup(const char *name)
* @data: not used; pass NULL
*
* Called by omap_hwmod_late_init() (after omap2_clk_init()).
- * Resolves all clock names embedded in the hwmod. Must be called
- * with omap_hwmod_mutex held. Returns -EINVAL if the omap_hwmod
- * has not yet been registered or if the clocks have already been
- * initialized, 0 on success, or a non-zero error on failure.
+ * Resolves all clock names embedded in the hwmod. Returns -EINVAL if
+ * the omap_hwmod has not yet been registered or if the clocks have
+ * already been initialized, 0 on success, or a non-zero error on
+ * failure.
*/
static int _init_clocks(struct omap_hwmod *oh, void *data)
{
@@ -834,56 +965,202 @@ static int _wait_target_ready(struct omap_hwmod *oh)
}
/**
+ * _lookup_hardreset - return the register bit shift for this hwmod/reset line
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line in the context of this hwmod
+ *
+ * Return the bit position of the reset line that match the
+ * input name. Return -ENOENT if not found.
+ */
+static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name)
+{
+ int i;
+
+ for (i = 0; i < oh->rst_lines_cnt; i++) {
+ const char *rst_line = oh->rst_lines[i].name;
+ if (!strcmp(rst_line, name)) {
+ u8 shift = oh->rst_lines[i].rst_shift;
+ pr_debug("omap_hwmod: %s: _lookup_hardreset: %s: %d\n",
+ oh->name, rst_line, shift);
+
+ return shift;
+ }
+ }
+
+ return -ENOENT;
+}
+
+/**
+ * _assert_hardreset - assert the HW reset line of submodules
+ * contained in the hwmod module.
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to lookup and assert
+ *
+ * Some IP like dsp, ipu or iva contain processor that require
+ * an HW reset line to be assert / deassert in order to enable fully
+ * the IP.
+ */
+static int _assert_hardreset(struct omap_hwmod *oh, const char *name)
+{
+ u8 shift;
+
+ if (!oh)
+ return -EINVAL;
+
+ shift = _lookup_hardreset(oh, name);
+ if (IS_ERR_VALUE(shift))
+ return shift;
+
+ if (cpu_is_omap24xx() || cpu_is_omap34xx())
+ return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs,
+ shift);
+ else if (cpu_is_omap44xx())
+ return omap4_prm_assert_hardreset(oh->prcm.omap4.rstctrl_reg,
+ shift);
+ else
+ return -EINVAL;
+}
+
+/**
+ * _deassert_hardreset - deassert the HW reset line of submodules contained
+ * in the hwmod module.
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to look up and deassert
+ *
+ * Some IP like dsp, ipu or iva contain processor that require
+ * an HW reset line to be assert / deassert in order to enable fully
+ * the IP.
+ */
+static int _deassert_hardreset(struct omap_hwmod *oh, const char *name)
+{
+ u8 shift;
+ int r;
+
+ if (!oh)
+ return -EINVAL;
+
+ shift = _lookup_hardreset(oh, name);
+ if (IS_ERR_VALUE(shift))
+ return shift;
+
+ if (cpu_is_omap24xx() || cpu_is_omap34xx())
+ r = omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs,
+ shift);
+ else if (cpu_is_omap44xx())
+ r = omap4_prm_deassert_hardreset(oh->prcm.omap4.rstctrl_reg,
+ shift);
+ else
+ return -EINVAL;
+
+ if (r == -EBUSY)
+ pr_warning("omap_hwmod: %s: failed to hardreset\n", oh->name);
+
+ return r;
+}
+
+/**
+ * _read_hardreset - read the HW reset line state of submodules
+ * contained in the hwmod module
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to look up and read
+ *
+ * Return the state of the reset line.
+ */
+static int _read_hardreset(struct omap_hwmod *oh, const char *name)
+{
+ u8 shift;
+
+ if (!oh)
+ return -EINVAL;
+
+ shift = _lookup_hardreset(oh, name);
+ if (IS_ERR_VALUE(shift))
+ return shift;
+
+ if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+ return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs,
+ shift);
+ } else if (cpu_is_omap44xx()) {
+ return omap4_prm_is_hardreset_asserted(oh->prcm.omap4.rstctrl_reg,
+ shift);
+ } else {
+ return -EINVAL;
+ }
+}
+
+/**
* _reset - reset an omap_hwmod
* @oh: struct omap_hwmod *
*
* Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be
- * enabled for this to work. Must be called with omap_hwmod_mutex
- * held. Returns -EINVAL if the hwmod cannot be reset this way or if
- * the hwmod is in the wrong state, -ETIMEDOUT if the module did not
- * reset in time, or 0 upon success.
+ * enabled for this to work. Returns -EINVAL if the hwmod cannot be
+ * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if
+ * the module did not reset in time, or 0 upon success.
+ *
+ * In OMAP3 a specific SYSSTATUS register is used to get the reset status.
+ * Starting in OMAP4, some IPs does not have SYSSTATUS register and instead
+ * use the SYSCONFIG softreset bit to provide the status.
+ *
+ * Note that some IP like McBSP does have a reset control but no reset status.
*/
static int _reset(struct omap_hwmod *oh)
{
- u32 r, v;
+ u32 v;
int c = 0;
+ int ret = 0;
if (!oh->class->sysc ||
- !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET) ||
- (oh->class->sysc->sysc_flags & SYSS_MISSING))
+ !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
return -EINVAL;
/* clocks must be on for this operation */
if (oh->_state != _HWMOD_STATE_ENABLED) {
- WARN(1, "omap_hwmod: %s: reset can only be entered from "
- "enabled state\n", oh->name);
+ pr_warning("omap_hwmod: %s: reset can only be entered from "
+ "enabled state\n", oh->name);
return -EINVAL;
}
+ /* For some modules, all optionnal clocks need to be enabled as well */
+ if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
+ _enable_optional_clocks(oh);
+
pr_debug("omap_hwmod: %s: resetting\n", oh->name);
v = oh->_sysc_cache;
- r = _set_softreset(oh, &v);
- if (r)
- return r;
+ ret = _set_softreset(oh, &v);
+ if (ret)
+ goto dis_opt_clks;
_write_sysconfig(v, oh);
- omap_test_timeout((omap_hwmod_readl(oh, oh->class->sysc->syss_offs) &
- SYSS_RESETDONE_MASK),
- MAX_MODULE_RESET_WAIT, c);
-
- if (c == MAX_MODULE_RESET_WAIT)
- WARN(1, "omap_hwmod: %s: failed to reset in %d usec\n",
- oh->name, MAX_MODULE_RESET_WAIT);
+ if (oh->class->sysc->sysc_flags & SYSS_HAS_RESET_STATUS)
+ omap_test_timeout((omap_hwmod_read(oh,
+ oh->class->sysc->syss_offs)
+ & SYSS_RESETDONE_MASK),
+ MAX_MODULE_SOFTRESET_WAIT, c);
+ else if (oh->class->sysc->sysc_flags & SYSC_HAS_RESET_STATUS)
+ omap_test_timeout(!(omap_hwmod_read(oh,
+ oh->class->sysc->sysc_offs)
+ & SYSC_TYPE2_SOFTRESET_MASK),
+ MAX_MODULE_SOFTRESET_WAIT, c);
+
+ if (c == MAX_MODULE_SOFTRESET_WAIT)
+ pr_warning("omap_hwmod: %s: softreset failed (waited %d usec)\n",
+ oh->name, MAX_MODULE_SOFTRESET_WAIT);
else
- pr_debug("omap_hwmod: %s: reset in %d usec\n", oh->name, c);
+ pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c);
/*
* XXX add _HWMOD_STATE_WEDGED for modules that don't come back from
* _wait_target_ready() or _reset()
*/
- return (c == MAX_MODULE_RESET_WAIT) ? -ETIMEDOUT : 0;
+ ret = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0;
+
+dis_opt_clks:
+ if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
+ _disable_optional_clocks(oh);
+
+ return ret;
}
/**
@@ -891,9 +1168,11 @@ static int _reset(struct omap_hwmod *oh)
* @oh: struct omap_hwmod *
*
* Enables an omap_hwmod @oh such that the MPU can access the hwmod's
- * register target. Must be called with omap_hwmod_mutex held.
- * Returns -EINVAL if the hwmod is in the wrong state or passes along
- * the return value of _wait_target_ready().
+ * register target. (This function has a full name --
+ * _omap_hwmod_enable() rather than simply _enable() -- because it is
+ * currently required by the pm34xx.c idle loop.) Returns -EINVAL if
+ * the hwmod is in the wrong state or passes along the return value of
+ * _wait_target_ready().
*/
int _omap_hwmod_enable(struct omap_hwmod *oh)
{
@@ -909,6 +1188,15 @@ int _omap_hwmod_enable(struct omap_hwmod *oh)
pr_debug("omap_hwmod: %s: enabling\n", oh->name);
+ /*
+ * If an IP contains only one HW reset line, then de-assert it in order
+ * to allow to enable the clocks. Otherwise the PRCM will return
+ * Intransition status, and the init will failed.
+ */
+ if ((oh->_state == _HWMOD_STATE_INITIALIZED ||
+ oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1)
+ _deassert_hardreset(oh, oh->rst_lines[0].name);
+
/* XXX mux balls */
_add_initiator_dep(oh, mpu_oh);
@@ -922,7 +1210,7 @@ int _omap_hwmod_enable(struct omap_hwmod *oh)
if (oh->class->sysc) {
if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED))
_update_sysc_cache(oh);
- _sysc_enable(oh);
+ _enable_sysc(oh);
}
} else {
pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n",
@@ -933,12 +1221,14 @@ int _omap_hwmod_enable(struct omap_hwmod *oh)
}
/**
- * _idle - idle an omap_hwmod
+ * _omap_hwmod_idle - idle an omap_hwmod
* @oh: struct omap_hwmod *
*
* Idles an omap_hwmod @oh. This should be called once the hwmod has
- * no further work. Returns -EINVAL if the hwmod is in the wrong
- * state or returns 0.
+ * no further work. (This function has a full name --
+ * _omap_hwmod_idle() rather than simply _idle() -- because it is
+ * currently required by the pm34xx.c idle loop.) Returns -EINVAL if
+ * the hwmod is in the wrong state or returns 0.
*/
int _omap_hwmod_idle(struct omap_hwmod *oh)
{
@@ -951,7 +1241,7 @@ int _omap_hwmod_idle(struct omap_hwmod *oh)
pr_debug("omap_hwmod: %s: idling\n", oh->name);
if (oh->class->sysc)
- _sysc_idle(oh);
+ _idle_sysc(oh);
_del_initiator_dep(oh, mpu_oh);
_disable_clocks(oh);
@@ -981,10 +1271,21 @@ static int _shutdown(struct omap_hwmod *oh)
pr_debug("omap_hwmod: %s: disabling\n", oh->name);
if (oh->class->sysc)
- _sysc_shutdown(oh);
- _del_initiator_dep(oh, mpu_oh);
- /* XXX what about the other system initiators here? DMA, tesla, d2d */
- _disable_clocks(oh);
+ _shutdown_sysc(oh);
+
+ /*
+ * If an IP contains only one HW reset line, then assert it
+ * before disabling the clocks and shutting down the IP.
+ */
+ if (oh->rst_lines_cnt == 1)
+ _assert_hardreset(oh, oh->rst_lines[0].name);
+
+ /* clocks and deps are already disabled in idle */
+ if (oh->_state == _HWMOD_STATE_ENABLED) {
+ _del_initiator_dep(oh, mpu_oh);
+ /* XXX what about the other system initiators here? dma, dsp */
+ _disable_clocks(oh);
+ }
/* XXX Should this code also force-disable the optional clocks? */
/* XXX mux any associated balls to safe mode */
@@ -1000,11 +1301,10 @@ static int _shutdown(struct omap_hwmod *oh)
* @skip_setup_idle_p: do not idle hwmods at the end of the fn if 1
*
* Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh
- * OCP_SYSCONFIG register. Must be called with omap_hwmod_mutex held.
- * @skip_setup_idle is intended to be used on a system that will not
- * call omap_hwmod_enable() to enable devices (e.g., a system without
- * PM runtime). Returns -EINVAL if the hwmod is in the wrong state or
- * returns 0.
+ * OCP_SYSCONFIG register. @skip_setup_idle is intended to be used on
+ * a system that will not call omap_hwmod_enable() to enable devices
+ * (e.g., a system without PM runtime). Returns -EINVAL if the hwmod
+ * is in the wrong state or returns 0.
*/
static int _setup(struct omap_hwmod *oh, void *data)
{
@@ -1034,8 +1334,19 @@ static int _setup(struct omap_hwmod *oh, void *data)
}
}
+ mutex_init(&oh->_mutex);
oh->_state = _HWMOD_STATE_INITIALIZED;
+ /*
+ * In the case of hwmod with hardreset that should not be
+ * de-assert at boot time, we have to keep the module
+ * initialized, because we cannot enable it properly with the
+ * reset asserted. Exit without warning because that behavior is
+ * expected.
+ */
+ if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1)
+ return 0;
+
r = _omap_hwmod_enable(oh);
if (r) {
pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n",
@@ -1044,16 +1355,16 @@ static int _setup(struct omap_hwmod *oh, void *data)
}
if (!(oh->flags & HWMOD_INIT_NO_RESET)) {
+ _reset(oh);
+
/*
- * XXX Do the OCP_SYSCONFIG bits need to be
- * reprogrammed after a reset? If not, then this can
- * be removed. If they do, then probably the
- * _omap_hwmod_enable() function should be split to avoid the
- * rewrite of the OCP_SYSCONFIG register.
+ * OCP_SYSCONFIG bits need to be reprogrammed after a softreset.
+ * The _omap_hwmod_enable() function should be split to
+ * avoid the rewrite of the OCP_SYSCONFIG register.
*/
if (oh->class->sysc) {
_update_sysc_cache(oh);
- _sysc_enable(oh);
+ _enable_sysc(oh);
}
}
@@ -1067,14 +1378,20 @@ static int _setup(struct omap_hwmod *oh, void *data)
/* Public functions */
-u32 omap_hwmod_readl(struct omap_hwmod *oh, u16 reg_offs)
+u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs)
{
- return __raw_readl(oh->_mpu_rt_va + reg_offs);
+ if (oh->flags & HWMOD_16BIT_REG)
+ return __raw_readw(oh->_mpu_rt_va + reg_offs);
+ else
+ return __raw_readl(oh->_mpu_rt_va + reg_offs);
}
-void omap_hwmod_writel(u32 v, struct omap_hwmod *oh, u16 reg_offs)
+void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs)
{
- __raw_writel(v, oh->_mpu_rt_va + reg_offs);
+ if (oh->flags & HWMOD_16BIT_REG)
+ __raw_writew(v, oh->_mpu_rt_va + reg_offs);
+ else
+ __raw_writel(v, oh->_mpu_rt_va + reg_offs);
}
/**
@@ -1309,7 +1626,7 @@ int omap_hwmod_unregister(struct omap_hwmod *oh)
* omap_hwmod_enable - enable an omap_hwmod
* @oh: struct omap_hwmod *
*
- * Enable an omap_hwomd @oh. Intended to be called by omap_device_enable().
+ * Enable an omap_hwmod @oh. Intended to be called by omap_device_enable().
* Returns -EINVAL on error or passes along the return value from _enable().
*/
int omap_hwmod_enable(struct omap_hwmod *oh)
@@ -1319,9 +1636,9 @@ int omap_hwmod_enable(struct omap_hwmod *oh)
if (!oh)
return -EINVAL;
- mutex_lock(&omap_hwmod_mutex);
+ mutex_lock(&oh->_mutex);
r = _omap_hwmod_enable(oh);
- mutex_unlock(&omap_hwmod_mutex);
+ mutex_unlock(&oh->_mutex);
return r;
}
@@ -1331,7 +1648,7 @@ int omap_hwmod_enable(struct omap_hwmod *oh)
* omap_hwmod_idle - idle an omap_hwmod
* @oh: struct omap_hwmod *
*
- * Idle an omap_hwomd @oh. Intended to be called by omap_device_idle().
+ * Idle an omap_hwmod @oh. Intended to be called by omap_device_idle().
* Returns -EINVAL on error or passes along the return value from _idle().
*/
int omap_hwmod_idle(struct omap_hwmod *oh)
@@ -1339,9 +1656,9 @@ int omap_hwmod_idle(struct omap_hwmod *oh)
if (!oh)
return -EINVAL;
- mutex_lock(&omap_hwmod_mutex);
+ mutex_lock(&oh->_mutex);
_omap_hwmod_idle(oh);
- mutex_unlock(&omap_hwmod_mutex);
+ mutex_unlock(&oh->_mutex);
return 0;
}
@@ -1350,7 +1667,7 @@ int omap_hwmod_idle(struct omap_hwmod *oh)
* omap_hwmod_shutdown - shutdown an omap_hwmod
* @oh: struct omap_hwmod *
*
- * Shutdown an omap_hwomd @oh. Intended to be called by
+ * Shutdown an omap_hwmod @oh. Intended to be called by
* omap_device_shutdown(). Returns -EINVAL on error or passes along
* the return value from _shutdown().
*/
@@ -1359,9 +1676,9 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh)
if (!oh)
return -EINVAL;
- mutex_lock(&omap_hwmod_mutex);
+ mutex_lock(&oh->_mutex);
_shutdown(oh);
- mutex_unlock(&omap_hwmod_mutex);
+ mutex_unlock(&oh->_mutex);
return 0;
}
@@ -1374,9 +1691,9 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh)
*/
int omap_hwmod_enable_clocks(struct omap_hwmod *oh)
{
- mutex_lock(&omap_hwmod_mutex);
+ mutex_lock(&oh->_mutex);
_enable_clocks(oh);
- mutex_unlock(&omap_hwmod_mutex);
+ mutex_unlock(&oh->_mutex);
return 0;
}
@@ -1389,9 +1706,9 @@ int omap_hwmod_enable_clocks(struct omap_hwmod *oh)
*/
int omap_hwmod_disable_clocks(struct omap_hwmod *oh)
{
- mutex_lock(&omap_hwmod_mutex);
+ mutex_lock(&oh->_mutex);
_disable_clocks(oh);
- mutex_unlock(&omap_hwmod_mutex);
+ mutex_unlock(&oh->_mutex);
return 0;
}
@@ -1421,7 +1738,7 @@ void omap_hwmod_ocp_barrier(struct omap_hwmod *oh)
* Forces posted writes to complete on the OCP thread handling
* register writes
*/
- omap_hwmod_readl(oh, oh->class->sysc->sysc_offs);
+ omap_hwmod_read(oh, oh->class->sysc->sysc_offs);
}
/**
@@ -1430,20 +1747,18 @@ void omap_hwmod_ocp_barrier(struct omap_hwmod *oh)
*
* Under some conditions, a driver may wish to reset the entire device.
* Called from omap_device code. Returns -EINVAL on error or passes along
- * the return value from _reset()/_enable().
+ * the return value from _reset().
*/
int omap_hwmod_reset(struct omap_hwmod *oh)
{
int r;
- if (!oh || !(oh->_state & _HWMOD_STATE_ENABLED))
+ if (!oh)
return -EINVAL;
- mutex_lock(&omap_hwmod_mutex);
+ mutex_lock(&oh->_mutex);
r = _reset(oh);
- if (!r)
- r = _omap_hwmod_enable(oh);
- mutex_unlock(&omap_hwmod_mutex);
+ mutex_unlock(&oh->_mutex);
return r;
}
@@ -1468,7 +1783,7 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh)
{
int ret, i;
- ret = oh->mpu_irqs_cnt + oh->sdma_chs_cnt;
+ ret = oh->mpu_irqs_cnt + oh->sdma_reqs_cnt;
for (i = 0; i < oh->slaves_cnt; i++)
ret += oh->slaves[i]->addr_cnt;
@@ -1501,10 +1816,10 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
r++;
}
- for (i = 0; i < oh->sdma_chs_cnt; i++) {
- (res + r)->name = (oh->sdma_chs + i)->name;
- (res + r)->start = (oh->sdma_chs + i)->dma_ch;
- (res + r)->end = (oh->sdma_chs + i)->dma_ch;
+ for (i = 0; i < oh->sdma_reqs_cnt; i++) {
+ (res + r)->name = (oh->sdma_reqs + i)->name;
+ (res + r)->start = (oh->sdma_reqs + i)->dma_req;
+ (res + r)->end = (oh->sdma_reqs + i)->dma_req;
(res + r)->flags = IORESOURCE_DMA;
r++;
}
@@ -1644,9 +1959,9 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh)
!(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
return -EINVAL;
- mutex_lock(&omap_hwmod_mutex);
+ mutex_lock(&oh->_mutex);
_enable_wakeup(oh);
- mutex_unlock(&omap_hwmod_mutex);
+ mutex_unlock(&oh->_mutex);
return 0;
}
@@ -1669,14 +1984,92 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh)
!(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
return -EINVAL;
- mutex_lock(&omap_hwmod_mutex);
+ mutex_lock(&oh->_mutex);
_disable_wakeup(oh);
- mutex_unlock(&omap_hwmod_mutex);
+ mutex_unlock(&oh->_mutex);
return 0;
}
/**
+ * omap_hwmod_assert_hardreset - assert the HW reset line of submodules
+ * contained in the hwmod module.
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to lookup and assert
+ *
+ * Some IP like dsp, ipu or iva contain processor that require
+ * an HW reset line to be assert / deassert in order to enable fully
+ * the IP. Returns -EINVAL if @oh is null or if the operation is not
+ * yet supported on this OMAP; otherwise, passes along the return value
+ * from _assert_hardreset().
+ */
+int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name)
+{
+ int ret;
+
+ if (!oh)
+ return -EINVAL;
+
+ mutex_lock(&oh->_mutex);
+ ret = _assert_hardreset(oh, name);
+ mutex_unlock(&oh->_mutex);
+
+ return ret;
+}
+
+/**
+ * omap_hwmod_deassert_hardreset - deassert the HW reset line of submodules
+ * contained in the hwmod module.
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to look up and deassert
+ *
+ * Some IP like dsp, ipu or iva contain processor that require
+ * an HW reset line to be assert / deassert in order to enable fully
+ * the IP. Returns -EINVAL if @oh is null or if the operation is not
+ * yet supported on this OMAP; otherwise, passes along the return value
+ * from _deassert_hardreset().
+ */
+int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name)
+{
+ int ret;
+
+ if (!oh)
+ return -EINVAL;
+
+ mutex_lock(&oh->_mutex);
+ ret = _deassert_hardreset(oh, name);
+ mutex_unlock(&oh->_mutex);
+
+ return ret;
+}
+
+/**
+ * omap_hwmod_read_hardreset - read the HW reset line state of submodules
+ * contained in the hwmod module
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to look up and read
+ *
+ * Return the current state of the hwmod @oh's reset line named @name:
+ * returns -EINVAL upon parameter error or if this operation
+ * is unsupported on the current OMAP; otherwise, passes along the return
+ * value from _read_hardreset().
+ */
+int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name)
+{
+ int ret;
+
+ if (!oh)
+ return -EINVAL;
+
+ mutex_lock(&oh->_mutex);
+ ret = _read_hardreset(oh, name);
+ mutex_unlock(&oh->_mutex);
+
+ return ret;
+}
+
+
+/**
* omap_hwmod_for_each_by_class - call @fn for each hwmod of class @classname
* @classname: struct omap_hwmod_class name to search for
* @fn: callback function pointer to call for each hwmod in class @classname
diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
index 3cc768e8bc04..adf6e3632a2b 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
@@ -15,10 +15,12 @@
#include <mach/irqs.h>
#include <plat/cpu.h>
#include <plat/dma.h>
+#include <plat/serial.h>
#include "omap_hwmod_common_data.h"
#include "prm-regbits-24xx.h"
+#include "cm-regbits-24xx.h"
/*
* OMAP2420 hardware module integration data
@@ -33,6 +35,7 @@ static struct omap_hwmod omap2420_mpu_hwmod;
static struct omap_hwmod omap2420_iva_hwmod;
static struct omap_hwmod omap2420_l3_main_hwmod;
static struct omap_hwmod omap2420_l4_core_hwmod;
+static struct omap_hwmod omap2420_wd_timer2_hwmod;
/* L3 -> L4_CORE interface */
static struct omap_hwmod_ocp_if omap2420_l3_main__l4_core = {
@@ -71,6 +74,9 @@ static struct omap_hwmod omap2420_l3_main_hwmod = {
};
static struct omap_hwmod omap2420_l4_wkup_hwmod;
+static struct omap_hwmod omap2420_uart1_hwmod;
+static struct omap_hwmod omap2420_uart2_hwmod;
+static struct omap_hwmod omap2420_uart3_hwmod;
/* L4_CORE -> L4_WKUP interface */
static struct omap_hwmod_ocp_if omap2420_l4_core__l4_wkup = {
@@ -79,6 +85,60 @@ static struct omap_hwmod_ocp_if omap2420_l4_core__l4_wkup = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
+/* L4 CORE -> UART1 interface */
+static struct omap_hwmod_addr_space omap2420_uart1_addr_space[] = {
+ {
+ .pa_start = OMAP2_UART1_BASE,
+ .pa_end = OMAP2_UART1_BASE + SZ_8K - 1,
+ .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart1 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_uart1_hwmod,
+ .clk = "uart1_ick",
+ .addr = omap2420_uart1_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap2420_uart1_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART2 interface */
+static struct omap_hwmod_addr_space omap2420_uart2_addr_space[] = {
+ {
+ .pa_start = OMAP2_UART2_BASE,
+ .pa_end = OMAP2_UART2_BASE + SZ_1K - 1,
+ .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart2 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_uart2_hwmod,
+ .clk = "uart2_ick",
+ .addr = omap2420_uart2_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap2420_uart2_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART3 interface */
+static struct omap_hwmod_addr_space omap2420_uart3_addr_space[] = {
+ {
+ .pa_start = OMAP2_UART3_BASE,
+ .pa_end = OMAP2_UART3_BASE + SZ_1K - 1,
+ .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart3 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_uart3_hwmod,
+ .clk = "uart3_ick",
+ .addr = omap2420_uart3_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap2420_uart3_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
/* Slave interfaces on the L4_CORE interconnect */
static struct omap_hwmod_ocp_if *omap2420_l4_core_slaves[] = {
&omap2420_l3_main__l4_core,
@@ -87,6 +147,9 @@ static struct omap_hwmod_ocp_if *omap2420_l4_core_slaves[] = {
/* Master interfaces on the L4_CORE interconnect */
static struct omap_hwmod_ocp_if *omap2420_l4_core_masters[] = {
&omap2420_l4_core__l4_wkup,
+ &omap2_l4_core__uart1,
+ &omap2_l4_core__uart2,
+ &omap2_l4_core__uart3,
};
/* L4 CORE */
@@ -165,12 +228,206 @@ static struct omap_hwmod omap2420_iva_hwmod = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
};
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap2420_wd_timer2_addrs[] = {
+ {
+ .pa_start = 0x48022000,
+ .pa_end = 0x4802207f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2420_l4_wkup__wd_timer2 = {
+ .master = &omap2420_l4_wkup_hwmod,
+ .slave = &omap2420_wd_timer2_hwmod,
+ .clk = "mpu_wdt_ick",
+ .addr = omap2420_wd_timer2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_wd_timer2_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap2420_wd_timer_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_EMUFREE | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2420_wd_timer_hwmod_class = {
+ .name = "wd_timer",
+ .sysc = &omap2420_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod_ocp_if *omap2420_wd_timer2_slaves[] = {
+ &omap2420_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap2420_wd_timer2_hwmod = {
+ .name = "wd_timer2",
+ .class = &omap2420_wd_timer_hwmod_class,
+ .main_clk = "mpu_wdt_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
+ .module_offs = WKUP_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
+ },
+ },
+ .slaves = omap2420_wd_timer2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_wd_timer2_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/* UART */
+
+static struct omap_hwmod_class_sysconfig uart_sysc = {
+ .rev_offs = 0x50,
+ .sysc_offs = 0x54,
+ .syss_offs = 0x58,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class uart_class = {
+ .name = "uart",
+ .sysc = &uart_sysc,
+};
+
+/* UART1 */
+
+static struct omap_hwmod_irq_info uart1_mpu_irqs[] = {
+ { .irq = INT_24XX_UART1_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart1_sdma_reqs[] = {
+ { .name = "rx", .dma_req = OMAP24XX_DMA_UART1_RX, },
+ { .name = "tx", .dma_req = OMAP24XX_DMA_UART1_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2420_uart1_slaves[] = {
+ &omap2_l4_core__uart1,
+};
+
+static struct omap_hwmod omap2420_uart1_hwmod = {
+ .name = "uart1",
+ .mpu_irqs = uart1_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(uart1_mpu_irqs),
+ .sdma_reqs = uart1_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(uart1_sdma_reqs),
+ .main_clk = "uart1_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_UART1_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
+ },
+ },
+ .slaves = omap2420_uart1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_uart1_slaves),
+ .class = &uart_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/* UART2 */
+
+static struct omap_hwmod_irq_info uart2_mpu_irqs[] = {
+ { .irq = INT_24XX_UART2_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart2_sdma_reqs[] = {
+ { .name = "rx", .dma_req = OMAP24XX_DMA_UART2_RX, },
+ { .name = "tx", .dma_req = OMAP24XX_DMA_UART2_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2420_uart2_slaves[] = {
+ &omap2_l4_core__uart2,
+};
+
+static struct omap_hwmod omap2420_uart2_hwmod = {
+ .name = "uart2",
+ .mpu_irqs = uart2_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(uart2_mpu_irqs),
+ .sdma_reqs = uart2_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(uart2_sdma_reqs),
+ .main_clk = "uart2_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_UART2_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
+ },
+ },
+ .slaves = omap2420_uart2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_uart2_slaves),
+ .class = &uart_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/* UART3 */
+
+static struct omap_hwmod_irq_info uart3_mpu_irqs[] = {
+ { .irq = INT_24XX_UART3_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart3_sdma_reqs[] = {
+ { .name = "rx", .dma_req = OMAP24XX_DMA_UART3_RX, },
+ { .name = "tx", .dma_req = OMAP24XX_DMA_UART3_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2420_uart3_slaves[] = {
+ &omap2_l4_core__uart3,
+};
+
+static struct omap_hwmod omap2420_uart3_hwmod = {
+ .name = "uart3",
+ .mpu_irqs = uart3_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(uart3_mpu_irqs),
+ .sdma_reqs = uart3_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(uart3_sdma_reqs),
+ .main_clk = "uart3_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 2,
+ .module_bit = OMAP24XX_EN_UART3_SHIFT,
+ .idlest_reg_id = 2,
+ .idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
+ },
+ },
+ .slaves = omap2420_uart3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_uart3_slaves),
+ .class = &uart_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
static __initdata struct omap_hwmod *omap2420_hwmods[] = {
&omap2420_l3_main_hwmod,
&omap2420_l4_core_hwmod,
&omap2420_l4_wkup_hwmod,
&omap2420_mpu_hwmod,
&omap2420_iva_hwmod,
+ &omap2420_wd_timer2_hwmod,
+ &omap2420_uart1_hwmod,
+ &omap2420_uart2_hwmod,
+ &omap2420_uart3_hwmod,
NULL,
};
diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
index 4526628ed287..12d939e456cf 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
@@ -15,10 +15,12 @@
#include <mach/irqs.h>
#include <plat/cpu.h>
#include <plat/dma.h>
+#include <plat/serial.h>
#include "omap_hwmod_common_data.h"
#include "prm-regbits-24xx.h"
+#include "cm-regbits-24xx.h"
/*
* OMAP2430 hardware module integration data
@@ -33,6 +35,7 @@ static struct omap_hwmod omap2430_mpu_hwmod;
static struct omap_hwmod omap2430_iva_hwmod;
static struct omap_hwmod omap2430_l3_main_hwmod;
static struct omap_hwmod omap2430_l4_core_hwmod;
+static struct omap_hwmod omap2430_wd_timer2_hwmod;
/* L3 -> L4_CORE interface */
static struct omap_hwmod_ocp_if omap2430_l3_main__l4_core = {
@@ -71,6 +74,9 @@ static struct omap_hwmod omap2430_l3_main_hwmod = {
};
static struct omap_hwmod omap2430_l4_wkup_hwmod;
+static struct omap_hwmod omap2430_uart1_hwmod;
+static struct omap_hwmod omap2430_uart2_hwmod;
+static struct omap_hwmod omap2430_uart3_hwmod;
/* L4_CORE -> L4_WKUP interface */
static struct omap_hwmod_ocp_if omap2430_l4_core__l4_wkup = {
@@ -79,6 +85,60 @@ static struct omap_hwmod_ocp_if omap2430_l4_core__l4_wkup = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
+/* L4 CORE -> UART1 interface */
+static struct omap_hwmod_addr_space omap2430_uart1_addr_space[] = {
+ {
+ .pa_start = OMAP2_UART1_BASE,
+ .pa_end = OMAP2_UART1_BASE + SZ_8K - 1,
+ .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart1 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_uart1_hwmod,
+ .clk = "uart1_ick",
+ .addr = omap2430_uart1_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap2430_uart1_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART2 interface */
+static struct omap_hwmod_addr_space omap2430_uart2_addr_space[] = {
+ {
+ .pa_start = OMAP2_UART2_BASE,
+ .pa_end = OMAP2_UART2_BASE + SZ_1K - 1,
+ .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart2 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_uart2_hwmod,
+ .clk = "uart2_ick",
+ .addr = omap2430_uart2_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap2430_uart2_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART3 interface */
+static struct omap_hwmod_addr_space omap2430_uart3_addr_space[] = {
+ {
+ .pa_start = OMAP2_UART3_BASE,
+ .pa_end = OMAP2_UART3_BASE + SZ_1K - 1,
+ .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart3 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_uart3_hwmod,
+ .clk = "uart3_ick",
+ .addr = omap2430_uart3_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap2430_uart3_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
/* Slave interfaces on the L4_CORE interconnect */
static struct omap_hwmod_ocp_if *omap2430_l4_core_slaves[] = {
&omap2430_l3_main__l4_core,
@@ -104,6 +164,9 @@ static struct omap_hwmod omap2430_l4_core_hwmod = {
/* Slave interfaces on the L4_WKUP interconnect */
static struct omap_hwmod_ocp_if *omap2430_l4_wkup_slaves[] = {
&omap2430_l4_core__l4_wkup,
+ &omap2_l4_core__uart1,
+ &omap2_l4_core__uart2,
+ &omap2_l4_core__uart3,
};
/* Master interfaces on the L4_WKUP interconnect */
@@ -165,12 +228,206 @@ static struct omap_hwmod omap2430_iva_hwmod = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
};
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap2430_wd_timer2_addrs[] = {
+ {
+ .pa_start = 0x49016000,
+ .pa_end = 0x4901607f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__wd_timer2 = {
+ .master = &omap2430_l4_wkup_hwmod,
+ .slave = &omap2430_wd_timer2_hwmod,
+ .clk = "mpu_wdt_ick",
+ .addr = omap2430_wd_timer2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_wd_timer2_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap2430_wd_timer_sysc = {
+ .rev_offs = 0x0,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_EMUFREE | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2430_wd_timer_hwmod_class = {
+ .name = "wd_timer",
+ .sysc = &omap2430_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod_ocp_if *omap2430_wd_timer2_slaves[] = {
+ &omap2430_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap2430_wd_timer2_hwmod = {
+ .name = "wd_timer2",
+ .class = &omap2430_wd_timer_hwmod_class,
+ .main_clk = "mpu_wdt_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
+ .module_offs = WKUP_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
+ },
+ },
+ .slaves = omap2430_wd_timer2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_wd_timer2_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* UART */
+
+static struct omap_hwmod_class_sysconfig uart_sysc = {
+ .rev_offs = 0x50,
+ .sysc_offs = 0x54,
+ .syss_offs = 0x58,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class uart_class = {
+ .name = "uart",
+ .sysc = &uart_sysc,
+};
+
+/* UART1 */
+
+static struct omap_hwmod_irq_info uart1_mpu_irqs[] = {
+ { .irq = INT_24XX_UART1_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart1_sdma_reqs[] = {
+ { .name = "rx", .dma_req = OMAP24XX_DMA_UART1_RX, },
+ { .name = "tx", .dma_req = OMAP24XX_DMA_UART1_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2430_uart1_slaves[] = {
+ &omap2_l4_core__uart1,
+};
+
+static struct omap_hwmod omap2430_uart1_hwmod = {
+ .name = "uart1",
+ .mpu_irqs = uart1_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(uart1_mpu_irqs),
+ .sdma_reqs = uart1_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(uart1_sdma_reqs),
+ .main_clk = "uart1_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_UART1_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
+ },
+ },
+ .slaves = omap2430_uart1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_uart1_slaves),
+ .class = &uart_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* UART2 */
+
+static struct omap_hwmod_irq_info uart2_mpu_irqs[] = {
+ { .irq = INT_24XX_UART2_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart2_sdma_reqs[] = {
+ { .name = "rx", .dma_req = OMAP24XX_DMA_UART2_RX, },
+ { .name = "tx", .dma_req = OMAP24XX_DMA_UART2_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2430_uart2_slaves[] = {
+ &omap2_l4_core__uart2,
+};
+
+static struct omap_hwmod omap2430_uart2_hwmod = {
+ .name = "uart2",
+ .mpu_irqs = uart2_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(uart2_mpu_irqs),
+ .sdma_reqs = uart2_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(uart2_sdma_reqs),
+ .main_clk = "uart2_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_UART2_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
+ },
+ },
+ .slaves = omap2430_uart2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_uart2_slaves),
+ .class = &uart_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* UART3 */
+
+static struct omap_hwmod_irq_info uart3_mpu_irqs[] = {
+ { .irq = INT_24XX_UART3_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart3_sdma_reqs[] = {
+ { .name = "rx", .dma_req = OMAP24XX_DMA_UART3_RX, },
+ { .name = "tx", .dma_req = OMAP24XX_DMA_UART3_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2430_uart3_slaves[] = {
+ &omap2_l4_core__uart3,
+};
+
+static struct omap_hwmod omap2430_uart3_hwmod = {
+ .name = "uart3",
+ .mpu_irqs = uart3_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(uart3_mpu_irqs),
+ .sdma_reqs = uart3_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(uart3_sdma_reqs),
+ .main_clk = "uart3_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 2,
+ .module_bit = OMAP24XX_EN_UART3_SHIFT,
+ .idlest_reg_id = 2,
+ .idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
+ },
+ },
+ .slaves = omap2430_uart3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_uart3_slaves),
+ .class = &uart_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
static __initdata struct omap_hwmod *omap2430_hwmods[] = {
&omap2430_l3_main_hwmod,
&omap2430_l4_core_hwmod,
&omap2430_l4_wkup_hwmod,
&omap2430_mpu_hwmod,
&omap2430_iva_hwmod,
+ &omap2430_wd_timer2_hwmod,
+ &omap2430_uart1_hwmod,
+ &omap2430_uart2_hwmod,
+ &omap2430_uart3_hwmod,
NULL,
};
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 5d8eb58ba5e3..cb97ecf0a3f6 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -17,10 +17,12 @@
#include <mach/irqs.h>
#include <plat/cpu.h>
#include <plat/dma.h>
+#include <plat/serial.h>
#include "omap_hwmod_common_data.h"
#include "prm-regbits-34xx.h"
+#include "cm-regbits-34xx.h"
/*
* OMAP3xxx hardware module integration data
@@ -36,6 +38,7 @@ static struct omap_hwmod omap3xxx_iva_hwmod;
static struct omap_hwmod omap3xxx_l3_main_hwmod;
static struct omap_hwmod omap3xxx_l4_core_hwmod;
static struct omap_hwmod omap3xxx_l4_per_hwmod;
+static struct omap_hwmod omap3xxx_wd_timer2_hwmod;
/* L3 -> L4_CORE interface */
static struct omap_hwmod_ocp_if omap3xxx_l3_main__l4_core = {
@@ -82,6 +85,10 @@ static struct omap_hwmod omap3xxx_l3_main_hwmod = {
};
static struct omap_hwmod omap3xxx_l4_wkup_hwmod;
+static struct omap_hwmod omap3xxx_uart1_hwmod;
+static struct omap_hwmod omap3xxx_uart2_hwmod;
+static struct omap_hwmod omap3xxx_uart3_hwmod;
+static struct omap_hwmod omap3xxx_uart4_hwmod;
/* L4_CORE -> L4_WKUP interface */
static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
@@ -90,6 +97,78 @@ static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
+/* L4 CORE -> UART1 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart1_addr_space[] = {
+ {
+ .pa_start = OMAP3_UART1_BASE,
+ .pa_end = OMAP3_UART1_BASE + SZ_8K - 1,
+ .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_core__uart1 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_uart1_hwmod,
+ .clk = "uart1_ick",
+ .addr = omap3xxx_uart1_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_uart1_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART2 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart2_addr_space[] = {
+ {
+ .pa_start = OMAP3_UART2_BASE,
+ .pa_end = OMAP3_UART2_BASE + SZ_1K - 1,
+ .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_core__uart2 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_uart2_hwmod,
+ .clk = "uart2_ick",
+ .addr = omap3xxx_uart2_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_uart2_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART3 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart3_addr_space[] = {
+ {
+ .pa_start = OMAP3_UART3_BASE,
+ .pa_end = OMAP3_UART3_BASE + SZ_1K - 1,
+ .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_per__uart3 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_uart3_hwmod,
+ .clk = "uart3_ick",
+ .addr = omap3xxx_uart3_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_uart3_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART4 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart4_addr_space[] = {
+ {
+ .pa_start = OMAP3_UART4_BASE,
+ .pa_end = OMAP3_UART4_BASE + SZ_1K - 1,
+ .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_per__uart4 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_uart4_hwmod,
+ .clk = "uart4_ick",
+ .addr = omap3xxx_uart4_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_uart4_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
/* Slave interfaces on the L4_CORE interconnect */
static struct omap_hwmod_ocp_if *omap3xxx_l4_core_slaves[] = {
&omap3xxx_l3_main__l4_core,
@@ -98,6 +177,8 @@ static struct omap_hwmod_ocp_if *omap3xxx_l4_core_slaves[] = {
/* Master interfaces on the L4_CORE interconnect */
static struct omap_hwmod_ocp_if *omap3xxx_l4_core_masters[] = {
&omap3xxx_l4_core__l4_wkup,
+ &omap3_l4_core__uart1,
+ &omap3_l4_core__uart2,
};
/* L4 CORE */
@@ -119,6 +200,8 @@ static struct omap_hwmod_ocp_if *omap3xxx_l4_per_slaves[] = {
/* Master interfaces on the L4_PER interconnect */
static struct omap_hwmod_ocp_if *omap3xxx_l4_per_masters[] = {
+ &omap3_l4_per__uart3,
+ &omap3_l4_per__uart4,
};
/* L4 PER */
@@ -197,6 +280,235 @@ static struct omap_hwmod omap3xxx_iva_hwmod = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
};
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap3xxx_wd_timer2_addrs[] = {
+ {
+ .pa_start = 0x48314000,
+ .pa_end = 0x4831407f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__wd_timer2 = {
+ .master = &omap3xxx_l4_wkup_hwmod,
+ .slave = &omap3xxx_wd_timer2_hwmod,
+ .clk = "wdt2_ick",
+ .addr = omap3xxx_wd_timer2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_wd_timer2_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_wd_timer_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_EMUFREE |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_wd_timer_hwmod_class = {
+ .name = "wd_timer",
+ .sysc = &omap3xxx_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod_ocp_if *omap3xxx_wd_timer2_slaves[] = {
+ &omap3xxx_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap3xxx_wd_timer2_hwmod = {
+ .name = "wd_timer2",
+ .class = &omap3xxx_wd_timer_hwmod_class,
+ .main_clk = "wdt2_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_WDT2_SHIFT,
+ .module_offs = WKUP_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_WDT2_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_wd_timer2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_wd_timer2_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART common */
+
+static struct omap_hwmod_class_sysconfig uart_sysc = {
+ .rev_offs = 0x50,
+ .sysc_offs = 0x54,
+ .syss_offs = 0x58,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class uart_class = {
+ .name = "uart",
+ .sysc = &uart_sysc,
+};
+
+/* UART1 */
+
+static struct omap_hwmod_irq_info uart1_mpu_irqs[] = {
+ { .irq = INT_24XX_UART1_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart1_sdma_reqs[] = {
+ { .name = "tx", .dma_req = OMAP24XX_DMA_UART1_TX, },
+ { .name = "rx", .dma_req = OMAP24XX_DMA_UART1_RX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart1_slaves[] = {
+ &omap3_l4_core__uart1,
+};
+
+static struct omap_hwmod omap3xxx_uart1_hwmod = {
+ .name = "uart1",
+ .mpu_irqs = uart1_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(uart1_mpu_irqs),
+ .sdma_reqs = uart1_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(uart1_sdma_reqs),
+ .main_clk = "uart1_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_UART1_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_EN_UART1_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_uart1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_uart1_slaves),
+ .class = &uart_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART2 */
+
+static struct omap_hwmod_irq_info uart2_mpu_irqs[] = {
+ { .irq = INT_24XX_UART2_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart2_sdma_reqs[] = {
+ { .name = "tx", .dma_req = OMAP24XX_DMA_UART2_TX, },
+ { .name = "rx", .dma_req = OMAP24XX_DMA_UART2_RX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart2_slaves[] = {
+ &omap3_l4_core__uart2,
+};
+
+static struct omap_hwmod omap3xxx_uart2_hwmod = {
+ .name = "uart2",
+ .mpu_irqs = uart2_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(uart2_mpu_irqs),
+ .sdma_reqs = uart2_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(uart2_sdma_reqs),
+ .main_clk = "uart2_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_UART2_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_EN_UART2_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_uart2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_uart2_slaves),
+ .class = &uart_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART3 */
+
+static struct omap_hwmod_irq_info uart3_mpu_irqs[] = {
+ { .irq = INT_24XX_UART3_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart3_sdma_reqs[] = {
+ { .name = "tx", .dma_req = OMAP24XX_DMA_UART3_TX, },
+ { .name = "rx", .dma_req = OMAP24XX_DMA_UART3_RX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart3_slaves[] = {
+ &omap3_l4_per__uart3,
+};
+
+static struct omap_hwmod omap3xxx_uart3_hwmod = {
+ .name = "uart3",
+ .mpu_irqs = uart3_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(uart3_mpu_irqs),
+ .sdma_reqs = uart3_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(uart3_sdma_reqs),
+ .main_clk = "uart3_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = OMAP3430_PER_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_UART3_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_EN_UART3_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_uart3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_uart3_slaves),
+ .class = &uart_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART4 */
+
+static struct omap_hwmod_irq_info uart4_mpu_irqs[] = {
+ { .irq = INT_36XX_UART4_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart4_sdma_reqs[] = {
+ { .name = "rx", .dma_req = OMAP36XX_DMA_UART4_RX, },
+ { .name = "tx", .dma_req = OMAP36XX_DMA_UART4_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart4_slaves[] = {
+ &omap3_l4_per__uart4,
+};
+
+static struct omap_hwmod omap3xxx_uart4_hwmod = {
+ .name = "uart4",
+ .mpu_irqs = uart4_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(uart4_mpu_irqs),
+ .sdma_reqs = uart4_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(uart4_sdma_reqs),
+ .main_clk = "uart4_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = OMAP3430_PER_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3630_EN_UART4_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3630_EN_UART4_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_uart4_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_uart4_slaves),
+ .class = &uart_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
+};
+
static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
&omap3xxx_l3_main_hwmod,
&omap3xxx_l4_core_hwmod,
@@ -204,6 +516,11 @@ static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
&omap3xxx_l4_wkup_hwmod,
&omap3xxx_mpu_hwmod,
&omap3xxx_iva_hwmod,
+ &omap3xxx_wd_timer2_hwmod,
+ &omap3xxx_uart1_hwmod,
+ &omap3xxx_uart2_hwmod,
+ &omap3xxx_uart3_hwmod,
+ &omap3xxx_uart4_hwmod,
NULL,
};
@@ -211,5 +528,3 @@ int __init omap3xxx_hwmod_init(void)
{
return omap_hwmod_init(omap3xxx_hwmods);
}
-
-
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
new file mode 100644
index 000000000000..7274db4de487
--- /dev/null
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -0,0 +1,850 @@
+/*
+ * Hardware modules present on the OMAP44xx chips
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Paul Walmsley
+ * Benoit Cousson
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * 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/io.h>
+
+#include <plat/omap_hwmod.h>
+#include <plat/cpu.h>
+
+#include "omap_hwmod_common_data.h"
+
+#include "cm.h"
+#include "prm-regbits-44xx.h"
+
+/* Base offset for all OMAP4 interrupts external to MPUSS */
+#define OMAP44XX_IRQ_GIC_START 32
+
+/* Base offset for all OMAP4 dma requests */
+#define OMAP44XX_DMA_REQ_START 1
+
+/* Backward references (IPs with Bus Master capability) */
+static struct omap_hwmod omap44xx_dmm_hwmod;
+static struct omap_hwmod omap44xx_emif_fw_hwmod;
+static struct omap_hwmod omap44xx_l3_instr_hwmod;
+static struct omap_hwmod omap44xx_l3_main_1_hwmod;
+static struct omap_hwmod omap44xx_l3_main_2_hwmod;
+static struct omap_hwmod omap44xx_l3_main_3_hwmod;
+static struct omap_hwmod omap44xx_l4_abe_hwmod;
+static struct omap_hwmod omap44xx_l4_cfg_hwmod;
+static struct omap_hwmod omap44xx_l4_per_hwmod;
+static struct omap_hwmod omap44xx_l4_wkup_hwmod;
+static struct omap_hwmod omap44xx_mpu_hwmod;
+static struct omap_hwmod omap44xx_mpu_private_hwmod;
+
+/*
+ * Interconnects omap_hwmod structures
+ * hwmods that compose the global OMAP interconnect
+ */
+
+/*
+ * 'dmm' class
+ * instance(s): dmm
+ */
+static struct omap_hwmod_class omap44xx_dmm_hwmod_class = {
+ .name = "dmm",
+};
+
+/* dmm interface data */
+/* l3_main_1 -> dmm */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__dmm = {
+ .master = &omap44xx_l3_main_1_hwmod,
+ .slave = &omap44xx_dmm_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu -> dmm */
+static struct omap_hwmod_ocp_if omap44xx_mpu__dmm = {
+ .master = &omap44xx_mpu_hwmod,
+ .slave = &omap44xx_dmm_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dmm slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_dmm_slaves[] = {
+ &omap44xx_l3_main_1__dmm,
+ &omap44xx_mpu__dmm,
+};
+
+static struct omap_hwmod_irq_info omap44xx_dmm_irqs[] = {
+ { .irq = 113 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod omap44xx_dmm_hwmod = {
+ .name = "dmm",
+ .class = &omap44xx_dmm_hwmod_class,
+ .slaves = omap44xx_dmm_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_dmm_slaves),
+ .mpu_irqs = omap44xx_dmm_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_dmm_irqs),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'emif_fw' class
+ * instance(s): emif_fw
+ */
+static struct omap_hwmod_class omap44xx_emif_fw_hwmod_class = {
+ .name = "emif_fw",
+};
+
+/* emif_fw interface data */
+/* dmm -> emif_fw */
+static struct omap_hwmod_ocp_if omap44xx_dmm__emif_fw = {
+ .master = &omap44xx_dmm_hwmod,
+ .slave = &omap44xx_emif_fw_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> emif_fw */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__emif_fw = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_emif_fw_hwmod,
+ .clk = "l4_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* emif_fw slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_emif_fw_slaves[] = {
+ &omap44xx_dmm__emif_fw,
+ &omap44xx_l4_cfg__emif_fw,
+};
+
+static struct omap_hwmod omap44xx_emif_fw_hwmod = {
+ .name = "emif_fw",
+ .class = &omap44xx_emif_fw_hwmod_class,
+ .slaves = omap44xx_emif_fw_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_emif_fw_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'l3' class
+ * instance(s): l3_instr, l3_main_1, l3_main_2, l3_main_3
+ */
+static struct omap_hwmod_class omap44xx_l3_hwmod_class = {
+ .name = "l3",
+};
+
+/* l3_instr interface data */
+/* l3_main_3 -> l3_instr */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_3__l3_instr = {
+ .master = &omap44xx_l3_main_3_hwmod,
+ .slave = &omap44xx_l3_instr_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_instr slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l3_instr_slaves[] = {
+ &omap44xx_l3_main_3__l3_instr,
+};
+
+static struct omap_hwmod omap44xx_l3_instr_hwmod = {
+ .name = "l3_instr",
+ .class = &omap44xx_l3_hwmod_class,
+ .slaves = omap44xx_l3_instr_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_l3_instr_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l3_main_2 -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l3_main_1 = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_l3_main_1_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_1 = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_l3_main_1_hwmod,
+ .clk = "l4_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_mpu__l3_main_1 = {
+ .master = &omap44xx_mpu_hwmod,
+ .slave = &omap44xx_l3_main_1_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l3_main_1_slaves[] = {
+ &omap44xx_l3_main_2__l3_main_1,
+ &omap44xx_l4_cfg__l3_main_1,
+ &omap44xx_mpu__l3_main_1,
+};
+
+static struct omap_hwmod omap44xx_l3_main_1_hwmod = {
+ .name = "l3_main_1",
+ .class = &omap44xx_l3_hwmod_class,
+ .slaves = omap44xx_l3_main_1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_l3_main_1_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l3_main_2 interface data */
+/* l3_main_1 -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l3_main_2 = {
+ .master = &omap44xx_l3_main_1_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_2 = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l4_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l3_main_2_slaves[] = {
+ &omap44xx_l3_main_1__l3_main_2,
+ &omap44xx_l4_cfg__l3_main_2,
+};
+
+static struct omap_hwmod omap44xx_l3_main_2_hwmod = {
+ .name = "l3_main_2",
+ .class = &omap44xx_l3_hwmod_class,
+ .slaves = omap44xx_l3_main_2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_l3_main_2_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l3_main_3 interface data */
+/* l3_main_1 -> l3_main_3 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l3_main_3 = {
+ .master = &omap44xx_l3_main_1_hwmod,
+ .slave = &omap44xx_l3_main_3_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_2 -> l3_main_3 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l3_main_3 = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_l3_main_3_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> l3_main_3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_3 = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_l3_main_3_hwmod,
+ .clk = "l4_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_3 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l3_main_3_slaves[] = {
+ &omap44xx_l3_main_1__l3_main_3,
+ &omap44xx_l3_main_2__l3_main_3,
+ &omap44xx_l4_cfg__l3_main_3,
+};
+
+static struct omap_hwmod omap44xx_l3_main_3_hwmod = {
+ .name = "l3_main_3",
+ .class = &omap44xx_l3_hwmod_class,
+ .slaves = omap44xx_l3_main_3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_l3_main_3_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'l4' class
+ * instance(s): l4_abe, l4_cfg, l4_per, l4_wkup
+ */
+static struct omap_hwmod_class omap44xx_l4_hwmod_class = {
+ .name = "l4",
+};
+
+/* l4_abe interface data */
+/* l3_main_1 -> l4_abe */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l4_abe = {
+ .master = &omap44xx_l3_main_1_hwmod,
+ .slave = &omap44xx_l4_abe_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu -> l4_abe */
+static struct omap_hwmod_ocp_if omap44xx_mpu__l4_abe = {
+ .master = &omap44xx_mpu_hwmod,
+ .slave = &omap44xx_l4_abe_hwmod,
+ .clk = "ocp_abe_iclk",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_abe slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l4_abe_slaves[] = {
+ &omap44xx_l3_main_1__l4_abe,
+ &omap44xx_mpu__l4_abe,
+};
+
+static struct omap_hwmod omap44xx_l4_abe_hwmod = {
+ .name = "l4_abe",
+ .class = &omap44xx_l4_hwmod_class,
+ .slaves = omap44xx_l4_abe_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_l4_abe_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l4_cfg interface data */
+/* l3_main_1 -> l4_cfg */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l4_cfg = {
+ .master = &omap44xx_l3_main_1_hwmod,
+ .slave = &omap44xx_l4_cfg_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l4_cfg_slaves[] = {
+ &omap44xx_l3_main_1__l4_cfg,
+};
+
+static struct omap_hwmod omap44xx_l4_cfg_hwmod = {
+ .name = "l4_cfg",
+ .class = &omap44xx_l4_hwmod_class,
+ .slaves = omap44xx_l4_cfg_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_l4_cfg_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l4_per interface data */
+/* l3_main_2 -> l4_per */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l4_per = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_l4_per_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l4_per_slaves[] = {
+ &omap44xx_l3_main_2__l4_per,
+};
+
+static struct omap_hwmod omap44xx_l4_per_hwmod = {
+ .name = "l4_per",
+ .class = &omap44xx_l4_hwmod_class,
+ .slaves = omap44xx_l4_per_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_l4_per_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l4_wkup interface data */
+/* l4_cfg -> l4_wkup */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l4_wkup = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_l4_wkup_hwmod,
+ .clk = "l4_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l4_wkup_slaves[] = {
+ &omap44xx_l4_cfg__l4_wkup,
+};
+
+static struct omap_hwmod omap44xx_l4_wkup_hwmod = {
+ .name = "l4_wkup",
+ .class = &omap44xx_l4_hwmod_class,
+ .slaves = omap44xx_l4_wkup_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_l4_wkup_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'mpu_bus' class
+ * instance(s): mpu_private
+ */
+static struct omap_hwmod_class omap44xx_mpu_bus_hwmod_class = {
+ .name = "mpu_bus",
+};
+
+/* mpu_private interface data */
+/* mpu -> mpu_private */
+static struct omap_hwmod_ocp_if omap44xx_mpu__mpu_private = {
+ .master = &omap44xx_mpu_hwmod,
+ .slave = &omap44xx_mpu_private_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu_private slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mpu_private_slaves[] = {
+ &omap44xx_mpu__mpu_private,
+};
+
+static struct omap_hwmod omap44xx_mpu_private_hwmod = {
+ .name = "mpu_private",
+ .class = &omap44xx_mpu_bus_hwmod_class,
+ .slaves = omap44xx_mpu_private_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mpu_private_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'mpu' class
+ * mpu sub-system
+ */
+
+static struct omap_hwmod_class omap44xx_mpu_hwmod_class = {
+ .name = "mpu",
+};
+
+/* mpu */
+static struct omap_hwmod_irq_info omap44xx_mpu_irqs[] = {
+ { .name = "pl310", .irq = 0 + OMAP44XX_IRQ_GIC_START },
+ { .name = "cti0", .irq = 1 + OMAP44XX_IRQ_GIC_START },
+ { .name = "cti1", .irq = 2 + OMAP44XX_IRQ_GIC_START },
+};
+
+/* mpu master ports */
+static struct omap_hwmod_ocp_if *omap44xx_mpu_masters[] = {
+ &omap44xx_mpu__l3_main_1,
+ &omap44xx_mpu__l4_abe,
+ &omap44xx_mpu__dmm,
+};
+
+static struct omap_hwmod omap44xx_mpu_hwmod = {
+ .name = "mpu",
+ .class = &omap44xx_mpu_hwmod_class,
+ .flags = (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+ .mpu_irqs = omap44xx_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mpu_irqs),
+ .main_clk = "dpll_mpu_m2_ck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_MPU_MPU_CLKCTRL,
+ },
+ },
+ .masters = omap44xx_mpu_masters,
+ .masters_cnt = ARRAY_SIZE(omap44xx_mpu_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_wd_timer_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_EMUFREE |
+ SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+/*
+ * 'uart' class
+ * universal asynchronous receiver/transmitter (uart)
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_uart_sysc = {
+ .rev_offs = 0x0050,
+ .sysc_offs = 0x0054,
+ .syss_offs = 0x0058,
+ .sysc_flags = (SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_wd_timer_hwmod_class = {
+ .name = "wd_timer",
+ .sysc = &omap44xx_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod omap44xx_wd_timer2_hwmod;
+static struct omap_hwmod_irq_info omap44xx_wd_timer2_irqs[] = {
+ { .irq = 80 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_wd_timer2_addrs[] = {
+ {
+ .pa_start = 0x4a314000,
+ .pa_end = 0x4a31407f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+static struct omap_hwmod_class omap44xx_uart_hwmod_class = {
+ .name = "uart",
+ .sysc = &omap44xx_uart_sysc,
+};
+
+/* uart1 */
+static struct omap_hwmod omap44xx_uart1_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart1_irqs[] = {
+ { .irq = 72 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart1_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 48 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx", .dma_req = 49 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart1_addrs[] = {
+ {
+ .pa_start = 0x4806a000,
+ .pa_end = 0x4806a0ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> uart1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart1 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_uart1_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_uart1_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_uart1_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart1 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart1_slaves[] = {
+ &omap44xx_l4_per__uart1,
+};
+
+static struct omap_hwmod omap44xx_uart1_hwmod = {
+ .name = "uart1",
+ .class = &omap44xx_uart_hwmod_class,
+ .mpu_irqs = omap44xx_uart1_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_uart1_irqs),
+ .sdma_reqs = omap44xx_uart1_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_uart1_sdma_reqs),
+ .main_clk = "uart1_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_UART1_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_uart1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_uart1_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* uart2 */
+static struct omap_hwmod omap44xx_uart2_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart2_irqs[] = {
+ { .irq = 73 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart2_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 50 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx", .dma_req = 51 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart2_addrs[] = {
+ {
+ .pa_start = 0x4806c000,
+ .pa_end = 0x4806c0ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__wd_timer2 = {
+ .master = &omap44xx_l4_wkup_hwmod,
+ .slave = &omap44xx_wd_timer2_hwmod,
+ .clk = "l4_wkup_clk_mux_ck",
+ .addr = omap44xx_wd_timer2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_wd_timer2_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* wd_timer2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_wd_timer2_slaves[] = {
+ &omap44xx_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap44xx_wd_timer2_hwmod = {
+ .name = "wd_timer2",
+ .class = &omap44xx_wd_timer_hwmod_class,
+ .mpu_irqs = omap44xx_wd_timer2_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_wd_timer2_irqs),
+ .main_clk = "wd_timer2_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_WKUP_WDT2_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_wd_timer2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_wd_timer2_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* wd_timer3 */
+static struct omap_hwmod omap44xx_wd_timer3_hwmod;
+static struct omap_hwmod_irq_info omap44xx_wd_timer3_irqs[] = {
+ { .irq = 36 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_wd_timer3_addrs[] = {
+ {
+ .pa_start = 0x40130000,
+ .pa_end = 0x4013007f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> uart2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart2 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_uart2_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_uart2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_uart2_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart2_slaves[] = {
+ &omap44xx_l4_per__uart2,
+};
+
+static struct omap_hwmod omap44xx_uart2_hwmod = {
+ .name = "uart2",
+ .class = &omap44xx_uart_hwmod_class,
+ .mpu_irqs = omap44xx_uart2_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_uart2_irqs),
+ .sdma_reqs = omap44xx_uart2_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_uart2_sdma_reqs),
+ .main_clk = "uart2_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_UART2_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_uart2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_uart2_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* uart3 */
+static struct omap_hwmod omap44xx_uart3_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart3_irqs[] = {
+ { .irq = 74 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart3_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 52 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx", .dma_req = 53 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart3_addrs[] = {
+ {
+ .pa_start = 0x48020000,
+ .pa_end = 0x480200ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> wd_timer3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__wd_timer3 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_wd_timer3_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_wd_timer3_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_wd_timer3_addrs),
+ .user = OCP_USER_MPU,
+};
+
+/* l4_abe -> wd_timer3 (dma) */
+static struct omap_hwmod_addr_space omap44xx_wd_timer3_dma_addrs[] = {
+ {
+ .pa_start = 0x49030000,
+ .pa_end = 0x4903007f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> uart3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart3 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_uart3_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_uart3_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_uart3_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart3 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart3_slaves[] = {
+ &omap44xx_l4_per__uart3,
+};
+
+static struct omap_hwmod omap44xx_uart3_hwmod = {
+ .name = "uart3",
+ .class = &omap44xx_uart_hwmod_class,
+ .flags = (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+ .mpu_irqs = omap44xx_uart3_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_uart3_irqs),
+ .sdma_reqs = omap44xx_uart3_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_uart3_sdma_reqs),
+ .main_clk = "uart3_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_UART3_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_uart3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_uart3_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* uart4 */
+static struct omap_hwmod omap44xx_uart4_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart4_irqs[] = {
+ { .irq = 70 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart4_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 54 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx", .dma_req = 55 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart4_addrs[] = {
+ {
+ .pa_start = 0x4806e000,
+ .pa_end = 0x4806e0ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__wd_timer3_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_wd_timer3_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_wd_timer3_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_wd_timer3_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+/* wd_timer3 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_wd_timer3_slaves[] = {
+ &omap44xx_l4_abe__wd_timer3,
+ &omap44xx_l4_abe__wd_timer3_dma,
+};
+
+static struct omap_hwmod omap44xx_wd_timer3_hwmod = {
+ .name = "wd_timer3",
+ .class = &omap44xx_wd_timer_hwmod_class,
+ .mpu_irqs = omap44xx_wd_timer3_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_wd_timer3_irqs),
+ .main_clk = "wd_timer3_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM1_ABE_WDT3_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_wd_timer3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_wd_timer3_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l4_per -> uart4 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart4 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_uart4_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_uart4_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_uart4_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart4 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart4_slaves[] = {
+ &omap44xx_l4_per__uart4,
+};
+
+static struct omap_hwmod omap44xx_uart4_hwmod = {
+ .name = "uart4",
+ .class = &omap44xx_uart_hwmod_class,
+ .mpu_irqs = omap44xx_uart4_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_uart4_irqs),
+ .sdma_reqs = omap44xx_uart4_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_uart4_sdma_reqs),
+ .main_clk = "uart4_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_UART4_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_uart4_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_uart4_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
+ /* dmm class */
+ &omap44xx_dmm_hwmod,
+ /* emif_fw class */
+ &omap44xx_emif_fw_hwmod,
+ /* l3 class */
+ &omap44xx_l3_instr_hwmod,
+ &omap44xx_l3_main_1_hwmod,
+ &omap44xx_l3_main_2_hwmod,
+ &omap44xx_l3_main_3_hwmod,
+ /* l4 class */
+ &omap44xx_l4_abe_hwmod,
+ &omap44xx_l4_cfg_hwmod,
+ &omap44xx_l4_per_hwmod,
+ &omap44xx_l4_wkup_hwmod,
+ /* mpu_bus class */
+ &omap44xx_mpu_private_hwmod,
+
+ /* mpu class */
+ &omap44xx_mpu_hwmod,
+ /* wd_timer class */
+ &omap44xx_wd_timer2_hwmod,
+ &omap44xx_wd_timer3_hwmod,
+
+ /* uart class */
+ &omap44xx_uart1_hwmod,
+ &omap44xx_uart2_hwmod,
+ &omap44xx_uart3_hwmod,
+ &omap44xx_uart4_hwmod,
+ NULL,
+};
+
+int __init omap44xx_hwmod_init(void)
+{
+ return omap_hwmod_init(omap44xx_hwmods);
+}
+
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
index 723b44e252fd..5e81517a7af2 100644
--- a/arch/arm/mach-omap2/pm-debug.c
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -31,12 +31,17 @@
#include <plat/board.h>
#include <plat/powerdomain.h>
#include <plat/clockdomain.h>
+#include <plat/dmtimer.h>
#include "prm.h"
#include "cm.h"
#include "pm.h"
int omap2_pm_debug;
+u32 enable_off_mode;
+u32 sleep_while_idle;
+u32 wakeup_timer_seconds;
+u32 wakeup_timer_milliseconds;
#define DUMP_PRM_MOD_REG(mod, reg) \
regs[reg_count].name = #mod "." #reg; \
@@ -162,7 +167,7 @@ void omap2_pm_dump(int mode, int resume, unsigned int us)
static void pm_dbg_regset_store(u32 *ptr);
-struct dentry *pm_dbg_dir;
+static struct dentry *pm_dbg_dir;
static int pm_dbg_init_done;
@@ -349,6 +354,23 @@ void pm_dbg_update_time(struct powerdomain *pwrdm, int prev)
pwrdm->timer = t;
}
+void omap2_pm_wakeup_on_timer(u32 seconds, u32 milliseconds)
+{
+ u32 tick_rate, cycles;
+
+ if (!seconds && !milliseconds)
+ return;
+
+ tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup));
+ cycles = tick_rate * seconds + tick_rate * milliseconds / 1000;
+ omap_dm_timer_stop(gptimer_wakeup);
+ omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles);
+
+ pr_info("PM: Resume timer in %u.%03u secs"
+ " (%d ticks at %d ticks/sec.)\n",
+ seconds, milliseconds, cycles, tick_rate);
+}
+
static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user)
{
struct seq_file *s = (struct seq_file *)user;
@@ -494,8 +516,10 @@ int pm_dbg_regset_init(int reg_set)
static int pwrdm_suspend_get(void *data, u64 *val)
{
- int ret;
- ret = omap3_pm_get_suspend_state((struct powerdomain *)data);
+ int ret = -EINVAL;
+
+ if (cpu_is_omap34xx())
+ ret = omap3_pm_get_suspend_state((struct powerdomain *)data);
*val = ret;
if (ret >= 0)
@@ -505,7 +529,10 @@ static int pwrdm_suspend_get(void *data, u64 *val)
static int pwrdm_suspend_set(void *data, u64 val)
{
- return omap3_pm_set_suspend_state((struct powerdomain *)data, (int)val);
+ if (cpu_is_omap34xx())
+ return omap3_pm_set_suspend_state(
+ (struct powerdomain *)data, (int)val);
+ return -EINVAL;
}
DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get,
@@ -553,8 +580,10 @@ static int option_set(void *data, u64 val)
*option = val;
- if (option == &enable_off_mode)
- omap3_pm_off_mode_enable(val);
+ if (option == &enable_off_mode) {
+ if (cpu_is_omap34xx())
+ omap3_pm_off_mode_enable(val);
+ }
return 0;
}
@@ -609,6 +638,9 @@ static int __init pm_dbg_init(void)
&sleep_while_idle, &pm_dbg_option_fops);
(void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUGO, d,
&wakeup_timer_seconds, &pm_dbg_option_fops);
+ (void) debugfs_create_file("wakeup_timer_milliseconds",
+ S_IRUGO | S_IWUGO, d, &wakeup_timer_milliseconds,
+ &pm_dbg_option_fops);
pm_dbg_init_done = 1;
return 0;
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 68f9f2e95891..59ca03b0e691 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -18,11 +18,15 @@
#include <plat/omap_device.h>
#include <plat/common.h>
+#include <plat/powerdomain.h>
+#include <plat/clockdomain.h>
+
static struct omap_device_pm_latency *pm_lats;
static struct device *mpu_dev;
-static struct device *dsp_dev;
+static struct device *iva_dev;
static struct device *l3_dev;
+static struct device *dsp_dev;
struct device *omap2_get_mpuss_device(void)
{
@@ -30,10 +34,10 @@ struct device *omap2_get_mpuss_device(void)
return mpu_dev;
}
-struct device *omap2_get_dsp_device(void)
+struct device *omap2_get_iva_device(void)
{
- WARN_ON_ONCE(!dsp_dev);
- return dsp_dev;
+ WARN_ON_ONCE(!iva_dev);
+ return iva_dev;
}
struct device *omap2_get_l3_device(void)
@@ -42,6 +46,13 @@ struct device *omap2_get_l3_device(void)
return l3_dev;
}
+struct device *omap4_get_dsp_device(void)
+{
+ WARN_ON_ONCE(!dsp_dev);
+ return dsp_dev;
+}
+EXPORT_SYMBOL(omap4_get_dsp_device);
+
/* static int _init_omap_device(struct omap_hwmod *oh, void *user) */
static int _init_omap_device(char *name, struct device **new_dev)
{
@@ -69,8 +80,60 @@ static int _init_omap_device(char *name, struct device **new_dev)
static void omap2_init_processor_devices(void)
{
_init_omap_device("mpu", &mpu_dev);
- _init_omap_device("iva", &dsp_dev);
- _init_omap_device("l3_main", &l3_dev);
+ _init_omap_device("iva", &iva_dev);
+ if (cpu_is_omap44xx()) {
+ _init_omap_device("l3_main_1", &l3_dev);
+ _init_omap_device("dsp", &dsp_dev);
+ } else {
+ _init_omap_device("l3_main", &l3_dev);
+ }
+}
+
+/*
+ * This sets pwrdm state (other than mpu & core. Currently only ON &
+ * RET are supported. Function is assuming that clkdm doesn't have
+ * hw_sup mode enabled.
+ */
+int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
+{
+ u32 cur_state;
+ int sleep_switch = 0;
+ int ret = 0;
+
+ if (pwrdm == NULL || IS_ERR(pwrdm))
+ return -EINVAL;
+
+ while (!(pwrdm->pwrsts & (1 << state))) {
+ if (state == PWRDM_POWER_OFF)
+ return ret;
+ state--;
+ }
+
+ cur_state = pwrdm_read_next_pwrst(pwrdm);
+ if (cur_state == state)
+ return ret;
+
+ if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
+ omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
+ sleep_switch = 1;
+ pwrdm_wait_transition(pwrdm);
+ }
+
+ ret = pwrdm_set_next_pwrst(pwrdm, state);
+ if (ret) {
+ printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
+ pwrdm->name);
+ goto err;
+ }
+
+ if (sleep_switch) {
+ omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+ pwrdm_wait_transition(pwrdm);
+ pwrdm_state_switch(pwrdm);
+ }
+
+err:
+ return ret;
}
static int __init omap2_common_pm_init(void)
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 3de6ece23fc8..0d75bfd1fdbe 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -13,14 +13,11 @@
#include <plat/powerdomain.h>
-extern u32 enable_off_mode;
-extern u32 sleep_while_idle;
-
extern void *omap3_secure_ram_storage;
extern void omap3_pm_off_mode_enable(int);
extern void omap_sram_idle(void);
extern int omap3_can_sleep(void);
-extern int set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
+extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
extern int omap3_idle_init(void);
struct cpuidle_params {
@@ -48,10 +45,16 @@ extern struct omap_dm_timer *gptimer_wakeup;
#ifdef CONFIG_PM_DEBUG
extern void omap2_pm_dump(int mode, int resume, unsigned int us);
+extern void omap2_pm_wakeup_on_timer(u32 seconds, u32 milliseconds);
extern int omap2_pm_debug;
+extern u32 enable_off_mode;
+extern u32 sleep_while_idle;
#else
#define omap2_pm_dump(mode, resume, us) do {} while (0);
+#define omap2_pm_wakeup_on_timer(seconds, milliseconds) do {} while (0);
#define omap2_pm_debug 0
+#define enable_off_mode 0
+#define sleep_while_idle 0
#endif
#if defined(CONFIG_CPU_IDLE)
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index 6aeedeacdad8..a40457d81927 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -38,7 +38,6 @@
#include <mach/irqs.h>
#include <plat/clock.h>
#include <plat/sram.h>
-#include <plat/control.h>
#include <plat/dma.h>
#include <plat/board.h>
@@ -48,6 +47,7 @@
#include "cm-regbits-24xx.h"
#include "sdrc.h"
#include "pm.h"
+#include "control.h"
#include <plat/powerdomain.h>
#include <plat/clockdomain.h>
@@ -245,6 +245,8 @@ static int omap2_can_sleep(void)
{
if (omap2_fclks_active())
return 0;
+ if (!omap_uart_can_sleep())
+ return 0;
if (osc_ck->usecount > 1)
return 0;
if (omap_dma_running())
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 7b03426c72a3..75c0cd13ad8e 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -32,13 +32,11 @@
#include <plat/sram.h>
#include <plat/clockdomain.h>
#include <plat/powerdomain.h>
-#include <plat/control.h>
#include <plat/serial.h>
#include <plat/sdrc.h>
#include <plat/prcm.h>
#include <plat/gpmc.h>
#include <plat/dma.h>
-#include <plat/dmtimer.h>
#include <asm/tlbflush.h>
@@ -49,16 +47,12 @@
#include "prm.h"
#include "pm.h"
#include "sdrc.h"
+#include "control.h"
/* Scratchpad offsets */
-#define OMAP343X_TABLE_ADDRESS_OFFSET 0x31
-#define OMAP343X_TABLE_VALUE_OFFSET 0x30
-#define OMAP343X_CONTROL_REG_VALUE_OFFSET 0x32
-
-u32 enable_off_mode;
-u32 sleep_while_idle;
-u32 wakeup_timer_seconds;
-u32 wakeup_timer_milliseconds;
+#define OMAP343X_TABLE_ADDRESS_OFFSET 0xc4
+#define OMAP343X_TABLE_VALUE_OFFSET 0xc0
+#define OMAP343X_CONTROL_REG_VALUE_OFFSET 0xc8
struct power_state {
struct powerdomain *pwrdm;
@@ -316,7 +310,7 @@ static void restore_control_register(u32 val)
/* Function to restore the table entry that was modified for enabling MMU */
static void restore_table_entry(void)
{
- u32 *scratchpad_address;
+ void __iomem *scratchpad_address;
u32 previous_value, control_reg_value;
u32 *address;
@@ -351,7 +345,6 @@ void omap_sram_idle(void)
int core_next_state = PWRDM_POWER_ON;
int core_prev_state, per_prev_state;
u32 sdrc_pwr = 0;
- int per_state_modified = 0;
if (!_omap_sram_idle)
return;
@@ -385,9 +378,9 @@ void omap_sram_idle(void)
/* Enable IO-PAD and IO-CHAIN wakeups */
per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
- if (omap3_has_io_wakeup() && \
- (per_next_state < PWRDM_POWER_ON ||
- core_next_state < PWRDM_POWER_ON)) {
+ if (omap3_has_io_wakeup() &&
+ (per_next_state < PWRDM_POWER_ON ||
+ core_next_state < PWRDM_POWER_ON)) {
prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, PM_WKEN);
omap3_enable_io_chain();
}
@@ -395,20 +388,12 @@ void omap_sram_idle(void)
/* PER */
if (per_next_state < PWRDM_POWER_ON) {
omap_uart_prepare_idle(2);
+ omap_uart_prepare_idle(3);
omap2_gpio_prepare_for_idle(per_next_state);
- if (per_next_state == PWRDM_POWER_OFF) {
- if (core_next_state == PWRDM_POWER_ON) {
- per_next_state = PWRDM_POWER_RET;
- pwrdm_set_next_pwrst(per_pwrdm, per_next_state);
- per_state_modified = 1;
- } else
+ if (per_next_state == PWRDM_POWER_OFF)
omap3_per_save_context();
- }
}
- if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON)
- omap2_clkdm_deny_idle(mpu_pwrdm->pwrdm_clkdms[0]);
-
/* CORE */
if (core_next_state < PWRDM_POWER_ON) {
omap_uart_prepare_idle(0);
@@ -475,8 +460,7 @@ void omap_sram_idle(void)
if (per_prev_state == PWRDM_POWER_OFF)
omap3_per_restore_context();
omap_uart_resume_idle(2);
- if (per_state_modified)
- pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF);
+ omap_uart_resume_idle(3);
}
/* Disable IO-PAD and IO-CHAIN wakeup */
@@ -501,51 +485,6 @@ int omap3_can_sleep(void)
return 1;
}
-/* This sets pwrdm state (other than mpu & core. Currently only ON &
- * RET are supported. Function is assuming that clkdm doesn't have
- * hw_sup mode enabled. */
-int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
-{
- u32 cur_state;
- int sleep_switch = 0;
- int ret = 0;
-
- if (pwrdm == NULL || IS_ERR(pwrdm))
- return -EINVAL;
-
- while (!(pwrdm->pwrsts & (1 << state))) {
- if (state == PWRDM_POWER_OFF)
- return ret;
- state--;
- }
-
- cur_state = pwrdm_read_next_pwrst(pwrdm);
- if (cur_state == state)
- return ret;
-
- if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
- omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
- sleep_switch = 1;
- pwrdm_wait_transition(pwrdm);
- }
-
- ret = pwrdm_set_next_pwrst(pwrdm, state);
- if (ret) {
- printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
- pwrdm->name);
- goto err;
- }
-
- if (sleep_switch) {
- omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
- pwrdm_wait_transition(pwrdm);
- pwrdm_state_switch(pwrdm);
- }
-
-err:
- return ret;
-}
-
static void omap3_pm_idle(void)
{
local_irq_disable();
@@ -567,23 +506,6 @@ out:
#ifdef CONFIG_SUSPEND
static suspend_state_t suspend_state;
-static void omap2_pm_wakeup_on_timer(u32 seconds, u32 milliseconds)
-{
- u32 tick_rate, cycles;
-
- if (!seconds && !milliseconds)
- return;
-
- tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup));
- cycles = tick_rate * seconds + tick_rate * milliseconds / 1000;
- omap_dm_timer_stop(gptimer_wakeup);
- omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles);
-
- pr_info("PM: Resume timer in %u.%03u secs"
- " (%d ticks at %d ticks/sec.)\n",
- seconds, milliseconds, cycles, tick_rate);
-}
-
static int omap3_pm_prepare(void)
{
disable_hlt();
@@ -604,7 +526,7 @@ static int omap3_pm_suspend(void)
pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
/* Set ones wanted by suspend */
list_for_each_entry(pwrst, &pwrst_list, node) {
- if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
+ if (omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
goto restore;
if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
goto restore;
@@ -625,7 +547,7 @@ restore:
pwrst->pwrdm->name, pwrst->next_state);
ret = -1;
}
- set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
+ omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
}
if (ret)
printk(KERN_ERR "Could not enter target state in pm_suspend\n");
@@ -756,6 +678,14 @@ static void __init omap3_d2d_idle(void)
static void __init prcm_setup_regs(void)
{
+ u32 omap3630_auto_uart4_mask = cpu_is_omap3630() ?
+ OMAP3630_AUTO_UART4_MASK : 0;
+ u32 omap3630_en_uart4_mask = cpu_is_omap3630() ?
+ OMAP3630_EN_UART4_MASK : 0;
+ u32 omap3630_grpsel_uart4_mask = cpu_is_omap3630() ?
+ OMAP3630_GRPSEL_UART4_MASK : 0;
+
+
/* XXX Reset all wkdeps. This should be done when initializing
* powerdomains */
prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
@@ -842,6 +772,7 @@ static void __init prcm_setup_regs(void)
CM_AUTOIDLE);
cm_write_mod_reg(
+ omap3630_auto_uart4_mask |
OMAP3430_AUTO_GPIO6_MASK |
OMAP3430_AUTO_GPIO5_MASK |
OMAP3430_AUTO_GPIO4_MASK |
@@ -918,14 +849,16 @@ static void __init prcm_setup_regs(void)
OMAP3430_DSS_MOD, PM_WKEN);
/* Enable wakeups in PER */
- prm_write_mod_reg(OMAP3430_EN_GPIO2_MASK | OMAP3430_EN_GPIO3_MASK |
+ prm_write_mod_reg(omap3630_en_uart4_mask |
+ OMAP3430_EN_GPIO2_MASK | OMAP3430_EN_GPIO3_MASK |
OMAP3430_EN_GPIO4_MASK | OMAP3430_EN_GPIO5_MASK |
OMAP3430_EN_GPIO6_MASK | OMAP3430_EN_UART3_MASK |
OMAP3430_EN_MCBSP2_MASK | OMAP3430_EN_MCBSP3_MASK |
OMAP3430_EN_MCBSP4_MASK,
OMAP3430_PER_MOD, PM_WKEN);
/* and allow them to wake up MPU */
- prm_write_mod_reg(OMAP3430_GRPSEL_GPIO2_MASK |
+ prm_write_mod_reg(omap3630_grpsel_uart4_mask |
+ OMAP3430_GRPSEL_GPIO2_MASK |
OMAP3430_GRPSEL_GPIO3_MASK |
OMAP3430_GRPSEL_GPIO4_MASK |
OMAP3430_GRPSEL_GPIO5_MASK |
@@ -974,7 +907,7 @@ void omap3_pm_off_mode_enable(int enable)
list_for_each_entry(pwrst, &pwrst_list, node) {
pwrst->next_state = state;
- set_pwrdm_state(pwrst->pwrdm, state);
+ omap_set_pwrdm_state(pwrst->pwrdm, state);
}
}
@@ -1019,7 +952,7 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
if (pwrdm_has_hdwr_sar(pwrdm))
pwrdm_enable_hdwr_sar(pwrdm);
- return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
+ return omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
}
/*
@@ -1029,9 +962,6 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
*/
static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
{
- clkdm_clear_all_wkdeps(clkdm);
- clkdm_clear_all_sleepdeps(clkdm);
-
if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
omap2_clkdm_allow_idle(clkdm);
else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
diff --git a/arch/arm/mach-omap2/pm_bus.c b/arch/arm/mach-omap2/pm_bus.c
new file mode 100644
index 000000000000..784989f8f2f5
--- /dev/null
+++ b/arch/arm/mach-omap2/pm_bus.c
@@ -0,0 +1,85 @@
+/*
+ * Runtime PM support code for OMAP
+ *
+ * Author: Kevin Hilman, Deep Root Systems, LLC
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+
+#include <plat/omap_device.h>
+#include <plat/omap-pm.h>
+
+#ifdef CONFIG_PM_RUNTIME
+int omap_pm_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int r, ret = 0;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ ret = pm_generic_runtime_suspend(dev);
+
+ if (!ret && dev->parent == &omap_device_parent) {
+ r = omap_device_idle(pdev);
+ WARN_ON(r);
+ }
+
+ return ret;
+};
+
+int omap_pm_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int r;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ if (dev->parent == &omap_device_parent) {
+ r = omap_device_enable(pdev);
+ WARN_ON(r);
+ }
+
+ return pm_generic_runtime_resume(dev);
+};
+#else
+#define omap_pm_runtime_suspend NULL
+#define omap_pm_runtime_resume NULL
+#endif /* CONFIG_PM_RUNTIME */
+
+static int __init omap_pm_runtime_init(void)
+{
+ const struct dev_pm_ops *pm;
+ struct dev_pm_ops *omap_pm;
+
+ pm = platform_bus_get_pm_ops();
+ if (!pm) {
+ pr_err("%s: unable to get dev_pm_ops from platform_bus\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ omap_pm = kmemdup(pm, sizeof(struct dev_pm_ops), GFP_KERNEL);
+ if (!omap_pm) {
+ pr_err("%s: unable to alloc memory for new dev_pm_ops\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ omap_pm->runtime_suspend = omap_pm_runtime_suspend;
+ omap_pm->runtime_resume = omap_pm_runtime_resume;
+
+ platform_bus_set_pm_ops(omap_pm);
+
+ return 0;
+}
+core_initcall(omap_pm_runtime_init);
diff --git a/arch/arm/mach-omap2/powerdomains44xx.h b/arch/arm/mach-omap2/powerdomains44xx.h
index c7219513472a..9c01b55d6102 100644
--- a/arch/arm/mach-omap2/powerdomains44xx.h
+++ b/arch/arm/mach-omap2/powerdomains44xx.h
@@ -98,7 +98,7 @@ static struct powerdomain dss_44xx_pwrdm = {
.prcm_offs = OMAP4430_PRM_DSS_MOD,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
.pwrsts = PWRSTS_OFF_RET_ON,
- .pwrsts_logic_ret = PWRSTS_OFF_RET,
+ .pwrsts_logic_ret = PWRSTS_OFF,
.banks = 1,
.pwrsts_mem_ret = {
[0] = PWRDM_POWER_OFF, /* dss_mem */
diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index 995b7edbf18d..298a22a754e2 100644
--- a/arch/arm/mach-omap2/prcm-common.h
+++ b/arch/arm/mach-omap2/prcm-common.h
@@ -382,6 +382,9 @@
#define OMAP3430_EN_MPU_SHIFT 1
/* CM_FCLKEN_PER, CM_ICLKEN_PER, PM_WKEN_PER shared bits */
+
+#define OMAP3630_EN_UART4_MASK (1 << 18)
+#define OMAP3630_EN_UART4_SHIFT 18
#define OMAP3430_EN_GPIO6_MASK (1 << 17)
#define OMAP3430_EN_GPIO6_SHIFT 17
#define OMAP3430_EN_GPIO5_MASK (1 << 16)
@@ -422,6 +425,8 @@
#define OMAP3430_EN_MCBSP2_SHIFT 0
/* CM_IDLEST_PER, PM_WKST_PER shared bits */
+#define OMAP3630_ST_UART4_SHIFT 18
+#define OMAP3630_ST_UART4_MASK (1 << 18)
#define OMAP3430_ST_GPIO6_SHIFT 17
#define OMAP3430_ST_GPIO6_MASK (1 << 17)
#define OMAP3430_ST_GPIO5_SHIFT 16
diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
index c20137497c92..a51846e3a6fa 100644
--- a/arch/arm/mach-omap2/prcm.c
+++ b/arch/arm/mach-omap2/prcm.c
@@ -26,13 +26,14 @@
#include <plat/common.h>
#include <plat/prcm.h>
#include <plat/irqs.h>
-#include <plat/control.h>
#include "clock.h"
#include "clock2xxx.h"
#include "cm.h"
#include "prm.h"
#include "prm-regbits-24xx.h"
+#include "prm-regbits-44xx.h"
+#include "control.h"
static void __iomem *prm_base;
static void __iomem *cm_base;
@@ -118,7 +119,7 @@ struct omap3_prcm_regs {
u32 wkup_pm_wken;
};
-struct omap3_prcm_regs prcm_context;
+static struct omap3_prcm_regs prcm_context;
u32 omap_prcm_get_reset_sources(void)
{
@@ -161,8 +162,8 @@ void omap_prcm_arch_reset(char mode, const char *cmd)
prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, prcm_offs,
OMAP2_RM_RSTCTRL);
if (cpu_is_omap44xx())
- prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, prcm_offs,
- OMAP4_RM_RSTCTRL);
+ prm_set_mod_reg_bits(OMAP4430_RST_GLOBAL_WARM_SW_MASK,
+ prcm_offs, OMAP4_RM_RSTCTRL);
}
static inline u32 __omap_prcm_read(void __iomem *base, s16 module, u16 reg)
@@ -215,6 +216,30 @@ u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask)
return v;
}
+/* Read a PRM register, AND it, and shift the result down to bit 0 */
+u32 omap4_prm_read_bits_shift(void __iomem *reg, u32 mask)
+{
+ u32 v;
+
+ v = __raw_readl(reg);
+ v &= mask;
+ v >>= __ffs(mask);
+
+ return v;
+}
+
+/* Read-modify-write a register in a PRM module. Caller must lock */
+u32 omap4_prm_rmw_reg_bits(u32 mask, u32 bits, void __iomem *reg)
+{
+ u32 v;
+
+ v = __raw_readl(reg);
+ v &= ~mask;
+ v |= bits;
+ __raw_writel(v, reg);
+
+ return v;
+}
/* Read a register in a CM module */
u32 cm_read_mod_reg(s16 module, u16 idx)
{
diff --git a/arch/arm/mach-omap2/prm-regbits-34xx.h b/arch/arm/mach-omap2/prm-regbits-34xx.h
index 7fd6023edf96..9e63cb743a97 100644
--- a/arch/arm/mach-omap2/prm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/prm-regbits-34xx.h
@@ -122,6 +122,7 @@
#define OMAP3430_MEMRETSTATE_MASK (1 << 8)
/* PM_MPUGRPSEL_PER, PM_IVA2GRPSEL_PER shared bits */
+#define OMAP3630_GRPSEL_UART4_MASK (1 << 18)
#define OMAP3430_GRPSEL_GPIO6_MASK (1 << 17)
#define OMAP3430_GRPSEL_GPIO5_MASK (1 << 16)
#define OMAP3430_GRPSEL_GPIO4_MASK (1 << 15)
diff --git a/arch/arm/mach-omap2/prm-regbits-44xx.h b/arch/arm/mach-omap2/prm-regbits-44xx.h
index 597be4a2b9ff..25b19b610177 100644
--- a/arch/arm/mach-omap2/prm-regbits-44xx.h
+++ b/arch/arm/mach-omap2/prm-regbits-44xx.h
@@ -1,8 +1,8 @@
/*
* OMAP44xx Power Management register bits
*
- * Copyright (C) 2009 Texas Instruments, Inc.
- * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ * Copyright (C) 2009-2010 Nokia Corporation
*
* Paul Walmsley (paul@pwsan.com)
* Rajendra Nayak (rnayak@ti.com)
@@ -30,587 +30,611 @@
* PRM_LDO_SRAM_MPU_SETUP
*/
#define OMAP4430_ABBOFF_ACT_EXPORT_SHIFT 1
-#define OMAP4430_ABBOFF_ACT_EXPORT_MASK BITFIELD(1, 1)
+#define OMAP4430_ABBOFF_ACT_EXPORT_MASK (1 << 1)
/*
* Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
* PRM_LDO_SRAM_MPU_SETUP
*/
#define OMAP4430_ABBOFF_SLEEP_EXPORT_SHIFT 2
-#define OMAP4430_ABBOFF_SLEEP_EXPORT_MASK BITFIELD(2, 2)
+#define OMAP4430_ABBOFF_SLEEP_EXPORT_MASK (1 << 2)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_ABB_IVA_DONE_EN_SHIFT 31
-#define OMAP4430_ABB_IVA_DONE_EN_MASK BITFIELD(31, 31)
+#define OMAP4430_ABB_IVA_DONE_EN_MASK (1 << 31)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_ABB_IVA_DONE_ST_SHIFT 31
-#define OMAP4430_ABB_IVA_DONE_ST_MASK BITFIELD(31, 31)
+#define OMAP4430_ABB_IVA_DONE_ST_MASK (1 << 31)
/* Used by PRM_IRQENABLE_MPU_2 */
#define OMAP4430_ABB_MPU_DONE_EN_SHIFT 7
-#define OMAP4430_ABB_MPU_DONE_EN_MASK BITFIELD(7, 7)
+#define OMAP4430_ABB_MPU_DONE_EN_MASK (1 << 7)
/* Used by PRM_IRQSTATUS_MPU_2 */
#define OMAP4430_ABB_MPU_DONE_ST_SHIFT 7
-#define OMAP4430_ABB_MPU_DONE_ST_MASK BITFIELD(7, 7)
+#define OMAP4430_ABB_MPU_DONE_ST_MASK (1 << 7)
/* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */
#define OMAP4430_ACTIVE_FBB_SEL_SHIFT 2
-#define OMAP4430_ACTIVE_FBB_SEL_MASK BITFIELD(2, 2)
+#define OMAP4430_ACTIVE_FBB_SEL_MASK (1 << 2)
/* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */
#define OMAP4430_ACTIVE_RBB_SEL_SHIFT 1
-#define OMAP4430_ACTIVE_RBB_SEL_MASK BITFIELD(1, 1)
+#define OMAP4430_ACTIVE_RBB_SEL_MASK (1 << 1)
/* Used by PM_ABE_PWRSTCTRL */
#define OMAP4430_AESSMEM_ONSTATE_SHIFT 16
-#define OMAP4430_AESSMEM_ONSTATE_MASK BITFIELD(16, 17)
+#define OMAP4430_AESSMEM_ONSTATE_MASK (0x3 << 16)
/* Used by PM_ABE_PWRSTCTRL */
#define OMAP4430_AESSMEM_RETSTATE_SHIFT 8
-#define OMAP4430_AESSMEM_RETSTATE_MASK BITFIELD(8, 8)
+#define OMAP4430_AESSMEM_RETSTATE_MASK (1 << 8)
/* Used by PM_ABE_PWRSTST */
#define OMAP4430_AESSMEM_STATEST_SHIFT 4
-#define OMAP4430_AESSMEM_STATEST_MASK BITFIELD(4, 5)
+#define OMAP4430_AESSMEM_STATEST_MASK (0x3 << 4)
/*
* Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
* PRM_LDO_SRAM_MPU_SETUP
*/
#define OMAP4430_AIPOFF_SHIFT 8
-#define OMAP4430_AIPOFF_MASK BITFIELD(8, 8)
+#define OMAP4430_AIPOFF_MASK (1 << 8)
/* Used by PRM_VOLTCTRL */
#define OMAP4430_AUTO_CTRL_VDD_CORE_L_SHIFT 0
-#define OMAP4430_AUTO_CTRL_VDD_CORE_L_MASK BITFIELD(0, 1)
+#define OMAP4430_AUTO_CTRL_VDD_CORE_L_MASK (0x3 << 0)
/* Used by PRM_VOLTCTRL */
#define OMAP4430_AUTO_CTRL_VDD_IVA_L_SHIFT 4
-#define OMAP4430_AUTO_CTRL_VDD_IVA_L_MASK BITFIELD(4, 5)
+#define OMAP4430_AUTO_CTRL_VDD_IVA_L_MASK (0x3 << 4)
/* Used by PRM_VOLTCTRL */
#define OMAP4430_AUTO_CTRL_VDD_MPU_L_SHIFT 2
-#define OMAP4430_AUTO_CTRL_VDD_MPU_L_MASK BITFIELD(2, 3)
+#define OMAP4430_AUTO_CTRL_VDD_MPU_L_MASK (0x3 << 2)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_BYPS_RA_ERR_SHIFT 25
+#define OMAP4430_BYPS_RA_ERR_MASK (1 << 25)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_BYPS_SA_ERR_SHIFT 24
+#define OMAP4430_BYPS_SA_ERR_MASK (1 << 24)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_BYPS_TIMEOUT_ERR_SHIFT 26
+#define OMAP4430_BYPS_TIMEOUT_ERR_MASK (1 << 26)
+
+/* Used by PRM_RSTST */
+#define OMAP4430_C2C_RST_SHIFT 10
+#define OMAP4430_C2C_RST_MASK (1 << 10)
/* Used by PM_CAM_PWRSTCTRL */
#define OMAP4430_CAM_MEM_ONSTATE_SHIFT 16
-#define OMAP4430_CAM_MEM_ONSTATE_MASK BITFIELD(16, 17)
+#define OMAP4430_CAM_MEM_ONSTATE_MASK (0x3 << 16)
/* Used by PM_CAM_PWRSTST */
#define OMAP4430_CAM_MEM_STATEST_SHIFT 4
-#define OMAP4430_CAM_MEM_STATEST_MASK BITFIELD(4, 5)
+#define OMAP4430_CAM_MEM_STATEST_MASK (0x3 << 4)
/* Used by PRM_CLKREQCTRL */
#define OMAP4430_CLKREQ_COND_SHIFT 0
-#define OMAP4430_CLKREQ_COND_MASK BITFIELD(0, 2)
+#define OMAP4430_CLKREQ_COND_MASK (0x7 << 0)
/* Used by PRM_VC_VAL_SMPS_RA_CMD */
#define OMAP4430_CMDRA_VDD_CORE_L_SHIFT 0
-#define OMAP4430_CMDRA_VDD_CORE_L_MASK BITFIELD(0, 7)
+#define OMAP4430_CMDRA_VDD_CORE_L_MASK (0xff << 0)
/* Used by PRM_VC_VAL_SMPS_RA_CMD */
#define OMAP4430_CMDRA_VDD_IVA_L_SHIFT 8
-#define OMAP4430_CMDRA_VDD_IVA_L_MASK BITFIELD(8, 15)
+#define OMAP4430_CMDRA_VDD_IVA_L_MASK (0xff << 8)
/* Used by PRM_VC_VAL_SMPS_RA_CMD */
#define OMAP4430_CMDRA_VDD_MPU_L_SHIFT 16
-#define OMAP4430_CMDRA_VDD_MPU_L_MASK BITFIELD(16, 23)
+#define OMAP4430_CMDRA_VDD_MPU_L_MASK (0xff << 16)
/* Used by PRM_VC_CFG_CHANNEL */
#define OMAP4430_CMD_VDD_CORE_L_SHIFT 4
-#define OMAP4430_CMD_VDD_CORE_L_MASK BITFIELD(4, 4)
+#define OMAP4430_CMD_VDD_CORE_L_MASK (1 << 4)
/* Used by PRM_VC_CFG_CHANNEL */
#define OMAP4430_CMD_VDD_IVA_L_SHIFT 12
-#define OMAP4430_CMD_VDD_IVA_L_MASK BITFIELD(12, 12)
+#define OMAP4430_CMD_VDD_IVA_L_MASK (1 << 12)
/* Used by PRM_VC_CFG_CHANNEL */
#define OMAP4430_CMD_VDD_MPU_L_SHIFT 17
-#define OMAP4430_CMD_VDD_MPU_L_MASK BITFIELD(17, 17)
+#define OMAP4430_CMD_VDD_MPU_L_MASK (1 << 17)
/* Used by PM_CORE_PWRSTCTRL */
#define OMAP4430_CORE_OCMRAM_ONSTATE_SHIFT 18
-#define OMAP4430_CORE_OCMRAM_ONSTATE_MASK BITFIELD(18, 19)
+#define OMAP4430_CORE_OCMRAM_ONSTATE_MASK (0x3 << 18)
/* Used by PM_CORE_PWRSTCTRL */
#define OMAP4430_CORE_OCMRAM_RETSTATE_SHIFT 9
-#define OMAP4430_CORE_OCMRAM_RETSTATE_MASK BITFIELD(9, 9)
+#define OMAP4430_CORE_OCMRAM_RETSTATE_MASK (1 << 9)
/* Used by PM_CORE_PWRSTST */
#define OMAP4430_CORE_OCMRAM_STATEST_SHIFT 6
-#define OMAP4430_CORE_OCMRAM_STATEST_MASK BITFIELD(6, 7)
+#define OMAP4430_CORE_OCMRAM_STATEST_MASK (0x3 << 6)
/* Used by PM_CORE_PWRSTCTRL */
#define OMAP4430_CORE_OTHER_BANK_ONSTATE_SHIFT 16
-#define OMAP4430_CORE_OTHER_BANK_ONSTATE_MASK BITFIELD(16, 17)
+#define OMAP4430_CORE_OTHER_BANK_ONSTATE_MASK (0x3 << 16)
/* Used by PM_CORE_PWRSTCTRL */
#define OMAP4430_CORE_OTHER_BANK_RETSTATE_SHIFT 8
-#define OMAP4430_CORE_OTHER_BANK_RETSTATE_MASK BITFIELD(8, 8)
+#define OMAP4430_CORE_OTHER_BANK_RETSTATE_MASK (1 << 8)
/* Used by PM_CORE_PWRSTST */
#define OMAP4430_CORE_OTHER_BANK_STATEST_SHIFT 4
-#define OMAP4430_CORE_OTHER_BANK_STATEST_MASK BITFIELD(4, 5)
+#define OMAP4430_CORE_OTHER_BANK_STATEST_MASK (0x3 << 4)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_CUSTOM_SHIFT 6
+#define OMAP4430_CUSTOM_MASK (0x3 << 6)
/* Used by PRM_VC_VAL_BYPASS */
#define OMAP4430_DATA_SHIFT 16
-#define OMAP4430_DATA_MASK BITFIELD(16, 23)
+#define OMAP4430_DATA_MASK (0xff << 16)
/* Used by PRM_DEVICE_OFF_CTRL */
#define OMAP4430_DEVICE_OFF_ENABLE_SHIFT 0
-#define OMAP4430_DEVICE_OFF_ENABLE_MASK BITFIELD(0, 0)
+#define OMAP4430_DEVICE_OFF_ENABLE_MASK (1 << 0)
/* Used by PRM_VC_CFG_I2C_MODE */
#define OMAP4430_DFILTEREN_SHIFT 6
-#define OMAP4430_DFILTEREN_MASK BITFIELD(6, 6)
+#define OMAP4430_DFILTEREN_MASK (1 << 6)
-/* Used by PRM_IRQENABLE_MPU, PRM_IRQENABLE_TESLA */
+/*
+ * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
+ * PRM_LDO_SRAM_MPU_SETUP, PRM_SRAM_WKUP_SETUP
+ */
+#define OMAP4430_DISABLE_RTA_EXPORT_SHIFT 0
+#define OMAP4430_DISABLE_RTA_EXPORT_MASK (1 << 0)
+
+/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU, PRM_IRQENABLE_TESLA */
#define OMAP4430_DPLL_ABE_RECAL_EN_SHIFT 4
-#define OMAP4430_DPLL_ABE_RECAL_EN_MASK BITFIELD(4, 4)
+#define OMAP4430_DPLL_ABE_RECAL_EN_MASK (1 << 4)
-/* Used by PRM_IRQSTATUS_MPU, PRM_IRQSTATUS_TESLA */
+/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU, PRM_IRQSTATUS_TESLA */
#define OMAP4430_DPLL_ABE_RECAL_ST_SHIFT 4
-#define OMAP4430_DPLL_ABE_RECAL_ST_MASK BITFIELD(4, 4)
+#define OMAP4430_DPLL_ABE_RECAL_ST_MASK (1 << 4)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_DPLL_CORE_RECAL_EN_SHIFT 0
-#define OMAP4430_DPLL_CORE_RECAL_EN_MASK BITFIELD(0, 0)
+#define OMAP4430_DPLL_CORE_RECAL_EN_MASK (1 << 0)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_DPLL_CORE_RECAL_ST_SHIFT 0
-#define OMAP4430_DPLL_CORE_RECAL_ST_MASK BITFIELD(0, 0)
+#define OMAP4430_DPLL_CORE_RECAL_ST_MASK (1 << 0)
/* Used by PRM_IRQENABLE_MPU */
#define OMAP4430_DPLL_DDRPHY_RECAL_EN_SHIFT 6
-#define OMAP4430_DPLL_DDRPHY_RECAL_EN_MASK BITFIELD(6, 6)
+#define OMAP4430_DPLL_DDRPHY_RECAL_EN_MASK (1 << 6)
/* Used by PRM_IRQSTATUS_MPU */
#define OMAP4430_DPLL_DDRPHY_RECAL_ST_SHIFT 6
-#define OMAP4430_DPLL_DDRPHY_RECAL_ST_MASK BITFIELD(6, 6)
+#define OMAP4430_DPLL_DDRPHY_RECAL_ST_MASK (1 << 6)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU, PRM_IRQENABLE_TESLA */
#define OMAP4430_DPLL_IVA_RECAL_EN_SHIFT 2
-#define OMAP4430_DPLL_IVA_RECAL_EN_MASK BITFIELD(2, 2)
+#define OMAP4430_DPLL_IVA_RECAL_EN_MASK (1 << 2)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU, PRM_IRQSTATUS_TESLA */
#define OMAP4430_DPLL_IVA_RECAL_ST_SHIFT 2
-#define OMAP4430_DPLL_IVA_RECAL_ST_MASK BITFIELD(2, 2)
+#define OMAP4430_DPLL_IVA_RECAL_ST_MASK (1 << 2)
/* Used by PRM_IRQENABLE_MPU */
#define OMAP4430_DPLL_MPU_RECAL_EN_SHIFT 1
-#define OMAP4430_DPLL_MPU_RECAL_EN_MASK BITFIELD(1, 1)
+#define OMAP4430_DPLL_MPU_RECAL_EN_MASK (1 << 1)
/* Used by PRM_IRQSTATUS_MPU */
#define OMAP4430_DPLL_MPU_RECAL_ST_SHIFT 1
-#define OMAP4430_DPLL_MPU_RECAL_ST_MASK BITFIELD(1, 1)
+#define OMAP4430_DPLL_MPU_RECAL_ST_MASK (1 << 1)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_DPLL_PER_RECAL_EN_SHIFT 3
-#define OMAP4430_DPLL_PER_RECAL_EN_MASK BITFIELD(3, 3)
+#define OMAP4430_DPLL_PER_RECAL_EN_MASK (1 << 3)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_DPLL_PER_RECAL_ST_SHIFT 3
-#define OMAP4430_DPLL_PER_RECAL_ST_MASK BITFIELD(3, 3)
+#define OMAP4430_DPLL_PER_RECAL_ST_MASK (1 << 3)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_DPLL_UNIPRO_RECAL_EN_SHIFT 7
-#define OMAP4430_DPLL_UNIPRO_RECAL_EN_MASK BITFIELD(7, 7)
+#define OMAP4430_DPLL_UNIPRO_RECAL_EN_MASK (1 << 7)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_DPLL_UNIPRO_RECAL_ST_SHIFT 7
-#define OMAP4430_DPLL_UNIPRO_RECAL_ST_MASK BITFIELD(7, 7)
-
-/* Used by PRM_IRQENABLE_MPU */
-#define OMAP4430_DPLL_USB_RECAL_EN_SHIFT 5
-#define OMAP4430_DPLL_USB_RECAL_EN_MASK BITFIELD(5, 5)
-
-/* Used by PRM_IRQSTATUS_MPU */
-#define OMAP4430_DPLL_USB_RECAL_ST_SHIFT 5
-#define OMAP4430_DPLL_USB_RECAL_ST_MASK BITFIELD(5, 5)
+#define OMAP4430_DPLL_UNIPRO_RECAL_ST_MASK (1 << 7)
/* Used by PM_DSS_PWRSTCTRL */
#define OMAP4430_DSS_MEM_ONSTATE_SHIFT 16
-#define OMAP4430_DSS_MEM_ONSTATE_MASK BITFIELD(16, 17)
+#define OMAP4430_DSS_MEM_ONSTATE_MASK (0x3 << 16)
/* Used by PM_DSS_PWRSTCTRL */
#define OMAP4430_DSS_MEM_RETSTATE_SHIFT 8
-#define OMAP4430_DSS_MEM_RETSTATE_MASK BITFIELD(8, 8)
+#define OMAP4430_DSS_MEM_RETSTATE_MASK (1 << 8)
/* Used by PM_DSS_PWRSTST */
#define OMAP4430_DSS_MEM_STATEST_SHIFT 4
-#define OMAP4430_DSS_MEM_STATEST_MASK BITFIELD(4, 5)
+#define OMAP4430_DSS_MEM_STATEST_MASK (0x3 << 4)
/* Used by PM_CORE_PWRSTCTRL */
#define OMAP4430_DUCATI_L2RAM_ONSTATE_SHIFT 20
-#define OMAP4430_DUCATI_L2RAM_ONSTATE_MASK BITFIELD(20, 21)
+#define OMAP4430_DUCATI_L2RAM_ONSTATE_MASK (0x3 << 20)
/* Used by PM_CORE_PWRSTCTRL */
#define OMAP4430_DUCATI_L2RAM_RETSTATE_SHIFT 10
-#define OMAP4430_DUCATI_L2RAM_RETSTATE_MASK BITFIELD(10, 10)
+#define OMAP4430_DUCATI_L2RAM_RETSTATE_MASK (1 << 10)
/* Used by PM_CORE_PWRSTST */
#define OMAP4430_DUCATI_L2RAM_STATEST_SHIFT 8
-#define OMAP4430_DUCATI_L2RAM_STATEST_MASK BITFIELD(8, 9)
+#define OMAP4430_DUCATI_L2RAM_STATEST_MASK (0x3 << 8)
/* Used by PM_CORE_PWRSTCTRL */
#define OMAP4430_DUCATI_UNICACHE_ONSTATE_SHIFT 22
-#define OMAP4430_DUCATI_UNICACHE_ONSTATE_MASK BITFIELD(22, 23)
+#define OMAP4430_DUCATI_UNICACHE_ONSTATE_MASK (0x3 << 22)
/* Used by PM_CORE_PWRSTCTRL */
#define OMAP4430_DUCATI_UNICACHE_RETSTATE_SHIFT 11
-#define OMAP4430_DUCATI_UNICACHE_RETSTATE_MASK BITFIELD(11, 11)
+#define OMAP4430_DUCATI_UNICACHE_RETSTATE_MASK (1 << 11)
/* Used by PM_CORE_PWRSTST */
#define OMAP4430_DUCATI_UNICACHE_STATEST_SHIFT 10
-#define OMAP4430_DUCATI_UNICACHE_STATEST_MASK BITFIELD(10, 11)
+#define OMAP4430_DUCATI_UNICACHE_STATEST_MASK (0x3 << 10)
/* Used by RM_MPU_RSTST */
#define OMAP4430_EMULATION_RST_SHIFT 0
-#define OMAP4430_EMULATION_RST_MASK BITFIELD(0, 0)
+#define OMAP4430_EMULATION_RST_MASK (1 << 0)
/* Used by RM_DUCATI_RSTST */
#define OMAP4430_EMULATION_RST1ST_SHIFT 3
-#define OMAP4430_EMULATION_RST1ST_MASK BITFIELD(3, 3)
+#define OMAP4430_EMULATION_RST1ST_MASK (1 << 3)
/* Used by RM_DUCATI_RSTST */
#define OMAP4430_EMULATION_RST2ST_SHIFT 4
-#define OMAP4430_EMULATION_RST2ST_MASK BITFIELD(4, 4)
+#define OMAP4430_EMULATION_RST2ST_MASK (1 << 4)
/* Used by RM_IVAHD_RSTST */
#define OMAP4430_EMULATION_SEQ1_RST1ST_SHIFT 3
-#define OMAP4430_EMULATION_SEQ1_RST1ST_MASK BITFIELD(3, 3)
+#define OMAP4430_EMULATION_SEQ1_RST1ST_MASK (1 << 3)
/* Used by RM_IVAHD_RSTST */
#define OMAP4430_EMULATION_SEQ2_RST2ST_SHIFT 4
-#define OMAP4430_EMULATION_SEQ2_RST2ST_MASK BITFIELD(4, 4)
+#define OMAP4430_EMULATION_SEQ2_RST2ST_MASK (1 << 4)
/* Used by PM_EMU_PWRSTCTRL */
#define OMAP4430_EMU_BANK_ONSTATE_SHIFT 16
-#define OMAP4430_EMU_BANK_ONSTATE_MASK BITFIELD(16, 17)
+#define OMAP4430_EMU_BANK_ONSTATE_MASK (0x3 << 16)
/* Used by PM_EMU_PWRSTST */
#define OMAP4430_EMU_BANK_STATEST_SHIFT 4
-#define OMAP4430_EMU_BANK_STATEST_MASK BITFIELD(4, 5)
-
-/*
- * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
- * PRM_LDO_SRAM_MPU_SETUP, PRM_SRAM_WKUP_SETUP
- */
-#define OMAP4430_ENABLE_RTA_EXPORT_SHIFT 0
-#define OMAP4430_ENABLE_RTA_EXPORT_MASK BITFIELD(0, 0)
+#define OMAP4430_EMU_BANK_STATEST_MASK (0x3 << 4)
/*
* Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
* PRM_LDO_SRAM_MPU_SETUP
*/
-#define OMAP4430_ENFUNC1_SHIFT 3
-#define OMAP4430_ENFUNC1_MASK BITFIELD(3, 3)
+#define OMAP4430_ENFUNC1_EXPORT_SHIFT 3
+#define OMAP4430_ENFUNC1_EXPORT_MASK (1 << 3)
/*
* Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
* PRM_LDO_SRAM_MPU_SETUP
*/
-#define OMAP4430_ENFUNC3_SHIFT 5
-#define OMAP4430_ENFUNC3_MASK BITFIELD(5, 5)
+#define OMAP4430_ENFUNC3_EXPORT_SHIFT 5
+#define OMAP4430_ENFUNC3_EXPORT_MASK (1 << 5)
/*
* Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
* PRM_LDO_SRAM_MPU_SETUP
*/
#define OMAP4430_ENFUNC4_SHIFT 6
-#define OMAP4430_ENFUNC4_MASK BITFIELD(6, 6)
+#define OMAP4430_ENFUNC4_MASK (1 << 6)
/*
* Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
* PRM_LDO_SRAM_MPU_SETUP
*/
#define OMAP4430_ENFUNC5_SHIFT 7
-#define OMAP4430_ENFUNC5_MASK BITFIELD(7, 7)
+#define OMAP4430_ENFUNC5_MASK (1 << 7)
/* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
#define OMAP4430_ERRORGAIN_SHIFT 16
-#define OMAP4430_ERRORGAIN_MASK BITFIELD(16, 23)
+#define OMAP4430_ERRORGAIN_MASK (0xff << 16)
/* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
#define OMAP4430_ERROROFFSET_SHIFT 24
-#define OMAP4430_ERROROFFSET_MASK BITFIELD(24, 31)
+#define OMAP4430_ERROROFFSET_MASK (0xff << 24)
/* Used by PRM_RSTST */
#define OMAP4430_EXTERNAL_WARM_RST_SHIFT 5
-#define OMAP4430_EXTERNAL_WARM_RST_MASK BITFIELD(5, 5)
+#define OMAP4430_EXTERNAL_WARM_RST_MASK (1 << 5)
/* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
#define OMAP4430_FORCEUPDATE_SHIFT 1
-#define OMAP4430_FORCEUPDATE_MASK BITFIELD(1, 1)
+#define OMAP4430_FORCEUPDATE_MASK (1 << 1)
/* Used by PRM_VP_CORE_VOLTAGE, PRM_VP_IVA_VOLTAGE, PRM_VP_MPU_VOLTAGE */
#define OMAP4430_FORCEUPDATEWAIT_SHIFT 8
-#define OMAP4430_FORCEUPDATEWAIT_MASK BITFIELD(8, 31)
+#define OMAP4430_FORCEUPDATEWAIT_MASK (0xffffff << 8)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_TESLA */
#define OMAP4430_FORCEWKUP_EN_SHIFT 10
-#define OMAP4430_FORCEWKUP_EN_MASK BITFIELD(10, 10)
+#define OMAP4430_FORCEWKUP_EN_MASK (1 << 10)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_TESLA */
#define OMAP4430_FORCEWKUP_ST_SHIFT 10
-#define OMAP4430_FORCEWKUP_ST_MASK BITFIELD(10, 10)
+#define OMAP4430_FORCEWKUP_ST_MASK (1 << 10)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_FUNC_SHIFT 16
+#define OMAP4430_FUNC_MASK (0xfff << 16)
/* Used by PM_GFX_PWRSTCTRL */
#define OMAP4430_GFX_MEM_ONSTATE_SHIFT 16
-#define OMAP4430_GFX_MEM_ONSTATE_MASK BITFIELD(16, 17)
+#define OMAP4430_GFX_MEM_ONSTATE_MASK (0x3 << 16)
/* Used by PM_GFX_PWRSTST */
#define OMAP4430_GFX_MEM_STATEST_SHIFT 4
-#define OMAP4430_GFX_MEM_STATEST_MASK BITFIELD(4, 5)
+#define OMAP4430_GFX_MEM_STATEST_MASK (0x3 << 4)
/* Used by PRM_RSTST */
#define OMAP4430_GLOBAL_COLD_RST_SHIFT 0
-#define OMAP4430_GLOBAL_COLD_RST_MASK BITFIELD(0, 0)
+#define OMAP4430_GLOBAL_COLD_RST_MASK (1 << 0)
/* Used by PRM_RSTST */
#define OMAP4430_GLOBAL_WARM_SW_RST_SHIFT 1
-#define OMAP4430_GLOBAL_WARM_SW_RST_MASK BITFIELD(1, 1)
+#define OMAP4430_GLOBAL_WARM_SW_RST_MASK (1 << 1)
/* Used by PRM_IO_PMCTRL */
#define OMAP4430_GLOBAL_WUEN_SHIFT 16
-#define OMAP4430_GLOBAL_WUEN_MASK BITFIELD(16, 16)
+#define OMAP4430_GLOBAL_WUEN_MASK (1 << 16)
/* Used by PRM_VC_CFG_I2C_MODE */
#define OMAP4430_HSMCODE_SHIFT 0
-#define OMAP4430_HSMCODE_MASK BITFIELD(0, 2)
+#define OMAP4430_HSMCODE_MASK (0x7 << 0)
/* Used by PRM_VC_CFG_I2C_MODE */
#define OMAP4430_HSMODEEN_SHIFT 3
-#define OMAP4430_HSMODEEN_MASK BITFIELD(3, 3)
+#define OMAP4430_HSMODEEN_MASK (1 << 3)
/* Used by PRM_VC_CFG_I2C_CLK */
#define OMAP4430_HSSCLH_SHIFT 16
-#define OMAP4430_HSSCLH_MASK BITFIELD(16, 23)
+#define OMAP4430_HSSCLH_MASK (0xff << 16)
/* Used by PRM_VC_CFG_I2C_CLK */
#define OMAP4430_HSSCLL_SHIFT 24
-#define OMAP4430_HSSCLL_MASK BITFIELD(24, 31)
+#define OMAP4430_HSSCLL_MASK (0xff << 24)
/* Used by PM_IVAHD_PWRSTCTRL */
#define OMAP4430_HWA_MEM_ONSTATE_SHIFT 16
-#define OMAP4430_HWA_MEM_ONSTATE_MASK BITFIELD(16, 17)
+#define OMAP4430_HWA_MEM_ONSTATE_MASK (0x3 << 16)
/* Used by PM_IVAHD_PWRSTCTRL */
#define OMAP4430_HWA_MEM_RETSTATE_SHIFT 8
-#define OMAP4430_HWA_MEM_RETSTATE_MASK BITFIELD(8, 8)
+#define OMAP4430_HWA_MEM_RETSTATE_MASK (1 << 8)
/* Used by PM_IVAHD_PWRSTST */
#define OMAP4430_HWA_MEM_STATEST_SHIFT 4
-#define OMAP4430_HWA_MEM_STATEST_MASK BITFIELD(4, 5)
+#define OMAP4430_HWA_MEM_STATEST_MASK (0x3 << 4)
/* Used by RM_MPU_RSTST */
#define OMAP4430_ICECRUSHER_MPU_RST_SHIFT 1
-#define OMAP4430_ICECRUSHER_MPU_RST_MASK BITFIELD(1, 1)
+#define OMAP4430_ICECRUSHER_MPU_RST_MASK (1 << 1)
/* Used by RM_DUCATI_RSTST */
#define OMAP4430_ICECRUSHER_RST1ST_SHIFT 5
-#define OMAP4430_ICECRUSHER_RST1ST_MASK BITFIELD(5, 5)
+#define OMAP4430_ICECRUSHER_RST1ST_MASK (1 << 5)
/* Used by RM_DUCATI_RSTST */
#define OMAP4430_ICECRUSHER_RST2ST_SHIFT 6
-#define OMAP4430_ICECRUSHER_RST2ST_MASK BITFIELD(6, 6)
+#define OMAP4430_ICECRUSHER_RST2ST_MASK (1 << 6)
/* Used by RM_IVAHD_RSTST */
#define OMAP4430_ICECRUSHER_SEQ1_RST1ST_SHIFT 5
-#define OMAP4430_ICECRUSHER_SEQ1_RST1ST_MASK BITFIELD(5, 5)
+#define OMAP4430_ICECRUSHER_SEQ1_RST1ST_MASK (1 << 5)
/* Used by RM_IVAHD_RSTST */
#define OMAP4430_ICECRUSHER_SEQ2_RST2ST_SHIFT 6
-#define OMAP4430_ICECRUSHER_SEQ2_RST2ST_MASK BITFIELD(6, 6)
+#define OMAP4430_ICECRUSHER_SEQ2_RST2ST_MASK (1 << 6)
/* Used by PRM_RSTST */
#define OMAP4430_ICEPICK_RST_SHIFT 9
-#define OMAP4430_ICEPICK_RST_MASK BITFIELD(9, 9)
+#define OMAP4430_ICEPICK_RST_MASK (1 << 9)
/* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
#define OMAP4430_INITVDD_SHIFT 2
-#define OMAP4430_INITVDD_MASK BITFIELD(2, 2)
+#define OMAP4430_INITVDD_MASK (1 << 2)
/* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
#define OMAP4430_INITVOLTAGE_SHIFT 8
-#define OMAP4430_INITVOLTAGE_MASK BITFIELD(8, 15)
+#define OMAP4430_INITVOLTAGE_MASK (0xff << 8)
/*
- * Used by PM_EMU_PWRSTST, PM_CORE_PWRSTST, PM_CAM_PWRSTST, PM_L3INIT_PWRSTST,
- * PM_ABE_PWRSTST, PM_GFX_PWRSTST, PM_MPU_PWRSTST, PM_CEFUSE_PWRSTST,
- * PM_DSS_PWRSTST, PM_L4PER_PWRSTST, PM_TESLA_PWRSTST, PM_IVAHD_PWRSTST
+ * Used by PM_ABE_PWRSTST, PM_CAM_PWRSTST, PM_CEFUSE_PWRSTST, PM_CORE_PWRSTST,
+ * PM_DSS_PWRSTST, PM_EMU_PWRSTST, PM_GFX_PWRSTST, PM_IVAHD_PWRSTST,
+ * PM_L3INIT_PWRSTST, PM_L4PER_PWRSTST, PM_MPU_PWRSTST, PM_TESLA_PWRSTST
*/
#define OMAP4430_INTRANSITION_SHIFT 20
-#define OMAP4430_INTRANSITION_MASK BITFIELD(20, 20)
+#define OMAP4430_INTRANSITION_MASK (1 << 20)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_IO_EN_SHIFT 9
-#define OMAP4430_IO_EN_MASK BITFIELD(9, 9)
+#define OMAP4430_IO_EN_MASK (1 << 9)
/* Used by PRM_IO_PMCTRL */
#define OMAP4430_IO_ON_STATUS_SHIFT 5
-#define OMAP4430_IO_ON_STATUS_MASK BITFIELD(5, 5)
+#define OMAP4430_IO_ON_STATUS_MASK (1 << 5)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_IO_ST_SHIFT 9
-#define OMAP4430_IO_ST_MASK BITFIELD(9, 9)
+#define OMAP4430_IO_ST_MASK (1 << 9)
/* Used by PRM_IO_PMCTRL */
#define OMAP4430_ISOCLK_OVERRIDE_SHIFT 0
-#define OMAP4430_ISOCLK_OVERRIDE_MASK BITFIELD(0, 0)
+#define OMAP4430_ISOCLK_OVERRIDE_MASK (1 << 0)
/* Used by PRM_IO_PMCTRL */
#define OMAP4430_ISOCLK_STATUS_SHIFT 1
-#define OMAP4430_ISOCLK_STATUS_MASK BITFIELD(1, 1)
+#define OMAP4430_ISOCLK_STATUS_MASK (1 << 1)
/* Used by PRM_IO_PMCTRL */
#define OMAP4430_ISOOVR_EXTEND_SHIFT 4
-#define OMAP4430_ISOOVR_EXTEND_MASK BITFIELD(4, 4)
+#define OMAP4430_ISOOVR_EXTEND_MASK (1 << 4)
/* Used by PRM_IO_COUNT */
#define OMAP4430_ISO_2_ON_TIME_SHIFT 0
-#define OMAP4430_ISO_2_ON_TIME_MASK BITFIELD(0, 7)
+#define OMAP4430_ISO_2_ON_TIME_MASK (0xff << 0)
/* Used by PM_L3INIT_PWRSTCTRL */
#define OMAP4430_L3INIT_BANK1_ONSTATE_SHIFT 16
-#define OMAP4430_L3INIT_BANK1_ONSTATE_MASK BITFIELD(16, 17)
+#define OMAP4430_L3INIT_BANK1_ONSTATE_MASK (0x3 << 16)
/* Used by PM_L3INIT_PWRSTCTRL */
#define OMAP4430_L3INIT_BANK1_RETSTATE_SHIFT 8
-#define OMAP4430_L3INIT_BANK1_RETSTATE_MASK BITFIELD(8, 8)
+#define OMAP4430_L3INIT_BANK1_RETSTATE_MASK (1 << 8)
/* Used by PM_L3INIT_PWRSTST */
#define OMAP4430_L3INIT_BANK1_STATEST_SHIFT 4
-#define OMAP4430_L3INIT_BANK1_STATEST_MASK BITFIELD(4, 5)
+#define OMAP4430_L3INIT_BANK1_STATEST_MASK (0x3 << 4)
+
+/*
+ * Used by PM_ABE_PWRSTST, PM_CORE_PWRSTST, PM_IVAHD_PWRSTST,
+ * PM_L3INIT_PWRSTST, PM_L4PER_PWRSTST, PM_MPU_PWRSTST, PM_TESLA_PWRSTST
+ */
+#define OMAP4430_LASTPOWERSTATEENTERED_SHIFT 24
+#define OMAP4430_LASTPOWERSTATEENTERED_MASK (0x3 << 24)
/*
- * Used by PM_CORE_PWRSTCTRL, PM_L3INIT_PWRSTCTRL, PM_ABE_PWRSTCTRL,
- * PM_MPU_PWRSTCTRL, PM_DSS_PWRSTCTRL, PM_L4PER_PWRSTCTRL, PM_TESLA_PWRSTCTRL,
- * PM_IVAHD_PWRSTCTRL
+ * Used by PM_ABE_PWRSTCTRL, PM_CORE_PWRSTCTRL, PM_DSS_PWRSTCTRL,
+ * PM_IVAHD_PWRSTCTRL, PM_L3INIT_PWRSTCTRL, PM_L4PER_PWRSTCTRL,
+ * PM_MPU_PWRSTCTRL, PM_TESLA_PWRSTCTRL
*/
#define OMAP4430_LOGICRETSTATE_SHIFT 2
-#define OMAP4430_LOGICRETSTATE_MASK BITFIELD(2, 2)
+#define OMAP4430_LOGICRETSTATE_MASK (1 << 2)
/*
- * Used by PM_EMU_PWRSTST, PM_CORE_PWRSTST, PM_CAM_PWRSTST, PM_L3INIT_PWRSTST,
- * PM_ABE_PWRSTST, PM_GFX_PWRSTST, PM_MPU_PWRSTST, PM_CEFUSE_PWRSTST,
- * PM_DSS_PWRSTST, PM_L4PER_PWRSTST, PM_TESLA_PWRSTST, PM_IVAHD_PWRSTST
+ * Used by PM_ABE_PWRSTST, PM_CAM_PWRSTST, PM_CEFUSE_PWRSTST, PM_CORE_PWRSTST,
+ * PM_DSS_PWRSTST, PM_EMU_PWRSTST, PM_GFX_PWRSTST, PM_IVAHD_PWRSTST,
+ * PM_L3INIT_PWRSTST, PM_L4PER_PWRSTST, PM_MPU_PWRSTST, PM_TESLA_PWRSTST
*/
#define OMAP4430_LOGICSTATEST_SHIFT 2
-#define OMAP4430_LOGICSTATEST_MASK BITFIELD(2, 2)
+#define OMAP4430_LOGICSTATEST_MASK (1 << 2)
/*
- * Used by RM_WKUP_GPIO1_CONTEXT, RM_WKUP_KEYBOARD_CONTEXT,
- * RM_WKUP_L4WKUP_CONTEXT, RM_WKUP_RTC_CONTEXT, RM_WKUP_SARRAM_CONTEXT,
- * RM_WKUP_SYNCTIMER_CONTEXT, RM_WKUP_TIMER12_CONTEXT, RM_WKUP_TIMER1_CONTEXT,
- * RM_WKUP_USIM_CONTEXT, RM_WKUP_WDT1_CONTEXT, RM_WKUP_WDT2_CONTEXT,
- * RM_EMU_DEBUGSS_CONTEXT, RM_D2D_SAD2D_CONTEXT, RM_D2D_SAD2D_FW_CONTEXT,
- * RM_DUCATI_DUCATI_CONTEXT, RM_L3INSTR_L3_3_CONTEXT,
- * RM_L3INSTR_L3_INSTR_CONTEXT, RM_L3INSTR_OCP_WP1_CONTEXT,
- * RM_L3_1_L3_1_CONTEXT, RM_L3_2_L3_2_CONTEXT, RM_L3_2_OCMC_RAM_CONTEXT,
- * RM_L4CFG_L4_CFG_CONTEXT, RM_L4CFG_SAR_ROM_CONTEXT, RM_MEMIF_DLL_CONTEXT,
- * RM_MEMIF_DLL_H_CONTEXT, RM_MEMIF_DMM_CONTEXT, RM_MEMIF_EMIF_FW_CONTEXT,
- * RM_CAM_FDIF_CONTEXT, RM_CAM_ISS_CONTEXT, RM_L3INIT_CCPTX_CONTEXT,
- * RM_L3INIT_EMAC_CONTEXT, RM_L3INIT_P1500_CONTEXT, RM_L3INIT_PCIESS_CONTEXT,
- * RM_L3INIT_SATA_CONTEXT, RM_L3INIT_TPPSS_CONTEXT, RM_L3INIT_UNIPRO1_CONTEXT,
- * RM_L3INIT_USBPHYOCP2SCP_CONTEXT, RM_L3INIT_XHPI_CONTEXT,
- * RM_ABE_AESS_CONTEXT, RM_ABE_DMIC_CONTEXT, RM_ABE_MCASP_CONTEXT,
+ * Used by RM_ABE_AESS_CONTEXT, RM_ABE_DMIC_CONTEXT, RM_ABE_MCASP_CONTEXT,
* RM_ABE_MCBSP1_CONTEXT, RM_ABE_MCBSP2_CONTEXT, RM_ABE_MCBSP3_CONTEXT,
* RM_ABE_PDM_CONTEXT, RM_ABE_SLIMBUS_CONTEXT, RM_ABE_TIMER5_CONTEXT,
* RM_ABE_TIMER6_CONTEXT, RM_ABE_TIMER7_CONTEXT, RM_ABE_TIMER8_CONTEXT,
- * RM_ABE_WDT3_CONTEXT, RM_GFX_GFX_CONTEXT, RM_MPU_MPU_CONTEXT,
- * RM_CEFUSE_CEFUSE_CONTEXT, RM_ALWON_MDMINTC_CONTEXT,
- * RM_ALWON_SR_CORE_CONTEXT, RM_ALWON_SR_IVA_CONTEXT, RM_ALWON_SR_MPU_CONTEXT,
- * RM_DSS_DEISS_CONTEXT, RM_DSS_DSS_CONTEXT, RM_L4PER_ADC_CONTEXT,
- * RM_L4PER_DMTIMER10_CONTEXT, RM_L4PER_DMTIMER11_CONTEXT,
- * RM_L4PER_DMTIMER2_CONTEXT, RM_L4PER_DMTIMER3_CONTEXT,
- * RM_L4PER_DMTIMER4_CONTEXT, RM_L4PER_DMTIMER9_CONTEXT, RM_L4PER_ELM_CONTEXT,
- * RM_L4PER_HDQ1W_CONTEXT, RM_L4PER_HECC1_CONTEXT, RM_L4PER_HECC2_CONTEXT,
- * RM_L4PER_I2C2_CONTEXT, RM_L4PER_I2C3_CONTEXT, RM_L4PER_I2C4_CONTEXT,
- * RM_L4PER_I2C5_CONTEXT, RM_L4PER_L4_PER_CONTEXT, RM_L4PER_MCASP2_CONTEXT,
- * RM_L4PER_MCASP3_CONTEXT, RM_L4PER_MCBSP4_CONTEXT, RM_L4PER_MCSPI1_CONTEXT,
- * RM_L4PER_MCSPI2_CONTEXT, RM_L4PER_MCSPI3_CONTEXT, RM_L4PER_MCSPI4_CONTEXT,
- * RM_L4PER_MGATE_CONTEXT, RM_L4PER_MMCSD3_CONTEXT, RM_L4PER_MMCSD4_CONTEXT,
- * RM_L4PER_MMCSD5_CONTEXT, RM_L4PER_MSPROHG_CONTEXT,
- * RM_L4PER_SLIMBUS2_CONTEXT, RM_L4SEC_PKAEIP29_CONTEXT,
- * RM_TESLA_TESLA_CONTEXT, RM_IVAHD_IVAHD_CONTEXT, RM_IVAHD_SL2_CONTEXT
+ * RM_ABE_WDT3_CONTEXT, RM_ALWON_MDMINTC_CONTEXT, RM_ALWON_SR_CORE_CONTEXT,
+ * RM_ALWON_SR_IVA_CONTEXT, RM_ALWON_SR_MPU_CONTEXT, RM_CAM_FDIF_CONTEXT,
+ * RM_CAM_ISS_CONTEXT, RM_CEFUSE_CEFUSE_CONTEXT, RM_D2D_SAD2D_CONTEXT,
+ * RM_D2D_SAD2D_FW_CONTEXT, RM_DSS_DEISS_CONTEXT, RM_DSS_DSS_CONTEXT,
+ * RM_DUCATI_DUCATI_CONTEXT, RM_EMU_DEBUGSS_CONTEXT, RM_GFX_GFX_CONTEXT,
+ * RM_IVAHD_IVAHD_CONTEXT, RM_IVAHD_SL2_CONTEXT, RM_L3INIT_CCPTX_CONTEXT,
+ * RM_L3INIT_EMAC_CONTEXT, RM_L3INIT_P1500_CONTEXT, RM_L3INIT_PCIESS_CONTEXT,
+ * RM_L3INIT_SATA_CONTEXT, RM_L3INIT_TPPSS_CONTEXT, RM_L3INIT_UNIPRO1_CONTEXT,
+ * RM_L3INIT_USBPHYOCP2SCP_CONTEXT, RM_L3INIT_XHPI_CONTEXT,
+ * RM_L3INSTR_L3_3_CONTEXT, RM_L3INSTR_L3_INSTR_CONTEXT,
+ * RM_L3INSTR_OCP_WP1_CONTEXT, RM_L3_1_L3_1_CONTEXT, RM_L3_2_L3_2_CONTEXT,
+ * RM_L3_2_OCMC_RAM_CONTEXT, RM_L4CFG_L4_CFG_CONTEXT, RM_L4CFG_SAR_ROM_CONTEXT,
+ * RM_L4PER_ADC_CONTEXT, RM_L4PER_DMTIMER10_CONTEXT,
+ * RM_L4PER_DMTIMER11_CONTEXT, RM_L4PER_DMTIMER2_CONTEXT,
+ * RM_L4PER_DMTIMER3_CONTEXT, RM_L4PER_DMTIMER4_CONTEXT,
+ * RM_L4PER_DMTIMER9_CONTEXT, RM_L4PER_ELM_CONTEXT, RM_L4PER_HDQ1W_CONTEXT,
+ * RM_L4PER_HECC1_CONTEXT, RM_L4PER_HECC2_CONTEXT, RM_L4PER_I2C2_CONTEXT,
+ * RM_L4PER_I2C3_CONTEXT, RM_L4PER_I2C4_CONTEXT, RM_L4PER_I2C5_CONTEXT,
+ * RM_L4PER_L4_PER_CONTEXT, RM_L4PER_MCASP2_CONTEXT, RM_L4PER_MCASP3_CONTEXT,
+ * RM_L4PER_MCBSP4_CONTEXT, RM_L4PER_MCSPI1_CONTEXT, RM_L4PER_MCSPI2_CONTEXT,
+ * RM_L4PER_MCSPI3_CONTEXT, RM_L4PER_MCSPI4_CONTEXT, RM_L4PER_MGATE_CONTEXT,
+ * RM_L4PER_MMCSD3_CONTEXT, RM_L4PER_MMCSD4_CONTEXT, RM_L4PER_MMCSD5_CONTEXT,
+ * RM_L4PER_MSPROHG_CONTEXT, RM_L4PER_SLIMBUS2_CONTEXT,
+ * RM_L4SEC_PKAEIP29_CONTEXT, RM_MEMIF_DLL_CONTEXT, RM_MEMIF_DLL_H_CONTEXT,
+ * RM_MEMIF_DMM_CONTEXT, RM_MEMIF_EMIF_1_CONTEXT, RM_MEMIF_EMIF_2_CONTEXT,
+ * RM_MEMIF_EMIF_FW_CONTEXT, RM_MPU_MPU_CONTEXT, RM_TESLA_TESLA_CONTEXT,
+ * RM_WKUP_GPIO1_CONTEXT, RM_WKUP_KEYBOARD_CONTEXT, RM_WKUP_L4WKUP_CONTEXT,
+ * RM_WKUP_RTC_CONTEXT, RM_WKUP_SARRAM_CONTEXT, RM_WKUP_SYNCTIMER_CONTEXT,
+ * RM_WKUP_TIMER12_CONTEXT, RM_WKUP_TIMER1_CONTEXT, RM_WKUP_USIM_CONTEXT,
+ * RM_WKUP_WDT1_CONTEXT, RM_WKUP_WDT2_CONTEXT
*/
#define OMAP4430_LOSTCONTEXT_DFF_SHIFT 0
-#define OMAP4430_LOSTCONTEXT_DFF_MASK BITFIELD(0, 0)
+#define OMAP4430_LOSTCONTEXT_DFF_MASK (1 << 0)
/*
* Used by RM_D2D_MODEM_ICR_CONTEXT, RM_D2D_SAD2D_CONTEXT,
- * RM_D2D_SAD2D_FW_CONTEXT, RM_DUCATI_DUCATI_CONTEXT, RM_L3INSTR_L3_3_CONTEXT,
+ * RM_D2D_SAD2D_FW_CONTEXT, RM_DSS_DSS_CONTEXT, RM_DUCATI_DUCATI_CONTEXT,
+ * RM_L3INIT_HSI_CONTEXT, RM_L3INIT_MMC1_CONTEXT, RM_L3INIT_MMC2_CONTEXT,
+ * RM_L3INIT_MMC6_CONTEXT, RM_L3INIT_USB_HOST_CONTEXT,
+ * RM_L3INIT_USB_HOST_FS_CONTEXT, RM_L3INIT_USB_OTG_CONTEXT,
+ * RM_L3INIT_USB_TLL_CONTEXT, RM_L3INSTR_L3_3_CONTEXT,
* RM_L3INSTR_OCP_WP1_CONTEXT, RM_L3_1_L3_1_CONTEXT, RM_L3_2_GPMC_CONTEXT,
* RM_L3_2_L3_2_CONTEXT, RM_L4CFG_HW_SEM_CONTEXT, RM_L4CFG_L4_CFG_CONTEXT,
- * RM_L4CFG_MAILBOX_CONTEXT, RM_MEMIF_DMM_CONTEXT, RM_MEMIF_EMIF_1_CONTEXT,
- * RM_MEMIF_EMIF_2_CONTEXT, RM_MEMIF_EMIF_FW_CONTEXT, RM_MEMIF_EMIF_H1_CONTEXT,
- * RM_MEMIF_EMIF_H2_CONTEXT, RM_SDMA_SDMA_CONTEXT, RM_L3INIT_HSI_CONTEXT,
- * RM_L3INIT_MMC1_CONTEXT, RM_L3INIT_MMC2_CONTEXT, RM_L3INIT_MMC6_CONTEXT,
- * RM_L3INIT_USB_HOST_CONTEXT, RM_L3INIT_USB_HOST_FS_CONTEXT,
- * RM_L3INIT_USB_OTG_CONTEXT, RM_L3INIT_USB_TLL_CONTEXT, RM_DSS_DSS_CONTEXT,
- * RM_L4PER_GPIO2_CONTEXT, RM_L4PER_GPIO3_CONTEXT, RM_L4PER_GPIO4_CONTEXT,
- * RM_L4PER_GPIO5_CONTEXT, RM_L4PER_GPIO6_CONTEXT, RM_L4PER_I2C1_CONTEXT,
- * RM_L4PER_L4_PER_CONTEXT, RM_L4PER_UART1_CONTEXT, RM_L4PER_UART2_CONTEXT,
- * RM_L4PER_UART3_CONTEXT, RM_L4PER_UART4_CONTEXT, RM_L4SEC_AES1_CONTEXT,
- * RM_L4SEC_AES2_CONTEXT, RM_L4SEC_CRYPTODMA_CONTEXT, RM_L4SEC_DES3DES_CONTEXT,
- * RM_L4SEC_RNG_CONTEXT, RM_L4SEC_SHA2MD51_CONTEXT, RM_TESLA_TESLA_CONTEXT
+ * RM_L4CFG_MAILBOX_CONTEXT, RM_L4PER_GPIO2_CONTEXT, RM_L4PER_GPIO3_CONTEXT,
+ * RM_L4PER_GPIO4_CONTEXT, RM_L4PER_GPIO5_CONTEXT, RM_L4PER_GPIO6_CONTEXT,
+ * RM_L4PER_I2C1_CONTEXT, RM_L4PER_L4_PER_CONTEXT, RM_L4PER_UART1_CONTEXT,
+ * RM_L4PER_UART2_CONTEXT, RM_L4PER_UART3_CONTEXT, RM_L4PER_UART4_CONTEXT,
+ * RM_L4SEC_AES1_CONTEXT, RM_L4SEC_AES2_CONTEXT, RM_L4SEC_CRYPTODMA_CONTEXT,
+ * RM_L4SEC_DES3DES_CONTEXT, RM_L4SEC_RNG_CONTEXT, RM_L4SEC_SHA2MD51_CONTEXT,
+ * RM_MEMIF_DMM_CONTEXT, RM_MEMIF_EMIF_1_CONTEXT, RM_MEMIF_EMIF_2_CONTEXT,
+ * RM_MEMIF_EMIF_FW_CONTEXT, RM_MEMIF_EMIF_H1_CONTEXT,
+ * RM_MEMIF_EMIF_H2_CONTEXT, RM_SDMA_SDMA_CONTEXT, RM_TESLA_TESLA_CONTEXT
*/
#define OMAP4430_LOSTCONTEXT_RFF_SHIFT 1
-#define OMAP4430_LOSTCONTEXT_RFF_MASK BITFIELD(1, 1)
+#define OMAP4430_LOSTCONTEXT_RFF_MASK (1 << 1)
/* Used by RM_ABE_AESS_CONTEXT */
#define OMAP4430_LOSTMEM_AESSMEM_SHIFT 8
-#define OMAP4430_LOSTMEM_AESSMEM_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_AESSMEM_MASK (1 << 8)
/* Used by RM_CAM_FDIF_CONTEXT, RM_CAM_ISS_CONTEXT */
#define OMAP4430_LOSTMEM_CAM_MEM_SHIFT 8
-#define OMAP4430_LOSTMEM_CAM_MEM_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_CAM_MEM_MASK (1 << 8)
/* Used by RM_L3INSTR_OCP_WP1_CONTEXT */
#define OMAP4430_LOSTMEM_CORE_NRET_BANK_SHIFT 8
-#define OMAP4430_LOSTMEM_CORE_NRET_BANK_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_CORE_NRET_BANK_MASK (1 << 8)
/* Renamed from LOSTMEM_CORE_NRET_BANK Used by RM_MEMIF_DMM_CONTEXT */
#define OMAP4430_LOSTMEM_CORE_NRET_BANK_9_9_SHIFT 9
-#define OMAP4430_LOSTMEM_CORE_NRET_BANK_9_9_MASK BITFIELD(9, 9)
+#define OMAP4430_LOSTMEM_CORE_NRET_BANK_9_9_MASK (1 << 9)
/* Used by RM_L3_2_OCMC_RAM_CONTEXT */
#define OMAP4430_LOSTMEM_CORE_OCMRAM_SHIFT 8
-#define OMAP4430_LOSTMEM_CORE_OCMRAM_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_CORE_OCMRAM_MASK (1 << 8)
/*
* Used by RM_D2D_MODEM_ICR_CONTEXT, RM_MEMIF_DMM_CONTEXT,
* RM_SDMA_SDMA_CONTEXT
*/
#define OMAP4430_LOSTMEM_CORE_OTHER_BANK_SHIFT 8
-#define OMAP4430_LOSTMEM_CORE_OTHER_BANK_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_CORE_OTHER_BANK_MASK (1 << 8)
/* Used by RM_DSS_DEISS_CONTEXT, RM_DSS_DSS_CONTEXT */
#define OMAP4430_LOSTMEM_DSS_MEM_SHIFT 8
-#define OMAP4430_LOSTMEM_DSS_MEM_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_DSS_MEM_MASK (1 << 8)
/* Used by RM_DUCATI_DUCATI_CONTEXT */
#define OMAP4430_LOSTMEM_DUCATI_L2RAM_SHIFT 9
-#define OMAP4430_LOSTMEM_DUCATI_L2RAM_MASK BITFIELD(9, 9)
+#define OMAP4430_LOSTMEM_DUCATI_L2RAM_MASK (1 << 9)
/* Used by RM_DUCATI_DUCATI_CONTEXT */
#define OMAP4430_LOSTMEM_DUCATI_UNICACHE_SHIFT 8
-#define OMAP4430_LOSTMEM_DUCATI_UNICACHE_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_DUCATI_UNICACHE_MASK (1 << 8)
/* Used by RM_EMU_DEBUGSS_CONTEXT */
#define OMAP4430_LOSTMEM_EMU_BANK_SHIFT 8
-#define OMAP4430_LOSTMEM_EMU_BANK_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_EMU_BANK_MASK (1 << 8)
/* Used by RM_GFX_GFX_CONTEXT */
#define OMAP4430_LOSTMEM_GFX_MEM_SHIFT 8
-#define OMAP4430_LOSTMEM_GFX_MEM_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_GFX_MEM_MASK (1 << 8)
/* Used by RM_IVAHD_IVAHD_CONTEXT */
#define OMAP4430_LOSTMEM_HWA_MEM_SHIFT 10
-#define OMAP4430_LOSTMEM_HWA_MEM_MASK BITFIELD(10, 10)
+#define OMAP4430_LOSTMEM_HWA_MEM_MASK (1 << 10)
/*
* Used by RM_L3INIT_CCPTX_CONTEXT, RM_L3INIT_EMAC_CONTEXT,
@@ -620,19 +644,19 @@
* RM_L3INIT_USB_OTG_CONTEXT, RM_L3INIT_XHPI_CONTEXT
*/
#define OMAP4430_LOSTMEM_L3INIT_BANK1_SHIFT 8
-#define OMAP4430_LOSTMEM_L3INIT_BANK1_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_L3INIT_BANK1_MASK (1 << 8)
/* Used by RM_MPU_MPU_CONTEXT */
#define OMAP4430_LOSTMEM_MPU_L1_SHIFT 8
-#define OMAP4430_LOSTMEM_MPU_L1_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_MPU_L1_MASK (1 << 8)
/* Used by RM_MPU_MPU_CONTEXT */
#define OMAP4430_LOSTMEM_MPU_L2_SHIFT 9
-#define OMAP4430_LOSTMEM_MPU_L2_MASK BITFIELD(9, 9)
+#define OMAP4430_LOSTMEM_MPU_L2_MASK (1 << 9)
/* Used by RM_MPU_MPU_CONTEXT */
#define OMAP4430_LOSTMEM_MPU_RAM_SHIFT 10
-#define OMAP4430_LOSTMEM_MPU_RAM_MASK BITFIELD(10, 10)
+#define OMAP4430_LOSTMEM_MPU_RAM_MASK (1 << 10)
/*
* Used by RM_L4PER_HECC1_CONTEXT, RM_L4PER_HECC2_CONTEXT,
@@ -640,14 +664,14 @@
* RM_L4PER_MMCSD5_CONTEXT, RM_L4PER_SLIMBUS2_CONTEXT, RM_L4SEC_PKAEIP29_CONTEXT
*/
#define OMAP4430_LOSTMEM_NONRETAINED_BANK_SHIFT 8
-#define OMAP4430_LOSTMEM_NONRETAINED_BANK_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_NONRETAINED_BANK_MASK (1 << 8)
/*
* Used by RM_ABE_DMIC_CONTEXT, RM_ABE_MCBSP1_CONTEXT, RM_ABE_MCBSP2_CONTEXT,
* RM_ABE_MCBSP3_CONTEXT, RM_ABE_PDM_CONTEXT, RM_ABE_SLIMBUS_CONTEXT
*/
#define OMAP4430_LOSTMEM_PERIHPMEM_SHIFT 8
-#define OMAP4430_LOSTMEM_PERIHPMEM_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_PERIHPMEM_MASK (1 << 8)
/*
* Used by RM_L4PER_MSPROHG_CONTEXT, RM_L4PER_UART1_CONTEXT,
@@ -655,245 +679,237 @@
* RM_L4SEC_CRYPTODMA_CONTEXT
*/
#define OMAP4430_LOSTMEM_RETAINED_BANK_SHIFT 8
-#define OMAP4430_LOSTMEM_RETAINED_BANK_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_RETAINED_BANK_MASK (1 << 8)
/* Used by RM_IVAHD_SL2_CONTEXT */
#define OMAP4430_LOSTMEM_SL2_MEM_SHIFT 8
-#define OMAP4430_LOSTMEM_SL2_MEM_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_SL2_MEM_MASK (1 << 8)
/* Used by RM_IVAHD_IVAHD_CONTEXT */
#define OMAP4430_LOSTMEM_TCM1_MEM_SHIFT 8
-#define OMAP4430_LOSTMEM_TCM1_MEM_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_TCM1_MEM_MASK (1 << 8)
/* Used by RM_IVAHD_IVAHD_CONTEXT */
#define OMAP4430_LOSTMEM_TCM2_MEM_SHIFT 9
-#define OMAP4430_LOSTMEM_TCM2_MEM_MASK BITFIELD(9, 9)
+#define OMAP4430_LOSTMEM_TCM2_MEM_MASK (1 << 9)
/* Used by RM_TESLA_TESLA_CONTEXT */
#define OMAP4430_LOSTMEM_TESLA_EDMA_SHIFT 10
-#define OMAP4430_LOSTMEM_TESLA_EDMA_MASK BITFIELD(10, 10)
+#define OMAP4430_LOSTMEM_TESLA_EDMA_MASK (1 << 10)
/* Used by RM_TESLA_TESLA_CONTEXT */
#define OMAP4430_LOSTMEM_TESLA_L1_SHIFT 8
-#define OMAP4430_LOSTMEM_TESLA_L1_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_TESLA_L1_MASK (1 << 8)
/* Used by RM_TESLA_TESLA_CONTEXT */
#define OMAP4430_LOSTMEM_TESLA_L2_SHIFT 9
-#define OMAP4430_LOSTMEM_TESLA_L2_MASK BITFIELD(9, 9)
+#define OMAP4430_LOSTMEM_TESLA_L2_MASK (1 << 9)
/* Used by RM_WKUP_SARRAM_CONTEXT */
#define OMAP4430_LOSTMEM_WKUP_BANK_SHIFT 8
-#define OMAP4430_LOSTMEM_WKUP_BANK_MASK BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_WKUP_BANK_MASK (1 << 8)
/*
- * Used by PM_CORE_PWRSTCTRL, PM_CAM_PWRSTCTRL, PM_L3INIT_PWRSTCTRL,
- * PM_ABE_PWRSTCTRL, PM_GFX_PWRSTCTRL, PM_MPU_PWRSTCTRL, PM_CEFUSE_PWRSTCTRL,
- * PM_DSS_PWRSTCTRL, PM_L4PER_PWRSTCTRL, PM_TESLA_PWRSTCTRL, PM_IVAHD_PWRSTCTRL
+ * Used by PM_ABE_PWRSTCTRL, PM_CAM_PWRSTCTRL, PM_CEFUSE_PWRSTCTRL,
+ * PM_CORE_PWRSTCTRL, PM_DSS_PWRSTCTRL, PM_GFX_PWRSTCTRL, PM_IVAHD_PWRSTCTRL,
+ * PM_L3INIT_PWRSTCTRL, PM_L4PER_PWRSTCTRL, PM_MPU_PWRSTCTRL, PM_TESLA_PWRSTCTRL
*/
#define OMAP4430_LOWPOWERSTATECHANGE_SHIFT 4
-#define OMAP4430_LOWPOWERSTATECHANGE_MASK BITFIELD(4, 4)
-
-/* Used by PM_CORE_PWRSTCTRL */
-#define OMAP4430_MEMORYCHANGE_SHIFT 3
-#define OMAP4430_MEMORYCHANGE_MASK BITFIELD(3, 3)
+#define OMAP4430_LOWPOWERSTATECHANGE_MASK (1 << 4)
/* Used by PRM_MODEM_IF_CTRL */
#define OMAP4430_MODEM_READY_SHIFT 1
-#define OMAP4430_MODEM_READY_MASK BITFIELD(1, 1)
+#define OMAP4430_MODEM_READY_MASK (1 << 1)
/* Used by PRM_MODEM_IF_CTRL */
#define OMAP4430_MODEM_SHUTDOWN_IRQ_SHIFT 9
-#define OMAP4430_MODEM_SHUTDOWN_IRQ_MASK BITFIELD(9, 9)
+#define OMAP4430_MODEM_SHUTDOWN_IRQ_MASK (1 << 9)
/* Used by PRM_MODEM_IF_CTRL */
#define OMAP4430_MODEM_SLEEP_ST_SHIFT 16
-#define OMAP4430_MODEM_SLEEP_ST_MASK BITFIELD(16, 16)
+#define OMAP4430_MODEM_SLEEP_ST_MASK (1 << 16)
/* Used by PRM_MODEM_IF_CTRL */
#define OMAP4430_MODEM_WAKE_IRQ_SHIFT 8
-#define OMAP4430_MODEM_WAKE_IRQ_MASK BITFIELD(8, 8)
+#define OMAP4430_MODEM_WAKE_IRQ_MASK (1 << 8)
/* Used by PM_MPU_PWRSTCTRL */
#define OMAP4430_MPU_L1_ONSTATE_SHIFT 16
-#define OMAP4430_MPU_L1_ONSTATE_MASK BITFIELD(16, 17)
+#define OMAP4430_MPU_L1_ONSTATE_MASK (0x3 << 16)
/* Used by PM_MPU_PWRSTCTRL */
#define OMAP4430_MPU_L1_RETSTATE_SHIFT 8
-#define OMAP4430_MPU_L1_RETSTATE_MASK BITFIELD(8, 8)
+#define OMAP4430_MPU_L1_RETSTATE_MASK (1 << 8)
/* Used by PM_MPU_PWRSTST */
#define OMAP4430_MPU_L1_STATEST_SHIFT 4
-#define OMAP4430_MPU_L1_STATEST_MASK BITFIELD(4, 5)
+#define OMAP4430_MPU_L1_STATEST_MASK (0x3 << 4)
/* Used by PM_MPU_PWRSTCTRL */
#define OMAP4430_MPU_L2_ONSTATE_SHIFT 18
-#define OMAP4430_MPU_L2_ONSTATE_MASK BITFIELD(18, 19)
+#define OMAP4430_MPU_L2_ONSTATE_MASK (0x3 << 18)
/* Used by PM_MPU_PWRSTCTRL */
#define OMAP4430_MPU_L2_RETSTATE_SHIFT 9
-#define OMAP4430_MPU_L2_RETSTATE_MASK BITFIELD(9, 9)
+#define OMAP4430_MPU_L2_RETSTATE_MASK (1 << 9)
/* Used by PM_MPU_PWRSTST */
#define OMAP4430_MPU_L2_STATEST_SHIFT 6
-#define OMAP4430_MPU_L2_STATEST_MASK BITFIELD(6, 7)
+#define OMAP4430_MPU_L2_STATEST_MASK (0x3 << 6)
/* Used by PM_MPU_PWRSTCTRL */
#define OMAP4430_MPU_RAM_ONSTATE_SHIFT 20
-#define OMAP4430_MPU_RAM_ONSTATE_MASK BITFIELD(20, 21)
+#define OMAP4430_MPU_RAM_ONSTATE_MASK (0x3 << 20)
/* Used by PM_MPU_PWRSTCTRL */
#define OMAP4430_MPU_RAM_RETSTATE_SHIFT 10
-#define OMAP4430_MPU_RAM_RETSTATE_MASK BITFIELD(10, 10)
+#define OMAP4430_MPU_RAM_RETSTATE_MASK (1 << 10)
/* Used by PM_MPU_PWRSTST */
#define OMAP4430_MPU_RAM_STATEST_SHIFT 8
-#define OMAP4430_MPU_RAM_STATEST_MASK BITFIELD(8, 9)
+#define OMAP4430_MPU_RAM_STATEST_MASK (0x3 << 8)
/* Used by PRM_RSTST */
#define OMAP4430_MPU_SECURITY_VIOL_RST_SHIFT 2
-#define OMAP4430_MPU_SECURITY_VIOL_RST_MASK BITFIELD(2, 2)
+#define OMAP4430_MPU_SECURITY_VIOL_RST_MASK (1 << 2)
/* Used by PRM_RSTST */
#define OMAP4430_MPU_WDT_RST_SHIFT 3
-#define OMAP4430_MPU_WDT_RST_MASK BITFIELD(3, 3)
+#define OMAP4430_MPU_WDT_RST_MASK (1 << 3)
/* Used by PM_L4PER_PWRSTCTRL */
#define OMAP4430_NONRETAINED_BANK_ONSTATE_SHIFT 18
-#define OMAP4430_NONRETAINED_BANK_ONSTATE_MASK BITFIELD(18, 19)
+#define OMAP4430_NONRETAINED_BANK_ONSTATE_MASK (0x3 << 18)
/* Used by PM_L4PER_PWRSTCTRL */
#define OMAP4430_NONRETAINED_BANK_RETSTATE_SHIFT 9
-#define OMAP4430_NONRETAINED_BANK_RETSTATE_MASK BITFIELD(9, 9)
+#define OMAP4430_NONRETAINED_BANK_RETSTATE_MASK (1 << 9)
/* Used by PM_L4PER_PWRSTST */
#define OMAP4430_NONRETAINED_BANK_STATEST_SHIFT 6
-#define OMAP4430_NONRETAINED_BANK_STATEST_MASK BITFIELD(6, 7)
+#define OMAP4430_NONRETAINED_BANK_STATEST_MASK (0x3 << 6)
/* Used by PM_CORE_PWRSTCTRL */
#define OMAP4430_OCP_NRET_BANK_ONSTATE_SHIFT 24
-#define OMAP4430_OCP_NRET_BANK_ONSTATE_MASK BITFIELD(24, 25)
+#define OMAP4430_OCP_NRET_BANK_ONSTATE_MASK (0x3 << 24)
/* Used by PM_CORE_PWRSTCTRL */
#define OMAP4430_OCP_NRET_BANK_RETSTATE_SHIFT 12
-#define OMAP4430_OCP_NRET_BANK_RETSTATE_MASK BITFIELD(12, 12)
+#define OMAP4430_OCP_NRET_BANK_RETSTATE_MASK (1 << 12)
/* Used by PM_CORE_PWRSTST */
#define OMAP4430_OCP_NRET_BANK_STATEST_SHIFT 12
-#define OMAP4430_OCP_NRET_BANK_STATEST_MASK BITFIELD(12, 13)
+#define OMAP4430_OCP_NRET_BANK_STATEST_MASK (0x3 << 12)
/*
* Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L,
* PRM_VC_VAL_CMD_VDD_MPU_L
*/
#define OMAP4430_OFF_SHIFT 0
-#define OMAP4430_OFF_MASK BITFIELD(0, 7)
-
-/* Used by PRM_LDO_BANDGAP_CTRL */
-#define OMAP4430_OFF_ENABLE_SHIFT 0
-#define OMAP4430_OFF_ENABLE_MASK BITFIELD(0, 0)
+#define OMAP4430_OFF_MASK (0xff << 0)
/*
* Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L,
* PRM_VC_VAL_CMD_VDD_MPU_L
*/
#define OMAP4430_ON_SHIFT 24
-#define OMAP4430_ON_MASK BITFIELD(24, 31)
+#define OMAP4430_ON_MASK (0xff << 24)
/*
* Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L,
* PRM_VC_VAL_CMD_VDD_MPU_L
*/
#define OMAP4430_ONLP_SHIFT 16
-#define OMAP4430_ONLP_MASK BITFIELD(16, 23)
+#define OMAP4430_ONLP_MASK (0xff << 16)
/* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */
#define OMAP4430_OPP_CHANGE_SHIFT 2
-#define OMAP4430_OPP_CHANGE_MASK BITFIELD(2, 2)
+#define OMAP4430_OPP_CHANGE_MASK (1 << 2)
/* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */
#define OMAP4430_OPP_SEL_SHIFT 0
-#define OMAP4430_OPP_SEL_MASK BITFIELD(0, 1)
+#define OMAP4430_OPP_SEL_MASK (0x3 << 0)
/* Used by PRM_SRAM_COUNT */
#define OMAP4430_PCHARGECNT_VALUE_SHIFT 0
-#define OMAP4430_PCHARGECNT_VALUE_MASK BITFIELD(0, 5)
+#define OMAP4430_PCHARGECNT_VALUE_MASK (0x3f << 0)
/* Used by PRM_PSCON_COUNT */
#define OMAP4430_PCHARGE_TIME_SHIFT 0
-#define OMAP4430_PCHARGE_TIME_MASK BITFIELD(0, 7)
+#define OMAP4430_PCHARGE_TIME_MASK (0xff << 0)
/* Used by PM_ABE_PWRSTCTRL */
#define OMAP4430_PERIPHMEM_ONSTATE_SHIFT 20
-#define OMAP4430_PERIPHMEM_ONSTATE_MASK BITFIELD(20, 21)
+#define OMAP4430_PERIPHMEM_ONSTATE_MASK (0x3 << 20)
/* Used by PM_ABE_PWRSTCTRL */
#define OMAP4430_PERIPHMEM_RETSTATE_SHIFT 10
-#define OMAP4430_PERIPHMEM_RETSTATE_MASK BITFIELD(10, 10)
+#define OMAP4430_PERIPHMEM_RETSTATE_MASK (1 << 10)
/* Used by PM_ABE_PWRSTST */
#define OMAP4430_PERIPHMEM_STATEST_SHIFT 8
-#define OMAP4430_PERIPHMEM_STATEST_MASK BITFIELD(8, 9)
+#define OMAP4430_PERIPHMEM_STATEST_MASK (0x3 << 8)
/* Used by PRM_PHASE1_CNDP */
#define OMAP4430_PHASE1_CNDP_SHIFT 0
-#define OMAP4430_PHASE1_CNDP_MASK BITFIELD(0, 31)
+#define OMAP4430_PHASE1_CNDP_MASK (0xffffffff << 0)
/* Used by PRM_PHASE2A_CNDP */
#define OMAP4430_PHASE2A_CNDP_SHIFT 0
-#define OMAP4430_PHASE2A_CNDP_MASK BITFIELD(0, 31)
+#define OMAP4430_PHASE2A_CNDP_MASK (0xffffffff << 0)
/* Used by PRM_PHASE2B_CNDP */
#define OMAP4430_PHASE2B_CNDP_SHIFT 0
-#define OMAP4430_PHASE2B_CNDP_MASK BITFIELD(0, 31)
+#define OMAP4430_PHASE2B_CNDP_MASK (0xffffffff << 0)
/* Used by PRM_PSCON_COUNT */
#define OMAP4430_PONOUT_2_PGOODIN_TIME_SHIFT 8
-#define OMAP4430_PONOUT_2_PGOODIN_TIME_MASK BITFIELD(8, 15)
+#define OMAP4430_PONOUT_2_PGOODIN_TIME_MASK (0xff << 8)
/*
- * Used by PM_EMU_PWRSTCTRL, PM_CORE_PWRSTCTRL, PM_CAM_PWRSTCTRL,
- * PM_L3INIT_PWRSTCTRL, PM_ABE_PWRSTCTRL, PM_GFX_PWRSTCTRL, PM_MPU_PWRSTCTRL,
- * PM_CEFUSE_PWRSTCTRL, PM_DSS_PWRSTCTRL, PM_L4PER_PWRSTCTRL,
- * PM_TESLA_PWRSTCTRL, PM_IVAHD_PWRSTCTRL
+ * Used by PM_ABE_PWRSTCTRL, PM_CAM_PWRSTCTRL, PM_CEFUSE_PWRSTCTRL,
+ * PM_CORE_PWRSTCTRL, PM_DSS_PWRSTCTRL, PM_EMU_PWRSTCTRL, PM_GFX_PWRSTCTRL,
+ * PM_IVAHD_PWRSTCTRL, PM_L3INIT_PWRSTCTRL, PM_L4PER_PWRSTCTRL,
+ * PM_MPU_PWRSTCTRL, PM_TESLA_PWRSTCTRL
*/
#define OMAP4430_POWERSTATE_SHIFT 0
-#define OMAP4430_POWERSTATE_MASK BITFIELD(0, 1)
+#define OMAP4430_POWERSTATE_MASK (0x3 << 0)
/*
- * Used by PM_EMU_PWRSTST, PM_CORE_PWRSTST, PM_CAM_PWRSTST, PM_L3INIT_PWRSTST,
- * PM_ABE_PWRSTST, PM_GFX_PWRSTST, PM_MPU_PWRSTST, PM_CEFUSE_PWRSTST,
- * PM_DSS_PWRSTST, PM_L4PER_PWRSTST, PM_TESLA_PWRSTST, PM_IVAHD_PWRSTST
+ * Used by PM_ABE_PWRSTST, PM_CAM_PWRSTST, PM_CEFUSE_PWRSTST, PM_CORE_PWRSTST,
+ * PM_DSS_PWRSTST, PM_EMU_PWRSTST, PM_GFX_PWRSTST, PM_IVAHD_PWRSTST,
+ * PM_L3INIT_PWRSTST, PM_L4PER_PWRSTST, PM_MPU_PWRSTST, PM_TESLA_PWRSTST
*/
#define OMAP4430_POWERSTATEST_SHIFT 0
-#define OMAP4430_POWERSTATEST_MASK BITFIELD(0, 1)
+#define OMAP4430_POWERSTATEST_MASK (0x3 << 0)
/* Used by PRM_PWRREQCTRL */
#define OMAP4430_PWRREQ_COND_SHIFT 0
-#define OMAP4430_PWRREQ_COND_MASK BITFIELD(0, 1)
+#define OMAP4430_PWRREQ_COND_MASK (0x3 << 0)
/* Used by PRM_VC_CFG_CHANNEL */
#define OMAP4430_RACEN_VDD_CORE_L_SHIFT 3
-#define OMAP4430_RACEN_VDD_CORE_L_MASK BITFIELD(3, 3)
+#define OMAP4430_RACEN_VDD_CORE_L_MASK (1 << 3)
/* Used by PRM_VC_CFG_CHANNEL */
#define OMAP4430_RACEN_VDD_IVA_L_SHIFT 11
-#define OMAP4430_RACEN_VDD_IVA_L_MASK BITFIELD(11, 11)
+#define OMAP4430_RACEN_VDD_IVA_L_MASK (1 << 11)
/* Used by PRM_VC_CFG_CHANNEL */
#define OMAP4430_RACEN_VDD_MPU_L_SHIFT 20
-#define OMAP4430_RACEN_VDD_MPU_L_MASK BITFIELD(20, 20)
+#define OMAP4430_RACEN_VDD_MPU_L_MASK (1 << 20)
/* Used by PRM_VC_CFG_CHANNEL */
#define OMAP4430_RAC_VDD_CORE_L_SHIFT 2
-#define OMAP4430_RAC_VDD_CORE_L_MASK BITFIELD(2, 2)
+#define OMAP4430_RAC_VDD_CORE_L_MASK (1 << 2)
/* Used by PRM_VC_CFG_CHANNEL */
#define OMAP4430_RAC_VDD_IVA_L_SHIFT 10
-#define OMAP4430_RAC_VDD_IVA_L_MASK BITFIELD(10, 10)
+#define OMAP4430_RAC_VDD_IVA_L_MASK (1 << 10)
/* Used by PRM_VC_CFG_CHANNEL */
#define OMAP4430_RAC_VDD_MPU_L_SHIFT 19
-#define OMAP4430_RAC_VDD_MPU_L_MASK BITFIELD(19, 19)
+#define OMAP4430_RAC_VDD_MPU_L_MASK (1 << 19)
/*
* Used by PRM_VOLTSETUP_CORE_OFF, PRM_VOLTSETUP_CORE_RET_SLEEP,
@@ -901,7 +917,7 @@
* PRM_VOLTSETUP_MPU_RET_SLEEP
*/
#define OMAP4430_RAMP_DOWN_COUNT_SHIFT 16
-#define OMAP4430_RAMP_DOWN_COUNT_MASK BITFIELD(16, 21)
+#define OMAP4430_RAMP_DOWN_COUNT_MASK (0x3f << 16)
/*
* Used by PRM_VOLTSETUP_CORE_OFF, PRM_VOLTSETUP_CORE_RET_SLEEP,
@@ -909,7 +925,7 @@
* PRM_VOLTSETUP_MPU_RET_SLEEP
*/
#define OMAP4430_RAMP_DOWN_PRESCAL_SHIFT 24
-#define OMAP4430_RAMP_DOWN_PRESCAL_MASK BITFIELD(24, 25)
+#define OMAP4430_RAMP_DOWN_PRESCAL_MASK (0x3 << 24)
/*
* Used by PRM_VOLTSETUP_CORE_OFF, PRM_VOLTSETUP_CORE_RET_SLEEP,
@@ -917,7 +933,7 @@
* PRM_VOLTSETUP_MPU_RET_SLEEP
*/
#define OMAP4430_RAMP_UP_COUNT_SHIFT 0
-#define OMAP4430_RAMP_UP_COUNT_MASK BITFIELD(0, 5)
+#define OMAP4430_RAMP_UP_COUNT_MASK (0x3f << 0)
/*
* Used by PRM_VOLTSETUP_CORE_OFF, PRM_VOLTSETUP_CORE_RET_SLEEP,
@@ -925,1281 +941,1381 @@
* PRM_VOLTSETUP_MPU_RET_SLEEP
*/
#define OMAP4430_RAMP_UP_PRESCAL_SHIFT 8
-#define OMAP4430_RAMP_UP_PRESCAL_MASK BITFIELD(8, 9)
+#define OMAP4430_RAMP_UP_PRESCAL_MASK (0x3 << 8)
/* Used by PRM_VC_CFG_CHANNEL */
#define OMAP4430_RAV_VDD_CORE_L_SHIFT 1
-#define OMAP4430_RAV_VDD_CORE_L_MASK BITFIELD(1, 1)
+#define OMAP4430_RAV_VDD_CORE_L_MASK (1 << 1)
/* Used by PRM_VC_CFG_CHANNEL */
#define OMAP4430_RAV_VDD_IVA_L_SHIFT 9
-#define OMAP4430_RAV_VDD_IVA_L_MASK BITFIELD(9, 9)
+#define OMAP4430_RAV_VDD_IVA_L_MASK (1 << 9)
/* Used by PRM_VC_CFG_CHANNEL */
#define OMAP4430_RAV_VDD_MPU_L_SHIFT 18
-#define OMAP4430_RAV_VDD_MPU_L_MASK BITFIELD(18, 18)
+#define OMAP4430_RAV_VDD_MPU_L_MASK (1 << 18)
/* Used by PRM_VC_VAL_BYPASS */
#define OMAP4430_REGADDR_SHIFT 8
-#define OMAP4430_REGADDR_MASK BITFIELD(8, 15)
+#define OMAP4430_REGADDR_MASK (0xff << 8)
/*
* Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L,
* PRM_VC_VAL_CMD_VDD_MPU_L
*/
#define OMAP4430_RET_SHIFT 8
-#define OMAP4430_RET_MASK BITFIELD(8, 15)
+#define OMAP4430_RET_MASK (0xff << 8)
/* Used by PM_L4PER_PWRSTCTRL */
#define OMAP4430_RETAINED_BANK_ONSTATE_SHIFT 16
-#define OMAP4430_RETAINED_BANK_ONSTATE_MASK BITFIELD(16, 17)
+#define OMAP4430_RETAINED_BANK_ONSTATE_MASK (0x3 << 16)
/* Used by PM_L4PER_PWRSTCTRL */
#define OMAP4430_RETAINED_BANK_RETSTATE_SHIFT 8
-#define OMAP4430_RETAINED_BANK_RETSTATE_MASK BITFIELD(8, 8)
+#define OMAP4430_RETAINED_BANK_RETSTATE_MASK (1 << 8)
/* Used by PM_L4PER_PWRSTST */
#define OMAP4430_RETAINED_BANK_STATEST_SHIFT 4
-#define OMAP4430_RETAINED_BANK_STATEST_MASK BITFIELD(4, 5)
+#define OMAP4430_RETAINED_BANK_STATEST_MASK (0x3 << 4)
/*
* Used by PRM_LDO_SRAM_CORE_CTRL, PRM_LDO_SRAM_IVA_CTRL,
* PRM_LDO_SRAM_MPU_CTRL
*/
#define OMAP4430_RETMODE_ENABLE_SHIFT 0
-#define OMAP4430_RETMODE_ENABLE_MASK BITFIELD(0, 0)
+#define OMAP4430_RETMODE_ENABLE_MASK (1 << 0)
-/* Used by REVISION_PRM */
-#define OMAP4430_REV_SHIFT 0
-#define OMAP4430_REV_MASK BITFIELD(0, 7)
-
-/* Used by RM_DUCATI_RSTCTRL, RM_TESLA_RSTCTRL, RM_IVAHD_RSTCTRL */
+/* Used by RM_DUCATI_RSTCTRL, RM_IVAHD_RSTCTRL, RM_TESLA_RSTCTRL */
#define OMAP4430_RST1_SHIFT 0
-#define OMAP4430_RST1_MASK BITFIELD(0, 0)
+#define OMAP4430_RST1_MASK (1 << 0)
-/* Used by RM_DUCATI_RSTST, RM_TESLA_RSTST, RM_IVAHD_RSTST */
+/* Used by RM_DUCATI_RSTST, RM_IVAHD_RSTST, RM_TESLA_RSTST */
#define OMAP4430_RST1ST_SHIFT 0
-#define OMAP4430_RST1ST_MASK BITFIELD(0, 0)
+#define OMAP4430_RST1ST_MASK (1 << 0)
-/* Used by RM_DUCATI_RSTCTRL, RM_TESLA_RSTCTRL, RM_IVAHD_RSTCTRL */
+/* Used by RM_DUCATI_RSTCTRL, RM_IVAHD_RSTCTRL, RM_TESLA_RSTCTRL */
#define OMAP4430_RST2_SHIFT 1
-#define OMAP4430_RST2_MASK BITFIELD(1, 1)
+#define OMAP4430_RST2_MASK (1 << 1)
-/* Used by RM_DUCATI_RSTST, RM_TESLA_RSTST, RM_IVAHD_RSTST */
+/* Used by RM_DUCATI_RSTST, RM_IVAHD_RSTST, RM_TESLA_RSTST */
#define OMAP4430_RST2ST_SHIFT 1
-#define OMAP4430_RST2ST_MASK BITFIELD(1, 1)
+#define OMAP4430_RST2ST_MASK (1 << 1)
/* Used by RM_DUCATI_RSTCTRL, RM_IVAHD_RSTCTRL */
#define OMAP4430_RST3_SHIFT 2
-#define OMAP4430_RST3_MASK BITFIELD(2, 2)
+#define OMAP4430_RST3_MASK (1 << 2)
/* Used by RM_DUCATI_RSTST, RM_IVAHD_RSTST */
#define OMAP4430_RST3ST_SHIFT 2
-#define OMAP4430_RST3ST_MASK BITFIELD(2, 2)
+#define OMAP4430_RST3ST_MASK (1 << 2)
/* Used by PRM_RSTTIME */
#define OMAP4430_RSTTIME1_SHIFT 0
-#define OMAP4430_RSTTIME1_MASK BITFIELD(0, 9)
+#define OMAP4430_RSTTIME1_MASK (0x3ff << 0)
/* Used by PRM_RSTTIME */
#define OMAP4430_RSTTIME2_SHIFT 10
-#define OMAP4430_RSTTIME2_MASK BITFIELD(10, 14)
+#define OMAP4430_RSTTIME2_MASK (0x1f << 10)
/* Used by PRM_RSTCTRL */
#define OMAP4430_RST_GLOBAL_COLD_SW_SHIFT 1
-#define OMAP4430_RST_GLOBAL_COLD_SW_MASK BITFIELD(1, 1)
+#define OMAP4430_RST_GLOBAL_COLD_SW_MASK (1 << 1)
/* Used by PRM_RSTCTRL */
#define OMAP4430_RST_GLOBAL_WARM_SW_SHIFT 0
-#define OMAP4430_RST_GLOBAL_WARM_SW_MASK BITFIELD(0, 0)
+#define OMAP4430_RST_GLOBAL_WARM_SW_MASK (1 << 0)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_R_RTL_SHIFT 11
+#define OMAP4430_R_RTL_MASK (0x1f << 11)
/* Used by PRM_VC_CFG_CHANNEL */
#define OMAP4430_SA_VDD_CORE_L_SHIFT 0
-#define OMAP4430_SA_VDD_CORE_L_MASK BITFIELD(0, 0)
+#define OMAP4430_SA_VDD_CORE_L_MASK (1 << 0)
/* Renamed from SA_VDD_CORE_L Used by PRM_VC_SMPS_SA */
#define OMAP4430_SA_VDD_CORE_L_0_6_SHIFT 0
-#define OMAP4430_SA_VDD_CORE_L_0_6_MASK BITFIELD(0, 6)
+#define OMAP4430_SA_VDD_CORE_L_0_6_MASK (0x7f << 0)
/* Used by PRM_VC_CFG_CHANNEL */
#define OMAP4430_SA_VDD_IVA_L_SHIFT 8
-#define OMAP4430_SA_VDD_IVA_L_MASK BITFIELD(8, 8)
+#define OMAP4430_SA_VDD_IVA_L_MASK (1 << 8)
/* Renamed from SA_VDD_IVA_L Used by PRM_VC_SMPS_SA */
#define OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_SHIFT 8
-#define OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_MASK BITFIELD(8, 14)
+#define OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_MASK (0x7f << 8)
/* Used by PRM_VC_CFG_CHANNEL */
#define OMAP4430_SA_VDD_MPU_L_SHIFT 16
-#define OMAP4430_SA_VDD_MPU_L_MASK BITFIELD(16, 16)
+#define OMAP4430_SA_VDD_MPU_L_MASK (1 << 16)
/* Renamed from SA_VDD_MPU_L Used by PRM_VC_SMPS_SA */
#define OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_SHIFT 16
-#define OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_MASK BITFIELD(16, 22)
+#define OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_MASK (0x7f << 16)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_SCHEME_SHIFT 30
+#define OMAP4430_SCHEME_MASK (0x3 << 30)
/* Used by PRM_VC_CFG_I2C_CLK */
#define OMAP4430_SCLH_SHIFT 0
-#define OMAP4430_SCLH_MASK BITFIELD(0, 7)
+#define OMAP4430_SCLH_MASK (0xff << 0)
/* Used by PRM_VC_CFG_I2C_CLK */
#define OMAP4430_SCLL_SHIFT 8
-#define OMAP4430_SCLL_MASK BITFIELD(8, 15)
+#define OMAP4430_SCLL_MASK (0xff << 8)
/* Used by PRM_RSTST */
#define OMAP4430_SECURE_WDT_RST_SHIFT 4
-#define OMAP4430_SECURE_WDT_RST_MASK BITFIELD(4, 4)
+#define OMAP4430_SECURE_WDT_RST_MASK (1 << 4)
/* Used by PM_IVAHD_PWRSTCTRL */
#define OMAP4430_SL2_MEM_ONSTATE_SHIFT 18
-#define OMAP4430_SL2_MEM_ONSTATE_MASK BITFIELD(18, 19)
+#define OMAP4430_SL2_MEM_ONSTATE_MASK (0x3 << 18)
/* Used by PM_IVAHD_PWRSTCTRL */
#define OMAP4430_SL2_MEM_RETSTATE_SHIFT 9
-#define OMAP4430_SL2_MEM_RETSTATE_MASK BITFIELD(9, 9)
+#define OMAP4430_SL2_MEM_RETSTATE_MASK (1 << 9)
/* Used by PM_IVAHD_PWRSTST */
#define OMAP4430_SL2_MEM_STATEST_SHIFT 6
-#define OMAP4430_SL2_MEM_STATEST_MASK BITFIELD(6, 7)
+#define OMAP4430_SL2_MEM_STATEST_MASK (0x3 << 6)
/* Used by PRM_VC_VAL_BYPASS */
#define OMAP4430_SLAVEADDR_SHIFT 0
-#define OMAP4430_SLAVEADDR_MASK BITFIELD(0, 6)
+#define OMAP4430_SLAVEADDR_MASK (0x7f << 0)
/* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */
#define OMAP4430_SLEEP_RBB_SEL_SHIFT 3
-#define OMAP4430_SLEEP_RBB_SEL_MASK BITFIELD(3, 3)
+#define OMAP4430_SLEEP_RBB_SEL_MASK (1 << 3)
/* Used by PRM_SRAM_COUNT */
#define OMAP4430_SLPCNT_VALUE_SHIFT 16
-#define OMAP4430_SLPCNT_VALUE_MASK BITFIELD(16, 23)
+#define OMAP4430_SLPCNT_VALUE_MASK (0xff << 16)
/* Used by PRM_VP_CORE_VSTEPMAX, PRM_VP_IVA_VSTEPMAX, PRM_VP_MPU_VSTEPMAX */
#define OMAP4430_SMPSWAITTIMEMAX_SHIFT 8
-#define OMAP4430_SMPSWAITTIMEMAX_MASK BITFIELD(8, 23)
+#define OMAP4430_SMPSWAITTIMEMAX_MASK (0xffff << 8)
/* Used by PRM_VP_CORE_VSTEPMIN, PRM_VP_IVA_VSTEPMIN, PRM_VP_MPU_VSTEPMIN */
#define OMAP4430_SMPSWAITTIMEMIN_SHIFT 8
-#define OMAP4430_SMPSWAITTIMEMIN_MASK BITFIELD(8, 23)
+#define OMAP4430_SMPSWAITTIMEMIN_MASK (0xffff << 8)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_RA_ERR_CORE_SHIFT 1
+#define OMAP4430_SMPS_RA_ERR_CORE_MASK (1 << 1)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_RA_ERR_IVA_SHIFT 9
+#define OMAP4430_SMPS_RA_ERR_IVA_MASK (1 << 9)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_RA_ERR_MPU_SHIFT 17
+#define OMAP4430_SMPS_RA_ERR_MPU_MASK (1 << 17)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_SA_ERR_CORE_SHIFT 0
+#define OMAP4430_SMPS_SA_ERR_CORE_MASK (1 << 0)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_SA_ERR_IVA_SHIFT 8
+#define OMAP4430_SMPS_SA_ERR_IVA_MASK (1 << 8)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_SA_ERR_MPU_SHIFT 16
+#define OMAP4430_SMPS_SA_ERR_MPU_MASK (1 << 16)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_TIMEOUT_ERR_CORE_SHIFT 2
+#define OMAP4430_SMPS_TIMEOUT_ERR_CORE_MASK (1 << 2)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_TIMEOUT_ERR_IVA_SHIFT 10
+#define OMAP4430_SMPS_TIMEOUT_ERR_IVA_MASK (1 << 10)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_TIMEOUT_ERR_MPU_SHIFT 18
+#define OMAP4430_SMPS_TIMEOUT_ERR_MPU_MASK (1 << 18)
/* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */
#define OMAP4430_SR2EN_SHIFT 0
-#define OMAP4430_SR2EN_MASK BITFIELD(0, 0)
+#define OMAP4430_SR2EN_MASK (1 << 0)
/* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */
#define OMAP4430_SR2_IN_TRANSITION_SHIFT 6
-#define OMAP4430_SR2_IN_TRANSITION_MASK BITFIELD(6, 6)
+#define OMAP4430_SR2_IN_TRANSITION_MASK (1 << 6)
/* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */
#define OMAP4430_SR2_STATUS_SHIFT 3
-#define OMAP4430_SR2_STATUS_MASK BITFIELD(3, 4)
+#define OMAP4430_SR2_STATUS_MASK (0x3 << 3)
/* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */
#define OMAP4430_SR2_WTCNT_VALUE_SHIFT 8
-#define OMAP4430_SR2_WTCNT_VALUE_MASK BITFIELD(8, 15)
+#define OMAP4430_SR2_WTCNT_VALUE_MASK (0xff << 8)
/*
* Used by PRM_LDO_SRAM_CORE_CTRL, PRM_LDO_SRAM_IVA_CTRL,
* PRM_LDO_SRAM_MPU_CTRL
*/
#define OMAP4430_SRAMLDO_STATUS_SHIFT 8
-#define OMAP4430_SRAMLDO_STATUS_MASK BITFIELD(8, 8)
+#define OMAP4430_SRAMLDO_STATUS_MASK (1 << 8)
/*
* Used by PRM_LDO_SRAM_CORE_CTRL, PRM_LDO_SRAM_IVA_CTRL,
* PRM_LDO_SRAM_MPU_CTRL
*/
#define OMAP4430_SRAM_IN_TRANSITION_SHIFT 9
-#define OMAP4430_SRAM_IN_TRANSITION_MASK BITFIELD(9, 9)
+#define OMAP4430_SRAM_IN_TRANSITION_MASK (1 << 9)
/* Used by PRM_VC_CFG_I2C_MODE */
#define OMAP4430_SRMODEEN_SHIFT 4
-#define OMAP4430_SRMODEEN_MASK BITFIELD(4, 4)
+#define OMAP4430_SRMODEEN_MASK (1 << 4)
/* Used by PRM_VOLTSETUP_WARMRESET */
#define OMAP4430_STABLE_COUNT_SHIFT 0
-#define OMAP4430_STABLE_COUNT_MASK BITFIELD(0, 5)
+#define OMAP4430_STABLE_COUNT_MASK (0x3f << 0)
/* Used by PRM_VOLTSETUP_WARMRESET */
#define OMAP4430_STABLE_PRESCAL_SHIFT 8
-#define OMAP4430_STABLE_PRESCAL_MASK BITFIELD(8, 9)
+#define OMAP4430_STABLE_PRESCAL_MASK (0x3 << 8)
+
+/* Used by PRM_LDO_BANDGAP_SETUP */
+#define OMAP4430_STARTUP_COUNT_SHIFT 0
+#define OMAP4430_STARTUP_COUNT_MASK (0xff << 0)
+
+/* Renamed from STARTUP_COUNT Used by PRM_SRAM_COUNT */
+#define OMAP4430_STARTUP_COUNT_24_31_SHIFT 24
+#define OMAP4430_STARTUP_COUNT_24_31_MASK (0xff << 24)
/* Used by PM_IVAHD_PWRSTCTRL */
#define OMAP4430_TCM1_MEM_ONSTATE_SHIFT 20
-#define OMAP4430_TCM1_MEM_ONSTATE_MASK BITFIELD(20, 21)
+#define OMAP4430_TCM1_MEM_ONSTATE_MASK (0x3 << 20)
/* Used by PM_IVAHD_PWRSTCTRL */
#define OMAP4430_TCM1_MEM_RETSTATE_SHIFT 10
-#define OMAP4430_TCM1_MEM_RETSTATE_MASK BITFIELD(10, 10)
+#define OMAP4430_TCM1_MEM_RETSTATE_MASK (1 << 10)
/* Used by PM_IVAHD_PWRSTST */
#define OMAP4430_TCM1_MEM_STATEST_SHIFT 8
-#define OMAP4430_TCM1_MEM_STATEST_MASK BITFIELD(8, 9)
+#define OMAP4430_TCM1_MEM_STATEST_MASK (0x3 << 8)
/* Used by PM_IVAHD_PWRSTCTRL */
#define OMAP4430_TCM2_MEM_ONSTATE_SHIFT 22
-#define OMAP4430_TCM2_MEM_ONSTATE_MASK BITFIELD(22, 23)
+#define OMAP4430_TCM2_MEM_ONSTATE_MASK (0x3 << 22)
/* Used by PM_IVAHD_PWRSTCTRL */
#define OMAP4430_TCM2_MEM_RETSTATE_SHIFT 11
-#define OMAP4430_TCM2_MEM_RETSTATE_MASK BITFIELD(11, 11)
+#define OMAP4430_TCM2_MEM_RETSTATE_MASK (1 << 11)
/* Used by PM_IVAHD_PWRSTST */
#define OMAP4430_TCM2_MEM_STATEST_SHIFT 10
-#define OMAP4430_TCM2_MEM_STATEST_MASK BITFIELD(10, 11)
+#define OMAP4430_TCM2_MEM_STATEST_MASK (0x3 << 10)
/* Used by RM_TESLA_RSTST */
#define OMAP4430_TESLASS_EMU_RSTST_SHIFT 2
-#define OMAP4430_TESLASS_EMU_RSTST_MASK BITFIELD(2, 2)
+#define OMAP4430_TESLASS_EMU_RSTST_MASK (1 << 2)
/* Used by RM_TESLA_RSTST */
#define OMAP4430_TESLA_DSP_EMU_REQ_RSTST_SHIFT 3
-#define OMAP4430_TESLA_DSP_EMU_REQ_RSTST_MASK BITFIELD(3, 3)
+#define OMAP4430_TESLA_DSP_EMU_REQ_RSTST_MASK (1 << 3)
/* Used by PM_TESLA_PWRSTCTRL */
#define OMAP4430_TESLA_EDMA_ONSTATE_SHIFT 20
-#define OMAP4430_TESLA_EDMA_ONSTATE_MASK BITFIELD(20, 21)
+#define OMAP4430_TESLA_EDMA_ONSTATE_MASK (0x3 << 20)
/* Used by PM_TESLA_PWRSTCTRL */
#define OMAP4430_TESLA_EDMA_RETSTATE_SHIFT 10
-#define OMAP4430_TESLA_EDMA_RETSTATE_MASK BITFIELD(10, 10)
+#define OMAP4430_TESLA_EDMA_RETSTATE_MASK (1 << 10)
/* Used by PM_TESLA_PWRSTST */
#define OMAP4430_TESLA_EDMA_STATEST_SHIFT 8
-#define OMAP4430_TESLA_EDMA_STATEST_MASK BITFIELD(8, 9)
+#define OMAP4430_TESLA_EDMA_STATEST_MASK (0x3 << 8)
/* Used by PM_TESLA_PWRSTCTRL */
#define OMAP4430_TESLA_L1_ONSTATE_SHIFT 16
-#define OMAP4430_TESLA_L1_ONSTATE_MASK BITFIELD(16, 17)
+#define OMAP4430_TESLA_L1_ONSTATE_MASK (0x3 << 16)
/* Used by PM_TESLA_PWRSTCTRL */
#define OMAP4430_TESLA_L1_RETSTATE_SHIFT 8
-#define OMAP4430_TESLA_L1_RETSTATE_MASK BITFIELD(8, 8)
+#define OMAP4430_TESLA_L1_RETSTATE_MASK (1 << 8)
/* Used by PM_TESLA_PWRSTST */
#define OMAP4430_TESLA_L1_STATEST_SHIFT 4
-#define OMAP4430_TESLA_L1_STATEST_MASK BITFIELD(4, 5)
+#define OMAP4430_TESLA_L1_STATEST_MASK (0x3 << 4)
/* Used by PM_TESLA_PWRSTCTRL */
#define OMAP4430_TESLA_L2_ONSTATE_SHIFT 18
-#define OMAP4430_TESLA_L2_ONSTATE_MASK BITFIELD(18, 19)
+#define OMAP4430_TESLA_L2_ONSTATE_MASK (0x3 << 18)
/* Used by PM_TESLA_PWRSTCTRL */
#define OMAP4430_TESLA_L2_RETSTATE_SHIFT 9
-#define OMAP4430_TESLA_L2_RETSTATE_MASK BITFIELD(9, 9)
+#define OMAP4430_TESLA_L2_RETSTATE_MASK (1 << 9)
/* Used by PM_TESLA_PWRSTST */
#define OMAP4430_TESLA_L2_STATEST_SHIFT 6
-#define OMAP4430_TESLA_L2_STATEST_MASK BITFIELD(6, 7)
+#define OMAP4430_TESLA_L2_STATEST_MASK (0x3 << 6)
/* Used by PRM_VP_CORE_VLIMITTO, PRM_VP_IVA_VLIMITTO, PRM_VP_MPU_VLIMITTO */
#define OMAP4430_TIMEOUT_SHIFT 0
-#define OMAP4430_TIMEOUT_MASK BITFIELD(0, 15)
+#define OMAP4430_TIMEOUT_MASK (0xffff << 0)
/* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
#define OMAP4430_TIMEOUTEN_SHIFT 3
-#define OMAP4430_TIMEOUTEN_MASK BITFIELD(3, 3)
+#define OMAP4430_TIMEOUTEN_MASK (1 << 3)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_TRANSITION_EN_SHIFT 8
-#define OMAP4430_TRANSITION_EN_MASK BITFIELD(8, 8)
+#define OMAP4430_TRANSITION_EN_MASK (1 << 8)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_TRANSITION_ST_SHIFT 8
-#define OMAP4430_TRANSITION_ST_MASK BITFIELD(8, 8)
+#define OMAP4430_TRANSITION_ST_MASK (1 << 8)
/* Used by PRM_VC_VAL_BYPASS */
#define OMAP4430_VALID_SHIFT 24
-#define OMAP4430_VALID_MASK BITFIELD(24, 24)
+#define OMAP4430_VALID_MASK (1 << 24)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VC_BYPASSACK_EN_SHIFT 14
-#define OMAP4430_VC_BYPASSACK_EN_MASK BITFIELD(14, 14)
+#define OMAP4430_VC_BYPASSACK_EN_MASK (1 << 14)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VC_BYPASSACK_ST_SHIFT 14
-#define OMAP4430_VC_BYPASSACK_ST_MASK BITFIELD(14, 14)
+#define OMAP4430_VC_BYPASSACK_ST_MASK (1 << 14)
+
+/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
+#define OMAP4430_VC_CORE_VPACK_EN_SHIFT 22
+#define OMAP4430_VC_CORE_VPACK_EN_MASK (1 << 22)
+
+/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
+#define OMAP4430_VC_CORE_VPACK_ST_SHIFT 22
+#define OMAP4430_VC_CORE_VPACK_ST_MASK (1 << 22)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VC_IVA_VPACK_EN_SHIFT 30
-#define OMAP4430_VC_IVA_VPACK_EN_MASK BITFIELD(30, 30)
+#define OMAP4430_VC_IVA_VPACK_EN_MASK (1 << 30)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VC_IVA_VPACK_ST_SHIFT 30
-#define OMAP4430_VC_IVA_VPACK_ST_MASK BITFIELD(30, 30)
+#define OMAP4430_VC_IVA_VPACK_ST_MASK (1 << 30)
/* Used by PRM_IRQENABLE_MPU_2 */
#define OMAP4430_VC_MPU_VPACK_EN_SHIFT 6
-#define OMAP4430_VC_MPU_VPACK_EN_MASK BITFIELD(6, 6)
+#define OMAP4430_VC_MPU_VPACK_EN_MASK (1 << 6)
/* Used by PRM_IRQSTATUS_MPU_2 */
#define OMAP4430_VC_MPU_VPACK_ST_SHIFT 6
-#define OMAP4430_VC_MPU_VPACK_ST_MASK BITFIELD(6, 6)
+#define OMAP4430_VC_MPU_VPACK_ST_MASK (1 << 6)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VC_RAERR_EN_SHIFT 12
-#define OMAP4430_VC_RAERR_EN_MASK BITFIELD(12, 12)
+#define OMAP4430_VC_RAERR_EN_MASK (1 << 12)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VC_RAERR_ST_SHIFT 12
-#define OMAP4430_VC_RAERR_ST_MASK BITFIELD(12, 12)
+#define OMAP4430_VC_RAERR_ST_MASK (1 << 12)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VC_SAERR_EN_SHIFT 11
-#define OMAP4430_VC_SAERR_EN_MASK BITFIELD(11, 11)
+#define OMAP4430_VC_SAERR_EN_MASK (1 << 11)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VC_SAERR_ST_SHIFT 11
-#define OMAP4430_VC_SAERR_ST_MASK BITFIELD(11, 11)
+#define OMAP4430_VC_SAERR_ST_MASK (1 << 11)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VC_TOERR_EN_SHIFT 13
-#define OMAP4430_VC_TOERR_EN_MASK BITFIELD(13, 13)
+#define OMAP4430_VC_TOERR_EN_MASK (1 << 13)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VC_TOERR_ST_SHIFT 13
-#define OMAP4430_VC_TOERR_ST_MASK BITFIELD(13, 13)
+#define OMAP4430_VC_TOERR_ST_MASK (1 << 13)
/* Used by PRM_VP_CORE_VLIMITTO, PRM_VP_IVA_VLIMITTO, PRM_VP_MPU_VLIMITTO */
#define OMAP4430_VDDMAX_SHIFT 24
-#define OMAP4430_VDDMAX_MASK BITFIELD(24, 31)
+#define OMAP4430_VDDMAX_MASK (0xff << 24)
/* Used by PRM_VP_CORE_VLIMITTO, PRM_VP_IVA_VLIMITTO, PRM_VP_MPU_VLIMITTO */
#define OMAP4430_VDDMIN_SHIFT 16
-#define OMAP4430_VDDMIN_MASK BITFIELD(16, 23)
+#define OMAP4430_VDDMIN_MASK (0xff << 16)
/* Used by PRM_VOLTCTRL */
#define OMAP4430_VDD_CORE_I2C_DISABLE_SHIFT 12
-#define OMAP4430_VDD_CORE_I2C_DISABLE_MASK BITFIELD(12, 12)
+#define OMAP4430_VDD_CORE_I2C_DISABLE_MASK (1 << 12)
/* Used by PRM_RSTST */
#define OMAP4430_VDD_CORE_VOLT_MGR_RST_SHIFT 8
-#define OMAP4430_VDD_CORE_VOLT_MGR_RST_MASK BITFIELD(8, 8)
+#define OMAP4430_VDD_CORE_VOLT_MGR_RST_MASK (1 << 8)
/* Used by PRM_VOLTCTRL */
#define OMAP4430_VDD_IVA_I2C_DISABLE_SHIFT 14
-#define OMAP4430_VDD_IVA_I2C_DISABLE_MASK BITFIELD(14, 14)
+#define OMAP4430_VDD_IVA_I2C_DISABLE_MASK (1 << 14)
/* Used by PRM_VOLTCTRL */
#define OMAP4430_VDD_IVA_PRESENCE_SHIFT 9
-#define OMAP4430_VDD_IVA_PRESENCE_MASK BITFIELD(9, 9)
+#define OMAP4430_VDD_IVA_PRESENCE_MASK (1 << 9)
/* Used by PRM_RSTST */
#define OMAP4430_VDD_IVA_VOLT_MGR_RST_SHIFT 7
-#define OMAP4430_VDD_IVA_VOLT_MGR_RST_MASK BITFIELD(7, 7)
+#define OMAP4430_VDD_IVA_VOLT_MGR_RST_MASK (1 << 7)
/* Used by PRM_VOLTCTRL */
#define OMAP4430_VDD_MPU_I2C_DISABLE_SHIFT 13
-#define OMAP4430_VDD_MPU_I2C_DISABLE_MASK BITFIELD(13, 13)
+#define OMAP4430_VDD_MPU_I2C_DISABLE_MASK (1 << 13)
/* Used by PRM_VOLTCTRL */
#define OMAP4430_VDD_MPU_PRESENCE_SHIFT 8
-#define OMAP4430_VDD_MPU_PRESENCE_MASK BITFIELD(8, 8)
+#define OMAP4430_VDD_MPU_PRESENCE_MASK (1 << 8)
/* Used by PRM_RSTST */
#define OMAP4430_VDD_MPU_VOLT_MGR_RST_SHIFT 6
-#define OMAP4430_VDD_MPU_VOLT_MGR_RST_MASK BITFIELD(6, 6)
+#define OMAP4430_VDD_MPU_VOLT_MGR_RST_MASK (1 << 6)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_RA_ERR_CORE_SHIFT 4
+#define OMAP4430_VFSM_RA_ERR_CORE_MASK (1 << 4)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_RA_ERR_IVA_SHIFT 12
+#define OMAP4430_VFSM_RA_ERR_IVA_MASK (1 << 12)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_RA_ERR_MPU_SHIFT 20
+#define OMAP4430_VFSM_RA_ERR_MPU_MASK (1 << 20)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_SA_ERR_CORE_SHIFT 3
+#define OMAP4430_VFSM_SA_ERR_CORE_MASK (1 << 3)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_SA_ERR_IVA_SHIFT 11
+#define OMAP4430_VFSM_SA_ERR_IVA_MASK (1 << 11)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_SA_ERR_MPU_SHIFT 19
+#define OMAP4430_VFSM_SA_ERR_MPU_MASK (1 << 19)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_TIMEOUT_ERR_CORE_SHIFT 5
+#define OMAP4430_VFSM_TIMEOUT_ERR_CORE_MASK (1 << 5)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_TIMEOUT_ERR_IVA_SHIFT 13
+#define OMAP4430_VFSM_TIMEOUT_ERR_IVA_MASK (1 << 13)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_TIMEOUT_ERR_MPU_SHIFT 21
+#define OMAP4430_VFSM_TIMEOUT_ERR_MPU_MASK (1 << 21)
/* Used by PRM_VC_VAL_SMPS_RA_VOL */
#define OMAP4430_VOLRA_VDD_CORE_L_SHIFT 0
-#define OMAP4430_VOLRA_VDD_CORE_L_MASK BITFIELD(0, 7)
+#define OMAP4430_VOLRA_VDD_CORE_L_MASK (0xff << 0)
/* Used by PRM_VC_VAL_SMPS_RA_VOL */
#define OMAP4430_VOLRA_VDD_IVA_L_SHIFT 8
-#define OMAP4430_VOLRA_VDD_IVA_L_MASK BITFIELD(8, 15)
+#define OMAP4430_VOLRA_VDD_IVA_L_MASK (0xff << 8)
/* Used by PRM_VC_VAL_SMPS_RA_VOL */
#define OMAP4430_VOLRA_VDD_MPU_L_SHIFT 16
-#define OMAP4430_VOLRA_VDD_MPU_L_MASK BITFIELD(16, 23)
+#define OMAP4430_VOLRA_VDD_MPU_L_MASK (0xff << 16)
/* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
#define OMAP4430_VPENABLE_SHIFT 0
-#define OMAP4430_VPENABLE_MASK BITFIELD(0, 0)
+#define OMAP4430_VPENABLE_MASK (1 << 0)
/* Used by PRM_VP_CORE_STATUS, PRM_VP_IVA_STATUS, PRM_VP_MPU_STATUS */
#define OMAP4430_VPINIDLE_SHIFT 0
-#define OMAP4430_VPINIDLE_MASK BITFIELD(0, 0)
+#define OMAP4430_VPINIDLE_MASK (1 << 0)
/* Used by PRM_VP_CORE_VOLTAGE, PRM_VP_IVA_VOLTAGE, PRM_VP_MPU_VOLTAGE */
#define OMAP4430_VPVOLTAGE_SHIFT 0
-#define OMAP4430_VPVOLTAGE_MASK BITFIELD(0, 7)
+#define OMAP4430_VPVOLTAGE_MASK (0xff << 0)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VP_CORE_EQVALUE_EN_SHIFT 20
-#define OMAP4430_VP_CORE_EQVALUE_EN_MASK BITFIELD(20, 20)
+#define OMAP4430_VP_CORE_EQVALUE_EN_MASK (1 << 20)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VP_CORE_EQVALUE_ST_SHIFT 20
-#define OMAP4430_VP_CORE_EQVALUE_ST_MASK BITFIELD(20, 20)
+#define OMAP4430_VP_CORE_EQVALUE_ST_MASK (1 << 20)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VP_CORE_MAXVDD_EN_SHIFT 18
-#define OMAP4430_VP_CORE_MAXVDD_EN_MASK BITFIELD(18, 18)
+#define OMAP4430_VP_CORE_MAXVDD_EN_MASK (1 << 18)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VP_CORE_MAXVDD_ST_SHIFT 18
-#define OMAP4430_VP_CORE_MAXVDD_ST_MASK BITFIELD(18, 18)
+#define OMAP4430_VP_CORE_MAXVDD_ST_MASK (1 << 18)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VP_CORE_MINVDD_EN_SHIFT 17
-#define OMAP4430_VP_CORE_MINVDD_EN_MASK BITFIELD(17, 17)
+#define OMAP4430_VP_CORE_MINVDD_EN_MASK (1 << 17)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VP_CORE_MINVDD_ST_SHIFT 17
-#define OMAP4430_VP_CORE_MINVDD_ST_MASK BITFIELD(17, 17)
+#define OMAP4430_VP_CORE_MINVDD_ST_MASK (1 << 17)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VP_CORE_NOSMPSACK_EN_SHIFT 19
-#define OMAP4430_VP_CORE_NOSMPSACK_EN_MASK BITFIELD(19, 19)
+#define OMAP4430_VP_CORE_NOSMPSACK_EN_MASK (1 << 19)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VP_CORE_NOSMPSACK_ST_SHIFT 19
-#define OMAP4430_VP_CORE_NOSMPSACK_ST_MASK BITFIELD(19, 19)
+#define OMAP4430_VP_CORE_NOSMPSACK_ST_MASK (1 << 19)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VP_CORE_OPPCHANGEDONE_EN_SHIFT 16
-#define OMAP4430_VP_CORE_OPPCHANGEDONE_EN_MASK BITFIELD(16, 16)
+#define OMAP4430_VP_CORE_OPPCHANGEDONE_EN_MASK (1 << 16)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VP_CORE_OPPCHANGEDONE_ST_SHIFT 16
-#define OMAP4430_VP_CORE_OPPCHANGEDONE_ST_MASK BITFIELD(16, 16)
+#define OMAP4430_VP_CORE_OPPCHANGEDONE_ST_MASK (1 << 16)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VP_CORE_TRANXDONE_EN_SHIFT 21
-#define OMAP4430_VP_CORE_TRANXDONE_EN_MASK BITFIELD(21, 21)
+#define OMAP4430_VP_CORE_TRANXDONE_EN_MASK (1 << 21)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VP_CORE_TRANXDONE_ST_SHIFT 21
-#define OMAP4430_VP_CORE_TRANXDONE_ST_MASK BITFIELD(21, 21)
+#define OMAP4430_VP_CORE_TRANXDONE_ST_MASK (1 << 21)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VP_IVA_EQVALUE_EN_SHIFT 28
-#define OMAP4430_VP_IVA_EQVALUE_EN_MASK BITFIELD(28, 28)
+#define OMAP4430_VP_IVA_EQVALUE_EN_MASK (1 << 28)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VP_IVA_EQVALUE_ST_SHIFT 28
-#define OMAP4430_VP_IVA_EQVALUE_ST_MASK BITFIELD(28, 28)
+#define OMAP4430_VP_IVA_EQVALUE_ST_MASK (1 << 28)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VP_IVA_MAXVDD_EN_SHIFT 26
-#define OMAP4430_VP_IVA_MAXVDD_EN_MASK BITFIELD(26, 26)
+#define OMAP4430_VP_IVA_MAXVDD_EN_MASK (1 << 26)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VP_IVA_MAXVDD_ST_SHIFT 26
-#define OMAP4430_VP_IVA_MAXVDD_ST_MASK BITFIELD(26, 26)
+#define OMAP4430_VP_IVA_MAXVDD_ST_MASK (1 << 26)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VP_IVA_MINVDD_EN_SHIFT 25
-#define OMAP4430_VP_IVA_MINVDD_EN_MASK BITFIELD(25, 25)
+#define OMAP4430_VP_IVA_MINVDD_EN_MASK (1 << 25)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VP_IVA_MINVDD_ST_SHIFT 25
-#define OMAP4430_VP_IVA_MINVDD_ST_MASK BITFIELD(25, 25)
+#define OMAP4430_VP_IVA_MINVDD_ST_MASK (1 << 25)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VP_IVA_NOSMPSACK_EN_SHIFT 27
-#define OMAP4430_VP_IVA_NOSMPSACK_EN_MASK BITFIELD(27, 27)
+#define OMAP4430_VP_IVA_NOSMPSACK_EN_MASK (1 << 27)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VP_IVA_NOSMPSACK_ST_SHIFT 27
-#define OMAP4430_VP_IVA_NOSMPSACK_ST_MASK BITFIELD(27, 27)
+#define OMAP4430_VP_IVA_NOSMPSACK_ST_MASK (1 << 27)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VP_IVA_OPPCHANGEDONE_EN_SHIFT 24
-#define OMAP4430_VP_IVA_OPPCHANGEDONE_EN_MASK BITFIELD(24, 24)
+#define OMAP4430_VP_IVA_OPPCHANGEDONE_EN_MASK (1 << 24)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VP_IVA_OPPCHANGEDONE_ST_SHIFT 24
-#define OMAP4430_VP_IVA_OPPCHANGEDONE_ST_MASK BITFIELD(24, 24)
+#define OMAP4430_VP_IVA_OPPCHANGEDONE_ST_MASK (1 << 24)
/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
#define OMAP4430_VP_IVA_TRANXDONE_EN_SHIFT 29
-#define OMAP4430_VP_IVA_TRANXDONE_EN_MASK BITFIELD(29, 29)
+#define OMAP4430_VP_IVA_TRANXDONE_EN_MASK (1 << 29)
/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
#define OMAP4430_VP_IVA_TRANXDONE_ST_SHIFT 29
-#define OMAP4430_VP_IVA_TRANXDONE_ST_MASK BITFIELD(29, 29)
+#define OMAP4430_VP_IVA_TRANXDONE_ST_MASK (1 << 29)
/* Used by PRM_IRQENABLE_MPU_2 */
#define OMAP4430_VP_MPU_EQVALUE_EN_SHIFT 4
-#define OMAP4430_VP_MPU_EQVALUE_EN_MASK BITFIELD(4, 4)
+#define OMAP4430_VP_MPU_EQVALUE_EN_MASK (1 << 4)
/* Used by PRM_IRQSTATUS_MPU_2 */
#define OMAP4430_VP_MPU_EQVALUE_ST_SHIFT 4
-#define OMAP4430_VP_MPU_EQVALUE_ST_MASK BITFIELD(4, 4)
+#define OMAP4430_VP_MPU_EQVALUE_ST_MASK (1 << 4)
/* Used by PRM_IRQENABLE_MPU_2 */
#define OMAP4430_VP_MPU_MAXVDD_EN_SHIFT 2
-#define OMAP4430_VP_MPU_MAXVDD_EN_MASK BITFIELD(2, 2)
+#define OMAP4430_VP_MPU_MAXVDD_EN_MASK (1 << 2)
/* Used by PRM_IRQSTATUS_MPU_2 */
#define OMAP4430_VP_MPU_MAXVDD_ST_SHIFT 2
-#define OMAP4430_VP_MPU_MAXVDD_ST_MASK BITFIELD(2, 2)
+#define OMAP4430_VP_MPU_MAXVDD_ST_MASK (1 << 2)
/* Used by PRM_IRQENABLE_MPU_2 */
#define OMAP4430_VP_MPU_MINVDD_EN_SHIFT 1
-#define OMAP4430_VP_MPU_MINVDD_EN_MASK BITFIELD(1, 1)
+#define OMAP4430_VP_MPU_MINVDD_EN_MASK (1 << 1)
/* Used by PRM_IRQSTATUS_MPU_2 */
#define OMAP4430_VP_MPU_MINVDD_ST_SHIFT 1
-#define OMAP4430_VP_MPU_MINVDD_ST_MASK BITFIELD(1, 1)
+#define OMAP4430_VP_MPU_MINVDD_ST_MASK (1 << 1)
/* Used by PRM_IRQENABLE_MPU_2 */
#define OMAP4430_VP_MPU_NOSMPSACK_EN_SHIFT 3
-#define OMAP4430_VP_MPU_NOSMPSACK_EN_MASK BITFIELD(3, 3)
+#define OMAP4430_VP_MPU_NOSMPSACK_EN_MASK (1 << 3)
/* Used by PRM_IRQSTATUS_MPU_2 */
#define OMAP4430_VP_MPU_NOSMPSACK_ST_SHIFT 3
-#define OMAP4430_VP_MPU_NOSMPSACK_ST_MASK BITFIELD(3, 3)
+#define OMAP4430_VP_MPU_NOSMPSACK_ST_MASK (1 << 3)
/* Used by PRM_IRQENABLE_MPU_2 */
#define OMAP4430_VP_MPU_OPPCHANGEDONE_EN_SHIFT 0
-#define OMAP4430_VP_MPU_OPPCHANGEDONE_EN_MASK BITFIELD(0, 0)
+#define OMAP4430_VP_MPU_OPPCHANGEDONE_EN_MASK (1 << 0)
/* Used by PRM_IRQSTATUS_MPU_2 */
#define OMAP4430_VP_MPU_OPPCHANGEDONE_ST_SHIFT 0
-#define OMAP4430_VP_MPU_OPPCHANGEDONE_ST_MASK BITFIELD(0, 0)
+#define OMAP4430_VP_MPU_OPPCHANGEDONE_ST_MASK (1 << 0)
/* Used by PRM_IRQENABLE_MPU_2 */
#define OMAP4430_VP_MPU_TRANXDONE_EN_SHIFT 5
-#define OMAP4430_VP_MPU_TRANXDONE_EN_MASK BITFIELD(5, 5)
+#define OMAP4430_VP_MPU_TRANXDONE_EN_MASK (1 << 5)
/* Used by PRM_IRQSTATUS_MPU_2 */
#define OMAP4430_VP_MPU_TRANXDONE_ST_SHIFT 5
-#define OMAP4430_VP_MPU_TRANXDONE_ST_MASK BITFIELD(5, 5)
+#define OMAP4430_VP_MPU_TRANXDONE_ST_MASK (1 << 5)
/* Used by PRM_SRAM_COUNT */
#define OMAP4430_VSETUPCNT_VALUE_SHIFT 8
-#define OMAP4430_VSETUPCNT_VALUE_MASK BITFIELD(8, 15)
+#define OMAP4430_VSETUPCNT_VALUE_MASK (0xff << 8)
/* Used by PRM_VP_CORE_VSTEPMAX, PRM_VP_IVA_VSTEPMAX, PRM_VP_MPU_VSTEPMAX */
#define OMAP4430_VSTEPMAX_SHIFT 0
-#define OMAP4430_VSTEPMAX_MASK BITFIELD(0, 7)
+#define OMAP4430_VSTEPMAX_MASK (0xff << 0)
/* Used by PRM_VP_CORE_VSTEPMIN, PRM_VP_IVA_VSTEPMIN, PRM_VP_MPU_VSTEPMIN */
#define OMAP4430_VSTEPMIN_SHIFT 0
-#define OMAP4430_VSTEPMIN_MASK BITFIELD(0, 7)
+#define OMAP4430_VSTEPMIN_MASK (0xff << 0)
/* Used by PRM_MODEM_IF_CTRL */
#define OMAP4430_WAKE_MODEM_SHIFT 0
-#define OMAP4430_WAKE_MODEM_MASK BITFIELD(0, 0)
+#define OMAP4430_WAKE_MODEM_MASK (1 << 0)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_DISPC_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_DISPC_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_DISPC_DUCATI_MASK (1 << 1)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_DISPC_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_DISPC_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DISPC_MPU_MASK (1 << 0)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_DISPC_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_DISPC_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_DISPC_SDMA_MASK (1 << 3)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_DISPC_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_DISPC_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_DISPC_TESLA_MASK (1 << 2)
/* Used by PM_ABE_DMIC_WKDEP */
#define OMAP4430_WKUPDEP_DMIC_DMA_SDMA_SHIFT 7
-#define OMAP4430_WKUPDEP_DMIC_DMA_SDMA_MASK BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_DMIC_DMA_SDMA_MASK (1 << 7)
/* Used by PM_ABE_DMIC_WKDEP */
#define OMAP4430_WKUPDEP_DMIC_DMA_TESLA_SHIFT 6
-#define OMAP4430_WKUPDEP_DMIC_DMA_TESLA_MASK BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_DMIC_DMA_TESLA_MASK (1 << 6)
/* Used by PM_ABE_DMIC_WKDEP */
#define OMAP4430_WKUPDEP_DMIC_IRQ_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_DMIC_IRQ_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMIC_IRQ_MPU_MASK (1 << 0)
/* Used by PM_ABE_DMIC_WKDEP */
#define OMAP4430_WKUPDEP_DMIC_IRQ_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_DMIC_IRQ_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_DMIC_IRQ_TESLA_MASK (1 << 2)
/* Used by PM_L4PER_DMTIMER10_WKDEP */
#define OMAP4430_WKUPDEP_DMTIMER10_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_DMTIMER10_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER10_MPU_MASK (1 << 0)
/* Used by PM_L4PER_DMTIMER11_WKDEP */
#define OMAP4430_WKUPDEP_DMTIMER11_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_DMTIMER11_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_DMTIMER11_DUCATI_MASK (1 << 1)
/* Used by PM_L4PER_DMTIMER11_WKDEP */
#define OMAP4430_WKUPDEP_DMTIMER11_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_DMTIMER11_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER11_MPU_MASK (1 << 0)
/* Used by PM_L4PER_DMTIMER2_WKDEP */
#define OMAP4430_WKUPDEP_DMTIMER2_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_DMTIMER2_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER2_MPU_MASK (1 << 0)
/* Used by PM_L4PER_DMTIMER3_WKDEP */
#define OMAP4430_WKUPDEP_DMTIMER3_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_DMTIMER3_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_DMTIMER3_DUCATI_MASK (1 << 1)
/* Used by PM_L4PER_DMTIMER3_WKDEP */
#define OMAP4430_WKUPDEP_DMTIMER3_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_DMTIMER3_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER3_MPU_MASK (1 << 0)
/* Used by PM_L4PER_DMTIMER4_WKDEP */
#define OMAP4430_WKUPDEP_DMTIMER4_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_DMTIMER4_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_DMTIMER4_DUCATI_MASK (1 << 1)
/* Used by PM_L4PER_DMTIMER4_WKDEP */
#define OMAP4430_WKUPDEP_DMTIMER4_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_DMTIMER4_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER4_MPU_MASK (1 << 0)
/* Used by PM_L4PER_DMTIMER9_WKDEP */
#define OMAP4430_WKUPDEP_DMTIMER9_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_DMTIMER9_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_DMTIMER9_DUCATI_MASK (1 << 1)
/* Used by PM_L4PER_DMTIMER9_WKDEP */
#define OMAP4430_WKUPDEP_DMTIMER9_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_DMTIMER9_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER9_MPU_MASK (1 << 0)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_DSI1_DUCATI_SHIFT 5
-#define OMAP4430_WKUPDEP_DSI1_DUCATI_MASK BITFIELD(5, 5)
+#define OMAP4430_WKUPDEP_DSI1_DUCATI_MASK (1 << 5)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_DSI1_MPU_SHIFT 4
-#define OMAP4430_WKUPDEP_DSI1_MPU_MASK BITFIELD(4, 4)
+#define OMAP4430_WKUPDEP_DSI1_MPU_MASK (1 << 4)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_DSI1_SDMA_SHIFT 7
-#define OMAP4430_WKUPDEP_DSI1_SDMA_MASK BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_DSI1_SDMA_MASK (1 << 7)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_DSI1_TESLA_SHIFT 6
-#define OMAP4430_WKUPDEP_DSI1_TESLA_MASK BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_DSI1_TESLA_MASK (1 << 6)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_DSI2_DUCATI_SHIFT 9
-#define OMAP4430_WKUPDEP_DSI2_DUCATI_MASK BITFIELD(9, 9)
+#define OMAP4430_WKUPDEP_DSI2_DUCATI_MASK (1 << 9)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_DSI2_MPU_SHIFT 8
-#define OMAP4430_WKUPDEP_DSI2_MPU_MASK BITFIELD(8, 8)
+#define OMAP4430_WKUPDEP_DSI2_MPU_MASK (1 << 8)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_DSI2_SDMA_SHIFT 11
-#define OMAP4430_WKUPDEP_DSI2_SDMA_MASK BITFIELD(11, 11)
+#define OMAP4430_WKUPDEP_DSI2_SDMA_MASK (1 << 11)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_DSI2_TESLA_SHIFT 10
-#define OMAP4430_WKUPDEP_DSI2_TESLA_MASK BITFIELD(10, 10)
+#define OMAP4430_WKUPDEP_DSI2_TESLA_MASK (1 << 10)
/* Used by PM_WKUP_GPIO1_WKDEP */
#define OMAP4430_WKUPDEP_GPIO1_IRQ1_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_GPIO1_IRQ1_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_GPIO1_IRQ1_DUCATI_MASK (1 << 1)
/* Used by PM_WKUP_GPIO1_WKDEP */
#define OMAP4430_WKUPDEP_GPIO1_IRQ1_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_GPIO1_IRQ1_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO1_IRQ1_MPU_MASK (1 << 0)
/* Used by PM_WKUP_GPIO1_WKDEP */
#define OMAP4430_WKUPDEP_GPIO1_IRQ2_TESLA_SHIFT 6
-#define OMAP4430_WKUPDEP_GPIO1_IRQ2_TESLA_MASK BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO1_IRQ2_TESLA_MASK (1 << 6)
/* Used by PM_L4PER_GPIO2_WKDEP */
#define OMAP4430_WKUPDEP_GPIO2_IRQ1_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_GPIO2_IRQ1_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_GPIO2_IRQ1_DUCATI_MASK (1 << 1)
/* Used by PM_L4PER_GPIO2_WKDEP */
#define OMAP4430_WKUPDEP_GPIO2_IRQ1_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_GPIO2_IRQ1_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO2_IRQ1_MPU_MASK (1 << 0)
/* Used by PM_L4PER_GPIO2_WKDEP */
#define OMAP4430_WKUPDEP_GPIO2_IRQ2_TESLA_SHIFT 6
-#define OMAP4430_WKUPDEP_GPIO2_IRQ2_TESLA_MASK BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO2_IRQ2_TESLA_MASK (1 << 6)
/* Used by PM_L4PER_GPIO3_WKDEP */
#define OMAP4430_WKUPDEP_GPIO3_IRQ1_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_GPIO3_IRQ1_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO3_IRQ1_MPU_MASK (1 << 0)
/* Used by PM_L4PER_GPIO3_WKDEP */
#define OMAP4430_WKUPDEP_GPIO3_IRQ2_TESLA_SHIFT 6
-#define OMAP4430_WKUPDEP_GPIO3_IRQ2_TESLA_MASK BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO3_IRQ2_TESLA_MASK (1 << 6)
/* Used by PM_L4PER_GPIO4_WKDEP */
#define OMAP4430_WKUPDEP_GPIO4_IRQ1_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_GPIO4_IRQ1_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO4_IRQ1_MPU_MASK (1 << 0)
/* Used by PM_L4PER_GPIO4_WKDEP */
#define OMAP4430_WKUPDEP_GPIO4_IRQ2_TESLA_SHIFT 6
-#define OMAP4430_WKUPDEP_GPIO4_IRQ2_TESLA_MASK BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO4_IRQ2_TESLA_MASK (1 << 6)
/* Used by PM_L4PER_GPIO5_WKDEP */
#define OMAP4430_WKUPDEP_GPIO5_IRQ1_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_GPIO5_IRQ1_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO5_IRQ1_MPU_MASK (1 << 0)
/* Used by PM_L4PER_GPIO5_WKDEP */
#define OMAP4430_WKUPDEP_GPIO5_IRQ2_TESLA_SHIFT 6
-#define OMAP4430_WKUPDEP_GPIO5_IRQ2_TESLA_MASK BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO5_IRQ2_TESLA_MASK (1 << 6)
/* Used by PM_L4PER_GPIO6_WKDEP */
#define OMAP4430_WKUPDEP_GPIO6_IRQ1_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_GPIO6_IRQ1_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO6_IRQ1_MPU_MASK (1 << 0)
/* Used by PM_L4PER_GPIO6_WKDEP */
#define OMAP4430_WKUPDEP_GPIO6_IRQ2_TESLA_SHIFT 6
-#define OMAP4430_WKUPDEP_GPIO6_IRQ2_TESLA_MASK BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO6_IRQ2_TESLA_MASK (1 << 6)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_HDMIDMA_SDMA_SHIFT 19
-#define OMAP4430_WKUPDEP_HDMIDMA_SDMA_MASK BITFIELD(19, 19)
+#define OMAP4430_WKUPDEP_HDMIDMA_SDMA_MASK (1 << 19)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_HDMIIRQ_DUCATI_SHIFT 13
-#define OMAP4430_WKUPDEP_HDMIIRQ_DUCATI_MASK BITFIELD(13, 13)
+#define OMAP4430_WKUPDEP_HDMIIRQ_DUCATI_MASK (1 << 13)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_HDMIIRQ_MPU_SHIFT 12
-#define OMAP4430_WKUPDEP_HDMIIRQ_MPU_MASK BITFIELD(12, 12)
+#define OMAP4430_WKUPDEP_HDMIIRQ_MPU_MASK (1 << 12)
/* Used by PM_DSS_DSS_WKDEP */
#define OMAP4430_WKUPDEP_HDMIIRQ_TESLA_SHIFT 14
-#define OMAP4430_WKUPDEP_HDMIIRQ_TESLA_MASK BITFIELD(14, 14)
+#define OMAP4430_WKUPDEP_HDMIIRQ_TESLA_MASK (1 << 14)
/* Used by PM_L4PER_HECC1_WKDEP */
#define OMAP4430_WKUPDEP_HECC1_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_HECC1_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_HECC1_MPU_MASK (1 << 0)
/* Used by PM_L4PER_HECC2_WKDEP */
#define OMAP4430_WKUPDEP_HECC2_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_HECC2_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_HECC2_MPU_MASK (1 << 0)
/* Used by PM_L3INIT_HSI_WKDEP */
#define OMAP4430_WKUPDEP_HSI_DSP_TESLA_SHIFT 6
-#define OMAP4430_WKUPDEP_HSI_DSP_TESLA_MASK BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_HSI_DSP_TESLA_MASK (1 << 6)
/* Used by PM_L3INIT_HSI_WKDEP */
#define OMAP4430_WKUPDEP_HSI_MCU_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_HSI_MCU_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_HSI_MCU_DUCATI_MASK (1 << 1)
/* Used by PM_L3INIT_HSI_WKDEP */
#define OMAP4430_WKUPDEP_HSI_MCU_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_HSI_MCU_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_HSI_MCU_MPU_MASK (1 << 0)
/* Used by PM_L4PER_I2C1_WKDEP */
#define OMAP4430_WKUPDEP_I2C1_DMA_SDMA_SHIFT 7
-#define OMAP4430_WKUPDEP_I2C1_DMA_SDMA_MASK BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_I2C1_DMA_SDMA_MASK (1 << 7)
/* Used by PM_L4PER_I2C1_WKDEP */
#define OMAP4430_WKUPDEP_I2C1_IRQ_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_I2C1_IRQ_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_I2C1_IRQ_DUCATI_MASK (1 << 1)
/* Used by PM_L4PER_I2C1_WKDEP */
#define OMAP4430_WKUPDEP_I2C1_IRQ_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_I2C1_IRQ_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_I2C1_IRQ_MPU_MASK (1 << 0)
/* Used by PM_L4PER_I2C2_WKDEP */
#define OMAP4430_WKUPDEP_I2C2_DMA_SDMA_SHIFT 7
-#define OMAP4430_WKUPDEP_I2C2_DMA_SDMA_MASK BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_I2C2_DMA_SDMA_MASK (1 << 7)
/* Used by PM_L4PER_I2C2_WKDEP */
#define OMAP4430_WKUPDEP_I2C2_IRQ_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_I2C2_IRQ_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_I2C2_IRQ_DUCATI_MASK (1 << 1)
/* Used by PM_L4PER_I2C2_WKDEP */
#define OMAP4430_WKUPDEP_I2C2_IRQ_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_I2C2_IRQ_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_I2C2_IRQ_MPU_MASK (1 << 0)
/* Used by PM_L4PER_I2C3_WKDEP */
#define OMAP4430_WKUPDEP_I2C3_DMA_SDMA_SHIFT 7
-#define OMAP4430_WKUPDEP_I2C3_DMA_SDMA_MASK BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_I2C3_DMA_SDMA_MASK (1 << 7)
/* Used by PM_L4PER_I2C3_WKDEP */
#define OMAP4430_WKUPDEP_I2C3_IRQ_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_I2C3_IRQ_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_I2C3_IRQ_DUCATI_MASK (1 << 1)
/* Used by PM_L4PER_I2C3_WKDEP */
#define OMAP4430_WKUPDEP_I2C3_IRQ_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_I2C3_IRQ_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_I2C3_IRQ_MPU_MASK (1 << 0)
/* Used by PM_L4PER_I2C4_WKDEP */
#define OMAP4430_WKUPDEP_I2C4_DMA_SDMA_SHIFT 7
-#define OMAP4430_WKUPDEP_I2C4_DMA_SDMA_MASK BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_I2C4_DMA_SDMA_MASK (1 << 7)
/* Used by PM_L4PER_I2C4_WKDEP */
#define OMAP4430_WKUPDEP_I2C4_IRQ_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_I2C4_IRQ_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_I2C4_IRQ_DUCATI_MASK (1 << 1)
/* Used by PM_L4PER_I2C4_WKDEP */
#define OMAP4430_WKUPDEP_I2C4_IRQ_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_I2C4_IRQ_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_I2C4_IRQ_MPU_MASK (1 << 0)
/* Used by PM_L4PER_I2C5_WKDEP */
#define OMAP4430_WKUPDEP_I2C5_DMA_SDMA_SHIFT 7
-#define OMAP4430_WKUPDEP_I2C5_DMA_SDMA_MASK BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_I2C5_DMA_SDMA_MASK (1 << 7)
/* Used by PM_L4PER_I2C5_WKDEP */
#define OMAP4430_WKUPDEP_I2C5_IRQ_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_I2C5_IRQ_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_I2C5_IRQ_MPU_MASK (1 << 0)
/* Used by PM_WKUP_KEYBOARD_WKDEP */
#define OMAP4430_WKUPDEP_KEYBOARD_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_KEYBOARD_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_KEYBOARD_MPU_MASK (1 << 0)
/* Used by PM_ABE_MCASP_WKDEP */
#define OMAP4430_WKUPDEP_MCASP1_DMA_SDMA_SHIFT 7
-#define OMAP4430_WKUPDEP_MCASP1_DMA_SDMA_MASK BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_MCASP1_DMA_SDMA_MASK (1 << 7)
/* Used by PM_ABE_MCASP_WKDEP */
#define OMAP4430_WKUPDEP_MCASP1_DMA_TESLA_SHIFT 6
-#define OMAP4430_WKUPDEP_MCASP1_DMA_TESLA_MASK BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_MCASP1_DMA_TESLA_MASK (1 << 6)
/* Used by PM_ABE_MCASP_WKDEP */
#define OMAP4430_WKUPDEP_MCASP1_IRQ_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MCASP1_IRQ_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCASP1_IRQ_MPU_MASK (1 << 0)
/* Used by PM_ABE_MCASP_WKDEP */
#define OMAP4430_WKUPDEP_MCASP1_IRQ_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_MCASP1_IRQ_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCASP1_IRQ_TESLA_MASK (1 << 2)
/* Used by PM_L4PER_MCASP2_WKDEP */
#define OMAP4430_WKUPDEP_MCASP2_DMA_SDMA_SHIFT 7
-#define OMAP4430_WKUPDEP_MCASP2_DMA_SDMA_MASK BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_MCASP2_DMA_SDMA_MASK (1 << 7)
/* Used by PM_L4PER_MCASP2_WKDEP */
#define OMAP4430_WKUPDEP_MCASP2_DMA_TESLA_SHIFT 6
-#define OMAP4430_WKUPDEP_MCASP2_DMA_TESLA_MASK BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_MCASP2_DMA_TESLA_MASK (1 << 6)
/* Used by PM_L4PER_MCASP2_WKDEP */
#define OMAP4430_WKUPDEP_MCASP2_IRQ_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MCASP2_IRQ_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCASP2_IRQ_MPU_MASK (1 << 0)
/* Used by PM_L4PER_MCASP2_WKDEP */
#define OMAP4430_WKUPDEP_MCASP2_IRQ_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_MCASP2_IRQ_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCASP2_IRQ_TESLA_MASK (1 << 2)
/* Used by PM_L4PER_MCASP3_WKDEP */
#define OMAP4430_WKUPDEP_MCASP3_DMA_SDMA_SHIFT 7
-#define OMAP4430_WKUPDEP_MCASP3_DMA_SDMA_MASK BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_MCASP3_DMA_SDMA_MASK (1 << 7)
/* Used by PM_L4PER_MCASP3_WKDEP */
#define OMAP4430_WKUPDEP_MCASP3_DMA_TESLA_SHIFT 6
-#define OMAP4430_WKUPDEP_MCASP3_DMA_TESLA_MASK BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_MCASP3_DMA_TESLA_MASK (1 << 6)
/* Used by PM_L4PER_MCASP3_WKDEP */
#define OMAP4430_WKUPDEP_MCASP3_IRQ_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MCASP3_IRQ_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCASP3_IRQ_MPU_MASK (1 << 0)
/* Used by PM_L4PER_MCASP3_WKDEP */
#define OMAP4430_WKUPDEP_MCASP3_IRQ_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_MCASP3_IRQ_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCASP3_IRQ_TESLA_MASK (1 << 2)
/* Used by PM_ABE_MCBSP1_WKDEP */
#define OMAP4430_WKUPDEP_MCBSP1_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MCBSP1_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCBSP1_MPU_MASK (1 << 0)
/* Used by PM_ABE_MCBSP1_WKDEP */
#define OMAP4430_WKUPDEP_MCBSP1_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_MCBSP1_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCBSP1_SDMA_MASK (1 << 3)
/* Used by PM_ABE_MCBSP1_WKDEP */
#define OMAP4430_WKUPDEP_MCBSP1_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_MCBSP1_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCBSP1_TESLA_MASK (1 << 2)
/* Used by PM_ABE_MCBSP2_WKDEP */
#define OMAP4430_WKUPDEP_MCBSP2_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MCBSP2_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCBSP2_MPU_MASK (1 << 0)
/* Used by PM_ABE_MCBSP2_WKDEP */
#define OMAP4430_WKUPDEP_MCBSP2_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_MCBSP2_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCBSP2_SDMA_MASK (1 << 3)
/* Used by PM_ABE_MCBSP2_WKDEP */
#define OMAP4430_WKUPDEP_MCBSP2_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_MCBSP2_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCBSP2_TESLA_MASK (1 << 2)
/* Used by PM_ABE_MCBSP3_WKDEP */
#define OMAP4430_WKUPDEP_MCBSP3_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MCBSP3_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCBSP3_MPU_MASK (1 << 0)
/* Used by PM_ABE_MCBSP3_WKDEP */
#define OMAP4430_WKUPDEP_MCBSP3_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_MCBSP3_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCBSP3_SDMA_MASK (1 << 3)
/* Used by PM_ABE_MCBSP3_WKDEP */
#define OMAP4430_WKUPDEP_MCBSP3_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_MCBSP3_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCBSP3_TESLA_MASK (1 << 2)
/* Used by PM_L4PER_MCBSP4_WKDEP */
#define OMAP4430_WKUPDEP_MCBSP4_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MCBSP4_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCBSP4_MPU_MASK (1 << 0)
/* Used by PM_L4PER_MCBSP4_WKDEP */
#define OMAP4430_WKUPDEP_MCBSP4_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_MCBSP4_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCBSP4_SDMA_MASK (1 << 3)
/* Used by PM_L4PER_MCBSP4_WKDEP */
#define OMAP4430_WKUPDEP_MCBSP4_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_MCBSP4_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCBSP4_TESLA_MASK (1 << 2)
/* Used by PM_L4PER_MCSPI1_WKDEP */
#define OMAP4430_WKUPDEP_MCSPI1_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_MCSPI1_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MCSPI1_DUCATI_MASK (1 << 1)
/* Used by PM_L4PER_MCSPI1_WKDEP */
#define OMAP4430_WKUPDEP_MCSPI1_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MCSPI1_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCSPI1_MPU_MASK (1 << 0)
/* Used by PM_L4PER_MCSPI1_WKDEP */
#define OMAP4430_WKUPDEP_MCSPI1_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_MCSPI1_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCSPI1_SDMA_MASK (1 << 3)
/* Used by PM_L4PER_MCSPI1_WKDEP */
#define OMAP4430_WKUPDEP_MCSPI1_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_MCSPI1_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCSPI1_TESLA_MASK (1 << 2)
/* Used by PM_L4PER_MCSPI2_WKDEP */
#define OMAP4430_WKUPDEP_MCSPI2_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_MCSPI2_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MCSPI2_DUCATI_MASK (1 << 1)
/* Used by PM_L4PER_MCSPI2_WKDEP */
#define OMAP4430_WKUPDEP_MCSPI2_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MCSPI2_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCSPI2_MPU_MASK (1 << 0)
/* Used by PM_L4PER_MCSPI2_WKDEP */
#define OMAP4430_WKUPDEP_MCSPI2_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_MCSPI2_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCSPI2_SDMA_MASK (1 << 3)
/* Used by PM_L4PER_MCSPI3_WKDEP */
#define OMAP4430_WKUPDEP_MCSPI3_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MCSPI3_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCSPI3_MPU_MASK (1 << 0)
/* Used by PM_L4PER_MCSPI3_WKDEP */
#define OMAP4430_WKUPDEP_MCSPI3_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_MCSPI3_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCSPI3_SDMA_MASK (1 << 3)
/* Used by PM_L4PER_MCSPI4_WKDEP */
#define OMAP4430_WKUPDEP_MCSPI4_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MCSPI4_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCSPI4_MPU_MASK (1 << 0)
/* Used by PM_L4PER_MCSPI4_WKDEP */
#define OMAP4430_WKUPDEP_MCSPI4_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_MCSPI4_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCSPI4_SDMA_MASK (1 << 3)
/* Used by PM_L3INIT_MMC1_WKDEP */
#define OMAP4430_WKUPDEP_MMC1_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_MMC1_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMC1_DUCATI_MASK (1 << 1)
/* Used by PM_L3INIT_MMC1_WKDEP */
#define OMAP4430_WKUPDEP_MMC1_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MMC1_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMC1_MPU_MASK (1 << 0)
/* Used by PM_L3INIT_MMC1_WKDEP */
#define OMAP4430_WKUPDEP_MMC1_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_MMC1_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MMC1_SDMA_MASK (1 << 3)
/* Used by PM_L3INIT_MMC1_WKDEP */
#define OMAP4430_WKUPDEP_MMC1_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_MMC1_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MMC1_TESLA_MASK (1 << 2)
/* Used by PM_L3INIT_MMC2_WKDEP */
#define OMAP4430_WKUPDEP_MMC2_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_MMC2_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMC2_DUCATI_MASK (1 << 1)
/* Used by PM_L3INIT_MMC2_WKDEP */
#define OMAP4430_WKUPDEP_MMC2_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MMC2_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMC2_MPU_MASK (1 << 0)
/* Used by PM_L3INIT_MMC2_WKDEP */
#define OMAP4430_WKUPDEP_MMC2_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_MMC2_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MMC2_SDMA_MASK (1 << 3)
/* Used by PM_L3INIT_MMC2_WKDEP */
#define OMAP4430_WKUPDEP_MMC2_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_MMC2_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MMC2_TESLA_MASK (1 << 2)
/* Used by PM_L3INIT_MMC6_WKDEP */
#define OMAP4430_WKUPDEP_MMC6_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_MMC6_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMC6_DUCATI_MASK (1 << 1)
/* Used by PM_L3INIT_MMC6_WKDEP */
#define OMAP4430_WKUPDEP_MMC6_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MMC6_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMC6_MPU_MASK (1 << 0)
/* Used by PM_L3INIT_MMC6_WKDEP */
#define OMAP4430_WKUPDEP_MMC6_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_MMC6_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MMC6_TESLA_MASK (1 << 2)
/* Used by PM_L4PER_MMCSD3_WKDEP */
#define OMAP4430_WKUPDEP_MMCSD3_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_MMCSD3_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMCSD3_DUCATI_MASK (1 << 1)
/* Used by PM_L4PER_MMCSD3_WKDEP */
#define OMAP4430_WKUPDEP_MMCSD3_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MMCSD3_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMCSD3_MPU_MASK (1 << 0)
/* Used by PM_L4PER_MMCSD3_WKDEP */
#define OMAP4430_WKUPDEP_MMCSD3_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_MMCSD3_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MMCSD3_SDMA_MASK (1 << 3)
/* Used by PM_L4PER_MMCSD4_WKDEP */
#define OMAP4430_WKUPDEP_MMCSD4_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_MMCSD4_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMCSD4_DUCATI_MASK (1 << 1)
/* Used by PM_L4PER_MMCSD4_WKDEP */
#define OMAP4430_WKUPDEP_MMCSD4_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MMCSD4_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMCSD4_MPU_MASK (1 << 0)
/* Used by PM_L4PER_MMCSD4_WKDEP */
#define OMAP4430_WKUPDEP_MMCSD4_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_MMCSD4_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MMCSD4_SDMA_MASK (1 << 3)
/* Used by PM_L4PER_MMCSD5_WKDEP */
#define OMAP4430_WKUPDEP_MMCSD5_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_MMCSD5_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMCSD5_DUCATI_MASK (1 << 1)
/* Used by PM_L4PER_MMCSD5_WKDEP */
#define OMAP4430_WKUPDEP_MMCSD5_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_MMCSD5_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMCSD5_MPU_MASK (1 << 0)
/* Used by PM_L4PER_MMCSD5_WKDEP */
#define OMAP4430_WKUPDEP_MMCSD5_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_MMCSD5_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MMCSD5_SDMA_MASK (1 << 3)
/* Used by PM_L3INIT_PCIESS_WKDEP */
#define OMAP4430_WKUPDEP_PCIESS_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_PCIESS_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_PCIESS_MPU_MASK (1 << 0)
/* Used by PM_L3INIT_PCIESS_WKDEP */
#define OMAP4430_WKUPDEP_PCIESS_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_PCIESS_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_PCIESS_TESLA_MASK (1 << 2)
/* Used by PM_ABE_PDM_WKDEP */
#define OMAP4430_WKUPDEP_PDM_DMA_SDMA_SHIFT 7
-#define OMAP4430_WKUPDEP_PDM_DMA_SDMA_MASK BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_PDM_DMA_SDMA_MASK (1 << 7)
/* Used by PM_ABE_PDM_WKDEP */
#define OMAP4430_WKUPDEP_PDM_DMA_TESLA_SHIFT 6
-#define OMAP4430_WKUPDEP_PDM_DMA_TESLA_MASK BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_PDM_DMA_TESLA_MASK (1 << 6)
/* Used by PM_ABE_PDM_WKDEP */
#define OMAP4430_WKUPDEP_PDM_IRQ_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_PDM_IRQ_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_PDM_IRQ_MPU_MASK (1 << 0)
/* Used by PM_ABE_PDM_WKDEP */
#define OMAP4430_WKUPDEP_PDM_IRQ_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_PDM_IRQ_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_PDM_IRQ_TESLA_MASK (1 << 2)
/* Used by PM_WKUP_RTC_WKDEP */
#define OMAP4430_WKUPDEP_RTC_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_RTC_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_RTC_MPU_MASK (1 << 0)
/* Used by PM_L3INIT_SATA_WKDEP */
#define OMAP4430_WKUPDEP_SATA_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_SATA_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SATA_MPU_MASK (1 << 0)
/* Used by PM_L3INIT_SATA_WKDEP */
#define OMAP4430_WKUPDEP_SATA_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_SATA_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_SATA_TESLA_MASK (1 << 2)
/* Used by PM_ABE_SLIMBUS_WKDEP */
#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_SDMA_SHIFT 7
-#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_SDMA_MASK BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_SDMA_MASK (1 << 7)
/* Used by PM_ABE_SLIMBUS_WKDEP */
#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_TESLA_SHIFT 6
-#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_TESLA_MASK BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_TESLA_MASK (1 << 6)
/* Used by PM_ABE_SLIMBUS_WKDEP */
#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_MPU_MASK (1 << 0)
/* Used by PM_ABE_SLIMBUS_WKDEP */
#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_TESLA_MASK (1 << 2)
/* Used by PM_L4PER_SLIMBUS2_WKDEP */
#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_SDMA_SHIFT 7
-#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_SDMA_MASK BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_SDMA_MASK (1 << 7)
/* Used by PM_L4PER_SLIMBUS2_WKDEP */
#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_TESLA_SHIFT 6
-#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_TESLA_MASK BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_TESLA_MASK (1 << 6)
/* Used by PM_L4PER_SLIMBUS2_WKDEP */
#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_MPU_MASK (1 << 0)
/* Used by PM_L4PER_SLIMBUS2_WKDEP */
#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_TESLA_MASK (1 << 2)
/* Used by PM_ALWON_SR_CORE_WKDEP */
#define OMAP4430_WKUPDEP_SR_CORE_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_SR_CORE_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_SR_CORE_DUCATI_MASK (1 << 1)
/* Used by PM_ALWON_SR_CORE_WKDEP */
#define OMAP4430_WKUPDEP_SR_CORE_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_SR_CORE_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SR_CORE_MPU_MASK (1 << 0)
/* Used by PM_ALWON_SR_IVA_WKDEP */
#define OMAP4430_WKUPDEP_SR_IVA_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_SR_IVA_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_SR_IVA_DUCATI_MASK (1 << 1)
/* Used by PM_ALWON_SR_IVA_WKDEP */
#define OMAP4430_WKUPDEP_SR_IVA_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_SR_IVA_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SR_IVA_MPU_MASK (1 << 0)
/* Used by PM_ALWON_SR_MPU_WKDEP */
#define OMAP4430_WKUPDEP_SR_MPU_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_SR_MPU_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SR_MPU_MPU_MASK (1 << 0)
/* Used by PM_WKUP_TIMER12_WKDEP */
#define OMAP4430_WKUPDEP_TIMER12_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_TIMER12_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER12_MPU_MASK (1 << 0)
/* Used by PM_WKUP_TIMER1_WKDEP */
#define OMAP4430_WKUPDEP_TIMER1_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_TIMER1_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER1_MPU_MASK (1 << 0)
/* Used by PM_ABE_TIMER5_WKDEP */
#define OMAP4430_WKUPDEP_TIMER5_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_TIMER5_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER5_MPU_MASK (1 << 0)
/* Used by PM_ABE_TIMER5_WKDEP */
#define OMAP4430_WKUPDEP_TIMER5_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_TIMER5_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_TIMER5_TESLA_MASK (1 << 2)
/* Used by PM_ABE_TIMER6_WKDEP */
#define OMAP4430_WKUPDEP_TIMER6_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_TIMER6_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER6_MPU_MASK (1 << 0)
/* Used by PM_ABE_TIMER6_WKDEP */
#define OMAP4430_WKUPDEP_TIMER6_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_TIMER6_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_TIMER6_TESLA_MASK (1 << 2)
/* Used by PM_ABE_TIMER7_WKDEP */
#define OMAP4430_WKUPDEP_TIMER7_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_TIMER7_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER7_MPU_MASK (1 << 0)
/* Used by PM_ABE_TIMER7_WKDEP */
#define OMAP4430_WKUPDEP_TIMER7_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_TIMER7_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_TIMER7_TESLA_MASK (1 << 2)
/* Used by PM_ABE_TIMER8_WKDEP */
#define OMAP4430_WKUPDEP_TIMER8_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_TIMER8_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER8_MPU_MASK (1 << 0)
/* Used by PM_ABE_TIMER8_WKDEP */
#define OMAP4430_WKUPDEP_TIMER8_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_TIMER8_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_TIMER8_TESLA_MASK (1 << 2)
/* Used by PM_L4PER_UART1_WKDEP */
#define OMAP4430_WKUPDEP_UART1_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_UART1_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_UART1_MPU_MASK (1 << 0)
/* Used by PM_L4PER_UART1_WKDEP */
#define OMAP4430_WKUPDEP_UART1_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_UART1_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_UART1_SDMA_MASK (1 << 3)
/* Used by PM_L4PER_UART2_WKDEP */
#define OMAP4430_WKUPDEP_UART2_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_UART2_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_UART2_MPU_MASK (1 << 0)
/* Used by PM_L4PER_UART2_WKDEP */
#define OMAP4430_WKUPDEP_UART2_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_UART2_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_UART2_SDMA_MASK (1 << 3)
/* Used by PM_L4PER_UART3_WKDEP */
#define OMAP4430_WKUPDEP_UART3_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_UART3_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_UART3_DUCATI_MASK (1 << 1)
/* Used by PM_L4PER_UART3_WKDEP */
#define OMAP4430_WKUPDEP_UART3_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_UART3_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_UART3_MPU_MASK (1 << 0)
/* Used by PM_L4PER_UART3_WKDEP */
#define OMAP4430_WKUPDEP_UART3_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_UART3_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_UART3_SDMA_MASK (1 << 3)
/* Used by PM_L4PER_UART3_WKDEP */
#define OMAP4430_WKUPDEP_UART3_TESLA_SHIFT 2
-#define OMAP4430_WKUPDEP_UART3_TESLA_MASK BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_UART3_TESLA_MASK (1 << 2)
/* Used by PM_L4PER_UART4_WKDEP */
#define OMAP4430_WKUPDEP_UART4_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_UART4_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_UART4_MPU_MASK (1 << 0)
/* Used by PM_L4PER_UART4_WKDEP */
#define OMAP4430_WKUPDEP_UART4_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_UART4_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_UART4_SDMA_MASK (1 << 3)
/* Used by PM_L3INIT_UNIPRO1_WKDEP */
#define OMAP4430_WKUPDEP_UNIPRO1_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_UNIPRO1_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_UNIPRO1_DUCATI_MASK (1 << 1)
/* Used by PM_L3INIT_UNIPRO1_WKDEP */
#define OMAP4430_WKUPDEP_UNIPRO1_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_UNIPRO1_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_UNIPRO1_MPU_MASK (1 << 0)
/* Used by PM_L3INIT_USB_HOST_WKDEP */
#define OMAP4430_WKUPDEP_USB_HOST_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_USB_HOST_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_USB_HOST_DUCATI_MASK (1 << 1)
/* Used by PM_L3INIT_USB_HOST_FS_WKDEP */
#define OMAP4430_WKUPDEP_USB_HOST_FS_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_USB_HOST_FS_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_USB_HOST_FS_DUCATI_MASK (1 << 1)
/* Used by PM_L3INIT_USB_HOST_FS_WKDEP */
#define OMAP4430_WKUPDEP_USB_HOST_FS_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_USB_HOST_FS_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_USB_HOST_FS_MPU_MASK (1 << 0)
/* Used by PM_L3INIT_USB_HOST_WKDEP */
#define OMAP4430_WKUPDEP_USB_HOST_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_USB_HOST_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_USB_HOST_MPU_MASK (1 << 0)
/* Used by PM_L3INIT_USB_OTG_WKDEP */
#define OMAP4430_WKUPDEP_USB_OTG_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_USB_OTG_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_USB_OTG_DUCATI_MASK (1 << 1)
/* Used by PM_L3INIT_USB_OTG_WKDEP */
#define OMAP4430_WKUPDEP_USB_OTG_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_USB_OTG_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_USB_OTG_MPU_MASK (1 << 0)
/* Used by PM_L3INIT_USB_TLL_WKDEP */
#define OMAP4430_WKUPDEP_USB_TLL_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_USB_TLL_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_USB_TLL_DUCATI_MASK (1 << 1)
/* Used by PM_L3INIT_USB_TLL_WKDEP */
#define OMAP4430_WKUPDEP_USB_TLL_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_USB_TLL_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_USB_TLL_MPU_MASK (1 << 0)
/* Used by PM_WKUP_USIM_WKDEP */
#define OMAP4430_WKUPDEP_USIM_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_USIM_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_USIM_MPU_MASK (1 << 0)
/* Used by PM_WKUP_USIM_WKDEP */
#define OMAP4430_WKUPDEP_USIM_SDMA_SHIFT 3
-#define OMAP4430_WKUPDEP_USIM_SDMA_MASK BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_USIM_SDMA_MASK (1 << 3)
/* Used by PM_WKUP_WDT2_WKDEP */
#define OMAP4430_WKUPDEP_WDT2_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_WDT2_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_WDT2_DUCATI_MASK (1 << 1)
/* Used by PM_WKUP_WDT2_WKDEP */
#define OMAP4430_WKUPDEP_WDT2_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_WDT2_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_WDT2_MPU_MASK (1 << 0)
/* Used by PM_ABE_WDT3_WKDEP */
#define OMAP4430_WKUPDEP_WDT3_MPU_SHIFT 0
-#define OMAP4430_WKUPDEP_WDT3_MPU_MASK BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_WDT3_MPU_MASK (1 << 0)
/* Used by PM_L3INIT_HSI_WKDEP */
#define OMAP4430_WKUPDEP_WGM_HSI_WAKE_MPU_SHIFT 8
-#define OMAP4430_WKUPDEP_WGM_HSI_WAKE_MPU_MASK BITFIELD(8, 8)
+#define OMAP4430_WKUPDEP_WGM_HSI_WAKE_MPU_MASK (1 << 8)
/* Used by PM_L3INIT_XHPI_WKDEP */
#define OMAP4430_WKUPDEP_XHPI_DUCATI_SHIFT 1
-#define OMAP4430_WKUPDEP_XHPI_DUCATI_MASK BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_XHPI_DUCATI_MASK (1 << 1)
/* Used by PRM_IO_PMCTRL */
#define OMAP4430_WUCLK_CTRL_SHIFT 8
-#define OMAP4430_WUCLK_CTRL_MASK BITFIELD(8, 8)
+#define OMAP4430_WUCLK_CTRL_MASK (1 << 8)
/* Used by PRM_IO_PMCTRL */
#define OMAP4430_WUCLK_STATUS_SHIFT 9
-#define OMAP4430_WUCLK_STATUS_MASK BITFIELD(9, 9)
+#define OMAP4430_WUCLK_STATUS_MASK (1 << 9)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_X_MAJOR_SHIFT 8
+#define OMAP4430_X_MAJOR_MASK (0x7 << 8)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_Y_MINOR_SHIFT 0
+#define OMAP4430_Y_MINOR_MASK (0x3f << 0)
#endif
diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h
index 588873b9303a..7be040b2fdab 100644
--- a/arch/arm/mach-omap2/prm.h
+++ b/arch/arm/mach-omap2/prm.h
@@ -5,7 +5,7 @@
* OMAP2/3 Power/Reset Management (PRM) register definitions
*
* Copyright (C) 2007-2009 Texas Instruments, Inc.
- * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2010 Nokia Corporation
*
* Written by Paul Walmsley
*
@@ -246,6 +246,15 @@ static inline u32 prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx)
return prm_rmw_mod_reg_bits(bits, 0x0, module, idx);
}
+/* These omap2_ PRM functions apply to both OMAP2 and 3 */
+int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift);
+int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift);
+int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift);
+
+int omap4_prm_is_hardreset_asserted(void __iomem *rstctrl_reg, u8 shift);
+int omap4_prm_assert_hardreset(void __iomem *rstctrl_reg, u8 shift);
+int omap4_prm_deassert_hardreset(void __iomem *rstctrl_reg, u8 shift);
+
#endif
/*
@@ -398,4 +407,11 @@ static inline u32 prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx)
#define OMAP_POWERSTATE_MASK (0x3 << 0)
+/*
+ * MAX_MODULE_HARDRESET_WAIT: Maximum microseconds to wait for an OMAP
+ * submodule to exit hardreset
+ */
+#define MAX_MODULE_HARDRESET_WAIT 10000
+
+
#endif
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
new file mode 100644
index 000000000000..421771eee450
--- /dev/null
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -0,0 +1,110 @@
+/*
+ * OMAP2/3 PRM module functions
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Copyright (C) 2010 Nokia Corporation
+ * Benoît Cousson
+ * Paul Walmsley
+ *
+ * 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/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include <plat/common.h>
+#include <plat/cpu.h>
+#include <plat/prcm.h>
+
+#include "prm.h"
+#include "prm-regbits-24xx.h"
+#include "prm-regbits-34xx.h"
+
+/**
+ * omap2_prm_is_hardreset_asserted - read the HW reset line state of
+ * submodules contained in the hwmod module
+ * @prm_mod: PRM submodule base (e.g. CORE_MOD)
+ * @shift: register bit shift corresponding to the reset line to check
+ *
+ * Returns 1 if the (sub)module hardreset line is currently asserted,
+ * 0 if the (sub)module hardreset line is not currently asserted, or
+ * -EINVAL if called while running on a non-OMAP2/3 chip.
+ */
+int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift)
+{
+ if (!(cpu_is_omap24xx() || cpu_is_omap34xx()))
+ return -EINVAL;
+
+ return prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL,
+ (1 << shift));
+}
+
+/**
+ * omap2_prm_assert_hardreset - assert the HW reset line of a submodule
+ * @prm_mod: PRM submodule base (e.g. CORE_MOD)
+ * @shift: register bit shift corresponding to the reset line to assert
+ *
+ * Some IPs like dsp or iva contain processors that require an HW
+ * reset line to be asserted / deasserted in order to fully enable the
+ * IP. These modules may have multiple hard-reset lines that reset
+ * different 'submodules' inside the IP block. This function will
+ * place the submodule into reset. Returns 0 upon success or -EINVAL
+ * upon an argument error.
+ */
+int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift)
+{
+ u32 mask;
+
+ if (!(cpu_is_omap24xx() || cpu_is_omap34xx()))
+ return -EINVAL;
+
+ mask = 1 << shift;
+ prm_rmw_mod_reg_bits(mask, mask, prm_mod, OMAP2_RM_RSTCTRL);
+
+ return 0;
+}
+
+/**
+ * omap2_prm_deassert_hardreset - deassert a submodule hardreset line and wait
+ * @prm_mod: PRM submodule base (e.g. CORE_MOD)
+ * @shift: register bit shift corresponding to the reset line to deassert
+ *
+ * Some IPs like dsp or iva contain processors that require an HW
+ * reset line to be asserted / deasserted in order to fully enable the
+ * IP. These modules may have multiple hard-reset lines that reset
+ * different 'submodules' inside the IP block. This function will
+ * take the submodule out of reset and wait until the PRCM indicates
+ * that the reset has completed before returning. Returns 0 upon success or
+ * -EINVAL upon an argument error, -EEXIST if the submodule was already out
+ * of reset, or -EBUSY if the submodule did not exit reset promptly.
+ */
+int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift)
+{
+ u32 mask;
+ int c;
+
+ if (!(cpu_is_omap24xx() || cpu_is_omap34xx()))
+ return -EINVAL;
+
+ mask = 1 << shift;
+
+ /* Check the current status to avoid de-asserting the line twice */
+ if (prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, mask) == 0)
+ return -EEXIST;
+
+ /* Clear the reset status by writing 1 to the status bit */
+ prm_rmw_mod_reg_bits(0xffffffff, mask, prm_mod, OMAP2_RM_RSTST);
+ /* de-assert the reset control line */
+ prm_rmw_mod_reg_bits(mask, 0, prm_mod, OMAP2_RM_RSTCTRL);
+ /* wait the status to be set */
+ omap_test_timeout(prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTST,
+ mask),
+ MAX_MODULE_HARDRESET_WAIT, c);
+
+ return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
+}
+
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
new file mode 100644
index 000000000000..a1ff918d9bed
--- /dev/null
+++ b/arch/arm/mach-omap2/prm44xx.c
@@ -0,0 +1,116 @@
+/*
+ * OMAP4 PRM module functions
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Copyright (C) 2010 Nokia Corporation
+ * Benoît Cousson
+ * Paul Walmsley
+ *
+ * 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/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include <plat/common.h>
+#include <plat/cpu.h>
+#include <plat/prcm.h>
+
+#include "prm.h"
+#include "prm-regbits-44xx.h"
+
+/*
+ * Address offset (in bytes) between the reset control and the reset
+ * status registers: 4 bytes on OMAP4
+ */
+#define OMAP4_RST_CTRL_ST_OFFSET 4
+
+/**
+ * omap4_prm_is_hardreset_asserted - read the HW reset line state of
+ * submodules contained in the hwmod module
+ * @rstctrl_reg: RM_RSTCTRL register address for this module
+ * @shift: register bit shift corresponding to the reset line to check
+ *
+ * Returns 1 if the (sub)module hardreset line is currently asserted,
+ * 0 if the (sub)module hardreset line is not currently asserted, or
+ * -EINVAL upon parameter error.
+ */
+int omap4_prm_is_hardreset_asserted(void __iomem *rstctrl_reg, u8 shift)
+{
+ if (!cpu_is_omap44xx() || !rstctrl_reg)
+ return -EINVAL;
+
+ return omap4_prm_read_bits_shift(rstctrl_reg, (1 << shift));
+}
+
+/**
+ * omap4_prm_assert_hardreset - assert the HW reset line of a submodule
+ * @rstctrl_reg: RM_RSTCTRL register address for this module
+ * @shift: register bit shift corresponding to the reset line to assert
+ *
+ * Some IPs like dsp, ipu or iva contain processors that require an HW
+ * reset line to be asserted / deasserted in order to fully enable the
+ * IP. These modules may have multiple hard-reset lines that reset
+ * different 'submodules' inside the IP block. This function will
+ * place the submodule into reset. Returns 0 upon success or -EINVAL
+ * upon an argument error.
+ */
+int omap4_prm_assert_hardreset(void __iomem *rstctrl_reg, u8 shift)
+{
+ u32 mask;
+
+ if (!cpu_is_omap44xx() || !rstctrl_reg)
+ return -EINVAL;
+
+ mask = 1 << shift;
+ omap4_prm_rmw_reg_bits(mask, mask, rstctrl_reg);
+
+ return 0;
+}
+
+/**
+ * omap4_prm_deassert_hardreset - deassert a submodule hardreset line and wait
+ * @rstctrl_reg: RM_RSTCTRL register address for this module
+ * @shift: register bit shift corresponding to the reset line to deassert
+ *
+ * Some IPs like dsp, ipu or iva contain processors that require an HW
+ * reset line to be asserted / deasserted in order to fully enable the
+ * IP. These modules may have multiple hard-reset lines that reset
+ * different 'submodules' inside the IP block. This function will
+ * take the submodule out of reset and wait until the PRCM indicates
+ * that the reset has completed before returning. Returns 0 upon success or
+ * -EINVAL upon an argument error, -EEXIST if the submodule was already out
+ * of reset, or -EBUSY if the submodule did not exit reset promptly.
+ */
+int omap4_prm_deassert_hardreset(void __iomem *rstctrl_reg, u8 shift)
+{
+ u32 mask;
+ void __iomem *rstst_reg;
+ int c;
+
+ if (!cpu_is_omap44xx() || !rstctrl_reg)
+ return -EINVAL;
+
+ rstst_reg = rstctrl_reg + OMAP4_RST_CTRL_ST_OFFSET;
+
+ mask = 1 << shift;
+
+ /* Check the current status to avoid de-asserting the line twice */
+ if (omap4_prm_read_bits_shift(rstctrl_reg, mask) == 0)
+ return -EEXIST;
+
+ /* Clear the reset status by writing 1 to the status bit */
+ omap4_prm_rmw_reg_bits(0xffffffff, mask, rstst_reg);
+ /* de-assert the reset control line */
+ omap4_prm_rmw_reg_bits(mask, 0, rstctrl_reg);
+ /* wait the status to be set */
+ omap_test_timeout(omap4_prm_read_bits_shift(rstst_reg, mask),
+ MAX_MODULE_HARDRESET_WAIT, c);
+
+ return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
+}
+
diff --git a/arch/arm/mach-omap2/prm44xx.h b/arch/arm/mach-omap2/prm44xx.h
index fe8ef26431e5..59839dbabd84 100644
--- a/arch/arm/mach-omap2/prm44xx.h
+++ b/arch/arm/mach-omap2/prm44xx.h
@@ -44,14 +44,12 @@
#define OMAP4430_PRM_IRQSTATUS_TESLA OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_MOD, 0x0030)
#define OMAP4_PRM_IRQENABLE_TESLA_OFFSET 0x0038
#define OMAP4430_PRM_IRQENABLE_TESLA OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_MOD, 0x0038)
-#define OMAP4_PRM_PRM_PROFILING_CLKCTRL_OFFSET 0x0040
-#define OMAP4430_PRM_PRM_PROFILING_CLKCTRL OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_MOD, 0x0040)
+#define OMAP4_CM_PRM_PROFILING_CLKCTRL_OFFSET 0x0040
+#define OMAP4430_CM_PRM_PROFILING_CLKCTRL OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_MOD, 0x0040)
/* PRM.CKGEN_PRM register offsets */
#define OMAP4_CM_ABE_DSS_SYS_CLKSEL_OFFSET 0x0000
#define OMAP4430_CM_ABE_DSS_SYS_CLKSEL OMAP44XX_PRM_REGADDR(OMAP4430_PRM_CKGEN_MOD, 0x0000)
-#define OMAP4_CM_DPLL_SYS_REF_CLKSEL_OFFSET 0x0004
-#define OMAP4430_CM_DPLL_SYS_REF_CLKSEL OMAP44XX_PRM_REGADDR(OMAP4430_PRM_CKGEN_MOD, 0x0004)
#define OMAP4_CM_L4_WKUP_CLKSEL_OFFSET 0x0008
#define OMAP4430_CM_L4_WKUP_CLKSEL OMAP44XX_PRM_REGADDR(OMAP4430_PRM_CKGEN_MOD, 0x0008)
#define OMAP4_CM_ABE_PLL_REF_CLKSEL_OFFSET 0x000c
@@ -686,8 +684,8 @@
#define OMAP4430_PRM_LDO_ABB_IVA_SETUP OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00d8)
#define OMAP4_PRM_LDO_ABB_IVA_CTRL_OFFSET 0x00dc
#define OMAP4430_PRM_LDO_ABB_IVA_CTRL OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00dc)
-#define OMAP4_PRM_LDO_BANDGAP_CTRL_OFFSET 0x00e0
-#define OMAP4430_PRM_LDO_BANDGAP_CTRL OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00e0)
+#define OMAP4_PRM_LDO_BANDGAP_SETUP_OFFSET 0x00e0
+#define OMAP4430_PRM_LDO_BANDGAP_SETUP OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00e0)
#define OMAP4_PRM_DEVICE_OFF_CTRL_OFFSET 0x00e4
#define OMAP4430_PRM_DEVICE_OFF_CTRL OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00e4)
#define OMAP4_PRM_PHASE1_CNDP_OFFSET 0x00e8
@@ -698,6 +696,8 @@
#define OMAP4430_PRM_PHASE2B_CNDP OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00f0)
#define OMAP4_PRM_MODEM_IF_CTRL_OFFSET 0x00f4
#define OMAP4430_PRM_MODEM_IF_CTRL OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00f4)
+#define OMAP4_PRM_VC_ERRST_OFFSET 0x00f8
+#define OMAP4430_PRM_VC_ERRST OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00f8)
/*
* PRCM_MPU
@@ -715,6 +715,8 @@
/* PRCM_MPU.DEVICE_PRM register offsets */
#define OMAP4_PRCM_MPU_PRM_RSTST_OFFSET 0x0000
#define OMAP4430_PRCM_MPU_PRM_RSTST OMAP44XX_PRCM_MPU_REGADDR(OMAP4430_PRCM_MPU_DEVICE_PRM_MOD, 0x0000)
+#define OMAP4_PRCM_MPU_PRM_PSCON_COUNT_OFFSET 0x0004
+#define OMAP4430_PRCM_MPU_PRM_PSCON_COUNT OMAP44XX_PRCM_MPU_REGADDR(OMAP4430_PRCM_MPU_DEVICE_PRM_MOD, 0x0004)
/* PRCM_MPU.CPU0 register offsets */
#define OMAP4_PM_CPU0_PWRSTCTRL_OFFSET 0x0000
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 566e991ede81..becf0e38ef7e 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -19,20 +19,31 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/serial_8250.h>
#include <linux/serial_reg.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/serial_8250.h>
+#include <linux/pm_runtime.h>
+
+#ifdef CONFIG_SERIAL_OMAP
+#include <plat/omap-serial.h>
+#endif
#include <plat/common.h>
#include <plat/board.h>
#include <plat/clock.h>
-#include <plat/control.h>
+#include <plat/dma.h>
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
#include "prm.h"
#include "pm.h"
+#include "cm.h"
#include "prm-regbits-34xx.h"
+#include "control.h"
#define UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV 0x52
#define UART_OMAP_WER 0x17 /* Wake-up enable register */
@@ -48,6 +59,8 @@
*/
#define DEFAULT_TIMEOUT 0
+#define MAX_UART_HWMOD_NAME_LEN 16
+
struct omap_uart_state {
int num;
int can_sleep;
@@ -58,14 +71,21 @@ struct omap_uart_state {
void __iomem *wk_en;
u32 wk_mask;
u32 padconf;
+ u32 dma_enabled;
struct clk *ick;
struct clk *fck;
int clocked;
- struct plat_serial8250_port *p;
+ int irq;
+ int regshift;
+ int irqflags;
+ void __iomem *membase;
+ resource_size_t mapbase;
+
struct list_head node;
- struct platform_device pdev;
+ struct omap_hwmod *oh;
+ struct platform_device *pdev;
u32 errata;
#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
@@ -83,75 +103,47 @@ struct omap_uart_state {
};
static LIST_HEAD(uart_list);
+static u8 num_uarts;
-static struct plat_serial8250_port serial_platform_data0[] = {
- {
- .irq = 72,
- .flags = UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = OMAP24XX_BASE_BAUD * 16,
- }, {
- .flags = 0
- }
-};
+/*
+ * Since these idle/enable hooks are used in the idle path itself
+ * which has interrupts disabled, use the non-locking versions of
+ * the hwmod enable/disable functions.
+ */
+static int uart_idle_hwmod(struct omap_device *od)
+{
+ _omap_hwmod_idle(od->hwmods[0]);
-static struct plat_serial8250_port serial_platform_data1[] = {
- {
- .irq = 73,
- .flags = UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = OMAP24XX_BASE_BAUD * 16,
- }, {
- .flags = 0
- }
-};
+ return 0;
+}
-static struct plat_serial8250_port serial_platform_data2[] = {
- {
- .irq = 74,
- .flags = UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = OMAP24XX_BASE_BAUD * 16,
- }, {
- .flags = 0
- }
-};
+static int uart_enable_hwmod(struct omap_device *od)
+{
+ _omap_hwmod_enable(od->hwmods[0]);
-static struct plat_serial8250_port serial_platform_data3[] = {
+ return 0;
+}
+
+static struct omap_device_pm_latency omap_uart_latency[] = {
{
- .irq = 70,
- .flags = UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = OMAP24XX_BASE_BAUD * 16,
- }, {
- .flags = 0
- }
+ .deactivate_func = uart_idle_hwmod,
+ .activate_func = uart_enable_hwmod,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ },
};
-void __init omap2_set_globals_uart(struct omap_globals *omap2_globals)
-{
- serial_platform_data0[0].mapbase = omap2_globals->uart1_phys;
- serial_platform_data1[0].mapbase = omap2_globals->uart2_phys;
- serial_platform_data2[0].mapbase = omap2_globals->uart3_phys;
- serial_platform_data3[0].mapbase = omap2_globals->uart4_phys;
-}
-
static inline unsigned int __serial_read_reg(struct uart_port *up,
- int offset)
+ int offset)
{
offset <<= up->regshift;
return (unsigned int)__raw_readb(up->membase + offset);
}
-static inline unsigned int serial_read_reg(struct plat_serial8250_port *up,
+static inline unsigned int serial_read_reg(struct omap_uart_state *uart,
int offset)
{
- offset <<= up->regshift;
- return (unsigned int)__raw_readb(up->membase + offset);
+ offset <<= uart->regshift;
+ return (unsigned int)__raw_readb(uart->membase + offset);
}
static inline void __serial_write_reg(struct uart_port *up, int offset,
@@ -161,11 +153,11 @@ static inline void __serial_write_reg(struct uart_port *up, int offset,
__raw_writeb(value, up->membase + offset);
}
-static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
+static inline void serial_write_reg(struct omap_uart_state *uart, int offset,
int value)
{
- offset <<= p->regshift;
- __raw_writeb(value, p->membase + offset);
+ offset <<= uart->regshift;
+ __raw_writeb(value, uart->membase + offset);
}
/*
@@ -173,14 +165,12 @@ static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
* properly. Note that the TX watermark initialization may not be needed
* once the 8250.c watermark handling code is merged.
*/
+
static inline void __init omap_uart_reset(struct omap_uart_state *uart)
{
- struct plat_serial8250_port *p = uart->p;
-
- serial_write_reg(p, UART_OMAP_MDR1, 0x07);
- serial_write_reg(p, UART_OMAP_SCR, 0x08);
- serial_write_reg(p, UART_OMAP_MDR1, 0x00);
- serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
+ serial_write_reg(uart, UART_OMAP_MDR1, 0x07);
+ serial_write_reg(uart, UART_OMAP_SCR, 0x08);
+ serial_write_reg(uart, UART_OMAP_MDR1, 0x00);
}
#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
@@ -197,24 +187,23 @@ static inline void __init omap_uart_reset(struct omap_uart_state *uart)
static void omap_uart_mdr1_errataset(struct omap_uart_state *uart, u8 mdr1_val,
u8 fcr_val)
{
- struct plat_serial8250_port *p = uart->p;
u8 timeout = 255;
- serial_write_reg(p, UART_OMAP_MDR1, mdr1_val);
+ serial_write_reg(uart, UART_OMAP_MDR1, mdr1_val);
udelay(2);
- serial_write_reg(p, UART_FCR, fcr_val | UART_FCR_CLEAR_XMIT |
+ serial_write_reg(uart, UART_FCR, fcr_val | UART_FCR_CLEAR_XMIT |
UART_FCR_CLEAR_RCVR);
/*
* Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and
* TX_FIFO_E bit is 1.
*/
- while (UART_LSR_THRE != (serial_read_reg(p, UART_LSR) &
+ while (UART_LSR_THRE != (serial_read_reg(uart, UART_LSR) &
(UART_LSR_THRE | UART_LSR_DR))) {
timeout--;
if (!timeout) {
/* Should *never* happen. we warn and carry on */
- dev_crit(&uart->pdev.dev, "Errata i202: timedout %x\n",
- serial_read_reg(p, UART_LSR));
+ dev_crit(&uart->pdev->dev, "Errata i202: timedout %x\n",
+ serial_read_reg(uart, UART_LSR));
break;
}
udelay(1);
@@ -224,23 +213,22 @@ static void omap_uart_mdr1_errataset(struct omap_uart_state *uart, u8 mdr1_val,
static void omap_uart_save_context(struct omap_uart_state *uart)
{
u16 lcr = 0;
- struct plat_serial8250_port *p = uart->p;
if (!enable_off_mode)
return;
- lcr = serial_read_reg(p, UART_LCR);
- serial_write_reg(p, UART_LCR, 0xBF);
- uart->dll = serial_read_reg(p, UART_DLL);
- uart->dlh = serial_read_reg(p, UART_DLM);
- serial_write_reg(p, UART_LCR, lcr);
- uart->ier = serial_read_reg(p, UART_IER);
- uart->sysc = serial_read_reg(p, UART_OMAP_SYSC);
- uart->scr = serial_read_reg(p, UART_OMAP_SCR);
- uart->wer = serial_read_reg(p, UART_OMAP_WER);
- serial_write_reg(p, UART_LCR, 0x80);
- uart->mcr = serial_read_reg(p, UART_MCR);
- serial_write_reg(p, UART_LCR, lcr);
+ lcr = serial_read_reg(uart, UART_LCR);
+ serial_write_reg(uart, UART_LCR, 0xBF);
+ uart->dll = serial_read_reg(uart, UART_DLL);
+ uart->dlh = serial_read_reg(uart, UART_DLM);
+ serial_write_reg(uart, UART_LCR, lcr);
+ uart->ier = serial_read_reg(uart, UART_IER);
+ uart->sysc = serial_read_reg(uart, UART_OMAP_SYSC);
+ uart->scr = serial_read_reg(uart, UART_OMAP_SCR);
+ uart->wer = serial_read_reg(uart, UART_OMAP_WER);
+ serial_write_reg(uart, UART_LCR, 0x80);
+ uart->mcr = serial_read_reg(uart, UART_MCR);
+ serial_write_reg(uart, UART_LCR, lcr);
uart->context_valid = 1;
}
@@ -248,7 +236,6 @@ static void omap_uart_save_context(struct omap_uart_state *uart)
static void omap_uart_restore_context(struct omap_uart_state *uart)
{
u16 efr = 0;
- struct plat_serial8250_port *p = uart->p;
if (!enable_off_mode)
return;
@@ -261,29 +248,30 @@ static void omap_uart_restore_context(struct omap_uart_state *uart)
if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS)
omap_uart_mdr1_errataset(uart, 0x07, 0xA0);
else
- serial_write_reg(p, UART_OMAP_MDR1, 0x7);
- serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
- efr = serial_read_reg(p, UART_EFR);
- serial_write_reg(p, UART_EFR, UART_EFR_ECB);
- serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
- serial_write_reg(p, UART_IER, 0x0);
- serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
- serial_write_reg(p, UART_DLL, uart->dll);
- serial_write_reg(p, UART_DLM, uart->dlh);
- serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
- serial_write_reg(p, UART_IER, uart->ier);
- serial_write_reg(p, UART_LCR, 0x80);
- serial_write_reg(p, UART_MCR, uart->mcr);
- serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
- serial_write_reg(p, UART_EFR, efr);
- serial_write_reg(p, UART_LCR, UART_LCR_WLEN8);
- serial_write_reg(p, UART_OMAP_SCR, uart->scr);
- serial_write_reg(p, UART_OMAP_WER, uart->wer);
- serial_write_reg(p, UART_OMAP_SYSC, uart->sysc);
+ serial_write_reg(uart, UART_OMAP_MDR1, 0x7);
+ serial_write_reg(uart, UART_LCR, 0xBF); /* Config B mode */
+ efr = serial_read_reg(uart, UART_EFR);
+ serial_write_reg(uart, UART_EFR, UART_EFR_ECB);
+ serial_write_reg(uart, UART_LCR, 0x0); /* Operational mode */
+ serial_write_reg(uart, UART_IER, 0x0);
+ serial_write_reg(uart, UART_LCR, 0xBF); /* Config B mode */
+ serial_write_reg(uart, UART_DLL, uart->dll);
+ serial_write_reg(uart, UART_DLM, uart->dlh);
+ serial_write_reg(uart, UART_LCR, 0x0); /* Operational mode */
+ serial_write_reg(uart, UART_IER, uart->ier);
+ serial_write_reg(uart, UART_LCR, 0x80);
+ serial_write_reg(uart, UART_MCR, uart->mcr);
+ serial_write_reg(uart, UART_LCR, 0xBF); /* Config B mode */
+ serial_write_reg(uart, UART_EFR, efr);
+ serial_write_reg(uart, UART_LCR, UART_LCR_WLEN8);
+ serial_write_reg(uart, UART_OMAP_SCR, uart->scr);
+ serial_write_reg(uart, UART_OMAP_WER, uart->wer);
+ serial_write_reg(uart, UART_OMAP_SYSC, uart->sysc);
if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS)
omap_uart_mdr1_errataset(uart, 0x00, 0xA1);
else
- serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */
+ /* UART 16x mode */
+ serial_write_reg(uart, UART_OMAP_MDR1, 0x00);
}
#else
static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
@@ -295,8 +283,7 @@ static inline void omap_uart_enable_clocks(struct omap_uart_state *uart)
if (uart->clocked)
return;
- clk_enable(uart->ick);
- clk_enable(uart->fck);
+ omap_device_enable(uart->pdev);
uart->clocked = 1;
omap_uart_restore_context(uart);
}
@@ -310,8 +297,7 @@ static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
omap_uart_save_context(uart);
uart->clocked = 0;
- clk_disable(uart->ick);
- clk_disable(uart->fck);
+ omap_device_idle(uart->pdev);
}
static void omap_uart_enable_wakeup(struct omap_uart_state *uart)
@@ -349,18 +335,24 @@ static void omap_uart_disable_wakeup(struct omap_uart_state *uart)
}
static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
- int enable)
+ int enable)
{
- struct plat_serial8250_port *p = uart->p;
- u16 sysc;
+ u8 idlemode;
- sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7;
- if (enable)
- sysc |= 0x2 << 3;
- else
- sysc |= 0x1 << 3;
+ if (enable) {
+ /**
+ * Errata 2.15: [UART]:Cannot Acknowledge Idle Requests
+ * in Smartidle Mode When Configured for DMA Operations.
+ */
+ if (uart->dma_enabled)
+ idlemode = HWMOD_IDLEMODE_FORCE;
+ else
+ idlemode = HWMOD_IDLEMODE_SMART;
+ } else {
+ idlemode = HWMOD_IDLEMODE_NO;
+ }
- serial_write_reg(p, UART_OMAP_SYSC, sysc);
+ omap_hwmod_set_slave_idlemode(uart->oh, idlemode);
}
static void omap_uart_block_sleep(struct omap_uart_state *uart)
@@ -377,7 +369,7 @@ static void omap_uart_block_sleep(struct omap_uart_state *uart)
static void omap_uart_allow_sleep(struct omap_uart_state *uart)
{
- if (device_may_wakeup(&uart->pdev.dev))
+ if (device_may_wakeup(&uart->pdev->dev))
omap_uart_enable_wakeup(uart);
else
omap_uart_disable_wakeup(uart);
@@ -472,6 +464,7 @@ int omap_uart_can_sleep(void)
* UART will not idle or sleep for its timeout period.
*
**/
+/* static int first_interrupt; */
static irqreturn_t omap_uart_interrupt(int irq, void *dev_id)
{
struct omap_uart_state *uart = dev_id;
@@ -483,7 +476,6 @@ static irqreturn_t omap_uart_interrupt(int irq, void *dev_id)
static void omap_uart_idle_init(struct omap_uart_state *uart)
{
- struct plat_serial8250_port *p = uart->p;
int ret;
uart->can_sleep = 0;
@@ -495,7 +487,7 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
omap_uart_smart_idle_enable(uart, 0);
if (cpu_is_omap34xx()) {
- u32 mod = (uart->num == 2) ? OMAP3430_PER_MOD : CORE_MOD;
+ u32 mod = (uart->num > 1) ? OMAP3430_PER_MOD : CORE_MOD;
u32 wk_mask = 0;
u32 padconf = 0;
@@ -514,19 +506,17 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
wk_mask = OMAP3430_ST_UART3_MASK;
padconf = 0x19e;
break;
+ case 3:
+ wk_mask = OMAP3630_ST_UART4_MASK;
+ padconf = 0x0d2;
+ break;
}
uart->wk_mask = wk_mask;
uart->padconf = padconf;
} else if (cpu_is_omap24xx()) {
u32 wk_mask = 0;
+ u32 wk_en = PM_WKEN1, wk_st = PM_WKST1;
- if (cpu_is_omap2430()) {
- uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKEN1);
- uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKST1);
- } else if (cpu_is_omap2420()) {
- uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKEN1);
- uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKST1);
- }
switch (uart->num) {
case 0:
wk_mask = OMAP24XX_ST_UART1_MASK;
@@ -535,10 +525,19 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
wk_mask = OMAP24XX_ST_UART2_MASK;
break;
case 2:
+ wk_en = OMAP24XX_PM_WKEN2;
+ wk_st = OMAP24XX_PM_WKST2;
wk_mask = OMAP24XX_ST_UART3_MASK;
break;
}
uart->wk_mask = wk_mask;
+ if (cpu_is_omap2430()) {
+ uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, wk_en);
+ uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, wk_st);
+ } else if (cpu_is_omap2420()) {
+ uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, wk_en);
+ uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, wk_st);
+ }
} else {
uart->wk_en = NULL;
uart->wk_st = NULL;
@@ -546,9 +545,9 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
uart->padconf = 0;
}
- p->irqflags |= IRQF_SHARED;
- ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED,
- "serial idle", (void *)uart);
+ uart->irqflags |= IRQF_SHARED;
+ ret = request_threaded_irq(uart->irq, NULL, omap_uart_interrupt,
+ IRQF_SHARED, "serial idle", (void *)uart);
WARN_ON(ret);
}
@@ -558,11 +557,17 @@ void omap_uart_enable_irqs(int enable)
struct omap_uart_state *uart;
list_for_each_entry(uart, &uart_list, node) {
- if (enable)
- ret = request_irq(uart->p->irq, omap_uart_interrupt,
- IRQF_SHARED, "serial idle", (void *)uart);
- else
- free_irq(uart->p->irq, (void *)uart);
+ if (enable) {
+ pm_runtime_put_sync(&uart->pdev->dev);
+ ret = request_threaded_irq(uart->irq, NULL,
+ omap_uart_interrupt,
+ IRQF_SHARED,
+ "serial idle",
+ (void *)uart);
+ } else {
+ pm_runtime_get_noresume(&uart->pdev->dev);
+ free_irq(uart->irq, (void *)uart);
+ }
}
}
@@ -570,10 +575,9 @@ static ssize_t sleep_timeout_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct platform_device *pdev = container_of(dev,
- struct platform_device, dev);
- struct omap_uart_state *uart = container_of(pdev,
- struct omap_uart_state, pdev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omap_device *odev = to_omap_device(pdev);
+ struct omap_uart_state *uart = odev->hwmods[0]->dev_attr;
return sprintf(buf, "%u\n", uart->timeout / HZ);
}
@@ -582,10 +586,9 @@ static ssize_t sleep_timeout_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t n)
{
- struct platform_device *pdev = container_of(dev,
- struct platform_device, dev);
- struct omap_uart_state *uart = container_of(pdev,
- struct omap_uart_state, pdev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omap_device *odev = to_omap_device(pdev);
+ struct omap_uart_state *uart = odev->hwmods[0]->dev_attr;
unsigned int value;
if (sscanf(buf, "%u", &value) != 1) {
@@ -608,48 +611,15 @@ static DEVICE_ATTR(sleep_timeout, 0644, sleep_timeout_show,
#define DEV_CREATE_FILE(dev, attr) WARN_ON(device_create_file(dev, attr))
#else
static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
+static void omap_uart_block_sleep(struct omap_uart_state *uart)
+{
+ /* Needed to enable UART clocks when built without CONFIG_PM */
+ omap_uart_enable_clocks(uart);
+}
#define DEV_CREATE_FILE(dev, attr)
#endif /* CONFIG_PM */
-static struct omap_uart_state omap_uart[] = {
- {
- .pdev = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM,
- .dev = {
- .platform_data = serial_platform_data0,
- },
- },
- }, {
- .pdev = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM1,
- .dev = {
- .platform_data = serial_platform_data1,
- },
- },
- }, {
- .pdev = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM2,
- .dev = {
- .platform_data = serial_platform_data2,
- },
- },
- },
-#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
- {
- .pdev = {
- .name = "serial8250",
- .id = 3,
- .dev = {
- .platform_data = serial_platform_data3,
- },
- },
- },
-#endif
-};
-
+#ifndef CONFIG_SERIAL_OMAP
/*
* Override the default 8250 read handler: mem_serial_in()
* Empty RX fifo read causes an abort on omap3630 and omap4
@@ -682,71 +652,44 @@ static void serial_out_override(struct uart_port *up, int offset, int value)
}
__serial_write_reg(up, offset, value);
}
+#endif
+
void __init omap_serial_early_init(void)
{
- int i, nr_ports;
- char name[16];
+ int i = 0;
- if (!(cpu_is_omap3630() || cpu_is_omap4430()))
- nr_ports = 3;
- else
- nr_ports = ARRAY_SIZE(omap_uart);
+ do {
+ char oh_name[MAX_UART_HWMOD_NAME_LEN];
+ struct omap_hwmod *oh;
+ struct omap_uart_state *uart;
- /*
- * Make sure the serial ports are muxed on at this point.
- * You have to mux them off in device drivers later on
- * if not needed.
- */
+ snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN,
+ "uart%d", i + 1);
+ oh = omap_hwmod_lookup(oh_name);
+ if (!oh)
+ break;
- for (i = 0; i < nr_ports; i++) {
- struct omap_uart_state *uart = &omap_uart[i];
- struct platform_device *pdev = &uart->pdev;
- struct device *dev = &pdev->dev;
- struct plat_serial8250_port *p = dev->platform_data;
+ uart = kzalloc(sizeof(struct omap_uart_state), GFP_KERNEL);
+ if (WARN_ON(!uart))
+ return;
+
+ uart->oh = oh;
+ uart->num = i++;
+ list_add_tail(&uart->node, &uart_list);
+ num_uarts++;
- /* Don't map zero-based physical address */
- if (p->mapbase == 0) {
- dev_warn(dev, "no physical address for uart#%d,"
- " so skipping early_init...\n", i);
- continue;
- }
/*
- * Module 4KB + L4 interconnect 4KB
- * Static mapping, never released
+ * NOTE: omap_hwmod_init() has not yet been called,
+ * so no hwmod functions will work yet.
*/
- p->membase = ioremap(p->mapbase, SZ_8K);
- if (!p->membase) {
- dev_err(dev, "ioremap failed for uart%i\n", i + 1);
- continue;
- }
-
- sprintf(name, "uart%d_ick", i + 1);
- uart->ick = clk_get(NULL, name);
- if (IS_ERR(uart->ick)) {
- dev_err(dev, "Could not get uart%d_ick\n", i + 1);
- uart->ick = NULL;
- }
- sprintf(name, "uart%d_fck", i+1);
- uart->fck = clk_get(NULL, name);
- if (IS_ERR(uart->fck)) {
- dev_err(dev, "Could not get uart%d_fck\n", i + 1);
- uart->fck = NULL;
- }
-
- /* FIXME: Remove this once the clkdev is ready */
- if (!cpu_is_omap44xx()) {
- if (!uart->ick || !uart->fck)
- continue;
- }
-
- uart->num = i;
- p->private_data = uart;
- uart->p = p;
-
- if (cpu_is_omap44xx())
- p->irq += 32;
- }
+ /*
+ * During UART early init, device need to be probed
+ * to determine SoC specific init before omap_device
+ * is ready. Therefore, don't allow idle here
+ */
+ uart->oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET;
+ } while (1);
}
/**
@@ -763,53 +706,135 @@ void __init omap_serial_early_init(void)
void __init omap_serial_init_port(int port)
{
struct omap_uart_state *uart;
- struct platform_device *pdev;
- struct device *dev;
-
- BUG_ON(port < 0);
- BUG_ON(port >= ARRAY_SIZE(omap_uart));
-
- uart = &omap_uart[port];
- pdev = &uart->pdev;
- dev = &pdev->dev;
+ struct omap_hwmod *oh;
+ struct omap_device *od;
+ void *pdata = NULL;
+ u32 pdata_size = 0;
+ char *name;
+#ifndef CONFIG_SERIAL_OMAP
+ struct plat_serial8250_port ports[2] = {
+ {},
+ {.flags = 0},
+ };
+ struct plat_serial8250_port *p = &ports[0];
+#else
+ struct omap_uart_port_info omap_up;
+#endif
- /* Don't proceed if there's no clocks available */
- if (unlikely(!uart->ick || !uart->fck)) {
- WARN(1, "%s: can't init uart%d, no clocks available\n",
- kobject_name(&dev->kobj), port);
+ if (WARN_ON(port < 0))
+ return;
+ if (WARN_ON(port >= num_uarts))
return;
- }
-
- omap_uart_enable_clocks(uart);
-
- omap_uart_reset(uart);
- omap_uart_idle_init(uart);
- list_add_tail(&uart->node, &uart_list);
+ list_for_each_entry(uart, &uart_list, node)
+ if (port == uart->num)
+ break;
- if (WARN_ON(platform_device_register(pdev)))
- return;
+ oh = uart->oh;
+ uart->dma_enabled = 0;
+#ifndef CONFIG_SERIAL_OMAP
+ name = "serial8250";
- if ((cpu_is_omap34xx() && uart->padconf) ||
- (uart->wk_en && uart->wk_mask)) {
- device_init_wakeup(dev, true);
- DEV_CREATE_FILE(dev, &dev_attr_sleep_timeout);
- }
+ /*
+ * !! 8250 driver does not use standard IORESOURCE* It
+ * has it's own custom pdata that can be taken from
+ * the hwmod resource data. But, this needs to be
+ * done after the build.
+ *
+ * ?? does it have to be done before the register ??
+ * YES, because platform_device_data_add() copies
+ * pdata, it does not use a pointer.
+ */
+ p->flags = UPF_BOOT_AUTOCONF;
+ p->iotype = UPIO_MEM;
+ p->regshift = 2;
+ p->uartclk = OMAP24XX_BASE_BAUD * 16;
+ p->irq = oh->mpu_irqs[0].irq;
+ p->mapbase = oh->slaves[0]->addr->pa_start;
+ p->membase = omap_hwmod_get_mpu_rt_va(oh);
+ p->irqflags = IRQF_SHARED;
+ p->private_data = uart;
/*
* omap44xx: Never read empty UART fifo
* omap3xxx: Never read empty UART fifo on UARTs
* with IP rev >=0x52
*/
+ uart->regshift = p->regshift;
+ uart->membase = p->membase;
if (cpu_is_omap44xx())
uart->errata |= UART_ERRATA_FIFO_FULL_ABORT;
- else if ((serial_read_reg(uart->p, UART_OMAP_MVER) & 0xFF)
+ else if ((serial_read_reg(uart, UART_OMAP_MVER) & 0xFF)
>= UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV)
uart->errata |= UART_ERRATA_FIFO_FULL_ABORT;
if (uart->errata & UART_ERRATA_FIFO_FULL_ABORT) {
- uart->p->serial_in = serial_in_override;
- uart->p->serial_out = serial_out_override;
+ p->serial_in = serial_in_override;
+ p->serial_out = serial_out_override;
+ }
+
+ pdata = &ports[0];
+ pdata_size = 2 * sizeof(struct plat_serial8250_port);
+#else
+
+ name = DRIVER_NAME;
+
+ omap_up.dma_enabled = uart->dma_enabled;
+ omap_up.uartclk = OMAP24XX_BASE_BAUD * 16;
+ omap_up.mapbase = oh->slaves[0]->addr->pa_start;
+ omap_up.membase = omap_hwmod_get_mpu_rt_va(oh);
+ omap_up.irqflags = IRQF_SHARED;
+ omap_up.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+
+ pdata = &omap_up;
+ pdata_size = sizeof(struct omap_uart_port_info);
+#endif
+
+ if (WARN_ON(!oh))
+ return;
+
+ od = omap_device_build(name, uart->num, oh, pdata, pdata_size,
+ omap_uart_latency,
+ ARRAY_SIZE(omap_uart_latency), false);
+ WARN(IS_ERR(od), "Could not build omap_device for %s: %s.\n",
+ name, oh->name);
+
+ uart->irq = oh->mpu_irqs[0].irq;
+ uart->regshift = 2;
+ uart->mapbase = oh->slaves[0]->addr->pa_start;
+ uart->membase = omap_hwmod_get_mpu_rt_va(oh);
+ uart->pdev = &od->pdev;
+
+ oh->dev_attr = uart;
+
+ /*
+ * Because of early UART probing, UART did not get idled
+ * on init. Now that omap_device is ready, ensure full idle
+ * before doing omap_device_enable().
+ */
+ omap_hwmod_idle(uart->oh);
+
+ omap_device_enable(uart->pdev);
+ omap_uart_idle_init(uart);
+ omap_uart_reset(uart);
+ omap_hwmod_enable_wakeup(uart->oh);
+ omap_device_idle(uart->pdev);
+
+ /*
+ * Need to block sleep long enough for interrupt driven
+ * driver to start. Console driver is in polling mode
+ * so device needs to be kept enabled while polling driver
+ * is in use.
+ */
+ if (uart->timeout)
+ uart->timeout = (30 * HZ);
+ omap_uart_block_sleep(uart);
+ uart->timeout = DEFAULT_TIMEOUT;
+
+ if ((cpu_is_omap34xx() && uart->padconf) ||
+ (uart->wk_en && uart->wk_mask)) {
+ device_init_wakeup(&od->pdev.dev, true);
+ DEV_CREATE_FILE(&od->pdev.dev, &dev_attr_sleep_timeout);
}
/* Enable the MDR1 errata for OMAP3 */
@@ -826,13 +851,8 @@ void __init omap_serial_init_port(int port)
*/
void __init omap_serial_init(void)
{
- int i, nr_ports;
-
- if (!(cpu_is_omap3630() || cpu_is_omap4430()))
- nr_ports = 3;
- else
- nr_ports = ARRAY_SIZE(omap_uart);
+ struct omap_uart_state *uart;
- for (i = 0; i < nr_ports; i++)
- omap_serial_init_port(i);
+ list_for_each_entry(uart, &uart_list, node)
+ omap_serial_init_port(uart->num);
}
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
index ba53191ae4c5..2fb205a7f285 100644
--- a/arch/arm/mach-omap2/sleep34xx.S
+++ b/arch/arm/mach-omap2/sleep34xx.S
@@ -27,11 +27,11 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <mach/io.h>
-#include <plat/control.h>
#include "cm.h"
#include "prm.h"
#include "sdrc.h"
+#include "control.h"
#define SDRC_SCRATCHPAD_SEM_V 0xfa00291c
diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S
index de99ba2a57ab..3637274af5be 100644
--- a/arch/arm/mach-omap2/sram34xx.S
+++ b/arch/arm/mach-omap2/sram34xx.S
@@ -129,8 +129,11 @@ ENTRY(omap3_sram_configure_core_dpll)
ldr r4, [sp, #80]
str r4, omap_sdrc_mr_1_val
skip_cs1_params:
+ mrc p15, 0, r8, c1, c0, 0 @ read ctrl register
+ bic r10, r8, #0x800 @ clear Z-bit, disable branch prediction
+ mcr p15, 0, r10, c1, c0, 0 @ write ctrl register
dsb @ flush buffered writes to interconnect
-
+ isb @ prevent speculative exec past here
cmp r3, #1 @ if increasing SDRC clk rate,
bleq configure_sdrc @ program the SDRC regs early (for RFR)
cmp r1, #SDRC_UNLOCK_DLL @ set the intended DLL state
@@ -148,6 +151,7 @@ skip_cs1_params:
beq return_to_sdram @ return to SDRAM code, otherwise,
bl configure_sdrc @ reprogram SDRC regs now
return_to_sdram:
+ mcr p15, 0, r8, c1, c0, 0 @ restore ctrl register
isb @ prevent speculative exec past here
mov r0, #0 @ return value
ldmfd sp!, {r1-r12, pc} @ restore regs and return
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index 74fbed8491f2..e13c29eecf2b 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -40,6 +40,8 @@
#include <plat/dmtimer.h>
#include <asm/localtimer.h>
+#include "timer-gp.h"
+
/* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
#define MAX_GPTIMER_ID 12
@@ -228,8 +230,10 @@ static void __init omap2_gp_clocksource_init(void)
static void __init omap2_gp_timer_init(void)
{
#ifdef CONFIG_LOCAL_TIMERS
- twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_256);
- BUG_ON(!twd_base);
+ if (cpu_is_omap44xx()) {
+ twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_256);
+ BUG_ON(!twd_base);
+ }
#endif
omap_dm_timer_init();
diff --git a/arch/arm/plat-omap/include/plat/timer-gp.h b/arch/arm/mach-omap2/timer-gp.h
index c88d346b59d9..5c1072c6783b 100644
--- a/arch/arm/plat-omap/include/plat/timer-gp.h
+++ b/arch/arm/mach-omap2/timer-gp.h
@@ -11,7 +11,6 @@
#ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_TIMER_GP_H
#define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_TIMER_GP_H
-int __init omap2_gp_clockevent_set_gptimer(u8 id);
+extern int __init omap2_gp_clockevent_set_gptimer(u8 id);
#endif
-
diff --git a/arch/arm/mach-omap2/usb-fs.c b/arch/arm/mach-omap2/usb-fs.c
index a216d88b04b5..1481078763b8 100644
--- a/arch/arm/mach-omap2/usb-fs.c
+++ b/arch/arm/mach-omap2/usb-fs.c
@@ -29,18 +29,18 @@
#include <asm/irq.h>
-#include <plat/control.h>
#include <plat/usb.h>
#include <plat/board.h>
+#include "control.h"
+#include "mux.h"
+
#define INT_USB_IRQ_GEN INT_24XX_USB_IRQ_GEN
#define INT_USB_IRQ_NISO INT_24XX_USB_IRQ_NISO
#define INT_USB_IRQ_ISO INT_24XX_USB_IRQ_ISO
#define INT_USB_IRQ_HGEN INT_24XX_USB_IRQ_HGEN
#define INT_USB_IRQ_OTG INT_24XX_USB_IRQ_OTG
-#include "mux.h"
-
#if defined(CONFIG_ARCH_OMAP2)
#ifdef CONFIG_USB_GADGET_OMAP
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index 08b410343870..aaa1166df964 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -382,6 +382,31 @@ struct platform_device pxa_device_i2s = {
.num_resources = ARRAY_SIZE(pxai2s_resources),
};
+struct platform_device pxa_device_asoc_ssp1 = {
+ .name = "pxa-ssp-dai",
+ .id = 0,
+};
+
+struct platform_device pxa_device_asoc_ssp2= {
+ .name = "pxa-ssp-dai",
+ .id = 1,
+};
+
+struct platform_device pxa_device_asoc_ssp3 = {
+ .name = "pxa-ssp-dai",
+ .id = 2,
+};
+
+struct platform_device pxa_device_asoc_ssp4 = {
+ .name = "pxa-ssp-dai",
+ .id = 3,
+};
+
+struct platform_device pxa_device_asoc_platform = {
+ .name = "pxa-pcm-audio",
+ .id = -1,
+};
+
static u64 pxaficp_dmamask = ~(u32)0;
struct platform_device pxa_device_ficp = {
diff --git a/arch/arm/mach-pxa/devices.h b/arch/arm/mach-pxa/devices.h
index 715e8bd02e24..2fd5a8b35757 100644
--- a/arch/arm/mach-pxa/devices.h
+++ b/arch/arm/mach-pxa/devices.h
@@ -39,4 +39,10 @@ extern struct platform_device pxa3xx_device_i2c_power;
extern struct platform_device pxa3xx_device_gcu;
+extern struct platform_device pxa_device_asoc_platform;
+extern struct platform_device pxa_device_asoc_ssp1;
+extern struct platform_device pxa_device_asoc_ssp2;
+extern struct platform_device pxa_device_asoc_ssp3;
+extern struct platform_device pxa_device_asoc_ssp4;
+
void __init pxa_register_device(struct platform_device *dev, void *data);
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 12e5b9f01e6f..d1fbf29d561c 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -385,6 +385,10 @@ static struct platform_device *devices[] __initdata = {
&pxa27x_device_udc,
&pxa_device_pmu,
&pxa_device_i2s,
+ &pxa_device_asoc_ssp1,
+ &pxa_device_asoc_ssp2,
+ &pxa_device_asoc_ssp3,
+ &pxa_device_asoc_platform,
&sa1100_device_rtc,
&pxa_device_rtc,
&pxa27x_device_ssp1,
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index c85c3a7abd31..d1c747cdacf8 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -593,6 +593,11 @@ static struct platform_device *devices[] __initdata = {
&pxa27x_device_udc,
&pxa_device_pmu,
&pxa_device_i2s,
+ &pxa_device_asoc_ssp1,
+ &pxa_device_asoc_ssp2,
+ &pxa_device_asoc_ssp3,
+ &pxa_device_asoc_ssp4,
+ &pxa_device_asoc_platform,
&sa1100_device_rtc,
&pxa_device_rtc,
&pxa27x_device_ssp1,
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index f25fb6245bd7..702f7a68e87d 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -45,6 +45,16 @@ int wm9713_irq;
int lcd_id;
int lcd_orientation;
+struct platform_device pxa_device_wm9713_audio = {
+ .name = "wm9713-codec",
+ .id = -1,
+};
+
+static void __init zylonite_init_wm9713_audio(void)
+{
+ platform_device_register(&pxa_device_wm9713_audio);
+}
+
static struct resource smc91x_resources[] = {
[0] = {
.start = ZYLONITE_ETH_PHYS + 0x300,
@@ -408,6 +418,7 @@ static void __init zylonite_init(void)
zylonite_init_nand();
zylonite_init_leds();
zylonite_init_ohci();
+ zylonite_init_wm9713_audio();
}
MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")
diff --git a/arch/arm/mach-s3c2440/mach-at2440evb.c b/arch/arm/mach-s3c2440/mach-at2440evb.c
index e3810c86a5e6..6c98b789b8c6 100644
--- a/arch/arm/mach-s3c2440/mach-at2440evb.c
+++ b/arch/arm/mach-s3c2440/mach-at2440evb.c
@@ -5,7 +5,7 @@
* and modifications by SBZ <sbz@spgui.org> and
* Weibing <http://weibing.blogbus.com>
*
- * For product information, visit http://www.arm9e.com/
+ * For product information, visit http://www.arm.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
diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c
index 9648fbc36eec..3838335f125b 100644
--- a/arch/arm/mach-s3c64xx/dev-audio.c
+++ b/arch/arm/mach-s3c64xx/dev-audio.c
@@ -43,8 +43,10 @@ static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
+ break;
default:
- printk(KERN_DEBUG "Invalid I2S Controller number!");
+ printk(KERN_DEBUG "Invalid I2S Controller number: %d\n",
+ pdev->id);
return -EINVAL;
}
@@ -184,7 +186,8 @@ static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev)
s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT);
break;
default:
- printk(KERN_DEBUG "Invalid PCM Controller number!");
+ printk(KERN_DEBUG "Invalid PCM Controller number: %d\n",
+ pdev->id);
return -EINVAL;
}
@@ -333,3 +336,16 @@ void __init s3c64xx_ac97_setup_gpio(int num)
else
s3c_ac97_pdata.cfg_gpio = s3c64xx_ac97_cfg_gpe;
}
+
+static u64 s3c_device_audio_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_pcm = {
+ .name = "s3c24xx-pcm-audio",
+ .id = -1,
+ .dev = {
+ .dma_mask = &s3c_device_audio_dmamask,
+ .coherent_dma_mask = 0xffffffffUL
+ }
+};
+EXPORT_SYMBOL(s3c_device_pcm);
+
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
index ec8865c03a19..77488facfe4c 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
@@ -283,6 +283,7 @@ static struct platform_device *smdk6410_devices[] __initdata = {
&s3c_device_fb,
&s3c_device_ohci,
&s3c_device_usb_hsotg,
+ &s3c_device_pcm,
&s3c64xx_device_iisv4,
&samsung_device_keypad,
diff --git a/arch/arm/mach-sa1100/Kconfig b/arch/arm/mach-sa1100/Kconfig
index fd4c52b7ccb6..5da8c35aa0de 100644
--- a/arch/arm/mach-sa1100/Kconfig
+++ b/arch/arm/mach-sa1100/Kconfig
@@ -90,8 +90,8 @@ config SA1100_JORNADA720
# FIXME: select CPU_FREQ_SA11x0
help
Say Y here if you want to build a kernel for the HP Jornada 720
- handheld computer. See <http://www.hp.com/jornada/products/720>
- for details.
+ handheld computer. See
+ <http://h10025.www1.hp.com/ewfrf/wc/product?product=61677&cc=us&lc=en&dlc=en&product=61677#>
config SA1100_JORNADA720_SSP
bool "HP Jornada 720 Extended SSP driver"
@@ -145,7 +145,7 @@ config SA1100_SIMPAD
FLASH. The SL4 version got 64 MB RAM and 32 MB FLASH and a
PCMCIA-Slot. The version for the Germany Telecom (DTAG) is the same
like CL4 in additional it has a PCMCIA-Slot. For more information
- visit <http://www.my-siemens.com/> or <http://www.siemens.ch/>.
+ visit <http://www.usa.siemens.com/> or <http://www.siemens.ch/>.
config SA1100_SSP
tristate "Generic PIO SSP"
diff --git a/arch/arm/mach-sa1100/cpu-sa1100.c b/arch/arm/mach-sa1100/cpu-sa1100.c
index ef817876a5d6..c0a13ef5436f 100644
--- a/arch/arm/mach-sa1100/cpu-sa1100.c
+++ b/arch/arm/mach-sa1100/cpu-sa1100.c
@@ -13,7 +13,7 @@
* This software has been developed while working on the LART
* computing board (http://www.lartmaker.nl/), which is
* sponsored by the Mobile Multi-media Communications
- * (http://www.mmc.tudelft.nl/) and Ubiquitous Communications
+ * (http://www.mobimedia.org/) and Ubiquitous Communications
* (http://www.ubicom.tudelft.nl/) projects.
*
* The authors can be reached at:
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index a57713c1954a..acd9552f8ada 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -16,6 +16,10 @@ config ARCH_TEGRA_2x_SOC
endchoice
+config TEGRA_PCI
+ bool "PCI Express support"
+ select PCI
+
comment "Tegra board type"
config MACH_HARMONY
@@ -47,4 +51,11 @@ config TEGRA_DEBUG_UARTE
endchoice
+config TEGRA_SYSTEM_DMA
+ bool "Enable system DMA driver for NVIDIA Tegra SoCs"
+ default y
+ help
+ Adds system DMA functionality for NVIDIA Tegra SoCs, used by
+ several Tegra device drivers
+
endif
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 51e9370eed99..cdbc68e4c0ca 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -1,14 +1,21 @@
obj-y += common.o
obj-y += io.o
-obj-y += irq.o
+obj-y += irq.o legacy_irq.o
obj-y += clock.o
obj-y += timer.o
obj-y += gpio.o
obj-y += pinmux.o
+obj-y += fuse.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clock.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_dvfs.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pinmux-t2-tables.o
obj-$(CONFIG_SMP) += platsmp.o localtimer.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
+obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o
+obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o
+obj-$(CONFIG_TEGRA_PCI) += pcie.o
obj-${CONFIG_MACH_HARMONY} += board-harmony.o
obj-${CONFIG_MACH_HARMONY} += board-harmony-pinmux.o
+obj-${CONFIG_MACH_HARMONY} += board-harmony-pcie.o
diff --git a/arch/arm/mach-tegra/board-harmony-pcie.c b/arch/arm/mach-tegra/board-harmony-pcie.c
new file mode 100644
index 000000000000..f7e7d4514b6a
--- /dev/null
+++ b/arch/arm/mach-tegra/board-harmony-pcie.c
@@ -0,0 +1,57 @@
+/*
+ * arch/arm/mach-tegra/board-harmony-pcie.c
+ *
+ * Copyright (C) 2010 CompuLab, Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * 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/kernel.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/pinmux.h>
+#include "board.h"
+
+#ifdef CONFIG_TEGRA_PCI
+
+static int __init harmony_pcie_init(void)
+{
+ int err;
+
+ if (!machine_is_harmony())
+ return 0;
+
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_GPV, TEGRA_TRI_NORMAL);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXA, TEGRA_TRI_NORMAL);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_NORMAL);
+
+ err = tegra_pcie_init(true, true);
+ if (err)
+ goto err_pcie;
+
+ return 0;
+
+err_pcie:
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_GPV, TEGRA_TRI_TRISTATE);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXA, TEGRA_TRI_TRISTATE);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_TRISTATE);
+
+ return err;
+}
+
+subsys_initcall(harmony_pcie_init);
+
+#endif
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index 3d06354136f2..0de565ca37c5 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -27,6 +27,7 @@ void __init tegra_common_init(void);
void __init tegra_map_common_io(void);
void __init tegra_init_irq(void);
void __init tegra_init_clock(void);
+int __init tegra_pcie_init(bool init_port0, bool init_port1);
extern struct sys_timer tegra_timer;
#endif
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 03ad578349b9..ae19f95585be 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -24,13 +24,80 @@
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
+#include <linux/regulator/consumer.h>
#include <asm/clkdev.h>
#include "clock.h"
+#include "board.h"
+#include "fuse.h"
static LIST_HEAD(clocks);
static DEFINE_SPINLOCK(clock_lock);
+static DEFINE_MUTEX(dvfs_lock);
+
+static int clk_is_dvfs(struct clk *c)
+{
+ return (c->dvfs != NULL);
+};
+
+static int dvfs_set_rate(struct dvfs *d, unsigned long rate)
+{
+ struct dvfs_table *t;
+
+ if (d->table == NULL)
+ return -ENODEV;
+
+ for (t = d->table; t->rate != 0; t++) {
+ if (rate <= t->rate) {
+ if (!d->reg)
+ return 0;
+
+ return regulator_set_voltage(d->reg,
+ t->millivolts * 1000,
+ d->max_millivolts * 1000);
+ }
+ }
+
+ return -EINVAL;
+}
+
+static void dvfs_init(struct clk *c)
+{
+ int process_id;
+ int i;
+ struct dvfs_table *table;
+
+ process_id = c->dvfs->cpu ? tegra_core_process_id() :
+ tegra_cpu_process_id();
+
+ for (i = 0; i < c->dvfs->process_id_table_length; i++)
+ if (process_id == c->dvfs->process_id_table[i].process_id)
+ c->dvfs->table = c->dvfs->process_id_table[i].table;
+
+ if (c->dvfs->table == NULL) {
+ pr_err("Failed to find dvfs table for clock %s process %d\n",
+ c->name, process_id);
+ return;
+ }
+
+ c->dvfs->max_millivolts = 0;
+ for (table = c->dvfs->table; table->rate != 0; table++)
+ if (c->dvfs->max_millivolts < table->millivolts)
+ c->dvfs->max_millivolts = table->millivolts;
+
+ c->dvfs->reg = regulator_get(NULL, c->dvfs->reg_id);
+
+ if (IS_ERR(c->dvfs->reg)) {
+ pr_err("Failed to get regulator %s for clock %s\n",
+ c->dvfs->reg_id, c->name);
+ c->dvfs->reg = NULL;
+ return;
+ }
+
+ if (c->refcnt > 0)
+ dvfs_set_rate(c->dvfs, c->rate);
+}
struct clk *tegra_get_clock_by_name(const char *name)
{
@@ -48,14 +115,31 @@ struct clk *tegra_get_clock_by_name(const char *name)
return ret;
}
+static void clk_recalculate_rate(struct clk *c)
+{
+ u64 rate;
+
+ if (!c->parent)
+ return;
+
+ rate = c->parent->rate;
+
+ if (c->mul != 0 && c->div != 0) {
+ rate = rate * c->mul;
+ do_div(rate, c->div);
+ }
+
+ if (rate > c->max_rate)
+ pr_warn("clocks: Set clock %s to rate %llu, max is %lu\n",
+ c->name, rate, c->max_rate);
+
+ c->rate = rate;
+}
+
int clk_reparent(struct clk *c, struct clk *parent)
{
pr_debug("%s: %s\n", __func__, c->name);
- if (c->refcnt && c->parent)
- clk_disable_locked(c->parent);
c->parent = parent;
- if (c->refcnt && c->parent)
- clk_enable_locked(c->parent);
list_del(&c->sibling);
list_add_tail(&c->sibling, &parent->children);
return 0;
@@ -67,8 +151,7 @@ static void propagate_rate(struct clk *c)
pr_debug("%s: %s\n", __func__, c->name);
list_for_each_entry(clkp, &c->children, sibling) {
pr_debug(" %s\n", clkp->name);
- if (clkp->ops->recalculate_rate)
- clkp->ops->recalculate_rate(clkp);
+ clk_recalculate_rate(clkp);
propagate_rate(clkp);
}
}
@@ -77,6 +160,8 @@ void clk_init(struct clk *c)
{
unsigned long flags;
+ pr_debug("%s: %s\n", __func__, c->name);
+
spin_lock_irqsave(&clock_lock, flags);
INIT_LIST_HEAD(&c->children);
@@ -85,6 +170,8 @@ void clk_init(struct clk *c)
if (c->ops && c->ops->init)
c->ops->init(c);
+ clk_recalculate_rate(c);
+
list_add(&c->node, &clocks);
if (c->parent)
@@ -122,13 +209,38 @@ int clk_enable_locked(struct clk *c)
return 0;
}
+int clk_enable_cansleep(struct clk *c)
+{
+ int ret;
+ unsigned long flags;
+
+ mutex_lock(&dvfs_lock);
+
+ if (clk_is_dvfs(c) && c->refcnt > 0)
+ dvfs_set_rate(c->dvfs, c->rate);
+
+ spin_lock_irqsave(&clock_lock, flags);
+ ret = clk_enable_locked(c);
+ spin_unlock_irqrestore(&clock_lock, flags);
+
+ mutex_unlock(&dvfs_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(clk_enable_cansleep);
+
int clk_enable(struct clk *c)
{
int ret;
unsigned long flags;
+
+ if (clk_is_dvfs(c))
+ BUG();
+
spin_lock_irqsave(&clock_lock, flags);
ret = clk_enable_locked(c);
spin_unlock_irqrestore(&clock_lock, flags);
+
return ret;
}
EXPORT_SYMBOL(clk_enable);
@@ -152,9 +264,30 @@ void clk_disable_locked(struct clk *c)
c->refcnt--;
}
+void clk_disable_cansleep(struct clk *c)
+{
+ unsigned long flags;
+
+ mutex_lock(&dvfs_lock);
+
+ spin_lock_irqsave(&clock_lock, flags);
+ clk_disable_locked(c);
+ spin_unlock_irqrestore(&clock_lock, flags);
+
+ if (clk_is_dvfs(c) && c->refcnt == 0)
+ dvfs_set_rate(c->dvfs, c->rate);
+
+ mutex_unlock(&dvfs_lock);
+}
+EXPORT_SYMBOL(clk_disable_cansleep);
+
void clk_disable(struct clk *c)
{
unsigned long flags;
+
+ if (clk_is_dvfs(c))
+ BUG();
+
spin_lock_irqsave(&clock_lock, flags);
clk_disable_locked(c);
spin_unlock_irqrestore(&clock_lock, flags);
@@ -175,6 +308,8 @@ int clk_set_parent_locked(struct clk *c, struct clk *parent)
if (ret)
return ret;
+ clk_recalculate_rate(c);
+
propagate_rate(c);
return 0;
@@ -197,22 +332,69 @@ struct clk *clk_get_parent(struct clk *c)
}
EXPORT_SYMBOL(clk_get_parent);
-int clk_set_rate(struct clk *c, unsigned long rate)
+int clk_set_rate_locked(struct clk *c, unsigned long rate)
+{
+ int ret;
+
+ if (rate > c->max_rate)
+ rate = c->max_rate;
+
+ if (!c->ops || !c->ops->set_rate)
+ return -ENOSYS;
+
+ ret = c->ops->set_rate(c, rate);
+
+ if (ret)
+ return ret;
+
+ clk_recalculate_rate(c);
+
+ propagate_rate(c);
+
+ return 0;
+}
+
+int clk_set_rate_cansleep(struct clk *c, unsigned long rate)
{
int ret = 0;
unsigned long flags;
+ pr_debug("%s: %s\n", __func__, c->name);
+
+ mutex_lock(&dvfs_lock);
+
+ if (rate > c->rate)
+ ret = dvfs_set_rate(c->dvfs, rate);
+ if (ret)
+ goto out;
+
spin_lock_irqsave(&clock_lock, flags);
+ ret = clk_set_rate_locked(c, rate);
+ spin_unlock_irqrestore(&clock_lock, flags);
- pr_debug("%s: %s\n", __func__, c->name);
+ if (ret)
+ goto out;
- if (c->ops && c->ops->set_rate)
- ret = c->ops->set_rate(c, rate);
- else
- ret = -ENOSYS;
+ ret = dvfs_set_rate(c->dvfs, rate);
- propagate_rate(c);
+out:
+ mutex_unlock(&dvfs_lock);
+ return ret;
+}
+EXPORT_SYMBOL(clk_set_rate_cansleep);
+
+int clk_set_rate(struct clk *c, unsigned long rate)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ pr_debug("%s: %s\n", __func__, c->name);
+
+ if (clk_is_dvfs(c))
+ BUG();
+ spin_lock_irqsave(&clock_lock, flags);
+ ret = clk_set_rate_locked(c, rate);
spin_unlock_irqrestore(&clock_lock, flags);
return ret;
@@ -235,6 +417,20 @@ unsigned long clk_get_rate(struct clk *c)
}
EXPORT_SYMBOL(clk_get_rate);
+long clk_round_rate(struct clk *c, unsigned long rate)
+{
+ pr_debug("%s: %s\n", __func__, c->name);
+
+ if (!c->ops || !c->ops->round_rate)
+ return -ENOSYS;
+
+ if (rate > c->max_rate)
+ rate = c->max_rate;
+
+ return c->ops->round_rate(c, rate);
+}
+EXPORT_SYMBOL(clk_round_rate);
+
static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
{
struct clk *c;
@@ -308,13 +504,28 @@ void tegra_periph_reset_assert(struct clk *c)
}
EXPORT_SYMBOL(tegra_periph_reset_assert);
-int __init tegra_init_clock(void)
+void __init tegra_init_clock(void)
{
tegra2_init_clocks();
+}
+
+int __init tegra_init_dvfs(void)
+{
+ struct clk *c, *safe;
+
+ mutex_lock(&dvfs_lock);
+
+ list_for_each_entry_safe(c, safe, &clocks, node)
+ if (c->dvfs)
+ dvfs_init(c);
+
+ mutex_unlock(&dvfs_lock);
return 0;
}
+late_initcall(tegra_init_dvfs);
+
#ifdef CONFIG_DEBUG_FS
static struct dentry *clk_debugfs_root;
@@ -324,7 +535,7 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
struct clk *child;
struct clk *safe;
const char *state = "uninit";
- char div[5] = {0};
+ char div[8] = {0};
if (c->state == ON)
state = "on";
@@ -332,16 +543,26 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
state = "off";
if (c->mul != 0 && c->div != 0) {
- BUG_ON(c->mul > 2);
- if (c->mul > c->div)
- snprintf(div, sizeof(div), "x%d", c->mul / c->div);
- else
+ if (c->mul > c->div) {
+ int mul = c->mul / c->div;
+ int mul2 = (c->mul * 10 / c->div) % 10;
+ int mul3 = (c->mul * 10) % c->div;
+ if (mul2 == 0 && mul3 == 0)
+ snprintf(div, sizeof(div), "x%d", mul);
+ else if (mul3 == 0)
+ snprintf(div, sizeof(div), "x%d.%d", mul, mul2);
+ else
+ snprintf(div, sizeof(div), "x%d.%d..", mul, mul2);
+ } else {
snprintf(div, sizeof(div), "%d%s", c->div / c->mul,
(c->div % c->mul) ? ".5" : "");
+ }
}
- seq_printf(s, "%*s%-*s %-6s %-3d %-5s %-10lu\n",
- level * 3 + 1, c->set ? "" : "*",
+ seq_printf(s, "%*s%c%c%-*s %-6s %-3d %-8s %-10lu\n",
+ level * 3 + 1, "",
+ c->rate > c->max_rate ? '!' : ' ',
+ !c->set ? '*' : ' ',
30 - level * 3, c->name,
state, c->refcnt, div, c->rate);
list_for_each_entry_safe(child, safe, &c->children, sibling) {
@@ -353,8 +574,8 @@ static int clock_tree_show(struct seq_file *s, void *data)
{
struct clk *c;
unsigned long flags;
- seq_printf(s, " clock state ref div rate \n");
- seq_printf(s, "-----------------------------------------------------------\n");
+ seq_printf(s, " clock state ref div rate\n");
+ seq_printf(s, "--------------------------------------------------------------\n");
spin_lock_irqsave(&clock_lock, flags);
list_for_each_entry(c, &clocks, node)
if (c->parent == NULL)
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index af7c70e2a3ba..94fd859770f1 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -27,18 +27,43 @@
#define DIV_U71 (1 << 1)
#define DIV_U71_FIXED (1 << 2)
#define DIV_2 (1 << 3)
-#define PLL_FIXED (1 << 4)
-#define PLL_HAS_CPCON (1 << 5)
-#define MUX (1 << 6)
-#define PLLD (1 << 7)
-#define PERIPH_NO_RESET (1 << 8)
-#define PERIPH_NO_ENB (1 << 9)
-#define PERIPH_EMC_ENB (1 << 10)
-#define PERIPH_MANUAL_RESET (1 << 11)
-#define PLL_ALT_MISC_REG (1 << 12)
+#define DIV_U16 (1 << 4)
+#define PLL_FIXED (1 << 5)
+#define PLL_HAS_CPCON (1 << 6)
+#define MUX (1 << 7)
+#define PLLD (1 << 8)
+#define PERIPH_NO_RESET (1 << 9)
+#define PERIPH_NO_ENB (1 << 10)
+#define PERIPH_EMC_ENB (1 << 11)
+#define PERIPH_MANUAL_RESET (1 << 12)
+#define PLL_ALT_MISC_REG (1 << 13)
+#define PLLU (1 << 14)
#define ENABLE_ON_INIT (1 << 28)
struct clk;
+struct regulator;
+
+struct dvfs_table {
+ unsigned long rate;
+ int millivolts;
+};
+
+struct dvfs_process_id_table {
+ int process_id;
+ struct dvfs_table *table;
+};
+
+
+struct dvfs {
+ struct regulator *reg;
+ struct dvfs_table *table;
+ int max_millivolts;
+
+ int process_id_table_length;
+ const char *reg_id;
+ bool cpu;
+ struct dvfs_process_id_table process_id_table[];
+};
struct clk_mux_sel {
struct clk *input;
@@ -58,12 +83,9 @@ struct clk_ops {
void (*init)(struct clk *);
int (*enable)(struct clk *);
void (*disable)(struct clk *);
- void (*recalc)(struct clk *);
int (*set_parent)(struct clk *, struct clk *);
int (*set_rate)(struct clk *, unsigned long);
- unsigned long (*get_rate)(struct clk *);
long (*round_rate)(struct clk *, unsigned long);
- unsigned long (*recalculate_rate)(struct clk *);
};
enum clk_state {
@@ -85,6 +107,7 @@ struct clk {
struct clk *parent;
struct clk_lookup lookup;
unsigned long rate;
+ unsigned long max_rate;
u32 flags;
u32 refcnt;
const char *name;
@@ -103,10 +126,6 @@ struct clk {
unsigned long cf_max;
unsigned long vco_min;
unsigned long vco_max;
- u32 m;
- u32 n;
- u32 p;
- u32 cpcon;
const struct clk_pll_table *pll_table;
/* DIV */
@@ -117,6 +136,12 @@ struct clk {
const struct clk_mux_sel *inputs;
u32 sel;
u32 reg_mask;
+
+ /* Virtual cpu clock */
+ struct clk *main;
+ struct clk *backup;
+
+ struct dvfs *dvfs;
};
@@ -141,6 +166,7 @@ unsigned long clk_measure_input_freq(void);
void clk_disable_locked(struct clk *c);
int clk_enable_locked(struct clk *c);
int clk_set_parent_locked(struct clk *c, struct clk *parent);
+int clk_set_rate_locked(struct clk *c, unsigned long rate);
int clk_reparent(struct clk *c, struct clk *parent);
void tegra_clk_init_from_table(struct tegra_clk_init_table *table);
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 039a514b61ef..7c91e2b9d643 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -19,13 +19,17 @@
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
#include <asm/hardware/cache-l2x0.h>
#include <mach/iomap.h>
+#include <mach/dma.h>
#include "board.h"
#include "clock.h"
+#include "fuse.h"
static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
/* name parent rate enabled */
@@ -35,8 +39,8 @@ static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
{ "pll_p_out2", "pll_p", 48000000, true },
{ "pll_p_out3", "pll_p", 72000000, true },
{ "pll_p_out4", "pll_p", 108000000, true },
- { "sys", "pll_p_out4", 108000000, true },
- { "hclk", "sys", 108000000, true },
+ { "sclk", "pll_p_out4", 108000000, true },
+ { "hclk", "sclk", 108000000, true },
{ "pclk", "hclk", 54000000, true },
{ NULL, NULL, 0, 0},
};
@@ -51,11 +55,16 @@ void __init tegra_init_cache(void)
l2x0_init(p, 0x6C080001, 0x8200c3fe);
#endif
+
}
void __init tegra_common_init(void)
{
+ tegra_init_fuse();
tegra_init_clock();
tegra_clk_init_from_table(common_clk_init_table);
tegra_init_cache();
+#ifdef CONFIG_TEGRA_SYSTEM_DMA
+ tegra_dma_init();
+#endif
}
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
new file mode 100644
index 000000000000..fea5719c7072
--- /dev/null
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -0,0 +1,185 @@
+/*
+ * arch/arm/mach-tegra/cpu-tegra.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ * Colin Cross <ccross@google.com>
+ * Based on arch/arm/plat-omap/cpu-omap.c, (C) 2005 Nokia Corporation
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+
+#include <mach/hardware.h>
+#include <mach/clk.h>
+
+/* Frequency table index must be sequential starting at 0 */
+static struct cpufreq_frequency_table freq_table[] = {
+ { 0, 312000 },
+ { 1, 456000 },
+ { 2, 608000 },
+ { 3, 760000 },
+ { 4, 816000 },
+ { 5, 912000 },
+ { 6, 1000000 },
+ { 7, CPUFREQ_TABLE_END },
+};
+
+#define NUM_CPUS 2
+
+static struct clk *cpu_clk;
+
+static unsigned long target_cpu_speed[NUM_CPUS];
+
+int tegra_verify_speed(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+unsigned int tegra_getspeed(unsigned int cpu)
+{
+ unsigned long rate;
+
+ if (cpu >= NUM_CPUS)
+ return 0;
+
+ rate = clk_get_rate(cpu_clk) / 1000;
+ return rate;
+}
+
+static int tegra_update_cpu_speed(void)
+{
+ int i;
+ unsigned long rate = 0;
+ int ret = 0;
+ struct cpufreq_freqs freqs;
+
+ for_each_online_cpu(i)
+ rate = max(rate, target_cpu_speed[i]);
+
+ freqs.old = tegra_getspeed(0);
+ freqs.new = rate;
+
+ if (freqs.old == freqs.new)
+ return ret;
+
+ for_each_online_cpu(freqs.cpu)
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+#ifdef CONFIG_CPU_FREQ_DEBUG
+ printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n",
+ freqs.old, freqs.new);
+#endif
+
+ ret = clk_set_rate_cansleep(cpu_clk, freqs.new * 1000);
+ if (ret) {
+ pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
+ freqs.new);
+ return ret;
+ }
+
+ for_each_online_cpu(freqs.cpu)
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ return 0;
+}
+
+static int tegra_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ int idx;
+ unsigned int freq;
+
+ cpufreq_frequency_table_target(policy, freq_table, target_freq,
+ relation, &idx);
+
+ freq = freq_table[idx].frequency;
+
+ target_cpu_speed[policy->cpu] = freq;
+
+ return tegra_update_cpu_speed();
+}
+
+static int tegra_cpu_init(struct cpufreq_policy *policy)
+{
+ if (policy->cpu >= NUM_CPUS)
+ return -EINVAL;
+
+ cpu_clk = clk_get_sys(NULL, "cpu");
+ if (IS_ERR(cpu_clk))
+ return PTR_ERR(cpu_clk);
+
+ cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+ policy->cur = tegra_getspeed(policy->cpu);
+ target_cpu_speed[policy->cpu] = policy->cur;
+
+ /* FIXME: what's the actual transition time? */
+ policy->cpuinfo.transition_latency = 300 * 1000;
+
+ policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+ cpumask_copy(policy->related_cpus, cpu_possible_mask);
+
+ return 0;
+}
+
+static int tegra_cpu_exit(struct cpufreq_policy *policy)
+{
+ cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ clk_put(cpu_clk);
+ return 0;
+}
+
+static struct freq_attr *tegra_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver tegra_cpufreq_driver = {
+ .verify = tegra_verify_speed,
+ .target = tegra_target,
+ .get = tegra_getspeed,
+ .init = tegra_cpu_init,
+ .exit = tegra_cpu_exit,
+ .name = "tegra",
+ .attr = tegra_cpufreq_attr,
+};
+
+static int __init tegra_cpufreq_init(void)
+{
+ return cpufreq_register_driver(&tegra_cpufreq_driver);
+}
+
+static void __exit tegra_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&tegra_cpufreq_driver);
+}
+
+
+MODULE_AUTHOR("Colin Cross <ccross@android.com>");
+MODULE_DESCRIPTION("cpufreq driver for Nvidia Tegra2");
+MODULE_LICENSE("GPL");
+module_init(tegra_cpufreq_init);
+module_exit(tegra_cpufreq_exit);
diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c
new file mode 100644
index 000000000000..edda6ec5e925
--- /dev/null
+++ b/arch/arm/mach-tegra/dma.c
@@ -0,0 +1,752 @@
+/*
+ * arch/arm/mach-tegra/dma.c
+ *
+ * System DMA driver for NVIDIA Tegra SoCs
+ *
+ * Copyright (c) 2008-2009, NVIDIA 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; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <mach/dma.h>
+#include <mach/irqs.h>
+#include <mach/iomap.h>
+
+#define APB_DMA_GEN 0x000
+#define GEN_ENABLE (1<<31)
+
+#define APB_DMA_CNTRL 0x010
+
+#define APB_DMA_IRQ_MASK 0x01c
+
+#define APB_DMA_IRQ_MASK_SET 0x020
+
+#define APB_DMA_CHAN_CSR 0x000
+#define CSR_ENB (1<<31)
+#define CSR_IE_EOC (1<<30)
+#define CSR_HOLD (1<<29)
+#define CSR_DIR (1<<28)
+#define CSR_ONCE (1<<27)
+#define CSR_FLOW (1<<21)
+#define CSR_REQ_SEL_SHIFT 16
+#define CSR_REQ_SEL_MASK (0x1F<<CSR_REQ_SEL_SHIFT)
+#define CSR_REQ_SEL_INVALID (31<<CSR_REQ_SEL_SHIFT)
+#define CSR_WCOUNT_SHIFT 2
+#define CSR_WCOUNT_MASK 0xFFFC
+
+#define APB_DMA_CHAN_STA 0x004
+#define STA_BUSY (1<<31)
+#define STA_ISE_EOC (1<<30)
+#define STA_HALT (1<<29)
+#define STA_PING_PONG (1<<28)
+#define STA_COUNT_SHIFT 2
+#define STA_COUNT_MASK 0xFFFC
+
+#define APB_DMA_CHAN_AHB_PTR 0x010
+
+#define APB_DMA_CHAN_AHB_SEQ 0x014
+#define AHB_SEQ_INTR_ENB (1<<31)
+#define AHB_SEQ_BUS_WIDTH_SHIFT 28
+#define AHB_SEQ_BUS_WIDTH_MASK (0x7<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_BUS_WIDTH_8 (0<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_BUS_WIDTH_16 (1<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_BUS_WIDTH_32 (2<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_BUS_WIDTH_64 (3<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_BUS_WIDTH_128 (4<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_DATA_SWAP (1<<27)
+#define AHB_SEQ_BURST_MASK (0x7<<24)
+#define AHB_SEQ_BURST_1 (4<<24)
+#define AHB_SEQ_BURST_4 (5<<24)
+#define AHB_SEQ_BURST_8 (6<<24)
+#define AHB_SEQ_DBL_BUF (1<<19)
+#define AHB_SEQ_WRAP_SHIFT 16
+#define AHB_SEQ_WRAP_MASK (0x7<<AHB_SEQ_WRAP_SHIFT)
+
+#define APB_DMA_CHAN_APB_PTR 0x018
+
+#define APB_DMA_CHAN_APB_SEQ 0x01c
+#define APB_SEQ_BUS_WIDTH_SHIFT 28
+#define APB_SEQ_BUS_WIDTH_MASK (0x7<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_BUS_WIDTH_8 (0<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_BUS_WIDTH_16 (1<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_BUS_WIDTH_32 (2<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_BUS_WIDTH_64 (3<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_BUS_WIDTH_128 (4<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_DATA_SWAP (1<<27)
+#define APB_SEQ_WRAP_SHIFT 16
+#define APB_SEQ_WRAP_MASK (0x7<<APB_SEQ_WRAP_SHIFT)
+
+#define TEGRA_SYSTEM_DMA_CH_NR 16
+#define TEGRA_SYSTEM_DMA_AVP_CH_NUM 4
+#define TEGRA_SYSTEM_DMA_CH_MIN 0
+#define TEGRA_SYSTEM_DMA_CH_MAX \
+ (TEGRA_SYSTEM_DMA_CH_NR - TEGRA_SYSTEM_DMA_AVP_CH_NUM - 1)
+
+#define NV_DMA_MAX_TRASFER_SIZE 0x10000
+
+const unsigned int ahb_addr_wrap_table[8] = {
+ 0, 32, 64, 128, 256, 512, 1024, 2048
+};
+
+const unsigned int apb_addr_wrap_table[8] = {0, 1, 2, 4, 8, 16, 32, 64};
+
+const unsigned int bus_width_table[5] = {8, 16, 32, 64, 128};
+
+#define TEGRA_DMA_NAME_SIZE 16
+struct tegra_dma_channel {
+ struct list_head list;
+ int id;
+ spinlock_t lock;
+ char name[TEGRA_DMA_NAME_SIZE];
+ void __iomem *addr;
+ int mode;
+ int irq;
+
+ /* Register shadow */
+ u32 csr;
+ u32 ahb_seq;
+ u32 ahb_ptr;
+ u32 apb_seq;
+ u32 apb_ptr;
+};
+
+#define NV_DMA_MAX_CHANNELS 32
+
+static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS);
+static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS];
+
+static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
+ struct tegra_dma_req *req);
+static void tegra_dma_update_hw_partial(struct tegra_dma_channel *ch,
+ struct tegra_dma_req *req);
+static void tegra_dma_init_hw(struct tegra_dma_channel *ch);
+static void tegra_dma_stop(struct tegra_dma_channel *ch);
+
+void tegra_dma_flush(struct tegra_dma_channel *ch)
+{
+}
+EXPORT_SYMBOL(tegra_dma_flush);
+
+void tegra_dma_dequeue(struct tegra_dma_channel *ch)
+{
+ struct tegra_dma_req *req;
+
+ req = list_entry(ch->list.next, typeof(*req), node);
+
+ tegra_dma_dequeue_req(ch, req);
+ return;
+}
+
+void tegra_dma_stop(struct tegra_dma_channel *ch)
+{
+ unsigned int csr;
+ unsigned int status;
+
+ csr = ch->csr;
+ csr &= ~CSR_IE_EOC;
+ writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+
+ csr &= ~CSR_ENB;
+ writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+
+ status = readl(ch->addr + APB_DMA_CHAN_STA);
+ if (status & STA_ISE_EOC)
+ writel(status, ch->addr + APB_DMA_CHAN_STA);
+}
+
+int tegra_dma_cancel(struct tegra_dma_channel *ch)
+{
+ unsigned int csr;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&ch->lock, irq_flags);
+ while (!list_empty(&ch->list))
+ list_del(ch->list.next);
+
+ csr = ch->csr;
+ csr &= ~CSR_REQ_SEL_MASK;
+ csr |= CSR_REQ_SEL_INVALID;
+
+ /* Set the enable as that is not shadowed */
+ csr |= CSR_ENB;
+ writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+
+ tegra_dma_stop(ch);
+
+ spin_unlock_irqrestore(&ch->lock, irq_flags);
+ return 0;
+}
+
+int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
+ struct tegra_dma_req *_req)
+{
+ unsigned int csr;
+ unsigned int status;
+ struct tegra_dma_req *req = NULL;
+ int found = 0;
+ unsigned long irq_flags;
+ int to_transfer;
+ int req_transfer_count;
+
+ spin_lock_irqsave(&ch->lock, irq_flags);
+ list_for_each_entry(req, &ch->list, node) {
+ if (req == _req) {
+ list_del(&req->node);
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ spin_unlock_irqrestore(&ch->lock, irq_flags);
+ return 0;
+ }
+
+ /* STOP the DMA and get the transfer count.
+ * Getting the transfer count is tricky.
+ * - Change the source selector to invalid to stop the DMA from
+ * FIFO to memory.
+ * - Read the status register to know the number of pending
+ * bytes to be transfered.
+ * - Finally stop or program the DMA to the next buffer in the
+ * list.
+ */
+ csr = ch->csr;
+ csr &= ~CSR_REQ_SEL_MASK;
+ csr |= CSR_REQ_SEL_INVALID;
+
+ /* Set the enable as that is not shadowed */
+ csr |= CSR_ENB;
+ writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+
+ /* Get the transfer count */
+ status = readl(ch->addr + APB_DMA_CHAN_STA);
+ to_transfer = (status & STA_COUNT_MASK) >> STA_COUNT_SHIFT;
+ req_transfer_count = (ch->csr & CSR_WCOUNT_MASK) >> CSR_WCOUNT_SHIFT;
+ req_transfer_count += 1;
+ to_transfer += 1;
+
+ req->bytes_transferred = req_transfer_count;
+
+ if (status & STA_BUSY)
+ req->bytes_transferred -= to_transfer;
+
+ /* In continous transfer mode, DMA only tracks the count of the
+ * half DMA buffer. So, if the DMA already finished half the DMA
+ * then add the half buffer to the completed count.
+ *
+ * FIXME: There can be a race here. What if the req to
+ * dequue happens at the same time as the DMA just moved to
+ * the new buffer and SW didn't yet received the interrupt?
+ */
+ if (ch->mode & TEGRA_DMA_MODE_CONTINOUS)
+ if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL)
+ req->bytes_transferred += req_transfer_count;
+
+ req->bytes_transferred *= 4;
+
+ tegra_dma_stop(ch);
+ if (!list_empty(&ch->list)) {
+ /* if the list is not empty, queue the next request */
+ struct tegra_dma_req *next_req;
+ next_req = list_entry(ch->list.next,
+ typeof(*next_req), node);
+ tegra_dma_update_hw(ch, next_req);
+ }
+ req->status = -TEGRA_DMA_REQ_ERROR_ABORTED;
+
+ spin_unlock_irqrestore(&ch->lock, irq_flags);
+
+ /* Callback should be called without any lock */
+ req->complete(req);
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dma_dequeue_req);
+
+bool tegra_dma_is_empty(struct tegra_dma_channel *ch)
+{
+ unsigned long irq_flags;
+ bool is_empty;
+
+ spin_lock_irqsave(&ch->lock, irq_flags);
+ if (list_empty(&ch->list))
+ is_empty = true;
+ else
+ is_empty = false;
+ spin_unlock_irqrestore(&ch->lock, irq_flags);
+ return is_empty;
+}
+EXPORT_SYMBOL(tegra_dma_is_empty);
+
+bool tegra_dma_is_req_inflight(struct tegra_dma_channel *ch,
+ struct tegra_dma_req *_req)
+{
+ unsigned long irq_flags;
+ struct tegra_dma_req *req;
+
+ spin_lock_irqsave(&ch->lock, irq_flags);
+ list_for_each_entry(req, &ch->list, node) {
+ if (req == _req) {
+ spin_unlock_irqrestore(&ch->lock, irq_flags);
+ return true;
+ }
+ }
+ spin_unlock_irqrestore(&ch->lock, irq_flags);
+ return false;
+}
+EXPORT_SYMBOL(tegra_dma_is_req_inflight);
+
+int tegra_dma_enqueue_req(struct tegra_dma_channel *ch,
+ struct tegra_dma_req *req)
+{
+ unsigned long irq_flags;
+ int start_dma = 0;
+
+ if (req->size > NV_DMA_MAX_TRASFER_SIZE ||
+ req->source_addr & 0x3 || req->dest_addr & 0x3) {
+ pr_err("Invalid DMA request for channel %d\n", ch->id);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&ch->lock, irq_flags);
+
+ req->bytes_transferred = 0;
+ req->status = 0;
+ req->buffer_status = 0;
+ if (list_empty(&ch->list))
+ start_dma = 1;
+
+ list_add_tail(&req->node, &ch->list);
+
+ if (start_dma)
+ tegra_dma_update_hw(ch, req);
+
+ spin_unlock_irqrestore(&ch->lock, irq_flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dma_enqueue_req);
+
+struct tegra_dma_channel *tegra_dma_allocate_channel(int mode)
+{
+ int channel;
+ struct tegra_dma_channel *ch;
+
+ /* first channel is the shared channel */
+ if (mode & TEGRA_DMA_SHARED) {
+ channel = TEGRA_SYSTEM_DMA_CH_MIN;
+ } else {
+ channel = find_first_zero_bit(channel_usage,
+ ARRAY_SIZE(dma_channels));
+ if (channel >= ARRAY_SIZE(dma_channels))
+ return NULL;
+ }
+ __set_bit(channel, channel_usage);
+ ch = &dma_channels[channel];
+ ch->mode = mode;
+ return ch;
+}
+EXPORT_SYMBOL(tegra_dma_allocate_channel);
+
+void tegra_dma_free_channel(struct tegra_dma_channel *ch)
+{
+ if (ch->mode & TEGRA_DMA_SHARED)
+ return;
+ tegra_dma_cancel(ch);
+ __clear_bit(ch->id, channel_usage);
+}
+EXPORT_SYMBOL(tegra_dma_free_channel);
+
+static void tegra_dma_update_hw_partial(struct tegra_dma_channel *ch,
+ struct tegra_dma_req *req)
+{
+ if (req->to_memory) {
+ ch->apb_ptr = req->source_addr;
+ ch->ahb_ptr = req->dest_addr;
+ } else {
+ ch->apb_ptr = req->dest_addr;
+ ch->ahb_ptr = req->source_addr;
+ }
+ writel(ch->apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR);
+ writel(ch->ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR);
+
+ req->status = TEGRA_DMA_REQ_INFLIGHT;
+ return;
+}
+
+static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
+ struct tegra_dma_req *req)
+{
+ int ahb_addr_wrap;
+ int apb_addr_wrap;
+ int ahb_bus_width;
+ int apb_bus_width;
+ int index;
+ unsigned long csr;
+
+
+ ch->csr |= CSR_FLOW;
+ ch->csr &= ~CSR_REQ_SEL_MASK;
+ ch->csr |= req->req_sel << CSR_REQ_SEL_SHIFT;
+ ch->ahb_seq &= ~AHB_SEQ_BURST_MASK;
+ ch->ahb_seq |= AHB_SEQ_BURST_1;
+
+ /* One shot mode is always single buffered,
+ * continuous mode is always double buffered
+ * */
+ if (ch->mode & TEGRA_DMA_MODE_ONESHOT) {
+ ch->csr |= CSR_ONCE;
+ ch->ahb_seq &= ~AHB_SEQ_DBL_BUF;
+ ch->csr &= ~CSR_WCOUNT_MASK;
+ ch->csr |= ((req->size>>2) - 1) << CSR_WCOUNT_SHIFT;
+ } else {
+ ch->csr &= ~CSR_ONCE;
+ ch->ahb_seq |= AHB_SEQ_DBL_BUF;
+
+ /* In double buffered mode, we set the size to half the
+ * requested size and interrupt when half the buffer
+ * is full */
+ ch->csr &= ~CSR_WCOUNT_MASK;
+ ch->csr |= ((req->size>>3) - 1) << CSR_WCOUNT_SHIFT;
+ }
+
+ if (req->to_memory) {
+ ch->csr &= ~CSR_DIR;
+ ch->apb_ptr = req->source_addr;
+ ch->ahb_ptr = req->dest_addr;
+
+ apb_addr_wrap = req->source_wrap;
+ ahb_addr_wrap = req->dest_wrap;
+ apb_bus_width = req->source_bus_width;
+ ahb_bus_width = req->dest_bus_width;
+
+ } else {
+ ch->csr |= CSR_DIR;
+ ch->apb_ptr = req->dest_addr;
+ ch->ahb_ptr = req->source_addr;
+
+ apb_addr_wrap = req->dest_wrap;
+ ahb_addr_wrap = req->source_wrap;
+ apb_bus_width = req->dest_bus_width;
+ ahb_bus_width = req->source_bus_width;
+ }
+
+ apb_addr_wrap >>= 2;
+ ahb_addr_wrap >>= 2;
+
+ /* set address wrap for APB size */
+ index = 0;
+ do {
+ if (apb_addr_wrap_table[index] == apb_addr_wrap)
+ break;
+ index++;
+ } while (index < ARRAY_SIZE(apb_addr_wrap_table));
+ BUG_ON(index == ARRAY_SIZE(apb_addr_wrap_table));
+ ch->apb_seq &= ~APB_SEQ_WRAP_MASK;
+ ch->apb_seq |= index << APB_SEQ_WRAP_SHIFT;
+
+ /* set address wrap for AHB size */
+ index = 0;
+ do {
+ if (ahb_addr_wrap_table[index] == ahb_addr_wrap)
+ break;
+ index++;
+ } while (index < ARRAY_SIZE(ahb_addr_wrap_table));
+ BUG_ON(index == ARRAY_SIZE(ahb_addr_wrap_table));
+ ch->ahb_seq &= ~AHB_SEQ_WRAP_MASK;
+ ch->ahb_seq |= index << AHB_SEQ_WRAP_SHIFT;
+
+ for (index = 0; index < ARRAY_SIZE(bus_width_table); index++) {
+ if (bus_width_table[index] == ahb_bus_width)
+ break;
+ }
+ BUG_ON(index == ARRAY_SIZE(bus_width_table));
+ ch->ahb_seq &= ~AHB_SEQ_BUS_WIDTH_MASK;
+ ch->ahb_seq |= index << AHB_SEQ_BUS_WIDTH_SHIFT;
+
+ for (index = 0; index < ARRAY_SIZE(bus_width_table); index++) {
+ if (bus_width_table[index] == apb_bus_width)
+ break;
+ }
+ BUG_ON(index == ARRAY_SIZE(bus_width_table));
+ ch->apb_seq &= ~APB_SEQ_BUS_WIDTH_MASK;
+ ch->apb_seq |= index << APB_SEQ_BUS_WIDTH_SHIFT;
+
+ ch->csr |= CSR_IE_EOC;
+
+ /* update hw registers with the shadow */
+ writel(ch->csr, ch->addr + APB_DMA_CHAN_CSR);
+ writel(ch->apb_seq, ch->addr + APB_DMA_CHAN_APB_SEQ);
+ writel(ch->apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR);
+ writel(ch->ahb_seq, ch->addr + APB_DMA_CHAN_AHB_SEQ);
+ writel(ch->ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR);
+
+ csr = ch->csr | CSR_ENB;
+ writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+
+ req->status = TEGRA_DMA_REQ_INFLIGHT;
+}
+
+static void tegra_dma_init_hw(struct tegra_dma_channel *ch)
+{
+ /* One shot with an interrupt to CPU after transfer */
+ ch->csr = CSR_ONCE | CSR_IE_EOC;
+ ch->ahb_seq = AHB_SEQ_BUS_WIDTH_32 | AHB_SEQ_INTR_ENB;
+ ch->apb_seq = APB_SEQ_BUS_WIDTH_32 | 1 << APB_SEQ_WRAP_SHIFT;
+}
+
+static void handle_oneshot_dma(struct tegra_dma_channel *ch)
+{
+ struct tegra_dma_req *req;
+
+ spin_lock(&ch->lock);
+ if (list_empty(&ch->list)) {
+ spin_unlock(&ch->lock);
+ return;
+ }
+
+ req = list_entry(ch->list.next, typeof(*req), node);
+ if (req) {
+ int bytes_transferred;
+
+ bytes_transferred =
+ (ch->csr & CSR_WCOUNT_MASK) >> CSR_WCOUNT_SHIFT;
+ bytes_transferred += 1;
+ bytes_transferred <<= 2;
+
+ list_del(&req->node);
+ req->bytes_transferred = bytes_transferred;
+ req->status = TEGRA_DMA_REQ_SUCCESS;
+
+ spin_unlock(&ch->lock);
+ /* Callback should be called without any lock */
+ pr_debug("%s: transferred %d bytes\n", __func__,
+ req->bytes_transferred);
+ req->complete(req);
+ spin_lock(&ch->lock);
+ }
+
+ if (!list_empty(&ch->list)) {
+ req = list_entry(ch->list.next, typeof(*req), node);
+ /* the complete function we just called may have enqueued
+ another req, in which case dma has already started */
+ if (req->status != TEGRA_DMA_REQ_INFLIGHT)
+ tegra_dma_update_hw(ch, req);
+ }
+ spin_unlock(&ch->lock);
+}
+
+static void handle_continuous_dma(struct tegra_dma_channel *ch)
+{
+ struct tegra_dma_req *req;
+
+ spin_lock(&ch->lock);
+ if (list_empty(&ch->list)) {
+ spin_unlock(&ch->lock);
+ return;
+ }
+
+ req = list_entry(ch->list.next, typeof(*req), node);
+ if (req) {
+ if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_EMPTY) {
+ /* Load the next request into the hardware, if available
+ * */
+ if (!list_is_last(&req->node, &ch->list)) {
+ struct tegra_dma_req *next_req;
+
+ next_req = list_entry(req->node.next,
+ typeof(*next_req), node);
+ tegra_dma_update_hw_partial(ch, next_req);
+ }
+ req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL;
+ req->status = TEGRA_DMA_REQ_SUCCESS;
+ /* DMA lock is NOT held when callback is called */
+ spin_unlock(&ch->lock);
+ if (likely(req->threshold))
+ req->threshold(req);
+ return;
+
+ } else if (req->buffer_status ==
+ TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) {
+ /* Callback when the buffer is completely full (i.e on
+ * the second interrupt */
+ int bytes_transferred;
+
+ bytes_transferred =
+ (ch->csr & CSR_WCOUNT_MASK) >> CSR_WCOUNT_SHIFT;
+ bytes_transferred += 1;
+ bytes_transferred <<= 3;
+
+ req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_FULL;
+ req->bytes_transferred = bytes_transferred;
+ req->status = TEGRA_DMA_REQ_SUCCESS;
+ list_del(&req->node);
+
+ /* DMA lock is NOT held when callbak is called */
+ spin_unlock(&ch->lock);
+ req->complete(req);
+ return;
+
+ } else {
+ BUG();
+ }
+ }
+ spin_unlock(&ch->lock);
+}
+
+static irqreturn_t dma_isr(int irq, void *data)
+{
+ struct tegra_dma_channel *ch = data;
+ unsigned long status;
+
+ status = readl(ch->addr + APB_DMA_CHAN_STA);
+ if (status & STA_ISE_EOC)
+ writel(status, ch->addr + APB_DMA_CHAN_STA);
+ else {
+ pr_warning("Got a spurious ISR for DMA channel %d\n", ch->id);
+ return IRQ_HANDLED;
+ }
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t dma_thread_fn(int irq, void *data)
+{
+ struct tegra_dma_channel *ch = data;
+
+ if (ch->mode & TEGRA_DMA_MODE_ONESHOT)
+ handle_oneshot_dma(ch);
+ else
+ handle_continuous_dma(ch);
+
+
+ return IRQ_HANDLED;
+}
+
+int __init tegra_dma_init(void)
+{
+ int ret = 0;
+ int i;
+ unsigned int irq;
+ void __iomem *addr;
+
+ addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
+ writel(GEN_ENABLE, addr + APB_DMA_GEN);
+ writel(0, addr + APB_DMA_CNTRL);
+ writel(0xFFFFFFFFul >> (31 - TEGRA_SYSTEM_DMA_CH_MAX),
+ addr + APB_DMA_IRQ_MASK_SET);
+
+ memset(channel_usage, 0, sizeof(channel_usage));
+ memset(dma_channels, 0, sizeof(dma_channels));
+
+ /* Reserve all the channels we are not supposed to touch */
+ for (i = 0; i < TEGRA_SYSTEM_DMA_CH_MIN; i++)
+ __set_bit(i, channel_usage);
+
+ for (i = TEGRA_SYSTEM_DMA_CH_MIN; i <= TEGRA_SYSTEM_DMA_CH_MAX; i++) {
+ struct tegra_dma_channel *ch = &dma_channels[i];
+
+ __clear_bit(i, channel_usage);
+
+ ch->id = i;
+ snprintf(ch->name, TEGRA_DMA_NAME_SIZE, "dma_channel_%d", i);
+
+ ch->addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE +
+ TEGRA_APB_DMA_CH0_SIZE * i);
+
+ spin_lock_init(&ch->lock);
+ INIT_LIST_HEAD(&ch->list);
+ tegra_dma_init_hw(ch);
+
+ irq = INT_APB_DMA_CH0 + i;
+ ret = request_threaded_irq(irq, dma_isr, dma_thread_fn, 0,
+ dma_channels[i].name, ch);
+ if (ret) {
+ pr_err("Failed to register IRQ %d for DMA %d\n",
+ irq, i);
+ goto fail;
+ }
+ ch->irq = irq;
+ }
+ /* mark the shared channel allocated */
+ __set_bit(TEGRA_SYSTEM_DMA_CH_MIN, channel_usage);
+
+ for (i = TEGRA_SYSTEM_DMA_CH_MAX+1; i < NV_DMA_MAX_CHANNELS; i++)
+ __set_bit(i, channel_usage);
+
+ return ret;
+fail:
+ writel(0, addr + APB_DMA_GEN);
+ for (i = TEGRA_SYSTEM_DMA_CH_MIN; i <= TEGRA_SYSTEM_DMA_CH_MAX; i++) {
+ struct tegra_dma_channel *ch = &dma_channels[i];
+ if (ch->irq)
+ free_irq(ch->irq, ch);
+ }
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static u32 apb_dma[5*TEGRA_SYSTEM_DMA_CH_NR + 3];
+
+void tegra_dma_suspend(void)
+{
+ void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
+ u32 *ctx = apb_dma;
+ int i;
+
+ *ctx++ = readl(addr + APB_DMA_GEN);
+ *ctx++ = readl(addr + APB_DMA_CNTRL);
+ *ctx++ = readl(addr + APB_DMA_IRQ_MASK);
+
+ for (i = 0; i < TEGRA_SYSTEM_DMA_CH_NR; i++) {
+ addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE +
+ TEGRA_APB_DMA_CH0_SIZE * i);
+
+ *ctx++ = readl(addr + APB_DMA_CHAN_CSR);
+ *ctx++ = readl(addr + APB_DMA_CHAN_AHB_PTR);
+ *ctx++ = readl(addr + APB_DMA_CHAN_AHB_SEQ);
+ *ctx++ = readl(addr + APB_DMA_CHAN_APB_PTR);
+ *ctx++ = readl(addr + APB_DMA_CHAN_APB_SEQ);
+ }
+}
+
+void tegra_dma_resume(void)
+{
+ void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
+ u32 *ctx = apb_dma;
+ int i;
+
+ writel(*ctx++, addr + APB_DMA_GEN);
+ writel(*ctx++, addr + APB_DMA_CNTRL);
+ writel(*ctx++, addr + APB_DMA_IRQ_MASK);
+
+ for (i = 0; i < TEGRA_SYSTEM_DMA_CH_NR; i++) {
+ addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE +
+ TEGRA_APB_DMA_CH0_SIZE * i);
+
+ writel(*ctx++, addr + APB_DMA_CHAN_CSR);
+ writel(*ctx++, addr + APB_DMA_CHAN_AHB_PTR);
+ writel(*ctx++, addr + APB_DMA_CHAN_AHB_SEQ);
+ writel(*ctx++, addr + APB_DMA_CHAN_APB_PTR);
+ writel(*ctx++, addr + APB_DMA_CHAN_APB_SEQ);
+ }
+}
+
+#endif
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
new file mode 100644
index 000000000000..1fa26d9a1a68
--- /dev/null
+++ b/arch/arm/mach-tegra/fuse.c
@@ -0,0 +1,84 @@
+/*
+ * arch/arm/mach-tegra/fuse.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ * Colin Cross <ccross@android.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/kernel.h>
+#include <linux/io.h>
+
+#include <mach/iomap.h>
+
+#include "fuse.h"
+
+#define FUSE_UID_LOW 0x108
+#define FUSE_UID_HIGH 0x10c
+#define FUSE_SKU_INFO 0x110
+#define FUSE_SPARE_BIT 0x200
+
+static inline u32 fuse_readl(unsigned long offset)
+{
+ return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
+}
+
+static inline void fuse_writel(u32 value, unsigned long offset)
+{
+ writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
+}
+
+void tegra_init_fuse(void)
+{
+ u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
+ reg |= 1 << 28;
+ writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
+
+ pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n",
+ tegra_sku_id(), tegra_cpu_process_id(),
+ tegra_core_process_id());
+}
+
+unsigned long long tegra_chip_uid(void)
+{
+ unsigned long long lo, hi;
+
+ lo = fuse_readl(FUSE_UID_LOW);
+ hi = fuse_readl(FUSE_UID_HIGH);
+ return (hi << 32ull) | lo;
+}
+
+int tegra_sku_id(void)
+{
+ int sku_id;
+ u32 reg = fuse_readl(FUSE_SKU_INFO);
+ sku_id = reg & 0xFF;
+ return sku_id;
+}
+
+int tegra_cpu_process_id(void)
+{
+ int cpu_process_id;
+ u32 reg = fuse_readl(FUSE_SPARE_BIT);
+ cpu_process_id = (reg >> 6) & 3;
+ return cpu_process_id;
+}
+
+int tegra_core_process_id(void)
+{
+ int core_process_id;
+ u32 reg = fuse_readl(FUSE_SPARE_BIT);
+ core_process_id = (reg >> 12) & 3;
+ return core_process_id;
+}
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
new file mode 100644
index 000000000000..584b2e27dbda
--- /dev/null
+++ b/arch/arm/mach-tegra/fuse.h
@@ -0,0 +1,24 @@
+/*
+ * arch/arm/mach-tegra/fuse.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ * Colin Cross <ccross@android.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.
+ *
+ */
+
+unsigned long long tegra_chip_uid(void);
+int tegra_sku_id(void);
+int tegra_cpu_process_id(void);
+int tegra_core_process_id(void);
+void tegra_init_fuse(void);
diff --git a/arch/arm/mach-tegra/gpio.c b/arch/arm/mach-tegra/gpio.c
index fe78fba25f3c..0775265e69f5 100644
--- a/arch/arm/mach-tegra/gpio.c
+++ b/arch/arm/mach-tegra/gpio.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/irq.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/gpio.h>
@@ -60,6 +61,13 @@ struct tegra_gpio_bank {
int bank;
int irq;
spinlock_t lvl_lock[4];
+#ifdef CONFIG_PM
+ u32 cnf[4];
+ u32 out[4];
+ u32 oe[4];
+ u32 int_enb[4];
+ u32 int_lvl[4];
+#endif
};
@@ -131,7 +139,7 @@ static struct gpio_chip tegra_gpio_chip = {
.direction_output = tegra_gpio_direction_output,
.set = tegra_gpio_set,
.base = 0,
- .ngpio = ARCH_NR_GPIOS,
+ .ngpio = TEGRA_NR_GPIOS,
};
static void tegra_gpio_irq_ack(unsigned int irq)
@@ -244,6 +252,76 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
}
+#ifdef CONFIG_PM
+void tegra_gpio_resume(void)
+{
+ unsigned long flags;
+ int b, p, i;
+
+ local_irq_save(flags);
+
+ for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
+ struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
+
+ for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
+ unsigned int gpio = (b<<5) | (p<<3);
+ __raw_writel(bank->cnf[p], GPIO_CNF(gpio));
+ __raw_writel(bank->out[p], GPIO_OUT(gpio));
+ __raw_writel(bank->oe[p], GPIO_OE(gpio));
+ __raw_writel(bank->int_lvl[p], GPIO_INT_LVL(gpio));
+ __raw_writel(bank->int_enb[p], GPIO_INT_ENB(gpio));
+ }
+ }
+
+ local_irq_restore(flags);
+
+ for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
+ struct irq_desc *desc = irq_to_desc(i);
+ if (!desc || (desc->status & IRQ_WAKEUP))
+ continue;
+ enable_irq(i);
+ }
+}
+
+void tegra_gpio_suspend(void)
+{
+ unsigned long flags;
+ int b, p, i;
+
+ for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
+ struct irq_desc *desc = irq_to_desc(i);
+ if (!desc)
+ continue;
+ if (desc->status & IRQ_WAKEUP) {
+ int gpio = i - INT_GPIO_BASE;
+ pr_debug("gpio %d.%d is wakeup\n", gpio/8, gpio&7);
+ continue;
+ }
+ disable_irq(i);
+ }
+
+ local_irq_save(flags);
+ for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
+ struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
+
+ for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
+ unsigned int gpio = (b<<5) | (p<<3);
+ bank->cnf[p] = __raw_readl(GPIO_CNF(gpio));
+ bank->out[p] = __raw_readl(GPIO_OUT(gpio));
+ bank->oe[p] = __raw_readl(GPIO_OE(gpio));
+ bank->int_enb[p] = __raw_readl(GPIO_INT_ENB(gpio));
+ bank->int_lvl[p] = __raw_readl(GPIO_INT_LVL(gpio));
+ }
+ }
+ local_irq_restore(flags);
+}
+
+static int tegra_gpio_wake_enable(unsigned int irq, unsigned int enable)
+{
+ struct tegra_gpio_bank *bank = get_irq_chip_data(irq);
+ return set_irq_wake(bank->irq, enable);
+}
+#endif
static struct irq_chip tegra_gpio_irq_chip = {
.name = "GPIO",
@@ -251,6 +329,9 @@ static struct irq_chip tegra_gpio_irq_chip = {
.mask = tegra_gpio_irq_mask,
.unmask = tegra_gpio_irq_unmask,
.set_type = tegra_gpio_irq_set_type,
+#ifdef CONFIG_PM
+ .set_wake = tegra_gpio_wake_enable,
+#endif
};
@@ -274,7 +355,7 @@ static int __init tegra_gpio_init(void)
gpiochip_add(&tegra_gpio_chip);
- for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + ARCH_NR_GPIOS); i++) {
+ for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
bank = &tegra_gpio_banks[GPIO_BANK(irq_to_gpio(i))];
lockdep_set_class(&irq_desc[i].lock, &gpio_lock_class);
@@ -312,15 +393,16 @@ static int dbg_gpio_show(struct seq_file *s, void *unused)
for (i = 0; i < 7; i++) {
for (j = 0; j < 4; j++) {
int gpio = tegra_gpio_compose(i, j, 0);
- seq_printf(s, "%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
- i, j,
- __raw_readl(GPIO_CNF(gpio)),
- __raw_readl(GPIO_OE(gpio)),
- __raw_readl(GPIO_OUT(gpio)),
- __raw_readl(GPIO_IN(gpio)),
- __raw_readl(GPIO_INT_STA(gpio)),
- __raw_readl(GPIO_INT_ENB(gpio)),
- __raw_readl(GPIO_INT_LVL(gpio)));
+ seq_printf(s,
+ "%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
+ i, j,
+ __raw_readl(GPIO_CNF(gpio)),
+ __raw_readl(GPIO_OE(gpio)),
+ __raw_readl(GPIO_OUT(gpio)),
+ __raw_readl(GPIO_IN(gpio)),
+ __raw_readl(GPIO_INT_STA(gpio)),
+ __raw_readl(GPIO_INT_ENB(gpio)),
+ __raw_readl(GPIO_INT_LVL(gpio)));
}
}
return 0;
diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h
index 2896f25ebfb5..d7723955dac7 100644
--- a/arch/arm/mach-tegra/include/mach/clk.h
+++ b/arch/arm/mach-tegra/include/mach/clk.h
@@ -23,4 +23,9 @@
void tegra_periph_reset_deassert(struct clk *c);
void tegra_periph_reset_assert(struct clk *c);
+int clk_enable_cansleep(struct clk *clk);
+void clk_disable_cansleep(struct clk *clk);
+int clk_set_rate_cansleep(struct clk *clk, unsigned long rate);
+int clk_set_parent_cansleep(struct clk *clk, struct clk *parent);
+
#endif
diff --git a/arch/arm/mach-tegra/include/mach/dma.h b/arch/arm/mach-tegra/include/mach/dma.h
new file mode 100644
index 000000000000..39011bd9a925
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/dma.h
@@ -0,0 +1,155 @@
+/*
+ * arch/arm/mach-tegra/include/mach/dma.h
+ *
+ * Copyright (c) 2008-2009, NVIDIA 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; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __MACH_TEGRA_DMA_H
+#define __MACH_TEGRA_DMA_H
+
+#include <linux/list.h>
+
+#if defined(CONFIG_TEGRA_SYSTEM_DMA)
+
+struct tegra_dma_req;
+struct tegra_dma_channel;
+
+#define TEGRA_DMA_REQ_SEL_CNTR 0
+#define TEGRA_DMA_REQ_SEL_I2S_2 1
+#define TEGRA_DMA_REQ_SEL_I2S_1 2
+#define TEGRA_DMA_REQ_SEL_SPD_I 3
+#define TEGRA_DMA_REQ_SEL_UI_I 4
+#define TEGRA_DMA_REQ_SEL_MIPI 5
+#define TEGRA_DMA_REQ_SEL_I2S2_2 6
+#define TEGRA_DMA_REQ_SEL_I2S2_1 7
+#define TEGRA_DMA_REQ_SEL_UARTA 8
+#define TEGRA_DMA_REQ_SEL_UARTB 9
+#define TEGRA_DMA_REQ_SEL_UARTC 10
+#define TEGRA_DMA_REQ_SEL_SPI 11
+#define TEGRA_DMA_REQ_SEL_AC97 12
+#define TEGRA_DMA_REQ_SEL_ACMODEM 13
+#define TEGRA_DMA_REQ_SEL_SL4B 14
+#define TEGRA_DMA_REQ_SEL_SL2B1 15
+#define TEGRA_DMA_REQ_SEL_SL2B2 16
+#define TEGRA_DMA_REQ_SEL_SL2B3 17
+#define TEGRA_DMA_REQ_SEL_SL2B4 18
+#define TEGRA_DMA_REQ_SEL_UARTD 19
+#define TEGRA_DMA_REQ_SEL_UARTE 20
+#define TEGRA_DMA_REQ_SEL_I2C 21
+#define TEGRA_DMA_REQ_SEL_I2C2 22
+#define TEGRA_DMA_REQ_SEL_I2C3 23
+#define TEGRA_DMA_REQ_SEL_DVC_I2C 24
+#define TEGRA_DMA_REQ_SEL_OWR 25
+#define TEGRA_DMA_REQ_SEL_INVALID 31
+
+enum tegra_dma_mode {
+ TEGRA_DMA_SHARED = 1,
+ TEGRA_DMA_MODE_CONTINOUS = 2,
+ TEGRA_DMA_MODE_ONESHOT = 4,
+};
+
+enum tegra_dma_req_error {
+ TEGRA_DMA_REQ_SUCCESS = 0,
+ TEGRA_DMA_REQ_ERROR_ABORTED,
+ TEGRA_DMA_REQ_INFLIGHT,
+};
+
+enum tegra_dma_req_buff_status {
+ TEGRA_DMA_REQ_BUF_STATUS_EMPTY = 0,
+ TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL,
+ TEGRA_DMA_REQ_BUF_STATUS_FULL,
+};
+
+struct tegra_dma_req {
+ struct list_head node;
+ unsigned int modid;
+ int instance;
+
+ /* Called when the req is complete and from the DMA ISR context.
+ * When this is called the req structure is no longer queued by
+ * the DMA channel.
+ *
+ * State of the DMA depends on the number of req it has. If there are
+ * no DMA requests queued up, then it will STOP the DMA. It there are
+ * more requests in the DMA, then it will queue the next request.
+ */
+ void (*complete)(struct tegra_dma_req *req);
+
+ /* This is a called from the DMA ISR context when the DMA is still in
+ * progress and is actively filling same buffer.
+ *
+ * In case of continous mode receive, this threshold is 1/2 the buffer
+ * size. In other cases, this will not even be called as there is no
+ * hardware support for it.
+ *
+ * In the case of continous mode receive, if there is next req already
+ * queued, DMA programs the HW to use that req when this req is
+ * completed. If there is no "next req" queued, then DMA ISR doesn't do
+ * anything before calling this callback.
+ *
+ * This is mainly used by the cases, where the clients has queued
+ * only one req and want to get some sort of DMA threshold
+ * callback to program the next buffer.
+ *
+ */
+ void (*threshold)(struct tegra_dma_req *req);
+
+ /* 1 to copy to memory.
+ * 0 to copy from the memory to device FIFO */
+ int to_memory;
+
+ void *virt_addr;
+
+ unsigned long source_addr;
+ unsigned long dest_addr;
+ unsigned long dest_wrap;
+ unsigned long source_wrap;
+ unsigned long source_bus_width;
+ unsigned long dest_bus_width;
+ unsigned long req_sel;
+ unsigned int size;
+
+ /* Updated by the DMA driver on the conpletion of the request. */
+ int bytes_transferred;
+ int status;
+
+ /* DMA completion tracking information */
+ int buffer_status;
+
+ /* Client specific data */
+ void *dev;
+};
+
+int tegra_dma_enqueue_req(struct tegra_dma_channel *ch,
+ struct tegra_dma_req *req);
+int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
+ struct tegra_dma_req *req);
+void tegra_dma_dequeue(struct tegra_dma_channel *ch);
+void tegra_dma_flush(struct tegra_dma_channel *ch);
+
+bool tegra_dma_is_req_inflight(struct tegra_dma_channel *ch,
+ struct tegra_dma_req *req);
+bool tegra_dma_is_empty(struct tegra_dma_channel *ch);
+
+struct tegra_dma_channel *tegra_dma_allocate_channel(int mode);
+void tegra_dma_free_channel(struct tegra_dma_channel *ch);
+
+int __init tegra_dma_init(void);
+
+#endif
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/gpio.h b/arch/arm/mach-tegra/include/mach/gpio.h
index 540e822e50f7..e31f486d69a2 100644
--- a/arch/arm/mach-tegra/include/mach/gpio.h
+++ b/arch/arm/mach-tegra/include/mach/gpio.h
@@ -22,7 +22,7 @@
#include <mach/irqs.h>
-#define ARCH_NR_GPIOS INT_GPIO_NR
+#define TEGRA_NR_GPIOS INT_GPIO_NR
#include <asm-generic/gpio.h>
@@ -35,7 +35,7 @@
static inline int gpio_to_irq(unsigned int gpio)
{
- if (gpio < ARCH_NR_GPIOS)
+ if (gpio < TEGRA_NR_GPIOS)
return INT_GPIO_BASE + gpio;
return -EINVAL;
}
diff --git a/arch/arm/mach-tegra/include/mach/hardware.h b/arch/arm/mach-tegra/include/mach/hardware.h
index 6014edf60d93..56e43b3a5b97 100644
--- a/arch/arm/mach-tegra/include/mach/hardware.h
+++ b/arch/arm/mach-tegra/include/mach/hardware.h
@@ -21,4 +21,8 @@
#ifndef __MACH_TEGRA_HARDWARE_H
#define __MACH_TEGRA_HARDWARE_H
+#define PCIBIOS_MIN_IO 0x1000
+#define PCIBIOS_MIN_MEM 0
+#define pcibios_assign_all_busses() 1
+
#endif
diff --git a/arch/arm/mach-tegra/include/mach/io.h b/arch/arm/mach-tegra/include/mach/io.h
index 35edfc32ffc9..f0981b1ac59e 100644
--- a/arch/arm/mach-tegra/include/mach/io.h
+++ b/arch/arm/mach-tegra/include/mach/io.h
@@ -21,7 +21,7 @@
#ifndef __MACH_TEGRA_IO_H
#define __MACH_TEGRA_IO_H
-#define IO_SPACE_LIMIT 0xffffffff
+#define IO_SPACE_LIMIT 0xffff
/* On TEGRA, many peripherals are very closely packed in
* two 256MB io windows (that actually only use about 64KB
@@ -33,6 +33,10 @@
*
*/
+#define IO_IRAM_PHYS 0x40000000
+#define IO_IRAM_VIRT 0xFE400000
+#define IO_IRAM_SIZE SZ_256K
+
#define IO_CPU_PHYS 0x50040000
#define IO_CPU_VIRT 0xFE000000
#define IO_CPU_SIZE SZ_16K
@@ -55,6 +59,8 @@
IO_TO_VIRT_XLATE((n), IO_APB_PHYS, IO_APB_VIRT) : \
IO_TO_VIRT_BETWEEN((n), IO_CPU_PHYS, IO_CPU_SIZE) ? \
IO_TO_VIRT_XLATE((n), IO_CPU_PHYS, IO_CPU_VIRT) : \
+ IO_TO_VIRT_BETWEEN((n), IO_IRAM_PHYS, IO_IRAM_SIZE) ? \
+ IO_TO_VIRT_XLATE((n), IO_IRAM_PHYS, IO_IRAM_VIRT) : \
0)
#ifndef __ASSEMBLER__
@@ -67,10 +73,20 @@ void tegra_iounmap(volatile void __iomem *addr);
#define IO_ADDRESS(n) ((void __iomem *) IO_TO_VIRT(n))
+#ifdef CONFIG_TEGRA_PCI
+extern void __iomem *tegra_pcie_io_base;
+
+static inline void __iomem *__io(unsigned long addr)
+{
+ return tegra_pcie_io_base + (addr & IO_SPACE_LIMIT);
+}
+#else
static inline void __iomem *__io(unsigned long addr)
{
return (void __iomem *)addr;
}
+#endif
+
#define __io(a) __io(a)
#define __mem_pci(a) (a)
diff --git a/arch/arm/mach-tegra/include/mach/iomap.h b/arch/arm/mach-tegra/include/mach/iomap.h
index 1741f7dd7a9b..44a4f4bcf91f 100644
--- a/arch/arm/mach-tegra/include/mach/iomap.h
+++ b/arch/arm/mach-tegra/include/mach/iomap.h
@@ -23,9 +23,15 @@
#include <asm/sizes.h>
+#define TEGRA_IRAM_BASE 0x40000000
+#define TEGRA_IRAM_SIZE SZ_256K
+
#define TEGRA_ARM_PERIF_BASE 0x50040000
#define TEGRA_ARM_PERIF_SIZE SZ_8K
+#define TEGRA_ARM_PL310_BASE 0x50043000
+#define TEGRA_ARM_PL310_SIZE SZ_4K
+
#define TEGRA_ARM_INT_DIST_BASE 0x50041000
#define TEGRA_ARM_INT_DIST_SIZE SZ_4K
@@ -68,7 +74,22 @@
#define TEGRA_FLOW_CTRL_BASE 0x60007000
#define TEGRA_FLOW_CTRL_SIZE 20
-#define TEGRA_STATMON_BASE 0x6000C4000
+#define TEGRA_AHB_DMA_BASE 0x60008000
+#define TEGRA_AHB_DMA_SIZE SZ_4K
+
+#define TEGRA_AHB_DMA_CH0_BASE 0x60009000
+#define TEGRA_AHB_DMA_CH0_SIZE 32
+
+#define TEGRA_APB_DMA_BASE 0x6000A000
+#define TEGRA_APB_DMA_SIZE SZ_4K
+
+#define TEGRA_APB_DMA_CH0_BASE 0x6000B000
+#define TEGRA_APB_DMA_CH0_SIZE 32
+
+#define TEGRA_AHB_GIZMO_BASE 0x6000C004
+#define TEGRA_AHB_GIZMO_SIZE 0x10C
+
+#define TEGRA_STATMON_BASE 0x6000C400
#define TEGRA_STATMON_SIZE SZ_1K
#define TEGRA_GPIO_BASE 0x6000D000
@@ -137,7 +158,7 @@
#define TEGRA_I2C3_BASE 0x7000C500
#define TEGRA_I2C3_SIZE SZ_256
-#define TEGRA_OWR_BASE 0x7000D000
+#define TEGRA_OWR_BASE 0x7000C600
#define TEGRA_OWR_SIZE 80
#define TEGRA_DVC_BASE 0x7000D000
@@ -182,12 +203,12 @@
#define TEGRA_USB_BASE 0xC5000000
#define TEGRA_USB_SIZE SZ_16K
-#define TEGRA_USB1_BASE 0xC5004000
-#define TEGRA_USB1_SIZE SZ_16K
-
-#define TEGRA_USB2_BASE 0xC5008000
+#define TEGRA_USB2_BASE 0xC5004000
#define TEGRA_USB2_SIZE SZ_16K
+#define TEGRA_USB3_BASE 0xC5008000
+#define TEGRA_USB3_SIZE SZ_16K
+
#define TEGRA_SDMMC1_BASE 0xC8000000
#define TEGRA_SDMMC1_SIZE SZ_512
diff --git a/arch/arm/mach-tegra/include/mach/irqs.h b/arch/arm/mach-tegra/include/mach/irqs.h
index 20f640edaa0d..71bbf3422953 100644
--- a/arch/arm/mach-tegra/include/mach/irqs.h
+++ b/arch/arm/mach-tegra/include/mach/irqs.h
@@ -25,6 +25,7 @@
#define IRQ_LOCALTIMER 29
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
/* Primary Interrupt Controller */
#define INT_PRI_BASE (INT_GIC_BASE + 32)
#define INT_TMR1 (INT_PRI_BASE + 0)
@@ -169,5 +170,6 @@
#define INT_GPIO_NR (28 * 8)
#define NR_IRQS (INT_GPIO_BASE + INT_GPIO_NR)
+#endif
#endif
diff --git a/arch/arm/mach-tegra/include/mach/legacy_irq.h b/arch/arm/mach-tegra/include/mach/legacy_irq.h
new file mode 100644
index 000000000000..db1eb3dd04c8
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/legacy_irq.h
@@ -0,0 +1,31 @@
+/*
+ * arch/arm/mach-tegra/include/mach/legacy_irq.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Colin Cross <ccross@android.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.
+ *
+ */
+
+#ifndef _ARCH_ARM_MACH_TEGRA_LEGARY_IRQ_H
+#define _ARCH_ARM_MACH_TEGRA_LEGARY_IRQ_H
+
+void tegra_legacy_mask_irq(unsigned int irq);
+void tegra_legacy_unmask_irq(unsigned int irq);
+void tegra_legacy_select_fiq(unsigned int irq, bool fiq);
+void tegra_legacy_force_irq_set(unsigned int irq);
+void tegra_legacy_force_irq_clr(unsigned int irq);
+int tegra_legacy_force_irq_status(unsigned int irq);
+void tegra_legacy_select_fiq(unsigned int irq, bool fiq);
+unsigned long tegra_legacy_vfiq(int nr);
+unsigned long tegra_legacy_class(int nr);
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/pinmux-t2.h b/arch/arm/mach-tegra/include/mach/pinmux-t2.h
new file mode 100644
index 000000000000..e5b9d740f973
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/pinmux-t2.h
@@ -0,0 +1,174 @@
+/*
+ * linux/arch/arm/mach-tegra/include/mach/pinmux-t2.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MACH_TEGRA_PINMUX_T2_H
+#define __MACH_TEGRA_PINMUX_T2_H
+
+enum tegra_pingroup {
+ TEGRA_PINGROUP_ATA = 0,
+ TEGRA_PINGROUP_ATB,
+ TEGRA_PINGROUP_ATC,
+ TEGRA_PINGROUP_ATD,
+ TEGRA_PINGROUP_ATE,
+ TEGRA_PINGROUP_CDEV1,
+ TEGRA_PINGROUP_CDEV2,
+ TEGRA_PINGROUP_CRTP,
+ TEGRA_PINGROUP_CSUS,
+ TEGRA_PINGROUP_DAP1,
+ TEGRA_PINGROUP_DAP2,
+ TEGRA_PINGROUP_DAP3,
+ TEGRA_PINGROUP_DAP4,
+ TEGRA_PINGROUP_DDC,
+ TEGRA_PINGROUP_DTA,
+ TEGRA_PINGROUP_DTB,
+ TEGRA_PINGROUP_DTC,
+ TEGRA_PINGROUP_DTD,
+ TEGRA_PINGROUP_DTE,
+ TEGRA_PINGROUP_DTF,
+ TEGRA_PINGROUP_GMA,
+ TEGRA_PINGROUP_GMB,
+ TEGRA_PINGROUP_GMC,
+ TEGRA_PINGROUP_GMD,
+ TEGRA_PINGROUP_GME,
+ TEGRA_PINGROUP_GPU,
+ TEGRA_PINGROUP_GPU7,
+ TEGRA_PINGROUP_GPV,
+ TEGRA_PINGROUP_HDINT,
+ TEGRA_PINGROUP_I2CP,
+ TEGRA_PINGROUP_IRRX,
+ TEGRA_PINGROUP_IRTX,
+ TEGRA_PINGROUP_KBCA,
+ TEGRA_PINGROUP_KBCB,
+ TEGRA_PINGROUP_KBCC,
+ TEGRA_PINGROUP_KBCD,
+ TEGRA_PINGROUP_KBCE,
+ TEGRA_PINGROUP_KBCF,
+ TEGRA_PINGROUP_LCSN,
+ TEGRA_PINGROUP_LD0,
+ TEGRA_PINGROUP_LD1,
+ TEGRA_PINGROUP_LD10,
+ TEGRA_PINGROUP_LD11,
+ TEGRA_PINGROUP_LD12,
+ TEGRA_PINGROUP_LD13,
+ TEGRA_PINGROUP_LD14,
+ TEGRA_PINGROUP_LD15,
+ TEGRA_PINGROUP_LD16,
+ TEGRA_PINGROUP_LD17,
+ TEGRA_PINGROUP_LD2,
+ TEGRA_PINGROUP_LD3,
+ TEGRA_PINGROUP_LD4,
+ TEGRA_PINGROUP_LD5,
+ TEGRA_PINGROUP_LD6,
+ TEGRA_PINGROUP_LD7,
+ TEGRA_PINGROUP_LD8,
+ TEGRA_PINGROUP_LD9,
+ TEGRA_PINGROUP_LDC,
+ TEGRA_PINGROUP_LDI,
+ TEGRA_PINGROUP_LHP0,
+ TEGRA_PINGROUP_LHP1,
+ TEGRA_PINGROUP_LHP2,
+ TEGRA_PINGROUP_LHS,
+ TEGRA_PINGROUP_LM0,
+ TEGRA_PINGROUP_LM1,
+ TEGRA_PINGROUP_LPP,
+ TEGRA_PINGROUP_LPW0,
+ TEGRA_PINGROUP_LPW1,
+ TEGRA_PINGROUP_LPW2,
+ TEGRA_PINGROUP_LSC0,
+ TEGRA_PINGROUP_LSC1,
+ TEGRA_PINGROUP_LSCK,
+ TEGRA_PINGROUP_LSDA,
+ TEGRA_PINGROUP_LSDI,
+ TEGRA_PINGROUP_LSPI,
+ TEGRA_PINGROUP_LVP0,
+ TEGRA_PINGROUP_LVP1,
+ TEGRA_PINGROUP_LVS,
+ TEGRA_PINGROUP_OWC,
+ TEGRA_PINGROUP_PMC,
+ TEGRA_PINGROUP_PTA,
+ TEGRA_PINGROUP_RM,
+ TEGRA_PINGROUP_SDB,
+ TEGRA_PINGROUP_SDC,
+ TEGRA_PINGROUP_SDD,
+ TEGRA_PINGROUP_SDIO1,
+ TEGRA_PINGROUP_SLXA,
+ TEGRA_PINGROUP_SLXC,
+ TEGRA_PINGROUP_SLXD,
+ TEGRA_PINGROUP_SLXK,
+ TEGRA_PINGROUP_SPDI,
+ TEGRA_PINGROUP_SPDO,
+ TEGRA_PINGROUP_SPIA,
+ TEGRA_PINGROUP_SPIB,
+ TEGRA_PINGROUP_SPIC,
+ TEGRA_PINGROUP_SPID,
+ TEGRA_PINGROUP_SPIE,
+ TEGRA_PINGROUP_SPIF,
+ TEGRA_PINGROUP_SPIG,
+ TEGRA_PINGROUP_SPIH,
+ TEGRA_PINGROUP_UAA,
+ TEGRA_PINGROUP_UAB,
+ TEGRA_PINGROUP_UAC,
+ TEGRA_PINGROUP_UAD,
+ TEGRA_PINGROUP_UCA,
+ TEGRA_PINGROUP_UCB,
+ TEGRA_PINGROUP_UDA,
+ /* these pin groups only have pullup and pull down control */
+ TEGRA_PINGROUP_CK32,
+ TEGRA_PINGROUP_DDRC,
+ TEGRA_PINGROUP_PMCA,
+ TEGRA_PINGROUP_PMCB,
+ TEGRA_PINGROUP_PMCC,
+ TEGRA_PINGROUP_PMCD,
+ TEGRA_PINGROUP_PMCE,
+ TEGRA_PINGROUP_XM2C,
+ TEGRA_PINGROUP_XM2D,
+ TEGRA_MAX_PINGROUP,
+};
+
+enum tegra_drive_pingroup {
+ TEGRA_DRIVE_PINGROUP_AO1 = 0,
+ TEGRA_DRIVE_PINGROUP_AO2,
+ TEGRA_DRIVE_PINGROUP_AT1,
+ TEGRA_DRIVE_PINGROUP_AT2,
+ TEGRA_DRIVE_PINGROUP_CDEV1,
+ TEGRA_DRIVE_PINGROUP_CDEV2,
+ TEGRA_DRIVE_PINGROUP_CSUS,
+ TEGRA_DRIVE_PINGROUP_DAP1,
+ TEGRA_DRIVE_PINGROUP_DAP2,
+ TEGRA_DRIVE_PINGROUP_DAP3,
+ TEGRA_DRIVE_PINGROUP_DAP4,
+ TEGRA_DRIVE_PINGROUP_DBG,
+ TEGRA_DRIVE_PINGROUP_LCD1,
+ TEGRA_DRIVE_PINGROUP_LCD2,
+ TEGRA_DRIVE_PINGROUP_SDMMC2,
+ TEGRA_DRIVE_PINGROUP_SDMMC3,
+ TEGRA_DRIVE_PINGROUP_SPI,
+ TEGRA_DRIVE_PINGROUP_UAA,
+ TEGRA_DRIVE_PINGROUP_UAB,
+ TEGRA_DRIVE_PINGROUP_UART2,
+ TEGRA_DRIVE_PINGROUP_UART3,
+ TEGRA_DRIVE_PINGROUP_VI1,
+ TEGRA_DRIVE_PINGROUP_VI2,
+ TEGRA_DRIVE_PINGROUP_XM2A,
+ TEGRA_DRIVE_PINGROUP_XM2C,
+ TEGRA_DRIVE_PINGROUP_XM2D,
+ TEGRA_DRIVE_PINGROUP_XM2CLK,
+ TEGRA_DRIVE_PINGROUP_MEMCOMP,
+ TEGRA_MAX_DRIVE_PINGROUP,
+};
+
+#endif
+
diff --git a/arch/arm/mach-tegra/include/mach/pinmux.h b/arch/arm/mach-tegra/include/mach/pinmux.h
index 41c8ce5b7c27..defd8775defa 100644
--- a/arch/arm/mach-tegra/include/mach/pinmux.h
+++ b/arch/arm/mach-tegra/include/mach/pinmux.h
@@ -17,126 +17,11 @@
#ifndef __MACH_TEGRA_PINMUX_H
#define __MACH_TEGRA_PINMUX_H
-enum tegra_pingroup {
- TEGRA_PINGROUP_ATA = 0,
- TEGRA_PINGROUP_ATB,
- TEGRA_PINGROUP_ATC,
- TEGRA_PINGROUP_ATD,
- TEGRA_PINGROUP_ATE,
- TEGRA_PINGROUP_CDEV1,
- TEGRA_PINGROUP_CDEV2,
- TEGRA_PINGROUP_CRTP,
- TEGRA_PINGROUP_CSUS,
- TEGRA_PINGROUP_DAP1,
- TEGRA_PINGROUP_DAP2,
- TEGRA_PINGROUP_DAP3,
- TEGRA_PINGROUP_DAP4,
- TEGRA_PINGROUP_DDC,
- TEGRA_PINGROUP_DTA,
- TEGRA_PINGROUP_DTB,
- TEGRA_PINGROUP_DTC,
- TEGRA_PINGROUP_DTD,
- TEGRA_PINGROUP_DTE,
- TEGRA_PINGROUP_DTF,
- TEGRA_PINGROUP_GMA,
- TEGRA_PINGROUP_GMB,
- TEGRA_PINGROUP_GMC,
- TEGRA_PINGROUP_GMD,
- TEGRA_PINGROUP_GME,
- TEGRA_PINGROUP_GPU,
- TEGRA_PINGROUP_GPU7,
- TEGRA_PINGROUP_GPV,
- TEGRA_PINGROUP_HDINT,
- TEGRA_PINGROUP_I2CP,
- TEGRA_PINGROUP_IRRX,
- TEGRA_PINGROUP_IRTX,
- TEGRA_PINGROUP_KBCA,
- TEGRA_PINGROUP_KBCB,
- TEGRA_PINGROUP_KBCC,
- TEGRA_PINGROUP_KBCD,
- TEGRA_PINGROUP_KBCE,
- TEGRA_PINGROUP_KBCF,
- TEGRA_PINGROUP_LCSN,
- TEGRA_PINGROUP_LD0,
- TEGRA_PINGROUP_LD1,
- TEGRA_PINGROUP_LD10,
- TEGRA_PINGROUP_LD11,
- TEGRA_PINGROUP_LD12,
- TEGRA_PINGROUP_LD13,
- TEGRA_PINGROUP_LD14,
- TEGRA_PINGROUP_LD15,
- TEGRA_PINGROUP_LD16,
- TEGRA_PINGROUP_LD17,
- TEGRA_PINGROUP_LD2,
- TEGRA_PINGROUP_LD3,
- TEGRA_PINGROUP_LD4,
- TEGRA_PINGROUP_LD5,
- TEGRA_PINGROUP_LD6,
- TEGRA_PINGROUP_LD7,
- TEGRA_PINGROUP_LD8,
- TEGRA_PINGROUP_LD9,
- TEGRA_PINGROUP_LDC,
- TEGRA_PINGROUP_LDI,
- TEGRA_PINGROUP_LHP0,
- TEGRA_PINGROUP_LHP1,
- TEGRA_PINGROUP_LHP2,
- TEGRA_PINGROUP_LHS,
- TEGRA_PINGROUP_LM0,
- TEGRA_PINGROUP_LM1,
- TEGRA_PINGROUP_LPP,
- TEGRA_PINGROUP_LPW0,
- TEGRA_PINGROUP_LPW1,
- TEGRA_PINGROUP_LPW2,
- TEGRA_PINGROUP_LSC0,
- TEGRA_PINGROUP_LSC1,
- TEGRA_PINGROUP_LSCK,
- TEGRA_PINGROUP_LSDA,
- TEGRA_PINGROUP_LSDI,
- TEGRA_PINGROUP_LSPI,
- TEGRA_PINGROUP_LVP0,
- TEGRA_PINGROUP_LVP1,
- TEGRA_PINGROUP_LVS,
- TEGRA_PINGROUP_OWC,
- TEGRA_PINGROUP_PMC,
- TEGRA_PINGROUP_PTA,
- TEGRA_PINGROUP_RM,
- TEGRA_PINGROUP_SDB,
- TEGRA_PINGROUP_SDC,
- TEGRA_PINGROUP_SDD,
- TEGRA_PINGROUP_SDIO1,
- TEGRA_PINGROUP_SLXA,
- TEGRA_PINGROUP_SLXC,
- TEGRA_PINGROUP_SLXD,
- TEGRA_PINGROUP_SLXK,
- TEGRA_PINGROUP_SPDI,
- TEGRA_PINGROUP_SPDO,
- TEGRA_PINGROUP_SPIA,
- TEGRA_PINGROUP_SPIB,
- TEGRA_PINGROUP_SPIC,
- TEGRA_PINGROUP_SPID,
- TEGRA_PINGROUP_SPIE,
- TEGRA_PINGROUP_SPIF,
- TEGRA_PINGROUP_SPIG,
- TEGRA_PINGROUP_SPIH,
- TEGRA_PINGROUP_UAA,
- TEGRA_PINGROUP_UAB,
- TEGRA_PINGROUP_UAC,
- TEGRA_PINGROUP_UAD,
- TEGRA_PINGROUP_UCA,
- TEGRA_PINGROUP_UCB,
- TEGRA_PINGROUP_UDA,
- /* these pin groups only have pullup and pull down control */
- TEGRA_PINGROUP_CK32,
- TEGRA_PINGROUP_DDRC,
- TEGRA_PINGROUP_PMCA,
- TEGRA_PINGROUP_PMCB,
- TEGRA_PINGROUP_PMCC,
- TEGRA_PINGROUP_PMCD,
- TEGRA_PINGROUP_PMCE,
- TEGRA_PINGROUP_XM2C,
- TEGRA_PINGROUP_XM2D,
- TEGRA_MAX_PINGROUP,
-};
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+#include "pinmux-t2.h"
+#else
+#error "Undefined Tegra architecture"
+#endif
enum tegra_mux_func {
TEGRA_MUX_RSVD = 0x8000,
@@ -205,6 +90,7 @@ enum tegra_mux_func {
TEGRA_MUX_VI,
TEGRA_MUX_VI_SENSOR_CLK,
TEGRA_MUX_XIO,
+ TEGRA_MUX_SAFE,
TEGRA_MAX_MUX,
};
@@ -219,6 +105,18 @@ enum tegra_tristate {
TEGRA_TRI_TRISTATE = 1,
};
+enum tegra_vddio {
+ TEGRA_VDDIO_BB = 0,
+ TEGRA_VDDIO_LCD,
+ TEGRA_VDDIO_VI,
+ TEGRA_VDDIO_UART,
+ TEGRA_VDDIO_DDR,
+ TEGRA_VDDIO_NAND,
+ TEGRA_VDDIO_SYS,
+ TEGRA_VDDIO_AUDIO,
+ TEGRA_VDDIO_SD,
+};
+
struct tegra_pingroup_config {
enum tegra_pingroup pingroup;
enum tegra_mux_func func;
@@ -270,38 +168,6 @@ enum tegra_pull_strength {
TEGRA_MAX_PULL,
};
-enum tegra_drive_pingroup {
- TEGRA_DRIVE_PINGROUP_AO1 = 0,
- TEGRA_DRIVE_PINGROUP_AO2,
- TEGRA_DRIVE_PINGROUP_AT1,
- TEGRA_DRIVE_PINGROUP_AT2,
- TEGRA_DRIVE_PINGROUP_CDEV1,
- TEGRA_DRIVE_PINGROUP_CDEV2,
- TEGRA_DRIVE_PINGROUP_CSUS,
- TEGRA_DRIVE_PINGROUP_DAP1,
- TEGRA_DRIVE_PINGROUP_DAP2,
- TEGRA_DRIVE_PINGROUP_DAP3,
- TEGRA_DRIVE_PINGROUP_DAP4,
- TEGRA_DRIVE_PINGROUP_DBG,
- TEGRA_DRIVE_PINGROUP_LCD1,
- TEGRA_DRIVE_PINGROUP_LCD2,
- TEGRA_DRIVE_PINGROUP_SDMMC2,
- TEGRA_DRIVE_PINGROUP_SDMMC3,
- TEGRA_DRIVE_PINGROUP_SPI,
- TEGRA_DRIVE_PINGROUP_UAA,
- TEGRA_DRIVE_PINGROUP_UAB,
- TEGRA_DRIVE_PINGROUP_UART2,
- TEGRA_DRIVE_PINGROUP_UART3,
- TEGRA_DRIVE_PINGROUP_VI1,
- TEGRA_DRIVE_PINGROUP_VI2,
- TEGRA_DRIVE_PINGROUP_XM2A,
- TEGRA_DRIVE_PINGROUP_XM2C,
- TEGRA_DRIVE_PINGROUP_XM2D,
- TEGRA_DRIVE_PINGROUP_XM2CLK,
- TEGRA_DRIVE_PINGROUP_MEMCOMP,
- TEGRA_MAX_DRIVE_PINGROUP,
-};
-
enum tegra_drive {
TEGRA_DRIVE_DIV_8 = 0,
TEGRA_DRIVE_DIV_4,
@@ -331,18 +197,44 @@ struct tegra_drive_pingroup_config {
enum tegra_slew slew_falling;
};
-int tegra_pinmux_set_func(enum tegra_pingroup pg, enum tegra_mux_func func);
-int tegra_pinmux_set_tristate(enum tegra_pingroup pg, enum tegra_tristate tristate);
-int tegra_pinmux_set_pullupdown(enum tegra_pingroup pg, enum tegra_pullupdown pupd);
+struct tegra_drive_pingroup_desc {
+ const char *name;
+ s16 reg;
+};
+
+struct tegra_pingroup_desc {
+ const char *name;
+ int funcs[4];
+ int func_safe;
+ int vddio;
+ s16 tri_reg; /* offset into the TRISTATE_REG_* register bank */
+ s16 mux_reg; /* offset into the PIN_MUX_CTL_* register bank */
+ s16 pupd_reg; /* offset into the PULL_UPDOWN_REG_* register bank */
+ s8 tri_bit; /* offset into the TRISTATE_REG_* register bit */
+ s8 mux_bit; /* offset into the PIN_MUX_CTL_* register bit */
+ s8 pupd_bit; /* offset into the PULL_UPDOWN_REG_* register bit */
+};
+
+extern const struct tegra_pingroup_desc tegra_soc_pingroups[];
+extern const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[];
-void tegra_pinmux_config_pingroup(enum tegra_pingroup pingroup,
- enum tegra_mux_func func, enum tegra_pullupdown pupd,
+int tegra_pinmux_set_tristate(enum tegra_pingroup pg,
enum tegra_tristate tristate);
+int tegra_pinmux_set_pullupdown(enum tegra_pingroup pg,
+ enum tegra_pullupdown pupd);
-void tegra_pinmux_config_table(struct tegra_pingroup_config *config, int len);
+void tegra_pinmux_config_table(const struct tegra_pingroup_config *config,
+ int len);
void tegra_drive_pinmux_config_table(struct tegra_drive_pingroup_config *config,
int len);
-
+void tegra_pinmux_set_safe_pinmux_table(const struct tegra_pingroup_config *config,
+ int len);
+void tegra_pinmux_config_pinmux_table(const struct tegra_pingroup_config *config,
+ int len);
+void tegra_pinmux_config_tristate_table(const struct tegra_pingroup_config *config,
+ int len, enum tegra_tristate tristate);
+void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *config,
+ int len, enum tegra_pullupdown pupd);
#endif
diff --git a/arch/arm/mach-tegra/io.c b/arch/arm/mach-tegra/io.c
index 9fe2c5c683d4..31848a9592f8 100644
--- a/arch/arm/mach-tegra/io.c
+++ b/arch/arm/mach-tegra/io.c
@@ -49,6 +49,12 @@ static struct map_desc tegra_io_desc[] __initdata = {
.length = IO_CPU_SIZE,
.type = MT_DEVICE,
},
+ {
+ .virtual = IO_IRAM_VIRT,
+ .pfn = __phys_to_pfn(IO_IRAM_PHYS),
+ .length = IO_IRAM_SIZE,
+ .type = MT_DEVICE,
+ },
};
void __init tegra_map_common_io(void)
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
index 1fdbe708d43d..50a8dfb9a0cf 100644
--- a/arch/arm/mach-tegra/irq.c
+++ b/arch/arm/mach-tegra/irq.c
@@ -4,6 +4,8 @@
* Author:
* Colin Cross <ccross@google.com>
*
+ * Copyright (C) 2010, NVIDIA Corporation
+ *
* 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.
@@ -27,8 +29,143 @@
#include "board.h"
+#define INT_SYS_NR (INT_GPIO_BASE - INT_PRI_BASE)
+#define INT_SYS_SZ (INT_SEC_BASE - INT_PRI_BASE)
+#define PPI_NR ((INT_SYS_NR+INT_SYS_SZ-1)/INT_SYS_SZ)
+
+#define APBDMA_IRQ_STA_CPU 0x14
+#define APBDMA_IRQ_MASK_SET 0x20
+#define APBDMA_IRQ_MASK_CLR 0x24
+
+#define ICTLR_CPU_IER 0x20
+#define ICTLR_CPU_IER_SET 0x24
+#define ICTLR_CPU_IER_CLR 0x28
+#define ICTLR_CPU_IEP_CLASS 0x2c
+#define ICTLR_COP_IER 0x30
+#define ICTLR_COP_IER_SET 0x34
+#define ICTLR_COP_IER_CLR 0x38
+#define ICTLR_COP_IEP_CLASS 0x3c
+
+static void (*gic_mask_irq)(unsigned int irq);
+static void (*gic_unmask_irq)(unsigned int irq);
+
+#define irq_to_ictlr(irq) (((irq)-32) >> 5)
+static void __iomem *tegra_ictlr_base = IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE);
+#define ictlr_to_virt(ictlr) (tegra_ictlr_base + (ictlr)*0x100)
+
+static void tegra_mask(unsigned int irq)
+{
+ void __iomem *addr = ictlr_to_virt(irq_to_ictlr(irq));
+ gic_mask_irq(irq);
+ writel(1<<(irq&31), addr+ICTLR_CPU_IER_CLR);
+}
+
+static void tegra_unmask(unsigned int irq)
+{
+ void __iomem *addr = ictlr_to_virt(irq_to_ictlr(irq));
+ gic_unmask_irq(irq);
+ writel(1<<(irq&31), addr+ICTLR_CPU_IER_SET);
+}
+
+#ifdef CONFIG_PM
+
+static int tegra_set_wake(unsigned int irq, unsigned int on)
+{
+ return 0;
+}
+#endif
+
+static struct irq_chip tegra_irq = {
+ .name = "PPI",
+ .mask = tegra_mask,
+ .unmask = tegra_unmask,
+#ifdef CONFIG_PM
+ .set_wake = tegra_set_wake,
+#endif
+};
+
void __init tegra_init_irq(void)
{
+ struct irq_chip *gic;
+ unsigned int i;
+
+ for (i = 0; i < PPI_NR; i++) {
+ writel(~0, ictlr_to_virt(i) + ICTLR_CPU_IER_CLR);
+ writel(0, ictlr_to_virt(i) + ICTLR_CPU_IEP_CLASS);
+ }
+
gic_dist_init(0, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE), 29);
gic_cpu_init(0, IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
+
+ gic = get_irq_chip(29);
+ gic_unmask_irq = gic->unmask;
+ gic_mask_irq = gic->mask;
+ tegra_irq.ack = gic->ack;
+#ifdef CONFIG_SMP
+ tegra_irq.set_affinity = gic->set_affinity;
+#endif
+
+ for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
+ set_irq_chip(i, &tegra_irq);
+ set_irq_handler(i, handle_level_irq);
+ set_irq_flags(i, IRQF_VALID);
+ }
+}
+
+#ifdef CONFIG_PM
+static u32 cop_ier[PPI_NR];
+static u32 cpu_ier[PPI_NR];
+static u32 cpu_iep[PPI_NR];
+
+void tegra_irq_suspend(void)
+{
+ unsigned long flags;
+ int i;
+
+ for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
+ struct irq_desc *desc = irq_to_desc(i);
+ if (!desc)
+ continue;
+ if (desc->status & IRQ_WAKEUP) {
+ pr_debug("irq %d is wakeup\n", i);
+ continue;
+ }
+ disable_irq(i);
+ }
+
+ local_irq_save(flags);
+ for (i = 0; i < PPI_NR; i++) {
+ void __iomem *ictlr = ictlr_to_virt(i);
+ cpu_ier[i] = readl(ictlr + ICTLR_CPU_IER);
+ cpu_iep[i] = readl(ictlr + ICTLR_CPU_IEP_CLASS);
+ cop_ier[i] = readl(ictlr + ICTLR_COP_IER);
+ writel(~0, ictlr + ICTLR_COP_IER_CLR);
+ }
+ local_irq_restore(flags);
+}
+
+void tegra_irq_resume(void)
+{
+ unsigned long flags;
+ int i;
+
+ local_irq_save(flags);
+ for (i = 0; i < PPI_NR; i++) {
+ void __iomem *ictlr = ictlr_to_virt(i);
+ writel(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS);
+ writel(~0ul, ictlr + ICTLR_CPU_IER_CLR);
+ writel(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET);
+ writel(0, ictlr + ICTLR_COP_IEP_CLASS);
+ writel(~0ul, ictlr + ICTLR_COP_IER_CLR);
+ writel(cop_ier[i], ictlr + ICTLR_COP_IER_SET);
+ }
+ local_irq_restore(flags);
+
+ for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
+ struct irq_desc *desc = irq_to_desc(i);
+ if (!desc || (desc->status & IRQ_WAKEUP))
+ continue;
+ enable_irq(i);
+ }
}
+#endif
diff --git a/arch/arm/mach-tegra/legacy_irq.c b/arch/arm/mach-tegra/legacy_irq.c
new file mode 100644
index 000000000000..7cc8601c19ff
--- /dev/null
+++ b/arch/arm/mach-tegra/legacy_irq.c
@@ -0,0 +1,114 @@
+/*
+ * arch/arm/mach-tegra/legacy_irq.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Colin Cross <ccross@android.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/io.h>
+#include <linux/kernel.h>
+#include <mach/iomap.h>
+#include <mach/legacy_irq.h>
+
+#define ICTLR_CPU_IER 0x20
+#define ICTLR_CPU_IER_SET 0x24
+#define ICTLR_CPU_IER_CLR 0x28
+#define ICTLR_CPU_IEP_CLASS 0x2C
+#define ICTLR_CPU_IEP_VFIQ 0x08
+#define ICTLR_CPU_IEP_FIR 0x14
+#define ICTLR_CPU_IEP_FIR_SET 0x18
+#define ICTLR_CPU_IEP_FIR_CLR 0x1c
+
+static void __iomem *ictlr_reg_base[] = {
+ IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE),
+ IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE),
+ IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE),
+ IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE),
+};
+
+/* When going into deep sleep, the CPU is powered down, taking the GIC with it
+ In order to wake, the wake interrupts need to be enabled in the legacy
+ interrupt controller. */
+void tegra_legacy_unmask_irq(unsigned int irq)
+{
+ void __iomem *base;
+ pr_debug("%s: %d\n", __func__, irq);
+
+ irq -= 32;
+ base = ictlr_reg_base[irq>>5];
+ writel(1 << (irq & 31), base + ICTLR_CPU_IER_SET);
+}
+
+void tegra_legacy_mask_irq(unsigned int irq)
+{
+ void __iomem *base;
+ pr_debug("%s: %d\n", __func__, irq);
+
+ irq -= 32;
+ base = ictlr_reg_base[irq>>5];
+ writel(1 << (irq & 31), base + ICTLR_CPU_IER_CLR);
+}
+
+void tegra_legacy_force_irq_set(unsigned int irq)
+{
+ void __iomem *base;
+ pr_debug("%s: %d\n", __func__, irq);
+
+ irq -= 32;
+ base = ictlr_reg_base[irq>>5];
+ writel(1 << (irq & 31), base + ICTLR_CPU_IEP_FIR_SET);
+}
+
+void tegra_legacy_force_irq_clr(unsigned int irq)
+{
+ void __iomem *base;
+ pr_debug("%s: %d\n", __func__, irq);
+
+ irq -= 32;
+ base = ictlr_reg_base[irq>>5];
+ writel(1 << (irq & 31), base + ICTLR_CPU_IEP_FIR_CLR);
+}
+
+int tegra_legacy_force_irq_status(unsigned int irq)
+{
+ void __iomem *base;
+ pr_debug("%s: %d\n", __func__, irq);
+
+ irq -= 32;
+ base = ictlr_reg_base[irq>>5];
+ return !!(readl(base + ICTLR_CPU_IEP_FIR) & (1 << (irq & 31)));
+}
+
+void tegra_legacy_select_fiq(unsigned int irq, bool fiq)
+{
+ void __iomem *base;
+ pr_debug("%s: %d\n", __func__, irq);
+
+ irq -= 32;
+ base = ictlr_reg_base[irq>>5];
+ writel(fiq << (irq & 31), base + ICTLR_CPU_IEP_CLASS);
+}
+
+unsigned long tegra_legacy_vfiq(int nr)
+{
+ void __iomem *base;
+ base = ictlr_reg_base[nr];
+ return readl(base + ICTLR_CPU_IEP_VFIQ);
+}
+
+unsigned long tegra_legacy_class(int nr)
+{
+ void __iomem *base;
+ base = ictlr_reg_base[nr];
+ return readl(base + ICTLR_CPU_IEP_CLASS);
+}
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
new file mode 100644
index 000000000000..53f5fa37014a
--- /dev/null
+++ b/arch/arm/mach-tegra/pcie.c
@@ -0,0 +1,915 @@
+/*
+ * arch/arm/mach-tegra/pci.c
+ *
+ * PCIe host controller driver for TEGRA(2) SOCs
+ *
+ * Copyright (c) 2010, CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on NVIDIA PCIe driver
+ * Copyright (c) 2008-2009, NVIDIA Corporation.
+ *
+ * Bits taken from arch/arm/mach-dove/pcie.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.
+ *
+ * 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/kernel.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#include <asm/sizes.h>
+#include <asm/mach/pci.h>
+
+#include <mach/pinmux.h>
+#include <mach/iomap.h>
+#include <mach/clk.h>
+
+/* register definitions */
+#define AFI_OFFSET 0x3800
+#define PADS_OFFSET 0x3000
+#define RP0_OFFSET 0x0000
+#define RP1_OFFSET 0x1000
+
+#define AFI_AXI_BAR0_SZ 0x00
+#define AFI_AXI_BAR1_SZ 0x04
+#define AFI_AXI_BAR2_SZ 0x08
+#define AFI_AXI_BAR3_SZ 0x0c
+#define AFI_AXI_BAR4_SZ 0x10
+#define AFI_AXI_BAR5_SZ 0x14
+
+#define AFI_AXI_BAR0_START 0x18
+#define AFI_AXI_BAR1_START 0x1c
+#define AFI_AXI_BAR2_START 0x20
+#define AFI_AXI_BAR3_START 0x24
+#define AFI_AXI_BAR4_START 0x28
+#define AFI_AXI_BAR5_START 0x2c
+
+#define AFI_FPCI_BAR0 0x30
+#define AFI_FPCI_BAR1 0x34
+#define AFI_FPCI_BAR2 0x38
+#define AFI_FPCI_BAR3 0x3c
+#define AFI_FPCI_BAR4 0x40
+#define AFI_FPCI_BAR5 0x44
+
+#define AFI_CACHE_BAR0_SZ 0x48
+#define AFI_CACHE_BAR0_ST 0x4c
+#define AFI_CACHE_BAR1_SZ 0x50
+#define AFI_CACHE_BAR1_ST 0x54
+
+#define AFI_MSI_BAR_SZ 0x60
+#define AFI_MSI_FPCI_BAR_ST 0x64
+#define AFI_MSI_AXI_BAR_ST 0x68
+
+#define AFI_CONFIGURATION 0xac
+#define AFI_CONFIGURATION_EN_FPCI (1 << 0)
+
+#define AFI_FPCI_ERROR_MASKS 0xb0
+
+#define AFI_INTR_MASK 0xb4
+#define AFI_INTR_MASK_INT_MASK (1 << 0)
+#define AFI_INTR_MASK_MSI_MASK (1 << 8)
+
+#define AFI_INTR_CODE 0xb8
+#define AFI_INTR_CODE_MASK 0xf
+#define AFI_INTR_MASTER_ABORT 4
+#define AFI_INTR_LEGACY 6
+
+#define AFI_INTR_SIGNATURE 0xbc
+#define AFI_SM_INTR_ENABLE 0xc4
+
+#define AFI_AFI_INTR_ENABLE 0xc8
+#define AFI_INTR_EN_INI_SLVERR (1 << 0)
+#define AFI_INTR_EN_INI_DECERR (1 << 1)
+#define AFI_INTR_EN_TGT_SLVERR (1 << 2)
+#define AFI_INTR_EN_TGT_DECERR (1 << 3)
+#define AFI_INTR_EN_TGT_WRERR (1 << 4)
+#define AFI_INTR_EN_DFPCI_DECERR (1 << 5)
+#define AFI_INTR_EN_AXI_DECERR (1 << 6)
+#define AFI_INTR_EN_FPCI_TIMEOUT (1 << 7)
+
+#define AFI_PCIE_CONFIG 0x0f8
+#define AFI_PCIE_CONFIG_PCIEC0_DISABLE_DEVICE (1 << 1)
+#define AFI_PCIE_CONFIG_PCIEC1_DISABLE_DEVICE (1 << 2)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK (0xf << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE (0x0 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL (0x1 << 20)
+
+#define AFI_FUSE 0x104
+#define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2)
+
+#define AFI_PEX0_CTRL 0x110
+#define AFI_PEX1_CTRL 0x118
+#define AFI_PEX_CTRL_RST (1 << 0)
+#define AFI_PEX_CTRL_REFCLK_EN (1 << 3)
+
+#define RP_VEND_XP 0x00000F00
+#define RP_VEND_XP_DL_UP (1 << 30)
+
+#define RP_LINK_CONTROL_STATUS 0x00000090
+#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000
+
+#define PADS_CTL_SEL 0x0000009C
+
+#define PADS_CTL 0x000000A0
+#define PADS_CTL_IDDQ_1L (1 << 0)
+#define PADS_CTL_TX_DATA_EN_1L (1 << 6)
+#define PADS_CTL_RX_DATA_EN_1L (1 << 10)
+
+#define PADS_PLL_CTL 0x000000B8
+#define PADS_PLL_CTL_RST_B4SM (1 << 1)
+#define PADS_PLL_CTL_LOCKDET (1 << 8)
+#define PADS_PLL_CTL_REFCLK_MASK (0x3 << 16)
+#define PADS_PLL_CTL_REFCLK_INTERNAL_CML (0 << 16)
+#define PADS_PLL_CTL_REFCLK_INTERNAL_CMOS (1 << 16)
+#define PADS_PLL_CTL_REFCLK_EXTERNAL (2 << 16)
+#define PADS_PLL_CTL_TXCLKREF_MASK (0x1 << 20)
+#define PADS_PLL_CTL_TXCLKREF_DIV10 (0 << 20)
+#define PADS_PLL_CTL_TXCLKREF_DIV5 (1 << 20)
+
+/* PMC access is required for PCIE xclk (un)clamping */
+#define PMC_SCRATCH42 0x144
+#define PMC_SCRATCH42_PCX_CLAMP (1 << 0)
+
+static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
+#define pmc_writel(value, reg) \
+ __raw_writel(value, (u32)reg_pmc_base + (reg))
+#define pmc_readl(reg) \
+ __raw_readl((u32)reg_pmc_base + (reg))
+
+/*
+ * Tegra2 defines 1GB in the AXI address map for PCIe.
+ *
+ * That address space is split into different regions, with sizes and
+ * offsets as follows:
+ *
+ * 0x80000000 - 0x80003fff - PCI controller registers
+ * 0x80004000 - 0x80103fff - PCI configuration space
+ * 0x80104000 - 0x80203fff - PCI extended configuration space
+ * 0x80203fff - 0x803fffff - unused
+ * 0x80400000 - 0x8040ffff - downstream IO
+ * 0x80410000 - 0x8fffffff - unused
+ * 0x90000000 - 0x9fffffff - non-prefetchable memory
+ * 0xa0000000 - 0xbfffffff - prefetchable memory
+ */
+#define TEGRA_PCIE_BASE 0x80000000
+
+#define PCIE_REGS_SZ SZ_16K
+#define PCIE_CFG_OFF PCIE_REGS_SZ
+#define PCIE_CFG_SZ SZ_1M
+#define PCIE_EXT_CFG_OFF (PCIE_CFG_SZ + PCIE_CFG_OFF)
+#define PCIE_EXT_CFG_SZ SZ_1M
+#define PCIE_IOMAP_SZ (PCIE_REGS_SZ + PCIE_CFG_SZ + PCIE_EXT_CFG_SZ)
+
+#define MMIO_BASE (TEGRA_PCIE_BASE + SZ_4M)
+#define MMIO_SIZE SZ_64K
+#define MEM_BASE_0 (TEGRA_PCIE_BASE + SZ_256M)
+#define MEM_SIZE_0 SZ_128M
+#define MEM_BASE_1 (MEM_BASE_0 + MEM_SIZE_0)
+#define MEM_SIZE_1 SZ_128M
+#define PREFETCH_MEM_BASE_0 (MEM_BASE_1 + MEM_SIZE_1)
+#define PREFETCH_MEM_SIZE_0 SZ_128M
+#define PREFETCH_MEM_BASE_1 (PREFETCH_MEM_BASE_0 + PREFETCH_MEM_SIZE_0)
+#define PREFETCH_MEM_SIZE_1 SZ_128M
+
+#define PCIE_CONF_BUS(b) ((b) << 16)
+#define PCIE_CONF_DEV(d) ((d) << 11)
+#define PCIE_CONF_FUNC(f) ((f) << 8)
+#define PCIE_CONF_REG(r) \
+ (((r) & ~0x3) | (((r) < 256) ? PCIE_CFG_OFF : PCIE_EXT_CFG_OFF))
+
+struct tegra_pcie_port {
+ int index;
+ u8 root_bus_nr;
+ void __iomem *base;
+
+ bool link_up;
+
+ char io_space_name[16];
+ char mem_space_name[16];
+ char prefetch_space_name[20];
+ struct resource res[3];
+};
+
+struct tegra_pcie_info {
+ struct tegra_pcie_port port[2];
+ int num_ports;
+
+ void __iomem *regs;
+ struct resource res_mmio;
+
+ struct clk *pex_clk;
+ struct clk *afi_clk;
+ struct clk *pcie_xclk;
+ struct clk *pll_e;
+};
+
+static struct tegra_pcie_info tegra_pcie = {
+ .res_mmio = {
+ .name = "PCI IO",
+ .start = MMIO_BASE,
+ .end = MMIO_BASE + MMIO_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+void __iomem *tegra_pcie_io_base;
+EXPORT_SYMBOL(tegra_pcie_io_base);
+
+static inline void afi_writel(u32 value, unsigned long offset)
+{
+ writel(value, offset + AFI_OFFSET + tegra_pcie.regs);
+}
+
+static inline u32 afi_readl(unsigned long offset)
+{
+ return readl(offset + AFI_OFFSET + tegra_pcie.regs);
+}
+
+static inline void pads_writel(u32 value, unsigned long offset)
+{
+ writel(value, offset + PADS_OFFSET + tegra_pcie.regs);
+}
+
+static inline u32 pads_readl(unsigned long offset)
+{
+ return readl(offset + PADS_OFFSET + tegra_pcie.regs);
+}
+
+static struct tegra_pcie_port *bus_to_port(int bus)
+{
+ int i;
+
+ for (i = tegra_pcie.num_ports - 1; i >= 0; i--) {
+ int rbus = tegra_pcie.port[i].root_bus_nr;
+ if (rbus != -1 && rbus == bus)
+ break;
+ }
+
+ return i >= 0 ? tegra_pcie.port + i : NULL;
+}
+
+static int tegra_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ struct tegra_pcie_port *pp = bus_to_port(bus->number);
+ void __iomem *addr;
+
+ if (pp) {
+ if (devfn != 0) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ addr = pp->base + (where & ~0x3);
+ } else {
+ addr = tegra_pcie.regs + (PCIE_CONF_BUS(bus->number) +
+ PCIE_CONF_DEV(PCI_SLOT(devfn)) +
+ PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
+ PCIE_CONF_REG(where));
+ }
+
+ *val = readl(addr);
+
+ if (size == 1)
+ *val = (*val >> (8 * (where & 3))) & 0xff;
+ else if (size == 2)
+ *val = (*val >> (8 * (where & 3))) & 0xffff;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int tegra_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ struct tegra_pcie_port *pp = bus_to_port(bus->number);
+ void __iomem *addr;
+
+ u32 mask;
+ u32 tmp;
+
+ if (pp) {
+ if (devfn != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ addr = pp->base + (where & ~0x3);
+ } else {
+ addr = tegra_pcie.regs + (PCIE_CONF_BUS(bus->number) +
+ PCIE_CONF_DEV(PCI_SLOT(devfn)) +
+ PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
+ PCIE_CONF_REG(where));
+ }
+
+ if (size == 4) {
+ writel(val, addr);
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ if (size == 2)
+ mask = ~(0xffff << ((where & 0x3) * 8));
+ else if (size == 1)
+ mask = ~(0xff << ((where & 0x3) * 8));
+ else
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ tmp = readl(addr) & mask;
+ tmp |= val << ((where & 0x3) * 8);
+ writel(tmp, addr);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops tegra_pcie_ops = {
+ .read = tegra_pcie_read_conf,
+ .write = tegra_pcie_write_conf,
+};
+
+static void __devinit tegra_pcie_fixup_bridge(struct pci_dev *dev)
+{
+ u16 reg;
+
+ if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) {
+ pci_read_config_word(dev, PCI_COMMAND, &reg);
+ reg |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
+ pci_write_config_word(dev, PCI_COMMAND, reg);
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_fixup_bridge);
+
+/* Tegra PCIE root complex wrongly reports device class */
+static void __devinit tegra_pcie_fixup_class(struct pci_dev *dev)
+{
+ dev->class = PCI_CLASS_BRIDGE_PCI << 8;
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_fixup_class);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_fixup_class);
+
+/* Tegra PCIE requires relaxed ordering */
+static void __devinit tegra_pcie_relax_enable(struct pci_dev *dev)
+{
+ u16 val16;
+ int pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+
+ if (pos <= 0) {
+ dev_err(&dev->dev, "skipping relaxed ordering fixup\n");
+ return;
+ }
+
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &val16);
+ val16 |= PCI_EXP_DEVCTL_RELAX_EN;
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, val16);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable);
+
+static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+ struct tegra_pcie_port *pp;
+
+ if (nr >= tegra_pcie.num_ports)
+ return 0;
+
+ pp = tegra_pcie.port + nr;
+ pp->root_bus_nr = sys->busnr;
+
+ /*
+ * IORESOURCE_IO
+ */
+ snprintf(pp->io_space_name, sizeof(pp->io_space_name),
+ "PCIe %d I/O", pp->index);
+ pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
+ pp->res[0].name = pp->io_space_name;
+ if (pp->index == 0) {
+ pp->res[0].start = PCIBIOS_MIN_IO;
+ pp->res[0].end = pp->res[0].start + SZ_32K - 1;
+ } else {
+ pp->res[0].start = PCIBIOS_MIN_IO + SZ_32K;
+ pp->res[0].end = IO_SPACE_LIMIT;
+ }
+ pp->res[0].flags = IORESOURCE_IO;
+ if (request_resource(&ioport_resource, &pp->res[0]))
+ panic("Request PCIe IO resource failed\n");
+ sys->resource[0] = &pp->res[0];
+
+ /*
+ * IORESOURCE_MEM
+ */
+ snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
+ "PCIe %d MEM", pp->index);
+ pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
+ pp->res[1].name = pp->mem_space_name;
+ if (pp->index == 0) {
+ pp->res[1].start = MEM_BASE_0;
+ pp->res[1].end = pp->res[1].start + MEM_SIZE_0 - 1;
+ } else {
+ pp->res[1].start = MEM_BASE_1;
+ pp->res[1].end = pp->res[1].start + MEM_SIZE_1 - 1;
+ }
+ pp->res[1].flags = IORESOURCE_MEM;
+ if (request_resource(&iomem_resource, &pp->res[1]))
+ panic("Request PCIe Memory resource failed\n");
+ sys->resource[1] = &pp->res[1];
+
+ /*
+ * IORESOURCE_MEM | IORESOURCE_PREFETCH
+ */
+ snprintf(pp->prefetch_space_name, sizeof(pp->prefetch_space_name),
+ "PCIe %d PREFETCH MEM", pp->index);
+ pp->prefetch_space_name[sizeof(pp->prefetch_space_name) - 1] = 0;
+ pp->res[2].name = pp->prefetch_space_name;
+ if (pp->index == 0) {
+ pp->res[2].start = PREFETCH_MEM_BASE_0;
+ pp->res[2].end = pp->res[2].start + PREFETCH_MEM_SIZE_0 - 1;
+ } else {
+ pp->res[2].start = PREFETCH_MEM_BASE_1;
+ pp->res[2].end = pp->res[2].start + PREFETCH_MEM_SIZE_1 - 1;
+ }
+ pp->res[2].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+ if (request_resource(&iomem_resource, &pp->res[2]))
+ panic("Request PCIe Prefetch Memory resource failed\n");
+ sys->resource[2] = &pp->res[2];
+
+ return 1;
+}
+
+static int tegra_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return INT_PCIE_INTR;
+}
+
+static struct pci_bus __init *tegra_pcie_scan_bus(int nr,
+ struct pci_sys_data *sys)
+{
+ struct tegra_pcie_port *pp;
+
+ if (nr >= tegra_pcie.num_ports)
+ return 0;
+
+ pp = tegra_pcie.port + nr;
+ pp->root_bus_nr = sys->busnr;
+
+ return pci_scan_bus(sys->busnr, &tegra_pcie_ops, sys);
+}
+
+static struct hw_pci tegra_pcie_hw __initdata = {
+ .nr_controllers = 2,
+ .setup = tegra_pcie_setup,
+ .scan = tegra_pcie_scan_bus,
+ .swizzle = pci_std_swizzle,
+ .map_irq = tegra_pcie_map_irq,
+};
+
+
+static irqreturn_t tegra_pcie_isr(int irq, void *arg)
+{
+ const char *err_msg[] = {
+ "Unknown",
+ "AXI slave error",
+ "AXI decode error",
+ "Target abort",
+ "Master abort",
+ "Invalid write",
+ "Response decoding error",
+ "AXI response decoding error",
+ "Transcation timeout",
+ };
+
+ u32 code, signature;
+
+ code = afi_readl(AFI_INTR_CODE) & AFI_INTR_CODE_MASK;
+ signature = afi_readl(AFI_INTR_SIGNATURE);
+ afi_writel(0, AFI_INTR_CODE);
+
+ if (code == AFI_INTR_LEGACY)
+ return IRQ_NONE;
+
+ if (code >= ARRAY_SIZE(err_msg))
+ code = 0;
+
+ /*
+ * do not pollute kernel log with master abort reports since they
+ * happen a lot during enumeration
+ */
+ if (code == AFI_INTR_MASTER_ABORT)
+ pr_debug("PCIE: %s, signature: %08x\n", err_msg[code], signature);
+ else
+ pr_err("PCIE: %s, signature: %08x\n", err_msg[code], signature);
+
+ return IRQ_HANDLED;
+}
+
+static void tegra_pcie_setup_translations(void)
+{
+ u32 fpci_bar;
+ u32 size;
+ u32 axi_address;
+
+ /* Bar 0: config Bar */
+ fpci_bar = ((u32)0xfdff << 16);
+ size = PCIE_CFG_SZ;
+ axi_address = TEGRA_PCIE_BASE + PCIE_CFG_OFF;
+ afi_writel(axi_address, AFI_AXI_BAR0_START);
+ afi_writel(size >> 12, AFI_AXI_BAR0_SZ);
+ afi_writel(fpci_bar, AFI_FPCI_BAR0);
+
+ /* Bar 1: extended config Bar */
+ fpci_bar = ((u32)0xfe1 << 20);
+ size = PCIE_EXT_CFG_SZ;
+ axi_address = TEGRA_PCIE_BASE + PCIE_EXT_CFG_OFF;
+ afi_writel(axi_address, AFI_AXI_BAR1_START);
+ afi_writel(size >> 12, AFI_AXI_BAR1_SZ);
+ afi_writel(fpci_bar, AFI_FPCI_BAR1);
+
+ /* Bar 2: downstream IO bar */
+ fpci_bar = ((__u32)0xfdfc << 16);
+ size = MMIO_SIZE;
+ axi_address = MMIO_BASE;
+ afi_writel(axi_address, AFI_AXI_BAR2_START);
+ afi_writel(size >> 12, AFI_AXI_BAR2_SZ);
+ afi_writel(fpci_bar, AFI_FPCI_BAR2);
+
+ /* Bar 3: prefetchable memory BAR */
+ fpci_bar = (((PREFETCH_MEM_BASE_0 >> 12) & 0x0fffffff) << 4) | 0x1;
+ size = PREFETCH_MEM_SIZE_0 + PREFETCH_MEM_SIZE_1;
+ axi_address = PREFETCH_MEM_BASE_0;
+ afi_writel(axi_address, AFI_AXI_BAR3_START);
+ afi_writel(size >> 12, AFI_AXI_BAR3_SZ);
+ afi_writel(fpci_bar, AFI_FPCI_BAR3);
+
+ /* Bar 4: non prefetchable memory BAR */
+ fpci_bar = (((MEM_BASE_0 >> 12) & 0x0FFFFFFF) << 4) | 0x1;
+ size = MEM_SIZE_0 + MEM_SIZE_1;
+ axi_address = MEM_BASE_0;
+ afi_writel(axi_address, AFI_AXI_BAR4_START);
+ afi_writel(size >> 12, AFI_AXI_BAR4_SZ);
+ afi_writel(fpci_bar, AFI_FPCI_BAR4);
+
+ /* Bar 5: NULL out the remaining BAR as it is not used */
+ fpci_bar = 0;
+ size = 0;
+ axi_address = 0;
+ afi_writel(axi_address, AFI_AXI_BAR5_START);
+ afi_writel(size >> 12, AFI_AXI_BAR5_SZ);
+ afi_writel(fpci_bar, AFI_FPCI_BAR5);
+
+ /* map all upstream transactions as uncached */
+ afi_writel(PHYS_OFFSET, AFI_CACHE_BAR0_ST);
+ afi_writel(0, AFI_CACHE_BAR0_SZ);
+ afi_writel(0, AFI_CACHE_BAR1_ST);
+ afi_writel(0, AFI_CACHE_BAR1_SZ);
+
+ /* No MSI */
+ afi_writel(0, AFI_MSI_FPCI_BAR_ST);
+ afi_writel(0, AFI_MSI_BAR_SZ);
+ afi_writel(0, AFI_MSI_AXI_BAR_ST);
+ afi_writel(0, AFI_MSI_BAR_SZ);
+}
+
+static void tegra_pcie_enable_controller(void)
+{
+ u32 val, reg;
+ int i;
+
+ /* Enable slot clock and pulse the reset signals */
+ for (i = 0, reg = AFI_PEX0_CTRL; i < 2; i++, reg += 0x8) {
+ val = afi_readl(reg) | AFI_PEX_CTRL_REFCLK_EN;
+ afi_writel(val, reg);
+ val &= ~AFI_PEX_CTRL_RST;
+ afi_writel(val, reg);
+
+ val = afi_readl(reg) | AFI_PEX_CTRL_RST;
+ afi_writel(val, reg);
+ }
+
+ /* Enable dual controller and both ports */
+ val = afi_readl(AFI_PCIE_CONFIG);
+ val &= ~(AFI_PCIE_CONFIG_PCIEC0_DISABLE_DEVICE |
+ AFI_PCIE_CONFIG_PCIEC1_DISABLE_DEVICE |
+ AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK);
+ val |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL;
+ afi_writel(val, AFI_PCIE_CONFIG);
+
+ val = afi_readl(AFI_FUSE) & ~AFI_FUSE_PCIE_T0_GEN2_DIS;
+ afi_writel(val, AFI_FUSE);
+
+ /* Initialze internal PHY, enable up to 16 PCIE lanes */
+ pads_writel(0x0, PADS_CTL_SEL);
+
+ /* override IDDQ to 1 on all 4 lanes */
+ val = pads_readl(PADS_CTL) | PADS_CTL_IDDQ_1L;
+ pads_writel(val, PADS_CTL);
+
+ /*
+ * set up PHY PLL inputs select PLLE output as refclock,
+ * set TX ref sel to div10 (not div5)
+ */
+ val = pads_readl(PADS_PLL_CTL);
+ val &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK);
+ val |= (PADS_PLL_CTL_REFCLK_INTERNAL_CML | PADS_PLL_CTL_TXCLKREF_DIV10);
+ pads_writel(val, PADS_PLL_CTL);
+
+ /* take PLL out of reset */
+ val = pads_readl(PADS_PLL_CTL) | PADS_PLL_CTL_RST_B4SM;
+ pads_writel(val, PADS_PLL_CTL);
+
+ /*
+ * Hack, set the clock voltage to the DEFAULT provided by hw folks.
+ * This doesn't exist in the documentation
+ */
+ pads_writel(0xfa5cfa5c, 0xc8);
+
+ /* Wait for the PLL to lock */
+ do {
+ val = pads_readl(PADS_PLL_CTL);
+ } while (!(val & PADS_PLL_CTL_LOCKDET));
+
+ /* turn off IDDQ override */
+ val = pads_readl(PADS_CTL) & ~PADS_CTL_IDDQ_1L;
+ pads_writel(val, PADS_CTL);
+
+ /* enable TX/RX data */
+ val = pads_readl(PADS_CTL);
+ val |= (PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L);
+ pads_writel(val, PADS_CTL);
+
+ /* Take the PCIe interface module out of reset */
+ tegra_periph_reset_deassert(tegra_pcie.pcie_xclk);
+
+ /* Finally enable PCIe */
+ val = afi_readl(AFI_CONFIGURATION) | AFI_CONFIGURATION_EN_FPCI;
+ afi_writel(val, AFI_CONFIGURATION);
+
+ val = (AFI_INTR_EN_INI_SLVERR | AFI_INTR_EN_INI_DECERR |
+ AFI_INTR_EN_TGT_SLVERR | AFI_INTR_EN_TGT_DECERR |
+ AFI_INTR_EN_TGT_WRERR | AFI_INTR_EN_DFPCI_DECERR);
+ afi_writel(val, AFI_AFI_INTR_ENABLE);
+ afi_writel(0xffffffff, AFI_SM_INTR_ENABLE);
+
+ /* FIXME: No MSI for now, only INT */
+ afi_writel(AFI_INTR_MASK_INT_MASK, AFI_INTR_MASK);
+
+ /* Disable all execptions */
+ afi_writel(0, AFI_FPCI_ERROR_MASKS);
+
+ return;
+}
+
+static void tegra_pcie_xclk_clamp(bool clamp)
+{
+ u32 reg;
+
+ reg = pmc_readl(PMC_SCRATCH42) & ~PMC_SCRATCH42_PCX_CLAMP;
+
+ if (clamp)
+ reg |= PMC_SCRATCH42_PCX_CLAMP;
+
+ pmc_writel(reg, PMC_SCRATCH42);
+}
+
+static int tegra_pcie_power_on(void)
+{
+ tegra_pcie_xclk_clamp(true);
+ tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
+ tegra_pcie_xclk_clamp(false);
+
+ clk_enable(tegra_pcie.afi_clk);
+ clk_enable(tegra_pcie.pex_clk);
+ return clk_enable(tegra_pcie.pll_e);
+}
+
+static void tegra_pcie_power_off(void)
+{
+ tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
+ tegra_periph_reset_assert(tegra_pcie.afi_clk);
+ tegra_periph_reset_assert(tegra_pcie.pex_clk);
+
+ tegra_pcie_xclk_clamp(true);
+}
+
+static int tegra_pcie_clocks_get(void)
+{
+ int err;
+
+ tegra_pcie.pex_clk = clk_get(NULL, "pex");
+ if (IS_ERR(tegra_pcie.pex_clk))
+ return PTR_ERR(tegra_pcie.pex_clk);
+
+ tegra_pcie.afi_clk = clk_get(NULL, "afi");
+ if (IS_ERR(tegra_pcie.afi_clk)) {
+ err = PTR_ERR(tegra_pcie.afi_clk);
+ goto err_afi_clk;
+ }
+
+ tegra_pcie.pcie_xclk = clk_get(NULL, "pcie_xclk");
+ if (IS_ERR(tegra_pcie.pcie_xclk)) {
+ err = PTR_ERR(tegra_pcie.pcie_xclk);
+ goto err_pcie_xclk;
+ }
+
+ tegra_pcie.pll_e = clk_get_sys(NULL, "pll_e");
+ if (IS_ERR(tegra_pcie.pll_e)) {
+ err = PTR_ERR(tegra_pcie.pll_e);
+ goto err_pll_e;
+ }
+
+ return 0;
+
+err_pll_e:
+ clk_put(tegra_pcie.pcie_xclk);
+err_pcie_xclk:
+ clk_put(tegra_pcie.afi_clk);
+err_afi_clk:
+ clk_put(tegra_pcie.pex_clk);
+
+ return err;
+}
+
+static void tegra_pcie_clocks_put(void)
+{
+ clk_put(tegra_pcie.pll_e);
+ clk_put(tegra_pcie.pcie_xclk);
+ clk_put(tegra_pcie.afi_clk);
+ clk_put(tegra_pcie.pex_clk);
+}
+
+static int __init tegra_pcie_get_resources(void)
+{
+ struct resource *res_mmio = &tegra_pcie.res_mmio;
+ int err;
+
+ err = tegra_pcie_clocks_get();
+ if (err) {
+ pr_err("PCIE: failed to get clocks: %d\n", err);
+ return err;
+ }
+
+ err = tegra_pcie_power_on();
+ if (err) {
+ pr_err("PCIE: failed to power up: %d\n", err);
+ goto err_pwr_on;
+ }
+
+ tegra_pcie.regs = ioremap_nocache(TEGRA_PCIE_BASE, PCIE_IOMAP_SZ);
+ if (tegra_pcie.regs == NULL) {
+ pr_err("PCIE: Failed to map PCI/AFI registers\n");
+ err = -ENOMEM;
+ goto err_map_reg;
+ }
+
+ err = request_resource(&iomem_resource, res_mmio);
+ if (err) {
+ pr_err("PCIE: Failed to request resources: %d\n", err);
+ goto err_req_io;
+ }
+
+ tegra_pcie_io_base = ioremap_nocache(res_mmio->start,
+ resource_size(res_mmio));
+ if (tegra_pcie_io_base == NULL) {
+ pr_err("PCIE: Failed to map IO\n");
+ err = -ENOMEM;
+ goto err_map_io;
+ }
+
+ err = request_irq(INT_PCIE_INTR, tegra_pcie_isr,
+ IRQF_SHARED, "PCIE", &tegra_pcie);
+ if (err) {
+ pr_err("PCIE: Failed to register IRQ: %d\n", err);
+ goto err_irq;
+ }
+ set_irq_flags(INT_PCIE_INTR, IRQF_VALID);
+
+ return 0;
+
+err_irq:
+ iounmap(tegra_pcie_io_base);
+err_map_io:
+ release_resource(&tegra_pcie.res_mmio);
+err_req_io:
+ iounmap(tegra_pcie.regs);
+err_map_reg:
+ tegra_pcie_power_off();
+err_pwr_on:
+ tegra_pcie_clocks_put();
+
+ return err;
+}
+
+/*
+ * FIXME: If there are no PCIe cards attached, then calling this function
+ * can result in the increase of the bootup time as there are big timeout
+ * loops.
+ */
+#define TEGRA_PCIE_LINKUP_TIMEOUT 200 /* up to 1.2 seconds */
+static bool tegra_pcie_check_link(struct tegra_pcie_port *pp, int idx,
+ u32 reset_reg)
+{
+ u32 reg;
+ int retries = 3;
+ int timeout;
+
+ do {
+ timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
+ while (timeout) {
+ reg = readl(pp->base + RP_VEND_XP);
+
+ if (reg & RP_VEND_XP_DL_UP)
+ break;
+
+ mdelay(1);
+ timeout--;
+ }
+
+ if (!timeout) {
+ pr_err("PCIE: port %d: link down, retrying\n", idx);
+ goto retry;
+ }
+
+ timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
+ while (timeout) {
+ reg = readl(pp->base + RP_LINK_CONTROL_STATUS);
+
+ if (reg & 0x20000000)
+ return true;
+
+ mdelay(1);
+ timeout--;
+ }
+
+retry:
+ /* Pulse the PEX reset */
+ reg = afi_readl(reset_reg) | AFI_PEX_CTRL_RST;
+ afi_writel(reg, reset_reg);
+ mdelay(1);
+ reg = afi_readl(reset_reg) & ~AFI_PEX_CTRL_RST;
+ afi_writel(reg, reset_reg);
+
+ retries--;
+ } while (retries);
+
+ return false;
+}
+
+static void __init tegra_pcie_add_port(int index, u32 offset, u32 reset_reg)
+{
+ struct tegra_pcie_port *pp;
+
+ pp = tegra_pcie.port + tegra_pcie.num_ports;
+
+ pp->index = -1;
+ pp->base = tegra_pcie.regs + offset;
+ pp->link_up = tegra_pcie_check_link(pp, index, reset_reg);
+
+ if (!pp->link_up) {
+ pp->base = NULL;
+ printk(KERN_INFO "PCIE: port %d: link down, ignoring\n", index);
+ return;
+ }
+
+ tegra_pcie.num_ports++;
+ pp->index = index;
+ pp->root_bus_nr = -1;
+ memset(pp->res, 0, sizeof(pp->res));
+}
+
+int __init tegra_pcie_init(bool init_port0, bool init_port1)
+{
+ int err;
+
+ if (!(init_port0 || init_port1))
+ return -ENODEV;
+
+ err = tegra_pcie_get_resources();
+ if (err)
+ return err;
+
+ tegra_pcie_enable_controller();
+
+ /* setup the AFI address translations */
+ tegra_pcie_setup_translations();
+
+ if (init_port0)
+ tegra_pcie_add_port(0, RP0_OFFSET, AFI_PEX0_CTRL);
+
+ if (init_port1)
+ tegra_pcie_add_port(1, RP1_OFFSET, AFI_PEX1_CTRL);
+
+ pci_common_init(&tegra_pcie_hw);
+
+ return 0;
+}
diff --git a/arch/arm/mach-tegra/pinmux-t2-tables.c b/arch/arm/mach-tegra/pinmux-t2-tables.c
new file mode 100644
index 000000000000..a6ea34e782dc
--- /dev/null
+++ b/arch/arm/mach-tegra/pinmux-t2-tables.c
@@ -0,0 +1,260 @@
+/*
+ * linux/arch/arm/mach-tegra/pinmux-t2-tables.c
+ *
+ * Common pinmux configurations for Tegra 2 SoCs
+ *
+ * Copyright (C) 2010 NVIDIA 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; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <mach/iomap.h>
+#include <mach/pinmux.h>
+
+#define DRIVE_PINGROUP(pg_name, r) \
+ [TEGRA_DRIVE_PINGROUP_ ## pg_name] = { \
+ .name = #pg_name, \
+ .reg = r \
+ }
+
+const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE_PINGROUP] = {
+ DRIVE_PINGROUP(AO1, 0x868),
+ DRIVE_PINGROUP(AO2, 0x86c),
+ DRIVE_PINGROUP(AT1, 0x870),
+ DRIVE_PINGROUP(AT2, 0x874),
+ DRIVE_PINGROUP(CDEV1, 0x878),
+ DRIVE_PINGROUP(CDEV2, 0x87c),
+ DRIVE_PINGROUP(CSUS, 0x880),
+ DRIVE_PINGROUP(DAP1, 0x884),
+ DRIVE_PINGROUP(DAP2, 0x888),
+ DRIVE_PINGROUP(DAP3, 0x88c),
+ DRIVE_PINGROUP(DAP4, 0x890),
+ DRIVE_PINGROUP(DBG, 0x894),
+ DRIVE_PINGROUP(LCD1, 0x898),
+ DRIVE_PINGROUP(LCD2, 0x89c),
+ DRIVE_PINGROUP(SDMMC2, 0x8a0),
+ DRIVE_PINGROUP(SDMMC3, 0x8a4),
+ DRIVE_PINGROUP(SPI, 0x8a8),
+ DRIVE_PINGROUP(UAA, 0x8ac),
+ DRIVE_PINGROUP(UAB, 0x8b0),
+ DRIVE_PINGROUP(UART2, 0x8b4),
+ DRIVE_PINGROUP(UART3, 0x8b8),
+ DRIVE_PINGROUP(VI1, 0x8bc),
+ DRIVE_PINGROUP(VI2, 0x8c0),
+ DRIVE_PINGROUP(XM2A, 0x8c4),
+ DRIVE_PINGROUP(XM2C, 0x8c8),
+ DRIVE_PINGROUP(XM2D, 0x8cc),
+ DRIVE_PINGROUP(XM2CLK, 0x8d0),
+ DRIVE_PINGROUP(MEMCOMP, 0x8d4),
+};
+
+#define PINGROUP(pg_name, vdd, f0, f1, f2, f3, f_safe, \
+ tri_r, tri_b, mux_r, mux_b, pupd_r, pupd_b) \
+ [TEGRA_PINGROUP_ ## pg_name] = { \
+ .name = #pg_name, \
+ .vddio = TEGRA_VDDIO_ ## vdd, \
+ .funcs = { \
+ TEGRA_MUX_ ## f0, \
+ TEGRA_MUX_ ## f1, \
+ TEGRA_MUX_ ## f2, \
+ TEGRA_MUX_ ## f3, \
+ }, \
+ .func_safe = TEGRA_MUX_ ## f_safe, \
+ .tri_reg = tri_r, \
+ .tri_bit = tri_b, \
+ .mux_reg = mux_r, \
+ .mux_bit = mux_b, \
+ .pupd_reg = pupd_r, \
+ .pupd_bit = pupd_b, \
+ }
+
+const struct tegra_pingroup_desc tegra_soc_pingroups[TEGRA_MAX_PINGROUP] = {
+ PINGROUP(ATA, NAND, IDE, NAND, GMI, RSVD, IDE, 0x14, 0, 0x80, 24, 0xA0, 0),
+ PINGROUP(ATB, NAND, IDE, NAND, GMI, SDIO4, IDE, 0x14, 1, 0x80, 16, 0xA0, 2),
+ PINGROUP(ATC, NAND, IDE, NAND, GMI, SDIO4, IDE, 0x14, 2, 0x80, 22, 0xA0, 4),
+ PINGROUP(ATD, NAND, IDE, NAND, GMI, SDIO4, IDE, 0x14, 3, 0x80, 20, 0xA0, 6),
+ PINGROUP(ATE, NAND, IDE, NAND, GMI, RSVD, IDE, 0x18, 25, 0x80, 12, 0xA0, 8),
+ PINGROUP(CDEV1, AUDIO, OSC, PLLA_OUT, PLLM_OUT1, AUDIO_SYNC, OSC, 0x14, 4, 0x88, 2, 0xA8, 0),
+ PINGROUP(CDEV2, AUDIO, OSC, AHB_CLK, APB_CLK, PLLP_OUT4, OSC, 0x14, 5, 0x88, 4, 0xA8, 2),
+ PINGROUP(CRTP, LCD, CRT, RSVD, RSVD, RSVD, RSVD, 0x20, 14, 0x98, 20, 0xA4, 24),
+ PINGROUP(CSUS, VI, PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, VI_SENSOR_CLK, PLLC_OUT1, 0x14, 6, 0x88, 6, 0xAC, 24),
+ PINGROUP(DAP1, AUDIO, DAP1, RSVD, GMI, SDIO2, DAP1, 0x14, 7, 0x88, 20, 0xA0, 10),
+ PINGROUP(DAP2, AUDIO, DAP2, TWC, RSVD, GMI, DAP2, 0x14, 8, 0x88, 22, 0xA0, 12),
+ PINGROUP(DAP3, BB, DAP3, RSVD, RSVD, RSVD, DAP3, 0x14, 9, 0x88, 24, 0xA0, 14),
+ PINGROUP(DAP4, UART, DAP4, RSVD, GMI, RSVD, DAP4, 0x14, 10, 0x88, 26, 0xA0, 16),
+ PINGROUP(DDC, LCD, I2C2, RSVD, RSVD, RSVD, RSVD4, 0x18, 31, 0x88, 0, 0xB0, 28),
+ PINGROUP(DTA, VI, RSVD, SDIO2, VI, RSVD, RSVD4, 0x14, 11, 0x84, 20, 0xA0, 18),
+ PINGROUP(DTB, VI, RSVD, RSVD, VI, SPI1, RSVD1, 0x14, 12, 0x84, 22, 0xA0, 20),
+ PINGROUP(DTC, VI, RSVD, RSVD, VI, RSVD, RSVD1, 0x14, 13, 0x84, 26, 0xA0, 22),
+ PINGROUP(DTD, VI, RSVD, SDIO2, VI, RSVD, RSVD1, 0x14, 14, 0x84, 28, 0xA0, 24),
+ PINGROUP(DTE, VI, RSVD, RSVD, VI, SPI1, RSVD1, 0x14, 15, 0x84, 30, 0xA0, 26),
+ PINGROUP(DTF, VI, I2C3, RSVD, VI, RSVD, RSVD4, 0x20, 12, 0x98, 30, 0xA0, 28),
+ PINGROUP(GMA, NAND, UARTE, SPI3, GMI, SDIO4, SPI3, 0x14, 28, 0x84, 0, 0xB0, 20),
+ PINGROUP(GMB, NAND, IDE, NAND, GMI, GMI_INT, GMI, 0x18, 29, 0x88, 28, 0xB0, 22),
+ PINGROUP(GMC, NAND, UARTD, SPI4, GMI, SFLASH, SPI4, 0x14, 29, 0x84, 2, 0xB0, 24),
+ PINGROUP(GMD, NAND, RSVD, NAND, GMI, SFLASH, GMI, 0x18, 30, 0x88, 30, 0xB0, 26),
+ PINGROUP(GME, NAND, RSVD, DAP5, GMI, SDIO4, GMI, 0x18, 0, 0x8C, 0, 0xA8, 24),
+ PINGROUP(GPU, UART, PWM, UARTA, GMI, RSVD, RSVD4, 0x14, 16, 0x8C, 4, 0xA4, 20),
+ PINGROUP(GPU7, SYS, RTCK, RSVD, RSVD, RSVD, RTCK, 0x20, 11, 0x98, 28, 0xA4, 6),
+ PINGROUP(GPV, SD, PCIE, RSVD, RSVD, RSVD, PCIE, 0x14, 17, 0x8C, 2, 0xA0, 30),
+ PINGROUP(HDINT, LCD, HDMI, RSVD, RSVD, RSVD, HDMI, 0x1C, 23, 0x84, 4, 0xAC, 22),
+ PINGROUP(I2CP, SYS, I2C, RSVD, RSVD, RSVD, RSVD4, 0x14, 18, 0x88, 8, 0xA4, 2),
+ PINGROUP(IRRX, UART, UARTA, UARTB, GMI, SPI4, UARTB, 0x14, 20, 0x88, 18, 0xA8, 22),
+ PINGROUP(IRTX, UART, UARTA, UARTB, GMI, SPI4, UARTB, 0x14, 19, 0x88, 16, 0xA8, 20),
+ PINGROUP(KBCA, SYS, KBC, NAND, SDIO2, EMC_TEST0_DLL, KBC, 0x14, 22, 0x88, 10, 0xA4, 8),
+ PINGROUP(KBCB, SYS, KBC, NAND, SDIO2, MIO, KBC, 0x14, 21, 0x88, 12, 0xA4, 10),
+ PINGROUP(KBCC, SYS, KBC, NAND, TRACE, EMC_TEST1_DLL, KBC, 0x18, 26, 0x88, 14, 0xA4, 12),
+ PINGROUP(KBCD, SYS, KBC, NAND, SDIO2, MIO, KBC, 0x20, 10, 0x98, 26, 0xA4, 14),
+ PINGROUP(KBCE, SYS, KBC, NAND, OWR, RSVD, KBC, 0x14, 26, 0x80, 28, 0xB0, 2),
+ PINGROUP(KBCF, SYS, KBC, NAND, TRACE, MIO, KBC, 0x14, 27, 0x80, 26, 0xB0, 0),
+ PINGROUP(LCSN, LCD, DISPLAYA, DISPLAYB, SPI3, RSVD, RSVD4, 0x1C, 31, 0x90, 12, 0xAC, 20),
+ PINGROUP(LD0, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 0, 0x94, 0, 0xAC, 12),
+ PINGROUP(LD1, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 1, 0x94, 2, 0xAC, 12),
+ PINGROUP(LD10, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 10, 0x94, 20, 0xAC, 12),
+ PINGROUP(LD11, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 11, 0x94, 22, 0xAC, 12),
+ PINGROUP(LD12, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 12, 0x94, 24, 0xAC, 12),
+ PINGROUP(LD13, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 13, 0x94, 26, 0xAC, 12),
+ PINGROUP(LD14, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 14, 0x94, 28, 0xAC, 12),
+ PINGROUP(LD15, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 15, 0x94, 30, 0xAC, 12),
+ PINGROUP(LD16, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 16, 0x98, 0, 0xAC, 12),
+ PINGROUP(LD17, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x1C, 17, 0x98, 2, 0xAC, 12),
+ PINGROUP(LD2, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 2, 0x94, 4, 0xAC, 12),
+ PINGROUP(LD3, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 3, 0x94, 6, 0xAC, 12),
+ PINGROUP(LD4, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 4, 0x94, 8, 0xAC, 12),
+ PINGROUP(LD5, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 5, 0x94, 10, 0xAC, 12),
+ PINGROUP(LD6, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 6, 0x94, 12, 0xAC, 12),
+ PINGROUP(LD7, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 7, 0x94, 14, 0xAC, 12),
+ PINGROUP(LD8, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 8, 0x94, 16, 0xAC, 12),
+ PINGROUP(LD9, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 9, 0x94, 18, 0xAC, 12),
+ PINGROUP(LDC, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x1C, 30, 0x90, 14, 0xAC, 20),
+ PINGROUP(LDI, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x20, 6, 0x98, 16, 0xAC, 18),
+ PINGROUP(LHP0, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x1C, 18, 0x98, 10, 0xAC, 16),
+ PINGROUP(LHP1, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x1C, 19, 0x98, 4, 0xAC, 14),
+ PINGROUP(LHP2, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x1C, 20, 0x98, 6, 0xAC, 14),
+ PINGROUP(LHS, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x20, 7, 0x90, 22, 0xAC, 22),
+ PINGROUP(LM0, LCD, DISPLAYA, DISPLAYB, SPI3, RSVD, RSVD4, 0x1C, 24, 0x90, 26, 0xAC, 22),
+ PINGROUP(LM1, LCD, DISPLAYA, DISPLAYB, RSVD, CRT, RSVD3, 0x1C, 25, 0x90, 28, 0xAC, 22),
+ PINGROUP(LPP, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x20, 8, 0x98, 14, 0xAC, 18),
+ PINGROUP(LPW0, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x20, 3, 0x90, 0, 0xAC, 20),
+ PINGROUP(LPW1, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x20, 4, 0x90, 2, 0xAC, 20),
+ PINGROUP(LPW2, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x20, 5, 0x90, 4, 0xAC, 20),
+ PINGROUP(LSC0, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 27, 0x90, 18, 0xAC, 22),
+ PINGROUP(LSC1, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x1C, 28, 0x90, 20, 0xAC, 20),
+ PINGROUP(LSCK, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x1C, 29, 0x90, 16, 0xAC, 20),
+ PINGROUP(LSDA, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x20, 1, 0x90, 8, 0xAC, 20),
+ PINGROUP(LSDI, LCD, DISPLAYA, DISPLAYB, SPI3, RSVD, DISPLAYA, 0x20, 2, 0x90, 6, 0xAC, 20),
+ PINGROUP(LSPI, LCD, DISPLAYA, DISPLAYB, XIO, HDMI, DISPLAYA, 0x20, 0, 0x90, 10, 0xAC, 22),
+ PINGROUP(LVP0, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x1C, 21, 0x90, 30, 0xAC, 22),
+ PINGROUP(LVP1, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x1C, 22, 0x98, 8, 0xAC, 16),
+ PINGROUP(LVS, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 26, 0x90, 24, 0xAC, 22),
+ PINGROUP(OWC, SYS, OWR, RSVD, RSVD, RSVD, OWR, 0x14, 31, 0x84, 8, 0xB0, 30),
+ PINGROUP(PMC, SYS, PWR_ON, PWR_INTR, RSVD, RSVD, PWR_ON, 0x14, 23, 0x98, 18, -1, -1),
+ PINGROUP(PTA, NAND, I2C2, HDMI, GMI, RSVD, RSVD4, 0x14, 24, 0x98, 22, 0xA4, 4),
+ PINGROUP(RM, UART, I2C, RSVD, RSVD, RSVD, RSVD4, 0x14, 25, 0x80, 14, 0xA4, 0),
+ PINGROUP(SDB, SD, UARTA, PWM, SDIO3, SPI2, PWM, 0x20, 15, 0x8C, 10, -1, -1),
+ PINGROUP(SDC, SD, PWM, TWC, SDIO3, SPI3, TWC, 0x18, 1, 0x8C, 12, 0xAC, 28),
+ PINGROUP(SDD, SD, UARTA, PWM, SDIO3, SPI3, PWM, 0x18, 2, 0x8C, 14, 0xAC, 30),
+ PINGROUP(SDIO1, BB, SDIO1, RSVD, UARTE, UARTA, RSVD2, 0x14, 30, 0x80, 30, 0xB0, 18),
+ PINGROUP(SLXA, SD, PCIE, SPI4, SDIO3, SPI2, PCIE, 0x18, 3, 0x84, 6, 0xA4, 22),
+ PINGROUP(SLXC, SD, SPDIF, SPI4, SDIO3, SPI2, SPI4, 0x18, 5, 0x84, 10, 0xA4, 26),
+ PINGROUP(SLXD, SD, SPDIF, SPI4, SDIO3, SPI2, SPI4, 0x18, 6, 0x84, 12, 0xA4, 28),
+ PINGROUP(SLXK, SD, PCIE, SPI4, SDIO3, SPI2, PCIE, 0x18, 7, 0x84, 14, 0xA4, 30),
+ PINGROUP(SPDI, AUDIO, SPDIF, RSVD, I2C, SDIO2, RSVD2, 0x18, 8, 0x8C, 8, 0xA4, 16),
+ PINGROUP(SPDO, AUDIO, SPDIF, RSVD, I2C, SDIO2, RSVD2, 0x18, 9, 0x8C, 6, 0xA4, 18),
+ PINGROUP(SPIA, AUDIO, SPI1, SPI2, SPI3, GMI, GMI, 0x18, 10, 0x8C, 30, 0xA8, 4),
+ PINGROUP(SPIB, AUDIO, SPI1, SPI2, SPI3, GMI, GMI, 0x18, 11, 0x8C, 28, 0xA8, 6),
+ PINGROUP(SPIC, AUDIO, SPI1, SPI2, SPI3, GMI, GMI, 0x18, 12, 0x8C, 26, 0xA8, 8),
+ PINGROUP(SPID, AUDIO, SPI2, SPI1, SPI2_ALT, GMI, GMI, 0x18, 13, 0x8C, 24, 0xA8, 10),
+ PINGROUP(SPIE, AUDIO, SPI2, SPI1, SPI2_ALT, GMI, GMI, 0x18, 14, 0x8C, 22, 0xA8, 12),
+ PINGROUP(SPIF, AUDIO, SPI3, SPI1, SPI2, RSVD, RSVD4, 0x18, 15, 0x8C, 20, 0xA8, 14),
+ PINGROUP(SPIG, AUDIO, SPI3, SPI2, SPI2_ALT, I2C, SPI2_ALT, 0x18, 16, 0x8C, 18, 0xA8, 16),
+ PINGROUP(SPIH, AUDIO, SPI3, SPI2, SPI2_ALT, I2C, SPI2_ALT, 0x18, 17, 0x8C, 16, 0xA8, 18),
+ PINGROUP(UAA, BB, SPI3, MIPI_HS, UARTA, ULPI, MIPI_HS, 0x18, 18, 0x80, 0, 0xAC, 0),
+ PINGROUP(UAB, BB, SPI2, MIPI_HS, UARTA, ULPI, MIPI_HS, 0x18, 19, 0x80, 2, 0xAC, 2),
+ PINGROUP(UAC, BB, OWR, RSVD, RSVD, RSVD, RSVD4, 0x18, 20, 0x80, 4, 0xAC, 4),
+ PINGROUP(UAD, UART, IRDA, SPDIF, UARTA, SPI4, SPDIF, 0x18, 21, 0x80, 6, 0xAC, 6),
+ PINGROUP(UCA, UART, UARTC, RSVD, GMI, RSVD, RSVD4, 0x18, 22, 0x84, 16, 0xAC, 8),
+ PINGROUP(UCB, UART, UARTC, PWM, GMI, RSVD, RSVD4, 0x18, 23, 0x84, 18, 0xAC, 10),
+ PINGROUP(UDA, BB, SPI1, RSVD, UARTD, ULPI, RSVD2, 0x20, 13, 0x80, 8, 0xB0, 16),
+ /* these pin groups only have pullup and pull down control */
+ PINGROUP(CK32, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xB0, 14),
+ PINGROUP(DDRC, DDR, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xAC, 26),
+ PINGROUP(PMCA, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xB0, 4),
+ PINGROUP(PMCB, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xB0, 6),
+ PINGROUP(PMCC, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xB0, 8),
+ PINGROUP(PMCD, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xB0, 10),
+ PINGROUP(PMCE, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xB0, 12),
+ PINGROUP(XM2C, DDR, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xA8, 30),
+ PINGROUP(XM2D, DDR, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xA8, 28),
+};
+
+#ifdef CONFIG_PM
+#define TRISTATE_REG_A 0x14
+#define TRISTATE_REG_NUM 4
+#define PIN_MUX_CTL_REG_A 0x80
+#define PIN_MUX_CTL_REG_NUM 8
+#define PULLUPDOWN_REG_A 0xa0
+#define PULLUPDOWN_REG_NUM 5
+
+static u32 pinmux_reg[TRISTATE_REG_NUM + PIN_MUX_CTL_REG_NUM +
+ PULLUPDOWN_REG_NUM];
+
+static inline unsigned long pg_readl(unsigned long offset)
+{
+ return readl(IO_TO_VIRT(TEGRA_APB_MISC_BASE + offset));
+}
+
+static inline void pg_writel(unsigned long value, unsigned long offset)
+{
+ writel(value, IO_TO_VIRT(TEGRA_APB_MISC_BASE + offset));
+}
+
+void tegra_pinmux_suspend(void)
+{
+ unsigned int i;
+ u32 *ctx = pinmux_reg;
+
+ for (i = 0; i < TRISTATE_REG_NUM; i++)
+ *ctx++ = pg_readl(TRISTATE_REG_A + i*4);
+
+ for (i = 0; i < PIN_MUX_CTL_REG_NUM; i++)
+ *ctx++ = pg_readl(PIN_MUX_CTL_REG_A + i*4);
+
+ for (i = 0; i < PULLUPDOWN_REG_NUM; i++)
+ *ctx++ = pg_readl(PULLUPDOWN_REG_A + i*4);
+}
+
+void tegra_pinmux_resume(void)
+{
+ unsigned int i;
+ u32 *ctx = pinmux_reg;
+
+ for (i = 0; i < PIN_MUX_CTL_REG_NUM; i++)
+ pg_writel(*ctx++, PIN_MUX_CTL_REG_A + i*4);
+
+ for (i = 0; i < PULLUPDOWN_REG_NUM; i++)
+ pg_writel(*ctx++, PULLUPDOWN_REG_A + i*4);
+
+ for (i = 0; i < TRISTATE_REG_NUM; i++)
+ pg_writel(*ctx++, TRISTATE_REG_A + i*4);
+}
+#endif
diff --git a/arch/arm/mach-tegra/pinmux.c b/arch/arm/mach-tegra/pinmux.c
index 13ae10237e84..f80d507671bc 100644
--- a/arch/arm/mach-tegra/pinmux.c
+++ b/arch/arm/mach-tegra/pinmux.c
@@ -14,7 +14,8 @@
*
*/
-
+#include <linux/init.h>
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/spinlock.h>
@@ -23,21 +24,6 @@
#include <mach/iomap.h>
#include <mach/pinmux.h>
-
-#define TEGRA_TRI_STATE(x) (0x14 + (4 * (x)))
-#define TEGRA_PP_MUX_CTL(x) (0x80 + (4 * (x)))
-#define TEGRA_PP_PU_PD(x) (0xa0 + (4 * (x)))
-
-#define REG_A 0
-#define REG_B 1
-#define REG_C 2
-#define REG_D 3
-#define REG_E 4
-#define REG_F 5
-#define REG_G 6
-
-#define REG_N -1
-
#define HSM_EN(reg) (((reg) >> 2) & 0x1)
#define SCHMT_EN(reg) (((reg) >> 3) & 0x1)
#define LPMD(reg) (((reg) >> 4) & 0x3)
@@ -46,154 +32,8 @@
#define SLWR(reg) (((reg) >> 28) & 0x3)
#define SLWF(reg) (((reg) >> 30) & 0x3)
-struct tegra_pingroup_desc {
- const char *name;
- int funcs[4];
- s8 tri_reg; /* offset into the TRISTATE_REG_* register bank */
- s8 tri_bit; /* offset into the TRISTATE_REG_* register bit */
- s8 mux_reg; /* offset into the PIN_MUX_CTL_* register bank */
- s8 mux_bit; /* offset into the PIN_MUX_CTL_* register bit */
- s8 pupd_reg; /* offset into the PULL_UPDOWN_REG_* register bank */
- s8 pupd_bit; /* offset into the PULL_UPDOWN_REG_* register bit */
-};
-
-#define PINGROUP(pg_name, f0, f1, f2, f3, \
- tri_r, tri_b, mux_r, mux_b, pupd_r, pupd_b) \
- [TEGRA_PINGROUP_ ## pg_name] = { \
- .name = #pg_name, \
- .funcs = { \
- TEGRA_MUX_ ## f0, \
- TEGRA_MUX_ ## f1, \
- TEGRA_MUX_ ## f2, \
- TEGRA_MUX_ ## f3, \
- }, \
- .tri_reg = REG_ ## tri_r, \
- .tri_bit = tri_b, \
- .mux_reg = REG_ ## mux_r, \
- .mux_bit = mux_b, \
- .pupd_reg = REG_ ## pupd_r, \
- .pupd_bit = pupd_b, \
- }
-
-static const struct tegra_pingroup_desc pingroups[TEGRA_MAX_PINGROUP] = {
- PINGROUP(ATA, IDE, NAND, GMI, RSVD, A, 0, A, 24, A, 0),
- PINGROUP(ATB, IDE, NAND, GMI, SDIO4, A, 1, A, 16, A, 2),
- PINGROUP(ATC, IDE, NAND, GMI, SDIO4, A, 2, A, 22, A, 4),
- PINGROUP(ATD, IDE, NAND, GMI, SDIO4, A, 3, A, 20, A, 6),
- PINGROUP(ATE, IDE, NAND, GMI, RSVD, B, 25, A, 12, A, 8),
- PINGROUP(CDEV1, OSC, PLLA_OUT, PLLM_OUT1, AUDIO_SYNC, A, 4, C, 2, C, 0),
- PINGROUP(CDEV2, OSC, AHB_CLK, APB_CLK, PLLP_OUT4, A, 5, C, 4, C, 2),
- PINGROUP(CRTP, CRT, RSVD, RSVD, RSVD, D, 14, G, 20, B, 24),
- PINGROUP(CSUS, PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, VI_SENSOR_CLK, A, 6, C, 6, D, 24),
- PINGROUP(DAP1, DAP1, RSVD, GMI, SDIO2, A, 7, C, 20, A, 10),
- PINGROUP(DAP2, DAP2, TWC, RSVD, GMI, A, 8, C, 22, A, 12),
- PINGROUP(DAP3, DAP3, RSVD, RSVD, RSVD, A, 9, C, 24, A, 14),
- PINGROUP(DAP4, DAP4, RSVD, GMI, RSVD, A, 10, C, 26, A, 16),
- PINGROUP(DDC, I2C2, RSVD, RSVD, RSVD, B, 31, C, 0, E, 28),
- PINGROUP(DTA, RSVD, SDIO2, VI, RSVD, A, 11, B, 20, A, 18),
- PINGROUP(DTB, RSVD, RSVD, VI, SPI1, A, 12, B, 22, A, 20),
- PINGROUP(DTC, RSVD, RSVD, VI, RSVD, A, 13, B, 26, A, 22),
- PINGROUP(DTD, RSVD, SDIO2, VI, RSVD, A, 14, B, 28, A, 24),
- PINGROUP(DTE, RSVD, RSVD, VI, SPI1, A, 15, B, 30, A, 26),
- PINGROUP(DTF, I2C3, RSVD, VI, RSVD, D, 12, G, 30, A, 28),
- PINGROUP(GMA, UARTE, SPI3, GMI, SDIO4, A, 28, B, 0, E, 20),
- PINGROUP(GMB, IDE, NAND, GMI, GMI_INT, B, 29, C, 28, E, 22),
- PINGROUP(GMC, UARTD, SPI4, GMI, SFLASH, A, 29, B, 2, E, 24),
- PINGROUP(GMD, RSVD, NAND, GMI, SFLASH, B, 30, C, 30, E, 26),
- PINGROUP(GME, RSVD, DAP5, GMI, SDIO4, B, 0, D, 0, C, 24),
- PINGROUP(GPU, PWM, UARTA, GMI, RSVD, A, 16, D, 4, B, 20),
- PINGROUP(GPU7, RTCK, RSVD, RSVD, RSVD, D, 11, G, 28, B, 6),
- PINGROUP(GPV, PCIE, RSVD, RSVD, RSVD, A, 17, D, 2, A, 30),
- PINGROUP(HDINT, HDMI, RSVD, RSVD, RSVD, C, 23, B, 4, D, 22),
- PINGROUP(I2CP, I2C, RSVD, RSVD, RSVD, A, 18, C, 8, B, 2),
- PINGROUP(IRRX, UARTA, UARTB, GMI, SPI4, A, 20, C, 18, C, 22),
- PINGROUP(IRTX, UARTA, UARTB, GMI, SPI4, A, 19, C, 16, C, 20),
- PINGROUP(KBCA, KBC, NAND, SDIO2, EMC_TEST0_DLL, A, 22, C, 10, B, 8),
- PINGROUP(KBCB, KBC, NAND, SDIO2, MIO, A, 21, C, 12, B, 10),
- PINGROUP(KBCC, KBC, NAND, TRACE, EMC_TEST1_DLL, B, 26, C, 14, B, 12),
- PINGROUP(KBCD, KBC, NAND, SDIO2, MIO, D, 10, G, 26, B, 14),
- PINGROUP(KBCE, KBC, NAND, OWR, RSVD, A, 26, A, 28, E, 2),
- PINGROUP(KBCF, KBC, NAND, TRACE, MIO, A, 27, A, 26, E, 0),
- PINGROUP(LCSN, DISPLAYA, DISPLAYB, SPI3, RSVD, C, 31, E, 12, D, 20),
- PINGROUP(LD0, DISPLAYA, DISPLAYB, XIO, RSVD, C, 0, F, 0, D, 12),
- PINGROUP(LD1, DISPLAYA, DISPLAYB, XIO, RSVD, C, 1, F, 2, D, 12),
- PINGROUP(LD10, DISPLAYA, DISPLAYB, XIO, RSVD, C, 10, F, 20, D, 12),
- PINGROUP(LD11, DISPLAYA, DISPLAYB, XIO, RSVD, C, 11, F, 22, D, 12),
- PINGROUP(LD12, DISPLAYA, DISPLAYB, XIO, RSVD, C, 12, F, 24, D, 12),
- PINGROUP(LD13, DISPLAYA, DISPLAYB, XIO, RSVD, C, 13, F, 26, D, 12),
- PINGROUP(LD14, DISPLAYA, DISPLAYB, XIO, RSVD, C, 14, F, 28, D, 12),
- PINGROUP(LD15, DISPLAYA, DISPLAYB, XIO, RSVD, C, 15, F, 30, D, 12),
- PINGROUP(LD16, DISPLAYA, DISPLAYB, XIO, RSVD, C, 16, G, 0, D, 12),
- PINGROUP(LD17, DISPLAYA, DISPLAYB, RSVD, RSVD, C, 17, G, 2, D, 12),
- PINGROUP(LD2, DISPLAYA, DISPLAYB, XIO, RSVD, C, 2, F, 4, D, 12),
- PINGROUP(LD3, DISPLAYA, DISPLAYB, XIO, RSVD, C, 3, F, 6, D, 12),
- PINGROUP(LD4, DISPLAYA, DISPLAYB, XIO, RSVD, C, 4, F, 8, D, 12),
- PINGROUP(LD5, DISPLAYA, DISPLAYB, XIO, RSVD, C, 5, F, 10, D, 12),
- PINGROUP(LD6, DISPLAYA, DISPLAYB, XIO, RSVD, C, 6, F, 12, D, 12),
- PINGROUP(LD7, DISPLAYA, DISPLAYB, XIO, RSVD, C, 7, F, 14, D, 12),
- PINGROUP(LD8, DISPLAYA, DISPLAYB, XIO, RSVD, C, 8, F, 16, D, 12),
- PINGROUP(LD9, DISPLAYA, DISPLAYB, XIO, RSVD, C, 9, F, 18, D, 12),
- PINGROUP(LDC, DISPLAYA, DISPLAYB, RSVD, RSVD, C, 30, E, 14, D, 20),
- PINGROUP(LDI, DISPLAYA, DISPLAYB, RSVD, RSVD, D, 6, G, 16, D, 18),
- PINGROUP(LHP0, DISPLAYA, DISPLAYB, RSVD, RSVD, C, 18, G, 10, D, 16),
- PINGROUP(LHP1, DISPLAYA, DISPLAYB, RSVD, RSVD, C, 19, G, 4, D, 14),
- PINGROUP(LHP2, DISPLAYA, DISPLAYB, RSVD, RSVD, C, 20, G, 6, D, 14),
- PINGROUP(LHS, DISPLAYA, DISPLAYB, XIO, RSVD, D, 7, E, 22, D, 22),
- PINGROUP(LM0, DISPLAYA, DISPLAYB, SPI3, RSVD, C, 24, E, 26, D, 22),
- PINGROUP(LM1, DISPLAYA, DISPLAYB, RSVD, CRT, C, 25, E, 28, D, 22),
- PINGROUP(LPP, DISPLAYA, DISPLAYB, RSVD, RSVD, D, 8, G, 14, D, 18),
- PINGROUP(LPW0, DISPLAYA, DISPLAYB, SPI3, HDMI, D, 3, E, 0, D, 20),
- PINGROUP(LPW1, DISPLAYA, DISPLAYB, RSVD, RSVD, D, 4, E, 2, D, 20),
- PINGROUP(LPW2, DISPLAYA, DISPLAYB, SPI3, HDMI, D, 5, E, 4, D, 20),
- PINGROUP(LSC0, DISPLAYA, DISPLAYB, XIO, RSVD, C, 27, E, 18, D, 22),
- PINGROUP(LSC1, DISPLAYA, DISPLAYB, SPI3, HDMI, C, 28, E, 20, D, 20),
- PINGROUP(LSCK, DISPLAYA, DISPLAYB, SPI3, HDMI, C, 29, E, 16, D, 20),
- PINGROUP(LSDA, DISPLAYA, DISPLAYB, SPI3, HDMI, D, 1, E, 8, D, 20),
- PINGROUP(LSDI, DISPLAYA, DISPLAYB, SPI3, RSVD, D, 2, E, 6, D, 20),
- PINGROUP(LSPI, DISPLAYA, DISPLAYB, XIO, HDMI, D, 0, E, 10, D, 22),
- PINGROUP(LVP0, DISPLAYA, DISPLAYB, RSVD, RSVD, C, 21, E, 30, D, 22),
- PINGROUP(LVP1, DISPLAYA, DISPLAYB, RSVD, RSVD, C, 22, G, 8, D, 16),
- PINGROUP(LVS, DISPLAYA, DISPLAYB, XIO, RSVD, C, 26, E, 24, D, 22),
- PINGROUP(OWC, OWR, RSVD, RSVD, RSVD, A, 31, B, 8, E, 30),
- PINGROUP(PMC, PWR_ON, PWR_INTR, RSVD, RSVD, A, 23, G, 18, N, -1),
- PINGROUP(PTA, I2C2, HDMI, GMI, RSVD, A, 24, G, 22, B, 4),
- PINGROUP(RM, I2C, RSVD, RSVD, RSVD, A, 25, A, 14, B, 0),
- PINGROUP(SDB, UARTA, PWM, SDIO3, SPI2, D, 15, D, 10, N, -1),
- PINGROUP(SDC, PWM, TWC, SDIO3, SPI3, B, 1, D, 12, D, 28),
- PINGROUP(SDD, UARTA, PWM, SDIO3, SPI3, B, 2, D, 14, D, 30),
- PINGROUP(SDIO1, SDIO1, RSVD, UARTE, UARTA, A, 30, A, 30, E, 18),
- PINGROUP(SLXA, PCIE, SPI4, SDIO3, SPI2, B, 3, B, 6, B, 22),
- PINGROUP(SLXC, SPDIF, SPI4, SDIO3, SPI2, B, 5, B, 10, B, 26),
- PINGROUP(SLXD, SPDIF, SPI4, SDIO3, SPI2, B, 6, B, 12, B, 28),
- PINGROUP(SLXK, PCIE, SPI4, SDIO3, SPI2, B, 7, B, 14, B, 30),
- PINGROUP(SPDI, SPDIF, RSVD, I2C, SDIO2, B, 8, D, 8, B, 16),
- PINGROUP(SPDO, SPDIF, RSVD, I2C, SDIO2, B, 9, D, 6, B, 18),
- PINGROUP(SPIA, SPI1, SPI2, SPI3, GMI, B, 10, D, 30, C, 4),
- PINGROUP(SPIB, SPI1, SPI2, SPI3, GMI, B, 11, D, 28, C, 6),
- PINGROUP(SPIC, SPI1, SPI2, SPI3, GMI, B, 12, D, 26, C, 8),
- PINGROUP(SPID, SPI2, SPI1, SPI2_ALT, GMI, B, 13, D, 24, C, 10),
- PINGROUP(SPIE, SPI2, SPI1, SPI2_ALT, GMI, B, 14, D, 22, C, 12),
- PINGROUP(SPIF, SPI3, SPI1, SPI2, RSVD, B, 15, D, 20, C, 14),
- PINGROUP(SPIG, SPI3, SPI2, SPI2_ALT, I2C, B, 16, D, 18, C, 16),
- PINGROUP(SPIH, SPI3, SPI2, SPI2_ALT, I2C, B, 17, D, 16, C, 18),
- PINGROUP(UAA, SPI3, MIPI_HS, UARTA, ULPI, B, 18, A, 0, D, 0),
- PINGROUP(UAB, SPI2, MIPI_HS, UARTA, ULPI, B, 19, A, 2, D, 2),
- PINGROUP(UAC, OWR, RSVD, RSVD, RSVD, B, 20, A, 4, D, 4),
- PINGROUP(UAD, IRDA, SPDIF, UARTA, SPI4, B, 21, A, 6, D, 6),
- PINGROUP(UCA, UARTC, RSVD, GMI, RSVD, B, 22, B, 16, D, 8),
- PINGROUP(UCB, UARTC, PWM, GMI, RSVD, B, 23, B, 18, D, 10),
- PINGROUP(UDA, SPI1, RSVD, UARTD, ULPI, D, 13, A, 8, E, 16),
- /* these pin groups only have pullup and pull down control */
- PINGROUP(CK32, RSVD, RSVD, RSVD, RSVD, N, -1, N, -1, E, 14),
- PINGROUP(DDRC, RSVD, RSVD, RSVD, RSVD, N, -1, N, -1, D, 26),
- PINGROUP(PMCA, RSVD, RSVD, RSVD, RSVD, N, -1, N, -1, E, 4),
- PINGROUP(PMCB, RSVD, RSVD, RSVD, RSVD, N, -1, N, -1, E, 6),
- PINGROUP(PMCC, RSVD, RSVD, RSVD, RSVD, N, -1, N, -1, E, 8),
- PINGROUP(PMCD, RSVD, RSVD, RSVD, RSVD, N, -1, N, -1, E, 10),
- PINGROUP(PMCE, RSVD, RSVD, RSVD, RSVD, N, -1, N, -1, E, 12),
- PINGROUP(XM2C, RSVD, RSVD, RSVD, RSVD, N, -1, N, -1, C, 30),
- PINGROUP(XM2D, RSVD, RSVD, RSVD, RSVD, N, -1, N, -1, C, 28),
-};
+static const struct tegra_pingroup_desc *const pingroups = tegra_soc_pingroups;
+static const struct tegra_drive_pingroup_desc *const drive_pingroups = tegra_soc_drive_pingroups;
static char *tegra_mux_names[TEGRA_MAX_MUX] = {
[TEGRA_MUX_AHB_CLK] = "AHB_CLK",
@@ -256,48 +96,7 @@ static char *tegra_mux_names[TEGRA_MAX_MUX] = {
[TEGRA_MUX_VI] = "VI",
[TEGRA_MUX_VI_SENSOR_CLK] = "VI_SENSOR_CLK",
[TEGRA_MUX_XIO] = "XIO",
-};
-
-struct tegra_drive_pingroup_desc {
- const char *name;
- s16 reg;
-};
-
-#define DRIVE_PINGROUP(pg_name, r) \
- [TEGRA_DRIVE_PINGROUP_ ## pg_name] = { \
- .name = #pg_name, \
- .reg = r \
- }
-
-static const struct tegra_drive_pingroup_desc drive_pingroups[TEGRA_MAX_PINGROUP] = {
- DRIVE_PINGROUP(AO1, 0x868),
- DRIVE_PINGROUP(AO2, 0x86c),
- DRIVE_PINGROUP(AT1, 0x870),
- DRIVE_PINGROUP(AT2, 0x874),
- DRIVE_PINGROUP(CDEV1, 0x878),
- DRIVE_PINGROUP(CDEV2, 0x87c),
- DRIVE_PINGROUP(CSUS, 0x880),
- DRIVE_PINGROUP(DAP1, 0x884),
- DRIVE_PINGROUP(DAP2, 0x888),
- DRIVE_PINGROUP(DAP3, 0x88c),
- DRIVE_PINGROUP(DAP4, 0x890),
- DRIVE_PINGROUP(DBG, 0x894),
- DRIVE_PINGROUP(LCD1, 0x898),
- DRIVE_PINGROUP(LCD2, 0x89c),
- DRIVE_PINGROUP(SDMMC2, 0x8a0),
- DRIVE_PINGROUP(SDMMC3, 0x8a4),
- DRIVE_PINGROUP(SPI, 0x8a8),
- DRIVE_PINGROUP(UAA, 0x8ac),
- DRIVE_PINGROUP(UAB, 0x8b0),
- DRIVE_PINGROUP(UART2, 0x8b4),
- DRIVE_PINGROUP(UART3, 0x8b8),
- DRIVE_PINGROUP(VI1, 0x8bc),
- DRIVE_PINGROUP(VI2, 0x8c0),
- DRIVE_PINGROUP(XM2A, 0x8c4),
- DRIVE_PINGROUP(XM2C, 0x8c8),
- DRIVE_PINGROUP(XM2D, 0x8cc),
- DRIVE_PINGROUP(XM2CLK, 0x8d0),
- DRIVE_PINGROUP(MEMCOMP, 0x8d4),
+ [TEGRA_MUX_SAFE] = "<safe>",
};
static const char *tegra_drive_names[TEGRA_MAX_DRIVE] = {
@@ -381,22 +180,27 @@ static inline void pg_writel(unsigned long value, unsigned long offset)
writel(value, IO_TO_VIRT(TEGRA_APB_MISC_BASE + offset));
}
-int tegra_pinmux_set_func(enum tegra_pingroup pg, enum tegra_mux_func func)
+static int tegra_pinmux_set_func(const struct tegra_pingroup_config *config)
{
int mux = -1;
int i;
unsigned long reg;
unsigned long flags;
+ enum tegra_pingroup pg = config->pingroup;
+ enum tegra_mux_func func = config->func;
if (pg < 0 || pg >= TEGRA_MAX_PINGROUP)
return -ERANGE;
- if (pingroups[pg].mux_reg == REG_N)
+ if (pingroups[pg].mux_reg < 0)
return -EINVAL;
if (func < 0)
return -ERANGE;
+ if (func == TEGRA_MUX_SAFE)
+ func = pingroups[pg].func_safe;
+
if (func & TEGRA_MUX_RSVD) {
mux = func & 0x3;
} else {
@@ -413,10 +217,10 @@ int tegra_pinmux_set_func(enum tegra_pingroup pg, enum tegra_mux_func func)
spin_lock_irqsave(&mux_lock, flags);
- reg = pg_readl(TEGRA_PP_MUX_CTL(pingroups[pg].mux_reg));
+ reg = pg_readl(pingroups[pg].mux_reg);
reg &= ~(0x3 << pingroups[pg].mux_bit);
reg |= mux << pingroups[pg].mux_bit;
- pg_writel(reg, TEGRA_PP_MUX_CTL(pingroups[pg].mux_reg));
+ pg_writel(reg, pingroups[pg].mux_reg);
spin_unlock_irqrestore(&mux_lock, flags);
@@ -432,16 +236,16 @@ int tegra_pinmux_set_tristate(enum tegra_pingroup pg,
if (pg < 0 || pg >= TEGRA_MAX_PINGROUP)
return -ERANGE;
- if (pingroups[pg].tri_reg == REG_N)
+ if (pingroups[pg].tri_reg < 0)
return -EINVAL;
spin_lock_irqsave(&mux_lock, flags);
- reg = pg_readl(TEGRA_TRI_STATE(pingroups[pg].tri_reg));
+ reg = pg_readl(pingroups[pg].tri_reg);
reg &= ~(0x1 << pingroups[pg].tri_bit);
if (tristate)
reg |= 1 << pingroups[pg].tri_bit;
- pg_writel(reg, TEGRA_TRI_STATE(pingroups[pg].tri_reg));
+ pg_writel(reg, pingroups[pg].tri_reg);
spin_unlock_irqrestore(&mux_lock, flags);
@@ -457,7 +261,7 @@ int tegra_pinmux_set_pullupdown(enum tegra_pingroup pg,
if (pg < 0 || pg >= TEGRA_MAX_PINGROUP)
return -ERANGE;
- if (pingroups[pg].pupd_reg == REG_N)
+ if (pingroups[pg].pupd_reg < 0)
return -EINVAL;
if (pupd != TEGRA_PUPD_NORMAL &&
@@ -468,38 +272,39 @@ int tegra_pinmux_set_pullupdown(enum tegra_pingroup pg,
spin_lock_irqsave(&mux_lock, flags);
- reg = pg_readl(TEGRA_PP_PU_PD(pingroups[pg].pupd_reg));
+ reg = pg_readl(pingroups[pg].pupd_reg);
reg &= ~(0x3 << pingroups[pg].pupd_bit);
reg |= pupd << pingroups[pg].pupd_bit;
- pg_writel(reg, TEGRA_PP_PU_PD(pingroups[pg].pupd_reg));
+ pg_writel(reg, pingroups[pg].pupd_reg);
spin_unlock_irqrestore(&mux_lock, flags);
return 0;
}
-void tegra_pinmux_config_pingroup(enum tegra_pingroup pingroup,
- enum tegra_mux_func func,
- enum tegra_pullupdown pupd,
- enum tegra_tristate tristate)
+static void tegra_pinmux_config_pingroup(const struct tegra_pingroup_config *config)
{
+ enum tegra_pingroup pingroup = config->pingroup;
+ enum tegra_mux_func func = config->func;
+ enum tegra_pullupdown pupd = config->pupd;
+ enum tegra_tristate tristate = config->tristate;
int err;
- if (pingroups[pingroup].mux_reg != REG_N) {
- err = tegra_pinmux_set_func(pingroup, func);
+ if (pingroups[pingroup].mux_reg >= 0) {
+ err = tegra_pinmux_set_func(config);
if (err < 0)
pr_err("pinmux: can't set pingroup %s func to %s: %d\n",
pingroup_name(pingroup), func_name(func), err);
}
- if (pingroups[pingroup].pupd_reg != REG_N) {
+ if (pingroups[pingroup].pupd_reg >= 0) {
err = tegra_pinmux_set_pullupdown(pingroup, pupd);
if (err < 0)
pr_err("pinmux: can't set pingroup %s pullupdown to %s: %d\n",
pingroup_name(pingroup), pupd_name(pupd), err);
}
- if (pingroups[pingroup].tri_reg != REG_N) {
+ if (pingroups[pingroup].tri_reg >= 0) {
err = tegra_pinmux_set_tristate(pingroup, tristate);
if (err < 0)
pr_err("pinmux: can't set pingroup %s tristate to %s: %d\n",
@@ -507,17 +312,12 @@ void tegra_pinmux_config_pingroup(enum tegra_pingroup pingroup,
}
}
-
-
-void tegra_pinmux_config_table(struct tegra_pingroup_config *config, int len)
+void tegra_pinmux_config_table(const struct tegra_pingroup_config *config, int len)
{
int i;
for (i = 0; i < len; i++)
- tegra_pinmux_config_pingroup(config[i].pingroup,
- config[i].func,
- config[i].pupd,
- config[i].tristate);
+ tegra_pinmux_config_pingroup(&config[i]);
}
static const char *drive_pinmux_name(enum tegra_drive_pingroup pg)
@@ -784,6 +584,86 @@ void tegra_drive_pinmux_config_table(struct tegra_drive_pingroup_config *config,
config[i].slew_falling);
}
+void tegra_pinmux_set_safe_pinmux_table(const struct tegra_pingroup_config *config,
+ int len)
+{
+ int i;
+ struct tegra_pingroup_config c;
+
+ for (i = 0; i < len; i++) {
+ int err;
+ c = config[i];
+ if (c.pingroup < 0 || c.pingroup >= TEGRA_MAX_PINGROUP) {
+ WARN_ON(1);
+ continue;
+ }
+ c.func = pingroups[c.pingroup].func_safe;
+ err = tegra_pinmux_set_func(&c);
+ if (err < 0)
+ pr_err("%s: tegra_pinmux_set_func returned %d setting "
+ "%s to %s\n", __func__, err,
+ pingroup_name(c.pingroup), func_name(c.func));
+ }
+}
+
+void tegra_pinmux_config_pinmux_table(const struct tegra_pingroup_config *config,
+ int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ int err;
+ if (config[i].pingroup < 0 ||
+ config[i].pingroup >= TEGRA_MAX_PINGROUP) {
+ WARN_ON(1);
+ continue;
+ }
+ err = tegra_pinmux_set_func(&config[i]);
+ if (err < 0)
+ pr_err("%s: tegra_pinmux_set_func returned %d setting "
+ "%s to %s\n", __func__, err,
+ pingroup_name(config[i].pingroup),
+ func_name(config[i].func));
+ }
+}
+
+void tegra_pinmux_config_tristate_table(const struct tegra_pingroup_config *config,
+ int len, enum tegra_tristate tristate)
+{
+ int i;
+ int err;
+ enum tegra_pingroup pingroup;
+
+ for (i = 0; i < len; i++) {
+ pingroup = config[i].pingroup;
+ if (pingroups[pingroup].tri_reg >= 0) {
+ err = tegra_pinmux_set_tristate(pingroup, tristate);
+ if (err < 0)
+ pr_err("pinmux: can't set pingroup %s tristate"
+ " to %s: %d\n", pingroup_name(pingroup),
+ tri_name(tristate), err);
+ }
+ }
+}
+
+void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *config,
+ int len, enum tegra_pullupdown pupd)
+{
+ int i;
+ int err;
+ enum tegra_pingroup pingroup;
+
+ for (i = 0; i < len; i++) {
+ pingroup = config[i].pingroup;
+ if (pingroups[pingroup].pupd_reg >= 0) {
+ err = tegra_pinmux_set_pullupdown(pingroup, pupd);
+ if (err < 0)
+ pr_err("pinmux: can't set pingroup %s pullupdown"
+ " to %s: %d\n", pingroup_name(pingroup),
+ pupd_name(pupd), err);
+ }
+ }
+}
#ifdef CONFIG_DEBUG_FS
@@ -812,11 +692,11 @@ static int dbg_pinmux_show(struct seq_file *s, void *unused)
len = strlen(pingroups[i].name);
dbg_pad_field(s, 5 - len);
- if (pingroups[i].mux_reg == REG_N) {
+ if (pingroups[i].mux_reg < 0) {
seq_printf(s, "TEGRA_MUX_NONE");
len = strlen("NONE");
} else {
- mux = (pg_readl(TEGRA_PP_MUX_CTL(pingroups[i].mux_reg)) >>
+ mux = (pg_readl(pingroups[i].mux_reg) >>
pingroups[i].mux_bit) & 0x3;
if (pingroups[i].funcs[mux] == TEGRA_MUX_RSVD) {
seq_printf(s, "TEGRA_MUX_RSVD%1lu", mux+1);
@@ -829,21 +709,21 @@ static int dbg_pinmux_show(struct seq_file *s, void *unused)
}
dbg_pad_field(s, 13-len);
- if (pingroups[i].mux_reg == REG_N) {
+ if (pingroups[i].pupd_reg < 0) {
seq_printf(s, "TEGRA_PUPD_NORMAL");
len = strlen("NORMAL");
} else {
- pupd = (pg_readl(TEGRA_PP_PU_PD(pingroups[i].pupd_reg)) >>
+ pupd = (pg_readl(pingroups[i].pupd_reg) >>
pingroups[i].pupd_bit) & 0x3;
seq_printf(s, "TEGRA_PUPD_%s", pupd_name(pupd));
len = strlen(pupd_name(pupd));
}
dbg_pad_field(s, 9 - len);
- if (pingroups[i].tri_reg == REG_N) {
+ if (pingroups[i].tri_reg < 0) {
seq_printf(s, "TEGRA_TRI_NORMAL");
} else {
- tri = (pg_readl(TEGRA_TRI_STATE(pingroups[i].tri_reg)) >>
+ tri = (pg_readl(pingroups[i].tri_reg) >>
pingroups[i].tri_bit) & 0x1;
seq_printf(s, "TEGRA_TRI_%s", tri_name(tri));
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 426163231fff..ae3b308e22a4 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -30,14 +30,21 @@
#include <mach/iomap.h>
#include "clock.h"
+#include "fuse.h"
+#include "tegra2_dvfs.h"
#define RST_DEVICES 0x004
#define RST_DEVICES_SET 0x300
#define RST_DEVICES_CLR 0x304
+#define RST_DEVICES_NUM 3
#define CLK_OUT_ENB 0x010
#define CLK_OUT_ENB_SET 0x320
#define CLK_OUT_ENB_CLR 0x324
+#define CLK_OUT_ENB_NUM 3
+
+#define CLK_MASK_ARM 0x44
+#define MISC_CLK_ENB 0x48
#define OSC_CTRL 0x50
#define OSC_CTRL_OSC_FREQ_MASK (3<<30)
@@ -45,6 +52,7 @@
#define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30)
#define OSC_CTRL_OSC_FREQ_12MHZ (2<<30)
#define OSC_CTRL_OSC_FREQ_26MHZ (3<<30)
+#define OSC_CTRL_MASK 0x3f2
#define OSC_FREQ_DET 0x58
#define OSC_FREQ_DET_TRIG (1<<31)
@@ -53,10 +61,17 @@
#define OSC_FREQ_DET_BUSY (1<<31)
#define OSC_FREQ_DET_CNT_MASK 0xFFFF
+#define PERIPH_CLK_SOURCE_I2S1 0x100
+#define PERIPH_CLK_SOURCE_EMC 0x19c
+#define PERIPH_CLK_SOURCE_OSC 0x1fc
+#define PERIPH_CLK_SOURCE_NUM \
+ ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
+
#define PERIPH_CLK_SOURCE_MASK (3<<30)
#define PERIPH_CLK_SOURCE_SHIFT 30
#define PERIPH_CLK_SOURCE_ENABLE (1<<28)
-#define PERIPH_CLK_SOURCE_DIV_MASK 0xFF
+#define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF
+#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF
#define PERIPH_CLK_SOURCE_DIV_SHIFT 0
#define PLL_BASE 0x0
@@ -79,8 +94,9 @@
#define PLL_OUT_RESET_DISABLE (1<<0)
#define PLL_MISC(c) (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
+#define PLL_MISC_LOCK_ENABLE(c) (((c)->flags & PLLU) ? (1<<22) : (1<<18))
+
#define PLL_MISC_DCCON_SHIFT 20
-#define PLL_MISC_LOCK_ENABLE (1<<18)
#define PLL_MISC_CPCON_SHIFT 8
#define PLL_MISC_CPCON_MASK (0xF<<PLL_MISC_CPCON_SHIFT)
#define PLL_MISC_LFCON_SHIFT 4
@@ -88,10 +104,14 @@
#define PLL_MISC_VCOCON_SHIFT 0
#define PLL_MISC_VCOCON_MASK (0xF<<PLL_MISC_VCOCON_SHIFT)
+#define PLLU_BASE_POST_DIV (1<<20)
+
#define PLLD_MISC_CLKENABLE (1<<30)
#define PLLD_MISC_DIV_RST (1<<23)
#define PLLD_MISC_DCCON_SHIFT 12
+#define PLLE_MISC_READY (1 << 15)
+
#define PERIPH_CLK_TO_ENB_REG(c) ((c->clk_num / 32) * 4)
#define PERIPH_CLK_TO_ENB_SET_REG(c) ((c->clk_num / 32) * 8)
#define PERIPH_CLK_TO_ENB_BIT(c) (1 << (c->clk_num % 32))
@@ -143,30 +163,37 @@ unsigned long clk_measure_input_freq(void)
}
}
-static int clk_div71_get_divider(struct clk *c, unsigned long rate)
+static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate)
{
- unsigned long divider_u71;
+ s64 divider_u71 = parent_rate * 2;
+ divider_u71 += rate - 1;
+ do_div(divider_u71, rate);
- divider_u71 = DIV_ROUND_UP(c->rate * 2, rate);
+ if (divider_u71 - 2 < 0)
+ return 0;
- if (divider_u71 - 2 > 255 || divider_u71 - 2 < 0)
+ if (divider_u71 - 2 > 255)
return -EINVAL;
return divider_u71 - 2;
}
-static unsigned long tegra2_clk_recalculate_rate(struct clk *c)
+static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
{
- unsigned long rate;
- rate = c->parent->rate;
+ s64 divider_u16;
- if (c->mul != 0 && c->div != 0)
- c->rate = rate * c->mul / c->div;
- else
- c->rate = rate;
- return c->rate;
-}
+ divider_u16 = parent_rate;
+ divider_u16 += rate - 1;
+ do_div(divider_u16, rate);
+
+ if (divider_u16 - 1 < 0)
+ return 0;
+ if (divider_u16 - 1 > 255)
+ return -EINVAL;
+
+ return divider_u16 - 1;
+}
/* clk_m functions */
static unsigned long tegra2_clk_m_autodetect_rate(struct clk *c)
@@ -244,7 +271,6 @@ static void tegra2_super_clk_init(struct clk *c)
}
BUG_ON(sel->input == NULL);
c->parent = sel->input;
- tegra2_clk_recalculate_rate(c);
}
static int tegra2_super_clk_enable(struct clk *c)
@@ -266,6 +292,7 @@ static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)
u32 val;
const struct clk_mux_sel *sel;
int shift;
+
val = clk_readl(c->reg + SUPER_CLK_MUX);;
BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
@@ -273,11 +300,18 @@ static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)
SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
for (sel = c->inputs; sel->input != NULL; sel++) {
if (sel->input == p) {
- clk_reparent(c, p);
val &= ~(SUPER_SOURCE_MASK << shift);
val |= sel->value << shift;
+
+ if (c->refcnt)
+ clk_enable_locked(p);
+
clk_writel(val, c->reg);
- c->rate = c->parent->rate;
+
+ if (c->refcnt && c->parent)
+ clk_disable_locked(c->parent);
+
+ clk_reparent(c, p);
return 0;
}
}
@@ -289,7 +323,61 @@ static struct clk_ops tegra_super_ops = {
.enable = tegra2_super_clk_enable,
.disable = tegra2_super_clk_disable,
.set_parent = tegra2_super_clk_set_parent,
- .recalculate_rate = tegra2_clk_recalculate_rate,
+};
+
+/* virtual cpu clock functions */
+/* some clocks can not be stopped (cpu, memory bus) while the SoC is running.
+ To change the frequency of these clocks, the parent pll may need to be
+ reprogrammed, so the clock must be moved off the pll, the pll reprogrammed,
+ and then the clock moved back to the pll. To hide this sequence, a virtual
+ clock handles it.
+ */
+static void tegra2_cpu_clk_init(struct clk *c)
+{
+}
+
+static int tegra2_cpu_clk_enable(struct clk *c)
+{
+ return 0;
+}
+
+static void tegra2_cpu_clk_disable(struct clk *c)
+{
+ pr_debug("%s on clock %s\n", __func__, c->name);
+
+ /* oops - don't disable the CPU clock! */
+ BUG();
+}
+
+static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ int ret;
+ ret = clk_set_parent_locked(c->parent, c->backup);
+ if (ret) {
+ pr_err("Failed to switch cpu to clock %s\n", c->backup->name);
+ return ret;
+ }
+
+ ret = clk_set_rate_locked(c->main, rate);
+ if (ret) {
+ pr_err("Failed to change cpu pll to %lu\n", rate);
+ return ret;
+ }
+
+ ret = clk_set_parent_locked(c->parent, c->main);
+ if (ret) {
+ pr_err("Failed to switch cpu to clock %s\n", c->main->name);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct clk_ops tegra_cpu_ops = {
+ .init = tegra2_cpu_clk_init,
+ .enable = tegra2_cpu_clk_enable,
+ .disable = tegra2_cpu_clk_disable,
+ .set_rate = tegra2_cpu_clk_set_rate,
};
/* bus clock functions */
@@ -299,7 +387,6 @@ static void tegra2_bus_clk_init(struct clk *c)
c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON;
c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
c->mul = 1;
- tegra2_clk_recalculate_rate(c);
}
static int tegra2_bus_clk_enable(struct clk *c)
@@ -340,27 +427,15 @@ static struct clk_ops tegra_bus_ops = {
.enable = tegra2_bus_clk_enable,
.disable = tegra2_bus_clk_disable,
.set_rate = tegra2_bus_clk_set_rate,
- .recalculate_rate = tegra2_clk_recalculate_rate,
};
/* PLL Functions */
-static unsigned long tegra2_pll_clk_recalculate_rate(struct clk *c)
-{
- u64 rate;
- rate = c->parent->rate;
- rate *= c->n;
- do_div(rate, c->m);
- if (c->p == 2)
- rate >>= 1;
- c->rate = rate;
- return c->rate;
-}
-
static int tegra2_pll_clk_wait_for_lock(struct clk *c)
{
ktime_t before;
before = ktime_get();
+
while (!(clk_readl(c->reg + PLL_BASE) & PLL_BASE_LOCK)) {
if (ktime_us_delta(ktime_get(), before) > 5000) {
pr_err("Timed out waiting for lock bit on pll %s",
@@ -380,24 +455,19 @@ static void tegra2_pll_clk_init(struct clk *c)
if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
pr_warning("Clock %s has unknown fixed frequency\n", c->name);
- c->n = 1;
- c->m = 0;
- c->p = 1;
+ c->mul = 1;
+ c->div = 1;
} else if (val & PLL_BASE_BYPASS) {
- c->n = 1;
- c->m = 1;
- c->p = 1;
+ c->mul = 1;
+ c->div = 1;
} else {
- c->n = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
- c->m = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
- c->p = (val & PLL_BASE_DIVP_MASK) ? 2 : 1;
+ c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
+ c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
+ if (c->flags & PLLU)
+ c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
+ else
+ c->div *= (val & PLL_BASE_DIVP_MASK) ? 2 : 1;
}
-
- val = clk_readl(c->reg + PLL_MISC(c));
- if (c->flags & PLL_HAS_CPCON)
- c->cpcon = (val & PLL_MISC_CPCON_MASK) >> PLL_MISC_CPCON_SHIFT;
-
- tegra2_pll_clk_recalculate_rate(c);
}
static int tegra2_pll_clk_enable(struct clk *c)
@@ -411,7 +481,7 @@ static int tegra2_pll_clk_enable(struct clk *c)
clk_writel(val, c->reg + PLL_BASE);
val = clk_readl(c->reg + PLL_MISC(c));
- val |= PLL_MISC_LOCK_ENABLE;
+ val |= PLL_MISC_LOCK_ENABLE(c);
clk_writel(val, c->reg + PLL_MISC(c));
tegra2_pll_clk_wait_for_lock(c);
@@ -441,33 +511,36 @@ static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)
input_rate = c->parent->rate;
for (sel = c->pll_table; sel->input_rate != 0; sel++) {
if (sel->input_rate == input_rate && sel->output_rate == rate) {
- c->n = sel->n;
- c->m = sel->m;
- c->p = sel->p;
- c->cpcon = sel->cpcon;
+ c->mul = sel->n;
+ c->div = sel->m * sel->p;
val = clk_readl(c->reg + PLL_BASE);
if (c->flags & PLL_FIXED)
val |= PLL_BASE_OVERRIDE;
val &= ~(PLL_BASE_DIVP_MASK | PLL_BASE_DIVN_MASK |
PLL_BASE_DIVM_MASK);
- val |= (c->m << PLL_BASE_DIVM_SHIFT) |
- (c->n << PLL_BASE_DIVN_SHIFT);
- BUG_ON(c->p > 2);
- if (c->p == 2)
- val |= 1 << PLL_BASE_DIVP_SHIFT;
+ val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
+ (sel->n << PLL_BASE_DIVN_SHIFT);
+ BUG_ON(sel->p < 1 || sel->p > 2);
+ if (c->flags & PLLU) {
+ if (sel->p == 1)
+ val |= PLLU_BASE_POST_DIV;
+ } else {
+ if (sel->p == 2)
+ val |= 1 << PLL_BASE_DIVP_SHIFT;
+ }
clk_writel(val, c->reg + PLL_BASE);
if (c->flags & PLL_HAS_CPCON) {
- val = c->cpcon << PLL_MISC_CPCON_SHIFT;
- val |= PLL_MISC_LOCK_ENABLE;
+ val = clk_readl(c->reg + PLL_MISC(c));
+ val &= ~PLL_MISC_CPCON_MASK;
+ val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
clk_writel(val, c->reg + PLL_MISC(c));
}
if (c->state == ON)
tegra2_pll_clk_enable(c);
- c->rate = rate;
return 0;
}
}
@@ -479,7 +552,46 @@ static struct clk_ops tegra_pll_ops = {
.enable = tegra2_pll_clk_enable,
.disable = tegra2_pll_clk_disable,
.set_rate = tegra2_pll_clk_set_rate,
- .recalculate_rate = tegra2_pll_clk_recalculate_rate,
+};
+
+static void tegra2_pllx_clk_init(struct clk *c)
+{
+ tegra2_pll_clk_init(c);
+
+ if (tegra_sku_id() == 7)
+ c->max_rate = 750000000;
+}
+
+static struct clk_ops tegra_pllx_ops = {
+ .init = tegra2_pllx_clk_init,
+ .enable = tegra2_pll_clk_enable,
+ .disable = tegra2_pll_clk_disable,
+ .set_rate = tegra2_pll_clk_set_rate,
+};
+
+static int tegra2_plle_clk_enable(struct clk *c)
+{
+ u32 val;
+
+ pr_debug("%s on clock %s\n", __func__, c->name);
+
+ mdelay(1);
+
+ val = clk_readl(c->reg + PLL_BASE);
+ if (!(val & PLLE_MISC_READY))
+ return -EBUSY;
+
+ val = clk_readl(c->reg + PLL_BASE);
+ val |= PLL_BASE_ENABLE | PLL_BASE_BYPASS;
+ clk_writel(val, c->reg + PLL_BASE);
+
+ return 0;
+}
+
+static struct clk_ops tegra_plle_ops = {
+ .init = tegra2_pll_clk_init,
+ .enable = tegra2_plle_clk_enable,
+ .set_rate = tegra2_pll_clk_set_rate,
};
/* Clock divider ops */
@@ -503,8 +615,6 @@ static void tegra2_pll_div_clk_init(struct clk *c)
c->div = 1;
c->mul = 1;
}
-
- tegra2_clk_recalculate_rate(c);
}
static int tegra2_pll_div_clk_enable(struct clk *c)
@@ -565,7 +675,7 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
int divider_u71;
pr_debug("%s: %s %lu\n", __func__, c->name, rate);
if (c->flags & DIV_U71) {
- divider_u71 = clk_div71_get_divider(c->parent, rate);
+ divider_u71 = clk_div71_get_divider(c->parent->rate, rate);
if (divider_u71 >= 0) {
val = clk_readl(c->reg);
new_val = val >> c->reg_shift;
@@ -580,25 +690,37 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
clk_writel(val, c->reg);
c->div = divider_u71 + 2;
c->mul = 2;
- tegra2_clk_recalculate_rate(c);
return 0;
}
} else if (c->flags & DIV_2) {
- if (c->parent->rate == rate * 2) {
- c->rate = rate;
+ if (c->parent->rate == rate * 2)
return 0;
- }
}
return -EINVAL;
}
+static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
+{
+ int divider;
+ pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+ if (c->flags & DIV_U71) {
+ divider = clk_div71_get_divider(c->parent->rate, rate);
+ if (divider < 0)
+ return divider;
+ return c->parent->rate * 2 / (divider + 2);
+ } else if (c->flags & DIV_2) {
+ return c->parent->rate / 2;
+ }
+ return -EINVAL;
+}
static struct clk_ops tegra_pll_div_ops = {
.init = tegra2_pll_div_clk_init,
.enable = tegra2_pll_div_clk_enable,
.disable = tegra2_pll_div_clk_disable,
.set_rate = tegra2_pll_div_clk_set_rate,
- .recalculate_rate = tegra2_clk_recalculate_rate,
+ .round_rate = tegra2_pll_div_clk_round_rate,
};
/* Periph clk ops */
@@ -621,9 +743,13 @@ static void tegra2_periph_clk_init(struct clk *c)
}
if (c->flags & DIV_U71) {
- u32 divu71 = val & PERIPH_CLK_SOURCE_DIV_MASK;
+ u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
c->div = divu71 + 2;
c->mul = 2;
+ } else if (c->flags & DIV_U16) {
+ u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
+ c->div = divu16 + 1;
+ c->mul = 1;
} else {
c->div = 1;
c->mul = 1;
@@ -637,7 +763,6 @@ static void tegra2_periph_clk_init(struct clk *c)
if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) &
PERIPH_CLK_TO_ENB_BIT(c))
c->state = OFF;
- tegra2_clk_recalculate_rate(c);
}
static int tegra2_periph_clk_enable(struct clk *c)
@@ -692,12 +817,19 @@ static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p)
pr_debug("%s: %s %s\n", __func__, c->name, p->name);
for (sel = c->inputs; sel->input != NULL; sel++) {
if (sel->input == p) {
- clk_reparent(c, p);
val = clk_readl(c->reg);
val &= ~PERIPH_CLK_SOURCE_MASK;
val |= (sel->value) << PERIPH_CLK_SOURCE_SHIFT;
+
+ if (c->refcnt)
+ clk_enable_locked(p);
+
clk_writel(val, c->reg);
- c->rate = c->parent->rate;
+
+ if (c->refcnt && c->parent)
+ clk_disable_locked(c->parent);
+
+ clk_reparent(c, p);
return 0;
}
}
@@ -708,20 +840,55 @@ static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p)
static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate)
{
u32 val;
- int divider_u71;
+ int divider;
pr_debug("%s: %lu\n", __func__, rate);
if (c->flags & DIV_U71) {
- divider_u71 = clk_div71_get_divider(c->parent, rate);
- if (divider_u71 >= 0) {
+ divider = clk_div71_get_divider(c->parent->rate, rate);
+ if (divider >= 0) {
val = clk_readl(c->reg);
- val &= ~PERIPH_CLK_SOURCE_DIV_MASK;
- val |= divider_u71;
+ val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
+ val |= divider;
clk_writel(val, c->reg);
- c->div = divider_u71 + 2;
+ c->div = divider + 2;
c->mul = 2;
- tegra2_clk_recalculate_rate(c);
return 0;
}
+ } else if (c->flags & DIV_U16) {
+ divider = clk_div16_get_divider(c->parent->rate, rate);
+ if (divider >= 0) {
+ val = clk_readl(c->reg);
+ val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
+ val |= divider;
+ clk_writel(val, c->reg);
+ c->div = divider + 1;
+ c->mul = 1;
+ return 0;
+ }
+ } else if (c->parent->rate <= rate) {
+ c->div = 1;
+ c->mul = 1;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static long tegra2_periph_clk_round_rate(struct clk *c,
+ unsigned long rate)
+{
+ int divider;
+ pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+ if (c->flags & DIV_U71) {
+ divider = clk_div71_get_divider(c->parent->rate, rate);
+ if (divider < 0)
+ return divider;
+
+ return c->parent->rate * 2 / (divider + 2);
+ } else if (c->flags & DIV_U16) {
+ divider = clk_div16_get_divider(c->parent->rate, rate);
+ if (divider < 0)
+ return divider;
+ return c->parent->rate / (divider + 1);
}
return -EINVAL;
}
@@ -732,7 +899,7 @@ static struct clk_ops tegra_periph_clk_ops = {
.disable = &tegra2_periph_clk_disable,
.set_parent = &tegra2_periph_clk_set_parent,
.set_rate = &tegra2_periph_clk_set_rate,
- .recalculate_rate = &tegra2_clk_recalculate_rate,
+ .round_rate = &tegra2_periph_clk_round_rate,
};
/* Clock doubler ops */
@@ -744,21 +911,108 @@ static void tegra2_clk_double_init(struct clk *c)
if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
PERIPH_CLK_TO_ENB_BIT(c)))
c->state = OFF;
- tegra2_clk_recalculate_rate(c);
};
+static int tegra2_clk_double_set_rate(struct clk *c, unsigned long rate)
+{
+ if (rate != 2 * c->parent->rate)
+ return -EINVAL;
+ c->mul = 2;
+ c->div = 1;
+ return 0;
+}
+
static struct clk_ops tegra_clk_double_ops = {
.init = &tegra2_clk_double_init,
.enable = &tegra2_periph_clk_enable,
.disable = &tegra2_periph_clk_disable,
- .recalculate_rate = &tegra2_clk_recalculate_rate,
+ .set_rate = &tegra2_clk_double_set_rate,
+};
+
+static void tegra2_audio_sync_clk_init(struct clk *c)
+{
+ int source;
+ const struct clk_mux_sel *sel;
+ u32 val = clk_readl(c->reg);
+ c->state = (val & (1<<4)) ? OFF : ON;
+ source = val & 0xf;
+ for (sel = c->inputs; sel->input != NULL; sel++)
+ if (sel->value == source)
+ break;
+ BUG_ON(sel->input == NULL);
+ c->parent = sel->input;
+}
+
+static int tegra2_audio_sync_clk_enable(struct clk *c)
+{
+ clk_writel(0, c->reg);
+ return 0;
+}
+
+static void tegra2_audio_sync_clk_disable(struct clk *c)
+{
+ clk_writel(1, c->reg);
+}
+
+static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
+{
+ u32 val;
+ const struct clk_mux_sel *sel;
+ for (sel = c->inputs; sel->input != NULL; sel++) {
+ if (sel->input == p) {
+ val = clk_readl(c->reg);
+ val &= ~0xf;
+ val |= sel->value;
+
+ if (c->refcnt)
+ clk_enable_locked(p);
+
+ clk_writel(val, c->reg);
+
+ if (c->refcnt && c->parent)
+ clk_disable_locked(c->parent);
+
+ clk_reparent(c, p);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int tegra2_audio_sync_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ unsigned long parent_rate;
+ if (!c->parent) {
+ pr_err("%s: clock has no parent\n", __func__);
+ return -EINVAL;
+ }
+ parent_rate = c->parent->rate;
+ if (rate != parent_rate) {
+ pr_err("%s: %s/%ld differs from parent %s/%ld\n",
+ __func__,
+ c->name, rate,
+ c->parent->name, parent_rate);
+ return -EINVAL;
+ }
+ c->rate = parent_rate;
+ return 0;
+}
+
+static struct clk_ops tegra_audio_sync_clk_ops = {
+ .init = tegra2_audio_sync_clk_init,
+ .enable = tegra2_audio_sync_clk_enable,
+ .disable = tegra2_audio_sync_clk_disable,
+ .set_rate = tegra2_audio_sync_clk_set_rate,
+ .set_parent = tegra2_audio_sync_clk_set_parent,
};
/* Clock definitions */
static struct clk tegra_clk_32k = {
.name = "clk_32k",
- .rate = 32678,
+ .rate = 32768,
.ops = NULL,
+ .max_rate = 32768,
};
static struct clk_pll_table tegra_pll_s_table[] = {
@@ -782,6 +1036,7 @@ static struct clk tegra_pll_s = {
.vco_min = 12000000,
.vco_max = 26000000,
.pll_table = tegra_pll_s_table,
+ .max_rate = 26000000,
};
static struct clk_mux_sel tegra_clk_m_sel[] = {
@@ -797,6 +1052,7 @@ static struct clk tegra_clk_m = {
.reg = 0x1fc,
.reg_mask = (1<<28),
.reg_shift = 28,
+ .max_rate = 26000000,
};
static struct clk_pll_table tegra_pll_c_table[] = {
@@ -816,6 +1072,7 @@ static struct clk tegra_pll_c = {
.vco_min = 20000000,
.vco_max = 1400000000,
.pll_table = tegra_pll_c_table,
+ .max_rate = 600000000,
};
static struct clk tegra_pll_c_out1 = {
@@ -825,9 +1082,18 @@ static struct clk tegra_pll_c_out1 = {
.parent = &tegra_pll_c,
.reg = 0x84,
.reg_shift = 0,
+ .max_rate = 600000000,
};
static struct clk_pll_table tegra_pll_m_table[] = {
+ { 12000000, 666000000, 666, 12, 1, 8},
+ { 13000000, 666000000, 666, 13, 1, 8},
+ { 19200000, 666000000, 555, 16, 1, 8},
+ { 26000000, 666000000, 666, 26, 1, 8},
+ { 12000000, 600000000, 600, 12, 1, 8},
+ { 13000000, 600000000, 600, 13, 1, 8},
+ { 19200000, 600000000, 375, 12, 1, 6},
+ { 26000000, 600000000, 600, 26, 1, 8},
{ 0, 0, 0, 0, 0, 0 },
};
@@ -844,6 +1110,7 @@ static struct clk tegra_pll_m = {
.vco_min = 20000000,
.vco_max = 1200000000,
.pll_table = tegra_pll_m_table,
+ .max_rate = 800000000,
};
static struct clk tegra_pll_m_out1 = {
@@ -853,6 +1120,7 @@ static struct clk tegra_pll_m_out1 = {
.parent = &tegra_pll_m,
.reg = 0x94,
.reg_shift = 0,
+ .max_rate = 600000000,
};
static struct clk_pll_table tegra_pll_p_table[] = {
@@ -880,6 +1148,7 @@ static struct clk tegra_pll_p = {
.vco_min = 20000000,
.vco_max = 1400000000,
.pll_table = tegra_pll_p_table,
+ .max_rate = 432000000,
};
static struct clk tegra_pll_p_out1 = {
@@ -889,6 +1158,7 @@ static struct clk tegra_pll_p_out1 = {
.parent = &tegra_pll_p,
.reg = 0xa4,
.reg_shift = 0,
+ .max_rate = 432000000,
};
static struct clk tegra_pll_p_out2 = {
@@ -898,6 +1168,7 @@ static struct clk tegra_pll_p_out2 = {
.parent = &tegra_pll_p,
.reg = 0xa4,
.reg_shift = 16,
+ .max_rate = 432000000,
};
static struct clk tegra_pll_p_out3 = {
@@ -907,6 +1178,7 @@ static struct clk tegra_pll_p_out3 = {
.parent = &tegra_pll_p,
.reg = 0xa8,
.reg_shift = 0,
+ .max_rate = 432000000,
};
static struct clk tegra_pll_p_out4 = {
@@ -916,6 +1188,7 @@ static struct clk tegra_pll_p_out4 = {
.parent = &tegra_pll_p,
.reg = 0xa8,
.reg_shift = 16,
+ .max_rate = 432000000,
};
static struct clk_pll_table tegra_pll_a_table[] = {
@@ -923,6 +1196,7 @@ static struct clk_pll_table tegra_pll_a_table[] = {
{ 28800000, 73728000, 64, 25, 1, 1},
{ 28800000, 11289600, 49, 25, 1, 1},
{ 28800000, 12288000, 64, 25, 1, 1},
+ { 28800000, 24000000, 5, 6, 1, 1},
{ 0, 0, 0, 0, 0, 0 },
};
@@ -939,6 +1213,7 @@ static struct clk tegra_pll_a = {
.vco_min = 20000000,
.vco_max = 1400000000,
.pll_table = tegra_pll_a_table,
+ .max_rate = 56448000,
};
static struct clk tegra_pll_a_out0 = {
@@ -948,6 +1223,7 @@ static struct clk tegra_pll_a_out0 = {
.parent = &tegra_pll_a,
.reg = 0xb4,
.reg_shift = 0,
+ .max_rate = 56448000,
};
static struct clk_pll_table tegra_pll_d_table[] = {
@@ -971,6 +1247,7 @@ static struct clk tegra_pll_d = {
.vco_min = 40000000,
.vco_max = 1000000000,
.pll_table = tegra_pll_d_table,
+ .max_rate = 1000000000,
};
static struct clk tegra_pll_d_out0 = {
@@ -978,19 +1255,20 @@ static struct clk tegra_pll_d_out0 = {
.ops = &tegra_pll_div_ops,
.flags = DIV_2 | PLLD,
.parent = &tegra_pll_d,
+ .max_rate = 500000000,
};
static struct clk_pll_table tegra_pll_u_table[] = {
- { 12000000, 480000000, 960, 12, 1, 0},
- { 13000000, 480000000, 960, 13, 1, 0},
- { 19200000, 480000000, 200, 4, 1, 0},
- { 26000000, 480000000, 960, 26, 1, 0},
+ { 12000000, 480000000, 960, 12, 2, 0},
+ { 13000000, 480000000, 960, 13, 2, 0},
+ { 19200000, 480000000, 200, 4, 2, 0},
+ { 26000000, 480000000, 960, 26, 2, 0},
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_u = {
.name = "pll_u",
- .flags = 0,
+ .flags = PLLU,
.ops = &tegra_pll_ops,
.reg = 0xc0,
.input_min = 2000000,
@@ -1001,24 +1279,59 @@ static struct clk tegra_pll_u = {
.vco_min = 480000000,
.vco_max = 960000000,
.pll_table = tegra_pll_u_table,
+ .max_rate = 480000000,
};
static struct clk_pll_table tegra_pll_x_table[] = {
+ /* 1 GHz */
{ 12000000, 1000000000, 1000, 12, 1, 12},
{ 13000000, 1000000000, 1000, 13, 1, 12},
{ 19200000, 1000000000, 625, 12, 1, 8},
{ 26000000, 1000000000, 1000, 26, 1, 12},
- { 12000000, 750000000, 750, 12, 1, 12},
- { 13000000, 750000000, 750, 13, 1, 12},
- { 19200000, 750000000, 625, 16, 1, 8},
- { 26000000, 750000000, 750, 26, 1, 12},
+
+ /* 912 MHz */
+ { 12000000, 912000000, 912, 12, 1, 12},
+ { 13000000, 912000000, 912, 13, 1, 12},
+ { 19200000, 912000000, 760, 16, 1, 8},
+ { 26000000, 912000000, 912, 26, 1, 12},
+
+ /* 816 MHz */
+ { 12000000, 816000000, 816, 12, 1, 12},
+ { 13000000, 816000000, 816, 13, 1, 12},
+ { 19200000, 816000000, 680, 16, 1, 8},
+ { 26000000, 816000000, 816, 26, 1, 12},
+
+ /* 760 MHz */
+ { 12000000, 760000000, 760, 12, 1, 12},
+ { 13000000, 760000000, 760, 13, 1, 12},
+ { 19200000, 760000000, 950, 24, 1, 8},
+ { 26000000, 760000000, 760, 26, 1, 12},
+
+ /* 608 MHz */
+ { 12000000, 608000000, 760, 12, 1, 12},
+ { 13000000, 608000000, 760, 13, 1, 12},
+ { 19200000, 608000000, 380, 12, 1, 8},
+ { 26000000, 608000000, 760, 26, 1, 12},
+
+ /* 456 MHz */
+ { 12000000, 456000000, 456, 12, 1, 12},
+ { 13000000, 456000000, 456, 13, 1, 12},
+ { 19200000, 456000000, 380, 16, 1, 8},
+ { 26000000, 456000000, 456, 26, 1, 12},
+
+ /* 312 MHz */
+ { 12000000, 312000000, 312, 12, 1, 12},
+ { 13000000, 312000000, 312, 13, 1, 12},
+ { 19200000, 312000000, 260, 16, 1, 8},
+ { 26000000, 312000000, 312, 26, 1, 12},
+
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_x = {
.name = "pll_x",
.flags = PLL_HAS_CPCON | PLL_ALT_MISC_REG,
- .ops = &tegra_pll_ops,
+ .ops = &tegra_pllx_ops,
.reg = 0xe0,
.input_min = 2000000,
.input_max = 31000000,
@@ -1028,6 +1341,24 @@ static struct clk tegra_pll_x = {
.vco_min = 20000000,
.vco_max = 1200000000,
.pll_table = tegra_pll_x_table,
+ .max_rate = 1000000000,
+};
+
+static struct clk_pll_table tegra_pll_e_table[] = {
+ { 12000000, 100000000, 200, 24, 1, 0 },
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_e = {
+ .name = "pll_e",
+ .flags = PLL_ALT_MISC_REG,
+ .ops = &tegra_plle_ops,
+ .input_min = 12000000,
+ .input_max = 12000000,
+ .max_rate = 100000000,
+ .parent = &tegra_clk_m,
+ .reg = 0xe8,
+ .pll_table = tegra_pll_e_table,
};
static struct clk tegra_clk_d = {
@@ -1038,19 +1369,77 @@ static struct clk tegra_clk_d = {
.reg = 0x34,
.reg_shift = 12,
.parent = &tegra_clk_m,
+ .max_rate = 52000000,
+};
+
+/* initialized before peripheral clocks */
+static struct clk_mux_sel mux_audio_sync_clk[8+1];
+static const struct audio_sources {
+ const char *name;
+ int value;
+} mux_audio_sync_clk_sources[] = {
+ { .name = "spdif_in", .value = 0 },
+ { .name = "i2s1", .value = 1 },
+ { .name = "i2s2", .value = 2 },
+ { .name = "pll_a_out0", .value = 4 },
+#if 0 /* FIXME: not implemented */
+ { .name = "ac97", .value = 3 },
+ { .name = "ext_audio_clk2", .value = 5 },
+ { .name = "ext_audio_clk1", .value = 6 },
+ { .name = "ext_vimclk", .value = 7 },
+#endif
+ { 0, 0 }
+};
+
+static struct clk tegra_clk_audio = {
+ .name = "audio",
+ .inputs = mux_audio_sync_clk,
+ .reg = 0x38,
+ .max_rate = 24000000,
+ .ops = &tegra_audio_sync_clk_ops
};
-/* FIXME: need tegra_audio
static struct clk tegra_clk_audio_2x = {
- .name = "clk_d",
+ .name = "audio_2x",
.flags = PERIPH_NO_RESET,
+ .max_rate = 48000000,
.ops = &tegra_clk_double_ops,
.clk_num = 89,
.reg = 0x34,
.reg_shift = 8,
- .parent = &tegra_audio,
+ .parent = &tegra_clk_audio,
+};
+
+struct clk_lookup tegra_audio_clk_lookups[] = {
+ { .con_id = "audio", .clk = &tegra_clk_audio },
+ { .con_id = "audio_2x", .clk = &tegra_clk_audio_2x }
+};
+
+/* This is called after peripheral clocks are initialized, as the
+ * audio_sync clock depends on some of the peripheral clocks.
+ */
+
+static void init_audio_sync_clock_mux(void)
+{
+ int i;
+ struct clk_mux_sel *sel = mux_audio_sync_clk;
+ const struct audio_sources *src = mux_audio_sync_clk_sources;
+ struct clk_lookup *lookup;
+
+ for (i = 0; src->name; i++, sel++, src++) {
+ sel->input = tegra_get_clock_by_name(src->name);
+ if (!sel->input)
+ pr_err("%s: could not find clk %s\n", __func__,
+ src->name);
+ sel->value = src->value;
+ }
+
+ lookup = tegra_audio_clk_lookups;
+ for (i = 0; i < ARRAY_SIZE(tegra_audio_clk_lookups); i++, lookup++) {
+ clk_init(lookup->clk);
+ clkdev_add(lookup);
+ }
}
-*/
static struct clk_mux_sel mux_cclk[] = {
{ .input = &tegra_clk_m, .value = 0},
@@ -1077,27 +1466,40 @@ static struct clk_mux_sel mux_sclk[] = {
{ 0, 0},
};
-static struct clk tegra_clk_cpu = {
- .name = "cpu",
+static struct clk tegra_clk_cclk = {
+ .name = "cclk",
.inputs = mux_cclk,
.reg = 0x20,
.ops = &tegra_super_ops,
+ .max_rate = 1000000000,
};
-static struct clk tegra_clk_sys = {
- .name = "sys",
+static struct clk tegra_clk_sclk = {
+ .name = "sclk",
.inputs = mux_sclk,
.reg = 0x28,
.ops = &tegra_super_ops,
+ .max_rate = 600000000,
+};
+
+static struct clk tegra_clk_virtual_cpu = {
+ .name = "cpu",
+ .parent = &tegra_clk_cclk,
+ .main = &tegra_pll_x,
+ .backup = &tegra_clk_m,
+ .ops = &tegra_cpu_ops,
+ .max_rate = 1000000000,
+ .dvfs = &tegra_dvfs_virtual_cpu_dvfs,
};
static struct clk tegra_clk_hclk = {
.name = "hclk",
.flags = DIV_BUS,
- .parent = &tegra_clk_sys,
+ .parent = &tegra_clk_sclk,
.reg = 0x30,
.reg_shift = 4,
.ops = &tegra_bus_ops,
+ .max_rate = 240000000,
};
static struct clk tegra_clk_pclk = {
@@ -1107,6 +1509,7 @@ static struct clk tegra_clk_pclk = {
.reg = 0x30,
.reg_shift = 0,
.ops = &tegra_bus_ops,
+ .max_rate = 108000000,
};
static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
@@ -1133,10 +1536,9 @@ static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = {
{ 0, 0},
};
-static struct clk_mux_sel mux_plla_audio_pllp_clkm[] = {
- {.input = &tegra_pll_a, .value = 0},
- /* FIXME: no mux defined for tegra_audio
- {.input = &tegra_audio, .value = 1},*/
+static struct clk_mux_sel mux_pllaout0_audio2x_pllp_clkm[] = {
+ {.input = &tegra_pll_a_out0, .value = 0},
+ {.input = &tegra_clk_audio_2x, .value = 1},
{.input = &tegra_pll_p, .value = 2},
{.input = &tegra_clk_m, .value = 3},
{ 0, 0},
@@ -1153,8 +1555,7 @@ static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = {
static struct clk_mux_sel mux_pllp_pllc_audio_clkm_clk32[] = {
{.input = &tegra_pll_p, .value = 0},
{.input = &tegra_pll_c, .value = 1},
- /* FIXME: no mux defined for tegra_audio
- {.input = &tegra_audio, .value = 2},*/
+ {.input = &tegra_clk_audio, .value = 2},
{.input = &tegra_clk_m, .value = 3},
{.input = &tegra_clk_32k, .value = 4},
{ 0, 0},
@@ -1187,7 +1588,7 @@ static struct clk_mux_sel mux_clk_32k[] = {
{ 0, 0},
};
-#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _inputs, _flags) \
+#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
{ \
.name = _name, \
.lookup = { \
@@ -1199,72 +1600,79 @@ static struct clk_mux_sel mux_clk_32k[] = {
.reg = _reg, \
.inputs = _inputs, \
.flags = _flags, \
+ .max_rate = _max, \
}
struct clk tegra_periph_clks[] = {
- PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, mux_clk_32k, PERIPH_NO_RESET),
- PERIPH_CLK("timer", "timer", NULL, 5, 0, mux_clk_m, 0),
- PERIPH_CLK("i2s1", "i2s.0", NULL, 11, 0x100, mux_plla_audio_pllp_clkm, MUX | DIV_U71),
- PERIPH_CLK("i2s2", "i2s.1", NULL, 18, 0x104, mux_plla_audio_pllp_clkm, MUX | DIV_U71),
+ PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET),
+ PERIPH_CLK("timer", "timer", NULL, 5, 0, 26000000, mux_clk_m, 0),
+ PERIPH_CLK("i2s1", "i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
+ PERIPH_CLK("i2s2", "i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
/* FIXME: spdif has 2 clocks but 1 enable */
- PERIPH_CLK("spdif_out", "spdif_out", NULL, 10, 0x108, mux_plla_audio_pllp_clkm, MUX | DIV_U71),
- PERIPH_CLK("spdif_in", "spdif_in", NULL, 10, 0x10c, mux_pllp_pllc_pllm, MUX | DIV_U71),
- PERIPH_CLK("pwm", "pwm", NULL, 17, 0x110, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71),
- PERIPH_CLK("spi", "spi", NULL, 43, 0x114, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("xio", "xio", NULL, 45, 0x120, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("twc", "twc", NULL, 16, 0x12c, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sbc1", "spi_tegra.0", NULL, 41, 0x134, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sbc2", "spi_tegra.1", NULL, 44, 0x118, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sbc3", "spi_tegra.2", NULL, 46, 0x11c, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sbc4", "spi_tegra.3", NULL, 68, 0x1b4, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("ide", "ide", NULL, 25, 0x144, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("ndflash", "tegra_nand", NULL, 13, 0x160, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("spdif_out", "spdif_out", NULL, 10, 0x108, 100000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
+ PERIPH_CLK("spdif_in", "spdif_in", NULL, 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71),
+ PERIPH_CLK("pwm", "pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71),
+ PERIPH_CLK("spi", "spi", NULL, 43, 0x114, 40000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("xio", "xio", NULL, 45, 0x120, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("twc", "twc", NULL, 16, 0x12c, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("sbc1", "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("sbc2", "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("sbc3", "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("sbc4", "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("ide", "ide", NULL, 25, 0x144, 100000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* requires min voltage */
+ PERIPH_CLK("ndflash", "tegra_nand", NULL, 13, 0x160, 164000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
/* FIXME: vfir shares an enable with uartb */
- PERIPH_CLK("vfir", "vfir", NULL, 7, 0x168, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sdmmc1", "sdhci-tegra.0", NULL, 14, 0x150, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sdmmc2", "sdhci-tegra.1", NULL, 9, 0x154, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sdmmc3", "sdhci-tegra.2", NULL, 69, 0x1bc, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sdmmc4", "sdhci-tegra.3", NULL, 15, 0x160, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("vde", "vde", NULL, 61, 0x1c8, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("csite", "csite", NULL, 73, 0x1d4, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("vfir", "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("sdmmc1", "sdhci-tegra.0", NULL, 14, 0x150, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
+ PERIPH_CLK("sdmmc2", "sdhci-tegra.1", NULL, 9, 0x154, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
+ PERIPH_CLK("sdmmc3", "sdhci-tegra.2", NULL, 69, 0x1bc, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
+ PERIPH_CLK("sdmmc4", "sdhci-tegra.3", NULL, 15, 0x160, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
+ PERIPH_CLK("vde", "vde", NULL, 61, 0x1c8, 250000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage and process_id */
+ PERIPH_CLK("csite", "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* max rate ??? */
/* FIXME: what is la? */
- PERIPH_CLK("la", "la", NULL, 76, 0x1f8, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("owr", "owr", NULL, 71, 0x1cc, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("nor", "nor", NULL, 42, 0x1d0, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("mipi", "mipi", NULL, 50, 0x174, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("i2c1", "tegra-i2c.0", NULL, 12, 0x124, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("i2c2", "tegra-i2c.1", NULL, 54, 0x198, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("i2c3", "tegra-i2c.2", NULL, 67, 0x1b8, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("dvc", "tegra-i2c.3", NULL, 47, 0x128, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("i2c1_i2c", "tegra-i2c.0", "i2c", 0, 0, mux_pllp_out3, 0),
- PERIPH_CLK("i2c2_i2c", "tegra-i2c.1", "i2c", 0, 0, mux_pllp_out3, 0),
- PERIPH_CLK("i2c3_i2c", "tegra-i2c.2", "i2c", 0, 0, mux_pllp_out3, 0),
- PERIPH_CLK("dvc_i2c", "tegra-i2c.3", "i2c", 0, 0, mux_pllp_out3, 0),
- PERIPH_CLK("uarta", "uart.0", NULL, 6, 0x178, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("uartb", "uart.1", NULL, 7, 0x17c, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("uartc", "uart.2", NULL, 55, 0x1a0, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("uartd", "uart.3", NULL, 65, 0x1c0, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("uarte", "uart.4", NULL, 66, 0x1c4, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("3d", "3d", NULL, 24, 0x158, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_MANUAL_RESET),
- PERIPH_CLK("2d", "2d", NULL, 21, 0x15c, mux_pllm_pllc_pllp_plla, MUX | DIV_U71),
+ PERIPH_CLK("la", "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("owr", "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("nor", "nor", NULL, 42, 0x1d0, 92000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* requires min voltage */
+ PERIPH_CLK("mipi", "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
+ PERIPH_CLK("i2c1", "tegra-i2c.0", NULL, 12, 0x124, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16),
+ PERIPH_CLK("i2c2", "tegra-i2c.1", NULL, 54, 0x198, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16),
+ PERIPH_CLK("i2c3", "tegra-i2c.2", NULL, 67, 0x1b8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16),
+ PERIPH_CLK("dvc", "tegra-i2c.3", NULL, 47, 0x128, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16),
+ PERIPH_CLK("i2c1_i2c", "tegra-i2c.0", "i2c", 0, 0, 72000000, mux_pllp_out3, 0),
+ PERIPH_CLK("i2c2_i2c", "tegra-i2c.1", "i2c", 0, 0, 72000000, mux_pllp_out3, 0),
+ PERIPH_CLK("i2c3_i2c", "tegra-i2c.2", "i2c", 0, 0, 72000000, mux_pllp_out3, 0),
+ PERIPH_CLK("dvc_i2c", "tegra-i2c.3", "i2c", 0, 0, 72000000, mux_pllp_out3, 0),
+ PERIPH_CLK("uarta", "uart.0", NULL, 6, 0x178, 216000000, mux_pllp_pllc_pllm_clkm, MUX),
+ PERIPH_CLK("uartb", "uart.1", NULL, 7, 0x17c, 216000000, mux_pllp_pllc_pllm_clkm, MUX),
+ PERIPH_CLK("uartc", "uart.2", NULL, 55, 0x1a0, 216000000, mux_pllp_pllc_pllm_clkm, MUX),
+ PERIPH_CLK("uartd", "uart.3", NULL, 65, 0x1c0, 216000000, mux_pllp_pllc_pllm_clkm, MUX),
+ PERIPH_CLK("uarte", "uart.4", NULL, 66, 0x1c4, 216000000, mux_pllp_pllc_pllm_clkm, MUX),
+ PERIPH_CLK("3d", "3d", NULL, 24, 0x158, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_MANUAL_RESET), /* scales with voltage and process_id */
+ PERIPH_CLK("2d", "2d", NULL, 21, 0x15c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
/* FIXME: vi and vi_sensor share an enable */
- PERIPH_CLK("vi", "vi", NULL, 20, 0x148, mux_pllm_pllc_pllp_plla, MUX | DIV_U71),
- PERIPH_CLK("vi_sensor", "vi_sensor", NULL, 20, 0x1a8, mux_pllm_pllc_pllp_plla, MUX | DIV_U71),
- PERIPH_CLK("epp", "epp", NULL, 19, 0x16c, mux_pllm_pllc_pllp_plla, MUX | DIV_U71),
- PERIPH_CLK("mpe", "mpe", NULL, 60, 0x170, mux_pllm_pllc_pllp_plla, MUX | DIV_U71),
- PERIPH_CLK("host1x", "host1x", NULL, 28, 0x180, mux_pllm_pllc_pllp_plla, MUX | DIV_U71),
+ PERIPH_CLK("vi", "vi", NULL, 20, 0x148, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
+ PERIPH_CLK("vi_sensor", "vi_sensor", NULL, 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET), /* scales with voltage and process_id */
+ PERIPH_CLK("epp", "epp", NULL, 19, 0x16c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
+ PERIPH_CLK("mpe", "mpe", NULL, 60, 0x170, 250000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
+ PERIPH_CLK("host1x", "host1x", NULL, 28, 0x180, 166000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
/* FIXME: cve and tvo share an enable */
- PERIPH_CLK("cve", "cve", NULL, 49, 0x140, mux_pllp_plld_pllc_clkm, MUX | DIV_U71),
- PERIPH_CLK("tvo", "tvo", NULL, 49, 0x188, mux_pllp_plld_pllc_clkm, MUX | DIV_U71),
- PERIPH_CLK("hdmi", "hdmi", NULL, 51, 0x18c, mux_pllp_plld_pllc_clkm, MUX | DIV_U71),
- PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, mux_pllp_plld_pllc_clkm, MUX | DIV_U71),
- PERIPH_CLK("disp1", "tegrafb.0", NULL, 27, 0x138, mux_pllp_plld_pllc_clkm, MUX | DIV_U71),
- PERIPH_CLK("disp2", "tegrafb.1", NULL, 26, 0x13c, mux_pllp_plld_pllc_clkm, MUX | DIV_U71),
- PERIPH_CLK("usbd", "fsl-tegra-udc", NULL, 22, 0, mux_clk_m, 0),
- PERIPH_CLK("usb2", "usb.1", NULL, 58, 0, mux_clk_m, 0),
- PERIPH_CLK("usb3", "usb.2", NULL, 59, 0, mux_clk_m, 0),
- PERIPH_CLK("emc", "emc", NULL, 57, 0x19c, mux_pllm_pllc_pllp_clkm, MUX | DIV_U71 | PERIPH_EMC_ENB),
- PERIPH_CLK("dsi", "dsi", NULL, 48, 0, mux_plld, 0),
+ PERIPH_CLK("cve", "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
+ PERIPH_CLK("tvo", "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
+ PERIPH_CLK("hdmi", "hdmi", NULL, 51, 0x18c, 148500000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
+ PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
+ PERIPH_CLK("disp1", "tegrafb.0", NULL, 27, 0x138, 190000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* scales with voltage and process_id */
+ PERIPH_CLK("disp2", "tegrafb.1", NULL, 26, 0x13c, 190000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* scales with voltage and process_id */
+ PERIPH_CLK("usbd", "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
+ PERIPH_CLK("usb2", "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
+ PERIPH_CLK("usb3", "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
+ PERIPH_CLK("emc", "emc", NULL, 57, 0x19c, 800000000, mux_pllm_pllc_pllp_clkm, MUX | DIV_U71 | PERIPH_EMC_ENB),
+ PERIPH_CLK("dsi", "dsi", NULL, 48, 0, 500000000, mux_plld, 0), /* scales with voltage */
+ PERIPH_CLK("csi", "csi", NULL, 52, 0, 72000000, mux_pllp_out3, 0),
+ PERIPH_CLK("isp", "isp", NULL, 23, 0, 150000000, mux_clk_m, 0), /* same frequency as VI */
+ PERIPH_CLK("csus", "csus", NULL, 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET),
+ PERIPH_CLK("pex", NULL, "pex", 70, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET),
+ PERIPH_CLK("afi", NULL, "afi", 72, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET),
+ PERIPH_CLK("pcie_xclk", NULL, "pcie_xclk", 74, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET),
};
#define CLK_DUPLICATE(_name, _dev, _con) \
@@ -1286,6 +1694,9 @@ struct clk_duplicate tegra_clk_duplicates[] = {
CLK_DUPLICATE("uartc", "tegra_uart.2", NULL),
CLK_DUPLICATE("uartd", "tegra_uart.3", NULL),
CLK_DUPLICATE("uarte", "tegra_uart.4", NULL),
+ CLK_DUPLICATE("host1x", "tegrafb.0", "host1x"),
+ CLK_DUPLICATE("host1x", "tegrafb.1", "host1x"),
+ CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
};
#define CLK(dev, con, ck) \
@@ -1315,11 +1726,13 @@ struct clk_lookup tegra_clk_lookups[] = {
CLK(NULL, "pll_d_out0", &tegra_pll_d_out0),
CLK(NULL, "pll_u", &tegra_pll_u),
CLK(NULL, "pll_x", &tegra_pll_x),
- CLK(NULL, "cpu", &tegra_clk_cpu),
- CLK(NULL, "sys", &tegra_clk_sys),
+ CLK(NULL, "pll_e", &tegra_pll_e),
+ CLK(NULL, "cclk", &tegra_clk_cclk),
+ CLK(NULL, "sclk", &tegra_clk_sclk),
CLK(NULL, "hclk", &tegra_clk_hclk),
CLK(NULL, "pclk", &tegra_clk_pclk),
CLK(NULL, "clk_d", &tegra_clk_d),
+ CLK(NULL, "cpu", &tegra_clk_virtual_cpu),
};
void __init tegra2_init_clocks(void)
@@ -1356,4 +1769,75 @@ void __init tegra2_init_clocks(void)
cd->name);
}
}
+
+ init_audio_sync_clock_mux();
+}
+
+#ifdef CONFIG_PM
+static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM +
+ PERIPH_CLK_SOURCE_NUM + 3];
+
+void tegra_clk_suspend(void)
+{
+ unsigned long off, i;
+ u32 *ctx = clk_rst_suspend;
+
+ *ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK;
+
+ for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
+ off += 4) {
+ if (off == PERIPH_CLK_SOURCE_EMC)
+ continue;
+ *ctx++ = clk_readl(off);
+ }
+
+ off = RST_DEVICES;
+ for (i = 0; i < RST_DEVICES_NUM; i++, off += 4)
+ *ctx++ = clk_readl(off);
+
+ off = CLK_OUT_ENB;
+ for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4)
+ *ctx++ = clk_readl(off);
+
+ *ctx++ = clk_readl(MISC_CLK_ENB);
+ *ctx++ = clk_readl(CLK_MASK_ARM);
+}
+
+void tegra_clk_resume(void)
+{
+ unsigned long off, i;
+ const u32 *ctx = clk_rst_suspend;
+ u32 val;
+
+ val = clk_readl(OSC_CTRL) & ~OSC_CTRL_MASK;
+ val |= *ctx++;
+ clk_writel(val, OSC_CTRL);
+
+ /* enable all clocks before configuring clock sources */
+ clk_writel(0xbffffff9ul, CLK_OUT_ENB);
+ clk_writel(0xfefffff7ul, CLK_OUT_ENB + 4);
+ clk_writel(0x77f01bfful, CLK_OUT_ENB + 8);
+ wmb();
+
+ for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
+ off += 4) {
+ if (off == PERIPH_CLK_SOURCE_EMC)
+ continue;
+ clk_writel(*ctx++, off);
+ }
+ wmb();
+
+ off = RST_DEVICES;
+ for (i = 0; i < RST_DEVICES_NUM; i++, off += 4)
+ clk_writel(*ctx++, off);
+ wmb();
+
+ off = CLK_OUT_ENB;
+ for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4)
+ clk_writel(*ctx++, off);
+ wmb();
+
+ clk_writel(*ctx++, MISC_CLK_ENB);
+ clk_writel(*ctx++, CLK_MASK_ARM);
}
+#endif
diff --git a/arch/arm/mach-tegra/tegra2_dvfs.c b/arch/arm/mach-tegra/tegra2_dvfs.c
new file mode 100644
index 000000000000..5529c238dd77
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra2_dvfs.c
@@ -0,0 +1,86 @@
+/*
+ * arch/arm/mach-tegra/tegra2_dvfs.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ * Colin Cross <ccross@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/kernel.h>
+
+#include "clock.h"
+#include "tegra2_dvfs.h"
+
+static struct dvfs_table virtual_cpu_process_0[] = {
+ {314000000, 750},
+ {456000000, 825},
+ {608000000, 900},
+ {760000000, 975},
+ {817000000, 1000},
+ {912000000, 1050},
+ {1000000000, 1100},
+ {0, 0},
+};
+
+static struct dvfs_table virtual_cpu_process_1[] = {
+ {314000000, 750},
+ {456000000, 825},
+ {618000000, 900},
+ {770000000, 975},
+ {827000000, 1000},
+ {922000000, 1050},
+ {1000000000, 1100},
+ {0, 0},
+};
+
+static struct dvfs_table virtual_cpu_process_2[] = {
+ {494000000, 750},
+ {675000000, 825},
+ {817000000, 875},
+ {922000000, 925},
+ {1000000000, 975},
+ {0, 0},
+};
+
+static struct dvfs_table virtual_cpu_process_3[] = {
+ {730000000, 750},
+ {760000000, 775},
+ {845000000, 800},
+ {1000000000, 875},
+ {0, 0},
+};
+
+struct dvfs tegra_dvfs_virtual_cpu_dvfs = {
+ .reg_id = "vdd_cpu",
+ .process_id_table = {
+ {
+ .process_id = 0,
+ .table = virtual_cpu_process_0,
+ },
+ {
+ .process_id = 1,
+ .table = virtual_cpu_process_1,
+ },
+ {
+ .process_id = 2,
+ .table = virtual_cpu_process_2,
+ },
+ {
+ .process_id = 3,
+ .table = virtual_cpu_process_3,
+ },
+ },
+ .process_id_table_length = 4,
+ .cpu = 1,
+};
diff --git a/arch/arm/mach-tegra/tegra2_dvfs.h b/arch/arm/mach-tegra/tegra2_dvfs.h
new file mode 100644
index 000000000000..f8c1adba96a6
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra2_dvfs.h
@@ -0,0 +1,20 @@
+/*
+ * arch/arm/mach-tegra/tegra2_dvfs.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ * Colin Cross <ccross@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.
+ *
+ */
+
+extern struct dvfs tegra_dvfs_virtual_cpu_dvfs;
diff --git a/arch/arm/mach-tegra/timer.c b/arch/arm/mach-tegra/timer.c
index 2f420210d406..9057d6fd1d31 100644
--- a/arch/arm/mach-tegra/timer.c
+++ b/arch/arm/mach-tegra/timer.c
@@ -28,7 +28,6 @@
#include <linux/cnt32_to_63.h>
#include <asm/mach/time.h>
-#include <asm/mach/time.h>
#include <asm/localtimer.h>
#include <mach/iomap.h>
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index fcb587f825cc..cac83a694880 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -18,12 +18,14 @@
#include <linux/amba/pl022.h>
#include <linux/spi/spi.h>
#include <linux/mfd/ab8500.h>
+#include <linux/input/matrix_keypad.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <plat/pincfg.h>
#include <plat/i2c.h>
+#include <plat/ske.h>
#include <mach/hardware.h>
#include <mach/setup.h>
@@ -49,6 +51,24 @@ static pin_cfg_t mop500_pins[] = {
GPIO11_I2C2_SCL,
GPIO229_I2C3_SDA,
GPIO230_I2C3_SCL,
+
+ /* SKE keypad */
+ GPIO153_KP_I7,
+ GPIO154_KP_I6,
+ GPIO155_KP_I5,
+ GPIO156_KP_I4,
+ GPIO157_KP_O7,
+ GPIO158_KP_O6,
+ GPIO159_KP_O5,
+ GPIO160_KP_O4,
+ GPIO161_KP_I3,
+ GPIO162_KP_I2,
+ GPIO163_KP_I1,
+ GPIO164_KP_I0,
+ GPIO165_KP_O3,
+ GPIO166_KP_O2,
+ GPIO167_KP_O1,
+ GPIO168_KP_O0,
};
static void ab4500_spi_cs_control(u32 command)
@@ -148,12 +168,120 @@ static struct amba_device *amba_devs[] __initdata = {
&u8500_ssp0_device,
};
+static const unsigned int ux500_keymap[] = {
+ KEY(2, 5, KEY_END),
+ KEY(4, 1, KEY_POWER),
+ KEY(3, 5, KEY_VOLUMEDOWN),
+ KEY(1, 3, KEY_3),
+ KEY(5, 2, KEY_RIGHT),
+ KEY(5, 0, KEY_9),
+
+ KEY(0, 5, KEY_MENU),
+ KEY(7, 6, KEY_ENTER),
+ KEY(4, 5, KEY_0),
+ KEY(6, 7, KEY_2),
+ KEY(3, 4, KEY_UP),
+ KEY(3, 3, KEY_DOWN),
+
+ KEY(6, 4, KEY_SEND),
+ KEY(6, 2, KEY_BACK),
+ KEY(4, 2, KEY_VOLUMEUP),
+ KEY(5, 5, KEY_1),
+ KEY(4, 3, KEY_LEFT),
+ KEY(3, 2, KEY_7),
+};
+
+static const struct matrix_keymap_data ux500_keymap_data = {
+ .keymap = ux500_keymap,
+ .keymap_size = ARRAY_SIZE(ux500_keymap),
+};
+
+/*
+ * Nomadik SKE keypad
+ */
+#define ROW_PIN_I0 164
+#define ROW_PIN_I1 163
+#define ROW_PIN_I2 162
+#define ROW_PIN_I3 161
+#define ROW_PIN_I4 156
+#define ROW_PIN_I5 155
+#define ROW_PIN_I6 154
+#define ROW_PIN_I7 153
+#define COL_PIN_O0 168
+#define COL_PIN_O1 167
+#define COL_PIN_O2 166
+#define COL_PIN_O3 165
+#define COL_PIN_O4 160
+#define COL_PIN_O5 159
+#define COL_PIN_O6 158
+#define COL_PIN_O7 157
+
+#define SKE_KPD_MAX_ROWS 8
+#define SKE_KPD_MAX_COLS 8
+
+static int ske_kp_rows[] = {
+ ROW_PIN_I0, ROW_PIN_I1, ROW_PIN_I2, ROW_PIN_I3,
+ ROW_PIN_I4, ROW_PIN_I5, ROW_PIN_I6, ROW_PIN_I7,
+};
+
+/*
+ * ske_set_gpio_row: request and set gpio rows
+ */
+static int ske_set_gpio_row(int gpio)
+{
+ int ret;
+
+ ret = gpio_request(gpio, "ske-kp");
+ if (ret < 0) {
+ pr_err("ske_set_gpio_row: gpio request failed\n");
+ return ret;
+ }
+
+ ret = gpio_direction_output(gpio, 1);
+ if (ret < 0) {
+ pr_err("ske_set_gpio_row: gpio direction failed\n");
+ gpio_free(gpio);
+ }
+
+ return ret;
+}
+
+/*
+ * ske_kp_init - enable the gpio configuration
+ */
+static int ske_kp_init(void)
+{
+ int ret, i;
+
+ for (i = 0; i < SKE_KPD_MAX_ROWS; i++) {
+ ret = ske_set_gpio_row(ske_kp_rows[i]);
+ if (ret < 0) {
+ pr_err("ske_kp_init: failed init\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static struct ske_keypad_platform_data ske_keypad_board = {
+ .init = ske_kp_init,
+ .keymap_data = &ux500_keymap_data,
+ .no_autorepeat = true,
+ .krow = SKE_KPD_MAX_ROWS, /* 8x8 matrix */
+ .kcol = SKE_KPD_MAX_COLS,
+ .debounce_ms = 40, /* in millsecs */
+};
+
+
+
/* add any platform devices here - TODO */
static struct platform_device *platform_devs[] __initdata = {
&u8500_i2c0_device,
&ux500_i2c1_device,
&ux500_i2c2_device,
&ux500_i2c3_device,
+ &ux500_ske_keypad_device,
};
static void __init u8500_init_machine(void)
@@ -168,6 +296,7 @@ static void __init u8500_init_machine(void)
ux500_i2c1_device.dev.platform_data = &u8500_i2c1_data;
ux500_i2c2_device.dev.platform_data = &u8500_i2c2_data;
ux500_i2c3_device.dev.platform_data = &u8500_i2c3_data;
+ ux500_ske_keypad_device.dev.platform_data = &ske_keypad_board;
u8500_ssp0_device.dev.platform_data = &ssp0_platform_data;
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c
index d8ab7f184fe4..1675047daf20 100644
--- a/arch/arm/mach-ux500/clock.c
+++ b/arch/arm/mach-ux500/clock.c
@@ -477,6 +477,7 @@ static struct clk_lookup u8500_common_clks[] = {
CLK(sdi5, "sdi5", NULL),
CLK(uart2, "uart2", NULL),
CLK(ske, "ske", NULL),
+ CLK(ske, "nmk-ske-keypad", NULL),
CLK(sdi2, "sdi2", NULL),
CLK(i2c0, "nmk-i2c.0", NULL),
CLK(fsmc, "fsmc", NULL),
diff --git a/arch/arm/mach-ux500/devices-db8500.c b/arch/arm/mach-ux500/devices-db8500.c
index 40032fecbc16..4a94be3304b9 100644
--- a/arch/arm/mach-ux500/devices-db8500.c
+++ b/arch/arm/mach-ux500/devices-db8500.c
@@ -208,35 +208,25 @@ static struct resource dma40_resources[] = {
/* Default configuration for physcial memcpy */
struct stedma40_chan_cfg dma40_memcpy_conf_phy = {
- .channel_type = (STEDMA40_CHANNEL_IN_PHY_MODE |
- STEDMA40_LOW_PRIORITY_CHANNEL |
- STEDMA40_PCHAN_BASIC_MODE),
+ .mode = STEDMA40_MODE_PHYSICAL,
.dir = STEDMA40_MEM_TO_MEM,
- .src_info.endianess = STEDMA40_LITTLE_ENDIAN,
.src_info.data_width = STEDMA40_BYTE_WIDTH,
.src_info.psize = STEDMA40_PSIZE_PHY_1,
.src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
- .dst_info.endianess = STEDMA40_LITTLE_ENDIAN,
.dst_info.data_width = STEDMA40_BYTE_WIDTH,
.dst_info.psize = STEDMA40_PSIZE_PHY_1,
.dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
};
/* Default configuration for logical memcpy */
struct stedma40_chan_cfg dma40_memcpy_conf_log = {
- .channel_type = (STEDMA40_CHANNEL_IN_LOG_MODE |
- STEDMA40_LOW_PRIORITY_CHANNEL |
- STEDMA40_LCHAN_SRC_LOG_DST_LOG |
- STEDMA40_NO_TIM_FOR_LINK),
.dir = STEDMA40_MEM_TO_MEM,
- .src_info.endianess = STEDMA40_LITTLE_ENDIAN,
.src_info.data_width = STEDMA40_BYTE_WIDTH,
.src_info.psize = STEDMA40_PSIZE_LOG_1,
.src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
- .dst_info.endianess = STEDMA40_LITTLE_ENDIAN,
.dst_info.data_width = STEDMA40_BYTE_WIDTH,
.dst_info.psize = STEDMA40_PSIZE_LOG_1,
.dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
@@ -269,7 +259,6 @@ static struct stedma40_platform_data dma40_plat_data = {
.memcpy_len = ARRAY_SIZE(dma40_memcpy_event),
.memcpy_conf_phy = &dma40_memcpy_conf_phy,
.memcpy_conf_log = &dma40_memcpy_conf_log,
- .llis_per_log = 8,
.disabled_channels = {-1},
};
@@ -292,3 +281,23 @@ void dma40_u8500ed_fixup(void)
dma40_resources[1].start = U8500_DMA_LCPA_BASE_ED;
dma40_resources[1].end = U8500_DMA_LCPA_BASE_ED + 2 * SZ_1K - 1;
}
+
+struct resource keypad_resources[] = {
+ [0] = {
+ .start = U8500_SKE_BASE,
+ .end = U8500_SKE_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_DB8500_KB,
+ .end = IRQ_DB8500_KB,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ux500_ske_keypad_device = {
+ .name = "nmk-ske-keypad",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(keypad_resources),
+ .resource = keypad_resources,
+};
diff --git a/arch/arm/mach-ux500/include/mach/devices.h b/arch/arm/mach-ux500/include/mach/devices.h
index 33a120c2e82e..b91a4d1211a2 100644
--- a/arch/arm/mach-ux500/include/mach/devices.h
+++ b/arch/arm/mach-ux500/include/mach/devices.h
@@ -26,6 +26,7 @@ extern struct platform_device ux500_i2c3_device;
extern struct platform_device u8500_i2c0_device;
extern struct platform_device u8500_i2c4_device;
extern struct platform_device u8500_dma40_device;
+extern struct platform_device ux500_ske_keypad_device;
extern struct amba_device u8500_sdi0_device;
extern struct amba_device u8500_sdi1_device;
diff --git a/arch/arm/mach-ux500/pins-db8500.h b/arch/arm/mach-ux500/pins-db8500.h
index 66f8761cc823..f923764ee16c 100644
--- a/arch/arm/mach-ux500/pins-db8500.h
+++ b/arch/arm/mach-ux500/pins-db8500.h
@@ -459,82 +459,82 @@
#define GPIO152_KP_O9 PIN_CFG(152, ALT_C)
#define GPIO153_GPIO PIN_CFG(153, GPIO)
-#define GPIO153_KP_I7 PIN_CFG(153, ALT_A)
+#define GPIO153_KP_I7 PIN_CFG_PULL(153, ALT_A, DOWN)
#define GPIO153_LCD_D24 PIN_CFG(153, ALT_B)
#define GPIO153_U2_RXD PIN_CFG(153, ALT_C)
#define GPIO154_GPIO PIN_CFG(154, GPIO)
-#define GPIO154_KP_I6 PIN_CFG(154, ALT_A)
+#define GPIO154_KP_I6 PIN_CFG_PULL(154, ALT_A, DOWN)
#define GPIO154_LCD_D25 PIN_CFG(154, ALT_B)
#define GPIO154_U2_TXD PIN_CFG(154, ALT_C)
#define GPIO155_GPIO PIN_CFG(155, GPIO)
-#define GPIO155_KP_I5 PIN_CFG(155, ALT_A)
+#define GPIO155_KP_I5 PIN_CFG_PULL(155, ALT_A, DOWN)
#define GPIO155_LCD_D26 PIN_CFG(155, ALT_B)
#define GPIO155_STMAPE_CLK PIN_CFG(155, ALT_C)
#define GPIO156_GPIO PIN_CFG(156, GPIO)
-#define GPIO156_KP_I4 PIN_CFG(156, ALT_A)
+#define GPIO156_KP_I4 PIN_CFG_PULL(156, ALT_A, DOWN)
#define GPIO156_LCD_D27 PIN_CFG(156, ALT_B)
#define GPIO156_STMAPE_DAT3 PIN_CFG(156, ALT_C)
#define GPIO157_GPIO PIN_CFG(157, GPIO)
-#define GPIO157_KP_O7 PIN_CFG(157, ALT_A)
+#define GPIO157_KP_O7 PIN_CFG_PULL(157, ALT_A, UP)
#define GPIO157_LCD_D28 PIN_CFG(157, ALT_B)
#define GPIO157_STMAPE_DAT2 PIN_CFG(157, ALT_C)
#define GPIO158_GPIO PIN_CFG(158, GPIO)
-#define GPIO158_KP_O6 PIN_CFG(158, ALT_A)
+#define GPIO158_KP_O6 PIN_CFG_PULL(158, ALT_A, UP)
#define GPIO158_LCD_D29 PIN_CFG(158, ALT_B)
#define GPIO158_STMAPE_DAT1 PIN_CFG(158, ALT_C)
#define GPIO159_GPIO PIN_CFG(159, GPIO)
-#define GPIO159_KP_O5 PIN_CFG(159, ALT_A)
+#define GPIO159_KP_O5 PIN_CFG_PULL(159, ALT_A, UP)
#define GPIO159_LCD_D30 PIN_CFG(159, ALT_B)
#define GPIO159_STMAPE_DAT0 PIN_CFG(159, ALT_C)
#define GPIO160_GPIO PIN_CFG(160, GPIO)
-#define GPIO160_KP_O4 PIN_CFG(160, ALT_A)
+#define GPIO160_KP_O4 PIN_CFG_PULL(160, ALT_A, UP)
#define GPIO160_LCD_D31 PIN_CFG(160, ALT_B)
#define GPIO160_NONE PIN_CFG(160, ALT_C)
#define GPIO161_GPIO PIN_CFG(161, GPIO)
-#define GPIO161_KP_I3 PIN_CFG(161, ALT_A)
+#define GPIO161_KP_I3 PIN_CFG_PULL(161, ALT_A, DOWN)
#define GPIO161_LCD_D32 PIN_CFG(161, ALT_B)
#define GPIO161_UARTMOD_RXD PIN_CFG(161, ALT_C)
#define GPIO162_GPIO PIN_CFG(162, GPIO)
-#define GPIO162_KP_I2 PIN_CFG(162, ALT_A)
+#define GPIO162_KP_I2 PIN_CFG_PULL(162, ALT_A, DOWN)
#define GPIO162_LCD_D33 PIN_CFG(162, ALT_B)
#define GPIO162_UARTMOD_TXD PIN_CFG(162, ALT_C)
#define GPIO163_GPIO PIN_CFG(163, GPIO)
-#define GPIO163_KP_I1 PIN_CFG(163, ALT_A)
+#define GPIO163_KP_I1 PIN_CFG_PULL(163, ALT_A, DOWN)
#define GPIO163_LCD_D34 PIN_CFG(163, ALT_B)
#define GPIO163_STMMOD_CLK PIN_CFG(163, ALT_C)
#define GPIO164_GPIO PIN_CFG(164, GPIO)
-#define GPIO164_KP_I0 PIN_CFG(164, ALT_A)
+#define GPIO164_KP_I0 PIN_CFG_PULL(164, ALT_A, UP)
#define GPIO164_LCD_D35 PIN_CFG(164, ALT_B)
#define GPIO164_STMMOD_DAT3 PIN_CFG(164, ALT_C)
#define GPIO165_GPIO PIN_CFG(165, GPIO)
-#define GPIO165_KP_O3 PIN_CFG(165, ALT_A)
+#define GPIO165_KP_O3 PIN_CFG_PULL(165, ALT_A, UP)
#define GPIO165_LCD_D36 PIN_CFG(165, ALT_B)
#define GPIO165_STMMOD_DAT2 PIN_CFG(165, ALT_C)
#define GPIO166_GPIO PIN_CFG(166, GPIO)
-#define GPIO166_KP_O2 PIN_CFG(166, ALT_A)
+#define GPIO166_KP_O2 PIN_CFG_PULL(166, ALT_A, UP)
#define GPIO166_LCD_D37 PIN_CFG(166, ALT_B)
#define GPIO166_STMMOD_DAT1 PIN_CFG(166, ALT_C)
#define GPIO167_GPIO PIN_CFG(167, GPIO)
-#define GPIO167_KP_O1 PIN_CFG(167, ALT_A)
+#define GPIO167_KP_O1 PIN_CFG_PULL(167, ALT_A, UP)
#define GPIO167_LCD_D38 PIN_CFG(167, ALT_B)
#define GPIO167_STMMOD_DAT0 PIN_CFG(167, ALT_C)
#define GPIO168_GPIO PIN_CFG(168, GPIO)
-#define GPIO168_KP_O0 PIN_CFG(168, ALT_A)
+#define GPIO168_KP_O0 PIN_CFG_PULL(168, ALT_A, UP)
#define GPIO168_LCD_D39 PIN_CFG(168, ALT_B)
#define GPIO168_NONE PIN_CFG(168, ALT_C)
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
index 8440d952ba6d..c493d7244d3d 100644
--- a/arch/arm/mm/fault-armv.c
+++ b/arch/arm/mm/fault-armv.c
@@ -89,13 +89,13 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address,
* open-code the spin-locking.
*/
ptl = pte_lockptr(vma->vm_mm, pmd);
- pte = pte_offset_map_nested(pmd, address);
+ pte = pte_offset_map(pmd, address);
spin_lock(ptl);
ret = do_adjust_pte(vma, address, pfn, pte);
spin_unlock(ptl);
- pte_unmap_nested(pte);
+ pte_unmap(pte);
return ret;
}
diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c
index 1fbdb55bfd1b..c435fd9e1da9 100644
--- a/arch/arm/mm/highmem.c
+++ b/arch/arm/mm/highmem.c
@@ -36,18 +36,17 @@ void kunmap(struct page *page)
}
EXPORT_SYMBOL(kunmap);
-void *kmap_atomic(struct page *page, enum km_type type)
+void *__kmap_atomic(struct page *page)
{
unsigned int idx;
unsigned long vaddr;
void *kmap;
+ int type;
pagefault_disable();
if (!PageHighMem(page))
return page_address(page);
- debug_kmap_atomic(type);
-
#ifdef CONFIG_DEBUG_HIGHMEM
/*
* There is no cache coherency issue when non VIVT, so force the
@@ -61,6 +60,8 @@ void *kmap_atomic(struct page *page, enum km_type type)
if (kmap)
return kmap;
+ type = kmap_atomic_idx_push();
+
idx = type + KM_TYPE_NR * smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
#ifdef CONFIG_DEBUG_HIGHMEM
@@ -80,14 +81,17 @@ void *kmap_atomic(struct page *page, enum km_type type)
return (void *)vaddr;
}
-EXPORT_SYMBOL(kmap_atomic);
+EXPORT_SYMBOL(__kmap_atomic);
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
{
unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
- unsigned int idx = type + KM_TYPE_NR * smp_processor_id();
+ int idx, type;
if (kvaddr >= (void *)FIXADDR_START) {
+ type = kmap_atomic_idx();
+ idx = type + KM_TYPE_NR * smp_processor_id();
+
if (cache_is_vivt())
__cpuc_flush_dcache_area((void *)vaddr, PAGE_SIZE);
#ifdef CONFIG_DEBUG_HIGHMEM
@@ -97,21 +101,23 @@ void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
#else
(void) idx; /* to kill a warning */
#endif
+ kmap_atomic_idx_pop();
} else if (vaddr >= PKMAP_ADDR(0) && vaddr < PKMAP_ADDR(LAST_PKMAP)) {
/* this address was obtained through kmap_high_get() */
kunmap_high(pte_page(pkmap_page_table[PKMAP_NR(vaddr)]));
}
pagefault_enable();
}
-EXPORT_SYMBOL(kunmap_atomic_notypecheck);
+EXPORT_SYMBOL(__kunmap_atomic);
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
+void *kmap_atomic_pfn(unsigned long pfn)
{
- unsigned int idx;
unsigned long vaddr;
+ int idx, type;
pagefault_disable();
+ type = kmap_atomic_idx_push();
idx = type + KM_TYPE_NR * smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
#ifdef CONFIG_DEBUG_HIGHMEM
diff --git a/arch/arm/mm/pgd.c b/arch/arm/mm/pgd.c
index be5f58e153bf..69bbfc6645a6 100644
--- a/arch/arm/mm/pgd.c
+++ b/arch/arm/mm/pgd.c
@@ -57,9 +57,9 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
goto no_pte;
init_pmd = pmd_offset(init_pgd, 0);
- init_pte = pte_offset_map_nested(init_pmd, 0);
+ init_pte = pte_offset_map(init_pmd, 0);
set_pte_ext(new_pte, *init_pte, 0);
- pte_unmap_nested(init_pte);
+ pte_unmap(init_pte);
pte_unmap(new_pte);
}
diff --git a/arch/arm/nwfpe/milieu.h b/arch/arm/nwfpe/milieu.h
index a3892ab2dca4..09a4f2ddeb77 100644
--- a/arch/arm/nwfpe/milieu.h
+++ b/arch/arm/nwfpe/milieu.h
@@ -12,8 +12,8 @@ National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
-is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
-arithmetic/softfloat.html'.
+is available through the Web page
+http://www.jhauser.us/arithmetic/SoftFloat-2b/SoftFloat-source.txt
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
diff --git a/arch/arm/nwfpe/softfloat-macros b/arch/arm/nwfpe/softfloat-macros
index 5a060f95a58f..cf2a6173149e 100644
--- a/arch/arm/nwfpe/softfloat-macros
+++ b/arch/arm/nwfpe/softfloat-macros
@@ -12,8 +12,8 @@ National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
-is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
-arithmetic/softfloat.html'.
+is available through the web page
+http://www.jhauser.us/arithmetic/SoftFloat-2b/SoftFloat-source.txt
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
diff --git a/arch/arm/nwfpe/softfloat-specialize b/arch/arm/nwfpe/softfloat-specialize
index d4a4c8e06635..679a0269dd25 100644
--- a/arch/arm/nwfpe/softfloat-specialize
+++ b/arch/arm/nwfpe/softfloat-specialize
@@ -12,8 +12,8 @@ National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
-is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
-arithmetic/softfloat.html'.
+is available through the Web page
+http://www.jhauser.us/arithmetic/SoftFloat-2b/SoftFloat-source.txt
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
diff --git a/arch/arm/nwfpe/softfloat.c b/arch/arm/nwfpe/softfloat.c
index 0f9656e482ba..ffa6b438786b 100644
--- a/arch/arm/nwfpe/softfloat.c
+++ b/arch/arm/nwfpe/softfloat.c
@@ -11,8 +11,8 @@ National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
-is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
-arithmetic/softfloat.html'.
+is available through the web page
+http://www.jhauser.us/arithmetic/SoftFloat-2b/SoftFloat-source.txt
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
diff --git a/arch/arm/nwfpe/softfloat.h b/arch/arm/nwfpe/softfloat.h
index 13e479c5da57..df4d243a2b7c 100644
--- a/arch/arm/nwfpe/softfloat.h
+++ b/arch/arm/nwfpe/softfloat.h
@@ -12,8 +12,8 @@ National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
-is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
-arithmetic/softfloat.html'.
+is available through the Web page
+http://www.jhauser.us/arithmetic/SoftFloat-2b/SoftFloat-source.txt
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
diff --git a/arch/arm/plat-mxc/include/mach/dma.h b/arch/arm/plat-mxc/include/mach/dma.h
new file mode 100644
index 000000000000..ef7751546f5f
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/dma.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_DMA_H__
+#define __ASM_ARCH_MXC_DMA_H__
+
+#include <linux/scatterlist.h>
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+
+/*
+ * This enumerates peripheral types. Used for SDMA.
+ */
+enum sdma_peripheral_type {
+ IMX_DMATYPE_SSI, /* MCU domain SSI */
+ IMX_DMATYPE_SSI_SP, /* Shared SSI */
+ IMX_DMATYPE_MMC, /* MMC */
+ IMX_DMATYPE_SDHC, /* SDHC */
+ IMX_DMATYPE_UART, /* MCU domain UART */
+ IMX_DMATYPE_UART_SP, /* Shared UART */
+ IMX_DMATYPE_FIRI, /* FIRI */
+ IMX_DMATYPE_CSPI, /* MCU domain CSPI */
+ IMX_DMATYPE_CSPI_SP, /* Shared CSPI */
+ IMX_DMATYPE_SIM, /* SIM */
+ IMX_DMATYPE_ATA, /* ATA */
+ IMX_DMATYPE_CCM, /* CCM */
+ IMX_DMATYPE_EXT, /* External peripheral */
+ IMX_DMATYPE_MSHC, /* Memory Stick Host Controller */
+ IMX_DMATYPE_MSHC_SP, /* Shared Memory Stick Host Controller */
+ IMX_DMATYPE_DSP, /* DSP */
+ IMX_DMATYPE_MEMORY, /* Memory */
+ IMX_DMATYPE_FIFO_MEMORY,/* FIFO type Memory */
+ IMX_DMATYPE_SPDIF, /* SPDIF */
+ IMX_DMATYPE_IPU_MEMORY, /* IPU Memory */
+ IMX_DMATYPE_ASRC, /* ASRC */
+ IMX_DMATYPE_ESAI, /* ESAI */
+};
+
+enum imx_dma_prio {
+ DMA_PRIO_HIGH = 0,
+ DMA_PRIO_MEDIUM = 1,
+ DMA_PRIO_LOW = 2
+};
+
+struct imx_dma_data {
+ int dma_request; /* DMA request line */
+ enum sdma_peripheral_type peripheral_type;
+ int priority;
+};
+
+static inline int imx_dma_is_ipu(struct dma_chan *chan)
+{
+ return !strcmp(dev_name(chan->device->dev), "ipu-core");
+}
+
+static inline int imx_dma_is_general_purpose(struct dma_chan *chan)
+{
+ return !strcmp(dev_name(chan->device->dev), "imx-sdma") ||
+ !strcmp(dev_name(chan->device->dev), "imx-dma");
+}
+
+#endif
diff --git a/arch/arm/plat-mxc/include/mach/sdma.h b/arch/arm/plat-mxc/include/mach/sdma.h
new file mode 100644
index 000000000000..9be112227ac4
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/sdma.h
@@ -0,0 +1,17 @@
+#ifndef __MACH_MXC_SDMA_H__
+#define __MACH_MXC_SDMA_H__
+
+/**
+ * struct sdma_platform_data - platform specific data for SDMA engine
+ *
+ * @sdma_version The version of this SDMA engine
+ * @cpu_name used to generate the firmware name
+ * @to_version CPU Tape out version
+ */
+struct sdma_platform_data {
+ int sdma_version;
+ char *cpu_name;
+ int to_version;
+};
+
+#endif /* __MACH_MXC_SDMA_H__ */
diff --git a/arch/arm/plat-nomadik/include/plat/ske.h b/arch/arm/plat-nomadik/include/plat/ske.h
new file mode 100644
index 000000000000..31382fbc07dc
--- /dev/null
+++ b/arch/arm/plat-nomadik/include/plat/ske.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
+ *
+ * ux500 Scroll key and Keypad Encoder (SKE) header
+ */
+
+#ifndef __SKE_H
+#define __SKE_H
+
+#include <linux/input/matrix_keypad.h>
+
+/* register definitions for SKE peripheral */
+#define SKE_CR 0x00
+#define SKE_VAL0 0x04
+#define SKE_VAL1 0x08
+#define SKE_DBCR 0x0C
+#define SKE_IMSC 0x10
+#define SKE_RIS 0x14
+#define SKE_MIS 0x18
+#define SKE_ICR 0x1C
+
+/*
+ * Keypad module
+ */
+
+/**
+ * struct keypad_platform_data - structure for platform specific data
+ * @init: pointer to keypad init function
+ * @exit: pointer to keypad deinitialisation function
+ * @keymap_data: matrix scan code table for keycodes
+ * @krow: maximum number of rows
+ * @kcol: maximum number of columns
+ * @debounce_ms: platform specific debounce time
+ * @no_autorepeat: flag for auto repetition
+ * @wakeup_enable: allow waking up the system
+ */
+struct ske_keypad_platform_data {
+ int (*init)(void);
+ int (*exit)(void);
+ const struct matrix_keymap_data *keymap_data;
+ u8 krow;
+ u8 kcol;
+ u8 debounce_ms;
+ bool no_autorepeat;
+ bool wakeup_enable;
+};
+#endif /*__SKE_KPD_H*/
diff --git a/arch/arm/plat-nomadik/include/plat/ste_dma40.h b/arch/arm/plat-nomadik/include/plat/ste_dma40.h
index 5fbde4b8dc12..74b62f10d07f 100644
--- a/arch/arm/plat-nomadik/include/plat/ste_dma40.h
+++ b/arch/arm/plat-nomadik/include/plat/ste_dma40.h
@@ -1,10 +1,8 @@
/*
- * arch/arm/plat-nomadik/include/plat/ste_dma40.h
- *
- * Copyright (C) ST-Ericsson 2007-2010
+ * Copyright (C) ST-Ericsson SA 2007-2010
+ * Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
- * Author: Per Friden <per.friden@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*/
@@ -14,43 +12,25 @@
#include <linux/dmaengine.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
-#include <linux/dmaengine.h>
/* dev types for memcpy */
#define STEDMA40_DEV_DST_MEMORY (-1)
#define STEDMA40_DEV_SRC_MEMORY (-1)
-/*
- * Description of bitfields of channel_type variable is available in
- * the info structure.
- */
+enum stedma40_mode {
+ STEDMA40_MODE_LOGICAL = 0,
+ STEDMA40_MODE_PHYSICAL,
+ STEDMA40_MODE_OPERATION,
+};
-/* Priority */
-#define STEDMA40_INFO_PRIO_TYPE_POS 2
-#define STEDMA40_HIGH_PRIORITY_CHANNEL (0x1 << STEDMA40_INFO_PRIO_TYPE_POS)
-#define STEDMA40_LOW_PRIORITY_CHANNEL (0x2 << STEDMA40_INFO_PRIO_TYPE_POS)
-
-/* Mode */
-#define STEDMA40_INFO_CH_MODE_TYPE_POS 6
-#define STEDMA40_CHANNEL_IN_PHY_MODE (0x1 << STEDMA40_INFO_CH_MODE_TYPE_POS)
-#define STEDMA40_CHANNEL_IN_LOG_MODE (0x2 << STEDMA40_INFO_CH_MODE_TYPE_POS)
-#define STEDMA40_CHANNEL_IN_OPER_MODE (0x3 << STEDMA40_INFO_CH_MODE_TYPE_POS)
-
-/* Mode options */
-#define STEDMA40_INFO_CH_MODE_OPT_POS 8
-#define STEDMA40_PCHAN_BASIC_MODE (0x1 << STEDMA40_INFO_CH_MODE_OPT_POS)
-#define STEDMA40_PCHAN_MODULO_MODE (0x2 << STEDMA40_INFO_CH_MODE_OPT_POS)
-#define STEDMA40_PCHAN_DOUBLE_DST_MODE (0x3 << STEDMA40_INFO_CH_MODE_OPT_POS)
-#define STEDMA40_LCHAN_SRC_PHY_DST_LOG (0x1 << STEDMA40_INFO_CH_MODE_OPT_POS)
-#define STEDMA40_LCHAN_SRC_LOG_DST_PHS (0x2 << STEDMA40_INFO_CH_MODE_OPT_POS)
-#define STEDMA40_LCHAN_SRC_LOG_DST_LOG (0x3 << STEDMA40_INFO_CH_MODE_OPT_POS)
-
-/* Interrupt */
-#define STEDMA40_INFO_TIM_POS 10
-#define STEDMA40_NO_TIM_FOR_LINK (0x0 << STEDMA40_INFO_TIM_POS)
-#define STEDMA40_TIM_FOR_LINK (0x1 << STEDMA40_INFO_TIM_POS)
-
-/* End of channel_type configuration */
+enum stedma40_mode_opt {
+ STEDMA40_PCHAN_BASIC_MODE = 0,
+ STEDMA40_LCHAN_SRC_LOG_DST_LOG = 0,
+ STEDMA40_PCHAN_MODULO_MODE,
+ STEDMA40_PCHAN_DOUBLE_DST_MODE,
+ STEDMA40_LCHAN_SRC_PHY_DST_LOG,
+ STEDMA40_LCHAN_SRC_LOG_DST_PHY,
+};
#define STEDMA40_ESIZE_8_BIT 0x0
#define STEDMA40_ESIZE_16_BIT 0x1
@@ -73,16 +53,14 @@
#define STEDMA40_PSIZE_LOG_8 STEDMA40_PSIZE_PHY_8
#define STEDMA40_PSIZE_LOG_16 STEDMA40_PSIZE_PHY_16
+/* Maximum number of possible physical channels */
+#define STEDMA40_MAX_PHYS 32
+
enum stedma40_flow_ctrl {
STEDMA40_NO_FLOW_CTRL,
STEDMA40_FLOW_CTRL,
};
-enum stedma40_endianess {
- STEDMA40_LITTLE_ENDIAN,
- STEDMA40_BIG_ENDIAN
-};
-
enum stedma40_periph_data_width {
STEDMA40_BYTE_WIDTH = STEDMA40_ESIZE_8_BIT,
STEDMA40_HALFWORD_WIDTH = STEDMA40_ESIZE_16_BIT,
@@ -90,15 +68,8 @@ enum stedma40_periph_data_width {
STEDMA40_DOUBLEWORD_WIDTH = STEDMA40_ESIZE_64_BIT
};
-struct stedma40_half_channel_info {
- enum stedma40_endianess endianess;
- enum stedma40_periph_data_width data_width;
- int psize;
- enum stedma40_flow_ctrl flow_ctrl;
-};
-
enum stedma40_xfer_dir {
- STEDMA40_MEM_TO_MEM,
+ STEDMA40_MEM_TO_MEM = 1,
STEDMA40_MEM_TO_PERIPH,
STEDMA40_PERIPH_TO_MEM,
STEDMA40_PERIPH_TO_PERIPH
@@ -106,18 +77,31 @@ enum stedma40_xfer_dir {
/**
+ * struct stedma40_chan_cfg - dst/src channel configuration
+ *
+ * @big_endian: true if the src/dst should be read as big endian
+ * @data_width: Data width of the src/dst hardware
+ * @p_size: Burst size
+ * @flow_ctrl: Flow control on/off.
+ */
+struct stedma40_half_channel_info {
+ bool big_endian;
+ enum stedma40_periph_data_width data_width;
+ int psize;
+ enum stedma40_flow_ctrl flow_ctrl;
+};
+
+/**
* struct stedma40_chan_cfg - Structure to be filled by client drivers.
*
* @dir: MEM 2 MEM, PERIPH 2 MEM , MEM 2 PERIPH, PERIPH 2 PERIPH
- * @channel_type: priority, mode, mode options and interrupt configuration.
+ * @high_priority: true if high-priority
+ * @mode: channel mode: physical, logical, or operation
+ * @mode_opt: options for the chosen channel mode
* @src_dev_type: Src device type
* @dst_dev_type: Dst device type
* @src_info: Parameters for dst half channel
* @dst_info: Parameters for dst half channel
- * @pre_transfer_data: Data to be passed on to the pre_transfer() function.
- * @pre_transfer: Callback used if needed before preparation of transfer.
- * Only called if device is set. size of bytes to transfer
- * (in case of multiple element transfer size is size of the first element).
*
*
* This structure has to be filled by the client drivers.
@@ -126,15 +110,13 @@ enum stedma40_xfer_dir {
*/
struct stedma40_chan_cfg {
enum stedma40_xfer_dir dir;
- unsigned int channel_type;
+ bool high_priority;
+ enum stedma40_mode mode;
+ enum stedma40_mode_opt mode_opt;
int src_dev_type;
int dst_dev_type;
struct stedma40_half_channel_info src_info;
struct stedma40_half_channel_info dst_info;
- void *pre_transfer_data;
- int (*pre_transfer) (struct dma_chan *chan,
- void *data,
- int size);
};
/**
@@ -147,7 +129,6 @@ struct stedma40_chan_cfg {
* @memcpy_len: length of memcpy
* @memcpy_conf_phy: default configuration of physical channel memcpy
* @memcpy_conf_log: default configuration of logical channel memcpy
- * @llis_per_log: number of max linked list items per logical channel
* @disabled_channels: A vector, ending with -1, that marks physical channels
* that are for different reasons not available for the driver.
*/
@@ -159,23 +140,10 @@ struct stedma40_platform_data {
u32 memcpy_len;
struct stedma40_chan_cfg *memcpy_conf_phy;
struct stedma40_chan_cfg *memcpy_conf_log;
- unsigned int llis_per_log;
- int disabled_channels[8];
+ int disabled_channels[STEDMA40_MAX_PHYS];
};
-/**
- * setdma40_set_psize() - Used for changing the package size of an
- * already configured dma channel.
- *
- * @chan: dmaengine handle
- * @src_psize: new package side for src. (STEDMA40_PSIZE*)
- * @src_psize: new package side for dst. (STEDMA40_PSIZE*)
- *
- * returns 0 on ok, otherwise negative error number.
- */
-int stedma40_set_psize(struct dma_chan *chan,
- int src_psize,
- int dst_psize);
+#ifdef CONFIG_STE_DMA40
/**
* stedma40_filter() - Provides stedma40_chan_cfg to the
@@ -238,4 +206,21 @@ dma_async_tx_descriptor *stedma40_slave_mem(struct dma_chan *chan,
direction, flags);
}
+#else
+static inline bool stedma40_filter(struct dma_chan *chan, void *data)
+{
+ return false;
+}
+
+static inline struct
+dma_async_tx_descriptor *stedma40_slave_mem(struct dma_chan *chan,
+ dma_addr_t addr,
+ unsigned int size,
+ enum dma_data_direction direction,
+ unsigned long flags)
+{
+ return NULL;
+}
+#endif
+
#endif
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index a92cb499313f..92c5bb7909f5 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -19,7 +19,7 @@ config ARCH_OMAP2PLUS
bool "TI OMAP2/3/4"
select COMMON_CLKDEV
help
- "Systems based on omap24xx, omap34xx or omap44xx"
+ "Systems based on OMAP2, OMAP3 or OMAP4"
endchoice
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 9405831b746a..a4a12859fdd5 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -4,7 +4,7 @@
# Common support
obj-y := common.o sram.o clock.o devices.o dma.o mux.o gpio.o \
- usb.o fb.o io.o
+ usb.o fb.o io.o counter_32k.o
obj-m :=
obj-n :=
obj- :=
@@ -31,4 +31,4 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y)
# OMAP mailbox framework
obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
-obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o \ No newline at end of file
+obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index 7190cbd92620..fc62fb5fc20b 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -60,7 +60,7 @@ void clk_disable(struct clk *clk)
spin_lock_irqsave(&clockfw_lock, flags);
if (clk->usecount == 0) {
- printk(KERN_ERR "Trying disable clock %s with 0 usecount\n",
+ pr_err("Trying disable clock %s with 0 usecount\n",
clk->name);
WARN_ON(1);
goto out;
@@ -397,6 +397,7 @@ static int __init clk_disable_unused(void)
struct clk *ck;
unsigned long flags;
+ pr_info("clock: disabling unused clocks to save power\n");
list_for_each_entry(ck, &clocks, node) {
if (ck->ops == &clkops_null)
continue;
@@ -418,7 +419,7 @@ late_initcall(clk_disable_unused);
int __init clk_init(struct clk_functions * custom_clocks)
{
if (!custom_clocks) {
- printk(KERN_ERR "No custom clock functions registered\n");
+ pr_err("No custom clock functions registered\n");
BUG();
}
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index 3008e7104487..221a675ebbae 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -11,38 +11,15 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/console.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_reg.h>
-#include <linux/clk.h>
#include <linux/io.h>
#include <linux/omapfb.h>
-#include <mach/hardware.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/mach/map.h>
-#include <asm/setup.h>
-
#include <plat/common.h>
#include <plat/board.h>
-#include <plat/control.h>
-#include <plat/mux.h>
-#include <plat/fpga.h>
-#include <plat/serial.h>
#include <plat/vram.h>
-#include <plat/clock.h>
-
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-# include "../mach-omap2/sdrc.h"
-#endif
#define NO_LENGTH_CHECK 0xffffffff
@@ -88,270 +65,3 @@ void __init omap_reserve(void)
omapfb_reserve_sdram_memblock();
omap_vram_reserve_sdram_memblock();
}
-
-/*
- * 32KHz clocksource ... always available, on pretty most chips except
- * OMAP 730 and 1510. Other timers could be used as clocksources, with
- * higher resolution in free-running counter modes (e.g. 12 MHz xtal),
- * but systems won't necessarily want to spend resources that way.
- */
-
-#define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410
-
-#if !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX))
-
-#include <linux/clocksource.h>
-
-/*
- * offset_32k holds the init time counter value. It is then subtracted
- * from every counter read to achieve a counter that counts time from the
- * kernel boot (needed for sched_clock()).
- */
-static u32 offset_32k __read_mostly;
-
-#ifdef CONFIG_ARCH_OMAP16XX
-static cycle_t omap16xx_32k_read(struct clocksource *cs)
-{
- return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED) - offset_32k;
-}
-#else
-#define omap16xx_32k_read NULL
-#endif
-
-#ifdef CONFIG_ARCH_OMAP2420
-static cycle_t omap2420_32k_read(struct clocksource *cs)
-{
- return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10) - offset_32k;
-}
-#else
-#define omap2420_32k_read NULL
-#endif
-
-#ifdef CONFIG_ARCH_OMAP2430
-static cycle_t omap2430_32k_read(struct clocksource *cs)
-{
- return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10) - offset_32k;
-}
-#else
-#define omap2430_32k_read NULL
-#endif
-
-#ifdef CONFIG_ARCH_OMAP3
-static cycle_t omap34xx_32k_read(struct clocksource *cs)
-{
- return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10) - offset_32k;
-}
-#else
-#define omap34xx_32k_read NULL
-#endif
-
-#ifdef CONFIG_ARCH_OMAP4
-static cycle_t omap44xx_32k_read(struct clocksource *cs)
-{
- return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10) - offset_32k;
-}
-#else
-#define omap44xx_32k_read NULL
-#endif
-
-/*
- * Kernel assumes that sched_clock can be called early but may not have
- * things ready yet.
- */
-static cycle_t omap_32k_read_dummy(struct clocksource *cs)
-{
- return 0;
-}
-
-static struct clocksource clocksource_32k = {
- .name = "32k_counter",
- .rating = 250,
- .read = omap_32k_read_dummy,
- .mask = CLOCKSOURCE_MASK(32),
- .shift = 10,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-/*
- * Returns current time from boot in nsecs. It's OK for this to wrap
- * around for now, as it's just a relative time stamp.
- */
-unsigned long long sched_clock(void)
-{
- return clocksource_cyc2ns(clocksource_32k.read(&clocksource_32k),
- clocksource_32k.mult, clocksource_32k.shift);
-}
-
-/**
- * read_persistent_clock - Return time from a persistent clock.
- *
- * Reads the time from a source which isn't disabled during PM, the
- * 32k sync timer. Convert the cycles elapsed since last read into
- * nsecs and adds to a monotonically increasing timespec.
- */
-static struct timespec persistent_ts;
-static cycles_t cycles, last_cycles;
-void read_persistent_clock(struct timespec *ts)
-{
- unsigned long long nsecs;
- cycles_t delta;
- struct timespec *tsp = &persistent_ts;
-
- last_cycles = cycles;
- cycles = clocksource_32k.read(&clocksource_32k);
- delta = cycles - last_cycles;
-
- nsecs = clocksource_cyc2ns(delta,
- clocksource_32k.mult, clocksource_32k.shift);
-
- timespec_add_ns(tsp, nsecs);
- *ts = *tsp;
-}
-
-static int __init omap_init_clocksource_32k(void)
-{
- static char err[] __initdata = KERN_ERR
- "%s: can't register clocksource!\n";
-
- if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
- struct clk *sync_32k_ick;
-
- if (cpu_is_omap16xx())
- clocksource_32k.read = omap16xx_32k_read;
- else if (cpu_is_omap2420())
- clocksource_32k.read = omap2420_32k_read;
- else if (cpu_is_omap2430())
- clocksource_32k.read = omap2430_32k_read;
- else if (cpu_is_omap34xx())
- clocksource_32k.read = omap34xx_32k_read;
- else if (cpu_is_omap44xx())
- clocksource_32k.read = omap44xx_32k_read;
- else
- return -ENODEV;
-
- sync_32k_ick = clk_get(NULL, "omap_32ksync_ick");
- if (sync_32k_ick)
- clk_enable(sync_32k_ick);
-
- clocksource_32k.mult = clocksource_hz2mult(32768,
- clocksource_32k.shift);
-
- offset_32k = clocksource_32k.read(&clocksource_32k);
-
- if (clocksource_register(&clocksource_32k))
- printk(err, clocksource_32k.name);
- }
- return 0;
-}
-arch_initcall(omap_init_clocksource_32k);
-
-#endif /* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */
-
-/* Global address base setup code */
-
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-
-static void __init __omap2_set_globals(struct omap_globals *omap2_globals)
-{
- omap2_set_globals_tap(omap2_globals);
- omap2_set_globals_sdrc(omap2_globals);
- omap2_set_globals_control(omap2_globals);
- omap2_set_globals_prcm(omap2_globals);
- omap2_set_globals_uart(omap2_globals);
-}
-
-#endif
-
-#if defined(CONFIG_ARCH_OMAP2420)
-
-static struct omap_globals omap242x_globals = {
- .class = OMAP242X_CLASS,
- .tap = OMAP2_L4_IO_ADDRESS(0x48014000),
- .sdrc = OMAP2420_SDRC_BASE,
- .sms = OMAP2420_SMS_BASE,
- .ctrl = OMAP2420_CTRL_BASE,
- .prm = OMAP2420_PRM_BASE,
- .cm = OMAP2420_CM_BASE,
- .uart1_phys = OMAP2_UART1_BASE,
- .uart2_phys = OMAP2_UART2_BASE,
- .uart3_phys = OMAP2_UART3_BASE,
-};
-
-void __init omap2_set_globals_242x(void)
-{
- __omap2_set_globals(&omap242x_globals);
-}
-#endif
-
-#if defined(CONFIG_ARCH_OMAP2430)
-
-static struct omap_globals omap243x_globals = {
- .class = OMAP243X_CLASS,
- .tap = OMAP2_L4_IO_ADDRESS(0x4900a000),
- .sdrc = OMAP243X_SDRC_BASE,
- .sms = OMAP243X_SMS_BASE,
- .ctrl = OMAP243X_CTRL_BASE,
- .prm = OMAP2430_PRM_BASE,
- .cm = OMAP2430_CM_BASE,
- .uart1_phys = OMAP2_UART1_BASE,
- .uart2_phys = OMAP2_UART2_BASE,
- .uart3_phys = OMAP2_UART3_BASE,
-};
-
-void __init omap2_set_globals_243x(void)
-{
- __omap2_set_globals(&omap243x_globals);
-}
-#endif
-
-#if defined(CONFIG_ARCH_OMAP3)
-
-static struct omap_globals omap3_globals = {
- .class = OMAP343X_CLASS,
- .tap = OMAP2_L4_IO_ADDRESS(0x4830A000),
- .sdrc = OMAP343X_SDRC_BASE,
- .sms = OMAP343X_SMS_BASE,
- .ctrl = OMAP343X_CTRL_BASE,
- .prm = OMAP3430_PRM_BASE,
- .cm = OMAP3430_CM_BASE,
- .uart1_phys = OMAP3_UART1_BASE,
- .uart2_phys = OMAP3_UART2_BASE,
- .uart3_phys = OMAP3_UART3_BASE,
- .uart4_phys = OMAP3_UART4_BASE, /* Only on 3630 */
-};
-
-void __init omap2_set_globals_3xxx(void)
-{
- __omap2_set_globals(&omap3_globals);
-}
-
-void __init omap3_map_io(void)
-{
- omap2_set_globals_3xxx();
- omap34xx_map_common_io();
-}
-#endif
-
-#if defined(CONFIG_ARCH_OMAP4)
-static struct omap_globals omap4_globals = {
- .class = OMAP443X_CLASS,
- .tap = OMAP2_L4_IO_ADDRESS(OMAP443X_SCM_BASE),
- .ctrl = OMAP443X_CTRL_BASE,
- .prm = OMAP4430_PRM_BASE,
- .cm = OMAP4430_CM_BASE,
- .cm2 = OMAP4430_CM2_BASE,
- .uart1_phys = OMAP4_UART1_BASE,
- .uart2_phys = OMAP4_UART2_BASE,
- .uart3_phys = OMAP4_UART3_BASE,
- .uart4_phys = OMAP4_UART4_BASE,
-};
-
-void __init omap2_set_globals_443x(void)
-{
- omap2_set_globals_tap(&omap4_globals);
- omap2_set_globals_control(&omap4_globals);
- omap2_set_globals_prcm(&omap4_globals);
- omap2_set_globals_uart(&omap4_globals);
-}
-#endif
-
diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c
new file mode 100644
index 000000000000..155fe43a672b
--- /dev/null
+++ b/arch/arm/plat-omap/counter_32k.c
@@ -0,0 +1,183 @@
+/*
+ * OMAP 32ksynctimer/counter_32k-related code
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Copyright (C) 2010 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@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.
+ *
+ * NOTE: This timer is not the same timer as the old OMAP1 MPU timer.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <plat/common.h>
+#include <plat/board.h>
+
+#include <plat/clock.h>
+
+
+/*
+ * 32KHz clocksource ... always available, on pretty most chips except
+ * OMAP 730 and 1510. Other timers could be used as clocksources, with
+ * higher resolution in free-running counter modes (e.g. 12 MHz xtal),
+ * but systems won't necessarily want to spend resources that way.
+ */
+
+#define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410
+
+#if !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX))
+
+#include <linux/clocksource.h>
+
+/*
+ * offset_32k holds the init time counter value. It is then subtracted
+ * from every counter read to achieve a counter that counts time from the
+ * kernel boot (needed for sched_clock()).
+ */
+static u32 offset_32k __read_mostly;
+
+#ifdef CONFIG_ARCH_OMAP16XX
+static cycle_t omap16xx_32k_read(struct clocksource *cs)
+{
+ return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED) - offset_32k;
+}
+#else
+#define omap16xx_32k_read NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2420
+static cycle_t omap2420_32k_read(struct clocksource *cs)
+{
+ return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10) - offset_32k;
+}
+#else
+#define omap2420_32k_read NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+static cycle_t omap2430_32k_read(struct clocksource *cs)
+{
+ return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10) - offset_32k;
+}
+#else
+#define omap2430_32k_read NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+static cycle_t omap34xx_32k_read(struct clocksource *cs)
+{
+ return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10) - offset_32k;
+}
+#else
+#define omap34xx_32k_read NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP4
+static cycle_t omap44xx_32k_read(struct clocksource *cs)
+{
+ return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10) - offset_32k;
+}
+#else
+#define omap44xx_32k_read NULL
+#endif
+
+/*
+ * Kernel assumes that sched_clock can be called early but may not have
+ * things ready yet.
+ */
+static cycle_t omap_32k_read_dummy(struct clocksource *cs)
+{
+ return 0;
+}
+
+static struct clocksource clocksource_32k = {
+ .name = "32k_counter",
+ .rating = 250,
+ .read = omap_32k_read_dummy,
+ .mask = CLOCKSOURCE_MASK(32),
+ .shift = 10,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/*
+ * Returns current time from boot in nsecs. It's OK for this to wrap
+ * around for now, as it's just a relative time stamp.
+ */
+unsigned long long sched_clock(void)
+{
+ return clocksource_cyc2ns(clocksource_32k.read(&clocksource_32k),
+ clocksource_32k.mult, clocksource_32k.shift);
+}
+
+/**
+ * read_persistent_clock - Return time from a persistent clock.
+ *
+ * Reads the time from a source which isn't disabled during PM, the
+ * 32k sync timer. Convert the cycles elapsed since last read into
+ * nsecs and adds to a monotonically increasing timespec.
+ */
+static struct timespec persistent_ts;
+static cycles_t cycles, last_cycles;
+void read_persistent_clock(struct timespec *ts)
+{
+ unsigned long long nsecs;
+ cycles_t delta;
+ struct timespec *tsp = &persistent_ts;
+
+ last_cycles = cycles;
+ cycles = clocksource_32k.read(&clocksource_32k);
+ delta = cycles - last_cycles;
+
+ nsecs = clocksource_cyc2ns(delta,
+ clocksource_32k.mult, clocksource_32k.shift);
+
+ timespec_add_ns(tsp, nsecs);
+ *ts = *tsp;
+}
+
+static int __init omap_init_clocksource_32k(void)
+{
+ static char err[] __initdata = KERN_ERR
+ "%s: can't register clocksource!\n";
+
+ if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
+ struct clk *sync_32k_ick;
+
+ if (cpu_is_omap16xx())
+ clocksource_32k.read = omap16xx_32k_read;
+ else if (cpu_is_omap2420())
+ clocksource_32k.read = omap2420_32k_read;
+ else if (cpu_is_omap2430())
+ clocksource_32k.read = omap2430_32k_read;
+ else if (cpu_is_omap34xx())
+ clocksource_32k.read = omap34xx_32k_read;
+ else if (cpu_is_omap44xx())
+ clocksource_32k.read = omap44xx_32k_read;
+ else
+ return -ENODEV;
+
+ sync_32k_ick = clk_get(NULL, "omap_32ksync_ick");
+ if (sync_32k_ick)
+ clk_enable(sync_32k_ick);
+
+ clocksource_32k.mult = clocksource_hz2mult(32768,
+ clocksource_32k.shift);
+
+ offset_32k = clocksource_32k.read(&clocksource_32k);
+
+ if (clocksource_register(&clocksource_32k))
+ printk(err, clocksource_32k.name);
+ }
+ return 0;
+}
+arch_initcall(omap_init_clocksource_32k);
+
+#endif /* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */
+
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index 6d3d33360056..11c54ec8d47f 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -40,7 +40,7 @@ static struct clk *mpu_clk;
/* TODO: Add support for SDRAM timing changes */
-int omap_verify_speed(struct cpufreq_policy *policy)
+static int omap_verify_speed(struct cpufreq_policy *policy)
{
if (freq_table)
return cpufreq_frequency_table_verify(policy, freq_table);
@@ -58,7 +58,7 @@ int omap_verify_speed(struct cpufreq_policy *policy)
return 0;
}
-unsigned int omap_getspeed(unsigned int cpu)
+static unsigned int omap_getspeed(unsigned int cpu)
{
unsigned long rate;
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index d1920be7833b..1e2383eae638 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -21,7 +21,6 @@
#include <asm/mach/map.h>
#include <plat/tc.h>
-#include <plat/control.h>
#include <plat/board.h>
#include <plat/mmc.h>
#include <mach/gpio.h>
@@ -232,46 +231,6 @@ static void omap_init_uwire(void)
static inline void omap_init_uwire(void) {}
#endif
-/*-------------------------------------------------------------------------*/
-
-#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
-
-static struct resource wdt_resources[] = {
- {
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device omap_wdt_device = {
- .name = "omap_wdt",
- .id = -1,
- .num_resources = ARRAY_SIZE(wdt_resources),
- .resource = wdt_resources,
-};
-
-static void omap_init_wdt(void)
-{
- if (cpu_is_omap16xx())
- wdt_resources[0].start = 0xfffeb000;
- else if (cpu_is_omap2420())
- wdt_resources[0].start = 0x48022000; /* WDT2 */
- else if (cpu_is_omap2430())
- wdt_resources[0].start = 0x49016000; /* WDT2 */
- else if (cpu_is_omap343x())
- wdt_resources[0].start = 0x48314000; /* WDT2 */
- else if (cpu_is_omap44xx())
- wdt_resources[0].start = 0x4a314000;
- else
- return;
-
- wdt_resources[0].end = wdt_resources[0].start + 0x4f;
-
- (void) platform_device_register(&omap_wdt_device);
-}
-#else
-static inline void omap_init_wdt(void) {}
-#endif
-
/*
* This gets called after board-specific INIT_MACHINE, and initializes most
* on-chip peripherals accessible on this board (except for few like USB):
@@ -300,7 +259,6 @@ static int __init omap_init_devices(void)
omap_init_rng();
omap_init_mcpdm();
omap_init_uwire();
- omap_init_wdt();
return 0;
}
arch_initcall(omap_init_devices);
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index ec7eddf9e525..f5c5b8da9a87 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -30,6 +30,7 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <asm/system.h>
#include <mach/hardware.h>
@@ -996,11 +997,17 @@ void omap_start_dma(int lch)
l = dma_read(CCR(lch));
/*
- * Errata: On ES2.0 BUFFERING disable must be set.
- * This will always fail on ES1.0
+ * Errata: Inter Frame DMA buffering issue (All OMAP2420 and
+ * OMAP2430ES1.0): DMA will wrongly buffer elements if packing and
+ * bursting is enabled. This might result in data gets stalled in
+ * FIFO at the end of the block.
+ * Workaround: DMA channels must have BUFFERING_DISABLED bit set to
+ * guarantee no data will stay in the DMA FIFO in case inter frame
+ * buffering occurs.
*/
- if (cpu_is_omap24xx())
- l |= OMAP_DMA_CCR_EN;
+ if (cpu_is_omap2420() ||
+ (cpu_is_omap2430() && (omap_type() == OMAP2430_REV_ES1_0)))
+ l |= OMAP_DMA_CCR_BUFFERING_DISABLE;
l |= OMAP_DMA_CCR_EN;
dma_write(l, CCR(lch));
@@ -1018,8 +1025,39 @@ void omap_stop_dma(int lch)
dma_write(0, CICR(lch));
l = dma_read(CCR(lch));
- l &= ~OMAP_DMA_CCR_EN;
- dma_write(l, CCR(lch));
+ /* OMAP3 Errata i541: sDMA FIFO draining does not finish */
+ if (cpu_is_omap34xx() && (l & OMAP_DMA_CCR_SEL_SRC_DST_SYNC)) {
+ int i = 0;
+ u32 sys_cf;
+
+ /* Configure No-Standby */
+ l = dma_read(OCP_SYSCONFIG);
+ sys_cf = l;
+ l &= ~DMA_SYSCONFIG_MIDLEMODE_MASK;
+ l |= DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_NO_IDLE);
+ dma_write(l , OCP_SYSCONFIG);
+
+ l = dma_read(CCR(lch));
+ l &= ~OMAP_DMA_CCR_EN;
+ dma_write(l, CCR(lch));
+
+ /* Wait for sDMA FIFO drain */
+ l = dma_read(CCR(lch));
+ while (i < 100 && (l & (OMAP_DMA_CCR_RD_ACTIVE |
+ OMAP_DMA_CCR_WR_ACTIVE))) {
+ udelay(5);
+ i++;
+ l = dma_read(CCR(lch));
+ }
+ if (i >= 100)
+ printk(KERN_ERR "DMA drain did not complete on "
+ "lch %d\n", lch);
+ /* Restore OCP_SYSCONFIG */
+ dma_write(sys_cf, OCP_SYSCONFIG);
+ } else {
+ l &= ~OMAP_DMA_CCR_EN;
+ dma_write(l, CCR(lch));
+ }
if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
int next_lch, cur_lch = lch;
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 44bafdab2dce..1d706cf63ca0 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -581,7 +581,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
* When the functional clock disappears, too quick writes seem
* to cause an abort. XXX Is this still necessary?
*/
- __delay(150000);
+ __delay(300000);
return ret;
}
diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c
index 71934817e172..c9e5d7298c40 100644
--- a/arch/arm/plat-omap/fb.c
+++ b/arch/arm/plat-omap/fb.c
@@ -36,6 +36,8 @@
#include <plat/board.h>
#include <plat/sram.h>
+#include "fb.h"
+
#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
static struct omapfb_platform_data omapfb_config;
@@ -94,7 +96,7 @@ static int fbmem_region_reserved(unsigned long start, size_t size)
* Get the region_idx`th region from board config/ATAG and convert it to
* our internal format.
*/
-static int get_fbmem_region(int region_idx, struct omapfb_mem_region *rg)
+static int __init get_fbmem_region(int region_idx, struct omapfb_mem_region *rg)
{
const struct omap_fbmem_config *conf;
u32 paddr;
@@ -126,7 +128,7 @@ static int set_fbmem_region_type(struct omapfb_mem_region *rg, int mem_type,
* type = 0 && paddr = 0, a default don't care case maps to
* the SDRAM type.
*/
- if (rg->type || (!rg->type && !rg->paddr))
+ if (rg->type || !rg->paddr)
return 0;
if (ranges_overlap(rg->paddr, rg->size, mem_start, mem_size)) {
rg->type = mem_type;
@@ -258,7 +260,7 @@ void __init omapfb_reserve_sdram_memblock(void)
* this point, since the driver built as a module would have problem with
* freeing / reallocating the regions.
*/
-unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart,
unsigned long sram_vstart,
unsigned long sram_size,
unsigned long pstart_avail,
@@ -332,7 +334,7 @@ void omapfb_set_ctrl_platform_data(void *data)
omapfb_config.ctrl_platform_data = data;
}
-static inline int omap_init_fb(void)
+static int __init omap_init_fb(void)
{
const struct omap_lcd_config *conf;
@@ -377,7 +379,7 @@ void omapfb_set_platform_data(struct omapfb_platform_data *data)
omapfb_config = *data;
}
-static inline int omap_init_fb(void)
+static int __init omap_init_fb(void)
{
return platform_device_register(&omap_fb_device);
}
@@ -388,7 +390,7 @@ void omapfb_reserve_sdram_memblock(void)
{
}
-unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart,
unsigned long sram_vstart,
unsigned long sram_size,
unsigned long start_avail,
@@ -407,7 +409,7 @@ void omapfb_reserve_sdram_memblock(void)
{
}
-unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart,
unsigned long sram_vstart,
unsigned long sram_size,
unsigned long start_avail,
diff --git a/arch/arm/plat-omap/fb.h b/arch/arm/plat-omap/fb.h
new file mode 100644
index 000000000000..d765d0bd8520
--- /dev/null
+++ b/arch/arm/plat-omap/fb.h
@@ -0,0 +1,10 @@
+#ifndef __PLAT_OMAP_FB_H__
+#define __PLAT_OMAP_FB_H__
+
+extern unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+ unsigned long sram_vstart,
+ unsigned long sram_size,
+ unsigned long pstart_avail,
+ unsigned long size_avail);
+
+#endif /* __PLAT_OMAP_FB_H__ */
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index 7951eefe1a0e..c05c653d1674 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -2084,9 +2084,10 @@ void omap2_gpio_prepare_for_idle(int power_state)
for (i = min; i < gpio_bank_count; i++) {
struct gpio_bank *bank = &gpio_bank[i];
- u32 l1, l2;
+ u32 l1 = 0, l2 = 0;
+ int j;
- if (bank->dbck_enable_mask)
+ for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
clk_disable(bank->dbck);
if (power_state > PWRDM_POWER_OFF)
@@ -2151,9 +2152,10 @@ void omap2_gpio_resume_after_idle(void)
min = 1;
for (i = min; i < gpio_bank_count; i++) {
struct gpio_bank *bank = &gpio_bank[i];
- u32 l, gen, gen0, gen1;
+ u32 l = 0, gen, gen0, gen1;
+ int j;
- if (bank->dbck_enable_mask)
+ for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
clk_enable(bank->dbck);
if (!workaround_enabled)
diff --git a/arch/arm/plat-omap/include/plat/common.h b/arch/arm/plat-omap/include/plat/common.h
index 9776b41ad76f..a9d69a09920d 100644
--- a/arch/arm/plat-omap/include/plat/common.h
+++ b/arch/arm/plat-omap/include/plat/common.h
@@ -47,6 +47,7 @@ struct omap_globals {
unsigned long sdrc; /* SDRAM Controller */
unsigned long sms; /* SDRAM Memory Scheduler */
unsigned long ctrl; /* System Control Module */
+ unsigned long ctrl_pad; /* PAD Control Module */
unsigned long prm; /* Power and Reset Management */
unsigned long cm; /* Clock Management */
unsigned long cm2;
@@ -66,7 +67,6 @@ void omap2_set_globals_tap(struct omap_globals *);
void omap2_set_globals_sdrc(struct omap_globals *);
void omap2_set_globals_control(struct omap_globals *);
void omap2_set_globals_prcm(struct omap_globals *);
-void omap2_set_globals_uart(struct omap_globals *);
void omap3_map_io(void);
@@ -91,7 +91,8 @@ void omap3_map_io(void);
})
extern struct device *omap2_get_mpuss_device(void);
-extern struct device *omap2_get_dsp_device(void);
+extern struct device *omap2_get_iva_device(void);
extern struct device *omap2_get_l3_device(void);
+extern struct device *omap4_get_dsp_device(void);
#endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */
diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h
index 2e2ae530fced..3fd8b4055727 100644
--- a/arch/arm/plat-omap/include/plat/cpu.h
+++ b/arch/arm/plat-omap/include/plat/cpu.h
@@ -68,10 +68,9 @@ unsigned int omap_rev(void);
#define OMAP_REVBITS_00 0x00
#define OMAP_REVBITS_01 0x01
#define OMAP_REVBITS_02 0x02
-#define OMAP_REVBITS_10 0x10
-#define OMAP_REVBITS_20 0x20
-#define OMAP_REVBITS_30 0x30
-#define OMAP_REVBITS_40 0x40
+#define OMAP_REVBITS_03 0x03
+#define OMAP_REVBITS_04 0x04
+#define OMAP_REVBITS_05 0x05
/*
* Get the CPU revision for OMAP devices
@@ -363,23 +362,24 @@ IS_OMAP_TYPE(3517, 0x3517)
/* Various silicon revisions for omap2 */
#define OMAP242X_CLASS 0x24200024
-#define OMAP2420_REV_ES1_0 0x24200024
-#define OMAP2420_REV_ES2_0 0x24201024
+#define OMAP2420_REV_ES1_0 OMAP242X_CLASS
+#define OMAP2420_REV_ES2_0 (OMAP242X_CLASS | (OMAP_REVBITS_01 << 8))
#define OMAP243X_CLASS 0x24300024
-#define OMAP2430_REV_ES1_0 0x24300024
+#define OMAP2430_REV_ES1_0 OMAP243X_CLASS
#define OMAP343X_CLASS 0x34300034
-#define OMAP3430_REV_ES1_0 0x34300034
-#define OMAP3430_REV_ES2_0 0x34301034
-#define OMAP3430_REV_ES2_1 0x34302034
-#define OMAP3430_REV_ES3_0 0x34303034
-#define OMAP3430_REV_ES3_1 0x34304034
-#define OMAP3430_REV_ES3_1_2 0x34305034
-
-#define OMAP3630_REV_ES1_0 0x36300034
-#define OMAP3630_REV_ES1_1 0x36300134
-#define OMAP3630_REV_ES1_2 0x36300234
+#define OMAP3430_REV_ES1_0 OMAP343X_CLASS
+#define OMAP3430_REV_ES2_0 (OMAP343X_CLASS | (OMAP_REVBITS_01 << 8))
+#define OMAP3430_REV_ES2_1 (OMAP343X_CLASS | (OMAP_REVBITS_02 << 8))
+#define OMAP3430_REV_ES3_0 (OMAP343X_CLASS | (OMAP_REVBITS_03 << 8))
+#define OMAP3430_REV_ES3_1 (OMAP343X_CLASS | (OMAP_REVBITS_04 << 8))
+#define OMAP3430_REV_ES3_1_2 (OMAP343X_CLASS | (OMAP_REVBITS_05 << 8))
+
+#define OMAP363X_CLASS 0x36300034
+#define OMAP3630_REV_ES1_0 OMAP363X_CLASS
+#define OMAP3630_REV_ES1_1 (OMAP363X_CLASS | (OMAP_REVBITS_01 << 8))
+#define OMAP3630_REV_ES1_2 (OMAP363X_CLASS | (OMAP_REVBITS_02 << 8))
#define OMAP35XX_CLASS 0x35000034
#define OMAP3503_REV(v) (OMAP35XX_CLASS | (0x3503 << 16) | (v << 8))
@@ -390,7 +390,8 @@ IS_OMAP_TYPE(3517, 0x3517)
#define OMAP3517_REV(v) (OMAP35XX_CLASS | (0x3517 << 16) | (v << 8))
#define OMAP443X_CLASS 0x44300044
-#define OMAP4430_REV_ES1_0 0x44300044
+#define OMAP4430_REV_ES1_0 OMAP443X_CLASS
+#define OMAP4430_REV_ES2_0 0x44301044
/*
* omap_chip bits
@@ -417,10 +418,12 @@ IS_OMAP_TYPE(3517, 0x3517)
#define CHIP_IS_OMAP4430ES1 (1 << 8)
#define CHIP_IS_OMAP3630ES1_1 (1 << 9)
#define CHIP_IS_OMAP3630ES1_2 (1 << 10)
+#define CHIP_IS_OMAP4430ES2 (1 << 11)
#define CHIP_IS_OMAP24XX (CHIP_IS_OMAP2420 | CHIP_IS_OMAP2430)
-#define CHIP_IS_OMAP4430 (CHIP_IS_OMAP4430ES1)
+#define CHIP_IS_OMAP4430 (CHIP_IS_OMAP4430ES1 | \
+ CHIP_IS_OMAP4430ES2)
/*
* "GE" here represents "greater than or equal to" in terms of ES
diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h
index 8bd15bdb4132..c915a661f1f5 100644
--- a/arch/arm/plat-omap/include/plat/display.h
+++ b/arch/arm/plat-omap/include/plat/display.h
@@ -81,37 +81,6 @@ enum omap_color_mode {
OMAP_DSS_COLOR_ARGB32 = 1 << 11, /* ARGB32 */
OMAP_DSS_COLOR_RGBA32 = 1 << 12, /* RGBA32 */
OMAP_DSS_COLOR_RGBX32 = 1 << 13, /* RGBx32 */
-
- OMAP_DSS_COLOR_GFX_OMAP2 =
- OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
- OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
- OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
- OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P,
-
- OMAP_DSS_COLOR_VID_OMAP2 =
- OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
- OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
- OMAP_DSS_COLOR_UYVY,
-
- OMAP_DSS_COLOR_GFX_OMAP3 =
- OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
- OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
- OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
- OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
- OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
- OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
-
- OMAP_DSS_COLOR_VID1_OMAP3 =
- OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
- OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P |
- OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY,
-
- OMAP_DSS_COLOR_VID2_OMAP3 =
- OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
- OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
- OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
- OMAP_DSS_COLOR_UYVY | OMAP_DSS_COLOR_ARGB32 |
- OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
};
enum omap_lcd_display_type {
diff --git a/arch/arm/plat-omap/include/plat/dma.h b/arch/arm/plat-omap/include/plat/dma.h
index af3a03941add..0cce4ca83aa0 100644
--- a/arch/arm/plat-omap/include/plat/dma.h
+++ b/arch/arm/plat-omap/include/plat/dma.h
@@ -319,6 +319,8 @@
#define OMAP34XX_DMA_USIM_TX 79 /* S_DMA_78 */
#define OMAP34XX_DMA_USIM_RX 80 /* S_DMA_79 */
+#define OMAP36XX_DMA_UART4_TX 81 /* S_DMA_80 */
+#define OMAP36XX_DMA_UART4_RX 82 /* S_DMA_81 */
/*----------------------------------------------------------------------------*/
#define OMAP1_DMA_TOUT_IRQ (1 << 0)
@@ -335,6 +337,10 @@
#define OMAP2_DMA_MISALIGNED_ERR_IRQ (1 << 11)
#define OMAP_DMA_CCR_EN (1 << 7)
+#define OMAP_DMA_CCR_RD_ACTIVE (1 << 9)
+#define OMAP_DMA_CCR_WR_ACTIVE (1 << 10)
+#define OMAP_DMA_CCR_SEL_SRC_DST_SYNC (1 << 24)
+#define OMAP_DMA_CCR_BUFFERING_DISABLE (1 << 25)
#define OMAP_DMA_DATA_TYPE_S8 0x00
#define OMAP_DMA_DATA_TYPE_S16 0x01
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 20f1054c0a80..dfa3aff9761b 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -45,6 +45,8 @@
#define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02
struct omap_dm_timer;
+extern struct omap_dm_timer *gptimer_wakeup;
+extern struct sys_timer omap_timer;
struct clk;
int omap_dm_timer_init(void);
diff --git a/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h b/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h
new file mode 100644
index 000000000000..872de0bf1e6b
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h
@@ -0,0 +1,35 @@
+/*
+ * arch/arm/plat-omap/include/plat/gpmc-smsc911x.h
+ *
+ * Copyright (C) 2009 Li-Pro.Net
+ * Stephan Linz <linz@li-pro.net>
+ *
+ * Modified from arch/arm/plat-omap/include/plat/gpmc-smc91x.h
+ *
+ * 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_ARCH_OMAP_GPMC_SMSC911X_H__
+
+struct omap_smsc911x_platform_data {
+ int cs;
+ int gpio_irq;
+ int gpio_reset;
+ u32 flags;
+};
+
+#if defined(CONFIG_SMSC911X) || \
+ defined(CONFIG_SMSC911X_MODULE)
+
+extern void gpmc_smsc911x_init(struct omap_smsc911x_platform_data *d);
+
+#else
+
+static inline void gpmc_smsc911x_init(struct omap_smsc911x_platform_data *d)
+{
+}
+
+#endif
+#endif
diff --git a/arch/arm/plat-omap/include/plat/i2c.h b/arch/arm/plat-omap/include/plat/i2c.h
index 87f6bf2ea4fa..36a0befd6168 100644
--- a/arch/arm/plat-omap/include/plat/i2c.h
+++ b/arch/arm/plat-omap/include/plat/i2c.h
@@ -18,6 +18,8 @@
* 02110-1301 USA
*
*/
+#ifndef __ASM__ARCH_OMAP_I2C_H
+#define __ASM__ARCH_OMAP_I2C_H
#include <linux/i2c.h>
@@ -36,3 +38,5 @@ static inline int omap_register_i2c_bus(int bus_id, u32 clkrate,
void __init omap1_i2c_mux_pins(int bus_id);
void __init omap2_i2c_mux_pins(int bus_id);
+
+#endif /* __ASM__ARCH_OMAP_I2C_H */
diff --git a/arch/arm/plat-omap/include/plat/irqs.h b/arch/arm/plat-omap/include/plat/irqs.h
index c01d9f08a198..65e20a686713 100644
--- a/arch/arm/plat-omap/include/plat/irqs.h
+++ b/arch/arm/plat-omap/include/plat/irqs.h
@@ -345,6 +345,8 @@
#define INT_34XX_MMC3_IRQ 94
#define INT_34XX_GPT12_IRQ 95
+#define INT_36XX_UART4_IRQ 80
+
#define INT_35XX_HECC0_IRQ 24
#define INT_35XX_HECC1_IRQ 28
#define INT_35XX_EMAC_C0_RXTHRESH_IRQ 67
diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h
index b4ff6a11a8f2..b87d83ccd545 100644
--- a/arch/arm/plat-omap/include/plat/mcbsp.h
+++ b/arch/arm/plat-omap/include/plat/mcbsp.h
@@ -30,6 +30,13 @@
#include <mach/hardware.h>
#include <plat/clock.h>
+/* macro for building platform_device for McBSP ports */
+#define OMAP_MCBSP_PLATFORM_DEVICE(port_nr) \
+static struct platform_device omap_mcbsp##port_nr = { \
+ .name = "omap-mcbsp-dai", \
+ .id = OMAP_MCBSP##port_nr, \
+}
+
#define OMAP7XX_MCBSP1_BASE 0xfffb1000
#define OMAP7XX_MCBSP2_BASE 0xfffb1800
@@ -312,6 +319,18 @@
#define RFSREN 0x0002
#define RSYNCERREN 0x0001
+/* CLKR signal muxing options */
+#define CLKR_SRC_CLKR 0
+#define CLKR_SRC_CLKX 1
+
+/* FSR signal muxing options */
+#define FSR_SRC_FSR 0
+#define FSR_SRC_FSX 1
+
+/* McBSP functional clock sources */
+#define MCBSP_CLKS_PRCM_SRC 0
+#define MCBSP_CLKS_PAD_SRC 1
+
/* we don't do multichannel for now */
struct omap_mcbsp_reg_cfg {
u16 spcr2;
@@ -398,6 +417,7 @@ struct omap_mcbsp_spi_cfg {
struct omap_mcbsp_ops {
void (*request)(unsigned int);
void (*free)(unsigned int);
+ int (*set_clks_src)(u8, u8);
};
struct omap_mcbsp_platform_data {
@@ -464,6 +484,9 @@ struct omap_mcbsp {
extern struct omap_mcbsp **mcbsp_ptr;
extern int omap_mcbsp_count, omap_mcbsp_cache_size;
+#define omap_mcbsp_check_valid_id(id) (id < omap_mcbsp_count)
+#define id_to_mcbsp_ptr(id) mcbsp_ptr[id];
+
int omap_mcbsp_init(void);
void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
int size);
@@ -502,6 +525,8 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word);
int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word);
+/* McBSP functional clock source changing function */
+extern int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id);
/* SPI specific API */
void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg);
@@ -510,6 +535,10 @@ int omap_mcbsp_pollread(unsigned int id, u16 * buf);
int omap_mcbsp_pollwrite(unsigned int id, u16 buf);
int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type);
+/* McBSP signal muxing API */
+void omap2_mcbsp1_mux_clkr_src(u8 mux);
+void omap2_mcbsp1_mux_fsr_src(u8 mux);
+
#ifdef CONFIG_ARCH_OMAP3
/* Sidetone specific API */
int omap_st_set_chgain(unsigned int id, int channel, s16 chgain);
diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h
index 9b89ec601ee2..f57f36abb07e 100644
--- a/arch/arm/plat-omap/include/plat/mmc.h
+++ b/arch/arm/plat-omap/include/plat/mmc.h
@@ -71,12 +71,17 @@ struct omap_mmc_platform_data {
u64 dma_mask;
+ /* Register offset deviation */
+ u16 reg_offset;
+
struct omap_mmc_slot_data {
- /* 4 wire signaling is optional, and is used for SD/SDIO/HSMMC;
- * 8 wire signaling is also optional, and is used with HSMMC
+ /*
+ * 4/8 wires and any additional host capabilities
+ * need to OR'd all capabilities (ref. linux/mmc/host.h)
*/
- u8 wires;
+ u8 wires; /* Used for the MMC driver on omap1 and 2420 */
+ u32 caps; /* Used for the MMC driver on 2430 and later */
/*
* nomux means "standard" muxing is wrong on this board, and
@@ -104,6 +109,7 @@ struct omap_mmc_platform_data {
/* we can put the features above into this variable */
#define HSMMC_HAS_PBIAS (1 << 0)
+#define HSMMC_HAS_UPDATED_RESET (1 << 1)
unsigned features;
int switch_pin; /* gpio (card detect) */
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
new file mode 100644
index 000000000000..c8dae02f0704
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -0,0 +1,128 @@
+/*
+ * Driver for OMAP-UART controller.
+ * Based on drivers/serial/8250.c
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * Authors:
+ * Govindraj R <govindraj.raja@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __OMAP_SERIAL_H__
+#define __OMAP_SERIAL_H__
+
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+
+#include <plat/mux.h>
+
+#define DRIVER_NAME "omap-hsuart"
+
+/*
+ * Use tty device name as ttyO, [O -> OMAP]
+ * in bootargs we specify as console=ttyO0 if uart1
+ * is used as console uart.
+ */
+#define OMAP_SERIAL_NAME "ttyO"
+
+#define OMAP_MDR1_DISABLE 0x07
+#define OMAP_MDR1_MODE13X 0x03
+#define OMAP_MDR1_MODE16X 0x00
+#define OMAP_MODE13X_SPEED 230400
+
+/*
+ * LCR = 0XBF: Switch to Configuration Mode B.
+ * In configuration mode b allow access
+ * to EFR,DLL,DLH.
+ * Reference OMAP TRM Chapter 17
+ * Section: 1.4.3 Mode Selection
+ */
+#define OMAP_UART_LCR_CONF_MDB 0XBF
+
+/* WER = 0x7F
+ * Enable module level wakeup in WER reg
+ */
+#define OMAP_UART_WER_MOD_WKUP 0X7F
+
+/* Enable XON/XOFF flow control on output */
+#define OMAP_UART_SW_TX 0x04
+
+/* Enable XON/XOFF flow control on input */
+#define OMAP_UART_SW_RX 0x04
+
+#define OMAP_UART_SYSC_RESET 0X07
+#define OMAP_UART_TCR_TRIG 0X0F
+#define OMAP_UART_SW_CLR 0XF0
+#define OMAP_UART_FIFO_CLR 0X06
+
+#define OMAP_UART_DMA_CH_FREE -1
+
+#define RX_TIMEOUT (3 * HZ)
+#define OMAP_MAX_HSUART_PORTS 4
+
+#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
+
+struct omap_uart_port_info {
+ bool dma_enabled; /* To specify DMA Mode */
+ unsigned int uartclk; /* UART clock rate */
+ void __iomem *membase; /* ioremap cookie or NULL */
+ resource_size_t mapbase; /* resource base */
+ unsigned long irqflags; /* request_irq flags */
+ upf_t flags; /* UPF_* flags */
+};
+
+struct uart_omap_dma {
+ u8 uart_dma_tx;
+ u8 uart_dma_rx;
+ int rx_dma_channel;
+ int tx_dma_channel;
+ dma_addr_t rx_buf_dma_phys;
+ dma_addr_t tx_buf_dma_phys;
+ unsigned int uart_base;
+ /*
+ * Buffer for rx dma.It is not required for tx because the buffer
+ * comes from port structure.
+ */
+ unsigned char *rx_buf;
+ unsigned int prev_rx_dma_pos;
+ int tx_buf_size;
+ int tx_dma_used;
+ int rx_dma_used;
+ spinlock_t tx_lock;
+ spinlock_t rx_lock;
+ /* timer to poll activity on rx dma */
+ struct timer_list rx_timer;
+ int rx_buf_size;
+ int rx_timeout;
+};
+
+struct uart_omap_port {
+ struct uart_port port;
+ struct uart_omap_dma uart_dma;
+ struct platform_device *pdev;
+
+ unsigned char ier;
+ unsigned char lcr;
+ unsigned char mcr;
+ unsigned char fcr;
+ unsigned char efr;
+
+ int use_dma;
+ /*
+ * Some bits in registers are cleared on a read, so they must
+ * be saved whenever the register is read but the bits will not
+ * be immediately processed.
+ */
+ unsigned int lsr_break_flag;
+ unsigned char msr_saved_flags;
+ char name[20];
+ unsigned long port_activity;
+};
+
+#endif /* __OMAP_SERIAL_H__ */
diff --git a/arch/arm/plat-omap/include/plat/omap24xx.h b/arch/arm/plat-omap/include/plat/omap24xx.h
index 7055672a8c68..92df9e27cc5c 100644
--- a/arch/arm/plat-omap/include/plat/omap24xx.h
+++ b/arch/arm/plat-omap/include/plat/omap24xx.h
@@ -40,7 +40,7 @@
#define OMAP24XX_IC_BASE (L4_24XX_BASE + 0xfe000)
#define OMAP24XX_IVA_INTC_BASE 0x40000000
-#define OMAP2420_CTRL_BASE L4_24XX_BASE
+#define OMAP242X_CTRL_BASE L4_24XX_BASE
#define OMAP2420_32KSYNCT_BASE (L4_24XX_BASE + 0x4000)
#define OMAP2420_PRCM_BASE (L4_24XX_BASE + 0x8000)
#define OMAP2420_CM_BASE (L4_24XX_BASE + 0x8000)
diff --git a/arch/arm/plat-omap/include/plat/omap4-keypad.h b/arch/arm/plat-omap/include/plat/omap4-keypad.h
new file mode 100644
index 000000000000..2b1d9bc1eebb
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/omap4-keypad.h
@@ -0,0 +1,14 @@
+#ifndef ARCH_ARM_PLAT_OMAP4_KEYPAD_H
+#define ARCH_ARM_PLAT_OMAP4_KEYPAD_H
+
+#include <linux/input/matrix_keypad.h>
+
+struct omap4_keypad_platform_data {
+ const struct matrix_keymap_data *keymap_data;
+
+ u8 rows;
+ u8 cols;
+};
+
+extern int omap4_keyboard_init(struct omap4_keypad_platform_data *);
+#endif
diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h
index 25cd9ac3b095..28e2d1a78433 100644
--- a/arch/arm/plat-omap/include/plat/omap_device.h
+++ b/arch/arm/plat-omap/include/plat/omap_device.h
@@ -36,6 +36,8 @@
#include <plat/omap_hwmod.h>
+extern struct device omap_device_parent;
+
/* omap_device._state values */
#define OMAP_DEVICE_STATE_UNKNOWN 0
#define OMAP_DEVICE_STATE_ENABLED 1
@@ -62,7 +64,6 @@
*
*/
struct omap_device {
- u32 magic;
struct platform_device pdev;
struct omap_hwmod **hwmods;
struct omap_device_pm_latency *pm_lats;
@@ -82,7 +83,6 @@ int omap_device_shutdown(struct platform_device *pdev);
/* Core code interface */
-bool omap_device_is_valid(struct omap_device *od);
int omap_device_count_resources(struct omap_device *od);
int omap_device_fill_resources(struct omap_device *od, struct resource *res);
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index a4e508dfaba2..7eaa8edf3b14 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -14,19 +14,16 @@
*
* These headers and macros are used to define OMAP on-chip module
* data and their integration with other OMAP modules and Linux.
- *
- * References:
- * - OMAP2420 Multimedia Processor Silicon Revision 2.1.1, 2.2 (SWPU064)
- * - OMAP2430 Multimedia Device POP Silicon Revision 2.1 (SWPU090)
- * - OMAP34xx Multimedia Device Silicon Revision 3.1 (SWPU108)
- * - OMAP4430 Multimedia Device Silicon Revision 1.0 (SWPU140)
- * - Open Core Protocol Specification 2.2
+ * Copious documentation and references can also be found in the
+ * omap_hwmod code, in arch/arm/mach-omap2/omap_hwmod.c (as of this
+ * writing).
*
* To do:
* - add interconnect error log structures
* - add pinmuxing
* - init_conn_id_bit (CONNID_BIT_VECTOR)
* - implement default hwmod SMS/SDRC flags?
+ * - remove unused fields
*
*/
#ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD_H
@@ -35,6 +32,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/ioport.h>
+#include <linux/mutex.h>
#include <plat/cpu.h>
struct omap_device;
@@ -96,7 +94,7 @@ struct omap_hwmod_irq_info {
/**
* struct omap_hwmod_dma_info - DMA channels used by the hwmod
* @name: name of the DMA channel (module local name)
- * @dma_ch: DMA channel ID
+ * @dma_req: DMA request ID
*
* @name should be something short, e.g., "tx" or "rx". It is for use
* by platform_get_resource_byname(). It is defined locally to the
@@ -104,7 +102,20 @@ struct omap_hwmod_irq_info {
*/
struct omap_hwmod_dma_info {
const char *name;
- u16 dma_ch;
+ u16 dma_req;
+};
+
+/**
+ * struct omap_hwmod_rst_info - IPs reset lines use by hwmod
+ * @name: name of the reset line (module local name)
+ * @rst_shift: Offset of the reset bit
+ *
+ * @name should be something short, e.g., "cpu0" or "rst". It is defined
+ * locally to the hwmod.
+ */
+struct omap_hwmod_rst_info {
+ const char *name;
+ u8 rst_shift;
};
/**
@@ -237,8 +248,9 @@ struct omap_hwmod_ocp_if {
#define SYSC_HAS_CLOCKACTIVITY (1 << 4)
#define SYSC_HAS_SIDLEMODE (1 << 5)
#define SYSC_HAS_MIDLEMODE (1 << 6)
-#define SYSS_MISSING (1 << 7)
+#define SYSS_HAS_RESET_STATUS (1 << 7)
#define SYSC_NO_CACHE (1 << 8) /* XXX SW flag, belongs elsewhere */
+#define SYSC_HAS_RESET_STATUS (1 << 9)
/* omap_hwmod_sysconfig.clockact flags */
#define CLOCKACT_TEST_BOTH 0x0
@@ -327,10 +339,12 @@ struct omap_hwmod_omap2_prcm {
/**
* struct omap_hwmod_omap4_prcm - OMAP4-specific PRCM data
* @clkctrl_reg: PRCM address of the clock control register
+ * @rstctrl_reg: adress of the XXX_RSTCTRL register located in the PRM
* @submodule_wkdep_bit: bit shift of the WKDEP range
*/
struct omap_hwmod_omap4_prcm {
void __iomem *clkctrl_reg;
+ void __iomem *rstctrl_reg;
u8 submodule_wkdep_bit;
};
@@ -352,6 +366,11 @@ struct omap_hwmod_omap4_prcm {
* HWMOD_SET_DEFAULT_CLOCKACT: program CLOCKACTIVITY bits at startup
* HWMOD_NO_IDLEST : this module does not have idle status - this is the case
* only for few initiator modules on OMAP2 & 3.
+ * HWMOD_CONTROL_OPT_CLKS_IN_RESET: Enable all optional clocks during reset.
+ * This is needed for devices like DSS that require optional clocks enabled
+ * in order to complete the reset. Optional clocks will be disabled
+ * again after the reset.
+ * HWMOD_16BIT_REG: Module has 16bit registers
*/
#define HWMOD_SWSUP_SIDLE (1 << 0)
#define HWMOD_SWSUP_MSTANDBY (1 << 1)
@@ -360,6 +379,8 @@ struct omap_hwmod_omap4_prcm {
#define HWMOD_NO_OCP_AUTOIDLE (1 << 4)
#define HWMOD_SET_DEFAULT_CLOCKACT (1 << 5)
#define HWMOD_NO_IDLEST (1 << 6)
+#define HWMOD_CONTROL_OPT_CLKS_IN_RESET (1 << 7)
+#define HWMOD_16BIT_REG (1 << 8)
/*
* omap_hwmod._int_flags definitions
@@ -410,7 +431,7 @@ struct omap_hwmod_class {
* @class: struct omap_hwmod_class * to the class of this hwmod
* @od: struct omap_device currently associated with this hwmod (internal use)
* @mpu_irqs: ptr to an array of MPU IRQs (see also mpu_irqs_cnt)
- * @sdma_chs: ptr to an array of SDMA channel IDs (see also sdma_chs_cnt)
+ * @sdma_reqs: ptr to an array of System DMA request IDs (see sdma_reqs_cnt)
* @prcm: PRCM data pertaining to this hwmod
* @main_clk: main clock: OMAP clock name
* @_clk: pointer to the main struct clk (filled in at runtime)
@@ -424,7 +445,7 @@ struct omap_hwmod_class {
* @msuspendmux_reg_id: CONTROL_MSUSPENDMUX register ID (1-6)
* @msuspendmux_shift: CONTROL_MSUSPENDMUX register bit shift
* @mpu_irqs_cnt: number of @mpu_irqs
- * @sdma_chs_cnt: number of @sdma_chs
+ * @sdma_reqs_cnt: number of @sdma_reqs
* @opt_clks_cnt: number of @opt_clks
* @master_cnt: number of @master entries
* @slaves_cnt: number of @slave entries
@@ -433,6 +454,7 @@ struct omap_hwmod_class {
* @_state: internal-use hwmod state
* @flags: hwmod flags (documented below)
* @omap_chip: OMAP chips this hwmod is present on
+ * @_mutex: mutex serializing operations on this hwmod
* @node: list node for hwmod list (internal use)
*
* @main_clk refers to this module's "main clock," which for our
@@ -448,7 +470,8 @@ struct omap_hwmod {
struct omap_hwmod_class *class;
struct omap_device *od;
struct omap_hwmod_irq_info *mpu_irqs;
- struct omap_hwmod_dma_info *sdma_chs;
+ struct omap_hwmod_dma_info *sdma_reqs;
+ struct omap_hwmod_rst_info *rst_lines;
union {
struct omap_hwmod_omap2_prcm omap2;
struct omap_hwmod_omap4_prcm omap4;
@@ -461,6 +484,7 @@ struct omap_hwmod {
void *dev_attr;
u32 _sysc_cache;
void __iomem *_mpu_rt_va;
+ struct mutex _mutex;
struct list_head node;
u16 flags;
u8 _mpu_port_index;
@@ -468,7 +492,8 @@ struct omap_hwmod {
u8 msuspendmux_shift;
u8 response_lat;
u8 mpu_irqs_cnt;
- u8 sdma_chs_cnt;
+ u8 sdma_reqs_cnt;
+ u8 rst_lines_cnt;
u8 opt_clks_cnt;
u8 masters_cnt;
u8 slaves_cnt;
@@ -492,6 +517,10 @@ int omap_hwmod_idle(struct omap_hwmod *oh);
int _omap_hwmod_idle(struct omap_hwmod *oh);
int omap_hwmod_shutdown(struct omap_hwmod *oh);
+int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name);
+int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name);
+int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name);
+
int omap_hwmod_enable_clocks(struct omap_hwmod *oh);
int omap_hwmod_disable_clocks(struct omap_hwmod *oh);
@@ -500,8 +529,8 @@ int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode);
int omap_hwmod_reset(struct omap_hwmod *oh);
void omap_hwmod_ocp_barrier(struct omap_hwmod *oh);
-void omap_hwmod_writel(u32 v, struct omap_hwmod *oh, u16 reg_offs);
-u32 omap_hwmod_readl(struct omap_hwmod *oh, u16 reg_offs);
+void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs);
+u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs);
int omap_hwmod_count_resources(struct omap_hwmod *oh);
int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res);
@@ -534,5 +563,6 @@ int omap_hwmod_for_each_by_class(const char *classname,
extern int omap2420_hwmod_init(void);
extern int omap2430_hwmod_init(void);
extern int omap3xxx_hwmod_init(void);
+extern int omap44xx_hwmod_init(void);
#endif
diff --git a/arch/arm/plat-omap/include/plat/powerdomain.h b/arch/arm/plat-omap/include/plat/powerdomain.h
index fb6ec74fe39e..9ca420dcd2f8 100644
--- a/arch/arm/plat-omap/include/plat/powerdomain.h
+++ b/arch/arm/plat-omap/include/plat/powerdomain.h
@@ -32,6 +32,7 @@
/* Powerdomain allowable state bitfields */
#define PWRSTS_ON (1 << PWRDM_POWER_ON)
+#define PWRSTS_OFF (1 << PWRDM_POWER_OFF)
#define PWRSTS_OFF_ON ((1 << PWRDM_POWER_OFF) | \
(1 << PWRDM_POWER_ON))
@@ -161,5 +162,6 @@ int pwrdm_state_switch(struct powerdomain *pwrdm);
int pwrdm_clkdm_state_switch(struct clockdomain *clkdm);
int pwrdm_pre_transition(void);
int pwrdm_post_transition(void);
+int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
#endif
diff --git a/arch/arm/plat-omap/include/plat/prcm.h b/arch/arm/plat-omap/include/plat/prcm.h
index 9fbd91419cd1..ab77442e42ab 100644
--- a/arch/arm/plat-omap/include/plat/prcm.h
+++ b/arch/arm/plat-omap/include/plat/prcm.h
@@ -38,6 +38,8 @@ u32 prm_read_mod_reg(s16 module, u16 idx);
void prm_write_mod_reg(u32 val, s16 module, u16 idx);
u32 prm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx);
u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask);
+u32 omap4_prm_read_bits_shift(void __iomem *reg, u32 mask);
+u32 omap4_prm_rmw_reg_bits(u32 mask, u32 bits, void __iomem *reg);
u32 cm_read_mod_reg(s16 module, u16 idx);
void cm_write_mod_reg(u32 val, s16 module, u16 idx);
u32 cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx);
diff --git a/arch/arm/plat-omap/include/plat/sdrc.h b/arch/arm/plat-omap/include/plat/sdrc.h
index 7b76f50564ba..efd87c8dda69 100644
--- a/arch/arm/plat-omap/include/plat/sdrc.h
+++ b/arch/arm/plat-omap/include/plat/sdrc.h
@@ -147,6 +147,7 @@ struct memory_timings {
};
extern void omap2xxx_sdrc_init_params(u32 force_lock_to_unlock_mode);
+struct omap_sdrc_params *rx51_get_sdram_timings(void);
u32 omap2xxx_sdrc_dll_is_unlocked(void);
u32 omap2xxx_sdrc_reprogram(u32 level, u32 force);
diff --git a/arch/arm/plat-omap/include/plat/sram.h b/arch/arm/plat-omap/include/plat/sram.h
index 16a1b458d53c..5905100b29a1 100644
--- a/arch/arm/plat-omap/include/plat/sram.h
+++ b/arch/arm/plat-omap/include/plat/sram.h
@@ -11,7 +11,6 @@
#ifndef __ARCH_ARM_OMAP_SRAM_H
#define __ARCH_ARM_OMAP_SRAM_H
-extern int __init omap_sram_init(void);
extern void * omap_sram_push(void * start, unsigned long size);
extern void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl);
diff --git a/arch/arm/plat-omap/include/plat/uncompress.h b/arch/arm/plat-omap/include/plat/uncompress.h
index ddf723be48dc..9036e374e0ac 100644
--- a/arch/arm/plat-omap/include/plat/uncompress.h
+++ b/arch/arm/plat-omap/include/plat/uncompress.h
@@ -139,10 +139,14 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
DEBUG_LL_OMAP2(1, omap3evm);
DEBUG_LL_OMAP3(1, omap_3430sdp);
DEBUG_LL_OMAP3(1, omap_3630sdp);
+ DEBUG_LL_OMAP3(1, omap3530_lv_som);
+ DEBUG_LL_OMAP3(1, omap3_torpedo);
/* omap3 based boards using UART3 */
DEBUG_LL_OMAP3(3, cm_t35);
+ DEBUG_LL_OMAP3(3, cm_t3517);
DEBUG_LL_OMAP3(3, igep0020);
+ DEBUG_LL_OMAP3(3, igep0030);
DEBUG_LL_OMAP3(3, nokia_rx51);
DEBUG_LL_OMAP3(3, omap3517evm);
DEBUG_LL_OMAP3(3, omap3_beagle);
@@ -153,6 +157,7 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
/* omap4 based boards using UART3 */
DEBUG_LL_OMAP4(3, omap_4430sdp);
+ DEBUG_LL_OMAP4(3, omap4_panda);
/* zoom2/3 external uart */
DEBUG_LL_ZOOM(omap_zoom2);
diff --git a/arch/arm/plat-omap/include/plat/usb.h b/arch/arm/plat-omap/include/plat/usb.h
index 9feddacfe850..59c7fe731f28 100644
--- a/arch/arm/plat-omap/include/plat/usb.h
+++ b/arch/arm/plat-omap/include/plat/usb.h
@@ -105,7 +105,7 @@ static inline void omap1_usb_init(struct omap_usb_config *pdata)
#if defined(CONFIG_ARCH_OMAP_OTG) || defined(CONFIG_ARCH_OMAP_OTG_MODULE)
void omap2_usbfs_init(struct omap_usb_config *pdata);
#else
-static inline omap2_usbfs_init(struct omap_usb_config *pdata)
+static inline void omap2_usbfs_init(struct omap_usb_config *pdata)
{
}
#endif
diff --git a/arch/arm/plat-omap/include/plat/vrfb.h b/arch/arm/plat-omap/include/plat/vrfb.h
index d8a03ced3b10..3792bdea2f6d 100644
--- a/arch/arm/plat-omap/include/plat/vrfb.h
+++ b/arch/arm/plat-omap/include/plat/vrfb.h
@@ -35,6 +35,7 @@ struct vrfb {
bool yuv_mode;
};
+#ifdef CONFIG_OMAP2_VRFB
extern int omap_vrfb_request_ctx(struct vrfb *vrfb);
extern void omap_vrfb_release_ctx(struct vrfb *vrfb);
extern void omap_vrfb_adjust_size(u16 *width, u16 *height,
@@ -47,4 +48,19 @@ extern void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
extern int omap_vrfb_map_angle(struct vrfb *vrfb, u16 height, u8 rot);
extern void omap_vrfb_restore_context(void);
+#else
+static inline int omap_vrfb_request_ctx(struct vrfb *vrfb) { return 0; }
+static inline void omap_vrfb_release_ctx(struct vrfb *vrfb) {}
+static inline void omap_vrfb_adjust_size(u16 *width, u16 *height,
+ u8 bytespp) {}
+static inline u32 omap_vrfb_min_phys_size(u16 width, u16 height, u8 bytespp)
+ { return 0; }
+static inline u16 omap_vrfb_max_height(u32 phys_size, u16 width, u8 bytespp)
+ { return 0; }
+static inline void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
+ u16 width, u16 height, unsigned bytespp, bool yuv_mode) {}
+static inline int omap_vrfb_map_angle(struct vrfb *vrfb, u16 height, u8 rot)
+ { return 0; }
+static inline void omap_vrfb_restore_context(void) {}
+#endif
#endif /* __VRFB_H */
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index 0c8612fd8312..eac4b978e9fd 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -33,7 +33,7 @@
struct omap_mcbsp **mcbsp_ptr;
int omap_mcbsp_count, omap_mcbsp_cache_size;
-void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
{
if (cpu_class_is_omap1()) {
((u16 *)mcbsp->reg_cache)[reg / sizeof(u16)] = (u16)val;
@@ -47,7 +47,7 @@ void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
}
}
-int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
+static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
{
if (cpu_class_is_omap1()) {
return !from_cache ? __raw_readw(mcbsp->io_base + reg) :
@@ -62,12 +62,12 @@ int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
}
#ifdef CONFIG_ARCH_OMAP3
-void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
{
__raw_writel(val, mcbsp->st_data->io_base_st + reg);
}
-int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
+static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
{
return __raw_readl(mcbsp->st_data->io_base_st + reg);
}
@@ -80,9 +80,6 @@ int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
#define MCBSP_READ_CACHE(mcbsp, reg) \
omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
-#define omap_mcbsp_check_valid_id(id) (id < omap_mcbsp_count)
-#define id_to_mcbsp_ptr(id) mcbsp_ptr[id];
-
#define MCBSP_ST_READ(mcbsp, reg) \
omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
#define MCBSP_ST_WRITE(mcbsp, reg, val) \
@@ -878,7 +875,7 @@ EXPORT_SYMBOL(omap_mcbsp_free);
void omap_mcbsp_start(unsigned int id, int tx, int rx)
{
struct omap_mcbsp *mcbsp;
- int idle;
+ int enable_srg = 0;
u16 w;
if (!omap_mcbsp_check_valid_id(id)) {
@@ -893,10 +890,13 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx)
mcbsp->rx_word_length = (MCBSP_READ_CACHE(mcbsp, RCR1) >> 5) & 0x7;
mcbsp->tx_word_length = (MCBSP_READ_CACHE(mcbsp, XCR1) >> 5) & 0x7;
- idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
- MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
+ /* Only enable SRG, if McBSP is master */
+ w = MCBSP_READ_CACHE(mcbsp, PCR0);
+ if (w & (FSXM | FSRM | CLKXM | CLKRM))
+ enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
+ MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
- if (idle) {
+ if (enable_srg) {
/* Start the sample generator */
w = MCBSP_READ_CACHE(mcbsp, SPCR2);
MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
@@ -919,7 +919,7 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx)
*/
udelay(500);
- if (idle) {
+ if (enable_srg) {
/* Start frame sync */
w = MCBSP_READ_CACHE(mcbsp, SPCR2);
MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
@@ -1645,7 +1645,7 @@ static const struct attribute_group sidetone_attr_group = {
.attrs = (struct attribute **)sidetone_attrs,
};
-int __devinit omap_st_add(struct omap_mcbsp *mcbsp)
+static int __devinit omap_st_add(struct omap_mcbsp *mcbsp)
{
struct omap_mcbsp_platform_data *pdata = mcbsp->pdata;
struct omap_mcbsp_st_data *st_data;
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index d2b160942ccc..abe933cd8f09 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -82,6 +82,7 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/clk.h>
#include <plat/omap_device.h>
#include <plat/omap_hwmod.h>
@@ -90,12 +91,6 @@
#define USE_WAKEUP_LAT 0
#define IGNORE_WAKEUP_LAT 1
-/*
- * OMAP_DEVICE_MAGIC: used to determine whether a struct omap_device
- * obtained via container_of() is in fact a struct omap_device
- */
-#define OMAP_DEVICE_MAGIC 0xf00dcafe
-
/* Private functions */
/**
@@ -243,6 +238,44 @@ static inline struct omap_device *_find_by_pdev(struct platform_device *pdev)
return container_of(pdev, struct omap_device, pdev);
}
+/**
+ * _add_optional_clock_alias - Add clock alias for hwmod optional clocks
+ * @od: struct omap_device *od
+ *
+ * For every optional clock present per hwmod per omap_device, this function
+ * adds an entry in the clocks list of the form <dev-id=dev_name, con-id=role>
+ * if an entry is already present in it with the form <dev-id=NULL, con-id=role>
+ *
+ * The function is called from inside omap_device_build_ss(), after
+ * omap_device_register.
+ *
+ * This allows drivers to get a pointer to its optional clocks based on its role
+ * by calling clk_get(<dev*>, <role>).
+ *
+ * No return value.
+ */
+static void _add_optional_clock_alias(struct omap_device *od,
+ struct omap_hwmod *oh)
+{
+ int i;
+
+ for (i = 0; i < oh->opt_clks_cnt; i++) {
+ struct omap_hwmod_opt_clk *oc;
+ int r;
+
+ oc = &oh->opt_clks[i];
+
+ if (!oc->_clk)
+ continue;
+
+ r = clk_add_alias(oc->role, dev_name(&od->pdev.dev),
+ (char *)oc->clk, &od->pdev.dev);
+ if (r)
+ pr_err("omap_device: %s: clk_add_alias for %s failed\n",
+ dev_name(&od->pdev.dev), oc->role);
+ }
+}
+
/* Public functions for use by core code */
@@ -257,12 +290,11 @@ static inline struct omap_device *_find_by_pdev(struct platform_device *pdev)
*/
int omap_device_count_resources(struct omap_device *od)
{
- struct omap_hwmod *oh;
int c = 0;
int i;
- for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
- c += omap_hwmod_count_resources(oh);
+ for (i = 0; i < od->hwmods_cnt; i++)
+ c += omap_hwmod_count_resources(od->hwmods[i]);
pr_debug("omap_device: %s: counted %d total resources across %d "
"hwmods\n", od->pdev.name, c, od->hwmods_cnt);
@@ -289,12 +321,11 @@ int omap_device_count_resources(struct omap_device *od)
*/
int omap_device_fill_resources(struct omap_device *od, struct resource *res)
{
- struct omap_hwmod *oh;
int c = 0;
int i, r;
- for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++) {
- r = omap_hwmod_fill_resources(oh, res);
+ for (i = 0; i < od->hwmods_cnt; i++) {
+ r = omap_hwmod_fill_resources(od->hwmods[i], res);
res += r;
c += r;
}
@@ -414,15 +445,15 @@ struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
od->pm_lats = pm_lats;
od->pm_lats_cnt = pm_lats_cnt;
- od->magic = OMAP_DEVICE_MAGIC;
-
if (is_early_device)
ret = omap_early_device_register(od);
else
ret = omap_device_register(od);
- for (i = 0; i < oh_cnt; i++)
+ for (i = 0; i < oh_cnt; i++) {
hwmods[i]->od = od;
+ _add_optional_clock_alias(od, hwmods[i]);
+ }
if (ret)
goto odbs_exit4;
@@ -473,6 +504,7 @@ int omap_device_register(struct omap_device *od)
{
pr_debug("omap_device: %s: registering\n", od->pdev.name);
+ od->pdev.dev.parent = &omap_device_parent;
return platform_device_register(&od->pdev);
}
@@ -566,7 +598,6 @@ int omap_device_shutdown(struct platform_device *pdev)
{
int ret, i;
struct omap_device *od;
- struct omap_hwmod *oh;
od = _find_by_pdev(pdev);
@@ -579,8 +610,8 @@ int omap_device_shutdown(struct platform_device *pdev)
ret = _omap_device_deactivate(od, IGNORE_WAKEUP_LAT);
- for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
- omap_hwmod_shutdown(oh);
+ for (i = 0; i < od->hwmods_cnt; i++)
+ omap_hwmod_shutdown(od->hwmods[i]);
od->_state = OMAP_DEVICE_STATE_SHUTDOWN;
@@ -627,18 +658,6 @@ int omap_device_align_pm_lat(struct platform_device *pdev,
}
/**
- * omap_device_is_valid - Check if pointer is a valid omap_device
- * @od: struct omap_device *
- *
- * Return whether struct omap_device pointer @od points to a valid
- * omap_device.
- */
-bool omap_device_is_valid(struct omap_device *od)
-{
- return (od && od->magic == OMAP_DEVICE_MAGIC);
-}
-
-/**
* omap_device_get_pwrdm - return the powerdomain * associated with @od
* @od: struct omap_device *
*
@@ -692,11 +711,10 @@ void __iomem *omap_device_get_rt_va(struct omap_device *od)
*/
int omap_device_enable_hwmods(struct omap_device *od)
{
- struct omap_hwmod *oh;
int i;
- for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
- omap_hwmod_enable(oh);
+ for (i = 0; i < od->hwmods_cnt; i++)
+ omap_hwmod_enable(od->hwmods[i]);
/* XXX pass along return value here? */
return 0;
@@ -710,11 +728,10 @@ int omap_device_enable_hwmods(struct omap_device *od)
*/
int omap_device_idle_hwmods(struct omap_device *od)
{
- struct omap_hwmod *oh;
int i;
- for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
- omap_hwmod_idle(oh);
+ for (i = 0; i < od->hwmods_cnt; i++)
+ omap_hwmod_idle(od->hwmods[i]);
/* XXX pass along return value here? */
return 0;
@@ -729,11 +746,10 @@ int omap_device_idle_hwmods(struct omap_device *od)
*/
int omap_device_disable_clocks(struct omap_device *od)
{
- struct omap_hwmod *oh;
int i;
- for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
- omap_hwmod_disable_clocks(oh);
+ for (i = 0; i < od->hwmods_cnt; i++)
+ omap_hwmod_disable_clocks(od->hwmods[i]);
/* XXX pass along return value here? */
return 0;
@@ -748,12 +764,22 @@ int omap_device_disable_clocks(struct omap_device *od)
*/
int omap_device_enable_clocks(struct omap_device *od)
{
- struct omap_hwmod *oh;
int i;
- for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
- omap_hwmod_enable_clocks(oh);
+ for (i = 0; i < od->hwmods_cnt; i++)
+ omap_hwmod_enable_clocks(od->hwmods[i]);
/* XXX pass along return value here? */
return 0;
}
+
+struct device omap_device_parent = {
+ .init_name = "omap",
+ .parent = &platform_bus,
+};
+
+static int __init omap_device_init(void)
+{
+ return device_register(&omap_device_parent);
+}
+core_initcall(omap_device_init);
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index 10b3b4c63372..e2c8eebe6b3a 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/omapfb.h>
#include <asm/tlb.h>
#include <asm/cacheflush.h>
@@ -30,8 +31,8 @@
#include <plat/cpu.h>
#include <plat/vram.h>
-#include <plat/control.h>
-
+#include "sram.h"
+#include "fb.h"
#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
# include "../mach-omap2/prm.h"
# include "../mach-omap2/cm.h"
@@ -53,7 +54,7 @@
#define OMAP4_SRAM_PUB_PA (OMAP4_SRAM_PA + 0x4000)
#define OMAP4_SRAM_PUB_VA (OMAP4_SRAM_VA + 0x4000)
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2PLUS)
#define SRAM_BOOTLOADER_SZ 0x00
#else
#define SRAM_BOOTLOADER_SZ 0x80
@@ -68,7 +69,6 @@
#define OMAP34XX_VA_WRITEPERM0 OMAP2_L3_IO_ADDRESS(0x68012858)
#define OMAP34XX_VA_ADDR_MATCH2 OMAP2_L3_IO_ADDRESS(0x68012880)
#define OMAP34XX_VA_SMS_RG_ATT0 OMAP2_L3_IO_ADDRESS(0x6C000048)
-#define OMAP34XX_VA_CONTROL_STAT OMAP2_L4_IO_ADDRESS(0x480022F0)
#define GP_DEVICE 0x300
@@ -79,12 +79,6 @@ static unsigned long omap_sram_base;
static unsigned long omap_sram_size;
static unsigned long omap_sram_ceil;
-extern unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
- unsigned long sram_vstart,
- unsigned long sram_size,
- unsigned long pstart_avail,
- unsigned long size_avail);
-
/*
* Depending on the target RAMFS firewall setup, the public usable amount of
* SRAM varies. The default accessible size for all device types is 2k. A GP
@@ -93,16 +87,7 @@ extern unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
*/
static int is_sram_locked(void)
{
- int type = 0;
-
- if (cpu_is_omap44xx())
- /* Not yet supported */
- return 0;
-
- if (cpu_is_omap242x())
- type = omap_rev() & OMAP2_DEVICETYPE_MASK;
-
- if (type == GP_DEVICE) {
+ if (OMAP2_DEVICE_TYPE_GP == omap_type()) {
/* RAMFW: R/W access to all initiators for all qualifier sets */
if (cpu_is_omap242x()) {
__raw_writel(0xFF, OMAP24XX_VA_REQINFOPERM0); /* all q-vects */
@@ -127,7 +112,7 @@ static int is_sram_locked(void)
* to secure SRAM will hang the system. Also the SRAM is not
* yet mapped at this point.
*/
-void __init omap_detect_sram(void)
+static void __init omap_detect_sram(void)
{
unsigned long reserved;
@@ -213,7 +198,7 @@ static struct map_desc omap_sram_io_desc[] __initdata = {
/*
* Note that we cannot use ioremap for SRAM, as clock init needs SRAM early.
*/
-void __init omap_map_sram(void)
+static void __init omap_map_sram(void)
{
unsigned long base;
@@ -330,7 +315,7 @@ u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass)
#endif
#ifdef CONFIG_ARCH_OMAP2420
-int __init omap242x_sram_init(void)
+static int __init omap242x_sram_init(void)
{
_omap2_sram_ddr_init = omap_sram_push(omap242x_sram_ddr_init,
omap242x_sram_ddr_init_sz);
@@ -351,7 +336,7 @@ static inline int omap242x_sram_init(void)
#endif
#ifdef CONFIG_ARCH_OMAP2430
-int __init omap243x_sram_init(void)
+static int __init omap243x_sram_init(void)
{
_omap2_sram_ddr_init = omap_sram_push(omap243x_sram_ddr_init,
omap243x_sram_ddr_init_sz);
@@ -407,7 +392,7 @@ void omap3_sram_restore_context(void)
}
#endif /* CONFIG_PM */
-int __init omap34xx_sram_init(void)
+static int __init omap34xx_sram_init(void)
{
_omap3_sram_configure_core_dpll =
omap_sram_push(omap3_sram_configure_core_dpll,
@@ -423,7 +408,7 @@ static inline int omap34xx_sram_init(void)
#endif
#ifdef CONFIG_ARCH_OMAP4
-int __init omap44xx_sram_init(void)
+static int __init omap44xx_sram_init(void)
{
printk(KERN_ERR "FIXME: %s not implemented\n", __func__);
diff --git a/arch/arm/plat-omap/sram.h b/arch/arm/plat-omap/sram.h
new file mode 100644
index 000000000000..29b43ef97f20
--- /dev/null
+++ b/arch/arm/plat-omap/sram.h
@@ -0,0 +1,6 @@
+#ifndef __PLAT_OMAP_SRAM_H__
+#define __PLAT_OMAP_SRAM_H__
+
+extern int __init omap_sram_init(void);
+
+#endif /* __PLAT_OMAP_SRAM_H__ */
diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
index 452e18438b41..2f91057a0c02 100644
--- a/arch/arm/plat-s3c24xx/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -247,7 +247,7 @@ static struct resource s3c_iis_resource[] = {
static u64 s3c_device_iis_dmamask = 0xffffffffUL;
struct platform_device s3c_device_iis = {
- .name = "s3c2410-iis",
+ .name = "s3c24xx-iis",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_iis_resource),
.resource = s3c_iis_resource,
@@ -259,6 +259,21 @@ struct platform_device s3c_device_iis = {
EXPORT_SYMBOL(s3c_device_iis);
+/* ASoC PCM DMA */
+
+static u64 s3c_device_audio_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_pcm = {
+ .name = "s3c24xx-pcm-audio",
+ .id = -1,
+ .dev = {
+ .dma_mask = &s3c_device_audio_dmamask,
+ .coherent_dma_mask = 0xffffffffUL
+ }
+};
+
+EXPORT_SYMBOL(s3c_device_pcm);
+
/* RTC */
static struct resource s3c_rtc_resource[] = {
@@ -481,19 +496,30 @@ static struct resource s3c_ac97_resource[] = {
},
};
-static u64 s3c_device_ac97_dmamask = 0xffffffffUL;
-
struct platform_device s3c_device_ac97 = {
.name = "s3c-ac97",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_ac97_resource),
.resource = s3c_ac97_resource,
.dev = {
- .dma_mask = &s3c_device_ac97_dmamask,
+ .dma_mask = &s3c_device_audio_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};
EXPORT_SYMBOL(s3c_device_ac97);
+/* ASoC I2S */
+
+struct platform_device s3c2412_device_iis = {
+ .name = "s3c2412-iis",
+ .id = -1,
+ .dev = {
+ .dma_mask = &s3c_device_audio_dmamask,
+ .coherent_dma_mask = 0xffffffffUL
+ }
+};
+
+EXPORT_SYMBOL(s3c2412_device_iis);
+
#endif // CONFIG_CPU_S32440
diff --git a/arch/arm/plat-samsung/include/plat/adc.h b/arch/arm/plat-samsung/include/plat/adc.h
index e8382c7be10b..b258a08de591 100644
--- a/arch/arm/plat-samsung/include/plat/adc.h
+++ b/arch/arm/plat-samsung/include/plat/adc.h
@@ -1,7 +1,7 @@
/* arch/arm/plat-samsung/include/plat/adc.h
*
* Copyright (c) 2008 Simtec Electronics
- * http://armlinux.simnte.co.uk/
+ * http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* S3C ADC driver information
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 7d448e138792..c8b94279bad1 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -32,6 +32,8 @@ extern struct platform_device s3c64xx_device_iisv4;
extern struct platform_device s3c64xx_device_spi0;
extern struct platform_device s3c64xx_device_spi1;
+extern struct platform_device s3c_device_pcm;
+
extern struct platform_device s3c64xx_device_pcm0;
extern struct platform_device s3c64xx_device_pcm1;
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index 9ac87255a03a..f0dc5b8075a7 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -146,7 +146,7 @@ config BOARD_HAMMERHEAD
will cover even the most exceptional need of memory bandwidth. Together with the onboard
video decoder the board is ready for video processing.
- For more information see: http://www.miromico.com/hammerhead
+ For more information see: http://www.miromico.ch/index.php/hammerhead.html
config BOARD_FAVR_32
bool "Favr-32 LCD-board"
diff --git a/arch/avr32/include/asm/pgtable.h b/arch/avr32/include/asm/pgtable.h
index a9ae30c41e74..6fbfea61f7bb 100644
--- a/arch/avr32/include/asm/pgtable.h
+++ b/arch/avr32/include/asm/pgtable.h
@@ -319,9 +319,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
#define pte_offset_kernel(dir, address) \
((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
#define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
-#define pte_offset_map_nested(dir, address) pte_offset_kernel(dir, address)
#define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
struct vm_area_struct;
extern void update_mmu_cache(struct vm_area_struct * vma,
diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c
index 5e73c25f8f85..4aedcab7cd4b 100644
--- a/arch/avr32/kernel/ptrace.c
+++ b/arch/avr32/kernel/ptrace.c
@@ -146,9 +146,11 @@ static int ptrace_setregs(struct task_struct *tsk, const void __user *uregs)
return ret;
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret;
+ void __user *datap = (void __user *) data;
switch (request) {
/* Read the word at location addr in the child process */
@@ -158,8 +160,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
case PTRACE_PEEKUSR:
- ret = ptrace_read_user(child, addr,
- (unsigned long __user *)data);
+ ret = ptrace_read_user(child, addr, datap);
break;
/* Write the word in data at location addr */
@@ -173,11 +174,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
case PTRACE_GETREGS:
- ret = ptrace_getregs(child, (void __user *)data);
+ ret = ptrace_getregs(child, datap);
break;
case PTRACE_SETREGS:
- ret = ptrace_setregs(child, (const void __user *)data);
+ ret = ptrace_setregs(child, datap);
break;
default:
diff --git a/arch/blackfin/Kconfig.debug b/arch/blackfin/Kconfig.debug
index d1825cb24768..acb83799a215 100644
--- a/arch/blackfin/Kconfig.debug
+++ b/arch/blackfin/Kconfig.debug
@@ -102,17 +102,6 @@ config DEBUG_DOUBLEFAULT_RESET
endchoice
-config DEBUG_ICACHE_CHECK
- bool "Check Instruction cache coherency"
- depends on DEBUG_KERNEL
- depends on DEBUG_HWERR
- help
- Say Y here if you are getting weird unexplained errors. This will
- ensure that icache is what SDRAM says it should be by doing a
- byte wise comparison between SDRAM and instruction cache. This
- also relocates the irq_panic() function to L1 memory, (which is
- un-cached).
-
config DEBUG_HUNT_FOR_ZERO
bool "Catch NULL pointer reads/writes"
default y
diff --git a/arch/blackfin/configs/BF518F-EZBRD_defconfig b/arch/blackfin/configs/BF518F-EZBRD_defconfig
index 46fac1bf0605..c0b988ee30df 100644
--- a/arch/blackfin/configs/BF518F-EZBRD_defconfig
+++ b/arch/blackfin/configs/BF518F-EZBRD_defconfig
@@ -35,6 +35,7 @@ CONFIG_C_CDPRIO=y
CONFIG_BANK_3=0x99B2
CONFIG_BINFMT_FLAT=y
CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -114,7 +115,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRYPTO=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRC_CCITT=m
diff --git a/arch/blackfin/configs/BF526-EZBRD_defconfig b/arch/blackfin/configs/BF526-EZBRD_defconfig
index 80240806cf9e..864af5b68874 100644
--- a/arch/blackfin/configs/BF526-EZBRD_defconfig
+++ b/arch/blackfin/configs/BF526-EZBRD_defconfig
@@ -40,6 +40,7 @@ CONFIG_C_CDPRIO=y
CONFIG_BANK_3=0x99B2
CONFIG_BINFMT_FLAT=y
CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -152,7 +153,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRYPTO=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRC_CCITT=m
diff --git a/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig b/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig
index 08c55f6b8b7a..7b6a3370dbe2 100644
--- a/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig
+++ b/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig
@@ -9,6 +9,7 @@ CONFIG_EMBEDDED=y
# CONFIG_ELF_CORE is not set
# CONFIG_AIO is not set
CONFIG_SLAB=y
+CONFIG_MMAP_ALLOW_UNINITIALIZED=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
@@ -101,5 +102,4 @@ CONFIG_DETECT_HUNG_TASK=y
# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRC_CCITT=m
diff --git a/arch/blackfin/configs/BF527-EZKIT-V2_defconfig b/arch/blackfin/configs/BF527-EZKIT-V2_defconfig
index 4a9125558fcf..4faa6b46a352 100644
--- a/arch/blackfin/configs/BF527-EZKIT-V2_defconfig
+++ b/arch/blackfin/configs/BF527-EZKIT-V2_defconfig
@@ -20,6 +20,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_LBDAF is not set
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_BF527=y
CONFIG_BF_REV_0_2=y
@@ -38,6 +39,7 @@ CONFIG_C_CDPRIO=y
CONFIG_BANK_3=0x99B2
CONFIG_BINFMT_FLAT=y
CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -181,6 +183,5 @@ CONFIG_DEBUG_DOUBLEFAULT=y
CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRYPTO=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/blackfin/configs/BF527-EZKIT_defconfig b/arch/blackfin/configs/BF527-EZKIT_defconfig
index 8ccf3cec7534..9d893eb68243 100644
--- a/arch/blackfin/configs/BF527-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF527-EZKIT_defconfig
@@ -20,6 +20,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_LBDAF is not set
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_BF527=y
CONFIG_BF_REV_0_1=y
@@ -37,6 +38,7 @@ CONFIG_C_CDPRIO=y
CONFIG_BANK_3=0x99B2
CONFIG_BINFMT_FLAT=y
CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -173,6 +175,5 @@ CONFIG_DEBUG_DOUBLEFAULT=y
CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRYPTO=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/blackfin/configs/BF527-TLL6527M_defconfig b/arch/blackfin/configs/BF527-TLL6527M_defconfig
index 92ded5edc86c..97a2767c80f8 100644
--- a/arch/blackfin/configs/BF527-TLL6527M_defconfig
+++ b/arch/blackfin/configs/BF527-TLL6527M_defconfig
@@ -174,7 +174,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRYPTO=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRC7=m
diff --git a/arch/blackfin/configs/BF533-EZKIT_defconfig b/arch/blackfin/configs/BF533-EZKIT_defconfig
index c40e0f1c7eac..f84774360c5b 100644
--- a/arch/blackfin/configs/BF533-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF533-EZKIT_defconfig
@@ -20,6 +20,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_LBDAF is not set
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_BFIN533_EZKIT=y
CONFIG_TIMER0=11
@@ -107,6 +108,5 @@ CONFIG_DEBUG_DOUBLEFAULT=y
CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRYPTO=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/blackfin/configs/BF533-STAMP_defconfig b/arch/blackfin/configs/BF533-STAMP_defconfig
index aa8c1d7453ba..0e7262c04cc2 100644
--- a/arch/blackfin/configs/BF533-STAMP_defconfig
+++ b/arch/blackfin/configs/BF533-STAMP_defconfig
@@ -20,6 +20,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_LBDAF is not set
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_TIMER0=11
CONFIG_HIGH_RES_TIMERS=y
@@ -121,6 +122,5 @@ CONFIG_DEBUG_DOUBLEFAULT=y
CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRYPTO=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/blackfin/configs/BF537-STAMP_defconfig b/arch/blackfin/configs/BF537-STAMP_defconfig
index f245c0b427e4..4d14a002e7bd 100644
--- a/arch/blackfin/configs/BF537-STAMP_defconfig
+++ b/arch/blackfin/configs/BF537-STAMP_defconfig
@@ -20,9 +20,9 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_LBDAF is not set
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_BF537=y
-CONFIG_IRQ_ERROR=11
CONFIG_HIGH_RES_TIMERS=y
CONFIG_NOMMU_INITIAL_TRIM_EXCESS=0
CONFIG_BFIN_GPTIMERS=m
@@ -133,6 +133,5 @@ CONFIG_DEBUG_DOUBLEFAULT=y
CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRYPTO=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/blackfin/configs/BF538-EZKIT_defconfig b/arch/blackfin/configs/BF538-EZKIT_defconfig
index 74a330cca9b4..fbee9d776f56 100644
--- a/arch/blackfin/configs/BF538-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF538-EZKIT_defconfig
@@ -20,6 +20,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_LBDAF is not set
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_BF538=y
CONFIG_IRQ_TIMER0=12
@@ -31,6 +32,7 @@ CONFIG_C_CDPRIO=y
CONFIG_BANK_3=0x99B2
CONFIG_BINFMT_FLAT=y
CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -129,6 +131,5 @@ CONFIG_DEBUG_DOUBLEFAULT=y
CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRYPTO=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/blackfin/configs/BF548-EZKIT_defconfig b/arch/blackfin/configs/BF548-EZKIT_defconfig
index 29373cbba227..05dd11db2f7d 100644
--- a/arch/blackfin/configs/BF548-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF548-EZKIT_defconfig
@@ -40,6 +40,7 @@ CONFIG_EBIU_MODEVAL=0x1
CONFIG_EBIU_FCTLVAL=0x6
CONFIG_BINFMT_FLAT=y
CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -62,7 +63,7 @@ CONFIG_IRCOMM=m
CONFIG_IRTTY_SIR=m
CONFIG_BFIN_SIR=m
CONFIG_BFIN_SIR3=y
-CONFIG_LIB80211=m
+# CONFIG_WIRELESS is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_FW_LOADER=m
CONFIG_MTD=y
@@ -92,6 +93,7 @@ CONFIG_NET_ETHERNET=y
CONFIG_SMSC911X=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
CONFIG_INPUT_FF_MEMLESS=m
# CONFIG_INPUT_MOUSEDEV is not set
CONFIG_INPUT_EVDEV=m
diff --git a/arch/blackfin/configs/BF561-ACVILON_defconfig b/arch/blackfin/configs/BF561-ACVILON_defconfig
index 1f12034f5610..bcb14d1c5664 100644
--- a/arch/blackfin/configs/BF561-ACVILON_defconfig
+++ b/arch/blackfin/configs/BF561-ACVILON_defconfig
@@ -14,6 +14,7 @@ CONFIG_EMBEDDED=y
# CONFIG_EVENTFD is not set
# CONFIG_AIO is not set
CONFIG_SLAB=y
+CONFIG_MMAP_ALLOW_UNINITIALIZED=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_LBDAF is not set
@@ -44,6 +45,7 @@ CONFIG_IP_PNP=y
CONFIG_SYN_COOKIES=y
# CONFIG_INET_LRO is not set
# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
@@ -71,6 +73,7 @@ CONFIG_NET_ETHERNET=y
CONFIG_SMSC911X=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
@@ -147,5 +150,4 @@ CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_MMRS=y
# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/blackfin/configs/BF561-EZKIT_defconfig b/arch/blackfin/configs/BF561-EZKIT_defconfig
index 8913d997fa47..843aaa54a9e3 100644
--- a/arch/blackfin/configs/BF561-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF561-EZKIT_defconfig
@@ -35,6 +35,7 @@ CONFIG_C_CDPRIO=y
CONFIG_BANK_3=0xAAC2
CONFIG_BINFMT_FLAT=y
CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/blackfin/configs/BlackStamp_defconfig b/arch/blackfin/configs/BlackStamp_defconfig
index 0242917b69c9..dae7adf3b2a2 100644
--- a/arch/blackfin/configs/BlackStamp_defconfig
+++ b/arch/blackfin/configs/BlackStamp_defconfig
@@ -40,6 +40,7 @@ CONFIG_INET=y
CONFIG_IP_PNP=y
# CONFIG_INET_LRO is not set
# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
@@ -63,6 +64,7 @@ CONFIG_NET_ETHERNET=y
CONFIG_SMC91X=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT_MOUSEDEV is not set
CONFIG_INPUT_EVDEV=m
# CONFIG_INPUT_KEYBOARD is not set
@@ -104,5 +106,4 @@ CONFIG_DEBUG_MMRS=y
# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRC_CCITT=m
diff --git a/arch/blackfin/configs/CM-BF527_defconfig b/arch/blackfin/configs/CM-BF527_defconfig
index 0512fef3d55a..f3414244bfed 100644
--- a/arch/blackfin/configs/CM-BF527_defconfig
+++ b/arch/blackfin/configs/CM-BF527_defconfig
@@ -50,6 +50,7 @@ CONFIG_IP_PNP=y
# CONFIG_INET_LRO is not set
# CONFIG_INET_DIAG is not set
# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
@@ -70,9 +71,9 @@ CONFIG_BLK_DEV_SD=y
CONFIG_NETDEVICES=y
CONFIG_NET_ETHERNET=y
CONFIG_BFIN_MAC=y
-CONFIG_BFIN_MAC_RMII=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
@@ -124,7 +125,6 @@ CONFIG_DEBUG_FS=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
CONFIG_EARLY_PRINTK=y
-CONFIG_SECURITY=y
CONFIG_CRYPTO=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRC_CCITT=m
diff --git a/arch/blackfin/configs/CM-BF533_defconfig b/arch/blackfin/configs/CM-BF533_defconfig
index 05e09be8b4c5..8c7e08f173d4 100644
--- a/arch/blackfin/configs/CM-BF533_defconfig
+++ b/arch/blackfin/configs/CM-BF533_defconfig
@@ -33,6 +33,7 @@ CONFIG_BINFMT_SHARED_FLAT=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
+# CONFIG_WIRELESS is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_PARTITIONS=y
@@ -47,6 +48,7 @@ CONFIG_MTD_PHYSMAP=y
CONFIG_NETDEVICES=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
@@ -72,7 +74,6 @@ CONFIG_DEBUG_MMRS=y
# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRC_CCITT=y
CONFIG_CRC_ITU_T=y
CONFIG_CRC7=y
diff --git a/arch/blackfin/configs/CM-BF537E_defconfig b/arch/blackfin/configs/CM-BF537E_defconfig
index d2eb5325b9c3..bd3cb766d078 100644
--- a/arch/blackfin/configs/CM-BF537E_defconfig
+++ b/arch/blackfin/configs/CM-BF537E_defconfig
@@ -48,6 +48,7 @@ CONFIG_IP_PNP=y
# CONFIG_INET_LRO is not set
# CONFIG_INET_DIAG is not set
# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_CMDLINE_PARTS=y
@@ -65,6 +66,7 @@ CONFIG_NET_ETHERNET=y
CONFIG_BFIN_MAC=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
@@ -99,7 +101,6 @@ CONFIG_DEBUG_MMRS=y
# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRYPTO=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRC_CCITT=m
diff --git a/arch/blackfin/configs/CM-BF537U_defconfig b/arch/blackfin/configs/CM-BF537U_defconfig
index 9d52c443eb09..82224f37c04e 100644
--- a/arch/blackfin/configs/CM-BF537U_defconfig
+++ b/arch/blackfin/configs/CM-BF537U_defconfig
@@ -44,6 +44,7 @@ CONFIG_INET=y
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_DIAG is not set
# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_CMDLINE_PARTS=y
@@ -59,6 +60,7 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_NETDEVICES=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
@@ -90,7 +92,6 @@ CONFIG_DEBUG_MMRS=y
# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRC_CCITT=m
CONFIG_CRC_ITU_T=y
CONFIG_CRC7=y
diff --git a/arch/blackfin/configs/CM-BF548_defconfig b/arch/blackfin/configs/CM-BF548_defconfig
index 9de13cf2cdda..433598c6e773 100644
--- a/arch/blackfin/configs/CM-BF548_defconfig
+++ b/arch/blackfin/configs/CM-BF548_defconfig
@@ -49,6 +49,7 @@ CONFIG_INET_XFRM_MODE_BEET=m
# CONFIG_INET_LRO is not set
# CONFIG_INET_DIAG is not set
# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
@@ -71,6 +72,7 @@ CONFIG_NET_ETHERNET=y
CONFIG_SMSC911X=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT_MOUSEDEV is not set
CONFIG_INPUT_EVDEV=m
CONFIG_INPUT_EVBUG=m
@@ -167,7 +169,6 @@ CONFIG_DEBUG_FS=y
# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRYPTO_HW is not set
CONFIG_CRC_CCITT=m
diff --git a/arch/blackfin/configs/CM-BF561_defconfig b/arch/blackfin/configs/CM-BF561_defconfig
index 238353a53bf0..ded7d845cb39 100644
--- a/arch/blackfin/configs/CM-BF561_defconfig
+++ b/arch/blackfin/configs/CM-BF561_defconfig
@@ -48,6 +48,7 @@ CONFIG_INET=y
# CONFIG_INET_LRO is not set
# CONFIG_INET_DIAG is not set
# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_PARTITIONS=y
@@ -67,6 +68,7 @@ CONFIG_MII=y
CONFIG_SMSC911X=m
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
@@ -99,7 +101,6 @@ CONFIG_DEBUG_MMRS=y
# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRC_CCITT=m
CONFIG_CRC_ITU_T=y
CONFIG_CRC7=y
diff --git a/arch/blackfin/configs/H8606_defconfig b/arch/blackfin/configs/H8606_defconfig
index 0cb524e8947f..700fb701c121 100644
--- a/arch/blackfin/configs/H8606_defconfig
+++ b/arch/blackfin/configs/H8606_defconfig
@@ -33,6 +33,7 @@ CONFIG_IRLAN=m
CONFIG_IRCOMM=m
CONFIG_IRDA_CACHE_LAST_LSAP=y
CONFIG_IRTTY_SIR=m
+# CONFIG_WIRELESS is not set
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_PARTITIONS=y
@@ -50,6 +51,7 @@ CONFIG_NET_ETHERNET=y
CONFIG_DM9000=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT_MOUSEDEV is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_KEYBOARD_ATKBD is not set
@@ -84,4 +86,3 @@ CONFIG_NFS_V3=y
CONFIG_NLS=m
# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
diff --git a/arch/blackfin/configs/IP0X_defconfig b/arch/blackfin/configs/IP0X_defconfig
index 2a3411ef19fd..b40156d217e3 100644
--- a/arch/blackfin/configs/IP0X_defconfig
+++ b/arch/blackfin/configs/IP0X_defconfig
@@ -41,6 +41,7 @@ CONFIG_IP_NF_IPTABLES=y
CONFIG_IP_NF_FILTER=y
CONFIG_IP_NF_TARGET_REJECT=y
CONFIG_IP_NF_MANGLE=y
+# CONFIG_WIRELESS is not set
CONFIG_MTD=y
CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CHAR=y
@@ -60,6 +61,7 @@ CONFIG_NET_ETHERNET=y
CONFIG_DM9000=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
@@ -89,5 +91,4 @@ CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRC_CCITT=y
diff --git a/arch/blackfin/configs/PNAV-10_defconfig b/arch/blackfin/configs/PNAV-10_defconfig
index fea303386548..be866d95ed76 100644
--- a/arch/blackfin/configs/PNAV-10_defconfig
+++ b/arch/blackfin/configs/PNAV-10_defconfig
@@ -14,6 +14,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_LBDAF is not set
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_BF537=y
CONFIG_IRQ_TIMER0=12
@@ -107,7 +108,6 @@ CONFIG_SMB_FS=m
# CONFIG_DEBUG_HUNT_FOR_ZERO is not set
# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
# CONFIG_ACCESS_CHECK is not set
-CONFIG_SECURITY=y
CONFIG_CRYPTO=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRC_CCITT=m
diff --git a/arch/blackfin/configs/SRV1_defconfig b/arch/blackfin/configs/SRV1_defconfig
index 9811b3186847..b64bdf759b82 100644
--- a/arch/blackfin/configs/SRV1_defconfig
+++ b/arch/blackfin/configs/SRV1_defconfig
@@ -35,6 +35,7 @@ CONFIG_IRLAN=m
CONFIG_IRCOMM=m
CONFIG_IRDA_CACHE_LAST_LSAP=y
CONFIG_IRTTY_SIR=m
+# CONFIG_WIRELESS is not set
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_PARTITIONS=y
@@ -51,6 +52,7 @@ CONFIG_EEPROM_AT25=m
CONFIG_NETDEVICES=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT_MOUSEDEV is not set
CONFIG_INPUT_EVDEV=m
# CONFIG_INPUT_KEYBOARD is not set
@@ -85,4 +87,3 @@ CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
diff --git a/arch/blackfin/configs/TCM-BF518_defconfig b/arch/blackfin/configs/TCM-BF518_defconfig
index 412bf79b9724..1bccd9a50986 100644
--- a/arch/blackfin/configs/TCM-BF518_defconfig
+++ b/arch/blackfin/configs/TCM-BF518_defconfig
@@ -128,7 +128,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
CONFIG_EARLY_PRINTK=y
CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
CONFIG_CRYPTO=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRC_CCITT=m
diff --git a/arch/blackfin/configs/TCM-BF537_defconfig b/arch/blackfin/configs/TCM-BF537_defconfig
index 04bf52c4cf12..00ce899e9e5d 100644
--- a/arch/blackfin/configs/TCM-BF537_defconfig
+++ b/arch/blackfin/configs/TCM-BF537_defconfig
@@ -40,6 +40,7 @@ CONFIG_UNIX=y
CONFIG_INET=y
# CONFIG_INET_DIAG is not set
# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_CMDLINE_PARTS=y
@@ -57,6 +58,7 @@ CONFIG_NET_ETHERNET=y
CONFIG_BFIN_MAC=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
diff --git a/arch/blackfin/include/asm/bfin5xx_spi.h b/arch/blackfin/include/asm/bfin5xx_spi.h
index 0b5136e334b5..5392583d0253 100644
--- a/arch/blackfin/include/asm/bfin5xx_spi.h
+++ b/arch/blackfin/include/asm/bfin5xx_spi.h
@@ -60,6 +60,8 @@ struct bfin_spi_regs {
__BFP(shadow);
};
+#undef __BFP
+
#define MAX_CTRL_CS 8 /* cs in spi controller */
/* device.platform_data for SSP controller devices */
diff --git a/arch/blackfin/include/asm/bfin_ppi.h b/arch/blackfin/include/asm/bfin_ppi.h
index 003900886f97..3be05faa2c65 100644
--- a/arch/blackfin/include/asm/bfin_ppi.h
+++ b/arch/blackfin/include/asm/bfin_ppi.h
@@ -48,4 +48,6 @@ struct bfin_eppi_regs {
u32 clip;
};
+#undef __BFP
+
#endif
diff --git a/arch/blackfin/include/asm/bfin_twi.h b/arch/blackfin/include/asm/bfin_twi.h
new file mode 100644
index 000000000000..e767d649dfc4
--- /dev/null
+++ b/arch/blackfin/include/asm/bfin_twi.h
@@ -0,0 +1,45 @@
+/*
+ * bfin_twi.h - interface to Blackfin TWIs
+ *
+ * Copyright 2005-2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __ASM_BFIN_TWI_H__
+#define __ASM_BFIN_TWI_H__
+
+#include <linux/types.h>
+
+/*
+ * All Blackfin system MMRs are padded to 32bits even if the register
+ * itself is only 16bits. So use a helper macro to streamline this.
+ */
+#define __BFP(m) u16 m; u16 __pad_##m
+
+/*
+ * bfin twi registers layout
+ */
+struct bfin_twi_regs {
+ __BFP(clkdiv);
+ __BFP(control);
+ __BFP(slave_ctl);
+ __BFP(slave_stat);
+ __BFP(slave_addr);
+ __BFP(master_ctl);
+ __BFP(master_stat);
+ __BFP(master_addr);
+ __BFP(int_stat);
+ __BFP(int_mask);
+ __BFP(fifo_ctl);
+ __BFP(fifo_stat);
+ u32 __pad[20];
+ __BFP(xmt_data8);
+ __BFP(xmt_data16);
+ __BFP(rcv_data8);
+ __BFP(rcv_data16);
+};
+
+#undef __BFP
+
+#endif
diff --git a/arch/blackfin/include/asm/cdef_LPBlackfin.h b/arch/blackfin/include/asm/cdef_LPBlackfin.h
index a1f6817687e8..59af63c0c2be 100644
--- a/arch/blackfin/include/asm/cdef_LPBlackfin.h
+++ b/arch/blackfin/include/asm/cdef_LPBlackfin.h
@@ -179,7 +179,7 @@
#define bfin_write_ITEST_DATA0(val) bfin_write32(ITEST_DATA0,val)
#define bfin_write_ITEST_DATA1(val) bfin_write32(ITEST_DATA1,val)
-#if ANOMALY_05000481
+#if !ANOMALY_05000481
#define bfin_read_ITEST_COMMAND() bfin_read32(ITEST_COMMAND)
#define bfin_read_ITEST_DATA0() bfin_read32(ITEST_DATA0)
#define bfin_read_ITEST_DATA1() bfin_read32(ITEST_DATA1)
diff --git a/arch/blackfin/include/asm/entry.h b/arch/blackfin/include/asm/entry.h
index a6886f6e4819..4104d5783e2c 100644
--- a/arch/blackfin/include/asm/entry.h
+++ b/arch/blackfin/include/asm/entry.h
@@ -15,14 +15,6 @@
#define LFLUSH_I_AND_D 0x00000808
#define LSIGTRAP 5
-/* process bits for task_struct.flags */
-#define PF_TRACESYS_OFF 3
-#define PF_TRACESYS_BIT 5
-#define PF_PTRACED_OFF 3
-#define PF_PTRACED_BIT 4
-#define PF_DTRACE_OFF 1
-#define PF_DTRACE_BIT 5
-
/*
* NOTE! The single-stepping code assumes that all interrupt handlers
* start by saving SYSCFG on the stack with their first instruction.
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
index b35839354130..75089f80855d 100644
--- a/arch/blackfin/kernel/ptrace.c
+++ b/arch/blackfin/kernel/ptrace.c
@@ -38,12 +38,13 @@
* Get contents of register REGNO in task TASK.
*/
static inline long
-get_reg(struct task_struct *task, long regno, unsigned long __user *datap)
+get_reg(struct task_struct *task, unsigned long regno,
+ unsigned long __user *datap)
{
long tmp;
struct pt_regs *regs = task_pt_regs(task);
- if (regno & 3 || regno > PT_LAST_PSEUDO || regno < 0)
+ if (regno & 3 || regno > PT_LAST_PSEUDO)
return -EIO;
switch (regno) {
@@ -74,11 +75,11 @@ get_reg(struct task_struct *task, long regno, unsigned long __user *datap)
* Write contents of register REGNO in task TASK.
*/
static inline int
-put_reg(struct task_struct *task, long regno, unsigned long data)
+put_reg(struct task_struct *task, unsigned long regno, unsigned long data)
{
struct pt_regs *regs = task_pt_regs(task);
- if (regno & 3 || regno > PT_LAST_PSEUDO || regno < 0)
+ if (regno & 3 || regno > PT_LAST_PSEUDO)
return -EIO;
switch (regno) {
@@ -240,7 +241,8 @@ void user_disable_single_step(struct task_struct *child)
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret;
unsigned long __user *datap = (unsigned long __user *)data;
@@ -368,14 +370,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
return copy_regset_to_user(child, &user_bfin_native_view,
REGSET_GENERAL,
0, sizeof(struct pt_regs),
- (void __user *)data);
+ datap);
case PTRACE_SETREGS:
pr_debug("ptrace: PTRACE_SETREGS\n");
return copy_regset_from_user(child, &user_bfin_native_view,
REGSET_GENERAL,
0, sizeof(struct pt_regs),
- (const void __user *)data);
+ datap);
case_default:
default:
diff --git a/arch/blackfin/mach-bf518/boards/ezbrd.c b/arch/blackfin/mach-bf518/boards/ezbrd.c
index f95e6096719b..b894c8abe7ec 100644
--- a/arch/blackfin/mach-bf518/boards/ezbrd.c
+++ b/arch/blackfin/mach-bf518/boards/ezbrd.c
@@ -87,13 +87,55 @@ static struct platform_device rtc_device = {
#endif
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = {
+ P_MII0_ETxD0,
+ P_MII0_ETxD1,
+ P_MII0_ETxEN,
+ P_MII0_ERxD0,
+ P_MII0_ERxD1,
+ P_MII0_TxCLK,
+ P_MII0_PHYINT,
+ P_MII0_CRS,
+ P_MII0_MDC,
+ P_MII0_MDIO,
+ 0
+};
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+ {
+ .addr = 1,
+ .irq = IRQ_MAC_PHYINT,
+ },
+ {
+ .addr = 2,
+ .irq = IRQ_MAC_PHYINT,
+ },
+ {
+ .addr = 3,
+ .irq = IRQ_MAC_PHYINT,
+ },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+ .phydev_number = 3,
+ .phydev_data = bfin_phydev_data,
+ .phy_mode = PHY_INTERFACE_MODE_MII,
+ .mac_peripherals = bfin_mac_peripherals,
+};
+
static struct platform_device bfin_mii_bus = {
.name = "bfin_mii_bus",
+ .dev = {
+ .platform_data = &bfin_mii_bus_data,
+ }
};
static struct platform_device bfin_mac_device = {
.name = "bfin_mac",
- .dev.platform_data = &bfin_mii_bus,
+ .dev = {
+ .platform_data = &bfin_mii_bus,
+ }
};
#if defined(CONFIG_NET_DSA_KSZ8893M) || defined(CONFIG_NET_DSA_KSZ8893M_MODULE)
diff --git a/arch/blackfin/mach-bf518/boards/tcm-bf518.c b/arch/blackfin/mach-bf518/boards/tcm-bf518.c
index bead810a6546..e6ce1d7c523a 100644
--- a/arch/blackfin/mach-bf518/boards/tcm-bf518.c
+++ b/arch/blackfin/mach-bf518/boards/tcm-bf518.c
@@ -81,13 +81,35 @@ static struct platform_device rtc_device = {
#endif
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+ {
+ .addr = 1,
+ .irq = IRQ_MAC_PHYINT,
+ },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+ .phydev_number = 1,
+ .phydev_data = bfin_phydev_data,
+ .phy_mode = PHY_INTERFACE_MODE_MII,
+ .mac_peripherals = bfin_mac_peripherals,
+};
+
static struct platform_device bfin_mii_bus = {
.name = "bfin_mii_bus",
+ .dev = {
+ .platform_data = &bfin_mii_bus_data,
+ }
};
static struct platform_device bfin_mac_device = {
.name = "bfin_mac",
- .dev.platform_data = &bfin_mii_bus,
+ .dev = {
+ .platform_data = &bfin_mii_bus,
+ }
};
#endif
diff --git a/arch/blackfin/mach-bf527/boards/cm_bf527.c b/arch/blackfin/mach-bf527/boards/cm_bf527.c
index 38037c7e125a..2c31af7a320a 100644
--- a/arch/blackfin/mach-bf527/boards/cm_bf527.c
+++ b/arch/blackfin/mach-bf527/boards/cm_bf527.c
@@ -273,13 +273,35 @@ static struct platform_device dm9000_device = {
#endif
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+ {
+ .addr = 1,
+ .irq = IRQ_MAC_PHYINT,
+ },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+ .phydev_number = 1,
+ .phydev_data = bfin_phydev_data,
+ .phy_mode = PHY_INTERFACE_MODE_RMII,
+ .mac_peripherals = bfin_mac_peripherals,
+};
+
static struct platform_device bfin_mii_bus = {
.name = "bfin_mii_bus",
+ .dev = {
+ .platform_data = &bfin_mii_bus_data,
+ }
};
static struct platform_device bfin_mac_device = {
.name = "bfin_mac",
- .dev.platform_data = &bfin_mii_bus,
+ .dev = {
+ .platform_data = &bfin_mii_bus,
+ }
};
#endif
diff --git a/arch/blackfin/mach-bf527/boards/ezbrd.c b/arch/blackfin/mach-bf527/boards/ezbrd.c
index 6cc64a1e78b9..9a736a850c5c 100644
--- a/arch/blackfin/mach-bf527/boards/ezbrd.c
+++ b/arch/blackfin/mach-bf527/boards/ezbrd.c
@@ -193,13 +193,35 @@ static struct platform_device rtc_device = {
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+ {
+ .addr = 1,
+ .irq = IRQ_MAC_PHYINT,
+ },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+ .phydev_number = 1,
+ .phydev_data = bfin_phydev_data,
+ .phy_mode = PHY_INTERFACE_MODE_RMII,
+ .mac_peripherals = bfin_mac_peripherals,
+};
+
static struct platform_device bfin_mii_bus = {
.name = "bfin_mii_bus",
+ .dev = {
+ .platform_data = &bfin_mii_bus_data,
+ }
};
static struct platform_device bfin_mac_device = {
.name = "bfin_mac",
- .dev.platform_data = &bfin_mii_bus,
+ .dev = {
+ .platform_data = &bfin_mii_bus,
+ }
};
#endif
diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c
index 07c132dc4125..9222bc00bbd3 100644
--- a/arch/blackfin/mach-bf527/boards/ezkit.c
+++ b/arch/blackfin/mach-bf527/boards/ezkit.c
@@ -366,13 +366,35 @@ static struct platform_device dm9000_device = {
#endif
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+ {
+ .addr = 1,
+ .irq = IRQ_MAC_PHYINT,
+ },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+ .phydev_number = 1,
+ .phydev_data = bfin_phydev_data,
+ .phy_mode = PHY_INTERFACE_MODE_RMII,
+ .mac_peripherals = bfin_mac_peripherals,
+};
+
static struct platform_device bfin_mii_bus = {
.name = "bfin_mii_bus",
+ .dev = {
+ .platform_data = &bfin_mii_bus_data,
+ }
};
static struct platform_device bfin_mac_device = {
.name = "bfin_mac",
- .dev.platform_data = &bfin_mii_bus,
+ .dev = {
+ .platform_data = &bfin_mii_bus,
+ }
};
#endif
@@ -887,7 +909,7 @@ static struct adp5520_keys_platform_data adp5520_keys_data = {
};
/*
- * ADP5520/5501 Multifuction Device Init Data
+ * ADP5520/5501 Multifunction Device Init Data
*/
static struct adp5520_platform_data adp5520_pdev_data = {
diff --git a/arch/blackfin/mach-bf527/boards/tll6527m.c b/arch/blackfin/mach-bf527/boards/tll6527m.c
index ae4130e97c01..9ec575729e2c 100644
--- a/arch/blackfin/mach-bf527/boards/tll6527m.c
+++ b/arch/blackfin/mach-bf527/boards/tll6527m.c
@@ -257,13 +257,35 @@ static struct platform_device rtc_device = {
#endif
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+ {
+ .addr = 1,
+ .irq = IRQ_MAC_PHYINT,
+ },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+ .phydev_number = 1,
+ .phydev_data = bfin_phydev_data,
+ .phy_mode = PHY_INTERFACE_MODE_RMII,
+ .mac_peripherals = bfin_mac_peripherals,
+};
+
static struct platform_device bfin_mii_bus = {
.name = "bfin_mii_bus",
+ .dev = {
+ .platform_data = &bfin_mii_bus_data,
+ }
};
static struct platform_device bfin_mac_device = {
.name = "bfin_mac",
- .dev.platform_data = &bfin_mii_bus,
+ .dev = {
+ .platform_data = &bfin_mii_bus,
+ }
};
#endif
diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537e.c b/arch/blackfin/mach-bf537/boards/cm_bf537e.c
index e2e7be40ef44..836698c4ee54 100644
--- a/arch/blackfin/mach-bf537/boards/cm_bf537e.c
+++ b/arch/blackfin/mach-bf537/boards/cm_bf537e.c
@@ -597,13 +597,35 @@ static struct platform_device bfin_sport1_uart_device = {
#endif
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+ {
+ .addr = 1,
+ .irq = IRQ_MAC_PHYINT,
+ },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+ .phydev_number = 1,
+ .phydev_data = bfin_phydev_data,
+ .phy_mode = PHY_INTERFACE_MODE_MII,
+ .mac_peripherals = bfin_mac_peripherals,
+};
+
static struct platform_device bfin_mii_bus = {
.name = "bfin_mii_bus",
+ .dev = {
+ .platform_data = &bfin_mii_bus_data,
+ }
};
static struct platform_device bfin_mac_device = {
.name = "bfin_mac",
- .dev.platform_data = &bfin_mii_bus,
+ .dev = {
+ .platform_data = &bfin_mii_bus,
+ }
};
#endif
diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537u.c b/arch/blackfin/mach-bf537/boards/cm_bf537u.c
index 752c833f7ca8..2a85670273cb 100644
--- a/arch/blackfin/mach-bf537/boards/cm_bf537u.c
+++ b/arch/blackfin/mach-bf537/boards/cm_bf537u.c
@@ -562,13 +562,35 @@ static struct platform_device bfin_sport1_uart_device = {
#endif
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+ {
+ .addr = 1,
+ .irq = IRQ_MAC_PHYINT,
+ },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+ .phydev_number = 1,
+ .phydev_data = bfin_phydev_data,
+ .phy_mode = PHY_INTERFACE_MODE_MII,
+ .mac_peripherals = bfin_mac_peripherals,
+};
+
static struct platform_device bfin_mii_bus = {
.name = "bfin_mii_bus",
+ .dev = {
+ .platform_data = &bfin_mii_bus_data,
+ }
};
static struct platform_device bfin_mac_device = {
.name = "bfin_mac",
- .dev.platform_data = &bfin_mii_bus,
+ .dev = {
+ .platform_data = &bfin_mii_bus,
+ }
};
#endif
diff --git a/arch/blackfin/mach-bf537/boards/minotaur.c b/arch/blackfin/mach-bf537/boards/minotaur.c
index 05d45994480e..49800518412c 100644
--- a/arch/blackfin/mach-bf537/boards/minotaur.c
+++ b/arch/blackfin/mach-bf537/boards/minotaur.c
@@ -68,13 +68,35 @@ static struct platform_device rtc_device = {
#endif
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+ {
+ .addr = 1,
+ .irq = IRQ_MAC_PHYINT,
+ },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+ .phydev_number = 1,
+ .phydev_data = bfin_phydev_data,
+ .phy_mode = PHY_INTERFACE_MODE_MII,
+ .mac_peripherals = bfin_mac_peripherals,
+};
+
static struct platform_device bfin_mii_bus = {
.name = "bfin_mii_bus",
+ .dev = {
+ .platform_data = &bfin_mii_bus_data,
+ }
};
static struct platform_device bfin_mac_device = {
.name = "bfin_mac",
- .dev.platform_data = &bfin_mii_bus,
+ .dev = {
+ .platform_data = &bfin_mii_bus,
+ }
};
#endif
diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c
index 6b03808800a6..b95807894e25 100644
--- a/arch/blackfin/mach-bf537/boards/pnav10.c
+++ b/arch/blackfin/mach-bf537/boards/pnav10.c
@@ -99,13 +99,35 @@ static struct platform_device smc91x_device = {
#endif
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+ {
+ .addr = 1,
+ .irq = IRQ_MAC_PHYINT,
+ },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+ .phydev_number = 1,
+ .phydev_data = bfin_phydev_data,
+ .phy_mode = PHY_INTERFACE_MODE_RMII,
+ .mac_peripherals = bfin_mac_peripherals,
+};
+
static struct platform_device bfin_mii_bus = {
.name = "bfin_mii_bus",
+ .dev = {
+ .platform_data = &bfin_mii_bus_data,
+ }
};
static struct platform_device bfin_mac_device = {
.name = "bfin_mac",
- .dev.platform_data = &bfin_mii_bus,
+ .dev = {
+ .platform_data = &bfin_mii_bus,
+ }
};
#endif
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index c9e0e85629bf..3aa344ce8e52 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -327,13 +327,35 @@ static struct platform_device bfin_can_device = {
#endif
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+ {
+ .addr = 1,
+ .irq = PHY_POLL, /* IRQ_MAC_PHYINT */
+ },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+ .phydev_number = 1,
+ .phydev_data = bfin_phydev_data,
+ .phy_mode = PHY_INTERFACE_MODE_MII,
+ .mac_peripherals = bfin_mac_peripherals,
+};
+
static struct platform_device bfin_mii_bus = {
.name = "bfin_mii_bus",
+ .dev = {
+ .platform_data = &bfin_mii_bus_data,
+ }
};
static struct platform_device bfin_mac_device = {
.name = "bfin_mac",
- .dev.platform_data = &bfin_mii_bus,
+ .dev = {
+ .platform_data = &bfin_mii_bus,
+ }
};
#endif
@@ -2015,7 +2037,7 @@ static struct adp5520_keys_platform_data adp5520_keys_data = {
};
/*
- * ADP5520/5501 Multifuction Device Init Data
+ * ADP5520/5501 Multifunction Device Init Data
*/
static struct adp5520_platform_data adp5520_pdev_data = {
diff --git a/arch/blackfin/mach-bf537/boards/tcm_bf537.c b/arch/blackfin/mach-bf537/boards/tcm_bf537.c
index a4d62b5fc7ba..31498add1a42 100644
--- a/arch/blackfin/mach-bf537/boards/tcm_bf537.c
+++ b/arch/blackfin/mach-bf537/boards/tcm_bf537.c
@@ -564,13 +564,35 @@ static struct platform_device bfin_sport1_uart_device = {
#endif
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+ {
+ .addr = 1,
+ .irq = IRQ_MAC_PHYINT,
+ },
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+ .phydev_number = 1,
+ .phydev_data = bfin_phydev_data,
+ .phy_mode = PHY_INTERFACE_MODE_MII,
+ .mac_peripherals = bfin_mac_peripherals,
+};
+
static struct platform_device bfin_mii_bus = {
.name = "bfin_mii_bus",
+ .dev = {
+ .platform_data = &bfin_mii_bus_data,
+ }
};
static struct platform_device bfin_mac_device = {
.name = "bfin_mac",
- .dev.platform_data = &bfin_mii_bus,
+ .dev = {
+ .platform_data = &bfin_mii_bus,
+ }
};
#endif
diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile
index 814cb483853b..ff299f24aba0 100644
--- a/arch/blackfin/mach-common/Makefile
+++ b/arch/blackfin/mach-common/Makefile
@@ -11,4 +11,3 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_BFIN_KERNEL_CLOCK) += clocks-init.o
-obj-$(CONFIG_DEBUG_ICACHE_CHECK) += irqpanic.o
diff --git a/arch/blackfin/mach-common/irqpanic.c b/arch/blackfin/mach-common/irqpanic.c
deleted file mode 100644
index c6496249e2bc..000000000000
--- a/arch/blackfin/mach-common/irqpanic.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * panic kernel with dump information
- *
- * Copyright 2005-2009 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/module.h>
-#include <linux/kernel_stat.h>
-#include <linux/sched.h>
-#include <asm/blackfin.h>
-
-#define L1_ICACHE_START 0xffa10000
-#define L1_ICACHE_END 0xffa13fff
-
-/*
- * irq_panic - calls panic with string setup
- */
-__attribute__ ((l1_text))
-asmlinkage void irq_panic(int reason, struct pt_regs *regs)
-{
- unsigned int cmd, tag, ca, cache_hi, cache_lo, *pa;
- unsigned short i, j, die;
- unsigned int bad[10][6];
-
- /* check entire cache for coherency
- * Since printk is in cacheable memory,
- * don't call it until you have checked everything
- */
-
- die = 0;
- i = 0;
-
- /* check icache */
-
- for (ca = L1_ICACHE_START; ca <= L1_ICACHE_END && i < 10; ca += 32) {
-
- /* Grab various address bits for the itest_cmd fields */
- cmd = (((ca & 0x3000) << 4) | /* ca[13:12] for SBNK[1:0] */
- ((ca & 0x0c00) << 16) | /* ca[11:10] for WAYSEL[1:0] */
- ((ca & 0x3f8)) | /* ca[09:03] for SET[4:0] and DW[1:0] */
- 0); /* Access Tag, Read access */
-
- SSYNC();
- bfin_write_ITEST_COMMAND(cmd);
- SSYNC();
- tag = bfin_read_ITEST_DATA0();
- SSYNC();
-
- /* if tag is marked as valid, check it */
- if (tag & 1) {
- /* The icache is arranged in 4 groups of 64-bits */
- for (j = 0; j < 32; j += 8) {
- cmd = ((((ca + j) & 0x3000) << 4) | /* ca[13:12] for SBNK[1:0] */
- (((ca + j) & 0x0c00) << 16) | /* ca[11:10] for WAYSEL[1:0] */
- (((ca + j) & 0x3f8)) | /* ca[09:03] for SET[4:0] and DW[1:0] */
- 4); /* Access Data, Read access */
-
- SSYNC();
- bfin_write_ITEST_COMMAND(cmd);
- SSYNC();
-
- cache_hi = bfin_read_ITEST_DATA1();
- cache_lo = bfin_read_ITEST_DATA0();
-
- pa = ((unsigned int *)((tag & 0xffffcc00) |
- ((ca + j) & ~(0xffffcc00))));
-
- /*
- * Debugging this, enable
- *
- * printk("addr: %08x %08x%08x | %08x%08x\n",
- * ((unsigned int *)((tag & 0xffffcc00) | ((ca+j) & ~(0xffffcc00)))),
- * cache_hi, cache_lo, *(pa+1), *pa);
- */
-
- if (cache_hi != *(pa + 1) || cache_lo != *pa) {
- /* Since icache is not working, stay out of it, by not printing */
- die = 1;
- bad[i][0] = (ca + j);
- bad[i][1] = cache_hi;
- bad[i][2] = cache_lo;
- bad[i][3] = ((tag & 0xffffcc00) |
- ((ca + j) & ~(0xffffcc00)));
- bad[i][4] = *(pa + 1);
- bad[i][5] = *(pa);
- i++;
- }
- }
- }
- }
- if (die) {
- printk(KERN_EMERG "icache coherency error\n");
- for (j = 0; j <= i; j++) {
- printk(KERN_EMERG
- "cache address : %08x cache value : %08x%08x\n",
- bad[j][0], bad[j][1], bad[j][2]);
- printk(KERN_EMERG
- "physical address: %08x SDRAM value : %08x%08x\n",
- bad[j][3], bad[j][4], bad[j][5]);
- }
- panic("icache coherency error");
- } else
- printk(KERN_EMERG "icache checked, and OK\n");
-}
diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c
index e70c804e9377..320065f3cbe5 100644
--- a/arch/cris/arch-v10/kernel/ptrace.c
+++ b/arch/cris/arch-v10/kernel/ptrace.c
@@ -76,9 +76,11 @@ ptrace_disable(struct task_struct *child)
* (in user space) where the result of the ptrace call is written (instead of
* being returned).
*/
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret;
+ unsigned int regno = addr >> 2;
unsigned long __user *datap = (unsigned long __user *)data;
switch (request) {
@@ -93,10 +95,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
unsigned long tmp;
ret = -EIO;
- if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+ if ((addr & 3) || regno > PT_MAX)
break;
- tmp = get_reg(child, addr >> 2);
+ tmp = get_reg(child, regno);
ret = put_user(tmp, datap);
break;
}
@@ -110,19 +112,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* Write the word at location address in the USER area. */
case PTRACE_POKEUSR:
ret = -EIO;
- if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+ if ((addr & 3) || regno > PT_MAX)
break;
- addr >>= 2;
-
- if (addr == PT_DCCR) {
+ if (regno == PT_DCCR) {
/* don't allow the tracing process to change stuff like
* interrupt enable, kernel/user bit, dma enables etc.
*/
data &= DCCR_MASK;
data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
}
- if (put_reg(child, addr, data))
+ if (put_reg(child, regno, data))
break;
ret = 0;
break;
@@ -141,7 +141,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
}
- data += sizeof(long);
+ datap++;
}
break;
@@ -165,7 +165,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
put_reg(child, i, tmp);
- data += sizeof(long);
+ datap++;
}
break;
diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c
index f4ebd1e7d0f5..511ece94a574 100644
--- a/arch/cris/arch-v32/kernel/ptrace.c
+++ b/arch/cris/arch-v32/kernel/ptrace.c
@@ -126,9 +126,11 @@ ptrace_disable(struct task_struct *child)
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret;
+ unsigned int regno = addr >> 2;
unsigned long __user *datap = (unsigned long __user *)data;
switch (request) {
@@ -163,10 +165,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
unsigned long tmp;
ret = -EIO;
- if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+ if ((addr & 3) || regno > PT_MAX)
break;
- tmp = get_reg(child, addr >> 2);
+ tmp = get_reg(child, regno);
ret = put_user(tmp, datap);
break;
}
@@ -180,19 +182,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* Write the word at location address in the USER area. */
case PTRACE_POKEUSR:
ret = -EIO;
- if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+ if ((addr & 3) || regno > PT_MAX)
break;
- addr >>= 2;
-
- if (addr == PT_CCS) {
+ if (regno == PT_CCS) {
/* don't allow the tracing process to change stuff like
* interrupt enable, kernel/user bit, dma enables etc.
*/
data &= CCS_MASK;
data |= get_reg(child, PT_CCS) & ~CCS_MASK;
}
- if (put_reg(child, addr, data))
+ if (put_reg(child, regno, data))
break;
ret = 0;
break;
diff --git a/arch/cris/include/asm/pgtable.h b/arch/cris/include/asm/pgtable.h
index f63d6fccbc6c..9eaae217b21b 100644
--- a/arch/cris/include/asm/pgtable.h
+++ b/arch/cris/include/asm/pgtable.h
@@ -248,10 +248,8 @@ static inline pgd_t * pgd_offset(const struct mm_struct *mm, unsigned long addre
((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address))
#define pte_offset_map(dir, address) \
((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
-#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
#define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
#define pte_pfn(x) ((unsigned long)(__va((x).pte)) >> PAGE_SHIFT)
#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
diff --git a/arch/frv/include/asm/highmem.h b/arch/frv/include/asm/highmem.h
index cb4c317eaecc..a8d6565d415d 100644
--- a/arch/frv/include/asm/highmem.h
+++ b/arch/frv/include/asm/highmem.h
@@ -112,12 +112,11 @@ extern struct page *kmap_atomic_to_page(void *ptr);
(void *) damlr; \
})
-static inline void *kmap_atomic(struct page *page, enum km_type type)
+static inline void *kmap_atomic_primary(struct page *page, enum km_type type)
{
unsigned long paddr;
pagefault_disable();
- debug_kmap_atomic(type);
paddr = page_to_phys(page);
switch (type) {
@@ -125,14 +124,6 @@ static inline void *kmap_atomic(struct page *page, enum km_type type)
case 1: return __kmap_atomic_primary(1, paddr, 3);
case 2: return __kmap_atomic_primary(2, paddr, 4);
case 3: return __kmap_atomic_primary(3, paddr, 5);
- case 4: return __kmap_atomic_primary(4, paddr, 6);
- case 5: return __kmap_atomic_primary(5, paddr, 7);
- case 6: return __kmap_atomic_primary(6, paddr, 8);
- case 7: return __kmap_atomic_primary(7, paddr, 9);
- case 8: return __kmap_atomic_primary(8, paddr, 10);
-
- case 9 ... 9 + NR_TLB_LINES - 1:
- return __kmap_atomic_secondary(type - 9, paddr);
default:
BUG();
@@ -152,22 +143,13 @@ do { \
asm volatile("tlbpr %0,gr0,#4,#1" : : "r"(vaddr) : "memory"); \
} while(0)
-static inline void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+static inline void kunmap_atomic_primary(void *kvaddr, enum km_type type)
{
switch (type) {
case 0: __kunmap_atomic_primary(0, 2); break;
case 1: __kunmap_atomic_primary(1, 3); break;
case 2: __kunmap_atomic_primary(2, 4); break;
case 3: __kunmap_atomic_primary(3, 5); break;
- case 4: __kunmap_atomic_primary(4, 6); break;
- case 5: __kunmap_atomic_primary(5, 7); break;
- case 6: __kunmap_atomic_primary(6, 8); break;
- case 7: __kunmap_atomic_primary(7, 9); break;
- case 8: __kunmap_atomic_primary(8, 10); break;
-
- case 9 ... 9 + NR_TLB_LINES - 1:
- __kunmap_atomic_secondary(type - 9, kvaddr);
- break;
default:
BUG();
@@ -175,6 +157,9 @@ static inline void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
pagefault_enable();
}
+void *__kmap_atomic(struct page *page);
+void __kunmap_atomic(void *kvaddr);
+
#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/arch/frv/include/asm/pgtable.h b/arch/frv/include/asm/pgtable.h
index c18b0d32e636..6bc241e4b4f8 100644
--- a/arch/frv/include/asm/pgtable.h
+++ b/arch/frv/include/asm/pgtable.h
@@ -451,17 +451,12 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
#if defined(CONFIG_HIGHPTE)
#define pte_offset_map(dir, address) \
- ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + pte_index(address))
-#define pte_offset_map_nested(dir, address) \
- ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE1) + pte_index(address))
-#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
-#define pte_unmap_nested(pte) kunmap_atomic((pte), KM_PTE1)
+ ((pte_t *)kmap_atomic(pmd_page(*(dir))) + pte_index(address))
+#define pte_unmap(pte) kunmap_atomic(pte)
#else
#define pte_offset_map(dir, address) \
((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
-#define pte_offset_map_nested(dir, address) pte_offset_map((dir), (address))
#define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
#endif
/*
diff --git a/arch/frv/kernel/ptrace.c b/arch/frv/kernel/ptrace.c
index fac028936a04..9d68f7fac730 100644
--- a/arch/frv/kernel/ptrace.c
+++ b/arch/frv/kernel/ptrace.c
@@ -254,23 +254,26 @@ void ptrace_disable(struct task_struct *child)
user_disable_single_step(child);
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
unsigned long tmp;
int ret;
+ int regno = addr >> 2;
+ unsigned long __user *datap = (unsigned long __user *) data;
switch (request) {
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
tmp = 0;
ret = -EIO;
- if ((addr & 3) || addr < 0)
+ if (addr & 3)
break;
ret = 0;
- switch (addr >> 2) {
+ switch (regno) {
case 0 ... PT__END - 1:
- tmp = get_reg(child, addr >> 2);
+ tmp = get_reg(child, regno);
break;
case PT__END + 0:
@@ -299,23 +302,18 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
if (ret == 0)
- ret = put_user(tmp, (unsigned long *) data);
+ ret = put_user(tmp, datap);
break;
}
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
ret = -EIO;
- if ((addr & 3) || addr < 0)
+ if (addr & 3)
break;
- ret = 0;
- switch (addr >> 2) {
+ switch (regno) {
case 0 ... PT__END - 1:
- ret = put_reg(child, addr >> 2, data);
- break;
-
- default:
- ret = -EIO;
+ ret = put_reg(child, regno, data);
break;
}
break;
@@ -324,25 +322,25 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
return copy_regset_to_user(child, &user_frv_native_view,
REGSET_GENERAL,
0, sizeof(child->thread.user->i),
- (void __user *)data);
+ datap);
case PTRACE_SETREGS: /* Set all integer regs in the child. */
return copy_regset_from_user(child, &user_frv_native_view,
REGSET_GENERAL,
0, sizeof(child->thread.user->i),
- (const void __user *)data);
+ datap);
case PTRACE_GETFPREGS: /* Get the child FP/Media state. */
return copy_regset_to_user(child, &user_frv_native_view,
REGSET_FPMEDIA,
0, sizeof(child->thread.user->f),
- (void __user *)data);
+ datap);
case PTRACE_SETFPREGS: /* Set the child FP/Media state. */
return copy_regset_from_user(child, &user_frv_native_view,
REGSET_FPMEDIA,
0, sizeof(child->thread.user->f),
- (const void __user *)data);
+ datap);
default:
ret = ptrace_request(child, request, addr, data);
diff --git a/arch/frv/mb93090-mb00/pci-dma.c b/arch/frv/mb93090-mb00/pci-dma.c
index 85d110b71cf7..41098a3803a2 100644
--- a/arch/frv/mb93090-mb00/pci-dma.c
+++ b/arch/frv/mb93090-mb00/pci-dma.c
@@ -61,14 +61,14 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
dampr2 = __get_DAMPR(2);
for (i = 0; i < nents; i++) {
- vaddr = kmap_atomic(sg_page(&sg[i]), __KM_CACHE);
+ vaddr = kmap_atomic_primary(sg_page(&sg[i]), __KM_CACHE);
frv_dcache_writeback((unsigned long) vaddr,
(unsigned long) vaddr + PAGE_SIZE);
}
- kunmap_atomic(vaddr, __KM_CACHE);
+ kunmap_atomic_primary(vaddr, __KM_CACHE);
if (dampr2) {
__set_DAMPR(2, dampr2);
__set_IAMPR(2, dampr2);
diff --git a/arch/frv/mm/cache-page.c b/arch/frv/mm/cache-page.c
index 0261cbe153b5..b24ade27a0f0 100644
--- a/arch/frv/mm/cache-page.c
+++ b/arch/frv/mm/cache-page.c
@@ -26,11 +26,11 @@ void flush_dcache_page(struct page *page)
dampr2 = __get_DAMPR(2);
- vaddr = kmap_atomic(page, __KM_CACHE);
+ vaddr = kmap_atomic_primary(page, __KM_CACHE);
frv_dcache_writeback((unsigned long) vaddr, (unsigned long) vaddr + PAGE_SIZE);
- kunmap_atomic(vaddr, __KM_CACHE);
+ kunmap_atomic_primary(vaddr, __KM_CACHE);
if (dampr2) {
__set_DAMPR(2, dampr2);
@@ -54,12 +54,12 @@ void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
dampr2 = __get_DAMPR(2);
- vaddr = kmap_atomic(page, __KM_CACHE);
+ vaddr = kmap_atomic_primary(page, __KM_CACHE);
start = (start & ~PAGE_MASK) | (unsigned long) vaddr;
frv_cache_wback_inv(start, start + len);
- kunmap_atomic(vaddr, __KM_CACHE);
+ kunmap_atomic_primary(vaddr, __KM_CACHE);
if (dampr2) {
__set_DAMPR(2, dampr2);
diff --git a/arch/frv/mm/highmem.c b/arch/frv/mm/highmem.c
index eadd07658075..fd7fcd4c2e33 100644
--- a/arch/frv/mm/highmem.c
+++ b/arch/frv/mm/highmem.c
@@ -36,3 +36,54 @@ struct page *kmap_atomic_to_page(void *ptr)
{
return virt_to_page(ptr);
}
+
+void *__kmap_atomic(struct page *page)
+{
+ unsigned long paddr;
+ int type;
+
+ pagefault_disable();
+ type = kmap_atomic_idx_push();
+ paddr = page_to_phys(page);
+
+ switch (type) {
+ /*
+ * The first 4 primary maps are reserved for architecture code
+ */
+ case 0: return __kmap_atomic_primary(4, paddr, 6);
+ case 1: return __kmap_atomic_primary(5, paddr, 7);
+ case 2: return __kmap_atomic_primary(6, paddr, 8);
+ case 3: return __kmap_atomic_primary(7, paddr, 9);
+ case 4: return __kmap_atomic_primary(8, paddr, 10);
+
+ case 5 ... 5 + NR_TLB_LINES - 1:
+ return __kmap_atomic_secondary(type - 5, paddr);
+
+ default:
+ BUG();
+ return NULL;
+ }
+}
+EXPORT_SYMBOL(__kmap_atomic);
+
+void __kunmap_atomic(void *kvaddr)
+{
+ int type = kmap_atomic_idx();
+ switch (type) {
+ case 0: __kunmap_atomic_primary(4, 6); break;
+ case 1: __kunmap_atomic_primary(5, 7); break;
+ case 2: __kunmap_atomic_primary(6, 8); break;
+ case 3: __kunmap_atomic_primary(7, 9); break;
+ case 4: __kunmap_atomic_primary(8, 10); break;
+
+ case 5 ... 5 + NR_TLB_LINES - 1:
+ __kunmap_atomic_secondary(type - 5, kvaddr);
+ break;
+
+ default:
+ BUG();
+ }
+ kmap_atomic_idx_pop();
+ pagefault_enable();
+}
+EXPORT_SYMBOL(__kunmap_atomic);
diff --git a/arch/h8300/Kconfig.cpu b/arch/h8300/Kconfig.cpu
index 6e2ecff199c5..d236ab4232ca 100644
--- a/arch/h8300/Kconfig.cpu
+++ b/arch/h8300/Kconfig.cpu
@@ -17,7 +17,7 @@ config H8300H_AKI3068NET
help
AKI-H8/3068F / AKI-H8/3069F Flashmicom LAN Board Support
More Information. (Japanese Only)
- <http://akizukidensi.com/catalog/h8.html>
+ <http://akizukidenshi.com/catalog/default.aspx>
AE-3068/69 Evaluation Board Support
More Information.
<http://www.microtronique.com/ae3069lan.htm>
@@ -36,7 +36,7 @@ config H8300H_SIM
help
GDB Simulator Support
More Information.
- arch/h8300/Doc/simulator.txt
+ <http://sourceware.org/sid/>
config H8S_GENERIC
bool "H8S Generic"
@@ -50,14 +50,14 @@ config H8S_EDOSK2674
Renesas EDOSK-2674 Evaluation Board Support
More Information.
<http://www.azpower.com/H8-uClinux/index.html>
- <http://www.eu.renesas.com/tools/edk/support/edosk2674.html>
+ <http://www.renesas.eu/products/tools/introductory_evaluation_tools/evaluation_development_os_kits/edosk2674r/edosk2674r_software_tools_root.jsp>
config H8S_SIM
bool "H8S Simulator"
help
GDB Simulator Support
More Information.
- arch/h8300/Doc/simulator.txt
+ <http://sourceware.org/sid/>
endchoice
diff --git a/arch/h8300/README b/arch/h8300/README
index 2fd6f6d7a019..637f5a02f311 100644
--- a/arch/h8300/README
+++ b/arch/h8300/README
@@ -18,6 +18,7 @@ H8/300H and H8S
4.EDOSK2674
see http://www.eu.renesas.com/products/mpumcu/tool/edk/support/edosk2674.html
+ http://www.uclinux.org/pub/uClinux/ports/h8/HITACHI-EDOSK2674-HOWTO
http://www.azpower.com/H8-uClinux/
* Toolchain Version
diff --git a/arch/h8300/kernel/ptrace.c b/arch/h8300/kernel/ptrace.c
index df114122ebdf..497fa89b5df4 100644
--- a/arch/h8300/kernel/ptrace.c
+++ b/arch/h8300/kernel/ptrace.c
@@ -50,27 +50,29 @@ void ptrace_disable(struct task_struct *child)
user_disable_single_step(child);
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret;
+ int regno = addr >> 2;
+ unsigned long __user *datap = (unsigned long __user *) data;
switch (request) {
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
unsigned long tmp = 0;
- if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
+ if ((addr & 3) || addr >= sizeof(struct user)) {
ret = -EIO;
break ;
}
ret = 0; /* Default return condition */
- addr = addr >> 2; /* temporary hack. */
- if (addr < H8300_REGS_NO)
- tmp = h8300_get_reg(child, addr);
+ if (regno < H8300_REGS_NO)
+ tmp = h8300_get_reg(child, regno);
else {
- switch(addr) {
+ switch (regno) {
case 49:
tmp = child->mm->start_code;
break ;
@@ -88,24 +90,23 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
}
if (!ret)
- ret = put_user(tmp,(unsigned long *) data);
+ ret = put_user(tmp, datap);
break ;
}
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
- if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
+ if ((addr & 3) || addr >= sizeof(struct user)) {
ret = -EIO;
break ;
}
- addr = addr >> 2; /* temporary hack. */
- if (addr == PT_ORIG_ER0) {
+ if (regno == PT_ORIG_ER0) {
ret = -EIO;
break ;
}
- if (addr < H8300_REGS_NO) {
- ret = h8300_put_reg(child, addr, data);
+ if (regno < H8300_REGS_NO) {
+ ret = h8300_put_reg(child, regno, data);
break ;
}
ret = -EIO;
@@ -116,11 +117,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
unsigned long tmp;
for (i = 0; i < H8300_REGS_NO; i++) {
tmp = h8300_get_reg(child, i);
- if (put_user(tmp, (unsigned long *) data)) {
+ if (put_user(tmp, datap)) {
ret = -EFAULT;
break;
}
- data += sizeof(long);
+ datap++;
}
ret = 0;
break;
@@ -130,12 +131,12 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
int i;
unsigned long tmp;
for (i = 0; i < H8300_REGS_NO; i++) {
- if (get_user(tmp, (unsigned long *) data)) {
+ if (get_user(tmp, datap)) {
ret = -EFAULT;
break;
}
h8300_put_reg(child, i, tmp);
- data += sizeof(long);
+ datap++;
}
ret = 0;
break;
diff --git a/arch/ia64/include/asm/cputime.h b/arch/ia64/include/asm/cputime.h
index 7fa8a8594660..6073b187528a 100644
--- a/arch/ia64/include/asm/cputime.h
+++ b/arch/ia64/include/asm/cputime.h
@@ -56,10 +56,10 @@ typedef u64 cputime64_t;
#define jiffies64_to_cputime64(__jif) ((__jif) * (NSEC_PER_SEC / HZ))
/*
- * Convert cputime <-> milliseconds
+ * Convert cputime <-> microseconds
*/
-#define cputime_to_msecs(__ct) ((__ct) / NSEC_PER_MSEC)
-#define msecs_to_cputime(__msecs) ((__msecs) * NSEC_PER_MSEC)
+#define cputime_to_usecs(__ct) ((__ct) / NSEC_PER_USEC)
+#define usecs_to_cputime(__usecs) ((__usecs) * NSEC_PER_USEC)
/*
* Convert cputime <-> seconds
diff --git a/arch/ia64/include/asm/pgtable.h b/arch/ia64/include/asm/pgtable.h
index c3286f42e501..1a97af31ef17 100644
--- a/arch/ia64/include/asm/pgtable.h
+++ b/arch/ia64/include/asm/pgtable.h
@@ -406,9 +406,7 @@ pgd_offset (const struct mm_struct *mm, unsigned long address)
#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
#define pte_offset_kernel(dir,addr) ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(addr))
#define pte_offset_map(dir,addr) pte_offset_kernel(dir, addr)
-#define pte_offset_map_nested(dir,addr) pte_offset_map(dir, addr)
#define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
/* atomic versions of the some PTE manipulations: */
diff --git a/arch/ia64/include/asm/siginfo.h b/arch/ia64/include/asm/siginfo.h
index 118d42979003..c8fcaa2ac48f 100644
--- a/arch/ia64/include/asm/siginfo.h
+++ b/arch/ia64/include/asm/siginfo.h
@@ -62,6 +62,7 @@ typedef struct siginfo {
int _imm; /* immediate value for "break" */
unsigned int _flags; /* see below */
unsigned long _isr; /* isr */
+ short _addr_lsb; /* lsb of faulting address */
} _sigfault;
/* SIGPOLL */
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index 7c7909f9bc93..8848f43d819e 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -1177,7 +1177,8 @@ ptrace_disable (struct task_struct *child)
}
long
-arch_ptrace (struct task_struct *child, long request, long addr, long data)
+arch_ptrace (struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
switch (request) {
case PTRACE_PEEKTEXT:
diff --git a/arch/ia64/kvm/lapic.h b/arch/ia64/kvm/lapic.h
index ee541cebcd78..c5f92a926a9a 100644
--- a/arch/ia64/kvm/lapic.h
+++ b/arch/ia64/kvm/lapic.h
@@ -25,5 +25,6 @@ int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2);
int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq);
#define kvm_apic_present(x) (true)
+#define kvm_lapic_enabled(x) (true)
#endif
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index 836abbbc9c04..3867fd21f333 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -315,7 +315,7 @@ config SMP
Management" code will be disabled if you say Y here.
See also the SMP-HOWTO available at
- <http://www.linuxdoc.org/docs.html#howto>.
+ <http://tldp.org/HOWTO/SMP-HOWTO.html>.
If you don't know what to do here, say N.
diff --git a/arch/m32r/include/asm/pgtable.h b/arch/m32r/include/asm/pgtable.h
index e6359c566b50..8a28cfea2729 100644
--- a/arch/m32r/include/asm/pgtable.h
+++ b/arch/m32r/include/asm/pgtable.h
@@ -332,9 +332,7 @@ static inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
((pte_t *)pmd_page_vaddr(*(dir)) + pte_index(address))
#define pte_offset_map(dir, address) \
((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
-#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
#define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
/* Encode and de-code a swap entry */
#define __swp_type(x) (((x).val >> 2) & 0x1f)
diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c
index 0021ade4cba8..20743754f2b2 100644
--- a/arch/m32r/kernel/ptrace.c
+++ b/arch/m32r/kernel/ptrace.c
@@ -622,9 +622,11 @@ void ptrace_disable(struct task_struct *child)
}
long
-arch_ptrace(struct task_struct *child, long request, long addr, long data)
+arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret;
+ unsigned long __user *datap = (unsigned long __user *) data;
switch (request) {
/*
@@ -639,8 +641,7 @@ arch_ptrace(struct task_struct *child, long request, long addr, long data)
* read the word at location addr in the USER area.
*/
case PTRACE_PEEKUSR:
- ret = ptrace_read_user(child, addr,
- (unsigned long __user *)data);
+ ret = ptrace_read_user(child, addr, datap);
break;
/*
@@ -661,11 +662,11 @@ arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
case PTRACE_GETREGS:
- ret = ptrace_getregs(child, (void __user *)data);
+ ret = ptrace_getregs(child, datap);
break;
case PTRACE_SETREGS:
- ret = ptrace_setregs(child, (void __user *)data);
+ ret = ptrace_setregs(child, datap);
break;
default:
diff --git a/arch/m68k/include/asm/cacheflush_no.h b/arch/m68k/include/asm/cacheflush_no.h
index 89f195656be7..7085bd51668b 100644
--- a/arch/m68k/include/asm/cacheflush_no.h
+++ b/arch/m68k/include/asm/cacheflush_no.h
@@ -29,7 +29,7 @@
static inline void __flush_cache_all(void)
{
-#ifdef CONFIG_M5407
+#if defined(CONFIG_M5407) || defined(CONFIG_M548x)
/*
* Use cpushl to push and invalidate all cache lines.
* Gas doesn't seem to know how to generate the ColdFire
diff --git a/arch/m68k/include/asm/coldfire.h b/arch/m68k/include/asm/coldfire.h
index 83a9fa4e618a..3b0a34d0fe33 100644
--- a/arch/m68k/include/asm/coldfire.h
+++ b/arch/m68k/include/asm/coldfire.h
@@ -32,7 +32,9 @@
*/
#define MCF_MBAR 0x10000000
#define MCF_MBAR2 0x80000000
-#if defined(CONFIG_M520x)
+#if defined(CONFIG_M548x)
+#define MCF_IPSBAR MCF_MBAR
+#elif defined(CONFIG_M520x)
#define MCF_IPSBAR 0xFC000000
#else
#define MCF_IPSBAR 0x40000000
diff --git a/arch/m68k/include/asm/entry_mm.h b/arch/m68k/include/asm/entry_mm.h
index e41fea399bfe..73b8c8fbed9c 100644
--- a/arch/m68k/include/asm/entry_mm.h
+++ b/arch/m68k/include/asm/entry_mm.h
@@ -50,14 +50,6 @@
LFLUSH_I_AND_D = 0x00000808
-/* process bits for task_struct.ptrace */
-PT_TRACESYS_OFF = 3
-PT_TRACESYS_BIT = 1
-PT_PTRACED_OFF = 3
-PT_PTRACED_BIT = 0
-PT_DTRACE_OFF = 3
-PT_DTRACE_BIT = 2
-
#define SAVE_ALL_INT save_all_int
#define SAVE_ALL_SYS save_all_sys
#define RESTORE_ALL restore_all
diff --git a/arch/m68k/include/asm/entry_no.h b/arch/m68k/include/asm/entry_no.h
index 80e41492aa2a..26be277394f9 100644
--- a/arch/m68k/include/asm/entry_no.h
+++ b/arch/m68k/include/asm/entry_no.h
@@ -32,16 +32,6 @@
#ifdef __ASSEMBLY__
-/* process bits for task_struct.flags */
-PF_TRACESYS_OFF = 3
-PF_TRACESYS_BIT = 5
-PF_PTRACED_OFF = 3
-PF_PTRACED_BIT = 4
-PF_DTRACE_OFF = 1
-PF_DTRACE_BIT = 5
-
-LENOSYS = 38
-
#define SWITCH_STACK_SIZE (6*4+4) /* Includes return address */
/*
diff --git a/arch/m68k/include/asm/gpio.h b/arch/m68k/include/asm/gpio.h
index 283214dc65a7..1b57adbafad5 100644
--- a/arch/m68k/include/asm/gpio.h
+++ b/arch/m68k/include/asm/gpio.h
@@ -36,7 +36,8 @@
*/
#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
- defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x)
+ defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+ defined(CONFIG_M532x) || defined(CONFIG_M548x)
/* These parts have GPIO organized by 8 bit ports */
@@ -136,6 +137,8 @@ static inline u32 __mcf_gpio_ppdr(unsigned gpio)
#endif
else
return MCFGPIO_PPDR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
+#else
+ return 0;
#endif
}
@@ -173,6 +176,8 @@ static inline u32 __mcf_gpio_podr(unsigned gpio)
#endif
else
return MCFGPIO_PODR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
+#else
+ return 0;
#endif
}
diff --git a/arch/m68k/include/asm/m548xgpt.h b/arch/m68k/include/asm/m548xgpt.h
new file mode 100644
index 000000000000..c8ef158a1c4e
--- /dev/null
+++ b/arch/m68k/include/asm/m548xgpt.h
@@ -0,0 +1,88 @@
+/*
+ * File: m548xgpt.h
+ * Purpose: Register and bit definitions for the MCF548X
+ *
+ * Notes:
+ *
+ */
+
+#ifndef m548xgpt_h
+#define m548xgpt_h
+
+/*********************************************************************
+*
+* General Purpose Timers (GPT)
+*
+*********************************************************************/
+
+/* Register read/write macros */
+#define MCF_GPT_GMS0 0x000800
+#define MCF_GPT_GCIR0 0x000804
+#define MCF_GPT_GPWM0 0x000808
+#define MCF_GPT_GSR0 0x00080C
+#define MCF_GPT_GMS1 0x000810
+#define MCF_GPT_GCIR1 0x000814
+#define MCF_GPT_GPWM1 0x000818
+#define MCF_GPT_GSR1 0x00081C
+#define MCF_GPT_GMS2 0x000820
+#define MCF_GPT_GCIR2 0x000824
+#define MCF_GPT_GPWM2 0x000828
+#define MCF_GPT_GSR2 0x00082C
+#define MCF_GPT_GMS3 0x000830
+#define MCF_GPT_GCIR3 0x000834
+#define MCF_GPT_GPWM3 0x000838
+#define MCF_GPT_GSR3 0x00083C
+#define MCF_GPT_GMS(x) (0x000800+((x)*0x010))
+#define MCF_GPT_GCIR(x) (0x000804+((x)*0x010))
+#define MCF_GPT_GPWM(x) (0x000808+((x)*0x010))
+#define MCF_GPT_GSR(x) (0x00080C+((x)*0x010))
+
+/* Bit definitions and macros for MCF_GPT_GMS */
+#define MCF_GPT_GMS_TMS(x) (((x)&0x00000007)<<0)
+#define MCF_GPT_GMS_GPIO(x) (((x)&0x00000003)<<4)
+#define MCF_GPT_GMS_IEN (0x00000100)
+#define MCF_GPT_GMS_OD (0x00000200)
+#define MCF_GPT_GMS_SC (0x00000400)
+#define MCF_GPT_GMS_CE (0x00001000)
+#define MCF_GPT_GMS_WDEN (0x00008000)
+#define MCF_GPT_GMS_ICT(x) (((x)&0x00000003)<<16)
+#define MCF_GPT_GMS_OCT(x) (((x)&0x00000003)<<20)
+#define MCF_GPT_GMS_OCPW(x) (((x)&0x000000FF)<<24)
+#define MCF_GPT_GMS_OCT_FRCLOW (0x00000000)
+#define MCF_GPT_GMS_OCT_PULSEHI (0x00100000)
+#define MCF_GPT_GMS_OCT_PULSELO (0x00200000)
+#define MCF_GPT_GMS_OCT_TOGGLE (0x00300000)
+#define MCF_GPT_GMS_ICT_ANY (0x00000000)
+#define MCF_GPT_GMS_ICT_RISE (0x00010000)
+#define MCF_GPT_GMS_ICT_FALL (0x00020000)
+#define MCF_GPT_GMS_ICT_PULSE (0x00030000)
+#define MCF_GPT_GMS_GPIO_INPUT (0x00000000)
+#define MCF_GPT_GMS_GPIO_OUTLO (0x00000020)
+#define MCF_GPT_GMS_GPIO_OUTHI (0x00000030)
+#define MCF_GPT_GMS_TMS_DISABLE (0x00000000)
+#define MCF_GPT_GMS_TMS_INCAPT (0x00000001)
+#define MCF_GPT_GMS_TMS_OUTCAPT (0x00000002)
+#define MCF_GPT_GMS_TMS_PWM (0x00000003)
+#define MCF_GPT_GMS_TMS_GPIO (0x00000004)
+
+/* Bit definitions and macros for MCF_GPT_GCIR */
+#define MCF_GPT_GCIR_CNT(x) (((x)&0x0000FFFF)<<0)
+#define MCF_GPT_GCIR_PRE(x) (((x)&0x0000FFFF)<<16)
+
+/* Bit definitions and macros for MCF_GPT_GPWM */
+#define MCF_GPT_GPWM_LOAD (0x00000001)
+#define MCF_GPT_GPWM_PWMOP (0x00000100)
+#define MCF_GPT_GPWM_WIDTH(x) (((x)&0x0000FFFF)<<16)
+
+/* Bit definitions and macros for MCF_GPT_GSR */
+#define MCF_GPT_GSR_CAPT (0x00000001)
+#define MCF_GPT_GSR_COMP (0x00000002)
+#define MCF_GPT_GSR_PWMP (0x00000004)
+#define MCF_GPT_GSR_TEXP (0x00000008)
+#define MCF_GPT_GSR_PIN (0x00000100)
+#define MCF_GPT_GSR_OVF(x) (((x)&0x00000007)<<12)
+#define MCF_GPT_GSR_CAPTURE(x) (((x)&0x0000FFFF)<<16)
+
+/********************************************************************/
+
+#endif /* m548xgpt_h */
diff --git a/arch/m68k/include/asm/m548xsim.h b/arch/m68k/include/asm/m548xsim.h
new file mode 100644
index 000000000000..149135ef30d2
--- /dev/null
+++ b/arch/m68k/include/asm/m548xsim.h
@@ -0,0 +1,55 @@
+/*
+ * m548xsim.h -- ColdFire 547x/548x System Integration Unit support.
+ */
+
+#ifndef m548xsim_h
+#define m548xsim_h
+
+#define MCFINT_VECBASE 64
+
+/*
+ * Interrupt Controller Registers
+ */
+#define MCFICM_INTC0 0x0700 /* Base for Interrupt Ctrl 0 */
+#define MCFINTC_IPRH 0x00 /* Interrupt pending 32-63 */
+#define MCFINTC_IPRL 0x04 /* Interrupt pending 1-31 */
+#define MCFINTC_IMRH 0x08 /* Interrupt mask 32-63 */
+#define MCFINTC_IMRL 0x0c /* Interrupt mask 1-31 */
+#define MCFINTC_INTFRCH 0x10 /* Interrupt force 32-63 */
+#define MCFINTC_INTFRCL 0x14 /* Interrupt force 1-31 */
+#define MCFINTC_IRLR 0x18 /* */
+#define MCFINTC_IACKL 0x19 /* */
+#define MCFINTC_ICR0 0x40 /* Base ICR register */
+
+/*
+ * Define system peripheral IRQ usage.
+ */
+#define MCF_IRQ_TIMER (64 + 54) /* Slice Timer 0 */
+#define MCF_IRQ_PROFILER (64 + 53) /* Slice Timer 1 */
+
+/*
+ * Generic GPIO support
+ */
+#define MCFGPIO_PIN_MAX 0 /* I am too lazy to count */
+#define MCFGPIO_IRQ_MAX -1
+#define MCFGPIO_IRQ_VECBASE -1
+
+/*
+ * Some PSC related definitions
+ */
+#define MCF_PAR_PSC(x) (0x000A4F-((x)&0x3))
+#define MCF_PAR_SDA (0x0008)
+#define MCF_PAR_SCL (0x0004)
+#define MCF_PAR_PSC_TXD (0x04)
+#define MCF_PAR_PSC_RXD (0x08)
+#define MCF_PAR_PSC_RTS(x) (((x)&0x03)<<4)
+#define MCF_PAR_PSC_CTS(x) (((x)&0x03)<<6)
+#define MCF_PAR_PSC_CTS_GPIO (0x00)
+#define MCF_PAR_PSC_CTS_BCLK (0x80)
+#define MCF_PAR_PSC_CTS_CTS (0xC0)
+#define MCF_PAR_PSC_RTS_GPIO (0x00)
+#define MCF_PAR_PSC_RTS_FSYNC (0x20)
+#define MCF_PAR_PSC_RTS_RTS (0x30)
+#define MCF_PAR_PSC_CANRX (0x40)
+
+#endif /* m548xsim_h */
diff --git a/arch/m68k/include/asm/mcfcache.h b/arch/m68k/include/asm/mcfcache.h
index c042634fadaa..f49dfc09f70a 100644
--- a/arch/m68k/include/asm/mcfcache.h
+++ b/arch/m68k/include/asm/mcfcache.h
@@ -107,7 +107,7 @@
.endm
#endif /* CONFIG_M532x */
-#if defined(CONFIG_M5407)
+#if defined(CONFIG_M5407) || defined(CONFIG_M548x)
/*
* Version 4 cores have a true harvard style separate instruction
* and data cache. Invalidate and enable cache, also enable write
diff --git a/arch/m68k/include/asm/mcfsim.h b/arch/m68k/include/asm/mcfsim.h
index 9c70a67bf85f..6901fd68165b 100644
--- a/arch/m68k/include/asm/mcfsim.h
+++ b/arch/m68k/include/asm/mcfsim.h
@@ -41,6 +41,8 @@
#elif defined(CONFIG_M5407)
#include <asm/m5407sim.h>
#include <asm/mcfintc.h>
+#elif defined(CONFIG_M548x)
+#include <asm/m548xsim.h>
#endif
/****************************************************************************/
diff --git a/arch/m68k/include/asm/mcfslt.h b/arch/m68k/include/asm/mcfslt.h
new file mode 100644
index 000000000000..d0d0ecba5333
--- /dev/null
+++ b/arch/m68k/include/asm/mcfslt.h
@@ -0,0 +1,44 @@
+/****************************************************************************/
+
+/*
+ * mcfslt.h -- ColdFire internal Slice (SLT) timer support defines.
+ *
+ * (C) Copyright 2004, Greg Ungerer (gerg@snapgear.com)
+ * (C) Copyright 2009, Philippe De Muyter (phdm@macqel.be)
+ */
+
+/****************************************************************************/
+#ifndef mcfslt_h
+#define mcfslt_h
+/****************************************************************************/
+
+/*
+ * Get address specific defines for the 547x.
+ */
+#define MCFSLT_TIMER0 0x900 /* Base address of TIMER0 */
+#define MCFSLT_TIMER1 0x910 /* Base address of TIMER1 */
+
+
+/*
+ * Define the SLT timer register set addresses.
+ */
+#define MCFSLT_STCNT 0x00 /* Terminal count */
+#define MCFSLT_SCR 0x04 /* Control */
+#define MCFSLT_SCNT 0x08 /* Current count */
+#define MCFSLT_SSR 0x0C /* Status */
+
+/*
+ * Bit definitions for the SCR control register.
+ */
+#define MCFSLT_SCR_RUN 0x04000000 /* Run mode (continuous) */
+#define MCFSLT_SCR_IEN 0x02000000 /* Interrupt enable */
+#define MCFSLT_SCR_TEN 0x01000000 /* Timer enable */
+
+/*
+ * Bit definitions for the SSR status register.
+ */
+#define MCFSLT_SSR_BE 0x02000000 /* Bus error condition */
+#define MCFSLT_SSR_TE 0x01000000 /* Timeout condition */
+
+/****************************************************************************/
+#endif /* mcfslt_h */
diff --git a/arch/m68k/include/asm/mcfuart.h b/arch/m68k/include/asm/mcfuart.h
index 01a8716c5fc5..db72e2b889ca 100644
--- a/arch/m68k/include/asm/mcfuart.h
+++ b/arch/m68k/include/asm/mcfuart.h
@@ -47,6 +47,11 @@
#define MCFUART_BASE1 0xfc060000 /* Base address of UART1 */
#define MCFUART_BASE2 0xfc064000 /* Base address of UART2 */
#define MCFUART_BASE3 0xfc068000 /* Base address of UART3 */
+#elif defined(CONFIG_M548x)
+#define MCFUART_BASE1 0x8600 /* on M548x */
+#define MCFUART_BASE2 0x8700 /* on M548x */
+#define MCFUART_BASE3 0x8800 /* on M548x */
+#define MCFUART_BASE4 0x8900 /* on M548x */
#endif
@@ -212,7 +217,9 @@ struct mcf_platform_uart {
#define MCFUART_URF_RXS 0xc0 /* Receiver status */
#endif
-#if defined(CONFIG_M5272)
+#if defined(CONFIG_M548x)
+#define MCFUART_TXFIFOSIZE 512
+#elif defined(CONFIG_M5272)
#define MCFUART_TXFIFOSIZE 25
#else
#define MCFUART_TXFIFOSIZE 1
diff --git a/arch/m68k/include/asm/motorola_pgtable.h b/arch/m68k/include/asm/motorola_pgtable.h
index 8e9a8a754dde..45bd3f589bf0 100644
--- a/arch/m68k/include/asm/motorola_pgtable.h
+++ b/arch/m68k/include/asm/motorola_pgtable.h
@@ -221,9 +221,7 @@ static inline pte_t *pte_offset_kernel(pmd_t *pmdp, unsigned long address)
}
#define pte_offset_map(pmdp,address) ((pte_t *)__pmd_page(*pmdp) + (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
-#define pte_offset_map_nested(pmdp, address) pte_offset_map(pmdp, address)
#define pte_unmap(pte) ((void)0)
-#define pte_unmap_nested(pte) ((void)0)
/*
* Allocate and free page tables. The xxx_kernel() versions are
diff --git a/arch/m68k/include/asm/sun3_pgtable.h b/arch/m68k/include/asm/sun3_pgtable.h
index f847ec732d62..cf5fad9b5250 100644
--- a/arch/m68k/include/asm/sun3_pgtable.h
+++ b/arch/m68k/include/asm/sun3_pgtable.h
@@ -219,9 +219,7 @@ static inline pte_t pgoff_to_pte(unsigned off)
#define pte_offset_kernel(pmd, address) ((pte_t *) __pmd_page(*pmd) + pte_index(address))
/* FIXME: should we bother with kmap() here? */
#define pte_offset_map(pmd, address) ((pte_t *)kmap(pmd_page(*pmd)) + pte_index(address))
-#define pte_offset_map_nested(pmd, address) pte_offset_map(pmd, address)
#define pte_unmap(pte) kunmap(pte)
-#define pte_unmap_nested(pte) kunmap(pte)
/* Macros to (de)construct the fake PTEs representing swap pages. */
#define __swp_type(x) ((x).val & 0x7F)
diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c
index 73e5e581245b..78e59b82ebc3 100644
--- a/arch/m68k/kernel/asm-offsets.c
+++ b/arch/m68k/kernel/asm-offsets.c
@@ -22,13 +22,9 @@
int main(void)
{
/* offsets into the task struct */
- DEFINE(TASK_STATE, offsetof(struct task_struct, state));
- DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
- DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
DEFINE(TASK_MM, offsetof(struct task_struct, mm));
- DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
#ifdef CONFIG_MMU
DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info));
#endif
@@ -64,14 +60,6 @@ int main(void)
/* bitfields are a bit difficult */
DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
- /* offsets into the irq_handler struct */
- DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler));
- DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id));
- DEFINE(IRQ_NEXT, offsetof(struct irq_node, next));
-
- /* offsets into the kernel_stat struct */
- DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs));
-
/* offsets into the irq_cpustat_t struct */
DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 616e59752c29..0b252683cefb 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -156,55 +156,57 @@ void user_disable_single_step(struct task_struct *child)
singlestep_disable(child);
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
unsigned long tmp;
int i, ret = 0;
+ int regno = addr >> 2; /* temporary hack. */
+ unsigned long __user *datap = (unsigned long __user *) data;
switch (request) {
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR:
if (addr & 3)
goto out_eio;
- addr >>= 2; /* temporary hack. */
- if (addr >= 0 && addr < 19) {
- tmp = get_reg(child, addr);
- } else if (addr >= 21 && addr < 49) {
- tmp = child->thread.fp[addr - 21];
+ if (regno >= 0 && regno < 19) {
+ tmp = get_reg(child, regno);
+ } else if (regno >= 21 && regno < 49) {
+ tmp = child->thread.fp[regno - 21];
/* Convert internal fpu reg representation
* into long double format
*/
- if (FPU_IS_EMU && (addr < 45) && !(addr % 3))
+ if (FPU_IS_EMU && (regno < 45) && !(regno % 3))
tmp = ((tmp & 0xffff0000) << 15) |
((tmp & 0x0000ffff) << 16);
} else
goto out_eio;
- ret = put_user(tmp, (unsigned long *)data);
+ ret = put_user(tmp, datap);
break;
- case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+ case PTRACE_POKEUSR:
+ /* write the word at location addr in the USER area */
if (addr & 3)
goto out_eio;
- addr >>= 2; /* temporary hack. */
- if (addr == PT_SR) {
+ if (regno == PT_SR) {
data &= SR_MASK;
data |= get_reg(child, PT_SR) & ~SR_MASK;
}
- if (addr >= 0 && addr < 19) {
- if (put_reg(child, addr, data))
+ if (regno >= 0 && regno < 19) {
+ if (put_reg(child, regno, data))
goto out_eio;
- } else if (addr >= 21 && addr < 48) {
+ } else if (regno >= 21 && regno < 48) {
/* Convert long double format
* into internal fpu reg representation
*/
- if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) {
- data = (unsigned long)data << 15;
+ if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) {
+ data <<= 15;
data = (data & 0xffff0000) |
((data & 0x0000ffff) >> 1);
}
- child->thread.fp[addr - 21] = data;
+ child->thread.fp[regno - 21] = data;
} else
goto out_eio;
break;
@@ -212,16 +214,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_GETREGS: /* Get all gp regs from the child. */
for (i = 0; i < 19; i++) {
tmp = get_reg(child, i);
- ret = put_user(tmp, (unsigned long *)data);
+ ret = put_user(tmp, datap);
if (ret)
break;
- data += sizeof(long);
+ datap++;
}
break;
case PTRACE_SETREGS: /* Set all gp regs in the child. */
for (i = 0; i < 19; i++) {
- ret = get_user(tmp, (unsigned long *)data);
+ ret = get_user(tmp, datap);
if (ret)
break;
if (i == PT_SR) {
@@ -229,25 +231,24 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
tmp |= get_reg(child, PT_SR) & ~SR_MASK;
}
put_reg(child, i, tmp);
- data += sizeof(long);
+ datap++;
}
break;
case PTRACE_GETFPREGS: /* Get the child FPU state. */
- if (copy_to_user((void *)data, &child->thread.fp,
+ if (copy_to_user(datap, &child->thread.fp,
sizeof(struct user_m68kfp_struct)))
ret = -EFAULT;
break;
case PTRACE_SETFPREGS: /* Set the child FPU state. */
- if (copy_from_user(&child->thread.fp, (void *)data,
+ if (copy_from_user(&child->thread.fp, datap,
sizeof(struct user_m68kfp_struct)))
ret = -EFAULT;
break;
case PTRACE_GET_THREAD_AREA:
- ret = put_user(task_thread_info(child)->tp_value,
- (unsigned long __user *)data);
+ ret = put_user(task_thread_info(child)->tp_value, datap);
break;
default:
diff --git a/arch/m68k/mac/macboing.c b/arch/m68k/mac/macboing.c
index 05285d08e547..ffaa1f6439ae 100644
--- a/arch/m68k/mac/macboing.c
+++ b/arch/m68k/mac/macboing.c
@@ -114,7 +114,8 @@ static void mac_init_asc( void )
* 16-bit I/O functionality. The PowerBook 500 series computers
* support 16-bit stereo output, but only mono input."
*
- * http://til.info.apple.com/techinfo.nsf/artnum/n16405
+ * Technical Information Library (TIL) article number 16405.
+ * http://support.apple.com/kb/TA32601
*
* --David Kilzer
*/
diff --git a/arch/m68k/q40/README b/arch/m68k/q40/README
index 6bdbf4879570..f877b7249790 100644
--- a/arch/m68k/q40/README
+++ b/arch/m68k/q40/README
@@ -3,7 +3,7 @@ Linux for the Q40
You may try http://www.geocities.com/SiliconValley/Bay/2602/ for
some up to date information. Booter and other tools will be also
-available from this place or ftp.uni-erlangen.de/linux/680x0/q40/
+available from this place or http://ftp.uni-erlangen.de/pub/unix/Linux/680x0/q40/
and mirrors.
Hints to documentation usually refer to the linux source tree in
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index 2609c394e1df..9287150e5fb0 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -59,6 +59,10 @@ config GENERIC_HARDIRQS
bool
default y
+config GENERIC_HARDIRQS_NO__DO_IRQ
+ bool
+ default y
+
config GENERIC_CALIBRATE_DELAY
bool
default y
@@ -171,6 +175,11 @@ config M5407
help
Motorola ColdFire 5407 processor support.
+config M548x
+ bool "MCF548x"
+ help
+ Freescale ColdFire 5480/5481/5482/5483/5484/5485 processor support.
+
endchoice
config M527x
@@ -181,7 +190,7 @@ config M527x
config COLDFIRE
bool
- depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407)
+ depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407 || M548x)
select GENERIC_GPIO
select ARCH_REQUIRE_GPIOLIB
default y
diff --git a/arch/m68knommu/Makefile b/arch/m68knommu/Makefile
index 14042574ac21..026ef16fa68e 100644
--- a/arch/m68knommu/Makefile
+++ b/arch/m68knommu/Makefile
@@ -25,6 +25,7 @@ platform-$(CONFIG_M528x) := 528x
platform-$(CONFIG_M5307) := 5307
platform-$(CONFIG_M532x) := 532x
platform-$(CONFIG_M5407) := 5407
+platform-$(CONFIG_M548x) := 548x
PLATFORM := $(platform-y)
board-$(CONFIG_PILOT) := pilot
@@ -73,6 +74,7 @@ cpuclass-$(CONFIG_M528x) := coldfire
cpuclass-$(CONFIG_M5307) := coldfire
cpuclass-$(CONFIG_M532x) := coldfire
cpuclass-$(CONFIG_M5407) := coldfire
+cpuclass-$(CONFIG_M548x) := coldfire
cpuclass-$(CONFIG_M68328) := 68328
cpuclass-$(CONFIG_M68EZ328) := 68328
cpuclass-$(CONFIG_M68VZ328) := 68328
@@ -100,6 +102,7 @@ cflags-$(CONFIG_M528x) := $(call cc-option,-m528x,-m5307)
cflags-$(CONFIG_M5307) := $(call cc-option,-m5307,-m5200)
cflags-$(CONFIG_M532x) := $(call cc-option,-mcpu=532x,-m5307)
cflags-$(CONFIG_M5407) := $(call cc-option,-m5407,-m5200)
+cflags-$(CONFIG_M548x) := $(call cc-option,-m5407,-m5200)
cflags-$(CONFIG_M68328) := -m68000
cflags-$(CONFIG_M68EZ328) := -m68000
cflags-$(CONFIG_M68VZ328) := -m68000
diff --git a/arch/m68knommu/kernel/.gitignore b/arch/m68knommu/kernel/.gitignore
new file mode 100644
index 000000000000..c5f676c3c224
--- /dev/null
+++ b/arch/m68knommu/kernel/.gitignore
@@ -0,0 +1 @@
+vmlinux.lds
diff --git a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c
index 24335022fa2c..ffe02f41ad46 100644
--- a/arch/m68knommu/kernel/asm-offsets.c
+++ b/arch/m68knommu/kernel/asm-offsets.c
@@ -21,14 +21,8 @@
int main(void)
{
/* offsets into the task struct */
- DEFINE(TASK_STATE, offsetof(struct task_struct, state));
- DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
- DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
- DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
- DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
DEFINE(TASK_MM, offsetof(struct task_struct, mm));
- DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
/* offsets into the irq_cpustat_t struct */
DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
@@ -63,7 +57,7 @@ int main(void)
DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
#else
/* bitfields are a bit difficult */
- DEFINE(PT_OFF_VECTOR, offsetof(struct pt_regs, pc) + 4);
+ DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
#endif
/* signal defines */
@@ -75,11 +69,8 @@ int main(void)
DEFINE(PT_PTRACED, PT_PTRACED);
/* Offsets in thread_info structure */
- DEFINE(TI_TASK, offsetof(struct thread_info, task));
- DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count));
- DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
return 0;
}
diff --git a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c
index f6be1248d216..6709fb707335 100644
--- a/arch/m68knommu/kernel/ptrace.c
+++ b/arch/m68knommu/kernel/ptrace.c
@@ -18,6 +18,7 @@
#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/signal.h>
+#include <linux/tracehook.h>
#include <asm/uaccess.h>
#include <asm/page.h>
@@ -111,9 +112,12 @@ void ptrace_disable(struct task_struct *child)
user_disable_single_step(child);
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret;
+ int regno = addr >> 2;
+ unsigned long __user *datap = (unsigned long __user *) data;
switch (request) {
/* read the word at location addr in the USER area. */
@@ -121,71 +125,48 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
unsigned long tmp;
ret = -EIO;
- if ((addr & 3) || addr < 0 ||
- addr > sizeof(struct user) - 3)
+ if ((addr & 3) || addr > sizeof(struct user) - 3)
break;
tmp = 0; /* Default return condition */
- addr = addr >> 2; /* temporary hack. */
ret = -EIO;
- if (addr < 19) {
- tmp = get_reg(child, addr);
- if (addr == PT_SR)
+ if (regno < 19) {
+ tmp = get_reg(child, regno);
+ if (regno == PT_SR)
tmp >>= 16;
- } else if (addr >= 21 && addr < 49) {
- tmp = child->thread.fp[addr - 21];
-#ifdef CONFIG_M68KFPU_EMU
- /* Convert internal fpu reg representation
- * into long double format
- */
- if (FPU_IS_EMU && (addr < 45) && !(addr % 3))
- tmp = ((tmp & 0xffff0000) << 15) |
- ((tmp & 0x0000ffff) << 16);
-#endif
- } else if (addr == 49) {
+ } else if (regno >= 21 && regno < 49) {
+ tmp = child->thread.fp[regno - 21];
+ } else if (regno == 49) {
tmp = child->mm->start_code;
- } else if (addr == 50) {
+ } else if (regno == 50) {
tmp = child->mm->start_data;
- } else if (addr == 51) {
+ } else if (regno == 51) {
tmp = child->mm->end_code;
} else
break;
- ret = put_user(tmp,(unsigned long *) data);
+ ret = put_user(tmp, datap);
break;
}
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
ret = -EIO;
- if ((addr & 3) || addr < 0 ||
- addr > sizeof(struct user) - 3)
+ if ((addr & 3) || addr > sizeof(struct user) - 3)
break;
- addr = addr >> 2; /* temporary hack. */
-
- if (addr == PT_SR) {
+ if (regno == PT_SR) {
data &= SR_MASK;
data <<= 16;
data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
}
- if (addr < 19) {
- if (put_reg(child, addr, data))
+ if (regno < 19) {
+ if (put_reg(child, regno, data))
break;
ret = 0;
break;
}
- if (addr >= 21 && addr < 48)
+ if (regno >= 21 && regno < 48)
{
-#ifdef CONFIG_M68KFPU_EMU
- /* Convert long double format
- * into internal fpu reg representation
- */
- if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) {
- data = (unsigned long)data << 15;
- data = (data & 0xffff0000) |
- ((data & 0x0000ffff) >> 1);
- }
-#endif
- child->thread.fp[addr - 21] = data;
+ child->thread.fp[regno - 21] = data;
ret = 0;
}
break;
@@ -197,11 +178,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
tmp = get_reg(child, i);
if (i == PT_SR)
tmp >>= 16;
- if (put_user(tmp, (unsigned long *) data)) {
+ if (put_user(tmp, datap)) {
ret = -EFAULT;
break;
}
- data += sizeof(long);
+ datap++;
}
ret = 0;
break;
@@ -211,7 +192,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
int i;
unsigned long tmp;
for (i = 0; i < 19; i++) {
- if (get_user(tmp, (unsigned long *) data)) {
+ if (get_user(tmp, datap)) {
ret = -EFAULT;
break;
}
@@ -221,7 +202,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
}
put_reg(child, i, tmp);
- data += sizeof(long);
+ datap++;
}
ret = 0;
break;
@@ -230,7 +211,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
#ifdef PTRACE_GETFPREGS
case PTRACE_GETFPREGS: { /* Get the child FPU state. */
ret = 0;
- if (copy_to_user((void *)data, &child->thread.fp,
+ if (copy_to_user(datap, &child->thread.fp,
sizeof(struct user_m68kfp_struct)))
ret = -EFAULT;
break;
@@ -240,7 +221,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
#ifdef PTRACE_SETFPREGS
case PTRACE_SETFPREGS: { /* Set the child FPU state. */
ret = 0;
- if (copy_from_user(&child->thread.fp, (void *)data,
+ if (copy_from_user(&child->thread.fp, datap,
sizeof(struct user_m68kfp_struct)))
ret = -EFAULT;
break;
@@ -248,8 +229,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
#endif
case PTRACE_GET_THREAD_AREA:
- ret = put_user(task_thread_info(child)->tp_value,
- (unsigned long __user *)data);
+ ret = put_user(task_thread_info(child)->tp_value, datap);
break;
default:
@@ -259,21 +239,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
return ret;
}
-asmlinkage void syscall_trace(void)
+asmlinkage int syscall_trace_enter(void)
{
- if (!test_thread_flag(TIF_SYSCALL_TRACE))
- return;
- if (!(current->ptrace & PT_PTRACED))
- return;
- ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
- ? 0x80 : 0));
- /*
- * this isn't the same as continuing with a signal, but it will do
- * for normal use. strace only continues with a signal if the
- * stopping signal is not SIGTRAP. -brl
- */
- if (current->exit_code) {
- send_sig(current->exit_code, current, 1);
- current->exit_code = 0;
- }
+ int ret = 0;
+
+ if (test_thread_flag(TIF_SYSCALL_TRACE))
+ ret = tracehook_report_syscall_entry(task_pt_regs(current));
+ return ret;
+}
+
+asmlinkage void syscall_trace_leave(void)
+{
+ if (test_thread_flag(TIF_SYSCALL_TRACE))
+ tracehook_report_syscall_exit(task_pt_regs(current), 0);
}
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c
index ba92b90d5fbc..c684adf5dc40 100644
--- a/arch/m68knommu/kernel/setup.c
+++ b/arch/m68knommu/kernel/setup.c
@@ -54,9 +54,6 @@ void (*mach_reset)(void);
void (*mach_halt)(void);
void (*mach_power_off)(void);
-#ifdef CONFIG_M68000
- #define CPU "MC68000"
-#endif
#ifdef CONFIG_M68328
#define CPU "MC68328"
#endif
diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c
index 7089dd9d843b..d6ac2a43453c 100644
--- a/arch/m68knommu/kernel/time.c
+++ b/arch/m68knommu/kernel/time.c
@@ -60,13 +60,16 @@ static unsigned long read_rtc_mmss(void)
{
unsigned int year, mon, day, hour, min, sec;
- if (mach_gettod)
+ if (mach_gettod) {
mach_gettod(&year, &mon, &day, &hour, &min, &sec);
- else
- year = mon = day = hour = min = sec = 0;
+ if ((year += 1900) < 1970)
+ year += 100;
+ } else {
+ year = 1970;
+ mon = day = 1;
+ hour = min = sec = 0;
+ }
- if ((year += 1900) < 1970)
- year += 100;
return mktime(year, mon, day, hour, min, sec);
}
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c
index 3739c8f657d7..a768008dfd06 100644
--- a/arch/m68knommu/kernel/traps.c
+++ b/arch/m68knommu/kernel/traps.c
@@ -179,14 +179,16 @@ static void __show_stack(struct task_struct *task, unsigned long *stack)
void bad_super_trap(struct frame *fp)
{
+ int vector = (fp->ptregs.vector >> 2) & 0xff;
+
console_verbose();
- if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
+ if (vector < ARRAY_SIZE(vec_names))
printk (KERN_WARNING "*** %s *** FORMAT=%X\n",
- vec_names[(fp->ptregs.vector) >> 2],
+ vec_names[vector],
fp->ptregs.format);
else
printk (KERN_WARNING "*** Exception %d *** FORMAT=%X\n",
- (fp->ptregs.vector) >> 2,
+ vector,
fp->ptregs.format);
printk (KERN_WARNING "Current process id is %d\n", current->pid);
die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
@@ -195,10 +197,11 @@ void bad_super_trap(struct frame *fp)
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 ((fp->ptregs.vector >> 2) == VEC_TRACE) {
+ if (vector == VEC_TRACE) {
/* traced a trapping instruction */
} else
bad_super_trap(fp);
@@ -206,7 +209,7 @@ asmlinkage void trap_c(struct frame *fp)
}
/* send the appropriate signal to the user program */
- switch ((fp->ptregs.vector) >> 2) {
+ switch (vector) {
case VEC_ADDRERR:
info.si_code = BUS_ADRALN;
sig = SIGBUS;
@@ -360,16 +363,3 @@ void show_stack(struct task_struct *task, unsigned long *stack)
else
__show_stack(task, stack);
}
-
-#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/m68knommu/platform/5206/Makefile b/arch/m68knommu/platform/5206/Makefile
index 113c33390064..b5db05625cfa 100644
--- a/arch/m68knommu/platform/5206/Makefile
+++ b/arch/m68knommu/platform/5206/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/5206e/Makefile b/arch/m68knommu/platform/5206e/Makefile
index 113c33390064..b5db05625cfa 100644
--- a/arch/m68knommu/platform/5206e/Makefile
+++ b/arch/m68knommu/platform/5206e/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/520x/Makefile b/arch/m68knommu/platform/520x/Makefile
index 435ab3483dc1..ad3f4e5a57ce 100644
--- a/arch/m68knommu/platform/520x/Makefile
+++ b/arch/m68knommu/platform/520x/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/523x/Makefile b/arch/m68knommu/platform/523x/Makefile
index b8f9b45440c2..c04b8f71c88c 100644
--- a/arch/m68knommu/platform/523x/Makefile
+++ b/arch/m68knommu/platform/523x/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/5249/Makefile b/arch/m68knommu/platform/5249/Makefile
index f56225d1582f..4bed30fd0073 100644
--- a/arch/m68knommu/platform/5249/Makefile
+++ b/arch/m68knommu/platform/5249/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/5272/Makefile b/arch/m68knommu/platform/5272/Makefile
index 93673ef8e2c1..34110fc14301 100644
--- a/arch/m68knommu/platform/5272/Makefile
+++ b/arch/m68knommu/platform/5272/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/5272/config.c b/arch/m68knommu/platform/5272/config.c
index 59278c0887d0..65bb582734e1 100644
--- a/arch/m68knommu/platform/5272/config.c
+++ b/arch/m68knommu/platform/5272/config.c
@@ -13,6 +13,8 @@
#include <linux/param.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
#include <asm/machdep.h>
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
@@ -148,9 +150,23 @@ void __init config_BSP(char *commandp, int size)
/***************************************************************************/
+/*
+ * Some 5272 based boards have the FEC ethernet diectly connected to
+ * an ethernet switch. In this case we need to use the fixed phy type,
+ * and we need to declare it early in boot.
+ */
+static struct fixed_phy_status nettel_fixed_phy_status __initdata = {
+ .link = 1,
+ .speed = 100,
+ .duplex = 0,
+};
+
+/***************************************************************************/
+
static int __init init_BSP(void)
{
m5272_uarts_init();
+ fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status);
platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices));
return 0;
}
diff --git a/arch/m68knommu/platform/5272/intc.c b/arch/m68knommu/platform/5272/intc.c
index 7081e0a9720e..3cf681c177aa 100644
--- a/arch/m68knommu/platform/5272/intc.c
+++ b/arch/m68knommu/platform/5272/intc.c
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <asm/coldfire.h>
@@ -29,6 +30,10 @@
* via a set of 4 "Interrupt Controller Registers" (ICR). There is a
* loose mapping of vector number to register and internal bits, but
* a table is the easiest and quickest way to map them.
+ *
+ * Note that the external interrupts are edge triggered (unlike the
+ * internal interrupt sources which are level triggered). Which means
+ * they also need acknowledgeing via acknowledge bits.
*/
struct irqmap {
unsigned char icr;
@@ -68,6 +73,11 @@ static struct irqmap intc_irqmap[MCFINT_VECMAX - MCFINT_VECBASE] = {
/*MCF_IRQ_SWTO*/ { .icr = MCFSIM_ICR4, .index = 16, .ack = 0, },
};
+/*
+ * The act of masking the interrupt also has a side effect of 'ack'ing
+ * an interrupt on this irq (for the external irqs). So this mask function
+ * is also an ack_mask function.
+ */
static void intc_irq_mask(unsigned int irq)
{
if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
@@ -95,7 +105,9 @@ static void intc_irq_ack(unsigned int irq)
irq -= MCFINT_VECBASE;
if (intc_irqmap[irq].ack) {
u32 v;
- v = 0xd << intc_irqmap[irq].index;
+ v = readl(MCF_MBAR + intc_irqmap[irq].icr);
+ v &= (0x7 << intc_irqmap[irq].index);
+ v |= (0x8 << intc_irqmap[irq].index);
writel(v, MCF_MBAR + intc_irqmap[irq].icr);
}
}
@@ -103,21 +115,47 @@ static void intc_irq_ack(unsigned int irq)
static int intc_irq_set_type(unsigned int irq, unsigned int type)
{
- /* We can set the edge type here for external interrupts */
+ if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
+ irq -= MCFINT_VECBASE;
+ if (intc_irqmap[irq].ack) {
+ u32 v;
+ v = readl(MCF_MBAR + MCFSIM_PITR);
+ if (type == IRQ_TYPE_EDGE_FALLING)
+ v &= ~(0x1 << (32 - irq));
+ else
+ v |= (0x1 << (32 - irq));
+ writel(v, MCF_MBAR + MCFSIM_PITR);
+ }
+ }
return 0;
}
+/*
+ * Simple flow handler to deal with the external edge triggered interrupts.
+ * We need to be careful with the masking/acking due to the side effects
+ * of masking an interrupt.
+ */
+static void intc_external_irq(unsigned int irq, struct irq_desc *desc)
+{
+ kstat_incr_irqs_this_cpu(irq, desc);
+ desc->status |= IRQ_INPROGRESS;
+ desc->chip->ack(irq);
+ handle_IRQ_event(irq, desc->action);
+ desc->status &= ~IRQ_INPROGRESS;
+}
+
static struct irq_chip intc_irq_chip = {
.name = "CF-INTC",
.mask = intc_irq_mask,
.unmask = intc_irq_unmask,
+ .mask_ack = intc_irq_mask,
.ack = intc_irq_ack,
.set_type = intc_irq_set_type,
};
void __init init_IRQ(void)
{
- int irq;
+ int irq, edge;
init_vectors();
@@ -128,11 +166,17 @@ void __init init_IRQ(void)
writel(0x88888888, MCF_MBAR + MCFSIM_ICR4);
for (irq = 0; (irq < NR_IRQS); irq++) {
- irq_desc[irq].status = IRQ_DISABLED;
- irq_desc[irq].action = NULL;
- irq_desc[irq].depth = 1;
- irq_desc[irq].chip = &intc_irq_chip;
- intc_irq_set_type(irq, 0);
+ set_irq_chip(irq, &intc_irq_chip);
+ edge = 0;
+ if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX))
+ edge = intc_irqmap[irq - MCFINT_VECBASE].ack;
+ if (edge) {
+ set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
+ set_irq_handler(irq, intc_external_irq);
+ } else {
+ set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+ set_irq_handler(irq, handle_level_irq);
+ }
}
}
diff --git a/arch/m68knommu/platform/527x/Makefile b/arch/m68knommu/platform/527x/Makefile
index 3d90e6d92459..6ac4b57370ea 100644
--- a/arch/m68knommu/platform/527x/Makefile
+++ b/arch/m68knommu/platform/527x/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/528x/Makefile b/arch/m68knommu/platform/528x/Makefile
index 3d90e6d92459..6ac4b57370ea 100644
--- a/arch/m68knommu/platform/528x/Makefile
+++ b/arch/m68knommu/platform/528x/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/5307/Makefile b/arch/m68knommu/platform/5307/Makefile
index 6de526976828..d4293b791f2e 100644
--- a/arch/m68knommu/platform/5307/Makefile
+++ b/arch/m68knommu/platform/5307/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/532x/Makefile b/arch/m68knommu/platform/532x/Makefile
index 4cc23245bcd1..ce01669399c6 100644
--- a/arch/m68knommu/platform/532x/Makefile
+++ b/arch/m68knommu/platform/532x/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/5407/Makefile b/arch/m68knommu/platform/5407/Makefile
index dee62c5dbaa6..e83fe148eddc 100644
--- a/arch/m68knommu/platform/5407/Makefile
+++ b/arch/m68knommu/platform/5407/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff --git a/arch/m68knommu/platform/548x/Makefile b/arch/m68knommu/platform/548x/Makefile
new file mode 100644
index 000000000000..e6035e7a2d3f
--- /dev/null
+++ b/arch/m68knommu/platform/548x/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for the m68knommu linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this, which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs. You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
+# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-y := config.o
+
diff --git a/arch/m68knommu/platform/548x/config.c b/arch/m68knommu/platform/548x/config.c
new file mode 100644
index 000000000000..9888846bd1cf
--- /dev/null
+++ b/arch/m68knommu/platform/548x/config.c
@@ -0,0 +1,115 @@
+/***************************************************************************/
+
+/*
+ * linux/arch/m68knommu/platform/548x/config.c
+ *
+ * Copyright (C) 2010, Philippe De Muyter <phdm@macqel.be>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/m548xsim.h>
+#include <asm/mcfuart.h>
+#include <asm/m548xgpt.h>
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m548x_uart_platform[] = {
+ {
+ .mapbase = MCF_MBAR + MCFUART_BASE1,
+ .irq = 64 + 35,
+ },
+ {
+ .mapbase = MCF_MBAR + MCFUART_BASE2,
+ .irq = 64 + 34,
+ },
+ {
+ .mapbase = MCF_MBAR + MCFUART_BASE3,
+ .irq = 64 + 33,
+ },
+ {
+ .mapbase = MCF_MBAR + MCFUART_BASE4,
+ .irq = 64 + 32,
+ },
+};
+
+static struct platform_device m548x_uart = {
+ .name = "mcfuart",
+ .id = 0,
+ .dev.platform_data = m548x_uart_platform,
+};
+
+static struct platform_device *m548x_devices[] __initdata = {
+ &m548x_uart,
+};
+
+
+/***************************************************************************/
+
+static void __init m548x_uart_init_line(int line, int irq)
+{
+ int rts_cts;
+
+ /* enable io pins */
+ switch (line) {
+ case 0:
+ rts_cts = 0; break;
+ case 1:
+ rts_cts = MCF_PAR_PSC_RTS_RTS; break;
+ case 2:
+ rts_cts = MCF_PAR_PSC_RTS_RTS | MCF_PAR_PSC_CTS_CTS; break;
+ case 3:
+ rts_cts = 0; break;
+ }
+ __raw_writeb(MCF_PAR_PSC_TXD | rts_cts | MCF_PAR_PSC_RXD,
+ MCF_MBAR + MCF_PAR_PSC(line));
+}
+
+static void __init m548x_uarts_init(void)
+{
+ const int nrlines = ARRAY_SIZE(m548x_uart_platform);
+ int line;
+
+ for (line = 0; (line < nrlines); line++)
+ m548x_uart_init_line(line, m548x_uart_platform[line].irq);
+}
+
+/***************************************************************************/
+
+static void mcf548x_reset(void)
+{
+ /* disable interrupts and enable the watchdog */
+ asm("movew #0x2700, %sr\n");
+ __raw_writel(0, MCF_MBAR + MCF_GPT_GMS0);
+ __raw_writel(MCF_GPT_GCIR_CNT(1), MCF_MBAR + MCF_GPT_GCIR0);
+ __raw_writel(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE | MCF_GPT_GMS_TMS(4),
+ MCF_MBAR + MCF_GPT_GMS0);
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+ mach_reset = mcf548x_reset;
+ m548x_uarts_init();
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+
+ platform_add_devices(m548x_devices, ARRAY_SIZE(m548x_devices));
+ return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff --git a/arch/m68knommu/platform/68328/entry.S b/arch/m68knommu/platform/68328/entry.S
index 9d80d2c42866..27241e16a526 100644
--- a/arch/m68knommu/platform/68328/entry.S
+++ b/arch/m68knommu/platform/68328/entry.S
@@ -43,10 +43,10 @@ badsys:
jra ret_from_exception
do_trace:
- movel #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
+ movel #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
subql #4,%sp
SAVE_SWITCH_STACK
- jbsr syscall_trace
+ jbsr syscall_trace_enter
RESTORE_SWITCH_STACK
addql #4,%sp
movel %sp@(PT_OFF_ORIG_D0),%d1
@@ -57,10 +57,10 @@ do_trace:
lea sys_call_table, %a0
jbsr %a0@(%d1)
-1: movel %d0,%sp@(PT_OFF_D0) /* save the return value */
+1: movel %d0,%sp@(PT_OFF_D0) /* save the return value */
subql #4,%sp /* dummy return address */
SAVE_SWITCH_STACK
- jbsr syscall_trace
+ jbsr syscall_trace_leave
ret_from_signal:
RESTORE_SWITCH_STACK
@@ -71,16 +71,16 @@ ENTRY(system_call)
SAVE_ALL
/* save top of frame*/
- pea %sp@
- jbsr set_esp0
- addql #4,%sp
+ pea %sp@
+ jbsr set_esp0
+ addql #4,%sp
movel %sp@(PT_OFF_ORIG_D0),%d0
movel %sp,%d1 /* get thread_info pointer */
andl #-THREAD_SIZE,%d1
movel %d1,%a2
- btst #TIF_SYSCALL_TRACE,%a2@(TI_FLAGS)
+ btst #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
jne do_trace
cmpl #NR_syscalls,%d0
jcc badsys
@@ -88,10 +88,10 @@ ENTRY(system_call)
lea sys_call_table,%a0
movel %a0@(%d0), %a0
jbsr %a0@
- movel %d0,%sp@(PT_OFF_D0) /* save the return value*/
+ movel %d0,%sp@(PT_OFF_D0) /* save the return value*/
ret_from_exception:
- btst #5,%sp@(PT_OFF_SR) /* check if returning to kernel*/
+ btst #5,%sp@(PT_OFF_SR) /* check if returning to kernel*/
jeq Luser_return /* if so, skip resched, signals*/
Lkernel_return:
@@ -133,7 +133,7 @@ Lreturn:
*/
inthandler1:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -144,7 +144,7 @@ inthandler1:
inthandler2:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -155,7 +155,7 @@ inthandler2:
inthandler3:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -166,7 +166,7 @@ inthandler3:
inthandler4:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -177,7 +177,7 @@ inthandler4:
inthandler5:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -188,7 +188,7 @@ inthandler5:
inthandler6:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -199,7 +199,7 @@ inthandler6:
inthandler7:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -210,7 +210,7 @@ inthandler7:
inthandler:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
movel %sp,%sp@-
diff --git a/arch/m68knommu/platform/68328/head-de2.S b/arch/m68knommu/platform/68328/head-de2.S
index 92d96456d363..f632fdcb93e9 100644
--- a/arch/m68knommu/platform/68328/head-de2.S
+++ b/arch/m68knommu/platform/68328/head-de2.S
@@ -1,11 +1,5 @@
-#if defined(CONFIG_RAM32MB)
-#define MEM_END 0x02000000 /* Memory size 32Mb */
-#elif defined(CONFIG_RAM16MB)
-#define MEM_END 0x01000000 /* Memory size 16Mb */
-#else
#define MEM_END 0x00800000 /* Memory size 8Mb */
-#endif
#undef CRT_DEBUG
diff --git a/arch/m68knommu/platform/68328/head-ram.S b/arch/m68knommu/platform/68328/head-ram.S
index 252b80b02038..7f1aeeacb219 100644
--- a/arch/m68knommu/platform/68328/head-ram.S
+++ b/arch/m68knommu/platform/68328/head-ram.S
@@ -67,33 +67,6 @@ pclp1:
beq pclp1
#endif /* DEBUG */
-#ifdef CONFIG_RELOCATE
- /* Copy me to RAM */
- moveal #__rom_start, %a0
- moveal #_stext, %a1
- moveal #_edata, %a2
-
- /* Copy %a0 to %a1 until %a1 == %a2 */
-LD1:
- movel %a0@+, %d0
- movel %d0, %a1@+
- cmpal %a1, %a2
- bhi LD1
-
-#ifdef DEBUG
- moveq #74, %d7 /* 'J' */
- moveb %d7,0xfffff907 /* No absolute addresses */
-pclp2:
- movew 0xfffff906, %d7
- andw #0x2000, %d7
- beq pclp2
-#endif /* DEBUG */
- /* jump into the RAM copy */
- jmp ram_jump
-ram_jump:
-
-#endif /* CONFIG_RELOCATE */
-
#ifdef DEBUG
moveq #82, %d7 /* 'R' */
moveb %d7,0xfffff907 /* No absolute addresses */
diff --git a/arch/m68knommu/platform/68328/ints.c b/arch/m68knommu/platform/68328/ints.c
index b91ee85d4b5d..865852806a17 100644
--- a/arch/m68knommu/platform/68328/ints.c
+++ b/arch/m68knommu/platform/68328/ints.c
@@ -179,10 +179,8 @@ void __init init_IRQ(void)
IMR = ~0;
for (i = 0; (i < NR_IRQS); i++) {
- irq_desc[i].status = IRQ_DISABLED;
- irq_desc[i].action = NULL;
- irq_desc[i].depth = 1;
- irq_desc[i].chip = &intc_irq_chip;
+ set_irq_chip(irq, &intc_irq_chip);
+ set_irq_handler(irq, handle_level_irq);
}
}
diff --git a/arch/m68knommu/platform/68360/entry.S b/arch/m68knommu/platform/68360/entry.S
index 6d3460a39cac..c131c6e1d92d 100644
--- a/arch/m68knommu/platform/68360/entry.S
+++ b/arch/m68knommu/platform/68360/entry.S
@@ -42,7 +42,7 @@ do_trace:
movel #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
subql #4,%sp
SAVE_SWITCH_STACK
- jbsr syscall_trace
+ jbsr syscall_trace_enter
RESTORE_SWITCH_STACK
addql #4,%sp
movel %sp@(PT_OFF_ORIG_D0),%d1
@@ -56,7 +56,7 @@ do_trace:
1: movel %d0,%sp@(PT_OFF_D0) /* save the return value */
subql #4,%sp /* dummy return address */
SAVE_SWITCH_STACK
- jbsr syscall_trace
+ jbsr syscall_trace_leave
ret_from_signal:
RESTORE_SWITCH_STACK
@@ -71,7 +71,12 @@ ENTRY(system_call)
jbsr set_esp0
addql #4,%sp
- btst #PF_TRACESYS_BIT,%a2@(TASK_FLAGS+PF_TRACESYS_OFF)
+ movel %sp@(PT_OFF_ORIG_D0),%d0
+
+ movel %sp,%d1 /* get thread_info pointer */
+ andl #-THREAD_SIZE,%d1
+ movel %d1,%a2
+ btst #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
jne do_trace
cmpl #NR_syscalls,%d0
jcc badsys
@@ -124,7 +129,7 @@ Lreturn:
*/
inthandler:
SAVE_ALL
- movew %sp@(PT_OFF_VECTOR), %d0
+ movew %sp@(PT_OFF_FORMATVEC), %d0
and.l #0x3ff, %d0
lsr.l #0x02, %d0
diff --git a/arch/m68knommu/platform/68360/ints.c b/arch/m68knommu/platform/68360/ints.c
index 6f22970d8c20..ad96ab1051f0 100644
--- a/arch/m68knommu/platform/68360/ints.c
+++ b/arch/m68knommu/platform/68360/ints.c
@@ -132,10 +132,8 @@ void init_IRQ(void)
pquicc->intr_cimr = 0x00000000;
for (i = 0; (i < NR_IRQS); i++) {
- irq_desc[i].status = IRQ_DISABLED;
- irq_desc[i].action = NULL;
- irq_desc[i].depth = 1;
- irq_desc[i].chip = &intc_irq_chip;
+ set_irq_chip(irq, &intc_irq_chip);
+ set_irq_handler(irq, handle_level_irq);
}
}
diff --git a/arch/m68knommu/platform/68VZ328/config.c b/arch/m68knommu/platform/68VZ328/config.c
index fc5c63054e98..eabaabe8af36 100644
--- a/arch/m68knommu/platform/68VZ328/config.c
+++ b/arch/m68knommu/platform/68VZ328/config.c
@@ -90,11 +90,6 @@ static void init_hardware(char *command, int size)
PDIQEG &= ~PD(1);
PDIRQEN |= PD(1); /* IRQ enabled */
-#ifdef CONFIG_68328_SERIAL_UART2
- /* Enable RXD TXD port bits to enable UART2 */
- PJSEL &= ~(PJ(5) | PJ(4));
-#endif
-
#ifdef CONFIG_INIT_LCD
/* initialize LCD controller */
LSSA = (long) screen_bits;
diff --git a/arch/m68knommu/platform/coldfire/Makefile b/arch/m68knommu/platform/coldfire/Makefile
index f72a0e5d9996..45f501fa4525 100644
--- a/arch/m68knommu/platform/coldfire/Makefile
+++ b/arch/m68knommu/platform/coldfire/Makefile
@@ -8,8 +8,8 @@
# on the console port whenever a DBG interrupt occurs. You have to
# set up you HW breakpoints to trigger a DBG interrupt:
#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
#
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
@@ -26,6 +26,7 @@ obj-$(CONFIG_M528x) += pit.o intc-2.o
obj-$(CONFIG_M5307) += timers.o intc.o
obj-$(CONFIG_M532x) += timers.o intc-simr.o
obj-$(CONFIG_M5407) += timers.o intc.o
+obj-$(CONFIG_M548x) += sltimers.o intc-2.o
obj-y += pinmux.o gpio.o
extra-y := head.o
diff --git a/arch/m68knommu/platform/coldfire/entry.S b/arch/m68knommu/platform/coldfire/entry.S
index cd79d7e92ce6..5e92bed94b7e 100644
--- a/arch/m68knommu/platform/coldfire/entry.S
+++ b/arch/m68knommu/platform/coldfire/entry.S
@@ -88,7 +88,7 @@ ENTRY(system_call)
movel %d2,PT_OFF_D0(%sp) /* on syscall entry */
subql #4,%sp
SAVE_SWITCH_STACK
- jbsr syscall_trace
+ jbsr syscall_trace_enter
RESTORE_SWITCH_STACK
addql #4,%sp
movel %d3,%a0
@@ -96,7 +96,7 @@ ENTRY(system_call)
movel %d0,%sp@(PT_OFF_D0) /* save the return value */
subql #4,%sp /* dummy return address */
SAVE_SWITCH_STACK
- jbsr syscall_trace
+ jbsr syscall_trace_leave
ret_from_signal:
RESTORE_SWITCH_STACK
diff --git a/arch/m68knommu/platform/coldfire/intc-2.c b/arch/m68knommu/platform/coldfire/intc-2.c
index 5598c8b8661f..85daa2b3001a 100644
--- a/arch/m68knommu/platform/coldfire/intc-2.c
+++ b/arch/m68knommu/platform/coldfire/intc-2.c
@@ -1,5 +1,11 @@
/*
- * intc-1.c
+ * intc-2.c
+ *
+ * General interrupt controller code for the many ColdFire cores that use
+ * interrupt controllers with 63 interrupt sources, organized as 56 fully-
+ * programmable + 7 fixed-level interrupt sources. This includes the 523x
+ * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such
+ * controllers, and the 547x and 548x families which have only one of them.
*
* (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
*
@@ -19,21 +25,37 @@
#include <asm/traps.h>
/*
- * Each vector needs a unique priority and level asscoiated with it.
+ * Bit definitions for the ICR family of registers.
+ */
+#define MCFSIM_ICR_LEVEL(l) ((l)<<3) /* Level l intr */
+#define MCFSIM_ICR_PRI(p) (p) /* Priority p intr */
+
+/*
+ * Each vector needs a unique priority and level associated with it.
* We don't really care so much what they are, we don't rely on the
- * tranditional priority interrupt scheme of the m68k/ColdFire.
+ * traditional priority interrupt scheme of the m68k/ColdFire.
*/
-static u8 intc_intpri = 0x36;
+static u8 intc_intpri = MCFSIM_ICR_LEVEL(6) | MCFSIM_ICR_PRI(6);
+
+#ifdef MCFICM_INTC1
+#define NR_VECS 128
+#else
+#define NR_VECS 64
+#endif
static void intc_irq_mask(unsigned int irq)
{
- if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + 128)) {
+ if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + NR_VECS)) {
unsigned long imraddr;
u32 val, imrbit;
irq -= MCFINT_VECBASE;
imraddr = MCF_IPSBAR;
+#ifdef MCFICM_INTC1
imraddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+#else
+ imraddr += MCFICM_INTC0;
+#endif
imraddr += (irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL;
imrbit = 0x1 << (irq & 0x1f);
@@ -44,13 +66,17 @@ static void intc_irq_mask(unsigned int irq)
static void intc_irq_unmask(unsigned int irq)
{
- if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + 128)) {
+ if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + NR_VECS)) {
unsigned long intaddr, imraddr, icraddr;
u32 val, imrbit;
irq -= MCFINT_VECBASE;
intaddr = MCF_IPSBAR;
+#ifdef MCFICM_INTC1
intaddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+#else
+ intaddr += MCFICM_INTC0;
+#endif
imraddr = intaddr + ((irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL);
icraddr = intaddr + MCFINTC_ICR0 + (irq & 0x3f);
imrbit = 0x1 << (irq & 0x1f);
@@ -67,10 +93,16 @@ static void intc_irq_unmask(unsigned int irq)
}
}
+static int intc_irq_set_type(unsigned int irq, unsigned int type)
+{
+ return 0;
+}
+
static struct irq_chip intc_irq_chip = {
.name = "CF-INTC",
.mask = intc_irq_mask,
.unmask = intc_irq_unmask,
+ .set_type = intc_irq_set_type,
};
void __init init_IRQ(void)
@@ -81,13 +113,14 @@ void __init init_IRQ(void)
/* Mask all interrupt sources */
__raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL);
+#ifdef MCFICM_INTC1
__raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC1 + MCFINTC_IMRL);
+#endif
for (irq = 0; (irq < NR_IRQS); irq++) {
- irq_desc[irq].status = IRQ_DISABLED;
- irq_desc[irq].action = NULL;
- irq_desc[irq].depth = 1;
- irq_desc[irq].chip = &intc_irq_chip;
+ set_irq_chip(irq, &intc_irq_chip);
+ set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+ set_irq_handler(irq, handle_level_irq);
}
}
diff --git a/arch/m68knommu/platform/coldfire/intc-simr.c b/arch/m68knommu/platform/coldfire/intc-simr.c
index 1b01e79c2f63..bb7048636140 100644
--- a/arch/m68knommu/platform/coldfire/intc-simr.c
+++ b/arch/m68knommu/platform/coldfire/intc-simr.c
@@ -1,6 +1,8 @@
/*
* intc-simr.c
*
+ * Interrupt controller code for the ColdFire 5208, 5207 & 532x parts.
+ *
* (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -68,11 +70,9 @@ void __init init_IRQ(void)
__raw_writeb(0xff, MCFINTC1_SIMR);
for (irq = 0; (irq < NR_IRQS); irq++) {
- irq_desc[irq].status = IRQ_DISABLED;
- irq_desc[irq].action = NULL;
- irq_desc[irq].depth = 1;
- irq_desc[irq].chip = &intc_irq_chip;
- intc_irq_set_type(irq, 0);
+ set_irq_chip(irq, &intc_irq_chip);
+ set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+ set_irq_handler(irq, handle_level_irq);
}
}
diff --git a/arch/m68knommu/platform/coldfire/intc.c b/arch/m68knommu/platform/coldfire/intc.c
index a4560c86db71..60d2fcbe182b 100644
--- a/arch/m68knommu/platform/coldfire/intc.c
+++ b/arch/m68knommu/platform/coldfire/intc.c
@@ -143,11 +143,9 @@ void __init init_IRQ(void)
mcf_maskimr(0xffffffff);
for (irq = 0; (irq < NR_IRQS); irq++) {
- irq_desc[irq].status = IRQ_DISABLED;
- irq_desc[irq].action = NULL;
- irq_desc[irq].depth = 1;
- irq_desc[irq].chip = &intc_irq_chip;
- intc_irq_set_type(irq, 0);
+ set_irq_chip(irq, &intc_irq_chip);
+ set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+ set_irq_handler(irq, handle_level_irq);
}
}
diff --git a/arch/m68knommu/platform/coldfire/sltimers.c b/arch/m68knommu/platform/coldfire/sltimers.c
new file mode 100644
index 000000000000..0a1b937c3e18
--- /dev/null
+++ b/arch/m68knommu/platform/coldfire/sltimers.c
@@ -0,0 +1,145 @@
+/***************************************************************************/
+
+/*
+ * sltimers.c -- generic ColdFire slice timer support.
+ *
+ * Copyright (C) 2009-2010, Philippe De Muyter <phdm@macqel.be>
+ * based on
+ * timers.c -- generic ColdFire hardware timer support.
+ * Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/profile.h>
+#include <linux/clocksource.h>
+#include <asm/io.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfslt.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+
+#ifdef CONFIG_HIGHPROFILE
+
+/*
+ * By default use Slice Timer 1 as the profiler clock timer.
+ */
+#define PA(a) (MCF_MBAR + MCFSLT_TIMER1 + (a))
+
+/*
+ * Choose a reasonably fast profile timer. Make it an odd value to
+ * try and get good coverage of kernel operations.
+ */
+#define PROFILEHZ 1013
+
+irqreturn_t mcfslt_profile_tick(int irq, void *dummy)
+{
+ /* Reset Slice Timer 1 */
+ __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, PA(MCFSLT_SSR));
+ if (current->pid)
+ profile_tick(CPU_PROFILING);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction mcfslt_profile_irq = {
+ .name = "profile timer",
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = mcfslt_profile_tick,
+};
+
+void mcfslt_profile_init(void)
+{
+ printk(KERN_INFO "PROFILE: lodging TIMER 1 @ %dHz as profile timer\n",
+ PROFILEHZ);
+
+ setup_irq(MCF_IRQ_PROFILER, &mcfslt_profile_irq);
+
+ /* Set up TIMER 2 as high speed profile clock */
+ __raw_writel(MCF_BUSCLK / PROFILEHZ - 1, PA(MCFSLT_STCNT));
+ __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
+ PA(MCFSLT_SCR));
+
+}
+
+#endif /* CONFIG_HIGHPROFILE */
+
+/***************************************************************************/
+
+/*
+ * By default use Slice Timer 0 as the system clock timer.
+ */
+#define TA(a) (MCF_MBAR + MCFSLT_TIMER0 + (a))
+
+static u32 mcfslt_cycles_per_jiffy;
+static u32 mcfslt_cnt;
+
+static irqreturn_t mcfslt_tick(int irq, void *dummy)
+{
+ /* Reset Slice Timer 0 */
+ __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR));
+ mcfslt_cnt += mcfslt_cycles_per_jiffy;
+ return arch_timer_interrupt(irq, dummy);
+}
+
+static struct irqaction mcfslt_timer_irq = {
+ .name = "timer",
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = mcfslt_tick,
+};
+
+static cycle_t mcfslt_read_clk(struct clocksource *cs)
+{
+ unsigned long flags;
+ u32 cycles;
+ u16 scnt;
+
+ local_irq_save(flags);
+ scnt = __raw_readl(TA(MCFSLT_SCNT));
+ cycles = mcfslt_cnt;
+ local_irq_restore(flags);
+
+ /* substract because slice timers count down */
+ return cycles - scnt;
+}
+
+static struct clocksource mcfslt_clk = {
+ .name = "slt",
+ .rating = 250,
+ .read = mcfslt_read_clk,
+ .shift = 20,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+void hw_timer_init(void)
+{
+ mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ;
+ /*
+ * The coldfire slice timer (SLT) runs from STCNT to 0 included,
+ * then STCNT again and so on. It counts thus actually
+ * STCNT + 1 steps for 1 tick, not STCNT. So if you want
+ * n cycles, initialize STCNT with n - 1.
+ */
+ __raw_writel(mcfslt_cycles_per_jiffy - 1, TA(MCFSLT_STCNT));
+ __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
+ TA(MCFSLT_SCR));
+ /* initialize mcfslt_cnt knowing that slice timers count down */
+ mcfslt_cnt = mcfslt_cycles_per_jiffy;
+
+ setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq);
+
+ mcfslt_clk.mult = clocksource_hz2mult(MCF_BUSCLK, mcfslt_clk.shift);
+ clocksource_register(&mcfslt_clk);
+
+#ifdef CONFIG_HIGHPROFILE
+ mcfslt_profile_init();
+#endif
+}
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index 692fdfce2a23..dad40fc2bef8 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -121,6 +121,23 @@ config CMDLINE_FORCE
Set this to have arguments from the default kernel command string
override those passed by the boot loader.
+config SECCOMP
+ bool "Enable seccomp to safely compute untrusted bytecode"
+ depends on PROC_FS
+ default y
+ help
+ This kernel feature is useful for number crunching applications
+ that may need to compute untrusted bytecode during their
+ execution. By using pipes or other transports made available to
+ the process as file descriptors supporting the read/write
+ syscalls, it's possible to isolate those applications in
+ their own address space using seccomp. Once seccomp is
+ enabled via /proc/<pid>/seccomp, it cannot be disabled
+ and the task is only allowed to execute a few safe syscalls
+ defined by each seccomp mode.
+
+ If unsure, say Y. Only embedded should say N here.
+
endmenu
menu "Advanced setup"
diff --git a/arch/microblaze/Kconfig.debug b/arch/microblaze/Kconfig.debug
index e6e5e0da28c3..e66e25c4b0b2 100644
--- a/arch/microblaze/Kconfig.debug
+++ b/arch/microblaze/Kconfig.debug
@@ -10,7 +10,7 @@ source "lib/Kconfig.debug"
config EARLY_PRINTK
bool "Early printk function for kernel"
- depends on SERIAL_UARTLITE_CONSOLE
+ depends on SERIAL_UARTLITE_CONSOLE || SERIAL_8250_CONSOLE
default n
help
This option turns on/off early printk messages to console.
diff --git a/arch/microblaze/Makefile b/arch/microblaze/Makefile
index 592c7079de88..15f1f1d1840d 100644
--- a/arch/microblaze/Makefile
+++ b/arch/microblaze/Makefile
@@ -42,11 +42,8 @@ KBUILD_CFLAGS += -ffixed-r31 $(CPUFLAGS-1) $(CPUFLAGS-2)
LDFLAGS :=
LDFLAGS_vmlinux :=
-LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
-
head-y := arch/microblaze/kernel/head.o
libs-y += arch/microblaze/lib/
-libs-y += $(LIBGCC)
core-y += arch/microblaze/kernel/
core-y += arch/microblaze/mm/
core-y += arch/microblaze/platform/
@@ -72,12 +69,16 @@ export MMU DTB
all: linux.bin
-BOOT_TARGETS = linux.bin linux.bin.gz simpleImage.%
+# With make 3.82 we cannot mix normal and wildcard targets
+BOOT_TARGETS1 = linux.bin linux.bin.gz
+BOOT_TARGETS2 = simpleImage.%
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
-$(BOOT_TARGETS): vmlinux
+$(BOOT_TARGETS1): vmlinux
+ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+$(BOOT_TARGETS2): vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
define archhelp
diff --git a/arch/microblaze/include/asm/byteorder.h b/arch/microblaze/include/asm/byteorder.h
index ce9c58732ffc..31902762a426 100644
--- a/arch/microblaze/include/asm/byteorder.h
+++ b/arch/microblaze/include/asm/byteorder.h
@@ -1,6 +1,10 @@
#ifndef _ASM_MICROBLAZE_BYTEORDER_H
#define _ASM_MICROBLAZE_BYTEORDER_H
+#ifdef __MICROBLAZEEL__
+#include <linux/byteorder/little_endian.h>
+#else
#include <linux/byteorder/big_endian.h>
+#endif
#endif /* _ASM_MICROBLAZE_BYTEORDER_H */
diff --git a/arch/microblaze/include/asm/checksum.h b/arch/microblaze/include/asm/checksum.h
index 128bf03b54b7..0185cbefdda4 100644
--- a/arch/microblaze/include/asm/checksum.h
+++ b/arch/microblaze/include/asm/checksum.h
@@ -24,8 +24,13 @@ csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
"addc %0, %0, %3\n\t"
"addc %0, %0, r0\n\t"
: "+&d" (sum)
- : "d" (saddr), "d" (daddr), "d" (len + proto));
-
+ : "d" (saddr), "d" (daddr),
+#ifdef __MICROBLAZEEL__
+ "d" ((len + proto) << 8)
+#else
+ "d" (len + proto)
+#endif
+);
return sum;
}
diff --git a/arch/microblaze/include/asm/cpuinfo.h b/arch/microblaze/include/asm/cpuinfo.h
index b4f5ca33aebf..cd257537ae54 100644
--- a/arch/microblaze/include/asm/cpuinfo.h
+++ b/arch/microblaze/include/asm/cpuinfo.h
@@ -38,6 +38,7 @@ struct cpuinfo {
u32 use_exc;
u32 ver_code;
u32 mmu;
+ u32 endian;
/* CPU caches */
u32 use_icache;
@@ -76,7 +77,6 @@ struct cpuinfo {
u32 num_rd_brk;
u32 num_wr_brk;
u32 cpu_clock_freq; /* store real freq of cpu */
- u32 freq_div_hz; /* store freq/HZ */
/* FPGA family */
u32 fpga_family_code;
@@ -97,7 +97,8 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu);
static inline unsigned int fcpu(struct device_node *cpu, char *n)
{
int *val;
- return (val = (int *) of_get_property(cpu, n, NULL)) ? *val : 0;
+ return (val = (int *) of_get_property(cpu, n, NULL)) ?
+ be32_to_cpup(val) : 0;
}
#endif /* _ASM_MICROBLAZE_CPUINFO_H */
diff --git a/arch/microblaze/include/asm/elf.h b/arch/microblaze/include/asm/elf.h
index 732caf1be741..098dfdde4b06 100644
--- a/arch/microblaze/include/asm/elf.h
+++ b/arch/microblaze/include/asm/elf.h
@@ -71,7 +71,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
#define ELF_ET_DYN_BASE (0x08000000)
-#ifdef __LITTLE_ENDIAN__
+#ifdef __MICROBLAZEEL__
#define ELF_DATA ELFDATA2LSB
#else
#define ELF_DATA ELFDATA2MSB
diff --git a/arch/microblaze/include/asm/gpio.h b/arch/microblaze/include/asm/gpio.h
index 2345ac354d9b..2b2c18be71c6 100644
--- a/arch/microblaze/include/asm/gpio.h
+++ b/arch/microblaze/include/asm/gpio.h
@@ -38,12 +38,9 @@ static inline int gpio_cansleep(unsigned int gpio)
return __gpio_cansleep(gpio);
}
-/*
- * Not implemented, yet.
- */
static inline int gpio_to_irq(unsigned int gpio)
{
- return -ENOSYS;
+ return __gpio_to_irq(gpio);
}
static inline int irq_to_gpio(unsigned int irq)
diff --git a/arch/microblaze/include/asm/io.h b/arch/microblaze/include/asm/io.h
index 00b5398d08c7..eae32220f447 100644
--- a/arch/microblaze/include/asm/io.h
+++ b/arch/microblaze/include/asm/io.h
@@ -243,6 +243,8 @@ static inline void __iomem *__ioremap(phys_addr_t address, unsigned long size,
#define out_8(a, v) __raw_writeb((v), (a))
#define in_8(a) __raw_readb(a)
+#define mmiowb()
+
#define ioport_map(port, nr) ((void __iomem *)(port))
#define ioport_unmap(addr)
diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h
index cf377d91da71..ed9d0f6e2cdb 100644
--- a/arch/microblaze/include/asm/page.h
+++ b/arch/microblaze/include/asm/page.h
@@ -205,9 +205,6 @@ extern int page_is_ram(unsigned long pfn);
#define TOPHYS(addr) __virt_to_phys(addr)
#ifdef CONFIG_MMU
-#ifdef CONFIG_CONTIGUOUS_PAGE_ALLOC
-#define WANT_PAGE_VIRTUAL 1 /* page alloc 2 relies on this */
-#endif
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h
index 5a388eeeb28f..2232ff942ba9 100644
--- a/arch/microblaze/include/asm/pci.h
+++ b/arch/microblaze/include/asm/pci.h
@@ -165,5 +165,7 @@ extern void __init xilinx_pci_init(void);
static inline void __init xilinx_pci_init(void) { return; }
#endif
+#include <asm-generic/pci-dma-compat.h>
+
#endif /* __KERNEL__ */
#endif /* __ASM_MICROBLAZE_PCI_H */
diff --git a/arch/microblaze/include/asm/pgalloc.h b/arch/microblaze/include/asm/pgalloc.h
index c614a893f8a3..ebd35792482c 100644
--- a/arch/microblaze/include/asm/pgalloc.h
+++ b/arch/microblaze/include/asm/pgalloc.h
@@ -165,7 +165,8 @@ extern inline void pte_free(struct mm_struct *mm, struct page *ptepage)
#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, (pte))
-#define pmd_populate(mm, pmd, pte) (pmd_val(*(pmd)) = page_address(pte))
+#define pmd_populate(mm, pmd, pte) \
+ (pmd_val(*(pmd)) = (unsigned long)page_address(pte))
#define pmd_populate_kernel(mm, pmd, pte) \
(pmd_val(*(pmd)) = (unsigned long) (pte))
diff --git a/arch/microblaze/include/asm/pgtable.h b/arch/microblaze/include/asm/pgtable.h
index ca2d92871545..cae268c22ba2 100644
--- a/arch/microblaze/include/asm/pgtable.h
+++ b/arch/microblaze/include/asm/pgtable.h
@@ -57,6 +57,13 @@ static inline int pte_file(pte_t pte) { return 0; }
#define pgprot_noncached_wc(prot) prot
+/*
+ * All 32bit addresses are effectively valid for vmalloc...
+ * Sort of meaningless for non-VM targets.
+ */
+#define VMALLOC_START 0
+#define VMALLOC_END 0xffffffff
+
#else /* CONFIG_MMU */
#include <asm-generic/4level-fixup.h>
@@ -497,12 +504,9 @@ static inline pmd_t *pmd_offset(pgd_t *dir, unsigned long address)
#define pte_offset_kernel(dir, addr) \
((pte_t *) pmd_page_kernel(*(dir)) + pte_index(addr))
#define pte_offset_map(dir, addr) \
- ((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE0) + pte_index(addr))
-#define pte_offset_map_nested(dir, addr) \
- ((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE1) + pte_index(addr))
+ ((pte_t *) kmap_atomic(pmd_page(*(dir))) + pte_index(addr))
-#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
-#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
+#define pte_unmap(pte) kunmap_atomic(pte)
/* Encode and decode a nonlinear file mapping entry */
#define PTE_FILE_MAX_BITS 29
diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h
index 101fa098f62a..bdc38312ae4a 100644
--- a/arch/microblaze/include/asm/prom.h
+++ b/arch/microblaze/include/asm/prom.h
@@ -27,6 +27,7 @@
/* Other Prototypes */
extern int early_uartlite_console(void);
+extern int early_uart16550_console(void);
#ifdef CONFIG_PCI
/*
diff --git a/arch/microblaze/include/asm/pvr.h b/arch/microblaze/include/asm/pvr.h
index 9578666e98ba..37db96a15b45 100644
--- a/arch/microblaze/include/asm/pvr.h
+++ b/arch/microblaze/include/asm/pvr.h
@@ -30,7 +30,9 @@ struct pvr_s {
#define PVR0_USE_EXC_MASK 0x04000000
#define PVR0_USE_ICACHE_MASK 0x02000000
#define PVR0_USE_DCACHE_MASK 0x01000000
-#define PVR0_USE_MMU 0x00800000 /* new */
+#define PVR0_USE_MMU 0x00800000
+#define PVR0_USE_BTC 0x00400000
+#define PVR0_ENDI 0x00200000
#define PVR0_VERSION_MASK 0x0000FF00
#define PVR0_USER1_MASK 0x000000FF
@@ -38,9 +40,9 @@ struct pvr_s {
#define PVR1_USER2_MASK 0xFFFFFFFF
/* Configuration PVR masks */
-#define PVR2_D_OPB_MASK 0x80000000
+#define PVR2_D_OPB_MASK 0x80000000 /* or AXI */
#define PVR2_D_LMB_MASK 0x40000000
-#define PVR2_I_OPB_MASK 0x20000000
+#define PVR2_I_OPB_MASK 0x20000000 /* or AXI */
#define PVR2_I_LMB_MASK 0x10000000
#define PVR2_INTERRUPT_IS_EDGE_MASK 0x08000000
#define PVR2_EDGE_IS_POSITIVE_MASK 0x04000000
@@ -63,8 +65,8 @@ struct pvr_s {
#define PVR2_OPCODE_0x0_ILL_MASK 0x00000040
#define PVR2_UNALIGNED_EXC_MASK 0x00000020
#define PVR2_ILL_OPCODE_EXC_MASK 0x00000010
-#define PVR2_IOPB_BUS_EXC_MASK 0x00000008
-#define PVR2_DOPB_BUS_EXC_MASK 0x00000004
+#define PVR2_IOPB_BUS_EXC_MASK 0x00000008 /* or AXI */
+#define PVR2_DOPB_BUS_EXC_MASK 0x00000004 /* or AXI */
#define PVR2_DIV_ZERO_EXC_MASK 0x00000002
#define PVR2_FPU_EXC_MASK 0x00000001
@@ -208,6 +210,8 @@ struct pvr_s {
#define PVR_MMU_TLB_ACCESS(pvr) (pvr.pvr[11] & PVR11_MMU_TLB_ACCESS)
#define PVR_MMU_ZONES(pvr) (pvr.pvr[11] & PVR11_MMU_ZONES)
+/* endian */
+#define PVR_ENDIAN(pvr) (pvr.pvr[0] & PVR0_ENDI)
int cpu_has_pvr(void);
void get_pvr(struct pvr_s *pvr);
diff --git a/arch/microblaze/include/asm/seccomp.h b/arch/microblaze/include/asm/seccomp.h
new file mode 100644
index 000000000000..0d912758a0d7
--- /dev/null
+++ b/arch/microblaze/include/asm/seccomp.h
@@ -0,0 +1,16 @@
+#ifndef _ASM_MICROBLAZE_SECCOMP_H
+#define _ASM_MICROBLAZE_SECCOMP_H
+
+#include <linux/unistd.h>
+
+#define __NR_seccomp_read __NR_read
+#define __NR_seccomp_write __NR_write
+#define __NR_seccomp_exit __NR_exit
+#define __NR_seccomp_sigreturn __NR_sigreturn
+
+#define __NR_seccomp_read_32 __NR_read
+#define __NR_seccomp_write_32 __NR_write
+#define __NR_seccomp_exit_32 __NR_exit
+#define __NR_seccomp_sigreturn_32 __NR_sigreturn
+
+#endif /* _ASM_MICROBLAZE_SECCOMP_H */
diff --git a/arch/microblaze/include/asm/setup.h b/arch/microblaze/include/asm/setup.h
index 782b5c89248e..8f3968971e4e 100644
--- a/arch/microblaze/include/asm/setup.h
+++ b/arch/microblaze/include/asm/setup.h
@@ -25,6 +25,12 @@ void early_printk(const char *fmt, ...);
int setup_early_printk(char *opt);
void disable_early_printk(void);
+#if defined(CONFIG_EARLY_PRINTK)
+#define eprintk early_printk
+#else
+#define eprintk printk
+#endif
+
void heartbeat(void);
void setup_heartbeat(void);
diff --git a/arch/microblaze/include/asm/thread_info.h b/arch/microblaze/include/asm/thread_info.h
index 8a8e9fc6e0c0..b73da2ac21b3 100644
--- a/arch/microblaze/include/asm/thread_info.h
+++ b/arch/microblaze/include/asm/thread_info.h
@@ -127,23 +127,19 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SECCOMP 10 /* secure computing */
#define TIF_FREEZE 14 /* Freezing for suspend */
-/* FIXME change in entry.S */
-#define TIF_KERNEL_TRACE 8 /* kernel trace active */
-
/* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_POLLING_NRFLAG 16
-#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
-#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
-#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
-#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
-#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
-#define _TIF_IRET (1<<TIF_IRET)
-#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
-#define _TIF_FREEZE (1<<TIF_FREEZE)
+#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
+#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
+#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
+#define _TIF_IRET (1 << TIF_IRET)
+#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
+#define _TIF_FREEZE (1 << TIF_FREEZE)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
-#define _TIF_KERNEL_TRACE (1 << TIF_KERNEL_TRACE)
/* work to do in syscall trace */
#define _TIF_WORK_SYSCALL_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
diff --git a/arch/microblaze/include/asm/unaligned.h b/arch/microblaze/include/asm/unaligned.h
index 3658d91ac0fb..2b97cbe500e9 100644
--- a/arch/microblaze/include/asm/unaligned.h
+++ b/arch/microblaze/include/asm/unaligned.h
@@ -12,12 +12,18 @@
# ifdef __KERNEL__
-# include <linux/unaligned/be_struct.h>
+# include <linux/unaligned/be_byteshift.h>
# include <linux/unaligned/le_byteshift.h>
# include <linux/unaligned/generic.h>
-# define get_unaligned __get_unaligned_be
-# define put_unaligned __put_unaligned_be
+
+# ifdef __MICROBLAZEEL__
+# define get_unaligned __get_unaligned_le
+# define put_unaligned __put_unaligned_le
+# else
+# define get_unaligned __get_unaligned_be
+# define put_unaligned __put_unaligned_be
+# endif
# endif /* __KERNEL__ */
#endif /* _ASM_MICROBLAZE_UNALIGNED_H */
diff --git a/arch/microblaze/include/asm/unistd.h b/arch/microblaze/include/asm/unistd.h
index 2b67e92a773c..d770b00ec6b1 100644
--- a/arch/microblaze/include/asm/unistd.h
+++ b/arch/microblaze/include/asm/unistd.h
@@ -383,8 +383,11 @@
#define __NR_rt_tgsigqueueinfo 365 /* new */
#define __NR_perf_event_open 366 /* new */
#define __NR_recvmmsg 367 /* new */
+#define __NR_fanotify_init 368
+#define __NR_fanotify_mark 369
+#define __NR_prlimit64 370
-#define __NR_syscalls 368
+#define __NR_syscalls 371
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
diff --git a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
index f72dbd66c844..f70a6047f08e 100644
--- a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
+++ b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
@@ -72,6 +72,7 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
CI(pvr_user2, USER2);
CI(mmu, USE_MMU);
+ CI(endian, ENDIAN);
CI(use_icache, USE_ICACHE);
CI(icache_tagbits, ICACHE_ADDR_TAG_BITS);
diff --git a/arch/microblaze/kernel/cpu/cpuinfo-static.c b/arch/microblaze/kernel/cpu/cpuinfo-static.c
index 6095aa6b5c88..b16b994ca3d2 100644
--- a/arch/microblaze/kernel/cpu/cpuinfo-static.c
+++ b/arch/microblaze/kernel/cpu/cpuinfo-static.c
@@ -119,6 +119,7 @@ void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)
ci->pvr_user2 = fcpu(cpu, "xlnx,pvr-user2");
ci->mmu = fcpu(cpu, "xlnx,use-mmu");
+ ci->endian = fcpu(cpu, "xlnx,endianness");
ci->ver_code = 0;
ci->fpga_family_code = 0;
diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c
index 255ef880351e..87c79fa275c3 100644
--- a/arch/microblaze/kernel/cpu/cpuinfo.c
+++ b/arch/microblaze/kernel/cpu/cpuinfo.c
@@ -30,6 +30,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
{"7.20.c", 0x0e},
{"7.20.d", 0x0f},
{"7.30.a", 0x10},
+ {"7.30.b", 0x11},
+ {"8.00.a", 0x12},
{NULL, 0},
};
diff --git a/arch/microblaze/kernel/cpu/mb.c b/arch/microblaze/kernel/cpu/mb.c
index 7086e3564281..b4048af02615 100644
--- a/arch/microblaze/kernel/cpu/mb.c
+++ b/arch/microblaze/kernel/cpu/mb.c
@@ -51,11 +51,12 @@ static int show_cpuinfo(struct seq_file *m, void *v)
count = seq_printf(m,
"CPU-Family: MicroBlaze\n"
"FPGA-Arch: %s\n"
- "CPU-Ver: %s\n"
+ "CPU-Ver: %s, %s endian\n"
"CPU-MHz: %d.%02d\n"
"BogoMips: %lu.%02lu\n",
fpga_family,
cpu_ver,
+ cpuinfo.endian ? "little" : "big",
cpuinfo.cpu_clock_freq /
1000000,
cpuinfo.cpu_clock_freq %
diff --git a/arch/microblaze/kernel/cpu/pvr.c b/arch/microblaze/kernel/cpu/pvr.c
index 9bee9382bf74..e01afa68273e 100644
--- a/arch/microblaze/kernel/cpu/pvr.c
+++ b/arch/microblaze/kernel/cpu/pvr.c
@@ -27,7 +27,7 @@
register unsigned tmp __asm__("r3"); \
tmp = 0x0; /* Prevent warning about unused */ \
__asm__ __volatile__ ( \
- ".byte 0x94,0x60,0xa0, " #pvrid "\n\t" \
+ "mfs %0, rpvr" #pvrid ";" \
: "=r" (tmp) : : "memory"); \
val = tmp; \
}
diff --git a/arch/microblaze/kernel/early_printk.c b/arch/microblaze/kernel/early_printk.c
index 7de84923ba07..c3616a080ebf 100644
--- a/arch/microblaze/kernel/early_printk.c
+++ b/arch/microblaze/kernel/early_printk.c
@@ -24,7 +24,8 @@
static u32 early_console_initialized;
static u32 base_addr;
-static void early_printk_putc(char c)
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+static void early_printk_uartlite_putc(char c)
{
/*
* Limit how many times we'll spin waiting for TX FIFO status.
@@ -45,25 +46,70 @@ static void early_printk_putc(char c)
out_be32(base_addr + 4, c & 0xff);
}
-static void early_printk_write(struct console *unused,
+static void early_printk_uartlite_write(struct console *unused,
const char *s, unsigned n)
{
while (*s && n-- > 0) {
- early_printk_putc(*s);
+ early_printk_uartlite_putc(*s);
if (*s == '\n')
- early_printk_putc('\r');
+ early_printk_uartlite_putc('\r');
s++;
}
}
-static struct console early_serial_console = {
+static struct console early_serial_uartlite_console = {
.name = "earlyser",
- .write = early_printk_write,
+ .write = early_printk_uartlite_write,
.flags = CON_PRINTBUFFER,
.index = -1,
};
+#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
-static struct console *early_console = &early_serial_console;
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static void early_printk_uart16550_putc(char c)
+{
+ /*
+ * Limit how many times we'll spin waiting for TX FIFO status.
+ * This will prevent lockups if the base address is incorrectly
+ * set, or any other issue on the UARTLITE.
+ * This limit is pretty arbitrary, unless we are at about 10 baud
+ * we'll never timeout on a working UART.
+ */
+
+ #define UART_LSR_TEMT 0x40 /* Transmitter empty */
+ #define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
+ #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+ unsigned retries = 10000;
+
+ while (--retries &&
+ !((in_be32(base_addr + 0x14) & BOTH_EMPTY) == BOTH_EMPTY))
+ ;
+
+ if (retries)
+ out_be32(base_addr, c & 0xff);
+}
+
+static void early_printk_uart16550_write(struct console *unused,
+ const char *s, unsigned n)
+{
+ while (*s && n-- > 0) {
+ early_printk_uart16550_putc(*s);
+ if (*s == '\n')
+ early_printk_uart16550_putc('\r');
+ s++;
+ }
+}
+
+static struct console early_serial_uart16550_console = {
+ .name = "earlyser",
+ .write = early_printk_uart16550_write,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+#endif /* CONFIG_SERIAL_8250_CONSOLE */
+
+static struct console *early_console;
void early_printk(const char *fmt, ...)
{
@@ -84,20 +130,43 @@ int __init setup_early_printk(char *opt)
if (early_console_initialized)
return 1;
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
base_addr = early_uartlite_console();
if (base_addr) {
early_console_initialized = 1;
#ifdef CONFIG_MMU
early_console_reg_tlb_alloc(base_addr);
#endif
+ early_console = &early_serial_uartlite_console;
early_printk("early_printk_console is enabled at 0x%08x\n",
base_addr);
/* register_console(early_console); */
return 0;
- } else
- return 1;
+ }
+#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+ base_addr = early_uart16550_console();
+ base_addr &= ~3; /* clear register offset */
+ if (base_addr) {
+ early_console_initialized = 1;
+#ifdef CONFIG_MMU
+ early_console_reg_tlb_alloc(base_addr);
+#endif
+ early_console = &early_serial_uart16550_console;
+
+ early_printk("early_printk_console is enabled at 0x%08x\n",
+ base_addr);
+
+ /* register_console(early_console); */
+
+ return 0;
+ }
+#endif /* CONFIG_SERIAL_8250_CONSOLE */
+
+ return 1;
}
void __init disable_early_printk(void)
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S
index 304882e56459..819238b8a429 100644
--- a/arch/microblaze/kernel/entry.S
+++ b/arch/microblaze/kernel/entry.S
@@ -186,6 +186,8 @@
swi r13, r1, PTO+PT_R13; /* Save SDA2 */ \
swi r14, r1, PTO+PT_PC; /* PC, before IRQ/trap */ \
swi r15, r1, PTO+PT_R15; /* Save LP */ \
+ swi r16, r1, PTO+PT_R16; \
+ swi r17, r1, PTO+PT_R17; \
swi r18, r1, PTO+PT_R18; /* Save asm scratch reg */ \
swi r19, r1, PTO+PT_R19; \
swi r20, r1, PTO+PT_R20; \
@@ -220,6 +222,8 @@
lwi r13, r1, PTO+PT_R13; /* restore SDA2 */ \
lwi r14, r1, PTO+PT_PC; /* RESTORE_LINK PC, before IRQ/trap */\
lwi r15, r1, PTO+PT_R15; /* restore LP */ \
+ lwi r16, r1, PTO+PT_R16; \
+ lwi r17, r1, PTO+PT_R17; \
lwi r18, r1, PTO+PT_R18; /* restore asm scratch reg */ \
lwi r19, r1, PTO+PT_R19; \
lwi r20, r1, PTO+PT_R20; \
@@ -295,6 +299,8 @@ C_ENTRY(_user_exception):
/* addik r1, r1, -STATE_SAVE_SIZE; */
addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE;
SAVE_REGS
+ swi r0, r1, PTO + PT_R3
+ swi r0, r1, PTO + PT_R4
lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
swi r11, r1, PTO+PT_R1; /* Store user SP. */
@@ -458,14 +464,8 @@ C_ENTRY(sys_execve):
addik r8, r1, PTO; /* add user context as 4th arg */
C_ENTRY(sys_rt_sigreturn_wrapper):
- swi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
- swi r4, r1, PTO+PT_R4;
- brlid r15, sys_rt_sigreturn /* Do real work */
+ brid sys_rt_sigreturn /* Do real work */
addik r5, r1, PTO; /* add user context as 1st arg */
- lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
- lwi r4, r1, PTO+PT_R4;
- bri ret_from_trap /* fall through will not work here due to align */
- nop;
/*
* HW EXCEPTION rutine start
@@ -765,9 +765,7 @@ C_ENTRY(_debug_exception):
/* save all regs to pt_reg structure */
swi r0, r1, PTO+PT_R0; /* R0 must be saved too */
swi r14, r1, PTO+PT_R14 /* rewrite saved R14 value */
- swi r16, r1, PTO+PT_R16
swi r16, r1, PTO+PT_PC; /* PC and r16 are the same */
- swi r17, r1, PTO+PT_R17
/* save special purpose registers to pt_regs */
mfs r11, rear;
swi r11, r1, PTO+PT_EAR;
@@ -801,8 +799,6 @@ C_ENTRY(_debug_exception):
addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */
SAVE_REGS;
- swi r17, r1, PTO+PT_R17;
- swi r16, r1, PTO+PT_R16;
swi r16, r1, PTO+PT_PC; /* Save LP */
swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */
lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
@@ -848,8 +844,6 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
tophys(r1,r1);
/* MS: Restore all regs */
RESTORE_REGS
- lwi r17, r1, PTO+PT_R17;
- lwi r16, r1, PTO+PT_R16;
addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space */
lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */
DBTRAP_return_user: /* MS: Make global symbol for debugging */
@@ -863,7 +857,6 @@ DBTRAP_return_user: /* MS: Make global symbol for debugging */
RESTORE_REGS
lwi r14, r1, PTO+PT_R14;
lwi r16, r1, PTO+PT_PC;
- lwi r17, r1, PTO+PT_R17;
addik r1, r1, STATE_SAVE_SIZE; /* MS: Clean up stack space */
tovirt(r1,r1);
DBTRAP_return_kernel: /* MS: Make global symbol for debugging */
diff --git a/arch/microblaze/kernel/exceptions.c b/arch/microblaze/kernel/exceptions.c
index b98ee8d0c1cd..478f2943ede7 100644
--- a/arch/microblaze/kernel/exceptions.c
+++ b/arch/microblaze/kernel/exceptions.c
@@ -72,7 +72,6 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
int fsr, int addr)
{
#ifdef CONFIG_MMU
- int code;
addr = regs->pc;
#endif
@@ -86,8 +85,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
switch (type & 0x1F) {
case MICROBLAZE_ILL_OPCODE_EXCEPTION:
if (user_mode(regs)) {
- pr_debug(KERN_WARNING "Illegal opcode exception " \
- "in user mode.\n");
+ pr_debug("Illegal opcode exception in user mode\n");
_exception(SIGILL, regs, ILL_ILLOPC, addr);
return;
}
@@ -97,8 +95,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
break;
case MICROBLAZE_IBUS_EXCEPTION:
if (user_mode(regs)) {
- pr_debug(KERN_WARNING "Instruction bus error " \
- "exception in user mode.\n");
+ pr_debug("Instruction bus error exception in user mode\n");
_exception(SIGBUS, regs, BUS_ADRERR, addr);
return;
}
@@ -108,8 +105,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
break;
case MICROBLAZE_DBUS_EXCEPTION:
if (user_mode(regs)) {
- pr_debug(KERN_WARNING "Data bus error exception " \
- "in user mode.\n");
+ pr_debug("Data bus error exception in user mode\n");
_exception(SIGBUS, regs, BUS_ADRERR, addr);
return;
}
@@ -119,8 +115,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
break;
case MICROBLAZE_DIV_ZERO_EXCEPTION:
if (user_mode(regs)) {
- pr_debug(KERN_WARNING "Divide by zero exception " \
- "in user mode\n");
+ pr_debug("Divide by zero exception in user mode\n");
_exception(SIGILL, regs, FPE_INTDIV, addr);
return;
}
@@ -129,7 +124,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
die("Divide by zero exception", regs, SIGBUS);
break;
case MICROBLAZE_FPU_EXCEPTION:
- pr_debug(KERN_WARNING "FPU exception\n");
+ pr_debug("FPU exception\n");
/* IEEE FP exception */
/* I removed fsr variable and use code var for storing fsr */
if (fsr & FSR_IO)
@@ -147,14 +142,8 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
#ifdef CONFIG_MMU
case MICROBLAZE_PRIVILEGED_EXCEPTION:
- pr_debug(KERN_WARNING "Privileged exception\n");
- /* "brk r0,r0" - used as debug breakpoint - old toolchain */
- if (get_user(code, (unsigned long *)regs->pc) == 0
- && code == 0x980c0000) {
- _exception(SIGTRAP, regs, TRAP_BRKPT, addr);
- } else {
- _exception(SIGILL, regs, ILL_PRVOPC, addr);
- }
+ pr_debug("Privileged exception\n");
+ _exception(SIGILL, regs, ILL_PRVOPC, addr);
break;
#endif
default:
diff --git a/arch/microblaze/kernel/heartbeat.c b/arch/microblaze/kernel/heartbeat.c
index 522751737cfa..154756f3c694 100644
--- a/arch/microblaze/kernel/heartbeat.c
+++ b/arch/microblaze/kernel/heartbeat.c
@@ -47,11 +47,10 @@ void setup_heartbeat(void)
struct device_node *gpio = NULL;
int *prop;
int j;
- char *gpio_list[] = {
- "xlnx,xps-gpio-1.00.a",
- "xlnx,opb-gpio-1.00.a",
- NULL
- };
+ const char * const gpio_list[] = {
+ "xlnx,xps-gpio-1.00.a",
+ NULL
+ };
for (j = 0; gpio_list[j] != NULL; j++) {
gpio = of_find_compatible_node(NULL, NULL, gpio_list[j]);
@@ -60,7 +59,7 @@ void setup_heartbeat(void)
}
if (gpio) {
- base_addr = *(int *) of_get_property(gpio, "reg", NULL);
+ base_addr = be32_to_cpup(of_get_property(gpio, "reg", NULL));
base_addr = (unsigned long) ioremap(base_addr, PAGE_SIZE);
printk(KERN_NOTICE "Heartbeat GPIO at 0x%x\n", base_addr);
diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c
index 03172c1da770..d61ea33aff7c 100644
--- a/arch/microblaze/kernel/intc.c
+++ b/arch/microblaze/kernel/intc.c
@@ -126,11 +126,8 @@ void __init init_IRQ(void)
0
};
#endif
- static char *intc_list[] = {
+ const char * const intc_list[] = {
"xlnx,xps-intc-1.00.a",
- "xlnx,opb-intc-1.00.c",
- "xlnx,opb-intc-1.00.b",
- "xlnx,opb-intc-1.00.a",
NULL
};
@@ -141,12 +138,15 @@ void __init init_IRQ(void)
}
BUG_ON(!intc);
- intc_baseaddr = *(int *) of_get_property(intc, "reg", NULL);
+ intc_baseaddr = be32_to_cpup(of_get_property(intc,
+ "reg", NULL));
intc_baseaddr = (unsigned long) ioremap(intc_baseaddr, PAGE_SIZE);
- nr_irq = *(int *) of_get_property(intc, "xlnx,num-intr-inputs", NULL);
+ nr_irq = be32_to_cpup(of_get_property(intc,
+ "xlnx,num-intr-inputs", NULL));
intr_type =
- *(int *) of_get_property(intc, "xlnx,kind-of-intr", NULL);
+ be32_to_cpup(of_get_property(intc,
+ "xlnx,kind-of-intr", NULL));
if (intr_type >= (1 << (nr_irq + 1)))
printk(KERN_INFO " ERROR: Mismatch in kind-of-intr param\n");
diff --git a/arch/microblaze/kernel/kgdb.c b/arch/microblaze/kernel/kgdb.c
index bfc006b7f2d8..09a5e8286137 100644
--- a/arch/microblaze/kernel/kgdb.c
+++ b/arch/microblaze/kernel/kgdb.c
@@ -80,7 +80,7 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
void microblaze_kgdb_break(struct pt_regs *regs)
{
if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0)
- return 0;
+ return;
/* Jump over the first arch_kgdb_breakpoint which is barrier to
* get kgdb work. The same solution is used for powerpc */
@@ -114,7 +114,6 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code,
{
char *ptr;
unsigned long address;
- int cpu = smp_processor_id();
switch (remcom_in_buffer[0]) {
case 'c':
@@ -143,5 +142,9 @@ void kgdb_arch_exit(void)
* Global data
*/
struct kgdb_arch arch_kgdb_ops = {
+#ifdef __MICROBLAZEEL__
+ .gdb_bpt_instr = {0x18, 0x00, 0x0c, 0xba}, /* brki r16, 0x18 */
+#else
.gdb_bpt_instr = {0xba, 0x0c, 0x00, 0x18}, /* brki r16, 0x18 */
+#endif
};
diff --git a/arch/microblaze/kernel/microblaze_ksyms.c b/arch/microblaze/kernel/microblaze_ksyms.c
index ff85f7718035..5cb034174005 100644
--- a/arch/microblaze/kernel/microblaze_ksyms.c
+++ b/arch/microblaze/kernel/microblaze_ksyms.c
@@ -15,37 +15,13 @@
#include <linux/syscalls.h>
#include <asm/checksum.h>
+#include <asm/cacheflush.h>
#include <linux/io.h>
#include <asm/page.h>
#include <asm/system.h>
#include <linux/ftrace.h>
#include <linux/uaccess.h>
-/*
- * libgcc functions - functions that are used internally by the
- * compiler... (prototypes are not correct though, but that
- * doesn't really matter since they're not versioned).
- */
-extern void __ashldi3(void);
-EXPORT_SYMBOL(__ashldi3);
-extern void __ashrdi3(void);
-EXPORT_SYMBOL(__ashrdi3);
-extern void __divsi3(void);
-EXPORT_SYMBOL(__divsi3);
-extern void __lshrdi3(void);
-EXPORT_SYMBOL(__lshrdi3);
-extern void __modsi3(void);
-EXPORT_SYMBOL(__modsi3);
-extern void __mulsi3(void);
-EXPORT_SYMBOL(__mulsi3);
-extern void __muldi3(void);
-EXPORT_SYMBOL(__muldi3);
-extern void __ucmpdi2(void);
-EXPORT_SYMBOL(__ucmpdi2);
-extern void __udivsi3(void);
-EXPORT_SYMBOL(__udivsi3);
-extern void __umodsi3(void);
-EXPORT_SYMBOL(__umodsi3);
extern char *_ebss;
EXPORT_SYMBOL_GPL(_ebss);
#ifdef CONFIG_FUNCTION_TRACER
@@ -63,3 +39,9 @@ EXPORT_SYMBOL(__strncpy_user);
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memmove);
#endif
+
+#ifdef CONFIG_MMU
+EXPORT_SYMBOL(empty_zero_page);
+#endif
+
+EXPORT_SYMBOL(mbc);
diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c
index 427b13b4740f..a105301e2b7f 100644
--- a/arch/microblaze/kernel/prom.c
+++ b/arch/microblaze/kernel/prom.c
@@ -42,11 +42,6 @@
#include <asm/sections.h>
#include <asm/pci-bridge.h>
-void __init early_init_dt_scan_chosen_arch(unsigned long node)
-{
- /* No Microblaze specific code here */
-}
-
void __init early_init_dt_add_memory_arch(u64 base, u64 size)
{
memblock_add(base, size);
@@ -77,11 +72,12 @@ static int __init early_init_dt_scan_serial(unsigned long node,
/* find compatible node with uartlite */
p = of_get_flat_dt_prop(node, "compatible", &l);
if ((strncmp(p, "xlnx,xps-uartlite", 17) != 0) &&
- (strncmp(p, "xlnx,opb-uartlite", 17) != 0))
+ (strncmp(p, "xlnx,opb-uartlite", 17) != 0) &&
+ (strncmp(p, "xlnx,axi-uartlite", 17) != 0))
return 0;
addr = of_get_flat_dt_prop(node, "reg", &l);
- return *addr; /* return address */
+ return be32_to_cpup(addr); /* return address */
}
/* this function is looking for early uartlite console - Microblaze specific */
@@ -89,6 +85,40 @@ int __init early_uartlite_console(void)
{
return of_scan_flat_dt(early_init_dt_scan_serial, NULL);
}
+
+/* MS this is Microblaze specifig function */
+static int __init early_init_dt_scan_serial_full(unsigned long node,
+ const char *uname, int depth, void *data)
+{
+ unsigned long l;
+ char *p;
+ unsigned int addr;
+
+ pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
+
+/* find all serial nodes */
+ if (strncmp(uname, "serial", 6) != 0)
+ return 0;
+
+ early_init_dt_check_for_initrd(node);
+
+/* find compatible node with uartlite */
+ p = of_get_flat_dt_prop(node, "compatible", &l);
+
+ if ((strncmp(p, "xlnx,xps-uart16550", 18) != 0) &&
+ (strncmp(p, "xlnx,axi-uart16550", 18) != 0))
+ return 0;
+
+ addr = *(u32 *)of_get_flat_dt_prop(node, "reg", &l);
+ addr += *(u32 *)of_get_flat_dt_prop(node, "reg-offset", &l);
+ return be32_to_cpu(addr); /* return address */
+}
+
+/* this function is looking for early uartlite console - Microblaze specific */
+int __init early_uart16550_console(void)
+{
+ return of_scan_flat_dt(early_init_dt_scan_serial_full, NULL);
+}
#endif
void __init early_init_devtree(void *params)
diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c
index dc03ffc8174a..05ac8cc975d5 100644
--- a/arch/microblaze/kernel/ptrace.c
+++ b/arch/microblaze/kernel/ptrace.c
@@ -73,7 +73,8 @@ static microblaze_reg_t *reg_save_addr(unsigned reg_offs,
return (microblaze_reg_t *)((char *)regs + reg_offs);
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int rval;
unsigned long val = 0;
@@ -99,7 +100,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
} else {
rval = -EIO;
}
- } else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) {
+ } else if (addr < PT_SIZE && (addr & 0x3) == 0) {
microblaze_reg_t *reg_addr = reg_save_addr(addr, child);
if (request == PTRACE_PEEKUSR)
val = *reg_addr;
diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c
index f5f768842354..bb1558e4b283 100644
--- a/arch/microblaze/kernel/setup.c
+++ b/arch/microblaze/kernel/setup.c
@@ -92,12 +92,6 @@ inline unsigned get_romfs_len(unsigned *addr)
}
#endif /* CONFIG_MTD_UCLINUX_EBSS */
-#if defined(CONFIG_EARLY_PRINTK) && defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
-#define eprintk early_printk
-#else
-#define eprintk printk
-#endif
-
void __init machine_early_init(const char *cmdline, unsigned int ram,
unsigned int fdt, unsigned int msr)
{
diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S
index 03376dc814c9..e88a930fd1e3 100644
--- a/arch/microblaze/kernel/syscall_table.S
+++ b/arch/microblaze/kernel/syscall_table.S
@@ -372,3 +372,6 @@ ENTRY(sys_call_table)
.long sys_rt_tgsigqueueinfo /* 365 */
.long sys_perf_event_open
.long sys_recvmmsg
+ .long sys_fanotify_init
+ .long sys_fanotify_mark
+ .long sys_prlimit64 /* 370 */
diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c
index b1380ae93ae1..a5aa33db1df3 100644
--- a/arch/microblaze/kernel/timer.c
+++ b/arch/microblaze/kernel/timer.c
@@ -38,6 +38,9 @@ static unsigned int timer_baseaddr;
#define TIMER_BASE timer_baseaddr
#endif
+unsigned int freq_div_hz;
+unsigned int timer_clock_freq;
+
#define TCSR0 (0x00)
#define TLR0 (0x04)
#define TCR0 (0x08)
@@ -115,7 +118,7 @@ static void microblaze_timer_set_mode(enum clock_event_mode mode,
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
printk(KERN_INFO "%s: periodic\n", __func__);
- microblaze_timer0_start_periodic(cpuinfo.freq_div_hz);
+ microblaze_timer0_start_periodic(freq_div_hz);
break;
case CLOCK_EVT_MODE_ONESHOT:
printk(KERN_INFO "%s: oneshot\n", __func__);
@@ -168,7 +171,7 @@ static struct irqaction timer_irqaction = {
static __init void microblaze_clockevent_init(void)
{
clockevent_microblaze_timer.mult =
- div_sc(cpuinfo.cpu_clock_freq, NSEC_PER_SEC,
+ div_sc(timer_clock_freq, NSEC_PER_SEC,
clockevent_microblaze_timer.shift);
clockevent_microblaze_timer.max_delta_ns =
clockevent_delta2ns((u32)~0, &clockevent_microblaze_timer);
@@ -201,7 +204,7 @@ static struct cyclecounter microblaze_cc = {
int __init init_microblaze_timecounter(void)
{
- microblaze_cc.mult = div_sc(cpuinfo.cpu_clock_freq, NSEC_PER_SEC,
+ microblaze_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC,
microblaze_cc.shift);
timecounter_init(&microblaze_tc, &microblaze_cc, sched_clock());
@@ -221,7 +224,7 @@ static struct clocksource clocksource_microblaze = {
static int __init microblaze_clocksource_init(void)
{
clocksource_microblaze.mult =
- clocksource_hz2mult(cpuinfo.cpu_clock_freq,
+ clocksource_hz2mult(timer_clock_freq,
clocksource_microblaze.shift);
if (clocksource_register(&clocksource_microblaze))
panic("failed to register clocksource");
@@ -247,6 +250,7 @@ void __init time_init(void)
u32 irq, i = 0;
u32 timer_num = 1;
struct device_node *timer = NULL;
+ const void *prop;
#ifdef CONFIG_SELFMOD_TIMER
unsigned int timer_baseaddr = 0;
int arr_func[] = {
@@ -258,12 +262,10 @@ void __init time_init(void)
0
};
#endif
- char *timer_list[] = {
- "xlnx,xps-timer-1.00.a",
- "xlnx,opb-timer-1.00.b",
- "xlnx,opb-timer-1.00.a",
- NULL
- };
+ const char * const timer_list[] = {
+ "xlnx,xps-timer-1.00.a",
+ NULL
+ };
for (i = 0; timer_list[i] != NULL; i++) {
timer = of_find_compatible_node(NULL, NULL, timer_list[i]);
@@ -272,13 +274,13 @@ void __init time_init(void)
}
BUG_ON(!timer);
- timer_baseaddr = *(int *) of_get_property(timer, "reg", NULL);
+ timer_baseaddr = be32_to_cpup(of_get_property(timer, "reg", NULL));
timer_baseaddr = (unsigned long) ioremap(timer_baseaddr, PAGE_SIZE);
- irq = *(int *) of_get_property(timer, "interrupts", NULL);
- timer_num =
- *(int *) of_get_property(timer, "xlnx,one-timer-only", NULL);
+ irq = be32_to_cpup(of_get_property(timer, "interrupts", NULL));
+ timer_num = be32_to_cpup(of_get_property(timer,
+ "xlnx,one-timer-only", NULL));
if (timer_num) {
- printk(KERN_EMERG "Please enable two timers in HW\n");
+ eprintk(KERN_EMERG "Please enable two timers in HW\n");
BUG();
}
@@ -288,7 +290,14 @@ void __init time_init(void)
printk(KERN_INFO "%s #0 at 0x%08x, irq=%d\n",
timer_list[i], timer_baseaddr, irq);
- cpuinfo.freq_div_hz = cpuinfo.cpu_clock_freq / HZ;
+ /* If there is clock-frequency property than use it */
+ prop = of_get_property(timer, "clock-frequency", NULL);
+ if (prop)
+ timer_clock_freq = be32_to_cpup(prop);
+ else
+ timer_clock_freq = cpuinfo.cpu_clock_freq;
+
+ freq_div_hz = timer_clock_freq / HZ;
setup_irq(irq, &timer_irqaction);
#ifdef CONFIG_HEART_BEAT
diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S
index a09f2962fbec..96a88c31fe48 100644
--- a/arch/microblaze/kernel/vmlinux.lds.S
+++ b/arch/microblaze/kernel/vmlinux.lds.S
@@ -8,7 +8,6 @@
* for more details.
*/
-OUTPUT_FORMAT("elf32-microblaze", "elf32-microblaze", "elf32-microblaze")
OUTPUT_ARCH(microblaze)
ENTRY(microblaze_start)
@@ -16,7 +15,11 @@ ENTRY(microblaze_start)
#include <asm-generic/vmlinux.lds.h>
#include <asm/thread_info.h>
+#ifdef __MICROBLAZEEL__
+jiffies = jiffies_64;
+#else
jiffies = jiffies_64 + 4;
+#endif
SECTIONS {
. = CONFIG_KERNEL_START;
diff --git a/arch/microblaze/lib/Makefile b/arch/microblaze/lib/Makefile
index 4dfe47d3cd91..f1fcbff3da25 100644
--- a/arch/microblaze/lib/Makefile
+++ b/arch/microblaze/lib/Makefile
@@ -11,3 +11,13 @@ lib-y += memcpy.o memmove.o
endif
lib-y += uaccess_old.o
+
+lib-y += ashldi3.o
+lib-y += ashrdi3.o
+lib-y += divsi3.o
+lib-y += lshrdi3.o
+lib-y += modsi3.o
+lib-y += muldi3.o
+lib-y += mulsi3.o
+lib-y += udivsi3.o
+lib-y += umodsi3.o
diff --git a/arch/microblaze/lib/ashldi3.c b/arch/microblaze/lib/ashldi3.c
new file mode 100644
index 000000000000..beb80f316095
--- /dev/null
+++ b/arch/microblaze/lib/ashldi3.c
@@ -0,0 +1,29 @@
+#include <linux/module.h>
+
+#include "libgcc.h"
+
+long long __ashldi3(long long u, word_type b)
+{
+ DWunion uu, w;
+ word_type bm;
+
+ if (b == 0)
+ return u;
+
+ uu.ll = u;
+ bm = 32 - b;
+
+ if (bm <= 0) {
+ w.s.low = 0;
+ w.s.high = (unsigned int) uu.s.low << -bm;
+ } else {
+ const unsigned int carries = (unsigned int) uu.s.low >> bm;
+
+ w.s.low = (unsigned int) uu.s.low << b;
+ w.s.high = ((unsigned int) uu.s.high << b) | carries;
+ }
+
+ return w.ll;
+}
+
+EXPORT_SYMBOL(__ashldi3);
diff --git a/arch/microblaze/lib/ashrdi3.c b/arch/microblaze/lib/ashrdi3.c
new file mode 100644
index 000000000000..c884a912b660
--- /dev/null
+++ b/arch/microblaze/lib/ashrdi3.c
@@ -0,0 +1,31 @@
+#include <linux/module.h>
+
+#include "libgcc.h"
+
+long long __ashrdi3(long long u, word_type b)
+{
+ DWunion uu, w;
+ word_type bm;
+
+ if (b == 0)
+ return u;
+
+ uu.ll = u;
+ bm = 32 - b;
+
+ if (bm <= 0) {
+ /* w.s.high = 1..1 or 0..0 */
+ w.s.high =
+ uu.s.high >> 31;
+ w.s.low = uu.s.high >> -bm;
+ } else {
+ const unsigned int carries = (unsigned int) uu.s.high << bm;
+
+ w.s.high = uu.s.high >> b;
+ w.s.low = ((unsigned int) uu.s.low >> b) | carries;
+ }
+
+ return w.ll;
+}
+
+EXPORT_SYMBOL(__ashrdi3);
diff --git a/arch/microblaze/lib/divsi3.S b/arch/microblaze/lib/divsi3.S
new file mode 100644
index 000000000000..595b02d6e86b
--- /dev/null
+++ b/arch/microblaze/lib/divsi3.S
@@ -0,0 +1,73 @@
+#include <linux/linkage.h>
+
+/*
+* Divide operation for 32 bit integers.
+* Input : Dividend in Reg r5
+* Divisor in Reg r6
+* Output: Result in Reg r3
+*/
+ .text
+ .globl __divsi3
+ .type __divsi3, @function
+ .ent __divsi3
+__divsi3:
+ .frame r1, 0, r15
+
+ addik r1, r1, -16
+ swi r28, r1, 0
+ swi r29, r1, 4
+ swi r30, r1, 8
+ swi r31, r1, 12
+
+ beqi r6, div_by_zero /* div_by_zero - division error */
+ beqi r5, result_is_zero /* result is zero */
+ bgeid r5, r5_pos
+ xor r28, r5, r6 /* get the sign of the result */
+ rsubi r5, r5, 0 /* make r5 positive */
+r5_pos:
+ bgei r6, r6_pos
+ rsubi r6, r6, 0 /* make r6 positive */
+r6_pos:
+ addik r30, r0, 0 /* clear mod */
+ addik r3, r0, 0 /* clear div */
+ addik r29, r0, 32 /* initialize the loop count */
+
+ /* first part try to find the first '1' in the r5 */
+div0:
+ blti r5, div2 /* this traps r5 == 0x80000000 */
+div1:
+ add r5, r5, r5 /* left shift logical r5 */
+ bgtid r5, div1
+ addik r29, r29, -1
+div2:
+ /* left shift logical r5 get the '1' into the carry */
+ add r5, r5, r5
+ addc r30, r30, r30 /* move that bit into the mod register */
+ rsub r31, r6, r30 /* try to subtract (r30 a r6) */
+ blti r31, mod_too_small
+ /* move the r31 to mod since the result was positive */
+ or r30, r0, r31
+ addik r3, r3, 1
+mod_too_small:
+ addik r29, r29, -1
+ beqi r29, loop_end
+ add r3, r3, r3 /* shift in the '1' into div */
+ bri div2 /* div2 */
+loop_end:
+ bgei r28, return_here
+ brid return_here
+ rsubi r3, r3, 0 /* negate the result */
+div_by_zero:
+result_is_zero:
+ or r3, r0, r0 /* set result to 0 */
+return_here:
+/* restore values of csrs and that of r3 and the divisor and the dividend */
+ lwi r28, r1, 0
+ lwi r29, r1, 4
+ lwi r30, r1, 8
+ lwi r31, r1, 12
+ rtsd r15, 8
+ addik r1, r1, 16
+
+.size __divsi3, . - __divsi3
+.end __divsi3
diff --git a/arch/microblaze/lib/libgcc.h b/arch/microblaze/lib/libgcc.h
new file mode 100644
index 000000000000..05909d58e2fe
--- /dev/null
+++ b/arch/microblaze/lib/libgcc.h
@@ -0,0 +1,25 @@
+#ifndef __ASM_LIBGCC_H
+#define __ASM_LIBGCC_H
+
+#include <asm/byteorder.h>
+
+typedef int word_type __attribute__ ((mode (__word__)));
+
+#ifdef __BIG_ENDIAN
+struct DWstruct {
+ int high, low;
+};
+#elif defined(__LITTLE_ENDIAN)
+struct DWstruct {
+ int low, high;
+};
+#else
+#error I feel sick.
+#endif
+
+typedef union {
+ struct DWstruct s;
+ long long ll;
+} DWunion;
+
+#endif /* __ASM_LIBGCC_H */
diff --git a/arch/microblaze/lib/lshrdi3.c b/arch/microblaze/lib/lshrdi3.c
new file mode 100644
index 000000000000..dcf8d6810b7c
--- /dev/null
+++ b/arch/microblaze/lib/lshrdi3.c
@@ -0,0 +1,29 @@
+#include <linux/module.h>
+
+#include "libgcc.h"
+
+long long __lshrdi3(long long u, word_type b)
+{
+ DWunion uu, w;
+ word_type bm;
+
+ if (b == 0)
+ return u;
+
+ uu.ll = u;
+ bm = 32 - b;
+
+ if (bm <= 0) {
+ w.s.high = 0;
+ w.s.low = (unsigned int) uu.s.high >> -bm;
+ } else {
+ const unsigned int carries = (unsigned int) uu.s.high << bm;
+
+ w.s.high = (unsigned int) uu.s.high >> b;
+ w.s.low = ((unsigned int) uu.s.low >> b) | carries;
+ }
+
+ return w.ll;
+}
+
+EXPORT_SYMBOL(__lshrdi3);
diff --git a/arch/microblaze/lib/memcpy.c b/arch/microblaze/lib/memcpy.c
index 014bac92bdff..cc495d7d99cc 100644
--- a/arch/microblaze/lib/memcpy.c
+++ b/arch/microblaze/lib/memcpy.c
@@ -33,17 +33,24 @@
#include <asm/system.h>
#ifdef __HAVE_ARCH_MEMCPY
+#ifndef CONFIG_OPT_LIB_FUNCTION
void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
{
const char *src = v_src;
char *dst = v_dst;
-#ifndef CONFIG_OPT_LIB_FUNCTION
+
/* Simple, byte oriented memcpy. */
while (c--)
*dst++ = *src++;
return v_dst;
-#else
+}
+#else /* CONFIG_OPT_LIB_FUNCTION */
+void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
+{
+ const char *src = v_src;
+ char *dst = v_dst;
+
/* The following code tries to optimize the copy by using unsigned
* alignment. This will work fine if both source and destination are
* aligned on the same boundary. However, if they are aligned on
@@ -86,7 +93,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
case 0x1: /* Unaligned - Off by 1 */
/* Word align the source */
i_src = (const void *) ((unsigned)src & ~3);
-
+#ifndef __MICROBLAZEEL__
/* Load the holding buffer */
buf_hold = *i_src++ << 8;
@@ -95,7 +102,16 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
*i_dst++ = buf_hold | value >> 24;
buf_hold = value << 8;
}
+#else
+ /* Load the holding buffer */
+ buf_hold = (*i_src++ & 0xFFFFFF00) >>8;
+ for (; c >= 4; c -= 4) {
+ value = *i_src++;
+ *i_dst++ = buf_hold | ((value & 0xFF) << 24);
+ buf_hold = (value & 0xFFFFFF00) >>8;
+ }
+#endif
/* Realign the source */
src = (const void *)i_src;
src -= 3;
@@ -103,7 +119,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
case 0x2: /* Unaligned - Off by 2 */
/* Word align the source */
i_src = (const void *) ((unsigned)src & ~3);
-
+#ifndef __MICROBLAZEEL__
/* Load the holding buffer */
buf_hold = *i_src++ << 16;
@@ -112,7 +128,16 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
*i_dst++ = buf_hold | value >> 16;
buf_hold = value << 16;
}
+#else
+ /* Load the holding buffer */
+ buf_hold = (*i_src++ & 0xFFFF0000 )>>16;
+ for (; c >= 4; c -= 4) {
+ value = *i_src++;
+ *i_dst++ = buf_hold | ((value & 0xFFFF)<<16);
+ buf_hold = (value & 0xFFFF0000) >>16;
+ }
+#endif
/* Realign the source */
src = (const void *)i_src;
src -= 2;
@@ -120,7 +145,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
case 0x3: /* Unaligned - Off by 3 */
/* Word align the source */
i_src = (const void *) ((unsigned)src & ~3);
-
+#ifndef __MICROBLAZEEL__
/* Load the holding buffer */
buf_hold = *i_src++ << 24;
@@ -129,7 +154,16 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
*i_dst++ = buf_hold | value >> 8;
buf_hold = value << 24;
}
+#else
+ /* Load the holding buffer */
+ buf_hold = (*i_src++ & 0xFF000000) >> 24;
+ for (; c >= 4; c -= 4) {
+ value = *i_src++;
+ *i_dst++ = buf_hold | ((value & 0xFFFFFF) << 8);
+ buf_hold = (value & 0xFF000000) >> 24;
+ }
+#endif
/* Realign the source */
src = (const void *)i_src;
src -= 1;
@@ -150,7 +184,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
}
return v_dst;
-#endif
}
+#endif /* CONFIG_OPT_LIB_FUNCTION */
EXPORT_SYMBOL(memcpy);
#endif /* __HAVE_ARCH_MEMCPY */
diff --git a/arch/microblaze/lib/memmove.c b/arch/microblaze/lib/memmove.c
index 0929198c5e68..123e3616f2dd 100644
--- a/arch/microblaze/lib/memmove.c
+++ b/arch/microblaze/lib/memmove.c
@@ -31,16 +31,12 @@
#include <linux/string.h>
#ifdef __HAVE_ARCH_MEMMOVE
+#ifndef CONFIG_OPT_LIB_FUNCTION
void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
{
const char *src = v_src;
char *dst = v_dst;
-#ifdef CONFIG_OPT_LIB_FUNCTION
- const uint32_t *i_src;
- uint32_t *i_dst;
-#endif
-
if (!c)
return v_dst;
@@ -48,7 +44,6 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
if (v_dst <= v_src)
return memcpy(v_dst, v_src, c);
-#ifndef CONFIG_OPT_LIB_FUNCTION
/* copy backwards, from end to beginning */
src += c;
dst += c;
@@ -58,7 +53,22 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
*--dst = *--src;
return v_dst;
-#else
+}
+#else /* CONFIG_OPT_LIB_FUNCTION */
+void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
+{
+ const char *src = v_src;
+ char *dst = v_dst;
+ const uint32_t *i_src;
+ uint32_t *i_dst;
+
+ if (!c)
+ return v_dst;
+
+ /* Use memcpy when source is higher than dest */
+ if (v_dst <= v_src)
+ return memcpy(v_dst, v_src, c);
+
/* The following code tries to optimize the copy by using unsigned
* alignment. This will work fine if both source and destination are
* aligned on the same boundary. However, if they are aligned on
@@ -104,7 +114,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
case 0x1: /* Unaligned - Off by 1 */
/* Word align the source */
i_src = (const void *) (((unsigned)src + 4) & ~3);
-
+#ifndef __MICROBLAZEEL__
/* Load the holding buffer */
buf_hold = *--i_src >> 24;
@@ -113,7 +123,16 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
*--i_dst = buf_hold << 8 | value;
buf_hold = value >> 24;
}
+#else
+ /* Load the holding buffer */
+ buf_hold = (*--i_src & 0xFF) << 24;
+ for (; c >= 4; c -= 4) {
+ value = *--i_src;
+ *--i_dst = buf_hold | ((value & 0xFFFFFF00)>>8);
+ buf_hold = (value & 0xFF) << 24;
+ }
+#endif
/* Realign the source */
src = (const void *)i_src;
src += 1;
@@ -121,7 +140,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
case 0x2: /* Unaligned - Off by 2 */
/* Word align the source */
i_src = (const void *) (((unsigned)src + 4) & ~3);
-
+#ifndef __MICROBLAZEEL__
/* Load the holding buffer */
buf_hold = *--i_src >> 16;
@@ -130,7 +149,16 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
*--i_dst = buf_hold << 16 | value;
buf_hold = value >> 16;
}
+#else
+ /* Load the holding buffer */
+ buf_hold = (*--i_src & 0xFFFF) << 16;
+ for (; c >= 4; c -= 4) {
+ value = *--i_src;
+ *--i_dst = buf_hold | ((value & 0xFFFF0000)>>16);
+ buf_hold = (value & 0xFFFF) << 16;
+ }
+#endif
/* Realign the source */
src = (const void *)i_src;
src += 2;
@@ -138,7 +166,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
case 0x3: /* Unaligned - Off by 3 */
/* Word align the source */
i_src = (const void *) (((unsigned)src + 4) & ~3);
-
+#ifndef __MICROBLAZEEL__
/* Load the holding buffer */
buf_hold = *--i_src >> 8;
@@ -147,7 +175,16 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
*--i_dst = buf_hold << 24 | value;
buf_hold = value >> 8;
}
+#else
+ /* Load the holding buffer */
+ buf_hold = (*--i_src & 0xFFFFFF) << 8;
+ for (; c >= 4; c -= 4) {
+ value = *--i_src;
+ *--i_dst = buf_hold | ((value & 0xFF000000)>> 24);
+ buf_hold = (value & 0xFFFFFF) << 8;;
+ }
+#endif
/* Realign the source */
src = (const void *)i_src;
src += 3;
@@ -169,7 +206,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
*--dst = *--src;
}
return v_dst;
-#endif
}
+#endif /* CONFIG_OPT_LIB_FUNCTION */
EXPORT_SYMBOL(memmove);
#endif /* __HAVE_ARCH_MEMMOVE */
diff --git a/arch/microblaze/lib/memset.c b/arch/microblaze/lib/memset.c
index ecfb663e1fc1..834565d1607e 100644
--- a/arch/microblaze/lib/memset.c
+++ b/arch/microblaze/lib/memset.c
@@ -31,17 +31,30 @@
#include <linux/string.h>
#ifdef __HAVE_ARCH_MEMSET
+#ifndef CONFIG_OPT_LIB_FUNCTION
+void *memset(void *v_src, int c, __kernel_size_t n)
+{
+ char *src = v_src;
+
+ /* Truncate c to 8 bits */
+ c = (c & 0xFF);
+
+ /* Simple, byte oriented memset or the rest of count. */
+ while (n--)
+ *src++ = c;
+
+ return v_src;
+}
+#else /* CONFIG_OPT_LIB_FUNCTION */
void *memset(void *v_src, int c, __kernel_size_t n)
{
char *src = v_src;
-#ifdef CONFIG_OPT_LIB_FUNCTION
uint32_t *i_src;
uint32_t w32 = 0;
-#endif
+
/* Truncate c to 8 bits */
c = (c & 0xFF);
-#ifdef CONFIG_OPT_LIB_FUNCTION
if (unlikely(c)) {
/* Make a repeating word out of it */
w32 = c;
@@ -72,12 +85,13 @@ void *memset(void *v_src, int c, __kernel_size_t n)
src = (void *)i_src;
}
-#endif
+
/* Simple, byte oriented memset or the rest of count. */
while (n--)
*src++ = c;
return v_src;
}
+#endif /* CONFIG_OPT_LIB_FUNCTION */
EXPORT_SYMBOL(memset);
#endif /* __HAVE_ARCH_MEMSET */
diff --git a/arch/microblaze/lib/modsi3.S b/arch/microblaze/lib/modsi3.S
new file mode 100644
index 000000000000..84e0bee6e8c7
--- /dev/null
+++ b/arch/microblaze/lib/modsi3.S
@@ -0,0 +1,73 @@
+#include <linux/linkage.h>
+
+/*
+* modulo operation for 32 bit integers.
+* Input : op1 in Reg r5
+* op2 in Reg r6
+* Output: op1 mod op2 in Reg r3
+*/
+
+ .text
+ .globl __modsi3
+ .type __modsi3, @function
+ .ent __modsi3
+
+__modsi3:
+ .frame r1, 0, r15
+
+ addik r1, r1, -16
+ swi r28, r1, 0
+ swi r29, r1, 4
+ swi r30, r1, 8
+ swi r31, r1, 12
+
+ beqi r6, div_by_zero /* div_by_zero division error */
+ beqi r5, result_is_zero /* result is zero */
+ bgeid r5, r5_pos
+ /* get the sign of the result [ depends only on the first arg] */
+ add r28, r5, r0
+ rsubi r5, r5, 0 /* make r5 positive */
+r5_pos:
+ bgei r6, r6_pos
+ rsubi r6, r6, 0 /* make r6 positive */
+r6_pos:
+ addik r3, r0, 0 /* clear mod */
+ addik r30, r0, 0 /* clear div */
+ addik r29, r0, 32 /* initialize the loop count */
+/* first part try to find the first '1' in the r5 */
+div1:
+ add r5, r5, r5 /* left shift logical r5 */
+ bgeid r5, div1
+ addik r29, r29, -1
+div2:
+ /* left shift logical r5 get the '1' into the carry */
+ add r5, r5, r5
+ addc r3, r3, r3 /* move that bit into the mod register */
+ rsub r31, r6, r3 /* try to subtract (r30 a r6) */
+ blti r31, mod_too_small
+ /* move the r31 to mod since the result was positive */
+ or r3, r0, r31
+ addik r30, r30, 1
+mod_too_small:
+ addik r29, r29, -1
+ beqi r29, loop_end
+ add r30, r30, r30 /* shift in the '1' into div */
+ bri div2 /* div2 */
+loop_end:
+ bgei r28, return_here
+ brid return_here
+ rsubi r3, r3, 0 /* negate the result */
+div_by_zero:
+result_is_zero:
+ or r3, r0, r0 /* set result to 0 [both mod as well as div are 0] */
+return_here:
+/* restore values of csrs and that of r3 and the divisor and the dividend */
+ lwi r28, r1, 0
+ lwi r29, r1, 4
+ lwi r30, r1, 8
+ lwi r31, r1, 12
+ rtsd r15, 8
+ addik r1, r1, 16
+
+.size __modsi3, . - __modsi3
+.end __modsi3
diff --git a/arch/microblaze/lib/muldi3.S b/arch/microblaze/lib/muldi3.S
new file mode 100644
index 000000000000..ceeaa8c407f2
--- /dev/null
+++ b/arch/microblaze/lib/muldi3.S
@@ -0,0 +1,121 @@
+#include <linux/linkage.h>
+
+/*
+ * Multiply operation for 64 bit integers, for devices with hard multiply
+ * Input : Operand1[H] in Reg r5
+ * Operand1[L] in Reg r6
+ * Operand2[H] in Reg r7
+ * Operand2[L] in Reg r8
+ * Output: Result[H] in Reg r3
+ * Result[L] in Reg r4
+ *
+ * Explaination:
+ *
+ * Both the input numbers are divided into 16 bit number as follows
+ * op1 = A B C D
+ * op2 = E F G H
+ * result = D * H
+ * + (C * H + D * G) << 16
+ * + (B * H + C * G + D * F) << 32
+ * + (A * H + B * G + C * F + D * E) << 48
+ *
+ * Only 64 bits of the output are considered
+ */
+
+ .text
+ .globl __muldi3
+ .type __muldi3, @function
+ .ent __muldi3
+
+__muldi3:
+ addi r1, r1, -40
+
+/* Save the input operands on the caller's stack */
+ swi r5, r1, 44
+ swi r6, r1, 48
+ swi r7, r1, 52
+ swi r8, r1, 56
+
+/* Store all the callee saved registers */
+ sw r20, r1, r0
+ swi r21, r1, 4
+ swi r22, r1, 8
+ swi r23, r1, 12
+ swi r24, r1, 16
+ swi r25, r1, 20
+ swi r26, r1, 24
+ swi r27, r1, 28
+
+/* Load all the 16 bit values for A thru H */
+ lhui r20, r1, 44 /* A */
+ lhui r21, r1, 46 /* B */
+ lhui r22, r1, 48 /* C */
+ lhui r23, r1, 50 /* D */
+ lhui r24, r1, 52 /* E */
+ lhui r25, r1, 54 /* F */
+ lhui r26, r1, 56 /* G */
+ lhui r27, r1, 58 /* H */
+
+/* D * H ==> LSB of the result on stack ==> Store1 */
+ mul r9, r23, r27
+ swi r9, r1, 36 /* Pos2 and Pos3 */
+
+/* Hi (Store1) + C * H + D * G ==> Store2 ==> Pos1 and Pos2 */
+/* Store the carry generated in position 2 for Pos 3 */
+ lhui r11, r1, 36 /* Pos2 */
+ mul r9, r22, r27 /* C * H */
+ mul r10, r23, r26 /* D * G */
+ add r9, r9, r10
+ addc r12, r0, r0
+ add r9, r9, r11
+ addc r12, r12, r0 /* Store the Carry */
+ shi r9, r1, 36 /* Store Pos2 */
+ swi r9, r1, 32
+ lhui r11, r1, 32
+ shi r11, r1, 34 /* Store Pos1 */
+
+/* Hi (Store2) + B * H + C * G + D * F ==> Store3 ==> Pos0 and Pos1 */
+ mul r9, r21, r27 /* B * H */
+ mul r10, r22, r26 /* C * G */
+ mul r7, r23, r25 /* D * F */
+ add r9, r9, r11
+ add r9, r9, r10
+ add r9, r9, r7
+ swi r9, r1, 32 /* Pos0 and Pos1 */
+
+/* Hi (Store3) + A * H + B * G + C * F + D * E ==> Store3 ==> Pos0 */
+ lhui r11, r1, 32 /* Pos0 */
+ mul r9, r20, r27 /* A * H */
+ mul r10, r21, r26 /* B * G */
+ mul r7, r22, r25 /* C * F */
+ mul r8, r23, r24 /* D * E */
+ add r9, r9, r11
+ add r9, r9, r10
+ add r9, r9, r7
+ add r9, r9, r8
+ sext16 r9, r9 /* Sign extend the MSB */
+ shi r9, r1, 32
+
+/* Move results to r3 and r4 */
+ lhui r3, r1, 32
+ add r3, r3, r12
+ shi r3, r1, 32
+ lwi r3, r1, 32 /* Hi Part */
+ lwi r4, r1, 36 /* Lo Part */
+
+/* Restore Callee saved registers */
+ lw r20, r1, r0
+ lwi r21, r1, 4
+ lwi r22, r1, 8
+ lwi r23, r1, 12
+ lwi r24, r1, 16
+ lwi r25, r1, 20
+ lwi r26, r1, 24
+ lwi r27, r1, 28
+
+/* Restore Frame and return */
+ rtsd r15, 8
+ addi r1, r1, 40
+
+.size __muldi3, . - __muldi3
+.end __muldi3
diff --git a/arch/microblaze/lib/mulsi3.S b/arch/microblaze/lib/mulsi3.S
new file mode 100644
index 000000000000..90bd7b93afe6
--- /dev/null
+++ b/arch/microblaze/lib/mulsi3.S
@@ -0,0 +1,46 @@
+#include <linux/linkage.h>
+
+/*
+ * Multiply operation for 32 bit integers.
+ * Input : Operand1 in Reg r5
+ * Operand2 in Reg r6
+ * Output: Result [op1 * op2] in Reg r3
+ */
+ .text
+ .globl __mulsi3
+ .type __mulsi3, @function
+ .ent __mulsi3
+
+__mulsi3:
+ .frame r1, 0, r15
+ add r3, r0, r0
+ beqi r5, result_is_zero /* multiply by zero */
+ beqi r6, result_is_zero /* multiply by zero */
+ bgeid r5, r5_pos
+ xor r4, r5, r6 /* get the sign of the result */
+ rsubi r5, r5, 0 /* make r5 positive */
+r5_pos:
+ bgei r6, r6_pos
+ rsubi r6, r6, 0 /* make r6 positive */
+r6_pos:
+ bri l1
+l2:
+ add r5, r5, r5
+l1:
+ srl r6, r6
+ addc r7, r0, r0
+ beqi r7, l2
+ bneid r6, l2
+ add r3, r3, r5
+ blti r4, negateresult
+ rtsd r15, 8
+ nop
+negateresult:
+ rtsd r15, 8
+ rsub r3, r3, r0
+result_is_zero:
+ rtsd r15, 8
+ addi r3, r0, 0
+
+.size __mulsi3, . - __mulsi3
+.end __mulsi3
diff --git a/arch/microblaze/lib/udivsi3.S b/arch/microblaze/lib/udivsi3.S
new file mode 100644
index 000000000000..64cf57e4bb85
--- /dev/null
+++ b/arch/microblaze/lib/udivsi3.S
@@ -0,0 +1,84 @@
+#include <linux/linkage.h>
+
+/*
+* Unsigned divide operation.
+* Input : Divisor in Reg r5
+* Dividend in Reg r6
+* Output: Result in Reg r3
+*/
+
+ .text
+ .globl __udivsi3
+ .type __udivsi3, @function
+ .ent __udivsi3
+
+__udivsi3:
+
+ .frame r1, 0, r15
+
+ addik r1, r1, -12
+ swi r29, r1, 0
+ swi r30, r1, 4
+ swi r31, r1, 8
+
+ beqi r6, div_by_zero /* div_by_zero /* division error */
+ beqid r5, result_is_zero /* result is zero */
+ addik r30, r0, 0 /* clear mod */
+ addik r29, r0, 32 /* initialize the loop count */
+
+/* check if r6 and r5 are equal - if yes, return 1 */
+ rsub r18, r5, r6
+ beqid r18, return_here
+ addik r3, r0, 1
+
+/* check if (uns)r6 is greater than (uns)r5. in that case, just return 0 */
+ xor r18, r5, r6
+ bgeid r18, 16
+ add r3, r0, r0 /* we would anyways clear r3 */
+ blti r6, return_here /* r6[bit 31 = 1] hence is greater */
+ bri checkr6
+ rsub r18, r6, r5 /* microblazecmp */
+ blti r18, return_here
+
+/* if r6 [bit 31] is set, then return result as 1 */
+checkr6:
+ bgti r6, div0
+ brid return_here
+ addik r3, r0, 1
+
+/* first part try to find the first '1' in the r5 */
+div0:
+ blti r5, div2
+div1:
+ add r5, r5, r5 /* left shift logical r5 */
+ bgtid r5, div1
+ addik r29, r29, -1
+div2:
+/* left shift logical r5 get the '1' into the carry */
+ add r5, r5, r5
+ addc r30, r30, r30 /* move that bit into the mod register */
+ rsub r31, r6, r30 /* try to subtract (r30 a r6) */
+ blti r31, mod_too_small
+/* move the r31 to mod since the result was positive */
+ or r30, r0, r31
+ addik r3, r3, 1
+mod_too_small:
+ addik r29, r29, -1
+ beqi r29, loop_end
+ add r3, r3, r3 /* shift in the '1' into div */
+ bri div2 /* div2 */
+loop_end:
+ bri return_here
+div_by_zero:
+result_is_zero:
+ or r3, r0, r0 /* set result to 0 */
+return_here:
+/* restore values of csrs and that of r3 and the divisor and the dividend */
+ lwi r29, r1, 0
+ lwi r30, r1, 4
+ lwi r31, r1, 8
+ rtsd r15, 8
+ addik r1, r1, 12
+
+.size __udivsi3, . - __udivsi3
+.end __udivsi3
diff --git a/arch/microblaze/lib/umodsi3.S b/arch/microblaze/lib/umodsi3.S
new file mode 100644
index 000000000000..17d16bafae58
--- /dev/null
+++ b/arch/microblaze/lib/umodsi3.S
@@ -0,0 +1,86 @@
+#include <linux/linkage.h>
+
+/*
+ * Unsigned modulo operation for 32 bit integers.
+ * Input : op1 in Reg r5
+ * op2 in Reg r6
+ * Output: op1 mod op2 in Reg r3
+ */
+
+ .text
+ .globl __umodsi3
+ .type __umodsi3, @function
+ .ent __umodsi3
+
+__umodsi3:
+ .frame r1, 0, r15
+
+ addik r1, r1, -12
+ swi r29, r1, 0
+ swi r30, r1, 4
+ swi r31, r1, 8
+
+ beqi r6, div_by_zero /* div_by_zero - division error */
+ beqid r5, result_is_zero /* result is zero */
+ addik r3, r0, 0 /* clear div */
+ addik r30, r0, 0 /* clear mod */
+ addik r29, r0, 32 /* initialize the loop count */
+
+/* check if r6 and r5 are equal /* if yes, return 0 */
+ rsub r18, r5, r6
+ beqi r18, return_here
+
+/* check if (uns)r6 is greater than (uns)r5. in that case, just return r5 */
+ xor r18, r5, r6
+ bgeid r18, 16
+ addik r3, r5, 0
+ blti r6, return_here
+ bri $lcheckr6
+ rsub r18, r5, r6 /* microblazecmp */
+ bgti r18, return_here
+
+/* if r6 [bit 31] is set, then return result as r5-r6 */
+$lcheckr6:
+ bgtid r6, div0
+ addik r3, r0, 0
+ addik r18, r0, 0x7fffffff
+ and r5, r5, r18
+ and r6, r6, r18
+ brid return_here
+ rsub r3, r6, r5
+/* first part: try to find the first '1' in the r5 */
+div0:
+ blti r5, div2
+div1:
+ add r5, r5, r5 /* left shift logical r5 */
+ bgeid r5, div1
+ addik r29, r29, -1
+div2:
+ /* left shift logical r5 get the '1' into the carry */
+ add r5, r5, r5
+ addc r3, r3, r3 /* move that bit into the mod register */
+ rsub r31, r6, r3 /* try to subtract (r3 a r6) */
+ blti r31, mod_too_small
+ /* move the r31 to mod since the result was positive */
+ or r3, r0, r31
+ addik r30, r30, 1
+mod_too_small:
+ addik r29, r29, -1
+ beqi r29, loop_end
+ add r30, r30, r30 /* shift in the '1' into div */
+ bri div2 /* div2 */
+loop_end:
+ bri return_here
+div_by_zero:
+result_is_zero:
+ or r3, r0, r0 /* set result to 0 */
+return_here:
+/* restore values of csrs and that of r3 and the divisor and the dividend */
+ lwi r29, r1, 0
+ lwi r30, r1, 4
+ lwi r31, r1, 8
+ rtsd r15, 8
+ addik r1, r1, 12
+
+.size __umodsi3, . - __umodsi3
+.end __umodsi3
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 55ef532f32be..e363615d6798 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -60,21 +60,6 @@ struct dma_map_ops *get_pci_dma_ops(void)
}
EXPORT_SYMBOL(get_pci_dma_ops);
-int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
-{
- return dma_set_mask(&dev->dev, mask);
-}
-
-int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
-{
- int rc;
-
- rc = dma_set_mask(&dev->dev, mask);
- dev->dev.coherent_dma_mask = dev->dma_mask;
-
- return rc;
-}
-
struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
{
struct pci_controller *phb;
@@ -1075,8 +1060,6 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
bus->number, bus->self ? pci_name(bus->self) : "PHB");
list_for_each_entry(dev, &bus->devices, bus_list) {
- struct dev_archdata *sd = &dev->dev.archdata;
-
/* Setup OF node pointer in archdata */
dev->dev.of_node = pci_device_to_OF_node(dev);
@@ -1086,8 +1069,8 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
/* Hook up default DMA ops */
- sd->dma_ops = pci_dma_ops;
- sd->dma_data = (void *)PCI_DRAM_OFFSET;
+ set_dma_ops(&dev->dev, pci_dma_ops);
+ dev->dev.archdata.dma_data = (void *)PCI_DRAM_OFFSET;
/* Read default IRQs and fixup if necessary */
pci_read_irq_line(dev);
diff --git a/arch/microblaze/platform/generic/system.dts b/arch/microblaze/platform/generic/system.dts
index 2d5c41767cd0..3f85df2b73b3 100644
--- a/arch/microblaze/platform/generic/system.dts
+++ b/arch/microblaze/platform/generic/system.dts
@@ -85,6 +85,7 @@
xlnx,dynamic-bus-sizing = <0x1>;
xlnx,edge-is-positive = <0x1>;
xlnx,family = "virtex5";
+ xlnx,endianness = <0x1>;
xlnx,fpu-exception = <0x1>;
xlnx,fsl-data-size = <0x20>;
xlnx,fsl-exception = <0x0>;
@@ -218,6 +219,7 @@
#address-cells = <1>;
#size-cells = <1>;
compatible = "xlnx,compound";
+ ranges ;
ethernet@81c00000 {
compatible = "xlnx,xps-ll-temac-1.01.b", "xlnx,xps-ll-temac-1.00.a";
device_type = "network";
@@ -332,6 +334,7 @@
#address-cells = <1>;
#size-cells = <1>;
compatible = "xlnx,mpmc-4.02.a";
+ ranges ;
PIM3: sdma@84600180 {
compatible = "xlnx,ll-dma-1.00.a";
interrupt-parent = <&xps_intc_0>;
diff --git a/arch/microblaze/platform/platform.c b/arch/microblaze/platform/platform.c
index 5b89b58c5aed..b9529caa507a 100644
--- a/arch/microblaze/platform/platform.c
+++ b/arch/microblaze/platform/platform.c
@@ -17,9 +17,6 @@
static struct of_device_id xilinx_of_bus_ids[] __initdata = {
{ .compatible = "simple-bus", },
- { .compatible = "xlnx,plb-v46-1.00.a", },
- { .compatible = "xlnx,opb-v20-1.10.c", },
- { .compatible = "xlnx,opb-v20-1.10.b", },
{ .compatible = "xlnx,compound", },
{}
};
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 4c9f402295dd..46cae2b163e4 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2128,6 +2128,13 @@ config SECCOMP
If unsure, say Y. Only embedded should say N here.
+config USE_OF
+ bool "Flattened Device Tree support"
+ select OF
+ select OF_FLATTREE
+ help
+ Include support for flattened device tree machine descriptions.
+
endmenu
config LOCKDEP_SUPPORT
@@ -2196,10 +2203,14 @@ config TC
bool "TURBOchannel support"
depends on MACH_DECSTATION
help
- TurboChannel is a DEC (now Compaq (now HP)) bus for Alpha and MIPS
- processors. Documentation on writing device drivers for TurboChannel
- is available at:
- <http://www.cs.arizona.edu/computer.help/policy/DIGITAL_unix/AA-PS3HD-TET1_html/TITLE.html>.
+ TURBOchannel is a DEC (now Compaq (now HP)) bus for Alpha and MIPS
+ processors. TURBOchannel programming specifications are available
+ at:
+ <ftp://ftp.hp.com/pub/alphaserver/archive/triadd/>
+ and:
+ <http://www.computer-refuge.org/classiccmp/ftp.digital.com/pub/DEC/TriAdd/>
+ Linux driver support status is documented at:
+ <http://www.linux-mips.org/wiki/DECstation>
#config ACCESSBUS
# bool "Access.Bus support"
diff --git a/arch/mips/alchemy/devboards/db1200/platform.c b/arch/mips/alchemy/devboards/db1200/platform.c
index 3fa34c3abc04..fbb55935b99e 100644
--- a/arch/mips/alchemy/devboards/db1200/platform.c
+++ b/arch/mips/alchemy/devboards/db1200/platform.c
@@ -429,6 +429,11 @@ static struct platform_device db1200_audio_dev = {
.resource = au1200_psc1_res,
};
+static struct platform_device db1200_stac_dev = {
+ .name = "ac97-codec",
+ .id = 1, /* on PSC1 */
+};
+
static struct platform_device *db1200_devs[] __initdata = {
NULL, /* PSC0, selected by S6.8 */
&db1200_ide_dev,
@@ -436,6 +441,7 @@ static struct platform_device *db1200_devs[] __initdata = {
&db1200_rtc_dev,
&db1200_nand_dev,
&db1200_audio_dev,
+ &db1200_stac_dev,
};
static int __init db1200_dev_init(void)
diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h
index 75753ca73bfd..77e644082a3b 100644
--- a/arch/mips/include/asm/highmem.h
+++ b/arch/mips/include/asm/highmem.h
@@ -45,18 +45,12 @@ extern pte_t *pkmap_page_table;
extern void * kmap_high(struct page *page);
extern void kunmap_high(struct page *page);
-extern void *__kmap(struct page *page);
-extern void __kunmap(struct page *page);
-extern void *__kmap_atomic(struct page *page, enum km_type type);
-extern void __kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
-extern void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
-extern struct page *__kmap_atomic_to_page(void *ptr);
-
-#define kmap __kmap
-#define kunmap __kunmap
-#define kmap_atomic __kmap_atomic
-#define kunmap_atomic_notypecheck __kunmap_atomic_notypecheck
-#define kmap_atomic_to_page __kmap_atomic_to_page
+extern void *kmap(struct page *page);
+extern void kunmap(struct page *page);
+extern void *__kmap_atomic(struct page *page);
+extern void __kunmap_atomic(void *kvaddr);
+extern void *kmap_atomic_pfn(unsigned long pfn);
+extern struct page *kmap_atomic_to_page(void *ptr);
#define flush_cache_kmaps() flush_cache_all()
diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h
index dea4aed6478f..b003ed52ed17 100644
--- a/arch/mips/include/asm/irq.h
+++ b/arch/mips/include/asm/irq.h
@@ -16,6 +16,11 @@
#include <irq.h>
+static inline void irq_dispose_mapping(unsigned int virq)
+{
+ return;
+}
+
#ifdef CONFIG_I8259
static inline int irq_canonicalize(int irq)
{
diff --git a/arch/mips/include/asm/pci/bridge.h b/arch/mips/include/asm/pci/bridge.h
index 5f4b9d4e4114..f1f508e4f971 100644
--- a/arch/mips/include/asm/pci/bridge.h
+++ b/arch/mips/include/asm/pci/bridge.h
@@ -839,7 +839,7 @@ struct bridge_controller {
nasid_t nasid;
unsigned int widget_id;
unsigned int irq_cpu;
- dma64_addr_t baddr;
+ u64 baddr;
unsigned int pci_int[8];
};
diff --git a/arch/mips/include/asm/pgtable-32.h b/arch/mips/include/asm/pgtable-32.h
index ae90412556d0..8a153d2fa62a 100644
--- a/arch/mips/include/asm/pgtable-32.h
+++ b/arch/mips/include/asm/pgtable-32.h
@@ -154,10 +154,7 @@ pfn_pte(unsigned long pfn, pgprot_t prot)
#define pte_offset_map(dir, address) \
((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
-#define pte_offset_map_nested(dir, address) \
- ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
#define pte_unmap(pte) ((void)(pte))
-#define pte_unmap_nested(pte) ((void)(pte))
#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
diff --git a/arch/mips/include/asm/pgtable-64.h b/arch/mips/include/asm/pgtable-64.h
index 1be4b0fa30da..f00896087dda 100644
--- a/arch/mips/include/asm/pgtable-64.h
+++ b/arch/mips/include/asm/pgtable-64.h
@@ -257,10 +257,7 @@ static inline pmd_t *pmd_offset(pud_t * pud, unsigned long address)
((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address))
#define pte_offset_map(dir, address) \
((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
-#define pte_offset_map_nested(dir, address) \
- ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
#define pte_unmap(pte) ((void)(pte))
-#define pte_unmap_nested(pte) ((void)(pte))
/*
* Initialize a new pgd / pmd table with invalid pointers.
diff --git a/arch/mips/include/asm/prom.h b/arch/mips/include/asm/prom.h
new file mode 100644
index 000000000000..f29b862d9db3
--- /dev/null
+++ b/arch/mips/include/asm/prom.h
@@ -0,0 +1,31 @@
+/*
+ * arch/mips/include/asm/prom.h
+ *
+ * Copyright (C) 2010 Cisco Systems Inc. <dediao@cisco.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 __ASM_MIPS_PROM_H
+#define __ASM_MIPS_PROM_H
+
+#ifdef CONFIG_OF
+#include <asm/bootinfo.h>
+
+/* which is compatible with the flattened device tree (FDT) */
+#define cmd_line arcs_cmdline
+
+extern int early_init_dt_scan_memory_arch(unsigned long node,
+ const char *uname, int depth, void *data);
+
+extern int reserve_mem_mach(unsigned long addr, unsigned long size);
+extern void free_mem_mach(unsigned long addr, unsigned long size);
+
+extern void device_tree_init(void);
+#else /* CONFIG_OF */
+static inline void device_tree_init(void) { }
+#endif /* CONFIG_OF */
+
+#endif /* _ASM_MIPS_PROM_H */
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 06f848299785..80884983270d 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -96,6 +96,8 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o
+obj-$(CONFIG_OF) += prom.o
+
CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT) += 8250-platform.o
diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
index 9a526ba6f257..802e6160f37e 100644
--- a/arch/mips/kernel/mips-mt-fpaff.c
+++ b/arch/mips/kernel/mips-mt-fpaff.c
@@ -103,7 +103,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
if (!check_same_owner(p) && !capable(CAP_SYS_NICE))
goto out_unlock;
- retval = security_task_setscheduler(p)
+ retval = security_task_setscheduler(p);
if (retval)
goto out_unlock;
diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c
new file mode 100644
index 000000000000..e000b278f024
--- /dev/null
+++ b/arch/mips/kernel/prom.c
@@ -0,0 +1,112 @@
+/*
+ * MIPS support for CONFIG_OF device tree support
+ *
+ * Copyright (C) 2010 Cisco Systems Inc. <dediao@cisco.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/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/bootmem.h>
+#include <linux/initrd.h>
+#include <linux/debugfs.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+
+#include <asm/page.h>
+#include <asm/prom.h>
+
+int __init early_init_dt_scan_memory_arch(unsigned long node,
+ const char *uname, int depth,
+ void *data)
+{
+ return early_init_dt_scan_memory(node, uname, depth, data);
+}
+
+void __init early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+ return add_memory_region(base, size, BOOT_MEM_RAM);
+}
+
+int __init reserve_mem_mach(unsigned long addr, unsigned long size)
+{
+ return reserve_bootmem(addr, size, BOOTMEM_DEFAULT);
+}
+
+void __init free_mem_mach(unsigned long addr, unsigned long size)
+{
+ return free_bootmem(addr, size);
+}
+
+u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+{
+ return virt_to_phys(
+ __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS))
+ );
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void __init early_init_dt_setup_initrd_arch(unsigned long start,
+ unsigned long end)
+{
+ initrd_start = (unsigned long)__va(start);
+ initrd_end = (unsigned long)__va(end);
+ initrd_below_start_ok = 1;
+}
+#endif
+
+/*
+ * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq#
+ *
+ * Currently the mapping mechanism is trivial; simple flat hwirq numbers are
+ * mapped 1:1 onto Linux irq numbers. Cascaded irq controllers are not
+ * supported.
+ */
+unsigned int irq_create_of_mapping(struct device_node *controller,
+ const u32 *intspec, unsigned int intsize)
+{
+ return intspec[0];
+}
+EXPORT_SYMBOL_GPL(irq_create_of_mapping);
+
+void __init early_init_devtree(void *params)
+{
+ /* Setup flat device-tree pointer */
+ initial_boot_params = params;
+
+ /* Retrieve various informations from the /chosen node of the
+ * device-tree, including the platform type, initrd location and
+ * size, and more ...
+ */
+ of_scan_flat_dt(early_init_dt_scan_chosen, NULL);
+
+ /* Scan memory nodes */
+ of_scan_flat_dt(early_init_dt_scan_root, NULL);
+ of_scan_flat_dt(early_init_dt_scan_memory_arch, NULL);
+}
+
+void __init device_tree_init(void)
+{
+ unsigned long base, size;
+
+ if (!initial_boot_params)
+ return;
+
+ base = virt_to_phys((void *)initial_boot_params);
+ size = initial_boot_params->totalsize;
+
+ /* Before we do anything, lets reserve the dt blob */
+ reserve_mem_mach(base, size);
+
+ unflatten_device_tree();
+
+ /* free the space reserved for the dt blob */
+ free_mem_mach(base, size);
+}
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index c8777333e198..d21c388c0116 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -255,9 +255,13 @@ int ptrace_set_watch_regs(struct task_struct *child,
return 0;
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret;
+ void __user *addrp = (void __user *) addr;
+ void __user *datavp = (void __user *) data;
+ unsigned long __user *datalp = (void __user *) data;
switch (request) {
/* when I and D space are separate, these will need to be fixed. */
@@ -386,7 +390,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = -EIO;
goto out;
}
- ret = put_user(tmp, (unsigned long __user *) data);
+ ret = put_user(tmp, datalp);
break;
}
@@ -478,34 +482,31 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
case PTRACE_GETREGS:
- ret = ptrace_getregs(child, (__s64 __user *) data);
+ ret = ptrace_getregs(child, datavp);
break;
case PTRACE_SETREGS:
- ret = ptrace_setregs(child, (__s64 __user *) data);
+ ret = ptrace_setregs(child, datavp);
break;
case PTRACE_GETFPREGS:
- ret = ptrace_getfpregs(child, (__u32 __user *) data);
+ ret = ptrace_getfpregs(child, datavp);
break;
case PTRACE_SETFPREGS:
- ret = ptrace_setfpregs(child, (__u32 __user *) data);
+ ret = ptrace_setfpregs(child, datavp);
break;
case PTRACE_GET_THREAD_AREA:
- ret = put_user(task_thread_info(child)->tp_value,
- (unsigned long __user *) data);
+ ret = put_user(task_thread_info(child)->tp_value, datalp);
break;
case PTRACE_GET_WATCH_REGS:
- ret = ptrace_get_watch_regs(child,
- (struct pt_watch_regs __user *) addr);
+ ret = ptrace_get_watch_regs(child, addrp);
break;
case PTRACE_SET_WATCH_REGS:
- ret = ptrace_set_watch_regs(child,
- (struct pt_watch_regs __user *) addr);
+ ret = ptrace_set_watch_regs(child, addrp);
break;
default:
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 85aef3fc6716..a6b900f2962b 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -31,6 +31,7 @@
#include <asm/setup.h>
#include <asm/smp-ops.h>
#include <asm/system.h>
+#include <asm/prom.h>
struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly;
@@ -487,6 +488,7 @@ static void __init arch_mem_init(char **cmdline_p)
}
bootmem_init();
+ device_tree_init();
sparse_init();
paging_init();
}
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index 47842b7d26ae..ec3faa413f3b 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -3,7 +3,6 @@
*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc.
diff --git a/arch/mips/math-emu/dp_add.c b/arch/mips/math-emu/dp_add.c
index bcf73bb5c33a..b422fcad852a 100644
--- a/arch/mips/math-emu/dp_add.c
+++ b/arch/mips/math-emu/dp_add.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/dp_cmp.c b/arch/mips/math-emu/dp_cmp.c
index 8ab4f320a478..0f32486b0ed9 100644
--- a/arch/mips/math-emu/dp_cmp.c
+++ b/arch/mips/math-emu/dp_cmp.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/dp_div.c b/arch/mips/math-emu/dp_div.c
index 6acedce3b32d..a1bce1b7c09c 100644
--- a/arch/mips/math-emu/dp_div.c
+++ b/arch/mips/math-emu/dp_div.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/dp_fint.c b/arch/mips/math-emu/dp_fint.c
index 39a71de16f47..88571288c9e0 100644
--- a/arch/mips/math-emu/dp_fint.c
+++ b/arch/mips/math-emu/dp_fint.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/dp_flong.c b/arch/mips/math-emu/dp_flong.c
index f08f223e488a..14fc01ec742d 100644
--- a/arch/mips/math-emu/dp_flong.c
+++ b/arch/mips/math-emu/dp_flong.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/dp_frexp.c b/arch/mips/math-emu/dp_frexp.c
index e650cb10c947..cb15a5eaecbb 100644
--- a/arch/mips/math-emu/dp_frexp.c
+++ b/arch/mips/math-emu/dp_frexp.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/dp_fsp.c b/arch/mips/math-emu/dp_fsp.c
index 494d19ac7049..1dfbd92ba9d0 100644
--- a/arch/mips/math-emu/dp_fsp.c
+++ b/arch/mips/math-emu/dp_fsp.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/dp_logb.c b/arch/mips/math-emu/dp_logb.c
index 603388621ca5..151127e59f5c 100644
--- a/arch/mips/math-emu/dp_logb.c
+++ b/arch/mips/math-emu/dp_logb.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/dp_modf.c b/arch/mips/math-emu/dp_modf.c
index a8570e5c3efc..b01f9cf6d402 100644
--- a/arch/mips/math-emu/dp_modf.c
+++ b/arch/mips/math-emu/dp_modf.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/dp_mul.c b/arch/mips/math-emu/dp_mul.c
index 48908a809c17..aa566e785f5a 100644
--- a/arch/mips/math-emu/dp_mul.c
+++ b/arch/mips/math-emu/dp_mul.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/dp_scalb.c b/arch/mips/math-emu/dp_scalb.c
index b84e6338330e..6f5df438dda8 100644
--- a/arch/mips/math-emu/dp_scalb.c
+++ b/arch/mips/math-emu/dp_scalb.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/dp_simple.c b/arch/mips/math-emu/dp_simple.c
index b90974246e5b..79ce2673a714 100644
--- a/arch/mips/math-emu/dp_simple.c
+++ b/arch/mips/math-emu/dp_simple.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/dp_sqrt.c b/arch/mips/math-emu/dp_sqrt.c
index 032328c49888..a2a51b87ae8f 100644
--- a/arch/mips/math-emu/dp_sqrt.c
+++ b/arch/mips/math-emu/dp_sqrt.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/dp_sub.c b/arch/mips/math-emu/dp_sub.c
index a2127d685a0d..0de098cbc77b 100644
--- a/arch/mips/math-emu/dp_sub.c
+++ b/arch/mips/math-emu/dp_sub.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/dp_tint.c b/arch/mips/math-emu/dp_tint.c
index 24478623c117..0ebe8598b94a 100644
--- a/arch/mips/math-emu/dp_tint.c
+++ b/arch/mips/math-emu/dp_tint.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/dp_tlong.c b/arch/mips/math-emu/dp_tlong.c
index 0f07ec2be3f9..133ce2ba0012 100644
--- a/arch/mips/math-emu/dp_tlong.c
+++ b/arch/mips/math-emu/dp_tlong.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/ieee754.c b/arch/mips/math-emu/ieee754.c
index cb1b6822711a..30554e1c67b4 100644
--- a/arch/mips/math-emu/ieee754.c
+++ b/arch/mips/math-emu/ieee754.c
@@ -9,7 +9,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h
index dd917332792c..22796e012060 100644
--- a/arch/mips/math-emu/ieee754.h
+++ b/arch/mips/math-emu/ieee754.h
@@ -1,7 +1,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
diff --git a/arch/mips/math-emu/ieee754d.c b/arch/mips/math-emu/ieee754d.c
index a0325337b76c..9599bdd32585 100644
--- a/arch/mips/math-emu/ieee754d.c
+++ b/arch/mips/math-emu/ieee754d.c
@@ -4,7 +4,6 @@
* MIPS floating point support
*
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
diff --git a/arch/mips/math-emu/ieee754dp.c b/arch/mips/math-emu/ieee754dp.c
index 2f22fd7fd784..080b5ca03fc6 100644
--- a/arch/mips/math-emu/ieee754dp.c
+++ b/arch/mips/math-emu/ieee754dp.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/ieee754dp.h b/arch/mips/math-emu/ieee754dp.h
index 762786538449..f139c724c59a 100644
--- a/arch/mips/math-emu/ieee754dp.h
+++ b/arch/mips/math-emu/ieee754dp.h
@@ -5,7 +5,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/ieee754int.h b/arch/mips/math-emu/ieee754int.h
index 1a846c5425cd..2701d9500959 100644
--- a/arch/mips/math-emu/ieee754int.h
+++ b/arch/mips/math-emu/ieee754int.h
@@ -5,7 +5,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/ieee754m.c b/arch/mips/math-emu/ieee754m.c
index d66896cd8f21..24190f3c9dd6 100644
--- a/arch/mips/math-emu/ieee754m.c
+++ b/arch/mips/math-emu/ieee754m.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/ieee754sp.c b/arch/mips/math-emu/ieee754sp.c
index a19b72185ab9..271d00d6113a 100644
--- a/arch/mips/math-emu/ieee754sp.c
+++ b/arch/mips/math-emu/ieee754sp.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h
index d9e3586b5bce..754fd54649b5 100644
--- a/arch/mips/math-emu/ieee754sp.h
+++ b/arch/mips/math-emu/ieee754sp.h
@@ -5,7 +5,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/ieee754xcpt.c b/arch/mips/math-emu/ieee754xcpt.c
index e02423a0ae23..b99a693c05af 100644
--- a/arch/mips/math-emu/ieee754xcpt.c
+++ b/arch/mips/math-emu/ieee754xcpt.c
@@ -1,7 +1,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_add.c b/arch/mips/math-emu/sp_add.c
index d8c4211bcfbe..ae1a327ccac0 100644
--- a/arch/mips/math-emu/sp_add.c
+++ b/arch/mips/math-emu/sp_add.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_cmp.c b/arch/mips/math-emu/sp_cmp.c
index d3eff6b04b5a..716cf37e2465 100644
--- a/arch/mips/math-emu/sp_cmp.c
+++ b/arch/mips/math-emu/sp_cmp.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_div.c b/arch/mips/math-emu/sp_div.c
index 2b437fcfdad9..d7747928c954 100644
--- a/arch/mips/math-emu/sp_div.c
+++ b/arch/mips/math-emu/sp_div.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_fdp.c b/arch/mips/math-emu/sp_fdp.c
index 4093723d1aa5..e1515aae0166 100644
--- a/arch/mips/math-emu/sp_fdp.c
+++ b/arch/mips/math-emu/sp_fdp.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_fint.c b/arch/mips/math-emu/sp_fint.c
index e88e125e01c2..9694d6c016cb 100644
--- a/arch/mips/math-emu/sp_fint.c
+++ b/arch/mips/math-emu/sp_fint.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_flong.c b/arch/mips/math-emu/sp_flong.c
index 26d6919a269a..16a651f29865 100644
--- a/arch/mips/math-emu/sp_flong.c
+++ b/arch/mips/math-emu/sp_flong.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_frexp.c b/arch/mips/math-emu/sp_frexp.c
index 359c6483dbfa..5bc993c30044 100644
--- a/arch/mips/math-emu/sp_frexp.c
+++ b/arch/mips/math-emu/sp_frexp.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_logb.c b/arch/mips/math-emu/sp_logb.c
index 3c337219ca32..9c14e0c75bd2 100644
--- a/arch/mips/math-emu/sp_logb.c
+++ b/arch/mips/math-emu/sp_logb.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_modf.c b/arch/mips/math-emu/sp_modf.c
index 76568946b4c0..25a0fbaa0556 100644
--- a/arch/mips/math-emu/sp_modf.c
+++ b/arch/mips/math-emu/sp_modf.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_mul.c b/arch/mips/math-emu/sp_mul.c
index 3f070f82212f..c06bb4022be5 100644
--- a/arch/mips/math-emu/sp_mul.c
+++ b/arch/mips/math-emu/sp_mul.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_scalb.c b/arch/mips/math-emu/sp_scalb.c
index 44ceb87ea944..dd76196984c8 100644
--- a/arch/mips/math-emu/sp_scalb.c
+++ b/arch/mips/math-emu/sp_scalb.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_simple.c b/arch/mips/math-emu/sp_simple.c
index 2fd53c920e99..ae4fcfafd853 100644
--- a/arch/mips/math-emu/sp_simple.c
+++ b/arch/mips/math-emu/sp_simple.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_sqrt.c b/arch/mips/math-emu/sp_sqrt.c
index 8a934b9f7eb8..fed20175f5fb 100644
--- a/arch/mips/math-emu/sp_sqrt.c
+++ b/arch/mips/math-emu/sp_sqrt.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_sub.c b/arch/mips/math-emu/sp_sub.c
index dbb802c1a086..886ed5bcfefb 100644
--- a/arch/mips/math-emu/sp_sub.c
+++ b/arch/mips/math-emu/sp_sub.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_tint.c b/arch/mips/math-emu/sp_tint.c
index 352dc3a5f1af..0fe9acc7716e 100644
--- a/arch/mips/math-emu/sp_tint.c
+++ b/arch/mips/math-emu/sp_tint.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/math-emu/sp_tlong.c b/arch/mips/math-emu/sp_tlong.c
index 92cd9c511a10..d0ca6e22be29 100644
--- a/arch/mips/math-emu/sp_tlong.c
+++ b/arch/mips/math-emu/sp_tlong.c
@@ -4,7 +4,6 @@
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
*
* ########################################################################
*
diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c
index 6a2b1bf9ef11..3634c7ea06ac 100644
--- a/arch/mips/mm/highmem.c
+++ b/arch/mips/mm/highmem.c
@@ -9,7 +9,7 @@ static pte_t *kmap_pte;
unsigned long highstart_pfn, highend_pfn;
-void *__kmap(struct page *page)
+void *kmap(struct page *page)
{
void *addr;
@@ -21,16 +21,16 @@ void *__kmap(struct page *page)
return addr;
}
-EXPORT_SYMBOL(__kmap);
+EXPORT_SYMBOL(kmap);
-void __kunmap(struct page *page)
+void kunmap(struct page *page)
{
BUG_ON(in_interrupt());
if (!PageHighMem(page))
return;
kunmap_high(page);
}
-EXPORT_SYMBOL(__kunmap);
+EXPORT_SYMBOL(kunmap);
/*
* kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because
@@ -41,17 +41,17 @@ EXPORT_SYMBOL(__kunmap);
* kmaps are appropriate for short, tight code paths only.
*/
-void *__kmap_atomic(struct page *page, enum km_type type)
+void *__kmap_atomic(struct page *page)
{
- enum fixed_addresses idx;
unsigned long vaddr;
+ int idx, type;
/* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
pagefault_disable();
if (!PageHighMem(page))
return page_address(page);
- debug_kmap_atomic(type);
+ type = kmap_atomic_idx_push();
idx = type + KM_TYPE_NR*smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
#ifdef CONFIG_DEBUG_HIGHMEM
@@ -64,43 +64,48 @@ void *__kmap_atomic(struct page *page, enum km_type type)
}
EXPORT_SYMBOL(__kmap_atomic);
-void __kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
{
-#ifdef CONFIG_DEBUG_HIGHMEM
unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
- enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
+ int type;
if (vaddr < FIXADDR_START) { // FIXME
pagefault_enable();
return;
}
- BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+ type = kmap_atomic_idx();
+#ifdef CONFIG_DEBUG_HIGHMEM
+ {
+ int idx = type + KM_TYPE_NR * smp_processor_id();
- /*
- * force other mappings to Oops if they'll try to access
- * this pte without first remap it
- */
- pte_clear(&init_mm, vaddr, kmap_pte-idx);
- local_flush_tlb_one(vaddr);
-#endif
+ BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+ /*
+ * force other mappings to Oops if they'll try to access
+ * this pte without first remap it
+ */
+ pte_clear(&init_mm, vaddr, kmap_pte-idx);
+ local_flush_tlb_one(vaddr);
+ }
+#endif
+ kmap_atomic_idx_pop();
pagefault_enable();
}
-EXPORT_SYMBOL(__kunmap_atomic_notypecheck);
+EXPORT_SYMBOL(__kunmap_atomic);
/*
* This is the same as kmap_atomic() but can map memory that doesn't
* have a struct page associated with it.
*/
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
+void *kmap_atomic_pfn(unsigned long pfn)
{
- enum fixed_addresses idx;
unsigned long vaddr;
+ int idx, type;
pagefault_disable();
- debug_kmap_atomic(type);
+ type = kmap_atomic_idx_push();
idx = type + KM_TYPE_NR*smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
set_pte(kmap_pte-idx, pfn_pte(pfn, PAGE_KERNEL));
@@ -109,7 +114,7 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
return (void*) vaddr;
}
-struct page *__kmap_atomic_to_page(void *ptr)
+struct page *kmap_atomic_to_page(void *ptr)
{
unsigned long idx, vaddr = (unsigned long)ptr;
pte_t *pte;
diff --git a/arch/mips/pci/fixup-fuloong2e.c b/arch/mips/pci/fixup-fuloong2e.c
index 4f6d8da07f93..d5d4c018fb04 100644
--- a/arch/mips/pci/fixup-fuloong2e.c
+++ b/arch/mips/pci/fixup-fuloong2e.c
@@ -52,7 +52,7 @@ static void __init loongson2e_nec_fixup(struct pci_dev *pdev)
{
unsigned int val;
- /* Configues port 1, 2, 3, 4 to be validate*/
+ /* Configures port 1, 2, 3, 4 to be validate*/
pci_read_config_dword(pdev, 0xe0, &val);
pci_write_config_dword(pdev, 0xe0, (val & ~7) | 0x4);
diff --git a/arch/mips/sibyte/common/sb_tbprof.c b/arch/mips/sibyte/common/sb_tbprof.c
index ca35b730d189..87ccdb4b5ac9 100644
--- a/arch/mips/sibyte/common/sb_tbprof.c
+++ b/arch/mips/sibyte/common/sb_tbprof.c
@@ -43,7 +43,7 @@
#include <asm/sibyte/sb1250_scd.h>
#include <asm/sibyte/sb1250_int.h>
#else
-#error invalid SiByte UART configuation
+#error invalid SiByte UART configuration
#endif
#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index 7c2a2f7f8dc1..365766a3d536 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -9,8 +9,19 @@ config MN10300
def_bool y
select HAVE_OPROFILE
-config AM33
- def_bool y
+config AM33_2
+ def_bool n
+
+config AM33_3
+ def_bool n
+
+config AM34_2
+ def_bool n
+ select MN10300_HAS_ATOMIC_OPS_UNIT
+ select MN10300_HAS_CACHE_SNOOP
+
+config ERRATUM_NEED_TO_RELOAD_MMUCTR
+ def_bool y if AM33_3 || AM34_2
config MMU
def_bool y
@@ -37,7 +48,7 @@ config GENERIC_CALIBRATE_DELAY
def_bool y
config GENERIC_CMOS_UPDATE
- def_bool y
+ def_bool n
config GENERIC_FIND_NEXT_BIT
def_bool y
@@ -45,6 +56,27 @@ config GENERIC_FIND_NEXT_BIT
config GENERIC_HWEIGHT
def_bool y
+config GENERIC_TIME
+ def_bool y
+
+config GENERIC_CLOCKEVENTS
+ def_bool y
+
+config GENERIC_CLOCKEVENTS_BUILD
+ def_bool y
+ depends on GENERIC_CLOCKEVENTS
+
+config GENERIC_CLOCKEVENTS_BROADCAST
+ bool
+
+config CEVT_MN10300
+ def_bool y
+ depends on GENERIC_CLOCKEVENTS
+
+config CSRC_MN10300
+ def_bool y
+ depends on GENERIC_TIME
+
config GENERIC_BUG
def_bool y
@@ -61,18 +93,14 @@ config GENERIC_HARDIRQS
config HOTPLUG_CPU
def_bool n
-config HZ
- int
- default 1000
-
-mainmenu "Matsushita MN10300/AM33 Kernel Configuration"
+mainmenu "Panasonic MN10300/AM33 Kernel Configuration"
source "init/Kconfig"
source "kernel/Kconfig.freezer"
-menu "Matsushita MN10300 system setup"
+menu "Panasonic MN10300 system setup"
choice
prompt "Unit type"
@@ -87,6 +115,10 @@ config MN10300_UNIT_ASB2303
config MN10300_UNIT_ASB2305
bool "ASB2305"
+config MN10300_UNIT_ASB2364
+ bool "ASB2364"
+ select SMSC911X_ARCH_HOOKS if SMSC911X
+
endchoice
choice
@@ -99,57 +131,51 @@ choice
config MN10300_PROC_MN103E010
bool "MN103E010"
depends on MN10300_UNIT_ASB2303 || MN10300_UNIT_ASB2305
+ select AM33_2
+ select MN10300_PROC_HAS_TTYSM0
+ select MN10300_PROC_HAS_TTYSM1
+ select MN10300_PROC_HAS_TTYSM2
+
+config MN10300_PROC_MN2WS0050
+ bool "MN2WS0050"
+ depends on MN10300_UNIT_ASB2364
+ select AM34_2
select MN10300_PROC_HAS_TTYSM0
select MN10300_PROC_HAS_TTYSM1
select MN10300_PROC_HAS_TTYSM2
endchoice
-choice
- prompt "Processor core support"
- default MN10300_CPU_AM33V2
+config MN10300_HAS_ATOMIC_OPS_UNIT
+ def_bool n
help
- This option specifies the processor core for which the kernel will be
- compiled. It affects the instruction set used.
-
-config MN10300_CPU_AM33V2
- bool "AM33v2"
-
-endchoice
+ This should be enabled if the processor has an atomic ops unit
+ capable of doing LL/SC equivalent operations.
config FPU
bool "FPU present"
default y
- depends on MN10300_PROC_MN103E010
+ depends on MN10300_PROC_MN103E010 || MN10300_PROC_MN2WS0050
-choice
- prompt "CPU Caching mode"
- default MN10300_CACHE_WBACK
+config LAZY_SAVE_FPU
+ bool "Save FPU state lazily"
+ default y
+ depends on FPU && !SMP
help
- This option determines the caching mode for the kernel.
-
- Write-Back caching mode involves the all reads and writes causing
- the affected cacheline to be read into the cache first before being
- operated upon. Memory is not then updated by a write until the cache
- is filled and a cacheline needs to be displaced from the cache to
- make room. Only at that point is it written back.
-
- Write-Through caching only fetches cachelines from memory on a
- read. Writes always get written directly to memory. If the affected
- cacheline is also in cache, it will be updated too.
-
- The final option is to turn of caching entirely.
+ Enable this to be lazy in the saving of the FPU state to the owning
+ task's thread struct. This is useful if most tasks on the system
+ don't use the FPU as only those tasks that use it will pass it
+ between them, and the state needn't be saved for a task that isn't
+ using it.
-config MN10300_CACHE_WBACK
- bool "Write-Back"
+ This can't be so easily used on SMP as the process that owns the FPU
+ state on a CPU may be currently running on another CPU, so for the
+ moment, it is disabled.
-config MN10300_CACHE_WTHRU
- bool "Write-Through"
+source "arch/mn10300/mm/Kconfig.cache"
-config MN10300_CACHE_DISABLED
- bool "Disabled"
-
-endchoice
+config MN10300_TLB_USE_PIDR
+ def_bool y
menu "Memory layout options"
@@ -170,24 +196,55 @@ config KERNEL_TEXT_ADDRESS
config KERNEL_ZIMAGE_BASE_ADDRESS
hex "Base address of compressed vmlinux image"
- default "0x90700000"
+ default "0x50700000"
+config BOOT_STACK_OFFSET
+ hex
+ default "0xF00" if SMP
+ default "0xFF0" if !SMP
+
+config BOOT_STACK_SIZE
+ hex
+ depends on SMP
+ default "0x100"
endmenu
-config PREEMPT
- bool "Preemptible Kernel"
- help
- This option reduces the latency of the kernel when reacting to
- real-time or interactive events by allowing a low priority process to
- be preempted even if it is in kernel mode executing a system call.
- This allows applications to run more reliably even when the system is
- under load.
+config SMP
+ bool "Symmetric multi-processing support"
+ default y
+ depends on MN10300_PROC_MN2WS0038 || MN10300_PROC_MN2WS0050
+ ---help---
+ This enables support for systems with more than one CPU. If you have
+ a system with only one CPU, like most personal computers, say N. If
+ you have a system with more than one CPU, say Y.
+
+ If you say N here, the kernel will run on single and multiprocessor
+ machines, but will use only one CPU of a multiprocessor machine. If
+ you say Y here, the kernel will run on many, but not all,
+ singleprocessor machines. On a singleprocessor machine, the kernel
+ will run faster if you say N here.
- Say Y here if you are building a kernel for a desktop, embedded
- or real-time system. Say N if you are unsure.
+ See also <file:Documentation/i386/IO-APIC.txt>,
+ <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
+ <http://www.tldp.org/docs.html#howto>.
+
+ If you don't know what to do here, say N.
+
+config NR_CPUS
+ int
+ depends on SMP
+ default "2"
+
+config USE_GENERIC_SMP_HELPERS
+ bool
+ depends on SMP
+ default y
+
+source "kernel/Kconfig.preempt"
config MN10300_CURRENT_IN_E2
bool "Hold current task address in E2 register"
+ depends on !SMP
default y
help
This option removes the E2/R2 register from the set available to gcc
@@ -209,12 +266,15 @@ config MN10300_USING_JTAG
suppresses the use of certain hardware debugging features, such as
single-stepping, which are taken over completely by the JTAG unit.
+source "kernel/Kconfig.hz"
+source "kernel/time/Kconfig"
+
config MN10300_RTC
bool "Using MN10300 RTC"
- depends on MN10300_PROC_MN103E010
+ depends on MN10300_PROC_MN103E010 || MN10300_PROC_MN2WS0050
+ select GENERIC_CMOS_UPDATE
default n
help
-
This option enables support for the RTC, thus enabling time to be
tracked, even when system is powered down. This is available on-chip
on the MN103E010.
@@ -306,14 +366,23 @@ config MN10300_TTYSM1
choice
prompt "Select the timer to supply the clock for SIF1"
- default MN10300_TTYSM0_TIMER9
+ default MN10300_TTYSM1_TIMER12 \
+ if !(AM33_2 || AM33_3)
+ default MN10300_TTYSM1_TIMER9 \
+ if AM33_2 || AM33_3
depends on MN10300_TTYSM1
+config MN10300_TTYSM1_TIMER12
+ bool "Use timer 12 (16-bit)"
+ depends on !(AM33_2 || AM33_3)
+
config MN10300_TTYSM1_TIMER9
bool "Use timer 9 (16-bit)"
+ depends on AM33_2 || AM33_3
config MN10300_TTYSM1_TIMER3
bool "Use timer 3 (8-bit)"
+ depends on AM33_2 || AM33_3
endchoice
@@ -328,17 +397,107 @@ config MN10300_TTYSM2
choice
prompt "Select the timer to supply the clock for SIF2"
- default MN10300_TTYSM0_TIMER10
+ default MN10300_TTYSM2_TIMER3 \
+ if !(AM33_2 || AM33_3)
+ default MN10300_TTYSM2_TIMER10 \
+ if AM33_2 || AM33_3
depends on MN10300_TTYSM2
+config MN10300_TTYSM2_TIMER9
+ bool "Use timer 9 (16-bit)"
+ depends on !(AM33_2 || AM33_3)
+
+config MN10300_TTYSM2_TIMER1
+ bool "Use timer 1 (8-bit)"
+ depends on !(AM33_2 || AM33_3)
+
+config MN10300_TTYSM2_TIMER3
+ bool "Use timer 3 (8-bit)"
+ depends on !(AM33_2 || AM33_3)
+
config MN10300_TTYSM2_TIMER10
bool "Use timer 10 (16-bit)"
+ depends on AM33_2 || AM33_3
endchoice
config MN10300_TTYSM2_CTS
bool "Enable the use of the CTS line /dev/ttySM2"
- depends on MN10300_TTYSM2
+ depends on MN10300_TTYSM2 && AM33_2
+
+endmenu
+
+menu "Interrupt request priority options"
+
+comment "[!] NOTE: A lower number/level indicates a higher priority (0 is highest, 6 is lowest)"
+
+comment "____Non-maskable interrupt levels____"
+comment "The following must be set to a higher priority than local_irq_disable() and on-chip serial"
+
+config GDBSTUB_IRQ_LEVEL
+ int "GDBSTUB interrupt priority"
+ depends on GDBSTUB
+ range 0 1 if LINUX_CLI_LEVEL = 2
+ range 0 2 if LINUX_CLI_LEVEL = 3
+ range 0 3 if LINUX_CLI_LEVEL = 4
+ range 0 4 if LINUX_CLI_LEVEL = 5
+ range 0 5 if LINUX_CLI_LEVEL = 6
+ default 0
+
+comment "The following must be set to a higher priority than local_irq_disable()"
+
+config MN10300_SERIAL_IRQ_LEVEL
+ int "MN10300 on-chip serial interrupt priority"
+ depends on MN10300_TTYSM
+ range 1 1 if LINUX_CLI_LEVEL = 2
+ range 1 2 if LINUX_CLI_LEVEL = 3
+ range 1 3 if LINUX_CLI_LEVEL = 4
+ range 1 4 if LINUX_CLI_LEVEL = 5
+ range 1 5 if LINUX_CLI_LEVEL = 6
+ default 1
+
+comment "-"
+comment "____Maskable interrupt levels____"
+
+config LINUX_CLI_LEVEL
+ int "The highest interrupt priority excluded by local_irq_disable() (2-6)"
+ range 2 6
+ default 2
+ help
+ local_irq_disable() doesn't actually disable maskable interrupts -
+ what it does is restrict the levels of interrupt which are permitted
+ (a lower level indicates a higher priority) by lowering the value in
+ EPSW.IM from 7. Any interrupt is permitted for which the level is
+ lower than EPSW.IM.
+
+ Certain interrupts, such as GDBSTUB and virtual MN10300 on-chip
+ serial DMA interrupts are allowed to interrupt normal disabled
+ sections.
+
+comment "The following must be set to a equal to or lower priority than LINUX_CLI_LEVEL"
+
+config TIMER_IRQ_LEVEL
+ int "Kernel timer interrupt priority"
+ range LINUX_CLI_LEVEL 6
+ default 4
+
+config PCI_IRQ_LEVEL
+ int "PCI interrupt priority"
+ depends on PCI
+ range LINUX_CLI_LEVEL 6
+ default 5
+
+config ETHERNET_IRQ_LEVEL
+ int "Ethernet interrupt priority"
+ depends on SMC91X || SMC911X || SMSC911X
+ range LINUX_CLI_LEVEL 6
+ default 6
+
+config EXT_SERIAL_IRQ_LEVEL
+ int "External serial port interrupt priority"
+ depends on SERIAL_8250
+ range LINUX_CLI_LEVEL 6
+ default 6
endmenu
diff --git a/arch/mn10300/Makefile b/arch/mn10300/Makefile
index ac5c6bdb2f05..7120282bf0d8 100644
--- a/arch/mn10300/Makefile
+++ b/arch/mn10300/Makefile
@@ -36,6 +36,9 @@ endif
ifeq ($(CONFIG_MN10300_PROC_MN103E010),y)
PROCESSOR := mn103e010
endif
+ifeq ($(CONFIG_MN10300_PROC_MN2WS0050),y)
+PROCESSOR := mn2ws0050
+endif
ifeq ($(CONFIG_MN10300_UNIT_ASB2303),y)
UNIT := asb2303
@@ -43,6 +46,9 @@ endif
ifeq ($(CONFIG_MN10300_UNIT_ASB2305),y)
UNIT := asb2305
endif
+ifeq ($(CONFIG_MN10300_UNIT_ASB2364),y)
+UNIT := asb2364
+endif
head-y := arch/mn10300/kernel/head.o arch/mn10300/kernel/init_task.o
diff --git a/arch/mn10300/boot/compressed/head.S b/arch/mn10300/boot/compressed/head.S
index 502e1eb56709..7b50345b9e84 100644
--- a/arch/mn10300/boot/compressed/head.S
+++ b/arch/mn10300/boot/compressed/head.S
@@ -14,10 +14,29 @@
#include <linux/linkage.h>
#include <asm/cpu-regs.h>
+#include <asm/cache.h>
+#ifdef CONFIG_SMP
+#include <proc/smp-regs.h>
+#endif
.globl startup_32
startup_32:
- # first save off parameters from bootloader
+#ifdef CONFIG_SMP
+ #
+ # Secondary CPUs jump directly to the kernel entry point
+ #
+ # Must save primary CPU's D0-D2 registers as they hold boot parameters
+ #
+ mov (CPUID), d3
+ and CPUID_MASK,d3
+ beq startup_primary
+ mov CONFIG_KERNEL_TEXT_ADDRESS,a0
+ jmp (a0)
+
+startup_primary:
+#endif /* CONFIG_SMP */
+
+ # first save parameters from bootloader
mov param_save_area,a0
mov d0,(a0)
mov d1,(4,a0)
@@ -37,8 +56,15 @@ startup_32:
mov (a0),d0
btst CHCTR_ICBUSY|CHCTR_DCBUSY,d0 # wait till not busy
lne
- mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD,d0 # writethru dcache
+
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+#ifdef CONFIG_MN10300_CACHE_WBACK
+ mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK,d0
+#else
+ mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRTHROUGH,d0
+#endif /* WBACK */
movhu d0,(a0) # enable
+#endif /* !ENABLED */
# clear the BSS area
mov __bss_start,a0
@@ -54,6 +80,9 @@ bssclear_end:
# decompress the kernel
call decompress_kernel[],0
+#ifdef CONFIG_MN10300_CACHE_WBACK
+ call mn10300_dcache_flush_inv[],0
+#endif
# disable caches again
mov CHCTR,a0
@@ -69,10 +98,46 @@ bssclear_end:
mov (4,a0),d1
mov (8,a0),d2
+ # jump to the kernel proper entry point
mov a3,sp
mov CONFIG_KERNEL_TEXT_ADDRESS,a0
jmp (a0)
+
+###############################################################################
+#
+# Cache flush routines
+#
+###############################################################################
+#ifdef CONFIG_MN10300_CACHE_WBACK
+mn10300_dcache_flush_inv:
+ movhu (CHCTR),d0
+ btst CHCTR_DCEN,d0
+ beq mn10300_dcache_flush_inv_end
+
+ mov L1_CACHE_NENTRIES,d1
+ clr a1
+
+mn10300_dcache_flush_inv_loop:
+ mov (DCACHE_PURGE_WAY0(0),a1),d0 # unconditional purge
+ mov (DCACHE_PURGE_WAY1(0),a1),d0 # unconditional purge
+ mov (DCACHE_PURGE_WAY2(0),a1),d0 # unconditional purge
+ mov (DCACHE_PURGE_WAY3(0),a1),d0 # unconditional purge
+
+ add L1_CACHE_BYTES,a1
+ add -1,d1
+ bne mn10300_dcache_flush_inv_loop
+
+mn10300_dcache_flush_inv_end:
+ ret [],0
+#endif /* CONFIG_MN10300_CACHE_WBACK */
+
+
+###############################################################################
+#
+# Data areas
+#
+###############################################################################
.data
.align 4
param_save_area:
diff --git a/arch/mn10300/configs/asb2303_defconfig b/arch/mn10300/configs/asb2303_defconfig
index d80dfcb2c902..3f749b69ca71 100644
--- a/arch/mn10300/configs/asb2303_defconfig
+++ b/arch/mn10300/configs/asb2303_defconfig
@@ -12,6 +12,8 @@ CONFIG_SLAB=y
CONFIG_PROFILING=y
# CONFIG_BLOCK is not set
CONFIG_PREEMPT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_MN10300_RTC=y
CONFIG_MN10300_TTYSM_CONSOLE=y
CONFIG_MN10300_TTYSM0=y
diff --git a/arch/mn10300/configs/asb2364_defconfig b/arch/mn10300/configs/asb2364_defconfig
new file mode 100644
index 000000000000..83ce2f27b12a
--- /dev/null
+++ b/arch/mn10300/configs/asb2364_defconfig
@@ -0,0 +1,98 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_NS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_RELAY=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLOCK is not set
+CONFIG_MN10300_UNIT_ASB2364=y
+CONFIG_PREEMPT=y
+# CONFIG_MN10300_USING_JTAG is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_MN10300_TTYSM_CONSOLE=y
+CONFIG_MN10300_TTYSM0=y
+CONFIG_MN10300_TTYSM0_TIMER2=y
+CONFIG_MN10300_TTYSM1=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_CFI_I4=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMSC911X=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_PROC_KCORE=y
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_JFFS2_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff --git a/arch/mn10300/include/asm/atomic.h b/arch/mn10300/include/asm/atomic.h
index f0cc1f84a72f..92d2f9298e38 100644
--- a/arch/mn10300/include/asm/atomic.h
+++ b/arch/mn10300/include/asm/atomic.h
@@ -1 +1,351 @@
+/* MN10300 Atomic counter operations
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef _ASM_ATOMIC_H
+#define _ASM_ATOMIC_H
+
+#include <asm/irqflags.h>
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_SMP
+#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+static inline
+unsigned long __xchg(volatile unsigned long *m, unsigned long val)
+{
+ unsigned long status;
+ unsigned long oldval;
+
+ asm volatile(
+ "1: mov %4,(_AAR,%3) \n"
+ " mov (_ADR,%3),%1 \n"
+ " mov %5,(_ADR,%3) \n"
+ " mov (_ADR,%3),%0 \n" /* flush */
+ " mov (_ASR,%3),%0 \n"
+ " or %0,%0 \n"
+ " bne 1b \n"
+ : "=&r"(status), "=&r"(oldval), "=m"(*m)
+ : "a"(ATOMIC_OPS_BASE_ADDR), "r"(m), "r"(val)
+ : "memory", "cc");
+
+ return oldval;
+}
+
+static inline unsigned long __cmpxchg(volatile unsigned long *m,
+ unsigned long old, unsigned long new)
+{
+ unsigned long status;
+ unsigned long oldval;
+
+ asm volatile(
+ "1: mov %4,(_AAR,%3) \n"
+ " mov (_ADR,%3),%1 \n"
+ " cmp %5,%1 \n"
+ " bne 2f \n"
+ " mov %6,(_ADR,%3) \n"
+ "2: mov (_ADR,%3),%0 \n" /* flush */
+ " mov (_ASR,%3),%0 \n"
+ " or %0,%0 \n"
+ " bne 1b \n"
+ : "=&r"(status), "=&r"(oldval), "=m"(*m)
+ : "a"(ATOMIC_OPS_BASE_ADDR), "r"(m),
+ "r"(old), "r"(new)
+ : "memory", "cc");
+
+ return oldval;
+}
+#else /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
+#error "No SMP atomic operation support!"
+#endif /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
+
+#else /* CONFIG_SMP */
+
+/*
+ * Emulate xchg for non-SMP MN10300
+ */
+struct __xchg_dummy { unsigned long a[100]; };
+#define __xg(x) ((struct __xchg_dummy *)(x))
+
+static inline
+unsigned long __xchg(volatile unsigned long *m, unsigned long val)
+{
+ unsigned long oldval;
+ unsigned long flags;
+
+ flags = arch_local_cli_save();
+ oldval = *m;
+ *m = val;
+ arch_local_irq_restore(flags);
+ return oldval;
+}
+
+/*
+ * Emulate cmpxchg for non-SMP MN10300
+ */
+static inline unsigned long __cmpxchg(volatile unsigned long *m,
+ unsigned long old, unsigned long new)
+{
+ unsigned long oldval;
+ unsigned long flags;
+
+ flags = arch_local_cli_save();
+ oldval = *m;
+ if (oldval == old)
+ *m = new;
+ arch_local_irq_restore(flags);
+ return oldval;
+}
+
+#endif /* CONFIG_SMP */
+
+#define xchg(ptr, v) \
+ ((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr), \
+ (unsigned long)(v)))
+
+#define cmpxchg(ptr, o, n) \
+ ((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \
+ (unsigned long)(o), \
+ (unsigned long)(n)))
+
+#define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v)))
+#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
+
+#endif /* !__ASSEMBLY__ */
+
+#ifndef CONFIG_SMP
#include <asm-generic/atomic.h>
+#else
+
+/*
+ * Atomic operations that C can't guarantee us. Useful for
+ * resource counting etc..
+ */
+
+#define ATOMIC_INIT(i) { (i) }
+
+#ifdef __KERNEL__
+
+/**
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically reads the value of @v. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_read(v) ((v)->counter)
+
+/**
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ *
+ * Atomically sets the value of @v to @i. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_set(v, i) (((v)->counter) = (i))
+
+/**
+ * atomic_add_return - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ *
+ * Atomically adds @i to @v and returns the result
+ * Note that the guaranteed useful range of an atomic_t is only 24 bits.
+ */
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+ int retval;
+#ifdef CONFIG_SMP
+ int status;
+
+ asm volatile(
+ "1: mov %4,(_AAR,%3) \n"
+ " mov (_ADR,%3),%1 \n"
+ " add %5,%1 \n"
+ " mov %1,(_ADR,%3) \n"
+ " mov (_ADR,%3),%0 \n" /* flush */
+ " mov (_ASR,%3),%0 \n"
+ " or %0,%0 \n"
+ " bne 1b \n"
+ : "=&r"(status), "=&r"(retval), "=m"(v->counter)
+ : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)
+ : "memory", "cc");
+
+#else
+ unsigned long flags;
+
+ flags = arch_local_cli_save();
+ retval = v->counter;
+ retval += i;
+ v->counter = retval;
+ arch_local_irq_restore(flags);
+#endif
+ return retval;
+}
+
+/**
+ * atomic_sub_return - subtract integer from atomic variable
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v and returns the result
+ * Note that the guaranteed useful range of an atomic_t is only 24 bits.
+ */
+static inline int atomic_sub_return(int i, atomic_t *v)
+{
+ int retval;
+#ifdef CONFIG_SMP
+ int status;
+
+ asm volatile(
+ "1: mov %4,(_AAR,%3) \n"
+ " mov (_ADR,%3),%1 \n"
+ " sub %5,%1 \n"
+ " mov %1,(_ADR,%3) \n"
+ " mov (_ADR,%3),%0 \n" /* flush */
+ " mov (_ASR,%3),%0 \n"
+ " or %0,%0 \n"
+ " bne 1b \n"
+ : "=&r"(status), "=&r"(retval), "=m"(v->counter)
+ : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)
+ : "memory", "cc");
+
+#else
+ unsigned long flags;
+ flags = arch_local_cli_save();
+ retval = v->counter;
+ retval -= i;
+ v->counter = retval;
+ arch_local_irq_restore(flags);
+#endif
+ return retval;
+}
+
+static inline int atomic_add_negative(int i, atomic_t *v)
+{
+ return atomic_add_return(i, v) < 0;
+}
+
+static inline void atomic_add(int i, atomic_t *v)
+{
+ atomic_add_return(i, v);
+}
+
+static inline void atomic_sub(int i, atomic_t *v)
+{
+ atomic_sub_return(i, v);
+}
+
+static inline void atomic_inc(atomic_t *v)
+{
+ atomic_add_return(1, v);
+}
+
+static inline void atomic_dec(atomic_t *v)
+{
+ atomic_sub_return(1, v);
+}
+
+#define atomic_dec_return(v) atomic_sub_return(1, (v))
+#define atomic_inc_return(v) atomic_add_return(1, (v))
+
+#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0)
+#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
+#define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0)
+
+#define atomic_add_unless(v, a, u) \
+({ \
+ int c, old; \
+ c = atomic_read(v); \
+ while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+ c = old; \
+ c != (u); \
+})
+
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
+/**
+ * atomic_clear_mask - Atomically clear bits in memory
+ * @mask: Mask of the bits to be cleared
+ * @v: pointer to word in memory
+ *
+ * Atomically clears the bits set in mask from the memory word specified.
+ */
+static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
+{
+#ifdef CONFIG_SMP
+ int status;
+
+ asm volatile(
+ "1: mov %3,(_AAR,%2) \n"
+ " mov (_ADR,%2),%0 \n"
+ " and %4,%0 \n"
+ " mov %0,(_ADR,%2) \n"
+ " mov (_ADR,%2),%0 \n" /* flush */
+ " mov (_ASR,%2),%0 \n"
+ " or %0,%0 \n"
+ " bne 1b \n"
+ : "=&r"(status), "=m"(*addr)
+ : "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(~mask)
+ : "memory", "cc");
+#else
+ unsigned long flags;
+
+ mask = ~mask;
+ flags = arch_local_cli_save();
+ *addr &= mask;
+ arch_local_irq_restore(flags);
+#endif
+}
+
+/**
+ * atomic_set_mask - Atomically set bits in memory
+ * @mask: Mask of the bits to be set
+ * @v: pointer to word in memory
+ *
+ * Atomically sets the bits set in mask from the memory word specified.
+ */
+static inline void atomic_set_mask(unsigned long mask, unsigned long *addr)
+{
+#ifdef CONFIG_SMP
+ int status;
+
+ asm volatile(
+ "1: mov %3,(_AAR,%2) \n"
+ " mov (_ADR,%2),%0 \n"
+ " or %4,%0 \n"
+ " mov %0,(_ADR,%2) \n"
+ " mov (_ADR,%2),%0 \n" /* flush */
+ " mov (_ASR,%2),%0 \n"
+ " or %0,%0 \n"
+ " bne 1b \n"
+ : "=&r"(status), "=m"(*addr)
+ : "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(mask)
+ : "memory", "cc");
+#else
+ unsigned long flags;
+
+ flags = arch_local_cli_save();
+ *addr |= mask;
+ arch_local_irq_restore(flags);
+#endif
+}
+
+/* Atomic operations are already serializing on MN10300??? */
+#define smp_mb__before_atomic_dec() barrier()
+#define smp_mb__after_atomic_dec() barrier()
+#define smp_mb__before_atomic_inc() barrier()
+#define smp_mb__after_atomic_inc() barrier()
+
+#include <asm-generic/atomic-long.h>
+
+#endif /* __KERNEL__ */
+#endif /* CONFIG_SMP */
+#endif /* _ASM_ATOMIC_H */
diff --git a/arch/mn10300/include/asm/bitops.h b/arch/mn10300/include/asm/bitops.h
index 3f50e9661076..3b8a868188f5 100644
--- a/arch/mn10300/include/asm/bitops.h
+++ b/arch/mn10300/include/asm/bitops.h
@@ -57,7 +57,7 @@
#define clear_bit(nr, addr) ___clear_bit((nr), (addr))
-static inline void __clear_bit(int nr, volatile void *addr)
+static inline void __clear_bit(unsigned long nr, volatile void *addr)
{
unsigned int *a = (unsigned int *) addr;
int mask;
@@ -70,15 +70,15 @@ static inline void __clear_bit(int nr, volatile void *addr)
/*
* test bit
*/
-static inline int test_bit(int nr, const volatile void *addr)
+static inline int test_bit(unsigned long nr, const volatile void *addr)
{
- return 1UL & (((const unsigned int *) addr)[nr >> 5] >> (nr & 31));
+ return 1UL & (((const volatile unsigned int *) addr)[nr >> 5] >> (nr & 31));
}
/*
* change bit
*/
-static inline void __change_bit(int nr, volatile void *addr)
+static inline void __change_bit(unsigned long nr, volatile void *addr)
{
int mask;
unsigned int *a = (unsigned int *) addr;
@@ -88,7 +88,7 @@ static inline void __change_bit(int nr, volatile void *addr)
*a ^= mask;
}
-extern void change_bit(int nr, volatile void *addr);
+extern void change_bit(unsigned long nr, volatile void *addr);
/*
* test and set bit
@@ -135,7 +135,7 @@ extern void change_bit(int nr, volatile void *addr);
/*
* test and change bit
*/
-static inline int __test_and_change_bit(int nr, volatile void *addr)
+static inline int __test_and_change_bit(unsigned long nr, volatile void *addr)
{
int mask, retval;
unsigned int *a = (unsigned int *)addr;
@@ -148,7 +148,7 @@ static inline int __test_and_change_bit(int nr, volatile void *addr)
return retval;
}
-extern int test_and_change_bit(int nr, volatile void *addr);
+extern int test_and_change_bit(unsigned long nr, volatile void *addr);
#include <asm-generic/bitops/lock.h>
diff --git a/arch/mn10300/include/asm/cache.h b/arch/mn10300/include/asm/cache.h
index 781bf613366d..f29cde2cfc91 100644
--- a/arch/mn10300/include/asm/cache.h
+++ b/arch/mn10300/include/asm/cache.h
@@ -43,14 +43,18 @@
/* instruction cache access registers */
#define ICACHE_DATA(WAY, ENTRY, OFF) \
- __SYSREG(0xc8000000 + (WAY) * L1_CACHE_WAYDISP + (ENTRY) * 0x10 + (OFF) * 4, u32)
+ __SYSREG(0xc8000000 + (WAY) * L1_CACHE_WAYDISP + \
+ (ENTRY) * L1_CACHE_BYTES + (OFF) * 4, u32)
#define ICACHE_TAG(WAY, ENTRY) \
- __SYSREG(0xc8100000 + (WAY) * L1_CACHE_WAYDISP + (ENTRY) * 0x10, u32)
+ __SYSREG(0xc8100000 + (WAY) * L1_CACHE_WAYDISP + \
+ (ENTRY) * L1_CACHE_BYTES, u32)
-/* instruction cache access registers */
+/* data cache access registers */
#define DCACHE_DATA(WAY, ENTRY, OFF) \
- __SYSREG(0xc8200000 + (WAY) * L1_CACHE_WAYDISP + (ENTRY) * 0x10 + (OFF) * 4, u32)
+ __SYSREG(0xc8200000 + (WAY) * L1_CACHE_WAYDISP + \
+ (ENTRY) * L1_CACHE_BYTES + (OFF) * 4, u32)
#define DCACHE_TAG(WAY, ENTRY) \
- __SYSREG(0xc8300000 + (WAY) * L1_CACHE_WAYDISP + (ENTRY) * 0x10, u32)
+ __SYSREG(0xc8300000 + (WAY) * L1_CACHE_WAYDISP + \
+ (ENTRY) * L1_CACHE_BYTES, u32)
#endif /* _ASM_CACHE_H */
diff --git a/arch/mn10300/include/asm/cacheflush.h b/arch/mn10300/include/asm/cacheflush.h
index 29e692f7f030..faed90240ded 100644
--- a/arch/mn10300/include/asm/cacheflush.h
+++ b/arch/mn10300/include/asm/cacheflush.h
@@ -17,66 +17,55 @@
#include <linux/mm.h>
/*
- * virtually-indexed cache management (our cache is physically indexed)
+ * Primitive routines
*/
-#define flush_cache_all() do {} while (0)
-#define flush_cache_mm(mm) do {} while (0)
-#define flush_cache_dup_mm(mm) do {} while (0)
-#define flush_cache_range(mm, start, end) do {} while (0)
-#define flush_cache_page(vma, vmaddr, pfn) do {} while (0)
-#define flush_cache_vmap(start, end) do {} while (0)
-#define flush_cache_vunmap(start, end) do {} while (0)
-#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
-#define flush_dcache_page(page) do {} while (0)
-#define flush_dcache_mmap_lock(mapping) do {} while (0)
-#define flush_dcache_mmap_unlock(mapping) do {} while (0)
-
-/*
- * physically-indexed cache management
- */
-#ifndef CONFIG_MN10300_CACHE_DISABLED
-
-extern void flush_icache_range(unsigned long start, unsigned long end);
-extern void flush_icache_page(struct vm_area_struct *vma, struct page *pg);
-
-#else
-
-#define flush_icache_range(start, end) do {} while (0)
-#define flush_icache_page(vma, pg) do {} while (0)
-
-#endif
-
-#define flush_icache_user_range(vma, pg, adr, len) \
- flush_icache_range(adr, adr + len)
-
-#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
- do { \
- memcpy(dst, src, len); \
- flush_icache_page(vma, page); \
- } while (0)
-
-#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
- memcpy(dst, src, len)
-
-/*
- * primitive routines
- */
-#ifndef CONFIG_MN10300_CACHE_DISABLED
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+extern void mn10300_local_icache_inv(void);
+extern void mn10300_local_icache_inv_page(unsigned long start);
+extern void mn10300_local_icache_inv_range(unsigned long start, unsigned long end);
+extern void mn10300_local_icache_inv_range2(unsigned long start, unsigned long size);
+extern void mn10300_local_dcache_inv(void);
+extern void mn10300_local_dcache_inv_page(unsigned long start);
+extern void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end);
+extern void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size);
extern void mn10300_icache_inv(void);
+extern void mn10300_icache_inv_page(unsigned long start);
+extern void mn10300_icache_inv_range(unsigned long start, unsigned long end);
+extern void mn10300_icache_inv_range2(unsigned long start, unsigned long size);
extern void mn10300_dcache_inv(void);
-extern void mn10300_dcache_inv_page(unsigned start);
-extern void mn10300_dcache_inv_range(unsigned start, unsigned end);
-extern void mn10300_dcache_inv_range2(unsigned start, unsigned size);
+extern void mn10300_dcache_inv_page(unsigned long start);
+extern void mn10300_dcache_inv_range(unsigned long start, unsigned long end);
+extern void mn10300_dcache_inv_range2(unsigned long start, unsigned long size);
#ifdef CONFIG_MN10300_CACHE_WBACK
+extern void mn10300_local_dcache_flush(void);
+extern void mn10300_local_dcache_flush_page(unsigned long start);
+extern void mn10300_local_dcache_flush_range(unsigned long start, unsigned long end);
+extern void mn10300_local_dcache_flush_range2(unsigned long start, unsigned long size);
+extern void mn10300_local_dcache_flush_inv(void);
+extern void mn10300_local_dcache_flush_inv_page(unsigned long start);
+extern void mn10300_local_dcache_flush_inv_range(unsigned long start, unsigned long end);
+extern void mn10300_local_dcache_flush_inv_range2(unsigned long start, unsigned long size);
extern void mn10300_dcache_flush(void);
-extern void mn10300_dcache_flush_page(unsigned start);
-extern void mn10300_dcache_flush_range(unsigned start, unsigned end);
-extern void mn10300_dcache_flush_range2(unsigned start, unsigned size);
+extern void mn10300_dcache_flush_page(unsigned long start);
+extern void mn10300_dcache_flush_range(unsigned long start, unsigned long end);
+extern void mn10300_dcache_flush_range2(unsigned long start, unsigned long size);
extern void mn10300_dcache_flush_inv(void);
-extern void mn10300_dcache_flush_inv_page(unsigned start);
-extern void mn10300_dcache_flush_inv_range(unsigned start, unsigned end);
-extern void mn10300_dcache_flush_inv_range2(unsigned start, unsigned size);
+extern void mn10300_dcache_flush_inv_page(unsigned long start);
+extern void mn10300_dcache_flush_inv_range(unsigned long start, unsigned long end);
+extern void mn10300_dcache_flush_inv_range2(unsigned long start, unsigned long size);
#else
+#define mn10300_local_dcache_flush() do {} while (0)
+#define mn10300_local_dcache_flush_page(start) do {} while (0)
+#define mn10300_local_dcache_flush_range(start, end) do {} while (0)
+#define mn10300_local_dcache_flush_range2(start, size) do {} while (0)
+#define mn10300_local_dcache_flush_inv() \
+ mn10300_local_dcache_inv()
+#define mn10300_local_dcache_flush_inv_page(start) \
+ mn10300_local_dcache_inv_page(start)
+#define mn10300_local_dcache_flush_inv_range(start, end) \
+ mn10300_local_dcache_inv_range(start, end)
+#define mn10300_local_dcache_flush_inv_range2(start, size) \
+ mn10300_local_dcache_inv_range2(start, size)
#define mn10300_dcache_flush() do {} while (0)
#define mn10300_dcache_flush_page(start) do {} while (0)
#define mn10300_dcache_flush_range(start, end) do {} while (0)
@@ -90,7 +79,26 @@ extern void mn10300_dcache_flush_inv_range2(unsigned start, unsigned size);
mn10300_dcache_inv_range2((start), (size))
#endif /* CONFIG_MN10300_CACHE_WBACK */
#else
+#define mn10300_local_icache_inv() do {} while (0)
+#define mn10300_local_icache_inv_page(start) do {} while (0)
+#define mn10300_local_icache_inv_range(start, end) do {} while (0)
+#define mn10300_local_icache_inv_range2(start, size) do {} while (0)
+#define mn10300_local_dcache_inv() do {} while (0)
+#define mn10300_local_dcache_inv_page(start) do {} while (0)
+#define mn10300_local_dcache_inv_range(start, end) do {} while (0)
+#define mn10300_local_dcache_inv_range2(start, size) do {} while (0)
+#define mn10300_local_dcache_flush() do {} while (0)
+#define mn10300_local_dcache_flush_inv_page(start) do {} while (0)
+#define mn10300_local_dcache_flush_inv() do {} while (0)
+#define mn10300_local_dcache_flush_inv_range(start, end)do {} while (0)
+#define mn10300_local_dcache_flush_inv_range2(start, size) do {} while (0)
+#define mn10300_local_dcache_flush_page(start) do {} while (0)
+#define mn10300_local_dcache_flush_range(start, end) do {} while (0)
+#define mn10300_local_dcache_flush_range2(start, size) do {} while (0)
#define mn10300_icache_inv() do {} while (0)
+#define mn10300_icache_inv_page(start) do {} while (0)
+#define mn10300_icache_inv_range(start, end) do {} while (0)
+#define mn10300_icache_inv_range2(start, size) do {} while (0)
#define mn10300_dcache_inv() do {} while (0)
#define mn10300_dcache_inv_page(start) do {} while (0)
#define mn10300_dcache_inv_range(start, end) do {} while (0)
@@ -103,10 +111,56 @@ extern void mn10300_dcache_flush_inv_range2(unsigned start, unsigned size);
#define mn10300_dcache_flush_page(start) do {} while (0)
#define mn10300_dcache_flush_range(start, end) do {} while (0)
#define mn10300_dcache_flush_range2(start, size) do {} while (0)
-#endif /* CONFIG_MN10300_CACHE_DISABLED */
+#endif /* CONFIG_MN10300_CACHE_ENABLED */
+
+/*
+ * Virtually-indexed cache management (our cache is physically indexed)
+ */
+#define flush_cache_all() do {} while (0)
+#define flush_cache_mm(mm) do {} while (0)
+#define flush_cache_dup_mm(mm) do {} while (0)
+#define flush_cache_range(mm, start, end) do {} while (0)
+#define flush_cache_page(vma, vmaddr, pfn) do {} while (0)
+#define flush_cache_vmap(start, end) do {} while (0)
+#define flush_cache_vunmap(start, end) do {} while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
+#define flush_dcache_page(page) do {} while (0)
+#define flush_dcache_mmap_lock(mapping) do {} while (0)
+#define flush_dcache_mmap_unlock(mapping) do {} while (0)
+
+/*
+ * Physically-indexed cache management
+ */
+#if defined(CONFIG_MN10300_CACHE_FLUSH_ICACHE)
+extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
+extern void flush_icache_range(unsigned long start, unsigned long end);
+#elif defined(CONFIG_MN10300_CACHE_INV_ICACHE)
+static inline void flush_icache_page(struct vm_area_struct *vma,
+ struct page *page)
+{
+ mn10300_icache_inv_page(page_to_phys(page));
+}
+extern void flush_icache_range(unsigned long start, unsigned long end);
+#else
+#define flush_icache_range(start, end) do {} while (0)
+#define flush_icache_page(vma, pg) do {} while (0)
+#endif
+
+
+#define flush_icache_user_range(vma, pg, adr, len) \
+ flush_icache_range(adr, adr + len)
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
+ do { \
+ memcpy(dst, src, len); \
+ flush_icache_page(vma, page); \
+ } while (0)
+
+#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
+ memcpy(dst, src, len)
/*
- * internal debugging function
+ * Internal debugging function
*/
#ifdef CONFIG_DEBUG_PAGEALLOC
extern void kernel_map_pages(struct page *page, int numpages, int enable);
diff --git a/arch/mn10300/include/asm/cpu-regs.h b/arch/mn10300/include/asm/cpu-regs.h
index 757e9b5388ea..90ed4a365c97 100644
--- a/arch/mn10300/include/asm/cpu-regs.h
+++ b/arch/mn10300/include/asm/cpu-regs.h
@@ -15,7 +15,6 @@
#include <linux/types.h>
#endif
-#ifdef CONFIG_MN10300_CPU_AM33V2
/* we tell the compiler to pretend to be AM33 so that it doesn't try and use
* the FP regs, but tell the assembler that we're actually allowed AM33v2
* instructions */
@@ -24,7 +23,6 @@ asm(" .am33_2\n");
#else
.am33_2
#endif
-#endif
#ifdef __KERNEL__
@@ -58,6 +56,9 @@ asm(" .am33_2\n");
#define EPSW_nAR 0x00040000 /* register bank control */
#define EPSW_ML 0x00080000 /* monitor level */
#define EPSW_FE 0x00100000 /* FPU enable */
+#define EPSW_IM_SHIFT 8 /* EPSW_IM_SHIFT determines the interrupt mode */
+
+#define NUM2EPSW_IM(num) ((num) << EPSW_IM_SHIFT)
/* FPU registers */
#define FPCR_EF_I 0x00000001 /* inexact result FPU exception flag */
@@ -99,9 +100,11 @@ asm(" .am33_2\n");
#define CPUREV __SYSREGC(0xc0000050, u32) /* CPU revision register */
#define CPUREV_TYPE 0x0000000f /* CPU type */
#define CPUREV_TYPE_S 0
-#define CPUREV_TYPE_AM33V1 0x00000000 /* - AM33 V1 core, AM33/1.00 arch */
-#define CPUREV_TYPE_AM33V2 0x00000001 /* - AM33 V2 core, AM33/2.00 arch */
-#define CPUREV_TYPE_AM34V1 0x00000002 /* - AM34 V1 core, AM33/2.00 arch */
+#define CPUREV_TYPE_AM33_1 0x00000000 /* - AM33-1 core, AM33/1.00 arch */
+#define CPUREV_TYPE_AM33_2 0x00000001 /* - AM33-2 core, AM33/2.00 arch */
+#define CPUREV_TYPE_AM34_1 0x00000002 /* - AM34-1 core, AM33/2.00 arch */
+#define CPUREV_TYPE_AM33_3 0x00000003 /* - AM33-3 core, AM33/2.00 arch */
+#define CPUREV_TYPE_AM34_2 0x00000004 /* - AM34-2 core, AM33/3.00 arch */
#define CPUREV_REVISION 0x000000f0 /* CPU revision */
#define CPUREV_REVISION_S 4
#define CPUREV_ICWAY 0x00000f00 /* number of instruction cache ways */
@@ -180,6 +183,21 @@ asm(" .am33_2\n");
#define CHCTR_ICWMD 0x0f00 /* instruction cache way mode */
#define CHCTR_DCWMD 0xf000 /* data cache way mode */
+#ifdef CONFIG_AM34_2
+#define ICIVCR __SYSREG(0xc0000c00, u32) /* icache area invalidate control */
+#define ICIVCR_ICIVBSY 0x00000008 /* icache area invalidate busy */
+#define ICIVCR_ICI 0x00000001 /* icache area invalidate */
+
+#define ICIVMR __SYSREG(0xc0000c04, u32) /* icache area invalidate mask */
+
+#define DCPGCR __SYSREG(0xc0000c10, u32) /* data cache area purge control */
+#define DCPGCR_DCPGBSY 0x00000008 /* data cache area purge busy */
+#define DCPGCR_DCP 0x00000002 /* data cache area purge */
+#define DCPGCR_DCI 0x00000001 /* data cache area invalidate */
+
+#define DCPGMR __SYSREG(0xc0000c14, u32) /* data cache area purge mask */
+#endif /* CONFIG_AM34_2 */
+
/* MMU control registers */
#define MMUCTR __SYSREG(0xc0000090, u32) /* MMU control register */
#define MMUCTR_IRP 0x0000003f /* instruction TLB replace pointer */
@@ -203,6 +221,9 @@ asm(" .am33_2\n");
#define MMUCTR_DTL_LOCK0_3 0x03000000 /* - entry 0-3 locked */
#define MMUCTR_DTL_LOCK0_7 0x04000000 /* - entry 0-7 locked */
#define MMUCTR_DTL_LOCK0_15 0x05000000 /* - entry 0-15 locked */
+#ifdef CONFIG_AM34_2
+#define MMUCTR_WTE 0x80000000 /* write-through cache TLB entry bit enable */
+#endif
#define PIDR __SYSREG(0xc0000094, u16) /* PID register */
#define PIDR_PID 0x00ff /* process identifier */
@@ -231,14 +252,6 @@ asm(" .am33_2\n");
#define xPTEL_PS_4Mb 0x00000c00 /* - 4Mb page */
#define xPTEL_PPN 0xfffff006 /* physical page number */
-#define xPTEL_V_BIT 0 /* bit numbers corresponding to above masks */
-#define xPTEL_UNUSED1_BIT 1
-#define xPTEL_UNUSED2_BIT 2
-#define xPTEL_C_BIT 3
-#define xPTEL_PV_BIT 4
-#define xPTEL_D_BIT 5
-#define xPTEL_G_BIT 9
-
#define IPTEU __SYSREG(0xc00000a4, u32) /* instruction TLB virtual addr */
#define DPTEU __SYSREG(0xc00000b4, u32) /* data TLB virtual addr */
#define xPTEU_VPN 0xfffffc00 /* virtual page number */
@@ -262,7 +275,16 @@ asm(" .am33_2\n");
#define xPTEL2_PS_128Kb 0x00000100 /* - 128Kb page */
#define xPTEL2_PS_1Kb 0x00000200 /* - 1Kb page */
#define xPTEL2_PS_4Mb 0x00000300 /* - 4Mb page */
-#define xPTEL2_PPN 0xfffffc00 /* physical page number */
+#define xPTEL2_CWT 0x00000400 /* cacheable write-through */
+#define xPTEL2_UNUSED1 0x00000800 /* unused bit (broadcast mask) */
+#define xPTEL2_PPN 0xfffff000 /* physical page number */
+
+#define xPTEL2_V_BIT 0 /* bit numbers corresponding to above masks */
+#define xPTEL2_C_BIT 1
+#define xPTEL2_PV_BIT 2
+#define xPTEL2_D_BIT 3
+#define xPTEL2_G_BIT 7
+#define xPTEL2_UNUSED1_BIT 11
#define MMUFCR __SYSREGC(0xc000009c, u32) /* MMU exception cause */
#define MMUFCR_IFC __SYSREGC(0xc000009c, u16) /* MMU instruction excep cause */
@@ -285,6 +307,47 @@ asm(" .am33_2\n");
#define MMUFCR_xFC_PR_RWK_RWU 0x01c0 /* - R/W kernel and R/W user */
#define MMUFCR_xFC_ILLADDR 0x0200 /* illegal address excep flag */
+#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+/* atomic operation registers */
+#define AAR __SYSREG(0xc0000a00, u32) /* cacheable address */
+#define AAR2 __SYSREG(0xc0000a04, u32) /* uncacheable address */
+#define ADR __SYSREG(0xc0000a08, u32) /* data */
+#define ASR __SYSREG(0xc0000a0c, u32) /* status */
+#define AARU __SYSREG(0xd400aa00, u32) /* user address */
+#define ADRU __SYSREG(0xd400aa08, u32) /* user data */
+#define ASRU __SYSREG(0xd400aa0c, u32) /* user status */
+
+#define ASR_RW 0x00000008 /* read */
+#define ASR_BW 0x00000004 /* bus error */
+#define ASR_IW 0x00000002 /* interrupt */
+#define ASR_LW 0x00000001 /* bus lock */
+
+#define ASRU_RW ASR_RW /* read */
+#define ASRU_BW ASR_BW /* bus error */
+#define ASRU_IW ASR_IW /* interrupt */
+#define ASRU_LW ASR_LW /* bus lock */
+
+/* in inline ASM, we stick the base pointer in to a reg and use offsets from
+ * it */
+#define ATOMIC_OPS_BASE_ADDR 0xc0000a00
+#ifndef __ASSEMBLY__
+asm(
+ "_AAR = 0\n"
+ "_AAR2 = 4\n"
+ "_ADR = 8\n"
+ "_ASR = 12\n");
+#else
+#define _AAR 0
+#define _AAR2 4
+#define _ADR 8
+#define _ASR 12
+#endif
+
+/* physical page address for userspace atomic operations registers */
+#define USER_ATOMIC_OPS_PAGE_ADDR 0xd400a000
+
+#endif /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
+
#endif /* __KERNEL__ */
#endif /* _ASM_CPU_REGS_H */
diff --git a/arch/mn10300/include/asm/dmactl-regs.h b/arch/mn10300/include/asm/dmactl-regs.h
index 58a199da0f4a..80337b339c90 100644
--- a/arch/mn10300/include/asm/dmactl-regs.h
+++ b/arch/mn10300/include/asm/dmactl-regs.h
@@ -11,91 +11,6 @@
#ifndef _ASM_DMACTL_REGS_H
#define _ASM_DMACTL_REGS_H
-#include <asm/cpu-regs.h>
-
-#ifdef __KERNEL__
-
-/* DMA registers */
-#define DMxCTR(N) __SYSREG(0xd2000000 + ((N) * 0x100), u32) /* control reg */
-#define DMxCTR_BG 0x0000001f /* transfer request source */
-#define DMxCTR_BG_SOFT 0x00000000 /* - software source */
-#define DMxCTR_BG_SC0TX 0x00000002 /* - serial port 0 transmission */
-#define DMxCTR_BG_SC0RX 0x00000003 /* - serial port 0 reception */
-#define DMxCTR_BG_SC1TX 0x00000004 /* - serial port 1 transmission */
-#define DMxCTR_BG_SC1RX 0x00000005 /* - serial port 1 reception */
-#define DMxCTR_BG_SC2TX 0x00000006 /* - serial port 2 transmission */
-#define DMxCTR_BG_SC2RX 0x00000007 /* - serial port 2 reception */
-#define DMxCTR_BG_TM0UFLOW 0x00000008 /* - timer 0 underflow */
-#define DMxCTR_BG_TM1UFLOW 0x00000009 /* - timer 1 underflow */
-#define DMxCTR_BG_TM2UFLOW 0x0000000a /* - timer 2 underflow */
-#define DMxCTR_BG_TM3UFLOW 0x0000000b /* - timer 3 underflow */
-#define DMxCTR_BG_TM6ACMPCAP 0x0000000c /* - timer 6A compare/capture */
-#define DMxCTR_BG_AFE 0x0000000d /* - analogue front-end interrupt source */
-#define DMxCTR_BG_ADC 0x0000000e /* - A/D conversion end interrupt source */
-#define DMxCTR_BG_IRDA 0x0000000f /* - IrDA interrupt source */
-#define DMxCTR_BG_RTC 0x00000010 /* - RTC interrupt source */
-#define DMxCTR_BG_XIRQ0 0x00000011 /* - XIRQ0 pin interrupt source */
-#define DMxCTR_BG_XIRQ1 0x00000012 /* - XIRQ1 pin interrupt source */
-#define DMxCTR_BG_XDMR0 0x00000013 /* - external request 0 source (XDMR0 pin) */
-#define DMxCTR_BG_XDMR1 0x00000014 /* - external request 1 source (XDMR1 pin) */
-#define DMxCTR_SAM 0x000000e0 /* DMA transfer src addr mode */
-#define DMxCTR_SAM_INCR 0x00000000 /* - increment */
-#define DMxCTR_SAM_DECR 0x00000020 /* - decrement */
-#define DMxCTR_SAM_FIXED 0x00000040 /* - fixed */
-#define DMxCTR_DAM 0x00000000 /* DMA transfer dest addr mode */
-#define DMxCTR_DAM_INCR 0x00000000 /* - increment */
-#define DMxCTR_DAM_DECR 0x00000100 /* - decrement */
-#define DMxCTR_DAM_FIXED 0x00000200 /* - fixed */
-#define DMxCTR_TM 0x00001800 /* DMA transfer mode */
-#define DMxCTR_TM_BATCH 0x00000000 /* - batch transfer */
-#define DMxCTR_TM_INTERM 0x00001000 /* - intermittent transfer */
-#define DMxCTR_UT 0x00006000 /* DMA transfer unit */
-#define DMxCTR_UT_1 0x00000000 /* - 1 byte */
-#define DMxCTR_UT_2 0x00002000 /* - 2 byte */
-#define DMxCTR_UT_4 0x00004000 /* - 4 byte */
-#define DMxCTR_UT_16 0x00006000 /* - 16 byte */
-#define DMxCTR_TEN 0x00010000 /* DMA channel transfer enable */
-#define DMxCTR_RQM 0x00060000 /* external request input source mode */
-#define DMxCTR_RQM_FALLEDGE 0x00000000 /* - falling edge */
-#define DMxCTR_RQM_RISEEDGE 0x00020000 /* - rising edge */
-#define DMxCTR_RQM_LOLEVEL 0x00040000 /* - low level */
-#define DMxCTR_RQM_HILEVEL 0x00060000 /* - high level */
-#define DMxCTR_RQF 0x01000000 /* DMA transfer request flag */
-#define DMxCTR_XEND 0x80000000 /* DMA transfer end flag */
-
-#define DMxSRC(N) __SYSREG(0xd2000004 + ((N) * 0x100), u32) /* control reg */
-
-#define DMxDST(N) __SYSREG(0xd2000008 + ((N) * 0x100), u32) /* src addr reg */
-
-#define DMxSIZ(N) __SYSREG(0xd200000c + ((N) * 0x100), u32) /* dest addr reg */
-#define DMxSIZ_CT 0x000fffff /* number of bytes to transfer */
-
-#define DMxCYC(N) __SYSREG(0xd2000010 + ((N) * 0x100), u32) /* intermittent
- * size reg */
-#define DMxCYC_CYC 0x000000ff /* number of interrmittent transfers -1 */
-
-#define DM0IRQ 16 /* DMA channel 0 complete IRQ */
-#define DM1IRQ 17 /* DMA channel 1 complete IRQ */
-#define DM2IRQ 18 /* DMA channel 2 complete IRQ */
-#define DM3IRQ 19 /* DMA channel 3 complete IRQ */
-
-#define DM0ICR GxICR(DM0IRQ) /* DMA channel 0 complete intr ctrl reg */
-#define DM1ICR GxICR(DM0IR1) /* DMA channel 1 complete intr ctrl reg */
-#define DM2ICR GxICR(DM0IR2) /* DMA channel 2 complete intr ctrl reg */
-#define DM3ICR GxICR(DM0IR3) /* DMA channel 3 complete intr ctrl reg */
-
-#ifndef __ASSEMBLY__
-
-struct mn10300_dmactl_regs {
- u32 ctr;
- const void *src;
- void *dst;
- u32 siz;
- u32 cyc;
-} __attribute__((aligned(0x100)));
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* __KERNEL__ */
+#include <proc/dmactl-regs.h>
#endif /* _ASM_DMACTL_REGS_H */
diff --git a/arch/mn10300/include/asm/elf.h b/arch/mn10300/include/asm/elf.h
index e5fa97cd9a14..8157c9267f42 100644
--- a/arch/mn10300/include/asm/elf.h
+++ b/arch/mn10300/include/asm/elf.h
@@ -32,6 +32,12 @@
#define R_MN10300_ALIGN 34 /* Alignment requirement. */
/*
+ * AM33/AM34 HW Capabilities
+ */
+#define HWCAP_MN10300_ATOMIC_OP_UNIT 1 /* Has AM34 Atomic Operations */
+
+
+/*
* ELF register definitions..
*/
typedef unsigned long elf_greg_t;
@@ -47,8 +53,6 @@ typedef struct {
u_int32_t fpcr;
} elf_fpregset_t;
-extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-
/*
* This is used to ensure we don't load something for the wrong architecture
*/
@@ -130,7 +134,11 @@ do { \
* instruction set this CPU supports. This could be done in user space,
* but it's not easy, and we've already done it here.
*/
+#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+#define ELF_HWCAP (HWCAP_MN10300_ATOMIC_OP_UNIT)
+#else
#define ELF_HWCAP (0)
+#endif
/*
* This yields a string that ld.so will use to load implementation
diff --git a/arch/mn10300/include/asm/exceptions.h b/arch/mn10300/include/asm/exceptions.h
index fa16466ef3f9..ca3e20508c77 100644
--- a/arch/mn10300/include/asm/exceptions.h
+++ b/arch/mn10300/include/asm/exceptions.h
@@ -15,8 +15,8 @@
/*
* define the breakpoint instruction opcode to use
- * - note that the JTAG unit steals 0xFF, so we want to avoid that if we can
- * (can use 0xF7)
+ * - note that the JTAG unit steals 0xFF, so you can't use JTAG and GDBSTUB at
+ * the same time.
*/
#define GDBSTUB_BKPT 0xFF
@@ -90,7 +90,6 @@ enum exception_code {
extern void __set_intr_stub(enum exception_code code, void *handler);
extern void set_intr_stub(enum exception_code code, void *handler);
-extern void set_jtag_stub(enum exception_code code, void *handler);
struct pt_regs;
@@ -102,7 +101,6 @@ extern asmlinkage void dtlb_aerror(void);
extern asmlinkage void raw_bus_error(void);
extern asmlinkage void double_fault(void);
extern asmlinkage int system_call(struct pt_regs *);
-extern asmlinkage void fpu_exception(struct pt_regs *, enum exception_code);
extern asmlinkage void nmi(struct pt_regs *, enum exception_code);
extern asmlinkage void uninitialised_exception(struct pt_regs *,
enum exception_code);
@@ -116,6 +114,8 @@ extern void die(const char *, struct pt_regs *, enum exception_code)
extern int die_if_no_fixup(const char *, struct pt_regs *, enum exception_code);
+#define NUM2EXCEP_IRQ_LEVEL(num) (EXCEP_IRQ_LEVEL0 + (num) * 8)
+
#endif /* __ASSEMBLY__ */
#endif /* _ASM_EXCEPTIONS_H */
diff --git a/arch/mn10300/include/asm/fpu.h b/arch/mn10300/include/asm/fpu.h
index 64a2b83a7a6a..b7625de8eade 100644
--- a/arch/mn10300/include/asm/fpu.h
+++ b/arch/mn10300/include/asm/fpu.h
@@ -12,74 +12,125 @@
#ifndef _ASM_FPU_H
#define _ASM_FPU_H
-#include <asm/processor.h>
+#ifndef __ASSEMBLY__
+
+#include <linux/sched.h>
+#include <asm/exceptions.h>
#include <asm/sigcontext.h>
-#include <asm/user.h>
#ifdef __KERNEL__
-/* the task that owns the FPU state */
+extern asmlinkage void fpu_disabled(void);
+
+#ifdef CONFIG_FPU
+
+#ifdef CONFIG_LAZY_SAVE_FPU
+/* the task that currently owns the FPU state */
extern struct task_struct *fpu_state_owner;
+#endif
-#define set_using_fpu(tsk) \
-do { \
- (tsk)->thread.fpu_flags |= THREAD_USING_FPU; \
-} while (0)
+#if (THREAD_USING_FPU & ~0xff)
+#error THREAD_USING_FPU must be smaller than 0x100.
+#endif
-#define clear_using_fpu(tsk) \
-do { \
- (tsk)->thread.fpu_flags &= ~THREAD_USING_FPU; \
-} while (0)
+static inline void set_using_fpu(struct task_struct *tsk)
+{
+ asm volatile(
+ "bset %0,(0,%1)"
+ :
+ : "i"(THREAD_USING_FPU), "a"(&tsk->thread.fpu_flags)
+ : "memory", "cc");
+}
-#define is_using_fpu(tsk) ((tsk)->thread.fpu_flags & THREAD_USING_FPU)
+static inline void clear_using_fpu(struct task_struct *tsk)
+{
+ asm volatile(
+ "bclr %0,(0,%1)"
+ :
+ : "i"(THREAD_USING_FPU), "a"(&tsk->thread.fpu_flags)
+ : "memory", "cc");
+}
-#define unlazy_fpu(tsk) \
-do { \
- preempt_disable(); \
- if (fpu_state_owner == (tsk)) \
- fpu_save(&tsk->thread.fpu_state); \
- preempt_enable(); \
-} while (0)
-
-#define exit_fpu() \
-do { \
- struct task_struct *__tsk = current; \
- preempt_disable(); \
- if (fpu_state_owner == __tsk) \
- fpu_state_owner = NULL; \
- preempt_enable(); \
-} while (0)
-
-#define flush_fpu() \
-do { \
- struct task_struct *__tsk = current; \
- preempt_disable(); \
- if (fpu_state_owner == __tsk) { \
- fpu_state_owner = NULL; \
- __tsk->thread.uregs->epsw &= ~EPSW_FE; \
- } \
- preempt_enable(); \
- clear_using_fpu(__tsk); \
-} while (0)
+#define is_using_fpu(tsk) ((tsk)->thread.fpu_flags & THREAD_USING_FPU)
-extern asmlinkage void fpu_init_state(void);
extern asmlinkage void fpu_kill_state(struct task_struct *);
-extern asmlinkage void fpu_disabled(struct pt_regs *, enum exception_code);
extern asmlinkage void fpu_exception(struct pt_regs *, enum exception_code);
-
-#ifdef CONFIG_FPU
+extern asmlinkage void fpu_invalid_op(struct pt_regs *, enum exception_code);
+extern asmlinkage void fpu_init_state(void);
extern asmlinkage void fpu_save(struct fpu_state_struct *);
-extern asmlinkage void fpu_restore(struct fpu_state_struct *);
-#else
-#define fpu_save(a)
-#define fpu_restore(a)
-#endif /* CONFIG_FPU */
-
-/*
- * signal frame handlers
- */
extern int fpu_setup_sigcontext(struct fpucontext *buf);
extern int fpu_restore_sigcontext(struct fpucontext *buf);
+static inline void unlazy_fpu(struct task_struct *tsk)
+{
+ preempt_disable();
+#ifndef CONFIG_LAZY_SAVE_FPU
+ if (tsk->thread.fpu_flags & THREAD_HAS_FPU) {
+ fpu_save(&tsk->thread.fpu_state);
+ tsk->thread.fpu_flags &= ~THREAD_HAS_FPU;
+ tsk->thread.uregs->epsw &= ~EPSW_FE;
+ }
+#else
+ if (fpu_state_owner == tsk)
+ fpu_save(&tsk->thread.fpu_state);
+#endif
+ preempt_enable();
+}
+
+static inline void exit_fpu(void)
+{
+#ifdef CONFIG_LAZY_SAVE_FPU
+ struct task_struct *tsk = current;
+
+ preempt_disable();
+ if (fpu_state_owner == tsk)
+ fpu_state_owner = NULL;
+ preempt_enable();
+#endif
+}
+
+static inline void flush_fpu(void)
+{
+ struct task_struct *tsk = current;
+
+ preempt_disable();
+#ifndef CONFIG_LAZY_SAVE_FPU
+ if (tsk->thread.fpu_flags & THREAD_HAS_FPU) {
+ tsk->thread.fpu_flags &= ~THREAD_HAS_FPU;
+ tsk->thread.uregs->epsw &= ~EPSW_FE;
+ }
+#else
+ if (fpu_state_owner == tsk) {
+ fpu_state_owner = NULL;
+ tsk->thread.uregs->epsw &= ~EPSW_FE;
+ }
+#endif
+ preempt_enable();
+ clear_using_fpu(tsk);
+}
+
+#else /* CONFIG_FPU */
+
+extern asmlinkage
+void unexpected_fpu_exception(struct pt_regs *, enum exception_code);
+#define fpu_invalid_op unexpected_fpu_exception
+#define fpu_exception unexpected_fpu_exception
+
+struct task_struct;
+struct fpu_state_struct;
+static inline bool is_using_fpu(struct task_struct *tsk) { return false; }
+static inline void set_using_fpu(struct task_struct *tsk) {}
+static inline void clear_using_fpu(struct task_struct *tsk) {}
+static inline void fpu_init_state(void) {}
+static inline void fpu_save(struct fpu_state_struct *s) {}
+static inline void fpu_kill_state(struct task_struct *tsk) {}
+static inline void unlazy_fpu(struct task_struct *tsk) {}
+static inline void exit_fpu(void) {}
+static inline void flush_fpu(void) {}
+static inline int fpu_setup_sigcontext(struct fpucontext *buf) { return 0; }
+static inline int fpu_restore_sigcontext(struct fpucontext *buf) { return 0; }
+#endif /* CONFIG_FPU */
+
#endif /* __KERNEL__ */
+#endif /* !__ASSEMBLY__ */
#endif /* _ASM_FPU_H */
diff --git a/arch/mn10300/include/asm/frame.inc b/arch/mn10300/include/asm/frame.inc
index 5b1949bdf039..2ee58e3eb6b3 100644
--- a/arch/mn10300/include/asm/frame.inc
+++ b/arch/mn10300/include/asm/frame.inc
@@ -18,6 +18,7 @@
#ifndef __ASM_OFFSETS_H__
#include <asm/asm-offsets.h>
#endif
+#include <asm/thread_info.h>
#define pi break
@@ -37,11 +38,15 @@
movm [d2,d3,a2,a3,exreg0,exreg1,exother],(sp)
mov sp,fp # FRAME pointer in A3
add -12,sp # allow for calls to be made
- mov (__frame),a1
- mov a1,(REG_NEXT,fp)
- mov fp,(__frame)
- and ~EPSW_FE,epsw # disable the FPU inside the kernel
+ # push the exception frame onto the front of the list
+ GET_THREAD_INFO a1
+ mov (TI_frame,a1),a0
+ mov a0,(REG_NEXT,fp)
+ mov fp,(TI_frame,a1)
+
+ # disable the FPU inside the kernel
+ and ~EPSW_FE,epsw
# we may be holding current in E2
#ifdef CONFIG_MN10300_CURRENT_IN_E2
@@ -57,10 +62,11 @@
.macro RESTORE_ALL
# peel back the stack to the calling frame
# - this permits execve() to discard extra frames due to kernel syscalls
- mov (__frame),fp
+ GET_THREAD_INFO a0
+ mov (TI_frame,a0),fp
mov fp,sp
- mov (REG_NEXT,fp),d0 # userspace has regs->next == 0
- mov d0,(__frame)
+ mov (REG_NEXT,fp),d0
+ mov d0,(TI_frame,a0) # userspace has regs->next == 0
#ifndef CONFIG_MN10300_USING_JTAG
mov (REG_EPSW,fp),d0
diff --git a/arch/mn10300/include/asm/gdb-stub.h b/arch/mn10300/include/asm/gdb-stub.h
index 41ed26763964..f5495ad82b77 100644
--- a/arch/mn10300/include/asm/gdb-stub.h
+++ b/arch/mn10300/include/asm/gdb-stub.h
@@ -110,7 +110,7 @@ extern asmlinkage void gdbstub_exception(struct pt_regs *, enum exception_code);
extern asmlinkage void __gdbstub_bug_trap(void);
extern asmlinkage void __gdbstub_pause(void);
-#ifndef CONFIG_MN10300_CACHE_DISABLED
+#ifdef CONFIG_MN10300_CACHE_ENABLED
extern asmlinkage void gdbstub_purge_cache(void);
#else
#define gdbstub_purge_cache() do {} while (0)
diff --git a/arch/mn10300/include/asm/hardirq.h b/arch/mn10300/include/asm/hardirq.h
index 54d950117674..0000d650b55f 100644
--- a/arch/mn10300/include/asm/hardirq.h
+++ b/arch/mn10300/include/asm/hardirq.h
@@ -19,9 +19,10 @@
/* assembly code in softirq.h is sensitive to the offsets of these fields */
typedef struct {
unsigned int __softirq_pending;
- unsigned long idle_timestamp;
+#ifdef CONFIG_MN10300_WD_TIMER
unsigned int __nmi_count; /* arch dependent */
unsigned int __irq_count; /* arch dependent */
+#endif
} ____cacheline_aligned irq_cpustat_t;
#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
diff --git a/arch/mn10300/include/asm/highmem.h b/arch/mn10300/include/asm/highmem.h
index b0b187a29b88..bfe2d88604d9 100644
--- a/arch/mn10300/include/asm/highmem.h
+++ b/arch/mn10300/include/asm/highmem.h
@@ -70,15 +70,16 @@ static inline void kunmap(struct page *page)
* be used in IRQ contexts, so in some (very limited) cases we need
* it.
*/
-static inline unsigned long kmap_atomic(struct page *page, enum km_type type)
+static inline unsigned long __kmap_atomic(struct page *page)
{
- enum fixed_addresses idx;
unsigned long vaddr;
+ int idx, type;
+ pagefault_disable();
if (page < highmem_start_page)
return page_address(page);
- debug_kmap_atomic(type);
+ type = kmap_atomic_idx_push();
idx = type + KM_TYPE_NR * smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
#if HIGHMEM_DEBUG
@@ -86,31 +87,42 @@ static inline unsigned long kmap_atomic(struct page *page, enum km_type type)
BUG();
#endif
set_pte(kmap_pte - idx, mk_pte(page, kmap_prot));
- __flush_tlb_one(vaddr);
+ local_flush_tlb_one(vaddr);
return vaddr;
}
-static inline void kunmap_atomic_notypecheck(unsigned long vaddr, enum km_type type)
+static inline void __kunmap_atomic(unsigned long vaddr)
{
-#if HIGHMEM_DEBUG
- enum fixed_addresses idx = type + KM_TYPE_NR * smp_processor_id();
+ int type;
- if (vaddr < FIXADDR_START) /* FIXME */
+ if (vaddr < FIXADDR_START) { /* FIXME */
+ pagefault_enable();
return;
+ }
- if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx))
- BUG();
+ type = kmap_atomic_idx();
- /*
- * force other mappings to Oops if they'll try to access
- * this pte without first remap it
- */
- pte_clear(kmap_pte - idx);
- __flush_tlb_one(vaddr);
+#if HIGHMEM_DEBUG
+ {
+ unsigned int idx;
+ idx = type + KM_TYPE_NR * smp_processor_id();
+
+ if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx))
+ BUG();
+
+ /*
+ * force other mappings to Oops if they'll try to access
+ * this pte without first remap it
+ */
+ pte_clear(kmap_pte - idx);
+ local_flush_tlb_one(vaddr);
+ }
#endif
-}
+ kmap_atomic_idx_pop();
+ pagefault_enable();
+}
#endif /* __KERNEL__ */
#endif /* _ASM_HIGHMEM_H */
diff --git a/arch/mn10300/include/asm/intctl-regs.h b/arch/mn10300/include/asm/intctl-regs.h
index ba544c796c5a..585b708c2bc0 100644
--- a/arch/mn10300/include/asm/intctl-regs.h
+++ b/arch/mn10300/include/asm/intctl-regs.h
@@ -15,24 +15,19 @@
#ifdef __KERNEL__
-/* interrupt controller registers */
-#define GxICR(X) __SYSREG(0xd4000000 + (X) * 4, u16) /* group irq ctrl regs */
-
-#define IAGR __SYSREG(0xd4000100, u16) /* intr acceptance group reg */
-#define IAGR_GN 0x00fc /* group number register
- * (documentation _has_ to be wrong)
- */
+/*
+ * Interrupt controller registers
+ * - Registers 64-191 are at addresses offset from the main array
+ */
+#define GxICR(X) \
+ __SYSREG(0xd4000000 + (X) * 4 + \
+ (((X) >= 64) && ((X) < 192)) * 0xf00, u16)
-#define EXTMD __SYSREG(0xd4000200, u16) /* external pin intr spec reg */
-#define GET_XIRQ_TRIGGER(X) ((EXTMD >> ((X) * 2)) & 3)
+#define GxICR_u8(X) \
+ __SYSREG(0xd4000000 + (X) * 4 + \
+ (((X) >= 64) && ((X) < 192)) * 0xf00, u8)
-#define SET_XIRQ_TRIGGER(X,Y) \
-do { \
- u16 x = EXTMD; \
- x &= ~(3 << ((X) * 2)); \
- x |= ((Y) & 3) << ((X) * 2); \
- EXTMD = x; \
-} while (0)
+#include <proc/intctl-regs.h>
#define XIRQ_TRIGGER_LOWLEVEL 0
#define XIRQ_TRIGGER_HILEVEL 1
@@ -59,10 +54,18 @@ do { \
#define GxICR_LEVEL_5 0x5000 /* - level 5 */
#define GxICR_LEVEL_6 0x6000 /* - level 6 */
#define GxICR_LEVEL_SHIFT 12
+#define GxICR_NMI 0x8000 /* nmi request flag */
+
+#define NUM2GxICR_LEVEL(num) ((num) << GxICR_LEVEL_SHIFT)
#ifndef __ASSEMBLY__
extern void set_intr_level(int irq, u16 level);
-extern void set_intr_postackable(int irq);
+extern void mn10300_intc_set_level(unsigned int irq, unsigned int level);
+extern void mn10300_intc_clear(unsigned int irq);
+extern void mn10300_intc_set(unsigned int irq);
+extern void mn10300_intc_enable(unsigned int irq);
+extern void mn10300_intc_disable(unsigned int irq);
+extern void mn10300_set_lateack_irq_type(int irq);
#endif
/* external interrupts */
diff --git a/arch/mn10300/include/asm/io.h b/arch/mn10300/include/asm/io.h
index c1a4119e6497..787255da744e 100644
--- a/arch/mn10300/include/asm/io.h
+++ b/arch/mn10300/include/asm/io.h
@@ -206,6 +206,19 @@ static inline void outsl(unsigned long addr, const void *buffer, int count)
#define iowrite32_rep(p, src, count) \
outsl((unsigned long) (p), (src), (count))
+#define readsb(p, dst, count) \
+ insb((unsigned long) (p), (dst), (count))
+#define readsw(p, dst, count) \
+ insw((unsigned long) (p), (dst), (count))
+#define readsl(p, dst, count) \
+ insl((unsigned long) (p), (dst), (count))
+
+#define writesb(p, src, count) \
+ outsb((unsigned long) (p), (src), (count))
+#define writesw(p, src, count) \
+ outsw((unsigned long) (p), (src), (count))
+#define writesl(p, src, count) \
+ outsl((unsigned long) (p), (src), (count))
#define IO_SPACE_LIMIT 0xffffffff
diff --git a/arch/mn10300/include/asm/irq.h b/arch/mn10300/include/asm/irq.h
index 25c045d16d1c..1a73fb3f60c6 100644
--- a/arch/mn10300/include/asm/irq.h
+++ b/arch/mn10300/include/asm/irq.h
@@ -21,8 +21,16 @@
/* this number is used when no interrupt has been assigned */
#define NO_IRQ INT_MAX
-/* hardware irq numbers */
-#define NR_IRQS GxICR_NUM_IRQS
+/*
+ * hardware irq numbers
+ * - the ASB2364 has an FPGA with an IRQ multiplexer on it
+ */
+#ifdef CONFIG_MN10300_UNIT_ASB2364
+#include <unit/irq.h>
+#else
+#define NR_CPU_IRQS GxICR_NUM_IRQS
+#define NR_IRQS NR_CPU_IRQS
+#endif
/* external hardware irq numbers */
#define NR_XIRQS GxICR_NUM_XIRQS
diff --git a/arch/mn10300/include/asm/irq_regs.h b/arch/mn10300/include/asm/irq_regs.h
index a848cd232eb4..97d0cb5af807 100644
--- a/arch/mn10300/include/asm/irq_regs.h
+++ b/arch/mn10300/include/asm/irq_regs.h
@@ -18,7 +18,11 @@
#define ARCH_HAS_OWN_IRQ_REGS
#ifndef __ASSEMBLY__
-#define get_irq_regs() (__frame)
+static inline __attribute__((const))
+struct pt_regs *get_irq_regs(void)
+{
+ return current_frame();
+}
#endif
#endif /* _ASM_IRQ_REGS_H */
diff --git a/arch/mn10300/include/asm/irqflags.h b/arch/mn10300/include/asm/irqflags.h
index 5e529a117cb2..7a7ae12c7119 100644
--- a/arch/mn10300/include/asm/irqflags.h
+++ b/arch/mn10300/include/asm/irqflags.h
@@ -13,6 +13,9 @@
#define _ASM_IRQFLAGS_H
#include <asm/cpu-regs.h>
+#ifndef __ASSEMBLY__
+#include <linux/smp.h>
+#endif
/*
* interrupt control
@@ -23,11 +26,7 @@
* - level 6 - timer interrupt
* - "enabled": run in IM7
*/
-#ifdef CONFIG_MN10300_TTYSM
-#define MN10300_CLI_LEVEL EPSW_IM_2
-#else
-#define MN10300_CLI_LEVEL EPSW_IM_1
-#endif
+#define MN10300_CLI_LEVEL (CONFIG_LINUX_CLI_LEVEL << EPSW_IM_SHIFT)
#ifndef __ASSEMBLY__
@@ -64,11 +63,12 @@ static inline unsigned long arch_local_irq_save(void)
/*
* we make sure arch_irq_enable() doesn't cause priority inversion
*/
-extern unsigned long __mn10300_irq_enabled_epsw;
+extern unsigned long __mn10300_irq_enabled_epsw[];
static inline void arch_local_irq_enable(void)
{
unsigned long tmp;
+ int cpu = raw_smp_processor_id();
asm volatile(
" mov epsw,%0 \n"
@@ -76,8 +76,8 @@ static inline void arch_local_irq_enable(void)
" or %2,%0 \n"
" mov %0,epsw \n"
: "=&d"(tmp)
- : "i"(~EPSW_IM), "r"(__mn10300_irq_enabled_epsw)
- : "memory");
+ : "i"(~EPSW_IM), "r"(__mn10300_irq_enabled_epsw[cpu])
+ : "memory", "cc");
}
static inline void arch_local_irq_restore(unsigned long flags)
@@ -94,7 +94,7 @@ static inline void arch_local_irq_restore(unsigned long flags)
static inline bool arch_irqs_disabled_flags(unsigned long flags)
{
- return (flags & EPSW_IM) <= MN10300_CLI_LEVEL;
+ return (flags & (EPSW_IE | EPSW_IM)) != (EPSW_IE | EPSW_IM_7);
}
static inline bool arch_irqs_disabled(void)
@@ -109,6 +109,9 @@ static inline bool arch_irqs_disabled(void)
*/
static inline void arch_safe_halt(void)
{
+#ifdef CONFIG_SMP
+ arch_local_irq_enable();
+#else
asm volatile(
" or %0,epsw \n"
" nop \n"
@@ -117,7 +120,97 @@ static inline void arch_safe_halt(void)
:
: "i"(EPSW_IE|EPSW_IM), "n"(&CPUM), "i"(CPUM_SLEEP)
: "cc");
+#endif
}
+#define __sleep_cpu() \
+do { \
+ asm volatile( \
+ " bset %1,(%0)\n" \
+ "1: btst %1,(%0)\n" \
+ " bne 1b\n" \
+ : \
+ : "i"(&CPUM), "i"(CPUM_SLEEP) \
+ : "cc" \
+ ); \
+} while (0)
+
+static inline void arch_local_cli(void)
+{
+ asm volatile(
+ " and %0,epsw \n"
+ " nop \n"
+ " nop \n"
+ " nop \n"
+ :
+ : "i"(~EPSW_IE)
+ : "memory"
+ );
+}
+
+static inline unsigned long arch_local_cli_save(void)
+{
+ unsigned long flags = arch_local_save_flags();
+ arch_local_cli();
+ return flags;
+}
+
+static inline void arch_local_sti(void)
+{
+ asm volatile(
+ " or %0,epsw \n"
+ :
+ : "i"(EPSW_IE)
+ : "memory");
+}
+
+static inline void arch_local_change_intr_mask_level(unsigned long level)
+{
+ asm volatile(
+ " and %0,epsw \n"
+ " or %1,epsw \n"
+ :
+ : "i"(~EPSW_IM), "i"(EPSW_IE | level)
+ : "cc", "memory");
+}
+
+#else /* !__ASSEMBLY__ */
+
+#define LOCAL_SAVE_FLAGS(reg) \
+ mov epsw,reg
+
+#define LOCAL_IRQ_DISABLE \
+ and ~EPSW_IM,epsw; \
+ or EPSW_IE|MN10300_CLI_LEVEL,epsw; \
+ nop; \
+ nop; \
+ nop
+
+#define LOCAL_IRQ_ENABLE \
+ or EPSW_IE|EPSW_IM_7,epsw
+
+#define LOCAL_IRQ_RESTORE(reg) \
+ mov reg,epsw
+
+#define LOCAL_CLI_SAVE(reg) \
+ mov epsw,reg; \
+ and ~EPSW_IE,epsw; \
+ nop; \
+ nop; \
+ nop
+
+#define LOCAL_CLI \
+ and ~EPSW_IE,epsw; \
+ nop; \
+ nop; \
+ nop
+
+#define LOCAL_STI \
+ or EPSW_IE,epsw
+
+#define LOCAL_CHANGE_INTR_MASK_LEVEL(level) \
+ and ~EPSW_IM,epsw; \
+ or EPSW_IE|(level),epsw
+
#endif /* __ASSEMBLY__ */
#endif /* _ASM_IRQFLAGS_H */
diff --git a/arch/mn10300/include/asm/mmu_context.h b/arch/mn10300/include/asm/mmu_context.h
index cb294c244de3..c8f6c82672ad 100644
--- a/arch/mn10300/include/asm/mmu_context.h
+++ b/arch/mn10300/include/asm/mmu_context.h
@@ -27,28 +27,38 @@
#include <asm/tlbflush.h>
#include <asm-generic/mm_hooks.h>
+#define MMU_CONTEXT_TLBPID_NR 256
#define MMU_CONTEXT_TLBPID_MASK 0x000000ffUL
#define MMU_CONTEXT_VERSION_MASK 0xffffff00UL
#define MMU_CONTEXT_FIRST_VERSION 0x00000100UL
#define MMU_NO_CONTEXT 0x00000000UL
-
-extern unsigned long mmu_context_cache[NR_CPUS];
-#define mm_context(mm) (mm->context.tlbpid[smp_processor_id()])
+#define MMU_CONTEXT_TLBPID_LOCK_NR 0
#define enter_lazy_tlb(mm, tsk) do {} while (0)
+static inline void cpu_ran_vm(int cpu, struct mm_struct *mm)
+{
#ifdef CONFIG_SMP
-#define cpu_ran_vm(cpu, mm) \
- cpumask_set_cpu((cpu), mm_cpumask(mm))
-#define cpu_maybe_ran_vm(cpu, mm) \
- cpumask_test_and_set_cpu((cpu), mm_cpumask(mm))
+ cpumask_set_cpu(cpu, mm_cpumask(mm));
+#endif
+}
+
+static inline bool cpu_maybe_ran_vm(int cpu, struct mm_struct *mm)
+{
+#ifdef CONFIG_SMP
+ return cpumask_test_and_set_cpu(cpu, mm_cpumask(mm));
#else
-#define cpu_ran_vm(cpu, mm) do {} while (0)
-#define cpu_maybe_ran_vm(cpu, mm) true
-#endif /* CONFIG_SMP */
+ return true;
+#endif
+}
-/*
- * allocate an MMU context
+#ifdef CONFIG_MN10300_TLB_USE_PIDR
+extern unsigned long mmu_context_cache[NR_CPUS];
+#define mm_context(mm) (mm->context.tlbpid[smp_processor_id()])
+
+/**
+ * allocate_mmu_context - Allocate storage for the arch-specific MMU data
+ * @mm: The userspace VM context being set up
*/
static inline unsigned long allocate_mmu_context(struct mm_struct *mm)
{
@@ -58,7 +68,7 @@ static inline unsigned long allocate_mmu_context(struct mm_struct *mm)
if (!(mc & MMU_CONTEXT_TLBPID_MASK)) {
/* we exhausted the TLB PIDs of this version on this CPU, so we
* flush this CPU's TLB in its entirety and start new cycle */
- flush_tlb_all();
+ local_flush_tlb_all();
/* fix the TLB version if needed (we avoid version #0 so as to
* distingush MMU_NO_CONTEXT) */
@@ -101,22 +111,34 @@ static inline int init_new_context(struct task_struct *tsk,
}
/*
- * destroy context related info for an mm_struct that is about to be put to
- * rest
- */
-#define destroy_context(mm) do { } while (0)
-
-/*
* after we have set current->mm to a new value, this activates the context for
* the new mm so we see the new mappings.
*/
-static inline void activate_context(struct mm_struct *mm, int cpu)
+static inline void activate_context(struct mm_struct *mm)
{
PIDR = get_mmu_context(mm) & MMU_CONTEXT_TLBPID_MASK;
}
+#else /* CONFIG_MN10300_TLB_USE_PIDR */
-/*
- * change between virtual memory sets
+#define init_new_context(tsk, mm) (0)
+#define activate_context(mm) local_flush_tlb()
+
+#endif /* CONFIG_MN10300_TLB_USE_PIDR */
+
+/**
+ * destroy_context - Destroy mm context information
+ * @mm: The MM being destroyed.
+ *
+ * Destroy context related info for an mm_struct that is about to be put to
+ * rest
+ */
+#define destroy_context(mm) do {} while (0)
+
+/**
+ * switch_mm - Change between userspace virtual memory contexts
+ * @prev: The outgoing MM context.
+ * @next: The incoming MM context.
+ * @tsk: The incoming task.
*/
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
@@ -124,11 +146,12 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
int cpu = smp_processor_id();
if (prev != next) {
+#ifdef CONFIG_SMP
+ per_cpu(cpu_tlbstate, cpu).active_mm = next;
+#endif
cpu_ran_vm(cpu, next);
- activate_context(next, cpu);
PTBR = (unsigned long) next->pgd;
- } else if (!cpu_maybe_ran_vm(cpu, next)) {
- activate_context(next, cpu);
+ activate_context(next);
}
}
diff --git a/arch/mn10300/include/asm/pgalloc.h b/arch/mn10300/include/asm/pgalloc.h
index a19f11327cd8..146bacf193ea 100644
--- a/arch/mn10300/include/asm/pgalloc.h
+++ b/arch/mn10300/include/asm/pgalloc.h
@@ -11,7 +11,6 @@
#ifndef _ASM_PGALLOC_H
#define _ASM_PGALLOC_H
-#include <asm/processor.h>
#include <asm/page.h>
#include <linux/threads.h>
#include <linux/mm.h> /* for struct page */
diff --git a/arch/mn10300/include/asm/pgtable.h b/arch/mn10300/include/asm/pgtable.h
index 16d88577f3e0..a1e894b5f65b 100644
--- a/arch/mn10300/include/asm/pgtable.h
+++ b/arch/mn10300/include/asm/pgtable.h
@@ -90,46 +90,58 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
* The vmalloc() routines also leaves a hole of 4kB between each vmalloced
* area to catch addressing errors.
*/
+#ifndef __ASSEMBLY__
+#define VMALLOC_OFFSET (8UL * 1024 * 1024)
+#define VMALLOC_START (0x70000000UL)
+#define VMALLOC_END (0x7C000000UL)
+#else
#define VMALLOC_OFFSET (8 * 1024 * 1024)
#define VMALLOC_START (0x70000000)
#define VMALLOC_END (0x7C000000)
+#endif
#ifndef __ASSEMBLY__
extern pte_t kernel_vmalloc_ptes[(VMALLOC_END - VMALLOC_START) / PAGE_SIZE];
#endif
-/* IPTEL/DPTEL bit assignments */
-#define _PAGE_BIT_VALID xPTEL_V_BIT
-#define _PAGE_BIT_ACCESSED xPTEL_UNUSED1_BIT /* mustn't be loaded into IPTEL/DPTEL */
-#define _PAGE_BIT_NX xPTEL_UNUSED2_BIT /* mustn't be loaded into IPTEL/DPTEL */
-#define _PAGE_BIT_CACHE xPTEL_C_BIT
-#define _PAGE_BIT_PRESENT xPTEL_PV_BIT
-#define _PAGE_BIT_DIRTY xPTEL_D_BIT
-#define _PAGE_BIT_GLOBAL xPTEL_G_BIT
-
-#define _PAGE_VALID xPTEL_V
-#define _PAGE_ACCESSED xPTEL_UNUSED1
-#define _PAGE_NX xPTEL_UNUSED2 /* no-execute bit */
-#define _PAGE_CACHE xPTEL_C
-#define _PAGE_PRESENT xPTEL_PV
-#define _PAGE_DIRTY xPTEL_D
-#define _PAGE_PROT xPTEL_PR
-#define _PAGE_PROT_RKNU xPTEL_PR_ROK
-#define _PAGE_PROT_WKNU xPTEL_PR_RWK
-#define _PAGE_PROT_RKRU xPTEL_PR_ROK_ROU
-#define _PAGE_PROT_WKRU xPTEL_PR_RWK_ROU
-#define _PAGE_PROT_WKWU xPTEL_PR_RWK_RWU
-#define _PAGE_GLOBAL xPTEL_G
-#define _PAGE_PSE xPTEL_PS_4Mb /* 4MB page */
-
-#define _PAGE_FILE xPTEL_UNUSED1_BIT /* set:pagecache unset:swap */
-
-#define __PAGE_PROT_UWAUX 0x040
-#define __PAGE_PROT_USER 0x080
-#define __PAGE_PROT_WRITE 0x100
+/* IPTEL2/DPTEL2 bit assignments */
+#define _PAGE_BIT_VALID xPTEL2_V_BIT
+#define _PAGE_BIT_CACHE xPTEL2_C_BIT
+#define _PAGE_BIT_PRESENT xPTEL2_PV_BIT
+#define _PAGE_BIT_DIRTY xPTEL2_D_BIT
+#define _PAGE_BIT_GLOBAL xPTEL2_G_BIT
+#define _PAGE_BIT_ACCESSED xPTEL2_UNUSED1_BIT /* mustn't be loaded into IPTEL2/DPTEL2 */
+
+#define _PAGE_VALID xPTEL2_V
+#define _PAGE_CACHE xPTEL2_C
+#define _PAGE_PRESENT xPTEL2_PV
+#define _PAGE_DIRTY xPTEL2_D
+#define _PAGE_PROT xPTEL2_PR
+#define _PAGE_PROT_RKNU xPTEL2_PR_ROK
+#define _PAGE_PROT_WKNU xPTEL2_PR_RWK
+#define _PAGE_PROT_RKRU xPTEL2_PR_ROK_ROU
+#define _PAGE_PROT_WKRU xPTEL2_PR_RWK_ROU
+#define _PAGE_PROT_WKWU xPTEL2_PR_RWK_RWU
+#define _PAGE_GLOBAL xPTEL2_G
+#define _PAGE_PS_MASK xPTEL2_PS
+#define _PAGE_PS_4Kb xPTEL2_PS_4Kb
+#define _PAGE_PS_128Kb xPTEL2_PS_128Kb
+#define _PAGE_PS_1Kb xPTEL2_PS_1Kb
+#define _PAGE_PS_4Mb xPTEL2_PS_4Mb
+#define _PAGE_PSE xPTEL2_PS_4Mb /* 4MB page */
+#define _PAGE_CACHE_WT xPTEL2_CWT
+#define _PAGE_ACCESSED xPTEL2_UNUSED1
+#define _PAGE_NX 0 /* no-execute bit */
+
+/* If _PAGE_VALID is clear, we use these: */
+#define _PAGE_FILE xPTEL2_C /* set:pagecache unset:swap */
+#define _PAGE_PROTNONE 0x000 /* If not present */
+
+#define __PAGE_PROT_UWAUX 0x010
+#define __PAGE_PROT_USER 0x020
+#define __PAGE_PROT_WRITE 0x040
#define _PAGE_PRESENTV (_PAGE_PRESENT|_PAGE_VALID)
-#define _PAGE_PROTNONE 0x000 /* If not present */
#ifndef __ASSEMBLY__
@@ -170,6 +182,9 @@ extern pte_t kernel_vmalloc_ptes[(VMALLOC_END - VMALLOC_START) / PAGE_SIZE];
#define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE)
#define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC)
+#define __PAGE_USERIO (__PAGE_KERNEL_BASE | _PAGE_PROT_WKWU | _PAGE_NX)
+#define PAGE_USERIO __pgprot(__PAGE_USERIO)
+
/*
* Whilst the MN10300 can do page protection for execute (given separate data
* and insn TLBs), we are not supporting it at the moment. Write permission,
@@ -323,11 +338,7 @@ static inline int pte_exec_kernel(pte_t pte)
return 1;
}
-/*
- * Bits 0 and 1 are taken, split up the 29 bits of offset
- * into this range:
- */
-#define PTE_FILE_MAX_BITS 29
+#define PTE_FILE_MAX_BITS 30
#define pte_to_pgoff(pte) (pte_val(pte) >> 2)
#define pgoff_to_pte(off) __pte((off) << 2 | _PAGE_FILE)
@@ -373,8 +384,13 @@ static inline void ptep_mkdirty(pte_t *ptep)
* Macro to mark a page protection value as "uncacheable". On processors which
* do not support it, this is a no-op.
*/
-#define pgprot_noncached(prot) __pgprot(pgprot_val(prot) | _PAGE_CACHE)
+#define pgprot_noncached(prot) __pgprot(pgprot_val(prot) & ~_PAGE_CACHE)
+/*
+ * Macro to mark a page protection value as "Write-Through".
+ * On processors which do not support it, this is a no-op.
+ */
+#define pgprot_through(prot) __pgprot(pgprot_val(prot) | _PAGE_CACHE_WT)
/*
* Conversion functions: convert a page and protection to a page entry,
@@ -457,9 +473,7 @@ static inline int set_kernel_exec(unsigned long vaddr, int enable)
#define pte_offset_map(dir, address) \
((pte_t *) page_address(pmd_page(*(dir))) + pte_index(address))
-#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
#define pte_unmap(pte) do {} while (0)
-#define pte_unmap_nested(pte) do {} while (0)
/*
* The MN10300 has external MMU info in the form of a TLB: this is adapted from
diff --git a/arch/mn10300/include/asm/processor.h b/arch/mn10300/include/asm/processor.h
index f7d4b0d285e8..4c1b5cc14c19 100644
--- a/arch/mn10300/include/asm/processor.h
+++ b/arch/mn10300/include/asm/processor.h
@@ -13,10 +13,13 @@
#ifndef _ASM_PROCESSOR_H
#define _ASM_PROCESSOR_H
+#include <linux/threads.h>
+#include <linux/thread_info.h>
#include <asm/page.h>
#include <asm/ptrace.h>
#include <asm/cpu-regs.h>
-#include <linux/threads.h>
+#include <asm/uaccess.h>
+#include <asm/current.h>
/* Forward declaration, a strange C thing */
struct task_struct;
@@ -33,6 +36,8 @@ struct mm_struct;
__pc; \
})
+extern void get_mem_info(unsigned long *mem_base, unsigned long *mem_size);
+
extern void show_registers(struct pt_regs *regs);
/*
@@ -43,17 +48,22 @@ extern void show_registers(struct pt_regs *regs);
struct mn10300_cpuinfo {
int type;
- unsigned long loops_per_sec;
+ unsigned long loops_per_jiffy;
char hard_math;
- unsigned long *pgd_quick;
- unsigned long *pte_quick;
- unsigned long pgtable_cache_sz;
};
extern struct mn10300_cpuinfo boot_cpu_data;
+#ifdef CONFIG_SMP
+#if CONFIG_NR_CPUS < 2 || CONFIG_NR_CPUS > 8
+# error Sorry, NR_CPUS should be 2 to 8
+#endif
+extern struct mn10300_cpuinfo cpu_data[];
+#define current_cpu_data cpu_data[smp_processor_id()]
+#else /* CONFIG_SMP */
#define cpu_data &boot_cpu_data
#define current_cpu_data boot_cpu_data
+#endif /* CONFIG_SMP */
extern void identify_cpu(struct mn10300_cpuinfo *);
extern void print_cpu_info(struct mn10300_cpuinfo *);
@@ -76,10 +86,6 @@ extern void dodgy_tsc(void);
*/
#define TASK_UNMAPPED_BASE 0x30000000
-typedef struct {
- unsigned long seg;
-} mm_segment_t;
-
struct fpu_state_struct {
unsigned long fs[32]; /* fpu registers */
unsigned long fpcr; /* fpu control register */
@@ -92,20 +98,19 @@ struct thread_struct {
unsigned long a3; /* kernel FP */
unsigned long wchan;
unsigned long usp;
- struct pt_regs *__frame;
unsigned long fpu_flags;
#define THREAD_USING_FPU 0x00000001 /* T if this task is using the FPU */
+#define THREAD_HAS_FPU 0x00000002 /* T if this task owns the FPU right now */
struct fpu_state_struct fpu_state;
};
-#define INIT_THREAD \
-{ \
- .uregs = init_uregs, \
- .pc = 0, \
- .sp = 0, \
- .a3 = 0, \
- .wchan = 0, \
- .__frame = NULL, \
+#define INIT_THREAD \
+{ \
+ .uregs = init_uregs, \
+ .pc = 0, \
+ .sp = 0, \
+ .a3 = 0, \
+ .wchan = 0, \
}
#define INIT_MMAP \
@@ -117,13 +122,20 @@ struct thread_struct {
* - need to discard the frame stacked by the kernel thread invoking the execve
* syscall (see RESTORE_ALL macro)
*/
-#define start_thread(regs, new_pc, new_sp) do { \
- set_fs(USER_DS); \
- __frame = current->thread.uregs; \
- __frame->epsw = EPSW_nSL | EPSW_IE | EPSW_IM; \
- __frame->pc = new_pc; \
- __frame->sp = new_sp; \
-} while (0)
+static inline void start_thread(struct pt_regs *regs,
+ unsigned long new_pc, unsigned long new_sp)
+{
+ struct thread_info *ti = current_thread_info();
+ struct pt_regs *frame0;
+ set_fs(USER_DS);
+
+ frame0 = thread_info_to_uregs(ti);
+ frame0->epsw = EPSW_nSL | EPSW_IE | EPSW_IM;
+ frame0->pc = new_pc;
+ frame0->sp = new_sp;
+ ti->frame = frame0;
+}
+
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
@@ -157,7 +169,7 @@ unsigned long get_wchan(struct task_struct *p);
static inline void prefetch(const void *x)
{
-#ifndef CONFIG_MN10300_CACHE_DISABLED
+#ifdef CONFIG_MN10300_CACHE_ENABLED
#ifdef CONFIG_MN10300_PROC_MN103E010
asm volatile ("nop; nop; dcpf (%0)" : : "r"(x));
#else
@@ -168,7 +180,7 @@ static inline void prefetch(const void *x)
static inline void prefetchw(const void *x)
{
-#ifndef CONFIG_MN10300_CACHE_DISABLED
+#ifdef CONFIG_MN10300_CACHE_ENABLED
#ifdef CONFIG_MN10300_PROC_MN103E010
asm volatile ("nop; nop; dcpf (%0)" : : "r"(x));
#else
diff --git a/arch/mn10300/include/asm/ptrace.h b/arch/mn10300/include/asm/ptrace.h
index 7c2e911052b6..b6961811d445 100644
--- a/arch/mn10300/include/asm/ptrace.h
+++ b/arch/mn10300/include/asm/ptrace.h
@@ -40,7 +40,6 @@
#define PT_PC 26
#define NR_PTREGS 27
-#ifndef __ASSEMBLY__
/*
* This defines the way registers are stored in the event of an exception
* - the strange order is due to the MOVM instruction
@@ -75,7 +74,6 @@ struct pt_regs {
unsigned long epsw;
unsigned long pc;
};
-#endif
/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
#define PTRACE_GETREGS 12
@@ -86,12 +84,7 @@ struct pt_regs {
/* options set using PTRACE_SETOPTIONS */
#define PTRACE_O_TRACESYSGOOD 0x00000001
-#if defined(__KERNEL__)
-
-extern struct pt_regs *__frame; /* current frame pointer */
-
-#if !defined(__ASSEMBLY__)
-struct task_struct;
+#ifdef __KERNEL__
#define user_mode(regs) (((regs)->epsw & EPSW_nSL) == EPSW_nSL)
#define instruction_pointer(regs) ((regs)->pc)
@@ -100,9 +93,7 @@ extern void show_regs(struct pt_regs *);
#define arch_has_single_step() (1)
-#endif /* !__ASSEMBLY */
-
#define profile_pc(regs) ((regs)->pc)
-#endif /* __KERNEL__ */
+#endif /* __KERNEL__ */
#endif /* _ASM_PTRACE_H */
diff --git a/arch/mn10300/include/asm/reset-regs.h b/arch/mn10300/include/asm/reset-regs.h
index 174523d50132..10c7502a113f 100644
--- a/arch/mn10300/include/asm/reset-regs.h
+++ b/arch/mn10300/include/asm/reset-regs.h
@@ -50,7 +50,7 @@ static inline void mn10300_proc_hard_reset(void)
RSTCTR |= RSTCTR_CHIPRST;
}
-extern unsigned int watchdog_alert_counter;
+extern unsigned int watchdog_alert_counter[];
extern void watchdog_go(void);
extern asmlinkage void watchdog_handler(void);
diff --git a/arch/mn10300/include/asm/rtc.h b/arch/mn10300/include/asm/rtc.h
index c295194cc703..6c14bb1d0d9b 100644
--- a/arch/mn10300/include/asm/rtc.h
+++ b/arch/mn10300/include/asm/rtc.h
@@ -15,25 +15,14 @@
#include <linux/init.h>
-extern void check_rtc_time(void);
extern void __init calibrate_clock(void);
-extern unsigned long __init get_initial_rtc_time(void);
#else /* !CONFIG_MN10300_RTC */
-static inline void check_rtc_time(void)
-{
-}
-
static inline void calibrate_clock(void)
{
}
-static inline unsigned long get_initial_rtc_time(void)
-{
- return 0;
-}
-
#endif /* !CONFIG_MN10300_RTC */
#include <asm-generic/rtc.h>
diff --git a/arch/mn10300/include/asm/rwlock.h b/arch/mn10300/include/asm/rwlock.h
new file mode 100644
index 000000000000..6d594d4a0e10
--- /dev/null
+++ b/arch/mn10300/include/asm/rwlock.h
@@ -0,0 +1,125 @@
+/*
+ * Helpers used by both rw spinlocks and rw semaphores.
+ *
+ * Based in part on code from semaphore.h and
+ * spinlock.h Copyright 1996 Linus Torvalds.
+ *
+ * Copyright 1999 Red Hat, Inc.
+ *
+ * Written by Benjamin LaHaise.
+ *
+ * Modified by Matsushita Electric Industrial Co., Ltd.
+ * Modifications:
+ * 13-Nov-2006 MEI Temporarily delete lock functions for SMP support.
+ *
+ * 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 _ASM_RWLOCK_H
+#define _ASM_RWLOCK_H
+
+#define RW_LOCK_BIAS 0x01000000
+
+#ifndef CONFIG_SMP
+
+typedef struct { unsigned long a[100]; } __dummy_lock_t;
+#define __dummy_lock(lock) (*(__dummy_lock_t *)(lock))
+
+#define RW_LOCK_BIAS_STR "0x01000000"
+
+#define __build_read_lock_ptr(rw, helper) \
+ do { \
+ asm volatile( \
+ " mov (%0),d3 \n" \
+ " sub 1,d3 \n" \
+ " mov d3,(%0) \n" \
+ " blt 1f \n" \
+ " bra 2f \n" \
+ "1: jmp 3f \n" \
+ "2: \n" \
+ " .section .text.lock,\"ax\" \n" \
+ "3: call "helper"[],0 \n" \
+ " jmp 2b \n" \
+ " .previous" \
+ : \
+ : "d" (rw) \
+ : "memory", "d3", "cc"); \
+ } while (0)
+
+#define __build_read_lock_const(rw, helper) \
+ do { \
+ asm volatile( \
+ " mov (%0),d3 \n" \
+ " sub 1,d3 \n" \
+ " mov d3,(%0) \n" \
+ " blt 1f \n" \
+ " bra 2f \n" \
+ "1: jmp 3f \n" \
+ "2: \n" \
+ " .section .text.lock,\"ax\" \n" \
+ "3: call "helper"[],0 \n" \
+ " jmp 2b \n" \
+ " .previous" \
+ : \
+ : "d" (rw) \
+ : "memory", "d3", "cc"); \
+ } while (0)
+
+#define __build_read_lock(rw, helper) \
+ do { \
+ if (__builtin_constant_p(rw)) \
+ __build_read_lock_const(rw, helper); \
+ else \
+ __build_read_lock_ptr(rw, helper); \
+ } while (0)
+
+#define __build_write_lock_ptr(rw, helper) \
+ do { \
+ asm volatile( \
+ " mov (%0),d3 \n" \
+ " sub 1,d3 \n" \
+ " mov d3,(%0) \n" \
+ " blt 1f \n" \
+ " bra 2f \n" \
+ "1: jmp 3f \n" \
+ "2: \n" \
+ " .section .text.lock,\"ax\" \n" \
+ "3: call "helper"[],0 \n" \
+ " jmp 2b \n" \
+ " .previous" \
+ : \
+ : "d" (rw) \
+ : "memory", "d3", "cc"); \
+ } while (0)
+
+#define __build_write_lock_const(rw, helper) \
+ do { \
+ asm volatile( \
+ " mov (%0),d3 \n" \
+ " sub 1,d3 \n" \
+ " mov d3,(%0) \n" \
+ " blt 1f \n" \
+ " bra 2f \n" \
+ "1: jmp 3f \n" \
+ "2: \n" \
+ " .section .text.lock,\"ax\" \n" \
+ "3: call "helper"[],0 \n" \
+ " jmp 2b \n" \
+ " .previous" \
+ : \
+ : "d" (rw) \
+ : "memory", "d3", "cc"); \
+ } while (0)
+
+#define __build_write_lock(rw, helper) \
+ do { \
+ if (__builtin_constant_p(rw)) \
+ __build_write_lock_const(rw, helper); \
+ else \
+ __build_write_lock_ptr(rw, helper); \
+ } while (0)
+
+#endif /* CONFIG_SMP */
+#endif /* _ASM_RWLOCK_H */
diff --git a/arch/mn10300/include/asm/serial-regs.h b/arch/mn10300/include/asm/serial-regs.h
index 6498469e93ac..8320cda32f5a 100644
--- a/arch/mn10300/include/asm/serial-regs.h
+++ b/arch/mn10300/include/asm/serial-regs.h
@@ -20,18 +20,25 @@
/* serial port 0 */
#define SC0CTR __SYSREG(0xd4002000, u16) /* control reg */
#define SC01CTR_CK 0x0007 /* clock source select */
-#define SC0CTR_CK_TM8UFLOW_8 0x0000 /* - 1/8 timer 8 underflow (serial port 0 only) */
-#define SC1CTR_CK_TM9UFLOW_8 0x0000 /* - 1/8 timer 9 underflow (serial port 1 only) */
#define SC01CTR_CK_IOCLK_8 0x0001 /* - 1/8 IOCLK */
#define SC01CTR_CK_IOCLK_32 0x0002 /* - 1/32 IOCLK */
+#define SC01CTR_CK_EXTERN_8 0x0006 /* - 1/8 external closk */
+#define SC01CTR_CK_EXTERN 0x0007 /* - external closk */
+#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
+#define SC0CTR_CK_TM8UFLOW_8 0x0000 /* - 1/8 timer 8 underflow (serial port 0 only) */
#define SC0CTR_CK_TM2UFLOW_2 0x0003 /* - 1/2 timer 2 underflow (serial port 0 only) */
-#define SC1CTR_CK_TM3UFLOW_2 0x0003 /* - 1/2 timer 3 underflow (serial port 1 only) */
-#define SC0CTR_CK_TM0UFLOW_8 0x0004 /* - 1/8 timer 1 underflow (serial port 0 only) */
-#define SC1CTR_CK_TM1UFLOW_8 0x0004 /* - 1/8 timer 2 underflow (serial port 1 only) */
+#define SC0CTR_CK_TM0UFLOW_8 0x0004 /* - 1/8 timer 0 underflow (serial port 0 only) */
#define SC0CTR_CK_TM2UFLOW_8 0x0005 /* - 1/8 timer 2 underflow (serial port 0 only) */
+#define SC1CTR_CK_TM9UFLOW_8 0x0000 /* - 1/8 timer 9 underflow (serial port 1 only) */
+#define SC1CTR_CK_TM3UFLOW_2 0x0003 /* - 1/2 timer 3 underflow (serial port 1 only) */
+#define SC1CTR_CK_TM1UFLOW_8 0x0004 /* - 1/8 timer 1 underflow (serial port 1 only) */
#define SC1CTR_CK_TM3UFLOW_8 0x0005 /* - 1/8 timer 3 underflow (serial port 1 only) */
-#define SC01CTR_CK_EXTERN_8 0x0006 /* - 1/8 external closk */
-#define SC01CTR_CK_EXTERN 0x0007 /* - external closk */
+#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+#define SC0CTR_CK_TM8UFLOW_8 0x0000 /* - 1/8 timer 8 underflow (serial port 0 only) */
+#define SC0CTR_CK_TM0UFLOW_8 0x0004 /* - 1/8 timer 0 underflow (serial port 0 only) */
+#define SC0CTR_CK_TM2UFLOW_8 0x0005 /* - 1/8 timer 2 underflow (serial port 0 only) */
+#define SC1CTR_CK_TM12UFLOW_8 0x0000 /* - 1/8 timer 12 underflow (serial port 1 only) */
+#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
#define SC01CTR_STB 0x0008 /* stop bit select */
#define SC01CTR_STB_1BIT 0x0000 /* - 1 stop bit */
#define SC01CTR_STB_2BIT 0x0008 /* - 2 stop bits */
@@ -100,11 +107,23 @@
/* serial port 2 */
#define SC2CTR __SYSREG(0xd4002020, u16) /* control reg */
+#ifdef CONFIG_AM33_2
#define SC2CTR_CK 0x0003 /* clock source select */
#define SC2CTR_CK_TM10UFLOW 0x0000 /* - timer 10 underflow */
#define SC2CTR_CK_TM2UFLOW 0x0001 /* - timer 2 underflow */
#define SC2CTR_CK_EXTERN 0x0002 /* - external closk */
#define SC2CTR_CK_TM3UFLOW 0x0003 /* - timer 3 underflow */
+#else /* CONFIG_AM33_2 */
+#define SC2CTR_CK 0x0007 /* clock source select */
+#define SC2CTR_CK_TM9UFLOW_8 0x0000 /* - 1/8 timer 9 underflow */
+#define SC2CTR_CK_IOCLK_8 0x0001 /* - 1/8 IOCLK */
+#define SC2CTR_CK_IOCLK_32 0x0002 /* - 1/32 IOCLK */
+#define SC2CTR_CK_TM3UFLOW_2 0x0003 /* - 1/2 timer 3 underflow */
+#define SC2CTR_CK_TM1UFLOW_8 0x0004 /* - 1/8 timer 1 underflow */
+#define SC2CTR_CK_TM3UFLOW_8 0x0005 /* - 1/8 timer 3 underflow */
+#define SC2CTR_CK_EXTERN_8 0x0006 /* - 1/8 external closk */
+#define SC2CTR_CK_EXTERN 0x0007 /* - external closk */
+#endif /* CONFIG_AM33_2 */
#define SC2CTR_STB 0x0008 /* stop bit select */
#define SC2CTR_STB_1BIT 0x0000 /* - 1 stop bit */
#define SC2CTR_STB_2BIT 0x0008 /* - 2 stop bits */
@@ -134,9 +153,14 @@
#define SC2ICR_RES 0x04 /* receive error select */
#define SC2ICR_RI 0x01 /* receive interrupt cause */
-#define SC2TXB __SYSREG(0xd4002018, u8) /* transmit buffer reg */
-#define SC2RXB __SYSREG(0xd4002019, u8) /* receive buffer reg */
-#define SC2STR __SYSREG(0xd400201c, u8) /* status reg */
+#define SC2TXB __SYSREG(0xd4002028, u8) /* transmit buffer reg */
+#define SC2RXB __SYSREG(0xd4002029, u8) /* receive buffer reg */
+
+#ifdef CONFIG_AM33_2
+#define SC2STR __SYSREG(0xd400202c, u8) /* status reg */
+#else /* CONFIG_AM33_2 */
+#define SC2STR __SYSREG(0xd400202c, u16) /* status reg */
+#endif /* CONFIG_AM33_2 */
#define SC2STR_OEF 0x0001 /* overrun error found */
#define SC2STR_PEF 0x0002 /* parity error found */
#define SC2STR_FEF 0x0004 /* framing error found */
@@ -146,10 +170,17 @@
#define SC2STR_RXF 0x0040 /* receive status */
#define SC2STR_TXF 0x0080 /* transmit status */
+#ifdef CONFIG_AM33_2
#define SC2TIM __SYSREG(0xd400202d, u8) /* status reg */
+#endif
+#ifdef CONFIG_AM33_2
#define SC2RXIRQ 24 /* serial 2 Receive IRQ */
#define SC2TXIRQ 25 /* serial 2 Transmit IRQ */
+#else /* CONFIG_AM33_2 */
+#define SC2RXIRQ 68 /* serial 2 Receive IRQ */
+#define SC2TXIRQ 69 /* serial 2 Transmit IRQ */
+#endif /* CONFIG_AM33_2 */
#define SC2RXICR GxICR(SC2RXIRQ) /* serial 2 receive intr ctrl reg */
#define SC2TXICR GxICR(SC2TXIRQ) /* serial 2 transmit intr ctrl reg */
diff --git a/arch/mn10300/include/asm/serial.h b/arch/mn10300/include/asm/serial.h
index a29445cddd6f..23a799293599 100644
--- a/arch/mn10300/include/asm/serial.h
+++ b/arch/mn10300/include/asm/serial.h
@@ -9,10 +9,8 @@
* 2 of the Licence, or (at your option) any later version.
*/
-/*
- * The ASB2305 has an 18.432 MHz clock the UART
- */
-#define BASE_BAUD (18432000 / 16)
+#ifndef _ASM_SERIAL_H
+#define _ASM_SERIAL_H
/* Standard COM flags (except for COM4, because of the 8514 problem) */
#ifdef CONFIG_SERIAL_DETECT_IRQ
@@ -34,3 +32,5 @@
#endif
#include <unit/serial.h>
+
+#endif /* _ASM_SERIAL_H */
diff --git a/arch/mn10300/include/asm/smp.h b/arch/mn10300/include/asm/smp.h
index 4eb8c61b7dab..a3930e43a958 100644
--- a/arch/mn10300/include/asm/smp.h
+++ b/arch/mn10300/include/asm/smp.h
@@ -3,6 +3,16 @@
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
+ * Modified by Matsushita Electric Industrial Co., Ltd.
+ * Modifications:
+ * 13-Nov-2006 MEI Define IPI-IRQ number and add inline/macro function
+ * for SMP support.
+ * 22-Jan-2007 MEI Add the define related to SMP_BOOT_IRQ.
+ * 23-Feb-2007 MEI Add the define related to SMP icahce invalidate.
+ * 23-Jun-2008 MEI Delete INTC_IPI.
+ * 22-Jul-2008 MEI Add smp_nmi_call_function and related defines.
+ * 04-Aug-2008 MEI Delete USE_DOIRQ_CACHE_IPI.
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
@@ -11,8 +21,85 @@
#ifndef _ASM_SMP_H
#define _ASM_SMP_H
-#ifdef CONFIG_SMP
-#error SMP not yet supported for MN10300
+#ifndef __ASSEMBLY__
+#include <linux/threads.h>
+#include <linux/cpumask.h>
#endif
+#ifdef CONFIG_SMP
+#include <proc/smp-regs.h>
+
+#define RESCHEDULE_IPI 63
+#define CALL_FUNC_SINGLE_IPI 192
+#define LOCAL_TIMER_IPI 193
+#define FLUSH_CACHE_IPI 194
+#define CALL_FUNCTION_NMI_IPI 195
+#define GDB_NMI_IPI 196
+
+#define SMP_BOOT_IRQ 195
+
+#define RESCHEDULE_GxICR_LV GxICR_LEVEL_6
+#define CALL_FUNCTION_GxICR_LV GxICR_LEVEL_4
+#define LOCAL_TIMER_GxICR_LV GxICR_LEVEL_4
+#define FLUSH_CACHE_GxICR_LV GxICR_LEVEL_0
+#define SMP_BOOT_GxICR_LV GxICR_LEVEL_0
+
+#define TIME_OUT_COUNT_BOOT_IPI 100
+#define DELAY_TIME_BOOT_IPI 75000
+
+
+#ifndef __ASSEMBLY__
+
+/**
+ * raw_smp_processor_id - Determine the raw CPU ID of the CPU running it
+ *
+ * What we really want to do is to use the CPUID hardware CPU register to get
+ * this information, but accesses to that aren't cached, and run at system bus
+ * speed, not CPU speed. A copy of this value is, however, stored in the
+ * thread_info struct, and that can be cached.
+ *
+ * An alternate way of dealing with this could be to use the EPSW.S bits to
+ * cache this information for systems with up to four CPUs.
+ */
+#if 0
+#define raw_smp_processor_id() (CPUID)
+#else
+#define raw_smp_processor_id() (current_thread_info()->cpu)
#endif
+
+static inline int cpu_logical_map(int cpu)
+{
+ return cpu;
+}
+
+static inline int cpu_number_map(int cpu)
+{
+ return cpu;
+}
+
+
+extern cpumask_t cpu_boot_map;
+
+extern void smp_init_cpus(void);
+extern void smp_cache_interrupt(void);
+extern void send_IPI_allbutself(int irq);
+extern int smp_nmi_call_function(smp_call_func_t func, void *info, int wait);
+
+extern void arch_send_call_function_single_ipi(int cpu);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+
+#ifdef CONFIG_HOTPLUG_CPU
+extern int __cpu_disable(void);
+extern void __cpu_die(unsigned int cpu);
+#endif /* CONFIG_HOTPLUG_CPU */
+
+#endif /* __ASSEMBLY__ */
+#else /* CONFIG_SMP */
+#ifndef __ASSEMBLY__
+
+static inline void smp_init_cpus(void) {}
+
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_SMP */
+
+#endif /* _ASM_SMP_H */
diff --git a/arch/mn10300/include/asm/smsc911x.h b/arch/mn10300/include/asm/smsc911x.h
new file mode 100644
index 000000000000..2fcd1080322b
--- /dev/null
+++ b/arch/mn10300/include/asm/smsc911x.h
@@ -0,0 +1 @@
+#include <unit/smsc911x.h>
diff --git a/arch/mn10300/include/asm/spinlock.h b/arch/mn10300/include/asm/spinlock.h
index 4bf9c8b169e0..93429154e898 100644
--- a/arch/mn10300/include/asm/spinlock.h
+++ b/arch/mn10300/include/asm/spinlock.h
@@ -11,6 +11,183 @@
#ifndef _ASM_SPINLOCK_H
#define _ASM_SPINLOCK_H
-#error SMP spinlocks not implemented for MN10300
+#include <asm/atomic.h>
+#include <asm/rwlock.h>
+#include <asm/page.h>
+/*
+ * Simple spin lock operations. There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ */
+
+#define arch_spin_is_locked(x) (*(volatile signed char *)(&(x)->slock) != 0)
+#define arch_spin_unlock_wait(x) do { barrier(); } while (arch_spin_is_locked(x))
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+ asm volatile(
+ " bclr 1,(0,%0) \n"
+ :
+ : "a"(&lock->slock)
+ : "memory", "cc");
+}
+
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+ int ret;
+
+ asm volatile(
+ " mov 1,%0 \n"
+ " bset %0,(%1) \n"
+ " bne 1f \n"
+ " clr %0 \n"
+ "1: xor 1,%0 \n"
+ : "=d"(ret)
+ : "a"(&lock->slock)
+ : "memory", "cc");
+
+ return ret;
+}
+
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+ asm volatile(
+ "1: bset 1,(0,%0) \n"
+ " bne 1b \n"
+ :
+ : "a"(&lock->slock)
+ : "memory", "cc");
+}
+
+static inline void arch_spin_lock_flags(arch_spinlock_t *lock,
+ unsigned long flags)
+{
+ int temp;
+
+ asm volatile(
+ "1: bset 1,(0,%2) \n"
+ " beq 3f \n"
+ " mov %1,epsw \n"
+ "2: mov (0,%2),%0 \n"
+ " or %0,%0 \n"
+ " bne 2b \n"
+ " mov %3,%0 \n"
+ " mov %0,epsw \n"
+ " nop \n"
+ " nop \n"
+ " bra 1b\n"
+ "3: \n"
+ : "=&d" (temp)
+ : "d" (flags), "a"(&lock->slock), "i"(EPSW_IE | MN10300_CLI_LEVEL)
+ : "memory", "cc");
+}
+
+#ifdef __KERNEL__
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts
+ * but no interrupt writers. For those circumstances we
+ * can "mix" irq-safe locks - any writer needs to get a
+ * irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ */
+
+/**
+ * read_can_lock - would read_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define arch_read_can_lock(x) ((int)(x)->lock > 0)
+
+/**
+ * write_can_lock - would write_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
+
+/*
+ * On mn10300, we implement read-write locks as a 32-bit counter
+ * with the high bit (sign) being the "contended" bit.
+ */
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+ __build_read_lock(rw, "__read_lock_failed");
+#else
+ {
+ atomic_t *count = (atomic_t *)rw;
+ while (atomic_dec_return(count) < 0)
+ atomic_inc(count);
+ }
+#endif
+}
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+ __build_write_lock(rw, "__write_lock_failed");
+#else
+ {
+ atomic_t *count = (atomic_t *)rw;
+ while (!atomic_sub_and_test(RW_LOCK_BIAS, count))
+ atomic_add(RW_LOCK_BIAS, count);
+ }
+#endif
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+ __build_read_unlock(rw);
+#else
+ {
+ atomic_t *count = (atomic_t *)rw;
+ atomic_inc(count);
+ }
+#endif
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+ __build_write_unlock(rw);
+#else
+ {
+ atomic_t *count = (atomic_t *)rw;
+ atomic_add(RW_LOCK_BIAS, count);
+ }
+#endif
+}
+
+static inline int arch_read_trylock(arch_rwlock_t *lock)
+{
+ atomic_t *count = (atomic_t *)lock;
+ atomic_dec(count);
+ if (atomic_read(count) >= 0)
+ return 1;
+ atomic_inc(count);
+ return 0;
+}
+
+static inline int arch_write_trylock(arch_rwlock_t *lock)
+{
+ atomic_t *count = (atomic_t *)lock;
+ if (atomic_sub_and_test(RW_LOCK_BIAS, count))
+ return 1;
+ atomic_add(RW_LOCK_BIAS, count);
+ return 0;
+}
+
+#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
+#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
+
+#define _raw_spin_relax(lock) cpu_relax()
+#define _raw_read_relax(lock) cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
+#endif /* __KERNEL__ */
#endif /* _ASM_SPINLOCK_H */
diff --git a/arch/mn10300/include/asm/spinlock_types.h b/arch/mn10300/include/asm/spinlock_types.h
new file mode 100644
index 000000000000..653dc519b405
--- /dev/null
+++ b/arch/mn10300/include/asm/spinlock_types.h
@@ -0,0 +1,20 @@
+#ifndef _ASM_SPINLOCK_TYPES_H
+#define _ASM_SPINLOCK_TYPES_H
+
+#ifndef __LINUX_SPINLOCK_TYPES_H
+# error "please don't include this file directly"
+#endif
+
+typedef struct arch_spinlock {
+ unsigned int slock;
+} arch_spinlock_t;
+
+#define __ARCH_SPIN_LOCK_UNLOCKED { 0 }
+
+typedef struct {
+ unsigned int lock;
+} arch_rwlock_t;
+
+#define __ARCH_RW_LOCK_UNLOCKED { RW_LOCK_BIAS }
+
+#endif /* _ASM_SPINLOCK_TYPES_H */
diff --git a/arch/mn10300/include/asm/system.h b/arch/mn10300/include/asm/system.h
index 9f7c7e17c01e..8ff3e5aaca41 100644
--- a/arch/mn10300/include/asm/system.h
+++ b/arch/mn10300/include/asm/system.h
@@ -12,12 +12,29 @@
#define _ASM_SYSTEM_H
#include <asm/cpu-regs.h>
+#include <asm/intctl-regs.h>
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
#include <linux/kernel.h>
#include <linux/irqflags.h>
+#include <asm/atomic.h>
+
+#if !defined(CONFIG_LAZY_SAVE_FPU)
+struct fpu_state_struct;
+extern asmlinkage void fpu_save(struct fpu_state_struct *);
+#define switch_fpu(prev, next) \
+ do { \
+ if ((prev)->thread.fpu_flags & THREAD_HAS_FPU) { \
+ (prev)->thread.fpu_flags &= ~THREAD_HAS_FPU; \
+ (prev)->thread.uregs->epsw &= ~EPSW_FE; \
+ fpu_save(&(prev)->thread.fpu_state); \
+ } \
+ } while (0)
+#else
+#define switch_fpu(prev, next) do {} while (0)
+#endif
struct task_struct;
struct thread_struct;
@@ -30,6 +47,7 @@ struct task_struct *__switch_to(struct thread_struct *prev,
/* context switching is now performed out-of-line in switch_to.S */
#define switch_to(prev, next, last) \
do { \
+ switch_fpu(prev, next); \
current->thread.wchan = (u_long) __builtin_return_address(0); \
(last) = __switch_to(&(prev)->thread, &(next)->thread, (prev)); \
mb(); \
@@ -40,8 +58,6 @@ do { \
#define nop() asm volatile ("nop")
-#endif /* !__ASSEMBLY__ */
-
/*
* Force strict CPU ordering.
* And yes, this is required on UP too when we're talking
@@ -68,64 +84,19 @@ do { \
#define smp_mb() mb()
#define smp_rmb() rmb()
#define smp_wmb() wmb()
-#else
+#define set_mb(var, value) do { xchg(&var, value); } while (0)
+#else /* CONFIG_SMP */
#define smp_mb() barrier()
#define smp_rmb() barrier()
#define smp_wmb() barrier()
-#endif
-
#define set_mb(var, value) do { var = value; mb(); } while (0)
+#endif /* CONFIG_SMP */
+
#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#define read_barrier_depends() do {} while (0)
#define smp_read_barrier_depends() do {} while (0)
-/*****************************************************************************/
-/*
- * MN10300 doesn't actually have an exchange instruction
- */
-#ifndef __ASSEMBLY__
-
-struct __xchg_dummy { unsigned long a[100]; };
-#define __xg(x) ((struct __xchg_dummy *)(x))
-
-static inline
-unsigned long __xchg(volatile unsigned long *m, unsigned long val)
-{
- unsigned long retval;
- unsigned long flags;
-
- local_irq_save(flags);
- retval = *m;
- *m = val;
- local_irq_restore(flags);
- return retval;
-}
-
-#define xchg(ptr, v) \
- ((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr), \
- (unsigned long)(v)))
-
-static inline unsigned long __cmpxchg(volatile unsigned long *m,
- unsigned long old, unsigned long new)
-{
- unsigned long retval;
- unsigned long flags;
-
- local_irq_save(flags);
- retval = *m;
- if (retval == old)
- *m = new;
- local_irq_restore(flags);
- return retval;
-}
-
-#define cmpxchg(ptr, o, n) \
- ((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \
- (unsigned long)(o), \
- (unsigned long)(n)))
-
#endif /* !__ASSEMBLY__ */
-
#endif /* __KERNEL__ */
#endif /* _ASM_SYSTEM_H */
diff --git a/arch/mn10300/include/asm/thread_info.h b/arch/mn10300/include/asm/thread_info.h
index 2001cb657a95..aa07a4a5d794 100644
--- a/arch/mn10300/include/asm/thread_info.h
+++ b/arch/mn10300/include/asm/thread_info.h
@@ -16,10 +16,6 @@
#include <asm/page.h>
-#ifndef __ASSEMBLY__
-#include <asm/processor.h>
-#endif
-
#define PREEMPT_ACTIVE 0x10000000
#ifdef CONFIG_4KSTACKS
@@ -38,10 +34,14 @@
* must also be changed
*/
#ifndef __ASSEMBLY__
+typedef struct {
+ unsigned long seg;
+} mm_segment_t;
struct thread_info {
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
+ struct pt_regs *frame; /* current exception frame */
unsigned long flags; /* low level flags */
__u32 cpu; /* current CPU */
__s32 preempt_count; /* 0 => preemptable, <0 => BUG */
@@ -55,6 +55,10 @@ struct thread_info {
__u8 supervisor_stack[0];
};
+#define thread_info_to_uregs(ti) \
+ ((struct pt_regs *) \
+ ((unsigned long)ti + THREAD_SIZE - sizeof(struct pt_regs)))
+
#else /* !__ASSEMBLY__ */
#ifndef __ASM_OFFSETS_H__
@@ -102,6 +106,12 @@ struct thread_info *current_thread_info(void)
return ti;
}
+static inline __attribute__((const))
+struct pt_regs *current_frame(void)
+{
+ return current_thread_info()->frame;
+}
+
/* how to get the current stack pointer from C */
static inline unsigned long current_stack_pointer(void)
{
diff --git a/arch/mn10300/include/asm/timer-regs.h b/arch/mn10300/include/asm/timer-regs.h
index 1d883b7f94ab..c634977caf66 100644
--- a/arch/mn10300/include/asm/timer-regs.h
+++ b/arch/mn10300/include/asm/timer-regs.h
@@ -17,21 +17,27 @@
#ifdef __KERNEL__
-/* timer prescalar control */
+/*
+ * Timer prescalar control
+ */
#define TMPSCNT __SYSREG(0xd4003071, u8) /* timer prescaler control */
#define TMPSCNT_ENABLE 0x80 /* timer prescaler enable */
#define TMPSCNT_DISABLE 0x00 /* timer prescaler disable */
-/* 8 bit timers */
+/*
+ * 8-bit timers
+ */
#define TM0MD __SYSREG(0xd4003000, u8) /* timer 0 mode register */
#define TM0MD_SRC 0x07 /* timer source */
#define TM0MD_SRC_IOCLK 0x00 /* - IOCLK */
#define TM0MD_SRC_IOCLK_8 0x01 /* - 1/8 IOCLK */
#define TM0MD_SRC_IOCLK_32 0x02 /* - 1/32 IOCLK */
-#define TM0MD_SRC_TM2IO 0x03 /* - TM2IO pin input */
#define TM0MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */
#define TM0MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
+#define TM0MD_SRC_TM2IO 0x03 /* - TM2IO pin input */
#define TM0MD_SRC_TM0IO 0x07 /* - TM0IO pin input */
+#endif /* CONFIG_AM33_2 */
#define TM0MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */
#define TM0MD_COUNT_ENABLE 0x80 /* timer count enable */
@@ -43,7 +49,9 @@
#define TM1MD_SRC_TM0CASCADE 0x03 /* - cascade with timer 0 */
#define TM1MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */
#define TM1MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
#define TM1MD_SRC_TM1IO 0x07 /* - TM1IO pin input */
+#endif /* CONFIG_AM33_2 */
#define TM1MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */
#define TM1MD_COUNT_ENABLE 0x80 /* timer count enable */
@@ -55,7 +63,9 @@
#define TM2MD_SRC_TM1CASCADE 0x03 /* - cascade with timer 1 */
#define TM2MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */
#define TM2MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */
+#if defined(CONFIG_AM33_2)
#define TM2MD_SRC_TM2IO 0x07 /* - TM2IO pin input */
+#endif /* CONFIG_AM33_2 */
#define TM2MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */
#define TM2MD_COUNT_ENABLE 0x80 /* timer count enable */
@@ -64,11 +74,13 @@
#define TM3MD_SRC_IOCLK 0x00 /* - IOCLK */
#define TM3MD_SRC_IOCLK_8 0x01 /* - 1/8 IOCLK */
#define TM3MD_SRC_IOCLK_32 0x02 /* - 1/32 IOCLK */
-#define TM3MD_SRC_TM1CASCADE 0x03 /* - cascade with timer 2 */
+#define TM3MD_SRC_TM2CASCADE 0x03 /* - cascade with timer 2 */
#define TM3MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */
#define TM3MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */
#define TM3MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
#define TM3MD_SRC_TM3IO 0x07 /* - TM3IO pin input */
+#endif /* CONFIG_AM33_2 */
#define TM3MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */
#define TM3MD_COUNT_ENABLE 0x80 /* timer count enable */
@@ -96,7 +108,9 @@
#define TM2ICR GxICR(TM2IRQ) /* timer 2 uflow intr ctrl reg */
#define TM3ICR GxICR(TM3IRQ) /* timer 3 uflow intr ctrl reg */
-/* 16-bit timers 4,5 & 7-11 */
+/*
+ * 16-bit timers 4,5 & 7-15
+ */
#define TM4MD __SYSREG(0xd4003080, u8) /* timer 4 mode register */
#define TM4MD_SRC 0x07 /* timer source */
#define TM4MD_SRC_IOCLK 0x00 /* - IOCLK */
@@ -105,7 +119,9 @@
#define TM4MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */
#define TM4MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */
#define TM4MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
#define TM4MD_SRC_TM4IO 0x07 /* - TM4IO pin input */
+#endif /* CONFIG_AM33_2 */
#define TM4MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */
#define TM4MD_COUNT_ENABLE 0x80 /* timer count enable */
@@ -118,7 +134,11 @@
#define TM5MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */
#define TM5MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */
#define TM5MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
#define TM5MD_SRC_TM5IO 0x07 /* - TM5IO pin input */
+#else /* !CONFIG_AM33_2 */
+#define TM5MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */
+#endif /* CONFIG_AM33_2 */
#define TM5MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */
#define TM5MD_COUNT_ENABLE 0x80 /* timer count enable */
@@ -130,7 +150,9 @@
#define TM7MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */
#define TM7MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */
#define TM7MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
#define TM7MD_SRC_TM7IO 0x07 /* - TM7IO pin input */
+#endif /* CONFIG_AM33_2 */
#define TM7MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */
#define TM7MD_COUNT_ENABLE 0x80 /* timer count enable */
@@ -143,7 +165,11 @@
#define TM8MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */
#define TM8MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */
#define TM8MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
#define TM8MD_SRC_TM8IO 0x07 /* - TM8IO pin input */
+#else /* !CONFIG_AM33_2 */
+#define TM8MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */
+#endif /* CONFIG_AM33_2 */
#define TM8MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */
#define TM8MD_COUNT_ENABLE 0x80 /* timer count enable */
@@ -156,7 +182,11 @@
#define TM9MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */
#define TM9MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */
#define TM9MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
#define TM9MD_SRC_TM9IO 0x07 /* - TM9IO pin input */
+#else /* !CONFIG_AM33_2 */
+#define TM9MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */
+#endif /* CONFIG_AM33_2 */
#define TM9MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */
#define TM9MD_COUNT_ENABLE 0x80 /* timer count enable */
@@ -169,7 +199,11 @@
#define TM10MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */
#define TM10MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */
#define TM10MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
#define TM10MD_SRC_TM10IO 0x07 /* - TM10IO pin input */
+#else /* !CONFIG_AM33_2 */
+#define TM10MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */
+#endif /* CONFIG_AM33_2 */
#define TM10MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */
#define TM10MD_COUNT_ENABLE 0x80 /* timer count enable */
@@ -178,32 +212,101 @@
#define TM11MD_SRC_IOCLK 0x00 /* - IOCLK */
#define TM11MD_SRC_IOCLK_8 0x01 /* - 1/8 IOCLK */
#define TM11MD_SRC_IOCLK_32 0x02 /* - 1/32 IOCLK */
-#define TM11MD_SRC_TM7CASCADE 0x03 /* - cascade with timer 7 */
#define TM11MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */
#define TM11MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */
#define TM11MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
#define TM11MD_SRC_TM11IO 0x07 /* - TM11IO pin input */
+#else /* !CONFIG_AM33_2 */
+#define TM11MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */
+#endif /* CONFIG_AM33_2 */
#define TM11MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */
#define TM11MD_COUNT_ENABLE 0x80 /* timer count enable */
+#if defined(CONFIG_AM34_2)
+#define TM12MD __SYSREG(0xd4003180, u8) /* timer 11 mode register */
+#define TM12MD_SRC 0x07 /* timer source */
+#define TM12MD_SRC_IOCLK 0x00 /* - IOCLK */
+#define TM12MD_SRC_IOCLK_8 0x01 /* - 1/8 IOCLK */
+#define TM12MD_SRC_IOCLK_32 0x02 /* - 1/32 IOCLK */
+#define TM12MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */
+#define TM12MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */
+#define TM12MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */
+#define TM12MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */
+#define TM12MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */
+#define TM12MD_COUNT_ENABLE 0x80 /* timer count enable */
+
+#define TM13MD __SYSREG(0xd4003182, u8) /* timer 11 mode register */
+#define TM13MD_SRC 0x07 /* timer source */
+#define TM13MD_SRC_IOCLK 0x00 /* - IOCLK */
+#define TM13MD_SRC_IOCLK_8 0x01 /* - 1/8 IOCLK */
+#define TM13MD_SRC_IOCLK_32 0x02 /* - 1/32 IOCLK */
+#define TM13MD_SRC_TM12CASCADE 0x03 /* - cascade with timer 12 */
+#define TM13MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */
+#define TM13MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */
+#define TM13MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */
+#define TM13MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */
+#define TM13MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */
+#define TM13MD_COUNT_ENABLE 0x80 /* timer count enable */
+
+#define TM14MD __SYSREG(0xd4003184, u8) /* timer 11 mode register */
+#define TM14MD_SRC 0x07 /* timer source */
+#define TM14MD_SRC_IOCLK 0x00 /* - IOCLK */
+#define TM14MD_SRC_IOCLK_8 0x01 /* - 1/8 IOCLK */
+#define TM14MD_SRC_IOCLK_32 0x02 /* - 1/32 IOCLK */
+#define TM14MD_SRC_TM13CASCADE 0x03 /* - cascade with timer 13 */
+#define TM14MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */
+#define TM14MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */
+#define TM14MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */
+#define TM14MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */
+#define TM14MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */
+#define TM14MD_COUNT_ENABLE 0x80 /* timer count enable */
+
+#define TM15MD __SYSREG(0xd4003186, u8) /* timer 11 mode register */
+#define TM15MD_SRC 0x07 /* timer source */
+#define TM15MD_SRC_IOCLK 0x00 /* - IOCLK */
+#define TM15MD_SRC_IOCLK_8 0x01 /* - 1/8 IOCLK */
+#define TM15MD_SRC_IOCLK_32 0x02 /* - 1/32 IOCLK */
+#define TM15MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */
+#define TM15MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */
+#define TM15MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */
+#define TM15MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */
+#define TM15MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */
+#define TM15MD_COUNT_ENABLE 0x80 /* timer count enable */
+#endif /* CONFIG_AM34_2 */
+
+
#define TM4BR __SYSREG(0xd4003090, u16) /* timer 4 base register */
#define TM5BR __SYSREG(0xd4003092, u16) /* timer 5 base register */
+#define TM45BR __SYSREG(0xd4003090, u32) /* timer 4:5 base register */
#define TM7BR __SYSREG(0xd4003096, u16) /* timer 7 base register */
#define TM8BR __SYSREG(0xd4003098, u16) /* timer 8 base register */
#define TM9BR __SYSREG(0xd400309a, u16) /* timer 9 base register */
+#define TM89BR __SYSREG(0xd4003098, u32) /* timer 8:9 base register */
#define TM10BR __SYSREG(0xd400309c, u16) /* timer 10 base register */
#define TM11BR __SYSREG(0xd400309e, u16) /* timer 11 base register */
-#define TM45BR __SYSREG(0xd4003090, u32) /* timer 4:5 base register */
+#if defined(CONFIG_AM34_2)
+#define TM12BR __SYSREG(0xd4003190, u16) /* timer 12 base register */
+#define TM13BR __SYSREG(0xd4003192, u16) /* timer 13 base register */
+#define TM14BR __SYSREG(0xd4003194, u16) /* timer 14 base register */
+#define TM15BR __SYSREG(0xd4003196, u16) /* timer 15 base register */
+#endif /* CONFIG_AM34_2 */
#define TM4BC __SYSREG(0xd40030a0, u16) /* timer 4 binary counter */
#define TM5BC __SYSREG(0xd40030a2, u16) /* timer 5 binary counter */
#define TM45BC __SYSREG(0xd40030a0, u32) /* timer 4:5 binary counter */
-
#define TM7BC __SYSREG(0xd40030a6, u16) /* timer 7 binary counter */
#define TM8BC __SYSREG(0xd40030a8, u16) /* timer 8 binary counter */
#define TM9BC __SYSREG(0xd40030aa, u16) /* timer 9 binary counter */
+#define TM89BC __SYSREG(0xd40030a8, u32) /* timer 8:9 binary counter */
#define TM10BC __SYSREG(0xd40030ac, u16) /* timer 10 binary counter */
#define TM11BC __SYSREG(0xd40030ae, u16) /* timer 11 binary counter */
+#if defined(CONFIG_AM34_2)
+#define TM12BC __SYSREG(0xd40031a0, u16) /* timer 12 binary counter */
+#define TM13BC __SYSREG(0xd40031a2, u16) /* timer 13 binary counter */
+#define TM14BC __SYSREG(0xd40031a4, u16) /* timer 14 binary counter */
+#define TM15BC __SYSREG(0xd40031a6, u16) /* timer 15 binary counter */
+#endif /* CONFIG_AM34_2 */
#define TM4IRQ 6 /* timer 4 IRQ */
#define TM5IRQ 7 /* timer 5 IRQ */
@@ -212,6 +315,12 @@
#define TM9IRQ 13 /* timer 9 IRQ */
#define TM10IRQ 14 /* timer 10 IRQ */
#define TM11IRQ 15 /* timer 11 IRQ */
+#if defined(CONFIG_AM34_2)
+#define TM12IRQ 64 /* timer 12 IRQ */
+#define TM13IRQ 65 /* timer 13 IRQ */
+#define TM14IRQ 66 /* timer 14 IRQ */
+#define TM15IRQ 67 /* timer 15 IRQ */
+#endif /* CONFIG_AM34_2 */
#define TM4ICR GxICR(TM4IRQ) /* timer 4 uflow intr ctrl reg */
#define TM5ICR GxICR(TM5IRQ) /* timer 5 uflow intr ctrl reg */
@@ -220,8 +329,16 @@
#define TM9ICR GxICR(TM9IRQ) /* timer 9 uflow intr ctrl reg */
#define TM10ICR GxICR(TM10IRQ) /* timer 10 uflow intr ctrl reg */
#define TM11ICR GxICR(TM11IRQ) /* timer 11 uflow intr ctrl reg */
-
-/* 16-bit timer 6 */
+#if defined(CONFIG_AM34_2)
+#define TM12ICR GxICR(TM12IRQ) /* timer 12 uflow intr ctrl reg */
+#define TM13ICR GxICR(TM13IRQ) /* timer 13 uflow intr ctrl reg */
+#define TM14ICR GxICR(TM14IRQ) /* timer 14 uflow intr ctrl reg */
+#define TM15ICR GxICR(TM15IRQ) /* timer 15 uflow intr ctrl reg */
+#endif /* CONFIG_AM34_2 */
+
+/*
+ * 16-bit timer 6
+ */
#define TM6MD __SYSREG(0xd4003084, u16) /* timer6 mode register */
#define TM6MD_SRC 0x0007 /* timer source */
#define TM6MD_SRC_IOCLK 0x0000 /* - IOCLK */
@@ -229,10 +346,14 @@
#define TM6MD_SRC_IOCLK_32 0x0002 /* - 1/32 IOCLK */
#define TM6MD_SRC_TM0UFLOW 0x0004 /* - timer 0 underflow */
#define TM6MD_SRC_TM1UFLOW 0x0005 /* - timer 1 underflow */
-#define TM6MD_SRC_TM6IOB_BOTH 0x0006 /* - TM6IOB pin input (both edges) */
+#define TM6MD_SRC_TM2UFLOW 0x0006 /* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
+/* #define TM6MD_SRC_TM6IOB_BOTH 0x0006 */ /* - TM6IOB pin input (both edges) */
#define TM6MD_SRC_TM6IOB_SINGLE 0x0007 /* - TM6IOB pin input (single edge) */
-#define TM6MD_CLR_ENABLE 0x0010 /* clear count enable */
+#endif /* CONFIG_AM33_2 */
#define TM6MD_ONESHOT_ENABLE 0x0040 /* oneshot count */
+#define TM6MD_CLR_ENABLE 0x0010 /* clear count enable */
+#if defined(CONFIG_AM33_2)
#define TM6MD_TRIG_ENABLE 0x0080 /* TM6IOB pin trigger enable */
#define TM6MD_PWM 0x3800 /* PWM output mode */
#define TM6MD_PWM_DIS 0x0000 /* - disabled */
@@ -240,10 +361,15 @@
#define TM6MD_PWM_11BIT 0x1800 /* - 11 bits mode */
#define TM6MD_PWM_12BIT 0x3000 /* - 12 bits mode */
#define TM6MD_PWM_14BIT 0x3800 /* - 14 bits mode */
+#endif /* CONFIG_AM33_2 */
+
#define TM6MD_INIT_COUNTER 0x4000 /* initialize TMnBC to zero */
#define TM6MD_COUNT_ENABLE 0x8000 /* timer count enable */
#define TM6MDA __SYSREG(0xd40030b4, u8) /* timer6 cmp/cap A mode reg */
+#define TM6MDA_MODE_CMP_SINGLE 0x00 /* - compare, single buffer mode */
+#define TM6MDA_MODE_CMP_DOUBLE 0x40 /* - compare, double buffer mode */
+#if defined(CONFIG_AM33_2)
#define TM6MDA_OUT 0x07 /* output select */
#define TM6MDA_OUT_SETA_RESETB 0x00 /* - set at match A, reset at match B */
#define TM6MDA_OUT_SETA_RESETOV 0x01 /* - set at match A, reset at overflow */
@@ -251,30 +377,35 @@
#define TM6MDA_OUT_RESETA 0x03 /* - reset at match A */
#define TM6MDA_OUT_TOGGLE 0x04 /* - toggle on match A */
#define TM6MDA_MODE 0xc0 /* compare A register mode */
-#define TM6MDA_MODE_CMP_SINGLE 0x00 /* - compare, single buffer mode */
-#define TM6MDA_MODE_CMP_DOUBLE 0x40 /* - compare, double buffer mode */
#define TM6MDA_MODE_CAP_S_EDGE 0x80 /* - capture, single edge mode */
#define TM6MDA_MODE_CAP_D_EDGE 0xc0 /* - capture, double edge mode */
#define TM6MDA_EDGE 0x20 /* compare A edge select */
#define TM6MDA_EDGE_FALLING 0x00 /* capture on falling edge */
#define TM6MDA_EDGE_RISING 0x20 /* capture on rising edge */
#define TM6MDA_CAPTURE_ENABLE 0x10 /* capture enable */
+#else /* !CONFIG_AM33_2 */
+#define TM6MDA_MODE 0x40 /* compare A register mode */
+#endif /* CONFIG_AM33_2 */
#define TM6MDB __SYSREG(0xd40030b5, u8) /* timer6 cmp/cap B mode reg */
+#define TM6MDB_MODE_CMP_SINGLE 0x00 /* - compare, single buffer mode */
+#define TM6MDB_MODE_CMP_DOUBLE 0x40 /* - compare, double buffer mode */
+#if defined(CONFIG_AM33_2)
#define TM6MDB_OUT 0x07 /* output select */
#define TM6MDB_OUT_SETB_RESETA 0x00 /* - set at match B, reset at match A */
#define TM6MDB_OUT_SETB_RESETOV 0x01 /* - set at match B */
#define TM6MDB_OUT_RESETB 0x03 /* - reset at match B */
#define TM6MDB_OUT_TOGGLE 0x04 /* - toggle on match B */
#define TM6MDB_MODE 0xc0 /* compare B register mode */
-#define TM6MDB_MODE_CMP_SINGLE 0x00 /* - compare, single buffer mode */
-#define TM6MDB_MODE_CMP_DOUBLE 0x40 /* - compare, double buffer mode */
#define TM6MDB_MODE_CAP_S_EDGE 0x80 /* - capture, single edge mode */
#define TM6MDB_MODE_CAP_D_EDGE 0xc0 /* - capture, double edge mode */
#define TM6MDB_EDGE 0x20 /* compare B edge select */
#define TM6MDB_EDGE_FALLING 0x00 /* capture on falling edge */
#define TM6MDB_EDGE_RISING 0x20 /* capture on rising edge */
#define TM6MDB_CAPTURE_ENABLE 0x10 /* capture enable */
+#else /* !CONFIG_AM33_2 */
+#define TM6MDB_MODE 0x40 /* compare B register mode */
+#endif /* CONFIG_AM33_2 */
#define TM6CA __SYSREG(0xd40030c4, u16) /* timer6 cmp/capture reg A */
#define TM6CB __SYSREG(0xd40030d4, u16) /* timer6 cmp/capture reg B */
@@ -288,6 +419,34 @@
#define TM6AICR GxICR(TM6AIRQ) /* timer 6A intr control reg */
#define TM6BICR GxICR(TM6BIRQ) /* timer 6B intr control reg */
+#if defined(CONFIG_AM34_2)
+/*
+ * MTM: OS Tick-Timer
+ */
+#define TMTMD __SYSREG(0xd4004100, u8) /* Tick Timer mode register */
+#define TMTMD_TMTLDE 0x40 /* initialize TMTBC = TMTBR */
+#define TMTMD_TMTCNE 0x80 /* timer count enable */
+
+#define TMTBR __SYSREG(0xd4004110, u32) /* Tick Timer mode reg */
+#define TMTBC __SYSREG(0xd4004120, u32) /* Tick Timer mode reg */
+
+/*
+ * MTM: OS Timestamp-Timer
+ */
+#define TMSMD __SYSREG(0xd4004140, u8) /* Tick Timer mode register */
+#define TMSMD_TMSLDE 0x40 /* initialize TMSBC = TMSBR */
+#define TMSMD_TMSCNE 0x80 /* timer count enable */
+
+#define TMSBR __SYSREG(0xd4004150, u32) /* Tick Timer mode register */
+#define TMSBC __SYSREG(0xd4004160, u32) /* Tick Timer mode register */
+
+#define TMTIRQ 119 /* OS Tick timer IRQ */
+#define TMSIRQ 120 /* Timestamp timer IRQ */
+
+#define TMTICR GxICR(TMTIRQ) /* OS Tick timer uflow intr ctrl reg */
+#define TMSICR GxICR(TMSIRQ) /* Timestamp timer uflow intr ctrl reg */
+#endif /* CONFIG_AM34_2 */
+
#endif /* __KERNEL__ */
#endif /* _ASM_TIMER_REGS_H */
diff --git a/arch/mn10300/include/asm/timex.h b/arch/mn10300/include/asm/timex.h
index 8d031f9e117d..bd4e90dfe6c2 100644
--- a/arch/mn10300/include/asm/timex.h
+++ b/arch/mn10300/include/asm/timex.h
@@ -16,18 +16,30 @@
#define TICK_SIZE (tick_nsec / 1000)
-#define CLOCK_TICK_RATE 1193180 /* Underlying HZ - this should probably be set
- * to something appropriate, but what? */
-
-extern cycles_t cacheflush_time;
+#define CLOCK_TICK_RATE MN10300_JCCLK /* Underlying HZ */
#ifdef __KERNEL__
+extern cycles_t cacheflush_time;
+
static inline cycles_t get_cycles(void)
{
return read_timestamp_counter();
}
+extern int init_clockevents(void);
+extern int init_clocksource(void);
+
+static inline void setup_jiffies_interrupt(int irq,
+ struct irqaction *action)
+{
+ u16 tmp;
+ setup_irq(irq, action);
+ set_intr_level(irq, NUM2GxICR_LEVEL(CONFIG_TIMER_IRQ_LEVEL));
+ GxICR(irq) |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST;
+ tmp = GxICR(irq);
+}
+
#endif /* __KERNEL__ */
#endif /* _ASM_TIMEX_H */
diff --git a/arch/mn10300/include/asm/tlbflush.h b/arch/mn10300/include/asm/tlbflush.h
index 1a7e29281c5d..efddd6e1adea 100644
--- a/arch/mn10300/include/asm/tlbflush.h
+++ b/arch/mn10300/include/asm/tlbflush.h
@@ -11,24 +11,78 @@
#ifndef _ASM_TLBFLUSH_H
#define _ASM_TLBFLUSH_H
+#include <linux/mm.h>
#include <asm/processor.h>
-#define __flush_tlb() \
-do { \
- int w; \
- __asm__ __volatile__ \
- (" mov %1,%0 \n" \
- " or %2,%0 \n" \
- " mov %0,%1 \n" \
- : "=d"(w) \
- : "m"(MMUCTR), "i"(MMUCTR_IIV|MMUCTR_DIV) \
- : "cc", "memory" \
- ); \
-} while (0)
+struct tlb_state {
+ struct mm_struct *active_mm;
+ int state;
+};
+DECLARE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate);
-#define __flush_tlb_all() __flush_tlb()
-#define __flush_tlb_one(addr) __flush_tlb()
+/**
+ * local_flush_tlb - Flush the current MM's entries from the local CPU's TLBs
+ */
+static inline void local_flush_tlb(void)
+{
+ int w;
+ asm volatile(
+ " mov %1,%0 \n"
+ " or %2,%0 \n"
+ " mov %0,%1 \n"
+ : "=d"(w)
+ : "m"(MMUCTR), "i"(MMUCTR_IIV|MMUCTR_DIV)
+ : "cc", "memory");
+}
+
+/**
+ * local_flush_tlb_all - Flush all entries from the local CPU's TLBs
+ */
+static inline void local_flush_tlb_all(void)
+{
+ local_flush_tlb();
+}
+/**
+ * local_flush_tlb_one - Flush one entry from the local CPU's TLBs
+ */
+static inline void local_flush_tlb_one(unsigned long addr)
+{
+ local_flush_tlb();
+}
+
+/**
+ * local_flush_tlb_page - Flush a page's entry from the local CPU's TLBs
+ * @mm: The MM to flush for
+ * @addr: The address of the target page in RAM (not its page struct)
+ */
+static inline
+void local_flush_tlb_page(struct mm_struct *mm, unsigned long addr)
+{
+ unsigned long pteu, flags, cnx;
+
+ addr &= PAGE_MASK;
+
+ local_irq_save(flags);
+
+ cnx = 1;
+#ifdef CONFIG_MN10300_TLB_USE_PIDR
+ cnx = mm->context.tlbpid[smp_processor_id()];
+#endif
+ if (cnx) {
+ pteu = addr;
+#ifdef CONFIG_MN10300_TLB_USE_PIDR
+ pteu |= cnx & xPTEU_PID;
+#endif
+ IPTEU = pteu;
+ DPTEU = pteu;
+ if (IPTEL & xPTEL_V)
+ IPTEL = 0;
+ if (DPTEL & xPTEL_V)
+ DPTEL = 0;
+ }
+ local_irq_restore(flags);
+}
/*
* TLB flushing:
@@ -40,41 +94,61 @@ do { \
* - flush_tlb_range(mm, start, end) flushes a range of pages
* - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
*/
-#define flush_tlb_all() \
-do { \
- preempt_disable(); \
- __flush_tlb_all(); \
- preempt_enable(); \
-} while (0)
-
-#define flush_tlb_mm(mm) \
-do { \
- preempt_disable(); \
- __flush_tlb_all(); \
- preempt_enable(); \
-} while (0)
-
-#define flush_tlb_range(vma, start, end) \
-do { \
- unsigned long __s __attribute__((unused)) = (start); \
- unsigned long __e __attribute__((unused)) = (end); \
- preempt_disable(); \
- __flush_tlb_all(); \
- preempt_enable(); \
-} while (0)
-
-
-#define __flush_tlb_global() flush_tlb_all()
-#define flush_tlb() flush_tlb_all()
-#define flush_tlb_kernel_range(start, end) \
-do { \
- unsigned long __s __attribute__((unused)) = (start); \
- unsigned long __e __attribute__((unused)) = (end); \
- flush_tlb_all(); \
-} while (0)
-
-extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr);
-
-#define flush_tlb_pgtables(mm, start, end) do {} while (0)
+#ifdef CONFIG_SMP
+
+#include <asm/smp.h>
+
+extern void flush_tlb_all(void);
+extern void flush_tlb_current_task(void);
+extern void flush_tlb_mm(struct mm_struct *);
+extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
+
+#define flush_tlb() flush_tlb_current_task()
+
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ flush_tlb_mm(vma->vm_mm);
+}
+
+#else /* CONFIG_SMP */
+
+static inline void flush_tlb_all(void)
+{
+ preempt_disable();
+ local_flush_tlb_all();
+ preempt_enable();
+}
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+ preempt_disable();
+ local_flush_tlb_all();
+ preempt_enable();
+}
+
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ preempt_disable();
+ local_flush_tlb_all();
+ preempt_enable();
+}
+
+#define flush_tlb_page(vma, addr) local_flush_tlb_page((vma)->vm_mm, addr)
+#define flush_tlb() flush_tlb_all()
+
+#endif /* CONFIG_SMP */
+
+static inline void flush_tlb_kernel_range(unsigned long start,
+ unsigned long end)
+{
+ flush_tlb_all();
+}
+
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+}
#endif /* _ASM_TLBFLUSH_H */
diff --git a/arch/mn10300/include/asm/uaccess.h b/arch/mn10300/include/asm/uaccess.h
index 197a7af3dd8a..679dee0bbd08 100644
--- a/arch/mn10300/include/asm/uaccess.h
+++ b/arch/mn10300/include/asm/uaccess.h
@@ -14,9 +14,8 @@
/*
* User space memory access functions
*/
-#include <linux/sched.h>
+#include <linux/thread_info.h>
#include <asm/page.h>
-#include <asm/pgtable.h>
#include <asm/errno.h>
#define VERIFY_READ 0
@@ -29,7 +28,6 @@
*
* For historical reasons, these macros are grossly misnamed.
*/
-
#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
#define KERNEL_XDS MAKE_MM_SEG(0xBFFFFFFF)
@@ -377,7 +375,7 @@ unsigned long __generic_copy_to_user_nocheck(void *to, const void *from,
#if 0
-#error don't use - these macros don't increment to & from pointers
+#error "don't use - these macros don't increment to & from pointers"
/* Optimize just a little bit when we know the size of the move. */
#define __constant_copy_user(to, from, size) \
do { \
diff --git a/arch/mn10300/kernel/Makefile b/arch/mn10300/kernel/Makefile
index 23f2ab67574c..8f5f1e81baf5 100644
--- a/arch/mn10300/kernel/Makefile
+++ b/arch/mn10300/kernel/Makefile
@@ -3,13 +3,16 @@
#
extra-y := head.o init_task.o vmlinux.lds
-obj-y := process.o signal.o entry.o fpu.o traps.o irq.o \
+fpu-obj-y := fpu-nofpu.o fpu-nofpu-low.o
+fpu-obj-$(CONFIG_FPU) := fpu.o fpu-low.o
+
+obj-y := process.o signal.o entry.o traps.o irq.o \
ptrace.o setup.o time.o sys_mn10300.o io.o kthread.o \
- switch_to.o mn10300_ksyms.o kernel_execve.o
+ switch_to.o mn10300_ksyms.o kernel_execve.o $(fpu-obj-y)
-obj-$(CONFIG_MN10300_WD_TIMER) += mn10300-watchdog.o mn10300-watchdog-low.o
+obj-$(CONFIG_SMP) += smp.o smp-low.o
-obj-$(CONFIG_FPU) += fpu-low.o
+obj-$(CONFIG_MN10300_WD_TIMER) += mn10300-watchdog.o mn10300-watchdog-low.o
obj-$(CONFIG_MN10300_TTYSM) += mn10300-serial.o mn10300-serial-low.o \
mn10300-debug.o
@@ -17,7 +20,7 @@ obj-$(CONFIG_GDBSTUB) += gdb-stub.o gdb-low.o
obj-$(CONFIG_GDBSTUB_ON_TTYSx) += gdb-io-serial.o gdb-io-serial-low.o
obj-$(CONFIG_GDBSTUB_ON_TTYSMx) += gdb-io-ttysm.o gdb-io-ttysm-low.o
-ifneq ($(CONFIG_MN10300_CACHE_DISABLED),y)
+ifeq ($(CONFIG_MN10300_CACHE_ENABLED),y)
obj-$(CONFIG_GDBSTUB) += gdb-cache.o
endif
@@ -25,3 +28,5 @@ obj-$(CONFIG_MN10300_RTC) += rtc.o
obj-$(CONFIG_PROFILE) += profile.o profile-low.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_KPROBES) += kprobes.o
+obj-$(CONFIG_CSRC_MN10300) += csrc-mn10300.o
+obj-$(CONFIG_CEVT_MN10300) += cevt-mn10300.o
diff --git a/arch/mn10300/kernel/asm-offsets.c b/arch/mn10300/kernel/asm-offsets.c
index 02dc7e461fef..96f24fab7de6 100644
--- a/arch/mn10300/kernel/asm-offsets.c
+++ b/arch/mn10300/kernel/asm-offsets.c
@@ -23,6 +23,7 @@ void foo(void)
OFFSET(TI_task, thread_info, task);
OFFSET(TI_exec_domain, thread_info, exec_domain);
+ OFFSET(TI_frame, thread_info, frame);
OFFSET(TI_flags, thread_info, flags);
OFFSET(TI_cpu, thread_info, cpu);
OFFSET(TI_preempt_count, thread_info, preempt_count);
@@ -66,7 +67,15 @@ void foo(void)
OFFSET(THREAD_SP, thread_struct, sp);
OFFSET(THREAD_A3, thread_struct, a3);
OFFSET(THREAD_USP, thread_struct, usp);
- OFFSET(THREAD_FRAME, thread_struct, __frame);
+#ifdef CONFIG_FPU
+ OFFSET(THREAD_FPU_FLAGS, thread_struct, fpu_flags);
+ OFFSET(THREAD_FPU_STATE, thread_struct, fpu_state);
+ DEFINE(__THREAD_USING_FPU, THREAD_USING_FPU);
+ DEFINE(__THREAD_HAS_FPU, THREAD_HAS_FPU);
+#endif /* CONFIG_FPU */
+ BLANK();
+
+ OFFSET(TASK_THREAD, task_struct, thread);
BLANK();
DEFINE(CLONE_VM_asm, CLONE_VM);
diff --git a/arch/mn10300/kernel/cevt-mn10300.c b/arch/mn10300/kernel/cevt-mn10300.c
new file mode 100644
index 000000000000..d4cb535bf786
--- /dev/null
+++ b/arch/mn10300/kernel/cevt-mn10300.c
@@ -0,0 +1,131 @@
+/* MN10300 clockevents
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by Mark Salter (msalter@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+#include <linux/smp.h>
+#include <asm/timex.h>
+#include "internal.h"
+
+#ifdef CONFIG_SMP
+#if (CONFIG_NR_CPUS > 2) && !defined(CONFIG_GEENERIC_CLOCKEVENTS_BROADCAST)
+#error "This doesn't scale well! Need per-core local timers."
+#endif
+#else /* CONFIG_SMP */
+#define stop_jiffies_counter1()
+#define reload_jiffies_counter1(x)
+#define TMJC1IRQ TMJCIRQ
+#endif
+
+
+static int next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ unsigned int cpu = smp_processor_id();
+
+ if (cpu == 0) {
+ stop_jiffies_counter();
+ reload_jiffies_counter(delta - 1);
+ } else {
+ stop_jiffies_counter1();
+ reload_jiffies_counter1(delta - 1);
+ }
+ return 0;
+}
+
+static void set_clock_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ /* Nothing to do ... */
+}
+
+static DEFINE_PER_CPU(struct clock_event_device, mn10300_clockevent_device);
+static DEFINE_PER_CPU(struct irqaction, timer_irq);
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *cd;
+ unsigned int cpu = smp_processor_id();
+
+ if (cpu == 0)
+ stop_jiffies_counter();
+ else
+ stop_jiffies_counter1();
+
+ cd = &per_cpu(mn10300_clockevent_device, cpu);
+ cd->event_handler(cd);
+
+ return IRQ_HANDLED;
+}
+
+static void event_handler(struct clock_event_device *dev)
+{
+}
+
+int __init init_clockevents(void)
+{
+ struct clock_event_device *cd;
+ struct irqaction *iact;
+ unsigned int cpu = smp_processor_id();
+
+ cd = &per_cpu(mn10300_clockevent_device, cpu);
+
+ if (cpu == 0) {
+ stop_jiffies_counter();
+ cd->irq = TMJCIRQ;
+ } else {
+ stop_jiffies_counter1();
+ cd->irq = TMJC1IRQ;
+ }
+
+ cd->name = "Timestamp";
+ cd->features = CLOCK_EVT_FEAT_ONESHOT;
+
+ /* Calculate the min / max delta */
+ clockevent_set_clock(cd, MN10300_JCCLK);
+
+ cd->max_delta_ns = clockevent_delta2ns(TMJCBR_MAX, cd);
+ cd->min_delta_ns = clockevent_delta2ns(100, cd);
+
+ cd->rating = 200;
+ cd->cpumask = cpumask_of(smp_processor_id());
+ cd->set_mode = set_clock_mode;
+ cd->event_handler = event_handler;
+ cd->set_next_event = next_event;
+
+ iact = &per_cpu(timer_irq, cpu);
+ iact->flags = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER;
+ iact->handler = timer_interrupt;
+
+ clockevents_register_device(cd);
+
+#if defined(CONFIG_SMP) && !defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+ /* setup timer irq affinity so it only runs on this cpu */
+ {
+ struct irq_desc *desc;
+ desc = irq_to_desc(cd->irq);
+ cpumask_copy(desc->affinity, cpumask_of(cpu));
+ iact->flags |= IRQF_NOBALANCING;
+ }
+#endif
+
+ if (cpu == 0) {
+ reload_jiffies_counter(MN10300_JC_PER_HZ - 1);
+ iact->name = "CPU0 Timer";
+ } else {
+ reload_jiffies_counter1(MN10300_JC_PER_HZ - 1);
+ iact->name = "CPU1 Timer";
+ }
+
+ setup_jiffies_interrupt(cd->irq, iact);
+
+ return 0;
+}
diff --git a/arch/mn10300/kernel/csrc-mn10300.c b/arch/mn10300/kernel/csrc-mn10300.c
new file mode 100644
index 000000000000..ba2f0c4d6e01
--- /dev/null
+++ b/arch/mn10300/kernel/csrc-mn10300.c
@@ -0,0 +1,35 @@
+/* MN10300 clocksource
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by Mark Salter (msalter@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/clocksource.h>
+#include <linux/init.h>
+#include <asm/timex.h>
+#include "internal.h"
+
+static cycle_t mn10300_read(struct clocksource *cs)
+{
+ return read_timestamp_counter();
+}
+
+static struct clocksource clocksource_mn10300 = {
+ .name = "TSC",
+ .rating = 200,
+ .read = mn10300_read,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+int __init init_clocksource(void)
+{
+ startup_timestamp_counter();
+ clocksource_set_clock(&clocksource_mn10300, MN10300_TSCCLK);
+ clocksource_register(&clocksource_mn10300);
+ return 0;
+}
diff --git a/arch/mn10300/kernel/entry.S b/arch/mn10300/kernel/entry.S
index 3d394b4eefba..f00b9bafcd3e 100644
--- a/arch/mn10300/kernel/entry.S
+++ b/arch/mn10300/kernel/entry.S
@@ -28,25 +28,17 @@
#include <asm/asm-offsets.h>
#include <asm/frame.inc>
+#if defined(CONFIG_SMP) && defined(CONFIG_GDBSTUB)
+#include <asm/gdb-stub.h>
+#endif /* CONFIG_SMP && CONFIG_GDBSTUB */
+
#ifdef CONFIG_PREEMPT
-#define preempt_stop __cli
+#define preempt_stop LOCAL_IRQ_DISABLE
#else
#define preempt_stop
#define resume_kernel restore_all
#endif
- .macro __cli
- and ~EPSW_IM,epsw
- or EPSW_IE|MN10300_CLI_LEVEL,epsw
- nop
- nop
- nop
- .endm
- .macro __sti
- or EPSW_IE|EPSW_IM_7,epsw
- .endm
-
-
.am33_2
###############################################################################
@@ -88,7 +80,7 @@ syscall_call:
syscall_exit:
# make sure we don't miss an interrupt setting need_resched or
# sigpending between sampling and the rti
- __cli
+ LOCAL_IRQ_DISABLE
mov (TI_flags,a2),d2
btst _TIF_ALLWORK_MASK,d2
bne syscall_exit_work
@@ -105,7 +97,7 @@ restore_all:
syscall_exit_work:
btst _TIF_SYSCALL_TRACE,d2
beq work_pending
- __sti # could let syscall_trace_exit() call
+ LOCAL_IRQ_ENABLE # could let syscall_trace_exit() call
# schedule() instead
mov fp,d0
call syscall_trace_exit[],0 # do_syscall_trace(regs)
@@ -121,7 +113,7 @@ work_resched:
# make sure we don't miss an interrupt setting need_resched or
# sigpending between sampling and the rti
- __cli
+ LOCAL_IRQ_DISABLE
# is there any work to be done other than syscall tracing?
mov (TI_flags,a2),d2
@@ -168,7 +160,7 @@ ret_from_intr:
ENTRY(resume_userspace)
# make sure we don't miss an interrupt setting need_resched or
# sigpending between sampling and the rti
- __cli
+ LOCAL_IRQ_DISABLE
# is there any work to be done on int/exception return?
mov (TI_flags,a2),d2
@@ -178,7 +170,7 @@ ENTRY(resume_userspace)
#ifdef CONFIG_PREEMPT
ENTRY(resume_kernel)
- __cli
+ LOCAL_IRQ_DISABLE
mov (TI_preempt_count,a2),d0 # non-zero preempt_count ?
cmp 0,d0
bne restore_all
@@ -216,31 +208,6 @@ ENTRY(irq_handler)
###############################################################################
#
-# Monitor Signal handler entry point
-#
-###############################################################################
-ENTRY(monitor_signal)
- movbu (0xae000001),d1
- cmp 1,d1
- beq monsignal
- ret [],0
-
-monsignal:
- or EPSW_NMID,epsw
- mov d0,a0
- mov a0,sp
- mov (REG_EPSW,fp),d1
- and ~EPSW_nSL,d1
- mov d1,(REG_EPSW,fp)
- movm (sp),[d2,d3,a2,a3,exreg0,exreg1,exother]
- mov (sp),a1
- mov a1,usp
- movm (sp),[other]
- add 4,sp
-here: jmp 0x8e000008-here+0x8e000008
-
-###############################################################################
-#
# Double Fault handler entry point
# - note that there will not be a stack, D0/A0 will hold EPSW/PC as were
#
@@ -276,6 +243,10 @@ double_fault_loop:
ENTRY(raw_bus_error)
add -4,sp
mov d0,(sp)
+#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR)
+ mov (MMUCTR),d0
+ mov d0,(MMUCTR)
+#endif
mov (BCBERR),d0 # what
btst BCBERR_BEMR_DMA,d0 # see if it was an external bus error
beq __common_exception_aux # it wasn't
@@ -302,11 +273,88 @@ ENTRY(nmi_handler)
add -4,sp
mov d0,(sp)
mov (TBR),d0
+
+#ifdef CONFIG_SMP
+ add -4,sp
+ mov d0,(sp) # save d0(TBR)
+ movhu (NMIAGR),d0
+ and NMIAGR_GN,d0
+ lsr 0x2,d0
+ cmp CALL_FUNCTION_NMI_IPI,d0
+ bne 5f # if not call function, jump
+
+ # function call nmi ipi
+ add 4,sp # no need to store TBR
+ mov GxICR_DETECT,d0 # clear NMI request
+ movbu d0,(GxICR(CALL_FUNCTION_NMI_IPI))
+ movhu (GxICR(CALL_FUNCTION_NMI_IPI)),d0
+ and ~EPSW_NMID,epsw # enable NMI
+
+ mov (sp),d0 # restore d0
+ SAVE_ALL
+ call smp_nmi_call_function_interrupt[],0
+ RESTORE_ALL
+
+5:
+#ifdef CONFIG_GDBSTUB
+ cmp GDB_NMI_IPI,d0
+ bne 3f # if not gdb nmi ipi, jump
+
+ # gdb nmi ipi
+ add 4,sp # no need to store TBR
+ mov GxICR_DETECT,d0 # clear NMI
+ movbu d0,(GxICR(GDB_NMI_IPI))
+ movhu (GxICR(GDB_NMI_IPI)),d0
+ and ~EPSW_NMID,epsw # enable NMI
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+ mov (gdbstub_nmi_opr_type),d0
+ cmp GDBSTUB_NMI_CACHE_PURGE,d0
+ bne 4f # if not gdb cache purge, jump
+
+ # gdb cache purge nmi ipi
+ add -20,sp
+ mov d1,(4,sp)
+ mov a0,(8,sp)
+ mov a1,(12,sp)
+ mov mdr,d0
+ mov d0,(16,sp)
+ call gdbstub_local_purge_cache[],0
+ mov 0x1,d0
+ mov (CPUID),d1
+ asl d1,d0
+ mov gdbstub_nmi_cpumask,a0
+ bclr d0,(a0)
+ mov (4,sp),d1
+ mov (8,sp),a0
+ mov (12,sp),a1
+ mov (16,sp),d0
+ mov d0,mdr
+ add 20,sp
+ mov (sp),d0
+ add 4,sp
+ rti
+4:
+#endif /* CONFIG_MN10300_CACHE_ENABLED */
+ # gdb wait nmi ipi
+ mov (sp),d0
+ SAVE_ALL
+ call gdbstub_nmi_wait[],0
+ RESTORE_ALL
+3:
+#endif /* CONFIG_GDBSTUB */
+ mov (sp),d0 # restore TBR to d0
+ add 4,sp
+#endif /* CONFIG_SMP */
+
bra __common_exception_nonmi
ENTRY(__common_exception)
add -4,sp
mov d0,(sp)
+#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR)
+ mov (MMUCTR),d0
+ mov d0,(MMUCTR)
+#endif
__common_exception_aux:
mov (TBR),d0
@@ -331,15 +379,21 @@ __common_exception_nonmi:
mov d0,(REG_ORIG_D0,fp)
#ifdef CONFIG_GDBSTUB
+#ifdef CONFIG_SMP
+ call gdbstub_busy_check[],0
+ and d0,d0 # check return value
+ beq 2f
+#else /* CONFIG_SMP */
btst 0x01,(gdbstub_busy)
beq 2f
+#endif /* CONFIG_SMP */
and ~EPSW_IE,epsw
mov fp,d0
mov a2,d1
call gdbstub_exception[],0 # gdbstub itself caused an exception
bra restore_all
2:
-#endif
+#endif /* CONFIG_GDBSTUB */
mov fp,d0 # arg 0: stacked register file
mov a2,d1 # arg 1: exception number
@@ -374,11 +428,7 @@ ENTRY(set_excp_vector)
add exception_table,d0
mov d1,(d0)
mov 4,d1
-#if defined(CONFIG_MN10300_CACHE_WBACK)
- jmp mn10300_dcache_flush_inv_range2
-#else
ret [],0
-#endif
###############################################################################
#
diff --git a/arch/mn10300/kernel/fpu-low.S b/arch/mn10300/kernel/fpu-low.S
index 96cfd47e68d5..78df25cfae29 100644
--- a/arch/mn10300/kernel/fpu-low.S
+++ b/arch/mn10300/kernel/fpu-low.S
@@ -8,25 +8,14 @@
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
+#include <linux/linkage.h>
#include <asm/cpu-regs.h>
+#include <asm/smp.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+#include <asm/frame.inc>
-###############################################################################
-#
-# void fpu_init_state(void)
-# - initialise the FPU
-#
-###############################################################################
- .globl fpu_init_state
- .type fpu_init_state,@function
-fpu_init_state:
- mov epsw,d0
- or EPSW_FE,epsw
-
-#ifdef CONFIG_MN10300_PROC_MN103E010
- nop
- nop
- nop
-#endif
+.macro FPU_INIT_STATE_ALL
fmov 0,fs0
fmov fs0,fs1
fmov fs0,fs2
@@ -60,7 +49,100 @@ fpu_init_state:
fmov fs0,fs30
fmov fs0,fs31
fmov FPCR_INIT,fpcr
+.endm
+
+.macro FPU_SAVE_ALL areg,dreg
+ fmov fs0,(\areg+)
+ fmov fs1,(\areg+)
+ fmov fs2,(\areg+)
+ fmov fs3,(\areg+)
+ fmov fs4,(\areg+)
+ fmov fs5,(\areg+)
+ fmov fs6,(\areg+)
+ fmov fs7,(\areg+)
+ fmov fs8,(\areg+)
+ fmov fs9,(\areg+)
+ fmov fs10,(\areg+)
+ fmov fs11,(\areg+)
+ fmov fs12,(\areg+)
+ fmov fs13,(\areg+)
+ fmov fs14,(\areg+)
+ fmov fs15,(\areg+)
+ fmov fs16,(\areg+)
+ fmov fs17,(\areg+)
+ fmov fs18,(\areg+)
+ fmov fs19,(\areg+)
+ fmov fs20,(\areg+)
+ fmov fs21,(\areg+)
+ fmov fs22,(\areg+)
+ fmov fs23,(\areg+)
+ fmov fs24,(\areg+)
+ fmov fs25,(\areg+)
+ fmov fs26,(\areg+)
+ fmov fs27,(\areg+)
+ fmov fs28,(\areg+)
+ fmov fs29,(\areg+)
+ fmov fs30,(\areg+)
+ fmov fs31,(\areg+)
+ fmov fpcr,\dreg
+ mov \dreg,(\areg)
+.endm
+
+.macro FPU_RESTORE_ALL areg,dreg
+ fmov (\areg+),fs0
+ fmov (\areg+),fs1
+ fmov (\areg+),fs2
+ fmov (\areg+),fs3
+ fmov (\areg+),fs4
+ fmov (\areg+),fs5
+ fmov (\areg+),fs6
+ fmov (\areg+),fs7
+ fmov (\areg+),fs8
+ fmov (\areg+),fs9
+ fmov (\areg+),fs10
+ fmov (\areg+),fs11
+ fmov (\areg+),fs12
+ fmov (\areg+),fs13
+ fmov (\areg+),fs14
+ fmov (\areg+),fs15
+ fmov (\areg+),fs16
+ fmov (\areg+),fs17
+ fmov (\areg+),fs18
+ fmov (\areg+),fs19
+ fmov (\areg+),fs20
+ fmov (\areg+),fs21
+ fmov (\areg+),fs22
+ fmov (\areg+),fs23
+ fmov (\areg+),fs24
+ fmov (\areg+),fs25
+ fmov (\areg+),fs26
+ fmov (\areg+),fs27
+ fmov (\areg+),fs28
+ fmov (\areg+),fs29
+ fmov (\areg+),fs30
+ fmov (\areg+),fs31
+ mov (\areg),\dreg
+ fmov \dreg,fpcr
+.endm
+###############################################################################
+#
+# void fpu_init_state(void)
+# - initialise the FPU
+#
+###############################################################################
+ .globl fpu_init_state
+ .type fpu_init_state,@function
+fpu_init_state:
+ mov epsw,d0
+ or EPSW_FE,epsw
+
+#ifdef CONFIG_MN10300_PROC_MN103E010
+ nop
+ nop
+ nop
+#endif
+ FPU_INIT_STATE_ALL
#ifdef CONFIG_MN10300_PROC_MN103E010
nop
nop
@@ -89,40 +171,7 @@ fpu_save:
nop
#endif
mov d0,a0
- fmov fs0,(a0+)
- fmov fs1,(a0+)
- fmov fs2,(a0+)
- fmov fs3,(a0+)
- fmov fs4,(a0+)
- fmov fs5,(a0+)
- fmov fs6,(a0+)
- fmov fs7,(a0+)
- fmov fs8,(a0+)
- fmov fs9,(a0+)
- fmov fs10,(a0+)
- fmov fs11,(a0+)
- fmov fs12,(a0+)
- fmov fs13,(a0+)
- fmov fs14,(a0+)
- fmov fs15,(a0+)
- fmov fs16,(a0+)
- fmov fs17,(a0+)
- fmov fs18,(a0+)
- fmov fs19,(a0+)
- fmov fs20,(a0+)
- fmov fs21,(a0+)
- fmov fs22,(a0+)
- fmov fs23,(a0+)
- fmov fs24,(a0+)
- fmov fs25,(a0+)
- fmov fs26,(a0+)
- fmov fs27,(a0+)
- fmov fs28,(a0+)
- fmov fs29,(a0+)
- fmov fs30,(a0+)
- fmov fs31,(a0+)
- fmov fpcr,d0
- mov d0,(a0)
+ FPU_SAVE_ALL a0,d0
#ifdef CONFIG_MN10300_PROC_MN103E010
nop
nop
@@ -135,63 +184,75 @@ fpu_save:
###############################################################################
#
-# void fpu_restore(struct fpu_state_struct *)
-# - restore the fpu state
-# - note that an FPU Operational exception might occur during this process
+# void fpu_disabled(void)
+# - handle an exception due to the FPU being disabled
+# when CONFIG_FPU is enabled
#
###############################################################################
- .globl fpu_restore
- .type fpu_restore,@function
-fpu_restore:
- mov epsw,d1
- or EPSW_FE,epsw /* enable the FPU so we can access it */
-
-#ifdef CONFIG_MN10300_PROC_MN103E010
+ .type fpu_disabled,@function
+ .globl fpu_disabled
+fpu_disabled:
+ or EPSW_nAR|EPSW_FE,epsw
nop
nop
-#endif
- mov d0,a0
- fmov (a0+),fs0
- fmov (a0+),fs1
- fmov (a0+),fs2
- fmov (a0+),fs3
- fmov (a0+),fs4
- fmov (a0+),fs5
- fmov (a0+),fs6
- fmov (a0+),fs7
- fmov (a0+),fs8
- fmov (a0+),fs9
- fmov (a0+),fs10
- fmov (a0+),fs11
- fmov (a0+),fs12
- fmov (a0+),fs13
- fmov (a0+),fs14
- fmov (a0+),fs15
- fmov (a0+),fs16
- fmov (a0+),fs17
- fmov (a0+),fs18
- fmov (a0+),fs19
- fmov (a0+),fs20
- fmov (a0+),fs21
- fmov (a0+),fs22
- fmov (a0+),fs23
- fmov (a0+),fs24
- fmov (a0+),fs25
- fmov (a0+),fs26
- fmov (a0+),fs27
- fmov (a0+),fs28
- fmov (a0+),fs29
- fmov (a0+),fs30
- fmov (a0+),fs31
- mov (a0),d0
- fmov d0,fpcr
-#ifdef CONFIG_MN10300_PROC_MN103E010
nop
+
+ mov sp,a1
+ mov (a1),d1 /* get epsw of user context */
+ and ~(THREAD_SIZE-1),a1 /* a1: (thread_info *ti) */
+ mov (TI_task,a1),a2 /* a2: (task_struct *tsk) */
+ btst EPSW_nSL,d1
+ beq fpu_used_in_kernel
+
+ or EPSW_FE,d1
+ mov d1,(sp)
+ mov (TASK_THREAD+THREAD_FPU_FLAGS,a2),d1
+#ifndef CONFIG_LAZY_SAVE_FPU
+ or __THREAD_HAS_FPU,d1
+ mov d1,(TASK_THREAD+THREAD_FPU_FLAGS,a2)
+#else /* !CONFIG_LAZY_SAVE_FPU */
+ mov (fpu_state_owner),a0
+ cmp 0,a0
+ beq fpu_regs_save_end
+
+ mov (TASK_THREAD+THREAD_UREGS,a0),a1
+ add TASK_THREAD+THREAD_FPU_STATE,a0
+ FPU_SAVE_ALL a0,d0
+
+ mov (REG_EPSW,a1),d0
+ and ~EPSW_FE,d0
+ mov d0,(REG_EPSW,a1)
+
+fpu_regs_save_end:
+ mov a2,(fpu_state_owner)
+#endif /* !CONFIG_LAZY_SAVE_FPU */
+
+ btst __THREAD_USING_FPU,d1
+ beq fpu_regs_init
+ add TASK_THREAD+THREAD_FPU_STATE,a2
+ FPU_RESTORE_ALL a2,d0
+ rti
+
+fpu_regs_init:
+ FPU_INIT_STATE_ALL
+ add TASK_THREAD+THREAD_FPU_FLAGS,a2
+ bset __THREAD_USING_FPU,(0,a2)
+ rti
+
+fpu_used_in_kernel:
+ and ~(EPSW_nAR|EPSW_FE),epsw
nop
nop
-#endif
- mov d1,epsw
- ret [],0
+ add -4,sp
+ SAVE_ALL
+ mov -1,d0
+ mov d0,(REG_ORIG_D0,fp)
+
+ and ~EPSW_NMID,epsw
+
+ mov fp,d0
+ call fpu_disabled_in_kernel[],0
+ jmp ret_from_exception
- .size fpu_restore,.-fpu_restore
+ .size fpu_disabled,.-fpu_disabled
diff --git a/arch/mn10300/kernel/fpu-nofpu-low.S b/arch/mn10300/kernel/fpu-nofpu-low.S
new file mode 100644
index 000000000000..7ea087a549f4
--- /dev/null
+++ b/arch/mn10300/kernel/fpu-nofpu-low.S
@@ -0,0 +1,39 @@
+/* MN10300 Low level FPU management operations
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/linkage.h>
+#include <asm/cpu-regs.h>
+#include <asm/smp.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+#include <asm/frame.inc>
+
+###############################################################################
+#
+# void fpu_disabled(void)
+# - handle an exception due to the FPU being disabled
+# when CONFIG_FPU is disabled
+#
+###############################################################################
+ .type fpu_disabled,@function
+ .globl fpu_disabled
+fpu_disabled:
+ add -4,sp
+ SAVE_ALL
+ mov -1,d0
+ mov d0,(REG_ORIG_D0,fp)
+
+ and ~EPSW_NMID,epsw
+
+ mov fp,d0
+ call unexpected_fpu_exception[],0
+ jmp ret_from_exception
+
+ .size fpu_disabled,.-fpu_disabled
diff --git a/arch/mn10300/kernel/fpu-nofpu.c b/arch/mn10300/kernel/fpu-nofpu.c
new file mode 100644
index 000000000000..31c765b92c5d
--- /dev/null
+++ b/arch/mn10300/kernel/fpu-nofpu.c
@@ -0,0 +1,30 @@
+/* MN10300 FPU management
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <asm/fpu.h>
+
+/*
+ * handle an FPU operational exception
+ * - there's a possibility that if the FPU is asynchronous, the signal might
+ * be meant for a process other than the current one
+ */
+asmlinkage
+void unexpected_fpu_exception(struct pt_regs *regs, enum exception_code code)
+{
+ panic("An FPU exception was received, but there's no FPU enabled.");
+}
+
+/*
+ * fill in the FPU structure for a core dump
+ */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpreg)
+{
+ return 0; /* not valid */
+}
diff --git a/arch/mn10300/kernel/fpu.c b/arch/mn10300/kernel/fpu.c
index e705f25ad5ff..5f9c3fa19a85 100644
--- a/arch/mn10300/kernel/fpu.c
+++ b/arch/mn10300/kernel/fpu.c
@@ -12,56 +12,19 @@
#include <asm/fpu.h>
#include <asm/elf.h>
#include <asm/exceptions.h>
+#include <asm/system.h>
+#ifdef CONFIG_LAZY_SAVE_FPU
struct task_struct *fpu_state_owner;
+#endif
/*
- * handle an exception due to the FPU being disabled
+ * error functions in FPU disabled exception
*/
-asmlinkage void fpu_disabled(struct pt_regs *regs, enum exception_code code)
+asmlinkage void fpu_disabled_in_kernel(struct pt_regs *regs)
{
- struct task_struct *tsk = current;
-
- if (!user_mode(regs))
- die_if_no_fixup("An FPU Disabled exception happened in"
- " kernel space\n",
- regs, code);
-
-#ifdef CONFIG_FPU
- preempt_disable();
-
- /* transfer the last process's FPU state to memory */
- if (fpu_state_owner) {
- fpu_save(&fpu_state_owner->thread.fpu_state);
- fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
- }
-
- /* the current process now owns the FPU state */
- fpu_state_owner = tsk;
- regs->epsw |= EPSW_FE;
-
- /* load the FPU with the current process's FPU state or invent a new
- * clean one if the process doesn't have one */
- if (is_using_fpu(tsk)) {
- fpu_restore(&tsk->thread.fpu_state);
- } else {
- fpu_init_state();
- set_using_fpu(tsk);
- }
-
- preempt_enable();
-#else
- {
- siginfo_t info;
-
- info.si_signo = SIGFPE;
- info.si_errno = 0;
- info.si_addr = (void *) tsk->thread.uregs->pc;
- info.si_code = FPE_FLTINV;
-
- force_sig_info(SIGFPE, &info, tsk);
- }
-#endif /* CONFIG_FPU */
+ die_if_no_fixup("An FPU Disabled exception happened in kernel space\n",
+ regs, EXCEP_FPU_DISABLED);
}
/*
@@ -71,15 +34,16 @@ asmlinkage void fpu_disabled(struct pt_regs *regs, enum exception_code code)
*/
asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code)
{
- struct task_struct *tsk = fpu_state_owner;
+ struct task_struct *tsk = current;
siginfo_t info;
+ u32 fpcr;
if (!user_mode(regs))
die_if_no_fixup("An FPU Operation exception happened in"
" kernel space\n",
regs, code);
- if (!tsk)
+ if (!is_using_fpu(tsk))
die_if_no_fixup("An FPU Operation exception happened,"
" but the FPU is not in use",
regs, code);
@@ -89,48 +53,45 @@ asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code)
info.si_addr = (void *) tsk->thread.uregs->pc;
info.si_code = FPE_FLTINV;
-#ifdef CONFIG_FPU
- {
- u32 fpcr;
+ unlazy_fpu(tsk);
- /* get FPCR (we need to enable the FPU whilst we do this) */
- asm volatile(" or %1,epsw \n"
-#ifdef CONFIG_MN10300_PROC_MN103E010
- " nop \n"
- " nop \n"
- " nop \n"
-#endif
- " fmov fpcr,%0 \n"
-#ifdef CONFIG_MN10300_PROC_MN103E010
- " nop \n"
- " nop \n"
- " nop \n"
-#endif
- " and %2,epsw \n"
- : "=&d"(fpcr)
- : "i"(EPSW_FE), "i"(~EPSW_FE)
- );
-
- if (fpcr & FPCR_EC_Z)
- info.si_code = FPE_FLTDIV;
- else if (fpcr & FPCR_EC_O)
- info.si_code = FPE_FLTOVF;
- else if (fpcr & FPCR_EC_U)
- info.si_code = FPE_FLTUND;
- else if (fpcr & FPCR_EC_I)
- info.si_code = FPE_FLTRES;
- }
-#endif
+ fpcr = tsk->thread.fpu_state.fpcr;
+
+ if (fpcr & FPCR_EC_Z)
+ info.si_code = FPE_FLTDIV;
+ else if (fpcr & FPCR_EC_O)
+ info.si_code = FPE_FLTOVF;
+ else if (fpcr & FPCR_EC_U)
+ info.si_code = FPE_FLTUND;
+ else if (fpcr & FPCR_EC_I)
+ info.si_code = FPE_FLTRES;
force_sig_info(SIGFPE, &info, tsk);
}
/*
+ * handle an FPU invalid_op exception
+ * - Derived from DO_EINFO() macro in arch/mn10300/kernel/traps.c
+ */
+asmlinkage void fpu_invalid_op(struct pt_regs *regs, enum exception_code code)
+{
+ siginfo_t info;
+
+ if (!user_mode(regs))
+ die_if_no_fixup("FPU invalid opcode", regs, code);
+
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = ILL_COPROC;
+ info.si_addr = (void *) regs->pc;
+ force_sig_info(info.si_signo, &info, current);
+}
+
+/*
* save the FPU state to a signal context
*/
int fpu_setup_sigcontext(struct fpucontext *fpucontext)
{
-#ifdef CONFIG_FPU
struct task_struct *tsk = current;
if (!is_using_fpu(tsk))
@@ -142,11 +103,19 @@ int fpu_setup_sigcontext(struct fpucontext *fpucontext)
*/
preempt_disable();
+#ifndef CONFIG_LAZY_SAVE_FPU
+ if (tsk->thread.fpu_flags & THREAD_HAS_FPU) {
+ fpu_save(&tsk->thread.fpu_state);
+ tsk->thread.uregs->epsw &= ~EPSW_FE;
+ tsk->thread.fpu_flags &= ~THREAD_HAS_FPU;
+ }
+#else /* !CONFIG_LAZY_SAVE_FPU */
if (fpu_state_owner == tsk) {
fpu_save(&tsk->thread.fpu_state);
fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
fpu_state_owner = NULL;
}
+#endif /* !CONFIG_LAZY_SAVE_FPU */
preempt_enable();
@@ -161,9 +130,6 @@ int fpu_setup_sigcontext(struct fpucontext *fpucontext)
return -1;
return 1;
-#else
- return 0;
-#endif
}
/*
@@ -171,17 +137,23 @@ int fpu_setup_sigcontext(struct fpucontext *fpucontext)
*/
void fpu_kill_state(struct task_struct *tsk)
{
-#ifdef CONFIG_FPU
/* disown anything left in the FPU */
preempt_disable();
+#ifndef CONFIG_LAZY_SAVE_FPU
+ if (tsk->thread.fpu_flags & THREAD_HAS_FPU) {
+ tsk->thread.uregs->epsw &= ~EPSW_FE;
+ tsk->thread.fpu_flags &= ~THREAD_HAS_FPU;
+ }
+#else /* !CONFIG_LAZY_SAVE_FPU */
if (fpu_state_owner == tsk) {
fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
fpu_state_owner = NULL;
}
+#endif /* !CONFIG_LAZY_SAVE_FPU */
preempt_enable();
-#endif
+
/* we no longer have a valid current FPU state */
clear_using_fpu(tsk);
}
@@ -195,8 +167,7 @@ int fpu_restore_sigcontext(struct fpucontext *fpucontext)
int ret;
/* load up the old FPU state */
- ret = copy_from_user(&tsk->thread.fpu_state,
- fpucontext,
+ ret = copy_from_user(&tsk->thread.fpu_state, fpucontext,
min(sizeof(struct fpu_state_struct),
sizeof(struct fpucontext)));
if (!ret)
diff --git a/arch/mn10300/kernel/gdb-io-serial-low.S b/arch/mn10300/kernel/gdb-io-serial-low.S
index 4998b24f5d3a..b1d0152e96cb 100644
--- a/arch/mn10300/kernel/gdb-io-serial-low.S
+++ b/arch/mn10300/kernel/gdb-io-serial-low.S
@@ -18,6 +18,7 @@
#include <asm/thread_info.h>
#include <asm/frame.inc>
#include <asm/intctl-regs.h>
+#include <asm/irqflags.h>
#include <unit/serial.h>
.text
@@ -69,7 +70,7 @@ gdbstub_io_rx_overflow:
bra gdbstub_io_rx_done
gdbstub_io_rx_enter:
- or EPSW_IE|EPSW_IM_1,epsw
+ LOCAL_CHANGE_INTR_MASK_LEVEL(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL+1))
add -4,sp
SAVE_ALL
@@ -80,7 +81,7 @@ gdbstub_io_rx_enter:
mov fp,d0
call gdbstub_rx_irq[],0 # gdbstub_rx_irq(regs,excep)
- and ~EPSW_IE,epsw
+ LOCAL_CLI
bclr 0x01,(gdbstub_busy)
.globl gdbstub_return
diff --git a/arch/mn10300/kernel/gdb-io-serial.c b/arch/mn10300/kernel/gdb-io-serial.c
index ae663dc717e9..0d5d63c91dc3 100644
--- a/arch/mn10300/kernel/gdb-io-serial.c
+++ b/arch/mn10300/kernel/gdb-io-serial.c
@@ -23,6 +23,7 @@
#include <asm/exceptions.h>
#include <asm/serial-regs.h>
#include <unit/serial.h>
+#include <asm/smp.h>
/*
* initialise the GDB stub
@@ -45,22 +46,34 @@ void gdbstub_io_init(void)
XIRQxICR(GDBPORT_SERIAL_IRQ) = 0;
tmp = XIRQxICR(GDBPORT_SERIAL_IRQ);
+#if CONFIG_GDBSTUB_IRQ_LEVEL == 0
IVAR0 = EXCEP_IRQ_LEVEL0;
- set_intr_stub(EXCEP_IRQ_LEVEL0, gdbstub_io_rx_handler);
+#elif CONFIG_GDBSTUB_IRQ_LEVEL == 1
+ IVAR1 = EXCEP_IRQ_LEVEL1;
+#elif CONFIG_GDBSTUB_IRQ_LEVEL == 2
+ IVAR2 = EXCEP_IRQ_LEVEL2;
+#elif CONFIG_GDBSTUB_IRQ_LEVEL == 3
+ IVAR3 = EXCEP_IRQ_LEVEL3;
+#elif CONFIG_GDBSTUB_IRQ_LEVEL == 4
+ IVAR4 = EXCEP_IRQ_LEVEL4;
+#elif CONFIG_GDBSTUB_IRQ_LEVEL == 5
+ IVAR5 = EXCEP_IRQ_LEVEL5;
+#else
+#error "Unknown irq level for gdbstub."
+#endif
+
+ set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL),
+ gdbstub_io_rx_handler);
XIRQxICR(GDBPORT_SERIAL_IRQ) &= ~GxICR_REQUEST;
- XIRQxICR(GDBPORT_SERIAL_IRQ) = GxICR_ENABLE | GxICR_LEVEL_0;
+ XIRQxICR(GDBPORT_SERIAL_IRQ) =
+ GxICR_ENABLE | NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL);
tmp = XIRQxICR(GDBPORT_SERIAL_IRQ);
GDBPORT_SERIAL_IER = UART_IER_RDI | UART_IER_RLSI;
/* permit level 0 IRQs to take place */
- asm volatile(
- " and %0,epsw \n"
- " or %1,epsw \n"
- :
- : "i"(~EPSW_IM), "i"(EPSW_IE | EPSW_IM_1)
- );
+ local_change_intr_mask_level(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
}
/*
@@ -87,6 +100,9 @@ int gdbstub_io_rx_char(unsigned char *_ch, int nonblock)
{
unsigned ix;
u8 ch, st;
+#if defined(CONFIG_MN10300_WD_TIMER)
+ int cpu;
+#endif
*_ch = 0xff;
@@ -104,8 +120,9 @@ int gdbstub_io_rx_char(unsigned char *_ch, int nonblock)
if (nonblock)
return -EAGAIN;
#ifdef CONFIG_MN10300_WD_TIMER
- watchdog_alert_counter = 0;
-#endif /* CONFIG_MN10300_WD_TIMER */
+ for (cpu = 0; cpu < NR_CPUS; cpu++)
+ watchdog_alert_counter[cpu] = 0;
+#endif
goto try_again;
}
diff --git a/arch/mn10300/kernel/gdb-io-ttysm.c b/arch/mn10300/kernel/gdb-io-ttysm.c
index a560bbc3137d..97dfda23342c 100644
--- a/arch/mn10300/kernel/gdb-io-ttysm.c
+++ b/arch/mn10300/kernel/gdb-io-ttysm.c
@@ -58,9 +58,12 @@ void __init gdbstub_io_init(void)
gdbstub_io_set_baud(115200);
/* we want to get serial receive interrupts */
- set_intr_level(gdbstub_port->rx_irq, GxICR_LEVEL_0);
- set_intr_level(gdbstub_port->tx_irq, GxICR_LEVEL_0);
- set_intr_stub(EXCEP_IRQ_LEVEL0, gdbstub_io_rx_handler);
+ set_intr_level(gdbstub_port->rx_irq,
+ NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL));
+ set_intr_level(gdbstub_port->tx_irq,
+ NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL));
+ set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL),
+ gdbstub_io_rx_handler);
*gdbstub_port->rx_icr |= GxICR_ENABLE;
tmp = *gdbstub_port->rx_icr;
@@ -84,12 +87,7 @@ void __init gdbstub_io_init(void)
tmp = *gdbstub_port->_control;
/* permit level 0 IRQs only */
- asm volatile(
- " and %0,epsw \n"
- " or %1,epsw \n"
- :
- : "i"(~EPSW_IM), "i"(EPSW_IE|EPSW_IM_1)
- );
+ local_change_intr_mask_level(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
}
/*
@@ -184,6 +182,9 @@ int gdbstub_io_rx_char(unsigned char *_ch, int nonblock)
{
unsigned ix;
u8 ch, st;
+#if defined(CONFIG_MN10300_WD_TIMER)
+ int cpu;
+#endif
*_ch = 0xff;
@@ -201,8 +202,9 @@ try_again:
if (nonblock)
return -EAGAIN;
#ifdef CONFIG_MN10300_WD_TIMER
- watchdog_alert_counter = 0;
-#endif /* CONFIG_MN10300_WD_TIMER */
+ for (cpu = 0; cpu < NR_CPUS; cpu++)
+ watchdog_alert_counter[cpu] = 0;
+#endif
goto try_again;
}
diff --git a/arch/mn10300/kernel/gdb-stub.c b/arch/mn10300/kernel/gdb-stub.c
index 41b11706c8ed..a5fc3f05309b 100644
--- a/arch/mn10300/kernel/gdb-stub.c
+++ b/arch/mn10300/kernel/gdb-stub.c
@@ -440,15 +440,11 @@ static const unsigned char gdbstub_insn_sizes[256] =
static int __gdbstub_mark_bp(u8 *addr, int ix)
{
- if (addr < (u8 *) 0x70000000UL)
- return 0;
- /* 70000000-7fffffff: vmalloc area */
- if (addr < (u8 *) 0x80000000UL)
+ /* vmalloc area */
+ if (((u8 *) VMALLOC_START <= addr) && (addr < (u8 *) VMALLOC_END))
goto okay;
- if (addr < (u8 *) 0x8c000000UL)
- return 0;
- /* 8c000000-93ffffff: SRAM, SDRAM */
- if (addr < (u8 *) 0x94000000UL)
+ /* SRAM, SDRAM */
+ if (((u8 *) 0x80000000UL <= addr) && (addr < (u8 *) 0xa0000000UL))
goto okay;
return 0;
@@ -1197,9 +1193,8 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep)
mn10300_set_gdbleds(1);
asm volatile("mov mdr,%0" : "=d"(mdr));
- asm volatile("mov epsw,%0" : "=d"(epsw));
- asm volatile("mov %0,epsw"
- :: "d"((epsw & ~EPSW_IM) | EPSW_IE | EPSW_IM_1));
+ local_save_flags(epsw);
+ local_change_intr_mask_level(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
gdbstub_store_fpu();
diff --git a/arch/mn10300/kernel/head.S b/arch/mn10300/kernel/head.S
index 14f27f3bfaf4..73e00fc78072 100644
--- a/arch/mn10300/kernel/head.S
+++ b/arch/mn10300/kernel/head.S
@@ -19,6 +19,12 @@
#include <asm/frame.inc>
#include <asm/param.h>
#include <unit/serial.h>
+#ifdef CONFIG_SMP
+#include <asm/smp.h>
+#include <asm/intctl-regs.h>
+#include <asm/cpu-regs.h>
+#include <proc/smp-regs.h>
+#endif /* CONFIG_SMP */
__HEAD
@@ -30,17 +36,51 @@
.globl _start
.type _start,@function
_start:
+#ifdef CONFIG_SMP
+ #
+ # If this is a secondary CPU (AP), then deal with that elsewhere
+ #
+ mov (CPUID),d3
+ and CPUID_MASK,d3
+ bne startup_secondary
+
+ #
+ # We're dealing with the primary CPU (BP) here, then.
+ # Keep BP's D0,D1,D2 register for boot check.
+ #
+
+ # Set up the Boot IPI for each secondary CPU
+ mov 0x1,a0
+loop_set_secondary_icr:
+ mov a0,a1
+ asl CROSS_ICR_CPU_SHIFT,a1
+ add CROSS_GxICR(SMP_BOOT_IRQ,0),a1
+ movhu (a1),d3
+ or GxICR_ENABLE|GxICR_LEVEL_0,d3
+ movhu d3,(a1)
+ movhu (a1),d3 # flush
+ inc a0
+ cmp NR_CPUS,a0
+ bne loop_set_secondary_icr
+#endif /* CONFIG_SMP */
+
# save commandline pointer
mov d0,a3
# preload the PGD pointer register
mov swapper_pg_dir,d0
mov d0,(PTBR)
+ clr d0
+ movbu d0,(PIDR)
# turn on the TLBs
mov MMUCTR_IIV|MMUCTR_DIV,d0
mov d0,(MMUCTR)
+#ifdef CONFIG_AM34_2
+ mov MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE|MMUCTR_WTE,d0
+#else
mov MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE,d0
+#endif
mov d0,(MMUCTR)
# turn on AM33v2 exception handling mode and set the trap table base
@@ -51,6 +91,11 @@ _start:
mov d0,(TBR)
# invalidate and enable both of the caches
+#ifdef CONFIG_SMP
+ mov ECHCTR,a0
+ clr d0
+ mov d0,(a0)
+#endif
mov CHCTR,a0
clr d0
movhu d0,(a0) # turn off first
@@ -61,18 +106,18 @@ _start:
btst CHCTR_ICBUSY|CHCTR_DCBUSY,d0 # wait till not busy
lne
-#ifndef CONFIG_MN10300_CACHE_DISABLED
+#ifdef CONFIG_MN10300_CACHE_ENABLED
#ifdef CONFIG_MN10300_CACHE_WBACK
#ifndef CONFIG_MN10300_CACHE_WBACK_NOWRALLOC
mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK,d0
#else
mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK|CHCTR_DCALMD,d0
-#endif /* CACHE_DISABLED */
+#endif /* NOWRALLOC */
#else
mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRTHROUGH,d0
#endif /* WBACK */
movhu d0,(a0) # enable
-#endif /* NOWRALLOC */
+#endif /* ENABLED */
# turn on RTS on the debug serial port if applicable
#ifdef CONFIG_MN10300_UNIT_ASB2305
@@ -206,6 +251,44 @@ __no_parameters:
call processor_init[],0
call unit_init[],0
+#ifdef CONFIG_SMP
+ # mark the primary CPU in cpu_boot_map
+ mov cpu_boot_map,a0
+ mov 0x1,d0
+ mov d0,(a0)
+
+ # signal each secondary CPU to begin booting
+ mov 0x1,d2 # CPU ID
+
+loop_request_boot_secondary:
+ mov d2,a0
+ # send SMP_BOOT_IPI to secondary CPU
+ asl CROSS_ICR_CPU_SHIFT,a0
+ add CROSS_GxICR(SMP_BOOT_IRQ,0),a0
+ movhu (a0),d0
+ or GxICR_REQUEST|GxICR_DETECT,d0
+ movhu d0,(a0)
+ movhu (a0),d0 # flush
+
+ # wait up to 100ms for AP's IPI to be received
+ clr d3
+wait_on_secondary_boot:
+ mov DELAY_TIME_BOOT_IPI,d0
+ call __delay[],0
+ inc d3
+ mov cpu_boot_map,a0
+ mov (a0),d0
+ lsr d2,d0
+ btst 0x1,d0
+ bne 1f
+ cmp TIME_OUT_COUNT_BOOT_IPI,d3
+ bne wait_on_secondary_boot
+1:
+ inc d2
+ cmp NR_CPUS,d2
+ bne loop_request_boot_secondary
+#endif /* CONFIG_SMP */
+
#ifdef CONFIG_GDBSTUB
call gdbstub_init[],0
@@ -217,7 +300,118 @@ __gdbstub_pause:
#endif
jmp start_kernel
- .size _start, _start-.
+ .size _start,.-_start
+
+###############################################################################
+#
+# Secondary CPU boot point
+#
+###############################################################################
+#ifdef CONFIG_SMP
+startup_secondary:
+ # preload the PGD pointer register
+ mov swapper_pg_dir,d0
+ mov d0,(PTBR)
+ clr d0
+ movbu d0,(PIDR)
+
+ # turn on the TLBs
+ mov MMUCTR_IIV|MMUCTR_DIV,d0
+ mov d0,(MMUCTR)
+#ifdef CONFIG_AM34_2
+ mov MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE|MMUCTR_WTE,d0
+#else
+ mov MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE,d0
+#endif
+ mov d0,(MMUCTR)
+
+ # turn on AM33v2 exception handling mode and set the trap table base
+ movhu (CPUP),d0
+ or CPUP_EXM_AM33V2,d0
+ movhu d0,(CPUP)
+
+ # set the interrupt vector table
+ mov CONFIG_INTERRUPT_VECTOR_BASE,d0
+ mov d0,(TBR)
+
+ # invalidate and enable both of the caches
+ mov ECHCTR,a0
+ clr d0
+ mov d0,(a0)
+ mov CHCTR,a0
+ clr d0
+ movhu d0,(a0) # turn off first
+ mov CHCTR_ICINV|CHCTR_DCINV,d0
+ movhu d0,(a0)
+ setlb
+ mov (a0),d0
+ btst CHCTR_ICBUSY|CHCTR_DCBUSY,d0 # wait till not busy (use CPU loop buffer)
+ lne
+
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+#ifdef CONFIG_MN10300_CACHE_WBACK
+#ifndef CONFIG_MN10300_CACHE_WBACK_NOWRALLOC
+ mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK,d0
+#else
+ mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK|CHCTR_DCALMD,d0
+#endif /* !NOWRALLOC */
+#else
+ mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRTHROUGH,d0
+#endif /* WBACK */
+ movhu d0,(a0) # enable
+#endif /* ENABLED */
+
+ # Clear the boot IPI interrupt for this CPU
+ movhu (GxICR(SMP_BOOT_IRQ)),d0
+ and ~GxICR_REQUEST,d0
+ movhu d0,(GxICR(SMP_BOOT_IRQ))
+ movhu (GxICR(SMP_BOOT_IRQ)),d0 # flush
+
+ /* get stack */
+ mov CONFIG_INTERRUPT_VECTOR_BASE + CONFIG_BOOT_STACK_OFFSET,a0
+ mov (CPUID),d0
+ and CPUID_MASK,d0
+ mulu CONFIG_BOOT_STACK_SIZE,d0
+ sub d0,a0
+ mov a0,sp
+
+ # init interrupt for AP
+ call smp_prepare_cpu_init[],0
+
+ # mark this secondary CPU in cpu_boot_map
+ mov (CPUID),d0
+ mov 0x1,d1
+ asl d0,d1
+ mov cpu_boot_map,a0
+ bset d1,(a0)
+
+ or EPSW_IE|EPSW_IM_1,epsw # permit level 0 interrupts
+ nop
+ nop
+#ifdef CONFIG_MN10300_CACHE_WBACK
+ # flush the local cache if it's in writeback mode
+ call mn10300_local_dcache_flush_inv[],0
+ setlb
+ mov (CHCTR),d0
+ btst CHCTR_DCBUSY,d0 # wait till not busy (use CPU loop buffer)
+ lne
+#endif
+
+ # now sleep waiting for further instructions
+secondary_sleep:
+ mov CPUM_SLEEP,d0
+ movhu d0,(CPUM)
+ nop
+ nop
+ bra secondary_sleep
+ .size startup_secondary,.-startup_secondary
+#endif /* CONFIG_SMP */
+
+###############################################################################
+#
+#
+#
+###############################################################################
ENTRY(__head_end)
/*
diff --git a/arch/mn10300/kernel/internal.h b/arch/mn10300/kernel/internal.h
index eee2eee86267..6a064ab5af07 100644
--- a/arch/mn10300/kernel/internal.h
+++ b/arch/mn10300/kernel/internal.h
@@ -9,6 +9,9 @@
* 2 of the Licence, or (at your option) any later version.
*/
+struct clocksource;
+struct clock_event_device;
+
/*
* kthread.S
*/
@@ -18,3 +21,25 @@ extern int kernel_thread_helper(int);
* entry.S
*/
extern void ret_from_fork(struct task_struct *) __attribute__((noreturn));
+
+/*
+ * smp-low.S
+ */
+#ifdef CONFIG_SMP
+extern void mn10300_low_ipi_handler(void);
+#endif
+
+/*
+ * time.c
+ */
+extern irqreturn_t local_timer_interrupt(void);
+
+/*
+ * time.c
+ */
+#ifdef CONFIG_CEVT_MN10300
+extern void clockevent_set_clock(struct clock_event_device *, unsigned int);
+#endif
+#ifdef CONFIG_CSRC_MN10300
+extern void clocksource_set_clock(struct clocksource *, unsigned int);
+#endif
diff --git a/arch/mn10300/kernel/irq.c b/arch/mn10300/kernel/irq.c
index e2d5ed891f37..c2e44597c22b 100644
--- a/arch/mn10300/kernel/irq.c
+++ b/arch/mn10300/kernel/irq.c
@@ -12,11 +12,26 @@
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/seq_file.h>
+#include <linux/cpumask.h>
#include <asm/setup.h>
+#include <asm/serial-regs.h>
-unsigned long __mn10300_irq_enabled_epsw = EPSW_IE | EPSW_IM_7;
+unsigned long __mn10300_irq_enabled_epsw[NR_CPUS] __cacheline_aligned_in_smp = {
+ [0 ... NR_CPUS - 1] = EPSW_IE | EPSW_IM_7
+};
EXPORT_SYMBOL(__mn10300_irq_enabled_epsw);
+#ifdef CONFIG_SMP
+static char irq_affinity_online[NR_IRQS] = {
+ [0 ... NR_IRQS - 1] = 0
+};
+
+#define NR_IRQ_WORDS ((NR_IRQS + 31) / 32)
+static unsigned long irq_affinity_request[NR_IRQ_WORDS] = {
+ [0 ... NR_IRQ_WORDS - 1] = 0
+};
+#endif /* CONFIG_SMP */
+
atomic_t irq_err_count;
/*
@@ -24,30 +39,67 @@ atomic_t irq_err_count;
*/
static void mn10300_cpupic_ack(unsigned int irq)
{
+ unsigned long flags;
u16 tmp;
- *(volatile u8 *) &GxICR(irq) = GxICR_DETECT;
+
+ flags = arch_local_cli_save();
+ GxICR_u8(irq) = GxICR_DETECT;
tmp = GxICR(irq);
+ arch_local_irq_restore(flags);
}
-static void mn10300_cpupic_mask(unsigned int irq)
+static void __mask_and_set_icr(unsigned int irq,
+ unsigned int mask, unsigned int set)
{
- u16 tmp = GxICR(irq);
- GxICR(irq) = (tmp & GxICR_LEVEL);
+ unsigned long flags;
+ u16 tmp;
+
+ flags = arch_local_cli_save();
+ tmp = GxICR(irq);
+ GxICR(irq) = (tmp & mask) | set;
tmp = GxICR(irq);
+ arch_local_irq_restore(flags);
+}
+
+static void mn10300_cpupic_mask(unsigned int irq)
+{
+ __mask_and_set_icr(irq, GxICR_LEVEL, 0);
}
static void mn10300_cpupic_mask_ack(unsigned int irq)
{
- u16 tmp = GxICR(irq);
- GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT;
- tmp = GxICR(irq);
+#ifdef CONFIG_SMP
+ unsigned long flags;
+ u16 tmp;
+
+ flags = arch_local_cli_save();
+
+ if (!test_and_clear_bit(irq, irq_affinity_request)) {
+ tmp = GxICR(irq);
+ GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT;
+ tmp = GxICR(irq);
+ } else {
+ u16 tmp2;
+ tmp = GxICR(irq);
+ GxICR(irq) = (tmp & GxICR_LEVEL);
+ tmp2 = GxICR(irq);
+
+ irq_affinity_online[irq] =
+ any_online_cpu(*irq_desc[irq].affinity);
+ CROSS_GxICR(irq, irq_affinity_online[irq]) =
+ (tmp & (GxICR_LEVEL | GxICR_ENABLE)) | GxICR_DETECT;
+ tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
+ }
+
+ arch_local_irq_restore(flags);
+#else /* CONFIG_SMP */
+ __mask_and_set_icr(irq, GxICR_LEVEL, GxICR_DETECT);
+#endif /* CONFIG_SMP */
}
static void mn10300_cpupic_unmask(unsigned int irq)
{
- u16 tmp = GxICR(irq);
- GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE;
- tmp = GxICR(irq);
+ __mask_and_set_icr(irq, GxICR_LEVEL, GxICR_ENABLE);
}
static void mn10300_cpupic_unmask_clear(unsigned int irq)
@@ -56,11 +108,89 @@ static void mn10300_cpupic_unmask_clear(unsigned int irq)
* device has ceased to assert its interrupt line and the interrupt
* channel has been disabled in the PIC, so for level-triggered
* interrupts we need to clear the request bit when we re-enable */
- u16 tmp = GxICR(irq);
- GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
- tmp = GxICR(irq);
+#ifdef CONFIG_SMP
+ unsigned long flags;
+ u16 tmp;
+
+ flags = arch_local_cli_save();
+
+ if (!test_and_clear_bit(irq, irq_affinity_request)) {
+ tmp = GxICR(irq);
+ GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
+ tmp = GxICR(irq);
+ } else {
+ tmp = GxICR(irq);
+
+ irq_affinity_online[irq] = any_online_cpu(*irq_desc[irq].affinity);
+ CROSS_GxICR(irq, irq_affinity_online[irq]) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
+ tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
+ }
+
+ arch_local_irq_restore(flags);
+#else /* CONFIG_SMP */
+ __mask_and_set_icr(irq, GxICR_LEVEL, GxICR_ENABLE | GxICR_DETECT);
+#endif /* CONFIG_SMP */
}
+#ifdef CONFIG_SMP
+static int
+mn10300_cpupic_setaffinity(unsigned int irq, const struct cpumask *mask)
+{
+ unsigned long flags;
+ int err;
+
+ flags = arch_local_cli_save();
+
+ /* check irq no */
+ switch (irq) {
+ case TMJCIRQ:
+ case RESCHEDULE_IPI:
+ case CALL_FUNC_SINGLE_IPI:
+ case LOCAL_TIMER_IPI:
+ case FLUSH_CACHE_IPI:
+ case CALL_FUNCTION_NMI_IPI:
+ case GDB_NMI_IPI:
+#ifdef CONFIG_MN10300_TTYSM0
+ case SC0RXIRQ:
+ case SC0TXIRQ:
+#ifdef CONFIG_MN10300_TTYSM0_TIMER8
+ case TM8IRQ:
+#elif CONFIG_MN10300_TTYSM0_TIMER2
+ case TM2IRQ:
+#endif /* CONFIG_MN10300_TTYSM0_TIMER8 */
+#endif /* CONFIG_MN10300_TTYSM0 */
+
+#ifdef CONFIG_MN10300_TTYSM1
+ case SC1RXIRQ:
+ case SC1TXIRQ:
+#ifdef CONFIG_MN10300_TTYSM1_TIMER12
+ case TM12IRQ:
+#elif CONFIG_MN10300_TTYSM1_TIMER9
+ case TM9IRQ:
+#elif CONFIG_MN10300_TTYSM1_TIMER3
+ case TM3IRQ:
+#endif /* CONFIG_MN10300_TTYSM1_TIMER12 */
+#endif /* CONFIG_MN10300_TTYSM1 */
+
+#ifdef CONFIG_MN10300_TTYSM2
+ case SC2RXIRQ:
+ case SC2TXIRQ:
+ case TM10IRQ:
+#endif /* CONFIG_MN10300_TTYSM2 */
+ err = -1;
+ break;
+
+ default:
+ set_bit(irq, irq_affinity_request);
+ err = 0;
+ break;
+ }
+
+ arch_local_irq_restore(flags);
+ return err;
+}
+#endif /* CONFIG_SMP */
+
/*
* MN10300 PIC level-triggered IRQ handling.
*
@@ -79,6 +209,9 @@ static struct irq_chip mn10300_cpu_pic_level = {
.mask = mn10300_cpupic_mask,
.mask_ack = mn10300_cpupic_mask,
.unmask = mn10300_cpupic_unmask_clear,
+#ifdef CONFIG_SMP
+ .set_affinity = mn10300_cpupic_setaffinity,
+#endif
};
/*
@@ -94,6 +227,9 @@ static struct irq_chip mn10300_cpu_pic_edge = {
.mask = mn10300_cpupic_mask,
.mask_ack = mn10300_cpupic_mask_ack,
.unmask = mn10300_cpupic_unmask,
+#ifdef CONFIG_SMP
+ .set_affinity = mn10300_cpupic_setaffinity,
+#endif
};
/*
@@ -111,14 +247,34 @@ void ack_bad_irq(int irq)
*/
void set_intr_level(int irq, u16 level)
{
- u16 tmp;
+ BUG_ON(in_interrupt());
- if (in_interrupt())
- BUG();
+ __mask_and_set_icr(irq, GxICR_ENABLE, level);
+}
- tmp = GxICR(irq);
- GxICR(irq) = (tmp & GxICR_ENABLE) | level;
- tmp = GxICR(irq);
+void mn10300_intc_set_level(unsigned int irq, unsigned int level)
+{
+ set_intr_level(irq, NUM2GxICR_LEVEL(level) & GxICR_LEVEL);
+}
+
+void mn10300_intc_clear(unsigned int irq)
+{
+ __mask_and_set_icr(irq, GxICR_LEVEL | GxICR_ENABLE, GxICR_DETECT);
+}
+
+void mn10300_intc_set(unsigned int irq)
+{
+ __mask_and_set_icr(irq, 0, GxICR_REQUEST | GxICR_DETECT);
+}
+
+void mn10300_intc_enable(unsigned int irq)
+{
+ mn10300_cpupic_unmask(irq);
+}
+
+void mn10300_intc_disable(unsigned int irq)
+{
+ mn10300_cpupic_mask(irq);
}
/*
@@ -126,7 +282,7 @@ void set_intr_level(int irq, u16 level)
* than before
* - see Documentation/mn10300/features.txt
*/
-void set_intr_postackable(int irq)
+void mn10300_set_lateack_irq_type(int irq)
{
set_irq_chip_and_handler(irq, &mn10300_cpu_pic_level,
handle_level_irq);
@@ -147,6 +303,7 @@ void __init init_IRQ(void)
* interrupts */
set_irq_chip_and_handler(irq, &mn10300_cpu_pic_edge,
handle_level_irq);
+
unit_init_IRQ();
}
@@ -156,20 +313,22 @@ void __init init_IRQ(void)
asmlinkage void do_IRQ(void)
{
unsigned long sp, epsw, irq_disabled_epsw, old_irq_enabled_epsw;
+ unsigned int cpu_id = smp_processor_id();
int irq;
sp = current_stack_pointer();
- if (sp - (sp & ~(THREAD_SIZE - 1)) < STACK_WARN)
- BUG();
+ BUG_ON(sp - (sp & ~(THREAD_SIZE - 1)) < STACK_WARN);
/* make sure local_irq_enable() doesn't muck up the interrupt priority
* setting in EPSW */
- old_irq_enabled_epsw = __mn10300_irq_enabled_epsw;
+ old_irq_enabled_epsw = __mn10300_irq_enabled_epsw[cpu_id];
local_save_flags(epsw);
- __mn10300_irq_enabled_epsw = EPSW_IE | (EPSW_IM & epsw);
+ __mn10300_irq_enabled_epsw[cpu_id] = EPSW_IE | (EPSW_IM & epsw);
irq_disabled_epsw = EPSW_IE | MN10300_CLI_LEVEL;
- __IRQ_STAT(smp_processor_id(), __irq_count)++;
+#ifdef CONFIG_MN10300_WD_TIMER
+ __IRQ_STAT(cpu_id, __irq_count)++;
+#endif
irq_enter();
@@ -189,7 +348,7 @@ asmlinkage void do_IRQ(void)
local_irq_restore(epsw);
}
- __mn10300_irq_enabled_epsw = old_irq_enabled_epsw;
+ __mn10300_irq_enabled_epsw[cpu_id] = old_irq_enabled_epsw;
irq_exit();
}
@@ -222,9 +381,16 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%3d: ", i);
for_each_present_cpu(cpu)
seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu));
- seq_printf(p, " %14s.%u", irq_desc[i].chip->name,
- (GxICR(i) & GxICR_LEVEL) >>
- GxICR_LEVEL_SHIFT);
+
+ if (i < NR_CPU_IRQS)
+ seq_printf(p, " %14s.%u",
+ irq_desc[i].chip->name,
+ (GxICR(i) & GxICR_LEVEL) >>
+ GxICR_LEVEL_SHIFT);
+ else
+ seq_printf(p, " %14s",
+ irq_desc[i].chip->name);
+
seq_printf(p, " %s", action->name);
for (action = action->next;
@@ -240,11 +406,13 @@ int show_interrupts(struct seq_file *p, void *v)
/* polish off with NMI and error counters */
case NR_IRQS:
+#ifdef CONFIG_MN10300_WD_TIMER
seq_printf(p, "NMI: ");
for (j = 0; j < NR_CPUS; j++)
if (cpu_online(j))
seq_printf(p, "%10u ", nmi_count(j));
seq_putc(p, '\n');
+#endif
seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
break;
@@ -252,3 +420,51 @@ int show_interrupts(struct seq_file *p, void *v)
return 0;
}
+
+#ifdef CONFIG_HOTPLUG_CPU
+void migrate_irqs(void)
+{
+ irq_desc_t *desc;
+ int irq;
+ unsigned int self, new;
+ unsigned long flags;
+
+ self = smp_processor_id();
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ desc = irq_desc + irq;
+
+ if (desc->status == IRQ_PER_CPU)
+ continue;
+
+ if (cpu_isset(self, irq_desc[irq].affinity) &&
+ !cpus_intersects(irq_affinity[irq], cpu_online_map)) {
+ int cpu_id;
+ cpu_id = first_cpu(cpu_online_map);
+ cpu_set(cpu_id, irq_desc[irq].affinity);
+ }
+ /* We need to operate irq_affinity_online atomically. */
+ arch_local_cli_save(flags);
+ if (irq_affinity_online[irq] == self) {
+ u16 x, tmp;
+
+ x = GxICR(irq);
+ GxICR(irq) = x & GxICR_LEVEL;
+ tmp = GxICR(irq);
+
+ new = any_online_cpu(irq_desc[irq].affinity);
+ irq_affinity_online[irq] = new;
+
+ CROSS_GxICR(irq, new) =
+ (x & GxICR_LEVEL) | GxICR_DETECT;
+ tmp = CROSS_GxICR(irq, new);
+
+ x &= GxICR_LEVEL | GxICR_ENABLE;
+ if (GxICR(irq) & GxICR_REQUEST) {
+ x |= GxICR_REQUEST | GxICR_DETECT;
+ CROSS_GxICR(irq, new) = x;
+ tmp = CROSS_GxICR(irq, new);
+ }
+ arch_local_irq_restore(flags);
+ }
+}
+#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/arch/mn10300/kernel/kprobes.c b/arch/mn10300/kernel/kprobes.c
index 67e6389d625a..0311a7fcea16 100644
--- a/arch/mn10300/kernel/kprobes.c
+++ b/arch/mn10300/kernel/kprobes.c
@@ -377,8 +377,10 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
+#ifndef CONFIG_MN10300_CACHE_SNOOP
mn10300_dcache_flush();
mn10300_icache_inv();
+#endif
}
void arch_remove_kprobe(struct kprobe *p)
@@ -390,8 +392,10 @@ void __kprobes disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
{
*p->addr = p->opcode;
regs->pc = (unsigned long) p->addr;
+#ifndef CONFIG_MN10300_CACHE_SNOOP
mn10300_dcache_flush();
mn10300_icache_inv();
+#endif
}
static inline
diff --git a/arch/mn10300/kernel/mn10300-serial-low.S b/arch/mn10300/kernel/mn10300-serial-low.S
index 66702d256610..dfc1b6f2fa9a 100644
--- a/arch/mn10300/kernel/mn10300-serial-low.S
+++ b/arch/mn10300/kernel/mn10300-serial-low.S
@@ -39,7 +39,7 @@
###############################################################################
.balign L1_CACHE_BYTES
ENTRY(mn10300_serial_vdma_interrupt)
- or EPSW_IE,psw # permit overriding by
+# or EPSW_IE,psw # permit overriding by
# debugging interrupts
movm [d2,d3,a2,a3,exreg0],(sp)
@@ -164,7 +164,7 @@ mnsc_vdma_tx_noint:
rti
mnsc_vdma_tx_empty:
- mov +(GxICR_LEVEL_1|GxICR_DETECT),d2
+ mov +(NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)|GxICR_DETECT),d2
movhu d2,(e3) # disable the interrupt
movhu (e3),d2 # flush
@@ -175,7 +175,7 @@ mnsc_vdma_tx_break:
movhu (SCxCTR,e2),d2 # turn on break mode
or SC01CTR_BKE,d2
movhu d2,(SCxCTR,e2)
- mov +(GxICR_LEVEL_1|GxICR_DETECT),d2
+ mov +(NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)|GxICR_DETECT),d2
movhu d2,(e3) # disable transmit interrupts on this
# channel
movhu (e3),d2 # flush
diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c
index db509dd80565..996384dba45d 100644
--- a/arch/mn10300/kernel/mn10300-serial.c
+++ b/arch/mn10300/kernel/mn10300-serial.c
@@ -44,6 +44,11 @@ static const char serial_revdate[] = "2007-11-06";
#include <unit/timex.h>
#include "mn10300-serial.h"
+#ifdef CONFIG_SMP
+#undef GxICR
+#define GxICR(X) CROSS_GxICR(X, 0)
+#endif /* CONFIG_SMP */
+
#define kenter(FMT, ...) \
printk(KERN_DEBUG "-->%s(" FMT ")\n", __func__, ##__VA_ARGS__)
#define _enter(FMT, ...) \
@@ -57,6 +62,11 @@ static const char serial_revdate[] = "2007-11-06";
#define _proto(FMT, ...) \
no_printk(KERN_DEBUG "### MNSERIAL " FMT " ###\n", ##__VA_ARGS__)
+#ifndef CODMSB
+/* c_cflag bit meaning */
+#define CODMSB 004000000000 /* change Transfer bit-order */
+#endif
+
#define NR_UARTS 3
#ifdef CONFIG_MN10300_TTYSM_CONSOLE
@@ -152,26 +162,35 @@ struct mn10300_serial_port mn10300_serial_port_sif0 = {
.name = "ttySM0",
._iobase = &SC0CTR,
._control = &SC0CTR,
- ._status = (volatile u8 *) &SC0STR,
+ ._status = (volatile u8 *)&SC0STR,
._intr = &SC0ICR,
._rxb = &SC0RXB,
._txb = &SC0TXB,
.rx_name = "ttySM0:Rx",
.tx_name = "ttySM0:Tx",
-#ifdef CONFIG_MN10300_TTYSM0_TIMER8
+#if defined(CONFIG_MN10300_TTYSM0_TIMER8)
.tm_name = "ttySM0:Timer8",
._tmxmd = &TM8MD,
._tmxbr = &TM8BR,
._tmicr = &TM8ICR,
.tm_irq = TM8IRQ,
.div_timer = MNSCx_DIV_TIMER_16BIT,
-#else /* CONFIG_MN10300_TTYSM0_TIMER2 */
+#elif defined(CONFIG_MN10300_TTYSM0_TIMER0)
+ .tm_name = "ttySM0:Timer0",
+ ._tmxmd = &TM0MD,
+ ._tmxbr = (volatile u16 *)&TM0BR,
+ ._tmicr = &TM0ICR,
+ .tm_irq = TM0IRQ,
+ .div_timer = MNSCx_DIV_TIMER_8BIT,
+#elif defined(CONFIG_MN10300_TTYSM0_TIMER2)
.tm_name = "ttySM0:Timer2",
._tmxmd = &TM2MD,
- ._tmxbr = (volatile u16 *) &TM2BR,
+ ._tmxbr = (volatile u16 *)&TM2BR,
._tmicr = &TM2ICR,
.tm_irq = TM2IRQ,
.div_timer = MNSCx_DIV_TIMER_8BIT,
+#else
+#error "Unknown config for ttySM0"
#endif
.rx_irq = SC0RXIRQ,
.tx_irq = SC0TXIRQ,
@@ -205,26 +224,35 @@ struct mn10300_serial_port mn10300_serial_port_sif1 = {
.name = "ttySM1",
._iobase = &SC1CTR,
._control = &SC1CTR,
- ._status = (volatile u8 *) &SC1STR,
+ ._status = (volatile u8 *)&SC1STR,
._intr = &SC1ICR,
._rxb = &SC1RXB,
._txb = &SC1TXB,
.rx_name = "ttySM1:Rx",
.tx_name = "ttySM1:Tx",
-#ifdef CONFIG_MN10300_TTYSM1_TIMER9
+#if defined(CONFIG_MN10300_TTYSM1_TIMER9)
.tm_name = "ttySM1:Timer9",
._tmxmd = &TM9MD,
._tmxbr = &TM9BR,
._tmicr = &TM9ICR,
.tm_irq = TM9IRQ,
.div_timer = MNSCx_DIV_TIMER_16BIT,
-#else /* CONFIG_MN10300_TTYSM1_TIMER3 */
+#elif defined(CONFIG_MN10300_TTYSM1_TIMER3)
.tm_name = "ttySM1:Timer3",
._tmxmd = &TM3MD,
- ._tmxbr = (volatile u16 *) &TM3BR,
+ ._tmxbr = (volatile u16 *)&TM3BR,
._tmicr = &TM3ICR,
.tm_irq = TM3IRQ,
.div_timer = MNSCx_DIV_TIMER_8BIT,
+#elif defined(CONFIG_MN10300_TTYSM1_TIMER12)
+ .tm_name = "ttySM1/Timer12",
+ ._tmxmd = &TM12MD,
+ ._tmxbr = &TM12BR,
+ ._tmicr = &TM12ICR,
+ .tm_irq = TM12IRQ,
+ .div_timer = MNSCx_DIV_TIMER_16BIT,
+#else
+#error "Unknown config for ttySM1"
#endif
.rx_irq = SC1RXIRQ,
.tx_irq = SC1TXIRQ,
@@ -260,20 +288,45 @@ struct mn10300_serial_port mn10300_serial_port_sif2 = {
.uart.lock =
__SPIN_LOCK_UNLOCKED(mn10300_serial_port_sif2.uart.lock),
.name = "ttySM2",
- .rx_name = "ttySM2:Rx",
- .tx_name = "ttySM2:Tx",
- .tm_name = "ttySM2:Timer10",
._iobase = &SC2CTR,
._control = &SC2CTR,
- ._status = &SC2STR,
+ ._status = (volatile u8 *)&SC2STR,
._intr = &SC2ICR,
._rxb = &SC2RXB,
._txb = &SC2TXB,
+ .rx_name = "ttySM2:Rx",
+ .tx_name = "ttySM2:Tx",
+#if defined(CONFIG_MN10300_TTYSM2_TIMER10)
+ .tm_name = "ttySM2/Timer10",
._tmxmd = &TM10MD,
._tmxbr = &TM10BR,
._tmicr = &TM10ICR,
.tm_irq = TM10IRQ,
.div_timer = MNSCx_DIV_TIMER_16BIT,
+#elif defined(CONFIG_MN10300_TTYSM2_TIMER9)
+ .tm_name = "ttySM2/Timer9",
+ ._tmxmd = &TM9MD,
+ ._tmxbr = &TM9BR,
+ ._tmicr = &TM9ICR,
+ .tm_irq = TM9IRQ,
+ .div_timer = MNSCx_DIV_TIMER_16BIT,
+#elif defined(CONFIG_MN10300_TTYSM2_TIMER1)
+ .tm_name = "ttySM2/Timer1",
+ ._tmxmd = &TM1MD,
+ ._tmxbr = (volatile u16 *)&TM1BR,
+ ._tmicr = &TM1ICR,
+ .tm_irq = TM1IRQ,
+ .div_timer = MNSCx_DIV_TIMER_8BIT,
+#elif defined(CONFIG_MN10300_TTYSM2_TIMER3)
+ .tm_name = "ttySM2/Timer3",
+ ._tmxmd = &TM3MD,
+ ._tmxbr = (volatile u16 *)&TM3BR,
+ ._tmicr = &TM3ICR,
+ .tm_irq = TM3IRQ,
+ .div_timer = MNSCx_DIV_TIMER_8BIT,
+#else
+#error "Unknown config for ttySM2"
+#endif
.rx_irq = SC2RXIRQ,
.tx_irq = SC2TXIRQ,
.rx_icr = &GxICR(SC2RXIRQ),
@@ -322,9 +375,13 @@ struct mn10300_serial_port *mn10300_serial_ports[NR_UARTS + 1] = {
*/
static void mn10300_serial_mask_ack(unsigned int irq)
{
+ unsigned long flags;
u16 tmp;
+
+ flags = arch_local_cli_save();
GxICR(irq) = GxICR_LEVEL_6;
tmp = GxICR(irq); /* flush write buffer */
+ arch_local_irq_restore(flags);
}
static void mn10300_serial_nop(unsigned int irq)
@@ -348,23 +405,36 @@ struct mn10300_serial_int mn10300_serial_int_tbl[NR_IRQS];
static void mn10300_serial_dis_tx_intr(struct mn10300_serial_port *port)
{
+ unsigned long flags;
u16 x;
- *port->tx_icr = GxICR_LEVEL_1 | GxICR_DETECT;
+
+ flags = arch_local_cli_save();
+ *port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
x = *port->tx_icr;
+ arch_local_irq_restore(flags);
}
static void mn10300_serial_en_tx_intr(struct mn10300_serial_port *port)
{
+ unsigned long flags;
u16 x;
- *port->tx_icr = GxICR_LEVEL_1 | GxICR_ENABLE;
+
+ flags = arch_local_cli_save();
+ *port->tx_icr =
+ NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL) | GxICR_ENABLE;
x = *port->tx_icr;
+ arch_local_irq_restore(flags);
}
static void mn10300_serial_dis_rx_intr(struct mn10300_serial_port *port)
{
+ unsigned long flags;
u16 x;
- *port->rx_icr = GxICR_LEVEL_1 | GxICR_DETECT;
+
+ flags = arch_local_cli_save();
+ *port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
x = *port->rx_icr;
+ arch_local_irq_restore(flags);
}
/*
@@ -650,7 +720,7 @@ static unsigned int mn10300_serial_tx_empty(struct uart_port *_port)
static void mn10300_serial_set_mctrl(struct uart_port *_port,
unsigned int mctrl)
{
- struct mn10300_serial_port *port =
+ struct mn10300_serial_port *port __attribute__ ((unused)) =
container_of(_port, struct mn10300_serial_port, uart);
_enter("%s,%x", port->name, mctrl);
@@ -706,6 +776,7 @@ static void mn10300_serial_start_tx(struct uart_port *_port)
UART_XMIT_SIZE));
/* kick the virtual DMA controller */
+ arch_local_cli();
x = *port->tx_icr;
x |= GxICR_ENABLE;
@@ -716,10 +787,14 @@ static void mn10300_serial_start_tx(struct uart_port *_port)
_debug("CTR=%04hx ICR=%02hx STR=%04x TMD=%02hx TBR=%04hx ICR=%04hx",
*port->_control, *port->_intr, *port->_status,
- *port->_tmxmd, *port->_tmxbr, *port->tx_icr);
+ *port->_tmxmd,
+ (port->div_timer == MNSCx_DIV_TIMER_8BIT) ?
+ *(volatile u8 *)port->_tmxbr : *port->_tmxbr,
+ *port->tx_icr);
*port->tx_icr = x;
x = *port->tx_icr;
+ arch_local_sti();
}
/*
@@ -842,8 +917,10 @@ static int mn10300_serial_startup(struct uart_port *_port)
pint->port = port;
pint->vdma = mn10300_serial_vdma_tx_handler;
- set_intr_level(port->rx_irq, GxICR_LEVEL_1);
- set_intr_level(port->tx_irq, GxICR_LEVEL_1);
+ set_intr_level(port->rx_irq,
+ NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL));
+ set_intr_level(port->tx_irq,
+ NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL));
set_irq_chip(port->tm_irq, &mn10300_serial_pic);
if (request_irq(port->rx_irq, mn10300_serial_interrupt,
@@ -876,6 +953,7 @@ error:
*/
static void mn10300_serial_shutdown(struct uart_port *_port)
{
+ u16 x;
struct mn10300_serial_port *port =
container_of(_port, struct mn10300_serial_port, uart);
@@ -897,8 +975,12 @@ static void mn10300_serial_shutdown(struct uart_port *_port)
free_irq(port->rx_irq, port);
free_irq(port->tx_irq, port);
- *port->rx_icr = GxICR_LEVEL_1;
- *port->tx_icr = GxICR_LEVEL_1;
+ arch_local_cli();
+ *port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
+ x = *port->rx_icr;
+ *port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
+ x = *port->tx_icr;
+ arch_local_sti();
}
/*
@@ -947,11 +1029,66 @@ static void mn10300_serial_change_speed(struct mn10300_serial_port *port,
/* Determine divisor based on baud rate */
battempt = 0;
- if (div_timer == MNSCx_DIV_TIMER_16BIT)
- scxctr |= SC0CTR_CK_TM8UFLOW_8; /* ( == SC1CTR_CK_TM9UFLOW_8
- * == SC2CTR_CK_TM10UFLOW) */
- else if (div_timer == MNSCx_DIV_TIMER_8BIT)
+ switch (port->uart.line) {
+#ifdef CONFIG_MN10300_TTYSM0
+ case 0: /* ttySM0 */
+#if defined(CONFIG_MN10300_TTYSM0_TIMER8)
+ scxctr |= SC0CTR_CK_TM8UFLOW_8;
+#elif defined(CONFIG_MN10300_TTYSM0_TIMER0)
+ scxctr |= SC0CTR_CK_TM0UFLOW_8;
+#elif defined(CONFIG_MN10300_TTYSM0_TIMER2)
scxctr |= SC0CTR_CK_TM2UFLOW_8;
+#else
+#error "Unknown config for ttySM0"
+#endif
+ break;
+#endif /* CONFIG_MN10300_TTYSM0 */
+
+#ifdef CONFIG_MN10300_TTYSM1
+ case 1: /* ttySM1 */
+#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
+#if defined(CONFIG_MN10300_TTYSM1_TIMER9)
+ scxctr |= SC1CTR_CK_TM9UFLOW_8;
+#elif defined(CONFIG_MN10300_TTYSM1_TIMER3)
+ scxctr |= SC1CTR_CK_TM3UFLOW_8;
+#else
+#error "Unknown config for ttySM1"
+#endif
+#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+#if defined(CONFIG_MN10300_TTYSM1_TIMER12)
+ scxctr |= SC1CTR_CK_TM12UFLOW_8;
+#else
+#error "Unknown config for ttySM1"
+#endif
+#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+ break;
+#endif /* CONFIG_MN10300_TTYSM1 */
+
+#ifdef CONFIG_MN10300_TTYSM2
+ case 2: /* ttySM2 */
+#if defined(CONFIG_AM33_2)
+#if defined(CONFIG_MN10300_TTYSM2_TIMER10)
+ scxctr |= SC2CTR_CK_TM10UFLOW;
+#else
+#error "Unknown config for ttySM2"
+#endif
+#else /* CONFIG_AM33_2 */
+#if defined(CONFIG_MN10300_TTYSM2_TIMER9)
+ scxctr |= SC2CTR_CK_TM9UFLOW_8;
+#elif defined(CONFIG_MN10300_TTYSM2_TIMER1)
+ scxctr |= SC2CTR_CK_TM1UFLOW_8;
+#elif defined(CONFIG_MN10300_TTYSM2_TIMER3)
+ scxctr |= SC2CTR_CK_TM3UFLOW_8;
+#else
+#error "Unknown config for ttySM2"
+#endif
+#endif /* CONFIG_AM33_2 */
+ break;
+#endif /* CONFIG_MN10300_TTYSM2 */
+
+ default:
+ break;
+ }
try_alternative:
baud = uart_get_baud_rate(&port->uart, new, old, 0,
@@ -1195,6 +1332,12 @@ static void mn10300_serial_set_termios(struct uart_port *_port,
ctr &= ~SC2CTR_TWE;
*port->_control = ctr;
}
+
+ /* change Transfer bit-order (LSB/MSB) */
+ if (new->c_cflag & CODMSB)
+ *port->_control |= SC01CTR_OD_MSBFIRST; /* MSB MODE */
+ else
+ *port->_control &= ~SC01CTR_OD_MSBFIRST; /* LSB MODE */
}
/*
@@ -1302,11 +1445,16 @@ static int __init mn10300_serial_init(void)
printk(KERN_INFO "%s version %s (%s)\n",
serial_name, serial_version, serial_revdate);
-#ifdef CONFIG_MN10300_TTYSM2
- SC2TIM = 8; /* make the baud base of timer 2 IOCLK/8 */
+#if defined(CONFIG_MN10300_TTYSM2) && defined(CONFIG_AM33_2)
+ {
+ int tmp;
+ SC2TIM = 8; /* make the baud base of timer 2 IOCLK/8 */
+ tmp = SC2TIM;
+ }
#endif
- set_intr_stub(EXCEP_IRQ_LEVEL1, mn10300_serial_vdma_interrupt);
+ set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL),
+ mn10300_serial_vdma_interrupt);
ret = uart_register_driver(&mn10300_serial_driver);
if (!ret) {
@@ -1366,9 +1514,11 @@ static void mn10300_serial_console_write(struct console *co,
port = mn10300_serial_ports[co->index];
/* firstly hijack the serial port from the "virtual DMA" controller */
+ arch_local_cli();
txicr = *port->tx_icr;
- *port->tx_icr = GxICR_LEVEL_1;
+ *port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
tmp = *port->tx_icr;
+ arch_local_sti();
/* the transmitter may be disabled */
scxctr = *port->_control;
@@ -1422,8 +1572,10 @@ static void mn10300_serial_console_write(struct console *co,
if (!(scxctr & SC01CTR_TXE))
*port->_control = scxctr;
+ arch_local_cli();
*port->tx_icr = txicr;
tmp = *port->tx_icr;
+ arch_local_sti();
}
/*
diff --git a/arch/mn10300/kernel/mn10300-watchdog-low.S b/arch/mn10300/kernel/mn10300-watchdog-low.S
index 996244745cca..f2f5c9cfaabd 100644
--- a/arch/mn10300/kernel/mn10300-watchdog-low.S
+++ b/arch/mn10300/kernel/mn10300-watchdog-low.S
@@ -16,6 +16,7 @@
#include <asm/intctl-regs.h>
#include <asm/timer-regs.h>
#include <asm/frame.inc>
+#include <linux/threads.h>
.text
@@ -53,7 +54,13 @@ watchdog_handler:
.type touch_nmi_watchdog,@function
touch_nmi_watchdog:
clr d0
- mov d0,(watchdog_alert_counter)
+ clr d1
+ mov watchdog_alert_counter, a0
+ setlb
+ mov d0, (a0+)
+ inc d1
+ cmp NR_CPUS, d1
+ lne
ret [],0
.size touch_nmi_watchdog,.-touch_nmi_watchdog
diff --git a/arch/mn10300/kernel/mn10300-watchdog.c b/arch/mn10300/kernel/mn10300-watchdog.c
index f362d9d138f1..c5e12bfd9fcd 100644
--- a/arch/mn10300/kernel/mn10300-watchdog.c
+++ b/arch/mn10300/kernel/mn10300-watchdog.c
@@ -30,7 +30,7 @@
static DEFINE_SPINLOCK(watchdog_print_lock);
static unsigned int watchdog;
static unsigned int watchdog_hz = 1;
-unsigned int watchdog_alert_counter;
+unsigned int watchdog_alert_counter[NR_CPUS];
EXPORT_SYMBOL(touch_nmi_watchdog);
@@ -39,9 +39,6 @@ EXPORT_SYMBOL(touch_nmi_watchdog);
* is to check its timer makes IRQ counts. If they are not
* changing then that CPU has some problem.
*
- * as these watchdog NMI IRQs are generated on every CPU, we only
- * have to check the current processor.
- *
* since NMIs dont listen to _any_ locks, we have to be extremely
* careful not to rely on unsafe variables. The printk might lock
* up though, so we have to break up any console locks first ...
@@ -69,8 +66,8 @@ int __init check_watchdog(void)
printk(KERN_INFO "OK.\n");
- /* now that we know it works we can reduce NMI frequency to
- * something more reasonable; makes a difference in some configs
+ /* now that we know it works we can reduce NMI frequency to something
+ * more reasonable; makes a difference in some configs
*/
watchdog_hz = 1;
@@ -121,15 +118,22 @@ void __init watchdog_go(void)
}
}
+#ifdef CONFIG_SMP
+static void watchdog_dump_register(void *dummy)
+{
+ printk(KERN_ERR "--- Register Dump (CPU%d) ---\n", CPUID);
+ show_registers(current_frame());
+}
+#endif
+
asmlinkage
void watchdog_interrupt(struct pt_regs *regs, enum exception_code excep)
{
-
/*
* Since current-> is always on the stack, and we always switch
* the stack NMI-atomically, it's safe to use smp_processor_id().
*/
- int sum, cpu = smp_processor_id();
+ int sum, cpu;
int irq = NMIIRQ;
u8 wdt, tmp;
@@ -138,43 +142,61 @@ void watchdog_interrupt(struct pt_regs *regs, enum exception_code excep)
tmp = WDCTR;
NMICR = NMICR_WDIF;
- nmi_count(cpu)++;
+ nmi_count(smp_processor_id())++;
kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
- sum = irq_stat[cpu].__irq_count;
-
- if (last_irq_sums[cpu] == sum) {
- /*
- * Ayiee, looks like this CPU is stuck ...
- * wait a few IRQs (5 seconds) before doing the oops ...
- */
- watchdog_alert_counter++;
- if (watchdog_alert_counter == 5 * watchdog_hz) {
- spin_lock(&watchdog_print_lock);
+
+ for_each_online_cpu(cpu) {
+
+ sum = irq_stat[cpu].__irq_count;
+
+ if ((last_irq_sums[cpu] == sum)
+#if defined(CONFIG_GDBSTUB) && defined(CONFIG_SMP)
+ && !(CHK_GDBSTUB_BUSY()
+ || atomic_read(&cpu_doing_single_step))
+#endif
+ ) {
/*
- * We are in trouble anyway, lets at least try
- * to get a message out.
+ * Ayiee, looks like this CPU is stuck ...
+ * wait a few IRQs (5 seconds) before doing the oops ...
*/
- bust_spinlocks(1);
- printk(KERN_ERR
- "NMI Watchdog detected LOCKUP on CPU%d,"
- " pc %08lx, registers:\n",
- cpu, regs->pc);
- show_registers(regs);
- printk("console shuts up ...\n");
- console_silent();
- spin_unlock(&watchdog_print_lock);
- bust_spinlocks(0);
+ watchdog_alert_counter[cpu]++;
+ if (watchdog_alert_counter[cpu] == 5 * watchdog_hz) {
+ spin_lock(&watchdog_print_lock);
+ /*
+ * We are in trouble anyway, lets at least try
+ * to get a message out.
+ */
+ bust_spinlocks(1);
+ printk(KERN_ERR
+ "NMI Watchdog detected LOCKUP on CPU%d,"
+ " pc %08lx, registers:\n",
+ cpu, regs->pc);
+#ifdef CONFIG_SMP
+ printk(KERN_ERR
+ "--- Register Dump (CPU%d) ---\n",
+ CPUID);
+#endif
+ show_registers(regs);
+#ifdef CONFIG_SMP
+ smp_nmi_call_function(watchdog_dump_register,
+ NULL, 1);
+#endif
+ printk(KERN_NOTICE "console shuts up ...\n");
+ console_silent();
+ spin_unlock(&watchdog_print_lock);
+ bust_spinlocks(0);
#ifdef CONFIG_GDBSTUB
- if (gdbstub_busy)
- gdbstub_exception(regs, excep);
- else
- gdbstub_intercept(regs, excep);
+ if (CHK_GDBSTUB_BUSY_AND_ACTIVE())
+ gdbstub_exception(regs, excep);
+ else
+ gdbstub_intercept(regs, excep);
#endif
- do_exit(SIGSEGV);
+ do_exit(SIGSEGV);
+ }
+ } else {
+ last_irq_sums[cpu] = sum;
+ watchdog_alert_counter[cpu] = 0;
}
- } else {
- last_irq_sums[cpu] = sum;
- watchdog_alert_counter = 0;
}
WDCTR = wdt | WDCTR_WDRST;
diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c
index f48373e2bc1c..0d0f8049a17b 100644
--- a/arch/mn10300/kernel/process.c
+++ b/arch/mn10300/kernel/process.c
@@ -57,6 +57,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
+#if !defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU)
/*
* we use this if we don't have any better idle routine
*/
@@ -69,6 +70,35 @@ static void default_idle(void)
local_irq_enable();
}
+#else /* !CONFIG_SMP || CONFIG_HOTPLUG_CPU */
+/*
+ * On SMP it's slightly faster (but much more power-consuming!)
+ * to poll the ->work.need_resched flag instead of waiting for the
+ * cross-CPU IPI to arrive. Use this option with caution.
+ */
+static inline void poll_idle(void)
+{
+ int oldval;
+
+ local_irq_enable();
+
+ /*
+ * Deal with another CPU just having chosen a thread to
+ * run here:
+ */
+ oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
+
+ if (!oldval) {
+ set_thread_flag(TIF_POLLING_NRFLAG);
+ while (!need_resched())
+ cpu_relax();
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+ } else {
+ set_need_resched();
+ }
+}
+#endif /* !CONFIG_SMP || CONFIG_HOTPLUG_CPU */
+
/*
* the idle thread
* - there's no useful work to be done, so just try to conserve power and have
@@ -77,8 +107,6 @@ static void default_idle(void)
*/
void cpu_idle(void)
{
- int cpu = smp_processor_id();
-
/* endless idle loop with no priority at all */
for (;;) {
while (!need_resched()) {
@@ -86,10 +114,13 @@ void cpu_idle(void)
smp_rmb();
idle = pm_idle;
- if (!idle)
+ if (!idle) {
+#if defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU)
+ idle = poll_idle;
+#else /* CONFIG_SMP && !CONFIG_HOTPLUG_CPU */
idle = default_idle;
-
- irq_stat[cpu].idle_timestamp = jiffies;
+#endif /* CONFIG_SMP && !CONFIG_HOTPLUG_CPU */
+ }
idle();
}
@@ -197,6 +228,7 @@ int copy_thread(unsigned long clone_flags,
unsigned long c_usp, unsigned long ustk_size,
struct task_struct *p, struct pt_regs *kregs)
{
+ struct thread_info *ti = task_thread_info(p);
struct pt_regs *c_uregs, *c_kregs, *uregs;
unsigned long c_ksp;
@@ -217,7 +249,7 @@ int copy_thread(unsigned long clone_flags,
/* the new TLS pointer is passed in as arg #5 to sys_clone() */
if (clone_flags & CLONE_SETTLS)
- c_uregs->e2 = __frame->d3;
+ c_uregs->e2 = current_frame()->d3;
/* set up the return kernel frame if called from kernel_thread() */
c_kregs = c_uregs;
@@ -235,7 +267,7 @@ int copy_thread(unsigned long clone_flags,
}
/* set up things up so the scheduler can start the new task */
- p->thread.__frame = c_kregs;
+ ti->frame = c_kregs;
p->thread.a3 = (unsigned long) c_kregs;
p->thread.sp = c_ksp;
p->thread.pc = (unsigned long) ret_from_fork;
@@ -247,25 +279,26 @@ int copy_thread(unsigned long clone_flags,
/*
* clone a process
- * - tlsptr is retrieved by copy_thread() from __frame->d3
+ * - tlsptr is retrieved by copy_thread() from current_frame()->d3
*/
asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
int __user *parent_tidptr, int __user *child_tidptr,
int __user *tlsptr)
{
- return do_fork(clone_flags, newsp ?: __frame->sp, __frame, 0,
- parent_tidptr, child_tidptr);
+ return do_fork(clone_flags, newsp ?: current_frame()->sp,
+ current_frame(), 0, parent_tidptr, child_tidptr);
}
asmlinkage long sys_fork(void)
{
- return do_fork(SIGCHLD, __frame->sp, __frame, 0, NULL, NULL);
+ return do_fork(SIGCHLD, current_frame()->sp,
+ current_frame(), 0, NULL, NULL);
}
asmlinkage long sys_vfork(void)
{
- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, __frame->sp, __frame,
- 0, NULL, NULL);
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, current_frame()->sp,
+ current_frame(), 0, NULL, NULL);
}
asmlinkage long sys_execve(const char __user *name,
@@ -279,7 +312,7 @@ asmlinkage long sys_execve(const char __user *name,
error = PTR_ERR(filename);
if (IS_ERR(filename))
return error;
- error = do_execve(filename, argv, envp, __frame);
+ error = do_execve(filename, argv, envp, current_frame());
putname(filename);
return error;
}
diff --git a/arch/mn10300/kernel/profile.c b/arch/mn10300/kernel/profile.c
index 20d7d0306b16..4f342f75d00c 100644
--- a/arch/mn10300/kernel/profile.c
+++ b/arch/mn10300/kernel/profile.c
@@ -41,7 +41,7 @@ static __init int profile_init(void)
tmp = TM11ICR;
printk(KERN_INFO "Profiling initiated on timer 11, priority 0, %uHz\n",
- mn10300_ioclk / 8 / (TM11BR + 1));
+ MN10300_IOCLK / 8 / (TM11BR + 1));
printk(KERN_INFO "Profile histogram stored %p-%p\n",
prof_buffer, (u8 *)(prof_buffer + prof_len) - 1);
diff --git a/arch/mn10300/kernel/ptrace.c b/arch/mn10300/kernel/ptrace.c
index cf847dabc1bd..5c0b07e61006 100644
--- a/arch/mn10300/kernel/ptrace.c
+++ b/arch/mn10300/kernel/ptrace.c
@@ -295,31 +295,31 @@ void ptrace_disable(struct task_struct *child)
/*
* handle the arch-specific side of process tracing
*/
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
unsigned long tmp;
int ret;
+ unsigned long __user *datap = (unsigned long __user *) data;
switch (request) {
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR:
ret = -EIO;
- if ((addr & 3) || addr < 0 ||
- addr > sizeof(struct user) - 3)
+ if ((addr & 3) || addr > sizeof(struct user) - 3)
break;
tmp = 0; /* Default return condition */
if (addr < NR_PTREGS << 2)
tmp = get_stack_long(child,
ptrace_regid_to_frame[addr]);
- ret = put_user(tmp, (unsigned long *) data);
+ ret = put_user(tmp, datap);
break;
/* write the word at location addr in the USER area */
case PTRACE_POKEUSR:
ret = -EIO;
- if ((addr & 3) || addr < 0 ||
- addr > sizeof(struct user) - 3)
+ if ((addr & 3) || addr > sizeof(struct user) - 3)
break;
ret = 0;
@@ -332,25 +332,25 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
return copy_regset_to_user(child, &user_mn10300_native_view,
REGSET_GENERAL,
0, NR_PTREGS * sizeof(long),
- (void __user *)data);
+ datap);
case PTRACE_SETREGS: /* Set all integer regs in the child. */
return copy_regset_from_user(child, &user_mn10300_native_view,
REGSET_GENERAL,
0, NR_PTREGS * sizeof(long),
- (const void __user *)data);
+ datap);
case PTRACE_GETFPREGS: /* Get the child FPU state. */
return copy_regset_to_user(child, &user_mn10300_native_view,
REGSET_FPU,
0, sizeof(struct fpu_state_struct),
- (void __user *)data);
+ datap);
case PTRACE_SETFPREGS: /* Set the child FPU state. */
return copy_regset_from_user(child, &user_mn10300_native_view,
REGSET_FPU,
0, sizeof(struct fpu_state_struct),
- (const void __user *)data);
+ datap);
default:
ret = ptrace_request(child, request, addr, data);
diff --git a/arch/mn10300/kernel/rtc.c b/arch/mn10300/kernel/rtc.c
index 4eef0e7224f6..e9e20f9a4dd3 100644
--- a/arch/mn10300/kernel/rtc.c
+++ b/arch/mn10300/kernel/rtc.c
@@ -20,18 +20,22 @@
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock);
-/* time for RTC to update itself in ioclks */
-static unsigned long mn10300_rtc_update_period;
-
+/*
+ * Read the current RTC time
+ */
void read_persistent_clock(struct timespec *ts)
{
struct rtc_time tm;
get_rtc_time(&tm);
- ts->tv_sec = mktime(tm.tm_year, tm.tm_mon, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
ts->tv_nsec = 0;
+ ts->tv_sec = mktime(tm.tm_year, tm.tm_mon, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ /* if rtc is way off in the past, set something reasonable */
+ if (ts->tv_sec < 0)
+ ts->tv_sec = mktime(2009, 1, 1, 12, 0, 0);
}
/*
@@ -115,39 +119,14 @@ int update_persistent_clock(struct timespec now)
*/
void __init calibrate_clock(void)
{
- unsigned long count0, counth, count1;
unsigned char status;
/* make sure the RTC is running and is set to operate in 24hr mode */
status = RTSRC;
RTCRB |= RTCRB_SET;
RTCRB |= RTCRB_TM_24HR;
+ RTCRB &= ~RTCRB_DM_BINARY;
RTCRA |= RTCRA_DVR;
RTCRA &= ~RTCRA_DVR;
RTCRB &= ~RTCRB_SET;
-
- /* work out the clock speed by counting clock cycles between ends of
- * the RTC update cycle - track the RTC through one complete update
- * cycle (1 second)
- */
- startup_timestamp_counter();
-
- while (!(RTCRA & RTCRA_UIP)) {}
- while ((RTCRA & RTCRA_UIP)) {}
-
- count0 = TMTSCBC;
-
- while (!(RTCRA & RTCRA_UIP)) {}
-
- counth = TMTSCBC;
-
- while ((RTCRA & RTCRA_UIP)) {}
-
- count1 = TMTSCBC;
-
- shutdown_timestamp_counter();
-
- MN10300_TSCCLK = count0 - count1; /* the timers count down */
- mn10300_rtc_update_period = counth - count1;
- MN10300_TSC_PER_HZ = MN10300_TSCCLK / HZ;
}
diff --git a/arch/mn10300/kernel/setup.c b/arch/mn10300/kernel/setup.c
index d464affcba0e..9e7a3209a3e1 100644
--- a/arch/mn10300/kernel/setup.c
+++ b/arch/mn10300/kernel/setup.c
@@ -22,6 +22,7 @@
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/seq_file.h>
+#include <linux/cpu.h>
#include <asm/processor.h>
#include <linux/console.h>
#include <asm/uaccess.h>
@@ -30,7 +31,6 @@
#include <asm/io.h>
#include <asm/smp.h>
#include <proc/proc.h>
-#include <asm/busctl-regs.h>
#include <asm/fpu.h>
#include <asm/sections.h>
@@ -64,11 +64,13 @@ unsigned long memory_size;
struct thread_info *__current_ti = &init_thread_union.thread_info;
struct task_struct *__current = &init_task;
-#define mn10300_known_cpus 3
+#define mn10300_known_cpus 5
static const char *const mn10300_cputypes[] = {
- "am33v1",
- "am33v2",
- "am34v1",
+ "am33-1",
+ "am33-2",
+ "am34-1",
+ "am33-3",
+ "am34-2",
"unknown"
};
@@ -123,6 +125,7 @@ void __init setup_arch(char **cmdline_p)
cpu_init();
unit_setup();
+ smp_init_cpus();
parse_mem_cmdline(cmdline_p);
init_mm.start_code = (unsigned long)&_text;
@@ -179,57 +182,55 @@ void __init setup_arch(char **cmdline_p)
void __init cpu_init(void)
{
unsigned long cpurev = CPUREV, type;
- unsigned long base, size;
type = (CPUREV & CPUREV_TYPE) >> CPUREV_TYPE_S;
if (type > mn10300_known_cpus)
type = mn10300_known_cpus;
- printk(KERN_INFO "Matsushita %s, rev %ld\n",
+ printk(KERN_INFO "Panasonic %s, rev %ld\n",
mn10300_cputypes[type],
(cpurev & CPUREV_REVISION) >> CPUREV_REVISION_S);
- /* determine the memory size and base from the memory controller regs */
- memory_size = 0;
-
- base = SDBASE(0);
- if (base & SDBASE_CE) {
- size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT;
- size = ~size + 1;
- base &= SDBASE_CBA;
+ get_mem_info(&phys_memory_base, &memory_size);
+ phys_memory_end = phys_memory_base + memory_size;
- printk(KERN_INFO "SDRAM[0]: %luMb @%08lx\n", size >> 20, base);
- memory_size += size;
- phys_memory_base = base;
- }
+ fpu_init_state();
+}
- base = SDBASE(1);
- if (base & SDBASE_CE) {
- size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT;
- size = ~size + 1;
- base &= SDBASE_CBA;
+static struct cpu cpu_devices[NR_CPUS];
- printk(KERN_INFO "SDRAM[1]: %luMb @%08lx\n", size >> 20, base);
- memory_size += size;
- if (phys_memory_base == 0)
- phys_memory_base = base;
- }
+static int __init topology_init(void)
+{
+ int i;
- phys_memory_end = phys_memory_base + memory_size;
+ for_each_present_cpu(i)
+ register_cpu(&cpu_devices[i], i);
-#ifdef CONFIG_FPU
- fpu_init_state();
-#endif
+ return 0;
}
+subsys_initcall(topology_init);
+
/*
* Get CPU information for use by the procfs.
*/
static int show_cpuinfo(struct seq_file *m, void *v)
{
+#ifdef CONFIG_SMP
+ struct mn10300_cpuinfo *c = v;
+ unsigned long cpu_id = c - cpu_data;
+ unsigned long cpurev = c->type, type, icachesz, dcachesz;
+#else /* CONFIG_SMP */
+ unsigned long cpu_id = 0;
unsigned long cpurev = CPUREV, type, icachesz, dcachesz;
+#endif /* CONFIG_SMP */
- type = (CPUREV & CPUREV_TYPE) >> CPUREV_TYPE_S;
+#ifdef CONFIG_SMP
+ if (!cpu_online(cpu_id))
+ return 0;
+#endif
+
+ type = (cpurev & CPUREV_TYPE) >> CPUREV_TYPE_S;
if (type > mn10300_known_cpus)
type = mn10300_known_cpus;
@@ -244,13 +245,14 @@ static int show_cpuinfo(struct seq_file *m, void *v)
1024;
seq_printf(m,
- "processor : 0\n"
- "vendor_id : Matsushita\n"
+ "processor : %ld\n"
+ "vendor_id : " PROCESSOR_VENDOR_NAME "\n"
"cpu core : %s\n"
"cpu rev : %lu\n"
"model name : " PROCESSOR_MODEL_NAME "\n"
"icache size: %lu\n"
"dcache size: %lu\n",
+ cpu_id,
mn10300_cputypes[type],
(cpurev & CPUREV_REVISION) >> CPUREV_REVISION_S,
icachesz,
@@ -262,8 +264,13 @@ static int show_cpuinfo(struct seq_file *m, void *v)
"bogomips : %lu.%02lu\n\n",
MN10300_IOCLK / 1000000,
(MN10300_IOCLK / 10000) % 100,
+#ifdef CONFIG_SMP
+ c->loops_per_jiffy / (500000 / HZ),
+ (c->loops_per_jiffy / (5000 / HZ)) % 100
+#else /* CONFIG_SMP */
loops_per_jiffy / (500000 / HZ),
(loops_per_jiffy / (5000 / HZ)) % 100
+#endif /* CONFIG_SMP */
);
return 0;
diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c
index d4de05ab7864..690f4e9507d7 100644
--- a/arch/mn10300/kernel/signal.c
+++ b/arch/mn10300/kernel/signal.c
@@ -91,7 +91,7 @@ asmlinkage long sys_sigaction(int sig,
*/
asmlinkage long sys_sigaltstack(const stack_t __user *uss, stack_t *uoss)
{
- return do_sigaltstack(uss, uoss, __frame->sp);
+ return do_sigaltstack(uss, uoss, current_frame()->sp);
}
/*
@@ -156,10 +156,11 @@ badframe:
*/
asmlinkage long sys_sigreturn(void)
{
- struct sigframe __user *frame = (struct sigframe __user *) __frame->sp;
+ struct sigframe __user *frame;
sigset_t set;
long d0;
+ frame = (struct sigframe __user *) current_frame()->sp;
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
if (__get_user(set.sig[0], &frame->sc.oldmask))
@@ -176,7 +177,7 @@ asmlinkage long sys_sigreturn(void)
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
- if (restore_sigcontext(__frame, &frame->sc, &d0))
+ if (restore_sigcontext(current_frame(), &frame->sc, &d0))
goto badframe;
return d0;
@@ -191,11 +192,11 @@ badframe:
*/
asmlinkage long sys_rt_sigreturn(void)
{
- struct rt_sigframe __user *frame =
- (struct rt_sigframe __user *) __frame->sp;
+ struct rt_sigframe __user *frame;
sigset_t set;
- unsigned long d0;
+ long d0;
+ frame = (struct rt_sigframe __user *) current_frame()->sp;
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
@@ -207,10 +208,11 @@ asmlinkage long sys_rt_sigreturn(void)
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
- if (restore_sigcontext(__frame, &frame->uc.uc_mcontext, &d0))
+ if (restore_sigcontext(current_frame(), &frame->uc.uc_mcontext, &d0))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, __frame->sp) == -EFAULT)
+ if (do_sigaltstack(&frame->uc.uc_stack, NULL, current_frame()->sp) ==
+ -EFAULT)
goto badframe;
return d0;
@@ -572,7 +574,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
- tracehook_notify_resume(__frame);
+ tracehook_notify_resume(current_frame());
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
diff --git a/arch/mn10300/kernel/smp-low.S b/arch/mn10300/kernel/smp-low.S
new file mode 100644
index 000000000000..72938cefc05e
--- /dev/null
+++ b/arch/mn10300/kernel/smp-low.S
@@ -0,0 +1,97 @@
+/* SMP IPI low-level handler
+ *
+ * Copyright (C) 2006-2007 Matsushita Electric Industrial Co., 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.
+ *
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/system.h>
+#include <asm/thread_info.h>
+#include <asm/cpu-regs.h>
+#include <proc/smp-regs.h>
+#include <asm/asm-offsets.h>
+#include <asm/frame.inc>
+
+ .am33_2
+
+###############################################################################
+#
+# IPI interrupt handler
+#
+###############################################################################
+ .globl mn10300_low_ipi_handler
+mn10300_low_ipi_handler:
+ add -4,sp
+ mov d0,(sp)
+ movhu (IAGR),d0
+ and IAGR_GN,d0
+ lsr 0x2,d0
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+ cmp FLUSH_CACHE_IPI,d0
+ beq mn10300_flush_cache_ipi
+#endif
+ cmp SMP_BOOT_IRQ,d0
+ beq mn10300_smp_boot_ipi
+ /* OTHERS */
+ mov (sp),d0
+ add 4,sp
+#ifdef CONFIG_GDBSTUB
+ jmp gdbstub_io_rx_handler
+#else
+ jmp end
+#endif
+
+###############################################################################
+#
+# Cache flush IPI interrupt handler
+#
+###############################################################################
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+mn10300_flush_cache_ipi:
+ mov (sp),d0
+ add 4,sp
+
+ /* FLUSH_CACHE_IPI */
+ add -4,sp
+ SAVE_ALL
+ mov GxICR_DETECT,d2
+ movbu d2,(GxICR(FLUSH_CACHE_IPI)) # ACK the interrupt
+ movhu (GxICR(FLUSH_CACHE_IPI)),d2
+ call smp_cache_interrupt[],0
+ RESTORE_ALL
+ jmp end
+#endif
+
+###############################################################################
+#
+# SMP boot CPU IPI interrupt handler
+#
+###############################################################################
+mn10300_smp_boot_ipi:
+ /* clear interrupt */
+ movhu (GxICR(SMP_BOOT_IRQ)),d0
+ and ~GxICR_REQUEST,d0
+ movhu d0,(GxICR(SMP_BOOT_IRQ))
+ mov (sp),d0
+ add 4,sp
+
+ # get stack
+ mov (CPUID),a0
+ add -1,a0
+ add a0,a0
+ add a0,a0
+ mov (start_stack,a0),a0
+ mov a0,sp
+ jmp initialize_secondary
+
+
+# Jump here after RTI to suppress the icache lookahead
+end:
diff --git a/arch/mn10300/kernel/smp.c b/arch/mn10300/kernel/smp.c
new file mode 100644
index 000000000000..0dcd1c686ba8
--- /dev/null
+++ b/arch/mn10300/kernel/smp.c
@@ -0,0 +1,1152 @@
+/* SMP support routines.
+ *
+ * Copyright (C) 2006-2008 Panasonic Corporation
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/cpumask.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/profile.h>
+#include <linux/smp.h>
+#include <asm/tlbflush.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/processor.h>
+#include <asm/bug.h>
+#include <asm/exceptions.h>
+#include <asm/hardirq.h>
+#include <asm/fpu.h>
+#include <asm/mmu_context.h>
+#include <asm/thread_info.h>
+#include <asm/cpu-regs.h>
+#include <asm/intctl-regs.h>
+#include "internal.h"
+
+#ifdef CONFIG_HOTPLUG_CPU
+#include <linux/cpu.h>
+#include <asm/cacheflush.h>
+
+static unsigned long sleep_mode[NR_CPUS];
+
+static void run_sleep_cpu(unsigned int cpu);
+static void run_wakeup_cpu(unsigned int cpu);
+#endif /* CONFIG_HOTPLUG_CPU */
+
+/*
+ * Debug Message function
+ */
+
+#undef DEBUG_SMP
+#ifdef DEBUG_SMP
+#define Dprintk(fmt, ...) printk(KERN_DEBUG fmt, ##__VA_ARGS__)
+#else
+#define Dprintk(fmt, ...) no_printk(KERN_DEBUG fmt, ##__VA_ARGS__)
+#endif
+
+/* timeout value in msec for smp_nmi_call_function. zero is no timeout. */
+#define CALL_FUNCTION_NMI_IPI_TIMEOUT 0
+
+/*
+ * Structure and data for smp_nmi_call_function().
+ */
+struct nmi_call_data_struct {
+ smp_call_func_t func;
+ void *info;
+ cpumask_t started;
+ cpumask_t finished;
+ int wait;
+ char size_alignment[0]
+ __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
+} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
+
+static DEFINE_SPINLOCK(smp_nmi_call_lock);
+static struct nmi_call_data_struct *nmi_call_data;
+
+/*
+ * Data structures and variables
+ */
+static cpumask_t cpu_callin_map; /* Bitmask of callin CPUs */
+static cpumask_t cpu_callout_map; /* Bitmask of callout CPUs */
+cpumask_t cpu_boot_map; /* Bitmask of boot APs */
+unsigned long start_stack[NR_CPUS - 1];
+
+/*
+ * Per CPU parameters
+ */
+struct mn10300_cpuinfo cpu_data[NR_CPUS] __cacheline_aligned;
+
+static int cpucount; /* The count of boot CPUs */
+static cpumask_t smp_commenced_mask;
+cpumask_t cpu_initialized __initdata = CPU_MASK_NONE;
+
+/*
+ * Function Prototypes
+ */
+static int do_boot_cpu(int);
+static void smp_show_cpu_info(int cpu_id);
+static void smp_callin(void);
+static void smp_online(void);
+static void smp_store_cpu_info(int);
+static void smp_cpu_init(void);
+static void smp_tune_scheduling(void);
+static void send_IPI_mask(const cpumask_t *cpumask, int irq);
+static void init_ipi(void);
+
+/*
+ * IPI Initialization interrupt definitions
+ */
+static void mn10300_ipi_disable(unsigned int irq);
+static void mn10300_ipi_enable(unsigned int irq);
+static void mn10300_ipi_ack(unsigned int irq);
+static void mn10300_ipi_nop(unsigned int irq);
+
+static struct irq_chip mn10300_ipi_type = {
+ .name = "cpu_ipi",
+ .disable = mn10300_ipi_disable,
+ .enable = mn10300_ipi_enable,
+ .ack = mn10300_ipi_ack,
+ .eoi = mn10300_ipi_nop
+};
+
+static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id);
+static irqreturn_t smp_call_function_interrupt(int irq, void *dev_id);
+
+static struct irqaction reschedule_ipi = {
+ .handler = smp_reschedule_interrupt,
+ .name = "smp reschedule IPI"
+};
+static struct irqaction call_function_ipi = {
+ .handler = smp_call_function_interrupt,
+ .name = "smp call function IPI"
+};
+
+#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+static irqreturn_t smp_ipi_timer_interrupt(int irq, void *dev_id);
+static struct irqaction local_timer_ipi = {
+ .handler = smp_ipi_timer_interrupt,
+ .flags = IRQF_DISABLED,
+ .name = "smp local timer IPI"
+};
+#endif
+
+/**
+ * init_ipi - Initialise the IPI mechanism
+ */
+static void init_ipi(void)
+{
+ unsigned long flags;
+ u16 tmp16;
+
+ /* set up the reschedule IPI */
+ set_irq_chip_and_handler(RESCHEDULE_IPI,
+ &mn10300_ipi_type, handle_percpu_irq);
+ setup_irq(RESCHEDULE_IPI, &reschedule_ipi);
+ set_intr_level(RESCHEDULE_IPI, RESCHEDULE_GxICR_LV);
+ mn10300_ipi_enable(RESCHEDULE_IPI);
+
+ /* set up the call function IPI */
+ set_irq_chip_and_handler(CALL_FUNC_SINGLE_IPI,
+ &mn10300_ipi_type, handle_percpu_irq);
+ setup_irq(CALL_FUNC_SINGLE_IPI, &call_function_ipi);
+ set_intr_level(CALL_FUNC_SINGLE_IPI, CALL_FUNCTION_GxICR_LV);
+ mn10300_ipi_enable(CALL_FUNC_SINGLE_IPI);
+
+ /* set up the local timer IPI */
+#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || \
+ defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+ set_irq_chip_and_handler(LOCAL_TIMER_IPI,
+ &mn10300_ipi_type, handle_percpu_irq);
+ setup_irq(LOCAL_TIMER_IPI, &local_timer_ipi);
+ set_intr_level(LOCAL_TIMER_IPI, LOCAL_TIMER_GxICR_LV);
+ mn10300_ipi_enable(LOCAL_TIMER_IPI);
+#endif
+
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+ /* set up the cache flush IPI */
+ flags = arch_local_cli_save();
+ __set_intr_stub(NUM2EXCEP_IRQ_LEVEL(FLUSH_CACHE_GxICR_LV),
+ mn10300_low_ipi_handler);
+ GxICR(FLUSH_CACHE_IPI) = FLUSH_CACHE_GxICR_LV | GxICR_DETECT;
+ mn10300_ipi_enable(FLUSH_CACHE_IPI);
+ arch_local_irq_restore(flags);
+#endif
+
+ /* set up the NMI call function IPI */
+ flags = arch_local_cli_save();
+ GxICR(CALL_FUNCTION_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT;
+ tmp16 = GxICR(CALL_FUNCTION_NMI_IPI);
+ arch_local_irq_restore(flags);
+
+ /* set up the SMP boot IPI */
+ flags = arch_local_cli_save();
+ __set_intr_stub(NUM2EXCEP_IRQ_LEVEL(SMP_BOOT_GxICR_LV),
+ mn10300_low_ipi_handler);
+ arch_local_irq_restore(flags);
+}
+
+/**
+ * mn10300_ipi_shutdown - Shut down handling of an IPI
+ * @irq: The IPI to be shut down.
+ */
+static void mn10300_ipi_shutdown(unsigned int irq)
+{
+ unsigned long flags;
+ u16 tmp;
+
+ flags = arch_local_cli_save();
+
+ tmp = GxICR(irq);
+ GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT;
+ tmp = GxICR(irq);
+
+ arch_local_irq_restore(flags);
+}
+
+/**
+ * mn10300_ipi_enable - Enable an IPI
+ * @irq: The IPI to be enabled.
+ */
+static void mn10300_ipi_enable(unsigned int irq)
+{
+ unsigned long flags;
+ u16 tmp;
+
+ flags = arch_local_cli_save();
+
+ tmp = GxICR(irq);
+ GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE;
+ tmp = GxICR(irq);
+
+ arch_local_irq_restore(flags);
+}
+
+/**
+ * mn10300_ipi_disable - Disable an IPI
+ * @irq: The IPI to be disabled.
+ */
+static void mn10300_ipi_disable(unsigned int irq)
+{
+ unsigned long flags;
+ u16 tmp;
+
+ flags = arch_local_cli_save();
+
+ tmp = GxICR(irq);
+ GxICR(irq) = tmp & GxICR_LEVEL;
+ tmp = GxICR(irq);
+
+ arch_local_irq_restore(flags);
+}
+
+/**
+ * mn10300_ipi_ack - Acknowledge an IPI interrupt in the PIC
+ * @irq: The IPI to be acknowledged.
+ *
+ * Clear the interrupt detection flag for the IPI on the appropriate interrupt
+ * channel in the PIC.
+ */
+static void mn10300_ipi_ack(unsigned int irq)
+{
+ unsigned long flags;
+ u16 tmp;
+
+ flags = arch_local_cli_save();
+ GxICR_u8(irq) = GxICR_DETECT;
+ tmp = GxICR(irq);
+ arch_local_irq_restore(flags);
+}
+
+/**
+ * mn10300_ipi_nop - Dummy IPI action
+ * @irq: The IPI to be acted upon.
+ */
+static void mn10300_ipi_nop(unsigned int irq)
+{
+}
+
+/**
+ * send_IPI_mask - Send IPIs to all CPUs in list
+ * @cpumask: The list of CPUs to target.
+ * @irq: The IPI request to be sent.
+ *
+ * Send the specified IPI to all the CPUs in the list, not waiting for them to
+ * finish before returning. The caller is responsible for synchronisation if
+ * that is needed.
+ */
+static void send_IPI_mask(const cpumask_t *cpumask, int irq)
+{
+ int i;
+ u16 tmp;
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (cpu_isset(i, *cpumask)) {
+ /* send IPI */
+ tmp = CROSS_GxICR(irq, i);
+ CROSS_GxICR(irq, i) =
+ tmp | GxICR_REQUEST | GxICR_DETECT;
+ tmp = CROSS_GxICR(irq, i); /* flush write buffer */
+ }
+ }
+}
+
+/**
+ * send_IPI_self - Send an IPI to this CPU.
+ * @irq: The IPI request to be sent.
+ *
+ * Send the specified IPI to the current CPU.
+ */
+void send_IPI_self(int irq)
+{
+ send_IPI_mask(cpumask_of(smp_processor_id()), irq);
+}
+
+/**
+ * send_IPI_allbutself - Send IPIs to all the other CPUs.
+ * @irq: The IPI request to be sent.
+ *
+ * Send the specified IPI to all CPUs in the system barring the current one,
+ * not waiting for them to finish before returning. The caller is responsible
+ * for synchronisation if that is needed.
+ */
+void send_IPI_allbutself(int irq)
+{
+ cpumask_t cpumask;
+
+ cpumask = cpu_online_map;
+ cpu_clear(smp_processor_id(), cpumask);
+ send_IPI_mask(&cpumask, irq);
+}
+
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
+{
+ BUG();
+ /*send_IPI_mask(mask, CALL_FUNCTION_IPI);*/
+}
+
+void arch_send_call_function_single_ipi(int cpu)
+{
+ send_IPI_mask(cpumask_of(cpu), CALL_FUNC_SINGLE_IPI);
+}
+
+/**
+ * smp_send_reschedule - Send reschedule IPI to a CPU
+ * @cpu: The CPU to target.
+ */
+void smp_send_reschedule(int cpu)
+{
+ send_IPI_mask(cpumask_of(cpu), RESCHEDULE_IPI);
+}
+
+/**
+ * smp_nmi_call_function - Send a call function NMI IPI to all CPUs
+ * @func: The function to ask to be run.
+ * @info: The context data to pass to that function.
+ * @wait: If true, wait (atomically) until function is run on all CPUs.
+ *
+ * Send a non-maskable request to all CPUs in the system, requesting them to
+ * run the specified function with the given context data, and, potentially, to
+ * wait for completion of that function on all CPUs.
+ *
+ * Returns 0 if successful, -ETIMEDOUT if we were asked to wait, but hit the
+ * timeout.
+ */
+int smp_nmi_call_function(smp_call_func_t func, void *info, int wait)
+{
+ struct nmi_call_data_struct data;
+ unsigned long flags;
+ unsigned int cnt;
+ int cpus, ret = 0;
+
+ cpus = num_online_cpus() - 1;
+ if (cpus < 1)
+ return 0;
+
+ data.func = func;
+ data.info = info;
+ data.started = cpu_online_map;
+ cpu_clear(smp_processor_id(), data.started);
+ data.wait = wait;
+ if (wait)
+ data.finished = data.started;
+
+ spin_lock_irqsave(&smp_nmi_call_lock, flags);
+ nmi_call_data = &data;
+ smp_mb();
+
+ /* Send a message to all other CPUs and wait for them to respond */
+ send_IPI_allbutself(CALL_FUNCTION_NMI_IPI);
+
+ /* Wait for response */
+ if (CALL_FUNCTION_NMI_IPI_TIMEOUT > 0) {
+ for (cnt = 0;
+ cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT &&
+ !cpus_empty(data.started);
+ cnt++)
+ mdelay(1);
+
+ if (wait && cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT) {
+ for (cnt = 0;
+ cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT &&
+ !cpus_empty(data.finished);
+ cnt++)
+ mdelay(1);
+ }
+
+ if (cnt >= CALL_FUNCTION_NMI_IPI_TIMEOUT)
+ ret = -ETIMEDOUT;
+
+ } else {
+ /* If timeout value is zero, wait until cpumask has been
+ * cleared */
+ while (!cpus_empty(data.started))
+ barrier();
+ if (wait)
+ while (!cpus_empty(data.finished))
+ barrier();
+ }
+
+ spin_unlock_irqrestore(&smp_nmi_call_lock, flags);
+ return ret;
+}
+
+/**
+ * stop_this_cpu - Callback to stop a CPU.
+ * @unused: Callback context (ignored).
+ */
+void stop_this_cpu(void *unused)
+{
+ static volatile int stopflag;
+ unsigned long flags;
+
+#ifdef CONFIG_GDBSTUB
+ /* In case of single stepping smp_send_stop by other CPU,
+ * clear procindebug to avoid deadlock.
+ */
+ atomic_set(&procindebug[smp_processor_id()], 0);
+#endif /* CONFIG_GDBSTUB */
+
+ flags = arch_local_cli_save();
+ cpu_clear(smp_processor_id(), cpu_online_map);
+
+ while (!stopflag)
+ cpu_relax();
+
+ cpu_set(smp_processor_id(), cpu_online_map);
+ arch_local_irq_restore(flags);
+}
+
+/**
+ * smp_send_stop - Send a stop request to all CPUs.
+ */
+void smp_send_stop(void)
+{
+ smp_nmi_call_function(stop_this_cpu, NULL, 0);
+}
+
+/**
+ * smp_reschedule_interrupt - Reschedule IPI handler
+ * @irq: The interrupt number.
+ * @dev_id: The device ID.
+ *
+ * We need do nothing here, since the scheduling will be effected on our way
+ * back through entry.S.
+ *
+ * Returns IRQ_HANDLED to indicate we handled the interrupt successfully.
+ */
+static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id)
+{
+ /* do nothing */
+ return IRQ_HANDLED;
+}
+
+/**
+ * smp_call_function_interrupt - Call function IPI handler
+ * @irq: The interrupt number.
+ * @dev_id: The device ID.
+ *
+ * Returns IRQ_HANDLED to indicate we handled the interrupt successfully.
+ */
+static irqreturn_t smp_call_function_interrupt(int irq, void *dev_id)
+{
+ /* generic_smp_call_function_interrupt(); */
+ generic_smp_call_function_single_interrupt();
+ return IRQ_HANDLED;
+}
+
+/**
+ * smp_nmi_call_function_interrupt - Non-maskable call function IPI handler
+ */
+void smp_nmi_call_function_interrupt(void)
+{
+ smp_call_func_t func = nmi_call_data->func;
+ void *info = nmi_call_data->info;
+ int wait = nmi_call_data->wait;
+
+ /* Notify the initiating CPU that I've grabbed the data and am about to
+ * execute the function
+ */
+ smp_mb();
+ cpu_clear(smp_processor_id(), nmi_call_data->started);
+ (*func)(info);
+
+ if (wait) {
+ smp_mb();
+ cpu_clear(smp_processor_id(), nmi_call_data->finished);
+ }
+}
+
+#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || \
+ defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+/**
+ * smp_ipi_timer_interrupt - Local timer IPI handler
+ * @irq: The interrupt number.
+ * @dev_id: The device ID.
+ *
+ * Returns IRQ_HANDLED to indicate we handled the interrupt successfully.
+ */
+static irqreturn_t smp_ipi_timer_interrupt(int irq, void *dev_id)
+{
+ return local_timer_interrupt();
+}
+#endif
+
+void __init smp_init_cpus(void)
+{
+ int i;
+ for (i = 0; i < NR_CPUS; i++) {
+ set_cpu_possible(i, true);
+ set_cpu_present(i, true);
+ }
+}
+
+/**
+ * smp_cpu_init - Initialise AP in start_secondary.
+ *
+ * For this Application Processor, set up init_mm, initialise FPU and set
+ * interrupt level 0-6 setting.
+ */
+static void __init smp_cpu_init(void)
+{
+ unsigned long flags;
+ int cpu_id = smp_processor_id();
+ u16 tmp16;
+
+ if (test_and_set_bit(cpu_id, &cpu_initialized)) {
+ printk(KERN_WARNING "CPU#%d already initialized!\n", cpu_id);
+ for (;;)
+ local_irq_enable();
+ }
+ printk(KERN_INFO "Initializing CPU#%d\n", cpu_id);
+
+ atomic_inc(&init_mm.mm_count);
+ current->active_mm = &init_mm;
+ BUG_ON(current->mm);
+
+ enter_lazy_tlb(&init_mm, current);
+
+ /* Force FPU initialization */
+ clear_using_fpu(current);
+
+ GxICR(CALL_FUNC_SINGLE_IPI) = CALL_FUNCTION_GxICR_LV | GxICR_DETECT;
+ mn10300_ipi_enable(CALL_FUNC_SINGLE_IPI);
+
+ GxICR(LOCAL_TIMER_IPI) = LOCAL_TIMER_GxICR_LV | GxICR_DETECT;
+ mn10300_ipi_enable(LOCAL_TIMER_IPI);
+
+ GxICR(RESCHEDULE_IPI) = RESCHEDULE_GxICR_LV | GxICR_DETECT;
+ mn10300_ipi_enable(RESCHEDULE_IPI);
+
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+ GxICR(FLUSH_CACHE_IPI) = FLUSH_CACHE_GxICR_LV | GxICR_DETECT;
+ mn10300_ipi_enable(FLUSH_CACHE_IPI);
+#endif
+
+ mn10300_ipi_shutdown(SMP_BOOT_IRQ);
+
+ /* Set up the non-maskable call function IPI */
+ flags = arch_local_cli_save();
+ GxICR(CALL_FUNCTION_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT;
+ tmp16 = GxICR(CALL_FUNCTION_NMI_IPI);
+ arch_local_irq_restore(flags);
+}
+
+/**
+ * smp_prepare_cpu_init - Initialise CPU in startup_secondary
+ *
+ * Set interrupt level 0-6 setting and init ICR of gdbstub.
+ */
+void smp_prepare_cpu_init(void)
+{
+ int loop;
+
+ /* Set the interrupt vector registers */
+ IVAR0 = EXCEP_IRQ_LEVEL0;
+ IVAR1 = EXCEP_IRQ_LEVEL1;
+ IVAR2 = EXCEP_IRQ_LEVEL2;
+ IVAR3 = EXCEP_IRQ_LEVEL3;
+ IVAR4 = EXCEP_IRQ_LEVEL4;
+ IVAR5 = EXCEP_IRQ_LEVEL5;
+ IVAR6 = EXCEP_IRQ_LEVEL6;
+
+ /* Disable all interrupts and set to priority 6 (lowest) */
+ for (loop = 0; loop < GxICR_NUM_IRQS; loop++)
+ GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT;
+
+#ifdef CONFIG_GDBSTUB
+ /* initialise GDB-stub */
+ do {
+ unsigned long flags;
+ u16 tmp16;
+
+ flags = arch_local_cli_save();
+ GxICR(GDB_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT;
+ tmp16 = GxICR(GDB_NMI_IPI);
+ arch_local_irq_restore(flags);
+ } while (0);
+#endif
+}
+
+/**
+ * start_secondary - Activate a secondary CPU (AP)
+ * @unused: Thread parameter (ignored).
+ */
+int __init start_secondary(void *unused)
+{
+ smp_cpu_init();
+ smp_callin();
+ while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
+ cpu_relax();
+
+ local_flush_tlb();
+ preempt_disable();
+ smp_online();
+
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+ init_clockevents();
+#endif
+ cpu_idle();
+ return 0;
+}
+
+/**
+ * smp_prepare_cpus - Boot up secondary CPUs (APs)
+ * @max_cpus: Maximum number of CPUs to boot.
+ *
+ * Call do_boot_cpu, and boot up APs.
+ */
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+ int phy_id;
+
+ /* Setup boot CPU information */
+ smp_store_cpu_info(0);
+ smp_tune_scheduling();
+
+ init_ipi();
+
+ /* If SMP should be disabled, then finish */
+ if (max_cpus == 0) {
+ printk(KERN_INFO "SMP mode deactivated.\n");
+ goto smp_done;
+ }
+
+ /* Boot secondary CPUs (for which phy_id > 0) */
+ for (phy_id = 0; phy_id < NR_CPUS; phy_id++) {
+ /* Don't boot primary CPU */
+ if (max_cpus <= cpucount + 1)
+ continue;
+ if (phy_id != 0)
+ do_boot_cpu(phy_id);
+ set_cpu_possible(phy_id, true);
+ smp_show_cpu_info(phy_id);
+ }
+
+smp_done:
+ Dprintk("Boot done.\n");
+}
+
+/**
+ * smp_store_cpu_info - Save a CPU's information
+ * @cpu: The CPU to save for.
+ *
+ * Save boot_cpu_data and jiffy for the specified CPU.
+ */
+static void __init smp_store_cpu_info(int cpu)
+{
+ struct mn10300_cpuinfo *ci = &cpu_data[cpu];
+
+ *ci = boot_cpu_data;
+ ci->loops_per_jiffy = loops_per_jiffy;
+ ci->type = CPUREV;
+}
+
+/**
+ * smp_tune_scheduling - Set time slice value
+ *
+ * Nothing to do here.
+ */
+static void __init smp_tune_scheduling(void)
+{
+}
+
+/**
+ * do_boot_cpu: Boot up one CPU
+ * @phy_id: Physical ID of CPU to boot.
+ *
+ * Send an IPI to a secondary CPU to boot it. Returns 0 on success, 1
+ * otherwise.
+ */
+static int __init do_boot_cpu(int phy_id)
+{
+ struct task_struct *idle;
+ unsigned long send_status, callin_status;
+ int timeout, cpu_id;
+
+ send_status = GxICR_REQUEST;
+ callin_status = 0;
+ timeout = 0;
+ cpu_id = phy_id;
+
+ cpucount++;
+
+ /* Create idle thread for this CPU */
+ idle = fork_idle(cpu_id);
+ if (IS_ERR(idle))
+ panic("Failed fork for CPU#%d.", cpu_id);
+
+ idle->thread.pc = (unsigned long)start_secondary;
+
+ printk(KERN_NOTICE "Booting CPU#%d\n", cpu_id);
+ start_stack[cpu_id - 1] = idle->thread.sp;
+
+ task_thread_info(idle)->cpu = cpu_id;
+
+ /* Send boot IPI to AP */
+ send_IPI_mask(cpumask_of(phy_id), SMP_BOOT_IRQ);
+
+ Dprintk("Waiting for send to finish...\n");
+
+ /* Wait for AP's IPI receive in 100[ms] */
+ do {
+ udelay(1000);
+ send_status =
+ CROSS_GxICR(SMP_BOOT_IRQ, phy_id) & GxICR_REQUEST;
+ } while (send_status == GxICR_REQUEST && timeout++ < 100);
+
+ Dprintk("Waiting for cpu_callin_map.\n");
+
+ if (send_status == 0) {
+ /* Allow AP to start initializing */
+ cpu_set(cpu_id, cpu_callout_map);
+
+ /* Wait for setting cpu_callin_map */
+ timeout = 0;
+ do {
+ udelay(1000);
+ callin_status = cpu_isset(cpu_id, cpu_callin_map);
+ } while (callin_status == 0 && timeout++ < 5000);
+
+ if (callin_status == 0)
+ Dprintk("Not responding.\n");
+ } else {
+ printk(KERN_WARNING "IPI not delivered.\n");
+ }
+
+ if (send_status == GxICR_REQUEST || callin_status == 0) {
+ cpu_clear(cpu_id, cpu_callout_map);
+ cpu_clear(cpu_id, cpu_callin_map);
+ cpu_clear(cpu_id, cpu_initialized);
+ cpucount--;
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * smp_show_cpu_info - Show SMP CPU information
+ * @cpu: The CPU of interest.
+ */
+static void __init smp_show_cpu_info(int cpu)
+{
+ struct mn10300_cpuinfo *ci = &cpu_data[cpu];
+
+ printk(KERN_INFO
+ "CPU#%d : ioclk speed: %lu.%02luMHz : bogomips : %lu.%02lu\n",
+ cpu,
+ MN10300_IOCLK / 1000000,
+ (MN10300_IOCLK / 10000) % 100,
+ ci->loops_per_jiffy / (500000 / HZ),
+ (ci->loops_per_jiffy / (5000 / HZ)) % 100);
+}
+
+/**
+ * smp_callin - Set cpu_callin_map of the current CPU ID
+ */
+static void __init smp_callin(void)
+{
+ unsigned long timeout;
+ int cpu;
+
+ cpu = smp_processor_id();
+ timeout = jiffies + (2 * HZ);
+
+ if (cpu_isset(cpu, cpu_callin_map)) {
+ printk(KERN_ERR "CPU#%d already present.\n", cpu);
+ BUG();
+ }
+ Dprintk("CPU#%d waiting for CALLOUT\n", cpu);
+
+ /* Wait for AP startup 2s total */
+ while (time_before(jiffies, timeout)) {
+ if (cpu_isset(cpu, cpu_callout_map))
+ break;
+ cpu_relax();
+ }
+
+ if (!time_before(jiffies, timeout)) {
+ printk(KERN_ERR
+ "BUG: CPU#%d started up but did not get a callout!\n",
+ cpu);
+ BUG();
+ }
+
+#ifdef CONFIG_CALIBRATE_DELAY
+ calibrate_delay(); /* Get our bogomips */
+#endif
+
+ /* Save our processor parameters */
+ smp_store_cpu_info(cpu);
+
+ /* Allow the boot processor to continue */
+ cpu_set(cpu, cpu_callin_map);
+}
+
+/**
+ * smp_online - Set cpu_online_map
+ */
+static void __init smp_online(void)
+{
+ int cpu;
+
+ cpu = smp_processor_id();
+
+ local_irq_enable();
+
+ cpu_set(cpu, cpu_online_map);
+ smp_wmb();
+}
+
+/**
+ * smp_cpus_done -
+ * @max_cpus: Maximum CPU count.
+ *
+ * Do nothing.
+ */
+void __init smp_cpus_done(unsigned int max_cpus)
+{
+}
+
+/*
+ * smp_prepare_boot_cpu - Set up stuff for the boot processor.
+ *
+ * Set up the cpu_online_map, cpu_callout_map and cpu_callin_map of the boot
+ * processor (CPU 0).
+ */
+void __devinit smp_prepare_boot_cpu(void)
+{
+ cpu_set(0, cpu_callout_map);
+ cpu_set(0, cpu_callin_map);
+ current_thread_info()->cpu = 0;
+}
+
+/*
+ * initialize_secondary - Initialise a secondary CPU (Application Processor).
+ *
+ * Set SP register and jump to thread's PC address.
+ */
+void initialize_secondary(void)
+{
+ asm volatile (
+ "mov %0,sp \n"
+ "jmp (%1) \n"
+ :
+ : "a"(current->thread.sp), "a"(current->thread.pc));
+}
+
+/**
+ * __cpu_up - Set smp_commenced_mask for the nominated CPU
+ * @cpu: The target CPU.
+ */
+int __devinit __cpu_up(unsigned int cpu)
+{
+ int timeout;
+
+#ifdef CONFIG_HOTPLUG_CPU
+ if (num_online_cpus() == 1)
+ disable_hlt();
+ if (sleep_mode[cpu])
+ run_wakeup_cpu(cpu);
+#endif /* CONFIG_HOTPLUG_CPU */
+
+ cpu_set(cpu, smp_commenced_mask);
+
+ /* Wait 5s total for a response */
+ for (timeout = 0 ; timeout < 5000 ; timeout++) {
+ if (cpu_isset(cpu, cpu_online_map))
+ break;
+ udelay(1000);
+ }
+
+ BUG_ON(!cpu_isset(cpu, cpu_online_map));
+ return 0;
+}
+
+/**
+ * setup_profiling_timer - Set up the profiling timer
+ * @multiplier - The frequency multiplier to use
+ *
+ * The frequency of the profiling timer can be changed by writing a multiplier
+ * value into /proc/profile.
+ */
+int setup_profiling_timer(unsigned int multiplier)
+{
+ return -EINVAL;
+}
+
+/*
+ * CPU hotplug routines
+ */
+#ifdef CONFIG_HOTPLUG_CPU
+
+static DEFINE_PER_CPU(struct cpu, cpu_devices);
+
+static int __init topology_init(void)
+{
+ int cpu, ret;
+
+ for_each_cpu(cpu) {
+ ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu, NULL);
+ if (ret)
+ printk(KERN_WARNING
+ "topology_init: register_cpu %d failed (%d)\n",
+ cpu, ret);
+ }
+ return 0;
+}
+
+subsys_initcall(topology_init);
+
+int __cpu_disable(void)
+{
+ int cpu = smp_processor_id();
+ if (cpu == 0)
+ return -EBUSY;
+
+ migrate_irqs();
+ cpu_clear(cpu, current->active_mm->cpu_vm_mask);
+ return 0;
+}
+
+void __cpu_die(unsigned int cpu)
+{
+ run_sleep_cpu(cpu);
+
+ if (num_online_cpus() == 1)
+ enable_hlt();
+}
+
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+static inline void hotplug_cpu_disable_cache(void)
+{
+ int tmp;
+ asm volatile(
+ " movhu (%1),%0 \n"
+ " and %2,%0 \n"
+ " movhu %0,(%1) \n"
+ "1: movhu (%1),%0 \n"
+ " btst %3,%0 \n"
+ " bne 1b \n"
+ : "=&r"(tmp)
+ : "a"(&CHCTR),
+ "i"(~(CHCTR_ICEN | CHCTR_DCEN)),
+ "i"(CHCTR_ICBUSY | CHCTR_DCBUSY)
+ : "memory", "cc");
+}
+
+static inline void hotplug_cpu_enable_cache(void)
+{
+ int tmp;
+ asm volatile(
+ "movhu (%1),%0 \n"
+ "or %2,%0 \n"
+ "movhu %0,(%1) \n"
+ : "=&r"(tmp)
+ : "a"(&CHCTR),
+ "i"(CHCTR_ICEN | CHCTR_DCEN)
+ : "memory", "cc");
+}
+
+static inline void hotplug_cpu_invalidate_cache(void)
+{
+ int tmp;
+ asm volatile (
+ "movhu (%1),%0 \n"
+ "or %2,%0 \n"
+ "movhu %0,(%1) \n"
+ : "=&r"(tmp)
+ : "a"(&CHCTR),
+ "i"(CHCTR_ICINV | CHCTR_DCINV)
+ : "cc");
+}
+
+#else /* CONFIG_MN10300_CACHE_ENABLED */
+#define hotplug_cpu_disable_cache() do {} while (0)
+#define hotplug_cpu_enable_cache() do {} while (0)
+#define hotplug_cpu_invalidate_cache() do {} while (0)
+#endif /* CONFIG_MN10300_CACHE_ENABLED */
+
+/**
+ * hotplug_cpu_nmi_call_function - Call a function on other CPUs for hotplug
+ * @cpumask: List of target CPUs.
+ * @func: The function to call on those CPUs.
+ * @info: The context data for the function to be called.
+ * @wait: Whether to wait for the calls to complete.
+ *
+ * Non-maskably call a function on another CPU for hotplug purposes.
+ *
+ * This function must be called with maskable interrupts disabled.
+ */
+static int hotplug_cpu_nmi_call_function(cpumask_t cpumask,
+ smp_call_func_t func, void *info,
+ int wait)
+{
+ /*
+ * The address and the size of nmi_call_func_mask_data
+ * need to be aligned on L1_CACHE_BYTES.
+ */
+ static struct nmi_call_data_struct nmi_call_func_mask_data
+ __cacheline_aligned;
+ unsigned long start, end;
+
+ start = (unsigned long)&nmi_call_func_mask_data;
+ end = start + sizeof(struct nmi_call_data_struct);
+
+ nmi_call_func_mask_data.func = func;
+ nmi_call_func_mask_data.info = info;
+ nmi_call_func_mask_data.started = cpumask;
+ nmi_call_func_mask_data.wait = wait;
+ if (wait)
+ nmi_call_func_mask_data.finished = cpumask;
+
+ spin_lock(&smp_nmi_call_lock);
+ nmi_call_data = &nmi_call_func_mask_data;
+ mn10300_local_dcache_flush_range(start, end);
+ smp_wmb();
+
+ send_IPI_mask(cpumask, CALL_FUNCTION_NMI_IPI);
+
+ do {
+ mn10300_local_dcache_inv_range(start, end);
+ barrier();
+ } while (!cpus_empty(nmi_call_func_mask_data.started));
+
+ if (wait) {
+ do {
+ mn10300_local_dcache_inv_range(start, end);
+ barrier();
+ } while (!cpus_empty(nmi_call_func_mask_data.finished));
+ }
+
+ spin_unlock(&smp_nmi_call_lock);
+ return 0;
+}
+
+static void restart_wakeup_cpu(void)
+{
+ unsigned int cpu = smp_processor_id();
+
+ cpu_set(cpu, cpu_callin_map);
+ local_flush_tlb();
+ cpu_set(cpu, cpu_online_map);
+ smp_wmb();
+}
+
+static void prepare_sleep_cpu(void *unused)
+{
+ sleep_mode[smp_processor_id()] = 1;
+ smp_mb();
+ mn10300_local_dcache_flush_inv();
+ hotplug_cpu_disable_cache();
+ hotplug_cpu_invalidate_cache();
+}
+
+/* when this function called, IE=0, NMID=0. */
+static void sleep_cpu(void *unused)
+{
+ unsigned int cpu_id = smp_processor_id();
+ /*
+ * CALL_FUNCTION_NMI_IPI for wakeup_cpu() shall not be requested,
+ * before this cpu goes in SLEEP mode.
+ */
+ do {
+ smp_mb();
+ __sleep_cpu();
+ } while (sleep_mode[cpu_id]);
+ restart_wakeup_cpu();
+}
+
+static void run_sleep_cpu(unsigned int cpu)
+{
+ unsigned long flags;
+ cpumask_t cpumask = cpumask_of(cpu);
+
+ flags = arch_local_cli_save();
+ hotplug_cpu_nmi_call_function(cpumask, prepare_sleep_cpu, NULL, 1);
+ hotplug_cpu_nmi_call_function(cpumask, sleep_cpu, NULL, 0);
+ udelay(1); /* delay for the cpu to sleep. */
+ arch_local_irq_restore(flags);
+}
+
+static void wakeup_cpu(void)
+{
+ hotplug_cpu_invalidate_cache();
+ hotplug_cpu_enable_cache();
+ smp_mb();
+ sleep_mode[smp_processor_id()] = 0;
+}
+
+static void run_wakeup_cpu(unsigned int cpu)
+{
+ unsigned long flags;
+
+ flags = arch_local_cli_save();
+#if NR_CPUS == 2
+ mn10300_local_dcache_flush_inv();
+#else
+ /*
+ * Before waking up the cpu,
+ * all online cpus should stop and flush D-Cache for global data.
+ */
+#error not support NR_CPUS > 2, when CONFIG_HOTPLUG_CPU=y.
+#endif
+ hotplug_cpu_nmi_call_function(cpumask_of(cpu), wakeup_cpu, NULL, 1);
+ arch_local_irq_restore(flags);
+}
+
+#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/arch/mn10300/kernel/switch_to.S b/arch/mn10300/kernel/switch_to.S
index 630aad71b946..9074d0fb8788 100644
--- a/arch/mn10300/kernel/switch_to.S
+++ b/arch/mn10300/kernel/switch_to.S
@@ -15,6 +15,9 @@
#include <linux/linkage.h>
#include <asm/thread_info.h>
#include <asm/cpu-regs.h>
+#ifdef CONFIG_SMP
+#include <proc/smp-regs.h>
+#endif /* CONFIG_SMP */
.text
@@ -35,8 +38,6 @@ ENTRY(__switch_to)
mov d1,a1
# save prev context
- mov (__frame),d0
- mov d0,(THREAD_FRAME,a0)
mov __switch_back,d0
mov d0,(THREAD_PC,a0)
mov sp,a2
@@ -58,8 +59,6 @@ ENTRY(__switch_to)
mov a2,e2
#endif
- mov (THREAD_FRAME,a1),a2
- mov a2,(__frame)
mov (THREAD_PC,a1),a2
mov d2,d0 # for ret_from_fork
mov d0,a0 # for __switch_to
diff --git a/arch/mn10300/kernel/time.c b/arch/mn10300/kernel/time.c
index 8f7f6d22783d..f860a340acc9 100644
--- a/arch/mn10300/kernel/time.c
+++ b/arch/mn10300/kernel/time.c
@@ -17,29 +17,18 @@
#include <linux/smp.h>
#include <linux/profile.h>
#include <linux/cnt32_to_63.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/irq.h>
#include <asm/div64.h>
#include <asm/processor.h>
#include <asm/intctl-regs.h>
#include <asm/rtc.h>
-
-#ifdef CONFIG_MN10300_RTC
-unsigned long mn10300_ioclk; /* system I/O clock frequency */
-unsigned long mn10300_iobclk; /* system I/O clock frequency */
-unsigned long mn10300_tsc_per_HZ; /* number of ioclks per jiffy */
-#endif /* CONFIG_MN10300_RTC */
+#include "internal.h"
static unsigned long mn10300_last_tsc; /* time-stamp counter at last time
* interrupt occurred */
-static irqreturn_t timer_interrupt(int irq, void *dev_id);
-
-static struct irqaction timer_irq = {
- .handler = timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER,
- .name = "timer",
-};
-
static unsigned long sched_clock_multiplier;
/*
@@ -54,9 +43,12 @@ unsigned long long sched_clock(void)
unsigned long tsc, tmp;
unsigned product[3]; /* 96-bit intermediate value */
+ /* cnt32_to_63() is not safe with preemption */
+ preempt_disable();
+
/* read the TSC value
*/
- tsc = 0 - get_cycles(); /* get_cycles() counts down */
+ tsc = get_cycles();
/* expand to 64-bits.
* - sched_clock() must be called once a minute or better or the
@@ -64,6 +56,8 @@ unsigned long long sched_clock(void)
*/
tsc64.ll = cnt32_to_63(tsc) & 0x7fffffffffffffffULL;
+ preempt_enable();
+
/* scale the 64-bit TSC value to a nanosecond value via a 96-bit
* intermediate
*/
@@ -90,6 +84,20 @@ static void __init mn10300_sched_clock_init(void)
__muldiv64u(NSEC_PER_SEC, 1 << 16, MN10300_TSCCLK);
}
+/**
+ * local_timer_interrupt - Local timer interrupt handler
+ *
+ * Handle local timer interrupts for this CPU. They may have been propagated
+ * to this CPU from the CPU that actually gets them by way of an IPI.
+ */
+irqreturn_t local_timer_interrupt(void)
+{
+ profile_tick(CPU_PROFILING);
+ update_process_times(user_mode(get_irq_regs()));
+ return IRQ_HANDLED;
+}
+
+#ifndef CONFIG_GENERIC_TIME
/*
* advance the kernel's time keeping clocks (xtime and jiffies)
* - we use Timer 0 & 1 cascaded as a clock to nudge us the next time
@@ -98,27 +106,73 @@ static void __init mn10300_sched_clock_init(void)
static irqreturn_t timer_interrupt(int irq, void *dev_id)
{
unsigned tsc, elapse;
+ irqreturn_t ret;
write_seqlock(&xtime_lock);
while (tsc = get_cycles(),
- elapse = mn10300_last_tsc - tsc, /* time elapsed since last
+ elapse = tsc - mn10300_last_tsc, /* time elapsed since last
* tick */
elapse > MN10300_TSC_PER_HZ
) {
- mn10300_last_tsc -= MN10300_TSC_PER_HZ;
+ mn10300_last_tsc += MN10300_TSC_PER_HZ;
/* advance the kernel's time tracking system */
- profile_tick(CPU_PROFILING);
do_timer(1);
}
write_sequnlock(&xtime_lock);
- update_process_times(user_mode(get_irq_regs()));
+ ret = local_timer_interrupt();
+#ifdef CONFIG_SMP
+ send_IPI_allbutself(LOCAL_TIMER_IPI);
+#endif
+ return ret;
+}
- return IRQ_HANDLED;
+static struct irqaction timer_irq = {
+ .handler = timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER,
+ .name = "timer",
+};
+#endif /* CONFIG_GENERIC_TIME */
+
+#ifdef CONFIG_CSRC_MN10300
+void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock)
+{
+ u64 temp;
+ u32 shift;
+
+ /* Find a shift value */
+ for (shift = 32; shift > 0; shift--) {
+ temp = (u64) NSEC_PER_SEC << shift;
+ do_div(temp, clock);
+ if ((temp >> 32) == 0)
+ break;
+ }
+ cs->shift = shift;
+ cs->mult = (u32) temp;
}
+#endif
+
+#if CONFIG_CEVT_MN10300
+void __cpuinit clockevent_set_clock(struct clock_event_device *cd,
+ unsigned int clock)
+{
+ u64 temp;
+ u32 shift;
+
+ /* Find a shift value */
+ for (shift = 32; shift > 0; shift--) {
+ temp = (u64) clock << shift;
+ do_div(temp, NSEC_PER_SEC);
+ if ((temp >> 32) == 0)
+ break;
+ }
+ cd->shift = shift;
+ cd->mult = (u32) temp;
+}
+#endif
/*
* initialise the various timers used by the main part of the kernel
@@ -131,21 +185,25 @@ void __init time_init(void)
*/
TMPSCNT |= TMPSCNT_ENABLE;
+#ifdef CONFIG_GENERIC_TIME
+ init_clocksource();
+#else
startup_timestamp_counter();
+#endif
printk(KERN_INFO
"timestamp counter I/O clock running at %lu.%02lu"
" (calibrated against RTC)\n",
MN10300_TSCCLK / 1000000, (MN10300_TSCCLK / 10000) % 100);
- mn10300_last_tsc = TMTSCBC;
-
- /* use timer 0 & 1 cascaded to tick at as close to HZ as possible */
- setup_irq(TMJCIRQ, &timer_irq);
+ mn10300_last_tsc = read_timestamp_counter();
- set_intr_level(TMJCIRQ, TMJCICR_LEVEL);
-
- startup_jiffies_counter();
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+ init_clockevents();
+#else
+ reload_jiffies_counter(MN10300_JC_PER_HZ - 1);
+ setup_jiffies_interrupt(TMJCIRQ, &timer_irq, CONFIG_TIMER_IRQ_LEVEL);
+#endif
#ifdef CONFIG_MN10300_WD_TIMER
/* start the watchdog timer */
diff --git a/arch/mn10300/kernel/traps.c b/arch/mn10300/kernel/traps.c
index 91365adba4f5..b90c3f160c77 100644
--- a/arch/mn10300/kernel/traps.c
+++ b/arch/mn10300/kernel/traps.c
@@ -45,9 +45,6 @@
#error "INTERRUPT_VECTOR_BASE not aligned to 16MiB boundary!"
#endif
-struct pt_regs *__frame; /* current frame pointer */
-EXPORT_SYMBOL(__frame);
-
int kstack_depth_to_print = 24;
spinlock_t die_lock = __SPIN_LOCK_UNLOCKED(die_lock);
@@ -101,7 +98,6 @@ DO_EINFO(SIGILL, {}, "invalid opcode", invalid_op, ILL_ILLOPC);
DO_EINFO(SIGILL, {}, "invalid ex opcode", invalid_exop, ILL_ILLOPC);
DO_EINFO(SIGBUS, {}, "invalid address", mem_error, BUS_ADRERR);
DO_EINFO(SIGBUS, {}, "bus error", bus_error, BUS_ADRERR);
-DO_EINFO(SIGILL, {}, "FPU invalid opcode", fpu_invalid_op, ILL_COPROC);
DO_ERROR(SIGTRAP,
#ifndef CONFIG_MN10300_USING_JTAG
@@ -222,11 +218,14 @@ void show_registers_only(struct pt_regs *regs)
printk(KERN_EMERG "threadinfo=%p task=%p)\n",
current_thread_info(), current);
- if ((unsigned long) current >= 0x90000000UL &&
- (unsigned long) current < 0x94000000UL)
+ if ((unsigned long) current >= PAGE_OFFSET &&
+ (unsigned long) current < (unsigned long)high_memory)
printk(KERN_EMERG "Process %s (pid: %d)\n",
current->comm, current->pid);
+#ifdef CONFIG_SMP
+ printk(KERN_EMERG "CPUID: %08x\n", CPUID);
+#endif
printk(KERN_EMERG "CPUP: %04hx\n", CPUP);
printk(KERN_EMERG "TBR: %08x\n", TBR);
printk(KERN_EMERG "DEAR: %08x\n", DEAR);
@@ -522,8 +521,12 @@ void __init set_intr_stub(enum exception_code code, void *handler)
{
unsigned long addr;
u8 *vector = (u8 *)(CONFIG_INTERRUPT_VECTOR_BASE + code);
+ unsigned long flags;
addr = (unsigned long) handler - (unsigned long) vector;
+
+ flags = arch_local_cli_save();
+
vector[0] = 0xdc; /* JMP handler */
vector[1] = addr;
vector[2] = addr >> 8;
@@ -533,30 +536,12 @@ void __init set_intr_stub(enum exception_code code, void *handler)
vector[6] = 0xcb;
vector[7] = 0xcb;
- mn10300_dcache_flush_inv();
- mn10300_icache_inv();
-}
-
-/*
- * set an interrupt stub to invoke the JTAG unit and then jump to a handler
- */
-void __init set_jtag_stub(enum exception_code code, void *handler)
-{
- unsigned long addr;
- u8 *vector = (u8 *)(CONFIG_INTERRUPT_VECTOR_BASE + code);
-
- addr = (unsigned long) handler - ((unsigned long) vector + 1);
- vector[0] = 0xff; /* PI to jump into JTAG debugger */
- vector[1] = 0xdc; /* jmp handler */
- vector[2] = addr;
- vector[3] = addr >> 8;
- vector[4] = addr >> 16;
- vector[5] = addr >> 24;
- vector[6] = 0xcb;
- vector[7] = 0xcb;
+ arch_local_irq_restore(flags);
+#ifndef CONFIG_MN10300_CACHE_SNOOP
mn10300_dcache_flush_inv();
- flush_icache_range((unsigned long) vector, (unsigned long) vector + 8);
+ mn10300_icache_inv();
+#endif
}
/*
@@ -581,7 +566,6 @@ void __init trap_init(void)
set_excp_vector(EXCEP_PRIVINSACC, insn_acc_error);
set_excp_vector(EXCEP_PRIVDATACC, data_acc_error);
set_excp_vector(EXCEP_DATINSACC, insn_acc_error);
- set_excp_vector(EXCEP_FPU_DISABLED, fpu_disabled);
set_excp_vector(EXCEP_FPU_UNIMPINS, fpu_invalid_op);
set_excp_vector(EXCEP_FPU_OPERATION, fpu_exception);
diff --git a/arch/mn10300/kernel/vmlinux.lds.S b/arch/mn10300/kernel/vmlinux.lds.S
index 10549dcfb610..febbeee7f2f5 100644
--- a/arch/mn10300/kernel/vmlinux.lds.S
+++ b/arch/mn10300/kernel/vmlinux.lds.S
@@ -70,7 +70,7 @@ SECTIONS
.exit.text : { EXIT_TEXT; }
.exit.data : { EXIT_DATA; }
- PERCPU(32)
+ PERCPU(PAGE_SIZE)
. = ALIGN(PAGE_SIZE);
__init_end = .;
/* freed after init ends here */
diff --git a/arch/mn10300/lib/bitops.c b/arch/mn10300/lib/bitops.c
index 440a7dcbf87b..a66c6cdaf442 100644
--- a/arch/mn10300/lib/bitops.c
+++ b/arch/mn10300/lib/bitops.c
@@ -15,7 +15,7 @@
/*
* try flipping a bit using BSET and BCLR
*/
-void change_bit(int nr, volatile void *addr)
+void change_bit(unsigned long nr, volatile void *addr)
{
if (test_bit(nr, addr))
goto try_clear_bit;
@@ -34,7 +34,7 @@ try_clear_bit:
/*
* try flipping a bit using BSET and BCLR and returning the old value
*/
-int test_and_change_bit(int nr, volatile void *addr)
+int test_and_change_bit(unsigned long nr, volatile void *addr)
{
if (test_bit(nr, addr))
goto try_clear_bit;
diff --git a/arch/mn10300/lib/delay.c b/arch/mn10300/lib/delay.c
index fdf6f710f94e..8e7ceb8ba33d 100644
--- a/arch/mn10300/lib/delay.c
+++ b/arch/mn10300/lib/delay.c
@@ -38,14 +38,14 @@ EXPORT_SYMBOL(__delay);
*/
void __udelay(unsigned long usecs)
{
- signed long ioclk, stop;
+ unsigned long start, stop, cnt;
/* usecs * CLK / 1E6 */
stop = __muldiv64u(usecs, MN10300_TSCCLK, 1000000);
- stop = TMTSCBC - stop;
+ start = TMTSCBC;
do {
- ioclk = TMTSCBC;
- } while (stop < ioclk);
+ cnt = start - TMTSCBC;
+ } while (cnt < stop);
}
EXPORT_SYMBOL(__udelay);
diff --git a/arch/mn10300/lib/do_csum.S b/arch/mn10300/lib/do_csum.S
index e138994e1667..1d27bba0cd8f 100644
--- a/arch/mn10300/lib/do_csum.S
+++ b/arch/mn10300/lib/do_csum.S
@@ -10,26 +10,25 @@
*/
#include <asm/cache.h>
- .section .text
- .balign L1_CACHE_BYTES
+ .section .text
+ .balign L1_CACHE_BYTES
###############################################################################
#
-# unsigned int do_csum(const unsigned char *buff, size_t len)
+# unsigned int do_csum(const unsigned char *buff, int len)
#
###############################################################################
.globl do_csum
- .type do_csum,@function
+ .type do_csum,@function
do_csum:
movm [d2,d3],(sp)
- mov d0,(12,sp)
- mov d1,(16,sp)
mov d1,d2 # count
mov d0,a0 # buff
+ mov a0,a1
clr d1 # accumulator
cmp +0,d2
- beq do_csum_done # return if zero-length buffer
+ ble do_csum_done # check for zero length or negative
# 4-byte align the buffer pointer
btst +3,a0
@@ -41,17 +40,15 @@ do_csum:
inc a0
asl +8,d0
add d0,d1
- addc +0,d1
add -1,d2
-do_csum_addr_not_odd:
+do_csum_addr_not_odd:
cmp +2,d2
bcs do_csum_fewer_than_4
btst +2,a0
beq do_csum_now_4b_aligned
movhu (a0+),d0
add d0,d1
- addc +0,d1
add -2,d2
cmp +4,d2
bcs do_csum_fewer_than_4
@@ -66,20 +63,20 @@ do_csum_now_4b_aligned:
do_csum_loop:
mov (a0+),d0
- add d0,d1
mov (a0+),e0
- addc e0,d1
mov (a0+),e1
- addc e1,d1
mov (a0+),e3
+ add d0,d1
+ addc e0,d1
+ addc e1,d1
addc e3,d1
mov (a0+),d0
- addc d0,d1
mov (a0+),e0
- addc e0,d1
mov (a0+),e1
- addc e1,d1
mov (a0+),e3
+ addc d0,d1
+ addc e0,d1
+ addc e1,d1
addc e3,d1
addc +0,d1
@@ -94,12 +91,12 @@ do_csum_remainder:
cmp +16,d2
bcs do_csum_fewer_than_16
mov (a0+),d0
- add d0,d1
mov (a0+),e0
- addc e0,d1
mov (a0+),e1
- addc e1,d1
mov (a0+),e3
+ add d0,d1
+ addc e0,d1
+ addc e1,d1
addc e3,d1
addc +0,d1
add -16,d2
@@ -131,9 +128,9 @@ do_csum_fewer_than_4:
xor_cmp d0,d0,+2,d2
bcs do_csum_fewer_than_2
movhu (a0+),d0
-do_csum_fewer_than_2:
and +1,d2
beq do_csum_add_last_bit
+do_csum_fewer_than_2:
movbu (a0),d3
add d3,d0
do_csum_add_last_bit:
@@ -142,21 +139,19 @@ do_csum_add_last_bit:
do_csum_done:
# compress the checksum down to 16 bits
- mov +0xffff0000,d2
- and d1,d2
+ mov +0xffff0000,d0
+ and d1,d0
asl +16,d1
- add d2,d1,d0
+ add d1,d0
addc +0xffff,d0
lsr +16,d0
# flip the halves of the word result if the buffer was oddly aligned
- mov (12,sp),d1
- and +1,d1
+ and +1,a1
beq do_csum_not_oddly_aligned
swaph d0,d0 # exchange bits 15:8 with 7:0
do_csum_not_oddly_aligned:
ret [d2,d3],8
-do_csum_end:
- .size do_csum, do_csum_end-do_csum
+ .size do_csum, .-do_csum
diff --git a/arch/mn10300/mm/Kconfig.cache b/arch/mn10300/mm/Kconfig.cache
new file mode 100644
index 000000000000..c4fd923a55a0
--- /dev/null
+++ b/arch/mn10300/mm/Kconfig.cache
@@ -0,0 +1,101 @@
+#
+# MN10300 CPU cache options
+#
+
+choice
+ prompt "CPU Caching mode"
+ default MN10300_CACHE_WBACK
+ help
+ This option determines the caching mode for the kernel.
+
+ Write-Back caching mode involves the all reads and writes causing
+ the affected cacheline to be read into the cache first before being
+ operated upon. Memory is not then updated by a write until the cache
+ is filled and a cacheline needs to be displaced from the cache to
+ make room. Only at that point is it written back.
+
+ Write-Through caching only fetches cachelines from memory on a
+ read. Writes always get written directly to memory. If the affected
+ cacheline is also in cache, it will be updated too.
+
+ The final option is to turn of caching entirely.
+
+config MN10300_CACHE_WBACK
+ bool "Write-Back"
+ help
+ The dcache operates in delayed write-back mode. It must be manually
+ flushed if writes are made that subsequently need to be executed or
+ to be DMA'd by a device.
+
+config MN10300_CACHE_WTHRU
+ bool "Write-Through"
+ help
+ The dcache operates in immediate write-through mode. Writes are
+ committed to RAM immediately in addition to being stored in the
+ cache. This means that the written data is immediately available for
+ execution or DMA.
+
+ This is not available for use with an SMP kernel if cache flushing
+ and invalidation by automatic purge register is not selected.
+
+config MN10300_CACHE_DISABLED
+ bool "Disabled"
+ help
+ The icache and dcache are disabled.
+
+endchoice
+
+config MN10300_CACHE_ENABLED
+ def_bool y if !MN10300_CACHE_DISABLED
+
+
+choice
+ prompt "CPU cache flush/invalidate method"
+ default MN10300_CACHE_MANAGE_BY_TAG if !AM34_2
+ default MN10300_CACHE_MANAGE_BY_REG if AM34_2
+ depends on MN10300_CACHE_ENABLED
+ help
+ This determines the method by which CPU cache flushing and
+ invalidation is performed.
+
+config MN10300_CACHE_MANAGE_BY_TAG
+ bool "Use the cache tag registers directly"
+ depends on !(SMP && MN10300_CACHE_WTHRU)
+
+config MN10300_CACHE_MANAGE_BY_REG
+ bool "Flush areas by way of automatic purge registers (AM34 only)"
+ depends on AM34_2
+
+endchoice
+
+config MN10300_CACHE_INV_BY_TAG
+ def_bool y if MN10300_CACHE_MANAGE_BY_TAG && MN10300_CACHE_ENABLED
+
+config MN10300_CACHE_INV_BY_REG
+ def_bool y if MN10300_CACHE_MANAGE_BY_REG && MN10300_CACHE_ENABLED
+
+config MN10300_CACHE_FLUSH_BY_TAG
+ def_bool y if MN10300_CACHE_MANAGE_BY_TAG && MN10300_CACHE_WBACK
+
+config MN10300_CACHE_FLUSH_BY_REG
+ def_bool y if MN10300_CACHE_MANAGE_BY_REG && MN10300_CACHE_WBACK
+
+
+config MN10300_HAS_CACHE_SNOOP
+ def_bool n
+
+config MN10300_CACHE_SNOOP
+ bool "Use CPU Cache Snooping"
+ depends on MN10300_CACHE_ENABLED && MN10300_HAS_CACHE_SNOOP
+ default y
+
+config MN10300_CACHE_FLUSH_ICACHE
+ def_bool y if MN10300_CACHE_WBACK && !MN10300_CACHE_SNOOP
+ help
+ Set if we need the dcache flushing before the icache is invalidated.
+
+config MN10300_CACHE_INV_ICACHE
+ def_bool y if MN10300_CACHE_WTHRU && !MN10300_CACHE_SNOOP
+ help
+ Set if we need the icache to be invalidated, even if the dcache is in
+ write-through mode and doesn't need flushing.
diff --git a/arch/mn10300/mm/Makefile b/arch/mn10300/mm/Makefile
index 1557277fbc5c..203fee23f7d7 100644
--- a/arch/mn10300/mm/Makefile
+++ b/arch/mn10300/mm/Makefile
@@ -2,11 +2,21 @@
# Makefile for the MN10300-specific memory management code
#
-cacheflush-y := cache.o cache-mn10300.o
-cacheflush-$(CONFIG_MN10300_CACHE_WBACK) += cache-flush-mn10300.o
+cache-smp-wback-$(CONFIG_MN10300_CACHE_WBACK) := cache-smp-flush.o
+
+cacheflush-y := cache.o
+cacheflush-$(CONFIG_SMP) += cache-smp.o cache-smp-inv.o $(cache-smp-wback-y)
+cacheflush-$(CONFIG_MN10300_CACHE_INV_ICACHE) += cache-inv-icache.o
+cacheflush-$(CONFIG_MN10300_CACHE_FLUSH_ICACHE) += cache-flush-icache.o
+cacheflush-$(CONFIG_MN10300_CACHE_INV_BY_TAG) += cache-inv-by-tag.o
+cacheflush-$(CONFIG_MN10300_CACHE_INV_BY_REG) += cache-inv-by-reg.o
+cacheflush-$(CONFIG_MN10300_CACHE_FLUSH_BY_TAG) += cache-flush-by-tag.o
+cacheflush-$(CONFIG_MN10300_CACHE_FLUSH_BY_REG) += cache-flush-by-reg.o
cacheflush-$(CONFIG_MN10300_CACHE_DISABLED) := cache-disabled.o
obj-y := \
init.o fault.o pgtable.o extable.o tlb-mn10300.o mmu-context.o \
misalignment.o dma-alloc.o $(cacheflush-y)
+
+obj-$(CONFIG_SMP) += tlb-smp.o
diff --git a/arch/mn10300/mm/cache-flush-by-reg.S b/arch/mn10300/mm/cache-flush-by-reg.S
new file mode 100644
index 000000000000..1dcae0211671
--- /dev/null
+++ b/arch/mn10300/mm/cache-flush-by-reg.S
@@ -0,0 +1,308 @@
+/* MN10300 CPU core caching routines, using indirect regs on cache controller
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/irqflags.h>
+
+ .am33_2
+
+#ifndef CONFIG_SMP
+ .globl mn10300_dcache_flush
+ .globl mn10300_dcache_flush_page
+ .globl mn10300_dcache_flush_range
+ .globl mn10300_dcache_flush_range2
+ .globl mn10300_dcache_flush_inv
+ .globl mn10300_dcache_flush_inv_page
+ .globl mn10300_dcache_flush_inv_range
+ .globl mn10300_dcache_flush_inv_range2
+
+mn10300_dcache_flush = mn10300_local_dcache_flush
+mn10300_dcache_flush_page = mn10300_local_dcache_flush_page
+mn10300_dcache_flush_range = mn10300_local_dcache_flush_range
+mn10300_dcache_flush_range2 = mn10300_local_dcache_flush_range2
+mn10300_dcache_flush_inv = mn10300_local_dcache_flush_inv
+mn10300_dcache_flush_inv_page = mn10300_local_dcache_flush_inv_page
+mn10300_dcache_flush_inv_range = mn10300_local_dcache_flush_inv_range
+mn10300_dcache_flush_inv_range2 = mn10300_local_dcache_flush_inv_range2
+
+#endif /* !CONFIG_SMP */
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush(void)
+# Flush the entire data cache back to RAM
+#
+###############################################################################
+ ALIGN
+ .globl mn10300_local_dcache_flush
+ .type mn10300_local_dcache_flush,@function
+mn10300_local_dcache_flush:
+ movhu (CHCTR),d0
+ btst CHCTR_DCEN,d0
+ beq mn10300_local_dcache_flush_end
+
+ mov DCPGCR,a0
+
+ LOCAL_CLI_SAVE(d1)
+
+ # wait for busy bit of area purge
+ setlb
+ mov (a0),d0
+ btst DCPGCR_DCPGBSY,d0
+ lne
+
+ # set mask
+ clr d0
+ mov d0,(DCPGMR)
+
+ # area purge
+ #
+ # DCPGCR = DCPGCR_DCP
+ #
+ mov DCPGCR_DCP,d0
+ mov d0,(a0)
+
+ # wait for busy bit of area purge
+ setlb
+ mov (a0),d0
+ btst DCPGCR_DCPGBSY,d0
+ lne
+
+ LOCAL_IRQ_RESTORE(d1)
+
+mn10300_local_dcache_flush_end:
+ ret [],0
+ .size mn10300_local_dcache_flush,.-mn10300_local_dcache_flush
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush_page(unsigned long start)
+# void mn10300_local_dcache_flush_range(unsigned long start, unsigned long end)
+# void mn10300_local_dcache_flush_range2(unsigned long start, unsigned long size)
+# Flush a range of addresses on a page in the dcache
+#
+###############################################################################
+ ALIGN
+ .globl mn10300_local_dcache_flush_page
+ .globl mn10300_local_dcache_flush_range
+ .globl mn10300_local_dcache_flush_range2
+ .type mn10300_local_dcache_flush_page,@function
+ .type mn10300_local_dcache_flush_range,@function
+ .type mn10300_local_dcache_flush_range2,@function
+mn10300_local_dcache_flush_page:
+ and ~(PAGE_SIZE-1),d0
+ mov PAGE_SIZE,d1
+mn10300_local_dcache_flush_range2:
+ add d0,d1
+mn10300_local_dcache_flush_range:
+ movm [d2,d3,a2],(sp)
+
+ movhu (CHCTR),d2
+ btst CHCTR_DCEN,d2
+ beq mn10300_local_dcache_flush_range_end
+
+ # calculate alignsize
+ #
+ # alignsize = L1_CACHE_BYTES;
+ # for (i = (end - start - 1) / L1_CACHE_BYTES ; i > 0; i >>= 1)
+ # alignsize <<= 1;
+ # d2 = alignsize;
+ #
+ mov L1_CACHE_BYTES,d2
+ sub d0,d1,d3
+ add -1,d3
+ lsr L1_CACHE_SHIFT,d3
+ beq 2f
+1:
+ add d2,d2
+ lsr 1,d3
+ bne 1b
+2:
+ mov d1,a1 # a1 = end
+
+ LOCAL_CLI_SAVE(d3)
+ mov DCPGCR,a0
+
+ # wait for busy bit of area purge
+ setlb
+ mov (a0),d1
+ btst DCPGCR_DCPGBSY,d1
+ lne
+
+ # determine the mask
+ mov d2,d1
+ add -1,d1
+ not d1 # d1 = mask = ~(alignsize-1)
+ mov d1,(DCPGMR)
+
+ and d1,d0,a2 # a2 = mask & start
+
+dcpgloop:
+ # area purge
+ mov a2,d0
+ or DCPGCR_DCP,d0
+ mov d0,(a0) # DCPGCR = (mask & start) | DCPGCR_DCP
+
+ # wait for busy bit of area purge
+ setlb
+ mov (a0),d1
+ btst DCPGCR_DCPGBSY,d1
+ lne
+
+ # check purge of end address
+ add d2,a2 # a2 += alignsize
+ cmp a1,a2 # if (a2 < end) goto dcpgloop
+ bns dcpgloop
+
+ LOCAL_IRQ_RESTORE(d3)
+
+mn10300_local_dcache_flush_range_end:
+ ret [d2,d3,a2],12
+
+ .size mn10300_local_dcache_flush_page,.-mn10300_local_dcache_flush_page
+ .size mn10300_local_dcache_flush_range,.-mn10300_local_dcache_flush_range
+ .size mn10300_local_dcache_flush_range2,.-mn10300_local_dcache_flush_range2
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush_inv(void)
+# Flush the entire data cache and invalidate all entries
+#
+###############################################################################
+ ALIGN
+ .globl mn10300_local_dcache_flush_inv
+ .type mn10300_local_dcache_flush_inv,@function
+mn10300_local_dcache_flush_inv:
+ movhu (CHCTR),d0
+ btst CHCTR_DCEN,d0
+ beq mn10300_local_dcache_flush_inv_end
+
+ mov DCPGCR,a0
+
+ LOCAL_CLI_SAVE(d1)
+
+ # wait for busy bit of area purge & invalidate
+ setlb
+ mov (a0),d0
+ btst DCPGCR_DCPGBSY,d0
+ lne
+
+ # set the mask to cover everything
+ clr d0
+ mov d0,(DCPGMR)
+
+ # area purge & invalidate
+ mov DCPGCR_DCP|DCPGCR_DCI,d0
+ mov d0,(a0)
+
+ # wait for busy bit of area purge & invalidate
+ setlb
+ mov (a0),d0
+ btst DCPGCR_DCPGBSY,d0
+ lne
+
+ LOCAL_IRQ_RESTORE(d1)
+
+mn10300_local_dcache_flush_inv_end:
+ ret [],0
+ .size mn10300_local_dcache_flush_inv,.-mn10300_local_dcache_flush_inv
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush_inv_page(unsigned long start)
+# void mn10300_local_dcache_flush_inv_range(unsigned long start, unsigned long end)
+# void mn10300_local_dcache_flush_inv_range2(unsigned long start, unsigned long size)
+# Flush and invalidate a range of addresses on a page in the dcache
+#
+###############################################################################
+ ALIGN
+ .globl mn10300_local_dcache_flush_inv_page
+ .globl mn10300_local_dcache_flush_inv_range
+ .globl mn10300_local_dcache_flush_inv_range2
+ .type mn10300_local_dcache_flush_inv_page,@function
+ .type mn10300_local_dcache_flush_inv_range,@function
+ .type mn10300_local_dcache_flush_inv_range2,@function
+mn10300_local_dcache_flush_inv_page:
+ and ~(PAGE_SIZE-1),d0
+ mov PAGE_SIZE,d1
+mn10300_local_dcache_flush_inv_range2:
+ add d0,d1
+mn10300_local_dcache_flush_inv_range:
+ movm [d2,d3,a2],(sp)
+
+ movhu (CHCTR),d2
+ btst CHCTR_DCEN,d2
+ beq mn10300_local_dcache_flush_inv_range_end
+
+ # calculate alignsize
+ #
+ # alignsize = L1_CACHE_BYTES;
+ # for (i = (end - start - 1) / L1_CACHE_BYTES; i > 0; i >>= 1)
+ # alignsize <<= 1;
+ # d2 = alignsize
+ #
+ mov L1_CACHE_BYTES,d2
+ sub d0,d1,d3
+ add -1,d3
+ lsr L1_CACHE_SHIFT,d3
+ beq 2f
+1:
+ add d2,d2
+ lsr 1,d3
+ bne 1b
+2:
+ mov d1,a1 # a1 = end
+
+ LOCAL_CLI_SAVE(d3)
+ mov DCPGCR,a0
+
+ # wait for busy bit of area purge & invalidate
+ setlb
+ mov (a0),d1
+ btst DCPGCR_DCPGBSY,d1
+ lne
+
+ # set the mask
+ mov d2,d1
+ add -1,d1
+ not d1 # d1 = mask = ~(alignsize-1)
+ mov d1,(DCPGMR)
+
+ and d1,d0,a2 # a2 = mask & start
+
+dcpgivloop:
+ # area purge & invalidate
+ mov a2,d0
+ or DCPGCR_DCP|DCPGCR_DCI,d0
+ mov d0,(a0) # DCPGCR = (mask & start)|DCPGCR_DCP|DCPGCR_DCI
+
+ # wait for busy bit of area purge & invalidate
+ setlb
+ mov (a0),d1
+ btst DCPGCR_DCPGBSY,d1
+ lne
+
+ # check purge & invalidate of end address
+ add d2,a2 # a2 += alignsize
+ cmp a1,a2 # if (a2 < end) goto dcpgivloop
+ bns dcpgivloop
+
+ LOCAL_IRQ_RESTORE(d3)
+
+mn10300_local_dcache_flush_inv_range_end:
+ ret [d2,d3,a2],12
+ .size mn10300_local_dcache_flush_inv_page,.-mn10300_local_dcache_flush_inv_page
+ .size mn10300_local_dcache_flush_inv_range,.-mn10300_local_dcache_flush_inv_range
+ .size mn10300_local_dcache_flush_inv_range2,.-mn10300_local_dcache_flush_inv_range2
diff --git a/arch/mn10300/mm/cache-flush-by-tag.S b/arch/mn10300/mm/cache-flush-by-tag.S
new file mode 100644
index 000000000000..5cd6a27dd63e
--- /dev/null
+++ b/arch/mn10300/mm/cache-flush-by-tag.S
@@ -0,0 +1,251 @@
+/* MN10300 CPU core caching routines, using direct tag flushing
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/irqflags.h>
+
+ .am33_2
+
+#ifndef CONFIG_SMP
+ .globl mn10300_dcache_flush
+ .globl mn10300_dcache_flush_page
+ .globl mn10300_dcache_flush_range
+ .globl mn10300_dcache_flush_range2
+ .globl mn10300_dcache_flush_inv
+ .globl mn10300_dcache_flush_inv_page
+ .globl mn10300_dcache_flush_inv_range
+ .globl mn10300_dcache_flush_inv_range2
+
+mn10300_dcache_flush = mn10300_local_dcache_flush
+mn10300_dcache_flush_page = mn10300_local_dcache_flush_page
+mn10300_dcache_flush_range = mn10300_local_dcache_flush_range
+mn10300_dcache_flush_range2 = mn10300_local_dcache_flush_range2
+mn10300_dcache_flush_inv = mn10300_local_dcache_flush_inv
+mn10300_dcache_flush_inv_page = mn10300_local_dcache_flush_inv_page
+mn10300_dcache_flush_inv_range = mn10300_local_dcache_flush_inv_range
+mn10300_dcache_flush_inv_range2 = mn10300_local_dcache_flush_inv_range2
+
+#endif /* !CONFIG_SMP */
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush(void)
+# Flush the entire data cache back to RAM
+#
+###############################################################################
+ ALIGN
+ .globl mn10300_local_dcache_flush
+ .type mn10300_local_dcache_flush,@function
+mn10300_local_dcache_flush:
+ movhu (CHCTR),d0
+ btst CHCTR_DCEN,d0
+ beq mn10300_local_dcache_flush_end
+
+ # read the addresses tagged in the cache's tag RAM and attempt to flush
+ # those addresses specifically
+ # - we rely on the hardware to filter out invalid tag entry addresses
+ mov DCACHE_TAG(0,0),a0 # dcache tag RAM access address
+ mov DCACHE_PURGE(0,0),a1 # dcache purge request address
+ mov L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1 # total number of entries
+
+mn10300_local_dcache_flush_loop:
+ mov (a0),d0
+ and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
+ or L1_CACHE_TAG_VALID,d0 # retain valid entries in the
+ # cache
+ mov d0,(a1) # conditional purge
+
+ add L1_CACHE_BYTES,a0
+ add L1_CACHE_BYTES,a1
+ add -1,d1
+ bne mn10300_local_dcache_flush_loop
+
+mn10300_local_dcache_flush_end:
+ ret [],0
+ .size mn10300_local_dcache_flush,.-mn10300_local_dcache_flush
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush_page(unsigned long start)
+# void mn10300_local_dcache_flush_range(unsigned long start, unsigned long end)
+# void mn10300_local_dcache_flush_range2(unsigned long start, unsigned long size)
+# Flush a range of addresses on a page in the dcache
+#
+###############################################################################
+ ALIGN
+ .globl mn10300_local_dcache_flush_page
+ .globl mn10300_local_dcache_flush_range
+ .globl mn10300_local_dcache_flush_range2
+ .type mn10300_local_dcache_flush_page,@function
+ .type mn10300_local_dcache_flush_range,@function
+ .type mn10300_local_dcache_flush_range2,@function
+mn10300_local_dcache_flush_page:
+ and ~(PAGE_SIZE-1),d0
+ mov PAGE_SIZE,d1
+mn10300_local_dcache_flush_range2:
+ add d0,d1
+mn10300_local_dcache_flush_range:
+ movm [d2],(sp)
+
+ movhu (CHCTR),d2
+ btst CHCTR_DCEN,d2
+ beq mn10300_local_dcache_flush_range_end
+
+ sub d0,d1,a0
+ cmp MN10300_DCACHE_FLUSH_BORDER,a0
+ ble 1f
+
+ movm (sp),[d2]
+ bra mn10300_local_dcache_flush
+1:
+
+ # round start addr down
+ and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
+ mov d0,a1
+
+ add L1_CACHE_BYTES,d1 # round end addr up
+ and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
+
+ # write a request to flush all instances of an address from the cache
+ mov DCACHE_PURGE(0,0),a0
+ mov a1,d0
+ and L1_CACHE_TAG_ENTRY,d0
+ add d0,a0 # starting dcache purge control
+ # reg address
+
+ sub a1,d1
+ lsr L1_CACHE_SHIFT,d1 # total number of entries to
+ # examine
+
+ or L1_CACHE_TAG_VALID,a1 # retain valid entries in the
+ # cache
+
+mn10300_local_dcache_flush_range_loop:
+ mov a1,(L1_CACHE_WAYDISP*0,a0) # conditionally purge this line
+ # all ways
+
+ add L1_CACHE_BYTES,a0
+ add L1_CACHE_BYTES,a1
+ and ~L1_CACHE_WAYDISP,a0 # make sure way stay on way 0
+ add -1,d1
+ bne mn10300_local_dcache_flush_range_loop
+
+mn10300_local_dcache_flush_range_end:
+ ret [d2],4
+
+ .size mn10300_local_dcache_flush_page,.-mn10300_local_dcache_flush_page
+ .size mn10300_local_dcache_flush_range,.-mn10300_local_dcache_flush_range
+ .size mn10300_local_dcache_flush_range2,.-mn10300_local_dcache_flush_range2
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush_inv(void)
+# Flush the entire data cache and invalidate all entries
+#
+###############################################################################
+ ALIGN
+ .globl mn10300_local_dcache_flush_inv
+ .type mn10300_local_dcache_flush_inv,@function
+mn10300_local_dcache_flush_inv:
+ movhu (CHCTR),d0
+ btst CHCTR_DCEN,d0
+ beq mn10300_local_dcache_flush_inv_end
+
+ mov L1_CACHE_NENTRIES,d1
+ clr a1
+
+mn10300_local_dcache_flush_inv_loop:
+ mov (DCACHE_PURGE_WAY0(0),a1),d0 # unconditional purge
+ mov (DCACHE_PURGE_WAY1(0),a1),d0 # unconditional purge
+ mov (DCACHE_PURGE_WAY2(0),a1),d0 # unconditional purge
+ mov (DCACHE_PURGE_WAY3(0),a1),d0 # unconditional purge
+
+ add L1_CACHE_BYTES,a1
+ add -1,d1
+ bne mn10300_local_dcache_flush_inv_loop
+
+mn10300_local_dcache_flush_inv_end:
+ ret [],0
+ .size mn10300_local_dcache_flush_inv,.-mn10300_local_dcache_flush_inv
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush_inv_page(unsigned long start)
+# void mn10300_local_dcache_flush_inv_range(unsigned long start, unsigned long end)
+# void mn10300_local_dcache_flush_inv_range2(unsigned long start, unsigned long size)
+# Flush and invalidate a range of addresses on a page in the dcache
+#
+###############################################################################
+ ALIGN
+ .globl mn10300_local_dcache_flush_inv_page
+ .globl mn10300_local_dcache_flush_inv_range
+ .globl mn10300_local_dcache_flush_inv_range2
+ .type mn10300_local_dcache_flush_inv_page,@function
+ .type mn10300_local_dcache_flush_inv_range,@function
+ .type mn10300_local_dcache_flush_inv_range2,@function
+mn10300_local_dcache_flush_inv_page:
+ and ~(PAGE_SIZE-1),d0
+ mov PAGE_SIZE,d1
+mn10300_local_dcache_flush_inv_range2:
+ add d0,d1
+mn10300_local_dcache_flush_inv_range:
+ movm [d2],(sp)
+
+ movhu (CHCTR),d2
+ btst CHCTR_DCEN,d2
+ beq mn10300_local_dcache_flush_inv_range_end
+
+ sub d0,d1,a0
+ cmp MN10300_DCACHE_FLUSH_INV_BORDER,a0
+ ble 1f
+
+ movm (sp),[d2]
+ bra mn10300_local_dcache_flush_inv
+1:
+
+ and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start
+ # addr down
+ mov d0,a1
+
+ add L1_CACHE_BYTES,d1 # round end addr up
+ and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
+
+ # write a request to flush and invalidate all instances of an address
+ # from the cache
+ mov DCACHE_PURGE(0,0),a0
+ mov a1,d0
+ and L1_CACHE_TAG_ENTRY,d0
+ add d0,a0 # starting dcache purge control
+ # reg address
+
+ sub a1,d1
+ lsr L1_CACHE_SHIFT,d1 # total number of entries to
+ # examine
+
+mn10300_local_dcache_flush_inv_range_loop:
+ mov a1,(L1_CACHE_WAYDISP*0,a0) # conditionally purge this line
+ # in all ways
+
+ add L1_CACHE_BYTES,a0
+ add L1_CACHE_BYTES,a1
+ and ~L1_CACHE_WAYDISP,a0 # make sure way stay on way 0
+ add -1,d1
+ bne mn10300_local_dcache_flush_inv_range_loop
+
+mn10300_local_dcache_flush_inv_range_end:
+ ret [d2],4
+ .size mn10300_local_dcache_flush_inv_page,.-mn10300_local_dcache_flush_inv_page
+ .size mn10300_local_dcache_flush_inv_range,.-mn10300_local_dcache_flush_inv_range
+ .size mn10300_local_dcache_flush_inv_range2,.-mn10300_local_dcache_flush_inv_range2
diff --git a/arch/mn10300/mm/cache-flush-icache.c b/arch/mn10300/mm/cache-flush-icache.c
new file mode 100644
index 000000000000..fdb1a9db20f0
--- /dev/null
+++ b/arch/mn10300/mm/cache-flush-icache.c
@@ -0,0 +1,155 @@
+/* Flush dcache and invalidate icache when the dcache is in writeback mode
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <asm/cacheflush.h>
+#include <asm/smp.h>
+#include "cache-smp.h"
+
+/**
+ * flush_icache_page - Flush a page from the dcache and invalidate the icache
+ * @vma: The VMA the page is part of.
+ * @page: The page to be flushed.
+ *
+ * Write a page back from the dcache and invalidate the icache so that we can
+ * run code from it that we've just written into it
+ */
+void flush_icache_page(struct vm_area_struct *vma, struct page *page)
+{
+ unsigned long start = page_to_phys(page);
+ unsigned long flags;
+
+ flags = smp_lock_cache();
+
+ mn10300_local_dcache_flush_page(start);
+ mn10300_local_icache_inv_page(start);
+
+ smp_cache_call(SMP_IDCACHE_INV_FLUSH_RANGE, start, start + PAGE_SIZE);
+ smp_unlock_cache(flags);
+}
+EXPORT_SYMBOL(flush_icache_page);
+
+/**
+ * flush_icache_page_range - Flush dcache and invalidate icache for part of a
+ * single page
+ * @start: The starting virtual address of the page part.
+ * @end: The ending virtual address of the page part.
+ *
+ * Flush the dcache and invalidate the icache for part of a single page, as
+ * determined by the virtual addresses given. The page must be in the paged
+ * area.
+ */
+static void flush_icache_page_range(unsigned long start, unsigned long end)
+{
+ unsigned long addr, size, off;
+ struct page *page;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *ppte, pte;
+
+ /* work out how much of the page to flush */
+ off = start & ~PAGE_MASK;
+ size = end - start;
+
+ /* get the physical address the page is mapped to from the page
+ * tables */
+ pgd = pgd_offset(current->mm, start);
+ if (!pgd || !pgd_val(*pgd))
+ return;
+
+ pud = pud_offset(pgd, start);
+ if (!pud || !pud_val(*pud))
+ return;
+
+ pmd = pmd_offset(pud, start);
+ if (!pmd || !pmd_val(*pmd))
+ return;
+
+ ppte = pte_offset_map(pmd, start);
+ if (!ppte)
+ return;
+ pte = *ppte;
+ pte_unmap(ppte);
+
+ if (pte_none(pte))
+ return;
+
+ page = pte_page(pte);
+ if (!page)
+ return;
+
+ addr = page_to_phys(page);
+
+ /* flush the dcache and invalidate the icache coverage on that
+ * region */
+ mn10300_local_dcache_flush_range2(addr + off, size);
+ mn10300_local_icache_inv_range2(addr + off, size);
+ smp_cache_call(SMP_IDCACHE_INV_FLUSH_RANGE, start, end);
+}
+
+/**
+ * flush_icache_range - Globally flush dcache and invalidate icache for region
+ * @start: The starting virtual address of the region.
+ * @end: The ending virtual address of the region.
+ *
+ * This is used by the kernel to globally flush some code it has just written
+ * from the dcache back to RAM and then to globally invalidate the icache over
+ * that region so that that code can be run on all CPUs in the system.
+ */
+void flush_icache_range(unsigned long start, unsigned long end)
+{
+ unsigned long start_page, end_page;
+ unsigned long flags;
+
+ flags = smp_lock_cache();
+
+ if (end > 0x80000000UL) {
+ /* addresses above 0xa0000000 do not go through the cache */
+ if (end > 0xa0000000UL) {
+ end = 0xa0000000UL;
+ if (start >= end)
+ goto done;
+ }
+
+ /* kernel addresses between 0x80000000 and 0x9fffffff do not
+ * require page tables, so we just map such addresses
+ * directly */
+ start_page = (start >= 0x80000000UL) ? start : 0x80000000UL;
+ mn10300_local_dcache_flush_range(start_page, end);
+ mn10300_local_icache_inv_range(start_page, end);
+ smp_cache_call(SMP_IDCACHE_INV_FLUSH_RANGE, start_page, end);
+ if (start_page == start)
+ goto done;
+ end = start_page;
+ }
+
+ start_page = start & PAGE_MASK;
+ end_page = (end - 1) & PAGE_MASK;
+
+ if (start_page == end_page) {
+ /* the first and last bytes are on the same page */
+ flush_icache_page_range(start, end);
+ } else if (start_page + 1 == end_page) {
+ /* split over two virtually contiguous pages */
+ flush_icache_page_range(start, end_page);
+ flush_icache_page_range(end_page, end);
+ } else {
+ /* more than 2 pages; just flush the entire cache */
+ mn10300_dcache_flush();
+ mn10300_icache_inv();
+ smp_cache_call(SMP_IDCACHE_INV_FLUSH, 0, 0);
+ }
+
+done:
+ smp_unlock_cache(flags);
+}
+EXPORT_SYMBOL(flush_icache_range);
diff --git a/arch/mn10300/mm/cache-flush-mn10300.S b/arch/mn10300/mm/cache-flush-mn10300.S
deleted file mode 100644
index c8ed1cbac107..000000000000
--- a/arch/mn10300/mm/cache-flush-mn10300.S
+++ /dev/null
@@ -1,192 +0,0 @@
-/* MN10300 CPU core caching routines
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-
-#include <linux/sys.h>
-#include <linux/linkage.h>
-#include <asm/smp.h>
-#include <asm/page.h>
-#include <asm/cache.h>
-
- .am33_2
- .globl mn10300_dcache_flush
- .globl mn10300_dcache_flush_page
- .globl mn10300_dcache_flush_range
- .globl mn10300_dcache_flush_range2
- .globl mn10300_dcache_flush_inv
- .globl mn10300_dcache_flush_inv_page
- .globl mn10300_dcache_flush_inv_range
- .globl mn10300_dcache_flush_inv_range2
-
-###############################################################################
-#
-# void mn10300_dcache_flush(void)
-# Flush the entire data cache back to RAM
-#
-###############################################################################
- ALIGN
-mn10300_dcache_flush:
- movhu (CHCTR),d0
- btst CHCTR_DCEN,d0
- beq mn10300_dcache_flush_end
-
- # read the addresses tagged in the cache's tag RAM and attempt to flush
- # those addresses specifically
- # - we rely on the hardware to filter out invalid tag entry addresses
- mov DCACHE_TAG(0,0),a0 # dcache tag RAM access address
- mov DCACHE_PURGE(0,0),a1 # dcache purge request address
- mov L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1 # total number of entries
-
-mn10300_dcache_flush_loop:
- mov (a0),d0
- and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
- or L1_CACHE_TAG_VALID,d0 # retain valid entries in the
- # cache
- mov d0,(a1) # conditional purge
-
-mn10300_dcache_flush_skip:
- add L1_CACHE_BYTES,a0
- add L1_CACHE_BYTES,a1
- add -1,d1
- bne mn10300_dcache_flush_loop
-
-mn10300_dcache_flush_end:
- ret [],0
-
-###############################################################################
-#
-# void mn10300_dcache_flush_page(unsigned start)
-# void mn10300_dcache_flush_range(unsigned start, unsigned end)
-# void mn10300_dcache_flush_range2(unsigned start, unsigned size)
-# Flush a range of addresses on a page in the dcache
-#
-###############################################################################
- ALIGN
-mn10300_dcache_flush_page:
- mov PAGE_SIZE,d1
-mn10300_dcache_flush_range2:
- add d0,d1
-mn10300_dcache_flush_range:
- movm [d2,d3],(sp)
-
- movhu (CHCTR),d2
- btst CHCTR_DCEN,d2
- beq mn10300_dcache_flush_range_end
-
- # round start addr down
- and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
- mov d0,a1
-
- add L1_CACHE_BYTES,d1 # round end addr up
- and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
-
- # write a request to flush all instances of an address from the cache
- mov DCACHE_PURGE(0,0),a0
- mov a1,d0
- and L1_CACHE_TAG_ENTRY,d0
- add d0,a0 # starting dcache purge control
- # reg address
-
- sub a1,d1
- lsr L1_CACHE_SHIFT,d1 # total number of entries to
- # examine
-
- or L1_CACHE_TAG_VALID,a1 # retain valid entries in the
- # cache
-
-mn10300_dcache_flush_range_loop:
- mov a1,(L1_CACHE_WAYDISP*0,a0) # conditionally purge this line
- # all ways
-
- add L1_CACHE_BYTES,a0
- add L1_CACHE_BYTES,a1
- and ~L1_CACHE_WAYDISP,a0 # make sure way stay on way 0
- add -1,d1
- bne mn10300_dcache_flush_range_loop
-
-mn10300_dcache_flush_range_end:
- ret [d2,d3],8
-
-###############################################################################
-#
-# void mn10300_dcache_flush_inv(void)
-# Flush the entire data cache and invalidate all entries
-#
-###############################################################################
- ALIGN
-mn10300_dcache_flush_inv:
- movhu (CHCTR),d0
- btst CHCTR_DCEN,d0
- beq mn10300_dcache_flush_inv_end
-
- # hit each line in the dcache with an unconditional purge
- mov DCACHE_PURGE(0,0),a1 # dcache purge request address
- mov L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1 # total number of entries
-
-mn10300_dcache_flush_inv_loop:
- mov (a1),d0 # unconditional purge
-
- add L1_CACHE_BYTES,a1
- add -1,d1
- bne mn10300_dcache_flush_inv_loop
-
-mn10300_dcache_flush_inv_end:
- ret [],0
-
-###############################################################################
-#
-# void mn10300_dcache_flush_inv_page(unsigned start)
-# void mn10300_dcache_flush_inv_range(unsigned start, unsigned end)
-# void mn10300_dcache_flush_inv_range2(unsigned start, unsigned size)
-# Flush and invalidate a range of addresses on a page in the dcache
-#
-###############################################################################
- ALIGN
-mn10300_dcache_flush_inv_page:
- mov PAGE_SIZE,d1
-mn10300_dcache_flush_inv_range2:
- add d0,d1
-mn10300_dcache_flush_inv_range:
- movm [d2,d3],(sp)
- movhu (CHCTR),d2
- btst CHCTR_DCEN,d2
- beq mn10300_dcache_flush_inv_range_end
-
- and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start
- # addr down
- mov d0,a1
-
- add L1_CACHE_BYTES,d1 # round end addr up
- and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
-
- # write a request to flush and invalidate all instances of an address
- # from the cache
- mov DCACHE_PURGE(0,0),a0
- mov a1,d0
- and L1_CACHE_TAG_ENTRY,d0
- add d0,a0 # starting dcache purge control
- # reg address
-
- sub a1,d1
- lsr L1_CACHE_SHIFT,d1 # total number of entries to
- # examine
-
-mn10300_dcache_flush_inv_range_loop:
- mov a1,(L1_CACHE_WAYDISP*0,a0) # conditionally purge this line
- # in all ways
-
- add L1_CACHE_BYTES,a0
- add L1_CACHE_BYTES,a1
- and ~L1_CACHE_WAYDISP,a0 # make sure way stay on way 0
- add -1,d1
- bne mn10300_dcache_flush_inv_range_loop
-
-mn10300_dcache_flush_inv_range_end:
- ret [d2,d3],8
diff --git a/arch/mn10300/mm/cache-inv-by-reg.S b/arch/mn10300/mm/cache-inv-by-reg.S
new file mode 100644
index 000000000000..c8950861ed77
--- /dev/null
+++ b/arch/mn10300/mm/cache-inv-by-reg.S
@@ -0,0 +1,356 @@
+/* MN10300 CPU cache invalidation routines, using automatic purge registers
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/irqflags.h>
+#include <asm/cacheflush.h>
+
+#define mn10300_local_dcache_inv_range_intr_interval \
+ +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
+
+#if mn10300_local_dcache_inv_range_intr_interval > 0xff
+#error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less
+#endif
+
+ .am33_2
+
+#ifndef CONFIG_SMP
+ .globl mn10300_icache_inv
+ .globl mn10300_icache_inv_page
+ .globl mn10300_icache_inv_range
+ .globl mn10300_icache_inv_range2
+ .globl mn10300_dcache_inv
+ .globl mn10300_dcache_inv_page
+ .globl mn10300_dcache_inv_range
+ .globl mn10300_dcache_inv_range2
+
+mn10300_icache_inv = mn10300_local_icache_inv
+mn10300_icache_inv_page = mn10300_local_icache_inv_page
+mn10300_icache_inv_range = mn10300_local_icache_inv_range
+mn10300_icache_inv_range2 = mn10300_local_icache_inv_range2
+mn10300_dcache_inv = mn10300_local_dcache_inv
+mn10300_dcache_inv_page = mn10300_local_dcache_inv_page
+mn10300_dcache_inv_range = mn10300_local_dcache_inv_range
+mn10300_dcache_inv_range2 = mn10300_local_dcache_inv_range2
+
+#endif /* !CONFIG_SMP */
+
+###############################################################################
+#
+# void mn10300_local_icache_inv(void)
+# Invalidate the entire icache
+#
+###############################################################################
+ ALIGN
+ .globl mn10300_local_icache_inv
+ .type mn10300_local_icache_inv,@function
+mn10300_local_icache_inv:
+ mov CHCTR,a0
+
+ movhu (a0),d0
+ btst CHCTR_ICEN,d0
+ beq mn10300_local_icache_inv_end
+
+ # invalidate
+ or CHCTR_ICINV,d0
+ movhu d0,(a0)
+ movhu (a0),d0
+
+mn10300_local_icache_inv_end:
+ ret [],0
+ .size mn10300_local_icache_inv,.-mn10300_local_icache_inv
+
+###############################################################################
+#
+# void mn10300_local_dcache_inv(void)
+# Invalidate the entire dcache
+#
+###############################################################################
+ ALIGN
+ .globl mn10300_local_dcache_inv
+ .type mn10300_local_dcache_inv,@function
+mn10300_local_dcache_inv:
+ mov CHCTR,a0
+
+ movhu (a0),d0
+ btst CHCTR_DCEN,d0
+ beq mn10300_local_dcache_inv_end
+
+ # invalidate
+ or CHCTR_DCINV,d0
+ movhu d0,(a0)
+ movhu (a0),d0
+
+mn10300_local_dcache_inv_end:
+ ret [],0
+ .size mn10300_local_dcache_inv,.-mn10300_local_dcache_inv
+
+###############################################################################
+#
+# void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end)
+# void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size)
+# void mn10300_local_dcache_inv_page(unsigned long start)
+# Invalidate a range of addresses on a page in the dcache
+#
+###############################################################################
+ ALIGN
+ .globl mn10300_local_dcache_inv_page
+ .globl mn10300_local_dcache_inv_range
+ .globl mn10300_local_dcache_inv_range2
+ .type mn10300_local_dcache_inv_page,@function
+ .type mn10300_local_dcache_inv_range,@function
+ .type mn10300_local_dcache_inv_range2,@function
+mn10300_local_dcache_inv_page:
+ and ~(PAGE_SIZE-1),d0
+ mov PAGE_SIZE,d1
+mn10300_local_dcache_inv_range2:
+ add d0,d1
+mn10300_local_dcache_inv_range:
+ # If we are in writeback mode we check the start and end alignments,
+ # and if they're not cacheline-aligned, we must flush any bits outside
+ # the range that share cachelines with stuff inside the range
+#ifdef CONFIG_MN10300_CACHE_WBACK
+ btst ~(L1_CACHE_BYTES-1),d0
+ bne 1f
+ btst ~(L1_CACHE_BYTES-1),d1
+ beq 2f
+1:
+ bra mn10300_local_dcache_flush_inv_range
+2:
+#endif /* CONFIG_MN10300_CACHE_WBACK */
+
+ movm [d2,d3,a2],(sp)
+
+ mov CHCTR,a0
+ movhu (a0),d2
+ btst CHCTR_DCEN,d2
+ beq mn10300_local_dcache_inv_range_end
+
+ # round the addresses out to be full cachelines, unless we're in
+ # writeback mode, in which case we would be in flush and invalidate by
+ # now
+#ifndef CONFIG_MN10300_CACHE_WBACK
+ and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start
+ # addr down
+
+ mov L1_CACHE_BYTES-1,d2
+ add d2,d1
+ and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 # round end addr up
+#endif /* !CONFIG_MN10300_CACHE_WBACK */
+
+ sub d0,d1,d2 # calculate the total size
+ mov d0,a2 # A2 = start address
+ mov d1,a1 # A1 = end address
+
+ LOCAL_CLI_SAVE(d3)
+
+ mov DCPGCR,a0 # make sure the purger isn't busy
+ setlb
+ mov (a0),d0
+ btst DCPGCR_DCPGBSY,d0
+ lne
+
+ # skip initial address alignment calculation if address is zero
+ mov d2,d1
+ cmp 0,a2
+ beq 1f
+
+dcivloop:
+ /* calculate alignsize
+ *
+ * alignsize = L1_CACHE_BYTES;
+ * while (! start & alignsize) {
+ * alignsize <<=1;
+ * }
+ * d1 = alignsize;
+ */
+ mov L1_CACHE_BYTES,d1
+ lsr 1,d1
+ setlb
+ add d1,d1
+ mov d1,d0
+ and a2,d0
+ leq
+
+1:
+ /* calculate invsize
+ *
+ * if (totalsize > alignsize) {
+ * invsize = alignsize;
+ * } else {
+ * invsize = totalsize;
+ * tmp = 0x80000000;
+ * while (! invsize & tmp) {
+ * tmp >>= 1;
+ * }
+ * invsize = tmp;
+ * }
+ * d1 = invsize
+ */
+ cmp d2,d1
+ bns 2f
+ mov d2,d1
+
+ mov 0x80000000,d0 # start from 31bit=1
+ setlb
+ lsr 1,d0
+ mov d0,e0
+ and d1,e0
+ leq
+ mov d0,d1
+
+2:
+ /* set mask
+ *
+ * mask = ~(invsize-1);
+ * DCPGMR = mask;
+ */
+ mov d1,d0
+ add -1,d0
+ not d0
+ mov d0,(DCPGMR)
+
+ # invalidate area
+ mov a2,d0
+ or DCPGCR_DCI,d0
+ mov d0,(a0) # DCPGCR = (mask & start) | DCPGCR_DCI
+
+ setlb # wait for the purge to complete
+ mov (a0),d0
+ btst DCPGCR_DCPGBSY,d0
+ lne
+
+ sub d1,d2 # decrease size remaining
+ add d1,a2 # increase next start address
+
+ /* check invalidating of end address
+ *
+ * a2 = a2 + invsize
+ * if (a2 < end) {
+ * goto dcivloop;
+ * } */
+ cmp a1,a2
+ bns dcivloop
+
+ LOCAL_IRQ_RESTORE(d3)
+
+mn10300_local_dcache_inv_range_end:
+ ret [d2,d3,a2],12
+ .size mn10300_local_dcache_inv_page,.-mn10300_local_dcache_inv_page
+ .size mn10300_local_dcache_inv_range,.-mn10300_local_dcache_inv_range
+ .size mn10300_local_dcache_inv_range2,.-mn10300_local_dcache_inv_range2
+
+###############################################################################
+#
+# void mn10300_local_icache_inv_page(unsigned long start)
+# void mn10300_local_icache_inv_range2(unsigned long start, unsigned long size)
+# void mn10300_local_icache_inv_range(unsigned long start, unsigned long end)
+# Invalidate a range of addresses on a page in the icache
+#
+###############################################################################
+ ALIGN
+ .globl mn10300_local_icache_inv_page
+ .globl mn10300_local_icache_inv_range
+ .globl mn10300_local_icache_inv_range2
+ .type mn10300_local_icache_inv_page,@function
+ .type mn10300_local_icache_inv_range,@function
+ .type mn10300_local_icache_inv_range2,@function
+mn10300_local_icache_inv_page:
+ and ~(PAGE_SIZE-1),d0
+ mov PAGE_SIZE,d1
+mn10300_local_icache_inv_range2:
+ add d0,d1
+mn10300_local_icache_inv_range:
+ movm [d2,d3,a2],(sp)
+
+ mov CHCTR,a0
+ movhu (a0),d2
+ btst CHCTR_ICEN,d2
+ beq mn10300_local_icache_inv_range_reg_end
+
+ /* calculate alignsize
+ *
+ * alignsize = L1_CACHE_BYTES;
+ * for (i = (end - start - 1) / L1_CACHE_BYTES ; i > 0; i >>= 1) {
+ * alignsize <<= 1;
+ * }
+ * d2 = alignsize;
+ */
+ mov L1_CACHE_BYTES,d2
+ sub d0,d1,d3
+ add -1,d3
+ lsr L1_CACHE_SHIFT,d3
+ beq 2f
+1:
+ add d2,d2
+ lsr 1,d3
+ bne 1b
+2:
+
+ /* a1 = end */
+ mov d1,a1
+
+ LOCAL_CLI_SAVE(d3)
+
+ mov ICIVCR,a0
+ /* wait for busy bit of area invalidation */
+ setlb
+ mov (a0),d1
+ btst ICIVCR_ICIVBSY,d1
+ lne
+
+ /* set mask
+ *
+ * mask = ~(alignsize-1);
+ * ICIVMR = mask;
+ */
+ mov d2,d1
+ add -1,d1
+ not d1
+ mov d1,(ICIVMR)
+ /* a2 = mask & start */
+ and d1,d0,a2
+
+icivloop:
+ /* area invalidate
+ *
+ * ICIVCR = (mask & start) | ICIVCR_ICI
+ */
+ mov a2,d0
+ or ICIVCR_ICI,d0
+ mov d0,(a0)
+
+ /* wait for busy bit of area invalidation */
+ setlb
+ mov (a0),d1
+ btst ICIVCR_ICIVBSY,d1
+ lne
+
+ /* check invalidating of end address
+ *
+ * a2 = a2 + alignsize
+ * if (a2 < end) {
+ * goto icivloop;
+ * } */
+ add d2,a2
+ cmp a1,a2
+ bns icivloop
+
+ LOCAL_IRQ_RESTORE(d3)
+
+mn10300_local_icache_inv_range_reg_end:
+ ret [d2,d3,a2],12
+ .size mn10300_local_icache_inv_page,.-mn10300_local_icache_inv_page
+ .size mn10300_local_icache_inv_range,.-mn10300_local_icache_inv_range
+ .size mn10300_local_icache_inv_range2,.-mn10300_local_icache_inv_range2
diff --git a/arch/mn10300/mm/cache-inv-by-tag.S b/arch/mn10300/mm/cache-inv-by-tag.S
new file mode 100644
index 000000000000..e9713b40c0ff
--- /dev/null
+++ b/arch/mn10300/mm/cache-inv-by-tag.S
@@ -0,0 +1,348 @@
+/* MN10300 CPU core caching routines
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/irqflags.h>
+#include <asm/cacheflush.h>
+
+#define mn10300_local_dcache_inv_range_intr_interval \
+ +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
+
+#if mn10300_local_dcache_inv_range_intr_interval > 0xff
+#error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less
+#endif
+
+ .am33_2
+
+ .globl mn10300_local_icache_inv_page
+ .globl mn10300_local_icache_inv_range
+ .globl mn10300_local_icache_inv_range2
+
+mn10300_local_icache_inv_page = mn10300_local_icache_inv
+mn10300_local_icache_inv_range = mn10300_local_icache_inv
+mn10300_local_icache_inv_range2 = mn10300_local_icache_inv
+
+#ifndef CONFIG_SMP
+ .globl mn10300_icache_inv
+ .globl mn10300_icache_inv_page
+ .globl mn10300_icache_inv_range
+ .globl mn10300_icache_inv_range2
+ .globl mn10300_dcache_inv
+ .globl mn10300_dcache_inv_page
+ .globl mn10300_dcache_inv_range
+ .globl mn10300_dcache_inv_range2
+
+mn10300_icache_inv = mn10300_local_icache_inv
+mn10300_icache_inv_page = mn10300_local_icache_inv_page
+mn10300_icache_inv_range = mn10300_local_icache_inv_range
+mn10300_icache_inv_range2 = mn10300_local_icache_inv_range2
+mn10300_dcache_inv = mn10300_local_dcache_inv
+mn10300_dcache_inv_page = mn10300_local_dcache_inv_page
+mn10300_dcache_inv_range = mn10300_local_dcache_inv_range
+mn10300_dcache_inv_range2 = mn10300_local_dcache_inv_range2
+
+#endif /* !CONFIG_SMP */
+
+###############################################################################
+#
+# void mn10300_local_icache_inv(void)
+# Invalidate the entire icache
+#
+###############################################################################
+ ALIGN
+ .globl mn10300_local_icache_inv
+ .type mn10300_local_icache_inv,@function
+mn10300_local_icache_inv:
+ mov CHCTR,a0
+
+ movhu (a0),d0
+ btst CHCTR_ICEN,d0
+ beq mn10300_local_icache_inv_end
+
+#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
+ LOCAL_CLI_SAVE(d1)
+
+ # disable the icache
+ and ~CHCTR_ICEN,d0
+ movhu d0,(a0)
+
+ # and wait for it to calm down
+ setlb
+ movhu (a0),d0
+ btst CHCTR_ICBUSY,d0
+ lne
+
+ # invalidate
+ or CHCTR_ICINV,d0
+ movhu d0,(a0)
+
+ # wait for the cache to finish
+ mov CHCTR,a0
+ setlb
+ movhu (a0),d0
+ btst CHCTR_ICBUSY,d0
+ lne
+
+ # and reenable it
+ and ~CHCTR_ICINV,d0
+ or CHCTR_ICEN,d0
+ movhu d0,(a0)
+ movhu (a0),d0
+
+ LOCAL_IRQ_RESTORE(d1)
+#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+ # invalidate
+ or CHCTR_ICINV,d0
+ movhu d0,(a0)
+ movhu (a0),d0
+#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+
+mn10300_local_icache_inv_end:
+ ret [],0
+ .size mn10300_local_icache_inv,.-mn10300_local_icache_inv
+
+###############################################################################
+#
+# void mn10300_local_dcache_inv(void)
+# Invalidate the entire dcache
+#
+###############################################################################
+ ALIGN
+ .globl mn10300_local_dcache_inv
+ .type mn10300_local_dcache_inv,@function
+mn10300_local_dcache_inv:
+ mov CHCTR,a0
+
+ movhu (a0),d0
+ btst CHCTR_DCEN,d0
+ beq mn10300_local_dcache_inv_end
+
+#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
+ LOCAL_CLI_SAVE(d1)
+
+ # disable the dcache
+ and ~CHCTR_DCEN,d0
+ movhu d0,(a0)
+
+ # and wait for it to calm down
+ setlb
+ movhu (a0),d0
+ btst CHCTR_DCBUSY,d0
+ lne
+
+ # invalidate
+ or CHCTR_DCINV,d0
+ movhu d0,(a0)
+
+ # wait for the cache to finish
+ mov CHCTR,a0
+ setlb
+ movhu (a0),d0
+ btst CHCTR_DCBUSY,d0
+ lne
+
+ # and reenable it
+ and ~CHCTR_DCINV,d0
+ or CHCTR_DCEN,d0
+ movhu d0,(a0)
+ movhu (a0),d0
+
+ LOCAL_IRQ_RESTORE(d1)
+#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+ # invalidate
+ or CHCTR_DCINV,d0
+ movhu d0,(a0)
+ movhu (a0),d0
+#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+
+mn10300_local_dcache_inv_end:
+ ret [],0
+ .size mn10300_local_dcache_inv,.-mn10300_local_dcache_inv
+
+###############################################################################
+#
+# void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end)
+# void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size)
+# void mn10300_local_dcache_inv_page(unsigned long start)
+# Invalidate a range of addresses on a page in the dcache
+#
+###############################################################################
+ ALIGN
+ .globl mn10300_local_dcache_inv_page
+ .globl mn10300_local_dcache_inv_range
+ .globl mn10300_local_dcache_inv_range2
+ .type mn10300_local_dcache_inv_page,@function
+ .type mn10300_local_dcache_inv_range,@function
+ .type mn10300_local_dcache_inv_range2,@function
+mn10300_local_dcache_inv_page:
+ and ~(PAGE_SIZE-1),d0
+ mov PAGE_SIZE,d1
+mn10300_local_dcache_inv_range2:
+ add d0,d1
+mn10300_local_dcache_inv_range:
+ # If we are in writeback mode we check the start and end alignments,
+ # and if they're not cacheline-aligned, we must flush any bits outside
+ # the range that share cachelines with stuff inside the range
+#ifdef CONFIG_MN10300_CACHE_WBACK
+ btst ~(L1_CACHE_BYTES-1),d0
+ bne 1f
+ btst ~(L1_CACHE_BYTES-1),d1
+ beq 2f
+1:
+ bra mn10300_local_dcache_flush_inv_range
+2:
+#endif /* CONFIG_MN10300_CACHE_WBACK */
+
+ movm [d2,d3,a2],(sp)
+
+ mov CHCTR,a2
+ movhu (a2),d2
+ btst CHCTR_DCEN,d2
+ beq mn10300_local_dcache_inv_range_end
+
+#ifndef CONFIG_MN10300_CACHE_WBACK
+ and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start
+ # addr down
+
+ add L1_CACHE_BYTES,d1 # round end addr up
+ and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
+#endif /* !CONFIG_MN10300_CACHE_WBACK */
+ mov d0,a1
+
+ clr d2 # we're going to clear tag RAM
+ # entries
+
+ # read the tags from the tag RAM, and if they indicate a valid dirty
+ # cache line then invalidate that line
+ mov DCACHE_TAG(0,0),a0
+ mov a1,d0
+ and L1_CACHE_TAG_ENTRY,d0
+ add d0,a0 # starting dcache tag RAM
+ # access address
+
+ sub a1,d1
+ lsr L1_CACHE_SHIFT,d1 # total number of entries to
+ # examine
+
+ and ~(L1_CACHE_DISPARITY-1),a1 # determine comparator base
+
+mn10300_local_dcache_inv_range_outer_loop:
+ LOCAL_CLI_SAVE(d3)
+
+ # disable the dcache
+ movhu (a2),d0
+ and ~CHCTR_DCEN,d0
+ movhu d0,(a2)
+
+ # and wait for it to calm down
+ setlb
+ movhu (a2),d0
+ btst CHCTR_DCBUSY,d0
+ lne
+
+mn10300_local_dcache_inv_range_loop:
+
+ # process the way 0 slot
+ mov (L1_CACHE_WAYDISP*0,a0),d0 # read the tag in the way 0 slot
+ btst L1_CACHE_TAG_VALID,d0
+ beq mn10300_local_dcache_inv_range_skip_0 # jump if this cacheline
+ # is not valid
+
+ xor a1,d0
+ lsr 12,d0
+ bne mn10300_local_dcache_inv_range_skip_0 # jump if not this cacheline
+
+ mov d2,(L1_CACHE_WAYDISP*0,a0) # kill the tag
+
+mn10300_local_dcache_inv_range_skip_0:
+
+ # process the way 1 slot
+ mov (L1_CACHE_WAYDISP*1,a0),d0 # read the tag in the way 1 slot
+ btst L1_CACHE_TAG_VALID,d0
+ beq mn10300_local_dcache_inv_range_skip_1 # jump if this cacheline
+ # is not valid
+
+ xor a1,d0
+ lsr 12,d0
+ bne mn10300_local_dcache_inv_range_skip_1 # jump if not this cacheline
+
+ mov d2,(L1_CACHE_WAYDISP*1,a0) # kill the tag
+
+mn10300_local_dcache_inv_range_skip_1:
+
+ # process the way 2 slot
+ mov (L1_CACHE_WAYDISP*2,a0),d0 # read the tag in the way 2 slot
+ btst L1_CACHE_TAG_VALID,d0
+ beq mn10300_local_dcache_inv_range_skip_2 # jump if this cacheline
+ # is not valid
+
+ xor a1,d0
+ lsr 12,d0
+ bne mn10300_local_dcache_inv_range_skip_2 # jump if not this cacheline
+
+ mov d2,(L1_CACHE_WAYDISP*2,a0) # kill the tag
+
+mn10300_local_dcache_inv_range_skip_2:
+
+ # process the way 3 slot
+ mov (L1_CACHE_WAYDISP*3,a0),d0 # read the tag in the way 3 slot
+ btst L1_CACHE_TAG_VALID,d0
+ beq mn10300_local_dcache_inv_range_skip_3 # jump if this cacheline
+ # is not valid
+
+ xor a1,d0
+ lsr 12,d0
+ bne mn10300_local_dcache_inv_range_skip_3 # jump if not this cacheline
+
+ mov d2,(L1_CACHE_WAYDISP*3,a0) # kill the tag
+
+mn10300_local_dcache_inv_range_skip_3:
+
+ # approx every N steps we re-enable the cache and see if there are any
+ # interrupts to be processed
+ # we also break out if we've reached the end of the loop
+ # (the bottom nibble of the count is zero in both cases)
+ add L1_CACHE_BYTES,a0
+ add L1_CACHE_BYTES,a1
+ and ~L1_CACHE_WAYDISP,a0
+ add -1,d1
+ btst mn10300_local_dcache_inv_range_intr_interval,d1
+ bne mn10300_local_dcache_inv_range_loop
+
+ # wait for the cache to finish what it's doing
+ setlb
+ movhu (a2),d0
+ btst CHCTR_DCBUSY,d0
+ lne
+
+ # and reenable it
+ or CHCTR_DCEN,d0
+ movhu d0,(a2)
+ movhu (a2),d0
+
+ # re-enable interrupts
+ # - we don't bother with delay NOPs as we'll have enough instructions
+ # before we disable interrupts again to give the interrupts a chance
+ # to happen
+ LOCAL_IRQ_RESTORE(d3)
+
+ # go around again if the counter hasn't yet reached zero
+ add 0,d1
+ bne mn10300_local_dcache_inv_range_outer_loop
+
+mn10300_local_dcache_inv_range_end:
+ ret [d2,d3,a2],12
+ .size mn10300_local_dcache_inv_page,.-mn10300_local_dcache_inv_page
+ .size mn10300_local_dcache_inv_range,.-mn10300_local_dcache_inv_range
+ .size mn10300_local_dcache_inv_range2,.-mn10300_local_dcache_inv_range2
diff --git a/arch/mn10300/mm/cache-inv-icache.c b/arch/mn10300/mm/cache-inv-icache.c
new file mode 100644
index 000000000000..a8933a60b2d4
--- /dev/null
+++ b/arch/mn10300/mm/cache-inv-icache.c
@@ -0,0 +1,129 @@
+/* Invalidate icache when dcache doesn't need invalidation as it's in
+ * write-through mode
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <asm/cacheflush.h>
+#include <asm/smp.h>
+#include "cache-smp.h"
+
+/**
+ * flush_icache_page_range - Flush dcache and invalidate icache for part of a
+ * single page
+ * @start: The starting virtual address of the page part.
+ * @end: The ending virtual address of the page part.
+ *
+ * Invalidate the icache for part of a single page, as determined by the
+ * virtual addresses given. The page must be in the paged area. The dcache is
+ * not flushed as the cache must be in write-through mode to get here.
+ */
+static void flush_icache_page_range(unsigned long start, unsigned long end)
+{
+ unsigned long addr, size, off;
+ struct page *page;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *ppte, pte;
+
+ /* work out how much of the page to flush */
+ off = start & ~PAGE_MASK;
+ size = end - start;
+
+ /* get the physical address the page is mapped to from the page
+ * tables */
+ pgd = pgd_offset(current->mm, start);
+ if (!pgd || !pgd_val(*pgd))
+ return;
+
+ pud = pud_offset(pgd, start);
+ if (!pud || !pud_val(*pud))
+ return;
+
+ pmd = pmd_offset(pud, start);
+ if (!pmd || !pmd_val(*pmd))
+ return;
+
+ ppte = pte_offset_map(pmd, start);
+ if (!ppte)
+ return;
+ pte = *ppte;
+ pte_unmap(ppte);
+
+ if (pte_none(pte))
+ return;
+
+ page = pte_page(pte);
+ if (!page)
+ return;
+
+ addr = page_to_phys(page);
+
+ /* invalidate the icache coverage on that region */
+ mn10300_local_icache_inv_range2(addr + off, size);
+ smp_cache_call(SMP_ICACHE_INV_FLUSH_RANGE, start, end);
+}
+
+/**
+ * flush_icache_range - Globally flush dcache and invalidate icache for region
+ * @start: The starting virtual address of the region.
+ * @end: The ending virtual address of the region.
+ *
+ * This is used by the kernel to globally flush some code it has just written
+ * from the dcache back to RAM and then to globally invalidate the icache over
+ * that region so that that code can be run on all CPUs in the system.
+ */
+void flush_icache_range(unsigned long start, unsigned long end)
+{
+ unsigned long start_page, end_page;
+ unsigned long flags;
+
+ flags = smp_lock_cache();
+
+ if (end > 0x80000000UL) {
+ /* addresses above 0xa0000000 do not go through the cache */
+ if (end > 0xa0000000UL) {
+ end = 0xa0000000UL;
+ if (start >= end)
+ goto done;
+ }
+
+ /* kernel addresses between 0x80000000 and 0x9fffffff do not
+ * require page tables, so we just map such addresses
+ * directly */
+ start_page = (start >= 0x80000000UL) ? start : 0x80000000UL;
+ mn10300_icache_inv_range(start_page, end);
+ smp_cache_call(SMP_ICACHE_INV_FLUSH_RANGE, start, end);
+ if (start_page == start)
+ goto done;
+ end = start_page;
+ }
+
+ start_page = start & PAGE_MASK;
+ end_page = (end - 1) & PAGE_MASK;
+
+ if (start_page == end_page) {
+ /* the first and last bytes are on the same page */
+ flush_icache_page_range(start, end);
+ } else if (start_page + 1 == end_page) {
+ /* split over two virtually contiguous pages */
+ flush_icache_page_range(start, end_page);
+ flush_icache_page_range(end_page, end);
+ } else {
+ /* more than 2 pages; just flush the entire cache */
+ mn10300_local_icache_inv();
+ smp_cache_call(SMP_ICACHE_INV, 0, 0);
+ }
+
+done:
+ smp_unlock_cache(flags);
+}
+EXPORT_SYMBOL(flush_icache_range);
diff --git a/arch/mn10300/mm/cache-mn10300.S b/arch/mn10300/mm/cache-mn10300.S
deleted file mode 100644
index e839d0aedd69..000000000000
--- a/arch/mn10300/mm/cache-mn10300.S
+++ /dev/null
@@ -1,289 +0,0 @@
-/* MN10300 CPU core caching routines
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-#include <linux/sys.h>
-#include <linux/linkage.h>
-#include <asm/smp.h>
-#include <asm/page.h>
-#include <asm/cache.h>
-
-#define mn10300_dcache_inv_range_intr_interval \
- +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
-
-#if mn10300_dcache_inv_range_intr_interval > 0xff
-#error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less
-#endif
-
- .am33_2
-
- .globl mn10300_icache_inv
- .globl mn10300_dcache_inv
- .globl mn10300_dcache_inv_range
- .globl mn10300_dcache_inv_range2
- .globl mn10300_dcache_inv_page
-
-###############################################################################
-#
-# void mn10300_icache_inv(void)
-# Invalidate the entire icache
-#
-###############################################################################
- ALIGN
-mn10300_icache_inv:
- mov CHCTR,a0
-
- movhu (a0),d0
- btst CHCTR_ICEN,d0
- beq mn10300_icache_inv_end
-
- mov epsw,d1
- and ~EPSW_IE,epsw
- nop
- nop
-
- # disable the icache
- and ~CHCTR_ICEN,d0
- movhu d0,(a0)
-
- # and wait for it to calm down
- setlb
- movhu (a0),d0
- btst CHCTR_ICBUSY,d0
- lne
-
- # invalidate
- or CHCTR_ICINV,d0
- movhu d0,(a0)
-
- # wait for the cache to finish
- mov CHCTR,a0
- setlb
- movhu (a0),d0
- btst CHCTR_ICBUSY,d0
- lne
-
- # and reenable it
- and ~CHCTR_ICINV,d0
- or CHCTR_ICEN,d0
- movhu d0,(a0)
- movhu (a0),d0
-
- mov d1,epsw
-
-mn10300_icache_inv_end:
- ret [],0
-
-###############################################################################
-#
-# void mn10300_dcache_inv(void)
-# Invalidate the entire dcache
-#
-###############################################################################
- ALIGN
-mn10300_dcache_inv:
- mov CHCTR,a0
-
- movhu (a0),d0
- btst CHCTR_DCEN,d0
- beq mn10300_dcache_inv_end
-
- mov epsw,d1
- and ~EPSW_IE,epsw
- nop
- nop
-
- # disable the dcache
- and ~CHCTR_DCEN,d0
- movhu d0,(a0)
-
- # and wait for it to calm down
- setlb
- movhu (a0),d0
- btst CHCTR_DCBUSY,d0
- lne
-
- # invalidate
- or CHCTR_DCINV,d0
- movhu d0,(a0)
-
- # wait for the cache to finish
- mov CHCTR,a0
- setlb
- movhu (a0),d0
- btst CHCTR_DCBUSY,d0
- lne
-
- # and reenable it
- and ~CHCTR_DCINV,d0
- or CHCTR_DCEN,d0
- movhu d0,(a0)
- movhu (a0),d0
-
- mov d1,epsw
-
-mn10300_dcache_inv_end:
- ret [],0
-
-###############################################################################
-#
-# void mn10300_dcache_inv_range(unsigned start, unsigned end)
-# void mn10300_dcache_inv_range2(unsigned start, unsigned size)
-# void mn10300_dcache_inv_page(unsigned start)
-# Invalidate a range of addresses on a page in the dcache
-#
-###############################################################################
- ALIGN
-mn10300_dcache_inv_page:
- mov PAGE_SIZE,d1
-mn10300_dcache_inv_range2:
- add d0,d1
-mn10300_dcache_inv_range:
- movm [d2,d3,a2],(sp)
- mov CHCTR,a2
-
- movhu (a2),d2
- btst CHCTR_DCEN,d2
- beq mn10300_dcache_inv_range_end
-
- and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start
- # addr down
- mov d0,a1
-
- add L1_CACHE_BYTES,d1 # round end addr up
- and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
-
- clr d2 # we're going to clear tag ram
- # entries
-
- # read the tags from the tag RAM, and if they indicate a valid dirty
- # cache line then invalidate that line
- mov DCACHE_TAG(0,0),a0
- mov a1,d0
- and L1_CACHE_TAG_ENTRY,d0
- add d0,a0 # starting dcache tag RAM
- # access address
-
- sub a1,d1
- lsr L1_CACHE_SHIFT,d1 # total number of entries to
- # examine
-
- and ~(L1_CACHE_DISPARITY-1),a1 # determine comparator base
-
-mn10300_dcache_inv_range_outer_loop:
- # disable interrupts
- mov epsw,d3
- and ~EPSW_IE,epsw
- nop # note that reading CHCTR and
- # AND'ing D0 occupy two delay
- # slots after disabling
- # interrupts
-
- # disable the dcache
- movhu (a2),d0
- and ~CHCTR_DCEN,d0
- movhu d0,(a2)
-
- # and wait for it to calm down
- setlb
- movhu (a2),d0
- btst CHCTR_DCBUSY,d0
- lne
-
-mn10300_dcache_inv_range_loop:
-
- # process the way 0 slot
- mov (L1_CACHE_WAYDISP*0,a0),d0 # read the tag in the way 0 slot
- btst L1_CACHE_TAG_VALID,d0
- beq mn10300_dcache_inv_range_skip_0 # jump if this cacheline is not
- # valid
-
- xor a1,d0
- lsr 12,d0
- bne mn10300_dcache_inv_range_skip_0 # jump if not this cacheline
-
- mov d2,(a0) # kill the tag
-
-mn10300_dcache_inv_range_skip_0:
-
- # process the way 1 slot
- mov (L1_CACHE_WAYDISP*1,a0),d0 # read the tag in the way 1 slot
- btst L1_CACHE_TAG_VALID,d0
- beq mn10300_dcache_inv_range_skip_1 # jump if this cacheline is not
- # valid
-
- xor a1,d0
- lsr 12,d0
- bne mn10300_dcache_inv_range_skip_1 # jump if not this cacheline
-
- mov d2,(a0) # kill the tag
-
-mn10300_dcache_inv_range_skip_1:
-
- # process the way 2 slot
- mov (L1_CACHE_WAYDISP*2,a0),d0 # read the tag in the way 2 slot
- btst L1_CACHE_TAG_VALID,d0
- beq mn10300_dcache_inv_range_skip_2 # jump if this cacheline is not
- # valid
-
- xor a1,d0
- lsr 12,d0
- bne mn10300_dcache_inv_range_skip_2 # jump if not this cacheline
-
- mov d2,(a0) # kill the tag
-
-mn10300_dcache_inv_range_skip_2:
-
- # process the way 3 slot
- mov (L1_CACHE_WAYDISP*3,a0),d0 # read the tag in the way 3 slot
- btst L1_CACHE_TAG_VALID,d0
- beq mn10300_dcache_inv_range_skip_3 # jump if this cacheline is not
- # valid
-
- xor a1,d0
- lsr 12,d0
- bne mn10300_dcache_inv_range_skip_3 # jump if not this cacheline
-
- mov d2,(a0) # kill the tag
-
-mn10300_dcache_inv_range_skip_3:
-
- # approx every N steps we re-enable the cache and see if there are any
- # interrupts to be processed
- # we also break out if we've reached the end of the loop
- # (the bottom nibble of the count is zero in both cases)
- add L1_CACHE_BYTES,a0
- add L1_CACHE_BYTES,a1
- add -1,d1
- btst mn10300_dcache_inv_range_intr_interval,d1
- bne mn10300_dcache_inv_range_loop
-
- # wait for the cache to finish what it's doing
- setlb
- movhu (a2),d0
- btst CHCTR_DCBUSY,d0
- lne
-
- # and reenable it
- or CHCTR_DCEN,d0
- movhu d0,(a2)
- movhu (a2),d0
-
- # re-enable interrupts
- # - we don't bother with delay NOPs as we'll have enough instructions
- # before we disable interrupts again to give the interrupts a chance
- # to happen
- mov d3,epsw
-
- # go around again if the counter hasn't yet reached zero
- add 0,d1
- bne mn10300_dcache_inv_range_outer_loop
-
-mn10300_dcache_inv_range_end:
- ret [d2,d3,a2],12
diff --git a/arch/mn10300/mm/cache-smp-flush.c b/arch/mn10300/mm/cache-smp-flush.c
new file mode 100644
index 000000000000..fd51af5eaf70
--- /dev/null
+++ b/arch/mn10300/mm/cache-smp-flush.c
@@ -0,0 +1,156 @@
+/* Functions for global dcache flush when writeback caching in SMP
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/mm.h>
+#include <asm/cacheflush.h>
+#include "cache-smp.h"
+
+/**
+ * mn10300_dcache_flush - Globally flush data cache
+ *
+ * Flush the data cache on all CPUs.
+ */
+void mn10300_dcache_flush(void)
+{
+ unsigned long flags;
+
+ flags = smp_lock_cache();
+ mn10300_local_dcache_flush();
+ smp_cache_call(SMP_DCACHE_FLUSH, 0, 0);
+ smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_flush_page - Globally flush a page of data cache
+ * @start: The address of the page of memory to be flushed.
+ *
+ * Flush a range of addresses in the data cache on all CPUs covering
+ * the page that includes the given address.
+ */
+void mn10300_dcache_flush_page(unsigned long start)
+{
+ unsigned long flags;
+
+ start &= ~(PAGE_SIZE-1);
+
+ flags = smp_lock_cache();
+ mn10300_local_dcache_flush_page(start);
+ smp_cache_call(SMP_DCACHE_FLUSH_RANGE, start, start + PAGE_SIZE);
+ smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_flush_range - Globally flush range of data cache
+ * @start: The start address of the region to be flushed.
+ * @end: The end address of the region to be flushed.
+ *
+ * Flush a range of addresses in the data cache on all CPUs, between start and
+ * end-1 inclusive.
+ */
+void mn10300_dcache_flush_range(unsigned long start, unsigned long end)
+{
+ unsigned long flags;
+
+ flags = smp_lock_cache();
+ mn10300_local_dcache_flush_range(start, end);
+ smp_cache_call(SMP_DCACHE_FLUSH_RANGE, start, end);
+ smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_flush_range2 - Globally flush range of data cache
+ * @start: The start address of the region to be flushed.
+ * @size: The size of the region to be flushed.
+ *
+ * Flush a range of addresses in the data cache on all CPUs, between start and
+ * start+size-1 inclusive.
+ */
+void mn10300_dcache_flush_range2(unsigned long start, unsigned long size)
+{
+ unsigned long flags;
+
+ flags = smp_lock_cache();
+ mn10300_local_dcache_flush_range2(start, size);
+ smp_cache_call(SMP_DCACHE_FLUSH_RANGE, start, start + size);
+ smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_flush_inv - Globally flush and invalidate data cache
+ *
+ * Flush and invalidate the data cache on all CPUs.
+ */
+void mn10300_dcache_flush_inv(void)
+{
+ unsigned long flags;
+
+ flags = smp_lock_cache();
+ mn10300_local_dcache_flush_inv();
+ smp_cache_call(SMP_DCACHE_FLUSH_INV, 0, 0);
+ smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_flush_inv_page - Globally flush and invalidate a page of data
+ * cache
+ * @start: The address of the page of memory to be flushed and invalidated.
+ *
+ * Flush and invalidate a range of addresses in the data cache on all CPUs
+ * covering the page that includes the given address.
+ */
+void mn10300_dcache_flush_inv_page(unsigned long start)
+{
+ unsigned long flags;
+
+ start &= ~(PAGE_SIZE-1);
+
+ flags = smp_lock_cache();
+ mn10300_local_dcache_flush_inv_page(start);
+ smp_cache_call(SMP_DCACHE_FLUSH_INV_RANGE, start, start + PAGE_SIZE);
+ smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_flush_inv_range - Globally flush and invalidate range of data
+ * cache
+ * @start: The start address of the region to be flushed and invalidated.
+ * @end: The end address of the region to be flushed and invalidated.
+ *
+ * Flush and invalidate a range of addresses in the data cache on all CPUs,
+ * between start and end-1 inclusive.
+ */
+void mn10300_dcache_flush_inv_range(unsigned long start, unsigned long end)
+{
+ unsigned long flags;
+
+ flags = smp_lock_cache();
+ mn10300_local_dcache_flush_inv_range(start, end);
+ smp_cache_call(SMP_DCACHE_FLUSH_INV_RANGE, start, end);
+ smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_flush_inv_range2 - Globally flush and invalidate range of data
+ * cache
+ * @start: The start address of the region to be flushed and invalidated.
+ * @size: The size of the region to be flushed and invalidated.
+ *
+ * Flush and invalidate a range of addresses in the data cache on all CPUs,
+ * between start and start+size-1 inclusive.
+ */
+void mn10300_dcache_flush_inv_range2(unsigned long start, unsigned long size)
+{
+ unsigned long flags;
+
+ flags = smp_lock_cache();
+ mn10300_local_dcache_flush_inv_range2(start, size);
+ smp_cache_call(SMP_DCACHE_FLUSH_INV_RANGE, start, start + size);
+ smp_unlock_cache(flags);
+}
diff --git a/arch/mn10300/mm/cache-smp-inv.c b/arch/mn10300/mm/cache-smp-inv.c
new file mode 100644
index 000000000000..ff1787358c8e
--- /dev/null
+++ b/arch/mn10300/mm/cache-smp-inv.c
@@ -0,0 +1,153 @@
+/* Functions for global i/dcache invalidation when caching in SMP
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/mm.h>
+#include <asm/cacheflush.h>
+#include "cache-smp.h"
+
+/**
+ * mn10300_icache_inv - Globally invalidate instruction cache
+ *
+ * Invalidate the instruction cache on all CPUs.
+ */
+void mn10300_icache_inv(void)
+{
+ unsigned long flags;
+
+ flags = smp_lock_cache();
+ mn10300_local_icache_inv();
+ smp_cache_call(SMP_ICACHE_INV, 0, 0);
+ smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_icache_inv_page - Globally invalidate a page of instruction cache
+ * @start: The address of the page of memory to be invalidated.
+ *
+ * Invalidate a range of addresses in the instruction cache on all CPUs
+ * covering the page that includes the given address.
+ */
+void mn10300_icache_inv_page(unsigned long start)
+{
+ unsigned long flags;
+
+ start &= ~(PAGE_SIZE-1);
+
+ flags = smp_lock_cache();
+ mn10300_local_icache_inv_page(start);
+ smp_cache_call(SMP_ICACHE_INV_RANGE, start, start + PAGE_SIZE);
+ smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_icache_inv_range - Globally invalidate range of instruction cache
+ * @start: The start address of the region to be invalidated.
+ * @end: The end address of the region to be invalidated.
+ *
+ * Invalidate a range of addresses in the instruction cache on all CPUs,
+ * between start and end-1 inclusive.
+ */
+void mn10300_icache_inv_range(unsigned long start, unsigned long end)
+{
+ unsigned long flags;
+
+ flags = smp_lock_cache();
+ mn10300_local_icache_inv_range(start, end);
+ smp_cache_call(SMP_ICACHE_INV_RANGE, start, end);
+ smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_icache_inv_range2 - Globally invalidate range of instruction cache
+ * @start: The start address of the region to be invalidated.
+ * @size: The size of the region to be invalidated.
+ *
+ * Invalidate a range of addresses in the instruction cache on all CPUs,
+ * between start and start+size-1 inclusive.
+ */
+void mn10300_icache_inv_range2(unsigned long start, unsigned long size)
+{
+ unsigned long flags;
+
+ flags = smp_lock_cache();
+ mn10300_local_icache_inv_range2(start, size);
+ smp_cache_call(SMP_ICACHE_INV_RANGE, start, start + size);
+ smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_inv - Globally invalidate data cache
+ *
+ * Invalidate the data cache on all CPUs.
+ */
+void mn10300_dcache_inv(void)
+{
+ unsigned long flags;
+
+ flags = smp_lock_cache();
+ mn10300_local_dcache_inv();
+ smp_cache_call(SMP_DCACHE_INV, 0, 0);
+ smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_inv_page - Globally invalidate a page of data cache
+ * @start: The address of the page of memory to be invalidated.
+ *
+ * Invalidate a range of addresses in the data cache on all CPUs covering the
+ * page that includes the given address.
+ */
+void mn10300_dcache_inv_page(unsigned long start)
+{
+ unsigned long flags;
+
+ start &= ~(PAGE_SIZE-1);
+
+ flags = smp_lock_cache();
+ mn10300_local_dcache_inv_page(start);
+ smp_cache_call(SMP_DCACHE_INV_RANGE, start, start + PAGE_SIZE);
+ smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_inv_range - Globally invalidate range of data cache
+ * @start: The start address of the region to be invalidated.
+ * @end: The end address of the region to be invalidated.
+ *
+ * Invalidate a range of addresses in the data cache on all CPUs, between start
+ * and end-1 inclusive.
+ */
+void mn10300_dcache_inv_range(unsigned long start, unsigned long end)
+{
+ unsigned long flags;
+
+ flags = smp_lock_cache();
+ mn10300_local_dcache_inv_range(start, end);
+ smp_cache_call(SMP_DCACHE_INV_RANGE, start, end);
+ smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_inv_range2 - Globally invalidate range of data cache
+ * @start: The start address of the region to be invalidated.
+ * @size: The size of the region to be invalidated.
+ *
+ * Invalidate a range of addresses in the data cache on all CPUs, between start
+ * and start+size-1 inclusive.
+ */
+void mn10300_dcache_inv_range2(unsigned long start, unsigned long size)
+{
+ unsigned long flags;
+
+ flags = smp_lock_cache();
+ mn10300_local_dcache_inv_range2(start, size);
+ smp_cache_call(SMP_DCACHE_INV_RANGE, start, start + size);
+ smp_unlock_cache(flags);
+}
diff --git a/arch/mn10300/mm/cache-smp.c b/arch/mn10300/mm/cache-smp.c
new file mode 100644
index 000000000000..4a6e9a4b5b27
--- /dev/null
+++ b/arch/mn10300/mm/cache-smp.c
@@ -0,0 +1,105 @@
+/* SMP global caching code
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/threads.h>
+#include <linux/interrupt.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/smp.h>
+#include "cache-smp.h"
+
+DEFINE_SPINLOCK(smp_cache_lock);
+static unsigned long smp_cache_mask;
+static unsigned long smp_cache_start;
+static unsigned long smp_cache_end;
+static cpumask_t smp_cache_ipi_map; /* Bitmask of cache IPI done CPUs */
+
+/**
+ * smp_cache_interrupt - Handle IPI request to flush caches.
+ *
+ * Handle a request delivered by IPI to flush the current CPU's
+ * caches. The parameters are stored in smp_cache_*.
+ */
+void smp_cache_interrupt(void)
+{
+ unsigned long opr_mask = smp_cache_mask;
+
+ switch ((enum smp_dcache_ops)(opr_mask & SMP_DCACHE_OP_MASK)) {
+ case SMP_DCACHE_NOP:
+ break;
+ case SMP_DCACHE_INV:
+ mn10300_local_dcache_inv();
+ break;
+ case SMP_DCACHE_INV_RANGE:
+ mn10300_local_dcache_inv_range(smp_cache_start, smp_cache_end);
+ break;
+ case SMP_DCACHE_FLUSH:
+ mn10300_local_dcache_flush();
+ break;
+ case SMP_DCACHE_FLUSH_RANGE:
+ mn10300_local_dcache_flush_range(smp_cache_start,
+ smp_cache_end);
+ break;
+ case SMP_DCACHE_FLUSH_INV:
+ mn10300_local_dcache_flush_inv();
+ break;
+ case SMP_DCACHE_FLUSH_INV_RANGE:
+ mn10300_local_dcache_flush_inv_range(smp_cache_start,
+ smp_cache_end);
+ break;
+ }
+
+ switch ((enum smp_icache_ops)(opr_mask & SMP_ICACHE_OP_MASK)) {
+ case SMP_ICACHE_NOP:
+ break;
+ case SMP_ICACHE_INV:
+ mn10300_local_icache_inv();
+ break;
+ case SMP_ICACHE_INV_RANGE:
+ mn10300_local_icache_inv_range(smp_cache_start, smp_cache_end);
+ break;
+ }
+
+ cpu_clear(smp_processor_id(), smp_cache_ipi_map);
+}
+
+/**
+ * smp_cache_call - Issue an IPI to request the other CPUs flush caches
+ * @opr_mask: Cache operation flags
+ * @start: Start address of request
+ * @end: End address of request
+ *
+ * Send cache flush IPI to other CPUs. This invokes smp_cache_interrupt()
+ * above on those other CPUs and then waits for them to finish.
+ *
+ * The caller must hold smp_cache_lock.
+ */
+void smp_cache_call(unsigned long opr_mask,
+ unsigned long start, unsigned long end)
+{
+ smp_cache_mask = opr_mask;
+ smp_cache_start = start;
+ smp_cache_end = end;
+ smp_cache_ipi_map = cpu_online_map;
+ cpu_clear(smp_processor_id(), smp_cache_ipi_map);
+
+ send_IPI_allbutself(FLUSH_CACHE_IPI);
+
+ while (!cpus_empty(smp_cache_ipi_map))
+ /* nothing. lockup detection does not belong here */
+ mb();
+}
diff --git a/arch/mn10300/mm/cache-smp.h b/arch/mn10300/mm/cache-smp.h
new file mode 100644
index 000000000000..cb52892aa66a
--- /dev/null
+++ b/arch/mn10300/mm/cache-smp.h
@@ -0,0 +1,69 @@
+/* SMP caching definitions
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+
+/*
+ * Operation requests for smp_cache_call().
+ *
+ * One of smp_icache_ops and one of smp_dcache_ops can be OR'd together.
+ */
+enum smp_icache_ops {
+ SMP_ICACHE_NOP = 0x0000,
+ SMP_ICACHE_INV = 0x0001,
+ SMP_ICACHE_INV_RANGE = 0x0002,
+};
+#define SMP_ICACHE_OP_MASK 0x0003
+
+enum smp_dcache_ops {
+ SMP_DCACHE_NOP = 0x0000,
+ SMP_DCACHE_INV = 0x0004,
+ SMP_DCACHE_INV_RANGE = 0x0008,
+ SMP_DCACHE_FLUSH = 0x000c,
+ SMP_DCACHE_FLUSH_RANGE = 0x0010,
+ SMP_DCACHE_FLUSH_INV = 0x0014,
+ SMP_DCACHE_FLUSH_INV_RANGE = 0x0018,
+};
+#define SMP_DCACHE_OP_MASK 0x001c
+
+#define SMP_IDCACHE_INV_FLUSH (SMP_ICACHE_INV | SMP_DCACHE_FLUSH)
+#define SMP_IDCACHE_INV_FLUSH_RANGE (SMP_ICACHE_INV_RANGE | SMP_DCACHE_FLUSH_RANGE)
+
+/*
+ * cache-smp.c
+ */
+#ifdef CONFIG_SMP
+extern spinlock_t smp_cache_lock;
+
+extern void smp_cache_call(unsigned long opr_mask,
+ unsigned long addr, unsigned long end);
+
+static inline unsigned long smp_lock_cache(void)
+ __acquires(&smp_cache_lock)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&smp_cache_lock, flags);
+ return flags;
+}
+
+static inline void smp_unlock_cache(unsigned long flags)
+ __releases(&smp_cache_lock)
+{
+ spin_unlock_irqrestore(&smp_cache_lock, flags);
+}
+
+#else
+static inline unsigned long smp_lock_cache(void) { return 0; }
+static inline void smp_unlock_cache(unsigned long flags) {}
+static inline void smp_cache_call(unsigned long opr_mask,
+ unsigned long addr, unsigned long end)
+{
+}
+#endif /* CONFIG_SMP */
diff --git a/arch/mn10300/mm/cache.c b/arch/mn10300/mm/cache.c
index 9261217e8d2c..0a1f0aa92ebc 100644
--- a/arch/mn10300/mm/cache.c
+++ b/arch/mn10300/mm/cache.c
@@ -18,8 +18,13 @@
#include <asm/cacheflush.h>
#include <asm/io.h>
#include <asm/uaccess.h>
+#include <asm/smp.h>
+#include "cache-smp.h"
EXPORT_SYMBOL(mn10300_icache_inv);
+EXPORT_SYMBOL(mn10300_icache_inv_range);
+EXPORT_SYMBOL(mn10300_icache_inv_range2);
+EXPORT_SYMBOL(mn10300_icache_inv_page);
EXPORT_SYMBOL(mn10300_dcache_inv);
EXPORT_SYMBOL(mn10300_dcache_inv_range);
EXPORT_SYMBOL(mn10300_dcache_inv_range2);
@@ -37,96 +42,6 @@ EXPORT_SYMBOL(mn10300_dcache_flush_page);
#endif
/*
- * write a page back from the dcache and invalidate the icache so that we can
- * run code from it that we've just written into it
- */
-void flush_icache_page(struct vm_area_struct *vma, struct page *page)
-{
- mn10300_dcache_flush_page(page_to_phys(page));
- mn10300_icache_inv();
-}
-EXPORT_SYMBOL(flush_icache_page);
-
-/*
- * write some code we've just written back from the dcache and invalidate the
- * icache so that we can run that code
- */
-void flush_icache_range(unsigned long start, unsigned long end)
-{
-#ifdef CONFIG_MN10300_CACHE_WBACK
- unsigned long addr, size, base, off;
- struct page *page;
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *ppte, pte;
-
- if (end > 0x80000000UL) {
- /* addresses above 0xa0000000 do not go through the cache */
- if (end > 0xa0000000UL) {
- end = 0xa0000000UL;
- if (start >= end)
- return;
- }
-
- /* kernel addresses between 0x80000000 and 0x9fffffff do not
- * require page tables, so we just map such addresses directly */
- base = (start >= 0x80000000UL) ? start : 0x80000000UL;
- mn10300_dcache_flush_range(base, end);
- if (base == start)
- goto invalidate;
- end = base;
- }
-
- for (; start < end; start += size) {
- /* work out how much of the page to flush */
- off = start & (PAGE_SIZE - 1);
-
- size = end - start;
- if (size > PAGE_SIZE - off)
- size = PAGE_SIZE - off;
-
- /* get the physical address the page is mapped to from the page
- * tables */
- pgd = pgd_offset(current->mm, start);
- if (!pgd || !pgd_val(*pgd))
- continue;
-
- pud = pud_offset(pgd, start);
- if (!pud || !pud_val(*pud))
- continue;
-
- pmd = pmd_offset(pud, start);
- if (!pmd || !pmd_val(*pmd))
- continue;
-
- ppte = pte_offset_map(pmd, start);
- if (!ppte)
- continue;
- pte = *ppte;
- pte_unmap(ppte);
-
- if (pte_none(pte))
- continue;
-
- page = pte_page(pte);
- if (!page)
- continue;
-
- addr = page_to_phys(page);
-
- /* flush the dcache and invalidate the icache coverage on that
- * region */
- mn10300_dcache_flush_range2(addr + off, size);
- }
-#endif
-
-invalidate:
- mn10300_icache_inv();
-}
-EXPORT_SYMBOL(flush_icache_range);
-
-/*
* allow userspace to flush the instruction cache
*/
asmlinkage long sys_cacheflush(unsigned long start, unsigned long end)
diff --git a/arch/mn10300/mm/fault.c b/arch/mn10300/mm/fault.c
index 81f153fa51b4..59c3da49d9d9 100644
--- a/arch/mn10300/mm/fault.c
+++ b/arch/mn10300/mm/fault.c
@@ -39,10 +39,6 @@ void bust_spinlocks(int yes)
{
if (yes) {
oops_in_progress = 1;
-#ifdef CONFIG_SMP
- /* Many serial drivers do __global_cli() */
- global_irq_lock = 0;
-#endif
} else {
int loglevel_save = console_loglevel;
#ifdef CONFIG_VT
@@ -100,8 +96,6 @@ static void print_pagetable_entries(pgd_t *pgdir, unsigned long address)
}
#endif
-asmlinkage void monitor_signal(struct pt_regs *);
-
/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
@@ -279,7 +273,6 @@ good_area:
*/
bad_area:
up_read(&mm->mmap_sem);
- monitor_signal(regs);
/* User mode accesses just cause a SIGSEGV */
if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR) {
@@ -292,7 +285,6 @@ bad_area:
}
no_context:
- monitor_signal(regs);
/* Are we prepared to handle this kernel fault? */
if (fixup_exception(regs))
return;
@@ -338,14 +330,13 @@ no_context:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if ((fault_code & MMUFCR_xFC_ACCESS) != MMUFCR_xFC_ACCESS_USR)
- goto no_context;
- pagefault_out_of_memory();
- return;
+ printk(KERN_ALERT "VM: killing process %s\n", tsk->comm);
+ if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR)
+ do_exit(SIGKILL);
+ goto no_context;
do_sigbus:
up_read(&mm->mmap_sem);
- monitor_signal(regs);
/*
* Send a sigbus, regardless of whether we were in kernel
diff --git a/arch/mn10300/mm/init.c b/arch/mn10300/mm/init.c
index 6e6bc0e51521..48907cc3bdb7 100644
--- a/arch/mn10300/mm/init.c
+++ b/arch/mn10300/mm/init.c
@@ -41,6 +41,10 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
unsigned long highstart_pfn, highend_pfn;
+#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+static struct vm_struct user_iomap_vm;
+#endif
+
/*
* set up paging
*/
@@ -73,7 +77,24 @@ void __init paging_init(void)
/* pass the memory from the bootmem allocator to the main allocator */
free_area_init(zones_size);
- __flush_tlb_all();
+#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+ /* The Atomic Operation Unit registers need to be mapped to userspace
+ * for all processes. The following uses vm_area_register_early() to
+ * reserve the first page of the vmalloc area and sets the pte for that
+ * page.
+ *
+ * glibc hardcodes this virtual mapping, so we're pretty much stuck with
+ * it from now on.
+ */
+ user_iomap_vm.flags = VM_USERMAP;
+ user_iomap_vm.size = 1 << PAGE_SHIFT;
+ vm_area_register_early(&user_iomap_vm, PAGE_SIZE);
+ ppte = kernel_vmalloc_ptes;
+ set_pte(ppte, pfn_pte(USER_ATOMIC_OPS_PAGE_ADDR >> PAGE_SHIFT,
+ PAGE_USERIO));
+#endif
+
+ local_flush_tlb_all();
}
/*
@@ -84,8 +105,7 @@ void __init mem_init(void)
int codesize, reservedpages, datasize, initsize;
int tmp;
- if (!mem_map)
- BUG();
+ BUG_ON(!mem_map);
#define START_PFN (contig_page_data.bdata->node_min_pfn)
#define MAX_LOW_PFN (contig_page_data.bdata->node_low_pfn)
diff --git a/arch/mn10300/mm/misalignment.c b/arch/mn10300/mm/misalignment.c
index 6dffbf97ac26..eef989c1d0c1 100644
--- a/arch/mn10300/mm/misalignment.c
+++ b/arch/mn10300/mm/misalignment.c
@@ -449,8 +449,7 @@ found_opcode:
regs->pc, opcode, pop->opcode, pop->params[0], pop->params[1]);
tmp = format_tbl[pop->format].opsz;
- if (tmp > noc)
- BUG(); /* match was less complete than it ought to have been */
+ BUG_ON(tmp > noc); /* match was less complete than it ought to have been */
if (tmp < noc) {
tmp = noc - tmp;
diff --git a/arch/mn10300/mm/mmu-context.c b/arch/mn10300/mm/mmu-context.c
index 36ba02191d40..a4f7d3dcc6e6 100644
--- a/arch/mn10300/mm/mmu-context.c
+++ b/arch/mn10300/mm/mmu-context.c
@@ -13,40 +13,15 @@
#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
+#ifdef CONFIG_MN10300_TLB_USE_PIDR
/*
* list of the MMU contexts last allocated on each CPU
*/
unsigned long mmu_context_cache[NR_CPUS] = {
- [0 ... NR_CPUS - 1] = MMU_CONTEXT_FIRST_VERSION * 2 - 1,
+ [0 ... NR_CPUS - 1] =
+ MMU_CONTEXT_FIRST_VERSION * 2 - (1 - MMU_CONTEXT_TLBPID_LOCK_NR),
};
-
-/*
- * flush the specified TLB entry
- */
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
-{
- unsigned long pteu, cnx, flags;
-
- addr &= PAGE_MASK;
-
- /* make sure the context doesn't migrate and defend against
- * interference from vmalloc'd regions */
- local_irq_save(flags);
-
- cnx = mm_context(vma->vm_mm);
-
- if (cnx != MMU_NO_CONTEXT) {
- pteu = addr | (cnx & 0x000000ffUL);
- IPTEU = pteu;
- DPTEU = pteu;
- if (IPTEL & xPTEL_V)
- IPTEL = 0;
- if (DPTEL & xPTEL_V)
- DPTEL = 0;
- }
-
- local_irq_restore(flags);
-}
+#endif /* CONFIG_MN10300_TLB_USE_PIDR */
/*
* preemptively set a TLB entry
@@ -63,10 +38,16 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t *pte
* interference from vmalloc'd regions */
local_irq_save(flags);
+ cnx = ~MMU_NO_CONTEXT;
+#ifdef CONFIG_MN10300_TLB_USE_PIDR
cnx = mm_context(vma->vm_mm);
+#endif
if (cnx != MMU_NO_CONTEXT) {
- pteu = addr | (cnx & 0x000000ffUL);
+ pteu = addr;
+#ifdef CONFIG_MN10300_TLB_USE_PIDR
+ pteu |= cnx & MMU_CONTEXT_TLBPID_MASK;
+#endif
if (!(pte_val(pte) & _PAGE_NX)) {
IPTEU = pteu;
if (IPTEL & xPTEL_V)
diff --git a/arch/mn10300/mm/pgtable.c b/arch/mn10300/mm/pgtable.c
index 9c1624c9e4e9..450f7ba3f8f2 100644
--- a/arch/mn10300/mm/pgtable.c
+++ b/arch/mn10300/mm/pgtable.c
@@ -59,7 +59,7 @@ void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
* It's enough to flush this one mapping.
* (PGE mappings get flushed as well)
*/
- __flush_tlb_one(vaddr);
+ local_flush_tlb_one(vaddr);
}
pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
diff --git a/arch/mn10300/mm/tlb-mn10300.S b/arch/mn10300/mm/tlb-mn10300.S
index 7095147dcb8b..b9940177d81b 100644
--- a/arch/mn10300/mm/tlb-mn10300.S
+++ b/arch/mn10300/mm/tlb-mn10300.S
@@ -27,7 +27,6 @@
###############################################################################
.type itlb_miss,@function
ENTRY(itlb_miss)
- and ~EPSW_NMID,epsw
#ifdef CONFIG_GDBSTUB
movm [d2,d3,a2],(sp)
#else
@@ -38,6 +37,12 @@ ENTRY(itlb_miss)
nop
#endif
+#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR)
+ mov (MMUCTR),d2
+ mov d2,(MMUCTR)
+#endif
+
+ and ~EPSW_NMID,epsw
mov (IPTEU),d3
mov (PTBR),a2
mov d3,d2
@@ -56,10 +61,16 @@ ENTRY(itlb_miss)
btst _PAGE_VALID,d2
beq itlb_miss_fault # jump if doesn't point to a page
# (might be a swap id)
+#if ((_PAGE_ACCESSED & 0xffffff00) == 0)
bset _PAGE_ACCESSED,(0,a2)
- and ~(xPTEL_UNUSED1|xPTEL_UNUSED2),d2
+#elif ((_PAGE_ACCESSED & 0xffff00ff) == 0)
+ bset +(_PAGE_ACCESSED >> 8),(1,a2)
+#else
+#error "_PAGE_ACCESSED value is out of range"
+#endif
+ and ~xPTEL2_UNUSED1,d2
itlb_miss_set:
- mov d2,(IPTEL) # change the TLB
+ mov d2,(IPTEL2) # change the TLB
#ifdef CONFIG_GDBSTUB
movm (sp),[d2,d3,a2]
#endif
@@ -79,7 +90,6 @@ itlb_miss_fault:
###############################################################################
.type dtlb_miss,@function
ENTRY(dtlb_miss)
- and ~EPSW_NMID,epsw
#ifdef CONFIG_GDBSTUB
movm [d2,d3,a2],(sp)
#else
@@ -90,6 +100,12 @@ ENTRY(dtlb_miss)
nop
#endif
+#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR)
+ mov (MMUCTR),d2
+ mov d2,(MMUCTR)
+#endif
+
+ and ~EPSW_NMID,epsw
mov (DPTEU),d3
mov (PTBR),a2
mov d3,d2
@@ -108,10 +124,16 @@ ENTRY(dtlb_miss)
btst _PAGE_VALID,d2
beq dtlb_miss_fault # jump if doesn't point to a page
# (might be a swap id)
+#if ((_PAGE_ACCESSED & 0xffffff00) == 0)
bset _PAGE_ACCESSED,(0,a2)
- and ~(xPTEL_UNUSED1|xPTEL_UNUSED2),d2
+#elif ((_PAGE_ACCESSED & 0xffff00ff) == 0)
+ bset +(_PAGE_ACCESSED >> 8),(1,a2)
+#else
+#error "_PAGE_ACCESSED value is out of range"
+#endif
+ and ~xPTEL2_UNUSED1,d2
dtlb_miss_set:
- mov d2,(DPTEL) # change the TLB
+ mov d2,(DPTEL2) # change the TLB
#ifdef CONFIG_GDBSTUB
movm (sp),[d2,d3,a2]
#endif
@@ -130,9 +152,15 @@ dtlb_miss_fault:
###############################################################################
.type itlb_aerror,@function
ENTRY(itlb_aerror)
- and ~EPSW_NMID,epsw
add -4,sp
SAVE_ALL
+
+#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR)
+ mov (MMUCTR),d1
+ mov d1,(MMUCTR)
+#endif
+
+ and ~EPSW_NMID,epsw
add -4,sp # need to pass three params
# calculate the fault code
@@ -140,15 +168,13 @@ ENTRY(itlb_aerror)
or 0x00010000,d1 # it's an instruction fetch
# determine the page address
- mov (IPTEU),a2
- mov a2,d0
+ mov (IPTEU),d0
and PAGE_MASK,d0
mov d0,(12,sp)
clr d0
- mov d0,(IPTEL)
+ mov d0,(IPTEL2)
- and ~EPSW_NMID,epsw
or EPSW_IE,epsw
mov fp,d0
call do_page_fault[],0 # do_page_fault(regs,code,addr
@@ -163,10 +189,16 @@ ENTRY(itlb_aerror)
###############################################################################
.type dtlb_aerror,@function
ENTRY(dtlb_aerror)
- and ~EPSW_NMID,epsw
add -4,sp
SAVE_ALL
+
+#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR)
+ mov (MMUCTR),d1
+ mov d1,(MMUCTR)
+#endif
+
add -4,sp # need to pass three params
+ and ~EPSW_NMID,epsw
# calculate the fault code
movhu (MMUFCR_DFC),d1
@@ -178,9 +210,8 @@ ENTRY(dtlb_aerror)
mov d0,(12,sp)
clr d0
- mov d0,(DPTEL)
+ mov d0,(DPTEL2)
- and ~EPSW_NMID,epsw
or EPSW_IE,epsw
mov fp,d0
call do_page_fault[],0 # do_page_fault(regs,code,addr
diff --git a/arch/mn10300/mm/tlb-smp.c b/arch/mn10300/mm/tlb-smp.c
new file mode 100644
index 000000000000..0b6a5ad1960e
--- /dev/null
+++ b/arch/mn10300/mm/tlb-smp.c
@@ -0,0 +1,214 @@
+/* SMP TLB support routines.
+ *
+ * Copyright (C) 2006-2008 Panasonic Corporation
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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.
+ */
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/cpumask.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/profile.h>
+#include <linux/smp.h>
+#include <asm/tlbflush.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/processor.h>
+#include <asm/bug.h>
+#include <asm/exceptions.h>
+#include <asm/hardirq.h>
+#include <asm/fpu.h>
+#include <asm/mmu_context.h>
+#include <asm/thread_info.h>
+#include <asm/cpu-regs.h>
+#include <asm/intctl-regs.h>
+
+/*
+ * For flush TLB
+ */
+#define FLUSH_ALL 0xffffffff
+
+static cpumask_t flush_cpumask;
+static struct mm_struct *flush_mm;
+static unsigned long flush_va;
+static DEFINE_SPINLOCK(tlbstate_lock);
+
+DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate) = {
+ &init_mm, 0
+};
+
+static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
+ unsigned long va);
+static void do_flush_tlb_all(void *info);
+
+/**
+ * smp_flush_tlb - Callback to invalidate the TLB.
+ * @unused: Callback context (ignored).
+ */
+void smp_flush_tlb(void *unused)
+{
+ unsigned long cpu_id;
+
+ cpu_id = get_cpu();
+
+ if (!cpu_isset(cpu_id, flush_cpumask))
+ /* This was a BUG() but until someone can quote me the line
+ * from the intel manual that guarantees an IPI to multiple
+ * CPUs is retried _only_ on the erroring CPUs its staying as a
+ * return
+ *
+ * BUG();
+ */
+ goto out;
+
+ if (flush_va == FLUSH_ALL)
+ local_flush_tlb();
+ else
+ local_flush_tlb_page(flush_mm, flush_va);
+
+ smp_mb__before_clear_bit();
+ cpu_clear(cpu_id, flush_cpumask);
+ smp_mb__after_clear_bit();
+out:
+ put_cpu();
+}
+
+/**
+ * flush_tlb_others - Tell the specified CPUs to invalidate their TLBs
+ * @cpumask: The list of CPUs to target.
+ * @mm: The VM context to flush from (if va!=FLUSH_ALL).
+ * @va: Virtual address to flush or FLUSH_ALL to flush everything.
+ */
+static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
+ unsigned long va)
+{
+ cpumask_t tmp;
+
+ /* A couple of sanity checks (to be removed):
+ * - mask must not be empty
+ * - current CPU must not be in mask
+ * - we do not send IPIs to as-yet unbooted CPUs.
+ */
+ BUG_ON(!mm);
+ BUG_ON(cpus_empty(cpumask));
+ BUG_ON(cpu_isset(smp_processor_id(), cpumask));
+
+ cpus_and(tmp, cpumask, cpu_online_map);
+ BUG_ON(!cpus_equal(cpumask, tmp));
+
+ /* I'm not happy about this global shared spinlock in the MM hot path,
+ * but we'll see how contended it is.
+ *
+ * Temporarily this turns IRQs off, so that lockups are detected by the
+ * NMI watchdog.
+ */
+ spin_lock(&tlbstate_lock);
+
+ flush_mm = mm;
+ flush_va = va;
+#if NR_CPUS <= BITS_PER_LONG
+ atomic_set_mask(cpumask.bits[0], &flush_cpumask.bits[0]);
+#else
+#error Not supported.
+#endif
+
+ /* FIXME: if NR_CPUS>=3, change send_IPI_mask */
+ smp_call_function(smp_flush_tlb, NULL, 1);
+
+ while (!cpus_empty(flush_cpumask))
+ /* Lockup detection does not belong here */
+ smp_mb();
+
+ flush_mm = NULL;
+ flush_va = 0;
+ spin_unlock(&tlbstate_lock);
+}
+
+/**
+ * flush_tlb_mm - Invalidate TLB of specified VM context
+ * @mm: The VM context to invalidate.
+ */
+void flush_tlb_mm(struct mm_struct *mm)
+{
+ cpumask_t cpu_mask;
+
+ preempt_disable();
+ cpu_mask = mm->cpu_vm_mask;
+ cpu_clear(smp_processor_id(), cpu_mask);
+
+ local_flush_tlb();
+ if (!cpus_empty(cpu_mask))
+ flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+
+ preempt_enable();
+}
+
+/**
+ * flush_tlb_current_task - Invalidate TLB of current task
+ */
+void flush_tlb_current_task(void)
+{
+ struct mm_struct *mm = current->mm;
+ cpumask_t cpu_mask;
+
+ preempt_disable();
+ cpu_mask = mm->cpu_vm_mask;
+ cpu_clear(smp_processor_id(), cpu_mask);
+
+ local_flush_tlb();
+ if (!cpus_empty(cpu_mask))
+ flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+
+ preempt_enable();
+}
+
+/**
+ * flush_tlb_page - Invalidate TLB of page
+ * @vma: The VM context to invalidate the page for.
+ * @va: The virtual address of the page to invalidate.
+ */
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
+{
+ struct mm_struct *mm = vma->vm_mm;
+ cpumask_t cpu_mask;
+
+ preempt_disable();
+ cpu_mask = mm->cpu_vm_mask;
+ cpu_clear(smp_processor_id(), cpu_mask);
+
+ local_flush_tlb_page(mm, va);
+ if (!cpus_empty(cpu_mask))
+ flush_tlb_others(cpu_mask, mm, va);
+
+ preempt_enable();
+}
+
+/**
+ * do_flush_tlb_all - Callback to completely invalidate a TLB
+ * @unused: Callback context (ignored).
+ */
+static void do_flush_tlb_all(void *unused)
+{
+ local_flush_tlb_all();
+}
+
+/**
+ * flush_tlb_all - Completely invalidate TLBs on all CPUs
+ */
+void flush_tlb_all(void)
+{
+ on_each_cpu(do_flush_tlb_all, 0, 1);
+}
diff --git a/arch/mn10300/proc-mn103e010/include/proc/cache.h b/arch/mn10300/proc-mn103e010/include/proc/cache.h
index bdc1f9a59b4c..c1528004163c 100644
--- a/arch/mn10300/proc-mn103e010/include/proc/cache.h
+++ b/arch/mn10300/proc-mn103e010/include/proc/cache.h
@@ -30,4 +30,13 @@
*/
#define MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL 4
+/*
+ * The size of range at which it becomes more economical to just flush the
+ * whole cache rather than trying to flush the specified range.
+ */
+#define MN10300_DCACHE_FLUSH_BORDER \
+ +(L1_CACHE_NWAYS * L1_CACHE_NENTRIES * L1_CACHE_BYTES)
+#define MN10300_DCACHE_FLUSH_INV_BORDER \
+ +(L1_CACHE_NWAYS * L1_CACHE_NENTRIES * L1_CACHE_BYTES)
+
#endif /* _ASM_PROC_CACHE_H */
diff --git a/arch/mn10300/proc-mn103e010/include/proc/clock.h b/arch/mn10300/proc-mn103e010/include/proc/clock.h
index aa23e147d620..704a819f1f4b 100644
--- a/arch/mn10300/proc-mn103e010/include/proc/clock.h
+++ b/arch/mn10300/proc-mn103e010/include/proc/clock.h
@@ -13,6 +13,4 @@
#include <unit/clock.h>
-#define MN10300_WDCLK MN10300_IOCLK
-
#endif /* _ASM_PROC_CLOCK_H */
diff --git a/arch/mn10300/proc-mn103e010/include/proc/dmactl-regs.h b/arch/mn10300/proc-mn103e010/include/proc/dmactl-regs.h
new file mode 100644
index 000000000000..d72d328d1f9c
--- /dev/null
+++ b/arch/mn10300/proc-mn103e010/include/proc/dmactl-regs.h
@@ -0,0 +1,102 @@
+/* MN103E010 on-board DMA controller registers
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _ASM_PROC_DMACTL_REGS_H
+#define _ASM_PROC_DMACTL_REGS_H
+
+#include <asm/cpu-regs.h>
+
+#ifdef __KERNEL__
+
+/* DMA registers */
+#define DMxCTR(N) __SYSREG(0xd2000000 + ((N) * 0x100), u32) /* control reg */
+#define DMxCTR_BG 0x0000001f /* transfer request source */
+#define DMxCTR_BG_SOFT 0x00000000 /* - software source */
+#define DMxCTR_BG_SC0TX 0x00000002 /* - serial port 0 transmission */
+#define DMxCTR_BG_SC0RX 0x00000003 /* - serial port 0 reception */
+#define DMxCTR_BG_SC1TX 0x00000004 /* - serial port 1 transmission */
+#define DMxCTR_BG_SC1RX 0x00000005 /* - serial port 1 reception */
+#define DMxCTR_BG_SC2TX 0x00000006 /* - serial port 2 transmission */
+#define DMxCTR_BG_SC2RX 0x00000007 /* - serial port 2 reception */
+#define DMxCTR_BG_TM0UFLOW 0x00000008 /* - timer 0 underflow */
+#define DMxCTR_BG_TM1UFLOW 0x00000009 /* - timer 1 underflow */
+#define DMxCTR_BG_TM2UFLOW 0x0000000a /* - timer 2 underflow */
+#define DMxCTR_BG_TM3UFLOW 0x0000000b /* - timer 3 underflow */
+#define DMxCTR_BG_TM6ACMPCAP 0x0000000c /* - timer 6A compare/capture */
+#define DMxCTR_BG_AFE 0x0000000d /* - analogue front-end interrupt source */
+#define DMxCTR_BG_ADC 0x0000000e /* - A/D conversion end interrupt source */
+#define DMxCTR_BG_IRDA 0x0000000f /* - IrDA interrupt source */
+#define DMxCTR_BG_RTC 0x00000010 /* - RTC interrupt source */
+#define DMxCTR_BG_XIRQ0 0x00000011 /* - XIRQ0 pin interrupt source */
+#define DMxCTR_BG_XIRQ1 0x00000012 /* - XIRQ1 pin interrupt source */
+#define DMxCTR_BG_XDMR0 0x00000013 /* - external request 0 source (XDMR0 pin) */
+#define DMxCTR_BG_XDMR1 0x00000014 /* - external request 1 source (XDMR1 pin) */
+#define DMxCTR_SAM 0x000000e0 /* DMA transfer src addr mode */
+#define DMxCTR_SAM_INCR 0x00000000 /* - increment */
+#define DMxCTR_SAM_DECR 0x00000020 /* - decrement */
+#define DMxCTR_SAM_FIXED 0x00000040 /* - fixed */
+#define DMxCTR_DAM 0x00000000 /* DMA transfer dest addr mode */
+#define DMxCTR_DAM_INCR 0x00000000 /* - increment */
+#define DMxCTR_DAM_DECR 0x00000100 /* - decrement */
+#define DMxCTR_DAM_FIXED 0x00000200 /* - fixed */
+#define DMxCTR_TM 0x00001800 /* DMA transfer mode */
+#define DMxCTR_TM_BATCH 0x00000000 /* - batch transfer */
+#define DMxCTR_TM_INTERM 0x00001000 /* - intermittent transfer */
+#define DMxCTR_UT 0x00006000 /* DMA transfer unit */
+#define DMxCTR_UT_1 0x00000000 /* - 1 byte */
+#define DMxCTR_UT_2 0x00002000 /* - 2 byte */
+#define DMxCTR_UT_4 0x00004000 /* - 4 byte */
+#define DMxCTR_UT_16 0x00006000 /* - 16 byte */
+#define DMxCTR_TEN 0x00010000 /* DMA channel transfer enable */
+#define DMxCTR_RQM 0x00060000 /* external request input source mode */
+#define DMxCTR_RQM_FALLEDGE 0x00000000 /* - falling edge */
+#define DMxCTR_RQM_RISEEDGE 0x00020000 /* - rising edge */
+#define DMxCTR_RQM_LOLEVEL 0x00040000 /* - low level */
+#define DMxCTR_RQM_HILEVEL 0x00060000 /* - high level */
+#define DMxCTR_RQF 0x01000000 /* DMA transfer request flag */
+#define DMxCTR_XEND 0x80000000 /* DMA transfer end flag */
+
+#define DMxSRC(N) __SYSREG(0xd2000004 + ((N) * 0x100), u32) /* control reg */
+
+#define DMxDST(N) __SYSREG(0xd2000008 + ((N) * 0x100), u32) /* src addr reg */
+
+#define DMxSIZ(N) __SYSREG(0xd200000c + ((N) * 0x100), u32) /* dest addr reg */
+#define DMxSIZ_CT 0x000fffff /* number of bytes to transfer */
+
+#define DMxCYC(N) __SYSREG(0xd2000010 + ((N) * 0x100), u32) /* intermittent
+ * size reg */
+#define DMxCYC_CYC 0x000000ff /* number of interrmittent transfers -1 */
+
+#define DM0IRQ 16 /* DMA channel 0 complete IRQ */
+#define DM1IRQ 17 /* DMA channel 1 complete IRQ */
+#define DM2IRQ 18 /* DMA channel 2 complete IRQ */
+#define DM3IRQ 19 /* DMA channel 3 complete IRQ */
+
+#define DM0ICR GxICR(DM0IRQ) /* DMA channel 0 complete intr ctrl reg */
+#define DM1ICR GxICR(DM0IR1) /* DMA channel 1 complete intr ctrl reg */
+#define DM2ICR GxICR(DM0IR2) /* DMA channel 2 complete intr ctrl reg */
+#define DM3ICR GxICR(DM0IR3) /* DMA channel 3 complete intr ctrl reg */
+
+#ifndef __ASSEMBLY__
+
+struct mn10300_dmactl_regs {
+ u32 ctr;
+ const void *src;
+ void *dst;
+ u32 siz;
+ u32 cyc;
+} __attribute__((aligned(0x100)));
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_PROC_DMACTL_REGS_H */
diff --git a/arch/mn10300/proc-mn103e010/include/proc/intctl-regs.h b/arch/mn10300/proc-mn103e010/include/proc/intctl-regs.h
new file mode 100644
index 000000000000..f537801a44ba
--- /dev/null
+++ b/arch/mn10300/proc-mn103e010/include/proc/intctl-regs.h
@@ -0,0 +1,29 @@
+#ifndef _ASM_PROC_INTCTL_REGS_H
+#define _ASM_PROC_INTCTL_REGS_H
+
+#ifndef _ASM_INTCTL_REGS_H
+# error "please don't include this file directly"
+#endif
+
+/* intr acceptance group reg */
+#define IAGR __SYSREG(0xd4000100, u16)
+
+/* group number register */
+#define IAGR_GN 0x00fc
+
+#define __GET_XIRQ_TRIGGER(X, Z) (((Z) >> ((X) * 2)) & 3)
+
+#define __SET_XIRQ_TRIGGER(X, Y, Z) \
+({ \
+ typeof(Z) x = (Z); \
+ x &= ~(3 << ((X) * 2)); \
+ x |= ((Y) & 3) << ((X) * 2); \
+ (Z) = x; \
+})
+
+/* external pin intr spec reg */
+#define EXTMD __SYSREG(0xd4000200, u16)
+#define GET_XIRQ_TRIGGER(X) __GET_XIRQ_TRIGGER(X, EXTMD)
+#define SET_XIRQ_TRIGGER(X, Y) __SET_XIRQ_TRIGGER(X, Y, EXTMD)
+
+#endif /* _ASM_PROC_INTCTL_REGS_H */
diff --git a/arch/mn10300/proc-mn103e010/include/proc/proc.h b/arch/mn10300/proc-mn103e010/include/proc/proc.h
index 22a2b93f70b7..39c4f8e7d2d3 100644
--- a/arch/mn10300/proc-mn103e010/include/proc/proc.h
+++ b/arch/mn10300/proc-mn103e010/include/proc/proc.h
@@ -12,7 +12,7 @@
#ifndef _ASM_PROC_PROC_H
#define _ASM_PROC_PROC_H
-#define PROCESSOR_VENDOR_NAME "Matsushita"
+#define PROCESSOR_VENDOR_NAME "Panasonic"
#define PROCESSOR_MODEL_NAME "mn103e010"
#endif /* _ASM_PROC_PROC_H */
diff --git a/arch/mn10300/proc-mn103e010/proc-init.c b/arch/mn10300/proc-mn103e010/proc-init.c
index 9a482efafa82..27b97980dca4 100644
--- a/arch/mn10300/proc-mn103e010/proc-init.c
+++ b/arch/mn10300/proc-mn103e010/proc-init.c
@@ -9,7 +9,9 @@
* 2 of the Licence, or (at your option) any later version.
*/
#include <linux/kernel.h>
+#include <asm/fpu.h>
#include <asm/rtc.h>
+#include <asm/busctl-regs.h>
/*
* initialise the on-silicon processor peripherals
@@ -28,6 +30,7 @@ asmlinkage void __init processor_init(void)
__set_intr_stub(EXCEP_DAERROR, dtlb_aerror);
__set_intr_stub(EXCEP_BUSERROR, raw_bus_error);
__set_intr_stub(EXCEP_DOUBLE_FAULT, double_fault);
+ __set_intr_stub(EXCEP_FPU_DISABLED, fpu_disabled);
__set_intr_stub(EXCEP_SYSCALL0, system_call);
__set_intr_stub(EXCEP_NMI, nmi_handler);
@@ -73,3 +76,37 @@ asmlinkage void __init processor_init(void)
calibrate_clock();
}
+
+/*
+ * determine the memory size and base from the memory controller regs
+ */
+void __init get_mem_info(unsigned long *mem_base, unsigned long *mem_size)
+{
+ unsigned long base, size;
+
+ *mem_base = 0;
+ *mem_size = 0;
+
+ base = SDBASE(0);
+ if (base & SDBASE_CE) {
+ size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT;
+ size = ~size + 1;
+ base &= SDBASE_CBA;
+
+ printk(KERN_INFO "SDRAM[0]: %luMb @%08lx\n", size >> 20, base);
+ *mem_size += size;
+ *mem_base = base;
+ }
+
+ base = SDBASE(1);
+ if (base & SDBASE_CE) {
+ size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT;
+ size = ~size + 1;
+ base &= SDBASE_CBA;
+
+ printk(KERN_INFO "SDRAM[1]: %luMb @%08lx\n", size >> 20, base);
+ *mem_size += size;
+ if (*mem_base == 0)
+ *mem_base = base;
+ }
+}
diff --git a/arch/mn10300/proc-mn2ws0050/Makefile b/arch/mn10300/proc-mn2ws0050/Makefile
new file mode 100644
index 000000000000..d4ca13309a85
--- /dev/null
+++ b/arch/mn10300/proc-mn2ws0050/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the linux kernel.
+#
+
+obj-y := proc-init.o
diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/cache.h b/arch/mn10300/proc-mn2ws0050/include/proc/cache.h
new file mode 100644
index 000000000000..cafd7b5b55b4
--- /dev/null
+++ b/arch/mn10300/proc-mn2ws0050/include/proc/cache.h
@@ -0,0 +1,48 @@
+/* Cache specification
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * Modified by Matsushita Electric Industrial Co., Ltd.
+ * Modifications:
+ * 13-Nov-2006 MEI Add L1_CACHE_SHIFT_MAX definition.
+ * 29-Jul-2008 MEI Add define for MN10300_HAS_AREAPURGE_REG.
+ *
+ * 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 _ASM_PROC_CACHE_H
+#define _ASM_PROC_CACHE_H
+
+/*
+ * L1 cache
+ */
+#define L1_CACHE_NWAYS 4 /* number of ways in caches */
+#define L1_CACHE_NENTRIES 128 /* number of entries in each way */
+#define L1_CACHE_BYTES 32 /* bytes per entry */
+#define L1_CACHE_SHIFT 5 /* shift for bytes per entry */
+#define L1_CACHE_WAYDISP 0x1000 /* distance from one way to the next */
+
+#define L1_CACHE_TAG_VALID 0x00000001 /* cache tag valid bit */
+#define L1_CACHE_TAG_DIRTY 0x00000008 /* data cache tag dirty bit */
+#define L1_CACHE_TAG_ENTRY 0x00000fe0 /* cache tag entry address mask */
+#define L1_CACHE_TAG_ADDRESS 0xfffff000 /* cache tag line address mask */
+
+/*
+ * specification of the interval between interrupt checking intervals whilst
+ * managing the cache with the interrupts disabled
+ */
+#define MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL 4
+
+/*
+ * The size of range at which it becomes more economical to just flush the
+ * whole cache rather than trying to flush the specified range.
+ */
+#define MN10300_DCACHE_FLUSH_BORDER \
+ +(L1_CACHE_NWAYS * L1_CACHE_NENTRIES * L1_CACHE_BYTES)
+#define MN10300_DCACHE_FLUSH_INV_BORDER \
+ +(L1_CACHE_NWAYS * L1_CACHE_NENTRIES * L1_CACHE_BYTES)
+
+#endif /* _ASM_PROC_CACHE_H */
diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/clock.h b/arch/mn10300/proc-mn2ws0050/include/proc/clock.h
new file mode 100644
index 000000000000..fe4c0a4a53a2
--- /dev/null
+++ b/arch/mn10300/proc-mn2ws0050/include/proc/clock.h
@@ -0,0 +1,20 @@
+/* clock.h: proc-specific clocks
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * Modified by Matsushita Electric Industrial Co., Ltd.
+ * Modifications:
+ * 23-Feb-2007 MEI Delete define for watchdog timer.
+ *
+ * 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 _ASM_PROC_CLOCK_H
+#define _ASM_PROC_CLOCK_H
+
+#include <unit/clock.h>
+
+#endif /* _ASM_PROC_CLOCK_H */
diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/dmactl-regs.h b/arch/mn10300/proc-mn2ws0050/include/proc/dmactl-regs.h
new file mode 100644
index 000000000000..4c4319e241d1
--- /dev/null
+++ b/arch/mn10300/proc-mn2ws0050/include/proc/dmactl-regs.h
@@ -0,0 +1,103 @@
+/* MN2WS0050 on-board DMA controller registers
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef _ASM_PROC_DMACTL_REGS_H
+#define _ASM_PROC_DMACTL_REGS_H
+
+#include <asm/cpu-regs.h>
+
+#ifdef __KERNEL__
+
+/* DMA registers */
+#define DMxCTR(N) __SYSREG(0xd4005000+(N*0x100), u32) /* control reg */
+#define DMxCTR_BG 0x0000001f /* transfer request source */
+#define DMxCTR_BG_SOFT 0x00000000 /* - software source */
+#define DMxCTR_BG_SC0TX 0x00000002 /* - serial port 0 transmission */
+#define DMxCTR_BG_SC0RX 0x00000003 /* - serial port 0 reception */
+#define DMxCTR_BG_SC1TX 0x00000004 /* - serial port 1 transmission */
+#define DMxCTR_BG_SC1RX 0x00000005 /* - serial port 1 reception */
+#define DMxCTR_BG_SC2TX 0x00000006 /* - serial port 2 transmission */
+#define DMxCTR_BG_SC2RX 0x00000007 /* - serial port 2 reception */
+#define DMxCTR_BG_TM0UFLOW 0x00000008 /* - timer 0 underflow */
+#define DMxCTR_BG_TM1UFLOW 0x00000009 /* - timer 1 underflow */
+#define DMxCTR_BG_TM2UFLOW 0x0000000a /* - timer 2 underflow */
+#define DMxCTR_BG_TM3UFLOW 0x0000000b /* - timer 3 underflow */
+#define DMxCTR_BG_TM6ACMPCAP 0x0000000c /* - timer 6A compare/capture */
+#define DMxCTR_BG_RYBY 0x0000000d /* - NAND Flash RY/BY request source */
+#define DMxCTR_BG_RMC 0x0000000e /* - remote controller output */
+#define DMxCTR_BG_XIRQ12 0x00000011 /* - XIRQ12 pin interrupt source */
+#define DMxCTR_BG_XIRQ13 0x00000012 /* - XIRQ13 pin interrupt source */
+#define DMxCTR_BG_TCK 0x00000014 /* - tick timer underflow */
+#define DMxCTR_BG_SC4TX 0x00000019 /* - serial port4 transmission */
+#define DMxCTR_BG_SC4RX 0x0000001a /* - serial port4 reception */
+#define DMxCTR_BG_SC5TX 0x0000001b /* - serial port5 transmission */
+#define DMxCTR_BG_SC5RX 0x0000001c /* - serial port5 reception */
+#define DMxCTR_BG_SC6TX 0x0000001d /* - serial port6 transmission */
+#define DMxCTR_BG_SC6RX 0x0000001e /* - serial port6 reception */
+#define DMxCTR_BG_TMSUFLOW 0x0000001f /* - timestamp timer underflow */
+#define DMxCTR_SAM 0x00000060 /* DMA transfer src addr mode */
+#define DMxCTR_SAM_INCR 0x00000000 /* - increment */
+#define DMxCTR_SAM_DECR 0x00000020 /* - decrement */
+#define DMxCTR_SAM_FIXED 0x00000040 /* - fixed */
+#define DMxCTR_DAM 0x00000300 /* DMA transfer dest addr mode */
+#define DMxCTR_DAM_INCR 0x00000000 /* - increment */
+#define DMxCTR_DAM_DECR 0x00000100 /* - decrement */
+#define DMxCTR_DAM_FIXED 0x00000200 /* - fixed */
+#define DMxCTR_UT 0x00006000 /* DMA transfer unit */
+#define DMxCTR_UT_1 0x00000000 /* - 1 byte */
+#define DMxCTR_UT_2 0x00002000 /* - 2 byte */
+#define DMxCTR_UT_4 0x00004000 /* - 4 byte */
+#define DMxCTR_UT_16 0x00006000 /* - 16 byte */
+#define DMxCTR_RRE 0x00008000 /* DMA round robin enable */
+#define DMxCTR_TEN 0x00010000 /* DMA channel transfer enable */
+#define DMxCTR_RQM 0x00060000 /* external request input source mode */
+#define DMxCTR_RQM_FALLEDGE 0x00000000 /* - falling edge */
+#define DMxCTR_RQM_RISEEDGE 0x00020000 /* - rising edge */
+#define DMxCTR_RQM_LOLEVEL 0x00040000 /* - low level */
+#define DMxCTR_RQM_HILEVEL 0x00060000 /* - high level */
+#define DMxCTR_RQF 0x01000000 /* DMA transfer request flag */
+#define DMxCTR_PERR 0x40000000 /* DMA transfer parameter error flag */
+#define DMxCTR_XEND 0x80000000 /* DMA transfer end flag */
+
+#define DMxSRC(N) __SYSREG(0xd4005004+(N*0x100), u32) /* control reg */
+
+#define DMxDST(N) __SYSREG(0xd4005008+(N*0x100), u32) /* source addr reg */
+
+#define DMxSIZ(N) __SYSREG(0xd400500c+(N*0x100), u32) /* dest addr reg */
+#define DMxSIZ_CT 0x000fffff /* number of bytes to transfer */
+
+#define DMxCYC(N) __SYSREG(0xd4005010+(N*0x100), u32) /* intermittent size reg */
+#define DMxCYC_CYC 0x000000ff /* number of interrmittent transfers -1 */
+
+#define DM0IRQ 16 /* DMA channel 0 complete IRQ */
+#define DM1IRQ 17 /* DMA channel 1 complete IRQ */
+#define DM2IRQ 18 /* DMA channel 2 complete IRQ */
+#define DM3IRQ 19 /* DMA channel 3 complete IRQ */
+
+#define DM0ICR GxICR(DM0IRQ) /* DMA channel 0 complete intr ctrl reg */
+#define DM1ICR GxICR(DM0IR1) /* DMA channel 1 complete intr ctrl reg */
+#define DM2ICR GxICR(DM0IR2) /* DMA channel 2 complete intr ctrl reg */
+#define DM3ICR GxICR(DM0IR3) /* DMA channel 3 complete intr ctrl reg */
+
+#ifndef __ASSEMBLY__
+
+struct mn10300_dmactl_regs {
+ u32 ctr;
+ const void *src;
+ void *dst;
+ u32 siz;
+ u32 cyc;
+} __attribute__((aligned(0x100)));
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_PROC_DMACTL_REGS_H */
diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/intctl-regs.h b/arch/mn10300/proc-mn2ws0050/include/proc/intctl-regs.h
new file mode 100644
index 000000000000..a1e977273d19
--- /dev/null
+++ b/arch/mn10300/proc-mn2ws0050/include/proc/intctl-regs.h
@@ -0,0 +1,29 @@
+#ifndef _ASM_PROC_INTCTL_REGS_H
+#define _ASM_PROC_INTCTL_REGS_H
+
+#ifndef _ASM_INTCTL_REGS_H
+# error "please don't include this file directly"
+#endif
+
+/* intr acceptance group reg */
+#define IAGR __SYSREG(0xd4000100, u16)
+
+/* group number register */
+#define IAGR_GN 0x003fc
+
+#define __GET_XIRQ_TRIGGER(X, Z) (((Z) >> ((X) * 2)) & 3)
+
+#define __SET_XIRQ_TRIGGER(X, Y, Z) \
+({ \
+ typeof(Z) x = (Z); \
+ x &= ~(3 << ((X) * 2)); \
+ x |= ((Y) & 3) << ((X) * 2); \
+ (Z) = x; \
+})
+
+/* external pin intr spec reg */
+#define EXTMD0 __SYSREG(0xd4000200, u32)
+#define GET_XIRQ_TRIGGER(X) __GET_XIRQ_TRIGGER(X, EXTMD0)
+#define SET_XIRQ_TRIGGER(X, Y) __SET_XIRQ_TRIGGER(X, Y, EXTMD0)
+
+#endif /* _ASM_PROC_INTCTL_REGS_H */
diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/irq.h b/arch/mn10300/proc-mn2ws0050/include/proc/irq.h
new file mode 100644
index 000000000000..37777a85ab6f
--- /dev/null
+++ b/arch/mn10300/proc-mn2ws0050/include/proc/irq.h
@@ -0,0 +1,49 @@
+/* MN2WS0050 on-board interrupt controller registers
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * Modified by Matsushita Electric Industrial Co., Ltd.
+ * Modifications:
+ * 13-Nov-2006 MEI Define extended IRQ number for SMP support.
+ *
+ * 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 _PROC_IRQ_H
+#define _PROC_IRQ_H
+
+#ifdef __KERNEL__
+
+#define GxICR_NUM_IRQS 163
+#ifdef CONFIG_SMP
+#define GxICR_NUM_EXT_IRQS 197
+#endif /* CONFIG_SMP */
+
+#define GxICR_NUM_XIRQS 16
+
+#define XIRQ0 34
+#define XIRQ1 35
+#define XIRQ2 36
+#define XIRQ3 37
+#define XIRQ4 38
+#define XIRQ5 39
+#define XIRQ6 40
+#define XIRQ7 41
+#define XIRQ8 42
+#define XIRQ9 43
+#define XIRQ10 44
+#define XIRQ11 45
+#define XIRQ12 46
+#define XIRQ13 47
+#define XIRQ14 48
+#define XIRQ15 49
+
+#define XIRQ2IRQ(num) (XIRQ0 + num)
+
+#endif /* __KERNEL__ */
+
+#endif /* _PROC_IRQ_H */
diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/nand-regs.h b/arch/mn10300/proc-mn2ws0050/include/proc/nand-regs.h
new file mode 100644
index 000000000000..84448f3828b3
--- /dev/null
+++ b/arch/mn10300/proc-mn2ws0050/include/proc/nand-regs.h
@@ -0,0 +1,120 @@
+/* NAND flash interface register definitions
+ *
+ * Copyright (C) 2008-2009 Panasonic Corporation
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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.
+ */
+
+#ifndef _PROC_NAND_REGS_H_
+#define _PROC_NAND_REGS_H_
+
+/* command register */
+#define FCOMMAND_0 __SYSREG(0xd8f00000, u8) /* fcommand[24:31] */
+#define FCOMMAND_1 __SYSREG(0xd8f00001, u8) /* fcommand[16:23] */
+#define FCOMMAND_2 __SYSREG(0xd8f00002, u8) /* fcommand[8:15] */
+#define FCOMMAND_3 __SYSREG(0xd8f00003, u8) /* fcommand[0:7] */
+
+/* for dma 16 byte trans, use FCOMMAND2 register */
+#define FCOMMAND2_0 __SYSREG(0xd8f00110, u8) /* fcommand2[24:31] */
+#define FCOMMAND2_1 __SYSREG(0xd8f00111, u8) /* fcommand2[16:23] */
+#define FCOMMAND2_2 __SYSREG(0xd8f00112, u8) /* fcommand2[8:15] */
+#define FCOMMAND2_3 __SYSREG(0xd8f00113, u8) /* fcommand2[0:7] */
+
+#define FCOMMAND_FIEN 0x80 /* nand flash I/F enable */
+#define FCOMMAND_BW_8BIT 0x00 /* 8bit bus width */
+#define FCOMMAND_BW_16BIT 0x40 /* 16bit bus width */
+#define FCOMMAND_BLOCKSZ_SMALL 0x00 /* small block */
+#define FCOMMAND_BLOCKSZ_LARGE 0x20 /* large block */
+#define FCOMMAND_DMASTART 0x10 /* dma start */
+#define FCOMMAND_RYBY 0x08 /* ready/busy flag */
+#define FCOMMAND_RYBYINTMSK 0x04 /* mask ready/busy interrupt */
+#define FCOMMAND_XFWP 0x02 /* write protect enable */
+#define FCOMMAND_XFCE 0x01 /* flash device disable */
+#define FCOMMAND_SEQKILL 0x10 /* stop seq-read */
+#define FCOMMAND_ANUM 0x07 /* address cycle */
+#define FCOMMAND_ANUM_NONE 0x00 /* address cycle none */
+#define FCOMMAND_ANUM_1CYC 0x01 /* address cycle 1cycle */
+#define FCOMMAND_ANUM_2CYC 0x02 /* address cycle 2cycle */
+#define FCOMMAND_ANUM_3CYC 0x03 /* address cycle 3cycle */
+#define FCOMMAND_ANUM_4CYC 0x04 /* address cycle 4cycle */
+#define FCOMMAND_ANUM_5CYC 0x05 /* address cycle 5cycle */
+#define FCOMMAND_FCMD_READ0 0x00 /* read1 command */
+#define FCOMMAND_FCMD_SEQIN 0x80 /* page program 1st command */
+#define FCOMMAND_FCMD_PAGEPROG 0x10 /* page program 2nd command */
+#define FCOMMAND_FCMD_RESET 0xff /* reset command */
+#define FCOMMAND_FCMD_ERASE1 0x60 /* erase 1st command */
+#define FCOMMAND_FCMD_ERASE2 0xd0 /* erase 2nd command */
+#define FCOMMAND_FCMD_STATUS 0x70 /* read status command */
+#define FCOMMAND_FCMD_READID 0x90 /* read id command */
+#define FCOMMAND_FCMD_READOOB 0x50 /* read3 command */
+/* address register */
+#define FADD __SYSREG(0xd8f00004, u32)
+/* address register 2 */
+#define FADD2 __SYSREG(0xd8f00008, u32)
+/* error judgement register */
+#define FJUDGE __SYSREG(0xd8f0000c, u32)
+#define FJUDGE_NOERR 0x0 /* no error */
+#define FJUDGE_1BITERR 0x1 /* 1bit error in data area */
+#define FJUDGE_PARITYERR 0x2 /* parity error */
+#define FJUDGE_UNCORRECTABLE 0x3 /* uncorrectable error */
+#define FJUDGE_ERRJDG_MSK 0x3 /* mask of judgement result */
+/* 1st ECC store register */
+#define FECC11 __SYSREG(0xd8f00010, u32)
+/* 2nd ECC store register */
+#define FECC12 __SYSREG(0xd8f00014, u32)
+/* 3rd ECC store register */
+#define FECC21 __SYSREG(0xd8f00018, u32)
+/* 4th ECC store register */
+#define FECC22 __SYSREG(0xd8f0001c, u32)
+/* 5th ECC store register */
+#define FECC31 __SYSREG(0xd8f00020, u32)
+/* 6th ECC store register */
+#define FECC32 __SYSREG(0xd8f00024, u32)
+/* 7th ECC store register */
+#define FECC41 __SYSREG(0xd8f00028, u32)
+/* 8th ECC store register */
+#define FECC42 __SYSREG(0xd8f0002c, u32)
+/* data register */
+#define FDATA __SYSREG(0xd8f00030, u32)
+/* access pulse register */
+#define FPWS __SYSREG(0xd8f00100, u32)
+#define FPWS_PWS1W_2CLK 0x00000000 /* write pulse width 1clock */
+#define FPWS_PWS1W_3CLK 0x01000000 /* write pulse width 2clock */
+#define FPWS_PWS1W_4CLK 0x02000000 /* write pulse width 4clock */
+#define FPWS_PWS1W_5CLK 0x03000000 /* write pulse width 5clock */
+#define FPWS_PWS1W_6CLK 0x04000000 /* write pulse width 6clock */
+#define FPWS_PWS1W_7CLK 0x05000000 /* write pulse width 7clock */
+#define FPWS_PWS1W_8CLK 0x06000000 /* write pulse width 8clock */
+#define FPWS_PWS1R_3CLK 0x00010000 /* read pulse width 3clock */
+#define FPWS_PWS1R_4CLK 0x00020000 /* read pulse width 4clock */
+#define FPWS_PWS1R_5CLK 0x00030000 /* read pulse width 5clock */
+#define FPWS_PWS1R_6CLK 0x00040000 /* read pulse width 6clock */
+#define FPWS_PWS1R_7CLK 0x00050000 /* read pulse width 7clock */
+#define FPWS_PWS1R_8CLK 0x00060000 /* read pulse width 8clock */
+#define FPWS_PWS2W_2CLK 0x00000100 /* write pulse interval 2clock */
+#define FPWS_PWS2W_3CLK 0x00000200 /* write pulse interval 3clock */
+#define FPWS_PWS2W_4CLK 0x00000300 /* write pulse interval 4clock */
+#define FPWS_PWS2W_5CLK 0x00000400 /* write pulse interval 5clock */
+#define FPWS_PWS2W_6CLK 0x00000500 /* write pulse interval 6clock */
+#define FPWS_PWS2R_2CLK 0x00000001 /* read pulse interval 2clock */
+#define FPWS_PWS2R_3CLK 0x00000002 /* read pulse interval 3clock */
+#define FPWS_PWS2R_4CLK 0x00000003 /* read pulse interval 4clock */
+#define FPWS_PWS2R_5CLK 0x00000004 /* read pulse interval 5clock */
+#define FPWS_PWS2R_6CLK 0x00000005 /* read pulse interval 6clock */
+/* command register 2 */
+#define FCOMMAND2 __SYSREG(0xd8f00110, u32)
+/* transfer frequency register */
+#define FNUM __SYSREG(0xd8f00114, u32)
+#define FSDATA_ADDR 0xd8f00400
+/* active data register */
+#define FSDATA __SYSREG(FSDATA_ADDR, u32)
+
+#endif /* _PROC_NAND_REGS_H_ */
diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/proc.h b/arch/mn10300/proc-mn2ws0050/include/proc/proc.h
new file mode 100644
index 000000000000..90d5cadd05bd
--- /dev/null
+++ b/arch/mn10300/proc-mn2ws0050/include/proc/proc.h
@@ -0,0 +1,18 @@
+/* proc.h: MN2WS0050 processor description
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ASM_PROC_PROC_H
+#define _ASM_PROC_PROC_H
+
+#define PROCESSOR_VENDOR_NAME "Panasonic"
+#define PROCESSOR_MODEL_NAME "mn2ws0050"
+
+#endif /* _ASM_PROC_PROC_H */
diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/smp-regs.h b/arch/mn10300/proc-mn2ws0050/include/proc/smp-regs.h
new file mode 100644
index 000000000000..22f277fbb4de
--- /dev/null
+++ b/arch/mn10300/proc-mn2ws0050/include/proc/smp-regs.h
@@ -0,0 +1,51 @@
+/* MN10300/AM33v2 Microcontroller SMP registers
+ *
+ * Copyright (C) 2006 Matsushita Electric Industrial Co., Ltd.
+ * All Rights Reserved.
+ * Created:
+ * 13-Nov-2006 MEI Add extended cache and atomic operation register
+ * for SMP support.
+ * 23-Feb-2007 MEI Add define for gdbstub SMP.
+ *
+ * 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 _ASM_PROC_SMP_REGS_H
+#define _ASM_PROC_SMP_REGS_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+#endif
+#include <asm/cpu-regs.h>
+
+/*
+ * Reference to the interrupt controllers of other CPUs
+ */
+#define CROSS_ICR_CPU_SHIFT 16
+
+#define CROSS_GxICR(X, CPU) __SYSREG(0xc4000000 + (X) * 4 + \
+ ((X) >= 64 && (X) < 192) * 0xf00 + ((CPU) << CROSS_ICR_CPU_SHIFT), u16)
+#define CROSS_GxICR_u8(X, CPU) __SYSREG(0xc4000000 + (X) * 4 + \
+ (((X) >= 64) && ((X) < 192)) * 0xf00 + ((CPU) << CROSS_ICR_CPU_SHIFT), u8)
+
+/* CPU ID register */
+#define CPUID __SYSREGC(0xc0000054, u32)
+#define CPUID_MASK 0x00000007 /* CPU ID mask */
+
+/* extended cache control register */
+#define ECHCTR __SYSREG(0xc0000c20, u32)
+#define ECHCTR_IBCM 0x00000001 /* instruction cache broad cast mask */
+#define ECHCTR_DBCM 0x00000002 /* data cache broad cast mask */
+#define ECHCTR_ISPM 0x00000004 /* instruction cache snoop mask */
+#define ECHCTR_DSPM 0x00000008 /* data cache snoop mask */
+
+#define NMIAGR __SYSREG(0xd400013c, u16)
+#define NMIAGR_GN 0x03fc
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_PROC_SMP_REGS_H */
diff --git a/arch/mn10300/proc-mn2ws0050/proc-init.c b/arch/mn10300/proc-mn2ws0050/proc-init.c
new file mode 100644
index 000000000000..c58249b9525a
--- /dev/null
+++ b/arch/mn10300/proc-mn2ws0050/proc-init.c
@@ -0,0 +1,134 @@
+/* MN2WS0050 processor initialisation
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/smp.h>
+#include <asm/pgalloc.h>
+#include <asm/busctl-regs.h>
+#include <unit/timex.h>
+#include <asm/fpu.h>
+#include <asm/rtc.h>
+
+#define MEMCONF __SYSREGC(0xdf800400, u32)
+
+/*
+ * initialise the on-silicon processor peripherals
+ */
+asmlinkage void __init processor_init(void)
+{
+ int loop;
+
+ /* set up the exception table first */
+ for (loop = 0x000; loop < 0x400; loop += 8)
+ __set_intr_stub(loop, __common_exception);
+
+ __set_intr_stub(EXCEP_ITLBMISS, itlb_miss);
+ __set_intr_stub(EXCEP_DTLBMISS, dtlb_miss);
+ __set_intr_stub(EXCEP_IAERROR, itlb_aerror);
+ __set_intr_stub(EXCEP_DAERROR, dtlb_aerror);
+ __set_intr_stub(EXCEP_BUSERROR, raw_bus_error);
+ __set_intr_stub(EXCEP_DOUBLE_FAULT, double_fault);
+ __set_intr_stub(EXCEP_FPU_DISABLED, fpu_disabled);
+ __set_intr_stub(EXCEP_SYSCALL0, system_call);
+
+ __set_intr_stub(EXCEP_NMI, nmi_handler);
+ __set_intr_stub(EXCEP_WDT, nmi_handler);
+ __set_intr_stub(EXCEP_IRQ_LEVEL0, irq_handler);
+ __set_intr_stub(EXCEP_IRQ_LEVEL1, irq_handler);
+ __set_intr_stub(EXCEP_IRQ_LEVEL2, irq_handler);
+ __set_intr_stub(EXCEP_IRQ_LEVEL3, irq_handler);
+ __set_intr_stub(EXCEP_IRQ_LEVEL4, irq_handler);
+ __set_intr_stub(EXCEP_IRQ_LEVEL5, irq_handler);
+ __set_intr_stub(EXCEP_IRQ_LEVEL6, irq_handler);
+
+ IVAR0 = EXCEP_IRQ_LEVEL0;
+ IVAR1 = EXCEP_IRQ_LEVEL1;
+ IVAR2 = EXCEP_IRQ_LEVEL2;
+ IVAR3 = EXCEP_IRQ_LEVEL3;
+ IVAR4 = EXCEP_IRQ_LEVEL4;
+ IVAR5 = EXCEP_IRQ_LEVEL5;
+ IVAR6 = EXCEP_IRQ_LEVEL6;
+
+#ifndef CONFIG_MN10300_HAS_CACHE_SNOOP
+ mn10300_dcache_flush_inv();
+ mn10300_icache_inv();
+#endif
+
+ /* disable all interrupts and set to priority 6 (lowest) */
+#ifdef CONFIG_SMP
+ for (loop = 0; loop < GxICR_NUM_IRQS; loop++)
+ GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT;
+#else /* !CONFIG_SMP */
+ for (loop = 0; loop < NR_IRQS; loop++)
+ GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT;
+#endif /* !CONFIG_SMP */
+
+ /* clear the timers */
+ TM0MD = 0;
+ TM1MD = 0;
+ TM2MD = 0;
+ TM3MD = 0;
+ TM4MD = 0;
+ TM5MD = 0;
+ TM6MD = 0;
+ TM6MDA = 0;
+ TM6MDB = 0;
+ TM7MD = 0;
+ TM8MD = 0;
+ TM9MD = 0;
+ TM10MD = 0;
+ TM11MD = 0;
+ TM12MD = 0;
+ TM13MD = 0;
+ TM14MD = 0;
+ TM15MD = 0;
+
+ calibrate_clock();
+}
+
+/*
+ * determine the memory size and base from the memory controller regs
+ */
+void __init get_mem_info(unsigned long *mem_base, unsigned long *mem_size)
+{
+ unsigned long memconf = MEMCONF;
+ unsigned long size = 0; /* order: MByte */
+
+ *mem_base = 0x90000000; /* fixed address */
+
+ switch (memconf & 0x00000003) {
+ case 0x01:
+ size = 256 / 8; /* 256 Mbit per chip */
+ break;
+ case 0x02:
+ size = 512 / 8; /* 512 Mbit per chip */
+ break;
+ case 0x03:
+ size = 1024 / 8; /* 1 Gbit per chip */
+ break;
+ default:
+ panic("Invalid SDRAM size");
+ break;
+ }
+
+ printk(KERN_INFO "DDR2-SDRAM: %luMB x 2 @%08lx\n", size, *mem_base);
+
+ *mem_size = (size * 2) << 20;
+}
diff --git a/arch/mn10300/unit-asb2303/include/unit/clock.h b/arch/mn10300/unit-asb2303/include/unit/clock.h
index 2a0bf79ab968..0316907a012e 100644
--- a/arch/mn10300/unit-asb2303/include/unit/clock.h
+++ b/arch/mn10300/unit-asb2303/include/unit/clock.h
@@ -14,32 +14,11 @@
#ifndef __ASSEMBLY__
-#ifdef CONFIG_MN10300_RTC
-
-extern unsigned long mn10300_ioclk; /* IOCLK (crystal speed) in HZ */
-extern unsigned long mn10300_iobclk;
-extern unsigned long mn10300_tsc_per_HZ;
-
-#define MN10300_IOCLK mn10300_ioclk
-/* If this processors has a another clock, uncomment the below. */
-/* #define MN10300_IOBCLK mn10300_iobclk */
-
-#else /* !CONFIG_MN10300_RTC */
-
#define MN10300_IOCLK 33333333UL
/* #define MN10300_IOBCLK 66666666UL */
-#endif /* !CONFIG_MN10300_RTC */
-
-#define MN10300_JCCLK MN10300_IOCLK
-#define MN10300_TSCCLK MN10300_IOCLK
-
-#ifdef CONFIG_MN10300_RTC
-#define MN10300_TSC_PER_HZ mn10300_tsc_per_HZ
-#else /* !CONFIG_MN10300_RTC */
-#define MN10300_TSC_PER_HZ (MN10300_TSCCLK/HZ)
-#endif /* !CONFIG_MN10300_RTC */
-
#endif /* !__ASSEMBLY__ */
+#define MN10300_WDCLK MN10300_IOCLK
+
#endif /* _ASM_UNIT_CLOCK_H */
diff --git a/arch/mn10300/unit-asb2303/include/unit/serial.h b/arch/mn10300/unit-asb2303/include/unit/serial.h
index 047566cd2e36..991e356bac5f 100644
--- a/arch/mn10300/unit-asb2303/include/unit/serial.h
+++ b/arch/mn10300/unit-asb2303/include/unit/serial.h
@@ -22,6 +22,11 @@
#define SERIAL_IRQ XIRQ0 /* Dual serial (PC16552) (Hi) */
/*
+ * The ASB2303 has an 18.432 MHz clock the UART
+ */
+#define BASE_BAUD (18432000 / 16)
+
+/*
* dispose of the /dev/ttyS0 and /dev/ttyS1 serial ports
*/
#ifndef CONFIG_GDBSTUB_ON_TTYSx
diff --git a/arch/mn10300/unit-asb2303/include/unit/timex.h b/arch/mn10300/unit-asb2303/include/unit/timex.h
index f206b63c95b4..cc18fe7d8b90 100644
--- a/arch/mn10300/unit-asb2303/include/unit/timex.h
+++ b/arch/mn10300/unit-asb2303/include/unit/timex.h
@@ -1,6 +1,6 @@
-/* ASB2303-specific timer specifcations
+/* ASB2303-specific timer specifications
*
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2007, 2010 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -17,67 +17,72 @@
#include <asm/timer-regs.h>
#include <unit/clock.h>
+#include <asm/param.h>
/*
* jiffies counter specifications
*/
#define TMJCBR_MAX 0xffff
-#define TMJCBC TM01BC
-
-#define TMJCMD TM01MD
-#define TMJCBR TM01BR
#define TMJCIRQ TM1IRQ
#define TMJCICR TM1ICR
-#define TMJCICR_LEVEL GxICR_LEVEL_5
#ifndef __ASSEMBLY__
-static inline void startup_jiffies_counter(void)
+#define MN10300_SRC_IOCLK MN10300_IOCLK
+
+#ifndef HZ
+# error HZ undeclared.
+#endif /* !HZ */
+/* use as little prescaling as possible to avoid losing accuracy */
+#if (MN10300_SRC_IOCLK + HZ / 2) / HZ - 1 <= TMJCBR_MAX
+# define IOCLK_PRESCALE 1
+# define JC_TIMER_CLKSRC TM0MD_SRC_IOCLK
+# define TSC_TIMER_CLKSRC TM4MD_SRC_IOCLK
+#elif (MN10300_SRC_IOCLK / 8 + HZ / 2) / HZ - 1 <= TMJCBR_MAX
+# define IOCLK_PRESCALE 8
+# define JC_TIMER_CLKSRC TM0MD_SRC_IOCLK_8
+# define TSC_TIMER_CLKSRC TM4MD_SRC_IOCLK_8
+#elif (MN10300_SRC_IOCLK / 32 + HZ / 2) / HZ - 1 <= TMJCBR_MAX
+# define IOCLK_PRESCALE 32
+# define JC_TIMER_CLKSRC TM0MD_SRC_IOCLK_32
+# define TSC_TIMER_CLKSRC TM4MD_SRC_IOCLK_32
+#else
+# error You lose.
+#endif
+
+#define MN10300_JCCLK (MN10300_SRC_IOCLK / IOCLK_PRESCALE)
+#define MN10300_TSCCLK (MN10300_SRC_IOCLK / IOCLK_PRESCALE)
+
+#define MN10300_JC_PER_HZ ((MN10300_JCCLK + HZ / 2) / HZ)
+#define MN10300_TSC_PER_HZ ((MN10300_TSCCLK + HZ / 2) / HZ)
+
+static inline void stop_jiffies_counter(void)
{
- unsigned rate;
- u16 md, t16;
-
- /* use as little prescaling as possible to avoid losing accuracy */
- md = TM0MD_SRC_IOCLK;
- rate = MN10300_JCCLK / HZ;
-
- if (rate > TMJCBR_MAX) {
- md = TM0MD_SRC_IOCLK_8;
- rate = MN10300_JCCLK / 8 / HZ;
-
- if (rate > TMJCBR_MAX) {
- md = TM0MD_SRC_IOCLK_32;
- rate = MN10300_JCCLK / 32 / HZ;
-
- if (rate > TMJCBR_MAX)
- BUG();
- }
- }
+ u16 tmp;
+ TM01MD = JC_TIMER_CLKSRC | TM1MD_SRC_TM0CASCADE << 8;
+ tmp = TM01MD;
+}
- TMJCBR = rate - 1;
- t16 = TMJCBR;
+static inline void reload_jiffies_counter(u32 cnt)
+{
+ u32 tmp;
- TMJCMD =
- md |
- TM1MD_SRC_TM0CASCADE << 8 |
- TM0MD_INIT_COUNTER |
- TM1MD_INIT_COUNTER << 8;
+ TM01BR = cnt;
+ tmp = TM01BR;
- TMJCMD =
- md |
- TM1MD_SRC_TM0CASCADE << 8 |
- TM0MD_COUNT_ENABLE |
- TM1MD_COUNT_ENABLE << 8;
+ TM01MD = JC_TIMER_CLKSRC | \
+ TM1MD_SRC_TM0CASCADE << 8 | \
+ TM0MD_INIT_COUNTER | \
+ TM1MD_INIT_COUNTER << 8;
- t16 = TMJCMD;
- TMJCICR |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST;
- t16 = TMJCICR;
-}
+ TM01MD = JC_TIMER_CLKSRC | \
+ TM1MD_SRC_TM0CASCADE << 8 | \
+ TM0MD_COUNT_ENABLE | \
+ TM1MD_COUNT_ENABLE << 8;
-static inline void shutdown_jiffies_counter(void)
-{
+ tmp = TM01MD;
}
#endif /* !__ASSEMBLY__ */
@@ -94,29 +99,39 @@ static inline void shutdown_jiffies_counter(void)
static inline void startup_timestamp_counter(void)
{
+ u32 t32;
+
/* set up timer 4 & 5 cascaded as a 32-bit counter to count real time
* - count down from 4Gig-1 to 0 and wrap at IOCLK rate
*/
TM45BR = TMTSCBR_MAX;
+ t32 = TM45BR;
- TM4MD = TM4MD_SRC_IOCLK;
+ TM4MD = TSC_TIMER_CLKSRC;
TM4MD |= TM4MD_INIT_COUNTER;
TM4MD &= ~TM4MD_INIT_COUNTER;
TM4ICR = 0;
+ t32 = TM4ICR;
TM5MD = TM5MD_SRC_TM4CASCADE;
TM5MD |= TM5MD_INIT_COUNTER;
TM5MD &= ~TM5MD_INIT_COUNTER;
TM5ICR = 0;
+ t32 = TM5ICR;
TM5MD |= TM5MD_COUNT_ENABLE;
TM4MD |= TM4MD_COUNT_ENABLE;
+ t32 = TM5MD;
+ t32 = TM4MD;
}
static inline void shutdown_timestamp_counter(void)
{
+ u8 t8;
TM4MD = 0;
TM5MD = 0;
+ t8 = TM4MD;
+ t8 = TM5MD;
}
/*
@@ -127,7 +142,7 @@ typedef unsigned long cycles_t;
static inline cycles_t read_timestamp_counter(void)
{
- return (cycles_t)TMTSCBC;
+ return (cycles_t)~TMTSCBC;
}
#endif /* !__ASSEMBLY__ */
diff --git a/arch/mn10300/unit-asb2303/unit-init.c b/arch/mn10300/unit-asb2303/unit-init.c
index 70e8cb4ea266..834a76aa551a 100644
--- a/arch/mn10300/unit-asb2303/unit-init.c
+++ b/arch/mn10300/unit-asb2303/unit-init.c
@@ -31,6 +31,14 @@ asmlinkage void __init unit_init(void)
SET_XIRQ_TRIGGER(3, XIRQ_TRIGGER_HILEVEL);
SET_XIRQ_TRIGGER(4, XIRQ_TRIGGER_LOWLEVEL);
SET_XIRQ_TRIGGER(5, XIRQ_TRIGGER_LOWLEVEL);
+
+#ifdef CONFIG_EXT_SERIAL_IRQ_LEVEL
+ set_intr_level(XIRQ0, NUM2GxICR_LEVEL(CONFIG_EXT_SERIAL_IRQ_LEVEL));
+#endif
+
+#ifdef CONFIG_ETHERNET_IRQ_LEVEL
+ set_intr_level(XIRQ3, NUM2GxICR_LEVEL(CONFIG_ETHERNET_IRQ_LEVEL));
+#endif
}
/*
@@ -51,7 +59,7 @@ void __init unit_init_IRQ(void)
switch (GET_XIRQ_TRIGGER(extnum)) {
case XIRQ_TRIGGER_HILEVEL:
case XIRQ_TRIGGER_LOWLEVEL:
- set_intr_postackable(XIRQ2IRQ(extnum));
+ mn10300_set_lateack_irq_type(XIRQ2IRQ(extnum));
break;
default:
break;
diff --git a/arch/mn10300/unit-asb2305/include/unit/clock.h b/arch/mn10300/unit-asb2305/include/unit/clock.h
index 67be3f2eb18e..29e3425431cf 100644
--- a/arch/mn10300/unit-asb2305/include/unit/clock.h
+++ b/arch/mn10300/unit-asb2305/include/unit/clock.h
@@ -14,32 +14,11 @@
#ifndef __ASSEMBLY__
-#ifdef CONFIG_MN10300_RTC
-
-extern unsigned long mn10300_ioclk; /* IOCLK (crystal speed) in HZ */
-extern unsigned long mn10300_iobclk;
-extern unsigned long mn10300_tsc_per_HZ;
-
-#define MN10300_IOCLK mn10300_ioclk
-/* If this processors has a another clock, uncomment the below. */
-/* #define MN10300_IOBCLK mn10300_iobclk */
-
-#else /* !CONFIG_MN10300_RTC */
-
#define MN10300_IOCLK 33333333UL
/* #define MN10300_IOBCLK 66666666UL */
-#endif /* !CONFIG_MN10300_RTC */
-
-#define MN10300_JCCLK MN10300_IOCLK
-#define MN10300_TSCCLK MN10300_IOCLK
-
-#ifdef CONFIG_MN10300_RTC
-#define MN10300_TSC_PER_HZ mn10300_tsc_per_HZ
-#else /* !CONFIG_MN10300_RTC */
-#define MN10300_TSC_PER_HZ (MN10300_TSCCLK/HZ)
-#endif /* !CONFIG_MN10300_RTC */
-
#endif /* !__ASSEMBLY__ */
+#define MN10300_WDCLK MN10300_IOCLK
+
#endif /* _ASM_UNIT_CLOCK_H */
diff --git a/arch/mn10300/unit-asb2305/include/unit/serial.h b/arch/mn10300/unit-asb2305/include/unit/serial.h
index 8086cc092cec..88c08219315f 100644
--- a/arch/mn10300/unit-asb2305/include/unit/serial.h
+++ b/arch/mn10300/unit-asb2305/include/unit/serial.h
@@ -21,6 +21,11 @@
#define SERIAL_IRQ XIRQ0 /* Dual serial (PC16552) (Hi) */
/*
+ * The ASB2305 has an 18.432 MHz clock the UART
+ */
+#define BASE_BAUD (18432000 / 16)
+
+/*
* dispose of the /dev/ttyS0 serial port
*/
#ifndef CONFIG_GDBSTUB_ON_TTYSx
diff --git a/arch/mn10300/unit-asb2305/include/unit/timex.h b/arch/mn10300/unit-asb2305/include/unit/timex.h
index d1c72d59fa9f..758af30d1a16 100644
--- a/arch/mn10300/unit-asb2305/include/unit/timex.h
+++ b/arch/mn10300/unit-asb2305/include/unit/timex.h
@@ -1,6 +1,6 @@
-/* ASB2305 timer specifcations
+/* ASB2305-specific timer specifications
*
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2007, 2010 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -17,67 +17,72 @@
#include <asm/timer-regs.h>
#include <unit/clock.h>
+#include <asm/param.h>
/*
* jiffies counter specifications
*/
#define TMJCBR_MAX 0xffff
-#define TMJCBC TM01BC
-
-#define TMJCMD TM01MD
-#define TMJCBR TM01BR
#define TMJCIRQ TM1IRQ
#define TMJCICR TM1ICR
-#define TMJCICR_LEVEL GxICR_LEVEL_5
#ifndef __ASSEMBLY__
-static inline void startup_jiffies_counter(void)
+#define MN10300_SRC_IOCLK MN10300_IOCLK
+
+#ifndef HZ
+# error HZ undeclared.
+#endif /* !HZ */
+/* use as little prescaling as possible to avoid losing accuracy */
+#if (MN10300_SRC_IOCLK + HZ / 2) / HZ - 1 <= TMJCBR_MAX
+# define IOCLK_PRESCALE 1
+# define JC_TIMER_CLKSRC TM0MD_SRC_IOCLK
+# define TSC_TIMER_CLKSRC TM4MD_SRC_IOCLK
+#elif (MN10300_SRC_IOCLK / 8 + HZ / 2) / HZ - 1 <= TMJCBR_MAX
+# define IOCLK_PRESCALE 8
+# define JC_TIMER_CLKSRC TM0MD_SRC_IOCLK_8
+# define TSC_TIMER_CLKSRC TM4MD_SRC_IOCLK_8
+#elif (MN10300_SRC_IOCLK / 32 + HZ / 2) / HZ - 1 <= TMJCBR_MAX
+# define IOCLK_PRESCALE 32
+# define JC_TIMER_CLKSRC TM0MD_SRC_IOCLK_32
+# define TSC_TIMER_CLKSRC TM4MD_SRC_IOCLK_32
+#else
+# error You lose.
+#endif
+
+#define MN10300_JCCLK (MN10300_SRC_IOCLK / IOCLK_PRESCALE)
+#define MN10300_TSCCLK (MN10300_SRC_IOCLK / IOCLK_PRESCALE)
+
+#define MN10300_JC_PER_HZ ((MN10300_JCCLK + HZ / 2) / HZ)
+#define MN10300_TSC_PER_HZ ((MN10300_TSCCLK + HZ / 2) / HZ)
+
+static inline void stop_jiffies_counter(void)
{
- unsigned rate;
- u16 md, t16;
-
- /* use as little prescaling as possible to avoid losing accuracy */
- md = TM0MD_SRC_IOCLK;
- rate = MN10300_JCCLK / HZ;
-
- if (rate > TMJCBR_MAX) {
- md = TM0MD_SRC_IOCLK_8;
- rate = MN10300_JCCLK / 8 / HZ;
-
- if (rate > TMJCBR_MAX) {
- md = TM0MD_SRC_IOCLK_32;
- rate = MN10300_JCCLK / 32 / HZ;
-
- if (rate > TMJCBR_MAX)
- BUG();
- }
- }
+ u16 tmp;
+ TM01MD = JC_TIMER_CLKSRC | TM1MD_SRC_TM0CASCADE << 8;
+ tmp = TM01MD;
+}
- TMJCBR = rate - 1;
- t16 = TMJCBR;
+static inline void reload_jiffies_counter(u32 cnt)
+{
+ u32 tmp;
- TMJCMD =
- md |
- TM1MD_SRC_TM0CASCADE << 8 |
- TM0MD_INIT_COUNTER |
- TM1MD_INIT_COUNTER << 8;
+ TM01BR = cnt;
+ tmp = TM01BR;
- TMJCMD =
- md |
- TM1MD_SRC_TM0CASCADE << 8 |
- TM0MD_COUNT_ENABLE |
- TM1MD_COUNT_ENABLE << 8;
+ TM01MD = JC_TIMER_CLKSRC | \
+ TM1MD_SRC_TM0CASCADE << 8 | \
+ TM0MD_INIT_COUNTER | \
+ TM1MD_INIT_COUNTER << 8;
- t16 = TMJCMD;
- TMJCICR |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST;
- t16 = TMJCICR;
-}
+ TM01MD = JC_TIMER_CLKSRC | \
+ TM1MD_SRC_TM0CASCADE << 8 | \
+ TM0MD_COUNT_ENABLE | \
+ TM1MD_COUNT_ENABLE << 8;
-static inline void shutdown_jiffies_counter(void)
-{
+ tmp = TM01MD;
}
#endif /* !__ASSEMBLY__ */
@@ -94,29 +99,39 @@ static inline void shutdown_jiffies_counter(void)
static inline void startup_timestamp_counter(void)
{
+ u32 t32;
+
/* set up timer 4 & 5 cascaded as a 32-bit counter to count real time
* - count down from 4Gig-1 to 0 and wrap at IOCLK rate
*/
TM45BR = TMTSCBR_MAX;
+ t32 = TM45BR;
- TM4MD = TM4MD_SRC_IOCLK;
+ TM4MD = TSC_TIMER_CLKSRC;
TM4MD |= TM4MD_INIT_COUNTER;
TM4MD &= ~TM4MD_INIT_COUNTER;
TM4ICR = 0;
+ t32 = TM4ICR;
TM5MD = TM5MD_SRC_TM4CASCADE;
TM5MD |= TM5MD_INIT_COUNTER;
TM5MD &= ~TM5MD_INIT_COUNTER;
TM5ICR = 0;
+ t32 = TM5ICR;
TM5MD |= TM5MD_COUNT_ENABLE;
TM4MD |= TM4MD_COUNT_ENABLE;
+ t32 = TM5MD;
+ t32 = TM4MD;
}
static inline void shutdown_timestamp_counter(void)
{
+ u8 t8;
TM4MD = 0;
TM5MD = 0;
+ t8 = TM4MD;
+ t8 = TM5MD;
}
/*
@@ -127,7 +142,7 @@ typedef unsigned long cycles_t;
static inline cycles_t read_timestamp_counter(void)
{
- return (cycles_t) TMTSCBC;
+ return (cycles_t)~TMTSCBC;
}
#endif /* !__ASSEMBLY__ */
diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.c b/arch/mn10300/unit-asb2305/pci-asb2305.c
index 45b40ac6c464..8e6763e6f250 100644
--- a/arch/mn10300/unit-asb2305/pci-asb2305.c
+++ b/arch/mn10300/unit-asb2305/pci-asb2305.c
@@ -93,7 +93,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
struct pci_bus *bus;
struct pci_dev *dev;
int idx;
- struct resource *r, *pr;
+ struct resource *r;
/* Depth-First Search on bus tree */
list_for_each_entry(bus, bus_list, node) {
@@ -105,10 +105,8 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
r = &dev->resource[idx];
if (!r->flags)
continue;
- pr = pci_find_parent_resource(dev, r);
if (!r->start ||
- !pr ||
- request_resource(pr, r) < 0) {
+ pci_claim_resource(dev, idx) < 0) {
printk(KERN_ERR "PCI:"
" Cannot allocate resource"
" region %d of bridge %s\n",
@@ -131,7 +129,7 @@ static void __init pcibios_allocate_resources(int pass)
struct pci_dev *dev = NULL;
int idx, disabled;
u16 command;
- struct resource *r, *pr;
+ struct resource *r;
for_each_pci_dev(dev) {
pci_read_config_word(dev, PCI_COMMAND, &command);
@@ -150,8 +148,7 @@ static void __init pcibios_allocate_resources(int pass)
" (f=%lx, d=%d, p=%d)\n",
pci_name(dev), r->start, r->end, r->flags,
disabled, pass);
- pr = pci_find_parent_resource(dev, r);
- if (!pr || request_resource(pr, r) < 0) {
+ if (pci_claim_resource(dev, idx) < 0) {
printk(KERN_ERR "PCI:"
" Cannot allocate resource"
" region %d of device %s\n",
@@ -184,7 +181,7 @@ static void __init pcibios_allocate_resources(int pass)
static int __init pcibios_assign_resources(void)
{
struct pci_dev *dev = NULL;
- struct resource *r, *pr;
+ struct resource *r;
if (!(pci_probe & PCI_ASSIGN_ROMS)) {
/* Try to use BIOS settings for ROMs, otherwise let
@@ -194,8 +191,7 @@ static int __init pcibios_assign_resources(void)
r = &dev->resource[PCI_ROM_RESOURCE];
if (!r->flags || !r->start)
continue;
- pr = pci_find_parent_resource(dev, r);
- if (!pr || request_resource(pr, r) < 0) {
+ if (pci_claim_resource(dev, PCI_ROM_RESOURCE) < 0) {
r->end -= r->start;
r->start = 0;
}
diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c
index 6d8720a0a599..a4954fe82094 100644
--- a/arch/mn10300/unit-asb2305/pci.c
+++ b/arch/mn10300/unit-asb2305/pci.c
@@ -503,7 +503,7 @@ asmlinkage void __init unit_pci_init(void)
struct pci_ops *o = &pci_direct_ampci;
u32 x;
- set_intr_level(XIRQ1, GxICR_LEVEL_3);
+ set_intr_level(XIRQ1, NUM2GxICR_LEVEL(CONFIG_PCI_IRQ_LEVEL));
memset(&bus, 0, sizeof(bus));
diff --git a/arch/mn10300/unit-asb2305/unit-init.c b/arch/mn10300/unit-asb2305/unit-init.c
index a76c8e0ab90f..e1becd6b7571 100644
--- a/arch/mn10300/unit-asb2305/unit-init.c
+++ b/arch/mn10300/unit-asb2305/unit-init.c
@@ -26,8 +26,10 @@ asmlinkage void __init unit_init(void)
{
#ifndef CONFIG_GDBSTUB_ON_TTYSx
/* set the 16550 interrupt line to level 3 if not being used for GDB */
- set_intr_level(XIRQ0, GxICR_LEVEL_3);
+#ifdef CONFIG_EXT_SERIAL_IRQ_LEVEL
+ set_intr_level(XIRQ0, NUM2GxICR_LEVEL(CONFIG_EXT_SERIAL_IRQ_LEVEL));
#endif
+#endif /* CONFIG_GDBSTUB_ON_TTYSx */
}
/*
@@ -51,7 +53,7 @@ void __init unit_init_IRQ(void)
switch (GET_XIRQ_TRIGGER(extnum)) {
case XIRQ_TRIGGER_HILEVEL:
case XIRQ_TRIGGER_LOWLEVEL:
- set_intr_postackable(XIRQ2IRQ(extnum));
+ mn10300_set_lateack_irq_type(XIRQ2IRQ(extnum));
break;
default:
break;
diff --git a/arch/mn10300/unit-asb2364/Makefile b/arch/mn10300/unit-asb2364/Makefile
new file mode 100644
index 000000000000..b3263ecfc4ff
--- /dev/null
+++ b/arch/mn10300/unit-asb2364/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+obj-y := unit-init.o leds.o irq-fpga.o
+
+obj-$(CONFIG_SMSC911X) += smsc911x.o
diff --git a/arch/mn10300/unit-asb2364/include/unit/clock.h b/arch/mn10300/unit-asb2364/include/unit/clock.h
new file mode 100644
index 000000000000..d34ac9a7508b
--- /dev/null
+++ b/arch/mn10300/unit-asb2364/include/unit/clock.h
@@ -0,0 +1,29 @@
+/* clock.h: unit-specific clocks
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * Modified by Matsushita Electric Industrial Co., Ltd.
+ * Modifications:
+ * 23-Feb-2007 MEI Add define for watchdog timer.
+ *
+ * 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 _ASM_UNIT_CLOCK_H
+#define _ASM_UNIT_CLOCK_H
+
+#ifndef __ASSEMBLY__
+
+#define MN10300_IOCLK 100000000UL /* for DDR800 */
+/*#define MN10300_IOCLK 83333333UL */ /* for DDR667 */
+#define MN10300_IOBCLK MN10300_IOCLK /* IOBCLK is equal to IOCLK */
+
+#endif /* !__ASSEMBLY__ */
+
+#define MN10300_WDCLK 27000000UL
+
+#endif /* _ASM_UNIT_CLOCK_H */
diff --git a/arch/mn10300/unit-asb2364/include/unit/fpga-regs.h b/arch/mn10300/unit-asb2364/include/unit/fpga-regs.h
new file mode 100644
index 000000000000..7cf12054db65
--- /dev/null
+++ b/arch/mn10300/unit-asb2364/include/unit/fpga-regs.h
@@ -0,0 +1,52 @@
+/* ASB2364 FPGA registers
+ */
+
+#ifndef _ASM_UNIT_FPGA_REGS_H
+#define _ASM_UNIT_FPGA_REGS_H
+
+#include <asm/cpu-regs.h>
+
+#ifdef __KERNEL__
+
+#define ASB2364_FPGA_REG_RESET_LAN __SYSREG(0xa9001300, u16)
+#define ASB2364_FPGA_REG_RESET_UART __SYSREG(0xa9001304, u16)
+#define ASB2364_FPGA_REG_RESET_I2C __SYSREG(0xa9001308, u16)
+#define ASB2364_FPGA_REG_RESET_USB __SYSREG(0xa900130c, u16)
+#define ASB2364_FPGA_REG_RESET_AV __SYSREG(0xa9001310, u16)
+
+#define ASB2364_FPGA_REG_IRQ(X) __SYSREG(0xa9001590+((X)*4), u16)
+#define ASB2364_FPGA_REG_IRQ_LAN ASB2364_FPGA_REG_IRQ(0)
+#define ASB2364_FPGA_REG_IRQ_UART ASB2364_FPGA_REG_IRQ(1)
+#define ASB2364_FPGA_REG_IRQ_I2C ASB2364_FPGA_REG_IRQ(2)
+#define ASB2364_FPGA_REG_IRQ_USB ASB2364_FPGA_REG_IRQ(3)
+#define ASB2364_FPGA_REG_IRQ_FPGA ASB2364_FPGA_REG_IRQ(5)
+
+#define ASB2364_FPGA_REG_MASK(X) __SYSREG(0xa9001590+((X)*4), u16)
+#define ASB2364_FPGA_REG_MASK_LAN ASB2364_FPGA_REG_MASK(0)
+#define ASB2364_FPGA_REG_MASK_UART ASB2364_FPGA_REG_MASK(1)
+#define ASB2364_FPGA_REG_MASK_I2C ASB2364_FPGA_REG_MASK(2)
+#define ASB2364_FPGA_REG_MASK_USB ASB2364_FPGA_REG_MASK(3)
+#define ASB2364_FPGA_REG_MASK_FPGA ASB2364_FPGA_REG_MASK(5)
+
+#define ASB2364_FPGA_REG_CPLD5_SET1 __SYSREG(0xa9002500, u16)
+#define ASB2364_FPGA_REG_CPLD5_SET2 __SYSREG(0xa9002504, u16)
+#define ASB2364_FPGA_REG_CPLD6_SET1 __SYSREG(0xa9002600, u16)
+#define ASB2364_FPGA_REG_CPLD6_SET2 __SYSREG(0xa9002604, u16)
+#define ASB2364_FPGA_REG_CPLD7_SET1 __SYSREG(0xa9002700, u16)
+#define ASB2364_FPGA_REG_CPLD7_SET2 __SYSREG(0xa9002704, u16)
+#define ASB2364_FPGA_REG_CPLD8_SET1 __SYSREG(0xa9002800, u16)
+#define ASB2364_FPGA_REG_CPLD8_SET2 __SYSREG(0xa9002804, u16)
+#define ASB2364_FPGA_REG_CPLD9_SET1 __SYSREG(0xa9002900, u16)
+#define ASB2364_FPGA_REG_CPLD9_SET2 __SYSREG(0xa9002904, u16)
+#define ASB2364_FPGA_REG_CPLD10_SET1 __SYSREG(0xa9002a00, u16)
+#define ASB2364_FPGA_REG_CPLD10_SET2 __SYSREG(0xa9002a04, u16)
+
+#define SyncExBus() \
+ do { \
+ unsigned short w; \
+ w = *(volatile short *)0xa9000000; \
+ } while (0)
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_UNIT_FPGA_REGS_H */
diff --git a/arch/mn10300/unit-asb2364/include/unit/irq.h b/arch/mn10300/unit-asb2364/include/unit/irq.h
new file mode 100644
index 000000000000..786148e46565
--- /dev/null
+++ b/arch/mn10300/unit-asb2364/include/unit/irq.h
@@ -0,0 +1,35 @@
+/* ASB2364 FPGA irq numbers
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef _UNIT_IRQ_H
+#define _UNIT_IRQ_H
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_SMP
+#define NR_CPU_IRQS GxICR_NUM_EXT_IRQS
+#else
+#define NR_CPU_IRQS GxICR_NUM_IRQS
+#endif
+
+enum {
+ FPGA_LAN_IRQ = NR_CPU_IRQS,
+ FPGA_UART_IRQ,
+ FPGA_I2C_IRQ,
+ FPGA_USB_IRQ,
+ FPGA_RESERVED_IRQ,
+ FPGA_FPGA_IRQ,
+ NR_IRQS
+};
+
+extern void __init irq_fpga_init(void);
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _UNIT_IRQ_H */
diff --git a/arch/mn10300/unit-asb2364/include/unit/leds.h b/arch/mn10300/unit-asb2364/include/unit/leds.h
new file mode 100644
index 000000000000..03a3933ad323
--- /dev/null
+++ b/arch/mn10300/unit-asb2364/include/unit/leds.h
@@ -0,0 +1,54 @@
+/* Unit-specific leds
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ASM_UNIT_LEDS_H
+#define _ASM_UNIT_LEDS_H
+
+#include <asm/pio-regs.h>
+#include <asm/cpu-regs.h>
+#include <asm/exceptions.h>
+
+#define MN10300_USE_7SEGLEDS 0
+
+#define ASB2364_7SEGLEDS __SYSREG(0xA9001630, u32)
+
+/*
+ * use the 7-segment LEDs to indicate states
+ */
+
+#if MN10300_USE_7SEGLEDS
+/* flip the 7-segment LEDs between "Gdb-" and "----" */
+#define mn10300_set_gdbleds(ONOFF) \
+ do { \
+ ASB2364_7SEGLEDS = (ONOFF) ? 0x8543077f : 0x7f7f7f7f; \
+ } while (0)
+#else
+#define mn10300_set_gdbleds(ONOFF) do {} while (0)
+#endif
+
+#if MN10300_USE_7SEGLEDS
+/* indicate double-fault by displaying "db-f" on the LEDs */
+#define mn10300_set_dbfleds \
+ mov 0x43077f1d,d0 ; \
+ mov d0,(ASB2364_7SEGLEDS)
+#else
+#define mn10300_set_dbfleds
+#endif
+
+#ifndef __ASSEMBLY__
+extern void peripheral_leds_display_exception(enum exception_code);
+extern void peripheral_leds_led_chase(void);
+extern void peripheral_leds7x4_display_dec(unsigned int, unsigned int);
+extern void peripheral_leds7x4_display_hex(unsigned int, unsigned int);
+extern void debug_to_serial(const char *, int);
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_UNIT_LEDS_H */
diff --git a/arch/mn10300/unit-asb2364/include/unit/serial.h b/arch/mn10300/unit-asb2364/include/unit/serial.h
new file mode 100644
index 000000000000..7f048bbfdfd7
--- /dev/null
+++ b/arch/mn10300/unit-asb2364/include/unit/serial.h
@@ -0,0 +1,151 @@
+/* Unit-specific 8250 serial ports
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ASM_UNIT_SERIAL_H
+#define _ASM_UNIT_SERIAL_H
+
+#include <asm/cpu-regs.h>
+#include <proc/irq.h>
+#include <unit/fpga-regs.h>
+#include <linux/serial_reg.h>
+
+#define SERIAL_PORT0_BASE_ADDRESS 0xA8200000
+
+#define SERIAL_IRQ XIRQ1 /* single serial (TL16C550C) (Lo) */
+
+/*
+ * The ASB2364 has an 12.288 MHz clock
+ * for your UART.
+ *
+ * It'd be nice if someone built a serial card with a 24.576 MHz
+ * clock, since the 16550A is capable of handling a top speed of 1.5
+ * megabits/second; but this requires the faster clock.
+ */
+#define BASE_BAUD (12288000 / 16)
+
+/*
+ * dispose of the /dev/ttyS0 and /dev/ttyS1 serial ports
+ */
+#ifndef CONFIG_GDBSTUB_ON_TTYSx
+
+#define SERIAL_PORT_DFNS \
+ { \
+ .baud_base = BASE_BAUD, \
+ .irq = SERIAL_IRQ, \
+ .flags = STD_COM_FLAGS, \
+ .iomem_base = (u8 *) SERIAL_PORT0_BASE_ADDRESS, \
+ .iomem_reg_shift = 1, \
+ .io_type = SERIAL_IO_MEM, \
+ },
+
+#ifndef __ASSEMBLY__
+
+static inline void __debug_to_serial(const char *p, int n)
+{
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#else /* CONFIG_GDBSTUB_ON_TTYSx */
+
+#define SERIAL_PORT_DFNS /* stolen by gdb-stub */
+
+#if defined(CONFIG_GDBSTUB_ON_TTYS0)
+#define GDBPORT_SERIAL_RX __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_RX * 4, u8)
+#define GDBPORT_SERIAL_TX __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_TX * 4, u8)
+#define GDBPORT_SERIAL_DLL __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_DLL * 4, u8)
+#define GDBPORT_SERIAL_DLM __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_DLM * 4, u8)
+#define GDBPORT_SERIAL_IER __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_IER * 4, u8)
+#define GDBPORT_SERIAL_IIR __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_IIR * 4, u8)
+#define GDBPORT_SERIAL_FCR __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_FCR * 4, u8)
+#define GDBPORT_SERIAL_LCR __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_LCR * 4, u8)
+#define GDBPORT_SERIAL_MCR __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_MCR * 4, u8)
+#define GDBPORT_SERIAL_LSR __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_LSR * 4, u8)
+#define GDBPORT_SERIAL_MSR __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_MSR * 4, u8)
+#define GDBPORT_SERIAL_SCR __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_SCR * 4, u8)
+#define GDBPORT_SERIAL_IRQ SERIAL_IRQ
+
+#elif defined(CONFIG_GDBSTUB_ON_TTYS1)
+#error The ASB2364 does not have a /dev/ttyS1
+#endif
+
+#ifndef __ASSEMBLY__
+
+static inline void __debug_to_serial(const char *p, int n)
+{
+ char ch;
+
+#define LSR_WAIT_FOR(STATE) \
+ do {} while (!(GDBPORT_SERIAL_LSR & UART_LSR_##STATE))
+#define FLOWCTL_QUERY(LINE) \
+ ({ GDBPORT_SERIAL_MSR & UART_MSR_##LINE; })
+#define FLOWCTL_WAIT_FOR(LINE) \
+ do {} while (!(GDBPORT_SERIAL_MSR & UART_MSR_##LINE))
+#define FLOWCTL_CLEAR(LINE) \
+ do { GDBPORT_SERIAL_MCR &= ~UART_MCR_##LINE; } while (0)
+#define FLOWCTL_SET(LINE) \
+ do { GDBPORT_SERIAL_MCR |= UART_MCR_##LINE; } while (0)
+
+ FLOWCTL_SET(DTR);
+
+ for (; n > 0; n--) {
+ LSR_WAIT_FOR(THRE);
+ FLOWCTL_WAIT_FOR(CTS);
+
+ ch = *p++;
+ if (ch == 0x0a) {
+ GDBPORT_SERIAL_TX = 0x0d;
+ LSR_WAIT_FOR(THRE);
+ FLOWCTL_WAIT_FOR(CTS);
+ }
+ GDBPORT_SERIAL_TX = ch;
+ }
+
+ FLOWCTL_CLEAR(DTR);
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* CONFIG_GDBSTUB_ON_TTYSx */
+
+#define SERIAL_INITIALIZE \
+do { \
+ /* release reset */ \
+ ASB2364_FPGA_REG_RESET_UART = 0x0001; \
+ SyncExBus(); \
+} while (0)
+
+#define SERIAL_CHECK_INTERRUPT \
+do { \
+ if ((ASB2364_FPGA_REG_IRQ_UART & 0x0001) == 0x0001) { \
+ return IRQ_NONE; \
+ } \
+} while (0)
+
+#define SERIAL_CLEAR_INTERRUPT \
+do { \
+ ASB2364_FPGA_REG_IRQ_UART = 0x0001; \
+ SyncExBus(); \
+} while (0)
+
+#define SERIAL_SET_INT_MASK \
+do { \
+ ASB2364_FPGA_REG_MASK_UART = 0x0001; \
+ SyncExBus(); \
+} while (0)
+
+#define SERIAL_CLEAR_INT_MASK \
+do { \
+ ASB2364_FPGA_REG_MASK_UART = 0x0000; \
+ SyncExBus(); \
+} while (0)
+
+#endif /* _ASM_UNIT_SERIAL_H */
diff --git a/arch/mn10300/unit-asb2364/include/unit/smsc911x.h b/arch/mn10300/unit-asb2364/include/unit/smsc911x.h
new file mode 100644
index 000000000000..4c1ede535fa9
--- /dev/null
+++ b/arch/mn10300/unit-asb2364/include/unit/smsc911x.h
@@ -0,0 +1,171 @@
+/* Support for the SMSC911x NIC
+ *
+ * Copyright (C) 2006 Matsushita Electric Industrial Co., 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 _ASM_UNIT_SMSC911X_H
+#define _ASM_UNIT_SMSC911X_H
+
+#include <linux/netdevice.h>
+#include <proc/irq.h>
+#include <unit/fpga-regs.h>
+
+#define MN10300_USE_EXT_EEPROM
+
+
+#define SMSC911X_BASE 0xA8000000UL
+#define SMSC911X_BASE_END 0xA8000100UL
+#define SMSC911X_IRQ FPGA_LAN_IRQ
+
+/*
+ * Allow the FPGA to be initialised by the SMSC911x driver
+ */
+#undef SMSC_INITIALIZE
+#define SMSC_INITIALIZE() \
+do { \
+ /* release reset */ \
+ ASB2364_FPGA_REG_RESET_LAN = 0x0001; \
+ SyncExBus(); \
+} while (0)
+
+#ifdef MN10300_USE_EXT_EEPROM
+#include <linux/delay.h>
+#include <unit/clock.h>
+
+#define EEPROM_ADDRESS 0xA0
+#define MAC_OFFSET 0x0008
+#define USE_IIC_CH 0 /* 0 or 1 */
+#define IIC_OFFSET (0x80000 * USE_IIC_CH)
+#define IIC_DTRM __SYSREG(0xd8400000 + IIC_OFFSET, u32)
+#define IIC_DREC __SYSREG(0xd8400004 + IIC_OFFSET, u32)
+#define IIC_MYADD __SYSREG(0xd8400008 + IIC_OFFSET, u32)
+#define IIC_CLK __SYSREG(0xd840000c + IIC_OFFSET, u32)
+#define IIC_BRST __SYSREG(0xd8400010 + IIC_OFFSET, u32)
+#define IIC_HOLD __SYSREG(0xd8400014 + IIC_OFFSET, u32)
+#define IIC_BSTS __SYSREG(0xd8400018 + IIC_OFFSET, u32)
+#define IIC_ICR __SYSREG(0xd4000080 + 4 * USE_IIC_CH, u16)
+
+#define IIC_CLK_PLS ((unsigned short)(MN10300_IOCLK / 100000 - 1))
+#define IIC_CLK_LOW ((unsigned short)(IIC_CLK_PLS / 2))
+
+#define SYS_IIC_DTRM_Bit_STA ((unsigned short)0x0400)
+#define SYS_IIC_DTRM_Bit_STO ((unsigned short)0x0200)
+#define SYS_IIC_DTRM_Bit_ACK ((unsigned short)0x0100)
+#define SYS_IIC_DTRM_Bit_DATA ((unsigned short)0x00FF)
+
+static inline void POLL_INT_REQ(volatile u16 *icr)
+{
+ unsigned long flags;
+ u16 tmp;
+
+ while (!(*icr & GxICR_REQUEST))
+ ;
+ flags = arch_local_cli_save();
+ tmp = *icr;
+ *icr = (tmp & GxICR_LEVEL) | GxICR_DETECT;
+ tmp = *icr;
+ arch_local_irq_restore(flags);
+}
+
+/*
+ * Implement the SMSC911x hook for MAC address retrieval
+ */
+#undef smsc_get_mac
+static inline int smsc_get_mac(struct net_device *dev)
+{
+ unsigned char *mac_buf = dev->dev_addr;
+ int i;
+ unsigned short value;
+ unsigned int data;
+ int mac_length = 6;
+ int check;
+ u16 orig_gicr, tmp;
+ unsigned long flags;
+
+ /* save original GnICR and clear GnICR.IE */
+ flags = arch_local_cli_save();
+ orig_gicr = IIC_ICR;
+ IIC_ICR = orig_gicr & GxICR_LEVEL;
+ tmp = IIC_ICR;
+ arch_local_irq_restore(flags);
+
+ IIC_MYADD = 0x00000008;
+ IIC_CLK = (IIC_CLK_LOW << 16) + (IIC_CLK_PLS);
+ /* bus hung recovery */
+
+ while (1) {
+ check = 0;
+ for (i = 0; i < 3; i++) {
+ if ((IIC_BSTS & 0x00000003) == 0x00000003)
+ check++;
+ udelay(3);
+ }
+
+ if (check == 3) {
+ IIC_BRST = 0x00000003;
+ break;
+ } else {
+ for (i = 0; i < 3; i++) {
+ IIC_BRST = 0x00000002;
+ udelay(8);
+ IIC_BRST = 0x00000003;
+ udelay(8);
+ }
+ }
+ }
+
+ IIC_BRST = 0x00000002;
+ IIC_BRST = 0x00000003;
+
+ value = SYS_IIC_DTRM_Bit_STA | SYS_IIC_DTRM_Bit_ACK;
+ value |= (((unsigned short)EEPROM_ADDRESS & SYS_IIC_DTRM_Bit_DATA) |
+ (unsigned short)0x0000);
+ IIC_DTRM = value;
+ POLL_INT_REQ(&IIC_ICR);
+
+ /** send offset of MAC address in EEPROM **/
+ IIC_DTRM = (unsigned char)((MAC_OFFSET & 0xFF00) >> 8);
+ POLL_INT_REQ(&IIC_ICR);
+
+ IIC_DTRM = (unsigned char)(MAC_OFFSET & 0x00FF);
+ POLL_INT_REQ(&IIC_ICR);
+
+ udelay(1000);
+
+ value = SYS_IIC_DTRM_Bit_STA;
+ value |= (((unsigned short)EEPROM_ADDRESS & SYS_IIC_DTRM_Bit_DATA) |
+ (unsigned short)0x0001);
+ IIC_DTRM = value;
+ POLL_INT_REQ(&IIC_ICR);
+
+ IIC_DTRM = 0x00000000;
+ while (mac_length > 0) {
+ POLL_INT_REQ(&IIC_ICR);
+
+ data = IIC_DREC;
+ mac_length--;
+ if (mac_length == 0)
+ value = 0x00000300; /* stop IIC bus */
+ else if (mac_length == 1)
+ value = 0x00000100; /* no ack */
+ else
+ value = 0x00000000; /* ack */
+ IIC_DTRM = value;
+ *mac_buf++ = (unsigned char)(data & 0xff);
+ }
+
+ /* restore GnICR.LV and GnICR.IE */
+ flags = arch_local_cli_save();
+ IIC_ICR = (orig_gicr & (GxICR_LEVEL | GxICR_ENABLE));
+ tmp = IIC_ICR;
+ arch_local_irq_restore(flags);
+
+ return 0;
+}
+#endif /* MN10300_USE_EXT_EEPROM */
+#endif /* _ASM_UNIT_SMSC911X_H */
diff --git a/arch/mn10300/unit-asb2364/include/unit/timex.h b/arch/mn10300/unit-asb2364/include/unit/timex.h
new file mode 100644
index 000000000000..ddb7ed010706
--- /dev/null
+++ b/arch/mn10300/unit-asb2364/include/unit/timex.h
@@ -0,0 +1,159 @@
+/* timex.h: MN2WS0038 architecture timer specifications
+ *
+ * Copyright (C) 2002, 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _ASM_UNIT_TIMEX_H
+#define _ASM_UNIT_TIMEX_H
+
+#ifndef __ASSEMBLY__
+#include <linux/irq.h>
+#endif /* __ASSEMBLY__ */
+
+#include <asm/timer-regs.h>
+#include <unit/clock.h>
+#include <asm/param.h>
+
+/*
+ * jiffies counter specifications
+ */
+
+#define TMJCBR_MAX 0xffffff /* 24bit */
+#define TMJCIRQ TMTIRQ
+
+#ifndef __ASSEMBLY__
+
+#define MN10300_SRC_IOBCLK MN10300_IOBCLK
+
+#ifndef HZ
+# error HZ undeclared.
+#endif /* !HZ */
+
+#define MN10300_JCCLK (MN10300_SRC_IOBCLK)
+#define MN10300_TSCCLK (MN10300_SRC_IOBCLK)
+
+#define MN10300_JC_PER_HZ ((MN10300_JCCLK + HZ / 2) / HZ)
+#define MN10300_TSC_PER_HZ ((MN10300_TSCCLK + HZ / 2) / HZ)
+
+/* Check bit width of MTM interval value that sets base register */
+#if (MN10300_JC_PER_HZ - 1) > TMJCBR_MAX
+# error MTM tick timer interval value is overflow.
+#endif
+
+static inline void stop_jiffies_counter(void)
+{
+ u16 tmp;
+ TMTMD = 0;
+ tmp = TMTMD;
+}
+
+static inline void reload_jiffies_counter(u32 cnt)
+{
+ u32 tmp;
+
+ TMTBR = cnt;
+ tmp = TMTBR;
+
+ TMTMD = TMTMD_TMTLDE;
+ TMTMD = TMTMD_TMTCNE;
+ tmp = TMTMD;
+}
+
+#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_CLOCKEVENTS) && \
+ !defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+/*
+ * If we aren't using broadcasting, each core needs its own event timer.
+ * Since CPU0 uses the tick timer which is 24-bits, we use timer 4 & 5
+ * cascaded to 32-bits for CPU1 (but only really use 24-bits to match
+ * CPU0).
+ */
+
+#define TMJC1IRQ TM5IRQ
+
+static inline void stop_jiffies_counter1(void)
+{
+ u8 tmp;
+ TM4MD = 0;
+ TM5MD = 0;
+ tmp = TM4MD;
+ tmp = TM5MD;
+}
+
+static inline void reload_jiffies_counter1(u32 cnt)
+{
+ u32 tmp;
+
+ TM45BR = cnt;
+ tmp = TM45BR;
+
+ TM4MD = TM4MD_INIT_COUNTER;
+ tmp = TM4MD;
+
+ TM5MD = TM5MD_SRC_TM4CASCADE | TM5MD_INIT_COUNTER;
+ TM5MD = TM5MD_SRC_TM4CASCADE | TM5MD_COUNT_ENABLE;
+ tmp = TM5MD;
+
+ TM4MD = TM4MD_COUNT_ENABLE;
+ tmp = TM4MD;
+}
+#endif /* CONFIG_SMP&GENERIC_CLOCKEVENTS&!GENERIC_CLOCKEVENTS_BROADCAST */
+
+#endif /* !__ASSEMBLY__ */
+
+
+/*
+ * timestamp counter specifications
+ */
+#define TMTSCBR_MAX 0xffffffff
+
+#ifndef __ASSEMBLY__
+
+/* Use 32-bit timestamp counter */
+#define TMTSCMD TMSMD
+#define TMTSCBR TMSBR
+#define TMTSCBC TMSBC
+#define TMTSCICR TMSICR
+
+static inline void startup_timestamp_counter(void)
+{
+ u32 sync;
+
+ /* set up TMS(Timestamp) 32bit timer register to count real time
+ * - count down from 4Gig-1 to 0 and wrap at IOBCLK rate
+ */
+
+ TMTSCBR = TMTSCBR_MAX;
+ sync = TMTSCBR;
+
+ TMTSCICR = 0;
+ sync = TMTSCICR;
+
+ TMTSCMD = TMTMD_TMTLDE;
+ TMTSCMD = TMTMD_TMTCNE;
+ sync = TMTSCMD;
+}
+
+static inline void shutdown_timestamp_counter(void)
+{
+ TMTSCMD = 0;
+}
+
+/*
+ * we use a cascaded pair of 16-bit down-counting timers to count I/O
+ * clock cycles for the purposes of time keeping
+ */
+typedef unsigned long cycles_t;
+
+static inline cycles_t read_timestamp_counter(void)
+{
+ return (cycles_t)~TMTSCBC;
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_UNIT_TIMEX_H */
diff --git a/arch/mn10300/unit-asb2364/irq-fpga.c b/arch/mn10300/unit-asb2364/irq-fpga.c
new file mode 100644
index 000000000000..fcf29754e4d1
--- /dev/null
+++ b/arch/mn10300/unit-asb2364/irq-fpga.c
@@ -0,0 +1,96 @@
+/* ASB2364 FPGA interrupt multiplexing
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <unit/fpga-regs.h>
+
+/*
+ * FPGA PIC operations
+ */
+static void asb2364_fpga_mask(unsigned int irq)
+{
+ ASB2364_FPGA_REG_MASK(irq - NR_CPU_IRQS) = 0x0001;
+ SyncExBus();
+}
+
+static void asb2364_fpga_ack(unsigned int irq)
+{
+ ASB2364_FPGA_REG_IRQ(irq - NR_CPU_IRQS) = 0x0001;
+ SyncExBus();
+}
+
+static void asb2364_fpga_mask_ack(unsigned int irq)
+{
+ ASB2364_FPGA_REG_MASK(irq - NR_CPU_IRQS) = 0x0001;
+ SyncExBus();
+ ASB2364_FPGA_REG_IRQ(irq - NR_CPU_IRQS) = 0x0001;
+ SyncExBus();
+}
+
+static void asb2364_fpga_unmask(unsigned int irq)
+{
+ ASB2364_FPGA_REG_MASK(irq - NR_CPU_IRQS) = 0x0000;
+ SyncExBus();
+}
+
+static struct irq_chip asb2364_fpga_pic = {
+ .name = "fpga",
+ .ack = asb2364_fpga_ack,
+ .mask = asb2364_fpga_mask,
+ .mask_ack = asb2364_fpga_mask_ack,
+ .unmask = asb2364_fpga_unmask,
+};
+
+/*
+ * FPGA PIC interrupt handler
+ */
+static irqreturn_t fpga_interrupt(int irq, void *_mask)
+{
+ if ((ASB2364_FPGA_REG_IRQ_LAN & 0x0001) != 0x0001)
+ generic_handle_irq(FPGA_LAN_IRQ);
+ if ((ASB2364_FPGA_REG_IRQ_UART & 0x0001) != 0x0001)
+ generic_handle_irq(FPGA_UART_IRQ);
+ if ((ASB2364_FPGA_REG_IRQ_I2C & 0x0001) != 0x0001)
+ generic_handle_irq(FPGA_I2C_IRQ);
+ if ((ASB2364_FPGA_REG_IRQ_USB & 0x0001) != 0x0001)
+ generic_handle_irq(FPGA_USB_IRQ);
+ if ((ASB2364_FPGA_REG_IRQ_FPGA & 0x0001) != 0x0001)
+ generic_handle_irq(FPGA_FPGA_IRQ);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Define an interrupt action for each FPGA PIC output
+ */
+static struct irqaction fpga_irq[] = {
+ [0] = {
+ .handler = fpga_interrupt,
+ .flags = IRQF_DISABLED | IRQF_SHARED,
+ .name = "fpga",
+ },
+};
+
+/*
+ * Initialise the FPGA's PIC
+ */
+void __init irq_fpga_init(void)
+{
+ int irq;
+
+ for (irq = NR_CPU_IRQS; irq < NR_IRQS; irq++)
+ set_irq_chip_and_handler(irq, &asb2364_fpga_pic, handle_level_irq);
+
+ /* the FPGA drives the XIRQ1 input on the CPU PIC */
+ setup_irq(XIRQ1, &fpga_irq[0]);
+}
diff --git a/arch/mn10300/unit-asb2364/leds.c b/arch/mn10300/unit-asb2364/leds.c
new file mode 100644
index 000000000000..1ff830c372b3
--- /dev/null
+++ b/arch/mn10300/unit-asb2364/leds.c
@@ -0,0 +1,98 @@
+/* leds.c: ASB2364 peripheral 7seg LEDs x4 support
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/intctl-regs.h>
+#include <asm/rtc-regs.h>
+#include <unit/leds.h>
+
+#if MN10300_USE_7SEGLEDS
+static const u8 asb2364_led_hex_tbl[16] = {
+ 0x80, 0xf2, 0x48, 0x60, 0x32, 0x24, 0x04, 0xf0,
+ 0x00, 0x20, 0x10, 0x06, 0x8c, 0x42, 0x0c, 0x1c
+};
+
+static const u32 asb2364_led_chase_tbl[6] = {
+ ~0x02020202, /* top - segA */
+ ~0x04040404, /* right top - segB */
+ ~0x08080808, /* right bottom - segC */
+ ~0x10101010, /* bottom - segD */
+ ~0x20202020, /* left bottom - segE */
+ ~0x40404040, /* left top - segF */
+};
+
+static unsigned asb2364_led_chase;
+
+void peripheral_leds7x4_display_dec(unsigned int val, unsigned int points)
+{
+ u32 leds;
+
+ leds = asb2364_led_hex_tbl[(val/1000) % 10];
+ leds <<= 8;
+ leds |= asb2364_led_hex_tbl[(val/100) % 10];
+ leds <<= 8;
+ leds |= asb2364_led_hex_tbl[(val/10) % 10];
+ leds <<= 8;
+ leds |= asb2364_led_hex_tbl[val % 10];
+ leds |= points^0x01010101;
+
+ ASB2364_7SEGLEDS = leds;
+}
+
+void peripheral_leds7x4_display_hex(unsigned int val, unsigned int points)
+{
+ u32 leds;
+
+ leds = asb2364_led_hex_tbl[(val/1000) % 10];
+ leds <<= 8;
+ leds |= asb2364_led_hex_tbl[(val/100) % 10];
+ leds <<= 8;
+ leds |= asb2364_led_hex_tbl[(val/10) % 10];
+ leds <<= 8;
+ leds |= asb2364_led_hex_tbl[val % 10];
+ leds |= points^0x01010101;
+
+ ASB2364_7SEGLEDS = leds;
+}
+
+/* display triple horizontal bar and exception code */
+void peripheral_leds_display_exception(enum exception_code code)
+{
+ u32 leds;
+
+ leds = asb2364_led_hex_tbl[(code/0x100) % 0x10];
+ leds <<= 8;
+ leds |= asb2364_led_hex_tbl[(code/0x10) % 0x10];
+ leds <<= 8;
+ leds |= asb2364_led_hex_tbl[code % 0x10];
+ leds |= 0x6d010101;
+
+ ASB2364_7SEGLEDS = leds;
+}
+
+void peripheral_leds_led_chase(void)
+{
+ ASB2364_7SEGLEDS = asb2364_led_chase_tbl[asb2364_led_chase];
+ asb2364_led_chase++;
+ if (asb2364_led_chase >= 6)
+ asb2364_led_chase = 0;
+}
+#else /* MN10300_USE_7SEGLEDS */
+void peripheral_leds7x4_display_dec(unsigned int val, unsigned int points) { }
+void peripheral_leds7x4_display_hex(unsigned int val, unsigned int points) { }
+void peripheral_leds_display_exception(enum exception_code code) { }
+void peripheral_leds_led_chase(void) { }
+#endif /* MN10300_USE_7SEGLEDS */
diff --git a/arch/mn10300/unit-asb2364/smsc911x.c b/arch/mn10300/unit-asb2364/smsc911x.c
new file mode 100644
index 000000000000..544a73e94c81
--- /dev/null
+++ b/arch/mn10300/unit-asb2364/smsc911x.c
@@ -0,0 +1,58 @@
+/* Specification for the SMSC911x NIC
+ *
+ * Copyright (C) 2006 Matsushita Electric Industrial Co., 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/smsc911x.h>
+#include <unit/smsc911x.h>
+
+static struct smsc911x_platform_config smsc911x_config = {
+ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+ .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+ .flags = SMSC911X_USE_32BIT,
+};
+
+static struct resource smsc911x_resources[] = {
+ [0] = {
+ .start = SMSC911X_BASE,
+ .end = SMSC911X_BASE_END,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = SMSC911X_IRQ,
+ .end = SMSC911X_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smsc911x_device = {
+ .name = "smsc911x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smsc911x_resources),
+ .resource = smsc911x_resources,
+ .dev = {
+ .platform_data = &smsc911x_config,
+ }
+};
+
+/*
+ * add platform devices
+ */
+static int __init unit_device_init(void)
+{
+ platform_device_register(&smsc911x_device);
+ return 0;
+}
+
+device_initcall(unit_device_init);
diff --git a/arch/mn10300/unit-asb2364/unit-init.c b/arch/mn10300/unit-asb2364/unit-init.c
new file mode 100644
index 000000000000..11440803db10
--- /dev/null
+++ b/arch/mn10300/unit-asb2364/unit-init.c
@@ -0,0 +1,88 @@
+/* ASB2364 initialisation
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/intctl-regs.h>
+#include <unit/fpga-regs.h>
+
+/*
+ * initialise some of the unit hardware before gdbstub is set up
+ */
+asmlinkage void __init unit_init(void)
+{
+ /* set up the external interrupts */
+
+ /* XIRQ[0]: NAND RXBY */
+ /* SET_XIRQ_TRIGGER(0, XIRQ_TRIGGER_LOWLEVEL); */
+
+ /* XIRQ[1]: LAN, UART, I2C, USB, PCI, FPGA */
+ SET_XIRQ_TRIGGER(1, XIRQ_TRIGGER_LOWLEVEL);
+
+ /* XIRQ[2]: Extend Slot 1-9 */
+ /* SET_XIRQ_TRIGGER(2, XIRQ_TRIGGER_LOWLEVEL); */
+
+#if defined(CONFIG_EXT_SERIAL_IRQ_LEVEL) && \
+ defined(CONFIG_ETHERNET_IRQ_LEVEL) && \
+ (CONFIG_EXT_SERIAL_IRQ_LEVEL != CONFIG_ETHERNET_IRQ_LEVEL)
+# error CONFIG_EXT_SERIAL_IRQ_LEVEL != CONFIG_ETHERNET_IRQ_LEVEL
+#endif
+
+#if defined(CONFIG_EXT_SERIAL_IRQ_LEVEL)
+ set_intr_level(XIRQ1, NUM2GxICR_LEVEL(CONFIG_EXT_SERIAL_IRQ_LEVEL));
+#elif defined(CONFIG_ETHERNET_IRQ_LEVEL)
+ set_intr_level(XIRQ1, NUM2GxICR_LEVEL(CONFIG_ETHERNET_IRQ_LEVEL));
+#endif
+}
+
+/*
+ * initialise the rest of the unit hardware after gdbstub is ready
+ */
+asmlinkage void __init unit_setup(void)
+{
+
+}
+
+/*
+ * initialise the external interrupts used by a unit of this type
+ */
+void __init unit_init_IRQ(void)
+{
+ unsigned int extnum;
+
+ for (extnum = 0 ; extnum < NR_XIRQS ; extnum++) {
+ switch (GET_XIRQ_TRIGGER(extnum)) {
+ /* LEVEL triggered interrupts should be made
+ * post-ACK'able as they hold their lines until
+ * serviced
+ */
+ case XIRQ_TRIGGER_HILEVEL:
+ case XIRQ_TRIGGER_LOWLEVEL:
+ mn10300_set_lateack_irq_type(XIRQ2IRQ(extnum));
+ break;
+ default:
+ break;
+ }
+ }
+
+#define IRQCTL __SYSREG(0xd5000090, u32)
+ IRQCTL |= 0x02;
+
+ irq_fpga_init();
+}
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 79a04a9394d5..abde955b1c21 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -19,6 +19,7 @@ config PARISC
select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select GENERIC_ATOMIC64 if !64BIT
+ select GENERIC_HARDIRQS_NO__DO_IRQ
help
The PA-RISC microprocessor is designed by Hewlett-Packard and used
in many of their workstations & servers (HP9000 700 and 800 series,
@@ -85,6 +86,9 @@ config IRQ_PER_CPU
bool
default y
+config GENERIC_HARDIRQS_NO__DO_IRQ
+ def_bool y
+
# unless you want to implement ACPI on PA-RISC ... ;-)
config PM
bool
diff --git a/arch/parisc/include/asm/cache.h b/arch/parisc/include/asm/cache.h
index 039880e7d2c9..47f11c707b65 100644
--- a/arch/parisc/include/asm/cache.h
+++ b/arch/parisc/include/asm/cache.h
@@ -24,8 +24,6 @@
#ifndef __ASSEMBLY__
-#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
-
#define SMP_CACHE_BYTES L1_CACHE_BYTES
#define ARCH_DMA_MINALIGN L1_CACHE_BYTES
diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h
index dba11aedce1b..f388a85bba11 100644
--- a/arch/parisc/include/asm/cacheflush.h
+++ b/arch/parisc/include/asm/cacheflush.h
@@ -126,20 +126,20 @@ static inline void *kmap(struct page *page)
#define kunmap(page) kunmap_parisc(page_address(page))
-static inline void *kmap_atomic(struct page *page, enum km_type idx)
+static inline void *__kmap_atomic(struct page *page)
{
pagefault_disable();
return page_address(page);
}
-static inline void kunmap_atomic_notypecheck(void *addr, enum km_type idx)
+static inline void __kunmap_atomic(void *addr)
{
kunmap_parisc(addr);
pagefault_enable();
}
-#define kmap_atomic_prot(page, idx, prot) kmap_atomic(page, idx)
-#define kmap_atomic_pfn(pfn, idx) kmap_atomic(pfn_to_page(pfn), (idx))
+#define kmap_atomic_prot(page, prot) kmap_atomic(page)
+#define kmap_atomic_pfn(pfn) kmap_atomic(pfn_to_page(pfn))
#define kmap_atomic_to_page(ptr) virt_to_page(ptr)
#endif
diff --git a/arch/parisc/include/asm/irq.h b/arch/parisc/include/asm/irq.h
index dfa26b67f919..c67dccf2e31f 100644
--- a/arch/parisc/include/asm/irq.h
+++ b/arch/parisc/include/asm/irq.h
@@ -40,7 +40,7 @@ struct irq_chip;
void no_ack_irq(unsigned int irq);
void no_end_irq(unsigned int irq);
void cpu_ack_irq(unsigned int irq);
-void cpu_end_irq(unsigned int irq);
+void cpu_eoi_irq(unsigned int irq);
extern int txn_alloc_irq(unsigned int nbits);
extern int txn_claim_irq(int);
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index 01c15035e783..865f37a8a881 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -397,9 +397,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
#define pte_offset_kernel(pmd, address) \
((pte_t *) pmd_page_vaddr(*(pmd)) + pte_index(address))
#define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
-#define pte_offset_map_nested(pmd, address) pte_offset_kernel(pmd, address)
#define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
#define pte_unmap(pte) do { } while (0)
#define pte_unmap_nested(pte) do { } while (0)
diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h
index 1ce7d2851d90..3eb82c2a5ec3 100644
--- a/arch/parisc/include/asm/unistd.h
+++ b/arch/parisc/include/asm/unistd.h
@@ -813,8 +813,9 @@
#define __NR_perf_event_open (__NR_Linux + 318)
#define __NR_recvmmsg (__NR_Linux + 319)
#define __NR_accept4 (__NR_Linux + 320)
+#define __NR_prlimit64 (__NR_Linux + 321)
-#define __NR_Linux_syscalls (__NR_accept4 + 1)
+#define __NR_Linux_syscalls (__NR_prlimit64 + 1)
#define __IGNORE_select /* newselect */
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index efbcee5d2220..5024f643b3b1 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -52,7 +52,7 @@ static volatile unsigned long cpu_eiem = 0;
*/
static DEFINE_PER_CPU(unsigned long, local_ack_eiem) = ~0UL;
-static void cpu_disable_irq(unsigned int irq)
+static void cpu_mask_irq(unsigned int irq)
{
unsigned long eirr_bit = EIEM_MASK(irq);
@@ -63,7 +63,7 @@ static void cpu_disable_irq(unsigned int irq)
* then gets disabled */
}
-static void cpu_enable_irq(unsigned int irq)
+static void cpu_unmask_irq(unsigned int irq)
{
unsigned long eirr_bit = EIEM_MASK(irq);
@@ -75,12 +75,6 @@ static void cpu_enable_irq(unsigned int irq)
smp_send_all_nop();
}
-static unsigned int cpu_startup_irq(unsigned int irq)
-{
- cpu_enable_irq(irq);
- return 0;
-}
-
void no_ack_irq(unsigned int irq) { }
void no_end_irq(unsigned int irq) { }
@@ -99,7 +93,7 @@ void cpu_ack_irq(unsigned int irq)
mtctl(mask, 23);
}
-void cpu_end_irq(unsigned int irq)
+void cpu_eoi_irq(unsigned int irq)
{
unsigned long mask = EIEM_MASK(irq);
int cpu = smp_processor_id();
@@ -146,12 +140,10 @@ static int cpu_set_affinity_irq(unsigned int irq, const struct cpumask *dest)
static struct irq_chip cpu_interrupt_type = {
.name = "CPU",
- .startup = cpu_startup_irq,
- .shutdown = cpu_disable_irq,
- .enable = cpu_enable_irq,
- .disable = cpu_disable_irq,
+ .mask = cpu_mask_irq,
+ .unmask = cpu_unmask_irq,
.ack = cpu_ack_irq,
- .end = cpu_end_irq,
+ .eoi = cpu_eoi_irq,
#ifdef CONFIG_SMP
.set_affinity = cpu_set_affinity_irq,
#endif
@@ -247,10 +239,11 @@ int cpu_claim_irq(unsigned int irq, struct irq_chip *type, void *data)
if (irq_desc[irq].chip != &cpu_interrupt_type)
return -EBUSY;
+ /* for iosapic interrupts */
if (type) {
- irq_desc[irq].chip = type;
- irq_desc[irq].chip_data = data;
- cpu_interrupt_type.enable(irq);
+ set_irq_chip_and_handler(irq, type, handle_level_irq);
+ set_irq_chip_data(irq, data);
+ cpu_unmask_irq(irq);
}
return 0;
}
@@ -368,7 +361,7 @@ void do_cpu_irq_mask(struct pt_regs *regs)
goto set_out;
}
#endif
- __do_IRQ(irq);
+ generic_handle_irq(irq);
out:
irq_exit();
@@ -398,14 +391,15 @@ static void claim_cpu_irqs(void)
{
int i;
for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++) {
- irq_desc[i].chip = &cpu_interrupt_type;
+ set_irq_chip_and_handler(i, &cpu_interrupt_type,
+ handle_level_irq);
}
- irq_desc[TIMER_IRQ].action = &timer_action;
- irq_desc[TIMER_IRQ].status = IRQ_PER_CPU;
+ set_irq_handler(TIMER_IRQ, handle_percpu_irq);
+ setup_irq(TIMER_IRQ, &timer_action);
#ifdef CONFIG_SMP
- irq_desc[IPI_IRQ].action = &ipi_action;
- irq_desc[IPI_IRQ].status = IRQ_PER_CPU;
+ set_irq_handler(IPI_IRQ, handle_percpu_irq);
+ setup_irq(IPI_IRQ, &ipi_action);
#endif
}
@@ -423,3 +417,4 @@ void __init init_IRQ(void)
set_eiem(cpu_eiem); /* EIEM : enable all external intr */
}
+
diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c
index 1ff366cb9685..66d1f17fdb94 100644
--- a/arch/parisc/kernel/pdc_cons.c
+++ b/arch/parisc/kernel/pdc_cons.c
@@ -12,6 +12,7 @@
* Copyright (C) 2001 Helge Deller <deller at parisc-linux.org>
* Copyright (C) 2001 Thomas Bogendoerfer <tsbogend at parisc-linux.org>
* Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org>
+ * Copyright (C) 2010 Guy Martin <gmsoft at tuxicoman.be>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -31,12 +32,11 @@
/*
* The PDC console is a simple console, which can be used for debugging
- * boot related problems on HP PA-RISC machines.
+ * boot related problems on HP PA-RISC machines. It is also useful when no
+ * other console works.
*
* This code uses the ROM (=PDC) based functions to read and write characters
* from and to PDC's boot path.
- * Since all character read from that path must be polled, this code never
- * can or will be a fully functional linux console.
*/
/* Define EARLY_BOOTUP_DEBUG to debug kernel related boot problems.
@@ -53,6 +53,7 @@
#include <asm/pdc.h> /* for iodc_call() proto and friends */
static DEFINE_SPINLOCK(pdc_console_lock);
+static struct console pdc_cons;
static void pdc_console_write(struct console *co, const char *s, unsigned count)
{
@@ -85,12 +86,138 @@ static int pdc_console_setup(struct console *co, char *options)
#if defined(CONFIG_PDC_CONSOLE)
#include <linux/vt_kern.h>
+#include <linux/tty_flip.h>
+
+#define PDC_CONS_POLL_DELAY (30 * HZ / 1000)
+
+static struct timer_list pdc_console_timer;
+
+extern struct console * console_drivers;
+
+static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp)
+{
+
+ mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
+
+ return 0;
+}
+
+static void pdc_console_tty_close(struct tty_struct *tty, struct file *filp)
+{
+ if (!tty->count)
+ del_timer(&pdc_console_timer);
+}
+
+static int pdc_console_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+ pdc_console_write(NULL, buf, count);
+ return count;
+}
+
+static int pdc_console_tty_write_room(struct tty_struct *tty)
+{
+ return 32768; /* no limit, no buffer used */
+}
+
+static int pdc_console_tty_chars_in_buffer(struct tty_struct *tty)
+{
+ return 0; /* no buffer */
+}
+
+static struct tty_driver *pdc_console_tty_driver;
+
+static const struct tty_operations pdc_console_tty_ops = {
+ .open = pdc_console_tty_open,
+ .close = pdc_console_tty_close,
+ .write = pdc_console_tty_write,
+ .write_room = pdc_console_tty_write_room,
+ .chars_in_buffer = pdc_console_tty_chars_in_buffer,
+};
+
+static void pdc_console_poll(unsigned long unused)
+{
+
+ int data, count = 0;
+
+ struct tty_struct *tty = pdc_console_tty_driver->ttys[0];
+
+ if (!tty)
+ return;
+
+ while (1) {
+ data = pdc_console_poll_key(NULL);
+ if (data == -1)
+ break;
+ tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL);
+ count ++;
+ }
+
+ if (count)
+ tty_flip_buffer_push(tty);
+
+ if (tty->count && (pdc_cons.flags & CON_ENABLED))
+ mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
+}
+
+static int __init pdc_console_tty_driver_init(void)
+{
+
+ int err;
+ struct tty_driver *drv;
+
+ /* Check if the console driver is still registered.
+ * It is unregistered if the pdc console was not selected as the
+ * primary console. */
+
+ struct console *tmp = console_drivers;
+
+ for (tmp = console_drivers; tmp; tmp = tmp->next)
+ if (tmp == &pdc_cons)
+ break;
+
+ if (!tmp) {
+ printk(KERN_INFO "PDC console driver not registered anymore, not creating %s\n", pdc_cons.name);
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "The PDC console driver is still registered, removing CON_BOOT flag\n");
+ pdc_cons.flags &= ~CON_BOOT;
+
+ drv = alloc_tty_driver(1);
+
+ if (!drv)
+ return -ENOMEM;
+
+ drv->driver_name = "pdc_cons";
+ drv->name = "ttyB";
+ drv->major = MUX_MAJOR;
+ drv->minor_start = 0;
+ drv->type = TTY_DRIVER_TYPE_SYSTEM;
+ drv->init_termios = tty_std_termios;
+ drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
+ tty_set_operations(drv, &pdc_console_tty_ops);
+
+ err = tty_register_driver(drv);
+ if (err) {
+ printk(KERN_ERR "Unable to register the PDC console TTY driver\n");
+ return err;
+ }
+
+ pdc_console_tty_driver = drv;
+
+ /* No need to initialize the pdc_console_timer if tty isn't allocated */
+ init_timer(&pdc_console_timer);
+ pdc_console_timer.function = pdc_console_poll;
+
+ return 0;
+}
+
+module_init(pdc_console_tty_driver_init);
static struct tty_driver * pdc_console_device (struct console *c, int *index)
{
- extern struct tty_driver console_driver;
- *index = c->index ? c->index-1 : fg_console;
- return &console_driver;
+ *index = c->index;
+ return pdc_console_tty_driver;
}
#else
#define pdc_console_device NULL
@@ -101,7 +228,7 @@ static struct console pdc_cons = {
.write = pdc_console_write,
.device = pdc_console_device,
.setup = pdc_console_setup,
- .flags = CON_BOOT | CON_PRINTBUFFER | CON_ENABLED,
+ .flags = CON_BOOT | CON_PRINTBUFFER,
.index = -1,
};
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
index c4f49e45129d..2905b1f52d30 100644
--- a/arch/parisc/kernel/ptrace.c
+++ b/arch/parisc/kernel/ptrace.c
@@ -110,7 +110,8 @@ void user_enable_block_step(struct task_struct *task)
pa_psw(task)->l = 0;
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
unsigned long tmp;
long ret = -EIO;
@@ -120,11 +121,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* Read the word at location addr in the USER area. For ptraced
processes, the kernel saves all regs on a syscall. */
case PTRACE_PEEKUSR:
- if ((addr & (sizeof(long)-1)) ||
- (unsigned long) addr >= sizeof(struct pt_regs))
+ if ((addr & (sizeof(unsigned long)-1)) ||
+ addr >= sizeof(struct pt_regs))
break;
tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
- ret = put_user(tmp, (unsigned long *) data);
+ ret = put_user(tmp, (unsigned long __user *) data);
break;
/* Write the word at location addr in the USER area. This will need
@@ -151,8 +152,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
}
- if ((addr & (sizeof(long)-1)) ||
- (unsigned long) addr >= sizeof(struct pt_regs))
+ if ((addr & (sizeof(unsigned long)-1)) ||
+ addr >= sizeof(struct pt_regs))
break;
if ((addr >= PT_GR1 && addr <= PT_GR31) ||
addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index 3d52c978738f..74867dfdabe5 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -419,6 +419,7 @@
ENTRY_SAME(perf_event_open)
ENTRY_COMP(recvmmsg)
ENTRY_SAME(accept4) /* 320 */
+ ENTRY_SAME(prlimit64)
/* Nothing yet */
diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c
index 92d977bb5ea8..234e3682cf09 100644
--- a/arch/parisc/kernel/unaligned.c
+++ b/arch/parisc/kernel/unaligned.c
@@ -619,15 +619,12 @@ void handle_unaligned(struct pt_regs *regs)
flop=1;
ret = emulate_std(regs, R2(regs->iir),1);
break;
-
-#ifdef CONFIG_PA20
case OPCODE_LDD_L:
ret = emulate_ldd(regs, R2(regs->iir),0);
break;
case OPCODE_STD_L:
ret = emulate_std(regs, R2(regs->iir),0);
break;
-#endif
}
#endif
switch (regs->iir & OPCODE3_MASK)
diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c
index d58eac1a8288..76ed62ed785b 100644
--- a/arch/parisc/kernel/unwind.c
+++ b/arch/parisc/kernel/unwind.c
@@ -80,8 +80,11 @@ find_unwind_entry(unsigned long addr)
if (addr >= table->start &&
addr <= table->end)
e = find_unwind_entry_in_table(table, addr);
- if (e)
+ if (e) {
+ /* Move-to-front to exploit common traces */
+ list_move(&table->list, &unwind_tables);
break;
+ }
}
return e;
diff --git a/arch/parisc/math-emu/Makefile b/arch/parisc/math-emu/Makefile
index 1f3f225897f5..0bd63b08a79a 100644
--- a/arch/parisc/math-emu/Makefile
+++ b/arch/parisc/math-emu/Makefile
@@ -3,7 +3,7 @@
#
# See arch/parisc/math-emu/README
-EXTRA_CFLAGS += -Wno-parentheses -Wno-implicit-function-declaration \
+ccflags-y := -Wno-parentheses -Wno-implicit-function-declaration \
-Wno-uninitialized -Wno-strict-prototypes -Wno-return-type \
-Wno-implicit-int
diff --git a/arch/powerpc/boot/dts/mpc8610_hpcd.dts b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
index 9535ce68caae..83c3218cb4da 100644
--- a/arch/powerpc/boot/dts/mpc8610_hpcd.dts
+++ b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
@@ -286,6 +286,7 @@
ssi@16100 {
compatible = "fsl,mpc8610-ssi";
+ status = "disabled";
cell-index = <1>;
reg = <0x16100 0x100>;
interrupt-parent = <&mpic>;
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index c3b113b2ca31..3aeb5949cfef 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -124,6 +124,9 @@ CONFIG_I2C_CPM=m
CONFIG_I2C_MPC=y
# CONFIG_HWMON is not set
CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_FSL_DIU=y
+# CONFIG_VGA_CONSOLE is not set
CONFIG_SOUND=y
CONFIG_SND=y
# CONFIG_SND_SUPPORT_OLD_API is not set
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index a075da2ea3fb..d62c8016f4bc 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -126,6 +126,9 @@ CONFIG_I2C_CPM=m
CONFIG_I2C_MPC=y
# CONFIG_HWMON is not set
CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_FSL_DIU=y
+# CONFIG_VGA_CONSOLE is not set
CONFIG_SOUND=y
CONFIG_SND=y
# CONFIG_SND_SUPPORT_OLD_API is not set
diff --git a/arch/powerpc/include/asm/cputime.h b/arch/powerpc/include/asm/cputime.h
index 8bdc6a9e5773..1cf20bdfbeca 100644
--- a/arch/powerpc/include/asm/cputime.h
+++ b/arch/powerpc/include/asm/cputime.h
@@ -124,23 +124,23 @@ static inline u64 cputime64_to_jiffies64(const cputime_t ct)
}
/*
- * Convert cputime <-> milliseconds
+ * Convert cputime <-> microseconds
*/
extern u64 __cputime_msec_factor;
-static inline unsigned long cputime_to_msecs(const cputime_t ct)
+static inline unsigned long cputime_to_usecs(const cputime_t ct)
{
- return mulhdu(ct, __cputime_msec_factor);
+ return mulhdu(ct, __cputime_msec_factor) * USEC_PER_MSEC;
}
-static inline cputime_t msecs_to_cputime(const unsigned long ms)
+static inline cputime_t usecs_to_cputime(const unsigned long us)
{
cputime_t ct;
unsigned long sec;
/* have to be a little careful about overflow */
- ct = ms % 1000;
- sec = ms / 1000;
+ ct = us % 1000000;
+ sec = us / 1000000;
if (ct) {
ct *= tb_ticks_per_sec;
do_div(ct, 1000);
diff --git a/arch/powerpc/include/asm/immap_86xx.h b/arch/powerpc/include/asm/fsl_guts.h
index 0f165e59c326..bebd12463ec9 100644
--- a/arch/powerpc/include/asm/immap_86xx.h
+++ b/arch/powerpc/include/asm/fsl_guts.h
@@ -1,5 +1,5 @@
/**
- * MPC86xx Internal Memory Map
+ * Freecale 85xx and 86xx Global Utilties register set
*
* Authors: Jeff Brown
* Timur Tabi <timur@freescale.com>
@@ -10,73 +10,112 @@
* 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 header file defines structures for various 86xx SOC devices that are
- * used by multiple source files.
*/
-#ifndef __ASM_POWERPC_IMMAP_86XX_H__
-#define __ASM_POWERPC_IMMAP_86XX_H__
+#ifndef __ASM_POWERPC_FSL_GUTS_H__
+#define __ASM_POWERPC_FSL_GUTS_H__
#ifdef __KERNEL__
-/* Global Utility Registers */
-struct ccsr_guts {
+/*
+ * These #ifdefs are safe because it's not possible to build a kernel that
+ * runs on e500 and e600 cores.
+ */
+
+#if !defined(CONFIG_PPC_85xx) && !defined(CONFIG_PPC_86xx)
+#error Only 85xx and 86xx SOCs are supported
+#endif
+
+/**
+ * Global Utility Registers.
+ *
+ * Not all registers defined in this structure are available on all chips, so
+ * you are expected to know whether a given register actually exists on your
+ * chip before you access it.
+ *
+ * Also, some registers are similar on different chips but have slightly
+ * different names. In these cases, one name is chosen to avoid extraneous
+ * #ifdefs.
+ */
+#ifdef CONFIG_PPC_85xx
+struct ccsr_guts_85xx {
+#else
+struct ccsr_guts_86xx {
+#endif
__be32 porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */
__be32 porbmsr; /* 0x.0004 - POR Boot Mode Status Register */
__be32 porimpscr; /* 0x.0008 - POR I/O Impedance Status and Control Register */
__be32 pordevsr; /* 0x.000c - POR I/O Device Status Register */
__be32 pordbgmsr; /* 0x.0010 - POR Debug Mode Status Register */
- u8 res1[0x20 - 0x14];
+ __be32 pordevsr2; /* 0x.0014 - POR device status register 2 */
+ u8 res018[0x20 - 0x18];
__be32 porcir; /* 0x.0020 - POR Configuration Information Register */
- u8 res2[0x30 - 0x24];
+ u8 res024[0x30 - 0x24];
__be32 gpiocr; /* 0x.0030 - GPIO Control Register */
- u8 res3[0x40 - 0x34];
+ u8 res034[0x40 - 0x34];
__be32 gpoutdr; /* 0x.0040 - General-Purpose Output Data Register */
- u8 res4[0x50 - 0x44];
+ u8 res044[0x50 - 0x44];
__be32 gpindr; /* 0x.0050 - General-Purpose Input Data Register */
- u8 res5[0x60 - 0x54];
+ u8 res054[0x60 - 0x54];
__be32 pmuxcr; /* 0x.0060 - Alternate Function Signal Multiplex Control */
- u8 res6[0x70 - 0x64];
+ __be32 pmuxcr2; /* 0x.0064 - Alternate function signal multiplex control 2 */
+ __be32 dmuxcr; /* 0x.0068 - DMA Mux Control Register */
+ u8 res06c[0x70 - 0x6c];
__be32 devdisr; /* 0x.0070 - Device Disable Control */
__be32 devdisr2; /* 0x.0074 - Device Disable Control 2 */
- u8 res7[0x80 - 0x78];
+ u8 res078[0x7c - 0x78];
+ __be32 pmjcr; /* 0x.007c - 4 Power Management Jog Control Register */
__be32 powmgtcsr; /* 0x.0080 - Power Management Status and Control Register */
- u8 res8[0x90 - 0x84];
+ __be32 pmrccr; /* 0x.0084 - Power Management Reset Counter Configuration Register */
+ __be32 pmpdccr; /* 0x.0088 - Power Management Power Down Counter Configuration Register */
+ __be32 pmcdr; /* 0x.008c - 4Power management clock disable register */
__be32 mcpsumr; /* 0x.0090 - Machine Check Summary Register */
__be32 rstrscr; /* 0x.0094 - Reset Request Status and Control Register */
- u8 res9[0xA0 - 0x98];
+ __be32 ectrstcr; /* 0x.0098 - Exception reset control register */
+ __be32 autorstsr; /* 0x.009c - Automatic reset status register */
__be32 pvr; /* 0x.00a0 - Processor Version Register */
__be32 svr; /* 0x.00a4 - System Version Register */
- u8 res10[0xB0 - 0xA8];
+ u8 res0a8[0xb0 - 0xa8];
__be32 rstcr; /* 0x.00b0 - Reset Control Register */
- u8 res11[0xC0 - 0xB4];
+ u8 res0b4[0xc0 - 0xb4];
+#ifdef CONFIG_PPC_85xx
+ __be32 iovselsr; /* 0x.00c0 - I/O voltage select status register */
+#else
__be32 elbcvselcr; /* 0x.00c0 - eLBC Voltage Select Ctrl Reg */
- u8 res12[0x800 - 0xC4];
+#endif
+ u8 res0c4[0x224 - 0xc4];
+ __be32 iodelay1; /* 0x.0224 - IO delay control register 1 */
+ __be32 iodelay2; /* 0x.0228 - IO delay control register 2 */
+ u8 res22c[0x800 - 0x22c];
__be32 clkdvdr; /* 0x.0800 - Clock Divide Register */
- u8 res13[0x900 - 0x804];
+ u8 res804[0x900 - 0x804];
__be32 ircr; /* 0x.0900 - Infrared Control Register */
- u8 res14[0x908 - 0x904];
+ u8 res904[0x908 - 0x904];
__be32 dmacr; /* 0x.0908 - DMA Control Register */
- u8 res15[0x914 - 0x90C];
+ u8 res90c[0x914 - 0x90c];
__be32 elbccr; /* 0x.0914 - eLBC Control Register */
- u8 res16[0xB20 - 0x918];
+ u8 res918[0xb20 - 0x918];
__be32 ddr1clkdr; /* 0x.0b20 - DDR1 Clock Disable Register */
__be32 ddr2clkdr; /* 0x.0b24 - DDR2 Clock Disable Register */
__be32 ddrclkdr; /* 0x.0b28 - DDR Clock Disable Register */
- u8 res17[0xE00 - 0xB2C];
+ u8 resb2c[0xe00 - 0xb2c];
__be32 clkocr; /* 0x.0e00 - Clock Out Select Register */
- u8 res18[0xE10 - 0xE04];
+ u8 rese04[0xe10 - 0xe04];
__be32 ddrdllcr; /* 0x.0e10 - DDR DLL Control Register */
- u8 res19[0xE20 - 0xE14];
+ u8 rese14[0xe20 - 0xe14];
__be32 lbcdllcr; /* 0x.0e20 - LBC DLL Control Register */
- u8 res20[0xF04 - 0xE24];
+ __be32 cpfor; /* 0x.0e24 - L2 charge pump fuse override register */
+ u8 rese28[0xf04 - 0xe28];
__be32 srds1cr0; /* 0x.0f04 - SerDes1 Control Register 0 */
__be32 srds1cr1; /* 0x.0f08 - SerDes1 Control Register 0 */
- u8 res21[0xF40 - 0xF0C];
- __be32 srds2cr0; /* 0x.0f40 - SerDes1 Control Register 0 */
- __be32 srds2cr1; /* 0x.0f44 - SerDes1 Control Register 0 */
+ u8 resf0c[0xf2c - 0xf0c];
+ __be32 itcr; /* 0x.0f2c - Internal transaction control register */
+ u8 resf30[0xf40 - 0xf30];
+ __be32 srds2cr0; /* 0x.0f40 - SerDes2 Control Register 0 */
+ __be32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */
} __attribute__ ((packed));
+#ifdef CONFIG_PPC_86xx
+
#define CCSR_GUTS_DMACR_DEV_SSI 0 /* DMA controller/channel set to SSI */
#define CCSR_GUTS_DMACR_DEV_IR 1 /* DMA controller/channel set to IR */
@@ -93,7 +132,7 @@ struct ccsr_guts {
* ch: The channel on the DMA controller (0, 1, 2, or 3)
* device: The device to set as the source (CCSR_GUTS_DMACR_DEV_xx)
*/
-static inline void guts_set_dmacr(struct ccsr_guts __iomem *guts,
+static inline void guts_set_dmacr(struct ccsr_guts_86xx __iomem *guts,
unsigned int co, unsigned int ch, unsigned int device)
{
unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
@@ -129,7 +168,7 @@ static inline void guts_set_dmacr(struct ccsr_guts __iomem *guts,
* ch: The channel on the DMA controller (0, 1, 2, or 3)
* value: the new value for the bit (0 or 1)
*/
-static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
+static inline void guts_set_pmuxcr_dma(struct ccsr_guts_86xx __iomem *guts,
unsigned int co, unsigned int ch, unsigned int value)
{
if ((ch == 0) || (ch == 3)) {
@@ -152,5 +191,7 @@ static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
#define CCSR_GUTS_CLKDVDR_SSICLK_MASK 0x000000FF
#define CCSR_GUTS_CLKDVDR_SSICLK(x) ((x) & CCSR_GUTS_CLKDVDR_SSICLK_MASK)
-#endif /* __ASM_POWERPC_IMMAP_86XX_H__ */
-#endif /* __KERNEL__ */
+#endif
+
+#endif
+#endif
diff --git a/arch/powerpc/include/asm/fsldma.h b/arch/powerpc/include/asm/fsldma.h
deleted file mode 100644
index debc5ed96d6e..000000000000
--- a/arch/powerpc/include/asm/fsldma.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Freescale MPC83XX / MPC85XX DMA Controller
- *
- * Copyright (c) 2009 Ira W. Snyder <iws@ovro.caltech.edu>
- *
- * 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.
- */
-
-#ifndef __ARCH_POWERPC_ASM_FSLDMA_H__
-#define __ARCH_POWERPC_ASM_FSLDMA_H__
-
-#include <linux/slab.h>
-#include <linux/dmaengine.h>
-
-/*
- * Definitions for the Freescale DMA controller's DMA_SLAVE implemention
- *
- * The Freescale DMA_SLAVE implementation was designed to handle many-to-many
- * transfers. An example usage would be an accelerated copy between two
- * scatterlists. Another example use would be an accelerated copy from
- * multiple non-contiguous device buffers into a single scatterlist.
- *
- * A DMA_SLAVE transaction is defined by a struct fsl_dma_slave. This
- * structure contains a list of hardware addresses that should be copied
- * to/from the scatterlist passed into device_prep_slave_sg(). The structure
- * also has some fields to enable hardware-specific features.
- */
-
-/**
- * struct fsl_dma_hw_addr
- * @entry: linked list entry
- * @address: the hardware address
- * @length: length to transfer
- *
- * Holds a single physical hardware address / length pair for use
- * with the DMAEngine DMA_SLAVE API.
- */
-struct fsl_dma_hw_addr {
- struct list_head entry;
-
- dma_addr_t address;
- size_t length;
-};
-
-/**
- * struct fsl_dma_slave
- * @addresses: a linked list of struct fsl_dma_hw_addr structures
- * @request_count: value for DMA request count
- * @src_loop_size: setup and enable constant source-address DMA transfers
- * @dst_loop_size: setup and enable constant destination address DMA transfers
- * @external_start: enable externally started DMA transfers
- * @external_pause: enable externally paused DMA transfers
- *
- * Holds a list of address / length pairs for use with the DMAEngine
- * DMA_SLAVE API implementation for the Freescale DMA controller.
- */
-struct fsl_dma_slave {
-
- /* List of hardware address/length pairs */
- struct list_head addresses;
-
- /* Support for extra controller features */
- unsigned int request_count;
- unsigned int src_loop_size;
- unsigned int dst_loop_size;
- bool external_start;
- bool external_pause;
-};
-
-/**
- * fsl_dma_slave_append - add an address/length pair to a struct fsl_dma_slave
- * @slave: the &struct fsl_dma_slave to add to
- * @address: the hardware address to add
- * @length: the length of bytes to transfer from @address
- *
- * Add a hardware address/length pair to a struct fsl_dma_slave. Returns 0 on
- * success, -ERRNO otherwise.
- */
-static inline int fsl_dma_slave_append(struct fsl_dma_slave *slave,
- dma_addr_t address, size_t length)
-{
- struct fsl_dma_hw_addr *addr;
-
- addr = kzalloc(sizeof(*addr), GFP_ATOMIC);
- if (!addr)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&addr->entry);
- addr->address = address;
- addr->length = length;
-
- list_add_tail(&addr->entry, &slave->addresses);
- return 0;
-}
-
-/**
- * fsl_dma_slave_free - free a struct fsl_dma_slave
- * @slave: the struct fsl_dma_slave to free
- *
- * Free a struct fsl_dma_slave and all associated address/length pairs
- */
-static inline void fsl_dma_slave_free(struct fsl_dma_slave *slave)
-{
- struct fsl_dma_hw_addr *addr, *tmp;
-
- if (slave) {
- list_for_each_entry_safe(addr, tmp, &slave->addresses, entry) {
- list_del(&addr->entry);
- kfree(addr);
- }
-
- kfree(slave);
- }
-}
-
-/**
- * fsl_dma_slave_alloc - allocate a struct fsl_dma_slave
- * @gfp: the flags to pass to kmalloc when allocating this structure
- *
- * Allocate a struct fsl_dma_slave for use by the DMA_SLAVE API. Returns a new
- * struct fsl_dma_slave on success, or NULL on failure.
- */
-static inline struct fsl_dma_slave *fsl_dma_slave_alloc(gfp_t gfp)
-{
- struct fsl_dma_slave *slave;
-
- slave = kzalloc(sizeof(*slave), gfp);
- if (!slave)
- return NULL;
-
- INIT_LIST_HEAD(&slave->addresses);
- return slave;
-}
-
-#endif /* __ARCH_POWERPC_ASM_FSLDMA_H__ */
diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h
index d10d64a4be38..dbc264010d0b 100644
--- a/arch/powerpc/include/asm/highmem.h
+++ b/arch/powerpc/include/asm/highmem.h
@@ -60,9 +60,8 @@ extern pte_t *pkmap_page_table;
extern void *kmap_high(struct page *page);
extern void kunmap_high(struct page *page);
-extern void *kmap_atomic_prot(struct page *page, enum km_type type,
- pgprot_t prot);
-extern void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
+extern void *kmap_atomic_prot(struct page *page, pgprot_t prot);
+extern void __kunmap_atomic(void *kvaddr);
static inline void *kmap(struct page *page)
{
@@ -80,9 +79,9 @@ static inline void kunmap(struct page *page)
kunmap_high(page);
}
-static inline void *kmap_atomic(struct page *page, enum km_type type)
+static inline void *__kmap_atomic(struct page *page)
{
- return kmap_atomic_prot(page, type, kmap_prot);
+ return kmap_atomic_prot(page, kmap_prot);
}
static inline struct page *kmap_atomic_to_page(void *ptr)
diff --git a/arch/powerpc/include/asm/hydra.h b/arch/powerpc/include/asm/hydra.h
index 1ad4eed07fbe..5b0c98bd46ab 100644
--- a/arch/powerpc/include/asm/hydra.h
+++ b/arch/powerpc/include/asm/hydra.h
@@ -10,7 +10,7 @@
*
* © Copyright 1995 Apple Computer, Inc. All rights reserved.
*
- * It's available online from http://chrp.apple.com/MacTech.pdf.
+ * It's available online from http://www.cpu.lu/~mlan/ftp/MacTech.pdf
* You can obtain paper copies of this book from computer bookstores or by
* writing Morgan Kaufmann Publishers, Inc., 340 Pine Street, Sixth Floor, San
* Francisco, CA 94104. Reference ISBN 1-55860-393-X.
diff --git a/arch/powerpc/include/asm/kvm.h b/arch/powerpc/include/asm/kvm.h
index 6c5547d82bbe..18ea6963ad77 100644
--- a/arch/powerpc/include/asm/kvm.h
+++ b/arch/powerpc/include/asm/kvm.h
@@ -86,5 +86,6 @@ struct kvm_guest_debug_arch {
#define KVM_INTERRUPT_SET -1U
#define KVM_INTERRUPT_UNSET -2U
+#define KVM_INTERRUPT_SET_LEVEL -3U
#endif /* __LINUX_KVM_POWERPC_H */
diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h
index c5ea4cda34b3..5b7504674397 100644
--- a/arch/powerpc/include/asm/kvm_asm.h
+++ b/arch/powerpc/include/asm/kvm_asm.h
@@ -58,6 +58,7 @@
#define BOOK3S_INTERRUPT_INST_STORAGE 0x400
#define BOOK3S_INTERRUPT_INST_SEGMENT 0x480
#define BOOK3S_INTERRUPT_EXTERNAL 0x500
+#define BOOK3S_INTERRUPT_EXTERNAL_LEVEL 0x501
#define BOOK3S_INTERRUPT_ALIGNMENT 0x600
#define BOOK3S_INTERRUPT_PROGRAM 0x700
#define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800
@@ -84,7 +85,8 @@
#define BOOK3S_IRQPRIO_EXTERNAL 13
#define BOOK3S_IRQPRIO_DECREMENTER 14
#define BOOK3S_IRQPRIO_PERFORMANCE_MONITOR 15
-#define BOOK3S_IRQPRIO_MAX 16
+#define BOOK3S_IRQPRIO_EXTERNAL_LEVEL 16
+#define BOOK3S_IRQPRIO_MAX 17
#define BOOK3S_HFLAG_DCBZ32 0x1
#define BOOK3S_HFLAG_SLB 0x2
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index 8274a2d43925..d62e703f1214 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -38,15 +38,6 @@ struct kvmppc_slb {
bool class : 1;
};
-struct kvmppc_sr {
- u32 raw;
- u32 vsid;
- bool Ks : 1;
- bool Kp : 1;
- bool nx : 1;
- bool valid : 1;
-};
-
struct kvmppc_bat {
u64 raw;
u32 bepi;
@@ -69,6 +60,13 @@ struct kvmppc_sid_map {
#define SID_MAP_NUM (1 << SID_MAP_BITS)
#define SID_MAP_MASK (SID_MAP_NUM - 1)
+#ifdef CONFIG_PPC_BOOK3S_64
+#define SID_CONTEXTS 1
+#else
+#define SID_CONTEXTS 128
+#define VSID_POOL_SIZE (SID_CONTEXTS * 16)
+#endif
+
struct kvmppc_vcpu_book3s {
struct kvm_vcpu vcpu;
struct kvmppc_book3s_shadow_vcpu *shadow_vcpu;
@@ -79,20 +77,22 @@ struct kvmppc_vcpu_book3s {
u64 vsid;
} slb_shadow[64];
u8 slb_shadow_max;
- struct kvmppc_sr sr[16];
struct kvmppc_bat ibat[8];
struct kvmppc_bat dbat[8];
u64 hid[6];
u64 gqr[8];
int slb_nr;
- u32 dsisr;
u64 sdr1;
u64 hior;
u64 msr_mask;
- u64 vsid_first;
u64 vsid_next;
+#ifdef CONFIG_PPC_BOOK3S_32
+ u32 vsid_pool[VSID_POOL_SIZE];
+#else
+ u64 vsid_first;
u64 vsid_max;
- int context_id;
+#endif
+ int context_id[SID_CONTEXTS];
ulong prog_flags; /* flags to inject when giving a 700 trap */
};
@@ -131,9 +131,10 @@ extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat,
bool upper, u32 val);
extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu);
+extern pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn);
-extern u32 kvmppc_trampoline_lowmem;
-extern u32 kvmppc_trampoline_enter;
+extern ulong kvmppc_trampoline_lowmem;
+extern ulong kvmppc_trampoline_enter;
extern void kvmppc_rmcall(ulong srr0, ulong srr1);
extern void kvmppc_load_up_fpu(void);
extern void kvmppc_load_up_altivec(void);
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index b0b23c007d6e..bba3b9b72a39 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -25,6 +25,7 @@
#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/kvm_types.h>
+#include <linux/kvm_para.h>
#include <asm/kvm_asm.h>
#define KVM_MAX_VCPUS 1
@@ -41,12 +42,17 @@
#define HPTEG_CACHE_NUM (1 << 15)
#define HPTEG_HASH_BITS_PTE 13
+#define HPTEG_HASH_BITS_PTE_LONG 12
#define HPTEG_HASH_BITS_VPTE 13
#define HPTEG_HASH_BITS_VPTE_LONG 5
#define HPTEG_HASH_NUM_PTE (1 << HPTEG_HASH_BITS_PTE)
+#define HPTEG_HASH_NUM_PTE_LONG (1 << HPTEG_HASH_BITS_PTE_LONG)
#define HPTEG_HASH_NUM_VPTE (1 << HPTEG_HASH_BITS_VPTE)
#define HPTEG_HASH_NUM_VPTE_LONG (1 << HPTEG_HASH_BITS_VPTE_LONG)
+/* Physical Address Mask - allowed range of real mode RAM access */
+#define KVM_PAM 0x0fffffffffffffffULL
+
struct kvm;
struct kvm_run;
struct kvm_vcpu;
@@ -159,8 +165,10 @@ struct kvmppc_mmu {
struct hpte_cache {
struct hlist_node list_pte;
+ struct hlist_node list_pte_long;
struct hlist_node list_vpte;
struct hlist_node list_vpte_long;
+ struct rcu_head rcu_head;
u64 host_va;
u64 pfn;
ulong slot;
@@ -210,28 +218,20 @@ struct kvm_vcpu_arch {
u32 cr;
#endif
- ulong msr;
#ifdef CONFIG_PPC_BOOK3S
ulong shadow_msr;
ulong hflags;
ulong guest_owned_ext;
#endif
u32 mmucr;
- ulong sprg0;
- ulong sprg1;
- ulong sprg2;
- ulong sprg3;
ulong sprg4;
ulong sprg5;
ulong sprg6;
ulong sprg7;
- ulong srr0;
- ulong srr1;
ulong csrr0;
ulong csrr1;
ulong dsrr0;
ulong dsrr1;
- ulong dear;
ulong esr;
u32 dec;
u32 decar;
@@ -290,12 +290,17 @@ struct kvm_vcpu_arch {
struct tasklet_struct tasklet;
u64 dec_jiffies;
unsigned long pending_exceptions;
+ struct kvm_vcpu_arch_shared *shared;
+ unsigned long magic_page_pa; /* phys addr to map the magic page to */
+ unsigned long magic_page_ea; /* effect. addr to map the magic page to */
#ifdef CONFIG_PPC_BOOK3S
struct hlist_head hpte_hash_pte[HPTEG_HASH_NUM_PTE];
+ struct hlist_head hpte_hash_pte_long[HPTEG_HASH_NUM_PTE_LONG];
struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE];
struct hlist_head hpte_hash_vpte_long[HPTEG_HASH_NUM_VPTE_LONG];
int hpte_cache_count;
+ spinlock_t mmu_lock;
#endif
};
diff --git a/arch/powerpc/include/asm/kvm_para.h b/arch/powerpc/include/asm/kvm_para.h
index 2d48f6a63d0b..50533f9adf40 100644
--- a/arch/powerpc/include/asm/kvm_para.h
+++ b/arch/powerpc/include/asm/kvm_para.h
@@ -20,16 +20,153 @@
#ifndef __POWERPC_KVM_PARA_H__
#define __POWERPC_KVM_PARA_H__
+#include <linux/types.h>
+
+struct kvm_vcpu_arch_shared {
+ __u64 scratch1;
+ __u64 scratch2;
+ __u64 scratch3;
+ __u64 critical; /* Guest may not get interrupts if == r1 */
+ __u64 sprg0;
+ __u64 sprg1;
+ __u64 sprg2;
+ __u64 sprg3;
+ __u64 srr0;
+ __u64 srr1;
+ __u64 dar;
+ __u64 msr;
+ __u32 dsisr;
+ __u32 int_pending; /* Tells the guest if we have an interrupt */
+ __u32 sr[16];
+};
+
+#define KVM_SC_MAGIC_R0 0x4b564d21 /* "KVM!" */
+#define HC_VENDOR_KVM (42 << 16)
+#define HC_EV_SUCCESS 0
+#define HC_EV_UNIMPLEMENTED 12
+
+#define KVM_FEATURE_MAGIC_PAGE 1
+
+#define KVM_MAGIC_FEAT_SR (1 << 0)
+
#ifdef __KERNEL__
+#ifdef CONFIG_KVM_GUEST
+
+#include <linux/of.h>
+
+static inline int kvm_para_available(void)
+{
+ struct device_node *hyper_node;
+
+ hyper_node = of_find_node_by_path("/hypervisor");
+ if (!hyper_node)
+ return 0;
+
+ if (!of_device_is_compatible(hyper_node, "linux,kvm"))
+ return 0;
+
+ return 1;
+}
+
+extern unsigned long kvm_hypercall(unsigned long *in,
+ unsigned long *out,
+ unsigned long nr);
+
+#else
+
static inline int kvm_para_available(void)
{
return 0;
}
+static unsigned long kvm_hypercall(unsigned long *in,
+ unsigned long *out,
+ unsigned long nr)
+{
+ return HC_EV_UNIMPLEMENTED;
+}
+
+#endif
+
+static inline long kvm_hypercall0_1(unsigned int nr, unsigned long *r2)
+{
+ unsigned long in[8];
+ unsigned long out[8];
+ unsigned long r;
+
+ r = kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+ *r2 = out[0];
+
+ return r;
+}
+
+static inline long kvm_hypercall0(unsigned int nr)
+{
+ unsigned long in[8];
+ unsigned long out[8];
+
+ return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+}
+
+static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
+{
+ unsigned long in[8];
+ unsigned long out[8];
+
+ in[0] = p1;
+ return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+}
+
+static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
+ unsigned long p2)
+{
+ unsigned long in[8];
+ unsigned long out[8];
+
+ in[0] = p1;
+ in[1] = p2;
+ return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+}
+
+static inline long kvm_hypercall3(unsigned int nr, unsigned long p1,
+ unsigned long p2, unsigned long p3)
+{
+ unsigned long in[8];
+ unsigned long out[8];
+
+ in[0] = p1;
+ in[1] = p2;
+ in[2] = p3;
+ return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+}
+
+static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
+ unsigned long p2, unsigned long p3,
+ unsigned long p4)
+{
+ unsigned long in[8];
+ unsigned long out[8];
+
+ in[0] = p1;
+ in[1] = p2;
+ in[2] = p3;
+ in[3] = p4;
+ return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+}
+
+
static inline unsigned int kvm_arch_para_features(void)
{
- return 0;
+ unsigned long r;
+
+ if (!kvm_para_available())
+ return 0;
+
+ if(kvm_hypercall0_1(KVM_HC_FEATURES, &r))
+ return 0;
+
+ return r;
}
#endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 18d139ec2d22..ecb3bc74c344 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -107,6 +107,7 @@ extern int kvmppc_booke_init(void);
extern void kvmppc_booke_exit(void);
extern void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu);
+extern int kvmppc_kvm_pv(struct kvm_vcpu *vcpu);
/*
* Cuts out inst bits with ordering according to spec.
diff --git a/arch/powerpc/include/asm/pgtable-ppc32.h b/arch/powerpc/include/asm/pgtable-ppc32.h
index a7db96f2b5c3..47edde8c3556 100644
--- a/arch/powerpc/include/asm/pgtable-ppc32.h
+++ b/arch/powerpc/include/asm/pgtable-ppc32.h
@@ -308,12 +308,8 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
#define pte_offset_kernel(dir, addr) \
((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(addr))
#define pte_offset_map(dir, addr) \
- ((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE0) + pte_index(addr))
-#define pte_offset_map_nested(dir, addr) \
- ((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE1) + pte_index(addr))
-
-#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
-#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
+ ((pte_t *) kmap_atomic(pmd_page(*(dir))) + pte_index(addr))
+#define pte_unmap(pte) kunmap_atomic(pte)
/*
* Encode and decode a swap entry.
diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
index 49865045d56f..2b09cd522d33 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64.h
+++ b/arch/powerpc/include/asm/pgtable-ppc64.h
@@ -193,9 +193,7 @@
(((pte_t *) pmd_page_vaddr(*(dir))) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr))
-#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr))
#define pte_unmap(pte) do { } while(0)
-#define pte_unmap_nested(pte) do { } while(0)
/* to find an entry in a kernel page-table-directory */
/* This now only contains the vmalloc pages */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 4ed076a4db24..36c30f31ec93 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -129,6 +129,8 @@ ifneq ($(CONFIG_XMON)$(CONFIG_KEXEC),)
obj-y += ppc_save_regs.o
endif
+obj-$(CONFIG_KVM_GUEST) += kvm.o kvm_emul.o
+
# Disable GCOV in odd or sensitive code
GCOV_PROFILE_prom_init.o := n
GCOV_PROFILE_ftrace.o := n
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index c3e01945ad4f..bd0df2e6aa8f 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -48,11 +48,11 @@
#ifdef CONFIG_PPC_ISERIES
#include <asm/iseries/alpaca.h>
#endif
-#ifdef CONFIG_KVM
+#if defined(CONFIG_KVM) || defined(CONFIG_KVM_GUEST)
#include <linux/kvm_host.h>
-#ifndef CONFIG_BOOKE
-#include <asm/kvm_book3s.h>
#endif
+#if defined(CONFIG_KVM) && defined(CONFIG_PPC_BOOK3S)
+#include <asm/kvm_book3s.h>
#endif
#ifdef CONFIG_PPC32
@@ -396,12 +396,13 @@ int main(void)
DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack));
DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid));
DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr));
- DEFINE(VCPU_MSR, offsetof(struct kvm_vcpu, arch.msr));
DEFINE(VCPU_SPRG4, offsetof(struct kvm_vcpu, arch.sprg4));
DEFINE(VCPU_SPRG5, offsetof(struct kvm_vcpu, arch.sprg5));
DEFINE(VCPU_SPRG6, offsetof(struct kvm_vcpu, arch.sprg6));
DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7));
DEFINE(VCPU_SHADOW_PID, offsetof(struct kvm_vcpu, arch.shadow_pid));
+ DEFINE(VCPU_SHARED, offsetof(struct kvm_vcpu, arch.shared));
+ DEFINE(VCPU_SHARED_MSR, offsetof(struct kvm_vcpu_arch_shared, msr));
/* book3s */
#ifdef CONFIG_PPC_BOOK3S
@@ -466,6 +467,22 @@ int main(void)
DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
#endif /* CONFIG_PPC_BOOK3S */
#endif
+
+#ifdef CONFIG_KVM_GUEST
+ DEFINE(KVM_MAGIC_SCRATCH1, offsetof(struct kvm_vcpu_arch_shared,
+ scratch1));
+ DEFINE(KVM_MAGIC_SCRATCH2, offsetof(struct kvm_vcpu_arch_shared,
+ scratch2));
+ DEFINE(KVM_MAGIC_SCRATCH3, offsetof(struct kvm_vcpu_arch_shared,
+ scratch3));
+ DEFINE(KVM_MAGIC_INT, offsetof(struct kvm_vcpu_arch_shared,
+ int_pending));
+ DEFINE(KVM_MAGIC_MSR, offsetof(struct kvm_vcpu_arch_shared, msr));
+ DEFINE(KVM_MAGIC_CRITICAL, offsetof(struct kvm_vcpu_arch_shared,
+ critical));
+ DEFINE(KVM_MAGIC_SR, offsetof(struct kvm_vcpu_arch_shared, sr));
+#endif
+
#ifdef CONFIG_44x
DEFINE(PGD_T_LOG2, PGD_T_LOG2);
DEFINE(PTE_T_LOG2, PTE_T_LOG2);
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 39b0c48872d2..9f8b01d6466f 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -299,6 +299,12 @@ slb_miss_user_pseries:
b . /* prevent spec. execution */
#endif /* __DISABLED__ */
+/* KVM's trampoline code needs to be close to the interrupt handlers */
+
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
+#include "../kvm/book3s_rmhandlers.S"
+#endif
+
.align 7
.globl __end_interrupts
__end_interrupts:
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index c571cd3c1453..f0dd577e4a5b 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -166,12 +166,6 @@ exception_marker:
#include "exceptions-64s.S"
#endif
-/* KVM trampoline code needs to be close to the interrupt handlers */
-
-#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
-#include "../kvm/book3s_rmhandlers.S"
-#endif
-
_GLOBAL(generic_secondary_thread_init)
mr r24,r3
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index 9b626cfffce1..f62efdfd1769 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -162,13 +162,10 @@ static int ibmebus_create_device(struct device_node *dn)
dev->dev.bus = &ibmebus_bus_type;
dev->dev.archdata.dma_ops = &ibmebus_dma_ops;
- ret = of_device_register(dev);
- if (ret) {
- of_device_free(dev);
- return ret;
- }
-
- return 0;
+ ret = of_device_add(dev);
+ if (ret)
+ platform_device_put(dev);
+ return ret;
}
static int ibmebus_create_devices(const struct of_device_id *matches)
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c
new file mode 100644
index 000000000000..428d0e538aec
--- /dev/null
+++ b/arch/powerpc/kernel/kvm.c
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved.
+ *
+ * Authors:
+ * Alexander Graf <agraf@suse.de>
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/kvm_host.h>
+#include <linux/init.h>
+#include <linux/kvm_para.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include <asm/reg.h>
+#include <asm/sections.h>
+#include <asm/cacheflush.h>
+#include <asm/disassemble.h>
+
+#define KVM_MAGIC_PAGE (-4096L)
+#define magic_var(x) KVM_MAGIC_PAGE + offsetof(struct kvm_vcpu_arch_shared, x)
+
+#define KVM_INST_LWZ 0x80000000
+#define KVM_INST_STW 0x90000000
+#define KVM_INST_LD 0xe8000000
+#define KVM_INST_STD 0xf8000000
+#define KVM_INST_NOP 0x60000000
+#define KVM_INST_B 0x48000000
+#define KVM_INST_B_MASK 0x03ffffff
+#define KVM_INST_B_MAX 0x01ffffff
+
+#define KVM_MASK_RT 0x03e00000
+#define KVM_RT_30 0x03c00000
+#define KVM_MASK_RB 0x0000f800
+#define KVM_INST_MFMSR 0x7c0000a6
+#define KVM_INST_MFSPR_SPRG0 0x7c1042a6
+#define KVM_INST_MFSPR_SPRG1 0x7c1142a6
+#define KVM_INST_MFSPR_SPRG2 0x7c1242a6
+#define KVM_INST_MFSPR_SPRG3 0x7c1342a6
+#define KVM_INST_MFSPR_SRR0 0x7c1a02a6
+#define KVM_INST_MFSPR_SRR1 0x7c1b02a6
+#define KVM_INST_MFSPR_DAR 0x7c1302a6
+#define KVM_INST_MFSPR_DSISR 0x7c1202a6
+
+#define KVM_INST_MTSPR_SPRG0 0x7c1043a6
+#define KVM_INST_MTSPR_SPRG1 0x7c1143a6
+#define KVM_INST_MTSPR_SPRG2 0x7c1243a6
+#define KVM_INST_MTSPR_SPRG3 0x7c1343a6
+#define KVM_INST_MTSPR_SRR0 0x7c1a03a6
+#define KVM_INST_MTSPR_SRR1 0x7c1b03a6
+#define KVM_INST_MTSPR_DAR 0x7c1303a6
+#define KVM_INST_MTSPR_DSISR 0x7c1203a6
+
+#define KVM_INST_TLBSYNC 0x7c00046c
+#define KVM_INST_MTMSRD_L0 0x7c000164
+#define KVM_INST_MTMSRD_L1 0x7c010164
+#define KVM_INST_MTMSR 0x7c000124
+
+#define KVM_INST_WRTEEI_0 0x7c000146
+#define KVM_INST_WRTEEI_1 0x7c008146
+
+#define KVM_INST_MTSRIN 0x7c0001e4
+
+static bool kvm_patching_worked = true;
+static char kvm_tmp[1024 * 1024];
+static int kvm_tmp_index;
+
+static inline void kvm_patch_ins(u32 *inst, u32 new_inst)
+{
+ *inst = new_inst;
+ flush_icache_range((ulong)inst, (ulong)inst + 4);
+}
+
+static void kvm_patch_ins_ll(u32 *inst, long addr, u32 rt)
+{
+#ifdef CONFIG_64BIT
+ kvm_patch_ins(inst, KVM_INST_LD | rt | (addr & 0x0000fffc));
+#else
+ kvm_patch_ins(inst, KVM_INST_LWZ | rt | (addr & 0x0000fffc));
+#endif
+}
+
+static void kvm_patch_ins_ld(u32 *inst, long addr, u32 rt)
+{
+#ifdef CONFIG_64BIT
+ kvm_patch_ins(inst, KVM_INST_LD | rt | (addr & 0x0000fffc));
+#else
+ kvm_patch_ins(inst, KVM_INST_LWZ | rt | ((addr + 4) & 0x0000fffc));
+#endif
+}
+
+static void kvm_patch_ins_lwz(u32 *inst, long addr, u32 rt)
+{
+ kvm_patch_ins(inst, KVM_INST_LWZ | rt | (addr & 0x0000ffff));
+}
+
+static void kvm_patch_ins_std(u32 *inst, long addr, u32 rt)
+{
+#ifdef CONFIG_64BIT
+ kvm_patch_ins(inst, KVM_INST_STD | rt | (addr & 0x0000fffc));
+#else
+ kvm_patch_ins(inst, KVM_INST_STW | rt | ((addr + 4) & 0x0000fffc));
+#endif
+}
+
+static void kvm_patch_ins_stw(u32 *inst, long addr, u32 rt)
+{
+ kvm_patch_ins(inst, KVM_INST_STW | rt | (addr & 0x0000fffc));
+}
+
+static void kvm_patch_ins_nop(u32 *inst)
+{
+ kvm_patch_ins(inst, KVM_INST_NOP);
+}
+
+static void kvm_patch_ins_b(u32 *inst, int addr)
+{
+#ifdef CONFIG_RELOCATABLE
+ /* On relocatable kernels interrupts handlers and our code
+ can be in different regions, so we don't patch them */
+
+ extern u32 __end_interrupts;
+ if ((ulong)inst < (ulong)&__end_interrupts)
+ return;
+#endif
+
+ kvm_patch_ins(inst, KVM_INST_B | (addr & KVM_INST_B_MASK));
+}
+
+static u32 *kvm_alloc(int len)
+{
+ u32 *p;
+
+ if ((kvm_tmp_index + len) > ARRAY_SIZE(kvm_tmp)) {
+ printk(KERN_ERR "KVM: No more space (%d + %d)\n",
+ kvm_tmp_index, len);
+ kvm_patching_worked = false;
+ return NULL;
+ }
+
+ p = (void*)&kvm_tmp[kvm_tmp_index];
+ kvm_tmp_index += len;
+
+ return p;
+}
+
+extern u32 kvm_emulate_mtmsrd_branch_offs;
+extern u32 kvm_emulate_mtmsrd_reg_offs;
+extern u32 kvm_emulate_mtmsrd_orig_ins_offs;
+extern u32 kvm_emulate_mtmsrd_len;
+extern u32 kvm_emulate_mtmsrd[];
+
+static void kvm_patch_ins_mtmsrd(u32 *inst, u32 rt)
+{
+ u32 *p;
+ int distance_start;
+ int distance_end;
+ ulong next_inst;
+
+ p = kvm_alloc(kvm_emulate_mtmsrd_len * 4);
+ if (!p)
+ return;
+
+ /* Find out where we are and put everything there */
+ distance_start = (ulong)p - (ulong)inst;
+ next_inst = ((ulong)inst + 4);
+ distance_end = next_inst - (ulong)&p[kvm_emulate_mtmsrd_branch_offs];
+
+ /* Make sure we only write valid b instructions */
+ if (distance_start > KVM_INST_B_MAX) {
+ kvm_patching_worked = false;
+ return;
+ }
+
+ /* Modify the chunk to fit the invocation */
+ memcpy(p, kvm_emulate_mtmsrd, kvm_emulate_mtmsrd_len * 4);
+ p[kvm_emulate_mtmsrd_branch_offs] |= distance_end & KVM_INST_B_MASK;
+ switch (get_rt(rt)) {
+ case 30:
+ kvm_patch_ins_ll(&p[kvm_emulate_mtmsrd_reg_offs],
+ magic_var(scratch2), KVM_RT_30);
+ break;
+ case 31:
+ kvm_patch_ins_ll(&p[kvm_emulate_mtmsrd_reg_offs],
+ magic_var(scratch1), KVM_RT_30);
+ break;
+ default:
+ p[kvm_emulate_mtmsrd_reg_offs] |= rt;
+ break;
+ }
+
+ p[kvm_emulate_mtmsrd_orig_ins_offs] = *inst;
+ flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtmsrd_len * 4);
+
+ /* Patch the invocation */
+ kvm_patch_ins_b(inst, distance_start);
+}
+
+extern u32 kvm_emulate_mtmsr_branch_offs;
+extern u32 kvm_emulate_mtmsr_reg1_offs;
+extern u32 kvm_emulate_mtmsr_reg2_offs;
+extern u32 kvm_emulate_mtmsr_orig_ins_offs;
+extern u32 kvm_emulate_mtmsr_len;
+extern u32 kvm_emulate_mtmsr[];
+
+static void kvm_patch_ins_mtmsr(u32 *inst, u32 rt)
+{
+ u32 *p;
+ int distance_start;
+ int distance_end;
+ ulong next_inst;
+
+ p = kvm_alloc(kvm_emulate_mtmsr_len * 4);
+ if (!p)
+ return;
+
+ /* Find out where we are and put everything there */
+ distance_start = (ulong)p - (ulong)inst;
+ next_inst = ((ulong)inst + 4);
+ distance_end = next_inst - (ulong)&p[kvm_emulate_mtmsr_branch_offs];
+
+ /* Make sure we only write valid b instructions */
+ if (distance_start > KVM_INST_B_MAX) {
+ kvm_patching_worked = false;
+ return;
+ }
+
+ /* Modify the chunk to fit the invocation */
+ memcpy(p, kvm_emulate_mtmsr, kvm_emulate_mtmsr_len * 4);
+ p[kvm_emulate_mtmsr_branch_offs] |= distance_end & KVM_INST_B_MASK;
+
+ /* Make clobbered registers work too */
+ switch (get_rt(rt)) {
+ case 30:
+ kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg1_offs],
+ magic_var(scratch2), KVM_RT_30);
+ kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg2_offs],
+ magic_var(scratch2), KVM_RT_30);
+ break;
+ case 31:
+ kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg1_offs],
+ magic_var(scratch1), KVM_RT_30);
+ kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg2_offs],
+ magic_var(scratch1), KVM_RT_30);
+ break;
+ default:
+ p[kvm_emulate_mtmsr_reg1_offs] |= rt;
+ p[kvm_emulate_mtmsr_reg2_offs] |= rt;
+ break;
+ }
+
+ p[kvm_emulate_mtmsr_orig_ins_offs] = *inst;
+ flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtmsr_len * 4);
+
+ /* Patch the invocation */
+ kvm_patch_ins_b(inst, distance_start);
+}
+
+#ifdef CONFIG_BOOKE
+
+extern u32 kvm_emulate_wrteei_branch_offs;
+extern u32 kvm_emulate_wrteei_ee_offs;
+extern u32 kvm_emulate_wrteei_len;
+extern u32 kvm_emulate_wrteei[];
+
+static void kvm_patch_ins_wrteei(u32 *inst)
+{
+ u32 *p;
+ int distance_start;
+ int distance_end;
+ ulong next_inst;
+
+ p = kvm_alloc(kvm_emulate_wrteei_len * 4);
+ if (!p)
+ return;
+
+ /* Find out where we are and put everything there */
+ distance_start = (ulong)p - (ulong)inst;
+ next_inst = ((ulong)inst + 4);
+ distance_end = next_inst - (ulong)&p[kvm_emulate_wrteei_branch_offs];
+
+ /* Make sure we only write valid b instructions */
+ if (distance_start > KVM_INST_B_MAX) {
+ kvm_patching_worked = false;
+ return;
+ }
+
+ /* Modify the chunk to fit the invocation */
+ memcpy(p, kvm_emulate_wrteei, kvm_emulate_wrteei_len * 4);
+ p[kvm_emulate_wrteei_branch_offs] |= distance_end & KVM_INST_B_MASK;
+ p[kvm_emulate_wrteei_ee_offs] |= (*inst & MSR_EE);
+ flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrteei_len * 4);
+
+ /* Patch the invocation */
+ kvm_patch_ins_b(inst, distance_start);
+}
+
+#endif
+
+#ifdef CONFIG_PPC_BOOK3S_32
+
+extern u32 kvm_emulate_mtsrin_branch_offs;
+extern u32 kvm_emulate_mtsrin_reg1_offs;
+extern u32 kvm_emulate_mtsrin_reg2_offs;
+extern u32 kvm_emulate_mtsrin_orig_ins_offs;
+extern u32 kvm_emulate_mtsrin_len;
+extern u32 kvm_emulate_mtsrin[];
+
+static void kvm_patch_ins_mtsrin(u32 *inst, u32 rt, u32 rb)
+{
+ u32 *p;
+ int distance_start;
+ int distance_end;
+ ulong next_inst;
+
+ p = kvm_alloc(kvm_emulate_mtsrin_len * 4);
+ if (!p)
+ return;
+
+ /* Find out where we are and put everything there */
+ distance_start = (ulong)p - (ulong)inst;
+ next_inst = ((ulong)inst + 4);
+ distance_end = next_inst - (ulong)&p[kvm_emulate_mtsrin_branch_offs];
+
+ /* Make sure we only write valid b instructions */
+ if (distance_start > KVM_INST_B_MAX) {
+ kvm_patching_worked = false;
+ return;
+ }
+
+ /* Modify the chunk to fit the invocation */
+ memcpy(p, kvm_emulate_mtsrin, kvm_emulate_mtsrin_len * 4);
+ p[kvm_emulate_mtsrin_branch_offs] |= distance_end & KVM_INST_B_MASK;
+ p[kvm_emulate_mtsrin_reg1_offs] |= (rb << 10);
+ p[kvm_emulate_mtsrin_reg2_offs] |= rt;
+ p[kvm_emulate_mtsrin_orig_ins_offs] = *inst;
+ flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtsrin_len * 4);
+
+ /* Patch the invocation */
+ kvm_patch_ins_b(inst, distance_start);
+}
+
+#endif
+
+static void kvm_map_magic_page(void *data)
+{
+ u32 *features = data;
+
+ ulong in[8];
+ ulong out[8];
+
+ in[0] = KVM_MAGIC_PAGE;
+ in[1] = KVM_MAGIC_PAGE;
+
+ kvm_hypercall(in, out, HC_VENDOR_KVM | KVM_HC_PPC_MAP_MAGIC_PAGE);
+
+ *features = out[0];
+}
+
+static void kvm_check_ins(u32 *inst, u32 features)
+{
+ u32 _inst = *inst;
+ u32 inst_no_rt = _inst & ~KVM_MASK_RT;
+ u32 inst_rt = _inst & KVM_MASK_RT;
+
+ switch (inst_no_rt) {
+ /* Loads */
+ case KVM_INST_MFMSR:
+ kvm_patch_ins_ld(inst, magic_var(msr), inst_rt);
+ break;
+ case KVM_INST_MFSPR_SPRG0:
+ kvm_patch_ins_ld(inst, magic_var(sprg0), inst_rt);
+ break;
+ case KVM_INST_MFSPR_SPRG1:
+ kvm_patch_ins_ld(inst, magic_var(sprg1), inst_rt);
+ break;
+ case KVM_INST_MFSPR_SPRG2:
+ kvm_patch_ins_ld(inst, magic_var(sprg2), inst_rt);
+ break;
+ case KVM_INST_MFSPR_SPRG3:
+ kvm_patch_ins_ld(inst, magic_var(sprg3), inst_rt);
+ break;
+ case KVM_INST_MFSPR_SRR0:
+ kvm_patch_ins_ld(inst, magic_var(srr0), inst_rt);
+ break;
+ case KVM_INST_MFSPR_SRR1:
+ kvm_patch_ins_ld(inst, magic_var(srr1), inst_rt);
+ break;
+ case KVM_INST_MFSPR_DAR:
+ kvm_patch_ins_ld(inst, magic_var(dar), inst_rt);
+ break;
+ case KVM_INST_MFSPR_DSISR:
+ kvm_patch_ins_lwz(inst, magic_var(dsisr), inst_rt);
+ break;
+
+ /* Stores */
+ case KVM_INST_MTSPR_SPRG0:
+ kvm_patch_ins_std(inst, magic_var(sprg0), inst_rt);
+ break;
+ case KVM_INST_MTSPR_SPRG1:
+ kvm_patch_ins_std(inst, magic_var(sprg1), inst_rt);
+ break;
+ case KVM_INST_MTSPR_SPRG2:
+ kvm_patch_ins_std(inst, magic_var(sprg2), inst_rt);
+ break;
+ case KVM_INST_MTSPR_SPRG3:
+ kvm_patch_ins_std(inst, magic_var(sprg3), inst_rt);
+ break;
+ case KVM_INST_MTSPR_SRR0:
+ kvm_patch_ins_std(inst, magic_var(srr0), inst_rt);
+ break;
+ case KVM_INST_MTSPR_SRR1:
+ kvm_patch_ins_std(inst, magic_var(srr1), inst_rt);
+ break;
+ case KVM_INST_MTSPR_DAR:
+ kvm_patch_ins_std(inst, magic_var(dar), inst_rt);
+ break;
+ case KVM_INST_MTSPR_DSISR:
+ kvm_patch_ins_stw(inst, magic_var(dsisr), inst_rt);
+ break;
+
+ /* Nops */
+ case KVM_INST_TLBSYNC:
+ kvm_patch_ins_nop(inst);
+ break;
+
+ /* Rewrites */
+ case KVM_INST_MTMSRD_L1:
+ kvm_patch_ins_mtmsrd(inst, inst_rt);
+ break;
+ case KVM_INST_MTMSR:
+ case KVM_INST_MTMSRD_L0:
+ kvm_patch_ins_mtmsr(inst, inst_rt);
+ break;
+ }
+
+ switch (inst_no_rt & ~KVM_MASK_RB) {
+#ifdef CONFIG_PPC_BOOK3S_32
+ case KVM_INST_MTSRIN:
+ if (features & KVM_MAGIC_FEAT_SR) {
+ u32 inst_rb = _inst & KVM_MASK_RB;
+ kvm_patch_ins_mtsrin(inst, inst_rt, inst_rb);
+ }
+ break;
+ break;
+#endif
+ }
+
+ switch (_inst) {
+#ifdef CONFIG_BOOKE
+ case KVM_INST_WRTEEI_0:
+ case KVM_INST_WRTEEI_1:
+ kvm_patch_ins_wrteei(inst);
+ break;
+#endif
+ }
+}
+
+static void kvm_use_magic_page(void)
+{
+ u32 *p;
+ u32 *start, *end;
+ u32 tmp;
+ u32 features;
+
+ /* Tell the host to map the magic page to -4096 on all CPUs */
+ on_each_cpu(kvm_map_magic_page, &features, 1);
+
+ /* Quick self-test to see if the mapping works */
+ if (__get_user(tmp, (u32*)KVM_MAGIC_PAGE)) {
+ kvm_patching_worked = false;
+ return;
+ }
+
+ /* Now loop through all code and find instructions */
+ start = (void*)_stext;
+ end = (void*)_etext;
+
+ for (p = start; p < end; p++)
+ kvm_check_ins(p, features);
+
+ printk(KERN_INFO "KVM: Live patching for a fast VM %s\n",
+ kvm_patching_worked ? "worked" : "failed");
+}
+
+unsigned long kvm_hypercall(unsigned long *in,
+ unsigned long *out,
+ unsigned long nr)
+{
+ unsigned long register r0 asm("r0");
+ unsigned long register r3 asm("r3") = in[0];
+ unsigned long register r4 asm("r4") = in[1];
+ unsigned long register r5 asm("r5") = in[2];
+ unsigned long register r6 asm("r6") = in[3];
+ unsigned long register r7 asm("r7") = in[4];
+ unsigned long register r8 asm("r8") = in[5];
+ unsigned long register r9 asm("r9") = in[6];
+ unsigned long register r10 asm("r10") = in[7];
+ unsigned long register r11 asm("r11") = nr;
+ unsigned long register r12 asm("r12");
+
+ asm volatile("bl kvm_hypercall_start"
+ : "=r"(r0), "=r"(r3), "=r"(r4), "=r"(r5), "=r"(r6),
+ "=r"(r7), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11),
+ "=r"(r12)
+ : "r"(r3), "r"(r4), "r"(r5), "r"(r6), "r"(r7), "r"(r8),
+ "r"(r9), "r"(r10), "r"(r11)
+ : "memory", "cc", "xer", "ctr", "lr");
+
+ out[0] = r4;
+ out[1] = r5;
+ out[2] = r6;
+ out[3] = r7;
+ out[4] = r8;
+ out[5] = r9;
+ out[6] = r10;
+ out[7] = r11;
+
+ return r3;
+}
+EXPORT_SYMBOL_GPL(kvm_hypercall);
+
+static int kvm_para_setup(void)
+{
+ extern u32 kvm_hypercall_start;
+ struct device_node *hyper_node;
+ u32 *insts;
+ int len, i;
+
+ hyper_node = of_find_node_by_path("/hypervisor");
+ if (!hyper_node)
+ return -1;
+
+ insts = (u32*)of_get_property(hyper_node, "hcall-instructions", &len);
+ if (len % 4)
+ return -1;
+ if (len > (4 * 4))
+ return -1;
+
+ for (i = 0; i < (len / 4); i++)
+ kvm_patch_ins(&(&kvm_hypercall_start)[i], insts[i]);
+
+ return 0;
+}
+
+static __init void kvm_free_tmp(void)
+{
+ unsigned long start, end;
+
+ start = (ulong)&kvm_tmp[kvm_tmp_index + (PAGE_SIZE - 1)] & PAGE_MASK;
+ end = (ulong)&kvm_tmp[ARRAY_SIZE(kvm_tmp)] & PAGE_MASK;
+
+ /* Free the tmp space we don't need */
+ for (; start < end; start += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(start));
+ init_page_count(virt_to_page(start));
+ free_page(start);
+ totalram_pages++;
+ }
+}
+
+static int __init kvm_guest_init(void)
+{
+ if (!kvm_para_available())
+ goto free_tmp;
+
+ if (kvm_para_setup())
+ goto free_tmp;
+
+ if (kvm_para_has_feature(KVM_FEATURE_MAGIC_PAGE))
+ kvm_use_magic_page();
+
+#ifdef CONFIG_PPC_BOOK3S_64
+ /* Enable napping */
+ powersave_nap = 1;
+#endif
+
+free_tmp:
+ kvm_free_tmp();
+
+ return 0;
+}
+
+postcore_initcall(kvm_guest_init);
diff --git a/arch/powerpc/kernel/kvm_emul.S b/arch/powerpc/kernel/kvm_emul.S
new file mode 100644
index 000000000000..f2b1b2523e61
--- /dev/null
+++ b/arch/powerpc/kernel/kvm_emul.S
@@ -0,0 +1,302 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright SUSE Linux Products GmbH 2010
+ *
+ * Authors: Alexander Graf <agraf@suse.de>
+ */
+
+#include <asm/ppc_asm.h>
+#include <asm/kvm_asm.h>
+#include <asm/reg.h>
+#include <asm/page.h>
+#include <asm/asm-offsets.h>
+
+/* Hypercall entry point. Will be patched with device tree instructions. */
+
+.global kvm_hypercall_start
+kvm_hypercall_start:
+ li r3, -1
+ nop
+ nop
+ nop
+ blr
+
+#define KVM_MAGIC_PAGE (-4096)
+
+#ifdef CONFIG_64BIT
+#define LL64(reg, offs, reg2) ld reg, (offs)(reg2)
+#define STL64(reg, offs, reg2) std reg, (offs)(reg2)
+#else
+#define LL64(reg, offs, reg2) lwz reg, (offs + 4)(reg2)
+#define STL64(reg, offs, reg2) stw reg, (offs + 4)(reg2)
+#endif
+
+#define SCRATCH_SAVE \
+ /* Enable critical section. We are critical if \
+ shared->critical == r1 */ \
+ STL64(r1, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0); \
+ \
+ /* Save state */ \
+ PPC_STL r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH1)(0); \
+ PPC_STL r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH2)(0); \
+ mfcr r31; \
+ stw r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH3)(0);
+
+#define SCRATCH_RESTORE \
+ /* Restore state */ \
+ PPC_LL r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH1)(0); \
+ lwz r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH3)(0); \
+ mtcr r30; \
+ PPC_LL r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH2)(0); \
+ \
+ /* Disable critical section. We are critical if \
+ shared->critical == r1 and r2 is always != r1 */ \
+ STL64(r2, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0);
+
+.global kvm_emulate_mtmsrd
+kvm_emulate_mtmsrd:
+
+ SCRATCH_SAVE
+
+ /* Put MSR & ~(MSR_EE|MSR_RI) in r31 */
+ LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+ lis r30, (~(MSR_EE | MSR_RI))@h
+ ori r30, r30, (~(MSR_EE | MSR_RI))@l
+ and r31, r31, r30
+
+ /* OR the register's (MSR_EE|MSR_RI) on MSR */
+kvm_emulate_mtmsrd_reg:
+ ori r30, r0, 0
+ andi. r30, r30, (MSR_EE|MSR_RI)
+ or r31, r31, r30
+
+ /* Put MSR back into magic page */
+ STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
+ /* Check if we have to fetch an interrupt */
+ lwz r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
+ cmpwi r31, 0
+ beq+ no_check
+
+ /* Check if we may trigger an interrupt */
+ andi. r30, r30, MSR_EE
+ beq no_check
+
+ SCRATCH_RESTORE
+
+ /* Nag hypervisor */
+kvm_emulate_mtmsrd_orig_ins:
+ tlbsync
+
+ b kvm_emulate_mtmsrd_branch
+
+no_check:
+
+ SCRATCH_RESTORE
+
+ /* Go back to caller */
+kvm_emulate_mtmsrd_branch:
+ b .
+kvm_emulate_mtmsrd_end:
+
+.global kvm_emulate_mtmsrd_branch_offs
+kvm_emulate_mtmsrd_branch_offs:
+ .long (kvm_emulate_mtmsrd_branch - kvm_emulate_mtmsrd) / 4
+
+.global kvm_emulate_mtmsrd_reg_offs
+kvm_emulate_mtmsrd_reg_offs:
+ .long (kvm_emulate_mtmsrd_reg - kvm_emulate_mtmsrd) / 4
+
+.global kvm_emulate_mtmsrd_orig_ins_offs
+kvm_emulate_mtmsrd_orig_ins_offs:
+ .long (kvm_emulate_mtmsrd_orig_ins - kvm_emulate_mtmsrd) / 4
+
+.global kvm_emulate_mtmsrd_len
+kvm_emulate_mtmsrd_len:
+ .long (kvm_emulate_mtmsrd_end - kvm_emulate_mtmsrd) / 4
+
+
+#define MSR_SAFE_BITS (MSR_EE | MSR_CE | MSR_ME | MSR_RI)
+#define MSR_CRITICAL_BITS ~MSR_SAFE_BITS
+
+.global kvm_emulate_mtmsr
+kvm_emulate_mtmsr:
+
+ SCRATCH_SAVE
+
+ /* Fetch old MSR in r31 */
+ LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
+ /* Find the changed bits between old and new MSR */
+kvm_emulate_mtmsr_reg1:
+ ori r30, r0, 0
+ xor r31, r30, r31
+
+ /* Check if we need to really do mtmsr */
+ LOAD_REG_IMMEDIATE(r30, MSR_CRITICAL_BITS)
+ and. r31, r31, r30
+
+ /* No critical bits changed? Maybe we can stay in the guest. */
+ beq maybe_stay_in_guest
+
+do_mtmsr:
+
+ SCRATCH_RESTORE
+
+ /* Just fire off the mtmsr if it's critical */
+kvm_emulate_mtmsr_orig_ins:
+ mtmsr r0
+
+ b kvm_emulate_mtmsr_branch
+
+maybe_stay_in_guest:
+
+ /* Get the target register in r30 */
+kvm_emulate_mtmsr_reg2:
+ ori r30, r0, 0
+
+ /* Check if we have to fetch an interrupt */
+ lwz r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
+ cmpwi r31, 0
+ beq+ no_mtmsr
+
+ /* Check if we may trigger an interrupt */
+ andi. r31, r30, MSR_EE
+ beq no_mtmsr
+
+ b do_mtmsr
+
+no_mtmsr:
+
+ /* Put MSR into magic page because we don't call mtmsr */
+ STL64(r30, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
+ SCRATCH_RESTORE
+
+ /* Go back to caller */
+kvm_emulate_mtmsr_branch:
+ b .
+kvm_emulate_mtmsr_end:
+
+.global kvm_emulate_mtmsr_branch_offs
+kvm_emulate_mtmsr_branch_offs:
+ .long (kvm_emulate_mtmsr_branch - kvm_emulate_mtmsr) / 4
+
+.global kvm_emulate_mtmsr_reg1_offs
+kvm_emulate_mtmsr_reg1_offs:
+ .long (kvm_emulate_mtmsr_reg1 - kvm_emulate_mtmsr) / 4
+
+.global kvm_emulate_mtmsr_reg2_offs
+kvm_emulate_mtmsr_reg2_offs:
+ .long (kvm_emulate_mtmsr_reg2 - kvm_emulate_mtmsr) / 4
+
+.global kvm_emulate_mtmsr_orig_ins_offs
+kvm_emulate_mtmsr_orig_ins_offs:
+ .long (kvm_emulate_mtmsr_orig_ins - kvm_emulate_mtmsr) / 4
+
+.global kvm_emulate_mtmsr_len
+kvm_emulate_mtmsr_len:
+ .long (kvm_emulate_mtmsr_end - kvm_emulate_mtmsr) / 4
+
+
+
+.global kvm_emulate_wrteei
+kvm_emulate_wrteei:
+
+ SCRATCH_SAVE
+
+ /* Fetch old MSR in r31 */
+ LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
+ /* Remove MSR_EE from old MSR */
+ li r30, 0
+ ori r30, r30, MSR_EE
+ andc r31, r31, r30
+
+ /* OR new MSR_EE onto the old MSR */
+kvm_emulate_wrteei_ee:
+ ori r31, r31, 0
+
+ /* Write new MSR value back */
+ STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
+ SCRATCH_RESTORE
+
+ /* Go back to caller */
+kvm_emulate_wrteei_branch:
+ b .
+kvm_emulate_wrteei_end:
+
+.global kvm_emulate_wrteei_branch_offs
+kvm_emulate_wrteei_branch_offs:
+ .long (kvm_emulate_wrteei_branch - kvm_emulate_wrteei) / 4
+
+.global kvm_emulate_wrteei_ee_offs
+kvm_emulate_wrteei_ee_offs:
+ .long (kvm_emulate_wrteei_ee - kvm_emulate_wrteei) / 4
+
+.global kvm_emulate_wrteei_len
+kvm_emulate_wrteei_len:
+ .long (kvm_emulate_wrteei_end - kvm_emulate_wrteei) / 4
+
+
+.global kvm_emulate_mtsrin
+kvm_emulate_mtsrin:
+
+ SCRATCH_SAVE
+
+ LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+ andi. r31, r31, MSR_DR | MSR_IR
+ beq kvm_emulate_mtsrin_reg1
+
+ SCRATCH_RESTORE
+
+kvm_emulate_mtsrin_orig_ins:
+ nop
+ b kvm_emulate_mtsrin_branch
+
+kvm_emulate_mtsrin_reg1:
+ /* rX >> 26 */
+ rlwinm r30,r0,6,26,29
+
+kvm_emulate_mtsrin_reg2:
+ stw r0, (KVM_MAGIC_PAGE + KVM_MAGIC_SR)(r30)
+
+ SCRATCH_RESTORE
+
+ /* Go back to caller */
+kvm_emulate_mtsrin_branch:
+ b .
+kvm_emulate_mtsrin_end:
+
+.global kvm_emulate_mtsrin_branch_offs
+kvm_emulate_mtsrin_branch_offs:
+ .long (kvm_emulate_mtsrin_branch - kvm_emulate_mtsrin) / 4
+
+.global kvm_emulate_mtsrin_reg1_offs
+kvm_emulate_mtsrin_reg1_offs:
+ .long (kvm_emulate_mtsrin_reg1 - kvm_emulate_mtsrin) / 4
+
+.global kvm_emulate_mtsrin_reg2_offs
+kvm_emulate_mtsrin_reg2_offs:
+ .long (kvm_emulate_mtsrin_reg2 - kvm_emulate_mtsrin) / 4
+
+.global kvm_emulate_mtsrin_orig_ins_offs
+kvm_emulate_mtsrin_orig_ins_offs:
+ .long (kvm_emulate_mtsrin_orig_ins - kvm_emulate_mtsrin) / 4
+
+.global kvm_emulate_mtsrin_len
+kvm_emulate_mtsrin_len:
+ .long (kvm_emulate_mtsrin_end - kvm_emulate_mtsrin) / 4
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
index c1fd0f9658fd..c834757bebc0 100644
--- a/arch/powerpc/kernel/legacy_serial.c
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -52,14 +52,14 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
phys_addr_t taddr, unsigned long irq,
upf_t flags, int irq_check_parent)
{
- const u32 *clk, *spd;
+ const __be32 *clk, *spd;
u32 clock = BASE_BAUD * 16;
int index;
/* get clock freq. if present */
clk = of_get_property(np, "clock-frequency", NULL);
if (clk && *clk)
- clock = *clk;
+ clock = be32_to_cpup(clk);
/* get default speed if present */
spd = of_get_property(np, "current-speed", NULL);
@@ -109,7 +109,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
legacy_serial_infos[index].taddr = taddr;
legacy_serial_infos[index].np = of_node_get(np);
legacy_serial_infos[index].clock = clock;
- legacy_serial_infos[index].speed = spd ? *spd : 0;
+ legacy_serial_infos[index].speed = spd ? be32_to_cpup(spd) : 0;
legacy_serial_infos[index].irq_check_parent = irq_check_parent;
printk(KERN_DEBUG "Found legacy serial port %d for %s\n",
@@ -168,7 +168,7 @@ static int __init add_legacy_soc_port(struct device_node *np,
static int __init add_legacy_isa_port(struct device_node *np,
struct device_node *isa_brg)
{
- const u32 *reg;
+ const __be32 *reg;
const char *typep;
int index = -1;
u64 taddr;
@@ -181,7 +181,7 @@ static int __init add_legacy_isa_port(struct device_node *np,
return -1;
/* Verify it's an IO port, we don't support anything else */
- if (!(reg[0] & 0x00000001))
+ if (!(be32_to_cpu(reg[0]) & 0x00000001))
return -1;
/* Now look for an "ibm,aix-loc" property that gives us ordering
@@ -202,7 +202,7 @@ static int __init add_legacy_isa_port(struct device_node *np,
taddr = 0;
/* Add port, irq will be dealt with later */
- return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr,
+ return add_legacy_port(np, index, UPIO_PORT, be32_to_cpu(reg[1]), taddr,
NO_IRQ, UPF_BOOT_AUTOCONF, 0);
}
@@ -251,9 +251,9 @@ static int __init add_legacy_pci_port(struct device_node *np,
* we get to their "reg" property
*/
if (np != pci_dev) {
- const u32 *reg = of_get_property(np, "reg", NULL);
- if (reg && (*reg < 4))
- index = lindex = *reg;
+ const __be32 *reg = of_get_property(np, "reg", NULL);
+ if (reg && (be32_to_cpup(reg) < 4))
+ index = lindex = be32_to_cpup(reg);
}
/* Local index means it's the Nth port in the PCI chip. Unfortunately
@@ -507,7 +507,7 @@ static int __init check_legacy_serial_console(void)
struct device_node *prom_stdout = NULL;
int i, speed = 0, offset = 0;
const char *name;
- const u32 *spd;
+ const __be32 *spd;
DBG(" -> check_legacy_serial_console()\n");
@@ -547,7 +547,7 @@ static int __init check_legacy_serial_console(void)
}
spd = of_get_property(prom_stdout, "current-speed", NULL);
if (spd)
- speed = *spd;
+ speed = be32_to_cpup(spd);
if (strcmp(name, "serial") != 0)
goto not_found;
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index c3c6a8857544..9e3132db718b 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -364,10 +364,15 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
return 0;
}
-void __init early_init_dt_scan_chosen_arch(unsigned long node)
+int __init early_init_dt_scan_chosen_ppc(unsigned long node, const char *uname,
+ int depth, void *data)
{
unsigned long *lprop;
+ /* Use common scan routine to determine if this is the chosen node */
+ if (early_init_dt_scan_chosen(node, uname, depth, data) == 0)
+ return 0;
+
#ifdef CONFIG_PPC64
/* check if iommu is forced on or off */
if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL)
@@ -399,6 +404,9 @@ void __init early_init_dt_scan_chosen_arch(unsigned long node)
if (lprop)
crashk_res.end = crashk_res.start + *lprop - 1;
#endif
+
+ /* break now */
+ return 1;
}
#ifdef CONFIG_PPC_PSERIES
@@ -683,7 +691,7 @@ void __init early_init_devtree(void *params)
* device-tree, including the platform type, initrd location and
* size, TCE reserve, and more ...
*/
- of_scan_flat_dt(early_init_dt_scan_chosen, NULL);
+ of_scan_flat_dt(early_init_dt_scan_chosen_ppc, NULL);
/* Scan memory nodes and rebuild MEMBLOCKs */
memblock_init();
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 286d9783d93f..a9b32967cff6 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -1406,37 +1406,42 @@ static long ppc_del_hwdebug(struct task_struct *child, long addr, long data)
* Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
* we mark them as obsolete now, they will be removed in a future version
*/
-static long arch_ptrace_old(struct task_struct *child, long request, long addr,
- long data)
+static long arch_ptrace_old(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
+ void __user *datavp = (void __user *) data;
+
switch (request) {
case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
return copy_regset_to_user(child, &user_ppc_native_view,
REGSET_GPR, 0, 32 * sizeof(long),
- (void __user *) data);
+ datavp);
case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
return copy_regset_from_user(child, &user_ppc_native_view,
REGSET_GPR, 0, 32 * sizeof(long),
- (const void __user *) data);
+ datavp);
case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */
return copy_regset_to_user(child, &user_ppc_native_view,
REGSET_FPR, 0, 32 * sizeof(double),
- (void __user *) data);
+ datavp);
case PPC_PTRACE_SETFPREGS: /* Set FPRs 0 - 31. */
return copy_regset_from_user(child, &user_ppc_native_view,
REGSET_FPR, 0, 32 * sizeof(double),
- (const void __user *) data);
+ datavp);
}
return -EPERM;
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret = -EPERM;
+ void __user *datavp = (void __user *) data;
+ unsigned long __user *datalp = datavp;
switch (request) {
/* read the word at location addr in the USER area. */
@@ -1446,11 +1451,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = -EIO;
/* convert to index and check */
#ifdef CONFIG_PPC32
- index = (unsigned long) addr >> 2;
+ index = addr >> 2;
if ((addr & 3) || (index > PT_FPSCR)
|| (child->thread.regs == NULL))
#else
- index = (unsigned long) addr >> 3;
+ index = addr >> 3;
if ((addr & 7) || (index > PT_FPSCR))
#endif
break;
@@ -1463,7 +1468,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
tmp = ((unsigned long *)child->thread.fpr)
[TS_FPRWIDTH * (index - PT_FPR0)];
}
- ret = put_user(tmp,(unsigned long __user *) data);
+ ret = put_user(tmp, datalp);
break;
}
@@ -1474,11 +1479,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = -EIO;
/* convert to index and check */
#ifdef CONFIG_PPC32
- index = (unsigned long) addr >> 2;
+ index = addr >> 2;
if ((addr & 3) || (index > PT_FPSCR)
|| (child->thread.regs == NULL))
#else
- index = (unsigned long) addr >> 3;
+ index = addr >> 3;
if ((addr & 7) || (index > PT_FPSCR))
#endif
break;
@@ -1525,11 +1530,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
dbginfo.features = 0;
#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
- if (!access_ok(VERIFY_WRITE, data,
+ if (!access_ok(VERIFY_WRITE, datavp,
sizeof(struct ppc_debug_info)))
return -EFAULT;
- ret = __copy_to_user((struct ppc_debug_info __user *)data,
- &dbginfo, sizeof(struct ppc_debug_info)) ?
+ ret = __copy_to_user(datavp, &dbginfo,
+ sizeof(struct ppc_debug_info)) ?
-EFAULT : 0;
break;
}
@@ -1537,11 +1542,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PPC_PTRACE_SETHWDEBUG: {
struct ppc_hw_breakpoint bp_info;
- if (!access_ok(VERIFY_READ, data,
+ if (!access_ok(VERIFY_READ, datavp,
sizeof(struct ppc_hw_breakpoint)))
return -EFAULT;
- ret = __copy_from_user(&bp_info,
- (struct ppc_hw_breakpoint __user *)data,
+ ret = __copy_from_user(&bp_info, datavp,
sizeof(struct ppc_hw_breakpoint)) ?
-EFAULT : 0;
if (!ret)
@@ -1560,11 +1564,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
if (addr > 0)
break;
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
- ret = put_user(child->thread.dac1,
- (unsigned long __user *)data);
+ ret = put_user(child->thread.dac1, datalp);
#else
- ret = put_user(child->thread.dabr,
- (unsigned long __user *)data);
+ ret = put_user(child->thread.dabr, datalp);
#endif
break;
}
@@ -1580,7 +1582,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
return copy_regset_to_user(child, &user_ppc_native_view,
REGSET_GPR,
0, sizeof(struct pt_regs),
- (void __user *) data);
+ datavp);
#ifdef CONFIG_PPC64
case PTRACE_SETREGS64:
@@ -1589,19 +1591,19 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
return copy_regset_from_user(child, &user_ppc_native_view,
REGSET_GPR,
0, sizeof(struct pt_regs),
- (const void __user *) data);
+ datavp);
case PTRACE_GETFPREGS: /* Get the child FPU state (FPR0...31 + FPSCR) */
return copy_regset_to_user(child, &user_ppc_native_view,
REGSET_FPR,
0, sizeof(elf_fpregset_t),
- (void __user *) data);
+ datavp);
case PTRACE_SETFPREGS: /* Set the child FPU state (FPR0...31 + FPSCR) */
return copy_regset_from_user(child, &user_ppc_native_view,
REGSET_FPR,
0, sizeof(elf_fpregset_t),
- (const void __user *) data);
+ datavp);
#ifdef CONFIG_ALTIVEC
case PTRACE_GETVRREGS:
@@ -1609,40 +1611,40 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
REGSET_VMX,
0, (33 * sizeof(vector128) +
sizeof(u32)),
- (void __user *) data);
+ datavp);
case PTRACE_SETVRREGS:
return copy_regset_from_user(child, &user_ppc_native_view,
REGSET_VMX,
0, (33 * sizeof(vector128) +
sizeof(u32)),
- (const void __user *) data);
+ datavp);
#endif
#ifdef CONFIG_VSX
case PTRACE_GETVSRREGS:
return copy_regset_to_user(child, &user_ppc_native_view,
REGSET_VSX,
0, 32 * sizeof(double),
- (void __user *) data);
+ datavp);
case PTRACE_SETVSRREGS:
return copy_regset_from_user(child, &user_ppc_native_view,
REGSET_VSX,
0, 32 * sizeof(double),
- (const void __user *) data);
+ datavp);
#endif
#ifdef CONFIG_SPE
case PTRACE_GETEVRREGS:
/* Get the child spe register state. */
return copy_regset_to_user(child, &user_ppc_native_view,
REGSET_SPE, 0, 35 * sizeof(u32),
- (void __user *) data);
+ datavp);
case PTRACE_SETEVRREGS:
/* Set the child spe register state. */
return copy_regset_from_user(child, &user_ppc_native_view,
REGSET_SPE, 0, 35 * sizeof(u32),
- (const void __user *) data);
+ datavp);
#endif
/* Old reverse args ptrace callss */
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index d692989a4318..441d2a722f06 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -238,9 +238,7 @@ static inline void vio_cmo_dealloc(struct vio_dev *viodev, size_t size)
* memory in this pool does not change.
*/
if (spare_needed && reserve_freed) {
- tmp = min(spare_needed, min(reserve_freed,
- (viodev->cmo.entitled -
- VIO_CMO_MIN_ENT)));
+ tmp = min3(spare_needed, reserve_freed, (viodev->cmo.entitled - VIO_CMO_MIN_ENT));
vio_cmo.spare += tmp;
viodev->cmo.entitled -= tmp;
diff --git a/arch/powerpc/kvm/44x.c b/arch/powerpc/kvm/44x.c
index 73c0a3f64ed1..74d0e7421143 100644
--- a/arch/powerpc/kvm/44x.c
+++ b/arch/powerpc/kvm/44x.c
@@ -43,7 +43,7 @@ int kvmppc_core_check_processor_compat(void)
{
int r;
- if (strcmp(cur_cpu_spec->platform, "ppc440") == 0)
+ if (strncmp(cur_cpu_spec->platform, "ppc440", 6) == 0)
r = 0;
else
r = -ENOTSUPP;
@@ -72,6 +72,7 @@ int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)
/* Since the guest can directly access the timebase, it must know the
* real timebase frequency. Accordingly, it must see the state of
* CCR1[TCS]. */
+ /* XXX CCR1 doesn't exist on all 440 SoCs. */
vcpu->arch.ccr1 = mfspr(SPRN_CCR1);
for (i = 0; i < ARRAY_SIZE(vcpu_44x->shadow_refs); i++)
@@ -123,8 +124,14 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
if (err)
goto free_vcpu;
+ vcpu->arch.shared = (void*)__get_free_page(GFP_KERNEL|__GFP_ZERO);
+ if (!vcpu->arch.shared)
+ goto uninit_vcpu;
+
return vcpu;
+uninit_vcpu:
+ kvm_vcpu_uninit(vcpu);
free_vcpu:
kmem_cache_free(kvm_vcpu_cache, vcpu_44x);
out:
@@ -135,6 +142,7 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
{
struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
+ free_page((unsigned long)vcpu->arch.shared);
kvm_vcpu_uninit(vcpu);
kmem_cache_free(kvm_vcpu_cache, vcpu_44x);
}
diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c
index 9b9b5cdea840..5f3cff83e089 100644
--- a/arch/powerpc/kvm/44x_tlb.c
+++ b/arch/powerpc/kvm/44x_tlb.c
@@ -47,6 +47,7 @@
#ifdef DEBUG
void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu)
{
+ struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
struct kvmppc_44x_tlbe *tlbe;
int i;
@@ -221,14 +222,14 @@ gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int gtlb_index,
int kvmppc_mmu_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr)
{
- unsigned int as = !!(vcpu->arch.msr & MSR_IS);
+ unsigned int as = !!(vcpu->arch.shared->msr & MSR_IS);
return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
}
int kvmppc_mmu_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr)
{
- unsigned int as = !!(vcpu->arch.msr & MSR_DS);
+ unsigned int as = !!(vcpu->arch.shared->msr & MSR_DS);
return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
}
@@ -354,7 +355,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr,
stlbe.word1 = (hpaddr & 0xfffffc00) | ((hpaddr >> 32) & 0xf);
stlbe.word2 = kvmppc_44x_tlb_shadow_attrib(flags,
- vcpu->arch.msr & MSR_PR);
+ vcpu->arch.shared->msr & MSR_PR);
stlbe.tid = !(asid & 0xff);
/* Keep track of the reference so we can properly release it later. */
@@ -423,7 +424,7 @@ static int tlbe_is_host_safe(const struct kvm_vcpu *vcpu,
/* Does it match current guest AS? */
/* XXX what about IS != DS? */
- if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS))
+ if (get_tlb_ts(tlbe) != !!(vcpu->arch.shared->msr & MSR_IS))
return 0;
gpa = get_tlb_raddr(tlbe);
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index a3cef30d1d42..e316847c08c0 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -17,6 +17,7 @@
#include <linux/kvm_host.h>
#include <linux/err.h>
#include <linux/slab.h>
+#include "trace.h"
#include <asm/reg.h>
#include <asm/cputable.h>
@@ -35,7 +36,6 @@
#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
/* #define EXIT_DEBUG */
-/* #define EXIT_DEBUG_SIMPLE */
/* #define DEBUG_EXT */
static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
@@ -105,65 +105,71 @@ void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
kvmppc_giveup_ext(vcpu, MSR_VSX);
}
-#if defined(EXIT_DEBUG)
-static u32 kvmppc_get_dec(struct kvm_vcpu *vcpu)
-{
- u64 jd = mftb() - vcpu->arch.dec_jiffies;
- return vcpu->arch.dec - jd;
-}
-#endif
-
static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu)
{
- vcpu->arch.shadow_msr = vcpu->arch.msr;
+ ulong smsr = vcpu->arch.shared->msr;
+
/* Guest MSR values */
- vcpu->arch.shadow_msr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE |
- MSR_BE | MSR_DE;
+ smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE | MSR_DE;
/* Process MSR values */
- vcpu->arch.shadow_msr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR |
- MSR_EE;
+ smsr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR | MSR_EE;
/* External providers the guest reserved */
- vcpu->arch.shadow_msr |= (vcpu->arch.msr & vcpu->arch.guest_owned_ext);
+ smsr |= (vcpu->arch.shared->msr & vcpu->arch.guest_owned_ext);
/* 64-bit Process MSR values */
#ifdef CONFIG_PPC_BOOK3S_64
- vcpu->arch.shadow_msr |= MSR_ISF | MSR_HV;
+ smsr |= MSR_ISF | MSR_HV;
#endif
+ vcpu->arch.shadow_msr = smsr;
}
void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)
{
- ulong old_msr = vcpu->arch.msr;
+ ulong old_msr = vcpu->arch.shared->msr;
#ifdef EXIT_DEBUG
printk(KERN_INFO "KVM: Set MSR to 0x%llx\n", msr);
#endif
msr &= to_book3s(vcpu)->msr_mask;
- vcpu->arch.msr = msr;
+ vcpu->arch.shared->msr = msr;
kvmppc_recalc_shadow_msr(vcpu);
- if (msr & (MSR_WE|MSR_POW)) {
+ if (msr & MSR_POW) {
if (!vcpu->arch.pending_exceptions) {
kvm_vcpu_block(vcpu);
vcpu->stat.halt_wakeup++;
+
+ /* Unset POW bit after we woke up */
+ msr &= ~MSR_POW;
+ vcpu->arch.shared->msr = msr;
}
}
- if ((vcpu->arch.msr & (MSR_PR|MSR_IR|MSR_DR)) !=
+ if ((vcpu->arch.shared->msr & (MSR_PR|MSR_IR|MSR_DR)) !=
(old_msr & (MSR_PR|MSR_IR|MSR_DR))) {
kvmppc_mmu_flush_segments(vcpu);
kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
+
+ /* Preload magic page segment when in kernel mode */
+ if (!(msr & MSR_PR) && vcpu->arch.magic_page_pa) {
+ struct kvm_vcpu_arch *a = &vcpu->arch;
+
+ if (msr & MSR_DR)
+ kvmppc_mmu_map_segment(vcpu, a->magic_page_ea);
+ else
+ kvmppc_mmu_map_segment(vcpu, a->magic_page_pa);
+ }
}
/* Preload FPU if it's enabled */
- if (vcpu->arch.msr & MSR_FP)
+ if (vcpu->arch.shared->msr & MSR_FP)
kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
}
void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags)
{
- vcpu->arch.srr0 = kvmppc_get_pc(vcpu);
- vcpu->arch.srr1 = vcpu->arch.msr | flags;
+ vcpu->arch.shared->srr0 = kvmppc_get_pc(vcpu);
+ vcpu->arch.shared->srr1 = vcpu->arch.shared->msr | flags;
kvmppc_set_pc(vcpu, to_book3s(vcpu)->hior + vec);
vcpu->arch.mmu.reset_msr(vcpu);
}
@@ -180,6 +186,7 @@ static int kvmppc_book3s_vec2irqprio(unsigned int vec)
case 0x400: prio = BOOK3S_IRQPRIO_INST_STORAGE; break;
case 0x480: prio = BOOK3S_IRQPRIO_INST_SEGMENT; break;
case 0x500: prio = BOOK3S_IRQPRIO_EXTERNAL; break;
+ case 0x501: prio = BOOK3S_IRQPRIO_EXTERNAL_LEVEL; break;
case 0x600: prio = BOOK3S_IRQPRIO_ALIGNMENT; break;
case 0x700: prio = BOOK3S_IRQPRIO_PROGRAM; break;
case 0x800: prio = BOOK3S_IRQPRIO_FP_UNAVAIL; break;
@@ -199,6 +206,9 @@ static void kvmppc_book3s_dequeue_irqprio(struct kvm_vcpu *vcpu,
{
clear_bit(kvmppc_book3s_vec2irqprio(vec),
&vcpu->arch.pending_exceptions);
+
+ if (!vcpu->arch.pending_exceptions)
+ vcpu->arch.shared->int_pending = 0;
}
void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec)
@@ -237,13 +247,19 @@ void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu)
void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
struct kvm_interrupt *irq)
{
- kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL);
+ unsigned int vec = BOOK3S_INTERRUPT_EXTERNAL;
+
+ if (irq->irq == KVM_INTERRUPT_SET_LEVEL)
+ vec = BOOK3S_INTERRUPT_EXTERNAL_LEVEL;
+
+ kvmppc_book3s_queue_irqprio(vcpu, vec);
}
void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu,
struct kvm_interrupt *irq)
{
kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL);
+ kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL_LEVEL);
}
int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
@@ -251,14 +267,29 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
int deliver = 1;
int vec = 0;
ulong flags = 0ULL;
+ ulong crit_raw = vcpu->arch.shared->critical;
+ ulong crit_r1 = kvmppc_get_gpr(vcpu, 1);
+ bool crit;
+
+ /* Truncate crit indicators in 32 bit mode */
+ if (!(vcpu->arch.shared->msr & MSR_SF)) {
+ crit_raw &= 0xffffffff;
+ crit_r1 &= 0xffffffff;
+ }
+
+ /* Critical section when crit == r1 */
+ crit = (crit_raw == crit_r1);
+ /* ... and we're in supervisor mode */
+ crit = crit && !(vcpu->arch.shared->msr & MSR_PR);
switch (priority) {
case BOOK3S_IRQPRIO_DECREMENTER:
- deliver = vcpu->arch.msr & MSR_EE;
+ deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit;
vec = BOOK3S_INTERRUPT_DECREMENTER;
break;
case BOOK3S_IRQPRIO_EXTERNAL:
- deliver = vcpu->arch.msr & MSR_EE;
+ case BOOK3S_IRQPRIO_EXTERNAL_LEVEL:
+ deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit;
vec = BOOK3S_INTERRUPT_EXTERNAL;
break;
case BOOK3S_IRQPRIO_SYSTEM_RESET:
@@ -320,9 +351,27 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
return deliver;
}
+/*
+ * This function determines if an irqprio should be cleared once issued.
+ */
+static bool clear_irqprio(struct kvm_vcpu *vcpu, unsigned int priority)
+{
+ switch (priority) {
+ case BOOK3S_IRQPRIO_DECREMENTER:
+ /* DEC interrupts get cleared by mtdec */
+ return false;
+ case BOOK3S_IRQPRIO_EXTERNAL_LEVEL:
+ /* External interrupts get cleared by userspace */
+ return false;
+ }
+
+ return true;
+}
+
void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
{
unsigned long *pending = &vcpu->arch.pending_exceptions;
+ unsigned long old_pending = vcpu->arch.pending_exceptions;
unsigned int priority;
#ifdef EXIT_DEBUG
@@ -332,8 +381,7 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
priority = __ffs(*pending);
while (priority < BOOK3S_IRQPRIO_MAX) {
if (kvmppc_book3s_irqprio_deliver(vcpu, priority) &&
- (priority != BOOK3S_IRQPRIO_DECREMENTER)) {
- /* DEC interrupts get cleared by mtdec */
+ clear_irqprio(vcpu, priority)) {
clear_bit(priority, &vcpu->arch.pending_exceptions);
break;
}
@@ -342,6 +390,12 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
BITS_PER_BYTE * sizeof(*pending),
priority + 1);
}
+
+ /* Tell the guest about our interrupt status */
+ if (*pending)
+ vcpu->arch.shared->int_pending = 1;
+ else if (old_pending)
+ vcpu->arch.shared->int_pending = 0;
}
void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
@@ -398,6 +452,25 @@ void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
}
}
+pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn)
+{
+ ulong mp_pa = vcpu->arch.magic_page_pa;
+
+ /* Magic page override */
+ if (unlikely(mp_pa) &&
+ unlikely(((gfn << PAGE_SHIFT) & KVM_PAM) ==
+ ((mp_pa & PAGE_MASK) & KVM_PAM))) {
+ ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK;
+ pfn_t pfn;
+
+ pfn = (pfn_t)virt_to_phys((void*)shared_page) >> PAGE_SHIFT;
+ get_page(pfn_to_page(pfn));
+ return pfn;
+ }
+
+ return gfn_to_pfn(vcpu->kvm, gfn);
+}
+
/* Book3s_32 CPUs always have 32 bytes cache line size, which Linux assumes. To
* make Book3s_32 Linux work on Book3s_64, we have to make sure we trap dcbz to
* emulate 32 bytes dcbz length.
@@ -415,8 +488,10 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
int i;
hpage = gfn_to_page(vcpu->kvm, pte->raddr >> PAGE_SHIFT);
- if (is_error_page(hpage))
+ if (is_error_page(hpage)) {
+ kvm_release_page_clean(hpage);
return;
+ }
hpage_offset = pte->raddr & ~PAGE_MASK;
hpage_offset &= ~0xFFFULL;
@@ -437,14 +512,14 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data,
struct kvmppc_pte *pte)
{
- int relocated = (vcpu->arch.msr & (data ? MSR_DR : MSR_IR));
+ int relocated = (vcpu->arch.shared->msr & (data ? MSR_DR : MSR_IR));
int r;
if (relocated) {
r = vcpu->arch.mmu.xlate(vcpu, eaddr, pte, data);
} else {
pte->eaddr = eaddr;
- pte->raddr = eaddr & 0xffffffff;
+ pte->raddr = eaddr & KVM_PAM;
pte->vpage = VSID_REAL | eaddr >> 12;
pte->may_read = true;
pte->may_write = true;
@@ -533,6 +608,13 @@ mmio:
static int kvmppc_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn)
{
+ ulong mp_pa = vcpu->arch.magic_page_pa;
+
+ if (unlikely(mp_pa) &&
+ unlikely((mp_pa & KVM_PAM) >> PAGE_SHIFT == gfn)) {
+ return 1;
+ }
+
return kvm_is_visible_gfn(vcpu->kvm, gfn);
}
@@ -545,8 +627,8 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
int page_found = 0;
struct kvmppc_pte pte;
bool is_mmio = false;
- bool dr = (vcpu->arch.msr & MSR_DR) ? true : false;
- bool ir = (vcpu->arch.msr & MSR_IR) ? true : false;
+ bool dr = (vcpu->arch.shared->msr & MSR_DR) ? true : false;
+ bool ir = (vcpu->arch.shared->msr & MSR_IR) ? true : false;
u64 vsid;
relocated = data ? dr : ir;
@@ -558,12 +640,12 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
pte.may_execute = true;
pte.may_read = true;
pte.may_write = true;
- pte.raddr = eaddr & 0xffffffff;
+ pte.raddr = eaddr & KVM_PAM;
pte.eaddr = eaddr;
pte.vpage = eaddr >> 12;
}
- switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
+ switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
case 0:
pte.vpage |= ((u64)VSID_REAL << (SID_SHIFT - 12));
break;
@@ -571,7 +653,7 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
case MSR_IR:
vcpu->arch.mmu.esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid);
- if ((vcpu->arch.msr & (MSR_DR|MSR_IR)) == MSR_DR)
+ if ((vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) == MSR_DR)
pte.vpage |= ((u64)VSID_REAL_DR << (SID_SHIFT - 12));
else
pte.vpage |= ((u64)VSID_REAL_IR << (SID_SHIFT - 12));
@@ -594,20 +676,23 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
if (page_found == -ENOENT) {
/* Page not found in guest PTE entries */
- vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
- to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr;
- vcpu->arch.msr |= (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
+ vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
+ vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr;
+ vcpu->arch.shared->msr |=
+ (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
kvmppc_book3s_queue_irqprio(vcpu, vec);
} else if (page_found == -EPERM) {
/* Storage protection */
- vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
- to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr & ~DSISR_NOHPTE;
- to_book3s(vcpu)->dsisr |= DSISR_PROTFAULT;
- vcpu->arch.msr |= (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
+ vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
+ vcpu->arch.shared->dsisr =
+ to_svcpu(vcpu)->fault_dsisr & ~DSISR_NOHPTE;
+ vcpu->arch.shared->dsisr |= DSISR_PROTFAULT;
+ vcpu->arch.shared->msr |=
+ (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
kvmppc_book3s_queue_irqprio(vcpu, vec);
} else if (page_found == -EINVAL) {
/* Page not found in guest SLB */
- vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
+ vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
kvmppc_book3s_queue_irqprio(vcpu, vec + 0x80);
} else if (!is_mmio &&
kvmppc_visible_gfn(vcpu, pte.raddr >> PAGE_SHIFT)) {
@@ -695,9 +780,11 @@ static int kvmppc_read_inst(struct kvm_vcpu *vcpu)
ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false);
if (ret == -ENOENT) {
- vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 33, 33, 1);
- vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 34, 36, 0);
- vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 42, 47, 0);
+ ulong msr = vcpu->arch.shared->msr;
+
+ msr = kvmppc_set_field(msr, 33, 33, 1);
+ msr = kvmppc_set_field(msr, 34, 36, 0);
+ vcpu->arch.shared->msr = kvmppc_set_field(msr, 42, 47, 0);
kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_INST_STORAGE);
return EMULATE_AGAIN;
}
@@ -736,7 +823,7 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
if (vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE)
return RESUME_GUEST;
- if (!(vcpu->arch.msr & msr)) {
+ if (!(vcpu->arch.shared->msr & msr)) {
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
return RESUME_GUEST;
}
@@ -796,16 +883,8 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
run->exit_reason = KVM_EXIT_UNKNOWN;
run->ready_for_interrupt_injection = 1;
-#ifdef EXIT_DEBUG
- printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | dec=0x%x | msr=0x%lx\n",
- exit_nr, kvmppc_get_pc(vcpu), kvmppc_get_fault_dar(vcpu),
- kvmppc_get_dec(vcpu), to_svcpu(vcpu)->shadow_srr1);
-#elif defined (EXIT_DEBUG_SIMPLE)
- if ((exit_nr != 0x900) && (exit_nr != 0x500))
- printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | msr=0x%lx\n",
- exit_nr, kvmppc_get_pc(vcpu), kvmppc_get_fault_dar(vcpu),
- vcpu->arch.msr);
-#endif
+
+ trace_kvm_book3s_exit(exit_nr, vcpu);
kvm_resched(vcpu);
switch (exit_nr) {
case BOOK3S_INTERRUPT_INST_STORAGE:
@@ -836,9 +915,9 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL);
r = RESUME_GUEST;
} else {
- vcpu->arch.msr |= to_svcpu(vcpu)->shadow_srr1 & 0x58000000;
+ vcpu->arch.shared->msr |=
+ to_svcpu(vcpu)->shadow_srr1 & 0x58000000;
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
- kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL);
r = RESUME_GUEST;
}
break;
@@ -861,17 +940,16 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
if (to_svcpu(vcpu)->fault_dsisr & DSISR_NOHPTE) {
r = kvmppc_handle_pagefault(run, vcpu, dar, exit_nr);
} else {
- vcpu->arch.dear = dar;
- to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr;
+ vcpu->arch.shared->dar = dar;
+ vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr;
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
- kvmppc_mmu_pte_flush(vcpu, vcpu->arch.dear, ~0xFFFUL);
r = RESUME_GUEST;
}
break;
}
case BOOK3S_INTERRUPT_DATA_SEGMENT:
if (kvmppc_mmu_map_segment(vcpu, kvmppc_get_fault_dar(vcpu)) < 0) {
- vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
+ vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
kvmppc_book3s_queue_irqprio(vcpu,
BOOK3S_INTERRUPT_DATA_SEGMENT);
}
@@ -904,7 +982,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
program_interrupt:
flags = to_svcpu(vcpu)->shadow_srr1 & 0x1f0000ull;
- if (vcpu->arch.msr & MSR_PR) {
+ if (vcpu->arch.shared->msr & MSR_PR) {
#ifdef EXIT_DEBUG
printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu));
#endif
@@ -941,10 +1019,10 @@ program_interrupt:
break;
}
case BOOK3S_INTERRUPT_SYSCALL:
- // XXX make user settable
if (vcpu->arch.osi_enabled &&
(((u32)kvmppc_get_gpr(vcpu, 3)) == OSI_SC_MAGIC_R3) &&
(((u32)kvmppc_get_gpr(vcpu, 4)) == OSI_SC_MAGIC_R4)) {
+ /* MOL hypercalls */
u64 *gprs = run->osi.gprs;
int i;
@@ -953,8 +1031,13 @@ program_interrupt:
gprs[i] = kvmppc_get_gpr(vcpu, i);
vcpu->arch.osi_needed = 1;
r = RESUME_HOST_NV;
-
+ } else if (!(vcpu->arch.shared->msr & MSR_PR) &&
+ (((u32)kvmppc_get_gpr(vcpu, 0)) == KVM_SC_MAGIC_R0)) {
+ /* KVM PV hypercalls */
+ kvmppc_set_gpr(vcpu, 3, kvmppc_kvm_pv(vcpu));
+ r = RESUME_GUEST;
} else {
+ /* Guest syscalls */
vcpu->stat.syscall_exits++;
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
r = RESUME_GUEST;
@@ -989,9 +1072,9 @@ program_interrupt:
}
case BOOK3S_INTERRUPT_ALIGNMENT:
if (kvmppc_read_inst(vcpu) == EMULATE_DONE) {
- to_book3s(vcpu)->dsisr = kvmppc_alignment_dsisr(vcpu,
+ vcpu->arch.shared->dsisr = kvmppc_alignment_dsisr(vcpu,
kvmppc_get_last_inst(vcpu));
- vcpu->arch.dear = kvmppc_alignment_dar(vcpu,
+ vcpu->arch.shared->dar = kvmppc_alignment_dar(vcpu,
kvmppc_get_last_inst(vcpu));
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
}
@@ -1031,9 +1114,7 @@ program_interrupt:
}
}
-#ifdef EXIT_DEBUG
- printk(KERN_EMERG "KVM exit: vcpu=0x%p pc=0x%lx r=0x%x\n", vcpu, kvmppc_get_pc(vcpu), r);
-#endif
+ trace_kvm_book3s_reenter(r, vcpu);
return r;
}
@@ -1052,14 +1133,14 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
regs->ctr = kvmppc_get_ctr(vcpu);
regs->lr = kvmppc_get_lr(vcpu);
regs->xer = kvmppc_get_xer(vcpu);
- regs->msr = vcpu->arch.msr;
- regs->srr0 = vcpu->arch.srr0;
- regs->srr1 = vcpu->arch.srr1;
+ regs->msr = vcpu->arch.shared->msr;
+ regs->srr0 = vcpu->arch.shared->srr0;
+ regs->srr1 = vcpu->arch.shared->srr1;
regs->pid = vcpu->arch.pid;
- regs->sprg0 = vcpu->arch.sprg0;
- regs->sprg1 = vcpu->arch.sprg1;
- regs->sprg2 = vcpu->arch.sprg2;
- regs->sprg3 = vcpu->arch.sprg3;
+ regs->sprg0 = vcpu->arch.shared->sprg0;
+ regs->sprg1 = vcpu->arch.shared->sprg1;
+ regs->sprg2 = vcpu->arch.shared->sprg2;
+ regs->sprg3 = vcpu->arch.shared->sprg3;
regs->sprg5 = vcpu->arch.sprg4;
regs->sprg6 = vcpu->arch.sprg5;
regs->sprg7 = vcpu->arch.sprg6;
@@ -1080,12 +1161,12 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
kvmppc_set_lr(vcpu, regs->lr);
kvmppc_set_xer(vcpu, regs->xer);
kvmppc_set_msr(vcpu, regs->msr);
- vcpu->arch.srr0 = regs->srr0;
- vcpu->arch.srr1 = regs->srr1;
- vcpu->arch.sprg0 = regs->sprg0;
- vcpu->arch.sprg1 = regs->sprg1;
- vcpu->arch.sprg2 = regs->sprg2;
- vcpu->arch.sprg3 = regs->sprg3;
+ vcpu->arch.shared->srr0 = regs->srr0;
+ vcpu->arch.shared->srr1 = regs->srr1;
+ vcpu->arch.shared->sprg0 = regs->sprg0;
+ vcpu->arch.shared->sprg1 = regs->sprg1;
+ vcpu->arch.shared->sprg2 = regs->sprg2;
+ vcpu->arch.shared->sprg3 = regs->sprg3;
vcpu->arch.sprg5 = regs->sprg4;
vcpu->arch.sprg6 = regs->sprg5;
vcpu->arch.sprg7 = regs->sprg6;
@@ -1111,10 +1192,9 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
sregs->u.s.ppc64.slb[i].slbv = vcpu3s->slb[i].origv;
}
} else {
- for (i = 0; i < 16; i++) {
- sregs->u.s.ppc32.sr[i] = vcpu3s->sr[i].raw;
- sregs->u.s.ppc32.sr[i] = vcpu3s->sr[i].raw;
- }
+ for (i = 0; i < 16; i++)
+ sregs->u.s.ppc32.sr[i] = vcpu->arch.shared->sr[i];
+
for (i = 0; i < 8; i++) {
sregs->u.s.ppc32.ibat[i] = vcpu3s->ibat[i].raw;
sregs->u.s.ppc32.dbat[i] = vcpu3s->dbat[i].raw;
@@ -1225,6 +1305,7 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
struct kvmppc_vcpu_book3s *vcpu_book3s;
struct kvm_vcpu *vcpu;
int err = -ENOMEM;
+ unsigned long p;
vcpu_book3s = vmalloc(sizeof(struct kvmppc_vcpu_book3s));
if (!vcpu_book3s)
@@ -1242,6 +1323,12 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
if (err)
goto free_shadow_vcpu;
+ p = __get_free_page(GFP_KERNEL|__GFP_ZERO);
+ /* the real shared page fills the last 4k of our page */
+ vcpu->arch.shared = (void*)(p + PAGE_SIZE - 4096);
+ if (!p)
+ goto uninit_vcpu;
+
vcpu->arch.host_retip = kvm_return_point;
vcpu->arch.host_msr = mfmsr();
#ifdef CONFIG_PPC_BOOK3S_64
@@ -1268,10 +1355,12 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
err = kvmppc_mmu_init(vcpu);
if (err < 0)
- goto free_shadow_vcpu;
+ goto uninit_vcpu;
return vcpu;
+uninit_vcpu:
+ kvm_vcpu_uninit(vcpu);
free_shadow_vcpu:
kfree(vcpu_book3s->shadow_vcpu);
free_vcpu:
@@ -1284,6 +1373,7 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
{
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
+ free_page((unsigned long)vcpu->arch.shared & PAGE_MASK);
kvm_vcpu_uninit(vcpu);
kfree(vcpu_book3s->shadow_vcpu);
vfree(vcpu_book3s);
@@ -1346,7 +1436,7 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
local_irq_enable();
/* Preload FPU if it's enabled */
- if (vcpu->arch.msr & MSR_FP)
+ if (vcpu->arch.shared->msr & MSR_FP)
kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
ret = __kvmppc_vcpu_entry(kvm_run, vcpu);
diff --git a/arch/powerpc/kvm/book3s_32_mmu.c b/arch/powerpc/kvm/book3s_32_mmu.c
index 3292d76101d2..c8cefdd15fd8 100644
--- a/arch/powerpc/kvm/book3s_32_mmu.c
+++ b/arch/powerpc/kvm/book3s_32_mmu.c
@@ -58,14 +58,39 @@ static inline bool check_debug_ip(struct kvm_vcpu *vcpu)
#endif
}
+static inline u32 sr_vsid(u32 sr_raw)
+{
+ return sr_raw & 0x0fffffff;
+}
+
+static inline bool sr_valid(u32 sr_raw)
+{
+ return (sr_raw & 0x80000000) ? false : true;
+}
+
+static inline bool sr_ks(u32 sr_raw)
+{
+ return (sr_raw & 0x40000000) ? true: false;
+}
+
+static inline bool sr_kp(u32 sr_raw)
+{
+ return (sr_raw & 0x20000000) ? true: false;
+}
+
+static inline bool sr_nx(u32 sr_raw)
+{
+ return (sr_raw & 0x10000000) ? true: false;
+}
+
static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr,
struct kvmppc_pte *pte, bool data);
static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
u64 *vsid);
-static struct kvmppc_sr *find_sr(struct kvmppc_vcpu_book3s *vcpu_book3s, gva_t eaddr)
+static u32 find_sr(struct kvm_vcpu *vcpu, gva_t eaddr)
{
- return &vcpu_book3s->sr[(eaddr >> 28) & 0xf];
+ return vcpu->arch.shared->sr[(eaddr >> 28) & 0xf];
}
static u64 kvmppc_mmu_book3s_32_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr,
@@ -87,7 +112,7 @@ static void kvmppc_mmu_book3s_32_reset_msr(struct kvm_vcpu *vcpu)
}
static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3s,
- struct kvmppc_sr *sre, gva_t eaddr,
+ u32 sre, gva_t eaddr,
bool primary)
{
u32 page, hash, pteg, htabmask;
@@ -96,7 +121,7 @@ static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3
page = (eaddr & 0x0FFFFFFF) >> 12;
htabmask = ((vcpu_book3s->sdr1 & 0x1FF) << 16) | 0xFFC0;
- hash = ((sre->vsid ^ page) << 6);
+ hash = ((sr_vsid(sre) ^ page) << 6);
if (!primary)
hash = ~hash;
hash &= htabmask;
@@ -104,8 +129,8 @@ static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3
pteg = (vcpu_book3s->sdr1 & 0xffff0000) | hash;
dprintk("MMU: pc=0x%lx eaddr=0x%lx sdr1=0x%llx pteg=0x%x vsid=0x%x\n",
- vcpu_book3s->vcpu.arch.pc, eaddr, vcpu_book3s->sdr1, pteg,
- sre->vsid);
+ kvmppc_get_pc(&vcpu_book3s->vcpu), eaddr, vcpu_book3s->sdr1, pteg,
+ sr_vsid(sre));
r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT);
if (kvm_is_error_hva(r))
@@ -113,10 +138,9 @@ static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3
return r | (pteg & ~PAGE_MASK);
}
-static u32 kvmppc_mmu_book3s_32_get_ptem(struct kvmppc_sr *sre, gva_t eaddr,
- bool primary)
+static u32 kvmppc_mmu_book3s_32_get_ptem(u32 sre, gva_t eaddr, bool primary)
{
- return ((eaddr & 0x0fffffff) >> 22) | (sre->vsid << 7) |
+ return ((eaddr & 0x0fffffff) >> 22) | (sr_vsid(sre) << 7) |
(primary ? 0 : 0x40) | 0x80000000;
}
@@ -133,7 +157,7 @@ static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr,
else
bat = &vcpu_book3s->ibat[i];
- if (vcpu->arch.msr & MSR_PR) {
+ if (vcpu->arch.shared->msr & MSR_PR) {
if (!bat->vp)
continue;
} else {
@@ -180,17 +204,17 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr,
bool primary)
{
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
- struct kvmppc_sr *sre;
+ u32 sre;
hva_t ptegp;
u32 pteg[16];
u32 ptem = 0;
int i;
int found = 0;
- sre = find_sr(vcpu_book3s, eaddr);
+ sre = find_sr(vcpu, eaddr);
dprintk_pte("SR 0x%lx: vsid=0x%x, raw=0x%x\n", eaddr >> 28,
- sre->vsid, sre->raw);
+ sr_vsid(sre), sre);
pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data);
@@ -214,8 +238,8 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr,
pte->raddr = (pteg[i+1] & ~(0xFFFULL)) | (eaddr & 0xFFF);
pp = pteg[i+1] & 3;
- if ((sre->Kp && (vcpu->arch.msr & MSR_PR)) ||
- (sre->Ks && !(vcpu->arch.msr & MSR_PR)))
+ if ((sr_kp(sre) && (vcpu->arch.shared->msr & MSR_PR)) ||
+ (sr_ks(sre) && !(vcpu->arch.shared->msr & MSR_PR)))
pp |= 4;
pte->may_write = false;
@@ -269,7 +293,7 @@ no_page_found:
dprintk_pte("KVM MMU: No PTE found (sdr1=0x%llx ptegp=0x%lx)\n",
to_book3s(vcpu)->sdr1, ptegp);
for (i=0; i<16; i+=2) {
- dprintk_pte(" %02d: 0x%x - 0x%x (0x%llx)\n",
+ dprintk_pte(" %02d: 0x%x - 0x%x (0x%x)\n",
i, pteg[i], pteg[i+1], ptem);
}
}
@@ -281,8 +305,24 @@ static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
struct kvmppc_pte *pte, bool data)
{
int r;
+ ulong mp_ea = vcpu->arch.magic_page_ea;
pte->eaddr = eaddr;
+
+ /* Magic page override */
+ if (unlikely(mp_ea) &&
+ unlikely((eaddr & ~0xfffULL) == (mp_ea & ~0xfffULL)) &&
+ !(vcpu->arch.shared->msr & MSR_PR)) {
+ pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data);
+ pte->raddr = vcpu->arch.magic_page_pa | (pte->raddr & 0xfff);
+ pte->raddr &= KVM_PAM;
+ pte->may_execute = true;
+ pte->may_read = true;
+ pte->may_write = true;
+
+ return 0;
+ }
+
r = kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, pte, data);
if (r < 0)
r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte, data, true);
@@ -295,30 +335,13 @@ static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
static u32 kvmppc_mmu_book3s_32_mfsrin(struct kvm_vcpu *vcpu, u32 srnum)
{
- return to_book3s(vcpu)->sr[srnum].raw;
+ return vcpu->arch.shared->sr[srnum];
}
static void kvmppc_mmu_book3s_32_mtsrin(struct kvm_vcpu *vcpu, u32 srnum,
ulong value)
{
- struct kvmppc_sr *sre;
-
- sre = &to_book3s(vcpu)->sr[srnum];
-
- /* Flush any left-over shadows from the previous SR */
-
- /* XXX Not necessary? */
- /* kvmppc_mmu_pte_flush(vcpu, ((u64)sre->vsid) << 28, 0xf0000000ULL); */
-
- /* And then put in the new SR */
- sre->raw = value;
- sre->vsid = (value & 0x0fffffff);
- sre->valid = (value & 0x80000000) ? false : true;
- sre->Ks = (value & 0x40000000) ? true : false;
- sre->Kp = (value & 0x20000000) ? true : false;
- sre->nx = (value & 0x10000000) ? true : false;
-
- /* Map the new segment */
+ vcpu->arch.shared->sr[srnum] = value;
kvmppc_mmu_map_segment(vcpu, srnum << SID_SHIFT);
}
@@ -331,19 +354,19 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
u64 *vsid)
{
ulong ea = esid << SID_SHIFT;
- struct kvmppc_sr *sr;
+ u32 sr;
u64 gvsid = esid;
- if (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
- sr = find_sr(to_book3s(vcpu), ea);
- if (sr->valid)
- gvsid = sr->vsid;
+ if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
+ sr = find_sr(vcpu, ea);
+ if (sr_valid(sr))
+ gvsid = sr_vsid(sr);
}
/* In case we only have one of MSR_IR or MSR_DR set, let's put
that in the real-mode context (and hope RM doesn't access
high memory) */
- switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
+ switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
case 0:
*vsid = VSID_REAL | esid;
break;
@@ -354,8 +377,8 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
*vsid = VSID_REAL_DR | gvsid;
break;
case MSR_DR|MSR_IR:
- if (sr->valid)
- *vsid = sr->vsid;
+ if (sr_valid(sr))
+ *vsid = sr_vsid(sr);
else
*vsid = VSID_BAT | gvsid;
break;
@@ -363,7 +386,7 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
BUG();
}
- if (vcpu->arch.msr & MSR_PR)
+ if (vcpu->arch.shared->msr & MSR_PR)
*vsid |= VSID_PR;
return 0;
diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c
index 0b51ef872c1e..9fecbfbce773 100644
--- a/arch/powerpc/kvm/book3s_32_mmu_host.c
+++ b/arch/powerpc/kvm/book3s_32_mmu_host.c
@@ -19,7 +19,6 @@
*/
#include <linux/kvm_host.h>
-#include <linux/hash.h>
#include <asm/kvm_ppc.h>
#include <asm/kvm_book3s.h>
@@ -77,7 +76,14 @@ void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
* a hash, so we don't waste cycles on looping */
static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid)
{
- return hash_64(gvsid, SID_MAP_BITS);
+ return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^
+ ((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^
+ ((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^
+ ((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^
+ ((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^
+ ((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^
+ ((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^
+ ((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK));
}
@@ -86,7 +92,7 @@ static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid)
struct kvmppc_sid_map *map;
u16 sid_map_mask;
- if (vcpu->arch.msr & MSR_PR)
+ if (vcpu->arch.shared->msr & MSR_PR)
gvsid |= VSID_PR;
sid_map_mask = kvmppc_sid_hash(vcpu, gvsid);
@@ -147,8 +153,8 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
struct hpte_cache *pte;
/* Get host physical address for gpa */
- hpaddr = gfn_to_pfn(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT);
- if (kvm_is_error_hva(hpaddr)) {
+ hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT);
+ if (is_error_pfn(hpaddr)) {
printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n",
orig_pte->eaddr);
return -EINVAL;
@@ -253,7 +259,7 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
u16 sid_map_mask;
static int backwards_map = 0;
- if (vcpu->arch.msr & MSR_PR)
+ if (vcpu->arch.shared->msr & MSR_PR)
gvsid |= VSID_PR;
/* We might get collisions that trap in preceding order, so let's
@@ -269,18 +275,15 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
backwards_map = !backwards_map;
/* Uh-oh ... out of mappings. Let's flush! */
- if (vcpu_book3s->vsid_next >= vcpu_book3s->vsid_max) {
- vcpu_book3s->vsid_next = vcpu_book3s->vsid_first;
+ if (vcpu_book3s->vsid_next >= VSID_POOL_SIZE) {
+ vcpu_book3s->vsid_next = 0;
memset(vcpu_book3s->sid_map, 0,
sizeof(struct kvmppc_sid_map) * SID_MAP_NUM);
kvmppc_mmu_pte_flush(vcpu, 0, 0);
kvmppc_mmu_flush_segments(vcpu);
}
- map->host_vsid = vcpu_book3s->vsid_next;
-
- /* Would have to be 111 to be completely aligned with the rest of
- Linux, but that is just way too little space! */
- vcpu_book3s->vsid_next+=1;
+ map->host_vsid = vcpu_book3s->vsid_pool[vcpu_book3s->vsid_next];
+ vcpu_book3s->vsid_next++;
map->guest_vsid = gvsid;
map->valid = true;
@@ -327,40 +330,38 @@ void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
{
+ int i;
+
kvmppc_mmu_hpte_destroy(vcpu);
preempt_disable();
- __destroy_context(to_book3s(vcpu)->context_id);
+ for (i = 0; i < SID_CONTEXTS; i++)
+ __destroy_context(to_book3s(vcpu)->context_id[i]);
preempt_enable();
}
/* From mm/mmu_context_hash32.c */
-#define CTX_TO_VSID(ctx) (((ctx) * (897 * 16)) & 0xffffff)
+#define CTX_TO_VSID(c, id) ((((c) * (897 * 16)) + (id * 0x111)) & 0xffffff)
int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
{
struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
int err;
ulong sdr1;
+ int i;
+ int j;
- err = __init_new_context();
- if (err < 0)
- return -1;
- vcpu3s->context_id = err;
-
- vcpu3s->vsid_max = CTX_TO_VSID(vcpu3s->context_id + 1) - 1;
- vcpu3s->vsid_first = CTX_TO_VSID(vcpu3s->context_id);
-
-#if 0 /* XXX still doesn't guarantee uniqueness */
- /* We could collide with the Linux vsid space because the vsid
- * wraps around at 24 bits. We're safe if we do our own space
- * though, so let's always set the highest bit. */
+ for (i = 0; i < SID_CONTEXTS; i++) {
+ err = __init_new_context();
+ if (err < 0)
+ goto init_fail;
+ vcpu3s->context_id[i] = err;
- vcpu3s->vsid_max |= 0x00800000;
- vcpu3s->vsid_first |= 0x00800000;
-#endif
- BUG_ON(vcpu3s->vsid_max < vcpu3s->vsid_first);
+ /* Remember context id for this combination */
+ for (j = 0; j < 16; j++)
+ vcpu3s->vsid_pool[(i * 16) + j] = CTX_TO_VSID(err, j);
+ }
- vcpu3s->vsid_next = vcpu3s->vsid_first;
+ vcpu3s->vsid_next = 0;
/* Remember where the HTAB is */
asm ( "mfsdr1 %0" : "=r"(sdr1) );
@@ -370,4 +371,14 @@ int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
kvmppc_mmu_hpte_init(vcpu);
return 0;
+
+init_fail:
+ for (j = 0; j < i; j++) {
+ if (!vcpu3s->context_id[j])
+ continue;
+
+ __destroy_context(to_book3s(vcpu)->context_id[j]);
+ }
+
+ return -1;
}
diff --git a/arch/powerpc/kvm/book3s_64_mmu.c b/arch/powerpc/kvm/book3s_64_mmu.c
index 4025ea26b3c1..d7889ef3211e 100644
--- a/arch/powerpc/kvm/book3s_64_mmu.c
+++ b/arch/powerpc/kvm/book3s_64_mmu.c
@@ -163,6 +163,22 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
bool found = false;
bool perm_err = false;
int second = 0;
+ ulong mp_ea = vcpu->arch.magic_page_ea;
+
+ /* Magic page override */
+ if (unlikely(mp_ea) &&
+ unlikely((eaddr & ~0xfffULL) == (mp_ea & ~0xfffULL)) &&
+ !(vcpu->arch.shared->msr & MSR_PR)) {
+ gpte->eaddr = eaddr;
+ gpte->vpage = kvmppc_mmu_book3s_64_ea_to_vp(vcpu, eaddr, data);
+ gpte->raddr = vcpu->arch.magic_page_pa | (gpte->raddr & 0xfff);
+ gpte->raddr &= KVM_PAM;
+ gpte->may_execute = true;
+ gpte->may_read = true;
+ gpte->may_write = true;
+
+ return 0;
+ }
slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu_book3s, eaddr);
if (!slbe)
@@ -180,9 +196,9 @@ do_second:
goto no_page_found;
}
- if ((vcpu->arch.msr & MSR_PR) && slbe->Kp)
+ if ((vcpu->arch.shared->msr & MSR_PR) && slbe->Kp)
key = 4;
- else if (!(vcpu->arch.msr & MSR_PR) && slbe->Ks)
+ else if (!(vcpu->arch.shared->msr & MSR_PR) && slbe->Ks)
key = 4;
for (i=0; i<16; i+=2) {
@@ -381,7 +397,7 @@ static void kvmppc_mmu_book3s_64_slbia(struct kvm_vcpu *vcpu)
for (i = 1; i < vcpu_book3s->slb_nr; i++)
vcpu_book3s->slb[i].valid = false;
- if (vcpu->arch.msr & MSR_IR) {
+ if (vcpu->arch.shared->msr & MSR_IR) {
kvmppc_mmu_flush_segments(vcpu);
kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
}
@@ -445,14 +461,15 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
ulong ea = esid << SID_SHIFT;
struct kvmppc_slb *slb;
u64 gvsid = esid;
+ ulong mp_ea = vcpu->arch.magic_page_ea;
- if (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
+ if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), ea);
if (slb)
gvsid = slb->vsid;
}
- switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
+ switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
case 0:
*vsid = VSID_REAL | esid;
break;
@@ -464,7 +481,7 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
break;
case MSR_DR|MSR_IR:
if (!slb)
- return -ENOENT;
+ goto no_slb;
*vsid = gvsid;
break;
@@ -473,10 +490,21 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
break;
}
- if (vcpu->arch.msr & MSR_PR)
+ if (vcpu->arch.shared->msr & MSR_PR)
*vsid |= VSID_PR;
return 0;
+
+no_slb:
+ /* Catch magic page case */
+ if (unlikely(mp_ea) &&
+ unlikely(esid == (mp_ea >> SID_SHIFT)) &&
+ !(vcpu->arch.shared->msr & MSR_PR)) {
+ *vsid = VSID_REAL | esid;
+ return 0;
+ }
+
+ return -EINVAL;
}
static bool kvmppc_mmu_book3s_64_is_dcbz32(struct kvm_vcpu *vcpu)
diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c
index 384179a5002b..fa2f08434ba5 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_host.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_host.c
@@ -20,7 +20,6 @@
*/
#include <linux/kvm_host.h>
-#include <linux/hash.h>
#include <asm/kvm_ppc.h>
#include <asm/kvm_book3s.h>
@@ -28,24 +27,9 @@
#include <asm/machdep.h>
#include <asm/mmu_context.h>
#include <asm/hw_irq.h>
+#include "trace.h"
#define PTE_SIZE 12
-#define VSID_ALL 0
-
-/* #define DEBUG_MMU */
-/* #define DEBUG_SLB */
-
-#ifdef DEBUG_MMU
-#define dprintk_mmu(a, ...) printk(KERN_INFO a, __VA_ARGS__)
-#else
-#define dprintk_mmu(a, ...) do { } while(0)
-#endif
-
-#ifdef DEBUG_SLB
-#define dprintk_slb(a, ...) printk(KERN_INFO a, __VA_ARGS__)
-#else
-#define dprintk_slb(a, ...) do { } while(0)
-#endif
void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
{
@@ -58,34 +42,39 @@ void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
* a hash, so we don't waste cycles on looping */
static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid)
{
- return hash_64(gvsid, SID_MAP_BITS);
+ return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^
+ ((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^
+ ((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^
+ ((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^
+ ((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^
+ ((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^
+ ((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^
+ ((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK));
}
+
static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid)
{
struct kvmppc_sid_map *map;
u16 sid_map_mask;
- if (vcpu->arch.msr & MSR_PR)
+ if (vcpu->arch.shared->msr & MSR_PR)
gvsid |= VSID_PR;
sid_map_mask = kvmppc_sid_hash(vcpu, gvsid);
map = &to_book3s(vcpu)->sid_map[sid_map_mask];
- if (map->guest_vsid == gvsid) {
- dprintk_slb("SLB: Searching: 0x%llx -> 0x%llx\n",
- gvsid, map->host_vsid);
+ if (map->valid && (map->guest_vsid == gvsid)) {
+ trace_kvm_book3s_slb_found(gvsid, map->host_vsid);
return map;
}
map = &to_book3s(vcpu)->sid_map[SID_MAP_MASK - sid_map_mask];
- if (map->guest_vsid == gvsid) {
- dprintk_slb("SLB: Searching 0x%llx -> 0x%llx\n",
- gvsid, map->host_vsid);
+ if (map->valid && (map->guest_vsid == gvsid)) {
+ trace_kvm_book3s_slb_found(gvsid, map->host_vsid);
return map;
}
- dprintk_slb("SLB: Searching %d/%d: 0x%llx -> not found\n",
- sid_map_mask, SID_MAP_MASK - sid_map_mask, gvsid);
+ trace_kvm_book3s_slb_fail(sid_map_mask, gvsid);
return NULL;
}
@@ -101,18 +90,13 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
struct kvmppc_sid_map *map;
/* Get host physical address for gpa */
- hpaddr = gfn_to_pfn(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT);
- if (kvm_is_error_hva(hpaddr)) {
+ hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT);
+ if (is_error_pfn(hpaddr)) {
printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n", orig_pte->eaddr);
return -EINVAL;
}
hpaddr <<= PAGE_SHIFT;
-#if PAGE_SHIFT == 12
-#elif PAGE_SHIFT == 16
- hpaddr |= orig_pte->raddr & 0xf000;
-#else
-#error Unknown page size
-#endif
+ hpaddr |= orig_pte->raddr & (~0xfffULL & ~PAGE_MASK);
/* and write the mapping ea -> hpa into the pt */
vcpu->arch.mmu.esid_to_vsid(vcpu, orig_pte->eaddr >> SID_SHIFT, &vsid);
@@ -161,10 +145,7 @@ map_again:
} else {
struct hpte_cache *pte = kvmppc_mmu_hpte_cache_next(vcpu);
- dprintk_mmu("KVM: %c%c Map 0x%lx: [%lx] 0x%lx (0x%llx) -> %lx\n",
- ((rflags & HPTE_R_PP) == 3) ? '-' : 'w',
- (rflags & HPTE_R_N) ? '-' : 'x',
- orig_pte->eaddr, hpteg, va, orig_pte->vpage, hpaddr);
+ trace_kvm_book3s_64_mmu_map(rflags, hpteg, va, hpaddr, orig_pte);
/* The ppc_md code may give us a secondary entry even though we
asked for a primary. Fix up. */
@@ -191,7 +172,7 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
u16 sid_map_mask;
static int backwards_map = 0;
- if (vcpu->arch.msr & MSR_PR)
+ if (vcpu->arch.shared->msr & MSR_PR)
gvsid |= VSID_PR;
/* We might get collisions that trap in preceding order, so let's
@@ -219,8 +200,7 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
map->guest_vsid = gvsid;
map->valid = true;
- dprintk_slb("SLB: New mapping at %d: 0x%llx -> 0x%llx\n",
- sid_map_mask, gvsid, map->host_vsid);
+ trace_kvm_book3s_slb_map(sid_map_mask, gvsid, map->host_vsid);
return map;
}
@@ -292,7 +272,7 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr)
to_svcpu(vcpu)->slb[slb_index].esid = slb_esid;
to_svcpu(vcpu)->slb[slb_index].vsid = slb_vsid;
- dprintk_slb("slbmte %#llx, %#llx\n", slb_vsid, slb_esid);
+ trace_kvm_book3s_slbmte(slb_vsid, slb_esid);
return 0;
}
@@ -306,7 +286,7 @@ void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
{
kvmppc_mmu_hpte_destroy(vcpu);
- __destroy_context(to_book3s(vcpu)->context_id);
+ __destroy_context(to_book3s(vcpu)->context_id[0]);
}
int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
@@ -317,10 +297,10 @@ int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
err = __init_new_context();
if (err < 0)
return -1;
- vcpu3s->context_id = err;
+ vcpu3s->context_id[0] = err;
- vcpu3s->vsid_max = ((vcpu3s->context_id + 1) << USER_ESID_BITS) - 1;
- vcpu3s->vsid_first = vcpu3s->context_id << USER_ESID_BITS;
+ vcpu3s->vsid_max = ((vcpu3s->context_id[0] + 1) << USER_ESID_BITS) - 1;
+ vcpu3s->vsid_first = vcpu3s->context_id[0] << USER_ESID_BITS;
vcpu3s->vsid_next = vcpu3s->vsid_first;
kvmppc_mmu_hpte_init(vcpu);
diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c
index c85f906038ce..466846557089 100644
--- a/arch/powerpc/kvm/book3s_emulate.c
+++ b/arch/powerpc/kvm/book3s_emulate.c
@@ -73,8 +73,8 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
switch (get_xop(inst)) {
case OP_19_XOP_RFID:
case OP_19_XOP_RFI:
- kvmppc_set_pc(vcpu, vcpu->arch.srr0);
- kvmppc_set_msr(vcpu, vcpu->arch.srr1);
+ kvmppc_set_pc(vcpu, vcpu->arch.shared->srr0);
+ kvmppc_set_msr(vcpu, vcpu->arch.shared->srr1);
*advance = 0;
break;
@@ -86,14 +86,15 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
case 31:
switch (get_xop(inst)) {
case OP_31_XOP_MFMSR:
- kvmppc_set_gpr(vcpu, get_rt(inst), vcpu->arch.msr);
+ kvmppc_set_gpr(vcpu, get_rt(inst),
+ vcpu->arch.shared->msr);
break;
case OP_31_XOP_MTMSRD:
{
ulong rs = kvmppc_get_gpr(vcpu, get_rs(inst));
if (inst & 0x10000) {
- vcpu->arch.msr &= ~(MSR_RI | MSR_EE);
- vcpu->arch.msr |= rs & (MSR_RI | MSR_EE);
+ vcpu->arch.shared->msr &= ~(MSR_RI | MSR_EE);
+ vcpu->arch.shared->msr |= rs & (MSR_RI | MSR_EE);
} else
kvmppc_set_msr(vcpu, rs);
break;
@@ -204,14 +205,14 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
ra = kvmppc_get_gpr(vcpu, get_ra(inst));
addr = (ra + rb) & ~31ULL;
- if (!(vcpu->arch.msr & MSR_SF))
+ if (!(vcpu->arch.shared->msr & MSR_SF))
addr &= 0xffffffff;
vaddr = addr;
r = kvmppc_st(vcpu, &addr, 32, zeros, true);
if ((r == -ENOENT) || (r == -EPERM)) {
*advance = 0;
- vcpu->arch.dear = vaddr;
+ vcpu->arch.shared->dar = vaddr;
to_svcpu(vcpu)->fault_dar = vaddr;
dsisr = DSISR_ISSTORE;
@@ -220,7 +221,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
else if (r == -EPERM)
dsisr |= DSISR_PROTFAULT;
- to_book3s(vcpu)->dsisr = dsisr;
+ vcpu->arch.shared->dsisr = dsisr;
to_svcpu(vcpu)->fault_dsisr = dsisr;
kvmppc_book3s_queue_irqprio(vcpu,
@@ -263,7 +264,7 @@ void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, bool upper,
}
}
-static u32 kvmppc_read_bat(struct kvm_vcpu *vcpu, int sprn)
+static struct kvmppc_bat *kvmppc_find_bat(struct kvm_vcpu *vcpu, int sprn)
{
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
struct kvmppc_bat *bat;
@@ -285,35 +286,7 @@ static u32 kvmppc_read_bat(struct kvm_vcpu *vcpu, int sprn)
BUG();
}
- if (sprn % 2)
- return bat->raw >> 32;
- else
- return bat->raw;
-}
-
-static void kvmppc_write_bat(struct kvm_vcpu *vcpu, int sprn, u32 val)
-{
- struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
- struct kvmppc_bat *bat;
-
- switch (sprn) {
- case SPRN_IBAT0U ... SPRN_IBAT3L:
- bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT0U) / 2];
- break;
- case SPRN_IBAT4U ... SPRN_IBAT7L:
- bat = &vcpu_book3s->ibat[4 + ((sprn - SPRN_IBAT4U) / 2)];
- break;
- case SPRN_DBAT0U ... SPRN_DBAT3L:
- bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT0U) / 2];
- break;
- case SPRN_DBAT4U ... SPRN_DBAT7L:
- bat = &vcpu_book3s->dbat[4 + ((sprn - SPRN_DBAT4U) / 2)];
- break;
- default:
- BUG();
- }
-
- kvmppc_set_bat(vcpu, bat, !(sprn % 2), val);
+ return bat;
}
int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
@@ -326,10 +299,10 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
to_book3s(vcpu)->sdr1 = spr_val;
break;
case SPRN_DSISR:
- to_book3s(vcpu)->dsisr = spr_val;
+ vcpu->arch.shared->dsisr = spr_val;
break;
case SPRN_DAR:
- vcpu->arch.dear = spr_val;
+ vcpu->arch.shared->dar = spr_val;
break;
case SPRN_HIOR:
to_book3s(vcpu)->hior = spr_val;
@@ -338,12 +311,16 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
case SPRN_IBAT4U ... SPRN_IBAT7L:
case SPRN_DBAT0U ... SPRN_DBAT3L:
case SPRN_DBAT4U ... SPRN_DBAT7L:
- kvmppc_write_bat(vcpu, sprn, (u32)spr_val);
+ {
+ struct kvmppc_bat *bat = kvmppc_find_bat(vcpu, sprn);
+
+ kvmppc_set_bat(vcpu, bat, !(sprn % 2), (u32)spr_val);
/* BAT writes happen so rarely that we're ok to flush
* everything here */
kvmppc_mmu_pte_flush(vcpu, 0, 0);
kvmppc_mmu_flush_segments(vcpu);
break;
+ }
case SPRN_HID0:
to_book3s(vcpu)->hid[0] = spr_val;
break;
@@ -433,16 +410,24 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
case SPRN_IBAT4U ... SPRN_IBAT7L:
case SPRN_DBAT0U ... SPRN_DBAT3L:
case SPRN_DBAT4U ... SPRN_DBAT7L:
- kvmppc_set_gpr(vcpu, rt, kvmppc_read_bat(vcpu, sprn));
+ {
+ struct kvmppc_bat *bat = kvmppc_find_bat(vcpu, sprn);
+
+ if (sprn % 2)
+ kvmppc_set_gpr(vcpu, rt, bat->raw >> 32);
+ else
+ kvmppc_set_gpr(vcpu, rt, bat->raw);
+
break;
+ }
case SPRN_SDR1:
kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->sdr1);
break;
case SPRN_DSISR:
- kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->dsisr);
+ kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->dsisr);
break;
case SPRN_DAR:
- kvmppc_set_gpr(vcpu, rt, vcpu->arch.dear);
+ kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->dar);
break;
case SPRN_HIOR:
kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hior);
diff --git a/arch/powerpc/kvm/book3s_mmu_hpte.c b/arch/powerpc/kvm/book3s_mmu_hpte.c
index 4868d4a7ebc5..79751d8dd131 100644
--- a/arch/powerpc/kvm/book3s_mmu_hpte.c
+++ b/arch/powerpc/kvm/book3s_mmu_hpte.c
@@ -21,6 +21,7 @@
#include <linux/kvm_host.h>
#include <linux/hash.h>
#include <linux/slab.h>
+#include "trace.h"
#include <asm/kvm_ppc.h>
#include <asm/kvm_book3s.h>
@@ -30,14 +31,6 @@
#define PTE_SIZE 12
-/* #define DEBUG_MMU */
-
-#ifdef DEBUG_MMU
-#define dprintk_mmu(a, ...) printk(KERN_INFO a, __VA_ARGS__)
-#else
-#define dprintk_mmu(a, ...) do { } while(0)
-#endif
-
static struct kmem_cache *hpte_cache;
static inline u64 kvmppc_mmu_hash_pte(u64 eaddr)
@@ -45,6 +38,12 @@ static inline u64 kvmppc_mmu_hash_pte(u64 eaddr)
return hash_64(eaddr >> PTE_SIZE, HPTEG_HASH_BITS_PTE);
}
+static inline u64 kvmppc_mmu_hash_pte_long(u64 eaddr)
+{
+ return hash_64((eaddr & 0x0ffff000) >> PTE_SIZE,
+ HPTEG_HASH_BITS_PTE_LONG);
+}
+
static inline u64 kvmppc_mmu_hash_vpte(u64 vpage)
{
return hash_64(vpage & 0xfffffffffULL, HPTEG_HASH_BITS_VPTE);
@@ -60,77 +59,128 @@ void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
{
u64 index;
+ trace_kvm_book3s_mmu_map(pte);
+
+ spin_lock(&vcpu->arch.mmu_lock);
+
/* Add to ePTE list */
index = kvmppc_mmu_hash_pte(pte->pte.eaddr);
- hlist_add_head(&pte->list_pte, &vcpu->arch.hpte_hash_pte[index]);
+ hlist_add_head_rcu(&pte->list_pte, &vcpu->arch.hpte_hash_pte[index]);
+
+ /* Add to ePTE_long list */
+ index = kvmppc_mmu_hash_pte_long(pte->pte.eaddr);
+ hlist_add_head_rcu(&pte->list_pte_long,
+ &vcpu->arch.hpte_hash_pte_long[index]);
/* Add to vPTE list */
index = kvmppc_mmu_hash_vpte(pte->pte.vpage);
- hlist_add_head(&pte->list_vpte, &vcpu->arch.hpte_hash_vpte[index]);
+ hlist_add_head_rcu(&pte->list_vpte, &vcpu->arch.hpte_hash_vpte[index]);
/* Add to vPTE_long list */
index = kvmppc_mmu_hash_vpte_long(pte->pte.vpage);
- hlist_add_head(&pte->list_vpte_long,
- &vcpu->arch.hpte_hash_vpte_long[index]);
+ hlist_add_head_rcu(&pte->list_vpte_long,
+ &vcpu->arch.hpte_hash_vpte_long[index]);
+
+ spin_unlock(&vcpu->arch.mmu_lock);
+}
+
+static void free_pte_rcu(struct rcu_head *head)
+{
+ struct hpte_cache *pte = container_of(head, struct hpte_cache, rcu_head);
+ kmem_cache_free(hpte_cache, pte);
}
static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
{
- dprintk_mmu("KVM: Flushing SPT: 0x%lx (0x%llx) -> 0x%llx\n",
- pte->pte.eaddr, pte->pte.vpage, pte->host_va);
+ trace_kvm_book3s_mmu_invalidate(pte);
/* Different for 32 and 64 bit */
kvmppc_mmu_invalidate_pte(vcpu, pte);
+ spin_lock(&vcpu->arch.mmu_lock);
+
+ /* pte already invalidated in between? */
+ if (hlist_unhashed(&pte->list_pte)) {
+ spin_unlock(&vcpu->arch.mmu_lock);
+ return;
+ }
+
+ hlist_del_init_rcu(&pte->list_pte);
+ hlist_del_init_rcu(&pte->list_pte_long);
+ hlist_del_init_rcu(&pte->list_vpte);
+ hlist_del_init_rcu(&pte->list_vpte_long);
+
if (pte->pte.may_write)
kvm_release_pfn_dirty(pte->pfn);
else
kvm_release_pfn_clean(pte->pfn);
- hlist_del(&pte->list_pte);
- hlist_del(&pte->list_vpte);
- hlist_del(&pte->list_vpte_long);
+ spin_unlock(&vcpu->arch.mmu_lock);
vcpu->arch.hpte_cache_count--;
- kmem_cache_free(hpte_cache, pte);
+ call_rcu(&pte->rcu_head, free_pte_rcu);
}
static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu)
{
struct hpte_cache *pte;
- struct hlist_node *node, *tmp;
+ struct hlist_node *node;
int i;
+ rcu_read_lock();
+
for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i];
- hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long)
+ hlist_for_each_entry_rcu(pte, node, list, list_vpte_long)
invalidate_pte(vcpu, pte);
}
+
+ rcu_read_unlock();
}
static void kvmppc_mmu_pte_flush_page(struct kvm_vcpu *vcpu, ulong guest_ea)
{
struct hlist_head *list;
- struct hlist_node *node, *tmp;
+ struct hlist_node *node;
struct hpte_cache *pte;
/* Find the list of entries in the map */
list = &vcpu->arch.hpte_hash_pte[kvmppc_mmu_hash_pte(guest_ea)];
+ rcu_read_lock();
+
/* Check the list for matching entries and invalidate */
- hlist_for_each_entry_safe(pte, node, tmp, list, list_pte)
+ hlist_for_each_entry_rcu(pte, node, list, list_pte)
if ((pte->pte.eaddr & ~0xfffUL) == guest_ea)
invalidate_pte(vcpu, pte);
+
+ rcu_read_unlock();
}
-void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
+static void kvmppc_mmu_pte_flush_long(struct kvm_vcpu *vcpu, ulong guest_ea)
{
- u64 i;
+ struct hlist_head *list;
+ struct hlist_node *node;
+ struct hpte_cache *pte;
- dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%lx & 0x%lx\n",
- vcpu->arch.hpte_cache_count, guest_ea, ea_mask);
+ /* Find the list of entries in the map */
+ list = &vcpu->arch.hpte_hash_pte_long[
+ kvmppc_mmu_hash_pte_long(guest_ea)];
+ rcu_read_lock();
+
+ /* Check the list for matching entries and invalidate */
+ hlist_for_each_entry_rcu(pte, node, list, list_pte_long)
+ if ((pte->pte.eaddr & 0x0ffff000UL) == guest_ea)
+ invalidate_pte(vcpu, pte);
+
+ rcu_read_unlock();
+}
+
+void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
+{
+ trace_kvm_book3s_mmu_flush("", vcpu, guest_ea, ea_mask);
guest_ea &= ea_mask;
switch (ea_mask) {
@@ -138,9 +188,7 @@ void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
kvmppc_mmu_pte_flush_page(vcpu, guest_ea);
break;
case 0x0ffff000:
- /* 32-bit flush w/o segment, go through all possible segments */
- for (i = 0; i < 0x100000000ULL; i += 0x10000000ULL)
- kvmppc_mmu_pte_flush(vcpu, guest_ea | i, ~0xfffUL);
+ kvmppc_mmu_pte_flush_long(vcpu, guest_ea);
break;
case 0:
/* Doing a complete flush -> start from scratch */
@@ -156,39 +204,46 @@ void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
static void kvmppc_mmu_pte_vflush_short(struct kvm_vcpu *vcpu, u64 guest_vp)
{
struct hlist_head *list;
- struct hlist_node *node, *tmp;
+ struct hlist_node *node;
struct hpte_cache *pte;
u64 vp_mask = 0xfffffffffULL;
list = &vcpu->arch.hpte_hash_vpte[kvmppc_mmu_hash_vpte(guest_vp)];
+ rcu_read_lock();
+
/* Check the list for matching entries and invalidate */
- hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte)
+ hlist_for_each_entry_rcu(pte, node, list, list_vpte)
if ((pte->pte.vpage & vp_mask) == guest_vp)
invalidate_pte(vcpu, pte);
+
+ rcu_read_unlock();
}
/* Flush with mask 0xffffff000 */
static void kvmppc_mmu_pte_vflush_long(struct kvm_vcpu *vcpu, u64 guest_vp)
{
struct hlist_head *list;
- struct hlist_node *node, *tmp;
+ struct hlist_node *node;
struct hpte_cache *pte;
u64 vp_mask = 0xffffff000ULL;
list = &vcpu->arch.hpte_hash_vpte_long[
kvmppc_mmu_hash_vpte_long(guest_vp)];
+ rcu_read_lock();
+
/* Check the list for matching entries and invalidate */
- hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long)
+ hlist_for_each_entry_rcu(pte, node, list, list_vpte_long)
if ((pte->pte.vpage & vp_mask) == guest_vp)
invalidate_pte(vcpu, pte);
+
+ rcu_read_unlock();
}
void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
{
- dprintk_mmu("KVM: Flushing %d Shadow vPTEs: 0x%llx & 0x%llx\n",
- vcpu->arch.hpte_cache_count, guest_vp, vp_mask);
+ trace_kvm_book3s_mmu_flush("v", vcpu, guest_vp, vp_mask);
guest_vp &= vp_mask;
switch(vp_mask) {
@@ -206,21 +261,24 @@ void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
{
- struct hlist_node *node, *tmp;
+ struct hlist_node *node;
struct hpte_cache *pte;
int i;
- dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%lx - 0x%lx\n",
- vcpu->arch.hpte_cache_count, pa_start, pa_end);
+ trace_kvm_book3s_mmu_flush("p", vcpu, pa_start, pa_end);
+
+ rcu_read_lock();
for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i];
- hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long)
+ hlist_for_each_entry_rcu(pte, node, list, list_vpte_long)
if ((pte->pte.raddr >= pa_start) &&
(pte->pte.raddr < pa_end))
invalidate_pte(vcpu, pte);
}
+
+ rcu_read_unlock();
}
struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu)
@@ -254,11 +312,15 @@ int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu)
/* init hpte lookup hashes */
kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte,
ARRAY_SIZE(vcpu->arch.hpte_hash_pte));
+ kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte_long,
+ ARRAY_SIZE(vcpu->arch.hpte_hash_pte_long));
kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte,
ARRAY_SIZE(vcpu->arch.hpte_hash_vpte));
kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte_long,
ARRAY_SIZE(vcpu->arch.hpte_hash_vpte_long));
+ spin_lock_init(&vcpu->arch.mmu_lock);
+
return 0;
}
diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c
index 35a701f3ece4..7b0ee96c1bed 100644
--- a/arch/powerpc/kvm/book3s_paired_singles.c
+++ b/arch/powerpc/kvm/book3s_paired_singles.c
@@ -165,14 +165,15 @@ static inline void kvmppc_sync_qpr(struct kvm_vcpu *vcpu, int rt)
static void kvmppc_inject_pf(struct kvm_vcpu *vcpu, ulong eaddr, bool is_store)
{
u64 dsisr;
+ struct kvm_vcpu_arch_shared *shared = vcpu->arch.shared;
- vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 33, 36, 0);
- vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 42, 47, 0);
- vcpu->arch.dear = eaddr;
+ shared->msr = kvmppc_set_field(shared->msr, 33, 36, 0);
+ shared->msr = kvmppc_set_field(shared->msr, 42, 47, 0);
+ shared->dar = eaddr;
/* Page Fault */
dsisr = kvmppc_set_field(0, 33, 33, 1);
if (is_store)
- to_book3s(vcpu)->dsisr = kvmppc_set_field(dsisr, 38, 38, 1);
+ shared->dsisr = kvmppc_set_field(dsisr, 38, 38, 1);
kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE);
}
@@ -658,7 +659,7 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
if (!kvmppc_inst_is_paired_single(vcpu, inst))
return EMULATE_FAIL;
- if (!(vcpu->arch.msr & MSR_FP)) {
+ if (!(vcpu->arch.shared->msr & MSR_FP)) {
kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL);
return EMULATE_AGAIN;
}
diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S
index 506d5c316c96..2b9c9088d00e 100644
--- a/arch/powerpc/kvm/book3s_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_rmhandlers.S
@@ -202,8 +202,25 @@ _GLOBAL(kvmppc_rmcall)
#if defined(CONFIG_PPC_BOOK3S_32)
#define STACK_LR INT_FRAME_SIZE+4
+
+/* load_up_xxx have to run with MSR_DR=0 on Book3S_32 */
+#define MSR_EXT_START \
+ PPC_STL r20, _NIP(r1); \
+ mfmsr r20; \
+ LOAD_REG_IMMEDIATE(r3, MSR_DR|MSR_EE); \
+ andc r3,r20,r3; /* Disable DR,EE */ \
+ mtmsr r3; \
+ sync
+
+#define MSR_EXT_END \
+ mtmsr r20; /* Enable DR,EE */ \
+ sync; \
+ PPC_LL r20, _NIP(r1)
+
#elif defined(CONFIG_PPC_BOOK3S_64)
#define STACK_LR _LINK
+#define MSR_EXT_START
+#define MSR_EXT_END
#endif
/*
@@ -215,19 +232,12 @@ _GLOBAL(kvmppc_load_up_ ## what); \
PPC_STLU r1, -INT_FRAME_SIZE(r1); \
mflr r3; \
PPC_STL r3, STACK_LR(r1); \
- PPC_STL r20, _NIP(r1); \
- mfmsr r20; \
- LOAD_REG_IMMEDIATE(r3, MSR_DR|MSR_EE); \
- andc r3,r20,r3; /* Disable DR,EE */ \
- mtmsr r3; \
- sync; \
+ MSR_EXT_START; \
\
bl FUNC(load_up_ ## what); \
\
- mtmsr r20; /* Enable DR,EE */ \
- sync; \
+ MSR_EXT_END; \
PPC_LL r3, STACK_LR(r1); \
- PPC_LL r20, _NIP(r1); \
mtlr r3; \
addi r1, r1, INT_FRAME_SIZE; \
blr
@@ -242,10 +252,10 @@ define_load_up(vsx)
.global kvmppc_trampoline_lowmem
kvmppc_trampoline_lowmem:
- .long kvmppc_handler_lowmem_trampoline - CONFIG_KERNEL_START
+ PPC_LONG kvmppc_handler_lowmem_trampoline - CONFIG_KERNEL_START
.global kvmppc_trampoline_enter
kvmppc_trampoline_enter:
- .long kvmppc_handler_trampoline_enter - CONFIG_KERNEL_START
+ PPC_LONG kvmppc_handler_trampoline_enter - CONFIG_KERNEL_START
#include "book3s_segment.S"
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 8d4e35f5372c..77575d08c818 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -62,9 +62,10 @@ void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu)
{
int i;
- printk("pc: %08lx msr: %08lx\n", vcpu->arch.pc, vcpu->arch.msr);
+ printk("pc: %08lx msr: %08llx\n", vcpu->arch.pc, vcpu->arch.shared->msr);
printk("lr: %08lx ctr: %08lx\n", vcpu->arch.lr, vcpu->arch.ctr);
- printk("srr0: %08lx srr1: %08lx\n", vcpu->arch.srr0, vcpu->arch.srr1);
+ printk("srr0: %08llx srr1: %08llx\n", vcpu->arch.shared->srr0,
+ vcpu->arch.shared->srr1);
printk("exceptions: %08lx\n", vcpu->arch.pending_exceptions);
@@ -130,13 +131,19 @@ void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu)
void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
struct kvm_interrupt *irq)
{
- kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_EXTERNAL);
+ unsigned int prio = BOOKE_IRQPRIO_EXTERNAL;
+
+ if (irq->irq == KVM_INTERRUPT_SET_LEVEL)
+ prio = BOOKE_IRQPRIO_EXTERNAL_LEVEL;
+
+ kvmppc_booke_queue_irqprio(vcpu, prio);
}
void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu,
struct kvm_interrupt *irq)
{
clear_bit(BOOKE_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions);
+ clear_bit(BOOKE_IRQPRIO_EXTERNAL_LEVEL, &vcpu->arch.pending_exceptions);
}
/* Deliver the interrupt of the corresponding priority, if possible. */
@@ -146,6 +153,26 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
int allowed = 0;
ulong uninitialized_var(msr_mask);
bool update_esr = false, update_dear = false;
+ ulong crit_raw = vcpu->arch.shared->critical;
+ ulong crit_r1 = kvmppc_get_gpr(vcpu, 1);
+ bool crit;
+ bool keep_irq = false;
+
+ /* Truncate crit indicators in 32 bit mode */
+ if (!(vcpu->arch.shared->msr & MSR_SF)) {
+ crit_raw &= 0xffffffff;
+ crit_r1 &= 0xffffffff;
+ }
+
+ /* Critical section when crit == r1 */
+ crit = (crit_raw == crit_r1);
+ /* ... and we're in supervisor mode */
+ crit = crit && !(vcpu->arch.shared->msr & MSR_PR);
+
+ if (priority == BOOKE_IRQPRIO_EXTERNAL_LEVEL) {
+ priority = BOOKE_IRQPRIO_EXTERNAL;
+ keep_irq = true;
+ }
switch (priority) {
case BOOKE_IRQPRIO_DTLB_MISS:
@@ -169,36 +196,38 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
break;
case BOOKE_IRQPRIO_CRITICAL:
case BOOKE_IRQPRIO_WATCHDOG:
- allowed = vcpu->arch.msr & MSR_CE;
+ allowed = vcpu->arch.shared->msr & MSR_CE;
msr_mask = MSR_ME;
break;
case BOOKE_IRQPRIO_MACHINE_CHECK:
- allowed = vcpu->arch.msr & MSR_ME;
+ allowed = vcpu->arch.shared->msr & MSR_ME;
msr_mask = 0;
break;
case BOOKE_IRQPRIO_EXTERNAL:
case BOOKE_IRQPRIO_DECREMENTER:
case BOOKE_IRQPRIO_FIT:
- allowed = vcpu->arch.msr & MSR_EE;
+ allowed = vcpu->arch.shared->msr & MSR_EE;
+ allowed = allowed && !crit;
msr_mask = MSR_CE|MSR_ME|MSR_DE;
break;
case BOOKE_IRQPRIO_DEBUG:
- allowed = vcpu->arch.msr & MSR_DE;
+ allowed = vcpu->arch.shared->msr & MSR_DE;
msr_mask = MSR_ME;
break;
}
if (allowed) {
- vcpu->arch.srr0 = vcpu->arch.pc;
- vcpu->arch.srr1 = vcpu->arch.msr;
+ vcpu->arch.shared->srr0 = vcpu->arch.pc;
+ vcpu->arch.shared->srr1 = vcpu->arch.shared->msr;
vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[priority];
if (update_esr == true)
vcpu->arch.esr = vcpu->arch.queued_esr;
if (update_dear == true)
- vcpu->arch.dear = vcpu->arch.queued_dear;
- kvmppc_set_msr(vcpu, vcpu->arch.msr & msr_mask);
+ vcpu->arch.shared->dar = vcpu->arch.queued_dear;
+ kvmppc_set_msr(vcpu, vcpu->arch.shared->msr & msr_mask);
- clear_bit(priority, &vcpu->arch.pending_exceptions);
+ if (!keep_irq)
+ clear_bit(priority, &vcpu->arch.pending_exceptions);
}
return allowed;
@@ -208,6 +237,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
{
unsigned long *pending = &vcpu->arch.pending_exceptions;
+ unsigned long old_pending = vcpu->arch.pending_exceptions;
unsigned int priority;
priority = __ffs(*pending);
@@ -219,6 +249,12 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
BITS_PER_BYTE * sizeof(*pending),
priority + 1);
}
+
+ /* Tell the guest about our interrupt status */
+ if (*pending)
+ vcpu->arch.shared->int_pending = 1;
+ else if (old_pending)
+ vcpu->arch.shared->int_pending = 0;
}
/**
@@ -265,7 +301,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
break;
case BOOKE_INTERRUPT_PROGRAM:
- if (vcpu->arch.msr & MSR_PR) {
+ if (vcpu->arch.shared->msr & MSR_PR) {
/* Program traps generated by user-level software must be handled
* by the guest kernel. */
kvmppc_core_queue_program(vcpu, vcpu->arch.fault_esr);
@@ -337,7 +373,15 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
break;
case BOOKE_INTERRUPT_SYSCALL:
- kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SYSCALL);
+ if (!(vcpu->arch.shared->msr & MSR_PR) &&
+ (((u32)kvmppc_get_gpr(vcpu, 0)) == KVM_SC_MAGIC_R0)) {
+ /* KVM PV hypercalls */
+ kvmppc_set_gpr(vcpu, 3, kvmppc_kvm_pv(vcpu));
+ r = RESUME_GUEST;
+ } else {
+ /* Guest syscalls */
+ kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SYSCALL);
+ }
kvmppc_account_exit(vcpu, SYSCALL_EXITS);
r = RESUME_GUEST;
break;
@@ -466,15 +510,19 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
/* Initial guest state: 16MB mapping 0 -> 0, PC = 0, MSR = 0, R1 = 16MB */
int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{
+ int i;
+
vcpu->arch.pc = 0;
- vcpu->arch.msr = 0;
+ vcpu->arch.shared->msr = 0;
kvmppc_set_gpr(vcpu, 1, (16<<20) - 8); /* -8 for the callee-save LR slot */
vcpu->arch.shadow_pid = 1;
- /* Eye-catching number so we know if the guest takes an interrupt
- * before it's programmed its own IVPR. */
+ /* Eye-catching numbers so we know if the guest takes an interrupt
+ * before it's programmed its own IVPR/IVORs. */
vcpu->arch.ivpr = 0x55550000;
+ for (i = 0; i < BOOKE_IRQPRIO_MAX; i++)
+ vcpu->arch.ivor[i] = 0x7700 | i * 4;
kvmppc_init_timing_stats(vcpu);
@@ -490,14 +538,14 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
regs->ctr = vcpu->arch.ctr;
regs->lr = vcpu->arch.lr;
regs->xer = kvmppc_get_xer(vcpu);
- regs->msr = vcpu->arch.msr;
- regs->srr0 = vcpu->arch.srr0;
- regs->srr1 = vcpu->arch.srr1;
+ regs->msr = vcpu->arch.shared->msr;
+ regs->srr0 = vcpu->arch.shared->srr0;
+ regs->srr1 = vcpu->arch.shared->srr1;
regs->pid = vcpu->arch.pid;
- regs->sprg0 = vcpu->arch.sprg0;
- regs->sprg1 = vcpu->arch.sprg1;
- regs->sprg2 = vcpu->arch.sprg2;
- regs->sprg3 = vcpu->arch.sprg3;
+ regs->sprg0 = vcpu->arch.shared->sprg0;
+ regs->sprg1 = vcpu->arch.shared->sprg1;
+ regs->sprg2 = vcpu->arch.shared->sprg2;
+ regs->sprg3 = vcpu->arch.shared->sprg3;
regs->sprg5 = vcpu->arch.sprg4;
regs->sprg6 = vcpu->arch.sprg5;
regs->sprg7 = vcpu->arch.sprg6;
@@ -518,12 +566,12 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
vcpu->arch.lr = regs->lr;
kvmppc_set_xer(vcpu, regs->xer);
kvmppc_set_msr(vcpu, regs->msr);
- vcpu->arch.srr0 = regs->srr0;
- vcpu->arch.srr1 = regs->srr1;
- vcpu->arch.sprg0 = regs->sprg0;
- vcpu->arch.sprg1 = regs->sprg1;
- vcpu->arch.sprg2 = regs->sprg2;
- vcpu->arch.sprg3 = regs->sprg3;
+ vcpu->arch.shared->srr0 = regs->srr0;
+ vcpu->arch.shared->srr1 = regs->srr1;
+ vcpu->arch.shared->sprg0 = regs->sprg0;
+ vcpu->arch.shared->sprg1 = regs->sprg1;
+ vcpu->arch.shared->sprg2 = regs->sprg2;
+ vcpu->arch.shared->sprg3 = regs->sprg3;
vcpu->arch.sprg5 = regs->sprg4;
vcpu->arch.sprg6 = regs->sprg5;
vcpu->arch.sprg7 = regs->sprg6;
diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h
index d59bcca1f9d8..492bb7030358 100644
--- a/arch/powerpc/kvm/booke.h
+++ b/arch/powerpc/kvm/booke.h
@@ -46,7 +46,9 @@
#define BOOKE_IRQPRIO_FIT 17
#define BOOKE_IRQPRIO_DECREMENTER 18
#define BOOKE_IRQPRIO_PERFORMANCE_MONITOR 19
-#define BOOKE_IRQPRIO_MAX 19
+/* Internal pseudo-irqprio for level triggered externals */
+#define BOOKE_IRQPRIO_EXTERNAL_LEVEL 20
+#define BOOKE_IRQPRIO_MAX 20
extern unsigned long kvmppc_booke_handlers;
@@ -54,12 +56,12 @@ extern unsigned long kvmppc_booke_handlers;
* changing. */
static inline void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
{
- if ((new_msr & MSR_PR) != (vcpu->arch.msr & MSR_PR))
+ if ((new_msr & MSR_PR) != (vcpu->arch.shared->msr & MSR_PR))
kvmppc_mmu_priv_switch(vcpu, new_msr & MSR_PR);
- vcpu->arch.msr = new_msr;
+ vcpu->arch.shared->msr = new_msr;
- if (vcpu->arch.msr & MSR_WE) {
+ if (vcpu->arch.shared->msr & MSR_WE) {
kvm_vcpu_block(vcpu);
kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS);
};
diff --git a/arch/powerpc/kvm/booke_emulate.c b/arch/powerpc/kvm/booke_emulate.c
index cbc790ee1928..1260f5f24c0c 100644
--- a/arch/powerpc/kvm/booke_emulate.c
+++ b/arch/powerpc/kvm/booke_emulate.c
@@ -31,8 +31,8 @@
static void kvmppc_emul_rfi(struct kvm_vcpu *vcpu)
{
- vcpu->arch.pc = vcpu->arch.srr0;
- kvmppc_set_msr(vcpu, vcpu->arch.srr1);
+ vcpu->arch.pc = vcpu->arch.shared->srr0;
+ kvmppc_set_msr(vcpu, vcpu->arch.shared->srr1);
}
int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
@@ -62,7 +62,7 @@ int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
case OP_31_XOP_MFMSR:
rt = get_rt(inst);
- kvmppc_set_gpr(vcpu, rt, vcpu->arch.msr);
+ kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->msr);
kvmppc_set_exit_type(vcpu, EMULATED_MFMSR_EXITS);
break;
@@ -74,13 +74,13 @@ int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
case OP_31_XOP_WRTEE:
rs = get_rs(inst);
- vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE)
+ vcpu->arch.shared->msr = (vcpu->arch.shared->msr & ~MSR_EE)
| (kvmppc_get_gpr(vcpu, rs) & MSR_EE);
kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS);
break;
case OP_31_XOP_WRTEEI:
- vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE)
+ vcpu->arch.shared->msr = (vcpu->arch.shared->msr & ~MSR_EE)
| (inst & MSR_EE);
kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS);
break;
@@ -105,7 +105,7 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
switch (sprn) {
case SPRN_DEAR:
- vcpu->arch.dear = spr_val; break;
+ vcpu->arch.shared->dar = spr_val; break;
case SPRN_ESR:
vcpu->arch.esr = spr_val; break;
case SPRN_DBCR0:
@@ -200,7 +200,7 @@ int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
case SPRN_IVPR:
kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivpr); break;
case SPRN_DEAR:
- kvmppc_set_gpr(vcpu, rt, vcpu->arch.dear); break;
+ kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->dar); break;
case SPRN_ESR:
kvmppc_set_gpr(vcpu, rt, vcpu->arch.esr); break;
case SPRN_DBCR0:
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S
index 380a78cf484d..049846911ce4 100644
--- a/arch/powerpc/kvm/booke_interrupts.S
+++ b/arch/powerpc/kvm/booke_interrupts.S
@@ -415,7 +415,8 @@ lightweight_exit:
lwz r8, VCPU_GPR(r8)(r4)
lwz r3, VCPU_PC(r4)
mtsrr0 r3
- lwz r3, VCPU_MSR(r4)
+ lwz r3, VCPU_SHARED(r4)
+ lwz r3, VCPU_SHARED_MSR(r3)
oris r3, r3, KVMPPC_MSR_MASK@h
ori r3, r3, KVMPPC_MSR_MASK@l
mtsrr1 r3
diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c
index e8a00b0c4449..71750f2dd5d3 100644
--- a/arch/powerpc/kvm/e500.c
+++ b/arch/powerpc/kvm/e500.c
@@ -117,8 +117,14 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
if (err)
goto uninit_vcpu;
+ vcpu->arch.shared = (void*)__get_free_page(GFP_KERNEL|__GFP_ZERO);
+ if (!vcpu->arch.shared)
+ goto uninit_tlb;
+
return vcpu;
+uninit_tlb:
+ kvmppc_e500_tlb_uninit(vcpu_e500);
uninit_vcpu:
kvm_vcpu_uninit(vcpu);
free_vcpu:
@@ -131,6 +137,7 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
{
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
+ free_page((unsigned long)vcpu->arch.shared);
kvmppc_e500_tlb_uninit(vcpu_e500);
kvm_vcpu_uninit(vcpu);
kmem_cache_free(kvm_vcpu_cache, vcpu_e500);
diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c
index 21011e12caeb..d6d6d47a75a9 100644
--- a/arch/powerpc/kvm/e500_tlb.c
+++ b/arch/powerpc/kvm/e500_tlb.c
@@ -226,8 +226,7 @@ static void kvmppc_e500_stlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500,
kvmppc_e500_shadow_release(vcpu_e500, tlbsel, esel);
stlbe->mas1 = 0;
- trace_kvm_stlb_inval(index_of(tlbsel, esel), stlbe->mas1, stlbe->mas2,
- stlbe->mas3, stlbe->mas7);
+ trace_kvm_stlb_inval(index_of(tlbsel, esel));
}
static void kvmppc_e500_tlb1_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500,
@@ -298,7 +297,8 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
/* Get reference to new page. */
new_page = gfn_to_page(vcpu_e500->vcpu.kvm, gfn);
if (is_error_page(new_page)) {
- printk(KERN_ERR "Couldn't get guest page for gfn %lx!\n", gfn);
+ printk(KERN_ERR "Couldn't get guest page for gfn %lx!\n",
+ (long)gfn);
kvm_release_page_clean(new_page);
return;
}
@@ -314,10 +314,10 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
| MAS1_TID(get_tlb_tid(gtlbe)) | MAS1_TS | MAS1_VALID;
stlbe->mas2 = (gvaddr & MAS2_EPN)
| e500_shadow_mas2_attrib(gtlbe->mas2,
- vcpu_e500->vcpu.arch.msr & MSR_PR);
+ vcpu_e500->vcpu.arch.shared->msr & MSR_PR);
stlbe->mas3 = (hpaddr & MAS3_RPN)
| e500_shadow_mas3_attrib(gtlbe->mas3,
- vcpu_e500->vcpu.arch.msr & MSR_PR);
+ vcpu_e500->vcpu.arch.shared->msr & MSR_PR);
stlbe->mas7 = (hpaddr >> 32) & MAS7_RPN;
trace_kvm_stlb_write(index_of(tlbsel, esel), stlbe->mas1, stlbe->mas2,
@@ -576,28 +576,28 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu)
int kvmppc_mmu_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr)
{
- unsigned int as = !!(vcpu->arch.msr & MSR_IS);
+ unsigned int as = !!(vcpu->arch.shared->msr & MSR_IS);
return kvmppc_e500_tlb_search(vcpu, eaddr, get_cur_pid(vcpu), as);
}
int kvmppc_mmu_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr)
{
- unsigned int as = !!(vcpu->arch.msr & MSR_DS);
+ unsigned int as = !!(vcpu->arch.shared->msr & MSR_DS);
return kvmppc_e500_tlb_search(vcpu, eaddr, get_cur_pid(vcpu), as);
}
void kvmppc_mmu_itlb_miss(struct kvm_vcpu *vcpu)
{
- unsigned int as = !!(vcpu->arch.msr & MSR_IS);
+ unsigned int as = !!(vcpu->arch.shared->msr & MSR_IS);
kvmppc_e500_deliver_tlb_miss(vcpu, vcpu->arch.pc, as);
}
void kvmppc_mmu_dtlb_miss(struct kvm_vcpu *vcpu)
{
- unsigned int as = !!(vcpu->arch.msr & MSR_DS);
+ unsigned int as = !!(vcpu->arch.shared->msr & MSR_DS);
kvmppc_e500_deliver_tlb_miss(vcpu, vcpu->arch.fault_dear, as);
}
diff --git a/arch/powerpc/kvm/e500_tlb.h b/arch/powerpc/kvm/e500_tlb.h
index d28e3010a5e2..458946b4775d 100644
--- a/arch/powerpc/kvm/e500_tlb.h
+++ b/arch/powerpc/kvm/e500_tlb.h
@@ -171,7 +171,7 @@ static inline int tlbe_is_host_safe(const struct kvm_vcpu *vcpu,
/* Does it match current guest AS? */
/* XXX what about IS != DS? */
- if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS))
+ if (get_tlb_ts(tlbe) != !!(vcpu->arch.shared->msr & MSR_IS))
return 0;
gpa = get_tlb_raddr(tlbe);
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index b83ba581fd8e..c64fd2909bb2 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -242,9 +242,11 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
switch (sprn) {
case SPRN_SRR0:
- kvmppc_set_gpr(vcpu, rt, vcpu->arch.srr0); break;
+ kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->srr0);
+ break;
case SPRN_SRR1:
- kvmppc_set_gpr(vcpu, rt, vcpu->arch.srr1); break;
+ kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->srr1);
+ break;
case SPRN_PVR:
kvmppc_set_gpr(vcpu, rt, vcpu->arch.pvr); break;
case SPRN_PIR:
@@ -261,13 +263,17 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
kvmppc_set_gpr(vcpu, rt, get_tb()); break;
case SPRN_SPRG0:
- kvmppc_set_gpr(vcpu, rt, vcpu->arch.sprg0); break;
+ kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg0);
+ break;
case SPRN_SPRG1:
- kvmppc_set_gpr(vcpu, rt, vcpu->arch.sprg1); break;
+ kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg1);
+ break;
case SPRN_SPRG2:
- kvmppc_set_gpr(vcpu, rt, vcpu->arch.sprg2); break;
+ kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg2);
+ break;
case SPRN_SPRG3:
- kvmppc_set_gpr(vcpu, rt, vcpu->arch.sprg3); break;
+ kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg3);
+ break;
/* Note: SPRG4-7 are user-readable, so we don't get
* a trap. */
@@ -320,9 +326,11 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
rs = get_rs(inst);
switch (sprn) {
case SPRN_SRR0:
- vcpu->arch.srr0 = kvmppc_get_gpr(vcpu, rs); break;
+ vcpu->arch.shared->srr0 = kvmppc_get_gpr(vcpu, rs);
+ break;
case SPRN_SRR1:
- vcpu->arch.srr1 = kvmppc_get_gpr(vcpu, rs); break;
+ vcpu->arch.shared->srr1 = kvmppc_get_gpr(vcpu, rs);
+ break;
/* XXX We need to context-switch the timebase for
* watchdog and FIT. */
@@ -337,13 +345,17 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
break;
case SPRN_SPRG0:
- vcpu->arch.sprg0 = kvmppc_get_gpr(vcpu, rs); break;
+ vcpu->arch.shared->sprg0 = kvmppc_get_gpr(vcpu, rs);
+ break;
case SPRN_SPRG1:
- vcpu->arch.sprg1 = kvmppc_get_gpr(vcpu, rs); break;
+ vcpu->arch.shared->sprg1 = kvmppc_get_gpr(vcpu, rs);
+ break;
case SPRN_SPRG2:
- vcpu->arch.sprg2 = kvmppc_get_gpr(vcpu, rs); break;
+ vcpu->arch.shared->sprg2 = kvmppc_get_gpr(vcpu, rs);
+ break;
case SPRN_SPRG3:
- vcpu->arch.sprg3 = kvmppc_get_gpr(vcpu, rs); break;
+ vcpu->arch.shared->sprg3 = kvmppc_get_gpr(vcpu, rs);
+ break;
default:
emulated = kvmppc_core_emulate_mtspr(vcpu, sprn, rs);
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 72a4ad86ee91..2f87a1627f6c 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -38,9 +38,56 @@
int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
{
- return !(v->arch.msr & MSR_WE) || !!(v->arch.pending_exceptions);
+ return !(v->arch.shared->msr & MSR_WE) ||
+ !!(v->arch.pending_exceptions);
}
+int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
+{
+ int nr = kvmppc_get_gpr(vcpu, 11);
+ int r;
+ unsigned long __maybe_unused param1 = kvmppc_get_gpr(vcpu, 3);
+ unsigned long __maybe_unused param2 = kvmppc_get_gpr(vcpu, 4);
+ unsigned long __maybe_unused param3 = kvmppc_get_gpr(vcpu, 5);
+ unsigned long __maybe_unused param4 = kvmppc_get_gpr(vcpu, 6);
+ unsigned long r2 = 0;
+
+ if (!(vcpu->arch.shared->msr & MSR_SF)) {
+ /* 32 bit mode */
+ param1 &= 0xffffffff;
+ param2 &= 0xffffffff;
+ param3 &= 0xffffffff;
+ param4 &= 0xffffffff;
+ }
+
+ switch (nr) {
+ case HC_VENDOR_KVM | KVM_HC_PPC_MAP_MAGIC_PAGE:
+ {
+ vcpu->arch.magic_page_pa = param1;
+ vcpu->arch.magic_page_ea = param2;
+
+ r2 = KVM_MAGIC_FEAT_SR;
+
+ r = HC_EV_SUCCESS;
+ break;
+ }
+ case HC_VENDOR_KVM | KVM_HC_FEATURES:
+ r = HC_EV_SUCCESS;
+#if defined(CONFIG_PPC_BOOK3S) /* XXX Missing magic page on BookE */
+ r2 |= (1 << KVM_FEATURE_MAGIC_PAGE);
+#endif
+
+ /* Second return value is in r4 */
+ break;
+ default:
+ r = HC_EV_UNIMPLEMENTED;
+ break;
+ }
+
+ kvmppc_set_gpr(vcpu, 4, r2);
+
+ return r;
+}
int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
{
@@ -145,8 +192,10 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_PPC_SEGSTATE:
case KVM_CAP_PPC_PAIRED_SINGLES:
case KVM_CAP_PPC_UNSET_IRQ:
+ case KVM_CAP_PPC_IRQ_LEVEL:
case KVM_CAP_ENABLE_CAP:
case KVM_CAP_PPC_OSI:
+ case KVM_CAP_PPC_GET_PVINFO:
r = 1;
break;
case KVM_CAP_COALESCED_MMIO:
@@ -534,16 +583,53 @@ out:
return r;
}
+static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)
+{
+ u32 inst_lis = 0x3c000000;
+ u32 inst_ori = 0x60000000;
+ u32 inst_nop = 0x60000000;
+ u32 inst_sc = 0x44000002;
+ u32 inst_imm_mask = 0xffff;
+
+ /*
+ * The hypercall to get into KVM from within guest context is as
+ * follows:
+ *
+ * lis r0, r0, KVM_SC_MAGIC_R0@h
+ * ori r0, KVM_SC_MAGIC_R0@l
+ * sc
+ * nop
+ */
+ pvinfo->hcall[0] = inst_lis | ((KVM_SC_MAGIC_R0 >> 16) & inst_imm_mask);
+ pvinfo->hcall[1] = inst_ori | (KVM_SC_MAGIC_R0 & inst_imm_mask);
+ pvinfo->hcall[2] = inst_sc;
+ pvinfo->hcall[3] = inst_nop;
+
+ return 0;
+}
+
long kvm_arch_vm_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
+ void __user *argp = (void __user *)arg;
long r;
switch (ioctl) {
+ case KVM_PPC_GET_PVINFO: {
+ struct kvm_ppc_pvinfo pvinfo;
+ r = kvm_vm_ioctl_get_pvinfo(&pvinfo);
+ if (copy_to_user(argp, &pvinfo, sizeof(pvinfo))) {
+ r = -EFAULT;
+ goto out;
+ }
+
+ break;
+ }
default:
r = -ENOTTY;
}
+out:
return r;
}
diff --git a/arch/powerpc/kvm/trace.h b/arch/powerpc/kvm/trace.h
index a8e840018052..3aca1b042b8c 100644
--- a/arch/powerpc/kvm/trace.h
+++ b/arch/powerpc/kvm/trace.h
@@ -98,6 +98,245 @@ TRACE_EVENT(kvm_gtlb_write,
__entry->word1, __entry->word2)
);
+
+/*************************************************************************
+ * Book3S trace points *
+ *************************************************************************/
+
+#ifdef CONFIG_PPC_BOOK3S
+
+TRACE_EVENT(kvm_book3s_exit,
+ TP_PROTO(unsigned int exit_nr, struct kvm_vcpu *vcpu),
+ TP_ARGS(exit_nr, vcpu),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, exit_nr )
+ __field( unsigned long, pc )
+ __field( unsigned long, msr )
+ __field( unsigned long, dar )
+ __field( unsigned long, srr1 )
+ ),
+
+ TP_fast_assign(
+ __entry->exit_nr = exit_nr;
+ __entry->pc = kvmppc_get_pc(vcpu);
+ __entry->dar = kvmppc_get_fault_dar(vcpu);
+ __entry->msr = vcpu->arch.shared->msr;
+ __entry->srr1 = to_svcpu(vcpu)->shadow_srr1;
+ ),
+
+ TP_printk("exit=0x%x | pc=0x%lx | msr=0x%lx | dar=0x%lx | srr1=0x%lx",
+ __entry->exit_nr, __entry->pc, __entry->msr, __entry->dar,
+ __entry->srr1)
+);
+
+TRACE_EVENT(kvm_book3s_reenter,
+ TP_PROTO(int r, struct kvm_vcpu *vcpu),
+ TP_ARGS(r, vcpu),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, r )
+ __field( unsigned long, pc )
+ ),
+
+ TP_fast_assign(
+ __entry->r = r;
+ __entry->pc = kvmppc_get_pc(vcpu);
+ ),
+
+ TP_printk("reentry r=%d | pc=0x%lx", __entry->r, __entry->pc)
+);
+
+#ifdef CONFIG_PPC_BOOK3S_64
+
+TRACE_EVENT(kvm_book3s_64_mmu_map,
+ TP_PROTO(int rflags, ulong hpteg, ulong va, pfn_t hpaddr,
+ struct kvmppc_pte *orig_pte),
+ TP_ARGS(rflags, hpteg, va, hpaddr, orig_pte),
+
+ TP_STRUCT__entry(
+ __field( unsigned char, flag_w )
+ __field( unsigned char, flag_x )
+ __field( unsigned long, eaddr )
+ __field( unsigned long, hpteg )
+ __field( unsigned long, va )
+ __field( unsigned long long, vpage )
+ __field( unsigned long, hpaddr )
+ ),
+
+ TP_fast_assign(
+ __entry->flag_w = ((rflags & HPTE_R_PP) == 3) ? '-' : 'w';
+ __entry->flag_x = (rflags & HPTE_R_N) ? '-' : 'x';
+ __entry->eaddr = orig_pte->eaddr;
+ __entry->hpteg = hpteg;
+ __entry->va = va;
+ __entry->vpage = orig_pte->vpage;
+ __entry->hpaddr = hpaddr;
+ ),
+
+ TP_printk("KVM: %c%c Map 0x%lx: [%lx] 0x%lx (0x%llx) -> %lx",
+ __entry->flag_w, __entry->flag_x, __entry->eaddr,
+ __entry->hpteg, __entry->va, __entry->vpage, __entry->hpaddr)
+);
+
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
+TRACE_EVENT(kvm_book3s_mmu_map,
+ TP_PROTO(struct hpte_cache *pte),
+ TP_ARGS(pte),
+
+ TP_STRUCT__entry(
+ __field( u64, host_va )
+ __field( u64, pfn )
+ __field( ulong, eaddr )
+ __field( u64, vpage )
+ __field( ulong, raddr )
+ __field( int, flags )
+ ),
+
+ TP_fast_assign(
+ __entry->host_va = pte->host_va;
+ __entry->pfn = pte->pfn;
+ __entry->eaddr = pte->pte.eaddr;
+ __entry->vpage = pte->pte.vpage;
+ __entry->raddr = pte->pte.raddr;
+ __entry->flags = (pte->pte.may_read ? 0x4 : 0) |
+ (pte->pte.may_write ? 0x2 : 0) |
+ (pte->pte.may_execute ? 0x1 : 0);
+ ),
+
+ TP_printk("Map: hva=%llx pfn=%llx ea=%lx vp=%llx ra=%lx [%x]",
+ __entry->host_va, __entry->pfn, __entry->eaddr,
+ __entry->vpage, __entry->raddr, __entry->flags)
+);
+
+TRACE_EVENT(kvm_book3s_mmu_invalidate,
+ TP_PROTO(struct hpte_cache *pte),
+ TP_ARGS(pte),
+
+ TP_STRUCT__entry(
+ __field( u64, host_va )
+ __field( u64, pfn )
+ __field( ulong, eaddr )
+ __field( u64, vpage )
+ __field( ulong, raddr )
+ __field( int, flags )
+ ),
+
+ TP_fast_assign(
+ __entry->host_va = pte->host_va;
+ __entry->pfn = pte->pfn;
+ __entry->eaddr = pte->pte.eaddr;
+ __entry->vpage = pte->pte.vpage;
+ __entry->raddr = pte->pte.raddr;
+ __entry->flags = (pte->pte.may_read ? 0x4 : 0) |
+ (pte->pte.may_write ? 0x2 : 0) |
+ (pte->pte.may_execute ? 0x1 : 0);
+ ),
+
+ TP_printk("Flush: hva=%llx pfn=%llx ea=%lx vp=%llx ra=%lx [%x]",
+ __entry->host_va, __entry->pfn, __entry->eaddr,
+ __entry->vpage, __entry->raddr, __entry->flags)
+);
+
+TRACE_EVENT(kvm_book3s_mmu_flush,
+ TP_PROTO(const char *type, struct kvm_vcpu *vcpu, unsigned long long p1,
+ unsigned long long p2),
+ TP_ARGS(type, vcpu, p1, p2),
+
+ TP_STRUCT__entry(
+ __field( int, count )
+ __field( unsigned long long, p1 )
+ __field( unsigned long long, p2 )
+ __field( const char *, type )
+ ),
+
+ TP_fast_assign(
+ __entry->count = vcpu->arch.hpte_cache_count;
+ __entry->p1 = p1;
+ __entry->p2 = p2;
+ __entry->type = type;
+ ),
+
+ TP_printk("Flush %d %sPTEs: %llx - %llx",
+ __entry->count, __entry->type, __entry->p1, __entry->p2)
+);
+
+TRACE_EVENT(kvm_book3s_slb_found,
+ TP_PROTO(unsigned long long gvsid, unsigned long long hvsid),
+ TP_ARGS(gvsid, hvsid),
+
+ TP_STRUCT__entry(
+ __field( unsigned long long, gvsid )
+ __field( unsigned long long, hvsid )
+ ),
+
+ TP_fast_assign(
+ __entry->gvsid = gvsid;
+ __entry->hvsid = hvsid;
+ ),
+
+ TP_printk("%llx -> %llx", __entry->gvsid, __entry->hvsid)
+);
+
+TRACE_EVENT(kvm_book3s_slb_fail,
+ TP_PROTO(u16 sid_map_mask, unsigned long long gvsid),
+ TP_ARGS(sid_map_mask, gvsid),
+
+ TP_STRUCT__entry(
+ __field( unsigned short, sid_map_mask )
+ __field( unsigned long long, gvsid )
+ ),
+
+ TP_fast_assign(
+ __entry->sid_map_mask = sid_map_mask;
+ __entry->gvsid = gvsid;
+ ),
+
+ TP_printk("%x/%x: %llx", __entry->sid_map_mask,
+ SID_MAP_MASK - __entry->sid_map_mask, __entry->gvsid)
+);
+
+TRACE_EVENT(kvm_book3s_slb_map,
+ TP_PROTO(u16 sid_map_mask, unsigned long long gvsid,
+ unsigned long long hvsid),
+ TP_ARGS(sid_map_mask, gvsid, hvsid),
+
+ TP_STRUCT__entry(
+ __field( unsigned short, sid_map_mask )
+ __field( unsigned long long, guest_vsid )
+ __field( unsigned long long, host_vsid )
+ ),
+
+ TP_fast_assign(
+ __entry->sid_map_mask = sid_map_mask;
+ __entry->guest_vsid = gvsid;
+ __entry->host_vsid = hvsid;
+ ),
+
+ TP_printk("%x: %llx -> %llx", __entry->sid_map_mask,
+ __entry->guest_vsid, __entry->host_vsid)
+);
+
+TRACE_EVENT(kvm_book3s_slbmte,
+ TP_PROTO(u64 slb_vsid, u64 slb_esid),
+ TP_ARGS(slb_vsid, slb_esid),
+
+ TP_STRUCT__entry(
+ __field( u64, slb_vsid )
+ __field( u64, slb_esid )
+ ),
+
+ TP_fast_assign(
+ __entry->slb_vsid = slb_vsid;
+ __entry->slb_esid = slb_esid;
+ ),
+
+ TP_printk("%llx, %llx", __entry->slb_vsid, __entry->slb_esid)
+);
+
+#endif /* CONFIG_PPC_BOOK3S */
+
#endif /* _TRACE_KVM_H */
/* This part must be outside protection */
diff --git a/arch/powerpc/mm/highmem.c b/arch/powerpc/mm/highmem.c
index 857d4173f9c6..e7450bdbe83a 100644
--- a/arch/powerpc/mm/highmem.c
+++ b/arch/powerpc/mm/highmem.c
@@ -29,17 +29,17 @@
* be used in IRQ contexts, so in some (very limited) cases we need
* it.
*/
-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot(struct page *page, pgprot_t prot)
{
- unsigned int idx;
unsigned long vaddr;
+ int idx, type;
/* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
pagefault_disable();
if (!PageHighMem(page))
return page_address(page);
- debug_kmap_atomic(type);
+ type = kmap_atomic_idx_push();
idx = type + KM_TYPE_NR*smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
#ifdef CONFIG_DEBUG_HIGHMEM
@@ -52,26 +52,35 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
}
EXPORT_SYMBOL(kmap_atomic_prot);
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
{
-#ifdef CONFIG_DEBUG_HIGHMEM
unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
- enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
+ int type;
if (vaddr < __fix_to_virt(FIX_KMAP_END)) {
pagefault_enable();
return;
}
- BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+ type = kmap_atomic_idx();
- /*
- * force other mappings to Oops if they'll try to access
- * this pte without first remap it
- */
- pte_clear(&init_mm, vaddr, kmap_pte-idx);
- local_flush_tlb_page(NULL, vaddr);
+#ifdef CONFIG_DEBUG_HIGHMEM
+ {
+ unsigned int idx;
+
+ idx = type + KM_TYPE_NR * smp_processor_id();
+ BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+
+ /*
+ * force other mappings to Oops if they'll try to access
+ * this pte without first remap it
+ */
+ pte_clear(&init_mm, vaddr, kmap_pte-idx);
+ local_flush_tlb_page(NULL, vaddr);
+ }
#endif
+
+ kmap_atomic_idx_pop();
pagefault_enable();
}
-EXPORT_SYMBOL(kunmap_atomic_notypecheck);
+EXPORT_SYMBOL(__kunmap_atomic);
diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c
index 2b390d19a1d1..7eb5c40c069f 100644
--- a/arch/powerpc/platforms/85xx/p1022_ds.c
+++ b/arch/powerpc/platforms/85xx/p1022_ds.c
@@ -8,7 +8,6 @@
* Copyright 2010 Freescale Semiconductor, Inc.
*
* This file is taken from the Freescale P1022DS BSP, with modifications:
- * 1) No DIU support (pending rewrite of DIU code)
* 2) No AMP support
* 3) No PCI endpoint support
*
@@ -20,12 +19,211 @@
#include <linux/pci.h>
#include <linux/of_platform.h>
#include <linux/memblock.h>
-
+#include <asm/div64.h>
#include <asm/mpic.h>
#include <asm/swiotlb.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
+#include <asm/fsl_guts.h>
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+
+/*
+ * Board-specific initialization of the DIU. This code should probably be
+ * executed when the DIU is opened, rather than in arch code, but the DIU
+ * driver does not have a mechanism for this (yet).
+ *
+ * This is especially problematic on the P1022DS because the local bus (eLBC)
+ * and the DIU video signals share the same pins, which means that enabling the
+ * DIU will disable access to NOR flash.
+ */
+
+/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */
+#define CLKDVDR_PXCKEN 0x80000000
+#define CLKDVDR_PXCKINV 0x10000000
+#define CLKDVDR_PXCKDLY 0x06000000
+#define CLKDVDR_PXCLK_MASK 0x00FF0000
+
+/* Some ngPIXIS register definitions */
+#define PX_BRDCFG1_DVIEN 0x80
+#define PX_BRDCFG1_DFPEN 0x40
+#define PX_BRDCFG1_BACKLIGHT 0x20
+#define PX_BRDCFG1_DDCEN 0x10
+
+/*
+ * DIU Area Descriptor
+ *
+ * Note that we need to byte-swap the value before it's written to the AD
+ * register. So even though the registers don't look like they're in the same
+ * bit positions as they are on the MPC8610, the same value is written to the
+ * AD register on the MPC8610 and on the P1022.
+ */
+#define AD_BYTE_F 0x10000000
+#define AD_ALPHA_C_MASK 0x0E000000
+#define AD_ALPHA_C_SHIFT 25
+#define AD_BLUE_C_MASK 0x01800000
+#define AD_BLUE_C_SHIFT 23
+#define AD_GREEN_C_MASK 0x00600000
+#define AD_GREEN_C_SHIFT 21
+#define AD_RED_C_MASK 0x00180000
+#define AD_RED_C_SHIFT 19
+#define AD_PALETTE 0x00040000
+#define AD_PIXEL_S_MASK 0x00030000
+#define AD_PIXEL_S_SHIFT 16
+#define AD_COMP_3_MASK 0x0000F000
+#define AD_COMP_3_SHIFT 12
+#define AD_COMP_2_MASK 0x00000F00
+#define AD_COMP_2_SHIFT 8
+#define AD_COMP_1_MASK 0x000000F0
+#define AD_COMP_1_SHIFT 4
+#define AD_COMP_0_MASK 0x0000000F
+#define AD_COMP_0_SHIFT 0
+
+#define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \
+ cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \
+ (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \
+ (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \
+ (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \
+ (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))
+
+/**
+ * p1022ds_get_pixel_format: return the Area Descriptor for a given pixel depth
+ *
+ * The Area Descriptor is a 32-bit value that determine which bits in each
+ * pixel are to be used for each color.
+ */
+static unsigned int p1022ds_get_pixel_format(unsigned int bits_per_pixel,
+ int monitor_port)
+{
+ switch (bits_per_pixel) {
+ case 32:
+ /* 0x88883316 */
+ return MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8);
+ case 24:
+ /* 0x88082219 */
+ return MAKE_AD(4, 0, 1, 2, 2, 0, 8, 8, 8);
+ case 16:
+ /* 0x65053118 */
+ return MAKE_AD(4, 2, 1, 0, 1, 5, 6, 5, 0);
+ default:
+ pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel);
+ return 0;
+ }
+}
+
+/**
+ * p1022ds_set_gamma_table: update the gamma table, if necessary
+ *
+ * On some boards, the gamma table for some ports may need to be modified.
+ * This is not the case on the P1022DS, so we do nothing.
+*/
+static void p1022ds_set_gamma_table(int monitor_port, char *gamma_table_base)
+{
+}
+
+/**
+ * p1022ds_set_monitor_port: switch the output to a different monitor port
+ *
+ */
+static void p1022ds_set_monitor_port(int monitor_port)
+{
+ struct device_node *pixis_node;
+ u8 __iomem *brdcfg1;
+
+ pixis_node = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis");
+ if (!pixis_node) {
+ pr_err("p1022ds: missing ngPIXIS node\n");
+ return;
+ }
+
+ brdcfg1 = of_iomap(pixis_node, 0);
+ if (!brdcfg1) {
+ pr_err("p1022ds: could not map ngPIXIS registers\n");
+ return;
+ }
+ brdcfg1 += 9; /* BRDCFG1 is at offset 9 in the ngPIXIS */
+
+ switch (monitor_port) {
+ case 0: /* DVI */
+ /* Enable the DVI port, disable the DFP and the backlight */
+ clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT,
+ PX_BRDCFG1_DVIEN);
+ break;
+ case 1: /* Single link LVDS */
+ /* Enable the DFP port, disable the DVI and the backlight */
+ clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT,
+ PX_BRDCFG1_DFPEN);
+ break;
+ default:
+ pr_err("p1022ds: unsupported monitor port %i\n", monitor_port);
+ }
+}
+
+/**
+ * p1022ds_set_pixel_clock: program the DIU's clock
+ *
+ * @pixclock: the wavelength, in picoseconds, of the clock
+ */
+void p1022ds_set_pixel_clock(unsigned int pixclock)
+{
+ struct device_node *guts_np = NULL;
+ struct ccsr_guts_85xx __iomem *guts;
+ unsigned long freq;
+ u64 temp;
+ u32 pxclk;
+
+ /* Map the global utilities registers. */
+ guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+ if (!guts_np) {
+ pr_err("p1022ds: missing global utilties device node\n");
+ return;
+ }
+
+ guts = of_iomap(guts_np, 0);
+ of_node_put(guts_np);
+ if (!guts) {
+ pr_err("p1022ds: could not map global utilties device\n");
+ return;
+ }
+
+ /* Convert pixclock from a wavelength to a frequency */
+ temp = 1000000000000ULL;
+ do_div(temp, pixclock);
+ freq = temp;
+
+ /* pixclk is the ratio of the platform clock to the pixel clock */
+ pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq);
+
+ /* Disable the pixel clock, and set it to non-inverted and no delay */
+ clrbits32(&guts->clkdvdr,
+ CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK);
+
+ /* Enable the clock and set the pxclk */
+ setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16));
+}
+
+/**
+ * p1022ds_show_monitor_port: show the current monitor
+ *
+ * This function returns a string indicating whether the current monitor is
+ * set to DVI or LVDS.
+ */
+ssize_t p1022ds_show_monitor_port(int monitor_port, char *buf)
+{
+ return sprintf(buf, "%c0 - DVI\n%c1 - Single link LVDS\n",
+ monitor_port == 0 ? '*' : ' ', monitor_port == 1 ? '*' : ' ');
+}
+
+/**
+ * p1022ds_set_sysfs_monitor_port: set the monitor port for sysfs
+ */
+int p1022ds_set_sysfs_monitor_port(int val)
+{
+ return val < 2 ? val : 0;
+}
+
+#endif
void __init p1022_ds_pic_init(void)
{
@@ -92,6 +290,15 @@ static void __init p1022_ds_setup_arch(void)
}
#endif
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+ diu_ops.get_pixel_format = p1022ds_get_pixel_format;
+ diu_ops.set_gamma_table = p1022ds_set_gamma_table;
+ diu_ops.set_monitor_port = p1022ds_set_monitor_port;
+ diu_ops.set_pixel_clock = p1022ds_set_pixel_clock;
+ diu_ops.show_monitor_port = p1022ds_show_monitor_port;
+ diu_ops.set_sysfs_monitor_port = p1022ds_set_sysfs_monitor_port;
+#endif
+
#ifdef CONFIG_SMP
mpc85xx_smp_init();
#endif
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 81c9208025fa..956154f32cfe 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -21,6 +21,16 @@ source "arch/powerpc/platforms/44x/Kconfig"
source "arch/powerpc/platforms/40x/Kconfig"
source "arch/powerpc/platforms/amigaone/Kconfig"
+config KVM_GUEST
+ bool "KVM Guest support"
+ default y
+ ---help---
+ This option enables various optimizations for running under the KVM
+ hypervisor. Overhead for the kernel when not running inside KVM should
+ be minimal.
+
+ In case of doubt, say Y
+
config PPC_NATIVE
bool
depends on 6xx || PPC64
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index 412763672d23..9725369d432a 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -50,6 +50,7 @@
#define RIO_ATMU_REGS_OFFSET 0x10c00
#define RIO_P_MSG_REGS_OFFSET 0x11000
#define RIO_S_MSG_REGS_OFFSET 0x13000
+#define RIO_GCCSR 0x13c
#define RIO_ESCSR 0x158
#define RIO_CCSR 0x15c
#define RIO_LTLEDCSR 0x0608
@@ -87,6 +88,9 @@
#define RIO_IPWSR_PWD 0x00000008
#define RIO_IPWSR_PWB 0x00000004
+#define RIO_EPWISR_PINT 0x80000000
+#define RIO_EPWISR_PW 0x00000001
+
#define RIO_MSG_DESC_SIZE 32
#define RIO_MSG_BUFFER_SIZE 4096
#define RIO_MIN_TX_RING_SIZE 2
@@ -1082,18 +1086,12 @@ fsl_rio_port_write_handler(int irq, void *dev_instance)
struct rio_priv *priv = port->priv;
u32 epwisr, tmp;
- ipwmr = in_be32(&priv->msg_regs->pwmr);
- ipwsr = in_be32(&priv->msg_regs->pwsr);
-
epwisr = in_be32(priv->regs_win + RIO_EPWISR);
- if (epwisr & 0x80000000) {
- tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
- pr_info("RIO_LTLEDCSR = 0x%x\n", tmp);
- out_be32(priv->regs_win + RIO_LTLEDCSR, 0);
- }
+ if (!(epwisr & RIO_EPWISR_PW))
+ goto pw_done;
- if (!(epwisr & 0x00000001))
- return IRQ_HANDLED;
+ ipwmr = in_be32(&priv->msg_regs->pwmr);
+ ipwsr = in_be32(&priv->msg_regs->pwsr);
#ifdef DEBUG_PW
pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr);
@@ -1109,20 +1107,6 @@ fsl_rio_port_write_handler(int irq, void *dev_instance)
pr_debug(" PWB");
pr_debug(" )\n");
#endif
- out_be32(&priv->msg_regs->pwsr,
- ipwsr & (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
-
- if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) {
- priv->port_write_msg.err_count++;
- pr_info("RIO: Port-Write Transaction Err (%d)\n",
- priv->port_write_msg.err_count);
- }
- if (ipwsr & RIO_IPWSR_PWD) {
- priv->port_write_msg.discard_count++;
- pr_info("RIO: Port Discarded Port-Write Msg(s) (%d)\n",
- priv->port_write_msg.discard_count);
- }
-
/* Schedule deferred processing if PW was received */
if (ipwsr & RIO_IPWSR_QFI) {
/* Save PW message (if there is room in FIFO),
@@ -1134,16 +1118,43 @@ fsl_rio_port_write_handler(int irq, void *dev_instance)
RIO_PW_MSG_SIZE);
} else {
priv->port_write_msg.discard_count++;
- pr_info("RIO: ISR Discarded Port-Write Msg(s) (%d)\n",
+ pr_debug("RIO: ISR Discarded Port-Write Msg(s) (%d)\n",
priv->port_write_msg.discard_count);
}
+ /* Clear interrupt and issue Clear Queue command. This allows
+ * another port-write to be received.
+ */
+ out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_QFI);
+ out_be32(&priv->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
+
schedule_work(&priv->pw_work);
}
- /* Issue Clear Queue command. This allows another
- * port-write to be received.
- */
- out_be32(&priv->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
+ if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) {
+ priv->port_write_msg.err_count++;
+ pr_debug("RIO: Port-Write Transaction Err (%d)\n",
+ priv->port_write_msg.err_count);
+ /* Clear Transaction Error: port-write controller should be
+ * disabled when clearing this error
+ */
+ out_be32(&priv->msg_regs->pwmr, ipwmr & ~RIO_IPWMR_PWE);
+ out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_TE);
+ out_be32(&priv->msg_regs->pwmr, ipwmr);
+ }
+
+ if (ipwsr & RIO_IPWSR_PWD) {
+ priv->port_write_msg.discard_count++;
+ pr_debug("RIO: Port Discarded Port-Write Msg(s) (%d)\n",
+ priv->port_write_msg.discard_count);
+ out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_PWD);
+ }
+
+pw_done:
+ if (epwisr & RIO_EPWISR_PINT) {
+ tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+ pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
+ out_be32(priv->regs_win + RIO_LTLEDCSR, 0);
+ }
return IRQ_HANDLED;
}
@@ -1461,6 +1472,7 @@ int fsl_rio_setup(struct platform_device *dev)
port->host_deviceid = fsl_rio_get_hdid(port->id);
port->priv = priv;
+ port->phys_efptr = 0x100;
rio_register_mport(port);
priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1);
@@ -1508,6 +1520,12 @@ int fsl_rio_setup(struct platform_device *dev)
dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n",
port->sys_size ? 65536 : 256);
+ if (port->host_deviceid >= 0)
+ out_be32(priv->regs_win + RIO_GCCSR, RIO_PORT_GEN_HOST |
+ RIO_PORT_GEN_MASTER | RIO_PORT_GEN_DISCOVERED);
+ else
+ out_be32(priv->regs_win + RIO_GCCSR, 0x00000000);
+
priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win
+ RIO_ATMU_REGS_OFFSET);
priv->maint_atmu_regs = priv->atmu_regs + 1;
diff --git a/arch/s390/Kbuild b/arch/s390/Kbuild
new file mode 100644
index 000000000000..ae4b01060edd
--- /dev/null
+++ b/arch/s390/Kbuild
@@ -0,0 +1,6 @@
+obj-y += kernel/
+obj-y += mm/
+obj-y += crypto/
+obj-y += appldata/
+obj-y += hypfs/
+obj-y += kvm/
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 75976a141947..068e55d1bba8 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -60,6 +60,9 @@ config NO_IOMEM
config NO_DMA
def_bool y
+config ARCH_DMA_ADDR_T_64BIT
+ def_bool 64BIT
+
config GENERIC_LOCKBREAK
bool
default y
@@ -101,6 +104,7 @@ config S390
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_LZMA
select HAVE_KERNEL_LZO
+ select HAVE_GET_USER_PAGES_FAST
select ARCH_INLINE_SPIN_TRYLOCK
select ARCH_INLINE_SPIN_TRYLOCK_BH
select ARCH_INLINE_SPIN_LOCK
@@ -286,6 +290,14 @@ config MARCH_Z10
machines such as the z990, z890, z900, z800, z9-109, z9-ec
and z9-bc.
+config MARCH_Z196
+ bool "IBM zEnterprise 196"
+ help
+ Select this to enable optimizations for IBM zEnterprise 196.
+ The kernel will be slightly faster but will not work on older
+ machines such as the z990, z890, z900, z800, z9-109, z9-ec,
+ z9-bc, z10-ec and z10-bc.
+
endchoice
config PACK_STACK
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index 0c9e6c6d2a64..d5b8a6ade525 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -40,6 +40,7 @@ cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900)
cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990)
cflags-$(CONFIG_MARCH_Z9_109) += $(call cc-option,-march=z9-109)
cflags-$(CONFIG_MARCH_Z10) += $(call cc-option,-march=z10)
+cflags-$(CONFIG_MARCH_Z196) += $(call cc-option,-march=z196)
#KBUILD_IMAGE is necessary for make rpm
KBUILD_IMAGE :=arch/s390/boot/image
@@ -94,8 +95,8 @@ head-y := arch/s390/kernel/head.o
head-y += arch/s390/kernel/$(if $(CONFIG_64BIT),head64.o,head31.o)
head-y += arch/s390/kernel/init_task.o
-core-y += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \
- arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/
+# See arch/s390/Kbuild for content of core part of the kernel
+core-y += arch/s390/
libs-y += arch/s390/lib/
drivers-y += drivers/s390/
diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h
index 0ef9829f2ad6..7ee9a1b4ad9f 100644
--- a/arch/s390/crypto/crypt_s390.h
+++ b/arch/s390/crypto/crypt_s390.h
@@ -297,7 +297,7 @@ static inline int crypt_s390_func_available(int func)
int ret;
/* check if CPACF facility (bit 17) is available */
- if (!(stfl() & 1ULL << (31 - 17)))
+ if (!test_facility(17))
return 0;
switch (func & CRYPT_S390_OP_MASK) {
diff --git a/arch/s390/include/asm/Kbuild b/arch/s390/include/asm/Kbuild
index 42e512ba8b43..287d7bbb6d36 100644
--- a/arch/s390/include/asm/Kbuild
+++ b/arch/s390/include/asm/Kbuild
@@ -5,6 +5,7 @@ header-y += chsc.h
header-y += cmb.h
header-y += dasd.h
header-y += debug.h
+header-y += kvm_virtio.h
header-y += monwriter.h
header-y += qeth.h
header-y += schid.h
diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h
index f3ba0fa98de6..e8501115eca8 100644
--- a/arch/s390/include/asm/ccwdev.h
+++ b/arch/s390/include/asm/ccwdev.h
@@ -92,6 +92,16 @@ struct ccw_device {
};
/*
+ * Possible events used by the path_event notifier.
+ */
+#define PE_NONE 0x0
+#define PE_PATH_GONE 0x1 /* A path is no longer available. */
+#define PE_PATH_AVAILABLE 0x2 /* A path has become available and
+ was successfully verified. */
+#define PE_PATHGROUP_ESTABLISHED 0x4 /* A pathgroup was reset and had
+ to be established again. */
+
+/*
* Possible CIO actions triggered by the unit check handler.
*/
enum uc_todo {
@@ -109,6 +119,7 @@ enum uc_todo {
* @set_online: called when setting device online
* @set_offline: called when setting device offline
* @notify: notify driver of device state changes
+ * @path_event: notify driver of channel path events
* @shutdown: called at device shutdown
* @prepare: prepare for pm state transition
* @complete: undo work done in @prepare
@@ -127,6 +138,7 @@ struct ccw_driver {
int (*set_online) (struct ccw_device *);
int (*set_offline) (struct ccw_device *);
int (*notify) (struct ccw_device *, int);
+ void (*path_event) (struct ccw_device *, int *);
void (*shutdown) (struct ccw_device *);
int (*prepare) (struct ccw_device *);
void (*complete) (struct ccw_device *);
diff --git a/arch/s390/include/asm/cpu.h b/arch/s390/include/asm/cpu.h
index 471234b90574..e0b69540216f 100644
--- a/arch/s390/include/asm/cpu.h
+++ b/arch/s390/include/asm/cpu.h
@@ -20,7 +20,7 @@ struct cpuid
unsigned int ident : 24;
unsigned int machine : 16;
unsigned int unused : 16;
-} __packed;
+} __attribute__ ((packed, aligned(8)));
#endif /* __ASSEMBLY__ */
#endif /* _ASM_S390_CPU_H */
diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h
index 8b1a52a137c5..40e2ab0fa3f0 100644
--- a/arch/s390/include/asm/cputime.h
+++ b/arch/s390/include/asm/cputime.h
@@ -73,18 +73,18 @@ cputime64_to_jiffies64(cputime64_t cputime)
}
/*
- * Convert cputime to milliseconds and back.
+ * Convert cputime to microseconds and back.
*/
static inline unsigned int
-cputime_to_msecs(const cputime_t cputime)
+cputime_to_usecs(const cputime_t cputime)
{
- return cputime_div(cputime, 4096000);
+ return cputime_div(cputime, 4096);
}
static inline cputime_t
-msecs_to_cputime(const unsigned int m)
+usecs_to_cputime(const unsigned int m)
{
- return (cputime_t) m * 4096000;
+ return (cputime_t) m * 4096;
}
/*
diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h
index bb8343d157bc..b56403c2df28 100644
--- a/arch/s390/include/asm/hugetlb.h
+++ b/arch/s390/include/asm/hugetlb.h
@@ -37,32 +37,6 @@ static inline int prepare_hugepage_range(struct file *file,
int arch_prepare_hugepage(struct page *page);
void arch_release_hugepage(struct page *page);
-static inline pte_t pte_mkhuge(pte_t pte)
-{
- /*
- * PROT_NONE needs to be remapped from the pte type to the ste type.
- * The HW invalid bit is also different for pte and ste. The pte
- * invalid bit happens to be the same as the ste _SEGMENT_ENTRY_LARGE
- * bit, so we don't have to clear it.
- */
- if (pte_val(pte) & _PAGE_INVALID) {
- if (pte_val(pte) & _PAGE_SWT)
- pte_val(pte) |= _HPAGE_TYPE_NONE;
- pte_val(pte) |= _SEGMENT_ENTRY_INV;
- }
- /*
- * Clear SW pte bits SWT and SWX, there are no SW bits in a segment
- * table entry.
- */
- pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX);
- /*
- * Also set the change-override bit because we don't need dirty bit
- * tracking for hugetlbfs pages.
- */
- pte_val(pte) |= (_SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_CO);
- return pte;
-}
-
static inline pte_t huge_pte_wrprotect(pte_t pte)
{
pte_val(pte) |= _PAGE_RO;
diff --git a/arch/s390/include/asm/kvm_virtio.h b/arch/s390/include/asm/kvm_virtio.h
index acdfdff26611..72f614181eff 100644
--- a/arch/s390/include/asm/kvm_virtio.h
+++ b/arch/s390/include/asm/kvm_virtio.h
@@ -54,4 +54,11 @@ struct kvm_vqconfig {
* This is pagesize for historical reasons. */
#define KVM_S390_VIRTIO_RING_ALIGN 4096
+
+/* These values are supposed to be in ext_params on an interrupt */
+#define VIRTIO_PARAM_MASK 0xff
+#define VIRTIO_PARAM_VRING_INTERRUPT 0x0
+#define VIRTIO_PARAM_CONFIG_CHANGED 0x1
+#define VIRTIO_PARAM_DEV_ADD 0x2
+
#endif
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h
index 0f97ef2d92ac..65e172f8209d 100644
--- a/arch/s390/include/asm/lowcore.h
+++ b/arch/s390/include/asm/lowcore.h
@@ -150,9 +150,10 @@ struct _lowcore {
*/
__u32 ipib; /* 0x0e00 */
__u32 ipib_checksum; /* 0x0e04 */
+ __u8 pad_0x0e08[0x0f00-0x0e08]; /* 0x0e08 */
- /* Align to the top 1k of prefix area */
- __u8 pad_0x0e08[0x1000-0x0e08]; /* 0x0e08 */
+ /* Extended facility list */
+ __u64 stfle_fac_list[32]; /* 0x0f00 */
} __packed;
#else /* CONFIG_32BIT */
@@ -285,7 +286,11 @@ struct _lowcore {
*/
__u64 ipib; /* 0x0e00 */
__u32 ipib_checksum; /* 0x0e08 */
- __u8 pad_0x0e0c[0x11b8-0x0e0c]; /* 0x0e0c */
+ __u8 pad_0x0e0c[0x0f00-0x0e0c]; /* 0x0e0c */
+
+ /* Extended facility list */
+ __u64 stfle_fac_list[32]; /* 0x0f00 */
+ __u8 pad_0x1000[0x11b8-0x1000]; /* 0x1000 */
/* 64 bit extparam used for pfault/diag 250: defined by architecture */
__u64 ext_params2; /* 0x11B8 */
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index af650fb47206..a8729ea7e9ac 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -108,9 +108,13 @@ typedef pte_t *pgtable_t;
#define __pgprot(x) ((pgprot_t) { (x) } )
static inline void
-page_set_storage_key(unsigned long addr, unsigned int skey)
+page_set_storage_key(unsigned long addr, unsigned int skey, int mapped)
{
- asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
+ if (!mapped)
+ asm volatile(".insn rrf,0xb22b0000,%0,%1,8,0"
+ : : "d" (skey), "a" (addr));
+ else
+ asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
}
static inline unsigned int
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h
index 68940d0bad91..082eb4e50e8b 100644
--- a/arch/s390/include/asm/pgalloc.h
+++ b/arch/s390/include/asm/pgalloc.h
@@ -21,9 +21,11 @@
unsigned long *crst_table_alloc(struct mm_struct *, int);
void crst_table_free(struct mm_struct *, unsigned long *);
+void crst_table_free_rcu(struct mm_struct *, unsigned long *);
unsigned long *page_table_alloc(struct mm_struct *);
void page_table_free(struct mm_struct *, unsigned long *);
+void page_table_free_rcu(struct mm_struct *, unsigned long *);
void disable_noexec(struct mm_struct *, struct task_struct *);
static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
@@ -176,4 +178,6 @@ static inline void pmd_populate(struct mm_struct *mm,
#define pte_free_kernel(mm, pte) page_table_free(mm, (unsigned long *) pte)
#define pte_free(mm, pte) page_table_free(mm, (unsigned long *) pte)
+extern void rcu_table_freelist_finish(void);
+
#endif /* _S390_PGALLOC_H */
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 3157441ee1da..02ace3491c51 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -38,6 +38,7 @@
extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
extern void paging_init(void);
extern void vmem_map_init(void);
+extern void fault_init(void);
/*
* The S390 doesn't have any external MMU info: the kernel page
@@ -46,11 +47,27 @@ extern void vmem_map_init(void);
#define update_mmu_cache(vma, address, ptep) do { } while (0)
/*
- * ZERO_PAGE is a global shared page that is always zero: used
+ * ZERO_PAGE is a global shared page that is always zero; used
* for zero-mapped memory areas etc..
*/
-extern char empty_zero_page[PAGE_SIZE];
-#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+extern unsigned long empty_zero_page;
+extern unsigned long zero_page_mask;
+
+#define ZERO_PAGE(vaddr) \
+ (virt_to_page((void *)(empty_zero_page + \
+ (((unsigned long)(vaddr)) &zero_page_mask))))
+
+#define is_zero_pfn is_zero_pfn
+static inline int is_zero_pfn(unsigned long pfn)
+{
+ extern unsigned long zero_pfn;
+ unsigned long offset_from_zero_pfn = pfn - zero_pfn;
+ return offset_from_zero_pfn <= (zero_page_mask >> PAGE_SHIFT);
+}
+
+#define my_zero_pfn(addr) page_to_pfn(ZERO_PAGE(addr))
+
#endif /* !__ASSEMBLY__ */
/*
@@ -300,6 +317,7 @@ extern unsigned long VMALLOC_START;
/* Bits in the segment table entry */
#define _SEGMENT_ENTRY_ORIGIN 0x7fffffc0UL /* page table origin */
+#define _SEGMENT_ENTRY_RO 0x200 /* page protection bit */
#define _SEGMENT_ENTRY_INV 0x20 /* invalid segment table entry */
#define _SEGMENT_ENTRY_COMMON 0x10 /* common segment bit */
#define _SEGMENT_ENTRY_PTL 0x0f /* page table length */
@@ -572,7 +590,7 @@ static inline void rcp_unlock(pte_t *ptep)
}
/* forward declaration for SetPageUptodate in page-flags.h*/
-static inline void page_clear_dirty(struct page *page);
+static inline void page_clear_dirty(struct page *page, int mapped);
#include <linux/page-flags.h>
static inline void ptep_rcp_copy(pte_t *ptep)
@@ -754,6 +772,34 @@ static inline pte_t pte_mkspecial(pte_t pte)
return pte;
}
+#ifdef CONFIG_HUGETLB_PAGE
+static inline pte_t pte_mkhuge(pte_t pte)
+{
+ /*
+ * PROT_NONE needs to be remapped from the pte type to the ste type.
+ * The HW invalid bit is also different for pte and ste. The pte
+ * invalid bit happens to be the same as the ste _SEGMENT_ENTRY_LARGE
+ * bit, so we don't have to clear it.
+ */
+ if (pte_val(pte) & _PAGE_INVALID) {
+ if (pte_val(pte) & _PAGE_SWT)
+ pte_val(pte) |= _HPAGE_TYPE_NONE;
+ pte_val(pte) |= _SEGMENT_ENTRY_INV;
+ }
+ /*
+ * Clear SW pte bits SWT and SWX, there are no SW bits in a segment
+ * table entry.
+ */
+ pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX);
+ /*
+ * Also set the change-override bit because we don't need dirty bit
+ * tracking for hugetlbfs pages.
+ */
+ pte_val(pte) |= (_SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_CO);
+ return pte;
+}
+#endif
+
#ifdef CONFIG_PGSTE
/*
* Get (and clear) the user dirty bit for a PTE.
@@ -782,7 +828,7 @@ static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm,
}
dirty = test_and_clear_bit_simple(KVM_UD_BIT, pgste);
if (skey & _PAGE_CHANGED)
- page_clear_dirty(page);
+ page_clear_dirty(page, 1);
rcp_unlock(ptep);
return dirty;
}
@@ -957,9 +1003,9 @@ static inline int page_test_dirty(struct page *page)
}
#define __HAVE_ARCH_PAGE_CLEAR_DIRTY
-static inline void page_clear_dirty(struct page *page)
+static inline void page_clear_dirty(struct page *page, int mapped)
{
- page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY);
+ page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY, mapped);
}
/*
@@ -1048,9 +1094,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
#define pte_offset(pmd, addr) ((pte_t *) pmd_deref(*(pmd)) + pte_index(addr))
#define pte_offset_kernel(pmd, address) pte_offset(pmd,address)
#define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
-#define pte_offset_map_nested(pmd, address) pte_offset_kernel(pmd, address)
#define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
/*
* 31 bit swap entry format:
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index 73e259834e10..8d6f87169577 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -82,8 +82,6 @@ struct thread_struct {
unsigned long prot_addr; /* address of protection-excep. */
unsigned int trap_no;
per_struct per_info;
- /* Used to give failing instruction back to user for ieee exceptions */
- unsigned long ieee_instruction_pointer;
/* pfault_wait is used to block the process on a pfault event */
unsigned long pfault_wait;
};
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index e2c218dc68a6..d9d42b1e46fa 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -481,8 +481,7 @@ struct user_regs_struct
* watchpoints. This is the way intel does it.
*/
per_struct per_info;
- unsigned long ieee_instruction_pointer;
- /* Used to give failing instruction back to user for ieee exceptions */
+ unsigned long ieee_instruction_pointer; /* obsolete, always 0 */
};
#ifdef __KERNEL__
diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h
index 2ba630276295..46e96bc1f5a1 100644
--- a/arch/s390/include/asm/qdio.h
+++ b/arch/s390/include/asm/qdio.h
@@ -360,6 +360,7 @@ 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);
unsigned long int_parm;
void **input_sbal_addr_array;
void **output_sbal_addr_array;
@@ -377,11 +378,13 @@ 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 int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
- int q_nr, unsigned int bufnr, unsigned int count);
-extern int qdio_shutdown(struct ccw_device*, int);
+extern int do_QDIO(struct ccw_device *, unsigned int, int, unsigned int,
+ unsigned int);
+extern int qdio_start_irq(struct ccw_device *, int);
+extern int qdio_stop_irq(struct ccw_device *, int);
+extern int qdio_get_next_buffers(struct ccw_device *, int, int *, int *);
+extern int qdio_shutdown(struct ccw_device *, int);
extern int qdio_free(struct ccw_device *);
-extern int qdio_get_ssqd_desc(struct ccw_device *dev, struct qdio_ssqd_desc*);
+extern int qdio_get_ssqd_desc(struct ccw_device *, struct qdio_ssqd_desc *);
#endif /* __QDIO_H__ */
diff --git a/arch/s390/include/asm/s390_ext.h b/arch/s390/include/asm/s390_ext.h
index 2afc060266a2..1a9307e70842 100644
--- a/arch/s390/include/asm/s390_ext.h
+++ b/arch/s390/include/asm/s390_ext.h
@@ -12,7 +12,7 @@
#include <linux/types.h>
-typedef void (*ext_int_handler_t)(__u16 code);
+typedef void (*ext_int_handler_t)(unsigned int, unsigned int, unsigned long);
typedef struct ext_int_info_t {
struct ext_int_info_t *next;
diff --git a/arch/s390/include/asm/scatterlist.h b/arch/s390/include/asm/scatterlist.h
index 35d786fe93ae..6d45ef6c12a7 100644
--- a/arch/s390/include/asm/scatterlist.h
+++ b/arch/s390/include/asm/scatterlist.h
@@ -1 +1,3 @@
#include <asm-generic/scatterlist.h>
+
+#define ARCH_HAS_SG_CHAIN
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index 25e831d58e1e..d5e2ef10537d 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -73,6 +73,7 @@ extern unsigned int user_mode;
#define MACHINE_FLAG_PFMF (1UL << 11)
#define MACHINE_FLAG_LPAR (1UL << 12)
#define MACHINE_FLAG_SPP (1UL << 13)
+#define MACHINE_FLAG_TOPOLOGY (1UL << 14)
#define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM)
#define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM)
@@ -90,6 +91,7 @@ extern unsigned int user_mode;
#define MACHINE_HAS_HPAGE (0)
#define MACHINE_HAS_PFMF (0)
#define MACHINE_HAS_SPP (0)
+#define MACHINE_HAS_TOPOLOGY (0)
#else /* __s390x__ */
#define MACHINE_HAS_IEEE (1)
#define MACHINE_HAS_CSP (1)
@@ -100,6 +102,7 @@ extern unsigned int user_mode;
#define MACHINE_HAS_HPAGE (S390_lowcore.machine_flags & MACHINE_FLAG_HPAGE)
#define MACHINE_HAS_PFMF (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF)
#define MACHINE_HAS_SPP (S390_lowcore.machine_flags & MACHINE_FLAG_SPP)
+#define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY)
#endif /* __s390x__ */
#define ZFCPDUMP_HSA_SIZE (32UL<<20)
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
index 8429686951f9..5c0246b955d8 100644
--- a/arch/s390/include/asm/syscall.h
+++ b/arch/s390/include/asm/syscall.h
@@ -65,8 +65,6 @@ static inline void syscall_get_arguments(struct task_struct *task,
if (test_tsk_thread_flag(task, TIF_31BIT))
mask = 0xffffffff;
#endif
- if (i + n == 6)
- args[--n] = regs->args[0] & mask;
while (n-- > 0)
if (i + n > 0)
args[n] = regs->gprs[2 + i + n] & mask;
@@ -80,8 +78,6 @@ static inline void syscall_set_arguments(struct task_struct *task,
const unsigned long *args)
{
BUG_ON(i + n > 6);
- if (i + n == 6)
- regs->args[0] = args[--n];
while (n-- > 0)
if (i + n > 0)
regs->gprs[2 + i + n] = args[n];
diff --git a/arch/s390/include/asm/sysinfo.h b/arch/s390/include/asm/sysinfo.h
index 22bdb2a0ee5f..79d3d6e2e9c5 100644
--- a/arch/s390/include/asm/sysinfo.h
+++ b/arch/s390/include/asm/sysinfo.h
@@ -14,8 +14,13 @@
#ifndef __ASM_S390_SYSINFO_H
#define __ASM_S390_SYSINFO_H
+#include <asm/bitsperlong.h>
+
struct sysinfo_1_1_1 {
- char reserved_0[32];
+ unsigned short :16;
+ unsigned char ccr;
+ unsigned char cai;
+ char reserved_0[28];
char manufacturer[16];
char type[4];
char reserved_1[12];
@@ -104,6 +109,39 @@ struct sysinfo_3_2_2 {
char reserved_544[3552];
};
+#define TOPOLOGY_CPU_BITS 64
+#define TOPOLOGY_NR_MAG 6
+
+struct topology_cpu {
+ unsigned char reserved0[4];
+ unsigned char :6;
+ unsigned char pp:2;
+ unsigned char reserved1;
+ unsigned short origin;
+ unsigned long mask[TOPOLOGY_CPU_BITS / BITS_PER_LONG];
+};
+
+struct topology_container {
+ unsigned char reserved[7];
+ unsigned char id;
+};
+
+union topology_entry {
+ unsigned char nl;
+ struct topology_cpu cpu;
+ struct topology_container container;
+};
+
+struct sysinfo_15_1_x {
+ unsigned char reserved0[2];
+ unsigned short length;
+ unsigned char mag[TOPOLOGY_NR_MAG];
+ unsigned char reserved1;
+ unsigned char mnest;
+ unsigned char reserved2[4];
+ union topology_entry tle[0];
+};
+
static inline int stsi(void *sysinfo, int fc, int sel1, int sel2)
{
register int r0 asm("0") = (fc << 28) | sel1;
diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h
index 1f2ebc4afd82..3ad16dbf622e 100644
--- a/arch/s390/include/asm/system.h
+++ b/arch/s390/include/asm/system.h
@@ -85,14 +85,16 @@ static inline void restore_access_regs(unsigned int *acrs)
asm volatile("lam 0,15,%0" : : "Q" (*acrs));
}
-#define switch_to(prev,next,last) do { \
- if (prev == next) \
- break; \
- save_fp_regs(&prev->thread.fp_regs); \
- restore_fp_regs(&next->thread.fp_regs); \
- save_access_regs(&prev->thread.acrs[0]); \
- restore_access_regs(&next->thread.acrs[0]); \
- prev = __switch_to(prev,next); \
+#define switch_to(prev,next,last) do { \
+ if (prev->mm) { \
+ save_fp_regs(&prev->thread.fp_regs); \
+ save_access_regs(&prev->thread.acrs[0]); \
+ } \
+ if (next->mm) { \
+ restore_fp_regs(&next->thread.fp_regs); \
+ restore_access_regs(&next->thread.acrs[0]); \
+ } \
+ prev = __switch_to(prev,next); \
} while (0)
extern void account_vtime(struct task_struct *, struct task_struct *);
@@ -418,30 +420,21 @@ extern void smp_ctl_clear_bit(int cr, int bit);
#endif /* CONFIG_SMP */
-static inline unsigned int stfl(void)
-{
- asm volatile(
- " .insn s,0xb2b10000,0(0)\n" /* stfl */
- "0:\n"
- EX_TABLE(0b,0b));
- return S390_lowcore.stfl_fac_list;
-}
+#define MAX_FACILITY_BIT (256*8) /* stfle_fac_list has 256 bytes */
-static inline int __stfle(unsigned long long *list, int doublewords)
+/*
+ * The test_facility function uses the bit odering where the MSB is bit 0.
+ * That makes it easier to query facility bits with the bit number as
+ * documented in the Principles of Operation.
+ */
+static inline int test_facility(unsigned long nr)
{
- typedef struct { unsigned long long _[doublewords]; } addrtype;
- register unsigned long __nr asm("0") = doublewords - 1;
-
- asm volatile(".insn s,0xb2b00000,%0" /* stfle */
- : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc");
- return __nr + 1;
-}
+ unsigned char *ptr;
-static inline int stfle(unsigned long long *list, int doublewords)
-{
- if (!(stfl() & (1UL << 24)))
- return -EOPNOTSUPP;
- return __stfle(list, doublewords);
+ if (nr >= MAX_FACILITY_BIT)
+ return 0;
+ ptr = (unsigned char *) &S390_lowcore.stfle_fac_list + (nr >> 3);
+ return (*ptr & (0x80 >> (nr & 7))) != 0;
}
static inline unsigned short stap(void)
diff --git a/arch/s390/include/asm/tlb.h b/arch/s390/include/asm/tlb.h
index fd1c00d08bf5..f1f644f2240a 100644
--- a/arch/s390/include/asm/tlb.h
+++ b/arch/s390/include/asm/tlb.h
@@ -64,10 +64,9 @@ static inline void tlb_flush_mmu(struct mmu_gather *tlb,
if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < TLB_NR_PTRS))
__tlb_flush_mm(tlb->mm);
while (tlb->nr_ptes > 0)
- pte_free(tlb->mm, tlb->array[--tlb->nr_ptes]);
+ page_table_free_rcu(tlb->mm, tlb->array[--tlb->nr_ptes]);
while (tlb->nr_pxds < TLB_NR_PTRS)
- /* pgd_free frees the pointer as region or segment table */
- pgd_free(tlb->mm, tlb->array[tlb->nr_pxds++]);
+ crst_table_free_rcu(tlb->mm, tlb->array[tlb->nr_pxds++]);
}
static inline void tlb_finish_mmu(struct mmu_gather *tlb,
@@ -75,6 +74,8 @@ static inline void tlb_finish_mmu(struct mmu_gather *tlb,
{
tlb_flush_mmu(tlb, start, end);
+ rcu_table_freelist_finish();
+
/* keep the page table cache within bounds */
check_pgt_cache();
@@ -103,7 +104,7 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
if (tlb->nr_ptes >= tlb->nr_pxds)
tlb_flush_mmu(tlb, 0, 0);
} else
- pte_free(tlb->mm, pte);
+ page_table_free(tlb->mm, (unsigned long *) pte);
}
/*
@@ -124,7 +125,7 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
if (tlb->nr_ptes >= tlb->nr_pxds)
tlb_flush_mmu(tlb, 0, 0);
} else
- pmd_free(tlb->mm, pmd);
+ crst_table_free(tlb->mm, (unsigned long *) pmd);
#endif
}
@@ -146,7 +147,7 @@ static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
if (tlb->nr_ptes >= tlb->nr_pxds)
tlb_flush_mmu(tlb, 0, 0);
} else
- pud_free(tlb->mm, pud);
+ crst_table_free(tlb->mm, (unsigned long *) pud);
#endif
}
diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h
index 051107a2c5e2..c5338834ddbd 100644
--- a/arch/s390/include/asm/topology.h
+++ b/arch/s390/include/asm/topology.h
@@ -2,6 +2,7 @@
#define _ASM_S390_TOPOLOGY_H
#include <linux/cpumask.h>
+#include <asm/sysinfo.h>
extern unsigned char cpu_core_id[NR_CPUS];
extern cpumask_t cpu_core_map[NR_CPUS];
@@ -32,6 +33,7 @@ static inline const struct cpumask *cpu_book_mask(unsigned int cpu)
int topology_set_cpu_management(int fc);
void topology_schedule_update(void);
+void store_topology(struct sysinfo_15_1_x *info);
#define POLARIZATION_UNKNWN (-1)
#define POLARIZATION_HRZ (0)
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 5232278d79ad..f3c1b823c9a8 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -84,6 +84,7 @@ int main(void)
DEFINE(__LC_SVC_INT_CODE, offsetof(struct _lowcore, svc_code));
DEFINE(__LC_PGM_ILC, offsetof(struct _lowcore, pgm_ilc));
DEFINE(__LC_PGM_INT_CODE, offsetof(struct _lowcore, pgm_code));
+ DEFINE(__LC_TRANS_EXC_CODE, offsetof(struct _lowcore, trans_exc_code));
DEFINE(__LC_PER_ATMID, offsetof(struct _lowcore, per_perc_atmid));
DEFINE(__LC_PER_ADDRESS, offsetof(struct _lowcore, per_address));
DEFINE(__LC_PER_ACCESS_ID, offsetof(struct _lowcore, per_access_id));
@@ -142,10 +143,8 @@ int main(void)
DEFINE(__LC_GPREGS_SAVE_AREA, offsetof(struct _lowcore, gpregs_save_area));
DEFINE(__LC_CREGS_SAVE_AREA, offsetof(struct _lowcore, cregs_save_area));
#ifdef CONFIG_32BIT
- DEFINE(__LC_PFAULT_INTPARM, offsetof(struct _lowcore, ext_params));
DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, extended_save_area_addr));
#else /* CONFIG_32BIT */
- DEFINE(__LC_PFAULT_INTPARM, offsetof(struct _lowcore, ext_params2));
DEFINE(__LC_EXT_PARAMS2, offsetof(struct _lowcore, ext_params2));
DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, floating_pt_save_area));
DEFINE(__LC_PASTE, offsetof(struct _lowcore, paste));
diff --git a/arch/s390/kernel/compat_ptrace.h b/arch/s390/kernel/compat_ptrace.h
index 123dd660d7fb..3141025724f4 100644
--- a/arch/s390/kernel/compat_ptrace.h
+++ b/arch/s390/kernel/compat_ptrace.h
@@ -51,8 +51,7 @@ struct user_regs_struct32
* watchpoints. This is the way intel does it.
*/
per_struct32 per_info;
- u32 ieee_instruction_pointer;
- /* Used to give failing instruction back to user for ieee exceptions */
+ u32 ieee_instruction_pointer; /* obsolete, always 0 */
};
struct user32 {
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index b39b27d68b45..c83726c9fe03 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -113,7 +113,7 @@ enum {
INSTR_INVALID,
INSTR_E,
INSTR_RIE_R0IU, INSTR_RIE_R0UU, INSTR_RIE_RRP, INSTR_RIE_RRPU,
- INSTR_RIE_RRUUU, INSTR_RIE_RUPI, INSTR_RIE_RUPU,
+ INSTR_RIE_RRUUU, INSTR_RIE_RUPI, INSTR_RIE_RUPU, INSTR_RIE_RRI0,
INSTR_RIL_RI, INSTR_RIL_RP, INSTR_RIL_RU, INSTR_RIL_UP,
INSTR_RIS_R0RDU, INSTR_RIS_R0UU, INSTR_RIS_RURDI, INSTR_RIS_RURDU,
INSTR_RI_RI, INSTR_RI_RP, INSTR_RI_RU, INSTR_RI_UP,
@@ -122,13 +122,14 @@ enum {
INSTR_RRE_RR, INSTR_RRE_RR_OPT,
INSTR_RRF_0UFF, INSTR_RRF_F0FF, INSTR_RRF_F0FF2, INSTR_RRF_F0FR,
INSTR_RRF_FFRU, INSTR_RRF_FUFF, INSTR_RRF_M0RR, INSTR_RRF_R0RR,
- INSTR_RRF_RURR, INSTR_RRF_U0FF, INSTR_RRF_U0RF, INSTR_RRF_U0RR,
- INSTR_RRF_UUFF, INSTR_RRR_F0FF, INSTR_RRS_RRRDU,
+ INSTR_RRF_R0RR2, INSTR_RRF_RURR, INSTR_RRF_U0FF, INSTR_RRF_U0RF,
+ INSTR_RRF_U0RR, INSTR_RRF_UUFF, INSTR_RRR_F0FF, INSTR_RRS_RRRDU,
INSTR_RR_FF, INSTR_RR_R0, INSTR_RR_RR, INSTR_RR_U0, INSTR_RR_UR,
INSTR_RSE_CCRD, INSTR_RSE_RRRD, INSTR_RSE_RURD,
INSTR_RSI_RRP,
INSTR_RSL_R0RD,
INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD, INSTR_RSY_RURD,
+ INSTR_RSY_RDRM,
INSTR_RS_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD, INSTR_RS_RRRD,
INSTR_RS_RURD,
INSTR_RXE_FRRD, INSTR_RXE_RRRD,
@@ -139,7 +140,7 @@ enum {
INSTR_SIY_IRD, INSTR_SIY_URD,
INSTR_SI_URD,
INSTR_SSE_RDRD,
- INSTR_SSF_RRDRD,
+ INSTR_SSF_RRDRD, INSTR_SSF_RRDRD2,
INSTR_SS_L0RDRD, INSTR_SS_LIRDRD, INSTR_SS_LLRDRD, INSTR_SS_RRRDRD,
INSTR_SS_RRRDRD2, INSTR_SS_RRRDRD3,
INSTR_S_00, INSTR_S_RD,
@@ -152,7 +153,7 @@ struct operand {
};
struct insn {
- const char name[6];
+ const char name[5];
unsigned char opfrag;
unsigned char format;
};
@@ -217,6 +218,7 @@ static const unsigned char formats[][7] = {
[INSTR_RIE_RRP] = { 0xff, R_8,R_12,J16_16,0,0,0 },
[INSTR_RIE_RRUUU] = { 0xff, R_8,R_12,U8_16,U8_24,U8_32,0 },
[INSTR_RIE_RUPI] = { 0xff, R_8,I8_32,U4_12,J16_16,0,0 },
+ [INSTR_RIE_RRI0] = { 0xff, R_8,R_12,I16_16,0,0,0 },
[INSTR_RIL_RI] = { 0x0f, R_8,I32_16,0,0,0,0 },
[INSTR_RIL_RP] = { 0x0f, R_8,J32_16,0,0,0,0 },
[INSTR_RIL_RU] = { 0x0f, R_8,U32_16,0,0,0,0 },
@@ -248,6 +250,7 @@ static const unsigned char formats[][7] = {
[INSTR_RRF_FUFF] = { 0xff, F_24,F_16,F_28,U4_20,0,0 },
[INSTR_RRF_M0RR] = { 0xff, R_24,R_28,M_16,0,0,0 },
[INSTR_RRF_R0RR] = { 0xff, R_24,R_16,R_28,0,0,0 },
+ [INSTR_RRF_R0RR2] = { 0xff, R_24,R_28,R_16,0,0,0 },
[INSTR_RRF_RURR] = { 0xff, R_24,R_28,R_16,U4_20,0,0 },
[INSTR_RRF_U0FF] = { 0xff, F_24,U4_16,F_28,0,0,0 },
[INSTR_RRF_U0RF] = { 0xff, R_24,U4_16,F_28,0,0,0 },
@@ -269,6 +272,7 @@ static const unsigned char formats[][7] = {
[INSTR_RSY_CCRD] = { 0xff, C_8,C_12,D20_20,B_16,0,0 },
[INSTR_RSY_RRRD] = { 0xff, R_8,R_12,D20_20,B_16,0,0 },
[INSTR_RSY_RURD] = { 0xff, R_8,U4_12,D20_20,B_16,0,0 },
+ [INSTR_RSY_RDRM] = { 0xff, R_8,D20_20,B_16,U4_12,0,0 },
[INSTR_RS_AARD] = { 0xff, A_8,A_12,D_20,B_16,0,0 },
[INSTR_RS_CCRD] = { 0xff, C_8,C_12,D_20,B_16,0,0 },
[INSTR_RS_R0RD] = { 0xff, R_8,D_20,B_16,0,0,0 },
@@ -290,6 +294,7 @@ static const unsigned char formats[][7] = {
[INSTR_SI_URD] = { 0xff, D_20,B_16,U8_8,0,0,0 },
[INSTR_SSE_RDRD] = { 0xff, D_20,B_16,D_36,B_32,0,0 },
[INSTR_SSF_RRDRD] = { 0x00, D_20,B_16,D_36,B_32,R_8,0 },
+ [INSTR_SSF_RRDRD2]= { 0x00, R_8,D_20,B_16,D_36,B_32,0 },
[INSTR_SS_L0RDRD] = { 0xff, D_20,L8_8,B_16,D_36,B_32,0 },
[INSTR_SS_LIRDRD] = { 0xff, D_20,L4_8,B_16,D_36,B_32,U4_12 },
[INSTR_SS_LLRDRD] = { 0xff, D_20,L4_8,B_16,D_36,L4_12,B_32 },
@@ -300,6 +305,36 @@ static const unsigned char formats[][7] = {
[INSTR_S_RD] = { 0xff, D_20,B_16,0,0,0,0 },
};
+enum {
+ LONG_INSN_ALGHSIK,
+ LONG_INSN_ALHSIK,
+ LONG_INSN_CLFHSI,
+ LONG_INSN_CLGFRL,
+ LONG_INSN_CLGHRL,
+ LONG_INSN_CLGHSI,
+ LONG_INSN_CLHHSI,
+ LONG_INSN_LLGFRL,
+ LONG_INSN_LLGHRL,
+ LONG_INSN_POPCNT,
+ LONG_INSN_RISBHG,
+ LONG_INSN_RISBLG,
+};
+
+static char *long_insn_name[] = {
+ [LONG_INSN_ALGHSIK] = "alghsik",
+ [LONG_INSN_ALHSIK] = "alhsik",
+ [LONG_INSN_CLFHSI] = "clfhsi",
+ [LONG_INSN_CLGFRL] = "clgfrl",
+ [LONG_INSN_CLGHRL] = "clghrl",
+ [LONG_INSN_CLGHSI] = "clghsi",
+ [LONG_INSN_CLHHSI] = "clhhsi",
+ [LONG_INSN_LLGFRL] = "llgfrl",
+ [LONG_INSN_LLGHRL] = "llghrl",
+ [LONG_INSN_POPCNT] = "popcnt",
+ [LONG_INSN_RISBHG] = "risbhg",
+ [LONG_INSN_RISBLG] = "risblk",
+};
+
static struct insn opcode[] = {
#ifdef CONFIG_64BIT
{ "lmd", 0xef, INSTR_SS_RRRDRD3 },
@@ -881,6 +916,35 @@ static struct insn opcode_b9[] = {
{ "pfmf", 0xaf, INSTR_RRE_RR },
{ "trte", 0xbf, INSTR_RRF_M0RR },
{ "trtre", 0xbd, INSTR_RRF_M0RR },
+ { "ahhhr", 0xc8, INSTR_RRF_R0RR2 },
+ { "shhhr", 0xc9, INSTR_RRF_R0RR2 },
+ { "alhhh", 0xca, INSTR_RRF_R0RR2 },
+ { "alhhl", 0xca, INSTR_RRF_R0RR2 },
+ { "slhhh", 0xcb, INSTR_RRF_R0RR2 },
+ { "chhr ", 0xcd, INSTR_RRE_RR },
+ { "clhhr", 0xcf, INSTR_RRE_RR },
+ { "ahhlr", 0xd8, INSTR_RRF_R0RR2 },
+ { "shhlr", 0xd9, INSTR_RRF_R0RR2 },
+ { "slhhl", 0xdb, INSTR_RRF_R0RR2 },
+ { "chlr", 0xdd, INSTR_RRE_RR },
+ { "clhlr", 0xdf, INSTR_RRE_RR },
+ { { 0, LONG_INSN_POPCNT }, 0xe1, INSTR_RRE_RR },
+ { "locgr", 0xe2, INSTR_RRF_M0RR },
+ { "ngrk", 0xe4, INSTR_RRF_R0RR2 },
+ { "ogrk", 0xe6, INSTR_RRF_R0RR2 },
+ { "xgrk", 0xe7, INSTR_RRF_R0RR2 },
+ { "agrk", 0xe8, INSTR_RRF_R0RR2 },
+ { "sgrk", 0xe9, INSTR_RRF_R0RR2 },
+ { "algrk", 0xea, INSTR_RRF_R0RR2 },
+ { "slgrk", 0xeb, INSTR_RRF_R0RR2 },
+ { "locr", 0xf2, INSTR_RRF_M0RR },
+ { "nrk", 0xf4, INSTR_RRF_R0RR2 },
+ { "ork", 0xf6, INSTR_RRF_R0RR2 },
+ { "xrk", 0xf7, INSTR_RRF_R0RR2 },
+ { "ark", 0xf8, INSTR_RRF_R0RR2 },
+ { "srk", 0xf9, INSTR_RRF_R0RR2 },
+ { "alrk", 0xfa, INSTR_RRF_R0RR2 },
+ { "slrk", 0xfb, INSTR_RRF_R0RR2 },
#endif
{ "kmac", 0x1e, INSTR_RRE_RR },
{ "lrvr", 0x1f, INSTR_RRE_RR },
@@ -949,9 +1013,9 @@ static struct insn opcode_c4[] = {
{ "lgfrl", 0x0c, INSTR_RIL_RP },
{ "lhrl", 0x05, INSTR_RIL_RP },
{ "lghrl", 0x04, INSTR_RIL_RP },
- { "llgfrl", 0x0e, INSTR_RIL_RP },
+ { { 0, LONG_INSN_LLGFRL }, 0x0e, INSTR_RIL_RP },
{ "llhrl", 0x02, INSTR_RIL_RP },
- { "llghrl", 0x06, INSTR_RIL_RP },
+ { { 0, LONG_INSN_LLGHRL }, 0x06, INSTR_RIL_RP },
{ "strl", 0x0f, INSTR_RIL_RP },
{ "stgrl", 0x0b, INSTR_RIL_RP },
{ "sthrl", 0x07, INSTR_RIL_RP },
@@ -968,9 +1032,9 @@ static struct insn opcode_c6[] = {
{ "cghrl", 0x04, INSTR_RIL_RP },
{ "clrl", 0x0f, INSTR_RIL_RP },
{ "clgrl", 0x0a, INSTR_RIL_RP },
- { "clgfrl", 0x0e, INSTR_RIL_RP },
+ { { 0, LONG_INSN_CLGFRL }, 0x0e, INSTR_RIL_RP },
{ "clhrl", 0x07, INSTR_RIL_RP },
- { "clghrl", 0x06, INSTR_RIL_RP },
+ { { 0, LONG_INSN_CLGHRL }, 0x06, INSTR_RIL_RP },
{ "pfdrl", 0x02, INSTR_RIL_UP },
{ "exrl", 0x00, INSTR_RIL_RP },
#endif
@@ -982,6 +1046,20 @@ static struct insn opcode_c8[] = {
{ "mvcos", 0x00, INSTR_SSF_RRDRD },
{ "ectg", 0x01, INSTR_SSF_RRDRD },
{ "csst", 0x02, INSTR_SSF_RRDRD },
+ { "lpd", 0x04, INSTR_SSF_RRDRD2 },
+ { "lpdg ", 0x05, INSTR_SSF_RRDRD2 },
+#endif
+ { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_cc[] = {
+#ifdef CONFIG_64BIT
+ { "brcth", 0x06, INSTR_RIL_RP },
+ { "aih", 0x08, INSTR_RIL_RI },
+ { "alsih", 0x0a, INSTR_RIL_RI },
+ { "alsih", 0x0b, INSTR_RIL_RI },
+ { "cih", 0x0d, INSTR_RIL_RI },
+ { "clih ", 0x0f, INSTR_RIL_RI },
#endif
{ "", 0, INSTR_INVALID }
};
@@ -1063,6 +1141,16 @@ static struct insn opcode_e3[] = {
{ "mfy", 0x5c, INSTR_RXY_RRRD },
{ "mhy", 0x7c, INSTR_RXY_RRRD },
{ "pfd", 0x36, INSTR_RXY_URRD },
+ { "lbh", 0xc0, INSTR_RXY_RRRD },
+ { "llch", 0xc2, INSTR_RXY_RRRD },
+ { "stch", 0xc3, INSTR_RXY_RRRD },
+ { "lhh", 0xc4, INSTR_RXY_RRRD },
+ { "llhh", 0xc6, INSTR_RXY_RRRD },
+ { "sthh", 0xc7, INSTR_RXY_RRRD },
+ { "lfh", 0xca, INSTR_RXY_RRRD },
+ { "stfh", 0xcb, INSTR_RXY_RRRD },
+ { "chf", 0xcd, INSTR_RXY_RRRD },
+ { "clhf", 0xcf, INSTR_RXY_RRRD },
#endif
{ "lrv", 0x1e, INSTR_RXY_RRRD },
{ "lrvh", 0x1f, INSTR_RXY_RRRD },
@@ -1080,9 +1168,9 @@ static struct insn opcode_e5[] = {
{ "chhsi", 0x54, INSTR_SIL_RDI },
{ "chsi", 0x5c, INSTR_SIL_RDI },
{ "cghsi", 0x58, INSTR_SIL_RDI },
- { "clhhsi", 0x55, INSTR_SIL_RDU },
- { "clfhsi", 0x5d, INSTR_SIL_RDU },
- { "clghsi", 0x59, INSTR_SIL_RDU },
+ { { 0, LONG_INSN_CLHHSI }, 0x55, INSTR_SIL_RDU },
+ { { 0, LONG_INSN_CLFHSI }, 0x5d, INSTR_SIL_RDU },
+ { { 0, LONG_INSN_CLGHSI }, 0x59, INSTR_SIL_RDU },
{ "mvhhi", 0x44, INSTR_SIL_RDI },
{ "mvhi", 0x4c, INSTR_SIL_RDI },
{ "mvghi", 0x48, INSTR_SIL_RDI },
@@ -1137,6 +1225,24 @@ static struct insn opcode_eb[] = {
{ "alsi", 0x6e, INSTR_SIY_IRD },
{ "algsi", 0x7e, INSTR_SIY_IRD },
{ "ecag", 0x4c, INSTR_RSY_RRRD },
+ { "srak", 0xdc, INSTR_RSY_RRRD },
+ { "slak", 0xdd, INSTR_RSY_RRRD },
+ { "srlk", 0xde, INSTR_RSY_RRRD },
+ { "sllk", 0xdf, INSTR_RSY_RRRD },
+ { "locg", 0xe2, INSTR_RSY_RDRM },
+ { "stocg", 0xe3, INSTR_RSY_RDRM },
+ { "lang", 0xe4, INSTR_RSY_RRRD },
+ { "laog", 0xe6, INSTR_RSY_RRRD },
+ { "laxg", 0xe7, INSTR_RSY_RRRD },
+ { "laag", 0xe8, INSTR_RSY_RRRD },
+ { "laalg", 0xea, INSTR_RSY_RRRD },
+ { "loc", 0xf2, INSTR_RSY_RDRM },
+ { "stoc", 0xf3, INSTR_RSY_RDRM },
+ { "lan", 0xf4, INSTR_RSY_RRRD },
+ { "lao", 0xf6, INSTR_RSY_RRRD },
+ { "lax", 0xf7, INSTR_RSY_RRRD },
+ { "laa", 0xf8, INSTR_RSY_RRRD },
+ { "laal", 0xfa, INSTR_RSY_RRRD },
#endif
{ "rll", 0x1d, INSTR_RSY_RRRD },
{ "mvclu", 0x8e, INSTR_RSY_RRRD },
@@ -1172,6 +1278,12 @@ static struct insn opcode_ec[] = {
{ "rxsbg", 0x57, INSTR_RIE_RRUUU },
{ "rosbg", 0x56, INSTR_RIE_RRUUU },
{ "risbg", 0x55, INSTR_RIE_RRUUU },
+ { { 0, LONG_INSN_RISBLG }, 0x51, INSTR_RIE_RRUUU },
+ { { 0, LONG_INSN_RISBHG }, 0x5D, INSTR_RIE_RRUUU },
+ { "ahik", 0xd8, INSTR_RIE_RRI0 },
+ { "aghik", 0xd9, INSTR_RIE_RRI0 },
+ { { 0, LONG_INSN_ALHSIK }, 0xda, INSTR_RIE_RRI0 },
+ { { 0, LONG_INSN_ALGHSIK }, 0xdb, INSTR_RIE_RRI0 },
#endif
{ "", 0, INSTR_INVALID }
};
@@ -1321,6 +1433,9 @@ static struct insn *find_insn(unsigned char *code)
case 0xc8:
table = opcode_c8;
break;
+ case 0xcc:
+ table = opcode_cc;
+ break;
case 0xe3:
table = opcode_e3;
opfrag = code[5];
@@ -1367,7 +1482,11 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
ptr = buffer;
insn = find_insn(code);
if (insn) {
- ptr += sprintf(ptr, "%.5s\t", insn->name);
+ if (insn->name[0] == '\0')
+ ptr += sprintf(ptr, "%s\t",
+ long_insn_name[(int) insn->name[1]]);
+ else
+ ptr += sprintf(ptr, "%.5s\t", insn->name);
/* Extract the operands. */
separator = 0;
for (ops = formats[insn->format] + 1, i = 0;
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index c00856ad4e5a..d149609e46e6 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -208,7 +208,8 @@ static noinline __init void init_kernel_storage_key(void)
end_pfn = PFN_UP(__pa(&_end));
for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++)
- page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
+ page_set_storage_key(init_pfn << PAGE_SHIFT,
+ PAGE_DEFAULT_KEY, 0);
}
static __initdata struct sysinfo_3_2_2 vmms __aligned(PAGE_SIZE);
@@ -255,13 +256,35 @@ static noinline __init void setup_lowcore_early(void)
s390_base_pgm_handler_fn = early_pgm_check_handler;
}
+static noinline __init void setup_facility_list(void)
+{
+ unsigned long nr;
+
+ S390_lowcore.stfl_fac_list = 0;
+ asm volatile(
+ " .insn s,0xb2b10000,0(0)\n" /* stfl */
+ "0:\n"
+ EX_TABLE(0b,0b) : "=m" (S390_lowcore.stfl_fac_list));
+ memcpy(&S390_lowcore.stfle_fac_list, &S390_lowcore.stfl_fac_list, 4);
+ nr = 4; /* # bytes stored by stfl */
+ if (test_facility(7)) {
+ /* More facility bits available with stfle */
+ register unsigned long reg0 asm("0") = MAX_FACILITY_BIT/64 - 1;
+ asm volatile(".insn s,0xb2b00000,%0" /* stfle */
+ : "=m" (S390_lowcore.stfle_fac_list), "+d" (reg0)
+ : : "cc");
+ nr = (reg0 + 1) * 8; /* # bytes stored by stfle */
+ }
+ memset((char *) S390_lowcore.stfle_fac_list + nr, 0,
+ MAX_FACILITY_BIT/8 - nr);
+}
+
static noinline __init void setup_hpage(void)
{
#ifndef CONFIG_DEBUG_PAGEALLOC
unsigned int facilities;
- facilities = stfl();
- if (!(facilities & (1UL << 23)) || !(facilities & (1UL << 29)))
+ if (!test_facility(2) || !test_facility(8))
return;
S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE;
__ctl_set_bit(0, 23);
@@ -355,18 +378,15 @@ static __init void detect_diag44(void)
static __init void detect_machine_facilities(void)
{
#ifdef CONFIG_64BIT
- unsigned int facilities;
- unsigned long long facility_bits;
-
- facilities = stfl();
- if (facilities & (1 << 28))
+ if (test_facility(3))
S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
- if (facilities & (1 << 23))
+ if (test_facility(8))
S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF;
- if (facilities & (1 << 4))
+ if (test_facility(11))
+ S390_lowcore.machine_flags |= MACHINE_FLAG_TOPOLOGY;
+ if (test_facility(27))
S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
- if ((stfle(&facility_bits, 1) > 0) &&
- (facility_bits & (1ULL << (63 - 40))))
+ if (test_facility(40))
S390_lowcore.machine_flags |= MACHINE_FLAG_SPP;
#endif
}
@@ -447,6 +467,7 @@ void __init startup_init(void)
lockdep_off();
sort_main_extable();
setup_lowcore_early();
+ setup_facility_list();
detect_machine_type();
ipl_update_parameters();
setup_boot_command_line();
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index bea9ee37ac9d..5efce7202984 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -72,25 +72,9 @@ STACK_SIZE = 1 << STACK_SHIFT
l %r1,BASED(.Ltrace_irq_off_caller)
basr %r14,%r1
.endm
-
- .macro TRACE_IRQS_CHECK_ON
- tm SP_PSW(%r15),0x03 # irqs enabled?
- bz BASED(0f)
- TRACE_IRQS_ON
-0:
- .endm
-
- .macro TRACE_IRQS_CHECK_OFF
- tm SP_PSW(%r15),0x03 # irqs enabled?
- bz BASED(0f)
- TRACE_IRQS_OFF
-0:
- .endm
#else
#define TRACE_IRQS_ON
#define TRACE_IRQS_OFF
-#define TRACE_IRQS_CHECK_ON
-#define TRACE_IRQS_CHECK_OFF
#endif
#ifdef CONFIG_LOCKDEP
@@ -198,6 +182,12 @@ STACK_SIZE = 1 << STACK_SHIFT
lpsw \psworg # back to caller
.endm
+ .macro REENABLE_IRQS
+ mvc __SF_EMPTY(1,%r15),SP_PSW(%r15)
+ ni __SF_EMPTY(%r15),0xbf
+ ssm __SF_EMPTY(%r15)
+ .endm
+
/*
* Scheduler resume function, called by switch_to
* gpr2 = (task_struct *) prev
@@ -264,12 +254,11 @@ sysc_do_svc:
bnl BASED(sysc_nr_ok)
lr %r7,%r1 # copy svc number to %r7
sysc_nr_ok:
- mvc SP_ARGS(4,%r15),SP_R7(%r15)
-sysc_do_restart:
sth %r7,SP_SVCNR(%r15)
sll %r7,2 # svc number *4
l %r8,BASED(.Lsysc_table)
tm __TI_flags+2(%r9),_TIF_SYSCALL
+ mvc SP_ARGS(4,%r15),SP_R7(%r15)
l %r8,0(%r7,%r8) # get system call addr.
bnz BASED(sysc_tracesys)
basr %r14,%r8 # call sys_xxxx
@@ -357,7 +346,7 @@ sysc_restart:
l %r7,SP_R2(%r15) # load new svc number
mvc SP_R2(4,%r15),SP_ORIG_R2(%r15) # restore first argument
lm %r2,%r6,SP_R2(%r15) # load svc arguments
- b BASED(sysc_do_restart) # restart svc
+ b BASED(sysc_nr_ok) # restart svc
#
# _TIF_SINGLE_STEP is set, call do_single_step
@@ -390,6 +379,7 @@ sysc_tracesys:
l %r8,0(%r7,%r8)
sysc_tracego:
lm %r3,%r6,SP_R3(%r15)
+ mvc SP_ARGS(4,%r15),SP_R7(%r15)
l %r2,SP_ORIG_R2(%r15)
basr %r14,%r8 # call sys_xxx
st %r2,SP_R2(%r15) # store return value
@@ -440,13 +430,11 @@ kernel_execve:
br %r14
# execve succeeded.
0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts
- TRACE_IRQS_OFF
l %r15,__LC_KERNEL_STACK # load ksp
s %r15,BASED(.Lc_spsize) # make room for registers & psw
l %r9,__LC_THREAD_INFO
mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
- TRACE_IRQS_ON
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
l %r1,BASED(.Lexecve_tail)
basr %r14,%r1
@@ -483,9 +471,10 @@ pgm_check_handler:
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
pgm_no_vtime:
- TRACE_IRQS_CHECK_OFF
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
l %r3,__LC_PGM_ILC # load program interruption code
+ l %r4,__LC_TRANS_EXC_CODE
+ REENABLE_IRQS
la %r8,0x7f
nr %r8,%r3
pgm_do_call:
@@ -495,7 +484,6 @@ pgm_do_call:
la %r2,SP_PTREGS(%r15) # address of register-save area
basr %r14,%r7 # branch to interrupt-handler
pgm_exit:
- TRACE_IRQS_CHECK_ON
b BASED(sysc_return)
#
@@ -523,7 +511,6 @@ pgm_per_std:
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
pgm_no_vtime2:
- TRACE_IRQS_CHECK_OFF
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
l %r1,__TI_task(%r9)
tm SP_PSW+1(%r15),0x01 # kernel per event ?
@@ -533,6 +520,8 @@ pgm_no_vtime2:
mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
l %r3,__LC_PGM_ILC # load program interruption code
+ l %r4,__LC_TRANS_EXC_CODE
+ REENABLE_IRQS
la %r8,0x7f
nr %r8,%r3 # clear per-event-bit and ilc
be BASED(pgm_exit2) # only per or per+check ?
@@ -542,8 +531,6 @@ pgm_no_vtime2:
la %r2,SP_PTREGS(%r15) # address of register-save area
basr %r14,%r7 # branch to interrupt-handler
pgm_exit2:
- TRACE_IRQS_ON
- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
b BASED(sysc_return)
#
@@ -557,13 +544,11 @@ pgm_svcper:
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
lh %r7,0x8a # get svc number from lowcore
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
- TRACE_IRQS_OFF
l %r8,__TI_task(%r9)
mvc __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
mvc __THREAD_per+__PER_address(4,%r8),__LC_PER_ADDRESS
mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
- TRACE_IRQS_ON
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
lm %r2,%r6,SP_R2(%r15) # load svc arguments
b BASED(sysc_do_svc)
@@ -737,7 +722,8 @@ ext_no_vtime:
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
TRACE_IRQS_OFF
la %r2,SP_PTREGS(%r15) # address of register-save area
- lh %r3,__LC_EXT_INT_CODE # get interruption code
+ l %r3,__LC_CPU_ADDRESS # get cpu address + interruption code
+ l %r4,__LC_EXT_PARAMS # get external parameters
l %r1,BASED(.Ldo_extint)
basr %r14,%r1
b BASED(io_return)
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index ff579b6bde06..95c1dfc4ef31 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -5,7 +5,7 @@
#include <linux/signal.h>
#include <asm/ptrace.h>
-typedef void pgm_check_handler_t(struct pt_regs *, long);
+typedef void pgm_check_handler_t(struct pt_regs *, long, unsigned long);
extern pgm_check_handler_t *pgm_check_table[128];
pgm_check_handler_t do_protection_exception;
pgm_check_handler_t do_dat_exception;
@@ -19,7 +19,7 @@ void do_signal(struct pt_regs *regs);
int handle_signal32(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs);
-void do_extint(struct pt_regs *regs, unsigned short code);
+void do_extint(struct pt_regs *regs, unsigned int, unsigned int, unsigned long);
int __cpuinit start_secondary(void *cpuvoid);
void __init startup_init(void);
void die(const char * str, struct pt_regs * regs, long err);
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 8bccec15ea90..a2be23922f43 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -79,25 +79,9 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
basr %r2,%r0
brasl %r14,trace_hardirqs_off_caller
.endm
-
- .macro TRACE_IRQS_CHECK_ON
- tm SP_PSW(%r15),0x03 # irqs enabled?
- jz 0f
- TRACE_IRQS_ON
-0:
- .endm
-
- .macro TRACE_IRQS_CHECK_OFF
- tm SP_PSW(%r15),0x03 # irqs enabled?
- jz 0f
- TRACE_IRQS_OFF
-0:
- .endm
#else
#define TRACE_IRQS_ON
#define TRACE_IRQS_OFF
-#define TRACE_IRQS_CHECK_ON
-#define TRACE_IRQS_CHECK_OFF
#endif
#ifdef CONFIG_LOCKDEP
@@ -207,6 +191,12 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
0:
.endm
+ .macro REENABLE_IRQS
+ mvc __SF_EMPTY(1,%r15),SP_PSW(%r15)
+ ni __SF_EMPTY(%r15),0xbf
+ ssm __SF_EMPTY(%r15)
+ .endm
+
/*
* Scheduler resume function, called by switch_to
* gpr2 = (task_struct *) prev
@@ -256,7 +246,6 @@ sysc_saveall:
CREATE_STACK_FRAME __LC_SAVE_AREA
mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW
mvc SP_ILC(4,%r15),__LC_SVC_ILC
- stg %r7,SP_ARGS(%r15)
lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct
sysc_vtime:
UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
@@ -284,6 +273,7 @@ sysc_nr_ok:
sysc_noemu:
#endif
tm __TI_flags+6(%r12),_TIF_SYSCALL
+ mvc SP_ARGS(8,%r15),SP_R7(%r15)
lgf %r8,0(%r7,%r10) # load address of system call routine
jnz sysc_tracesys
basr %r14,%r8 # call sys_xxxx
@@ -397,6 +387,7 @@ sysc_tracesys:
lgf %r8,0(%r7,%r10)
sysc_tracego:
lmg %r3,%r6,SP_R3(%r15)
+ mvc SP_ARGS(8,%r15),SP_R7(%r15)
lg %r2,SP_ORIG_R2(%r15)
basr %r14,%r8 # call sys_xxx
stg %r2,SP_R2(%r15) # store return value
@@ -443,14 +434,12 @@ kernel_execve:
br %r14
# execve succeeded.
0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts
-# TRACE_IRQS_OFF
lg %r15,__LC_KERNEL_STACK # load ksp
aghi %r15,-SP_SIZE # make room for registers & psw
lg %r13,__LC_SVC_NEW_PSW+8
mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs
lg %r12,__LC_THREAD_INFO
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
-# TRACE_IRQS_ON
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
brasl %r14,execve_tail
j sysc_return
@@ -490,19 +479,18 @@ pgm_check_handler:
LAST_BREAK
pgm_no_vtime:
HANDLE_SIE_INTERCEPT
- TRACE_IRQS_CHECK_OFF
stg %r11,SP_ARGS(%r15)
lgf %r3,__LC_PGM_ILC # load program interruption code
+ lg %r4,__LC_TRANS_EXC_CODE
+ REENABLE_IRQS
lghi %r8,0x7f
ngr %r8,%r3
-pgm_do_call:
sll %r8,3
larl %r1,pgm_check_table
lg %r1,0(%r8,%r1) # load address of handler routine
la %r2,SP_PTREGS(%r15) # address of register-save area
basr %r14,%r1 # branch to interrupt-handler
pgm_exit:
- TRACE_IRQS_CHECK_ON
j sysc_return
#
@@ -533,7 +521,6 @@ pgm_per_std:
LAST_BREAK
pgm_no_vtime2:
HANDLE_SIE_INTERCEPT
- TRACE_IRQS_CHECK_OFF
lg %r1,__TI_task(%r12)
tm SP_PSW+1(%r15),0x01 # kernel per event ?
jz kernel_per
@@ -542,6 +529,8 @@ pgm_no_vtime2:
mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
oi __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
lgf %r3,__LC_PGM_ILC # load program interruption code
+ lg %r4,__LC_TRANS_EXC_CODE
+ REENABLE_IRQS
lghi %r8,0x7f
ngr %r8,%r3 # clear per-event-bit and ilc
je pgm_exit2
@@ -551,8 +540,6 @@ pgm_no_vtime2:
la %r2,SP_PTREGS(%r15) # address of register-save area
basr %r14,%r1 # branch to interrupt-handler
pgm_exit2:
- TRACE_IRQS_ON
- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
j sysc_return
#
@@ -568,13 +555,11 @@ pgm_svcper:
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
LAST_BREAK
- TRACE_IRQS_OFF
lg %r8,__TI_task(%r12)
mvc __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
mvc __THREAD_per+__PER_address(8,%r8),__LC_PER_ADDRESS
mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
oi __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
- TRACE_IRQS_ON
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
lmg %r2,%r6,SP_R2(%r15) # load svc arguments
j sysc_do_svc
@@ -743,8 +728,11 @@ ext_int_handler:
ext_no_vtime:
HANDLE_SIE_INTERCEPT
TRACE_IRQS_OFF
+ lghi %r1,4096
la %r2,SP_PTREGS(%r15) # address of register-save area
- llgh %r3,__LC_EXT_INT_CODE # get interruption code
+ llgf %r3,__LC_CPU_ADDRESS # get cpu address + interruption code
+ llgf %r4,__LC_EXT_PARAMS # get external parameter
+ lg %r5,__LC_EXT_PARAMS2-4096(%r1) # get 64 bit external parameter
brasl %r14,do_extint
j io_return
@@ -966,7 +954,6 @@ cleanup_system_call:
CREATE_STACK_FRAME __LC_SAVE_AREA
mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW
mvc SP_ILC(4,%r15),__LC_SVC_ILC
- stg %r7,SP_ARGS(%r15)
mvc 8(8,%r12),__LC_THREAD_INFO
cleanup_vtime:
clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24)
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
index db1696e210af..7061398341d5 100644
--- a/arch/s390/kernel/head.S
+++ b/arch/s390/kernel/head.S
@@ -488,7 +488,9 @@ startup:
.align 16
2: .long 0x000a0000,0x8badcccc
#if defined(CONFIG_64BIT)
-#if defined(CONFIG_MARCH_Z10)
+#if defined(CONFIG_MARCH_Z196)
+ .long 0xc100efe3, 0xf46c0000
+#elif defined(CONFIG_MARCH_Z10)
.long 0xc100efe3, 0xf0680000
#elif defined(CONFIG_MARCH_Z9_109)
.long 0xc100efc3, 0x00000000
@@ -498,7 +500,9 @@ startup:
.long 0xc0000000, 0x00000000
#endif
#else
-#if defined(CONFIG_MARCH_Z10)
+#if defined(CONFIG_MARCH_Z196)
+ .long 0x8100c880, 0x00000000
+#elif defined(CONFIG_MARCH_Z10)
.long 0x8100c880, 0x00000000
#elif defined(CONFIG_MARCH_Z9_109)
.long 0x8100c880, 0x00000000
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index d3a2d1c6438e..ec2e03b22ead 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -76,17 +76,17 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
static void default_idle(void)
{
/* CPU is going idle. */
- local_irq_disable();
- if (need_resched()) {
- local_irq_enable();
- return;
- }
#ifdef CONFIG_HOTPLUG_CPU
if (cpu_is_offline(smp_processor_id())) {
preempt_enable_no_resched();
cpu_die();
}
#endif
+ local_irq_disable();
+ if (need_resched()) {
+ local_irq_enable();
+ return;
+ }
local_mcck_disable();
if (test_thread_flag(TIF_MCCK_PENDING)) {
local_mcck_enable();
diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c
index ecb2d02b02e4..644548e615c6 100644
--- a/arch/s390/kernel/processor.c
+++ b/arch/s390/kernel/processor.c
@@ -42,7 +42,7 @@ void __cpuinit print_cpu_info(void)
struct cpuid *id = &per_cpu(cpu_id, smp_processor_id());
pr_info("Processor %d started, address %d, identification %06X\n",
- S390_lowcore.cpu_nr, S390_lowcore.cpu_addr, id->ident);
+ S390_lowcore.cpu_nr, stap(), id->ident);
}
/*
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 83339d33c4b1..019bb714db49 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -343,7 +343,8 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
return __poke_user(child, addr, data);
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
ptrace_area parea;
int copied, ret;
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
index 9ce641b5291f..bd1db508e8af 100644
--- a/arch/s390/kernel/s390_ext.c
+++ b/arch/s390/kernel/s390_ext.c
@@ -113,12 +113,15 @@ int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
return 0;
}
-void __irq_entry do_extint(struct pt_regs *regs, unsigned short code)
+void __irq_entry do_extint(struct pt_regs *regs, unsigned int ext_int_code,
+ unsigned int param32, unsigned long param64)
{
+ struct pt_regs *old_regs;
+ unsigned short code;
ext_int_info_t *p;
int index;
- struct pt_regs *old_regs;
+ code = (unsigned short) ext_int_code;
old_regs = set_irq_regs(regs);
s390_idle_check(regs, S390_lowcore.int_clock,
S390_lowcore.async_enter_timer);
@@ -132,7 +135,7 @@ void __irq_entry do_extint(struct pt_regs *regs, unsigned short code)
index = ext_hash(code);
for (p = ext_int_hash[index]; p; p = p->next) {
if (likely(p->code == code))
- p->handler(code);
+ p->handler(ext_int_code, param32, param64);
}
irq_exit();
set_irq_regs(old_regs);
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index c8e8e1354e1d..e3ceb911dc75 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -409,6 +409,9 @@ setup_lowcore(void)
lc->current_task = (unsigned long) init_thread_union.thread_info.task;
lc->thread_info = (unsigned long) &init_thread_union;
lc->machine_flags = S390_lowcore.machine_flags;
+ lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
+ memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
+ MAX_FACILITY_BIT/8);
#ifndef CONFIG_64BIT
if (MACHINE_HAS_IEEE) {
lc->extended_save_area_addr = (__u32)
@@ -627,7 +630,8 @@ setup_memory(void)
add_active_range(0, start_chunk, end_chunk);
pfn = max(start_chunk, start_pfn);
for (; pfn < end_chunk; pfn++)
- page_set_storage_key(PFN_PHYS(pfn), PAGE_DEFAULT_KEY);
+ page_set_storage_key(PFN_PHYS(pfn),
+ PAGE_DEFAULT_KEY, 0);
}
psw_set_key(PAGE_DEFAULT_KEY);
@@ -674,12 +678,9 @@ setup_memory(void)
static void __init setup_hwcaps(void)
{
static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 };
- unsigned long long facility_list_extended;
- unsigned int facility_list;
struct cpuid cpu_id;
int i;
- facility_list = stfl();
/*
* The store facility list bits numbers as found in the principles
* of operation are numbered with bit 1UL<<31 as number 0 to
@@ -699,11 +700,10 @@ static void __init setup_hwcaps(void)
* HWCAP_S390_ETF3EH bit 8 (22 && 30).
*/
for (i = 0; i < 6; i++)
- if (facility_list & (1UL << (31 - stfl_bits[i])))
+ if (test_facility(stfl_bits[i]))
elf_hwcap |= 1UL << i;
- if ((facility_list & (1UL << (31 - 22)))
- && (facility_list & (1UL << (31 - 30))))
+ if (test_facility(22) && test_facility(30))
elf_hwcap |= HWCAP_S390_ETF3EH;
/*
@@ -719,12 +719,8 @@ static void __init setup_hwcaps(void)
* translated to:
* HWCAP_S390_DFP bit 6 (42 && 44).
*/
- if ((elf_hwcap & (1UL << 2)) &&
- __stfle(&facility_list_extended, 1) > 0) {
- if ((facility_list_extended & (1ULL << (63 - 42)))
- && (facility_list_extended & (1ULL << (63 - 44))))
- elf_hwcap |= HWCAP_S390_DFP;
- }
+ if ((elf_hwcap & (1UL << 2)) && test_facility(42) && test_facility(44))
+ elf_hwcap |= HWCAP_S390_DFP;
/*
* Huge page support HWCAP_S390_HPAGE is bit 7.
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 8127ebd59c4d..94cf510b8fe1 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -156,7 +156,8 @@ void smp_send_stop(void)
* cpus are handled.
*/
-static void do_ext_call_interrupt(__u16 code)
+static void do_ext_call_interrupt(unsigned int ext_int_code,
+ unsigned int param32, unsigned long param64)
{
unsigned long bits;
@@ -593,6 +594,8 @@ int __cpuinit __cpu_up(unsigned int cpu)
cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce;
cpu_lowcore->machine_flags = S390_lowcore.machine_flags;
cpu_lowcore->ftrace_func = S390_lowcore.ftrace_func;
+ memcpy(cpu_lowcore->stfle_fac_list, S390_lowcore.stfle_fac_list,
+ MAX_FACILITY_BIT/8);
eieio();
while (sigp(cpu, sigp_restart) == sigp_busy)
diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c
index a0ffc7717ed6..f04d93aa48ec 100644
--- a/arch/s390/kernel/sysinfo.c
+++ b/arch/s390/kernel/sysinfo.c
@@ -15,6 +15,7 @@
#include <asm/ebcdic.h>
#include <asm/sysinfo.h>
#include <asm/cpcmd.h>
+#include <asm/topology.h>
/* Sigh, math-emu. Don't ask. */
#include <asm/sfp-util.h>
@@ -74,6 +75,42 @@ static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len)
"Model Temp. Capacity: %-16.16s %08u\n",
info->model_temp_cap,
*(u32 *) info->model_temp_cap_rating);
+ if (info->cai) {
+ len += sprintf(page + len,
+ "Capacity Adj. Ind.: %d\n",
+ info->cai);
+ len += sprintf(page + len, "Capacity Ch. Reason: %d\n",
+ info->ccr);
+ }
+ return len;
+}
+
+static int stsi_15_1_x(struct sysinfo_15_1_x *info, char *page, int len)
+{
+ static int max_mnest;
+ int i, rc;
+
+ len += sprintf(page + len, "\n");
+ if (!MACHINE_HAS_TOPOLOGY)
+ return len;
+ if (max_mnest) {
+ stsi(info, 15, 1, max_mnest);
+ } else {
+ for (max_mnest = 6; max_mnest > 1; max_mnest--) {
+ rc = stsi(info, 15, 1, max_mnest);
+ if (rc != -ENOSYS)
+ break;
+ }
+ }
+ len += sprintf(page + len, "CPU Topology HW: ");
+ for (i = 0; i < TOPOLOGY_NR_MAG; i++)
+ len += sprintf(page + len, " %d", info->mag[i]);
+ len += sprintf(page + len, "\n");
+ store_topology(info);
+ len += sprintf(page + len, "CPU Topology SW: ");
+ for (i = 0; i < TOPOLOGY_NR_MAG; i++)
+ len += sprintf(page + len, " %d", info->mag[i]);
+ len += sprintf(page + len, "\n");
return len;
}
@@ -87,7 +124,6 @@ static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)
ext = (struct sysinfo_1_2_2_extension *)
((unsigned long) info + info->acc_offset);
- len += sprintf(page + len, "\n");
len += sprintf(page + len, "CPUs Total: %d\n",
info->cpus_total);
len += sprintf(page + len, "CPUs Configured: %d\n",
@@ -217,6 +253,9 @@ static int proc_read_sysinfo(char *page, char **start,
len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len);
if (level >= 1)
+ len = stsi_15_1_x((struct sysinfo_15_1_x *) info, page, len);
+
+ if (level >= 1)
len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len);
if (level >= 2)
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 2896cac9c14a..f754a6dc4f94 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -155,7 +155,9 @@ void init_cpu_timer(void)
__ctl_set_bit(0, 4);
}
-static void clock_comparator_interrupt(__u16 code)
+static void clock_comparator_interrupt(unsigned int ext_int_code,
+ unsigned int param32,
+ unsigned long param64)
{
if (S390_lowcore.clock_comparator == -1ULL)
set_clock_comparator(S390_lowcore.clock_comparator);
@@ -164,14 +166,13 @@ static void clock_comparator_interrupt(__u16 code)
static void etr_timing_alert(struct etr_irq_parm *);
static void stp_timing_alert(struct stp_irq_parm *);
-static void timing_alert_interrupt(__u16 code)
+static void timing_alert_interrupt(unsigned int ext_int_code,
+ unsigned int param32, unsigned long param64)
{
- if (S390_lowcore.ext_params & 0x00c40000)
- etr_timing_alert((struct etr_irq_parm *)
- &S390_lowcore.ext_params);
- if (S390_lowcore.ext_params & 0x00038000)
- stp_timing_alert((struct stp_irq_parm *)
- &S390_lowcore.ext_params);
+ if (param32 & 0x00c40000)
+ etr_timing_alert((struct etr_irq_parm *) &param32);
+ if (param32 & 0x00038000)
+ stp_timing_alert((struct stp_irq_parm *) &param32);
}
static void etr_reset(void);
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c
index 13559c993847..a9dee9048ee5 100644
--- a/arch/s390/kernel/topology.c
+++ b/arch/s390/kernel/topology.c
@@ -18,55 +18,20 @@
#include <linux/cpuset.h>
#include <asm/delay.h>
#include <asm/s390_ext.h>
-#include <asm/sysinfo.h>
-
-#define CPU_BITS 64
-#define NR_MAG 6
#define PTF_HORIZONTAL (0UL)
#define PTF_VERTICAL (1UL)
#define PTF_CHECK (2UL)
-struct tl_cpu {
- unsigned char reserved0[4];
- unsigned char :6;
- unsigned char pp:2;
- unsigned char reserved1;
- unsigned short origin;
- unsigned long mask[CPU_BITS / BITS_PER_LONG];
-};
-
-struct tl_container {
- unsigned char reserved[7];
- unsigned char id;
-};
-
-union tl_entry {
- unsigned char nl;
- struct tl_cpu cpu;
- struct tl_container container;
-};
-
-struct tl_info {
- unsigned char reserved0[2];
- unsigned short length;
- unsigned char mag[NR_MAG];
- unsigned char reserved1;
- unsigned char mnest;
- unsigned char reserved2[4];
- union tl_entry tle[0];
-};
-
struct mask_info {
struct mask_info *next;
unsigned char id;
cpumask_t mask;
};
-static int topology_enabled;
+static int topology_enabled = 1;
static void topology_work_fn(struct work_struct *work);
-static struct tl_info *tl_info;
-static int machine_has_topology;
+static struct sysinfo_15_1_x *tl_info;
static struct timer_list topology_timer;
static void set_topology_timer(void);
static DECLARE_WORK(topology_work, topology_work_fn);
@@ -88,7 +53,7 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
cpumask_t mask;
cpus_clear(mask);
- if (!topology_enabled || !machine_has_topology)
+ if (!topology_enabled || !MACHINE_HAS_TOPOLOGY)
return cpu_possible_map;
while (info) {
if (cpu_isset(cpu, info->mask)) {
@@ -102,18 +67,18 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
return mask;
}
-static void add_cpus_to_mask(struct tl_cpu *tl_cpu, struct mask_info *book,
- struct mask_info *core)
+static void add_cpus_to_mask(struct topology_cpu *tl_cpu,
+ struct mask_info *book, struct mask_info *core)
{
unsigned int cpu;
- for (cpu = find_first_bit(&tl_cpu->mask[0], CPU_BITS);
- cpu < CPU_BITS;
- cpu = find_next_bit(&tl_cpu->mask[0], CPU_BITS, cpu + 1))
+ for (cpu = find_first_bit(&tl_cpu->mask[0], TOPOLOGY_CPU_BITS);
+ cpu < TOPOLOGY_CPU_BITS;
+ cpu = find_next_bit(&tl_cpu->mask[0], TOPOLOGY_CPU_BITS, cpu + 1))
{
unsigned int rcpu, lcpu;
- rcpu = CPU_BITS - 1 - cpu + tl_cpu->origin;
+ rcpu = TOPOLOGY_CPU_BITS - 1 - cpu + tl_cpu->origin;
for_each_present_cpu(lcpu) {
if (cpu_logical_map(lcpu) != rcpu)
continue;
@@ -146,15 +111,14 @@ static void clear_masks(void)
#endif
}
-static union tl_entry *next_tle(union tl_entry *tle)
+static union topology_entry *next_tle(union topology_entry *tle)
{
- if (tle->nl)
- return (union tl_entry *)((struct tl_container *)tle + 1);
- else
- return (union tl_entry *)((struct tl_cpu *)tle + 1);
+ if (!tle->nl)
+ return (union topology_entry *)((struct topology_cpu *)tle + 1);
+ return (union topology_entry *)((struct topology_container *)tle + 1);
}
-static void tl_to_cores(struct tl_info *info)
+static void tl_to_cores(struct sysinfo_15_1_x *info)
{
#ifdef CONFIG_SCHED_BOOK
struct mask_info *book = &book_info;
@@ -162,13 +126,13 @@ static void tl_to_cores(struct tl_info *info)
struct mask_info *book = NULL;
#endif
struct mask_info *core = &core_info;
- union tl_entry *tle, *end;
+ union topology_entry *tle, *end;
spin_lock_irq(&topology_lock);
clear_masks();
tle = info->tle;
- end = (union tl_entry *)((unsigned long)info + info->length);
+ end = (union topology_entry *)((unsigned long)info + info->length);
while (tle < end) {
switch (tle->nl) {
#ifdef CONFIG_SCHED_BOOK
@@ -186,7 +150,6 @@ static void tl_to_cores(struct tl_info *info)
break;
default:
clear_masks();
- machine_has_topology = 0;
goto out;
}
tle = next_tle(tle);
@@ -223,7 +186,7 @@ int topology_set_cpu_management(int fc)
int cpu;
int rc;
- if (!machine_has_topology)
+ if (!MACHINE_HAS_TOPOLOGY)
return -EOPNOTSUPP;
if (fc)
rc = ptf(PTF_VERTICAL);
@@ -251,7 +214,7 @@ static void update_cpu_core_map(void)
spin_unlock_irqrestore(&topology_lock, flags);
}
-static void store_topology(struct tl_info *info)
+void store_topology(struct sysinfo_15_1_x *info)
{
#ifdef CONFIG_SCHED_BOOK
int rc;
@@ -265,11 +228,11 @@ static void store_topology(struct tl_info *info)
int arch_update_cpu_topology(void)
{
- struct tl_info *info = tl_info;
+ struct sysinfo_15_1_x *info = tl_info;
struct sys_device *sysdev;
int cpu;
- if (!machine_has_topology) {
+ if (!MACHINE_HAS_TOPOLOGY) {
update_cpu_core_map();
topology_update_polarization_simple();
return 0;
@@ -311,9 +274,9 @@ static void set_topology_timer(void)
static int __init early_parse_topology(char *p)
{
- if (strncmp(p, "on", 2))
+ if (strncmp(p, "off", 3))
return 0;
- topology_enabled = 1;
+ topology_enabled = 0;
return 0;
}
early_param("topology", early_parse_topology);
@@ -323,7 +286,7 @@ static int __init init_topology_update(void)
int rc;
rc = 0;
- if (!machine_has_topology) {
+ if (!MACHINE_HAS_TOPOLOGY) {
topology_update_polarization_simple();
goto out;
}
@@ -335,13 +298,14 @@ out:
}
__initcall(init_topology_update);
-static void alloc_masks(struct tl_info *info, struct mask_info *mask, int offset)
+static void alloc_masks(struct sysinfo_15_1_x *info, struct mask_info *mask,
+ int offset)
{
int i, nr_masks;
- nr_masks = info->mag[NR_MAG - offset];
+ nr_masks = info->mag[TOPOLOGY_NR_MAG - offset];
for (i = 0; i < info->mnest - offset; i++)
- nr_masks *= info->mag[NR_MAG - offset - 1 - i];
+ nr_masks *= info->mag[TOPOLOGY_NR_MAG - offset - 1 - i];
nr_masks = max(nr_masks, 1);
for (i = 0; i < nr_masks; i++) {
mask->next = alloc_bootmem(sizeof(struct mask_info));
@@ -351,21 +315,16 @@ static void alloc_masks(struct tl_info *info, struct mask_info *mask, int offset
void __init s390_init_cpu_topology(void)
{
- unsigned long long facility_bits;
- struct tl_info *info;
+ struct sysinfo_15_1_x *info;
int i;
- if (stfle(&facility_bits, 1) <= 0)
- return;
- if (!(facility_bits & (1ULL << 52)) || !(facility_bits & (1ULL << 61)))
+ if (!MACHINE_HAS_TOPOLOGY)
return;
- machine_has_topology = 1;
-
tl_info = alloc_bootmem_pages(PAGE_SIZE);
info = tl_info;
store_topology(info);
pr_info("The CPU configuration topology of the machine is:");
- for (i = 0; i < NR_MAG; i++)
+ for (i = 0; i < TOPOLOGY_NR_MAG; i++)
printk(" %d", info->mag[i]);
printk(" / %d\n", info->mnest);
alloc_masks(info, &core_info, 2);
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 5d8f0f3d0250..70640822621a 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -329,27 +329,19 @@ int is_valid_bugaddr(unsigned long addr)
return 1;
}
-static void __kprobes inline do_trap(long interruption_code, int signr,
- char *str, struct pt_regs *regs,
- siginfo_t *info)
+static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str,
+ struct pt_regs *regs, siginfo_t *info)
{
- /*
- * We got all needed information from the lowcore and can
- * now safely switch on interrupts.
- */
- if (regs->psw.mask & PSW_MASK_PSTATE)
- local_irq_enable();
-
- if (notify_die(DIE_TRAP, str, regs, interruption_code,
- interruption_code, signr) == NOTIFY_STOP)
+ if (notify_die(DIE_TRAP, str, regs, pgm_int_code,
+ pgm_int_code, signr) == NOTIFY_STOP)
return;
if (regs->psw.mask & PSW_MASK_PSTATE) {
struct task_struct *tsk = current;
- tsk->thread.trap_no = interruption_code & 0xffff;
+ tsk->thread.trap_no = pgm_int_code & 0xffff;
force_sig_info(signr, info, tsk);
- report_user_fault(regs, interruption_code, signr);
+ report_user_fault(regs, pgm_int_code, signr);
} else {
const struct exception_table_entry *fixup;
fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
@@ -361,14 +353,16 @@ static void __kprobes inline do_trap(long interruption_code, int signr,
btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);
if (btt == BUG_TRAP_TYPE_WARN)
return;
- die(str, regs, interruption_code);
+ die(str, regs, pgm_int_code);
}
}
}
-static inline void __user *get_check_address(struct pt_regs *regs)
+static inline void __user *get_psw_address(struct pt_regs *regs,
+ long pgm_int_code)
{
- return (void __user *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
+ return (void __user *)
+ ((regs->psw.addr - (pgm_int_code >> 16)) & PSW_ADDR_INSN);
}
void __kprobes do_single_step(struct pt_regs *regs)
@@ -381,57 +375,57 @@ void __kprobes do_single_step(struct pt_regs *regs)
force_sig(SIGTRAP, current);
}
-static void default_trap_handler(struct pt_regs * regs, long interruption_code)
+static void default_trap_handler(struct pt_regs *regs, long pgm_int_code,
+ unsigned long trans_exc_code)
{
if (regs->psw.mask & PSW_MASK_PSTATE) {
- local_irq_enable();
- report_user_fault(regs, interruption_code, SIGSEGV);
+ report_user_fault(regs, pgm_int_code, SIGSEGV);
do_exit(SIGSEGV);
} else
- die("Unknown program exception", regs, interruption_code);
+ die("Unknown program exception", regs, pgm_int_code);
}
-#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
-static void name(struct pt_regs * regs, long interruption_code) \
+#define DO_ERROR_INFO(name, signr, sicode, str) \
+static void name(struct pt_regs *regs, long pgm_int_code, \
+ unsigned long trans_exc_code) \
{ \
siginfo_t info; \
info.si_signo = signr; \
info.si_errno = 0; \
info.si_code = sicode; \
- info.si_addr = siaddr; \
- do_trap(interruption_code, signr, str, regs, &info); \
+ info.si_addr = get_psw_address(regs, pgm_int_code); \
+ do_trap(pgm_int_code, signr, str, regs, &info); \
}
-DO_ERROR_INFO(SIGILL, "addressing exception", addressing_exception,
- ILL_ILLADR, get_check_address(regs))
-DO_ERROR_INFO(SIGILL, "execute exception", execute_exception,
- ILL_ILLOPN, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE, "fixpoint divide exception", divide_exception,
- FPE_INTDIV, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE, "fixpoint overflow exception", overflow_exception,
- FPE_INTOVF, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE, "HFP overflow exception", hfp_overflow_exception,
- FPE_FLTOVF, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE, "HFP underflow exception", hfp_underflow_exception,
- FPE_FLTUND, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE, "HFP significance exception", hfp_significance_exception,
- FPE_FLTRES, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE, "HFP divide exception", hfp_divide_exception,
- FPE_FLTDIV, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE, "HFP square root exception", hfp_sqrt_exception,
- FPE_FLTINV, get_check_address(regs))
-DO_ERROR_INFO(SIGILL, "operand exception", operand_exception,
- ILL_ILLOPN, get_check_address(regs))
-DO_ERROR_INFO(SIGILL, "privileged operation", privileged_op,
- ILL_PRVOPC, get_check_address(regs))
-DO_ERROR_INFO(SIGILL, "special operation exception", special_op_exception,
- ILL_ILLOPN, get_check_address(regs))
-DO_ERROR_INFO(SIGILL, "translation exception", translation_exception,
- ILL_ILLOPN, get_check_address(regs))
-
-static inline void
-do_fp_trap(struct pt_regs *regs, void __user *location,
- int fpc, long interruption_code)
+DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
+ "addressing exception")
+DO_ERROR_INFO(execute_exception, SIGILL, ILL_ILLOPN,
+ "execute exception")
+DO_ERROR_INFO(divide_exception, SIGFPE, FPE_INTDIV,
+ "fixpoint divide exception")
+DO_ERROR_INFO(overflow_exception, SIGFPE, FPE_INTOVF,
+ "fixpoint overflow exception")
+DO_ERROR_INFO(hfp_overflow_exception, SIGFPE, FPE_FLTOVF,
+ "HFP overflow exception")
+DO_ERROR_INFO(hfp_underflow_exception, SIGFPE, FPE_FLTUND,
+ "HFP underflow exception")
+DO_ERROR_INFO(hfp_significance_exception, SIGFPE, FPE_FLTRES,
+ "HFP significance exception")
+DO_ERROR_INFO(hfp_divide_exception, SIGFPE, FPE_FLTDIV,
+ "HFP divide exception")
+DO_ERROR_INFO(hfp_sqrt_exception, SIGFPE, FPE_FLTINV,
+ "HFP square root exception")
+DO_ERROR_INFO(operand_exception, SIGILL, ILL_ILLOPN,
+ "operand exception")
+DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC,
+ "privileged operation")
+DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
+ "special operation exception")
+DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN,
+ "translation exception")
+
+static inline void do_fp_trap(struct pt_regs *regs, void __user *location,
+ int fpc, long pgm_int_code)
{
siginfo_t si;
@@ -453,26 +447,19 @@ do_fp_trap(struct pt_regs *regs, void __user *location,
else if (fpc & 0x0800) /* inexact */
si.si_code = FPE_FLTRES;
}
- current->thread.ieee_instruction_pointer = (addr_t) location;
- do_trap(interruption_code, SIGFPE,
+ do_trap(pgm_int_code, SIGFPE,
"floating point exception", regs, &si);
}
-static void illegal_op(struct pt_regs * regs, long interruption_code)
+static void illegal_op(struct pt_regs *regs, long pgm_int_code,
+ unsigned long trans_exc_code)
{
siginfo_t info;
__u8 opcode[6];
__u16 __user *location;
int signal = 0;
- location = get_check_address(regs);
-
- /*
- * We got all needed information from the lowcore and can
- * now safely switch on interrupts.
- */
- if (regs->psw.mask & PSW_MASK_PSTATE)
- local_irq_enable();
+ location = get_psw_address(regs, pgm_int_code);
if (regs->psw.mask & PSW_MASK_PSTATE) {
if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
@@ -512,7 +499,7 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
* If we get an illegal op in kernel mode, send it through the
* kprobes notifier. If kprobes doesn't pick it up, SIGILL
*/
- if (notify_die(DIE_BPT, "bpt", regs, interruption_code,
+ if (notify_die(DIE_BPT, "bpt", regs, pgm_int_code,
3, SIGTRAP) != NOTIFY_STOP)
signal = SIGILL;
}
@@ -520,13 +507,13 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
#ifdef CONFIG_MATHEMU
if (signal == SIGFPE)
do_fp_trap(regs, location,
- current->thread.fp_regs.fpc, interruption_code);
+ current->thread.fp_regs.fpc, pgm_int_code);
else if (signal == SIGSEGV) {
info.si_signo = signal;
info.si_errno = 0;
info.si_code = SEGV_MAPERR;
info.si_addr = (void __user *) location;
- do_trap(interruption_code, signal,
+ do_trap(pgm_int_code, signal,
"user address fault", regs, &info);
} else
#endif
@@ -535,28 +522,22 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
info.si_errno = 0;
info.si_code = ILL_ILLOPC;
info.si_addr = (void __user *) location;
- do_trap(interruption_code, signal,
+ do_trap(pgm_int_code, signal,
"illegal operation", regs, &info);
}
}
#ifdef CONFIG_MATHEMU
-asmlinkage void
-specification_exception(struct pt_regs * regs, long interruption_code)
+asmlinkage void specification_exception(struct pt_regs *regs,
+ long pgm_int_code,
+ unsigned long trans_exc_code)
{
__u8 opcode[6];
__u16 __user *location = NULL;
int signal = 0;
- location = (__u16 __user *) get_check_address(regs);
-
- /*
- * We got all needed information from the lowcore and can
- * now safely switch on interrupts.
- */
- if (regs->psw.mask & PSW_MASK_PSTATE)
- local_irq_enable();
+ location = (__u16 __user *) get_psw_address(regs, pgm_int_code);
if (regs->psw.mask & PSW_MASK_PSTATE) {
get_user(*((__u16 *) opcode), location);
@@ -592,35 +573,29 @@ specification_exception(struct pt_regs * regs, long interruption_code)
if (signal == SIGFPE)
do_fp_trap(regs, location,
- current->thread.fp_regs.fpc, interruption_code);
+ current->thread.fp_regs.fpc, pgm_int_code);
else if (signal) {
siginfo_t info;
info.si_signo = signal;
info.si_errno = 0;
info.si_code = ILL_ILLOPN;
info.si_addr = location;
- do_trap(interruption_code, signal,
+ do_trap(pgm_int_code, signal,
"specification exception", regs, &info);
}
}
#else
-DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
- ILL_ILLOPN, get_check_address(regs));
+DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
+ "specification exception");
#endif
-static void data_exception(struct pt_regs * regs, long interruption_code)
+static void data_exception(struct pt_regs *regs, long pgm_int_code,
+ unsigned long trans_exc_code)
{
__u16 __user *location;
int signal = 0;
- location = get_check_address(regs);
-
- /*
- * We got all needed information from the lowcore and can
- * now safely switch on interrupts.
- */
- if (regs->psw.mask & PSW_MASK_PSTATE)
- local_irq_enable();
+ location = get_psw_address(regs, pgm_int_code);
if (MACHINE_HAS_IEEE)
asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
@@ -686,19 +661,19 @@ static void data_exception(struct pt_regs * regs, long interruption_code)
signal = SIGILL;
if (signal == SIGFPE)
do_fp_trap(regs, location,
- current->thread.fp_regs.fpc, interruption_code);
+ current->thread.fp_regs.fpc, pgm_int_code);
else if (signal) {
siginfo_t info;
info.si_signo = signal;
info.si_errno = 0;
info.si_code = ILL_ILLOPN;
info.si_addr = location;
- do_trap(interruption_code, signal,
- "data exception", regs, &info);
+ do_trap(pgm_int_code, signal, "data exception", regs, &info);
}
}
-static void space_switch_exception(struct pt_regs * regs, long int_code)
+static void space_switch_exception(struct pt_regs *regs, long pgm_int_code,
+ unsigned long trans_exc_code)
{
siginfo_t info;
@@ -709,8 +684,8 @@ static void space_switch_exception(struct pt_regs * regs, long int_code)
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_PRVOPC;
- info.si_addr = get_check_address(regs);
- do_trap(int_code, SIGILL, "space switch event", regs, &info);
+ info.si_addr = get_psw_address(regs, pgm_int_code);
+ do_trap(pgm_int_code, SIGILL, "space switch event", regs, &info);
}
asmlinkage void kernel_stack_overflow(struct pt_regs * regs)
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index 6b83870507d5..e3150dd2fe74 100644
--- a/arch/s390/kernel/vdso.c
+++ b/arch/s390/kernel/vdso.c
@@ -84,11 +84,7 @@ struct vdso_data *vdso_data = &vdso_data_store.data;
*/
static void vdso_init_data(struct vdso_data *vd)
{
- unsigned int facility_list;
-
- facility_list = stfl();
- vd->ectg_available =
- user_mode != HOME_SPACE_MODE && (facility_list & 1);
+ vd->ectg_available = user_mode != HOME_SPACE_MODE && test_facility(31);
}
#ifdef CONFIG_64BIT
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index 3479f1b0d4e0..56c8687b29b3 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -314,7 +314,8 @@ static void do_callbacks(struct list_head *cb_list)
/*
* Handler for the virtual CPU timer.
*/
-static void do_cpu_timer_interrupt(__u16 error_code)
+static void do_cpu_timer_interrupt(unsigned int ext_int_code,
+ unsigned int param32, unsigned long param64)
{
struct vtimer_queue *vq;
struct vtimer_list *event, *tmp;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 4fe68650535c..985d825494f1 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -740,8 +740,8 @@ static int __init kvm_s390_init(void)
kvm_exit();
return -ENOMEM;
}
- stfle(facilities, 1);
- facilities[0] &= 0xff00fff3f0700000ULL;
+ memcpy(facilities, S390_lowcore.stfle_fac_list, 16);
+ facilities[0] &= 0xff00fff3f47c0000ULL;
return 0;
}
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 44205507717c..9194a4b52b22 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -154,12 +154,12 @@ static int handle_chsc(struct kvm_vcpu *vcpu)
static int handle_stfl(struct kvm_vcpu *vcpu)
{
- unsigned int facility_list = stfl();
+ unsigned int facility_list;
int rc;
vcpu->stat.instruction_stfl++;
/* only pass the facility bits, which we can handle */
- facility_list &= 0xff00fff3;
+ facility_list = S390_lowcore.stfl_fac_list & 0xff00fff3;
rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
&facility_list, sizeof(facility_list));
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile
index eec054484419..6fbc6f3fbdf2 100644
--- a/arch/s390/mm/Makefile
+++ b/arch/s390/mm/Makefile
@@ -3,6 +3,6 @@
#
obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o \
- page-states.o
+ page-states.o gup.o
obj-$(CONFIG_CMM) += cmm.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c
index a9550dca3e4b..c66ffd8dbbb7 100644
--- a/arch/s390/mm/cmm.c
+++ b/arch/s390/mm/cmm.c
@@ -23,7 +23,10 @@
#include <asm/pgalloc.h>
#include <asm/diag.h>
-static char *sender = "VMRMSVM";
+#ifdef CONFIG_CMM_IUCV
+static char *cmm_default_sender = "VMRMSVM";
+#endif
+static char *sender;
module_param(sender, charp, 0400);
MODULE_PARM_DESC(sender,
"Guest name that may send SMSG messages (default VMRMSVM)");
@@ -440,6 +443,8 @@ static int __init cmm_init(void)
int len = strlen(sender);
while (len--)
sender[len] = toupper(sender[len]);
+ } else {
+ sender = cmm_default_sender;
}
rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 2505b2ea0ef1..fe5701e9efbf 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -52,6 +52,14 @@
#define VM_FAULT_BADMAP 0x020000
#define VM_FAULT_BADACCESS 0x040000
+static unsigned long store_indication;
+
+void fault_init(void)
+{
+ if (test_facility(2) && test_facility(75))
+ store_indication = 0xc00;
+}
+
static inline int notify_page_fault(struct pt_regs *regs)
{
int ret = 0;
@@ -199,14 +207,21 @@ static noinline void do_sigbus(struct pt_regs *regs, long int_code,
unsigned long trans_exc_code)
{
struct task_struct *tsk = current;
+ unsigned long address;
+ struct siginfo si;
/*
* Send a sigbus, regardless of whether we were in kernel
* or user mode.
*/
- tsk->thread.prot_addr = trans_exc_code & __FAIL_ADDR_MASK;
+ address = trans_exc_code & __FAIL_ADDR_MASK;
+ tsk->thread.prot_addr = address;
tsk->thread.trap_no = int_code;
- force_sig(SIGBUS, tsk);
+ si.si_signo = SIGBUS;
+ si.si_errno = 0;
+ si.si_code = BUS_ADRERR;
+ si.si_addr = (void __user *) address;
+ force_sig_info(SIGBUS, &si, tsk);
}
#ifdef CONFIG_S390_EXEC_PROTECT
@@ -266,10 +281,11 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code,
if (fault & VM_FAULT_OOM)
pagefault_out_of_memory();
else if (fault & VM_FAULT_SIGBUS) {
- do_sigbus(regs, int_code, trans_exc_code);
/* Kernel mode? Handle exceptions or die */
if (!(regs->psw.mask & PSW_MASK_PSTATE))
do_no_context(regs, int_code, trans_exc_code);
+ else
+ do_sigbus(regs, int_code, trans_exc_code);
} else
BUG();
break;
@@ -294,7 +310,7 @@ static inline int do_exception(struct pt_regs *regs, int access,
struct mm_struct *mm;
struct vm_area_struct *vma;
unsigned long address;
- int fault;
+ int fault, write;
if (notify_page_fault(regs))
return 0;
@@ -312,12 +328,6 @@ static inline int do_exception(struct pt_regs *regs, int access,
goto out;
address = trans_exc_code & __FAIL_ADDR_MASK;
- /*
- * When we get here, the fault happened in the current
- * task's user address space, so we can switch on the
- * interrupts again and then search the VMAs
- */
- local_irq_enable();
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
down_read(&mm->mmap_sem);
@@ -348,8 +358,10 @@ static inline int do_exception(struct pt_regs *regs, int access,
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- fault = handle_mm_fault(mm, vma, address,
- (access == VM_WRITE) ? FAULT_FLAG_WRITE : 0);
+ write = (access == VM_WRITE ||
+ (trans_exc_code & store_indication) == 0x400) ?
+ FAULT_FLAG_WRITE : 0;
+ fault = handle_mm_fault(mm, vma, address, write);
if (unlikely(fault & VM_FAULT_ERROR))
goto out_up;
@@ -374,20 +386,20 @@ out:
return fault;
}
-void __kprobes do_protection_exception(struct pt_regs *regs, long int_code)
+void __kprobes do_protection_exception(struct pt_regs *regs, long pgm_int_code,
+ unsigned long trans_exc_code)
{
- unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
int fault;
/* Protection exception is supressing, decrement psw address. */
- regs->psw.addr -= (int_code >> 16);
+ regs->psw.addr -= (pgm_int_code >> 16);
/*
* Check for low-address protection. This needs to be treated
* as a special case because the translation exception code
* field is not guaranteed to contain valid data in this case.
*/
if (unlikely(!(trans_exc_code & 4))) {
- do_low_address(regs, int_code, trans_exc_code);
+ do_low_address(regs, pgm_int_code, trans_exc_code);
return;
}
fault = do_exception(regs, VM_WRITE, trans_exc_code);
@@ -395,9 +407,9 @@ void __kprobes do_protection_exception(struct pt_regs *regs, long int_code)
do_fault_error(regs, 4, trans_exc_code, fault);
}
-void __kprobes do_dat_exception(struct pt_regs *regs, long int_code)
+void __kprobes do_dat_exception(struct pt_regs *regs, long pgm_int_code,
+ unsigned long trans_exc_code)
{
- unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
int access, fault;
access = VM_READ | VM_EXEC | VM_WRITE;
@@ -408,21 +420,19 @@ void __kprobes do_dat_exception(struct pt_regs *regs, long int_code)
#endif
fault = do_exception(regs, access, trans_exc_code);
if (unlikely(fault))
- do_fault_error(regs, int_code & 255, trans_exc_code, fault);
+ do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault);
}
#ifdef CONFIG_64BIT
-void __kprobes do_asce_exception(struct pt_regs *regs, long int_code)
+void __kprobes do_asce_exception(struct pt_regs *regs, long pgm_int_code,
+ unsigned long trans_exc_code)
{
- unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
goto no_context;
- local_irq_enable();
-
down_read(&mm->mmap_sem);
vma = find_vma(mm, trans_exc_code & __FAIL_ADDR_MASK);
up_read(&mm->mmap_sem);
@@ -434,16 +444,16 @@ void __kprobes do_asce_exception(struct pt_regs *regs, long int_code)
/* User mode accesses just cause a SIGSEGV */
if (regs->psw.mask & PSW_MASK_PSTATE) {
- do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code);
+ do_sigsegv(regs, pgm_int_code, SEGV_MAPERR, trans_exc_code);
return;
}
no_context:
- do_no_context(regs, int_code, trans_exc_code);
+ do_no_context(regs, pgm_int_code, trans_exc_code);
}
#endif
-int __handle_fault(unsigned long uaddr, unsigned long int_code, int write_user)
+int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
{
struct pt_regs regs;
int access, fault;
@@ -454,14 +464,14 @@ int __handle_fault(unsigned long uaddr, unsigned long int_code, int write_user)
regs.psw.addr = (unsigned long) __builtin_return_address(0);
regs.psw.addr |= PSW_ADDR_AMODE;
uaddr &= PAGE_MASK;
- access = write_user ? VM_WRITE : VM_READ;
+ access = write ? VM_WRITE : VM_READ;
fault = do_exception(&regs, access, uaddr | 2);
if (unlikely(fault)) {
if (fault & VM_FAULT_OOM) {
pagefault_out_of_memory();
fault = 0;
} else if (fault & VM_FAULT_SIGBUS)
- do_sigbus(&regs, int_code, uaddr);
+ do_sigbus(&regs, pgm_int_code, uaddr);
}
return fault ? -EFAULT : 0;
}
@@ -527,7 +537,8 @@ void pfault_fini(void)
: : "a" (&refbk), "m" (refbk) : "cc");
}
-static void pfault_interrupt(__u16 int_code)
+static void pfault_interrupt(unsigned int ext_int_code,
+ unsigned int param32, unsigned long param64)
{
struct task_struct *tsk;
__u16 subcode;
@@ -538,14 +549,18 @@ static void pfault_interrupt(__u16 int_code)
* in the 'cpu address' field associated with the
* external interrupt.
*/
- subcode = S390_lowcore.cpu_addr;
+ subcode = ext_int_code >> 16;
if ((subcode & 0xff00) != __SUBCODE_MASK)
return;
/*
* Get the token (= address of the task structure of the affected task).
*/
- tsk = *(struct task_struct **) __LC_PFAULT_INTPARM;
+#ifdef CONFIG_64BIT
+ tsk = *(struct task_struct **) param64;
+#else
+ tsk = *(struct task_struct **) param32;
+#endif
if (subcode & 0x0080) {
/* signal bit is set -> a page has been swapped in by VM */
diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c
new file mode 100644
index 000000000000..38e641cdd977
--- /dev/null
+++ b/arch/s390/mm/gup.c
@@ -0,0 +1,225 @@
+/*
+ * Lockless get_user_pages_fast for s390
+ *
+ * Copyright IBM Corp. 2010
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/vmstat.h>
+#include <linux/pagemap.h>
+#include <linux/rwsem.h>
+#include <asm/pgtable.h>
+
+/*
+ * The performance critical leaf functions are made noinline otherwise gcc
+ * inlines everything into a single function which results in too much
+ * register pressure.
+ */
+static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
+ unsigned long end, int write, struct page **pages, int *nr)
+{
+ unsigned long mask, result;
+ pte_t *ptep, pte;
+ struct page *page;
+
+ result = write ? 0 : _PAGE_RO;
+ mask = result | _PAGE_INVALID | _PAGE_SPECIAL;
+
+ ptep = ((pte_t *) pmd_deref(pmd)) + pte_index(addr);
+ do {
+ pte = *ptep;
+ barrier();
+ if ((pte_val(pte) & mask) != result)
+ return 0;
+ VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+ page = pte_page(pte);
+ if (!page_cache_get_speculative(page))
+ return 0;
+ if (unlikely(pte_val(pte) != pte_val(*ptep))) {
+ put_page(page);
+ return 0;
+ }
+ pages[*nr] = page;
+ (*nr)++;
+
+ } while (ptep++, addr += PAGE_SIZE, addr != end);
+
+ return 1;
+}
+
+static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
+ unsigned long end, int write, struct page **pages, int *nr)
+{
+ unsigned long mask, result;
+ struct page *head, *page;
+ int refs;
+
+ result = write ? 0 : _SEGMENT_ENTRY_RO;
+ mask = result | _SEGMENT_ENTRY_INV;
+ if ((pmd_val(pmd) & mask) != result)
+ return 0;
+ VM_BUG_ON(!pfn_valid(pmd_val(pmd) >> PAGE_SHIFT));
+
+ refs = 0;
+ head = pmd_page(pmd);
+ page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
+ do {
+ VM_BUG_ON(compound_head(page) != head);
+ pages[*nr] = page;
+ (*nr)++;
+ page++;
+ refs++;
+ } while (addr += PAGE_SIZE, addr != end);
+
+ if (!page_cache_add_speculative(head, refs)) {
+ *nr -= refs;
+ return 0;
+ }
+
+ if (unlikely(pmd_val(pmd) != pmd_val(*pmdp))) {
+ *nr -= refs;
+ while (refs--)
+ put_page(head);
+ }
+
+ return 1;
+}
+
+
+static inline int gup_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr,
+ unsigned long end, int write, struct page **pages, int *nr)
+{
+ unsigned long next;
+ pmd_t *pmdp, pmd;
+
+ pmdp = (pmd_t *) pudp;
+#ifdef CONFIG_64BIT
+ if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
+ pmdp = (pmd_t *) pud_deref(pud);
+ pmdp += pmd_index(addr);
+#endif
+ do {
+ pmd = *pmdp;
+ barrier();
+ next = pmd_addr_end(addr, end);
+ if (pmd_none(pmd))
+ return 0;
+ if (unlikely(pmd_huge(pmd))) {
+ if (!gup_huge_pmd(pmdp, pmd, addr, next,
+ write, pages, nr))
+ return 0;
+ } else if (!gup_pte_range(pmdp, pmd, addr, next,
+ write, pages, nr))
+ return 0;
+ } while (pmdp++, addr = next, addr != end);
+
+ return 1;
+}
+
+static inline int gup_pud_range(pgd_t *pgdp, pgd_t pgd, unsigned long addr,
+ unsigned long end, int write, struct page **pages, int *nr)
+{
+ unsigned long next;
+ pud_t *pudp, pud;
+
+ pudp = (pud_t *) pgdp;
+#ifdef CONFIG_64BIT
+ if ((pgd_val(pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2)
+ pudp = (pud_t *) pgd_deref(pgd);
+ pudp += pud_index(addr);
+#endif
+ do {
+ pud = *pudp;
+ barrier();
+ next = pud_addr_end(addr, end);
+ if (pud_none(pud))
+ return 0;
+ if (!gup_pmd_range(pudp, pud, addr, next, write, pages, nr))
+ return 0;
+ } while (pudp++, addr = next, addr != end);
+
+ return 1;
+}
+
+/**
+ * get_user_pages_fast() - pin user pages in memory
+ * @start: starting user address
+ * @nr_pages: number of pages from start to pin
+ * @write: whether pages will be written to
+ * @pages: array that receives pointers to the pages pinned.
+ * Should be at least nr_pages long.
+ *
+ * Attempt to pin user pages in memory without taking mm->mmap_sem.
+ * If not successful, it will fall back to taking the lock and
+ * calling get_user_pages().
+ *
+ * Returns number of pages pinned. This may be fewer than the number
+ * requested. If nr_pages is 0 or negative, returns 0. If no pages
+ * were pinned, returns -errno.
+ */
+int get_user_pages_fast(unsigned long start, int nr_pages, int write,
+ struct page **pages)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long addr, len, end;
+ unsigned long next;
+ pgd_t *pgdp, pgd;
+ int nr = 0;
+
+ start &= PAGE_MASK;
+ addr = start;
+ len = (unsigned long) nr_pages << PAGE_SHIFT;
+ end = start + len;
+ if (end < start)
+ goto slow_irqon;
+
+ /*
+ * local_irq_disable() doesn't prevent pagetable teardown, but does
+ * prevent the pagetables from being freed on s390.
+ *
+ * So long as we atomically load page table pointers versus teardown,
+ * we can follow the address down to the the page and take a ref on it.
+ */
+ local_irq_disable();
+ pgdp = pgd_offset(mm, addr);
+ do {
+ pgd = *pgdp;
+ barrier();
+ next = pgd_addr_end(addr, end);
+ if (pgd_none(pgd))
+ goto slow;
+ if (!gup_pud_range(pgdp, pgd, addr, next, write, pages, &nr))
+ goto slow;
+ } while (pgdp++, addr = next, addr != end);
+ local_irq_enable();
+
+ VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT);
+ return nr;
+
+ {
+ int ret;
+slow:
+ local_irq_enable();
+slow_irqon:
+ /* Try to get the remaining pages with get_user_pages */
+ start += nr << PAGE_SHIFT;
+ pages += nr;
+
+ down_read(&mm->mmap_sem);
+ ret = get_user_pages(current, mm, start,
+ (end - start) >> PAGE_SHIFT, write, 0, pages, NULL);
+ up_read(&mm->mmap_sem);
+
+ /* Have to be a bit careful with return values */
+ if (nr > 0) {
+ if (ret < 0)
+ ret = nr;
+ else
+ ret += nr;
+ }
+
+ return ret;
+ }
+}
diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c
index f28c43d2f61d..639cd21f2218 100644
--- a/arch/s390/mm/hugetlbpage.c
+++ b/arch/s390/mm/hugetlbpage.c
@@ -68,7 +68,7 @@ void arch_release_hugepage(struct page *page)
ptep = (pte_t *) page[1].index;
if (!ptep)
return;
- pte_free(&init_mm, ptep);
+ page_table_free(&init_mm, (unsigned long *) ptep);
page[1].index = 0;
}
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 94b8ba2ec857..bb409332a484 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -38,13 +38,54 @@
#include <asm/tlbflush.h>
#include <asm/sections.h>
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
-char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+unsigned long empty_zero_page, zero_page_mask;
EXPORT_SYMBOL(empty_zero_page);
+static unsigned long setup_zero_pages(void)
+{
+ struct cpuid cpu_id;
+ unsigned int order;
+ unsigned long size;
+ struct page *page;
+ int i;
+
+ get_cpu_id(&cpu_id);
+ switch (cpu_id.machine) {
+ case 0x9672: /* g5 */
+ case 0x2064: /* z900 */
+ case 0x2066: /* z900 */
+ case 0x2084: /* z990 */
+ case 0x2086: /* z990 */
+ case 0x2094: /* z9-109 */
+ case 0x2096: /* z9-109 */
+ order = 0;
+ break;
+ case 0x2097: /* z10 */
+ case 0x2098: /* z10 */
+ default:
+ order = 2;
+ break;
+ }
+
+ empty_zero_page = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
+ if (!empty_zero_page)
+ panic("Out of memory in setup_zero_pages");
+
+ page = virt_to_page((void *) empty_zero_page);
+ split_page(page, order);
+ for (i = 1 << order; i > 0; i--) {
+ SetPageReserved(page);
+ page++;
+ }
+
+ size = PAGE_SIZE << order;
+ zero_page_mask = (size - 1) & PAGE_MASK;
+
+ return 1UL << order;
+}
+
/*
* paging_init() sets up the page tables
*/
@@ -83,6 +124,7 @@ void __init paging_init(void)
#endif
max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
free_area_init_nodes(max_zone_pfns);
+ fault_init();
}
void __init mem_init(void)
@@ -92,14 +134,12 @@ void __init mem_init(void)
max_mapnr = num_physpages = max_low_pfn;
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
- /* clear the zero-page */
- memset(empty_zero_page, 0, PAGE_SIZE);
-
/* Setup guest page hinting */
cmma_init();
/* this will put all low memory onto the freelists */
totalram_pages += free_all_bootmem();
+ totalram_pages -= setup_zero_pages(); /* Setup zeroed pages. */
reservedpages = 0;
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 8d999249d357..0c719c61972e 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -15,6 +15,7 @@
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/quicklist.h>
+#include <linux/rcupdate.h>
#include <asm/system.h>
#include <asm/pgtable.h>
@@ -23,6 +24,67 @@
#include <asm/tlbflush.h>
#include <asm/mmu_context.h>
+struct rcu_table_freelist {
+ struct rcu_head rcu;
+ struct mm_struct *mm;
+ unsigned int pgt_index;
+ unsigned int crst_index;
+ unsigned long *table[0];
+};
+
+#define RCU_FREELIST_SIZE \
+ ((PAGE_SIZE - sizeof(struct rcu_table_freelist)) \
+ / sizeof(unsigned long))
+
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+static DEFINE_PER_CPU(struct rcu_table_freelist *, rcu_table_freelist);
+
+static void __page_table_free(struct mm_struct *mm, unsigned long *table);
+static void __crst_table_free(struct mm_struct *mm, unsigned long *table);
+
+static struct rcu_table_freelist *rcu_table_freelist_get(struct mm_struct *mm)
+{
+ struct rcu_table_freelist **batchp = &__get_cpu_var(rcu_table_freelist);
+ struct rcu_table_freelist *batch = *batchp;
+
+ if (batch)
+ return batch;
+ batch = (struct rcu_table_freelist *) __get_free_page(GFP_ATOMIC);
+ if (batch) {
+ batch->mm = mm;
+ batch->pgt_index = 0;
+ batch->crst_index = RCU_FREELIST_SIZE;
+ *batchp = batch;
+ }
+ return batch;
+}
+
+static void rcu_table_freelist_callback(struct rcu_head *head)
+{
+ struct rcu_table_freelist *batch =
+ container_of(head, struct rcu_table_freelist, rcu);
+
+ while (batch->pgt_index > 0)
+ __page_table_free(batch->mm, batch->table[--batch->pgt_index]);
+ while (batch->crst_index < RCU_FREELIST_SIZE)
+ __crst_table_free(batch->mm, batch->table[batch->crst_index++]);
+ free_page((unsigned long) batch);
+}
+
+void rcu_table_freelist_finish(void)
+{
+ struct rcu_table_freelist *batch = __get_cpu_var(rcu_table_freelist);
+
+ if (!batch)
+ return;
+ call_rcu(&batch->rcu, rcu_table_freelist_callback);
+ __get_cpu_var(rcu_table_freelist) = NULL;
+}
+
+static void smp_sync(void *arg)
+{
+}
+
#ifndef CONFIG_64BIT
#define ALLOC_ORDER 1
#define TABLES_PER_PAGE 4
@@ -78,25 +140,55 @@ unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec)
}
page->index = page_to_phys(shadow);
}
- spin_lock(&mm->context.list_lock);
+ spin_lock_bh(&mm->context.list_lock);
list_add(&page->lru, &mm->context.crst_list);
- spin_unlock(&mm->context.list_lock);
+ spin_unlock_bh(&mm->context.list_lock);
return (unsigned long *) page_to_phys(page);
}
-void crst_table_free(struct mm_struct *mm, unsigned long *table)
+static void __crst_table_free(struct mm_struct *mm, unsigned long *table)
{
unsigned long *shadow = get_shadow_table(table);
- struct page *page = virt_to_page(table);
- spin_lock(&mm->context.list_lock);
- list_del(&page->lru);
- spin_unlock(&mm->context.list_lock);
if (shadow)
free_pages((unsigned long) shadow, ALLOC_ORDER);
free_pages((unsigned long) table, ALLOC_ORDER);
}
+void crst_table_free(struct mm_struct *mm, unsigned long *table)
+{
+ struct page *page = virt_to_page(table);
+
+ spin_lock_bh(&mm->context.list_lock);
+ list_del(&page->lru);
+ spin_unlock_bh(&mm->context.list_lock);
+ __crst_table_free(mm, table);
+}
+
+void crst_table_free_rcu(struct mm_struct *mm, unsigned long *table)
+{
+ struct rcu_table_freelist *batch;
+ struct page *page = virt_to_page(table);
+
+ spin_lock_bh(&mm->context.list_lock);
+ list_del(&page->lru);
+ spin_unlock_bh(&mm->context.list_lock);
+ if (atomic_read(&mm->mm_users) < 2 &&
+ cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
+ __crst_table_free(mm, table);
+ return;
+ }
+ batch = rcu_table_freelist_get(mm);
+ if (!batch) {
+ smp_call_function(smp_sync, NULL, 1);
+ __crst_table_free(mm, table);
+ return;
+ }
+ batch->table[--batch->crst_index] = table;
+ if (batch->pgt_index >= batch->crst_index)
+ rcu_table_freelist_finish();
+}
+
#ifdef CONFIG_64BIT
int crst_table_upgrade(struct mm_struct *mm, unsigned long limit)
{
@@ -108,7 +200,7 @@ repeat:
table = crst_table_alloc(mm, mm->context.noexec);
if (!table)
return -ENOMEM;
- spin_lock(&mm->page_table_lock);
+ spin_lock_bh(&mm->page_table_lock);
if (mm->context.asce_limit < limit) {
pgd = (unsigned long *) mm->pgd;
if (mm->context.asce_limit <= (1UL << 31)) {
@@ -130,7 +222,7 @@ repeat:
mm->task_size = mm->context.asce_limit;
table = NULL;
}
- spin_unlock(&mm->page_table_lock);
+ spin_unlock_bh(&mm->page_table_lock);
if (table)
crst_table_free(mm, table);
if (mm->context.asce_limit < limit)
@@ -182,7 +274,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
unsigned long bits;
bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
- spin_lock(&mm->context.list_lock);
+ spin_lock_bh(&mm->context.list_lock);
page = NULL;
if (!list_empty(&mm->context.pgtable_list)) {
page = list_first_entry(&mm->context.pgtable_list,
@@ -191,7 +283,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
page = NULL;
}
if (!page) {
- spin_unlock(&mm->context.list_lock);
+ spin_unlock_bh(&mm->context.list_lock);
page = alloc_page(GFP_KERNEL|__GFP_REPEAT);
if (!page)
return NULL;
@@ -202,7 +294,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
clear_table_pgstes(table);
else
clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
- spin_lock(&mm->context.list_lock);
+ spin_lock_bh(&mm->context.list_lock);
list_add(&page->lru, &mm->context.pgtable_list);
}
table = (unsigned long *) page_to_phys(page);
@@ -213,10 +305,25 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
page->flags |= bits;
if ((page->flags & FRAG_MASK) == ((1UL << TABLES_PER_PAGE) - 1))
list_move_tail(&page->lru, &mm->context.pgtable_list);
- spin_unlock(&mm->context.list_lock);
+ spin_unlock_bh(&mm->context.list_lock);
return table;
}
+static void __page_table_free(struct mm_struct *mm, unsigned long *table)
+{
+ struct page *page;
+ unsigned long bits;
+
+ bits = ((unsigned long) table) & 15;
+ table = (unsigned long *)(((unsigned long) table) ^ bits);
+ page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+ page->flags ^= bits;
+ if (!(page->flags & FRAG_MASK)) {
+ pgtable_page_dtor(page);
+ __free_page(page);
+ }
+}
+
void page_table_free(struct mm_struct *mm, unsigned long *table)
{
struct page *page;
@@ -225,7 +332,7 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
- spin_lock(&mm->context.list_lock);
+ spin_lock_bh(&mm->context.list_lock);
page->flags ^= bits;
if (page->flags & FRAG_MASK) {
/* Page now has some free pgtable fragments. */
@@ -234,18 +341,48 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
} else
/* All fragments of the 4K page have been freed. */
list_del(&page->lru);
- spin_unlock(&mm->context.list_lock);
+ spin_unlock_bh(&mm->context.list_lock);
if (page) {
pgtable_page_dtor(page);
__free_page(page);
}
}
+void page_table_free_rcu(struct mm_struct *mm, unsigned long *table)
+{
+ struct rcu_table_freelist *batch;
+ struct page *page;
+ unsigned long bits;
+
+ if (atomic_read(&mm->mm_users) < 2 &&
+ cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
+ page_table_free(mm, table);
+ return;
+ }
+ batch = rcu_table_freelist_get(mm);
+ if (!batch) {
+ smp_call_function(smp_sync, NULL, 1);
+ page_table_free(mm, table);
+ return;
+ }
+ bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
+ bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
+ page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+ spin_lock_bh(&mm->context.list_lock);
+ /* Delayed freeing with rcu prevents reuse of pgtable fragments */
+ list_del_init(&page->lru);
+ spin_unlock_bh(&mm->context.list_lock);
+ table = (unsigned long *)(((unsigned long) table) | bits);
+ batch->table[batch->pgt_index++] = table;
+ if (batch->pgt_index >= batch->crst_index)
+ rcu_table_freelist_finish();
+}
+
void disable_noexec(struct mm_struct *mm, struct task_struct *tsk)
{
struct page *page;
- spin_lock(&mm->context.list_lock);
+ spin_lock_bh(&mm->context.list_lock);
/* Free shadow region and segment tables. */
list_for_each_entry(page, &mm->context.crst_list, lru)
if (page->index) {
@@ -255,7 +392,7 @@ void disable_noexec(struct mm_struct *mm, struct task_struct *tsk)
/* "Free" second halves of page tables. */
list_for_each_entry(page, &mm->context.pgtable_list, lru)
page->flags &= ~SECOND_HALVES;
- spin_unlock(&mm->context.list_lock);
+ spin_unlock_bh(&mm->context.list_lock);
mm->context.noexec = 0;
update_mm(mm, tsk);
}
@@ -312,6 +449,8 @@ int s390_enable_sie(void)
tsk->mm = tsk->active_mm = mm;
preempt_disable();
update_mm(mm, tsk);
+ atomic_inc(&mm->context.attach_count);
+ atomic_dec(&old_mm->context.attach_count);
cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
preempt_enable();
task_unlock(tsk);
diff --git a/arch/score/include/asm/pgtable.h b/arch/score/include/asm/pgtable.h
index ccf38f06c57d..2fd469807683 100644
--- a/arch/score/include/asm/pgtable.h
+++ b/arch/score/include/asm/pgtable.h
@@ -88,10 +88,7 @@ static inline void pmd_clear(pmd_t *pmdp)
#define pte_offset_map(dir, address) \
((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
-#define pte_offset_map_nested(dir, address) \
- ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
#define pte_unmap(pte) ((void)(pte))
-#define pte_unmap_nested(pte) ((void)(pte))
/*
* Bits 9(_PAGE_PRESENT) and 10(_PAGE_FILE)are taken,
diff --git a/arch/score/kernel/ptrace.c b/arch/score/kernel/ptrace.c
index 174c6422b096..55836188b217 100644
--- a/arch/score/kernel/ptrace.c
+++ b/arch/score/kernel/ptrace.c
@@ -325,7 +325,8 @@ void ptrace_disable(struct task_struct *child)
}
long
-arch_ptrace(struct task_struct *child, long request, long addr, long data)
+arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret;
unsigned long __user *datap = (void __user *)data;
@@ -335,14 +336,14 @@ arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = copy_regset_to_user(child, &user_score_native_view,
REGSET_GENERAL,
0, sizeof(struct pt_regs),
- (void __user *)datap);
+ datap);
break;
case PTRACE_SETREGS:
ret = copy_regset_from_user(child, &user_score_native_view,
REGSET_GENERAL,
0, sizeof(struct pt_regs),
- (const void __user *)datap);
+ datap);
break;
default:
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 35b6879628a0..0f40fc35d0a2 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -24,6 +24,7 @@ config SUPERH
select HAVE_KERNEL_LZMA
select HAVE_KERNEL_LZO
select HAVE_SYSCALL_TRACEPOINTS
+ select HAVE_REGS_AND_STACK_ACCESS_API
select RTC_LIB
select GENERIC_ATOMIC64
help
@@ -46,7 +47,7 @@ config SUPERH32
select HAVE_ARCH_KGDB
select HAVE_HW_BREAKPOINT
select HAVE_MIXED_BREAKPOINTS_REGS
- select PERF_EVENTS if HAVE_HW_BREAKPOINT
+ select PERF_EVENTS
select ARCH_HIBERNATION_POSSIBLE if MMU
config SUPERH64
@@ -471,6 +472,7 @@ config CPU_SUBTYPE_SHX3
select CPU_SH4A
select CPU_SHX3
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+ select ARCH_REQUIRE_GPIOLIB
# SH4AL-DSP Processor Support
@@ -575,7 +577,7 @@ config SH_CLK_CPG
config SH_CLK_CPG_LEGACY
depends on SH_CLK_CPG
def_bool y if !CPU_SUBTYPE_SH7785 && !ARCH_SHMOBILE && \
- !CPU_SUBTYPE_SH7786
+ !CPU_SHX3 && !CPU_SUBTYPE_SH7757
config SH_CLK_MD
int "CPU Mode Pin Setting"
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index 07b35ca2f644..9c94711aa6ca 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -155,6 +155,8 @@ config SH_SDK7786
depends on CPU_SUBTYPE_SH7786
select SYS_SUPPORTS_PCI
select NO_IOPORT if !PCI
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select HAVE_SRAM_POOL
help
Select SDK7786 if configuring for a Renesas Technology Europe
SH7786-65nm board.
@@ -165,6 +167,11 @@ config SH_HIGHLANDER
select SYS_SUPPORTS_PCI
select IO_TRAPPED if MMU
+config SH_SH7757LCR
+ bool "SH7757LCR"
+ depends on CPU_SUBTYPE_SH7757
+ select ARCH_REQUIRE_GPIOLIB
+
config SH_SH7785LCR
bool "SH7785LCR"
depends on CPU_SUBTYPE_SH7785
@@ -309,6 +316,17 @@ config SH_POLARIS
help
Select if configuring for an SMSC Polaris development board
+config SH_SH2007
+ bool "SH-2007 board"
+ select NO_IOPORT
+ depends on CPU_SUBTYPE_SH7780
+ help
+ SH-2007 is a single-board computer based around SH7780 chip
+ intended for embedded applications.
+ It has an Ethernet interface (SMC9118), direct connected
+ Compact Flash socket, two serial ports and PC-104 bus.
+ More information at <http://sh2000.sh-linux.org>.
+
endmenu
source "arch/sh/boards/mach-r2d/Kconfig"
diff --git a/arch/sh/boards/Makefile b/arch/sh/boards/Makefile
index 4f90f9b7a922..38ef655cc0f0 100644
--- a/arch/sh/boards/Makefile
+++ b/arch/sh/boards/Makefile
@@ -2,6 +2,7 @@
# Specific board support, not covered by a mach group.
#
obj-$(CONFIG_SH_MAGIC_PANEL_R2) += board-magicpanelr2.o
+obj-$(CONFIG_SH_SH2007) += board-sh2007.o
obj-$(CONFIG_SH_SH7785LCR) += board-sh7785lcr.o
obj-$(CONFIG_SH_URQUELL) += board-urquell.o
obj-$(CONFIG_SH_SHMIN) += board-shmin.o
@@ -9,3 +10,4 @@ obj-$(CONFIG_SH_EDOSK7760) += board-edosk7760.o
obj-$(CONFIG_SH_ESPT) += board-espt.o
obj-$(CONFIG_SH_POLARIS) += board-polaris.o
obj-$(CONFIG_SH_TITAN) += board-titan.o
+obj-$(CONFIG_SH_SH7757LCR) += board-sh7757lcr.o
diff --git a/arch/sh/boards/board-sh2007.c b/arch/sh/boards/board-sh2007.c
new file mode 100644
index 000000000000..b90b78f6a829
--- /dev/null
+++ b/arch/sh/boards/board-sh2007.c
@@ -0,0 +1,133 @@
+/*
+ * SH-2007 board support.
+ *
+ * Copyright (C) 2003, 2004 SUGIOKA Toshinobu
+ * Copyright (C) 2010 Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/smsc911x.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+#include <linux/io.h>
+#include <asm/machvec.h>
+#include <mach/sh2007.h>
+
+struct smsc911x_platform_config smc911x_info = {
+ .flags = SMSC911X_USE_32BIT,
+ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+ .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
+};
+
+static struct resource smsc9118_0_resources[] = {
+ [0] = {
+ .start = SMC0_BASE,
+ .end = SMC0_BASE + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x240),
+ .end = evt2irq(0x240),
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct resource smsc9118_1_resources[] = {
+ [0] = {
+ .start = SMC1_BASE,
+ .end = SMC1_BASE + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x280),
+ .end = evt2irq(0x280),
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device smsc9118_0_device = {
+ .name = "smsc911x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smsc9118_0_resources),
+ .resource = smsc9118_0_resources,
+ .dev = {
+ .platform_data = &smc911x_info,
+ },
+};
+
+static struct platform_device smsc9118_1_device = {
+ .name = "smsc911x",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(smsc9118_1_resources),
+ .resource = smsc9118_1_resources,
+ .dev = {
+ .platform_data = &smc911x_info,
+ },
+};
+
+static struct resource cf_resources[] = {
+ [0] = {
+ .start = CF_BASE + CF_OFFSET,
+ .end = CF_BASE + CF_OFFSET + 0x0f,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = CF_BASE + CF_OFFSET + 0x206,
+ .end = CF_BASE + CF_OFFSET + 0x20f,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = evt2irq(0x2c0),
+ .end = evt2irq(0x2c0),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cf_device = {
+ .name = "pata_platform",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(cf_resources),
+ .resource = cf_resources,
+};
+
+static struct platform_device *sh2007_devices[] __initdata = {
+ &smsc9118_0_device,
+ &smsc9118_1_device,
+ &cf_device,
+};
+
+static int __init sh2007_io_init(void)
+{
+ platform_add_devices(sh2007_devices, ARRAY_SIZE(sh2007_devices));
+ return 0;
+}
+subsys_initcall(sh2007_io_init);
+
+static void __init sh2007_init_irq(void)
+{
+ plat_irq_setup_pins(IRQ_MODE_IRQ);
+}
+
+/*
+ * Initialize the board
+ */
+static void __init sh2007_setup(char **cmdline_p)
+{
+ printk(KERN_INFO "SH-2007 Setup...");
+
+ /* setup wait control registers for area 5 */
+ __raw_writel(CS5BCR_D, CS5BCR);
+ __raw_writel(CS5WCR_D, CS5WCR);
+ __raw_writel(CS5PCR_D, CS5PCR);
+
+ printk(KERN_INFO " done.\n");
+}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_sh2007 __initmv = {
+ .mv_setup = sh2007_setup,
+ .mv_name = "sh2007",
+ .mv_init_irq = sh2007_init_irq,
+};
diff --git a/arch/sh/boards/board-sh7757lcr.c b/arch/sh/boards/board-sh7757lcr.c
new file mode 100644
index 000000000000..c475f1056ab4
--- /dev/null
+++ b/arch/sh/boards/board-sh7757lcr.c
@@ -0,0 +1,374 @@
+/*
+ * Renesas R0P7757LC0012RL Support.
+ *
+ * Copyright (C) 2009 - 2010 Renesas Solutions Corp.
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/io.h>
+#include <cpu/sh7757.h>
+#include <asm/sh_eth.h>
+#include <asm/heartbeat.h>
+
+static struct resource heartbeat_resource = {
+ .start = 0xffec005c, /* PUDR */
+ .end = 0xffec005c,
+ .flags = IORESOURCE_MEM | IORESOURCE_MEM_8BIT,
+};
+
+static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3 };
+
+static struct heartbeat_data heartbeat_data = {
+ .bit_pos = heartbeat_bit_pos,
+ .nr_bits = ARRAY_SIZE(heartbeat_bit_pos),
+ .flags = HEARTBEAT_INVERTED,
+};
+
+static struct platform_device heartbeat_device = {
+ .name = "heartbeat",
+ .id = -1,
+ .dev = {
+ .platform_data = &heartbeat_data,
+ },
+ .num_resources = 1,
+ .resource = &heartbeat_resource,
+};
+
+/* Fast Ethernet */
+static struct resource sh_eth0_resources[] = {
+ {
+ .start = 0xfef00000,
+ .end = 0xfef001ff,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = 84,
+ .end = 84,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct sh_eth_plat_data sh7757_eth0_pdata = {
+ .phy = 1,
+ .edmac_endian = EDMAC_LITTLE_ENDIAN,
+};
+
+static struct platform_device sh7757_eth0_device = {
+ .name = "sh-eth",
+ .resource = sh_eth0_resources,
+ .id = 0,
+ .num_resources = ARRAY_SIZE(sh_eth0_resources),
+ .dev = {
+ .platform_data = &sh7757_eth0_pdata,
+ },
+};
+
+static struct resource sh_eth1_resources[] = {
+ {
+ .start = 0xfef00800,
+ .end = 0xfef009ff,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = 84,
+ .end = 84,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct sh_eth_plat_data sh7757_eth1_pdata = {
+ .phy = 1,
+ .edmac_endian = EDMAC_LITTLE_ENDIAN,
+};
+
+static struct platform_device sh7757_eth1_device = {
+ .name = "sh-eth",
+ .resource = sh_eth1_resources,
+ .id = 1,
+ .num_resources = ARRAY_SIZE(sh_eth1_resources),
+ .dev = {
+ .platform_data = &sh7757_eth1_pdata,
+ },
+};
+
+static struct platform_device *sh7757lcr_devices[] __initdata = {
+ &heartbeat_device,
+ &sh7757_eth0_device,
+ &sh7757_eth1_device,
+};
+
+static int __init sh7757lcr_devices_setup(void)
+{
+ /* RGMII (PTA) */
+ gpio_request(GPIO_FN_ET0_MDC, NULL);
+ gpio_request(GPIO_FN_ET0_MDIO, NULL);
+ gpio_request(GPIO_FN_ET1_MDC, NULL);
+ gpio_request(GPIO_FN_ET1_MDIO, NULL);
+
+ /* ONFI (PTB, PTZ) */
+ gpio_request(GPIO_FN_ON_NRE, NULL);
+ gpio_request(GPIO_FN_ON_NWE, NULL);
+ gpio_request(GPIO_FN_ON_NWP, NULL);
+ gpio_request(GPIO_FN_ON_NCE0, NULL);
+ gpio_request(GPIO_FN_ON_R_B0, NULL);
+ gpio_request(GPIO_FN_ON_ALE, NULL);
+ gpio_request(GPIO_FN_ON_CLE, NULL);
+
+ gpio_request(GPIO_FN_ON_DQ7, NULL);
+ gpio_request(GPIO_FN_ON_DQ6, NULL);
+ gpio_request(GPIO_FN_ON_DQ5, NULL);
+ gpio_request(GPIO_FN_ON_DQ4, NULL);
+ gpio_request(GPIO_FN_ON_DQ3, NULL);
+ gpio_request(GPIO_FN_ON_DQ2, NULL);
+ gpio_request(GPIO_FN_ON_DQ1, NULL);
+ gpio_request(GPIO_FN_ON_DQ0, NULL);
+
+ /* IRQ8 to 0 (PTB, PTC) */
+ gpio_request(GPIO_FN_IRQ8, NULL);
+ gpio_request(GPIO_FN_IRQ7, NULL);
+ gpio_request(GPIO_FN_IRQ6, NULL);
+ gpio_request(GPIO_FN_IRQ5, NULL);
+ gpio_request(GPIO_FN_IRQ4, NULL);
+ gpio_request(GPIO_FN_IRQ3, NULL);
+ gpio_request(GPIO_FN_IRQ2, NULL);
+ gpio_request(GPIO_FN_IRQ1, NULL);
+ gpio_request(GPIO_FN_IRQ0, NULL);
+
+ /* SPI0 (PTD) */
+ gpio_request(GPIO_FN_SP0_MOSI, NULL);
+ gpio_request(GPIO_FN_SP0_MISO, NULL);
+ gpio_request(GPIO_FN_SP0_SCK, NULL);
+ gpio_request(GPIO_FN_SP0_SCK_FB, NULL);
+ gpio_request(GPIO_FN_SP0_SS0, NULL);
+ gpio_request(GPIO_FN_SP0_SS1, NULL);
+ gpio_request(GPIO_FN_SP0_SS2, NULL);
+ gpio_request(GPIO_FN_SP0_SS3, NULL);
+
+ /* RMII 0/1 (PTE, PTF) */
+ gpio_request(GPIO_FN_RMII0_CRS_DV, NULL);
+ gpio_request(GPIO_FN_RMII0_TXD1, NULL);
+ gpio_request(GPIO_FN_RMII0_TXD0, NULL);
+ gpio_request(GPIO_FN_RMII0_TXEN, NULL);
+ gpio_request(GPIO_FN_RMII0_REFCLK, NULL);
+ gpio_request(GPIO_FN_RMII0_RXD1, NULL);
+ gpio_request(GPIO_FN_RMII0_RXD0, NULL);
+ gpio_request(GPIO_FN_RMII0_RX_ER, NULL);
+ gpio_request(GPIO_FN_RMII1_CRS_DV, NULL);
+ gpio_request(GPIO_FN_RMII1_TXD1, NULL);
+ gpio_request(GPIO_FN_RMII1_TXD0, NULL);
+ gpio_request(GPIO_FN_RMII1_TXEN, NULL);
+ gpio_request(GPIO_FN_RMII1_REFCLK, NULL);
+ gpio_request(GPIO_FN_RMII1_RXD1, NULL);
+ gpio_request(GPIO_FN_RMII1_RXD0, NULL);
+ gpio_request(GPIO_FN_RMII1_RX_ER, NULL);
+
+ /* eMMC (PTG) */
+ gpio_request(GPIO_FN_MMCCLK, NULL);
+ gpio_request(GPIO_FN_MMCCMD, NULL);
+ gpio_request(GPIO_FN_MMCDAT7, NULL);
+ gpio_request(GPIO_FN_MMCDAT6, NULL);
+ gpio_request(GPIO_FN_MMCDAT5, NULL);
+ gpio_request(GPIO_FN_MMCDAT4, NULL);
+ gpio_request(GPIO_FN_MMCDAT3, NULL);
+ gpio_request(GPIO_FN_MMCDAT2, NULL);
+ gpio_request(GPIO_FN_MMCDAT1, NULL);
+ gpio_request(GPIO_FN_MMCDAT0, NULL);
+
+ /* LPC (PTG, PTH, PTQ, PTU) */
+ gpio_request(GPIO_FN_SERIRQ, NULL);
+ gpio_request(GPIO_FN_LPCPD, NULL);
+ gpio_request(GPIO_FN_LDRQ, NULL);
+ gpio_request(GPIO_FN_WP, NULL);
+ gpio_request(GPIO_FN_FMS0, NULL);
+ gpio_request(GPIO_FN_LAD3, NULL);
+ gpio_request(GPIO_FN_LAD2, NULL);
+ gpio_request(GPIO_FN_LAD1, NULL);
+ gpio_request(GPIO_FN_LAD0, NULL);
+ gpio_request(GPIO_FN_LFRAME, NULL);
+ gpio_request(GPIO_FN_LRESET, NULL);
+ gpio_request(GPIO_FN_LCLK, NULL);
+ gpio_request(GPIO_FN_LGPIO7, NULL);
+ gpio_request(GPIO_FN_LGPIO6, NULL);
+ gpio_request(GPIO_FN_LGPIO5, NULL);
+ gpio_request(GPIO_FN_LGPIO4, NULL);
+
+ /* SPI1 (PTH) */
+ gpio_request(GPIO_FN_SP1_MOSI, NULL);
+ gpio_request(GPIO_FN_SP1_MISO, NULL);
+ gpio_request(GPIO_FN_SP1_SCK, NULL);
+ gpio_request(GPIO_FN_SP1_SCK_FB, NULL);
+ gpio_request(GPIO_FN_SP1_SS0, NULL);
+ gpio_request(GPIO_FN_SP1_SS1, NULL);
+
+ /* SDHI (PTI) */
+ gpio_request(GPIO_FN_SD_WP, NULL);
+ gpio_request(GPIO_FN_SD_CD, NULL);
+ gpio_request(GPIO_FN_SD_CLK, NULL);
+ gpio_request(GPIO_FN_SD_CMD, NULL);
+ gpio_request(GPIO_FN_SD_D3, NULL);
+ gpio_request(GPIO_FN_SD_D2, NULL);
+ gpio_request(GPIO_FN_SD_D1, NULL);
+ gpio_request(GPIO_FN_SD_D0, NULL);
+
+ /* SCIF3/4 (PTJ, PTW) */
+ gpio_request(GPIO_FN_RTS3, NULL);
+ gpio_request(GPIO_FN_CTS3, NULL);
+ gpio_request(GPIO_FN_TXD3, NULL);
+ gpio_request(GPIO_FN_RXD3, NULL);
+ gpio_request(GPIO_FN_RTS4, NULL);
+ gpio_request(GPIO_FN_RXD4, NULL);
+ gpio_request(GPIO_FN_TXD4, NULL);
+ gpio_request(GPIO_FN_CTS4, NULL);
+
+ /* SERMUX (PTK, PTL, PTO, PTV) */
+ gpio_request(GPIO_FN_COM2_TXD, NULL);
+ gpio_request(GPIO_FN_COM2_RXD, NULL);
+ gpio_request(GPIO_FN_COM2_RTS, NULL);
+ gpio_request(GPIO_FN_COM2_CTS, NULL);
+ gpio_request(GPIO_FN_COM2_DTR, NULL);
+ gpio_request(GPIO_FN_COM2_DSR, NULL);
+ gpio_request(GPIO_FN_COM2_DCD, NULL);
+ gpio_request(GPIO_FN_COM2_RI, NULL);
+ gpio_request(GPIO_FN_RAC_RXD, NULL);
+ gpio_request(GPIO_FN_RAC_RTS, NULL);
+ gpio_request(GPIO_FN_RAC_CTS, NULL);
+ gpio_request(GPIO_FN_RAC_DTR, NULL);
+ gpio_request(GPIO_FN_RAC_DSR, NULL);
+ gpio_request(GPIO_FN_RAC_DCD, NULL);
+ gpio_request(GPIO_FN_RAC_TXD, NULL);
+ gpio_request(GPIO_FN_COM1_TXD, NULL);
+ gpio_request(GPIO_FN_COM1_RXD, NULL);
+ gpio_request(GPIO_FN_COM1_RTS, NULL);
+ gpio_request(GPIO_FN_COM1_CTS, NULL);
+
+ writeb(0x10, 0xfe470000); /* SMR0: SerMux mode 0 */
+
+ /* IIC (PTM, PTR, PTS) */
+ gpio_request(GPIO_FN_SDA7, NULL);
+ gpio_request(GPIO_FN_SCL7, NULL);
+ gpio_request(GPIO_FN_SDA6, NULL);
+ gpio_request(GPIO_FN_SCL6, NULL);
+ gpio_request(GPIO_FN_SDA5, NULL);
+ gpio_request(GPIO_FN_SCL5, NULL);
+ gpio_request(GPIO_FN_SDA4, NULL);
+ gpio_request(GPIO_FN_SCL4, NULL);
+ gpio_request(GPIO_FN_SDA3, NULL);
+ gpio_request(GPIO_FN_SCL3, NULL);
+ gpio_request(GPIO_FN_SDA2, NULL);
+ gpio_request(GPIO_FN_SCL2, NULL);
+ gpio_request(GPIO_FN_SDA1, NULL);
+ gpio_request(GPIO_FN_SCL1, NULL);
+ gpio_request(GPIO_FN_SDA0, NULL);
+ gpio_request(GPIO_FN_SCL0, NULL);
+
+ /* USB (PTN) */
+ gpio_request(GPIO_FN_VBUS_EN, NULL);
+ gpio_request(GPIO_FN_VBUS_OC, NULL);
+
+ /* SGPIO1/0 (PTN, PTO) */
+ gpio_request(GPIO_FN_SGPIO1_CLK, NULL);
+ gpio_request(GPIO_FN_SGPIO1_LOAD, NULL);
+ gpio_request(GPIO_FN_SGPIO1_DI, NULL);
+ gpio_request(GPIO_FN_SGPIO1_DO, NULL);
+ gpio_request(GPIO_FN_SGPIO0_CLK, NULL);
+ gpio_request(GPIO_FN_SGPIO0_LOAD, NULL);
+ gpio_request(GPIO_FN_SGPIO0_DI, NULL);
+ gpio_request(GPIO_FN_SGPIO0_DO, NULL);
+
+ /* WDT (PTN) */
+ gpio_request(GPIO_FN_SUB_CLKIN, NULL);
+
+ /* System (PTT) */
+ gpio_request(GPIO_FN_STATUS1, NULL);
+ gpio_request(GPIO_FN_STATUS0, NULL);
+
+ /* PWMX (PTT) */
+ gpio_request(GPIO_FN_PWMX1, NULL);
+ gpio_request(GPIO_FN_PWMX0, NULL);
+
+ /* R-SPI (PTV) */
+ gpio_request(GPIO_FN_R_SPI_MOSI, NULL);
+ gpio_request(GPIO_FN_R_SPI_MISO, NULL);
+ gpio_request(GPIO_FN_R_SPI_RSPCK, NULL);
+ gpio_request(GPIO_FN_R_SPI_SSL0, NULL);
+ gpio_request(GPIO_FN_R_SPI_SSL1, NULL);
+
+ /* EVC (PTV, PTW) */
+ gpio_request(GPIO_FN_EVENT7, NULL);
+ gpio_request(GPIO_FN_EVENT6, NULL);
+ gpio_request(GPIO_FN_EVENT5, NULL);
+ gpio_request(GPIO_FN_EVENT4, NULL);
+ gpio_request(GPIO_FN_EVENT3, NULL);
+ gpio_request(GPIO_FN_EVENT2, NULL);
+ gpio_request(GPIO_FN_EVENT1, NULL);
+ gpio_request(GPIO_FN_EVENT0, NULL);
+
+ /* LED for heartbeat */
+ gpio_request(GPIO_PTU3, NULL);
+ gpio_direction_output(GPIO_PTU3, 1);
+ gpio_request(GPIO_PTU2, NULL);
+ gpio_direction_output(GPIO_PTU2, 1);
+ gpio_request(GPIO_PTU1, NULL);
+ gpio_direction_output(GPIO_PTU1, 1);
+ gpio_request(GPIO_PTU0, NULL);
+ gpio_direction_output(GPIO_PTU0, 1);
+
+ /* control for MDIO of Gigabit Ethernet */
+ gpio_request(GPIO_PTT4, NULL);
+ gpio_direction_output(GPIO_PTT4, 1);
+
+ /* control for eMMC */
+ gpio_request(GPIO_PTT7, NULL); /* eMMC_RST# */
+ gpio_direction_output(GPIO_PTT7, 0);
+ gpio_request(GPIO_PTT6, NULL); /* eMMC_INDEX# */
+ gpio_direction_output(GPIO_PTT6, 0);
+ gpio_request(GPIO_PTT5, NULL); /* eMMC_PRST# */
+ gpio_direction_output(GPIO_PTT5, 1);
+
+ /* General platform */
+ return platform_add_devices(sh7757lcr_devices,
+ ARRAY_SIZE(sh7757lcr_devices));
+}
+arch_initcall(sh7757lcr_devices_setup);
+
+/* Initialize IRQ setting */
+void __init init_sh7757lcr_IRQ(void)
+{
+ plat_irq_setup_pins(IRQ_MODE_IRQ7654);
+ plat_irq_setup_pins(IRQ_MODE_IRQ3210);
+}
+
+/* Initialize the board */
+static void __init sh7757lcr_setup(char **cmdline_p)
+{
+ printk(KERN_INFO "Renesas R0P7757LC0012RL support.\n");
+}
+
+static int sh7757lcr_mode_pins(void)
+{
+ int value = 0;
+
+ /* These are the factory default settings of S3 (Low active).
+ * If you change these dip switches then you will need to
+ * adjust the values below as well.
+ */
+ value |= MODE_PIN0; /* Clock Mode: 1 */
+
+ return value;
+}
+
+/* The Machine Vector */
+static struct sh_machine_vector mv_sh7757lcr __initmv = {
+ .mv_name = "SH7757LCR",
+ .mv_setup = sh7757lcr_setup,
+ .mv_init_irq = init_sh7757lcr_IRQ,
+ .mv_mode_pins = sh7757lcr_mode_pins,
+};
+
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 1d7b495a7db4..71a3368ab1fc 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -1248,14 +1248,14 @@ static int __init arch_setup(void)
/* set SPU2 clock to 83.4 MHz */
clk = clk_get(NULL, "spu_clk");
- if (clk) {
+ if (!IS_ERR(clk)) {
clk_set_rate(clk, clk_round_rate(clk, 83333333));
clk_put(clk);
}
/* change parent of FSI B */
clk = clk_get(NULL, "fsib_clk");
- if (clk) {
+ if (!IS_ERR(clk)) {
clk_register(&fsimckb_clk);
clk_set_parent(clk, &fsimckb_clk);
clk_set_rate(clk, 11000);
@@ -1273,7 +1273,7 @@ static int __init arch_setup(void)
/* set VPU clock to 166 MHz */
clk = clk_get(NULL, "vpu_clk");
- if (clk) {
+ if (!IS_ERR(clk)) {
clk_set_rate(clk, clk_round_rate(clk, 166000000));
clk_put(clk);
}
diff --git a/arch/sh/boards/mach-sdk7786/Makefile b/arch/sh/boards/mach-sdk7786/Makefile
index a29f19e85b63..23ff7d4ac491 100644
--- a/arch/sh/boards/mach-sdk7786/Makefile
+++ b/arch/sh/boards/mach-sdk7786/Makefile
@@ -1 +1,4 @@
-obj-y := setup.o fpga.o irq.o
+obj-y := fpga.o irq.o setup.o
+
+obj-$(CONFIG_GENERIC_GPIO) += gpio.o
+obj-$(CONFIG_HAVE_SRAM_POOL) += sram.o
diff --git a/arch/sh/boards/mach-sdk7786/gpio.c b/arch/sh/boards/mach-sdk7786/gpio.c
new file mode 100644
index 000000000000..f71ce09d4e15
--- /dev/null
+++ b/arch/sh/boards/mach-sdk7786/gpio.c
@@ -0,0 +1,49 @@
+/*
+ * SDK7786 FPGA USRGPIR Support.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <mach/fpga.h>
+
+#define NR_FPGA_GPIOS 8
+
+static const char *usrgpir_gpio_names[NR_FPGA_GPIOS] = {
+ "in0", "in1", "in2", "in3", "in4", "in5", "in6", "in7",
+};
+
+static int usrgpir_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ /* always in */
+ return 0;
+}
+
+static int usrgpir_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+ return !!(fpga_read_reg(USRGPIR) & (1 << gpio));
+}
+
+static struct gpio_chip usrgpir_gpio_chip = {
+ .label = "sdk7786-fpga",
+ .names = usrgpir_gpio_names,
+ .direction_input = usrgpir_gpio_direction_input,
+ .get = usrgpir_gpio_get,
+ .base = -1, /* don't care */
+ .ngpio = NR_FPGA_GPIOS,
+};
+
+static int __init usrgpir_gpio_setup(void)
+{
+ return gpiochip_add(&usrgpir_gpio_chip);
+}
+device_initcall(usrgpir_gpio_setup);
diff --git a/arch/sh/boards/mach-sdk7786/setup.c b/arch/sh/boards/mach-sdk7786/setup.c
index 2ec1ea5cf8ef..7e0c4e3878e0 100644
--- a/arch/sh/boards/mach-sdk7786/setup.c
+++ b/arch/sh/boards/mach-sdk7786/setup.c
@@ -20,6 +20,8 @@
#include <asm/machvec.h>
#include <asm/heartbeat.h>
#include <asm/sizes.h>
+#include <asm/clock.h>
+#include <asm/clkdev.h>
#include <asm/reboot.h>
#include <asm/smp-ops.h>
@@ -140,6 +142,45 @@ static int sdk7786_mode_pins(void)
return fpga_read_reg(MODSWR);
}
+/*
+ * FPGA-driven PCIe clocks
+ *
+ * Historically these include the oscillator, clock B (slots 2/3/4) and
+ * clock A (slot 1 and the CPU clock). Newer revs of the PCB shove
+ * everything under a single PCIe clocks enable bit that happens to map
+ * to the same bit position as the oscillator bit for earlier FPGA
+ * versions.
+ *
+ * Given that the legacy clocks have the side-effect of shutting the CPU
+ * off through the FPGA along with the PCI slots, we simply leave them in
+ * their initial state and don't bother registering them with the clock
+ * framework.
+ */
+static int sdk7786_pcie_clk_enable(struct clk *clk)
+{
+ fpga_write_reg(fpga_read_reg(PCIECR) | PCIECR_CLKEN, PCIECR);
+ return 0;
+}
+
+static void sdk7786_pcie_clk_disable(struct clk *clk)
+{
+ fpga_write_reg(fpga_read_reg(PCIECR) & ~PCIECR_CLKEN, PCIECR);
+}
+
+static struct clk_ops sdk7786_pcie_clk_ops = {
+ .enable = sdk7786_pcie_clk_enable,
+ .disable = sdk7786_pcie_clk_disable,
+};
+
+static struct clk sdk7786_pcie_clk = {
+ .ops = &sdk7786_pcie_clk_ops,
+};
+
+static struct clk_lookup sdk7786_pcie_cl = {
+ .con_id = "pcie_plat_clk",
+ .clk = &sdk7786_pcie_clk,
+};
+
static int sdk7786_clk_init(void)
{
struct clk *clk;
@@ -158,7 +199,18 @@ static int sdk7786_clk_init(void)
ret = clk_set_rate(clk, 33333333);
clk_put(clk);
- return ret;
+ /*
+ * Setup the FPGA clocks.
+ */
+ ret = clk_register(&sdk7786_pcie_clk);
+ if (unlikely(ret)) {
+ pr_err("FPGA clock registration failed\n");
+ return ret;
+ }
+
+ clkdev_add(&sdk7786_pcie_cl);
+
+ return 0;
}
static void sdk7786_restart(char *cmd)
diff --git a/arch/sh/boards/mach-sdk7786/sram.c b/arch/sh/boards/mach-sdk7786/sram.c
new file mode 100644
index 000000000000..c81c3abbe01c
--- /dev/null
+++ b/arch/sh/boards/mach-sdk7786/sram.c
@@ -0,0 +1,72 @@
+/*
+ * SDK7786 FPGA SRAM Support.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <mach/fpga.h>
+#include <asm/sram.h>
+#include <asm/sizes.h>
+
+static int __init fpga_sram_init(void)
+{
+ unsigned long phys;
+ unsigned int area;
+ void __iomem *vaddr;
+ int ret;
+ u16 data;
+
+ /* Enable FPGA SRAM */
+ data = fpga_read_reg(LCLASR);
+ data |= LCLASR_FRAMEN;
+ fpga_write_reg(data, LCLASR);
+
+ /*
+ * FPGA_SEL determines the area mapping
+ */
+ area = (data & LCLASR_FPGA_SEL_MASK) >> LCLASR_FPGA_SEL_SHIFT;
+ if (unlikely(area == LCLASR_AREA_MASK)) {
+ pr_err("FPGA memory unmapped.\n");
+ return -ENXIO;
+ }
+
+ /*
+ * The memory itself occupies a 2KiB range at the top of the area
+ * immediately below the system registers.
+ */
+ phys = (area << 26) + SZ_64M - SZ_4K;
+
+ /*
+ * The FPGA SRAM resides in translatable physical space, so set
+ * up a mapping prior to inserting it in to the pool.
+ */
+ vaddr = ioremap(phys, SZ_2K);
+ if (unlikely(!vaddr)) {
+ pr_err("Failed remapping FPGA memory.\n");
+ return -ENXIO;
+ }
+
+ pr_info("Adding %dKiB of FPGA memory at 0x%08lx-0x%08lx "
+ "(area %d) to pool.\n",
+ SZ_2K >> 10, phys, phys + SZ_2K - 1, area);
+
+ ret = gen_pool_add(sram_pool, (unsigned long)vaddr, SZ_2K, -1);
+ if (unlikely(ret < 0)) {
+ pr_err("Failed adding memory\n");
+ iounmap(vaddr);
+ return ret;
+ }
+
+ return 0;
+}
+postcore_initcall(fpga_sram_init);
diff --git a/arch/sh/boards/mach-x3proto/Makefile b/arch/sh/boards/mach-x3proto/Makefile
index 983e4551fecf..708c21c919ff 100644
--- a/arch/sh/boards/mach-x3proto/Makefile
+++ b/arch/sh/boards/mach-x3proto/Makefile
@@ -1 +1,3 @@
obj-y += setup.o ilsel.o
+
+obj-$(CONFIG_GENERIC_GPIO) += gpio.o
diff --git a/arch/sh/boards/mach-x3proto/gpio.c b/arch/sh/boards/mach-x3proto/gpio.c
new file mode 100644
index 000000000000..594adf76e46a
--- /dev/null
+++ b/arch/sh/boards/mach-x3proto/gpio.c
@@ -0,0 +1,135 @@
+/*
+ * arch/sh/boards/mach-x3proto/gpio.c
+ *
+ * Renesas SH-X3 Prototype Baseboard GPIO Support.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <mach/ilsel.h>
+#include <mach/hardware.h>
+
+#define KEYCTLR 0xb81c0000
+#define KEYOUTR 0xb81c0002
+#define KEYDETR 0xb81c0004
+
+static DEFINE_SPINLOCK(x3proto_gpio_lock);
+static unsigned int x3proto_gpio_irq_map[NR_BASEBOARD_GPIOS] = { 0, };
+
+static int x3proto_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ unsigned long flags;
+ unsigned int data;
+
+ spin_lock_irqsave(&x3proto_gpio_lock, flags);
+ data = __raw_readw(KEYCTLR);
+ data |= (1 << gpio);
+ __raw_writew(data, KEYCTLR);
+ spin_unlock_irqrestore(&x3proto_gpio_lock, flags);
+
+ return 0;
+}
+
+static int x3proto_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+ return !!(__raw_readw(KEYDETR) & (1 << gpio));
+}
+
+static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+ return x3proto_gpio_irq_map[gpio];
+}
+
+static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
+ unsigned long mask;
+ int pin;
+
+ chip->mask_ack(irq);
+
+ mask = __raw_readw(KEYDETR);
+
+ for_each_set_bit(pin, &mask, NR_BASEBOARD_GPIOS)
+ generic_handle_irq(x3proto_gpio_to_irq(NULL, pin));
+
+ chip->unmask(irq);
+}
+
+struct gpio_chip x3proto_gpio_chip = {
+ .label = "x3proto-gpio",
+ .direction_input = x3proto_gpio_direction_input,
+ .get = x3proto_gpio_get,
+ .to_irq = x3proto_gpio_to_irq,
+ .base = -1,
+ .ngpio = NR_BASEBOARD_GPIOS,
+};
+
+int __init x3proto_gpio_setup(void)
+{
+ int ilsel;
+ int ret, i;
+
+ ilsel = ilsel_enable(ILSEL_KEY);
+ if (unlikely(ilsel < 0))
+ return ilsel;
+
+ ret = gpiochip_add(&x3proto_gpio_chip);
+ if (unlikely(ret))
+ goto err_gpio;
+
+ for (i = 0; i < NR_BASEBOARD_GPIOS; i++) {
+ unsigned long flags;
+ int irq = create_irq();
+
+ if (unlikely(irq < 0)) {
+ ret = -EINVAL;
+ goto err_irq;
+ }
+
+ spin_lock_irqsave(&x3proto_gpio_lock, flags);
+ x3proto_gpio_irq_map[i] = irq;
+ set_irq_chip_and_handler_name(irq, &dummy_irq_chip,
+ handle_simple_irq, "gpio");
+ spin_unlock_irqrestore(&x3proto_gpio_lock, flags);
+ }
+
+ pr_info("registering '%s' support, handling GPIOs %u -> %u, "
+ "bound to IRQ %u\n",
+ x3proto_gpio_chip.label, x3proto_gpio_chip.base,
+ x3proto_gpio_chip.base + x3proto_gpio_chip.ngpio,
+ ilsel);
+
+ set_irq_chained_handler(ilsel, x3proto_gpio_irq_handler);
+ set_irq_wake(ilsel, 1);
+
+ return 0;
+
+err_irq:
+ for (; i >= 0; --i)
+ if (x3proto_gpio_irq_map[i])
+ destroy_irq(x3proto_gpio_irq_map[i]);
+
+ ret = gpiochip_remove(&x3proto_gpio_chip);
+ if (unlikely(ret))
+ pr_err("Failed deregistering GPIO\n");
+
+err_gpio:
+ synchronize_irq(ilsel);
+
+ ilsel_disable(ILSEL_KEY);
+
+ return ret;
+}
diff --git a/arch/sh/boards/mach-x3proto/ilsel.c b/arch/sh/boards/mach-x3proto/ilsel.c
index 5c9842704c60..95e346139515 100644
--- a/arch/sh/boards/mach-x3proto/ilsel.c
+++ b/arch/sh/boards/mach-x3proto/ilsel.c
@@ -1,20 +1,22 @@
/*
- * arch/sh/boards/renesas/x3proto/ilsel.c
+ * arch/sh/boards/mach-x3proto/ilsel.c
*
* Helper routines for SH-X3 proto board ILSEL.
*
- * Copyright (C) 2007 Paul Mundt
+ * Copyright (C) 2007 - 2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/bitmap.h>
#include <linux/io.h>
-#include <asm/ilsel.h>
+#include <mach/ilsel.h>
/*
* ILSEL is split across:
@@ -64,6 +66,8 @@ static void __ilsel_enable(ilsel_source_t set, unsigned int bit)
unsigned int tmp, shift;
unsigned long addr;
+ pr_notice("enabling ILSEL set %d\n", set);
+
addr = mk_ilsel_addr(bit);
shift = mk_ilsel_shift(bit);
@@ -92,8 +96,10 @@ int ilsel_enable(ilsel_source_t set)
{
unsigned int bit;
- /* Aliased sources must use ilsel_enable_fixed() */
- BUG_ON(set > ILSEL_KEY);
+ if (unlikely(set > ILSEL_KEY)) {
+ pr_err("Aliased sources must use ilsel_enable_fixed()\n");
+ return -EINVAL;
+ }
do {
bit = find_first_zero_bit(&ilsel_level_map, ILSEL_LEVELS);
@@ -140,6 +146,8 @@ void ilsel_disable(unsigned int irq)
unsigned long addr;
unsigned int tmp;
+ pr_notice("disabling ILSEL set %d\n", irq);
+
addr = mk_ilsel_addr(irq);
tmp = __raw_readw(addr);
diff --git a/arch/sh/boards/mach-x3proto/setup.c b/arch/sh/boards/mach-x3proto/setup.c
index 102bf56befb4..d682e2b6a856 100644
--- a/arch/sh/boards/mach-x3proto/setup.c
+++ b/arch/sh/boards/mach-x3proto/setup.c
@@ -1,9 +1,9 @@
/*
- * arch/sh/boards/renesas/x3proto/setup.c
+ * arch/sh/boards/mach-x3proto/setup.c
*
* Renesas SH-X3 Prototype Board Support.
*
- * Copyright (C) 2007 - 2008 Paul Mundt
+ * Copyright (C) 2007 - 2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -16,9 +16,13 @@
#include <linux/smc91x.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/input.h>
#include <linux/usb/r8a66597.h>
#include <linux/usb/m66592.h>
-#include <asm/ilsel.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <mach/ilsel.h>
+#include <mach/hardware.h>
#include <asm/smp-ops.h>
static struct resource heartbeat_resources[] = {
@@ -122,15 +126,128 @@ static struct platform_device m66592_usb_peripheral_device = {
.resource = m66592_usb_peripheral_resources,
};
+static struct gpio_keys_button baseboard_buttons[NR_BASEBOARD_GPIOS] = {
+ {
+ .desc = "key44",
+ .code = KEY_POWER,
+ .active_low = 1,
+ .wakeup = 1,
+ }, {
+ .desc = "key43",
+ .code = KEY_SUSPEND,
+ .active_low = 1,
+ .wakeup = 1,
+ }, {
+ .desc = "key42",
+ .code = KEY_KATAKANAHIRAGANA,
+ .active_low = 1,
+ }, {
+ .desc = "key41",
+ .code = KEY_SWITCHVIDEOMODE,
+ .active_low = 1,
+ }, {
+ .desc = "key34",
+ .code = KEY_F12,
+ .active_low = 1,
+ }, {
+ .desc = "key33",
+ .code = KEY_F11,
+ .active_low = 1,
+ }, {
+ .desc = "key32",
+ .code = KEY_F10,
+ .active_low = 1,
+ }, {
+ .desc = "key31",
+ .code = KEY_F9,
+ .active_low = 1,
+ }, {
+ .desc = "key24",
+ .code = KEY_F8,
+ .active_low = 1,
+ }, {
+ .desc = "key23",
+ .code = KEY_F7,
+ .active_low = 1,
+ }, {
+ .desc = "key22",
+ .code = KEY_F6,
+ .active_low = 1,
+ }, {
+ .desc = "key21",
+ .code = KEY_F5,
+ .active_low = 1,
+ }, {
+ .desc = "key14",
+ .code = KEY_F4,
+ .active_low = 1,
+ }, {
+ .desc = "key13",
+ .code = KEY_F3,
+ .active_low = 1,
+ }, {
+ .desc = "key12",
+ .code = KEY_F2,
+ .active_low = 1,
+ }, {
+ .desc = "key11",
+ .code = KEY_F1,
+ .active_low = 1,
+ },
+};
+
+static struct gpio_keys_platform_data baseboard_buttons_data = {
+ .buttons = baseboard_buttons,
+ .nbuttons = ARRAY_SIZE(baseboard_buttons),
+};
+
+static struct platform_device baseboard_buttons_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &baseboard_buttons_data,
+ },
+};
+
static struct platform_device *x3proto_devices[] __initdata = {
&heartbeat_device,
&smc91x_device,
&r8a66597_usb_host_device,
&m66592_usb_peripheral_device,
+ &baseboard_buttons_device,
};
+static void __init x3proto_init_irq(void)
+{
+ plat_irq_setup_pins(IRQ_MODE_IRL3210);
+
+ /* Set ICR0.LVLMODE */
+ __raw_writel(__raw_readl(0xfe410000) | (1 << 21), 0xfe410000);
+}
+
static int __init x3proto_devices_setup(void)
{
+ int ret, i;
+
+ /*
+ * IRLs are only needed for ILSEL mappings, so flip over the INTC
+ * pins at a later point to enable the GPIOs to settle.
+ */
+ x3proto_init_irq();
+
+ /*
+ * Now that ILSELs are available, set up the baseboard GPIOs.
+ */
+ ret = x3proto_gpio_setup();
+ if (unlikely(ret))
+ return ret;
+
+ /*
+ * Propagate dynamic GPIOs for the baseboard button device.
+ */
+ for (i = 0; i < ARRAY_SIZE(baseboard_buttons); i++)
+ baseboard_buttons[i].gpio = x3proto_gpio_chip.base + i;
+
r8a66597_usb_host_resources[1].start =
r8a66597_usb_host_resources[1].end = ilsel_enable(ILSEL_USBH_I);
@@ -145,14 +262,6 @@ static int __init x3proto_devices_setup(void)
}
device_initcall(x3proto_devices_setup);
-static void __init x3proto_init_irq(void)
-{
- plat_irq_setup_pins(IRQ_MODE_IRL3210);
-
- /* Set ICR0.LVLMODE */
- __raw_writel(__raw_readl(0xfe410000) | (1 << 21), 0xfe410000);
-}
-
static void __init x3proto_setup(char **cmdline_p)
{
register_smp_ops(&shx3_smp_ops);
@@ -161,5 +270,4 @@ static void __init x3proto_setup(char **cmdline_p)
static struct sh_machine_vector mv_x3proto __initmv = {
.mv_name = "x3proto",
.mv_setup = x3proto_setup,
- .mv_init_irq = x3proto_init_irq,
};
diff --git a/arch/sh/boot/compressed/head_32.S b/arch/sh/boot/compressed/head_32.S
index 200c1d4f1efe..3e150326f1fd 100644
--- a/arch/sh/boot/compressed/head_32.S
+++ b/arch/sh/boot/compressed/head_32.S
@@ -91,7 +91,9 @@ bss_start_addr:
end_addr:
.long _end
init_sr:
- .long 0x400000F0 /* Privileged mode, Bank=0, Block=0, IMASK=0xF */
+ .long 0x500000F0 /* Privileged mode, Bank=0, Block=1, IMASK=0xF */
+kexec_magic:
+ .long 0x400000F0 /* magic used by kexec to parse zImage format */
init_stack_addr:
.long stack_start
decompress_kernel_addr:
diff --git a/arch/sh/cchips/hd6446x/Makefile b/arch/sh/cchips/hd6446x/Makefile
index 9682e3ab668f..59c348337bb8 100644
--- a/arch/sh/cchips/hd6446x/Makefile
+++ b/arch/sh/cchips/hd6446x/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_HD64461) += hd64461.o
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
diff --git a/arch/sh/configs/ap325rxa_defconfig b/arch/sh/configs/ap325rxa_defconfig
index 238d6833ac70..e5335123b5e9 100644
--- a/arch/sh/configs/ap325rxa_defconfig
+++ b/arch/sh/configs/ap325rxa_defconfig
@@ -3,7 +3,6 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_KALLSYMS is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/cayman_defconfig b/arch/sh/configs/cayman_defconfig
index b3bf11bcf025..67e150631ea5 100644
--- a/arch/sh/configs/cayman_defconfig
+++ b/arch/sh/configs/cayman_defconfig
@@ -1,7 +1,6 @@
CONFIG_EXPERIMENTAL=y
CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/dreamcast_defconfig b/arch/sh/configs/dreamcast_defconfig
index 3cdee4f0c184..ec243ca29529 100644
--- a/arch/sh/configs/dreamcast_defconfig
+++ b/arch/sh/configs/dreamcast_defconfig
@@ -2,7 +2,6 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_SLAB=y
CONFIG_PROFILING=y
diff --git a/arch/sh/configs/ecovec24-romimage_defconfig b/arch/sh/configs/ecovec24-romimage_defconfig
index 021633b02835..5fcb17bff24a 100644
--- a/arch/sh/configs/ecovec24-romimage_defconfig
+++ b/arch/sh/configs/ecovec24-romimage_defconfig
@@ -5,7 +5,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_KALLSYMS is not set
CONFIG_SLAB=y
diff --git a/arch/sh/configs/edosk7760_defconfig b/arch/sh/configs/edosk7760_defconfig
index 365f2318e9b5..e1077a041ac3 100644
--- a/arch/sh/configs/edosk7760_defconfig
+++ b/arch/sh/configs/edosk7760_defconfig
@@ -5,7 +5,6 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_KALLSYMS_ALL=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/espt_defconfig b/arch/sh/configs/espt_defconfig
index ca7fc1b3d567..67cb1094a033 100644
--- a/arch/sh/configs/espt_defconfig
+++ b/arch/sh/configs/espt_defconfig
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
CONFIG_IPC_NS=y
diff --git a/arch/sh/configs/hp6xx_defconfig b/arch/sh/configs/hp6xx_defconfig
index 45c18a3830d2..496edcdf95a3 100644
--- a/arch/sh/configs/hp6xx_defconfig
+++ b/arch/sh/configs/hp6xx_defconfig
@@ -3,7 +3,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_SLAB=y
diff --git a/arch/sh/configs/kfr2r09-romimage_defconfig b/arch/sh/configs/kfr2r09-romimage_defconfig
index d4268b1953bc..029a506ca325 100644
--- a/arch/sh/configs/kfr2r09-romimage_defconfig
+++ b/arch/sh/configs/kfr2r09-romimage_defconfig
@@ -5,7 +5,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_KALLSYMS is not set
CONFIG_SLAB=y
diff --git a/arch/sh/configs/kfr2r09_defconfig b/arch/sh/configs/kfr2r09_defconfig
index ad5d296b375f..fac13ded07b2 100644
--- a/arch/sh/configs/kfr2r09_defconfig
+++ b/arch/sh/configs/kfr2r09_defconfig
@@ -5,7 +5,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_KALLSYMS is not set
CONFIG_SLAB=y
diff --git a/arch/sh/configs/landisk_defconfig b/arch/sh/configs/landisk_defconfig
index 14e658e9318f..3670e937f2b7 100644
--- a/arch/sh/configs/landisk_defconfig
+++ b/arch/sh/configs/landisk_defconfig
@@ -1,7 +1,6 @@
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_SLAB=y
diff --git a/arch/sh/configs/lboxre2_defconfig b/arch/sh/configs/lboxre2_defconfig
index 6be7eaaa8bb6..e3c0894b1bb4 100644
--- a/arch/sh/configs/lboxre2_defconfig
+++ b/arch/sh/configs/lboxre2_defconfig
@@ -1,7 +1,6 @@
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_SLAB=y
diff --git a/arch/sh/configs/magicpanelr2_defconfig b/arch/sh/configs/magicpanelr2_defconfig
index 4d61b7711b40..9479872b1ae6 100644
--- a/arch/sh/configs/magicpanelr2_defconfig
+++ b/arch/sh/configs/magicpanelr2_defconfig
@@ -5,7 +5,6 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_AUDIT=y
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
diff --git a/arch/sh/configs/microdev_defconfig b/arch/sh/configs/microdev_defconfig
index 0e32a24fed53..f1d2e1b5ee41 100644
--- a/arch/sh/configs/microdev_defconfig
+++ b/arch/sh/configs/microdev_defconfig
@@ -1,7 +1,6 @@
CONFIG_EXPERIMENTAL=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
diff --git a/arch/sh/configs/migor_defconfig b/arch/sh/configs/migor_defconfig
index c19fcdfdee37..9ad904a110de 100644
--- a/arch/sh/configs/migor_defconfig
+++ b/arch/sh/configs/migor_defconfig
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
diff --git a/arch/sh/configs/polaris_defconfig b/arch/sh/configs/polaris_defconfig
index 984e3fe1ce5d..f3d5d9f76310 100644
--- a/arch/sh/configs/polaris_defconfig
+++ b/arch/sh/configs/polaris_defconfig
@@ -7,7 +7,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_AUDIT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/r7780mp_defconfig b/arch/sh/configs/r7780mp_defconfig
index e8b5472e6d84..920b8471ceb7 100644
--- a/arch/sh/configs/r7780mp_defconfig
+++ b/arch/sh/configs/r7780mp_defconfig
@@ -4,7 +4,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/sh/configs/r7785rp_defconfig b/arch/sh/configs/r7785rp_defconfig
index fd8848060982..c77da6be06b8 100644
--- a/arch/sh/configs/r7785rp_defconfig
+++ b/arch/sh/configs/r7785rp_defconfig
@@ -8,7 +8,6 @@ CONFIG_RCU_TRACE=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_SLAB=y
CONFIG_PROFILING=y
diff --git a/arch/sh/configs/rts7751r2d1_defconfig b/arch/sh/configs/rts7751r2d1_defconfig
index a42f7c22ca1a..a3d081095ce2 100644
--- a/arch/sh/configs/rts7751r2d1_defconfig
+++ b/arch/sh/configs/rts7751r2d1_defconfig
@@ -1,7 +1,6 @@
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_SLAB=y
diff --git a/arch/sh/configs/rts7751r2dplus_defconfig b/arch/sh/configs/rts7751r2dplus_defconfig
index 742aa61f2427..b1a04f3c598b 100644
--- a/arch/sh/configs/rts7751r2dplus_defconfig
+++ b/arch/sh/configs/rts7751r2dplus_defconfig
@@ -1,7 +1,6 @@
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_SLAB=y
diff --git a/arch/sh/configs/sdk7780_defconfig b/arch/sh/configs/sdk7780_defconfig
index aed394d89346..ae1115849dda 100644
--- a/arch/sh/configs/sdk7780_defconfig
+++ b/arch/sh/configs/sdk7780_defconfig
@@ -6,7 +6,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=18
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_RELAY=y
CONFIG_KALLSYMS_ALL=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/se7343_defconfig b/arch/sh/configs/se7343_defconfig
index 7a7e13853cfd..be9c474197b3 100644
--- a/arch/sh/configs/se7343_defconfig
+++ b/arch/sh/configs/se7343_defconfig
@@ -3,7 +3,6 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/sh/configs/se7712_defconfig b/arch/sh/configs/se7712_defconfig
index 3620a7f4c821..1248635e4f88 100644
--- a/arch/sh/configs/se7712_defconfig
+++ b/arch/sh/configs/se7712_defconfig
@@ -5,7 +5,6 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_KALLSYMS_ALL=y
# CONFIG_BUG is not set
diff --git a/arch/sh/configs/se7721_defconfig b/arch/sh/configs/se7721_defconfig
index fe22f599c0cb..c3ba6e8a9818 100644
--- a/arch/sh/configs/se7721_defconfig
+++ b/arch/sh/configs/se7721_defconfig
@@ -5,7 +5,6 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_KALLSYMS_ALL=y
# CONFIG_BUG is not set
diff --git a/arch/sh/configs/se7722_defconfig b/arch/sh/configs/se7722_defconfig
index b9b64c38810e..ae998c7e2ee0 100644
--- a/arch/sh/configs/se7722_defconfig
+++ b/arch/sh/configs/se7722_defconfig
@@ -4,7 +4,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_PROFILING=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/se7724_defconfig b/arch/sh/configs/se7724_defconfig
index 03e736781c2e..ed35093e3758 100644
--- a/arch/sh/configs/se7724_defconfig
+++ b/arch/sh/configs/se7724_defconfig
@@ -3,7 +3,6 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_KALLSYMS is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/se7750_defconfig b/arch/sh/configs/se7750_defconfig
index 1a686b6d5cd4..912c98590e22 100644
--- a/arch/sh/configs/se7750_defconfig
+++ b/arch/sh/configs/se7750_defconfig
@@ -5,7 +5,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_HOTPLUG is not set
diff --git a/arch/sh/configs/se7751_defconfig b/arch/sh/configs/se7751_defconfig
index 7e03451a9fad..75c92fc1876b 100644
--- a/arch/sh/configs/se7751_defconfig
+++ b/arch/sh/configs/se7751_defconfig
@@ -2,7 +2,6 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
diff --git a/arch/sh/configs/se7780_defconfig b/arch/sh/configs/se7780_defconfig
index 4cfc4deff135..c8c5e7f7a68d 100644
--- a/arch/sh/configs/se7780_defconfig
+++ b/arch/sh/configs/se7780_defconfig
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_EPOLL is not set
diff --git a/arch/sh/configs/sh03_defconfig b/arch/sh/configs/sh03_defconfig
index b95dc76b04c1..2051821724c6 100644
--- a/arch/sh/configs/sh03_defconfig
+++ b/arch/sh/configs/sh03_defconfig
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_SLAB=y
diff --git a/arch/sh/configs/sh2007_defconfig b/arch/sh/configs/sh2007_defconfig
new file mode 100644
index 000000000000..0d2f41472a19
--- /dev/null
+++ b/arch/sh/configs/sh2007_defconfig
@@ -0,0 +1,212 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
+CONFIG_IKCONFIG=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_SLAB=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_CPU_SUBTYPE_SH7780=y
+CONFIG_MEMORY_SIZE=0x08000000
+# CONFIG_VSYSCALL is not set
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_SH_SH2007=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SH_DMA=y
+CONFIG_SH_DMA_API=y
+CONFIG_NR_DMA_CHANNELS_BOOL=y
+CONFIG_HZ_100=y
+CONFIG_CMDLINE_OVERWRITE=y
+CONFIG_CMDLINE="console=ttySC1,115200 ip=dhcp root=/dev/nfs rw nfsroot=/nfs/rootfs,rsize=1024,wsize=1024 earlyprintk=sh-sci.1"
+CONFIG_PCCARD=y
+CONFIG_BINFMT_MISC=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_NET_IPIP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NET_PKTGEN=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_CDROM_PKTCDVD=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_RAID_ATTRS=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_FC_ATTRS=y
+CONFIG_SCSI_ISCSI_ATTRS=y
+CONFIG_SCSI_SRP_ATTRS=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_EQUALIZER=y
+CONFIG_TUN=y
+CONFIG_VETH=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMSC911X=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+CONFIG_INPUT_FF_MEMLESS=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_SH_WDT=y
+CONFIG_SSB=y
+CONFIG_FB=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_LOGO=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_MON=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+CONFIG_DMADEVICES=y
+CONFIG_TIMB_DMA=y
+CONFIG_EXT3_FS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=932
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=y
+CONFIG_NLS_CODEPAGE_775=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+CONFIG_NLS_CODEPAGE_855=y
+CONFIG_NLS_CODEPAGE_857=y
+CONFIG_NLS_CODEPAGE_860=y
+CONFIG_NLS_CODEPAGE_861=y
+CONFIG_NLS_CODEPAGE_862=y
+CONFIG_NLS_CODEPAGE_863=y
+CONFIG_NLS_CODEPAGE_864=y
+CONFIG_NLS_CODEPAGE_865=y
+CONFIG_NLS_CODEPAGE_866=y
+CONFIG_NLS_CODEPAGE_869=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_CODEPAGE_949=y
+CONFIG_NLS_CODEPAGE_874=y
+CONFIG_NLS_ISO8859_8=y
+CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_CODEPAGE_1251=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+CONFIG_NLS_ISO8859_3=y
+CONFIG_NLS_ISO8859_4=y
+CONFIG_NLS_ISO8859_5=y
+CONFIG_NLS_ISO8859_6=y
+CONFIG_NLS_ISO8859_7=y
+CONFIG_NLS_ISO8859_9=y
+CONFIG_NLS_ISO8859_13=y
+CONFIG_NLS_ISO8859_14=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_KOI8_R=y
+CONFIG_NLS_KOI8_U=y
+CONFIG_NLS_UTF8=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SH_STANDARD_BIOS=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_LRW=y
+CONFIG_CRYPTO_PCBC=y
+CONFIG_CRYPTO_XTS=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_TGR192=y
+CONFIG_CRYPTO_WP512=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLOWFISH=y
+CONFIG_CRYPTO_CAMELLIA=y
+CONFIG_CRYPTO_CAST5=y
+CONFIG_CRYPTO_CAST6=y
+CONFIG_CRYPTO_FCRYPT=y
+CONFIG_CRYPTO_KHAZAD=y
+CONFIG_CRYPTO_SEED=y
+CONFIG_CRYPTO_SERPENT=y
+CONFIG_CRYPTO_TEA=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_LZO=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_LIBCRC32C=y
diff --git a/arch/sh/configs/sh7710voipgw_defconfig b/arch/sh/configs/sh7710voipgw_defconfig
index b804641c8dd2..f92ad17cd629 100644
--- a/arch/sh/configs/sh7710voipgw_defconfig
+++ b/arch/sh/configs/sh7710voipgw_defconfig
@@ -3,7 +3,6 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/sh/configs/sh7757lcr_defconfig b/arch/sh/configs/sh7757lcr_defconfig
new file mode 100644
index 000000000000..273f3fa198f7
--- /dev/null
+++ b/arch/sh/configs/sh7757lcr_defconfig
@@ -0,0 +1,85 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_CPU_SUBTYPE_SH7757=y
+CONFIG_MEMORY_START=0x40000000
+CONFIG_MEMORY_SIZE=0x0f000000
+CONFIG_PMB=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_SH_SH7757LCR=y
+CONFIG_HEARTBEAT=y
+CONFIG_SECCOMP=y
+CONFIG_CMDLINE_OVERWRITE=y
+CONFIG_CMDLINE="console=ttySC2,115200 root=/dev/nfs ip=dhcp"
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FW_LOADER is not set
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_NETDEVICES=y
+CONFIG_PHYLIB=y
+CONFIG_VITESSE_PHY=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=3
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_INOTIFY=y
+CONFIG_ISO9660_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_SQUASHFS=y
+CONFIG_MINIX_FS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_FTRACE is not set
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/sh/configs/sh7763rdp_defconfig b/arch/sh/configs/sh7763rdp_defconfig
index 361876786932..479536440264 100644
--- a/arch/sh/configs/sh7763rdp_defconfig
+++ b/arch/sh/configs/sh7763rdp_defconfig
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
CONFIG_IPC_NS=y
diff --git a/arch/sh/configs/sh7785lcr_defconfig b/arch/sh/configs/sh7785lcr_defconfig
index ee6b81f7539e..51561f5677d8 100644
--- a/arch/sh/configs/sh7785lcr_defconfig
+++ b/arch/sh/configs/sh7785lcr_defconfig
@@ -4,7 +4,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_MODULES=y
diff --git a/arch/sh/configs/shx3_defconfig b/arch/sh/configs/shx3_defconfig
index bb4f60c0f866..3f92d37c6374 100644
--- a/arch/sh/configs/shx3_defconfig
+++ b/arch/sh/configs/shx3_defconfig
@@ -15,7 +15,6 @@ CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_RESOURCE_COUNTERS=y
CONFIG_CGROUP_MEM_RES_CTLR=y
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_RELAY=y
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
diff --git a/arch/sh/configs/snapgear_defconfig b/arch/sh/configs/snapgear_defconfig
index f38c98341f15..7eae4e59d7f0 100644
--- a/arch/sh/configs/snapgear_defconfig
+++ b/arch/sh/configs/snapgear_defconfig
@@ -1,7 +1,6 @@
CONFIG_EXPERIMENTAL=y
# CONFIG_SWAP is not set
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_HOTPLUG is not set
diff --git a/arch/sh/configs/systemh_defconfig b/arch/sh/configs/systemh_defconfig
index 7007d00c67e0..b58dfc505efe 100644
--- a/arch/sh/configs/systemh_defconfig
+++ b/arch/sh/configs/systemh_defconfig
@@ -1,6 +1,5 @@
CONFIG_EXPERIMENTAL=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
diff --git a/arch/sh/configs/titan_defconfig b/arch/sh/configs/titan_defconfig
index 45c309ff447e..0f558914e760 100644
--- a/arch/sh/configs/titan_defconfig
+++ b/arch/sh/configs/titan_defconfig
@@ -5,7 +5,6 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=16
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
diff --git a/arch/sh/configs/ul2_defconfig b/arch/sh/configs/ul2_defconfig
index e107d424acf0..2d288b887fbd 100644
--- a/arch/sh/configs/ul2_defconfig
+++ b/arch/sh/configs/ul2_defconfig
@@ -4,7 +4,6 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_PROFILING=y
CONFIG_MODULES=y
diff --git a/arch/sh/drivers/dma/dma-api.c b/arch/sh/drivers/dma/dma-api.c
index 4a277224a871..f46848f088e4 100644
--- a/arch/sh/drivers/dma/dma-api.c
+++ b/arch/sh/drivers/dma/dma-api.c
@@ -412,8 +412,8 @@ EXPORT_SYMBOL(unregister_dmac);
static int __init dma_api_init(void)
{
printk(KERN_NOTICE "DMA: Registering DMA API.\n");
- create_proc_read_entry("dma", 0, 0, dma_read_proc, 0);
- return 0;
+ return create_proc_read_entry("dma", 0, 0, dma_read_proc, 0)
+ ? 0 : -ENOMEM;
}
subsys_initcall(dma_api_init);
diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
index 4a59e6890876..82f0a335fd19 100644
--- a/arch/sh/drivers/pci/Makefile
+++ b/arch/sh/drivers/pci/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_SH_RTS7751R2D) += fixups-rts7751r2d.o
obj-$(CONFIG_SH_SH03) += fixups-sh03.o
obj-$(CONFIG_SH_HIGHLANDER) += fixups-r7780rp.o
obj-$(CONFIG_SH_SH7785LCR) += fixups-r7780rp.o
+obj-$(CONFIG_SH_SDK7786) += fixups-sdk7786.o
obj-$(CONFIG_SH_SDK7780) += fixups-sdk7780.o
obj-$(CONFIG_SH_7780_SOLUTION_ENGINE) += fixups-sdk7780.o
obj-$(CONFIG_SH_TITAN) += fixups-titan.o
diff --git a/arch/sh/drivers/pci/fixups-sdk7786.c b/arch/sh/drivers/pci/fixups-sdk7786.c
new file mode 100644
index 000000000000..0e18ee332553
--- /dev/null
+++ b/arch/sh/drivers/pci/fixups-sdk7786.c
@@ -0,0 +1,67 @@
+/*
+ * SDK7786 FPGA PCIe mux handling
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "PCI: " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <mach/fpga.h>
+
+/*
+ * The SDK7786 FPGA supports mangling of most of the slots in some way or
+ * another. Slots 3/4 are special in that only one can be supported at a
+ * time, and both appear on port 3 to the PCI bus scan. Enabling slot 4
+ * (the horizontal edge connector) will disable slot 3 entirely.
+ *
+ * Misconfigurations can be detected through the FPGA via the slot
+ * resistors to determine card presence. Hotplug remains unsupported.
+ */
+static unsigned int slot4en __devinitdata;
+
+char *__devinit pcibios_setup(char *str)
+{
+ if (strcmp(str, "slot4en") == 0) {
+ slot4en = 1;
+ return NULL;
+ }
+
+ return str;
+}
+
+static int __init sdk7786_pci_init(void)
+{
+ u16 data = fpga_read_reg(PCIECR);
+
+ /*
+ * Enable slot #4 if it's been specified on the command line.
+ *
+ * Optionally reroute if slot #4 has a card present while slot #3
+ * does not, regardless of command line value.
+ *
+ * Card presence is logically inverted.
+ */
+ slot4en ?: (!(data & PCIECR_PRST4) && (data & PCIECR_PRST3));
+ if (slot4en) {
+ pr_info("Activating PCIe slot#4 (disabling slot#3)\n");
+
+ data &= ~PCIECR_PCIEMUX1;
+ fpga_write_reg(data, PCIECR);
+
+ /* Warn about forced rerouting if slot#3 is occupied */
+ if ((data & PCIECR_PRST3) == 0) {
+ pr_warning("Unreachable card detected in slot#3\n");
+ return -EBUSY;
+ }
+ } else
+ pr_info("PCIe slot#4 disabled\n");
+
+ return 0;
+}
+postcore_initcall(sdk7786_pci_init);
diff --git a/arch/sh/drivers/pci/ops-sh4.c b/arch/sh/drivers/pci/ops-sh4.c
index 0b81999fb88b..b6234203e0ac 100644
--- a/arch/sh/drivers/pci/ops-sh4.c
+++ b/arch/sh/drivers/pci/ops-sh4.c
@@ -9,6 +9,7 @@
*/
#include <linux/pci.h>
#include <linux/io.h>
+#include <linux/spinlock.h>
#include <asm/addrspace.h>
#include "pci-sh4.h"
@@ -18,8 +19,6 @@
#define CONFIG_CMD(bus, devfn, where) \
(0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
-static DEFINE_SPINLOCK(sh4_pci_lock);
-
/*
* Functions for accessing PCI configuration space with type 1 accesses
*/
@@ -34,10 +33,10 @@ static int sh4_pci_read(struct pci_bus *bus, unsigned int devfn,
* PCIPDR may only be accessed as 32 bit words,
* so we must do byte alignment by hand
*/
- spin_lock_irqsave(&sh4_pci_lock, flags);
+ raw_spin_lock_irqsave(&pci_config_lock, flags);
pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
data = pci_read_reg(chan, SH4_PCIPDR);
- spin_unlock_irqrestore(&sh4_pci_lock, flags);
+ raw_spin_unlock_irqrestore(&pci_config_lock, flags);
switch (size) {
case 1:
@@ -69,10 +68,10 @@ static int sh4_pci_write(struct pci_bus *bus, unsigned int devfn,
int shift;
u32 data;
- spin_lock_irqsave(&sh4_pci_lock, flags);
+ raw_spin_lock_irqsave(&pci_config_lock, flags);
pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
data = pci_read_reg(chan, SH4_PCIPDR);
- spin_unlock_irqrestore(&sh4_pci_lock, flags);
+ raw_spin_unlock_irqrestore(&pci_config_lock, flags);
switch (size) {
case 1:
diff --git a/arch/sh/drivers/pci/ops-sh7786.c b/arch/sh/drivers/pci/ops-sh7786.c
index 48f594b9582b..128421009e3f 100644
--- a/arch/sh/drivers/pci/ops-sh7786.c
+++ b/arch/sh/drivers/pci/ops-sh7786.c
@@ -1,7 +1,7 @@
/*
* Generic SH7786 PCI-Express operations.
*
- * Copyright (C) 2009 Paul Mundt
+ * Copyright (C) 2009 - 2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License v2. See the file "COPYING" in the main directory of this archive
@@ -19,37 +19,72 @@ enum {
PCI_ACCESS_WRITE,
};
-static DEFINE_SPINLOCK(sh7786_pcie_lock);
-
static int sh7786_pcie_config_access(unsigned char access_type,
struct pci_bus *bus, unsigned int devfn, int where, u32 *data)
{
struct pci_channel *chan = bus->sysdata;
- int dev, func;
+ int dev, func, type, reg;
dev = PCI_SLOT(devfn);
func = PCI_FUNC(devfn);
+ type = !!bus->parent;
+ reg = where & ~3;
if (bus->number > 255 || dev > 31 || func > 7)
return PCIBIOS_FUNC_NOT_SUPPORTED;
- if (devfn)
- return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /*
+ * While each channel has its own memory-mapped extended config
+ * space, it's generally only accessible when in endpoint mode.
+ * When in root complex mode, the controller is unable to target
+ * itself with either type 0 or type 1 accesses, and indeed, any
+ * controller initiated target transfer to its own config space
+ * result in a completer abort.
+ *
+ * Each channel effectively only supports a single device, but as
+ * the same channel <-> device access works for any PCI_SLOT()
+ * value, we cheat a bit here and bind the controller's config
+ * space to devfn 0 in order to enable self-enumeration. In this
+ * case the regular PAR/PDR path is sidelined and the mangled
+ * config access itself is initiated as a SuperHyway transaction.
+ */
+ if (pci_is_root_bus(bus)) {
+ if (dev == 0) {
+ if (access_type == PCI_ACCESS_READ)
+ *data = pci_read_reg(chan, PCI_REG(reg));
+ else
+ pci_write_reg(chan, *data, PCI_REG(reg));
+
+ return PCIBIOS_SUCCESSFUL;
+ } else if (dev > 1)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ /* Clear errors */
+ pci_write_reg(chan, pci_read_reg(chan, SH4A_PCIEERRFR), SH4A_PCIEERRFR);
/* Set the PIO address */
pci_write_reg(chan, (bus->number << 24) | (dev << 19) |
- (func << 16) | (where & ~3), SH4A_PCIEPAR);
+ (func << 16) | reg, SH4A_PCIEPAR);
/* Enable the configuration access */
- pci_write_reg(chan, (1 << 31), SH4A_PCIEPCTLR);
+ pci_write_reg(chan, (1 << 31) | (type << 8), SH4A_PCIEPCTLR);
+
+ /* Check for errors */
+ if (pci_read_reg(chan, SH4A_PCIEERRFR) & 0x10)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /* Check for master and target aborts */
+ if (pci_read_reg(chan, SH4A_PCIEPCICONF1) & ((1 << 29) | (1 << 28)))
+ return PCIBIOS_DEVICE_NOT_FOUND;
if (access_type == PCI_ACCESS_READ)
*data = pci_read_reg(chan, SH4A_PCIEPDR);
else
pci_write_reg(chan, *data, SH4A_PCIEPDR);
- /* Check for master and target aborts */
- if (pci_read_reg(chan, SH4A_PCIEPCICONF1) & ((1 << 29) | (1 << 28)))
- return PCIBIOS_DEVICE_NOT_FOUND;
+ /* Disable the configuration access */
+ pci_write_reg(chan, 0, SH4A_PCIEPCTLR);
return PCIBIOS_SUCCESSFUL;
}
@@ -66,11 +101,13 @@ static int sh7786_pcie_read(struct pci_bus *bus, unsigned int devfn,
else if ((size == 4) && (where & 3))
return PCIBIOS_BAD_REGISTER_NUMBER;
- spin_lock_irqsave(&sh7786_pcie_lock, flags);
+ raw_spin_lock_irqsave(&pci_config_lock, flags);
ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
devfn, where, &data);
- if (ret != PCIBIOS_SUCCESSFUL)
+ if (ret != PCIBIOS_SUCCESSFUL) {
+ *val = 0xffffffff;
goto out;
+ }
if (size == 1)
*val = (data >> ((where & 3) << 3)) & 0xff;
@@ -84,7 +121,7 @@ static int sh7786_pcie_read(struct pci_bus *bus, unsigned int devfn,
devfn, where, size, (unsigned long)*val);
out:
- spin_unlock_irqrestore(&sh7786_pcie_lock, flags);
+ raw_spin_unlock_irqrestore(&pci_config_lock, flags);
return ret;
}
@@ -100,7 +137,7 @@ static int sh7786_pcie_write(struct pci_bus *bus, unsigned int devfn,
else if ((size == 4) && (where & 3))
return PCIBIOS_BAD_REGISTER_NUMBER;
- spin_lock_irqsave(&sh7786_pcie_lock, flags);
+ raw_spin_lock_irqsave(&pci_config_lock, flags);
ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
devfn, where, &data);
if (ret != PCIBIOS_SUCCESSFUL)
@@ -124,7 +161,7 @@ static int sh7786_pcie_write(struct pci_bus *bus, unsigned int devfn,
ret = sh7786_pcie_config_access(PCI_ACCESS_WRITE, bus,
devfn, where, &data);
out:
- spin_unlock_irqrestore(&sh7786_pcie_lock, flags);
+ raw_spin_unlock_irqrestore(&pci_config_lock, flags);
return ret;
}
diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c
index f98141b3b7d7..86adb1e235cd 100644
--- a/arch/sh/drivers/pci/pci-sh7751.c
+++ b/arch/sh/drivers/pci/pci-sh7751.c
@@ -81,7 +81,7 @@ static int __init sh7751_pci_init(void)
unsigned int id;
u32 word, reg;
- printk(KERN_NOTICE "PCI: Starting intialization.\n");
+ printk(KERN_NOTICE "PCI: Starting initialization.\n");
chan->reg_base = 0xfe200000;
diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c
index ffdcbf10b95e..edb7cca14882 100644
--- a/arch/sh/drivers/pci/pci-sh7780.c
+++ b/arch/sh/drivers/pci/pci-sh7780.c
@@ -246,7 +246,7 @@ static int __init sh7780_pci_init(void)
const char *type;
int ret, i;
- printk(KERN_NOTICE "PCI: Starting intialization.\n");
+ printk(KERN_NOTICE "PCI: Starting initialization.\n");
chan->reg_base = 0xfe040000;
diff --git a/arch/sh/drivers/pci/pci-sh7780.h b/arch/sh/drivers/pci/pci-sh7780.h
index 205dcbefe275..1742e2c9db7a 100644
--- a/arch/sh/drivers/pci/pci-sh7780.h
+++ b/arch/sh/drivers/pci/pci-sh7780.h
@@ -12,12 +12,6 @@
#ifndef _PCI_SH7780_H_
#define _PCI_SH7780_H_
-#define PCI_VENDOR_ID_RENESAS 0x1912
-#define PCI_DEVICE_ID_RENESAS_SH7781 0x0001
-#define PCI_DEVICE_ID_RENESAS_SH7780 0x0002
-#define PCI_DEVICE_ID_RENESAS_SH7763 0x0004
-#define PCI_DEVICE_ID_RENESAS_SH7785 0x0007
-
/* SH7780 Control Registers */
#define PCIECR 0xFE000008
#define PCIECR_ENBL 0x01
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 1e9598d2bbf4..60ee09a4e121 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -19,6 +19,7 @@
#include <linux/dma-debug.h>
#include <linux/io.h>
#include <linux/mutex.h>
+#include <linux/spinlock.h>
unsigned long PCIBIOS_MIN_IO = 0x0000;
unsigned long PCIBIOS_MIN_MEM = 0;
@@ -56,6 +57,11 @@ static void __devinit pcibios_scanbus(struct pci_channel *hose)
}
}
+/*
+ * This interrupt-safe spinlock protects all accesses to PCI
+ * configuration space.
+ */
+DEFINE_RAW_SPINLOCK(pci_config_lock);
static DEFINE_MUTEX(pci_scan_mutex);
int __devinit register_pci_controller(struct pci_channel *hose)
@@ -233,40 +239,7 @@ void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
- u16 cmd, old_cmd;
- int idx;
- struct resource *r;
-
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
- old_cmd = cmd;
- for (idx=0; idx < PCI_NUM_RESOURCES; idx++) {
- /* Only set up the requested stuff */
- if (!(mask & (1<<idx)))
- continue;
-
- r = &dev->resource[idx];
- if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
- continue;
- if ((idx == PCI_ROM_RESOURCE) &&
- (!(r->flags & IORESOURCE_ROM_ENABLE)))
- continue;
- if (!r->start && r->end) {
- printk(KERN_ERR "PCI: Device %s not available "
- "because of resource collisions\n",
- pci_name(dev));
- return -EINVAL;
- }
- if (r->flags & IORESOURCE_IO)
- cmd |= PCI_COMMAND_IO;
- if (r->flags & IORESOURCE_MEM)
- cmd |= PCI_COMMAND_MEMORY;
- }
- if (cmd != old_cmd) {
- printk("PCI: Enabling device %s (%04x -> %04x)\n",
- pci_name(dev), old_cmd, cmd);
- pci_write_config_word(dev, PCI_COMMAND, cmd);
- }
- return 0;
+ return pci_enable_resources(dev, mask);
}
/*
@@ -295,7 +268,7 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
-char * __devinit pcibios_setup(char *str)
+char * __devinit __weak pcibios_setup(char *str)
{
return str;
}
diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c
index 68cb9b0ac9d2..96e9b058aa1d 100644
--- a/arch/sh/drivers/pci/pcie-sh7786.c
+++ b/arch/sh/drivers/pci/pcie-sh7786.c
@@ -13,11 +13,14 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/sh_clk.h>
#include "pcie-sh7786.h"
#include <asm/sizes.h>
struct sh7786_pcie_port {
struct pci_channel *hose;
+ struct clk *fclk, phy_clk;
unsigned int index;
int endpoint;
int link;
@@ -51,6 +54,7 @@ static struct resource sh7786_pci0_resources[] = {
.name = "PCIe0 MEM 2",
.start = 0xfe100000,
.end = 0xfe100000 + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
},
};
@@ -74,6 +78,7 @@ static struct resource sh7786_pci1_resources[] = {
.name = "PCIe1 MEM 2",
.start = 0xfe300000,
.end = 0xfe300000 + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
},
};
@@ -82,6 +87,7 @@ static struct resource sh7786_pci2_resources[] = {
.name = "PCIe2 IO",
.start = 0xfc800000,
.end = 0xfc800000 + SZ_4M - 1,
+ .flags = IORESOURCE_IO,
}, {
.name = "PCIe2 MEM 0",
.start = 0x80000000,
@@ -96,6 +102,7 @@ static struct resource sh7786_pci2_resources[] = {
.name = "PCIe2 MEM 2",
.start = 0xfcd00000,
.end = 0xfcd00000 + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
},
};
@@ -117,7 +124,29 @@ static struct pci_channel sh7786_pci_channels[] = {
DEFINE_CONTROLLER(0xfcc00000, 2),
};
-static int phy_wait_for_ack(struct pci_channel *chan)
+static struct clk fixed_pciexclkp = {
+ .rate = 100000000, /* 100 MHz reference clock */
+};
+
+static void __devinit sh7786_pci_fixup(struct pci_dev *dev)
+{
+ /*
+ * Prevent enumeration of root complex resources.
+ */
+ if (pci_is_root_bus(dev->bus) && dev->devfn == 0) {
+ int i;
+
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ dev->resource[i].start = 0;
+ dev->resource[i].end = 0;
+ dev->resource[i].flags = 0;
+ }
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_SH7786,
+ sh7786_pci_fixup);
+
+static int __init phy_wait_for_ack(struct pci_channel *chan)
{
unsigned int timeout = 100;
@@ -131,7 +160,7 @@ static int phy_wait_for_ack(struct pci_channel *chan)
return -ETIMEDOUT;
}
-static int pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
+static int __init pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
{
unsigned int timeout = 100;
@@ -145,19 +174,14 @@ static int pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
return -ETIMEDOUT;
}
-static void phy_write_reg(struct pci_channel *chan, unsigned int addr,
- unsigned int lane, unsigned int data)
+static void __init phy_write_reg(struct pci_channel *chan, unsigned int addr,
+ unsigned int lane, unsigned int data)
{
- unsigned long phyaddr, ctrl;
+ unsigned long phyaddr;
phyaddr = (1 << BITS_CMD) + ((lane & 0xf) << BITS_LANE) +
((addr & 0xff) << BITS_ADR);
- /* Enable clock */
- ctrl = pci_read_reg(chan, SH4A_PCIEPHYCTLR);
- ctrl |= (1 << BITS_CKE);
- pci_write_reg(chan, ctrl, SH4A_PCIEPHYCTLR);
-
/* Set write data */
pci_write_reg(chan, data, SH4A_PCIEPHYDOUTR);
pci_write_reg(chan, phyaddr, SH4A_PCIEPHYADRR);
@@ -165,20 +189,74 @@ static void phy_write_reg(struct pci_channel *chan, unsigned int addr,
phy_wait_for_ack(chan);
/* Clear command */
+ pci_write_reg(chan, 0, SH4A_PCIEPHYDOUTR);
pci_write_reg(chan, 0, SH4A_PCIEPHYADRR);
phy_wait_for_ack(chan);
+}
- /* Disable clock */
- ctrl = pci_read_reg(chan, SH4A_PCIEPHYCTLR);
- ctrl &= ~(1 << BITS_CKE);
- pci_write_reg(chan, ctrl, SH4A_PCIEPHYCTLR);
+static int __init pcie_clk_init(struct sh7786_pcie_port *port)
+{
+ struct pci_channel *chan = port->hose;
+ struct clk *clk;
+ char fclk_name[16];
+ int ret;
+
+ /*
+ * First register the fixed clock
+ */
+ ret = clk_register(&fixed_pciexclkp);
+ if (unlikely(ret != 0))
+ return ret;
+
+ /*
+ * Grab the port's function clock, which the PHY clock depends
+ * on. clock lookups don't help us much at this point, since no
+ * dev_id is available this early. Lame.
+ */
+ snprintf(fclk_name, sizeof(fclk_name), "pcie%d_fck", port->index);
+
+ port->fclk = clk_get(NULL, fclk_name);
+ if (IS_ERR(port->fclk)) {
+ ret = PTR_ERR(port->fclk);
+ goto err_fclk;
+ }
+
+ clk_enable(port->fclk);
+
+ /*
+ * And now, set up the PHY clock
+ */
+ clk = &port->phy_clk;
+
+ memset(clk, 0, sizeof(struct clk));
+
+ clk->parent = &fixed_pciexclkp;
+ clk->enable_reg = (void __iomem *)(chan->reg_base + SH4A_PCIEPHYCTLR);
+ clk->enable_bit = BITS_CKE;
+
+ ret = sh_clk_mstp32_register(clk, 1);
+ if (unlikely(ret < 0))
+ goto err_phy;
+
+ return 0;
+
+err_phy:
+ clk_disable(port->fclk);
+ clk_put(port->fclk);
+err_fclk:
+ clk_unregister(&fixed_pciexclkp);
+
+ return ret;
}
-static int phy_init(struct pci_channel *chan)
+static int __init phy_init(struct sh7786_pcie_port *port)
{
+ struct pci_channel *chan = port->hose;
unsigned int timeout = 100;
+ clk_enable(&port->phy_clk);
+
/* Initialize the phy */
phy_write_reg(chan, 0x60, 0xf, 0x004b008b);
phy_write_reg(chan, 0x61, 0xf, 0x00007b41);
@@ -187,9 +265,13 @@ static int phy_init(struct pci_channel *chan)
phy_write_reg(chan, 0x66, 0xf, 0x00000010);
phy_write_reg(chan, 0x74, 0xf, 0x0007001c);
phy_write_reg(chan, 0x79, 0xf, 0x01fc000d);
+ phy_write_reg(chan, 0xb0, 0xf, 0x00000610);
/* Deassert Standby */
- phy_write_reg(chan, 0x67, 0xf, 0x00000400);
+ phy_write_reg(chan, 0x67, 0x1, 0x00000400);
+
+ /* Disable clock */
+ clk_disable(&port->phy_clk);
while (timeout--) {
if (pci_read_reg(chan, SH4A_PCIEPHYSR))
@@ -201,22 +283,33 @@ static int phy_init(struct pci_channel *chan)
return -ETIMEDOUT;
}
-static int pcie_init(struct sh7786_pcie_port *port)
+static void __init pcie_reset(struct sh7786_pcie_port *port)
+{
+ struct pci_channel *chan = port->hose;
+
+ pci_write_reg(chan, 1, SH4A_PCIESRSTR);
+ pci_write_reg(chan, 0, SH4A_PCIETCTLR);
+ pci_write_reg(chan, 0, SH4A_PCIESRSTR);
+ pci_write_reg(chan, 0, SH4A_PCIETXVC0SR);
+}
+
+static int __init pcie_init(struct sh7786_pcie_port *port)
{
struct pci_channel *chan = port->hose;
unsigned int data;
phys_addr_t memphys;
size_t memsize;
- int ret, i;
+ int ret, i, win;
/* Begin initialization */
- pci_write_reg(chan, 0, SH4A_PCIETCTLR);
+ pcie_reset(port);
- /* Initialize as type1. */
- data = pci_read_reg(chan, SH4A_PCIEPCICONF3);
- data &= ~(0x7f << 16);
- data |= PCI_HEADER_TYPE_BRIDGE << 16;
- pci_write_reg(chan, data, SH4A_PCIEPCICONF3);
+ /*
+ * Initial header for port config space is type 1, set the device
+ * class to match. Hardware takes care of propagating the IDSETR
+ * settings, so there is no need to bother with a quirk.
+ */
+ pci_write_reg(chan, PCI_CLASS_BRIDGE_PCI << 16, SH4A_PCIEIDSETR1);
/* Initialize default capabilities. */
data = pci_read_reg(chan, SH4A_PCIEEXPCAP0);
@@ -268,30 +361,33 @@ static int pcie_init(struct sh7786_pcie_port *port)
* LAR1/LAMR1.
*/
if (memsize > SZ_512M) {
- __raw_writel(memphys + SZ_512M, chan->reg_base + SH4A_PCIELAR1);
- __raw_writel(((memsize - SZ_512M) - SZ_256) | 1,
- chan->reg_base + SH4A_PCIELAMR1);
+ pci_write_reg(chan, memphys + SZ_512M, SH4A_PCIELAR1);
+ pci_write_reg(chan, ((memsize - SZ_512M) - SZ_256) | 1,
+ SH4A_PCIELAMR1);
memsize = SZ_512M;
} else {
/*
* Otherwise just zero it out and disable it.
*/
- __raw_writel(0, chan->reg_base + SH4A_PCIELAR1);
- __raw_writel(0, chan->reg_base + SH4A_PCIELAMR1);
+ pci_write_reg(chan, 0, SH4A_PCIELAR1);
+ pci_write_reg(chan, 0, SH4A_PCIELAMR1);
}
/*
* LAR0/LAMR0 covers up to the first 512MB, which is enough to
* cover all of lowmem on most platforms.
*/
- __raw_writel(memphys, chan->reg_base + SH4A_PCIELAR0);
- __raw_writel((memsize - SZ_256) | 1, chan->reg_base + SH4A_PCIELAMR0);
+ pci_write_reg(chan, memphys, SH4A_PCIELAR0);
+ pci_write_reg(chan, (memsize - SZ_256) | 1, SH4A_PCIELAMR0);
/* Finish initialization */
data = pci_read_reg(chan, SH4A_PCIETCTLR);
data |= 0x1;
pci_write_reg(chan, data, SH4A_PCIETCTLR);
+ /* Let things settle down a bit.. */
+ mdelay(100);
+
/* Enable DL_Active Interrupt generation */
data = pci_read_reg(chan, SH4A_PCIEDLINTENR);
data |= PCIEDLINTENR_DLL_ACT_ENABLE;
@@ -302,9 +398,12 @@ static int pcie_init(struct sh7786_pcie_port *port)
data |= PCIEMACCTLR_SCR_DIS | (0xff << 16);
pci_write_reg(chan, data, SH4A_PCIEMACCTLR);
+ /*
+ * This will timeout if we don't have a link, but we permit the
+ * port to register anyways in order to support hotplug on future
+ * hardware.
+ */
ret = pci_wait_for_irq(chan, MASK_INT_TX_CTRL);
- if (unlikely(ret != 0))
- return -ENODEV;
data = pci_read_reg(chan, SH4A_PCIEPCICONF1);
data &= ~(PCI_STATUS_DEVSEL_MASK << 16);
@@ -317,35 +416,48 @@ static int pcie_init(struct sh7786_pcie_port *port)
wmb();
- data = pci_read_reg(chan, SH4A_PCIEMACSR);
- printk(KERN_NOTICE "PCI: PCIe#%d link width %d\n",
- port->index, (data >> 20) & 0x3f);
-
+ if (ret == 0) {
+ data = pci_read_reg(chan, SH4A_PCIEMACSR);
+ printk(KERN_NOTICE "PCI: PCIe#%d x%d link detected\n",
+ port->index, (data >> 20) & 0x3f);
+ } else
+ printk(KERN_NOTICE "PCI: PCIe#%d link down\n",
+ port->index);
- for (i = 0; i < chan->nr_resources; i++) {
+ for (i = win = 0; i < chan->nr_resources; i++) {
struct resource *res = chan->resources + i;
resource_size_t size;
- u32 enable_mask;
+ u32 mask;
- pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(i));
+ /*
+ * We can't use the 32-bit mode windows in legacy 29-bit
+ * mode, so just skip them entirely.
+ */
+ if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode())
+ continue;
- size = resource_size(res);
+ pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(win));
/*
* The PAMR mask is calculated in units of 256kB, which
* keeps things pretty simple.
*/
- __raw_writel(((roundup_pow_of_two(size) / SZ_256K) - 1) << 18,
- chan->reg_base + SH4A_PCIEPAMR(i));
+ size = resource_size(res);
+ mask = (roundup_pow_of_two(size) / SZ_256K) - 1;
+ pci_write_reg(chan, mask << 18, SH4A_PCIEPAMR(win));
- pci_write_reg(chan, 0x00000000, SH4A_PCIEPARH(i));
- pci_write_reg(chan, 0x00000000, SH4A_PCIEPARL(i));
+ pci_write_reg(chan, upper_32_bits(res->start),
+ SH4A_PCIEPARH(win));
+ pci_write_reg(chan, lower_32_bits(res->start),
+ SH4A_PCIEPARL(win));
- enable_mask = MASK_PARE;
+ mask = MASK_PARE;
if (res->flags & IORESOURCE_IO)
- enable_mask |= MASK_SPC;
+ mask |= MASK_SPC;
+
+ pci_write_reg(chan, mask, SH4A_PCIEPTCTLR(win));
- pci_write_reg(chan, enable_mask, SH4A_PCIEPTCTLR(i));
+ win++;
}
return 0;
@@ -356,26 +468,33 @@ int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
return 71;
}
-static int sh7786_pcie_core_init(void)
+static int __init sh7786_pcie_core_init(void)
{
/* Return the number of ports */
return test_mode_pin(MODE_PIN12) ? 3 : 2;
}
-static int __devinit sh7786_pcie_init_hw(struct sh7786_pcie_port *port)
+static int __init sh7786_pcie_init_hw(struct sh7786_pcie_port *port)
{
int ret;
- ret = phy_init(port->hose);
- if (unlikely(ret < 0))
- return ret;
-
/*
* Check if we are configured in endpoint or root complex mode,
* this is a fixed pin setting that applies to all PCIe ports.
*/
port->endpoint = test_mode_pin(MODE_PIN11);
+ /*
+ * Setup clocks, needed both for PHY and PCIe registers.
+ */
+ ret = pcie_clk_init(port);
+ if (unlikely(ret < 0))
+ return ret;
+
+ ret = phy_init(port);
+ if (unlikely(ret < 0))
+ return ret;
+
ret = pcie_init(port);
if (unlikely(ret < 0))
return ret;
@@ -390,9 +509,10 @@ static struct sh7786_pcie_hwops sh7786_65nm_pcie_hwops __initdata = {
static int __init sh7786_pcie_init(void)
{
+ struct clk *platclk;
int ret = 0, i;
- printk(KERN_NOTICE "PCI: Starting intialization.\n");
+ printk(KERN_NOTICE "PCI: Starting initialization.\n");
sh7786_pcie_hwops = &sh7786_65nm_pcie_hwops;
@@ -407,6 +527,22 @@ static int __init sh7786_pcie_init(void)
if (unlikely(!sh7786_pcie_ports))
return -ENOMEM;
+ /*
+ * Fetch any optional platform clock associated with this block.
+ *
+ * This is a rather nasty hack for boards with spec-mocking FPGAs
+ * that have a secondary set of clocks outside of the on-chip
+ * ones that need to be accounted for before there is any chance
+ * of touching the existing MSTP bits or CPG clocks.
+ */
+ platclk = clk_get(NULL, "pcie_plat_clk");
+ if (IS_ERR(platclk)) {
+ /* Sane hardware should probably get a WARN_ON.. */
+ platclk = NULL;
+ }
+
+ clk_enable(platclk);
+
printk(KERN_NOTICE "PCI: probing %d ports.\n", nr_ports);
for (i = 0; i < nr_ports; i++) {
@@ -419,8 +555,11 @@ static int __init sh7786_pcie_init(void)
ret |= sh7786_pcie_hwops->port_init_hw(port);
}
- if (unlikely(ret))
+ if (unlikely(ret)) {
+ clk_disable(platclk);
+ clk_put(platclk);
return ret;
+ }
return 0;
}
diff --git a/arch/sh/drivers/pci/pcie-sh7786.h b/arch/sh/drivers/pci/pcie-sh7786.h
index 90a6992576b0..1ee054e47eae 100644
--- a/arch/sh/drivers/pci/pcie-sh7786.h
+++ b/arch/sh/drivers/pci/pcie-sh7786.h
@@ -55,8 +55,11 @@
#define BITS_ERRRCV (0) /* 0 ERRRCV 0 */
#define MASK_ERRRCV (1<<BITS_ERRRCV)
+/* PCIEENBLR */
+#define SH4A_PCIEENBLR (0x000008) /* R/W - 0x0000 0001 32 */
+
/* PCIEECR */
-#define SH4A_PCIEECR (0x000008) /* R/W - 0x0000 0000 32 */
+#define SH4A_PCIEECR (0x00000C) /* R/W - 0x0000 0000 32 */
#define BITS_ENBL (0) /* 0 ENBL 0 R/W */
#define MASK_ENBL (1<<BITS_ENBL)
@@ -113,6 +116,27 @@
#define BITS_MDATA (0)
#define MASK_MDATA (0xffffffff<<BITS_MDATA)
+/* PCIEUNLOCKCR */
+#define SH4A_PCIEUNLOCKCR (0x000048) /* R/W - 0x0000 0000 32 */
+
+/* PCIEIDR */
+#define SH4A_PCIEIDR (0x000060) /* R/W - 0x0101 1101 32 */
+
+/* PCIEDBGCTLR */
+#define SH4A_PCIEDBGCTLR (0x000100) /* R/W - 0x0000 0000 32 */
+
+/* PCIEINTXR */
+#define SH4A_PCIEINTXR (0x004000) /* R/W - 0x0000 0000 32 */
+
+/* PCIERMSGR */
+#define SH4A_PCIERMSGR (0x004010) /* R/W - 0x0000 0000 32 */
+
+/* PCIERSTR */
+#define SH4A_PCIERSTR(x) (0x008000 + ((x) * 0x4)) /* R/W - 0x0000 0000 32 */
+
+/* PCIESRSTR */
+#define SH4A_PCIESRSTR (0x008040) /* R/W - 0x0000 0000 32 */
+
/* PCIEPHYCTLR */
#define SH4A_PCIEPHYCTLR (0x010000) /* R/W - 0x0000 0000 32 */
#define BITS_CKE (0)
@@ -121,6 +145,9 @@
/* PCIERMSGIER */
#define SH4A_PCIERMSGIER (0x004040) /* R/W - 0x0000 0000 32 */
+/* PCIEPHYCTLR */
+#define SH4A_PCIEPHYCTLR (0x010000) /* R/W - 0x0000 0000 32 */
+
/* PCIEPHYADRR */
#define SH4A_PCIEPHYADRR (0x010004) /* R/W - 0x0000 0000 32 */
#define BITS_ACK (24) // Rev1.171
@@ -152,7 +179,7 @@
#define MASK_CFINT (1<<BITS_CFINT)
/* PCIETSTR */
-#define SH4A_PCIETSTR (0x020004) /* R/W R/W 0x0000 0000 32 */
+#define SH4A_PCIETSTR (0x020004) /* R 0x0000 0000 32 */
/* PCIEINTR */
#define SH4A_PCIEINTR (0x020008) /* R/W R/W 0x0000 0000 32 */
@@ -236,6 +263,9 @@
#define BITS_INTPM (8)
#define MASK_INTPM (1<<BITS_INTPM)
+/* PCIEEH0R */
+#define SH4A_PCIEEHR(x) (0x020010 + ((x) * 0x4)) /* R - 0x0000 0000 32 */
+
/* PCIEAIR */
#define SH4A_PCIEAIR (SH4A_PCIE_BASE + 0x020010) /* R/W R/W 0xxxxx xxxx 32 */
@@ -244,6 +274,25 @@
/* PCIEERRFR */ // Rev1.18
#define SH4A_PCIEERRFR (0x020020) /* R/W R/W 0xxxxx xxxx 32 */ // Rev1.18
+
+/* PCIEERRFER */
+#define SH4A_PCIEERRFER (0x020024) /* R/W R/W 0x0000 0000 32 */
+
+/* PCIEERRFR2 */
+#define SH4A_PCIEERRFR2 (0x020028) /* R/W R/W 0x0000 0000 32 */
+
+/* PCIEMSIR */
+#define SH4A_PCIEMSIR (0x020040) /* R/W - 0x0000 0000 32 */
+
+/* PCIEMSIFR */
+#define SH4A_PCIEMSIFR (0x020044) /* R/W R/W 0x0000 0000 32 */
+
+/* PCIEPWRCTLR */
+#define SH4A_PCIEPWRCTLR (0x020100) /* R/W - 0x0000 0000 32 */
+
+/* PCIEPCCTLR */
+#define SH4A_PCIEPCCTLR (0x020180) /* R/W - 0x0000 0000 32 */
+
// Rev1.18
/* PCIELAR0 */
#define SH4A_PCIELAR0 (0x020200) /* R/W R/W 0x0000 0000 32 */
@@ -352,6 +401,7 @@
#define SH4A_PCIEDMCCR0 (0x021120) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEDMCC2R0 (0x021124) /* R/W R/W 0x0000 0000 - */
#define SH4A_PCIEDMCCCR0 (0x021128) /* R/W R/W 0x0000 0000 32 */
+#define SH4A_PCIEDMCHSR0 (0x02112C) /* R/W - 0x0000 0000 32 */
#define SH4A_PCIEDMSAR1 (0x021140) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEDMSAHR1 (0x021144) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEDMDAR1 (0x021148) /* R/W R/W 0x0000 0000 32 */
@@ -363,6 +413,7 @@
#define SH4A_PCIEDMCCR1 (0x021160) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEDMCC2R1 (0x021164) /* R/W R/W 0x0000 0000 - */
#define SH4A_PCIEDMCCCR1 (0x021168) /* R/W R/W 0x0000 0000 32 */
+#define SH4A_PCIEDMCHSR1 (0x02116C) /* R/W - 0x0000 0000 32 */
#define SH4A_PCIEDMSAR2 (0x021180) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEDMSAHR2 (0x021184) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEDMDAR2 (0x021188) /* R/W R/W 0x0000 0000 32 */
@@ -385,6 +436,7 @@
#define SH4A_PCIEDMCCR3 (0x0211E0) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEDMCC2R3 (0x0211E4) /* R/W R/W 0x0000 0000 - */
#define SH4A_PCIEDMCCCR3 (0x0211E8) /* R/W R/W 0x0000 0000 32 */
+#define SH4A_PCIEDMCHSR3 (0x0211EC) /* R/W R/W 0x0000 0000 32 */
#define SH4A_PCIEPCICONF0 (0x040000) /* R R - 8/16/32 */
#define SH4A_PCIEPCICONF1 (0x040004) /* R/W R/W 0x0008 0000 8/16/32 */
#define SH4A_PCIEPCICONF2 (0x040008) /* R/W R/W 0xFF00 0000 8/16/32 */
diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild
index 0eed47b236ab..7beb42322f60 100644
--- a/arch/sh/include/asm/Kbuild
+++ b/arch/sh/include/asm/Kbuild
@@ -5,5 +5,7 @@ header-y += cpu-features.h
header-y += hw_breakpoint.h
header-y += posix_types_32.h
header-y += posix_types_64.h
+header-y += ptrace_32.h
+header-y += ptrace_64.h
header-y += unistd_32.h
header-y += unistd_64.h
diff --git a/arch/sh/include/asm/elf.h b/arch/sh/include/asm/elf.h
index ce830faeebbf..f38112be67d2 100644
--- a/arch/sh/include/asm/elf.h
+++ b/arch/sh/include/asm/elf.h
@@ -50,25 +50,14 @@
#define R_SH_GOTPC 167
/* FDPIC relocs */
-#define R_SH_GOT20 70
-#define R_SH_GOTOFF20 71
-#define R_SH_GOTFUNCDESC 72
-#define R_SH_GOTFUNCDESC20 73
-#define R_SH_GOTOFFFUNCDESC 74
-#define R_SH_GOTOFFFUNCDESC20 75
-#define R_SH_FUNCDESC 76
-#define R_SH_FUNCDESC_VALUE 77
-
-#if 0 /* XXX - later .. */
-#define R_SH_GOT20 198
-#define R_SH_GOTOFF20 199
-#define R_SH_GOTFUNCDESC 200
-#define R_SH_GOTFUNCDESC20 201
-#define R_SH_GOTOFFFUNCDESC 202
-#define R_SH_GOTOFFFUNCDESC20 203
-#define R_SH_FUNCDESC 204
-#define R_SH_FUNCDESC_VALUE 205
-#endif
+#define R_SH_GOT20 201
+#define R_SH_GOTOFF20 202
+#define R_SH_GOTFUNCDESC 203
+#define R_SH_GOTFUNCDESC20 204
+#define R_SH_GOTOFFFUNCDESC 205
+#define R_SH_GOTOFFFUNCDESC20 206
+#define R_SH_FUNCDESC 207
+#define R_SH_FUNCDESC_VALUE 208
/* SHmedia relocs */
#define R_SH_IMM_LOW16 246
diff --git a/arch/sh/include/asm/fixmap.h b/arch/sh/include/asm/fixmap.h
index 6e7cea453895..bd7e79a12653 100644
--- a/arch/sh/include/asm/fixmap.h
+++ b/arch/sh/include/asm/fixmap.h
@@ -58,7 +58,7 @@ enum fixed_addresses {
#ifdef CONFIG_HIGHMEM
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
- FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+ FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * NR_CPUS) - 1,
#endif
#ifdef CONFIG_IOREMAP_FIXED
@@ -69,7 +69,7 @@ enum fixed_addresses {
*/
#define FIX_N_IOREMAPS 32
FIX_IOREMAP_BEGIN,
- FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS,
+ FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS - 1,
#endif
__end_of_fixed_addresses
diff --git a/arch/sh/include/asm/gpio.h b/arch/sh/include/asm/gpio.h
index f8d9a731e903..04f53d31489f 100644
--- a/arch/sh/include/asm/gpio.h
+++ b/arch/sh/include/asm/gpio.h
@@ -41,14 +41,12 @@ static inline int gpio_cansleep(unsigned gpio)
static inline int gpio_to_irq(unsigned gpio)
{
- WARN_ON(1);
- return -ENOSYS;
+ return __gpio_to_irq(gpio);
}
static inline int irq_to_gpio(unsigned int irq)
{
- WARN_ON(1);
- return -EINVAL;
+ return -ENOSYS;
}
#endif /* CONFIG_GPIOLIB */
diff --git a/arch/sh/include/asm/irq.h b/arch/sh/include/asm/irq.h
index 02c2f0102cfa..45d08b6a5ef7 100644
--- a/arch/sh/include/asm/irq.h
+++ b/arch/sh/include/asm/irq.h
@@ -9,7 +9,7 @@
* advised to cap this at the hard limit that they're interested in
* through the machvec.
*/
-#define NR_IRQS 256
+#define NR_IRQS 512
#define NR_IRQS_LEGACY 8 /* Legacy external IRQ0-7 */
/*
diff --git a/arch/sh/include/asm/kprobes.h b/arch/sh/include/asm/kprobes.h
index 036c3311233c..134f3980e44a 100644
--- a/arch/sh/include/asm/kprobes.h
+++ b/arch/sh/include/asm/kprobes.h
@@ -16,7 +16,6 @@ typedef insn_size_t kprobe_opcode_t;
? (MAX_STACK_SIZE) \
: (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
-#define regs_return_value(_regs) ((_regs)->regs[0])
#define flush_insn_slot(p) do { } while (0)
#define kretprobe_blacklist_size 0
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index 8bd952fcf3ba..f0efe97f1750 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -37,6 +37,8 @@ struct pci_channel {
};
/* arch/sh/drivers/pci/pci.c */
+extern raw_spinlock_t pci_config_lock;
+
extern int register_pci_controller(struct pci_channel *hose);
extern void pcibios_report_status(unsigned int status_mask, int warn);
diff --git a/arch/sh/include/asm/pgtable_32.h b/arch/sh/include/asm/pgtable_32.h
index e172d696e52b..69fdfbf14ea5 100644
--- a/arch/sh/include/asm/pgtable_32.h
+++ b/arch/sh/include/asm/pgtable_32.h
@@ -429,10 +429,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
#define pte_offset_kernel(dir, address) \
((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
#define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
-#define pte_offset_map_nested(dir, address) pte_offset_kernel(dir, address)
-
#define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
#ifdef CONFIG_X2TLB
#define pte_ERROR(e) \
diff --git a/arch/sh/include/asm/pgtable_64.h b/arch/sh/include/asm/pgtable_64.h
index 0ee46776dad6..10a48111226d 100644
--- a/arch/sh/include/asm/pgtable_64.h
+++ b/arch/sh/include/asm/pgtable_64.h
@@ -84,9 +84,7 @@ static __inline__ void set_pte(pte_t *pteptr, pte_t pteval)
((pte_t *) ((pmd_val(*(dir))) & PAGE_MASK) + pte_index((addr)))
#define pte_offset_map(dir,addr) pte_offset_kernel(dir, addr)
-#define pte_offset_map_nested(dir,addr) pte_offset_kernel(dir, addr)
#define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
#ifndef __ASSEMBLY__
#define IOBASE_VADDR 0xff000000
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h
index 61a445d2d02a..46d5179c9f49 100644
--- a/arch/sh/include/asm/processor_32.h
+++ b/arch/sh/include/asm/processor_32.h
@@ -13,7 +13,6 @@
#include <linux/linkage.h>
#include <asm/page.h>
#include <asm/types.h>
-#include <asm/ptrace.h>
#include <asm/hw_breakpoint.h>
/*
@@ -194,8 +193,6 @@ extern unsigned long get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc)
#define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[15])
-#define user_stack_pointer(_regs) ((_regs)->regs[15])
-
#if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH4)
#define PREFETCH_STRIDE L1_CACHE_BYTES
#define ARCH_HAS_PREFETCH
diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h
index 621bc4618c6b..2a541ddb5a1b 100644
--- a/arch/sh/include/asm/processor_64.h
+++ b/arch/sh/include/asm/processor_64.h
@@ -17,7 +17,6 @@
#include <linux/compiler.h>
#include <asm/page.h>
#include <asm/types.h>
-#include <asm/ptrace.h>
#include <cpu/registers.h>
/*
@@ -231,7 +230,5 @@ extern unsigned long get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) ((tsk)->thread.pc)
#define KSTK_ESP(tsk) ((tsk)->thread.sp)
-#define user_stack_pointer(_regs) ((_regs)->regs[15])
-
#endif /* __ASSEMBLY__ */
#endif /* __ASM_SH_PROCESSOR_64_H */
diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h
index 2168fde25611..f6edc10aa0d3 100644
--- a/arch/sh/include/asm/ptrace.h
+++ b/arch/sh/include/asm/ptrace.h
@@ -3,90 +3,7 @@
/*
* Copyright (C) 1999, 2000 Niibe Yutaka
- *
- */
-#if defined(__SH5__)
-struct pt_regs {
- unsigned long long pc;
- unsigned long long sr;
- long long syscall_nr;
- unsigned long long regs[63];
- unsigned long long tregs[8];
- unsigned long long pad[2];
-};
-#else
-/*
- * GCC defines register number like this:
- * -----------------------------
- * 0 - 15 are integer registers
- * 17 - 22 are control/special registers
- * 24 - 39 fp registers
- * 40 - 47 xd registers
- * 48 - fpscr register
- * -----------------------------
- *
- * We follows above, except:
- * 16 --- program counter (PC)
- * 22 --- syscall #
- * 23 --- floating point communication register
*/
-#define REG_REG0 0
-#define REG_REG15 15
-
-#define REG_PC 16
-
-#define REG_PR 17
-#define REG_SR 18
-#define REG_GBR 19
-#define REG_MACH 20
-#define REG_MACL 21
-
-#define REG_SYSCALL 22
-
-#define REG_FPREG0 23
-#define REG_FPREG15 38
-#define REG_XFREG0 39
-#define REG_XFREG15 54
-
-#define REG_FPSCR 55
-#define REG_FPUL 56
-
-/*
- * This struct defines the way the registers are stored on the
- * kernel stack during a system call or other kernel entry.
- */
-struct pt_regs {
- unsigned long regs[16];
- unsigned long pc;
- unsigned long pr;
- unsigned long sr;
- unsigned long gbr;
- unsigned long mach;
- unsigned long macl;
- long tra;
-};
-
-/*
- * This struct defines the way the DSP registers are stored on the
- * kernel stack during a system call or other kernel entry.
- */
-struct pt_dspregs {
- unsigned long a1;
- unsigned long a0g;
- unsigned long a1g;
- unsigned long m0;
- unsigned long m1;
- unsigned long a0;
- unsigned long x0;
- unsigned long x1;
- unsigned long y0;
- unsigned long y1;
- unsigned long dsr;
- unsigned long rs;
- unsigned long re;
- unsigned long mod;
-};
-#endif
#define PTRACE_GETREGS 12 /* General registers */
#define PTRACE_SETREGS 13
@@ -107,22 +24,102 @@ struct pt_dspregs {
#define PT_DATA_ADDR 248 /* &(struct user)->start_data */
#define PT_TEXT_LEN 252
+#if defined(__SH5__) || defined(CONFIG_CPU_SH5)
+#include "ptrace_64.h"
+#else
+#include "ptrace_32.h"
+#endif
+
#ifdef __KERNEL__
+
+#include <linux/stringify.h>
+#include <linux/stddef.h>
+#include <linux/thread_info.h>
#include <asm/addrspace.h>
#include <asm/page.h>
#include <asm/system.h>
#define user_mode(regs) (((regs)->sr & 0x40000000)==0)
+#define user_stack_pointer(regs) ((unsigned long)(regs)->regs[15])
+#define kernel_stack_pointer(regs) ((unsigned long)(regs)->regs[15])
#define instruction_pointer(regs) ((unsigned long)(regs)->pc)
extern void show_regs(struct pt_regs *);
+#define arch_has_single_step() (1)
+
/*
- * These are defined as per linux/ptrace.h.
+ * kprobe-based event tracer support
*/
-struct task_struct;
+struct pt_regs_offset {
+ const char *name;
+ int offset;
+};
-#define arch_has_single_step() (1)
+#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
+#define REGS_OFFSET_NAME(num) \
+ {.name = __stringify(r##num), .offset = offsetof(struct pt_regs, regs[num])}
+#define TREGS_OFFSET_NAME(num) \
+ {.name = __stringify(tr##num), .offset = offsetof(struct pt_regs, tregs[num])}
+#define REG_OFFSET_END {.name = NULL, .offset = 0}
+
+/* Query offset/name of register from its name/offset */
+extern int regs_query_register_offset(const char *name);
+extern const char *regs_query_register_name(unsigned int offset);
+
+extern const struct pt_regs_offset regoffset_table[];
+
+/**
+ * regs_get_register() - get register value from its offset
+ * @regs: pt_regs from which register value is gotten.
+ * @offset: offset number of the register.
+ *
+ * regs_get_register returns the value of a register. The @offset is the
+ * offset of the register in struct pt_regs address which specified by @regs.
+ * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
+ */
+static inline unsigned long regs_get_register(struct pt_regs *regs,
+ unsigned int offset)
+{
+ if (unlikely(offset > MAX_REG_OFFSET))
+ return 0;
+ return *(unsigned long *)((unsigned long)regs + offset);
+}
+
+/**
+ * regs_within_kernel_stack() - check the address in the stack
+ * @regs: pt_regs which contains kernel stack pointer.
+ * @addr: address which is checked.
+ *
+ * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
+ * If @addr is within the kernel stack, it returns true. If not, returns false.
+ */
+static inline int regs_within_kernel_stack(struct pt_regs *regs,
+ unsigned long addr)
+{
+ return ((addr & ~(THREAD_SIZE - 1)) ==
+ (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
+}
+
+/**
+ * regs_get_kernel_stack_nth() - get Nth entry of the stack
+ * @regs: pt_regs which contains kernel stack pointer.
+ * @n: stack entry number.
+ *
+ * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
+ * is specified by @regs. If the @n th entry is NOT in the kernel stack,
+ * this returns 0.
+ */
+static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
+ unsigned int n)
+{
+ unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
+ addr += n;
+ if (regs_within_kernel_stack(regs, (unsigned long)addr))
+ return *addr;
+ else
+ return 0;
+}
struct perf_event;
struct perf_sample_data;
diff --git a/arch/sh/include/asm/ptrace_32.h b/arch/sh/include/asm/ptrace_32.h
new file mode 100644
index 000000000000..35d9e257558c
--- /dev/null
+++ b/arch/sh/include/asm/ptrace_32.h
@@ -0,0 +1,83 @@
+#ifndef __ASM_SH_PTRACE_32_H
+#define __ASM_SH_PTRACE_32_H
+
+/*
+ * GCC defines register number like this:
+ * -----------------------------
+ * 0 - 15 are integer registers
+ * 17 - 22 are control/special registers
+ * 24 - 39 fp registers
+ * 40 - 47 xd registers
+ * 48 - fpscr register
+ * -----------------------------
+ *
+ * We follows above, except:
+ * 16 --- program counter (PC)
+ * 22 --- syscall #
+ * 23 --- floating point communication register
+ */
+#define REG_REG0 0
+#define REG_REG15 15
+
+#define REG_PC 16
+
+#define REG_PR 17
+#define REG_SR 18
+#define REG_GBR 19
+#define REG_MACH 20
+#define REG_MACL 21
+
+#define REG_SYSCALL 22
+
+#define REG_FPREG0 23
+#define REG_FPREG15 38
+#define REG_XFREG0 39
+#define REG_XFREG15 54
+
+#define REG_FPSCR 55
+#define REG_FPUL 56
+
+/*
+ * This struct defines the way the registers are stored on the
+ * kernel stack during a system call or other kernel entry.
+ */
+struct pt_regs {
+ unsigned long regs[16];
+ unsigned long pc;
+ unsigned long pr;
+ unsigned long sr;
+ unsigned long gbr;
+ unsigned long mach;
+ unsigned long macl;
+ long tra;
+};
+
+/*
+ * This struct defines the way the DSP registers are stored on the
+ * kernel stack during a system call or other kernel entry.
+ */
+struct pt_dspregs {
+ unsigned long a1;
+ unsigned long a0g;
+ unsigned long a1g;
+ unsigned long m0;
+ unsigned long m1;
+ unsigned long a0;
+ unsigned long x0;
+ unsigned long x1;
+ unsigned long y0;
+ unsigned long y1;
+ unsigned long dsr;
+ unsigned long rs;
+ unsigned long re;
+ unsigned long mod;
+};
+
+#ifdef __KERNEL__
+
+#define MAX_REG_OFFSET offsetof(struct pt_regs, tra)
+#define regs_return_value(regs) ((regs)->regs[0])
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_SH_PTRACE_32_H */
diff --git a/arch/sh/include/asm/ptrace_64.h b/arch/sh/include/asm/ptrace_64.h
new file mode 100644
index 000000000000..d43c1cb0bbe7
--- /dev/null
+++ b/arch/sh/include/asm/ptrace_64.h
@@ -0,0 +1,20 @@
+#ifndef __ASM_SH_PTRACE_64_H
+#define __ASM_SH_PTRACE_64_H
+
+struct pt_regs {
+ unsigned long long pc;
+ unsigned long long sr;
+ long long syscall_nr;
+ unsigned long long regs[63];
+ unsigned long long tregs[8];
+ unsigned long long pad[2];
+};
+
+#ifdef __KERNEL__
+
+#define MAX_REG_OFFSET offsetof(struct pt_regs, tregs[7])
+#define regs_return_value(regs) ((regs)->regs[3])
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_SH_PTRACE_64_H */
diff --git a/arch/sh/include/asm/sizes.h b/arch/sh/include/asm/sizes.h
index 3a1fb97770f1..0b9fe2d5c36d 100644
--- a/arch/sh/include/asm/sizes.h
+++ b/arch/sh/include/asm/sizes.h
@@ -32,6 +32,7 @@
#define SZ_512 0x00000200
#define SZ_1K 0x00000400
+#define SZ_2K 0x00000800
#define SZ_4K 0x00001000
#define SZ_8K 0x00002000
#define SZ_16K 0x00004000
diff --git a/arch/sh/include/asm/sram.h b/arch/sh/include/asm/sram.h
new file mode 100644
index 000000000000..a2808ce4c0aa
--- /dev/null
+++ b/arch/sh/include/asm/sram.h
@@ -0,0 +1,38 @@
+#ifndef __ASM_SRAM_H
+#define __ASM_SRAM_H
+
+#ifdef CONFIG_HAVE_SRAM_POOL
+
+#include <linux/spinlock.h>
+#include <linux/genalloc.h>
+
+/* arch/sh/mm/sram.c */
+extern struct gen_pool *sram_pool;
+
+static inline unsigned long sram_alloc(size_t len)
+{
+ if (!sram_pool)
+ return 0UL;
+
+ return gen_pool_alloc(sram_pool, len);
+}
+
+static inline void sram_free(unsigned long addr, size_t len)
+{
+ return gen_pool_free(sram_pool, addr, len);
+}
+
+#else
+
+static inline unsigned long sram_alloc(size_t len)
+{
+ return 0;
+}
+
+static inline void sram_free(unsigned long addr, size_t len)
+{
+}
+
+#endif /* CONFIG_HAVE_SRAM_POOL */
+
+#endif /* __ASM_SRAM_H */
diff --git a/arch/sh/include/asm/system.h b/arch/sh/include/asm/system.h
index 0bd7a17d5e1a..1f1af5afff03 100644
--- a/arch/sh/include/asm/system.h
+++ b/arch/sh/include/asm/system.h
@@ -140,8 +140,6 @@ extern unsigned int instruction_size(unsigned int insn);
extern unsigned long cached_to_uncached;
extern unsigned long uncached_size;
-extern struct dentry *sh_debugfs_root;
-
void per_cpu_trap_init(void);
void default_idle(void);
void cpu_idle_wait(void);
diff --git a/arch/sh/include/asm/system_32.h b/arch/sh/include/asm/system_32.h
index 51296b36770e..c941b2739405 100644
--- a/arch/sh/include/asm/system_32.h
+++ b/arch/sh/include/asm/system_32.h
@@ -212,17 +212,16 @@ static inline reg_size_t register_align(void *val)
}
int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
- struct mem_access *ma, int);
+ struct mem_access *ma, int, unsigned long address);
static inline void trigger_address_error(void)
{
- if (__in_29bit_mode())
- __asm__ __volatile__ (
- "ldc %0, sr\n\t"
- "mov.l @%1, %0"
- :
- : "r" (0x10000000), "r" (0x80000001)
- );
+ __asm__ __volatile__ (
+ "ldc %0, sr\n\t"
+ "mov.l @%1, %0"
+ :
+ : "r" (0x10000000), "r" (0x80000001)
+ );
}
asmlinkage void do_address_error(struct pt_regs *regs,
diff --git a/arch/sh/include/asm/tlbflush.h b/arch/sh/include/asm/tlbflush.h
index e0ac97221ae6..0df66f0c7284 100644
--- a/arch/sh/include/asm/tlbflush.h
+++ b/arch/sh/include/asm/tlbflush.h
@@ -21,6 +21,8 @@ extern void local_flush_tlb_kernel_range(unsigned long start,
unsigned long end);
extern void local_flush_tlb_one(unsigned long asid, unsigned long page);
+extern void __flush_tlb_global(void);
+
#ifdef CONFIG_SMP
extern void flush_tlb_all(void);
diff --git a/arch/sh/include/asm/unistd_32.h b/arch/sh/include/asm/unistd_32.h
index 0e7f0fc8f086..903cd618eb74 100644
--- a/arch/sh/include/asm/unistd_32.h
+++ b/arch/sh/include/asm/unistd_32.h
@@ -345,12 +345,33 @@
#define __NR_pwritev 334
#define __NR_rt_tgsigqueueinfo 335
#define __NR_perf_event_open 336
+#define __NR_fanotify_init 337
+#define __NR_fanotify_mark 338
+#define __NR_prlimit64 339
-#define NR_syscalls 337
+/* Non-multiplexed socket family */
+#define __NR_socket 340
+#define __NR_bind 341
+#define __NR_connect 342
+#define __NR_listen 343
+#define __NR_accept 344
+#define __NR_getsockname 345
+#define __NR_getpeername 346
+#define __NR_socketpair 347
+#define __NR_send 348
+#define __NR_sendto 349
+#define __NR_recv 350
+#define __NR_recvfrom 351
+#define __NR_shutdown 352
+#define __NR_setsockopt 353
+#define __NR_getsockopt 354
+#define __NR_sendmsg 355
+#define __NR_recvmsg 356
+#define __NR_recvmmsg 357
-#ifdef __KERNEL__
+#define NR_syscalls 358
-#define __IGNORE_recvmmsg
+#ifdef __KERNEL__
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/sh/include/asm/unistd_64.h b/arch/sh/include/asm/unistd_64.h
index 0580c33a1e04..09aa93f9eb70 100644
--- a/arch/sh/include/asm/unistd_64.h
+++ b/arch/sh/include/asm/unistd_64.h
@@ -387,10 +387,13 @@
#define __NR_perf_event_open 364
#define __NR_recvmmsg 365
#define __NR_accept4 366
+#define __NR_fanotify_init 367
+#define __NR_fanotify_mark 368
+#define __NR_prlimit64 369
#ifdef __KERNEL__
-#define NR_syscalls 367
+#define NR_syscalls 370
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/sh/include/cpu-sh3/cpu/mmu_context.h b/arch/sh/include/cpu-sh3/cpu/mmu_context.h
index ab09da73ce77..0c7c735ea82a 100644
--- a/arch/sh/include/cpu-sh3/cpu/mmu_context.h
+++ b/arch/sh/include/cpu-sh3/cpu/mmu_context.h
@@ -16,6 +16,7 @@
#define MMU_TEA 0xFFFFFFFC /* TLB Exception Address */
#define MMUCR 0xFFFFFFE0 /* MMU Control Register */
+#define MMUCR_TI (1 << 2) /* TLB flush bit */
#define MMU_TLB_ADDRESS_ARRAY 0xF2000000
#define MMU_PAGE_ASSOC_BIT 0x80
diff --git a/arch/sh/include/cpu-sh4/cpu/freq.h b/arch/sh/include/cpu-sh4/cpu/freq.h
index e1e90960ee9a..cffd25ed0240 100644
--- a/arch/sh/include/cpu-sh4/cpu/freq.h
+++ b/arch/sh/include/cpu-sh4/cpu/freq.h
@@ -56,7 +56,9 @@
#define FRQCR1 0xffc40004
#define FRQMR1 0xffc40014
#elif defined(CONFIG_CPU_SUBTYPE_SHX3)
-#define FRQCR 0xffc00014
+#define FRQCR0 0xffc00000
+#define FRQCR1 0xffc00004
+#define FRQMR1 0xffc00014
#else
#define FRQCR 0xffc00000
#define FRQCR_PSTBY 0x0200
diff --git a/arch/sh/include/cpu-sh4/cpu/sh7757.h b/arch/sh/include/cpu-sh4/cpu/sh7757.h
index f4d267efad71..15f3de11c55a 100644
--- a/arch/sh/include/cpu-sh4/cpu/sh7757.h
+++ b/arch/sh/include/cpu-sh4/cpu/sh7757.h
@@ -3,241 +3,252 @@
enum {
/* PTA */
- GPIO_PTA7, GPIO_PTA6, GPIO_PTA5, GPIO_PTA4,
- GPIO_PTA3, GPIO_PTA2, GPIO_PTA1, GPIO_PTA0,
+ GPIO_PTA0, GPIO_PTA1, GPIO_PTA2, GPIO_PTA3,
+ GPIO_PTA4, GPIO_PTA5, GPIO_PTA6, GPIO_PTA7,
/* PTB */
- GPIO_PTB7, GPIO_PTB6, GPIO_PTB5, GPIO_PTB4,
- GPIO_PTB3, GPIO_PTB2, GPIO_PTB1, GPIO_PTB0,
+ GPIO_PTB0, GPIO_PTB1, GPIO_PTB2, GPIO_PTB3,
+ GPIO_PTB4, GPIO_PTB5, GPIO_PTB6, GPIO_PTB7,
/* PTC */
- GPIO_PTC7, GPIO_PTC6, GPIO_PTC5, GPIO_PTC4,
- GPIO_PTC3, GPIO_PTC2, GPIO_PTC1, GPIO_PTC0,
+ GPIO_PTC0, GPIO_PTC1, GPIO_PTC2, GPIO_PTC3,
+ GPIO_PTC4, GPIO_PTC5, GPIO_PTC6, GPIO_PTC7,
/* PTD */
- GPIO_PTD7, GPIO_PTD6, GPIO_PTD5, GPIO_PTD4,
- GPIO_PTD3, GPIO_PTD2, GPIO_PTD1, GPIO_PTD0,
+ GPIO_PTD0, GPIO_PTD1, GPIO_PTD2, GPIO_PTD3,
+ GPIO_PTD4, GPIO_PTD5, GPIO_PTD6, GPIO_PTD7,
/* PTE */
- GPIO_PTE7, GPIO_PTE6, GPIO_PTE5, GPIO_PTE4,
- GPIO_PTE3, GPIO_PTE2, GPIO_PTE1, GPIO_PTE0,
+ GPIO_PTE0, GPIO_PTE1, GPIO_PTE2, GPIO_PTE3,
+ GPIO_PTE4, GPIO_PTE5, GPIO_PTE6, GPIO_PTE7,
/* PTF */
- GPIO_PTF7, GPIO_PTF6, GPIO_PTF5, GPIO_PTF4,
- GPIO_PTF3, GPIO_PTF2, GPIO_PTF1, GPIO_PTF0,
+ GPIO_PTF0, GPIO_PTF1, GPIO_PTF2, GPIO_PTF3,
+ GPIO_PTF4, GPIO_PTF5, GPIO_PTF6, GPIO_PTF7,
/* PTG */
- GPIO_PTG7, GPIO_PTG6, GPIO_PTG5, GPIO_PTG4,
- GPIO_PTG3, GPIO_PTG2, GPIO_PTG1, GPIO_PTG0,
+ GPIO_PTG0, GPIO_PTG1, GPIO_PTG2, GPIO_PTG3,
+ GPIO_PTG4, GPIO_PTG5, GPIO_PTG6, GPIO_PTG7,
/* PTH */
- GPIO_PTH7, GPIO_PTH6, GPIO_PTH5, GPIO_PTH4,
- GPIO_PTH3, GPIO_PTH2, GPIO_PTH1, GPIO_PTH0,
+ GPIO_PTH0, GPIO_PTH1, GPIO_PTH2, GPIO_PTH3,
+ GPIO_PTH4, GPIO_PTH5, GPIO_PTH6, GPIO_PTH7,
/* PTI */
- GPIO_PTI7, GPIO_PTI6, GPIO_PTI5, GPIO_PTI4,
- GPIO_PTI3, GPIO_PTI2, GPIO_PTI1, GPIO_PTI0,
+ GPIO_PTI0, GPIO_PTI1, GPIO_PTI2, GPIO_PTI3,
+ GPIO_PTI4, GPIO_PTI5, GPIO_PTI6, GPIO_PTI7,
/* PTJ */
- GPIO_PTJ7, GPIO_PTJ6, GPIO_PTJ5, GPIO_PTJ4,
- GPIO_PTJ3, GPIO_PTJ2, GPIO_PTJ1, GPIO_PTJ0,
+ GPIO_PTJ0, GPIO_PTJ1, GPIO_PTJ2, GPIO_PTJ3,
+ GPIO_PTJ4, GPIO_PTJ5, GPIO_PTJ6, GPIO_PTJ7_RESV,
/* PTK */
- GPIO_PTK7, GPIO_PTK6, GPIO_PTK5, GPIO_PTK4,
- GPIO_PTK3, GPIO_PTK2, GPIO_PTK1, GPIO_PTK0,
+ GPIO_PTK0, GPIO_PTK1, GPIO_PTK2, GPIO_PTK3,
+ GPIO_PTK4, GPIO_PTK5, GPIO_PTK6, GPIO_PTK7,
/* PTL */
- GPIO_PTL7, GPIO_PTL6, GPIO_PTL5, GPIO_PTL4,
- GPIO_PTL3, GPIO_PTL2, GPIO_PTL1, GPIO_PTL0,
+ GPIO_PTL0, GPIO_PTL1, GPIO_PTL2, GPIO_PTL3,
+ GPIO_PTL4, GPIO_PTL5, GPIO_PTL6, GPIO_PTL7_RESV,
/* PTM */
- GPIO_PTM6, GPIO_PTM5, GPIO_PTM4,
- GPIO_PTM3, GPIO_PTM2, GPIO_PTM1, GPIO_PTM0,
+ GPIO_PTM0, GPIO_PTM1, GPIO_PTM2, GPIO_PTM3,
+ GPIO_PTM4, GPIO_PTM5, GPIO_PTM6, GPIO_PTM7,
/* PTN */
- GPIO_PTN7, GPIO_PTN6, GPIO_PTN5, GPIO_PTN4,
- GPIO_PTN3, GPIO_PTN2, GPIO_PTN1, GPIO_PTN0,
+ GPIO_PTN0, GPIO_PTN1, GPIO_PTN2, GPIO_PTN3,
+ GPIO_PTN4, GPIO_PTN5, GPIO_PTN6, GPIO_PTN7_RESV,
/* PTO */
- GPIO_PTO7, GPIO_PTO6, GPIO_PTO5, GPIO_PTO4,
- GPIO_PTO3, GPIO_PTO2, GPIO_PTO1, GPIO_PTO0,
+ GPIO_PTO0, GPIO_PTO1, GPIO_PTO2, GPIO_PTO3,
+ GPIO_PTO4, GPIO_PTO5, GPIO_PTO6, GPIO_PTO7,
/* PTP */
- GPIO_PTP6, GPIO_PTP5, GPIO_PTP4,
- GPIO_PTP3, GPIO_PTP2, GPIO_PTP1, GPIO_PTP0,
+ GPIO_PTP0, GPIO_PTP1, GPIO_PTP2, GPIO_PTP3,
+ GPIO_PTP4, GPIO_PTP5, GPIO_PTP6, GPIO_PTP7,
/* PTQ */
- GPIO_PTQ6, GPIO_PTQ5, GPIO_PTQ4,
- GPIO_PTQ3, GPIO_PTQ2, GPIO_PTQ1, GPIO_PTQ0,
+ GPIO_PTQ0, GPIO_PTQ1, GPIO_PTQ2, GPIO_PTQ3,
+ GPIO_PTQ4, GPIO_PTQ5, GPIO_PTQ6, GPIO_PTQ7_RESV,
/* PTR */
- GPIO_PTR7, GPIO_PTR6, GPIO_PTR5, GPIO_PTR4,
- GPIO_PTR3, GPIO_PTR2, GPIO_PTR1, GPIO_PTR0,
+ GPIO_PTR0, GPIO_PTR1, GPIO_PTR2, GPIO_PTR3,
+ GPIO_PTR4, GPIO_PTR5, GPIO_PTR6, GPIO_PTR7,
/* PTS */
- GPIO_PTS7, GPIO_PTS6, GPIO_PTS5, GPIO_PTS4,
- GPIO_PTS3, GPIO_PTS2, GPIO_PTS1, GPIO_PTS0,
+ GPIO_PTS0, GPIO_PTS1, GPIO_PTS2, GPIO_PTS3,
+ GPIO_PTS4, GPIO_PTS5, GPIO_PTS6, GPIO_PTS7,
/* PTT */
- GPIO_PTT5, GPIO_PTT4,
- GPIO_PTT3, GPIO_PTT2, GPIO_PTT1, GPIO_PTT0,
+ GPIO_PTT0, GPIO_PTT1, GPIO_PTT2, GPIO_PTT3,
+ GPIO_PTT4, GPIO_PTT5, GPIO_PTT6, GPIO_PTT7,
/* PTU */
- GPIO_PTU7, GPIO_PTU6, GPIO_PTU5, GPIO_PTU4,
- GPIO_PTU3, GPIO_PTU2, GPIO_PTU1, GPIO_PTU0,
+ GPIO_PTU0, GPIO_PTU1, GPIO_PTU2, GPIO_PTU3,
+ GPIO_PTU4, GPIO_PTU5, GPIO_PTU6, GPIO_PTU7,
/* PTV */
- GPIO_PTV7, GPIO_PTV6, GPIO_PTV5, GPIO_PTV4,
- GPIO_PTV3, GPIO_PTV2, GPIO_PTV1, GPIO_PTV0,
+ GPIO_PTV0, GPIO_PTV1, GPIO_PTV2, GPIO_PTV3,
+ GPIO_PTV4, GPIO_PTV5, GPIO_PTV6, GPIO_PTV7,
/* PTW */
- GPIO_PTW7, GPIO_PTW6, GPIO_PTW5, GPIO_PTW4,
- GPIO_PTW3, GPIO_PTW2, GPIO_PTW1, GPIO_PTW0,
+ GPIO_PTW0, GPIO_PTW1, GPIO_PTW2, GPIO_PTW3,
+ GPIO_PTW4, GPIO_PTW5, GPIO_PTW6, GPIO_PTW7,
/* PTX */
- GPIO_PTX7, GPIO_PTX6, GPIO_PTX5, GPIO_PTX4,
- GPIO_PTX3, GPIO_PTX2, GPIO_PTX1, GPIO_PTX0,
+ GPIO_PTX0, GPIO_PTX1, GPIO_PTX2, GPIO_PTX3,
+ GPIO_PTX4, GPIO_PTX5, GPIO_PTX6, GPIO_PTX7,
/* PTY */
- GPIO_PTY7, GPIO_PTY6, GPIO_PTY5, GPIO_PTY4,
- GPIO_PTY3, GPIO_PTY2, GPIO_PTY1, GPIO_PTY0,
+ GPIO_PTY0, GPIO_PTY1, GPIO_PTY2, GPIO_PTY3,
+ GPIO_PTY4, GPIO_PTY5, GPIO_PTY6, GPIO_PTY7,
/* PTZ */
- GPIO_PTZ7, GPIO_PTZ6, GPIO_PTZ5, GPIO_PTZ4,
- GPIO_PTZ3, GPIO_PTZ2, GPIO_PTZ1, GPIO_PTZ0,
+ GPIO_PTZ0, GPIO_PTZ1, GPIO_PTZ2, GPIO_PTZ3,
+ GPIO_PTZ4, GPIO_PTZ5, GPIO_PTZ6, GPIO_PTZ7,
- /* PTA (mobule: LBSC, CPG, LPC) */
+ /* PTA (mobule: LBSC, RGMII) */
GPIO_FN_BS, GPIO_FN_RDWR, GPIO_FN_WE1, GPIO_FN_RDY,
- GPIO_FN_MD10, GPIO_FN_MD9, GPIO_FN_MD8,
- GPIO_FN_LGPIO7, GPIO_FN_LGPIO6, GPIO_FN_LGPIO5, GPIO_FN_LGPIO4,
- GPIO_FN_LGPIO3, GPIO_FN_LGPIO2, GPIO_FN_LGPIO1, GPIO_FN_LGPIO0,
-
- /* PTB (mobule: LBSC, EtherC, SIM, LPC) */
- GPIO_FN_D15, GPIO_FN_D14, GPIO_FN_D13, GPIO_FN_D12,
- GPIO_FN_D11, GPIO_FN_D10, GPIO_FN_D9, GPIO_FN_D8,
- GPIO_FN_ET0_MDC, GPIO_FN_ET0_MDIO,
- GPIO_FN_ET1_MDC, GPIO_FN_ET1_MDIO,
- GPIO_FN_SIM_D, GPIO_FN_SIM_CLK, GPIO_FN_SIM_RST,
- GPIO_FN_WPSZ1, GPIO_FN_WPSZ0, GPIO_FN_FWID, GPIO_FN_FLSHSZ,
- GPIO_FN_LPC_SPIEN, GPIO_FN_BASEL,
+ GPIO_FN_ET0_MDC, GPIO_FN_ET0_MDIO,
+ GPIO_FN_ET1_MDC, GPIO_FN_ET1_MDIO,
- /* PTC (mobule: SD) */
- GPIO_FN_SD_WP, GPIO_FN_SD_CD, GPIO_FN_SD_CLK, GPIO_FN_SD_CMD,
- GPIO_FN_SD_D3, GPIO_FN_SD_D2, GPIO_FN_SD_D1, GPIO_FN_SD_D0,
+ /* PTB (mobule: INTC, ONFI, TMU) */
+ GPIO_FN_IRQ15, GPIO_FN_IRQ14, GPIO_FN_IRQ13, GPIO_FN_IRQ12,
+ GPIO_FN_IRQ11, GPIO_FN_IRQ10, GPIO_FN_IRQ9, GPIO_FN_IRQ8,
+ GPIO_FN_ON_NRE, GPIO_FN_ON_NWE, GPIO_FN_ON_NWP, GPIO_FN_ON_NCE0,
+ GPIO_FN_ON_R_B0, GPIO_FN_ON_ALE, GPIO_FN_ON_CLE,
+ GPIO_FN_TCLK,
- /* PTD (mobule: INTC, SPI0, LBSC, CPG, ADC) */
+ /* PTC (mobule: IRQ, PWMU) */
GPIO_FN_IRQ7, GPIO_FN_IRQ6, GPIO_FN_IRQ5, GPIO_FN_IRQ4,
GPIO_FN_IRQ3, GPIO_FN_IRQ2, GPIO_FN_IRQ1, GPIO_FN_IRQ0,
- GPIO_FN_MD6, GPIO_FN_MD5, GPIO_FN_MD3, GPIO_FN_MD2,
- GPIO_FN_MD1, GPIO_FN_MD0, GPIO_FN_ADTRG1, GPIO_FN_ADTRG0,
-
- /* PTE (mobule: EtherC) */
- GPIO_FN_ET0_CRS_DV, GPIO_FN_ET0_TXD1,
- GPIO_FN_ET0_TXD0, GPIO_FN_ET0_TX_EN,
- GPIO_FN_ET0_REF_CLK, GPIO_FN_ET0_RXD1,
- GPIO_FN_ET0_RXD0, GPIO_FN_ET0_RX_ER,
-
- /* PTF (mobule: EtherC) */
- GPIO_FN_ET1_CRS_DV, GPIO_FN_ET1_TXD1,
- GPIO_FN_ET1_TXD0, GPIO_FN_ET1_TX_EN,
- GPIO_FN_ET1_REF_CLK, GPIO_FN_ET1_RXD1,
- GPIO_FN_ET1_RXD0, GPIO_FN_ET1_RX_ER,
-
- /* PTG (mobule: SYSTEM, PWMX, LPC) */
- GPIO_FN_STATUS0, GPIO_FN_STATUS1,
- GPIO_FN_PWX0, GPIO_FN_PWX1, GPIO_FN_PWX2, GPIO_FN_PWX3,
- GPIO_FN_SERIRQ, GPIO_FN_CLKRUN, GPIO_FN_LPCPD, GPIO_FN_LDRQ,
-
- /* PTH (mobule: TMU, SCIF234, SPI1, SPI0) */
- GPIO_FN_TCLK, GPIO_FN_RXD4, GPIO_FN_TXD4,
+ GPIO_FN_PWMU0, GPIO_FN_PWMU1, GPIO_FN_PWMU2, GPIO_FN_PWMU3,
+ GPIO_FN_PWMU4, GPIO_FN_PWMU5,
+
+ /* PTD (mobule: SPI0, DMAC) */
+ GPIO_FN_SP0_MOSI, GPIO_FN_SP0_MISO, GPIO_FN_SP0_SCK,
+ GPIO_FN_SP0_SCK_FB, GPIO_FN_SP0_SS0, GPIO_FN_SP0_SS1,
+ GPIO_FN_SP0_SS2, GPIO_FN_SP0_SS3, GPIO_FN_DREQ0,
+ GPIO_FN_DACK0, GPIO_FN_TEND0,
+
+ /* PTE (mobule: RMII) */
+ GPIO_FN_RMII0_CRS_DV, GPIO_FN_RMII0_TXD1, GPIO_FN_RMII0_TXD0,
+ GPIO_FN_RMII0_TXEN, GPIO_FN_RMII0_REFCLK, GPIO_FN_RMII0_RXD1,
+ GPIO_FN_RMII0_RXD0, GPIO_FN_RMII0_RX_ER,
+
+ /* PTF (mobule: RMII, SerMux) */
+ GPIO_FN_RMII1_CRS_DV, GPIO_FN_RMII1_TXD1, GPIO_FN_RMII1_TXD0,
+ GPIO_FN_RMII1_TXEN, GPIO_FN_RMII1_REFCLK, GPIO_FN_RMII1_RXD1,
+ GPIO_FN_RMII1_RXD0, GPIO_FN_RMII1_RX_ER, GPIO_FN_RAC_RI,
+
+ /* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
+ GPIO_FN_BOOTFMS, GPIO_FN_BOOTWP,
+ GPIO_FN_A25, GPIO_FN_A24, GPIO_FN_SERIRQ, GPIO_FN_WDTOVF,
+ GPIO_FN_LPCPD, GPIO_FN_LDRQ, GPIO_FN_MMCCLK, GPIO_FN_MMCCMD,
+
+ /* PTH (mobule: SPI1, LPC, DMAC, ADC) */
GPIO_FN_SP1_MOSI, GPIO_FN_SP1_MISO,
GPIO_FN_SP1_SCK, GPIO_FN_SP1_SCK_FB,
GPIO_FN_SP1_SS0, GPIO_FN_SP1_SS1,
- GPIO_FN_SP0_SS1,
-
- /* PTI (mobule: INTC) */
- GPIO_FN_IRQ15, GPIO_FN_IRQ14, GPIO_FN_IRQ13, GPIO_FN_IRQ12,
- GPIO_FN_IRQ11, GPIO_FN_IRQ10, GPIO_FN_IRQ9, GPIO_FN_IRQ8,
-
- /* PTJ (mobule: SCIF234, SERMUX) */
- GPIO_FN_RXD3, GPIO_FN_TXD3, GPIO_FN_RXD2, GPIO_FN_TXD2,
- GPIO_FN_COM1_TXD, GPIO_FN_COM1_RXD,
- GPIO_FN_COM1_RTS, GPIO_FN_COM1_CTS,
-
- /* PTK (mobule: SERMUX) */
- GPIO_FN_COM2_TXD, GPIO_FN_COM2_RXD,
- GPIO_FN_COM2_RTS, GPIO_FN_COM2_CTS,
- GPIO_FN_COM2_DTR, GPIO_FN_COM2_DSR,
- GPIO_FN_COM2_DCD, GPIO_FN_COM2_RI,
+ GPIO_FN_WP, GPIO_FN_FMS0, GPIO_FN_TEND1, GPIO_FN_DREQ1,
+ GPIO_FN_DACK1, GPIO_FN_ADTRG1, GPIO_FN_ADTRG0,
- /* PTL (mobule: SERMUX) */
- GPIO_FN_RAC_TXD, GPIO_FN_RAC_RXD,
- GPIO_FN_RAC_RTS, GPIO_FN_RAC_CTS,
- GPIO_FN_RAC_DTR, GPIO_FN_RAC_DSR,
- GPIO_FN_RAC_DCD, GPIO_FN_RAC_RI,
+ /* PTI (mobule: LBSC, SDHI) */
+ GPIO_FN_D15, GPIO_FN_D14, GPIO_FN_D13, GPIO_FN_D12,
+ GPIO_FN_D11, GPIO_FN_D10, GPIO_FN_D9, GPIO_FN_D8,
+ GPIO_FN_SD_WP, GPIO_FN_SD_CD, GPIO_FN_SD_CLK, GPIO_FN_SD_CMD,
+ GPIO_FN_SD_D3, GPIO_FN_SD_D2, GPIO_FN_SD_D1, GPIO_FN_SD_D0,
- /* PTM (mobule: IIC, LPC) */
+ /* PTJ (mobule: SCIF234) */
+ GPIO_FN_RTS3, GPIO_FN_CTS3, GPIO_FN_TXD3, GPIO_FN_RXD3,
+ GPIO_FN_RTS4, GPIO_FN_RXD4, GPIO_FN_TXD4,
+
+ /* PTK (mobule: SERMUX, LBSC, SCIF) */
+ GPIO_FN_COM2_TXD, GPIO_FN_COM2_RXD, GPIO_FN_COM2_RTS,
+ GPIO_FN_COM2_CTS, GPIO_FN_COM2_DTR, GPIO_FN_COM2_DSR,
+ GPIO_FN_COM2_DCD, GPIO_FN_CLKOUT,
+ GPIO_FN_SCK2, GPIO_FN_SCK4, GPIO_FN_SCK3,
+
+ /* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
+ GPIO_FN_RAC_RXD, GPIO_FN_RAC_RTS, GPIO_FN_RAC_CTS,
+ GPIO_FN_RAC_DTR, GPIO_FN_RAC_DSR, GPIO_FN_RAC_DCD,
+ GPIO_FN_RAC_TXD, GPIO_FN_RXD2, GPIO_FN_CS5,
+ GPIO_FN_CS6, GPIO_FN_AUDSYNC, GPIO_FN_AUDCK,
+ GPIO_FN_TXD2,
+
+ /* PTM (mobule: LBSC, IIC) */
+ GPIO_FN_CS4, GPIO_FN_RD, GPIO_FN_WE0, GPIO_FN_CS0,
GPIO_FN_SDA6, GPIO_FN_SCL6, GPIO_FN_SDA7, GPIO_FN_SCL7,
- GPIO_FN_WP, GPIO_FN_FMS0, GPIO_FN_FMS1,
-
- /* PTN (mobule: SCIF234, EVC) */
- GPIO_FN_SCK2, GPIO_FN_RTS4, GPIO_FN_RTS3, GPIO_FN_RTS2,
- GPIO_FN_CTS4, GPIO_FN_CTS3, GPIO_FN_CTS2,
- GPIO_FN_EVENT7, GPIO_FN_EVENT6, GPIO_FN_EVENT5, GPIO_FN_EVENT4,
- GPIO_FN_EVENT3, GPIO_FN_EVENT2, GPIO_FN_EVENT1, GPIO_FN_EVENT0,
- /* PTO (mobule: SGPIO) */
- GPIO_FN_SGPIO0_CLK, GPIO_FN_SGPIO0_LOAD,
- GPIO_FN_SGPIO0_DI, GPIO_FN_SGPIO0_DO,
- GPIO_FN_SGPIO1_CLK, GPIO_FN_SGPIO1_LOAD,
- GPIO_FN_SGPIO1_DI, GPIO_FN_SGPIO1_DO,
+ /* PTN (mobule: USB, JMC, SGPIO, WDT) */
+ GPIO_FN_VBUS_EN, GPIO_FN_VBUS_OC, GPIO_FN_JMCTCK,
+ GPIO_FN_JMCTMS, GPIO_FN_JMCTDO, GPIO_FN_JMCTDI,
+ GPIO_FN_JMCTRST,
+ GPIO_FN_SGPIO1_CLK, GPIO_FN_SGPIO1_LOAD, GPIO_FN_SGPIO1_DI,
+ GPIO_FN_SGPIO1_DO, GPIO_FN_SUB_CLKIN,
- /* PTP (mobule: JMC, SCIF234) */
- GPIO_FN_JMCTCK, GPIO_FN_JMCTMS, GPIO_FN_JMCTDO, GPIO_FN_JMCTDI,
- GPIO_FN_JMCRST, GPIO_FN_SCK4, GPIO_FN_SCK3,
+ /* PTO (mobule: SGPIO, SerMux) */
+ GPIO_FN_SGPIO0_CLK, GPIO_FN_SGPIO0_LOAD, GPIO_FN_SGPIO0_DI,
+ GPIO_FN_SGPIO0_DO, GPIO_FN_SGPIO2_CLK, GPIO_FN_SGPIO2_LOAD,
+ GPIO_FN_SGPIO2_DI, GPIO_FN_SGPIO2_DO, GPIO_FN_COM1_TXD,
+ GPIO_FN_COM1_RXD, GPIO_FN_COM1_RTS, GPIO_FN_COM1_CTS,
/* PTQ (mobule: LPC) */
GPIO_FN_LAD3, GPIO_FN_LAD2, GPIO_FN_LAD1, GPIO_FN_LAD0,
GPIO_FN_LFRAME, GPIO_FN_LRESET, GPIO_FN_LCLK,
/* PTR (mobule: GRA, IIC) */
- GPIO_FN_DDC3, GPIO_FN_DDC2,
- GPIO_FN_SDA8, GPIO_FN_SCL8, GPIO_FN_SDA2, GPIO_FN_SCL2,
+ GPIO_FN_DDC3, GPIO_FN_DDC2, GPIO_FN_SDA2, GPIO_FN_SCL2,
GPIO_FN_SDA1, GPIO_FN_SCL1, GPIO_FN_SDA0, GPIO_FN_SCL0,
+ GPIO_FN_SDA8, GPIO_FN_SCL8,
/* PTS (mobule: GRA, IIC) */
- GPIO_FN_DDC1, GPIO_FN_DDC0,
- GPIO_FN_SDA9, GPIO_FN_SCL9, GPIO_FN_SDA5, GPIO_FN_SCL5,
+ GPIO_FN_DDC1, GPIO_FN_DDC0, GPIO_FN_SDA5, GPIO_FN_SCL5,
GPIO_FN_SDA4, GPIO_FN_SCL4, GPIO_FN_SDA3, GPIO_FN_SCL3,
+ GPIO_FN_SDA9, GPIO_FN_SCL9,
- /* PTT (mobule: SYSTEM, PWMX) */
- GPIO_FN_AUDSYNC, GPIO_FN_AUDCK,
- GPIO_FN_AUDATA3, GPIO_FN_AUDATA2,
- GPIO_FN_AUDATA1, GPIO_FN_AUDATA0,
- GPIO_FN_PWX7, GPIO_FN_PWX6, GPIO_FN_PWX5, GPIO_FN_PWX4,
+ /* PTT (mobule: PWMX, AUD) */
+ GPIO_FN_PWMX7, GPIO_FN_PWMX6, GPIO_FN_PWMX5, GPIO_FN_PWMX4,
+ GPIO_FN_PWMX3, GPIO_FN_PWMX2, GPIO_FN_PWMX1, GPIO_FN_PWMX0,
+ GPIO_FN_AUDATA3, GPIO_FN_AUDATA2, GPIO_FN_AUDATA1,
+ GPIO_FN_AUDATA0, GPIO_FN_STATUS1, GPIO_FN_STATUS0,
- /* PTU (mobule: LBSC, DMAC) */
- GPIO_FN_CS6, GPIO_FN_CS5, GPIO_FN_CS4, GPIO_FN_CS0,
- GPIO_FN_RD, GPIO_FN_WE0, GPIO_FN_A25, GPIO_FN_A24,
- GPIO_FN_DREQ0, GPIO_FN_DACK0,
+ /* PTU (mobule: LPC, APM) */
+ GPIO_FN_LGPIO7, GPIO_FN_LGPIO6, GPIO_FN_LGPIO5, GPIO_FN_LGPIO4,
+ GPIO_FN_LGPIO3, GPIO_FN_LGPIO2, GPIO_FN_LGPIO1, GPIO_FN_LGPIO0,
+ GPIO_FN_APMONCTL_O, GPIO_FN_APMPWBTOUT_O, GPIO_FN_APMSCI_O,
+ GPIO_FN_APMVDDON, GPIO_FN_APMSLPBTN, GPIO_FN_APMPWRBTN,
+ GPIO_FN_APMS5N, GPIO_FN_APMS3N,
- /* PTV (mobule: LBSC, DMAC) */
+ /* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
GPIO_FN_A23, GPIO_FN_A22, GPIO_FN_A21, GPIO_FN_A20,
GPIO_FN_A19, GPIO_FN_A18, GPIO_FN_A17, GPIO_FN_A16,
- GPIO_FN_TEND0, GPIO_FN_DREQ1, GPIO_FN_DACK1, GPIO_FN_TEND1,
+ GPIO_FN_COM2_RI, GPIO_FN_R_SPI_MOSI, GPIO_FN_R_SPI_MISO,
+ GPIO_FN_R_SPI_RSPCK, GPIO_FN_R_SPI_SSL0, GPIO_FN_R_SPI_SSL1,
+ GPIO_FN_EVENT7, GPIO_FN_EVENT6, GPIO_FN_VBIOS_DI,
+ GPIO_FN_VBIOS_DO, GPIO_FN_VBIOS_CLK, GPIO_FN_VBIOS_CS,
- /* PTW (mobule: LBSC) */
+ /* PTW (mobule: LBSC, EVC, SCIF) */
GPIO_FN_A15, GPIO_FN_A14, GPIO_FN_A13, GPIO_FN_A12,
GPIO_FN_A11, GPIO_FN_A10, GPIO_FN_A9, GPIO_FN_A8,
+ GPIO_FN_EVENT5, GPIO_FN_EVENT4, GPIO_FN_EVENT3, GPIO_FN_EVENT2,
+ GPIO_FN_EVENT1, GPIO_FN_EVENT0, GPIO_FN_CTS4, GPIO_FN_CTS2,
- /* PTX (mobule: LBSC) */
+ /* PTX (mobule: LBSC, SCIF, SIM) */
GPIO_FN_A7, GPIO_FN_A6, GPIO_FN_A5, GPIO_FN_A4,
GPIO_FN_A3, GPIO_FN_A2, GPIO_FN_A1, GPIO_FN_A0,
+ GPIO_FN_RTS2, GPIO_FN_SIM_D, GPIO_FN_SIM_CLK, GPIO_FN_SIM_RST,
/* PTY (mobule: LBSC) */
GPIO_FN_D7, GPIO_FN_D6, GPIO_FN_D5, GPIO_FN_D4,
GPIO_FN_D3, GPIO_FN_D2, GPIO_FN_D1, GPIO_FN_D0,
+
+ /* PTZ (mobule: eMMC, ONFI) */
+ GPIO_FN_MMCDAT7, GPIO_FN_MMCDAT6, GPIO_FN_MMCDAT5,
+ GPIO_FN_MMCDAT4, GPIO_FN_MMCDAT3, GPIO_FN_MMCDAT2,
+ GPIO_FN_MMCDAT1, GPIO_FN_MMCDAT0,
+ GPIO_FN_ON_DQ7, GPIO_FN_ON_DQ6, GPIO_FN_ON_DQ5, GPIO_FN_ON_DQ4,
+ GPIO_FN_ON_DQ3, GPIO_FN_ON_DQ2, GPIO_FN_ON_DQ1, GPIO_FN_ON_DQ0,
};
#endif /* __ASM_SH7757_H__ */
diff --git a/arch/sh/include/cpu-sh4/cpu/shx3.h b/arch/sh/include/cpu-sh4/cpu/shx3.h
new file mode 100644
index 000000000000..68d9080a8da9
--- /dev/null
+++ b/arch/sh/include/cpu-sh4/cpu/shx3.h
@@ -0,0 +1,64 @@
+#ifndef __CPU_SHX3_H
+#define __CPU_SHX3_H
+
+enum {
+ /* PA */
+ GPIO_PA7, GPIO_PA6, GPIO_PA5, GPIO_PA4,
+ GPIO_PA3, GPIO_PA2, GPIO_PA1, GPIO_PA0,
+
+ /* PB */
+ GPIO_PB7, GPIO_PB6, GPIO_PB5, GPIO_PB4,
+ GPIO_PB3, GPIO_PB2, GPIO_PB1, GPIO_PB0,
+
+ /* PC */
+ GPIO_PC7, GPIO_PC6, GPIO_PC5, GPIO_PC4,
+ GPIO_PC3, GPIO_PC2, GPIO_PC1, GPIO_PC0,
+
+ /* PD */
+ GPIO_PD7, GPIO_PD6, GPIO_PD5, GPIO_PD4,
+ GPIO_PD3, GPIO_PD2, GPIO_PD1, GPIO_PD0,
+
+ /* PE */
+ GPIO_PE7, GPIO_PE6, GPIO_PE5, GPIO_PE4,
+ GPIO_PE3, GPIO_PE2, GPIO_PE1, GPIO_PE0,
+
+ /* PF */
+ GPIO_PF7, GPIO_PF6, GPIO_PF5, GPIO_PF4,
+ GPIO_PF3, GPIO_PF2, GPIO_PF1, GPIO_PF0,
+
+ /* PG */
+ GPIO_PG7, GPIO_PG6, GPIO_PG5, GPIO_PG4,
+ GPIO_PG3, GPIO_PG2, GPIO_PG1, GPIO_PG0,
+
+ /* PH */
+ GPIO_PH5, GPIO_PH4,
+ GPIO_PH3, GPIO_PH2, GPIO_PH1, GPIO_PH0,
+
+ /* SCIF */
+ GPIO_FN_SCK3, GPIO_FN_TXD3, GPIO_FN_RXD3,
+ GPIO_FN_SCK2, GPIO_FN_TXD2, GPIO_FN_RXD2,
+ GPIO_FN_SCK1, GPIO_FN_TXD1, GPIO_FN_RXD1,
+ GPIO_FN_SCK0, GPIO_FN_TXD0, GPIO_FN_RXD0,
+
+ /* LBSC */
+ GPIO_FN_D31, GPIO_FN_D30, GPIO_FN_D29, GPIO_FN_D28,
+ GPIO_FN_D27, GPIO_FN_D26, GPIO_FN_D25, GPIO_FN_D24,
+ GPIO_FN_D23, GPIO_FN_D22, GPIO_FN_D21, GPIO_FN_D20,
+ GPIO_FN_D19, GPIO_FN_D18, GPIO_FN_D17, GPIO_FN_D16,
+ GPIO_FN_WE3, GPIO_FN_WE2, GPIO_FN_CS6, GPIO_FN_CS5,
+ GPIO_FN_CS4, GPIO_FN_CLKOUTENB, GPIO_FN_BREQ,
+ GPIO_FN_IOIS16, GPIO_FN_CE2B, GPIO_FN_CE2A, GPIO_FN_BACK,
+
+ /* DMAC */
+ GPIO_FN_DACK0, GPIO_FN_DREQ0, GPIO_FN_DRAK0,
+ GPIO_FN_DACK1, GPIO_FN_DREQ1, GPIO_FN_DRAK1,
+ GPIO_FN_DACK2, GPIO_FN_DREQ2, GPIO_FN_DRAK2,
+ GPIO_FN_DACK3, GPIO_FN_DREQ3, GPIO_FN_DRAK3,
+
+ /* INTC */
+ GPIO_FN_IRQ3, GPIO_FN_IRQ2, GPIO_FN_IRQ1, GPIO_FN_IRQ0,
+ GPIO_FN_IRL3, GPIO_FN_IRL2, GPIO_FN_IRL1, GPIO_FN_IRL0,
+ GPIO_FN_IRQOUT, GPIO_FN_STATUS1, GPIO_FN_STATUS0,
+};
+
+#endif /* __CPU_SHX3_H */
diff --git a/arch/sh/include/mach-common/mach/sh2007.h b/arch/sh/include/mach-common/mach/sh2007.h
new file mode 100644
index 000000000000..48180b9aa03d
--- /dev/null
+++ b/arch/sh/include/mach-common/mach/sh2007.h
@@ -0,0 +1,117 @@
+#ifndef __MACH_SH2007_H
+#define __MACH_SH2007_H
+
+#define CS5BCR 0xff802050
+#define CS5WCR 0xff802058
+#define CS5PCR 0xff802070
+
+#define BUS_SZ8 1
+#define BUS_SZ16 2
+#define BUS_SZ32 3
+
+#define PCMCIA_IODYN 1
+#define PCMCIA_ATA 0
+#define PCMCIA_IO8 2
+#define PCMCIA_IO16 3
+#define PCMCIA_COMM8 4
+#define PCMCIA_COMM16 5
+#define PCMCIA_ATTR8 6
+#define PCMCIA_ATTR16 7
+
+#define TYPE_SRAM 0
+#define TYPE_PCMCIA 4
+
+/* write-read/write-write delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWW5 0
+#define IWW6 3
+/* different area, read-write delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRWD5 2
+#define IWRWD6 2
+/* same area, read-write delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRWS5 2
+#define IWRWS6 2
+/* different area, read-read delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRRD5 2
+#define IWRRD6 2
+/* same area, read-read delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRRS5 0
+#define IWRRS6 2
+/* burst count (0-3:4,8,16,32) */
+#define BST5 0
+#define BST6 0
+/* bus size */
+#define SZ5 BUS_SZ16
+#define SZ6 BUS_SZ16
+/* RD hold for SRAM (0-1:0,1) */
+#define RDSPL5 0
+#define RDSPL6 0
+/* Burst pitch (0-7:0,1,2,3,4,5,6,7) */
+#define BW5 0
+#define BW6 0
+/* Multiplex (0-1:0,1) */
+#define MPX5 0
+#define MPX6 0
+/* device type */
+#define TYPE5 TYPE_PCMCIA
+#define TYPE6 TYPE_PCMCIA
+/* address setup before assert CSn for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define ADS5 0
+#define ADS6 0
+/* address hold after negate CSn for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define ADH5 0
+#define ADH6 0
+/* CSn assert to RD assert delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define RDS5 0
+#define RDS6 0
+/* RD negate to CSn negate delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define RDH5 0
+#define RDH6 0
+/* CSn assert to WE assert delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define WTS5 0
+#define WTS6 0
+/* WE negate to CSn negate delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define WTH5 0
+#define WTH6 0
+/* BS hold (0-1:1,2) */
+#define BSH5 0
+#define BSH6 0
+/* wait cycle (0-15:0,1,2,3,4,5,6,7,8,9,11,13,15,17,21,25) */
+#define IW5 6 /* 60ns PIO mode 4 */
+#define IW6 15 /* 250ns */
+
+#define SAA5 PCMCIA_IODYN /* IDE area b4000000-b5ffffff */
+#define SAB5 PCMCIA_IODYN /* CF area b6000000-b7ffffff */
+#define PCWA5 0 /* additional wait A (0-3:0,15,30,50) */
+#define PCWB5 0 /* additional wait B (0-3:0,15,30,50) */
+/* wait B (0-15:0,1,2,3,4,5,6,7,8,9,11,13,15,17,21,25) */
+#define PCIW5 12
+/* Address->OE/WE assert delay A (0-7:0,1,2,3,6,9,12,15) */
+#define TEDA5 2
+/* Address->OE/WE assert delay B (0-7:0,1,2,3,6,9,12,15) */
+#define TEDB5 4
+/* OE/WE negate->Address delay A (0-7:0,1,2,3,6,9,12,15) */
+#define TEHA5 2
+/* OE/WE negate->Address delay B (0-7:0,1,2,3,6,9,12,15) */
+#define TEHB5 3
+
+#define CS5BCR_D ((IWW5<<28)|(IWRWD5<<24)|(IWRWS5<<20)| \
+ (IWRRD5<<16)|(IWRRS5<<12)|(BST5<<10)| \
+ (SZ5<<8)|(RDSPL5<<7)|(BW5<<4)|(MPX5<<3)|TYPE5)
+#define CS5WCR_D ((ADS5<<28)|(ADH5<<24)|(RDS5<<20)| \
+ (RDH5<<16)|(WTS5<<12)|(WTH5<<8)|(BSH5<<4)|IW5)
+#define CS5PCR_D ((SAA5<<28)|(SAB5<<24)|(PCWA5<<22)| \
+ (PCWB5<<20)|(PCIW5<<16)|(TEDA5<<12)| \
+ (TEDB5<<8)|(TEHA5<<4)|TEHB5)
+
+#define SMC0_BASE 0xb0800000 /* eth0 */
+#define SMC1_BASE 0xb0900000 /* eth1 */
+#define CF_BASE 0xb6100000 /* Compact Flash (I/O area) */
+#define IDE_BASE 0xb4000000 /* IDE */
+#define PC104_IO_BASE 0xb8000000
+#define PC104_MEM_BASE 0xba000000
+#define SMC_IO_SIZE 0x100
+
+#define CF_OFFSET 0x1f0
+#define IDE_OFFSET 0x170
+
+#endif /* __MACH_SH2007_H */
diff --git a/arch/sh/include/mach-sdk7786/mach/fpga.h b/arch/sh/include/mach-sdk7786/mach/fpga.h
index 416b621d94d1..40f0c2d3690c 100644
--- a/arch/sh/include/mach-sdk7786/mach/fpga.h
+++ b/arch/sh/include/mach-sdk7786/mach/fpga.h
@@ -31,11 +31,35 @@
#define EXTASR 0x110
#define SPCAR 0x120
#define INTMSR 0x130
+
#define PCIECR 0x140
+#define PCIECR_PCIEMUX1 BIT(15)
+#define PCIECR_PCIEMUX0 BIT(14)
+#define PCIECR_PRST4 BIT(12) /* slot 4 card present */
+#define PCIECR_PRST3 BIT(11) /* slot 3 card present */
+#define PCIECR_PRST2 BIT(10) /* slot 2 card present */
+#define PCIECR_PRST1 BIT(9) /* slot 1 card present */
+#define PCIECR_CLKEN BIT(4) /* oscillator enable */
+
#define FAER 0x150
#define USRGPIR 0x160
+
/* 0x170 reserved */
-#define LCLASR 0x180
+
+#define LCLASR 0x180
+#define LCLASR_FRAMEN BIT(15)
+
+#define LCLASR_FPGA_SEL_SHIFT 12
+#define LCLASR_NAND_SEL_SHIFT 8
+#define LCLASR_NORB_SEL_SHIFT 4
+#define LCLASR_NORA_SEL_SHIFT 0
+
+#define LCLASR_AREA_MASK 0x7
+
+#define LCLASR_FPGA_SEL_MASK (LCLASR_AREA_MASK << LCLASR_FPGA_SEL_SHIFT)
+#define LCLASR_NAND_SEL_MASK (LCLASR_AREA_MASK << LCLASR_NAND_SEL_SHIFT)
+#define LCLASR_NORB_SEL_MASK (LCLASR_AREA_MASK << LCLASR_NORB_SEL_SHIFT)
+#define LCLASR_NORA_SEL_MASK (LCLASR_AREA_MASK << LCLASR_NORA_SEL_SHIFT)
#define SBCR 0x190
#define SCBR_I2CMEN BIT(0) /* FPGA I2C master enable */
diff --git a/arch/sh/include/mach-x3proto/mach/hardware.h b/arch/sh/include/mach-x3proto/mach/hardware.h
new file mode 100644
index 000000000000..52bca57bfeb6
--- /dev/null
+++ b/arch/sh/include/mach-x3proto/mach/hardware.h
@@ -0,0 +1,12 @@
+#ifndef __MACH_X3PROTO_HARDWARE_H
+#define __MACH_X3PROTO_HARDWARE_H
+
+struct gpio_chip;
+
+/* arch/sh/boards/mach-x3proto/gpio.c */
+int x3proto_gpio_setup(void);
+extern struct gpio_chip x3proto_gpio_chip;
+
+#define NR_BASEBOARD_GPIOS 16
+
+#endif /* __MACH_X3PROTO_HARDWARE_H */
diff --git a/arch/sh/include/asm/ilsel.h b/arch/sh/include/mach-x3proto/mach/ilsel.h
index e3d304b280f6..e3d304b280f6 100644
--- a/arch/sh/include/asm/ilsel.h
+++ b/arch/sh/include/mach-x3proto/mach/ilsel.h
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index e25f3c69525d..8eed6a485446 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -12,9 +12,9 @@ endif
CFLAGS_REMOVE_return_address.o = -pg
obj-y := clkdev.o debugtraps.o dma-nommu.o dumpstack.o \
- idle.o io.o irq.o \
- irq_$(BITS).o machvec.o nmi_debug.o process.o \
- process_$(BITS).o ptrace_$(BITS).o \
+ idle.o io.o irq.o irq_$(BITS).o kdebugfs.o \
+ machvec.o nmi_debug.o process.o \
+ process_$(BITS).o ptrace.o ptrace_$(BITS).o \
reboot.o return_address.o \
setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \
syscalls_$(BITS).o time.o topology.o traps.o \
@@ -44,4 +44,4 @@ obj-$(CONFIG_HAS_IOPORT) += io_generic.o
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
diff --git a/arch/sh/kernel/clkdev.c b/arch/sh/kernel/clkdev.c
index befc255830a4..1f800ef4a735 100644
--- a/arch/sh/kernel/clkdev.c
+++ b/arch/sh/kernel/clkdev.c
@@ -161,9 +161,11 @@ EXPORT_SYMBOL(clk_add_alias);
*/
void clkdev_drop(struct clk_lookup *cl)
{
+ struct clk_lookup_alloc *cla = container_of(cl, struct clk_lookup_alloc, cl);
+
mutex_lock(&clocks_mutex);
list_del(&cl->node);
mutex_unlock(&clocks_mutex);
- kfree(cl);
+ kfree(cla);
}
EXPORT_SYMBOL(clkdev_drop);
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index d180f16281ed..b93458f33b74 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -150,7 +150,7 @@ void __cpuinit cpu_probe(void)
boot_cpu_data.type = CPU_SH7724;
boot_cpu_data.flags |= CPU_HAS_L2_CACHE;
break;
- case 0x50:
+ case 0x10:
boot_cpu_data.type = CPU_SH7757;
break;
}
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index b144e8af89dc..cc122b1d3035 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -8,13 +8,13 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7763) += setup-sh7763.o
obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o
obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o
obj-$(CONFIG_CPU_SUBTYPE_SH7785) += setup-sh7785.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7786) += setup-sh7786.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7786) += setup-sh7786.o intc-shx3.o
obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o
obj-$(CONFIG_CPU_SUBTYPE_SH7723) += setup-sh7723.o
obj-$(CONFIG_CPU_SUBTYPE_SH7724) += setup-sh7724.o
obj-$(CONFIG_CPU_SUBTYPE_SH7366) += setup-sh7366.o
-obj-$(CONFIG_CPU_SUBTYPE_SHX3) += setup-shx3.o
+obj-$(CONFIG_CPU_SUBTYPE_SHX3) += setup-shx3.o intc-shx3.o
# SMP setup
smp-$(CONFIG_CPU_SHX3) := smp-shx3.o
@@ -40,6 +40,7 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7724) := pinmux-sh7724.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7757) := pinmux-sh7757.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7785) := pinmux-sh7785.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7786) := pinmux-sh7786.o
+pinmux-$(CONFIG_CPU_SUBTYPE_SHX3) := pinmux-shx3.o
obj-y += $(clock-y)
obj-$(CONFIG_SMP) += $(smp-y)
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
index 0a752bd324ac..ce39a2ae8c6c 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
@@ -3,7 +3,7 @@
*
* SH7757 support for the clock framework
*
- * Copyright (C) 2009 Renesas Solutions Corp.
+ * Copyright (C) 2009-2010 Renesas Solutions Corp.
*
* 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
@@ -16,124 +16,147 @@
#include <asm/clock.h>
#include <asm/freq.h>
-static int ifc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
- 16, 1, 1, 32, 1, 1, 1, 1 };
-static int sfc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
- 16, 1, 1, 32, 1, 1, 1, 1 };
-static int bfc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
- 16, 1, 1, 32, 1, 1, 1, 1 };
-static int p1fc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
- 16, 1, 1, 32, 1, 1, 1, 1 };
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk extal_clk = {
+ .rate = 48000000,
+};
-static void master_clk_init(struct clk *clk)
+static unsigned long pll_recalc(struct clk *clk)
{
- clk->rate = CONFIG_SH_PCLK_FREQ * 16;
-}
+ int multiplier;
-static struct clk_ops sh7757_master_clk_ops = {
- .init = master_clk_init,
-};
+ multiplier = test_mode_pin(MODE_PIN0) ? 24 : 16;
-static void module_clk_recalc(struct clk *clk)
-{
- int idx = __raw_readl(FRQCR) & 0x0000000f;
- clk->rate = clk->parent->rate / p1fc_divisors[idx];
+ return clk->parent->rate * multiplier;
}
-static struct clk_ops sh7757_module_clk_ops = {
- .recalc = module_clk_recalc,
+static struct clk_ops pll_clk_ops = {
+ .recalc = pll_recalc,
};
-static void bus_clk_recalc(struct clk *clk)
-{
- int idx = (__raw_readl(FRQCR) >> 8) & 0x0000000f;
- clk->rate = clk->parent->rate / bfc_divisors[idx];
-}
+static struct clk pll_clk = {
+ .ops = &pll_clk_ops,
+ .parent = &extal_clk,
+ .flags = CLK_ENABLE_ON_INIT,
+};
-static struct clk_ops sh7757_bus_clk_ops = {
- .recalc = bus_clk_recalc,
+static struct clk *clks[] = {
+ &extal_clk,
+ &pll_clk,
};
-static void cpu_clk_recalc(struct clk *clk)
-{
- int idx = (__raw_readl(FRQCR) >> 20) & 0x0000000f;
- clk->rate = clk->parent->rate / ifc_divisors[idx];
-}
+static unsigned int div2[] = { 1, 1, 2, 1, 1, 4, 1, 6,
+ 1, 1, 1, 16, 1, 24, 1, 1 };
-static struct clk_ops sh7757_cpu_clk_ops = {
- .recalc = cpu_clk_recalc,
+static struct clk_div_mult_table div4_div_mult_table = {
+ .divisors = div2,
+ .nr_divisors = ARRAY_SIZE(div2),
};
-static struct clk_ops *sh7757_clk_ops[] = {
- &sh7757_master_clk_ops,
- &sh7757_module_clk_ops,
- &sh7757_bus_clk_ops,
- &sh7757_cpu_clk_ops,
+static struct clk_div4_table div4_table = {
+ .div_mult_table = &div4_div_mult_table,
};
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
-{
- if (idx < ARRAY_SIZE(sh7757_clk_ops))
- *ops = sh7757_clk_ops[idx];
-}
+enum { DIV4_I, DIV4_SH, DIV4_P, DIV4_NR };
-static void shyway_clk_recalc(struct clk *clk)
-{
- int idx = (__raw_readl(FRQCR) >> 12) & 0x0000000f;
- clk->rate = clk->parent->rate / sfc_divisors[idx];
-}
-
-static struct clk_ops sh7757_shyway_clk_ops = {
- .recalc = shyway_clk_recalc,
-};
+#define DIV4(_bit, _mask, _flags) \
+ SH_CLK_DIV4(&pll_clk, FRQCR, _bit, _mask, _flags)
-static struct clk sh7757_shyway_clk = {
- .flags = CLK_ENABLE_ON_INIT,
- .ops = &sh7757_shyway_clk_ops,
+struct clk div4_clks[DIV4_NR] = {
+ /*
+ * P clock is always enable, because some P clock modules is used
+ * by Host PC.
+ */
+ [DIV4_P] = DIV4(0, 0x2800, CLK_ENABLE_ON_INIT),
+ [DIV4_SH] = DIV4(12, 0x00a0, CLK_ENABLE_ON_INIT),
+ [DIV4_I] = DIV4(20, 0x0004, CLK_ENABLE_ON_INIT),
};
-/*
- * Additional sh7757-specific on-chip clocks that aren't already part of the
- * clock framework
- */
-static struct clk *sh7757_onchip_clocks[] = {
- &sh7757_shyway_clk,
+#define MSTPCR0 0xffc80030
+#define MSTPCR1 0xffc80034
+
+enum { MSTP004, MSTP000, MSTP114, MSTP113, MSTP112,
+ MSTP111, MSTP110, MSTP103, MSTP102,
+ MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+ /* MSTPCR0 */
+ [MSTP004] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 4, 0),
+ [MSTP000] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 0, 0),
+
+ /* MSTPCR1 */
+ [MSTP114] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 14, 0),
+ [MSTP113] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 13, 0),
+ [MSTP112] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 12, 0),
+ [MSTP111] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 11, 0),
+ [MSTP110] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 10, 0),
+ [MSTP103] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 3, 0),
+ [MSTP102] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 2, 0),
};
#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
static struct clk_lookup lookups[] = {
/* main clocks */
- CLKDEV_CON_ID("shyway_clk", &sh7757_shyway_clk),
+ CLKDEV_CON_ID("extal", &extal_clk),
+ CLKDEV_CON_ID("pll_clk", &pll_clk),
+
+ /* DIV4 clocks */
+ CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
+ CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
+ CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+
+ /* MSTP32 clocks */
+ CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP004]),
+ CLKDEV_CON_ID("riic", &mstp_clks[MSTP000]),
+ {
+ /* TMU0 */
+ .dev_id = "sh_tmu.0",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP113],
+ }, {
+ /* TMU1 */
+ .dev_id = "sh_tmu.1",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP114],
+ },
+ {
+ /* SCIF4 (But, ID is 2) */
+ .dev_id = "sh-sci.2",
+ .con_id = "sci_fck",
+ .clk = &mstp_clks[MSTP112],
+ }, {
+ /* SCIF3 */
+ .dev_id = "sh-sci.1",
+ .con_id = "sci_fck",
+ .clk = &mstp_clks[MSTP111],
+ }, {
+ /* SCIF2 */
+ .dev_id = "sh-sci.0",
+ .con_id = "sci_fck",
+ .clk = &mstp_clks[MSTP110],
+ },
+ CLKDEV_CON_ID("usb0", &mstp_clks[MSTP102]),
};
-static int __init sh7757_clk_init(void)
+int __init arch_clk_init(void)
{
- struct clk *clk = clk_get(NULL, "master_clk");
- int i;
-
- for (i = 0; i < ARRAY_SIZE(sh7757_onchip_clocks); i++) {
- struct clk *clkp = sh7757_onchip_clocks[i];
+ int i, ret = 0;
- clkp->parent = clk;
- clk_register(clkp);
- clk_enable(clkp);
- }
+ for (i = 0; i < ARRAY_SIZE(clks); i++)
+ ret |= clk_register(clks[i]);
+ for (i = 0; i < ARRAY_SIZE(lookups); i++)
+ clkdev_add(&lookups[i]);
- /*
- * Now that we have the rest of the clocks registered, we need to
- * force the parent clock to propagate so that these clocks will
- * automatically figure out their rate. We cheat by handing the
- * parent clock its current rate and forcing child propagation.
- */
- clk_set_rate(clk, clk_get_rate(clk));
+ if (!ret)
+ ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+ &div4_table);
+ if (!ret)
+ ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
- clk_put(clk);
-
- clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-
- return 0;
+ return ret;
}
-arch_initcall(sh7757_clk_init);
-
diff --git a/arch/sh/kernel/cpu/sh4a/clock-shx3.c b/arch/sh/kernel/cpu/sh4a/clock-shx3.c
index 236a6282d778..4f70df6b6169 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-shx3.c
@@ -5,7 +5,7 @@
*
* Copyright (C) 2006-2007 Renesas Technology Corp.
* Copyright (C) 2006-2007 Renesas Solutions Corp.
- * Copyright (C) 2006-2007 Paul Mundt
+ * Copyright (C) 2006-2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -18,120 +18,179 @@
#include <asm/clock.h>
#include <asm/freq.h>
-static int ifc_divisors[] = { 1, 2, 4 ,6 };
-static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 18, 24, 32, 36, 48 };
-static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 18, 24, 32, 36, 48 };
-static int cfc_divisors[] = { 1, 1, 4, 6 };
-
-#define IFC_POS 28
-#define IFC_MSK 0x0003
-#define BFC_MSK 0x000f
-#define PFC_MSK 0x000f
-#define CFC_MSK 0x0003
-#define BFC_POS 16
-#define PFC_POS 0
-#define CFC_POS 20
-
-static void master_clk_init(struct clk *clk)
-{
- clk->rate *= pfc_divisors[(__raw_readl(FRQCR) >> PFC_POS) & PFC_MSK];
-}
-
-static struct clk_ops shx3_master_clk_ops = {
- .init = master_clk_init,
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk extal_clk = {
+ .rate = 16666666,
};
-static unsigned long module_clk_recalc(struct clk *clk)
+static unsigned long pll_recalc(struct clk *clk)
{
- int idx = ((__raw_readl(FRQCR) >> PFC_POS) & PFC_MSK);
- return clk->parent->rate / pfc_divisors[idx];
+ /* PLL1 has a fixed x72 multiplier. */
+ return clk->parent->rate * 72;
}
-static struct clk_ops shx3_module_clk_ops = {
- .recalc = module_clk_recalc,
+static struct clk_ops pll_clk_ops = {
+ .recalc = pll_recalc,
};
-static unsigned long bus_clk_recalc(struct clk *clk)
-{
- int idx = ((__raw_readl(FRQCR) >> BFC_POS) & BFC_MSK);
- return clk->parent->rate / bfc_divisors[idx];
-}
+static struct clk pll_clk = {
+ .ops = &pll_clk_ops,
+ .parent = &extal_clk,
+ .flags = CLK_ENABLE_ON_INIT,
+};
-static struct clk_ops shx3_bus_clk_ops = {
- .recalc = bus_clk_recalc,
+static struct clk *clks[] = {
+ &extal_clk,
+ &pll_clk,
};
-static unsigned long cpu_clk_recalc(struct clk *clk)
-{
- int idx = ((__raw_readl(FRQCR) >> IFC_POS) & IFC_MSK);
- return clk->parent->rate / ifc_divisors[idx];
-}
+static unsigned int div2[] = { 1, 2, 4, 6, 8, 12, 16, 18,
+ 24, 32, 36, 48 };
-static struct clk_ops shx3_cpu_clk_ops = {
- .recalc = cpu_clk_recalc,
+static struct clk_div_mult_table div4_div_mult_table = {
+ .divisors = div2,
+ .nr_divisors = ARRAY_SIZE(div2),
};
-static struct clk_ops *shx3_clk_ops[] = {
- &shx3_master_clk_ops,
- &shx3_module_clk_ops,
- &shx3_bus_clk_ops,
- &shx3_cpu_clk_ops,
+static struct clk_div4_table div4_table = {
+ .div_mult_table = &div4_div_mult_table,
};
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
-{
- if (idx < ARRAY_SIZE(shx3_clk_ops))
- *ops = shx3_clk_ops[idx];
-}
+enum { DIV4_I, DIV4_SH, DIV4_B, DIV4_DDR, DIV4_SHA, DIV4_P, DIV4_NR };
-static unsigned long shyway_clk_recalc(struct clk *clk)
-{
- int idx = ((__raw_readl(FRQCR) >> CFC_POS) & CFC_MSK);
- return clk->parent->rate / cfc_divisors[idx];
-}
+#define DIV4(_bit, _mask, _flags) \
+ SH_CLK_DIV4(&pll_clk, FRQMR1, _bit, _mask, _flags)
-static struct clk_ops shx3_shyway_clk_ops = {
- .recalc = shyway_clk_recalc,
+struct clk div4_clks[DIV4_NR] = {
+ [DIV4_P] = DIV4(0, 0x0f80, 0),
+ [DIV4_SHA] = DIV4(4, 0x0ff0, 0),
+ [DIV4_DDR] = DIV4(12, 0x000c, CLK_ENABLE_ON_INIT),
+ [DIV4_B] = DIV4(16, 0x0fe0, CLK_ENABLE_ON_INIT),
+ [DIV4_SH] = DIV4(20, 0x000c, CLK_ENABLE_ON_INIT),
+ [DIV4_I] = DIV4(28, 0x000e, CLK_ENABLE_ON_INIT),
};
-static struct clk shx3_shyway_clk = {
- .flags = CLK_ENABLE_ON_INIT,
- .ops = &shx3_shyway_clk_ops,
-};
-
-/*
- * Additional SHx3-specific on-chip clocks that aren't already part of the
- * clock framework
- */
-static struct clk *shx3_onchip_clocks[] = {
- &shx3_shyway_clk,
+#define MSTPCR0 0xffc00030
+#define MSTPCR1 0xffc00034
+
+enum { MSTP027, MSTP026, MSTP025, MSTP024,
+ MSTP009, MSTP008, MSTP003, MSTP002,
+ MSTP001, MSTP000, MSTP119, MSTP105,
+ MSTP104, MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+ /* MSTPCR0 */
+ [MSTP027] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 27, 0),
+ [MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0),
+ [MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0),
+ [MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0),
+ [MSTP009] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 9, 0),
+ [MSTP008] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 8, 0),
+ [MSTP003] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 3, 0),
+ [MSTP002] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 2, 0),
+ [MSTP001] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 1, 0),
+ [MSTP000] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 0, 0),
+
+ /* MSTPCR1 */
+ [MSTP119] = SH_CLK_MSTP32(NULL, MSTPCR1, 19, 0),
+ [MSTP105] = SH_CLK_MSTP32(NULL, MSTPCR1, 5, 0),
+ [MSTP104] = SH_CLK_MSTP32(NULL, MSTPCR1, 4, 0),
};
#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
static struct clk_lookup lookups[] = {
/* main clocks */
- CLKDEV_CON_ID("shyway_clk", &shx3_shyway_clk),
+ CLKDEV_CON_ID("extal", &extal_clk),
+ CLKDEV_CON_ID("pll_clk", &pll_clk),
+
+ /* DIV4 clocks */
+ CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
+ CLKDEV_CON_ID("shywaya_clk", &div4_clks[DIV4_SHA]),
+ CLKDEV_CON_ID("ddr_clk", &div4_clks[DIV4_DDR]),
+ CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
+ CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
+ CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+
+ /* MSTP32 clocks */
+ {
+ /* SCIF3 */
+ .dev_id = "sh-sci.3",
+ .con_id = "sci_fck",
+ .clk = &mstp_clks[MSTP027],
+ }, {
+ /* SCIF2 */
+ .dev_id = "sh-sci.2",
+ .con_id = "sci_fck",
+ .clk = &mstp_clks[MSTP026],
+ }, {
+ /* SCIF1 */
+ .dev_id = "sh-sci.1",
+ .con_id = "sci_fck",
+ .clk = &mstp_clks[MSTP025],
+ }, {
+ /* SCIF0 */
+ .dev_id = "sh-sci.0",
+ .con_id = "sci_fck",
+ .clk = &mstp_clks[MSTP024],
+ },
+ CLKDEV_CON_ID("h8ex_fck", &mstp_clks[MSTP003]),
+ CLKDEV_CON_ID("csm_fck", &mstp_clks[MSTP002]),
+ CLKDEV_CON_ID("fe1_fck", &mstp_clks[MSTP001]),
+ CLKDEV_CON_ID("fe0_fck", &mstp_clks[MSTP000]),
+ {
+ /* TMU0 */
+ .dev_id = "sh_tmu.0",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP008],
+ }, {
+ /* TMU1 */
+ .dev_id = "sh_tmu.1",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP008],
+ }, {
+ /* TMU2 */
+ .dev_id = "sh_tmu.2",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP008],
+ }, {
+ /* TMU3 */
+ .dev_id = "sh_tmu.3",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP009],
+ }, {
+ /* TMU4 */
+ .dev_id = "sh_tmu.4",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP009],
+ }, {
+ /* TMU5 */
+ .dev_id = "sh_tmu.5",
+ .con_id = "tmu_fck",
+ .clk = &mstp_clks[MSTP009],
+ },
+ CLKDEV_CON_ID("hudi_fck", &mstp_clks[MSTP119]),
+ CLKDEV_CON_ID("dmac_11_6_fck", &mstp_clks[MSTP105]),
+ CLKDEV_CON_ID("dmac_5_0_fck", &mstp_clks[MSTP104]),
};
int __init arch_clk_init(void)
{
- struct clk *clk;
int i, ret = 0;
- cpg_clk_init();
-
- clk = clk_get(NULL, "master_clk");
- for (i = 0; i < ARRAY_SIZE(shx3_onchip_clocks); i++) {
- struct clk *clkp = shx3_onchip_clocks[i];
-
- clkp->parent = clk;
- ret |= clk_register(clkp);
- }
-
- clk_put(clk);
+ for (i = 0; i < ARRAY_SIZE(clks); i++)
+ ret |= clk_register(clks[i]);
+ for (i = 0; i < ARRAY_SIZE(lookups); i++)
+ clkdev_add(&lookups[i]);
- clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+ if (!ret)
+ ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+ &div4_table);
+ if (!ret)
+ ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
return ret;
}
diff --git a/arch/sh/kernel/cpu/sh4a/intc-shx3.c b/arch/sh/kernel/cpu/sh4a/intc-shx3.c
new file mode 100644
index 000000000000..78c971486b4e
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/intc-shx3.c
@@ -0,0 +1,34 @@
+/*
+ * Shared support for SH-X3 interrupt controllers.
+ *
+ * Copyright (C) 2009 - 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/init.h>
+
+#define INTACK 0xfe4100b8
+#define INTACKCLR 0xfe4100bc
+#define INTC_USERIMASK 0xfe411000
+
+#ifdef CONFIG_INTC_BALANCING
+unsigned int irq_lookup(unsigned int irq)
+{
+ return __raw_readl(INTACK) & 1 ? irq : NO_IRQ_IGNORE;
+}
+
+void irq_finish(unsigned int irq)
+{
+ __raw_writel(irq2evt(irq), INTACKCLR);
+}
+#endif
+
+static int __init shx3_irq_setup(void)
+{
+ return register_intc_userimask(INTC_USERIMASK);
+}
+arch_initcall(shx3_irq_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/perf_event.c b/arch/sh/kernel/cpu/sh4a/perf_event.c
index eddc21973fa1..b8b873d8d6b5 100644
--- a/arch/sh/kernel/cpu/sh4a/perf_event.c
+++ b/arch/sh/kernel/cpu/sh4a/perf_event.c
@@ -1,7 +1,7 @@
/*
* Performance events support for SH-4A performance counters
*
- * Copyright (C) 2009 Paul Mundt
+ * Copyright (C) 2009, 2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -22,7 +22,25 @@
#define CCBR_CMDS (1 << 1)
#define CCBR_PPCE (1 << 0)
+#ifdef CONFIG_CPU_SHX3
+/*
+ * The PMCAT location for SH-X3 CPUs was quietly moved, while the CCBR
+ * and PMCTR locations remains tentatively constant. This change remains
+ * wholly undocumented, and was simply found through trial and error.
+ *
+ * Early cuts of SH-X3 still appear to use the SH-X/SH-X2 locations, and
+ * it's unclear when this ceased to be the case. For now we always use
+ * the new location (if future parts keep up with this trend then
+ * scanning for them at runtime also remains a viable option.)
+ *
+ * The gap in the register space also suggests that there are other
+ * undocumented counters, so this will need to be revisited at a later
+ * point in time.
+ */
+#define PPC_PMCAT 0xfc100240
+#else
#define PPC_PMCAT 0xfc100080
+#endif
#define PMCAT_OVF3 (1 << 27)
#define PMCAT_CNN3 (1 << 26)
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c b/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c
index ed23b155c097..4c74bd04bba4 100644
--- a/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c
@@ -1,11 +1,11 @@
/*
- * SH7757 (A0 step) Pinmux
+ * SH7757 (B0 step) Pinmux
*
- * Copyright (C) 2009 Renesas Solutions Corp.
+ * Copyright (C) 2009-2010 Renesas Solutions Corp.
*
* Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
*
- * Based on SH7757 Pinmux
+ * Based on SH7723 Pinmux
* Copyright (C) 2008 Magnus Damm
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -40,27 +40,27 @@ enum {
PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA,
PTI7_DATA, PTI6_DATA, PTI5_DATA, PTI4_DATA,
PTI3_DATA, PTI2_DATA, PTI1_DATA, PTI0_DATA,
- PTJ7_DATA, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
+ PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA,
PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA,
- PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+ PTL6_DATA, PTL5_DATA, PTL4_DATA,
PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA,
- PTM6_DATA, PTM5_DATA, PTM4_DATA,
+ PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA,
- PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+ PTN6_DATA, PTN5_DATA, PTN4_DATA,
PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA,
PTO7_DATA, PTO6_DATA, PTO5_DATA, PTO4_DATA,
PTO3_DATA, PTO2_DATA, PTO1_DATA, PTO0_DATA,
- PTP6_DATA, PTP5_DATA, PTP4_DATA,
+ PTP7_DATA, PTP6_DATA, PTP5_DATA, PTP4_DATA,
PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA,
- PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
+ PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA,
PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA,
PTS7_DATA, PTS6_DATA, PTS5_DATA, PTS4_DATA,
PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA,
- PTT5_DATA, PTT4_DATA,
+ PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA,
PTU7_DATA, PTU6_DATA, PTU5_DATA, PTU4_DATA,
PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA,
@@ -95,27 +95,27 @@ enum {
PTH3_IN, PTH2_IN, PTH1_IN, PTH0_IN,
PTI7_IN, PTI6_IN, PTI5_IN, PTI4_IN,
PTI3_IN, PTI2_IN, PTI1_IN, PTI0_IN,
- PTJ7_IN, PTJ6_IN, PTJ5_IN, PTJ4_IN,
+ PTJ6_IN, PTJ5_IN, PTJ4_IN,
PTJ3_IN, PTJ2_IN, PTJ1_IN, PTJ0_IN,
PTK7_IN, PTK6_IN, PTK5_IN, PTK4_IN,
PTK3_IN, PTK2_IN, PTK1_IN, PTK0_IN,
- PTL7_IN, PTL6_IN, PTL5_IN, PTL4_IN,
+ PTL6_IN, PTL5_IN, PTL4_IN,
PTL3_IN, PTL2_IN, PTL1_IN, PTL0_IN,
- PTM6_IN, PTM5_IN, PTM4_IN,
+ PTM7_IN, PTM6_IN, PTM5_IN, PTM4_IN,
PTM3_IN, PTM2_IN, PTM1_IN, PTM0_IN,
- PTN7_IN, PTN6_IN, PTN5_IN, PTN4_IN,
+ PTN6_IN, PTN5_IN, PTN4_IN,
PTN3_IN, PTN2_IN, PTN1_IN, PTN0_IN,
PTO7_IN, PTO6_IN, PTO5_IN, PTO4_IN,
PTO3_IN, PTO2_IN, PTO1_IN, PTO0_IN,
- PTP6_IN, PTP5_IN, PTP4_IN,
+ PTP7_IN, PTP6_IN, PTP5_IN, PTP4_IN,
PTP3_IN, PTP2_IN, PTP1_IN, PTP0_IN,
- PTQ6_IN, PTQ5_IN, PTQ4_IN,
+ PTQ6_IN, PTQ5_IN, PTQ4_IN,
PTQ3_IN, PTQ2_IN, PTQ1_IN, PTQ0_IN,
PTR7_IN, PTR6_IN, PTR5_IN, PTR4_IN,
PTR3_IN, PTR2_IN, PTR1_IN, PTR0_IN,
PTS7_IN, PTS6_IN, PTS5_IN, PTS4_IN,
PTS3_IN, PTS2_IN, PTS1_IN, PTS0_IN,
- PTT5_IN, PTT4_IN,
+ PTT7_IN, PTT6_IN, PTT5_IN, PTT4_IN,
PTT3_IN, PTT2_IN, PTT1_IN, PTT0_IN,
PTU7_IN, PTU6_IN, PTU5_IN, PTU4_IN,
PTU3_IN, PTU2_IN, PTU1_IN, PTU0_IN,
@@ -132,16 +132,43 @@ enum {
PINMUX_INPUT_END,
PINMUX_INPUT_PULLUP_BEGIN,
+ PTA7_IN_PU, PTA6_IN_PU, PTA5_IN_PU, PTA4_IN_PU,
+ PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
+ PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
+ PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU, PTD0_IN_PU,
+ PTE7_IN_PU, PTE6_IN_PU, PTE5_IN_PU, PTE4_IN_PU,
+ PTE3_IN_PU, PTE2_IN_PU, PTE1_IN_PU, PTE0_IN_PU,
+ PTF7_IN_PU, PTF6_IN_PU, PTF5_IN_PU, PTF4_IN_PU,
+ PTF3_IN_PU, PTF2_IN_PU, PTF1_IN_PU, PTF0_IN_PU,
+ PTG7_IN_PU, PTG6_IN_PU, PTG4_IN_PU,
+ PTH7_IN_PU, PTH6_IN_PU, PTH5_IN_PU, PTH4_IN_PU,
+ PTH3_IN_PU, PTH2_IN_PU, PTH1_IN_PU, PTH0_IN_PU,
+ PTI7_IN_PU, PTI6_IN_PU, PTI4_IN_PU,
+ PTI3_IN_PU, PTI2_IN_PU, PTI1_IN_PU, PTI0_IN_PU,
+ PTJ6_IN_PU, PTJ5_IN_PU, PTJ4_IN_PU,
+ PTJ3_IN_PU, PTJ2_IN_PU, PTJ1_IN_PU, PTJ0_IN_PU,
+ PTK7_IN_PU, PTK6_IN_PU, PTK5_IN_PU, PTK4_IN_PU,
+ PTK3_IN_PU, PTK2_IN_PU, PTK1_IN_PU, PTK0_IN_PU,
+ PTL6_IN_PU, PTL5_IN_PU, PTL4_IN_PU,
+ PTL3_IN_PU, PTL2_IN_PU, PTL1_IN_PU, PTL0_IN_PU,
+ PTM7_IN_PU, PTM6_IN_PU, PTM5_IN_PU, PTM4_IN_PU,
+ PTN4_IN_PU,
+ PTN3_IN_PU, PTN2_IN_PU, PTN1_IN_PU, PTN0_IN_PU,
+ PTO7_IN_PU, PTO6_IN_PU, PTO5_IN_PU, PTO4_IN_PU,
+ PTO3_IN_PU, PTO2_IN_PU, PTO1_IN_PU, PTO0_IN_PU,
+ PTT7_IN_PU, PTT6_IN_PU, PTT5_IN_PU, PTT4_IN_PU,
+ PTT3_IN_PU, PTT2_IN_PU, PTT1_IN_PU, PTT0_IN_PU,
PTU7_IN_PU, PTU6_IN_PU, PTU5_IN_PU, PTU4_IN_PU,
PTU3_IN_PU, PTU2_IN_PU, PTU1_IN_PU, PTU0_IN_PU,
PTV7_IN_PU, PTV6_IN_PU, PTV5_IN_PU, PTV4_IN_PU,
- PTV3_IN_PU, PTV2_IN_PU, PTV1_IN_PU, PTV0_IN_PU,
- PTW7_IN_PU, PTW6_IN_PU, PTW5_IN_PU, PTW4_IN_PU,
- PTW3_IN_PU, PTW2_IN_PU, PTW1_IN_PU, PTW0_IN_PU,
+ PTV3_IN_PU, PTV2_IN_PU,
+ PTW1_IN_PU, PTW0_IN_PU,
PTX7_IN_PU, PTX6_IN_PU, PTX5_IN_PU, PTX4_IN_PU,
PTX3_IN_PU, PTX2_IN_PU, PTX1_IN_PU, PTX0_IN_PU,
PTY7_IN_PU, PTY6_IN_PU, PTY5_IN_PU, PTY4_IN_PU,
PTY3_IN_PU, PTY2_IN_PU, PTY1_IN_PU, PTY0_IN_PU,
+ PTZ7_IN_PU, PTZ6_IN_PU, PTZ5_IN_PU, PTZ4_IN_PU,
+ PTZ3_IN_PU, PTZ2_IN_PU, PTZ1_IN_PU, PTZ0_IN_PU,
PINMUX_INPUT_PULLUP_END,
PINMUX_OUTPUT_BEGIN,
@@ -163,27 +190,27 @@ enum {
PTH3_OUT, PTH2_OUT, PTH1_OUT, PTH0_OUT,
PTI7_OUT, PTI6_OUT, PTI5_OUT, PTI4_OUT,
PTI3_OUT, PTI2_OUT, PTI1_OUT, PTI0_OUT,
- PTJ7_OUT, PTJ6_OUT, PTJ5_OUT, PTJ4_OUT,
+ PTJ6_OUT, PTJ5_OUT, PTJ4_OUT,
PTJ3_OUT, PTJ2_OUT, PTJ1_OUT, PTJ0_OUT,
PTK7_OUT, PTK6_OUT, PTK5_OUT, PTK4_OUT,
PTK3_OUT, PTK2_OUT, PTK1_OUT, PTK0_OUT,
- PTL7_OUT, PTL6_OUT, PTL5_OUT, PTL4_OUT,
+ PTL6_OUT, PTL5_OUT, PTL4_OUT,
PTL3_OUT, PTL2_OUT, PTL1_OUT, PTL0_OUT,
- PTM6_OUT, PTM5_OUT, PTM4_OUT,
+ PTM7_OUT, PTM6_OUT, PTM5_OUT, PTM4_OUT,
PTM3_OUT, PTM2_OUT, PTM1_OUT, PTM0_OUT,
- PTN7_OUT, PTN6_OUT, PTN5_OUT, PTN4_OUT,
+ PTN6_OUT, PTN5_OUT, PTN4_OUT,
PTN3_OUT, PTN2_OUT, PTN1_OUT, PTN0_OUT,
PTO7_OUT, PTO6_OUT, PTO5_OUT, PTO4_OUT,
PTO3_OUT, PTO2_OUT, PTO1_OUT, PTO0_OUT,
- PTP6_OUT, PTP5_OUT, PTP4_OUT,
+ PTP7_OUT, PTP6_OUT, PTP5_OUT, PTP4_OUT,
PTP3_OUT, PTP2_OUT, PTP1_OUT, PTP0_OUT,
- PTQ6_OUT, PTQ5_OUT, PTQ4_OUT,
+ PTQ6_OUT, PTQ5_OUT, PTQ4_OUT,
PTQ3_OUT, PTQ2_OUT, PTQ1_OUT, PTQ0_OUT,
PTR7_OUT, PTR6_OUT, PTR5_OUT, PTR4_OUT,
PTR3_OUT, PTR2_OUT, PTR1_OUT, PTR0_OUT,
PTS7_OUT, PTS6_OUT, PTS5_OUT, PTS4_OUT,
PTS3_OUT, PTS2_OUT, PTS1_OUT, PTS0_OUT,
- PTT5_OUT, PTT4_OUT,
+ PTT7_OUT, PTT6_OUT, PTT5_OUT, PTT4_OUT,
PTT3_OUT, PTT2_OUT, PTT1_OUT, PTT0_OUT,
PTU7_OUT, PTU6_OUT, PTU5_OUT, PTU4_OUT,
PTU3_OUT, PTU2_OUT, PTU1_OUT, PTU0_OUT,
@@ -218,27 +245,27 @@ enum {
PTH3_FN, PTH2_FN, PTH1_FN, PTH0_FN,
PTI7_FN, PTI6_FN, PTI5_FN, PTI4_FN,
PTI3_FN, PTI2_FN, PTI1_FN, PTI0_FN,
- PTJ7_FN, PTJ6_FN, PTJ5_FN, PTJ4_FN,
+ PTJ6_FN, PTJ5_FN, PTJ4_FN,
PTJ3_FN, PTJ2_FN, PTJ1_FN, PTJ0_FN,
PTK7_FN, PTK6_FN, PTK5_FN, PTK4_FN,
PTK3_FN, PTK2_FN, PTK1_FN, PTK0_FN,
- PTL7_FN, PTL6_FN, PTL5_FN, PTL4_FN,
+ PTL6_FN, PTL5_FN, PTL4_FN,
PTL3_FN, PTL2_FN, PTL1_FN, PTL0_FN,
- PTM6_FN, PTM5_FN, PTM4_FN,
+ PTM7_FN, PTM6_FN, PTM5_FN, PTM4_FN,
PTM3_FN, PTM2_FN, PTM1_FN, PTM0_FN,
- PTN7_FN, PTN6_FN, PTN5_FN, PTN4_FN,
+ PTN6_FN, PTN5_FN, PTN4_FN,
PTN3_FN, PTN2_FN, PTN1_FN, PTN0_FN,
PTO7_FN, PTO6_FN, PTO5_FN, PTO4_FN,
PTO3_FN, PTO2_FN, PTO1_FN, PTO0_FN,
- PTP6_FN, PTP5_FN, PTP4_FN,
+ PTP7_FN, PTP6_FN, PTP5_FN, PTP4_FN,
PTP3_FN, PTP2_FN, PTP1_FN, PTP0_FN,
- PTQ6_FN, PTQ5_FN, PTQ4_FN,
+ PTQ6_FN, PTQ5_FN, PTQ4_FN,
PTQ3_FN, PTQ2_FN, PTQ1_FN, PTQ0_FN,
PTR7_FN, PTR6_FN, PTR5_FN, PTR4_FN,
PTR3_FN, PTR2_FN, PTR1_FN, PTR0_FN,
PTS7_FN, PTS6_FN, PTS5_FN, PTS4_FN,
PTS3_FN, PTS2_FN, PTS1_FN, PTS0_FN,
- PTT5_FN, PTT4_FN,
+ PTT7_FN, PTT6_FN, PTT5_FN, PTT4_FN,
PTT3_FN, PTT2_FN, PTT1_FN, PTT0_FN,
PTU7_FN, PTU6_FN, PTU5_FN, PTU4_FN,
PTU3_FN, PTU2_FN, PTU1_FN, PTU0_FN,
@@ -253,181 +280,248 @@ enum {
PTZ7_FN, PTZ6_FN, PTZ5_FN, PTZ4_FN,
PTZ3_FN, PTZ2_FN, PTZ1_FN, PTZ0_FN,
- PS0_15_FN1, PS0_15_FN3,
- PS0_14_FN1, PS0_14_FN3,
- PS0_13_FN1, PS0_13_FN3,
- PS0_12_FN1, PS0_12_FN3,
+ PS0_15_FN1, PS0_15_FN2,
+ PS0_14_FN1, PS0_14_FN2,
+ PS0_13_FN1, PS0_13_FN2,
+ PS0_12_FN1, PS0_12_FN2,
+ PS0_11_FN1, PS0_11_FN2,
+ PS0_10_FN1, PS0_10_FN2,
+ PS0_9_FN1, PS0_9_FN2,
+ PS0_8_FN1, PS0_8_FN2,
PS0_7_FN1, PS0_7_FN2,
PS0_6_FN1, PS0_6_FN2,
PS0_5_FN1, PS0_5_FN2,
PS0_4_FN1, PS0_4_FN2,
PS0_3_FN1, PS0_3_FN2,
PS0_2_FN1, PS0_2_FN2,
- PS0_1_FN1, PS0_1_FN2,
- PS1_7_FN1, PS1_7_FN3,
- PS1_6_FN1, PS1_6_FN3,
+ PS1_10_FN1, PS1_10_FN2,
+ PS1_9_FN1, PS1_9_FN2,
+ PS1_8_FN1, PS1_8_FN2,
+ PS1_2_FN1, PS1_2_FN2,
+
+ PS2_13_FN1, PS2_13_FN2,
+ PS2_12_FN1, PS2_12_FN2,
+ PS2_7_FN1, PS2_7_FN2,
+ PS2_6_FN1, PS2_6_FN2,
+ PS2_5_FN1, PS2_5_FN2,
+ PS2_4_FN1, PS2_4_FN2,
+ PS2_2_FN1, PS2_2_FN2,
+
+ PS3_15_FN1, PS3_15_FN2,
+ PS3_14_FN1, PS3_14_FN2,
+ PS3_13_FN1, PS3_13_FN2,
+ PS3_12_FN1, PS3_12_FN2,
+ PS3_11_FN1, PS3_11_FN2,
+ PS3_10_FN1, PS3_10_FN2,
+ PS3_9_FN1, PS3_9_FN2,
+ PS3_8_FN1, PS3_8_FN2,
+ PS3_7_FN1, PS3_7_FN2,
+ PS3_2_FN1, PS3_2_FN2,
+ PS3_1_FN1, PS3_1_FN2,
- PS2_13_FN1, PS2_13_FN3,
- PS2_12_FN1, PS2_12_FN3,
- PS2_1_FN1, PS2_1_FN2,
- PS2_0_FN1, PS2_0_FN2,
-
- PS4_15_FN1, PS4_15_FN2,
PS4_14_FN1, PS4_14_FN2,
PS4_13_FN1, PS4_13_FN2,
PS4_12_FN1, PS4_12_FN2,
- PS4_11_FN1, PS4_11_FN2,
PS4_10_FN1, PS4_10_FN2,
PS4_9_FN1, PS4_9_FN2,
+ PS4_8_FN1, PS4_8_FN2,
+ PS4_4_FN1, PS4_4_FN2,
PS4_3_FN1, PS4_3_FN2,
PS4_2_FN1, PS4_2_FN2,
PS4_1_FN1, PS4_1_FN2,
PS4_0_FN1, PS4_0_FN2,
+ PS5_11_FN1, PS5_11_FN2,
+ PS5_10_FN1, PS5_10_FN2,
PS5_9_FN1, PS5_9_FN2,
PS5_8_FN1, PS5_8_FN2,
PS5_7_FN1, PS5_7_FN2,
PS5_6_FN1, PS5_6_FN2,
PS5_5_FN1, PS5_5_FN2,
PS5_4_FN1, PS5_4_FN2,
-
- /* AN15 to 8 : EVENT15 to 8 */
- PS6_7_FN_AN, PS6_7_FN_EV,
- PS6_6_FN_AN, PS6_6_FN_EV,
- PS6_5_FN_AN, PS6_5_FN_EV,
- PS6_4_FN_AN, PS6_4_FN_EV,
- PS6_3_FN_AN, PS6_3_FN_EV,
- PS6_2_FN_AN, PS6_2_FN_EV,
- PS6_1_FN_AN, PS6_1_FN_EV,
- PS6_0_FN_AN, PS6_0_FN_EV,
-
+ PS5_3_FN1, PS5_3_FN2,
+ PS5_2_FN1, PS5_2_FN2,
+
+ PS6_15_FN1, PS6_15_FN2,
+ PS6_14_FN1, PS6_14_FN2,
+ PS6_13_FN1, PS6_13_FN2,
+ PS6_12_FN1, PS6_12_FN2,
+ PS6_11_FN1, PS6_11_FN2,
+ PS6_10_FN1, PS6_10_FN2,
+ PS6_9_FN1, PS6_9_FN2,
+ PS6_8_FN1, PS6_8_FN2,
+ PS6_7_FN1, PS6_7_FN2,
+ PS6_6_FN1, PS6_6_FN2,
+ PS6_5_FN1, PS6_5_FN2,
+ PS6_4_FN1, PS6_4_FN2,
+ PS6_3_FN1, PS6_3_FN2,
+ PS6_2_FN1, PS6_2_FN2,
+ PS6_1_FN1, PS6_1_FN2,
+ PS6_0_FN1, PS6_0_FN2,
+
+ PS7_15_FN1, PS7_15_FN2,
+ PS7_14_FN1, PS7_14_FN2,
+ PS7_13_FN1, PS7_13_FN2,
+ PS7_12_FN1, PS7_12_FN2,
+ PS7_11_FN1, PS7_11_FN2,
+ PS7_10_FN1, PS7_10_FN2,
+ PS7_9_FN1, PS7_9_FN2,
+ PS7_8_FN1, PS7_8_FN2,
+ PS7_7_FN1, PS7_7_FN2,
+ PS7_6_FN1, PS7_6_FN2,
+ PS7_5_FN1, PS7_5_FN2,
+ PS7_4_FN1, PS7_4_FN2,
+
+ PS8_15_FN1, PS8_15_FN2,
+ PS8_14_FN1, PS8_14_FN2,
+ PS8_13_FN1, PS8_13_FN2,
+ PS8_12_FN1, PS8_12_FN2,
+ PS8_11_FN1, PS8_11_FN2,
+ PS8_10_FN1, PS8_10_FN2,
+ PS8_9_FN1, PS8_9_FN2,
+ PS8_8_FN1, PS8_8_FN2,
PINMUX_FUNCTION_END,
PINMUX_MARK_BEGIN,
- /* PTA (mobule: LBSC, CPG, LPC) */
+ /* PTA (mobule: LBSC, RGMII) */
BS_MARK, RDWR_MARK, WE1_MARK, RDY_MARK,
- MD10_MARK, MD9_MARK, MD8_MARK,
- LGPIO7_MARK, LGPIO6_MARK, LGPIO5_MARK, LGPIO4_MARK,
- LGPIO3_MARK, LGPIO2_MARK, LGPIO1_MARK, LGPIO0_MARK,
-
- /* PTB (mobule: LBSC, EtherC, SIM, LPC) */
- D15_MARK, D14_MARK, D13_MARK, D12_MARK,
- D11_MARK, D10_MARK, D9_MARK, D8_MARK,
ET0_MDC_MARK, ET0_MDIO_MARK, ET1_MDC_MARK, ET1_MDIO_MARK,
- SIM_D_MARK, SIM_CLK_MARK, SIM_RST_MARK,
- WPSZ1_MARK, WPSZ0_MARK, FWID_MARK, FLSHSZ_MARK,
- LPC_SPIEN_MARK, BASEL_MARK,
- /* PTC (mobule: SD) */
- SD_WP_MARK, SD_CD_MARK, SD_CLK_MARK, SD_CMD_MARK,
- SD_D3_MARK, SD_D2_MARK, SD_D1_MARK, SD_D0_MARK,
+ /* PTB (mobule: INTC, ONFI, TMU) */
+ IRQ15_MARK, IRQ14_MARK, IRQ13_MARK, IRQ12_MARK,
+ IRQ11_MARK, IRQ10_MARK, IRQ9_MARK, IRQ8_MARK,
+ ON_NRE_MARK, ON_NWE_MARK, ON_NWP_MARK, ON_NCE0_MARK,
+ ON_R_B0_MARK, ON_ALE_MARK, ON_CLE_MARK, TCLK_MARK,
- /* PTD (mobule: INTC, SPI0, LBSC, CPG, ADC) */
+ /* PTC (mobule: IRQ, PWMU) */
IRQ7_MARK, IRQ6_MARK, IRQ5_MARK, IRQ4_MARK,
IRQ3_MARK, IRQ2_MARK, IRQ1_MARK, IRQ0_MARK,
- MD6_MARK, MD5_MARK, MD3_MARK, MD2_MARK,
- MD1_MARK, MD0_MARK, ADTRG1_MARK, ADTRG0_MARK,
-
- /* PTE (mobule: EtherC) */
- ET0_CRS_DV_MARK, ET0_TXD1_MARK,
- ET0_TXD0_MARK, ET0_TX_EN_MARK,
- ET0_REF_CLK_MARK, ET0_RXD1_MARK,
- ET0_RXD0_MARK, ET0_RX_ER_MARK,
-
- /* PTF (mobule: EtherC) */
- ET1_CRS_DV_MARK, ET1_TXD1_MARK,
- ET1_TXD0_MARK, ET1_TX_EN_MARK,
- ET1_REF_CLK_MARK, ET1_RXD1_MARK,
- ET1_RXD0_MARK, ET1_RX_ER_MARK,
-
- /* PTG (mobule: SYSTEM, PWMX, LPC) */
- STATUS0_MARK, STATUS1_MARK,
- PWX0_MARK, PWX1_MARK, PWX2_MARK, PWX3_MARK,
- SERIRQ_MARK, CLKRUN_MARK, LPCPD_MARK, LDRQ_MARK,
-
- /* PTH (mobule: TMU, SCIF234, SPI1, SPI0) */
- TCLK_MARK, RXD4_MARK, TXD4_MARK,
+ PWMU0_MARK, PWMU1_MARK, PWMU2_MARK, PWMU3_MARK,
+ PWMU4_MARK, PWMU5_MARK,
+
+ /* PTD (mobule: SPI0, DMAC) */
+ SP0_MOSI_MARK, SP0_MISO_MARK, SP0_SCK_MARK, SP0_SCK_FB_MARK,
+ SP0_SS0_MARK, SP0_SS1_MARK, SP0_SS2_MARK, SP0_SS3_MARK,
+ DREQ0_MARK, DACK0_MARK, TEND0_MARK,
+
+ /* PTE (mobule: RMII) */
+ RMII0_CRS_DV_MARK, RMII0_TXD1_MARK,
+ RMII0_TXD0_MARK, RMII0_TXEN_MARK,
+ RMII0_REFCLK_MARK, RMII0_RXD1_MARK,
+ RMII0_RXD0_MARK, RMII0_RX_ER_MARK,
+
+ /* PTF (mobule: RMII, SerMux) */
+ RMII1_CRS_DV_MARK, RMII1_TXD1_MARK,
+ RMII1_TXD0_MARK, RMII1_TXEN_MARK,
+ RMII1_REFCLK_MARK, RMII1_RXD1_MARK,
+ RMII1_RXD0_MARK, RMII1_RX_ER_MARK,
+ RAC_RI_MARK,
+
+ /* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
+ BOOTFMS_MARK, BOOTWP_MARK, A25_MARK, A24_MARK,
+ SERIRQ_MARK, WDTOVF_MARK, LPCPD_MARK, LDRQ_MARK,
+ MMCCLK_MARK, MMCCMD_MARK,
+
+ /* PTH (mobule: SPI1, LPC, DMAC, ADC) */
SP1_MOSI_MARK, SP1_MISO_MARK, SP1_SCK_MARK, SP1_SCK_FB_MARK,
- SP1_SS0_MARK, SP1_SS1_MARK, SP0_SS1_MARK,
+ SP1_SS0_MARK, SP1_SS1_MARK, WP_MARK, FMS0_MARK,
+ TEND1_MARK, DREQ1_MARK, DACK1_MARK, ADTRG1_MARK,
+ ADTRG0_MARK,
- /* PTI (mobule: INTC) */
- IRQ15_MARK, IRQ14_MARK, IRQ13_MARK, IRQ12_MARK,
- IRQ11_MARK, IRQ10_MARK, IRQ9_MARK, IRQ8_MARK,
+ /* PTI (mobule: LBSC, SDHI) */
+ D15_MARK, D14_MARK, D13_MARK, D12_MARK,
+ D11_MARK, D10_MARK, D9_MARK, D8_MARK,
+ SD_WP_MARK, SD_CD_MARK, SD_CLK_MARK, SD_CMD_MARK,
+ SD_D3_MARK, SD_D2_MARK, SD_D1_MARK, SD_D0_MARK,
- /* PTJ (mobule: SCIF234, SERMUX) */
- RXD3_MARK, TXD3_MARK, RXD2_MARK, TXD2_MARK,
- COM1_TXD_MARK, COM1_RXD_MARK, COM1_RTS_MARK, COM1_CTS_MARK,
+ /* PTJ (mobule: SCIF234) */
+ RTS3_MARK, CTS3_MARK, TXD3_MARK, RXD3_MARK,
+ RTS4_MARK, RXD4_MARK, TXD4_MARK,
- /* PTK (mobule: SERMUX) */
+ /* PTK (mobule: SERMUX, LBSC, SCIF) */
COM2_TXD_MARK, COM2_RXD_MARK, COM2_RTS_MARK, COM2_CTS_MARK,
- COM2_DTR_MARK, COM2_DSR_MARK, COM2_DCD_MARK, COM2_RI_MARK,
+ COM2_DTR_MARK, COM2_DSR_MARK, COM2_DCD_MARK, CLKOUT_MARK,
+ SCK2_MARK, SCK4_MARK, SCK3_MARK,
- /* PTL (mobule: SERMUX) */
- RAC_TXD_MARK, RAC_RXD_MARK, RAC_RTS_MARK, RAC_CTS_MARK,
- RAC_DTR_MARK, RAC_DSR_MARK, RAC_DCD_MARK, RAC_RI_MARK,
+ /* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
+ RAC_RXD_MARK, RAC_RTS_MARK, RAC_CTS_MARK, RAC_DTR_MARK,
+ RAC_DSR_MARK, RAC_DCD_MARK, RAC_TXD_MARK, RXD2_MARK,
+ CS5_MARK, CS6_MARK, AUDSYNC_MARK, AUDCK_MARK,
+ TXD2_MARK,
- /* PTM (mobule: IIC, LPC) */
+ /* PTM (mobule: LBSC, IIC) */
+ CS4_MARK, RD_MARK, WE0_MARK, CS0_MARK,
SDA6_MARK, SCL6_MARK, SDA7_MARK, SCL7_MARK,
- WP_MARK, FMS0_MARK, FMS1_MARK,
- /* PTN (mobule: SCIF234, EVC) */
- SCK2_MARK, RTS4_MARK, RTS3_MARK, RTS2_MARK,
- CTS4_MARK, CTS3_MARK, CTS2_MARK,
- EVENT7_MARK, EVENT6_MARK, EVENT5_MARK, EVENT4_MARK,
- EVENT3_MARK, EVENT2_MARK, EVENT1_MARK, EVENT0_MARK,
+ /* PTN (mobule: USB, JMC, SGPIO, WDT) */
+ VBUS_EN_MARK, VBUS_OC_MARK, JMCTCK_MARK, JMCTMS_MARK,
+ JMCTDO_MARK, JMCTDI_MARK, JMCTRST_MARK,
+ SGPIO1_CLK_MARK, SGPIO1_LOAD_MARK, SGPIO1_DI_MARK,
+ SGPIO1_DO_MARK, SUB_CLKIN_MARK,
- /* PTO (mobule: SGPIO) */
- SGPIO0_CLK_MARK, SGPIO0_LOAD_MARK,
- SGPIO0_DI_MARK, SGPIO0_DO_MARK,
- SGPIO1_CLK_MARK, SGPIO1_LOAD_MARK,
- SGPIO1_DI_MARK, SGPIO1_DO_MARK,
-
- /* PTP (mobule: JMC, SCIF234) */
- JMCTCK_MARK, JMCTMS_MARK, JMCTDO_MARK, JMCTDI_MARK,
- JMCRST_MARK, SCK4_MARK, SCK3_MARK,
+ /* PTO (mobule: SGPIO, SerMux) */
+ SGPIO0_CLK_MARK, SGPIO0_LOAD_MARK, SGPIO0_DI_MARK,
+ SGPIO0_DO_MARK, SGPIO2_CLK_MARK, SGPIO2_LOAD_MARK,
+ SGPIO2_DI_MARK, SGPIO2_DO_MARK,
+ COM1_TXD_MARK, COM1_RXD_MARK, COM1_RTS_MARK, COM1_CTS_MARK,
/* PTQ (mobule: LPC) */
LAD3_MARK, LAD2_MARK, LAD1_MARK, LAD0_MARK,
LFRAME_MARK, LRESET_MARK, LCLK_MARK,
/* PTR (mobule: GRA, IIC) */
- DDC3_MARK, DDC2_MARK,
- SDA8_MARK, SCL8_MARK, SDA2_MARK, SCL2_MARK,
+ DDC3_MARK, DDC2_MARK, SDA2_MARK, SCL2_MARK,
SDA1_MARK, SCL1_MARK, SDA0_MARK, SCL0_MARK,
+ SDA8_MARK, SCL8_MARK,
/* PTS (mobule: GRA, IIC) */
- DDC1_MARK, DDC0_MARK,
- SDA9_MARK, SCL9_MARK, SDA5_MARK, SCL5_MARK,
+ DDC1_MARK, DDC0_MARK, SDA5_MARK, SCL5_MARK,
SDA4_MARK, SCL4_MARK, SDA3_MARK, SCL3_MARK,
+ SDA9_MARK, SCL9_MARK,
- /* PTT (mobule: SYSTEM, PWMX) */
- AUDSYNC_MARK, AUDCK_MARK,
- AUDATA3_MARK, AUDATA2_MARK,
- AUDATA1_MARK, AUDATA0_MARK,
- PWX7_MARK, PWX6_MARK, PWX5_MARK, PWX4_MARK,
+ /* PTT (mobule: PWMX, AUD) */
+ PWMX7_MARK, PWMX6_MARK, PWMX5_MARK, PWMX4_MARK,
+ PWMX3_MARK, PWMX2_MARK, PWMX1_MARK, PWMX0_MARK,
+ AUDATA3_MARK, AUDATA2_MARK, AUDATA1_MARK, AUDATA0_MARK,
+ STATUS1_MARK, STATUS0_MARK,
- /* PTU (mobule: LBSC, DMAC) */
- CS6_MARK, CS5_MARK, CS4_MARK, CS0_MARK,
- RD_MARK, WE0_MARK, A25_MARK, A24_MARK,
- DREQ0_MARK, DACK0_MARK,
+ /* PTU (mobule: LPC, APM) */
+ LGPIO7_MARK, LGPIO6_MARK, LGPIO5_MARK, LGPIO4_MARK,
+ LGPIO3_MARK, LGPIO2_MARK, LGPIO1_MARK, LGPIO0_MARK,
+ APMONCTL_O_MARK, APMPWBTOUT_O_MARK, APMSCI_O_MARK,
+ APMVDDON_MARK, APMSLPBTN_MARK, APMPWRBTN_MARK, APMS5N_MARK,
+ APMS3N_MARK,
- /* PTV (mobule: LBSC, DMAC) */
+ /* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
A23_MARK, A22_MARK, A21_MARK, A20_MARK,
A19_MARK, A18_MARK, A17_MARK, A16_MARK,
- TEND0_MARK, DREQ1_MARK, DACK1_MARK, TEND1_MARK,
+ COM2_RI_MARK, R_SPI_MOSI_MARK, R_SPI_MISO_MARK,
+ R_SPI_RSPCK_MARK, R_SPI_SSL0_MARK, R_SPI_SSL1_MARK,
+ EVENT7_MARK, EVENT6_MARK, VBIOS_DI_MARK, VBIOS_DO_MARK,
+ VBIOS_CLK_MARK, VBIOS_CS_MARK,
- /* PTW (mobule: LBSC) */
+ /* PTW (mobule: LBSC, EVC, SCIF) */
A15_MARK, A14_MARK, A13_MARK, A12_MARK,
A11_MARK, A10_MARK, A9_MARK, A8_MARK,
+ EVENT5_MARK, EVENT4_MARK, EVENT3_MARK, EVENT2_MARK,
+ EVENT1_MARK, EVENT0_MARK, CTS4_MARK, CTS2_MARK,
- /* PTX (mobule: LBSC) */
+ /* PTX (mobule: LBSC, SCIF, SIM) */
A7_MARK, A6_MARK, A5_MARK, A4_MARK,
A3_MARK, A2_MARK, A1_MARK, A0_MARK,
+ RTS2_MARK, SIM_D_MARK, SIM_CLK_MARK, SIM_RST_MARK,
/* PTY (mobule: LBSC) */
D7_MARK, D6_MARK, D5_MARK, D4_MARK,
D3_MARK, D2_MARK, D1_MARK, D0_MARK,
+
+ /* PTZ (mobule: eMMC, ONFI) */
+ MMCDAT7_MARK, MMCDAT6_MARK, MMCDAT5_MARK, MMCDAT4_MARK,
+ MMCDAT3_MARK, MMCDAT2_MARK, MMCDAT1_MARK, MMCDAT0_MARK,
+ ON_DQ7_MARK, ON_DQ6_MARK, ON_DQ5_MARK, ON_DQ4_MARK,
+ ON_DQ3_MARK, ON_DQ2_MARK, ON_DQ1_MARK, ON_DQ0_MARK,
+
PINMUX_MARK_END,
};
@@ -473,6 +567,8 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT),
/* PTE GPIO */
+ PINMUX_DATA(PTE7_DATA, PTE7_IN, PTE7_OUT),
+ PINMUX_DATA(PTE6_DATA, PTE6_IN, PTE6_OUT),
PINMUX_DATA(PTE5_DATA, PTE5_IN, PTE5_OUT),
PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT),
PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT),
@@ -521,7 +617,6 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(PTI0_DATA, PTI0_IN, PTI0_OUT),
/* PTJ GPIO */
- PINMUX_DATA(PTJ7_DATA, PTJ7_IN, PTJ7_OUT),
PINMUX_DATA(PTJ6_DATA, PTJ6_IN, PTJ6_OUT),
PINMUX_DATA(PTJ5_DATA, PTJ5_IN, PTJ5_OUT),
PINMUX_DATA(PTJ4_DATA, PTJ4_IN, PTJ4_OUT),
@@ -541,7 +636,6 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT),
/* PTL GPIO */
- PINMUX_DATA(PTL7_DATA, PTL7_IN, PTL7_OUT),
PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT),
PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT),
PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT),
@@ -560,7 +654,6 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT),
/* PTN GPIO */
- PINMUX_DATA(PTN7_DATA, PTN7_IN, PTN7_OUT),
PINMUX_DATA(PTN6_DATA, PTN6_IN, PTN6_OUT),
PINMUX_DATA(PTN5_DATA, PTN5_IN, PTN5_OUT),
PINMUX_DATA(PTN4_DATA, PTN4_IN, PTN4_OUT),
@@ -609,6 +702,8 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT),
/* PTT GPIO */
+ PINMUX_DATA(PTT7_DATA, PTT7_IN, PTT7_OUT),
+ PINMUX_DATA(PTT6_DATA, PTT6_IN, PTT6_OUT),
PINMUX_DATA(PTT5_DATA, PTT5_IN, PTT5_OUT),
PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT),
PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT),
@@ -677,186 +772,204 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(PTZ0_DATA, PTZ0_IN, PTZ0_OUT),
/* PTA FN */
- PINMUX_DATA(BS_MARK, PS0_15_FN1, PTA7_FN),
- PINMUX_DATA(LGPIO7_MARK, PS0_15_FN3, PTA7_FN),
- PINMUX_DATA(RDWR_MARK, PS0_14_FN1, PTA6_FN),
- PINMUX_DATA(LGPIO6_MARK, PS0_14_FN3, PTA6_FN),
- PINMUX_DATA(WE1_MARK, PS0_13_FN1, PTA5_FN),
- PINMUX_DATA(LGPIO5_MARK, PS0_13_FN3, PTA5_FN),
- PINMUX_DATA(RDY_MARK, PS0_12_FN1, PTA4_FN),
- PINMUX_DATA(LGPIO4_MARK, PS0_12_FN3, PTA4_FN),
- PINMUX_DATA(LGPIO3_MARK, PTA3_FN),
- PINMUX_DATA(LGPIO2_MARK, PTA2_FN),
- PINMUX_DATA(LGPIO1_MARK, PTA1_FN),
- PINMUX_DATA(LGPIO0_MARK, PTA0_FN),
+ PINMUX_DATA(BS_MARK, PTA7_FN),
+ PINMUX_DATA(RDWR_MARK, PTA6_FN),
+ PINMUX_DATA(WE1_MARK, PTA5_FN),
+ PINMUX_DATA(RDY_MARK, PTA4_FN),
+ PINMUX_DATA(ET0_MDC_MARK, PTA3_FN),
+ PINMUX_DATA(ET0_MDIO_MARK, PTA2_FN),
+ PINMUX_DATA(ET1_MDC_MARK, PTA1_FN),
+ PINMUX_DATA(ET1_MDIO_MARK, PTA0_FN),
/* PTB FN */
- PINMUX_DATA(D15_MARK, PS0_7_FN1, PTB7_FN),
- PINMUX_DATA(ET0_MDC_MARK, PS0_7_FN2, PTB7_FN),
- PINMUX_DATA(D14_MARK, PS0_6_FN1, PTB6_FN),
- PINMUX_DATA(ET0_MDIO_MARK, PS0_6_FN2, PTB6_FN),
- PINMUX_DATA(D13_MARK, PS0_5_FN1, PTB5_FN),
- PINMUX_DATA(ET1_MDC_MARK, PS0_5_FN2, PTB5_FN),
- PINMUX_DATA(D12_MARK, PS0_4_FN1, PTB4_FN),
- PINMUX_DATA(ET1_MDIO_MARK, PS0_4_FN2, PTB4_FN),
- PINMUX_DATA(D11_MARK, PS0_3_FN1, PTB3_FN),
- PINMUX_DATA(SIM_D_MARK, PS0_3_FN2, PTB3_FN),
- PINMUX_DATA(D10_MARK, PS0_2_FN1, PTB2_FN),
- PINMUX_DATA(SIM_CLK_MARK, PS0_2_FN2, PTB2_FN),
- PINMUX_DATA(D9_MARK, PS0_1_FN1, PTB1_FN),
- PINMUX_DATA(SIM_RST_MARK, PS0_1_FN2, PTB1_FN),
- PINMUX_DATA(D8_MARK, PTB0_FN),
+ PINMUX_DATA(IRQ15_MARK, PS0_15_FN1, PTB7_FN),
+ PINMUX_DATA(ON_NRE_MARK, PS0_15_FN2, PTB7_FN),
+ PINMUX_DATA(IRQ14_MARK, PS0_14_FN1, PTB6_FN),
+ PINMUX_DATA(ON_NWE_MARK, PS0_14_FN2, PTB6_FN),
+ PINMUX_DATA(IRQ13_MARK, PS0_13_FN1, PTB5_FN),
+ PINMUX_DATA(ON_NWP_MARK, PS0_13_FN2, PTB5_FN),
+ PINMUX_DATA(IRQ12_MARK, PS0_12_FN1, PTB4_FN),
+ PINMUX_DATA(ON_NCE0_MARK, PS0_12_FN2, PTB4_FN),
+ PINMUX_DATA(IRQ11_MARK, PS0_11_FN1, PTB3_FN),
+ PINMUX_DATA(ON_R_B0_MARK, PS0_11_FN2, PTB3_FN),
+ PINMUX_DATA(IRQ10_MARK, PS0_10_FN1, PTB2_FN),
+ PINMUX_DATA(ON_ALE_MARK, PS0_10_FN2, PTB2_FN),
+ PINMUX_DATA(IRQ9_MARK, PS0_9_FN1, PTB1_FN),
+ PINMUX_DATA(ON_CLE_MARK, PS0_9_FN2, PTB1_FN),
+ PINMUX_DATA(IRQ8_MARK, PS0_8_FN1, PTB0_FN),
+ PINMUX_DATA(TCLK_MARK, PS0_8_FN2, PTB0_FN),
/* PTC FN */
- PINMUX_DATA(SD_WP_MARK, PTC7_FN),
- PINMUX_DATA(SD_CD_MARK, PTC6_FN),
- PINMUX_DATA(SD_CLK_MARK, PTC5_FN),
- PINMUX_DATA(SD_CMD_MARK, PTC4_FN),
- PINMUX_DATA(SD_D3_MARK, PTC3_FN),
- PINMUX_DATA(SD_D2_MARK, PTC2_FN),
- PINMUX_DATA(SD_D1_MARK, PTC1_FN),
- PINMUX_DATA(SD_D0_MARK, PTC0_FN),
+ PINMUX_DATA(IRQ7_MARK, PS0_7_FN1, PTC7_FN),
+ PINMUX_DATA(PWMU0_MARK, PS0_7_FN2, PTC7_FN),
+ PINMUX_DATA(IRQ6_MARK, PS0_6_FN1, PTC6_FN),
+ PINMUX_DATA(PWMU1_MARK, PS0_6_FN2, PTC6_FN),
+ PINMUX_DATA(IRQ5_MARK, PS0_5_FN1, PTC5_FN),
+ PINMUX_DATA(PWMU2_MARK, PS0_5_FN2, PTC5_FN),
+ PINMUX_DATA(IRQ4_MARK, PS0_4_FN1, PTC5_FN),
+ PINMUX_DATA(PWMU3_MARK, PS0_4_FN2, PTC4_FN),
+ PINMUX_DATA(IRQ3_MARK, PS0_3_FN1, PTC3_FN),
+ PINMUX_DATA(PWMU4_MARK, PS0_3_FN2, PTC3_FN),
+ PINMUX_DATA(IRQ2_MARK, PS0_2_FN1, PTC2_FN),
+ PINMUX_DATA(PWMU5_MARK, PS0_2_FN2, PTC2_FN),
+ PINMUX_DATA(IRQ1_MARK, PTC1_FN),
+ PINMUX_DATA(IRQ0_MARK, PTC0_FN),
/* PTD FN */
- PINMUX_DATA(IRQ7_MARK, PS1_7_FN1, PTD7_FN),
- PINMUX_DATA(ADTRG1_MARK, PS1_7_FN3, PTD7_FN),
- PINMUX_DATA(IRQ6_MARK, PS1_6_FN1, PTD6_FN),
- PINMUX_DATA(ADTRG0_MARK, PS1_6_FN3, PTD6_FN),
- PINMUX_DATA(IRQ5_MARK, PTD5_FN),
- PINMUX_DATA(IRQ4_MARK, PTD4_FN),
- PINMUX_DATA(IRQ3_MARK, PTD3_FN),
- PINMUX_DATA(IRQ2_MARK, PTD2_FN),
- PINMUX_DATA(IRQ1_MARK, PTD1_FN),
- PINMUX_DATA(IRQ0_MARK, PTD0_FN),
+ PINMUX_DATA(SP0_MOSI_MARK, PTD7_FN),
+ PINMUX_DATA(SP0_MISO_MARK, PTD6_FN),
+ PINMUX_DATA(SP0_SCK_MARK, PTD5_FN),
+ PINMUX_DATA(SP0_SCK_FB_MARK, PTD4_FN),
+ PINMUX_DATA(SP0_SS0_MARK, PTD3_FN),
+ PINMUX_DATA(SP0_SS1_MARK, PS1_10_FN1, PTD2_FN),
+ PINMUX_DATA(DREQ0_MARK, PS1_10_FN2, PTD2_FN),
+ PINMUX_DATA(SP0_SS2_MARK, PS1_9_FN1, PTD1_FN),
+ PINMUX_DATA(DACK0_MARK, PS1_9_FN2, PTD1_FN),
+ PINMUX_DATA(SP0_SS3_MARK, PS1_8_FN1, PTD0_FN),
+ PINMUX_DATA(TEND0_MARK, PS1_8_FN2, PTD0_FN),
/* PTE FN */
- PINMUX_DATA(ET0_CRS_DV_MARK, PTE7_FN),
- PINMUX_DATA(ET0_TXD1_MARK, PTE6_FN),
- PINMUX_DATA(ET0_TXD0_MARK, PTE5_FN),
- PINMUX_DATA(ET0_TX_EN_MARK, PTE4_FN),
- PINMUX_DATA(ET0_REF_CLK_MARK, PTE3_FN),
- PINMUX_DATA(ET0_RXD1_MARK, PTE2_FN),
- PINMUX_DATA(ET0_RXD0_MARK, PTE1_FN),
- PINMUX_DATA(ET0_RX_ER_MARK, PTE0_FN),
+ PINMUX_DATA(RMII0_CRS_DV_MARK, PTE7_FN),
+ PINMUX_DATA(RMII0_TXD1_MARK, PTE6_FN),
+ PINMUX_DATA(RMII0_TXD0_MARK, PTE5_FN),
+ PINMUX_DATA(RMII0_TXEN_MARK, PTE4_FN),
+ PINMUX_DATA(RMII0_REFCLK_MARK, PTE3_FN),
+ PINMUX_DATA(RMII0_RXD1_MARK, PTE2_FN),
+ PINMUX_DATA(RMII0_RXD0_MARK, PTE1_FN),
+ PINMUX_DATA(RMII0_RX_ER_MARK, PTE0_FN),
/* PTF FN */
- PINMUX_DATA(ET1_CRS_DV_MARK, PTF7_FN),
- PINMUX_DATA(ET1_TXD1_MARK, PTF6_FN),
- PINMUX_DATA(ET1_TXD0_MARK, PTF5_FN),
- PINMUX_DATA(ET1_TX_EN_MARK, PTF4_FN),
- PINMUX_DATA(ET1_REF_CLK_MARK, PTF3_FN),
- PINMUX_DATA(ET1_RXD1_MARK, PTF2_FN),
- PINMUX_DATA(ET1_RXD0_MARK, PTF1_FN),
- PINMUX_DATA(ET1_RX_ER_MARK, PTF0_FN),
+ PINMUX_DATA(RMII1_CRS_DV_MARK, PTF7_FN),
+ PINMUX_DATA(RMII1_TXD1_MARK, PTF6_FN),
+ PINMUX_DATA(RMII1_TXD0_MARK, PTF5_FN),
+ PINMUX_DATA(RMII1_TXEN_MARK, PTF4_FN),
+ PINMUX_DATA(RMII1_REFCLK_MARK, PTF3_FN),
+ PINMUX_DATA(RMII1_RXD1_MARK, PS1_2_FN1, PTF2_FN),
+ PINMUX_DATA(RAC_RI_MARK, PS1_2_FN2, PTF2_FN),
+ PINMUX_DATA(RMII1_RXD0_MARK, PTF1_FN),
+ PINMUX_DATA(RMII1_RX_ER_MARK, PTF0_FN),
/* PTG FN */
- PINMUX_DATA(PWX0_MARK, PTG7_FN),
- PINMUX_DATA(PWX1_MARK, PTG6_FN),
- PINMUX_DATA(STATUS0_MARK, PS2_13_FN1, PTG5_FN),
- PINMUX_DATA(PWX2_MARK, PS2_13_FN3, PTG5_FN),
- PINMUX_DATA(STATUS1_MARK, PS2_12_FN1, PTG4_FN),
- PINMUX_DATA(PWX3_MARK, PS2_12_FN3, PTG4_FN),
+ PINMUX_DATA(BOOTFMS_MARK, PTG7_FN),
+ PINMUX_DATA(BOOTWP_MARK, PTG6_FN),
+ PINMUX_DATA(A25_MARK, PS2_13_FN1, PTG5_FN),
+ PINMUX_DATA(MMCCLK_MARK, PS2_13_FN2, PTG5_FN),
+ PINMUX_DATA(A24_MARK, PS2_12_FN1, PTG4_FN),
+ PINMUX_DATA(MMCCMD_MARK, PS2_12_FN2, PTG4_FN),
PINMUX_DATA(SERIRQ_MARK, PTG3_FN),
- PINMUX_DATA(CLKRUN_MARK, PTG2_FN),
+ PINMUX_DATA(WDTOVF_MARK, PTG2_FN),
PINMUX_DATA(LPCPD_MARK, PTG1_FN),
PINMUX_DATA(LDRQ_MARK, PTG0_FN),
/* PTH FN */
- PINMUX_DATA(SP1_MOSI_MARK, PTH7_FN),
- PINMUX_DATA(SP1_MISO_MARK, PTH6_FN),
- PINMUX_DATA(SP1_SCK_MARK, PTH5_FN),
- PINMUX_DATA(SP1_SCK_FB_MARK, PTH4_FN),
+ PINMUX_DATA(SP1_MOSI_MARK, PS2_7_FN1, PTH7_FN),
+ PINMUX_DATA(TEND1_MARK, PS2_7_FN2, PTH7_FN),
+ PINMUX_DATA(SP1_MISO_MARK, PS2_6_FN1, PTH6_FN),
+ PINMUX_DATA(DREQ1_MARK, PS2_6_FN2, PTH6_FN),
+ PINMUX_DATA(SP1_SCK_MARK, PS2_5_FN1, PTH5_FN),
+ PINMUX_DATA(DACK1_MARK, PS2_5_FN2, PTH5_FN),
+ PINMUX_DATA(SP1_SCK_FB_MARK, PS2_4_FN1, PTH4_FN),
+ PINMUX_DATA(ADTRG1_MARK, PS2_4_FN2, PTH4_FN),
PINMUX_DATA(SP1_SS0_MARK, PTH3_FN),
- PINMUX_DATA(TCLK_MARK, PTH2_FN),
- PINMUX_DATA(RXD4_MARK, PS2_1_FN1, PTH1_FN),
- PINMUX_DATA(SP1_SS1_MARK, PS2_1_FN2, PTH1_FN),
- PINMUX_DATA(TXD4_MARK, PS2_0_FN1, PTH0_FN),
- PINMUX_DATA(SP0_SS1_MARK, PS2_0_FN2, PTH0_FN),
+ PINMUX_DATA(SP1_SS1_MARK, PS2_2_FN1, PTH2_FN),
+ PINMUX_DATA(ADTRG0_MARK, PS2_2_FN2, PTH2_FN),
+ PINMUX_DATA(WP_MARK, PTH1_FN),
+ PINMUX_DATA(FMS0_MARK, PTH0_FN),
/* PTI FN */
- PINMUX_DATA(IRQ15_MARK, PTI7_FN),
- PINMUX_DATA(IRQ14_MARK, PTI6_FN),
- PINMUX_DATA(IRQ13_MARK, PTI5_FN),
- PINMUX_DATA(IRQ12_MARK, PTI4_FN),
- PINMUX_DATA(IRQ11_MARK, PTI3_FN),
- PINMUX_DATA(IRQ10_MARK, PTI2_FN),
- PINMUX_DATA(IRQ9_MARK, PTI1_FN),
- PINMUX_DATA(IRQ8_MARK, PTI0_FN),
+ PINMUX_DATA(D15_MARK, PS3_15_FN1, PTI7_FN),
+ PINMUX_DATA(SD_WP_MARK, PS3_15_FN2, PTI7_FN),
+ PINMUX_DATA(D14_MARK, PS3_14_FN1, PTI6_FN),
+ PINMUX_DATA(SD_CD_MARK, PS3_14_FN2, PTI6_FN),
+ PINMUX_DATA(D13_MARK, PS3_13_FN1, PTI5_FN),
+ PINMUX_DATA(SD_CLK_MARK, PS3_13_FN2, PTI5_FN),
+ PINMUX_DATA(D12_MARK, PS3_12_FN1, PTI4_FN),
+ PINMUX_DATA(SD_CMD_MARK, PS3_12_FN2, PTI4_FN),
+ PINMUX_DATA(D11_MARK, PS3_11_FN1, PTI3_FN),
+ PINMUX_DATA(SD_D3_MARK, PS3_11_FN2, PTI3_FN),
+ PINMUX_DATA(D10_MARK, PS3_10_FN1, PTI2_FN),
+ PINMUX_DATA(SD_D2_MARK, PS3_10_FN2, PTI2_FN),
+ PINMUX_DATA(D9_MARK, PS3_9_FN1, PTI1_FN),
+ PINMUX_DATA(SD_D1_MARK, PS3_9_FN2, PTI1_FN),
+ PINMUX_DATA(D8_MARK, PS3_8_FN1, PTI0_FN),
+ PINMUX_DATA(SD_D0_MARK, PS3_8_FN2, PTI0_FN),
/* PTJ FN */
- PINMUX_DATA(RXD3_MARK, PTJ7_FN),
- PINMUX_DATA(TXD3_MARK, PTJ6_FN),
- PINMUX_DATA(RXD2_MARK, PTJ5_FN),
- PINMUX_DATA(TXD2_MARK, PTJ4_FN),
- PINMUX_DATA(COM1_TXD_MARK, PTJ3_FN),
- PINMUX_DATA(COM1_RXD_MARK, PTJ2_FN),
- PINMUX_DATA(COM1_RTS_MARK, PTJ1_FN),
- PINMUX_DATA(COM1_CTS_MARK, PTJ0_FN),
+ PINMUX_DATA(RTS3_MARK, PTJ6_FN),
+ PINMUX_DATA(CTS3_MARK, PTJ5_FN),
+ PINMUX_DATA(TXD3_MARK, PTJ4_FN),
+ PINMUX_DATA(RXD3_MARK, PTJ3_FN),
+ PINMUX_DATA(RTS4_MARK, PTJ2_FN),
+ PINMUX_DATA(RXD4_MARK, PTJ1_FN),
+ PINMUX_DATA(TXD4_MARK, PTJ0_FN),
/* PTK FN */
- PINMUX_DATA(COM2_TXD_MARK, PTK7_FN),
+ PINMUX_DATA(COM2_TXD_MARK, PS3_7_FN1, PTK7_FN),
+ PINMUX_DATA(SCK2_MARK, PS3_7_FN2, PTK7_FN),
PINMUX_DATA(COM2_RXD_MARK, PTK6_FN),
PINMUX_DATA(COM2_RTS_MARK, PTK5_FN),
PINMUX_DATA(COM2_CTS_MARK, PTK4_FN),
PINMUX_DATA(COM2_DTR_MARK, PTK3_FN),
- PINMUX_DATA(COM2_DSR_MARK, PTK2_FN),
- PINMUX_DATA(COM2_DCD_MARK, PTK1_FN),
- PINMUX_DATA(COM2_RI_MARK, PTK0_FN),
+ PINMUX_DATA(COM2_DSR_MARK, PS3_2_FN1, PTK2_FN),
+ PINMUX_DATA(SCK4_MARK, PS3_2_FN2, PTK2_FN),
+ PINMUX_DATA(COM2_DCD_MARK, PS3_1_FN1, PTK1_FN),
+ PINMUX_DATA(SCK3_MARK, PS3_1_FN2, PTK1_FN),
+ PINMUX_DATA(CLKOUT_MARK, PTK0_FN),
/* PTL FN */
- PINMUX_DATA(RAC_TXD_MARK, PTL7_FN),
- PINMUX_DATA(RAC_RXD_MARK, PTL6_FN),
- PINMUX_DATA(RAC_RTS_MARK, PTL5_FN),
- PINMUX_DATA(RAC_CTS_MARK, PTL4_FN),
+ PINMUX_DATA(RAC_RXD_MARK, PS4_14_FN1, PTL6_FN),
+ PINMUX_DATA(RXD2_MARK, PS4_14_FN2, PTL6_FN),
+ PINMUX_DATA(RAC_RTS_MARK, PS4_13_FN1, PTL5_FN),
+ PINMUX_DATA(CS5_MARK, PS4_13_FN2, PTL5_FN),
+ PINMUX_DATA(RAC_CTS_MARK, PS4_12_FN1, PTL4_FN),
+ PINMUX_DATA(CS6_MARK, PS4_12_FN2, PTL4_FN),
PINMUX_DATA(RAC_DTR_MARK, PTL3_FN),
- PINMUX_DATA(RAC_DSR_MARK, PTL2_FN),
- PINMUX_DATA(RAC_DCD_MARK, PTL1_FN),
- PINMUX_DATA(RAC_RI_MARK, PTL0_FN),
+ PINMUX_DATA(RAC_DSR_MARK, PS4_10_FN1, PTL2_FN),
+ PINMUX_DATA(AUDSYNC_MARK, PS4_10_FN2, PTL2_FN),
+ PINMUX_DATA(RAC_DCD_MARK, PS4_9_FN1, PTL1_FN),
+ PINMUX_DATA(AUDCK_MARK, PS4_9_FN2, PTL1_FN),
+ PINMUX_DATA(RAC_TXD_MARK, PS4_8_FN1, PTL0_FN),
+ PINMUX_DATA(TXD2_MARK, PS4_8_FN1, PTL0_FN),
/* PTM FN */
- PINMUX_DATA(WP_MARK, PTM6_FN),
- PINMUX_DATA(FMS0_MARK, PTM5_FN),
- PINMUX_DATA(FMS1_MARK, PTM4_FN),
+ PINMUX_DATA(CS4_MARK, PTM7_FN),
+ PINMUX_DATA(RD_MARK, PTM6_FN),
+ PINMUX_DATA(WE0_MARK, PTM7_FN),
+ PINMUX_DATA(CS0_MARK, PTM4_FN),
PINMUX_DATA(SDA6_MARK, PTM3_FN),
PINMUX_DATA(SCL6_MARK, PTM2_FN),
PINMUX_DATA(SDA7_MARK, PTM1_FN),
PINMUX_DATA(SCL7_MARK, PTM0_FN),
/* PTN FN */
- PINMUX_DATA(SCK2_MARK, PS4_15_FN1, PTN7_FN),
- PINMUX_DATA(EVENT7_MARK, PS4_15_FN2, PTN7_FN),
- PINMUX_DATA(RTS4_MARK, PS4_14_FN1, PTN6_FN),
- PINMUX_DATA(EVENT6_MARK, PS4_14_FN2, PTN6_FN),
- PINMUX_DATA(RTS3_MARK, PS4_13_FN1, PTN5_FN),
- PINMUX_DATA(EVENT5_MARK, PS4_13_FN2, PTN5_FN),
- PINMUX_DATA(RTS2_MARK, PS4_12_FN1, PTN4_FN),
- PINMUX_DATA(EVENT4_MARK, PS4_12_FN2, PTN4_FN),
- PINMUX_DATA(CTS4_MARK, PS4_11_FN1, PTN3_FN),
- PINMUX_DATA(EVENT3_MARK, PS4_11_FN2, PTN3_FN),
- PINMUX_DATA(CTS3_MARK, PS4_10_FN1, PTN2_FN),
- PINMUX_DATA(EVENT2_MARK, PS4_10_FN2, PTN2_FN),
- PINMUX_DATA(CTS2_MARK, PS4_9_FN1, PTN1_FN),
- PINMUX_DATA(EVENT1_MARK, PS4_9_FN2, PTN1_FN),
- PINMUX_DATA(EVENT0_MARK, PTN0_FN),
+ PINMUX_DATA(VBUS_EN_MARK, PTN6_FN),
+ PINMUX_DATA(VBUS_OC_MARK, PTN5_FN),
+ PINMUX_DATA(JMCTCK_MARK, PS4_4_FN1, PTN4_FN),
+ PINMUX_DATA(SGPIO1_CLK_MARK, PS4_4_FN2, PTN4_FN),
+ PINMUX_DATA(JMCTMS_MARK, PS4_3_FN1, PTN5_FN),
+ PINMUX_DATA(SGPIO1_LOAD_MARK, PS4_3_FN2, PTN5_FN),
+ PINMUX_DATA(JMCTDO_MARK, PS4_2_FN1, PTN2_FN),
+ PINMUX_DATA(SGPIO1_DO_MARK, PS4_2_FN2, PTN2_FN),
+ PINMUX_DATA(JMCTDI_MARK, PS4_1_FN1, PTN1_FN),
+ PINMUX_DATA(SGPIO1_DI_MARK, PS4_1_FN2, PTN1_FN),
+ PINMUX_DATA(JMCTRST_MARK, PS4_0_FN1, PTN0_FN),
+ PINMUX_DATA(SUB_CLKIN_MARK, PS4_0_FN2, PTN0_FN),
/* PTO FN */
PINMUX_DATA(SGPIO0_CLK_MARK, PTO7_FN),
PINMUX_DATA(SGPIO0_LOAD_MARK, PTO6_FN),
PINMUX_DATA(SGPIO0_DI_MARK, PTO5_FN),
PINMUX_DATA(SGPIO0_DO_MARK, PTO4_FN),
- PINMUX_DATA(SGPIO1_CLK_MARK, PTO3_FN),
- PINMUX_DATA(SGPIO1_LOAD_MARK, PTO2_FN),
- PINMUX_DATA(SGPIO1_DI_MARK, PTO1_FN),
- PINMUX_DATA(SGPIO1_DO_MARK, PTO0_FN),
+ PINMUX_DATA(SGPIO2_CLK_MARK, PS5_11_FN1, PTO3_FN),
+ PINMUX_DATA(COM1_TXD_MARK, PS5_11_FN2, PTO3_FN),
+ PINMUX_DATA(SGPIO2_LOAD_MARK, PS5_10_FN1, PTO2_FN),
+ PINMUX_DATA(COM1_RXD_MARK, PS5_10_FN2, PTO2_FN),
+ PINMUX_DATA(SGPIO2_DI_MARK, PS5_9_FN1, PTO1_FN),
+ PINMUX_DATA(COM1_RTS_MARK, PS5_9_FN2, PTO1_FN),
+ PINMUX_DATA(SGPIO2_DO_MARK, PS5_8_FN1, PTO0_FN),
+ PINMUX_DATA(COM1_CTS_MARK, PS5_8_FN2, PTO0_FN),
/* PTP FN */
- PINMUX_DATA(JMCTCK_MARK, PTP6_FN),
- PINMUX_DATA(JMCTMS_MARK, PTP5_FN),
- PINMUX_DATA(JMCTDO_MARK, PTP4_FN),
- PINMUX_DATA(JMCTDI_MARK, PTP3_FN),
- PINMUX_DATA(JMCRST_MARK, PTP2_FN),
- PINMUX_DATA(SCK4_MARK, PTP1_FN),
- PINMUX_DATA(SCK3_MARK, PTP0_FN),
/* PTQ FN */
PINMUX_DATA(LAD3_MARK, PTQ6_FN),
@@ -864,8 +977,8 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(LAD1_MARK, PTQ4_FN),
PINMUX_DATA(LAD0_MARK, PTQ3_FN),
PINMUX_DATA(LFRAME_MARK, PTQ2_FN),
- PINMUX_DATA(SCK4_MARK, PTQ1_FN),
- PINMUX_DATA(SCK3_MARK, PTQ0_FN),
+ PINMUX_DATA(LRESET_MARK, PTQ1_FN),
+ PINMUX_DATA(LCLK_MARK, PTQ0_FN),
/* PTR FN */
PINMUX_DATA(SDA8_MARK, PTR7_FN), /* DDC3? */
@@ -888,58 +1001,84 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(SCL3_MARK, PTS0_FN),
/* PTT FN */
- PINMUX_DATA(AUDSYNC_MARK, PTS5_FN),
- PINMUX_DATA(AUDCK_MARK, PTS4_FN),
- PINMUX_DATA(AUDATA3_MARK, PS4_3_FN1, PTS3_FN),
- PINMUX_DATA(PWX7_MARK, PS4_3_FN2, PTS3_FN),
- PINMUX_DATA(AUDATA2_MARK, PS4_2_FN1, PTS2_FN),
- PINMUX_DATA(PWX6_MARK, PS4_2_FN2, PTS2_FN),
- PINMUX_DATA(AUDATA1_MARK, PS4_1_FN1, PTS1_FN),
- PINMUX_DATA(PWX5_MARK, PS4_1_FN2, PTS1_FN),
- PINMUX_DATA(AUDATA0_MARK, PS4_0_FN1, PTS0_FN),
- PINMUX_DATA(PWX4_MARK, PS4_0_FN2, PTS0_FN),
+ PINMUX_DATA(PWMX7_MARK, PS5_7_FN1, PTT7_FN),
+ PINMUX_DATA(AUDATA3_MARK, PS5_7_FN2, PTT7_FN),
+ PINMUX_DATA(PWMX6_MARK, PS5_6_FN1, PTT6_FN),
+ PINMUX_DATA(AUDATA2_MARK, PS5_6_FN2, PTT6_FN),
+ PINMUX_DATA(PWMX5_MARK, PS5_5_FN1, PTT5_FN),
+ PINMUX_DATA(AUDATA1_MARK, PS5_5_FN2, PTT5_FN),
+ PINMUX_DATA(PWMX4_MARK, PS5_4_FN1, PTT4_FN),
+ PINMUX_DATA(AUDATA0_MARK, PS5_4_FN2, PTT4_FN),
+ PINMUX_DATA(PWMX3_MARK, PS5_3_FN1, PTT3_FN),
+ PINMUX_DATA(STATUS1_MARK, PS5_3_FN2, PTT3_FN),
+ PINMUX_DATA(PWMX2_MARK, PS5_2_FN1, PTT2_FN),
+ PINMUX_DATA(STATUS0_MARK, PS5_2_FN2, PTT2_FN),
+ PINMUX_DATA(PWMX1_MARK, PTT1_FN),
+ PINMUX_DATA(PWMX0_MARK, PTT0_FN),
/* PTU FN */
- PINMUX_DATA(CS6_MARK, PTU7_FN),
- PINMUX_DATA(CS5_MARK, PTU6_FN),
- PINMUX_DATA(CS4_MARK, PTU5_FN),
- PINMUX_DATA(CS0_MARK, PTU4_FN),
- PINMUX_DATA(RD_MARK, PTU3_FN),
- PINMUX_DATA(WE0_MARK, PTU2_FN),
- PINMUX_DATA(A25_MARK, PS5_9_FN1, PTU1_FN),
- PINMUX_DATA(DREQ0_MARK, PS5_9_FN2, PTU1_FN),
- PINMUX_DATA(A24_MARK, PS5_8_FN1, PTU0_FN),
- PINMUX_DATA(DACK0_MARK, PS5_8_FN2, PTU0_FN),
+ PINMUX_DATA(LGPIO7_MARK, PS6_15_FN1, PTU7_FN),
+ PINMUX_DATA(APMONCTL_O_MARK, PS6_15_FN2, PTU7_FN),
+ PINMUX_DATA(LGPIO6_MARK, PS6_14_FN1, PTU6_FN),
+ PINMUX_DATA(APMPWBTOUT_O_MARK, PS6_14_FN2, PTU6_FN),
+ PINMUX_DATA(LGPIO5_MARK, PS6_13_FN1, PTU5_FN),
+ PINMUX_DATA(APMSCI_O_MARK, PS6_13_FN2, PTU5_FN),
+ PINMUX_DATA(LGPIO4_MARK, PS6_12_FN1, PTU4_FN),
+ PINMUX_DATA(APMVDDON_MARK, PS6_12_FN2, PTU4_FN),
+ PINMUX_DATA(LGPIO3_MARK, PS6_11_FN1, PTU3_FN),
+ PINMUX_DATA(APMSLPBTN_MARK, PS6_11_FN2, PTU3_FN),
+ PINMUX_DATA(LGPIO2_MARK, PS6_10_FN1, PTU2_FN),
+ PINMUX_DATA(APMPWRBTN_MARK, PS6_10_FN2, PTU2_FN),
+ PINMUX_DATA(LGPIO1_MARK, PS6_9_FN1, PTU1_FN),
+ PINMUX_DATA(APMS5N_MARK, PS6_9_FN2, PTU1_FN),
+ PINMUX_DATA(LGPIO0_MARK, PS6_8_FN1, PTU0_FN),
+ PINMUX_DATA(APMS3N_MARK, PS6_8_FN2, PTU0_FN),
/* PTV FN */
- PINMUX_DATA(A23_MARK, PS5_7_FN1, PTV7_FN),
- PINMUX_DATA(TEND0_MARK, PS5_7_FN2, PTV7_FN),
- PINMUX_DATA(A22_MARK, PS5_6_FN1, PTV6_FN),
- PINMUX_DATA(DREQ1_MARK, PS5_6_FN2, PTV6_FN),
- PINMUX_DATA(A21_MARK, PS5_5_FN1, PTV5_FN),
- PINMUX_DATA(DACK1_MARK, PS5_5_FN2, PTV5_FN),
- PINMUX_DATA(A20_MARK, PS5_4_FN1, PTV4_FN),
- PINMUX_DATA(TEND1_MARK, PS5_4_FN2, PTV4_FN),
- PINMUX_DATA(A19_MARK, PTV3_FN),
- PINMUX_DATA(A18_MARK, PTV2_FN),
- PINMUX_DATA(A17_MARK, PTV1_FN),
- PINMUX_DATA(A16_MARK, PTV0_FN),
+ PINMUX_DATA(A23_MARK, PS6_7_FN1, PTV7_FN),
+ PINMUX_DATA(COM2_RI_MARK, PS6_7_FN2, PTV7_FN),
+ PINMUX_DATA(A22_MARK, PS6_6_FN1, PTV6_FN),
+ PINMUX_DATA(R_SPI_MOSI_MARK, PS6_6_FN2, PTV6_FN),
+ PINMUX_DATA(A21_MARK, PS6_5_FN1, PTV5_FN),
+ PINMUX_DATA(R_SPI_MISO_MARK, PS6_5_FN2, PTV5_FN),
+ PINMUX_DATA(A20_MARK, PS6_4_FN1, PTV4_FN),
+ PINMUX_DATA(R_SPI_RSPCK_MARK, PS6_4_FN2, PTV4_FN),
+ PINMUX_DATA(A19_MARK, PS6_3_FN1, PTV3_FN),
+ PINMUX_DATA(R_SPI_SSL0_MARK, PS6_3_FN2, PTV3_FN),
+ PINMUX_DATA(A18_MARK, PS6_2_FN1, PTV2_FN),
+ PINMUX_DATA(R_SPI_SSL1_MARK, PS6_2_FN2, PTV2_FN),
+ PINMUX_DATA(A17_MARK, PS6_1_FN1, PTV1_FN),
+ PINMUX_DATA(EVENT7_MARK, PS6_1_FN2, PTV1_FN),
+ PINMUX_DATA(A16_MARK, PS6_0_FN1, PTV0_FN),
+ PINMUX_DATA(EVENT6_MARK, PS6_0_FN1, PTV0_FN),
/* PTW FN */
- PINMUX_DATA(A15_MARK, PTW7_FN),
- PINMUX_DATA(A14_MARK, PTW6_FN),
- PINMUX_DATA(A13_MARK, PTW5_FN),
- PINMUX_DATA(A12_MARK, PTW4_FN),
- PINMUX_DATA(A11_MARK, PTW3_FN),
- PINMUX_DATA(A10_MARK, PTW2_FN),
- PINMUX_DATA(A9_MARK, PTW1_FN),
- PINMUX_DATA(A8_MARK, PTW0_FN),
+ PINMUX_DATA(A15_MARK, PS7_15_FN1, PTW7_FN),
+ PINMUX_DATA(EVENT5_MARK, PS7_15_FN2, PTW7_FN),
+ PINMUX_DATA(A14_MARK, PS7_14_FN1, PTW6_FN),
+ PINMUX_DATA(EVENT4_MARK, PS7_14_FN2, PTW6_FN),
+ PINMUX_DATA(A13_MARK, PS7_13_FN1, PTW5_FN),
+ PINMUX_DATA(EVENT3_MARK, PS7_13_FN2, PTW5_FN),
+ PINMUX_DATA(A12_MARK, PS7_12_FN1, PTW4_FN),
+ PINMUX_DATA(EVENT2_MARK, PS7_12_FN2, PTW4_FN),
+ PINMUX_DATA(A11_MARK, PS7_11_FN1, PTW3_FN),
+ PINMUX_DATA(EVENT1_MARK, PS7_11_FN2, PTW3_FN),
+ PINMUX_DATA(A10_MARK, PS7_10_FN1, PTW2_FN),
+ PINMUX_DATA(EVENT0_MARK, PS7_10_FN2, PTW2_FN),
+ PINMUX_DATA(A9_MARK, PS7_9_FN1, PTW1_FN),
+ PINMUX_DATA(CTS4_MARK, PS7_9_FN2, PTW1_FN),
+ PINMUX_DATA(A8_MARK, PS7_8_FN1, PTW0_FN),
+ PINMUX_DATA(CTS2_MARK, PS7_8_FN2, PTW0_FN),
/* PTX FN */
- PINMUX_DATA(A7_MARK, PTX7_FN),
- PINMUX_DATA(A6_MARK, PTX6_FN),
- PINMUX_DATA(A5_MARK, PTX5_FN),
- PINMUX_DATA(A4_MARK, PTX4_FN),
+ PINMUX_DATA(A7_MARK, PS7_7_FN1, PTX7_FN),
+ PINMUX_DATA(RTS2_MARK, PS7_7_FN2, PTX7_FN),
+ PINMUX_DATA(A6_MARK, PS7_6_FN1, PTX6_FN),
+ PINMUX_DATA(SIM_D_MARK, PS7_6_FN2, PTX6_FN),
+ PINMUX_DATA(A5_MARK, PS7_5_FN1, PTX5_FN),
+ PINMUX_DATA(SIM_CLK_MARK, PS7_5_FN2, PTX5_FN),
+ PINMUX_DATA(A4_MARK, PS7_4_FN1, PTX4_FN),
+ PINMUX_DATA(SIM_RST_MARK, PS7_4_FN2, PTX4_FN),
PINMUX_DATA(A3_MARK, PTX3_FN),
PINMUX_DATA(A2_MARK, PTX2_FN),
PINMUX_DATA(A1_MARK, PTX1_FN),
@@ -954,6 +1093,24 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(D2_MARK, PTY2_FN),
PINMUX_DATA(D1_MARK, PTY1_FN),
PINMUX_DATA(D0_MARK, PTY0_FN),
+
+ /* PTZ FN */
+ PINMUX_DATA(MMCDAT7_MARK, PS8_15_FN1, PTZ7_FN),
+ PINMUX_DATA(ON_DQ7_MARK, PS8_15_FN2, PTZ7_FN),
+ PINMUX_DATA(MMCDAT6_MARK, PS8_14_FN1, PTZ6_FN),
+ PINMUX_DATA(ON_DQ6_MARK, PS8_14_FN2, PTZ6_FN),
+ PINMUX_DATA(MMCDAT5_MARK, PS8_13_FN1, PTZ5_FN),
+ PINMUX_DATA(ON_DQ5_MARK, PS8_13_FN2, PTZ5_FN),
+ PINMUX_DATA(MMCDAT4_MARK, PS8_12_FN1, PTZ4_FN),
+ PINMUX_DATA(ON_DQ4_MARK, PS8_12_FN2, PTZ4_FN),
+ PINMUX_DATA(MMCDAT3_MARK, PS8_11_FN1, PTZ3_FN),
+ PINMUX_DATA(ON_DQ3_MARK, PS8_11_FN2, PTZ3_FN),
+ PINMUX_DATA(MMCDAT2_MARK, PS8_10_FN1, PTZ2_FN),
+ PINMUX_DATA(ON_DQ2_MARK, PS8_10_FN2, PTZ2_FN),
+ PINMUX_DATA(MMCDAT1_MARK, PS8_9_FN1, PTZ1_FN),
+ PINMUX_DATA(ON_DQ1_MARK, PS8_9_FN2, PTZ1_FN),
+ PINMUX_DATA(MMCDAT0_MARK, PS8_8_FN1, PTZ0_FN),
+ PINMUX_DATA(ON_DQ0_MARK, PS8_8_FN2, PTZ0_FN),
};
static struct pinmux_gpio pinmux_gpios[] = {
@@ -1048,7 +1205,6 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_PTI0, PTI0_DATA),
/* PTJ */
- PINMUX_GPIO(GPIO_PTJ7, PTJ7_DATA),
PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
PINMUX_GPIO(GPIO_PTJ4, PTJ4_DATA),
@@ -1068,7 +1224,6 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
/* PTL */
- PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
@@ -1078,6 +1233,7 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
/* PTM */
+ PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
@@ -1087,7 +1243,6 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
/* PTN */
- PINMUX_GPIO(GPIO_PTN7, PTN7_DATA),
PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
@@ -1107,6 +1262,7 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_PTO0, PTO0_DATA),
/* PTP */
+ PINMUX_GPIO(GPIO_PTP7, PTP7_DATA),
PINMUX_GPIO(GPIO_PTP6, PTP6_DATA),
PINMUX_GPIO(GPIO_PTP5, PTP5_DATA),
PINMUX_GPIO(GPIO_PTP4, PTP4_DATA),
@@ -1145,6 +1301,8 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
/* PTT */
+ PINMUX_GPIO(GPIO_PTT7, PTT7_DATA),
+ PINMUX_GPIO(GPIO_PTT6, PTT6_DATA),
PINMUX_GPIO(GPIO_PTT5, PTT5_DATA),
PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
@@ -1212,54 +1370,35 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
PINMUX_GPIO(GPIO_PTZ0, PTZ0_DATA),
- /* PTA (mobule: LBSC, CPG, LPC) */
+ /* PTA (mobule: LBSC, RGMII) */
PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
PINMUX_GPIO(GPIO_FN_WE1, WE1_MARK),
PINMUX_GPIO(GPIO_FN_RDY, RDY_MARK),
- PINMUX_GPIO(GPIO_FN_MD10, MD10_MARK),
- PINMUX_GPIO(GPIO_FN_MD9, MD9_MARK),
- PINMUX_GPIO(GPIO_FN_MD8, MD8_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO7, LGPIO7_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO6, LGPIO6_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO5, LGPIO5_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO4, LGPIO4_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO3, LGPIO3_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO2, LGPIO2_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO1, LGPIO1_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO0, LGPIO0_MARK),
-
- /* PTB (mobule: LBSC, EtherC, SIM, LPC) */
- PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
- PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
- PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
- PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
- PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
- PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
- PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
- PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
PINMUX_GPIO(GPIO_FN_ET0_MDC, ET0_MDC_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_MDIO, ET0_MDIO_MARK),
+ PINMUX_GPIO(GPIO_FN_ET0_MDIO, ET0_MDC_MARK),
PINMUX_GPIO(GPIO_FN_ET1_MDC, ET1_MDC_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_MDIO, ET1_MDIO_MARK),
- PINMUX_GPIO(GPIO_FN_WPSZ1, WPSZ1_MARK),
- PINMUX_GPIO(GPIO_FN_WPSZ0, WPSZ0_MARK),
- PINMUX_GPIO(GPIO_FN_FWID, FWID_MARK),
- PINMUX_GPIO(GPIO_FN_FLSHSZ, FLSHSZ_MARK),
- PINMUX_GPIO(GPIO_FN_LPC_SPIEN, LPC_SPIEN_MARK),
- PINMUX_GPIO(GPIO_FN_BASEL, BASEL_MARK),
-
- /* PTC (mobule: SD) */
- PINMUX_GPIO(GPIO_FN_SD_WP, SD_WP_MARK),
- PINMUX_GPIO(GPIO_FN_SD_CD, SD_CD_MARK),
- PINMUX_GPIO(GPIO_FN_SD_CLK, SD_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SD_CMD, SD_CMD_MARK),
- PINMUX_GPIO(GPIO_FN_SD_D3, SD_D3_MARK),
- PINMUX_GPIO(GPIO_FN_SD_D2, SD_D2_MARK),
- PINMUX_GPIO(GPIO_FN_SD_D1, SD_D1_MARK),
- PINMUX_GPIO(GPIO_FN_SD_D0, SD_D0_MARK),
+ PINMUX_GPIO(GPIO_FN_ET1_MDIO, ET1_MDC_MARK),
- /* PTD (mobule: INTC, SPI0, LBSC, CPG, ADC) */
+ /* PTB (mobule: INTC, ONFI, TMU) */
+ PINMUX_GPIO(GPIO_FN_IRQ15, IRQ15_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ14, IRQ14_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ13, IRQ13_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ12, IRQ12_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ11, IRQ11_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ10, IRQ10_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ9, IRQ9_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ8, IRQ8_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_NRE, ON_NRE_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_NWE, ON_NWE_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_NWP, ON_NWP_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_NCE0, ON_NCE0_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_R_B0, ON_R_B0_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_ALE, ON_ALE_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_CLE, ON_CLE_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLK, TCLK_MARK),
+
+ /* PTC (mobule: IRQ, PWMU) */
PINMUX_GPIO(GPIO_FN_IRQ7, IRQ7_MARK),
PINMUX_GPIO(GPIO_FN_IRQ6, IRQ6_MARK),
PINMUX_GPIO(GPIO_FN_IRQ5, IRQ5_MARK),
@@ -1268,80 +1407,102 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_FN_IRQ2, IRQ2_MARK),
PINMUX_GPIO(GPIO_FN_IRQ1, IRQ1_MARK),
PINMUX_GPIO(GPIO_FN_IRQ0, IRQ0_MARK),
- PINMUX_GPIO(GPIO_FN_MD6, MD6_MARK),
- PINMUX_GPIO(GPIO_FN_MD5, MD5_MARK),
- PINMUX_GPIO(GPIO_FN_MD3, MD3_MARK),
- PINMUX_GPIO(GPIO_FN_MD2, MD2_MARK),
- PINMUX_GPIO(GPIO_FN_MD1, MD1_MARK),
- PINMUX_GPIO(GPIO_FN_MD0, MD0_MARK),
- PINMUX_GPIO(GPIO_FN_ADTRG1, ADTRG1_MARK),
- PINMUX_GPIO(GPIO_FN_ADTRG0, ADTRG0_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU0, PWMU0_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU1, PWMU1_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU2, PWMU2_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU3, PWMU3_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU4, PWMU4_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU5, PWMU5_MARK),
+
+ /* PTD (mobule: SPI0, DMAC) */
+ PINMUX_GPIO(GPIO_FN_SP0_MOSI, SP0_MOSI_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_MISO, SP0_MISO_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SCK, SP0_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SCK_FB, SP0_SCK_FB_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SS0, SP0_SS0_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SS1, SP0_SS1_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SS2, SP0_SS2_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SS3, SP0_SS3_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
- /* PTE (mobule: EtherC) */
- PINMUX_GPIO(GPIO_FN_ET0_CRS_DV, ET0_CRS_DV_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_TXD1, ET0_TXD1_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_TXD0, ET0_TXD0_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_TX_EN, ET0_TX_EN_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_REF_CLK, ET0_REF_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_RXD1, ET0_RXD1_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_RXD0, ET0_RXD0_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_RX_ER, ET0_RX_ER_MARK),
-
- /* PTF (mobule: EtherC) */
- PINMUX_GPIO(GPIO_FN_ET1_CRS_DV, ET1_CRS_DV_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_TXD1, ET1_TXD1_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_TXD0, ET1_TXD0_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_TX_EN, ET1_TX_EN_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_REF_CLK, ET1_REF_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_RXD1, ET1_RXD1_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_RXD0, ET1_RXD0_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_RX_ER, ET1_RX_ER_MARK),
-
- /* PTG (mobule: SYSTEM, PWMX, LPC) */
- PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
- PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
- PINMUX_GPIO(GPIO_FN_PWX0, PWX0_MARK),
- PINMUX_GPIO(GPIO_FN_PWX1, PWX1_MARK),
- PINMUX_GPIO(GPIO_FN_PWX2, PWX2_MARK),
- PINMUX_GPIO(GPIO_FN_PWX3, PWX3_MARK),
+ /* PTE (mobule: RMII) */
+ PINMUX_GPIO(GPIO_FN_RMII0_CRS_DV, RMII0_CRS_DV_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_TXD1, RMII0_TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_TXD0, RMII0_TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_TXEN, RMII0_TXEN_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_REFCLK, RMII0_REFCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_RXD1, RMII0_RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_RXD0, RMII0_RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_RX_ER, RMII0_RX_ER_MARK),
+
+ /* PTF (mobule: RMII, SerMux) */
+ PINMUX_GPIO(GPIO_FN_RMII1_CRS_DV, RMII1_CRS_DV_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_TXD1, RMII1_TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_TXD0, RMII1_TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_TXEN, RMII1_TXEN_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_REFCLK, RMII1_REFCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_RXD1, RMII1_RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_RXD0, RMII1_RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_RX_ER, RMII1_RX_ER_MARK),
+ PINMUX_GPIO(GPIO_FN_RAC_RI, RAC_RI_MARK),
+
+ /* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
+ PINMUX_GPIO(GPIO_FN_BOOTFMS, BOOTFMS_MARK),
+ PINMUX_GPIO(GPIO_FN_BOOTWP, BOOTWP_MARK),
+ PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+ PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
PINMUX_GPIO(GPIO_FN_SERIRQ, SERIRQ_MARK),
- PINMUX_GPIO(GPIO_FN_CLKRUN, CLKRUN_MARK),
+ PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
PINMUX_GPIO(GPIO_FN_LPCPD, LPCPD_MARK),
PINMUX_GPIO(GPIO_FN_LDRQ, LDRQ_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCCLK, MMCCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCCMD, MMCCMD_MARK),
- /* PTH (mobule: TMU, SCIF234, SPI1, SPI0) */
- PINMUX_GPIO(GPIO_FN_TCLK, TCLK_MARK),
- PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
- PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
+ /* PTH (mobule: SPI1, LPC, DMAC, ADC) */
PINMUX_GPIO(GPIO_FN_SP1_MOSI, SP1_MOSI_MARK),
PINMUX_GPIO(GPIO_FN_SP1_MISO, SP1_MISO_MARK),
PINMUX_GPIO(GPIO_FN_SP1_SCK, SP1_SCK_MARK),
PINMUX_GPIO(GPIO_FN_SP1_SCK_FB, SP1_SCK_FB_MARK),
PINMUX_GPIO(GPIO_FN_SP1_SS0, SP1_SS0_MARK),
PINMUX_GPIO(GPIO_FN_SP1_SS1, SP1_SS1_MARK),
- PINMUX_GPIO(GPIO_FN_SP0_SS1, SP0_SS1_MARK),
+ PINMUX_GPIO(GPIO_FN_WP, WP_MARK),
+ PINMUX_GPIO(GPIO_FN_FMS0, FMS0_MARK),
+ PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+ PINMUX_GPIO(GPIO_FN_ADTRG1, ADTRG1_MARK),
+ PINMUX_GPIO(GPIO_FN_ADTRG0, ADTRG0_MARK),
- /* PTI (mobule: INTC) */
- PINMUX_GPIO(GPIO_FN_IRQ15, IRQ15_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ14, IRQ14_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ13, IRQ13_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ12, IRQ12_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ11, IRQ11_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ10, IRQ10_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ9, IRQ9_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ8, IRQ8_MARK),
+ /* PTI (mobule: LBSC, SDHI) */
+ PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
+ PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
+ PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
+ PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
+ PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
+ PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
+ PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
+ PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_WP, SD_WP_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_CD, SD_CD_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_CLK, SD_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_CMD, SD_CMD_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_D3, SD_D3_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_D2, SD_D2_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_D1, SD_D1_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_D0, SD_D0_MARK),
/* PTJ (mobule: SCIF234, SERMUX) */
- PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
- PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
- PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
- PINMUX_GPIO(GPIO_FN_COM1_TXD, COM1_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_COM1_RXD, COM1_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_COM1_RTS, COM1_RTS_MARK),
- PINMUX_GPIO(GPIO_FN_COM1_CTS, COM1_CTS_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS4, RTS4_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
- /* PTK (mobule: SERMUX) */
+ /* PTK (mobule: SERMUX, LBSC, SCIF) */
PINMUX_GPIO(GPIO_FN_COM2_TXD, COM2_TXD_MARK),
PINMUX_GPIO(GPIO_FN_COM2_RXD, COM2_RXD_MARK),
PINMUX_GPIO(GPIO_FN_COM2_RTS, COM2_RTS_MARK),
@@ -1349,62 +1510,65 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_FN_COM2_DTR, COM2_DTR_MARK),
PINMUX_GPIO(GPIO_FN_COM2_DSR, COM2_DSR_MARK),
PINMUX_GPIO(GPIO_FN_COM2_DCD, COM2_DCD_MARK),
- PINMUX_GPIO(GPIO_FN_COM2_RI, COM2_RI_MARK),
+ PINMUX_GPIO(GPIO_FN_CLKOUT, CLKOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK4, SCK4_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
- /* PTL (mobule: SERMUX) */
- PINMUX_GPIO(GPIO_FN_RAC_TXD, RAC_TXD_MARK),
+ /* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
PINMUX_GPIO(GPIO_FN_RAC_RXD, RAC_RXD_MARK),
PINMUX_GPIO(GPIO_FN_RAC_RTS, RAC_RTS_MARK),
PINMUX_GPIO(GPIO_FN_RAC_CTS, RAC_CTS_MARK),
PINMUX_GPIO(GPIO_FN_RAC_DTR, RAC_DTR_MARK),
PINMUX_GPIO(GPIO_FN_RAC_DSR, RAC_DSR_MARK),
PINMUX_GPIO(GPIO_FN_RAC_DCD, RAC_DCD_MARK),
- PINMUX_GPIO(GPIO_FN_RAC_RI, RAC_RI_MARK),
+ PINMUX_GPIO(GPIO_FN_RAC_TXD, RAC_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5, CS5_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6, CS6_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
- /* PTM (mobule: IIC, LPC) */
+ /* PTM (mobule: LBSC, IIC) */
+ PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+ PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
+ PINMUX_GPIO(GPIO_FN_WE0, WE0_MARK),
+ PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
PINMUX_GPIO(GPIO_FN_SDA6, SDA6_MARK),
PINMUX_GPIO(GPIO_FN_SCL6, SCL6_MARK),
PINMUX_GPIO(GPIO_FN_SDA7, SDA7_MARK),
PINMUX_GPIO(GPIO_FN_SCL7, SCL7_MARK),
- PINMUX_GPIO(GPIO_FN_WP, WP_MARK),
- PINMUX_GPIO(GPIO_FN_FMS0, FMS0_MARK),
- PINMUX_GPIO(GPIO_FN_FMS1, FMS1_MARK),
- /* PTN (mobule: SCIF234, EVC) */
- PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
- PINMUX_GPIO(GPIO_FN_RTS4, RTS4_MARK),
- PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
- PINMUX_GPIO(GPIO_FN_RTS2, RTS2_MARK),
- PINMUX_GPIO(GPIO_FN_CTS4, CTS4_MARK),
- PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
- PINMUX_GPIO(GPIO_FN_CTS2, CTS2_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT7, EVENT7_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT6, EVENT6_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT5, EVENT5_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT4, EVENT4_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT3, EVENT3_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT2, EVENT2_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT1, EVENT1_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT0, EVENT0_MARK),
+ /* PTN (mobule: USB, JMC, SGPIO, WDT) */
+ PINMUX_GPIO(GPIO_FN_VBUS_EN, VBUS_EN_MARK),
+ PINMUX_GPIO(GPIO_FN_VBUS_OC, VBUS_OC_MARK),
+ PINMUX_GPIO(GPIO_FN_JMCTCK, JMCTCK_MARK),
+ PINMUX_GPIO(GPIO_FN_JMCTMS, JMCTMS_MARK),
+ PINMUX_GPIO(GPIO_FN_JMCTDO, JMCTDO_MARK),
+ PINMUX_GPIO(GPIO_FN_JMCTDI, JMCTDI_MARK),
+ PINMUX_GPIO(GPIO_FN_JMCTRST, JMCTRST_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO1_CLK, SGPIO1_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO1_LOAD, SGPIO1_LOAD_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO1_DI, SGPIO1_DI_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO1_DO, SGPIO1_DO_MARK),
+ PINMUX_GPIO(GPIO_FN_SUB_CLKIN, SUB_CLKIN_MARK),
- /* PTO (mobule: SGPIO) */
+ /* PTO (mobule: SGPIO, SerMux) */
PINMUX_GPIO(GPIO_FN_SGPIO0_CLK, SGPIO0_CLK_MARK),
PINMUX_GPIO(GPIO_FN_SGPIO0_LOAD, SGPIO0_LOAD_MARK),
PINMUX_GPIO(GPIO_FN_SGPIO0_DI, SGPIO0_DI_MARK),
PINMUX_GPIO(GPIO_FN_SGPIO0_DO, SGPIO0_DO_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO1_CLK, SGPIO1_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO1_LOAD, SGPIO1_LOAD_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO1_DI, SGPIO1_DI_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO1_DO, SGPIO1_DO_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO2_CLK, SGPIO2_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO2_LOAD, SGPIO2_LOAD_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO2_DI, SGPIO2_DI_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO2_DO, SGPIO2_DO_MARK),
+ PINMUX_GPIO(GPIO_FN_COM1_TXD, COM1_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_COM1_RXD, COM1_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_COM1_RTS, COM1_RTS_MARK),
+ PINMUX_GPIO(GPIO_FN_COM1_CTS, COM1_CTS_MARK),
- /* PTP (mobule: JMC, SCIF234) */
- PINMUX_GPIO(GPIO_FN_JMCTCK, JMCTCK_MARK),
- PINMUX_GPIO(GPIO_FN_JMCTMS, JMCTMS_MARK),
- PINMUX_GPIO(GPIO_FN_JMCTDO, JMCTDO_MARK),
- PINMUX_GPIO(GPIO_FN_JMCTDI, JMCTDI_MARK),
- PINMUX_GPIO(GPIO_FN_JMCRST, JMCRST_MARK),
- PINMUX_GPIO(GPIO_FN_SCK4, SCK4_MARK),
- PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+ /* PTP (mobule: EVC, ADC) */
/* PTQ (mobule: LPC) */
PINMUX_GPIO(GPIO_FN_LAD3, LAD3_MARK),
@@ -1439,31 +1603,41 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_FN_SDA3, SDA3_MARK),
PINMUX_GPIO(GPIO_FN_SCL3, SCL3_MARK),
- /* PTT (mobule: SYSTEM, PWMX) */
- PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
+ /* PTT (mobule: PWMX, AUD) */
+ PINMUX_GPIO(GPIO_FN_PWMX7, PWMX7_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX6, PWMX6_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX5, PWMX5_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX4, PWMX4_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX3, PWMX3_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX2, PWMX2_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX1, PWMX1_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX0, PWMX0_MARK),
PINMUX_GPIO(GPIO_FN_AUDATA3, AUDATA3_MARK),
PINMUX_GPIO(GPIO_FN_AUDATA2, AUDATA2_MARK),
PINMUX_GPIO(GPIO_FN_AUDATA1, AUDATA1_MARK),
PINMUX_GPIO(GPIO_FN_AUDATA0, AUDATA0_MARK),
- PINMUX_GPIO(GPIO_FN_PWX7, PWX7_MARK),
- PINMUX_GPIO(GPIO_FN_PWX6, PWX6_MARK),
- PINMUX_GPIO(GPIO_FN_PWX5, PWX5_MARK),
- PINMUX_GPIO(GPIO_FN_PWX4, PWX4_MARK),
-
- /* PTU (mobule: LBSC, DMAC) */
- PINMUX_GPIO(GPIO_FN_CS6, CS6_MARK),
- PINMUX_GPIO(GPIO_FN_CS5, CS5_MARK),
- PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
- PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
- PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
- PINMUX_GPIO(GPIO_FN_WE0, WE0_MARK),
- PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
- PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
- PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
- /* PTV (mobule: LBSC, DMAC) */
+ /* PTU (mobule: LPC, APM) */
+ PINMUX_GPIO(GPIO_FN_LGPIO7, LGPIO7_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO6, LGPIO6_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO5, LGPIO5_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO4, LGPIO4_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO3, LGPIO3_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO2, LGPIO2_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO1, LGPIO1_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO0, LGPIO0_MARK),
+ PINMUX_GPIO(GPIO_FN_APMONCTL_O, APMONCTL_O_MARK),
+ PINMUX_GPIO(GPIO_FN_APMPWBTOUT_O, APMPWBTOUT_O_MARK),
+ PINMUX_GPIO(GPIO_FN_APMSCI_O, APMSCI_O_MARK),
+ PINMUX_GPIO(GPIO_FN_APMVDDON, APMVDDON_MARK),
+ PINMUX_GPIO(GPIO_FN_APMSLPBTN, APMSLPBTN_MARK),
+ PINMUX_GPIO(GPIO_FN_APMPWRBTN, APMPWRBTN_MARK),
+ PINMUX_GPIO(GPIO_FN_APMS5N, APMS5N_MARK),
+ PINMUX_GPIO(GPIO_FN_APMS3N, APMS3N_MARK),
+
+ /* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
@@ -1472,12 +1646,20 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
- PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
- PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
- PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+ PINMUX_GPIO(GPIO_FN_COM2_RI, COM2_RI_MARK),
+ PINMUX_GPIO(GPIO_FN_R_SPI_MOSI, R_SPI_MOSI_MARK),
+ PINMUX_GPIO(GPIO_FN_R_SPI_MISO, R_SPI_MISO_MARK),
+ PINMUX_GPIO(GPIO_FN_R_SPI_RSPCK, R_SPI_RSPCK_MARK),
+ PINMUX_GPIO(GPIO_FN_R_SPI_SSL0, R_SPI_SSL0_MARK),
+ PINMUX_GPIO(GPIO_FN_R_SPI_SSL1, R_SPI_SSL1_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT7, EVENT7_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT6, EVENT6_MARK),
+ PINMUX_GPIO(GPIO_FN_VBIOS_DI, VBIOS_DI_MARK),
+ PINMUX_GPIO(GPIO_FN_VBIOS_DO, VBIOS_DO_MARK),
+ PINMUX_GPIO(GPIO_FN_VBIOS_CLK, VBIOS_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_VBIOS_CS, VBIOS_CS_MARK),
- /* PTW (mobule: LBSC) */
+ /* PTW (mobule: LBSC, EVC, SCIF) */
PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
@@ -1487,6 +1669,14 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT5, EVENT5_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT4, EVENT4_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT3, EVENT3_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT2, EVENT2_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT1, EVENT1_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT0, EVENT0_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS4, CTS4_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS2, CTS2_MARK),
/* PTX (mobule: LBSC) */
PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
@@ -1497,6 +1687,10 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS2, RTS2_MARK),
+ PINMUX_GPIO(GPIO_FN_SIM_D, SIM_D_MARK),
+ PINMUX_GPIO(GPIO_FN_SIM_CLK, SIM_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIM_RST, SIM_RST_MARK),
/* PTY (mobule: LBSC) */
PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
@@ -1507,18 +1701,36 @@ static struct pinmux_gpio pinmux_gpios[] = {
PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
+
+ /* PTZ (mobule: eMMC, ONFI) */
+ PINMUX_GPIO(GPIO_FN_MMCDAT7, MMCDAT7_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT6, MMCDAT6_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT5, MMCDAT5_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT4, MMCDAT4_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT3, MMCDAT3_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT2, MMCDAT2_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT1, MMCDAT1_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT0, MMCDAT0_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ7, ON_DQ7_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ6, ON_DQ6_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ5, ON_DQ5_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ4, ON_DQ4_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ3, ON_DQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ2, ON_DQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ1, ON_DQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ0, ON_DQ0_MARK),
};
static struct pinmux_cfg_reg pinmux_config_regs[] = {
{ PINMUX_CFG_REG("PACR", 0xffec0000, 16, 2) {
- PTA7_FN, PTA7_OUT, PTA7_IN, 0,
- PTA6_FN, PTA6_OUT, PTA6_IN, 0,
- PTA5_FN, PTA5_OUT, PTA5_IN, 0,
- PTA4_FN, PTA4_OUT, PTA4_IN, 0,
- PTA3_FN, PTA3_OUT, PTA3_IN, 0,
- PTA2_FN, PTA2_OUT, PTA2_IN, 0,
- PTA1_FN, PTA1_OUT, PTA1_IN, 0,
- PTA0_FN, PTA0_OUT, PTA0_IN, 0 }
+ PTA7_FN, PTA7_OUT, PTA7_IN, PTA7_IN_PU,
+ PTA6_FN, PTA6_OUT, PTA6_IN, PTA6_IN_PU,
+ PTA5_FN, PTA5_OUT, PTA5_IN, PTA5_IN_PU,
+ PTA4_FN, PTA4_OUT, PTA4_IN, PTA4_IN_PU,
+ PTA3_FN, PTA3_OUT, PTA3_IN, PTA3_IN_PU,
+ PTA2_FN, PTA2_OUT, PTA2_IN, PTA2_IN_PU,
+ PTA1_FN, PTA1_OUT, PTA1_IN, PTA1_IN_PU,
+ PTA0_FN, PTA0_OUT, PTA0_IN, PTA0_IN_PU }
},
{ PINMUX_CFG_REG("PBCR", 0xffec0002, 16, 2) {
PTB7_FN, PTB7_OUT, PTB7_IN, 0,
@@ -1541,125 +1753,126 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
PTC0_FN, PTC0_OUT, PTC0_IN, 0 }
},
{ PINMUX_CFG_REG("PDCR", 0xffec0006, 16, 2) {
- PTD7_FN, PTD7_OUT, PTD7_IN, 0,
- PTD6_FN, PTD6_OUT, PTD6_IN, 0,
- PTD5_FN, PTD5_OUT, PTD5_IN, 0,
- PTD4_FN, PTD4_OUT, PTD4_IN, 0,
- PTD3_FN, PTD3_OUT, PTD3_IN, 0,
- PTD2_FN, PTD2_OUT, PTD2_IN, 0,
- PTD1_FN, PTD1_OUT, PTD1_IN, 0,
- PTD0_FN, PTD0_OUT, PTD0_IN, 0 }
+ PTD7_FN, PTD7_OUT, PTD7_IN, PTD7_IN_PU,
+ PTD6_FN, PTD6_OUT, PTD6_IN, PTD6_IN_PU,
+ PTD5_FN, PTD5_OUT, PTD5_IN, PTD5_IN_PU,
+ PTD4_FN, PTD4_OUT, PTD4_IN, PTD4_IN_PU,
+ PTD3_FN, PTD3_OUT, PTD3_IN, PTD3_IN_PU,
+ PTD2_FN, PTD2_OUT, PTD2_IN, PTD2_IN_PU,
+ PTD1_FN, PTD1_OUT, PTD1_IN, PTD1_IN_PU,
+ PTD0_FN, PTD0_OUT, PTD0_IN, PTD0_IN_PU }
},
{ PINMUX_CFG_REG("PECR", 0xffec0008, 16, 2) {
- PTE7_FN, PTE7_OUT, PTE7_IN, 0,
- PTE6_FN, PTE6_OUT, PTE6_IN, 0,
- PTE5_FN, PTE5_OUT, PTE5_IN, 0,
- PTE4_FN, PTE4_OUT, PTE4_IN, 0,
- PTE3_FN, PTE3_OUT, PTE3_IN, 0,
- PTE2_FN, PTE2_OUT, PTE2_IN, 0,
- PTE1_FN, PTE1_OUT, PTE1_IN, 0,
- PTE0_FN, PTE0_OUT, PTE0_IN, 0 }
+ PTE7_FN, PTE7_OUT, PTE7_IN, PTE7_IN_PU,
+ PTE6_FN, PTE6_OUT, PTE6_IN, PTE6_IN_PU,
+ PTE5_FN, PTE5_OUT, PTE5_IN, PTE5_IN_PU,
+ PTE4_FN, PTE4_OUT, PTE4_IN, PTE4_IN_PU,
+ PTE3_FN, PTE3_OUT, PTE3_IN, PTE3_IN_PU,
+ PTE2_FN, PTE2_OUT, PTE2_IN, PTE2_IN_PU,
+ PTE1_FN, PTE1_OUT, PTE1_IN, PTE1_IN_PU,
+ PTE0_FN, PTE0_OUT, PTE0_IN, PTE0_IN_PU }
},
{ PINMUX_CFG_REG("PFCR", 0xffec000a, 16, 2) {
- PTF7_FN, PTF7_OUT, PTF7_IN, 0,
- PTF6_FN, PTF6_OUT, PTF6_IN, 0,
- PTF5_FN, PTF5_OUT, PTF5_IN, 0,
- PTF4_FN, PTF4_OUT, PTF4_IN, 0,
- PTF3_FN, PTF3_OUT, PTF3_IN, 0,
- PTF2_FN, PTF2_OUT, PTF2_IN, 0,
- PTF1_FN, PTF1_OUT, PTF1_IN, 0,
- PTF0_FN, PTF0_OUT, PTF0_IN, 0 }
+ PTF7_FN, PTF7_OUT, PTF7_IN, PTF7_IN_PU,
+ PTF6_FN, PTF6_OUT, PTF6_IN, PTF6_IN_PU,
+ PTF5_FN, PTF5_OUT, PTF5_IN, PTF5_IN_PU,
+ PTF4_FN, PTF4_OUT, PTF4_IN, PTF4_IN_PU,
+ PTF3_FN, PTF3_OUT, PTF3_IN, PTF3_IN_PU,
+ PTF2_FN, PTF2_OUT, PTF2_IN, PTF2_IN_PU,
+ PTF1_FN, PTF1_OUT, PTF1_IN, PTF1_IN_PU,
+ PTF0_FN, PTF0_OUT, PTF0_IN, PTF0_IN_PU }
},
{ PINMUX_CFG_REG("PGCR", 0xffec000c, 16, 2) {
- PTG7_FN, PTG7_OUT, PTG7_IN, 0,
- PTG6_FN, PTG6_OUT, PTG6_IN, 0,
+ PTG7_FN, PTG7_OUT, PTG7_IN, PTG7_IN_PU ,
+ PTG6_FN, PTG6_OUT, PTG6_IN, PTG6_IN_PU ,
PTG5_FN, PTG5_OUT, PTG5_IN, 0,
- PTG4_FN, PTG4_OUT, PTG4_IN, 0,
+ PTG4_FN, PTG4_OUT, PTG4_IN, PTG4_IN_PU ,
PTG3_FN, PTG3_OUT, PTG3_IN, 0,
PTG2_FN, PTG2_OUT, PTG2_IN, 0,
PTG1_FN, PTG1_OUT, PTG1_IN, 0,
PTG0_FN, PTG0_OUT, PTG0_IN, 0 }
},
{ PINMUX_CFG_REG("PHCR", 0xffec000e, 16, 2) {
- PTH7_FN, PTH7_OUT, PTH7_IN, 0,
- PTH6_FN, PTH6_OUT, PTH6_IN, 0,
- PTH5_FN, PTH5_OUT, PTH5_IN, 0,
- PTH4_FN, PTH4_OUT, PTH4_IN, 0,
- PTH3_FN, PTH3_OUT, PTH3_IN, 0,
- PTH2_FN, PTH2_OUT, PTH2_IN, 0,
- PTH1_FN, PTH1_OUT, PTH1_IN, 0,
- PTH0_FN, PTH0_OUT, PTH0_IN, 0 }
+ PTH7_FN, PTH7_OUT, PTH7_IN, PTH7_IN_PU,
+ PTH6_FN, PTH6_OUT, PTH6_IN, PTH6_IN_PU,
+ PTH5_FN, PTH5_OUT, PTH5_IN, PTH5_IN_PU,
+ PTH4_FN, PTH4_OUT, PTH4_IN, PTH4_IN_PU,
+ PTH3_FN, PTH3_OUT, PTH3_IN, PTH3_IN_PU,
+ PTH2_FN, PTH2_OUT, PTH2_IN, PTH2_IN_PU,
+ PTH1_FN, PTH1_OUT, PTH1_IN, PTH1_IN_PU,
+ PTH0_FN, PTH0_OUT, PTH0_IN, PTH0_IN_PU }
},
{ PINMUX_CFG_REG("PICR", 0xffec0010, 16, 2) {
- PTI7_FN, PTI7_OUT, PTI7_IN, 0,
- PTI6_FN, PTI6_OUT, PTI6_IN, 0,
+ PTI7_FN, PTI7_OUT, PTI7_IN, PTI7_IN_PU,
+ PTI6_FN, PTI6_OUT, PTI6_IN, PTI6_IN_PU,
PTI5_FN, PTI5_OUT, PTI5_IN, 0,
- PTI4_FN, PTI4_OUT, PTI4_IN, 0,
- PTI3_FN, PTI3_OUT, PTI3_IN, 0,
- PTI2_FN, PTI2_OUT, PTI2_IN, 0,
- PTI1_FN, PTI1_OUT, PTI1_IN, 0,
- PTI0_FN, PTI0_OUT, PTI0_IN, 0 }
+ PTI4_FN, PTI4_OUT, PTI4_IN, PTI4_IN_PU,
+ PTI3_FN, PTI3_OUT, PTI3_IN, PTI3_IN_PU,
+ PTI2_FN, PTI2_OUT, PTI2_IN, PTI2_IN_PU,
+ PTI1_FN, PTI1_OUT, PTI1_IN, PTI1_IN_PU,
+ PTI0_FN, PTI0_OUT, PTI0_IN, PTI0_IN_PU }
},
{ PINMUX_CFG_REG("PJCR", 0xffec0012, 16, 2) {
- PTJ7_FN, PTJ7_OUT, PTJ7_IN, 0,
- PTJ6_FN, PTJ6_OUT, PTJ6_IN, 0,
- PTJ5_FN, PTJ5_OUT, PTJ5_IN, 0,
- PTJ4_FN, PTJ4_OUT, PTJ4_IN, 0,
- PTJ3_FN, PTJ3_OUT, PTJ3_IN, 0,
- PTJ2_FN, PTJ2_OUT, PTJ2_IN, 0,
- PTJ1_FN, PTJ1_OUT, PTJ1_IN, 0,
- PTJ0_FN, PTJ0_OUT, PTJ0_IN, 0 }
+ 0, 0, 0, 0, /* reserved: always set 1 */
+ PTJ6_FN, PTJ6_OUT, PTJ6_IN, PTJ6_IN_PU,
+ PTJ5_FN, PTJ5_OUT, PTJ5_IN, PTJ5_IN_PU,
+ PTJ4_FN, PTJ4_OUT, PTJ4_IN, PTJ4_IN_PU,
+ PTJ3_FN, PTJ3_OUT, PTJ3_IN, PTJ3_IN_PU,
+ PTJ2_FN, PTJ2_OUT, PTJ2_IN, PTJ2_IN_PU,
+ PTJ1_FN, PTJ1_OUT, PTJ1_IN, PTJ1_IN_PU,
+ PTJ0_FN, PTJ0_OUT, PTJ0_IN, PTJ0_IN_PU }
},
{ PINMUX_CFG_REG("PKCR", 0xffec0014, 16, 2) {
- PTK7_FN, PTK7_OUT, PTK7_IN, 0,
- PTK6_FN, PTK6_OUT, PTK6_IN, 0,
- PTK5_FN, PTK5_OUT, PTK5_IN, 0,
- PTK4_FN, PTK4_OUT, PTK4_IN, 0,
- PTK3_FN, PTK3_OUT, PTK3_IN, 0,
- PTK2_FN, PTK2_OUT, PTK2_IN, 0,
- PTK1_FN, PTK1_OUT, PTK1_IN, 0,
- PTK0_FN, PTK0_OUT, PTK0_IN, 0 }
+ PTK7_FN, PTK7_OUT, PTK7_IN, PTK7_IN_PU,
+ PTK6_FN, PTK6_OUT, PTK6_IN, PTK6_IN_PU,
+ PTK5_FN, PTK5_OUT, PTK5_IN, PTK5_IN_PU,
+ PTK4_FN, PTK4_OUT, PTK4_IN, PTK4_IN_PU,
+ PTK3_FN, PTK3_OUT, PTK3_IN, PTK3_IN_PU,
+ PTK2_FN, PTK2_OUT, PTK2_IN, PTK2_IN_PU,
+ PTK1_FN, PTK1_OUT, PTK1_IN, PTK1_IN_PU,
+ PTK0_FN, PTK0_OUT, PTK0_IN, PTK0_IN_PU }
},
{ PINMUX_CFG_REG("PLCR", 0xffec0016, 16, 2) {
- PTL7_FN, PTL7_OUT, PTL7_IN, 0,
- PTL6_FN, PTL6_OUT, PTL6_IN, 0,
- PTL5_FN, PTL5_OUT, PTL5_IN, 0,
- PTL4_FN, PTL4_OUT, PTL4_IN, 0,
- PTL3_FN, PTL3_OUT, PTL3_IN, 0,
- PTL2_FN, PTL2_OUT, PTL2_IN, 0,
- PTL1_FN, PTL1_OUT, PTL1_IN, 0,
- PTL0_FN, PTL0_OUT, PTL0_IN, 0 }
+ 0, 0, 0, 0, /* reserved: always set 1 */
+ PTL6_FN, PTL6_OUT, PTL6_IN, PTL6_IN_PU,
+ PTL5_FN, PTL5_OUT, PTL5_IN, PTL5_IN_PU,
+ PTL4_FN, PTL4_OUT, PTL4_IN, PTL4_IN_PU,
+ PTL3_FN, PTL3_OUT, PTL3_IN, PTL3_IN_PU,
+ PTL2_FN, PTL2_OUT, PTL2_IN, PTL2_IN_PU,
+ PTL1_FN, PTL1_OUT, PTL1_IN, PTL1_IN_PU,
+ PTL0_FN, PTL0_OUT, PTL0_IN, PTL0_IN_PU }
},
{ PINMUX_CFG_REG("PMCR", 0xffec0018, 16, 2) {
- 0, 0, 0, 0, /* reserved: always set 1 */
- PTM6_FN, PTM6_OUT, PTM6_IN, 0,
- PTM5_FN, PTM5_OUT, PTM5_IN, 0,
- PTM4_FN, PTM4_OUT, PTM4_IN, 0,
+ PTM7_FN, PTM7_OUT, PTM7_IN, PTM7_IN_PU,
+ PTM6_FN, PTM6_OUT, PTM6_IN, PTM6_IN_PU,
+ PTM5_FN, PTM5_OUT, PTM5_IN, PTM5_IN_PU,
+ PTM4_FN, PTM4_OUT, PTM4_IN, PTM4_IN_PU,
PTM3_FN, PTM3_OUT, PTM3_IN, 0,
PTM2_FN, PTM2_OUT, PTM2_IN, 0,
PTM1_FN, PTM1_OUT, PTM1_IN, 0,
PTM0_FN, PTM0_OUT, PTM0_IN, 0 }
},
{ PINMUX_CFG_REG("PNCR", 0xffec001a, 16, 2) {
- PTN7_FN, PTN7_OUT, PTN7_IN, 0,
+ 0, 0, 0, 0, /* reserved: always set 1 */
PTN6_FN, PTN6_OUT, PTN6_IN, 0,
PTN5_FN, PTN5_OUT, PTN5_IN, 0,
- PTN4_FN, PTN4_OUT, PTN4_IN, 0,
- PTN3_FN, PTN3_OUT, PTN3_IN, 0,
- PTN2_FN, PTN2_OUT, PTN2_IN, 0,
- PTN1_FN, PTN1_OUT, PTN1_IN, 0,
- PTN0_FN, PTN0_OUT, PTN0_IN, 0 }
+ PTN4_FN, PTN4_OUT, PTN4_IN, PTN4_IN_PU,
+ PTN3_FN, PTN3_OUT, PTN3_IN, PTN3_IN_PU,
+ PTN2_FN, PTN2_OUT, PTN2_IN, PTN2_IN_PU,
+ PTN1_FN, PTN1_OUT, PTN1_IN, PTN1_IN_PU,
+ PTN0_FN, PTN0_OUT, PTN0_IN, PTN0_IN_PU }
},
{ PINMUX_CFG_REG("POCR", 0xffec001c, 16, 2) {
- PTO7_FN, PTO7_OUT, PTO7_IN, 0,
- PTO6_FN, PTO6_OUT, PTO6_IN, 0,
- PTO5_FN, PTO5_OUT, PTO5_IN, 0,
- PTO4_FN, PTO4_OUT, PTO4_IN, 0,
- PTO3_FN, PTO3_OUT, PTO3_IN, 0,
- PTO2_FN, PTO2_OUT, PTO2_IN, 0,
- PTO1_FN, PTO1_OUT, PTO1_IN, 0,
- PTO0_FN, PTO0_OUT, PTO0_IN, 0 }
+ PTO7_FN, PTO7_OUT, PTO7_IN, PTO7_IN_PU,
+ PTO6_FN, PTO6_OUT, PTO6_IN, PTO6_IN_PU,
+ PTO5_FN, PTO5_OUT, PTO5_IN, PTO5_IN_PU,
+ PTO4_FN, PTO4_OUT, PTO4_IN, PTO4_IN_PU,
+ PTO3_FN, PTO3_OUT, PTO3_IN, PTO3_IN_PU,
+ PTO2_FN, PTO2_OUT, PTO2_IN, PTO2_IN_PU,
+ PTO1_FN, PTO1_OUT, PTO1_IN, PTO1_IN_PU,
+ PTO0_FN, PTO0_OUT, PTO0_IN, PTO0_IN_PU }
},
+#if 0 /* FIXME: Remove it? */
{ PINMUX_CFG_REG("PPCR", 0xffec001e, 16, 2) {
0, 0, 0, 0, /* reserved: always set 1 */
PTP6_FN, PTP6_OUT, PTP6_IN, 0,
@@ -1670,6 +1883,7 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
PTP1_FN, PTP1_OUT, PTP1_IN, 0,
PTP0_FN, PTP0_OUT, PTP0_IN, 0 }
},
+#endif
{ PINMUX_CFG_REG("PQCR", 0xffec0020, 16, 2) {
0, 0, 0, 0, /* reserved: always set 1 */
PTQ6_FN, PTQ6_OUT, PTQ6_IN, 0,
@@ -1701,14 +1915,14 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
PTS0_FN, PTS0_OUT, PTS0_IN, 0 }
},
{ PINMUX_CFG_REG("PTCR", 0xffec0026, 16, 2) {
- 0, 0, 0, 0, /* reserved: always set 1 */
- 0, 0, 0, 0, /* reserved: always set 1 */
- PTT5_FN, PTT5_OUT, PTT5_IN, 0,
- PTT4_FN, PTT4_OUT, PTT4_IN, 0,
- PTT3_FN, PTT3_OUT, PTT3_IN, 0,
- PTT2_FN, PTT2_OUT, PTT2_IN, 0,
- PTT1_FN, PTT1_OUT, PTT1_IN, 0,
- PTT0_FN, PTT0_OUT, PTT0_IN, 0 }
+ PTT7_FN, PTT7_OUT, PTT7_IN, PTO7_IN_PU,
+ PTT6_FN, PTT6_OUT, PTT6_IN, PTO6_IN_PU,
+ PTT5_FN, PTT5_OUT, PTT5_IN, PTO5_IN_PU,
+ PTT4_FN, PTT4_OUT, PTT4_IN, PTO4_IN_PU,
+ PTT3_FN, PTT3_OUT, PTT3_IN, PTO3_IN_PU,
+ PTT2_FN, PTT2_OUT, PTT2_IN, PTO2_IN_PU,
+ PTT1_FN, PTT1_OUT, PTT1_IN, PTO1_IN_PU,
+ PTT0_FN, PTT0_OUT, PTT0_IN, PTO0_IN_PU }
},
{ PINMUX_CFG_REG("PUCR", 0xffec0028, 16, 2) {
PTU7_FN, PTU7_OUT, PTU7_IN, PTU7_IN_PU,
@@ -1727,16 +1941,16 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
PTV4_FN, PTV4_OUT, PTV4_IN, PTV4_IN_PU,
PTV3_FN, PTV3_OUT, PTV3_IN, PTV3_IN_PU,
PTV2_FN, PTV2_OUT, PTV2_IN, PTV2_IN_PU,
- PTV1_FN, PTV1_OUT, PTV1_IN, PTV1_IN_PU,
- PTV0_FN, PTV0_OUT, PTV0_IN, PTV0_IN_PU }
+ PTV1_FN, PTV1_OUT, PTV1_IN, 0,
+ PTV0_FN, PTV0_OUT, PTV0_IN, 0 }
},
{ PINMUX_CFG_REG("PWCR", 0xffec002c, 16, 2) {
- PTW7_FN, PTW7_OUT, PTW7_IN, PTW7_IN_PU,
- PTW6_FN, PTW6_OUT, PTW6_IN, PTW6_IN_PU,
- PTW5_FN, PTW5_OUT, PTW5_IN, PTW5_IN_PU,
- PTW4_FN, PTW4_OUT, PTW4_IN, PTW4_IN_PU,
- PTW3_FN, PTW3_OUT, PTW3_IN, PTW3_IN_PU,
- PTW2_FN, PTW2_OUT, PTW2_IN, PTW2_IN_PU,
+ PTW7_FN, PTW7_OUT, PTW7_IN, 0,
+ PTW6_FN, PTW6_OUT, PTW6_IN, 0,
+ PTW5_FN, PTW5_OUT, PTW5_IN, 0,
+ PTW4_FN, PTW4_OUT, PTW4_IN, 0,
+ PTW3_FN, PTW3_OUT, PTW3_IN, 0,
+ PTW2_FN, PTW2_OUT, PTW2_IN, 0,
PTW1_FN, PTW1_OUT, PTW1_IN, PTW1_IN_PU,
PTW0_FN, PTW0_OUT, PTW0_IN, PTW0_IN_PU }
},
@@ -1761,32 +1975,32 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
PTY0_FN, PTY0_OUT, PTY0_IN, PTY0_IN_PU }
},
{ PINMUX_CFG_REG("PZCR", 0xffec0032, 16, 2) {
- 0, PTZ7_OUT, PTZ7_IN, 0,
- 0, PTZ6_OUT, PTZ6_IN, 0,
- 0, PTZ5_OUT, PTZ5_IN, 0,
- 0, PTZ4_OUT, PTZ4_IN, 0,
- 0, PTZ3_OUT, PTZ3_IN, 0,
- 0, PTZ2_OUT, PTZ2_IN, 0,
- 0, PTZ1_OUT, PTZ1_IN, 0,
- 0, PTZ0_OUT, PTZ0_IN, 0 }
+ PTZ7_FN, PTZ7_OUT, PTZ7_IN, 0,
+ PTZ6_FN, PTZ6_OUT, PTZ6_IN, 0,
+ PTZ5_FN, PTZ5_OUT, PTZ5_IN, 0,
+ PTZ4_FN, PTZ4_OUT, PTZ4_IN, 0,
+ PTZ3_FN, PTZ3_OUT, PTZ3_IN, 0,
+ PTZ2_FN, PTZ2_OUT, PTZ2_IN, 0,
+ PTZ1_FN, PTZ1_OUT, PTZ1_IN, 0,
+ PTZ0_FN, PTZ0_OUT, PTZ0_IN, 0 }
},
{ PINMUX_CFG_REG("PSEL0", 0xffec0070, 16, 1) {
- PS0_15_FN3, PS0_15_FN1,
- PS0_14_FN3, PS0_14_FN1,
- PS0_13_FN3, PS0_13_FN1,
- PS0_12_FN3, PS0_12_FN1,
- 0, 0,
- 0, 0,
+ PS0_15_FN1, PS0_15_FN2,
+ PS0_14_FN1, PS0_14_FN2,
+ PS0_13_FN1, PS0_13_FN2,
+ PS0_12_FN1, PS0_12_FN2,
+ PS0_11_FN1, PS0_11_FN2,
+ PS0_10_FN1, PS0_10_FN2,
+ PS0_9_FN1, PS0_9_FN2,
+ PS0_8_FN1, PS0_8_FN2,
+ PS0_7_FN1, PS0_7_FN2,
+ PS0_6_FN1, PS0_6_FN2,
+ PS0_5_FN1, PS0_5_FN2,
+ PS0_4_FN1, PS0_4_FN2,
+ PS0_3_FN1, PS0_3_FN2,
+ PS0_2_FN1, PS0_2_FN2,
0, 0,
- 0, 0,
- PS0_7_FN2, PS0_7_FN1,
- PS0_6_FN2, PS0_6_FN1,
- PS0_5_FN2, PS0_5_FN1,
- PS0_4_FN2, PS0_4_FN1,
- PS0_3_FN2, PS0_3_FN1,
- PS0_2_FN2, PS0_2_FN1,
- PS0_1_FN2, PS0_1_FN1,
0, 0, }
},
{ PINMUX_CFG_REG("PSEL1", 0xffec0072, 16, 1) {
@@ -1795,73 +2009,136 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
0, 0,
0, 0,
0, 0,
+ PS1_10_FN1, PS1_10_FN2,
+ PS1_9_FN1, PS1_9_FN2,
+ PS1_8_FN1, PS1_8_FN2,
0, 0,
0, 0,
0, 0,
- PS1_7_FN1, PS1_7_FN3,
- PS1_6_FN1, PS1_6_FN3,
- 0, 0,
- 0, 0,
0, 0,
0, 0,
+ PS1_2_FN1, PS1_2_FN2,
0, 0,
0, 0, }
},
{ PINMUX_CFG_REG("PSEL2", 0xffec0074, 16, 1) {
0, 0,
0, 0,
- PS2_13_FN3, PS2_13_FN1,
- PS2_12_FN3, PS2_12_FN1,
+ PS2_13_FN1, PS2_13_FN2,
+ PS2_12_FN1, PS2_12_FN2,
0, 0,
0, 0,
0, 0,
0, 0,
+ PS2_7_FN1, PS2_7_FN2,
+ PS2_6_FN1, PS2_6_FN2,
+ PS2_5_FN1, PS2_5_FN2,
+ PS2_4_FN1, PS2_4_FN2,
0, 0,
+ PS2_2_FN1, PS2_2_FN2,
0, 0,
+ 0, 0, }
+ },
+ { PINMUX_CFG_REG("PSEL3", 0xffec0076, 16, 1) {
+ PS3_15_FN1, PS3_15_FN2,
+ PS3_14_FN1, PS3_14_FN2,
+ PS3_13_FN1, PS3_13_FN2,
+ PS3_12_FN1, PS3_12_FN2,
+ PS3_11_FN1, PS3_11_FN2,
+ PS3_10_FN1, PS3_10_FN2,
+ PS3_9_FN1, PS3_9_FN2,
+ PS3_8_FN1, PS3_8_FN2,
+ PS3_7_FN1, PS3_7_FN2,
0, 0,
0, 0,
0, 0,
0, 0,
- PS2_1_FN1, PS2_1_FN2,
- PS2_0_FN1, PS2_0_FN2, }
+ PS3_2_FN1, PS3_2_FN2,
+ PS3_1_FN1, PS3_1_FN2,
+ 0, 0, }
},
+
{ PINMUX_CFG_REG("PSEL4", 0xffec0078, 16, 1) {
- PS4_15_FN2, PS4_15_FN1,
- PS4_14_FN2, PS4_14_FN1,
- PS4_13_FN2, PS4_13_FN1,
- PS4_12_FN2, PS4_12_FN1,
- PS4_11_FN2, PS4_11_FN1,
- PS4_10_FN2, PS4_10_FN1,
- PS4_9_FN2, PS4_9_FN1,
0, 0,
+ PS4_14_FN1, PS4_14_FN2,
+ PS4_13_FN1, PS4_13_FN2,
+ PS4_12_FN1, PS4_12_FN2,
0, 0,
+ PS4_10_FN1, PS4_10_FN2,
+ PS4_9_FN1, PS4_9_FN2,
+ PS4_8_FN1, PS4_8_FN2,
0, 0,
0, 0,
0, 0,
- PS4_3_FN2, PS4_3_FN1,
- PS4_2_FN2, PS4_2_FN1,
- PS4_1_FN2, PS4_1_FN1,
- PS4_0_FN2, PS4_0_FN1, }
+ PS4_4_FN1, PS4_4_FN2,
+ PS4_3_FN1, PS4_3_FN2,
+ PS4_2_FN1, PS4_2_FN2,
+ PS4_1_FN1, PS4_1_FN2,
+ PS4_0_FN1, PS4_0_FN2, }
},
{ PINMUX_CFG_REG("PSEL5", 0xffec007a, 16, 1) {
0, 0,
0, 0,
0, 0,
0, 0,
- 0, 0,
- 0, 0,
+ PS5_11_FN1, PS5_11_FN2,
+ PS5_10_FN1, PS5_10_FN2,
PS5_9_FN1, PS5_9_FN2,
PS5_8_FN1, PS5_8_FN2,
PS5_7_FN1, PS5_7_FN2,
PS5_6_FN1, PS5_6_FN2,
PS5_5_FN1, PS5_5_FN2,
+ PS5_4_FN1, PS5_4_FN2,
+ PS5_3_FN1, PS5_3_FN2,
+ PS5_2_FN1, PS5_2_FN2,
+ 0, 0,
+ 0, 0, }
+ },
+ { PINMUX_CFG_REG("PSEL6", 0xffec007c, 16, 1) {
+ PS6_15_FN1, PS6_15_FN2,
+ PS6_14_FN1, PS6_14_FN2,
+ PS6_13_FN1, PS6_13_FN2,
+ PS6_12_FN1, PS6_12_FN2,
+ PS6_11_FN1, PS6_11_FN2,
+ PS6_10_FN1, PS6_10_FN2,
+ PS6_9_FN1, PS6_9_FN2,
+ PS6_8_FN1, PS6_8_FN2,
+ PS6_7_FN1, PS6_7_FN2,
+ PS6_6_FN1, PS6_6_FN2,
+ PS6_5_FN1, PS6_5_FN2,
+ PS6_4_FN1, PS6_4_FN2,
+ PS6_3_FN1, PS6_3_FN2,
+ PS6_2_FN1, PS6_2_FN2,
+ PS6_1_FN1, PS6_1_FN2,
+ PS6_0_FN1, PS6_0_FN2, }
+ },
+ { PINMUX_CFG_REG("PSEL7", 0xffec0082, 16, 1) {
+ PS7_15_FN1, PS7_15_FN2,
+ PS7_14_FN1, PS7_14_FN2,
+ PS7_13_FN1, PS7_13_FN2,
+ PS7_12_FN1, PS7_12_FN2,
+ PS7_11_FN1, PS7_11_FN2,
+ PS7_10_FN1, PS7_10_FN2,
+ PS7_9_FN1, PS7_9_FN2,
+ PS7_8_FN1, PS7_8_FN2,
+ PS7_7_FN1, PS7_7_FN2,
+ PS7_6_FN1, PS7_6_FN2,
+ PS7_5_FN1, PS7_5_FN2,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0, }
},
- { PINMUX_CFG_REG("PSEL6", 0xffec007c, 16, 1) {
+ { PINMUX_CFG_REG("PSEL8", 0xffec0084, 16, 1) {
+ PS8_15_FN1, PS8_15_FN2,
+ PS8_14_FN1, PS8_14_FN2,
+ PS8_13_FN1, PS8_13_FN2,
+ PS8_12_FN1, PS8_12_FN2,
+ PS8_11_FN1, PS8_11_FN2,
+ PS8_10_FN1, PS8_10_FN2,
+ PS8_9_FN1, PS8_9_FN2,
+ PS8_8_FN1, PS8_8_FN2,
0, 0,
0, 0,
0, 0,
@@ -1869,15 +2146,7 @@ static struct pinmux_cfg_reg pinmux_config_regs[] = {
0, 0,
0, 0,
0, 0,
- 0, 0,
- PS6_7_FN_AN, PS6_7_FN_EV,
- PS6_6_FN_AN, PS6_6_FN_EV,
- PS6_5_FN_AN, PS6_5_FN_EV,
- PS6_4_FN_AN, PS6_4_FN_EV,
- PS6_3_FN_AN, PS6_3_FN_EV,
- PS6_2_FN_AN, PS6_2_FN_EV,
- PS6_1_FN_AN, PS6_1_FN_EV,
- PS6_0_FN_AN, PS6_0_FN_EV, }
+ 0, 0, }
},
{}
};
@@ -1920,7 +2189,7 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
PTI3_DATA, PTI2_DATA, PTI1_DATA, PTI0_DATA }
},
{ PINMUX_DATA_REG("PJDR", 0xffec0046, 8) {
- PTJ7_DATA, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
+ 0, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA }
},
{ PINMUX_DATA_REG("PKDR", 0xffec0048, 8) {
@@ -1928,15 +2197,15 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA }
},
{ PINMUX_DATA_REG("PLDR", 0xffec004a, 8) {
- PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+ 0, PTL6_DATA, PTL5_DATA, PTL4_DATA,
PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA }
},
{ PINMUX_DATA_REG("PMDR", 0xffec004c, 8) {
- 0, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+ PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA }
},
{ PINMUX_DATA_REG("PNDR", 0xffec004e, 8) {
- PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+ 0, PTN6_DATA, PTN5_DATA, PTN4_DATA,
PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA }
},
{ PINMUX_DATA_REG("PODR", 0xffec0050, 8) {
@@ -1944,7 +2213,7 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
PTO3_DATA, PTO2_DATA, PTO1_DATA, PTO0_DATA }
},
{ PINMUX_DATA_REG("PPDR", 0xffec0052, 8) {
- 0, PTP6_DATA, PTP5_DATA, PTP4_DATA,
+ PTP7_DATA, PTP6_DATA, PTP5_DATA, PTP4_DATA,
PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA }
},
{ PINMUX_DATA_REG("PQDR", 0xffec0054, 8) {
@@ -1960,7 +2229,7 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA }
},
{ PINMUX_DATA_REG("PTDR", 0xffec005a, 8) {
- 0, 0, PTT5_DATA, PTT4_DATA,
+ PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA }
},
{ PINMUX_DATA_REG("PUDR", 0xffec005c, 8) {
@@ -2000,8 +2269,8 @@ static struct pinmux_info sh7757_pinmux_info = {
.mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
.function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
- .first_gpio = GPIO_PTA7,
- .last_gpio = GPIO_FN_D0,
+ .first_gpio = GPIO_PTA0,
+ .last_gpio = GPIO_FN_ON_DQ0,
.gpios = pinmux_gpios,
.cfg_regs = pinmux_config_regs,
@@ -2015,5 +2284,4 @@ static int __init plat_pinmux_setup(void)
{
return register_pinmux(&sh7757_pinmux_info);
}
-
arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c b/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c
new file mode 100644
index 000000000000..aaa5338abbff
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c
@@ -0,0 +1,587 @@
+/*
+ * SH-X3 prototype CPU pinmux
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/shx3.h>
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+ PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+ PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+
+ PH5_DATA, PH4_DATA,
+ PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ PA7_IN, PA6_IN, PA5_IN, PA4_IN,
+ PA3_IN, PA2_IN, PA1_IN, PA0_IN,
+ PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+ PB3_IN, PB2_IN, PB1_IN, PB0_IN,
+ PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+ PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+ PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+ PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+ PE7_IN, PE6_IN, PE5_IN, PE4_IN,
+ PE3_IN, PE2_IN, PE1_IN, PE0_IN,
+ PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+ PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+ PG7_IN, PG6_IN, PG5_IN, PG4_IN,
+ PG3_IN, PG2_IN, PG1_IN, PG0_IN,
+
+ PH5_IN, PH4_IN,
+ PH3_IN, PH2_IN, PH1_IN, PH0_IN,
+ PINMUX_INPUT_END,
+
+ PINMUX_INPUT_PULLUP_BEGIN,
+ PA7_IN_PU, PA6_IN_PU, PA5_IN_PU, PA4_IN_PU,
+ PA3_IN_PU, PA2_IN_PU, PA1_IN_PU, PA0_IN_PU,
+ PB7_IN_PU, PB6_IN_PU, PB5_IN_PU, PB4_IN_PU,
+ PB3_IN_PU, PB2_IN_PU, PB1_IN_PU, PB0_IN_PU,
+ PC7_IN_PU, PC6_IN_PU, PC5_IN_PU, PC4_IN_PU,
+ PC3_IN_PU, PC2_IN_PU, PC1_IN_PU, PC0_IN_PU,
+ PD7_IN_PU, PD6_IN_PU, PD5_IN_PU, PD4_IN_PU,
+ PD3_IN_PU, PD2_IN_PU, PD1_IN_PU, PD0_IN_PU,
+ PE7_IN_PU, PE6_IN_PU, PE5_IN_PU, PE4_IN_PU,
+ PE3_IN_PU, PE2_IN_PU, PE1_IN_PU, PE0_IN_PU,
+ PF7_IN_PU, PF6_IN_PU, PF5_IN_PU, PF4_IN_PU,
+ PF3_IN_PU, PF2_IN_PU, PF1_IN_PU, PF0_IN_PU,
+ PG7_IN_PU, PG6_IN_PU, PG5_IN_PU, PG4_IN_PU,
+ PG3_IN_PU, PG2_IN_PU, PG1_IN_PU, PG0_IN_PU,
+
+ PH5_IN_PU, PH4_IN_PU,
+ PH3_IN_PU, PH2_IN_PU, PH1_IN_PU, PH0_IN_PU,
+ PINMUX_INPUT_PULLUP_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ PA7_OUT, PA6_OUT, PA5_OUT, PA4_OUT,
+ PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
+ PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+ PB3_OUT, PB2_OUT, PB1_OUT, PB0_OUT,
+ PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+ PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+ PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+ PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+ PE7_OUT, PE6_OUT, PE5_OUT, PE4_OUT,
+ PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
+ PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+ PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+ PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
+ PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
+
+ PH5_OUT, PH4_OUT,
+ PH3_OUT, PH2_OUT, PH1_OUT, PH0_OUT,
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ PA7_FN, PA6_FN, PA5_FN, PA4_FN,
+ PA3_FN, PA2_FN, PA1_FN, PA0_FN,
+ PB7_FN, PB6_FN, PB5_FN, PB4_FN,
+ PB3_FN, PB2_FN, PB1_FN, PB0_FN,
+ PC7_FN, PC6_FN, PC5_FN, PC4_FN,
+ PC3_FN, PC2_FN, PC1_FN, PC0_FN,
+ PD7_FN, PD6_FN, PD5_FN, PD4_FN,
+ PD3_FN, PD2_FN, PD1_FN, PD0_FN,
+ PE7_FN, PE6_FN, PE5_FN, PE4_FN,
+ PE3_FN, PE2_FN, PE1_FN, PE0_FN,
+ PF7_FN, PF6_FN, PF5_FN, PF4_FN,
+ PF3_FN, PF2_FN, PF1_FN, PF0_FN,
+ PG7_FN, PG6_FN, PG5_FN, PG4_FN,
+ PG3_FN, PG2_FN, PG1_FN, PG0_FN,
+
+ PH5_FN, PH4_FN,
+ PH3_FN, PH2_FN, PH1_FN, PH0_FN,
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+
+ D31_MARK, D30_MARK, D29_MARK, D28_MARK, D27_MARK, D26_MARK,
+ D25_MARK, D24_MARK, D23_MARK, D22_MARK, D21_MARK, D20_MARK,
+ D19_MARK, D18_MARK, D17_MARK, D16_MARK,
+
+ BACK_MARK, BREQ_MARK,
+ WE3_MARK, WE2_MARK,
+ CS6_MARK, CS5_MARK, CS4_MARK,
+ CLKOUTENB_MARK,
+
+ DACK3_MARK, DACK2_MARK, DACK1_MARK, DACK0_MARK,
+ DREQ3_MARK, DREQ2_MARK, DREQ1_MARK, DREQ0_MARK,
+
+ IRQ3_MARK, IRQ2_MARK, IRQ1_MARK, IRQ0_MARK,
+
+ DRAK3_MARK, DRAK2_MARK, DRAK1_MARK, DRAK0_MARK,
+
+ SCK3_MARK, SCK2_MARK, SCK1_MARK, SCK0_MARK,
+ IRL3_MARK, IRL2_MARK, IRL1_MARK, IRL0_MARK,
+ TXD3_MARK, TXD2_MARK, TXD1_MARK, TXD0_MARK,
+ RXD3_MARK, RXD2_MARK, RXD1_MARK, RXD0_MARK,
+
+ CE2B_MARK, CE2A_MARK, IOIS16_MARK,
+ STATUS1_MARK, STATUS0_MARK,
+
+ IRQOUT_MARK,
+
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t shx3_pinmux_data[] = {
+
+ /* PA GPIO */
+ PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT, PA7_IN_PU),
+ PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT, PA6_IN_PU),
+ PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT, PA5_IN_PU),
+ PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT, PA4_IN_PU),
+ PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT, PA3_IN_PU),
+ PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT, PA2_IN_PU),
+ PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT, PA1_IN_PU),
+ PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT, PA0_IN_PU),
+
+ /* PB GPIO */
+ PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT, PB7_IN_PU),
+ PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT, PB6_IN_PU),
+ PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT, PB5_IN_PU),
+ PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT, PB4_IN_PU),
+ PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT, PB3_IN_PU),
+ PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT, PB2_IN_PU),
+ PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT, PB1_IN_PU),
+ PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT, PB0_IN_PU),
+
+ /* PC GPIO */
+ PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT, PC7_IN_PU),
+ PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT, PC6_IN_PU),
+ PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT, PC5_IN_PU),
+ PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT, PC4_IN_PU),
+ PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT, PC3_IN_PU),
+ PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT, PC2_IN_PU),
+ PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT, PC1_IN_PU),
+ PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT, PC0_IN_PU),
+
+ /* PD GPIO */
+ PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT, PD7_IN_PU),
+ PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT, PD6_IN_PU),
+ PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT, PD5_IN_PU),
+ PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT, PD4_IN_PU),
+ PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT, PD3_IN_PU),
+ PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT, PD2_IN_PU),
+ PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT, PD1_IN_PU),
+ PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT, PD0_IN_PU),
+
+ /* PE GPIO */
+ PINMUX_DATA(PE7_DATA, PE7_IN, PE7_OUT, PE7_IN_PU),
+ PINMUX_DATA(PE6_DATA, PE6_IN, PE6_OUT, PE6_IN_PU),
+ PINMUX_DATA(PE5_DATA, PE5_IN, PE5_OUT, PE5_IN_PU),
+ PINMUX_DATA(PE4_DATA, PE4_IN, PE4_OUT, PE4_IN_PU),
+ PINMUX_DATA(PE3_DATA, PE3_IN, PE3_OUT, PE3_IN_PU),
+ PINMUX_DATA(PE2_DATA, PE2_IN, PE2_OUT, PE2_IN_PU),
+ PINMUX_DATA(PE1_DATA, PE1_IN, PE1_OUT, PE1_IN_PU),
+ PINMUX_DATA(PE0_DATA, PE0_IN, PE0_OUT, PE0_IN_PU),
+
+ /* PF GPIO */
+ PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT, PF7_IN_PU),
+ PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT, PF6_IN_PU),
+ PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT, PF5_IN_PU),
+ PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT, PF4_IN_PU),
+ PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT, PF3_IN_PU),
+ PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT, PF2_IN_PU),
+ PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT, PF1_IN_PU),
+ PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT, PF0_IN_PU),
+
+ /* PG GPIO */
+ PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT, PG7_IN_PU),
+ PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT, PG6_IN_PU),
+ PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT, PG5_IN_PU),
+ PINMUX_DATA(PG4_DATA, PG4_IN, PG4_OUT, PG4_IN_PU),
+ PINMUX_DATA(PG3_DATA, PG3_IN, PG3_OUT, PG3_IN_PU),
+ PINMUX_DATA(PG2_DATA, PG2_IN, PG2_OUT, PG2_IN_PU),
+ PINMUX_DATA(PG1_DATA, PG1_IN, PG1_OUT, PG1_IN_PU),
+ PINMUX_DATA(PG0_DATA, PG0_IN, PG0_OUT, PG0_IN_PU),
+
+ /* PH GPIO */
+ PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT, PH5_IN_PU),
+ PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT, PH4_IN_PU),
+ PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT, PH3_IN_PU),
+ PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT, PH2_IN_PU),
+ PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT, PH1_IN_PU),
+ PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT, PH0_IN_PU),
+
+ /* PA FN */
+ PINMUX_DATA(D31_MARK, PA7_FN),
+ PINMUX_DATA(D30_MARK, PA6_FN),
+ PINMUX_DATA(D29_MARK, PA5_FN),
+ PINMUX_DATA(D28_MARK, PA4_FN),
+ PINMUX_DATA(D27_MARK, PA3_FN),
+ PINMUX_DATA(D26_MARK, PA2_FN),
+ PINMUX_DATA(D25_MARK, PA1_FN),
+ PINMUX_DATA(D24_MARK, PA0_FN),
+
+ /* PB FN */
+ PINMUX_DATA(D23_MARK, PB7_FN),
+ PINMUX_DATA(D22_MARK, PB6_FN),
+ PINMUX_DATA(D21_MARK, PB5_FN),
+ PINMUX_DATA(D20_MARK, PB4_FN),
+ PINMUX_DATA(D19_MARK, PB3_FN),
+ PINMUX_DATA(D18_MARK, PB2_FN),
+ PINMUX_DATA(D17_MARK, PB1_FN),
+ PINMUX_DATA(D16_MARK, PB0_FN),
+
+ /* PC FN */
+ PINMUX_DATA(BACK_MARK, PC7_FN),
+ PINMUX_DATA(BREQ_MARK, PC6_FN),
+ PINMUX_DATA(WE3_MARK, PC5_FN),
+ PINMUX_DATA(WE2_MARK, PC4_FN),
+ PINMUX_DATA(CS6_MARK, PC3_FN),
+ PINMUX_DATA(CS5_MARK, PC2_FN),
+ PINMUX_DATA(CS4_MARK, PC1_FN),
+ PINMUX_DATA(CLKOUTENB_MARK, PC0_FN),
+
+ /* PD FN */
+ PINMUX_DATA(DACK3_MARK, PD7_FN),
+ PINMUX_DATA(DACK2_MARK, PD6_FN),
+ PINMUX_DATA(DACK1_MARK, PD5_FN),
+ PINMUX_DATA(DACK0_MARK, PD4_FN),
+ PINMUX_DATA(DREQ3_MARK, PD3_FN),
+ PINMUX_DATA(DREQ2_MARK, PD2_FN),
+ PINMUX_DATA(DREQ1_MARK, PD1_FN),
+ PINMUX_DATA(DREQ0_MARK, PD0_FN),
+
+ /* PE FN */
+ PINMUX_DATA(IRQ3_MARK, PE7_FN),
+ PINMUX_DATA(IRQ2_MARK, PE6_FN),
+ PINMUX_DATA(IRQ1_MARK, PE5_FN),
+ PINMUX_DATA(IRQ0_MARK, PE4_FN),
+ PINMUX_DATA(DRAK3_MARK, PE3_FN),
+ PINMUX_DATA(DRAK2_MARK, PE2_FN),
+ PINMUX_DATA(DRAK1_MARK, PE1_FN),
+ PINMUX_DATA(DRAK0_MARK, PE0_FN),
+
+ /* PF FN */
+ PINMUX_DATA(SCK3_MARK, PF7_FN),
+ PINMUX_DATA(SCK2_MARK, PF6_FN),
+ PINMUX_DATA(SCK1_MARK, PF5_FN),
+ PINMUX_DATA(SCK0_MARK, PF4_FN),
+ PINMUX_DATA(IRL3_MARK, PF3_FN),
+ PINMUX_DATA(IRL2_MARK, PF2_FN),
+ PINMUX_DATA(IRL1_MARK, PF1_FN),
+ PINMUX_DATA(IRL0_MARK, PF0_FN),
+
+ /* PG FN */
+ PINMUX_DATA(TXD3_MARK, PG7_FN),
+ PINMUX_DATA(TXD2_MARK, PG6_FN),
+ PINMUX_DATA(TXD1_MARK, PG5_FN),
+ PINMUX_DATA(TXD0_MARK, PG4_FN),
+ PINMUX_DATA(RXD3_MARK, PG3_FN),
+ PINMUX_DATA(RXD2_MARK, PG2_FN),
+ PINMUX_DATA(RXD1_MARK, PG1_FN),
+ PINMUX_DATA(RXD0_MARK, PG0_FN),
+
+ /* PH FN */
+ PINMUX_DATA(CE2B_MARK, PH5_FN),
+ PINMUX_DATA(CE2A_MARK, PH4_FN),
+ PINMUX_DATA(IOIS16_MARK, PH3_FN),
+ PINMUX_DATA(STATUS1_MARK, PH2_FN),
+ PINMUX_DATA(STATUS0_MARK, PH1_FN),
+ PINMUX_DATA(IRQOUT_MARK, PH0_FN),
+};
+
+static struct pinmux_gpio shx3_pinmux_gpios[] = {
+ /* PA */
+ PINMUX_GPIO(GPIO_PA7, PA7_DATA),
+ PINMUX_GPIO(GPIO_PA6, PA6_DATA),
+ PINMUX_GPIO(GPIO_PA5, PA5_DATA),
+ PINMUX_GPIO(GPIO_PA4, PA4_DATA),
+ PINMUX_GPIO(GPIO_PA3, PA3_DATA),
+ PINMUX_GPIO(GPIO_PA2, PA2_DATA),
+ PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+ PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+ /* PB */
+ PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+ PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+ PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+ PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+ PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+ PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+ PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+ PINMUX_GPIO(GPIO_PB0, PB0_DATA),
+
+ /* PC */
+ PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+ PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+ PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+ PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+ PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+ PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+ PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+ PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+ /* PD */
+ PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+ PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+ PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+ PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+ PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+ PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+ PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+ PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+ /* PE */
+ PINMUX_GPIO(GPIO_PE7, PE7_DATA),
+ PINMUX_GPIO(GPIO_PE6, PE6_DATA),
+ PINMUX_GPIO(GPIO_PE5, PE5_DATA),
+ PINMUX_GPIO(GPIO_PE4, PE4_DATA),
+ PINMUX_GPIO(GPIO_PE3, PE3_DATA),
+ PINMUX_GPIO(GPIO_PE2, PE2_DATA),
+ PINMUX_GPIO(GPIO_PE1, PE1_DATA),
+ PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+
+ /* PF */
+ PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+ PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+ PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+ PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+ PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+ PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+ PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+ PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+ /* PG */
+ PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+ PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+ PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+ PINMUX_GPIO(GPIO_PG4, PG4_DATA),
+ PINMUX_GPIO(GPIO_PG3, PG3_DATA),
+ PINMUX_GPIO(GPIO_PG2, PG2_DATA),
+ PINMUX_GPIO(GPIO_PG1, PG1_DATA),
+ PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+
+ /* PH */
+ PINMUX_GPIO(GPIO_PH5, PH5_DATA),
+ PINMUX_GPIO(GPIO_PH4, PH4_DATA),
+ PINMUX_GPIO(GPIO_PH3, PH3_DATA),
+ PINMUX_GPIO(GPIO_PH2, PH2_DATA),
+ PINMUX_GPIO(GPIO_PH1, PH1_DATA),
+ PINMUX_GPIO(GPIO_PH0, PH0_DATA),
+
+ /* FN */
+ PINMUX_GPIO(GPIO_FN_D31, D31_MARK),
+ PINMUX_GPIO(GPIO_FN_D30, D30_MARK),
+ PINMUX_GPIO(GPIO_FN_D29, D29_MARK),
+ PINMUX_GPIO(GPIO_FN_D28, D28_MARK),
+ PINMUX_GPIO(GPIO_FN_D27, D27_MARK),
+ PINMUX_GPIO(GPIO_FN_D26, D26_MARK),
+ PINMUX_GPIO(GPIO_FN_D25, D25_MARK),
+ PINMUX_GPIO(GPIO_FN_D24, D24_MARK),
+ PINMUX_GPIO(GPIO_FN_D23, D23_MARK),
+ PINMUX_GPIO(GPIO_FN_D22, D22_MARK),
+ PINMUX_GPIO(GPIO_FN_D21, D21_MARK),
+ PINMUX_GPIO(GPIO_FN_D20, D20_MARK),
+ PINMUX_GPIO(GPIO_FN_D19, D19_MARK),
+ PINMUX_GPIO(GPIO_FN_D18, D18_MARK),
+ PINMUX_GPIO(GPIO_FN_D17, D17_MARK),
+ PINMUX_GPIO(GPIO_FN_D16, D16_MARK),
+ PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
+ PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
+ PINMUX_GPIO(GPIO_FN_WE3, WE3_MARK),
+ PINMUX_GPIO(GPIO_FN_WE2, WE2_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6, CS6_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5, CS5_MARK),
+ PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+ PINMUX_GPIO(GPIO_FN_CLKOUTENB, CLKOUTENB_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK3, DACK3_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK2, DACK2_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ3, DREQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ2, DREQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3, IRQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2, IRQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1, IRQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0, IRQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK3, DRAK3_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK2, DRAK2_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK1, DRAK1_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK0, DRAK0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL3, IRL3_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL2, IRL2_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL1, IRL1_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL0, IRL0_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
+ PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQOUT, IRQOUT_MARK),
+};
+
+static struct pinmux_cfg_reg shx3_pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("PABCR", 0xffc70000, 32, 2) {
+ PA7_FN, PA7_OUT, PA7_IN, PA7_IN_PU,
+ PA6_FN, PA6_OUT, PA6_IN, PA6_IN_PU,
+ PA5_FN, PA5_OUT, PA5_IN, PA5_IN_PU,
+ PA4_FN, PA4_OUT, PA4_IN, PA4_IN_PU,
+ PA3_FN, PA3_OUT, PA3_IN, PA3_IN_PU,
+ PA2_FN, PA2_OUT, PA2_IN, PA2_IN_PU,
+ PA1_FN, PA1_OUT, PA1_IN, PA1_IN_PU,
+ PA0_FN, PA0_OUT, PA0_IN, PA0_IN_PU,
+ PB7_FN, PB7_OUT, PB7_IN, PB7_IN_PU,
+ PB6_FN, PB6_OUT, PB6_IN, PB6_IN_PU,
+ PB5_FN, PB5_OUT, PB5_IN, PB5_IN_PU,
+ PB4_FN, PB4_OUT, PB4_IN, PB4_IN_PU,
+ PB3_FN, PB3_OUT, PB3_IN, PB3_IN_PU,
+ PB2_FN, PB2_OUT, PB2_IN, PB2_IN_PU,
+ PB1_FN, PB1_OUT, PB1_IN, PB1_IN_PU,
+ PB0_FN, PB0_OUT, PB0_IN, PB0_IN_PU, },
+ },
+ { PINMUX_CFG_REG("PCDCR", 0xffc70004, 32, 2) {
+ PC7_FN, PC7_OUT, PC7_IN, PC7_IN_PU,
+ PC6_FN, PC6_OUT, PC6_IN, PC6_IN_PU,
+ PC5_FN, PC5_OUT, PC5_IN, PC5_IN_PU,
+ PC4_FN, PC4_OUT, PC4_IN, PC4_IN_PU,
+ PC3_FN, PC3_OUT, PC3_IN, PC3_IN_PU,
+ PC2_FN, PC2_OUT, PC2_IN, PC2_IN_PU,
+ PC1_FN, PC1_OUT, PC1_IN, PC1_IN_PU,
+ PC0_FN, PC0_OUT, PC0_IN, PC0_IN_PU,
+ PD7_FN, PD7_OUT, PD7_IN, PD7_IN_PU,
+ PD6_FN, PD6_OUT, PD6_IN, PD6_IN_PU,
+ PD5_FN, PD5_OUT, PD5_IN, PD5_IN_PU,
+ PD4_FN, PD4_OUT, PD4_IN, PD4_IN_PU,
+ PD3_FN, PD3_OUT, PD3_IN, PD3_IN_PU,
+ PD2_FN, PD2_OUT, PD2_IN, PD2_IN_PU,
+ PD1_FN, PD1_OUT, PD1_IN, PD1_IN_PU,
+ PD0_FN, PD0_OUT, PD0_IN, PD0_IN_PU, },
+ },
+ { PINMUX_CFG_REG("PEFCR", 0xffc70008, 32, 2) {
+ PE7_FN, PE7_OUT, PE7_IN, PE7_IN_PU,
+ PE6_FN, PE6_OUT, PE6_IN, PE6_IN_PU,
+ PE5_FN, PE5_OUT, PE5_IN, PE5_IN_PU,
+ PE4_FN, PE4_OUT, PE4_IN, PE4_IN_PU,
+ PE3_FN, PE3_OUT, PE3_IN, PE3_IN_PU,
+ PE2_FN, PE2_OUT, PE2_IN, PE2_IN_PU,
+ PE1_FN, PE1_OUT, PE1_IN, PE1_IN_PU,
+ PE0_FN, PE0_OUT, PE0_IN, PE0_IN_PU,
+ PF7_FN, PF7_OUT, PF7_IN, PF7_IN_PU,
+ PF6_FN, PF6_OUT, PF6_IN, PF6_IN_PU,
+ PF5_FN, PF5_OUT, PF5_IN, PF5_IN_PU,
+ PF4_FN, PF4_OUT, PF4_IN, PF4_IN_PU,
+ PF3_FN, PF3_OUT, PF3_IN, PF3_IN_PU,
+ PF2_FN, PF2_OUT, PF2_IN, PF2_IN_PU,
+ PF1_FN, PF1_OUT, PF1_IN, PF1_IN_PU,
+ PF0_FN, PF0_OUT, PF0_IN, PF0_IN_PU, },
+ },
+ { PINMUX_CFG_REG("PGHCR", 0xffc7000c, 32, 2) {
+ PG7_FN, PG7_OUT, PG7_IN, PG7_IN_PU,
+ PG6_FN, PG6_OUT, PG6_IN, PG6_IN_PU,
+ PG5_FN, PG5_OUT, PG5_IN, PG5_IN_PU,
+ PG4_FN, PG4_OUT, PG4_IN, PG4_IN_PU,
+ PG3_FN, PG3_OUT, PG3_IN, PG3_IN_PU,
+ PG2_FN, PG2_OUT, PG2_IN, PG2_IN_PU,
+ PG1_FN, PG1_OUT, PG1_IN, PG1_IN_PU,
+ PG0_FN, PG0_OUT, PG0_IN, PG0_IN_PU,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PH5_FN, PH5_OUT, PH5_IN, PH5_IN_PU,
+ PH4_FN, PH4_OUT, PH4_IN, PH4_IN_PU,
+ PH3_FN, PH3_OUT, PH3_IN, PH3_IN_PU,
+ PH2_FN, PH2_OUT, PH2_IN, PH2_IN_PU,
+ PH1_FN, PH1_OUT, PH1_IN, PH1_IN_PU,
+ PH0_FN, PH0_OUT, PH0_IN, PH0_IN_PU, },
+ },
+ { },
+};
+
+static struct pinmux_data_reg shx3_pinmux_data_regs[] = {
+ { PINMUX_DATA_REG("PABDR", 0xffc70010, 32) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+ PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA, },
+ },
+ { PINMUX_DATA_REG("PCDDR", 0xffc70014, 32) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA, },
+ },
+ { PINMUX_DATA_REG("PEFDR", 0xffc70018, 32) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA, },
+ },
+ { PINMUX_DATA_REG("PGHDR", 0xffc7001c, 32) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, PH5_DATA, PH4_DATA,
+ PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA, },
+ },
+ { },
+};
+
+static struct pinmux_info shx3_pinmux_info = {
+ .name = "shx3_pfc",
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+ .input_pu = { PINMUX_INPUT_PULLUP_BEGIN,
+ PINMUX_INPUT_PULLUP_END },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+ .first_gpio = GPIO_PA7,
+ .last_gpio = GPIO_FN_IRQOUT,
+ .gpios = shx3_pinmux_gpios,
+ .gpio_data = shx3_pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(shx3_pinmux_data),
+ .cfg_regs = shx3_pinmux_config_regs,
+ .data_regs = shx3_pinmux_data_regs,
+};
+
+static int __init shx3_pinmux_setup(void)
+{
+ return register_pinmux(&shx3_pinmux_info);
+}
+arch_initcall(shx3_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
index 156ccc960015..d551ed8dea95 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
@@ -551,7 +551,7 @@ static struct resource siu_resources[] = {
};
static struct platform_device siu_device = {
- .name = "sh_siu",
+ .name = "siu-pcm-audio",
.id = -1,
.dev = {
.platform_data = &siu_platform_data,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
index 79c556e56262..828c9657eb52 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
@@ -524,6 +524,70 @@ static struct platform_device veu1_device = {
},
};
+/* BEU0 */
+static struct uio_info beu0_platform_data = {
+ .name = "BEU0",
+ .version = "0",
+ .irq = evt2irq(0x8A0),
+};
+
+static struct resource beu0_resources[] = {
+ [0] = {
+ .name = "BEU0",
+ .start = 0xfe930000,
+ .end = 0xfe933400,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /* place holder for contiguous memory */
+ },
+};
+
+static struct platform_device beu0_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 6,
+ .dev = {
+ .platform_data = &beu0_platform_data,
+ },
+ .resource = beu0_resources,
+ .num_resources = ARRAY_SIZE(beu0_resources),
+ .archdata = {
+ .hwblk_id = HWBLK_BEU0,
+ },
+};
+
+/* BEU1 */
+static struct uio_info beu1_platform_data = {
+ .name = "BEU1",
+ .version = "0",
+ .irq = evt2irq(0xA00),
+};
+
+static struct resource beu1_resources[] = {
+ [0] = {
+ .name = "BEU1",
+ .start = 0xfe940000,
+ .end = 0xfe943400,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /* place holder for contiguous memory */
+ },
+};
+
+static struct platform_device beu1_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 7,
+ .dev = {
+ .platform_data = &beu1_platform_data,
+ },
+ .resource = beu1_resources,
+ .num_resources = ARRAY_SIZE(beu1_resources),
+ .archdata = {
+ .hwblk_id = HWBLK_BEU1,
+ },
+};
+
static struct sh_timer_config cmt_platform_data = {
.channel_offset = 0x60,
.timer_bit = 5,
@@ -857,6 +921,8 @@ static struct platform_device *sh7724_devices[] __initdata = {
&vpu_device,
&veu0_device,
&veu1_device,
+ &beu0_device,
+ &beu1_device,
&jpu_device,
&spu0_device,
&spu1_device,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
index 444aca95b20d..749c6388d5a5 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
@@ -26,7 +26,7 @@ static struct plat_sci_port scif2_platform_data = {
static struct platform_device scif2_device = {
.name = "sh-sci",
- .id = 2,
+ .id = 0,
.dev = {
.platform_data = &scif2_platform_data,
},
@@ -41,7 +41,7 @@ static struct plat_sci_port scif3_platform_data = {
static struct platform_device scif3_device = {
.name = "sh-sci",
- .id = 3,
+ .id = 1,
.dev = {
.platform_data = &scif3_platform_data,
},
@@ -56,7 +56,7 @@ static struct plat_sci_port scif4_platform_data = {
static struct platform_device scif4_device = {
.name = "sh-sci",
- .id = 4,
+ .id = 2,
.dev = {
.platform_data = &scif4_platform_data,
},
@@ -163,39 +163,23 @@ enum {
IRL4_HHLL, IRL4_HHLH, IRL4_HHHL,
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
- SDHI,
- DVC,
- IRQ8, IRQ9, IRQ10,
- WDT0,
- TMU0, TMU1, TMU2, TMU2_TICPI,
+ SDHI, DVC,
+ IRQ8, IRQ9, IRQ11, IRQ10, IRQ12, IRQ13, IRQ14, IRQ15,
+ TMU0, TMU1, TMU2, TMU2_TICPI, TMU3, TMU4, TMU5,
HUDI,
-
ARC4,
- DMAC0,
- IRQ11,
- SCIF2,
- DMAC1_6,
- USB0,
- IRQ12,
+ DMAC0_5, DMAC6_7, DMAC8_11,
+ SCIF0, SCIF1, SCIF2, SCIF3, SCIF4,
+ USB0, USB1,
JMC,
- SPI1,
- IRQ13, IRQ14,
- USB1,
+ SPI0, SPI1,
TMR01, TMR23, TMR45,
- WDT1,
FRT,
- LPC,
- SCIF0, SCIF1, SCIF3,
- PECI0I, PECI1I, PECI2I,
- IRQ15,
+ LPC, LPC5, LPC6, LPC7, LPC8,
+ PECI0, PECI1, PECI2, PECI3, PECI4, PECI5,
ETHERC,
- SPI0,
- ADC1,
- DMAC1_8,
+ ADC0, ADC1,
SIM,
- TMU3, TMU4, TMU5,
- ADC0,
- SCIF4,
IIC0_0, IIC0_1, IIC0_2, IIC0_3,
IIC1_0, IIC1_1, IIC1_2, IIC1_3,
IIC2_0, IIC2_1, IIC2_2, IIC2_3,
@@ -206,9 +190,23 @@ enum {
IIC7_0, IIC7_1, IIC7_2, IIC7_3,
IIC8_0, IIC8_1, IIC8_2, IIC8_3,
IIC9_0, IIC9_1, IIC9_2, IIC9_3,
- PCIINTA,
- PCIE,
+ ONFICTL,
+ MMC1, MMC2,
+ ECCU,
+ PCIC,
+ G200,
+ RSPI,
SGPIO,
+ DMINT12, DMINT13, DMINT14, DMINT15, DMINT16, DMINT17, DMINT18, DMINT19,
+ DMINT20, DMINT21, DMINT22, DMINT23,
+ DDRECC,
+ TSIP,
+ PCIE_BRIDGE,
+ WDT0B, WDT1B, WDT2B, WDT3B, WDT4B, WDT5B, WDT6B, WDT7B, WDT8B,
+ GETHER0, GETHER1, GETHER2,
+ PBIA, PBIB, PBIC,
+ DMAE2, DMAE3,
+ SERMUX2, SERMUX3,
/* interrupt groups */
@@ -221,19 +219,18 @@ static struct intc_vect vectors[] __initdata = {
INTC_VECT(DVC, 0x4e0),
INTC_VECT(IRQ8, 0x500), INTC_VECT(IRQ9, 0x520),
INTC_VECT(IRQ10, 0x540),
- INTC_VECT(WDT0, 0x560),
INTC_VECT(TMU0, 0x580), INTC_VECT(TMU1, 0x5a0),
INTC_VECT(TMU2, 0x5c0), INTC_VECT(TMU2_TICPI, 0x5e0),
INTC_VECT(HUDI, 0x600),
INTC_VECT(ARC4, 0x620),
- INTC_VECT(DMAC0, 0x640), INTC_VECT(DMAC0, 0x660),
- INTC_VECT(DMAC0, 0x680), INTC_VECT(DMAC0, 0x6a0),
- INTC_VECT(DMAC0, 0x6c0),
+ INTC_VECT(DMAC0_5, 0x640), INTC_VECT(DMAC0_5, 0x660),
+ INTC_VECT(DMAC0_5, 0x680), INTC_VECT(DMAC0_5, 0x6a0),
+ INTC_VECT(DMAC0_5, 0x6c0),
INTC_VECT(IRQ11, 0x6e0),
INTC_VECT(SCIF2, 0x700), INTC_VECT(SCIF2, 0x720),
INTC_VECT(SCIF2, 0x740), INTC_VECT(SCIF2, 0x760),
- INTC_VECT(DMAC0, 0x780), INTC_VECT(DMAC0, 0x7a0),
- INTC_VECT(DMAC1_6, 0x7c0), INTC_VECT(DMAC1_6, 0x7e0),
+ INTC_VECT(DMAC0_5, 0x780), INTC_VECT(DMAC0_5, 0x7a0),
+ INTC_VECT(DMAC6_7, 0x7c0), INTC_VECT(DMAC6_7, 0x7e0),
INTC_VECT(USB0, 0x840),
INTC_VECT(IRQ12, 0x880),
INTC_VECT(JMC, 0x8a0),
@@ -242,7 +239,6 @@ static struct intc_vect vectors[] __initdata = {
INTC_VECT(USB1, 0x920),
INTC_VECT(TMR01, 0xa00), INTC_VECT(TMR23, 0xa20),
INTC_VECT(TMR45, 0xa40),
- INTC_VECT(WDT1, 0xa60),
INTC_VECT(FRT, 0xa80),
INTC_VECT(LPC, 0xaa0), INTC_VECT(LPC, 0xac0),
INTC_VECT(LPC, 0xae0), INTC_VECT(LPC, 0xb00),
@@ -250,14 +246,14 @@ static struct intc_vect vectors[] __initdata = {
INTC_VECT(SCIF0, 0xb40), INTC_VECT(SCIF1, 0xb60),
INTC_VECT(SCIF3, 0xb80), INTC_VECT(SCIF3, 0xba0),
INTC_VECT(SCIF3, 0xbc0), INTC_VECT(SCIF3, 0xbe0),
- INTC_VECT(PECI0I, 0xc00), INTC_VECT(PECI1I, 0xc20),
- INTC_VECT(PECI2I, 0xc40),
+ INTC_VECT(PECI0, 0xc00), INTC_VECT(PECI1, 0xc20),
+ INTC_VECT(PECI2, 0xc40),
INTC_VECT(IRQ15, 0xc60),
INTC_VECT(ETHERC, 0xc80), INTC_VECT(ETHERC, 0xca0),
INTC_VECT(SPI0, 0xcc0),
INTC_VECT(ADC1, 0xce0),
- INTC_VECT(DMAC1_8, 0xd00), INTC_VECT(DMAC1_8, 0xd20),
- INTC_VECT(DMAC1_8, 0xd40), INTC_VECT(DMAC1_8, 0xd60),
+ INTC_VECT(DMAC8_11, 0xd00), INTC_VECT(DMAC8_11, 0xd20),
+ INTC_VECT(DMAC8_11, 0xd40), INTC_VECT(DMAC8_11, 0xd60),
INTC_VECT(SIM, 0xd80), INTC_VECT(SIM, 0xda0),
INTC_VECT(SIM, 0xdc0), INTC_VECT(SIM, 0xde0),
INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20),
@@ -278,17 +274,47 @@ static struct intc_vect vectors[] __initdata = {
INTC_VECT(IIC5_0, 0x1860), INTC_VECT(IIC5_1, 0x1880),
INTC_VECT(IIC5_2, 0x18a0), INTC_VECT(IIC5_3, 0x18c0),
INTC_VECT(IIC6_0, 0x18e0), INTC_VECT(IIC6_1, 0x1900),
- INTC_VECT(IIC6_2, 0x1920), INTC_VECT(IIC6_3, 0x1980),
+ INTC_VECT(IIC6_2, 0x1920),
+ INTC_VECT(ONFICTL, 0x1960),
+ INTC_VECT(IIC6_3, 0x1980),
INTC_VECT(IIC7_0, 0x19a0), INTC_VECT(IIC7_1, 0x1a00),
INTC_VECT(IIC7_2, 0x1a20), INTC_VECT(IIC7_3, 0x1a40),
INTC_VECT(IIC8_0, 0x1a60), INTC_VECT(IIC8_1, 0x1a80),
INTC_VECT(IIC8_2, 0x1aa0), INTC_VECT(IIC8_3, 0x1b40),
INTC_VECT(IIC9_0, 0x1b60), INTC_VECT(IIC9_1, 0x1b80),
INTC_VECT(IIC9_2, 0x1c00), INTC_VECT(IIC9_3, 0x1c20),
- INTC_VECT(PCIINTA, 0x1ce0),
- INTC_VECT(PCIE, 0x1e00),
- INTC_VECT(SGPIO, 0x1f80),
- INTC_VECT(SGPIO, 0x1fa0),
+ INTC_VECT(MMC1, 0x1c60), INTC_VECT(MMC2, 0x1c80),
+ INTC_VECT(ECCU, 0x1cc0),
+ INTC_VECT(PCIC, 0x1ce0),
+ INTC_VECT(G200, 0x1d00),
+ INTC_VECT(RSPI, 0x1d80), INTC_VECT(RSPI, 0x1da0),
+ INTC_VECT(RSPI, 0x1dc0), INTC_VECT(RSPI, 0x1de0),
+ INTC_VECT(PECI3, 0x1ec0), INTC_VECT(PECI4, 0x1ee0),
+ INTC_VECT(PECI5, 0x1f00),
+ INTC_VECT(SGPIO, 0x1f80), INTC_VECT(SGPIO, 0x1fa0),
+ INTC_VECT(SGPIO, 0x1fc0),
+ INTC_VECT(DMINT12, 0x2400), INTC_VECT(DMINT13, 0x2420),
+ INTC_VECT(DMINT14, 0x2440), INTC_VECT(DMINT15, 0x2460),
+ INTC_VECT(DMINT16, 0x2480), INTC_VECT(DMINT17, 0x24e0),
+ INTC_VECT(DMINT18, 0x2500), INTC_VECT(DMINT19, 0x2520),
+ INTC_VECT(DMINT20, 0x2540), INTC_VECT(DMINT21, 0x2560),
+ INTC_VECT(DMINT22, 0x2580), INTC_VECT(DMINT23, 0x2600),
+ INTC_VECT(DDRECC, 0x2620),
+ INTC_VECT(TSIP, 0x2640),
+ INTC_VECT(PCIE_BRIDGE, 0x27c0),
+ INTC_VECT(WDT0B, 0x2800), INTC_VECT(WDT1B, 0x2820),
+ INTC_VECT(WDT2B, 0x2840), INTC_VECT(WDT3B, 0x2860),
+ INTC_VECT(WDT4B, 0x2880), INTC_VECT(WDT5B, 0x28a0),
+ INTC_VECT(WDT6B, 0x28c0), INTC_VECT(WDT7B, 0x28e0),
+ INTC_VECT(WDT8B, 0x2900),
+ INTC_VECT(GETHER0, 0x2960), INTC_VECT(GETHER1, 0x2980),
+ INTC_VECT(GETHER2, 0x29a0),
+ INTC_VECT(PBIA, 0x2a00), INTC_VECT(PBIB, 0x2a20),
+ INTC_VECT(PBIC, 0x2a40),
+ INTC_VECT(DMAE2, 0x2a60), INTC_VECT(DMAE3, 0x2a80),
+ INTC_VECT(SERMUX2, 0x2aa0), INTC_VECT(SERMUX3, 0x2b40),
+ INTC_VECT(LPC5, 0x2b60), INTC_VECT(LPC6, 0x2b80),
+ INTC_VECT(LPC7, 0x2c00), INTC_VECT(LPC8, 0x2c20),
};
static struct intc_group groups[] __initdata = {
@@ -312,31 +338,45 @@ static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
{ 0, 0, 0, 0, 0, 0, 0, 0,
- 0, DMAC1_8, 0, PECI0I, LPC, FRT, WDT1, TMR45,
- TMR23, TMR01, 0, 0, 0, 0, 0, DMAC0,
- HUDI, 0, WDT0, SCIF3, SCIF2, SDHI, TMU345, TMU012
+ 0, DMAC8_11, 0, PECI0, LPC, FRT, 0, TMR45,
+ TMR23, TMR01, 0, 0, 0, 0, 0, DMAC0_5,
+ HUDI, 0, 0, SCIF3, SCIF2, SDHI, TMU345, TMU012
} },
{ 0xffd400d0, 0xffd400d4, 32, /* INT2MSKR1 / INT2MSKCR1 */
{ IRQ15, IRQ14, IRQ13, IRQ12, IRQ11, IRQ10, SCIF4, ETHERC,
IRQ9, IRQ8, SCIF1, SCIF0, USB0, 0, 0, USB1,
- ADC1, 0, DMAC1_6, ADC0, SPI0, SIM, PECI2I, PECI1I,
+ ADC1, 0, DMAC6_7, ADC0, SPI0, SIM, PECI2, PECI1,
ARC4, 0, SPI1, JMC, 0, 0, 0, DVC
} },
{ 0xffd10038, 0xffd1003c, 32, /* INT2MSKR2 / INT2MSKCR2 */
- { IIC4_1, IIC4_2, IIC5_0, 0, 0, 0, SGPIO, 0,
- 0, 0, 0, IIC9_2, IIC8_2, IIC8_1, IIC8_0, IIC7_3,
+ { IIC4_1, IIC4_2, IIC5_0, ONFICTL, 0, 0, SGPIO, 0,
+ 0, G200, 0, IIC9_2, IIC8_2, IIC8_1, IIC8_0, IIC7_3,
IIC7_2, IIC7_1, IIC6_3, IIC0_0, IIC0_1, IIC0_2, IIC0_3, IIC3_1,
- IIC2_3, 0, IIC2_1, IIC9_1, IIC3_3, IIC1_0, PCIE, IIC2_2
+ IIC2_3, 0, IIC2_1, IIC9_1, IIC3_3, IIC1_0, 0, IIC2_2
} },
- { 0xffd100d0, 0xff1400d4, 32, /* INT2MSKR3 / INT2MSKCR4 */
- { 0, IIC6_1, IIC6_0, IIC5_1, IIC3_2, IIC2_0, 0, 0,
+ { 0xffd100d0, 0xffd100d4, 32, /* INT2MSKR3 / INT2MSKCR3 */
+ { MMC1, IIC6_1, IIC6_0, IIC5_1, IIC3_2, IIC2_0, PECI5, MMC2,
IIC1_3, IIC1_2, IIC9_0, IIC8_3, IIC4_3, IIC7_0, 0, IIC6_2,
- PCIINTA, 0, IIC4_0, 0, 0, 0, 0, IIC9_3,
+ PCIC, 0, IIC4_0, 0, ECCU, RSPI, 0, IIC9_3,
IIC3_0, 0, IIC5_3, IIC5_2, 0, 0, 0, IIC1_1
} },
+
+ { 0xffd20038, 0xffd2003c, 32, /* INT2MSKR4 / INT2MSKCR4 */
+ { WDT0B, WDT1B, WDT3B, GETHER0, 0, 0, 0, 0,
+ 0, 0, 0, LPC7, SERMUX2, DMAE3, DMAE2, PBIC,
+ PBIB, PBIA, GETHER1, DMINT12, DMINT13, DMINT14, DMINT15, TSIP,
+ DMINT23, 0, DMINT21, LPC6, 0, DMINT16, 0, DMINT22
+ } },
+
+ { 0xffd200d0, 0xffd200d4, 32, /* INT2MSKR5 / INT2MSKCR5 */
+ { 0, WDT8B, WDT7B, WDT4B, 0, DMINT20, 0, 0,
+ DMINT19, DMINT18, LPC5, SERMUX3, WDT2B, GETHER2, 0, 0,
+ 0, 0, PCIE_BRIDGE, 0, 0, 0, 0, LPC8,
+ DDRECC, 0, WDT6B, WDT5B, 0, 0, 0, DMINT17
+ } },
};
#define INTPRI 0xffd00010
@@ -372,6 +412,22 @@ static struct intc_mask_reg mask_registers[] __initdata = {
#define INT2PRI29 0xffd100b4
#define INT2PRI30 0xffd100b8
#define INT2PRI31 0xffd100bc
+#define INT2PRI32 0xffd20000
+#define INT2PRI33 0xffd20004
+#define INT2PRI34 0xffd20008
+#define INT2PRI35 0xffd2000c
+#define INT2PRI36 0xffd20010
+#define INT2PRI37 0xffd20014
+#define INT2PRI38 0xffd20018
+#define INT2PRI39 0xffd2001c
+#define INT2PRI40 0xffd200a0
+#define INT2PRI41 0xffd200a4
+#define INT2PRI42 0xffd200a8
+#define INT2PRI43 0xffd200ac
+#define INT2PRI44 0xffd200b0
+#define INT2PRI45 0xffd200b4
+#define INT2PRI46 0xffd200b8
+#define INT2PRI47 0xffd200bc
static struct intc_prio_reg prio_registers[] __initdata = {
{ INTPRI, 0, 32, 4, { IRQ0, IRQ1, IRQ2, IRQ3,
@@ -379,39 +435,61 @@ static struct intc_prio_reg prio_registers[] __initdata = {
{ INT2PRI0, 0, 32, 8, { TMU0, TMU1, TMU2, TMU2_TICPI } },
{ INT2PRI1, 0, 32, 8, { TMU3, TMU4, TMU5, SDHI } },
- { INT2PRI2, 0, 32, 8, { SCIF2, SCIF3, WDT0, IRQ8 } },
- { INT2PRI3, 0, 32, 8, { HUDI, DMAC0, ADC0, IRQ9 } },
+ { INT2PRI2, 0, 32, 8, { SCIF2, SCIF3, 0, IRQ8 } },
+ { INT2PRI3, 0, 32, 8, { HUDI, DMAC0_5, ADC0, IRQ9 } },
{ INT2PRI4, 0, 32, 8, { IRQ10, 0, TMR01, TMR23 } },
- { INT2PRI5, 0, 32, 8, { TMR45, WDT1, FRT, LPC } },
- { INT2PRI6, 0, 32, 8, { PECI0I, ETHERC, DMAC1_8, 0 } },
+ { INT2PRI5, 0, 32, 8, { TMR45, 0, FRT, LPC } },
+ { INT2PRI6, 0, 32, 8, { PECI0, ETHERC, DMAC8_11, 0 } },
{ INT2PRI7, 0, 32, 8, { SCIF4, 0, IRQ11, IRQ12 } },
{ INT2PRI8, 0, 32, 8, { 0, 0, 0, DVC } },
{ INT2PRI9, 0, 32, 8, { ARC4, 0, SPI1, JMC } },
- { INT2PRI10, 0, 32, 8, { SPI0, SIM, PECI2I, PECI1I } },
- { INT2PRI11, 0, 32, 8, { ADC1, IRQ13, DMAC1_6, IRQ14 } },
+ { INT2PRI10, 0, 32, 8, { SPI0, SIM, PECI2, PECI1 } },
+ { INT2PRI11, 0, 32, 8, { ADC1, IRQ13, DMAC6_7, IRQ14 } },
{ INT2PRI12, 0, 32, 8, { USB0, 0, IRQ15, USB1 } },
{ INT2PRI13, 0, 32, 8, { 0, 0, SCIF1, SCIF0 } },
{ INT2PRI16, 0, 32, 8, { IIC2_2, 0, 0, 0 } },
- { INT2PRI17, 0, 32, 8, { PCIE, 0, 0, IIC1_0 } },
+ { INT2PRI17, 0, 32, 8, { 0, 0, 0, IIC1_0 } },
{ INT2PRI18, 0, 32, 8, { IIC3_3, IIC9_1, IIC2_1, IIC1_2 } },
{ INT2PRI19, 0, 32, 8, { IIC2_3, IIC3_1, 0, IIC1_3 } },
{ INT2PRI20, 0, 32, 8, { IIC2_0, IIC6_3, IIC7_1, IIC7_2 } },
{ INT2PRI21, 0, 32, 8, { IIC7_3, IIC8_0, IIC8_1, IIC8_2 } },
- { INT2PRI22, 0, 32, 8, { IIC9_2, 0, 0, 0 } },
- { INT2PRI23, 0, 32, 8, { 0, SGPIO, IIC3_2, IIC5_1 } },
- { INT2PRI24, 0, 32, 8, { 0, 0, 0, IIC1_1 } },
+ { INT2PRI22, 0, 32, 8, { IIC9_2, MMC2, G200, 0 } },
+ { INT2PRI23, 0, 32, 8, { PECI5, SGPIO, IIC3_2, IIC5_1 } },
+ { INT2PRI24, 0, 32, 8, { PECI4, PECI3, 0, IIC1_1 } },
{ INT2PRI25, 0, 32, 8, { IIC3_0, 0, IIC5_3, IIC5_2 } },
- { INT2PRI26, 0, 32, 8, { 0, 0, 0, IIC9_3 } },
- { INT2PRI27, 0, 32, 8, { PCIINTA, IIC6_0, IIC4_0, IIC6_1 } },
- { INT2PRI28, 0, 32, 8, { IIC4_3, IIC7_0, 0, IIC6_2 } },
+ { INT2PRI26, 0, 32, 8, { ECCU, RSPI, 0, IIC9_3 } },
+ { INT2PRI27, 0, 32, 8, { PCIC, IIC6_0, IIC4_0, IIC6_1 } },
+ { INT2PRI28, 0, 32, 8, { IIC4_3, IIC7_0, MMC1, IIC6_2 } },
{ INT2PRI29, 0, 32, 8, { 0, 0, IIC9_0, IIC8_3 } },
- { INT2PRI30, 0, 32, 8, { IIC4_1, IIC4_2, IIC5_0, 0 } },
+ { INT2PRI30, 0, 32, 8, { IIC4_1, IIC4_2, IIC5_0, ONFICTL } },
{ INT2PRI31, 0, 32, 8, { IIC0_0, IIC0_1, IIC0_2, IIC0_3 } },
+ { INT2PRI32, 0, 32, 8, { DMINT22, 0, 0, 0 } },
+ { INT2PRI33, 0, 32, 8, { 0, 0, 0, DMINT16 } },
+ { INT2PRI34, 0, 32, 8, { 0, LPC6, DMINT21, DMINT18 } },
+ { INT2PRI35, 0, 32, 8, { DMINT23, TSIP, 0, DMINT19 } },
+ { INT2PRI36, 0, 32, 8, { DMINT20, GETHER1, PBIA, PBIB } },
+ { INT2PRI37, 0, 32, 8, { PBIC, DMAE2, DMAE3, SERMUX2 } },
+ { INT2PRI38, 0, 32, 8, { LPC7, 0, 0, 0 } },
+ { INT2PRI39, 0, 32, 8, { 0, 0, 0, WDT4B } },
+ { INT2PRI40, 0, 32, 8, { 0, 0, 0, DMINT17 } },
+ { INT2PRI41, 0, 32, 8, { DDRECC, 0, WDT6B, WDT5B } },
+ { INT2PRI42, 0, 32, 8, { 0, 0, 0, LPC8 } },
+ { INT2PRI43, 0, 32, 8, { 0, WDT7B, PCIE_BRIDGE, WDT8B } },
+ { INT2PRI44, 0, 32, 8, { WDT2B, GETHER2, 0, 0 } },
+ { INT2PRI45, 0, 32, 8, { 0, 0, LPC5, SERMUX3 } },
+ { INT2PRI46, 0, 32, 8, { WDT0B, WDT1B, WDT3B, GETHER0 } },
+ { INT2PRI47, 0, 32, 8, { DMINT12, DMINT13, DMINT14, DMINT15 } },
+};
+
+static struct intc_sense_reg sense_registers_irq8to15[] __initdata = {
+ { 0xffd100f8, 32, 2, /* ICR2 */ { IRQ15, IRQ14, IRQ13, IRQ12,
+ IRQ11, IRQ10, IRQ9, IRQ8 } },
};
static DECLARE_INTC_DESC(intc_desc, "sh7757", vectors, groups,
- mask_registers, prio_registers, NULL);
+ mask_registers, prio_registers,
+ sense_registers_irq8to15);
/* Support for external interrupt pins in IRQ mode */
static struct intc_vect vectors_irq0123[] __initdata = {
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
index 8797723231ea..c016c0004714 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
@@ -629,33 +629,10 @@ static void __init sh7786_usb_setup(void)
}
}
-static int __init sh7786_devices_setup(void)
-{
- int ret;
-
- sh7786_usb_setup();
-
- ret = platform_add_devices(sh7786_early_devices,
- ARRAY_SIZE(sh7786_early_devices));
- if (unlikely(ret != 0))
- return ret;
-
- return platform_add_devices(sh7786_devices,
- ARRAY_SIZE(sh7786_devices));
-}
-arch_initcall(sh7786_devices_setup);
-
-void __init plat_early_device_setup(void)
-{
- early_platform_add_devices(sh7786_early_devices,
- ARRAY_SIZE(sh7786_early_devices));
-}
-
enum {
UNUSED = 0,
/* interrupt sources */
-
IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH,
IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH,
IRL0_HLLL, IRL0_HLLH, IRL0_HLHL, IRL0_HLHH,
@@ -693,9 +670,12 @@ enum {
Thermal,
INTICI0, INTICI1, INTICI2, INTICI3,
INTICI4, INTICI5, INTICI6, INTICI7,
+
+ /* Muxed sub-events */
+ TXI1, BRI1, RXI1, ERI1,
};
-static struct intc_vect vectors[] __initdata = {
+static struct intc_vect sh7786_vectors[] __initdata = {
INTC_VECT(WDT, 0x3e0),
INTC_VECT(TMU0_0, 0x400), INTC_VECT(TMU0_1, 0x420),
INTC_VECT(TMU0_2, 0x440), INTC_VECT(TMU0_3, 0x460),
@@ -756,14 +736,12 @@ static struct intc_vect vectors[] __initdata = {
#define INTDISTCR0 0xfe4100b0
#define INTDISTCR1 0xfe4100b4
-#define INTACK 0xfe4100b8
-#define INTACKCLR 0xfe4100bc
#define INT2DISTCR0 0xfe410900
#define INT2DISTCR1 0xfe410904
#define INT2DISTCR2 0xfe410908
#define INT2DISTCR3 0xfe41090c
-static struct intc_mask_reg mask_registers[] __initdata = {
+static struct intc_mask_reg sh7786_mask_registers[] __initdata = {
{ CnINTMSK0, CnINTMSKCLR0, 32,
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 },
INTC_SMP_BALANCING(INTDISTCR0) },
@@ -807,7 +785,7 @@ static struct intc_mask_reg mask_registers[] __initdata = {
0, 0, 0, 0, 0, 0, 0, 0 }, INTC_SMP_BALANCING(INT2DISTCR3) },
};
-static struct intc_prio_reg prio_registers[] __initdata = {
+static struct intc_prio_reg sh7786_prio_registers[] __initdata = {
{ 0xfe410010, 0, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3,
IRQ4, IRQ5, IRQ6, IRQ7 } },
{ 0xfe410800, 0, 32, 8, /* INT2PRI0 */ { 0, 0, 0, WDT } },
@@ -851,11 +829,27 @@ static struct intc_prio_reg prio_registers[] __initdata = {
INTICI3, INTICI2, INTICI1, INTICI0 }, INTC_SMP(4, 2) },
};
-static DECLARE_INTC_DESC(intc_desc, "sh7786", vectors, NULL,
- mask_registers, prio_registers, NULL);
+static struct intc_subgroup sh7786_subgroups[] __initdata = {
+ { 0xfe410c20, 32, SCIF1,
+ { 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, TXI1, BRI1, RXI1, ERI1 } },
+};
-/* Support for external interrupt pins in IRQ mode */
+static struct intc_desc sh7786_intc_desc __initdata = {
+ .name = "sh7786",
+ .hw = {
+ .vectors = sh7786_vectors,
+ .nr_vectors = ARRAY_SIZE(sh7786_vectors),
+ .mask_regs = sh7786_mask_registers,
+ .nr_mask_regs = ARRAY_SIZE(sh7786_mask_registers),
+ .subgroups = sh7786_subgroups,
+ .nr_subgroups = ARRAY_SIZE(sh7786_subgroups),
+ .prio_regs = sh7786_prio_registers,
+ .nr_prio_regs = ARRAY_SIZE(sh7786_prio_registers),
+ },
+};
+/* Support for external interrupt pins in IRQ mode */
static struct intc_vect vectors_irq0123[] __initdata = {
INTC_VECT(IRQ0, 0x200), INTC_VECT(IRQ1, 0x240),
INTC_VECT(IRQ2, 0x280), INTC_VECT(IRQ3, 0x2c0),
@@ -866,23 +860,25 @@ static struct intc_vect vectors_irq4567[] __initdata = {
INTC_VECT(IRQ6, 0x380), INTC_VECT(IRQ7, 0x3c0),
};
-static struct intc_sense_reg sense_registers[] __initdata = {
+static struct intc_sense_reg sh7786_sense_registers[] __initdata = {
{ 0xfe41001c, 32, 2, /* ICR1 */ { IRQ0, IRQ1, IRQ2, IRQ3,
IRQ4, IRQ5, IRQ6, IRQ7 } },
};
-static struct intc_mask_reg ack_registers[] __initdata = {
+static struct intc_mask_reg sh7786_ack_registers[] __initdata = {
{ 0xfe410024, 0, 32, /* INTREQ */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static DECLARE_INTC_DESC_ACK(intc_desc_irq0123, "sh7786-irq0123",
- vectors_irq0123, NULL, mask_registers,
- prio_registers, sense_registers, ack_registers);
+ vectors_irq0123, NULL, sh7786_mask_registers,
+ sh7786_prio_registers, sh7786_sense_registers,
+ sh7786_ack_registers);
static DECLARE_INTC_DESC_ACK(intc_desc_irq4567, "sh7786-irq4567",
- vectors_irq4567, NULL, mask_registers,
- prio_registers, sense_registers, ack_registers);
+ vectors_irq4567, NULL, sh7786_mask_registers,
+ sh7786_prio_registers, sh7786_sense_registers,
+ sh7786_ack_registers);
/* External interrupt pins in IRL mode */
@@ -909,10 +905,10 @@ static struct intc_vect vectors_irl4567[] __initdata = {
};
static DECLARE_INTC_DESC(intc_desc_irl0123, "sh7786-irl0123", vectors_irl0123,
- NULL, mask_registers, NULL, NULL);
+ NULL, sh7786_mask_registers, NULL, NULL);
static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7786-irl4567", vectors_irl4567,
- NULL, mask_registers, NULL, NULL);
+ NULL, sh7786_mask_registers, NULL, NULL);
#define INTC_ICR0 0xfe410000
#define INTC_INTMSK0 CnINTMSK0
@@ -920,19 +916,6 @@ static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7786-irl4567", vectors_irl4567,
#define INTC_INTMSK2 INTMSK2
#define INTC_INTMSKCLR1 CnINTMSKCLR1
#define INTC_INTMSKCLR2 INTMSKCLR2
-#define INTC_USERIMASK 0xfe411000
-
-#ifdef CONFIG_INTC_BALANCING
-unsigned int irq_lookup(unsigned int irq)
-{
- return __raw_readl(INTACK) & 1 ? irq : NO_IRQ_IGNORE;
-}
-
-void irq_finish(unsigned int irq)
-{
- __raw_writel(irq2evt(irq), INTACKCLR);
-}
-#endif
void __init plat_irq_setup(void)
{
@@ -946,8 +929,7 @@ void __init plat_irq_setup(void)
/* select IRL mode for IRL3-0 + IRL7-4 */
__raw_writel(__raw_readl(INTC_ICR0) & ~0x00c00000, INTC_ICR0);
- register_intc_controller(&intc_desc);
- register_intc_userimask(INTC_USERIMASK);
+ register_intc_controller(&sh7786_intc_desc);
}
void __init plat_irq_setup_pins(int mode)
@@ -991,3 +973,39 @@ void __init plat_irq_setup_pins(int mode)
void __init plat_mem_setup(void)
{
}
+
+static int __init sh7786_devices_setup(void)
+{
+ int ret, irq;
+
+ sh7786_usb_setup();
+
+ /*
+ * De-mux SCIF1 IRQs if possible
+ */
+ irq = intc_irq_lookup(sh7786_intc_desc.name, TXI1);
+ if (irq > 0) {
+ scif1_platform_data.irqs[SCIx_TXI_IRQ] = irq;
+ scif1_platform_data.irqs[SCIx_ERI_IRQ] =
+ intc_irq_lookup(sh7786_intc_desc.name, ERI1);
+ scif1_platform_data.irqs[SCIx_BRI_IRQ] =
+ intc_irq_lookup(sh7786_intc_desc.name, BRI1);
+ scif1_platform_data.irqs[SCIx_RXI_IRQ] =
+ intc_irq_lookup(sh7786_intc_desc.name, RXI1);
+ }
+
+ ret = platform_add_devices(sh7786_early_devices,
+ ARRAY_SIZE(sh7786_early_devices));
+ if (unlikely(ret != 0))
+ return ret;
+
+ return platform_add_devices(sh7786_devices,
+ ARRAY_SIZE(sh7786_devices));
+}
+arch_initcall(sh7786_devices_setup);
+
+void __init plat_early_device_setup(void)
+{
+ early_platform_add_devices(sh7786_early_devices,
+ ARRAY_SIZE(sh7786_early_devices));
+}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index 9158bc5ea38b..013f0b144489 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -1,7 +1,7 @@
/*
* SH-X3 Prototype Setup
*
- * Copyright (C) 2007 - 2009 Paul Mundt
+ * Copyright (C) 2007 - 2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -12,7 +12,9 @@
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/io.h>
+#include <linux/gpio.h>
#include <linux/sh_timer.h>
+#include <cpu/shx3.h>
#include <asm/mmzone.h>
/*
@@ -354,6 +356,10 @@ static struct intc_group groups[] __initdata = {
DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11),
};
+#define INT2DISTCR0 0xfe4108a0
+#define INT2DISTCR1 0xfe4108a4
+#define INT2DISTCR2 0xfe4108a8
+
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xfe410030, 0xfe410050, 32, /* CnINTMSK0 / CnINTMSKCLR0 */
{ IRQ0, IRQ1, IRQ2, IRQ3 } },
@@ -363,20 +369,23 @@ static struct intc_mask_reg mask_registers[] __initdata = {
{ FE1, FE0, 0, ATAPI, VCORE0, VIN1, VIN0, IIC,
DU, GPIO3, GPIO2, GPIO1, GPIO0, PAM, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, /* HUDI bits ignored */
- 0, TMU5, TMU4, TMU3, TMU2, TMU1, TMU0, 0, } },
+ 0, TMU5, TMU4, TMU3, TMU2, TMU1, TMU0, 0, },
+ INTC_SMP_BALANCING(INT2DISTCR0) },
{ 0xfe410830, 0xfe410860, 32, /* CnINT2MSK1 / CnINT2MSKCLR1 */
{ 0, 0, 0, 0, DTU3, DTU2, DTU1, DTU0, /* IRM bits ignored */
PCII9, PCII8, PCII7, PCII6, PCII5, PCII4, PCII3, PCII2,
PCII1, PCII0, DMAC1_DMAE, DMAC1_DMINT11,
DMAC1_DMINT10, DMAC1_DMINT9, DMAC1_DMINT8, DMAC1_DMINT7,
DMAC1_DMINT6, DMAC0_DMAE, DMAC0_DMINT5, DMAC0_DMINT4,
- DMAC0_DMINT3, DMAC0_DMINT2, DMAC0_DMINT1, DMAC0_DMINT0 } },
+ DMAC0_DMINT3, DMAC0_DMINT2, DMAC0_DMINT1, DMAC0_DMINT0 },
+ INTC_SMP_BALANCING(INT2DISTCR1) },
{ 0xfe410840, 0xfe410870, 32, /* CnINT2MSK2 / CnINT2MSKCLR2 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
SCIF3_TXI, SCIF3_BRI, SCIF3_RXI, SCIF3_ERI,
SCIF2_TXI, SCIF2_BRI, SCIF2_RXI, SCIF2_ERI,
SCIF1_TXI, SCIF1_BRI, SCIF1_RXI, SCIF1_ERI,
- SCIF0_TXI, SCIF0_BRI, SCIF0_RXI, SCIF0_ERI } },
+ SCIF0_TXI, SCIF0_BRI, SCIF0_RXI, SCIF0_ERI },
+ INTC_SMP_BALANCING(INT2DISTCR2) },
};
static struct intc_prio_reg prio_registers[] __initdata = {
@@ -433,11 +442,33 @@ static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups,
void __init plat_irq_setup_pins(int mode)
{
+ int ret = 0;
+
switch (mode) {
case IRQ_MODE_IRQ:
+ ret |= gpio_request(GPIO_FN_IRQ3, intc_desc_irq.name);
+ ret |= gpio_request(GPIO_FN_IRQ2, intc_desc_irq.name);
+ ret |= gpio_request(GPIO_FN_IRQ1, intc_desc_irq.name);
+ ret |= gpio_request(GPIO_FN_IRQ0, intc_desc_irq.name);
+
+ if (unlikely(ret)) {
+ pr_err("Failed to set IRQ mode\n");
+ return;
+ }
+
register_intc_controller(&intc_desc_irq);
break;
case IRQ_MODE_IRL3210:
+ ret |= gpio_request(GPIO_FN_IRL3, intc_desc_irl.name);
+ ret |= gpio_request(GPIO_FN_IRL2, intc_desc_irl.name);
+ ret |= gpio_request(GPIO_FN_IRL1, intc_desc_irl.name);
+ ret |= gpio_request(GPIO_FN_IRL0, intc_desc_irl.name);
+
+ if (unlikely(ret)) {
+ pr_err("Failed to set IRL mode\n");
+ return;
+ }
+
register_intc_controller(&intc_desc_irl);
break;
default:
@@ -447,6 +478,9 @@ void __init plat_irq_setup_pins(int mode)
void __init plat_irq_setup(void)
{
+ reserve_intc_vectors(vectors_irq, ARRAY_SIZE(vectors_irq));
+ reserve_intc_vectors(vectors_irl, ARRAY_SIZE(vectors_irl));
+
register_intc_controller(&intc_desc);
}
diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S
index 6e35f012cc03..7db248936b60 100644
--- a/arch/sh/kernel/head_32.S
+++ b/arch/sh/kernel/head_32.S
@@ -330,7 +330,7 @@ ENTRY(_stext)
#if defined(CONFIG_CPU_SH2)
1: .long 0x000000F0 ! IMASK=0xF
#else
-1: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF
+1: .long 0x500080F0 ! MD=1, RB=0, BL=1, FD=1, IMASK=0xF
#endif
ENTRY(stack_start)
2: .long init_thread_union+THREAD_SIZE
diff --git a/arch/sh/kernel/io_trapped.c b/arch/sh/kernel/io_trapped.c
index 2947d2bd1291..32c385ef1011 100644
--- a/arch/sh/kernel/io_trapped.c
+++ b/arch/sh/kernel/io_trapped.c
@@ -291,7 +291,7 @@ int handle_trapped_io(struct pt_regs *regs, unsigned long address)
}
tmp = handle_unaligned_access(instruction, regs,
- &trapped_io_access, 1);
+ &trapped_io_access, 1, address);
set_fs(oldfs);
return tmp == 0;
}
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index ae5bac39b896..9dc447db8a44 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -283,6 +283,8 @@ void __init init_IRQ(void)
if (sh_mv.mv_init_irq)
sh_mv.mv_init_irq();
+ intc_finalize();
+
irq_ctx_init(smp_processor_id());
}
diff --git a/arch/sh/kernel/kdebugfs.c b/arch/sh/kernel/kdebugfs.c
new file mode 100644
index 000000000000..e11c30bb100c
--- /dev/null
+++ b/arch/sh/kernel/kdebugfs.c
@@ -0,0 +1,16 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+
+struct dentry *arch_debugfs_dir;
+EXPORT_SYMBOL(arch_debugfs_dir);
+
+static int __init arch_kdebugfs_init(void)
+{
+ arch_debugfs_dir = debugfs_create_dir("sh", NULL);
+ if (!arch_debugfs_dir)
+ return -ENOMEM;
+
+ return 0;
+}
+arch_initcall(arch_kdebugfs_init);
diff --git a/arch/sh/kernel/kprobes.c b/arch/sh/kernel/kprobes.c
index 4049d99f76e1..1208b09e95c3 100644
--- a/arch/sh/kernel/kprobes.c
+++ b/arch/sh/kernel/kprobes.c
@@ -20,9 +20,9 @@
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
-static struct kprobe saved_current_opcode;
-static struct kprobe saved_next_opcode;
-static struct kprobe saved_next_opcode2;
+static DEFINE_PER_CPU(struct kprobe, saved_current_opcode);
+static DEFINE_PER_CPU(struct kprobe, saved_next_opcode);
+static DEFINE_PER_CPU(struct kprobe, saved_next_opcode2);
#define OPCODE_JMP(x) (((x) & 0xF0FF) == 0x402b)
#define OPCODE_JSR(x) (((x) & 0xF0FF) == 0x400b)
@@ -102,16 +102,21 @@ int __kprobes kprobe_handle_illslot(unsigned long pc)
void __kprobes arch_remove_kprobe(struct kprobe *p)
{
- if (saved_next_opcode.addr != 0x0) {
+ struct kprobe *saved = &__get_cpu_var(saved_next_opcode);
+
+ if (saved->addr) {
arch_disarm_kprobe(p);
- arch_disarm_kprobe(&saved_next_opcode);
- saved_next_opcode.addr = 0x0;
- saved_next_opcode.opcode = 0x0;
-
- if (saved_next_opcode2.addr != 0x0) {
- arch_disarm_kprobe(&saved_next_opcode2);
- saved_next_opcode2.addr = 0x0;
- saved_next_opcode2.opcode = 0x0;
+ arch_disarm_kprobe(saved);
+
+ saved->addr = NULL;
+ saved->opcode = 0;
+
+ saved = &__get_cpu_var(saved_next_opcode2);
+ if (saved->addr) {
+ arch_disarm_kprobe(saved);
+
+ saved->addr = NULL;
+ saved->opcode = 0;
}
}
}
@@ -141,57 +146,59 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
*/
static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
{
- kprobe_opcode_t *addr = NULL;
- saved_current_opcode.addr = (kprobe_opcode_t *) (regs->pc);
- addr = saved_current_opcode.addr;
+ __get_cpu_var(saved_current_opcode).addr = (kprobe_opcode_t *)regs->pc;
if (p != NULL) {
+ struct kprobe *op1, *op2;
+
arch_disarm_kprobe(p);
+ op1 = &__get_cpu_var(saved_next_opcode);
+ op2 = &__get_cpu_var(saved_next_opcode2);
+
if (OPCODE_JSR(p->opcode) || OPCODE_JMP(p->opcode)) {
unsigned int reg_nr = ((p->opcode >> 8) & 0x000F);
- saved_next_opcode.addr =
- (kprobe_opcode_t *) regs->regs[reg_nr];
+ op1->addr = (kprobe_opcode_t *) regs->regs[reg_nr];
} else if (OPCODE_BRA(p->opcode) || OPCODE_BSR(p->opcode)) {
unsigned long disp = (p->opcode & 0x0FFF);
- saved_next_opcode.addr =
+ op1->addr =
(kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
} else if (OPCODE_BRAF(p->opcode) || OPCODE_BSRF(p->opcode)) {
unsigned int reg_nr = ((p->opcode >> 8) & 0x000F);
- saved_next_opcode.addr =
+ op1->addr =
(kprobe_opcode_t *) (regs->pc + 4 +
regs->regs[reg_nr]);
} else if (OPCODE_RTS(p->opcode)) {
- saved_next_opcode.addr = (kprobe_opcode_t *) regs->pr;
+ op1->addr = (kprobe_opcode_t *) regs->pr;
} else if (OPCODE_BF(p->opcode) || OPCODE_BT(p->opcode)) {
unsigned long disp = (p->opcode & 0x00FF);
/* case 1 */
- saved_next_opcode.addr = p->addr + 1;
+ op1->addr = p->addr + 1;
/* case 2 */
- saved_next_opcode2.addr =
+ op2->addr =
(kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
- saved_next_opcode2.opcode = *(saved_next_opcode2.addr);
- arch_arm_kprobe(&saved_next_opcode2);
+ op2->opcode = *(op2->addr);
+ arch_arm_kprobe(op2);
} else if (OPCODE_BF_S(p->opcode) || OPCODE_BT_S(p->opcode)) {
unsigned long disp = (p->opcode & 0x00FF);
/* case 1 */
- saved_next_opcode.addr = p->addr + 2;
+ op1->addr = p->addr + 2;
/* case 2 */
- saved_next_opcode2.addr =
+ op2->addr =
(kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
- saved_next_opcode2.opcode = *(saved_next_opcode2.addr);
- arch_arm_kprobe(&saved_next_opcode2);
+ op2->opcode = *(op2->addr);
+ arch_arm_kprobe(op2);
} else {
- saved_next_opcode.addr = p->addr + 1;
+ op1->addr = p->addr + 1;
}
- saved_next_opcode.opcode = *(saved_next_opcode.addr);
- arch_arm_kprobe(&saved_next_opcode);
+ op1->opcode = *(op1->addr);
+ arch_arm_kprobe(op1);
}
}
@@ -376,21 +383,23 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
cur->post_handler(cur, regs, 0);
}
- if (saved_next_opcode.addr != 0x0) {
- arch_disarm_kprobe(&saved_next_opcode);
- saved_next_opcode.addr = 0x0;
- saved_next_opcode.opcode = 0x0;
+ p = &__get_cpu_var(saved_next_opcode);
+ if (p->addr) {
+ arch_disarm_kprobe(p);
+ p->addr = NULL;
+ p->opcode = 0;
- addr = saved_current_opcode.addr;
- saved_current_opcode.addr = 0x0;
+ addr = __get_cpu_var(saved_current_opcode).addr;
+ __get_cpu_var(saved_current_opcode).addr = NULL;
p = get_kprobe(addr);
arch_arm_kprobe(p);
- if (saved_next_opcode2.addr != 0x0) {
- arch_disarm_kprobe(&saved_next_opcode2);
- saved_next_opcode2.addr = 0x0;
- saved_next_opcode2.opcode = 0x0;
+ p = &__get_cpu_var(saved_next_opcode2);
+ if (p->addr) {
+ arch_disarm_kprobe(p);
+ p->addr = NULL;
+ p->opcode = 0;
}
}
@@ -572,14 +581,5 @@ static struct kprobe trampoline_p = {
int __init arch_init_kprobes(void)
{
- saved_next_opcode.addr = 0x0;
- saved_next_opcode.opcode = 0x0;
-
- saved_current_opcode.addr = 0x0;
- saved_current_opcode.opcode = 0x0;
-
- saved_next_opcode2.addr = 0x0;
- saved_next_opcode2.opcode = 0x0;
-
return register_kprobe(&trampoline_p);
}
diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c
new file mode 100644
index 000000000000..0a05983633ca
--- /dev/null
+++ b/arch/sh/kernel/ptrace.c
@@ -0,0 +1,33 @@
+#include <linux/ptrace.h>
+
+/**
+ * regs_query_register_offset() - query register offset from its name
+ * @name: the name of a register
+ *
+ * regs_query_register_offset() returns the offset of a register in struct
+ * pt_regs from its name. If the name is invalid, this returns -EINVAL;
+ */
+int regs_query_register_offset(const char *name)
+{
+ const struct pt_regs_offset *roff;
+ for (roff = regoffset_table; roff->name != NULL; roff++)
+ if (!strcmp(roff->name, name))
+ return roff->offset;
+ return -EINVAL;
+}
+
+/**
+ * regs_query_register_name() - query register name from its offset
+ * @offset: the offset of a register in struct pt_regs.
+ *
+ * regs_query_register_name() returns the name of a register from its
+ * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
+ */
+const char *regs_query_register_name(unsigned int offset)
+{
+ const struct pt_regs_offset *roff;
+ for (roff = regoffset_table; roff->name != NULL; roff++)
+ if (roff->offset == offset)
+ return roff->name;
+ return NULL;
+}
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c
index 6c4bbba2a675..90a15d29feeb 100644
--- a/arch/sh/kernel/ptrace_32.c
+++ b/arch/sh/kernel/ptrace_32.c
@@ -274,6 +274,33 @@ static int dspregs_active(struct task_struct *target,
}
#endif
+const struct pt_regs_offset regoffset_table[] = {
+ REGS_OFFSET_NAME(0),
+ REGS_OFFSET_NAME(1),
+ REGS_OFFSET_NAME(2),
+ REGS_OFFSET_NAME(3),
+ REGS_OFFSET_NAME(4),
+ REGS_OFFSET_NAME(5),
+ REGS_OFFSET_NAME(6),
+ REGS_OFFSET_NAME(7),
+ REGS_OFFSET_NAME(8),
+ REGS_OFFSET_NAME(9),
+ REGS_OFFSET_NAME(10),
+ REGS_OFFSET_NAME(11),
+ REGS_OFFSET_NAME(12),
+ REGS_OFFSET_NAME(13),
+ REGS_OFFSET_NAME(14),
+ REGS_OFFSET_NAME(15),
+ REG_OFFSET_NAME(pc),
+ REG_OFFSET_NAME(pr),
+ REG_OFFSET_NAME(sr),
+ REG_OFFSET_NAME(gbr),
+ REG_OFFSET_NAME(mach),
+ REG_OFFSET_NAME(macl),
+ REG_OFFSET_NAME(tra),
+ REG_OFFSET_END,
+};
+
/*
* These are our native regset flavours.
*/
@@ -338,9 +365,9 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
return &user_sh_native_view;
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
- struct user * dummy = NULL;
unsigned long __user *datap = (unsigned long __user *)data;
int ret;
@@ -356,17 +383,20 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
if (addr < sizeof(struct pt_regs))
tmp = get_stack_long(child, addr);
- else if (addr >= (long) &dummy->fpu &&
- addr < (long) &dummy->u_fpvalid) {
+ else if (addr >= offsetof(struct user, fpu) &&
+ addr < offsetof(struct user, u_fpvalid)) {
if (!tsk_used_math(child)) {
- if (addr == (long)&dummy->fpu.fpscr)
+ if (addr == offsetof(struct user, fpu.fpscr))
tmp = FPSCR_INIT;
else
tmp = 0;
- } else
- tmp = ((long *)child->thread.xstate)
- [(addr - (long)&dummy->fpu) >> 2];
- } else if (addr == (long) &dummy->u_fpvalid)
+ } else {
+ unsigned long index;
+ index = addr - offsetof(struct user, fpu);
+ tmp = ((unsigned long *)child->thread.xstate)
+ [index >> 2];
+ }
+ } else if (addr == offsetof(struct user, u_fpvalid))
tmp = !!tsk_used_math(child);
else if (addr == PT_TEXT_ADDR)
tmp = child->mm->start_code;
@@ -390,13 +420,15 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
if (addr < sizeof(struct pt_regs))
ret = put_stack_long(child, addr, data);
- else if (addr >= (long) &dummy->fpu &&
- addr < (long) &dummy->u_fpvalid) {
+ else if (addr >= offsetof(struct user, fpu) &&
+ addr < offsetof(struct user, u_fpvalid)) {
+ unsigned long index;
+ index = addr - offsetof(struct user, fpu);
set_stopped_child_used_math(child);
- ((long *)child->thread.xstate)
- [(addr - (long)&dummy->fpu) >> 2] = data;
+ ((unsigned long *)child->thread.xstate)
+ [index >> 2] = data;
ret = 0;
- } else if (addr == (long) &dummy->u_fpvalid) {
+ } else if (addr == offsetof(struct user, u_fpvalid)) {
conditional_stopped_child_used_math(data, child);
ret = 0;
}
@@ -406,35 +438,35 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
return copy_regset_to_user(child, &user_sh_native_view,
REGSET_GENERAL,
0, sizeof(struct pt_regs),
- (void __user *)data);
+ datap);
case PTRACE_SETREGS:
return copy_regset_from_user(child, &user_sh_native_view,
REGSET_GENERAL,
0, sizeof(struct pt_regs),
- (const void __user *)data);
+ datap);
#ifdef CONFIG_SH_FPU
case PTRACE_GETFPREGS:
return copy_regset_to_user(child, &user_sh_native_view,
REGSET_FPU,
0, sizeof(struct user_fpu_struct),
- (void __user *)data);
+ datap);
case PTRACE_SETFPREGS:
return copy_regset_from_user(child, &user_sh_native_view,
REGSET_FPU,
0, sizeof(struct user_fpu_struct),
- (const void __user *)data);
+ datap);
#endif
#ifdef CONFIG_SH_DSP
case PTRACE_GETDSPREGS:
return copy_regset_to_user(child, &user_sh_native_view,
REGSET_DSP,
0, sizeof(struct pt_dspregs),
- (void __user *)data);
+ datap);
case PTRACE_SETDSPREGS:
return copy_regset_from_user(child, &user_sh_native_view,
REGSET_DSP,
0, sizeof(struct pt_dspregs),
- (const void __user *)data);
+ datap);
#endif
default:
ret = ptrace_request(child, request, addr, data);
diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c
index 5fd644da7f02..4436eacddb15 100644
--- a/arch/sh/kernel/ptrace_64.c
+++ b/arch/sh/kernel/ptrace_64.c
@@ -20,7 +20,7 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
+#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
@@ -252,6 +252,85 @@ static int fpregs_active(struct task_struct *target,
}
#endif
+const struct pt_regs_offset regoffset_table[] = {
+ REG_OFFSET_NAME(pc),
+ REG_OFFSET_NAME(sr),
+ REG_OFFSET_NAME(syscall_nr),
+ REGS_OFFSET_NAME(0),
+ REGS_OFFSET_NAME(1),
+ REGS_OFFSET_NAME(2),
+ REGS_OFFSET_NAME(3),
+ REGS_OFFSET_NAME(4),
+ REGS_OFFSET_NAME(5),
+ REGS_OFFSET_NAME(6),
+ REGS_OFFSET_NAME(7),
+ REGS_OFFSET_NAME(8),
+ REGS_OFFSET_NAME(9),
+ REGS_OFFSET_NAME(10),
+ REGS_OFFSET_NAME(11),
+ REGS_OFFSET_NAME(12),
+ REGS_OFFSET_NAME(13),
+ REGS_OFFSET_NAME(14),
+ REGS_OFFSET_NAME(15),
+ REGS_OFFSET_NAME(16),
+ REGS_OFFSET_NAME(17),
+ REGS_OFFSET_NAME(18),
+ REGS_OFFSET_NAME(19),
+ REGS_OFFSET_NAME(20),
+ REGS_OFFSET_NAME(21),
+ REGS_OFFSET_NAME(22),
+ REGS_OFFSET_NAME(23),
+ REGS_OFFSET_NAME(24),
+ REGS_OFFSET_NAME(25),
+ REGS_OFFSET_NAME(26),
+ REGS_OFFSET_NAME(27),
+ REGS_OFFSET_NAME(28),
+ REGS_OFFSET_NAME(29),
+ REGS_OFFSET_NAME(30),
+ REGS_OFFSET_NAME(31),
+ REGS_OFFSET_NAME(32),
+ REGS_OFFSET_NAME(33),
+ REGS_OFFSET_NAME(34),
+ REGS_OFFSET_NAME(35),
+ REGS_OFFSET_NAME(36),
+ REGS_OFFSET_NAME(37),
+ REGS_OFFSET_NAME(38),
+ REGS_OFFSET_NAME(39),
+ REGS_OFFSET_NAME(40),
+ REGS_OFFSET_NAME(41),
+ REGS_OFFSET_NAME(42),
+ REGS_OFFSET_NAME(43),
+ REGS_OFFSET_NAME(44),
+ REGS_OFFSET_NAME(45),
+ REGS_OFFSET_NAME(46),
+ REGS_OFFSET_NAME(47),
+ REGS_OFFSET_NAME(48),
+ REGS_OFFSET_NAME(49),
+ REGS_OFFSET_NAME(50),
+ REGS_OFFSET_NAME(51),
+ REGS_OFFSET_NAME(52),
+ REGS_OFFSET_NAME(53),
+ REGS_OFFSET_NAME(54),
+ REGS_OFFSET_NAME(55),
+ REGS_OFFSET_NAME(56),
+ REGS_OFFSET_NAME(57),
+ REGS_OFFSET_NAME(58),
+ REGS_OFFSET_NAME(59),
+ REGS_OFFSET_NAME(60),
+ REGS_OFFSET_NAME(61),
+ REGS_OFFSET_NAME(62),
+ REGS_OFFSET_NAME(63),
+ TREGS_OFFSET_NAME(0),
+ TREGS_OFFSET_NAME(1),
+ TREGS_OFFSET_NAME(2),
+ TREGS_OFFSET_NAME(3),
+ TREGS_OFFSET_NAME(4),
+ TREGS_OFFSET_NAME(5),
+ TREGS_OFFSET_NAME(6),
+ TREGS_OFFSET_NAME(7),
+ REG_OFFSET_END,
+};
+
/*
* These are our native regset flavours.
*/
@@ -304,9 +383,11 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
return &user_sh64_native_view;
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret;
+ unsigned long __user *datap = (unsigned long __user *) data;
switch (request) {
/* read the word at location addr in the USER area. */
@@ -321,13 +402,15 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
tmp = get_stack_long(child, addr);
else if ((addr >= offsetof(struct user, fpu)) &&
(addr < offsetof(struct user, u_fpvalid))) {
- tmp = get_fpu_long(child, addr - offsetof(struct user, fpu));
+ unsigned long index;
+ index = addr - offsetof(struct user, fpu);
+ tmp = get_fpu_long(child, index);
} else if (addr == offsetof(struct user, u_fpvalid)) {
tmp = !!tsk_used_math(child);
} else {
break;
}
- ret = put_user(tmp, (unsigned long *)data);
+ ret = put_user(tmp, datap);
break;
}
@@ -358,7 +441,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
else if ((addr >= offsetof(struct user, fpu)) &&
(addr < offsetof(struct user, u_fpvalid))) {
- ret = put_fpu_long(child, addr - offsetof(struct user, fpu), data);
+ unsigned long index;
+ index = addr - offsetof(struct user, fpu);
+ ret = put_fpu_long(child, index, data);
}
break;
@@ -366,23 +451,23 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
return copy_regset_to_user(child, &user_sh64_native_view,
REGSET_GENERAL,
0, sizeof(struct pt_regs),
- (void __user *)data);
+ datap);
case PTRACE_SETREGS:
return copy_regset_from_user(child, &user_sh64_native_view,
REGSET_GENERAL,
0, sizeof(struct pt_regs),
- (const void __user *)data);
+ datap);
#ifdef CONFIG_SH_FPU
case PTRACE_GETFPREGS:
return copy_regset_to_user(child, &user_sh64_native_view,
REGSET_FPU,
0, sizeof(struct user_fpu_struct),
- (void __user *)data);
+ datap);
case PTRACE_SETFPREGS:
return copy_regset_from_user(child, &user_sh64_native_view,
REGSET_FPU,
0, sizeof(struct user_fpu_struct),
- (const void __user *)data);
+ datap);
#endif
default:
ret = ptrace_request(child, request, addr, data);
@@ -392,13 +477,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
return ret;
}
-asmlinkage int sh64_ptrace(long request, long pid, long addr, long data)
+asmlinkage int sh64_ptrace(long request, long pid,
+ unsigned long addr, unsigned long data)
{
#define WPC_DBRMODE 0x0d104008
- static int first_call = 1;
+ static unsigned long first_call;
- lock_kernel();
- if (first_call) {
+ if (!test_and_set_bit(0, &first_call)) {
/* Set WPC.DBRMODE to 0. This makes all debug events get
* delivered through RESVEC, i.e. into the handlers in entry.S.
* (If the kernel was downloaded using a remote gdb, WPC.DBRMODE
@@ -408,9 +493,7 @@ asmlinkage int sh64_ptrace(long request, long pid, long addr, long data)
* the remote gdb.) */
printk("DBRMODE set to 0 to permit native debugging\n");
poke_real_address_q(WPC_DBRMODE, 0);
- first_call = 0;
}
- unlock_kernel();
return sys_ptrace(request, pid, addr, data);
}
diff --git a/arch/sh/kernel/reboot.c b/arch/sh/kernel/reboot.c
index b1fca66bb92e..ca6a5ca64015 100644
--- a/arch/sh/kernel/reboot.c
+++ b/arch/sh/kernel/reboot.c
@@ -9,6 +9,7 @@
#include <asm/addrspace.h>
#include <asm/reboot.h>
#include <asm/system.h>
+#include <asm/tlbflush.h>
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
@@ -25,6 +26,9 @@ static void native_machine_restart(char * __unused)
{
local_irq_disable();
+ /* Destroy all of the TLBs in preparation for reset by MMU */
+ __flush_tlb_global();
+
/* Address error with SR.BL=1 first. */
trigger_address_error();
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index e769401a78ba..4e278467f76c 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -24,7 +24,6 @@
#include <linux/module.h>
#include <linux/smp.h>
#include <linux/err.h>
-#include <linux/debugfs.h>
#include <linux/crash_dump.h>
#include <linux/mmzone.h>
#include <linux/clk.h>
@@ -136,8 +135,9 @@ void __init check_for_initrd(void)
goto disable;
}
- if (unlikely(start < PAGE_OFFSET)) {
- pr_err("initrd start < PAGE_OFFSET\n");
+ if (unlikely(start < __MEMORY_START)) {
+ pr_err("initrd start (%08lx) < __MEMORY_START(%x)\n",
+ start, __MEMORY_START);
goto disable;
}
@@ -158,7 +158,7 @@ void __init check_for_initrd(void)
/*
* Address sanitization
*/
- initrd_start = (unsigned long)__va(__pa(start));
+ initrd_start = (unsigned long)__va(start);
initrd_end = initrd_start + INITRD_SIZE;
memblock_reserve(__pa(initrd_start), INITRD_SIZE);
@@ -458,17 +458,3 @@ const struct seq_operations cpuinfo_op = {
.show = show_cpuinfo,
};
#endif /* CONFIG_PROC_FS */
-
-struct dentry *sh_debugfs_root;
-
-static int __init sh_debugfs_init(void)
-{
- sh_debugfs_root = debugfs_create_dir("sh", NULL);
- if (!sh_debugfs_root)
- return -ENOMEM;
- if (IS_ERR(sh_debugfs_root))
- return PTR_ERR(sh_debugfs_root);
-
- return 0;
-}
-arch_initcall(sh_debugfs_init);
diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S
index 19fd11dd9871..e872e81add8a 100644
--- a/arch/sh/kernel/syscalls_32.S
+++ b/arch/sh/kernel/syscalls_32.S
@@ -353,3 +353,25 @@ ENTRY(sys_call_table)
.long sys_pwritev
.long sys_rt_tgsigqueueinfo /* 335 */
.long sys_perf_event_open
+ .long sys_fanotify_init
+ .long sys_fanotify_mark
+ .long sys_prlimit64
+ /* Broken-out socket family */
+ .long sys_socket /* 340 */
+ .long sys_bind
+ .long sys_connect
+ .long sys_listen
+ .long sys_accept
+ .long sys_getsockname /* 345 */
+ .long sys_getpeername
+ .long sys_socketpair
+ .long sys_send
+ .long sys_sendto
+ .long sys_recv /* 350 */
+ .long sys_recvfrom
+ .long sys_shutdown
+ .long sys_setsockopt
+ .long sys_getsockopt
+ .long sys_sendmsg /* 355 */
+ .long sys_recvmsg
+ .long sys_recvmmsg
diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S
index 2048a20d7c80..66585708ce90 100644
--- a/arch/sh/kernel/syscalls_64.S
+++ b/arch/sh/kernel/syscalls_64.S
@@ -393,3 +393,6 @@ sys_call_table:
.long sys_perf_event_open
.long sys_recvmmsg /* 365 */
.long sys_accept4
+ .long sys_fanotify_init
+ .long sys_fanotify_mark
+ .long sys_prlimit64
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index c3d86fa71ddf..3484c2f65aba 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -5,7 +5,7 @@
* SuperH version: Copyright (C) 1999 Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf
* Copyright (C) 2000 David Howells
- * Copyright (C) 2002 - 2007 Paul Mundt
+ * Copyright (C) 2002 - 2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -26,6 +26,7 @@
#include <linux/limits.h>
#include <linux/sysfs.h>
#include <linux/uaccess.h>
+#include <linux/perf_event.h>
#include <asm/system.h>
#include <asm/alignment.h>
#include <asm/fpu.h>
@@ -369,7 +370,8 @@ static inline int handle_delayslot(struct pt_regs *regs,
#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
- struct mem_access *ma, int expected)
+ struct mem_access *ma, int expected,
+ unsigned long address)
{
u_int rm;
int ret, index;
@@ -383,9 +385,18 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
index = (instruction>>8)&15; /* 0x0F00 */
rm = regs->regs[index];
- /* shout about fixups */
- if (!expected)
+ /*
+ * Log the unexpected fixups, and then pass them on to perf.
+ *
+ * We intentionally don't report the expected cases to perf as
+ * otherwise the trapped I/O case will skew the results too much
+ * to be useful.
+ */
+ if (!expected) {
unaligned_fixups_notify(current, instruction, regs);
+ perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0,
+ regs, address);
+ }
ret = -EFAULT;
switch (instruction&0xF000) {
@@ -574,7 +585,8 @@ fixup:
set_fs(USER_DS);
tmp = handle_unaligned_access(instruction, regs,
- &user_mem_access, 0);
+ &user_mem_access, 0,
+ address);
set_fs(oldfs);
if (tmp == 0)
@@ -607,8 +619,8 @@ uspace_segv:
unaligned_fixups_notify(current, instruction, regs);
- handle_unaligned_access(instruction, regs,
- &user_mem_access, 0);
+ handle_unaligned_access(instruction, regs, &user_mem_access,
+ 0, address);
set_fs(oldfs);
}
}
@@ -802,6 +814,9 @@ void __cpuinit per_cpu_trap_init(void)
: /* no output */
: "r" (&vbr_base)
: "memory");
+
+ /* disable exception blocking now when the vbr has been setup */
+ clear_bl_bit();
}
void *set_exception_table_vec(unsigned int vec, void *handler)
diff --git a/arch/sh/kernel/traps_64.c b/arch/sh/kernel/traps_64.c
index e67e140bf1f6..6713ca97e553 100644
--- a/arch/sh/kernel/traps_64.c
+++ b/arch/sh/kernel/traps_64.c
@@ -24,6 +24,7 @@
#include <linux/interrupt.h>
#include <linux/sysctl.h>
#include <linux/module.h>
+#include <linux/perf_event.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -50,7 +51,7 @@ asmlinkage void do_##name(unsigned long error_code, struct pt_regs *regs) \
do_unhandled_exception(trapnr, signr, str, __stringify(name), error_code, regs, current); \
}
-spinlock_t die_lock;
+static DEFINE_SPINLOCK(die_lock);
void die(const char * str, struct pt_regs * regs, long err)
{
@@ -433,6 +434,8 @@ static int misaligned_load(struct pt_regs *regs,
return error;
}
+ perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address);
+
destreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) {
__u64 buffer;
@@ -509,6 +512,8 @@ static int misaligned_store(struct pt_regs *regs,
return error;
}
+ perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address);
+
srcreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) {
__u64 buffer;
@@ -583,6 +588,8 @@ static int misaligned_fpu_load(struct pt_regs *regs,
return error;
}
+ perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address);
+
destreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) {
__u64 buffer;
@@ -658,6 +665,8 @@ static int misaligned_fpu_store(struct pt_regs *regs,
return error;
}
+ perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address);
+
srcreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) {
__u64 buffer;
diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile
index dab4d2129812..7b95f29e3174 100644
--- a/arch/sh/lib/Makefile
+++ b/arch/sh/lib/Makefile
@@ -30,4 +30,4 @@ lib-$(CONFIG_MMU) += copy_page.o __clear_user.o
lib-$(CONFIG_MCOUNT) += mcount.o
lib-y += $(memcpy-y) $(memset-y) $(udivsi3-y)
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c
index 1fcdb1220975..f76a5090d5d1 100644
--- a/arch/sh/math-emu/math.c
+++ b/arch/sh/math-emu/math.c
@@ -12,6 +12,7 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/signal.h>
+#include <linux/perf_event.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -619,6 +620,8 @@ int do_fpu_inst(unsigned short inst, struct pt_regs *regs)
struct task_struct *tsk = current;
struct sh_fpu_soft_struct *fpu = &(tsk->thread.xstate->softfpu);
+ perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0);
+
if (!(task_thread_info(tsk)->status & TS_USEDFPU)) {
/* initialize once. */
fpu_init(fpu);
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 1445ca6257df..09370392aff1 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -168,6 +168,10 @@ config IOREMAP_FIXED
config UNCACHED_MAPPING
bool
+config HAVE_SRAM_POOL
+ bool
+ select GENERIC_ALLOCATOR
+
choice
prompt "Kernel page size"
default PAGE_SIZE_4KB
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index 53f7c684afb2..ab89ea4f9414 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_PMB) += pmb.o
obj-$(CONFIG_NUMA) += numa.o
obj-$(CONFIG_IOREMAP_FIXED) += ioremap_fixed.o
obj-$(CONFIG_UNCACHED_MAPPING) += uncached.o
+obj-$(CONFIG_HAVE_SRAM_POOL) += sram.o
# Special flags for fault_64.o. This puts restrictions on the number of
# caller-save registers that the compiler can target when building this file.
@@ -66,4 +67,4 @@ CFLAGS_fault_64.o += -ffixed-r7 \
-ffixed-r60 -ffixed-r61 -ffixed-r62 \
-fomit-frame-pointer
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
diff --git a/arch/sh/mm/asids-debugfs.c b/arch/sh/mm/asids-debugfs.c
index cd8c3bf39b5a..74c03ecc4871 100644
--- a/arch/sh/mm/asids-debugfs.c
+++ b/arch/sh/mm/asids-debugfs.c
@@ -63,7 +63,7 @@ static int __init asids_debugfs_init(void)
{
struct dentry *asids_dentry;
- asids_dentry = debugfs_create_file("asids", S_IRUSR, sh_debugfs_root,
+ asids_dentry = debugfs_create_file("asids", S_IRUSR, arch_debugfs_dir,
NULL, &asids_debugfs_fops);
if (!asids_dentry)
return -ENOMEM;
diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c
index 690ed010d002..52411462c409 100644
--- a/arch/sh/mm/cache-debugfs.c
+++ b/arch/sh/mm/cache-debugfs.c
@@ -126,25 +126,19 @@ static int __init cache_debugfs_init(void)
{
struct dentry *dcache_dentry, *icache_dentry;
- dcache_dentry = debugfs_create_file("dcache", S_IRUSR, sh_debugfs_root,
+ dcache_dentry = debugfs_create_file("dcache", S_IRUSR, arch_debugfs_dir,
(unsigned int *)CACHE_TYPE_DCACHE,
&cache_debugfs_fops);
if (!dcache_dentry)
return -ENOMEM;
- if (IS_ERR(dcache_dentry))
- return PTR_ERR(dcache_dentry);
- icache_dentry = debugfs_create_file("icache", S_IRUSR, sh_debugfs_root,
+ icache_dentry = debugfs_create_file("icache", S_IRUSR, arch_debugfs_dir,
(unsigned int *)CACHE_TYPE_ICACHE,
&cache_debugfs_fops);
if (!icache_dentry) {
debugfs_remove(dcache_dentry);
return -ENOMEM;
}
- if (IS_ERR(icache_dentry)) {
- debugfs_remove(dcache_dentry);
- return PTR_ERR(icache_dentry);
- }
return 0;
}
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index c86a08540258..038793286990 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -38,11 +38,12 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size,
void *ret, *ret_nocache;
int order = get_order(size);
+ gfp |= __GFP_ZERO;
+
ret = (void *)__get_free_pages(gfp, order);
if (!ret)
return NULL;
- memset(ret, 0, size);
/*
* Pages from the page allocator may have data present in
* cache. So flush the cache before using uncached memory.
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 552bea5113f5..3385b28acaac 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -47,7 +47,6 @@ static pte_t *__get_pte_phys(unsigned long addr)
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
- pte_t *pte;
pgd = pgd_offset_k(addr);
if (pgd_none(*pgd)) {
@@ -67,8 +66,7 @@ static pte_t *__get_pte_phys(unsigned long addr)
return NULL;
}
- pte = pte_offset_kernel(pmd, addr);
- return pte;
+ return pte_offset_kernel(pmd, addr);
}
static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
@@ -125,13 +123,45 @@ void __clear_fixmap(enum fixed_addresses idx, pgprot_t prot)
clear_pte_phys(address, prot);
}
+static pmd_t * __init one_md_table_init(pud_t *pud)
+{
+ if (pud_none(*pud)) {
+ pmd_t *pmd;
+
+ pmd = alloc_bootmem_pages(PAGE_SIZE);
+ pud_populate(&init_mm, pud, pmd);
+ BUG_ON(pmd != pmd_offset(pud, 0));
+ }
+
+ return pmd_offset(pud, 0);
+}
+
+static pte_t * __init one_page_table_init(pmd_t *pmd)
+{
+ if (pmd_none(*pmd)) {
+ pte_t *pte;
+
+ pte = alloc_bootmem_pages(PAGE_SIZE);
+ pmd_populate_kernel(&init_mm, pmd, pte);
+ BUG_ON(pte != pte_offset_kernel(pmd, 0));
+ }
+
+ return pte_offset_kernel(pmd, 0);
+}
+
+static pte_t * __init page_table_kmap_check(pte_t *pte, pmd_t *pmd,
+ unsigned long vaddr, pte_t *lastpte)
+{
+ return pte;
+}
+
void __init page_table_range_init(unsigned long start, unsigned long end,
pgd_t *pgd_base)
{
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
- pte_t *pte;
+ pte_t *pte = NULL;
int i, j, k;
unsigned long vaddr;
@@ -144,19 +174,13 @@ void __init page_table_range_init(unsigned long start, unsigned long end,
for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) {
pud = (pud_t *)pgd;
for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) {
-#ifdef __PAGETABLE_PMD_FOLDED
- pmd = (pmd_t *)pud;
-#else
- pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
- pud_populate(&init_mm, pud, pmd);
+ pmd = one_md_table_init(pud);
+#ifndef __PAGETABLE_PMD_FOLDED
pmd += k;
#endif
for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) {
- if (pmd_none(*pmd)) {
- pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
- pmd_populate_kernel(&init_mm, pmd, pte);
- BUG_ON(pte != pte_offset_kernel(pmd, 0));
- }
+ pte = page_table_kmap_check(one_page_table_init(pmd),
+ pmd, vaddr, pte);
vaddr += PMD_SIZE;
}
k = 0;
diff --git a/arch/sh/mm/nommu.c b/arch/sh/mm/nommu.c
index 7694f50c9034..36312d254faf 100644
--- a/arch/sh/mm/nommu.c
+++ b/arch/sh/mm/nommu.c
@@ -67,6 +67,10 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
BUG();
}
+void __flush_tlb_global(void)
+{
+}
+
void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
{
}
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
index 6379091a1647..b20b1b3eee4b 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -40,7 +40,7 @@ struct pmb_entry {
unsigned long flags;
unsigned long size;
- spinlock_t lock;
+ raw_spinlock_t lock;
/*
* 0 .. NR_PMB_ENTRIES for specific entry selection, or
@@ -265,7 +265,7 @@ static struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
memset(pmbe, 0, sizeof(struct pmb_entry));
- spin_lock_init(&pmbe->lock);
+ raw_spin_lock_init(&pmbe->lock);
pmbe->vpn = vpn;
pmbe->ppn = ppn;
@@ -327,9 +327,9 @@ static void set_pmb_entry(struct pmb_entry *pmbe)
{
unsigned long flags;
- spin_lock_irqsave(&pmbe->lock, flags);
+ raw_spin_lock_irqsave(&pmbe->lock, flags);
__set_pmb_entry(pmbe);
- spin_unlock_irqrestore(&pmbe->lock, flags);
+ raw_spin_unlock_irqrestore(&pmbe->lock, flags);
}
#endif /* CONFIG_PM */
@@ -368,7 +368,7 @@ int pmb_bolt_mapping(unsigned long vaddr, phys_addr_t phys,
return PTR_ERR(pmbe);
}
- spin_lock_irqsave(&pmbe->lock, flags);
+ raw_spin_lock_irqsave(&pmbe->lock, flags);
pmbe->size = pmb_sizes[i].size;
@@ -383,9 +383,10 @@ int pmb_bolt_mapping(unsigned long vaddr, phys_addr_t phys,
* entries for easier tear-down.
*/
if (likely(pmbp)) {
- spin_lock(&pmbp->lock);
+ raw_spin_lock_nested(&pmbp->lock,
+ SINGLE_DEPTH_NESTING);
pmbp->link = pmbe;
- spin_unlock(&pmbp->lock);
+ raw_spin_unlock(&pmbp->lock);
}
pmbp = pmbe;
@@ -398,7 +399,7 @@ int pmb_bolt_mapping(unsigned long vaddr, phys_addr_t phys,
i--;
mapped++;
- spin_unlock_irqrestore(&pmbe->lock, flags);
+ raw_spin_unlock_irqrestore(&pmbe->lock, flags);
}
} while (size >= SZ_16M);
@@ -627,15 +628,14 @@ static void __init pmb_synchronize(void)
continue;
}
- spin_lock_irqsave(&pmbe->lock, irqflags);
+ raw_spin_lock_irqsave(&pmbe->lock, irqflags);
for (j = 0; j < ARRAY_SIZE(pmb_sizes); j++)
if (pmb_sizes[j].flag == size)
pmbe->size = pmb_sizes[j].size;
if (pmbp) {
- spin_lock(&pmbp->lock);
-
+ raw_spin_lock_nested(&pmbp->lock, SINGLE_DEPTH_NESTING);
/*
* Compare the previous entry against the current one to
* see if the entries span a contiguous mapping. If so,
@@ -644,13 +644,12 @@ static void __init pmb_synchronize(void)
*/
if (pmb_can_merge(pmbp, pmbe))
pmbp->link = pmbe;
-
- spin_unlock(&pmbp->lock);
+ raw_spin_unlock(&pmbp->lock);
}
pmbp = pmbe;
- spin_unlock_irqrestore(&pmbe->lock, irqflags);
+ raw_spin_unlock_irqrestore(&pmbe->lock, irqflags);
}
}
@@ -757,7 +756,7 @@ static void __init pmb_resize(void)
/*
* Found it, now resize it.
*/
- spin_lock_irqsave(&pmbe->lock, flags);
+ raw_spin_lock_irqsave(&pmbe->lock, flags);
pmbe->size = SZ_16M;
pmbe->flags &= ~PMB_SZ_MASK;
@@ -767,7 +766,7 @@ static void __init pmb_resize(void)
__set_pmb_entry(pmbe);
- spin_unlock_irqrestore(&pmbe->lock, flags);
+ raw_spin_unlock_irqrestore(&pmbe->lock, flags);
}
read_unlock(&pmb_rwlock);
@@ -866,11 +865,9 @@ static int __init pmb_debugfs_init(void)
struct dentry *dentry;
dentry = debugfs_create_file("pmb", S_IFREG | S_IRUGO,
- sh_debugfs_root, NULL, &pmb_debugfs_fops);
+ arch_debugfs_dir, NULL, &pmb_debugfs_fops);
if (!dentry)
return -ENOMEM;
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
return 0;
}
diff --git a/arch/sh/mm/sram.c b/arch/sh/mm/sram.c
new file mode 100644
index 000000000000..bc156ec4545e
--- /dev/null
+++ b/arch/sh/mm/sram.c
@@ -0,0 +1,34 @@
+/*
+ * SRAM pool for tiny memories not otherwise managed.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/sram.h>
+
+/*
+ * This provides a standard SRAM pool for tiny memories that can be
+ * added either by the CPU or the platform code. Typical SRAM sizes
+ * to be inserted in to the pool will generally be less than the page
+ * size, with anything more reasonably sized handled as a NUMA memory
+ * node.
+ */
+struct gen_pool *sram_pool;
+
+static int __init sram_pool_init(void)
+{
+ /*
+ * This is a global pool, we don't care about node locality.
+ */
+ sram_pool = gen_pool_create(1, -1);
+ if (unlikely(!sram_pool))
+ return -ENOMEM;
+
+ return 0;
+}
+core_initcall(sram_pool_init);
diff --git a/arch/sh/mm/tlb-debugfs.c b/arch/sh/mm/tlb-debugfs.c
index 229bf75f28df..dea637a09246 100644
--- a/arch/sh/mm/tlb-debugfs.c
+++ b/arch/sh/mm/tlb-debugfs.c
@@ -151,15 +151,13 @@ static int __init tlb_debugfs_init(void)
{
struct dentry *itlb, *utlb;
- itlb = debugfs_create_file("itlb", S_IRUSR, sh_debugfs_root,
+ itlb = debugfs_create_file("itlb", S_IRUSR, arch_debugfs_dir,
(unsigned int *)TLB_TYPE_ITLB,
&tlb_debugfs_fops);
if (unlikely(!itlb))
return -ENOMEM;
- if (IS_ERR(itlb))
- return PTR_ERR(itlb);
- utlb = debugfs_create_file("utlb", S_IRUSR, sh_debugfs_root,
+ utlb = debugfs_create_file("utlb", S_IRUSR, arch_debugfs_dir,
(unsigned int *)TLB_TYPE_UTLB,
&tlb_debugfs_fops);
if (unlikely(!utlb)) {
@@ -167,11 +165,6 @@ static int __init tlb_debugfs_init(void)
return -ENOMEM;
}
- if (IS_ERR(utlb)) {
- debugfs_remove(itlb);
- return PTR_ERR(utlb);
- }
-
return 0;
}
module_init(tlb_debugfs_init);
diff --git a/arch/sh/mm/tlbflush_32.c b/arch/sh/mm/tlbflush_32.c
index 3fbe03ce8fe3..a6a20d6de4c0 100644
--- a/arch/sh/mm/tlbflush_32.c
+++ b/arch/sh/mm/tlbflush_32.c
@@ -119,3 +119,19 @@ void local_flush_tlb_mm(struct mm_struct *mm)
local_irq_restore(flags);
}
}
+
+void __flush_tlb_global(void)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ /*
+ * This is the most destructive of the TLB flushing options,
+ * and will tear down all of the UTLB/ITLB mappings, including
+ * wired entries.
+ */
+ __raw_writel(__raw_readl(MMUCR) | MMUCR_TI, MMUCR);
+
+ local_irq_restore(flags);
+}
diff --git a/arch/sh/mm/tlbflush_64.c b/arch/sh/mm/tlbflush_64.c
index 03db41cc1268..7f5810f5dfdc 100644
--- a/arch/sh/mm/tlbflush_64.c
+++ b/arch/sh/mm/tlbflush_64.c
@@ -455,6 +455,11 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
flush_tlb_all();
}
+void __flush_tlb_global(void)
+{
+ flush_tlb_all();
+}
+
void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
{
}
diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types
index b25aa554ee5e..9f56eb978024 100644
--- a/arch/sh/tools/mach-types
+++ b/arch/sh/tools/mach-types
@@ -52,6 +52,8 @@ MIGOR SH_MIGOR
RSK7201 SH_RSK7201
RSK7203 SH_RSK7203
AP325RXA SH_AP325RXA
+SH2007 SH_SH2007
+SH7757LCR SH_SH7757LCR
SH7763RDP SH_SH7763RDP
SH7785LCR SH_SH7785LCR
SH7785LCR_PT SH_SH7785LCR_PT
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 3e9d31401fb2..8e7bafc5dd0e 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -19,6 +19,7 @@ config SPARC
bool
default y
select OF
+ select OF_PROMTREE
select HAVE_IDE
select HAVE_OPROFILE
select HAVE_ARCH_KGDB if !SMP || SPARC64
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index deeb0fba8029..3c93f08ce187 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -7,7 +7,6 @@ header-y += display7seg.h
header-y += envctrl.h
header-y += fbio.h
header-y += jsflash.h
-header-y += openprom.h
header-y += openpromio.h
header-y += perfctr.h
header-y += psrcompat.h
diff --git a/arch/sparc/include/asm/floppy_32.h b/arch/sparc/include/asm/floppy_32.h
index c792830636de..86666f70322e 100644
--- a/arch/sparc/include/asm/floppy_32.h
+++ b/arch/sparc/include/asm/floppy_32.h
@@ -304,7 +304,8 @@ static struct linux_prom_registers fd_regs[2];
static int sun_floppy_init(void)
{
char state[128];
- int tnode, fd_node, num_regs;
+ phandle tnode, fd_node;
+ int num_regs;
struct resource r;
use_virtual_dma = 1;
diff --git a/arch/sparc/include/asm/highmem.h b/arch/sparc/include/asm/highmem.h
index ec23b0a87b98..3d7afbb7f4bb 100644
--- a/arch/sparc/include/asm/highmem.h
+++ b/arch/sparc/include/asm/highmem.h
@@ -70,8 +70,8 @@ static inline void kunmap(struct page *page)
kunmap_high(page);
}
-extern void *kmap_atomic(struct page *page, enum km_type type);
-extern void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
+extern void *__kmap_atomic(struct page *page);
+extern void __kunmap_atomic(void *kvaddr);
extern struct page *kmap_atomic_to_page(void *vaddr);
#define flush_cache_kmaps() flush_cache_all()
diff --git a/arch/sparc/include/asm/io_32.h b/arch/sparc/include/asm/io_32.h
index 2889574608db..c2ced21c9dc1 100644
--- a/arch/sparc/include/asm/io_32.h
+++ b/arch/sparc/include/asm/io_32.h
@@ -208,6 +208,21 @@ _memset_io(volatile void __iomem *dst, int c, __kernel_size_t n)
#define memset_io(d,c,sz) _memset_io(d,c,sz)
static inline void
+_sbus_memcpy_fromio(void *dst, const volatile void __iomem *src,
+ __kernel_size_t n)
+{
+ char *d = dst;
+
+ while (n--) {
+ char tmp = sbus_readb(src);
+ *d++ = tmp;
+ src++;
+ }
+}
+
+#define sbus_memcpy_fromio(d, s, sz) _sbus_memcpy_fromio(d, s, sz)
+
+static inline void
_memcpy_fromio(void *dst, const volatile void __iomem *src, __kernel_size_t n)
{
char *d = dst;
@@ -222,6 +237,22 @@ _memcpy_fromio(void *dst, const volatile void __iomem *src, __kernel_size_t n)
#define memcpy_fromio(d,s,sz) _memcpy_fromio(d,s,sz)
static inline void
+_sbus_memcpy_toio(volatile void __iomem *dst, const void *src,
+ __kernel_size_t n)
+{
+ const char *s = src;
+ volatile void __iomem *d = dst;
+
+ while (n--) {
+ char tmp = *s++;
+ sbus_writeb(tmp, d);
+ d++;
+ }
+}
+
+#define sbus_memcpy_toio(d, s, sz) _sbus_memcpy_toio(d, s, sz)
+
+static inline void
_memcpy_toio(volatile void __iomem *dst, const void *src, __kernel_size_t n)
{
const char *s = src;
diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h
index 9517d063c79c..9c8965415f0a 100644
--- a/arch/sparc/include/asm/io_64.h
+++ b/arch/sparc/include/asm/io_64.h
@@ -419,6 +419,21 @@ _memset_io(volatile void __iomem *dst, int c, __kernel_size_t n)
#define memset_io(d,c,sz) _memset_io(d,c,sz)
static inline void
+_sbus_memcpy_fromio(void *dst, const volatile void __iomem *src,
+ __kernel_size_t n)
+{
+ char *d = dst;
+
+ while (n--) {
+ char tmp = sbus_readb(src);
+ *d++ = tmp;
+ src++;
+ }
+}
+
+#define sbus_memcpy_fromio(d, s, sz) _sbus_memcpy_fromio(d, s, sz)
+
+static inline void
_memcpy_fromio(void *dst, const volatile void __iomem *src, __kernel_size_t n)
{
char *d = dst;
@@ -433,6 +448,22 @@ _memcpy_fromio(void *dst, const volatile void __iomem *src, __kernel_size_t n)
#define memcpy_fromio(d,s,sz) _memcpy_fromio(d,s,sz)
static inline void
+_sbus_memcpy_toio(volatile void __iomem *dst, const void *src,
+ __kernel_size_t n)
+{
+ const char *s = src;
+ volatile void __iomem *d = dst;
+
+ while (n--) {
+ char tmp = *s++;
+ sbus_writeb(tmp, d);
+ d++;
+ }
+}
+
+#define sbus_memcpy_toio(d, s, sz) _sbus_memcpy_toio(d, s, sz)
+
+static inline void
_memcpy_toio(volatile void __iomem *dst, const void *src, __kernel_size_t n)
{
const char *s = src;
diff --git a/arch/sparc/include/asm/openprom.h b/arch/sparc/include/asm/openprom.h
index 963e1a45c35f..81cd43432dc0 100644
--- a/arch/sparc/include/asm/openprom.h
+++ b/arch/sparc/include/asm/openprom.h
@@ -11,6 +11,8 @@
#define LINUX_OPPROM_MAGIC 0x10010407
#ifndef __ASSEMBLY__
+#include <linux/of.h>
+
/* V0 prom device operations. */
struct linux_dev_v0_funcs {
int (*v0_devopen)(char *device_str);
@@ -26,7 +28,7 @@ struct linux_dev_v0_funcs {
/* V2 and later prom device operations. */
struct linux_dev_v2_funcs {
- int (*v2_inst2pkg)(int d); /* Convert ihandle to phandle */
+ phandle (*v2_inst2pkg)(int d); /* Convert ihandle to phandle */
char * (*v2_dumb_mem_alloc)(char *va, unsigned sz);
void (*v2_dumb_mem_free)(char *va, unsigned sz);
@@ -168,12 +170,12 @@ struct linux_romvec {
/* Routines for traversing the prom device tree. */
struct linux_nodeops {
- int (*no_nextnode)(int node);
- int (*no_child)(int node);
- int (*no_proplen)(int node, const char *name);
- int (*no_getprop)(int node, const char *name, char *val);
- int (*no_setprop)(int node, const char *name, char *val, int len);
- char * (*no_nextprop)(int node, char *name);
+ phandle (*no_nextnode)(phandle node);
+ phandle (*no_child)(phandle node);
+ int (*no_proplen)(phandle node, const char *name);
+ int (*no_getprop)(phandle node, const char *name, char *val);
+ int (*no_setprop)(phandle node, const char *name, char *val, int len);
+ char * (*no_nextprop)(phandle node, char *name);
};
/* More fun PROM structures for device probing. */
diff --git a/arch/sparc/include/asm/oplib_32.h b/arch/sparc/include/asm/oplib_32.h
index 33e31ce6b31f..51296a6f5005 100644
--- a/arch/sparc/include/asm/oplib_32.h
+++ b/arch/sparc/include/asm/oplib_32.h
@@ -30,7 +30,7 @@ extern unsigned int prom_rev, prom_prev;
/* Root node of the prom device tree, this stays constant after
* initialization is complete.
*/
-extern int prom_root_node;
+extern phandle prom_root_node;
/* Pointer to prom structure containing the device tree traversal
* and usage utility functions. Only prom-lib should use these,
@@ -178,68 +178,68 @@ extern void prom_putsegment(int context, unsigned long virt_addr,
/* PROM device tree traversal functions... */
/* Get the child node of the given node, or zero if no child exists. */
-extern int prom_getchild(int parent_node);
+extern phandle prom_getchild(phandle parent_node);
/* Get the next sibling node of the given node, or zero if no further
* siblings exist.
*/
-extern int prom_getsibling(int node);
+extern phandle prom_getsibling(phandle node);
/* Get the length, at the passed node, of the given property type.
* Returns -1 on error (ie. no such property at this node).
*/
-extern int prom_getproplen(int thisnode, const char *property);
+extern int prom_getproplen(phandle thisnode, const char *property);
/* Fetch the requested property using the given buffer. Returns
* the number of bytes the prom put into your buffer or -1 on error.
*/
-extern int __must_check prom_getproperty(int thisnode, const char *property,
+extern int __must_check prom_getproperty(phandle thisnode, const char *property,
char *prop_buffer, int propbuf_size);
/* Acquire an integer property. */
-extern int prom_getint(int node, char *property);
+extern int prom_getint(phandle node, char *property);
/* Acquire an integer property, with a default value. */
-extern int prom_getintdefault(int node, char *property, int defval);
+extern int prom_getintdefault(phandle node, char *property, int defval);
/* Acquire a boolean property, 0=FALSE 1=TRUE. */
-extern int prom_getbool(int node, char *prop);
+extern int prom_getbool(phandle node, char *prop);
/* Acquire a string property, null string on error. */
-extern void prom_getstring(int node, char *prop, char *buf, int bufsize);
+extern void prom_getstring(phandle node, char *prop, char *buf, int bufsize);
/* Does the passed node have the given "name"? YES=1 NO=0 */
-extern int prom_nodematch(int thisnode, char *name);
+extern int prom_nodematch(phandle thisnode, char *name);
/* Search all siblings starting at the passed node for "name" matching
* the given string. Returns the node on success, zero on failure.
*/
-extern int prom_searchsiblings(int node_start, char *name);
+extern phandle prom_searchsiblings(phandle node_start, char *name);
/* Return the first property type, as a string, for the given node.
* Returns a null string on error.
*/
-extern char *prom_firstprop(int node, char *buffer);
+extern char *prom_firstprop(phandle node, char *buffer);
/* Returns the next property after the passed property for the given
* node. Returns null string on failure.
*/
-extern char *prom_nextprop(int node, char *prev_property, char *buffer);
+extern char *prom_nextprop(phandle node, char *prev_property, char *buffer);
/* Returns phandle of the path specified */
-extern int prom_finddevice(char *name);
+extern phandle prom_finddevice(char *name);
/* Returns 1 if the specified node has given property. */
-extern int prom_node_has_property(int node, char *property);
+extern int prom_node_has_property(phandle node, char *property);
/* Set the indicated property at the given node with the passed value.
* Returns the number of bytes of your value that the prom took.
*/
-extern int prom_setprop(int node, const char *prop_name, char *prop_value,
+extern int prom_setprop(phandle node, const char *prop_name, char *prop_value,
int value_size);
-extern int prom_pathtoinode(char *path);
-extern int prom_inst2pkg(int);
+extern phandle prom_pathtoinode(char *path);
+extern phandle prom_inst2pkg(int);
/* Dorking with Bus ranges... */
@@ -247,13 +247,13 @@ extern int prom_inst2pkg(int);
extern void prom_apply_obio_ranges(struct linux_prom_registers *obioregs, int nregs);
/* Apply ranges of any prom node (and optionally parent node as well) to registers. */
-extern void prom_apply_generic_ranges(int node, int parent,
+extern void prom_apply_generic_ranges(phandle node, phandle parent,
struct linux_prom_registers *sbusregs, int nregs);
/* CPU probing helpers. */
-int cpu_find_by_instance(int instance, int *prom_node, int *mid);
-int cpu_find_by_mid(int mid, int *prom_node);
-int cpu_get_hwmid(int prom_node);
+int cpu_find_by_instance(int instance, phandle *prom_node, int *mid);
+int cpu_find_by_mid(int mid, phandle *prom_node);
+int cpu_get_hwmid(phandle prom_node);
extern spinlock_t prom_lock;
diff --git a/arch/sparc/include/asm/oplib_64.h b/arch/sparc/include/asm/oplib_64.h
index 3e0b2d62303d..c9cc078e3e31 100644
--- a/arch/sparc/include/asm/oplib_64.h
+++ b/arch/sparc/include/asm/oplib_64.h
@@ -16,7 +16,7 @@ extern char prom_version[];
/* Root node of the prom device tree, this stays constant after
* initialization is complete.
*/
-extern int prom_root_node;
+extern phandle prom_root_node;
/* PROM stdin and stdout */
extern int prom_stdin, prom_stdout;
@@ -24,7 +24,7 @@ extern int prom_stdin, prom_stdout;
/* /chosen node of the prom device tree, this stays constant after
* initialization is complete.
*/
-extern int prom_chosen_node;
+extern phandle prom_chosen_node;
/* Helper values and strings in arch/sparc64/kernel/head.S */
extern const char prom_peer_name[];
@@ -218,68 +218,69 @@ extern void prom_unmap(unsigned long size, unsigned long vaddr);
/* PROM device tree traversal functions... */
/* Get the child node of the given node, or zero if no child exists. */
-extern int prom_getchild(int parent_node);
+extern phandle prom_getchild(phandle parent_node);
/* Get the next sibling node of the given node, or zero if no further
* siblings exist.
*/
-extern int prom_getsibling(int node);
+extern phandle prom_getsibling(phandle node);
/* Get the length, at the passed node, of the given property type.
* Returns -1 on error (ie. no such property at this node).
*/
-extern int prom_getproplen(int thisnode, const char *property);
+extern int prom_getproplen(phandle thisnode, const char *property);
/* Fetch the requested property using the given buffer. Returns
* the number of bytes the prom put into your buffer or -1 on error.
*/
-extern int prom_getproperty(int thisnode, const char *property,
+extern int prom_getproperty(phandle thisnode, const char *property,
char *prop_buffer, int propbuf_size);
/* Acquire an integer property. */
-extern int prom_getint(int node, const char *property);
+extern int prom_getint(phandle node, const char *property);
/* Acquire an integer property, with a default value. */
-extern int prom_getintdefault(int node, const char *property, int defval);
+extern int prom_getintdefault(phandle node, const char *property, int defval);
/* Acquire a boolean property, 0=FALSE 1=TRUE. */
-extern int prom_getbool(int node, const char *prop);
+extern int prom_getbool(phandle node, const char *prop);
/* Acquire a string property, null string on error. */
-extern void prom_getstring(int node, const char *prop, char *buf, int bufsize);
+extern void prom_getstring(phandle node, const char *prop, char *buf,
+ int bufsize);
/* Does the passed node have the given "name"? YES=1 NO=0 */
-extern int prom_nodematch(int thisnode, const char *name);
+extern int prom_nodematch(phandle thisnode, const char *name);
/* Search all siblings starting at the passed node for "name" matching
* the given string. Returns the node on success, zero on failure.
*/
-extern int prom_searchsiblings(int node_start, const char *name);
+extern phandle prom_searchsiblings(phandle node_start, const char *name);
/* Return the first property type, as a string, for the given node.
* Returns a null string on error. Buffer should be at least 32B long.
*/
-extern char *prom_firstprop(int node, char *buffer);
+extern char *prom_firstprop(phandle node, char *buffer);
/* Returns the next property after the passed property for the given
* node. Returns null string on failure. Buffer should be at least 32B long.
*/
-extern char *prom_nextprop(int node, const char *prev_property, char *buffer);
+extern char *prom_nextprop(phandle node, const char *prev_property, char *buf);
/* Returns 1 if the specified node has given property. */
-extern int prom_node_has_property(int node, const char *property);
+extern int prom_node_has_property(phandle node, const char *property);
/* Returns phandle of the path specified */
-extern int prom_finddevice(const char *name);
+extern phandle prom_finddevice(const char *name);
/* Set the indicated property at the given node with the passed value.
* Returns the number of bytes of your value that the prom took.
*/
-extern int prom_setprop(int node, const char *prop_name, char *prop_value,
+extern int prom_setprop(phandle node, const char *prop_name, char *prop_value,
int value_size);
-extern int prom_pathtoinode(const char *path);
-extern int prom_inst2pkg(int);
+extern phandle prom_pathtoinode(const char *path);
+extern phandle prom_inst2pkg(int);
extern int prom_service_exists(const char *service_name);
extern void prom_sun4v_guest_soft_state(void);
diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h
index 5312782f0b5e..948b686ec089 100644
--- a/arch/sparc/include/asm/pci_64.h
+++ b/arch/sparc/include/asm/pci_64.h
@@ -38,7 +38,7 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
* types on sparc64. However, it requires that the device
* can drive enough of the 64 bits.
*/
-#define PCI64_REQUIRED_MASK (~(dma64_addr_t)0)
+#define PCI64_REQUIRED_MASK (~(u64)0)
#define PCI64_ADDR_BASE 0xfffc000000000000UL
#ifdef CONFIG_PCI
diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h
index 0ece77f47753..303bd4dc8292 100644
--- a/arch/sparc/include/asm/pgtable_32.h
+++ b/arch/sparc/include/asm/pgtable_32.h
@@ -304,10 +304,7 @@ BTFIXUPDEF_CALL(pte_t *, pte_offset_kernel, pmd_t *, unsigned long)
* and sun4c is guaranteed to have no highmem anyway.
*/
#define pte_offset_map(d, a) pte_offset_kernel(d,a)
-#define pte_offset_map_nested(d, a) pte_offset_kernel(d,a)
-
#define pte_unmap(pte) do{}while(0)
-#define pte_unmap_nested(pte) do{}while(0)
/* Certain architectures need to do special things when pte's
* within a page table are directly modified. Thus, the following
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index f5b5fa76c02d..f8dddb7045bb 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -652,9 +652,7 @@ static inline int pte_special(pte_t pte)
((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
#define pte_offset_kernel pte_index
#define pte_offset_map pte_index
-#define pte_offset_map_nested pte_index
#define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
/* Actual page table PTE updates. */
extern void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t orig);
diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h
index 291f12575edd..56bbaadef646 100644
--- a/arch/sparc/include/asm/prom.h
+++ b/arch/sparc/include/asm/prom.h
@@ -18,6 +18,7 @@
* 2 of the License, or (at your option) any later version.
*/
#include <linux/types.h>
+#include <linux/of_pdt.h>
#include <linux/proc_fs.h>
#include <linux/mutex.h>
#include <asm/atomic.h>
@@ -67,8 +68,8 @@ extern struct device_node *of_console_device;
extern char *of_console_path;
extern char *of_console_options;
-extern void (*prom_build_more)(struct device_node *dp, struct device_node ***nextp);
-extern char *build_full_name(struct device_node *dp);
+extern void irq_trans_init(struct device_node *dp);
+extern char *build_path_component(struct device_node *dp);
#endif /* __KERNEL__ */
#endif /* _SPARC_PROM_H */
diff --git a/arch/sparc/kernel/auxio_32.c b/arch/sparc/kernel/auxio_32.c
index ee8d214cae1e..35f48837871a 100644
--- a/arch/sparc/kernel/auxio_32.c
+++ b/arch/sparc/kernel/auxio_32.c
@@ -23,7 +23,7 @@ static DEFINE_SPINLOCK(auxio_lock);
void __init auxio_probe(void)
{
- int node, auxio_nd;
+ phandle node, auxio_nd;
struct linux_prom_registers auxregs[1];
struct resource r;
@@ -113,7 +113,7 @@ volatile unsigned char * auxio_power_register = NULL;
void __init auxio_power_probe(void)
{
struct linux_prom_registers regs;
- int node;
+ phandle node;
struct resource r;
/* Attempt to find the sun4m power control node. */
diff --git a/arch/sparc/kernel/btext.c b/arch/sparc/kernel/btext.c
index 8cc2d56ffe9a..89aa4eb20cf5 100644
--- a/arch/sparc/kernel/btext.c
+++ b/arch/sparc/kernel/btext.c
@@ -40,7 +40,7 @@ static unsigned char *dispDeviceBase __force_data;
static unsigned char vga_font[cmapsz];
-static int __init btext_initialize(unsigned int node)
+static int __init btext_initialize(phandle node)
{
unsigned int width, height, depth, pitch;
unsigned long address = 0;
@@ -309,7 +309,7 @@ static struct console btext_console = {
int __init btext_find_display(void)
{
- unsigned int node;
+ phandle node;
char type[32];
int ret;
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
index 62dc7a021413..d2eddd6647cd 100644
--- a/arch/sparc/kernel/devices.c
+++ b/arch/sparc/kernel/devices.c
@@ -31,9 +31,9 @@ static char *cpu_mid_prop(void)
return "mid";
}
-static int check_cpu_node(int nd, int *cur_inst,
- int (*compare)(int, int, void *), void *compare_arg,
- int *prom_node, int *mid)
+static int check_cpu_node(phandle nd, int *cur_inst,
+ int (*compare)(phandle, int, void *), void *compare_arg,
+ phandle *prom_node, int *mid)
{
if (!compare(nd, *cur_inst, compare_arg)) {
if (prom_node)
@@ -51,8 +51,8 @@ static int check_cpu_node(int nd, int *cur_inst,
return -ENODEV;
}
-static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
- int *prom_node, int *mid)
+static int __cpu_find_by(int (*compare)(phandle, int, void *),
+ void *compare_arg, phandle *prom_node, int *mid)
{
struct device_node *dp;
int cur_inst;
@@ -71,7 +71,7 @@ static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
return -ENODEV;
}
-static int cpu_instance_compare(int nd, int instance, void *_arg)
+static int cpu_instance_compare(phandle nd, int instance, void *_arg)
{
int desired_instance = (int) _arg;
@@ -80,13 +80,13 @@ static int cpu_instance_compare(int nd, int instance, void *_arg)
return -ENODEV;
}
-int cpu_find_by_instance(int instance, int *prom_node, int *mid)
+int cpu_find_by_instance(int instance, phandle *prom_node, int *mid)
{
return __cpu_find_by(cpu_instance_compare, (void *)instance,
prom_node, mid);
}
-static int cpu_mid_compare(int nd, int instance, void *_arg)
+static int cpu_mid_compare(phandle nd, int instance, void *_arg)
{
int desired_mid = (int) _arg;
int this_mid;
@@ -98,7 +98,7 @@ static int cpu_mid_compare(int nd, int instance, void *_arg)
return -ENODEV;
}
-int cpu_find_by_mid(int mid, int *prom_node)
+int cpu_find_by_mid(int mid, phandle *prom_node)
{
return __cpu_find_by(cpu_mid_compare, (void *)mid,
prom_node, NULL);
@@ -108,7 +108,7 @@ int cpu_find_by_mid(int mid, int *prom_node)
* address (0-3). This gives us the true hardware mid, which might have
* some other bits set. On 4d hardware and software mids are the same.
*/
-int cpu_get_hwmid(int prom_node)
+int cpu_get_hwmid(phandle prom_node)
{
return prom_getintdefault(prom_node, cpu_mid_prop(), -ENODEV);
}
@@ -119,7 +119,8 @@ void __init device_scan(void)
#ifndef CONFIG_SMP
{
- int err, cpu_node;
+ phandle cpu_node;
+ int err;
err = cpu_find_by_instance(0, &cpu_node, NULL);
if (err) {
/* Probably a sun4e, Sun is trying to trick us ;-) */
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c
index 6a7b4dbc8e09..2d51527d810f 100644
--- a/arch/sparc/kernel/leon_kernel.c
+++ b/arch/sparc/kernel/leon_kernel.c
@@ -282,5 +282,5 @@ void __init leon_init_IRQ(void)
void __init leon_init(void)
{
- prom_build_more = &leon_node_init;
+ of_pdt_build_more = &leon_node_init;
}
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index d36a8d391ca0..aeaa09a3c655 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -284,7 +284,7 @@ int __init pcic_probe(void)
struct linux_prom_registers regs[PROMREG_MAX];
struct linux_pbm_info* pbm;
char namebuf[64];
- int node;
+ phandle node;
int err;
if (pcic0_up) {
@@ -440,7 +440,7 @@ static int __devinit pdev_to_pnode(struct linux_pbm_info *pbm,
{
struct linux_prom_pci_registers regs[PROMREG_MAX];
int err;
- int node = prom_getchild(pbm->prom_node);
+ phandle node = prom_getchild(pbm->prom_node);
while(node) {
err = prom_getproperty(node, "reg",
diff --git a/arch/sparc/kernel/prom.h b/arch/sparc/kernel/prom.h
index eeb04a782ec8..cf5fe1c0b024 100644
--- a/arch/sparc/kernel/prom.h
+++ b/arch/sparc/kernel/prom.h
@@ -4,12 +4,6 @@
#include <linux/spinlock.h>
#include <asm/prom.h>
-extern void * prom_early_alloc(unsigned long size);
-extern void irq_trans_init(struct device_node *dp);
-
-extern unsigned int prom_unique_id;
-
-extern char *build_path_component(struct device_node *dp);
extern void of_console_init(void);
extern unsigned int prom_early_allocated;
diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c
index 1f830da2ddf2..ed25834328f4 100644
--- a/arch/sparc/kernel/prom_common.c
+++ b/arch/sparc/kernel/prom_common.c
@@ -20,14 +20,13 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/of.h>
+#include <linux/of_pdt.h>
#include <asm/prom.h>
#include <asm/oplib.h>
#include <asm/leon.h>
#include "prom.h"
-void (*prom_build_more)(struct device_node *dp, struct device_node ***nextp);
-
struct device_node *of_console_device;
EXPORT_SYMBOL(of_console_device);
@@ -119,192 +118,47 @@ int of_find_in_proplist(const char *list, const char *match, int len)
}
EXPORT_SYMBOL(of_find_in_proplist);
-unsigned int prom_unique_id;
-
-static struct property * __init build_one_prop(phandle node, char *prev,
- char *special_name,
- void *special_val,
- int special_len)
+/*
+ * SPARC32 and SPARC64's prom_nextprop() do things differently
+ * here, despite sharing the same interface. SPARC32 doesn't fill in 'buf',
+ * returning NULL on an error. SPARC64 fills in 'buf', but sets it to an
+ * empty string upon error.
+ */
+static int __init handle_nextprop_quirks(char *buf, const char *name)
{
- static struct property *tmp = NULL;
- struct property *p;
- const char *name;
-
- if (tmp) {
- p = tmp;
- memset(p, 0, sizeof(*p) + 32);
- tmp = NULL;
- } else {
- p = prom_early_alloc(sizeof(struct property) + 32);
- p->unique_id = prom_unique_id++;
- }
-
- p->name = (char *) (p + 1);
- if (special_name) {
- strcpy(p->name, special_name);
- p->length = special_len;
- p->value = prom_early_alloc(special_len);
- memcpy(p->value, special_val, special_len);
- } else {
- if (prev == NULL) {
- name = prom_firstprop(node, p->name);
- } else {
- name = prom_nextprop(node, prev, p->name);
- }
+ if (!name || strlen(name) == 0)
+ return -1;
- if (!name || strlen(name) == 0) {
- tmp = p;
- return NULL;
- }
#ifdef CONFIG_SPARC32
- strcpy(p->name, name);
+ strcpy(buf, name);
#endif
- p->length = prom_getproplen(node, p->name);
- if (p->length <= 0) {
- p->length = 0;
- } else {
- int len;
-
- p->value = prom_early_alloc(p->length + 1);
- len = prom_getproperty(node, p->name, p->value,
- p->length);
- if (len <= 0)
- p->length = 0;
- ((unsigned char *)p->value)[p->length] = '\0';
- }
- }
- return p;
-}
-
-static struct property * __init build_prop_list(phandle node)
-{
- struct property *head, *tail;
-
- head = tail = build_one_prop(node, NULL,
- ".node", &node, sizeof(node));
-
- tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
- tail = tail->next;
- while(tail) {
- tail->next = build_one_prop(node, tail->name,
- NULL, NULL, 0);
- tail = tail->next;
- }
-
- return head;
-}
-
-static char * __init get_one_property(phandle node, const char *name)
-{
- char *buf = "<NULL>";
- int len;
-
- len = prom_getproplen(node, name);
- if (len > 0) {
- buf = prom_early_alloc(len);
- len = prom_getproperty(node, name, buf, len);
- }
-
- return buf;
-}
-
-static struct device_node * __init prom_create_node(phandle node,
- struct device_node *parent)
-{
- struct device_node *dp;
-
- if (!node)
- return NULL;
-
- dp = prom_early_alloc(sizeof(*dp));
- dp->unique_id = prom_unique_id++;
- dp->parent = parent;
-
- kref_init(&dp->kref);
-
- dp->name = get_one_property(node, "name");
- dp->type = get_one_property(node, "device_type");
- dp->phandle = node;
-
- dp->properties = build_prop_list(node);
-
- irq_trans_init(dp);
-
- return dp;
-}
-
-char * __init build_full_name(struct device_node *dp)
-{
- int len, ourlen, plen;
- char *n;
-
- plen = strlen(dp->parent->full_name);
- ourlen = strlen(dp->path_component_name);
- len = ourlen + plen + 2;
-
- n = prom_early_alloc(len);
- strcpy(n, dp->parent->full_name);
- if (!of_node_is_root(dp->parent)) {
- strcpy(n + plen, "/");
- plen++;
- }
- strcpy(n + plen, dp->path_component_name);
-
- return n;
+ return 0;
}
-static struct device_node * __init prom_build_tree(struct device_node *parent,
- phandle node,
- struct device_node ***nextp)
+static int __init prom_common_nextprop(phandle node, char *prev, char *buf)
{
- struct device_node *ret = NULL, *prev_sibling = NULL;
- struct device_node *dp;
-
- while (1) {
- dp = prom_create_node(node, parent);
- if (!dp)
- break;
-
- if (prev_sibling)
- prev_sibling->sibling = dp;
-
- if (!ret)
- ret = dp;
- prev_sibling = dp;
-
- *(*nextp) = dp;
- *nextp = &dp->allnext;
-
- dp->path_component_name = build_path_component(dp);
- dp->full_name = build_full_name(dp);
-
- dp->child = prom_build_tree(dp, prom_getchild(node), nextp);
-
- if (prom_build_more)
- prom_build_more(dp, nextp);
-
- node = prom_getsibling(node);
- }
+ const char *name;
- return ret;
+ buf[0] = '\0';
+ name = prom_nextprop(node, prev, buf);
+ return handle_nextprop_quirks(buf, name);
}
unsigned int prom_early_allocated __initdata;
+static struct of_pdt_ops prom_sparc_ops __initdata = {
+ .nextprop = prom_common_nextprop,
+ .getproplen = prom_getproplen,
+ .getproperty = prom_getproperty,
+ .getchild = prom_getchild,
+ .getsibling = prom_getsibling,
+};
+
void __init prom_build_devicetree(void)
{
- struct device_node **nextp;
-
- allnodes = prom_create_node(prom_root_node, NULL);
- allnodes->path_component_name = "";
- allnodes->full_name = "/";
-
- nextp = &allnodes->allnext;
- allnodes->child = prom_build_tree(allnodes,
- prom_getchild(allnodes->phandle),
- &nextp);
+ of_pdt_build_devicetree(prom_root_node, &prom_sparc_ops);
of_console_init();
- printk("PROM: Built device tree with %u bytes of memory.\n",
- prom_early_allocated);
+ pr_info("PROM: Built device tree with %u bytes of memory.\n",
+ prom_early_allocated);
}
diff --git a/arch/sparc/kernel/ptrace_32.c b/arch/sparc/kernel/ptrace_32.c
index e608f397e11f..27b9e93d0121 100644
--- a/arch/sparc/kernel/ptrace_32.c
+++ b/arch/sparc/kernel/ptrace_32.c
@@ -323,18 +323,35 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
return &user_sparc32_view;
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+struct fps {
+ unsigned long regs[32];
+ unsigned long fsr;
+ unsigned long flags;
+ unsigned long extra;
+ unsigned long fpqd;
+ struct fq {
+ unsigned long *insnaddr;
+ unsigned long insn;
+ } fpq[16];
+};
+
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
+ void __user *addr2p;
const struct user_regset_view *view;
+ struct pt_regs __user *pregs;
+ struct fps __user *fps;
int ret;
view = task_user_regset_view(current);
+ addr2p = (void __user *) addr2;
+ pregs = (struct pt_regs __user *) addr;
+ fps = (struct fps __user *) addr;
switch(request) {
case PTRACE_GETREGS: {
- struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
-
ret = copy_regset_to_user(child, view, REGSET_GENERAL,
32 * sizeof(u32),
4 * sizeof(u32),
@@ -348,8 +365,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
case PTRACE_SETREGS: {
- struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
-
ret = copy_regset_from_user(child, view, REGSET_GENERAL,
32 * sizeof(u32),
4 * sizeof(u32),
@@ -363,19 +378,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
case PTRACE_GETFPREGS: {
- struct fps {
- unsigned long regs[32];
- unsigned long fsr;
- unsigned long flags;
- unsigned long extra;
- unsigned long fpqd;
- struct fq {
- unsigned long *insnaddr;
- unsigned long insn;
- } fpq[16];
- };
- struct fps __user *fps = (struct fps __user *) addr;
-
ret = copy_regset_to_user(child, view, REGSET_FP,
0 * sizeof(u32),
32 * sizeof(u32),
@@ -397,19 +399,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
case PTRACE_SETFPREGS: {
- struct fps {
- unsigned long regs[32];
- unsigned long fsr;
- unsigned long flags;
- unsigned long extra;
- unsigned long fpqd;
- struct fq {
- unsigned long *insnaddr;
- unsigned long insn;
- } fpq[16];
- };
- struct fps __user *fps = (struct fps __user *) addr;
-
ret = copy_regset_from_user(child, view, REGSET_FP,
0 * sizeof(u32),
32 * sizeof(u32),
@@ -424,8 +413,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_READTEXT:
case PTRACE_READDATA:
- ret = ptrace_readdata(child, addr,
- (void __user *) addr2, data);
+ ret = ptrace_readdata(child, addr, addr2p, data);
if (ret == data)
ret = 0;
@@ -435,8 +423,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_WRITETEXT:
case PTRACE_WRITEDATA:
- ret = ptrace_writedata(child, (void __user *) addr2,
- addr, data);
+ ret = ptrace_writedata(child, addr2p, addr, data);
if (ret == data)
ret = 0;
diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c
index aa90da08bf61..9ccc812bc09e 100644
--- a/arch/sparc/kernel/ptrace_64.c
+++ b/arch/sparc/kernel/ptrace_64.c
@@ -969,16 +969,19 @@ struct fps {
unsigned long fsr;
};
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
const struct user_regset_view *view = task_user_regset_view(current);
unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4];
struct pt_regs __user *pregs;
struct fps __user *fps;
+ void __user *addr2p;
int ret;
- pregs = (struct pt_regs __user *) (unsigned long) addr;
- fps = (struct fps __user *) (unsigned long) addr;
+ pregs = (struct pt_regs __user *) addr;
+ fps = (struct fps __user *) addr;
+ addr2p = (void __user *) addr2;
switch (request) {
case PTRACE_PEEKUSR:
@@ -1029,8 +1032,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_READTEXT:
case PTRACE_READDATA:
- ret = ptrace_readdata(child, addr,
- (char __user *)addr2, data);
+ ret = ptrace_readdata(child, addr, addr2p, data);
if (ret == data)
ret = 0;
else if (ret >= 0)
@@ -1039,8 +1041,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_WRITETEXT:
case PTRACE_WRITEDATA:
- ret = ptrace_writedata(child, (char __user *) addr2,
- addr, data);
+ ret = ptrace_writedata(child, addr2p, addr, data);
if (ret == data)
ret = 0;
else if (ret >= 0)
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index 5f72de67588b..29bafe051bb1 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -315,7 +315,7 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_IP_PNP
if (!ic_set_manually) {
- int chosen = prom_finddevice ("/chosen");
+ phandle chosen = prom_finddevice("/chosen");
u32 cl, sv, gw;
cl = prom_getintdefault (chosen, "client-ip", 0);
diff --git a/arch/sparc/kernel/starfire.c b/arch/sparc/kernel/starfire.c
index 060d0f3a6151..a4446c0fb7a1 100644
--- a/arch/sparc/kernel/starfire.c
+++ b/arch/sparc/kernel/starfire.c
@@ -23,7 +23,7 @@ int this_is_starfire = 0;
void check_if_starfire(void)
{
- int ssnode = prom_finddevice("/ssp-serial");
+ phandle ssnode = prom_finddevice("/ssp-serial");
if (ssnode != 0 && ssnode != -1)
this_is_starfire = 1;
}
diff --git a/arch/sparc/kernel/tadpole.c b/arch/sparc/kernel/tadpole.c
index f476a5f4af6a..9aba8bd5a78b 100644
--- a/arch/sparc/kernel/tadpole.c
+++ b/arch/sparc/kernel/tadpole.c
@@ -100,7 +100,7 @@ static void swift_clockstop(void)
void __init clock_stop_probe(void)
{
- unsigned int node, clk_nd;
+ phandle node, clk_nd;
char name[20];
prom_getstring(prom_root_node, "name", name, sizeof(name));
diff --git a/arch/sparc/mm/highmem.c b/arch/sparc/mm/highmem.c
index e139e9cbf5f7..4730eac0747b 100644
--- a/arch/sparc/mm/highmem.c
+++ b/arch/sparc/mm/highmem.c
@@ -29,17 +29,17 @@
#include <asm/tlbflush.h>
#include <asm/fixmap.h>
-void *kmap_atomic(struct page *page, enum km_type type)
+void *__kmap_atomic(struct page *page)
{
- unsigned long idx;
unsigned long vaddr;
+ long idx, type;
/* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
pagefault_disable();
if (!PageHighMem(page))
return page_address(page);
- debug_kmap_atomic(type);
+ type = kmap_atomic_idx_push();
idx = type + KM_TYPE_NR*smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
@@ -63,44 +63,52 @@ void *kmap_atomic(struct page *page, enum km_type type)
return (void*) vaddr;
}
-EXPORT_SYMBOL(kmap_atomic);
+EXPORT_SYMBOL(__kmap_atomic);
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
{
-#ifdef CONFIG_DEBUG_HIGHMEM
unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
- unsigned long idx = type + KM_TYPE_NR*smp_processor_id();
+ int type;
if (vaddr < FIXADDR_START) { // FIXME
pagefault_enable();
return;
}
- BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx));
+ type = kmap_atomic_idx();
-/* XXX Fix - Anton */
+#ifdef CONFIG_DEBUG_HIGHMEM
+ {
+ unsigned long idx;
+
+ idx = type + KM_TYPE_NR * smp_processor_id();
+ BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx));
+
+ /* XXX Fix - Anton */
#if 0
- __flush_cache_one(vaddr);
+ __flush_cache_one(vaddr);
#else
- flush_cache_all();
+ flush_cache_all();
#endif
- /*
- * force other mappings to Oops if they'll try to access
- * this pte without first remap it
- */
- pte_clear(&init_mm, vaddr, kmap_pte-idx);
-/* XXX Fix - Anton */
+ /*
+ * force other mappings to Oops if they'll try to access
+ * this pte without first remap it
+ */
+ pte_clear(&init_mm, vaddr, kmap_pte-idx);
+ /* XXX Fix - Anton */
#if 0
- __flush_tlb_one(vaddr);
+ __flush_tlb_one(vaddr);
#else
- flush_tlb_all();
+ flush_tlb_all();
#endif
+ }
#endif
+ kmap_atomic_idx_pop();
pagefault_enable();
}
-EXPORT_SYMBOL(kunmap_atomic_notypecheck);
+EXPORT_SYMBOL(__kunmap_atomic);
/* We may be fed a pagetable here by ptep_to_xxx and others. */
struct page *kmap_atomic_to_page(void *ptr)
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 4c2572773b55..2f6ae1d1fb6b 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -88,7 +88,7 @@ static void __init read_obp_memory(const char *property,
struct linux_prom64_registers *regs,
int *num_ents)
{
- int node = prom_finddevice("/memory");
+ phandle node = prom_finddevice("/memory");
int prop_size = prom_getproplen(node, property);
int ents, ret, i;
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index b0b43aa5e45a..92319aa8b662 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1262,7 +1262,8 @@ extern unsigned long bootmem_init(unsigned long *pages_avail);
void __init srmmu_paging_init(void)
{
- int i, cpunode;
+ int i;
+ phandle cpunode;
char node_str[128];
pgd_t *pgd;
pmd_t *pmd;
@@ -1398,7 +1399,8 @@ static void __init srmmu_is_bad(void)
static void __init init_vac_layout(void)
{
- int nd, cache_lines;
+ phandle nd;
+ int cache_lines;
char node_str[128];
#ifdef CONFIG_SMP
int cpu = 0;
@@ -2082,7 +2084,7 @@ static void __init get_srmmu_type(void)
/* Next check for Fujitsu Swift. */
if(psr_typ == 0 && psr_vers == 4) {
- int cpunode;
+ phandle cpunode;
char node_str[128];
/* Look if it is not a TurboSparc emulating Swift... */
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index 4289f90f8697..ddd0d86e508e 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -420,7 +420,7 @@ volatile unsigned long __iomem *sun4c_memerr_reg = NULL;
void __init sun4c_probe_memerr_reg(void)
{
- int node;
+ phandle node;
struct linux_prom_registers regs[1];
node = prom_getchild(prom_root_node);
diff --git a/arch/sparc/prom/init_32.c b/arch/sparc/prom/init_32.c
index ccb36c7f9b8c..d342dba4dd54 100644
--- a/arch/sparc/prom/init_32.c
+++ b/arch/sparc/prom/init_32.c
@@ -20,7 +20,7 @@ enum prom_major_version prom_vers;
unsigned int prom_rev, prom_prev;
/* The root node of the prom device tree. */
-int prom_root_node;
+phandle prom_root_node;
EXPORT_SYMBOL(prom_root_node);
/* Pointer to the device tree operations structure. */
diff --git a/arch/sparc/prom/init_64.c b/arch/sparc/prom/init_64.c
index 7b00f89490a4..3ff911e7d25b 100644
--- a/arch/sparc/prom/init_64.c
+++ b/arch/sparc/prom/init_64.c
@@ -19,7 +19,7 @@ char prom_version[80];
/* The root node of the prom device tree. */
int prom_stdin, prom_stdout;
-int prom_chosen_node;
+phandle prom_chosen_node;
/* You must call prom_init() before you attempt to use any of the
* routines in the prom library. It returns 0 on success, 1 on
@@ -30,7 +30,7 @@ extern void prom_cif_init(void *, void *);
void __init prom_init(void *cif_handler, void *cif_stack)
{
- int node;
+ phandle node;
prom_cif_init(cif_handler, cif_stack);
diff --git a/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c
index fac7899a29c3..3f263a64857d 100644
--- a/arch/sparc/prom/memory.c
+++ b/arch/sparc/prom/memory.c
@@ -31,7 +31,8 @@ static int __init prom_meminit_v0(void)
static int __init prom_meminit_v2(void)
{
struct linux_prom_registers reg[64];
- int node, size, num_ents, i;
+ phandle node;
+ int size, num_ents, i;
node = prom_searchsiblings(prom_getchild(prom_root_node), "memory");
size = prom_getproperty(node, "available", (char *) reg, sizeof(reg));
diff --git a/arch/sparc/prom/misc_64.c b/arch/sparc/prom/misc_64.c
index 6cb1581d6aef..d24bc44e361e 100644
--- a/arch/sparc/prom/misc_64.c
+++ b/arch/sparc/prom/misc_64.c
@@ -183,7 +183,8 @@ unsigned char prom_get_idprom(char *idbuf, int num_bytes)
int prom_get_mmu_ihandle(void)
{
- int node, ret;
+ phandle node;
+ int ret;
if (prom_mmu_ihandle_cache != 0)
return prom_mmu_ihandle_cache;
@@ -201,7 +202,8 @@ int prom_get_mmu_ihandle(void)
static int prom_get_memory_ihandle(void)
{
static int memory_ihandle_cache;
- int node, ret;
+ phandle node;
+ int ret;
if (memory_ihandle_cache != 0)
return memory_ihandle_cache;
diff --git a/arch/sparc/prom/ranges.c b/arch/sparc/prom/ranges.c
index aeff43e44e45..541fc829c207 100644
--- a/arch/sparc/prom/ranges.c
+++ b/arch/sparc/prom/ranges.c
@@ -68,7 +68,7 @@ EXPORT_SYMBOL(prom_apply_obio_ranges);
void __init prom_ranges_init(void)
{
- int node, obio_node;
+ phandle node, obio_node;
int success;
num_obio_ranges = 0;
@@ -89,8 +89,8 @@ void __init prom_ranges_init(void)
prom_printf("PROMLIB: obio_ranges %d\n", num_obio_ranges);
}
-void
-prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs)
+void prom_apply_generic_ranges(phandle node, phandle parent,
+ struct linux_prom_registers *regs, int nregs)
{
int success;
int num_ranges;
diff --git a/arch/sparc/prom/tree_32.c b/arch/sparc/prom/tree_32.c
index b21592f8e3fe..63e08e149774 100644
--- a/arch/sparc/prom/tree_32.c
+++ b/arch/sparc/prom/tree_32.c
@@ -20,10 +20,10 @@ extern void restore_current(void);
static char promlib_buf[128];
/* Internal version of prom_getchild that does not alter return values. */
-int __prom_getchild(int node)
+phandle __prom_getchild(phandle node)
{
unsigned long flags;
- int cnode;
+ phandle cnode;
spin_lock_irqsave(&prom_lock, flags);
cnode = prom_nodeops->no_child(node);
@@ -36,9 +36,9 @@ int __prom_getchild(int node)
/* Return the child of node 'node' or zero if no this node has no
* direct descendent.
*/
-int prom_getchild(int node)
+phandle prom_getchild(phandle node)
{
- int cnode;
+ phandle cnode;
if (node == -1)
return 0;
@@ -52,10 +52,10 @@ int prom_getchild(int node)
EXPORT_SYMBOL(prom_getchild);
/* Internal version of prom_getsibling that does not alter return values. */
-int __prom_getsibling(int node)
+phandle __prom_getsibling(phandle node)
{
unsigned long flags;
- int cnode;
+ phandle cnode;
spin_lock_irqsave(&prom_lock, flags);
cnode = prom_nodeops->no_nextnode(node);
@@ -68,9 +68,9 @@ int __prom_getsibling(int node)
/* Return the next sibling of node 'node' or zero if no more siblings
* at this level of depth in the tree.
*/
-int prom_getsibling(int node)
+phandle prom_getsibling(phandle node)
{
- int sibnode;
+ phandle sibnode;
if (node == -1)
return 0;
@@ -86,7 +86,7 @@ EXPORT_SYMBOL(prom_getsibling);
/* Return the length in bytes of property 'prop' at node 'node'.
* Return -1 on error.
*/
-int prom_getproplen(int node, const char *prop)
+int prom_getproplen(phandle node, const char *prop)
{
int ret;
unsigned long flags;
@@ -106,7 +106,7 @@ EXPORT_SYMBOL(prom_getproplen);
* 'buffer' which has a size of 'bufsize'. If the acquisition
* was successful the length will be returned, else -1 is returned.
*/
-int prom_getproperty(int node, const char *prop, char *buffer, int bufsize)
+int prom_getproperty(phandle node, const char *prop, char *buffer, int bufsize)
{
int plen, ret;
unsigned long flags;
@@ -126,7 +126,7 @@ EXPORT_SYMBOL(prom_getproperty);
/* Acquire an integer property and return its value. Returns -1
* on failure.
*/
-int prom_getint(int node, char *prop)
+int prom_getint(phandle node, char *prop)
{
static int intprop;
@@ -140,7 +140,7 @@ EXPORT_SYMBOL(prom_getint);
/* Acquire an integer property, upon error return the passed default
* integer.
*/
-int prom_getintdefault(int node, char *property, int deflt)
+int prom_getintdefault(phandle node, char *property, int deflt)
{
int retval;
@@ -152,7 +152,7 @@ int prom_getintdefault(int node, char *property, int deflt)
EXPORT_SYMBOL(prom_getintdefault);
/* Acquire a boolean property, 1=TRUE 0=FALSE. */
-int prom_getbool(int node, char *prop)
+int prom_getbool(phandle node, char *prop)
{
int retval;
@@ -166,7 +166,7 @@ EXPORT_SYMBOL(prom_getbool);
* string on error. The char pointer is the user supplied string
* buffer.
*/
-void prom_getstring(int node, char *prop, char *user_buf, int ubuf_size)
+void prom_getstring(phandle node, char *prop, char *user_buf, int ubuf_size)
{
int len;
@@ -180,7 +180,7 @@ EXPORT_SYMBOL(prom_getstring);
/* Does the device at node 'node' have name 'name'?
* YES = 1 NO = 0
*/
-int prom_nodematch(int node, char *name)
+int prom_nodematch(phandle node, char *name)
{
int error;
@@ -194,10 +194,11 @@ int prom_nodematch(int node, char *name)
/* Search siblings at 'node_start' for a node with name
* 'nodename'. Return node if successful, zero if not.
*/
-int prom_searchsiblings(int node_start, char *nodename)
+phandle prom_searchsiblings(phandle node_start, char *nodename)
{
- int thisnode, error;
+ phandle thisnode;
+ int error;
for(thisnode = node_start; thisnode;
thisnode=prom_getsibling(thisnode)) {
@@ -213,7 +214,7 @@ int prom_searchsiblings(int node_start, char *nodename)
EXPORT_SYMBOL(prom_searchsiblings);
/* Interal version of nextprop that does not alter return values. */
-char * __prom_nextprop(int node, char * oprop)
+char *__prom_nextprop(phandle node, char * oprop)
{
unsigned long flags;
char *prop;
@@ -228,7 +229,7 @@ char * __prom_nextprop(int node, char * oprop)
/* Return the first property name for node 'node'. */
/* buffer is unused argument, but as v9 uses it, we need to have the same interface */
-char * prom_firstprop(int node, char *bufer)
+char *prom_firstprop(phandle node, char *bufer)
{
if (node == 0 || node == -1)
return "";
@@ -241,7 +242,7 @@ EXPORT_SYMBOL(prom_firstprop);
* at node 'node' . Returns empty string if no more
* property types for this node.
*/
-char * prom_nextprop(int node, char *oprop, char *buffer)
+char *prom_nextprop(phandle node, char *oprop, char *buffer)
{
if (node == 0 || node == -1)
return "";
@@ -250,11 +251,11 @@ char * prom_nextprop(int node, char *oprop, char *buffer)
}
EXPORT_SYMBOL(prom_nextprop);
-int prom_finddevice(char *name)
+phandle prom_finddevice(char *name)
{
char nbuf[128];
char *s = name, *d;
- int node = prom_root_node, node2;
+ phandle node = prom_root_node, node2;
unsigned int which_io, phys_addr;
struct linux_prom_registers reg[PROMREG_MAX];
@@ -298,7 +299,7 @@ int prom_finddevice(char *name)
}
EXPORT_SYMBOL(prom_finddevice);
-int prom_node_has_property(int node, char *prop)
+int prom_node_has_property(phandle node, char *prop)
{
char *current_property = "";
@@ -314,7 +315,7 @@ EXPORT_SYMBOL(prom_node_has_property);
/* Set property 'pname' at node 'node' to value 'value' which has a length
* of 'size' bytes. Return the number of bytes the prom accepted.
*/
-int prom_setprop(int node, const char *pname, char *value, int size)
+int prom_setprop(phandle node, const char *pname, char *value, int size)
{
unsigned long flags;
int ret;
@@ -329,9 +330,9 @@ int prom_setprop(int node, const char *pname, char *value, int size)
}
EXPORT_SYMBOL(prom_setprop);
-int prom_inst2pkg(int inst)
+phandle prom_inst2pkg(int inst)
{
- int node;
+ phandle node;
unsigned long flags;
spin_lock_irqsave(&prom_lock, flags);
@@ -345,9 +346,10 @@ int prom_inst2pkg(int inst)
/* Return 'node' assigned to a particular prom 'path'
* FIXME: Should work for v0 as well
*/
-int prom_pathtoinode(char *path)
+phandle prom_pathtoinode(char *path)
{
- int node, inst;
+ phandle node;
+ int inst;
inst = prom_devopen (path);
if (inst == -1) return 0;
diff --git a/arch/sparc/prom/tree_64.c b/arch/sparc/prom/tree_64.c
index 9d3f9137a43a..691be68932f8 100644
--- a/arch/sparc/prom/tree_64.c
+++ b/arch/sparc/prom/tree_64.c
@@ -16,7 +16,7 @@
#include <asm/oplib.h>
#include <asm/ldc.h>
-static int prom_node_to_node(const char *type, int node)
+static phandle prom_node_to_node(const char *type, phandle node)
{
unsigned long args[5];
@@ -28,20 +28,20 @@ static int prom_node_to_node(const char *type, int node)
p1275_cmd_direct(args);
- return (int) args[4];
+ return (phandle) args[4];
}
/* Return the child of node 'node' or zero if no this node has no
* direct descendent.
*/
-inline int __prom_getchild(int node)
+inline phandle __prom_getchild(phandle node)
{
return prom_node_to_node("child", node);
}
-inline int prom_getchild(int node)
+inline phandle prom_getchild(phandle node)
{
- int cnode;
+ phandle cnode;
if (node == -1)
return 0;
@@ -52,9 +52,9 @@ inline int prom_getchild(int node)
}
EXPORT_SYMBOL(prom_getchild);
-inline int prom_getparent(int node)
+inline phandle prom_getparent(phandle node)
{
- int cnode;
+ phandle cnode;
if (node == -1)
return 0;
@@ -67,14 +67,14 @@ inline int prom_getparent(int node)
/* Return the next sibling of node 'node' or zero if no more siblings
* at this level of depth in the tree.
*/
-inline int __prom_getsibling(int node)
+inline phandle __prom_getsibling(phandle node)
{
return prom_node_to_node(prom_peer_name, node);
}
-inline int prom_getsibling(int node)
+inline phandle prom_getsibling(phandle node)
{
- int sibnode;
+ phandle sibnode;
if (node == -1)
return 0;
@@ -89,7 +89,7 @@ EXPORT_SYMBOL(prom_getsibling);
/* Return the length in bytes of property 'prop' at node 'node'.
* Return -1 on error.
*/
-inline int prom_getproplen(int node, const char *prop)
+inline int prom_getproplen(phandle node, const char *prop)
{
unsigned long args[6];
@@ -113,7 +113,7 @@ EXPORT_SYMBOL(prom_getproplen);
* 'buffer' which has a size of 'bufsize'. If the acquisition
* was successful the length will be returned, else -1 is returned.
*/
-inline int prom_getproperty(int node, const char *prop,
+inline int prom_getproperty(phandle node, const char *prop,
char *buffer, int bufsize)
{
unsigned long args[8];
@@ -141,7 +141,7 @@ EXPORT_SYMBOL(prom_getproperty);
/* Acquire an integer property and return its value. Returns -1
* on failure.
*/
-inline int prom_getint(int node, const char *prop)
+inline int prom_getint(phandle node, const char *prop)
{
int intprop;
@@ -156,7 +156,7 @@ EXPORT_SYMBOL(prom_getint);
* integer.
*/
-int prom_getintdefault(int node, const char *property, int deflt)
+int prom_getintdefault(phandle node, const char *property, int deflt)
{
int retval;
@@ -169,7 +169,7 @@ int prom_getintdefault(int node, const char *property, int deflt)
EXPORT_SYMBOL(prom_getintdefault);
/* Acquire a boolean property, 1=TRUE 0=FALSE. */
-int prom_getbool(int node, const char *prop)
+int prom_getbool(phandle node, const char *prop)
{
int retval;
@@ -184,7 +184,8 @@ EXPORT_SYMBOL(prom_getbool);
* string on error. The char pointer is the user supplied string
* buffer.
*/
-void prom_getstring(int node, const char *prop, char *user_buf, int ubuf_size)
+void prom_getstring(phandle node, const char *prop, char *user_buf,
+ int ubuf_size)
{
int len;
@@ -198,7 +199,7 @@ EXPORT_SYMBOL(prom_getstring);
/* Does the device at node 'node' have name 'name'?
* YES = 1 NO = 0
*/
-int prom_nodematch(int node, const char *name)
+int prom_nodematch(phandle node, const char *name)
{
char namebuf[128];
prom_getproperty(node, "name", namebuf, sizeof(namebuf));
@@ -210,10 +211,10 @@ int prom_nodematch(int node, const char *name)
/* Search siblings at 'node_start' for a node with name
* 'nodename'. Return node if successful, zero if not.
*/
-int prom_searchsiblings(int node_start, const char *nodename)
+phandle prom_searchsiblings(phandle node_start, const char *nodename)
{
-
- int thisnode, error;
+ phandle thisnode;
+ int error;
char promlib_buf[128];
for(thisnode = node_start; thisnode;
@@ -234,7 +235,7 @@ static const char *prom_nextprop_name = "nextprop";
/* Return the first property type for node 'node'.
* buffer should be at least 32B in length
*/
-inline char *prom_firstprop(int node, char *buffer)
+inline char *prom_firstprop(phandle node, char *buffer)
{
unsigned long args[7];
@@ -260,7 +261,7 @@ EXPORT_SYMBOL(prom_firstprop);
* at node 'node' . Returns NULL string if no more
* property types for this node.
*/
-inline char *prom_nextprop(int node, const char *oprop, char *buffer)
+inline char *prom_nextprop(phandle node, const char *oprop, char *buffer)
{
unsigned long args[7];
char buf[32];
@@ -288,8 +289,7 @@ inline char *prom_nextprop(int node, const char *oprop, char *buffer)
}
EXPORT_SYMBOL(prom_nextprop);
-int
-prom_finddevice(const char *name)
+phandle prom_finddevice(const char *name)
{
unsigned long args[5];
@@ -307,7 +307,7 @@ prom_finddevice(const char *name)
}
EXPORT_SYMBOL(prom_finddevice);
-int prom_node_has_property(int node, const char *prop)
+int prom_node_has_property(phandle node, const char *prop)
{
char buf [32];
@@ -325,7 +325,7 @@ EXPORT_SYMBOL(prom_node_has_property);
* of 'size' bytes. Return the number of bytes the prom accepted.
*/
int
-prom_setprop(int node, const char *pname, char *value, int size)
+prom_setprop(phandle node, const char *pname, char *value, int size)
{
unsigned long args[8];
@@ -355,10 +355,10 @@ prom_setprop(int node, const char *pname, char *value, int size)
}
EXPORT_SYMBOL(prom_setprop);
-inline int prom_inst2pkg(int inst)
+inline phandle prom_inst2pkg(int inst)
{
unsigned long args[5];
- int node;
+ phandle node;
args[0] = (unsigned long) "instance-to-package";
args[1] = 1;
@@ -377,10 +377,10 @@ inline int prom_inst2pkg(int inst)
/* Return 'node' assigned to a particular prom 'path'
* FIXME: Should work for v0 as well
*/
-int
-prom_pathtoinode(const char *path)
+phandle prom_pathtoinode(const char *path)
{
- int node, inst;
+ phandle node;
+ int inst;
inst = prom_devopen (path);
if (inst == 0)
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 1eb308cb711a..7e8c2844e093 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -58,6 +58,9 @@ config ARCH_SUPPORTS_OPTIMIZED_INLINING
config ARCH_PHYS_ADDR_T_64BIT
def_bool y
+config ARCH_DMA_ADDR_T_64BIT
+ def_bool y
+
config LOCKDEP_SUPPORT
def_bool y
@@ -96,6 +99,7 @@ config HVC_TILE
config TILE
def_bool y
+ select HAVE_KVM if !TILEGX
select GENERIC_FIND_FIRST_BIT
select GENERIC_FIND_NEXT_BIT
select USE_GENERIC_SMP_HELPERS
@@ -236,9 +240,9 @@ choice
If you are not absolutely sure what you are doing, leave this
option alone!
- config VMSPLIT_375G
+ config VMSPLIT_3_75G
bool "3.75G/0.25G user/kernel split (no kernel networking)"
- config VMSPLIT_35G
+ config VMSPLIT_3_5G
bool "3.5G/0.5G user/kernel split"
config VMSPLIT_3G
bool "3G/1G user/kernel split"
@@ -252,8 +256,8 @@ endchoice
config PAGE_OFFSET
hex
- default 0xF0000000 if VMSPLIT_375G
- default 0xE0000000 if VMSPLIT_35G
+ default 0xF0000000 if VMSPLIT_3_75G
+ default 0xE0000000 if VMSPLIT_3_5G
default 0xB0000000 if VMSPLIT_3G_OPT
default 0x80000000 if VMSPLIT_2G
default 0x40000000 if VMSPLIT_1G
@@ -314,6 +318,15 @@ config HARDWALL
bool "Hardwall support to allow access to user dynamic network"
default y
+config KERNEL_PL
+ int "Processor protection level for kernel"
+ range 1 2
+ default "1"
+ ---help---
+ This setting determines the processor protection level the
+ kernel will be built to run at. Generally you should use
+ the default value here.
+
endmenu # Tilera-specific configuration
menu "Bus options"
@@ -354,3 +367,5 @@ source "security/Kconfig"
source "crypto/Kconfig"
source "lib/Kconfig"
+
+source "arch/tile/kvm/Kconfig"
diff --git a/arch/tile/Makefile b/arch/tile/Makefile
index fd8f6bb5face..17acce70569b 100644
--- a/arch/tile/Makefile
+++ b/arch/tile/Makefile
@@ -26,8 +26,9 @@ $(error Set TILERA_ROOT or CROSS_COMPILE when building $(ARCH) on $(HOST_ARCH))
endif
endif
-
+ifneq ($(CONFIG_DEBUG_EXTRA_FLAGS),"")
KBUILD_CFLAGS += $(CONFIG_DEBUG_EXTRA_FLAGS)
+endif
LIBGCC_PATH := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
@@ -49,6 +50,20 @@ head-y := arch/tile/kernel/head_$(BITS).o
libs-y += arch/tile/lib/
libs-y += $(LIBGCC_PATH)
-
# See arch/tile/Kbuild for content of core part of the kernel
core-y += arch/tile/
+
+core-$(CONFIG_KVM) += arch/tile/kvm/
+
+ifdef TILERA_ROOT
+INSTALL_PATH ?= $(TILERA_ROOT)/tile/boot
+endif
+
+install:
+ install -D -m 755 vmlinux $(INSTALL_PATH)/vmlinux-$(KERNELRELEASE)
+ install -D -m 644 .config $(INSTALL_PATH)/config-$(KERNELRELEASE)
+ install -D -m 644 System.map $(INSTALL_PATH)/System.map-$(KERNELRELEASE)
+
+define archhelp
+ echo ' install - install kernel into $(INSTALL_PATH)'
+endef
diff --git a/arch/tile/include/arch/sim.h b/arch/tile/include/arch/sim.h
new file mode 100644
index 000000000000..74b7c1624d34
--- /dev/null
+++ b/arch/tile/include/arch/sim.h
@@ -0,0 +1,619 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+/**
+ * @file
+ *
+ * Provides an API for controlling the simulator at runtime.
+ */
+
+/**
+ * @addtogroup arch_sim
+ * @{
+ *
+ * An API for controlling the simulator at runtime.
+ *
+ * The simulator's behavior can be modified while it is running.
+ * For example, human-readable trace output can be enabled and disabled
+ * around code of interest.
+ *
+ * There are two ways to modify simulator behavior:
+ * programmatically, by calling various sim_* functions, and
+ * interactively, by entering commands like "sim set functional true"
+ * at the tile-monitor prompt. Typing "sim help" at that prompt provides
+ * a list of interactive commands.
+ *
+ * All interactive commands can also be executed programmatically by
+ * passing a string to the sim_command function.
+ */
+
+#ifndef __ARCH_SIM_H__
+#define __ARCH_SIM_H__
+
+#include <arch/sim_def.h>
+#include <arch/abi.h>
+
+#ifndef __ASSEMBLER__
+
+#include <arch/spr_def.h>
+
+
+/**
+ * Return true if the current program is running under a simulator,
+ * rather than on real hardware. If running on hardware, other "sim_xxx()"
+ * calls have no useful effect.
+ */
+static inline int
+sim_is_simulator(void)
+{
+ return __insn_mfspr(SPR_SIM_CONTROL) != 0;
+}
+
+
+/**
+ * Checkpoint the simulator state to a checkpoint file.
+ *
+ * The checkpoint file name is either the default or the name specified
+ * on the command line with "--checkpoint-file".
+ */
+static __inline void
+sim_checkpoint(void)
+{
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_CHECKPOINT);
+}
+
+
+/**
+ * Report whether or not various kinds of simulator tracing are enabled.
+ *
+ * @return The bitwise OR of these values:
+ *
+ * SIM_TRACE_CYCLES (--trace-cycles),
+ * SIM_TRACE_ROUTER (--trace-router),
+ * SIM_TRACE_REGISTER_WRITES (--trace-register-writes),
+ * SIM_TRACE_DISASM (--trace-disasm),
+ * SIM_TRACE_STALL_INFO (--trace-stall-info)
+ * SIM_TRACE_MEMORY_CONTROLLER (--trace-memory-controller)
+ * SIM_TRACE_L2_CACHE (--trace-l2)
+ * SIM_TRACE_LINES (--trace-lines)
+ */
+static __inline unsigned int
+sim_get_tracing(void)
+{
+ return __insn_mfspr(SPR_SIM_CONTROL) & SIM_TRACE_FLAG_MASK;
+}
+
+
+/**
+ * Turn on or off different kinds of simulator tracing.
+ *
+ * @param mask Either one of these special values:
+ *
+ * SIM_TRACE_NONE (turns off tracing),
+ * SIM_TRACE_ALL (turns on all possible tracing).
+ *
+ * or the bitwise OR of these values:
+ *
+ * SIM_TRACE_CYCLES (--trace-cycles),
+ * SIM_TRACE_ROUTER (--trace-router),
+ * SIM_TRACE_REGISTER_WRITES (--trace-register-writes),
+ * SIM_TRACE_DISASM (--trace-disasm),
+ * SIM_TRACE_STALL_INFO (--trace-stall-info)
+ * SIM_TRACE_MEMORY_CONTROLLER (--trace-memory-controller)
+ * SIM_TRACE_L2_CACHE (--trace-l2)
+ * SIM_TRACE_LINES (--trace-lines)
+ */
+static __inline void
+sim_set_tracing(unsigned int mask)
+{
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_TRACE_SPR_ARG(mask));
+}
+
+
+/**
+ * Request dumping of different kinds of simulator state.
+ *
+ * @param mask Either this special value:
+ *
+ * SIM_DUMP_ALL (dump all known state)
+ *
+ * or the bitwise OR of these values:
+ *
+ * SIM_DUMP_REGS (the register file),
+ * SIM_DUMP_SPRS (the SPRs),
+ * SIM_DUMP_ITLB (the iTLB),
+ * SIM_DUMP_DTLB (the dTLB),
+ * SIM_DUMP_L1I (the L1 I-cache),
+ * SIM_DUMP_L1D (the L1 D-cache),
+ * SIM_DUMP_L2 (the L2 cache),
+ * SIM_DUMP_SNREGS (the switch register file),
+ * SIM_DUMP_SNITLB (the switch iTLB),
+ * SIM_DUMP_SNL1I (the switch L1 I-cache),
+ * SIM_DUMP_BACKTRACE (the current backtrace)
+ */
+static __inline void
+sim_dump(unsigned int mask)
+{
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_DUMP_SPR_ARG(mask));
+}
+
+
+/**
+ * Print a string to the simulator stdout.
+ *
+ * @param str The string to be written; a newline is automatically added.
+ */
+static __inline void
+sim_print_string(const char* str)
+{
+ int i;
+ for (i = 0; str[i] != 0; i++)
+ {
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
+ (str[i] << _SIM_CONTROL_OPERATOR_BITS));
+ }
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
+ (SIM_PUTC_FLUSH_STRING << _SIM_CONTROL_OPERATOR_BITS));
+}
+
+
+/**
+ * Execute a simulator command string.
+ *
+ * Type 'sim help' at the tile-monitor prompt to learn what commands
+ * are available. Note the use of the tile-monitor "sim" command to
+ * pass commands to the simulator.
+ *
+ * The argument to sim_command() does not include the leading "sim"
+ * prefix used at the tile-monitor prompt; for example, you might call
+ * sim_command("trace disasm").
+ */
+static __inline void
+sim_command(const char* str)
+{
+ int c;
+ do
+ {
+ c = *str++;
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_COMMAND |
+ (c << _SIM_CONTROL_OPERATOR_BITS));
+ }
+ while (c);
+}
+
+
+
+#ifndef __DOXYGEN__
+
+/**
+ * The underlying implementation of "_sim_syscall()".
+ *
+ * We use extra "and" instructions to ensure that all the values
+ * we are passing to the simulator are actually valid in the registers
+ * (i.e. returned from memory) prior to the SIM_CONTROL spr.
+ */
+static __inline int _sim_syscall0(int val)
+{
+ long result;
+ __asm__ __volatile__ ("mtspr SIM_CONTROL, r0"
+ : "=R00" (result) : "R00" (val));
+ return result;
+}
+
+static __inline int _sim_syscall1(int val, long arg1)
+{
+ long result;
+ __asm__ __volatile__ ("{ and zero, r1, r1; mtspr SIM_CONTROL, r0 }"
+ : "=R00" (result) : "R00" (val), "R01" (arg1));
+ return result;
+}
+
+static __inline int _sim_syscall2(int val, long arg1, long arg2)
+{
+ long result;
+ __asm__ __volatile__ ("{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
+ : "=R00" (result)
+ : "R00" (val), "R01" (arg1), "R02" (arg2));
+ return result;
+}
+
+/* Note that _sim_syscall3() and higher are technically at risk of
+ receiving an interrupt right before the mtspr bundle, in which case
+ the register values for arguments 3 and up may still be in flight
+ to the core from a stack frame reload. */
+
+static __inline int _sim_syscall3(int val, long arg1, long arg2, long arg3)
+{
+ long result;
+ __asm__ __volatile__ ("{ and zero, r3, r3 };"
+ "{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
+ : "=R00" (result)
+ : "R00" (val), "R01" (arg1), "R02" (arg2),
+ "R03" (arg3));
+ return result;
+}
+
+static __inline int _sim_syscall4(int val, long arg1, long arg2, long arg3,
+ long arg4)
+{
+ long result;
+ __asm__ __volatile__ ("{ and zero, r3, r4 };"
+ "{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
+ : "=R00" (result)
+ : "R00" (val), "R01" (arg1), "R02" (arg2),
+ "R03" (arg3), "R04" (arg4));
+ return result;
+}
+
+static __inline int _sim_syscall5(int val, long arg1, long arg2, long arg3,
+ long arg4, long arg5)
+{
+ long result;
+ __asm__ __volatile__ ("{ and zero, r3, r4; and zero, r5, r5 };"
+ "{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
+ : "=R00" (result)
+ : "R00" (val), "R01" (arg1), "R02" (arg2),
+ "R03" (arg3), "R04" (arg4), "R05" (arg5));
+ return result;
+}
+
+
+/**
+ * Make a special syscall to the simulator itself, if running under
+ * simulation. This is used as the implementation of other functions
+ * and should not be used outside this file.
+ *
+ * @param syscall_num The simulator syscall number.
+ * @param nr The number of additional arguments provided.
+ *
+ * @return Varies by syscall.
+ */
+#define _sim_syscall(syscall_num, nr, args...) \
+ _sim_syscall##nr( \
+ ((syscall_num) << _SIM_CONTROL_OPERATOR_BITS) | SIM_CONTROL_SYSCALL, args)
+
+
+/* Values for the "access_mask" parameters below. */
+#define SIM_WATCHPOINT_READ 1
+#define SIM_WATCHPOINT_WRITE 2
+#define SIM_WATCHPOINT_EXECUTE 4
+
+
+static __inline int
+sim_add_watchpoint(unsigned int process_id,
+ unsigned long address,
+ unsigned long size,
+ unsigned int access_mask,
+ unsigned long user_data)
+{
+ return _sim_syscall(SIM_SYSCALL_ADD_WATCHPOINT, 5, process_id,
+ address, size, access_mask, user_data);
+}
+
+
+static __inline int
+sim_remove_watchpoint(unsigned int process_id,
+ unsigned long address,
+ unsigned long size,
+ unsigned int access_mask,
+ unsigned long user_data)
+{
+ return _sim_syscall(SIM_SYSCALL_REMOVE_WATCHPOINT, 5, process_id,
+ address, size, access_mask, user_data);
+}
+
+
+/**
+ * Return value from sim_query_watchpoint.
+ */
+struct SimQueryWatchpointStatus
+{
+ /**
+ * 0 if a watchpoint fired, 1 if no watchpoint fired, or -1 for
+ * error (meaning a bad process_id).
+ */
+ int syscall_status;
+
+ /**
+ * The address of the watchpoint that fired (this is the address
+ * passed to sim_add_watchpoint, not an address within that range
+ * that actually triggered the watchpoint).
+ */
+ unsigned long address;
+
+ /** The arbitrary user_data installed by sim_add_watchpoint. */
+ unsigned long user_data;
+};
+
+
+static __inline struct SimQueryWatchpointStatus
+sim_query_watchpoint(unsigned int process_id)
+{
+ struct SimQueryWatchpointStatus status;
+ long val = SIM_CONTROL_SYSCALL |
+ (SIM_SYSCALL_QUERY_WATCHPOINT << _SIM_CONTROL_OPERATOR_BITS);
+ __asm__ __volatile__ ("{ and zero, r1, r1; mtspr SIM_CONTROL, r0 }"
+ : "=R00" (status.syscall_status),
+ "=R01" (status.address),
+ "=R02" (status.user_data)
+ : "R00" (val), "R01" (process_id));
+ return status;
+}
+
+
+/* On the simulator, confirm lines have been evicted everywhere. */
+static __inline void
+sim_validate_lines_evicted(unsigned long long pa, unsigned long length)
+{
+#ifdef __LP64__
+ _sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED, 2, pa, length);
+#else
+ _sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED, 4,
+ 0 /* dummy */, (long)(pa), (long)(pa >> 32), length);
+#endif
+}
+
+
+#endif /* !__DOXYGEN__ */
+
+
+
+
+/**
+ * Modify the shaping parameters of a shim.
+ *
+ * @param shim The shim to modify. One of:
+ * SIM_CONTROL_SHAPING_GBE_0
+ * SIM_CONTROL_SHAPING_GBE_1
+ * SIM_CONTROL_SHAPING_GBE_2
+ * SIM_CONTROL_SHAPING_GBE_3
+ * SIM_CONTROL_SHAPING_XGBE_0
+ * SIM_CONTROL_SHAPING_XGBE_1
+ *
+ * @param type The type of shaping. This should be the same type of
+ * shaping that is already in place on the shim. One of:
+ * SIM_CONTROL_SHAPING_MULTIPLIER
+ * SIM_CONTROL_SHAPING_PPS
+ * SIM_CONTROL_SHAPING_BPS
+ *
+ * @param units The magnitude of the rate. One of:
+ * SIM_CONTROL_SHAPING_UNITS_SINGLE
+ * SIM_CONTROL_SHAPING_UNITS_KILO
+ * SIM_CONTROL_SHAPING_UNITS_MEGA
+ * SIM_CONTROL_SHAPING_UNITS_GIGA
+ *
+ * @param rate The rate to which to change it. This must fit in
+ * SIM_CONTROL_SHAPING_RATE_BITS bits or a warning is issued and
+ * the shaping is not changed.
+ *
+ * @return 0 if no problems were detected in the arguments to sim_set_shaping
+ * or 1 if problems were detected (for example, rate does not fit in 17 bits).
+ */
+static __inline int
+sim_set_shaping(unsigned shim,
+ unsigned type,
+ unsigned units,
+ unsigned rate)
+{
+ if ((rate & ~((1 << SIM_CONTROL_SHAPING_RATE_BITS) - 1)) != 0)
+ return 1;
+
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_SHAPING_SPR_ARG(shim, type, units, rate));
+ return 0;
+}
+
+#ifdef __tilegx__
+
+/** Enable a set of mPIPE links. Pass a -1 link_mask to enable all links. */
+static __inline void
+sim_enable_mpipe_links(unsigned mpipe, unsigned long link_mask)
+{
+ __insn_mtspr(SPR_SIM_CONTROL,
+ (SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE |
+ (mpipe << 8) | (1 << 16) | ((uint_reg_t)link_mask << 32)));
+}
+
+/** Disable a set of mPIPE links. Pass a -1 link_mask to disable all links. */
+static __inline void
+sim_disable_mpipe_links(unsigned mpipe, unsigned long link_mask)
+{
+ __insn_mtspr(SPR_SIM_CONTROL,
+ (SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE |
+ (mpipe << 8) | (0 << 16) | ((uint_reg_t)link_mask << 32)));
+}
+
+#endif /* __tilegx__ */
+
+
+/*
+ * An API for changing "functional" mode.
+ */
+
+#ifndef __DOXYGEN__
+
+#define sim_enable_functional() \
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_ENABLE_FUNCTIONAL)
+
+#define sim_disable_functional() \
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_DISABLE_FUNCTIONAL)
+
+#endif /* __DOXYGEN__ */
+
+
+/*
+ * Profiler support.
+ */
+
+/**
+ * Turn profiling on for the current task.
+ *
+ * Note that this has no effect if run in an environment without
+ * profiling support (thus, the proper flags to the simulator must
+ * be supplied).
+ */
+static __inline void
+sim_profiler_enable(void)
+{
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_ENABLE);
+}
+
+
+/** Turn profiling off for the current task. */
+static __inline void
+sim_profiler_disable(void)
+{
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_DISABLE);
+}
+
+
+/**
+ * Turn profiling on or off for the current task.
+ *
+ * @param enabled If true, turns on profiling. If false, turns it off.
+ *
+ * Note that this has no effect if run in an environment without
+ * profiling support (thus, the proper flags to the simulator must
+ * be supplied).
+ */
+static __inline void
+sim_profiler_set_enabled(int enabled)
+{
+ int val =
+ enabled ? SIM_CONTROL_PROFILER_ENABLE : SIM_CONTROL_PROFILER_DISABLE;
+ __insn_mtspr(SPR_SIM_CONTROL, val);
+}
+
+
+/**
+ * Return true if and only if profiling is currently enabled
+ * for the current task.
+ *
+ * This returns false even if sim_profiler_enable() was called
+ * if the current execution environment does not support profiling.
+ */
+static __inline int
+sim_profiler_is_enabled(void)
+{
+ return ((__insn_mfspr(SPR_SIM_CONTROL) & SIM_PROFILER_ENABLED_MASK) != 0);
+}
+
+
+/**
+ * Reset profiling counters to zero for the current task.
+ *
+ * Resetting can be done while profiling is enabled. It does not affect
+ * the chip-wide profiling counters.
+ */
+static __inline void
+sim_profiler_clear(void)
+{
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_CLEAR);
+}
+
+
+/**
+ * Enable specified chip-level profiling counters.
+ *
+ * Does not affect the per-task profiling counters.
+ *
+ * @param mask Either this special value:
+ *
+ * SIM_CHIP_ALL (enables all chip-level components).
+ *
+ * or the bitwise OR of these values:
+ *
+ * SIM_CHIP_MEMCTL (enable all memory controllers)
+ * SIM_CHIP_XAUI (enable all XAUI controllers)
+ * SIM_CHIP_MPIPE (enable all MPIPE controllers)
+ */
+static __inline void
+sim_profiler_chip_enable(unsigned int mask)
+{
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_ENABLE_SPR_ARG(mask));
+}
+
+
+/**
+ * Disable specified chip-level profiling counters.
+ *
+ * Does not affect the per-task profiling counters.
+ *
+ * @param mask Either this special value:
+ *
+ * SIM_CHIP_ALL (disables all chip-level components).
+ *
+ * or the bitwise OR of these values:
+ *
+ * SIM_CHIP_MEMCTL (disable all memory controllers)
+ * SIM_CHIP_XAUI (disable all XAUI controllers)
+ * SIM_CHIP_MPIPE (disable all MPIPE controllers)
+ */
+static __inline void
+sim_profiler_chip_disable(unsigned int mask)
+{
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_DISABLE_SPR_ARG(mask));
+}
+
+
+/**
+ * Reset specified chip-level profiling counters to zero.
+ *
+ * Does not affect the per-task profiling counters.
+ *
+ * @param mask Either this special value:
+ *
+ * SIM_CHIP_ALL (clears all chip-level components).
+ *
+ * or the bitwise OR of these values:
+ *
+ * SIM_CHIP_MEMCTL (clear all memory controllers)
+ * SIM_CHIP_XAUI (clear all XAUI controllers)
+ * SIM_CHIP_MPIPE (clear all MPIPE controllers)
+ */
+static __inline void
+sim_profiler_chip_clear(unsigned int mask)
+{
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_CLEAR_SPR_ARG(mask));
+}
+
+
+/*
+ * Event support.
+ */
+
+#ifndef __DOXYGEN__
+
+static __inline void
+sim_event_begin(unsigned int x)
+{
+#if defined(__tile__) && !defined(__NO_EVENT_SPR__)
+ __insn_mtspr(SPR_EVENT_BEGIN, x);
+#endif
+}
+
+static __inline void
+sim_event_end(unsigned int x)
+{
+#if defined(__tile__) && !defined(__NO_EVENT_SPR__)
+ __insn_mtspr(SPR_EVENT_END, x);
+#endif
+}
+
+#endif /* !__DOXYGEN__ */
+
+#endif /* !__ASSEMBLER__ */
+
+#endif /* !__ARCH_SIM_H__ */
+
+/** @} */
diff --git a/arch/tile/include/arch/sim_def.h b/arch/tile/include/arch/sim_def.h
index 6418fbde063e..7a17082c3773 100644
--- a/arch/tile/include/arch/sim_def.h
+++ b/arch/tile/include/arch/sim_def.h
@@ -1,477 +1,461 @@
-// Copyright 2010 Tilera Corporation. All Rights Reserved.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation, version 2.
-//
-// 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, GOOD TITLE or
-// NON INFRINGEMENT. See the GNU General Public License for
-// more details.
-
-//! @file
-//!
-//! Some low-level simulator definitions.
-//!
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+/**
+ * @file
+ *
+ * Some low-level simulator definitions.
+ */
#ifndef __ARCH_SIM_DEF_H__
#define __ARCH_SIM_DEF_H__
-//! Internal: the low bits of the SIM_CONTROL_* SPR values specify
-//! the operation to perform, and the remaining bits are
-//! an operation-specific parameter (often unused).
-//!
+/**
+ * Internal: the low bits of the SIM_CONTROL_* SPR values specify
+ * the operation to perform, and the remaining bits are
+ * an operation-specific parameter (often unused).
+ */
#define _SIM_CONTROL_OPERATOR_BITS 8
-//== Values which can be written to SPR_SIM_CONTROL.
+/*
+ * Values which can be written to SPR_SIM_CONTROL.
+ */
-//! If written to SPR_SIM_CONTROL, stops profiling.
-//!
+/** If written to SPR_SIM_CONTROL, stops profiling. */
#define SIM_CONTROL_PROFILER_DISABLE 0
-//! If written to SPR_SIM_CONTROL, starts profiling.
-//!
+/** If written to SPR_SIM_CONTROL, starts profiling. */
#define SIM_CONTROL_PROFILER_ENABLE 1
-//! If written to SPR_SIM_CONTROL, clears profiling counters.
-//!
+/** If written to SPR_SIM_CONTROL, clears profiling counters. */
#define SIM_CONTROL_PROFILER_CLEAR 2
-//! If written to SPR_SIM_CONTROL, checkpoints the simulator.
-//!
+/** If written to SPR_SIM_CONTROL, checkpoints the simulator. */
#define SIM_CONTROL_CHECKPOINT 3
-//! If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8),
-//! sets the tracing mask to the given mask. See "sim_set_tracing()".
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8),
+ * sets the tracing mask to the given mask. See "sim_set_tracing()".
+ */
#define SIM_CONTROL_SET_TRACING 4
-//! If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8),
-//! dumps the requested items of machine state to the log.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8),
+ * dumps the requested items of machine state to the log.
+ */
#define SIM_CONTROL_DUMP 5
-//! If written to SPR_SIM_CONTROL, clears chip-level profiling counters.
-//!
+/** If written to SPR_SIM_CONTROL, clears chip-level profiling counters. */
#define SIM_CONTROL_PROFILER_CHIP_CLEAR 6
-//! If written to SPR_SIM_CONTROL, disables chip-level profiling.
-//!
+/** If written to SPR_SIM_CONTROL, disables chip-level profiling. */
#define SIM_CONTROL_PROFILER_CHIP_DISABLE 7
-//! If written to SPR_SIM_CONTROL, enables chip-level profiling.
-//!
+/** If written to SPR_SIM_CONTROL, enables chip-level profiling. */
#define SIM_CONTROL_PROFILER_CHIP_ENABLE 8
-//! If written to SPR_SIM_CONTROL, enables chip-level functional mode
-//!
+/** If written to SPR_SIM_CONTROL, enables chip-level functional mode */
#define SIM_CONTROL_ENABLE_FUNCTIONAL 9
-//! If written to SPR_SIM_CONTROL, disables chip-level functional mode.
-//!
+/** If written to SPR_SIM_CONTROL, disables chip-level functional mode. */
#define SIM_CONTROL_DISABLE_FUNCTIONAL 10
-//! If written to SPR_SIM_CONTROL, enables chip-level functional mode.
-//! All tiles must perform this write for functional mode to be enabled.
-//! Ignored in naked boot mode unless --functional is specified.
-//! WARNING: Only the hypervisor startup code should use this!
-//!
+/**
+ * If written to SPR_SIM_CONTROL, enables chip-level functional mode.
+ * All tiles must perform this write for functional mode to be enabled.
+ * Ignored in naked boot mode unless --functional is specified.
+ * WARNING: Only the hypervisor startup code should use this!
+ */
#define SIM_CONTROL_ENABLE_FUNCTIONAL_BARRIER 11
-//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
-//! writes a string directly to the simulator output. Written to once for
-//! each character in the string, plus a final NUL. Instead of NUL,
-//! you can also use "SIM_PUTC_FLUSH_STRING" or "SIM_PUTC_FLUSH_BINARY".
-//!
-// ISSUE: Document the meaning of "newline", and the handling of NUL.
-//
+/**
+ * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+ * writes a string directly to the simulator output. Written to once for
+ * each character in the string, plus a final NUL. Instead of NUL,
+ * you can also use "SIM_PUTC_FLUSH_STRING" or "SIM_PUTC_FLUSH_BINARY".
+ */
+/* ISSUE: Document the meaning of "newline", and the handling of NUL. */
#define SIM_CONTROL_PUTC 12
-//! If written to SPR_SIM_CONTROL, clears the --grind-coherence state for
-//! this core. This is intended to be used before a loop that will
-//! invalidate the cache by loading new data and evicting all current data.
-//! Generally speaking, this API should only be used by system code.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, clears the --grind-coherence state for
+ * this core. This is intended to be used before a loop that will
+ * invalidate the cache by loading new data and evicting all current data.
+ * Generally speaking, this API should only be used by system code.
+ */
#define SIM_CONTROL_GRINDER_CLEAR 13
-//! If written to SPR_SIM_CONTROL, shuts down the simulator.
-//!
+/** If written to SPR_SIM_CONTROL, shuts down the simulator. */
#define SIM_CONTROL_SHUTDOWN 14
-//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
-//! indicates that a fork syscall just created the given process.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+ * indicates that a fork syscall just created the given process.
+ */
#define SIM_CONTROL_OS_FORK 15
-//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
-//! indicates that an exit syscall was just executed by the given process.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+ * indicates that an exit syscall was just executed by the given process.
+ */
#define SIM_CONTROL_OS_EXIT 16
-//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
-//! indicates that the OS just switched to the given process.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+ * indicates that the OS just switched to the given process.
+ */
#define SIM_CONTROL_OS_SWITCH 17
-//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
-//! indicates that an exec syscall was just executed. Written to once for
-//! each character in the executable name, plus a final NUL.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+ * indicates that an exec syscall was just executed. Written to once for
+ * each character in the executable name, plus a final NUL.
+ */
#define SIM_CONTROL_OS_EXEC 18
-//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
-//! indicates that an interpreter (PT_INTERP) was loaded. Written to once
-//! for each character in "ADDR:PATH", plus a final NUL, where "ADDR" is a
-//! hex load address starting with "0x", and "PATH" is the executable name.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+ * indicates that an interpreter (PT_INTERP) was loaded. Written to once
+ * for each character in "ADDR:PATH", plus a final NUL, where "ADDR" is a
+ * hex load address starting with "0x", and "PATH" is the executable name.
+ */
#define SIM_CONTROL_OS_INTERP 19
-//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
-//! indicates that a dll was loaded. Written to once for each character
-//! in "ADDR:PATH", plus a final NUL, where "ADDR" is a hexadecimal load
-//! address starting with "0x", and "PATH" is the executable name.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+ * indicates that a dll was loaded. Written to once for each character
+ * in "ADDR:PATH", plus a final NUL, where "ADDR" is a hexadecimal load
+ * address starting with "0x", and "PATH" is the executable name.
+ */
#define SIM_CONTROL_DLOPEN 20
-//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
-//! indicates that a dll was unloaded. Written to once for each character
-//! in "ADDR", plus a final NUL, where "ADDR" is a hexadecimal load
-//! address starting with "0x".
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+ * indicates that a dll was unloaded. Written to once for each character
+ * in "ADDR", plus a final NUL, where "ADDR" is a hexadecimal load
+ * address starting with "0x".
+ */
#define SIM_CONTROL_DLCLOSE 21
-//! If written to SPR_SIM_CONTROL, combined with a flag (shifted by 8),
-//! indicates whether to allow data reads to remotely-cached
-//! dirty cache lines to be cached locally without grinder warnings or
-//! assertions (used by Linux kernel fast memcpy).
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a flag (shifted by 8),
+ * indicates whether to allow data reads to remotely-cached
+ * dirty cache lines to be cached locally without grinder warnings or
+ * assertions (used by Linux kernel fast memcpy).
+ */
#define SIM_CONTROL_ALLOW_MULTIPLE_CACHING 22
-//! If written to SPR_SIM_CONTROL, enables memory tracing.
-//!
+/** If written to SPR_SIM_CONTROL, enables memory tracing. */
#define SIM_CONTROL_ENABLE_MEM_LOGGING 23
-//! If written to SPR_SIM_CONTROL, disables memory tracing.
-//!
+/** If written to SPR_SIM_CONTROL, disables memory tracing. */
#define SIM_CONTROL_DISABLE_MEM_LOGGING 24
-//! If written to SPR_SIM_CONTROL, changes the shaping parameters of one of
-//! the gbe or xgbe shims. Must specify the shim id, the type, the units, and
-//! the rate, as defined in SIM_SHAPING_SPR_ARG.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, changes the shaping parameters of one of
+ * the gbe or xgbe shims. Must specify the shim id, the type, the units, and
+ * the rate, as defined in SIM_SHAPING_SPR_ARG.
+ */
#define SIM_CONTROL_SHAPING 25
-//! If written to SPR_SIM_CONTROL, combined with character (shifted by 8),
-//! requests that a simulator command be executed. Written to once for each
-//! character in the command, plus a final NUL.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with character (shifted by 8),
+ * requests that a simulator command be executed. Written to once for each
+ * character in the command, plus a final NUL.
+ */
#define SIM_CONTROL_COMMAND 26
-//! If written to SPR_SIM_CONTROL, indicates that the simulated system
-//! is panicking, to allow debugging via --debug-on-panic.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, indicates that the simulated system
+ * is panicking, to allow debugging via --debug-on-panic.
+ */
#define SIM_CONTROL_PANIC 27
-//! If written to SPR_SIM_CONTROL, triggers a simulator syscall.
-//! See "sim_syscall()" for more info.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, triggers a simulator syscall.
+ * See "sim_syscall()" for more info.
+ */
#define SIM_CONTROL_SYSCALL 32
-//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
-//! provides the pid that subsequent SIM_CONTROL_OS_FORK writes should
-//! use as the pid, rather than the default previous SIM_CONTROL_OS_SWITCH.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+ * provides the pid that subsequent SIM_CONTROL_OS_FORK writes should
+ * use as the pid, rather than the default previous SIM_CONTROL_OS_SWITCH.
+ */
#define SIM_CONTROL_OS_FORK_PARENT 33
-//! If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
-//! (shifted by 8), clears the pending magic data section. The cleared
-//! pending magic data section and any subsequently appended magic bytes
-//! will only take effect when the classifier blast programmer is run.
+/**
+ * If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
+ * (shifted by 8), clears the pending magic data section. The cleared
+ * pending magic data section and any subsequently appended magic bytes
+ * will only take effect when the classifier blast programmer is run.
+ */
#define SIM_CONTROL_CLEAR_MPIPE_MAGIC_BYTES 34
-//! If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
-//! (shifted by 8) and a byte of data (shifted by 16), appends that byte
-//! to the shim's pending magic data section. The pending magic data
-//! section takes effect when the classifier blast programmer is run.
+/**
+ * If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
+ * (shifted by 8) and a byte of data (shifted by 16), appends that byte
+ * to the shim's pending magic data section. The pending magic data
+ * section takes effect when the classifier blast programmer is run.
+ */
#define SIM_CONTROL_APPEND_MPIPE_MAGIC_BYTE 35
-//! If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
-//! (shifted by 8), an enable=1/disable=0 bit (shifted by 16), and a
-//! mask of links (shifted by 32), enable or disable the corresponding
-//! mPIPE links.
+/**
+ * If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
+ * (shifted by 8), an enable=1/disable=0 bit (shifted by 16), and a
+ * mask of links (shifted by 32), enable or disable the corresponding
+ * mPIPE links.
+ */
#define SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE 36
-//== Syscall numbers for use with "sim_syscall()".
-//! Syscall number for sim_add_watchpoint().
-//!
+/*
+ * Syscall numbers for use with "sim_syscall()".
+ */
+
+/** Syscall number for sim_add_watchpoint(). */
#define SIM_SYSCALL_ADD_WATCHPOINT 2
-//! Syscall number for sim_remove_watchpoint().
-//!
+/** Syscall number for sim_remove_watchpoint(). */
#define SIM_SYSCALL_REMOVE_WATCHPOINT 3
-//! Syscall number for sim_query_watchpoint().
-//!
+/** Syscall number for sim_query_watchpoint(). */
#define SIM_SYSCALL_QUERY_WATCHPOINT 4
-//! Syscall number that asserts that the cache lines whose 64-bit PA
-//! is passed as the second argument to sim_syscall(), and over a
-//! range passed as the third argument, are no longer in cache.
-//! The simulator raises an error if this is not the case.
-//!
+/**
+ * Syscall number that asserts that the cache lines whose 64-bit PA
+ * is passed as the second argument to sim_syscall(), and over a
+ * range passed as the third argument, are no longer in cache.
+ * The simulator raises an error if this is not the case.
+ */
#define SIM_SYSCALL_VALIDATE_LINES_EVICTED 5
-//== Bit masks which can be shifted by 8, combined with
-//== SIM_CONTROL_SET_TRACING, and written to SPR_SIM_CONTROL.
+/*
+ * Bit masks which can be shifted by 8, combined with
+ * SIM_CONTROL_SET_TRACING, and written to SPR_SIM_CONTROL.
+ */
-//! @addtogroup arch_sim
-//! @{
+/**
+ * @addtogroup arch_sim
+ * @{
+ */
-//! Enable --trace-cycle when passed to simulator_set_tracing().
-//!
+/** Enable --trace-cycle when passed to simulator_set_tracing(). */
#define SIM_TRACE_CYCLES 0x01
-//! Enable --trace-router when passed to simulator_set_tracing().
-//!
+/** Enable --trace-router when passed to simulator_set_tracing(). */
#define SIM_TRACE_ROUTER 0x02
-//! Enable --trace-register-writes when passed to simulator_set_tracing().
-//!
+/** Enable --trace-register-writes when passed to simulator_set_tracing(). */
#define SIM_TRACE_REGISTER_WRITES 0x04
-//! Enable --trace-disasm when passed to simulator_set_tracing().
-//!
+/** Enable --trace-disasm when passed to simulator_set_tracing(). */
#define SIM_TRACE_DISASM 0x08
-//! Enable --trace-stall-info when passed to simulator_set_tracing().
-//!
+/** Enable --trace-stall-info when passed to simulator_set_tracing(). */
#define SIM_TRACE_STALL_INFO 0x10
-//! Enable --trace-memory-controller when passed to simulator_set_tracing().
-//!
+/** Enable --trace-memory-controller when passed to simulator_set_tracing(). */
#define SIM_TRACE_MEMORY_CONTROLLER 0x20
-//! Enable --trace-l2 when passed to simulator_set_tracing().
-//!
+/** Enable --trace-l2 when passed to simulator_set_tracing(). */
#define SIM_TRACE_L2_CACHE 0x40
-//! Enable --trace-lines when passed to simulator_set_tracing().
-//!
+/** Enable --trace-lines when passed to simulator_set_tracing(). */
#define SIM_TRACE_LINES 0x80
-//! Turn off all tracing when passed to simulator_set_tracing().
-//!
+/** Turn off all tracing when passed to simulator_set_tracing(). */
#define SIM_TRACE_NONE 0
-//! Turn on all tracing when passed to simulator_set_tracing().
-//!
+/** Turn on all tracing when passed to simulator_set_tracing(). */
#define SIM_TRACE_ALL (-1)
-//! @}
+/** @} */
-//! Computes the value to write to SPR_SIM_CONTROL to set tracing flags.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to set tracing flags. */
#define SIM_TRACE_SPR_ARG(mask) \
(SIM_CONTROL_SET_TRACING | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
-//== Bit masks which can be shifted by 8, combined with
-//== SIM_CONTROL_DUMP, and written to SPR_SIM_CONTROL.
+/*
+ * Bit masks which can be shifted by 8, combined with
+ * SIM_CONTROL_DUMP, and written to SPR_SIM_CONTROL.
+ */
-//! @addtogroup arch_sim
-//! @{
+/**
+ * @addtogroup arch_sim
+ * @{
+ */
-//! Dump the general-purpose registers.
-//!
+/** Dump the general-purpose registers. */
#define SIM_DUMP_REGS 0x001
-//! Dump the SPRs.
-//!
+/** Dump the SPRs. */
#define SIM_DUMP_SPRS 0x002
-//! Dump the ITLB.
-//!
+/** Dump the ITLB. */
#define SIM_DUMP_ITLB 0x004
-//! Dump the DTLB.
-//!
+/** Dump the DTLB. */
#define SIM_DUMP_DTLB 0x008
-//! Dump the L1 I-cache.
-//!
+/** Dump the L1 I-cache. */
#define SIM_DUMP_L1I 0x010
-//! Dump the L1 D-cache.
-//!
+/** Dump the L1 D-cache. */
#define SIM_DUMP_L1D 0x020
-//! Dump the L2 cache.
-//!
+/** Dump the L2 cache. */
#define SIM_DUMP_L2 0x040
-//! Dump the switch registers.
-//!
+/** Dump the switch registers. */
#define SIM_DUMP_SNREGS 0x080
-//! Dump the switch ITLB.
-//!
+/** Dump the switch ITLB. */
#define SIM_DUMP_SNITLB 0x100
-//! Dump the switch L1 I-cache.
-//!
+/** Dump the switch L1 I-cache. */
#define SIM_DUMP_SNL1I 0x200
-//! Dump the current backtrace.
-//!
+/** Dump the current backtrace. */
#define SIM_DUMP_BACKTRACE 0x400
-//! Only dump valid lines in caches.
-//!
+/** Only dump valid lines in caches. */
#define SIM_DUMP_VALID_LINES 0x800
-//! Dump everything that is dumpable.
-//!
+/** Dump everything that is dumpable. */
#define SIM_DUMP_ALL (-1 & ~SIM_DUMP_VALID_LINES)
-// @}
+/** @} */
-//! Computes the value to write to SPR_SIM_CONTROL to dump machine state.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to dump machine state. */
#define SIM_DUMP_SPR_ARG(mask) \
(SIM_CONTROL_DUMP | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
-//== Bit masks which can be shifted by 8, combined with
-//== SIM_CONTROL_PROFILER_CHIP_xxx, and written to SPR_SIM_CONTROL.
+/*
+ * Bit masks which can be shifted by 8, combined with
+ * SIM_CONTROL_PROFILER_CHIP_xxx, and written to SPR_SIM_CONTROL.
+ */
-//! @addtogroup arch_sim
-//! @{
+/**
+ * @addtogroup arch_sim
+ * @{
+ */
-//! Use with with SIM_PROFILER_CHIP_xxx to control the memory controllers.
-//!
+/** Use with with SIM_PROFILER_CHIP_xxx to control the memory controllers. */
#define SIM_CHIP_MEMCTL 0x001
-//! Use with with SIM_PROFILER_CHIP_xxx to control the XAUI interface.
-//!
+/** Use with with SIM_PROFILER_CHIP_xxx to control the XAUI interface. */
#define SIM_CHIP_XAUI 0x002
-//! Use with with SIM_PROFILER_CHIP_xxx to control the PCIe interface.
-//!
+/** Use with with SIM_PROFILER_CHIP_xxx to control the PCIe interface. */
#define SIM_CHIP_PCIE 0x004
-//! Use with with SIM_PROFILER_CHIP_xxx to control the MPIPE interface.
-//!
+/** Use with with SIM_PROFILER_CHIP_xxx to control the MPIPE interface. */
#define SIM_CHIP_MPIPE 0x008
-//! Reference all chip devices.
-//!
+/** Use with with SIM_PROFILER_CHIP_xxx to control the TRIO interface. */
+#define SIM_CHIP_TRIO 0x010
+
+/** Reference all chip devices. */
#define SIM_CHIP_ALL (-1)
-//! @}
+/** @} */
-//! Computes the value to write to SPR_SIM_CONTROL to clear chip statistics.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to clear chip statistics. */
#define SIM_PROFILER_CHIP_CLEAR_SPR_ARG(mask) \
(SIM_CONTROL_PROFILER_CHIP_CLEAR | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
-//! Computes the value to write to SPR_SIM_CONTROL to disable chip statistics.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to disable chip statistics.*/
#define SIM_PROFILER_CHIP_DISABLE_SPR_ARG(mask) \
(SIM_CONTROL_PROFILER_CHIP_DISABLE | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
-//! Computes the value to write to SPR_SIM_CONTROL to enable chip statistics.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to enable chip statistics. */
#define SIM_PROFILER_CHIP_ENABLE_SPR_ARG(mask) \
(SIM_CONTROL_PROFILER_CHIP_ENABLE | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
-// Shim bitrate controls.
+/* Shim bitrate controls. */
-//! The number of bits used to store the shim id.
-//!
+/** The number of bits used to store the shim id. */
#define SIM_CONTROL_SHAPING_SHIM_ID_BITS 3
-//! @addtogroup arch_sim
-//! @{
+/**
+ * @addtogroup arch_sim
+ * @{
+ */
-//! Change the gbe 0 bitrate.
-//!
+/** Change the gbe 0 bitrate. */
#define SIM_CONTROL_SHAPING_GBE_0 0x0
-//! Change the gbe 1 bitrate.
-//!
+/** Change the gbe 1 bitrate. */
#define SIM_CONTROL_SHAPING_GBE_1 0x1
-//! Change the gbe 2 bitrate.
-//!
+/** Change the gbe 2 bitrate. */
#define SIM_CONTROL_SHAPING_GBE_2 0x2
-//! Change the gbe 3 bitrate.
-//!
+/** Change the gbe 3 bitrate. */
#define SIM_CONTROL_SHAPING_GBE_3 0x3
-//! Change the xgbe 0 bitrate.
-//!
+/** Change the xgbe 0 bitrate. */
#define SIM_CONTROL_SHAPING_XGBE_0 0x4
-//! Change the xgbe 1 bitrate.
-//!
+/** Change the xgbe 1 bitrate. */
#define SIM_CONTROL_SHAPING_XGBE_1 0x5
-//! The type of shaping to do.
-//!
+/** The type of shaping to do. */
#define SIM_CONTROL_SHAPING_TYPE_BITS 2
-//! Control the multiplier.
-//!
+/** Control the multiplier. */
#define SIM_CONTROL_SHAPING_MULTIPLIER 0
-//! Control the PPS.
-//!
+/** Control the PPS. */
#define SIM_CONTROL_SHAPING_PPS 1
-//! Control the BPS.
-//!
+/** Control the BPS. */
#define SIM_CONTROL_SHAPING_BPS 2
-//! The number of bits for the units for the shaping parameter.
-//!
+/** The number of bits for the units for the shaping parameter. */
#define SIM_CONTROL_SHAPING_UNITS_BITS 2
-//! Provide a number in single units.
-//!
+/** Provide a number in single units. */
#define SIM_CONTROL_SHAPING_UNITS_SINGLE 0
-//! Provide a number in kilo units.
-//!
+/** Provide a number in kilo units. */
#define SIM_CONTROL_SHAPING_UNITS_KILO 1
-//! Provide a number in mega units.
-//!
+/** Provide a number in mega units. */
#define SIM_CONTROL_SHAPING_UNITS_MEGA 2
-//! Provide a number in giga units.
-//!
+/** Provide a number in giga units. */
#define SIM_CONTROL_SHAPING_UNITS_GIGA 3
-// @}
+/** @} */
-//! How many bits are available for the rate.
-//!
+/** How many bits are available for the rate. */
#define SIM_CONTROL_SHAPING_RATE_BITS \
(32 - (_SIM_CONTROL_OPERATOR_BITS + \
SIM_CONTROL_SHAPING_SHIM_ID_BITS + \
SIM_CONTROL_SHAPING_TYPE_BITS + \
SIM_CONTROL_SHAPING_UNITS_BITS))
-//! Computes the value to write to SPR_SIM_CONTROL to change a bitrate.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to change a bitrate. */
#define SIM_SHAPING_SPR_ARG(shim, type, units, rate) \
(SIM_CONTROL_SHAPING | \
((shim) | \
@@ -483,30 +467,36 @@
SIM_CONTROL_SHAPING_UNITS_BITS))) << _SIM_CONTROL_OPERATOR_BITS)
-//== Values returned when reading SPR_SIM_CONTROL.
-// ISSUE: These names should share a longer common prefix.
+/*
+ * Values returned when reading SPR_SIM_CONTROL.
+ * ISSUE: These names should share a longer common prefix.
+ */
-//! When reading SPR_SIM_CONTROL, the mask of simulator tracing bits
-//! (SIM_TRACE_xxx values).
-//!
+/**
+ * When reading SPR_SIM_CONTROL, the mask of simulator tracing bits
+ * (SIM_TRACE_xxx values).
+ */
#define SIM_TRACE_FLAG_MASK 0xFFFF
-//! When reading SPR_SIM_CONTROL, the mask for whether profiling is enabled.
-//!
+/** When reading SPR_SIM_CONTROL, the mask for whether profiling is enabled. */
#define SIM_PROFILER_ENABLED_MASK 0x10000
-//== Special arguments for "SIM_CONTROL_PUTC".
+/*
+ * Special arguments for "SIM_CONTROL_PUTC".
+ */
-//! Flag value for forcing a PUTC string-flush, including
-//! coordinate/cycle prefix and newline.
-//!
+/**
+ * Flag value for forcing a PUTC string-flush, including
+ * coordinate/cycle prefix and newline.
+ */
#define SIM_PUTC_FLUSH_STRING 0x100
-//! Flag value for forcing a PUTC binary-data-flush, which skips the
-//! prefix and does not append a newline.
-//!
+/**
+ * Flag value for forcing a PUTC binary-data-flush, which skips the
+ * prefix and does not append a newline.
+ */
#define SIM_PUTC_FLUSH_BINARY 0x101
-#endif //__ARCH_SIM_DEF_H__
+#endif /* __ARCH_SIM_DEF_H__ */
diff --git a/arch/tile/include/arch/spr_def.h b/arch/tile/include/arch/spr_def.h
index c8fdbd9a45e6..442fcba0d122 100644
--- a/arch/tile/include/arch/spr_def.h
+++ b/arch/tile/include/arch/spr_def.h
@@ -12,8 +12,93 @@
* more details.
*/
+/*
+ * In addition to including the proper base SPR definition file, depending
+ * on machine architecture, this file defines several macros which allow
+ * kernel code to use protection-level dependent SPRs without worrying
+ * about which PL it's running at. In these macros, the PL that the SPR
+ * or interrupt number applies to is replaced by K.
+ */
+
+#if CONFIG_KERNEL_PL != 1 && CONFIG_KERNEL_PL != 2
+#error CONFIG_KERNEL_PL must be 1 or 2
+#endif
+
+/* Concatenate 4 strings. */
+#define __concat4(a, b, c, d) a ## b ## c ## d
+#define _concat4(a, b, c, d) __concat4(a, b, c, d)
+
#ifdef __tilegx__
#include <arch/spr_def_64.h>
+
+/* TILE-Gx dependent, protection-level dependent SPRs. */
+
+#define SPR_INTERRUPT_MASK_K \
+ _concat4(SPR_INTERRUPT_MASK_, CONFIG_KERNEL_PL,,)
+#define SPR_INTERRUPT_MASK_SET_K \
+ _concat4(SPR_INTERRUPT_MASK_SET_, CONFIG_KERNEL_PL,,)
+#define SPR_INTERRUPT_MASK_RESET_K \
+ _concat4(SPR_INTERRUPT_MASK_RESET_, CONFIG_KERNEL_PL,,)
+#define SPR_INTERRUPT_VECTOR_BASE_K \
+ _concat4(SPR_INTERRUPT_VECTOR_BASE_, CONFIG_KERNEL_PL,,)
+
+#define SPR_IPI_MASK_K \
+ _concat4(SPR_IPI_MASK_, CONFIG_KERNEL_PL,,)
+#define SPR_IPI_MASK_RESET_K \
+ _concat4(SPR_IPI_MASK_RESET_, CONFIG_KERNEL_PL,,)
+#define SPR_IPI_MASK_SET_K \
+ _concat4(SPR_IPI_MASK_SET_, CONFIG_KERNEL_PL,,)
+#define SPR_IPI_EVENT_K \
+ _concat4(SPR_IPI_EVENT_, CONFIG_KERNEL_PL,,)
+#define SPR_IPI_EVENT_RESET_K \
+ _concat4(SPR_IPI_EVENT_RESET_, CONFIG_KERNEL_PL,,)
+#define SPR_IPI_MASK_SET_K \
+ _concat4(SPR_IPI_MASK_SET_, CONFIG_KERNEL_PL,,)
+#define INT_IPI_K \
+ _concat4(INT_IPI_, CONFIG_KERNEL_PL,,)
+
+#define SPR_SINGLE_STEP_CONTROL_K \
+ _concat4(SPR_SINGLE_STEP_CONTROL_, CONFIG_KERNEL_PL,,)
+#define SPR_SINGLE_STEP_EN_K_K \
+ _concat4(SPR_SINGLE_STEP_EN_, CONFIG_KERNEL_PL, _, CONFIG_KERNEL_PL)
+#define INT_SINGLE_STEP_K \
+ _concat4(INT_SINGLE_STEP_, CONFIG_KERNEL_PL,,)
+
#else
#include <arch/spr_def_32.h>
+
+/* TILEPro dependent, protection-level dependent SPRs. */
+
+#define SPR_INTERRUPT_MASK_K_0 \
+ _concat4(SPR_INTERRUPT_MASK_, CONFIG_KERNEL_PL, _0,)
+#define SPR_INTERRUPT_MASK_K_1 \
+ _concat4(SPR_INTERRUPT_MASK_, CONFIG_KERNEL_PL, _1,)
+#define SPR_INTERRUPT_MASK_SET_K_0 \
+ _concat4(SPR_INTERRUPT_MASK_SET_, CONFIG_KERNEL_PL, _0,)
+#define SPR_INTERRUPT_MASK_SET_K_1 \
+ _concat4(SPR_INTERRUPT_MASK_SET_, CONFIG_KERNEL_PL, _1,)
+#define SPR_INTERRUPT_MASK_RESET_K_0 \
+ _concat4(SPR_INTERRUPT_MASK_RESET_, CONFIG_KERNEL_PL, _0,)
+#define SPR_INTERRUPT_MASK_RESET_K_1 \
+ _concat4(SPR_INTERRUPT_MASK_RESET_, CONFIG_KERNEL_PL, _1,)
+
#endif
+
+/* Generic protection-level dependent SPRs. */
+
+#define SPR_SYSTEM_SAVE_K_0 \
+ _concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _0,)
+#define SPR_SYSTEM_SAVE_K_1 \
+ _concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _1,)
+#define SPR_SYSTEM_SAVE_K_2 \
+ _concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _2,)
+#define SPR_SYSTEM_SAVE_K_3 \
+ _concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _3,)
+#define SPR_EX_CONTEXT_K_0 \
+ _concat4(SPR_EX_CONTEXT_, CONFIG_KERNEL_PL, _0,)
+#define SPR_EX_CONTEXT_K_1 \
+ _concat4(SPR_EX_CONTEXT_, CONFIG_KERNEL_PL, _1,)
+#define SPR_INTCTRL_K_STATUS \
+ _concat4(SPR_INTCTRL_, CONFIG_KERNEL_PL, _STATUS,)
+#define INT_INTCTRL_K \
+ _concat4(INT_INTCTRL_, CONFIG_KERNEL_PL,,)
diff --git a/arch/tile/include/arch/spr_def_32.h b/arch/tile/include/arch/spr_def_32.h
index b4fc06864df6..bbc1f4c924ee 100644
--- a/arch/tile/include/arch/spr_def_32.h
+++ b/arch/tile/include/arch/spr_def_32.h
@@ -56,58 +56,93 @@
#define SPR_EX_CONTEXT_1_1__ICS_SHIFT 2
#define SPR_EX_CONTEXT_1_1__ICS_RMASK 0x1
#define SPR_EX_CONTEXT_1_1__ICS_MASK 0x4
+#define SPR_EX_CONTEXT_2_0 0x4605
+#define SPR_EX_CONTEXT_2_1 0x4606
+#define SPR_EX_CONTEXT_2_1__PL_SHIFT 0
+#define SPR_EX_CONTEXT_2_1__PL_RMASK 0x3
+#define SPR_EX_CONTEXT_2_1__PL_MASK 0x3
+#define SPR_EX_CONTEXT_2_1__ICS_SHIFT 2
+#define SPR_EX_CONTEXT_2_1__ICS_RMASK 0x1
+#define SPR_EX_CONTEXT_2_1__ICS_MASK 0x4
#define SPR_FAIL 0x4e09
#define SPR_INTCTRL_0_STATUS 0x4a07
#define SPR_INTCTRL_1_STATUS 0x4807
+#define SPR_INTCTRL_2_STATUS 0x4607
#define SPR_INTERRUPT_CRITICAL_SECTION 0x4e0a
#define SPR_INTERRUPT_MASK_0_0 0x4a08
#define SPR_INTERRUPT_MASK_0_1 0x4a09
#define SPR_INTERRUPT_MASK_1_0 0x4809
#define SPR_INTERRUPT_MASK_1_1 0x480a
+#define SPR_INTERRUPT_MASK_2_0 0x4608
+#define SPR_INTERRUPT_MASK_2_1 0x4609
#define SPR_INTERRUPT_MASK_RESET_0_0 0x4a0a
#define SPR_INTERRUPT_MASK_RESET_0_1 0x4a0b
#define SPR_INTERRUPT_MASK_RESET_1_0 0x480b
#define SPR_INTERRUPT_MASK_RESET_1_1 0x480c
+#define SPR_INTERRUPT_MASK_RESET_2_0 0x460a
+#define SPR_INTERRUPT_MASK_RESET_2_1 0x460b
#define SPR_INTERRUPT_MASK_SET_0_0 0x4a0c
#define SPR_INTERRUPT_MASK_SET_0_1 0x4a0d
#define SPR_INTERRUPT_MASK_SET_1_0 0x480d
#define SPR_INTERRUPT_MASK_SET_1_1 0x480e
+#define SPR_INTERRUPT_MASK_SET_2_0 0x460c
+#define SPR_INTERRUPT_MASK_SET_2_1 0x460d
#define SPR_MPL_DMA_CPL_SET_0 0x5800
#define SPR_MPL_DMA_CPL_SET_1 0x5801
+#define SPR_MPL_DMA_CPL_SET_2 0x5802
#define SPR_MPL_DMA_NOTIFY_SET_0 0x3800
#define SPR_MPL_DMA_NOTIFY_SET_1 0x3801
+#define SPR_MPL_DMA_NOTIFY_SET_2 0x3802
#define SPR_MPL_INTCTRL_0_SET_0 0x4a00
#define SPR_MPL_INTCTRL_0_SET_1 0x4a01
+#define SPR_MPL_INTCTRL_0_SET_2 0x4a02
#define SPR_MPL_INTCTRL_1_SET_0 0x4800
#define SPR_MPL_INTCTRL_1_SET_1 0x4801
+#define SPR_MPL_INTCTRL_1_SET_2 0x4802
+#define SPR_MPL_INTCTRL_2_SET_0 0x4600
+#define SPR_MPL_INTCTRL_2_SET_1 0x4601
+#define SPR_MPL_INTCTRL_2_SET_2 0x4602
#define SPR_MPL_SN_ACCESS_SET_0 0x0800
#define SPR_MPL_SN_ACCESS_SET_1 0x0801
+#define SPR_MPL_SN_ACCESS_SET_2 0x0802
#define SPR_MPL_SN_CPL_SET_0 0x5a00
#define SPR_MPL_SN_CPL_SET_1 0x5a01
+#define SPR_MPL_SN_CPL_SET_2 0x5a02
#define SPR_MPL_SN_FIREWALL_SET_0 0x2c00
#define SPR_MPL_SN_FIREWALL_SET_1 0x2c01
+#define SPR_MPL_SN_FIREWALL_SET_2 0x2c02
#define SPR_MPL_SN_NOTIFY_SET_0 0x2a00
#define SPR_MPL_SN_NOTIFY_SET_1 0x2a01
+#define SPR_MPL_SN_NOTIFY_SET_2 0x2a02
#define SPR_MPL_UDN_ACCESS_SET_0 0x0c00
#define SPR_MPL_UDN_ACCESS_SET_1 0x0c01
+#define SPR_MPL_UDN_ACCESS_SET_2 0x0c02
#define SPR_MPL_UDN_AVAIL_SET_0 0x4000
#define SPR_MPL_UDN_AVAIL_SET_1 0x4001
+#define SPR_MPL_UDN_AVAIL_SET_2 0x4002
#define SPR_MPL_UDN_CA_SET_0 0x3c00
#define SPR_MPL_UDN_CA_SET_1 0x3c01
+#define SPR_MPL_UDN_CA_SET_2 0x3c02
#define SPR_MPL_UDN_COMPLETE_SET_0 0x1400
#define SPR_MPL_UDN_COMPLETE_SET_1 0x1401
+#define SPR_MPL_UDN_COMPLETE_SET_2 0x1402
#define SPR_MPL_UDN_FIREWALL_SET_0 0x3000
#define SPR_MPL_UDN_FIREWALL_SET_1 0x3001
+#define SPR_MPL_UDN_FIREWALL_SET_2 0x3002
#define SPR_MPL_UDN_REFILL_SET_0 0x1000
#define SPR_MPL_UDN_REFILL_SET_1 0x1001
+#define SPR_MPL_UDN_REFILL_SET_2 0x1002
#define SPR_MPL_UDN_TIMER_SET_0 0x3600
#define SPR_MPL_UDN_TIMER_SET_1 0x3601
+#define SPR_MPL_UDN_TIMER_SET_2 0x3602
#define SPR_MPL_WORLD_ACCESS_SET_0 0x4e00
#define SPR_MPL_WORLD_ACCESS_SET_1 0x4e01
+#define SPR_MPL_WORLD_ACCESS_SET_2 0x4e02
#define SPR_PASS 0x4e0b
#define SPR_PERF_COUNT_0 0x4205
#define SPR_PERF_COUNT_1 0x4206
#define SPR_PERF_COUNT_CTL 0x4207
+#define SPR_PERF_COUNT_DN_CTL 0x4210
#define SPR_PERF_COUNT_STS 0x4208
#define SPR_PROC_STATUS 0x4f00
#define SPR_SIM_CONTROL 0x4e0c
@@ -124,6 +159,10 @@
#define SPR_SYSTEM_SAVE_1_1 0x4901
#define SPR_SYSTEM_SAVE_1_2 0x4902
#define SPR_SYSTEM_SAVE_1_3 0x4903
+#define SPR_SYSTEM_SAVE_2_0 0x4700
+#define SPR_SYSTEM_SAVE_2_1 0x4701
+#define SPR_SYSTEM_SAVE_2_2 0x4702
+#define SPR_SYSTEM_SAVE_2_3 0x4703
#define SPR_TILE_COORD 0x4c17
#define SPR_TILE_RTF_HWM 0x4e10
#define SPR_TILE_TIMER_CONTROL 0x3205
diff --git a/arch/tile/include/asm/backtrace.h b/arch/tile/include/asm/backtrace.h
index 758ca4619d50..f18887d82399 100644
--- a/arch/tile/include/asm/backtrace.h
+++ b/arch/tile/include/asm/backtrace.h
@@ -146,7 +146,10 @@ enum {
CALLER_SP_IN_R52_BASE = 4,
- CALLER_SP_OFFSET_BASE = 8
+ CALLER_SP_OFFSET_BASE = 8,
+
+ /* Marks the entry point of certain functions. */
+ ENTRY_POINT_INFO_OP = 16
};
diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h
index 8b60ec8b2d19..c3ae570c0a5d 100644
--- a/arch/tile/include/asm/compat.h
+++ b/arch/tile/include/asm/compat.h
@@ -216,15 +216,16 @@ struct compat_siginfo;
struct compat_sigaltstack;
long compat_sys_execve(const char __user *path,
const compat_uptr_t __user *argv,
- const compat_uptr_t __user *envp);
+ const compat_uptr_t __user *envp, struct pt_regs *);
long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
struct compat_sigaction __user *oact,
size_t sigsetsize);
long compat_sys_rt_sigqueueinfo(int pid, int sig,
struct compat_siginfo __user *uinfo);
-long compat_sys_rt_sigreturn(void);
+long compat_sys_rt_sigreturn(struct pt_regs *);
long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
- struct compat_sigaltstack __user *uoss_ptr);
+ struct compat_sigaltstack __user *uoss_ptr,
+ struct pt_regs *);
long compat_sys_truncate64(char __user *filename, u32 dummy, u32 low, u32 high);
long compat_sys_ftruncate64(unsigned int fd, u32 dummy, u32 low, u32 high);
long compat_sys_pread64(unsigned int fd, char __user *ubuf, size_t count,
@@ -255,4 +256,12 @@ long tile_compat_sys_ptrace(compat_long_t request, compat_long_t pid,
/* Tilera Linux syscalls that don't have "compat" versions. */
#define compat_sys_flush_cache sys_flush_cache
+/* These are the intvec_64.S trampolines. */
+long _compat_sys_execve(const char __user *path,
+ const compat_uptr_t __user *argv,
+ const compat_uptr_t __user *envp);
+long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
+ struct compat_sigaltstack __user *uoss_ptr);
+long _compat_sys_rt_sigreturn(void);
+
#endif /* _ASM_TILE_COMPAT_H */
diff --git a/arch/tile/include/asm/highmem.h b/arch/tile/include/asm/highmem.h
index d155db6fa9bd..e0f7ee186721 100644
--- a/arch/tile/include/asm/highmem.h
+++ b/arch/tile/include/asm/highmem.h
@@ -60,12 +60,12 @@ void *kmap_fix_kpte(struct page *page, int finished);
/* This macro is used only in map_new_virtual() to map "page". */
#define kmap_prot page_to_kpgprot(page)
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
-void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
+void *__kmap_atomic(struct page *page);
+void __kunmap_atomic(void *kvaddr);
+void *kmap_atomic_pfn(unsigned long pfn);
+void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot);
struct page *kmap_atomic_to_page(void *ptr);
-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot);
-void *kmap_atomic(struct page *page, enum km_type type);
+void *kmap_atomic_prot(struct page *page, pgprot_t prot);
void kmap_atomic_fix_kpte(struct page *page, int finished);
#define flush_cache_kmaps() do { } while (0)
diff --git a/arch/tile/include/asm/irqflags.h b/arch/tile/include/asm/irqflags.h
index a11d4837ee4d..641e4ff3d805 100644
--- a/arch/tile/include/asm/irqflags.h
+++ b/arch/tile/include/asm/irqflags.h
@@ -47,53 +47,53 @@
int __n = (n); \
int __mask = 1 << (__n & 0x1f); \
if (__n < 32) \
- __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_0, __mask); \
+ __insn_mtspr(SPR_INTERRUPT_MASK_SET_K_0, __mask); \
else \
- __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_1, __mask); \
+ __insn_mtspr(SPR_INTERRUPT_MASK_SET_K_1, __mask); \
} while (0)
#define interrupt_mask_reset(n) do { \
int __n = (n); \
int __mask = 1 << (__n & 0x1f); \
if (__n < 32) \
- __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_0, __mask); \
+ __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_0, __mask); \
else \
- __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_1, __mask); \
+ __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_1, __mask); \
} while (0)
#define interrupt_mask_check(n) ({ \
int __n = (n); \
(((__n < 32) ? \
- __insn_mfspr(SPR_INTERRUPT_MASK_1_0) : \
- __insn_mfspr(SPR_INTERRUPT_MASK_1_1)) \
+ __insn_mfspr(SPR_INTERRUPT_MASK_K_0) : \
+ __insn_mfspr(SPR_INTERRUPT_MASK_K_1)) \
>> (__n & 0x1f)) & 1; \
})
#define interrupt_mask_set_mask(mask) do { \
unsigned long long __m = (mask); \
- __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_0, (unsigned long)(__m)); \
- __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_1, (unsigned long)(__m>>32)); \
+ __insn_mtspr(SPR_INTERRUPT_MASK_SET_K_0, (unsigned long)(__m)); \
+ __insn_mtspr(SPR_INTERRUPT_MASK_SET_K_1, (unsigned long)(__m>>32)); \
} while (0)
#define interrupt_mask_reset_mask(mask) do { \
unsigned long long __m = (mask); \
- __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_0, (unsigned long)(__m)); \
- __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_1, (unsigned long)(__m>>32)); \
+ __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_0, (unsigned long)(__m)); \
+ __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_1, (unsigned long)(__m>>32)); \
} while (0)
#else
#define interrupt_mask_set(n) \
- __insn_mtspr(SPR_INTERRUPT_MASK_SET_1, (1UL << (n)))
+ __insn_mtspr(SPR_INTERRUPT_MASK_SET_K, (1UL << (n)))
#define interrupt_mask_reset(n) \
- __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1, (1UL << (n)))
+ __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K, (1UL << (n)))
#define interrupt_mask_check(n) \
- ((__insn_mfspr(SPR_INTERRUPT_MASK_1) >> (n)) & 1)
+ ((__insn_mfspr(SPR_INTERRUPT_MASK_K) >> (n)) & 1)
#define interrupt_mask_set_mask(mask) \
- __insn_mtspr(SPR_INTERRUPT_MASK_SET_1, (mask))
+ __insn_mtspr(SPR_INTERRUPT_MASK_SET_K, (mask))
#define interrupt_mask_reset_mask(mask) \
- __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1, (mask))
+ __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K, (mask))
#endif
/*
* The set of interrupts we want active if irqs are enabled.
* Note that in particular, the tile timer interrupt comes and goes
* from this set, since we have no other way to turn off the timer.
- * Likewise, INTCTRL_1 is removed and re-added during device
+ * Likewise, INTCTRL_K is removed and re-added during device
* interrupts, as is the the hardwall UDN_FIREWALL interrupt.
* We use a low bit (MEM_ERROR) as our sentinel value and make sure it
* is always claimed as an "active interrupt" so we can query that bit
@@ -170,14 +170,14 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
/* Return 0 or 1 to indicate whether interrupts are currently disabled. */
#define IRQS_DISABLED(tmp) \
- mfspr tmp, INTERRUPT_MASK_1; \
+ mfspr tmp, SPR_INTERRUPT_MASK_K; \
andi tmp, tmp, 1
/* Load up a pointer to &interrupts_enabled_mask. */
#define GET_INTERRUPTS_ENABLED_MASK_PTR(reg) \
- moveli reg, hw2_last(interrupts_enabled_mask); \
- shl16insli reg, reg, hw1(interrupts_enabled_mask); \
- shl16insli reg, reg, hw0(interrupts_enabled_mask); \
+ moveli reg, hw2_last(interrupts_enabled_mask); \
+ shl16insli reg, reg, hw1(interrupts_enabled_mask); \
+ shl16insli reg, reg, hw0(interrupts_enabled_mask); \
add reg, reg, tp
/* Disable interrupts. */
@@ -185,18 +185,18 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
moveli tmp0, hw2_last(LINUX_MASKABLE_INTERRUPTS); \
shl16insli tmp0, tmp0, hw1(LINUX_MASKABLE_INTERRUPTS); \
shl16insli tmp0, tmp0, hw0(LINUX_MASKABLE_INTERRUPTS); \
- mtspr INTERRUPT_MASK_SET_1, tmp0
+ mtspr SPR_INTERRUPT_MASK_SET_K, tmp0
/* Disable ALL synchronous interrupts (used by NMI entry). */
#define IRQ_DISABLE_ALL(tmp) \
movei tmp, -1; \
- mtspr INTERRUPT_MASK_SET_1, tmp
+ mtspr SPR_INTERRUPT_MASK_SET_K, tmp
/* Enable interrupts. */
#define IRQ_ENABLE(tmp0, tmp1) \
GET_INTERRUPTS_ENABLED_MASK_PTR(tmp0); \
ld tmp0, tmp0; \
- mtspr INTERRUPT_MASK_RESET_1, tmp0
+ mtspr SPR_INTERRUPT_MASK_RESET_K, tmp0
#else /* !__tilegx__ */
@@ -210,14 +210,14 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
* (making the original code's write of the "high" mask word idempotent).
*/
#define IRQS_DISABLED(tmp) \
- mfspr tmp, INTERRUPT_MASK_1_0; \
+ mfspr tmp, SPR_INTERRUPT_MASK_K_0; \
shri tmp, tmp, INT_MEM_ERROR; \
andi tmp, tmp, 1
/* Load up a pointer to &interrupts_enabled_mask. */
#define GET_INTERRUPTS_ENABLED_MASK_PTR(reg) \
- moveli reg, lo16(interrupts_enabled_mask); \
- auli reg, reg, ha16(interrupts_enabled_mask);\
+ moveli reg, lo16(interrupts_enabled_mask); \
+ auli reg, reg, ha16(interrupts_enabled_mask); \
add reg, reg, tp
/* Disable interrupts. */
@@ -227,16 +227,16 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
moveli tmp1, lo16(LINUX_MASKABLE_INTERRUPTS) \
}; \
{ \
- mtspr INTERRUPT_MASK_SET_1_0, tmp0; \
+ mtspr SPR_INTERRUPT_MASK_SET_K_0, tmp0; \
auli tmp1, tmp1, ha16(LINUX_MASKABLE_INTERRUPTS) \
}; \
- mtspr INTERRUPT_MASK_SET_1_1, tmp1
+ mtspr SPR_INTERRUPT_MASK_SET_K_1, tmp1
/* Disable ALL synchronous interrupts (used by NMI entry). */
#define IRQ_DISABLE_ALL(tmp) \
movei tmp, -1; \
- mtspr INTERRUPT_MASK_SET_1_0, tmp; \
- mtspr INTERRUPT_MASK_SET_1_1, tmp
+ mtspr SPR_INTERRUPT_MASK_SET_K_0, tmp; \
+ mtspr SPR_INTERRUPT_MASK_SET_K_1, tmp
/* Enable interrupts. */
#define IRQ_ENABLE(tmp0, tmp1) \
@@ -246,8 +246,8 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
addi tmp1, tmp0, 4 \
}; \
lw tmp1, tmp1; \
- mtspr INTERRUPT_MASK_RESET_1_0, tmp0; \
- mtspr INTERRUPT_MASK_RESET_1_1, tmp1
+ mtspr SPR_INTERRUPT_MASK_RESET_K_0, tmp0; \
+ mtspr SPR_INTERRUPT_MASK_RESET_K_1, tmp1
#endif
/*
diff --git a/arch/tile/include/asm/mman.h b/arch/tile/include/asm/mman.h
index 4c6811e3e8dc..81b8fc348d63 100644
--- a/arch/tile/include/asm/mman.h
+++ b/arch/tile/include/asm/mman.h
@@ -23,6 +23,7 @@
#define MAP_POPULATE 0x0040 /* populate (prefault) pagetables */
#define MAP_NONBLOCK 0x0080 /* do not block on IO */
#define MAP_GROWSDOWN 0x0100 /* stack-like segment */
+#define MAP_STACK MAP_GROWSDOWN /* provide convenience alias */
#define MAP_LOCKED 0x0200 /* pages are locked */
#define MAP_NORESERVE 0x0400 /* don't check for reservations */
#define MAP_DENYWRITE 0x0800 /* ETXTBSY */
diff --git a/arch/tile/include/asm/page.h b/arch/tile/include/asm/page.h
index 7d90641cf18d..7979a45430d3 100644
--- a/arch/tile/include/asm/page.h
+++ b/arch/tile/include/asm/page.h
@@ -199,17 +199,17 @@ static inline __attribute_const__ int get_order(unsigned long size)
* If you want more physical memory than this then see the CONFIG_HIGHMEM
* option in the kernel configuration.
*
- * The top two 16MB chunks in the table below (VIRT and HV) are
- * unavailable to Linux. Since the kernel interrupt vectors must live
- * at 0xfd000000, we map all of the bottom of RAM at this address with
- * a huge page table entry to minimize its ITLB footprint (as well as
- * at PAGE_OFFSET). The last architected requirement is that user
- * interrupt vectors live at 0xfc000000, so we make that range of
- * memory available to user processes. The remaining regions are sized
- * as shown; after the first four addresses, we show "typical" values,
- * since the actual addresses depend on kernel #defines.
+ * The top 16MB chunk in the table below is unavailable to Linux. Since
+ * the kernel interrupt vectors must live at ether 0xfe000000 or 0xfd000000
+ * (depending on whether the kernel is at PL2 or Pl1), we map all of the
+ * bottom of RAM at this address with a huge page table entry to minimize
+ * its ITLB footprint (as well as at PAGE_OFFSET). The last architected
+ * requirement is that user interrupt vectors live at 0xfc000000, so we
+ * make that range of memory available to user processes. The remaining
+ * regions are sized as shown; the first four addresses use the PL 1
+ * values, and after that, we show "typical" values, since the actual
+ * addresses depend on kernel #defines.
*
- * MEM_VIRT_INTRPT 0xff000000
* MEM_HV_INTRPT 0xfe000000
* MEM_SV_INTRPT (kernel code) 0xfd000000
* MEM_USER_INTRPT (user vector) 0xfc000000
@@ -221,9 +221,14 @@ static inline __attribute_const__ int get_order(unsigned long size)
*/
#define MEM_USER_INTRPT _AC(0xfc000000, UL)
+#if CONFIG_KERNEL_PL == 1
#define MEM_SV_INTRPT _AC(0xfd000000, UL)
#define MEM_HV_INTRPT _AC(0xfe000000, UL)
-#define MEM_VIRT_INTRPT _AC(0xff000000, UL)
+#else
+#define MEM_GUEST_INTRPT _AC(0xfd000000, UL)
+#define MEM_SV_INTRPT _AC(0xfe000000, UL)
+#define MEM_HV_INTRPT _AC(0xff000000, UL)
+#endif
#define INTRPT_SIZE 0x4000
diff --git a/arch/tile/include/asm/pgtable.h b/arch/tile/include/asm/pgtable.h
index b3367379d537..dc4ccdd855bc 100644
--- a/arch/tile/include/asm/pgtable.h
+++ b/arch/tile/include/asm/pgtable.h
@@ -347,15 +347,10 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
extern pte_t *_pte_offset_map(pmd_t *, unsigned long address, enum km_type);
#define pte_offset_map(dir, address) \
_pte_offset_map(dir, address, KM_PTE0)
-#define pte_offset_map_nested(dir, address) \
- _pte_offset_map(dir, address, KM_PTE1)
#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
-#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
#else
#define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
-#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
#define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
#endif
/* Clear a non-executable kernel PTE and flush it from the TLB. */
diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h
index ccd5f8425688..1747ff3946b2 100644
--- a/arch/tile/include/asm/processor.h
+++ b/arch/tile/include/asm/processor.h
@@ -328,18 +328,21 @@ extern int kdata_huge;
* Note that assembly code assumes that USER_PL is zero.
*/
#define USER_PL 0
-#define KERNEL_PL 1
+#if CONFIG_KERNEL_PL == 2
+#define GUEST_PL 1
+#endif
+#define KERNEL_PL CONFIG_KERNEL_PL
-/* SYSTEM_SAVE_1_0 holds the current cpu number ORed with ksp0. */
+/* SYSTEM_SAVE_K_0 holds the current cpu number ORed with ksp0. */
#define CPU_LOG_MASK_VALUE 12
#define CPU_MASK_VALUE ((1 << CPU_LOG_MASK_VALUE) - 1)
#if CONFIG_NR_CPUS > CPU_MASK_VALUE
# error Too many cpus!
#endif
#define raw_smp_processor_id() \
- ((int)__insn_mfspr(SPR_SYSTEM_SAVE_1_0) & CPU_MASK_VALUE)
+ ((int)__insn_mfspr(SPR_SYSTEM_SAVE_K_0) & CPU_MASK_VALUE)
#define get_current_ksp0() \
- (__insn_mfspr(SPR_SYSTEM_SAVE_1_0) & ~CPU_MASK_VALUE)
+ (__insn_mfspr(SPR_SYSTEM_SAVE_K_0) & ~CPU_MASK_VALUE)
#define next_current_ksp0(task) ({ \
unsigned long __ksp0 = task_ksp0(task); \
int __cpu = raw_smp_processor_id(); \
diff --git a/arch/tile/include/asm/ptrace.h b/arch/tile/include/asm/ptrace.h
index 4a02bb073979..ac6d343129d3 100644
--- a/arch/tile/include/asm/ptrace.h
+++ b/arch/tile/include/asm/ptrace.h
@@ -62,8 +62,8 @@ struct pt_regs {
pt_reg_t lr; /* aliases regs[TREG_LR] */
/* Saved special registers. */
- pt_reg_t pc; /* stored in EX_CONTEXT_1_0 */
- pt_reg_t ex1; /* stored in EX_CONTEXT_1_1 (PL and ICS bit) */
+ pt_reg_t pc; /* stored in EX_CONTEXT_K_0 */
+ pt_reg_t ex1; /* stored in EX_CONTEXT_K_1 (PL and ICS bit) */
pt_reg_t faultnum; /* fault number (INT_SWINT_1 for syscall) */
pt_reg_t orig_r0; /* r0 at syscall entry, else zero */
pt_reg_t flags; /* flags (see below) */
diff --git a/arch/tile/include/asm/syscalls.h b/arch/tile/include/asm/syscalls.h
index ce99ffefeacf..3b5507c31eae 100644
--- a/arch/tile/include/asm/syscalls.h
+++ b/arch/tile/include/asm/syscalls.h
@@ -32,8 +32,9 @@ extern void *compat_sys_call_table[];
/*
* Note that by convention, any syscall which requires the current
- * register set takes an additional "struct pt_regs *" pointer; the
- * sys_xxx() function just adds the pointer and tail-calls to _sys_xxx().
+ * register set takes an additional "struct pt_regs *" pointer; a
+ * _sys_xxx() trampoline in intvec*.S just sets up the pointer and
+ * jumps to sys_xxx().
*/
/* kernel/sys.c */
@@ -43,66 +44,17 @@ long sys32_fadvise64(int fd, u32 offset_lo, u32 offset_hi,
int sys32_fadvise64_64(int fd, u32 offset_lo, u32 offset_hi,
u32 len_lo, u32 len_hi, int advice);
long sys_flush_cache(void);
-long sys_mmap2(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff);
-#ifdef __tilegx__
-long sys_mmap(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, off_t pgoff);
+#ifndef __tilegx__ /* No mmap() in the 32-bit kernel. */
+#define sys_mmap sys_mmap
#endif
-/* kernel/process.c */
-long sys_clone(unsigned long clone_flags, unsigned long newsp,
- void __user *parent_tid, void __user *child_tid);
-long _sys_clone(unsigned long clone_flags, unsigned long newsp,
- void __user *parent_tid, void __user *child_tid,
- struct pt_regs *regs);
-long sys_fork(void);
-long _sys_fork(struct pt_regs *regs);
-long sys_vfork(void);
-long _sys_vfork(struct pt_regs *regs);
-long sys_execve(const char __user *filename,
- const char __user *const __user *argv,
- const char __user *const __user *envp);
-long _sys_execve(const char __user *filename,
- const char __user *const __user *argv,
- const char __user *const __user *envp, struct pt_regs *regs);
-
-/* kernel/signal.c */
-long sys_sigaltstack(const stack_t __user *, stack_t __user *);
-long _sys_sigaltstack(const stack_t __user *, stack_t __user *,
- struct pt_regs *);
-long sys_rt_sigreturn(void);
-long _sys_rt_sigreturn(struct pt_regs *regs);
-
-/* platform-independent functions */
-long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize);
-long sys_rt_sigaction(int sig, const struct sigaction __user *act,
- struct sigaction __user *oact, size_t sigsetsize);
-
#ifndef __tilegx__
/* mm/fault.c */
-int sys_cmpxchg_badaddr(unsigned long address);
-int _sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *);
+long sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *);
+long _sys_cmpxchg_badaddr(unsigned long address);
#endif
#ifdef CONFIG_COMPAT
-long compat_sys_execve(const char __user *path,
- const compat_uptr_t __user *argv,
- const compat_uptr_t __user *envp);
-long _compat_sys_execve(const char __user *path,
- const compat_uptr_t __user *argv,
- const compat_uptr_t __user *envp,
- struct pt_regs *regs);
-long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
- struct compat_sigaltstack __user *uoss_ptr);
-long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
- struct compat_sigaltstack __user *uoss_ptr,
- struct pt_regs *regs);
-long compat_sys_rt_sigreturn(void);
-long _compat_sys_rt_sigreturn(struct pt_regs *regs);
-
/* These four are not defined for 64-bit, but serve as "compat" syscalls. */
long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg);
long sys_fstat64(unsigned long fd, struct stat64 __user *statbuf);
@@ -110,4 +62,15 @@ long sys_truncate64(const char __user *path, loff_t length);
long sys_ftruncate64(unsigned int fd, loff_t length);
#endif
+/* These are the intvec*.S trampolines. */
+long _sys_sigaltstack(const stack_t __user *, stack_t __user *);
+long _sys_rt_sigreturn(void);
+long _sys_clone(unsigned long clone_flags, unsigned long newsp,
+ void __user *parent_tid, void __user *child_tid);
+long _sys_execve(const char __user *filename,
+ const char __user *const __user *argv,
+ const char __user *const __user *envp);
+
+#include <asm-generic/syscalls.h>
+
#endif /* _ASM_TILE_SYSCALLS_H */
diff --git a/arch/tile/include/asm/system.h b/arch/tile/include/asm/system.h
index f749be327ce0..5388850deeb2 100644
--- a/arch/tile/include/asm/system.h
+++ b/arch/tile/include/asm/system.h
@@ -89,6 +89,10 @@
#define get_cycles_low() __insn_mfspr(SPR_CYCLE) /* just get all 64 bits */
#endif
+#if !CHIP_HAS_MF_WAITS_FOR_VICTIMS()
+int __mb_incoherent(void); /* Helper routine for mb_incoherent(). */
+#endif
+
/* Fence to guarantee visibility of stores to incoherent memory. */
static inline void
mb_incoherent(void)
@@ -97,7 +101,6 @@ mb_incoherent(void)
#if !CHIP_HAS_MF_WAITS_FOR_VICTIMS()
{
- int __mb_incoherent(void);
#if CHIP_HAS_TILE_WRITE_PENDING()
const unsigned long WRITE_TIMEOUT_CYCLES = 400;
unsigned long start = get_cycles_low();
@@ -161,7 +164,7 @@ extern struct task_struct *_switch_to(struct task_struct *prev,
/* Helper function for _switch_to(). */
extern struct task_struct *__switch_to(struct task_struct *prev,
struct task_struct *next,
- unsigned long new_system_save_1_0);
+ unsigned long new_system_save_k_0);
/* Address that switched-away from tasks are at. */
extern unsigned long get_switch_to_pc(void);
@@ -214,13 +217,6 @@ int hardwall_deactivate(struct task_struct *task);
} while (0)
#endif
-/* Invoke the simulator "syscall" mechanism (see arch/tile/kernel/entry.S). */
-extern int _sim_syscall(int syscall_num, ...);
-#define sim_syscall(syscall_num, ...) \
- _sim_syscall(SIM_CONTROL_SYSCALL + \
- ((syscall_num) << _SIM_CONTROL_OPERATOR_BITS), \
- ## __VA_ARGS__)
-
/*
* Kernel threads can check to see if they need to migrate their
* stack whenever they return from a context switch; for user
diff --git a/arch/tile/include/asm/traps.h b/arch/tile/include/asm/traps.h
index 432a9c15c8a2..d06e35f57201 100644
--- a/arch/tile/include/asm/traps.h
+++ b/arch/tile/include/asm/traps.h
@@ -59,4 +59,8 @@ void do_hardwall_trap(struct pt_regs *, int fault_num);
void do_breakpoint(struct pt_regs *, int fault_num);
+#ifdef __tilegx__
+void gx_singlestep_handle(struct pt_regs *, int fault_num);
+#endif
+
#endif /* _ASM_TILE_SYSCALLS_H */
diff --git a/arch/tile/include/hv/hypervisor.h b/arch/tile/include/hv/hypervisor.h
index 9bd303a141b2..f672544cd4f9 100644
--- a/arch/tile/include/hv/hypervisor.h
+++ b/arch/tile/include/hv/hypervisor.h
@@ -1003,37 +1003,37 @@ int hv_console_write(HV_VirtAddr bytes, int len);
* when these occur in a client's interrupt critical section, they must
* be delivered through the downcall mechanism.
*
- * A downcall is initially delivered to the client as an INTCTRL_1
- * interrupt. Upon entry to the INTCTRL_1 vector, the client must
- * immediately invoke the hv_downcall_dispatch service. This service
- * will not return; instead it will cause one of the client's actual
- * downcall-handling interrupt vectors to be entered. The EX_CONTEXT
- * registers in the client will be set so that when the client irets,
- * it will return to the code which was interrupted by the INTCTRL_1
- * interrupt.
- *
- * Under some circumstances, the firing of INTCTRL_1 can race with
+ * A downcall is initially delivered to the client as an INTCTRL_CL
+ * interrupt, where CL is the client's PL. Upon entry to the INTCTRL_CL
+ * vector, the client must immediately invoke the hv_downcall_dispatch
+ * service. This service will not return; instead it will cause one of
+ * the client's actual downcall-handling interrupt vectors to be entered.
+ * The EX_CONTEXT registers in the client will be set so that when the
+ * client irets, it will return to the code which was interrupted by the
+ * INTCTRL_CL interrupt.
+ *
+ * Under some circumstances, the firing of INTCTRL_CL can race with
* the lowering of a device interrupt. In such a case, the
* hv_downcall_dispatch service may issue an iret instruction instead
* of entering one of the client's actual downcall-handling interrupt
* vectors. This will return execution to the location that was
- * interrupted by INTCTRL_1.
+ * interrupted by INTCTRL_CL.
*
* Any saving of registers should be done by the actual handling
- * vectors; no registers should be changed by the INTCTRL_1 handler.
+ * vectors; no registers should be changed by the INTCTRL_CL handler.
* In particular, the client should not use a jal instruction to invoke
* the hv_downcall_dispatch service, as that would overwrite the client's
* lr register. Note that the hv_downcall_dispatch service may overwrite
* one or more of the client's system save registers.
*
- * The client must not modify the INTCTRL_1_STATUS SPR. The hypervisor
+ * The client must not modify the INTCTRL_CL_STATUS SPR. The hypervisor
* will set this register to cause a downcall to happen, and will clear
* it when no further downcalls are pending.
*
- * When a downcall vector is entered, the INTCTRL_1 interrupt will be
+ * When a downcall vector is entered, the INTCTRL_CL interrupt will be
* masked. When the client is done processing a downcall, and is ready
* to accept another, it must unmask this interrupt; if more downcalls
- * are pending, this will cause the INTCTRL_1 vector to be reentered.
+ * are pending, this will cause the INTCTRL_CL vector to be reentered.
* Currently the following interrupt vectors can be entered through a
* downcall:
*
diff --git a/arch/tile/kernel/backtrace.c b/arch/tile/kernel/backtrace.c
index d3c41c1ff6bd..55a6a74974b4 100644
--- a/arch/tile/kernel/backtrace.c
+++ b/arch/tile/kernel/backtrace.c
@@ -369,6 +369,10 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
/* Weird; reserved value, ignore it. */
continue;
}
+ if (info_operand & ENTRY_POINT_INFO_OP) {
+ /* This info op is ignored by the backtracer. */
+ continue;
+ }
/* Skip info ops which are not in the
* "one_ago" mode we want right now.
diff --git a/arch/tile/kernel/compat.c b/arch/tile/kernel/compat.c
index b1e06d041555..77739cdd9462 100644
--- a/arch/tile/kernel/compat.c
+++ b/arch/tile/kernel/compat.c
@@ -154,8 +154,14 @@ long tile_compat_sys_msgrcv(int msqid,
#define compat_sys_fstat64 sys_newfstat
#define compat_sys_fstatat64 sys_newfstatat
-/* Pass full 64-bit values through ptrace. */
-#define compat_sys_ptrace tile_compat_sys_ptrace
+/* The native sys_ptrace dynamically handles compat binaries. */
+#define compat_sys_ptrace sys_ptrace
+
+/* Call the trampolines to manage pt_regs where necessary. */
+#define compat_sys_execve _compat_sys_execve
+#define compat_sys_sigaltstack _compat_sys_sigaltstack
+#define compat_sys_rt_sigreturn _compat_sys_rt_sigreturn
+#define sys_clone _sys_clone
/*
* Note that we can't include <linux/unistd.h> here since the header
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
index 9c710db43f13..fb64b99959d4 100644
--- a/arch/tile/kernel/compat_signal.c
+++ b/arch/tile/kernel/compat_signal.c
@@ -256,9 +256,9 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
return err;
}
-long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
- struct compat_sigaltstack __user *uoss_ptr,
- struct pt_regs *regs)
+long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
+ struct compat_sigaltstack __user *uoss_ptr,
+ struct pt_regs *regs)
{
stack_t uss, uoss;
int ret;
@@ -291,7 +291,7 @@ long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
return ret;
}
-long _compat_sys_rt_sigreturn(struct pt_regs *regs)
+long compat_sys_rt_sigreturn(struct pt_regs *regs)
{
struct compat_rt_sigframe __user *frame =
(struct compat_rt_sigframe __user *) compat_ptr(regs->sp);
@@ -312,7 +312,7 @@ long _compat_sys_rt_sigreturn(struct pt_regs *regs)
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
goto badframe;
- if (_compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
+ if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
goto badframe;
return r0;
diff --git a/arch/tile/kernel/entry.S b/arch/tile/kernel/entry.S
index 3d01383b1b0e..fd8dc42abdcb 100644
--- a/arch/tile/kernel/entry.S
+++ b/arch/tile/kernel/entry.S
@@ -15,7 +15,9 @@
#include <linux/linkage.h>
#include <linux/unistd.h>
#include <asm/irqflags.h>
+#include <asm/processor.h>
#include <arch/abi.h>
+#include <arch/spr_def.h>
#ifdef __tilegx__
#define bnzt bnezt
@@ -25,28 +27,6 @@ STD_ENTRY(current_text_addr)
{ move r0, lr; jrp lr }
STD_ENDPROC(current_text_addr)
-STD_ENTRY(_sim_syscall)
- /*
- * Wait for r0-r9 to be ready (and lr on the off chance we
- * want the syscall to locate its caller), then make a magic
- * simulator syscall.
- *
- * We carefully stall until the registers are readable in case they
- * are the target of a slow load, etc. so that tile-sim will
- * definitely be able to read all of them inside the magic syscall.
- *
- * Technically this is wrong for r3-r9 and lr, since an interrupt
- * could come in and restore the registers with a slow load right
- * before executing the mtspr. We may need to modify tile-sim to
- * explicitly stall for this case, but we do not yet have
- * a way to implement such a stall.
- */
- { and zero, lr, r9 ; and zero, r8, r7 }
- { and zero, r6, r5 ; and zero, r4, r3 }
- { and zero, r2, r1 ; mtspr SIM_CONTROL, r0 }
- { jrp lr }
- STD_ENDPROC(_sim_syscall)
-
/*
* Implement execve(). The i386 code has a note that forking from kernel
* space results in no copy on write until the execve, so we should be
@@ -102,7 +82,7 @@ STD_ENTRY(KBacktraceIterator_init_current)
STD_ENTRY(cpu_idle_on_new_stack)
{
move sp, r1
- mtspr SYSTEM_SAVE_1_0, r2
+ mtspr SPR_SYSTEM_SAVE_K_0, r2
}
jal free_thread_info
j cpu_idle
@@ -124,15 +104,15 @@ STD_ENTRY(smp_nap)
STD_ENTRY(_cpu_idle)
{
lnk r0
- movei r1, 1
+ movei r1, KERNEL_PL
}
{
addli r0, r0, _cpu_idle_nap - .
mtspr INTERRUPT_CRITICAL_SECTION, r1
}
- IRQ_ENABLE(r2, r3) /* unmask, but still with ICS set */
- mtspr EX_CONTEXT_1_1, r1 /* PL1, ICS clear */
- mtspr EX_CONTEXT_1_0, r0
+ IRQ_ENABLE(r2, r3) /* unmask, but still with ICS set */
+ mtspr SPR_EX_CONTEXT_K_1, r1 /* Kernel PL, ICS clear */
+ mtspr SPR_EX_CONTEXT_K_0, r0
iret
.global _cpu_idle_nap
_cpu_idle_nap:
diff --git a/arch/tile/kernel/head_32.S b/arch/tile/kernel/head_32.S
index 2b4f6c091701..90e7c4435693 100644
--- a/arch/tile/kernel/head_32.S
+++ b/arch/tile/kernel/head_32.S
@@ -23,6 +23,7 @@
#include <asm/asm-offsets.h>
#include <hv/hypervisor.h>
#include <arch/chip.h>
+#include <arch/spr_def.h>
/*
* This module contains the entry code for kernel images. It performs the
@@ -76,7 +77,7 @@ ENTRY(_start)
}
1:
- /* Get our processor number and save it away in SAVE_1_0. */
+ /* Get our processor number and save it away in SAVE_K_0. */
jal hv_inquire_topology
mulll_uu r4, r1, r2 /* r1 == y, r2 == width */
add r4, r4, r0 /* r0 == x, so r4 == cpu == y*width + x */
@@ -124,7 +125,7 @@ ENTRY(_start)
lw r0, r0
lw sp, r1
or r4, sp, r4
- mtspr SYSTEM_SAVE_1_0, r4 /* save ksp0 + cpu */
+ mtspr SPR_SYSTEM_SAVE_K_0, r4 /* save ksp0 + cpu */
addi sp, sp, -STACK_TOP_DELTA
{
move lr, zero /* stop backtraces in the called function */
diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S
index 8f58bdff20d7..f5821626247f 100644
--- a/arch/tile/kernel/intvec_32.S
+++ b/arch/tile/kernel/intvec_32.S
@@ -32,8 +32,8 @@
# error "No support for kernel preemption currently"
#endif
-#if INT_INTCTRL_1 < 32 || INT_INTCTRL_1 >= 48
-# error INT_INTCTRL_1 coded to set high interrupt mask
+#if INT_INTCTRL_K < 32 || INT_INTCTRL_K >= 48
+# error INT_INTCTRL_K coded to set high interrupt mask
#endif
#define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg)
@@ -132,8 +132,8 @@ intvec_\vecname:
/* Temporarily save a register so we have somewhere to work. */
- mtspr SYSTEM_SAVE_1_1, r0
- mfspr r0, EX_CONTEXT_1_1
+ mtspr SPR_SYSTEM_SAVE_K_1, r0
+ mfspr r0, SPR_EX_CONTEXT_K_1
/* The cmpxchg code clears sp to force us to reset it here on fault. */
{
@@ -167,18 +167,18 @@ intvec_\vecname:
* The page_fault handler may be downcalled directly by the
* hypervisor even when Linux is running and has ICS set.
*
- * In this case the contents of EX_CONTEXT_1_1 reflect the
+ * In this case the contents of EX_CONTEXT_K_1 reflect the
* previous fault and can't be relied on to choose whether or
* not to reinitialize the stack pointer. So we add a test
- * to see whether SYSTEM_SAVE_1_2 has the high bit set,
+ * to see whether SYSTEM_SAVE_K_2 has the high bit set,
* and if so we don't reinitialize sp, since we must be coming
* from Linux. (In fact the precise case is !(val & ~1),
* but any Linux PC has to have the high bit set.)
*
- * Note that the hypervisor *always* sets SYSTEM_SAVE_1_2 for
+ * Note that the hypervisor *always* sets SYSTEM_SAVE_K_2 for
* any path that turns into a downcall to one of our TLB handlers.
*/
- mfspr r0, SYSTEM_SAVE_1_2
+ mfspr r0, SPR_SYSTEM_SAVE_K_2
{
blz r0, 0f /* high bit in S_S_1_2 is for a PC to use */
move r0, sp
@@ -187,12 +187,12 @@ intvec_\vecname:
2:
/*
- * SYSTEM_SAVE_1_0 holds the cpu number in the low bits, and
+ * SYSTEM_SAVE_K_0 holds the cpu number in the low bits, and
* the current stack top in the higher bits. So we recover
* our stack top by just masking off the low bits, then
* point sp at the top aligned address on the actual stack page.
*/
- mfspr r0, SYSTEM_SAVE_1_0
+ mfspr r0, SPR_SYSTEM_SAVE_K_0
mm r0, r0, zero, LOG2_THREAD_SIZE, 31
0:
@@ -254,7 +254,7 @@ intvec_\vecname:
sw sp, r3
addli sp, sp, PTREGS_OFFSET_PC - PTREGS_OFFSET_REG(3)
}
- mfspr r0, EX_CONTEXT_1_0
+ mfspr r0, SPR_EX_CONTEXT_K_0
.ifc \processing,handle_syscall
/*
* Bump the saved PC by one bundle so that when we return, we won't
@@ -267,7 +267,7 @@ intvec_\vecname:
sw sp, r0
addli sp, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC
}
- mfspr r0, EX_CONTEXT_1_1
+ mfspr r0, SPR_EX_CONTEXT_K_1
{
sw sp, r0
addi sp, sp, PTREGS_OFFSET_FAULTNUM - PTREGS_OFFSET_EX1
@@ -289,7 +289,7 @@ intvec_\vecname:
.endif
addli sp, sp, PTREGS_OFFSET_REG(0) - PTREGS_OFFSET_FAULTNUM
}
- mfspr r0, SYSTEM_SAVE_1_1 /* Original r0 */
+ mfspr r0, SPR_SYSTEM_SAVE_K_1 /* Original r0 */
{
sw sp, r0
addi sp, sp, -PTREGS_OFFSET_REG(0) - 4
@@ -309,12 +309,12 @@ intvec_\vecname:
* See discussion below at "finish_interrupt_save".
*/
.ifc \c_routine, do_page_fault
- mfspr r2, SYSTEM_SAVE_1_3 /* address of page fault */
- mfspr r3, SYSTEM_SAVE_1_2 /* info about page fault */
+ mfspr r2, SPR_SYSTEM_SAVE_K_3 /* address of page fault */
+ mfspr r3, SPR_SYSTEM_SAVE_K_2 /* info about page fault */
.else
.ifc \vecnum, INT_DOUBLE_FAULT
{
- mfspr r2, SYSTEM_SAVE_1_2 /* double fault info from HV */
+ mfspr r2, SPR_SYSTEM_SAVE_K_2 /* double fault info from HV */
movei r3, 0
}
.else
@@ -467,7 +467,7 @@ intvec_\vecname:
/* Load tp with our per-cpu offset. */
#ifdef CONFIG_SMP
{
- mfspr r20, SYSTEM_SAVE_1_0
+ mfspr r20, SPR_SYSTEM_SAVE_K_0
moveli r21, lo16(__per_cpu_offset)
}
{
@@ -487,7 +487,7 @@ intvec_\vecname:
* We load flags in r32 here so we can jump to .Lrestore_regs
* directly after do_page_fault_ics() if necessary.
*/
- mfspr r32, EX_CONTEXT_1_1
+ mfspr r32, SPR_EX_CONTEXT_K_1
{
andi r32, r32, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */
PTREGS_PTR(r21, PTREGS_OFFSET_FLAGS)
@@ -957,11 +957,11 @@ STD_ENTRY(interrupt_return)
pop_reg_zero r21, r3, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC
pop_reg_zero lr, r4, sp, PTREGS_OFFSET_REG(52) - PTREGS_OFFSET_EX1
{
- mtspr EX_CONTEXT_1_0, r21
+ mtspr SPR_EX_CONTEXT_K_0, r21
move r5, zero
}
{
- mtspr EX_CONTEXT_1_1, lr
+ mtspr SPR_EX_CONTEXT_K_1, lr
andi lr, lr, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */
}
@@ -1020,7 +1020,7 @@ STD_ENTRY(interrupt_return)
/* Set r1 to errno if we are returning an error, otherwise zero. */
{
- moveli r29, 1024
+ moveli r29, 4096
sub r1, zero, r0
}
slt_u r29, r1, r29
@@ -1199,7 +1199,7 @@ STD_ENTRY(interrupt_return)
STD_ENDPROC(interrupt_return)
/*
- * This interrupt variant clears the INT_INTCTRL_1 interrupt mask bit
+ * This interrupt variant clears the INT_INTCTRL_K interrupt mask bit
* before returning, so we can properly get more downcalls.
*/
.pushsection .text.handle_interrupt_downcall,"ax"
@@ -1208,11 +1208,11 @@ handle_interrupt_downcall:
check_single_stepping normal, .Ldispatch_downcall
.Ldispatch_downcall:
- /* Clear INTCTRL_1 from the set of interrupts we ever enable. */
+ /* Clear INTCTRL_K from the set of interrupts we ever enable. */
GET_INTERRUPTS_ENABLED_MASK_PTR(r30)
{
addi r30, r30, 4
- movei r31, INT_MASK(INT_INTCTRL_1)
+ movei r31, INT_MASK(INT_INTCTRL_K)
}
{
lw r20, r30
@@ -1227,7 +1227,7 @@ handle_interrupt_downcall:
}
FEEDBACK_REENTER(handle_interrupt_downcall)
- /* Allow INTCTRL_1 to be enabled next time we enable interrupts. */
+ /* Allow INTCTRL_K to be enabled next time we enable interrupts. */
lw r20, r30
or r20, r20, r31
sw r30, r20
@@ -1472,7 +1472,12 @@ handle_ill:
lw r26, r24
sw r28, r26
- /* Clear TIF_SINGLESTEP */
+ /*
+ * Clear TIF_SINGLESTEP to prevent recursion if we execute an ill.
+ * The normal non-arch flow redundantly clears TIF_SINGLESTEP, but we
+ * need to clear it here and can't really impose on all other arches.
+ * So what's another write between friends?
+ */
GET_THREAD_INFO(r0)
addi r1, r0, THREAD_INFO_FLAGS_OFFSET
@@ -1509,7 +1514,7 @@ handle_ill:
/* Various stub interrupt handlers and syscall handlers */
STD_ENTRY_LOCAL(_kernel_double_fault)
- mfspr r1, EX_CONTEXT_1_0
+ mfspr r1, SPR_EX_CONTEXT_K_0
move r2, lr
move r3, sp
move r4, r52
@@ -1518,34 +1523,29 @@ STD_ENTRY_LOCAL(_kernel_double_fault)
STD_ENDPROC(_kernel_double_fault)
STD_ENTRY_LOCAL(bad_intr)
- mfspr r2, EX_CONTEXT_1_0
+ mfspr r2, SPR_EX_CONTEXT_K_0
panic "Unhandled interrupt %#x: PC %#lx"
STD_ENDPROC(bad_intr)
/* Put address of pt_regs in reg and jump. */
#define PTREGS_SYSCALL(x, reg) \
- STD_ENTRY(x); \
+ STD_ENTRY(_##x); \
{ \
PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \
- j _##x \
+ j x \
}; \
- STD_ENDPROC(x)
+ STD_ENDPROC(_##x)
PTREGS_SYSCALL(sys_execve, r3)
PTREGS_SYSCALL(sys_sigaltstack, r2)
PTREGS_SYSCALL(sys_rt_sigreturn, r0)
+PTREGS_SYSCALL(sys_cmpxchg_badaddr, r1)
-/* Save additional callee-saves to pt_regs, put address in reg and jump. */
-#define PTREGS_SYSCALL_ALL_REGS(x, reg) \
- STD_ENTRY(x); \
- push_extra_callee_saves reg; \
- j _##x; \
- STD_ENDPROC(x)
-
-PTREGS_SYSCALL_ALL_REGS(sys_fork, r0)
-PTREGS_SYSCALL_ALL_REGS(sys_vfork, r0)
-PTREGS_SYSCALL_ALL_REGS(sys_clone, r4)
-PTREGS_SYSCALL_ALL_REGS(sys_cmpxchg_badaddr, r1)
+/* Save additional callee-saves to pt_regs, put address in r4 and jump. */
+STD_ENTRY(_sys_clone)
+ push_extra_callee_saves r4
+ j sys_clone
+ STD_ENDPROC(_sys_clone)
/*
* This entrypoint is taken for the cmpxchg and atomic_update fast
@@ -1558,12 +1558,14 @@ PTREGS_SYSCALL_ALL_REGS(sys_cmpxchg_badaddr, r1)
* to be available to it on entry. It does not modify any callee-save
* registers (including "lr"). It does not check what PL it is being
* called at, so you'd better not call it other than at PL0.
+ * The <atomic.h> wrapper assumes it only clobbers r20-r29, so if
+ * it ever is necessary to use more registers, be aware.
*
* It does not use the stack, but since it might be re-interrupted by
* a page fault which would assume the stack was valid, it does
* save/restore the stack pointer and zero it out to make sure it gets reset.
* Since we always keep interrupts disabled, the hypervisor won't
- * clobber our EX_CONTEXT_1_x registers, so we don't save/restore them
+ * clobber our EX_CONTEXT_K_x registers, so we don't save/restore them
* (other than to advance the PC on return).
*
* We have to manually validate the user vs kernel address range
@@ -1769,7 +1771,7 @@ ENTRY(sys_cmpxchg)
/* Do slow mtspr here so the following "mf" waits less. */
{
move sp, r27
- mtspr EX_CONTEXT_1_0, r28
+ mtspr SPR_EX_CONTEXT_K_0, r28
}
mf
@@ -1788,7 +1790,7 @@ ENTRY(sys_cmpxchg)
}
{
move sp, r27
- mtspr EX_CONTEXT_1_0, r28
+ mtspr SPR_EX_CONTEXT_K_0, r28
}
iret
@@ -1816,7 +1818,7 @@ ENTRY(sys_cmpxchg)
#endif
/* Issue the slow SPR here while the tns result is in flight. */
- mfspr r28, EX_CONTEXT_1_0
+ mfspr r28, SPR_EX_CONTEXT_K_0
{
addi r28, r28, 8 /* return to the instruction after the swint1 */
@@ -1904,7 +1906,7 @@ ENTRY(sys_cmpxchg)
.Lcmpxchg64_mismatch:
{
move sp, r27
- mtspr EX_CONTEXT_1_0, r28
+ mtspr SPR_EX_CONTEXT_K_0, r28
}
mf
{
@@ -1985,8 +1987,13 @@ int_unalign:
int_hand INT_PERF_COUNT, PERF_COUNT, \
op_handle_perf_interrupt, handle_nmi
int_hand INT_INTCTRL_3, INTCTRL_3, bad_intr
+#if CONFIG_KERNEL_PL == 2
+ dc_dispatch INT_INTCTRL_2, INTCTRL_2
+ int_hand INT_INTCTRL_1, INTCTRL_1, bad_intr
+#else
int_hand INT_INTCTRL_2, INTCTRL_2, bad_intr
dc_dispatch INT_INTCTRL_1, INTCTRL_1
+#endif
int_hand INT_INTCTRL_0, INTCTRL_0, bad_intr
int_hand INT_MESSAGE_RCV_DWNCL, MESSAGE_RCV_DWNCL, \
hv_message_intr, handle_interrupt_downcall
diff --git a/arch/tile/kernel/irq.c b/arch/tile/kernel/irq.c
index 9a27d563fc30..e63917687e99 100644
--- a/arch/tile/kernel/irq.c
+++ b/arch/tile/kernel/irq.c
@@ -61,9 +61,9 @@ static DEFINE_SPINLOCK(available_irqs_lock);
#if CHIP_HAS_IPI()
/* Use SPRs to manipulate device interrupts. */
-#define mask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_SET_1, irq_mask)
-#define unmask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_RESET_1, irq_mask)
-#define clear_irqs(irq_mask) __insn_mtspr(SPR_IPI_EVENT_RESET_1, irq_mask)
+#define mask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_SET_K, irq_mask)
+#define unmask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_RESET_K, irq_mask)
+#define clear_irqs(irq_mask) __insn_mtspr(SPR_IPI_EVENT_RESET_K, irq_mask)
#else
/* Use HV to manipulate device interrupts. */
#define mask_irqs(irq_mask) hv_disable_intr(irq_mask)
@@ -89,16 +89,16 @@ void tile_dev_intr(struct pt_regs *regs, int intnum)
* masked by a previous interrupt. Then, mask out the ones
* we're going to handle.
*/
- unsigned long masked = __insn_mfspr(SPR_IPI_MASK_1);
- original_irqs = __insn_mfspr(SPR_IPI_EVENT_1) & ~masked;
- __insn_mtspr(SPR_IPI_MASK_SET_1, original_irqs);
+ unsigned long masked = __insn_mfspr(SPR_IPI_MASK_K);
+ original_irqs = __insn_mfspr(SPR_IPI_EVENT_K) & ~masked;
+ __insn_mtspr(SPR_IPI_MASK_SET_K, original_irqs);
#else
/*
* Hypervisor performs the equivalent of the Gx code above and
* then puts the pending interrupt mask into a system save reg
* for us to find.
*/
- original_irqs = __insn_mfspr(SPR_SYSTEM_SAVE_1_3);
+ original_irqs = __insn_mfspr(SPR_SYSTEM_SAVE_K_3);
#endif
remaining_irqs = original_irqs;
@@ -225,7 +225,7 @@ void __cpuinit setup_irq_regs(void)
/* Enable interrupt delivery. */
unmask_irqs(~0UL);
#if CHIP_HAS_IPI()
- raw_local_irq_unmask(INT_IPI_1);
+ raw_local_irq_unmask(INT_IPI_K);
#endif
}
diff --git a/arch/tile/kernel/messaging.c b/arch/tile/kernel/messaging.c
index 6d23ed271d10..997e3933f726 100644
--- a/arch/tile/kernel/messaging.c
+++ b/arch/tile/kernel/messaging.c
@@ -34,7 +34,7 @@ void __cpuinit init_messaging(void)
panic("hv_register_message_state: error %d", rc);
/* Make sure downcall interrupts will be enabled. */
- raw_local_irq_unmask(INT_INTCTRL_1);
+ raw_local_irq_unmask(INT_INTCTRL_K);
}
void hv_message_intr(struct pt_regs *regs, int intnum)
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index 84c29111756c..8430f45daea6 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -214,9 +214,10 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
/*
* Copy the callee-saved registers from the passed pt_regs struct
* into the context-switch callee-saved registers area.
- * We have to restore the callee-saved registers since we may
- * be cloning a userspace task with userspace register state,
- * and we won't be unwinding the same kernel frames to restore them.
+ * This way when we start the interrupt-return sequence, the
+ * callee-save registers will be correctly in registers, which
+ * is how we assume the compiler leaves them as we start doing
+ * the normal return-from-interrupt path after calling C code.
* Zero out the C ABI save area to mark the top of the stack.
*/
ksp = (unsigned long) childregs;
@@ -304,15 +305,25 @@ int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
/* Allow user processes to access the DMA SPRs */
void grant_dma_mpls(void)
{
+#if CONFIG_KERNEL_PL == 2
+ __insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1);
+ __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1);
+#else
__insn_mtspr(SPR_MPL_DMA_CPL_SET_0, 1);
__insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_0, 1);
+#endif
}
/* Forbid user processes from accessing the DMA SPRs */
void restrict_dma_mpls(void)
{
+#if CONFIG_KERNEL_PL == 2
+ __insn_mtspr(SPR_MPL_DMA_CPL_SET_2, 1);
+ __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_2, 1);
+#else
__insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1);
__insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1);
+#endif
}
/* Pause the DMA engine, then save off its state registers. */
@@ -523,19 +534,14 @@ struct task_struct *__sched _switch_to(struct task_struct *prev,
* Switch kernel SP, PC, and callee-saved registers.
* In the context of the new task, return the old task pointer
* (i.e. the task that actually called __switch_to).
- * Pass the value to use for SYSTEM_SAVE_1_0 when we reset our sp.
+ * Pass the value to use for SYSTEM_SAVE_K_0 when we reset our sp.
*/
return __switch_to(prev, next, next_current_ksp0(next));
}
-long _sys_fork(struct pt_regs *regs)
-{
- return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
-}
-
-long _sys_clone(unsigned long clone_flags, unsigned long newsp,
- void __user *parent_tidptr, void __user *child_tidptr,
- struct pt_regs *regs)
+SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
+ void __user *, parent_tidptr, void __user *, child_tidptr,
+ struct pt_regs *, regs)
{
if (!newsp)
newsp = regs->sp;
@@ -543,18 +549,13 @@ long _sys_clone(unsigned long clone_flags, unsigned long newsp,
parent_tidptr, child_tidptr);
}
-long _sys_vfork(struct pt_regs *regs)
-{
- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp,
- regs, 0, NULL, NULL);
-}
-
/*
* sys_execve() executes a new program.
*/
-long _sys_execve(const char __user *path,
- const char __user *const __user *argv,
- const char __user *const __user *envp, struct pt_regs *regs)
+SYSCALL_DEFINE4(execve, const char __user *, path,
+ const char __user *const __user *, argv,
+ const char __user *const __user *, envp,
+ struct pt_regs *, regs)
{
long error;
char *filename;
@@ -570,9 +571,10 @@ out:
}
#ifdef CONFIG_COMPAT
-long _compat_sys_execve(const char __user *path,
- const compat_uptr_t __user *argv,
- const compat_uptr_t __user *envp, struct pt_regs *regs)
+long compat_sys_execve(const char __user *path,
+ const compat_uptr_t __user *argv,
+ const compat_uptr_t __user *envp,
+ struct pt_regs *regs)
{
long error;
char *filename;
diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c
index 7161bd03d2fd..9cd29884c09f 100644
--- a/arch/tile/kernel/ptrace.c
+++ b/arch/tile/kernel/ptrace.c
@@ -32,25 +32,6 @@ void user_disable_single_step(struct task_struct *child)
}
/*
- * This routine will put a word on the process's privileged stack.
- */
-static void putreg(struct task_struct *task,
- unsigned long addr, unsigned long value)
-{
- unsigned int regno = addr / sizeof(unsigned long);
- struct pt_regs *childregs = task_pt_regs(task);
- childregs->regs[regno] = value;
- childregs->flags |= PT_FLAGS_RESTORE_REGS;
-}
-
-static unsigned long getreg(struct task_struct *task, unsigned long addr)
-{
- unsigned int regno = addr / sizeof(unsigned long);
- struct pt_regs *childregs = task_pt_regs(task);
- return childregs->regs[regno];
-}
-
-/*
* Called by kernel/ptrace.c when detaching..
*/
void ptrace_disable(struct task_struct *child)
@@ -64,61 +45,77 @@ void ptrace_disable(struct task_struct *child)
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
- unsigned long __user *datap;
+ unsigned long __user *datap = (long __user __force *)data;
unsigned long tmp;
int i;
long ret = -EIO;
-
-#ifdef CONFIG_COMPAT
- if (task_thread_info(current)->status & TS_COMPAT)
- data = (u32)data;
- if (task_thread_info(child)->status & TS_COMPAT)
- addr = (u32)addr;
-#endif
- datap = (unsigned long __user __force *)data;
+ unsigned long *childregs;
+ char *childreg;
switch (request) {
case PTRACE_PEEKUSR: /* Read register from pt_regs. */
- if (addr & (sizeof(data)-1))
- break;
- if (addr < 0 || addr >= PTREGS_SIZE)
+ if (addr >= PTREGS_SIZE)
break;
- tmp = getreg(child, addr); /* Read register */
- ret = put_user(tmp, datap);
+ childreg = (char *)task_pt_regs(child) + addr;
+#ifdef CONFIG_COMPAT
+ if (is_compat_task()) {
+ if (addr & (sizeof(compat_long_t)-1))
+ break;
+ ret = put_user(*(compat_long_t *)childreg,
+ (compat_long_t __user *)datap);
+ } else
+#endif
+ {
+ if (addr & (sizeof(long)-1))
+ break;
+ ret = put_user(*(long *)childreg, datap);
+ }
break;
case PTRACE_POKEUSR: /* Write register in pt_regs. */
- if (addr & (sizeof(data)-1))
- break;
- if (addr < 0 || addr >= PTREGS_SIZE)
+ if (addr >= PTREGS_SIZE)
break;
- putreg(child, addr, data); /* Write register */
+ childreg = (char *)task_pt_regs(child) + addr;
+#ifdef CONFIG_COMPAT
+ if (is_compat_task()) {
+ if (addr & (sizeof(compat_long_t)-1))
+ break;
+ *(compat_long_t *)childreg = data;
+ } else
+#endif
+ {
+ if (addr & (sizeof(long)-1))
+ break;
+ *(long *)childreg = data;
+ }
ret = 0;
break;
case PTRACE_GETREGS: /* Get all registers from the child. */
if (!access_ok(VERIFY_WRITE, datap, PTREGS_SIZE))
break;
- for (i = 0; i < PTREGS_SIZE; i += sizeof(long)) {
- ret = __put_user(getreg(child, i), datap);
+ childregs = (long *)task_pt_regs(child);
+ for (i = 0; i < sizeof(struct pt_regs)/sizeof(unsigned long);
+ ++i) {
+ ret = __put_user(childregs[i], &datap[i]);
if (ret != 0)
break;
- datap++;
}
break;
case PTRACE_SETREGS: /* Set all registers in the child. */
if (!access_ok(VERIFY_READ, datap, PTREGS_SIZE))
break;
- for (i = 0; i < PTREGS_SIZE; i += sizeof(long)) {
- ret = __get_user(tmp, datap);
+ childregs = (long *)task_pt_regs(child);
+ for (i = 0; i < sizeof(struct pt_regs)/sizeof(unsigned long);
+ ++i) {
+ ret = __get_user(childregs[i], &datap[i]);
if (ret != 0)
break;
- putreg(child, i, tmp);
- datap++;
}
break;
diff --git a/arch/tile/kernel/regs_32.S b/arch/tile/kernel/regs_32.S
index e88d6e122783..caa13101c264 100644
--- a/arch/tile/kernel/regs_32.S
+++ b/arch/tile/kernel/regs_32.S
@@ -85,7 +85,7 @@ STD_ENTRY_SECTION(__switch_to, .sched.text)
{
/* Update sp and ksp0 simultaneously to avoid backtracer warnings. */
move sp, r13
- mtspr SYSTEM_SAVE_1_0, r2
+ mtspr SPR_SYSTEM_SAVE_K_0, r2
}
FOR_EACH_CALLEE_SAVED_REG(LOAD_REG)
.L__switch_to_pc:
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
index e7d54c73d5c1..ae51cad12da0 100644
--- a/arch/tile/kernel/setup.c
+++ b/arch/tile/kernel/setup.c
@@ -30,8 +30,6 @@
#include <linux/timex.h>
#include <asm/setup.h>
#include <asm/sections.h>
-#include <asm/sections.h>
-#include <asm/cacheflush.h>
#include <asm/cacheflush.h>
#include <asm/pgalloc.h>
#include <asm/mmu_context.h>
@@ -187,11 +185,11 @@ early_param("vmalloc", parse_vmalloc);
#ifdef CONFIG_HIGHMEM
/*
- * Determine for each controller where its lowmem is mapped and how
- * much of it is mapped there. On controller zero, the first few
- * megabytes are mapped at 0xfd000000 as code, so in principle we
- * could start our data mappings higher up, but for now we don't
- * bother, to avoid additional confusion.
+ * Determine for each controller where its lowmem is mapped and how much of
+ * it is mapped there. On controller zero, the first few megabytes are
+ * already mapped in as code at MEM_SV_INTRPT, so in principle we could
+ * start our data mappings higher up, but for now we don't bother, to avoid
+ * additional confusion.
*
* One question is whether, on systems with more than 768 Mb and
* controllers of different sizes, to map in a proportionate amount of
@@ -311,7 +309,7 @@ static void __init setup_memory(void)
#endif
/* We are using a char to hold the cpu_2_node[] mapping */
- BUG_ON(MAX_NUMNODES > 127);
+ BUILD_BUG_ON(MAX_NUMNODES > 127);
/* Discover the ranges of memory available to us */
for (i = 0; ; ++i) {
@@ -876,6 +874,9 @@ void __cpuinit setup_cpu(int boot)
#if CHIP_HAS_SN_PROC()
raw_local_irq_unmask(INT_SNITLB_MISS);
#endif
+#ifdef __tilegx__
+ raw_local_irq_unmask(INT_SINGLE_STEP_K);
+#endif
/*
* Allow user access to many generic SPRs, like the cycle
@@ -893,11 +894,12 @@ void __cpuinit setup_cpu(int boot)
#endif
/*
- * Set the MPL for interrupt control 0 to user level.
- * This includes access to the SYSTEM_SAVE and EX_CONTEXT SPRs,
- * as well as the PL 0 interrupt mask.
+ * Set the MPL for interrupt control 0 & 1 to the corresponding
+ * values. This includes access to the SYSTEM_SAVE and EX_CONTEXT
+ * SPRs, as well as the interrupt mask.
*/
__insn_mtspr(SPR_MPL_INTCTRL_0_SET_0, 1);
+ __insn_mtspr(SPR_MPL_INTCTRL_1_SET_1, 1);
/* Initialize IRQ support for this cpu. */
setup_irq_regs();
@@ -1033,7 +1035,7 @@ static void __init validate_va(void)
* In addition, make sure we CAN'T use the end of memory, since
* we use the last chunk of each pgd for the pgd_list.
*/
- int i, fc_fd_ok = 0;
+ int i, user_kernel_ok = 0;
unsigned long max_va = 0;
unsigned long list_va =
((PGD_LIST_OFFSET / sizeof(pgd_t)) << PGDIR_SHIFT);
@@ -1044,13 +1046,13 @@ static void __init validate_va(void)
break;
if (range.start <= MEM_USER_INTRPT &&
range.start + range.size >= MEM_HV_INTRPT)
- fc_fd_ok = 1;
+ user_kernel_ok = 1;
if (range.start == 0)
max_va = range.size;
BUG_ON(range.start + range.size > list_va);
}
- if (!fc_fd_ok)
- early_panic("Hypervisor not configured for VAs 0xfc/0xfd\n");
+ if (!user_kernel_ok)
+ early_panic("Hypervisor not configured for user/kernel VAs\n");
if (max_va == 0)
early_panic("Hypervisor not configured for low VAs\n");
if (max_va < KERNEL_HIGH_VADDR)
@@ -1334,6 +1336,10 @@ static void __init pcpu_fc_populate_pte(unsigned long addr)
pte_t *pte;
BUG_ON(pgd_addr_invalid(addr));
+ if (addr < VMALLOC_START || addr >= VMALLOC_END)
+ panic("PCPU addr %#lx outside vmalloc range %#lx..%#lx;"
+ " try increasing CONFIG_VMALLOC_RESERVE\n",
+ addr, VMALLOC_START, VMALLOC_END);
pgd = swapper_pg_dir + pgd_index(addr);
pud = pud_offset(pgd, addr);
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c
index ce183aa1492c..fb28e85ae3ae 100644
--- a/arch/tile/kernel/signal.c
+++ b/arch/tile/kernel/signal.c
@@ -41,8 +41,8 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-long _sys_sigaltstack(const stack_t __user *uss,
- stack_t __user *uoss, struct pt_regs *regs)
+SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss,
+ stack_t __user *, uoss, struct pt_regs *, regs)
{
return do_sigaltstack(uss, uoss, regs->sp);
}
@@ -78,7 +78,7 @@ int restore_sigcontext(struct pt_regs *regs,
}
/* sigreturn() returns long since it restores r0 in the interrupted code. */
-long _sys_rt_sigreturn(struct pt_regs *regs)
+SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
{
struct rt_sigframe __user *frame =
(struct rt_sigframe __user *)(regs->sp);
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c
index 5ec4b9c651f2..1eb3b39e36c7 100644
--- a/arch/tile/kernel/single_step.c
+++ b/arch/tile/kernel/single_step.c
@@ -15,7 +15,7 @@
* Derived from iLib's single-stepping code.
*/
-#ifndef __tilegx__ /* No support for single-step yet. */
+#ifndef __tilegx__ /* Hardware support for single step unavailable. */
/* These functions are only used on the TILE platform */
#include <linux/slab.h>
@@ -660,4 +660,75 @@ void single_step_once(struct pt_regs *regs)
regs->pc += 8;
}
+#else
+#include <linux/smp.h>
+#include <linux/ptrace.h>
+#include <arch/spr_def.h>
+
+static DEFINE_PER_CPU(unsigned long, ss_saved_pc);
+
+
+/*
+ * Called directly on the occasion of an interrupt.
+ *
+ * If the process doesn't have single step set, then we use this as an
+ * opportunity to turn single step off.
+ *
+ * It has been mentioned that we could conditionally turn off single stepping
+ * on each entry into the kernel and rely on single_step_once to turn it
+ * on for the processes that matter (as we already do), but this
+ * implementation is somewhat more efficient in that we muck with registers
+ * once on a bum interrupt rather than on every entry into the kernel.
+ *
+ * If SINGLE_STEP_CONTROL_K has CANCELED set, then an interrupt occurred,
+ * so we have to run through this process again before we can say that an
+ * instruction has executed.
+ *
+ * swint will set CANCELED, but it's a legitimate instruction. Fortunately
+ * it changes the PC. If it hasn't changed, then we know that the interrupt
+ * wasn't generated by swint and we'll need to run this process again before
+ * we can say an instruction has executed.
+ *
+ * If either CANCELED == 0 or the PC's changed, we send out SIGTRAPs and get
+ * on with our lives.
+ */
+
+void gx_singlestep_handle(struct pt_regs *regs, int fault_num)
+{
+ unsigned long *ss_pc = &__get_cpu_var(ss_saved_pc);
+ struct thread_info *info = (void *)current_thread_info();
+ int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP);
+ unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K);
+
+ if (is_single_step == 0) {
+ __insn_mtspr(SPR_SINGLE_STEP_EN_K_K, 0);
+
+ } else if ((*ss_pc != regs->pc) ||
+ (!(control & SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK))) {
+
+ ptrace_notify(SIGTRAP);
+ control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK;
+ control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK;
+ __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control);
+ }
+}
+
+
+/*
+ * Called from need_singlestep. Set up the control registers and the enable
+ * register, then return back.
+ */
+
+void single_step_once(struct pt_regs *regs)
+{
+ unsigned long *ss_pc = &__get_cpu_var(ss_saved_pc);
+ unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K);
+
+ *ss_pc = regs->pc;
+ control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK;
+ control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK;
+ __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control);
+ __insn_mtspr(SPR_SINGLE_STEP_EN_K_K, 1 << USER_PL);
+}
+
#endif /* !__tilegx__ */
diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c
index 1cb5ec79de04..75255d90aff3 100644
--- a/arch/tile/kernel/smp.c
+++ b/arch/tile/kernel/smp.c
@@ -212,7 +212,7 @@ void __init ipi_init(void)
tile.x = cpu_x(cpu);
tile.y = cpu_y(cpu);
- if (hv_get_ipi_pte(tile, 1, &pte) != 0)
+ if (hv_get_ipi_pte(tile, KERNEL_PL, &pte) != 0)
panic("Failed to initialize IPI for cpu %d\n", cpu);
offset = hv_pte_get_pfn(pte) << PAGE_SHIFT;
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c
index ea2e0ce28380..0d54106be3d6 100644
--- a/arch/tile/kernel/stack.c
+++ b/arch/tile/kernel/stack.c
@@ -30,6 +30,10 @@
#include <arch/abi.h>
#include <arch/interrupts.h>
+#define KBT_ONGOING 0 /* Backtrace still ongoing */
+#define KBT_DONE 1 /* Backtrace cleanly completed */
+#define KBT_RUNNING 2 /* Can't run backtrace on a running task */
+#define KBT_LOOP 3 /* Backtrace entered a loop */
/* Is address on the specified kernel stack? */
static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp)
@@ -207,11 +211,11 @@ static int KBacktraceIterator_next_item_inclusive(
for (;;) {
do {
if (!KBacktraceIterator_is_sigreturn(kbt))
- return 1;
+ return KBT_ONGOING;
} while (backtrace_next(&kbt->it));
if (!KBacktraceIterator_restart(kbt))
- return 0;
+ return KBT_DONE;
}
}
@@ -264,7 +268,7 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
kbt->pgtable = NULL;
kbt->verbose = 0; /* override in caller if desired */
kbt->profile = 0; /* override in caller if desired */
- kbt->end = 0;
+ kbt->end = KBT_ONGOING;
kbt->new_context = 0;
if (is_current) {
HV_PhysAddr pgdir_pa = hv_inquire_context().page_table;
@@ -290,7 +294,7 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
if (regs == NULL) {
if (is_current || t->state == TASK_RUNNING) {
/* Can't do this; we need registers */
- kbt->end = 1;
+ kbt->end = KBT_RUNNING;
return;
}
pc = get_switch_to_pc();
@@ -305,26 +309,29 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
}
backtrace_init(&kbt->it, read_memory_func, kbt, pc, lr, sp, r52);
- kbt->end = !KBacktraceIterator_next_item_inclusive(kbt);
+ kbt->end = KBacktraceIterator_next_item_inclusive(kbt);
}
EXPORT_SYMBOL(KBacktraceIterator_init);
int KBacktraceIterator_end(struct KBacktraceIterator *kbt)
{
- return kbt->end;
+ return kbt->end != KBT_ONGOING;
}
EXPORT_SYMBOL(KBacktraceIterator_end);
void KBacktraceIterator_next(struct KBacktraceIterator *kbt)
{
+ VirtualAddress old_pc = kbt->it.pc, old_sp = kbt->it.sp;
kbt->new_context = 0;
- if (!backtrace_next(&kbt->it) &&
- !KBacktraceIterator_restart(kbt)) {
- kbt->end = 1;
- return;
- }
-
- kbt->end = !KBacktraceIterator_next_item_inclusive(kbt);
+ if (!backtrace_next(&kbt->it) && !KBacktraceIterator_restart(kbt)) {
+ kbt->end = KBT_DONE;
+ return;
+ }
+ kbt->end = KBacktraceIterator_next_item_inclusive(kbt);
+ if (old_pc == kbt->it.pc && old_sp == kbt->it.sp) {
+ /* Trapped in a loop; give up. */
+ kbt->end = KBT_LOOP;
+ }
}
EXPORT_SYMBOL(KBacktraceIterator_next);
@@ -387,6 +394,8 @@ void tile_show_stack(struct KBacktraceIterator *kbt, int headers)
break;
}
}
+ if (kbt->end == KBT_LOOP)
+ pr_err("Stack dump stopped; next frame identical to this one\n");
if (headers)
pr_err("Stack dump complete\n");
}
diff --git a/arch/tile/kernel/sys.c b/arch/tile/kernel/sys.c
index f0f87eab8c39..7e764669a022 100644
--- a/arch/tile/kernel/sys.c
+++ b/arch/tile/kernel/sys.c
@@ -110,6 +110,15 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
#define sys_sync_file_range sys_sync_file_range2
#endif
+/* Call the trampolines to manage pt_regs where necessary. */
+#define sys_execve _sys_execve
+#define sys_sigaltstack _sys_sigaltstack
+#define sys_rt_sigreturn _sys_rt_sigreturn
+#define sys_clone _sys_clone
+#ifndef __tilegx__
+#define sys_cmpxchg_badaddr _sys_cmpxchg_badaddr
+#endif
+
/*
* Note that we can't include <linux/unistd.h> here since the header
* guard will defeat us; <asm/unistd.h> checks for __SYSCALL as well.
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c
index 0f362dc2c57f..5474fc2e77e8 100644
--- a/arch/tile/kernel/traps.c
+++ b/arch/tile/kernel/traps.c
@@ -260,7 +260,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
address = regs->pc;
break;
case INT_UNALIGN_DATA:
-#ifndef __tilegx__ /* FIXME: GX: no single-step yet */
+#ifndef __tilegx__ /* Emulated support for single step debugging */
if (unaligned_fixup >= 0) {
struct single_step_state *state =
current_thread_info()->step_state;
@@ -278,7 +278,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
case INT_DOUBLE_FAULT:
/*
* For double fault, "reason" is actually passed as
- * SYSTEM_SAVE_1_2, the hypervisor's double-fault info, so
+ * SYSTEM_SAVE_K_2, the hypervisor's double-fault info, so
* we can provide the original fault number rather than
* the uninteresting "INT_DOUBLE_FAULT" so the user can
* learn what actually struck while PL0 ICS was set.
diff --git a/arch/tile/kvm/Kconfig b/arch/tile/kvm/Kconfig
new file mode 100644
index 000000000000..b88f9c047781
--- /dev/null
+++ b/arch/tile/kvm/Kconfig
@@ -0,0 +1,38 @@
+#
+# KVM configuration
+#
+
+source "virt/kvm/Kconfig"
+
+menuconfig VIRTUALIZATION
+ bool "Virtualization"
+ ---help---
+ Say Y here to get to see options for using your Linux host to run
+ other operating systems inside virtual machines (guests).
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and
+ disabled.
+
+if VIRTUALIZATION
+
+config KVM
+ tristate "Kernel-based Virtual Machine (KVM) support"
+ depends on HAVE_KVM && MODULES && EXPERIMENTAL
+ select PREEMPT_NOTIFIERS
+ select ANON_INODES
+ ---help---
+ Support hosting paravirtualized guest machines.
+
+ This module provides access to the hardware capabilities through
+ a character device node named /dev/kvm.
+
+ To compile this as a module, choose M here: the module
+ will be called kvm.
+
+ If unsure, say N.
+
+source drivers/vhost/Kconfig
+source drivers/virtio/Kconfig
+
+endif # VIRTUALIZATION
diff --git a/arch/tile/lib/Makefile b/arch/tile/lib/Makefile
index 746dc81ed3c4..93122d5b1558 100644
--- a/arch/tile/lib/Makefile
+++ b/arch/tile/lib/Makefile
@@ -3,8 +3,8 @@
#
lib-y = cacheflush.o checksum.o cpumask.o delay.o \
- mb_incoherent.o uaccess.o \
- memcpy_$(BITS).o memchr_$(BITS).o memmove_$(BITS).o memset_$(BITS).o \
+ mb_incoherent.o uaccess.o memmove.o \
+ memcpy_$(BITS).o memchr_$(BITS).o memset_$(BITS).o \
strchr_$(BITS).o strlen_$(BITS).o
ifeq ($(CONFIG_TILEGX),y)
diff --git a/arch/tile/lib/atomic_32.c b/arch/tile/lib/atomic_32.c
index 8040b42a8eea..7a5cc706ab62 100644
--- a/arch/tile/lib/atomic_32.c
+++ b/arch/tile/lib/atomic_32.c
@@ -300,7 +300,7 @@ void __init __init_atomic_per_cpu(void)
#else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
/* Validate power-of-two and "bigger than cpus" assumption */
- BUG_ON(ATOMIC_HASH_SIZE & (ATOMIC_HASH_SIZE-1));
+ BUILD_BUG_ON(ATOMIC_HASH_SIZE & (ATOMIC_HASH_SIZE-1));
BUG_ON(ATOMIC_HASH_SIZE < nr_cpu_ids);
/*
@@ -314,17 +314,17 @@ void __init __init_atomic_per_cpu(void)
BUG_ON((unsigned long)atomic_locks % PAGE_SIZE != 0);
/* The locks must all fit on one page. */
- BUG_ON(ATOMIC_HASH_SIZE * sizeof(int) > PAGE_SIZE);
+ BUILD_BUG_ON(ATOMIC_HASH_SIZE * sizeof(int) > PAGE_SIZE);
/*
* We use the page offset of the atomic value's address as
* an index into atomic_locks, excluding the low 3 bits.
* That should not produce more indices than ATOMIC_HASH_SIZE.
*/
- BUG_ON((PAGE_SIZE >> 3) > ATOMIC_HASH_SIZE);
+ BUILD_BUG_ON((PAGE_SIZE >> 3) > ATOMIC_HASH_SIZE);
#endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
/* The futex code makes this assumption, so we validate it here. */
- BUG_ON(sizeof(atomic_t) != sizeof(int));
+ BUILD_BUG_ON(sizeof(atomic_t) != sizeof(int));
}
diff --git a/arch/tile/lib/exports.c b/arch/tile/lib/exports.c
index ce5dbf56578f..1509c5597653 100644
--- a/arch/tile/lib/exports.c
+++ b/arch/tile/lib/exports.c
@@ -45,6 +45,9 @@ EXPORT_SYMBOL(__copy_from_user_zeroing);
EXPORT_SYMBOL(__copy_in_user_inatomic);
#endif
+/* arch/tile/lib/mb_incoherent.S */
+EXPORT_SYMBOL(__mb_incoherent);
+
/* hypervisor glue */
#include <hv/hypervisor.h>
EXPORT_SYMBOL(hv_dev_open);
diff --git a/arch/tile/lib/memcpy_32.S b/arch/tile/lib/memcpy_32.S
index 30c3b7ebb55d..2a419a6122db 100644
--- a/arch/tile/lib/memcpy_32.S
+++ b/arch/tile/lib/memcpy_32.S
@@ -10,14 +10,16 @@
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for
* more details.
- *
- * This file shares the implementation of the userspace memcpy and
- * the kernel's memcpy, copy_to_user and copy_from_user.
*/
#include <arch/chip.h>
+/*
+ * This file shares the implementation of the userspace memcpy and
+ * the kernel's memcpy, copy_to_user and copy_from_user.
+ */
+
#include <linux/linkage.h>
/* On TILE64, we wrap these functions via arch/tile/lib/memcpy_tile64.c */
@@ -53,9 +55,9 @@
*/
ENTRY(__copy_from_user_inatomic)
.type __copy_from_user_inatomic, @function
- FEEDBACK_ENTER_EXPLICIT(__copy_from_user_inatomic, \
+ FEEDBACK_ENTER_EXPLICIT(__copy_from_user_inatomic, \
.text.memcpy_common, \
- .Lend_memcpy_common - __copy_from_user_inatomic)
+ .Lend_memcpy_common - __copy_from_user_inatomic)
{ movei r29, IS_COPY_FROM_USER; j memcpy_common }
.size __copy_from_user_inatomic, . - __copy_from_user_inatomic
@@ -64,7 +66,7 @@ ENTRY(__copy_from_user_inatomic)
*/
ENTRY(__copy_from_user_zeroing)
.type __copy_from_user_zeroing, @function
- FEEDBACK_REENTER(__copy_from_user_inatomic)
+ FEEDBACK_REENTER(__copy_from_user_inatomic)
{ movei r29, IS_COPY_FROM_USER_ZEROING; j memcpy_common }
.size __copy_from_user_zeroing, . - __copy_from_user_zeroing
@@ -74,13 +76,13 @@ ENTRY(__copy_from_user_zeroing)
*/
ENTRY(__copy_to_user_inatomic)
.type __copy_to_user_inatomic, @function
- FEEDBACK_REENTER(__copy_from_user_inatomic)
+ FEEDBACK_REENTER(__copy_from_user_inatomic)
{ movei r29, IS_COPY_TO_USER; j memcpy_common }
.size __copy_to_user_inatomic, . - __copy_to_user_inatomic
ENTRY(memcpy)
.type memcpy, @function
- FEEDBACK_REENTER(__copy_from_user_inatomic)
+ FEEDBACK_REENTER(__copy_from_user_inatomic)
{ movei r29, IS_MEMCPY }
.size memcpy, . - memcpy
/* Fall through */
@@ -157,35 +159,35 @@ EX: { sw r0, r3; addi r0, r0, 4; addi r2, r2, -4 }
{ addi r3, r1, 60; andi r9, r9, -64 }
#if CHIP_HAS_WH64()
- /* No need to prefetch dst, we'll just do the wh64
- * right before we copy a line.
+ /* No need to prefetch dst, we'll just do the wh64
+ * right before we copy a line.
*/
#endif
EX: { lw r5, r3; addi r3, r3, 64; movei r4, 1 }
- /* Intentionally stall for a few cycles to leave L2 cache alone. */
- { bnzt zero, .; move r27, lr }
+ /* Intentionally stall for a few cycles to leave L2 cache alone. */
+ { bnzt zero, .; move r27, lr }
EX: { lw r6, r3; addi r3, r3, 64 }
- /* Intentionally stall for a few cycles to leave L2 cache alone. */
- { bnzt zero, . }
+ /* Intentionally stall for a few cycles to leave L2 cache alone. */
+ { bnzt zero, . }
EX: { lw r7, r3; addi r3, r3, 64 }
#if !CHIP_HAS_WH64()
- /* Prefetch the dest */
- /* Intentionally stall for a few cycles to leave L2 cache alone. */
- { bnzt zero, . }
- /* Use a real load to cause a TLB miss if necessary. We aren't using
- * r28, so this should be fine.
- */
+ /* Prefetch the dest */
+ /* Intentionally stall for a few cycles to leave L2 cache alone. */
+ { bnzt zero, . }
+ /* Use a real load to cause a TLB miss if necessary. We aren't using
+ * r28, so this should be fine.
+ */
EX: { lw r28, r9; addi r9, r9, 64 }
- /* Intentionally stall for a few cycles to leave L2 cache alone. */
- { bnzt zero, . }
- { prefetch r9; addi r9, r9, 64 }
- /* Intentionally stall for a few cycles to leave L2 cache alone. */
- { bnzt zero, . }
- { prefetch r9; addi r9, r9, 64 }
+ /* Intentionally stall for a few cycles to leave L2 cache alone. */
+ { bnzt zero, . }
+ { prefetch r9; addi r9, r9, 64 }
+ /* Intentionally stall for a few cycles to leave L2 cache alone. */
+ { bnzt zero, . }
+ { prefetch r9; addi r9, r9, 64 }
#endif
- /* Intentionally stall for a few cycles to leave L2 cache alone. */
- { bz zero, .Lbig_loop2 }
+ /* Intentionally stall for a few cycles to leave L2 cache alone. */
+ { bz zero, .Lbig_loop2 }
/* On entry to this loop:
* - r0 points to the start of dst line 0
@@ -197,7 +199,7 @@ EX: { lw r28, r9; addi r9, r9, 64 }
* to some "safe" recently loaded address.
* - r5 contains *(r1 + 60) [i.e. last word of source line 0]
* - r6 contains *(r1 + 64 + 60) [i.e. last word of source line 1]
- * - r9 contains ((r0 + 63) & -64)
+ * - r9 contains ((r0 + 63) & -64)
* [start of next dst cache line.]
*/
@@ -208,137 +210,137 @@ EX: { lw r28, r9; addi r9, r9, 64 }
/* Copy line 0, first stalling until r5 is ready. */
EX: { move r12, r5; lw r16, r1 }
{ bz r4, .Lcopy_8_check; slti_u r8, r2, 8 }
- /* Prefetch several lines ahead. */
+ /* Prefetch several lines ahead. */
EX: { lw r5, r3; addi r3, r3, 64 }
- { jal .Lcopy_line }
+ { jal .Lcopy_line }
/* Copy line 1, first stalling until r6 is ready. */
EX: { move r12, r6; lw r16, r1 }
{ bz r4, .Lcopy_8_check; slti_u r8, r2, 8 }
- /* Prefetch several lines ahead. */
+ /* Prefetch several lines ahead. */
EX: { lw r6, r3; addi r3, r3, 64 }
{ jal .Lcopy_line }
/* Copy line 2, first stalling until r7 is ready. */
EX: { move r12, r7; lw r16, r1 }
{ bz r4, .Lcopy_8_check; slti_u r8, r2, 8 }
- /* Prefetch several lines ahead. */
+ /* Prefetch several lines ahead. */
EX: { lw r7, r3; addi r3, r3, 64 }
- /* Use up a caches-busy cycle by jumping back to the top of the
- * loop. Might as well get it out of the way now.
- */
- { j .Lbig_loop }
+ /* Use up a caches-busy cycle by jumping back to the top of the
+ * loop. Might as well get it out of the way now.
+ */
+ { j .Lbig_loop }
/* On entry:
* - r0 points to the destination line.
* - r1 points to the source line.
- * - r3 is the next prefetch address.
+ * - r3 is the next prefetch address.
* - r9 holds the last address used for wh64.
* - r12 = WORD_15
- * - r16 = WORD_0.
- * - r17 == r1 + 16.
- * - r27 holds saved lr to restore.
+ * - r16 = WORD_0.
+ * - r17 == r1 + 16.
+ * - r27 holds saved lr to restore.
*
* On exit:
* - r0 is incremented by 64.
* - r1 is incremented by 64, unless that would point to a word
- * beyond the end of the source array, in which case it is redirected
- * to point to an arbitrary word already in the cache.
+ * beyond the end of the source array, in which case it is redirected
+ * to point to an arbitrary word already in the cache.
* - r2 is decremented by 64.
- * - r3 is unchanged, unless it points to a word beyond the
- * end of the source array, in which case it is redirected
- * to point to an arbitrary word already in the cache.
- * Redirecting is OK since if we are that close to the end
- * of the array we will not come back to this subroutine
- * and use the contents of the prefetched address.
+ * - r3 is unchanged, unless it points to a word beyond the
+ * end of the source array, in which case it is redirected
+ * to point to an arbitrary word already in the cache.
+ * Redirecting is OK since if we are that close to the end
+ * of the array we will not come back to this subroutine
+ * and use the contents of the prefetched address.
* - r4 is nonzero iff r2 >= 64.
- * - r9 is incremented by 64, unless it points beyond the
- * end of the last full destination cache line, in which
- * case it is redirected to a "safe address" that can be
- * clobbered (sp - 64)
+ * - r9 is incremented by 64, unless it points beyond the
+ * end of the last full destination cache line, in which
+ * case it is redirected to a "safe address" that can be
+ * clobbered (sp - 64)
* - lr contains the value in r27.
*/
/* r26 unused */
.Lcopy_line:
- /* TODO: when r3 goes past the end, we would like to redirect it
- * to prefetch the last partial cache line (if any) just once, for the
- * benefit of the final cleanup loop. But we don't want to
- * prefetch that line more than once, or subsequent prefetches
- * will go into the RTF. But then .Lbig_loop should unconditionally
- * branch to top of loop to execute final prefetch, and its
- * nop should become a conditional branch.
- */
-
- /* We need two non-memory cycles here to cover the resources
- * used by the loads initiated by the caller.
- */
- { add r15, r1, r2 }
+ /* TODO: when r3 goes past the end, we would like to redirect it
+ * to prefetch the last partial cache line (if any) just once, for the
+ * benefit of the final cleanup loop. But we don't want to
+ * prefetch that line more than once, or subsequent prefetches
+ * will go into the RTF. But then .Lbig_loop should unconditionally
+ * branch to top of loop to execute final prefetch, and its
+ * nop should become a conditional branch.
+ */
+
+ /* We need two non-memory cycles here to cover the resources
+ * used by the loads initiated by the caller.
+ */
+ { add r15, r1, r2 }
.Lcopy_line2:
- { slt_u r13, r3, r15; addi r17, r1, 16 }
+ { slt_u r13, r3, r15; addi r17, r1, 16 }
- /* NOTE: this will stall for one cycle as L1 is busy. */
+ /* NOTE: this will stall for one cycle as L1 is busy. */
- /* Fill second L1D line. */
+ /* Fill second L1D line. */
EX: { lw r17, r17; addi r1, r1, 48; mvz r3, r13, r1 } /* r17 = WORD_4 */
#if CHIP_HAS_WH64()
- /* Prepare destination line for writing. */
+ /* Prepare destination line for writing. */
EX: { wh64 r9; addi r9, r9, 64 }
#else
- /* Prefetch dest line */
+ /* Prefetch dest line */
{ prefetch r9; addi r9, r9, 64 }
#endif
- /* Load seven words that are L1D hits to cover wh64 L2 usage. */
+ /* Load seven words that are L1D hits to cover wh64 L2 usage. */
- /* Load the three remaining words from the last L1D line, which
- * we know has already filled the L1D.
- */
+ /* Load the three remaining words from the last L1D line, which
+ * we know has already filled the L1D.
+ */
EX: { lw r4, r1; addi r1, r1, 4; addi r20, r1, 16 } /* r4 = WORD_12 */
EX: { lw r8, r1; addi r1, r1, 4; slt_u r13, r20, r15 }/* r8 = WORD_13 */
EX: { lw r11, r1; addi r1, r1, -52; mvz r20, r13, r1 } /* r11 = WORD_14 */
- /* Load the three remaining words from the first L1D line, first
- * stalling until it has filled by "looking at" r16.
- */
+ /* Load the three remaining words from the first L1D line, first
+ * stalling until it has filled by "looking at" r16.
+ */
EX: { lw r13, r1; addi r1, r1, 4; move zero, r16 } /* r13 = WORD_1 */
EX: { lw r14, r1; addi r1, r1, 4 } /* r14 = WORD_2 */
EX: { lw r15, r1; addi r1, r1, 8; addi r10, r0, 60 } /* r15 = WORD_3 */
- /* Load second word from the second L1D line, first
- * stalling until it has filled by "looking at" r17.
- */
+ /* Load second word from the second L1D line, first
+ * stalling until it has filled by "looking at" r17.
+ */
EX: { lw r19, r1; addi r1, r1, 4; move zero, r17 } /* r19 = WORD_5 */
- /* Store last word to the destination line, potentially dirtying it
- * for the first time, which keeps the L2 busy for two cycles.
- */
+ /* Store last word to the destination line, potentially dirtying it
+ * for the first time, which keeps the L2 busy for two cycles.
+ */
EX: { sw r10, r12 } /* store(WORD_15) */
- /* Use two L1D hits to cover the sw L2 access above. */
+ /* Use two L1D hits to cover the sw L2 access above. */
EX: { lw r10, r1; addi r1, r1, 4 } /* r10 = WORD_6 */
EX: { lw r12, r1; addi r1, r1, 4 } /* r12 = WORD_7 */
- /* Fill third L1D line. */
+ /* Fill third L1D line. */
EX: { lw r18, r1; addi r1, r1, 4 } /* r18 = WORD_8 */
- /* Store first L1D line. */
+ /* Store first L1D line. */
EX: { sw r0, r16; addi r0, r0, 4; add r16, r0, r2 } /* store(WORD_0) */
EX: { sw r0, r13; addi r0, r0, 4; andi r16, r16, -64 } /* store(WORD_1) */
EX: { sw r0, r14; addi r0, r0, 4; slt_u r16, r9, r16 } /* store(WORD_2) */
#if CHIP_HAS_WH64()
EX: { sw r0, r15; addi r0, r0, 4; addi r13, sp, -64 } /* store(WORD_3) */
#else
- /* Back up the r9 to a cache line we are already storing to
+ /* Back up the r9 to a cache line we are already storing to
* if it gets past the end of the dest vector. Strictly speaking,
* we don't need to back up to the start of a cache line, but it's free
* and tidy, so why not?
- */
+ */
EX: { sw r0, r15; addi r0, r0, 4; andi r13, r0, -64 } /* store(WORD_3) */
#endif
- /* Store second L1D line. */
+ /* Store second L1D line. */
EX: { sw r0, r17; addi r0, r0, 4; mvz r9, r16, r13 }/* store(WORD_4) */
EX: { sw r0, r19; addi r0, r0, 4 } /* store(WORD_5) */
EX: { sw r0, r10; addi r0, r0, 4 } /* store(WORD_6) */
@@ -348,30 +350,30 @@ EX: { lw r13, r1; addi r1, r1, 4; move zero, r18 } /* r13 = WORD_9 */
EX: { lw r14, r1; addi r1, r1, 4 } /* r14 = WORD_10 */
EX: { lw r15, r1; move r1, r20 } /* r15 = WORD_11 */
- /* Store third L1D line. */
+ /* Store third L1D line. */
EX: { sw r0, r18; addi r0, r0, 4 } /* store(WORD_8) */
EX: { sw r0, r13; addi r0, r0, 4 } /* store(WORD_9) */
EX: { sw r0, r14; addi r0, r0, 4 } /* store(WORD_10) */
EX: { sw r0, r15; addi r0, r0, 4 } /* store(WORD_11) */
- /* Store rest of fourth L1D line. */
+ /* Store rest of fourth L1D line. */
EX: { sw r0, r4; addi r0, r0, 4 } /* store(WORD_12) */
- {
+ {
EX: sw r0, r8 /* store(WORD_13) */
- addi r0, r0, 4
+ addi r0, r0, 4
/* Will r2 be > 64 after we subtract 64 below? */
- shri r4, r2, 7
- }
- {
+ shri r4, r2, 7
+ }
+ {
EX: sw r0, r11 /* store(WORD_14) */
- addi r0, r0, 8
- /* Record 64 bytes successfully copied. */
- addi r2, r2, -64
- }
+ addi r0, r0, 8
+ /* Record 64 bytes successfully copied. */
+ addi r2, r2, -64
+ }
{ jrp lr; move lr, r27 }
- /* Convey to the backtrace library that the stack frame is size
+ /* Convey to the backtrace library that the stack frame is size
* zero, and the real return address is on the stack rather than
* in 'lr'.
*/
diff --git a/arch/tile/lib/memmove_32.c b/arch/tile/lib/memmove.c
index fd615ae6ade7..fd615ae6ade7 100644
--- a/arch/tile/lib/memmove_32.c
+++ b/arch/tile/lib/memmove.c
diff --git a/arch/tile/lib/memset_32.c b/arch/tile/lib/memset_32.c
index d014c1fbcbc2..57dbb3a5bff8 100644
--- a/arch/tile/lib/memset_32.c
+++ b/arch/tile/lib/memset_32.c
@@ -18,6 +18,7 @@
#include <linux/string.h>
#include <linux/module.h>
+#undef memset
void *memset(void *s, int c, size_t n)
{
diff --git a/arch/tile/lib/strlen_32.c b/arch/tile/lib/strlen_32.c
index f26f88e11e4a..4974292a5534 100644
--- a/arch/tile/lib/strlen_32.c
+++ b/arch/tile/lib/strlen_32.c
@@ -16,6 +16,8 @@
#include <linux/string.h>
#include <linux/module.h>
+#undef strlen
+
size_t strlen(const char *s)
{
/* Get an aligned pointer. */
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c
index 704f3e8a4385..f295b4ac941d 100644
--- a/arch/tile/mm/fault.c
+++ b/arch/tile/mm/fault.c
@@ -66,10 +66,10 @@ static noinline void force_sig_info_fault(int si_signo, int si_code,
#ifndef __tilegx__
/*
* Synthesize the fault a PL0 process would get by doing a word-load of
- * an unaligned address or a high kernel address. Called indirectly
- * from sys_cmpxchg() in kernel/intvec.S.
+ * an unaligned address or a high kernel address.
*/
-int _sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *regs)
+SYSCALL_DEFINE2(cmpxchg_badaddr, unsigned long, address,
+ struct pt_regs *, regs)
{
if (address >= PAGE_OFFSET)
force_sig_info_fault(SIGSEGV, SEGV_MAPERR, address,
@@ -563,10 +563,10 @@ do_sigbus:
/*
* When we take an ITLB or DTLB fault or access violation in the
* supervisor while the critical section bit is set, the hypervisor is
- * reluctant to write new values into the EX_CONTEXT_1_x registers,
+ * reluctant to write new values into the EX_CONTEXT_K_x registers,
* since that might indicate we have not yet squirreled the SPR
* contents away and can thus safely take a recursive interrupt.
- * Accordingly, the hypervisor passes us the PC via SYSTEM_SAVE_1_2.
+ * Accordingly, the hypervisor passes us the PC via SYSTEM_SAVE_K_2.
*
* Note that this routine is called before homecache_tlb_defer_enter(),
* which means that we can properly unlock any atomics that might
@@ -610,7 +610,7 @@ struct intvec_state do_page_fault_ics(struct pt_regs *regs, int fault_num,
* fault. We didn't set up a kernel stack on initial entry to
* sys_cmpxchg, but instead had one set up by the fault, which
* (because sys_cmpxchg never releases ICS) came to us via the
- * SYSTEM_SAVE_1_2 mechanism, and thus EX_CONTEXT_1_[01] are
+ * SYSTEM_SAVE_K_2 mechanism, and thus EX_CONTEXT_K_[01] are
* still referencing the original user code. We release the
* atomic lock and rewrite pt_regs so that it appears that we
* came from user-space directly, and after we finish the
diff --git a/arch/tile/mm/highmem.c b/arch/tile/mm/highmem.c
index 12ab137e7d4f..abb57331cf6e 100644
--- a/arch/tile/mm/highmem.c
+++ b/arch/tile/mm/highmem.c
@@ -56,50 +56,6 @@ void kunmap(struct page *page)
}
EXPORT_SYMBOL(kunmap);
-static void debug_kmap_atomic_prot(enum km_type type)
-{
-#ifdef CONFIG_DEBUG_HIGHMEM
- static unsigned warn_count = 10;
-
- if (unlikely(warn_count == 0))
- return;
-
- if (unlikely(in_interrupt())) {
- if (in_irq()) {
- if (type != KM_IRQ0 && type != KM_IRQ1 &&
- type != KM_BIO_SRC_IRQ &&
- /* type != KM_BIO_DST_IRQ && */
- type != KM_BOUNCE_READ) {
- WARN_ON(1);
- warn_count--;
- }
- } else if (!irqs_disabled()) { /* softirq */
- if (type != KM_IRQ0 && type != KM_IRQ1 &&
- type != KM_SOFTIRQ0 && type != KM_SOFTIRQ1 &&
- type != KM_SKB_SUNRPC_DATA &&
- type != KM_SKB_DATA_SOFTIRQ &&
- type != KM_BOUNCE_READ) {
- WARN_ON(1);
- warn_count--;
- }
- }
- }
-
- if (type == KM_IRQ0 || type == KM_IRQ1 || type == KM_BOUNCE_READ ||
- type == KM_BIO_SRC_IRQ /* || type == KM_BIO_DST_IRQ */) {
- if (!irqs_disabled()) {
- WARN_ON(1);
- warn_count--;
- }
- } else if (type == KM_SOFTIRQ0 || type == KM_SOFTIRQ1) {
- if (irq_count() == 0 && !irqs_disabled()) {
- WARN_ON(1);
- warn_count--;
- }
- }
-#endif
-}
-
/*
* Describe a single atomic mapping of a page on a given cpu at a
* given address, and allow it to be linked into a list.
@@ -240,10 +196,10 @@ void kmap_atomic_fix_kpte(struct page *page, int finished)
* When holding an atomic kmap is is not legal to sleep, so atomic
* kmaps are appropriate for short, tight code paths only.
*/
-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot(struct page *page, pgprot_t prot)
{
- enum fixed_addresses idx;
unsigned long vaddr;
+ int idx, type;
pte_t *pte;
/* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
@@ -255,8 +211,7 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
if (!PageHighMem(page))
return page_address(page);
- debug_kmap_atomic_prot(type);
-
+ type = kmap_atomic_idx_push();
idx = type + KM_TYPE_NR*smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
pte = kmap_get_pte(vaddr);
@@ -269,28 +224,35 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
}
EXPORT_SYMBOL(kmap_atomic_prot);
-void *kmap_atomic(struct page *page, enum km_type type)
+void *__kmap_atomic(struct page *page)
{
/* PAGE_NONE is a magic value that tells us to check immutability. */
return kmap_atomic_prot(page, type, PAGE_NONE);
}
-EXPORT_SYMBOL(kmap_atomic);
+EXPORT_SYMBOL(__kmap_atomic);
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
{
unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
- enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
- /*
- * Force other mappings to Oops if they try to access this pte without
- * first remapping it. Keeping stale mappings around is a bad idea.
- */
- if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx)) {
+ if (vaddr >= __fix_to_virt(FIX_KMAP_END) &&
+ vaddr <= __fix_to_virt(FIX_KMAP_BEGIN)) {
pte_t *pte = kmap_get_pte(vaddr);
pte_t pteval = *pte;
+ int idx, type;
+
+ type = kmap_atomic_idx();
+ idx = type + KM_TYPE_NR*smp_processor_id();
+
+ /*
+ * Force other mappings to Oops if they try to access this pte
+ * without first remapping it. Keeping stale mappings around
+ * is a bad idea.
+ */
BUG_ON(!pte_present(pteval) && !pte_migrating(pteval));
kmap_atomic_unregister(pte_page(pteval), vaddr);
kpte_clear_flush(pte, vaddr);
+ kmap_atomic_idx_pop();
} else {
/* Must be a lowmem page */
BUG_ON(vaddr < PAGE_OFFSET);
@@ -300,19 +262,19 @@ void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
arch_flush_lazy_mmu_mode();
pagefault_enable();
}
-EXPORT_SYMBOL(kunmap_atomic_notypecheck);
+EXPORT_SYMBOL(__kunmap_atomic);
/*
* This API is supposed to allow us to map memory without a "struct page".
* Currently we don't support this, though this may change in the future.
*/
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
+void *kmap_atomic_pfn(unsigned long pfn)
{
- return kmap_atomic(pfn_to_page(pfn), type);
+ return kmap_atomic(pfn_to_page(pfn));
}
-void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot)
{
- return kmap_atomic_prot(pfn_to_page(pfn), type, prot);
+ return kmap_atomic_prot(pfn_to_page(pfn), prot);
}
struct page *kmap_atomic_to_page(void *ptr)
diff --git a/arch/tile/mm/homecache.c b/arch/tile/mm/homecache.c
index fb3b4a55cec4..d78df3a6ee15 100644
--- a/arch/tile/mm/homecache.c
+++ b/arch/tile/mm/homecache.c
@@ -37,6 +37,8 @@
#include <asm/pgalloc.h>
#include <asm/homecache.h>
+#include <arch/sim.h>
+
#include "migrate.h"
@@ -217,13 +219,6 @@ static unsigned long cache_flush_length(unsigned long length)
return (length >= CHIP_L2_CACHE_SIZE()) ? HV_FLUSH_EVICT_L2 : length;
}
-/* On the simulator, confirm lines have been evicted everywhere. */
-static void validate_lines_evicted(unsigned long pfn, size_t length)
-{
- sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED,
- (HV_PhysAddr)pfn << PAGE_SHIFT, length);
-}
-
/* Flush a page out of whatever cache(s) it is in. */
void homecache_flush_cache(struct page *page, int order)
{
@@ -234,7 +229,7 @@ void homecache_flush_cache(struct page *page, int order)
homecache_mask(page, pages, &home_mask);
flush_remote(pfn, length, &home_mask, 0, 0, 0, NULL, NULL, 0);
- validate_lines_evicted(pfn, pages * PAGE_SIZE);
+ sim_validate_lines_evicted(PFN_PHYS(pfn), pages * PAGE_SIZE);
}
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c
index d89c9eacd162..78e1982cb6c9 100644
--- a/arch/tile/mm/init.c
+++ b/arch/tile/mm/init.c
@@ -1060,7 +1060,7 @@ void free_initmem(void)
/*
* Free the pages mapped from 0xc0000000 that correspond to code
- * pages from 0xfd000000 that we won't use again after init.
+ * pages from MEM_SV_INTRPT that we won't use again after init.
*/
free_init_pages("unused kernel text",
(unsigned long)_sinittext - text_delta,
diff --git a/arch/um/Kconfig.um b/arch/um/Kconfig.um
index ec2b8da1aba4..50d6aa20c353 100644
--- a/arch/um/Kconfig.um
+++ b/arch/um/Kconfig.um
@@ -120,6 +120,9 @@ config SMP
If you don't know what to do, say N.
+config GENERIC_HARDIRQS_NO__DO_IRQ
+ def_bool y
+
config NR_CPUS
int "Maximum number of CPUs (2-32)"
range 2 32
@@ -147,3 +150,6 @@ config KERNEL_STACK_ORDER
This option determines the size of UML kernel stacks. They will
be 1 << order pages. The default is OK unless you're running Valgrind
on UML, in which case, set this to 3.
+
+config NO_DMA
+ def_bool y
diff --git a/arch/um/defconfig b/arch/um/defconfig
index 6bd456f96f90..564f3de65b4a 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -566,7 +566,6 @@ CONFIG_CRC32=m
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
-CONFIG_HAS_DMA=y
#
# SCSI device support
diff --git a/arch/um/include/asm/dma-mapping.h b/arch/um/include/asm/dma-mapping.h
deleted file mode 100644
index 1f469e80fdd3..000000000000
--- a/arch/um/include/asm/dma-mapping.h
+++ /dev/null
@@ -1,112 +0,0 @@
-#ifndef _ASM_DMA_MAPPING_H
-#define _ASM_DMA_MAPPING_H
-
-#include <asm/scatterlist.h>
-
-static inline int
-dma_supported(struct device *dev, u64 mask)
-{
- BUG();
- return(0);
-}
-
-static inline int
-dma_set_mask(struct device *dev, u64 dma_mask)
-{
- BUG();
- return(0);
-}
-
-static inline void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
- gfp_t flag)
-{
- BUG();
- return((void *) 0);
-}
-
-static inline void
-dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
- dma_addr_t dma_handle)
-{
- BUG();
-}
-
-static inline dma_addr_t
-dma_map_single(struct device *dev, void *cpu_addr, size_t size,
- enum dma_data_direction direction)
-{
- BUG();
- return(0);
-}
-
-static inline void
-dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
- enum dma_data_direction direction)
-{
- BUG();
-}
-
-static inline dma_addr_t
-dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size,
- enum dma_data_direction direction)
-{
- BUG();
- return(0);
-}
-
-static inline void
-dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
- enum dma_data_direction direction)
-{
- BUG();
-}
-
-static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
- enum dma_data_direction direction)
-{
- BUG();
- return(0);
-}
-
-static inline void
-dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
- enum dma_data_direction direction)
-{
- BUG();
-}
-
-static inline void
-dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
- enum dma_data_direction direction)
-{
- BUG();
-}
-
-static inline void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
- enum dma_data_direction direction)
-{
- BUG();
-}
-
-#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)
-
-static inline void
-dma_cache_sync(struct device *dev, void *vaddr, size_t size,
- enum dma_data_direction direction)
-{
- BUG();
-}
-
-static inline int
-dma_mapping_error(struct device *dev, dma_addr_t dma_handle)
-{
- BUG();
- return 0;
-}
-
-#endif
diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h
index a9f7251b4a8d..41474fb5eee7 100644
--- a/arch/um/include/asm/pgtable.h
+++ b/arch/um/include/asm/pgtable.h
@@ -338,9 +338,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
#define pte_offset_map(dir, address) \
((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
-#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
#define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
struct mm_struct;
extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr);
diff --git a/arch/um/include/asm/system.h b/arch/um/include/asm/system.h
index 93af1cf0907d..68a90ecd1450 100644
--- a/arch/um/include/asm/system.h
+++ b/arch/um/include/asm/system.h
@@ -8,23 +8,38 @@ extern int set_signals(int enable);
extern void block_signals(void);
extern void unblock_signals(void);
-#define local_save_flags(flags) do { typecheck(unsigned long, flags); \
- (flags) = get_signals(); } while(0)
-#define local_irq_restore(flags) do { typecheck(unsigned long, flags); \
- set_signals(flags); } while(0)
-
-#define local_irq_save(flags) do { local_save_flags(flags); \
- local_irq_disable(); } while(0)
-
-#define local_irq_enable() unblock_signals()
-#define local_irq_disable() block_signals()
-
-#define irqs_disabled() \
-({ \
- unsigned long flags; \
- local_save_flags(flags); \
- (flags == 0); \
-})
+static inline unsigned long arch_local_save_flags(void)
+{
+ return get_signals();
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+ set_signals(flags);
+}
+
+static inline void arch_local_irq_enable(void)
+{
+ unblock_signals();
+}
+
+static inline void arch_local_irq_disable(void)
+{
+ block_signals();
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+ unsigned long flags;
+ flags = arch_local_save_flags();
+ arch_local_irq_disable();
+ return flags;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+ return arch_local_save_flags() == 0;
+}
extern void *_switch_to(void *prev, void *next, void *last);
#define switch_to(prev, next, last) prev = _switch_to(prev, next, last)
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index 69268014dd8e..a3cab6d3ae02 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -50,8 +50,18 @@ SECTIONS
.rela.got : { *(.rela.got) }
.rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
- .rel.plt : { *(.rel.plt) }
- .rela.plt : { *(.rela.plt) }
+ .rel.plt : {
+ *(.rel.plt)
+ PROVIDE_HIDDEN(__rel_iplt_start = .);
+ *(.rel.iplt)
+ PROVIDE_HIDDEN(__rel_iplt_end = .);
+ }
+ .rela.plt : {
+ *(.rela.plt)
+ PROVIDE_HIDDEN(__rela_iplt_start = .);
+ *(.rela.iplt)
+ PROVIDE_HIDDEN(__rela_iplt_end = .);
+ }
.init : {
KEEP (*(.init))
} =0x90909090
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index a746e3037a5b..3f0ac9e0c966 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -334,7 +334,7 @@ unsigned int do_IRQ(int irq, struct uml_pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs((struct pt_regs *)regs);
irq_enter();
- __do_IRQ(irq);
+ generic_handle_irq(irq);
irq_exit();
set_irq_regs(old_regs);
return 1;
@@ -391,17 +391,10 @@ void __init init_IRQ(void)
{
int i;
- irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
- irq_desc[TIMER_IRQ].action = NULL;
- irq_desc[TIMER_IRQ].depth = 1;
- irq_desc[TIMER_IRQ].chip = &SIGVTALRM_irq_type;
- enable_irq(TIMER_IRQ);
+ set_irq_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, handle_edge_irq);
+
for (i = 1; i < NR_IRQS; i++) {
- irq_desc[i].status = IRQ_DISABLED;
- irq_desc[i].action = NULL;
- irq_desc[i].depth = 1;
- irq_desc[i].chip = &normal_irq_type;
- enable_irq(i);
+ set_irq_chip_and_handler(i, &normal_irq_type, handle_edge_irq);
}
}
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
index e0510496596c..a5e33f29bbeb 100644
--- a/arch/um/kernel/ptrace.c
+++ b/arch/um/kernel/ptrace.c
@@ -42,10 +42,12 @@ void ptrace_disable(struct task_struct *child)
extern int peek_user(struct task_struct * child, long addr, long data);
extern int poke_user(struct task_struct * child, long addr, long data);
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int i, ret;
- unsigned long __user *p = (void __user *)(unsigned long)data;
+ unsigned long __user *p = (void __user *)data;
+ void __user *vp = p;
switch (request) {
/* read word at location addr. */
@@ -107,24 +109,20 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
#endif
#ifdef PTRACE_GETFPREGS
case PTRACE_GETFPREGS: /* Get the child FPU state. */
- ret = get_fpregs((struct user_i387_struct __user *) data,
- child);
+ ret = get_fpregs(vp, child);
break;
#endif
#ifdef PTRACE_SETFPREGS
case PTRACE_SETFPREGS: /* Set the child FPU state. */
- ret = set_fpregs((struct user_i387_struct __user *) data,
- child);
+ ret = set_fpregs(vp, child);
break;
#endif
case PTRACE_GET_THREAD_AREA:
- ret = ptrace_get_thread_area(child, addr,
- (struct user_desc __user *) data);
+ ret = ptrace_get_thread_area(child, addr, vp);
break;
case PTRACE_SET_THREAD_AREA:
- ret = ptrace_set_thread_area(child, addr,
- (struct user_desc __user *) data);
+ ret = ptrace_set_thread_area(child, addr, datavp);
break;
case PTRACE_FAULTINFO: {
@@ -134,7 +132,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
* On i386, ptrace_faultinfo is smaller!
*/
ret = copy_to_user(p, &child->thread.arch.faultinfo,
- sizeof(struct ptrace_faultinfo));
+ sizeof(struct ptrace_faultinfo)) ?
+ -EIO : 0;
break;
}
@@ -158,7 +157,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
#ifdef PTRACE_ARCH_PRCTL
case PTRACE_ARCH_PRCTL:
/* XXX Calls ptrace on the host - needs some SMP thinking */
- ret = arch_prctl(child, data, (void *) addr);
+ ret = arch_prctl(child, data, (void __user *) addr);
break;
#endif
default:
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index ec6378550671..fbd99402d4d2 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -22,7 +22,7 @@ SECTIONS
_text = .;
_stext = .;
__init_begin = .;
- INIT_TEXT_SECTION(PAGE_SIZE)
+ INIT_TEXT_SECTION(0)
. = ALIGN(PAGE_SIZE);
.text :
@@ -43,6 +43,23 @@ SECTIONS
__syscall_stub_end = .;
}
+ /*
+ * These are needed even in a static link, even if they wind up being empty.
+ * Newer glibc needs these __rel{,a}_iplt_{start,end} symbols.
+ */
+ .rel.plt : {
+ *(.rel.plt)
+ PROVIDE_HIDDEN(__rel_iplt_start = .);
+ *(.rel.iplt)
+ PROVIDE_HIDDEN(__rel_iplt_end = .);
+ }
+ .rela.plt : {
+ *(.rela.plt)
+ PROVIDE_HIDDEN(__rela_iplt_start = .);
+ *(.rela.iplt)
+ PROVIDE_HIDDEN(__rela_iplt_end = .);
+ }
+
#include "asm/common.lds.S"
init.data : { INIT_DATA }
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
index dec5678fc17f..6e3359d6a839 100644
--- a/arch/um/os-Linux/time.c
+++ b/arch/um/os-Linux/time.c
@@ -60,7 +60,7 @@ static inline long long timeval_to_ns(const struct timeval *tv)
long long disable_timer(void)
{
struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } });
- int remain, max = UM_NSEC_PER_SEC / UM_HZ;
+ long long remain, max = UM_NSEC_PER_SEC / UM_HZ;
if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0)
printk(UM_KERN_ERR "disable_timer - setitimer failed, "
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c
index c9b176534d65..d23b2d3ea384 100644
--- a/arch/um/sys-i386/ptrace.c
+++ b/arch/um/sys-i386/ptrace.c
@@ -203,8 +203,8 @@ int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
(unsigned long *) &fpregs);
}
-long subarch_ptrace(struct task_struct *child, long request, long addr,
- long data)
+long subarch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
return -EIO;
}
diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c
index f3458d7d1c5a..f43613643cdb 100644
--- a/arch/um/sys-x86_64/ptrace.c
+++ b/arch/um/sys-x86_64/ptrace.c
@@ -175,19 +175,18 @@ int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
return restore_fp_registers(userspace_pid[cpu], fpregs);
}
-long subarch_ptrace(struct task_struct *child, long request, long addr,
- long data)
+long subarch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret = -EIO;
+ void __user *datap = (void __user *) data;
switch (request) {
case PTRACE_GETFPXREGS: /* Get the child FPU state. */
- ret = get_fpregs((struct user_i387_struct __user *) data,
- child);
+ ret = get_fpregs(datap, child);
break;
case PTRACE_SETFPXREGS: /* Set the child FPU state. */
- ret = set_fpregs((struct user_i387_struct __user *) data,
- child);
+ ret = set_fpregs(datap, child);
break;
}
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index dfabfefc21c4..299fbc86f570 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -347,6 +347,7 @@ endif
config X86_VSMP
bool "ScaleMP vSMP"
+ select PARAVIRT_GUEST
select PARAVIRT
depends on X86_64 && PCI
depends on X86_EXTENDED_PLATFORM
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index 8f7bef8e9fff..23f315c9f215 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -229,18 +229,35 @@ void *memset(void *s, int c, size_t n)
ss[i] = c;
return s;
}
-
+#ifdef CONFIG_X86_32
void *memcpy(void *dest, const void *src, size_t n)
{
- int i;
- const char *s = src;
- char *d = dest;
+ int d0, d1, d2;
+ asm volatile(
+ "rep ; movsl\n\t"
+ "movl %4,%%ecx\n\t"
+ "rep ; movsb\n\t"
+ : "=&c" (d0), "=&D" (d1), "=&S" (d2)
+ : "0" (n >> 2), "g" (n & 3), "1" (dest), "2" (src)
+ : "memory");
- for (i = 0; i < n; i++)
- d[i] = s[i];
return dest;
}
+#else
+void *memcpy(void *dest, const void *src, size_t n)
+{
+ long d0, d1, d2;
+ asm volatile(
+ "rep ; movsq\n\t"
+ "movq %4,%%rcx\n\t"
+ "rep ; movsb\n\t"
+ : "=&c" (d0), "=&D" (d1), "=&S" (d2)
+ : "0" (n >> 3), "g" (n & 7), "1" (dest), "2" (src)
+ : "memory");
+ return dest;
+}
+#endif
static void error(char *x)
{
diff --git a/arch/x86/include/asm/calling.h b/arch/x86/include/asm/calling.h
index 0e63c9a2a8d0..30af5a832163 100644
--- a/arch/x86/include/asm/calling.h
+++ b/arch/x86/include/asm/calling.h
@@ -48,36 +48,38 @@ For 32-bit we have the following conventions - kernel is built with
/*
- * 64-bit system call stack frame layout defines and helpers,
- * for assembly code:
+ * 64-bit system call stack frame layout defines and helpers, for
+ * assembly code (note that the seemingly unnecessary parentheses
+ * are to prevent cpp from inserting spaces in expressions that get
+ * passed to macros):
*/
-#define R15 0
-#define R14 8
-#define R13 16
-#define R12 24
-#define RBP 32
-#define RBX 40
+#define R15 (0)
+#define R14 (8)
+#define R13 (16)
+#define R12 (24)
+#define RBP (32)
+#define RBX (40)
/* arguments: interrupts/non tracing syscalls only save up to here: */
-#define R11 48
-#define R10 56
-#define R9 64
-#define R8 72
-#define RAX 80
-#define RCX 88
-#define RDX 96
-#define RSI 104
-#define RDI 112
-#define ORIG_RAX 120 /* + error_code */
+#define R11 (48)
+#define R10 (56)
+#define R9 (64)
+#define R8 (72)
+#define RAX (80)
+#define RCX (88)
+#define RDX (96)
+#define RSI (104)
+#define RDI (112)
+#define ORIG_RAX (120) /* + error_code */
/* end of arguments */
/* cpu exception frame or undefined in case of fast syscall: */
-#define RIP 128
-#define CS 136
-#define EFLAGS 144
-#define RSP 152
-#define SS 160
+#define RIP (128)
+#define CS (136)
+#define EFLAGS (144)
+#define RSP (152)
+#define SS (160)
#define ARGOFFSET R11
#define SWFRAME ORIG_RAX
@@ -111,7 +113,7 @@ For 32-bit we have the following conventions - kernel is built with
.endif
.endm
-#define ARG_SKIP 9*8
+#define ARG_SKIP (9*8)
.macro RESTORE_ARGS skiprax=0, addskip=0, skiprcx=0, skipr11=0, \
skipr8910=0, skiprdx=0
@@ -169,7 +171,7 @@ For 32-bit we have the following conventions - kernel is built with
.endif
.endm
-#define REST_SKIP 6*8
+#define REST_SKIP (6*8)
.macro SAVE_REST
subq $REST_SKIP, %rsp
diff --git a/arch/x86/include/asm/entry_arch.h b/arch/x86/include/asm/entry_arch.h
index b8e96a18676b..57650ab4a5f5 100644
--- a/arch/x86/include/asm/entry_arch.h
+++ b/arch/x86/include/asm/entry_arch.h
@@ -16,22 +16,11 @@ BUILD_INTERRUPT(call_function_single_interrupt,CALL_FUNCTION_SINGLE_VECTOR)
BUILD_INTERRUPT(irq_move_cleanup_interrupt,IRQ_MOVE_CLEANUP_VECTOR)
BUILD_INTERRUPT(reboot_interrupt,REBOOT_VECTOR)
-BUILD_INTERRUPT3(invalidate_interrupt0,INVALIDATE_TLB_VECTOR_START+0,
- smp_invalidate_interrupt)
-BUILD_INTERRUPT3(invalidate_interrupt1,INVALIDATE_TLB_VECTOR_START+1,
- smp_invalidate_interrupt)
-BUILD_INTERRUPT3(invalidate_interrupt2,INVALIDATE_TLB_VECTOR_START+2,
- smp_invalidate_interrupt)
-BUILD_INTERRUPT3(invalidate_interrupt3,INVALIDATE_TLB_VECTOR_START+3,
- smp_invalidate_interrupt)
-BUILD_INTERRUPT3(invalidate_interrupt4,INVALIDATE_TLB_VECTOR_START+4,
- smp_invalidate_interrupt)
-BUILD_INTERRUPT3(invalidate_interrupt5,INVALIDATE_TLB_VECTOR_START+5,
- smp_invalidate_interrupt)
-BUILD_INTERRUPT3(invalidate_interrupt6,INVALIDATE_TLB_VECTOR_START+6,
- smp_invalidate_interrupt)
-BUILD_INTERRUPT3(invalidate_interrupt7,INVALIDATE_TLB_VECTOR_START+7,
+.irpc idx, "01234567"
+BUILD_INTERRUPT3(invalidate_interrupt\idx,
+ (INVALIDATE_TLB_VECTOR_START)+\idx,
smp_invalidate_interrupt)
+.endr
#endif
BUILD_INTERRUPT(x86_platform_ipi, X86_PLATFORM_IPI_VECTOR)
diff --git a/arch/x86/include/asm/highmem.h b/arch/x86/include/asm/highmem.h
index 8caac76ac324..3bd04022fd0c 100644
--- a/arch/x86/include/asm/highmem.h
+++ b/arch/x86/include/asm/highmem.h
@@ -59,11 +59,12 @@ extern void kunmap_high(struct page *page);
void *kmap(struct page *page);
void kunmap(struct page *page);
-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot);
-void *kmap_atomic(struct page *page, enum km_type type);
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
-void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
+
+void *kmap_atomic_prot(struct page *page, pgprot_t prot);
+void *__kmap_atomic(struct page *page);
+void __kunmap_atomic(void *kvaddr);
+void *kmap_atomic_pfn(unsigned long pfn);
+void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot);
struct page *kmap_atomic_to_page(void *ptr);
#define flush_cache_kmaps() do { } while (0)
diff --git a/arch/x86/include/asm/iomap.h b/arch/x86/include/asm/iomap.h
index c4191b3b7056..363e33eb6ec1 100644
--- a/arch/x86/include/asm/iomap.h
+++ b/arch/x86/include/asm/iomap.h
@@ -27,10 +27,10 @@
#include <asm/tlbflush.h>
void __iomem *
-iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
+iomap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot);
void
-iounmap_atomic(void __iomem *kvaddr, enum km_type type);
+iounmap_atomic(void __iomem *kvaddr);
int
iomap_create_wc(resource_size_t base, unsigned long size, pgprot_t *prot);
diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h
index 0bf5b0083650..13b0ebaa512f 100644
--- a/arch/x86/include/asm/irq.h
+++ b/arch/x86/include/asm/irq.h
@@ -21,10 +21,8 @@ static inline int irq_canonicalize(int irq)
#ifdef CONFIG_X86_32
extern void irq_ctx_init(int cpu);
-extern void irq_ctx_exit(int cpu);
#else
# define irq_ctx_init(cpu) do { } while (0)
-# define irq_ctx_exit(cpu) do { } while (0)
#endif
#define __ARCH_HAS_DO_SOFTIRQ
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 1f99ecfc48e1..b36c6b3fe144 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -139,6 +139,7 @@ struct x86_emulate_ops {
void (*set_segment_selector)(u16 sel, int seg, struct kvm_vcpu *vcpu);
unsigned long (*get_cached_segment_base)(int seg, struct kvm_vcpu *vcpu);
void (*get_gdt)(struct desc_ptr *dt, struct kvm_vcpu *vcpu);
+ void (*get_idt)(struct desc_ptr *dt, struct kvm_vcpu *vcpu);
ulong (*get_cr)(int cr, struct kvm_vcpu *vcpu);
int (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu);
int (*cpl)(struct kvm_vcpu *vcpu);
@@ -156,7 +157,10 @@ struct operand {
unsigned long orig_val;
u64 orig_val64;
};
- unsigned long *ptr;
+ union {
+ unsigned long *reg;
+ unsigned long mem;
+ } addr;
union {
unsigned long val;
u64 val64;
@@ -190,6 +194,7 @@ struct decode_cache {
bool has_seg_override;
u8 seg_override;
unsigned int d;
+ int (*execute)(struct x86_emulate_ctxt *ctxt);
unsigned long regs[NR_VCPU_REGS];
unsigned long eip;
/* modrm */
@@ -197,17 +202,16 @@ struct decode_cache {
u8 modrm_mod;
u8 modrm_reg;
u8 modrm_rm;
- u8 use_modrm_ea;
+ u8 modrm_seg;
bool rip_relative;
- unsigned long modrm_ea;
- void *modrm_ptr;
- unsigned long modrm_val;
struct fetch_cache fetch;
struct read_cache io_read;
struct read_cache mem_read;
};
struct x86_emulate_ctxt {
+ struct x86_emulate_ops *ops;
+
/* Register state before/after emulation. */
struct kvm_vcpu *vcpu;
@@ -220,12 +224,11 @@ struct x86_emulate_ctxt {
/* interruptibility state, as a result of execution of STI or MOV SS */
int interruptibility;
- bool restart; /* restart string instruction after writeback */
+ bool perm_ok; /* do not check permissions if true */
int exception; /* exception that happens during emulation or -1 */
u32 error_code; /* error code for exception */
bool error_code_valid;
- unsigned long cr2; /* faulted address in case of #PF */
/* decode cache */
struct decode_cache decode;
@@ -249,13 +252,14 @@ struct x86_emulate_ctxt {
#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64
#endif
-int x86_decode_insn(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops);
-int x86_emulate_insn(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops);
+int x86_decode_insn(struct x86_emulate_ctxt *ctxt);
+#define EMULATION_FAILED -1
+#define EMULATION_OK 0
+#define EMULATION_RESTART 1
+int x86_emulate_insn(struct x86_emulate_ctxt *ctxt);
int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops,
u16 tss_selector, int reason,
bool has_error_code, u32 error_code);
-
+int emulate_int_real(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops, int irq);
#endif /* _ASM_X86_KVM_X86_EMULATE_H */
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index c52e2eb40a1e..9e6fe391094e 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -236,10 +236,14 @@ struct kvm_pio_request {
*/
struct kvm_mmu {
void (*new_cr3)(struct kvm_vcpu *vcpu);
+ void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long root);
+ unsigned long (*get_cr3)(struct kvm_vcpu *vcpu);
int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err);
+ void (*inject_page_fault)(struct kvm_vcpu *vcpu);
void (*free)(struct kvm_vcpu *vcpu);
gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva, u32 access,
u32 *error);
+ gpa_t (*translate_gpa)(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access);
void (*prefetch_page)(struct kvm_vcpu *vcpu,
struct kvm_mmu_page *page);
int (*sync_page)(struct kvm_vcpu *vcpu,
@@ -249,13 +253,18 @@ struct kvm_mmu {
int root_level;
int shadow_root_level;
union kvm_mmu_page_role base_role;
+ bool direct_map;
u64 *pae_root;
+ u64 *lm_root;
u64 rsvd_bits_mask[2][4];
+
+ bool nx;
+
+ u64 pdptrs[4]; /* pae */
};
struct kvm_vcpu_arch {
- u64 host_tsc;
/*
* rip and regs accesses must go through
* kvm_{register,rip}_{read,write} functions.
@@ -272,7 +281,6 @@ struct kvm_vcpu_arch {
unsigned long cr4_guest_owned_bits;
unsigned long cr8;
u32 hflags;
- u64 pdptrs[4]; /* pae */
u64 efer;
u64 apic_base;
struct kvm_lapic *apic; /* kernel irqchip context */
@@ -282,7 +290,41 @@ struct kvm_vcpu_arch {
u64 ia32_misc_enable_msr;
bool tpr_access_reporting;
+ /*
+ * Paging state of the vcpu
+ *
+ * If the vcpu runs in guest mode with two level paging this still saves
+ * the paging mode of the l1 guest. This context is always used to
+ * handle faults.
+ */
struct kvm_mmu mmu;
+
+ /*
+ * Paging state of an L2 guest (used for nested npt)
+ *
+ * This context will save all necessary information to walk page tables
+ * of the an L2 guest. This context is only initialized for page table
+ * walking and not for faulting since we never handle l2 page faults on
+ * the host.
+ */
+ struct kvm_mmu nested_mmu;
+
+ /*
+ * Pointer to the mmu context currently used for
+ * gva_to_gpa translations.
+ */
+ struct kvm_mmu *walk_mmu;
+
+ /*
+ * This struct is filled with the necessary information to propagate a
+ * page fault into the guest
+ */
+ struct {
+ u64 address;
+ unsigned error_code;
+ bool nested;
+ } fault;
+
/* only needed in kvm_pv_mmu_op() path, but it's hot so
* put it here to avoid allocation */
struct kvm_pv_mmu_op_buffer mmu_op_buffer;
@@ -336,9 +378,15 @@ struct kvm_vcpu_arch {
gpa_t time;
struct pvclock_vcpu_time_info hv_clock;
- unsigned int hv_clock_tsc_khz;
+ unsigned int hw_tsc_khz;
unsigned int time_offset;
struct page *time_page;
+ u64 last_host_tsc;
+ u64 last_guest_tsc;
+ u64 last_kernel_ns;
+ u64 last_tsc_nsec;
+ u64 last_tsc_write;
+ bool tsc_catchup;
bool nmi_pending;
bool nmi_injected;
@@ -367,9 +415,9 @@ struct kvm_vcpu_arch {
};
struct kvm_arch {
- unsigned int n_free_mmu_pages;
+ unsigned int n_used_mmu_pages;
unsigned int n_requested_mmu_pages;
- unsigned int n_alloc_mmu_pages;
+ unsigned int n_max_mmu_pages;
atomic_t invlpg_counter;
struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
/*
@@ -394,8 +442,14 @@ struct kvm_arch {
gpa_t ept_identity_map_addr;
unsigned long irq_sources_bitmap;
- u64 vm_init_tsc;
s64 kvmclock_offset;
+ spinlock_t tsc_write_lock;
+ u64 last_tsc_nsec;
+ u64 last_tsc_offset;
+ u64 last_tsc_write;
+ u32 virtual_tsc_khz;
+ u32 virtual_tsc_mult;
+ s8 virtual_tsc_shift;
struct kvm_xen_hvm_config xen_hvm_config;
@@ -505,6 +559,7 @@ struct kvm_x86_ops {
void (*queue_exception)(struct kvm_vcpu *vcpu, unsigned nr,
bool has_error_code, u32 error_code,
bool reinject);
+ void (*cancel_injection)(struct kvm_vcpu *vcpu);
int (*interrupt_allowed)(struct kvm_vcpu *vcpu);
int (*nmi_allowed)(struct kvm_vcpu *vcpu);
bool (*get_nmi_mask)(struct kvm_vcpu *vcpu);
@@ -517,11 +572,16 @@ struct kvm_x86_ops {
u64 (*get_mt_mask)(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio);
int (*get_lpage_level)(void);
bool (*rdtscp_supported)(void);
+ void (*adjust_tsc_offset)(struct kvm_vcpu *vcpu, s64 adjustment);
+
+ void (*set_tdp_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
void (*set_supported_cpuid)(u32 func, struct kvm_cpuid_entry2 *entry);
bool (*has_wbinvd_exit)(void);
+ void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
+
const struct trace_print_flags *exit_reasons_str;
};
@@ -544,7 +604,7 @@ void kvm_mmu_zap_all(struct kvm *kvm);
unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm);
void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages);
-int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3);
+int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3);
int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
const void *val, int bytes);
@@ -608,8 +668,11 @@ void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr);
void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code);
void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned nr);
void kvm_requeue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code);
-void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long cr2,
- u32 error_code);
+void kvm_inject_page_fault(struct kvm_vcpu *vcpu);
+int kvm_read_guest_page_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
+ gfn_t gfn, void *data, int offset, int len,
+ u32 access);
+void kvm_propagate_fault(struct kvm_vcpu *vcpu);
bool kvm_require_cpl(struct kvm_vcpu *vcpu, int required_cpl);
int kvm_pic_set_irq(void *opaque, int irq, int level);
diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h
index 05eba5e9a8e8..7b562b6184bc 100644
--- a/arch/x86/include/asm/kvm_para.h
+++ b/arch/x86/include/asm/kvm_para.h
@@ -158,6 +158,12 @@ static inline unsigned int kvm_arch_para_features(void)
return cpuid_eax(KVM_CPUID_FEATURES);
}
+#ifdef CONFIG_KVM_GUEST
+void __init kvm_guest_init(void);
+#else
+#define kvm_guest_init() do { } while (0)
#endif
+#endif /* __KERNEL__ */
+
#endif /* _ASM_X86_KVM_PARA_H */
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 986f7790fdb2..3ea3dc487047 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -121,6 +121,7 @@
#define MSR_AMD64_IBSDCLINAD 0xc0011038
#define MSR_AMD64_IBSDCPHYSAD 0xc0011039
#define MSR_AMD64_IBSCTL 0xc001103a
+#define MSR_AMD64_IBSBRTARGET 0xc001103b
/* Fam 10h MSRs */
#define MSR_FAM10H_MMIO_CONF_BASE 0xc0010058
@@ -198,6 +199,7 @@
#define MSR_IA32_TSC 0x00000010
#define MSR_IA32_PLATFORM_ID 0x00000017
#define MSR_IA32_EBL_CR_POWERON 0x0000002a
+#define MSR_EBC_FREQUENCY_ID 0x0000002c
#define MSR_IA32_FEATURE_CONTROL 0x0000003a
#define FEATURE_CONTROL_LOCKED (1<<0)
diff --git a/arch/x86/include/asm/olpc.h b/arch/x86/include/asm/olpc.h
index 101229b0d8ed..42a978c0c1b3 100644
--- a/arch/x86/include/asm/olpc.h
+++ b/arch/x86/include/asm/olpc.h
@@ -89,6 +89,8 @@ extern int olpc_ec_mask_unset(uint8_t bits);
/* EC commands */
#define EC_FIRMWARE_REV 0x08
+#define EC_WLAN_ENTER_RESET 0x35
+#define EC_WLAN_LEAVE_RESET 0x25
/* SCI source values */
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index 6e742cc4251b..550e26b1dbb3 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -111,17 +111,18 @@ union cpuid10_edx {
#define X86_PMC_IDX_FIXED_BTS (X86_PMC_IDX_FIXED + 16)
/* IbsFetchCtl bits/masks */
-#define IBS_FETCH_RAND_EN (1ULL<<57)
-#define IBS_FETCH_VAL (1ULL<<49)
-#define IBS_FETCH_ENABLE (1ULL<<48)
-#define IBS_FETCH_CNT 0xFFFF0000ULL
-#define IBS_FETCH_MAX_CNT 0x0000FFFFULL
+#define IBS_FETCH_RAND_EN (1ULL<<57)
+#define IBS_FETCH_VAL (1ULL<<49)
+#define IBS_FETCH_ENABLE (1ULL<<48)
+#define IBS_FETCH_CNT 0xFFFF0000ULL
+#define IBS_FETCH_MAX_CNT 0x0000FFFFULL
/* IbsOpCtl bits */
-#define IBS_OP_CNT_CTL (1ULL<<19)
-#define IBS_OP_VAL (1ULL<<18)
-#define IBS_OP_ENABLE (1ULL<<17)
-#define IBS_OP_MAX_CNT 0x0000FFFFULL
+#define IBS_OP_CNT_CTL (1ULL<<19)
+#define IBS_OP_VAL (1ULL<<18)
+#define IBS_OP_ENABLE (1ULL<<17)
+#define IBS_OP_MAX_CNT 0x0000FFFFULL
+#define IBS_OP_MAX_CNT_EXT 0x007FFFFFULL /* not a register bit mask */
#ifdef CONFIG_PERF_EVENTS
extern void init_hw_perf_events(void);
diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h
index 8abde9ec90bf..0c92113c4cb6 100644
--- a/arch/x86/include/asm/pgtable_32.h
+++ b/arch/x86/include/asm/pgtable_32.h
@@ -49,24 +49,14 @@ extern void set_pmd_pfn(unsigned long, unsigned long, pgprot_t);
#endif
#if defined(CONFIG_HIGHPTE)
-#define __KM_PTE \
- (in_nmi() ? KM_NMI_PTE : \
- in_irq() ? KM_IRQ_PTE : \
- KM_PTE0)
#define pte_offset_map(dir, address) \
- ((pte_t *)kmap_atomic(pmd_page(*(dir)), __KM_PTE) + \
+ ((pte_t *)kmap_atomic(pmd_page(*(dir))) + \
pte_index((address)))
-#define pte_offset_map_nested(dir, address) \
- ((pte_t *)kmap_atomic(pmd_page(*(dir)), KM_PTE1) + \
- pte_index((address)))
-#define pte_unmap(pte) kunmap_atomic((pte), __KM_PTE)
-#define pte_unmap_nested(pte) kunmap_atomic((pte), KM_PTE1)
+#define pte_unmap(pte) kunmap_atomic((pte))
#else
#define pte_offset_map(dir, address) \
((pte_t *)page_address(pmd_page(*(dir))) + pte_index((address)))
-#define pte_offset_map_nested(dir, address) pte_offset_map((dir), (address))
#define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
#endif
/* Clear a kernel PTE and flush it from the TLB */
diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h
index f96ac9bedf75..f86da20347f2 100644
--- a/arch/x86/include/asm/pgtable_64.h
+++ b/arch/x86/include/asm/pgtable_64.h
@@ -127,9 +127,7 @@ static inline int pgd_large(pgd_t pgd) { return 0; }
/* x86-64 always has all page tables mapped. */
#define pte_offset_map(dir, address) pte_offset_kernel((dir), (address))
-#define pte_offset_map_nested(dir, address) pte_offset_kernel((dir), (address))
#define pte_unmap(pte) ((void)(pte))/* NOP */
-#define pte_unmap_nested(pte) ((void)(pte)) /* NOP */
#define update_mmu_cache(vma, address, ptep) do { } while (0)
diff --git a/arch/x86/include/asm/pvclock.h b/arch/x86/include/asm/pvclock.h
index cd02f324aa6b..7f7e577a0e39 100644
--- a/arch/x86/include/asm/pvclock.h
+++ b/arch/x86/include/asm/pvclock.h
@@ -12,4 +12,42 @@ void pvclock_read_wallclock(struct pvclock_wall_clock *wall,
struct pvclock_vcpu_time_info *vcpu,
struct timespec *ts);
+/*
+ * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
+ * yielding a 64-bit result.
+ */
+static inline u64 pvclock_scale_delta(u64 delta, u32 mul_frac, int shift)
+{
+ u64 product;
+#ifdef __i386__
+ u32 tmp1, tmp2;
+#endif
+
+ if (shift < 0)
+ delta >>= -shift;
+ else
+ delta <<= shift;
+
+#ifdef __i386__
+ __asm__ (
+ "mul %5 ; "
+ "mov %4,%%eax ; "
+ "mov %%edx,%4 ; "
+ "mul %5 ; "
+ "xor %5,%5 ; "
+ "add %4,%%eax ; "
+ "adc %5,%%edx ; "
+ : "=A" (product), "=r" (tmp1), "=r" (tmp2)
+ : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
+#elif defined(__x86_64__)
+ __asm__ (
+ "mul %%rdx ; shrd $32,%%rdx,%%rax"
+ : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
+#else
+#error implement me!
+#endif
+
+ return product;
+}
+
#endif /* _ASM_X86_PVCLOCK_H */
diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h
index 14e0ed86a6f9..231f1c1d6607 100644
--- a/arch/x86/include/asm/segment.h
+++ b/arch/x86/include/asm/segment.h
@@ -73,31 +73,31 @@
#define GDT_ENTRY_DEFAULT_USER_DS 15
-#define GDT_ENTRY_KERNEL_BASE 12
+#define GDT_ENTRY_KERNEL_BASE (12)
-#define GDT_ENTRY_KERNEL_CS (GDT_ENTRY_KERNEL_BASE + 0)
+#define GDT_ENTRY_KERNEL_CS (GDT_ENTRY_KERNEL_BASE+0)
-#define GDT_ENTRY_KERNEL_DS (GDT_ENTRY_KERNEL_BASE + 1)
+#define GDT_ENTRY_KERNEL_DS (GDT_ENTRY_KERNEL_BASE+1)
-#define GDT_ENTRY_TSS (GDT_ENTRY_KERNEL_BASE + 4)
-#define GDT_ENTRY_LDT (GDT_ENTRY_KERNEL_BASE + 5)
+#define GDT_ENTRY_TSS (GDT_ENTRY_KERNEL_BASE+4)
+#define GDT_ENTRY_LDT (GDT_ENTRY_KERNEL_BASE+5)
-#define GDT_ENTRY_PNPBIOS_BASE (GDT_ENTRY_KERNEL_BASE + 6)
-#define GDT_ENTRY_APMBIOS_BASE (GDT_ENTRY_KERNEL_BASE + 11)
+#define GDT_ENTRY_PNPBIOS_BASE (GDT_ENTRY_KERNEL_BASE+6)
+#define GDT_ENTRY_APMBIOS_BASE (GDT_ENTRY_KERNEL_BASE+11)
-#define GDT_ENTRY_ESPFIX_SS (GDT_ENTRY_KERNEL_BASE + 14)
-#define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8)
+#define GDT_ENTRY_ESPFIX_SS (GDT_ENTRY_KERNEL_BASE+14)
+#define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS*8)
-#define GDT_ENTRY_PERCPU (GDT_ENTRY_KERNEL_BASE + 15)
+#define GDT_ENTRY_PERCPU (GDT_ENTRY_KERNEL_BASE+15)
#ifdef CONFIG_SMP
#define __KERNEL_PERCPU (GDT_ENTRY_PERCPU * 8)
#else
#define __KERNEL_PERCPU 0
#endif
-#define GDT_ENTRY_STACK_CANARY (GDT_ENTRY_KERNEL_BASE + 16)
+#define GDT_ENTRY_STACK_CANARY (GDT_ENTRY_KERNEL_BASE+16)
#ifdef CONFIG_CC_STACKPROTECTOR
-#define __KERNEL_STACK_CANARY (GDT_ENTRY_STACK_CANARY * 8)
+#define __KERNEL_STACK_CANARY (GDT_ENTRY_STACK_CANARY*8)
#else
#define __KERNEL_STACK_CANARY 0
#endif
@@ -182,10 +182,10 @@
#endif
-#define __KERNEL_CS (GDT_ENTRY_KERNEL_CS * 8)
-#define __KERNEL_DS (GDT_ENTRY_KERNEL_DS * 8)
-#define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS* 8 + 3)
-#define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS* 8 + 3)
+#define __KERNEL_CS (GDT_ENTRY_KERNEL_CS*8)
+#define __KERNEL_DS (GDT_ENTRY_KERNEL_DS*8)
+#define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS*8+3)
+#define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS*8+3)
#ifndef CONFIG_PARAVIRT
#define get_kernel_rpl() 0
#endif
diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h
index 4cfc90824068..4c2f63c7fc1b 100644
--- a/arch/x86/include/asm/smp.h
+++ b/arch/x86/include/asm/smp.h
@@ -50,7 +50,7 @@ struct smp_ops {
void (*smp_prepare_cpus)(unsigned max_cpus);
void (*smp_cpus_done)(unsigned max_cpus);
- void (*smp_send_stop)(void);
+ void (*stop_other_cpus)(int wait);
void (*smp_send_reschedule)(int cpu);
int (*cpu_up)(unsigned cpu);
@@ -73,7 +73,12 @@ extern struct smp_ops smp_ops;
static inline void smp_send_stop(void)
{
- smp_ops.smp_send_stop();
+ smp_ops.stop_other_cpus(0);
+}
+
+static inline void stop_other_cpus(void)
+{
+ smp_ops.stop_other_cpus(1);
}
static inline void smp_prepare_boot_cpu(void)
diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h
index 7fda040a76cd..a3c28ae4025b 100644
--- a/arch/x86/include/asm/xen/hypercall.h
+++ b/arch/x86/include/asm/xen/hypercall.h
@@ -200,6 +200,23 @@ extern struct { char _entry[32]; } hypercall_page[];
(type)__res; \
})
+static inline long
+privcmd_call(unsigned call,
+ unsigned long a1, unsigned long a2,
+ unsigned long a3, unsigned long a4,
+ unsigned long a5)
+{
+ __HYPERCALL_DECLS;
+ __HYPERCALL_5ARG(a1, a2, a3, a4, a5);
+
+ asm volatile("call *%[call]"
+ : __HYPERCALL_5PARAM
+ : [call] "a" (&hypercall_page[call])
+ : __HYPERCALL_CLOBBER5);
+
+ return (long)__res;
+}
+
static inline int
HYPERVISOR_set_trap_table(struct trap_info *table)
{
diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
index bf5f7d32bd08..dd8c1414b3d5 100644
--- a/arch/x86/include/asm/xen/page.h
+++ b/arch/x86/include/asm/xen/page.h
@@ -37,14 +37,21 @@ typedef struct xpaddr {
extern unsigned long get_phys_to_machine(unsigned long pfn);
-extern void set_phys_to_machine(unsigned long pfn, unsigned long mfn);
+extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
static inline unsigned long pfn_to_mfn(unsigned long pfn)
{
+ unsigned long mfn;
+
if (xen_feature(XENFEAT_auto_translated_physmap))
return pfn;
- return get_phys_to_machine(pfn) & ~FOREIGN_FRAME_BIT;
+ mfn = get_phys_to_machine(pfn);
+
+ if (mfn != INVALID_P2M_ENTRY)
+ mfn &= ~FOREIGN_FRAME_BIT;
+
+ return mfn;
}
static inline int phys_to_machine_mapping_valid(unsigned long pfn)
@@ -159,6 +166,7 @@ static inline pte_t __pte_ma(pteval_t x)
#define pgd_val_ma(x) ((x).pgd)
+void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid);
xmaddr_t arbitrary_virt_to_machine(void *address);
unsigned long arbitrary_virt_to_mfn(void *vaddr);
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 74a847835bab..69fd72aa5594 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -15,7 +15,6 @@
#ifdef CONFIG_X86_32
#include <asm/pgtable.h>
-#include <asm/pgtable_32.h>
#endif
#include "realmode/wakeup.h"
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index fbbc4dadecc4..0e4f24c2a746 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -189,8 +189,8 @@
* Intel Order Number 241704-001. Microsoft Part Number 781-110-X01.
*
* [This document is available free from Intel by calling 800.628.8686 (fax
- * 916.356.6100) or 800.548.4725; or via anonymous ftp from
- * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc. It is also
+ * 916.356.6100) or 800.548.4725; or from
+ * http://www.microsoft.com/whdc/archive/amp_12.mspx It is also
* available from Microsoft by calling 206.882.8080.]
*
* APM 1.2 Reference:
diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c
index dfdbf6403895..1a4088dda37a 100644
--- a/arch/x86/kernel/asm-offsets_32.c
+++ b/arch/x86/kernel/asm-offsets_32.c
@@ -99,9 +99,7 @@ void foo(void)
DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
DEFINE(PAGE_SHIFT_asm, PAGE_SHIFT);
- DEFINE(PTRS_PER_PTE, PTRS_PER_PTE);
- DEFINE(PTRS_PER_PMD, PTRS_PER_PMD);
- DEFINE(PTRS_PER_PGD, PTRS_PER_PGD);
+ DEFINE(THREAD_SIZE_asm, THREAD_SIZE);
OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
index cd8da247dda1..a2baafb2fe6d 100644
--- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -701,6 +701,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
per_cpu(acfreq_data, policy->cpu) = NULL;
acpi_processor_unregister_performance(data->acpi_data,
policy->cpu);
+ kfree(data->freq_table);
kfree(data);
}
diff --git a/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c b/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
index 733093d60436..141abebc4516 100644
--- a/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
+++ b/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
@@ -393,7 +393,7 @@ static struct cpufreq_driver nforce2_driver = {
* Detects nForce2 A2 and C1 stepping
*
*/
-static unsigned int nforce2_detect_chipset(void)
+static int nforce2_detect_chipset(void)
{
nforce2_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
PCI_DEVICE_ID_NVIDIA_NFORCE2,
diff --git a/arch/x86/kernel/cpu/cpufreq/longrun.c b/arch/x86/kernel/cpu/cpufreq/longrun.c
index fc09f142d94d..d9f51367666b 100644
--- a/arch/x86/kernel/cpu/cpufreq/longrun.c
+++ b/arch/x86/kernel/cpu/cpufreq/longrun.c
@@ -35,7 +35,7 @@ static unsigned int longrun_low_freq, longrun_high_freq;
* Reads the current LongRun policy by access to MSR_TMTA_LONGRUN_FLAGS
* and MSR_TMTA_LONGRUN_CTRL
*/
-static void __init longrun_get_policy(struct cpufreq_policy *policy)
+static void __cpuinit longrun_get_policy(struct cpufreq_policy *policy)
{
u32 msr_lo, msr_hi;
@@ -165,7 +165,7 @@ static unsigned int longrun_get(unsigned int cpu)
* TMTA rules:
* performance_pctg = (target_freq - low_freq)/(high_freq - low_freq)
*/
-static unsigned int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
+static int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
unsigned int *high_freq)
{
u32 msr_lo, msr_hi;
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 695f17731e23..d16c2c53d6bf 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -284,9 +284,7 @@ static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c)
/* Don't do the funky fallback heuristics the AMD version employs
for now. */
node = apicid_to_node[apicid];
- if (node == NUMA_NO_NODE)
- node = first_node(node_online_map);
- else if (!node_online(node)) {
+ if (node == NUMA_NO_NODE || !node_online(node)) {
/* reuse the value from init_cpu_to_node() */
node = cpu_to_node(cpu);
}
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 12cd823c8d03..17ad03366211 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -327,6 +327,7 @@ static void __cpuinit amd_calc_l3_indices(struct amd_l3_cache *l3)
l3->subcaches[3] = sc3 = !(val & BIT(12)) + !(val & BIT(13));
l3->indices = (max(max(max(sc0, sc1), sc2), sc3) << 10) - 1;
+ l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
}
static struct amd_l3_cache * __cpuinit amd_init_l3_cache(int node)
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index fe73c1844a9a..ed6310183efb 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -49,7 +49,6 @@ static unsigned long
copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
{
unsigned long offset, addr = (unsigned long)from;
- int type = in_nmi() ? KM_NMI : KM_IRQ0;
unsigned long size, len = 0;
struct page *page;
void *map;
@@ -63,9 +62,9 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
offset = addr & (PAGE_SIZE - 1);
size = min(PAGE_SIZE - offset, n - len);
- map = kmap_atomic(page, type);
+ map = kmap_atomic(page);
memcpy(to, map+offset, size);
- kunmap_atomic(map, type);
+ kunmap_atomic(map);
put_page(page);
len += size;
@@ -238,6 +237,7 @@ struct x86_pmu {
* Intel DebugStore bits
*/
int bts, pebs;
+ int bts_active, pebs_active;
int pebs_record_size;
void (*drain_pebs)(struct pt_regs *regs);
struct event_constraint *pebs_constraints;
@@ -381,7 +381,7 @@ static void release_pmc_hardware(void) {}
#endif
-static int reserve_ds_buffers(void);
+static void reserve_ds_buffers(void);
static void release_ds_buffers(void);
static void hw_perf_event_destroy(struct perf_event *event)
@@ -478,7 +478,7 @@ static int x86_setup_perfctr(struct perf_event *event)
if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
(hwc->sample_period == 1)) {
/* BTS is not supported by this architecture. */
- if (!x86_pmu.bts)
+ if (!x86_pmu.bts_active)
return -EOPNOTSUPP;
/* BTS is currently only allowed for user-mode. */
@@ -497,12 +497,13 @@ static int x86_pmu_hw_config(struct perf_event *event)
int precise = 0;
/* Support for constant skid */
- if (x86_pmu.pebs)
+ if (x86_pmu.pebs_active) {
precise++;
- /* Support for IP fixup */
- if (x86_pmu.lbr_nr)
- precise++;
+ /* Support for IP fixup */
+ if (x86_pmu.lbr_nr)
+ precise++;
+ }
if (event->attr.precise_ip > precise)
return -EOPNOTSUPP;
@@ -544,11 +545,8 @@ static int __x86_pmu_event_init(struct perf_event *event)
if (atomic_read(&active_events) == 0) {
if (!reserve_pmc_hardware())
err = -EBUSY;
- else {
- err = reserve_ds_buffers();
- if (err)
- release_pmc_hardware();
- }
+ else
+ reserve_ds_buffers();
}
if (!err)
atomic_inc(&active_events);
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index 4977f9c400e5..b7dcd9f2b8a0 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -74,6 +74,107 @@ static void fini_debug_store_on_cpu(int cpu)
wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0);
}
+static int alloc_pebs_buffer(int cpu)
+{
+ struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+ int node = cpu_to_node(cpu);
+ int max, thresh = 1; /* always use a single PEBS record */
+ void *buffer;
+
+ if (!x86_pmu.pebs)
+ return 0;
+
+ buffer = kmalloc_node(PEBS_BUFFER_SIZE, GFP_KERNEL | __GFP_ZERO, node);
+ if (unlikely(!buffer))
+ return -ENOMEM;
+
+ max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size;
+
+ ds->pebs_buffer_base = (u64)(unsigned long)buffer;
+ ds->pebs_index = ds->pebs_buffer_base;
+ ds->pebs_absolute_maximum = ds->pebs_buffer_base +
+ max * x86_pmu.pebs_record_size;
+
+ ds->pebs_interrupt_threshold = ds->pebs_buffer_base +
+ thresh * x86_pmu.pebs_record_size;
+
+ return 0;
+}
+
+static void release_pebs_buffer(int cpu)
+{
+ struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+
+ if (!ds || !x86_pmu.pebs)
+ return;
+
+ kfree((void *)(unsigned long)ds->pebs_buffer_base);
+ ds->pebs_buffer_base = 0;
+}
+
+static int alloc_bts_buffer(int cpu)
+{
+ struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+ int node = cpu_to_node(cpu);
+ int max, thresh;
+ void *buffer;
+
+ if (!x86_pmu.bts)
+ return 0;
+
+ buffer = kmalloc_node(BTS_BUFFER_SIZE, GFP_KERNEL | __GFP_ZERO, node);
+ if (unlikely(!buffer))
+ return -ENOMEM;
+
+ max = BTS_BUFFER_SIZE / BTS_RECORD_SIZE;
+ thresh = max / 16;
+
+ ds->bts_buffer_base = (u64)(unsigned long)buffer;
+ ds->bts_index = ds->bts_buffer_base;
+ ds->bts_absolute_maximum = ds->bts_buffer_base +
+ max * BTS_RECORD_SIZE;
+ ds->bts_interrupt_threshold = ds->bts_absolute_maximum -
+ thresh * BTS_RECORD_SIZE;
+
+ return 0;
+}
+
+static void release_bts_buffer(int cpu)
+{
+ struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+
+ if (!ds || !x86_pmu.bts)
+ return;
+
+ kfree((void *)(unsigned long)ds->bts_buffer_base);
+ ds->bts_buffer_base = 0;
+}
+
+static int alloc_ds_buffer(int cpu)
+{
+ int node = cpu_to_node(cpu);
+ struct debug_store *ds;
+
+ ds = kmalloc_node(sizeof(*ds), GFP_KERNEL | __GFP_ZERO, node);
+ if (unlikely(!ds))
+ return -ENOMEM;
+
+ per_cpu(cpu_hw_events, cpu).ds = ds;
+
+ return 0;
+}
+
+static void release_ds_buffer(int cpu)
+{
+ struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+
+ if (!ds)
+ return;
+
+ per_cpu(cpu_hw_events, cpu).ds = NULL;
+ kfree(ds);
+}
+
static void release_ds_buffers(void)
{
int cpu;
@@ -82,93 +183,77 @@ static void release_ds_buffers(void)
return;
get_online_cpus();
-
for_each_online_cpu(cpu)
fini_debug_store_on_cpu(cpu);
for_each_possible_cpu(cpu) {
- struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
-
- if (!ds)
- continue;
-
- per_cpu(cpu_hw_events, cpu).ds = NULL;
-
- kfree((void *)(unsigned long)ds->pebs_buffer_base);
- kfree((void *)(unsigned long)ds->bts_buffer_base);
- kfree(ds);
+ release_pebs_buffer(cpu);
+ release_bts_buffer(cpu);
+ release_ds_buffer(cpu);
}
-
put_online_cpus();
}
-static int reserve_ds_buffers(void)
+static void reserve_ds_buffers(void)
{
- int cpu, err = 0;
+ int bts_err = 0, pebs_err = 0;
+ int cpu;
+
+ x86_pmu.bts_active = 0;
+ x86_pmu.pebs_active = 0;
if (!x86_pmu.bts && !x86_pmu.pebs)
- return 0;
+ return;
+
+ if (!x86_pmu.bts)
+ bts_err = 1;
+
+ if (!x86_pmu.pebs)
+ pebs_err = 1;
get_online_cpus();
for_each_possible_cpu(cpu) {
- struct debug_store *ds;
- void *buffer;
- int max, thresh;
+ if (alloc_ds_buffer(cpu)) {
+ bts_err = 1;
+ pebs_err = 1;
+ }
+
+ if (!bts_err && alloc_bts_buffer(cpu))
+ bts_err = 1;
- err = -ENOMEM;
- ds = kzalloc(sizeof(*ds), GFP_KERNEL);
- if (unlikely(!ds))
+ if (!pebs_err && alloc_pebs_buffer(cpu))
+ pebs_err = 1;
+
+ if (bts_err && pebs_err)
break;
- per_cpu(cpu_hw_events, cpu).ds = ds;
-
- if (x86_pmu.bts) {
- buffer = kzalloc(BTS_BUFFER_SIZE, GFP_KERNEL);
- if (unlikely(!buffer))
- break;
-
- max = BTS_BUFFER_SIZE / BTS_RECORD_SIZE;
- thresh = max / 16;
-
- ds->bts_buffer_base = (u64)(unsigned long)buffer;
- ds->bts_index = ds->bts_buffer_base;
- ds->bts_absolute_maximum = ds->bts_buffer_base +
- max * BTS_RECORD_SIZE;
- ds->bts_interrupt_threshold = ds->bts_absolute_maximum -
- thresh * BTS_RECORD_SIZE;
- }
+ }
- if (x86_pmu.pebs) {
- buffer = kzalloc(PEBS_BUFFER_SIZE, GFP_KERNEL);
- if (unlikely(!buffer))
- break;
-
- max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size;
-
- ds->pebs_buffer_base = (u64)(unsigned long)buffer;
- ds->pebs_index = ds->pebs_buffer_base;
- ds->pebs_absolute_maximum = ds->pebs_buffer_base +
- max * x86_pmu.pebs_record_size;
- /*
- * Always use single record PEBS
- */
- ds->pebs_interrupt_threshold = ds->pebs_buffer_base +
- x86_pmu.pebs_record_size;
- }
+ if (bts_err) {
+ for_each_possible_cpu(cpu)
+ release_bts_buffer(cpu);
+ }
- err = 0;
+ if (pebs_err) {
+ for_each_possible_cpu(cpu)
+ release_pebs_buffer(cpu);
}
- if (err)
- release_ds_buffers();
- else {
+ if (bts_err && pebs_err) {
+ for_each_possible_cpu(cpu)
+ release_ds_buffer(cpu);
+ } else {
+ if (x86_pmu.bts && !bts_err)
+ x86_pmu.bts_active = 1;
+
+ if (x86_pmu.pebs && !pebs_err)
+ x86_pmu.pebs_active = 1;
+
for_each_online_cpu(cpu)
init_debug_store_on_cpu(cpu);
}
put_online_cpus();
-
- return err;
}
/*
@@ -233,7 +318,7 @@ static int intel_pmu_drain_bts_buffer(void)
if (!event)
return 0;
- if (!ds)
+ if (!x86_pmu.bts_active)
return 0;
at = (struct bts_record *)(unsigned long)ds->bts_buffer_base;
@@ -503,7 +588,7 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
struct pebs_record_core *at, *top;
int n;
- if (!ds || !x86_pmu.pebs)
+ if (!x86_pmu.pebs_active)
return;
at = (struct pebs_record_core *)(unsigned long)ds->pebs_buffer_base;
@@ -545,7 +630,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
u64 status = 0;
int bit, n;
- if (!ds || !x86_pmu.pebs)
+ if (!x86_pmu.pebs_active)
return;
at = (struct pebs_record_nhm *)(unsigned long)ds->pebs_buffer_base;
@@ -630,9 +715,8 @@ static void intel_ds_init(void)
#else /* CONFIG_CPU_SUP_INTEL */
-static int reserve_ds_buffers(void)
+static void reserve_ds_buffers(void)
{
- return 0;
}
static void release_ds_buffers(void)
diff --git a/arch/x86/kernel/crash_dump_32.c b/arch/x86/kernel/crash_dump_32.c
index 67414550c3cc..d5cd13945d5a 100644
--- a/arch/x86/kernel/crash_dump_32.c
+++ b/arch/x86/kernel/crash_dump_32.c
@@ -61,7 +61,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
if (!is_crashed_pfn_valid(pfn))
return -EFAULT;
- vaddr = kmap_atomic_pfn(pfn, KM_PTE0);
+ vaddr = kmap_atomic_pfn(pfn);
if (!userbuf) {
memcpy(buf, (vaddr + offset), csize);
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index 0f6376ffa2d9..1bc7f75a5bda 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -82,11 +82,11 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
if (kstack_end(stack))
break;
if (i && ((i % STACKSLOTS_PER_LINE) == 0))
- printk("\n%s", log_lvl);
- printk(" %08lx", *stack++);
+ printk(KERN_CONT "\n");
+ printk(KERN_CONT " %08lx", *stack++);
touch_nmi_watchdog();
}
- printk("\n");
+ printk(KERN_CONT "\n");
show_trace_log_lvl(task, regs, sp, bp, log_lvl);
}
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index 57a21f11c791..6a340485249a 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -265,20 +265,20 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
if (stack >= irq_stack && stack <= irq_stack_end) {
if (stack == irq_stack_end) {
stack = (unsigned long *) (irq_stack_end[-1]);
- printk(" <EOI> ");
+ printk(KERN_CONT " <EOI> ");
}
} else {
if (((long) stack & (THREAD_SIZE-1)) == 0)
break;
}
if (i && ((i % STACKSLOTS_PER_LINE) == 0))
- printk("\n%s", log_lvl);
- printk(" %016lx", *stack++);
+ printk(KERN_CONT "\n");
+ printk(KERN_CONT " %016lx", *stack++);
touch_nmi_watchdog();
}
preempt_enable();
- printk("\n");
+ printk(KERN_CONT "\n");
show_trace_log_lvl(task, regs, sp, bp, log_lvl);
}
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 9fb188d7bc76..59e175e89599 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -382,20 +382,20 @@ sysenter_past_esp:
* enough kernel state to call TRACE_IRQS_OFF can be called - but
* we immediately enable interrupts at that point anyway.
*/
- pushl_cfi $(__USER_DS)
+ pushl_cfi $__USER_DS
/*CFI_REL_OFFSET ss, 0*/
pushl_cfi %ebp
CFI_REL_OFFSET esp, 0
pushfl_cfi
orl $X86_EFLAGS_IF, (%esp)
- pushl_cfi $(__USER_CS)
+ pushl_cfi $__USER_CS
/*CFI_REL_OFFSET cs, 0*/
/*
* Push current_thread_info()->sysenter_return to the stack.
* A tiny bit of offset fixup is necessary - 4*4 means the 4 words
* pushed above; +8 corresponds to copy_thread's esp0 setting.
*/
- pushl_cfi (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp)
+ pushl_cfi (TI_sysenter_return-THREAD_SIZE_asm+8+4*4)(%esp)
CFI_REL_OFFSET eip, 0
pushl_cfi %eax
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index a7ae7fd1010f..fe2690d71c0c 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -963,22 +963,10 @@ apicinterrupt X86_PLATFORM_IPI_VECTOR \
x86_platform_ipi smp_x86_platform_ipi
#ifdef CONFIG_SMP
-apicinterrupt INVALIDATE_TLB_VECTOR_START+0 \
- invalidate_interrupt0 smp_invalidate_interrupt
-apicinterrupt INVALIDATE_TLB_VECTOR_START+1 \
- invalidate_interrupt1 smp_invalidate_interrupt
-apicinterrupt INVALIDATE_TLB_VECTOR_START+2 \
- invalidate_interrupt2 smp_invalidate_interrupt
-apicinterrupt INVALIDATE_TLB_VECTOR_START+3 \
- invalidate_interrupt3 smp_invalidate_interrupt
-apicinterrupt INVALIDATE_TLB_VECTOR_START+4 \
- invalidate_interrupt4 smp_invalidate_interrupt
-apicinterrupt INVALIDATE_TLB_VECTOR_START+5 \
- invalidate_interrupt5 smp_invalidate_interrupt
-apicinterrupt INVALIDATE_TLB_VECTOR_START+6 \
- invalidate_interrupt6 smp_invalidate_interrupt
-apicinterrupt INVALIDATE_TLB_VECTOR_START+7 \
- invalidate_interrupt7 smp_invalidate_interrupt
+.irpc idx, "01234567"
+apicinterrupt (INVALIDATE_TLB_VECTOR_START)+\idx \
+ invalidate_interrupt\idx smp_invalidate_interrupt
+.endr
#endif
apicinterrupt THRESHOLD_APIC_VECTOR \
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index aff0b3c27509..ae03cab4352e 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -713,7 +713,7 @@ static int hpet_cpuhp_notify(struct notifier_block *n,
switch (action & 0xf) {
case CPU_ONLINE:
- INIT_DELAYED_WORK_ON_STACK(&work.work, hpet_work);
+ INIT_DELAYED_WORK_ONSTACK(&work.work, hpet_work);
init_completion(&work.complete);
/* FIXME: add schedule_work_on() */
schedule_delayed_work_on(cpu, &work.work, 0);
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c
index 50fbbe60e507..64668dbf00a4 100644
--- a/arch/x86/kernel/irq_32.c
+++ b/arch/x86/kernel/irq_32.c
@@ -60,9 +60,6 @@ union irq_ctx {
static DEFINE_PER_CPU(union irq_ctx *, hardirq_ctx);
static DEFINE_PER_CPU(union irq_ctx *, softirq_ctx);
-static DEFINE_PER_CPU_MULTIPAGE_ALIGNED(union irq_ctx, hardirq_stack, THREAD_SIZE);
-static DEFINE_PER_CPU_MULTIPAGE_ALIGNED(union irq_ctx, softirq_stack, THREAD_SIZE);
-
static void call_on_stack(void *func, void *stack)
{
asm volatile("xchgl %%ebx,%%esp \n"
@@ -128,7 +125,7 @@ void __cpuinit irq_ctx_init(int cpu)
if (per_cpu(hardirq_ctx, cpu))
return;
- irqctx = &per_cpu(hardirq_stack, cpu);
+ irqctx = (union irq_ctx *)__get_free_pages(THREAD_FLAGS, THREAD_ORDER);
irqctx->tinfo.task = NULL;
irqctx->tinfo.exec_domain = NULL;
irqctx->tinfo.cpu = cpu;
@@ -137,7 +134,7 @@ void __cpuinit irq_ctx_init(int cpu)
per_cpu(hardirq_ctx, cpu) = irqctx;
- irqctx = &per_cpu(softirq_stack, cpu);
+ irqctx = (union irq_ctx *)__get_free_pages(THREAD_FLAGS, THREAD_ORDER);
irqctx->tinfo.task = NULL;
irqctx->tinfo.exec_domain = NULL;
irqctx->tinfo.cpu = cpu;
@@ -150,11 +147,6 @@ void __cpuinit irq_ctx_init(int cpu)
cpu, per_cpu(hardirq_ctx, cpu), per_cpu(softirq_ctx, cpu));
}
-void irq_ctx_exit(int cpu)
-{
- per_cpu(hardirq_ctx, cpu) = NULL;
-}
-
asmlinkage void do_softirq(void)
{
unsigned long flags;
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
index eb9b76c716c2..ca43ce31a19c 100644
--- a/arch/x86/kernel/kvmclock.c
+++ b/arch/x86/kernel/kvmclock.c
@@ -128,13 +128,15 @@ static struct clocksource kvm_clock = {
static int kvm_register_clock(char *txt)
{
int cpu = smp_processor_id();
- int low, high;
+ int low, high, ret;
+
low = (int)__pa(&per_cpu(hv_clock, cpu)) | 1;
high = ((u64)__pa(&per_cpu(hv_clock, cpu)) >> 32);
+ ret = native_write_msr_safe(msr_kvm_system_time, low, high);
printk(KERN_INFO "kvm-clock: cpu %d, msr %x:%x, %s\n",
cpu, high, low, txt);
- return native_write_msr_safe(msr_kvm_system_time, low, high);
+ return ret;
}
#ifdef CONFIG_X86_LOCAL_APIC
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
index 0b3d37e83606..1cca374a2bac 100644
--- a/arch/x86/kernel/microcode_core.c
+++ b/arch/x86/kernel/microcode_core.c
@@ -12,7 +12,7 @@
* Software Developer's Manual
* Order Number 253668 or free download from:
*
- * http://developer.intel.com/design/pentium4/manuals/253668.htm
+ * http://developer.intel.com/Assets/PDF/manual/253668.pdf
*
* For more information, go to http://www.urbanmyth.org/microcode
*
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c
index 356170262a93..dcb65cc0a053 100644
--- a/arch/x86/kernel/microcode_intel.c
+++ b/arch/x86/kernel/microcode_intel.c
@@ -12,7 +12,7 @@
* Software Developer's Manual
* Order Number 253668 or free download from:
*
- * http://developer.intel.com/design/pentium4/manuals/253668.htm
+ * http://developer.intel.com/Assets/PDF/manual/253668.pdf
*
* For more information, go to http://www.urbanmyth.org/microcode
*
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 70c4872cd8aa..45892dc4b72a 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -801,7 +801,8 @@ void ptrace_disable(struct task_struct *child)
static const struct user_regset_view user_x86_32_view; /* Initialized below. */
#endif
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret;
unsigned long __user *datap = (unsigned long __user *)data;
@@ -812,8 +813,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
unsigned long tmp;
ret = -EIO;
- if ((addr & (sizeof(data) - 1)) || addr < 0 ||
- addr >= sizeof(struct user))
+ if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user))
break;
tmp = 0; /* Default return condition */
@@ -830,8 +830,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
ret = -EIO;
- if ((addr & (sizeof(data) - 1)) || addr < 0 ||
- addr >= sizeof(struct user))
+ if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user))
break;
if (addr < sizeof(struct user_regs_struct))
@@ -888,17 +887,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
case PTRACE_GET_THREAD_AREA:
- if (addr < 0)
+ if ((int) addr < 0)
return -EIO;
ret = do_get_thread_area(child, addr,
- (struct user_desc __user *) data);
+ (struct user_desc __user *)data);
break;
case PTRACE_SET_THREAD_AREA:
- if (addr < 0)
+ if ((int) addr < 0)
return -EIO;
ret = do_set_thread_area(child, addr,
- (struct user_desc __user *) data, 0);
+ (struct user_desc __user *)data, 0);
break;
#endif
diff --git a/arch/x86/kernel/pvclock.c b/arch/x86/kernel/pvclock.c
index 239427ca02af..bab3b9e6f66d 100644
--- a/arch/x86/kernel/pvclock.c
+++ b/arch/x86/kernel/pvclock.c
@@ -82,7 +82,8 @@ static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
static u64 pvclock_get_nsec_offset(struct pvclock_shadow_time *shadow)
{
u64 delta = native_read_tsc() - shadow->tsc_timestamp;
- return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
+ return pvclock_scale_delta(delta, shadow->tsc_to_nsec_mul,
+ shadow->tsc_shift);
}
/*
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
index 939b9e98245f..8bbe8c56916d 100644
--- a/arch/x86/kernel/quirks.c
+++ b/arch/x86/kernel/quirks.c
@@ -344,6 +344,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235,
vt8237_force_enable_hpet);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237,
vt8237_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700,
+ vt8237_force_enable_hpet);
static void ati_force_hpet_resume(void)
{
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index f7f53dcd3e0a..c495aa8d4815 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -635,7 +635,7 @@ void native_machine_shutdown(void)
/* O.K Now that I'm on the appropriate processor,
* stop all of the others.
*/
- smp_send_stop();
+ stop_other_cpus();
#endif
lapic_shutdown();
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index d801210945d6..513deac7228d 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -159,10 +159,10 @@ asmlinkage void smp_reboot_interrupt(void)
irq_exit();
}
-static void native_smp_send_stop(void)
+static void native_stop_other_cpus(int wait)
{
unsigned long flags;
- unsigned long wait;
+ unsigned long timeout;
if (reboot_force)
return;
@@ -179,9 +179,12 @@ static void native_smp_send_stop(void)
if (num_online_cpus() > 1) {
apic->send_IPI_allbutself(REBOOT_VECTOR);
- /* Don't wait longer than a second */
- wait = USEC_PER_SEC;
- while (num_online_cpus() > 1 && wait--)
+ /*
+ * Don't wait longer than a second if the caller
+ * didn't ask us to wait.
+ */
+ timeout = USEC_PER_SEC;
+ while (num_online_cpus() > 1 && (wait || timeout--))
udelay(1);
}
@@ -227,7 +230,7 @@ struct smp_ops smp_ops = {
.smp_prepare_cpus = native_smp_prepare_cpus,
.smp_cpus_done = native_smp_cpus_done,
- .smp_send_stop = native_smp_send_stop,
+ .stop_other_cpus = native_stop_other_cpus,
.smp_send_reschedule = native_smp_send_reschedule,
.cpu_up = native_cpu_up,
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 6af118511b4a..083e99d1b7df 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -747,7 +747,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
.done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
};
- INIT_WORK_ON_STACK(&c_idle.work, do_fork_idle);
+ INIT_WORK_ONSTACK(&c_idle.work, do_fork_idle);
alternatives_smp_switch(1);
@@ -1373,7 +1373,6 @@ void play_dead_common(void)
{
idle_task_exit();
reset_lazy_tlbstate();
- irq_ctx_exit(raw_smp_processor_id());
c1e_remove_cpu(raw_smp_processor_id());
mb();
diff --git a/arch/x86/kernel/tlb_uv.c b/arch/x86/kernel/tlb_uv.c
index 50ac949c7f1c..20ea20a39e2a 100644
--- a/arch/x86/kernel/tlb_uv.c
+++ b/arch/x86/kernel/tlb_uv.c
@@ -1001,10 +1001,10 @@ static int uv_ptc_seq_show(struct seq_file *file, void *data)
static ssize_t tunables_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
- char buf[300];
+ char *buf;
int ret;
- ret = snprintf(buf, 300, "%s %s %s\n%d %d %d %d %d %d %d %d %d\n",
+ buf = kasprintf(GFP_KERNEL, "%s %s %s\n%d %d %d %d %d %d %d %d %d\n",
"max_bau_concurrent plugged_delay plugsb4reset",
"timeoutsb4reset ipi_reset_limit complete_threshold",
"congested_response_us congested_reps congested_period",
@@ -1012,7 +1012,12 @@ static ssize_t tunables_read(struct file *file, char __user *userbuf,
timeoutsb4reset, ipi_reset_limit, complete_threshold,
congested_response_us, congested_reps, congested_period);
- return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
+ kfree(buf);
+ return ret;
}
/*
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index d43968503dd2..cb838ca42c96 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -575,6 +575,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
if (regs->flags & X86_VM_MASK) {
handle_vm86_trap((struct kernel_vm86_regs *) regs,
error_code, 1);
+ preempt_conditional_cli(regs);
return;
}
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
index 5ffb5622f793..61fb98519622 100644
--- a/arch/x86/kernel/vm86_32.c
+++ b/arch/x86/kernel/vm86_32.c
@@ -551,8 +551,14 @@ cannot_handle:
int handle_vm86_trap(struct kernel_vm86_regs *regs, long error_code, int trapno)
{
if (VMPI.is_vm86pus) {
- if ((trapno == 3) || (trapno == 1))
- return_to_32bit(regs, VM86_TRAP + (trapno << 8));
+ if ((trapno == 3) || (trapno == 1)) {
+ KVM86->regs32->ax = VM86_TRAP + (trapno << 8);
+ /* setting this flag forces the code in entry_32.S to
+ call save_v86_state() and change the stack pointer
+ to KVM86->regs32 */
+ set_thread_flag(TIF_IRET);
+ return 0;
+ }
do_int(regs, trapno, (unsigned char __user *) (regs->pt.ss << 4), SP(regs));
return 0;
}
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index 970bbd479516..ddc131ff438f 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -64,6 +64,13 @@ config KVM_AMD
To compile this as a module, choose M here: the module
will be called kvm-amd.
+config KVM_MMU_AUDIT
+ bool "Audit KVM MMU"
+ depends on KVM && TRACEPOINTS
+ ---help---
+ This option adds a R/W kVM module parameter 'mmu_audit', which allows
+ audit KVM MMU at runtime.
+
# OK, it's a little counter-intuitive to do this, but it puts it neatly under
# the virtualization menu.
source drivers/vhost/Kconfig
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 66ca98aafdd6..38b6e8dafaff 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -9,7 +9,7 @@
* privileged instructions:
*
* Copyright (C) 2006 Qumranet
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
*
* Avi Kivity <avi@qumranet.com>
* Yaniv Kamay <yaniv@qumranet.com>
@@ -51,13 +51,13 @@
#define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */
#define DstReg (2<<1) /* Register operand. */
#define DstMem (3<<1) /* Memory operand. */
-#define DstAcc (4<<1) /* Destination Accumulator */
+#define DstAcc (4<<1) /* Destination Accumulator */
#define DstDI (5<<1) /* Destination is in ES:(E)DI */
#define DstMem64 (6<<1) /* 64bit memory operand */
+#define DstImmUByte (7<<1) /* 8-bit unsigned immediate operand */
#define DstMask (7<<1)
/* Source operand type. */
#define SrcNone (0<<4) /* No source operand. */
-#define SrcImplicit (0<<4) /* Source operand is implicit in the opcode. */
#define SrcReg (1<<4) /* Register operand. */
#define SrcMem (2<<4) /* Memory operand. */
#define SrcMem16 (3<<4) /* Memory operand (16-bit). */
@@ -71,6 +71,7 @@
#define SrcImmFAddr (0xb<<4) /* Source is immediate far address */
#define SrcMemFAddr (0xc<<4) /* Source is far address in memory */
#define SrcAcc (0xd<<4) /* Source Accumulator */
+#define SrcImmU16 (0xe<<4) /* Immediate operand, unsigned, 16 bits */
#define SrcMask (0xf<<4)
/* Generic ModRM decode. */
#define ModRM (1<<8)
@@ -82,8 +83,10 @@
#define Stack (1<<13) /* Stack instruction (push/pop) */
#define Group (1<<14) /* Bits 3:5 of modrm byte extend opcode */
#define GroupDual (1<<15) /* Alternate decoding of mod == 3 */
-#define GroupMask 0xff /* Group number stored in bits 0:7 */
/* Misc flags */
+#define NoAccess (1<<23) /* Don't access memory (lea/invlpg/verr etc) */
+#define Op3264 (1<<24) /* Operand is 64b in long mode, 32b otherwise */
+#define Undefined (1<<25) /* No Such Instruction */
#define Lock (1<<26) /* lock prefix is allowed for the instruction */
#define Priv (1<<27) /* instruction generates #GP if current CPL != 0 */
#define No64 (1<<28)
@@ -92,285 +95,30 @@
#define Src2CL (1<<29)
#define Src2ImmByte (2<<29)
#define Src2One (3<<29)
+#define Src2Imm (4<<29)
#define Src2Mask (7<<29)
-enum {
- Group1_80, Group1_81, Group1_82, Group1_83,
- Group1A, Group3_Byte, Group3, Group4, Group5, Group7,
- Group8, Group9,
+#define X2(x...) x, x
+#define X3(x...) X2(x), x
+#define X4(x...) X2(x), X2(x)
+#define X5(x...) X4(x), x
+#define X6(x...) X4(x), X2(x)
+#define X7(x...) X4(x), X3(x)
+#define X8(x...) X4(x), X4(x)
+#define X16(x...) X8(x), X8(x)
+
+struct opcode {
+ u32 flags;
+ union {
+ int (*execute)(struct x86_emulate_ctxt *ctxt);
+ struct opcode *group;
+ struct group_dual *gdual;
+ } u;
};
-static u32 opcode_table[256] = {
- /* 0x00 - 0x07 */
- ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
- ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
- ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
- /* 0x08 - 0x0F */
- ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
- ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
- ImplicitOps | Stack | No64, 0,
- /* 0x10 - 0x17 */
- ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
- ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
- ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
- /* 0x18 - 0x1F */
- ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
- ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
- ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
- /* 0x20 - 0x27 */
- ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
- ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- ByteOp | DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0,
- /* 0x28 - 0x2F */
- ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
- ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- ByteOp | DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0,
- /* 0x30 - 0x37 */
- ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
- ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- ByteOp | DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0,
- /* 0x38 - 0x3F */
- ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
- ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
- 0, 0,
- /* 0x40 - 0x47 */
- DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
- /* 0x48 - 0x4F */
- DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
- /* 0x50 - 0x57 */
- SrcReg | Stack, SrcReg | Stack, SrcReg | Stack, SrcReg | Stack,
- SrcReg | Stack, SrcReg | Stack, SrcReg | Stack, SrcReg | Stack,
- /* 0x58 - 0x5F */
- DstReg | Stack, DstReg | Stack, DstReg | Stack, DstReg | Stack,
- DstReg | Stack, DstReg | Stack, DstReg | Stack, DstReg | Stack,
- /* 0x60 - 0x67 */
- ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
- 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
- 0, 0, 0, 0,
- /* 0x68 - 0x6F */
- SrcImm | Mov | Stack, 0, SrcImmByte | Mov | Stack, 0,
- DstDI | ByteOp | Mov | String, DstDI | Mov | String, /* insb, insw/insd */
- SrcSI | ByteOp | ImplicitOps | String, SrcSI | ImplicitOps | String, /* outsb, outsw/outsd */
- /* 0x70 - 0x77 */
- SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
- SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
- /* 0x78 - 0x7F */
- SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
- SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
- /* 0x80 - 0x87 */
- Group | Group1_80, Group | Group1_81,
- Group | Group1_82, Group | Group1_83,
- ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
- ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
- /* 0x88 - 0x8F */
- ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov,
- ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
- DstMem | SrcNone | ModRM | Mov, ModRM | DstReg,
- ImplicitOps | SrcMem16 | ModRM, Group | Group1A,
- /* 0x90 - 0x97 */
- DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
- /* 0x98 - 0x9F */
- 0, 0, SrcImmFAddr | No64, 0,
- ImplicitOps | Stack, ImplicitOps | Stack, 0, 0,
- /* 0xA0 - 0xA7 */
- ByteOp | DstAcc | SrcMem | Mov | MemAbs, DstAcc | SrcMem | Mov | MemAbs,
- ByteOp | DstMem | SrcAcc | Mov | MemAbs, DstMem | SrcAcc | Mov | MemAbs,
- ByteOp | SrcSI | DstDI | Mov | String, SrcSI | DstDI | Mov | String,
- ByteOp | SrcSI | DstDI | String, SrcSI | DstDI | String,
- /* 0xA8 - 0xAF */
- DstAcc | SrcImmByte | ByteOp, DstAcc | SrcImm, ByteOp | DstDI | Mov | String, DstDI | Mov | String,
- ByteOp | SrcSI | DstAcc | Mov | String, SrcSI | DstAcc | Mov | String,
- ByteOp | DstDI | String, DstDI | String,
- /* 0xB0 - 0xB7 */
- ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
- ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
- ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
- ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
- /* 0xB8 - 0xBF */
- DstReg | SrcImm | Mov, DstReg | SrcImm | Mov,
- DstReg | SrcImm | Mov, DstReg | SrcImm | Mov,
- DstReg | SrcImm | Mov, DstReg | SrcImm | Mov,
- DstReg | SrcImm | Mov, DstReg | SrcImm | Mov,
- /* 0xC0 - 0xC7 */
- ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM,
- 0, ImplicitOps | Stack, 0, 0,
- ByteOp | DstMem | SrcImm | ModRM | Mov, DstMem | SrcImm | ModRM | Mov,
- /* 0xC8 - 0xCF */
- 0, 0, 0, ImplicitOps | Stack,
- ImplicitOps, SrcImmByte, ImplicitOps | No64, ImplicitOps,
- /* 0xD0 - 0xD7 */
- ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
- ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
- 0, 0, 0, 0,
- /* 0xD8 - 0xDF */
- 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xE0 - 0xE7 */
- 0, 0, 0, 0,
- ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
- ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
- /* 0xE8 - 0xEF */
- SrcImm | Stack, SrcImm | ImplicitOps,
- SrcImmFAddr | No64, SrcImmByte | ImplicitOps,
- SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
- SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
- /* 0xF0 - 0xF7 */
- 0, 0, 0, 0,
- ImplicitOps | Priv, ImplicitOps, Group | Group3_Byte, Group | Group3,
- /* 0xF8 - 0xFF */
- ImplicitOps, 0, ImplicitOps, ImplicitOps,
- ImplicitOps, ImplicitOps, Group | Group4, Group | Group5,
-};
-
-static u32 twobyte_table[256] = {
- /* 0x00 - 0x0F */
- 0, Group | GroupDual | Group7, 0, 0,
- 0, ImplicitOps, ImplicitOps | Priv, 0,
- ImplicitOps | Priv, ImplicitOps | Priv, 0, 0,
- 0, ImplicitOps | ModRM, 0, 0,
- /* 0x10 - 0x1F */
- 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0,
- /* 0x20 - 0x2F */
- ModRM | ImplicitOps | Priv, ModRM | Priv,
- ModRM | ImplicitOps | Priv, ModRM | Priv,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x30 - 0x3F */
- ImplicitOps | Priv, 0, ImplicitOps | Priv, 0,
- ImplicitOps, ImplicitOps | Priv, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x40 - 0x47 */
- DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
- DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
- DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
- DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
- /* 0x48 - 0x4F */
- DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
- DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
- DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
- DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
- /* 0x50 - 0x5F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x60 - 0x6F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x70 - 0x7F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x80 - 0x8F */
- SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm,
- SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm,
- /* 0x90 - 0x9F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xA0 - 0xA7 */
- ImplicitOps | Stack, ImplicitOps | Stack,
- 0, DstMem | SrcReg | ModRM | BitOp,
- DstMem | SrcReg | Src2ImmByte | ModRM,
- DstMem | SrcReg | Src2CL | ModRM, 0, 0,
- /* 0xA8 - 0xAF */
- ImplicitOps | Stack, ImplicitOps | Stack,
- 0, DstMem | SrcReg | ModRM | BitOp | Lock,
- DstMem | SrcReg | Src2ImmByte | ModRM,
- DstMem | SrcReg | Src2CL | ModRM,
- ModRM, 0,
- /* 0xB0 - 0xB7 */
- ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
- 0, DstMem | SrcReg | ModRM | BitOp | Lock,
- 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
- DstReg | SrcMem16 | ModRM | Mov,
- /* 0xB8 - 0xBF */
- 0, 0,
- Group | Group8, DstMem | SrcReg | ModRM | BitOp | Lock,
- 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
- DstReg | SrcMem16 | ModRM | Mov,
- /* 0xC0 - 0xCF */
- 0, 0, 0, DstMem | SrcReg | ModRM | Mov,
- 0, 0, 0, Group | GroupDual | Group9,
- 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xD0 - 0xDF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xE0 - 0xEF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xF0 - 0xFF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-static u32 group_table[] = {
- [Group1_80*8] =
- ByteOp | DstMem | SrcImm | ModRM | Lock,
- ByteOp | DstMem | SrcImm | ModRM | Lock,
- ByteOp | DstMem | SrcImm | ModRM | Lock,
- ByteOp | DstMem | SrcImm | ModRM | Lock,
- ByteOp | DstMem | SrcImm | ModRM | Lock,
- ByteOp | DstMem | SrcImm | ModRM | Lock,
- ByteOp | DstMem | SrcImm | ModRM | Lock,
- ByteOp | DstMem | SrcImm | ModRM,
- [Group1_81*8] =
- DstMem | SrcImm | ModRM | Lock,
- DstMem | SrcImm | ModRM | Lock,
- DstMem | SrcImm | ModRM | Lock,
- DstMem | SrcImm | ModRM | Lock,
- DstMem | SrcImm | ModRM | Lock,
- DstMem | SrcImm | ModRM | Lock,
- DstMem | SrcImm | ModRM | Lock,
- DstMem | SrcImm | ModRM,
- [Group1_82*8] =
- ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
- ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
- ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
- ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
- ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
- ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
- ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
- ByteOp | DstMem | SrcImm | ModRM | No64,
- [Group1_83*8] =
- DstMem | SrcImmByte | ModRM | Lock,
- DstMem | SrcImmByte | ModRM | Lock,
- DstMem | SrcImmByte | ModRM | Lock,
- DstMem | SrcImmByte | ModRM | Lock,
- DstMem | SrcImmByte | ModRM | Lock,
- DstMem | SrcImmByte | ModRM | Lock,
- DstMem | SrcImmByte | ModRM | Lock,
- DstMem | SrcImmByte | ModRM,
- [Group1A*8] =
- DstMem | SrcNone | ModRM | Mov | Stack, 0, 0, 0, 0, 0, 0, 0,
- [Group3_Byte*8] =
- ByteOp | SrcImm | DstMem | ModRM, ByteOp | SrcImm | DstMem | ModRM,
- ByteOp | DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM,
- 0, 0, 0, 0,
- [Group3*8] =
- DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
- DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
- 0, 0, 0, 0,
- [Group4*8] =
- ByteOp | DstMem | SrcNone | ModRM | Lock, ByteOp | DstMem | SrcNone | ModRM | Lock,
- 0, 0, 0, 0, 0, 0,
- [Group5*8] =
- DstMem | SrcNone | ModRM | Lock, DstMem | SrcNone | ModRM | Lock,
- SrcMem | ModRM | Stack, 0,
- SrcMem | ModRM | Stack, SrcMemFAddr | ModRM | ImplicitOps,
- SrcMem | ModRM | Stack, 0,
- [Group7*8] =
- 0, 0, ModRM | SrcMem | Priv, ModRM | SrcMem | Priv,
- SrcNone | ModRM | DstMem | Mov, 0,
- SrcMem16 | ModRM | Mov | Priv, SrcMem | ModRM | ByteOp | Priv,
- [Group8*8] =
- 0, 0, 0, 0,
- DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM | Lock,
- DstMem | SrcImmByte | ModRM | Lock, DstMem | SrcImmByte | ModRM | Lock,
- [Group9*8] =
- 0, DstMem64 | ModRM | Lock, 0, 0, 0, 0, 0, 0,
-};
-
-static u32 group2_table[] = {
- [Group7*8] =
- SrcNone | ModRM | Priv, 0, 0, SrcNone | ModRM | Priv,
- SrcNone | ModRM | DstMem | Mov, 0,
- SrcMem16 | ModRM | Mov | Priv, 0,
- [Group9*8] =
- 0, 0, 0, 0, 0, 0, 0, 0,
+struct group_dual {
+ struct opcode mod012[8];
+ struct opcode mod3[8];
};
/* EFLAGS bit definitions. */
@@ -392,6 +140,9 @@ static u32 group2_table[] = {
#define EFLG_PF (1<<2)
#define EFLG_CF (1<<0)
+#define EFLG_RESERVED_ZEROS_MASK 0xffc0802a
+#define EFLG_RESERVED_ONE_MASK 2
+
/*
* Instruction emulation:
* Most instructions are emulated directly via a fragment of inline assembly
@@ -444,13 +195,13 @@ static u32 group2_table[] = {
#define ON64(x)
#endif
-#define ____emulate_2op(_op, _src, _dst, _eflags, _x, _y, _suffix) \
+#define ____emulate_2op(_op, _src, _dst, _eflags, _x, _y, _suffix, _dsttype) \
do { \
__asm__ __volatile__ ( \
_PRE_EFLAGS("0", "4", "2") \
_op _suffix " %"_x"3,%1; " \
_POST_EFLAGS("0", "4", "2") \
- : "=m" (_eflags), "=m" ((_dst).val), \
+ : "=m" (_eflags), "+q" (*(_dsttype*)&(_dst).val),\
"=&r" (_tmp) \
: _y ((_src).val), "i" (EFLAGS_MASK)); \
} while (0)
@@ -463,13 +214,13 @@ static u32 group2_table[] = {
\
switch ((_dst).bytes) { \
case 2: \
- ____emulate_2op(_op,_src,_dst,_eflags,_wx,_wy,"w"); \
+ ____emulate_2op(_op,_src,_dst,_eflags,_wx,_wy,"w",u16);\
break; \
case 4: \
- ____emulate_2op(_op,_src,_dst,_eflags,_lx,_ly,"l"); \
+ ____emulate_2op(_op,_src,_dst,_eflags,_lx,_ly,"l",u32);\
break; \
case 8: \
- ON64(____emulate_2op(_op,_src,_dst,_eflags,_qx,_qy,"q")); \
+ ON64(____emulate_2op(_op,_src,_dst,_eflags,_qx,_qy,"q",u64)); \
break; \
} \
} while (0)
@@ -479,7 +230,7 @@ static u32 group2_table[] = {
unsigned long _tmp; \
switch ((_dst).bytes) { \
case 1: \
- ____emulate_2op(_op,_src,_dst,_eflags,_bx,_by,"b"); \
+ ____emulate_2op(_op,_src,_dst,_eflags,_bx,_by,"b",u8); \
break; \
default: \
__emulate_2op_nobyte(_op, _src, _dst, _eflags, \
@@ -566,6 +317,74 @@ static u32 group2_table[] = {
} \
} while (0)
+#define __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, _suffix) \
+ do { \
+ unsigned long _tmp; \
+ \
+ __asm__ __volatile__ ( \
+ _PRE_EFLAGS("0", "4", "1") \
+ _op _suffix " %5; " \
+ _POST_EFLAGS("0", "4", "1") \
+ : "=m" (_eflags), "=&r" (_tmp), \
+ "+a" (_rax), "+d" (_rdx) \
+ : "i" (EFLAGS_MASK), "m" ((_src).val), \
+ "a" (_rax), "d" (_rdx)); \
+ } while (0)
+
+#define __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, _eflags, _suffix, _ex) \
+ do { \
+ unsigned long _tmp; \
+ \
+ __asm__ __volatile__ ( \
+ _PRE_EFLAGS("0", "5", "1") \
+ "1: \n\t" \
+ _op _suffix " %6; " \
+ "2: \n\t" \
+ _POST_EFLAGS("0", "5", "1") \
+ ".pushsection .fixup,\"ax\" \n\t" \
+ "3: movb $1, %4 \n\t" \
+ "jmp 2b \n\t" \
+ ".popsection \n\t" \
+ _ASM_EXTABLE(1b, 3b) \
+ : "=m" (_eflags), "=&r" (_tmp), \
+ "+a" (_rax), "+d" (_rdx), "+qm"(_ex) \
+ : "i" (EFLAGS_MASK), "m" ((_src).val), \
+ "a" (_rax), "d" (_rdx)); \
+ } while (0)
+
+/* instruction has only one source operand, destination is implicit (e.g. mul, div, imul, idiv) */
+#define emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags) \
+ do { \
+ switch((_src).bytes) { \
+ case 1: __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "b"); break; \
+ case 2: __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "w"); break; \
+ case 4: __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "l"); break; \
+ case 8: ON64(__emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "q")); break; \
+ } \
+ } while (0)
+
+#define emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, _eflags, _ex) \
+ do { \
+ switch((_src).bytes) { \
+ case 1: \
+ __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, \
+ _eflags, "b", _ex); \
+ break; \
+ case 2: \
+ __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, \
+ _eflags, "w", _ex); \
+ break; \
+ case 4: \
+ __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, \
+ _eflags, "l", _ex); \
+ break; \
+ case 8: ON64( \
+ __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, \
+ _eflags, "q", _ex)); \
+ break; \
+ } \
+ } while (0)
+
/* Fetch next part of the instruction being emulated. */
#define insn_fetch(_type, _size, _eip) \
({ unsigned long _x; \
@@ -661,7 +480,6 @@ static void emulate_exception(struct x86_emulate_ctxt *ctxt, int vec,
ctxt->exception = vec;
ctxt->error_code = error;
ctxt->error_code_valid = valid;
- ctxt->restart = false;
}
static void emulate_gp(struct x86_emulate_ctxt *ctxt, int err)
@@ -669,11 +487,9 @@ static void emulate_gp(struct x86_emulate_ctxt *ctxt, int err)
emulate_exception(ctxt, GP_VECTOR, err, true);
}
-static void emulate_pf(struct x86_emulate_ctxt *ctxt, unsigned long addr,
- int err)
+static void emulate_pf(struct x86_emulate_ctxt *ctxt)
{
- ctxt->cr2 = addr;
- emulate_exception(ctxt, PF_VECTOR, err, true);
+ emulate_exception(ctxt, PF_VECTOR, 0, true);
}
static void emulate_ud(struct x86_emulate_ctxt *ctxt)
@@ -686,6 +502,12 @@ static void emulate_ts(struct x86_emulate_ctxt *ctxt, int err)
emulate_exception(ctxt, TS_VECTOR, err, true);
}
+static int emulate_de(struct x86_emulate_ctxt *ctxt)
+{
+ emulate_exception(ctxt, DE_VECTOR, 0, false);
+ return X86EMUL_PROPAGATE_FAULT;
+}
+
static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops,
unsigned long eip, u8 *dest)
@@ -742,7 +564,7 @@ static void *decode_register(u8 modrm_reg, unsigned long *regs,
static int read_descriptor(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops,
- void *ptr,
+ ulong addr,
u16 *size, unsigned long *address, int op_bytes)
{
int rc;
@@ -750,12 +572,10 @@ static int read_descriptor(struct x86_emulate_ctxt *ctxt,
if (op_bytes == 2)
op_bytes = 3;
*address = 0;
- rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2,
- ctxt->vcpu, NULL);
+ rc = ops->read_std(addr, (unsigned long *)size, 2, ctxt->vcpu, NULL);
if (rc != X86EMUL_CONTINUE)
return rc;
- rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes,
- ctxt->vcpu, NULL);
+ rc = ops->read_std(addr + 2, address, op_bytes, ctxt->vcpu, NULL);
return rc;
}
@@ -794,6 +614,24 @@ static int test_cc(unsigned int condition, unsigned int flags)
return (!!rc ^ (condition & 1));
}
+static void fetch_register_operand(struct operand *op)
+{
+ switch (op->bytes) {
+ case 1:
+ op->val = *(u8 *)op->addr.reg;
+ break;
+ case 2:
+ op->val = *(u16 *)op->addr.reg;
+ break;
+ case 4:
+ op->val = *(u32 *)op->addr.reg;
+ break;
+ case 8:
+ op->val = *(u64 *)op->addr.reg;
+ break;
+ }
+}
+
static void decode_register_operand(struct operand *op,
struct decode_cache *c,
int inhibit_bytereg)
@@ -805,34 +643,25 @@ static void decode_register_operand(struct operand *op,
reg = (c->b & 7) | ((c->rex_prefix & 1) << 3);
op->type = OP_REG;
if ((c->d & ByteOp) && !inhibit_bytereg) {
- op->ptr = decode_register(reg, c->regs, highbyte_regs);
- op->val = *(u8 *)op->ptr;
+ op->addr.reg = decode_register(reg, c->regs, highbyte_regs);
op->bytes = 1;
} else {
- op->ptr = decode_register(reg, c->regs, 0);
+ op->addr.reg = decode_register(reg, c->regs, 0);
op->bytes = c->op_bytes;
- switch (op->bytes) {
- case 2:
- op->val = *(u16 *)op->ptr;
- break;
- case 4:
- op->val = *(u32 *)op->ptr;
- break;
- case 8:
- op->val = *(u64 *) op->ptr;
- break;
- }
}
+ fetch_register_operand(op);
op->orig_val = op->val;
}
static int decode_modrm(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops)
+ struct x86_emulate_ops *ops,
+ struct operand *op)
{
struct decode_cache *c = &ctxt->decode;
u8 sib;
int index_reg = 0, base_reg = 0, scale;
int rc = X86EMUL_CONTINUE;
+ ulong modrm_ea = 0;
if (c->rex_prefix) {
c->modrm_reg = (c->rex_prefix & 4) << 1; /* REX.R */
@@ -844,16 +673,19 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
c->modrm_mod |= (c->modrm & 0xc0) >> 6;
c->modrm_reg |= (c->modrm & 0x38) >> 3;
c->modrm_rm |= (c->modrm & 0x07);
- c->modrm_ea = 0;
- c->use_modrm_ea = 1;
+ c->modrm_seg = VCPU_SREG_DS;
if (c->modrm_mod == 3) {
- c->modrm_ptr = decode_register(c->modrm_rm,
+ op->type = OP_REG;
+ op->bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+ op->addr.reg = decode_register(c->modrm_rm,
c->regs, c->d & ByteOp);
- c->modrm_val = *(unsigned long *)c->modrm_ptr;
+ fetch_register_operand(op);
return rc;
}
+ op->type = OP_MEM;
+
if (c->ad_bytes == 2) {
unsigned bx = c->regs[VCPU_REGS_RBX];
unsigned bp = c->regs[VCPU_REGS_RBP];
@@ -864,47 +696,46 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
switch (c->modrm_mod) {
case 0:
if (c->modrm_rm == 6)
- c->modrm_ea += insn_fetch(u16, 2, c->eip);
+ modrm_ea += insn_fetch(u16, 2, c->eip);
break;
case 1:
- c->modrm_ea += insn_fetch(s8, 1, c->eip);
+ modrm_ea += insn_fetch(s8, 1, c->eip);
break;
case 2:
- c->modrm_ea += insn_fetch(u16, 2, c->eip);
+ modrm_ea += insn_fetch(u16, 2, c->eip);
break;
}
switch (c->modrm_rm) {
case 0:
- c->modrm_ea += bx + si;
+ modrm_ea += bx + si;
break;
case 1:
- c->modrm_ea += bx + di;
+ modrm_ea += bx + di;
break;
case 2:
- c->modrm_ea += bp + si;
+ modrm_ea += bp + si;
break;
case 3:
- c->modrm_ea += bp + di;
+ modrm_ea += bp + di;
break;
case 4:
- c->modrm_ea += si;
+ modrm_ea += si;
break;
case 5:
- c->modrm_ea += di;
+ modrm_ea += di;
break;
case 6:
if (c->modrm_mod != 0)
- c->modrm_ea += bp;
+ modrm_ea += bp;
break;
case 7:
- c->modrm_ea += bx;
+ modrm_ea += bx;
break;
}
if (c->modrm_rm == 2 || c->modrm_rm == 3 ||
(c->modrm_rm == 6 && c->modrm_mod != 0))
- if (!c->has_seg_override)
- set_seg_override(c, VCPU_SREG_SS);
- c->modrm_ea = (u16)c->modrm_ea;
+ c->modrm_seg = VCPU_SREG_SS;
+ modrm_ea = (u16)modrm_ea;
} else {
/* 32/64-bit ModR/M decode. */
if ((c->modrm_rm & 7) == 4) {
@@ -914,410 +745,74 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
scale = sib >> 6;
if ((base_reg & 7) == 5 && c->modrm_mod == 0)
- c->modrm_ea += insn_fetch(s32, 4, c->eip);
+ modrm_ea += insn_fetch(s32, 4, c->eip);
else
- c->modrm_ea += c->regs[base_reg];
+ modrm_ea += c->regs[base_reg];
if (index_reg != 4)
- c->modrm_ea += c->regs[index_reg] << scale;
+ modrm_ea += c->regs[index_reg] << scale;
} else if ((c->modrm_rm & 7) == 5 && c->modrm_mod == 0) {
if (ctxt->mode == X86EMUL_MODE_PROT64)
c->rip_relative = 1;
} else
- c->modrm_ea += c->regs[c->modrm_rm];
+ modrm_ea += c->regs[c->modrm_rm];
switch (c->modrm_mod) {
case 0:
if (c->modrm_rm == 5)
- c->modrm_ea += insn_fetch(s32, 4, c->eip);
+ modrm_ea += insn_fetch(s32, 4, c->eip);
break;
case 1:
- c->modrm_ea += insn_fetch(s8, 1, c->eip);
+ modrm_ea += insn_fetch(s8, 1, c->eip);
break;
case 2:
- c->modrm_ea += insn_fetch(s32, 4, c->eip);
+ modrm_ea += insn_fetch(s32, 4, c->eip);
break;
}
}
+ op->addr.mem = modrm_ea;
done:
return rc;
}
static int decode_abs(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops)
+ struct x86_emulate_ops *ops,
+ struct operand *op)
{
struct decode_cache *c = &ctxt->decode;
int rc = X86EMUL_CONTINUE;
+ op->type = OP_MEM;
switch (c->ad_bytes) {
case 2:
- c->modrm_ea = insn_fetch(u16, 2, c->eip);
+ op->addr.mem = insn_fetch(u16, 2, c->eip);
break;
case 4:
- c->modrm_ea = insn_fetch(u32, 4, c->eip);
+ op->addr.mem = insn_fetch(u32, 4, c->eip);
break;
case 8:
- c->modrm_ea = insn_fetch(u64, 8, c->eip);
+ op->addr.mem = insn_fetch(u64, 8, c->eip);
break;
}
done:
return rc;
}
-int
-x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
+static void fetch_bit_operand(struct decode_cache *c)
{
- struct decode_cache *c = &ctxt->decode;
- int rc = X86EMUL_CONTINUE;
- int mode = ctxt->mode;
- int def_op_bytes, def_ad_bytes, group;
-
-
- /* we cannot decode insn before we complete previous rep insn */
- WARN_ON(ctxt->restart);
-
- c->eip = ctxt->eip;
- c->fetch.start = c->fetch.end = c->eip;
- ctxt->cs_base = seg_base(ctxt, ops, VCPU_SREG_CS);
-
- switch (mode) {
- case X86EMUL_MODE_REAL:
- case X86EMUL_MODE_VM86:
- case X86EMUL_MODE_PROT16:
- def_op_bytes = def_ad_bytes = 2;
- break;
- case X86EMUL_MODE_PROT32:
- def_op_bytes = def_ad_bytes = 4;
- break;
-#ifdef CONFIG_X86_64
- case X86EMUL_MODE_PROT64:
- def_op_bytes = 4;
- def_ad_bytes = 8;
- break;
-#endif
- default:
- return -1;
- }
-
- c->op_bytes = def_op_bytes;
- c->ad_bytes = def_ad_bytes;
-
- /* Legacy prefixes. */
- for (;;) {
- switch (c->b = insn_fetch(u8, 1, c->eip)) {
- case 0x66: /* operand-size override */
- /* switch between 2/4 bytes */
- c->op_bytes = def_op_bytes ^ 6;
- break;
- case 0x67: /* address-size override */
- if (mode == X86EMUL_MODE_PROT64)
- /* switch between 4/8 bytes */
- c->ad_bytes = def_ad_bytes ^ 12;
- else
- /* switch between 2/4 bytes */
- c->ad_bytes = def_ad_bytes ^ 6;
- break;
- case 0x26: /* ES override */
- case 0x2e: /* CS override */
- case 0x36: /* SS override */
- case 0x3e: /* DS override */
- set_seg_override(c, (c->b >> 3) & 3);
- break;
- case 0x64: /* FS override */
- case 0x65: /* GS override */
- set_seg_override(c, c->b & 7);
- break;
- case 0x40 ... 0x4f: /* REX */
- if (mode != X86EMUL_MODE_PROT64)
- goto done_prefixes;
- c->rex_prefix = c->b;
- continue;
- case 0xf0: /* LOCK */
- c->lock_prefix = 1;
- break;
- case 0xf2: /* REPNE/REPNZ */
- c->rep_prefix = REPNE_PREFIX;
- break;
- case 0xf3: /* REP/REPE/REPZ */
- c->rep_prefix = REPE_PREFIX;
- break;
- default:
- goto done_prefixes;
- }
-
- /* Any legacy prefix after a REX prefix nullifies its effect. */
-
- c->rex_prefix = 0;
- }
-
-done_prefixes:
-
- /* REX prefix. */
- if (c->rex_prefix)
- if (c->rex_prefix & 8)
- c->op_bytes = 8; /* REX.W */
-
- /* Opcode byte(s). */
- c->d = opcode_table[c->b];
- if (c->d == 0) {
- /* Two-byte opcode? */
- if (c->b == 0x0f) {
- c->twobyte = 1;
- c->b = insn_fetch(u8, 1, c->eip);
- c->d = twobyte_table[c->b];
- }
- }
-
- if (c->d & Group) {
- group = c->d & GroupMask;
- c->modrm = insn_fetch(u8, 1, c->eip);
- --c->eip;
-
- group = (group << 3) + ((c->modrm >> 3) & 7);
- if ((c->d & GroupDual) && (c->modrm >> 6) == 3)
- c->d = group2_table[group];
- else
- c->d = group_table[group];
- }
-
- /* Unrecognised? */
- if (c->d == 0) {
- DPRINTF("Cannot emulate %02x\n", c->b);
- return -1;
- }
-
- if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack))
- c->op_bytes = 8;
-
- /* ModRM and SIB bytes. */
- if (c->d & ModRM)
- rc = decode_modrm(ctxt, ops);
- else if (c->d & MemAbs)
- rc = decode_abs(ctxt, ops);
- if (rc != X86EMUL_CONTINUE)
- goto done;
-
- if (!c->has_seg_override)
- set_seg_override(c, VCPU_SREG_DS);
-
- if (!(!c->twobyte && c->b == 0x8d))
- c->modrm_ea += seg_override_base(ctxt, ops, c);
-
- if (c->ad_bytes != 8)
- c->modrm_ea = (u32)c->modrm_ea;
-
- if (c->rip_relative)
- c->modrm_ea += c->eip;
-
- /*
- * Decode and fetch the source operand: register, memory
- * or immediate.
- */
- switch (c->d & SrcMask) {
- case SrcNone:
- break;
- case SrcReg:
- decode_register_operand(&c->src, c, 0);
- break;
- case SrcMem16:
- c->src.bytes = 2;
- goto srcmem_common;
- case SrcMem32:
- c->src.bytes = 4;
- goto srcmem_common;
- case SrcMem:
- c->src.bytes = (c->d & ByteOp) ? 1 :
- c->op_bytes;
- /* Don't fetch the address for invlpg: it could be unmapped. */
- if (c->twobyte && c->b == 0x01 && c->modrm_reg == 7)
- break;
- srcmem_common:
- /*
- * For instructions with a ModR/M byte, switch to register
- * access if Mod = 3.
- */
- if ((c->d & ModRM) && c->modrm_mod == 3) {
- c->src.type = OP_REG;
- c->src.val = c->modrm_val;
- c->src.ptr = c->modrm_ptr;
- break;
- }
- c->src.type = OP_MEM;
- c->src.ptr = (unsigned long *)c->modrm_ea;
- c->src.val = 0;
- break;
- case SrcImm:
- case SrcImmU:
- c->src.type = OP_IMM;
- c->src.ptr = (unsigned long *)c->eip;
- c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- if (c->src.bytes == 8)
- c->src.bytes = 4;
- /* NB. Immediates are sign-extended as necessary. */
- switch (c->src.bytes) {
- case 1:
- c->src.val = insn_fetch(s8, 1, c->eip);
- break;
- case 2:
- c->src.val = insn_fetch(s16, 2, c->eip);
- break;
- case 4:
- c->src.val = insn_fetch(s32, 4, c->eip);
- break;
- }
- if ((c->d & SrcMask) == SrcImmU) {
- switch (c->src.bytes) {
- case 1:
- c->src.val &= 0xff;
- break;
- case 2:
- c->src.val &= 0xffff;
- break;
- case 4:
- c->src.val &= 0xffffffff;
- break;
- }
- }
- break;
- case SrcImmByte:
- case SrcImmUByte:
- c->src.type = OP_IMM;
- c->src.ptr = (unsigned long *)c->eip;
- c->src.bytes = 1;
- if ((c->d & SrcMask) == SrcImmByte)
- c->src.val = insn_fetch(s8, 1, c->eip);
- else
- c->src.val = insn_fetch(u8, 1, c->eip);
- break;
- case SrcAcc:
- c->src.type = OP_REG;
- c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->src.ptr = &c->regs[VCPU_REGS_RAX];
- switch (c->src.bytes) {
- case 1:
- c->src.val = *(u8 *)c->src.ptr;
- break;
- case 2:
- c->src.val = *(u16 *)c->src.ptr;
- break;
- case 4:
- c->src.val = *(u32 *)c->src.ptr;
- break;
- case 8:
- c->src.val = *(u64 *)c->src.ptr;
- break;
- }
- break;
- case SrcOne:
- c->src.bytes = 1;
- c->src.val = 1;
- break;
- case SrcSI:
- c->src.type = OP_MEM;
- c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->src.ptr = (unsigned long *)
- register_address(c, seg_override_base(ctxt, ops, c),
- c->regs[VCPU_REGS_RSI]);
- c->src.val = 0;
- break;
- case SrcImmFAddr:
- c->src.type = OP_IMM;
- c->src.ptr = (unsigned long *)c->eip;
- c->src.bytes = c->op_bytes + 2;
- insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip);
- break;
- case SrcMemFAddr:
- c->src.type = OP_MEM;
- c->src.ptr = (unsigned long *)c->modrm_ea;
- c->src.bytes = c->op_bytes + 2;
- break;
- }
+ long sv = 0, mask;
- /*
- * Decode and fetch the second source operand: register, memory
- * or immediate.
- */
- switch (c->d & Src2Mask) {
- case Src2None:
- break;
- case Src2CL:
- c->src2.bytes = 1;
- c->src2.val = c->regs[VCPU_REGS_RCX] & 0x8;
- break;
- case Src2ImmByte:
- c->src2.type = OP_IMM;
- c->src2.ptr = (unsigned long *)c->eip;
- c->src2.bytes = 1;
- c->src2.val = insn_fetch(u8, 1, c->eip);
- break;
- case Src2One:
- c->src2.bytes = 1;
- c->src2.val = 1;
- break;
- }
+ if (c->dst.type == OP_MEM && c->src.type == OP_REG) {
+ mask = ~(c->dst.bytes * 8 - 1);
- /* Decode and fetch the destination operand: register or memory. */
- switch (c->d & DstMask) {
- case ImplicitOps:
- /* Special instructions do their own operand decoding. */
- return 0;
- case DstReg:
- decode_register_operand(&c->dst, c,
- c->twobyte && (c->b == 0xb6 || c->b == 0xb7));
- break;
- case DstMem:
- case DstMem64:
- if ((c->d & ModRM) && c->modrm_mod == 3) {
- c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->dst.type = OP_REG;
- c->dst.val = c->dst.orig_val = c->modrm_val;
- c->dst.ptr = c->modrm_ptr;
- break;
- }
- c->dst.type = OP_MEM;
- c->dst.ptr = (unsigned long *)c->modrm_ea;
- if ((c->d & DstMask) == DstMem64)
- c->dst.bytes = 8;
- else
- c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->dst.val = 0;
- if (c->d & BitOp) {
- unsigned long mask = ~(c->dst.bytes * 8 - 1);
+ if (c->src.bytes == 2)
+ sv = (s16)c->src.val & (s16)mask;
+ else if (c->src.bytes == 4)
+ sv = (s32)c->src.val & (s32)mask;
- c->dst.ptr = (void *)c->dst.ptr +
- (c->src.val & mask) / 8;
- }
- break;
- case DstAcc:
- c->dst.type = OP_REG;
- c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->dst.ptr = &c->regs[VCPU_REGS_RAX];
- switch (c->dst.bytes) {
- case 1:
- c->dst.val = *(u8 *)c->dst.ptr;
- break;
- case 2:
- c->dst.val = *(u16 *)c->dst.ptr;
- break;
- case 4:
- c->dst.val = *(u32 *)c->dst.ptr;
- break;
- case 8:
- c->dst.val = *(u64 *)c->dst.ptr;
- break;
- }
- c->dst.orig_val = c->dst.val;
- break;
- case DstDI:
- c->dst.type = OP_MEM;
- c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->dst.ptr = (unsigned long *)
- register_address(c, es_base(ctxt, ops),
- c->regs[VCPU_REGS_RDI]);
- c->dst.val = 0;
- break;
+ c->dst.addr.mem += (sv >> 3);
}
-done:
- return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+ /* only subword offset */
+ c->src.val &= (c->dst.bytes << 3) - 1;
}
static int read_emulated(struct x86_emulate_ctxt *ctxt,
@@ -1337,7 +832,7 @@ static int read_emulated(struct x86_emulate_ctxt *ctxt,
rc = ops->read_emulated(addr, mc->data + mc->end, n, &err,
ctxt->vcpu);
if (rc == X86EMUL_PROPAGATE_FAULT)
- emulate_pf(ctxt, addr, err);
+ emulate_pf(ctxt);
if (rc != X86EMUL_CONTINUE)
return rc;
mc->end += n;
@@ -1424,7 +919,7 @@ static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt,
addr = dt.address + index * 8;
ret = ops->read_std(addr, desc, sizeof *desc, ctxt->vcpu, &err);
if (ret == X86EMUL_PROPAGATE_FAULT)
- emulate_pf(ctxt, addr, err);
+ emulate_pf(ctxt);
return ret;
}
@@ -1450,7 +945,7 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
addr = dt.address + index * 8;
ret = ops->write_std(addr, desc, sizeof *desc, ctxt->vcpu, &err);
if (ret == X86EMUL_PROPAGATE_FAULT)
- emulate_pf(ctxt, addr, err);
+ emulate_pf(ctxt);
return ret;
}
@@ -1573,6 +1068,25 @@ exception:
return X86EMUL_PROPAGATE_FAULT;
}
+static void write_register_operand(struct operand *op)
+{
+ /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
+ switch (op->bytes) {
+ case 1:
+ *(u8 *)op->addr.reg = (u8)op->val;
+ break;
+ case 2:
+ *(u16 *)op->addr.reg = (u16)op->val;
+ break;
+ case 4:
+ *op->addr.reg = (u32)op->val;
+ break; /* 64b: zero-extend */
+ case 8:
+ *op->addr.reg = op->val;
+ break;
+ }
+}
+
static inline int writeback(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops)
{
@@ -1582,28 +1096,12 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt,
switch (c->dst.type) {
case OP_REG:
- /* The 4-byte case *is* correct:
- * in 64-bit mode we zero-extend.
- */
- switch (c->dst.bytes) {
- case 1:
- *(u8 *)c->dst.ptr = (u8)c->dst.val;
- break;
- case 2:
- *(u16 *)c->dst.ptr = (u16)c->dst.val;
- break;
- case 4:
- *c->dst.ptr = (u32)c->dst.val;
- break; /* 64b: zero-ext */
- case 8:
- *c->dst.ptr = c->dst.val;
- break;
- }
+ write_register_operand(&c->dst);
break;
case OP_MEM:
if (c->lock_prefix)
rc = ops->cmpxchg_emulated(
- (unsigned long)c->dst.ptr,
+ c->dst.addr.mem,
&c->dst.orig_val,
&c->dst.val,
c->dst.bytes,
@@ -1611,14 +1109,13 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt,
ctxt->vcpu);
else
rc = ops->write_emulated(
- (unsigned long)c->dst.ptr,
+ c->dst.addr.mem,
&c->dst.val,
c->dst.bytes,
&err,
ctxt->vcpu);
if (rc == X86EMUL_PROPAGATE_FAULT)
- emulate_pf(ctxt,
- (unsigned long)c->dst.ptr, err);
+ emulate_pf(ctxt);
if (rc != X86EMUL_CONTINUE)
return rc;
break;
@@ -1640,8 +1137,8 @@ static inline void emulate_push(struct x86_emulate_ctxt *ctxt,
c->dst.bytes = c->op_bytes;
c->dst.val = c->src.val;
register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes);
- c->dst.ptr = (void *) register_address(c, ss_base(ctxt, ops),
- c->regs[VCPU_REGS_RSP]);
+ c->dst.addr.mem = register_address(c, ss_base(ctxt, ops),
+ c->regs[VCPU_REGS_RSP]);
}
static int emulate_pop(struct x86_emulate_ctxt *ctxt,
@@ -1701,6 +1198,9 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt,
*(unsigned long *)dest =
(ctxt->eflags & ~change_mask) | (val & change_mask);
+ if (rc == X86EMUL_PROPAGATE_FAULT)
+ emulate_pf(ctxt);
+
return rc;
}
@@ -1778,6 +1278,150 @@ static int emulate_popa(struct x86_emulate_ctxt *ctxt,
return rc;
}
+int emulate_int_real(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops, int irq)
+{
+ struct decode_cache *c = &ctxt->decode;
+ int rc;
+ struct desc_ptr dt;
+ gva_t cs_addr;
+ gva_t eip_addr;
+ u16 cs, eip;
+ u32 err;
+
+ /* TODO: Add limit checks */
+ c->src.val = ctxt->eflags;
+ emulate_push(ctxt, ops);
+ rc = writeback(ctxt, ops);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
+ ctxt->eflags &= ~(EFLG_IF | EFLG_TF | EFLG_AC);
+
+ c->src.val = ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu);
+ emulate_push(ctxt, ops);
+ rc = writeback(ctxt, ops);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
+ c->src.val = c->eip;
+ emulate_push(ctxt, ops);
+ rc = writeback(ctxt, ops);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
+ c->dst.type = OP_NONE;
+
+ ops->get_idt(&dt, ctxt->vcpu);
+
+ eip_addr = dt.address + (irq << 2);
+ cs_addr = dt.address + (irq << 2) + 2;
+
+ rc = ops->read_std(cs_addr, &cs, 2, ctxt->vcpu, &err);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
+ rc = ops->read_std(eip_addr, &eip, 2, ctxt->vcpu, &err);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
+ rc = load_segment_descriptor(ctxt, ops, cs, VCPU_SREG_CS);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
+ c->eip = eip;
+
+ return rc;
+}
+
+static int emulate_int(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops, int irq)
+{
+ switch(ctxt->mode) {
+ case X86EMUL_MODE_REAL:
+ return emulate_int_real(ctxt, ops, irq);
+ case X86EMUL_MODE_VM86:
+ case X86EMUL_MODE_PROT16:
+ case X86EMUL_MODE_PROT32:
+ case X86EMUL_MODE_PROT64:
+ default:
+ /* Protected mode interrupts unimplemented yet */
+ return X86EMUL_UNHANDLEABLE;
+ }
+}
+
+static int emulate_iret_real(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops)
+{
+ struct decode_cache *c = &ctxt->decode;
+ int rc = X86EMUL_CONTINUE;
+ unsigned long temp_eip = 0;
+ unsigned long temp_eflags = 0;
+ unsigned long cs = 0;
+ unsigned long mask = EFLG_CF | EFLG_PF | EFLG_AF | EFLG_ZF | EFLG_SF | EFLG_TF |
+ EFLG_IF | EFLG_DF | EFLG_OF | EFLG_IOPL | EFLG_NT | EFLG_RF |
+ EFLG_AC | EFLG_ID | (1 << 1); /* Last one is the reserved bit */
+ unsigned long vm86_mask = EFLG_VM | EFLG_VIF | EFLG_VIP;
+
+ /* TODO: Add stack limit check */
+
+ rc = emulate_pop(ctxt, ops, &temp_eip, c->op_bytes);
+
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
+ if (temp_eip & ~0xffff) {
+ emulate_gp(ctxt, 0);
+ return X86EMUL_PROPAGATE_FAULT;
+ }
+
+ rc = emulate_pop(ctxt, ops, &cs, c->op_bytes);
+
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
+ rc = emulate_pop(ctxt, ops, &temp_eflags, c->op_bytes);
+
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
+ rc = load_segment_descriptor(ctxt, ops, (u16)cs, VCPU_SREG_CS);
+
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
+ c->eip = temp_eip;
+
+
+ if (c->op_bytes == 4)
+ ctxt->eflags = ((temp_eflags & mask) | (ctxt->eflags & vm86_mask));
+ else if (c->op_bytes == 2) {
+ ctxt->eflags &= ~0xffff;
+ ctxt->eflags |= temp_eflags;
+ }
+
+ ctxt->eflags &= ~EFLG_RESERVED_ZEROS_MASK; /* Clear reserved zeros */
+ ctxt->eflags |= EFLG_RESERVED_ONE_MASK;
+
+ return rc;
+}
+
+static inline int emulate_iret(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops* ops)
+{
+ switch(ctxt->mode) {
+ case X86EMUL_MODE_REAL:
+ return emulate_iret_real(ctxt, ops);
+ case X86EMUL_MODE_VM86:
+ case X86EMUL_MODE_PROT16:
+ case X86EMUL_MODE_PROT32:
+ case X86EMUL_MODE_PROT64:
+ default:
+ /* iret from protected mode unimplemented yet */
+ return X86EMUL_UNHANDLEABLE;
+ }
+}
+
static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops)
{
@@ -1819,6 +1463,9 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops)
{
struct decode_cache *c = &ctxt->decode;
+ unsigned long *rax = &c->regs[VCPU_REGS_RAX];
+ unsigned long *rdx = &c->regs[VCPU_REGS_RDX];
+ u8 de = 0;
switch (c->modrm_reg) {
case 0 ... 1: /* test */
@@ -1830,10 +1477,26 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt,
case 3: /* neg */
emulate_1op("neg", c->dst, ctxt->eflags);
break;
+ case 4: /* mul */
+ emulate_1op_rax_rdx("mul", c->src, *rax, *rdx, ctxt->eflags);
+ break;
+ case 5: /* imul */
+ emulate_1op_rax_rdx("imul", c->src, *rax, *rdx, ctxt->eflags);
+ break;
+ case 6: /* div */
+ emulate_1op_rax_rdx_ex("div", c->src, *rax, *rdx,
+ ctxt->eflags, de);
+ break;
+ case 7: /* idiv */
+ emulate_1op_rax_rdx_ex("idiv", c->src, *rax, *rdx,
+ ctxt->eflags, de);
+ break;
default:
- return 0;
+ return X86EMUL_UNHANDLEABLE;
}
- return 1;
+ if (de)
+ return emulate_de(ctxt);
+ return X86EMUL_CONTINUE;
}
static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt,
@@ -1905,6 +1568,23 @@ static int emulate_ret_far(struct x86_emulate_ctxt *ctxt,
return rc;
}
+static int emulate_load_segment(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops, int seg)
+{
+ struct decode_cache *c = &ctxt->decode;
+ unsigned short sel;
+ int rc;
+
+ memcpy(&sel, c->src.valptr + c->op_bytes, 2);
+
+ rc = load_segment_descriptor(ctxt, ops, sel, seg);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
+ c->dst.val = c->src.val;
+ return rc;
+}
+
static inline void
setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops, struct desc_struct *cs,
@@ -2160,9 +1840,15 @@ static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops,
u16 port, u16 len)
{
+ if (ctxt->perm_ok)
+ return true;
+
if (emulator_bad_iopl(ctxt, ops))
if (!emulator_io_port_access_allowed(ctxt, ops, port, len))
return false;
+
+ ctxt->perm_ok = true;
+
return true;
}
@@ -2254,7 +1940,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt,
&err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- emulate_pf(ctxt, old_tss_base, err);
+ emulate_pf(ctxt);
return ret;
}
@@ -2264,7 +1950,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt,
&err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- emulate_pf(ctxt, old_tss_base, err);
+ emulate_pf(ctxt);
return ret;
}
@@ -2272,7 +1958,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt,
&err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- emulate_pf(ctxt, new_tss_base, err);
+ emulate_pf(ctxt);
return ret;
}
@@ -2285,7 +1971,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt,
ctxt->vcpu, &err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- emulate_pf(ctxt, new_tss_base, err);
+ emulate_pf(ctxt);
return ret;
}
}
@@ -2396,7 +2082,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,
&err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- emulate_pf(ctxt, old_tss_base, err);
+ emulate_pf(ctxt);
return ret;
}
@@ -2406,7 +2092,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,
&err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- emulate_pf(ctxt, old_tss_base, err);
+ emulate_pf(ctxt);
return ret;
}
@@ -2414,7 +2100,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,
&err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- emulate_pf(ctxt, new_tss_base, err);
+ emulate_pf(ctxt);
return ret;
}
@@ -2427,7 +2113,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,
ctxt->vcpu, &err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- emulate_pf(ctxt, new_tss_base, err);
+ emulate_pf(ctxt);
return ret;
}
}
@@ -2523,10 +2209,10 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
}
int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops,
u16 tss_selector, int reason,
bool has_error_code, u32 error_code)
{
+ struct x86_emulate_ops *ops = ctxt->ops;
struct decode_cache *c = &ctxt->decode;
int rc;
@@ -2552,16 +2238,784 @@ static void string_addr_inc(struct x86_emulate_ctxt *ctxt, unsigned long base,
int df = (ctxt->eflags & EFLG_DF) ? -1 : 1;
register_address_increment(c, &c->regs[reg], df * op->bytes);
- op->ptr = (unsigned long *)register_address(c, base, c->regs[reg]);
+ op->addr.mem = register_address(c, base, c->regs[reg]);
+}
+
+static int em_push(struct x86_emulate_ctxt *ctxt)
+{
+ emulate_push(ctxt, ctxt->ops);
+ return X86EMUL_CONTINUE;
+}
+
+static int em_das(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ u8 al, old_al;
+ bool af, cf, old_cf;
+
+ cf = ctxt->eflags & X86_EFLAGS_CF;
+ al = c->dst.val;
+
+ old_al = al;
+ old_cf = cf;
+ cf = false;
+ af = ctxt->eflags & X86_EFLAGS_AF;
+ if ((al & 0x0f) > 9 || af) {
+ al -= 6;
+ cf = old_cf | (al >= 250);
+ af = true;
+ } else {
+ af = false;
+ }
+ if (old_al > 0x99 || old_cf) {
+ al -= 0x60;
+ cf = true;
+ }
+
+ c->dst.val = al;
+ /* Set PF, ZF, SF */
+ c->src.type = OP_IMM;
+ c->src.val = 0;
+ c->src.bytes = 1;
+ emulate_2op_SrcV("or", c->src, c->dst, ctxt->eflags);
+ ctxt->eflags &= ~(X86_EFLAGS_AF | X86_EFLAGS_CF);
+ if (cf)
+ ctxt->eflags |= X86_EFLAGS_CF;
+ if (af)
+ ctxt->eflags |= X86_EFLAGS_AF;
+ return X86EMUL_CONTINUE;
+}
+
+static int em_call_far(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ u16 sel, old_cs;
+ ulong old_eip;
+ int rc;
+
+ old_cs = ctxt->ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu);
+ old_eip = c->eip;
+
+ memcpy(&sel, c->src.valptr + c->op_bytes, 2);
+ if (load_segment_descriptor(ctxt, ctxt->ops, sel, VCPU_SREG_CS))
+ return X86EMUL_CONTINUE;
+
+ c->eip = 0;
+ memcpy(&c->eip, c->src.valptr, c->op_bytes);
+
+ c->src.val = old_cs;
+ emulate_push(ctxt, ctxt->ops);
+ rc = writeback(ctxt, ctxt->ops);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
+ c->src.val = old_eip;
+ emulate_push(ctxt, ctxt->ops);
+ rc = writeback(ctxt, ctxt->ops);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
+ c->dst.type = OP_NONE;
+
+ return X86EMUL_CONTINUE;
+}
+
+static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ int rc;
+
+ c->dst.type = OP_REG;
+ c->dst.addr.reg = &c->eip;
+ c->dst.bytes = c->op_bytes;
+ rc = emulate_pop(ctxt, ctxt->ops, &c->dst.val, c->op_bytes);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+ register_address_increment(c, &c->regs[VCPU_REGS_RSP], c->src.val);
+ return X86EMUL_CONTINUE;
+}
+
+static int em_imul(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ emulate_2op_SrcV_nobyte("imul", c->src, c->dst, ctxt->eflags);
+ return X86EMUL_CONTINUE;
+}
+
+static int em_imul_3op(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ c->dst.val = c->src2.val;
+ return em_imul(ctxt);
+}
+
+static int em_cwd(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ c->dst.type = OP_REG;
+ c->dst.bytes = c->src.bytes;
+ c->dst.addr.reg = &c->regs[VCPU_REGS_RDX];
+ c->dst.val = ~((c->src.val >> (c->src.bytes * 8 - 1)) - 1);
+
+ return X86EMUL_CONTINUE;
+}
+
+static int em_rdtsc(struct x86_emulate_ctxt *ctxt)
+{
+ unsigned cpl = ctxt->ops->cpl(ctxt->vcpu);
+ struct decode_cache *c = &ctxt->decode;
+ u64 tsc = 0;
+
+ if (cpl > 0 && (ctxt->ops->get_cr(4, ctxt->vcpu) & X86_CR4_TSD)) {
+ emulate_gp(ctxt, 0);
+ return X86EMUL_PROPAGATE_FAULT;
+ }
+ ctxt->ops->get_msr(ctxt->vcpu, MSR_IA32_TSC, &tsc);
+ c->regs[VCPU_REGS_RAX] = (u32)tsc;
+ c->regs[VCPU_REGS_RDX] = tsc >> 32;
+ return X86EMUL_CONTINUE;
+}
+
+static int em_mov(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ c->dst.val = c->src.val;
+ return X86EMUL_CONTINUE;
+}
+
+#define D(_y) { .flags = (_y) }
+#define N D(0)
+#define G(_f, _g) { .flags = ((_f) | Group), .u.group = (_g) }
+#define GD(_f, _g) { .flags = ((_f) | Group | GroupDual), .u.gdual = (_g) }
+#define I(_f, _e) { .flags = (_f), .u.execute = (_e) }
+
+#define D2bv(_f) D((_f) | ByteOp), D(_f)
+#define I2bv(_f, _e) I((_f) | ByteOp, _e), I(_f, _e)
+
+#define D6ALU(_f) D2bv((_f) | DstMem | SrcReg | ModRM), \
+ D2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock), \
+ D2bv(((_f) & ~Lock) | DstAcc | SrcImm)
+
+
+static struct opcode group1[] = {
+ X7(D(Lock)), N
+};
+
+static struct opcode group1A[] = {
+ D(DstMem | SrcNone | ModRM | Mov | Stack), N, N, N, N, N, N, N,
+};
+
+static struct opcode group3[] = {
+ D(DstMem | SrcImm | ModRM), D(DstMem | SrcImm | ModRM),
+ D(DstMem | SrcNone | ModRM | Lock), D(DstMem | SrcNone | ModRM | Lock),
+ X4(D(SrcMem | ModRM)),
+};
+
+static struct opcode group4[] = {
+ D(ByteOp | DstMem | SrcNone | ModRM | Lock), D(ByteOp | DstMem | SrcNone | ModRM | Lock),
+ N, N, N, N, N, N,
+};
+
+static struct opcode group5[] = {
+ D(DstMem | SrcNone | ModRM | Lock), D(DstMem | SrcNone | ModRM | Lock),
+ D(SrcMem | ModRM | Stack),
+ I(SrcMemFAddr | ModRM | ImplicitOps | Stack, em_call_far),
+ D(SrcMem | ModRM | Stack), D(SrcMemFAddr | ModRM | ImplicitOps),
+ D(SrcMem | ModRM | Stack), N,
+};
+
+static struct group_dual group7 = { {
+ N, N, D(ModRM | SrcMem | Priv), D(ModRM | SrcMem | Priv),
+ D(SrcNone | ModRM | DstMem | Mov), N,
+ D(SrcMem16 | ModRM | Mov | Priv),
+ D(SrcMem | ModRM | ByteOp | Priv | NoAccess),
+}, {
+ D(SrcNone | ModRM | Priv), N, N, D(SrcNone | ModRM | Priv),
+ D(SrcNone | ModRM | DstMem | Mov), N,
+ D(SrcMem16 | ModRM | Mov | Priv), N,
+} };
+
+static struct opcode group8[] = {
+ N, N, N, N,
+ D(DstMem | SrcImmByte | ModRM), D(DstMem | SrcImmByte | ModRM | Lock),
+ D(DstMem | SrcImmByte | ModRM | Lock), D(DstMem | SrcImmByte | ModRM | Lock),
+};
+
+static struct group_dual group9 = { {
+ N, D(DstMem64 | ModRM | Lock), N, N, N, N, N, N,
+}, {
+ N, N, N, N, N, N, N, N,
+} };
+
+static struct opcode group11[] = {
+ I(DstMem | SrcImm | ModRM | Mov, em_mov), X7(D(Undefined)),
+};
+
+static struct opcode opcode_table[256] = {
+ /* 0x00 - 0x07 */
+ D6ALU(Lock),
+ D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64),
+ /* 0x08 - 0x0F */
+ D6ALU(Lock),
+ D(ImplicitOps | Stack | No64), N,
+ /* 0x10 - 0x17 */
+ D6ALU(Lock),
+ D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64),
+ /* 0x18 - 0x1F */
+ D6ALU(Lock),
+ D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64),
+ /* 0x20 - 0x27 */
+ D6ALU(Lock), N, N,
+ /* 0x28 - 0x2F */
+ D6ALU(Lock), N, I(ByteOp | DstAcc | No64, em_das),
+ /* 0x30 - 0x37 */
+ D6ALU(Lock), N, N,
+ /* 0x38 - 0x3F */
+ D6ALU(0), N, N,
+ /* 0x40 - 0x4F */
+ X16(D(DstReg)),
+ /* 0x50 - 0x57 */
+ X8(I(SrcReg | Stack, em_push)),
+ /* 0x58 - 0x5F */
+ X8(D(DstReg | Stack)),
+ /* 0x60 - 0x67 */
+ D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64),
+ N, D(DstReg | SrcMem32 | ModRM | Mov) /* movsxd (x86/64) */ ,
+ N, N, N, N,
+ /* 0x68 - 0x6F */
+ I(SrcImm | Mov | Stack, em_push),
+ I(DstReg | SrcMem | ModRM | Src2Imm, em_imul_3op),
+ I(SrcImmByte | Mov | Stack, em_push),
+ I(DstReg | SrcMem | ModRM | Src2ImmByte, em_imul_3op),
+ D2bv(DstDI | Mov | String), /* insb, insw/insd */
+ D2bv(SrcSI | ImplicitOps | String), /* outsb, outsw/outsd */
+ /* 0x70 - 0x7F */
+ X16(D(SrcImmByte)),
+ /* 0x80 - 0x87 */
+ G(ByteOp | DstMem | SrcImm | ModRM | Group, group1),
+ G(DstMem | SrcImm | ModRM | Group, group1),
+ G(ByteOp | DstMem | SrcImm | ModRM | No64 | Group, group1),
+ G(DstMem | SrcImmByte | ModRM | Group, group1),
+ D2bv(DstMem | SrcReg | ModRM), D2bv(DstMem | SrcReg | ModRM | Lock),
+ /* 0x88 - 0x8F */
+ I2bv(DstMem | SrcReg | ModRM | Mov, em_mov),
+ I2bv(DstReg | SrcMem | ModRM | Mov, em_mov),
+ D(DstMem | SrcNone | ModRM | Mov), D(ModRM | SrcMem | NoAccess | DstReg),
+ D(ImplicitOps | SrcMem16 | ModRM), G(0, group1A),
+ /* 0x90 - 0x97 */
+ X8(D(SrcAcc | DstReg)),
+ /* 0x98 - 0x9F */
+ D(DstAcc | SrcNone), I(ImplicitOps | SrcAcc, em_cwd),
+ I(SrcImmFAddr | No64, em_call_far), N,
+ D(ImplicitOps | Stack), D(ImplicitOps | Stack), N, N,
+ /* 0xA0 - 0xA7 */
+ I2bv(DstAcc | SrcMem | Mov | MemAbs, em_mov),
+ I2bv(DstMem | SrcAcc | Mov | MemAbs, em_mov),
+ I2bv(SrcSI | DstDI | Mov | String, em_mov),
+ D2bv(SrcSI | DstDI | String),
+ /* 0xA8 - 0xAF */
+ D2bv(DstAcc | SrcImm),
+ I2bv(SrcAcc | DstDI | Mov | String, em_mov),
+ I2bv(SrcSI | DstAcc | Mov | String, em_mov),
+ D2bv(SrcAcc | DstDI | String),
+ /* 0xB0 - 0xB7 */
+ X8(I(ByteOp | DstReg | SrcImm | Mov, em_mov)),
+ /* 0xB8 - 0xBF */
+ X8(I(DstReg | SrcImm | Mov, em_mov)),
+ /* 0xC0 - 0xC7 */
+ D2bv(DstMem | SrcImmByte | ModRM),
+ I(ImplicitOps | Stack | SrcImmU16, em_ret_near_imm),
+ D(ImplicitOps | Stack),
+ D(DstReg | SrcMemFAddr | ModRM | No64), D(DstReg | SrcMemFAddr | ModRM | No64),
+ G(ByteOp, group11), G(0, group11),
+ /* 0xC8 - 0xCF */
+ N, N, N, D(ImplicitOps | Stack),
+ D(ImplicitOps), D(SrcImmByte), D(ImplicitOps | No64), D(ImplicitOps),
+ /* 0xD0 - 0xD7 */
+ D2bv(DstMem | SrcOne | ModRM), D2bv(DstMem | ModRM),
+ N, N, N, N,
+ /* 0xD8 - 0xDF */
+ N, N, N, N, N, N, N, N,
+ /* 0xE0 - 0xE7 */
+ X4(D(SrcImmByte)),
+ D2bv(SrcImmUByte | DstAcc), D2bv(SrcAcc | DstImmUByte),
+ /* 0xE8 - 0xEF */
+ D(SrcImm | Stack), D(SrcImm | ImplicitOps),
+ D(SrcImmFAddr | No64), D(SrcImmByte | ImplicitOps),
+ D2bv(SrcNone | DstAcc), D2bv(SrcAcc | ImplicitOps),
+ /* 0xF0 - 0xF7 */
+ N, N, N, N,
+ D(ImplicitOps | Priv), D(ImplicitOps), G(ByteOp, group3), G(0, group3),
+ /* 0xF8 - 0xFF */
+ D(ImplicitOps), D(ImplicitOps), D(ImplicitOps), D(ImplicitOps),
+ D(ImplicitOps), D(ImplicitOps), G(0, group4), G(0, group5),
+};
+
+static struct opcode twobyte_table[256] = {
+ /* 0x00 - 0x0F */
+ N, GD(0, &group7), N, N,
+ N, D(ImplicitOps), D(ImplicitOps | Priv), N,
+ D(ImplicitOps | Priv), D(ImplicitOps | Priv), N, N,
+ N, D(ImplicitOps | ModRM), N, N,
+ /* 0x10 - 0x1F */
+ N, N, N, N, N, N, N, N, D(ImplicitOps | ModRM), N, N, N, N, N, N, N,
+ /* 0x20 - 0x2F */
+ D(ModRM | DstMem | Priv | Op3264), D(ModRM | DstMem | Priv | Op3264),
+ D(ModRM | SrcMem | Priv | Op3264), D(ModRM | SrcMem | Priv | Op3264),
+ N, N, N, N,
+ N, N, N, N, N, N, N, N,
+ /* 0x30 - 0x3F */
+ D(ImplicitOps | Priv), I(ImplicitOps, em_rdtsc),
+ D(ImplicitOps | Priv), N,
+ D(ImplicitOps), D(ImplicitOps | Priv), N, N,
+ N, N, N, N, N, N, N, N,
+ /* 0x40 - 0x4F */
+ X16(D(DstReg | SrcMem | ModRM | Mov)),
+ /* 0x50 - 0x5F */
+ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+ /* 0x60 - 0x6F */
+ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+ /* 0x70 - 0x7F */
+ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+ /* 0x80 - 0x8F */
+ X16(D(SrcImm)),
+ /* 0x90 - 0x9F */
+ X16(D(ByteOp | DstMem | SrcNone | ModRM| Mov)),
+ /* 0xA0 - 0xA7 */
+ D(ImplicitOps | Stack), D(ImplicitOps | Stack),
+ N, D(DstMem | SrcReg | ModRM | BitOp),
+ D(DstMem | SrcReg | Src2ImmByte | ModRM),
+ D(DstMem | SrcReg | Src2CL | ModRM), N, N,
+ /* 0xA8 - 0xAF */
+ D(ImplicitOps | Stack), D(ImplicitOps | Stack),
+ N, D(DstMem | SrcReg | ModRM | BitOp | Lock),
+ D(DstMem | SrcReg | Src2ImmByte | ModRM),
+ D(DstMem | SrcReg | Src2CL | ModRM),
+ D(ModRM), I(DstReg | SrcMem | ModRM, em_imul),
+ /* 0xB0 - 0xB7 */
+ D2bv(DstMem | SrcReg | ModRM | Lock),
+ D(DstReg | SrcMemFAddr | ModRM), D(DstMem | SrcReg | ModRM | BitOp | Lock),
+ D(DstReg | SrcMemFAddr | ModRM), D(DstReg | SrcMemFAddr | ModRM),
+ D(ByteOp | DstReg | SrcMem | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
+ /* 0xB8 - 0xBF */
+ N, N,
+ G(BitOp, group8), D(DstMem | SrcReg | ModRM | BitOp | Lock),
+ D(DstReg | SrcMem | ModRM), D(DstReg | SrcMem | ModRM),
+ D(ByteOp | DstReg | SrcMem | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
+ /* 0xC0 - 0xCF */
+ D2bv(DstMem | SrcReg | ModRM | Lock),
+ N, D(DstMem | SrcReg | ModRM | Mov),
+ N, N, N, GD(0, &group9),
+ N, N, N, N, N, N, N, N,
+ /* 0xD0 - 0xDF */
+ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+ /* 0xE0 - 0xEF */
+ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+ /* 0xF0 - 0xFF */
+ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N
+};
+
+#undef D
+#undef N
+#undef G
+#undef GD
+#undef I
+
+#undef D2bv
+#undef I2bv
+#undef D6ALU
+
+static unsigned imm_size(struct decode_cache *c)
+{
+ unsigned size;
+
+ size = (c->d & ByteOp) ? 1 : c->op_bytes;
+ if (size == 8)
+ size = 4;
+ return size;
+}
+
+static int decode_imm(struct x86_emulate_ctxt *ctxt, struct operand *op,
+ unsigned size, bool sign_extension)
+{
+ struct decode_cache *c = &ctxt->decode;
+ struct x86_emulate_ops *ops = ctxt->ops;
+ int rc = X86EMUL_CONTINUE;
+
+ op->type = OP_IMM;
+ op->bytes = size;
+ op->addr.mem = c->eip;
+ /* NB. Immediates are sign-extended as necessary. */
+ switch (op->bytes) {
+ case 1:
+ op->val = insn_fetch(s8, 1, c->eip);
+ break;
+ case 2:
+ op->val = insn_fetch(s16, 2, c->eip);
+ break;
+ case 4:
+ op->val = insn_fetch(s32, 4, c->eip);
+ break;
+ }
+ if (!sign_extension) {
+ switch (op->bytes) {
+ case 1:
+ op->val &= 0xff;
+ break;
+ case 2:
+ op->val &= 0xffff;
+ break;
+ case 4:
+ op->val &= 0xffffffff;
+ break;
+ }
+ }
+done:
+ return rc;
}
int
-x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
+x86_decode_insn(struct x86_emulate_ctxt *ctxt)
{
+ struct x86_emulate_ops *ops = ctxt->ops;
+ struct decode_cache *c = &ctxt->decode;
+ int rc = X86EMUL_CONTINUE;
+ int mode = ctxt->mode;
+ int def_op_bytes, def_ad_bytes, dual, goffset;
+ struct opcode opcode, *g_mod012, *g_mod3;
+ struct operand memop = { .type = OP_NONE };
+
+ c->eip = ctxt->eip;
+ c->fetch.start = c->fetch.end = c->eip;
+ ctxt->cs_base = seg_base(ctxt, ops, VCPU_SREG_CS);
+
+ switch (mode) {
+ case X86EMUL_MODE_REAL:
+ case X86EMUL_MODE_VM86:
+ case X86EMUL_MODE_PROT16:
+ def_op_bytes = def_ad_bytes = 2;
+ break;
+ case X86EMUL_MODE_PROT32:
+ def_op_bytes = def_ad_bytes = 4;
+ break;
+#ifdef CONFIG_X86_64
+ case X86EMUL_MODE_PROT64:
+ def_op_bytes = 4;
+ def_ad_bytes = 8;
+ break;
+#endif
+ default:
+ return -1;
+ }
+
+ c->op_bytes = def_op_bytes;
+ c->ad_bytes = def_ad_bytes;
+
+ /* Legacy prefixes. */
+ for (;;) {
+ switch (c->b = insn_fetch(u8, 1, c->eip)) {
+ case 0x66: /* operand-size override */
+ /* switch between 2/4 bytes */
+ c->op_bytes = def_op_bytes ^ 6;
+ break;
+ case 0x67: /* address-size override */
+ if (mode == X86EMUL_MODE_PROT64)
+ /* switch between 4/8 bytes */
+ c->ad_bytes = def_ad_bytes ^ 12;
+ else
+ /* switch between 2/4 bytes */
+ c->ad_bytes = def_ad_bytes ^ 6;
+ break;
+ case 0x26: /* ES override */
+ case 0x2e: /* CS override */
+ case 0x36: /* SS override */
+ case 0x3e: /* DS override */
+ set_seg_override(c, (c->b >> 3) & 3);
+ break;
+ case 0x64: /* FS override */
+ case 0x65: /* GS override */
+ set_seg_override(c, c->b & 7);
+ break;
+ case 0x40 ... 0x4f: /* REX */
+ if (mode != X86EMUL_MODE_PROT64)
+ goto done_prefixes;
+ c->rex_prefix = c->b;
+ continue;
+ case 0xf0: /* LOCK */
+ c->lock_prefix = 1;
+ break;
+ case 0xf2: /* REPNE/REPNZ */
+ c->rep_prefix = REPNE_PREFIX;
+ break;
+ case 0xf3: /* REP/REPE/REPZ */
+ c->rep_prefix = REPE_PREFIX;
+ break;
+ default:
+ goto done_prefixes;
+ }
+
+ /* Any legacy prefix after a REX prefix nullifies its effect. */
+
+ c->rex_prefix = 0;
+ }
+
+done_prefixes:
+
+ /* REX prefix. */
+ if (c->rex_prefix & 8)
+ c->op_bytes = 8; /* REX.W */
+
+ /* Opcode byte(s). */
+ opcode = opcode_table[c->b];
+ /* Two-byte opcode? */
+ if (c->b == 0x0f) {
+ c->twobyte = 1;
+ c->b = insn_fetch(u8, 1, c->eip);
+ opcode = twobyte_table[c->b];
+ }
+ c->d = opcode.flags;
+
+ if (c->d & Group) {
+ dual = c->d & GroupDual;
+ c->modrm = insn_fetch(u8, 1, c->eip);
+ --c->eip;
+
+ if (c->d & GroupDual) {
+ g_mod012 = opcode.u.gdual->mod012;
+ g_mod3 = opcode.u.gdual->mod3;
+ } else
+ g_mod012 = g_mod3 = opcode.u.group;
+
+ c->d &= ~(Group | GroupDual);
+
+ goffset = (c->modrm >> 3) & 7;
+
+ if ((c->modrm >> 6) == 3)
+ opcode = g_mod3[goffset];
+ else
+ opcode = g_mod012[goffset];
+ c->d |= opcode.flags;
+ }
+
+ c->execute = opcode.u.execute;
+
+ /* Unrecognised? */
+ if (c->d == 0 || (c->d & Undefined)) {
+ DPRINTF("Cannot emulate %02x\n", c->b);
+ return -1;
+ }
+
+ if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack))
+ c->op_bytes = 8;
+
+ if (c->d & Op3264) {
+ if (mode == X86EMUL_MODE_PROT64)
+ c->op_bytes = 8;
+ else
+ c->op_bytes = 4;
+ }
+
+ /* ModRM and SIB bytes. */
+ if (c->d & ModRM) {
+ rc = decode_modrm(ctxt, ops, &memop);
+ if (!c->has_seg_override)
+ set_seg_override(c, c->modrm_seg);
+ } else if (c->d & MemAbs)
+ rc = decode_abs(ctxt, ops, &memop);
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+
+ if (!c->has_seg_override)
+ set_seg_override(c, VCPU_SREG_DS);
+
+ if (memop.type == OP_MEM && !(!c->twobyte && c->b == 0x8d))
+ memop.addr.mem += seg_override_base(ctxt, ops, c);
+
+ if (memop.type == OP_MEM && c->ad_bytes != 8)
+ memop.addr.mem = (u32)memop.addr.mem;
+
+ if (memop.type == OP_MEM && c->rip_relative)
+ memop.addr.mem += c->eip;
+
+ /*
+ * Decode and fetch the source operand: register, memory
+ * or immediate.
+ */
+ switch (c->d & SrcMask) {
+ case SrcNone:
+ break;
+ case SrcReg:
+ decode_register_operand(&c->src, c, 0);
+ break;
+ case SrcMem16:
+ memop.bytes = 2;
+ goto srcmem_common;
+ case SrcMem32:
+ memop.bytes = 4;
+ goto srcmem_common;
+ case SrcMem:
+ memop.bytes = (c->d & ByteOp) ? 1 :
+ c->op_bytes;
+ srcmem_common:
+ c->src = memop;
+ break;
+ case SrcImmU16:
+ rc = decode_imm(ctxt, &c->src, 2, false);
+ break;
+ case SrcImm:
+ rc = decode_imm(ctxt, &c->src, imm_size(c), true);
+ break;
+ case SrcImmU:
+ rc = decode_imm(ctxt, &c->src, imm_size(c), false);
+ break;
+ case SrcImmByte:
+ rc = decode_imm(ctxt, &c->src, 1, true);
+ break;
+ case SrcImmUByte:
+ rc = decode_imm(ctxt, &c->src, 1, false);
+ break;
+ case SrcAcc:
+ c->src.type = OP_REG;
+ c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+ c->src.addr.reg = &c->regs[VCPU_REGS_RAX];
+ fetch_register_operand(&c->src);
+ break;
+ case SrcOne:
+ c->src.bytes = 1;
+ c->src.val = 1;
+ break;
+ case SrcSI:
+ c->src.type = OP_MEM;
+ c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+ c->src.addr.mem =
+ register_address(c, seg_override_base(ctxt, ops, c),
+ c->regs[VCPU_REGS_RSI]);
+ c->src.val = 0;
+ break;
+ case SrcImmFAddr:
+ c->src.type = OP_IMM;
+ c->src.addr.mem = c->eip;
+ c->src.bytes = c->op_bytes + 2;
+ insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip);
+ break;
+ case SrcMemFAddr:
+ memop.bytes = c->op_bytes + 2;
+ goto srcmem_common;
+ break;
+ }
+
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+
+ /*
+ * Decode and fetch the second source operand: register, memory
+ * or immediate.
+ */
+ switch (c->d & Src2Mask) {
+ case Src2None:
+ break;
+ case Src2CL:
+ c->src2.bytes = 1;
+ c->src2.val = c->regs[VCPU_REGS_RCX] & 0x8;
+ break;
+ case Src2ImmByte:
+ rc = decode_imm(ctxt, &c->src2, 1, true);
+ break;
+ case Src2One:
+ c->src2.bytes = 1;
+ c->src2.val = 1;
+ break;
+ case Src2Imm:
+ rc = decode_imm(ctxt, &c->src2, imm_size(c), true);
+ break;
+ }
+
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+
+ /* Decode and fetch the destination operand: register or memory. */
+ switch (c->d & DstMask) {
+ case DstReg:
+ decode_register_operand(&c->dst, c,
+ c->twobyte && (c->b == 0xb6 || c->b == 0xb7));
+ break;
+ case DstImmUByte:
+ c->dst.type = OP_IMM;
+ c->dst.addr.mem = c->eip;
+ c->dst.bytes = 1;
+ c->dst.val = insn_fetch(u8, 1, c->eip);
+ break;
+ case DstMem:
+ case DstMem64:
+ c->dst = memop;
+ if ((c->d & DstMask) == DstMem64)
+ c->dst.bytes = 8;
+ else
+ c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+ if (c->d & BitOp)
+ fetch_bit_operand(c);
+ c->dst.orig_val = c->dst.val;
+ break;
+ case DstAcc:
+ c->dst.type = OP_REG;
+ c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+ c->dst.addr.reg = &c->regs[VCPU_REGS_RAX];
+ fetch_register_operand(&c->dst);
+ c->dst.orig_val = c->dst.val;
+ break;
+ case DstDI:
+ c->dst.type = OP_MEM;
+ c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+ c->dst.addr.mem =
+ register_address(c, es_base(ctxt, ops),
+ c->regs[VCPU_REGS_RDI]);
+ c->dst.val = 0;
+ break;
+ case ImplicitOps:
+ /* Special instructions do their own operand decoding. */
+ default:
+ c->dst.type = OP_NONE; /* Disable writeback. */
+ return 0;
+ }
+
+done:
+ return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+}
+
+static bool string_insn_completed(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ /* The second termination condition only applies for REPE
+ * and REPNE. Test if the repeat string operation prefix is
+ * REPE/REPZ or REPNE/REPNZ and if it's the case it tests the
+ * corresponding termination condition according to:
+ * - if REPE/REPZ and ZF = 0 then done
+ * - if REPNE/REPNZ and ZF = 1 then done
+ */
+ if (((c->b == 0xa6) || (c->b == 0xa7) ||
+ (c->b == 0xae) || (c->b == 0xaf))
+ && (((c->rep_prefix == REPE_PREFIX) &&
+ ((ctxt->eflags & EFLG_ZF) == 0))
+ || ((c->rep_prefix == REPNE_PREFIX) &&
+ ((ctxt->eflags & EFLG_ZF) == EFLG_ZF))))
+ return true;
+
+ return false;
+}
+
+int
+x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
+{
+ struct x86_emulate_ops *ops = ctxt->ops;
u64 msr_data;
struct decode_cache *c = &ctxt->decode;
int rc = X86EMUL_CONTINUE;
int saved_dst_type = c->dst.type;
+ int irq; /* Used for int 3, int, and into */
ctxt->decode.mem_read.pos = 0;
@@ -2576,6 +3030,11 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
goto done;
}
+ if ((c->d & SrcMask) == SrcMemFAddr && c->src.type != OP_MEM) {
+ emulate_ud(ctxt);
+ goto done;
+ }
+
/* Privileged instruction can be executed only in CPL=0 */
if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) {
emulate_gp(ctxt, 0);
@@ -2583,35 +3042,15 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
}
if (c->rep_prefix && (c->d & String)) {
- ctxt->restart = true;
/* All REP prefixes have the same first termination condition */
if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) {
- string_done:
- ctxt->restart = false;
ctxt->eip = c->eip;
goto done;
}
- /* The second termination condition only applies for REPE
- * and REPNE. Test if the repeat string operation prefix is
- * REPE/REPZ or REPNE/REPNZ and if it's the case it tests the
- * corresponding termination condition according to:
- * - if REPE/REPZ and ZF = 0 then done
- * - if REPNE/REPNZ and ZF = 1 then done
- */
- if ((c->b == 0xa6) || (c->b == 0xa7) ||
- (c->b == 0xae) || (c->b == 0xaf)) {
- if ((c->rep_prefix == REPE_PREFIX) &&
- ((ctxt->eflags & EFLG_ZF) == 0))
- goto string_done;
- if ((c->rep_prefix == REPNE_PREFIX) &&
- ((ctxt->eflags & EFLG_ZF) == EFLG_ZF))
- goto string_done;
- }
- c->eip = ctxt->eip;
}
- if (c->src.type == OP_MEM) {
- rc = read_emulated(ctxt, ops, (unsigned long)c->src.ptr,
+ if ((c->src.type == OP_MEM) && !(c->d & NoAccess)) {
+ rc = read_emulated(ctxt, ops, c->src.addr.mem,
c->src.valptr, c->src.bytes);
if (rc != X86EMUL_CONTINUE)
goto done;
@@ -2619,7 +3058,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
}
if (c->src2.type == OP_MEM) {
- rc = read_emulated(ctxt, ops, (unsigned long)c->src2.ptr,
+ rc = read_emulated(ctxt, ops, c->src2.addr.mem,
&c->src2.val, c->src2.bytes);
if (rc != X86EMUL_CONTINUE)
goto done;
@@ -2631,7 +3070,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
if ((c->dst.type == OP_MEM) && !(c->d & Mov)) {
/* optimisation - avoid slow emulated read if Mov */
- rc = read_emulated(ctxt, ops, (unsigned long)c->dst.ptr,
+ rc = read_emulated(ctxt, ops, c->dst.addr.mem,
&c->dst.val, c->dst.bytes);
if (rc != X86EMUL_CONTINUE)
goto done;
@@ -2640,6 +3079,13 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
special_insn:
+ if (c->execute) {
+ rc = c->execute(ctxt);
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+ goto writeback;
+ }
+
if (c->twobyte)
goto twobyte_insn;
@@ -2653,8 +3099,6 @@ special_insn:
break;
case 0x07: /* pop es */
rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_ES);
- if (rc != X86EMUL_CONTINUE)
- goto done;
break;
case 0x08 ... 0x0d:
or: /* or */
@@ -2672,8 +3116,6 @@ special_insn:
break;
case 0x17: /* pop ss */
rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_SS);
- if (rc != X86EMUL_CONTINUE)
- goto done;
break;
case 0x18 ... 0x1d:
sbb: /* sbb */
@@ -2684,8 +3126,6 @@ special_insn:
break;
case 0x1f: /* pop ds */
rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_DS);
- if (rc != X86EMUL_CONTINUE)
- goto done;
break;
case 0x20 ... 0x25:
and: /* and */
@@ -2709,58 +3149,29 @@ special_insn:
case 0x48 ... 0x4f: /* dec r16/r32 */
emulate_1op("dec", c->dst, ctxt->eflags);
break;
- case 0x50 ... 0x57: /* push reg */
- emulate_push(ctxt, ops);
- break;
case 0x58 ... 0x5f: /* pop reg */
pop_instruction:
rc = emulate_pop(ctxt, ops, &c->dst.val, c->op_bytes);
- if (rc != X86EMUL_CONTINUE)
- goto done;
break;
case 0x60: /* pusha */
rc = emulate_pusha(ctxt, ops);
- if (rc != X86EMUL_CONTINUE)
- goto done;
break;
case 0x61: /* popa */
rc = emulate_popa(ctxt, ops);
- if (rc != X86EMUL_CONTINUE)
- goto done;
break;
case 0x63: /* movsxd */
if (ctxt->mode != X86EMUL_MODE_PROT64)
goto cannot_emulate;
c->dst.val = (s32) c->src.val;
break;
- case 0x68: /* push imm */
- case 0x6a: /* push imm8 */
- emulate_push(ctxt, ops);
- break;
case 0x6c: /* insb */
case 0x6d: /* insw/insd */
- c->dst.bytes = min(c->dst.bytes, 4u);
- if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
- c->dst.bytes)) {
- emulate_gp(ctxt, 0);
- goto done;
- }
- if (!pio_in_emulated(ctxt, ops, c->dst.bytes,
- c->regs[VCPU_REGS_RDX], &c->dst.val))
- goto done; /* IO is needed, skip writeback */
- break;
+ c->src.val = c->regs[VCPU_REGS_RDX];
+ goto do_io_in;
case 0x6e: /* outsb */
case 0x6f: /* outsw/outsd */
- c->src.bytes = min(c->src.bytes, 4u);
- if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
- c->src.bytes)) {
- emulate_gp(ctxt, 0);
- goto done;
- }
- ops->pio_out_emulated(c->src.bytes, c->regs[VCPU_REGS_RDX],
- &c->src.val, 1, ctxt->vcpu);
-
- c->dst.type = OP_NONE; /* nothing to writeback */
+ c->dst.val = c->regs[VCPU_REGS_RDX];
+ goto do_io_out;
break;
case 0x70 ... 0x7f: /* jcc (short) */
if (test_cc(c->b, ctxt->eflags))
@@ -2793,29 +3204,15 @@ special_insn:
case 0x86 ... 0x87: /* xchg */
xchg:
/* Write back the register source. */
- switch (c->dst.bytes) {
- case 1:
- *(u8 *) c->src.ptr = (u8) c->dst.val;
- break;
- case 2:
- *(u16 *) c->src.ptr = (u16) c->dst.val;
- break;
- case 4:
- *c->src.ptr = (u32) c->dst.val;
- break; /* 64b reg: zero-extend */
- case 8:
- *c->src.ptr = c->dst.val;
- break;
- }
+ c->src.val = c->dst.val;
+ write_register_operand(&c->src);
/*
* Write back the memory destination with implicit LOCK
* prefix.
*/
- c->dst.val = c->src.val;
+ c->dst.val = c->src.orig_val;
c->lock_prefix = 1;
break;
- case 0x88 ... 0x8b: /* mov */
- goto mov;
case 0x8c: /* mov r/m, sreg */
if (c->modrm_reg > VCPU_SREG_GS) {
emulate_ud(ctxt);
@@ -2824,7 +3221,7 @@ special_insn:
c->dst.val = ops->get_segment_selector(c->modrm_reg, ctxt->vcpu);
break;
case 0x8d: /* lea r16/r32, m */
- c->dst.val = c->modrm_ea;
+ c->dst.val = c->src.addr.mem;
break;
case 0x8e: { /* mov seg, r/m16 */
uint16_t sel;
@@ -2847,76 +3244,87 @@ special_insn:
}
case 0x8f: /* pop (sole member of Grp1a) */
rc = emulate_grp1a(ctxt, ops);
- if (rc != X86EMUL_CONTINUE)
- goto done;
break;
- case 0x90: /* nop / xchg r8,rax */
- if (c->dst.ptr == (unsigned long *)&c->regs[VCPU_REGS_RAX]) {
- c->dst.type = OP_NONE; /* nop */
+ case 0x90 ... 0x97: /* nop / xchg reg, rax */
+ if (c->dst.addr.reg == &c->regs[VCPU_REGS_RAX])
break;
- }
- case 0x91 ... 0x97: /* xchg reg,rax */
- c->src.type = OP_REG;
- c->src.bytes = c->op_bytes;
- c->src.ptr = (unsigned long *) &c->regs[VCPU_REGS_RAX];
- c->src.val = *(c->src.ptr);
goto xchg;
+ case 0x98: /* cbw/cwde/cdqe */
+ switch (c->op_bytes) {
+ case 2: c->dst.val = (s8)c->dst.val; break;
+ case 4: c->dst.val = (s16)c->dst.val; break;
+ case 8: c->dst.val = (s32)c->dst.val; break;
+ }
+ break;
case 0x9c: /* pushf */
c->src.val = (unsigned long) ctxt->eflags;
emulate_push(ctxt, ops);
break;
case 0x9d: /* popf */
c->dst.type = OP_REG;
- c->dst.ptr = (unsigned long *) &ctxt->eflags;
+ c->dst.addr.reg = &ctxt->eflags;
c->dst.bytes = c->op_bytes;
rc = emulate_popf(ctxt, ops, &c->dst.val, c->op_bytes);
- if (rc != X86EMUL_CONTINUE)
- goto done;
break;
- case 0xa0 ... 0xa3: /* mov */
- case 0xa4 ... 0xa5: /* movs */
- goto mov;
case 0xa6 ... 0xa7: /* cmps */
c->dst.type = OP_NONE; /* Disable writeback. */
- DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.ptr, c->dst.ptr);
+ DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.addr.mem, c->dst.addr.mem);
goto cmp;
case 0xa8 ... 0xa9: /* test ax, imm */
goto test;
- case 0xaa ... 0xab: /* stos */
- c->dst.val = c->regs[VCPU_REGS_RAX];
- break;
- case 0xac ... 0xad: /* lods */
- goto mov;
case 0xae ... 0xaf: /* scas */
- DPRINTF("Urk! I don't handle SCAS.\n");
- goto cannot_emulate;
- case 0xb0 ... 0xbf: /* mov r, imm */
- goto mov;
+ goto cmp;
case 0xc0 ... 0xc1:
emulate_grp2(ctxt);
break;
case 0xc3: /* ret */
c->dst.type = OP_REG;
- c->dst.ptr = &c->eip;
+ c->dst.addr.reg = &c->eip;
c->dst.bytes = c->op_bytes;
goto pop_instruction;
- case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */
- mov:
- c->dst.val = c->src.val;
+ case 0xc4: /* les */
+ rc = emulate_load_segment(ctxt, ops, VCPU_SREG_ES);
+ break;
+ case 0xc5: /* lds */
+ rc = emulate_load_segment(ctxt, ops, VCPU_SREG_DS);
break;
case 0xcb: /* ret far */
rc = emulate_ret_far(ctxt, ops);
- if (rc != X86EMUL_CONTINUE)
- goto done;
+ break;
+ case 0xcc: /* int3 */
+ irq = 3;
+ goto do_interrupt;
+ case 0xcd: /* int n */
+ irq = c->src.val;
+ do_interrupt:
+ rc = emulate_int(ctxt, ops, irq);
+ break;
+ case 0xce: /* into */
+ if (ctxt->eflags & EFLG_OF) {
+ irq = 4;
+ goto do_interrupt;
+ }
+ break;
+ case 0xcf: /* iret */
+ rc = emulate_iret(ctxt, ops);
break;
case 0xd0 ... 0xd1: /* Grp2 */
- c->src.val = 1;
emulate_grp2(ctxt);
break;
case 0xd2 ... 0xd3: /* Grp2 */
c->src.val = c->regs[VCPU_REGS_RCX];
emulate_grp2(ctxt);
break;
+ case 0xe0 ... 0xe2: /* loop/loopz/loopnz */
+ register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1);
+ if (address_mask(c, c->regs[VCPU_REGS_RCX]) != 0 &&
+ (c->b == 0xe2 || test_cc(c->b ^ 0x5, ctxt->eflags)))
+ jmp_rel(c, c->src.val);
+ break;
+ case 0xe3: /* jcxz/jecxz/jrcxz */
+ if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0)
+ jmp_rel(c, c->src.val);
+ break;
case 0xe4: /* inb */
case 0xe5: /* in */
goto do_io_in;
@@ -2964,15 +3372,16 @@ special_insn:
break;
case 0xee: /* out dx,al */
case 0xef: /* out dx,(e/r)ax */
- c->src.val = c->regs[VCPU_REGS_RDX];
+ c->dst.val = c->regs[VCPU_REGS_RDX];
do_io_out:
- c->dst.bytes = min(c->dst.bytes, 4u);
- if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) {
+ c->src.bytes = min(c->src.bytes, 4u);
+ if (!emulator_io_permited(ctxt, ops, c->dst.val,
+ c->src.bytes)) {
emulate_gp(ctxt, 0);
goto done;
}
- ops->pio_out_emulated(c->dst.bytes, c->src.val, &c->dst.val, 1,
- ctxt->vcpu);
+ ops->pio_out_emulated(c->src.bytes, c->dst.val,
+ &c->src.val, 1, ctxt->vcpu);
c->dst.type = OP_NONE; /* Disable writeback. */
break;
case 0xf4: /* hlt */
@@ -2981,24 +3390,22 @@ special_insn:
case 0xf5: /* cmc */
/* complement carry flag from eflags reg */
ctxt->eflags ^= EFLG_CF;
- c->dst.type = OP_NONE; /* Disable writeback. */
break;
case 0xf6 ... 0xf7: /* Grp3 */
- if (!emulate_grp3(ctxt, ops))
- goto cannot_emulate;
+ rc = emulate_grp3(ctxt, ops);
break;
case 0xf8: /* clc */
ctxt->eflags &= ~EFLG_CF;
- c->dst.type = OP_NONE; /* Disable writeback. */
+ break;
+ case 0xf9: /* stc */
+ ctxt->eflags |= EFLG_CF;
break;
case 0xfa: /* cli */
if (emulator_bad_iopl(ctxt, ops)) {
emulate_gp(ctxt, 0);
goto done;
- } else {
+ } else
ctxt->eflags &= ~X86_EFLAGS_IF;
- c->dst.type = OP_NONE; /* Disable writeback. */
- }
break;
case 0xfb: /* sti */
if (emulator_bad_iopl(ctxt, ops)) {
@@ -3007,29 +3414,29 @@ special_insn:
} else {
ctxt->interruptibility = KVM_X86_SHADOW_INT_STI;
ctxt->eflags |= X86_EFLAGS_IF;
- c->dst.type = OP_NONE; /* Disable writeback. */
}
break;
case 0xfc: /* cld */
ctxt->eflags &= ~EFLG_DF;
- c->dst.type = OP_NONE; /* Disable writeback. */
break;
case 0xfd: /* std */
ctxt->eflags |= EFLG_DF;
- c->dst.type = OP_NONE; /* Disable writeback. */
break;
case 0xfe: /* Grp4 */
grp45:
rc = emulate_grp45(ctxt, ops);
- if (rc != X86EMUL_CONTINUE)
- goto done;
break;
case 0xff: /* Grp5 */
if (c->modrm_reg == 5)
goto jump_far;
goto grp45;
+ default:
+ goto cannot_emulate;
}
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+
writeback:
rc = writeback(ctxt, ops);
if (rc != X86EMUL_CONTINUE)
@@ -3050,25 +3457,32 @@ writeback:
&c->dst);
if (c->rep_prefix && (c->d & String)) {
- struct read_cache *rc = &ctxt->decode.io_read;
+ struct read_cache *r = &ctxt->decode.io_read;
register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1);
- /*
- * Re-enter guest when pio read ahead buffer is empty or,
- * if it is not used, after each 1024 iteration.
- */
- if ((rc->end == 0 && !(c->regs[VCPU_REGS_RCX] & 0x3ff)) ||
- (rc->end != 0 && rc->end == rc->pos))
- ctxt->restart = false;
+
+ if (!string_insn_completed(ctxt)) {
+ /*
+ * Re-enter guest when pio read ahead buffer is empty
+ * or, if it is not used, after each 1024 iteration.
+ */
+ if ((r->end != 0 || c->regs[VCPU_REGS_RCX] & 0x3ff) &&
+ (r->end == 0 || r->end != r->pos)) {
+ /*
+ * Reset read cache. Usually happens before
+ * decode, but since instruction is restarted
+ * we have to do it here.
+ */
+ ctxt->decode.mem_read.end = 0;
+ return EMULATION_RESTART;
+ }
+ goto done; /* skip rip writeback */
+ }
}
- /*
- * reset read cache here in case string instruction is restared
- * without decoding
- */
- ctxt->decode.mem_read.end = 0;
+
ctxt->eip = c->eip;
done:
- return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+ return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK;
twobyte_insn:
switch (c->b) {
@@ -3091,7 +3505,7 @@ twobyte_insn:
c->dst.type = OP_NONE;
break;
case 2: /* lgdt */
- rc = read_descriptor(ctxt, ops, c->src.ptr,
+ rc = read_descriptor(ctxt, ops, c->src.addr.mem,
&size, &address, c->op_bytes);
if (rc != X86EMUL_CONTINUE)
goto done;
@@ -3104,14 +3518,12 @@ twobyte_insn:
switch (c->modrm_rm) {
case 1:
rc = kvm_fix_hypercall(ctxt->vcpu);
- if (rc != X86EMUL_CONTINUE)
- goto done;
break;
default:
goto cannot_emulate;
}
} else {
- rc = read_descriptor(ctxt, ops, c->src.ptr,
+ rc = read_descriptor(ctxt, ops, c->src.addr.mem,
&size, &address,
c->op_bytes);
if (rc != X86EMUL_CONTINUE)
@@ -3126,7 +3538,7 @@ twobyte_insn:
c->dst.val = ops->get_cr(0, ctxt->vcpu);
break;
case 6: /* lmsw */
- ops->set_cr(0, (ops->get_cr(0, ctxt->vcpu) & ~0x0ful) |
+ ops->set_cr(0, (ops->get_cr(0, ctxt->vcpu) & ~0x0eul) |
(c->src.val & 0x0f), ctxt->vcpu);
c->dst.type = OP_NONE;
break;
@@ -3134,7 +3546,7 @@ twobyte_insn:
emulate_ud(ctxt);
goto done;
case 7: /* invlpg*/
- emulate_invlpg(ctxt->vcpu, c->modrm_ea);
+ emulate_invlpg(ctxt->vcpu, c->src.addr.mem);
/* Disable writeback. */
c->dst.type = OP_NONE;
break;
@@ -3144,23 +3556,16 @@ twobyte_insn:
break;
case 0x05: /* syscall */
rc = emulate_syscall(ctxt, ops);
- if (rc != X86EMUL_CONTINUE)
- goto done;
- else
- goto writeback;
break;
case 0x06:
emulate_clts(ctxt->vcpu);
- c->dst.type = OP_NONE;
break;
case 0x09: /* wbinvd */
kvm_emulate_wbinvd(ctxt->vcpu);
- c->dst.type = OP_NONE;
break;
case 0x08: /* invd */
case 0x0d: /* GrpP (prefetch) */
case 0x18: /* Grp16 (prefetch/nop) */
- c->dst.type = OP_NONE;
break;
case 0x20: /* mov cr, reg */
switch (c->modrm_reg) {
@@ -3170,8 +3575,7 @@ twobyte_insn:
emulate_ud(ctxt);
goto done;
}
- c->regs[c->modrm_rm] = ops->get_cr(c->modrm_reg, ctxt->vcpu);
- c->dst.type = OP_NONE; /* no writeback */
+ c->dst.val = ops->get_cr(c->modrm_reg, ctxt->vcpu);
break;
case 0x21: /* mov from dr to reg */
if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
@@ -3179,11 +3583,10 @@ twobyte_insn:
emulate_ud(ctxt);
goto done;
}
- ops->get_dr(c->modrm_reg, &c->regs[c->modrm_rm], ctxt->vcpu);
- c->dst.type = OP_NONE; /* no writeback */
+ ops->get_dr(c->modrm_reg, &c->dst.val, ctxt->vcpu);
break;
case 0x22: /* mov reg, cr */
- if (ops->set_cr(c->modrm_reg, c->modrm_val, ctxt->vcpu)) {
+ if (ops->set_cr(c->modrm_reg, c->src.val, ctxt->vcpu)) {
emulate_gp(ctxt, 0);
goto done;
}
@@ -3196,7 +3599,7 @@ twobyte_insn:
goto done;
}
- if (ops->set_dr(c->modrm_reg, c->regs[c->modrm_rm] &
+ if (ops->set_dr(c->modrm_reg, c->src.val &
((ctxt->mode == X86EMUL_MODE_PROT64) ?
~0ULL : ~0U), ctxt->vcpu) < 0) {
/* #UD condition is already handled by the code above */
@@ -3215,7 +3618,6 @@ twobyte_insn:
goto done;
}
rc = X86EMUL_CONTINUE;
- c->dst.type = OP_NONE;
break;
case 0x32:
/* rdmsr */
@@ -3227,21 +3629,12 @@ twobyte_insn:
c->regs[VCPU_REGS_RDX] = msr_data >> 32;
}
rc = X86EMUL_CONTINUE;
- c->dst.type = OP_NONE;
break;
case 0x34: /* sysenter */
rc = emulate_sysenter(ctxt, ops);
- if (rc != X86EMUL_CONTINUE)
- goto done;
- else
- goto writeback;
break;
case 0x35: /* sysexit */
rc = emulate_sysexit(ctxt, ops);
- if (rc != X86EMUL_CONTINUE)
- goto done;
- else
- goto writeback;
break;
case 0x40 ... 0x4f: /* cmov */
c->dst.val = c->dst.orig_val = c->src.val;
@@ -3251,15 +3644,15 @@ twobyte_insn:
case 0x80 ... 0x8f: /* jnz rel, etc*/
if (test_cc(c->b, ctxt->eflags))
jmp_rel(c, c->src.val);
- c->dst.type = OP_NONE;
+ break;
+ case 0x90 ... 0x9f: /* setcc r/m8 */
+ c->dst.val = test_cc(c->b, ctxt->eflags);
break;
case 0xa0: /* push fs */
emulate_push_sreg(ctxt, ops, VCPU_SREG_FS);
break;
case 0xa1: /* pop fs */
rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_FS);
- if (rc != X86EMUL_CONTINUE)
- goto done;
break;
case 0xa3:
bt: /* bt */
@@ -3277,13 +3670,9 @@ twobyte_insn:
break;
case 0xa9: /* pop gs */
rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_GS);
- if (rc != X86EMUL_CONTINUE)
- goto done;
break;
case 0xab:
bts: /* bts */
- /* only subword offset */
- c->src.val &= (c->dst.bytes << 3) - 1;
emulate_2op_SrcV_nobyte("bts", c->src, c->dst, ctxt->eflags);
break;
case 0xac: /* shrd imm8, r, r/m */
@@ -3306,15 +3695,22 @@ twobyte_insn:
} else {
/* Failure: write the value we saw to EAX. */
c->dst.type = OP_REG;
- c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
+ c->dst.addr.reg = (unsigned long *)&c->regs[VCPU_REGS_RAX];
}
break;
+ case 0xb2: /* lss */
+ rc = emulate_load_segment(ctxt, ops, VCPU_SREG_SS);
+ break;
case 0xb3:
btr: /* btr */
- /* only subword offset */
- c->src.val &= (c->dst.bytes << 3) - 1;
emulate_2op_SrcV_nobyte("btr", c->src, c->dst, ctxt->eflags);
break;
+ case 0xb4: /* lfs */
+ rc = emulate_load_segment(ctxt, ops, VCPU_SREG_FS);
+ break;
+ case 0xb5: /* lgs */
+ rc = emulate_load_segment(ctxt, ops, VCPU_SREG_GS);
+ break;
case 0xb6 ... 0xb7: /* movzx */
c->dst.bytes = c->op_bytes;
c->dst.val = (c->d & ByteOp) ? (u8) c->src.val
@@ -3334,15 +3730,43 @@ twobyte_insn:
break;
case 0xbb:
btc: /* btc */
- /* only subword offset */
- c->src.val &= (c->dst.bytes << 3) - 1;
emulate_2op_SrcV_nobyte("btc", c->src, c->dst, ctxt->eflags);
break;
+ case 0xbc: { /* bsf */
+ u8 zf;
+ __asm__ ("bsf %2, %0; setz %1"
+ : "=r"(c->dst.val), "=q"(zf)
+ : "r"(c->src.val));
+ ctxt->eflags &= ~X86_EFLAGS_ZF;
+ if (zf) {
+ ctxt->eflags |= X86_EFLAGS_ZF;
+ c->dst.type = OP_NONE; /* Disable writeback. */
+ }
+ break;
+ }
+ case 0xbd: { /* bsr */
+ u8 zf;
+ __asm__ ("bsr %2, %0; setz %1"
+ : "=r"(c->dst.val), "=q"(zf)
+ : "r"(c->src.val));
+ ctxt->eflags &= ~X86_EFLAGS_ZF;
+ if (zf) {
+ ctxt->eflags |= X86_EFLAGS_ZF;
+ c->dst.type = OP_NONE; /* Disable writeback. */
+ }
+ break;
+ }
case 0xbe ... 0xbf: /* movsx */
c->dst.bytes = c->op_bytes;
c->dst.val = (c->d & ByteOp) ? (s8) c->src.val :
(s16) c->src.val;
break;
+ case 0xc0 ... 0xc1: /* xadd */
+ emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags);
+ /* Write back the register source. */
+ c->src.val = c->dst.orig_val;
+ write_register_operand(&c->src);
+ break;
case 0xc3: /* movnti */
c->dst.bytes = c->op_bytes;
c->dst.val = (c->op_bytes == 4) ? (u32) c->src.val :
@@ -3350,10 +3774,14 @@ twobyte_insn:
break;
case 0xc7: /* Grp9 (cmpxchg8b) */
rc = emulate_grp9(ctxt, ops);
- if (rc != X86EMUL_CONTINUE)
- goto done;
break;
+ default:
+ goto cannot_emulate;
}
+
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+
goto writeback;
cannot_emulate:
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index ddeb2314b522..efad72385058 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -5,7 +5,7 @@
* Copyright (c) 2006 Intel Corporation
* Copyright (c) 2007 Keir Fraser, XenSource Inc
* Copyright (c) 2008 Intel Corporation
- * Copyright 2009 Red Hat, Inc. and/or its affilates.
+ * Copyright 2009 Red Hat, Inc. and/or its affiliates.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -232,15 +232,6 @@ static void pit_latch_status(struct kvm *kvm, int channel)
}
}
-int pit_has_pending_timer(struct kvm_vcpu *vcpu)
-{
- struct kvm_pit *pit = vcpu->kvm->arch.vpit;
-
- if (pit && kvm_vcpu_is_bsp(vcpu) && pit->pit_state.irq_ack)
- return atomic_read(&pit->pit_state.pit_timer.pending);
- return 0;
-}
-
static void kvm_pit_ack_irq(struct kvm_irq_ack_notifier *kian)
{
struct kvm_kpit_state *ps = container_of(kian, struct kvm_kpit_state,
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c
index 4b7b73ce2098..f628234fbeca 100644
--- a/arch/x86/kvm/i8259.c
+++ b/arch/x86/kvm/i8259.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2003-2004 Fabrice Bellard
* Copyright (c) 2007 Intel Corporation
- * Copyright 2009 Red Hat, Inc. and/or its affilates.
+ * Copyright 2009 Red Hat, Inc. and/or its affiliates.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -39,7 +39,7 @@ static void pic_irq_request(struct kvm *kvm, int level);
static void pic_lock(struct kvm_pic *s)
__acquires(&s->lock)
{
- raw_spin_lock(&s->lock);
+ spin_lock(&s->lock);
}
static void pic_unlock(struct kvm_pic *s)
@@ -51,7 +51,7 @@ static void pic_unlock(struct kvm_pic *s)
s->wakeup_needed = false;
- raw_spin_unlock(&s->lock);
+ spin_unlock(&s->lock);
if (wakeup) {
kvm_for_each_vcpu(i, vcpu, s->kvm) {
@@ -67,6 +67,7 @@ static void pic_unlock(struct kvm_pic *s)
if (!found)
return;
+ kvm_make_request(KVM_REQ_EVENT, found);
kvm_vcpu_kick(found);
}
}
@@ -308,13 +309,17 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val)
addr &= 1;
if (addr == 0) {
if (val & 0x10) {
- kvm_pic_reset(s); /* init */
- /*
- * deassert a pending interrupt
- */
- pic_irq_request(s->pics_state->kvm, 0);
- s->init_state = 1;
s->init4 = val & 1;
+ s->last_irr = 0;
+ s->imr = 0;
+ s->priority_add = 0;
+ s->special_mask = 0;
+ s->read_reg_select = 0;
+ if (!s->init4) {
+ s->special_fully_nested_mode = 0;
+ s->auto_eoi = 0;
+ }
+ s->init_state = 1;
if (val & 0x02)
printk(KERN_ERR "single mode not supported");
if (val & 0x08)
@@ -564,7 +569,7 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm)
s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL);
if (!s)
return NULL;
- raw_spin_lock_init(&s->lock);
+ spin_lock_init(&s->lock);
s->kvm = kvm;
s->pics[0].elcr_mask = 0xf8;
s->pics[1].elcr_mask = 0xde;
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
index 2095a049835e..7e06ba1618bd 100644
--- a/arch/x86/kvm/irq.c
+++ b/arch/x86/kvm/irq.c
@@ -1,7 +1,7 @@
/*
* irq.c: API for in kernel interrupt controller
* Copyright (c) 2007, Intel Corporation.
- * Copyright 2009 Red Hat, Inc. and/or its affilates.
+ * Copyright 2009 Red Hat, Inc. and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -33,12 +33,7 @@
*/
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
{
- int ret;
-
- ret = pit_has_pending_timer(vcpu);
- ret |= apic_has_pending_timer(vcpu);
-
- return ret;
+ return apic_has_pending_timer(vcpu);
}
EXPORT_SYMBOL(kvm_cpu_has_pending_timer);
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
index 63c314502993..ba910d149410 100644
--- a/arch/x86/kvm/irq.h
+++ b/arch/x86/kvm/irq.h
@@ -60,7 +60,7 @@ struct kvm_kpic_state {
};
struct kvm_pic {
- raw_spinlock_t lock;
+ spinlock_t lock;
bool wakeup_needed;
unsigned pending_acks;
struct kvm *kvm;
diff --git a/arch/x86/kvm/kvm_cache_regs.h b/arch/x86/kvm/kvm_cache_regs.h
index 6491ac8e755b..975bb45329a1 100644
--- a/arch/x86/kvm/kvm_cache_regs.h
+++ b/arch/x86/kvm/kvm_cache_regs.h
@@ -42,7 +42,14 @@ static inline u64 kvm_pdptr_read(struct kvm_vcpu *vcpu, int index)
(unsigned long *)&vcpu->arch.regs_avail))
kvm_x86_ops->cache_reg(vcpu, VCPU_EXREG_PDPTR);
- return vcpu->arch.pdptrs[index];
+ return vcpu->arch.walk_mmu->pdptrs[index];
+}
+
+static inline u64 kvm_pdptr_read_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, int index)
+{
+ load_pdptrs(vcpu, mmu, mmu->get_cr3(vcpu));
+
+ return mmu->pdptrs[index];
}
static inline ulong kvm_read_cr0_bits(struct kvm_vcpu *vcpu, ulong mask)
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 22b06f7660f4..413f8973a855 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -5,7 +5,7 @@
* Copyright (C) 2006 Qumranet, Inc.
* Copyright (C) 2007 Novell
* Copyright (C) 2007 Intel
- * Copyright 2009 Red Hat, Inc. and/or its affilates.
+ * Copyright 2009 Red Hat, Inc. and/or its affiliates.
*
* Authors:
* Dor Laor <dor.laor@qumranet.com>
@@ -259,9 +259,10 @@ static inline int apic_find_highest_isr(struct kvm_lapic *apic)
static void apic_update_ppr(struct kvm_lapic *apic)
{
- u32 tpr, isrv, ppr;
+ u32 tpr, isrv, ppr, old_ppr;
int isr;
+ old_ppr = apic_get_reg(apic, APIC_PROCPRI);
tpr = apic_get_reg(apic, APIC_TASKPRI);
isr = apic_find_highest_isr(apic);
isrv = (isr != -1) ? isr : 0;
@@ -274,7 +275,10 @@ static void apic_update_ppr(struct kvm_lapic *apic)
apic_debug("vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x",
apic, ppr, isr, isrv);
- apic_set_reg(apic, APIC_PROCPRI, ppr);
+ if (old_ppr != ppr) {
+ apic_set_reg(apic, APIC_PROCPRI, ppr);
+ kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
+ }
}
static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr)
@@ -391,6 +395,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
break;
}
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
kvm_vcpu_kick(vcpu);
break;
@@ -416,6 +421,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
"INIT on a runnable vcpu %d\n",
vcpu->vcpu_id);
vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED;
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
kvm_vcpu_kick(vcpu);
} else {
apic_debug("Ignoring de-assert INIT to vcpu %d\n",
@@ -430,6 +436,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
result = 1;
vcpu->arch.sipi_vector = vector;
vcpu->arch.mp_state = KVM_MP_STATE_SIPI_RECEIVED;
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
kvm_vcpu_kick(vcpu);
}
break;
@@ -475,6 +482,7 @@ static void apic_set_eoi(struct kvm_lapic *apic)
trigger_mode = IOAPIC_EDGE_TRIG;
if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI))
kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode);
+ kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
}
static void apic_send_ipi(struct kvm_lapic *apic)
@@ -1151,6 +1159,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
update_divide_count(apic);
start_apic_timer(apic);
apic->irr_pending = true;
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
}
void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 311f6dad8951..908ea5464a51 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -7,7 +7,7 @@
* MMU support
*
* Copyright (C) 2006 Qumranet, Inc.
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
*
* Authors:
* Yaniv Kamay <yaniv@qumranet.com>
@@ -49,15 +49,25 @@
*/
bool tdp_enabled = false;
-#undef MMU_DEBUG
+enum {
+ AUDIT_PRE_PAGE_FAULT,
+ AUDIT_POST_PAGE_FAULT,
+ AUDIT_PRE_PTE_WRITE,
+ AUDIT_POST_PTE_WRITE,
+ AUDIT_PRE_SYNC,
+ AUDIT_POST_SYNC
+};
-#undef AUDIT
+char *audit_point_name[] = {
+ "pre page fault",
+ "post page fault",
+ "pre pte write",
+ "post pte write",
+ "pre sync",
+ "post sync"
+};
-#ifdef AUDIT
-static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg);
-#else
-static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {}
-#endif
+#undef MMU_DEBUG
#ifdef MMU_DEBUG
@@ -71,7 +81,7 @@ static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {}
#endif
-#if defined(MMU_DEBUG) || defined(AUDIT)
+#ifdef MMU_DEBUG
static int dbg = 0;
module_param(dbg, bool, 0644);
#endif
@@ -89,6 +99,8 @@ module_param(oos_shadow, bool, 0644);
}
#endif
+#define PTE_PREFETCH_NUM 8
+
#define PT_FIRST_AVAIL_BITS_SHIFT 9
#define PT64_SECOND_AVAIL_BITS_SHIFT 52
@@ -178,6 +190,7 @@ typedef void (*mmu_parent_walk_fn) (struct kvm_mmu_page *sp, u64 *spte);
static struct kmem_cache *pte_chain_cache;
static struct kmem_cache *rmap_desc_cache;
static struct kmem_cache *mmu_page_header_cache;
+static struct percpu_counter kvm_total_used_mmu_pages;
static u64 __read_mostly shadow_trap_nonpresent_pte;
static u64 __read_mostly shadow_notrap_nonpresent_pte;
@@ -299,18 +312,50 @@ static u64 __xchg_spte(u64 *sptep, u64 new_spte)
#endif
}
+static bool spte_has_volatile_bits(u64 spte)
+{
+ if (!shadow_accessed_mask)
+ return false;
+
+ if (!is_shadow_present_pte(spte))
+ return false;
+
+ if ((spte & shadow_accessed_mask) &&
+ (!is_writable_pte(spte) || (spte & shadow_dirty_mask)))
+ return false;
+
+ return true;
+}
+
+static bool spte_is_bit_cleared(u64 old_spte, u64 new_spte, u64 bit_mask)
+{
+ return (old_spte & bit_mask) && !(new_spte & bit_mask);
+}
+
static void update_spte(u64 *sptep, u64 new_spte)
{
- u64 old_spte;
+ u64 mask, old_spte = *sptep;
+
+ WARN_ON(!is_rmap_spte(new_spte));
+
+ new_spte |= old_spte & shadow_dirty_mask;
- if (!shadow_accessed_mask || (new_spte & shadow_accessed_mask) ||
- !is_rmap_spte(*sptep))
+ mask = shadow_accessed_mask;
+ if (is_writable_pte(old_spte))
+ mask |= shadow_dirty_mask;
+
+ if (!spte_has_volatile_bits(old_spte) || (new_spte & mask) == mask)
__set_spte(sptep, new_spte);
- else {
+ else
old_spte = __xchg_spte(sptep, new_spte);
- if (old_spte & shadow_accessed_mask)
- mark_page_accessed(pfn_to_page(spte_to_pfn(old_spte)));
- }
+
+ if (!shadow_accessed_mask)
+ return;
+
+ if (spte_is_bit_cleared(old_spte, new_spte, shadow_accessed_mask))
+ kvm_set_pfn_accessed(spte_to_pfn(old_spte));
+ if (spte_is_bit_cleared(old_spte, new_spte, shadow_dirty_mask))
+ kvm_set_pfn_dirty(spte_to_pfn(old_spte));
}
static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
@@ -367,7 +412,7 @@ static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu)
if (r)
goto out;
r = mmu_topup_memory_cache(&vcpu->arch.mmu_rmap_desc_cache,
- rmap_desc_cache, 4);
+ rmap_desc_cache, 4 + PTE_PREFETCH_NUM);
if (r)
goto out;
r = mmu_topup_memory_cache_page(&vcpu->arch.mmu_page_cache, 8);
@@ -591,6 +636,7 @@ static int rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
desc->sptes[0] = (u64 *)*rmapp;
desc->sptes[1] = spte;
*rmapp = (unsigned long)desc | 1;
+ ++count;
} else {
rmap_printk("rmap_add: %p %llx many->many\n", spte, *spte);
desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul);
@@ -603,7 +649,7 @@ static int rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
desc = desc->more;
}
for (i = 0; desc->sptes[i]; ++i)
- ;
+ ++count;
desc->sptes[i] = spte;
}
return count;
@@ -645,18 +691,17 @@ static void rmap_remove(struct kvm *kvm, u64 *spte)
gfn = kvm_mmu_page_get_gfn(sp, spte - sp->spt);
rmapp = gfn_to_rmap(kvm, gfn, sp->role.level);
if (!*rmapp) {
- printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte);
+ printk(KERN_ERR "rmap_remove: %p 0->BUG\n", spte);
BUG();
} else if (!(*rmapp & 1)) {
- rmap_printk("rmap_remove: %p %llx 1->0\n", spte, *spte);
+ rmap_printk("rmap_remove: %p 1->0\n", spte);
if ((u64 *)*rmapp != spte) {
- printk(KERN_ERR "rmap_remove: %p %llx 1->BUG\n",
- spte, *spte);
+ printk(KERN_ERR "rmap_remove: %p 1->BUG\n", spte);
BUG();
}
*rmapp = 0;
} else {
- rmap_printk("rmap_remove: %p %llx many->many\n", spte, *spte);
+ rmap_printk("rmap_remove: %p many->many\n", spte);
desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul);
prev_desc = NULL;
while (desc) {
@@ -670,7 +715,7 @@ static void rmap_remove(struct kvm *kvm, u64 *spte)
prev_desc = desc;
desc = desc->more;
}
- pr_err("rmap_remove: %p %llx many->many\n", spte, *spte);
+ pr_err("rmap_remove: %p many->many\n", spte);
BUG();
}
}
@@ -680,18 +725,18 @@ static void set_spte_track_bits(u64 *sptep, u64 new_spte)
pfn_t pfn;
u64 old_spte = *sptep;
- if (!shadow_accessed_mask || !is_shadow_present_pte(old_spte) ||
- old_spte & shadow_accessed_mask) {
+ if (!spte_has_volatile_bits(old_spte))
__set_spte(sptep, new_spte);
- } else
+ else
old_spte = __xchg_spte(sptep, new_spte);
if (!is_rmap_spte(old_spte))
return;
+
pfn = spte_to_pfn(old_spte);
if (!shadow_accessed_mask || old_spte & shadow_accessed_mask)
kvm_set_pfn_accessed(pfn);
- if (is_writable_pte(old_spte))
+ if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask))
kvm_set_pfn_dirty(pfn);
}
@@ -746,13 +791,6 @@ static int rmap_write_protect(struct kvm *kvm, u64 gfn)
}
spte = rmap_next(kvm, rmapp, spte);
}
- if (write_protected) {
- pfn_t pfn;
-
- spte = rmap_next(kvm, rmapp, NULL);
- pfn = spte_to_pfn(*spte);
- kvm_set_pfn_dirty(pfn);
- }
/* check for huge page mappings */
for (i = PT_DIRECTORY_LEVEL;
@@ -947,6 +985,18 @@ static int is_empty_shadow_page(u64 *spt)
}
#endif
+/*
+ * This value is the sum of all of the kvm instances's
+ * kvm->arch.n_used_mmu_pages values. We need a global,
+ * aggregate version in order to make the slab shrinker
+ * faster
+ */
+static inline void kvm_mod_used_mmu_pages(struct kvm *kvm, int nr)
+{
+ kvm->arch.n_used_mmu_pages += nr;
+ percpu_counter_add(&kvm_total_used_mmu_pages, nr);
+}
+
static void kvm_mmu_free_page(struct kvm *kvm, struct kvm_mmu_page *sp)
{
ASSERT(is_empty_shadow_page(sp->spt));
@@ -956,7 +1006,7 @@ static void kvm_mmu_free_page(struct kvm *kvm, struct kvm_mmu_page *sp)
if (!sp->role.direct)
__free_page(virt_to_page(sp->gfns));
kmem_cache_free(mmu_page_header_cache, sp);
- ++kvm->arch.n_free_mmu_pages;
+ kvm_mod_used_mmu_pages(kvm, -1);
}
static unsigned kvm_page_table_hashfn(gfn_t gfn)
@@ -979,7 +1029,7 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
bitmap_zero(sp->slot_bitmap, KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS);
sp->multimapped = 0;
sp->parent_pte = parent_pte;
- --vcpu->kvm->arch.n_free_mmu_pages;
+ kvm_mod_used_mmu_pages(vcpu->kvm, +1);
return sp;
}
@@ -1403,7 +1453,8 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
if (role.direct)
role.cr4_pae = 0;
role.access = access;
- if (!tdp_enabled && vcpu->arch.mmu.root_level <= PT32_ROOT_LEVEL) {
+ if (!vcpu->arch.mmu.direct_map
+ && vcpu->arch.mmu.root_level <= PT32_ROOT_LEVEL) {
quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level));
quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1;
role.quadrant = quadrant;
@@ -1458,6 +1509,12 @@ static void shadow_walk_init(struct kvm_shadow_walk_iterator *iterator,
iterator->addr = addr;
iterator->shadow_addr = vcpu->arch.mmu.root_hpa;
iterator->level = vcpu->arch.mmu.shadow_root_level;
+
+ if (iterator->level == PT64_ROOT_LEVEL &&
+ vcpu->arch.mmu.root_level < PT64_ROOT_LEVEL &&
+ !vcpu->arch.mmu.direct_map)
+ --iterator->level;
+
if (iterator->level == PT32E_ROOT_LEVEL) {
iterator->shadow_addr
= vcpu->arch.mmu.pae_root[(addr >> 30) & 3];
@@ -1665,41 +1722,31 @@ static void kvm_mmu_commit_zap_page(struct kvm *kvm,
/*
* Changing the number of mmu pages allocated to the vm
- * Note: if kvm_nr_mmu_pages is too small, you will get dead lock
+ * Note: if goal_nr_mmu_pages is too small, you will get dead lock
*/
-void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages)
+void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int goal_nr_mmu_pages)
{
- int used_pages;
LIST_HEAD(invalid_list);
-
- used_pages = kvm->arch.n_alloc_mmu_pages - kvm->arch.n_free_mmu_pages;
- used_pages = max(0, used_pages);
-
/*
* If we set the number of mmu pages to be smaller be than the
* number of actived pages , we must to free some mmu pages before we
* change the value
*/
- if (used_pages > kvm_nr_mmu_pages) {
- while (used_pages > kvm_nr_mmu_pages &&
+ if (kvm->arch.n_used_mmu_pages > goal_nr_mmu_pages) {
+ while (kvm->arch.n_used_mmu_pages > goal_nr_mmu_pages &&
!list_empty(&kvm->arch.active_mmu_pages)) {
struct kvm_mmu_page *page;
page = container_of(kvm->arch.active_mmu_pages.prev,
struct kvm_mmu_page, link);
- used_pages -= kvm_mmu_prepare_zap_page(kvm, page,
- &invalid_list);
+ kvm_mmu_prepare_zap_page(kvm, page, &invalid_list);
+ kvm_mmu_commit_zap_page(kvm, &invalid_list);
}
- kvm_mmu_commit_zap_page(kvm, &invalid_list);
- kvm_nr_mmu_pages = used_pages;
- kvm->arch.n_free_mmu_pages = 0;
+ goal_nr_mmu_pages = kvm->arch.n_used_mmu_pages;
}
- else
- kvm->arch.n_free_mmu_pages += kvm_nr_mmu_pages
- - kvm->arch.n_alloc_mmu_pages;
- kvm->arch.n_alloc_mmu_pages = kvm_nr_mmu_pages;
+ kvm->arch.n_max_mmu_pages = goal_nr_mmu_pages;
}
static int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn)
@@ -1709,11 +1756,11 @@ static int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn)
LIST_HEAD(invalid_list);
int r;
- pgprintk("%s: looking for gfn %lx\n", __func__, gfn);
+ pgprintk("%s: looking for gfn %llx\n", __func__, gfn);
r = 0;
for_each_gfn_indirect_valid_sp(kvm, sp, gfn, node) {
- pgprintk("%s: gfn %lx role %x\n", __func__, gfn,
+ pgprintk("%s: gfn %llx role %x\n", __func__, gfn,
sp->role.word);
r = 1;
kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list);
@@ -1729,7 +1776,7 @@ static void mmu_unshadow(struct kvm *kvm, gfn_t gfn)
LIST_HEAD(invalid_list);
for_each_gfn_indirect_valid_sp(kvm, sp, gfn, node) {
- pgprintk("%s: zap %lx %x\n",
+ pgprintk("%s: zap %llx %x\n",
__func__, gfn, sp->role.word);
kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list);
}
@@ -1925,7 +1972,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
* whether the guest actually used the pte (in order to detect
* demand paging).
*/
- spte = shadow_base_present_pte | shadow_dirty_mask;
+ spte = shadow_base_present_pte;
if (!speculative)
spte |= shadow_accessed_mask;
if (!dirty)
@@ -1948,8 +1995,8 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
spte |= (u64)pfn << PAGE_SHIFT;
if ((pte_access & ACC_WRITE_MASK)
- || (!tdp_enabled && write_fault && !is_write_protection(vcpu)
- && !user_fault)) {
+ || (!vcpu->arch.mmu.direct_map && write_fault
+ && !is_write_protection(vcpu) && !user_fault)) {
if (level > PT_PAGE_TABLE_LEVEL &&
has_wrprotected_page(vcpu->kvm, gfn, level)) {
@@ -1960,7 +2007,8 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
spte |= PT_WRITABLE_MASK;
- if (!tdp_enabled && !(pte_access & ACC_WRITE_MASK))
+ if (!vcpu->arch.mmu.direct_map
+ && !(pte_access & ACC_WRITE_MASK))
spte &= ~PT_USER_MASK;
/*
@@ -1973,7 +2021,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
goto set_pte;
if (mmu_need_write_protect(vcpu, gfn, can_unsync)) {
- pgprintk("%s: found shadow page for %lx, marking ro\n",
+ pgprintk("%s: found shadow page for %llx, marking ro\n",
__func__, gfn);
ret = 1;
pte_access &= ~ACC_WRITE_MASK;
@@ -1986,8 +2034,6 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
mark_page_dirty(vcpu->kvm, gfn);
set_pte:
- if (is_writable_pte(*sptep) && !is_writable_pte(spte))
- kvm_set_pfn_dirty(pfn);
update_spte(sptep, spte);
done:
return ret;
@@ -2004,7 +2050,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
int rmap_count;
pgprintk("%s: spte %llx access %x write_fault %d"
- " user_fault %d gfn %lx\n",
+ " user_fault %d gfn %llx\n",
__func__, *sptep, pt_access,
write_fault, user_fault, gfn);
@@ -2023,7 +2069,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
__set_spte(sptep, shadow_trap_nonpresent_pte);
kvm_flush_remote_tlbs(vcpu->kvm);
} else if (pfn != spte_to_pfn(*sptep)) {
- pgprintk("hfn old %lx new %lx\n",
+ pgprintk("hfn old %llx new %llx\n",
spte_to_pfn(*sptep), pfn);
drop_spte(vcpu->kvm, sptep, shadow_trap_nonpresent_pte);
kvm_flush_remote_tlbs(vcpu->kvm);
@@ -2040,7 +2086,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
}
pgprintk("%s: setting spte %llx\n", __func__, *sptep);
- pgprintk("instantiating %s PTE (%s) at %ld (%llx) addr %p\n",
+ pgprintk("instantiating %s PTE (%s) at %llx (%llx) addr %p\n",
is_large_pte(*sptep)? "2MB" : "4kB",
*sptep & PT_PRESENT_MASK ?"RW":"R", gfn,
*sptep, sptep);
@@ -2064,6 +2110,105 @@ static void nonpaging_new_cr3(struct kvm_vcpu *vcpu)
{
}
+static struct kvm_memory_slot *
+pte_prefetch_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn, bool no_dirty_log)
+{
+ struct kvm_memory_slot *slot;
+
+ slot = gfn_to_memslot(vcpu->kvm, gfn);
+ if (!slot || slot->flags & KVM_MEMSLOT_INVALID ||
+ (no_dirty_log && slot->dirty_bitmap))
+ slot = NULL;
+
+ return slot;
+}
+
+static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn,
+ bool no_dirty_log)
+{
+ struct kvm_memory_slot *slot;
+ unsigned long hva;
+
+ slot = pte_prefetch_gfn_to_memslot(vcpu, gfn, no_dirty_log);
+ if (!slot) {
+ get_page(bad_page);
+ return page_to_pfn(bad_page);
+ }
+
+ hva = gfn_to_hva_memslot(slot, gfn);
+
+ return hva_to_pfn_atomic(vcpu->kvm, hva);
+}
+
+static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu,
+ struct kvm_mmu_page *sp,
+ u64 *start, u64 *end)
+{
+ struct page *pages[PTE_PREFETCH_NUM];
+ unsigned access = sp->role.access;
+ int i, ret;
+ gfn_t gfn;
+
+ gfn = kvm_mmu_page_get_gfn(sp, start - sp->spt);
+ if (!pte_prefetch_gfn_to_memslot(vcpu, gfn, access & ACC_WRITE_MASK))
+ return -1;
+
+ ret = gfn_to_page_many_atomic(vcpu->kvm, gfn, pages, end - start);
+ if (ret <= 0)
+ return -1;
+
+ for (i = 0; i < ret; i++, gfn++, start++)
+ mmu_set_spte(vcpu, start, ACC_ALL,
+ access, 0, 0, 1, NULL,
+ sp->role.level, gfn,
+ page_to_pfn(pages[i]), true, true);
+
+ return 0;
+}
+
+static void __direct_pte_prefetch(struct kvm_vcpu *vcpu,
+ struct kvm_mmu_page *sp, u64 *sptep)
+{
+ u64 *spte, *start = NULL;
+ int i;
+
+ WARN_ON(!sp->role.direct);
+
+ i = (sptep - sp->spt) & ~(PTE_PREFETCH_NUM - 1);
+ spte = sp->spt + i;
+
+ for (i = 0; i < PTE_PREFETCH_NUM; i++, spte++) {
+ if (*spte != shadow_trap_nonpresent_pte || spte == sptep) {
+ if (!start)
+ continue;
+ if (direct_pte_prefetch_many(vcpu, sp, start, spte) < 0)
+ break;
+ start = NULL;
+ } else if (!start)
+ start = spte;
+ }
+}
+
+static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep)
+{
+ struct kvm_mmu_page *sp;
+
+ /*
+ * Since it's no accessed bit on EPT, it's no way to
+ * distinguish between actually accessed translations
+ * and prefetched, so disable pte prefetch if EPT is
+ * enabled.
+ */
+ if (!shadow_accessed_mask)
+ return;
+
+ sp = page_header(__pa(sptep));
+ if (sp->role.level > PT_PAGE_TABLE_LEVEL)
+ return;
+
+ __direct_pte_prefetch(vcpu, sp, sptep);
+}
+
static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
int level, gfn_t gfn, pfn_t pfn)
{
@@ -2077,6 +2222,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, ACC_ALL,
0, write, 1, &pt_write,
level, gfn, pfn, false, true);
+ direct_pte_prefetch(vcpu, iterator.sptep);
++vcpu->stat.pf_fixed;
break;
}
@@ -2098,28 +2244,31 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
__set_spte(iterator.sptep,
__pa(sp->spt)
| PT_PRESENT_MASK | PT_WRITABLE_MASK
- | shadow_user_mask | shadow_x_mask);
+ | shadow_user_mask | shadow_x_mask
+ | shadow_accessed_mask);
}
}
return pt_write;
}
-static void kvm_send_hwpoison_signal(struct kvm *kvm, gfn_t gfn)
+static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct *tsk)
{
- char buf[1];
- void __user *hva;
- int r;
+ siginfo_t info;
+
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_MCEERR_AR;
+ info.si_addr = (void __user *)address;
+ info.si_addr_lsb = PAGE_SHIFT;
- /* Touch the page, so send SIGBUS */
- hva = (void __user *)gfn_to_hva(kvm, gfn);
- r = copy_from_user(buf, hva, 1);
+ send_sig_info(SIGBUS, &info, tsk);
}
static int kvm_handle_bad_page(struct kvm *kvm, gfn_t gfn, pfn_t pfn)
{
kvm_release_pfn_clean(pfn);
if (is_hwpoison_pfn(pfn)) {
- kvm_send_hwpoison_signal(kvm, gfn);
+ kvm_send_hwpoison_signal(gfn_to_hva(kvm, gfn), current);
return 0;
} else if (is_fault_pfn(pfn))
return -EFAULT;
@@ -2179,7 +2328,9 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
return;
spin_lock(&vcpu->kvm->mmu_lock);
- if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
+ if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL &&
+ (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL ||
+ vcpu->arch.mmu.direct_map)) {
hpa_t root = vcpu->arch.mmu.root_hpa;
sp = page_header(root);
@@ -2222,80 +2373,158 @@ static int mmu_check_root(struct kvm_vcpu *vcpu, gfn_t root_gfn)
return ret;
}
-static int mmu_alloc_roots(struct kvm_vcpu *vcpu)
+static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu)
{
- int i;
- gfn_t root_gfn;
struct kvm_mmu_page *sp;
- int direct = 0;
- u64 pdptr;
-
- root_gfn = vcpu->arch.cr3 >> PAGE_SHIFT;
+ unsigned i;
if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
+ spin_lock(&vcpu->kvm->mmu_lock);
+ kvm_mmu_free_some_pages(vcpu);
+ sp = kvm_mmu_get_page(vcpu, 0, 0, PT64_ROOT_LEVEL,
+ 1, ACC_ALL, NULL);
+ ++sp->root_count;
+ spin_unlock(&vcpu->kvm->mmu_lock);
+ vcpu->arch.mmu.root_hpa = __pa(sp->spt);
+ } else if (vcpu->arch.mmu.shadow_root_level == PT32E_ROOT_LEVEL) {
+ for (i = 0; i < 4; ++i) {
+ hpa_t root = vcpu->arch.mmu.pae_root[i];
+
+ ASSERT(!VALID_PAGE(root));
+ spin_lock(&vcpu->kvm->mmu_lock);
+ kvm_mmu_free_some_pages(vcpu);
+ sp = kvm_mmu_get_page(vcpu, i << 30, i << 30,
+ PT32_ROOT_LEVEL, 1, ACC_ALL,
+ NULL);
+ root = __pa(sp->spt);
+ ++sp->root_count;
+ spin_unlock(&vcpu->kvm->mmu_lock);
+ vcpu->arch.mmu.pae_root[i] = root | PT_PRESENT_MASK;
+ }
+ vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.pae_root);
+ } else
+ BUG();
+
+ return 0;
+}
+
+static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
+{
+ struct kvm_mmu_page *sp;
+ u64 pdptr, pm_mask;
+ gfn_t root_gfn;
+ int i;
+
+ root_gfn = vcpu->arch.mmu.get_cr3(vcpu) >> PAGE_SHIFT;
+
+ if (mmu_check_root(vcpu, root_gfn))
+ return 1;
+
+ /*
+ * Do we shadow a long mode page table? If so we need to
+ * write-protect the guests page table root.
+ */
+ if (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL) {
hpa_t root = vcpu->arch.mmu.root_hpa;
ASSERT(!VALID_PAGE(root));
- if (mmu_check_root(vcpu, root_gfn))
- return 1;
- if (tdp_enabled) {
- direct = 1;
- root_gfn = 0;
- }
+
spin_lock(&vcpu->kvm->mmu_lock);
kvm_mmu_free_some_pages(vcpu);
- sp = kvm_mmu_get_page(vcpu, root_gfn, 0,
- PT64_ROOT_LEVEL, direct,
- ACC_ALL, NULL);
+ sp = kvm_mmu_get_page(vcpu, root_gfn, 0, PT64_ROOT_LEVEL,
+ 0, ACC_ALL, NULL);
root = __pa(sp->spt);
++sp->root_count;
spin_unlock(&vcpu->kvm->mmu_lock);
vcpu->arch.mmu.root_hpa = root;
return 0;
}
- direct = !is_paging(vcpu);
+
+ /*
+ * We shadow a 32 bit page table. This may be a legacy 2-level
+ * or a PAE 3-level page table. In either case we need to be aware that
+ * the shadow page table may be a PAE or a long mode page table.
+ */
+ pm_mask = PT_PRESENT_MASK;
+ if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL)
+ pm_mask |= PT_ACCESSED_MASK | PT_WRITABLE_MASK | PT_USER_MASK;
+
for (i = 0; i < 4; ++i) {
hpa_t root = vcpu->arch.mmu.pae_root[i];
ASSERT(!VALID_PAGE(root));
if (vcpu->arch.mmu.root_level == PT32E_ROOT_LEVEL) {
- pdptr = kvm_pdptr_read(vcpu, i);
+ pdptr = kvm_pdptr_read_mmu(vcpu, &vcpu->arch.mmu, i);
if (!is_present_gpte(pdptr)) {
vcpu->arch.mmu.pae_root[i] = 0;
continue;
}
root_gfn = pdptr >> PAGE_SHIFT;
- } else if (vcpu->arch.mmu.root_level == 0)
- root_gfn = 0;
- if (mmu_check_root(vcpu, root_gfn))
- return 1;
- if (tdp_enabled) {
- direct = 1;
- root_gfn = i << 30;
+ if (mmu_check_root(vcpu, root_gfn))
+ return 1;
}
spin_lock(&vcpu->kvm->mmu_lock);
kvm_mmu_free_some_pages(vcpu);
sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
- PT32_ROOT_LEVEL, direct,
+ PT32_ROOT_LEVEL, 0,
ACC_ALL, NULL);
root = __pa(sp->spt);
++sp->root_count;
spin_unlock(&vcpu->kvm->mmu_lock);
- vcpu->arch.mmu.pae_root[i] = root | PT_PRESENT_MASK;
+ vcpu->arch.mmu.pae_root[i] = root | pm_mask;
}
vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.pae_root);
+
+ /*
+ * If we shadow a 32 bit page table with a long mode page
+ * table we enter this path.
+ */
+ if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
+ if (vcpu->arch.mmu.lm_root == NULL) {
+ /*
+ * The additional page necessary for this is only
+ * allocated on demand.
+ */
+
+ u64 *lm_root;
+
+ lm_root = (void*)get_zeroed_page(GFP_KERNEL);
+ if (lm_root == NULL)
+ return 1;
+
+ lm_root[0] = __pa(vcpu->arch.mmu.pae_root) | pm_mask;
+
+ vcpu->arch.mmu.lm_root = lm_root;
+ }
+
+ vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.lm_root);
+ }
+
return 0;
}
+static int mmu_alloc_roots(struct kvm_vcpu *vcpu)
+{
+ if (vcpu->arch.mmu.direct_map)
+ return mmu_alloc_direct_roots(vcpu);
+ else
+ return mmu_alloc_shadow_roots(vcpu);
+}
+
static void mmu_sync_roots(struct kvm_vcpu *vcpu)
{
int i;
struct kvm_mmu_page *sp;
+ if (vcpu->arch.mmu.direct_map)
+ return;
+
if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
return;
- if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
+
+ trace_kvm_mmu_audit(vcpu, AUDIT_PRE_SYNC);
+ if (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL) {
hpa_t root = vcpu->arch.mmu.root_hpa;
sp = page_header(root);
mmu_sync_children(vcpu, sp);
@@ -2310,6 +2539,7 @@ static void mmu_sync_roots(struct kvm_vcpu *vcpu)
mmu_sync_children(vcpu, sp);
}
}
+ trace_kvm_mmu_audit(vcpu, AUDIT_POST_SYNC);
}
void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu)
@@ -2327,6 +2557,14 @@ static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr,
return vaddr;
}
+static gpa_t nonpaging_gva_to_gpa_nested(struct kvm_vcpu *vcpu, gva_t vaddr,
+ u32 access, u32 *error)
+{
+ if (error)
+ *error = 0;
+ return vcpu->arch.nested_mmu.translate_gpa(vcpu, vaddr, access);
+}
+
static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
u32 error_code)
{
@@ -2393,10 +2631,9 @@ static void nonpaging_free(struct kvm_vcpu *vcpu)
mmu_free_roots(vcpu);
}
-static int nonpaging_init_context(struct kvm_vcpu *vcpu)
+static int nonpaging_init_context(struct kvm_vcpu *vcpu,
+ struct kvm_mmu *context)
{
- struct kvm_mmu *context = &vcpu->arch.mmu;
-
context->new_cr3 = nonpaging_new_cr3;
context->page_fault = nonpaging_page_fault;
context->gva_to_gpa = nonpaging_gva_to_gpa;
@@ -2407,6 +2644,8 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu)
context->root_level = 0;
context->shadow_root_level = PT32E_ROOT_LEVEL;
context->root_hpa = INVALID_PAGE;
+ context->direct_map = true;
+ context->nx = false;
return 0;
}
@@ -2422,11 +2661,14 @@ static void paging_new_cr3(struct kvm_vcpu *vcpu)
mmu_free_roots(vcpu);
}
-static void inject_page_fault(struct kvm_vcpu *vcpu,
- u64 addr,
- u32 err_code)
+static unsigned long get_cr3(struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.cr3;
+}
+
+static void inject_page_fault(struct kvm_vcpu *vcpu)
{
- kvm_inject_page_fault(vcpu, addr, err_code);
+ vcpu->arch.mmu.inject_page_fault(vcpu);
}
static void paging_free(struct kvm_vcpu *vcpu)
@@ -2434,12 +2676,12 @@ static void paging_free(struct kvm_vcpu *vcpu)
nonpaging_free(vcpu);
}
-static bool is_rsvd_bits_set(struct kvm_vcpu *vcpu, u64 gpte, int level)
+static bool is_rsvd_bits_set(struct kvm_mmu *mmu, u64 gpte, int level)
{
int bit7;
bit7 = (gpte >> 7) & 1;
- return (gpte & vcpu->arch.mmu.rsvd_bits_mask[bit7][level-1]) != 0;
+ return (gpte & mmu->rsvd_bits_mask[bit7][level-1]) != 0;
}
#define PTTYPE 64
@@ -2450,13 +2692,14 @@ static bool is_rsvd_bits_set(struct kvm_vcpu *vcpu, u64 gpte, int level)
#include "paging_tmpl.h"
#undef PTTYPE
-static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level)
+static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
+ struct kvm_mmu *context,
+ int level)
{
- struct kvm_mmu *context = &vcpu->arch.mmu;
int maxphyaddr = cpuid_maxphyaddr(vcpu);
u64 exb_bit_rsvd = 0;
- if (!is_nx(vcpu))
+ if (!context->nx)
exb_bit_rsvd = rsvd_bits(63, 63);
switch (level) {
case PT32_ROOT_LEVEL:
@@ -2511,9 +2754,13 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level)
}
}
-static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level)
+static int paging64_init_context_common(struct kvm_vcpu *vcpu,
+ struct kvm_mmu *context,
+ int level)
{
- struct kvm_mmu *context = &vcpu->arch.mmu;
+ context->nx = is_nx(vcpu);
+
+ reset_rsvds_bits_mask(vcpu, context, level);
ASSERT(is_pae(vcpu));
context->new_cr3 = paging_new_cr3;
@@ -2526,20 +2773,23 @@ static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level)
context->root_level = level;
context->shadow_root_level = level;
context->root_hpa = INVALID_PAGE;
+ context->direct_map = false;
return 0;
}
-static int paging64_init_context(struct kvm_vcpu *vcpu)
+static int paging64_init_context(struct kvm_vcpu *vcpu,
+ struct kvm_mmu *context)
{
- reset_rsvds_bits_mask(vcpu, PT64_ROOT_LEVEL);
- return paging64_init_context_common(vcpu, PT64_ROOT_LEVEL);
+ return paging64_init_context_common(vcpu, context, PT64_ROOT_LEVEL);
}
-static int paging32_init_context(struct kvm_vcpu *vcpu)
+static int paging32_init_context(struct kvm_vcpu *vcpu,
+ struct kvm_mmu *context)
{
- struct kvm_mmu *context = &vcpu->arch.mmu;
+ context->nx = false;
+
+ reset_rsvds_bits_mask(vcpu, context, PT32_ROOT_LEVEL);
- reset_rsvds_bits_mask(vcpu, PT32_ROOT_LEVEL);
context->new_cr3 = paging_new_cr3;
context->page_fault = paging32_page_fault;
context->gva_to_gpa = paging32_gva_to_gpa;
@@ -2550,18 +2800,19 @@ static int paging32_init_context(struct kvm_vcpu *vcpu)
context->root_level = PT32_ROOT_LEVEL;
context->shadow_root_level = PT32E_ROOT_LEVEL;
context->root_hpa = INVALID_PAGE;
+ context->direct_map = false;
return 0;
}
-static int paging32E_init_context(struct kvm_vcpu *vcpu)
+static int paging32E_init_context(struct kvm_vcpu *vcpu,
+ struct kvm_mmu *context)
{
- reset_rsvds_bits_mask(vcpu, PT32E_ROOT_LEVEL);
- return paging64_init_context_common(vcpu, PT32E_ROOT_LEVEL);
+ return paging64_init_context_common(vcpu, context, PT32E_ROOT_LEVEL);
}
static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
{
- struct kvm_mmu *context = &vcpu->arch.mmu;
+ struct kvm_mmu *context = vcpu->arch.walk_mmu;
context->new_cr3 = nonpaging_new_cr3;
context->page_fault = tdp_page_fault;
@@ -2571,20 +2822,29 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
context->invlpg = nonpaging_invlpg;
context->shadow_root_level = kvm_x86_ops->get_tdp_level();
context->root_hpa = INVALID_PAGE;
+ context->direct_map = true;
+ context->set_cr3 = kvm_x86_ops->set_tdp_cr3;
+ context->get_cr3 = get_cr3;
+ context->inject_page_fault = kvm_inject_page_fault;
+ context->nx = is_nx(vcpu);
if (!is_paging(vcpu)) {
+ context->nx = false;
context->gva_to_gpa = nonpaging_gva_to_gpa;
context->root_level = 0;
} else if (is_long_mode(vcpu)) {
- reset_rsvds_bits_mask(vcpu, PT64_ROOT_LEVEL);
+ context->nx = is_nx(vcpu);
+ reset_rsvds_bits_mask(vcpu, context, PT64_ROOT_LEVEL);
context->gva_to_gpa = paging64_gva_to_gpa;
context->root_level = PT64_ROOT_LEVEL;
} else if (is_pae(vcpu)) {
- reset_rsvds_bits_mask(vcpu, PT32E_ROOT_LEVEL);
+ context->nx = is_nx(vcpu);
+ reset_rsvds_bits_mask(vcpu, context, PT32E_ROOT_LEVEL);
context->gva_to_gpa = paging64_gva_to_gpa;
context->root_level = PT32E_ROOT_LEVEL;
} else {
- reset_rsvds_bits_mask(vcpu, PT32_ROOT_LEVEL);
+ context->nx = false;
+ reset_rsvds_bits_mask(vcpu, context, PT32_ROOT_LEVEL);
context->gva_to_gpa = paging32_gva_to_gpa;
context->root_level = PT32_ROOT_LEVEL;
}
@@ -2592,33 +2852,83 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
return 0;
}
-static int init_kvm_softmmu(struct kvm_vcpu *vcpu)
+int kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context)
{
int r;
-
ASSERT(vcpu);
ASSERT(!VALID_PAGE(vcpu->arch.mmu.root_hpa));
if (!is_paging(vcpu))
- r = nonpaging_init_context(vcpu);
+ r = nonpaging_init_context(vcpu, context);
else if (is_long_mode(vcpu))
- r = paging64_init_context(vcpu);
+ r = paging64_init_context(vcpu, context);
else if (is_pae(vcpu))
- r = paging32E_init_context(vcpu);
+ r = paging32E_init_context(vcpu, context);
else
- r = paging32_init_context(vcpu);
+ r = paging32_init_context(vcpu, context);
vcpu->arch.mmu.base_role.cr4_pae = !!is_pae(vcpu);
- vcpu->arch.mmu.base_role.cr0_wp = is_write_protection(vcpu);
+ vcpu->arch.mmu.base_role.cr0_wp = is_write_protection(vcpu);
return r;
}
+EXPORT_SYMBOL_GPL(kvm_init_shadow_mmu);
+
+static int init_kvm_softmmu(struct kvm_vcpu *vcpu)
+{
+ int r = kvm_init_shadow_mmu(vcpu, vcpu->arch.walk_mmu);
+
+ vcpu->arch.walk_mmu->set_cr3 = kvm_x86_ops->set_cr3;
+ vcpu->arch.walk_mmu->get_cr3 = get_cr3;
+ vcpu->arch.walk_mmu->inject_page_fault = kvm_inject_page_fault;
+
+ return r;
+}
+
+static int init_kvm_nested_mmu(struct kvm_vcpu *vcpu)
+{
+ struct kvm_mmu *g_context = &vcpu->arch.nested_mmu;
+
+ g_context->get_cr3 = get_cr3;
+ g_context->inject_page_fault = kvm_inject_page_fault;
+
+ /*
+ * Note that arch.mmu.gva_to_gpa translates l2_gva to l1_gpa. The
+ * translation of l2_gpa to l1_gpa addresses is done using the
+ * arch.nested_mmu.gva_to_gpa function. Basically the gva_to_gpa
+ * functions between mmu and nested_mmu are swapped.
+ */
+ if (!is_paging(vcpu)) {
+ g_context->nx = false;
+ g_context->root_level = 0;
+ g_context->gva_to_gpa = nonpaging_gva_to_gpa_nested;
+ } else if (is_long_mode(vcpu)) {
+ g_context->nx = is_nx(vcpu);
+ reset_rsvds_bits_mask(vcpu, g_context, PT64_ROOT_LEVEL);
+ g_context->root_level = PT64_ROOT_LEVEL;
+ g_context->gva_to_gpa = paging64_gva_to_gpa_nested;
+ } else if (is_pae(vcpu)) {
+ g_context->nx = is_nx(vcpu);
+ reset_rsvds_bits_mask(vcpu, g_context, PT32E_ROOT_LEVEL);
+ g_context->root_level = PT32E_ROOT_LEVEL;
+ g_context->gva_to_gpa = paging64_gva_to_gpa_nested;
+ } else {
+ g_context->nx = false;
+ reset_rsvds_bits_mask(vcpu, g_context, PT32_ROOT_LEVEL);
+ g_context->root_level = PT32_ROOT_LEVEL;
+ g_context->gva_to_gpa = paging32_gva_to_gpa_nested;
+ }
+
+ return 0;
+}
static int init_kvm_mmu(struct kvm_vcpu *vcpu)
{
vcpu->arch.update_pte.pfn = bad_pfn;
- if (tdp_enabled)
+ if (mmu_is_nested(vcpu))
+ return init_kvm_nested_mmu(vcpu);
+ else if (tdp_enabled)
return init_kvm_tdp_mmu(vcpu);
else
return init_kvm_softmmu(vcpu);
@@ -2653,7 +2963,7 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu)
if (r)
goto out;
/* set_cr3() should ensure TLB has been flushed */
- kvm_x86_ops->set_cr3(vcpu, vcpu->arch.mmu.root_hpa);
+ vcpu->arch.mmu.set_cr3(vcpu, vcpu->arch.mmu.root_hpa);
out:
return r;
}
@@ -2663,6 +2973,7 @@ void kvm_mmu_unload(struct kvm_vcpu *vcpu)
{
mmu_free_roots(vcpu);
}
+EXPORT_SYMBOL_GPL(kvm_mmu_unload);
static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
struct kvm_mmu_page *sp,
@@ -2695,7 +3006,7 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
return;
}
- if (is_rsvd_bits_set(vcpu, *(u64 *)new, PT_PAGE_TABLE_LEVEL))
+ if (is_rsvd_bits_set(&vcpu->arch.mmu, *(u64 *)new, PT_PAGE_TABLE_LEVEL))
return;
++vcpu->kvm->stat.mmu_pte_updated;
@@ -2837,7 +3148,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
kvm_mmu_access_page(vcpu, gfn);
kvm_mmu_free_some_pages(vcpu);
++vcpu->kvm->stat.mmu_pte_write;
- kvm_mmu_audit(vcpu, "pre pte write");
+ trace_kvm_mmu_audit(vcpu, AUDIT_PRE_PTE_WRITE);
if (guest_initiated) {
if (gfn == vcpu->arch.last_pt_write_gfn
&& !last_updated_pte_accessed(vcpu)) {
@@ -2910,7 +3221,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
}
mmu_pte_write_flush_tlb(vcpu, zap_page, remote_flush, local_flush);
kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
- kvm_mmu_audit(vcpu, "post pte write");
+ trace_kvm_mmu_audit(vcpu, AUDIT_POST_PTE_WRITE);
spin_unlock(&vcpu->kvm->mmu_lock);
if (!is_error_pfn(vcpu->arch.update_pte.pfn)) {
kvm_release_pfn_clean(vcpu->arch.update_pte.pfn);
@@ -2923,7 +3234,7 @@ int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva)
gpa_t gpa;
int r;
- if (tdp_enabled)
+ if (vcpu->arch.mmu.direct_map)
return 0;
gpa = kvm_mmu_gva_to_gpa_read(vcpu, gva, NULL);
@@ -2937,21 +3248,18 @@ EXPORT_SYMBOL_GPL(kvm_mmu_unprotect_page_virt);
void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
{
- int free_pages;
LIST_HEAD(invalid_list);
- free_pages = vcpu->kvm->arch.n_free_mmu_pages;
- while (free_pages < KVM_REFILL_PAGES &&
+ while (kvm_mmu_available_pages(vcpu->kvm) < KVM_REFILL_PAGES &&
!list_empty(&vcpu->kvm->arch.active_mmu_pages)) {
struct kvm_mmu_page *sp;
sp = container_of(vcpu->kvm->arch.active_mmu_pages.prev,
struct kvm_mmu_page, link);
- free_pages += kvm_mmu_prepare_zap_page(vcpu->kvm, sp,
- &invalid_list);
+ kvm_mmu_prepare_zap_page(vcpu->kvm, sp, &invalid_list);
+ kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
++vcpu->kvm->stat.mmu_recycled;
}
- kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
}
int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code)
@@ -3013,6 +3321,8 @@ EXPORT_SYMBOL_GPL(kvm_disable_tdp);
static void free_mmu_pages(struct kvm_vcpu *vcpu)
{
free_page((unsigned long)vcpu->arch.mmu.pae_root);
+ if (vcpu->arch.mmu.lm_root != NULL)
+ free_page((unsigned long)vcpu->arch.mmu.lm_root);
}
static int alloc_mmu_pages(struct kvm_vcpu *vcpu)
@@ -3054,15 +3364,6 @@ int kvm_mmu_setup(struct kvm_vcpu *vcpu)
return init_kvm_mmu(vcpu);
}
-void kvm_mmu_destroy(struct kvm_vcpu *vcpu)
-{
- ASSERT(vcpu);
-
- destroy_kvm_mmu(vcpu);
- free_mmu_pages(vcpu);
- mmu_free_memory_caches(vcpu);
-}
-
void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
{
struct kvm_mmu_page *sp;
@@ -3112,23 +3413,22 @@ static int mmu_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
{
struct kvm *kvm;
struct kvm *kvm_freed = NULL;
- int cache_count = 0;
+
+ if (nr_to_scan == 0)
+ goto out;
spin_lock(&kvm_lock);
list_for_each_entry(kvm, &vm_list, vm_list) {
- int npages, idx, freed_pages;
+ int idx, freed_pages;
LIST_HEAD(invalid_list);
idx = srcu_read_lock(&kvm->srcu);
spin_lock(&kvm->mmu_lock);
- npages = kvm->arch.n_alloc_mmu_pages -
- kvm->arch.n_free_mmu_pages;
- cache_count += npages;
- if (!kvm_freed && nr_to_scan > 0 && npages > 0) {
+ if (!kvm_freed && nr_to_scan > 0 &&
+ kvm->arch.n_used_mmu_pages > 0) {
freed_pages = kvm_mmu_remove_some_alloc_mmu_pages(kvm,
&invalid_list);
- cache_count -= freed_pages;
kvm_freed = kvm;
}
nr_to_scan--;
@@ -3142,7 +3442,8 @@ static int mmu_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
spin_unlock(&kvm_lock);
- return cache_count;
+out:
+ return percpu_counter_read_positive(&kvm_total_used_mmu_pages);
}
static struct shrinker mmu_shrinker = {
@@ -3163,6 +3464,7 @@ static void mmu_destroy_caches(void)
void kvm_mmu_module_exit(void)
{
mmu_destroy_caches();
+ percpu_counter_destroy(&kvm_total_used_mmu_pages);
unregister_shrinker(&mmu_shrinker);
}
@@ -3185,6 +3487,9 @@ int kvm_mmu_module_init(void)
if (!mmu_page_header_cache)
goto nomem;
+ if (percpu_counter_init(&kvm_total_used_mmu_pages, 0))
+ goto nomem;
+
register_shrinker(&mmu_shrinker);
return 0;
@@ -3355,271 +3660,18 @@ int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4])
}
EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy);
-#ifdef AUDIT
-
-static const char *audit_msg;
-
-static gva_t canonicalize(gva_t gva)
-{
-#ifdef CONFIG_X86_64
- gva = (long long)(gva << 16) >> 16;
+#ifdef CONFIG_KVM_MMU_AUDIT
+#include "mmu_audit.c"
+#else
+static void mmu_audit_disable(void) { }
#endif
- return gva;
-}
-
-
-typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep);
-
-static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp,
- inspect_spte_fn fn)
-{
- int i;
-
- for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
- u64 ent = sp->spt[i];
-
- if (is_shadow_present_pte(ent)) {
- if (!is_last_spte(ent, sp->role.level)) {
- struct kvm_mmu_page *child;
- child = page_header(ent & PT64_BASE_ADDR_MASK);
- __mmu_spte_walk(kvm, child, fn);
- } else
- fn(kvm, &sp->spt[i]);
- }
- }
-}
-
-static void mmu_spte_walk(struct kvm_vcpu *vcpu, inspect_spte_fn fn)
-{
- int i;
- struct kvm_mmu_page *sp;
-
- if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
- return;
- if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
- hpa_t root = vcpu->arch.mmu.root_hpa;
- sp = page_header(root);
- __mmu_spte_walk(vcpu->kvm, sp, fn);
- return;
- }
- for (i = 0; i < 4; ++i) {
- hpa_t root = vcpu->arch.mmu.pae_root[i];
-
- if (root && VALID_PAGE(root)) {
- root &= PT64_BASE_ADDR_MASK;
- sp = page_header(root);
- __mmu_spte_walk(vcpu->kvm, sp, fn);
- }
- }
- return;
-}
-
-static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte,
- gva_t va, int level)
-{
- u64 *pt = __va(page_pte & PT64_BASE_ADDR_MASK);
- int i;
- gva_t va_delta = 1ul << (PAGE_SHIFT + 9 * (level - 1));
-
- for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) {
- u64 ent = pt[i];
-
- if (ent == shadow_trap_nonpresent_pte)
- continue;
-
- va = canonicalize(va);
- if (is_shadow_present_pte(ent) && !is_last_spte(ent, level))
- audit_mappings_page(vcpu, ent, va, level - 1);
- else {
- gpa_t gpa = kvm_mmu_gva_to_gpa_read(vcpu, va, NULL);
- gfn_t gfn = gpa >> PAGE_SHIFT;
- pfn_t pfn = gfn_to_pfn(vcpu->kvm, gfn);
- hpa_t hpa = (hpa_t)pfn << PAGE_SHIFT;
- if (is_error_pfn(pfn)) {
- kvm_release_pfn_clean(pfn);
- continue;
- }
-
- if (is_shadow_present_pte(ent)
- && (ent & PT64_BASE_ADDR_MASK) != hpa)
- printk(KERN_ERR "xx audit error: (%s) levels %d"
- " gva %lx gpa %llx hpa %llx ent %llx %d\n",
- audit_msg, vcpu->arch.mmu.root_level,
- va, gpa, hpa, ent,
- is_shadow_present_pte(ent));
- else if (ent == shadow_notrap_nonpresent_pte
- && !is_error_hpa(hpa))
- printk(KERN_ERR "audit: (%s) notrap shadow,"
- " valid guest gva %lx\n", audit_msg, va);
- kvm_release_pfn_clean(pfn);
-
- }
- }
-}
-
-static void audit_mappings(struct kvm_vcpu *vcpu)
-{
- unsigned i;
-
- if (vcpu->arch.mmu.root_level == 4)
- audit_mappings_page(vcpu, vcpu->arch.mmu.root_hpa, 0, 4);
- else
- for (i = 0; i < 4; ++i)
- if (vcpu->arch.mmu.pae_root[i] & PT_PRESENT_MASK)
- audit_mappings_page(vcpu,
- vcpu->arch.mmu.pae_root[i],
- i << 30,
- 2);
-}
-
-static int count_rmaps(struct kvm_vcpu *vcpu)
-{
- struct kvm *kvm = vcpu->kvm;
- struct kvm_memslots *slots;
- int nmaps = 0;
- int i, j, k, idx;
-
- idx = srcu_read_lock(&kvm->srcu);
- slots = kvm_memslots(kvm);
- for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
- struct kvm_memory_slot *m = &slots->memslots[i];
- struct kvm_rmap_desc *d;
-
- for (j = 0; j < m->npages; ++j) {
- unsigned long *rmapp = &m->rmap[j];
-
- if (!*rmapp)
- continue;
- if (!(*rmapp & 1)) {
- ++nmaps;
- continue;
- }
- d = (struct kvm_rmap_desc *)(*rmapp & ~1ul);
- while (d) {
- for (k = 0; k < RMAP_EXT; ++k)
- if (d->sptes[k])
- ++nmaps;
- else
- break;
- d = d->more;
- }
- }
- }
- srcu_read_unlock(&kvm->srcu, idx);
- return nmaps;
-}
-
-void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
-{
- unsigned long *rmapp;
- struct kvm_mmu_page *rev_sp;
- gfn_t gfn;
-
- if (is_writable_pte(*sptep)) {
- rev_sp = page_header(__pa(sptep));
- gfn = kvm_mmu_page_get_gfn(rev_sp, sptep - rev_sp->spt);
-
- if (!gfn_to_memslot(kvm, gfn)) {
- if (!printk_ratelimit())
- return;
- printk(KERN_ERR "%s: no memslot for gfn %ld\n",
- audit_msg, gfn);
- printk(KERN_ERR "%s: index %ld of sp (gfn=%lx)\n",
- audit_msg, (long int)(sptep - rev_sp->spt),
- rev_sp->gfn);
- dump_stack();
- return;
- }
-
- rmapp = gfn_to_rmap(kvm, gfn, rev_sp->role.level);
- if (!*rmapp) {
- if (!printk_ratelimit())
- return;
- printk(KERN_ERR "%s: no rmap for writable spte %llx\n",
- audit_msg, *sptep);
- dump_stack();
- }
- }
-
-}
-
-void audit_writable_sptes_have_rmaps(struct kvm_vcpu *vcpu)
-{
- mmu_spte_walk(vcpu, inspect_spte_has_rmap);
-}
-
-static void check_writable_mappings_rmap(struct kvm_vcpu *vcpu)
-{
- struct kvm_mmu_page *sp;
- int i;
-
- list_for_each_entry(sp, &vcpu->kvm->arch.active_mmu_pages, link) {
- u64 *pt = sp->spt;
-
- if (sp->role.level != PT_PAGE_TABLE_LEVEL)
- continue;
-
- for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
- u64 ent = pt[i];
-
- if (!(ent & PT_PRESENT_MASK))
- continue;
- if (!is_writable_pte(ent))
- continue;
- inspect_spte_has_rmap(vcpu->kvm, &pt[i]);
- }
- }
- return;
-}
-
-static void audit_rmap(struct kvm_vcpu *vcpu)
-{
- check_writable_mappings_rmap(vcpu);
- count_rmaps(vcpu);
-}
-
-static void audit_write_protection(struct kvm_vcpu *vcpu)
-{
- struct kvm_mmu_page *sp;
- struct kvm_memory_slot *slot;
- unsigned long *rmapp;
- u64 *spte;
- gfn_t gfn;
-
- list_for_each_entry(sp, &vcpu->kvm->arch.active_mmu_pages, link) {
- if (sp->role.direct)
- continue;
- if (sp->unsync)
- continue;
-
- slot = gfn_to_memslot(vcpu->kvm, sp->gfn);
- rmapp = &slot->rmap[gfn - slot->base_gfn];
-
- spte = rmap_next(vcpu->kvm, rmapp, NULL);
- while (spte) {
- if (is_writable_pte(*spte))
- printk(KERN_ERR "%s: (%s) shadow page has "
- "writable mappings: gfn %lx role %x\n",
- __func__, audit_msg, sp->gfn,
- sp->role.word);
- spte = rmap_next(vcpu->kvm, rmapp, spte);
- }
- }
-}
-
-static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg)
+void kvm_mmu_destroy(struct kvm_vcpu *vcpu)
{
- int olddbg = dbg;
+ ASSERT(vcpu);
- dbg = 0;
- audit_msg = msg;
- audit_rmap(vcpu);
- audit_write_protection(vcpu);
- if (strcmp("pre pte write", audit_msg) != 0)
- audit_mappings(vcpu);
- audit_writable_sptes_have_rmaps(vcpu);
- dbg = olddbg;
+ destroy_kvm_mmu(vcpu);
+ free_mmu_pages(vcpu);
+ mmu_free_memory_caches(vcpu);
+ mmu_audit_disable();
}
-
-#endif
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index be66759321a5..7086ca85d3e7 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -49,10 +49,17 @@
#define PFERR_FETCH_MASK (1U << 4)
int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]);
+int kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context);
+
+static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm)
+{
+ return kvm->arch.n_max_mmu_pages -
+ kvm->arch.n_used_mmu_pages;
+}
static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
{
- if (unlikely(vcpu->kvm->arch.n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
+ if (unlikely(kvm_mmu_available_pages(vcpu->kvm)< KVM_MIN_FREE_MMU_PAGES))
__kvm_mmu_free_some_pages(vcpu);
}
diff --git a/arch/x86/kvm/mmu_audit.c b/arch/x86/kvm/mmu_audit.c
new file mode 100644
index 000000000000..ba2bcdde6221
--- /dev/null
+++ b/arch/x86/kvm/mmu_audit.c
@@ -0,0 +1,299 @@
+/*
+ * mmu_audit.c:
+ *
+ * Audit code for KVM MMU
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
+ *
+ * Authors:
+ * Yaniv Kamay <yaniv@qumranet.com>
+ * Avi Kivity <avi@qumranet.com>
+ * Marcelo Tosatti <mtosatti@redhat.com>
+ * Xiao Guangrong <xiaoguangrong@cn.fujitsu.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <linux/ratelimit.h>
+
+static int audit_point;
+
+#define audit_printk(fmt, args...) \
+ printk(KERN_ERR "audit: (%s) error: " \
+ fmt, audit_point_name[audit_point], ##args)
+
+typedef void (*inspect_spte_fn) (struct kvm_vcpu *vcpu, u64 *sptep, int level);
+
+static void __mmu_spte_walk(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
+ inspect_spte_fn fn, int level)
+{
+ int i;
+
+ for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
+ u64 *ent = sp->spt;
+
+ fn(vcpu, ent + i, level);
+
+ if (is_shadow_present_pte(ent[i]) &&
+ !is_last_spte(ent[i], level)) {
+ struct kvm_mmu_page *child;
+
+ child = page_header(ent[i] & PT64_BASE_ADDR_MASK);
+ __mmu_spte_walk(vcpu, child, fn, level - 1);
+ }
+ }
+}
+
+static void mmu_spte_walk(struct kvm_vcpu *vcpu, inspect_spte_fn fn)
+{
+ int i;
+ struct kvm_mmu_page *sp;
+
+ if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
+ return;
+
+ if (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL) {
+ hpa_t root = vcpu->arch.mmu.root_hpa;
+
+ sp = page_header(root);
+ __mmu_spte_walk(vcpu, sp, fn, PT64_ROOT_LEVEL);
+ return;
+ }
+
+ for (i = 0; i < 4; ++i) {
+ hpa_t root = vcpu->arch.mmu.pae_root[i];
+
+ if (root && VALID_PAGE(root)) {
+ root &= PT64_BASE_ADDR_MASK;
+ sp = page_header(root);
+ __mmu_spte_walk(vcpu, sp, fn, 2);
+ }
+ }
+
+ return;
+}
+
+typedef void (*sp_handler) (struct kvm *kvm, struct kvm_mmu_page *sp);
+
+static void walk_all_active_sps(struct kvm *kvm, sp_handler fn)
+{
+ struct kvm_mmu_page *sp;
+
+ list_for_each_entry(sp, &kvm->arch.active_mmu_pages, link)
+ fn(kvm, sp);
+}
+
+static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level)
+{
+ struct kvm_mmu_page *sp;
+ gfn_t gfn;
+ pfn_t pfn;
+ hpa_t hpa;
+
+ sp = page_header(__pa(sptep));
+
+ if (sp->unsync) {
+ if (level != PT_PAGE_TABLE_LEVEL) {
+ audit_printk("unsync sp: %p level = %d\n", sp, level);
+ return;
+ }
+
+ if (*sptep == shadow_notrap_nonpresent_pte) {
+ audit_printk("notrap spte in unsync sp: %p\n", sp);
+ return;
+ }
+ }
+
+ if (sp->role.direct && *sptep == shadow_notrap_nonpresent_pte) {
+ audit_printk("notrap spte in direct sp: %p\n", sp);
+ return;
+ }
+
+ if (!is_shadow_present_pte(*sptep) || !is_last_spte(*sptep, level))
+ return;
+
+ gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt);
+ pfn = gfn_to_pfn_atomic(vcpu->kvm, gfn);
+
+ if (is_error_pfn(pfn)) {
+ kvm_release_pfn_clean(pfn);
+ return;
+ }
+
+ hpa = pfn << PAGE_SHIFT;
+ if ((*sptep & PT64_BASE_ADDR_MASK) != hpa)
+ audit_printk("levels %d pfn %llx hpa %llx ent %llxn",
+ vcpu->arch.mmu.root_level, pfn, hpa, *sptep);
+}
+
+static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
+{
+ unsigned long *rmapp;
+ struct kvm_mmu_page *rev_sp;
+ gfn_t gfn;
+
+
+ rev_sp = page_header(__pa(sptep));
+ gfn = kvm_mmu_page_get_gfn(rev_sp, sptep - rev_sp->spt);
+
+ if (!gfn_to_memslot(kvm, gfn)) {
+ if (!printk_ratelimit())
+ return;
+ audit_printk("no memslot for gfn %llx\n", gfn);
+ audit_printk("index %ld of sp (gfn=%llx)\n",
+ (long int)(sptep - rev_sp->spt), rev_sp->gfn);
+ dump_stack();
+ return;
+ }
+
+ rmapp = gfn_to_rmap(kvm, gfn, rev_sp->role.level);
+ if (!*rmapp) {
+ if (!printk_ratelimit())
+ return;
+ audit_printk("no rmap for writable spte %llx\n", *sptep);
+ dump_stack();
+ }
+}
+
+static void audit_sptes_have_rmaps(struct kvm_vcpu *vcpu, u64 *sptep, int level)
+{
+ if (is_shadow_present_pte(*sptep) && is_last_spte(*sptep, level))
+ inspect_spte_has_rmap(vcpu->kvm, sptep);
+}
+
+static void audit_spte_after_sync(struct kvm_vcpu *vcpu, u64 *sptep, int level)
+{
+ struct kvm_mmu_page *sp = page_header(__pa(sptep));
+
+ if (audit_point == AUDIT_POST_SYNC && sp->unsync)
+ audit_printk("meet unsync sp(%p) after sync root.\n", sp);
+}
+
+static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp)
+{
+ int i;
+
+ if (sp->role.level != PT_PAGE_TABLE_LEVEL)
+ return;
+
+ for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
+ if (!is_rmap_spte(sp->spt[i]))
+ continue;
+
+ inspect_spte_has_rmap(kvm, sp->spt + i);
+ }
+}
+
+static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp)
+{
+ struct kvm_memory_slot *slot;
+ unsigned long *rmapp;
+ u64 *spte;
+
+ if (sp->role.direct || sp->unsync || sp->role.invalid)
+ return;
+
+ slot = gfn_to_memslot(kvm, sp->gfn);
+ rmapp = &slot->rmap[sp->gfn - slot->base_gfn];
+
+ spte = rmap_next(kvm, rmapp, NULL);
+ while (spte) {
+ if (is_writable_pte(*spte))
+ audit_printk("shadow page has writable mappings: gfn "
+ "%llx role %x\n", sp->gfn, sp->role.word);
+ spte = rmap_next(kvm, rmapp, spte);
+ }
+}
+
+static void audit_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
+{
+ check_mappings_rmap(kvm, sp);
+ audit_write_protection(kvm, sp);
+}
+
+static void audit_all_active_sps(struct kvm *kvm)
+{
+ walk_all_active_sps(kvm, audit_sp);
+}
+
+static void audit_spte(struct kvm_vcpu *vcpu, u64 *sptep, int level)
+{
+ audit_sptes_have_rmaps(vcpu, sptep, level);
+ audit_mappings(vcpu, sptep, level);
+ audit_spte_after_sync(vcpu, sptep, level);
+}
+
+static void audit_vcpu_spte(struct kvm_vcpu *vcpu)
+{
+ mmu_spte_walk(vcpu, audit_spte);
+}
+
+static void kvm_mmu_audit(void *ignore, struct kvm_vcpu *vcpu, int point)
+{
+ static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10);
+
+ if (!__ratelimit(&ratelimit_state))
+ return;
+
+ audit_point = point;
+ audit_all_active_sps(vcpu->kvm);
+ audit_vcpu_spte(vcpu);
+}
+
+static bool mmu_audit;
+
+static void mmu_audit_enable(void)
+{
+ int ret;
+
+ if (mmu_audit)
+ return;
+
+ ret = register_trace_kvm_mmu_audit(kvm_mmu_audit, NULL);
+ WARN_ON(ret);
+
+ mmu_audit = true;
+}
+
+static void mmu_audit_disable(void)
+{
+ if (!mmu_audit)
+ return;
+
+ unregister_trace_kvm_mmu_audit(kvm_mmu_audit, NULL);
+ tracepoint_synchronize_unregister();
+ mmu_audit = false;
+}
+
+static int mmu_audit_set(const char *val, const struct kernel_param *kp)
+{
+ int ret;
+ unsigned long enable;
+
+ ret = strict_strtoul(val, 10, &enable);
+ if (ret < 0)
+ return -EINVAL;
+
+ switch (enable) {
+ case 0:
+ mmu_audit_disable();
+ break;
+ case 1:
+ mmu_audit_enable();
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct kernel_param_ops audit_param_ops = {
+ .set = mmu_audit_set,
+ .get = param_get_bool,
+};
+
+module_param_cb(mmu_audit, &audit_param_ops, &mmu_audit, 0644);
diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h
index 3aab0f0930ef..b60b4fdb3eda 100644
--- a/arch/x86/kvm/mmutrace.h
+++ b/arch/x86/kvm/mmutrace.h
@@ -195,6 +195,25 @@ DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_prepare_zap_page,
TP_ARGS(sp)
);
+
+TRACE_EVENT(
+ kvm_mmu_audit,
+ TP_PROTO(struct kvm_vcpu *vcpu, int audit_point),
+ TP_ARGS(vcpu, audit_point),
+
+ TP_STRUCT__entry(
+ __field(struct kvm_vcpu *, vcpu)
+ __field(int, audit_point)
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu = vcpu;
+ __entry->audit_point = audit_point;
+ ),
+
+ TP_printk("vcpu:%d %s", __entry->vcpu->cpu,
+ audit_point_name[__entry->audit_point])
+);
#endif /* _TRACE_KVMMMU_H */
#undef TRACE_INCLUDE_PATH
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 51ef9097960d..cd7a833a3b52 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -7,7 +7,7 @@
* MMU support
*
* Copyright (C) 2006 Qumranet, Inc.
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
*
* Authors:
* Yaniv Kamay <yaniv@qumranet.com>
@@ -67,6 +67,7 @@ struct guest_walker {
int level;
gfn_t table_gfn[PT_MAX_FULL_LEVELS];
pt_element_t ptes[PT_MAX_FULL_LEVELS];
+ pt_element_t prefetch_ptes[PTE_PREFETCH_NUM];
gpa_t pte_gpa[PT_MAX_FULL_LEVELS];
unsigned pt_access;
unsigned pte_access;
@@ -104,7 +105,7 @@ static unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, pt_element_t gpte)
access = (gpte & (PT_WRITABLE_MASK | PT_USER_MASK)) | ACC_EXEC_MASK;
#if PTTYPE == 64
- if (is_nx(vcpu))
+ if (vcpu->arch.mmu.nx)
access &= ~(gpte >> PT64_NX_SHIFT);
#endif
return access;
@@ -113,26 +114,32 @@ static unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, pt_element_t gpte)
/*
* Fetch a guest pte for a guest virtual address
*/
-static int FNAME(walk_addr)(struct guest_walker *walker,
- struct kvm_vcpu *vcpu, gva_t addr,
- int write_fault, int user_fault, int fetch_fault)
+static int FNAME(walk_addr_generic)(struct guest_walker *walker,
+ struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
+ gva_t addr, u32 access)
{
pt_element_t pte;
gfn_t table_gfn;
unsigned index, pt_access, uninitialized_var(pte_access);
gpa_t pte_gpa;
bool eperm, present, rsvd_fault;
+ int offset, write_fault, user_fault, fetch_fault;
+
+ write_fault = access & PFERR_WRITE_MASK;
+ user_fault = access & PFERR_USER_MASK;
+ fetch_fault = access & PFERR_FETCH_MASK;
trace_kvm_mmu_pagetable_walk(addr, write_fault, user_fault,
fetch_fault);
walk:
present = true;
eperm = rsvd_fault = false;
- walker->level = vcpu->arch.mmu.root_level;
- pte = vcpu->arch.cr3;
+ walker->level = mmu->root_level;
+ pte = mmu->get_cr3(vcpu);
+
#if PTTYPE == 64
- if (!is_long_mode(vcpu)) {
- pte = kvm_pdptr_read(vcpu, (addr >> 30) & 3);
+ if (walker->level == PT32E_ROOT_LEVEL) {
+ pte = kvm_pdptr_read_mmu(vcpu, mmu, (addr >> 30) & 3);
trace_kvm_mmu_paging_element(pte, walker->level);
if (!is_present_gpte(pte)) {
present = false;
@@ -142,7 +149,7 @@ walk:
}
#endif
ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) ||
- (vcpu->arch.cr3 & CR3_NONPAE_RESERVED_BITS) == 0);
+ (mmu->get_cr3(vcpu) & CR3_NONPAE_RESERVED_BITS) == 0);
pt_access = ACC_ALL;
@@ -150,12 +157,14 @@ walk:
index = PT_INDEX(addr, walker->level);
table_gfn = gpte_to_gfn(pte);
- pte_gpa = gfn_to_gpa(table_gfn);
- pte_gpa += index * sizeof(pt_element_t);
+ offset = index * sizeof(pt_element_t);
+ pte_gpa = gfn_to_gpa(table_gfn) + offset;
walker->table_gfn[walker->level - 1] = table_gfn;
walker->pte_gpa[walker->level - 1] = pte_gpa;
- if (kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte))) {
+ if (kvm_read_guest_page_mmu(vcpu, mmu, table_gfn, &pte,
+ offset, sizeof(pte),
+ PFERR_USER_MASK|PFERR_WRITE_MASK)) {
present = false;
break;
}
@@ -167,7 +176,7 @@ walk:
break;
}
- if (is_rsvd_bits_set(vcpu, pte, walker->level)) {
+ if (is_rsvd_bits_set(&vcpu->arch.mmu, pte, walker->level)) {
rsvd_fault = true;
break;
}
@@ -204,17 +213,28 @@ walk:
(PTTYPE == 64 || is_pse(vcpu))) ||
((walker->level == PT_PDPE_LEVEL) &&
is_large_pte(pte) &&
- is_long_mode(vcpu))) {
+ mmu->root_level == PT64_ROOT_LEVEL)) {
int lvl = walker->level;
+ gpa_t real_gpa;
+ gfn_t gfn;
+ u32 ac;
- walker->gfn = gpte_to_gfn_lvl(pte, lvl);
- walker->gfn += (addr & PT_LVL_OFFSET_MASK(lvl))
- >> PAGE_SHIFT;
+ gfn = gpte_to_gfn_lvl(pte, lvl);
+ gfn += (addr & PT_LVL_OFFSET_MASK(lvl)) >> PAGE_SHIFT;
if (PTTYPE == 32 &&
walker->level == PT_DIRECTORY_LEVEL &&
is_cpuid_PSE36())
- walker->gfn += pse36_gfn_delta(pte);
+ gfn += pse36_gfn_delta(pte);
+
+ ac = write_fault | fetch_fault | user_fault;
+
+ real_gpa = mmu->translate_gpa(vcpu, gfn_to_gpa(gfn),
+ ac);
+ if (real_gpa == UNMAPPED_GVA)
+ return 0;
+
+ walker->gfn = real_gpa >> PAGE_SHIFT;
break;
}
@@ -249,18 +269,36 @@ error:
walker->error_code = 0;
if (present)
walker->error_code |= PFERR_PRESENT_MASK;
- if (write_fault)
- walker->error_code |= PFERR_WRITE_MASK;
- if (user_fault)
- walker->error_code |= PFERR_USER_MASK;
- if (fetch_fault && is_nx(vcpu))
+
+ walker->error_code |= write_fault | user_fault;
+
+ if (fetch_fault && mmu->nx)
walker->error_code |= PFERR_FETCH_MASK;
if (rsvd_fault)
walker->error_code |= PFERR_RSVD_MASK;
+
+ vcpu->arch.fault.address = addr;
+ vcpu->arch.fault.error_code = walker->error_code;
+
trace_kvm_mmu_walker_error(walker->error_code);
return 0;
}
+static int FNAME(walk_addr)(struct guest_walker *walker,
+ struct kvm_vcpu *vcpu, gva_t addr, u32 access)
+{
+ return FNAME(walk_addr_generic)(walker, vcpu, &vcpu->arch.mmu, addr,
+ access);
+}
+
+static int FNAME(walk_addr_nested)(struct guest_walker *walker,
+ struct kvm_vcpu *vcpu, gva_t addr,
+ u32 access)
+{
+ return FNAME(walk_addr_generic)(walker, vcpu, &vcpu->arch.nested_mmu,
+ addr, access);
+}
+
static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
u64 *spte, const void *pte)
{
@@ -302,14 +340,87 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
static bool FNAME(gpte_changed)(struct kvm_vcpu *vcpu,
struct guest_walker *gw, int level)
{
- int r;
pt_element_t curr_pte;
-
- r = kvm_read_guest_atomic(vcpu->kvm, gw->pte_gpa[level - 1],
+ gpa_t base_gpa, pte_gpa = gw->pte_gpa[level - 1];
+ u64 mask;
+ int r, index;
+
+ if (level == PT_PAGE_TABLE_LEVEL) {
+ mask = PTE_PREFETCH_NUM * sizeof(pt_element_t) - 1;
+ base_gpa = pte_gpa & ~mask;
+ index = (pte_gpa - base_gpa) / sizeof(pt_element_t);
+
+ r = kvm_read_guest_atomic(vcpu->kvm, base_gpa,
+ gw->prefetch_ptes, sizeof(gw->prefetch_ptes));
+ curr_pte = gw->prefetch_ptes[index];
+ } else
+ r = kvm_read_guest_atomic(vcpu->kvm, pte_gpa,
&curr_pte, sizeof(curr_pte));
+
return r || curr_pte != gw->ptes[level - 1];
}
+static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw,
+ u64 *sptep)
+{
+ struct kvm_mmu_page *sp;
+ struct kvm_mmu *mmu = &vcpu->arch.mmu;
+ pt_element_t *gptep = gw->prefetch_ptes;
+ u64 *spte;
+ int i;
+
+ sp = page_header(__pa(sptep));
+
+ if (sp->role.level > PT_PAGE_TABLE_LEVEL)
+ return;
+
+ if (sp->role.direct)
+ return __direct_pte_prefetch(vcpu, sp, sptep);
+
+ i = (sptep - sp->spt) & ~(PTE_PREFETCH_NUM - 1);
+ spte = sp->spt + i;
+
+ for (i = 0; i < PTE_PREFETCH_NUM; i++, spte++) {
+ pt_element_t gpte;
+ unsigned pte_access;
+ gfn_t gfn;
+ pfn_t pfn;
+ bool dirty;
+
+ if (spte == sptep)
+ continue;
+
+ if (*spte != shadow_trap_nonpresent_pte)
+ continue;
+
+ gpte = gptep[i];
+
+ if (!is_present_gpte(gpte) ||
+ is_rsvd_bits_set(mmu, gpte, PT_PAGE_TABLE_LEVEL)) {
+ if (!sp->unsync)
+ __set_spte(spte, shadow_notrap_nonpresent_pte);
+ continue;
+ }
+
+ if (!(gpte & PT_ACCESSED_MASK))
+ continue;
+
+ pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
+ gfn = gpte_to_gfn(gpte);
+ dirty = is_dirty_gpte(gpte);
+ pfn = pte_prefetch_gfn_to_pfn(vcpu, gfn,
+ (pte_access & ACC_WRITE_MASK) && dirty);
+ if (is_error_pfn(pfn)) {
+ kvm_release_pfn_clean(pfn);
+ break;
+ }
+
+ mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0,
+ dirty, NULL, PT_PAGE_TABLE_LEVEL, gfn,
+ pfn, true, true);
+ }
+}
+
/*
* Fetch a shadow pte for a specific level in the paging hierarchy.
*/
@@ -391,6 +502,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
mmu_set_spte(vcpu, it.sptep, access, gw->pte_access & access,
user_fault, write_fault, dirty, ptwrite, it.level,
gw->gfn, pfn, false, true);
+ FNAME(pte_prefetch)(vcpu, gw, it.sptep);
return it.sptep;
@@ -420,7 +532,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
{
int write_fault = error_code & PFERR_WRITE_MASK;
int user_fault = error_code & PFERR_USER_MASK;
- int fetch_fault = error_code & PFERR_FETCH_MASK;
struct guest_walker walker;
u64 *sptep;
int write_pt = 0;
@@ -430,7 +541,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
unsigned long mmu_seq;
pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code);
- kvm_mmu_audit(vcpu, "pre page fault");
r = mmu_topup_memory_caches(vcpu);
if (r)
@@ -439,15 +549,14 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
/*
* Look up the guest pte for the faulting address.
*/
- r = FNAME(walk_addr)(&walker, vcpu, addr, write_fault, user_fault,
- fetch_fault);
+ r = FNAME(walk_addr)(&walker, vcpu, addr, error_code);
/*
* The page is not mapped by the guest. Let the guest handle it.
*/
if (!r) {
pgprintk("%s: guest page fault\n", __func__);
- inject_page_fault(vcpu, addr, walker.error_code);
+ inject_page_fault(vcpu);
vcpu->arch.last_pt_write_count = 0; /* reset fork detector */
return 0;
}
@@ -468,6 +577,8 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
spin_lock(&vcpu->kvm->mmu_lock);
if (mmu_notifier_retry(vcpu, mmu_seq))
goto out_unlock;
+
+ trace_kvm_mmu_audit(vcpu, AUDIT_PRE_PAGE_FAULT);
kvm_mmu_free_some_pages(vcpu);
sptep = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault,
level, &write_pt, pfn);
@@ -479,7 +590,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
vcpu->arch.last_pt_write_count = 0; /* reset fork detector */
++vcpu->stat.pf_fixed;
- kvm_mmu_audit(vcpu, "post page fault (fixed)");
+ trace_kvm_mmu_audit(vcpu, AUDIT_POST_PAGE_FAULT);
spin_unlock(&vcpu->kvm->mmu_lock);
return write_pt;
@@ -556,10 +667,25 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr, u32 access,
gpa_t gpa = UNMAPPED_GVA;
int r;
- r = FNAME(walk_addr)(&walker, vcpu, vaddr,
- !!(access & PFERR_WRITE_MASK),
- !!(access & PFERR_USER_MASK),
- !!(access & PFERR_FETCH_MASK));
+ r = FNAME(walk_addr)(&walker, vcpu, vaddr, access);
+
+ if (r) {
+ gpa = gfn_to_gpa(walker.gfn);
+ gpa |= vaddr & ~PAGE_MASK;
+ } else if (error)
+ *error = walker.error_code;
+
+ return gpa;
+}
+
+static gpa_t FNAME(gva_to_gpa_nested)(struct kvm_vcpu *vcpu, gva_t vaddr,
+ u32 access, u32 *error)
+{
+ struct guest_walker walker;
+ gpa_t gpa = UNMAPPED_GVA;
+ int r;
+
+ r = FNAME(walk_addr_nested)(&walker, vcpu, vaddr, access);
if (r) {
gpa = gfn_to_gpa(walker.gfn);
@@ -638,7 +764,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
return -EINVAL;
gfn = gpte_to_gfn(gpte);
- if (is_rsvd_bits_set(vcpu, gpte, PT_PAGE_TABLE_LEVEL)
+ if (is_rsvd_bits_set(&vcpu->arch.mmu, gpte, PT_PAGE_TABLE_LEVEL)
|| gfn != sp->gfns[i] || !is_present_gpte(gpte)
|| !(gpte & PT_ACCESSED_MASK)) {
u64 nonpresent;
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 8a3f9f64f86f..82e144a4e514 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -4,7 +4,7 @@
* AMD SVM support
*
* Copyright (C) 2006 Qumranet, Inc.
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
*
* Authors:
* Yaniv Kamay <yaniv@qumranet.com>
@@ -88,6 +88,14 @@ struct nested_state {
/* A VMEXIT is required but not yet emulated */
bool exit_required;
+ /*
+ * If we vmexit during an instruction emulation we need this to restore
+ * the l1 guest rip after the emulation
+ */
+ unsigned long vmexit_rip;
+ unsigned long vmexit_rsp;
+ unsigned long vmexit_rax;
+
/* cache for intercepts of the guest */
u16 intercept_cr_read;
u16 intercept_cr_write;
@@ -96,6 +104,8 @@ struct nested_state {
u32 intercept_exceptions;
u64 intercept;
+ /* Nested Paging related state */
+ u64 nested_cr3;
};
#define MSRPM_OFFSETS 16
@@ -284,6 +294,15 @@ static inline void flush_guest_tlb(struct kvm_vcpu *vcpu)
force_new_asid(vcpu);
}
+static int get_npt_level(void)
+{
+#ifdef CONFIG_X86_64
+ return PT64_ROOT_LEVEL;
+#else
+ return PT32E_ROOT_LEVEL;
+#endif
+}
+
static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
{
vcpu->arch.efer = efer;
@@ -701,6 +720,29 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
seg->base = 0;
}
+static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u64 g_tsc_offset = 0;
+
+ if (is_nested(svm)) {
+ g_tsc_offset = svm->vmcb->control.tsc_offset -
+ svm->nested.hsave->control.tsc_offset;
+ svm->nested.hsave->control.tsc_offset = offset;
+ }
+
+ svm->vmcb->control.tsc_offset = offset + g_tsc_offset;
+}
+
+static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ svm->vmcb->control.tsc_offset += adjustment;
+ if (is_nested(svm))
+ svm->nested.hsave->control.tsc_offset += adjustment;
+}
+
static void init_vmcb(struct vcpu_svm *svm)
{
struct vmcb_control_area *control = &svm->vmcb->control;
@@ -793,7 +835,7 @@ static void init_vmcb(struct vcpu_svm *svm)
init_sys_seg(&save->ldtr, SEG_TYPE_LDT);
init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16);
- save->efer = EFER_SVME;
+ svm_set_efer(&svm->vcpu, 0);
save->dr6 = 0xffff0ff0;
save->dr7 = 0x400;
save->rflags = 2;
@@ -804,8 +846,8 @@ static void init_vmcb(struct vcpu_svm *svm)
* This is the guest-visible cr0 value.
* svm_set_cr0() sets PG and WP and clears NW and CD on save->cr0.
*/
- svm->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
- (void)kvm_set_cr0(&svm->vcpu, svm->vcpu.arch.cr0);
+ svm->vcpu.arch.cr0 = 0;
+ (void)kvm_set_cr0(&svm->vcpu, X86_CR0_NW | X86_CR0_CD | X86_CR0_ET);
save->cr4 = X86_CR4_PAE;
/* rdx = ?? */
@@ -901,7 +943,7 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
svm->asid_generation = 0;
init_vmcb(svm);
- svm->vmcb->control.tsc_offset = 0-native_read_tsc();
+ kvm_write_tsc(&svm->vcpu, 0);
err = fx_init(&svm->vcpu);
if (err)
@@ -947,20 +989,6 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
int i;
if (unlikely(cpu != vcpu->cpu)) {
- u64 delta;
-
- if (check_tsc_unstable()) {
- /*
- * Make sure that the guest sees a monotonically
- * increasing TSC.
- */
- delta = vcpu->arch.host_tsc - native_read_tsc();
- svm->vmcb->control.tsc_offset += delta;
- if (is_nested(svm))
- svm->nested.hsave->control.tsc_offset += delta;
- }
- vcpu->cpu = cpu;
- kvm_migrate_timers(vcpu);
svm->asid_generation = 0;
}
@@ -976,8 +1004,6 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
++vcpu->stat.host_state_reload;
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
-
- vcpu->arch.host_tsc = native_read_tsc();
}
static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
@@ -995,7 +1021,7 @@ static void svm_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
switch (reg) {
case VCPU_EXREG_PDPTR:
BUG_ON(!npt_enabled);
- load_pdptrs(vcpu, vcpu->arch.cr3);
+ load_pdptrs(vcpu, vcpu->arch.walk_mmu, vcpu->arch.cr3);
break;
default:
BUG();
@@ -1206,8 +1232,12 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
if (old == new) {
/* cr0 write with ts and mp unchanged */
svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE;
- if (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE)
+ if (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE) {
+ svm->nested.vmexit_rip = kvm_rip_read(vcpu);
+ svm->nested.vmexit_rsp = kvm_register_read(vcpu, VCPU_REGS_RSP);
+ svm->nested.vmexit_rax = kvm_register_read(vcpu, VCPU_REGS_RAX);
return;
+ }
}
}
@@ -1581,6 +1611,54 @@ static int vmmcall_interception(struct vcpu_svm *svm)
return 1;
}
+static unsigned long nested_svm_get_tdp_cr3(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ return svm->nested.nested_cr3;
+}
+
+static void nested_svm_set_tdp_cr3(struct kvm_vcpu *vcpu,
+ unsigned long root)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ svm->vmcb->control.nested_cr3 = root;
+ force_new_asid(vcpu);
+}
+
+static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ svm->vmcb->control.exit_code = SVM_EXIT_NPF;
+ svm->vmcb->control.exit_code_hi = 0;
+ svm->vmcb->control.exit_info_1 = vcpu->arch.fault.error_code;
+ svm->vmcb->control.exit_info_2 = vcpu->arch.fault.address;
+
+ nested_svm_vmexit(svm);
+}
+
+static int nested_svm_init_mmu_context(struct kvm_vcpu *vcpu)
+{
+ int r;
+
+ r = kvm_init_shadow_mmu(vcpu, &vcpu->arch.mmu);
+
+ vcpu->arch.mmu.set_cr3 = nested_svm_set_tdp_cr3;
+ vcpu->arch.mmu.get_cr3 = nested_svm_get_tdp_cr3;
+ vcpu->arch.mmu.inject_page_fault = nested_svm_inject_npf_exit;
+ vcpu->arch.mmu.shadow_root_level = get_npt_level();
+ vcpu->arch.walk_mmu = &vcpu->arch.nested_mmu;
+
+ return r;
+}
+
+static void nested_svm_uninit_mmu_context(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.walk_mmu = &vcpu->arch.mmu;
+}
+
static int nested_svm_check_permissions(struct vcpu_svm *svm)
{
if (!(svm->vcpu.arch.efer & EFER_SVME)
@@ -1629,6 +1707,14 @@ static inline bool nested_svm_intr(struct vcpu_svm *svm)
if (!(svm->vcpu.arch.hflags & HF_HIF_MASK))
return false;
+ /*
+ * if vmexit was already requested (by intercepted exception
+ * for instance) do not overwrite it with "external interrupt"
+ * vmexit.
+ */
+ if (svm->nested.exit_required)
+ return false;
+
svm->vmcb->control.exit_code = SVM_EXIT_INTR;
svm->vmcb->control.exit_info_1 = 0;
svm->vmcb->control.exit_info_2 = 0;
@@ -1896,6 +1982,7 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
nested_vmcb->save.ds = vmcb->save.ds;
nested_vmcb->save.gdtr = vmcb->save.gdtr;
nested_vmcb->save.idtr = vmcb->save.idtr;
+ nested_vmcb->save.efer = svm->vcpu.arch.efer;
nested_vmcb->save.cr0 = kvm_read_cr0(&svm->vcpu);
nested_vmcb->save.cr3 = svm->vcpu.arch.cr3;
nested_vmcb->save.cr2 = vmcb->save.cr2;
@@ -1917,6 +2004,7 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
nested_vmcb->control.exit_info_2 = vmcb->control.exit_info_2;
nested_vmcb->control.exit_int_info = vmcb->control.exit_int_info;
nested_vmcb->control.exit_int_info_err = vmcb->control.exit_int_info_err;
+ nested_vmcb->control.next_rip = vmcb->control.next_rip;
/*
* If we emulate a VMRUN/#VMEXIT in the same host #vmexit cycle we have
@@ -1947,6 +2035,8 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
kvm_clear_exception_queue(&svm->vcpu);
kvm_clear_interrupt_queue(&svm->vcpu);
+ svm->nested.nested_cr3 = 0;
+
/* Restore selected save entries */
svm->vmcb->save.es = hsave->save.es;
svm->vmcb->save.cs = hsave->save.cs;
@@ -1973,6 +2063,7 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
nested_svm_unmap(page);
+ nested_svm_uninit_mmu_context(&svm->vcpu);
kvm_mmu_reset_context(&svm->vcpu);
kvm_mmu_load(&svm->vcpu);
@@ -2012,6 +2103,20 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
return true;
}
+static bool nested_vmcb_checks(struct vmcb *vmcb)
+{
+ if ((vmcb->control.intercept & (1ULL << INTERCEPT_VMRUN)) == 0)
+ return false;
+
+ if (vmcb->control.asid == 0)
+ return false;
+
+ if (vmcb->control.nested_ctl && !npt_enabled)
+ return false;
+
+ return true;
+}
+
static bool nested_svm_vmrun(struct vcpu_svm *svm)
{
struct vmcb *nested_vmcb;
@@ -2026,7 +2131,18 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
if (!nested_vmcb)
return false;
- trace_kvm_nested_vmrun(svm->vmcb->save.rip - 3, vmcb_gpa,
+ if (!nested_vmcb_checks(nested_vmcb)) {
+ nested_vmcb->control.exit_code = SVM_EXIT_ERR;
+ nested_vmcb->control.exit_code_hi = 0;
+ nested_vmcb->control.exit_info_1 = 0;
+ nested_vmcb->control.exit_info_2 = 0;
+
+ nested_svm_unmap(page);
+
+ return false;
+ }
+
+ trace_kvm_nested_vmrun(svm->vmcb->save.rip, vmcb_gpa,
nested_vmcb->save.rip,
nested_vmcb->control.int_ctl,
nested_vmcb->control.event_inj,
@@ -2055,7 +2171,7 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
hsave->save.cr0 = kvm_read_cr0(&svm->vcpu);
hsave->save.cr4 = svm->vcpu.arch.cr4;
hsave->save.rflags = vmcb->save.rflags;
- hsave->save.rip = svm->next_rip;
+ hsave->save.rip = kvm_rip_read(&svm->vcpu);
hsave->save.rsp = vmcb->save.rsp;
hsave->save.rax = vmcb->save.rax;
if (npt_enabled)
@@ -2070,6 +2186,12 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
else
svm->vcpu.arch.hflags &= ~HF_HIF_MASK;
+ if (nested_vmcb->control.nested_ctl) {
+ kvm_mmu_unload(&svm->vcpu);
+ svm->nested.nested_cr3 = nested_vmcb->control.nested_cr3;
+ nested_svm_init_mmu_context(&svm->vcpu);
+ }
+
/* Load the nested guest state */
svm->vmcb->save.es = nested_vmcb->save.es;
svm->vmcb->save.cs = nested_vmcb->save.cs;
@@ -2227,8 +2349,8 @@ static int vmrun_interception(struct vcpu_svm *svm)
if (nested_svm_check_permissions(svm))
return 1;
- svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
- skip_emulated_instruction(&svm->vcpu);
+ /* Save rip after vmrun instruction */
+ kvm_rip_write(&svm->vcpu, kvm_rip_read(&svm->vcpu) + 3);
if (!nested_svm_vmrun(svm))
return 1;
@@ -2257,6 +2379,7 @@ static int stgi_interception(struct vcpu_svm *svm)
svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
skip_emulated_instruction(&svm->vcpu);
+ kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
enable_gif(svm);
@@ -2399,6 +2522,23 @@ static int emulate_on_interception(struct vcpu_svm *svm)
return emulate_instruction(&svm->vcpu, 0, 0, 0) == EMULATE_DONE;
}
+static int cr0_write_interception(struct vcpu_svm *svm)
+{
+ struct kvm_vcpu *vcpu = &svm->vcpu;
+ int r;
+
+ r = emulate_instruction(&svm->vcpu, 0, 0, 0);
+
+ if (svm->nested.vmexit_rip) {
+ kvm_register_write(vcpu, VCPU_REGS_RIP, svm->nested.vmexit_rip);
+ kvm_register_write(vcpu, VCPU_REGS_RSP, svm->nested.vmexit_rsp);
+ kvm_register_write(vcpu, VCPU_REGS_RAX, svm->nested.vmexit_rax);
+ svm->nested.vmexit_rip = 0;
+ }
+
+ return r == EMULATE_DONE;
+}
+
static int cr8_write_interception(struct vcpu_svm *svm)
{
struct kvm_run *kvm_run = svm->vcpu.run;
@@ -2542,20 +2682,9 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
struct vcpu_svm *svm = to_svm(vcpu);
switch (ecx) {
- case MSR_IA32_TSC: {
- u64 tsc_offset = data - native_read_tsc();
- u64 g_tsc_offset = 0;
-
- if (is_nested(svm)) {
- g_tsc_offset = svm->vmcb->control.tsc_offset -
- svm->nested.hsave->control.tsc_offset;
- svm->nested.hsave->control.tsc_offset = tsc_offset;
- }
-
- svm->vmcb->control.tsc_offset = tsc_offset + g_tsc_offset;
-
+ case MSR_IA32_TSC:
+ kvm_write_tsc(vcpu, data);
break;
- }
case MSR_STAR:
svm->vmcb->save.star = data;
break;
@@ -2643,6 +2772,7 @@ static int interrupt_window_interception(struct vcpu_svm *svm)
{
struct kvm_run *kvm_run = svm->vcpu.run;
+ kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
svm_clear_vintr(svm);
svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
/*
@@ -2672,7 +2802,7 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = {
[SVM_EXIT_READ_CR4] = emulate_on_interception,
[SVM_EXIT_READ_CR8] = emulate_on_interception,
[SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception,
- [SVM_EXIT_WRITE_CR0] = emulate_on_interception,
+ [SVM_EXIT_WRITE_CR0] = cr0_write_interception,
[SVM_EXIT_WRITE_CR3] = emulate_on_interception,
[SVM_EXIT_WRITE_CR4] = emulate_on_interception,
[SVM_EXIT_WRITE_CR8] = cr8_write_interception,
@@ -2871,7 +3001,8 @@ static int handle_exit(struct kvm_vcpu *vcpu)
if (is_external_interrupt(svm->vmcb->control.exit_int_info) &&
exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR &&
- exit_code != SVM_EXIT_NPF && exit_code != SVM_EXIT_TASK_SWITCH)
+ exit_code != SVM_EXIT_NPF && exit_code != SVM_EXIT_TASK_SWITCH &&
+ exit_code != SVM_EXIT_INTR && exit_code != SVM_EXIT_NMI)
printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x "
"exit_code 0x%x\n",
__func__, svm->vmcb->control.exit_int_info,
@@ -3088,8 +3219,10 @@ static void svm_complete_interrupts(struct vcpu_svm *svm)
svm->int3_injected = 0;
- if (svm->vcpu.arch.hflags & HF_IRET_MASK)
+ if (svm->vcpu.arch.hflags & HF_IRET_MASK) {
svm->vcpu.arch.hflags &= ~(HF_NMI_MASK | HF_IRET_MASK);
+ kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
+ }
svm->vcpu.arch.nmi_injected = false;
kvm_clear_exception_queue(&svm->vcpu);
@@ -3098,6 +3231,8 @@ static void svm_complete_interrupts(struct vcpu_svm *svm)
if (!(exitintinfo & SVM_EXITINTINFO_VALID))
return;
+ kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
+
vector = exitintinfo & SVM_EXITINTINFO_VEC_MASK;
type = exitintinfo & SVM_EXITINTINFO_TYPE_MASK;
@@ -3134,6 +3269,17 @@ static void svm_complete_interrupts(struct vcpu_svm *svm)
}
}
+static void svm_cancel_injection(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ struct vmcb_control_area *control = &svm->vmcb->control;
+
+ control->exit_int_info = control->event_inj;
+ control->exit_int_info_err = control->event_inj_err;
+ control->event_inj = 0;
+ svm_complete_interrupts(svm);
+}
+
#ifdef CONFIG_X86_64
#define R "r"
#else
@@ -3167,9 +3313,6 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
savesegment(gs, gs_selector);
ldt_selector = kvm_read_ldt();
svm->vmcb->save.cr2 = vcpu->arch.cr2;
- /* required for live migration with NPT */
- if (npt_enabled)
- svm->vmcb->save.cr3 = vcpu->arch.cr3;
clgi();
@@ -3291,16 +3434,22 @@ static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
{
struct vcpu_svm *svm = to_svm(vcpu);
- if (npt_enabled) {
- svm->vmcb->control.nested_cr3 = root;
- force_new_asid(vcpu);
- return;
- }
-
svm->vmcb->save.cr3 = root;
force_new_asid(vcpu);
}
+static void set_tdp_cr3(struct kvm_vcpu *vcpu, unsigned long root)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ svm->vmcb->control.nested_cr3 = root;
+
+ /* Also sync guest cr3 here in case we live migrate */
+ svm->vmcb->save.cr3 = vcpu->arch.cr3;
+
+ force_new_asid(vcpu);
+}
+
static int is_disabled(void)
{
u64 vm_cr;
@@ -3333,15 +3482,6 @@ static bool svm_cpu_has_accelerated_tpr(void)
return false;
}
-static int get_npt_level(void)
-{
-#ifdef CONFIG_X86_64
- return PT64_ROOT_LEVEL;
-#else
- return PT32E_ROOT_LEVEL;
-#endif
-}
-
static u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
{
return 0;
@@ -3354,12 +3494,25 @@ static void svm_cpuid_update(struct kvm_vcpu *vcpu)
static void svm_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry)
{
switch (func) {
+ case 0x80000001:
+ if (nested)
+ entry->ecx |= (1 << 2); /* Set SVM bit */
+ break;
case 0x8000000A:
entry->eax = 1; /* SVM revision 1 */
entry->ebx = 8; /* Lets support 8 ASIDs in case we add proper
ASID emulation to nested SVM */
entry->ecx = 0; /* Reserved */
- entry->edx = 0; /* Do not support any additional features */
+ entry->edx = 0; /* Per default do not support any
+ additional features */
+
+ /* Support next_rip if host supports it */
+ if (svm_has(SVM_FEATURE_NRIP))
+ entry->edx |= SVM_FEATURE_NRIP;
+
+ /* Support NPT for the guest if enabled */
+ if (npt_enabled)
+ entry->edx |= SVM_FEATURE_NPT;
break;
}
@@ -3497,6 +3650,7 @@ static struct kvm_x86_ops svm_x86_ops = {
.set_irq = svm_set_irq,
.set_nmi = svm_inject_nmi,
.queue_exception = svm_queue_exception,
+ .cancel_injection = svm_cancel_injection,
.interrupt_allowed = svm_interrupt_allowed,
.nmi_allowed = svm_nmi_allowed,
.get_nmi_mask = svm_get_nmi_mask,
@@ -3519,6 +3673,11 @@ static struct kvm_x86_ops svm_x86_ops = {
.set_supported_cpuid = svm_set_supported_cpuid,
.has_wbinvd_exit = svm_has_wbinvd_exit,
+
+ .write_tsc_offset = svm_write_tsc_offset,
+ .adjust_tsc_offset = svm_adjust_tsc_offset,
+
+ .set_tdp_cr3 = set_tdp_cr3,
};
static int __init svm_init(void)
diff --git a/arch/x86/kvm/timer.c b/arch/x86/kvm/timer.c
index e16a0dbe74d8..fc7a101c4a35 100644
--- a/arch/x86/kvm/timer.c
+++ b/arch/x86/kvm/timer.c
@@ -6,7 +6,7 @@
*
* timer support
*
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 7bddfab12013..8da0e45ff7c9 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -5,7 +5,7 @@
* machines without emulation or binary translation.
*
* Copyright (C) 2006 Qumranet, Inc.
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
*
* Authors:
* Avi Kivity <avi@qumranet.com>
@@ -125,6 +125,7 @@ struct vcpu_vmx {
unsigned long host_rsp;
int launched;
u8 fail;
+ u32 exit_intr_info;
u32 idt_vectoring_info;
struct shared_msr_entry *guest_msrs;
int nmsrs;
@@ -154,11 +155,6 @@ struct vcpu_vmx {
u32 limit;
u32 ar;
} tr, es, ds, fs, gs;
- struct {
- bool pending;
- u8 vector;
- unsigned rip;
- } irq;
} rmode;
int vpid;
bool emulation_required;
@@ -505,7 +501,6 @@ static void __vcpu_clear(void *arg)
vmcs_clear(vmx->vmcs);
if (per_cpu(current_vmcs, cpu) == vmx->vmcs)
per_cpu(current_vmcs, cpu) = NULL;
- rdtscll(vmx->vcpu.arch.host_tsc);
list_del(&vmx->local_vcpus_link);
vmx->vcpu.cpu = -1;
vmx->launched = 0;
@@ -706,11 +701,10 @@ static void reload_tss(void)
/*
* VT restores TR but not its size. Useless.
*/
- struct desc_ptr gdt;
+ struct desc_ptr *gdt = &__get_cpu_var(host_gdt);
struct desc_struct *descs;
- native_store_gdt(&gdt);
- descs = (void *)gdt.address;
+ descs = (void *)gdt->address;
descs[GDT_ENTRY_TSS].type = 9; /* available TSS */
load_TR_desc();
}
@@ -753,7 +747,7 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset)
static unsigned long segment_base(u16 selector)
{
- struct desc_ptr gdt;
+ struct desc_ptr *gdt = &__get_cpu_var(host_gdt);
struct desc_struct *d;
unsigned long table_base;
unsigned long v;
@@ -761,8 +755,7 @@ static unsigned long segment_base(u16 selector)
if (!(selector & ~3))
return 0;
- native_store_gdt(&gdt);
- table_base = gdt.address;
+ table_base = gdt->address;
if (selector & 4) { /* from ldt */
u16 ldt_selector = kvm_read_ldt();
@@ -883,7 +876,6 @@ static void vmx_load_host_state(struct vcpu_vmx *vmx)
static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
- u64 tsc_this, delta, new_offset;
u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
if (!vmm_exclusive)
@@ -897,37 +889,24 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
}
if (vcpu->cpu != cpu) {
- struct desc_ptr dt;
+ struct desc_ptr *gdt = &__get_cpu_var(host_gdt);
unsigned long sysenter_esp;
- kvm_migrate_timers(vcpu);
kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
local_irq_disable();
list_add(&vmx->local_vcpus_link,
&per_cpu(vcpus_on_cpu, cpu));
local_irq_enable();
- vcpu->cpu = cpu;
/*
* Linux uses per-cpu TSS and GDT, so set these when switching
* processors.
*/
vmcs_writel(HOST_TR_BASE, kvm_read_tr_base()); /* 22.2.4 */
- native_store_gdt(&dt);
- vmcs_writel(HOST_GDTR_BASE, dt.address); /* 22.2.4 */
+ vmcs_writel(HOST_GDTR_BASE, gdt->address); /* 22.2.4 */
rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp);
vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */
-
- /*
- * Make sure the time stamp counter is monotonous.
- */
- rdtscll(tsc_this);
- if (tsc_this < vcpu->arch.host_tsc) {
- delta = vcpu->arch.host_tsc - tsc_this;
- new_offset = vmcs_read64(TSC_OFFSET) + delta;
- vmcs_write64(TSC_OFFSET, new_offset);
- }
}
}
@@ -1044,16 +1023,8 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
}
if (vmx->rmode.vm86_active) {
- vmx->rmode.irq.pending = true;
- vmx->rmode.irq.vector = nr;
- vmx->rmode.irq.rip = kvm_rip_read(vcpu);
- if (kvm_exception_is_soft(nr))
- vmx->rmode.irq.rip +=
- vmx->vcpu.arch.event_exit_inst_len;
- intr_info |= INTR_TYPE_SOFT_INTR;
- vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info);
- vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1);
- kvm_rip_write(vcpu, vmx->rmode.irq.rip - 1);
+ if (kvm_inject_realmode_interrupt(vcpu, nr) != EMULATE_DONE)
+ kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
return;
}
@@ -1149,12 +1120,17 @@ static u64 guest_read_tsc(void)
}
/*
- * writes 'guest_tsc' into guest's timestamp counter "register"
- * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc
+ * writes 'offset' into guest's timestamp counter offset register
*/
-static void guest_write_tsc(u64 guest_tsc, u64 host_tsc)
+static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
+{
+ vmcs_write64(TSC_OFFSET, offset);
+}
+
+static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment)
{
- vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc);
+ u64 offset = vmcs_read64(TSC_OFFSET);
+ vmcs_write64(TSC_OFFSET, offset + adjustment);
}
/*
@@ -1227,7 +1203,6 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
struct shared_msr_entry *msr;
- u64 host_tsc;
int ret = 0;
switch (msr_index) {
@@ -1257,8 +1232,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
vmcs_writel(GUEST_SYSENTER_ESP, data);
break;
case MSR_IA32_TSC:
- rdtscll(host_tsc);
- guest_write_tsc(data, host_tsc);
+ kvm_write_tsc(vcpu, data);
break;
case MSR_IA32_CR_PAT:
if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) {
@@ -1856,20 +1830,20 @@ static void ept_load_pdptrs(struct kvm_vcpu *vcpu)
return;
if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) {
- vmcs_write64(GUEST_PDPTR0, vcpu->arch.pdptrs[0]);
- vmcs_write64(GUEST_PDPTR1, vcpu->arch.pdptrs[1]);
- vmcs_write64(GUEST_PDPTR2, vcpu->arch.pdptrs[2]);
- vmcs_write64(GUEST_PDPTR3, vcpu->arch.pdptrs[3]);
+ vmcs_write64(GUEST_PDPTR0, vcpu->arch.mmu.pdptrs[0]);
+ vmcs_write64(GUEST_PDPTR1, vcpu->arch.mmu.pdptrs[1]);
+ vmcs_write64(GUEST_PDPTR2, vcpu->arch.mmu.pdptrs[2]);
+ vmcs_write64(GUEST_PDPTR3, vcpu->arch.mmu.pdptrs[3]);
}
}
static void ept_save_pdptrs(struct kvm_vcpu *vcpu)
{
if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) {
- vcpu->arch.pdptrs[0] = vmcs_read64(GUEST_PDPTR0);
- vcpu->arch.pdptrs[1] = vmcs_read64(GUEST_PDPTR1);
- vcpu->arch.pdptrs[2] = vmcs_read64(GUEST_PDPTR2);
- vcpu->arch.pdptrs[3] = vmcs_read64(GUEST_PDPTR3);
+ vcpu->arch.mmu.pdptrs[0] = vmcs_read64(GUEST_PDPTR0);
+ vcpu->arch.mmu.pdptrs[1] = vmcs_read64(GUEST_PDPTR1);
+ vcpu->arch.mmu.pdptrs[2] = vmcs_read64(GUEST_PDPTR2);
+ vcpu->arch.mmu.pdptrs[3] = vmcs_read64(GUEST_PDPTR3);
}
__set_bit(VCPU_EXREG_PDPTR,
@@ -2515,7 +2489,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
{
u32 host_sysenter_cs, msr_low, msr_high;
u32 junk;
- u64 host_pat, tsc_this, tsc_base;
+ u64 host_pat;
unsigned long a;
struct desc_ptr dt;
int i;
@@ -2656,12 +2630,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
vmx->vcpu.arch.cr4_guest_owned_bits |= X86_CR4_PGE;
vmcs_writel(CR4_GUEST_HOST_MASK, ~vmx->vcpu.arch.cr4_guest_owned_bits);
- tsc_base = vmx->vcpu.kvm->arch.vm_init_tsc;
- rdtscll(tsc_this);
- if (tsc_this < vmx->vcpu.kvm->arch.vm_init_tsc)
- tsc_base = tsc_this;
-
- guest_write_tsc(0, tsc_base);
+ kvm_write_tsc(&vmx->vcpu, 0);
return 0;
}
@@ -2834,16 +2803,8 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu)
++vcpu->stat.irq_injections;
if (vmx->rmode.vm86_active) {
- vmx->rmode.irq.pending = true;
- vmx->rmode.irq.vector = irq;
- vmx->rmode.irq.rip = kvm_rip_read(vcpu);
- if (vcpu->arch.interrupt.soft)
- vmx->rmode.irq.rip +=
- vmx->vcpu.arch.event_exit_inst_len;
- vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
- irq | INTR_TYPE_SOFT_INTR | INTR_INFO_VALID_MASK);
- vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1);
- kvm_rip_write(vcpu, vmx->rmode.irq.rip - 1);
+ if (kvm_inject_realmode_interrupt(vcpu, irq) != EMULATE_DONE)
+ kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
return;
}
intr = irq | INTR_INFO_VALID_MASK;
@@ -2875,14 +2836,8 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
++vcpu->stat.nmi_injections;
if (vmx->rmode.vm86_active) {
- vmx->rmode.irq.pending = true;
- vmx->rmode.irq.vector = NMI_VECTOR;
- vmx->rmode.irq.rip = kvm_rip_read(vcpu);
- vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
- NMI_VECTOR | INTR_TYPE_SOFT_INTR |
- INTR_INFO_VALID_MASK);
- vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1);
- kvm_rip_write(vcpu, vmx->rmode.irq.rip - 1);
+ if (kvm_inject_realmode_interrupt(vcpu, NMI_VECTOR) != EMULATE_DONE)
+ kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
return;
}
vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
@@ -3346,6 +3301,7 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu)
static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu)
{
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
return 1;
}
@@ -3358,6 +3314,8 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu)
cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
+
++vcpu->stat.irq_window_exits;
/*
@@ -3614,6 +3572,7 @@ static int handle_nmi_window(struct kvm_vcpu *vcpu)
cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_NMI_PENDING;
vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
++vcpu->stat.nmi_window_exits;
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
return 1;
}
@@ -3623,8 +3582,17 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu)
struct vcpu_vmx *vmx = to_vmx(vcpu);
enum emulation_result err = EMULATE_DONE;
int ret = 1;
+ u32 cpu_exec_ctrl;
+ bool intr_window_requested;
+
+ cpu_exec_ctrl = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+ intr_window_requested = cpu_exec_ctrl & CPU_BASED_VIRTUAL_INTR_PENDING;
while (!guest_state_valid(vcpu)) {
+ if (intr_window_requested
+ && (kvm_get_rflags(&vmx->vcpu) & X86_EFLAGS_IF))
+ return handle_interrupt_window(&vmx->vcpu);
+
err = emulate_instruction(vcpu, 0, 0, 0);
if (err == EMULATE_DO_MMIO) {
@@ -3790,18 +3758,9 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
vmcs_write32(TPR_THRESHOLD, irr);
}
-static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
+static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx)
{
- u32 exit_intr_info;
- u32 idt_vectoring_info = vmx->idt_vectoring_info;
- bool unblock_nmi;
- u8 vector;
- int type;
- bool idtv_info_valid;
-
- exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
-
- vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);
+ u32 exit_intr_info = vmx->exit_intr_info;
/* Handle machine checks before interrupts are enabled */
if ((vmx->exit_reason == EXIT_REASON_MCE_DURING_VMENTRY)
@@ -3816,8 +3775,16 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
asm("int $2");
kvm_after_handle_nmi(&vmx->vcpu);
}
+}
- idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK;
+static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx)
+{
+ u32 exit_intr_info = vmx->exit_intr_info;
+ bool unblock_nmi;
+ u8 vector;
+ bool idtv_info_valid;
+
+ idtv_info_valid = vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK;
if (cpu_has_virtual_nmis()) {
unblock_nmi = (exit_intr_info & INTR_INFO_UNBLOCK_NMI) != 0;
@@ -3839,6 +3806,18 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
} else if (unlikely(vmx->soft_vnmi_blocked))
vmx->vnmi_blocked_time +=
ktime_to_ns(ktime_sub(ktime_get(), vmx->entry_time));
+}
+
+static void __vmx_complete_interrupts(struct vcpu_vmx *vmx,
+ u32 idt_vectoring_info,
+ int instr_len_field,
+ int error_code_field)
+{
+ u8 vector;
+ int type;
+ bool idtv_info_valid;
+
+ idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK;
vmx->vcpu.arch.nmi_injected = false;
kvm_clear_exception_queue(&vmx->vcpu);
@@ -3847,6 +3826,8 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
if (!idtv_info_valid)
return;
+ kvm_make_request(KVM_REQ_EVENT, &vmx->vcpu);
+
vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK;
type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK;
@@ -3863,18 +3844,18 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
break;
case INTR_TYPE_SOFT_EXCEPTION:
vmx->vcpu.arch.event_exit_inst_len =
- vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+ vmcs_read32(instr_len_field);
/* fall through */
case INTR_TYPE_HARD_EXCEPTION:
if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK) {
- u32 err = vmcs_read32(IDT_VECTORING_ERROR_CODE);
+ u32 err = vmcs_read32(error_code_field);
kvm_queue_exception_e(&vmx->vcpu, vector, err);
} else
kvm_queue_exception(&vmx->vcpu, vector);
break;
case INTR_TYPE_SOFT_INTR:
vmx->vcpu.arch.event_exit_inst_len =
- vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+ vmcs_read32(instr_len_field);
/* fall through */
case INTR_TYPE_EXT_INTR:
kvm_queue_interrupt(&vmx->vcpu, vector,
@@ -3885,27 +3866,21 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
}
}
-/*
- * Failure to inject an interrupt should give us the information
- * in IDT_VECTORING_INFO_FIELD. However, if the failure occurs
- * when fetching the interrupt redirection bitmap in the real-mode
- * tss, this doesn't happen. So we do it ourselves.
- */
-static void fixup_rmode_irq(struct vcpu_vmx *vmx)
+static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
{
- vmx->rmode.irq.pending = 0;
- if (kvm_rip_read(&vmx->vcpu) + 1 != vmx->rmode.irq.rip)
- return;
- kvm_rip_write(&vmx->vcpu, vmx->rmode.irq.rip);
- if (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK) {
- vmx->idt_vectoring_info &= ~VECTORING_INFO_TYPE_MASK;
- vmx->idt_vectoring_info |= INTR_TYPE_EXT_INTR;
- return;
- }
- vmx->idt_vectoring_info =
- VECTORING_INFO_VALID_MASK
- | INTR_TYPE_EXT_INTR
- | vmx->rmode.irq.vector;
+ __vmx_complete_interrupts(vmx, vmx->idt_vectoring_info,
+ VM_EXIT_INSTRUCTION_LEN,
+ IDT_VECTORING_ERROR_CODE);
+}
+
+static void vmx_cancel_injection(struct kvm_vcpu *vcpu)
+{
+ __vmx_complete_interrupts(to_vmx(vcpu),
+ vmcs_read32(VM_ENTRY_INTR_INFO_FIELD),
+ VM_ENTRY_INSTRUCTION_LEN,
+ VM_ENTRY_EXCEPTION_ERROR_CODE);
+
+ vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0);
}
#ifdef CONFIG_X86_64
@@ -4032,7 +4007,7 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
#endif
[cr2]"i"(offsetof(struct vcpu_vmx, vcpu.arch.cr2))
: "cc", "memory"
- , R"bx", R"di", R"si"
+ , R"ax", R"bx", R"di", R"si"
#ifdef CONFIG_X86_64
, "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
#endif
@@ -4043,12 +4018,15 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
vcpu->arch.regs_dirty = 0;
vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
- if (vmx->rmode.irq.pending)
- fixup_rmode_irq(vmx);
asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
vmx->launched = 1;
+ vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);
+ vmx->exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
+
+ vmx_complete_atomic_exit(vmx);
+ vmx_recover_nmi_blocking(vmx);
vmx_complete_interrupts(vmx);
}
@@ -4119,6 +4097,7 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
cpu = get_cpu();
vmx_vcpu_load(&vmx->vcpu, cpu);
+ vmx->vcpu.cpu = cpu;
err = vmx_vcpu_setup(vmx);
vmx_vcpu_put(&vmx->vcpu);
put_cpu();
@@ -4334,6 +4313,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
.set_irq = vmx_inject_irq,
.set_nmi = vmx_inject_nmi,
.queue_exception = vmx_queue_exception,
+ .cancel_injection = vmx_cancel_injection,
.interrupt_allowed = vmx_interrupt_allowed,
.nmi_allowed = vmx_nmi_allowed,
.get_nmi_mask = vmx_get_nmi_mask,
@@ -4356,6 +4336,11 @@ static struct kvm_x86_ops vmx_x86_ops = {
.set_supported_cpuid = vmx_set_supported_cpuid,
.has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
+
+ .write_tsc_offset = vmx_write_tsc_offset,
+ .adjust_tsc_offset = vmx_adjust_tsc_offset,
+
+ .set_tdp_cr3 = vmx_set_cr3,
};
static int __init vmx_init(void)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 6c2ecf0a806d..2288ad829b32 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -6,7 +6,7 @@
* Copyright (C) 2006 Qumranet, Inc.
* Copyright (C) 2008 Qumranet, Inc.
* Copyright IBM Corporation, 2008
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
*
* Authors:
* Avi Kivity <avi@qumranet.com>
@@ -55,6 +55,8 @@
#include <asm/mce.h>
#include <asm/i387.h>
#include <asm/xcr.h>
+#include <asm/pvclock.h>
+#include <asm/div64.h>
#define MAX_IO_MSRS 256
#define CR0_RESERVED_BITS \
@@ -71,7 +73,7 @@
#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
#define KVM_MAX_MCE_BANKS 32
-#define KVM_MCE_CAP_SUPPORTED MCG_CTL_P
+#define KVM_MCE_CAP_SUPPORTED (MCG_CTL_P | MCG_SER_P)
/* EFER defaults:
* - enable syscall per default because its emulated by KVM
@@ -282,6 +284,8 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
u32 prev_nr;
int class1, class2;
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
+
if (!vcpu->arch.exception.pending) {
queue:
vcpu->arch.exception.pending = true;
@@ -327,16 +331,28 @@ void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned nr)
}
EXPORT_SYMBOL_GPL(kvm_requeue_exception);
-void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr,
- u32 error_code)
+void kvm_inject_page_fault(struct kvm_vcpu *vcpu)
{
+ unsigned error_code = vcpu->arch.fault.error_code;
+
++vcpu->stat.pf_guest;
- vcpu->arch.cr2 = addr;
+ vcpu->arch.cr2 = vcpu->arch.fault.address;
kvm_queue_exception_e(vcpu, PF_VECTOR, error_code);
}
+void kvm_propagate_fault(struct kvm_vcpu *vcpu)
+{
+ if (mmu_is_nested(vcpu) && !vcpu->arch.fault.nested)
+ vcpu->arch.nested_mmu.inject_page_fault(vcpu);
+ else
+ vcpu->arch.mmu.inject_page_fault(vcpu);
+
+ vcpu->arch.fault.nested = false;
+}
+
void kvm_inject_nmi(struct kvm_vcpu *vcpu)
{
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
vcpu->arch.nmi_pending = 1;
}
EXPORT_SYMBOL_GPL(kvm_inject_nmi);
@@ -367,18 +383,49 @@ bool kvm_require_cpl(struct kvm_vcpu *vcpu, int required_cpl)
EXPORT_SYMBOL_GPL(kvm_require_cpl);
/*
+ * This function will be used to read from the physical memory of the currently
+ * running guest. The difference to kvm_read_guest_page is that this function
+ * can read from guest physical or from the guest's guest physical memory.
+ */
+int kvm_read_guest_page_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
+ gfn_t ngfn, void *data, int offset, int len,
+ u32 access)
+{
+ gfn_t real_gfn;
+ gpa_t ngpa;
+
+ ngpa = gfn_to_gpa(ngfn);
+ real_gfn = mmu->translate_gpa(vcpu, ngpa, access);
+ if (real_gfn == UNMAPPED_GVA)
+ return -EFAULT;
+
+ real_gfn = gpa_to_gfn(real_gfn);
+
+ return kvm_read_guest_page(vcpu->kvm, real_gfn, data, offset, len);
+}
+EXPORT_SYMBOL_GPL(kvm_read_guest_page_mmu);
+
+int kvm_read_nested_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn,
+ void *data, int offset, int len, u32 access)
+{
+ return kvm_read_guest_page_mmu(vcpu, vcpu->arch.walk_mmu, gfn,
+ data, offset, len, access);
+}
+
+/*
* Load the pae pdptrs. Return true is they are all valid.
*/
-int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
+int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3)
{
gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT;
unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2;
int i;
int ret;
- u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)];
+ u64 pdpte[ARRAY_SIZE(mmu->pdptrs)];
- ret = kvm_read_guest_page(vcpu->kvm, pdpt_gfn, pdpte,
- offset * sizeof(u64), sizeof(pdpte));
+ ret = kvm_read_guest_page_mmu(vcpu, mmu, pdpt_gfn, pdpte,
+ offset * sizeof(u64), sizeof(pdpte),
+ PFERR_USER_MASK|PFERR_WRITE_MASK);
if (ret < 0) {
ret = 0;
goto out;
@@ -392,7 +439,7 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
}
ret = 1;
- memcpy(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs));
+ memcpy(mmu->pdptrs, pdpte, sizeof(mmu->pdptrs));
__set_bit(VCPU_EXREG_PDPTR,
(unsigned long *)&vcpu->arch.regs_avail);
__set_bit(VCPU_EXREG_PDPTR,
@@ -405,8 +452,10 @@ EXPORT_SYMBOL_GPL(load_pdptrs);
static bool pdptrs_changed(struct kvm_vcpu *vcpu)
{
- u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)];
+ u64 pdpte[ARRAY_SIZE(vcpu->arch.walk_mmu->pdptrs)];
bool changed = true;
+ int offset;
+ gfn_t gfn;
int r;
if (is_long_mode(vcpu) || !is_pae(vcpu))
@@ -416,10 +465,13 @@ static bool pdptrs_changed(struct kvm_vcpu *vcpu)
(unsigned long *)&vcpu->arch.regs_avail))
return true;
- r = kvm_read_guest(vcpu->kvm, vcpu->arch.cr3 & ~31u, pdpte, sizeof(pdpte));
+ gfn = (vcpu->arch.cr3 & ~31u) >> PAGE_SHIFT;
+ offset = (vcpu->arch.cr3 & ~31u) & (PAGE_SIZE - 1);
+ r = kvm_read_nested_guest_page(vcpu, gfn, pdpte, offset, sizeof(pdpte),
+ PFERR_USER_MASK | PFERR_WRITE_MASK);
if (r < 0)
goto out;
- changed = memcmp(pdpte, vcpu->arch.pdptrs, sizeof(pdpte)) != 0;
+ changed = memcmp(pdpte, vcpu->arch.walk_mmu->pdptrs, sizeof(pdpte)) != 0;
out:
return changed;
@@ -458,7 +510,8 @@ int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
return 1;
} else
#endif
- if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->arch.cr3))
+ if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->arch.walk_mmu,
+ vcpu->arch.cr3))
return 1;
}
@@ -547,7 +600,7 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
return 1;
} else if (is_paging(vcpu) && (cr4 & X86_CR4_PAE)
&& ((cr4 ^ old_cr4) & pdptr_bits)
- && !load_pdptrs(vcpu, vcpu->arch.cr3))
+ && !load_pdptrs(vcpu, vcpu->arch.walk_mmu, vcpu->arch.cr3))
return 1;
if (cr4 & X86_CR4_VMXE)
@@ -580,7 +633,8 @@ int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
if (is_pae(vcpu)) {
if (cr3 & CR3_PAE_RESERVED_BITS)
return 1;
- if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3))
+ if (is_paging(vcpu) &&
+ !load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3))
return 1;
}
/*
@@ -737,7 +791,7 @@ static u32 msrs_to_save[] = {
#ifdef CONFIG_X86_64
MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
#endif
- MSR_IA32_TSC, MSR_IA32_PERF_STATUS, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA
+ MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA
};
static unsigned num_msrs_to_save;
@@ -838,7 +892,7 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
/*
* The guest calculates current wall clock time by adding
- * system time (updated by kvm_write_guest_time below) to the
+ * system time (updated by kvm_guest_time_update below) to the
* wall clock specified here. guest system time equals host
* system time for us, thus we must fill in host boot time here.
*/
@@ -866,65 +920,229 @@ static uint32_t div_frac(uint32_t dividend, uint32_t divisor)
return quotient;
}
-static void kvm_set_time_scale(uint32_t tsc_khz, struct pvclock_vcpu_time_info *hv_clock)
+static void kvm_get_time_scale(uint32_t scaled_khz, uint32_t base_khz,
+ s8 *pshift, u32 *pmultiplier)
{
- uint64_t nsecs = 1000000000LL;
+ uint64_t scaled64;
int32_t shift = 0;
uint64_t tps64;
uint32_t tps32;
- tps64 = tsc_khz * 1000LL;
- while (tps64 > nsecs*2) {
+ tps64 = base_khz * 1000LL;
+ scaled64 = scaled_khz * 1000LL;
+ while (tps64 > scaled64*2 || tps64 & 0xffffffff00000000ULL) {
tps64 >>= 1;
shift--;
}
tps32 = (uint32_t)tps64;
- while (tps32 <= (uint32_t)nsecs) {
- tps32 <<= 1;
+ while (tps32 <= scaled64 || scaled64 & 0xffffffff00000000ULL) {
+ if (scaled64 & 0xffffffff00000000ULL || tps32 & 0x80000000)
+ scaled64 >>= 1;
+ else
+ tps32 <<= 1;
shift++;
}
- hv_clock->tsc_shift = shift;
- hv_clock->tsc_to_system_mul = div_frac(nsecs, tps32);
+ *pshift = shift;
+ *pmultiplier = div_frac(scaled64, tps32);
- pr_debug("%s: tsc_khz %u, tsc_shift %d, tsc_mul %u\n",
- __func__, tsc_khz, hv_clock->tsc_shift,
- hv_clock->tsc_to_system_mul);
+ pr_debug("%s: base_khz %u => %u, shift %d, mul %u\n",
+ __func__, base_khz, scaled_khz, shift, *pmultiplier);
+}
+
+static inline u64 get_kernel_ns(void)
+{
+ struct timespec ts;
+
+ WARN_ON(preemptible());
+ ktime_get_ts(&ts);
+ monotonic_to_bootbased(&ts);
+ return timespec_to_ns(&ts);
}
static DEFINE_PER_CPU(unsigned long, cpu_tsc_khz);
+unsigned long max_tsc_khz;
-static void kvm_write_guest_time(struct kvm_vcpu *v)
+static inline int kvm_tsc_changes_freq(void)
+{
+ int cpu = get_cpu();
+ int ret = !boot_cpu_has(X86_FEATURE_CONSTANT_TSC) &&
+ cpufreq_quick_get(cpu) != 0;
+ put_cpu();
+ return ret;
+}
+
+static inline u64 nsec_to_cycles(u64 nsec)
+{
+ u64 ret;
+
+ WARN_ON(preemptible());
+ if (kvm_tsc_changes_freq())
+ printk_once(KERN_WARNING
+ "kvm: unreliable cycle conversion on adjustable rate TSC\n");
+ ret = nsec * __get_cpu_var(cpu_tsc_khz);
+ do_div(ret, USEC_PER_SEC);
+ return ret;
+}
+
+static void kvm_arch_set_tsc_khz(struct kvm *kvm, u32 this_tsc_khz)
+{
+ /* Compute a scale to convert nanoseconds in TSC cycles */
+ kvm_get_time_scale(this_tsc_khz, NSEC_PER_SEC / 1000,
+ &kvm->arch.virtual_tsc_shift,
+ &kvm->arch.virtual_tsc_mult);
+ kvm->arch.virtual_tsc_khz = this_tsc_khz;
+}
+
+static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
+{
+ u64 tsc = pvclock_scale_delta(kernel_ns-vcpu->arch.last_tsc_nsec,
+ vcpu->kvm->arch.virtual_tsc_mult,
+ vcpu->kvm->arch.virtual_tsc_shift);
+ tsc += vcpu->arch.last_tsc_write;
+ return tsc;
+}
+
+void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data)
+{
+ struct kvm *kvm = vcpu->kvm;
+ u64 offset, ns, elapsed;
+ unsigned long flags;
+ s64 sdiff;
+
+ spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
+ offset = data - native_read_tsc();
+ ns = get_kernel_ns();
+ elapsed = ns - kvm->arch.last_tsc_nsec;
+ sdiff = data - kvm->arch.last_tsc_write;
+ if (sdiff < 0)
+ sdiff = -sdiff;
+
+ /*
+ * Special case: close write to TSC within 5 seconds of
+ * another CPU is interpreted as an attempt to synchronize
+ * The 5 seconds is to accomodate host load / swapping as
+ * well as any reset of TSC during the boot process.
+ *
+ * In that case, for a reliable TSC, we can match TSC offsets,
+ * or make a best guest using elapsed value.
+ */
+ if (sdiff < nsec_to_cycles(5ULL * NSEC_PER_SEC) &&
+ elapsed < 5ULL * NSEC_PER_SEC) {
+ if (!check_tsc_unstable()) {
+ offset = kvm->arch.last_tsc_offset;
+ pr_debug("kvm: matched tsc offset for %llu\n", data);
+ } else {
+ u64 delta = nsec_to_cycles(elapsed);
+ offset += delta;
+ pr_debug("kvm: adjusted tsc offset by %llu\n", delta);
+ }
+ ns = kvm->arch.last_tsc_nsec;
+ }
+ kvm->arch.last_tsc_nsec = ns;
+ kvm->arch.last_tsc_write = data;
+ kvm->arch.last_tsc_offset = offset;
+ kvm_x86_ops->write_tsc_offset(vcpu, offset);
+ spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
+
+ /* Reset of TSC must disable overshoot protection below */
+ vcpu->arch.hv_clock.tsc_timestamp = 0;
+ vcpu->arch.last_tsc_write = data;
+ vcpu->arch.last_tsc_nsec = ns;
+}
+EXPORT_SYMBOL_GPL(kvm_write_tsc);
+
+static int kvm_guest_time_update(struct kvm_vcpu *v)
{
- struct timespec ts;
unsigned long flags;
struct kvm_vcpu_arch *vcpu = &v->arch;
void *shared_kaddr;
unsigned long this_tsc_khz;
+ s64 kernel_ns, max_kernel_ns;
+ u64 tsc_timestamp;
- if ((!vcpu->time_page))
- return;
+ /* Keep irq disabled to prevent changes to the clock */
+ local_irq_save(flags);
+ kvm_get_msr(v, MSR_IA32_TSC, &tsc_timestamp);
+ kernel_ns = get_kernel_ns();
+ this_tsc_khz = __get_cpu_var(cpu_tsc_khz);
- this_tsc_khz = get_cpu_var(cpu_tsc_khz);
- if (unlikely(vcpu->hv_clock_tsc_khz != this_tsc_khz)) {
- kvm_set_time_scale(this_tsc_khz, &vcpu->hv_clock);
- vcpu->hv_clock_tsc_khz = this_tsc_khz;
+ if (unlikely(this_tsc_khz == 0)) {
+ local_irq_restore(flags);
+ kvm_make_request(KVM_REQ_CLOCK_UPDATE, v);
+ return 1;
+ }
+
+ /*
+ * We may have to catch up the TSC to match elapsed wall clock
+ * time for two reasons, even if kvmclock is used.
+ * 1) CPU could have been running below the maximum TSC rate
+ * 2) Broken TSC compensation resets the base at each VCPU
+ * entry to avoid unknown leaps of TSC even when running
+ * again on the same CPU. This may cause apparent elapsed
+ * time to disappear, and the guest to stand still or run
+ * very slowly.
+ */
+ if (vcpu->tsc_catchup) {
+ u64 tsc = compute_guest_tsc(v, kernel_ns);
+ if (tsc > tsc_timestamp) {
+ kvm_x86_ops->adjust_tsc_offset(v, tsc - tsc_timestamp);
+ tsc_timestamp = tsc;
+ }
}
- put_cpu_var(cpu_tsc_khz);
- /* Keep irq disabled to prevent changes to the clock */
- local_irq_save(flags);
- kvm_get_msr(v, MSR_IA32_TSC, &vcpu->hv_clock.tsc_timestamp);
- ktime_get_ts(&ts);
- monotonic_to_bootbased(&ts);
local_irq_restore(flags);
- /* With all the info we got, fill in the values */
+ if (!vcpu->time_page)
+ return 0;
- vcpu->hv_clock.system_time = ts.tv_nsec +
- (NSEC_PER_SEC * (u64)ts.tv_sec) + v->kvm->arch.kvmclock_offset;
+ /*
+ * Time as measured by the TSC may go backwards when resetting the base
+ * tsc_timestamp. The reason for this is that the TSC resolution is
+ * higher than the resolution of the other clock scales. Thus, many
+ * possible measurments of the TSC correspond to one measurement of any
+ * other clock, and so a spread of values is possible. This is not a
+ * problem for the computation of the nanosecond clock; with TSC rates
+ * around 1GHZ, there can only be a few cycles which correspond to one
+ * nanosecond value, and any path through this code will inevitably
+ * take longer than that. However, with the kernel_ns value itself,
+ * the precision may be much lower, down to HZ granularity. If the
+ * first sampling of TSC against kernel_ns ends in the low part of the
+ * range, and the second in the high end of the range, we can get:
+ *
+ * (TSC - offset_low) * S + kns_old > (TSC - offset_high) * S + kns_new
+ *
+ * As the sampling errors potentially range in the thousands of cycles,
+ * it is possible such a time value has already been observed by the
+ * guest. To protect against this, we must compute the system time as
+ * observed by the guest and ensure the new system time is greater.
+ */
+ max_kernel_ns = 0;
+ if (vcpu->hv_clock.tsc_timestamp && vcpu->last_guest_tsc) {
+ max_kernel_ns = vcpu->last_guest_tsc -
+ vcpu->hv_clock.tsc_timestamp;
+ max_kernel_ns = pvclock_scale_delta(max_kernel_ns,
+ vcpu->hv_clock.tsc_to_system_mul,
+ vcpu->hv_clock.tsc_shift);
+ max_kernel_ns += vcpu->last_kernel_ns;
+ }
+ if (unlikely(vcpu->hw_tsc_khz != this_tsc_khz)) {
+ kvm_get_time_scale(NSEC_PER_SEC / 1000, this_tsc_khz,
+ &vcpu->hv_clock.tsc_shift,
+ &vcpu->hv_clock.tsc_to_system_mul);
+ vcpu->hw_tsc_khz = this_tsc_khz;
+ }
+
+ if (max_kernel_ns > kernel_ns)
+ kernel_ns = max_kernel_ns;
+
+ /* With all the info we got, fill in the values */
+ vcpu->hv_clock.tsc_timestamp = tsc_timestamp;
+ vcpu->hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset;
+ vcpu->last_kernel_ns = kernel_ns;
+ vcpu->last_guest_tsc = tsc_timestamp;
vcpu->hv_clock.flags = 0;
/*
@@ -942,16 +1160,7 @@ static void kvm_write_guest_time(struct kvm_vcpu *v)
kunmap_atomic(shared_kaddr, KM_USER0);
mark_page_dirty(v->kvm, vcpu->time >> PAGE_SHIFT);
-}
-
-static int kvm_request_guest_time_update(struct kvm_vcpu *v)
-{
- struct kvm_vcpu_arch *vcpu = &v->arch;
-
- if (!vcpu->time_page)
- return 0;
- kvm_make_request(KVM_REQ_KVMCLOCK_UPDATE, v);
- return 1;
+ return 0;
}
static bool msr_mtrr_valid(unsigned msr)
@@ -1277,6 +1486,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
}
vcpu->arch.time = data;
+ kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
/* we verify if the enable bit is set... */
if (!(data & 1))
@@ -1292,8 +1502,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
kvm_release_page_clean(vcpu->arch.time_page);
vcpu->arch.time_page = NULL;
}
-
- kvm_request_guest_time_update(vcpu);
break;
}
case MSR_IA32_MCG_CTL:
@@ -1330,6 +1538,16 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
pr_unimpl(vcpu, "unimplemented perfctr wrmsr: "
"0x%x data 0x%llx\n", msr, data);
break;
+ case MSR_K7_CLK_CTL:
+ /*
+ * Ignore all writes to this no longer documented MSR.
+ * Writes are only relevant for old K7 processors,
+ * all pre-dating SVM, but a recommended workaround from
+ * AMD for these chips. It is possible to speicify the
+ * affected processor models on the command line, hence
+ * the need to ignore the workaround.
+ */
+ break;
case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
if (kvm_hv_msr_partition_wide(msr)) {
int r;
@@ -1522,6 +1740,20 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
case 0xcd: /* fsb frequency */
data = 3;
break;
+ /*
+ * MSR_EBC_FREQUENCY_ID
+ * Conservative value valid for even the basic CPU models.
+ * Models 0,1: 000 in bits 23:21 indicating a bus speed of
+ * 100MHz, model 2 000 in bits 18:16 indicating 100MHz,
+ * and 266MHz for model 3, or 4. Set Core Clock
+ * Frequency to System Bus Frequency Ratio to 1 (bits
+ * 31:24) even though these are only valid for CPU
+ * models > 2, however guests may end up dividing or
+ * multiplying by zero otherwise.
+ */
+ case MSR_EBC_FREQUENCY_ID:
+ data = 1 << 24;
+ break;
case MSR_IA32_APICBASE:
data = kvm_get_apic_base(vcpu);
break;
@@ -1555,6 +1787,18 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
case MSR_IA32_MCG_STATUS:
case MSR_IA32_MC0_CTL ... MSR_IA32_MC0_CTL + 4 * KVM_MAX_MCE_BANKS - 1:
return get_msr_mce(vcpu, msr, pdata);
+ case MSR_K7_CLK_CTL:
+ /*
+ * Provide expected ramp-up count for K7. All other
+ * are set to zero, indicating minimum divisors for
+ * every field.
+ *
+ * This prevents guest kernels on AMD host with CPU
+ * type 6, model 8 and higher from exploding due to
+ * the rdmsr failing.
+ */
+ data = 0x20000000;
+ break;
case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
if (kvm_hv_msr_partition_wide(msr)) {
int r;
@@ -1808,19 +2052,28 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
}
kvm_x86_ops->vcpu_load(vcpu, cpu);
- if (unlikely(per_cpu(cpu_tsc_khz, cpu) == 0)) {
- unsigned long khz = cpufreq_quick_get(cpu);
- if (!khz)
- khz = tsc_khz;
- per_cpu(cpu_tsc_khz, cpu) = khz;
+ if (unlikely(vcpu->cpu != cpu) || check_tsc_unstable()) {
+ /* Make sure TSC doesn't go backwards */
+ s64 tsc_delta = !vcpu->arch.last_host_tsc ? 0 :
+ native_read_tsc() - vcpu->arch.last_host_tsc;
+ if (tsc_delta < 0)
+ mark_tsc_unstable("KVM discovered backwards TSC");
+ if (check_tsc_unstable()) {
+ kvm_x86_ops->adjust_tsc_offset(vcpu, -tsc_delta);
+ vcpu->arch.tsc_catchup = 1;
+ kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
+ }
+ if (vcpu->cpu != cpu)
+ kvm_migrate_timers(vcpu);
+ vcpu->cpu = cpu;
}
- kvm_request_guest_time_update(vcpu);
}
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
{
kvm_x86_ops->vcpu_put(vcpu);
kvm_put_guest_fpu(vcpu);
+ vcpu->arch.last_host_tsc = native_read_tsc();
}
static int is_efer_nx(void)
@@ -1995,7 +2248,7 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
F(F16C);
/* cpuid 0x80000001.ecx */
const u32 kvm_supported_word6_x86_features =
- F(LAHF_LM) | F(CMP_LEGACY) | F(SVM) | 0 /* ExtApicSpace */ |
+ F(LAHF_LM) | F(CMP_LEGACY) | 0 /*SVM*/ | 0 /* ExtApicSpace */ |
F(CR8_LEGACY) | F(ABM) | F(SSE4A) | F(MISALIGNSSE) |
F(3DNOWPREFETCH) | 0 /* OSVW */ | 0 /* IBS */ | F(XOP) |
0 /* SKINIT, WDT, LWP */ | F(FMA4) | F(TBM);
@@ -2204,6 +2457,7 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
return -ENXIO;
kvm_queue_interrupt(vcpu, irq->irq, false);
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
return 0;
}
@@ -2357,6 +2611,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
if (events->flags & KVM_VCPUEVENT_VALID_SIPI_VECTOR)
vcpu->arch.sipi_vector = events->sipi_vector;
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
+
return 0;
}
@@ -2760,7 +3016,7 @@ static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm,
static int kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm)
{
- return kvm->arch.n_alloc_mmu_pages;
+ return kvm->arch.n_max_mmu_pages;
}
static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
@@ -2796,18 +3052,18 @@ static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
r = 0;
switch (chip->chip_id) {
case KVM_IRQCHIP_PIC_MASTER:
- raw_spin_lock(&pic_irqchip(kvm)->lock);
+ spin_lock(&pic_irqchip(kvm)->lock);
memcpy(&pic_irqchip(kvm)->pics[0],
&chip->chip.pic,
sizeof(struct kvm_pic_state));
- raw_spin_unlock(&pic_irqchip(kvm)->lock);
+ spin_unlock(&pic_irqchip(kvm)->lock);
break;
case KVM_IRQCHIP_PIC_SLAVE:
- raw_spin_lock(&pic_irqchip(kvm)->lock);
+ spin_lock(&pic_irqchip(kvm)->lock);
memcpy(&pic_irqchip(kvm)->pics[1],
&chip->chip.pic,
sizeof(struct kvm_pic_state));
- raw_spin_unlock(&pic_irqchip(kvm)->lock);
+ spin_unlock(&pic_irqchip(kvm)->lock);
break;
case KVM_IRQCHIP_IOAPIC:
r = kvm_set_ioapic(kvm, &chip->chip.ioapic);
@@ -3201,7 +3457,6 @@ long kvm_arch_vm_ioctl(struct file *filp,
break;
}
case KVM_SET_CLOCK: {
- struct timespec now;
struct kvm_clock_data user_ns;
u64 now_ns;
s64 delta;
@@ -3215,20 +3470,21 @@ long kvm_arch_vm_ioctl(struct file *filp,
goto out;
r = 0;
- ktime_get_ts(&now);
- now_ns = timespec_to_ns(&now);
+ local_irq_disable();
+ now_ns = get_kernel_ns();
delta = user_ns.clock - now_ns;
+ local_irq_enable();
kvm->arch.kvmclock_offset = delta;
break;
}
case KVM_GET_CLOCK: {
- struct timespec now;
struct kvm_clock_data user_ns;
u64 now_ns;
- ktime_get_ts(&now);
- now_ns = timespec_to_ns(&now);
+ local_irq_disable();
+ now_ns = get_kernel_ns();
user_ns.clock = kvm->arch.kvmclock_offset + now_ns;
+ local_irq_enable();
user_ns.flags = 0;
r = -EFAULT;
@@ -3292,30 +3548,51 @@ void kvm_get_segment(struct kvm_vcpu *vcpu,
kvm_x86_ops->get_segment(vcpu, var, seg);
}
+static gpa_t translate_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access)
+{
+ return gpa;
+}
+
+static gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access)
+{
+ gpa_t t_gpa;
+ u32 error;
+
+ BUG_ON(!mmu_is_nested(vcpu));
+
+ /* NPT walks are always user-walks */
+ access |= PFERR_USER_MASK;
+ t_gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, gpa, access, &error);
+ if (t_gpa == UNMAPPED_GVA)
+ vcpu->arch.fault.nested = true;
+
+ return t_gpa;
+}
+
gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
{
u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
- return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error);
+ return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, error);
}
gpa_t kvm_mmu_gva_to_gpa_fetch(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
{
u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
access |= PFERR_FETCH_MASK;
- return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error);
+ return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, error);
}
gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
{
u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
access |= PFERR_WRITE_MASK;
- return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error);
+ return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, error);
}
/* uses this to access any guest's mapped memory without checking CPL */
gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
{
- return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, 0, error);
+ return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, 0, error);
}
static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes,
@@ -3326,7 +3603,8 @@ static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes,
int r = X86EMUL_CONTINUE;
while (bytes) {
- gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr, access, error);
+ gpa_t gpa = vcpu->arch.walk_mmu->gva_to_gpa(vcpu, addr, access,
+ error);
unsigned offset = addr & (PAGE_SIZE-1);
unsigned toread = min(bytes, (unsigned)PAGE_SIZE - offset);
int ret;
@@ -3381,8 +3659,9 @@ static int kvm_write_guest_virt_system(gva_t addr, void *val,
int r = X86EMUL_CONTINUE;
while (bytes) {
- gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr,
- PFERR_WRITE_MASK, error);
+ gpa_t gpa = vcpu->arch.walk_mmu->gva_to_gpa(vcpu, addr,
+ PFERR_WRITE_MASK,
+ error);
unsigned offset = addr & (PAGE_SIZE-1);
unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset);
int ret;
@@ -3624,7 +3903,7 @@ static int emulator_pio_in_emulated(int size, unsigned short port, void *val,
if (vcpu->arch.pio.count)
goto data_avail;
- trace_kvm_pio(1, port, size, 1);
+ trace_kvm_pio(0, port, size, 1);
vcpu->arch.pio.port = port;
vcpu->arch.pio.in = 1;
@@ -3652,7 +3931,7 @@ static int emulator_pio_out_emulated(int size, unsigned short port,
const void *val, unsigned int count,
struct kvm_vcpu *vcpu)
{
- trace_kvm_pio(0, port, size, 1);
+ trace_kvm_pio(1, port, size, 1);
vcpu->arch.pio.port = port;
vcpu->arch.pio.in = 0;
@@ -3791,6 +4070,11 @@ static void emulator_get_gdt(struct desc_ptr *dt, struct kvm_vcpu *vcpu)
kvm_x86_ops->get_gdt(vcpu, dt);
}
+static void emulator_get_idt(struct desc_ptr *dt, struct kvm_vcpu *vcpu)
+{
+ kvm_x86_ops->get_idt(vcpu, dt);
+}
+
static unsigned long emulator_get_cached_segment_base(int seg,
struct kvm_vcpu *vcpu)
{
@@ -3884,6 +4168,7 @@ static struct x86_emulate_ops emulate_ops = {
.set_segment_selector = emulator_set_segment_selector,
.get_cached_segment_base = emulator_get_cached_segment_base,
.get_gdt = emulator_get_gdt,
+ .get_idt = emulator_get_idt,
.get_cr = emulator_get_cr,
.set_cr = emulator_set_cr,
.cpl = emulator_get_cpl,
@@ -3919,13 +4204,64 @@ static void inject_emulated_exception(struct kvm_vcpu *vcpu)
{
struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
if (ctxt->exception == PF_VECTOR)
- kvm_inject_page_fault(vcpu, ctxt->cr2, ctxt->error_code);
+ kvm_propagate_fault(vcpu);
else if (ctxt->error_code_valid)
kvm_queue_exception_e(vcpu, ctxt->exception, ctxt->error_code);
else
kvm_queue_exception(vcpu, ctxt->exception);
}
+static void init_emulate_ctxt(struct kvm_vcpu *vcpu)
+{
+ struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode;
+ int cs_db, cs_l;
+
+ cache_all_regs(vcpu);
+
+ kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
+
+ vcpu->arch.emulate_ctxt.vcpu = vcpu;
+ vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
+ vcpu->arch.emulate_ctxt.eip = kvm_rip_read(vcpu);
+ vcpu->arch.emulate_ctxt.mode =
+ (!is_protmode(vcpu)) ? X86EMUL_MODE_REAL :
+ (vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
+ ? X86EMUL_MODE_VM86 : cs_l
+ ? X86EMUL_MODE_PROT64 : cs_db
+ ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
+ memset(c, 0, sizeof(struct decode_cache));
+ memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
+}
+
+int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq)
+{
+ struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode;
+ int ret;
+
+ init_emulate_ctxt(vcpu);
+
+ vcpu->arch.emulate_ctxt.decode.op_bytes = 2;
+ vcpu->arch.emulate_ctxt.decode.ad_bytes = 2;
+ vcpu->arch.emulate_ctxt.decode.eip = vcpu->arch.emulate_ctxt.eip;
+ ret = emulate_int_real(&vcpu->arch.emulate_ctxt, &emulate_ops, irq);
+
+ if (ret != X86EMUL_CONTINUE)
+ return EMULATE_FAIL;
+
+ vcpu->arch.emulate_ctxt.eip = c->eip;
+ memcpy(vcpu->arch.regs, c->regs, sizeof c->regs);
+ kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip);
+ kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
+
+ if (irq == NMI_VECTOR)
+ vcpu->arch.nmi_pending = false;
+ else
+ vcpu->arch.interrupt.pending = false;
+
+ return EMULATE_DONE;
+}
+EXPORT_SYMBOL_GPL(kvm_inject_realmode_interrupt);
+
static int handle_emulation_failure(struct kvm_vcpu *vcpu)
{
++vcpu->stat.insn_emulation_fail;
@@ -3982,24 +4318,15 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
cache_all_regs(vcpu);
if (!(emulation_type & EMULTYPE_NO_DECODE)) {
- int cs_db, cs_l;
- kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
-
- vcpu->arch.emulate_ctxt.vcpu = vcpu;
- vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
- vcpu->arch.emulate_ctxt.eip = kvm_rip_read(vcpu);
- vcpu->arch.emulate_ctxt.mode =
- (!is_protmode(vcpu)) ? X86EMUL_MODE_REAL :
- (vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
- ? X86EMUL_MODE_VM86 : cs_l
- ? X86EMUL_MODE_PROT64 : cs_db
- ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
- memset(c, 0, sizeof(struct decode_cache));
- memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
+ init_emulate_ctxt(vcpu);
vcpu->arch.emulate_ctxt.interruptibility = 0;
vcpu->arch.emulate_ctxt.exception = -1;
+ vcpu->arch.emulate_ctxt.perm_ok = false;
+
+ r = x86_decode_insn(&vcpu->arch.emulate_ctxt);
+ if (r == X86EMUL_PROPAGATE_FAULT)
+ goto done;
- r = x86_decode_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
trace_kvm_emulate_insn_start(vcpu);
/* Only allow emulation of specific instructions on #UD
@@ -4049,41 +4376,39 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
restart:
- r = x86_emulate_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
+ r = x86_emulate_insn(&vcpu->arch.emulate_ctxt);
- if (r) { /* emulation failed */
+ if (r == EMULATION_FAILED) {
if (reexecute_instruction(vcpu, cr2))
return EMULATE_DONE;
return handle_emulation_failure(vcpu);
}
- toggle_interruptibility(vcpu, vcpu->arch.emulate_ctxt.interruptibility);
- kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
- memcpy(vcpu->arch.regs, c->regs, sizeof c->regs);
- kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip);
-
+done:
if (vcpu->arch.emulate_ctxt.exception >= 0) {
inject_emulated_exception(vcpu);
- return EMULATE_DONE;
- }
-
- if (vcpu->arch.pio.count) {
+ r = EMULATE_DONE;
+ } else if (vcpu->arch.pio.count) {
if (!vcpu->arch.pio.in)
vcpu->arch.pio.count = 0;
- return EMULATE_DO_MMIO;
- }
-
- if (vcpu->mmio_needed) {
+ r = EMULATE_DO_MMIO;
+ } else if (vcpu->mmio_needed) {
if (vcpu->mmio_is_write)
vcpu->mmio_needed = 0;
- return EMULATE_DO_MMIO;
- }
-
- if (vcpu->arch.emulate_ctxt.restart)
+ r = EMULATE_DO_MMIO;
+ } else if (r == EMULATION_RESTART)
goto restart;
+ else
+ r = EMULATE_DONE;
- return EMULATE_DONE;
+ toggle_interruptibility(vcpu, vcpu->arch.emulate_ctxt.interruptibility);
+ kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
+ memcpy(vcpu->arch.regs, c->regs, sizeof c->regs);
+ kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip);
+
+ return r;
}
EXPORT_SYMBOL_GPL(emulate_instruction);
@@ -4097,9 +4422,23 @@ int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port)
}
EXPORT_SYMBOL_GPL(kvm_fast_pio_out);
-static void bounce_off(void *info)
+static void tsc_bad(void *info)
+{
+ __get_cpu_var(cpu_tsc_khz) = 0;
+}
+
+static void tsc_khz_changed(void *data)
{
- /* nothing */
+ struct cpufreq_freqs *freq = data;
+ unsigned long khz = 0;
+
+ if (data)
+ khz = freq->new;
+ else if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
+ khz = cpufreq_quick_get(raw_smp_processor_id());
+ if (!khz)
+ khz = tsc_khz;
+ __get_cpu_var(cpu_tsc_khz) = khz;
}
static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
@@ -4110,21 +4449,60 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long va
struct kvm_vcpu *vcpu;
int i, send_ipi = 0;
+ /*
+ * We allow guests to temporarily run on slowing clocks,
+ * provided we notify them after, or to run on accelerating
+ * clocks, provided we notify them before. Thus time never
+ * goes backwards.
+ *
+ * However, we have a problem. We can't atomically update
+ * the frequency of a given CPU from this function; it is
+ * merely a notifier, which can be called from any CPU.
+ * Changing the TSC frequency at arbitrary points in time
+ * requires a recomputation of local variables related to
+ * the TSC for each VCPU. We must flag these local variables
+ * to be updated and be sure the update takes place with the
+ * new frequency before any guests proceed.
+ *
+ * Unfortunately, the combination of hotplug CPU and frequency
+ * change creates an intractable locking scenario; the order
+ * of when these callouts happen is undefined with respect to
+ * CPU hotplug, and they can race with each other. As such,
+ * merely setting per_cpu(cpu_tsc_khz) = X during a hotadd is
+ * undefined; you can actually have a CPU frequency change take
+ * place in between the computation of X and the setting of the
+ * variable. To protect against this problem, all updates of
+ * the per_cpu tsc_khz variable are done in an interrupt
+ * protected IPI, and all callers wishing to update the value
+ * must wait for a synchronous IPI to complete (which is trivial
+ * if the caller is on the CPU already). This establishes the
+ * necessary total order on variable updates.
+ *
+ * Note that because a guest time update may take place
+ * anytime after the setting of the VCPU's request bit, the
+ * correct TSC value must be set before the request. However,
+ * to ensure the update actually makes it to any guest which
+ * starts running in hardware virtualization between the set
+ * and the acquisition of the spinlock, we must also ping the
+ * CPU after setting the request bit.
+ *
+ */
+
if (val == CPUFREQ_PRECHANGE && freq->old > freq->new)
return 0;
if (val == CPUFREQ_POSTCHANGE && freq->old < freq->new)
return 0;
- per_cpu(cpu_tsc_khz, freq->cpu) = freq->new;
+
+ smp_call_function_single(freq->cpu, tsc_khz_changed, freq, 1);
spin_lock(&kvm_lock);
list_for_each_entry(kvm, &vm_list, vm_list) {
kvm_for_each_vcpu(i, vcpu, kvm) {
if (vcpu->cpu != freq->cpu)
continue;
- if (!kvm_request_guest_time_update(vcpu))
- continue;
+ kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
if (vcpu->cpu != smp_processor_id())
- send_ipi++;
+ send_ipi = 1;
}
}
spin_unlock(&kvm_lock);
@@ -4142,32 +4520,57 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long va
* guest context is entered kvmclock will be updated,
* so the guest will not see stale values.
*/
- smp_call_function_single(freq->cpu, bounce_off, NULL, 1);
+ smp_call_function_single(freq->cpu, tsc_khz_changed, freq, 1);
}
return 0;
}
static struct notifier_block kvmclock_cpufreq_notifier_block = {
- .notifier_call = kvmclock_cpufreq_notifier
+ .notifier_call = kvmclock_cpufreq_notifier
+};
+
+static int kvmclock_cpu_notifier(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_DOWN_FAILED:
+ smp_call_function_single(cpu, tsc_khz_changed, NULL, 1);
+ break;
+ case CPU_DOWN_PREPARE:
+ smp_call_function_single(cpu, tsc_bad, NULL, 1);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block kvmclock_cpu_notifier_block = {
+ .notifier_call = kvmclock_cpu_notifier,
+ .priority = -INT_MAX
};
static void kvm_timer_init(void)
{
int cpu;
+ max_tsc_khz = tsc_khz;
+ register_hotcpu_notifier(&kvmclock_cpu_notifier_block);
if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
+#ifdef CONFIG_CPU_FREQ
+ struct cpufreq_policy policy;
+ memset(&policy, 0, sizeof(policy));
+ cpufreq_get_policy(&policy, get_cpu());
+ if (policy.cpuinfo.max_freq)
+ max_tsc_khz = policy.cpuinfo.max_freq;
+#endif
cpufreq_register_notifier(&kvmclock_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
- for_each_online_cpu(cpu) {
- unsigned long khz = cpufreq_get(cpu);
- if (!khz)
- khz = tsc_khz;
- per_cpu(cpu_tsc_khz, cpu) = khz;
- }
- } else {
- for_each_possible_cpu(cpu)
- per_cpu(cpu_tsc_khz, cpu) = tsc_khz;
}
+ pr_debug("kvm: max_tsc_khz = %ld\n", max_tsc_khz);
+ for_each_online_cpu(cpu)
+ smp_call_function_single(cpu, tsc_khz_changed, NULL, 1);
}
static DEFINE_PER_CPU(struct kvm_vcpu *, current_vcpu);
@@ -4269,6 +4672,7 @@ void kvm_arch_exit(void)
if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
cpufreq_unregister_notifier(&kvmclock_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
+ unregister_hotcpu_notifier(&kvmclock_cpu_notifier_block);
kvm_x86_ops = NULL;
kvm_mmu_module_exit();
}
@@ -4684,8 +5088,11 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
kvm_mmu_unload(vcpu);
if (kvm_check_request(KVM_REQ_MIGRATE_TIMER, vcpu))
__kvm_migrate_timers(vcpu);
- if (kvm_check_request(KVM_REQ_KVMCLOCK_UPDATE, vcpu))
- kvm_write_guest_time(vcpu);
+ if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, vcpu)) {
+ r = kvm_guest_time_update(vcpu);
+ if (unlikely(r))
+ goto out;
+ }
if (kvm_check_request(KVM_REQ_MMU_SYNC, vcpu))
kvm_mmu_sync_roots(vcpu);
if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu))
@@ -4710,6 +5117,21 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
if (unlikely(r))
goto out;
+ if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) {
+ inject_pending_event(vcpu);
+
+ /* enable NMI/IRQ window open exits if needed */
+ if (vcpu->arch.nmi_pending)
+ kvm_x86_ops->enable_nmi_window(vcpu);
+ else if (kvm_cpu_has_interrupt(vcpu) || req_int_win)
+ kvm_x86_ops->enable_irq_window(vcpu);
+
+ if (kvm_lapic_enabled(vcpu)) {
+ update_cr8_intercept(vcpu);
+ kvm_lapic_sync_to_vapic(vcpu);
+ }
+ }
+
preempt_disable();
kvm_x86_ops->prepare_guest_switch(vcpu);
@@ -4728,23 +5150,11 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
smp_wmb();
local_irq_enable();
preempt_enable();
+ kvm_x86_ops->cancel_injection(vcpu);
r = 1;
goto out;
}
- inject_pending_event(vcpu);
-
- /* enable NMI/IRQ window open exits if needed */
- if (vcpu->arch.nmi_pending)
- kvm_x86_ops->enable_nmi_window(vcpu);
- else if (kvm_cpu_has_interrupt(vcpu) || req_int_win)
- kvm_x86_ops->enable_irq_window(vcpu);
-
- if (kvm_lapic_enabled(vcpu)) {
- update_cr8_intercept(vcpu);
- kvm_lapic_sync_to_vapic(vcpu);
- }
-
srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
kvm_guest_enter();
@@ -4770,6 +5180,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
if (hw_breakpoint_active())
hw_breakpoint_restore();
+ kvm_get_msr(vcpu, MSR_IA32_TSC, &vcpu->arch.last_guest_tsc);
+
atomic_set(&vcpu->guest_mode, 0);
smp_wmb();
local_irq_enable();
@@ -4899,8 +5311,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (!irqchip_in_kernel(vcpu->kvm))
kvm_set_cr8(vcpu, kvm_run->cr8);
- if (vcpu->arch.pio.count || vcpu->mmio_needed ||
- vcpu->arch.emulate_ctxt.restart) {
+ if (vcpu->arch.pio.count || vcpu->mmio_needed) {
if (vcpu->mmio_needed) {
memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
vcpu->mmio_read_completed = 1;
@@ -4981,6 +5392,8 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
vcpu->arch.exception.pending = false;
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
+
return 0;
}
@@ -5044,6 +5457,7 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
struct kvm_mp_state *mp_state)
{
vcpu->arch.mp_state = mp_state->mp_state;
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
return 0;
}
@@ -5051,24 +5465,11 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
bool has_error_code, u32 error_code)
{
struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode;
- int cs_db, cs_l, ret;
- cache_all_regs(vcpu);
-
- kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
+ int ret;
- vcpu->arch.emulate_ctxt.vcpu = vcpu;
- vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
- vcpu->arch.emulate_ctxt.eip = kvm_rip_read(vcpu);
- vcpu->arch.emulate_ctxt.mode =
- (!is_protmode(vcpu)) ? X86EMUL_MODE_REAL :
- (vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
- ? X86EMUL_MODE_VM86 : cs_l
- ? X86EMUL_MODE_PROT64 : cs_db
- ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
- memset(c, 0, sizeof(struct decode_cache));
- memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
+ init_emulate_ctxt(vcpu);
- ret = emulator_task_switch(&vcpu->arch.emulate_ctxt, &emulate_ops,
+ ret = emulator_task_switch(&vcpu->arch.emulate_ctxt,
tss_selector, reason, has_error_code,
error_code);
@@ -5078,6 +5479,7 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
memcpy(vcpu->arch.regs, c->regs, sizeof c->regs);
kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip);
kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
return EMULATE_DONE;
}
EXPORT_SYMBOL_GPL(kvm_task_switch);
@@ -5113,7 +5515,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4;
kvm_x86_ops->set_cr4(vcpu, sregs->cr4);
if (!is_long_mode(vcpu) && is_pae(vcpu)) {
- load_pdptrs(vcpu, vcpu->arch.cr3);
+ load_pdptrs(vcpu, vcpu->arch.walk_mmu, vcpu->arch.cr3);
mmu_reset_needed = 1;
}
@@ -5148,6 +5550,8 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
!is_protmode(vcpu))
vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
+
return 0;
}
@@ -5334,6 +5738,10 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
unsigned int id)
{
+ if (check_tsc_unstable() && atomic_read(&kvm->online_vcpus) != 0)
+ printk_once(KERN_WARNING
+ "kvm: SMP vm created on host with unstable TSC; "
+ "guest TSC will not be reliable\n");
return kvm_x86_ops->vcpu_create(kvm, id);
}
@@ -5376,22 +5784,22 @@ int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu)
vcpu->arch.dr6 = DR6_FIXED_1;
vcpu->arch.dr7 = DR7_FIXED_1;
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
+
return kvm_x86_ops->vcpu_reset(vcpu);
}
int kvm_arch_hardware_enable(void *garbage)
{
- /*
- * Since this may be called from a hotplug notifcation,
- * we can't get the CPU frequency directly.
- */
- if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
- int cpu = raw_smp_processor_id();
- per_cpu(cpu_tsc_khz, cpu) = 0;
- }
+ struct kvm *kvm;
+ struct kvm_vcpu *vcpu;
+ int i;
kvm_shared_msr_cpu_online();
-
+ list_for_each_entry(kvm, &vm_list, vm_list)
+ kvm_for_each_vcpu(i, vcpu, kvm)
+ if (vcpu->cpu == smp_processor_id())
+ kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
return kvm_x86_ops->hardware_enable(garbage);
}
@@ -5425,7 +5833,11 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
BUG_ON(vcpu->kvm == NULL);
kvm = vcpu->kvm;
+ vcpu->arch.emulate_ctxt.ops = &emulate_ops;
+ vcpu->arch.walk_mmu = &vcpu->arch.mmu;
vcpu->arch.mmu.root_hpa = INVALID_PAGE;
+ vcpu->arch.mmu.translate_gpa = translate_gpa;
+ vcpu->arch.nested_mmu.translate_gpa = translate_nested_gpa;
if (!irqchip_in_kernel(kvm) || kvm_vcpu_is_bsp(vcpu))
vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
else
@@ -5438,6 +5850,9 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
}
vcpu->arch.pio_data = page_address(page);
+ if (!kvm->arch.virtual_tsc_khz)
+ kvm_arch_set_tsc_khz(kvm, max_tsc_khz);
+
r = kvm_mmu_create(vcpu);
if (r < 0)
goto fail_free_pio_data;
@@ -5497,7 +5912,7 @@ struct kvm *kvm_arch_create_vm(void)
/* Reserve bit 0 of irq_sources_bitmap for userspace irq source */
set_bit(KVM_USERSPACE_IRQ_SOURCE_ID, &kvm->arch.irq_sources_bitmap);
- rdtscll(kvm->arch.vm_init_tsc);
+ spin_lock_init(&kvm->arch.tsc_write_lock);
return kvm;
}
@@ -5684,6 +6099,7 @@ void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
kvm_is_linear_rip(vcpu, vcpu->arch.singlestep_rip))
rflags |= X86_EFLAGS_TF;
kvm_x86_ops->set_rflags(vcpu, rflags);
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
}
EXPORT_SYMBOL_GPL(kvm_set_rflags);
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index b7a404722d2b..2cea414489f3 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -50,6 +50,11 @@ static inline int is_long_mode(struct kvm_vcpu *vcpu)
#endif
}
+static inline bool mmu_is_nested(struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.walk_mmu == &vcpu->arch.nested_mmu;
+}
+
static inline int is_pae(struct kvm_vcpu *vcpu)
{
return kvm_read_cr4_bits(vcpu, X86_CR4_PAE);
@@ -67,5 +72,8 @@ static inline int is_paging(struct kvm_vcpu *vcpu)
void kvm_before_handle_nmi(struct kvm_vcpu *vcpu);
void kvm_after_handle_nmi(struct kvm_vcpu *vcpu);
+int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq);
+
+void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data);
#endif
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 79b0b372d2d0..7d90ceb882a4 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -11,6 +11,7 @@
#include <linux/kprobes.h> /* __kprobes, ... */
#include <linux/mmiotrace.h> /* kmmio_handler, ... */
#include <linux/perf_event.h> /* perf_sw_event */
+#include <linux/hugetlb.h> /* hstate_index_to_shift */
#include <asm/traps.h> /* dotraplinkage, ... */
#include <asm/pgalloc.h> /* pgd_*(), ... */
@@ -160,15 +161,20 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr)
static void
force_sig_info_fault(int si_signo, int si_code, unsigned long address,
- struct task_struct *tsk)
+ struct task_struct *tsk, int fault)
{
+ unsigned lsb = 0;
siginfo_t info;
info.si_signo = si_signo;
info.si_errno = 0;
info.si_code = si_code;
info.si_addr = (void __user *)address;
- info.si_addr_lsb = si_code == BUS_MCEERR_AR ? PAGE_SHIFT : 0;
+ if (fault & VM_FAULT_HWPOISON_LARGE)
+ lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
+ if (fault & VM_FAULT_HWPOISON)
+ lsb = PAGE_SHIFT;
+ info.si_addr_lsb = lsb;
force_sig_info(si_signo, &info, tsk);
}
@@ -722,7 +728,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
tsk->thread.error_code = error_code | (address >= TASK_SIZE);
tsk->thread.trap_no = 14;
- force_sig_info_fault(SIGSEGV, si_code, address, tsk);
+ force_sig_info_fault(SIGSEGV, si_code, address, tsk, 0);
return;
}
@@ -807,14 +813,14 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
tsk->thread.trap_no = 14;
#ifdef CONFIG_MEMORY_FAILURE
- if (fault & VM_FAULT_HWPOISON) {
+ if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) {
printk(KERN_ERR
"MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n",
tsk->comm, tsk->pid, address);
code = BUS_MCEERR_AR;
}
#endif
- force_sig_info_fault(SIGBUS, code, address, tsk);
+ force_sig_info_fault(SIGBUS, code, address, tsk, fault);
}
static noinline void
@@ -824,7 +830,8 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
if (fault & VM_FAULT_OOM) {
out_of_memory(regs, error_code, address);
} else {
- if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON))
+ if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
+ VM_FAULT_HWPOISON_LARGE))
do_sigbus(regs, error_code, address, fault);
else
BUG();
@@ -912,9 +919,9 @@ spurious_fault(unsigned long error_code, unsigned long address)
int show_unhandled_signals = 1;
static inline int
-access_error(unsigned long error_code, int write, struct vm_area_struct *vma)
+access_error(unsigned long error_code, struct vm_area_struct *vma)
{
- if (write) {
+ if (error_code & PF_WRITE) {
/* write, present and write, not present: */
if (unlikely(!(vma->vm_flags & VM_WRITE)))
return 1;
@@ -949,8 +956,10 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
struct task_struct *tsk;
unsigned long address;
struct mm_struct *mm;
- int write;
int fault;
+ int write = error_code & PF_WRITE;
+ unsigned int flags = FAULT_FLAG_ALLOW_RETRY |
+ (write ? FAULT_FLAG_WRITE : 0);
tsk = current;
mm = tsk->mm;
@@ -1061,6 +1070,7 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
bad_area_nosemaphore(regs, error_code, address);
return;
}
+retry:
down_read(&mm->mmap_sem);
} else {
/*
@@ -1104,9 +1114,7 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
* we can handle it..
*/
good_area:
- write = error_code & PF_WRITE;
-
- if (unlikely(access_error(error_code, write, vma))) {
+ if (unlikely(access_error(error_code, vma))) {
bad_area_access_error(regs, error_code, address);
return;
}
@@ -1116,21 +1124,34 @@ good_area:
* make sure we exit gracefully rather than endlessly redo
* the fault:
*/
- fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);
+ fault = handle_mm_fault(mm, vma, address, flags);
if (unlikely(fault & VM_FAULT_ERROR)) {
mm_fault_error(regs, error_code, address, fault);
return;
}
- if (fault & VM_FAULT_MAJOR) {
- tsk->maj_flt++;
- perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
- regs, address);
- } else {
- tsk->min_flt++;
- perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
- regs, address);
+ /*
+ * Major/minor page fault accounting is only done on the
+ * initial attempt. If we go through a retry, it is extremely
+ * likely that the page will be found in page cache at that point.
+ */
+ if (flags & FAULT_FLAG_ALLOW_RETRY) {
+ if (fault & VM_FAULT_MAJOR) {
+ tsk->maj_flt++;
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
+ regs, address);
+ } else {
+ tsk->min_flt++;
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
+ regs, address);
+ }
+ if (fault & VM_FAULT_RETRY) {
+ /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
+ * of starvation. */
+ flags &= ~FAULT_FLAG_ALLOW_RETRY;
+ goto retry;
+ }
}
check_v8086_mode(regs, address, tsk);
diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c
index 5e8fa12ef861..b49962662101 100644
--- a/arch/x86/mm/highmem_32.c
+++ b/arch/x86/mm/highmem_32.c
@@ -9,6 +9,7 @@ void *kmap(struct page *page)
return page_address(page);
return kmap_high(page);
}
+EXPORT_SYMBOL(kmap);
void kunmap(struct page *page)
{
@@ -18,6 +19,7 @@ void kunmap(struct page *page)
return;
kunmap_high(page);
}
+EXPORT_SYMBOL(kunmap);
/*
* kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because
@@ -27,10 +29,10 @@ void kunmap(struct page *page)
* However when holding an atomic kmap it is not legal to sleep, so atomic
* kmaps are appropriate for short, tight code paths only.
*/
-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot(struct page *page, pgprot_t prot)
{
- enum fixed_addresses idx;
unsigned long vaddr;
+ int idx, type;
/* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
pagefault_disable();
@@ -38,8 +40,7 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
if (!PageHighMem(page))
return page_address(page);
- debug_kmap_atomic(type);
-
+ type = kmap_atomic_idx_push();
idx = type + KM_TYPE_NR*smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
BUG_ON(!pte_none(*(kmap_pte-idx)));
@@ -47,44 +48,57 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
return (void *)vaddr;
}
+EXPORT_SYMBOL(kmap_atomic_prot);
+
+void *__kmap_atomic(struct page *page)
+{
+ return kmap_atomic_prot(page, kmap_prot);
+}
+EXPORT_SYMBOL(__kmap_atomic);
-void *kmap_atomic(struct page *page, enum km_type type)
+/*
+ * This is the same as kmap_atomic() but can map memory that doesn't
+ * have a struct page associated with it.
+ */
+void *kmap_atomic_pfn(unsigned long pfn)
{
- return kmap_atomic_prot(page, type, kmap_prot);
+ return kmap_atomic_prot_pfn(pfn, kmap_prot);
}
+EXPORT_SYMBOL_GPL(kmap_atomic_pfn);
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
{
unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
- enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
-
- /*
- * Force other mappings to Oops if they'll try to access this pte
- * without first remap it. Keeping stale mappings around is a bad idea
- * also, in case the page changes cacheability attributes or becomes
- * a protected page in a hypervisor.
- */
- if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx))
+
+ if (vaddr >= __fix_to_virt(FIX_KMAP_END) &&
+ vaddr <= __fix_to_virt(FIX_KMAP_BEGIN)) {
+ int idx, type;
+
+ type = kmap_atomic_idx();
+ idx = type + KM_TYPE_NR * smp_processor_id();
+
+#ifdef CONFIG_DEBUG_HIGHMEM
+ WARN_ON_ONCE(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+#endif
+ /*
+ * Force other mappings to Oops if they'll try to access this
+ * pte without first remap it. Keeping stale mappings around
+ * is a bad idea also, in case the page changes cacheability
+ * attributes or becomes a protected page in a hypervisor.
+ */
kpte_clear_flush(kmap_pte-idx, vaddr);
- else {
+ kmap_atomic_idx_pop();
+ }
#ifdef CONFIG_DEBUG_HIGHMEM
+ else {
BUG_ON(vaddr < PAGE_OFFSET);
BUG_ON(vaddr >= (unsigned long)high_memory);
-#endif
}
+#endif
pagefault_enable();
}
-
-/*
- * This is the same as kmap_atomic() but can map memory that doesn't
- * have a struct page associated with it.
- */
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
-{
- return kmap_atomic_prot_pfn(pfn, type, kmap_prot);
-}
-EXPORT_SYMBOL_GPL(kmap_atomic_pfn); /* temporarily in use by i915 GEM until vmap */
+EXPORT_SYMBOL(__kunmap_atomic);
struct page *kmap_atomic_to_page(void *ptr)
{
@@ -98,12 +112,6 @@ struct page *kmap_atomic_to_page(void *ptr)
pte = kmap_pte - (idx - FIX_KMAP_BEGIN);
return pte_page(*pte);
}
-
-EXPORT_SYMBOL(kmap);
-EXPORT_SYMBOL(kunmap);
-EXPORT_SYMBOL(kmap_atomic);
-EXPORT_SYMBOL(kunmap_atomic_notypecheck);
-EXPORT_SYMBOL(kmap_atomic_prot);
EXPORT_SYMBOL(kmap_atomic_to_page);
void __init set_highmem_pages_init(void)
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 84346200e783..71a59296af80 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -51,7 +51,6 @@
#include <asm/numa.h>
#include <asm/cacheflush.h>
#include <asm/init.h>
-#include <linux/bootmem.h>
static int __init parse_direct_gbpages_off(char *arg)
{
diff --git a/arch/x86/mm/iomap_32.c b/arch/x86/mm/iomap_32.c
index 72fc70cf6184..7b179b499fa3 100644
--- a/arch/x86/mm/iomap_32.c
+++ b/arch/x86/mm/iomap_32.c
@@ -48,21 +48,20 @@ int iomap_create_wc(resource_size_t base, unsigned long size, pgprot_t *prot)
}
EXPORT_SYMBOL_GPL(iomap_create_wc);
-void
-iomap_free(resource_size_t base, unsigned long size)
+void iomap_free(resource_size_t base, unsigned long size)
{
io_free_memtype(base, base + size);
}
EXPORT_SYMBOL_GPL(iomap_free);
-void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot)
{
- enum fixed_addresses idx;
unsigned long vaddr;
+ int idx, type;
pagefault_disable();
- debug_kmap_atomic(type);
+ type = kmap_atomic_idx_push();
idx = type + KM_TYPE_NR * smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
set_pte(kmap_pte - idx, pfn_pte(pfn, prot));
@@ -72,10 +71,10 @@ void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
}
/*
- * Map 'pfn' using fixed map 'type' and protections 'prot'
+ * Map 'pfn' using protections 'prot'
*/
void __iomem *
-iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
+iomap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot)
{
/*
* For non-PAT systems, promote PAGE_KERNEL_WC to PAGE_KERNEL_UC_MINUS.
@@ -86,24 +85,34 @@ iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
if (!pat_enabled && pgprot_val(prot) == pgprot_val(PAGE_KERNEL_WC))
prot = PAGE_KERNEL_UC_MINUS;
- return (void __force __iomem *) kmap_atomic_prot_pfn(pfn, type, prot);
+ return (void __force __iomem *) kmap_atomic_prot_pfn(pfn, prot);
}
EXPORT_SYMBOL_GPL(iomap_atomic_prot_pfn);
void
-iounmap_atomic(void __iomem *kvaddr, enum km_type type)
+iounmap_atomic(void __iomem *kvaddr)
{
unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
- enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
- /*
- * Force other mappings to Oops if they'll try to access this pte
- * without first remap it. Keeping stale mappings around is a bad idea
- * also, in case the page changes cacheability attributes or becomes
- * a protected page in a hypervisor.
- */
- if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx))
+ if (vaddr >= __fix_to_virt(FIX_KMAP_END) &&
+ vaddr <= __fix_to_virt(FIX_KMAP_BEGIN)) {
+ int idx, type;
+
+ type = kmap_atomic_idx();
+ idx = type + KM_TYPE_NR * smp_processor_id();
+
+#ifdef CONFIG_DEBUG_HIGHMEM
+ WARN_ON_ONCE(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+#endif
+ /*
+ * Force other mappings to Oops if they'll try to access this
+ * pte without first remap it. Keeping stale mappings around
+ * is a bad idea also, in case the page changes cacheability
+ * attributes or becomes a protected page in a hypervisor.
+ */
kpte_clear_flush(kmap_pte-idx, vaddr);
+ kmap_atomic_idx_pop();
+ }
pagefault_enable();
}
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c
index bd1489c3ce09..4e8baad36d37 100644
--- a/arch/x86/oprofile/nmi_int.c
+++ b/arch/x86/oprofile/nmi_int.c
@@ -726,6 +726,12 @@ int __init op_nmi_init(struct oprofile_operations *ops)
case 0x11:
cpu_type = "x86-64/family11h";
break;
+ case 0x12:
+ cpu_type = "x86-64/family12h";
+ break;
+ case 0x14:
+ cpu_type = "x86-64/family14h";
+ break;
default:
return -ENODEV;
}
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c
index 42fb46f83883..a011bcc0f943 100644
--- a/arch/x86/oprofile/op_model_amd.c
+++ b/arch/x86/oprofile/op_model_amd.c
@@ -48,17 +48,24 @@ static unsigned long reset_value[NUM_VIRT_COUNTERS];
static u32 ibs_caps;
-struct op_ibs_config {
+struct ibs_config {
unsigned long op_enabled;
unsigned long fetch_enabled;
unsigned long max_cnt_fetch;
unsigned long max_cnt_op;
unsigned long rand_en;
unsigned long dispatched_ops;
+ unsigned long branch_target;
};
-static struct op_ibs_config ibs_config;
-static u64 ibs_op_ctl;
+struct ibs_state {
+ u64 ibs_op_ctl;
+ int branch_target;
+ unsigned long sample_size;
+};
+
+static struct ibs_config ibs_config;
+static struct ibs_state ibs_state;
/*
* IBS cpuid feature detection
@@ -71,8 +78,16 @@ static u64 ibs_op_ctl;
* bit 0 is used to indicate the existence of IBS.
*/
#define IBS_CAPS_AVAIL (1U<<0)
+#define IBS_CAPS_FETCHSAM (1U<<1)
+#define IBS_CAPS_OPSAM (1U<<2)
#define IBS_CAPS_RDWROPCNT (1U<<3)
#define IBS_CAPS_OPCNT (1U<<4)
+#define IBS_CAPS_BRNTRGT (1U<<5)
+#define IBS_CAPS_OPCNTEXT (1U<<6)
+
+#define IBS_CAPS_DEFAULT (IBS_CAPS_AVAIL \
+ | IBS_CAPS_FETCHSAM \
+ | IBS_CAPS_OPSAM)
/*
* IBS APIC setup
@@ -99,12 +114,12 @@ static u32 get_ibs_caps(void)
/* check IBS cpuid feature flags */
max_level = cpuid_eax(0x80000000);
if (max_level < IBS_CPUID_FEATURES)
- return IBS_CAPS_AVAIL;
+ return IBS_CAPS_DEFAULT;
ibs_caps = cpuid_eax(IBS_CPUID_FEATURES);
if (!(ibs_caps & IBS_CAPS_AVAIL))
/* cpuid flags not valid */
- return IBS_CAPS_AVAIL;
+ return IBS_CAPS_DEFAULT;
return ibs_caps;
}
@@ -197,8 +212,8 @@ op_amd_handle_ibs(struct pt_regs * const regs,
rdmsrl(MSR_AMD64_IBSOPCTL, ctl);
if (ctl & IBS_OP_VAL) {
rdmsrl(MSR_AMD64_IBSOPRIP, val);
- oprofile_write_reserve(&entry, regs, val,
- IBS_OP_CODE, IBS_OP_SIZE);
+ oprofile_write_reserve(&entry, regs, val, IBS_OP_CODE,
+ ibs_state.sample_size);
oprofile_add_data64(&entry, val);
rdmsrl(MSR_AMD64_IBSOPDATA, val);
oprofile_add_data64(&entry, val);
@@ -210,10 +225,14 @@ op_amd_handle_ibs(struct pt_regs * const regs,
oprofile_add_data64(&entry, val);
rdmsrl(MSR_AMD64_IBSDCPHYSAD, val);
oprofile_add_data64(&entry, val);
+ if (ibs_state.branch_target) {
+ rdmsrl(MSR_AMD64_IBSBRTARGET, val);
+ oprofile_add_data(&entry, (unsigned long)val);
+ }
oprofile_write_commit(&entry);
/* reenable the IRQ */
- ctl = op_amd_randomize_ibs_op(ibs_op_ctl);
+ ctl = op_amd_randomize_ibs_op(ibs_state.ibs_op_ctl);
wrmsrl(MSR_AMD64_IBSOPCTL, ctl);
}
}
@@ -226,21 +245,32 @@ static inline void op_amd_start_ibs(void)
if (!ibs_caps)
return;
+ memset(&ibs_state, 0, sizeof(ibs_state));
+
+ /*
+ * Note: Since the max count settings may out of range we
+ * write back the actual used values so that userland can read
+ * it.
+ */
+
if (ibs_config.fetch_enabled) {
- val = (ibs_config.max_cnt_fetch >> 4) & IBS_FETCH_MAX_CNT;
+ val = ibs_config.max_cnt_fetch >> 4;
+ val = min(val, IBS_FETCH_MAX_CNT);
+ ibs_config.max_cnt_fetch = val << 4;
val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0;
val |= IBS_FETCH_ENABLE;
wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
}
if (ibs_config.op_enabled) {
- ibs_op_ctl = ibs_config.max_cnt_op >> 4;
+ val = ibs_config.max_cnt_op >> 4;
if (!(ibs_caps & IBS_CAPS_RDWROPCNT)) {
/*
* IbsOpCurCnt not supported. See
* op_amd_randomize_ibs_op() for details.
*/
- ibs_op_ctl = clamp(ibs_op_ctl, 0x0081ULL, 0xFF80ULL);
+ val = clamp(val, 0x0081ULL, 0xFF80ULL);
+ ibs_config.max_cnt_op = val << 4;
} else {
/*
* The start value is randomized with a
@@ -248,13 +278,24 @@ static inline void op_amd_start_ibs(void)
* with the half of the randomized range. Also
* avoid underflows.
*/
- ibs_op_ctl = min(ibs_op_ctl + IBS_RANDOM_MAXCNT_OFFSET,
- IBS_OP_MAX_CNT);
+ val += IBS_RANDOM_MAXCNT_OFFSET;
+ if (ibs_caps & IBS_CAPS_OPCNTEXT)
+ val = min(val, IBS_OP_MAX_CNT_EXT);
+ else
+ val = min(val, IBS_OP_MAX_CNT);
+ ibs_config.max_cnt_op =
+ (val - IBS_RANDOM_MAXCNT_OFFSET) << 4;
+ }
+ val = ((val & ~IBS_OP_MAX_CNT) << 4) | (val & IBS_OP_MAX_CNT);
+ val |= ibs_config.dispatched_ops ? IBS_OP_CNT_CTL : 0;
+ val |= IBS_OP_ENABLE;
+ ibs_state.ibs_op_ctl = val;
+ ibs_state.sample_size = IBS_OP_SIZE;
+ if (ibs_config.branch_target) {
+ ibs_state.branch_target = 1;
+ ibs_state.sample_size++;
}
- if (ibs_caps & IBS_CAPS_OPCNT && ibs_config.dispatched_ops)
- ibs_op_ctl |= IBS_OP_CNT_CTL;
- ibs_op_ctl |= IBS_OP_ENABLE;
- val = op_amd_randomize_ibs_op(ibs_op_ctl);
+ val = op_amd_randomize_ibs_op(ibs_state.ibs_op_ctl);
wrmsrl(MSR_AMD64_IBSOPCTL, val);
}
}
@@ -281,29 +322,25 @@ static inline int eilvt_is_available(int offset)
static inline int ibs_eilvt_valid(void)
{
- u64 val;
int offset;
+ u64 val;
rdmsrl(MSR_AMD64_IBSCTL, val);
+ offset = val & IBSCTL_LVT_OFFSET_MASK;
+
if (!(val & IBSCTL_LVT_OFFSET_VALID)) {
- pr_err(FW_BUG "cpu %d, invalid IBS "
- "interrupt offset %d (MSR%08X=0x%016llx)",
- smp_processor_id(), offset,
- MSR_AMD64_IBSCTL, val);
+ pr_err(FW_BUG "cpu %d, invalid IBS interrupt offset %d (MSR%08X=0x%016llx)\n",
+ smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
return 0;
}
- offset = val & IBSCTL_LVT_OFFSET_MASK;
-
- if (eilvt_is_available(offset))
- return !0;
-
- pr_err(FW_BUG "cpu %d, IBS interrupt offset %d "
- "not available (MSR%08X=0x%016llx)",
- smp_processor_id(), offset,
- MSR_AMD64_IBSCTL, val);
+ if (!eilvt_is_available(offset)) {
+ pr_err(FW_BUG "cpu %d, IBS interrupt offset %d not available (MSR%08X=0x%016llx)\n",
+ smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
+ return 0;
+ }
- return 0;
+ return 1;
}
static inline int get_ibs_offset(void)
@@ -630,28 +667,33 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root)
/* model specific files */
/* setup some reasonable defaults */
+ memset(&ibs_config, 0, sizeof(ibs_config));
ibs_config.max_cnt_fetch = 250000;
- ibs_config.fetch_enabled = 0;
ibs_config.max_cnt_op = 250000;
- ibs_config.op_enabled = 0;
- ibs_config.dispatched_ops = 0;
-
- dir = oprofilefs_mkdir(sb, root, "ibs_fetch");
- oprofilefs_create_ulong(sb, dir, "enable",
- &ibs_config.fetch_enabled);
- oprofilefs_create_ulong(sb, dir, "max_count",
- &ibs_config.max_cnt_fetch);
- oprofilefs_create_ulong(sb, dir, "rand_enable",
- &ibs_config.rand_en);
-
- dir = oprofilefs_mkdir(sb, root, "ibs_op");
- oprofilefs_create_ulong(sb, dir, "enable",
- &ibs_config.op_enabled);
- oprofilefs_create_ulong(sb, dir, "max_count",
- &ibs_config.max_cnt_op);
- if (ibs_caps & IBS_CAPS_OPCNT)
- oprofilefs_create_ulong(sb, dir, "dispatched_ops",
- &ibs_config.dispatched_ops);
+
+ if (ibs_caps & IBS_CAPS_FETCHSAM) {
+ dir = oprofilefs_mkdir(sb, root, "ibs_fetch");
+ oprofilefs_create_ulong(sb, dir, "enable",
+ &ibs_config.fetch_enabled);
+ oprofilefs_create_ulong(sb, dir, "max_count",
+ &ibs_config.max_cnt_fetch);
+ oprofilefs_create_ulong(sb, dir, "rand_enable",
+ &ibs_config.rand_en);
+ }
+
+ if (ibs_caps & IBS_CAPS_OPSAM) {
+ dir = oprofilefs_mkdir(sb, root, "ibs_op");
+ oprofilefs_create_ulong(sb, dir, "enable",
+ &ibs_config.op_enabled);
+ oprofilefs_create_ulong(sb, dir, "max_count",
+ &ibs_config.max_cnt_op);
+ if (ibs_caps & IBS_CAPS_OPCNT)
+ oprofilefs_create_ulong(sb, dir, "dispatched_ops",
+ &ibs_config.dispatched_ops);
+ if (ibs_caps & IBS_CAPS_BRNTRGT)
+ oprofilefs_create_ulong(sb, dir, "branch_target",
+ &ibs_config.branch_target);
+ }
return 0;
}
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig
index 68128a1b401a..90a7f5ad6916 100644
--- a/arch/x86/xen/Kconfig
+++ b/arch/x86/xen/Kconfig
@@ -19,15 +19,12 @@ config XEN_PVHVM
depends on X86_LOCAL_APIC
config XEN_MAX_DOMAIN_MEMORY
- int "Maximum allowed size of a domain in gigabytes"
- default 8 if X86_32
- default 32 if X86_64
+ int
+ default 128
depends on XEN
help
- The pseudo-physical to machine address array is sized
- according to the maximum possible memory size of a Xen
- domain. This array uses 1 page per gigabyte, so there's no
- need to be too stingy here.
+ This only affects the sizing of some bss arrays, the unused
+ portions of which are freed.
config XEN_SAVE_RESTORE
bool
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 63b83ceebd1a..70ddeaeb1ef3 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -59,7 +59,6 @@
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
#include <asm/reboot.h>
-#include <asm/setup.h>
#include <asm/stackprotector.h>
#include <asm/hypervisor.h>
@@ -136,9 +135,6 @@ static void xen_vcpu_setup(int cpu)
info.mfn = arbitrary_virt_to_mfn(vcpup);
info.offset = offset_in_page(vcpup);
- printk(KERN_DEBUG "trying to map vcpu_info %d at %p, mfn %llx, offset %d\n",
- cpu, vcpup, info.mfn, info.offset);
-
/* Check to see if the hypervisor will put the vcpu_info
structure where we want it, which allows direct access via
a percpu-variable. */
@@ -152,9 +148,6 @@ static void xen_vcpu_setup(int cpu)
/* This cpu is using the registered vcpu info, even if
later ones fail to. */
per_cpu(xen_vcpu, cpu) = vcpup;
-
- printk(KERN_DEBUG "cpu %d using vcpu_info at %p\n",
- cpu, vcpup);
}
}
@@ -836,6 +829,11 @@ static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high)
Xen console noise. */
break;
+ case MSR_IA32_CR_PAT:
+ if (smp_processor_id() == 0)
+ xen_set_pat(((u64)high << 32) | low);
+ break;
+
default:
ret = native_write_msr_safe(msr, low, high);
}
@@ -874,8 +872,6 @@ void xen_setup_vcpu_info_placement(void)
/* xen_vcpu_setup managed to place the vcpu_info within the
percpu area for all cpus, so make use of it */
if (have_vcpu_info_placement) {
- printk(KERN_INFO "Xen: using vcpu_info placement\n");
-
pv_irq_ops.save_fl = __PV_IS_CALLEE_SAVE(xen_save_fl_direct);
pv_irq_ops.restore_fl = __PV_IS_CALLEE_SAVE(xen_restore_fl_direct);
pv_irq_ops.irq_disable = __PV_IS_CALLEE_SAVE(xen_irq_disable_direct);
@@ -1019,7 +1015,7 @@ static void xen_reboot(int reason)
struct sched_shutdown r = { .reason = reason };
#ifdef CONFIG_SMP
- smp_send_stop();
+ stop_other_cpus();
#endif
if (HYPERVISOR_sched_op(SCHEDOP_shutdown, &r))
@@ -1189,6 +1185,9 @@ asmlinkage void __init xen_start_kernel(void)
xen_raw_console_write("mapping kernel into physical memory\n");
pgd = xen_setup_kernel_pagetable(pgd, xen_start_info->nr_pages);
+ /* Allocate and initialize top and mid mfn levels for p2m structure */
+ xen_build_mfn_list_list();
+
init_mm.pgd = pgd;
/* keep using Xen gdt for now; no urgent need to change it */
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index f72d18c69221..9631c90907eb 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -57,6 +57,7 @@
#include <asm/linkage.h>
#include <asm/page.h>
#include <asm/init.h>
+#include <asm/pat.h>
#include <asm/xen/hypercall.h>
#include <asm/xen/hypervisor.h>
@@ -140,7 +141,8 @@ static inline void check_zero(void)
* large enough to allocate page table pages to allocate the rest.
* Each page can map 2MB.
*/
-static pte_t level1_ident_pgt[PTRS_PER_PTE * 4] __page_aligned_bss;
+#define LEVEL1_IDENT_ENTRIES (PTRS_PER_PTE * 4)
+static RESERVE_BRK_ARRAY(pte_t, level1_ident_pgt, LEVEL1_IDENT_ENTRIES);
#ifdef CONFIG_X86_64
/* l3 pud for userspace vsyscall mapping */
@@ -171,49 +173,182 @@ DEFINE_PER_CPU(unsigned long, xen_current_cr3); /* actual vcpu cr3 */
*/
#define USER_LIMIT ((STACK_TOP_MAX + PGDIR_SIZE - 1) & PGDIR_MASK)
+/*
+ * Xen leaves the responsibility for maintaining p2m mappings to the
+ * guests themselves, but it must also access and update the p2m array
+ * during suspend/resume when all the pages are reallocated.
+ *
+ * The p2m table is logically a flat array, but we implement it as a
+ * three-level tree to allow the address space to be sparse.
+ *
+ * Xen
+ * |
+ * p2m_top p2m_top_mfn
+ * / \ / \
+ * p2m_mid p2m_mid p2m_mid_mfn p2m_mid_mfn
+ * / \ / \ / /
+ * p2m p2m p2m p2m p2m p2m p2m ...
+ *
+ * The p2m_mid_mfn pages are mapped by p2m_top_mfn_p.
+ *
+ * The p2m_top and p2m_top_mfn levels are limited to 1 page, so the
+ * maximum representable pseudo-physical address space is:
+ * P2M_TOP_PER_PAGE * P2M_MID_PER_PAGE * P2M_PER_PAGE pages
+ *
+ * P2M_PER_PAGE depends on the architecture, as a mfn is always
+ * unsigned long (8 bytes on 64-bit, 4 bytes on 32), leading to
+ * 512 and 1024 entries respectively.
+ */
+
+unsigned long xen_max_p2m_pfn __read_mostly;
-#define P2M_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(unsigned long))
-#define TOP_ENTRIES (MAX_DOMAIN_PAGES / P2M_ENTRIES_PER_PAGE)
+#define P2M_PER_PAGE (PAGE_SIZE / sizeof(unsigned long))
+#define P2M_MID_PER_PAGE (PAGE_SIZE / sizeof(unsigned long *))
+#define P2M_TOP_PER_PAGE (PAGE_SIZE / sizeof(unsigned long **))
-/* Placeholder for holes in the address space */
-static unsigned long p2m_missing[P2M_ENTRIES_PER_PAGE] __page_aligned_data =
- { [ 0 ... P2M_ENTRIES_PER_PAGE-1 ] = ~0UL };
+#define MAX_P2M_PFN (P2M_TOP_PER_PAGE * P2M_MID_PER_PAGE * P2M_PER_PAGE)
- /* Array of pointers to pages containing p2m entries */
-static unsigned long *p2m_top[TOP_ENTRIES] __page_aligned_data =
- { [ 0 ... TOP_ENTRIES - 1] = &p2m_missing[0] };
+/* Placeholders for holes in the address space */
+static RESERVE_BRK_ARRAY(unsigned long, p2m_missing, P2M_PER_PAGE);
+static RESERVE_BRK_ARRAY(unsigned long *, p2m_mid_missing, P2M_MID_PER_PAGE);
+static RESERVE_BRK_ARRAY(unsigned long, p2m_mid_missing_mfn, P2M_MID_PER_PAGE);
-/* Arrays of p2m arrays expressed in mfns used for save/restore */
-static unsigned long p2m_top_mfn[TOP_ENTRIES] __page_aligned_bss;
+static RESERVE_BRK_ARRAY(unsigned long **, p2m_top, P2M_TOP_PER_PAGE);
+static RESERVE_BRK_ARRAY(unsigned long, p2m_top_mfn, P2M_TOP_PER_PAGE);
+static RESERVE_BRK_ARRAY(unsigned long *, p2m_top_mfn_p, P2M_TOP_PER_PAGE);
-static unsigned long p2m_top_mfn_list[TOP_ENTRIES / P2M_ENTRIES_PER_PAGE]
- __page_aligned_bss;
+RESERVE_BRK(p2m_mid, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE)));
+RESERVE_BRK(p2m_mid_mfn, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE)));
static inline unsigned p2m_top_index(unsigned long pfn)
{
- BUG_ON(pfn >= MAX_DOMAIN_PAGES);
- return pfn / P2M_ENTRIES_PER_PAGE;
+ BUG_ON(pfn >= MAX_P2M_PFN);
+ return pfn / (P2M_MID_PER_PAGE * P2M_PER_PAGE);
+}
+
+static inline unsigned p2m_mid_index(unsigned long pfn)
+{
+ return (pfn / P2M_PER_PAGE) % P2M_MID_PER_PAGE;
}
static inline unsigned p2m_index(unsigned long pfn)
{
- return pfn % P2M_ENTRIES_PER_PAGE;
+ return pfn % P2M_PER_PAGE;
+}
+
+static void p2m_top_init(unsigned long ***top)
+{
+ unsigned i;
+
+ for (i = 0; i < P2M_TOP_PER_PAGE; i++)
+ top[i] = p2m_mid_missing;
+}
+
+static void p2m_top_mfn_init(unsigned long *top)
+{
+ unsigned i;
+
+ for (i = 0; i < P2M_TOP_PER_PAGE; i++)
+ top[i] = virt_to_mfn(p2m_mid_missing_mfn);
+}
+
+static void p2m_top_mfn_p_init(unsigned long **top)
+{
+ unsigned i;
+
+ for (i = 0; i < P2M_TOP_PER_PAGE; i++)
+ top[i] = p2m_mid_missing_mfn;
+}
+
+static void p2m_mid_init(unsigned long **mid)
+{
+ unsigned i;
+
+ for (i = 0; i < P2M_MID_PER_PAGE; i++)
+ mid[i] = p2m_missing;
+}
+
+static void p2m_mid_mfn_init(unsigned long *mid)
+{
+ unsigned i;
+
+ for (i = 0; i < P2M_MID_PER_PAGE; i++)
+ mid[i] = virt_to_mfn(p2m_missing);
}
-/* Build the parallel p2m_top_mfn structures */
+static void p2m_init(unsigned long *p2m)
+{
+ unsigned i;
+
+ for (i = 0; i < P2M_MID_PER_PAGE; i++)
+ p2m[i] = INVALID_P2M_ENTRY;
+}
+
+/*
+ * Build the parallel p2m_top_mfn and p2m_mid_mfn structures
+ *
+ * This is called both at boot time, and after resuming from suspend:
+ * - At boot time we're called very early, and must use extend_brk()
+ * to allocate memory.
+ *
+ * - After resume we're called from within stop_machine, but the mfn
+ * tree should alreay be completely allocated.
+ */
void xen_build_mfn_list_list(void)
{
- unsigned pfn, idx;
+ unsigned long pfn;
- for (pfn = 0; pfn < MAX_DOMAIN_PAGES; pfn += P2M_ENTRIES_PER_PAGE) {
- unsigned topidx = p2m_top_index(pfn);
+ /* Pre-initialize p2m_top_mfn to be completely missing */
+ if (p2m_top_mfn == NULL) {
+ p2m_mid_missing_mfn = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ p2m_mid_mfn_init(p2m_mid_missing_mfn);
+
+ p2m_top_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ p2m_top_mfn_p_init(p2m_top_mfn_p);
- p2m_top_mfn[topidx] = virt_to_mfn(p2m_top[topidx]);
+ p2m_top_mfn = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ p2m_top_mfn_init(p2m_top_mfn);
+ } else {
+ /* Reinitialise, mfn's all change after migration */
+ p2m_mid_mfn_init(p2m_mid_missing_mfn);
}
- for (idx = 0; idx < ARRAY_SIZE(p2m_top_mfn_list); idx++) {
- unsigned topidx = idx * P2M_ENTRIES_PER_PAGE;
- p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]);
+ for (pfn = 0; pfn < xen_max_p2m_pfn; pfn += P2M_PER_PAGE) {
+ unsigned topidx = p2m_top_index(pfn);
+ unsigned mididx = p2m_mid_index(pfn);
+ unsigned long **mid;
+ unsigned long *mid_mfn_p;
+
+ mid = p2m_top[topidx];
+ mid_mfn_p = p2m_top_mfn_p[topidx];
+
+ /* Don't bother allocating any mfn mid levels if
+ * they're just missing, just update the stored mfn,
+ * since all could have changed over a migrate.
+ */
+ if (mid == p2m_mid_missing) {
+ BUG_ON(mididx);
+ BUG_ON(mid_mfn_p != p2m_mid_missing_mfn);
+ p2m_top_mfn[topidx] = virt_to_mfn(p2m_mid_missing_mfn);
+ pfn += (P2M_MID_PER_PAGE - 1) * P2M_PER_PAGE;
+ continue;
+ }
+
+ if (mid_mfn_p == p2m_mid_missing_mfn) {
+ /*
+ * XXX boot-time only! We should never find
+ * missing parts of the mfn tree after
+ * runtime. extend_brk() will BUG if we call
+ * it too late.
+ */
+ mid_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ p2m_mid_mfn_init(mid_mfn_p);
+
+ p2m_top_mfn_p[topidx] = mid_mfn_p;
+ }
+
+ p2m_top_mfn[topidx] = virt_to_mfn(mid_mfn_p);
+ mid_mfn_p[mididx] = virt_to_mfn(mid[mididx]);
}
}
@@ -222,8 +357,8 @@ void xen_setup_mfn_list_list(void)
BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info);
HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
- virt_to_mfn(p2m_top_mfn_list);
- HYPERVISOR_shared_info->arch.max_pfn = xen_start_info->nr_pages;
+ virt_to_mfn(p2m_top_mfn);
+ HYPERVISOR_shared_info->arch.max_pfn = xen_max_p2m_pfn;
}
/* Set up p2m_top to point to the domain-builder provided p2m pages */
@@ -231,98 +366,176 @@ void __init xen_build_dynamic_phys_to_machine(void)
{
unsigned long *mfn_list = (unsigned long *)xen_start_info->mfn_list;
unsigned long max_pfn = min(MAX_DOMAIN_PAGES, xen_start_info->nr_pages);
- unsigned pfn;
+ unsigned long pfn;
+
+ xen_max_p2m_pfn = max_pfn;
- for (pfn = 0; pfn < max_pfn; pfn += P2M_ENTRIES_PER_PAGE) {
+ p2m_missing = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ p2m_init(p2m_missing);
+
+ p2m_mid_missing = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ p2m_mid_init(p2m_mid_missing);
+
+ p2m_top = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ p2m_top_init(p2m_top);
+
+ /*
+ * The domain builder gives us a pre-constructed p2m array in
+ * mfn_list for all the pages initially given to us, so we just
+ * need to graft that into our tree structure.
+ */
+ for (pfn = 0; pfn < max_pfn; pfn += P2M_PER_PAGE) {
unsigned topidx = p2m_top_index(pfn);
+ unsigned mididx = p2m_mid_index(pfn);
- p2m_top[topidx] = &mfn_list[pfn];
- }
+ if (p2m_top[topidx] == p2m_mid_missing) {
+ unsigned long **mid = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ p2m_mid_init(mid);
+
+ p2m_top[topidx] = mid;
+ }
- xen_build_mfn_list_list();
+ p2m_top[topidx][mididx] = &mfn_list[pfn];
+ }
}
unsigned long get_phys_to_machine(unsigned long pfn)
{
- unsigned topidx, idx;
+ unsigned topidx, mididx, idx;
- if (unlikely(pfn >= MAX_DOMAIN_PAGES))
+ if (unlikely(pfn >= MAX_P2M_PFN))
return INVALID_P2M_ENTRY;
topidx = p2m_top_index(pfn);
+ mididx = p2m_mid_index(pfn);
idx = p2m_index(pfn);
- return p2m_top[topidx][idx];
+
+ return p2m_top[topidx][mididx][idx];
}
EXPORT_SYMBOL_GPL(get_phys_to_machine);
-/* install a new p2m_top page */
-bool install_p2mtop_page(unsigned long pfn, unsigned long *p)
+static void *alloc_p2m_page(void)
{
- unsigned topidx = p2m_top_index(pfn);
- unsigned long **pfnp, *mfnp;
- unsigned i;
+ return (void *)__get_free_page(GFP_KERNEL | __GFP_REPEAT);
+}
- pfnp = &p2m_top[topidx];
- mfnp = &p2m_top_mfn[topidx];
+static void free_p2m_page(void *p)
+{
+ free_page((unsigned long)p);
+}
- for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++)
- p[i] = INVALID_P2M_ENTRY;
+/*
+ * Fully allocate the p2m structure for a given pfn. We need to check
+ * that both the top and mid levels are allocated, and make sure the
+ * parallel mfn tree is kept in sync. We may race with other cpus, so
+ * the new pages are installed with cmpxchg; if we lose the race then
+ * simply free the page we allocated and use the one that's there.
+ */
+static bool alloc_p2m(unsigned long pfn)
+{
+ unsigned topidx, mididx;
+ unsigned long ***top_p, **mid;
+ unsigned long *top_mfn_p, *mid_mfn;
- if (cmpxchg(pfnp, p2m_missing, p) == p2m_missing) {
- *mfnp = virt_to_mfn(p);
- return true;
+ topidx = p2m_top_index(pfn);
+ mididx = p2m_mid_index(pfn);
+
+ top_p = &p2m_top[topidx];
+ mid = *top_p;
+
+ if (mid == p2m_mid_missing) {
+ /* Mid level is missing, allocate a new one */
+ mid = alloc_p2m_page();
+ if (!mid)
+ return false;
+
+ p2m_mid_init(mid);
+
+ if (cmpxchg(top_p, p2m_mid_missing, mid) != p2m_mid_missing)
+ free_p2m_page(mid);
}
- return false;
-}
+ top_mfn_p = &p2m_top_mfn[topidx];
+ mid_mfn = p2m_top_mfn_p[topidx];
-static void alloc_p2m(unsigned long pfn)
-{
- unsigned long *p;
+ BUG_ON(virt_to_mfn(mid_mfn) != *top_mfn_p);
+
+ if (mid_mfn == p2m_mid_missing_mfn) {
+ /* Separately check the mid mfn level */
+ unsigned long missing_mfn;
+ unsigned long mid_mfn_mfn;
+
+ mid_mfn = alloc_p2m_page();
+ if (!mid_mfn)
+ return false;
+
+ p2m_mid_mfn_init(mid_mfn);
+
+ missing_mfn = virt_to_mfn(p2m_mid_missing_mfn);
+ mid_mfn_mfn = virt_to_mfn(mid_mfn);
+ if (cmpxchg(top_mfn_p, missing_mfn, mid_mfn_mfn) != missing_mfn)
+ free_p2m_page(mid_mfn);
+ else
+ p2m_top_mfn_p[topidx] = mid_mfn;
+ }
+
+ if (p2m_top[topidx][mididx] == p2m_missing) {
+ /* p2m leaf page is missing */
+ unsigned long *p2m;
+
+ p2m = alloc_p2m_page();
+ if (!p2m)
+ return false;
- p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
- BUG_ON(p == NULL);
+ p2m_init(p2m);
+
+ if (cmpxchg(&mid[mididx], p2m_missing, p2m) != p2m_missing)
+ free_p2m_page(p2m);
+ else
+ mid_mfn[mididx] = virt_to_mfn(p2m);
+ }
- if (!install_p2mtop_page(pfn, p))
- free_page((unsigned long)p);
+ return true;
}
/* Try to install p2m mapping; fail if intermediate bits missing */
bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
{
- unsigned topidx, idx;
+ unsigned topidx, mididx, idx;
- if (unlikely(pfn >= MAX_DOMAIN_PAGES)) {
+ if (unlikely(pfn >= MAX_P2M_PFN)) {
BUG_ON(mfn != INVALID_P2M_ENTRY);
return true;
}
topidx = p2m_top_index(pfn);
- if (p2m_top[topidx] == p2m_missing) {
- if (mfn == INVALID_P2M_ENTRY)
- return true;
- return false;
- }
-
+ mididx = p2m_mid_index(pfn);
idx = p2m_index(pfn);
- p2m_top[topidx][idx] = mfn;
+
+ if (p2m_top[topidx][mididx] == p2m_missing)
+ return mfn == INVALID_P2M_ENTRY;
+
+ p2m_top[topidx][mididx][idx] = mfn;
return true;
}
-void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
{
if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
- return;
+ return true;
}
if (unlikely(!__set_phys_to_machine(pfn, mfn))) {
- alloc_p2m(pfn);
+ if (!alloc_p2m(pfn))
+ return false;
if (!__set_phys_to_machine(pfn, mfn))
- BUG();
+ return false;
}
+
+ return true;
}
unsigned long arbitrary_virt_to_mfn(void *vaddr)
@@ -399,7 +612,7 @@ static bool xen_iomap_pte(pte_t pte)
return pte_flags(pte) & _PAGE_IOMAP;
}
-static void xen_set_iomap_pte(pte_t *ptep, pte_t pteval)
+void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid)
{
struct multicall_space mcs;
struct mmu_update *u;
@@ -411,10 +624,16 @@ static void xen_set_iomap_pte(pte_t *ptep, pte_t pteval)
u->ptr = arbitrary_virt_to_machine(ptep).maddr;
u->val = pte_val_ma(pteval);
- MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, DOMID_IO);
+ MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, domid);
xen_mc_issue(PARAVIRT_LAZY_MMU);
}
+EXPORT_SYMBOL_GPL(xen_set_domain_pte);
+
+static void xen_set_iomap_pte(pte_t *ptep, pte_t pteval)
+{
+ xen_set_domain_pte(ptep, pteval, DOMID_IO);
+}
static void xen_extend_mmu_update(const struct mmu_update *update)
{
@@ -561,7 +780,20 @@ static pteval_t pte_pfn_to_mfn(pteval_t val)
if (val & _PAGE_PRESENT) {
unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT;
pteval_t flags = val & PTE_FLAGS_MASK;
- val = ((pteval_t)pfn_to_mfn(pfn) << PAGE_SHIFT) | flags;
+ unsigned long mfn = pfn_to_mfn(pfn);
+
+ /*
+ * If there's no mfn for the pfn, then just create an
+ * empty non-present pte. Unfortunately this loses
+ * information about the original pfn, so
+ * pte_mfn_to_pfn is asymmetric.
+ */
+ if (unlikely(mfn == INVALID_P2M_ENTRY)) {
+ mfn = 0;
+ flags = 0;
+ }
+
+ val = ((pteval_t)mfn << PAGE_SHIFT) | flags;
}
return val;
@@ -583,10 +815,18 @@ static pteval_t iomap_pte(pteval_t val)
pteval_t xen_pte_val(pte_t pte)
{
- if (xen_initial_domain() && (pte.pte & _PAGE_IOMAP))
- return pte.pte;
+ pteval_t pteval = pte.pte;
+
+ /* If this is a WC pte, convert back from Xen WC to Linux WC */
+ if ((pteval & (_PAGE_PAT | _PAGE_PCD | _PAGE_PWT)) == _PAGE_PAT) {
+ WARN_ON(!pat_enabled);
+ pteval = (pteval & ~_PAGE_PAT) | _PAGE_PWT;
+ }
- return pte_mfn_to_pfn(pte.pte);
+ if (xen_initial_domain() && (pteval & _PAGE_IOMAP))
+ return pteval;
+
+ return pte_mfn_to_pfn(pteval);
}
PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val);
@@ -596,10 +836,48 @@ pgdval_t xen_pgd_val(pgd_t pgd)
}
PV_CALLEE_SAVE_REGS_THUNK(xen_pgd_val);
+/*
+ * Xen's PAT setup is part of its ABI, though I assume entries 6 & 7
+ * are reserved for now, to correspond to the Intel-reserved PAT
+ * types.
+ *
+ * We expect Linux's PAT set as follows:
+ *
+ * Idx PTE flags Linux Xen Default
+ * 0 WB WB WB
+ * 1 PWT WC WT WT
+ * 2 PCD UC- UC- UC-
+ * 3 PCD PWT UC UC UC
+ * 4 PAT WB WC WB
+ * 5 PAT PWT WC WP WT
+ * 6 PAT PCD UC- UC UC-
+ * 7 PAT PCD PWT UC UC UC
+ */
+
+void xen_set_pat(u64 pat)
+{
+ /* We expect Linux to use a PAT setting of
+ * UC UC- WC WB (ignoring the PAT flag) */
+ WARN_ON(pat != 0x0007010600070106ull);
+}
+
pte_t xen_make_pte(pteval_t pte)
{
phys_addr_t addr = (pte & PTE_PFN_MASK);
+ /* If Linux is trying to set a WC pte, then map to the Xen WC.
+ * If _PAGE_PAT is set, then it probably means it is really
+ * _PAGE_PSE, so avoid fiddling with the PAT mapping and hope
+ * things work out OK...
+ *
+ * (We should never see kernel mappings with _PAGE_PSE set,
+ * but we could see hugetlbfs mappings, I think.).
+ */
+ if (pat_enabled && !WARN_ON(pte & _PAGE_PAT)) {
+ if ((pte & (_PAGE_PCD | _PAGE_PWT)) == _PAGE_PWT)
+ pte = (pte & ~(_PAGE_PCD | _PAGE_PWT)) | _PAGE_PAT;
+ }
+
/*
* Unprivileged domains are allowed to do IOMAPpings for
* PCI passthrough, but not map ISA space. The ISA
@@ -1712,6 +1990,9 @@ static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
unsigned ident_pte;
unsigned long pfn;
+ level1_ident_pgt = extend_brk(sizeof(pte_t) * LEVEL1_IDENT_ENTRIES,
+ PAGE_SIZE);
+
ident_pte = 0;
pfn = 0;
for (pmdidx = 0; pmdidx < PTRS_PER_PMD && pfn < max_pfn; pmdidx++) {
@@ -1722,7 +2003,7 @@ static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
pte_page = m2v(pmd[pmdidx].pmd);
else {
/* Check for free pte pages */
- if (ident_pte == ARRAY_SIZE(level1_ident_pgt))
+ if (ident_pte == LEVEL1_IDENT_ENTRIES)
break;
pte_page = &level1_ident_pgt[ident_pte];
@@ -1837,13 +2118,15 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
return pgd;
}
#else /* !CONFIG_X86_64 */
-static pmd_t level2_kernel_pgt[PTRS_PER_PMD] __page_aligned_bss;
+static RESERVE_BRK_ARRAY(pmd_t, level2_kernel_pgt, PTRS_PER_PMD);
__init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
unsigned long max_pfn)
{
pmd_t *kernel_pmd;
+ level2_kernel_pgt = extend_brk(sizeof(pmd_t *) * PTRS_PER_PMD, PAGE_SIZE);
+
max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->pt_base) +
xen_start_info->nr_pt_frames * PAGE_SIZE +
512*1024);
@@ -2269,6 +2552,72 @@ void __init xen_hvm_init_mmu_ops(void)
}
#endif
+#define REMAP_BATCH_SIZE 16
+
+struct remap_data {
+ unsigned long mfn;
+ pgprot_t prot;
+ struct mmu_update *mmu_update;
+};
+
+static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token,
+ unsigned long addr, void *data)
+{
+ struct remap_data *rmd = data;
+ pte_t pte = pte_mkspecial(pfn_pte(rmd->mfn++, rmd->prot));
+
+ rmd->mmu_update->ptr = arbitrary_virt_to_machine(ptep).maddr;
+ rmd->mmu_update->val = pte_val_ma(pte);
+ rmd->mmu_update++;
+
+ return 0;
+}
+
+int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
+ unsigned long addr,
+ unsigned long mfn, int nr,
+ pgprot_t prot, unsigned domid)
+{
+ struct remap_data rmd;
+ struct mmu_update mmu_update[REMAP_BATCH_SIZE];
+ int batch;
+ unsigned long range;
+ int err = 0;
+
+ prot = __pgprot(pgprot_val(prot) | _PAGE_IOMAP);
+
+ vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
+
+ rmd.mfn = mfn;
+ rmd.prot = prot;
+
+ while (nr) {
+ batch = min(REMAP_BATCH_SIZE, nr);
+ range = (unsigned long)batch << PAGE_SHIFT;
+
+ rmd.mmu_update = mmu_update;
+ err = apply_to_page_range(vma->vm_mm, addr, range,
+ remap_area_mfn_pte_fn, &rmd);
+ if (err)
+ goto out;
+
+ err = -EFAULT;
+ if (HYPERVISOR_mmu_update(mmu_update, batch, NULL, domid) < 0)
+ goto out;
+
+ nr -= batch;
+ addr += range;
+ }
+
+ err = 0;
+out:
+
+ flush_tlb_all();
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
+
#ifdef CONFIG_XEN_DEBUG_FS
static struct dentry *d_mmu_debug;
diff --git a/arch/x86/xen/mmu.h b/arch/x86/xen/mmu.h
index fa938c4aa2f7..537bb9aab777 100644
--- a/arch/x86/xen/mmu.h
+++ b/arch/x86/xen/mmu.h
@@ -12,7 +12,6 @@ enum pt_level {
bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
-bool install_p2mtop_page(unsigned long pfn, unsigned long *p);
void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index 9729c903404b..105db2501050 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -18,8 +18,10 @@
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
+#include <xen/xen.h>
#include <xen/page.h>
#include <xen/interface/callback.h>
+#include <xen/interface/memory.h>
#include <xen/interface/physdev.h>
#include <xen/interface/memory.h>
#include <xen/features.h>
@@ -34,6 +36,39 @@ extern void xen_sysenter_target(void);
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;
+
+/*
+ * The maximum amount of extra memory compared to the base size. The
+ * main scaling factor is the size of struct page. At extreme ratios
+ * of base:extra, all the base memory can be filled with page
+ * structures for the extra memory, leaving no space for anything
+ * else.
+ *
+ * 10x seems like a reasonable balance between scaling flexibility and
+ * leaving a practically usable system.
+ */
+#define EXTRA_MEM_RATIO (10)
+
+static __init void xen_add_extra_mem(unsigned long pages)
+{
+ 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");
+
+ xen_extra_mem_size += size;
+
+ xen_max_p2m_pfn = PFN_DOWN(extra_start + size);
+}
+
static unsigned long __init xen_release_chunk(phys_addr_t start_addr,
phys_addr_t end_addr)
{
@@ -105,16 +140,65 @@ static unsigned long __init xen_return_unused_memory(unsigned long max_pfn,
/**
* machine_specific_memory_setup - Hook for machine specific memory setup.
**/
-
char * __init xen_memory_setup(void)
{
+ static struct e820entry map[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 extra_pages = 0;
+ unsigned long extra_limit;
+ int i;
+ int op;
max_pfn = min(MAX_DOMAIN_PAGES, max_pfn);
+ mem_end = PFN_PHYS(max_pfn);
+
+ memmap.nr_entries = E820MAX;
+ set_xen_guest_handle(memmap.buffer, map);
+
+ op = xen_initial_domain() ?
+ XENMEM_machine_memory_map :
+ XENMEM_memory_map;
+ rc = HYPERVISOR_memory_op(op, &memmap);
+ if (rc == -ENOSYS) {
+ memmap.nr_entries = 1;
+ map[0].addr = 0ULL;
+ map[0].size = mem_end;
+ /* 8MB slack (to balance backend allocations). */
+ map[0].size += 8ULL << 20;
+ map[0].type = E820_RAM;
+ rc = 0;
+ }
+ BUG_ON(rc);
e820.nr_map = 0;
+ xen_extra_mem_start = mem_end;
+ for (i = 0; i < memmap.nr_entries; i++) {
+ unsigned long long end = map[i].addr + map[i].size;
+
+ if (map[i].type == E820_RAM) {
+ if (map[i].addr < mem_end && end > mem_end) {
+ /* Truncate region to max_mem. */
+ u64 delta = end - mem_end;
+
+ map[i].size -= delta;
+ extra_pages += PFN_DOWN(delta);
+
+ end = mem_end;
+ }
+ }
- e820_add_region(0, PFN_PHYS((u64)max_pfn), E820_RAM);
+ if (end > xen_extra_mem_start)
+ xen_extra_mem_start = end;
+
+ /* If region is non-RAM or below mem_end, add what remains */
+ if ((map[i].type != E820_RAM || map[i].addr < mem_end) &&
+ map[i].size > 0)
+ e820_add_region(map[i].addr, map[i].size, map[i].type);
+ }
/*
* Even though this is normal, usable memory under Xen, reserve
@@ -136,7 +220,29 @@ char * __init xen_memory_setup(void)
sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
- xen_return_unused_memory(xen_start_info->nr_pages, &e820);
+ 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;
+
+ if (!xen_initial_domain())
+ xen_add_extra_mem(extra_pages);
return "Xen";
}
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index 25f232b18a82..f4d010031465 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -400,9 +400,9 @@ static void stop_self(void *v)
BUG();
}
-static void xen_smp_send_stop(void)
+static void xen_stop_other_cpus(int wait)
{
- smp_call_function(stop_self, NULL, 0);
+ smp_call_function(stop_self, NULL, wait);
}
static void xen_smp_send_reschedule(int cpu)
@@ -470,7 +470,7 @@ static const struct smp_ops xen_smp_ops __initdata = {
.cpu_disable = xen_cpu_disable,
.play_dead = xen_play_dead,
- .smp_send_stop = xen_smp_send_stop,
+ .stop_other_cpus = xen_stop_other_cpus,
.smp_send_reschedule = xen_smp_send_reschedule,
.send_call_func_ipi = xen_smp_send_call_function_ipi,
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index 7c8ab86163e9..64044747348e 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -30,6 +30,9 @@ void xen_setup_machphys_mapping(void);
pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn);
void xen_ident_map_ISA(void);
void xen_reserve_top(void);
+extern unsigned long xen_max_p2m_pfn;
+
+void xen_set_pat(u64);
char * __init xen_memory_setup(void);
void __init xen_arch_setup(void);
diff --git a/arch/xtensa/include/asm/pgtable.h b/arch/xtensa/include/asm/pgtable.h
index 76bf35554117..b03c043ce75b 100644
--- a/arch/xtensa/include/asm/pgtable.h
+++ b/arch/xtensa/include/asm/pgtable.h
@@ -324,10 +324,7 @@ ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
#define pte_offset_kernel(dir,addr) \
((pte_t*) pmd_page_vaddr(*(dir)) + pte_index(addr))
#define pte_offset_map(dir,addr) pte_offset_kernel((dir),(addr))
-#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir),(addr))
-
#define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
/*
diff --git a/arch/xtensa/include/asm/uaccess.h b/arch/xtensa/include/asm/uaccess.h
index b8528426ab1f..5b0c18c1cce1 100644
--- a/arch/xtensa/include/asm/uaccess.h
+++ b/arch/xtensa/include/asm/uaccess.h
@@ -4,7 +4,7 @@
* User space memory access functions
*
* These routines provide basic accessing functions to the user memory
- * space for the kernel. This header file provides fuctions such as:
+ * space for the kernel. This header file provides functions such as:
*
* 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
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
index 9d4e1ceb3f09..c72c9473ef99 100644
--- a/arch/xtensa/kernel/ptrace.c
+++ b/arch/xtensa/kernel/ptrace.c
@@ -256,9 +256,11 @@ int ptrace_pokeusr(struct task_struct *child, long regno, long val)
return 0;
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret = -EPERM;
+ void __user *datap = (void __user *) data;
switch (request) {
case PTRACE_PEEKTEXT: /* read word at location addr. */
@@ -267,7 +269,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
case PTRACE_PEEKUSR: /* read register specified by addr. */
- ret = ptrace_peekusr(child, addr, (void __user *) data);
+ ret = ptrace_peekusr(child, addr, datap);
break;
case PTRACE_POKETEXT: /* write the word at location addr. */
@@ -280,19 +282,19 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
case PTRACE_GETREGS:
- ret = ptrace_getregs(child, (void __user *) data);
+ ret = ptrace_getregs(child, datap);
break;
case PTRACE_SETREGS:
- ret = ptrace_setregs(child, (void __user *) data);
+ ret = ptrace_setregs(child, datap);
break;
case PTRACE_GETXTREGS:
- ret = ptrace_getxregs(child, (void __user *) data);
+ ret = ptrace_getxregs(child, datap);
break;
case PTRACE_SETXTREGS:
- ret = ptrace_setxregs(child, (void __user *) data);
+ ret = ptrace_setxregs(child, datap);
break;
default:
diff --git a/block/blk-core.c b/block/blk-core.c
index 45141469e89e..f0834e2f5727 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -64,15 +64,13 @@ static void drive_stat_acct(struct request *rq, int new_io)
return;
cpu = part_stat_lock();
+ part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq));
- if (!new_io) {
- part = rq->part;
+ if (!new_io)
part_stat_inc(cpu, part, merges[rw]);
- } else {
- part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq));
+ else {
part_round_stats(cpu, part);
part_inc_in_flight(part, rw);
- rq->part = part;
}
part_stat_unlock();
@@ -130,7 +128,6 @@ void blk_rq_init(struct request_queue *q, struct request *rq)
rq->ref_count = 1;
rq->start_time = jiffies;
set_start_time_ns(rq);
- rq->part = NULL;
}
EXPORT_SYMBOL(blk_rq_init);
@@ -462,8 +459,6 @@ void blk_cleanup_queue(struct request_queue *q)
if (q->elevator)
elevator_exit(q->elevator);
- blk_throtl_exit(q);
-
blk_put_queue(q);
}
EXPORT_SYMBOL(blk_cleanup_queue);
@@ -807,16 +802,11 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
rl->starved[is_sync] = 0;
priv = !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
- if (priv) {
+ if (priv)
rl->elvpriv++;
- /*
- * Don't do stats for non-priv requests
- */
- if (blk_queue_io_stat(q))
- rw_flags |= REQ_IO_STAT;
- }
-
+ if (blk_queue_io_stat(q))
+ rw_flags |= REQ_IO_STAT;
spin_unlock_irq(q->queue_lock);
rq = blk_alloc_request(q, rw_flags, priv, gfp_mask);
@@ -1671,7 +1661,7 @@ EXPORT_SYMBOL(submit_bio);
* the insertion using this generic function.
*
* This function should also be useful for request stacking drivers
- * in some cases below, so export this fuction.
+ * in some cases below, so export this function.
* Request stacking drivers like request-based dm may change the queue
* limits while requests are in the queue (e.g. dm's table swapping).
* Such request stacking drivers should check those requests agaist
@@ -1793,7 +1783,7 @@ static void blk_account_io_completion(struct request *req, unsigned int bytes)
int cpu;
cpu = part_stat_lock();
- part = req->part;
+ part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
part_stat_add(cpu, part, sectors[rw], bytes >> 9);
part_stat_unlock();
}
@@ -1813,7 +1803,7 @@ static void blk_account_io_done(struct request *req)
int cpu;
cpu = part_stat_lock();
- part = req->part;
+ part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
part_stat_inc(cpu, part, ios[rw]);
part_stat_add(cpu, part, ticks[rw], duration);
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 0a2fd8a48a38..77b7c26df6b5 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -351,7 +351,7 @@ static void blk_account_io_merge(struct request *req)
int cpu;
cpu = part_stat_lock();
- part = req->part;
+ part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
part_round_stats(cpu, part);
part_dec_in_flight(part, rq_data_dir(req));
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index da8a8a40cd4c..013457f47fdc 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -471,6 +471,8 @@ static void blk_release_queue(struct kobject *kobj)
blk_sync_queue(q);
+ blk_throtl_exit(q);
+
if (rl->rq_pool)
mempool_destroy(rl->rq_pool);
diff --git a/block/blk.h b/block/blk.h
index 1e675e5ade02..2db8f32838e7 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -116,6 +116,10 @@ void blk_queue_congestion_threshold(struct request_queue *q);
int blk_dev_init(void);
+void elv_quiesce_start(struct request_queue *q);
+void elv_quiesce_end(struct request_queue *q);
+
+
/*
* Return the threshold (number of used requests) at which the queue is
* considered to be congested. It include a little hysteresis to keep the
diff --git a/block/genhd.c b/block/genhd.c
index a8adf96a4b41..5fa2b44a72ff 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -929,15 +929,8 @@ static void disk_free_ptbl_rcu_cb(struct rcu_head *head)
{
struct disk_part_tbl *ptbl =
container_of(head, struct disk_part_tbl, rcu_head);
- struct gendisk *disk = ptbl->disk;
- struct request_queue *q = disk->queue;
- unsigned long flags;
kfree(ptbl);
-
- spin_lock_irqsave(q->queue_lock, flags);
- elv_quiesce_end(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
}
/**
@@ -955,17 +948,11 @@ static void disk_replace_part_tbl(struct gendisk *disk,
struct disk_part_tbl *new_ptbl)
{
struct disk_part_tbl *old_ptbl = disk->part_tbl;
- struct request_queue *q = disk->queue;
rcu_assign_pointer(disk->part_tbl, new_ptbl);
if (old_ptbl) {
rcu_assign_pointer(old_ptbl->last_lookup, NULL);
-
- spin_lock_irq(q->queue_lock);
- elv_quiesce_start(q);
- spin_unlock_irq(q->queue_lock);
-
call_rcu(&old_ptbl->rcu_head, disk_free_ptbl_rcu_cb);
}
}
@@ -1006,7 +993,6 @@ int disk_expand_part_tbl(struct gendisk *disk, int partno)
return -ENOMEM;
new_ptbl->len = target;
- new_ptbl->disk = disk;
for (i = 0; i < len; i++)
rcu_assign_pointer(new_ptbl->part[i], old_ptbl->part[i]);
diff --git a/crypto/Kconfig b/crypto/Kconfig
index e573077f1672..e4bac29a32e7 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -23,13 +23,12 @@ comment "Crypto core or helper"
config CRYPTO_FIPS
bool "FIPS 200 compliance"
- depends on CRYPTO_ANSI_CPRNG
+ depends on CRYPTO_ANSI_CPRNG && !CRYPTO_MANAGER_DISABLE_TESTS
help
This options enables the fips boot option which is
required if you want to system to operate in a FIPS 200
certification. You should say no unless you know what
- this is. Note that CRYPTO_ANSI_CPRNG is required if this
- option is selected
+ this is.
config CRYPTO_ALGAPI
tristate
@@ -365,7 +364,7 @@ config CRYPTO_RMD128
RIPEMD-160 should be used.
Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
- See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+ See <http://homes.esat.kuleuven.be/~bosselae/ripemd160.html>
config CRYPTO_RMD160
tristate "RIPEMD-160 digest algorithm"
@@ -382,7 +381,7 @@ config CRYPTO_RMD160
against RIPEMD-160.
Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
- See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+ See <http://homes.esat.kuleuven.be/~bosselae/ripemd160.html>
config CRYPTO_RMD256
tristate "RIPEMD-256 digest algorithm"
@@ -394,7 +393,7 @@ config CRYPTO_RMD256
(than RIPEMD-128).
Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
- See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+ See <http://homes.esat.kuleuven.be/~bosselae/ripemd160.html>
config CRYPTO_RMD320
tristate "RIPEMD-320 digest algorithm"
@@ -406,7 +405,7 @@ config CRYPTO_RMD320
(than RIPEMD-160).
Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
- See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+ See <http://homes.esat.kuleuven.be/~bosselae/ripemd160.html>
config CRYPTO_SHA1
tristate "SHA1 digest algorithm"
@@ -461,7 +460,7 @@ config CRYPTO_WP512
Whirlpool will be part of the ISO/IEC 10118-3:2003(E) standard
See also:
- <http://planeta.terra.com.br/informatica/paulobarreto/WhirlpoolPage.html>
+ <http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html>
config CRYPTO_GHASH_CLMUL_NI_INTEL
tristate "GHASH digest algorithm (CLMUL-NI accelerated)"
@@ -579,8 +578,8 @@ config CRYPTO_ANUBIS
in the NESSIE competition.
See also:
- <https://www.cosic.esat.kuleuven.ac.be/nessie/reports/>
- <http://planeta.terra.com.br/informatica/paulobarreto/AnubisPage.html>
+ <https://www.cosic.esat.kuleuven.be/nessie/reports/>
+ <http://www.larc.usp.br/~pbarreto/AnubisPage.html>
config CRYPTO_ARC4
tristate "ARC4 cipher algorithm"
@@ -659,7 +658,7 @@ config CRYPTO_KHAZAD
on 32-bit processors. Khazad uses an 128 bit key size.
See also:
- <http://planeta.terra.com.br/informatica/paulobarreto/KhazadPage.html>
+ <http://www.larc.usp.br/~pbarreto/KhazadPage.html>
config CRYPTO_SALSA20
tristate "Salsa20 stream cipher algorithm (EXPERIMENTAL)"
diff --git a/crypto/async_tx/Kconfig b/crypto/async_tx/Kconfig
index 5de2ed13b35d..1b11abbb5c91 100644
--- a/crypto/async_tx/Kconfig
+++ b/crypto/async_tx/Kconfig
@@ -24,19 +24,6 @@ config ASYNC_RAID6_RECOV
select ASYNC_PQ
select ASYNC_XOR
-config ASYNC_RAID6_TEST
- tristate "Self test for hardware accelerated raid6 recovery"
- depends on ASYNC_RAID6_RECOV
- select ASYNC_MEMCPY
- ---help---
- This is a one-shot self test that permutes through the
- recovery of all the possible two disk failure scenarios for a
- N-disk array. Recovery is performed with the asynchronous
- raid6 recovery routines, and will optionally use an offload
- engine if one is available.
-
- If unsure, say N.
-
config ASYNC_TX_DISABLE_PQ_VAL_DMA
bool
diff --git a/crypto/async_tx/async_memcpy.c b/crypto/async_tx/async_memcpy.c
index 0ec1fb69d4ea..518c22bd9562 100644
--- a/crypto/async_tx/async_memcpy.c
+++ b/crypto/async_tx/async_memcpy.c
@@ -83,8 +83,8 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
memcpy(dest_buf, src_buf, len);
- kunmap_atomic(dest_buf, KM_USER0);
kunmap_atomic(src_buf, KM_USER1);
+ kunmap_atomic(dest_buf, KM_USER0);
async_tx_sync_epilog(submit);
}
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
index 90d26c91f4e9..7a7219266e3c 100644
--- a/crypto/blkcipher.c
+++ b/crypto/blkcipher.c
@@ -89,9 +89,9 @@ static inline unsigned int blkcipher_done_fast(struct blkcipher_walk *walk,
memcpy(walk->dst.virt.addr, walk->page, n);
blkcipher_unmap_dst(walk);
} else if (!(walk->flags & BLKCIPHER_WALK_PHYS)) {
- blkcipher_unmap_src(walk);
if (walk->flags & BLKCIPHER_WALK_DIFF)
blkcipher_unmap_dst(walk);
+ blkcipher_unmap_src(walk);
}
scatterwalk_advance(&walk->in, n);
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index ef71318976c7..e46d21ae26bc 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -3,6 +3,13 @@
*
* Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
*
+ * Added AEAD support to cryptd.
+ * Authors: Tadeusz Struk (tadeusz.struk@intel.com)
+ * Adrian Hoban <adrian.hoban@intel.com>
+ * Gabriele Paoloni <gabriele.paoloni@intel.com>
+ * Aidan O'Mahony (aidan.o.mahony@intel.com)
+ * Copyright (c) 2010, Intel 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)
@@ -12,6 +19,7 @@
#include <crypto/algapi.h>
#include <crypto/internal/hash.h>
+#include <crypto/internal/aead.h>
#include <crypto/cryptd.h>
#include <crypto/crypto_wq.h>
#include <linux/err.h>
@@ -44,6 +52,11 @@ struct hashd_instance_ctx {
struct cryptd_queue *queue;
};
+struct aead_instance_ctx {
+ struct crypto_aead_spawn aead_spawn;
+ struct cryptd_queue *queue;
+};
+
struct cryptd_blkcipher_ctx {
struct crypto_blkcipher *child;
};
@@ -61,6 +74,14 @@ struct cryptd_hash_request_ctx {
struct shash_desc desc;
};
+struct cryptd_aead_ctx {
+ struct crypto_aead *child;
+};
+
+struct cryptd_aead_request_ctx {
+ crypto_completion_t complete;
+};
+
static void cryptd_queue_worker(struct work_struct *work);
static int cryptd_init_queue(struct cryptd_queue *queue,
@@ -601,6 +622,144 @@ out_put_alg:
return err;
}
+static void cryptd_aead_crypt(struct aead_request *req,
+ struct crypto_aead *child,
+ int err,
+ int (*crypt)(struct aead_request *req))
+{
+ struct cryptd_aead_request_ctx *rctx;
+ rctx = aead_request_ctx(req);
+
+ if (unlikely(err == -EINPROGRESS))
+ goto out;
+ aead_request_set_tfm(req, child);
+ err = crypt( req );
+ req->base.complete = rctx->complete;
+out:
+ local_bh_disable();
+ rctx->complete(&req->base, err);
+ local_bh_enable();
+}
+
+static void cryptd_aead_encrypt(struct crypto_async_request *areq, int err)
+{
+ struct cryptd_aead_ctx *ctx = crypto_tfm_ctx(areq->tfm);
+ struct crypto_aead *child = ctx->child;
+ struct aead_request *req;
+
+ req = container_of(areq, struct aead_request, base);
+ cryptd_aead_crypt(req, child, err, crypto_aead_crt(child)->encrypt);
+}
+
+static void cryptd_aead_decrypt(struct crypto_async_request *areq, int err)
+{
+ struct cryptd_aead_ctx *ctx = crypto_tfm_ctx(areq->tfm);
+ struct crypto_aead *child = ctx->child;
+ struct aead_request *req;
+
+ req = container_of(areq, struct aead_request, base);
+ cryptd_aead_crypt(req, child, err, crypto_aead_crt(child)->decrypt);
+}
+
+static int cryptd_aead_enqueue(struct aead_request *req,
+ crypto_completion_t complete)
+{
+ struct cryptd_aead_request_ctx *rctx = aead_request_ctx(req);
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct cryptd_queue *queue = cryptd_get_queue(crypto_aead_tfm(tfm));
+
+ rctx->complete = req->base.complete;
+ req->base.complete = complete;
+ return cryptd_enqueue_request(queue, &req->base);
+}
+
+static int cryptd_aead_encrypt_enqueue(struct aead_request *req)
+{
+ return cryptd_aead_enqueue(req, cryptd_aead_encrypt );
+}
+
+static int cryptd_aead_decrypt_enqueue(struct aead_request *req)
+{
+ return cryptd_aead_enqueue(req, cryptd_aead_decrypt );
+}
+
+static int cryptd_aead_init_tfm(struct crypto_tfm *tfm)
+{
+ struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
+ struct aead_instance_ctx *ictx = crypto_instance_ctx(inst);
+ struct crypto_aead_spawn *spawn = &ictx->aead_spawn;
+ struct cryptd_aead_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_aead *cipher;
+
+ cipher = crypto_spawn_aead(spawn);
+ if (IS_ERR(cipher))
+ return PTR_ERR(cipher);
+
+ crypto_aead_set_flags(cipher, CRYPTO_TFM_REQ_MAY_SLEEP);
+ ctx->child = cipher;
+ tfm->crt_aead.reqsize = sizeof(struct cryptd_aead_request_ctx);
+ return 0;
+}
+
+static void cryptd_aead_exit_tfm(struct crypto_tfm *tfm)
+{
+ struct cryptd_aead_ctx *ctx = crypto_tfm_ctx(tfm);
+ crypto_free_aead(ctx->child);
+}
+
+static int cryptd_create_aead(struct crypto_template *tmpl,
+ struct rtattr **tb,
+ struct cryptd_queue *queue)
+{
+ struct aead_instance_ctx *ctx;
+ struct crypto_instance *inst;
+ struct crypto_alg *alg;
+ int err;
+
+ alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_AEAD,
+ CRYPTO_ALG_TYPE_MASK);
+ if (IS_ERR(alg))
+ return PTR_ERR(alg);
+
+ inst = cryptd_alloc_instance(alg, 0, sizeof(*ctx));
+ err = PTR_ERR(inst);
+ if (IS_ERR(inst))
+ goto out_put_alg;
+
+ ctx = crypto_instance_ctx(inst);
+ ctx->queue = queue;
+
+ err = crypto_init_spawn(&ctx->aead_spawn.base, alg, inst,
+ CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+ if (err)
+ goto out_free_inst;
+
+ inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC;
+ inst->alg.cra_type = alg->cra_type;
+ inst->alg.cra_ctxsize = sizeof(struct cryptd_aead_ctx);
+ inst->alg.cra_init = cryptd_aead_init_tfm;
+ inst->alg.cra_exit = cryptd_aead_exit_tfm;
+ inst->alg.cra_aead.setkey = alg->cra_aead.setkey;
+ inst->alg.cra_aead.setauthsize = alg->cra_aead.setauthsize;
+ inst->alg.cra_aead.geniv = alg->cra_aead.geniv;
+ inst->alg.cra_aead.ivsize = alg->cra_aead.ivsize;
+ inst->alg.cra_aead.maxauthsize = alg->cra_aead.maxauthsize;
+ inst->alg.cra_aead.encrypt = cryptd_aead_encrypt_enqueue;
+ inst->alg.cra_aead.decrypt = cryptd_aead_decrypt_enqueue;
+ inst->alg.cra_aead.givencrypt = alg->cra_aead.givencrypt;
+ inst->alg.cra_aead.givdecrypt = alg->cra_aead.givdecrypt;
+
+ err = crypto_register_instance(tmpl, inst);
+ if (err) {
+ crypto_drop_spawn(&ctx->aead_spawn.base);
+out_free_inst:
+ kfree(inst);
+ }
+out_put_alg:
+ crypto_mod_put(alg);
+ return err;
+}
+
static struct cryptd_queue queue;
static int cryptd_create(struct crypto_template *tmpl, struct rtattr **tb)
@@ -616,6 +775,8 @@ static int cryptd_create(struct crypto_template *tmpl, struct rtattr **tb)
return cryptd_create_blkcipher(tmpl, tb, &queue);
case CRYPTO_ALG_TYPE_DIGEST:
return cryptd_create_hash(tmpl, tb, &queue);
+ case CRYPTO_ALG_TYPE_AEAD:
+ return cryptd_create_aead(tmpl, tb, &queue);
}
return -EINVAL;
@@ -625,16 +786,21 @@ static void cryptd_free(struct crypto_instance *inst)
{
struct cryptd_instance_ctx *ctx = crypto_instance_ctx(inst);
struct hashd_instance_ctx *hctx = crypto_instance_ctx(inst);
+ struct aead_instance_ctx *aead_ctx = crypto_instance_ctx(inst);
switch (inst->alg.cra_flags & CRYPTO_ALG_TYPE_MASK) {
case CRYPTO_ALG_TYPE_AHASH:
crypto_drop_shash(&hctx->spawn);
kfree(ahash_instance(inst));
return;
+ case CRYPTO_ALG_TYPE_AEAD:
+ crypto_drop_spawn(&aead_ctx->aead_spawn.base);
+ kfree(inst);
+ return;
+ default:
+ crypto_drop_spawn(&ctx->spawn);
+ kfree(inst);
}
-
- crypto_drop_spawn(&ctx->spawn);
- kfree(inst);
}
static struct crypto_template cryptd_tmpl = {
@@ -724,6 +890,40 @@ void cryptd_free_ahash(struct cryptd_ahash *tfm)
}
EXPORT_SYMBOL_GPL(cryptd_free_ahash);
+struct cryptd_aead *cryptd_alloc_aead(const char *alg_name,
+ u32 type, u32 mask)
+{
+ char cryptd_alg_name[CRYPTO_MAX_ALG_NAME];
+ struct crypto_aead *tfm;
+
+ if (snprintf(cryptd_alg_name, CRYPTO_MAX_ALG_NAME,
+ "cryptd(%s)", alg_name) >= CRYPTO_MAX_ALG_NAME)
+ return ERR_PTR(-EINVAL);
+ tfm = crypto_alloc_aead(cryptd_alg_name, type, mask);
+ if (IS_ERR(tfm))
+ return ERR_CAST(tfm);
+ if (tfm->base.__crt_alg->cra_module != THIS_MODULE) {
+ crypto_free_aead(tfm);
+ return ERR_PTR(-EINVAL);
+ }
+ return __cryptd_aead_cast(tfm);
+}
+EXPORT_SYMBOL_GPL(cryptd_alloc_aead);
+
+struct crypto_aead *cryptd_aead_child(struct cryptd_aead *tfm)
+{
+ struct cryptd_aead_ctx *ctx;
+ ctx = crypto_aead_ctx(&tfm->base);
+ return ctx->child;
+}
+EXPORT_SYMBOL_GPL(cryptd_aead_child);
+
+void cryptd_free_aead(struct cryptd_aead *tfm)
+{
+ crypto_free_aead(&tfm->base);
+}
+EXPORT_SYMBOL_GPL(cryptd_free_aead);
+
static int __init cryptd_init(void)
{
int err;
diff --git a/drivers/Makefile b/drivers/Makefile
index a2aea53a75ed..14cf9077bb2b 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -51,7 +51,6 @@ obj-y += net/
obj-$(CONFIG_ATM) += atm/
obj-$(CONFIG_FUSION) += message/
obj-y += firewire/
-obj-y += ieee1394/
obj-$(CONFIG_UIO) += uio/
obj-y += cdrom/
obj-y += auxdisplay/
@@ -92,6 +91,7 @@ obj-$(CONFIG_EISA) += eisa/
obj-y += lguest/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_CPU_IDLE) += cpuidle/
+obj-$(CONFIG_DMA_ENGINE) += dma/
obj-$(CONFIG_MMC) += mmc/
obj-$(CONFIG_MEMSTICK) += memstick/
obj-$(CONFIG_NEW_LEDS) += leds/
@@ -104,7 +104,6 @@ obj-$(CONFIG_ARCH_SHMOBILE) += sh/
ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
obj-y += clocksource/
endif
-obj-$(CONFIG_DMA_ENGINE) += dma/
obj-$(CONFIG_DCA) += dca/
obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 88681aca88c5..3f3489c5ca8c 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -9,7 +9,6 @@ menuconfig ACPI
depends on PCI
depends on PM
select PNP
- select CPU_IDLE
default y
help
Advanced Configuration and Power Interface (ACPI) support for
@@ -66,7 +65,6 @@ config ACPI_PROCFS
config ACPI_PROCFS_POWER
bool "Deprecated power /proc/acpi directories"
depends on PROC_FS
- default y
help
For backwards compatibility, this option allows
deprecated power /proc/acpi/ directories to exist, even when
@@ -90,13 +88,6 @@ config ACPI_POWER_METER
To compile this driver as a module, choose M here:
the module will be called power-meter.
-config ACPI_SYSFS_POWER
- bool "Future power /sys interface"
- select POWER_SUPPLY
- default y
- help
- Say N to disable power /sys interface
-
config ACPI_EC_DEBUGFS
tristate "EC read/write access through /sys/kernel/debug/ec"
default n
@@ -136,6 +127,7 @@ config ACPI_PROC_EVENT
config ACPI_AC
tristate "AC Adapter"
depends on X86
+ select POWER_SUPPLY
default y
help
This driver supports the AC Adapter object, which indicates
@@ -148,6 +140,7 @@ config ACPI_AC
config ACPI_BATTERY
tristate "Battery"
depends on X86
+ select POWER_SUPPLY
default y
help
This driver adds support for battery information through
@@ -206,6 +199,7 @@ config ACPI_DOCK
config ACPI_PROCESSOR
tristate "Processor"
select THERMAL
+ select CPU_IDLE
default y
help
This driver installs ACPI as the idle handler for Linux and uses
@@ -364,6 +358,7 @@ config ACPI_HOTPLUG_MEMORY
config ACPI_SBS
tristate "Smart Battery System"
depends on X86
+ select POWER_SUPPLY
help
This driver supports the Smart Battery System, another
type of access to battery information, found on some laptops.
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 56205a0b85df..ba9afeaa23ac 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -32,9 +32,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
#include <linux/power_supply.h>
-#endif
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -86,9 +84,7 @@ static struct acpi_driver acpi_ac_driver = {
};
struct acpi_ac {
-#ifdef CONFIG_ACPI_SYSFS_POWER
struct power_supply charger;
-#endif
struct acpi_device * device;
unsigned long long state;
};
@@ -104,7 +100,6 @@ static const struct file_operations acpi_ac_fops = {
.release = single_release,
};
#endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
static int get_ac_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -123,7 +118,6 @@ static int get_ac_property(struct power_supply *psy,
static enum power_supply_property ac_props[] = {
POWER_SUPPLY_PROP_ONLINE,
};
-#endif
/* --------------------------------------------------------------------------
AC Adapter Management
-------------------------------------------------------------------------- */
@@ -247,9 +241,7 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event)
dev_name(&device->dev), event,
(u32) ac->state);
acpi_notifier_call_chain(device, event, (u32) ac->state);
-#ifdef CONFIG_ACPI_SYSFS_POWER
kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
-#endif
}
return;
@@ -282,14 +274,12 @@ static int acpi_ac_add(struct acpi_device *device)
#endif
if (result)
goto end;
-#ifdef CONFIG_ACPI_SYSFS_POWER
ac->charger.name = acpi_device_bid(device);
ac->charger.type = POWER_SUPPLY_TYPE_MAINS;
ac->charger.properties = ac_props;
ac->charger.num_properties = ARRAY_SIZE(ac_props);
ac->charger.get_property = get_ac_property;
power_supply_register(&ac->device->dev, &ac->charger);
-#endif
printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
acpi_device_name(device), acpi_device_bid(device),
@@ -316,10 +306,8 @@ static int acpi_ac_resume(struct acpi_device *device)
old_state = ac->state;
if (acpi_ac_get_state(ac))
return 0;
-#ifdef CONFIG_ACPI_SYSFS_POWER
if (old_state != ac->state)
kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
-#endif
return 0;
}
@@ -333,10 +321,8 @@ static int acpi_ac_remove(struct acpi_device *device, int type)
ac = acpi_driver_data(device);
-#ifdef CONFIG_ACPI_SYSFS_POWER
if (ac->charger.dev)
power_supply_unregister(&ac->charger);
-#endif
#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_ac_remove_fs(device);
#endif
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index d93cc06f4bf8..a7e1d1aa4107 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -21,7 +21,7 @@ acpi-y += exconfig.o exfield.o exnames.o exoparg6.o exresolv.o exstorob.o\
excreate.o exmisc.o exoparg2.o exregion.o exstore.o exutils.o \
exdump.o exmutex.o exoparg3.o exresnte.o exstoren.o exdebug.o
-acpi-y += hwacpi.o hwgpe.o hwregs.o hwsleep.o hwxface.o hwvalid.o
+acpi-y += hwacpi.o hwgpe.o hwregs.o hwsleep.o hwxface.o hwvalid.o hwpci.o
acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o
@@ -44,4 +44,5 @@ acpi-y += tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o
acpi-y += utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \
utcopy.o utdelete.o utglobal.o utmath.o utobject.o \
- utstate.o utmutex.o utobject.o utresrc.o utlock.o utids.o
+ utstate.o utmutex.o utobject.o utresrc.o utlock.o utids.o \
+ utosi.o utxferror.o
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 48faf3eba9fb..72e9d5eb083c 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -105,6 +105,8 @@ void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg);
acpi_status
acpi_db_display_objects(char *obj_type_arg, char *display_count_arg);
+void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg);
+
acpi_status acpi_db_find_name_in_namespace(char *name_arg);
void acpi_db_set_scope(char *name);
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index 36867cd70eac..a6f99cc37a19 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -105,8 +105,9 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
struct acpi_gpe_block_info **return_gpe_block);
acpi_status
-acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
- struct acpi_gpe_block_info *gpe_block);
+acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block,
+ void *ignored);
acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 1d192142c691..ad88fcae4eb9 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -132,6 +132,7 @@ struct acpi_table_fadt acpi_gbl_FADT;
u32 acpi_current_gpe_count;
u32 acpi_gbl_trace_flags;
acpi_name acpi_gbl_trace_method_name;
+u8 acpi_gbl_system_awake_and_running;
#endif
@@ -187,6 +188,10 @@ ACPI_EXTERN u8 acpi_gbl_integer_bit_width;
ACPI_EXTERN u8 acpi_gbl_integer_byte_width;
ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
+/* Mutex for _OSI support */
+
+ACPI_EXTERN acpi_mutex acpi_gbl_osi_mutex;
+
/* Reader/Writer lock is used for namespace walk and dynamic table unload */
ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock;
@@ -255,6 +260,7 @@ ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler;
ACPI_EXTERN void *acpi_gbl_table_handler_context;
ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk;
+ACPI_EXTERN acpi_interface_handler acpi_gbl_interface_handler;
/* Owner ID support */
@@ -273,8 +279,8 @@ ACPI_EXTERN u8 acpi_gbl_debugger_configuration;
ACPI_EXTERN u8 acpi_gbl_step_to_next_call;
ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present;
ACPI_EXTERN u8 acpi_gbl_events_initialized;
-ACPI_EXTERN u8 acpi_gbl_system_awake_and_running;
ACPI_EXTERN u8 acpi_gbl_osi_data;
+ACPI_EXTERN struct acpi_interface_info *acpi_gbl_supported_interfaces;
#ifndef DEFINE_ACPI_GLOBALS
@@ -364,6 +370,7 @@ ACPI_EXTERN struct acpi_fixed_event_handler
ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
ACPI_EXTERN struct acpi_gpe_block_info
*acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
+ACPI_EXTERN u8 acpi_all_gpes_initialized;
/*****************************************************************************
*
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
index 120b3af56596..167470ad2d21 100644
--- a/drivers/acpi/acpica/achware.h
+++ b/drivers/acpi/acpica/achware.h
@@ -121,6 +121,13 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block,
void *context);
+/*
+ * hwpci - PCI configuration support
+ */
+acpi_status
+acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
+ acpi_handle root_pci_device, acpi_handle pci_region);
+
#ifdef ACPI_FUTURE_USAGE
/*
* hwtimer - ACPI Timer prototypes
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 7dad9160f209..2ceb0c05b2d7 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -413,6 +413,7 @@ struct acpi_handler_info {
void *context; /* Context to be passed to handler */
struct acpi_namespace_node *method_node; /* Method node for this GPE level (saved) */
u8 orig_flags; /* Original misc info about this GPE */
+ u8 orig_enabled; /* Set if the GPE was originally enabled */
};
union acpi_gpe_dispatch_info {
@@ -457,6 +458,7 @@ struct acpi_gpe_block_info {
u32 register_count; /* Number of register pairs in block */
u16 gpe_count; /* Number of individual GPEs in block */
u8 block_base_number; /* Base GPE number for this block */
+ u8 initialized; /* If set, the GPE block has been initialized */
};
/* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */
@@ -473,7 +475,6 @@ struct acpi_gpe_walk_info {
struct acpi_gpe_block_info *gpe_block;
u16 count;
acpi_owner_id owner_id;
- u8 enable_this_gpe;
u8 execute_by_owner_id;
};
@@ -854,7 +855,7 @@ struct acpi_bit_register_info {
ACPI_BITMASK_POWER_BUTTON_STATUS | \
ACPI_BITMASK_SLEEP_BUTTON_STATUS | \
ACPI_BITMASK_RT_CLOCK_STATUS | \
- ACPI_BITMASK_PCIEXP_WAKE_DISABLE | \
+ ACPI_BITMASK_PCIEXP_WAKE_STATUS | \
ACPI_BITMASK_WAKE_STATUS)
#define ACPI_BITMASK_TIMER_ENABLE 0x0001
@@ -909,15 +910,21 @@ struct acpi_bit_register_info {
#define ACPI_OSI_WIN_VISTA 0x07
#define ACPI_OSI_WINSRV_2008 0x08
#define ACPI_OSI_WIN_VISTA_SP1 0x09
-#define ACPI_OSI_WIN_7 0x0A
+#define ACPI_OSI_WIN_VISTA_SP2 0x0A
+#define ACPI_OSI_WIN_7 0x0B
#define ACPI_ALWAYS_ILLEGAL 0x00
struct acpi_interface_info {
char *name;
+ struct acpi_interface_info *next;
+ u8 flags;
u8 value;
};
+#define ACPI_OSI_INVALID 0x01
+#define ACPI_OSI_DYNAMIC 0x02
+
struct acpi_port_info {
char *name;
u16 start;
@@ -997,7 +1004,7 @@ struct acpi_port_info {
struct acpi_db_method_info {
acpi_handle main_thread_gate;
acpi_handle thread_complete_gate;
- u32 *threads;
+ acpi_thread_id *threads;
u32 num_threads;
u32 num_created;
u32 num_completed;
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index 9894929a2abb..8d5c9e0a495f 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -338,8 +338,8 @@
* the plist contains a set of parens to allow variable-length lists.
* These macros are used for both the debug and non-debug versions of the code.
*/
-#define ACPI_ERROR_NAMESPACE(s, e) acpi_ns_report_error (AE_INFO, s, e);
-#define ACPI_ERROR_METHOD(s, n, p, e) acpi_ns_report_method_error (AE_INFO, s, n, p, e);
+#define ACPI_ERROR_NAMESPACE(s, e) acpi_ut_namespace_error (AE_INFO, s, e);
+#define ACPI_ERROR_METHOD(s, n, p, e) acpi_ut_method_error (AE_INFO, s, n, p, e);
#define ACPI_WARN_PREDEFINED(plist) acpi_ut_predefined_warning plist
#define ACPI_INFO_PREDEFINED(plist) acpi_ut_predefined_info plist
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index 9f60ff002203..d44d3bc5b847 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -339,18 +339,6 @@ acpi_object_type acpi_ns_get_type(struct acpi_namespace_node *node);
u32 acpi_ns_local(acpi_object_type type);
void
-acpi_ns_report_error(const char *module_name,
- u32 line_number,
- const char *internal_name, acpi_status lookup_status);
-
-void
-acpi_ns_report_method_error(const char *module_name,
- u32 line_number,
- const char *message,
- struct acpi_namespace_node *node,
- const char *path, acpi_status lookup_status);
-
-void
acpi_ns_print_node_pathname(struct acpi_namespace_node *node, const char *msg);
acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info);
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index 54857fa87aaf..bdbfaf22bd14 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -248,7 +248,7 @@ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO};
u32 base_byte_offset; /* Byte offset within containing object */\
u32 value; /* Value to store into the Bank or Index register */\
u8 start_field_bit_offset;/* Bit offset within first field datum (0-63) */\
- u8 access_bit_width; /* Read/Write size in bits (8-64) */
+
struct acpi_object_field_common { /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Parent Operation Region object (REGION/BANK fields only) */
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index 35df755251ce..72e4183c1937 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -312,8 +312,6 @@ void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list);
/*
* uteval - object evaluation
*/
-acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state);
-
acpi_status
acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
char *path,
@@ -395,6 +393,21 @@ acpi_status
acpi_ut_get_object_size(union acpi_operand_object *obj, acpi_size * obj_length);
/*
+ * utosi - Support for the _OSI predefined control method
+ */
+acpi_status acpi_ut_initialize_interfaces(void);
+
+void acpi_ut_interface_terminate(void);
+
+acpi_status acpi_ut_install_interface(acpi_string interface_name);
+
+acpi_status acpi_ut_remove_interface(acpi_string interface_name);
+
+struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name);
+
+acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state);
+
+/*
* utstate - Generic state creation/cache routines
*/
void
@@ -473,17 +486,6 @@ u8 acpi_ut_valid_acpi_char(char character, u32 position);
acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer);
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_warning(const char *module_name,
- u32 line_number,
- char *pathname,
- u8 node_flags, const char *format, ...);
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_info(const char *module_name,
- u32 line_number,
- char *pathname, u8 node_flags, const char *format, ...);
-
/* Values for Base above (16=Hex, 10=Decimal) */
#define ACPI_ANY_BASE 0
@@ -574,6 +576,32 @@ acpi_status
acpi_ut_create_list(char *list_name,
u16 object_size, struct acpi_memory_list **return_cache);
-#endif
+#endif /* ACPI_DBG_TRACK_ALLOCATIONS */
+
+/*
+ * utxferror - various error/warning output functions
+ */
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_warning(const char *module_name,
+ u32 line_number,
+ char *pathname,
+ u8 node_flags, const char *format, ...);
+
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_info(const char *module_name,
+ u32 line_number,
+ char *pathname, u8 node_flags, const char *format, ...);
+
+void
+acpi_ut_namespace_error(const char *module_name,
+ u32 line_number,
+ const char *internal_name, acpi_status lookup_status);
+
+void
+acpi_ut_method_error(const char *module_name,
+ u32 line_number,
+ const char *message,
+ struct acpi_namespace_node *node,
+ const char *path, acpi_status lookup_status);
#endif /* _ACUTILS_H */
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index 64750ee96e20..d94dd8974b55 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -573,7 +573,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
acpi_os_release_mutex(method_desc->method.
mutex->mutex.os_mutex);
- method_desc->method.mutex->mutex.thread_id = NULL;
+ method_desc->method.mutex->mutex.thread_id = 0;
}
}
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index d555b374e314..6b0b5d08d97a 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -300,10 +300,25 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
* we must enter this object into the namespace. The created
* object is temporary and will be deleted upon completion of
* the execution of this method.
+ *
+ * Note 10/2010: Except for the Scope() op. This opcode does
+ * not actually create a new object, it refers to an existing
+ * object. However, for Scope(), we want to indeed open a
+ * new scope.
*/
- status = acpi_ds_load2_begin_op(walk_state, NULL);
+ if (op->common.aml_opcode != AML_SCOPE_OP) {
+ status =
+ acpi_ds_load2_begin_op(walk_state, NULL);
+ } else {
+ status =
+ acpi_ds_scope_stack_push(op->named.node,
+ op->named.node->
+ type, walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ }
}
-
break;
case AML_CLASS_EXECUTE:
diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c
index 303618889da0..c61c3039c31a 100644
--- a/drivers/acpi/acpica/evevent.c
+++ b/drivers/acpi/acpica/evevent.c
@@ -95,47 +95,6 @@ acpi_status acpi_ev_initialize_events(void)
/*******************************************************************************
*
- * FUNCTION: acpi_ev_install_fadt_gpes
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Completes initialization of the FADT-defined GPE blocks
- * (0 and 1). The HW must be fully initialized at this point,
- * including global lock support.
- *
- ******************************************************************************/
-
-acpi_status acpi_ev_install_fadt_gpes(void)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(ev_install_fadt_gpes);
-
- /* Namespace must be locked */
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
- /* FADT GPE Block 0 */
-
- (void)acpi_ev_initialize_gpe_block(acpi_gbl_fadt_gpe_device,
- acpi_gbl_gpe_fadt_blocks[0]);
-
- /* FADT GPE Block 1 */
-
- (void)acpi_ev_initialize_gpe_block(acpi_gbl_fadt_gpe_device,
- acpi_gbl_gpe_fadt_blocks[1]);
-
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ev_install_xrupt_handlers
*
* PARAMETERS: None
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index 85445fb5844e..020add3eee1c 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -363,6 +363,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH);
gpe_block->register_count = register_count;
gpe_block->block_base_number = gpe_block_base_number;
+ gpe_block->initialized = FALSE;
ACPI_MEMCPY(&gpe_block->block_address, gpe_block_address,
sizeof(struct acpi_generic_address));
@@ -385,11 +386,12 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
return_ACPI_STATUS(status);
}
+ acpi_all_gpes_initialized = FALSE;
+
/* Find all GPE methods (_Lxx or_Exx) for this block */
walk_info.gpe_block = gpe_block;
walk_info.gpe_device = gpe_device;
- walk_info.enable_this_gpe = FALSE;
walk_info.execute_by_owner_id = FALSE;
status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device,
@@ -434,35 +436,34 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
******************************************************************************/
acpi_status
-acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
- struct acpi_gpe_block_info *gpe_block)
+acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block,
+ void *ignored)
{
acpi_status status;
struct acpi_gpe_event_info *gpe_event_info;
u32 gpe_enabled_count;
u32 gpe_index;
- u32 gpe_number;
u32 i;
u32 j;
ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
- /* Ignore a null GPE block (e.g., if no GPE block 1 exists) */
-
- if (!gpe_block) {
+ /*
+ * Ignore a null GPE block (e.g., if no GPE block 1 exists) and
+ * GPE blocks that have been initialized already.
+ */
+ if (!gpe_block || gpe_block->initialized) {
return_ACPI_STATUS(AE_OK);
}
/*
- * Enable all GPEs that have a corresponding method. Any other GPEs
- * within this block must be enabled via the acpi_enable_gpe interface.
+ * Enable all GPEs that have a corresponding method and have the
+ * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block must
+ * be enabled via the acpi_enable_gpe() interface.
*/
gpe_enabled_count = 0;
- if (gpe_device == acpi_gbl_fadt_gpe_device) {
- gpe_device = NULL;
- }
-
for (i = 0; i < gpe_block->register_count; i++) {
for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
@@ -470,27 +471,19 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
gpe_event_info = &gpe_block->event_info[gpe_index];
- gpe_number = gpe_index + gpe_block->block_base_number;
/* Ignore GPEs that have no corresponding _Lxx/_Exx method */
- if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD)) {
+ if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD)
+ || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
continue;
}
- /*
- * If the GPE has already been enabled for runtime
- * signaling, make sure it remains enabled, but do not
- * increment its reference counter.
- */
- status = gpe_event_info->runtime_count ?
- acpi_ev_enable_gpe(gpe_event_info) :
- acpi_enable_gpe(gpe_device, gpe_number);
-
+ status = acpi_raw_enable_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "Could not enable GPE 0x%02X",
- gpe_number));
+ "Could not enable GPE 0x%02X",
+ gpe_index + gpe_block->block_base_number));
continue;
}
@@ -504,5 +497,7 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
gpe_enabled_count));
}
+ gpe_block->initialized = TRUE;
+
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index 3084c5de1bba..2c7def95f721 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -210,8 +210,7 @@ acpi_status acpi_ev_gpe_initialize(void)
*
* DESCRIPTION: Check for new GPE methods (_Lxx/_Exx) made available as a
* result of a Load() or load_table() operation. If new GPE
- * methods have been installed, register the new methods and
- * enable and runtime GPEs that are associated with them.
+ * methods have been installed, register the new methods.
*
******************************************************************************/
@@ -239,7 +238,6 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
walk_info.owner_id = table_owner_id;
walk_info.execute_by_owner_id = TRUE;
walk_info.count = 0;
- walk_info.enable_this_gpe = TRUE;
/* Walk the interrupt level descriptor list */
@@ -301,8 +299,6 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
*
* If walk_info->execute_by_owner_id is TRUE, we only execute examine GPE methods
* with that owner.
- * If walk_info->enable_this_gpe is TRUE, the GPE that is referred to by a GPE
- * method is immediately enabled (Used for Load/load_table operators)
*
******************************************************************************/
@@ -315,8 +311,6 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
struct acpi_gpe_walk_info *walk_info =
ACPI_CAST_PTR(struct acpi_gpe_walk_info, context);
struct acpi_gpe_event_info *gpe_event_info;
- struct acpi_namespace_node *gpe_device;
- acpi_status status;
u32 gpe_number;
char name[ACPI_NAME_SIZE + 1];
u8 type;
@@ -421,29 +415,6 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_METHOD);
gpe_event_info->dispatch.method_node = method_node;
- /*
- * Enable this GPE if requested. This only happens when during the
- * execution of a Load or load_table operator. We have found a new
- * GPE method and want to immediately enable the GPE if it is a
- * runtime GPE.
- */
- if (walk_info->enable_this_gpe) {
-
- walk_info->count++;
- gpe_device = walk_info->gpe_device;
-
- if (gpe_device == acpi_gbl_fadt_gpe_device) {
- gpe_device = NULL;
- }
-
- status = acpi_enable_gpe(gpe_device, gpe_number);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not enable GPE 0x%02X",
- gpe_number));
- }
- }
-
ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
"Registered GPE method %s as GPE number 0x%.2X\n",
name, gpe_number));
diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c
index df0aea9a8cfd..fcaed9fb44ff 100644
--- a/drivers/acpi/acpica/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -553,7 +553,7 @@ acpi_status acpi_ev_release_global_lock(void)
acpi_gbl_global_lock_acquired = FALSE;
/* Release the local GL mutex */
- acpi_ev_global_lock_thread_id = NULL;
+ acpi_ev_global_lock_thread_id = 0;
acpi_ev_global_lock_acquired = 0;
acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex);
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index f40d271bf568..0b47a6dc9290 100644
--- a/drivers/acpi/acpica/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -289,8 +289,8 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
}
/*
- * Get the PCI device and function numbers from the _ADR object contained
- * in the parent's scope.
+ * Get the PCI device and function numbers from the _ADR object
+ * contained in the parent's scope.
*/
status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
pci_device_node, &pci_value);
@@ -320,9 +320,15 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
pci_id->bus = ACPI_LOWORD(pci_value);
}
- /* Complete this device's pci_id */
+ /* Complete/update the PCI ID for this device */
- acpi_os_derive_pci_id(pci_root_node, region_obj->region.node, &pci_id);
+ status =
+ acpi_hw_derive_pci_id(pci_id, pci_root_node,
+ region_obj->region.node);
+ if (ACPI_FAILURE(status)) {
+ ACPI_FREE(pci_id);
+ return_ACPI_STATUS(status);
+ }
*region_context = pci_id;
return_ACPI_STATUS(AE_OK);
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 14e48add32fa..36af222cac65 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -726,15 +726,16 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
/*
- * If the GPE is associated with a method and it cannot wake up the
- * system from sleep states, it was enabled automatically during
- * initialization, so it has to be disabled now to avoid spurious
- * execution of the handler.
+ * If the GPE is associated with a method, it might have been enabled
+ * automatically during initialization, in which case it has to be
+ * disabled now to avoid spurious execution of the handler.
*/
if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD)
- && !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE))
+ && gpe_event_info->runtime_count) {
+ handler->orig_enabled = 1;
(void)acpi_raw_disable_gpe(gpe_event_info);
+ }
/* Install the handler */
@@ -837,13 +838,13 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
gpe_event_info->flags |= handler->orig_flags;
/*
- * If the GPE was previously associated with a method and it cannot wake
- * up the system from sleep states, it should be enabled at this point
- * to restore the post-initialization configuration.
+ * If the GPE was previously associated with a method and it was
+ * enabled, it should be enabled at this point to restore the
+ * post-initialization configuration.
*/
if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD)
- && !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE))
+ && handler->orig_enabled)
(void)acpi_raw_enable_gpe(gpe_event_info);
/* Now we can free the handler object */
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index 304825528d48..a1dabe3fd8ae 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -379,21 +379,12 @@ acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number)
/* Ensure that we have a valid GPE number */
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
- if (!gpe_event_info) {
+ if (gpe_event_info) {
+ gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
+ } else {
status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
- }
-
- if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) {
- goto unlock_and_exit;
}
- gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
- if (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) {
- (void)acpi_raw_disable_gpe(gpe_event_info);
- }
-
-unlock_and_exit:
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
return_ACPI_STATUS(status);
}
@@ -651,7 +642,7 @@ acpi_install_gpe_block(acpi_handle gpe_device,
struct acpi_generic_address *gpe_block_address,
u32 register_count, u32 interrupt_number)
{
- acpi_status status;
+ acpi_status status = AE_OK;
union acpi_operand_object *obj_desc;
struct acpi_namespace_node *node;
struct acpi_gpe_block_info *gpe_block;
@@ -715,10 +706,6 @@ acpi_install_gpe_block(acpi_handle gpe_device,
obj_desc->device.gpe_block = gpe_block;
- /* Enable the runtime GPEs in the new block */
-
- status = acpi_ev_initialize_gpe_block(node, gpe_block);
-
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return_ACPI_STATUS(status);
@@ -924,3 +911,43 @@ acpi_status acpi_enable_all_runtime_gpes(void)
return_ACPI_STATUS(status);
}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_update_gpes
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Enable all GPEs that have associated _Lxx or _Exx methods and
+ * are not pointed to by any device _PRW methods indicating that
+ * these GPEs are generally intended for system or device wakeup
+ * (such GPEs have to be enabled directly when the devices whose
+ * _PRW methods point to them are set up for wakeup signaling).
+ *
+ ******************************************************************************/
+
+acpi_status acpi_update_gpes(void)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_update_gpes);
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ } else if (acpi_all_gpes_initialized) {
+ goto unlock;
+ }
+
+ status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block, NULL);
+ if (ACPI_SUCCESS(status)) {
+ acpi_all_gpes_initialized = TRUE;
+ }
+
+unlock:
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c
index 541cbc1544d5..ce9314f79451 100644
--- a/drivers/acpi/acpica/evxfregn.c
+++ b/drivers/acpi/acpica/evxfregn.c
@@ -64,6 +64,12 @@ ACPI_MODULE_NAME("evxfregn")
*
* DESCRIPTION: Install a handler for all op_regions of a given space_id.
*
+ * NOTE: This function should only be called after acpi_enable_subsystem has
+ * been called. This is because any _REG methods associated with the Space ID
+ * are executed here, and these methods can only be safely executed after
+ * the default handlers have been installed and the hardware has been
+ * initialized (via acpi_enable_subsystem.)
+ *
******************************************************************************/
acpi_status
acpi_install_address_space_handler(acpi_handle device,
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c
index 047217303a4b..38293fd3e088 100644
--- a/drivers/acpi/acpica/exfldio.c
+++ b/drivers/acpi/acpica/exfldio.c
@@ -119,8 +119,8 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
}
/*
- * Exit now for SMBus or IPMI address space, it has a non-linear address space
- * and the request cannot be directly validated
+ * Exit now for SMBus or IPMI address space, it has a non-linear
+ * address space and the request cannot be directly validated
*/
if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS ||
rgn_desc->region.space_id == ACPI_ADR_SPACE_IPMI) {
@@ -147,8 +147,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
* (Region length is specified in bytes)
*/
if (rgn_desc->region.length <
- (obj_desc->common_field.base_byte_offset +
- field_datum_byte_offset +
+ (obj_desc->common_field.base_byte_offset + field_datum_byte_offset +
obj_desc->common_field.access_byte_width)) {
if (acpi_gbl_enable_interpreter_slack) {
/*
@@ -680,6 +679,7 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
u32 buffer_tail_bits;
u32 datum_count;
u32 field_datum_count;
+ u32 access_bit_width;
u32 i;
ACPI_FUNCTION_TRACE(ex_extract_from_field);
@@ -694,16 +694,36 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
}
+
ACPI_MEMSET(buffer, 0, buffer_length);
+ access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width);
+
+ /* Handle the simple case here */
+
+ if ((obj_desc->common_field.start_field_bit_offset == 0) &&
+ (obj_desc->common_field.bit_length == access_bit_width)) {
+ status = acpi_ex_field_datum_io(obj_desc, 0, buffer, ACPI_READ);
+ return_ACPI_STATUS(status);
+ }
+
+/* TBD: Move to common setup code */
+
+ /* Field algorithm is limited to sizeof(u64), truncate if needed */
+
+ if (obj_desc->common_field.access_byte_width > sizeof(u64)) {
+ obj_desc->common_field.access_byte_width = sizeof(u64);
+ access_bit_width = sizeof(u64) * 8;
+ }
/* Compute the number of datums (access width data items) */
- datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
- obj_desc->common_field.access_bit_width);
+ datum_count =
+ ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
+ access_bit_width);
+
field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
obj_desc->common_field.
start_field_bit_offset,
- obj_desc->common_field.
access_bit_width);
/* Priming read from the field */
@@ -738,12 +758,11 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
* This avoids the differences in behavior between different compilers
* concerning shift values larger than the target data width.
*/
- if ((obj_desc->common_field.access_bit_width -
- obj_desc->common_field.start_field_bit_offset) <
+ if (access_bit_width -
+ obj_desc->common_field.start_field_bit_offset <
ACPI_INTEGER_BIT_SIZE) {
merged_datum |=
- raw_datum << (obj_desc->common_field.
- access_bit_width -
+ raw_datum << (access_bit_width -
obj_desc->common_field.
start_field_bit_offset);
}
@@ -765,8 +784,7 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
/* Mask off any extra bits in the last datum */
- buffer_tail_bits = obj_desc->common_field.bit_length %
- obj_desc->common_field.access_bit_width;
+ buffer_tail_bits = obj_desc->common_field.bit_length % access_bit_width;
if (buffer_tail_bits) {
merged_datum &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
}
@@ -798,6 +816,7 @@ acpi_status
acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
void *buffer, u32 buffer_length)
{
+ void *new_buffer;
acpi_status status;
u64 mask;
u64 width_mask;
@@ -808,9 +827,9 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
u32 buffer_tail_bits;
u32 datum_count;
u32 field_datum_count;
- u32 i;
+ u32 access_bit_width;
u32 required_length;
- void *new_buffer;
+ u32 i;
ACPI_FUNCTION_TRACE(ex_insert_into_field);
@@ -844,17 +863,24 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
buffer_length = required_length;
}
+/* TBD: Move to common setup code */
+
+ /* Algo is limited to sizeof(u64), so cut the access_byte_width */
+ if (obj_desc->common_field.access_byte_width > sizeof(u64)) {
+ obj_desc->common_field.access_byte_width = sizeof(u64);
+ }
+
+ access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width);
+
/*
* Create the bitmasks used for bit insertion.
* Note: This if/else is used to bypass compiler differences with the
* shift operator
*/
- if (obj_desc->common_field.access_bit_width == ACPI_INTEGER_BIT_SIZE) {
+ if (access_bit_width == ACPI_INTEGER_BIT_SIZE) {
width_mask = ACPI_UINT64_MAX;
} else {
- width_mask =
- ACPI_MASK_BITS_ABOVE(obj_desc->common_field.
- access_bit_width);
+ width_mask = ACPI_MASK_BITS_ABOVE(access_bit_width);
}
mask = width_mask &
@@ -863,12 +889,11 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
/* Compute the number of datums (access width data items) */
datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
- obj_desc->common_field.access_bit_width);
+ access_bit_width);
field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
obj_desc->common_field.
start_field_bit_offset,
- obj_desc->common_field.
access_bit_width);
/* Get initial Datum from the input buffer */
@@ -905,12 +930,11 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
* This avoids the differences in behavior between different compilers
* concerning shift values larger than the target data width.
*/
- if ((obj_desc->common_field.access_bit_width -
+ if ((access_bit_width -
obj_desc->common_field.start_field_bit_offset) <
ACPI_INTEGER_BIT_SIZE) {
merged_datum =
- raw_datum >> (obj_desc->common_field.
- access_bit_width -
+ raw_datum >> (access_bit_width -
obj_desc->common_field.
start_field_bit_offset);
} else {
@@ -929,6 +953,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
ACPI_MEMCPY(&raw_datum, ((char *)buffer) + buffer_offset,
ACPI_MIN(obj_desc->common_field.access_byte_width,
buffer_length - buffer_offset));
+
merged_datum |=
raw_datum << obj_desc->common_field.start_field_bit_offset;
}
@@ -937,7 +962,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
buffer_tail_bits = (obj_desc->common_field.bit_length +
obj_desc->common_field.start_field_bit_offset) %
- obj_desc->common_field.access_bit_width;
+ access_bit_width;
if (buffer_tail_bits) {
mask &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
}
diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c
index f73be97043c0..6af14e43f839 100644
--- a/drivers/acpi/acpica/exmutex.c
+++ b/drivers/acpi/acpica/exmutex.c
@@ -336,7 +336,7 @@ acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc)
/* Clear mutex info */
- obj_desc->mutex.thread_id = NULL;
+ obj_desc->mutex.thread_id = 0;
return_ACPI_STATUS(status);
}
@@ -393,10 +393,10 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
if ((owner_thread->thread_id != walk_state->thread->thread_id) &&
(obj_desc != acpi_gbl_global_lock_mutex)) {
ACPI_ERROR((AE_INFO,
- "Thread %p cannot release Mutex [%4.4s] acquired by thread %p",
- ACPI_CAST_PTR(void, walk_state->thread->thread_id),
+ "Thread %u cannot release Mutex [%4.4s] acquired by thread %u",
+ (u32)walk_state->thread->thread_id,
acpi_ut_get_node_name(obj_desc->mutex.node),
- ACPI_CAST_PTR(void, owner_thread->thread_id)));
+ (u32)owner_thread->thread_id));
return_ACPI_STATUS(AE_AML_NOT_OWNER);
}
@@ -488,7 +488,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
/* Mark mutex unowned */
obj_desc->mutex.owner_thread = NULL;
- obj_desc->mutex.thread_id = NULL;
+ obj_desc->mutex.thread_id = 0;
/* Update Thread sync_level (Last mutex is the important one) */
diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
index 98a331d2249b..7aae29f73d3f 100644
--- a/drivers/acpi/acpica/exprep.c
+++ b/drivers/acpi/acpica/exprep.c
@@ -355,12 +355,10 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
}
- /* Setup width (access granularity) fields */
+ /* Setup width (access granularity) fields (values are: 1, 2, 4, 8) */
obj_desc->common_field.access_byte_width = (u8)
- ACPI_DIV_8(access_bit_width); /* 1, 2, 4, 8 */
-
- obj_desc->common_field.access_bit_width = (u8) access_bit_width;
+ ACPI_DIV_8(access_bit_width);
/*
* base_byte_offset is the address of the start of the field within the
@@ -405,8 +403,9 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
{
union acpi_operand_object *obj_desc;
union acpi_operand_object *second_desc = NULL;
- u32 type;
acpi_status status;
+ u32 access_byte_width;
+ u32 type;
ACPI_FUNCTION_TRACE(ex_prep_field_value);
@@ -421,8 +420,8 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
type = acpi_ns_get_type(info->region_node);
if (type != ACPI_TYPE_REGION) {
ACPI_ERROR((AE_INFO,
- "Needed Region, found type 0x%X (%s)",
- type, acpi_ut_get_type_name(type)));
+ "Needed Region, found type 0x%X (%s)", type,
+ acpi_ut_get_type_name(type)));
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
@@ -438,7 +437,8 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
/* Initialize areas of the object that are common to all fields */
obj_desc->common_field.node = info->field_node;
- status = acpi_ex_prep_common_field_object(obj_desc, info->field_flags,
+ status = acpi_ex_prep_common_field_object(obj_desc,
+ info->field_flags,
info->attribute,
info->field_bit_position,
info->field_bit_length);
@@ -455,26 +455,25 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
obj_desc->field.region_obj =
acpi_ns_get_attached_object(info->region_node);
- /* An additional reference for the container */
+ /* Allow full data read from EC address space */
- acpi_ut_add_reference(obj_desc->field.region_obj);
+ if ((obj_desc->field.region_obj->region.space_id ==
+ ACPI_ADR_SPACE_EC)
+ && (obj_desc->common_field.bit_length > 8)) {
+ access_byte_width =
+ ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.
+ bit_length);
+
+ /* Maximum byte width supported is 255 */
- /* allow full data read from EC address space */
- if (obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_EC) {
- if (obj_desc->common_field.bit_length > 8) {
- unsigned width =
- ACPI_ROUND_BITS_UP_TO_BYTES(
- obj_desc->common_field.bit_length);
- // access_bit_width is u8, don't overflow it
- if (width > 8)
- width = 8;
+ if (access_byte_width < 256) {
obj_desc->common_field.access_byte_width =
- width;
- obj_desc->common_field.access_bit_width =
- 8 * width;
+ (u8)access_byte_width;
}
}
+ /* An additional reference for the container */
+
+ acpi_ut_add_reference(obj_desc->field.region_obj);
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
"RegionField: BitOff %X, Off %X, Gran %X, Region %p\n",
diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c
index 8819d2ac5aee..de17e10da0ed 100644
--- a/drivers/acpi/acpica/exregion.c
+++ b/drivers/acpi/acpica/exregion.c
@@ -353,7 +353,6 @@ acpi_ex_pci_config_space_handler(u32 function,
acpi_status status = AE_OK;
struct acpi_pci_id *pci_id;
u16 pci_register;
- u32 value32;
ACPI_FUNCTION_TRACE(ex_pci_config_space_handler);
@@ -381,8 +380,7 @@ acpi_ex_pci_config_space_handler(u32 function,
case ACPI_READ:
status = acpi_os_read_pci_configuration(pci_id, pci_register,
- &value32, bit_width);
- *value = value32;
+ value, bit_width);
break;
case ACPI_WRITE:
diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c
new file mode 100644
index 000000000000..ad21c7d8bf4f
--- /dev/null
+++ b/drivers/acpi/acpica/hwpci.c
@@ -0,0 +1,412 @@
+/*******************************************************************************
+ *
+ * Module Name: hwpci - Obtain PCI bus, device, and function numbers
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2010, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+
+#define _COMPONENT ACPI_NAMESPACE
+ACPI_MODULE_NAME("hwpci")
+
+/* PCI configuration space values */
+#define PCI_CFG_HEADER_TYPE_REG 0x0E
+#define PCI_CFG_PRIMARY_BUS_NUMBER_REG 0x18
+#define PCI_CFG_SECONDARY_BUS_NUMBER_REG 0x19
+/* PCI header values */
+#define PCI_HEADER_TYPE_MASK 0x7F
+#define PCI_TYPE_BRIDGE 0x01
+#define PCI_TYPE_CARDBUS_BRIDGE 0x02
+typedef struct acpi_pci_device {
+ acpi_handle device;
+ struct acpi_pci_device *next;
+
+} acpi_pci_device;
+
+/* Local prototypes */
+
+static acpi_status
+acpi_hw_build_pci_list(acpi_handle root_pci_device,
+ acpi_handle pci_region,
+ struct acpi_pci_device **return_list_head);
+
+static acpi_status
+acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
+ struct acpi_pci_device *list_head);
+
+static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head);
+
+static acpi_status
+acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
+ acpi_handle pci_device,
+ u16 *bus_number, u8 *is_bridge);
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_hw_derive_pci_id
+ *
+ * PARAMETERS: pci_id - Initial values for the PCI ID. May be
+ * modified by this function.
+ * root_pci_device - A handle to a PCI device object. This
+ * object must be a PCI Root Bridge having a
+ * _HID value of either PNP0A03 or PNP0A08
+ * pci_region - A handle to a PCI configuration space
+ * Operation Region being initialized
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function derives a full PCI ID for a PCI device,
+ * consisting of a Segment number, Bus number, Device number,
+ * and function code.
+ *
+ * The PCI hardware dynamically configures PCI bus numbers
+ * depending on the bus topology discovered during system
+ * initialization. This function is invoked during configuration
+ * of a PCI_Config Operation Region in order to (possibly) update
+ * the Bus/Device/Function numbers in the pci_id with the actual
+ * values as determined by the hardware and operating system
+ * configuration.
+ *
+ * The pci_id parameter is initially populated during the Operation
+ * Region initialization. This function is then called, and is
+ * will make any necessary modifications to the Bus, Device, or
+ * Function number PCI ID subfields as appropriate for the
+ * current hardware and OS configuration.
+ *
+ * NOTE: Created 08/2010. Replaces the previous OSL acpi_os_derive_pci_id
+ * interface since this feature is OS-independent. This module
+ * specifically avoids any use of recursion by building a local
+ * temporary device list.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
+ acpi_handle root_pci_device, acpi_handle pci_region)
+{
+ acpi_status status;
+ struct acpi_pci_device *list_head = NULL;
+
+ ACPI_FUNCTION_TRACE(hw_derive_pci_id);
+
+ if (!pci_id) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ /* Build a list of PCI devices, from pci_region up to root_pci_device */
+
+ status =
+ acpi_hw_build_pci_list(root_pci_device, pci_region, &list_head);
+ if (ACPI_SUCCESS(status)) {
+
+ /* Walk the list, updating the PCI device/function/bus numbers */
+
+ status = acpi_hw_process_pci_list(pci_id, list_head);
+ }
+
+ /* Always delete the list */
+
+ acpi_hw_delete_pci_list(list_head);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_hw_build_pci_list
+ *
+ * PARAMETERS: root_pci_device - A handle to a PCI device object. This
+ * object is guaranteed to be a PCI Root
+ * Bridge having a _HID value of either
+ * PNP0A03 or PNP0A08
+ * pci_region - A handle to the PCI configuration space
+ * Operation Region
+ * return_list_head - Where the PCI device list is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Builds a list of devices from the input PCI region up to the
+ * Root PCI device for this namespace subtree.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_hw_build_pci_list(acpi_handle root_pci_device,
+ acpi_handle pci_region,
+ struct acpi_pci_device **return_list_head)
+{
+ acpi_handle current_device;
+ acpi_handle parent_device;
+ acpi_status status;
+ struct acpi_pci_device *list_element;
+ struct acpi_pci_device *list_head = NULL;
+
+ /*
+ * Ascend namespace branch until the root_pci_device is reached, building
+ * a list of device nodes. Loop will exit when either the PCI device is
+ * found, or the root of the namespace is reached.
+ */
+ current_device = pci_region;
+ while (1) {
+ status = acpi_get_parent(current_device, &parent_device);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */
+
+ if (parent_device == root_pci_device) {
+ *return_list_head = list_head;
+ return (AE_OK);
+ }
+
+ list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device));
+ if (!list_element) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Put new element at the head of the list */
+
+ list_element->next = list_head;
+ list_element->device = parent_device;
+ list_head = list_element;
+
+ current_device = parent_device;
+ }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_hw_process_pci_list
+ *
+ * PARAMETERS: pci_id - Initial values for the PCI ID. May be
+ * modified by this function.
+ * list_head - Device list created by
+ * acpi_hw_build_pci_list
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Walk downward through the PCI device list, getting the device
+ * info for each, via the PCI configuration space and updating
+ * the PCI ID as necessary. Deletes the list during traversal.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
+ struct acpi_pci_device *list_head)
+{
+ acpi_status status = AE_OK;
+ struct acpi_pci_device *info;
+ u16 bus_number;
+ u8 is_bridge = TRUE;
+
+ ACPI_FUNCTION_NAME(hw_process_pci_list);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
+ "Input PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n",
+ pci_id->segment, pci_id->bus, pci_id->device,
+ pci_id->function));
+
+ bus_number = pci_id->bus;
+
+ /*
+ * Descend down the namespace tree, collecting PCI device, function,
+ * and bus numbers. bus_number is only important for PCI bridges.
+ * Algorithm: As we descend the tree, use the last valid PCI device,
+ * function, and bus numbers that are discovered, and assign them
+ * to the PCI ID for the target device.
+ */
+ info = list_head;
+ while (info) {
+ status = acpi_hw_get_pci_device_info(pci_id, info->device,
+ &bus_number, &is_bridge);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ info = info->next;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
+ "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X "
+ "Status %X BusNumber %X IsBridge %X\n",
+ pci_id->segment, pci_id->bus, pci_id->device,
+ pci_id->function, status, bus_number, is_bridge));
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_hw_delete_pci_list
+ *
+ * PARAMETERS: list_head - Device list created by
+ * acpi_hw_build_pci_list
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Free the entire PCI list.
+ *
+ ******************************************************************************/
+
+static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head)
+{
+ struct acpi_pci_device *next;
+ struct acpi_pci_device *previous;
+
+ next = list_head;
+ while (next) {
+ previous = next;
+ next = previous->next;
+ ACPI_FREE(previous);
+ }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_hw_get_pci_device_info
+ *
+ * PARAMETERS: pci_id - Initial values for the PCI ID. May be
+ * modified by this function.
+ * pci_device - Handle for the PCI device object
+ * bus_number - Where a PCI bridge bus number is returned
+ * is_bridge - Return value, indicates if this PCI
+ * device is a PCI bridge
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get the device info for a single PCI device object. Get the
+ * _ADR (contains PCI device and function numbers), and for PCI
+ * bridge devices, get the bus number from PCI configuration
+ * space.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
+ acpi_handle pci_device,
+ u16 *bus_number, u8 *is_bridge)
+{
+ acpi_status status;
+ acpi_object_type object_type;
+ u64 return_value;
+ u64 pci_value;
+
+ /* We only care about objects of type Device */
+
+ status = acpi_get_type(pci_device, &object_type);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ if (object_type != ACPI_TYPE_DEVICE) {
+ return (AE_OK);
+ }
+
+ /* We need an _ADR. Ignore device if not present */
+
+ status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
+ pci_device, &return_value);
+ if (ACPI_FAILURE(status)) {
+ return (AE_OK);
+ }
+
+ /*
+ * From _ADR, get the PCI Device and Function and
+ * update the PCI ID.
+ */
+ pci_id->device = ACPI_HIWORD(ACPI_LODWORD(return_value));
+ pci_id->function = ACPI_LOWORD(ACPI_LODWORD(return_value));
+
+ /*
+ * If the previous device was a bridge, use the previous
+ * device bus number
+ */
+ if (*is_bridge) {
+ pci_id->bus = *bus_number;
+ }
+
+ /*
+ * Get the bus numbers from PCI Config space:
+ *
+ * First, get the PCI header_type
+ */
+ *is_bridge = FALSE;
+ status = acpi_os_read_pci_configuration(pci_id,
+ PCI_CFG_HEADER_TYPE_REG,
+ &pci_value, 8);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /* We only care about bridges (1=pci_bridge, 2=card_bus_bridge) */
+
+ pci_value &= PCI_HEADER_TYPE_MASK;
+
+ if ((pci_value != PCI_TYPE_BRIDGE) &&
+ (pci_value != PCI_TYPE_CARDBUS_BRIDGE)) {
+ return (AE_OK);
+ }
+
+ /* Bridge: Get the Primary bus_number */
+
+ status = acpi_os_read_pci_configuration(pci_id,
+ PCI_CFG_PRIMARY_BUS_NUMBER_REG,
+ &pci_value, 8);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ *is_bridge = TRUE;
+ pci_id->bus = (u16)pci_value;
+
+ /* Bridge: Get the Secondary bus_number */
+
+ status = acpi_os_read_pci_configuration(pci_id,
+ PCI_CFG_SECONDARY_BUS_NUMBER_REG,
+ &pci_value, 8);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ *bus_number = (u16)pci_value;
+ return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c
index 4009498fbabd..4ef9f43ea926 100644
--- a/drivers/acpi/acpica/nsrepair2.c
+++ b/drivers/acpi/acpica/nsrepair2.c
@@ -74,10 +74,18 @@ acpi_ns_repair_ALR(struct acpi_predefined_data *data,
union acpi_operand_object **return_object_ptr);
static acpi_status
+acpi_ns_repair_CID(struct acpi_predefined_data *data,
+ union acpi_operand_object **return_object_ptr);
+
+static acpi_status
acpi_ns_repair_FDE(struct acpi_predefined_data *data,
union acpi_operand_object **return_object_ptr);
static acpi_status
+acpi_ns_repair_HID(struct acpi_predefined_data *data,
+ union acpi_operand_object **return_object_ptr);
+
+static acpi_status
acpi_ns_repair_PSS(struct acpi_predefined_data *data,
union acpi_operand_object **return_object_ptr);
@@ -108,8 +116,10 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
* As necessary:
*
* _ALR: Sort the list ascending by ambient_illuminance
+ * _CID: Strings: uppercase all, remove any leading asterisk
* _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
* _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
+ * _HID: Strings: uppercase all, remove any leading asterisk
* _PSS: Sort the list descending by Power
* _TSS: Sort the list descending by Power
*
@@ -122,8 +132,10 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
*/
static const struct acpi_repair_info acpi_ns_repairable_names[] = {
{"_ALR", acpi_ns_repair_ALR},
+ {"_CID", acpi_ns_repair_CID},
{"_FDE", acpi_ns_repair_FDE},
{"_GTM", acpi_ns_repair_FDE}, /* _GTM has same repair as _FDE */
+ {"_HID", acpi_ns_repair_HID},
{"_PSS", acpi_ns_repair_PSS},
{"_TSS", acpi_ns_repair_TSS},
{{0, 0, 0, 0}, NULL} /* Table terminator */
@@ -321,6 +333,157 @@ acpi_ns_repair_FDE(struct acpi_predefined_data *data,
/******************************************************************************
*
+ * FUNCTION: acpi_ns_repair_CID
+ *
+ * PARAMETERS: Data - Pointer to validation data structure
+ * return_object_ptr - Pointer to the object returned from the
+ * evaluation of a method or object
+ *
+ * RETURN: Status. AE_OK if object is OK or was repaired successfully
+ *
+ * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
+ * letters are uppercase and that there is no leading asterisk.
+ * If a Package, ensure same for all string elements.
+ *
+ *****************************************************************************/
+
+static acpi_status
+acpi_ns_repair_CID(struct acpi_predefined_data *data,
+ union acpi_operand_object **return_object_ptr)
+{
+ acpi_status status;
+ union acpi_operand_object *return_object = *return_object_ptr;
+ union acpi_operand_object **element_ptr;
+ union acpi_operand_object *original_element;
+ u16 original_ref_count;
+ u32 i;
+
+ /* Check for _CID as a simple string */
+
+ if (return_object->common.type == ACPI_TYPE_STRING) {
+ status = acpi_ns_repair_HID(data, return_object_ptr);
+ return (status);
+ }
+
+ /* Exit if not a Package */
+
+ if (return_object->common.type != ACPI_TYPE_PACKAGE) {
+ return (AE_OK);
+ }
+
+ /* Examine each element of the _CID package */
+
+ element_ptr = return_object->package.elements;
+ for (i = 0; i < return_object->package.count; i++) {
+ original_element = *element_ptr;
+ original_ref_count = original_element->common.reference_count;
+
+ status = acpi_ns_repair_HID(data, element_ptr);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /* Take care with reference counts */
+
+ if (original_element != *element_ptr) {
+
+ /* Element was replaced */
+
+ (*element_ptr)->common.reference_count =
+ original_ref_count;
+
+ acpi_ut_remove_reference(original_element);
+ }
+
+ element_ptr++;
+ }
+
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_ns_repair_HID
+ *
+ * PARAMETERS: Data - Pointer to validation data structure
+ * return_object_ptr - Pointer to the object returned from the
+ * evaluation of a method or object
+ *
+ * RETURN: Status. AE_OK if object is OK or was repaired successfully
+ *
+ * DESCRIPTION: Repair for the _HID object. If a string, ensure that all
+ * letters are uppercase and that there is no leading asterisk.
+ *
+ *****************************************************************************/
+
+static acpi_status
+acpi_ns_repair_HID(struct acpi_predefined_data *data,
+ union acpi_operand_object **return_object_ptr)
+{
+ union acpi_operand_object *return_object = *return_object_ptr;
+ union acpi_operand_object *new_string;
+ char *source;
+ char *dest;
+
+ ACPI_FUNCTION_NAME(ns_repair_HID);
+
+ /* We only care about string _HID objects (not integers) */
+
+ if (return_object->common.type != ACPI_TYPE_STRING) {
+ return (AE_OK);
+ }
+
+ if (return_object->string.length == 0) {
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Invalid zero-length _HID or _CID string"));
+
+ /* Return AE_OK anyway, let driver handle it */
+
+ data->flags |= ACPI_OBJECT_REPAIRED;
+ return (AE_OK);
+ }
+
+ /* It is simplest to always create a new string object */
+
+ new_string = acpi_ut_create_string_object(return_object->string.length);
+ if (!new_string) {
+ return (AE_NO_MEMORY);
+ }
+
+ /*
+ * Remove a leading asterisk if present. For some unknown reason, there
+ * are many machines in the field that contains IDs like this.
+ *
+ * Examples: "*PNP0C03", "*ACPI0003"
+ */
+ source = return_object->string.pointer;
+ if (*source == '*') {
+ source++;
+ new_string->string.length--;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
+ "%s: Removed invalid leading asterisk\n",
+ data->pathname));
+ }
+
+ /*
+ * Copy and uppercase the string. From the ACPI specification:
+ *
+ * A valid PNP ID must be of the form "AAA####" where A is an uppercase
+ * letter and # is a hex digit. A valid ACPI ID must be of the form
+ * "ACPI####" where # is a hex digit.
+ */
+ for (dest = new_string->string.pointer; *source; dest++, source++) {
+ *dest = (char)ACPI_TOUPPER(*source);
+ }
+
+ acpi_ut_remove_reference(return_object);
+ *return_object_ptr = new_string;
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
* FUNCTION: acpi_ns_repair_TSS
*
* PARAMETERS: Data - Pointer to validation data structure
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index e1add3491b04..a7d6ad9c111b 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -60,104 +60,6 @@ acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node *node_to_search);
/*******************************************************************************
*
- * FUNCTION: acpi_ns_report_error
- *
- * PARAMETERS: module_name - Caller's module name (for error output)
- * line_number - Caller's line number (for error output)
- * internal_name - Name or path of the namespace node
- * lookup_status - Exception code from NS lookup
- *
- * RETURN: None
- *
- * DESCRIPTION: Print warning message with full pathname
- *
- ******************************************************************************/
-
-void
-acpi_ns_report_error(const char *module_name,
- u32 line_number,
- const char *internal_name, acpi_status lookup_status)
-{
- acpi_status status;
- u32 bad_name;
- char *name = NULL;
-
- acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number);
-
- if (lookup_status == AE_BAD_CHARACTER) {
-
- /* There is a non-ascii character in the name */
-
- ACPI_MOVE_32_TO_32(&bad_name,
- ACPI_CAST_PTR(u32, internal_name));
- acpi_os_printf("[0x%4.4X] (NON-ASCII)", bad_name);
- } else {
- /* Convert path to external format */
-
- status = acpi_ns_externalize_name(ACPI_UINT32_MAX,
- internal_name, NULL, &name);
-
- /* Print target name */
-
- if (ACPI_SUCCESS(status)) {
- acpi_os_printf("[%s]", name);
- } else {
- acpi_os_printf("[COULD NOT EXTERNALIZE NAME]");
- }
-
- if (name) {
- ACPI_FREE(name);
- }
- }
-
- acpi_os_printf(" Namespace lookup failure, %s\n",
- acpi_format_exception(lookup_status));
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_report_method_error
- *
- * PARAMETERS: module_name - Caller's module name (for error output)
- * line_number - Caller's line number (for error output)
- * Message - Error message to use on failure
- * prefix_node - Prefix relative to the path
- * Path - Path to the node (optional)
- * method_status - Execution status
- *
- * RETURN: None
- *
- * DESCRIPTION: Print warning message with full pathname
- *
- ******************************************************************************/
-
-void
-acpi_ns_report_method_error(const char *module_name,
- u32 line_number,
- const char *message,
- struct acpi_namespace_node *prefix_node,
- const char *path, acpi_status method_status)
-{
- acpi_status status;
- struct acpi_namespace_node *node = prefix_node;
-
- acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number);
-
- if (path) {
- status =
- acpi_ns_get_node(prefix_node, path, ACPI_NS_NO_UPSEARCH,
- &node);
- if (ACPI_FAILURE(status)) {
- acpi_os_printf("[Could not get node by pathname]");
- }
- }
-
- acpi_ns_print_node_pathname(node, message);
- acpi_os_printf(", %s\n", acpi_format_exception(method_status));
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ns_print_node_pathname
*
* PARAMETERS: Node - Object
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index 1728cb9bf600..d2ff4325c427 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -49,7 +49,7 @@
ACPI_MODULE_NAME("tbfadt")
/* Local prototypes */
-static inline void
+static ACPI_INLINE void
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
u8 space_id, u8 byte_width, u64 address);
@@ -181,7 +181,7 @@ static struct acpi_fadt_pm_info fadt_pm_info_table[] = {
*
******************************************************************************/
-static inline void
+static ACPI_INLINE void
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
u8 space_id, u8 byte_width, u64 address)
{
diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c
index 983510640059..f21c486929a5 100644
--- a/drivers/acpi/acpica/utdebug.c
+++ b/drivers/acpi/acpica/utdebug.c
@@ -179,9 +179,8 @@ acpi_debug_print(u32 requested_debug_level,
if (thread_id != acpi_gbl_prev_thread_id) {
if (ACPI_LV_THREADS & acpi_dbg_level) {
acpi_os_printf
- ("\n**** Context Switch from TID %p to TID %p ****\n\n",
- ACPI_CAST_PTR(void, acpi_gbl_prev_thread_id),
- ACPI_CAST_PTR(void, thread_id));
+ ("\n**** Context Switch from TID %u to TID %u ****\n\n",
+ (u32)acpi_gbl_prev_thread_id, (u32)thread_id);
}
acpi_gbl_prev_thread_id = thread_id;
@@ -194,7 +193,7 @@ acpi_debug_print(u32 requested_debug_level,
acpi_os_printf("%8s-%04ld ", module_name, line_number);
if (ACPI_LV_THREADS & acpi_dbg_level) {
- acpi_os_printf("[%p] ", ACPI_CAST_PTR(void, thread_id));
+ acpi_os_printf("[%u] ", (u32)thread_id);
}
acpi_os_printf("[%02ld] %-22.22s: ",
diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c
index 6dfdeb653490..22f59ef604e0 100644
--- a/drivers/acpi/acpica/uteval.c
+++ b/drivers/acpi/acpica/uteval.c
@@ -48,153 +48,6 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("uteval")
-/*
- * Strings supported by the _OSI predefined (internal) method.
- *
- * March 2009: Removed "Linux" as this host no longer wants to respond true
- * for this string. Basically, the only safe OS strings are windows-related
- * and in many or most cases represent the only test path within the
- * BIOS-provided ASL code.
- *
- * The second element of each entry is used to track the newest version of
- * Windows that the BIOS has requested.
- */
-static struct acpi_interface_info acpi_interfaces_supported[] = {
- /* Operating System Vendor Strings */
-
- {"Windows 2000", ACPI_OSI_WIN_2000}, /* Windows 2000 */
- {"Windows 2001", ACPI_OSI_WIN_XP}, /* Windows XP */
- {"Windows 2001 SP1", ACPI_OSI_WIN_XP_SP1}, /* Windows XP SP1 */
- {"Windows 2001.1", ACPI_OSI_WINSRV_2003}, /* Windows Server 2003 */
- {"Windows 2001 SP2", ACPI_OSI_WIN_XP_SP2}, /* Windows XP SP2 */
- {"Windows 2001.1 SP1", ACPI_OSI_WINSRV_2003_SP1}, /* Windows Server 2003 SP1 - Added 03/2006 */
- {"Windows 2006", ACPI_OSI_WIN_VISTA}, /* Windows Vista - Added 03/2006 */
- {"Windows 2006.1", ACPI_OSI_WINSRV_2008}, /* Windows Server 2008 - Added 09/2009 */
- {"Windows 2006 SP1", ACPI_OSI_WIN_VISTA_SP1}, /* Windows Vista SP1 - Added 09/2009 */
- {"Windows 2009", ACPI_OSI_WIN_7}, /* Windows 7 and Server 2008 R2 - Added 09/2009 */
-
- /* Feature Group Strings */
-
- {"Extended Address Space Descriptor", 0}
-
- /*
- * All "optional" feature group strings (features that are implemented
- * by the host) should be implemented in the host version of
- * acpi_os_validate_interface and should not be added here.
- */
-};
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_osi_implementation
- *
- * PARAMETERS: walk_state - Current walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Implementation of the _OSI predefined control method
- *
- ******************************************************************************/
-
-acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state)
-{
- acpi_status status;
- union acpi_operand_object *string_desc;
- union acpi_operand_object *return_desc;
- u32 return_value;
- u32 i;
-
- ACPI_FUNCTION_TRACE(ut_osi_implementation);
-
- /* Validate the string input argument */
-
- string_desc = walk_state->arguments[0].object;
- if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) {
- return_ACPI_STATUS(AE_TYPE);
- }
-
- /* Create a return object */
-
- return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
- if (!return_desc) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /* Default return value is 0, NOT SUPPORTED */
-
- return_value = 0;
-
- /* Compare input string to static table of supported interfaces */
-
- for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_interfaces_supported); i++) {
- if (!ACPI_STRCMP(string_desc->string.pointer,
- acpi_interfaces_supported[i].name)) {
- /*
- * The interface is supported.
- * Update the osi_data if necessary. We keep track of the latest
- * version of Windows that has been requested by the BIOS.
- */
- if (acpi_interfaces_supported[i].value >
- acpi_gbl_osi_data) {
- acpi_gbl_osi_data =
- acpi_interfaces_supported[i].value;
- }
-
- return_value = ACPI_UINT32_MAX;
- goto exit;
- }
- }
-
- /*
- * Did not match the string in the static table, call the host OSL to
- * check for a match with one of the optional strings (such as
- * "Module Device", "3.0 Thermal Model", etc.)
- */
- status = acpi_os_validate_interface(string_desc->string.pointer);
- if (ACPI_SUCCESS(status)) {
-
- /* The interface is supported */
-
- return_value = ACPI_UINT32_MAX;
- }
-
-exit:
- ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO,
- "ACPI: BIOS _OSI(%s) is %ssupported\n",
- string_desc->string.pointer, return_value == 0 ? "not " : ""));
-
- /* Complete the return value */
-
- return_desc->integer.value = return_value;
- walk_state->return_desc = return_desc;
- return_ACPI_STATUS (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_osi_invalidate
- *
- * PARAMETERS: interface_string
- *
- * RETURN: Status
- *
- * DESCRIPTION: invalidate string in pre-defiend _OSI string list
- *
- ******************************************************************************/
-
-acpi_status acpi_osi_invalidate(char *interface)
-{
- int i;
-
- for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_interfaces_supported); i++) {
- if (!ACPI_STRCMP(interface, acpi_interfaces_supported[i].name)) {
- *acpi_interfaces_supported[i].name = '\0';
- return AE_OK;
- }
- }
- return AE_NOT_FOUND;
-}
-
/*******************************************************************************
*
* FUNCTION: acpi_ut_evaluate_object
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index 0558747579ef..e87bc6760be6 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -154,14 +154,16 @@ ACPI_EXPORT_SYMBOL(acpi_format_exception)
* 1) _SB_ is defined to be a device to allow \_SB_._INI to be run
* during the initialization sequence.
* 2) _TZ_ is defined to be a thermal zone in order to allow ASL code to
- * perform a Notify() operation on it.
+ * perform a Notify() operation on it. 09/2010: Changed to type Device.
+ * This still allows notifies, but does not confuse host code that
+ * searches for valid thermal_zone objects.
*/
const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = {
{"_GPE", ACPI_TYPE_LOCAL_SCOPE, NULL},
{"_PR_", ACPI_TYPE_LOCAL_SCOPE, NULL},
{"_SB_", ACPI_TYPE_DEVICE, NULL},
{"_SI_", ACPI_TYPE_LOCAL_SCOPE, NULL},
- {"_TZ_", ACPI_TYPE_THERMAL, NULL},
+ {"_TZ_", ACPI_TYPE_DEVICE, NULL},
{"_REV", ACPI_TYPE_INTEGER, (char *)ACPI_CA_SUPPORT_LEVEL},
{"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME},
{"_GL_", ACPI_TYPE_MUTEX, (char *)1},
@@ -766,6 +768,7 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_gpe_fadt_blocks[0] = NULL;
acpi_gbl_gpe_fadt_blocks[1] = NULL;
acpi_current_gpe_count = 0;
+ acpi_all_gpes_initialized = FALSE;
/* Global handlers */
@@ -774,6 +777,7 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_exception_handler = NULL;
acpi_gbl_init_handler = NULL;
acpi_gbl_table_handler = NULL;
+ acpi_gbl_interface_handler = NULL;
/* Global Lock support */
@@ -800,6 +804,7 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_debugger_configuration = DEBUGGER_THREADING;
acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;
acpi_gbl_osi_data = 0;
+ acpi_gbl_osi_mutex = NULL;
/* Hardware oriented */
diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c
index 1397fadd0d4b..d2906328535d 100644
--- a/drivers/acpi/acpica/utids.c
+++ b/drivers/acpi/acpica/utids.c
@@ -48,42 +48,6 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utids")
-/* Local prototypes */
-static void acpi_ut_copy_id_string(char *destination, char *source);
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_copy_id_string
- *
- * PARAMETERS: Destination - Where to copy the string
- * Source - Source string
- *
- * RETURN: None
- *
- * DESCRIPTION: Copies an ID string for the _HID, _CID, and _UID methods.
- * Performs removal of a leading asterisk if present -- workaround
- * for a known issue on a bunch of machines.
- *
- ******************************************************************************/
-
-static void acpi_ut_copy_id_string(char *destination, char *source)
-{
-
- /*
- * Workaround for ID strings that have a leading asterisk. This construct
- * is not allowed by the ACPI specification (ID strings must be
- * alphanumeric), but enough existing machines have this embedded in their
- * ID strings that the following code is useful.
- */
- if (*source == '*') {
- source++;
- }
-
- /* Do the actual copy */
-
- ACPI_STRCPY(destination, source);
-}
-
/*******************************************************************************
*
* FUNCTION: acpi_ut_execute_HID
@@ -101,7 +65,6 @@ static void acpi_ut_copy_id_string(char *destination, char *source)
* NOTE: Internal function, no parameter validation
*
******************************************************************************/
-
acpi_status
acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
struct acpica_device_id **return_id)
@@ -147,7 +110,7 @@ acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
acpi_ex_eisa_id_to_string(hid->string, obj_desc->integer.value);
} else {
- acpi_ut_copy_id_string(hid->string, obj_desc->string.pointer);
+ ACPI_STRCPY(hid->string, obj_desc->string.pointer);
}
hid->length = length;
@@ -224,7 +187,7 @@ acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
acpi_ex_integer_to_string(uid->string, obj_desc->integer.value);
} else {
- acpi_ut_copy_id_string(uid->string, obj_desc->string.pointer);
+ ACPI_STRCPY(uid->string, obj_desc->string.pointer);
}
uid->length = length;
@@ -357,8 +320,8 @@ acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
/* Copy the String CID from the returned object */
- acpi_ut_copy_id_string(next_id_string,
- cid_objects[i]->string.pointer);
+ ACPI_STRCPY(next_id_string,
+ cid_objects[i]->string.pointer);
length = cid_objects[i]->string.length + 1;
}
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index a39c93dac719..c1b1c803ea9b 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -117,6 +117,10 @@ void acpi_ut_subsystem_shutdown(void)
/* Close the acpi_event Handling */
acpi_ev_terminate();
+
+ /* Delete any dynamic _OSI interfaces */
+
+ acpi_ut_interface_terminate();
#endif
/* Close the Namespace */
diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c
index 35059a14eb72..49cf7b7fd816 100644
--- a/drivers/acpi/acpica/utmath.c
+++ b/drivers/acpi/acpica/utmath.c
@@ -48,11 +48,27 @@
ACPI_MODULE_NAME("utmath")
/*
- * Support for double-precision integer divide. This code is included here
- * in order to support kernel environments where the double-precision math
- * library is not available.
+ * Optional support for 64-bit double-precision integer divide. This code
+ * is configurable and is implemented in order to support 32-bit kernel
+ * environments where a 64-bit double-precision math library is not available.
+ *
+ * Support for a more normal 64-bit divide/modulo (with check for a divide-
+ * by-zero) appears after this optional section of code.
*/
#ifndef ACPI_USE_NATIVE_DIVIDE
+/* Structures used only for 64-bit divide */
+typedef struct uint64_struct {
+ u32 lo;
+ u32 hi;
+
+} uint64_struct;
+
+typedef union uint64_overlay {
+ u64 full;
+ struct uint64_struct part;
+
+} uint64_overlay;
+
/*******************************************************************************
*
* FUNCTION: acpi_ut_short_divide
@@ -69,6 +85,7 @@ ACPI_MODULE_NAME("utmath")
* 32-bit remainder.
*
******************************************************************************/
+
acpi_status
acpi_ut_short_divide(u64 dividend,
u32 divisor, u64 *out_quotient, u32 *out_remainder)
diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c
index e8d0724ee403..c7d0e05ef5a4 100644
--- a/drivers/acpi/acpica/utmisc.c
+++ b/drivers/acpi/acpica/utmisc.c
@@ -50,11 +50,6 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utmisc")
-/*
- * Common suffix for messages
- */
-#define ACPI_COMMON_MSG_SUFFIX \
- acpi_os_printf(" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number)
/*******************************************************************************
*
* FUNCTION: acpi_ut_validate_exception
@@ -1044,160 +1039,3 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object,
return_ACPI_STATUS(AE_AML_INTERNAL);
}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_error, acpi_exception, acpi_warning, acpi_info
- *
- * PARAMETERS: module_name - Caller's module name (for error output)
- * line_number - Caller's line number (for error output)
- * Format - Printf format string + additional args
- *
- * RETURN: None
- *
- * DESCRIPTION: Print message with module/line/version info
- *
- ******************************************************************************/
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_error(const char *module_name, u32 line_number, const char *format, ...)
-{
- va_list args;
-
- acpi_os_printf("ACPI Error: ");
-
- va_start(args, format);
- acpi_os_vprintf(format, args);
- ACPI_COMMON_MSG_SUFFIX;
- va_end(args);
-}
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_exception(const char *module_name,
- u32 line_number, acpi_status status, const char *format, ...)
-{
- va_list args;
-
- acpi_os_printf("ACPI Exception: %s, ", acpi_format_exception(status));
-
- va_start(args, format);
- acpi_os_vprintf(format, args);
- ACPI_COMMON_MSG_SUFFIX;
- va_end(args);
-}
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_warning(const char *module_name, u32 line_number, const char *format, ...)
-{
- va_list args;
-
- acpi_os_printf("ACPI Warning: ");
-
- va_start(args, format);
- acpi_os_vprintf(format, args);
- ACPI_COMMON_MSG_SUFFIX;
- va_end(args);
-}
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_info(const char *module_name, u32 line_number, const char *format, ...)
-{
- va_list args;
-
- acpi_os_printf("ACPI: ");
-
- va_start(args, format);
- acpi_os_vprintf(format, args);
- acpi_os_printf("\n");
- va_end(args);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_error)
-ACPI_EXPORT_SYMBOL(acpi_exception)
-ACPI_EXPORT_SYMBOL(acpi_warning)
-ACPI_EXPORT_SYMBOL(acpi_info)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_predefined_warning
- *
- * PARAMETERS: module_name - Caller's module name (for error output)
- * line_number - Caller's line number (for error output)
- * Pathname - Full pathname to the node
- * node_flags - From Namespace node for the method/object
- * Format - Printf format string + additional args
- *
- * RETURN: None
- *
- * DESCRIPTION: Warnings for the predefined validation module. Messages are
- * only emitted the first time a problem with a particular
- * method/object is detected. This prevents a flood of error
- * messages for methods that are repeatedly evaluated.
- *
-******************************************************************************/
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_warning(const char *module_name,
- u32 line_number,
- char *pathname,
- u8 node_flags, const char *format, ...)
-{
- va_list args;
-
- /*
- * Warning messages for this method/object will be disabled after the
- * first time a validation fails or an object is successfully repaired.
- */
- if (node_flags & ANOBJ_EVALUATED) {
- return;
- }
-
- acpi_os_printf("ACPI Warning for %s: ", pathname);
-
- va_start(args, format);
- acpi_os_vprintf(format, args);
- ACPI_COMMON_MSG_SUFFIX;
- va_end(args);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_predefined_info
- *
- * PARAMETERS: module_name - Caller's module name (for error output)
- * line_number - Caller's line number (for error output)
- * Pathname - Full pathname to the node
- * node_flags - From Namespace node for the method/object
- * Format - Printf format string + additional args
- *
- * RETURN: None
- *
- * DESCRIPTION: Info messages for the predefined validation module. Messages
- * are only emitted the first time a problem with a particular
- * method/object is detected. This prevents a flood of
- * messages for methods that are repeatedly evaluated.
- *
- ******************************************************************************/
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_info(const char *module_name,
- u32 line_number,
- char *pathname, u8 node_flags, const char *format, ...)
-{
- va_list args;
-
- /*
- * Warning messages for this method/object will be disabled after the
- * first time a validation fails or an object is successfully repaired.
- */
- if (node_flags & ANOBJ_EVALUATED) {
- return;
- }
-
- acpi_os_printf("ACPI Info for %s: ", pathname);
-
- va_start(args, format);
- acpi_os_vprintf(format, args);
- ACPI_COMMON_MSG_SUFFIX;
- va_end(args);
-}
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index f5cca3a1300c..d9efa495b433 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -86,6 +86,12 @@ acpi_status acpi_ut_mutex_initialize(void)
spin_lock_init(acpi_gbl_gpe_lock);
spin_lock_init(acpi_gbl_hardware_lock);
+ /* Mutex for _OSI support */
+ status = acpi_os_create_mutex(&acpi_gbl_osi_mutex);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
/* Create the reader/writer lock for namespace access */
status = acpi_ut_create_rw_lock(&acpi_gbl_namespace_rw_lock);
@@ -117,6 +123,8 @@ void acpi_ut_mutex_terminate(void)
acpi_ut_delete_mutex(i);
}
+ acpi_os_delete_mutex(acpi_gbl_osi_mutex);
+
/* Delete the spinlocks */
acpi_os_delete_lock(acpi_gbl_gpe_lock);
@@ -220,18 +228,17 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) {
if (i == mutex_id) {
ACPI_ERROR((AE_INFO,
- "Mutex [%s] already acquired by this thread [%p]",
+ "Mutex [%s] already acquired by this thread [%u]",
acpi_ut_get_mutex_name
(mutex_id),
- ACPI_CAST_PTR(void,
- this_thread_id)));
+ (u32)this_thread_id));
return (AE_ALREADY_ACQUIRED);
}
ACPI_ERROR((AE_INFO,
- "Invalid acquire order: Thread %p owns [%s], wants [%s]",
- ACPI_CAST_PTR(void, this_thread_id),
+ "Invalid acquire order: Thread %u owns [%s], wants [%s]",
+ (u32)this_thread_id,
acpi_ut_get_mutex_name(i),
acpi_ut_get_mutex_name(mutex_id)));
@@ -242,24 +249,24 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
#endif
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
- "Thread %p attempting to acquire Mutex [%s]\n",
- ACPI_CAST_PTR(void, this_thread_id),
+ "Thread %u attempting to acquire Mutex [%s]\n",
+ (u32)this_thread_id,
acpi_ut_get_mutex_name(mutex_id)));
status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex,
ACPI_WAIT_FOREVER);
if (ACPI_SUCCESS(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
- "Thread %p acquired Mutex [%s]\n",
- ACPI_CAST_PTR(void, this_thread_id),
+ "Thread %u acquired Mutex [%s]\n",
+ (u32)this_thread_id,
acpi_ut_get_mutex_name(mutex_id)));
acpi_gbl_mutex_info[mutex_id].use_count++;
acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id;
} else {
ACPI_EXCEPTION((AE_INFO, status,
- "Thread %p could not acquire Mutex [0x%X]",
- ACPI_CAST_PTR(void, this_thread_id), mutex_id));
+ "Thread %u could not acquire Mutex [0x%X]",
+ (u32)this_thread_id, mutex_id));
}
return (status);
@@ -279,10 +286,14 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
{
+ acpi_thread_id this_thread_id;
+
ACPI_FUNCTION_NAME(ut_release_mutex);
- ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %p releasing Mutex [%s]\n",
- ACPI_CAST_PTR(void, acpi_os_get_thread_id()),
+ this_thread_id = acpi_os_get_thread_id();
+
+ ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n",
+ (u32)this_thread_id,
acpi_ut_get_mutex_name(mutex_id)));
if (mutex_id > ACPI_MAX_MUTEX) {
diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c
new file mode 100644
index 000000000000..18c59a85fdca
--- /dev/null
+++ b/drivers/acpi/acpica/utosi.c
@@ -0,0 +1,380 @@
+/******************************************************************************
+ *
+ * Module Name: utosi - Support for the _OSI predefined control method
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2010, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+
+#define _COMPONENT ACPI_UTILITIES
+ACPI_MODULE_NAME("utosi")
+
+/*
+ * Strings supported by the _OSI predefined control method (which is
+ * implemented internally within this module.)
+ *
+ * March 2009: Removed "Linux" as this host no longer wants to respond true
+ * for this string. Basically, the only safe OS strings are windows-related
+ * and in many or most cases represent the only test path within the
+ * BIOS-provided ASL code.
+ *
+ * The last element of each entry is used to track the newest version of
+ * Windows that the BIOS has requested.
+ */
+static struct acpi_interface_info acpi_default_supported_interfaces[] = {
+ /* Operating System Vendor Strings */
+
+ {"Windows 2000", NULL, 0, ACPI_OSI_WIN_2000}, /* Windows 2000 */
+ {"Windows 2001", NULL, 0, ACPI_OSI_WIN_XP}, /* Windows XP */
+ {"Windows 2001 SP1", NULL, 0, ACPI_OSI_WIN_XP_SP1}, /* Windows XP SP1 */
+ {"Windows 2001.1", NULL, 0, ACPI_OSI_WINSRV_2003}, /* Windows Server 2003 */
+ {"Windows 2001 SP2", NULL, 0, ACPI_OSI_WIN_XP_SP2}, /* Windows XP SP2 */
+ {"Windows 2001.1 SP1", NULL, 0, ACPI_OSI_WINSRV_2003_SP1}, /* Windows Server 2003 SP1 - Added 03/2006 */
+ {"Windows 2006", NULL, 0, ACPI_OSI_WIN_VISTA}, /* Windows Vista - Added 03/2006 */
+ {"Windows 2006.1", NULL, 0, ACPI_OSI_WINSRV_2008}, /* Windows Server 2008 - Added 09/2009 */
+ {"Windows 2006 SP1", NULL, 0, ACPI_OSI_WIN_VISTA_SP1}, /* Windows Vista SP1 - Added 09/2009 */
+ {"Windows 2006 SP2", NULL, 0, ACPI_OSI_WIN_VISTA_SP2}, /* Windows Vista SP2 - Added 09/2010 */
+ {"Windows 2009", NULL, 0, ACPI_OSI_WIN_7}, /* Windows 7 and Server 2008 R2 - Added 09/2009 */
+
+ /* Feature Group Strings */
+
+ {"Extended Address Space Descriptor", NULL, 0, 0}
+
+ /*
+ * All "optional" feature group strings (features that are implemented
+ * by the host) should be dynamically added by the host via
+ * acpi_install_interface and should not be manually added here.
+ *
+ * Examples of optional feature group strings:
+ *
+ * "Module Device"
+ * "Processor Device"
+ * "3.0 Thermal Model"
+ * "3.0 _SCP Extensions"
+ * "Processor Aggregator Device"
+ */
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_initialize_interfaces
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize the global _OSI supported interfaces list
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_initialize_interfaces(void)
+{
+ u32 i;
+
+ (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+ acpi_gbl_supported_interfaces = acpi_default_supported_interfaces;
+
+ /* Link the static list of supported interfaces */
+
+ for (i = 0;
+ i < (ACPI_ARRAY_LENGTH(acpi_default_supported_interfaces) - 1);
+ i++) {
+ acpi_default_supported_interfaces[i].next =
+ &acpi_default_supported_interfaces[(acpi_size) i + 1];
+ }
+
+ acpi_os_release_mutex(acpi_gbl_osi_mutex);
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_interface_terminate
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Delete all interfaces in the global list. Sets
+ * acpi_gbl_supported_interfaces to NULL.
+ *
+ ******************************************************************************/
+
+void acpi_ut_interface_terminate(void)
+{
+ struct acpi_interface_info *next_interface;
+
+ (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+ next_interface = acpi_gbl_supported_interfaces;
+
+ while (next_interface) {
+ acpi_gbl_supported_interfaces = next_interface->next;
+
+ /* Only interfaces added at runtime can be freed */
+
+ if (next_interface->flags & ACPI_OSI_DYNAMIC) {
+ ACPI_FREE(next_interface->name);
+ ACPI_FREE(next_interface);
+ }
+
+ next_interface = acpi_gbl_supported_interfaces;
+ }
+
+ acpi_os_release_mutex(acpi_gbl_osi_mutex);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_install_interface
+ *
+ * PARAMETERS: interface_name - The interface to install
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install the interface into the global interface list.
+ * Caller MUST hold acpi_gbl_osi_mutex
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_install_interface(acpi_string interface_name)
+{
+ struct acpi_interface_info *interface_info;
+
+ /* Allocate info block and space for the name string */
+
+ interface_info =
+ ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_interface_info));
+ if (!interface_info) {
+ return (AE_NO_MEMORY);
+ }
+
+ interface_info->name =
+ ACPI_ALLOCATE_ZEROED(ACPI_STRLEN(interface_name) + 1);
+ if (!interface_info->name) {
+ ACPI_FREE(interface_info);
+ return (AE_NO_MEMORY);
+ }
+
+ /* Initialize new info and insert at the head of the global list */
+
+ ACPI_STRCPY(interface_info->name, interface_name);
+ interface_info->flags = ACPI_OSI_DYNAMIC;
+ interface_info->next = acpi_gbl_supported_interfaces;
+
+ acpi_gbl_supported_interfaces = interface_info;
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_remove_interface
+ *
+ * PARAMETERS: interface_name - The interface to remove
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove the interface from the global interface list.
+ * Caller MUST hold acpi_gbl_osi_mutex
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_remove_interface(acpi_string interface_name)
+{
+ struct acpi_interface_info *previous_interface;
+ struct acpi_interface_info *next_interface;
+
+ previous_interface = next_interface = acpi_gbl_supported_interfaces;
+ while (next_interface) {
+ if (!ACPI_STRCMP(interface_name, next_interface->name)) {
+
+ /* Found: name is in either the static list or was added at runtime */
+
+ if (next_interface->flags & ACPI_OSI_DYNAMIC) {
+
+ /* Interface was added dynamically, remove and free it */
+
+ if (previous_interface == next_interface) {
+ acpi_gbl_supported_interfaces =
+ next_interface->next;
+ } else {
+ previous_interface->next =
+ next_interface->next;
+ }
+
+ ACPI_FREE(next_interface->name);
+ ACPI_FREE(next_interface);
+ } else {
+ /*
+ * Interface is in static list. If marked invalid, then it
+ * does not actually exist. Else, mark it invalid.
+ */
+ if (next_interface->flags & ACPI_OSI_INVALID) {
+ return (AE_NOT_EXIST);
+ }
+
+ next_interface->flags |= ACPI_OSI_INVALID;
+ }
+
+ return (AE_OK);
+ }
+
+ previous_interface = next_interface;
+ next_interface = next_interface->next;
+ }
+
+ /* Interface was not found */
+
+ return (AE_NOT_EXIST);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_interface
+ *
+ * PARAMETERS: interface_name - The interface to find
+ *
+ * RETURN: struct acpi_interface_info if found. NULL if not found.
+ *
+ * DESCRIPTION: Search for the specified interface name in the global list.
+ * Caller MUST hold acpi_gbl_osi_mutex
+ *
+ ******************************************************************************/
+
+struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name)
+{
+ struct acpi_interface_info *next_interface;
+
+ next_interface = acpi_gbl_supported_interfaces;
+ while (next_interface) {
+ if (!ACPI_STRCMP(interface_name, next_interface->name)) {
+ return (next_interface);
+ }
+
+ next_interface = next_interface->next;
+ }
+
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_osi_implementation
+ *
+ * PARAMETERS: walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Implementation of the _OSI predefined control method. When
+ * an invocation of _OSI is encountered in the system AML,
+ * control is transferred to this function.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_osi_implementation(struct acpi_walk_state * walk_state)
+{
+ union acpi_operand_object *string_desc;
+ union acpi_operand_object *return_desc;
+ struct acpi_interface_info *interface_info;
+ acpi_interface_handler interface_handler;
+ u32 return_value;
+
+ ACPI_FUNCTION_TRACE(ut_osi_implementation);
+
+ /* Validate the string input argument (from the AML caller) */
+
+ string_desc = walk_state->arguments[0].object;
+ if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) {
+ return_ACPI_STATUS(AE_TYPE);
+ }
+
+ /* Create a return object */
+
+ return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
+ if (!return_desc) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* Default return value is 0, NOT SUPPORTED */
+
+ return_value = 0;
+ (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+
+ /* Lookup the interface in the global _OSI list */
+
+ interface_info = acpi_ut_get_interface(string_desc->string.pointer);
+ if (interface_info && !(interface_info->flags & ACPI_OSI_INVALID)) {
+ /*
+ * The interface is supported.
+ * Update the osi_data if necessary. We keep track of the latest
+ * version of Windows that has been requested by the BIOS.
+ */
+ if (interface_info->value > acpi_gbl_osi_data) {
+ acpi_gbl_osi_data = interface_info->value;
+ }
+
+ return_value = ACPI_UINT32_MAX;
+ }
+
+ acpi_os_release_mutex(acpi_gbl_osi_mutex);
+
+ /*
+ * Invoke an optional _OSI interface handler. The host OS may wish
+ * to do some interface-specific handling. For example, warn about
+ * certain interfaces or override the true/false support value.
+ */
+ interface_handler = acpi_gbl_interface_handler;
+ if (interface_handler) {
+ return_value =
+ interface_handler(string_desc->string.pointer,
+ return_value);
+ }
+
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO,
+ "ACPI: BIOS _OSI(\"%s\") is %ssupported\n",
+ string_desc->string.pointer,
+ return_value == 0 ? "not " : ""));
+
+ /* Complete the return object */
+
+ return_desc->integer.value = return_value;
+ walk_state->return_desc = return_desc;
+ return_ACPI_STATUS(AE_OK);
+}
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index 7f8cefcb2b32..1f484c9a6888 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -110,6 +110,15 @@ acpi_status __init acpi_initialize_subsystem(void)
return_ACPI_STATUS(status);
}
+ /* Initialize the global OSI interfaces list with the static names */
+
+ status = acpi_ut_initialize_interfaces();
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "During OSI interfaces initialization"));
+ return_ACPI_STATUS(status);
+ }
+
/* If configured, initialize the AML debugger */
ACPI_DEBUGGER_EXEC(status = acpi_db_initialize());
@@ -290,19 +299,6 @@ acpi_status acpi_initialize_objects(u32 flags)
}
/*
- * Complete the GPE initialization for the GPE blocks defined in the FADT
- * (GPE block 0 and 1).
- *
- * NOTE: Currently, there seems to be no need to run the _REG methods
- * before enabling the GPEs.
- */
- if (!(flags & ACPI_NO_EVENT_INIT)) {
- status = acpi_ev_install_fadt_gpes();
- if (ACPI_FAILURE(status))
- return (status);
- }
-
- /*
* Empty the caches (delete the cached objects) on the assumption that
* the table load filled them up more than they will be at runtime --
* thus wasting non-paged memory.
@@ -506,6 +502,7 @@ acpi_install_initialization_handler(acpi_init_handler handler, u32 function)
ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler)
#endif /* ACPI_FUTURE_USAGE */
+
/*****************************************************************************
*
* FUNCTION: acpi_purge_cached_objects
@@ -529,4 +526,117 @@ acpi_status acpi_purge_cached_objects(void)
}
ACPI_EXPORT_SYMBOL(acpi_purge_cached_objects)
-#endif
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_install_interface
+ *
+ * PARAMETERS: interface_name - The interface to install
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install an _OSI interface to the global list
+ *
+ ****************************************************************************/
+acpi_status acpi_install_interface(acpi_string interface_name)
+{
+ acpi_status status;
+ struct acpi_interface_info *interface_info;
+
+ /* Parameter validation */
+
+ if (!interface_name || (ACPI_STRLEN(interface_name) == 0)) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+
+ /* Check if the interface name is already in the global list */
+
+ interface_info = acpi_ut_get_interface(interface_name);
+ if (interface_info) {
+ /*
+ * The interface already exists in the list. This is OK if the
+ * interface has been marked invalid -- just clear the bit.
+ */
+ if (interface_info->flags & ACPI_OSI_INVALID) {
+ interface_info->flags &= ~ACPI_OSI_INVALID;
+ status = AE_OK;
+ } else {
+ status = AE_ALREADY_EXISTS;
+ }
+ } else {
+ /* New interface name, install into the global list */
+
+ status = acpi_ut_install_interface(interface_name);
+ }
+
+ acpi_os_release_mutex(acpi_gbl_osi_mutex);
+ return (status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_interface)
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_remove_interface
+ *
+ * PARAMETERS: interface_name - The interface to remove
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove an _OSI interface from the global list
+ *
+ ****************************************************************************/
+acpi_status acpi_remove_interface(acpi_string interface_name)
+{
+ acpi_status status;
+
+ /* Parameter validation */
+
+ if (!interface_name || (ACPI_STRLEN(interface_name) == 0)) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+
+ status = acpi_ut_remove_interface(interface_name);
+
+ acpi_os_release_mutex(acpi_gbl_osi_mutex);
+ return (status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_remove_interface)
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_install_interface_handler
+ *
+ * PARAMETERS: Handler - The _OSI interface handler to install
+ * NULL means "remove existing handler"
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install a handler for the predefined _OSI ACPI method.
+ * invoked during execution of the internal implementation of
+ * _OSI. A NULL handler simply removes any existing handler.
+ *
+ ****************************************************************************/
+acpi_status acpi_install_interface_handler(acpi_interface_handler handler)
+{
+ acpi_status status = AE_OK;
+
+ (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+
+ if (handler && acpi_gbl_interface_handler) {
+ status = AE_ALREADY_EXISTS;
+ } else {
+ acpi_gbl_interface_handler = handler;
+ }
+
+ acpi_os_release_mutex(acpi_gbl_osi_mutex);
+ return (status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_interface_handler)
+#endif /* !ACPI_ASL_COMPILER */
diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c
new file mode 100644
index 000000000000..6f12e314fbae
--- /dev/null
+++ b/drivers/acpi/acpica/utxferror.c
@@ -0,0 +1,415 @@
+/*******************************************************************************
+ *
+ * Module Name: utxferror - Various error/warning output functions
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2010, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+
+#define _COMPONENT ACPI_UTILITIES
+ACPI_MODULE_NAME("utxferror")
+
+/*
+ * This module is used for the in-kernel ACPICA as well as the ACPICA
+ * tools/applications.
+ *
+ * For the i_aSL compiler case, the output is redirected to stderr so that
+ * any of the various ACPI errors and warnings do not appear in the output
+ * files, for either the compiler or disassembler portions of the tool.
+ */
+#ifdef ACPI_ASL_COMPILER
+#include <stdio.h>
+extern FILE *acpi_gbl_output_file;
+
+#define ACPI_MSG_REDIRECT_BEGIN \
+ FILE *output_file = acpi_gbl_output_file; \
+ acpi_os_redirect_output (stderr);
+
+#define ACPI_MSG_REDIRECT_END \
+ acpi_os_redirect_output (output_file);
+
+#else
+/*
+ * non-i_aSL case - no redirection, nothing to do
+ */
+#define ACPI_MSG_REDIRECT_BEGIN
+#define ACPI_MSG_REDIRECT_END
+#endif
+/*
+ * Common message prefixes
+ */
+#define ACPI_MSG_ERROR "ACPI Error: "
+#define ACPI_MSG_EXCEPTION "ACPI Exception: "
+#define ACPI_MSG_WARNING "ACPI Warning: "
+#define ACPI_MSG_INFO "ACPI: "
+/*
+ * Common message suffix
+ */
+#define ACPI_MSG_SUFFIX \
+ acpi_os_printf (" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number)
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_error
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * Format - Printf format string + additional args
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print "ACPI Error" message with module/line/version info
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_error(const char *module_name, u32 line_number, const char *format, ...)
+{
+ va_list arg_list;
+
+ ACPI_MSG_REDIRECT_BEGIN;
+ acpi_os_printf(ACPI_MSG_ERROR);
+
+ va_start(arg_list, format);
+ acpi_os_vprintf(format, arg_list);
+ ACPI_MSG_SUFFIX;
+ va_end(arg_list);
+
+ ACPI_MSG_REDIRECT_END;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_error)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_exception
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * Status - Status to be formatted
+ * Format - Printf format string + additional args
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print "ACPI Exception" message with module/line/version info
+ * and decoded acpi_status.
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_exception(const char *module_name,
+ u32 line_number, acpi_status status, const char *format, ...)
+{
+ va_list arg_list;
+
+ ACPI_MSG_REDIRECT_BEGIN;
+ acpi_os_printf(ACPI_MSG_EXCEPTION "%s, ",
+ acpi_format_exception(status));
+
+ va_start(arg_list, format);
+ acpi_os_vprintf(format, arg_list);
+ ACPI_MSG_SUFFIX;
+ va_end(arg_list);
+
+ ACPI_MSG_REDIRECT_END;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_exception)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_warning
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * Format - Printf format string + additional args
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print "ACPI Warning" message with module/line/version info
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_warning(const char *module_name, u32 line_number, const char *format, ...)
+{
+ va_list arg_list;
+
+ ACPI_MSG_REDIRECT_BEGIN;
+ acpi_os_printf(ACPI_MSG_WARNING);
+
+ va_start(arg_list, format);
+ acpi_os_vprintf(format, arg_list);
+ ACPI_MSG_SUFFIX;
+ va_end(arg_list);
+
+ ACPI_MSG_REDIRECT_END;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_warning)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_info
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * Format - Printf format string + additional args
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print generic "ACPI:" information message. There is no
+ * module/line/version info in order to keep the message simple.
+ *
+ * TBD: module_name and line_number args are not needed, should be removed.
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_info(const char *module_name, u32 line_number, const char *format, ...)
+{
+ va_list arg_list;
+
+ ACPI_MSG_REDIRECT_BEGIN;
+ acpi_os_printf(ACPI_MSG_INFO);
+
+ va_start(arg_list, format);
+ acpi_os_vprintf(format, arg_list);
+ acpi_os_printf("\n");
+ va_end(arg_list);
+
+ ACPI_MSG_REDIRECT_END;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_info)
+
+/*
+ * The remainder of this module contains internal error functions that may
+ * be configured out.
+ */
+#if !defined (ACPI_NO_ERROR_MESSAGES) && !defined (ACPI_BIN_APP)
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_predefined_warning
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * Pathname - Full pathname to the node
+ * node_flags - From Namespace node for the method/object
+ * Format - Printf format string + additional args
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Warnings for the predefined validation module. Messages are
+ * only emitted the first time a problem with a particular
+ * method/object is detected. This prevents a flood of error
+ * messages for methods that are repeatedly evaluated.
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_warning(const char *module_name,
+ u32 line_number,
+ char *pathname,
+ u8 node_flags, const char *format, ...)
+{
+ va_list arg_list;
+
+ /*
+ * Warning messages for this method/object will be disabled after the
+ * first time a validation fails or an object is successfully repaired.
+ */
+ if (node_flags & ANOBJ_EVALUATED) {
+ return;
+ }
+
+ acpi_os_printf(ACPI_MSG_WARNING "For %s: ", pathname);
+
+ va_start(arg_list, format);
+ acpi_os_vprintf(format, arg_list);
+ ACPI_MSG_SUFFIX;
+ va_end(arg_list);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_predefined_info
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * Pathname - Full pathname to the node
+ * node_flags - From Namespace node for the method/object
+ * Format - Printf format string + additional args
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Info messages for the predefined validation module. Messages
+ * are only emitted the first time a problem with a particular
+ * method/object is detected. This prevents a flood of
+ * messages for methods that are repeatedly evaluated.
+ *
+ ******************************************************************************/
+
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_info(const char *module_name,
+ u32 line_number,
+ char *pathname, u8 node_flags, const char *format, ...)
+{
+ va_list arg_list;
+
+ /*
+ * Warning messages for this method/object will be disabled after the
+ * first time a validation fails or an object is successfully repaired.
+ */
+ if (node_flags & ANOBJ_EVALUATED) {
+ return;
+ }
+
+ acpi_os_printf(ACPI_MSG_INFO "For %s: ", pathname);
+
+ va_start(arg_list, format);
+ acpi_os_vprintf(format, arg_list);
+ ACPI_MSG_SUFFIX;
+ va_end(arg_list);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_namespace_error
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * internal_name - Name or path of the namespace node
+ * lookup_status - Exception code from NS lookup
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print error message with the full pathname for the NS node.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_namespace_error(const char *module_name,
+ u32 line_number,
+ const char *internal_name, acpi_status lookup_status)
+{
+ acpi_status status;
+ u32 bad_name;
+ char *name = NULL;
+
+ ACPI_MSG_REDIRECT_BEGIN;
+ acpi_os_printf(ACPI_MSG_ERROR);
+
+ if (lookup_status == AE_BAD_CHARACTER) {
+
+ /* There is a non-ascii character in the name */
+
+ ACPI_MOVE_32_TO_32(&bad_name,
+ ACPI_CAST_PTR(u32, internal_name));
+ acpi_os_printf("[0x%4.4X] (NON-ASCII)", bad_name);
+ } else {
+ /* Convert path to external format */
+
+ status = acpi_ns_externalize_name(ACPI_UINT32_MAX,
+ internal_name, NULL, &name);
+
+ /* Print target name */
+
+ if (ACPI_SUCCESS(status)) {
+ acpi_os_printf("[%s]", name);
+ } else {
+ acpi_os_printf("[COULD NOT EXTERNALIZE NAME]");
+ }
+
+ if (name) {
+ ACPI_FREE(name);
+ }
+ }
+
+ acpi_os_printf(" Namespace lookup failure, %s",
+ acpi_format_exception(lookup_status));
+
+ ACPI_MSG_SUFFIX;
+ ACPI_MSG_REDIRECT_END;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_method_error
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * Message - Error message to use on failure
+ * prefix_node - Prefix relative to the path
+ * Path - Path to the node (optional)
+ * method_status - Execution status
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print error message with the full pathname for the method.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_method_error(const char *module_name,
+ u32 line_number,
+ const char *message,
+ struct acpi_namespace_node *prefix_node,
+ const char *path, acpi_status method_status)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node = prefix_node;
+
+ ACPI_MSG_REDIRECT_BEGIN;
+ acpi_os_printf(ACPI_MSG_ERROR);
+
+ if (path) {
+ status =
+ acpi_ns_get_node(prefix_node, path, ACPI_NS_NO_UPSEARCH,
+ &node);
+ if (ACPI_FAILURE(status)) {
+ acpi_os_printf("[Could not get node by pathname]");
+ }
+ }
+
+ acpi_ns_print_node_pathname(node, message);
+ acpi_os_printf(", %s", acpi_format_exception(method_status));
+
+ ACPI_MSG_SUFFIX;
+ ACPI_MSG_REDIRECT_END;
+}
+
+#endif /* ACPI_NO_ERROR_MESSAGES */
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 98417201e9ce..95649d373071 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -42,10 +42,7 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
-
-#ifdef CONFIG_ACPI_SYSFS_POWER
#include <linux/power_supply.h>
-#endif
#define PREFIX "ACPI: "
@@ -98,13 +95,12 @@ enum {
* due to bad math.
*/
ACPI_BATTERY_QUIRK_SIGNED16_CURRENT,
+ ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY,
};
struct acpi_battery {
struct mutex lock;
-#ifdef CONFIG_ACPI_SYSFS_POWER
struct power_supply bat;
-#endif
struct acpi_device *device;
unsigned long update_time;
int rate_now;
@@ -141,7 +137,6 @@ inline int acpi_battery_present(struct acpi_battery *battery)
return battery->device->status.battery_present;
}
-#ifdef CONFIG_ACPI_SYSFS_POWER
static int acpi_battery_technology(struct acpi_battery *battery)
{
if (!strcasecmp("NiCd", battery->type))
@@ -186,6 +181,7 @@ static int acpi_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
+ int ret = 0;
struct acpi_battery *battery = to_acpi_battery(psy);
if (acpi_battery_present(battery)) {
@@ -214,26 +210,44 @@ static int acpi_battery_get_property(struct power_supply *psy,
val->intval = battery->cycle_count;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
- val->intval = battery->design_voltage * 1000;
+ if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
+ ret = -ENODEV;
+ else
+ val->intval = battery->design_voltage * 1000;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
- val->intval = battery->voltage_now * 1000;
+ if (battery->voltage_now == ACPI_BATTERY_VALUE_UNKNOWN)
+ ret = -ENODEV;
+ else
+ val->intval = battery->voltage_now * 1000;
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
case POWER_SUPPLY_PROP_POWER_NOW:
- val->intval = battery->rate_now * 1000;
+ if (battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN)
+ ret = -ENODEV;
+ else
+ val->intval = battery->rate_now * 1000;
break;
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
- val->intval = battery->design_capacity * 1000;
+ if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+ ret = -ENODEV;
+ else
+ val->intval = battery->design_capacity * 1000;
break;
case POWER_SUPPLY_PROP_CHARGE_FULL:
case POWER_SUPPLY_PROP_ENERGY_FULL:
- val->intval = battery->full_charge_capacity * 1000;
+ if (battery->full_charge_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+ ret = -ENODEV;
+ else
+ val->intval = battery->full_charge_capacity * 1000;
break;
case POWER_SUPPLY_PROP_CHARGE_NOW:
case POWER_SUPPLY_PROP_ENERGY_NOW:
- val->intval = battery->capacity_now * 1000;
+ if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN)
+ ret = -ENODEV;
+ else
+ val->intval = battery->capacity_now * 1000;
break;
case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = battery->model_number;
@@ -245,9 +259,9 @@ static int acpi_battery_get_property(struct power_supply *psy,
val->strval = battery->serial_number;
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+ return ret;
}
static enum power_supply_property charge_battery_props[] = {
@@ -281,7 +295,6 @@ static enum power_supply_property energy_battery_props[] = {
POWER_SUPPLY_PROP_MANUFACTURER,
POWER_SUPPLY_PROP_SERIAL_NUMBER,
};
-#endif
#ifdef CONFIG_ACPI_PROCFS_POWER
inline char *acpi_battery_units(struct acpi_battery *battery)
@@ -412,6 +425,8 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
result = extract_package(battery, buffer.pointer,
info_offsets, ARRAY_SIZE(info_offsets));
kfree(buffer.pointer);
+ if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
+ battery->full_charge_capacity = battery->design_capacity;
return result;
}
@@ -448,6 +463,10 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
battery->rate_now != -1)
battery->rate_now = abs((s16)battery->rate_now);
+ if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)
+ && battery->capacity_now >= 0 && battery->capacity_now <= 100)
+ battery->capacity_now = (battery->capacity_now *
+ battery->full_charge_capacity) / 100;
return result;
}
@@ -492,7 +511,6 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery)
return acpi_battery_set_alarm(battery);
}
-#ifdef CONFIG_ACPI_SYSFS_POWER
static ssize_t acpi_battery_alarm_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -552,7 +570,6 @@ static void sysfs_remove_battery(struct acpi_battery *battery)
power_supply_unregister(&battery->bat);
battery->bat.dev = NULL;
}
-#endif
static void acpi_battery_quirks(struct acpi_battery *battery)
{
@@ -561,6 +578,33 @@ static void acpi_battery_quirks(struct acpi_battery *battery)
}
}
+/*
+ * According to the ACPI spec, some kinds of primary batteries can
+ * report percentage battery remaining capacity directly to OS.
+ * In this case, it reports the Last Full Charged Capacity == 100
+ * and BatteryPresentRate == 0xFFFFFFFF.
+ *
+ * Now we found some battery reports percentage remaining capacity
+ * even if it's rechargeable.
+ * https://bugzilla.kernel.org/show_bug.cgi?id=15979
+ *
+ * Handle this correctly so that they won't break userspace.
+ */
+static void acpi_battery_quirks2(struct acpi_battery *battery)
+{
+ if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
+ return ;
+
+ if (battery->full_charge_capacity == 100 &&
+ battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN &&
+ battery->capacity_now >=0 && battery->capacity_now <= 100) {
+ set_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags);
+ battery->full_charge_capacity = battery->design_capacity;
+ battery->capacity_now = (battery->capacity_now *
+ battery->full_charge_capacity) / 100;
+ }
+}
+
static int acpi_battery_update(struct acpi_battery *battery)
{
int result, old_present = acpi_battery_present(battery);
@@ -568,9 +612,7 @@ static int acpi_battery_update(struct acpi_battery *battery)
if (result)
return result;
if (!acpi_battery_present(battery)) {
-#ifdef CONFIG_ACPI_SYSFS_POWER
sysfs_remove_battery(battery);
-#endif
battery->update_time = 0;
return 0;
}
@@ -582,11 +624,11 @@ static int acpi_battery_update(struct acpi_battery *battery)
acpi_battery_quirks(battery);
acpi_battery_init_alarm(battery);
}
-#ifdef CONFIG_ACPI_SYSFS_POWER
if (!battery->bat.dev)
sysfs_add_battery(battery);
-#endif
- return acpi_battery_get_state(battery);
+ result = acpi_battery_get_state(battery);
+ acpi_battery_quirks2(battery);
+ return result;
}
/* --------------------------------------------------------------------------
@@ -867,26 +909,20 @@ static void acpi_battery_remove_fs(struct acpi_device *device)
static void acpi_battery_notify(struct acpi_device *device, u32 event)
{
struct acpi_battery *battery = acpi_driver_data(device);
-#ifdef CONFIG_ACPI_SYSFS_POWER
struct device *old;
-#endif
if (!battery)
return;
-#ifdef CONFIG_ACPI_SYSFS_POWER
old = battery->bat.dev;
-#endif
acpi_battery_update(battery);
acpi_bus_generate_proc_event(device, event,
acpi_battery_present(battery));
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event,
acpi_battery_present(battery));
-#ifdef CONFIG_ACPI_SYSFS_POWER
/* acpi_battery_update could remove power_supply object */
if (old && battery->bat.dev)
power_supply_changed(&battery->bat);
-#endif
}
static int acpi_battery_add(struct acpi_device *device)
@@ -934,9 +970,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_battery_remove_fs(device);
#endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
sysfs_remove_battery(battery);
-#endif
mutex_destroy(&battery->lock);
kfree(battery);
return 0;
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 310e3b9749cb..d68bd61072bb 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -935,6 +935,12 @@ static int __init acpi_bus_init(void)
goto error1;
}
+ /*
+ * _PDC control method may load dynamic SSDT tables,
+ * and we need to install the table handler before that.
+ */
+ acpi_sysfs_init();
+
acpi_early_processor_set_pdc();
/*
@@ -1026,7 +1032,6 @@ static int __init acpi_init(void)
acpi_scan_init();
acpi_ec_init();
acpi_power_init();
- acpi_sysfs_init();
acpi_debugfs_init();
acpi_sleep_proc_init();
acpi_wakeup_device_init();
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 1575a9b51f1d..71ef9cd0735f 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -338,7 +338,8 @@ static int acpi_button_add(struct acpi_device *device)
{
struct acpi_button *button;
struct input_dev *input;
- char *hid, *name, *class;
+ const char *hid = acpi_device_hid(device);
+ char *name, *class;
int error;
button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL);
@@ -353,7 +354,6 @@ static int acpi_button_add(struct acpi_device *device)
goto err_free_button;
}
- hid = acpi_device_hid(device);
name = acpi_device_name(device);
class = acpi_device_class(device);
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 3fe29e992be8..81514a4918cc 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -725,6 +725,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
complete_dock(ds);
dock_event(ds, event, DOCK_EVENT);
dock_lock(ds, 1);
+ acpi_update_gpes();
break;
}
if (dock_present(ds) || dock_in_progress(ds))
@@ -929,7 +930,7 @@ static struct attribute_group dock_attribute_group = {
* allocated and initialize a new dock station device. Find all devices
* that are on the dock station, and register for dock event notifications.
*/
-static int dock_add(acpi_handle handle)
+static int __init dock_add(acpi_handle handle)
{
int ret, id;
struct dock_station ds, *dock_station;
@@ -1023,7 +1024,7 @@ static int dock_remove(struct dock_station *ds)
*
* This is called by acpi_walk_namespace to look for dock stations.
*/
-static acpi_status
+static __init acpi_status
find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
{
if (is_dock(handle))
@@ -1032,7 +1033,7 @@ find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
}
-static acpi_status
+static __init acpi_status
find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
{
/* If bay is a dock, it's already handled */
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index f31291ba94d0..372ff80b7b0c 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -83,6 +83,11 @@ enum {
EC_FLAGS_BLOCKED, /* Transactions are blocked */
};
+/* ec.c is compiled in acpi namespace so this shows up as acpi.ec_delay param */
+static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
+module_param(ec_delay, uint, 0644);
+MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes");
+
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
/* External interfaces use first EC only, so remember */
typedef int (*acpi_ec_query_func) (void *data);
@@ -210,7 +215,7 @@ static int ec_poll(struct acpi_ec *ec)
int repeat = 2; /* number of command restarts */
while (repeat--) {
unsigned long delay = jiffies +
- msecs_to_jiffies(ACPI_EC_DELAY);
+ msecs_to_jiffies(ec_delay);
do {
/* don't sleep with disabled interrupts */
if (EC_FLAGS_MSI || irqs_disabled()) {
@@ -265,7 +270,7 @@ static int ec_check_ibf0(struct acpi_ec *ec)
static int ec_wait_ibf0(struct acpi_ec *ec)
{
- unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
+ unsigned long delay = jiffies + msecs_to_jiffies(ec_delay);
/* interrupt wait manually if GPE mode is not active */
while (time_before(jiffies, delay))
if (wait_event_timeout(ec->wait, ec_check_ibf0(ec),
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index d94d2953c974..60049080c869 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -27,8 +27,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include <linux/thermal.h>
#include <acpi/acpi_bus.h>
@@ -119,122 +117,6 @@ static struct thermal_cooling_device_ops fan_cooling_ops = {
};
/* --------------------------------------------------------------------------
- FS Interface (/proc)
- -------------------------------------------------------------------------- */
-#ifdef CONFIG_ACPI_PROCFS
-
-static struct proc_dir_entry *acpi_fan_dir;
-
-static int acpi_fan_read_state(struct seq_file *seq, void *offset)
-{
- struct acpi_device *device = seq->private;
- int state = 0;
-
-
- if (device) {
- if (acpi_bus_get_power(device->handle, &state))
- seq_printf(seq, "status: ERROR\n");
- else
- seq_printf(seq, "status: %s\n",
- !state ? "on" : "off");
- }
- return 0;
-}
-
-static int acpi_fan_state_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_fan_read_state, PDE(inode)->data);
-}
-
-static ssize_t
-acpi_fan_write_state(struct file *file, const char __user * buffer,
- size_t count, loff_t * ppos)
-{
- int result = 0;
- struct seq_file *m = file->private_data;
- struct acpi_device *device = m->private;
- char state_string[3] = { '\0' };
-
- if (count > sizeof(state_string) - 1)
- return -EINVAL;
-
- if (copy_from_user(state_string, buffer, count))
- return -EFAULT;
-
- state_string[count] = '\0';
- if ((state_string[0] < '0') || (state_string[0] > '3'))
- return -EINVAL;
- if (state_string[1] == '\n')
- state_string[1] = '\0';
- if (state_string[1] != '\0')
- return -EINVAL;
-
- result = acpi_bus_set_power(device->handle,
- simple_strtoul(state_string, NULL, 0));
- if (result)
- return result;
-
- return count;
-}
-
-static const struct file_operations acpi_fan_state_ops = {
- .open = acpi_fan_state_open_fs,
- .read = seq_read,
- .write = acpi_fan_write_state,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static int acpi_fan_add_fs(struct acpi_device *device)
-{
- struct proc_dir_entry *entry = NULL;
-
-
- if (!device)
- return -EINVAL;
-
- if (!acpi_device_dir(device)) {
- acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
- acpi_fan_dir);
- if (!acpi_device_dir(device))
- return -ENODEV;
- }
-
- /* 'status' [R/W] */
- entry = proc_create_data(ACPI_FAN_FILE_STATE,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device),
- &acpi_fan_state_ops,
- device);
- if (!entry)
- return -ENODEV;
- return 0;
-}
-
-static int acpi_fan_remove_fs(struct acpi_device *device)
-{
-
- if (acpi_device_dir(device)) {
- remove_proc_entry(ACPI_FAN_FILE_STATE, acpi_device_dir(device));
- remove_proc_entry(acpi_device_bid(device), acpi_fan_dir);
- acpi_device_dir(device) = NULL;
- }
-
- return 0;
-}
-#else
-static int acpi_fan_add_fs(struct acpi_device *device)
-{
- return 0;
-}
-
-static int acpi_fan_remove_fs(struct acpi_device *device)
-{
- return 0;
-}
-#endif
-/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
@@ -284,10 +166,6 @@ static int acpi_fan_add(struct acpi_device *device)
dev_err(&device->dev, "Failed to create sysfs link "
"'device'\n");
- result = acpi_fan_add_fs(device);
- if (result)
- goto end;
-
printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
acpi_device_name(device), acpi_device_bid(device),
!device->power.state ? "on" : "off");
@@ -303,7 +181,6 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
if (!device || !cdev)
return -EINVAL;
- acpi_fan_remove_fs(device);
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
sysfs_remove_link(&cdev->device.kobj, "device");
thermal_cooling_device_unregister(cdev);
@@ -347,19 +224,9 @@ static int __init acpi_fan_init(void)
{
int result = 0;
-#ifdef CONFIG_ACPI_PROCFS
- acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
- if (!acpi_fan_dir)
- return -ENODEV;
-#endif
-
result = acpi_bus_register_driver(&acpi_fan_driver);
- if (result < 0) {
-#ifdef CONFIG_ACPI_PROCFS
- remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
-#endif
+ if (result < 0)
return -ENODEV;
- }
return 0;
}
@@ -369,10 +236,6 @@ static void __exit acpi_fan_exit(void)
acpi_bus_unregister_driver(&acpi_fan_driver);
-#ifdef CONFIG_ACPI_PROCFS
- remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
-#endif
-
return;
}
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 65b25a303b86..966feddf6b1b 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -95,8 +95,25 @@ struct acpi_res_list {
static LIST_HEAD(resource_list_head);
static DEFINE_SPINLOCK(acpi_res_lock);
+/*
+ * This list of permanent mappings is for memory that may be accessed from
+ * interrupt context, where we can't do the ioremap().
+ */
+struct acpi_ioremap {
+ struct list_head list;
+ void __iomem *virt;
+ acpi_physical_address phys;
+ acpi_size size;
+ struct kref ref;
+};
+
+static LIST_HEAD(acpi_ioremaps);
+static DEFINE_SPINLOCK(acpi_ioremap_lock);
+
#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
-static char osi_additional_string[OSI_STRING_LENGTH_MAX];
+static char osi_setup_string[OSI_STRING_LENGTH_MAX];
+
+static void __init acpi_osi_setup_late(void);
/*
* The story of _OSI(Linux)
@@ -138,6 +155,20 @@ static struct osi_linux {
unsigned int known:1;
} osi_linux = { 0, 0, 0, 0};
+static u32 acpi_osi_handler(acpi_string interface, u32 supported)
+{
+ if (!strcmp("Linux", interface)) {
+
+ printk(KERN_NOTICE FW_BUG PREFIX
+ "BIOS _OSI(Linux) query %s%s\n",
+ osi_linux.enable ? "honored" : "ignored",
+ osi_linux.cmdline ? " via cmdline" :
+ osi_linux.dmi ? " via DMI" : "");
+ }
+
+ return supported;
+}
+
static void __init acpi_request_region (struct acpi_generic_address *addr,
unsigned int length, char *desc)
{
@@ -185,36 +216,6 @@ static int __init acpi_reserve_resources(void)
}
device_initcall(acpi_reserve_resources);
-acpi_status __init acpi_os_initialize(void)
-{
- return AE_OK;
-}
-
-acpi_status acpi_os_initialize1(void)
-{
- kacpid_wq = create_workqueue("kacpid");
- kacpi_notify_wq = create_workqueue("kacpi_notify");
- kacpi_hotplug_wq = create_workqueue("kacpi_hotplug");
- BUG_ON(!kacpid_wq);
- BUG_ON(!kacpi_notify_wq);
- BUG_ON(!kacpi_hotplug_wq);
- return AE_OK;
-}
-
-acpi_status acpi_os_terminate(void)
-{
- if (acpi_irq_handler) {
- acpi_os_remove_interrupt_handler(acpi_irq_irq,
- acpi_irq_handler);
- }
-
- destroy_workqueue(kacpid_wq);
- destroy_workqueue(kacpi_notify_wq);
- destroy_workqueue(kacpi_hotplug_wq);
-
- return AE_OK;
-}
-
void acpi_os_printf(const char *fmt, ...)
{
va_list args;
@@ -260,29 +261,135 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
}
}
+/* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */
+static struct acpi_ioremap *
+acpi_map_lookup(acpi_physical_address phys, acpi_size size)
+{
+ struct acpi_ioremap *map;
+
+ list_for_each_entry_rcu(map, &acpi_ioremaps, list)
+ if (map->phys <= phys &&
+ phys + size <= map->phys + map->size)
+ return map;
+
+ return NULL;
+}
+
+/* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */
+static void __iomem *
+acpi_map_vaddr_lookup(acpi_physical_address phys, unsigned int size)
+{
+ struct acpi_ioremap *map;
+
+ map = acpi_map_lookup(phys, size);
+ if (map)
+ return map->virt + (phys - map->phys);
+
+ return NULL;
+}
+
+/* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */
+static struct acpi_ioremap *
+acpi_map_lookup_virt(void __iomem *virt, acpi_size size)
+{
+ struct acpi_ioremap *map;
+
+ list_for_each_entry_rcu(map, &acpi_ioremaps, list)
+ if (map->virt <= virt &&
+ virt + size <= map->virt + map->size)
+ return map;
+
+ return NULL;
+}
+
void __iomem *__init_refok
acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
{
+ struct acpi_ioremap *map, *tmp_map;
+ unsigned long flags, pg_sz;
+ void __iomem *virt;
+ phys_addr_t pg_off;
+
if (phys > ULONG_MAX) {
printk(KERN_ERR PREFIX "Cannot map memory that high\n");
return NULL;
}
- if (acpi_gbl_permanent_mmap)
- /*
- * ioremap checks to ensure this is in reserved space
- */
- return ioremap((unsigned long)phys, size);
- else
+
+ if (!acpi_gbl_permanent_mmap)
return __acpi_map_table((unsigned long)phys, size);
+
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (!map)
+ return NULL;
+
+ pg_off = round_down(phys, PAGE_SIZE);
+ pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off;
+ virt = ioremap(pg_off, pg_sz);
+ if (!virt) {
+ kfree(map);
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&map->list);
+ map->virt = virt;
+ map->phys = pg_off;
+ map->size = pg_sz;
+ kref_init(&map->ref);
+
+ spin_lock_irqsave(&acpi_ioremap_lock, flags);
+ /* Check if page has already been mapped. */
+ tmp_map = acpi_map_lookup(phys, size);
+ if (tmp_map) {
+ kref_get(&tmp_map->ref);
+ spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+ iounmap(map->virt);
+ kfree(map);
+ return tmp_map->virt + (phys - tmp_map->phys);
+ }
+ list_add_tail_rcu(&map->list, &acpi_ioremaps);
+ spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+
+ return map->virt + (phys - map->phys);
}
EXPORT_SYMBOL_GPL(acpi_os_map_memory);
+static void acpi_kref_del_iomap(struct kref *ref)
+{
+ struct acpi_ioremap *map;
+
+ map = container_of(ref, struct acpi_ioremap, ref);
+ list_del_rcu(&map->list);
+}
+
void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
{
- if (acpi_gbl_permanent_mmap)
- iounmap(virt);
- else
+ struct acpi_ioremap *map;
+ unsigned long flags;
+ int del;
+
+ if (!acpi_gbl_permanent_mmap) {
__acpi_unmap_table(virt, size);
+ return;
+ }
+
+ spin_lock_irqsave(&acpi_ioremap_lock, flags);
+ map = acpi_map_lookup_virt(virt, size);
+ if (!map) {
+ spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+ printk(KERN_ERR PREFIX "%s: bad address %p\n", __func__, virt);
+ dump_stack();
+ return;
+ }
+
+ del = kref_put(&map->ref, acpi_kref_del_iomap);
+ spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+
+ if (!del)
+ return;
+
+ synchronize_rcu();
+ iounmap(map->virt);
+ kfree(map);
}
EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
@@ -292,6 +399,44 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
__acpi_unmap_table(virt, size);
}
+int acpi_os_map_generic_address(struct acpi_generic_address *addr)
+{
+ void __iomem *virt;
+
+ if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
+ return 0;
+
+ if (!addr->address || !addr->bit_width)
+ return -EINVAL;
+
+ virt = acpi_os_map_memory(addr->address, addr->bit_width / 8);
+ if (!virt)
+ return -EIO;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_os_map_generic_address);
+
+void acpi_os_unmap_generic_address(struct acpi_generic_address *addr)
+{
+ void __iomem *virt;
+ unsigned long flags;
+ acpi_size size = addr->bit_width / 8;
+
+ if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
+ return;
+
+ if (!addr->address || !addr->bit_width)
+ return;
+
+ spin_lock_irqsave(&acpi_ioremap_lock, flags);
+ virt = acpi_map_vaddr_lookup(addr->address, size);
+ spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+
+ acpi_os_unmap_memory(virt, size);
+}
+EXPORT_SYMBOL_GPL(acpi_os_unmap_generic_address);
+
#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_os_get_physical_address(void *virt, acpi_physical_address * phys)
@@ -495,8 +640,15 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
{
u32 dummy;
void __iomem *virt_addr;
-
- virt_addr = ioremap(phys_addr, width);
+ int size = width / 8, unmap = 0;
+
+ rcu_read_lock();
+ virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
+ rcu_read_unlock();
+ if (!virt_addr) {
+ virt_addr = ioremap(phys_addr, size);
+ unmap = 1;
+ }
if (!value)
value = &dummy;
@@ -514,7 +666,8 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
BUG();
}
- iounmap(virt_addr);
+ if (unmap)
+ iounmap(virt_addr);
return AE_OK;
}
@@ -523,8 +676,15 @@ acpi_status
acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
{
void __iomem *virt_addr;
-
- virt_addr = ioremap(phys_addr, width);
+ int size = width / 8, unmap = 0;
+
+ rcu_read_lock();
+ virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
+ rcu_read_unlock();
+ if (!virt_addr) {
+ virt_addr = ioremap(phys_addr, size);
+ unmap = 1;
+ }
switch (width) {
case 8:
@@ -540,16 +700,18 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
BUG();
}
- iounmap(virt_addr);
+ if (unmap)
+ iounmap(virt_addr);
return AE_OK;
}
acpi_status
acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
- u32 *value, u32 width)
+ u64 *value, u32 width)
{
int result, size;
+ u32 value32;
if (!value)
return AE_BAD_PARAMETER;
@@ -570,7 +732,8 @@ acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
result = raw_pci_read(pci_id->segment, pci_id->bus,
PCI_DEVFN(pci_id->device, pci_id->function),
- reg, size, value);
+ reg, size, &value32);
+ *value = value32;
return (result ? AE_ERROR : AE_OK);
}
@@ -602,74 +765,6 @@ acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
return (result ? AE_ERROR : AE_OK);
}
-/* TODO: Change code to take advantage of driver model more */
-static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */
- acpi_handle chandle, /* current node */
- struct acpi_pci_id **id,
- int *is_bridge, u8 * bus_number)
-{
- acpi_handle handle;
- struct acpi_pci_id *pci_id = *id;
- acpi_status status;
- unsigned long long temp;
- acpi_object_type type;
-
- acpi_get_parent(chandle, &handle);
- if (handle != rhandle) {
- acpi_os_derive_pci_id_2(rhandle, handle, &pci_id, is_bridge,
- bus_number);
-
- status = acpi_get_type(handle, &type);
- if ((ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE))
- return;
-
- status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
- &temp);
- if (ACPI_SUCCESS(status)) {
- u32 val;
- pci_id->device = ACPI_HIWORD(ACPI_LODWORD(temp));
- pci_id->function = ACPI_LOWORD(ACPI_LODWORD(temp));
-
- if (*is_bridge)
- pci_id->bus = *bus_number;
-
- /* any nicer way to get bus number of bridge ? */
- status =
- acpi_os_read_pci_configuration(pci_id, 0x0e, &val,
- 8);
- if (ACPI_SUCCESS(status)
- && ((val & 0x7f) == 1 || (val & 0x7f) == 2)) {
- status =
- acpi_os_read_pci_configuration(pci_id, 0x18,
- &val, 8);
- if (!ACPI_SUCCESS(status)) {
- /* Certainly broken... FIX ME */
- return;
- }
- *is_bridge = 1;
- pci_id->bus = val;
- status =
- acpi_os_read_pci_configuration(pci_id, 0x19,
- &val, 8);
- if (ACPI_SUCCESS(status)) {
- *bus_number = val;
- }
- } else
- *is_bridge = 0;
- }
- }
-}
-
-void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */
- acpi_handle chandle, /* current node */
- struct acpi_pci_id **id)
-{
- int is_bridge = 1;
- u8 bus_number = (*id)->bus;
-
- acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number);
-}
-
static void acpi_os_execute_deferred(struct work_struct *work)
{
struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
@@ -780,16 +875,6 @@ void acpi_os_wait_events_complete(void *context)
EXPORT_SYMBOL(acpi_os_wait_events_complete);
/*
- * Allocate the memory for a spinlock and initialize it.
- */
-acpi_status acpi_os_create_lock(acpi_spinlock * handle)
-{
- spin_lock_init(*handle);
-
- return AE_OK;
-}
-
-/*
* Deallocate the memory for a spinlock.
*/
void acpi_os_delete_lock(acpi_spinlock handle)
@@ -977,6 +1062,12 @@ static void __init set_osi_linux(unsigned int enable)
printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n",
enable ? "Add": "Delet");
}
+
+ if (osi_linux.enable)
+ acpi_osi_setup("Linux");
+ else
+ acpi_osi_setup("!Linux");
+
return;
}
@@ -1011,21 +1102,33 @@ void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
* string starting with '!' disables that string
* otherwise string is added to list, augmenting built-in strings
*/
-int __init acpi_osi_setup(char *str)
+static void __init acpi_osi_setup_late(void)
{
- if (str == NULL || *str == '\0') {
- printk(KERN_INFO PREFIX "_OSI method disabled\n");
- acpi_gbl_create_osi_method = FALSE;
- } else if (!strcmp("!Linux", str)) {
+ char *str = osi_setup_string;
+
+ if (*str == '\0')
+ return;
+
+ if (!strcmp("!Linux", str)) {
acpi_cmdline_osi_linux(0); /* !enable */
} else if (*str == '!') {
- if (acpi_osi_invalidate(++str) == AE_OK)
+ if (acpi_remove_interface(++str) == AE_OK)
printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
} else if (!strcmp("Linux", str)) {
acpi_cmdline_osi_linux(1); /* enable */
- } else if (*osi_additional_string == '\0') {
- strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX);
- printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
+ } else {
+ if (acpi_install_interface(str) == AE_OK)
+ printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
+ }
+}
+
+int __init acpi_osi_setup(char *str)
+{
+ if (str == NULL || *str == '\0') {
+ printk(KERN_INFO PREFIX "_OSI method disabled\n");
+ acpi_gbl_create_osi_method = FALSE;
+ } else {
+ strncpy(osi_setup_string, str, OSI_STRING_LENGTH_MAX);
}
return 1;
@@ -1152,21 +1255,6 @@ int acpi_check_region(resource_size_t start, resource_size_t n,
}
EXPORT_SYMBOL(acpi_check_region);
-int acpi_check_mem_region(resource_size_t start, resource_size_t n,
- const char *name)
-{
- struct resource res = {
- .start = start,
- .end = start + n - 1,
- .name = name,
- .flags = IORESOURCE_MEM,
- };
-
- return acpi_check_resource_conflict(&res);
-
-}
-EXPORT_SYMBOL(acpi_check_mem_region);
-
/*
* Let drivers know whether the resource checks are effective
*/
@@ -1282,38 +1370,6 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
return (AE_OK);
}
-/******************************************************************************
- *
- * FUNCTION: acpi_os_validate_interface
- *
- * PARAMETERS: interface - Requested interface to be validated
- *
- * RETURN: AE_OK if interface is supported, AE_SUPPORT otherwise
- *
- * DESCRIPTION: Match an interface string to the interfaces supported by the
- * host. Strings originate from an AML call to the _OSI method.
- *
- *****************************************************************************/
-
-acpi_status
-acpi_os_validate_interface (char *interface)
-{
- if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX))
- return AE_OK;
- if (!strcmp("Linux", interface)) {
-
- printk(KERN_NOTICE PREFIX
- "BIOS _OSI(Linux) query %s%s\n",
- osi_linux.enable ? "honored" : "ignored",
- osi_linux.cmdline ? " via cmdline" :
- osi_linux.dmi ? " via DMI" : "");
-
- if (osi_linux.enable)
- return AE_OK;
- }
- return AE_SUPPORT;
-}
-
static inline int acpi_res_list_add(struct acpi_res_list *res)
{
struct acpi_res_list *res_list_elem;
@@ -1462,5 +1518,46 @@ acpi_os_validate_address (
}
return AE_OK;
}
-
#endif
+
+acpi_status __init acpi_os_initialize(void)
+{
+ acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
+ acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block);
+ acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block);
+ acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block);
+
+ return AE_OK;
+}
+
+acpi_status acpi_os_initialize1(void)
+{
+ kacpid_wq = create_workqueue("kacpid");
+ kacpi_notify_wq = create_workqueue("kacpi_notify");
+ kacpi_hotplug_wq = create_workqueue("kacpi_hotplug");
+ BUG_ON(!kacpid_wq);
+ BUG_ON(!kacpi_notify_wq);
+ BUG_ON(!kacpi_hotplug_wq);
+ acpi_install_interface_handler(acpi_osi_handler);
+ acpi_osi_setup_late();
+ return AE_OK;
+}
+
+acpi_status acpi_os_terminate(void)
+{
+ if (acpi_irq_handler) {
+ acpi_os_remove_interrupt_handler(acpi_irq_irq,
+ acpi_irq_handler);
+ }
+
+ acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe1_block);
+ acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe0_block);
+ acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1b_event_block);
+ acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
+
+ destroy_workqueue(kacpid_wq);
+ destroy_workqueue(kacpi_notify_wq);
+ destroy_workqueue(kacpi_hotplug_wq);
+
+ return AE_OK;
+}
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index e4804fb05e23..f907cfbfa13c 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -32,7 +32,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <linux/pci.h>
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 8d47a5846aeb..9ff80a7e9f6a 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -34,7 +34,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <linux/pci.h>
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 3ba8d1f44a73..96668ad09622 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -27,7 +27,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 844c155aeb0f..67dedeed144c 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -80,18 +80,13 @@ static struct acpi_driver acpi_power_driver = {
},
};
-struct acpi_power_reference {
- struct list_head node;
- struct acpi_device *device;
-};
-
struct acpi_power_resource {
struct acpi_device * device;
acpi_bus_id name;
u32 system_level;
u32 order;
+ unsigned int ref_count;
struct mutex resource_lock;
- struct list_head reference;
};
static struct list_head acpi_power_resource_list;
@@ -184,101 +179,89 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
return result;
}
-static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
+static int __acpi_power_on(struct acpi_power_resource *resource)
{
- int result = 0;
- int found = 0;
acpi_status status = AE_OK;
- struct acpi_power_resource *resource = NULL;
- struct list_head *node, *next;
- struct acpi_power_reference *ref;
+ status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ /* Update the power resource's _device_ power state */
+ resource->device->power.state = ACPI_STATE_D0;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
+ resource->name));
+
+ return 0;
+}
+
+static int acpi_power_on(acpi_handle handle)
+{
+ int result = 0;
+ struct acpi_power_resource *resource = NULL;
result = acpi_power_get_context(handle, &resource);
if (result)
return result;
mutex_lock(&resource->resource_lock);
- list_for_each_safe(node, next, &resource->reference) {
- ref = container_of(node, struct acpi_power_reference, node);
- if (dev->handle == ref->device->handle) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already referenced by resource [%s]\n",
- dev->pnp.bus_id, resource->name));
- found = 1;
- break;
- }
- }
- if (!found) {
- ref = kmalloc(sizeof (struct acpi_power_reference),
- irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
- if (!ref) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "kmalloc() failed\n"));
- mutex_unlock(&resource->resource_lock);
- return -ENOMEM;
- }
- list_add_tail(&ref->node, &resource->reference);
- ref->device = dev;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] added to resource [%s] references\n",
- dev->pnp.bus_id, resource->name));
+ if (resource->ref_count++) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Power resource [%s] already on",
+ resource->name));
+ } else {
+ result = __acpi_power_on(resource);
}
- mutex_unlock(&resource->resource_lock);
- status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- /* Update the power resource's _device_ power state */
- resource->device->power.state = ACPI_STATE_D0;
+ mutex_unlock(&resource->resource_lock);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned on\n",
- resource->name));
return 0;
}
-static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
+static int acpi_power_off_device(acpi_handle handle)
{
int result = 0;
acpi_status status = AE_OK;
struct acpi_power_resource *resource = NULL;
- struct list_head *node, *next;
- struct acpi_power_reference *ref;
result = acpi_power_get_context(handle, &resource);
if (result)
return result;
mutex_lock(&resource->resource_lock);
- list_for_each_safe(node, next, &resource->reference) {
- ref = container_of(node, struct acpi_power_reference, node);
- if (dev->handle == ref->device->handle) {
- list_del(&ref->node);
- kfree(ref);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] removed from resource [%s] references\n",
- dev->pnp.bus_id, resource->name));
- break;
- }
+
+ if (!resource->ref_count) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Power resource [%s] already off",
+ resource->name));
+ goto unlock;
}
- if (!list_empty(&resource->reference)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cannot turn resource [%s] off - resource is in use\n",
- resource->name));
- mutex_unlock(&resource->resource_lock);
- return 0;
+ if (--resource->ref_count) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Power resource [%s] still in use\n",
+ resource->name));
+ goto unlock;
}
- mutex_unlock(&resource->resource_lock);
status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL);
- if (ACPI_FAILURE(status))
- return -ENODEV;
+ if (ACPI_FAILURE(status)) {
+ result = -ENODEV;
+ } else {
+ /* Update the power resource's _device_ power state */
+ resource->device->power.state = ACPI_STATE_D3;
- /* Update the power resource's _device_ power state */
- resource->device->power.state = ACPI_STATE_D3;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Power resource [%s] turned off\n",
+ resource->name));
+ }
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned off\n",
- resource->name));
+ unlock:
+ mutex_unlock(&resource->resource_lock);
- return 0;
+ return result;
}
/**
@@ -364,7 +347,7 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
/* Open power resource */
for (i = 0; i < dev->wakeup.resources.count; i++) {
- int ret = acpi_power_on(dev->wakeup.resources.handles[i], dev);
+ int ret = acpi_power_on(dev->wakeup.resources.handles[i]);
if (ret) {
printk(KERN_ERR PREFIX "Transition power state\n");
dev->wakeup.flags.valid = 0;
@@ -420,7 +403,7 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
/* Close power resource */
for (i = 0; i < dev->wakeup.resources.count; i++) {
int ret = acpi_power_off_device(
- dev->wakeup.resources.handles[i], dev);
+ dev->wakeup.resources.handles[i]);
if (ret) {
printk(KERN_ERR PREFIX "Transition power state\n");
dev->wakeup.flags.valid = 0;
@@ -500,7 +483,7 @@ int acpi_power_transition(struct acpi_device *device, int state)
* (e.g. so the device doesn't lose power while transitioning).
*/
for (i = 0; i < tl->count; i++) {
- result = acpi_power_on(tl->handles[i], device);
+ result = acpi_power_on(tl->handles[i]);
if (result)
goto end;
}
@@ -513,7 +496,7 @@ int acpi_power_transition(struct acpi_device *device, int state)
* Then we dereference all power resources used in the current list.
*/
for (i = 0; i < cl->count; i++) {
- result = acpi_power_off_device(cl->handles[i], device);
+ result = acpi_power_off_device(cl->handles[i]);
if (result)
goto end;
}
@@ -551,7 +534,6 @@ static int acpi_power_add(struct acpi_device *device)
resource->device = device;
mutex_init(&resource->resource_lock);
- INIT_LIST_HEAD(&resource->reference);
strcpy(resource->name, device->pnp.bus_id);
strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
@@ -594,22 +576,14 @@ static int acpi_power_add(struct acpi_device *device)
static int acpi_power_remove(struct acpi_device *device, int type)
{
- struct acpi_power_resource *resource = NULL;
- struct list_head *node, *next;
+ struct acpi_power_resource *resource;
-
- if (!device || !acpi_driver_data(device))
+ if (!device)
return -EINVAL;
resource = acpi_driver_data(device);
-
- mutex_lock(&resource->resource_lock);
- list_for_each_safe(node, next, &resource->reference) {
- struct acpi_power_reference *ref = container_of(node, struct acpi_power_reference, node);
- list_del(&ref->node);
- kfree(ref);
- }
- mutex_unlock(&resource->resource_lock);
+ if (!resource)
+ return -EINVAL;
kfree(resource);
@@ -619,29 +593,28 @@ static int acpi_power_remove(struct acpi_device *device, int type)
static int acpi_power_resume(struct acpi_device *device)
{
int result = 0, state;
- struct acpi_power_resource *resource = NULL;
- struct acpi_power_reference *ref;
+ struct acpi_power_resource *resource;
- if (!device || !acpi_driver_data(device))
+ if (!device)
return -EINVAL;
resource = acpi_driver_data(device);
+ if (!resource)
+ return -EINVAL;
+
+ mutex_lock(&resource->resource_lock);
result = acpi_power_get_state(device->handle, &state);
if (result)
- return result;
+ goto unlock;
- mutex_lock(&resource->resource_lock);
- if (state == ACPI_POWER_RESOURCE_STATE_OFF &&
- !list_empty(&resource->reference)) {
- ref = container_of(resource->reference.next, struct acpi_power_reference, node);
- mutex_unlock(&resource->resource_lock);
- result = acpi_power_on(device->handle, ref->device);
- return result;
- }
+ if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count)
+ result = __acpi_power_on(resource);
+ unlock:
mutex_unlock(&resource->resource_lock);
- return 0;
+
+ return result;
}
int __init acpi_power_init(void)
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 347eb21b2353..85e48047d7b0 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -40,8 +40,10 @@
#include <linux/pm.h>
#include <linux/cpufreq.h>
#include <linux/cpu.h>
+#ifdef CONFIG_ACPI_PROCFS
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#endif
#include <linux/dmi.h>
#include <linux/moduleparam.h>
#include <linux/cpuidle.h>
@@ -244,6 +246,7 @@ static int acpi_processor_errata(struct acpi_processor *pr)
return result;
}
+#ifdef CONFIG_ACPI_PROCFS
static struct proc_dir_entry *acpi_processor_dir = NULL;
static int __cpuinit acpi_processor_add_fs(struct acpi_device *device)
@@ -280,7 +283,16 @@ static int acpi_processor_remove_fs(struct acpi_device *device)
return 0;
}
-
+#else
+static inline int acpi_processor_add_fs(struct acpi_device *device)
+{
+ return 0;
+}
+static inline int acpi_processor_remove_fs(struct acpi_device *device)
+{
+ return 0;
+}
+#endif
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
@@ -842,9 +854,11 @@ static int __init acpi_processor_init(void)
memset(&errata, 0, sizeof(errata));
+#ifdef CONFIG_ACPI_PROCFS
acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
if (!acpi_processor_dir)
return -ENOMEM;
+#endif
if (!cpuidle_register_driver(&acpi_idle_driver)) {
printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
@@ -871,7 +885,9 @@ static int __init acpi_processor_init(void)
out_cpuidle:
cpuidle_unregister_driver(&acpi_idle_driver);
+#ifdef CONFIG_ACPI_PROCFS
remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+#endif
return result;
}
@@ -891,7 +907,9 @@ static void __exit acpi_processor_exit(void)
cpuidle_unregister_driver(&acpi_idle_driver);
+#ifdef CONFIG_ACPI_PROCFS
remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+#endif
return;
}
@@ -899,6 +917,4 @@ static void __exit acpi_processor_exit(void)
module_init(acpi_processor_init);
module_exit(acpi_processor_exit);
-EXPORT_SYMBOL(acpi_processor_set_thermal_limit);
-
MODULE_ALIAS("processor");
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index f4428e82b352..dcb38f8ddfda 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -64,7 +64,6 @@
#define ACPI_PROCESSOR_CLASS "processor"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_idle");
-#define ACPI_PROCESSOR_FILE_POWER "power"
#define PM_TIMER_TICK_NS (1000000000ULL/PM_TIMER_FREQUENCY)
#define C2_OVERHEAD 1 /* 1us */
#define C3_OVERHEAD 1 /* 1us */
@@ -1013,7 +1012,6 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
state->exit_latency = cx->latency;
state->target_residency = cx->latency * latency_factor;
- state->power_usage = cx->power;
state->flags = 0;
switch (cx->type) {
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 953b25fb9869..fde49b9b1d99 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -44,47 +44,6 @@
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_thermal");
-/* --------------------------------------------------------------------------
- Limit Interface
- -------------------------------------------------------------------------- */
-static int acpi_processor_apply_limit(struct acpi_processor *pr)
-{
- int result = 0;
- u16 px = 0;
- u16 tx = 0;
-
-
- if (!pr)
- return -EINVAL;
-
- if (!pr->flags.limit)
- return -ENODEV;
-
- if (pr->flags.throttling) {
- if (pr->limit.user.tx > tx)
- tx = pr->limit.user.tx;
- if (pr->limit.thermal.tx > tx)
- tx = pr->limit.thermal.tx;
-
- result = acpi_processor_set_throttling(pr, tx, false);
- if (result)
- goto end;
- }
-
- pr->limit.state.px = px;
- pr->limit.state.tx = tx;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Processor [%d] limit set to (P%d:T%d)\n", pr->id,
- pr->limit.state.px, pr->limit.state.tx));
-
- end:
- if (result)
- printk(KERN_ERR PREFIX "Unable to set limit\n");
-
- return result;
-}
-
#ifdef CONFIG_CPU_FREQ
/* If a passive cooling situation is detected, primarily CPUfreq is used, as it
@@ -107,36 +66,6 @@ static int cpu_has_cpufreq(unsigned int cpu)
return 1;
}
-static int acpi_thermal_cpufreq_increase(unsigned int cpu)
-{
- if (!cpu_has_cpufreq(cpu))
- return -ENODEV;
-
- if (per_cpu(cpufreq_thermal_reduction_pctg, cpu) <
- CPUFREQ_THERMAL_MAX_STEP) {
- per_cpu(cpufreq_thermal_reduction_pctg, cpu)++;
- cpufreq_update_policy(cpu);
- return 0;
- }
-
- return -ERANGE;
-}
-
-static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
-{
- if (!cpu_has_cpufreq(cpu))
- return -ENODEV;
-
- if (per_cpu(cpufreq_thermal_reduction_pctg, cpu) >
- (CPUFREQ_THERMAL_MIN_STEP + 1))
- per_cpu(cpufreq_thermal_reduction_pctg, cpu)--;
- else
- per_cpu(cpufreq_thermal_reduction_pctg, cpu) = 0;
- cpufreq_update_policy(cpu);
- /* We reached max freq again and can leave passive mode */
- return !per_cpu(cpufreq_thermal_reduction_pctg, cpu);
-}
-
static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
@@ -238,113 +167,6 @@ static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
#endif
-int acpi_processor_set_thermal_limit(acpi_handle handle, int type)
-{
- int result = 0;
- struct acpi_processor *pr = NULL;
- struct acpi_device *device = NULL;
- int tx = 0, max_tx_px = 0;
-
-
- if ((type < ACPI_PROCESSOR_LIMIT_NONE)
- || (type > ACPI_PROCESSOR_LIMIT_DECREMENT))
- return -EINVAL;
-
- result = acpi_bus_get_device(handle, &device);
- if (result)
- return result;
-
- pr = acpi_driver_data(device);
- if (!pr)
- return -ENODEV;
-
- /* Thermal limits are always relative to the current Px/Tx state. */
- if (pr->flags.throttling)
- pr->limit.thermal.tx = pr->throttling.state;
-
- /*
- * Our default policy is to only use throttling at the lowest
- * performance state.
- */
-
- tx = pr->limit.thermal.tx;
-
- switch (type) {
-
- case ACPI_PROCESSOR_LIMIT_NONE:
- do {
- result = acpi_thermal_cpufreq_decrease(pr->id);
- } while (!result);
- tx = 0;
- break;
-
- case ACPI_PROCESSOR_LIMIT_INCREMENT:
- /* if going up: P-states first, T-states later */
-
- result = acpi_thermal_cpufreq_increase(pr->id);
- if (!result)
- goto end;
- else if (result == -ERANGE)
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "At maximum performance state\n"));
-
- if (pr->flags.throttling) {
- if (tx == (pr->throttling.state_count - 1))
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "At maximum throttling state\n"));
- else
- tx++;
- }
- break;
-
- case ACPI_PROCESSOR_LIMIT_DECREMENT:
- /* if going down: T-states first, P-states later */
-
- if (pr->flags.throttling) {
- if (tx == 0) {
- max_tx_px = 1;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "At minimum throttling state\n"));
- } else {
- tx--;
- goto end;
- }
- }
-
- result = acpi_thermal_cpufreq_decrease(pr->id);
- if (result) {
- /*
- * We only could get -ERANGE, 1 or 0.
- * In the first two cases we reached max freq again.
- */
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "At minimum performance state\n"));
- max_tx_px = 1;
- } else
- max_tx_px = 0;
-
- break;
- }
-
- end:
- if (pr->flags.throttling) {
- pr->limit.thermal.px = 0;
- pr->limit.thermal.tx = tx;
-
- result = acpi_processor_apply_limit(pr);
- if (result)
- printk(KERN_ERR PREFIX "Unable to set thermal limit\n");
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Thermal limit now (P%d:T%d)\n",
- pr->limit.thermal.px, pr->limit.thermal.tx));
- } else
- result = 0;
- if (max_tx_px)
- return 1;
- else
- return result;
-}
-
int acpi_processor_get_limit_info(struct acpi_processor *pr)
{
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 730863855ed5..ff3632717c51 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -32,8 +32,10 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/cpufreq.h>
+#ifdef CONFIG_ACPI_PROCFS
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#endif
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -1214,6 +1216,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
return result;
}
+#ifdef CONFIG_ACPI_PROCFS
/* proc interface */
static int acpi_processor_throttling_seq_show(struct seq_file *seq,
void *offset)
@@ -1322,3 +1325,4 @@ const struct file_operations acpi_processor_throttling_fops = {
.llseek = seq_lseek,
.release = single_release,
};
+#endif
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 4ff76e8174eb..e5dbedb16bbf 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -40,10 +40,7 @@
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/delay.h>
-
-#ifdef CONFIG_ACPI_SYSFS_POWER
#include <linux/power_supply.h>
-#endif
#include "sbshc.h"
@@ -85,9 +82,7 @@ static const struct acpi_device_id sbs_device_ids[] = {
MODULE_DEVICE_TABLE(acpi, sbs_device_ids);
struct acpi_battery {
-#ifdef CONFIG_ACPI_SYSFS_POWER
struct power_supply bat;
-#endif
struct acpi_sbs *sbs;
#ifdef CONFIG_ACPI_PROCFS_POWER
struct proc_dir_entry *proc_entry;
@@ -120,9 +115,7 @@ struct acpi_battery {
#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
struct acpi_sbs {
-#ifdef CONFIG_ACPI_SYSFS_POWER
struct power_supply charger;
-#endif
struct acpi_device *device;
struct acpi_smb_hc *hc;
struct mutex lock;
@@ -166,7 +159,6 @@ static inline int acpi_battery_scale(struct acpi_battery *battery)
acpi_battery_ipscale(battery);
}
-#ifdef CONFIG_ACPI_SYSFS_POWER
static int sbs_get_ac_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -313,7 +305,6 @@ static enum power_supply_property sbs_energy_battery_props[] = {
POWER_SUPPLY_PROP_MANUFACTURER,
};
-#endif
/* --------------------------------------------------------------------------
Smart Battery System Management
@@ -449,7 +440,6 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs)
return result;
}
-#ifdef CONFIG_ACPI_SYSFS_POWER
static ssize_t acpi_battery_alarm_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -479,7 +469,6 @@ static struct device_attribute alarm_attr = {
.show = acpi_battery_alarm_show,
.store = acpi_battery_alarm_store,
};
-#endif
/* --------------------------------------------------------------------------
FS Interface (/proc/acpi)
@@ -798,7 +787,6 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
&acpi_battery_state_fops, &acpi_battery_alarm_fops,
battery);
#endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
battery->bat.name = battery->name;
battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
if (!acpi_battery_mode(battery)) {
@@ -819,7 +807,6 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
goto end;
battery->have_sysfs_alarm = 1;
end:
-#endif
printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
battery->name, battery->present ? "present" : "absent");
@@ -828,17 +815,13 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
static void acpi_battery_remove(struct acpi_sbs *sbs, int id)
{
-#if defined(CONFIG_ACPI_SYSFS_POWER) || defined(CONFIG_ACPI_PROCFS_POWER)
struct acpi_battery *battery = &sbs->battery[id];
-#endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
if (battery->bat.dev) {
if (battery->have_sysfs_alarm)
device_remove_file(battery->bat.dev, &alarm_attr);
power_supply_unregister(&battery->bat);
}
-#endif
#ifdef CONFIG_ACPI_PROCFS_POWER
if (battery->proc_entry)
acpi_sbs_remove_fs(&battery->proc_entry, acpi_battery_dir);
@@ -859,14 +842,12 @@ static int acpi_charger_add(struct acpi_sbs *sbs)
if (result)
goto end;
#endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
sbs->charger.name = "sbs-charger";
sbs->charger.type = POWER_SUPPLY_TYPE_MAINS;
sbs->charger.properties = sbs_ac_props;
sbs->charger.num_properties = ARRAY_SIZE(sbs_ac_props);
sbs->charger.get_property = sbs_get_ac_property;
power_supply_register(&sbs->device->dev, &sbs->charger);
-#endif
printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n",
ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line");
@@ -876,10 +857,8 @@ static int acpi_charger_add(struct acpi_sbs *sbs)
static void acpi_charger_remove(struct acpi_sbs *sbs)
{
-#ifdef CONFIG_ACPI_SYSFS_POWER
if (sbs->charger.dev)
power_supply_unregister(&sbs->charger);
-#endif
#ifdef CONFIG_ACPI_PROCFS_POWER
if (sbs->charger_entry)
acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir);
@@ -900,9 +879,7 @@ static void acpi_sbs_callback(void *context)
ACPI_SBS_NOTIFY_STATUS,
sbs->charger_present);
#endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE);
-#endif
}
if (sbs->manager_present) {
for (id = 0; id < MAX_SBS_BAT; ++id) {
@@ -919,9 +896,7 @@ static void acpi_sbs_callback(void *context)
ACPI_SBS_NOTIFY_STATUS,
bat->present);
#endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE);
-#endif
}
}
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index b23825ecfa37..2b6c21d86b98 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -26,6 +26,8 @@ extern struct acpi_device *acpi_root;
#define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent)
+static const char *dummy_hid = "device";
+
static LIST_HEAD(acpi_device_list);
static LIST_HEAD(acpi_bus_id_list);
DEFINE_MUTEX(acpi_device_lock);
@@ -49,6 +51,9 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
int count;
struct acpi_hardware_id *id;
+ if (list_empty(&acpi_dev->pnp.ids))
+ return 0;
+
len = snprintf(modalias, size, "acpi:");
size -= len;
@@ -202,13 +207,15 @@ static int acpi_device_setup_files(struct acpi_device *dev)
goto end;
}
- result = device_create_file(&dev->dev, &dev_attr_hid);
- if (result)
- goto end;
+ if (!list_empty(&dev->pnp.ids)) {
+ result = device_create_file(&dev->dev, &dev_attr_hid);
+ if (result)
+ goto end;
- result = device_create_file(&dev->dev, &dev_attr_modalias);
- if (result)
- goto end;
+ result = device_create_file(&dev->dev, &dev_attr_modalias);
+ if (result)
+ goto end;
+ }
/*
* If device has _EJ0, 'eject' file is created that is used to trigger
@@ -316,6 +323,9 @@ static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
struct acpi_device *acpi_dev = to_acpi_device(dev);
int len;
+ if (list_empty(&acpi_dev->pnp.ids))
+ return 0;
+
if (add_uevent_var(env, "MODALIAS="))
return -ENOMEM;
len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
@@ -1010,10 +1020,13 @@ static int acpi_dock_match(struct acpi_device *device)
return acpi_get_handle(device->handle, "_DCK", &tmp);
}
-char *acpi_device_hid(struct acpi_device *device)
+const char *acpi_device_hid(struct acpi_device *device)
{
struct acpi_hardware_id *hid;
+ if (list_empty(&device->pnp.ids))
+ return dummy_hid;
+
hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list);
return hid->id;
}
@@ -1142,16 +1155,6 @@ static void acpi_device_set_id(struct acpi_device *device)
acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF);
break;
}
-
- /*
- * We build acpi_devices for some objects that don't have _HID or _CID,
- * e.g., PCI bridges and slots. Drivers can't bind to these objects,
- * but we do use them indirectly by traversing the acpi_device tree.
- * This generic ID isn't useful for driver binding, but it provides
- * the useful property that "every acpi_device has an ID."
- */
- if (list_empty(&device->pnp.ids))
- acpi_add_id(device, "device");
}
static int acpi_device_set_context(struct acpi_device *device)
@@ -1431,6 +1434,7 @@ EXPORT_SYMBOL(acpi_bus_add);
int acpi_bus_start(struct acpi_device *device)
{
struct acpi_bus_ops ops;
+ int result;
if (!device)
return -EINVAL;
@@ -1438,7 +1442,11 @@ int acpi_bus_start(struct acpi_device *device)
memset(&ops, 0, sizeof(ops));
ops.acpi_op_start = 1;
- return acpi_bus_scan(device->handle, &ops, NULL);
+ result = acpi_bus_scan(device->handle, &ops, NULL);
+
+ acpi_update_gpes();
+
+ return result;
}
EXPORT_SYMBOL(acpi_bus_start);
@@ -1552,6 +1560,8 @@ int __init acpi_scan_init(void)
if (result)
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
+ else
+ acpi_update_gpes();
return result;
}
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 4754ff6e70e6..721d93b3ceee 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -25,7 +25,9 @@
#include "internal.h"
#include "sleep.h"
-u8 sleep_states[ACPI_S_STATE_COUNT];
+static u8 sleep_states[ACPI_S_STATE_COUNT];
+
+static u32 acpi_target_sleep_state = ACPI_STATE_S0;
static void acpi_sleep_tts_switch(u32 acpi_state)
{
@@ -79,8 +81,6 @@ static int acpi_sleep_prepare(u32 acpi_state)
}
#ifdef CONFIG_ACPI_SLEEP
-static u32 acpi_target_sleep_state = ACPI_STATE_S0;
-
/*
* The ACPI specification wants us to save NVS memory regions during hibernation
* and to restore them during the subsequent resume. Windows does that also for
@@ -419,6 +419,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Everex StepNote Series"),
},
},
+ {
+ .callback = init_nvs_nosave,
+ .ident = "Sony Vaio VPCEB1Z1E",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"),
+ },
+ },
{},
};
#endif /* CONFIG_SUSPEND */
@@ -562,7 +570,7 @@ int acpi_suspend(u32 acpi_state)
return -EINVAL;
}
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM_OPS
/**
* acpi_pm_device_sleep_state - return preferred power state of ACPI device
* in the system sleep state given by %acpi_target_sleep_state
@@ -624,7 +632,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
* can wake the system. _S0W may be valid, too.
*/
if (acpi_target_sleep_state == ACPI_STATE_S0 ||
- (device_may_wakeup(dev) && adev->wakeup.state.enabled &&
+ (device_may_wakeup(dev) &&
adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
acpi_status status;
@@ -632,7 +640,9 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
status = acpi_evaluate_integer(handle, acpi_method, NULL,
&d_max);
if (ACPI_FAILURE(status)) {
- d_max = d_min;
+ if (acpi_target_sleep_state != ACPI_STATE_S0 ||
+ status != AE_NOT_FOUND)
+ d_max = d_min;
} else if (d_max < d_min) {
/* Warn the user of the broken DSDT */
printk(KERN_WARNING "ACPI: Wrong value from %s\n",
@@ -646,7 +656,9 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
*d_min_p = d_min;
return d_max;
}
+#endif /* CONFIG_PM_OPS */
+#ifdef CONFIG_PM_SLEEP
/**
* acpi_pm_device_sleep_wake - enable or disable the system wake-up
* capability of given device
@@ -677,7 +689,7 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
return error;
}
-#endif
+#endif /* CONFIG_PM_SLEEP */
static void acpi_power_off_prepare(void)
{
@@ -702,7 +714,7 @@ static void acpi_power_off(void)
* paths through the BIOS, so disable _GTS and _BFS by default,
* but do speak up and offer the option to enable them.
*/
-void __init acpi_gts_bfs_check(void)
+static void __init acpi_gts_bfs_check(void)
{
acpi_handle dummy;
diff --git a/drivers/acpi/sleep.h b/drivers/acpi/sleep.h
index d8821805c3bc..74d59c8f4678 100644
--- a/drivers/acpi/sleep.h
+++ b/drivers/acpi/sleep.h
@@ -1,5 +1,4 @@
-extern u8 sleep_states[];
extern int acpi_suspend(u32 state);
extern void acpi_enable_wakeup_devices(u8 sleep_state);
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 2f8f17131d9f..5a27b0a31315 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -37,12 +37,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
-
-#ifdef CONFIG_ACPI_PROCFS
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#endif
-
#include <linux/jiffies.h>
#include <linux/kmod.h>
#include <linux/reboot.h>
@@ -195,61 +189,6 @@ struct acpi_thermal {
struct mutex lock;
};
-#ifdef CONFIG_ACPI_PROCFS
-static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
-static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
-static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
-static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file);
-static ssize_t acpi_thermal_write_cooling_mode(struct file *,
- const char __user *, size_t,
- loff_t *);
-static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file);
-static ssize_t acpi_thermal_write_polling(struct file *, const char __user *,
- size_t, loff_t *);
-
-static const struct file_operations acpi_thermal_state_fops = {
- .owner = THIS_MODULE,
- .open = acpi_thermal_state_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations acpi_thermal_temp_fops = {
- .owner = THIS_MODULE,
- .open = acpi_thermal_temp_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations acpi_thermal_trip_fops = {
- .owner = THIS_MODULE,
- .open = acpi_thermal_trip_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations acpi_thermal_cooling_fops = {
- .owner = THIS_MODULE,
- .open = acpi_thermal_cooling_open_fs,
- .read = seq_read,
- .write = acpi_thermal_write_cooling_mode,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations acpi_thermal_polling_fops = {
- .owner = THIS_MODULE,
- .open = acpi_thermal_polling_open_fs,
- .read = seq_read,
- .write = acpi_thermal_write_polling,
- .llseek = seq_lseek,
- .release = single_release,
-};
-#endif /* CONFIG_ACPI_PROCFS*/
-
/* --------------------------------------------------------------------------
Thermal Zone Management
-------------------------------------------------------------------------- */
@@ -958,358 +897,6 @@ static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
/* --------------------------------------------------------------------------
- FS Interface (/proc)
- -------------------------------------------------------------------------- */
-#ifdef CONFIG_ACPI_PROCFS
-static struct proc_dir_entry *acpi_thermal_dir;
-
-static int acpi_thermal_state_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_thermal *tz = seq->private;
-
-
- if (!tz)
- goto end;
-
- seq_puts(seq, "state: ");
-
- if (!tz->state.critical && !tz->state.hot && !tz->state.passive
- && !tz->state.active)
- seq_puts(seq, "ok\n");
- else {
- if (tz->state.critical)
- seq_puts(seq, "critical ");
- if (tz->state.hot)
- seq_puts(seq, "hot ");
- if (tz->state.passive)
- seq_puts(seq, "passive ");
- if (tz->state.active)
- seq_printf(seq, "active[%d]", tz->state.active_index);
- seq_puts(seq, "\n");
- }
-
- end:
- return 0;
-}
-
-static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_thermal_state_seq_show, PDE(inode)->data);
-}
-
-static int acpi_thermal_temp_seq_show(struct seq_file *seq, void *offset)
-{
- int result = 0;
- struct acpi_thermal *tz = seq->private;
-
-
- if (!tz)
- goto end;
-
- result = acpi_thermal_get_temperature(tz);
- if (result)
- goto end;
-
- seq_printf(seq, "temperature: %ld C\n",
- KELVIN_TO_CELSIUS(tz->temperature));
-
- end:
- return 0;
-}
-
-static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_thermal_temp_seq_show, PDE(inode)->data);
-}
-
-static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_thermal *tz = seq->private;
- struct acpi_device *device;
- acpi_status status;
-
- int i = 0;
- int j = 0;
-
-
- if (!tz)
- goto end;
-
- if (tz->trips.critical.flags.valid)
- seq_printf(seq, "critical (S5): %ld C%s",
- KELVIN_TO_CELSIUS(tz->trips.critical.temperature),
- nocrt ? " <disabled>\n" : "\n");
-
- if (tz->trips.hot.flags.valid)
- seq_printf(seq, "hot (S4): %ld C%s",
- KELVIN_TO_CELSIUS(tz->trips.hot.temperature),
- nocrt ? " <disabled>\n" : "\n");
-
- if (tz->trips.passive.flags.valid) {
- seq_printf(seq,
- "passive: %ld C: tc1=%lu tc2=%lu tsp=%lu devices=",
- KELVIN_TO_CELSIUS(tz->trips.passive.temperature),
- tz->trips.passive.tc1, tz->trips.passive.tc2,
- tz->trips.passive.tsp);
- for (j = 0; j < tz->trips.passive.devices.count; j++) {
- status = acpi_bus_get_device(tz->trips.passive.devices.
- handles[j], &device);
- seq_printf(seq, "%4.4s ", status ? "" :
- acpi_device_bid(device));
- }
- seq_puts(seq, "\n");
- } else {
- seq_printf(seq, "passive (forced):");
- if (tz->thermal_zone->forced_passive)
- seq_printf(seq, " %i C\n",
- tz->thermal_zone->forced_passive / 1000);
- else
- seq_printf(seq, "<not set>\n");
- }
-
- for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
- if (!(tz->trips.active[i].flags.valid))
- break;
- seq_printf(seq, "active[%d]: %ld C: devices=",
- i,
- KELVIN_TO_CELSIUS(tz->trips.active[i].temperature));
- for (j = 0; j < tz->trips.active[i].devices.count; j++){
- status = acpi_bus_get_device(tz->trips.active[i].
- devices.handles[j],
- &device);
- seq_printf(seq, "%4.4s ", status ? "" :
- acpi_device_bid(device));
- }
- seq_puts(seq, "\n");
- }
-
- end:
- return 0;
-}
-
-static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_thermal_trip_seq_show, PDE(inode)->data);
-}
-
-static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_thermal *tz = seq->private;
-
-
- if (!tz)
- goto end;
-
- if (!tz->flags.cooling_mode)
- seq_puts(seq, "<setting not supported>\n");
- else
- seq_puts(seq, "0 - Active; 1 - Passive\n");
-
- end:
- return 0;
-}
-
-static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_thermal_cooling_seq_show,
- PDE(inode)->data);
-}
-
-static ssize_t
-acpi_thermal_write_cooling_mode(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * ppos)
-{
- struct seq_file *m = file->private_data;
- struct acpi_thermal *tz = m->private;
- int result = 0;
- char mode_string[12] = { '\0' };
-
-
- if (!tz || (count > sizeof(mode_string) - 1))
- return -EINVAL;
-
- if (!tz->flags.cooling_mode)
- return -ENODEV;
-
- if (copy_from_user(mode_string, buffer, count))
- return -EFAULT;
-
- mode_string[count] = '\0';
-
- result = acpi_thermal_set_cooling_mode(tz,
- simple_strtoul(mode_string, NULL,
- 0));
- if (result)
- return result;
-
- acpi_thermal_check(tz);
-
- return count;
-}
-
-static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_thermal *tz = seq->private;
-
-
- if (!tz)
- goto end;
-
- if (!tz->thermal_zone->polling_delay) {
- seq_puts(seq, "<polling disabled>\n");
- goto end;
- }
-
- seq_printf(seq, "polling frequency: %d seconds\n",
- (tz->thermal_zone->polling_delay / 1000));
-
- end:
- return 0;
-}
-
-static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_thermal_polling_seq_show,
- PDE(inode)->data);
-}
-
-static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds)
-{
- if (!tz)
- return -EINVAL;
-
- /* Convert value to deci-seconds */
- tz->polling_frequency = seconds * 10;
-
- tz->thermal_zone->polling_delay = seconds * 1000;
-
- if (tz->tz_enabled)
- thermal_zone_device_update(tz->thermal_zone);
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Polling frequency set to %lu seconds\n",
- tz->polling_frequency/10));
-
- return 0;
-}
-
-static ssize_t
-acpi_thermal_write_polling(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * ppos)
-{
- struct seq_file *m = file->private_data;
- struct acpi_thermal *tz = m->private;
- int result = 0;
- char polling_string[12] = { '\0' };
- int seconds = 0;
-
-
- if (!tz || (count > sizeof(polling_string) - 1))
- return -EINVAL;
-
- if (copy_from_user(polling_string, buffer, count))
- return -EFAULT;
-
- polling_string[count] = '\0';
-
- seconds = simple_strtoul(polling_string, NULL, 0);
-
- result = acpi_thermal_set_polling(tz, seconds);
- if (result)
- return result;
-
- acpi_thermal_check(tz);
-
- return count;
-}
-
-static int acpi_thermal_add_fs(struct acpi_device *device)
-{
- struct proc_dir_entry *entry = NULL;
-
-
- if (!acpi_device_dir(device)) {
- acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
- acpi_thermal_dir);
- if (!acpi_device_dir(device))
- return -ENODEV;
- }
-
- /* 'state' [R] */
- entry = proc_create_data(ACPI_THERMAL_FILE_STATE,
- S_IRUGO, acpi_device_dir(device),
- &acpi_thermal_state_fops,
- acpi_driver_data(device));
- if (!entry)
- return -ENODEV;
-
- /* 'temperature' [R] */
- entry = proc_create_data(ACPI_THERMAL_FILE_TEMPERATURE,
- S_IRUGO, acpi_device_dir(device),
- &acpi_thermal_temp_fops,
- acpi_driver_data(device));
- if (!entry)
- return -ENODEV;
-
- /* 'trip_points' [R] */
- entry = proc_create_data(ACPI_THERMAL_FILE_TRIP_POINTS,
- S_IRUGO,
- acpi_device_dir(device),
- &acpi_thermal_trip_fops,
- acpi_driver_data(device));
- if (!entry)
- return -ENODEV;
-
- /* 'cooling_mode' [R/W] */
- entry = proc_create_data(ACPI_THERMAL_FILE_COOLING_MODE,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device),
- &acpi_thermal_cooling_fops,
- acpi_driver_data(device));
- if (!entry)
- return -ENODEV;
-
- /* 'polling_frequency' [R/W] */
- entry = proc_create_data(ACPI_THERMAL_FILE_POLLING_FREQ,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device),
- &acpi_thermal_polling_fops,
- acpi_driver_data(device));
- if (!entry)
- return -ENODEV;
- return 0;
-}
-
-static int acpi_thermal_remove_fs(struct acpi_device *device)
-{
-
- if (acpi_device_dir(device)) {
- remove_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
- acpi_device_dir(device));
- remove_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
- acpi_device_dir(device));
- remove_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
- acpi_device_dir(device));
- remove_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
- acpi_device_dir(device));
- remove_proc_entry(ACPI_THERMAL_FILE_STATE,
- acpi_device_dir(device));
- remove_proc_entry(acpi_device_bid(device), acpi_thermal_dir);
- acpi_device_dir(device) = NULL;
- }
-
- return 0;
-}
-#else
-static inline int acpi_thermal_add_fs(struct acpi_device *device) { return 0; }
-static inline int acpi_thermal_remove_fs(struct acpi_device *device)
-{
- return 0;
-}
-#endif /* CONFIG_ACPI_PROCFS */
-/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
@@ -1428,17 +1015,11 @@ static int acpi_thermal_add(struct acpi_device *device)
if (result)
goto free_memory;
- result = acpi_thermal_add_fs(device);
- if (result)
- goto unregister_thermal_zone;
-
printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
acpi_device_name(device), acpi_device_bid(device),
KELVIN_TO_CELSIUS(tz->temperature));
goto end;
-unregister_thermal_zone:
- thermal_zone_device_unregister(tz->thermal_zone);
free_memory:
kfree(tz);
end:
@@ -1454,7 +1035,6 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
tz = acpi_driver_data(device);
- acpi_thermal_remove_fs(device);
acpi_thermal_unregister_thermal_zone(tz);
mutex_destroy(&tz->lock);
kfree(tz);
@@ -1580,19 +1160,9 @@ static int __init acpi_thermal_init(void)
return -ENODEV;
}
-#ifdef CONFIG_ACPI_PROCFS
- acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
- if (!acpi_thermal_dir)
- return -ENODEV;
-#endif
-
result = acpi_bus_register_driver(&acpi_thermal_driver);
- if (result < 0) {
-#ifdef CONFIG_ACPI_PROCFS
- remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
-#endif
+ if (result < 0)
return -ENODEV;
- }
return 0;
}
@@ -1602,10 +1172,6 @@ static void __exit acpi_thermal_exit(void)
acpi_bus_unregister_driver(&acpi_thermal_driver);
-#ifdef CONFIG_ACPI_PROCFS
- remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
-#endif
-
return;
}
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 67dec0c675aa..5cd0228d2daa 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -30,8 +30,6 @@
#include <linux/types.h>
#include <linux/list.h>
#include <linux/mutex.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
#include <linux/input.h>
#include <linux/backlight.h>
#include <linux/thermal.h>
@@ -152,9 +150,6 @@ struct acpi_video_bus {
struct acpi_video_bus_flags flags;
struct list_head video_device_list;
struct mutex device_list_lock; /* protects video_device_list */
-#ifdef CONFIG_ACPI_PROCFS
- struct proc_dir_entry *dir;
-#endif
struct input_dev *input;
char phys[32]; /* for input device */
struct notifier_block pm_nb;
@@ -210,108 +205,6 @@ struct acpi_video_device {
struct output_device *output_dev;
};
-#ifdef CONFIG_ACPI_PROCFS
-/* bus */
-static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file);
-static const struct file_operations acpi_video_bus_info_fops = {
- .owner = THIS_MODULE,
- .open = acpi_video_bus_info_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file);
-static const struct file_operations acpi_video_bus_ROM_fops = {
- .owner = THIS_MODULE,
- .open = acpi_video_bus_ROM_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int acpi_video_bus_POST_info_open_fs(struct inode *inode,
- struct file *file);
-static const struct file_operations acpi_video_bus_POST_info_fops = {
- .owner = THIS_MODULE,
- .open = acpi_video_bus_POST_info_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file);
-static ssize_t acpi_video_bus_write_POST(struct file *file,
- const char __user *buffer, size_t count, loff_t *data);
-static const struct file_operations acpi_video_bus_POST_fops = {
- .owner = THIS_MODULE,
- .open = acpi_video_bus_POST_open_fs,
- .read = seq_read,
- .write = acpi_video_bus_write_POST,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file);
-static ssize_t acpi_video_bus_write_DOS(struct file *file,
- const char __user *buffer, size_t count, loff_t *data);
-static const struct file_operations acpi_video_bus_DOS_fops = {
- .owner = THIS_MODULE,
- .open = acpi_video_bus_DOS_open_fs,
- .read = seq_read,
- .write = acpi_video_bus_write_DOS,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-/* device */
-static int acpi_video_device_info_open_fs(struct inode *inode,
- struct file *file);
-static const struct file_operations acpi_video_device_info_fops = {
- .owner = THIS_MODULE,
- .open = acpi_video_device_info_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int acpi_video_device_state_open_fs(struct inode *inode,
- struct file *file);
-static ssize_t acpi_video_device_write_state(struct file *file,
- const char __user *buffer, size_t count, loff_t *data);
-static const struct file_operations acpi_video_device_state_fops = {
- .owner = THIS_MODULE,
- .open = acpi_video_device_state_open_fs,
- .read = seq_read,
- .write = acpi_video_device_write_state,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int acpi_video_device_brightness_open_fs(struct inode *inode,
- struct file *file);
-static ssize_t acpi_video_device_write_brightness(struct file *file,
- const char __user *buffer, size_t count, loff_t *data);
-static const struct file_operations acpi_video_device_brightness_fops = {
- .owner = THIS_MODULE,
- .open = acpi_video_device_brightness_open_fs,
- .read = seq_read,
- .write = acpi_video_device_write_brightness,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int acpi_video_device_EDID_open_fs(struct inode *inode,
- struct file *file);
-static const struct file_operations acpi_video_device_EDID_fops = {
- .owner = THIS_MODULE,
- .open = acpi_video_device_EDID_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-#endif /* CONFIG_ACPI_PROCFS */
-
static const char device_decode[][30] = {
"motherboard VGA device",
"PCI VGA device",
@@ -1111,646 +1004,6 @@ static int acpi_video_bus_check(struct acpi_video_bus *video)
}
/* --------------------------------------------------------------------------
- FS Interface (/proc)
- -------------------------------------------------------------------------- */
-#ifdef CONFIG_ACPI_PROCFS
-
-static struct proc_dir_entry *acpi_video_dir;
-
-/* video devices */
-
-static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_video_device *dev = seq->private;
-
-
- if (!dev)
- goto end;
-
- seq_printf(seq, "device_id: 0x%04x\n", (u32) dev->device_id);
- seq_printf(seq, "type: ");
- if (dev->flags.crt)
- seq_printf(seq, "CRT\n");
- else if (dev->flags.lcd)
- seq_printf(seq, "LCD\n");
- else if (dev->flags.tvout)
- seq_printf(seq, "TVOUT\n");
- else if (dev->flags.dvi)
- seq_printf(seq, "DVI\n");
- else
- seq_printf(seq, "UNKNOWN\n");
-
- seq_printf(seq, "known by bios: %s\n", dev->flags.bios ? "yes" : "no");
-
- end:
- return 0;
-}
-
-static int
-acpi_video_device_info_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_video_device_info_seq_show,
- PDE(inode)->data);
-}
-
-static int
-acpi_video_device_query(struct acpi_video_device *device,
- unsigned long long *state)
-{
- int status;
-
- status = acpi_evaluate_integer(device->dev->handle, "_DGS",
- NULL, state);
-
- return status;
-}
-
-static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
-{
- int status;
- struct acpi_video_device *dev = seq->private;
- unsigned long long state;
-
-
- if (!dev)
- goto end;
-
- status = acpi_video_device_get_state(dev, &state);
- seq_printf(seq, "state: ");
- if (ACPI_SUCCESS(status))
- seq_printf(seq, "0x%02llx\n", state);
- else
- seq_printf(seq, "<not supported>\n");
-
- status = acpi_video_device_query(dev, &state);
- seq_printf(seq, "query: ");
- if (ACPI_SUCCESS(status))
- seq_printf(seq, "0x%02llx\n", state);
- else
- seq_printf(seq, "<not supported>\n");
-
- end:
- return 0;
-}
-
-static int
-acpi_video_device_state_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_video_device_state_seq_show,
- PDE(inode)->data);
-}
-
-static ssize_t
-acpi_video_device_write_state(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * data)
-{
- int status;
- struct seq_file *m = file->private_data;
- struct acpi_video_device *dev = m->private;
- char str[12] = { 0 };
- u32 state = 0;
-
-
- if (!dev || count >= sizeof(str))
- return -EINVAL;
-
- if (copy_from_user(str, buffer, count))
- return -EFAULT;
-
- str[count] = 0;
- state = simple_strtoul(str, NULL, 0);
- state &= ((1ul << 31) | (1ul << 30) | (1ul << 0));
-
- status = acpi_video_device_set_state(dev, state);
-
- if (status)
- return -EFAULT;
-
- return count;
-}
-
-static int
-acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_video_device *dev = seq->private;
- int i;
-
-
- if (!dev || !dev->brightness) {
- seq_printf(seq, "<not supported>\n");
- return 0;
- }
-
- seq_printf(seq, "levels: ");
- for (i = 2; i < dev->brightness->count; i++)
- seq_printf(seq, " %d", dev->brightness->levels[i]);
- seq_printf(seq, "\ncurrent: %d\n", dev->brightness->curr);
-
- return 0;
-}
-
-static int
-acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_video_device_brightness_seq_show,
- PDE(inode)->data);
-}
-
-static ssize_t
-acpi_video_device_write_brightness(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * data)
-{
- struct seq_file *m = file->private_data;
- struct acpi_video_device *dev = m->private;
- char str[5] = { 0 };
- unsigned int level = 0;
- int i;
-
-
- if (!dev || !dev->brightness || count >= sizeof(str))
- return -EINVAL;
-
- if (copy_from_user(str, buffer, count))
- return -EFAULT;
-
- str[count] = 0;
- level = simple_strtoul(str, NULL, 0);
-
- if (level > 100)
- return -EFAULT;
-
- /* validate through the list of available levels */
- for (i = 2; i < dev->brightness->count; i++)
- if (level == dev->brightness->levels[i]) {
- if (!acpi_video_device_lcd_set_level(dev, level))
- return count;
- break;
- }
-
- return -EINVAL;
-}
-
-static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_video_device *dev = seq->private;
- int status;
- int i;
- union acpi_object *edid = NULL;
-
-
- if (!dev)
- goto out;
-
- status = acpi_video_device_EDID(dev, &edid, 128);
- if (ACPI_FAILURE(status)) {
- status = acpi_video_device_EDID(dev, &edid, 256);
- }
-
- if (ACPI_FAILURE(status)) {
- goto out;
- }
-
- if (edid && edid->type == ACPI_TYPE_BUFFER) {
- for (i = 0; i < edid->buffer.length; i++)
- seq_putc(seq, edid->buffer.pointer[i]);
- }
-
- out:
- if (!edid)
- seq_printf(seq, "<not supported>\n");
- else
- kfree(edid);
-
- return 0;
-}
-
-static int
-acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_video_device_EDID_seq_show,
- PDE(inode)->data);
-}
-
-static int acpi_video_device_add_fs(struct acpi_device *device)
-{
- struct proc_dir_entry *entry, *device_dir;
- struct acpi_video_device *vid_dev;
-
- vid_dev = acpi_driver_data(device);
- if (!vid_dev)
- return -ENODEV;
-
- device_dir = proc_mkdir(acpi_device_bid(device),
- vid_dev->video->dir);
- if (!device_dir)
- return -ENOMEM;
-
- /* 'info' [R] */
- entry = proc_create_data("info", S_IRUGO, device_dir,
- &acpi_video_device_info_fops, acpi_driver_data(device));
- if (!entry)
- goto err_remove_dir;
-
- /* 'state' [R/W] */
- entry = proc_create_data("state", S_IFREG | S_IRUGO | S_IWUSR,
- device_dir,
- &acpi_video_device_state_fops,
- acpi_driver_data(device));
- if (!entry)
- goto err_remove_info;
-
- /* 'brightness' [R/W] */
- entry = proc_create_data("brightness", S_IFREG | S_IRUGO | S_IWUSR,
- device_dir,
- &acpi_video_device_brightness_fops,
- acpi_driver_data(device));
- if (!entry)
- goto err_remove_state;
-
- /* 'EDID' [R] */
- entry = proc_create_data("EDID", S_IRUGO, device_dir,
- &acpi_video_device_EDID_fops,
- acpi_driver_data(device));
- if (!entry)
- goto err_remove_brightness;
-
- acpi_device_dir(device) = device_dir;
-
- return 0;
-
- err_remove_brightness:
- remove_proc_entry("brightness", device_dir);
- err_remove_state:
- remove_proc_entry("state", device_dir);
- err_remove_info:
- remove_proc_entry("info", device_dir);
- err_remove_dir:
- remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
- return -ENOMEM;
-}
-
-static int acpi_video_device_remove_fs(struct acpi_device *device)
-{
- struct acpi_video_device *vid_dev;
- struct proc_dir_entry *device_dir;
-
- vid_dev = acpi_driver_data(device);
- if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
- return -ENODEV;
-
- device_dir = acpi_device_dir(device);
- if (device_dir) {
- remove_proc_entry("info", device_dir);
- remove_proc_entry("state", device_dir);
- remove_proc_entry("brightness", device_dir);
- remove_proc_entry("EDID", device_dir);
- remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
- acpi_device_dir(device) = NULL;
- }
-
- return 0;
-}
-
-/* video bus */
-static int acpi_video_bus_info_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_video_bus *video = seq->private;
-
-
- if (!video)
- goto end;
-
- seq_printf(seq, "Switching heads: %s\n",
- video->flags.multihead ? "yes" : "no");
- seq_printf(seq, "Video ROM: %s\n",
- video->flags.rom ? "yes" : "no");
- seq_printf(seq, "Device to be POSTed on boot: %s\n",
- video->flags.post ? "yes" : "no");
-
- end:
- return 0;
-}
-
-static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_video_bus_info_seq_show,
- PDE(inode)->data);
-}
-
-static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_video_bus *video = seq->private;
-
-
- if (!video)
- goto end;
-
- printk(KERN_INFO PREFIX "Please implement %s\n", __func__);
- seq_printf(seq, "<TODO>\n");
-
- end:
- return 0;
-}
-
-static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_video_bus_ROM_seq_show, PDE(inode)->data);
-}
-
-static int
-acpi_video_bus_POST_options(struct acpi_video_bus *video,
- unsigned long long *options)
-{
- int status;
-
- status = acpi_evaluate_integer(video->device->handle, "_VPO",
- NULL, options);
- *options &= 3;
-
- return status;
-}
-
-static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_video_bus *video = seq->private;
- unsigned long long options;
- int status;
-
-
- if (!video)
- goto end;
-
- status = acpi_video_bus_POST_options(video, &options);
- if (ACPI_SUCCESS(status)) {
- if (!(options & 1)) {
- printk(KERN_WARNING PREFIX
- "The motherboard VGA device is not listed as a possible POST device.\n");
- printk(KERN_WARNING PREFIX
- "This indicates a BIOS bug. Please contact the manufacturer.\n");
- }
- printk(KERN_WARNING "%llx\n", options);
- seq_printf(seq, "can POST: <integrated video>");
- if (options & 2)
- seq_printf(seq, " <PCI video>");
- if (options & 4)
- seq_printf(seq, " <AGP video>");
- seq_putc(seq, '\n');
- } else
- seq_printf(seq, "<not supported>\n");
- end:
- return 0;
-}
-
-static int
-acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_video_bus_POST_info_seq_show,
- PDE(inode)->data);
-}
-
-static int
-acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long long *id)
-{
- int status;
-
- status = acpi_evaluate_integer(video->device->handle, "_GPD", NULL, id);
-
- return status;
-}
-
-static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_video_bus *video = seq->private;
- int status;
- unsigned long long id;
-
-
- if (!video)
- goto end;
-
- status = acpi_video_bus_get_POST(video, &id);
- if (!ACPI_SUCCESS(status)) {
- seq_printf(seq, "<not supported>\n");
- goto end;
- }
- seq_printf(seq, "device POSTed is <%s>\n", device_decode[id & 3]);
-
- end:
- return 0;
-}
-
-static int acpi_video_bus_DOS_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_video_bus *video = seq->private;
-
-
- seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting);
-
- return 0;
-}
-
-static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_video_bus_POST_seq_show,
- PDE(inode)->data);
-}
-
-static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_video_bus_DOS_seq_show, PDE(inode)->data);
-}
-
-static int
-acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option)
-{
- int status;
- unsigned long long tmp;
- union acpi_object arg0 = { ACPI_TYPE_INTEGER };
- struct acpi_object_list args = { 1, &arg0 };
-
-
- arg0.integer.value = option;
-
- status = acpi_evaluate_integer(video->device->handle, "_SPD",
- &args, &tmp);
- if (ACPI_SUCCESS(status))
- status = tmp ? (-EINVAL) : (AE_OK);
-
- return status;
-}
-
-static ssize_t
-acpi_video_bus_write_POST(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * data)
-{
- int status;
- struct seq_file *m = file->private_data;
- struct acpi_video_bus *video = m->private;
- char str[12] = { 0 };
- unsigned long long opt, options;
-
-
- if (!video || count >= sizeof(str))
- return -EINVAL;
-
- status = acpi_video_bus_POST_options(video, &options);
- if (!ACPI_SUCCESS(status))
- return -EINVAL;
-
- if (copy_from_user(str, buffer, count))
- return -EFAULT;
-
- str[count] = 0;
- opt = strtoul(str, NULL, 0);
- if (opt > 3)
- return -EFAULT;
-
- /* just in case an OEM 'forgot' the motherboard... */
- options |= 1;
-
- if (options & (1ul << opt)) {
- status = acpi_video_bus_set_POST(video, opt);
- if (!ACPI_SUCCESS(status))
- return -EFAULT;
-
- }
-
- return count;
-}
-
-static ssize_t
-acpi_video_bus_write_DOS(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * data)
-{
- int status;
- struct seq_file *m = file->private_data;
- struct acpi_video_bus *video = m->private;
- char str[12] = { 0 };
- unsigned long opt;
-
-
- if (!video || count >= sizeof(str))
- return -EINVAL;
-
- if (copy_from_user(str, buffer, count))
- return -EFAULT;
-
- str[count] = 0;
- opt = strtoul(str, NULL, 0);
- if (opt > 7)
- return -EFAULT;
-
- status = acpi_video_bus_DOS(video, opt & 0x3, (opt & 0x4) >> 2);
-
- if (!ACPI_SUCCESS(status))
- return -EFAULT;
-
- return count;
-}
-
-static int acpi_video_bus_add_fs(struct acpi_device *device)
-{
- struct acpi_video_bus *video = acpi_driver_data(device);
- struct proc_dir_entry *device_dir;
- struct proc_dir_entry *entry;
-
- device_dir = proc_mkdir(acpi_device_bid(device), acpi_video_dir);
- if (!device_dir)
- return -ENOMEM;
-
- /* 'info' [R] */
- entry = proc_create_data("info", S_IRUGO, device_dir,
- &acpi_video_bus_info_fops,
- acpi_driver_data(device));
- if (!entry)
- goto err_remove_dir;
-
- /* 'ROM' [R] */
- entry = proc_create_data("ROM", S_IRUGO, device_dir,
- &acpi_video_bus_ROM_fops,
- acpi_driver_data(device));
- if (!entry)
- goto err_remove_info;
-
- /* 'POST_info' [R] */
- entry = proc_create_data("POST_info", S_IRUGO, device_dir,
- &acpi_video_bus_POST_info_fops,
- acpi_driver_data(device));
- if (!entry)
- goto err_remove_rom;
-
- /* 'POST' [R/W] */
- entry = proc_create_data("POST", S_IFREG | S_IRUGO | S_IWUSR,
- device_dir,
- &acpi_video_bus_POST_fops,
- acpi_driver_data(device));
- if (!entry)
- goto err_remove_post_info;
-
- /* 'DOS' [R/W] */
- entry = proc_create_data("DOS", S_IFREG | S_IRUGO | S_IWUSR,
- device_dir,
- &acpi_video_bus_DOS_fops,
- acpi_driver_data(device));
- if (!entry)
- goto err_remove_post;
-
- video->dir = acpi_device_dir(device) = device_dir;
- return 0;
-
- err_remove_post:
- remove_proc_entry("POST", device_dir);
- err_remove_post_info:
- remove_proc_entry("POST_info", device_dir);
- err_remove_rom:
- remove_proc_entry("ROM", device_dir);
- err_remove_info:
- remove_proc_entry("info", device_dir);
- err_remove_dir:
- remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
- return -ENOMEM;
-}
-
-static int acpi_video_bus_remove_fs(struct acpi_device *device)
-{
- struct proc_dir_entry *device_dir = acpi_device_dir(device);
-
- if (device_dir) {
- remove_proc_entry("info", device_dir);
- remove_proc_entry("ROM", device_dir);
- remove_proc_entry("POST_info", device_dir);
- remove_proc_entry("POST", device_dir);
- remove_proc_entry("DOS", device_dir);
- remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
- acpi_device_dir(device) = NULL;
- }
-
- return 0;
-}
-#else
-static inline int acpi_video_device_add_fs(struct acpi_device *device)
-{
- return 0;
-}
-static inline int acpi_video_device_remove_fs(struct acpi_device *device)
-{
- return 0;
-}
-static inline int acpi_video_bus_add_fs(struct acpi_device *device)
-{
- return 0;
-}
-static inline int acpi_video_bus_remove_fs(struct acpi_device *device)
-{
- return 0;
-}
-#endif /* CONFIG_ACPI_PROCFS */
-
-/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
@@ -1877,8 +1130,6 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
list_add_tail(&data->entry, &video->video_device_list);
mutex_unlock(&video->device_list_lock);
- acpi_video_device_add_fs(device);
-
return 0;
}
@@ -2181,8 +1432,6 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
if (!device || !device->video)
return -ENOENT;
- acpi_video_device_remove_fs(device->dev);
-
status = acpi_remove_notify_handler(device->dev->handle,
ACPI_DEVICE_NOTIFY,
acpi_video_device_notify);
@@ -2466,10 +1715,6 @@ static int acpi_video_bus_add(struct acpi_device *device)
if (error)
goto err_free_video;
- error = acpi_video_bus_add_fs(device);
- if (error)
- goto err_free_video;
-
mutex_init(&video->device_list_lock);
INIT_LIST_HEAD(&video->video_device_list);
@@ -2522,7 +1767,6 @@ static int acpi_video_bus_add(struct acpi_device *device)
acpi_video_bus_stop_devices(video);
acpi_video_bus_put_devices(video);
kfree(video->attached_array);
- acpi_video_bus_remove_fs(device);
err_free_video:
kfree(video);
device->driver_data = NULL;
@@ -2544,7 +1788,6 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)
acpi_video_bus_stop_devices(video);
acpi_video_bus_put_devices(video);
- acpi_video_bus_remove_fs(device);
input_unregister_device(video->input);
kfree(video->attached_array);
@@ -2584,17 +1827,9 @@ int acpi_video_register(void)
return 0;
}
-#ifdef CONFIG_ACPI_PROCFS
- acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
- if (!acpi_video_dir)
- return -ENODEV;
-#endif
-
result = acpi_bus_register_driver(&acpi_video_bus);
- if (result < 0) {
- remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
+ if (result < 0)
return -ENODEV;
- }
/*
* When the acpi_video_bus is loaded successfully, increase
@@ -2617,10 +1852,6 @@ void acpi_video_unregister(void)
}
acpi_bus_unregister_driver(&acpi_video_bus);
-#ifdef CONFIG_ACPI_PROCFS
- remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
-#endif
-
register_count = 0;
return;
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
index ec2c777fcdb0..7aed5c792597 100644
--- a/drivers/ata/pata_bf54x.c
+++ b/drivers/ata/pata_bf54x.c
@@ -1588,7 +1588,7 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev)
host->ports[0]->ioaddr.ctl_addr = (void *)res->start;
if (peripheral_request_list(atapi_io_port, "atapi-io-port")) {
- dev_err(&pdev->dev, "Requesting Peripherals faild\n");
+ dev_err(&pdev->dev, "Requesting Peripherals failed\n");
return -EFAULT;
}
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index bf88f71a21f4..aa0e0c51cc08 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -15,8 +15,8 @@
* May be copied or modified under the terms of the GNU General Public License
* Based in part on the ITE vendor provided SCSI driver.
*
- * Documentation available from
- * http://www.ite.com.tw/pc/IT8212F_V04.pdf
+ * Documentation available from IT8212F_V04.pdf
+ * http://www.ite.com.tw/EN/products_more.aspx?CategoryID=3&ID=5,91
* Some other documents are NDA.
*
* The ITE8212 isn't exactly a standard IDE controller. It has two
diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig
index be7461c9a87e..31c60101a69a 100644
--- a/drivers/atm/Kconfig
+++ b/drivers/atm/Kconfig
@@ -301,7 +301,7 @@ config ATM_IA
control memory (128K-1KVC, 512K-4KVC), the size of the packet
memory (128K, 512K, 1M), and the PHY type (Single/Multi mode OC3,
UTP155, UTP25, DS3 and E3). Go to:
- <http://www.iphase.com/products/ClassSheet.cfm?ClassID=ATM>
+ <http://www.iphase.com/>
for more info about the cards. Say Y (or M to compile as a module
named iphase) here if you have one of these cards.
diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile
index 62c3cc1075ae..c6c9ee9f5da2 100644
--- a/drivers/atm/Makefile
+++ b/drivers/atm/Makefile
@@ -2,7 +2,7 @@
# Makefile for the Linux network (ATM) device drivers.
#
-fore_200e-objs := fore200e.o
+fore_200e-y := fore200e.o
obj-$(CONFIG_ATM_ZATM) += zatm.o uPD98402.o
obj-$(CONFIG_ATM_NICSTAR) += nicstar.o
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 80f9f3659e4d..97c5898cd76e 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -1736,9 +1736,10 @@ static int __devinit eni_do_init(struct atm_dev *dev)
eprom = (base+EPROM_SIZE-sizeof(struct midway_eprom));
if (readl(&eprom->magic) != ENI155_MAGIC) {
printk("\n");
- printk(KERN_ERR KERN_ERR DEV_LABEL "(itf %d): bad "
- "magic - expected 0x%x, got 0x%x\n",dev->number,
- ENI155_MAGIC,(unsigned) readl(&eprom->magic));
+ printk(KERN_ERR DEV_LABEL
+ "(itf %d): bad magic - expected 0x%x, got 0x%x\n",
+ dev->number, ENI155_MAGIC,
+ (unsigned)readl(&eprom->magic));
error = -EINVAL;
goto unmap;
}
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 8717809787fb..5d86bb803e94 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -444,8 +444,8 @@ static inline void fs_kfree_skb (struct sk_buff * skb)
#define ROUND_NEAREST 3
/********** make rate (not quite as much fun as Horizon) **********/
-static unsigned int make_rate (unsigned int rate, int r,
- u16 * bits, unsigned int * actual)
+static int make_rate(unsigned int rate, int r,
+ u16 *bits, unsigned int *actual)
{
unsigned char exp = -1; /* hush gcc */
unsigned int man = -1; /* hush gcc */
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index 54720baa7363..a95790452a68 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -1645,10 +1645,8 @@ static int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
unsigned short d = 0;
char * s = skb->data;
if (*s++ == 'D') {
- for (i = 0; i < 4; ++i) {
- d = (d<<4) | ((*s <= '9') ? (*s - '0') : (*s - 'a' + 10));
- ++s;
- }
+ for (i = 0; i < 4; ++i)
+ d = (d << 4) | hex_to_bin(*s++);
PRINTK (KERN_INFO, "debug bitmap is now %hx", debug = d);
}
}
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index 1679cbf0c584..bce57328ddde 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -3152,7 +3152,7 @@ deinit_card(struct idt77252_dev *card)
}
-static int __devinit
+static void __devinit
init_sram(struct idt77252_dev *card)
{
int i;
@@ -3298,7 +3298,6 @@ init_sram(struct idt77252_dev *card)
SAR_REG_RXFD);
IPRINTK("%s: SRAM initialization complete.\n", card->name);
- return 0;
}
static int __devinit
@@ -3410,8 +3409,7 @@ init_card(struct atm_dev *dev)
writel(readl(SAR_REG_CFG) | conf, SAR_REG_CFG);
- if (init_sram(card) < 0)
- return -1;
+ init_sram(card);
/********************************************************************/
/* A L L O C R A M A N D S E T V A R I O U S T H I N G S */
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 8cb0347dec28..9309d4724e13 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -220,7 +220,7 @@ static u16 get_desc (IADEV *dev, struct ia_vcc *iavcc) {
while (!desc_num || (dev->desc_tbl[desc_num -1]).timestamp) {
dev->ffL.tcq_rd += 2;
if (dev->ffL.tcq_rd > dev->ffL.tcq_ed)
- dev->ffL.tcq_rd = dev->ffL.tcq_st;
+ dev->ffL.tcq_rd = dev->ffL.tcq_st;
if (dev->ffL.tcq_rd == dev->host_tcq_wr)
return 0xFFFF;
desc_num = *(u_short *)(dev->seg_ram + dev->ffL.tcq_rd);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 2cb49a93b1e6..6ed645411c40 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -233,7 +233,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
__func__, retval);
}
- /* have the device type specific fuction add its stuff */
+ /* have the device type specific function add its stuff */
if (dev->type && dev->type->uevent) {
retval = dev->type->uevent(dev, env);
if (retval)
diff --git a/drivers/base/node.c b/drivers/base/node.c
index ee53558b452f..ce012a9c6201 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -160,6 +160,18 @@ static ssize_t node_read_numastat(struct sys_device * dev,
}
static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
+static ssize_t node_read_vmstat(struct sys_device *dev,
+ struct sysdev_attribute *attr, char *buf)
+{
+ int nid = dev->id;
+ return sprintf(buf,
+ "nr_written %lu\n"
+ "nr_dirtied %lu\n",
+ node_page_state(nid, NR_WRITTEN),
+ node_page_state(nid, NR_DIRTIED));
+}
+static SYSDEV_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL);
+
static ssize_t node_read_distance(struct sys_device * dev,
struct sysdev_attribute *attr, char * buf)
{
@@ -243,6 +255,7 @@ int register_node(struct node *node, int num, struct node *parent)
sysdev_create_file(&node->sysdev, &attr_meminfo);
sysdev_create_file(&node->sysdev, &attr_numastat);
sysdev_create_file(&node->sysdev, &attr_distance);
+ sysdev_create_file(&node->sysdev, &attr_vmstat);
scan_unevictable_register_node(node);
@@ -267,6 +280,7 @@ void unregister_node(struct node *node)
sysdev_remove_file(&node->sysdev, &attr_meminfo);
sysdev_remove_file(&node->sysdev, &attr_numastat);
sysdev_remove_file(&node->sysdev, &attr_distance);
+ sysdev_remove_file(&node->sysdev, &attr_vmstat);
scan_unevictable_unregister_node(node);
hugetlb_unregister_node(node); /* no-op, if memoryless node */
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 3966e62ad019..f051cfff18af 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -147,6 +147,7 @@ static void platform_device_release(struct device *dev)
struct platform_object *pa = container_of(dev, struct platform_object,
pdev.dev);
+ of_device_node_put(&pa->pdev.dev);
kfree(pa->pdev.dev.platform_data);
kfree(pa->pdev.resource);
kfree(pa);
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 1dd8676d7f55..126ca492dd08 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -503,7 +503,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
* the resume will actually succeed.
*/
if (dev->power.no_callbacks && !parent && dev->parent) {
- spin_lock(&dev->parent->power.lock);
+ spin_lock_nested(&dev->parent->power.lock, SINGLE_DEPTH_NESTING);
if (dev->parent->power.disable_depth > 0
|| dev->parent->power.ignore_children
|| dev->parent->power.runtime_status == RPM_ACTIVE) {
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index f21c237a9e5e..541e18879965 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -4,12 +4,14 @@
* block device routines
*/
+#include <linux/kernel.h>
#include <linux/hdreg.h>
#include <linux/blkdev.h>
#include <linux/backing-dev.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
+#include <linux/ratelimit.h>
#include <linux/genhd.h>
#include <linux/netdevice.h>
#include <linux/mutex.h>
@@ -207,7 +209,7 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio)
spin_lock_irqsave(&d->lock, flags);
if ((d->flags & DEVFL_UP) == 0) {
- printk(KERN_INFO "aoe: device %ld.%d is not up\n",
+ pr_info_ratelimited("aoe: device %ld.%d is not up\n",
d->aoemajor, d->aoeminor);
spin_unlock_irqrestore(&d->lock, flags);
mempool_free(buf, d->bufpool);
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index 0849280bfc1c..6b5110a47458 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -102,6 +102,7 @@ aoedev_freedev(struct aoedev *d)
{
struct aoetgt **t, **e;
+ cancel_work_sync(&d->work);
if (d->gd) {
aoedisk_rm_sysfs(d);
del_gendisk(d->gd);
@@ -135,7 +136,6 @@ aoedev_flush(const char __user *str, size_t cnt)
all = !strncmp(buf, "all", 3);
}
- flush_scheduled_work();
spin_lock_irqsave(&devlist_lock, flags);
dd = &devlist;
while ((d = *dd)) {
@@ -257,8 +257,6 @@ aoedev_exit(void)
struct aoedev *d;
ulong flags;
- flush_scheduled_work();
-
while ((d = devlist)) {
devlist = d->next;
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index f09e6df15aa7..2cc4dda46279 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -66,11 +66,6 @@ MODULE_VERSION("3.6.26");
MODULE_LICENSE("GPL");
static DEFINE_MUTEX(cciss_mutex);
-static int cciss_allow_hpsa;
-module_param(cciss_allow_hpsa, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(cciss_allow_hpsa,
- "Prevent cciss driver from accessing hardware known to be "
- " supported by the hpsa driver");
#include "cciss_cmd.h"
#include "cciss.h"
@@ -98,19 +93,6 @@ static const struct pci_device_id cciss_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3215},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3237},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x323D},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3241},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3243},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3245},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3247},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324A},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324B},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3350},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3351},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3352},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3353},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3354},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3355},
{0,}
};
@@ -138,24 +120,9 @@ static struct board_type products[] = {
{0x3214103C, "Smart Array E200i", &SA5_access},
{0x3215103C, "Smart Array E200i", &SA5_access},
{0x3237103C, "Smart Array E500", &SA5_access},
-/* controllers below this line are also supported by the hpsa driver. */
-#define HPSA_BOUNDARY 0x3223103C
{0x3223103C, "Smart Array P800", &SA5_access},
{0x3234103C, "Smart Array P400", &SA5_access},
{0x323D103C, "Smart Array P700m", &SA5_access},
- {0x3241103C, "Smart Array P212", &SA5_access},
- {0x3243103C, "Smart Array P410", &SA5_access},
- {0x3245103C, "Smart Array P410i", &SA5_access},
- {0x3247103C, "Smart Array P411", &SA5_access},
- {0x3249103C, "Smart Array P812", &SA5_access},
- {0x324A103C, "Smart Array P712m", &SA5_access},
- {0x324B103C, "Smart Array P711m", &SA5_access},
- {0x3350103C, "Smart Array", &SA5_access},
- {0x3351103C, "Smart Array", &SA5_access},
- {0x3352103C, "Smart Array", &SA5_access},
- {0x3353103C, "Smart Array", &SA5_access},
- {0x3354103C, "Smart Array", &SA5_access},
- {0x3355103C, "Smart Array", &SA5_access},
};
/* How long to wait (in milliseconds) for board to go into simple mode */
@@ -1184,6 +1151,7 @@ static int cciss_ioctl32_big_passthru(struct block_device *bdev, fmode_t mode,
int err;
u32 cp;
+ memset(&arg64, 0, sizeof(arg64));
err = 0;
err |=
copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
@@ -3970,9 +3938,6 @@ static int __devinit cciss_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
subsystem_vendor_id;
for (i = 0; i < ARRAY_SIZE(products); i++) {
- /* Stand aside for hpsa driver on request */
- if (cciss_allow_hpsa && products[i].board_id == HPSA_BOUNDARY)
- return -ENODEV;
if (*board_id == products[i].board_id)
return i;
}
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index c5dfe6486cf3..25c7a73c5062 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -2982,7 +2982,7 @@ static int drbd_create_mempools(void)
drbd_ee_mempool = mempool_create(number,
mempool_alloc_slab, mempool_free_slab, drbd_ee_cache);
- if (drbd_request_mempool == NULL)
+ if (drbd_ee_mempool == NULL)
goto Enomem;
/* drbd's page pool */
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 6c48b3545f84..1e5284ef65fa 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -101,8 +101,8 @@ static int transfer_none(struct loop_device *lo, int cmd,
else
memcpy(raw_buf, loop_buf, size);
- kunmap_atomic(raw_buf, KM_USER0);
kunmap_atomic(loop_buf, KM_USER1);
+ kunmap_atomic(raw_buf, KM_USER0);
cond_resched();
return 0;
}
@@ -130,8 +130,8 @@ static int transfer_xor(struct loop_device *lo, int cmd,
for (i = 0; i < size; i++)
*out++ = *in++ ^ key[(i & 511) % keysize];
- kunmap_atomic(raw_buf, KM_USER0);
kunmap_atomic(loop_buf, KM_USER1);
+ kunmap_atomic(raw_buf, KM_USER0);
cond_resched();
return 0;
}
@@ -1049,9 +1049,9 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
if (bdev)
invalidate_bdev(bdev);
set_capacity(lo->lo_disk, 0);
+ loop_sysfs_exit(lo);
if (bdev) {
bd_set_size(bdev, 0);
- loop_sysfs_exit(lo);
/* let user-space know about this change */
kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
}
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index 6e968cd4893c..829161edae53 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -1225,7 +1225,8 @@ ace_of_probe(struct platform_device *op, const struct of_device_id *match)
bus_width = ACE_BUS_WIDTH_8;
/* Call the bus-independant setup code */
- return ace_alloc(&op->dev, id ? *id : 0, physaddr, irq, bus_width);
+ return ace_alloc(&op->dev, id ? be32_to_cpup(id) : 0,
+ physaddr, irq, bus_width);
}
static int __devexit ace_of_remove(struct platform_device *op)
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index dcd4cfcf4126..a22e3f895947 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -80,8 +80,10 @@ static void do_z2_request(struct request_queue *q)
int err = 0;
if (start + len > z2ram_size) {
- printk( KERN_ERR DEVICE_NAME ": bad access: block=%lu, count=%u\n",
- blk_rq_pos(req), blk_rq_cur_sectors(req));
+ pr_err(DEVICE_NAME ": bad access: block=%llu, "
+ "count=%u\n",
+ (unsigned long long)blk_rq_pos(req),
+ blk_rq_cur_sectors(req));
err = -EIO;
goto done;
}
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index 0d32ec82e9bf..548d1d9e4dda 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -117,8 +117,8 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
(event->data[2] == MODULE_ALREADY_UP)) ?
"Bring-up succeed" : "Bring-up failed");
- if (event->length > 3)
- priv->btmrvl_dev.dev_type = event->data[3];
+ if (event->length > 3 && event->data[3])
+ priv->btmrvl_dev.dev_type = HCI_AMP;
else
priv->btmrvl_dev.dev_type = HCI_BREDR;
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
index 76e5127884f0..792e32d29a1d 100644
--- a/drivers/bluetooth/btsdio.c
+++ b/drivers/bluetooth/btsdio.c
@@ -46,6 +46,9 @@ static const struct sdio_device_id btsdio_table[] = {
/* Generic Bluetooth Type-B SDIO device */
{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) },
+ /* Generic Bluetooth AMP controller */
+ { SDIO_DEVICE_CLASS(SDIO_CLASS_BT_AMP) },
+
{ } /* Terminating entry */
};
@@ -329,6 +332,11 @@ static int btsdio_probe(struct sdio_func *func,
hdev->bus = HCI_SDIO;
hdev->driver_data = data;
+ if (id->class == SDIO_CLASS_BT_AMP)
+ hdev->dev_type = HCI_AMP;
+ else
+ hdev->dev_type = HCI_BREDR;
+
data->hdev = hdev;
SET_HCIDEV_DEV(hdev, &func->dev);
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index d22ce3cc611e..d120a5c1c093 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -59,9 +59,15 @@ static struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
+ /* Apple MacBookPro 7,1 */
+ { USB_DEVICE(0x05ac, 0x8213) },
+
/* Apple iMac11,1 */
{ USB_DEVICE(0x05ac, 0x8215) },
+ /* Apple MacBookPro6,2 */
+ { USB_DEVICE(0x05ac, 0x8218) },
+
/* AVM BlueFRITZ! USB v2.0 */
{ USB_DEVICE(0x057c, 0x3800) },
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 17361bad46dd..720148294e64 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -101,7 +101,7 @@ static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
break;
case HCI_SCODATA_PKT:
- hdev->stat.cmd_tx++;
+ hdev->stat.sco_tx++;
break;
}
}
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index 5ddf67e76f8b..fcd867d923ba 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -34,7 +34,7 @@ config AGP_ALI
X on the following ALi chipsets. The supported chipsets
include M1541, M1621, M1631, M1632, M1641,M1647,and M1651.
For the ALi-chipset question, ALi suggests you refer to
- <http://www.ali.com.tw/eng/support/index.shtml>.
+ <http://www.ali.com.tw/>.
The M1541 chipset can do AGP 1x and 2x, but note that there is an
acknowledged incompatibility with Matrox G200 cards. Due to
diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
index 627f542827c7..8eb56e273e75 100644
--- a/drivers/char/agp/Makefile
+++ b/drivers/char/agp/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o
obj-$(CONFIG_AGP_PARISC) += parisc-agp.o
obj-$(CONFIG_AGP_I460) += i460-agp.o
obj-$(CONFIG_AGP_INTEL) += intel-agp.o
+obj-$(CONFIG_AGP_INTEL) += intel-gtt.o
obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o
obj-$(CONFIG_AGP_SGI_TIOCA) += sgi-agp.o
obj-$(CONFIG_AGP_SIS) += sis-agp.o
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 120490949997..5259065f3c79 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -121,11 +121,6 @@ struct agp_bridge_driver {
void (*agp_destroy_pages)(struct agp_memory *);
int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
void (*chipset_flush)(struct agp_bridge_data *);
-
- int (*agp_map_page)(struct page *page, dma_addr_t *ret);
- void (*agp_unmap_page)(struct page *page, dma_addr_t dma);
- int (*agp_map_memory)(struct agp_memory *mem);
- void (*agp_unmap_memory)(struct agp_memory *mem);
};
struct agp_bridge_data {
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index b6b1568314c8..b1b4362bc648 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -309,7 +309,8 @@ static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries;
- if (type != 0 || mem->type != 0)
+ if (type != mem->type ||
+ agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type))
return -EINVAL;
if ((pg_start + mem->page_count) > num_entries)
@@ -348,7 +349,8 @@ static int amd_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
unsigned long __iomem *cur_gatt;
unsigned long addr;
- if (type != 0 || mem->type != 0)
+ if (type != mem->type ||
+ agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type))
return -EINVAL;
for (i = pg_start; i < (mem->page_count + pg_start); i++) {
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index ee4f855611b6..f27d0d0816d3 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -151,17 +151,7 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
}
bridge->scratch_page_page = page;
- if (bridge->driver->agp_map_page) {
- if (bridge->driver->agp_map_page(page,
- &bridge->scratch_page_dma)) {
- dev_err(&bridge->dev->dev,
- "unable to dma-map scratch page\n");
- rc = -ENOMEM;
- goto err_out_nounmap;
- }
- } else {
- bridge->scratch_page_dma = page_to_phys(page);
- }
+ bridge->scratch_page_dma = page_to_phys(page);
bridge->scratch_page = bridge->driver->mask_memory(bridge,
bridge->scratch_page_dma, 0);
@@ -204,12 +194,6 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
return 0;
err_out:
- if (bridge->driver->needs_scratch_page &&
- bridge->driver->agp_unmap_page) {
- bridge->driver->agp_unmap_page(bridge->scratch_page_page,
- bridge->scratch_page_dma);
- }
-err_out_nounmap:
if (bridge->driver->needs_scratch_page) {
void *va = page_address(bridge->scratch_page_page);
@@ -240,10 +224,6 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge)
bridge->driver->needs_scratch_page) {
void *va = page_address(bridge->scratch_page_page);
- if (bridge->driver->agp_unmap_page)
- bridge->driver->agp_unmap_page(bridge->scratch_page_page,
- bridge->scratch_page_dma);
-
bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
}
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 64255cef8a7d..4956f1c8f9d5 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -437,11 +437,6 @@ int agp_bind_memory(struct agp_memory *curr, off_t pg_start)
curr->is_flushed = true;
}
- if (curr->bridge->driver->agp_map_memory) {
- ret_val = curr->bridge->driver->agp_map_memory(curr);
- if (ret_val)
- return ret_val;
- }
ret_val = curr->bridge->driver->insert_memory(curr, pg_start, curr->type);
if (ret_val != 0)
@@ -483,9 +478,6 @@ int agp_unbind_memory(struct agp_memory *curr)
if (ret_val != 0)
return ret_val;
- if (curr->bridge->driver->agp_unmap_memory)
- curr->bridge->driver->agp_unmap_memory(curr);
-
curr->is_bound = false;
curr->pg_start = 0;
spin_lock(&curr->bridge->mapped_lock);
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index e763d3312ce7..75b763cb3ea1 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -1,7 +1,7 @@
/*
* For documentation on the i460 AGP interface, see Chapter 7 (AGP Subsystem) of
* the "Intel 460GTX Chipset Software Developer's Manual":
- * http://developer.intel.com/design/itanium/downloads/24870401s.htm
+ * http://www.intel.com/design/archives/itanium/downloads/248704.htm
*/
/*
* 460GX support by Chris Ahna <christopher.j.ahna@intel.com>
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index cd18493c9527..e72f49d52202 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -12,9 +12,6 @@
#include <asm/smp.h>
#include "agp.h"
#include "intel-agp.h"
-#include <linux/intel-gtt.h>
-
-#include "intel-gtt.c"
int intel_agp_enabled;
EXPORT_SYMBOL(intel_agp_enabled);
@@ -703,179 +700,37 @@ static const struct agp_bridge_driver intel_7505_driver = {
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static int find_gmch(u16 device)
-{
- struct pci_dev *gmch_device;
-
- gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
- if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) {
- gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL,
- device, gmch_device);
- }
-
- if (!gmch_device)
- return 0;
-
- intel_private.pcidev = gmch_device;
- return 1;
-}
-
/* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of
* driver and gmch_driver must be non-null, and find_gmch will determine
* which one should be used if a gmch_chip_id is present.
*/
-static const struct intel_driver_description {
+static const struct intel_agp_driver_description {
unsigned int chip_id;
- unsigned int gmch_chip_id;
char *name;
const struct agp_bridge_driver *driver;
- const struct agp_bridge_driver *gmch_driver;
} intel_agp_chipsets[] = {
- { PCI_DEVICE_ID_INTEL_82443LX_0, 0, "440LX", &intel_generic_driver, NULL },
- { PCI_DEVICE_ID_INTEL_82443BX_0, 0, "440BX", &intel_generic_driver, NULL },
- { PCI_DEVICE_ID_INTEL_82443GX_0, 0, "440GX", &intel_generic_driver, NULL },
- { PCI_DEVICE_ID_INTEL_82810_MC1, PCI_DEVICE_ID_INTEL_82810_IG1, "i810",
- NULL, &intel_810_driver },
- { PCI_DEVICE_ID_INTEL_82810_MC3, PCI_DEVICE_ID_INTEL_82810_IG3, "i810",
- NULL, &intel_810_driver },
- { PCI_DEVICE_ID_INTEL_82810E_MC, PCI_DEVICE_ID_INTEL_82810E_IG, "i810",
- NULL, &intel_810_driver },
- { PCI_DEVICE_ID_INTEL_82815_MC, PCI_DEVICE_ID_INTEL_82815_CGC, "i815",
- &intel_815_driver, &intel_810_driver },
- { PCI_DEVICE_ID_INTEL_82820_HB, 0, "i820", &intel_820_driver, NULL },
- { PCI_DEVICE_ID_INTEL_82820_UP_HB, 0, "i820", &intel_820_driver, NULL },
- { PCI_DEVICE_ID_INTEL_82830_HB, PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
- &intel_830mp_driver, &intel_830_driver },
- { PCI_DEVICE_ID_INTEL_82840_HB, 0, "i840", &intel_840_driver, NULL },
- { PCI_DEVICE_ID_INTEL_82845_HB, 0, "845G", &intel_845_driver, NULL },
- { PCI_DEVICE_ID_INTEL_82845G_HB, PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
- &intel_845_driver, &intel_830_driver },
- { PCI_DEVICE_ID_INTEL_82850_HB, 0, "i850", &intel_850_driver, NULL },
- { PCI_DEVICE_ID_INTEL_82854_HB, PCI_DEVICE_ID_INTEL_82854_IG, "854",
- &intel_845_driver, &intel_830_driver },
- { PCI_DEVICE_ID_INTEL_82855PM_HB, 0, "855PM", &intel_845_driver, NULL },
- { PCI_DEVICE_ID_INTEL_82855GM_HB, PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM",
- &intel_845_driver, &intel_830_driver },
- { PCI_DEVICE_ID_INTEL_82860_HB, 0, "i860", &intel_860_driver, NULL },
- { PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, "865",
- &intel_845_driver, &intel_830_driver },
- { PCI_DEVICE_ID_INTEL_82875_HB, 0, "i875", &intel_845_driver, NULL },
- { PCI_DEVICE_ID_INTEL_E7221_HB, PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)",
- NULL, &intel_915_driver },
- { PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, "915G",
- NULL, &intel_915_driver },
- { PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM",
- NULL, &intel_915_driver },
- { PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, "945G",
- NULL, &intel_915_driver },
- { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM",
- NULL, &intel_915_driver },
- { PCI_DEVICE_ID_INTEL_82945GME_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME",
- NULL, &intel_915_driver },
- { PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ",
- NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_82G35_HB, PCI_DEVICE_ID_INTEL_82G35_IG, "G35",
- NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q",
- NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, "965G",
- NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM",
- NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_82965GME_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE",
- NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_7505_0, 0, "E7505", &intel_7505_driver, NULL },
- { PCI_DEVICE_ID_INTEL_7205_0, 0, "E7205", &intel_7505_driver, NULL },
- { PCI_DEVICE_ID_INTEL_G33_HB, PCI_DEVICE_ID_INTEL_G33_IG, "G33",
- NULL, &intel_g33_driver },
- { PCI_DEVICE_ID_INTEL_Q35_HB, PCI_DEVICE_ID_INTEL_Q35_IG, "Q35",
- NULL, &intel_g33_driver },
- { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, "Q33",
- NULL, &intel_g33_driver },
- { PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150",
- NULL, &intel_g33_driver },
- { PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150",
- NULL, &intel_g33_driver },
- { PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG,
- "GM45", NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_EAGLELAKE_HB, PCI_DEVICE_ID_INTEL_EAGLELAKE_IG,
- "Eaglelake", NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_Q45_HB, PCI_DEVICE_ID_INTEL_Q45_IG,
- "Q45/Q43", NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_G45_HB, PCI_DEVICE_ID_INTEL_G45_IG,
- "G45/G43", NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_B43_HB, PCI_DEVICE_ID_INTEL_B43_IG,
- "B43", NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_B43_1_HB, PCI_DEVICE_ID_INTEL_B43_1_IG,
- "B43", NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG,
- "G41", NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG,
- "HD Graphics", NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
- "HD Graphics", NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
- "HD Graphics", NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
- "HD Graphics", NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG,
- "Sandybridge", NULL, &intel_gen6_driver },
- { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG,
- "Sandybridge", NULL, &intel_gen6_driver },
- { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG,
- "Sandybridge", NULL, &intel_gen6_driver },
- { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG,
- "Sandybridge", NULL, &intel_gen6_driver },
- { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG,
- "Sandybridge", NULL, &intel_gen6_driver },
- { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG,
- "Sandybridge", NULL, &intel_gen6_driver },
- { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
- "Sandybridge", NULL, &intel_gen6_driver },
- { 0, 0, NULL, NULL, NULL }
+ { PCI_DEVICE_ID_INTEL_82443LX_0, "440LX", &intel_generic_driver },
+ { PCI_DEVICE_ID_INTEL_82443BX_0, "440BX", &intel_generic_driver },
+ { PCI_DEVICE_ID_INTEL_82443GX_0, "440GX", &intel_generic_driver },
+ { PCI_DEVICE_ID_INTEL_82815_MC, "i815", &intel_815_driver },
+ { PCI_DEVICE_ID_INTEL_82820_HB, "i820", &intel_820_driver },
+ { PCI_DEVICE_ID_INTEL_82820_UP_HB, "i820", &intel_820_driver },
+ { PCI_DEVICE_ID_INTEL_82830_HB, "830M", &intel_830mp_driver },
+ { PCI_DEVICE_ID_INTEL_82840_HB, "i840", &intel_840_driver },
+ { PCI_DEVICE_ID_INTEL_82845_HB, "845G", &intel_845_driver },
+ { PCI_DEVICE_ID_INTEL_82845G_HB, "830M", &intel_845_driver },
+ { PCI_DEVICE_ID_INTEL_82850_HB, "i850", &intel_850_driver },
+ { PCI_DEVICE_ID_INTEL_82854_HB, "854", &intel_845_driver },
+ { PCI_DEVICE_ID_INTEL_82855PM_HB, "855PM", &intel_845_driver },
+ { PCI_DEVICE_ID_INTEL_82855GM_HB, "855GM", &intel_845_driver },
+ { PCI_DEVICE_ID_INTEL_82860_HB, "i860", &intel_860_driver },
+ { PCI_DEVICE_ID_INTEL_82865_HB, "865", &intel_845_driver },
+ { PCI_DEVICE_ID_INTEL_82875_HB, "i875", &intel_845_driver },
+ { PCI_DEVICE_ID_INTEL_7505_0, "E7505", &intel_7505_driver },
+ { PCI_DEVICE_ID_INTEL_7205_0, "E7205", &intel_7505_driver },
+ { 0, NULL, NULL }
};
-static int __devinit intel_gmch_probe(struct pci_dev *pdev,
- struct agp_bridge_data *bridge)
-{
- int i, mask;
-
- bridge->driver = NULL;
-
- for (i = 0; intel_agp_chipsets[i].name != NULL; i++) {
- if ((intel_agp_chipsets[i].gmch_chip_id != 0) &&
- find_gmch(intel_agp_chipsets[i].gmch_chip_id)) {
- bridge->driver =
- intel_agp_chipsets[i].gmch_driver;
- break;
- }
- }
-
- if (!bridge->driver)
- return 0;
-
- bridge->dev_private_data = &intel_private;
- bridge->dev = pdev;
-
- dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);
-
- if (bridge->driver->mask_memory == intel_gen6_mask_memory)
- mask = 40;
- else if (bridge->driver->mask_memory == intel_i965_mask_memory)
- mask = 36;
- else
- mask = 32;
-
- if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask)))
- dev_err(&intel_private.pcidev->dev,
- "set gfx device dma mask %d-bit failed!\n", mask);
- else
- pci_set_consistent_dma_mask(intel_private.pcidev,
- DMA_BIT_MASK(mask));
-
- return 1;
-}
-
static int __devinit agp_intel_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -905,7 +760,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
}
}
- if (intel_agp_chipsets[i].name == NULL) {
+ if (!bridge->driver) {
if (cap_ptr)
dev_warn(&pdev->dev, "unsupported Intel chipset [%04x/%04x]\n",
pdev->vendor, pdev->device);
@@ -913,14 +768,6 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
return -ENODEV;
}
- if (!bridge->driver) {
- if (cap_ptr)
- dev_warn(&pdev->dev, "can't find bridge device (chip_id: %04x)\n",
- intel_agp_chipsets[i].gmch_chip_id);
- agp_put_bridge(bridge);
- return -ENODEV;
- }
-
bridge->dev = pdev;
bridge->dev_private_data = NULL;
@@ -972,8 +819,7 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev)
agp_remove_bridge(bridge);
- if (intel_private.pcidev)
- pci_dev_put(intel_private.pcidev);
+ intel_gmch_remove(pdev);
agp_put_bridge(bridge);
}
@@ -1049,6 +895,7 @@ static struct pci_device_id agp_intel_pci_table[] = {
ID(PCI_DEVICE_ID_INTEL_G45_HB),
ID(PCI_DEVICE_ID_INTEL_G41_HB),
ID(PCI_DEVICE_ID_INTEL_B43_HB),
+ ID(PCI_DEVICE_ID_INTEL_B43_1_HB),
ID(PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB),
ID(PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB),
ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB),
diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h
index d09b1ab7e8ab..90539df02504 100644
--- a/drivers/char/agp/intel-agp.h
+++ b/drivers/char/agp/intel-agp.h
@@ -215,44 +215,7 @@
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB 0x0108 /* Server */
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG 0x010A
-/* cover 915 and 945 variants */
-#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB)
-
-#define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82G35_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB)
-
-#define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q33_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
-
-#define IS_PINEVIEW (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
-
-#define IS_SNB (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB)
-
-#define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_EAGLELAKE_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_B43_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \
- IS_SNB)
-
+int intel_gmch_probe(struct pci_dev *pdev,
+ struct agp_bridge_data *bridge);
+void intel_gmch_remove(struct pci_dev *pdev);
#endif
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index 75e0a3497888..6b6760ea2435 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -15,6 +15,18 @@
* /fairy-tale-mode off
*/
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pagemap.h>
+#include <linux/agp_backend.h>
+#include <asm/smp.h>
+#include "agp.h"
+#include "intel-agp.h"
+#include <linux/intel-gtt.h>
+#include <drm/intel-gtt.h>
+
/*
* If we have Intel graphics, we're not going to have anything other than
* an Intel IOMMU. So make the correct use of the PCI DMA API contingent
@@ -23,11 +35,12 @@
*/
#ifdef CONFIG_DMAR
#define USE_PCI_DMA_API 1
+#else
+#define USE_PCI_DMA_API 0
#endif
/* Max amount of stolen space, anything above will be returned to Linux */
int intel_max_stolen = 32 * 1024 * 1024;
-EXPORT_SYMBOL(intel_max_stolen);
static const struct aper_size_info_fixed intel_i810_sizes[] =
{
@@ -55,32 +68,36 @@ static struct gatt_mask intel_i810_masks[] =
#define INTEL_AGP_CACHED_MEMORY_LLC_MLC 3
#define INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT 4
-static struct gatt_mask intel_gen6_masks[] =
-{
- {.mask = I810_PTE_VALID | GEN6_PTE_UNCACHED,
- .type = INTEL_AGP_UNCACHED_MEMORY },
- {.mask = I810_PTE_VALID | GEN6_PTE_LLC,
- .type = INTEL_AGP_CACHED_MEMORY_LLC },
- {.mask = I810_PTE_VALID | GEN6_PTE_LLC | GEN6_PTE_GFDT,
- .type = INTEL_AGP_CACHED_MEMORY_LLC_GFDT },
- {.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC,
- .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC },
- {.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC | GEN6_PTE_GFDT,
- .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT },
+struct intel_gtt_driver {
+ unsigned int gen : 8;
+ unsigned int is_g33 : 1;
+ unsigned int is_pineview : 1;
+ unsigned int is_ironlake : 1;
+ unsigned int dma_mask_size : 8;
+ /* Chipset specific GTT setup */
+ int (*setup)(void);
+ /* This should undo anything done in ->setup() save the unmapping
+ * of the mmio register file, that's done in the generic code. */
+ void (*cleanup)(void);
+ void (*write_entry)(dma_addr_t addr, unsigned int entry, unsigned int flags);
+ /* Flags is a more or less chipset specific opaque value.
+ * For chipsets that need to support old ums (non-gem) code, this
+ * needs to be identical to the various supported agp memory types! */
+ bool (*check_flags)(unsigned int flags);
+ void (*chipset_flush)(void);
};
static struct _intel_private {
+ struct intel_gtt base;
+ const struct intel_gtt_driver *driver;
struct pci_dev *pcidev; /* device one */
+ struct pci_dev *bridge_dev;
u8 __iomem *registers;
+ phys_addr_t gtt_bus_addr;
+ phys_addr_t gma_bus_addr;
+ phys_addr_t pte_bus_addr;
u32 __iomem *gtt; /* I915G */
int num_dcache_entries;
- /* gtt_entries is the number of gtt entries that are already mapped
- * to stolen memory. Stolen memory is larger than the memory mapped
- * through gtt_entries, as it includes some reserved space for the BIOS
- * popup and for the GTT.
- */
- int gtt_entries; /* i830+ */
- int gtt_total_size;
union {
void __iomem *i9xx_flush_page;
void *i8xx_flush_page;
@@ -88,23 +105,14 @@ static struct _intel_private {
struct page *i8xx_page;
struct resource ifp_resource;
int resource_valid;
+ struct page *scratch_page;
+ dma_addr_t scratch_page_dma;
} intel_private;
-#ifdef USE_PCI_DMA_API
-static int intel_agp_map_page(struct page *page, dma_addr_t *ret)
-{
- *ret = pci_map_page(intel_private.pcidev, page, 0,
- PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
- if (pci_dma_mapping_error(intel_private.pcidev, *ret))
- return -EINVAL;
- return 0;
-}
-
-static void intel_agp_unmap_page(struct page *page, dma_addr_t dma)
-{
- pci_unmap_page(intel_private.pcidev, dma,
- PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-}
+#define INTEL_GTT_GEN intel_private.driver->gen
+#define IS_G33 intel_private.driver->is_g33
+#define IS_PINEVIEW intel_private.driver->is_pineview
+#define IS_IRONLAKE intel_private.driver->is_ironlake
static void intel_agp_free_sglist(struct agp_memory *mem)
{
@@ -125,6 +133,9 @@ static int intel_agp_map_memory(struct agp_memory *mem)
struct scatterlist *sg;
int i;
+ if (mem->sg_list)
+ return 0; /* already mapped (for e.g. resume */
+
DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
@@ -156,70 +167,17 @@ static void intel_agp_unmap_memory(struct agp_memory *mem)
intel_agp_free_sglist(mem);
}
-static void intel_agp_insert_sg_entries(struct agp_memory *mem,
- off_t pg_start, int mask_type)
-{
- struct scatterlist *sg;
- int i, j;
-
- j = pg_start;
-
- WARN_ON(!mem->num_sg);
-
- if (mem->num_sg == mem->page_count) {
- for_each_sg(mem->sg_list, sg, mem->page_count, i) {
- writel(agp_bridge->driver->mask_memory(agp_bridge,
- sg_dma_address(sg), mask_type),
- intel_private.gtt+j);
- j++;
- }
- } else {
- /* sg may merge pages, but we have to separate
- * per-page addr for GTT */
- unsigned int len, m;
-
- for_each_sg(mem->sg_list, sg, mem->num_sg, i) {
- len = sg_dma_len(sg) / PAGE_SIZE;
- for (m = 0; m < len; m++) {
- writel(agp_bridge->driver->mask_memory(agp_bridge,
- sg_dma_address(sg) + m * PAGE_SIZE,
- mask_type),
- intel_private.gtt+j);
- j++;
- }
- }
- }
- readl(intel_private.gtt+j-1);
-}
-
-#else
-
-static void intel_agp_insert_sg_entries(struct agp_memory *mem,
- off_t pg_start, int mask_type)
-{
- int i, j;
-
- for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
- writel(agp_bridge->driver->mask_memory(agp_bridge,
- page_to_phys(mem->pages[i]), mask_type),
- intel_private.gtt+j);
- }
-
- readl(intel_private.gtt+j-1);
-}
-
-#endif
-
static int intel_i810_fetch_size(void)
{
u32 smram_miscc;
struct aper_size_info_fixed *values;
- pci_read_config_dword(agp_bridge->dev, I810_SMRAM_MISCC, &smram_miscc);
+ pci_read_config_dword(intel_private.bridge_dev,
+ I810_SMRAM_MISCC, &smram_miscc);
values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
- dev_warn(&agp_bridge->dev->dev, "i810 is disabled\n");
+ dev_warn(&intel_private.bridge_dev->dev, "i810 is disabled\n");
return 0;
}
if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
@@ -284,7 +242,7 @@ static void intel_i810_cleanup(void)
iounmap(intel_private.registers);
}
-static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode)
+static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode)
{
return;
}
@@ -319,34 +277,6 @@ static void i8xx_destroy_pages(struct page *page)
atomic_dec(&agp_bridge->current_memory_agp);
}
-static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge,
- int type)
-{
- if (type < AGP_USER_TYPES)
- return type;
- else if (type == AGP_USER_CACHED_MEMORY)
- return INTEL_AGP_CACHED_MEMORY;
- else
- return 0;
-}
-
-static int intel_gen6_type_to_mask_type(struct agp_bridge_data *bridge,
- int type)
-{
- unsigned int type_mask = type & ~AGP_USER_CACHED_MEMORY_GFDT;
- unsigned int gfdt = type & AGP_USER_CACHED_MEMORY_GFDT;
-
- if (type_mask == AGP_USER_UNCACHED_MEMORY)
- return INTEL_AGP_UNCACHED_MEMORY;
- else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC)
- return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT :
- INTEL_AGP_CACHED_MEMORY_LLC_MLC;
- else /* set 'normal'/'cached' to LLC by default */
- return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_GFDT :
- INTEL_AGP_CACHED_MEMORY_LLC;
-}
-
-
static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
int type)
{
@@ -514,8 +444,33 @@ static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge,
return addr | bridge->driver->masks[type].mask;
}
-static struct aper_size_info_fixed intel_i830_sizes[] =
+static int intel_gtt_setup_scratch_page(void)
{
+ struct page *page;
+ dma_addr_t dma_addr;
+
+ page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
+ if (page == NULL)
+ return -ENOMEM;
+ get_page(page);
+ set_pages_uc(page, 1);
+
+ if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) {
+ dma_addr = pci_map_page(intel_private.pcidev, page, 0,
+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(intel_private.pcidev, dma_addr))
+ return -EINVAL;
+
+ intel_private.scratch_page_dma = dma_addr;
+ } else
+ intel_private.scratch_page_dma = page_to_phys(page);
+
+ intel_private.scratch_page = page;
+
+ return 0;
+}
+
+static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = {
{128, 32768, 5},
/* The 64M mode still requires a 128k gatt */
{64, 16384, 5},
@@ -523,102 +478,49 @@ static struct aper_size_info_fixed intel_i830_sizes[] =
{512, 131072, 7},
};
-static void intel_i830_init_gtt_entries(void)
+static unsigned int intel_gtt_stolen_entries(void)
{
u16 gmch_ctrl;
- int gtt_entries = 0;
u8 rdct;
int local = 0;
static const int ddt[4] = { 0, 16, 32, 64 };
- int size; /* reserved space (in kb) at the top of stolen memory */
+ unsigned int overhead_entries, stolen_entries;
+ unsigned int stolen_size = 0;
- pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+ pci_read_config_word(intel_private.bridge_dev,
+ I830_GMCH_CTRL, &gmch_ctrl);
- if (IS_I965) {
- u32 pgetbl_ctl;
- pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+ if (INTEL_GTT_GEN > 4 || IS_PINEVIEW)
+ overhead_entries = 0;
+ else
+ overhead_entries = intel_private.base.gtt_mappable_entries
+ / 1024;
- /* The 965 has a field telling us the size of the GTT,
- * which may be larger than what is necessary to map the
- * aperture.
- */
- switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
- case I965_PGETBL_SIZE_128KB:
- size = 128;
- break;
- case I965_PGETBL_SIZE_256KB:
- size = 256;
- break;
- case I965_PGETBL_SIZE_512KB:
- size = 512;
- break;
- case I965_PGETBL_SIZE_1MB:
- size = 1024;
- break;
- case I965_PGETBL_SIZE_2MB:
- size = 2048;
- break;
- case I965_PGETBL_SIZE_1_5MB:
- size = 1024 + 512;
- break;
- default:
- dev_info(&intel_private.pcidev->dev,
- "unknown page table size, assuming 512KB\n");
- size = 512;
- }
- size += 4; /* add in BIOS popup space */
- } else if (IS_G33 && !IS_PINEVIEW) {
- /* G33's GTT size defined in gmch_ctrl */
- switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) {
- case G33_PGETBL_SIZE_1M:
- size = 1024;
- break;
- case G33_PGETBL_SIZE_2M:
- size = 2048;
- break;
- default:
- dev_info(&agp_bridge->dev->dev,
- "unknown page table size 0x%x, assuming 512KB\n",
- (gmch_ctrl & G33_PGETBL_SIZE_MASK));
- size = 512;
- }
- size += 4;
- } else if (IS_G4X || IS_PINEVIEW) {
- /* On 4 series hardware, GTT stolen is separate from graphics
- * stolen, ignore it in stolen gtt entries counting. However,
- * 4KB of the stolen memory doesn't get mapped to the GTT.
- */
- size = 4;
- } else {
- /* On previous hardware, the GTT size was just what was
- * required to map the aperture.
- */
- size = agp_bridge->driver->fetch_size() + 4;
- }
+ overhead_entries += 1; /* BIOS popup */
- if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
+ if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
+ intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
case I830_GMCH_GMS_STOLEN_512:
- gtt_entries = KB(512) - KB(size);
+ stolen_size = KB(512);
break;
case I830_GMCH_GMS_STOLEN_1024:
- gtt_entries = MB(1) - KB(size);
+ stolen_size = MB(1);
break;
case I830_GMCH_GMS_STOLEN_8192:
- gtt_entries = MB(8) - KB(size);
+ stolen_size = MB(8);
break;
case I830_GMCH_GMS_LOCAL:
rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE);
- gtt_entries = (I830_RDRAM_ND(rdct) + 1) *
+ stolen_size = (I830_RDRAM_ND(rdct) + 1) *
MB(ddt[I830_RDRAM_DDT(rdct)]);
local = 1;
break;
default:
- gtt_entries = 0;
+ stolen_size = 0;
break;
}
- } else if (IS_SNB) {
+ } else if (INTEL_GTT_GEN == 6) {
/*
* SandyBridge has new memory control reg at 0x50.w
*/
@@ -626,149 +528,292 @@ static void intel_i830_init_gtt_entries(void)
pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) {
case SNB_GMCH_GMS_STOLEN_32M:
- gtt_entries = MB(32) - KB(size);
+ stolen_size = MB(32);
break;
case SNB_GMCH_GMS_STOLEN_64M:
- gtt_entries = MB(64) - KB(size);
+ stolen_size = MB(64);
break;
case SNB_GMCH_GMS_STOLEN_96M:
- gtt_entries = MB(96) - KB(size);
+ stolen_size = MB(96);
break;
case SNB_GMCH_GMS_STOLEN_128M:
- gtt_entries = MB(128) - KB(size);
+ stolen_size = MB(128);
break;
case SNB_GMCH_GMS_STOLEN_160M:
- gtt_entries = MB(160) - KB(size);
+ stolen_size = MB(160);
break;
case SNB_GMCH_GMS_STOLEN_192M:
- gtt_entries = MB(192) - KB(size);
+ stolen_size = MB(192);
break;
case SNB_GMCH_GMS_STOLEN_224M:
- gtt_entries = MB(224) - KB(size);
+ stolen_size = MB(224);
break;
case SNB_GMCH_GMS_STOLEN_256M:
- gtt_entries = MB(256) - KB(size);
+ stolen_size = MB(256);
break;
case SNB_GMCH_GMS_STOLEN_288M:
- gtt_entries = MB(288) - KB(size);
+ stolen_size = MB(288);
break;
case SNB_GMCH_GMS_STOLEN_320M:
- gtt_entries = MB(320) - KB(size);
+ stolen_size = MB(320);
break;
case SNB_GMCH_GMS_STOLEN_352M:
- gtt_entries = MB(352) - KB(size);
+ stolen_size = MB(352);
break;
case SNB_GMCH_GMS_STOLEN_384M:
- gtt_entries = MB(384) - KB(size);
+ stolen_size = MB(384);
break;
case SNB_GMCH_GMS_STOLEN_416M:
- gtt_entries = MB(416) - KB(size);
+ stolen_size = MB(416);
break;
case SNB_GMCH_GMS_STOLEN_448M:
- gtt_entries = MB(448) - KB(size);
+ stolen_size = MB(448);
break;
case SNB_GMCH_GMS_STOLEN_480M:
- gtt_entries = MB(480) - KB(size);
+ stolen_size = MB(480);
break;
case SNB_GMCH_GMS_STOLEN_512M:
- gtt_entries = MB(512) - KB(size);
+ stolen_size = MB(512);
break;
}
} else {
switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
case I855_GMCH_GMS_STOLEN_1M:
- gtt_entries = MB(1) - KB(size);
+ stolen_size = MB(1);
break;
case I855_GMCH_GMS_STOLEN_4M:
- gtt_entries = MB(4) - KB(size);
+ stolen_size = MB(4);
break;
case I855_GMCH_GMS_STOLEN_8M:
- gtt_entries = MB(8) - KB(size);
+ stolen_size = MB(8);
break;
case I855_GMCH_GMS_STOLEN_16M:
- gtt_entries = MB(16) - KB(size);
+ stolen_size = MB(16);
break;
case I855_GMCH_GMS_STOLEN_32M:
- gtt_entries = MB(32) - KB(size);
+ stolen_size = MB(32);
break;
case I915_GMCH_GMS_STOLEN_48M:
- /* Check it's really I915G */
- if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
- gtt_entries = MB(48) - KB(size);
- else
- gtt_entries = 0;
+ stolen_size = MB(48);
break;
case I915_GMCH_GMS_STOLEN_64M:
- /* Check it's really I915G */
- if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
- gtt_entries = MB(64) - KB(size);
- else
- gtt_entries = 0;
+ stolen_size = MB(64);
break;
case G33_GMCH_GMS_STOLEN_128M:
- if (IS_G33 || IS_I965 || IS_G4X)
- gtt_entries = MB(128) - KB(size);
- else
- gtt_entries = 0;
+ stolen_size = MB(128);
break;
case G33_GMCH_GMS_STOLEN_256M:
- if (IS_G33 || IS_I965 || IS_G4X)
- gtt_entries = MB(256) - KB(size);
- else
- gtt_entries = 0;
+ stolen_size = MB(256);
break;
case INTEL_GMCH_GMS_STOLEN_96M:
- if (IS_I965 || IS_G4X)
- gtt_entries = MB(96) - KB(size);
- else
- gtt_entries = 0;
+ stolen_size = MB(96);
break;
case INTEL_GMCH_GMS_STOLEN_160M:
- if (IS_I965 || IS_G4X)
- gtt_entries = MB(160) - KB(size);
- else
- gtt_entries = 0;
+ stolen_size = MB(160);
break;
case INTEL_GMCH_GMS_STOLEN_224M:
- if (IS_I965 || IS_G4X)
- gtt_entries = MB(224) - KB(size);
- else
- gtt_entries = 0;
+ stolen_size = MB(224);
break;
case INTEL_GMCH_GMS_STOLEN_352M:
- if (IS_I965 || IS_G4X)
- gtt_entries = MB(352) - KB(size);
- else
- gtt_entries = 0;
+ stolen_size = MB(352);
break;
default:
- gtt_entries = 0;
+ stolen_size = 0;
break;
}
}
- if (!local && gtt_entries > intel_max_stolen) {
- dev_info(&agp_bridge->dev->dev,
+
+ if (!local && stolen_size > intel_max_stolen) {
+ dev_info(&intel_private.bridge_dev->dev,
"detected %dK stolen memory, trimming to %dK\n",
- gtt_entries / KB(1), intel_max_stolen / KB(1));
- gtt_entries = intel_max_stolen / KB(4);
- } else if (gtt_entries > 0) {
- dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n",
- gtt_entries / KB(1), local ? "local" : "stolen");
- gtt_entries /= KB(4);
+ stolen_size / KB(1), intel_max_stolen / KB(1));
+ stolen_size = intel_max_stolen;
+ } else if (stolen_size > 0) {
+ dev_info(&intel_private.bridge_dev->dev, "detected %dK %s memory\n",
+ stolen_size / KB(1), local ? "local" : "stolen");
} else {
- dev_info(&agp_bridge->dev->dev,
+ dev_info(&intel_private.bridge_dev->dev,
"no pre-allocated video memory detected\n");
- gtt_entries = 0;
+ stolen_size = 0;
+ }
+
+ stolen_entries = stolen_size/KB(4) - overhead_entries;
+
+ return stolen_entries;
+}
+
+static unsigned int intel_gtt_total_entries(void)
+{
+ int size;
+
+ if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) {
+ u32 pgetbl_ctl;
+ pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+
+ switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
+ case I965_PGETBL_SIZE_128KB:
+ size = KB(128);
+ break;
+ case I965_PGETBL_SIZE_256KB:
+ size = KB(256);
+ break;
+ case I965_PGETBL_SIZE_512KB:
+ size = KB(512);
+ break;
+ case I965_PGETBL_SIZE_1MB:
+ size = KB(1024);
+ break;
+ case I965_PGETBL_SIZE_2MB:
+ size = KB(2048);
+ break;
+ case I965_PGETBL_SIZE_1_5MB:
+ size = KB(1024 + 512);
+ break;
+ default:
+ dev_info(&intel_private.pcidev->dev,
+ "unknown page table size, assuming 512KB\n");
+ size = KB(512);
+ }
+
+ return size/4;
+ } else if (INTEL_GTT_GEN == 6) {
+ u16 snb_gmch_ctl;
+
+ pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
+ switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) {
+ default:
+ case SNB_GTT_SIZE_0M:
+ printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl);
+ size = MB(0);
+ break;
+ case SNB_GTT_SIZE_1M:
+ size = MB(1);
+ break;
+ case SNB_GTT_SIZE_2M:
+ size = MB(2);
+ break;
+ }
+ return size/4;
+ } else {
+ /* On previous hardware, the GTT size was just what was
+ * required to map the aperture.
+ */
+ return intel_private.base.gtt_mappable_entries;
+ }
+}
+
+static unsigned int intel_gtt_mappable_entries(void)
+{
+ unsigned int aperture_size;
+
+ if (INTEL_GTT_GEN == 2) {
+ u16 gmch_ctrl;
+
+ pci_read_config_word(intel_private.bridge_dev,
+ I830_GMCH_CTRL, &gmch_ctrl);
+
+ if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M)
+ aperture_size = MB(64);
+ else
+ aperture_size = MB(128);
+ } else {
+ /* 9xx supports large sizes, just look at the length */
+ aperture_size = pci_resource_len(intel_private.pcidev, 2);
}
- intel_private.gtt_entries = gtt_entries;
+ return aperture_size >> PAGE_SHIFT;
}
-static void intel_i830_fini_flush(void)
+static void intel_gtt_teardown_scratch_page(void)
+{
+ set_pages_wb(intel_private.scratch_page, 1);
+ pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma,
+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+ put_page(intel_private.scratch_page);
+ __free_page(intel_private.scratch_page);
+}
+
+static void intel_gtt_cleanup(void)
+{
+ intel_private.driver->cleanup();
+
+ iounmap(intel_private.gtt);
+ iounmap(intel_private.registers);
+
+ intel_gtt_teardown_scratch_page();
+}
+
+static int intel_gtt_init(void)
+{
+ u32 gtt_map_size;
+ int ret;
+
+ ret = intel_private.driver->setup();
+ if (ret != 0)
+ return ret;
+
+ intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries();
+ intel_private.base.gtt_total_entries = intel_gtt_total_entries();
+
+ dev_info(&intel_private.bridge_dev->dev,
+ "detected gtt size: %dK total, %dK mappable\n",
+ intel_private.base.gtt_total_entries * 4,
+ intel_private.base.gtt_mappable_entries * 4);
+
+ gtt_map_size = intel_private.base.gtt_total_entries * 4;
+
+ intel_private.gtt = ioremap(intel_private.gtt_bus_addr,
+ gtt_map_size);
+ if (!intel_private.gtt) {
+ intel_private.driver->cleanup();
+ iounmap(intel_private.registers);
+ return -ENOMEM;
+ }
+
+ global_cache_flush(); /* FIXME: ? */
+
+ /* we have to call this as early as possible after the MMIO base address is known */
+ intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries();
+ if (intel_private.base.gtt_stolen_entries == 0) {
+ intel_private.driver->cleanup();
+ iounmap(intel_private.registers);
+ iounmap(intel_private.gtt);
+ return -ENOMEM;
+ }
+
+ ret = intel_gtt_setup_scratch_page();
+ if (ret != 0) {
+ intel_gtt_cleanup();
+ return ret;
+ }
+
+ return 0;
+}
+
+static int intel_fake_agp_fetch_size(void)
+{
+ int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes);
+ unsigned int aper_size;
+ int i;
+
+ aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT)
+ / MB(1);
+
+ for (i = 0; i < num_sizes; i++) {
+ if (aper_size == intel_fake_agp_sizes[i].size) {
+ agp_bridge->current_size =
+ (void *) (intel_fake_agp_sizes + i);
+ return aper_size;
+ }
+ }
+
+ return 0;
+}
+
+static void i830_cleanup(void)
{
kunmap(intel_private.i8xx_page);
intel_private.i8xx_flush_page = NULL;
- unmap_page_from_agp(intel_private.i8xx_page);
__free_page(intel_private.i8xx_page);
intel_private.i8xx_page = NULL;
@@ -780,13 +825,13 @@ static void intel_i830_setup_flush(void)
if (intel_private.i8xx_page)
return;
- intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32);
+ intel_private.i8xx_page = alloc_page(GFP_KERNEL);
if (!intel_private.i8xx_page)
return;
intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
if (!intel_private.i8xx_flush_page)
- intel_i830_fini_flush();
+ i830_cleanup();
}
/* The chipset_flush interface needs to get data that has already been
@@ -799,7 +844,7 @@ static void intel_i830_setup_flush(void)
* that buffer out, we just fill 1KB and clflush it out, on the assumption
* that it'll push whatever was in there out. It appears to work.
*/
-static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
+static void i830_chipset_flush(void)
{
unsigned int *pg = intel_private.i8xx_flush_page;
@@ -811,169 +856,184 @@ static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
printk(KERN_ERR "Timed out waiting for cache flush.\n");
}
-/* The intel i830 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge)
+static void i830_write_entry(dma_addr_t addr, unsigned int entry,
+ unsigned int flags)
{
- int page_order;
- struct aper_size_info_fixed *size;
- int num_entries;
- u32 temp;
+ u32 pte_flags = I810_PTE_VALID;
+
+ switch (flags) {
+ case AGP_DCACHE_MEMORY:
+ pte_flags |= I810_PTE_LOCAL;
+ break;
+ case AGP_USER_CACHED_MEMORY:
+ pte_flags |= I830_PTE_SYSTEM_CACHED;
+ break;
+ }
- size = agp_bridge->current_size;
- page_order = size->page_order;
- num_entries = size->num_entries;
- agp_bridge->gatt_table_real = NULL;
+ writel(addr | pte_flags, intel_private.gtt + entry);
+}
- pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
- temp &= 0xfff80000;
+static void intel_enable_gtt(void)
+{
+ u32 gma_addr;
+ u16 gmch_ctrl;
- intel_private.registers = ioremap(temp, 128 * 4096);
- if (!intel_private.registers)
- return -ENOMEM;
+ if (INTEL_GTT_GEN == 2)
+ pci_read_config_dword(intel_private.pcidev, I810_GMADDR,
+ &gma_addr);
+ else
+ pci_read_config_dword(intel_private.pcidev, I915_GMADDR,
+ &gma_addr);
- temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
- global_cache_flush(); /* FIXME: ?? */
+ intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK);
- /* we have to call this as early as possible after the MMIO base address is known */
- intel_i830_init_gtt_entries();
- if (intel_private.gtt_entries == 0) {
- iounmap(intel_private.registers);
+ pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl);
+ gmch_ctrl |= I830_GMCH_ENABLED;
+ pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl);
+
+ writel(intel_private.pte_bus_addr|I810_PGETBL_ENABLED,
+ intel_private.registers+I810_PGETBL_CTL);
+ readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
+}
+
+static int i830_setup(void)
+{
+ u32 reg_addr;
+
+ pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &reg_addr);
+ reg_addr &= 0xfff80000;
+
+ intel_private.registers = ioremap(reg_addr, KB(64));
+ if (!intel_private.registers)
return -ENOMEM;
- }
- agp_bridge->gatt_table = NULL;
+ intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE;
+ intel_private.pte_bus_addr =
+ readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
- agp_bridge->gatt_bus_addr = temp;
+ intel_i830_setup_flush();
return 0;
}
-/* Return the gatt table to a sane state. Use the top of stolen
- * memory for the GTT.
- */
-static int intel_i830_free_gatt_table(struct agp_bridge_data *bridge)
+static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge)
{
+ agp_bridge->gatt_table_real = NULL;
+ agp_bridge->gatt_table = NULL;
+ agp_bridge->gatt_bus_addr = 0;
+
return 0;
}
-static int intel_i830_fetch_size(void)
+static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge)
{
- u16 gmch_ctrl;
- struct aper_size_info_fixed *values;
-
- values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
-
- if (agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82830_HB &&
- agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) {
- /* 855GM/852GM/865G has 128MB aperture size */
- agp_bridge->current_size = (void *) values;
- agp_bridge->aperture_size_idx = 0;
- return values[0].size;
- }
-
- pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-
- if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
- agp_bridge->current_size = (void *) values;
- agp_bridge->aperture_size_idx = 0;
- return values[0].size;
- } else {
- agp_bridge->current_size = (void *) (values + 1);
- agp_bridge->aperture_size_idx = 1;
- return values[1].size;
- }
-
return 0;
}
-static int intel_i830_configure(void)
+static int intel_fake_agp_configure(void)
{
- struct aper_size_info_fixed *current_size;
- u32 temp;
- u16 gmch_ctrl;
int i;
- current_size = A_SIZE_FIX(agp_bridge->current_size);
-
- pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
- pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
- gmch_ctrl |= I830_GMCH_ENABLED;
- pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
+ intel_enable_gtt();
- writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
- readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
+ agp_bridge->gart_bus_addr = intel_private.gma_bus_addr;
- if (agp_bridge->driver->needs_scratch_page) {
- for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) {
- writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
- }
- readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */
+ for (i = intel_private.base.gtt_stolen_entries;
+ i < intel_private.base.gtt_total_entries; i++) {
+ intel_private.driver->write_entry(intel_private.scratch_page_dma,
+ i, 0);
}
+ readl(intel_private.gtt+i-1); /* PCI Posting. */
global_cache_flush();
- intel_i830_setup_flush();
return 0;
}
-static void intel_i830_cleanup(void)
+static bool i830_check_flags(unsigned int flags)
{
- iounmap(intel_private.registers);
+ switch (flags) {
+ case 0:
+ case AGP_PHYS_MEMORY:
+ case AGP_USER_CACHED_MEMORY:
+ case AGP_USER_MEMORY:
+ return true;
+ }
+
+ return false;
}
-static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
- int type)
+static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list,
+ unsigned int sg_len,
+ unsigned int pg_start,
+ unsigned int flags)
{
- int i, j, num_entries;
- void *temp;
+ struct scatterlist *sg;
+ unsigned int len, m;
+ int i, j;
+
+ j = pg_start;
+
+ /* sg may merge pages, but we have to separate
+ * per-page addr for GTT */
+ for_each_sg(sg_list, sg, sg_len, i) {
+ len = sg_dma_len(sg) >> PAGE_SHIFT;
+ for (m = 0; m < len; m++) {
+ dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
+ intel_private.driver->write_entry(addr,
+ j, flags);
+ j++;
+ }
+ }
+ readl(intel_private.gtt+j-1);
+}
+
+static int intel_fake_agp_insert_entries(struct agp_memory *mem,
+ off_t pg_start, int type)
+{
+ int i, j;
int ret = -EINVAL;
- int mask_type;
if (mem->page_count == 0)
goto out;
- temp = agp_bridge->current_size;
- num_entries = A_SIZE_FIX(temp)->num_entries;
-
- if (pg_start < intel_private.gtt_entries) {
+ if (pg_start < intel_private.base.gtt_stolen_entries) {
dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
- "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
- pg_start, intel_private.gtt_entries);
+ "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n",
+ pg_start, intel_private.base.gtt_stolen_entries);
dev_info(&intel_private.pcidev->dev,
"trying to insert into local/stolen memory\n");
goto out_err;
}
- if ((pg_start + mem->page_count) > num_entries)
+ if ((pg_start + mem->page_count) > intel_private.base.gtt_total_entries)
goto out_err;
- /* The i830 can't check the GTT for entries since its read only,
- * depend on the caller to make the correct offset decisions.
- */
-
if (type != mem->type)
goto out_err;
- mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
-
- if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
- mask_type != INTEL_AGP_CACHED_MEMORY)
+ if (!intel_private.driver->check_flags(type))
goto out_err;
if (!mem->is_flushed)
global_cache_flush();
- for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
- writel(agp_bridge->driver->mask_memory(agp_bridge,
- page_to_phys(mem->pages[i]), mask_type),
- intel_private.registers+I810_PTE_BASE+(j*4));
+ if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) {
+ ret = intel_agp_map_memory(mem);
+ if (ret != 0)
+ return ret;
+
+ intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg,
+ pg_start, type);
+ } else {
+ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+ dma_addr_t addr = page_to_phys(mem->pages[i]);
+ intel_private.driver->write_entry(addr,
+ j, type);
+ }
+ readl(intel_private.gtt+j-1);
}
- readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
out:
ret = 0;
@@ -982,29 +1042,39 @@ out_err:
return ret;
}
-static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start,
- int type)
+static int intel_fake_agp_remove_entries(struct agp_memory *mem,
+ off_t pg_start, int type)
{
int i;
if (mem->page_count == 0)
return 0;
- if (pg_start < intel_private.gtt_entries) {
+ if (pg_start < intel_private.base.gtt_stolen_entries) {
dev_info(&intel_private.pcidev->dev,
"trying to disable local/stolen memory\n");
return -EINVAL;
}
+ if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2)
+ intel_agp_unmap_memory(mem);
+
for (i = pg_start; i < (mem->page_count + pg_start); i++) {
- writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
+ intel_private.driver->write_entry(intel_private.scratch_page_dma,
+ i, 0);
}
- readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
+ readl(intel_private.gtt+i-1);
return 0;
}
-static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
+static void intel_fake_agp_chipset_flush(struct agp_bridge_data *bridge)
+{
+ intel_private.driver->chipset_flush();
+}
+
+static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count,
+ int type)
{
if (type == AGP_PHYS_MEMORY)
return alloc_agpphysmem_i8xx(pg_count, type);
@@ -1015,9 +1085,9 @@ static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
static int intel_alloc_chipset_flush_resource(void)
{
int ret;
- ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
+ ret = pci_bus_alloc_resource(intel_private.bridge_dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
PAGE_SIZE, PCIBIOS_MIN_MEM, 0,
- pcibios_align_resource, agp_bridge->dev);
+ pcibios_align_resource, intel_private.bridge_dev);
return ret;
}
@@ -1027,11 +1097,11 @@ static void intel_i915_setup_chipset_flush(void)
int ret;
u32 temp;
- pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp);
+ pci_read_config_dword(intel_private.bridge_dev, I915_IFPADDR, &temp);
if (!(temp & 0x1)) {
intel_alloc_chipset_flush_resource();
intel_private.resource_valid = 1;
- pci_write_config_dword(agp_bridge->dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+ pci_write_config_dword(intel_private.bridge_dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
} else {
temp &= ~1;
@@ -1050,17 +1120,17 @@ static void intel_i965_g33_setup_chipset_flush(void)
u32 temp_hi, temp_lo;
int ret;
- pci_read_config_dword(agp_bridge->dev, I965_IFPADDR + 4, &temp_hi);
- pci_read_config_dword(agp_bridge->dev, I965_IFPADDR, &temp_lo);
+ pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, &temp_hi);
+ pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR, &temp_lo);
if (!(temp_lo & 0x1)) {
intel_alloc_chipset_flush_resource();
intel_private.resource_valid = 1;
- pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4,
+ pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4,
upper_32_bits(intel_private.ifp_resource.start));
- pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+ pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
} else {
u64 l64;
@@ -1083,7 +1153,7 @@ static void intel_i9xx_setup_flush(void)
if (intel_private.ifp_resource.start)
return;
- if (IS_SNB)
+ if (INTEL_GTT_GEN == 6)
return;
/* setup a resource for this object */
@@ -1091,7 +1161,7 @@ static void intel_i9xx_setup_flush(void)
intel_private.ifp_resource.flags = IORESOURCE_MEM;
/* Setup chipset flush for 915 */
- if (IS_I965 || IS_G33 || IS_G4X) {
+ if (IS_G33 || INTEL_GTT_GEN >= 4) {
intel_i965_g33_setup_chipset_flush();
} else {
intel_i915_setup_chipset_flush();
@@ -1104,41 +1174,7 @@ static void intel_i9xx_setup_flush(void)
"can't ioremap flush page - no chipset flushing\n");
}
-static int intel_i9xx_configure(void)
-{
- struct aper_size_info_fixed *current_size;
- u32 temp;
- u16 gmch_ctrl;
- int i;
-
- current_size = A_SIZE_FIX(agp_bridge->current_size);
-
- pci_read_config_dword(intel_private.pcidev, I915_GMADDR, &temp);
-
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
- pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
- gmch_ctrl |= I830_GMCH_ENABLED;
- pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
-
- writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
- readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
-
- if (agp_bridge->driver->needs_scratch_page) {
- for (i = intel_private.gtt_entries; i < intel_private.gtt_total_size; i++) {
- writel(agp_bridge->scratch_page, intel_private.gtt+i);
- }
- readl(intel_private.gtt+i-1); /* PCI Posting. */
- }
-
- global_cache_flush();
-
- intel_i9xx_setup_flush();
-
- return 0;
-}
-
-static void intel_i915_cleanup(void)
+static void i9xx_cleanup(void)
{
if (intel_private.i9xx_flush_page)
iounmap(intel_private.i9xx_flush_page);
@@ -1146,320 +1182,93 @@ static void intel_i915_cleanup(void)
release_resource(&intel_private.ifp_resource);
intel_private.ifp_resource.start = 0;
intel_private.resource_valid = 0;
- iounmap(intel_private.gtt);
- iounmap(intel_private.registers);
}
-static void intel_i915_chipset_flush(struct agp_bridge_data *bridge)
+static void i9xx_chipset_flush(void)
{
if (intel_private.i9xx_flush_page)
writel(1, intel_private.i9xx_flush_page);
}
-static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
- int type)
+static void i965_write_entry(dma_addr_t addr, unsigned int entry,
+ unsigned int flags)
{
- int num_entries;
- void *temp;
- int ret = -EINVAL;
- int mask_type;
-
- if (mem->page_count == 0)
- goto out;
-
- temp = agp_bridge->current_size;
- num_entries = A_SIZE_FIX(temp)->num_entries;
-
- if (pg_start < intel_private.gtt_entries) {
- dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
- "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
- pg_start, intel_private.gtt_entries);
-
- dev_info(&intel_private.pcidev->dev,
- "trying to insert into local/stolen memory\n");
- goto out_err;
- }
-
- if ((pg_start + mem->page_count) > num_entries)
- goto out_err;
-
- /* The i915 can't check the GTT for entries since it's read only;
- * depend on the caller to make the correct offset decisions.
- */
-
- if (type != mem->type)
- goto out_err;
-
- mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
-
- if (!IS_SNB && mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
- mask_type != INTEL_AGP_CACHED_MEMORY)
- goto out_err;
-
- if (!mem->is_flushed)
- global_cache_flush();
-
- intel_agp_insert_sg_entries(mem, pg_start, mask_type);
-
- out:
- ret = 0;
- out_err:
- mem->is_flushed = true;
- return ret;
+ /* Shift high bits down */
+ addr |= (addr >> 28) & 0xf0;
+ writel(addr | I810_PTE_VALID, intel_private.gtt + entry);
}
-static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start,
- int type)
+static bool gen6_check_flags(unsigned int flags)
{
- int i;
-
- if (mem->page_count == 0)
- return 0;
-
- if (pg_start < intel_private.gtt_entries) {
- dev_info(&intel_private.pcidev->dev,
- "trying to disable local/stolen memory\n");
- return -EINVAL;
- }
-
- for (i = pg_start; i < (mem->page_count + pg_start); i++)
- writel(agp_bridge->scratch_page, intel_private.gtt+i);
-
- readl(intel_private.gtt+i-1);
-
- return 0;
+ return true;
}
-/* Return the aperture size by just checking the resource length. The effect
- * described in the spec of the MSAC registers is just changing of the
- * resource size.
- */
-static int intel_i9xx_fetch_size(void)
+static void gen6_write_entry(dma_addr_t addr, unsigned int entry,
+ unsigned int flags)
{
- int num_sizes = ARRAY_SIZE(intel_i830_sizes);
- int aper_size; /* size in megabytes */
- int i;
-
- aper_size = pci_resource_len(intel_private.pcidev, 2) / MB(1);
+ unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT;
+ unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT;
+ u32 pte_flags;
- for (i = 0; i < num_sizes; i++) {
- if (aper_size == intel_i830_sizes[i].size) {
- agp_bridge->current_size = intel_i830_sizes + i;
- return aper_size;
- }
+ if (type_mask == AGP_USER_UNCACHED_MEMORY)
+ pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID;
+ else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) {
+ pte_flags = GEN6_PTE_LLC | I810_PTE_VALID;
+ if (gfdt)
+ pte_flags |= GEN6_PTE_GFDT;
+ } else { /* set 'normal'/'cached' to LLC by default */
+ pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID;
+ if (gfdt)
+ pte_flags |= GEN6_PTE_GFDT;
}
- return 0;
+ /* gen6 has bit11-4 for physical addr bit39-32 */
+ addr |= (addr >> 28) & 0xff0;
+ writel(addr | pte_flags, intel_private.gtt + entry);
}
-static int intel_i915_get_gtt_size(void)
+static void gen6_cleanup(void)
{
- int size;
-
- if (IS_G33) {
- u16 gmch_ctrl;
-
- /* G33's GTT size defined in gmch_ctrl */
- pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
- switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
- case I830_GMCH_GMS_STOLEN_512:
- size = 512;
- break;
- case I830_GMCH_GMS_STOLEN_1024:
- size = 1024;
- break;
- case I830_GMCH_GMS_STOLEN_8192:
- size = 8*1024;
- break;
- default:
- dev_info(&agp_bridge->dev->dev,
- "unknown page table size 0x%x, assuming 512KB\n",
- (gmch_ctrl & I830_GMCH_GMS_MASK));
- size = 512;
- }
- } else {
- /* On previous hardware, the GTT size was just what was
- * required to map the aperture.
- */
- size = agp_bridge->driver->fetch_size();
- }
-
- return KB(size);
}
-/* The intel i915 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
+static int i9xx_setup(void)
{
- int page_order;
- struct aper_size_info_fixed *size;
- int num_entries;
- u32 temp, temp2;
- int gtt_map_size;
-
- size = agp_bridge->current_size;
- page_order = size->page_order;
- num_entries = size->num_entries;
- agp_bridge->gatt_table_real = NULL;
-
- pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
- pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2);
+ u32 reg_addr;
- gtt_map_size = intel_i915_get_gtt_size();
-
- intel_private.gtt = ioremap(temp2, gtt_map_size);
- if (!intel_private.gtt)
- return -ENOMEM;
-
- intel_private.gtt_total_size = gtt_map_size / 4;
-
- temp &= 0xfff80000;
-
- intel_private.registers = ioremap(temp, 128 * 4096);
- if (!intel_private.registers) {
- iounmap(intel_private.gtt);
- return -ENOMEM;
- }
+ pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &reg_addr);
- temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
- global_cache_flush(); /* FIXME: ? */
+ reg_addr &= 0xfff80000;
- /* we have to call this as early as possible after the MMIO base address is known */
- intel_i830_init_gtt_entries();
- if (intel_private.gtt_entries == 0) {
- iounmap(intel_private.gtt);
- iounmap(intel_private.registers);
+ intel_private.registers = ioremap(reg_addr, 128 * 4096);
+ if (!intel_private.registers)
return -ENOMEM;
- }
-
- agp_bridge->gatt_table = NULL;
-
- agp_bridge->gatt_bus_addr = temp;
-
- return 0;
-}
-
-/*
- * The i965 supports 36-bit physical addresses, but to keep
- * the format of the GTT the same, the bits that don't fit
- * in a 32-bit word are shifted down to bits 4..7.
- *
- * Gcc is smart enough to notice that "(addr >> 28) & 0xf0"
- * is always zero on 32-bit architectures, so no need to make
- * this conditional.
- */
-static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
- dma_addr_t addr, int type)
-{
- /* Shift high bits down */
- addr |= (addr >> 28) & 0xf0;
-
- /* Type checking must be done elsewhere */
- return addr | bridge->driver->masks[type].mask;
-}
-static unsigned long intel_gen6_mask_memory(struct agp_bridge_data *bridge,
- dma_addr_t addr, int type)
-{
- /* gen6 has bit11-4 for physical addr bit39-32 */
- addr |= (addr >> 28) & 0xff0;
+ if (INTEL_GTT_GEN == 3) {
+ u32 gtt_addr;
- /* Type checking must be done elsewhere */
- return addr | bridge->driver->masks[type].mask;
-}
-
-static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
-{
- u16 snb_gmch_ctl;
-
- switch (agp_bridge->dev->device) {
- case PCI_DEVICE_ID_INTEL_GM45_HB:
- case PCI_DEVICE_ID_INTEL_EAGLELAKE_HB:
- case PCI_DEVICE_ID_INTEL_Q45_HB:
- case PCI_DEVICE_ID_INTEL_G45_HB:
- case PCI_DEVICE_ID_INTEL_G41_HB:
- case PCI_DEVICE_ID_INTEL_B43_HB:
- case PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB:
- case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB:
- case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB:
- case PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB:
- *gtt_offset = *gtt_size = MB(2);
- break;
- case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB:
- case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB:
- case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB:
- *gtt_offset = MB(2);
+ pci_read_config_dword(intel_private.pcidev,
+ I915_PTEADDR, &gtt_addr);
+ intel_private.gtt_bus_addr = gtt_addr;
+ } else {
+ u32 gtt_offset;
- pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
- switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) {
- default:
- case SNB_GTT_SIZE_0M:
- printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl);
- *gtt_size = MB(0);
+ switch (INTEL_GTT_GEN) {
+ case 5:
+ case 6:
+ gtt_offset = MB(2);
break;
- case SNB_GTT_SIZE_1M:
- *gtt_size = MB(1);
- break;
- case SNB_GTT_SIZE_2M:
- *gtt_size = MB(2);
+ case 4:
+ default:
+ gtt_offset = KB(512);
break;
}
- break;
- default:
- *gtt_offset = *gtt_size = KB(512);
+ intel_private.gtt_bus_addr = reg_addr + gtt_offset;
}
-}
-
-/* The intel i965 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
-{
- int page_order;
- struct aper_size_info_fixed *size;
- int num_entries;
- u32 temp;
- int gtt_offset, gtt_size;
-
- size = agp_bridge->current_size;
- page_order = size->page_order;
- num_entries = size->num_entries;
- agp_bridge->gatt_table_real = NULL;
-
- pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
-
- temp &= 0xfff00000;
-
- intel_i965_get_gtt_range(&gtt_offset, &gtt_size);
- intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size);
+ intel_private.pte_bus_addr =
+ readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
- if (!intel_private.gtt)
- return -ENOMEM;
-
- intel_private.gtt_total_size = gtt_size / 4;
-
- intel_private.registers = ioremap(temp, 128 * 4096);
- if (!intel_private.registers) {
- iounmap(intel_private.gtt);
- return -ENOMEM;
- }
-
- temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
- global_cache_flush(); /* FIXME: ? */
-
- /* we have to call this as early as possible after the MMIO base address is known */
- intel_i830_init_gtt_entries();
- if (intel_private.gtt_entries == 0) {
- iounmap(intel_private.gtt);
- iounmap(intel_private.registers);
- return -ENOMEM;
- }
-
- agp_bridge->gatt_table = NULL;
-
- agp_bridge->gatt_bus_addr = temp;
+ intel_i9xx_setup_flush();
return 0;
}
@@ -1475,7 +1284,7 @@ static const struct agp_bridge_driver intel_810_driver = {
.cleanup = intel_i810_cleanup,
.mask_memory = intel_i810_mask_memory,
.masks = intel_i810_masks,
- .agp_enable = intel_i810_agp_enable,
+ .agp_enable = intel_fake_agp_enable,
.cache_flush = global_cache_flush,
.create_gatt_table = agp_generic_create_gatt_table,
.free_gatt_table = agp_generic_free_gatt_table,
@@ -1490,161 +1299,282 @@ static const struct agp_bridge_driver intel_810_driver = {
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static const struct agp_bridge_driver intel_830_driver = {
+static const struct agp_bridge_driver intel_fake_agp_driver = {
.owner = THIS_MODULE,
- .aperture_sizes = intel_i830_sizes,
.size_type = FIXED_APER_SIZE,
- .num_aperture_sizes = 4,
- .needs_scratch_page = true,
- .configure = intel_i830_configure,
- .fetch_size = intel_i830_fetch_size,
- .cleanup = intel_i830_cleanup,
- .mask_memory = intel_i810_mask_memory,
- .masks = intel_i810_masks,
- .agp_enable = intel_i810_agp_enable,
+ .aperture_sizes = intel_fake_agp_sizes,
+ .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes),
+ .configure = intel_fake_agp_configure,
+ .fetch_size = intel_fake_agp_fetch_size,
+ .cleanup = intel_gtt_cleanup,
+ .agp_enable = intel_fake_agp_enable,
.cache_flush = global_cache_flush,
- .create_gatt_table = intel_i830_create_gatt_table,
- .free_gatt_table = intel_i830_free_gatt_table,
- .insert_memory = intel_i830_insert_entries,
- .remove_memory = intel_i830_remove_entries,
- .alloc_by_type = intel_i830_alloc_by_type,
+ .create_gatt_table = intel_fake_agp_create_gatt_table,
+ .free_gatt_table = intel_fake_agp_free_gatt_table,
+ .insert_memory = intel_fake_agp_insert_entries,
+ .remove_memory = intel_fake_agp_remove_entries,
+ .alloc_by_type = intel_fake_agp_alloc_by_type,
.free_by_type = intel_i810_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_alloc_pages = agp_generic_alloc_pages,
.agp_destroy_page = agp_generic_destroy_page,
.agp_destroy_pages = agp_generic_destroy_pages,
- .agp_type_to_mask_type = intel_i830_type_to_mask_type,
- .chipset_flush = intel_i830_chipset_flush,
+ .chipset_flush = intel_fake_agp_chipset_flush,
};
-static const struct agp_bridge_driver intel_915_driver = {
- .owner = THIS_MODULE,
- .aperture_sizes = intel_i830_sizes,
- .size_type = FIXED_APER_SIZE,
- .num_aperture_sizes = 4,
- .needs_scratch_page = true,
- .configure = intel_i9xx_configure,
- .fetch_size = intel_i9xx_fetch_size,
- .cleanup = intel_i915_cleanup,
- .mask_memory = intel_i810_mask_memory,
- .masks = intel_i810_masks,
- .agp_enable = intel_i810_agp_enable,
- .cache_flush = global_cache_flush,
- .create_gatt_table = intel_i915_create_gatt_table,
- .free_gatt_table = intel_i830_free_gatt_table,
- .insert_memory = intel_i915_insert_entries,
- .remove_memory = intel_i915_remove_entries,
- .alloc_by_type = intel_i830_alloc_by_type,
- .free_by_type = intel_i810_free_by_type,
- .agp_alloc_page = agp_generic_alloc_page,
- .agp_alloc_pages = agp_generic_alloc_pages,
- .agp_destroy_page = agp_generic_destroy_page,
- .agp_destroy_pages = agp_generic_destroy_pages,
- .agp_type_to_mask_type = intel_i830_type_to_mask_type,
- .chipset_flush = intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
- .agp_map_page = intel_agp_map_page,
- .agp_unmap_page = intel_agp_unmap_page,
- .agp_map_memory = intel_agp_map_memory,
- .agp_unmap_memory = intel_agp_unmap_memory,
-#endif
+static const struct intel_gtt_driver i81x_gtt_driver = {
+ .gen = 1,
+ .dma_mask_size = 32,
};
-
-static const struct agp_bridge_driver intel_i965_driver = {
- .owner = THIS_MODULE,
- .aperture_sizes = intel_i830_sizes,
- .size_type = FIXED_APER_SIZE,
- .num_aperture_sizes = 4,
- .needs_scratch_page = true,
- .configure = intel_i9xx_configure,
- .fetch_size = intel_i9xx_fetch_size,
- .cleanup = intel_i915_cleanup,
- .mask_memory = intel_i965_mask_memory,
- .masks = intel_i810_masks,
- .agp_enable = intel_i810_agp_enable,
- .cache_flush = global_cache_flush,
- .create_gatt_table = intel_i965_create_gatt_table,
- .free_gatt_table = intel_i830_free_gatt_table,
- .insert_memory = intel_i915_insert_entries,
- .remove_memory = intel_i915_remove_entries,
- .alloc_by_type = intel_i830_alloc_by_type,
- .free_by_type = intel_i810_free_by_type,
- .agp_alloc_page = agp_generic_alloc_page,
- .agp_alloc_pages = agp_generic_alloc_pages,
- .agp_destroy_page = agp_generic_destroy_page,
- .agp_destroy_pages = agp_generic_destroy_pages,
- .agp_type_to_mask_type = intel_i830_type_to_mask_type,
- .chipset_flush = intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
- .agp_map_page = intel_agp_map_page,
- .agp_unmap_page = intel_agp_unmap_page,
- .agp_map_memory = intel_agp_map_memory,
- .agp_unmap_memory = intel_agp_unmap_memory,
-#endif
+static const struct intel_gtt_driver i8xx_gtt_driver = {
+ .gen = 2,
+ .setup = i830_setup,
+ .cleanup = i830_cleanup,
+ .write_entry = i830_write_entry,
+ .dma_mask_size = 32,
+ .check_flags = i830_check_flags,
+ .chipset_flush = i830_chipset_flush,
};
-
-static const struct agp_bridge_driver intel_gen6_driver = {
- .owner = THIS_MODULE,
- .aperture_sizes = intel_i830_sizes,
- .size_type = FIXED_APER_SIZE,
- .num_aperture_sizes = 4,
- .needs_scratch_page = true,
- .configure = intel_i9xx_configure,
- .fetch_size = intel_i9xx_fetch_size,
- .cleanup = intel_i915_cleanup,
- .mask_memory = intel_gen6_mask_memory,
- .masks = intel_gen6_masks,
- .agp_enable = intel_i810_agp_enable,
- .cache_flush = global_cache_flush,
- .create_gatt_table = intel_i965_create_gatt_table,
- .free_gatt_table = intel_i830_free_gatt_table,
- .insert_memory = intel_i915_insert_entries,
- .remove_memory = intel_i915_remove_entries,
- .alloc_by_type = intel_i830_alloc_by_type,
- .free_by_type = intel_i810_free_by_type,
- .agp_alloc_page = agp_generic_alloc_page,
- .agp_alloc_pages = agp_generic_alloc_pages,
- .agp_destroy_page = agp_generic_destroy_page,
- .agp_destroy_pages = agp_generic_destroy_pages,
- .agp_type_to_mask_type = intel_gen6_type_to_mask_type,
- .chipset_flush = intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
- .agp_map_page = intel_agp_map_page,
- .agp_unmap_page = intel_agp_unmap_page,
- .agp_map_memory = intel_agp_map_memory,
- .agp_unmap_memory = intel_agp_unmap_memory,
-#endif
+static const struct intel_gtt_driver i915_gtt_driver = {
+ .gen = 3,
+ .setup = i9xx_setup,
+ .cleanup = i9xx_cleanup,
+ /* i945 is the last gpu to need phys mem (for overlay and cursors). */
+ .write_entry = i830_write_entry,
+ .dma_mask_size = 32,
+ .check_flags = i830_check_flags,
+ .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver g33_gtt_driver = {
+ .gen = 3,
+ .is_g33 = 1,
+ .setup = i9xx_setup,
+ .cleanup = i9xx_cleanup,
+ .write_entry = i965_write_entry,
+ .dma_mask_size = 36,
+ .check_flags = i830_check_flags,
+ .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver pineview_gtt_driver = {
+ .gen = 3,
+ .is_pineview = 1, .is_g33 = 1,
+ .setup = i9xx_setup,
+ .cleanup = i9xx_cleanup,
+ .write_entry = i965_write_entry,
+ .dma_mask_size = 36,
+ .check_flags = i830_check_flags,
+ .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver i965_gtt_driver = {
+ .gen = 4,
+ .setup = i9xx_setup,
+ .cleanup = i9xx_cleanup,
+ .write_entry = i965_write_entry,
+ .dma_mask_size = 36,
+ .check_flags = i830_check_flags,
+ .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver g4x_gtt_driver = {
+ .gen = 5,
+ .setup = i9xx_setup,
+ .cleanup = i9xx_cleanup,
+ .write_entry = i965_write_entry,
+ .dma_mask_size = 36,
+ .check_flags = i830_check_flags,
+ .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver ironlake_gtt_driver = {
+ .gen = 5,
+ .is_ironlake = 1,
+ .setup = i9xx_setup,
+ .cleanup = i9xx_cleanup,
+ .write_entry = i965_write_entry,
+ .dma_mask_size = 36,
+ .check_flags = i830_check_flags,
+ .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver sandybridge_gtt_driver = {
+ .gen = 6,
+ .setup = i9xx_setup,
+ .cleanup = gen6_cleanup,
+ .write_entry = gen6_write_entry,
+ .dma_mask_size = 40,
+ .check_flags = gen6_check_flags,
+ .chipset_flush = i9xx_chipset_flush,
};
-static const struct agp_bridge_driver intel_g33_driver = {
- .owner = THIS_MODULE,
- .aperture_sizes = intel_i830_sizes,
- .size_type = FIXED_APER_SIZE,
- .num_aperture_sizes = 4,
- .needs_scratch_page = true,
- .configure = intel_i9xx_configure,
- .fetch_size = intel_i9xx_fetch_size,
- .cleanup = intel_i915_cleanup,
- .mask_memory = intel_i965_mask_memory,
- .masks = intel_i810_masks,
- .agp_enable = intel_i810_agp_enable,
- .cache_flush = global_cache_flush,
- .create_gatt_table = intel_i915_create_gatt_table,
- .free_gatt_table = intel_i830_free_gatt_table,
- .insert_memory = intel_i915_insert_entries,
- .remove_memory = intel_i915_remove_entries,
- .alloc_by_type = intel_i830_alloc_by_type,
- .free_by_type = intel_i810_free_by_type,
- .agp_alloc_page = agp_generic_alloc_page,
- .agp_alloc_pages = agp_generic_alloc_pages,
- .agp_destroy_page = agp_generic_destroy_page,
- .agp_destroy_pages = agp_generic_destroy_pages,
- .agp_type_to_mask_type = intel_i830_type_to_mask_type,
- .chipset_flush = intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
- .agp_map_page = intel_agp_map_page,
- .agp_unmap_page = intel_agp_unmap_page,
- .agp_map_memory = intel_agp_map_memory,
- .agp_unmap_memory = intel_agp_unmap_memory,
-#endif
+/* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of
+ * driver and gmch_driver must be non-null, and find_gmch will determine
+ * which one should be used if a gmch_chip_id is present.
+ */
+static const struct intel_gtt_driver_description {
+ unsigned int gmch_chip_id;
+ char *name;
+ const struct agp_bridge_driver *gmch_driver;
+ const struct intel_gtt_driver *gtt_driver;
+} intel_gtt_chipsets[] = {
+ { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver,
+ &i81x_gtt_driver},
+ { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver,
+ &i81x_gtt_driver},
+ { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver,
+ &i81x_gtt_driver},
+ { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver,
+ &i81x_gtt_driver},
+ { PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
+ &intel_fake_agp_driver, &i8xx_gtt_driver},
+ { PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
+ &intel_fake_agp_driver, &i8xx_gtt_driver},
+ { PCI_DEVICE_ID_INTEL_82854_IG, "854",
+ &intel_fake_agp_driver, &i8xx_gtt_driver},
+ { PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM",
+ &intel_fake_agp_driver, &i8xx_gtt_driver},
+ { PCI_DEVICE_ID_INTEL_82865_IG, "865",
+ &intel_fake_agp_driver, &i8xx_gtt_driver},
+ { PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)",
+ &intel_fake_agp_driver, &i915_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_82915G_IG, "915G",
+ &intel_fake_agp_driver, &i915_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM",
+ &intel_fake_agp_driver, &i915_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_82945G_IG, "945G",
+ &intel_fake_agp_driver, &i915_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM",
+ &intel_fake_agp_driver, &i915_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME",
+ &intel_fake_agp_driver, &i915_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ",
+ &intel_fake_agp_driver, &i965_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_82G35_IG, "G35",
+ &intel_fake_agp_driver, &i965_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q",
+ &intel_fake_agp_driver, &i965_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_82965G_IG, "965G",
+ &intel_fake_agp_driver, &i965_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM",
+ &intel_fake_agp_driver, &i965_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE",
+ &intel_fake_agp_driver, &i965_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_G33_IG, "G33",
+ &intel_fake_agp_driver, &g33_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_Q35_IG, "Q35",
+ &intel_fake_agp_driver, &g33_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_Q33_IG, "Q33",
+ &intel_fake_agp_driver, &g33_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150",
+ &intel_fake_agp_driver, &pineview_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150",
+ &intel_fake_agp_driver, &pineview_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_GM45_IG, "GM45",
+ &intel_fake_agp_driver, &g4x_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake",
+ &intel_fake_agp_driver, &g4x_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43",
+ &intel_fake_agp_driver, &g4x_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43",
+ &intel_fake_agp_driver, &g4x_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_B43_IG, "B43",
+ &intel_fake_agp_driver, &g4x_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_B43_1_IG, "B43",
+ &intel_fake_agp_driver, &g4x_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_G41_IG, "G41",
+ &intel_fake_agp_driver, &g4x_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG,
+ "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
+ "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG,
+ "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG,
+ "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG,
+ "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG,
+ "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG,
+ "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG,
+ "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
+ "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+ { 0, NULL, NULL }
};
+
+static int find_gmch(u16 device)
+{
+ struct pci_dev *gmch_device;
+
+ gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
+ if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) {
+ gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL,
+ device, gmch_device);
+ }
+
+ if (!gmch_device)
+ return 0;
+
+ intel_private.pcidev = gmch_device;
+ return 1;
+}
+
+int intel_gmch_probe(struct pci_dev *pdev,
+ struct agp_bridge_data *bridge)
+{
+ int i, mask;
+ bridge->driver = NULL;
+
+ for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) {
+ if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) {
+ bridge->driver =
+ intel_gtt_chipsets[i].gmch_driver;
+ intel_private.driver =
+ intel_gtt_chipsets[i].gtt_driver;
+ break;
+ }
+ }
+
+ if (!bridge->driver)
+ return 0;
+
+ bridge->dev_private_data = &intel_private;
+ bridge->dev = pdev;
+
+ intel_private.bridge_dev = pci_dev_get(pdev);
+
+ dev_info(&pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name);
+
+ mask = intel_private.driver->dma_mask_size;
+ if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask)))
+ dev_err(&intel_private.pcidev->dev,
+ "set gfx device dma mask %d-bit failed!\n", mask);
+ else
+ pci_set_consistent_dma_mask(intel_private.pcidev,
+ DMA_BIT_MASK(mask));
+
+ if (bridge->driver == &intel_810_driver)
+ return 1;
+
+ if (intel_gtt_init() != 0)
+ return 0;
+
+ return 1;
+}
+EXPORT_SYMBOL(intel_gmch_probe);
+
+struct intel_gtt *intel_gtt_get(void)
+{
+ return &intel_private.base;
+}
+EXPORT_SYMBOL(intel_gtt_get);
+
+void intel_gmch_remove(struct pci_dev *pdev)
+{
+ if (intel_private.pcidev)
+ pci_dev_put(intel_private.pcidev);
+ if (intel_private.bridge_dev)
+ pci_dev_put(intel_private.bridge_dev);
+}
+EXPORT_SYMBOL(intel_gmch_remove);
+
+MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index 1c129211302d..17e380f5f818 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -358,8 +358,12 @@ parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
bridge->dev = fake_bridge_dev;
error = agp_add_bridge(bridge);
+ if (error)
+ goto fail;
+ return 0;
fail:
+ kfree(fake_bridge_dev);
return error;
}
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index 3022801669b1..45b987c9889e 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -7,8 +7,8 @@
* Intel Corporation, Microsoft Corporation. Advanced Power Management
* (APM) BIOS Interface Specification, Revision 1.2, February 1996.
*
- * [This document is available from Microsoft at:
- * http://www.microsoft.com/hwdev/busbios/amp_12.htm]
+ * This document is available from Microsoft at:
+ * http://www.microsoft.com/whdc/archive/amp_12.mspx
*/
#include <linux/module.h>
#include <linux/poll.h>
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index e7ba774beda6..25373df1dcf8 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -566,6 +566,7 @@ static ssize_t ac_read (struct file *filp, char __user *buf, size_t count, loff_
struct mailbox mailbox;
/* Got a packet for us */
+ memset(&st_loc, 0, sizeof(st_loc));
ret = do_ac_read(i, buf, &st_loc, &mailbox);
spin_unlock_irqrestore(&apbs[i].mutex, flags);
set_current_state(TASK_RUNNING);
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index a4eee324eb1e..55b8667f739f 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -32,12 +32,12 @@
#include <linux/bitops.h>
#include <linux/compat.h>
#include <linux/clocksource.h>
+#include <linux/uaccess.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <asm/current.h>
-#include <asm/uaccess.h>
#include <asm/system.h>
-#include <asm/io.h>
#include <asm/irq.h>
#include <asm/div64.h>
@@ -81,13 +81,13 @@ static cycle_t read_hpet(struct clocksource *cs)
}
static struct clocksource clocksource_hpet = {
- .name = "hpet",
- .rating = 250,
- .read = read_hpet,
- .mask = CLOCKSOURCE_MASK(64),
- .mult = 0, /* to be calculated */
- .shift = 10,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .name = "hpet",
+ .rating = 250,
+ .read = read_hpet,
+ .mask = CLOCKSOURCE_MASK(64),
+ .mult = 0, /* to be calculated */
+ .shift = 10,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static struct clocksource *hpet_clocksource;
#endif
@@ -465,6 +465,21 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
if (irq) {
unsigned long irq_flags;
+ if (devp->hd_flags & HPET_SHARED_IRQ) {
+ /*
+ * To prevent the interrupt handler from seeing an
+ * unwanted interrupt status bit, program the timer
+ * so that it will not fire in the near future ...
+ */
+ writel(readl(&timer->hpet_config) & ~Tn_TYPE_CNF_MASK,
+ &timer->hpet_config);
+ write_counter(read_counter(&hpet->hpet_mc),
+ &timer->hpet_compare);
+ /* ... and clear any left-over status. */
+ isr = 1 << (devp - devp->hd_hpets->hp_dev);
+ writel(isr, &hpet->hpet_isr);
+ }
+
sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev));
irq_flags = devp->hd_flags & HPET_SHARED_IRQ
? IRQF_SHARED : IRQF_DISABLED;
@@ -581,11 +596,10 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg,
break;
case HPET_INFO:
{
+ memset(info, 0, sizeof(*info));
if (devp->hd_ireqfreq)
info->hi_ireqfreq =
hpet_time_div(hpetp, devp->hd_ireqfreq);
- else
- info->hi_ireqfreq = 0;
info->hi_flags =
readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK;
info->hi_hpet = hpetp->hp_which;
@@ -811,7 +825,7 @@ int hpet_alloc(struct hpet_data *hdp)
struct hpets *hpetp;
size_t siz;
struct hpet __iomem *hpet;
- static struct hpets *last = NULL;
+ static struct hpets *last;
unsigned long period;
unsigned long long temp;
u32 remainder;
@@ -1000,6 +1014,8 @@ static int hpet_acpi_add(struct acpi_device *device)
return -ENODEV;
if (!data.hd_address || !data.hd_nirqs) {
+ if (data.hd_address)
+ iounmap(data.hd_address);
printk("%s: no address or irqs in _CRS\n", __func__);
return -ENODEV;
}
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 3afd62e856eb..e9cba13ee800 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -713,7 +713,6 @@ static int khvcd(void *unused)
struct hvc_struct *hp;
set_freezable();
- __set_current_state(TASK_RUNNING);
do {
poll_mask = 0;
hvc_kicked = 0;
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c
index 7b01bc609de3..c3425bb3a1f6 100644
--- a/drivers/char/hvc_iucv.c
+++ b/drivers/char/hvc_iucv.c
@@ -1303,13 +1303,11 @@ static int __init hvc_iucv_init(void)
if (rc) {
pr_err("Registering IUCV handlers failed with error code=%d\n",
rc);
- goto out_error_iucv;
+ goto out_error_hvc;
}
return 0;
-out_error_iucv:
- iucv_unregister(&hvc_iucv_handler, 0);
out_error_hvc:
for (i = 0; i < hvc_iucv_devices; i++)
if (hvc_iucv_table[i])
diff --git a/drivers/char/hvc_tile.c b/drivers/char/hvc_tile.c
index c4efb55cbc03..7a84a0595477 100644
--- a/drivers/char/hvc_tile.c
+++ b/drivers/char/hvc_tile.c
@@ -61,7 +61,8 @@ console_initcall(hvc_tile_console_init);
static int __init hvc_tile_init(void)
{
- hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128);
- return 0;
+ struct hvc_struct *s;
+ s = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128);
+ return IS_ERR(s) ? PTR_ERR(s) : 0;
}
device_initcall(hvc_tile_init);
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
index 60446f82a3fc..6b8e6d18a8e6 100644
--- a/drivers/char/hvc_xen.c
+++ b/drivers/char/hvc_xen.c
@@ -74,7 +74,8 @@ static int __write_console(const char *data, int len)
wmb(); /* write ring before updating pointer */
intf->out_prod = prod;
- notify_daemon();
+ if (sent)
+ notify_daemon();
return sent;
}
diff --git a/drivers/char/ip2/Makefile b/drivers/char/ip2/Makefile
index bc397d92b499..7b78e0dfc5b0 100644
--- a/drivers/char/ip2/Makefile
+++ b/drivers/char/ip2/Makefile
@@ -4,5 +4,5 @@
obj-$(CONFIG_COMPUTONE) += ip2.o
-ip2-objs := ip2main.o
+ip2-y := ip2main.o
diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile
index eb8a1a8c188e..16a93648d54e 100644
--- a/drivers/char/ipmi/Makefile
+++ b/drivers/char/ipmi/Makefile
@@ -2,7 +2,7 @@
# Makefile for the ipmi drivers.
#
-ipmi_si-objs := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o
+ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o
obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c
index 7b98c067190a..3ed20e8abc0d 100644
--- a/drivers/char/ipmi/ipmi_bt_sm.c
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
@@ -2,7 +2,7 @@
* ipmi_bt_sm.c
*
* The state machine for an Open IPMI BT sub-driver under ipmi_si.c, part
- * of the driver architecture at http://sourceforge.net/project/openipmi
+ * of the driver architecture at http://sourceforge.net/projects/openipmi
*
* Author: Rocky Craig <first.last@hp.com>
*
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index 1fc8876af1f5..2aa3977aae5e 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -916,7 +916,7 @@ static struct ipmi_smi_watcher smi_watcher =
.smi_gone = ipmi_smi_gone,
};
-static __init int init_ipmi_devintf(void)
+static int __init init_ipmi_devintf(void)
{
int rv;
@@ -954,7 +954,7 @@ static __init int init_ipmi_devintf(void)
}
module_init(init_ipmi_devintf);
-static __exit void cleanup_ipmi(void)
+static void __exit cleanup_ipmi(void)
{
struct ipmi_reg_list *entry, *entry2;
mutex_lock(&reg_list_mutex);
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 4f3f8c9ec262..2fe72f8edf44 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -4442,13 +4442,13 @@ static int ipmi_init_msghandler(void)
return 0;
}
-static __init int ipmi_init_msghandler_mod(void)
+static int __init ipmi_init_msghandler_mod(void)
{
ipmi_init_msghandler();
return 0;
}
-static __exit void cleanup_ipmi(void)
+static void __exit cleanup_ipmi(void)
{
int count;
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 7bd7c45b53ef..035da9e64a17 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1665,6 +1665,17 @@ static int check_hotmod_int_op(const char *curr, const char *option,
return 0;
}
+static struct smi_info *smi_info_alloc(void)
+{
+ struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL);
+
+ if (info) {
+ spin_lock_init(&info->si_lock);
+ spin_lock_init(&info->msg_lock);
+ }
+ return info;
+}
+
static int hotmod_handler(const char *val, struct kernel_param *kp)
{
char *str = kstrdup(val, GFP_KERNEL);
@@ -1779,7 +1790,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
}
if (op == HM_ADD) {
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = smi_info_alloc();
if (!info) {
rv = -ENOMEM;
goto out;
@@ -1835,7 +1846,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
return rv;
}
-static __devinit void hardcode_find_bmc(void)
+static void __devinit hardcode_find_bmc(void)
{
int i;
struct smi_info *info;
@@ -1844,7 +1855,7 @@ static __devinit void hardcode_find_bmc(void)
if (!ports[i] && !addrs[i])
continue;
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = smi_info_alloc();
if (!info)
return;
@@ -1974,8 +1985,7 @@ static int acpi_gpe_irq_setup(struct smi_info *info)
/*
* Defined at
- * http://h21007.www2.hp.com/portal/download/files
- * /unprot/hpspmi.pdf
+ * http://h21007.www2.hp.com/portal/download/files/unprot/hpspmi.pdf
*/
struct SPMITable {
s8 Signature[4];
@@ -2019,7 +2029,7 @@ struct SPMITable {
s8 spmi_id[1]; /* A '\0' terminated array starts here. */
};
-static __devinit int try_init_spmi(struct SPMITable *spmi)
+static int __devinit try_init_spmi(struct SPMITable *spmi)
{
struct smi_info *info;
@@ -2028,7 +2038,7 @@ static __devinit int try_init_spmi(struct SPMITable *spmi)
return -ENODEV;
}
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = smi_info_alloc();
if (!info) {
printk(KERN_ERR PFX "Could not allocate SI data (3)\n");
return -ENOMEM;
@@ -2102,7 +2112,7 @@ static __devinit int try_init_spmi(struct SPMITable *spmi)
return 0;
}
-static __devinit void spmi_find_bmc(void)
+static void __devinit spmi_find_bmc(void)
{
acpi_status status;
struct SPMITable *spmi;
@@ -2138,7 +2148,7 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
if (!acpi_dev)
return -ENODEV;
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = smi_info_alloc();
if (!info)
return -ENOMEM;
@@ -2315,11 +2325,11 @@ static int __devinit decode_dmi(const struct dmi_header *dm,
return 0;
}
-static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
+static void __devinit try_init_dmi(struct dmi_ipmi_data *ipmi_data)
{
struct smi_info *info;
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = smi_info_alloc();
if (!info) {
printk(KERN_ERR PFX "Could not allocate SI data\n");
return;
@@ -2426,7 +2436,7 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
int class_type = pdev->class & PCI_ERMC_CLASSCODE_TYPE_MASK;
struct smi_info *info;
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = smi_info_alloc();
if (!info)
return -ENOMEM;
@@ -2567,7 +2577,7 @@ static int __devinit ipmi_of_probe(struct platform_device *dev,
return -EINVAL;
}
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = smi_info_alloc();
if (!info) {
dev_err(&dev->dev,
@@ -3002,7 +3012,7 @@ static __devinitdata struct ipmi_default_vals
{ .port = 0 }
};
-static __devinit void default_find_bmc(void)
+static void __devinit default_find_bmc(void)
{
struct smi_info *info;
int i;
@@ -3014,7 +3024,7 @@ static __devinit void default_find_bmc(void)
if (check_legacy_ioport(ipmi_defaults[i].port))
continue;
#endif
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = smi_info_alloc();
if (!info)
return;
@@ -3139,9 +3149,6 @@ static int try_smi_init(struct smi_info *new_smi)
goto out_err;
}
- spin_lock_init(&(new_smi->si_lock));
- spin_lock_init(&(new_smi->msg_lock));
-
/* Do low-level detection first. */
if (new_smi->handlers->detect(new_smi->si_sm)) {
if (new_smi->addr_source)
@@ -3305,7 +3312,7 @@ static int try_smi_init(struct smi_info *new_smi)
return rv;
}
-static __devinit int init_ipmi_si(void)
+static int __devinit init_ipmi_si(void)
{
int i;
char *str;
@@ -3518,7 +3525,7 @@ static void cleanup_one_si(struct smi_info *to_clean)
kfree(to_clean);
}
-static __exit void cleanup_ipmi_si(void)
+static void __exit cleanup_ipmi_si(void)
{
struct smi_info *e, *tmp_e;
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index a7ca75212bfe..e95d7876ca6b 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -175,8 +175,7 @@ EXPORT_SYMBOL_GPL(unregister_keyboard_notifier);
*/
struct getset_keycode_data {
- unsigned int scancode;
- unsigned int keycode;
+ struct input_keymap_entry ke;
int error;
};
@@ -184,32 +183,50 @@ static int getkeycode_helper(struct input_handle *handle, void *data)
{
struct getset_keycode_data *d = data;
- d->error = input_get_keycode(handle->dev, d->scancode, &d->keycode);
+ d->error = input_get_keycode(handle->dev, &d->ke);
return d->error == 0; /* stop as soon as we successfully get one */
}
int getkeycode(unsigned int scancode)
{
- struct getset_keycode_data d = { scancode, 0, -ENODEV };
+ struct getset_keycode_data d = {
+ .ke = {
+ .flags = 0,
+ .len = sizeof(scancode),
+ .keycode = 0,
+ },
+ .error = -ENODEV,
+ };
+
+ memcpy(d.ke.scancode, &scancode, sizeof(scancode));
input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper);
- return d.error ?: d.keycode;
+ return d.error ?: d.ke.keycode;
}
static int setkeycode_helper(struct input_handle *handle, void *data)
{
struct getset_keycode_data *d = data;
- d->error = input_set_keycode(handle->dev, d->scancode, d->keycode);
+ d->error = input_set_keycode(handle->dev, &d->ke);
return d->error == 0; /* stop as soon as we successfully set one */
}
int setkeycode(unsigned int scancode, unsigned int keycode)
{
- struct getset_keycode_data d = { scancode, keycode, -ENODEV };
+ struct getset_keycode_data d = {
+ .ke = {
+ .flags = 0,
+ .len = sizeof(scancode),
+ .keycode = keycode,
+ },
+ .error = -ENODEV,
+ };
+
+ memcpy(d.ke.scancode, &scancode, sizeof(scancode));
input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper);
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index e985b1c2730e..1256454b2d43 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -876,6 +876,10 @@ static int memory_open(struct inode *inode, struct file *filp)
if (dev->dev_info)
filp->f_mapping->backing_dev_info = dev->dev_info;
+ /* Is /dev/mem or /dev/kmem ? */
+ if (dev->dev_info == &directly_mappable_cdev_bdi)
+ filp->f_mode |= FMODE_UNSIGNED_OFFSET;
+
if (dev->fops->open)
return dev->fops->open(inode, filp);
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index c070b53984e4..e6d75627c6c8 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -176,9 +176,9 @@ static void mmtimer_setup_int_2(int cpu, u64 expires)
* in order to insure that the setup succeeds in a deterministic time frame.
* It will check if the interrupt setup succeeded.
*/
-static int mmtimer_setup(int cpu, int comparator, unsigned long expires)
+static int mmtimer_setup(int cpu, int comparator, unsigned long expires,
+ u64 *set_completion_time)
{
-
switch (comparator) {
case 0:
mmtimer_setup_int_0(cpu, expires);
@@ -191,7 +191,8 @@ static int mmtimer_setup(int cpu, int comparator, unsigned long expires)
break;
}
/* We might've missed our expiration time */
- if (rtc_time() <= expires)
+ *set_completion_time = rtc_time();
+ if (*set_completion_time <= expires)
return 1;
/*
@@ -227,6 +228,8 @@ static int mmtimer_disable_int(long nasid, int comparator)
#define TIMER_OFF 0xbadcabLL /* Timer is not setup */
#define TIMER_SET 0 /* Comparator is set for this timer */
+#define MMTIMER_INTERVAL_RETRY_INCREMENT_DEFAULT 40
+
/* There is one of these for each timer */
struct mmtimer {
struct rb_node list;
@@ -242,6 +245,11 @@ struct mmtimer_node {
};
static struct mmtimer_node *timers;
+static unsigned mmtimer_interval_retry_increment =
+ MMTIMER_INTERVAL_RETRY_INCREMENT_DEFAULT;
+module_param(mmtimer_interval_retry_increment, uint, 0644);
+MODULE_PARM_DESC(mmtimer_interval_retry_increment,
+ "RTC ticks to add to expiration on interval retry (default 40)");
/*
* Add a new mmtimer struct to the node's mmtimer list.
@@ -289,7 +297,8 @@ static void mmtimer_set_next_timer(int nodeid)
struct mmtimer_node *n = &timers[nodeid];
struct mmtimer *x;
struct k_itimer *t;
- int o;
+ u64 expires, exp, set_completion_time;
+ int i;
restart:
if (n->next == NULL)
@@ -300,7 +309,8 @@ restart:
if (!t->it.mmtimer.incr) {
/* Not an interval timer */
if (!mmtimer_setup(x->cpu, COMPARATOR,
- t->it.mmtimer.expires)) {
+ t->it.mmtimer.expires,
+ &set_completion_time)) {
/* Late setup, fire now */
tasklet_schedule(&n->tasklet);
}
@@ -308,14 +318,23 @@ restart:
}
/* Interval timer */
- o = 0;
- while (!mmtimer_setup(x->cpu, COMPARATOR, t->it.mmtimer.expires)) {
- unsigned long e, e1;
- struct rb_node *next;
- t->it.mmtimer.expires += t->it.mmtimer.incr << o;
- t->it_overrun += 1 << o;
- o++;
- if (o > 20) {
+ i = 0;
+ expires = exp = t->it.mmtimer.expires;
+ while (!mmtimer_setup(x->cpu, COMPARATOR, expires,
+ &set_completion_time)) {
+ int to;
+
+ i++;
+ expires = set_completion_time +
+ mmtimer_interval_retry_increment + (1 << i);
+ /* Calculate overruns as we go. */
+ to = ((u64)(expires - exp) / t->it.mmtimer.incr);
+ if (to) {
+ t->it_overrun += to;
+ t->it.mmtimer.expires += t->it.mmtimer.incr * to;
+ exp = t->it.mmtimer.expires;
+ }
+ if (i > 20) {
printk(KERN_ALERT "mmtimer: cannot reschedule timer\n");
t->it.mmtimer.clock = TIMER_OFF;
n->next = rb_next(&x->list);
@@ -323,21 +342,6 @@ restart:
kfree(x);
goto restart;
}
-
- e = t->it.mmtimer.expires;
- next = rb_next(&x->list);
-
- if (next == NULL)
- continue;
-
- e1 = rb_entry(next, struct mmtimer, list)->
- timer->it.mmtimer.expires;
- if (e > e1) {
- n->next = next;
- rb_erase(&x->list, &n->timer_head);
- mmtimer_add_list(x);
- goto restart;
- }
}
}
diff --git a/drivers/char/mwave/Makefile b/drivers/char/mwave/Makefile
index 754c9e2058ed..26b4fce217b6 100644
--- a/drivers/char/mwave/Makefile
+++ b/drivers/char/mwave/Makefile
@@ -6,10 +6,10 @@
obj-$(CONFIG_MWAVE) += mwave.o
-mwave-objs := mwavedd.o smapi.o tp3780i.o 3780i.o
+mwave-y := mwavedd.o smapi.o tp3780i.o 3780i.o
# To have the mwave driver disable other uarts if necessary
# EXTRA_CFLAGS += -DMWAVE_FUTZ_WITH_OTHER_DEVICES
# To compile in lots (~20 KiB) of run-time enablable printk()s for debugging:
-EXTRA_CFLAGS += -DMW_TRACE
+ccflags-y := -DMW_TRACE
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 463df27494bd..dd9d75351cd6 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -303,6 +303,7 @@ static void mxser_enable_must_enchance_mode(unsigned long baseio)
outb(oldlcr, baseio + UART_LCR);
}
+#ifdef CONFIG_PCI
static void mxser_disable_must_enchance_mode(unsigned long baseio)
{
u8 oldlcr;
@@ -317,6 +318,7 @@ static void mxser_disable_must_enchance_mode(unsigned long baseio)
outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
outb(oldlcr, baseio + UART_LCR);
}
+#endif
static void mxser_set_must_xon1_value(unsigned long baseio, u8 value)
{
@@ -388,6 +390,7 @@ static void mxser_set_must_enum_value(unsigned long baseio, u8 value)
outb(oldlcr, baseio + UART_LCR);
}
+#ifdef CONFIG_PCI
static void mxser_get_must_hardware_id(unsigned long baseio, u8 *pId)
{
u8 oldlcr;
@@ -404,6 +407,7 @@ static void mxser_get_must_hardware_id(unsigned long baseio, u8 *pId)
*pId = inb(baseio + MOXA_MUST_HWID_REGISTER);
outb(oldlcr, baseio + UART_LCR);
}
+#endif
static void SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(unsigned long baseio)
{
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index a98290d7a2c5..88dda0c45ee0 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -4,7 +4,6 @@
* Copyright by
* Philips Automation Projects
* Kassel (Germany)
- * http://www.pap-philips.de
* -----------------------------------------------------------
* This software may be used and distributed according to the terms of
* the GNU General Public License, incorporated herein by reference.
diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig
index ffa0efce0aed..6614416a8623 100644
--- a/drivers/char/pcmcia/Kconfig
+++ b/drivers/char/pcmcia/Kconfig
@@ -28,7 +28,7 @@ config CARDMAN_4000
This kernel driver requires additional userspace support, either
by the vendor-provided PC/SC ifd_handler (http://www.omnikey.com/),
- or via the cm4000 backend of OpenCT (http://www.opensc.com/).
+ or via the cm4000 backend of OpenCT (http://www.opensc-project.org/opensc).
config CARDMAN_4040
tristate "Omnikey CardMan 4040 support"
@@ -41,7 +41,7 @@ config CARDMAN_4040
in I/O space. To use the kernel driver, you will need either the
PC/SC ifdhandler provided from the Omnikey homepage
(http://www.omnikey.com/), or a current development version of OpenCT
- (http://www.opensc.org/).
+ (http://www.opensc-project.org/opensc).
config IPWIRELESS
tristate "IPWireless 3G UMTS PCMCIA card support"
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 6835c23e9a51..d962f25dcc2a 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -1666,7 +1666,7 @@ static int cmm_open(struct inode *inode, struct file *filp)
/* opening will always block since the
* monitor will be started by open, which
* means we have to wait for ATR becoming
- * vaild = block until valid (or card
+ * valid = block until valid (or card
* inserted)
*/
if (filp->f_flags & O_NONBLOCK) {
diff --git a/drivers/char/pcmcia/ipwireless/Makefile b/drivers/char/pcmcia/ipwireless/Makefile
index b71eb593643d..db80873d7f20 100644
--- a/drivers/char/pcmcia/ipwireless/Makefile
+++ b/drivers/char/pcmcia/ipwireless/Makefile
@@ -6,5 +6,5 @@
obj-$(CONFIG_IPWIRELESS) += ipwireless.o
-ipwireless-objs := hardware.o main.o network.o tty.o
+ipwireless-y := hardware.o main.o network.o tty.o
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 723152d978a9..f176dbaeb15a 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -613,6 +613,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case PPGETTIME:
to_jiffies = pp->pdev->timeout;
+ memset(&par_timeout, 0, sizeof(par_timeout));
par_timeout.tv_sec = to_jiffies / HZ;
par_timeout.tv_usec = (to_jiffies % (long)HZ) * (1000000/HZ);
if (copy_to_user (argp, &par_timeout, sizeof(struct timeval)))
diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c
index 74f00b5ffa36..73dcb0ee41fd 100644
--- a/drivers/char/ramoops.c
+++ b/drivers/char/ramoops.c
@@ -25,6 +25,8 @@
#include <linux/time.h>
#include <linux/io.h>
#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/ramoops.h>
#define RAMOOPS_KERNMSG_HDR "===="
#define RAMOOPS_HEADER_SIZE (5 + sizeof(struct timeval))
@@ -91,11 +93,17 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper,
cxt->count = (cxt->count + 1) % cxt->max_count;
}
-static int __init ramoops_init(void)
+static int __init ramoops_probe(struct platform_device *pdev)
{
+ struct ramoops_platform_data *pdata = pdev->dev.platform_data;
struct ramoops_context *cxt = &oops_cxt;
int err = -EINVAL;
+ if (pdata) {
+ mem_size = pdata->mem_size;
+ mem_address = pdata->mem_address;
+ }
+
if (!mem_size) {
printk(KERN_ERR "ramoops: invalid size specification");
goto fail3;
@@ -142,7 +150,7 @@ fail3:
return err;
}
-static void __exit ramoops_exit(void)
+static int __exit ramoops_remove(struct platform_device *pdev)
{
struct ramoops_context *cxt = &oops_cxt;
@@ -151,8 +159,26 @@ static void __exit ramoops_exit(void)
iounmap(cxt->virt_addr);
release_mem_region(cxt->phys_addr, cxt->size);
+ return 0;
}
+static struct platform_driver ramoops_driver = {
+ .remove = __exit_p(ramoops_remove),
+ .driver = {
+ .name = "ramoops",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ramoops_init(void)
+{
+ return platform_driver_probe(&ramoops_driver, ramoops_probe);
+}
+
+static void __exit ramoops_exit(void)
+{
+ platform_driver_unregister(&ramoops_driver);
+}
module_init(ramoops_init);
module_exit(ramoops_exit);
diff --git a/drivers/char/rio/Makefile b/drivers/char/rio/Makefile
index 2d1c5a7cba7d..1661875883fb 100644
--- a/drivers/char/rio/Makefile
+++ b/drivers/char/rio/Makefile
@@ -8,5 +8,5 @@
obj-$(CONFIG_RIO) += rio.o
-rio-objs := rio_linux.o rioinit.o rioboot.o riocmd.o rioctrl.o riointr.o \
+rio-y := rio_linux.o rioinit.o rioboot.o riocmd.o rioctrl.o riointr.o \
rioparam.o rioroute.o riotable.o riotty.o
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 7c79d243acc9..86308830ac42 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -2345,7 +2345,7 @@ static int __init rp_init(void)
ret = tty_register_driver(rocket_driver);
if (ret < 0) {
printk(KERN_ERR "Couldn't install tty RocketPort driver\n");
- goto err_tty;
+ goto err_controller;
}
#ifdef ROCKET_DEBUG_OPEN
@@ -2380,6 +2380,9 @@ static int __init rp_init(void)
return 0;
err_ttyu:
tty_unregister_driver(rocket_driver);
+err_controller:
+ if (controller)
+ release_region(controller, 4);
err_tty:
put_tty_driver(rocket_driver);
err:
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 8ef16490810c..4bef6ab83622 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -3181,7 +3181,7 @@ static void stl_cd1400flush(struct stlport *portp)
/*
* Return the current state of data flow on this port. This is only
- * really interresting when determining if data has fully completed
+ * really interesting when determining if data has fully completed
* transmission or not... This is easy for the cd1400, it accurately
* maintains the busy port flag.
*/
@@ -4131,7 +4131,7 @@ static void stl_sc26198flush(struct stlport *portp)
/*
* Return the current state of data flow on this port. This is only
- * really interresting when determining if data has fully completed
+ * really interesting when determining if data has fully completed
* transmission or not... The sc26198 interrupt scheme cannot
* determine when all data has actually drained, so we need to
* check the port statusy register to be sure.
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 1746d91205f7..d01fffeac951 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -301,6 +301,8 @@ struct slgt_info {
unsigned int rx_pio;
unsigned int if_mode;
unsigned int base_clock;
+ unsigned int xsync;
+ unsigned int xctrl;
/* device status */
@@ -405,6 +407,8 @@ static MGSL_PARAMS default_params = {
#define TDCSR 0x94 /* tx DMA control/status */
#define RDDAR 0x98 /* rx DMA descriptor address */
#define TDDAR 0x9c /* tx DMA descriptor address */
+#define XSR 0x40 /* extended sync pattern */
+#define XCR 0x44 /* extended control */
#define RXIDLE BIT14
#define RXBREAK BIT14
@@ -517,6 +521,10 @@ static int set_interface(struct slgt_info *info, int if_mode);
static int set_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
static int get_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
+static int get_xsync(struct slgt_info *info, int __user *if_mode);
+static int set_xsync(struct slgt_info *info, int if_mode);
+static int get_xctrl(struct slgt_info *info, int __user *if_mode);
+static int set_xctrl(struct slgt_info *info, int if_mode);
/*
* driver functions
@@ -1056,6 +1064,14 @@ static int ioctl(struct tty_struct *tty, struct file *file,
return get_gpio(info, argp);
case MGSL_IOCWAITGPIO:
return wait_gpio(info, argp);
+ case MGSL_IOCGXSYNC:
+ return get_xsync(info, argp);
+ case MGSL_IOCSXSYNC:
+ return set_xsync(info, (int)arg);
+ case MGSL_IOCGXCTRL:
+ return get_xctrl(info, argp);
+ case MGSL_IOCSXCTRL:
+ return set_xctrl(info, (int)arg);
}
mutex_lock(&info->port.mutex);
switch (cmd) {
@@ -1132,6 +1148,7 @@ static long get_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *us
struct MGSL_PARAMS32 tmp_params;
DBGINFO(("%s get_params32\n", info->device_name));
+ memset(&tmp_params, 0, sizeof(tmp_params));
tmp_params.mode = (compat_ulong_t)info->params.mode;
tmp_params.loopback = info->params.loopback;
tmp_params.flags = info->params.flags;
@@ -1212,12 +1229,16 @@ static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file,
case MGSL_IOCSGPIO:
case MGSL_IOCGGPIO:
case MGSL_IOCWAITGPIO:
+ case MGSL_IOCGXSYNC:
+ case MGSL_IOCGXCTRL:
case MGSL_IOCSTXIDLE:
case MGSL_IOCTXENABLE:
case MGSL_IOCRXENABLE:
case MGSL_IOCTXABORT:
case TIOCMIWAIT:
case MGSL_IOCSIF:
+ case MGSL_IOCSXSYNC:
+ case MGSL_IOCSXCTRL:
rc = ioctl(tty, file, cmd, arg);
break;
}
@@ -1617,6 +1638,8 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (cmd != SIOCWANDEV)
return hdlc_ioctl(dev, ifr, cmd);
+ memset(&new_line, 0, sizeof(new_line));
+
switch(ifr->ifr_settings.type) {
case IF_GET_IFACE: /* return current sync_serial_settings */
@@ -1958,6 +1981,7 @@ static void bh_handler(struct work_struct *work)
case MGSL_MODE_RAW:
case MGSL_MODE_MONOSYNC:
case MGSL_MODE_BISYNC:
+ case MGSL_MODE_XSYNC:
while(rx_get_buf(info));
break;
}
@@ -2357,26 +2381,27 @@ static irqreturn_t slgt_interrupt(int dummy, void *dev_id)
DBGISR(("slgt_interrupt irq=%d entry\n", info->irq_level));
- spin_lock(&info->lock);
-
while((gsr = rd_reg32(info, GSR) & 0xffffff00)) {
DBGISR(("%s gsr=%08x\n", info->device_name, gsr));
info->irq_occurred = true;
for(i=0; i < info->port_count ; i++) {
if (info->port_array[i] == NULL)
continue;
+ spin_lock(&info->port_array[i]->lock);
if (gsr & (BIT8 << i))
isr_serial(info->port_array[i]);
if (gsr & (BIT16 << (i*2)))
isr_rdma(info->port_array[i]);
if (gsr & (BIT17 << (i*2)))
isr_tdma(info->port_array[i]);
+ spin_unlock(&info->port_array[i]->lock);
}
}
if (info->gpio_present) {
unsigned int state;
unsigned int changed;
+ spin_lock(&info->lock);
while ((changed = rd_reg32(info, IOSR)) != 0) {
DBGISR(("%s iosr=%08x\n", info->device_name, changed));
/* read latched state of GPIO signals */
@@ -2388,22 +2413,24 @@ static irqreturn_t slgt_interrupt(int dummy, void *dev_id)
isr_gpio(info->port_array[i], changed, state);
}
}
+ spin_unlock(&info->lock);
}
for(i=0; i < info->port_count ; i++) {
struct slgt_info *port = info->port_array[i];
-
- if (port && (port->port.count || port->netcount) &&
+ if (port == NULL)
+ continue;
+ spin_lock(&port->lock);
+ if ((port->port.count || port->netcount) &&
port->pending_bh && !port->bh_running &&
!port->bh_requested) {
DBGISR(("%s bh queued\n", port->device_name));
schedule_work(&port->task);
port->bh_requested = true;
}
+ spin_unlock(&port->lock);
}
- spin_unlock(&info->lock);
-
DBGISR(("slgt_interrupt irq=%d exit\n", info->irq_level));
return IRQ_HANDLED;
}
@@ -2883,6 +2910,69 @@ static int set_interface(struct slgt_info *info, int if_mode)
return 0;
}
+static int get_xsync(struct slgt_info *info, int __user *xsync)
+{
+ DBGINFO(("%s get_xsync=%x\n", info->device_name, info->xsync));
+ if (put_user(info->xsync, xsync))
+ return -EFAULT;
+ return 0;
+}
+
+/*
+ * set extended sync pattern (1 to 4 bytes) for extended sync mode
+ *
+ * sync pattern is contained in least significant bytes of value
+ * most significant byte of sync pattern is oldest (1st sent/detected)
+ */
+static int set_xsync(struct slgt_info *info, int xsync)
+{
+ unsigned long flags;
+
+ DBGINFO(("%s set_xsync=%x)\n", info->device_name, xsync));
+ spin_lock_irqsave(&info->lock, flags);
+ info->xsync = xsync;
+ wr_reg32(info, XSR, xsync);
+ spin_unlock_irqrestore(&info->lock, flags);
+ return 0;
+}
+
+static int get_xctrl(struct slgt_info *info, int __user *xctrl)
+{
+ DBGINFO(("%s get_xctrl=%x\n", info->device_name, info->xctrl));
+ if (put_user(info->xctrl, xctrl))
+ return -EFAULT;
+ return 0;
+}
+
+/*
+ * set extended control options
+ *
+ * xctrl[31:19] reserved, must be zero
+ * xctrl[18:17] extended sync pattern length in bytes
+ * 00 = 1 byte in xsr[7:0]
+ * 01 = 2 bytes in xsr[15:0]
+ * 10 = 3 bytes in xsr[23:0]
+ * 11 = 4 bytes in xsr[31:0]
+ * xctrl[16] 1 = enable terminal count, 0=disabled
+ * xctrl[15:0] receive terminal count for fixed length packets
+ * value is count minus one (0 = 1 byte packet)
+ * when terminal count is reached, receiver
+ * automatically returns to hunt mode and receive
+ * FIFO contents are flushed to DMA buffers with
+ * end of frame (EOF) status
+ */
+static int set_xctrl(struct slgt_info *info, int xctrl)
+{
+ unsigned long flags;
+
+ DBGINFO(("%s set_xctrl=%x)\n", info->device_name, xctrl));
+ spin_lock_irqsave(&info->lock, flags);
+ info->xctrl = xctrl;
+ wr_reg32(info, XCR, xctrl);
+ spin_unlock_irqrestore(&info->lock, flags);
+ return 0;
+}
+
/*
* set general purpose IO pin state and direction
*
@@ -2906,7 +2996,7 @@ static int set_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
info->device_name, gpio.state, gpio.smask,
gpio.dir, gpio.dmask));
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->port_array[0]->lock, flags);
if (gpio.dmask) {
data = rd_reg32(info, IODR);
data |= gpio.dmask & gpio.dir;
@@ -2919,7 +3009,7 @@ static int set_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
data &= ~(gpio.smask & ~gpio.state);
wr_reg32(info, IOVR, data);
}
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->port_array[0]->lock, flags);
return 0;
}
@@ -3020,7 +3110,7 @@ static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
return -EINVAL;
init_cond_wait(&wait, gpio.smask);
- spin_lock_irqsave(&info->lock, flags);
+ spin_lock_irqsave(&info->port_array[0]->lock, flags);
/* enable interrupts for watched pins */
wr_reg32(info, IOER, rd_reg32(info, IOER) | gpio.smask);
/* get current pin states */
@@ -3032,20 +3122,20 @@ static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
} else {
/* wait for target state */
add_cond_wait(&info->gpio_wait_q, &wait);
- spin_unlock_irqrestore(&info->lock, flags);
+ spin_unlock_irqrestore(&info->port_array[0]->lock, flags);
schedule();
if (signal_pending(current))
rc = -ERESTARTSYS;
else
gpio.state = wait.data;
- spin_lock_irqsave(&info->lock, flags);
+ spin_lock_irqsave(&info->port_array[0]->lock, flags);
remove_cond_wait(&info->gpio_wait_q, &wait);
}
/* disable all GPIO interrupts if no waiting processes */
if (info->gpio_wait_q == NULL)
wr_reg32(info, IOER, 0);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->port_array[0]->lock, flags);
if ((rc == 0) && copy_to_user(user_gpio, &gpio, sizeof(gpio)))
rc = -EFAULT;
@@ -3578,7 +3668,6 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
/* copy resource information from first port to others */
for (i = 1; i < port_count; ++i) {
- port_array[i]->lock = port_array[0]->lock;
port_array[i]->irq_level = port_array[0]->irq_level;
port_array[i]->reg_addr = port_array[0]->reg_addr;
alloc_dma_bufs(port_array[i]);
@@ -3763,7 +3852,9 @@ module_exit(slgt_exit);
#define CALC_REGADDR() \
unsigned long reg_addr = ((unsigned long)info->reg_addr) + addr; \
if (addr >= 0x80) \
- reg_addr += (info->port_num) * 32;
+ reg_addr += (info->port_num) * 32; \
+ else if (addr >= 0x40) \
+ reg_addr += (info->port_num) * 16;
static __u8 rd_reg8(struct slgt_info *info, unsigned int addr)
{
@@ -4182,7 +4273,13 @@ static void sync_mode(struct slgt_info *info)
/* TCR (tx control)
*
- * 15..13 mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync
+ * 15..13 mode
+ * 000=HDLC/SDLC
+ * 001=raw bit synchronous
+ * 010=asynchronous/isochronous
+ * 011=monosync byte synchronous
+ * 100=bisync byte synchronous
+ * 101=xsync byte synchronous
* 12..10 encoding
* 09 CRC enable
* 08 CRC32
@@ -4197,6 +4294,9 @@ static void sync_mode(struct slgt_info *info)
val = BIT2;
switch(info->params.mode) {
+ case MGSL_MODE_XSYNC:
+ val |= BIT15 + BIT13;
+ break;
case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break;
case MGSL_MODE_BISYNC: val |= BIT15; break;
case MGSL_MODE_RAW: val |= BIT13; break;
@@ -4251,7 +4351,13 @@ static void sync_mode(struct slgt_info *info)
/* RCR (rx control)
*
- * 15..13 mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync
+ * 15..13 mode
+ * 000=HDLC/SDLC
+ * 001=raw bit synchronous
+ * 010=asynchronous/isochronous
+ * 011=monosync byte synchronous
+ * 100=bisync byte synchronous
+ * 101=xsync byte synchronous
* 12..10 encoding
* 09 CRC enable
* 08 CRC32
@@ -4263,6 +4369,9 @@ static void sync_mode(struct slgt_info *info)
val = 0;
switch(info->params.mode) {
+ case MGSL_MODE_XSYNC:
+ val |= BIT15 + BIT13;
+ break;
case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break;
case MGSL_MODE_BISYNC: val |= BIT15; break;
case MGSL_MODE_RAW: val |= BIT13; break;
@@ -4679,6 +4788,7 @@ static bool rx_get_buf(struct slgt_info *info)
switch(info->params.mode) {
case MGSL_MODE_MONOSYNC:
case MGSL_MODE_BISYNC:
+ case MGSL_MODE_XSYNC:
/* ignore residue in byte synchronous modes */
if (desc_residue(info->rbufs[i]))
count--;
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index f3019f53e875..eaa5d3efa79d 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -566,10 +566,16 @@ static const unsigned char sysrq_xlate[KEY_MAX + 1] =
static bool sysrq_down;
static int sysrq_alt_use;
static int sysrq_alt;
+static DEFINE_SPINLOCK(sysrq_event_lock);
static bool sysrq_filter(struct input_handle *handle, unsigned int type,
unsigned int code, int value)
{
+ bool suppress;
+
+ /* We are called with interrupts disabled, just take the lock */
+ spin_lock(&sysrq_event_lock);
+
if (type != EV_KEY)
goto out;
@@ -601,7 +607,10 @@ static bool sysrq_filter(struct input_handle *handle, unsigned int type,
}
out:
- return sysrq_down;
+ suppress = sysrq_down;
+ spin_unlock(&sysrq_event_lock);
+
+ return suppress;
}
static int sysrq_connect(struct input_handler *handler,
@@ -652,8 +661,8 @@ static void sysrq_disconnect(struct input_handle *handle)
}
/*
- * We are matching on KEY_LEFTALT insteard of KEY_SYSRQ because not all
- * keyboards have SysRq ikey predefined and so user may add it to keymap
+ * We are matching on KEY_LEFTALT instead of KEY_SYSRQ because not all
+ * keyboards have SysRq key predefined and so user may add it to keymap
* later, but we expect all such keyboards to have left alt.
*/
static const struct input_device_id sysrq_ids[] = {
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index 4dc338f3d1aa..f6595aba4f0f 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -58,6 +58,6 @@ config TCG_INFINEON
To compile this driver as a module, choose M here; the module
will be called tpm_infineon.
Further information on this driver and the supported hardware
- can be found at http://www.prosec.rub.de/tpm
+ can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/
endif # TCG_TPM
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index f58440791e65..76da32e11f18 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -7,7 +7,7 @@
* Copyright (C) 2005, Marcel Selhorst <m.selhorst@sirrix.com>
* Sirrix AG - security technologies, http://www.sirrix.com and
* Applied Data Security Group, Ruhr-University Bochum, Germany
- * Project-Homepage: http://www.prosec.rub.de/tpm
+ * Project-Homepage: http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index 38df8c19e74c..6b68a0fb4611 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -503,6 +503,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
struct kbd_struct * kbd;
unsigned int console;
unsigned char ucval;
+ unsigned int uival;
void __user *up = (void __user *)arg;
int i, perm;
int ret = 0;
@@ -657,7 +658,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
break;
case KDGETMODE:
- ucval = vc->vc_mode;
+ uival = vc->vc_mode;
goto setint;
case KDMAPDISP:
@@ -695,7 +696,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
break;
case KDGKBMODE:
- ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW :
+ uival = ((kbd->kbdmode == VC_RAW) ? K_RAW :
(kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
(kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
K_XLATE);
@@ -717,9 +718,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
break;
case KDGKBMETA:
- ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
+ uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
setint:
- ret = put_user(ucval, (int __user *)arg);
+ ret = put_user(uival, (int __user *)arg);
break;
case KDGETKEYCODE:
@@ -949,7 +950,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
for (i = 0; i < MAX_NR_CONSOLES; ++i)
if (! VT_IS_IN_USE(i))
break;
- ucval = i < MAX_NR_CONSOLES ? (i+1) : -1;
+ uival = i < MAX_NR_CONSOLES ? (i+1) : -1;
goto setint;
/*
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index 717305d30444..a44611652282 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -308,7 +308,7 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id)
* isr before we end up here.
*/
if (p->flags & FLAG_CLOCKSOURCE)
- p->total_cycles += p->match_value;
+ p->total_cycles += p->match_value + 1;
if (!(p->flags & FLAG_REPROGRAM))
p->next_match_value = p->max_match_value;
@@ -403,7 +403,7 @@ static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
raw = sh_cmt_get_counter(p, &has_wrapped);
if (unlikely(has_wrapped))
- raw += p->match_value;
+ raw += p->match_value + 1;
spin_unlock_irqrestore(&p->lock, flags);
return value + raw;
@@ -445,7 +445,7 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
/* clk_get_rate() needs an enabled clock */
clk_enable(p->clk);
- p->rate = clk_get_rate(p->clk) / (p->width == 16) ? 512 : 8;
+ p->rate = clk_get_rate(p->clk) / ((p->width == 16) ? 512 : 8);
clk_disable(p->clk);
/* TODO: calculate good shift from rate and counter bit width */
@@ -478,7 +478,7 @@ static void sh_cmt_clock_event_start(struct sh_cmt_priv *p, int periodic)
ced->min_delta_ns = clockevent_delta2ns(0x1f, ced);
if (periodic)
- sh_cmt_set_next(p, (p->rate + HZ/2) / HZ);
+ sh_cmt_set_next(p, ((p->rate + HZ/2) / HZ) - 1);
else
sh_cmt_set_next(p, p->max_match_value);
}
@@ -523,9 +523,9 @@ static int sh_cmt_clock_event_next(unsigned long delta,
BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT);
if (likely(p->flags & FLAG_IRQCONTEXT))
- p->next_match_value = delta;
+ p->next_match_value = delta - 1;
else
- sh_cmt_set_next(p, delta);
+ sh_cmt_set_next(p, delta - 1);
return 0;
}
diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c
index 210338ea222f..81270d221e5a 100644
--- a/drivers/connector/cn_queue.c
+++ b/drivers/connector/cn_queue.c
@@ -31,48 +31,6 @@
#include <linux/connector.h>
#include <linux/delay.h>
-
-/*
- * This job is sent to the kevent workqueue.
- * While no event is once sent to any callback, the connector workqueue
- * is not created to avoid a useless waiting kernel task.
- * Once the first event is received, we create this dedicated workqueue which
- * is necessary because the flow of data can be high and we don't want
- * to encumber keventd with that.
- */
-static void cn_queue_create(struct work_struct *work)
-{
- struct cn_queue_dev *dev;
-
- dev = container_of(work, struct cn_queue_dev, wq_creation);
-
- dev->cn_queue = create_singlethread_workqueue(dev->name);
- /* If we fail, we will use keventd for all following connector jobs */
- WARN_ON(!dev->cn_queue);
-}
-
-/*
- * Queue a data sent to a callback.
- * If the connector workqueue is already created, we queue the job on it.
- * Otherwise, we queue the job to kevent and queue the connector workqueue
- * creation too.
- */
-int queue_cn_work(struct cn_callback_entry *cbq, struct work_struct *work)
-{
- struct cn_queue_dev *pdev = cbq->pdev;
-
- if (likely(pdev->cn_queue))
- return queue_work(pdev->cn_queue, work);
-
- /* Don't create the connector workqueue twice */
- if (atomic_inc_return(&pdev->wq_requested) == 1)
- schedule_work(&pdev->wq_creation);
- else
- atomic_dec(&pdev->wq_requested);
-
- return schedule_work(work);
-}
-
void cn_queue_wrapper(struct work_struct *work)
{
struct cn_callback_entry *cbq =
@@ -111,11 +69,7 @@ cn_queue_alloc_callback_entry(char *name, struct cb_id *id,
static void cn_queue_free_callback(struct cn_callback_entry *cbq)
{
- /* The first jobs have been sent to kevent, flush them too */
- flush_scheduled_work();
- if (cbq->pdev->cn_queue)
- flush_workqueue(cbq->pdev->cn_queue);
-
+ flush_workqueue(cbq->pdev->cn_queue);
kfree(cbq);
}
@@ -193,11 +147,14 @@ struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *nls)
atomic_set(&dev->refcnt, 0);
INIT_LIST_HEAD(&dev->queue_list);
spin_lock_init(&dev->queue_lock);
- init_waitqueue_head(&dev->wq_created);
dev->nls = nls;
- INIT_WORK(&dev->wq_creation, cn_queue_create);
+ dev->cn_queue = alloc_ordered_workqueue(dev->name, 0);
+ if (!dev->cn_queue) {
+ kfree(dev);
+ return NULL;
+ }
return dev;
}
@@ -205,25 +162,9 @@ struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *nls)
void cn_queue_free_dev(struct cn_queue_dev *dev)
{
struct cn_callback_entry *cbq, *n;
- long timeout;
- DEFINE_WAIT(wait);
-
- /* Flush the first pending jobs queued on kevent */
- flush_scheduled_work();
-
- /* If the connector workqueue creation is still pending, wait for it */
- prepare_to_wait(&dev->wq_created, &wait, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&dev->wq_requested) && !dev->cn_queue) {
- timeout = schedule_timeout(HZ * 2);
- if (!timeout && !dev->cn_queue)
- WARN_ON(1);
- }
- finish_wait(&dev->wq_created, &wait);
- if (dev->cn_queue) {
- flush_workqueue(dev->cn_queue);
- destroy_workqueue(dev->cn_queue);
- }
+ flush_workqueue(dev->cn_queue);
+ destroy_workqueue(dev->cn_queue);
spin_lock_bh(&dev->queue_lock);
list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry)
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index 1d48f40342cb..e16c3fa8d2e3 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -133,7 +133,8 @@ static int cn_call_callback(struct sk_buff *skb)
__cbq->data.skb == NULL)) {
__cbq->data.skb = skb;
- if (queue_cn_work(__cbq, &__cbq->work))
+ if (queue_work(dev->cbdev->cn_queue,
+ &__cbq->work))
err = 0;
else
err = -EINVAL;
@@ -148,13 +149,11 @@ static int cn_call_callback(struct sk_buff *skb)
d->callback = __cbq->data.callback;
d->free = __new_cbq;
- __new_cbq->pdev = __cbq->pdev;
-
INIT_WORK(&__new_cbq->work,
&cn_queue_wrapper);
- if (queue_cn_work(__new_cbq,
- &__new_cbq->work))
+ if (queue_work(dev->cbdev->cn_queue,
+ &__new_cbq->work))
err = 0;
else {
kfree(__new_cbq);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 199dcb9f0b83..c63a43823744 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -918,8 +918,8 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
spin_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu(j, policy->cpus) {
- if (!cpu_online(j))
- continue;
+ if (!cpu_online(j))
+ continue;
per_cpu(cpufreq_cpu_data, j) = policy;
per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
}
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 7b5093664e49..c631f27a3dcc 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -30,6 +30,8 @@
#define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10)
#define DEF_FREQUENCY_UP_THRESHOLD (80)
+#define DEF_SAMPLING_DOWN_FACTOR (1)
+#define MAX_SAMPLING_DOWN_FACTOR (100000)
#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (3)
#define MICRO_FREQUENCY_UP_THRESHOLD (95)
#define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000)
@@ -82,6 +84,7 @@ struct cpu_dbs_info_s {
unsigned int freq_lo;
unsigned int freq_lo_jiffies;
unsigned int freq_hi_jiffies;
+ unsigned int rate_mult;
int cpu;
unsigned int sample_type:1;
/*
@@ -108,10 +111,12 @@ static struct dbs_tuners {
unsigned int up_threshold;
unsigned int down_differential;
unsigned int ignore_nice;
+ unsigned int sampling_down_factor;
unsigned int powersave_bias;
unsigned int io_is_busy;
} dbs_tuners_ins = {
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
+ .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
.down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL,
.ignore_nice = 0,
.powersave_bias = 0,
@@ -259,6 +264,7 @@ static ssize_t show_##file_name \
show_one(sampling_rate, sampling_rate);
show_one(io_is_busy, io_is_busy);
show_one(up_threshold, up_threshold);
+show_one(sampling_down_factor, sampling_down_factor);
show_one(ignore_nice_load, ignore_nice);
show_one(powersave_bias, powersave_bias);
@@ -340,6 +346,29 @@ static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
return count;
}
+static ssize_t store_sampling_down_factor(struct kobject *a,
+ struct attribute *b, const char *buf, size_t count)
+{
+ unsigned int input, j;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+
+ if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
+ return -EINVAL;
+ mutex_lock(&dbs_mutex);
+ dbs_tuners_ins.sampling_down_factor = input;
+
+ /* Reset down sampling multiplier in case it was active */
+ for_each_online_cpu(j) {
+ struct cpu_dbs_info_s *dbs_info;
+ dbs_info = &per_cpu(od_cpu_dbs_info, j);
+ dbs_info->rate_mult = 1;
+ }
+ mutex_unlock(&dbs_mutex);
+
+ return count;
+}
+
static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
const char *buf, size_t count)
{
@@ -401,6 +430,7 @@ static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b,
define_one_global_rw(sampling_rate);
define_one_global_rw(io_is_busy);
define_one_global_rw(up_threshold);
+define_one_global_rw(sampling_down_factor);
define_one_global_rw(ignore_nice_load);
define_one_global_rw(powersave_bias);
@@ -409,6 +439,7 @@ static struct attribute *dbs_attributes[] = {
&sampling_rate_min.attr,
&sampling_rate.attr,
&up_threshold.attr,
+ &sampling_down_factor.attr,
&ignore_nice_load.attr,
&powersave_bias.attr,
&io_is_busy.attr,
@@ -562,6 +593,10 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
/* Check for frequency increase */
if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) {
+ /* If switching to max speed, apply sampling_down_factor */
+ if (policy->cur < policy->max)
+ this_dbs_info->rate_mult =
+ dbs_tuners_ins.sampling_down_factor;
dbs_freq_increase(policy, policy->max);
return;
}
@@ -584,6 +619,9 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
(dbs_tuners_ins.up_threshold -
dbs_tuners_ins.down_differential);
+ /* No longer fully busy, reset rate_mult */
+ this_dbs_info->rate_mult = 1;
+
if (freq_next < policy->min)
freq_next = policy->min;
@@ -607,7 +645,8 @@ static void do_dbs_timer(struct work_struct *work)
int sample_type = dbs_info->sample_type;
/* We want all CPUs to do sampling nearly on same jiffy */
- int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate
+ * dbs_info->rate_mult);
if (num_online_cpus() > 1)
delay -= jiffies % delay;
@@ -711,6 +750,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
}
}
this_dbs_info->cpu = cpu;
+ this_dbs_info->rate_mult = 1;
ondemand_powersave_bias_init_cpu(cpu);
/*
* Start the timerschedule work, when this governor
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index ea0b3863ad0f..eab2cf7a0269 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -172,6 +172,7 @@ config CRYPTO_DEV_MV_CESA
config CRYPTO_DEV_NIAGARA2
tristate "Niagara2 Stream Processing Unit driver"
+ select CRYPTO_DES
select CRYPTO_ALGAPI
depends on SPARC64
help
@@ -243,4 +244,12 @@ config CRYPTO_DEV_OMAP_SHAM
OMAP processors have SHA1/MD5 hw accelerator. Select this if you
want to use the OMAP module for SHA1/MD5 algorithms.
+config CRYPTO_DEV_OMAP_AES
+ tristate "Support for OMAP AES hw engine"
+ depends on ARCH_OMAP2 || ARCH_OMAP3
+ select CRYPTO_AES
+ help
+ OMAP processors have AES module accelerator. Select this if you
+ want to use the OMAP module for AES algorithms.
+
endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 6dbbe00c4524..256697330a41 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -2,11 +2,12 @@ obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
obj-$(CONFIG_CRYPTO_DEV_NIAGARA2) += n2_crypto.o
-n2_crypto-objs := n2_core.o n2_asm.o
+n2_crypto-y := n2_core.o n2_asm.o
obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o
obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o
obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
+obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
diff --git a/drivers/crypto/amcc/Makefile b/drivers/crypto/amcc/Makefile
index aa376e8d5ed5..5c0c62b65d69 100644
--- a/drivers/crypto/amcc/Makefile
+++ b/drivers/crypto/amcc/Makefile
@@ -1,2 +1,2 @@
obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += crypto4xx.o
-crypto4xx-objs := crypto4xx_core.o crypto4xx_alg.o crypto4xx_sa.o
+crypto4xx-y := crypto4xx_core.o crypto4xx_alg.o crypto4xx_sa.o
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
index e449ac5627a5..a84250a5dd51 100644
--- a/drivers/crypto/hifn_795x.c
+++ b/drivers/crypto/hifn_795x.c
@@ -1467,7 +1467,7 @@ static int ablkcipher_add(unsigned int *drestp, struct scatterlist *dst,
return -EINVAL;
while (size) {
- copy = min(drest, min(size, dst->length));
+ copy = min3(drest, size, dst->length);
size -= copy;
drest -= copy;
@@ -1729,7 +1729,7 @@ static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset
return -EINVAL;
while (size) {
- copy = min(srest, min(dst->length, size));
+ copy = min3(srest, dst->length, size);
daddr = kmap_atomic(sg_page(dst), KM_IRQ0);
memcpy(daddr + dst->offset + offset, saddr, copy);
@@ -2700,8 +2700,7 @@ static void __devexit hifn_remove(struct pci_dev *pdev)
dev = pci_get_drvdata(pdev);
if (dev) {
- cancel_delayed_work(&dev->work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&dev->work);
hifn_unregister_rng(dev);
hifn_unregister_alg(dev);
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
new file mode 100644
index 000000000000..799ca517c121
--- /dev/null
+++ b/drivers/crypto/omap-aes.c
@@ -0,0 +1,948 @@
+/*
+ * Cryptographic API.
+ *
+ * Support for OMAP AES HW acceleration.
+ *
+ * Copyright (c) 2010 Nokia Corporation
+ * Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/crypto.h>
+#include <linux/interrupt.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/aes.h>
+
+#include <plat/cpu.h>
+#include <plat/dma.h>
+
+/* OMAP TRM gives bitfields as start:end, where start is the higher bit
+ number. For example 7:0 */
+#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
+#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
+
+#define AES_REG_KEY(x) (0x1C - ((x ^ 0x01) * 0x04))
+#define AES_REG_IV(x) (0x20 + ((x) * 0x04))
+
+#define AES_REG_CTRL 0x30
+#define AES_REG_CTRL_CTR_WIDTH (1 << 7)
+#define AES_REG_CTRL_CTR (1 << 6)
+#define AES_REG_CTRL_CBC (1 << 5)
+#define AES_REG_CTRL_KEY_SIZE (3 << 3)
+#define AES_REG_CTRL_DIRECTION (1 << 2)
+#define AES_REG_CTRL_INPUT_READY (1 << 1)
+#define AES_REG_CTRL_OUTPUT_READY (1 << 0)
+
+#define AES_REG_DATA 0x34
+#define AES_REG_DATA_N(x) (0x34 + ((x) * 0x04))
+
+#define AES_REG_REV 0x44
+#define AES_REG_REV_MAJOR 0xF0
+#define AES_REG_REV_MINOR 0x0F
+
+#define AES_REG_MASK 0x48
+#define AES_REG_MASK_SIDLE (1 << 6)
+#define AES_REG_MASK_START (1 << 5)
+#define AES_REG_MASK_DMA_OUT_EN (1 << 3)
+#define AES_REG_MASK_DMA_IN_EN (1 << 2)
+#define AES_REG_MASK_SOFTRESET (1 << 1)
+#define AES_REG_AUTOIDLE (1 << 0)
+
+#define AES_REG_SYSSTATUS 0x4C
+#define AES_REG_SYSSTATUS_RESETDONE (1 << 0)
+
+#define DEFAULT_TIMEOUT (5*HZ)
+
+#define FLAGS_MODE_MASK 0x000f
+#define FLAGS_ENCRYPT BIT(0)
+#define FLAGS_CBC BIT(1)
+#define FLAGS_GIV BIT(2)
+
+#define FLAGS_NEW_KEY BIT(4)
+#define FLAGS_NEW_IV BIT(5)
+#define FLAGS_INIT BIT(6)
+#define FLAGS_FAST BIT(7)
+#define FLAGS_BUSY 8
+
+struct omap_aes_ctx {
+ struct omap_aes_dev *dd;
+
+ int keylen;
+ u32 key[AES_KEYSIZE_256 / sizeof(u32)];
+ unsigned long flags;
+};
+
+struct omap_aes_reqctx {
+ unsigned long mode;
+};
+
+#define OMAP_AES_QUEUE_LENGTH 1
+#define OMAP_AES_CACHE_SIZE 0
+
+struct omap_aes_dev {
+ struct list_head list;
+ unsigned long phys_base;
+ void __iomem *io_base;
+ struct clk *iclk;
+ struct omap_aes_ctx *ctx;
+ struct device *dev;
+ unsigned long flags;
+
+ u32 *iv;
+ u32 ctrl;
+
+ spinlock_t lock;
+ struct crypto_queue queue;
+
+ struct tasklet_struct task;
+
+ struct ablkcipher_request *req;
+ size_t total;
+ struct scatterlist *in_sg;
+ size_t in_offset;
+ struct scatterlist *out_sg;
+ size_t out_offset;
+
+ size_t buflen;
+ void *buf_in;
+ size_t dma_size;
+ int dma_in;
+ int dma_lch_in;
+ dma_addr_t dma_addr_in;
+ void *buf_out;
+ int dma_out;
+ int dma_lch_out;
+ dma_addr_t dma_addr_out;
+};
+
+/* keep registered devices data here */
+static LIST_HEAD(dev_list);
+static DEFINE_SPINLOCK(list_lock);
+
+static inline u32 omap_aes_read(struct omap_aes_dev *dd, u32 offset)
+{
+ return __raw_readl(dd->io_base + offset);
+}
+
+static inline void omap_aes_write(struct omap_aes_dev *dd, u32 offset,
+ u32 value)
+{
+ __raw_writel(value, dd->io_base + offset);
+}
+
+static inline void omap_aes_write_mask(struct omap_aes_dev *dd, u32 offset,
+ u32 value, u32 mask)
+{
+ u32 val;
+
+ val = omap_aes_read(dd, offset);
+ val &= ~mask;
+ val |= value;
+ omap_aes_write(dd, offset, val);
+}
+
+static void omap_aes_write_n(struct omap_aes_dev *dd, u32 offset,
+ u32 *value, int count)
+{
+ for (; count--; value++, offset += 4)
+ omap_aes_write(dd, offset, *value);
+}
+
+static int omap_aes_wait(struct omap_aes_dev *dd, u32 offset, u32 bit)
+{
+ unsigned long timeout = jiffies + DEFAULT_TIMEOUT;
+
+ while (!(omap_aes_read(dd, offset) & bit)) {
+ if (time_is_before_jiffies(timeout)) {
+ dev_err(dd->dev, "omap-aes timeout\n");
+ return -ETIMEDOUT;
+ }
+ }
+ return 0;
+}
+
+static int omap_aes_hw_init(struct omap_aes_dev *dd)
+{
+ int err = 0;
+
+ clk_enable(dd->iclk);
+ if (!(dd->flags & FLAGS_INIT)) {
+ /* is it necessary to reset before every operation? */
+ omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_SOFTRESET,
+ AES_REG_MASK_SOFTRESET);
+ /*
+ * prevent OCP bus error (SRESP) in case an access to the module
+ * is performed while the module is coming out of soft reset
+ */
+ __asm__ __volatile__("nop");
+ __asm__ __volatile__("nop");
+
+ err = omap_aes_wait(dd, AES_REG_SYSSTATUS,
+ AES_REG_SYSSTATUS_RESETDONE);
+ if (!err)
+ dd->flags |= FLAGS_INIT;
+ }
+
+ return err;
+}
+
+static void omap_aes_hw_cleanup(struct omap_aes_dev *dd)
+{
+ clk_disable(dd->iclk);
+}
+
+static void omap_aes_write_ctrl(struct omap_aes_dev *dd)
+{
+ unsigned int key32;
+ int i;
+ u32 val, mask;
+
+ val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3);
+ if (dd->flags & FLAGS_CBC)
+ val |= AES_REG_CTRL_CBC;
+ if (dd->flags & FLAGS_ENCRYPT)
+ val |= AES_REG_CTRL_DIRECTION;
+
+ if (dd->ctrl == val && !(dd->flags & FLAGS_NEW_IV) &&
+ !(dd->ctx->flags & FLAGS_NEW_KEY))
+ goto out;
+
+ /* only need to write control registers for new settings */
+
+ dd->ctrl = val;
+
+ val = 0;
+ if (dd->dma_lch_out >= 0)
+ val |= AES_REG_MASK_DMA_OUT_EN;
+ if (dd->dma_lch_in >= 0)
+ val |= AES_REG_MASK_DMA_IN_EN;
+
+ mask = AES_REG_MASK_DMA_IN_EN | AES_REG_MASK_DMA_OUT_EN;
+
+ omap_aes_write_mask(dd, AES_REG_MASK, val, mask);
+
+ pr_debug("Set key\n");
+ key32 = dd->ctx->keylen / sizeof(u32);
+ /* set a key */
+ for (i = 0; i < key32; i++) {
+ omap_aes_write(dd, AES_REG_KEY(i),
+ __le32_to_cpu(dd->ctx->key[i]));
+ }
+ dd->ctx->flags &= ~FLAGS_NEW_KEY;
+
+ if (dd->flags & FLAGS_NEW_IV) {
+ pr_debug("Set IV\n");
+ omap_aes_write_n(dd, AES_REG_IV(0), dd->iv, 4);
+ dd->flags &= ~FLAGS_NEW_IV;
+ }
+
+ mask = AES_REG_CTRL_CBC | AES_REG_CTRL_DIRECTION |
+ AES_REG_CTRL_KEY_SIZE;
+
+ omap_aes_write_mask(dd, AES_REG_CTRL, dd->ctrl, mask);
+
+out:
+ /* start DMA or disable idle mode */
+ omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_START,
+ AES_REG_MASK_START);
+}
+
+static struct omap_aes_dev *omap_aes_find_dev(struct omap_aes_ctx *ctx)
+{
+ struct omap_aes_dev *dd = NULL, *tmp;
+
+ spin_lock_bh(&list_lock);
+ if (!ctx->dd) {
+ list_for_each_entry(tmp, &dev_list, list) {
+ /* FIXME: take fist available aes core */
+ dd = tmp;
+ break;
+ }
+ ctx->dd = dd;
+ } else {
+ /* already found before */
+ dd = ctx->dd;
+ }
+ spin_unlock_bh(&list_lock);
+
+ return dd;
+}
+
+static void omap_aes_dma_callback(int lch, u16 ch_status, void *data)
+{
+ struct omap_aes_dev *dd = data;
+
+ if (lch == dd->dma_lch_out)
+ tasklet_schedule(&dd->task);
+}
+
+static int omap_aes_dma_init(struct omap_aes_dev *dd)
+{
+ int err = -ENOMEM;
+
+ dd->dma_lch_out = -1;
+ dd->dma_lch_in = -1;
+
+ dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, OMAP_AES_CACHE_SIZE);
+ dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, OMAP_AES_CACHE_SIZE);
+ dd->buflen = PAGE_SIZE << OMAP_AES_CACHE_SIZE;
+ dd->buflen &= ~(AES_BLOCK_SIZE - 1);
+
+ if (!dd->buf_in || !dd->buf_out) {
+ dev_err(dd->dev, "unable to alloc pages.\n");
+ goto err_alloc;
+ }
+
+ /* MAP here */
+ dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in, dd->buflen,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dd->dev, dd->dma_addr_in)) {
+ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
+ err = -EINVAL;
+ goto err_map_in;
+ }
+
+ dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out, dd->buflen,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(dd->dev, dd->dma_addr_out)) {
+ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
+ err = -EINVAL;
+ goto err_map_out;
+ }
+
+ err = omap_request_dma(dd->dma_in, "omap-aes-rx",
+ omap_aes_dma_callback, dd, &dd->dma_lch_in);
+ if (err) {
+ dev_err(dd->dev, "Unable to request DMA channel\n");
+ goto err_dma_in;
+ }
+ err = omap_request_dma(dd->dma_out, "omap-aes-tx",
+ omap_aes_dma_callback, dd, &dd->dma_lch_out);
+ if (err) {
+ dev_err(dd->dev, "Unable to request DMA channel\n");
+ goto err_dma_out;
+ }
+
+ omap_set_dma_dest_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_CONSTANT,
+ dd->phys_base + AES_REG_DATA, 0, 4);
+
+ omap_set_dma_dest_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4);
+ omap_set_dma_src_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4);
+
+ omap_set_dma_src_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_CONSTANT,
+ dd->phys_base + AES_REG_DATA, 0, 4);
+
+ omap_set_dma_src_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4);
+ omap_set_dma_dest_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4);
+
+ return 0;
+
+err_dma_out:
+ omap_free_dma(dd->dma_lch_in);
+err_dma_in:
+ dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
+ DMA_FROM_DEVICE);
+err_map_out:
+ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, DMA_TO_DEVICE);
+err_map_in:
+ free_pages((unsigned long)dd->buf_out, OMAP_AES_CACHE_SIZE);
+ free_pages((unsigned long)dd->buf_in, OMAP_AES_CACHE_SIZE);
+err_alloc:
+ if (err)
+ pr_err("error: %d\n", err);
+ return err;
+}
+
+static void omap_aes_dma_cleanup(struct omap_aes_dev *dd)
+{
+ omap_free_dma(dd->dma_lch_out);
+ omap_free_dma(dd->dma_lch_in);
+ dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
+ DMA_FROM_DEVICE);
+ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, DMA_TO_DEVICE);
+ free_pages((unsigned long)dd->buf_out, OMAP_AES_CACHE_SIZE);
+ free_pages((unsigned long)dd->buf_in, OMAP_AES_CACHE_SIZE);
+}
+
+static void sg_copy_buf(void *buf, struct scatterlist *sg,
+ unsigned int start, unsigned int nbytes, int out)
+{
+ struct scatter_walk walk;
+
+ if (!nbytes)
+ return;
+
+ scatterwalk_start(&walk, sg);
+ scatterwalk_advance(&walk, start);
+ scatterwalk_copychunks(buf, &walk, nbytes, out);
+ scatterwalk_done(&walk, out, 0);
+}
+
+static int sg_copy(struct scatterlist **sg, size_t *offset, void *buf,
+ size_t buflen, size_t total, int out)
+{
+ unsigned int count, off = 0;
+
+ while (buflen && total) {
+ count = min((*sg)->length - *offset, total);
+ count = min(count, buflen);
+
+ if (!count)
+ return off;
+
+ sg_copy_buf(buf + off, *sg, *offset, count, out);
+
+ off += count;
+ buflen -= count;
+ *offset += count;
+ total -= count;
+
+ if (*offset == (*sg)->length) {
+ *sg = sg_next(*sg);
+ if (*sg)
+ *offset = 0;
+ else
+ total = 0;
+ }
+ }
+
+ return off;
+}
+
+static int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
+ dma_addr_t dma_addr_out, int length)
+{
+ struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct omap_aes_dev *dd = ctx->dd;
+ int len32;
+
+ pr_debug("len: %d\n", length);
+
+ dd->dma_size = length;
+
+ if (!(dd->flags & FLAGS_FAST))
+ dma_sync_single_for_device(dd->dev, dma_addr_in, length,
+ DMA_TO_DEVICE);
+
+ len32 = DIV_ROUND_UP(length, sizeof(u32));
+
+ /* IN */
+ omap_set_dma_transfer_params(dd->dma_lch_in, OMAP_DMA_DATA_TYPE_S32,
+ len32, 1, OMAP_DMA_SYNC_PACKET, dd->dma_in,
+ OMAP_DMA_DST_SYNC);
+
+ omap_set_dma_src_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_addr_in, 0, 0);
+
+ /* OUT */
+ omap_set_dma_transfer_params(dd->dma_lch_out, OMAP_DMA_DATA_TYPE_S32,
+ len32, 1, OMAP_DMA_SYNC_PACKET,
+ dd->dma_out, OMAP_DMA_SRC_SYNC);
+
+ omap_set_dma_dest_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_POST_INC,
+ dma_addr_out, 0, 0);
+
+ omap_start_dma(dd->dma_lch_in);
+ omap_start_dma(dd->dma_lch_out);
+
+ omap_aes_write_ctrl(dd);
+
+ return 0;
+}
+
+static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd)
+{
+ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(
+ crypto_ablkcipher_reqtfm(dd->req));
+ int err, fast = 0, in, out;
+ size_t count;
+ dma_addr_t addr_in, addr_out;
+
+ pr_debug("total: %d\n", dd->total);
+
+ if (sg_is_last(dd->in_sg) && sg_is_last(dd->out_sg)) {
+ /* check for alignment */
+ in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32));
+ out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32));
+
+ fast = in && out;
+ }
+
+ if (fast) {
+ count = min(dd->total, sg_dma_len(dd->in_sg));
+ count = min(count, sg_dma_len(dd->out_sg));
+
+ if (count != dd->total)
+ return -EINVAL;
+
+ pr_debug("fast\n");
+
+ err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+ if (!err) {
+ dev_err(dd->dev, "dma_map_sg() error\n");
+ return -EINVAL;
+ }
+
+ err = dma_map_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
+ if (!err) {
+ dev_err(dd->dev, "dma_map_sg() error\n");
+ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+ return -EINVAL;
+ }
+
+ addr_in = sg_dma_address(dd->in_sg);
+ addr_out = sg_dma_address(dd->out_sg);
+
+ dd->flags |= FLAGS_FAST;
+
+ } else {
+ /* use cache buffers */
+ count = sg_copy(&dd->in_sg, &dd->in_offset, dd->buf_in,
+ dd->buflen, dd->total, 0);
+
+ addr_in = dd->dma_addr_in;
+ addr_out = dd->dma_addr_out;
+
+ dd->flags &= ~FLAGS_FAST;
+
+ }
+
+ dd->total -= count;
+
+ err = omap_aes_hw_init(dd);
+
+ err = omap_aes_crypt_dma(tfm, addr_in, addr_out, count);
+
+ return err;
+}
+
+static void omap_aes_finish_req(struct omap_aes_dev *dd, int err)
+{
+ struct omap_aes_ctx *ctx;
+
+ pr_debug("err: %d\n", err);
+
+ ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(dd->req));
+
+ if (!dd->total)
+ dd->req->base.complete(&dd->req->base, err);
+}
+
+static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd)
+{
+ int err = 0;
+ size_t count;
+
+ pr_debug("total: %d\n", dd->total);
+
+ omap_aes_write_mask(dd, AES_REG_MASK, 0, AES_REG_MASK_START);
+
+ omap_aes_hw_cleanup(dd);
+
+ omap_stop_dma(dd->dma_lch_in);
+ omap_stop_dma(dd->dma_lch_out);
+
+ if (dd->flags & FLAGS_FAST) {
+ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
+ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+ } else {
+ dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
+ dd->dma_size, DMA_FROM_DEVICE);
+
+ /* copy data */
+ count = sg_copy(&dd->out_sg, &dd->out_offset, dd->buf_out,
+ dd->buflen, dd->dma_size, 1);
+ if (count != dd->dma_size) {
+ err = -EINVAL;
+ pr_err("not all data converted: %u\n", count);
+ }
+ }
+
+ if (err || !dd->total)
+ omap_aes_finish_req(dd, err);
+
+ return err;
+}
+
+static int omap_aes_handle_req(struct omap_aes_dev *dd)
+{
+ struct crypto_async_request *async_req, *backlog;
+ struct omap_aes_ctx *ctx;
+ struct omap_aes_reqctx *rctx;
+ struct ablkcipher_request *req;
+ unsigned long flags;
+
+ if (dd->total)
+ goto start;
+
+ spin_lock_irqsave(&dd->lock, flags);
+ backlog = crypto_get_backlog(&dd->queue);
+ async_req = crypto_dequeue_request(&dd->queue);
+ if (!async_req)
+ clear_bit(FLAGS_BUSY, &dd->flags);
+ spin_unlock_irqrestore(&dd->lock, flags);
+
+ if (!async_req)
+ return 0;
+
+ if (backlog)
+ backlog->complete(backlog, -EINPROGRESS);
+
+ req = ablkcipher_request_cast(async_req);
+
+ pr_debug("get new req\n");
+
+ /* assign new request to device */
+ dd->req = req;
+ dd->total = req->nbytes;
+ dd->in_offset = 0;
+ dd->in_sg = req->src;
+ dd->out_offset = 0;
+ dd->out_sg = req->dst;
+
+ rctx = ablkcipher_request_ctx(req);
+ ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
+ rctx->mode &= FLAGS_MODE_MASK;
+ dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode;
+
+ dd->iv = req->info;
+ if ((dd->flags & FLAGS_CBC) && dd->iv)
+ dd->flags |= FLAGS_NEW_IV;
+ else
+ dd->flags &= ~FLAGS_NEW_IV;
+
+ ctx->dd = dd;
+ if (dd->ctx != ctx) {
+ /* assign new context to device */
+ dd->ctx = ctx;
+ ctx->flags |= FLAGS_NEW_KEY;
+ }
+
+ if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE))
+ pr_err("request size is not exact amount of AES blocks\n");
+
+start:
+ return omap_aes_crypt_dma_start(dd);
+}
+
+static void omap_aes_task(unsigned long data)
+{
+ struct omap_aes_dev *dd = (struct omap_aes_dev *)data;
+ int err;
+
+ pr_debug("enter\n");
+
+ err = omap_aes_crypt_dma_stop(dd);
+
+ err = omap_aes_handle_req(dd);
+
+ pr_debug("exit\n");
+}
+
+static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
+{
+ struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(
+ crypto_ablkcipher_reqtfm(req));
+ struct omap_aes_reqctx *rctx = ablkcipher_request_ctx(req);
+ struct omap_aes_dev *dd;
+ unsigned long flags;
+ int err;
+
+ pr_debug("nbytes: %d, enc: %d, cbc: %d\n", req->nbytes,
+ !!(mode & FLAGS_ENCRYPT),
+ !!(mode & FLAGS_CBC));
+
+ dd = omap_aes_find_dev(ctx);
+ if (!dd)
+ return -ENODEV;
+
+ rctx->mode = mode;
+
+ spin_lock_irqsave(&dd->lock, flags);
+ err = ablkcipher_enqueue_request(&dd->queue, req);
+ spin_unlock_irqrestore(&dd->lock, flags);
+
+ if (!test_and_set_bit(FLAGS_BUSY, &dd->flags))
+ omap_aes_handle_req(dd);
+
+ pr_debug("exit\n");
+
+ return err;
+}
+
+/* ********************** ALG API ************************************ */
+
+static int omap_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+ if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 &&
+ keylen != AES_KEYSIZE_256)
+ return -EINVAL;
+
+ pr_debug("enter, keylen: %d\n", keylen);
+
+ memcpy(ctx->key, key, keylen);
+ ctx->keylen = keylen;
+ ctx->flags |= FLAGS_NEW_KEY;
+
+ return 0;
+}
+
+static int omap_aes_ecb_encrypt(struct ablkcipher_request *req)
+{
+ return omap_aes_crypt(req, FLAGS_ENCRYPT);
+}
+
+static int omap_aes_ecb_decrypt(struct ablkcipher_request *req)
+{
+ return omap_aes_crypt(req, 0);
+}
+
+static int omap_aes_cbc_encrypt(struct ablkcipher_request *req)
+{
+ return omap_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC);
+}
+
+static int omap_aes_cbc_decrypt(struct ablkcipher_request *req)
+{
+ return omap_aes_crypt(req, FLAGS_CBC);
+}
+
+static int omap_aes_cra_init(struct crypto_tfm *tfm)
+{
+ pr_debug("enter\n");
+
+ tfm->crt_ablkcipher.reqsize = sizeof(struct omap_aes_reqctx);
+
+ return 0;
+}
+
+static void omap_aes_cra_exit(struct crypto_tfm *tfm)
+{
+ pr_debug("enter\n");
+}
+
+/* ********************** ALGS ************************************ */
+
+static struct crypto_alg algs[] = {
+{
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "ecb-aes-omap",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap_aes_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = omap_aes_cra_init,
+ .cra_exit = omap_aes_cra_exit,
+ .cra_u.ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = omap_aes_setkey,
+ .encrypt = omap_aes_ecb_encrypt,
+ .decrypt = omap_aes_ecb_decrypt,
+ }
+},
+{
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-omap",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap_aes_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = omap_aes_cra_init,
+ .cra_exit = omap_aes_cra_exit,
+ .cra_u.ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = omap_aes_setkey,
+ .encrypt = omap_aes_cbc_encrypt,
+ .decrypt = omap_aes_cbc_decrypt,
+ }
+}
+};
+
+static int omap_aes_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct omap_aes_dev *dd;
+ struct resource *res;
+ int err = -ENOMEM, i, j;
+ u32 reg;
+
+ dd = kzalloc(sizeof(struct omap_aes_dev), GFP_KERNEL);
+ if (dd == NULL) {
+ dev_err(dev, "unable to alloc data struct.\n");
+ goto err_data;
+ }
+ dd->dev = dev;
+ platform_set_drvdata(pdev, dd);
+
+ spin_lock_init(&dd->lock);
+ crypto_init_queue(&dd->queue, OMAP_AES_QUEUE_LENGTH);
+
+ /* Get the base address */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "invalid resource type\n");
+ err = -ENODEV;
+ goto err_res;
+ }
+ dd->phys_base = res->start;
+
+ /* Get the DMA */
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res)
+ dev_info(dev, "no DMA info\n");
+ else
+ dd->dma_out = res->start;
+
+ /* Get the DMA */
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!res)
+ dev_info(dev, "no DMA info\n");
+ else
+ dd->dma_in = res->start;
+
+ /* Initializing the clock */
+ dd->iclk = clk_get(dev, "ick");
+ if (!dd->iclk) {
+ dev_err(dev, "clock intialization failed.\n");
+ err = -ENODEV;
+ goto err_res;
+ }
+
+ dd->io_base = ioremap(dd->phys_base, SZ_4K);
+ if (!dd->io_base) {
+ dev_err(dev, "can't ioremap\n");
+ err = -ENOMEM;
+ goto err_io;
+ }
+
+ clk_enable(dd->iclk);
+ reg = omap_aes_read(dd, AES_REG_REV);
+ dev_info(dev, "OMAP AES hw accel rev: %u.%u\n",
+ (reg & AES_REG_REV_MAJOR) >> 4, reg & AES_REG_REV_MINOR);
+ clk_disable(dd->iclk);
+
+ tasklet_init(&dd->task, omap_aes_task, (unsigned long)dd);
+
+ err = omap_aes_dma_init(dd);
+ if (err)
+ goto err_dma;
+
+ INIT_LIST_HEAD(&dd->list);
+ spin_lock(&list_lock);
+ list_add_tail(&dd->list, &dev_list);
+ spin_unlock(&list_lock);
+
+ for (i = 0; i < ARRAY_SIZE(algs); i++) {
+ pr_debug("i: %d\n", i);
+ INIT_LIST_HEAD(&algs[i].cra_list);
+ err = crypto_register_alg(&algs[i]);
+ if (err)
+ goto err_algs;
+ }
+
+ pr_info("probe() done\n");
+
+ return 0;
+err_algs:
+ for (j = 0; j < i; j++)
+ crypto_unregister_alg(&algs[j]);
+ omap_aes_dma_cleanup(dd);
+err_dma:
+ tasklet_kill(&dd->task);
+ iounmap(dd->io_base);
+err_io:
+ clk_put(dd->iclk);
+err_res:
+ kfree(dd);
+ dd = NULL;
+err_data:
+ dev_err(dev, "initialization failed.\n");
+ return err;
+}
+
+static int omap_aes_remove(struct platform_device *pdev)
+{
+ struct omap_aes_dev *dd = platform_get_drvdata(pdev);
+ int i;
+
+ if (!dd)
+ return -ENODEV;
+
+ spin_lock(&list_lock);
+ list_del(&dd->list);
+ spin_unlock(&list_lock);
+
+ for (i = 0; i < ARRAY_SIZE(algs); i++)
+ crypto_unregister_alg(&algs[i]);
+
+ tasklet_kill(&dd->task);
+ omap_aes_dma_cleanup(dd);
+ iounmap(dd->io_base);
+ clk_put(dd->iclk);
+ kfree(dd);
+ dd = NULL;
+
+ return 0;
+}
+
+static struct platform_driver omap_aes_driver = {
+ .probe = omap_aes_probe,
+ .remove = omap_aes_remove,
+ .driver = {
+ .name = "omap-aes",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap_aes_mod_init(void)
+{
+ pr_info("loading %s driver\n", "omap-aes");
+
+ if (!cpu_class_is_omap2() || omap_type() != OMAP2_DEVICE_TYPE_SEC) {
+ pr_err("Unsupported cpu\n");
+ return -ENODEV;
+ }
+
+ return platform_driver_register(&omap_aes_driver);
+}
+
+static void __exit omap_aes_mod_exit(void)
+{
+ platform_driver_unregister(&omap_aes_driver);
+}
+
+module_init(omap_aes_mod_init);
+module_exit(omap_aes_mod_exit);
+
+MODULE_DESCRIPTION("OMAP AES hw acceleration support.");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Dmitry Kasatkin");
+
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 7d1485676886..a081c7c7d03f 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -311,7 +311,8 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
len32 = DIV_ROUND_UP(length, sizeof(u32));
omap_set_dma_transfer_params(dd->dma_lch, OMAP_DMA_DATA_TYPE_S32, len32,
- 1, OMAP_DMA_SYNC_PACKET, dd->dma, OMAP_DMA_DST_SYNC);
+ 1, OMAP_DMA_SYNC_PACKET, dd->dma,
+ OMAP_DMA_DST_SYNC_PREFETCH);
omap_set_dma_src_params(dd->dma_lch, 0, OMAP_DMA_AMODE_POST_INC,
dma_addr, 0, 0);
@@ -1072,6 +1073,9 @@ static int omap_sham_dma_init(struct omap_sham_dev *dd)
omap_set_dma_dest_burst_mode(dd->dma_lch,
OMAP_DMA_DATA_BURST_16);
+ omap_set_dma_src_burst_mode(dd->dma_lch,
+ OMAP_DMA_DATA_BURST_4);
+
return 0;
}
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 4bcd825b5739..b879c3f5d7c0 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -161,7 +161,7 @@ struct talitos_private {
static void to_talitos_ptr(struct talitos_ptr *talitos_ptr, dma_addr_t dma_addr)
{
talitos_ptr->ptr = cpu_to_be32(lower_32_bits(dma_addr));
- talitos_ptr->eptr = cpu_to_be32(upper_32_bits(dma_addr));
+ talitos_ptr->eptr = upper_32_bits(dma_addr);
}
/*
@@ -332,10 +332,9 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc,
/* GO! */
wmb();
- out_be32(priv->reg + TALITOS_FF(ch),
- cpu_to_be32(upper_32_bits(request->dma_desc)));
+ out_be32(priv->reg + TALITOS_FF(ch), upper_32_bits(request->dma_desc));
out_be32(priv->reg + TALITOS_FF_LO(ch),
- cpu_to_be32(lower_32_bits(request->dma_desc)));
+ lower_32_bits(request->dma_desc));
spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags);
@@ -1751,14 +1750,14 @@ static int ahash_init_sha224_swinit(struct ahash_request *areq)
ahash_init(areq);
req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
- req_ctx->hw_context[0] = cpu_to_be32(SHA224_H0);
- req_ctx->hw_context[1] = cpu_to_be32(SHA224_H1);
- req_ctx->hw_context[2] = cpu_to_be32(SHA224_H2);
- req_ctx->hw_context[3] = cpu_to_be32(SHA224_H3);
- req_ctx->hw_context[4] = cpu_to_be32(SHA224_H4);
- req_ctx->hw_context[5] = cpu_to_be32(SHA224_H5);
- req_ctx->hw_context[6] = cpu_to_be32(SHA224_H6);
- req_ctx->hw_context[7] = cpu_to_be32(SHA224_H7);
+ req_ctx->hw_context[0] = SHA224_H0;
+ req_ctx->hw_context[1] = SHA224_H1;
+ req_ctx->hw_context[2] = SHA224_H2;
+ req_ctx->hw_context[3] = SHA224_H3;
+ req_ctx->hw_context[4] = SHA224_H4;
+ req_ctx->hw_context[5] = SHA224_H5;
+ req_ctx->hw_context[6] = SHA224_H6;
+ req_ctx->hw_context[7] = SHA224_H7;
/* init 64-bit count */
req_ctx->hw_context[8] = 0;
@@ -2333,8 +2332,7 @@ static int talitos_remove(struct platform_device *ofdev)
talitos_unregister_rng(dev);
for (i = 0; i < priv->num_channels; i++)
- if (priv->chan[i].fifo)
- kfree(priv->chan[i].fifo);
+ kfree(priv->chan[i].fifo);
kfree(priv->chan);
@@ -2389,6 +2387,9 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
DESC_HDR_MODE0_MDEU_SHA256;
}
break;
+ default:
+ dev_err(dev, "unknown algorithm type %d\n", t_alg->algt.type);
+ return ERR_PTR(-EINVAL);
}
alg->cra_module = THIS_MODULE;
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 9520cf02edc8..79d1542f31c0 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -46,15 +46,22 @@ config INTEL_MID_DMAC
If unsure, say N.
-config ASYNC_TX_DISABLE_CHANNEL_SWITCH
+config ASYNC_TX_ENABLE_CHANNEL_SWITCH
bool
+config AMBA_PL08X
+ bool "ARM PrimeCell PL080 or PL081 support"
+ depends on ARM_AMBA && EXPERIMENTAL
+ select DMA_ENGINE
+ help
+ Platform has a PL08x DMAC device
+ which can provide DMA engine support
+
config INTEL_IOATDMA
tristate "Intel I/OAT DMA support"
depends on PCI && X86
select DMA_ENGINE
select DCA
- select ASYNC_TX_DISABLE_CHANNEL_SWITCH
select ASYNC_TX_DISABLE_PQ_VAL_DMA
select ASYNC_TX_DISABLE_XOR_VAL_DMA
help
@@ -69,6 +76,7 @@ config INTEL_IOP_ADMA
tristate "Intel IOP ADMA support"
depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX
select DMA_ENGINE
+ select ASYNC_TX_ENABLE_CHANNEL_SWITCH
help
Enable support for the Intel(R) IOP Series RAID engines.
@@ -93,6 +101,7 @@ config FSL_DMA
tristate "Freescale Elo and Elo Plus DMA support"
depends on FSL_SOC
select DMA_ENGINE
+ select ASYNC_TX_ENABLE_CHANNEL_SWITCH
---help---
Enable support for the Freescale Elo and Elo Plus DMA controllers.
The Elo is the DMA controller on some 82xx and 83xx parts, and the
@@ -109,6 +118,7 @@ config MV_XOR
bool "Marvell XOR engine support"
depends on PLAT_ORION
select DMA_ENGINE
+ select ASYNC_TX_ENABLE_CHANNEL_SWITCH
---help---
Enable support for the Marvell XOR engine.
@@ -166,6 +176,7 @@ config AMCC_PPC440SPE_ADMA
depends on 440SPe || 440SP
select DMA_ENGINE
select ARCH_HAS_ASYNC_TX_FIND_CHANNEL
+ select ASYNC_TX_ENABLE_CHANNEL_SWITCH
help
Enable support for the AMCC PPC440SPe RAID engines.
@@ -195,6 +206,22 @@ config PCH_DMA
help
Enable support for the Topcliff PCH DMA engine.
+config IMX_SDMA
+ tristate "i.MX SDMA support"
+ depends on ARCH_MX25 || ARCH_MX3 || ARCH_MX5
+ select DMA_ENGINE
+ help
+ Support the i.MX SDMA engine. This engine is integrated into
+ Freescale i.MX25/31/35/51 chips.
+
+config IMX_DMA
+ tristate "i.MX DMA support"
+ depends on ARCH_MX1 || ARCH_MX21 || MACH_MX27
+ select DMA_ENGINE
+ help
+ Support the i.MX DMA engine. This engine is integrated into
+ Freescale i.MX1/21/27 chips.
+
config DMA_ENGINE
bool
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 72bd70384d8a..a8a84f4587f2 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -21,7 +21,10 @@ obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
obj-$(CONFIG_SH_DMAE) += shdma.o
obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o
obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/
+obj-$(CONFIG_IMX_SDMA) += imx-sdma.o
+obj-$(CONFIG_IMX_DMA) += imx-dma.o
obj-$(CONFIG_TIMB_DMA) += timb_dma.o
obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
obj-$(CONFIG_PL330_DMA) += pl330.o
obj-$(CONFIG_PCH_DMA) += pch_dma.o
+obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
new file mode 100644
index 000000000000..b605cc9ac3a2
--- /dev/null
+++ b/drivers/dma/amba-pl08x.c
@@ -0,0 +1,2167 @@
+/*
+ * Copyright (c) 2006 ARM Ltd.
+ * Copyright (c) 2010 ST-Ericsson SA
+ *
+ * Author: Peter Pearse <peter.pearse@arm.com>
+ * Author: Linus Walleij <linus.walleij@stericsson.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.
+ *
+ * The full GNU General Public License is iin this distribution in the
+ * file called COPYING.
+ *
+ * Documentation: ARM DDI 0196G == PL080
+ * Documentation: ARM DDI 0218E == PL081
+ *
+ * PL080 & PL081 both have 16 sets of DMA signals that can be routed to
+ * any channel.
+ *
+ * The PL080 has 8 channels available for simultaneous use, and the PL081
+ * has only two channels. So on these DMA controllers the number of channels
+ * and the number of incoming DMA signals are two totally different things.
+ * It is usually not possible to theoretically handle all physical signals,
+ * so a multiplexing scheme with possible denial of use is necessary.
+ *
+ * The PL080 has a dual bus master, PL081 has a single master.
+ *
+ * Memory to peripheral transfer may be visualized as
+ * Get data from memory to DMAC
+ * Until no data left
+ * On burst request from peripheral
+ * Destination burst from DMAC to peripheral
+ * Clear burst request
+ * Raise terminal count interrupt
+ *
+ * For peripherals with a FIFO:
+ * Source burst size == half the depth of the peripheral FIFO
+ * Destination burst size == the depth of the peripheral FIFO
+ *
+ * (Bursts are irrelevant for mem to mem transfers - there are no burst
+ * signals, the DMA controller will simply facilitate its AHB master.)
+ *
+ * ASSUMES default (little) endianness for DMA transfers
+ *
+ * Only DMAC flow control is implemented
+ *
+ * Global TODO:
+ * - Break out common code from arch/arm/mach-s3c64xx and share
+ */
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/dmapool.h>
+#include <linux/amba/bus.h>
+#include <linux/dmaengine.h>
+#include <linux/amba/pl08x.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <asm/hardware/pl080.h>
+#include <asm/dma.h>
+#include <asm/mach/dma.h>
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <asm/cacheflush.h>
+
+#define DRIVER_NAME "pl08xdmac"
+
+/**
+ * struct vendor_data - vendor-specific config parameters
+ * for PL08x derivates
+ * @name: the name of this specific variant
+ * @channels: the number of channels available in this variant
+ * @dualmaster: whether this version supports dual AHB masters
+ * or not.
+ */
+struct vendor_data {
+ char *name;
+ u8 channels;
+ bool dualmaster;
+};
+
+/*
+ * PL08X private data structures
+ * An LLI struct - see pl08x TRM
+ * Note that next uses bit[0] as a bus bit,
+ * start & end do not - their bus bit info
+ * is in cctl
+ */
+struct lli {
+ dma_addr_t src;
+ dma_addr_t dst;
+ dma_addr_t next;
+ u32 cctl;
+};
+
+/**
+ * struct pl08x_driver_data - the local state holder for the PL08x
+ * @slave: slave engine for this instance
+ * @memcpy: memcpy engine for this instance
+ * @base: virtual memory base (remapped) for the PL08x
+ * @adev: the corresponding AMBA (PrimeCell) bus entry
+ * @vd: vendor data for this PL08x variant
+ * @pd: platform data passed in from the platform/machine
+ * @phy_chans: array of data for the physical channels
+ * @pool: a pool for the LLI descriptors
+ * @pool_ctr: counter of LLIs in the pool
+ * @lock: a spinlock for this struct
+ */
+struct pl08x_driver_data {
+ struct dma_device slave;
+ struct dma_device memcpy;
+ void __iomem *base;
+ struct amba_device *adev;
+ struct vendor_data *vd;
+ struct pl08x_platform_data *pd;
+ struct pl08x_phy_chan *phy_chans;
+ struct dma_pool *pool;
+ int pool_ctr;
+ spinlock_t lock;
+};
+
+/*
+ * PL08X specific defines
+ */
+
+/*
+ * Memory boundaries: the manual for PL08x says that the controller
+ * cannot read past a 1KiB boundary, so these defines are used to
+ * create transfer LLIs that do not cross such boundaries.
+ */
+#define PL08X_BOUNDARY_SHIFT (10) /* 1KB 0x400 */
+#define PL08X_BOUNDARY_SIZE (1 << PL08X_BOUNDARY_SHIFT)
+
+/* Minimum period between work queue runs */
+#define PL08X_WQ_PERIODMIN 20
+
+/* Size (bytes) of each LLI buffer allocated for one transfer */
+# define PL08X_LLI_TSFR_SIZE 0x2000
+
+/* Maximimum times we call dma_pool_alloc on this pool without freeing */
+#define PL08X_MAX_ALLOCS 0x40
+#define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct lli))
+#define PL08X_ALIGN 8
+
+static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan)
+{
+ return container_of(chan, struct pl08x_dma_chan, chan);
+}
+
+/*
+ * Physical channel handling
+ */
+
+/* Whether a certain channel is busy or not */
+static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch)
+{
+ unsigned int val;
+
+ val = readl(ch->base + PL080_CH_CONFIG);
+ return val & PL080_CONFIG_ACTIVE;
+}
+
+/*
+ * Set the initial DMA register values i.e. those for the first LLI
+ * The next lli pointer and the configuration interrupt bit have
+ * been set when the LLIs were constructed
+ */
+static void pl08x_set_cregs(struct pl08x_driver_data *pl08x,
+ struct pl08x_phy_chan *ch)
+{
+ /* Wait for channel inactive */
+ while (pl08x_phy_channel_busy(ch))
+ ;
+
+ dev_vdbg(&pl08x->adev->dev,
+ "WRITE channel %d: csrc=%08x, cdst=%08x, "
+ "cctl=%08x, clli=%08x, ccfg=%08x\n",
+ ch->id,
+ ch->csrc,
+ ch->cdst,
+ ch->cctl,
+ ch->clli,
+ ch->ccfg);
+
+ writel(ch->csrc, ch->base + PL080_CH_SRC_ADDR);
+ writel(ch->cdst, ch->base + PL080_CH_DST_ADDR);
+ writel(ch->clli, ch->base + PL080_CH_LLI);
+ writel(ch->cctl, ch->base + PL080_CH_CONTROL);
+ writel(ch->ccfg, ch->base + PL080_CH_CONFIG);
+}
+
+static inline void pl08x_config_phychan_for_txd(struct pl08x_dma_chan *plchan)
+{
+ struct pl08x_channel_data *cd = plchan->cd;
+ struct pl08x_phy_chan *phychan = plchan->phychan;
+ struct pl08x_txd *txd = plchan->at;
+
+ /* Copy the basic control register calculated at transfer config */
+ phychan->csrc = txd->csrc;
+ phychan->cdst = txd->cdst;
+ phychan->clli = txd->clli;
+ phychan->cctl = txd->cctl;
+
+ /* Assign the signal to the proper control registers */
+ phychan->ccfg = cd->ccfg;
+ phychan->ccfg &= ~PL080_CONFIG_SRC_SEL_MASK;
+ phychan->ccfg &= ~PL080_CONFIG_DST_SEL_MASK;
+ /* If it wasn't set from AMBA, ignore it */
+ if (txd->direction == DMA_TO_DEVICE)
+ /* Select signal as destination */
+ phychan->ccfg |=
+ (phychan->signal << PL080_CONFIG_DST_SEL_SHIFT);
+ else if (txd->direction == DMA_FROM_DEVICE)
+ /* Select signal as source */
+ phychan->ccfg |=
+ (phychan->signal << PL080_CONFIG_SRC_SEL_SHIFT);
+ /* Always enable error interrupts */
+ phychan->ccfg |= PL080_CONFIG_ERR_IRQ_MASK;
+ /* Always enable terminal interrupts */
+ phychan->ccfg |= PL080_CONFIG_TC_IRQ_MASK;
+}
+
+/*
+ * Enable the DMA channel
+ * Assumes all other configuration bits have been set
+ * as desired before this code is called
+ */
+static void pl08x_enable_phy_chan(struct pl08x_driver_data *pl08x,
+ struct pl08x_phy_chan *ch)
+{
+ u32 val;
+
+ /*
+ * Do not access config register until channel shows as disabled
+ */
+ while (readl(pl08x->base + PL080_EN_CHAN) & (1 << ch->id))
+ ;
+
+ /*
+ * Do not access config register until channel shows as inactive
+ */
+ val = readl(ch->base + PL080_CH_CONFIG);
+ while ((val & PL080_CONFIG_ACTIVE) || (val & PL080_CONFIG_ENABLE))
+ val = readl(ch->base + PL080_CH_CONFIG);
+
+ writel(val | PL080_CONFIG_ENABLE, ch->base + PL080_CH_CONFIG);
+}
+
+/*
+ * Overall DMAC remains enabled always.
+ *
+ * Disabling individual channels could lose data.
+ *
+ * Disable the peripheral DMA after disabling the DMAC
+ * in order to allow the DMAC FIFO to drain, and
+ * hence allow the channel to show inactive
+ *
+ */
+static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch)
+{
+ u32 val;
+
+ /* Set the HALT bit and wait for the FIFO to drain */
+ val = readl(ch->base + PL080_CH_CONFIG);
+ val |= PL080_CONFIG_HALT;
+ writel(val, ch->base + PL080_CH_CONFIG);
+
+ /* Wait for channel inactive */
+ while (pl08x_phy_channel_busy(ch))
+ ;
+}
+
+static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch)
+{
+ u32 val;
+
+ /* Clear the HALT bit */
+ val = readl(ch->base + PL080_CH_CONFIG);
+ val &= ~PL080_CONFIG_HALT;
+ writel(val, ch->base + PL080_CH_CONFIG);
+}
+
+
+/* Stops the channel */
+static void pl08x_stop_phy_chan(struct pl08x_phy_chan *ch)
+{
+ u32 val;
+
+ pl08x_pause_phy_chan(ch);
+
+ /* Disable channel */
+ val = readl(ch->base + PL080_CH_CONFIG);
+ val &= ~PL080_CONFIG_ENABLE;
+ val &= ~PL080_CONFIG_ERR_IRQ_MASK;
+ val &= ~PL080_CONFIG_TC_IRQ_MASK;
+ writel(val, ch->base + PL080_CH_CONFIG);
+}
+
+static inline u32 get_bytes_in_cctl(u32 cctl)
+{
+ /* The source width defines the number of bytes */
+ u32 bytes = cctl & PL080_CONTROL_TRANSFER_SIZE_MASK;
+
+ switch (cctl >> PL080_CONTROL_SWIDTH_SHIFT) {
+ case PL080_WIDTH_8BIT:
+ break;
+ case PL080_WIDTH_16BIT:
+ bytes *= 2;
+ break;
+ case PL080_WIDTH_32BIT:
+ bytes *= 4;
+ break;
+ }
+ return bytes;
+}
+
+/* The channel should be paused when calling this */
+static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
+{
+ struct pl08x_phy_chan *ch;
+ struct pl08x_txd *txdi = NULL;
+ struct pl08x_txd *txd;
+ unsigned long flags;
+ u32 bytes = 0;
+
+ spin_lock_irqsave(&plchan->lock, flags);
+
+ ch = plchan->phychan;
+ txd = plchan->at;
+
+ /*
+ * Next follow the LLIs to get the number of pending bytes in the
+ * currently active transaction.
+ */
+ if (ch && txd) {
+ struct lli *llis_va = txd->llis_va;
+ struct lli *llis_bus = (struct lli *) txd->llis_bus;
+ u32 clli = readl(ch->base + PL080_CH_LLI);
+
+ /* First get the bytes in the current active LLI */
+ bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL));
+
+ if (clli) {
+ int i = 0;
+
+ /* Forward to the LLI pointed to by clli */
+ while ((clli != (u32) &(llis_bus[i])) &&
+ (i < MAX_NUM_TSFR_LLIS))
+ i++;
+
+ while (clli) {
+ bytes += get_bytes_in_cctl(llis_va[i].cctl);
+ /*
+ * A clli of 0x00000000 will terminate the
+ * LLI list
+ */
+ clli = llis_va[i].next;
+ i++;
+ }
+ }
+ }
+
+ /* Sum up all queued transactions */
+ if (!list_empty(&plchan->desc_list)) {
+ list_for_each_entry(txdi, &plchan->desc_list, node) {
+ bytes += txdi->len;
+ }
+
+ }
+
+ spin_unlock_irqrestore(&plchan->lock, flags);
+
+ return bytes;
+}
+
+/*
+ * Allocate a physical channel for a virtual channel
+ */
+static struct pl08x_phy_chan *
+pl08x_get_phy_channel(struct pl08x_driver_data *pl08x,
+ struct pl08x_dma_chan *virt_chan)
+{
+ struct pl08x_phy_chan *ch = NULL;
+ unsigned long flags;
+ int i;
+
+ /*
+ * Try to locate a physical channel to be used for
+ * this transfer. If all are taken return NULL and
+ * the requester will have to cope by using some fallback
+ * PIO mode or retrying later.
+ */
+ for (i = 0; i < pl08x->vd->channels; i++) {
+ ch = &pl08x->phy_chans[i];
+
+ spin_lock_irqsave(&ch->lock, flags);
+
+ if (!ch->serving) {
+ ch->serving = virt_chan;
+ ch->signal = -1;
+ spin_unlock_irqrestore(&ch->lock, flags);
+ break;
+ }
+
+ spin_unlock_irqrestore(&ch->lock, flags);
+ }
+
+ if (i == pl08x->vd->channels) {
+ /* No physical channel available, cope with it */
+ return NULL;
+ }
+
+ return ch;
+}
+
+static inline void pl08x_put_phy_channel(struct pl08x_driver_data *pl08x,
+ struct pl08x_phy_chan *ch)
+{
+ unsigned long flags;
+
+ /* Stop the channel and clear its interrupts */
+ pl08x_stop_phy_chan(ch);
+ writel((1 << ch->id), pl08x->base + PL080_ERR_CLEAR);
+ writel((1 << ch->id), pl08x->base + PL080_TC_CLEAR);
+
+ /* Mark it as free */
+ spin_lock_irqsave(&ch->lock, flags);
+ ch->serving = NULL;
+ spin_unlock_irqrestore(&ch->lock, flags);
+}
+
+/*
+ * LLI handling
+ */
+
+static inline unsigned int pl08x_get_bytes_for_cctl(unsigned int coded)
+{
+ switch (coded) {
+ case PL080_WIDTH_8BIT:
+ return 1;
+ case PL080_WIDTH_16BIT:
+ return 2;
+ case PL080_WIDTH_32BIT:
+ return 4;
+ default:
+ break;
+ }
+ BUG();
+ return 0;
+}
+
+static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth,
+ u32 tsize)
+{
+ u32 retbits = cctl;
+
+ /* Remove all src, dst and transfersize bits */
+ retbits &= ~PL080_CONTROL_DWIDTH_MASK;
+ retbits &= ~PL080_CONTROL_SWIDTH_MASK;
+ retbits &= ~PL080_CONTROL_TRANSFER_SIZE_MASK;
+
+ /* Then set the bits according to the parameters */
+ switch (srcwidth) {
+ case 1:
+ retbits |= PL080_WIDTH_8BIT << PL080_CONTROL_SWIDTH_SHIFT;
+ break;
+ case 2:
+ retbits |= PL080_WIDTH_16BIT << PL080_CONTROL_SWIDTH_SHIFT;
+ break;
+ case 4:
+ retbits |= PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT;
+ break;
+ default:
+ BUG();
+ break;
+ }
+
+ switch (dstwidth) {
+ case 1:
+ retbits |= PL080_WIDTH_8BIT << PL080_CONTROL_DWIDTH_SHIFT;
+ break;
+ case 2:
+ retbits |= PL080_WIDTH_16BIT << PL080_CONTROL_DWIDTH_SHIFT;
+ break;
+ case 4:
+ retbits |= PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT;
+ break;
+ default:
+ BUG();
+ break;
+ }
+
+ retbits |= tsize << PL080_CONTROL_TRANSFER_SIZE_SHIFT;
+ return retbits;
+}
+
+/*
+ * Autoselect a master bus to use for the transfer
+ * this prefers the destination bus if both available
+ * if fixed address on one bus the other will be chosen
+ */
+void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus,
+ struct pl08x_bus_data *dst_bus, struct pl08x_bus_data **mbus,
+ struct pl08x_bus_data **sbus, u32 cctl)
+{
+ if (!(cctl & PL080_CONTROL_DST_INCR)) {
+ *mbus = src_bus;
+ *sbus = dst_bus;
+ } else if (!(cctl & PL080_CONTROL_SRC_INCR)) {
+ *mbus = dst_bus;
+ *sbus = src_bus;
+ } else {
+ if (dst_bus->buswidth == 4) {
+ *mbus = dst_bus;
+ *sbus = src_bus;
+ } else if (src_bus->buswidth == 4) {
+ *mbus = src_bus;
+ *sbus = dst_bus;
+ } else if (dst_bus->buswidth == 2) {
+ *mbus = dst_bus;
+ *sbus = src_bus;
+ } else if (src_bus->buswidth == 2) {
+ *mbus = src_bus;
+ *sbus = dst_bus;
+ } else {
+ /* src_bus->buswidth == 1 */
+ *mbus = dst_bus;
+ *sbus = src_bus;
+ }
+ }
+}
+
+/*
+ * Fills in one LLI for a certain transfer descriptor
+ * and advance the counter
+ */
+int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x,
+ struct pl08x_txd *txd, int num_llis, int len,
+ u32 cctl, u32 *remainder)
+{
+ struct lli *llis_va = txd->llis_va;
+ struct lli *llis_bus = (struct lli *) txd->llis_bus;
+
+ BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS);
+
+ llis_va[num_llis].cctl = cctl;
+ llis_va[num_llis].src = txd->srcbus.addr;
+ llis_va[num_llis].dst = txd->dstbus.addr;
+
+ /*
+ * On versions with dual masters, you can optionally AND on
+ * PL080_LLI_LM_AHB2 to the LLI to tell the hardware to read
+ * in new LLIs with that controller, but we always try to
+ * choose AHB1 to point into memory. The idea is to have AHB2
+ * fixed on the peripheral and AHB1 messing around in the
+ * memory. So we don't manipulate this bit currently.
+ */
+
+ llis_va[num_llis].next =
+ (dma_addr_t)((u32) &(llis_bus[num_llis + 1]));
+
+ if (cctl & PL080_CONTROL_SRC_INCR)
+ txd->srcbus.addr += len;
+ if (cctl & PL080_CONTROL_DST_INCR)
+ txd->dstbus.addr += len;
+
+ *remainder -= len;
+
+ return num_llis + 1;
+}
+
+/*
+ * Return number of bytes to fill to boundary, or len
+ */
+static inline u32 pl08x_pre_boundary(u32 addr, u32 len)
+{
+ u32 boundary;
+
+ boundary = ((addr >> PL08X_BOUNDARY_SHIFT) + 1)
+ << PL08X_BOUNDARY_SHIFT;
+
+ if (boundary < addr + len)
+ return boundary - addr;
+ else
+ return len;
+}
+
+/*
+ * This fills in the table of LLIs for the transfer descriptor
+ * Note that we assume we never have to change the burst sizes
+ * Return 0 for error
+ */
+static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
+ struct pl08x_txd *txd)
+{
+ struct pl08x_channel_data *cd = txd->cd;
+ struct pl08x_bus_data *mbus, *sbus;
+ u32 remainder;
+ int num_llis = 0;
+ u32 cctl;
+ int max_bytes_per_lli;
+ int total_bytes = 0;
+ struct lli *llis_va;
+ struct lli *llis_bus;
+
+ if (!txd) {
+ dev_err(&pl08x->adev->dev, "%s no descriptor\n", __func__);
+ return 0;
+ }
+
+ txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT,
+ &txd->llis_bus);
+ if (!txd->llis_va) {
+ dev_err(&pl08x->adev->dev, "%s no memory for llis\n", __func__);
+ return 0;
+ }
+
+ pl08x->pool_ctr++;
+
+ /*
+ * Initialize bus values for this transfer
+ * from the passed optimal values
+ */
+ if (!cd) {
+ dev_err(&pl08x->adev->dev, "%s no channel data\n", __func__);
+ return 0;
+ }
+
+ /* Get the default CCTL from the platform data */
+ cctl = cd->cctl;
+
+ /*
+ * On the PL080 we have two bus masters and we
+ * should select one for source and one for
+ * destination. We try to use AHB2 for the
+ * bus which does not increment (typically the
+ * peripheral) else we just choose something.
+ */
+ cctl &= ~(PL080_CONTROL_DST_AHB2 | PL080_CONTROL_SRC_AHB2);
+ if (pl08x->vd->dualmaster) {
+ if (cctl & PL080_CONTROL_SRC_INCR)
+ /* Source increments, use AHB2 for destination */
+ cctl |= PL080_CONTROL_DST_AHB2;
+ else if (cctl & PL080_CONTROL_DST_INCR)
+ /* Destination increments, use AHB2 for source */
+ cctl |= PL080_CONTROL_SRC_AHB2;
+ else
+ /* Just pick something, source AHB1 dest AHB2 */
+ cctl |= PL080_CONTROL_DST_AHB2;
+ }
+
+ /* Find maximum width of the source bus */
+ txd->srcbus.maxwidth =
+ pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_SWIDTH_MASK) >>
+ PL080_CONTROL_SWIDTH_SHIFT);
+
+ /* Find maximum width of the destination bus */
+ txd->dstbus.maxwidth =
+ pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_DWIDTH_MASK) >>
+ PL080_CONTROL_DWIDTH_SHIFT);
+
+ /* Set up the bus widths to the maximum */
+ txd->srcbus.buswidth = txd->srcbus.maxwidth;
+ txd->dstbus.buswidth = txd->dstbus.maxwidth;
+ dev_vdbg(&pl08x->adev->dev,
+ "%s source bus is %d bytes wide, dest bus is %d bytes wide\n",
+ __func__, txd->srcbus.buswidth, txd->dstbus.buswidth);
+
+
+ /*
+ * Bytes transferred == tsize * MIN(buswidths), not max(buswidths)
+ */
+ max_bytes_per_lli = min(txd->srcbus.buswidth, txd->dstbus.buswidth) *
+ PL080_CONTROL_TRANSFER_SIZE_MASK;
+ dev_vdbg(&pl08x->adev->dev,
+ "%s max bytes per lli = %d\n",
+ __func__, max_bytes_per_lli);
+
+ /* We need to count this down to zero */
+ remainder = txd->len;
+ dev_vdbg(&pl08x->adev->dev,
+ "%s remainder = %d\n",
+ __func__, remainder);
+
+ /*
+ * Choose bus to align to
+ * - prefers destination bus if both available
+ * - if fixed address on one bus chooses other
+ * - modifies cctl to choose an apropriate master
+ */
+ pl08x_choose_master_bus(&txd->srcbus, &txd->dstbus,
+ &mbus, &sbus, cctl);
+
+
+ /*
+ * The lowest bit of the LLI register
+ * is also used to indicate which master to
+ * use for reading the LLIs.
+ */
+
+ if (txd->len < mbus->buswidth) {
+ /*
+ * Less than a bus width available
+ * - send as single bytes
+ */
+ while (remainder) {
+ dev_vdbg(&pl08x->adev->dev,
+ "%s single byte LLIs for a transfer of "
+ "less than a bus width (remain %08x)\n",
+ __func__, remainder);
+ cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
+ num_llis =
+ pl08x_fill_lli_for_desc(pl08x, txd, num_llis, 1,
+ cctl, &remainder);
+ total_bytes++;
+ }
+ } else {
+ /*
+ * Make one byte LLIs until master bus is aligned
+ * - slave will then be aligned also
+ */
+ while ((mbus->addr) % (mbus->buswidth)) {
+ dev_vdbg(&pl08x->adev->dev,
+ "%s adjustment lli for less than bus width "
+ "(remain %08x)\n",
+ __func__, remainder);
+ cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
+ num_llis = pl08x_fill_lli_for_desc
+ (pl08x, txd, num_llis, 1, cctl, &remainder);
+ total_bytes++;
+ }
+
+ /*
+ * Master now aligned
+ * - if slave is not then we must set its width down
+ */
+ if (sbus->addr % sbus->buswidth) {
+ dev_dbg(&pl08x->adev->dev,
+ "%s set down bus width to one byte\n",
+ __func__);
+
+ sbus->buswidth = 1;
+ }
+
+ /*
+ * Make largest possible LLIs until less than one bus
+ * width left
+ */
+ while (remainder > (mbus->buswidth - 1)) {
+ int lli_len, target_len;
+ int tsize;
+ int odd_bytes;
+
+ /*
+ * If enough left try to send max possible,
+ * otherwise try to send the remainder
+ */
+ target_len = remainder;
+ if (remainder > max_bytes_per_lli)
+ target_len = max_bytes_per_lli;
+
+ /*
+ * Set bus lengths for incrementing busses
+ * to number of bytes which fill to next memory
+ * boundary
+ */
+ if (cctl & PL080_CONTROL_SRC_INCR)
+ txd->srcbus.fill_bytes =
+ pl08x_pre_boundary(
+ txd->srcbus.addr,
+ remainder);
+ else
+ txd->srcbus.fill_bytes =
+ max_bytes_per_lli;
+
+ if (cctl & PL080_CONTROL_DST_INCR)
+ txd->dstbus.fill_bytes =
+ pl08x_pre_boundary(
+ txd->dstbus.addr,
+ remainder);
+ else
+ txd->dstbus.fill_bytes =
+ max_bytes_per_lli;
+
+ /*
+ * Find the nearest
+ */
+ lli_len = min(txd->srcbus.fill_bytes,
+ txd->dstbus.fill_bytes);
+
+ BUG_ON(lli_len > remainder);
+
+ if (lli_len <= 0) {
+ dev_err(&pl08x->adev->dev,
+ "%s lli_len is %d, <= 0\n",
+ __func__, lli_len);
+ return 0;
+ }
+
+ if (lli_len == target_len) {
+ /*
+ * Can send what we wanted
+ */
+ /*
+ * Maintain alignment
+ */
+ lli_len = (lli_len/mbus->buswidth) *
+ mbus->buswidth;
+ odd_bytes = 0;
+ } else {
+ /*
+ * So now we know how many bytes to transfer
+ * to get to the nearest boundary
+ * The next lli will past the boundary
+ * - however we may be working to a boundary
+ * on the slave bus
+ * We need to ensure the master stays aligned
+ */
+ odd_bytes = lli_len % mbus->buswidth;
+ /*
+ * - and that we are working in multiples
+ * of the bus widths
+ */
+ lli_len -= odd_bytes;
+
+ }
+
+ if (lli_len) {
+ /*
+ * Check against minimum bus alignment:
+ * Calculate actual transfer size in relation
+ * to bus width an get a maximum remainder of
+ * the smallest bus width - 1
+ */
+ /* FIXME: use round_down()? */
+ tsize = lli_len / min(mbus->buswidth,
+ sbus->buswidth);
+ lli_len = tsize * min(mbus->buswidth,
+ sbus->buswidth);
+
+ if (target_len != lli_len) {
+ dev_vdbg(&pl08x->adev->dev,
+ "%s can't send what we want. Desired %08x, lli of %08x bytes in txd of %08x\n",
+ __func__, target_len, lli_len, txd->len);
+ }
+
+ cctl = pl08x_cctl_bits(cctl,
+ txd->srcbus.buswidth,
+ txd->dstbus.buswidth,
+ tsize);
+
+ dev_vdbg(&pl08x->adev->dev,
+ "%s fill lli with single lli chunk of size %08x (remainder %08x)\n",
+ __func__, lli_len, remainder);
+ num_llis = pl08x_fill_lli_for_desc(pl08x, txd,
+ num_llis, lli_len, cctl,
+ &remainder);
+ total_bytes += lli_len;
+ }
+
+
+ if (odd_bytes) {
+ /*
+ * Creep past the boundary,
+ * maintaining master alignment
+ */
+ int j;
+ for (j = 0; (j < mbus->buswidth)
+ && (remainder); j++) {
+ cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
+ dev_vdbg(&pl08x->adev->dev,
+ "%s align with boundardy, single byte (remain %08x)\n",
+ __func__, remainder);
+ num_llis =
+ pl08x_fill_lli_for_desc(pl08x,
+ txd, num_llis, 1,
+ cctl, &remainder);
+ total_bytes++;
+ }
+ }
+ }
+
+ /*
+ * Send any odd bytes
+ */
+ if (remainder < 0) {
+ dev_err(&pl08x->adev->dev, "%s remainder not fitted 0x%08x bytes\n",
+ __func__, remainder);
+ return 0;
+ }
+
+ while (remainder) {
+ cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
+ dev_vdbg(&pl08x->adev->dev,
+ "%s align with boundardy, single odd byte (remain %d)\n",
+ __func__, remainder);
+ num_llis = pl08x_fill_lli_for_desc(pl08x, txd, num_llis,
+ 1, cctl, &remainder);
+ total_bytes++;
+ }
+ }
+ if (total_bytes != txd->len) {
+ dev_err(&pl08x->adev->dev,
+ "%s size of encoded lli:s don't match total txd, transferred 0x%08x from size 0x%08x\n",
+ __func__, total_bytes, txd->len);
+ return 0;
+ }
+
+ if (num_llis >= MAX_NUM_TSFR_LLIS) {
+ dev_err(&pl08x->adev->dev,
+ "%s need to increase MAX_NUM_TSFR_LLIS from 0x%08x\n",
+ __func__, (u32) MAX_NUM_TSFR_LLIS);
+ return 0;
+ }
+ /*
+ * Decide whether this is a loop or a terminated transfer
+ */
+ llis_va = txd->llis_va;
+ llis_bus = (struct lli *) txd->llis_bus;
+
+ if (cd->circular_buffer) {
+ /*
+ * Loop the circular buffer so that the next element
+ * points back to the beginning of the LLI.
+ */
+ llis_va[num_llis - 1].next =
+ (dma_addr_t)((unsigned int)&(llis_bus[0]));
+ } else {
+ /*
+ * On non-circular buffers, the final LLI terminates
+ * the LLI.
+ */
+ llis_va[num_llis - 1].next = 0;
+ /*
+ * The final LLI element shall also fire an interrupt
+ */
+ llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN;
+ }
+
+ /* Now store the channel register values */
+ txd->csrc = llis_va[0].src;
+ txd->cdst = llis_va[0].dst;
+ if (num_llis > 1)
+ txd->clli = llis_va[0].next;
+ else
+ txd->clli = 0;
+
+ txd->cctl = llis_va[0].cctl;
+ /* ccfg will be set at physical channel allocation time */
+
+#ifdef VERBOSE_DEBUG
+ {
+ int i;
+
+ for (i = 0; i < num_llis; i++) {
+ dev_vdbg(&pl08x->adev->dev,
+ "lli %d @%p: csrc=%08x, cdst=%08x, cctl=%08x, clli=%08x\n",
+ i,
+ &llis_va[i],
+ llis_va[i].src,
+ llis_va[i].dst,
+ llis_va[i].cctl,
+ llis_va[i].next
+ );
+ }
+ }
+#endif
+
+ return num_llis;
+}
+
+/* You should call this with the struct pl08x lock held */
+static void pl08x_free_txd(struct pl08x_driver_data *pl08x,
+ struct pl08x_txd *txd)
+{
+ if (!txd)
+ dev_err(&pl08x->adev->dev,
+ "%s no descriptor to free\n",
+ __func__);
+
+ /* Free the LLI */
+ dma_pool_free(pl08x->pool, txd->llis_va,
+ txd->llis_bus);
+
+ pl08x->pool_ctr--;
+
+ kfree(txd);
+}
+
+static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x,
+ struct pl08x_dma_chan *plchan)
+{
+ struct pl08x_txd *txdi = NULL;
+ struct pl08x_txd *next;
+
+ if (!list_empty(&plchan->desc_list)) {
+ list_for_each_entry_safe(txdi,
+ next, &plchan->desc_list, node) {
+ list_del(&txdi->node);
+ pl08x_free_txd(pl08x, txdi);
+ }
+
+ }
+}
+
+/*
+ * The DMA ENGINE API
+ */
+static int pl08x_alloc_chan_resources(struct dma_chan *chan)
+{
+ return 0;
+}
+
+static void pl08x_free_chan_resources(struct dma_chan *chan)
+{
+}
+
+/*
+ * This should be called with the channel plchan->lock held
+ */
+static int prep_phy_channel(struct pl08x_dma_chan *plchan,
+ struct pl08x_txd *txd)
+{
+ struct pl08x_driver_data *pl08x = plchan->host;
+ struct pl08x_phy_chan *ch;
+ int ret;
+
+ /* Check if we already have a channel */
+ if (plchan->phychan)
+ return 0;
+
+ ch = pl08x_get_phy_channel(pl08x, plchan);
+ if (!ch) {
+ /* No physical channel available, cope with it */
+ dev_dbg(&pl08x->adev->dev, "no physical channel available for xfer on %s\n", plchan->name);
+ return -EBUSY;
+ }
+
+ /*
+ * OK we have a physical channel: for memcpy() this is all we
+ * need, but for slaves the physical signals may be muxed!
+ * Can the platform allow us to use this channel?
+ */
+ if (plchan->slave &&
+ ch->signal < 0 &&
+ pl08x->pd->get_signal) {
+ ret = pl08x->pd->get_signal(plchan);
+ if (ret < 0) {
+ dev_dbg(&pl08x->adev->dev,
+ "unable to use physical channel %d for transfer on %s due to platform restrictions\n",
+ ch->id, plchan->name);
+ /* Release physical channel & return */
+ pl08x_put_phy_channel(pl08x, ch);
+ return -EBUSY;
+ }
+ ch->signal = ret;
+ }
+
+ dev_dbg(&pl08x->adev->dev, "allocated physical channel %d and signal %d for xfer on %s\n",
+ ch->id,
+ ch->signal,
+ plchan->name);
+
+ plchan->phychan = ch;
+
+ return 0;
+}
+
+static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(tx->chan);
+
+ atomic_inc(&plchan->last_issued);
+ tx->cookie = atomic_read(&plchan->last_issued);
+ /* This unlock follows the lock in the prep() function */
+ spin_unlock_irqrestore(&plchan->lock, plchan->lockflags);
+
+ return tx->cookie;
+}
+
+static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt(
+ struct dma_chan *chan, unsigned long flags)
+{
+ struct dma_async_tx_descriptor *retval = NULL;
+
+ return retval;
+}
+
+/*
+ * Code accessing dma_async_is_complete() in a tight loop
+ * may give problems - could schedule where indicated.
+ * If slaves are relying on interrupts to signal completion this
+ * function must not be called with interrupts disabled
+ */
+static enum dma_status
+pl08x_dma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ dma_cookie_t last_used;
+ dma_cookie_t last_complete;
+ enum dma_status ret;
+ u32 bytesleft = 0;
+
+ last_used = atomic_read(&plchan->last_issued);
+ last_complete = plchan->lc;
+
+ ret = dma_async_is_complete(cookie, last_complete, last_used);
+ if (ret == DMA_SUCCESS) {
+ dma_set_tx_state(txstate, last_complete, last_used, 0);
+ return ret;
+ }
+
+ /*
+ * schedule(); could be inserted here
+ */
+
+ /*
+ * This cookie not complete yet
+ */
+ last_used = atomic_read(&plchan->last_issued);
+ last_complete = plchan->lc;
+
+ /* Get number of bytes left in the active transactions and queue */
+ bytesleft = pl08x_getbytes_chan(plchan);
+
+ dma_set_tx_state(txstate, last_complete, last_used,
+ bytesleft);
+
+ if (plchan->state == PL08X_CHAN_PAUSED)
+ return DMA_PAUSED;
+
+ /* Whether waiting or running, we're in progress */
+ return DMA_IN_PROGRESS;
+}
+
+/* PrimeCell DMA extension */
+struct burst_table {
+ int burstwords;
+ u32 reg;
+};
+
+static const struct burst_table burst_sizes[] = {
+ {
+ .burstwords = 256,
+ .reg = (PL080_BSIZE_256 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_256 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+ {
+ .burstwords = 128,
+ .reg = (PL080_BSIZE_128 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_128 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+ {
+ .burstwords = 64,
+ .reg = (PL080_BSIZE_64 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_64 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+ {
+ .burstwords = 32,
+ .reg = (PL080_BSIZE_32 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_32 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+ {
+ .burstwords = 16,
+ .reg = (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+ {
+ .burstwords = 8,
+ .reg = (PL080_BSIZE_8 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_8 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+ {
+ .burstwords = 4,
+ .reg = (PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+ {
+ .burstwords = 1,
+ .reg = (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT),
+ },
+};
+
+static void dma_set_runtime_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ struct pl08x_driver_data *pl08x = plchan->host;
+ struct pl08x_channel_data *cd = plchan->cd;
+ enum dma_slave_buswidth addr_width;
+ u32 maxburst;
+ u32 cctl = 0;
+ /* Mask out all except src and dst channel */
+ u32 ccfg = cd->ccfg & 0x000003DEU;
+ int i = 0;
+
+ /* Transfer direction */
+ plchan->runtime_direction = config->direction;
+ if (config->direction == DMA_TO_DEVICE) {
+ plchan->runtime_addr = config->dst_addr;
+ cctl |= PL080_CONTROL_SRC_INCR;
+ ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+ addr_width = config->dst_addr_width;
+ maxburst = config->dst_maxburst;
+ } else if (config->direction == DMA_FROM_DEVICE) {
+ plchan->runtime_addr = config->src_addr;
+ cctl |= PL080_CONTROL_DST_INCR;
+ ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+ addr_width = config->src_addr_width;
+ maxburst = config->src_maxburst;
+ } else {
+ dev_err(&pl08x->adev->dev,
+ "bad runtime_config: alien transfer direction\n");
+ return;
+ }
+
+ switch (addr_width) {
+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
+ cctl |= (PL080_WIDTH_8BIT << PL080_CONTROL_SWIDTH_SHIFT) |
+ (PL080_WIDTH_8BIT << PL080_CONTROL_DWIDTH_SHIFT);
+ break;
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
+ cctl |= (PL080_WIDTH_16BIT << PL080_CONTROL_SWIDTH_SHIFT) |
+ (PL080_WIDTH_16BIT << PL080_CONTROL_DWIDTH_SHIFT);
+ break;
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ cctl |= (PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT) |
+ (PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT);
+ break;
+ default:
+ dev_err(&pl08x->adev->dev,
+ "bad runtime_config: alien address width\n");
+ return;
+ }
+
+ /*
+ * Now decide on a maxburst:
+ * If this channel will only request single transfers, set
+ * this down to ONE element.
+ */
+ if (plchan->cd->single) {
+ cctl |= (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) |
+ (PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT);
+ } else {
+ while (i < ARRAY_SIZE(burst_sizes)) {
+ if (burst_sizes[i].burstwords <= maxburst)
+ break;
+ i++;
+ }
+ cctl |= burst_sizes[i].reg;
+ }
+
+ /* Access the cell in privileged mode, non-bufferable, non-cacheable */
+ cctl &= ~PL080_CONTROL_PROT_MASK;
+ cctl |= PL080_CONTROL_PROT_SYS;
+
+ /* Modify the default channel data to fit PrimeCell request */
+ cd->cctl = cctl;
+ cd->ccfg = ccfg;
+
+ dev_dbg(&pl08x->adev->dev,
+ "configured channel %s (%s) for %s, data width %d, "
+ "maxburst %d words, LE, CCTL=%08x, CCFG=%08x\n",
+ dma_chan_name(chan), plchan->name,
+ (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX",
+ addr_width,
+ maxburst,
+ cctl, ccfg);
+}
+
+/*
+ * Slave transactions callback to the slave device to allow
+ * synchronization of slave DMA signals with the DMAC enable
+ */
+static void pl08x_issue_pending(struct dma_chan *chan)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ struct pl08x_driver_data *pl08x = plchan->host;
+ unsigned long flags;
+
+ spin_lock_irqsave(&plchan->lock, flags);
+ /* Something is already active */
+ if (plchan->at) {
+ spin_unlock_irqrestore(&plchan->lock, flags);
+ return;
+ }
+
+ /* Didn't get a physical channel so waiting for it ... */
+ if (plchan->state == PL08X_CHAN_WAITING)
+ return;
+
+ /* Take the first element in the queue and execute it */
+ if (!list_empty(&plchan->desc_list)) {
+ struct pl08x_txd *next;
+
+ next = list_first_entry(&plchan->desc_list,
+ struct pl08x_txd,
+ node);
+ list_del(&next->node);
+ plchan->at = next;
+ plchan->state = PL08X_CHAN_RUNNING;
+
+ /* Configure the physical channel for the active txd */
+ pl08x_config_phychan_for_txd(plchan);
+ pl08x_set_cregs(pl08x, plchan->phychan);
+ pl08x_enable_phy_chan(pl08x, plchan->phychan);
+ }
+
+ spin_unlock_irqrestore(&plchan->lock, flags);
+}
+
+static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan,
+ struct pl08x_txd *txd)
+{
+ int num_llis;
+ struct pl08x_driver_data *pl08x = plchan->host;
+ int ret;
+
+ num_llis = pl08x_fill_llis_for_desc(pl08x, txd);
+
+ if (!num_llis)
+ return -EINVAL;
+
+ spin_lock_irqsave(&plchan->lock, plchan->lockflags);
+
+ /*
+ * If this device is not using a circular buffer then
+ * queue this new descriptor for transfer.
+ * The descriptor for a circular buffer continues
+ * to be used until the channel is freed.
+ */
+ if (txd->cd->circular_buffer)
+ dev_err(&pl08x->adev->dev,
+ "%s attempting to queue a circular buffer\n",
+ __func__);
+ else
+ list_add_tail(&txd->node,
+ &plchan->desc_list);
+
+ /*
+ * See if we already have a physical channel allocated,
+ * else this is the time to try to get one.
+ */
+ ret = prep_phy_channel(plchan, txd);
+ if (ret) {
+ /*
+ * No physical channel available, we will
+ * stack up the memcpy channels until there is a channel
+ * available to handle it whereas slave transfers may
+ * have been denied due to platform channel muxing restrictions
+ * and since there is no guarantee that this will ever be
+ * resolved, and since the signal must be aquired AFTER
+ * aquiring the physical channel, we will let them be NACK:ed
+ * with -EBUSY here. The drivers can alway retry the prep()
+ * call if they are eager on doing this using DMA.
+ */
+ if (plchan->slave) {
+ pl08x_free_txd_list(pl08x, plchan);
+ spin_unlock_irqrestore(&plchan->lock, plchan->lockflags);
+ return -EBUSY;
+ }
+ /* Do this memcpy whenever there is a channel ready */
+ plchan->state = PL08X_CHAN_WAITING;
+ plchan->waiting = txd;
+ } else
+ /*
+ * Else we're all set, paused and ready to roll,
+ * status will switch to PL08X_CHAN_RUNNING when
+ * we call issue_pending(). If there is something
+ * running on the channel already we don't change
+ * its state.
+ */
+ if (plchan->state == PL08X_CHAN_IDLE)
+ plchan->state = PL08X_CHAN_PAUSED;
+
+ /*
+ * Notice that we leave plchan->lock locked on purpose:
+ * it will be unlocked in the subsequent tx_submit()
+ * call. This is a consequence of the current API.
+ */
+
+ return 0;
+}
+
+/*
+ * Initialize a descriptor to be used by memcpy submit
+ */
+static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
+ struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+ size_t len, unsigned long flags)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ struct pl08x_driver_data *pl08x = plchan->host;
+ struct pl08x_txd *txd;
+ int ret;
+
+ txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT);
+ if (!txd) {
+ dev_err(&pl08x->adev->dev,
+ "%s no memory for descriptor\n", __func__);
+ return NULL;
+ }
+
+ dma_async_tx_descriptor_init(&txd->tx, chan);
+ txd->direction = DMA_NONE;
+ txd->srcbus.addr = src;
+ txd->dstbus.addr = dest;
+
+ /* Set platform data for m2m */
+ txd->cd = &pl08x->pd->memcpy_channel;
+ /* Both to be incremented or the code will break */
+ txd->cd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR;
+ txd->tx.tx_submit = pl08x_tx_submit;
+ txd->tx.callback = NULL;
+ txd->tx.callback_param = NULL;
+ txd->len = len;
+
+ INIT_LIST_HEAD(&txd->node);
+ ret = pl08x_prep_channel_resources(plchan, txd);
+ if (ret)
+ return NULL;
+ /*
+ * NB: the channel lock is held at this point so tx_submit()
+ * must be called in direct succession.
+ */
+
+ return &txd->tx;
+}
+
+struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_data_direction direction,
+ unsigned long flags)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ struct pl08x_driver_data *pl08x = plchan->host;
+ struct pl08x_txd *txd;
+ int ret;
+
+ /*
+ * Current implementation ASSUMES only one sg
+ */
+ if (sg_len != 1) {
+ dev_err(&pl08x->adev->dev, "%s prepared too long sglist\n",
+ __func__);
+ BUG();
+ }
+
+ dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n",
+ __func__, sgl->length, plchan->name);
+
+ txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT);
+ if (!txd) {
+ dev_err(&pl08x->adev->dev, "%s no txd\n", __func__);
+ return NULL;
+ }
+
+ dma_async_tx_descriptor_init(&txd->tx, chan);
+
+ if (direction != plchan->runtime_direction)
+ dev_err(&pl08x->adev->dev, "%s DMA setup does not match "
+ "the direction configured for the PrimeCell\n",
+ __func__);
+
+ /*
+ * Set up addresses, the PrimeCell configured address
+ * will take precedence since this may configure the
+ * channel target address dynamically at runtime.
+ */
+ txd->direction = direction;
+ if (direction == DMA_TO_DEVICE) {
+ txd->srcbus.addr = sgl->dma_address;
+ if (plchan->runtime_addr)
+ txd->dstbus.addr = plchan->runtime_addr;
+ else
+ txd->dstbus.addr = plchan->cd->addr;
+ } else if (direction == DMA_FROM_DEVICE) {
+ if (plchan->runtime_addr)
+ txd->srcbus.addr = plchan->runtime_addr;
+ else
+ txd->srcbus.addr = plchan->cd->addr;
+ txd->dstbus.addr = sgl->dma_address;
+ } else {
+ dev_err(&pl08x->adev->dev,
+ "%s direction unsupported\n", __func__);
+ return NULL;
+ }
+ txd->cd = plchan->cd;
+ txd->tx.tx_submit = pl08x_tx_submit;
+ txd->tx.callback = NULL;
+ txd->tx.callback_param = NULL;
+ txd->len = sgl->length;
+ INIT_LIST_HEAD(&txd->node);
+
+ ret = pl08x_prep_channel_resources(plchan, txd);
+ if (ret)
+ return NULL;
+ /*
+ * NB: the channel lock is held at this point so tx_submit()
+ * must be called in direct succession.
+ */
+
+ return &txd->tx;
+}
+
+static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ struct pl08x_driver_data *pl08x = plchan->host;
+ unsigned long flags;
+ int ret = 0;
+
+ /* Controls applicable to inactive channels */
+ if (cmd == DMA_SLAVE_CONFIG) {
+ dma_set_runtime_config(chan,
+ (struct dma_slave_config *)
+ arg);
+ return 0;
+ }
+
+ /*
+ * Anything succeeds on channels with no physical allocation and
+ * no queued transfers.
+ */
+ spin_lock_irqsave(&plchan->lock, flags);
+ if (!plchan->phychan && !plchan->at) {
+ spin_unlock_irqrestore(&plchan->lock, flags);
+ return 0;
+ }
+
+ switch (cmd) {
+ case DMA_TERMINATE_ALL:
+ plchan->state = PL08X_CHAN_IDLE;
+
+ if (plchan->phychan) {
+ pl08x_stop_phy_chan(plchan->phychan);
+
+ /*
+ * Mark physical channel as free and free any slave
+ * signal
+ */
+ if ((plchan->phychan->signal >= 0) &&
+ pl08x->pd->put_signal) {
+ pl08x->pd->put_signal(plchan);
+ plchan->phychan->signal = -1;
+ }
+ pl08x_put_phy_channel(pl08x, plchan->phychan);
+ plchan->phychan = NULL;
+ }
+ /* Stop any pending tasklet */
+ tasklet_disable(&plchan->tasklet);
+ /* Dequeue jobs and free LLIs */
+ if (plchan->at) {
+ pl08x_free_txd(pl08x, plchan->at);
+ plchan->at = NULL;
+ }
+ /* Dequeue jobs not yet fired as well */
+ pl08x_free_txd_list(pl08x, plchan);
+ break;
+ case DMA_PAUSE:
+ pl08x_pause_phy_chan(plchan->phychan);
+ plchan->state = PL08X_CHAN_PAUSED;
+ break;
+ case DMA_RESUME:
+ pl08x_resume_phy_chan(plchan->phychan);
+ plchan->state = PL08X_CHAN_RUNNING;
+ break;
+ default:
+ /* Unknown command */
+ ret = -ENXIO;
+ break;
+ }
+
+ spin_unlock_irqrestore(&plchan->lock, flags);
+
+ return ret;
+}
+
+bool pl08x_filter_id(struct dma_chan *chan, void *chan_id)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ char *name = chan_id;
+
+ /* Check that the channel is not taken! */
+ if (!strcmp(plchan->name, name))
+ return true;
+
+ return false;
+}
+
+/*
+ * Just check that the device is there and active
+ * TODO: turn this bit on/off depending on the number of
+ * physical channels actually used, if it is zero... well
+ * shut it off. That will save some power. Cut the clock
+ * at the same time.
+ */
+static void pl08x_ensure_on(struct pl08x_driver_data *pl08x)
+{
+ u32 val;
+
+ val = readl(pl08x->base + PL080_CONFIG);
+ val &= ~(PL080_CONFIG_M2_BE | PL080_CONFIG_M1_BE | PL080_CONFIG_ENABLE);
+ /* We implictly clear bit 1 and that means little-endian mode */
+ val |= PL080_CONFIG_ENABLE;
+ writel(val, pl08x->base + PL080_CONFIG);
+}
+
+static void pl08x_tasklet(unsigned long data)
+{
+ struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data;
+ struct pl08x_phy_chan *phychan = plchan->phychan;
+ struct pl08x_driver_data *pl08x = plchan->host;
+
+ if (!plchan)
+ BUG();
+
+ spin_lock(&plchan->lock);
+
+ if (plchan->at) {
+ dma_async_tx_callback callback =
+ plchan->at->tx.callback;
+ void *callback_param =
+ plchan->at->tx.callback_param;
+
+ /*
+ * Update last completed
+ */
+ plchan->lc =
+ (plchan->at->tx.cookie);
+
+ /*
+ * Callback to signal completion
+ */
+ if (callback)
+ callback(callback_param);
+
+ /*
+ * Device callbacks should NOT clear
+ * the current transaction on the channel
+ * Linus: sometimes they should?
+ */
+ if (!plchan->at)
+ BUG();
+
+ /*
+ * Free the descriptor if it's not for a device
+ * using a circular buffer
+ */
+ if (!plchan->at->cd->circular_buffer) {
+ pl08x_free_txd(pl08x, plchan->at);
+ plchan->at = NULL;
+ }
+ /*
+ * else descriptor for circular
+ * buffers only freed when
+ * client has disabled dma
+ */
+ }
+ /*
+ * If a new descriptor is queued, set it up
+ * plchan->at is NULL here
+ */
+ if (!list_empty(&plchan->desc_list)) {
+ struct pl08x_txd *next;
+
+ next = list_first_entry(&plchan->desc_list,
+ struct pl08x_txd,
+ node);
+ list_del(&next->node);
+ plchan->at = next;
+ /* Configure the physical channel for the next txd */
+ pl08x_config_phychan_for_txd(plchan);
+ pl08x_set_cregs(pl08x, plchan->phychan);
+ pl08x_enable_phy_chan(pl08x, plchan->phychan);
+ } else {
+ struct pl08x_dma_chan *waiting = NULL;
+
+ /*
+ * No more jobs, so free up the physical channel
+ * Free any allocated signal on slave transfers too
+ */
+ if ((phychan->signal >= 0) && pl08x->pd->put_signal) {
+ pl08x->pd->put_signal(plchan);
+ phychan->signal = -1;
+ }
+ pl08x_put_phy_channel(pl08x, phychan);
+ plchan->phychan = NULL;
+ plchan->state = PL08X_CHAN_IDLE;
+
+ /*
+ * And NOW before anyone else can grab that free:d
+ * up physical channel, see if there is some memcpy
+ * pending that seriously needs to start because of
+ * being stacked up while we were choking the
+ * physical channels with data.
+ */
+ list_for_each_entry(waiting, &pl08x->memcpy.channels,
+ chan.device_node) {
+ if (waiting->state == PL08X_CHAN_WAITING &&
+ waiting->waiting != NULL) {
+ int ret;
+
+ /* This should REALLY not fail now */
+ ret = prep_phy_channel(waiting,
+ waiting->waiting);
+ BUG_ON(ret);
+ waiting->state = PL08X_CHAN_RUNNING;
+ waiting->waiting = NULL;
+ pl08x_issue_pending(&waiting->chan);
+ break;
+ }
+ }
+ }
+
+ spin_unlock(&plchan->lock);
+}
+
+static irqreturn_t pl08x_irq(int irq, void *dev)
+{
+ struct pl08x_driver_data *pl08x = dev;
+ u32 mask = 0;
+ u32 val;
+ int i;
+
+ val = readl(pl08x->base + PL080_ERR_STATUS);
+ if (val) {
+ /*
+ * An error interrupt (on one or more channels)
+ */
+ dev_err(&pl08x->adev->dev,
+ "%s error interrupt, register value 0x%08x\n",
+ __func__, val);
+ /*
+ * Simply clear ALL PL08X error interrupts,
+ * regardless of channel and cause
+ * FIXME: should be 0x00000003 on PL081 really.
+ */
+ writel(0x000000FF, pl08x->base + PL080_ERR_CLEAR);
+ }
+ val = readl(pl08x->base + PL080_INT_STATUS);
+ for (i = 0; i < pl08x->vd->channels; i++) {
+ if ((1 << i) & val) {
+ /* Locate physical channel */
+ struct pl08x_phy_chan *phychan = &pl08x->phy_chans[i];
+ struct pl08x_dma_chan *plchan = phychan->serving;
+
+ /* Schedule tasklet on this channel */
+ tasklet_schedule(&plchan->tasklet);
+
+ mask |= (1 << i);
+ }
+ }
+ /*
+ * Clear only the terminal interrupts on channels we processed
+ */
+ writel(mask, pl08x->base + PL080_TC_CLEAR);
+
+ return mask ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/*
+ * Initialise the DMAC memcpy/slave channels.
+ * Make a local wrapper to hold required data
+ */
+static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
+ struct dma_device *dmadev,
+ unsigned int channels,
+ bool slave)
+{
+ struct pl08x_dma_chan *chan;
+ int i;
+
+ INIT_LIST_HEAD(&dmadev->channels);
+ /*
+ * Register as many many memcpy as we have physical channels,
+ * we won't always be able to use all but the code will have
+ * to cope with that situation.
+ */
+ for (i = 0; i < channels; i++) {
+ chan = kzalloc(sizeof(struct pl08x_dma_chan), GFP_KERNEL);
+ if (!chan) {
+ dev_err(&pl08x->adev->dev,
+ "%s no memory for channel\n", __func__);
+ return -ENOMEM;
+ }
+
+ chan->host = pl08x;
+ chan->state = PL08X_CHAN_IDLE;
+
+ if (slave) {
+ chan->slave = true;
+ chan->name = pl08x->pd->slave_channels[i].bus_id;
+ chan->cd = &pl08x->pd->slave_channels[i];
+ } else {
+ chan->cd = &pl08x->pd->memcpy_channel;
+ chan->name = kasprintf(GFP_KERNEL, "memcpy%d", i);
+ if (!chan->name) {
+ kfree(chan);
+ return -ENOMEM;
+ }
+ }
+ dev_info(&pl08x->adev->dev,
+ "initialize virtual channel \"%s\"\n",
+ chan->name);
+
+ chan->chan.device = dmadev;
+ atomic_set(&chan->last_issued, 0);
+ chan->lc = atomic_read(&chan->last_issued);
+
+ spin_lock_init(&chan->lock);
+ INIT_LIST_HEAD(&chan->desc_list);
+ tasklet_init(&chan->tasklet, pl08x_tasklet,
+ (unsigned long) chan);
+
+ list_add_tail(&chan->chan.device_node, &dmadev->channels);
+ }
+ dev_info(&pl08x->adev->dev, "initialized %d virtual %s channels\n",
+ i, slave ? "slave" : "memcpy");
+ return i;
+}
+
+static void pl08x_free_virtual_channels(struct dma_device *dmadev)
+{
+ struct pl08x_dma_chan *chan = NULL;
+ struct pl08x_dma_chan *next;
+
+ list_for_each_entry_safe(chan,
+ next, &dmadev->channels, chan.device_node) {
+ list_del(&chan->chan.device_node);
+ kfree(chan);
+ }
+}
+
+#ifdef CONFIG_DEBUG_FS
+static const char *pl08x_state_str(enum pl08x_dma_chan_state state)
+{
+ switch (state) {
+ case PL08X_CHAN_IDLE:
+ return "idle";
+ case PL08X_CHAN_RUNNING:
+ return "running";
+ case PL08X_CHAN_PAUSED:
+ return "paused";
+ case PL08X_CHAN_WAITING:
+ return "waiting";
+ default:
+ break;
+ }
+ return "UNKNOWN STATE";
+}
+
+static int pl08x_debugfs_show(struct seq_file *s, void *data)
+{
+ struct pl08x_driver_data *pl08x = s->private;
+ struct pl08x_dma_chan *chan;
+ struct pl08x_phy_chan *ch;
+ unsigned long flags;
+ int i;
+
+ seq_printf(s, "PL08x physical channels:\n");
+ seq_printf(s, "CHANNEL:\tUSER:\n");
+ seq_printf(s, "--------\t-----\n");
+ for (i = 0; i < pl08x->vd->channels; i++) {
+ struct pl08x_dma_chan *virt_chan;
+
+ ch = &pl08x->phy_chans[i];
+
+ spin_lock_irqsave(&ch->lock, flags);
+ virt_chan = ch->serving;
+
+ seq_printf(s, "%d\t\t%s\n",
+ ch->id, virt_chan ? virt_chan->name : "(none)");
+
+ spin_unlock_irqrestore(&ch->lock, flags);
+ }
+
+ seq_printf(s, "\nPL08x virtual memcpy channels:\n");
+ seq_printf(s, "CHANNEL:\tSTATE:\n");
+ seq_printf(s, "--------\t------\n");
+ list_for_each_entry(chan, &pl08x->memcpy.channels, chan.device_node) {
+ seq_printf(s, "%s\t\t\%s\n", chan->name,
+ pl08x_state_str(chan->state));
+ }
+
+ seq_printf(s, "\nPL08x virtual slave channels:\n");
+ seq_printf(s, "CHANNEL:\tSTATE:\n");
+ seq_printf(s, "--------\t------\n");
+ list_for_each_entry(chan, &pl08x->slave.channels, chan.device_node) {
+ seq_printf(s, "%s\t\t\%s\n", chan->name,
+ pl08x_state_str(chan->state));
+ }
+
+ return 0;
+}
+
+static int pl08x_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pl08x_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations pl08x_debugfs_operations = {
+ .open = pl08x_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void init_pl08x_debugfs(struct pl08x_driver_data *pl08x)
+{
+ /* Expose a simple debugfs interface to view all clocks */
+ (void) debugfs_create_file(dev_name(&pl08x->adev->dev), S_IFREG | S_IRUGO,
+ NULL, pl08x,
+ &pl08x_debugfs_operations);
+}
+
+#else
+static inline void init_pl08x_debugfs(struct pl08x_driver_data *pl08x)
+{
+}
+#endif
+
+static int pl08x_probe(struct amba_device *adev, struct amba_id *id)
+{
+ struct pl08x_driver_data *pl08x;
+ struct vendor_data *vd = id->data;
+ int ret = 0;
+ int i;
+
+ ret = amba_request_regions(adev, NULL);
+ if (ret)
+ return ret;
+
+ /* Create the driver state holder */
+ pl08x = kzalloc(sizeof(struct pl08x_driver_data), GFP_KERNEL);
+ if (!pl08x) {
+ ret = -ENOMEM;
+ goto out_no_pl08x;
+ }
+
+ /* Initialize memcpy engine */
+ dma_cap_set(DMA_MEMCPY, pl08x->memcpy.cap_mask);
+ pl08x->memcpy.dev = &adev->dev;
+ pl08x->memcpy.device_alloc_chan_resources = pl08x_alloc_chan_resources;
+ pl08x->memcpy.device_free_chan_resources = pl08x_free_chan_resources;
+ pl08x->memcpy.device_prep_dma_memcpy = pl08x_prep_dma_memcpy;
+ pl08x->memcpy.device_prep_dma_interrupt = pl08x_prep_dma_interrupt;
+ pl08x->memcpy.device_tx_status = pl08x_dma_tx_status;
+ pl08x->memcpy.device_issue_pending = pl08x_issue_pending;
+ pl08x->memcpy.device_control = pl08x_control;
+
+ /* Initialize slave engine */
+ dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask);
+ pl08x->slave.dev = &adev->dev;
+ pl08x->slave.device_alloc_chan_resources = pl08x_alloc_chan_resources;
+ pl08x->slave.device_free_chan_resources = pl08x_free_chan_resources;
+ pl08x->slave.device_prep_dma_interrupt = pl08x_prep_dma_interrupt;
+ pl08x->slave.device_tx_status = pl08x_dma_tx_status;
+ pl08x->slave.device_issue_pending = pl08x_issue_pending;
+ pl08x->slave.device_prep_slave_sg = pl08x_prep_slave_sg;
+ pl08x->slave.device_control = pl08x_control;
+
+ /* Get the platform data */
+ pl08x->pd = dev_get_platdata(&adev->dev);
+ if (!pl08x->pd) {
+ dev_err(&adev->dev, "no platform data supplied\n");
+ goto out_no_platdata;
+ }
+
+ /* Assign useful pointers to the driver state */
+ pl08x->adev = adev;
+ pl08x->vd = vd;
+
+ /* A DMA memory pool for LLIs, align on 1-byte boundary */
+ pl08x->pool = dma_pool_create(DRIVER_NAME, &pl08x->adev->dev,
+ PL08X_LLI_TSFR_SIZE, PL08X_ALIGN, 0);
+ if (!pl08x->pool) {
+ ret = -ENOMEM;
+ goto out_no_lli_pool;
+ }
+
+ spin_lock_init(&pl08x->lock);
+
+ pl08x->base = ioremap(adev->res.start, resource_size(&adev->res));
+ if (!pl08x->base) {
+ ret = -ENOMEM;
+ goto out_no_ioremap;
+ }
+
+ /* Turn on the PL08x */
+ pl08x_ensure_on(pl08x);
+
+ /*
+ * Attach the interrupt handler
+ */
+ writel(0x000000FF, pl08x->base + PL080_ERR_CLEAR);
+ writel(0x000000FF, pl08x->base + PL080_TC_CLEAR);
+
+ ret = request_irq(adev->irq[0], pl08x_irq, IRQF_DISABLED,
+ vd->name, pl08x);
+ if (ret) {
+ dev_err(&adev->dev, "%s failed to request interrupt %d\n",
+ __func__, adev->irq[0]);
+ goto out_no_irq;
+ }
+
+ /* Initialize physical channels */
+ pl08x->phy_chans = kmalloc((vd->channels * sizeof(struct pl08x_phy_chan)),
+ GFP_KERNEL);
+ if (!pl08x->phy_chans) {
+ dev_err(&adev->dev, "%s failed to allocate "
+ "physical channel holders\n",
+ __func__);
+ goto out_no_phychans;
+ }
+
+ for (i = 0; i < vd->channels; i++) {
+ struct pl08x_phy_chan *ch = &pl08x->phy_chans[i];
+
+ ch->id = i;
+ ch->base = pl08x->base + PL080_Cx_BASE(i);
+ spin_lock_init(&ch->lock);
+ ch->serving = NULL;
+ ch->signal = -1;
+ dev_info(&adev->dev,
+ "physical channel %d is %s\n", i,
+ pl08x_phy_channel_busy(ch) ? "BUSY" : "FREE");
+ }
+
+ /* Register as many memcpy channels as there are physical channels */
+ ret = pl08x_dma_init_virtual_channels(pl08x, &pl08x->memcpy,
+ pl08x->vd->channels, false);
+ if (ret <= 0) {
+ dev_warn(&pl08x->adev->dev,
+ "%s failed to enumerate memcpy channels - %d\n",
+ __func__, ret);
+ goto out_no_memcpy;
+ }
+ pl08x->memcpy.chancnt = ret;
+
+ /* Register slave channels */
+ ret = pl08x_dma_init_virtual_channels(pl08x, &pl08x->slave,
+ pl08x->pd->num_slave_channels,
+ true);
+ if (ret <= 0) {
+ dev_warn(&pl08x->adev->dev,
+ "%s failed to enumerate slave channels - %d\n",
+ __func__, ret);
+ goto out_no_slave;
+ }
+ pl08x->slave.chancnt = ret;
+
+ ret = dma_async_device_register(&pl08x->memcpy);
+ if (ret) {
+ dev_warn(&pl08x->adev->dev,
+ "%s failed to register memcpy as an async device - %d\n",
+ __func__, ret);
+ goto out_no_memcpy_reg;
+ }
+
+ ret = dma_async_device_register(&pl08x->slave);
+ if (ret) {
+ dev_warn(&pl08x->adev->dev,
+ "%s failed to register slave as an async device - %d\n",
+ __func__, ret);
+ goto out_no_slave_reg;
+ }
+
+ amba_set_drvdata(adev, pl08x);
+ init_pl08x_debugfs(pl08x);
+ dev_info(&pl08x->adev->dev, "ARM(R) %s DMA block initialized @%08x\n",
+ vd->name, adev->res.start);
+ return 0;
+
+out_no_slave_reg:
+ dma_async_device_unregister(&pl08x->memcpy);
+out_no_memcpy_reg:
+ pl08x_free_virtual_channels(&pl08x->slave);
+out_no_slave:
+ pl08x_free_virtual_channels(&pl08x->memcpy);
+out_no_memcpy:
+ kfree(pl08x->phy_chans);
+out_no_phychans:
+ free_irq(adev->irq[0], pl08x);
+out_no_irq:
+ iounmap(pl08x->base);
+out_no_ioremap:
+ dma_pool_destroy(pl08x->pool);
+out_no_lli_pool:
+out_no_platdata:
+ kfree(pl08x);
+out_no_pl08x:
+ amba_release_regions(adev);
+ return ret;
+}
+
+/* PL080 has 8 channels and the PL080 have just 2 */
+static struct vendor_data vendor_pl080 = {
+ .name = "PL080",
+ .channels = 8,
+ .dualmaster = true,
+};
+
+static struct vendor_data vendor_pl081 = {
+ .name = "PL081",
+ .channels = 2,
+ .dualmaster = false,
+};
+
+static struct amba_id pl08x_ids[] = {
+ /* PL080 */
+ {
+ .id = 0x00041080,
+ .mask = 0x000fffff,
+ .data = &vendor_pl080,
+ },
+ /* PL081 */
+ {
+ .id = 0x00041081,
+ .mask = 0x000fffff,
+ .data = &vendor_pl081,
+ },
+ /* Nomadik 8815 PL080 variant */
+ {
+ .id = 0x00280880,
+ .mask = 0x00ffffff,
+ .data = &vendor_pl080,
+ },
+ { 0, 0 },
+};
+
+static struct amba_driver pl08x_amba_driver = {
+ .drv.name = DRIVER_NAME,
+ .id_table = pl08x_ids,
+ .probe = pl08x_probe,
+};
+
+static int __init pl08x_init(void)
+{
+ int retval;
+ retval = amba_driver_register(&pl08x_amba_driver);
+ if (retval)
+ printk(KERN_WARNING DRIVER_NAME
+ "failed to register as an amba device (%d)\n",
+ retval);
+ return retval;
+}
+subsys_initcall(pl08x_init);
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index ae2b8714d190..a6656834f0ff 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -1610,7 +1610,7 @@ int __init coh901318_init(void)
{
return platform_driver_probe(&coh901318_driver, coh901318_probe);
}
-subsys_initcall(coh901318_init);
+arch_initcall(coh901318_init);
void __exit coh901318_exit(void)
{
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 9d31d5eb95c1..8bcb15fb959d 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -690,8 +690,12 @@ int dma_async_device_register(struct dma_device *device)
!device->device_prep_dma_memset);
BUG_ON(dma_has_cap(DMA_INTERRUPT, device->cap_mask) &&
!device->device_prep_dma_interrupt);
+ BUG_ON(dma_has_cap(DMA_SG, device->cap_mask) &&
+ !device->device_prep_dma_sg);
BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&
!device->device_prep_slave_sg);
+ BUG_ON(dma_has_cap(DMA_CYCLIC, device->cap_mask) &&
+ !device->device_prep_dma_cyclic);
BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&
!device->device_control);
@@ -702,7 +706,7 @@ int dma_async_device_register(struct dma_device *device)
BUG_ON(!device->dev);
/* note: this only matters in the
- * CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH=y case
+ * CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH=n case
*/
if (device_has_all_tx_types(device))
dma_cap_set(DMA_ASYNC_TX, device->cap_mask);
@@ -976,7 +980,7 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx,
struct dma_chan *chan)
{
tx->chan = chan;
- #ifndef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH
+ #ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
spin_lock_init(&tx->lock);
#endif
}
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index cea08bed9cf9..286c3ac6bdcc 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -35,9 +35,10 @@
#include <linux/dmapool.h>
#include <linux/of_platform.h>
-#include <asm/fsldma.h>
#include "fsldma.h"
+static const char msg_ld_oom[] = "No free memory for link descriptor\n";
+
static void dma_init(struct fsldma_chan *chan)
{
/* Reset the channel */
@@ -499,7 +500,7 @@ fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags)
new = fsl_dma_alloc_descriptor(chan);
if (!new) {
- dev_err(chan->dev, "No free memory for link descriptor\n");
+ dev_err(chan->dev, msg_ld_oom);
return NULL;
}
@@ -536,8 +537,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
/* Allocate the link descriptor from DMA pool */
new = fsl_dma_alloc_descriptor(chan);
if (!new) {
- dev_err(chan->dev,
- "No free memory for link descriptor\n");
+ dev_err(chan->dev, msg_ld_oom);
goto fail;
}
#ifdef FSL_DMA_LD_DEBUG
@@ -583,223 +583,205 @@ fail:
return NULL;
}
-/**
- * fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
- * @chan: DMA channel
- * @sgl: scatterlist to transfer to/from
- * @sg_len: number of entries in @scatterlist
- * @direction: DMA direction
- * @flags: DMAEngine flags
- *
- * Prepare a set of descriptors for a DMA_SLAVE transaction. Following the
- * DMA_SLAVE API, this gets the device-specific information from the
- * chan->private variable.
- */
-static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
- struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
- enum dma_data_direction direction, unsigned long flags)
+static struct dma_async_tx_descriptor *fsl_dma_prep_sg(struct dma_chan *dchan,
+ struct scatterlist *dst_sg, unsigned int dst_nents,
+ struct scatterlist *src_sg, unsigned int src_nents,
+ unsigned long flags)
{
- struct fsldma_chan *chan;
struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL;
- struct fsl_dma_slave *slave;
- size_t copy;
-
- int i;
- struct scatterlist *sg;
- size_t sg_used;
- size_t hw_used;
- struct fsl_dma_hw_addr *hw;
- dma_addr_t dma_dst, dma_src;
+ struct fsldma_chan *chan = to_fsl_chan(dchan);
+ size_t dst_avail, src_avail;
+ dma_addr_t dst, src;
+ size_t len;
- if (!dchan)
+ /* basic sanity checks */
+ if (dst_nents == 0 || src_nents == 0)
return NULL;
- if (!dchan->private)
+ if (dst_sg == NULL || src_sg == NULL)
return NULL;
- chan = to_fsl_chan(dchan);
- slave = dchan->private;
+ /*
+ * TODO: should we check that both scatterlists have the same
+ * TODO: number of bytes in total? Is that really an error?
+ */
- if (list_empty(&slave->addresses))
- return NULL;
+ /* get prepared for the loop */
+ dst_avail = sg_dma_len(dst_sg);
+ src_avail = sg_dma_len(src_sg);
- hw = list_first_entry(&slave->addresses, struct fsl_dma_hw_addr, entry);
- hw_used = 0;
+ /* run until we are out of scatterlist entries */
+ while (true) {
- /*
- * Build the hardware transaction to copy from the scatterlist to
- * the hardware, or from the hardware to the scatterlist
- *
- * If you are copying from the hardware to the scatterlist and it
- * takes two hardware entries to fill an entire page, then both
- * hardware entries will be coalesced into the same page
- *
- * If you are copying from the scatterlist to the hardware and a
- * single page can fill two hardware entries, then the data will
- * be read out of the page into the first hardware entry, and so on
- */
- for_each_sg(sgl, sg, sg_len, i) {
- sg_used = 0;
-
- /* Loop until the entire scatterlist entry is used */
- while (sg_used < sg_dma_len(sg)) {
-
- /*
- * If we've used up the current hardware address/length
- * pair, we need to load a new one
- *
- * This is done in a while loop so that descriptors with
- * length == 0 will be skipped
- */
- while (hw_used >= hw->length) {
-
- /*
- * If the current hardware entry is the last
- * entry in the list, we're finished
- */
- if (list_is_last(&hw->entry, &slave->addresses))
- goto finished;
-
- /* Get the next hardware address/length pair */
- hw = list_entry(hw->entry.next,
- struct fsl_dma_hw_addr, entry);
- hw_used = 0;
- }
-
- /* Allocate the link descriptor from DMA pool */
- new = fsl_dma_alloc_descriptor(chan);
- if (!new) {
- dev_err(chan->dev, "No free memory for "
- "link descriptor\n");
- goto fail;
- }
+ /* create the largest transaction possible */
+ len = min_t(size_t, src_avail, dst_avail);
+ len = min_t(size_t, len, FSL_DMA_BCR_MAX_CNT);
+ if (len == 0)
+ goto fetch;
+
+ dst = sg_dma_address(dst_sg) + sg_dma_len(dst_sg) - dst_avail;
+ src = sg_dma_address(src_sg) + sg_dma_len(src_sg) - src_avail;
+
+ /* allocate and populate the descriptor */
+ new = fsl_dma_alloc_descriptor(chan);
+ if (!new) {
+ dev_err(chan->dev, msg_ld_oom);
+ goto fail;
+ }
#ifdef FSL_DMA_LD_DEBUG
- dev_dbg(chan->dev, "new link desc alloc %p\n", new);
+ dev_dbg(chan->dev, "new link desc alloc %p\n", new);
#endif
- /*
- * Calculate the maximum number of bytes to transfer,
- * making sure it is less than the DMA controller limit
- */
- copy = min_t(size_t, sg_dma_len(sg) - sg_used,
- hw->length - hw_used);
- copy = min_t(size_t, copy, FSL_DMA_BCR_MAX_CNT);
-
- /*
- * DMA_FROM_DEVICE
- * from the hardware to the scatterlist
- *
- * DMA_TO_DEVICE
- * from the scatterlist to the hardware
- */
- if (direction == DMA_FROM_DEVICE) {
- dma_src = hw->address + hw_used;
- dma_dst = sg_dma_address(sg) + sg_used;
- } else {
- dma_src = sg_dma_address(sg) + sg_used;
- dma_dst = hw->address + hw_used;
- }
-
- /* Fill in the descriptor */
- set_desc_cnt(chan, &new->hw, copy);
- set_desc_src(chan, &new->hw, dma_src);
- set_desc_dst(chan, &new->hw, dma_dst);
-
- /*
- * If this is not the first descriptor, chain the
- * current descriptor after the previous descriptor
- */
- if (!first) {
- first = new;
- } else {
- set_desc_next(chan, &prev->hw,
- new->async_tx.phys);
- }
-
- new->async_tx.cookie = 0;
- async_tx_ack(&new->async_tx);
-
- prev = new;
- sg_used += copy;
- hw_used += copy;
-
- /* Insert the link descriptor into the LD ring */
- list_add_tail(&new->node, &first->tx_list);
- }
- }
+ set_desc_cnt(chan, &new->hw, len);
+ set_desc_src(chan, &new->hw, src);
+ set_desc_dst(chan, &new->hw, dst);
-finished:
+ if (!first)
+ first = new;
+ else
+ set_desc_next(chan, &prev->hw, new->async_tx.phys);
- /* All of the hardware address/length pairs had length == 0 */
- if (!first || !new)
- return NULL;
+ new->async_tx.cookie = 0;
+ async_tx_ack(&new->async_tx);
+ prev = new;
- new->async_tx.flags = flags;
- new->async_tx.cookie = -EBUSY;
+ /* Insert the link descriptor to the LD ring */
+ list_add_tail(&new->node, &first->tx_list);
- /* Set End-of-link to the last link descriptor of new list */
- set_ld_eol(chan, new);
+ /* update metadata */
+ dst_avail -= len;
+ src_avail -= len;
+
+fetch:
+ /* fetch the next dst scatterlist entry */
+ if (dst_avail == 0) {
+
+ /* no more entries: we're done */
+ if (dst_nents == 0)
+ break;
+
+ /* fetch the next entry: if there are no more: done */
+ dst_sg = sg_next(dst_sg);
+ if (dst_sg == NULL)
+ break;
+
+ dst_nents--;
+ dst_avail = sg_dma_len(dst_sg);
+ }
- /* Enable extra controller features */
- if (chan->set_src_loop_size)
- chan->set_src_loop_size(chan, slave->src_loop_size);
+ /* fetch the next src scatterlist entry */
+ if (src_avail == 0) {
- if (chan->set_dst_loop_size)
- chan->set_dst_loop_size(chan, slave->dst_loop_size);
+ /* no more entries: we're done */
+ if (src_nents == 0)
+ break;
- if (chan->toggle_ext_start)
- chan->toggle_ext_start(chan, slave->external_start);
+ /* fetch the next entry: if there are no more: done */
+ src_sg = sg_next(src_sg);
+ if (src_sg == NULL)
+ break;
- if (chan->toggle_ext_pause)
- chan->toggle_ext_pause(chan, slave->external_pause);
+ src_nents--;
+ src_avail = sg_dma_len(src_sg);
+ }
+ }
- if (chan->set_request_count)
- chan->set_request_count(chan, slave->request_count);
+ new->async_tx.flags = flags; /* client is in control of this ack */
+ new->async_tx.cookie = -EBUSY;
+
+ /* Set End-of-link to the last link descriptor of new list */
+ set_ld_eol(chan, new);
return &first->async_tx;
fail:
- /* If first was not set, then we failed to allocate the very first
- * descriptor, and we're done */
if (!first)
return NULL;
+ fsldma_free_desc_list_reverse(chan, &first->tx_list);
+ return NULL;
+}
+
+/**
+ * fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
+ * @chan: DMA channel
+ * @sgl: scatterlist to transfer to/from
+ * @sg_len: number of entries in @scatterlist
+ * @direction: DMA direction
+ * @flags: DMAEngine flags
+ *
+ * Prepare a set of descriptors for a DMA_SLAVE transaction. Following the
+ * DMA_SLAVE API, this gets the device-specific information from the
+ * chan->private variable.
+ */
+static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
+ struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
+ enum dma_data_direction direction, unsigned long flags)
+{
/*
- * First is set, so all of the descriptors we allocated have been added
- * to first->tx_list, INCLUDING "first" itself. Therefore we
- * must traverse the list backwards freeing each descriptor in turn
+ * This operation is not supported on the Freescale DMA controller
*
- * We're re-using variables for the loop, oh well
+ * However, we need to provide the function pointer to allow the
+ * device_control() method to work.
*/
- fsldma_free_desc_list_reverse(chan, &first->tx_list);
return NULL;
}
static int fsl_dma_device_control(struct dma_chan *dchan,
enum dma_ctrl_cmd cmd, unsigned long arg)
{
+ struct dma_slave_config *config;
struct fsldma_chan *chan;
unsigned long flags;
-
- /* Only supports DMA_TERMINATE_ALL */
- if (cmd != DMA_TERMINATE_ALL)
- return -ENXIO;
+ int size;
if (!dchan)
return -EINVAL;
chan = to_fsl_chan(dchan);
- /* Halt the DMA engine */
- dma_halt(chan);
+ switch (cmd) {
+ case DMA_TERMINATE_ALL:
+ /* Halt the DMA engine */
+ dma_halt(chan);
- spin_lock_irqsave(&chan->desc_lock, flags);
+ spin_lock_irqsave(&chan->desc_lock, flags);
- /* Remove and free all of the descriptors in the LD queue */
- fsldma_free_desc_list(chan, &chan->ld_pending);
- fsldma_free_desc_list(chan, &chan->ld_running);
+ /* Remove and free all of the descriptors in the LD queue */
+ fsldma_free_desc_list(chan, &chan->ld_pending);
+ fsldma_free_desc_list(chan, &chan->ld_running);
- spin_unlock_irqrestore(&chan->desc_lock, flags);
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
+ return 0;
+
+ case DMA_SLAVE_CONFIG:
+ config = (struct dma_slave_config *)arg;
+
+ /* make sure the channel supports setting burst size */
+ if (!chan->set_request_count)
+ return -ENXIO;
+
+ /* we set the controller burst size depending on direction */
+ if (config->direction == DMA_TO_DEVICE)
+ size = config->dst_addr_width * config->dst_maxburst;
+ else
+ size = config->src_addr_width * config->src_maxburst;
+
+ chan->set_request_count(chan, size);
+ return 0;
+
+ case FSLDMA_EXTERNAL_START:
+
+ /* make sure the channel supports external start */
+ if (!chan->toggle_ext_start)
+ return -ENXIO;
+
+ chan->toggle_ext_start(chan, arg);
+ return 0;
+
+ default:
+ return -ENXIO;
+ }
return 0;
}
@@ -1327,11 +1309,13 @@ static int __devinit fsldma_of_probe(struct platform_device *op,
dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask);
+ dma_cap_set(DMA_SG, fdev->common.cap_mask);
dma_cap_set(DMA_SLAVE, fdev->common.cap_mask);
fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources;
fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources;
fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt;
fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy;
+ fdev->common.device_prep_dma_sg = fsl_dma_prep_sg;
fdev->common.device_tx_status = fsl_tx_status;
fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending;
fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg;
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
new file mode 100644
index 000000000000..f629e4961af5
--- /dev/null
+++ b/drivers/dma/imx-dma.c
@@ -0,0 +1,424 @@
+/*
+ * drivers/dma/imx-dma.c
+ *
+ * This file contains a driver for the Freescale i.MX DMA engine
+ * found on i.MX1/21/27
+ *
+ * Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+
+#include <asm/irq.h>
+#include <mach/dma-v1.h>
+#include <mach/hardware.h>
+
+struct imxdma_channel {
+ struct imxdma_engine *imxdma;
+ unsigned int channel;
+ unsigned int imxdma_channel;
+
+ enum dma_slave_buswidth word_size;
+ dma_addr_t per_address;
+ u32 watermark_level;
+ struct dma_chan chan;
+ spinlock_t lock;
+ struct dma_async_tx_descriptor desc;
+ dma_cookie_t last_completed;
+ enum dma_status status;
+ int dma_request;
+ struct scatterlist *sg_list;
+};
+
+#define MAX_DMA_CHANNELS 8
+
+struct imxdma_engine {
+ struct device *dev;
+ struct dma_device dma_device;
+ struct imxdma_channel channel[MAX_DMA_CHANNELS];
+};
+
+static struct imxdma_channel *to_imxdma_chan(struct dma_chan *chan)
+{
+ return container_of(chan, struct imxdma_channel, chan);
+}
+
+static void imxdma_handle(struct imxdma_channel *imxdmac)
+{
+ if (imxdmac->desc.callback)
+ imxdmac->desc.callback(imxdmac->desc.callback_param);
+ imxdmac->last_completed = imxdmac->desc.cookie;
+}
+
+static void imxdma_irq_handler(int channel, void *data)
+{
+ struct imxdma_channel *imxdmac = data;
+
+ imxdmac->status = DMA_SUCCESS;
+ imxdma_handle(imxdmac);
+}
+
+static void imxdma_err_handler(int channel, void *data, int error)
+{
+ struct imxdma_channel *imxdmac = data;
+
+ imxdmac->status = DMA_ERROR;
+ imxdma_handle(imxdmac);
+}
+
+static void imxdma_progression(int channel, void *data,
+ struct scatterlist *sg)
+{
+ struct imxdma_channel *imxdmac = data;
+
+ imxdmac->status = DMA_SUCCESS;
+ imxdma_handle(imxdmac);
+}
+
+static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+ struct dma_slave_config *dmaengine_cfg = (void *)arg;
+ int ret;
+ unsigned int mode = 0;
+
+ switch (cmd) {
+ case DMA_TERMINATE_ALL:
+ imxdmac->status = DMA_ERROR;
+ imx_dma_disable(imxdmac->imxdma_channel);
+ return 0;
+ case DMA_SLAVE_CONFIG:
+ if (dmaengine_cfg->direction == DMA_FROM_DEVICE) {
+ imxdmac->per_address = dmaengine_cfg->src_addr;
+ imxdmac->watermark_level = dmaengine_cfg->src_maxburst;
+ imxdmac->word_size = dmaengine_cfg->src_addr_width;
+ } else {
+ imxdmac->per_address = dmaengine_cfg->dst_addr;
+ imxdmac->watermark_level = dmaengine_cfg->dst_maxburst;
+ imxdmac->word_size = dmaengine_cfg->dst_addr_width;
+ }
+
+ switch (imxdmac->word_size) {
+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
+ mode = IMX_DMA_MEMSIZE_8;
+ break;
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
+ mode = IMX_DMA_MEMSIZE_16;
+ break;
+ default:
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ mode = IMX_DMA_MEMSIZE_32;
+ break;
+ }
+ ret = imx_dma_config_channel(imxdmac->imxdma_channel,
+ mode | IMX_DMA_TYPE_FIFO,
+ IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
+ imxdmac->dma_request, 1);
+
+ if (ret)
+ return ret;
+
+ imx_dma_config_burstlen(imxdmac->imxdma_channel, imxdmac->watermark_level);
+
+ return 0;
+ default:
+ return -ENOSYS;
+ }
+
+ return -EINVAL;
+}
+
+static enum dma_status imxdma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+ dma_cookie_t last_used;
+ enum dma_status ret;
+
+ last_used = chan->cookie;
+
+ ret = dma_async_is_complete(cookie, imxdmac->last_completed, last_used);
+ dma_set_tx_state(txstate, imxdmac->last_completed, last_used, 0);
+
+ return ret;
+}
+
+static dma_cookie_t imxdma_assign_cookie(struct imxdma_channel *imxdma)
+{
+ dma_cookie_t cookie = imxdma->chan.cookie;
+
+ if (++cookie < 0)
+ cookie = 1;
+
+ imxdma->chan.cookie = cookie;
+ imxdma->desc.cookie = cookie;
+
+ return cookie;
+}
+
+static dma_cookie_t imxdma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct imxdma_channel *imxdmac = to_imxdma_chan(tx->chan);
+ dma_cookie_t cookie;
+
+ spin_lock_irq(&imxdmac->lock);
+
+ cookie = imxdma_assign_cookie(imxdmac);
+
+ imx_dma_enable(imxdmac->imxdma_channel);
+
+ spin_unlock_irq(&imxdmac->lock);
+
+ return cookie;
+}
+
+static int imxdma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+ struct imx_dma_data *data = chan->private;
+
+ imxdmac->dma_request = data->dma_request;
+
+ dma_async_tx_descriptor_init(&imxdmac->desc, chan);
+ imxdmac->desc.tx_submit = imxdma_tx_submit;
+ /* txd.flags will be overwritten in prep funcs */
+ imxdmac->desc.flags = DMA_CTRL_ACK;
+
+ imxdmac->status = DMA_SUCCESS;
+
+ return 0;
+}
+
+static void imxdma_free_chan_resources(struct dma_chan *chan)
+{
+ struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+
+ imx_dma_disable(imxdmac->imxdma_channel);
+
+ if (imxdmac->sg_list) {
+ kfree(imxdmac->sg_list);
+ imxdmac->sg_list = NULL;
+ }
+}
+
+static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_data_direction direction,
+ unsigned long flags)
+{
+ struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+ struct scatterlist *sg;
+ int i, ret, dma_length = 0;
+ unsigned int dmamode;
+
+ if (imxdmac->status == DMA_IN_PROGRESS)
+ return NULL;
+
+ imxdmac->status = DMA_IN_PROGRESS;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ dma_length += sg->length;
+ }
+
+ if (direction == DMA_FROM_DEVICE)
+ dmamode = DMA_MODE_READ;
+ else
+ dmamode = DMA_MODE_WRITE;
+
+ ret = imx_dma_setup_sg(imxdmac->imxdma_channel, sgl, sg_len,
+ dma_length, imxdmac->per_address, dmamode);
+ if (ret)
+ return NULL;
+
+ return &imxdmac->desc;
+}
+
+static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
+ struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+ size_t period_len, enum dma_data_direction direction)
+{
+ struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+ struct imxdma_engine *imxdma = imxdmac->imxdma;
+ int i, ret;
+ unsigned int periods = buf_len / period_len;
+ unsigned int dmamode;
+
+ dev_dbg(imxdma->dev, "%s channel: %d buf_len=%d period_len=%d\n",
+ __func__, imxdmac->channel, buf_len, period_len);
+
+ if (imxdmac->status == DMA_IN_PROGRESS)
+ return NULL;
+ imxdmac->status = DMA_IN_PROGRESS;
+
+ ret = imx_dma_setup_progression_handler(imxdmac->imxdma_channel,
+ imxdma_progression);
+ if (ret) {
+ dev_err(imxdma->dev, "Failed to setup the DMA handler\n");
+ return NULL;
+ }
+
+ if (imxdmac->sg_list)
+ kfree(imxdmac->sg_list);
+
+ imxdmac->sg_list = kcalloc(periods + 1,
+ sizeof(struct scatterlist), GFP_KERNEL);
+ if (!imxdmac->sg_list)
+ return NULL;
+
+ sg_init_table(imxdmac->sg_list, periods);
+
+ for (i = 0; i < periods; i++) {
+ imxdmac->sg_list[i].page_link = 0;
+ imxdmac->sg_list[i].offset = 0;
+ imxdmac->sg_list[i].dma_address = dma_addr;
+ imxdmac->sg_list[i].length = period_len;
+ dma_addr += period_len;
+ }
+
+ /* close the loop */
+ imxdmac->sg_list[periods].offset = 0;
+ imxdmac->sg_list[periods].length = 0;
+ imxdmac->sg_list[periods].page_link =
+ ((unsigned long)imxdmac->sg_list | 0x01) & ~0x02;
+
+ if (direction == DMA_FROM_DEVICE)
+ dmamode = DMA_MODE_READ;
+ else
+ dmamode = DMA_MODE_WRITE;
+
+ ret = imx_dma_setup_sg(imxdmac->imxdma_channel, imxdmac->sg_list, periods,
+ IMX_DMA_LENGTH_LOOP, imxdmac->per_address, dmamode);
+ if (ret)
+ return NULL;
+
+ return &imxdmac->desc;
+}
+
+static void imxdma_issue_pending(struct dma_chan *chan)
+{
+ /*
+ * Nothing to do. We only have a single descriptor
+ */
+}
+
+static int __init imxdma_probe(struct platform_device *pdev)
+{
+ struct imxdma_engine *imxdma;
+ int ret, i;
+
+ imxdma = kzalloc(sizeof(*imxdma), GFP_KERNEL);
+ if (!imxdma)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&imxdma->dma_device.channels);
+
+ /* Initialize channel parameters */
+ for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+ struct imxdma_channel *imxdmac = &imxdma->channel[i];
+
+ imxdmac->imxdma_channel = imx_dma_request_by_prio("dmaengine",
+ DMA_PRIO_MEDIUM);
+ if ((int)imxdmac->channel < 0) {
+ ret = -ENODEV;
+ goto err_init;
+ }
+
+ imx_dma_setup_handlers(imxdmac->imxdma_channel,
+ imxdma_irq_handler, imxdma_err_handler, imxdmac);
+
+ imxdmac->imxdma = imxdma;
+ spin_lock_init(&imxdmac->lock);
+
+ dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask);
+ dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask);
+
+ imxdmac->chan.device = &imxdma->dma_device;
+ imxdmac->chan.chan_id = i;
+ imxdmac->channel = i;
+
+ /* Add the channel to the DMAC list */
+ list_add_tail(&imxdmac->chan.device_node, &imxdma->dma_device.channels);
+ }
+
+ imxdma->dev = &pdev->dev;
+ imxdma->dma_device.dev = &pdev->dev;
+
+ imxdma->dma_device.device_alloc_chan_resources = imxdma_alloc_chan_resources;
+ imxdma->dma_device.device_free_chan_resources = imxdma_free_chan_resources;
+ imxdma->dma_device.device_tx_status = imxdma_tx_status;
+ imxdma->dma_device.device_prep_slave_sg = imxdma_prep_slave_sg;
+ imxdma->dma_device.device_prep_dma_cyclic = imxdma_prep_dma_cyclic;
+ imxdma->dma_device.device_control = imxdma_control;
+ imxdma->dma_device.device_issue_pending = imxdma_issue_pending;
+
+ platform_set_drvdata(pdev, imxdma);
+
+ ret = dma_async_device_register(&imxdma->dma_device);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to register\n");
+ goto err_init;
+ }
+
+ return 0;
+
+err_init:
+ while (i-- >= 0) {
+ struct imxdma_channel *imxdmac = &imxdma->channel[i];
+ imx_dma_free(imxdmac->imxdma_channel);
+ }
+
+ kfree(imxdma);
+ return ret;
+}
+
+static int __exit imxdma_remove(struct platform_device *pdev)
+{
+ struct imxdma_engine *imxdma = platform_get_drvdata(pdev);
+ int i;
+
+ dma_async_device_unregister(&imxdma->dma_device);
+
+ for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+ struct imxdma_channel *imxdmac = &imxdma->channel[i];
+
+ imx_dma_free(imxdmac->imxdma_channel);
+ }
+
+ kfree(imxdma);
+
+ return 0;
+}
+
+static struct platform_driver imxdma_driver = {
+ .driver = {
+ .name = "imx-dma",
+ },
+ .remove = __exit_p(imxdma_remove),
+};
+
+static int __init imxdma_module_init(void)
+{
+ return platform_driver_probe(&imxdma_driver, imxdma_probe);
+}
+subsys_initcall(imxdma_module_init);
+
+MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("i.MX dma driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
new file mode 100644
index 000000000000..0834323a0599
--- /dev/null
+++ b/drivers/dma/imx-sdma.c
@@ -0,0 +1,1392 @@
+/*
+ * drivers/dma/imx-sdma.c
+ *
+ * This file contains a driver for the Freescale Smart DMA engine
+ *
+ * Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ *
+ * Based on code from Freescale:
+ *
+ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+
+#include <asm/irq.h>
+#include <mach/sdma.h>
+#include <mach/dma.h>
+#include <mach/hardware.h>
+
+/* SDMA registers */
+#define SDMA_H_C0PTR 0x000
+#define SDMA_H_INTR 0x004
+#define SDMA_H_STATSTOP 0x008
+#define SDMA_H_START 0x00c
+#define SDMA_H_EVTOVR 0x010
+#define SDMA_H_DSPOVR 0x014
+#define SDMA_H_HOSTOVR 0x018
+#define SDMA_H_EVTPEND 0x01c
+#define SDMA_H_DSPENBL 0x020
+#define SDMA_H_RESET 0x024
+#define SDMA_H_EVTERR 0x028
+#define SDMA_H_INTRMSK 0x02c
+#define SDMA_H_PSW 0x030
+#define SDMA_H_EVTERRDBG 0x034
+#define SDMA_H_CONFIG 0x038
+#define SDMA_ONCE_ENB 0x040
+#define SDMA_ONCE_DATA 0x044
+#define SDMA_ONCE_INSTR 0x048
+#define SDMA_ONCE_STAT 0x04c
+#define SDMA_ONCE_CMD 0x050
+#define SDMA_EVT_MIRROR 0x054
+#define SDMA_ILLINSTADDR 0x058
+#define SDMA_CHN0ADDR 0x05c
+#define SDMA_ONCE_RTB 0x060
+#define SDMA_XTRIG_CONF1 0x070
+#define SDMA_XTRIG_CONF2 0x074
+#define SDMA_CHNENBL0_V2 0x200
+#define SDMA_CHNENBL0_V1 0x080
+#define SDMA_CHNPRI_0 0x100
+
+/*
+ * Buffer descriptor status values.
+ */
+#define BD_DONE 0x01
+#define BD_WRAP 0x02
+#define BD_CONT 0x04
+#define BD_INTR 0x08
+#define BD_RROR 0x10
+#define BD_LAST 0x20
+#define BD_EXTD 0x80
+
+/*
+ * Data Node descriptor status values.
+ */
+#define DND_END_OF_FRAME 0x80
+#define DND_END_OF_XFER 0x40
+#define DND_DONE 0x20
+#define DND_UNUSED 0x01
+
+/*
+ * IPCV2 descriptor status values.
+ */
+#define BD_IPCV2_END_OF_FRAME 0x40
+
+#define IPCV2_MAX_NODES 50
+/*
+ * Error bit set in the CCB status field by the SDMA,
+ * in setbd routine, in case of a transfer error
+ */
+#define DATA_ERROR 0x10000000
+
+/*
+ * Buffer descriptor commands.
+ */
+#define C0_ADDR 0x01
+#define C0_LOAD 0x02
+#define C0_DUMP 0x03
+#define C0_SETCTX 0x07
+#define C0_GETCTX 0x03
+#define C0_SETDM 0x01
+#define C0_SETPM 0x04
+#define C0_GETDM 0x02
+#define C0_GETPM 0x08
+/*
+ * Change endianness indicator in the BD command field
+ */
+#define CHANGE_ENDIANNESS 0x80
+
+/*
+ * Mode/Count of data node descriptors - IPCv2
+ */
+struct sdma_mode_count {
+ u32 count : 16; /* size of the buffer pointed by this BD */
+ u32 status : 8; /* E,R,I,C,W,D status bits stored here */
+ u32 command : 8; /* command mostlky used for channel 0 */
+};
+
+/*
+ * Buffer descriptor
+ */
+struct sdma_buffer_descriptor {
+ struct sdma_mode_count mode;
+ u32 buffer_addr; /* address of the buffer described */
+ u32 ext_buffer_addr; /* extended buffer address */
+} __attribute__ ((packed));
+
+/**
+ * struct sdma_channel_control - Channel control Block
+ *
+ * @current_bd_ptr current buffer descriptor processed
+ * @base_bd_ptr first element of buffer descriptor array
+ * @unused padding. The SDMA engine expects an array of 128 byte
+ * control blocks
+ */
+struct sdma_channel_control {
+ u32 current_bd_ptr;
+ u32 base_bd_ptr;
+ u32 unused[2];
+} __attribute__ ((packed));
+
+/**
+ * struct sdma_state_registers - SDMA context for a channel
+ *
+ * @pc: program counter
+ * @t: test bit: status of arithmetic & test instruction
+ * @rpc: return program counter
+ * @sf: source fault while loading data
+ * @spc: loop start program counter
+ * @df: destination fault while storing data
+ * @epc: loop end program counter
+ * @lm: loop mode
+ */
+struct sdma_state_registers {
+ u32 pc :14;
+ u32 unused1: 1;
+ u32 t : 1;
+ u32 rpc :14;
+ u32 unused0: 1;
+ u32 sf : 1;
+ u32 spc :14;
+ u32 unused2: 1;
+ u32 df : 1;
+ u32 epc :14;
+ u32 lm : 2;
+} __attribute__ ((packed));
+
+/**
+ * struct sdma_context_data - sdma context specific to a channel
+ *
+ * @channel_state: channel state bits
+ * @gReg: general registers
+ * @mda: burst dma destination address register
+ * @msa: burst dma source address register
+ * @ms: burst dma status register
+ * @md: burst dma data register
+ * @pda: peripheral dma destination address register
+ * @psa: peripheral dma source address register
+ * @ps: peripheral dma status register
+ * @pd: peripheral dma data register
+ * @ca: CRC polynomial register
+ * @cs: CRC accumulator register
+ * @dda: dedicated core destination address register
+ * @dsa: dedicated core source address register
+ * @ds: dedicated core status register
+ * @dd: dedicated core data register
+ */
+struct sdma_context_data {
+ struct sdma_state_registers channel_state;
+ u32 gReg[8];
+ u32 mda;
+ u32 msa;
+ u32 ms;
+ u32 md;
+ u32 pda;
+ u32 psa;
+ u32 ps;
+ u32 pd;
+ u32 ca;
+ u32 cs;
+ u32 dda;
+ u32 dsa;
+ u32 ds;
+ u32 dd;
+ u32 scratch0;
+ u32 scratch1;
+ u32 scratch2;
+ u32 scratch3;
+ u32 scratch4;
+ u32 scratch5;
+ u32 scratch6;
+ u32 scratch7;
+} __attribute__ ((packed));
+
+#define NUM_BD (int)(PAGE_SIZE / sizeof(struct sdma_buffer_descriptor))
+
+struct sdma_engine;
+
+/**
+ * struct sdma_channel - housekeeping for a SDMA channel
+ *
+ * @sdma pointer to the SDMA engine for this channel
+ * @channel the channel number, matches dmaengine chan_id
+ * @direction transfer type. Needed for setting SDMA script
+ * @peripheral_type Peripheral type. Needed for setting SDMA script
+ * @event_id0 aka dma request line
+ * @event_id1 for channels that use 2 events
+ * @word_size peripheral access size
+ * @buf_tail ID of the buffer that was processed
+ * @done channel completion
+ * @num_bd max NUM_BD. number of descriptors currently handling
+ */
+struct sdma_channel {
+ struct sdma_engine *sdma;
+ unsigned int channel;
+ enum dma_data_direction direction;
+ enum sdma_peripheral_type peripheral_type;
+ unsigned int event_id0;
+ unsigned int event_id1;
+ enum dma_slave_buswidth word_size;
+ unsigned int buf_tail;
+ struct completion done;
+ unsigned int num_bd;
+ struct sdma_buffer_descriptor *bd;
+ dma_addr_t bd_phys;
+ unsigned int pc_from_device, pc_to_device;
+ unsigned long flags;
+ dma_addr_t per_address;
+ u32 event_mask0, event_mask1;
+ u32 watermark_level;
+ u32 shp_addr, per_addr;
+ struct dma_chan chan;
+ spinlock_t lock;
+ struct dma_async_tx_descriptor desc;
+ dma_cookie_t last_completed;
+ enum dma_status status;
+};
+
+#define IMX_DMA_SG_LOOP (1 << 0)
+
+#define MAX_DMA_CHANNELS 32
+#define MXC_SDMA_DEFAULT_PRIORITY 1
+#define MXC_SDMA_MIN_PRIORITY 1
+#define MXC_SDMA_MAX_PRIORITY 7
+
+/**
+ * struct sdma_script_start_addrs - SDMA script start pointers
+ *
+ * start addresses of the different functions in the physical
+ * address space of the SDMA engine.
+ */
+struct sdma_script_start_addrs {
+ u32 ap_2_ap_addr;
+ u32 ap_2_bp_addr;
+ u32 ap_2_ap_fixed_addr;
+ u32 bp_2_ap_addr;
+ u32 loopback_on_dsp_side_addr;
+ u32 mcu_interrupt_only_addr;
+ u32 firi_2_per_addr;
+ u32 firi_2_mcu_addr;
+ u32 per_2_firi_addr;
+ u32 mcu_2_firi_addr;
+ u32 uart_2_per_addr;
+ u32 uart_2_mcu_addr;
+ u32 per_2_app_addr;
+ u32 mcu_2_app_addr;
+ u32 per_2_per_addr;
+ u32 uartsh_2_per_addr;
+ u32 uartsh_2_mcu_addr;
+ u32 per_2_shp_addr;
+ u32 mcu_2_shp_addr;
+ u32 ata_2_mcu_addr;
+ u32 mcu_2_ata_addr;
+ u32 app_2_per_addr;
+ u32 app_2_mcu_addr;
+ u32 shp_2_per_addr;
+ u32 shp_2_mcu_addr;
+ u32 mshc_2_mcu_addr;
+ u32 mcu_2_mshc_addr;
+ u32 spdif_2_mcu_addr;
+ u32 mcu_2_spdif_addr;
+ u32 asrc_2_mcu_addr;
+ u32 ext_mem_2_ipu_addr;
+ u32 descrambler_addr;
+ u32 dptc_dvfs_addr;
+ u32 utra_addr;
+ u32 ram_code_start_addr;
+};
+
+#define SDMA_FIRMWARE_MAGIC 0x414d4453
+
+/**
+ * struct sdma_firmware_header - Layout of the firmware image
+ *
+ * @magic "SDMA"
+ * @version_major increased whenever layout of struct sdma_script_start_addrs
+ * changes.
+ * @version_minor firmware minor version (for binary compatible changes)
+ * @script_addrs_start offset of struct sdma_script_start_addrs in this image
+ * @num_script_addrs Number of script addresses in this image
+ * @ram_code_start offset of SDMA ram image in this firmware image
+ * @ram_code_size size of SDMA ram image
+ * @script_addrs Stores the start address of the SDMA scripts
+ * (in SDMA memory space)
+ */
+struct sdma_firmware_header {
+ u32 magic;
+ u32 version_major;
+ u32 version_minor;
+ u32 script_addrs_start;
+ u32 num_script_addrs;
+ u32 ram_code_start;
+ u32 ram_code_size;
+};
+
+struct sdma_engine {
+ struct device *dev;
+ struct sdma_channel channel[MAX_DMA_CHANNELS];
+ struct sdma_channel_control *channel_control;
+ void __iomem *regs;
+ unsigned int version;
+ unsigned int num_events;
+ struct sdma_context_data *context;
+ dma_addr_t context_phys;
+ struct dma_device dma_device;
+ struct clk *clk;
+ struct sdma_script_start_addrs *script_addrs;
+};
+
+#define SDMA_H_CONFIG_DSPDMA (1 << 12) /* indicates if the DSPDMA is used */
+#define SDMA_H_CONFIG_RTD_PINS (1 << 11) /* indicates if Real-Time Debug pins are enabled */
+#define SDMA_H_CONFIG_ACR (1 << 4) /* indicates if AHB freq /core freq = 2 or 1 */
+#define SDMA_H_CONFIG_CSM (3) /* indicates which context switch mode is selected*/
+
+static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event)
+{
+ u32 chnenbl0 = (sdma->version == 2 ? SDMA_CHNENBL0_V2 : SDMA_CHNENBL0_V1);
+
+ return chnenbl0 + event * 4;
+}
+
+static int sdma_config_ownership(struct sdma_channel *sdmac,
+ bool event_override, bool mcu_override, bool dsp_override)
+{
+ struct sdma_engine *sdma = sdmac->sdma;
+ int channel = sdmac->channel;
+ u32 evt, mcu, dsp;
+
+ if (event_override && mcu_override && dsp_override)
+ return -EINVAL;
+
+ evt = __raw_readl(sdma->regs + SDMA_H_EVTOVR);
+ mcu = __raw_readl(sdma->regs + SDMA_H_HOSTOVR);
+ dsp = __raw_readl(sdma->regs + SDMA_H_DSPOVR);
+
+ if (dsp_override)
+ dsp &= ~(1 << channel);
+ else
+ dsp |= (1 << channel);
+
+ if (event_override)
+ evt &= ~(1 << channel);
+ else
+ evt |= (1 << channel);
+
+ if (mcu_override)
+ mcu &= ~(1 << channel);
+ else
+ mcu |= (1 << channel);
+
+ __raw_writel(evt, sdma->regs + SDMA_H_EVTOVR);
+ __raw_writel(mcu, sdma->regs + SDMA_H_HOSTOVR);
+ __raw_writel(dsp, sdma->regs + SDMA_H_DSPOVR);
+
+ return 0;
+}
+
+/*
+ * sdma_run_channel - run a channel and wait till it's done
+ */
+static int sdma_run_channel(struct sdma_channel *sdmac)
+{
+ struct sdma_engine *sdma = sdmac->sdma;
+ int channel = sdmac->channel;
+ int ret;
+
+ init_completion(&sdmac->done);
+
+ __raw_writel(1 << channel, sdma->regs + SDMA_H_START);
+
+ ret = wait_for_completion_timeout(&sdmac->done, HZ);
+
+ return ret ? 0 : -ETIMEDOUT;
+}
+
+static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
+ u32 address)
+{
+ struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
+ void *buf_virt;
+ dma_addr_t buf_phys;
+ int ret;
+
+ buf_virt = dma_alloc_coherent(NULL,
+ size,
+ &buf_phys, GFP_KERNEL);
+ if (!buf_virt)
+ return -ENOMEM;
+
+ bd0->mode.command = C0_SETPM;
+ bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
+ bd0->mode.count = size / 2;
+ bd0->buffer_addr = buf_phys;
+ bd0->ext_buffer_addr = address;
+
+ memcpy(buf_virt, buf, size);
+
+ ret = sdma_run_channel(&sdma->channel[0]);
+
+ dma_free_coherent(NULL, size, buf_virt, buf_phys);
+
+ return ret;
+}
+
+static void sdma_event_enable(struct sdma_channel *sdmac, unsigned int event)
+{
+ struct sdma_engine *sdma = sdmac->sdma;
+ int channel = sdmac->channel;
+ u32 val;
+ u32 chnenbl = chnenbl_ofs(sdma, event);
+
+ val = __raw_readl(sdma->regs + chnenbl);
+ val |= (1 << channel);
+ __raw_writel(val, sdma->regs + chnenbl);
+}
+
+static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
+{
+ struct sdma_engine *sdma = sdmac->sdma;
+ int channel = sdmac->channel;
+ u32 chnenbl = chnenbl_ofs(sdma, event);
+ u32 val;
+
+ val = __raw_readl(sdma->regs + chnenbl);
+ val &= ~(1 << channel);
+ __raw_writel(val, sdma->regs + chnenbl);
+}
+
+static void sdma_handle_channel_loop(struct sdma_channel *sdmac)
+{
+ struct sdma_buffer_descriptor *bd;
+
+ /*
+ * loop mode. Iterate over descriptors, re-setup them and
+ * call callback function.
+ */
+ while (1) {
+ bd = &sdmac->bd[sdmac->buf_tail];
+
+ if (bd->mode.status & BD_DONE)
+ break;
+
+ if (bd->mode.status & BD_RROR)
+ sdmac->status = DMA_ERROR;
+ else
+ sdmac->status = DMA_SUCCESS;
+
+ bd->mode.status |= BD_DONE;
+ sdmac->buf_tail++;
+ sdmac->buf_tail %= sdmac->num_bd;
+
+ if (sdmac->desc.callback)
+ sdmac->desc.callback(sdmac->desc.callback_param);
+ }
+}
+
+static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
+{
+ struct sdma_buffer_descriptor *bd;
+ int i, error = 0;
+
+ /*
+ * non loop mode. Iterate over all descriptors, collect
+ * errors and call callback function
+ */
+ for (i = 0; i < sdmac->num_bd; i++) {
+ bd = &sdmac->bd[i];
+
+ if (bd->mode.status & (BD_DONE | BD_RROR))
+ error = -EIO;
+ }
+
+ if (error)
+ sdmac->status = DMA_ERROR;
+ else
+ sdmac->status = DMA_SUCCESS;
+
+ if (sdmac->desc.callback)
+ sdmac->desc.callback(sdmac->desc.callback_param);
+ sdmac->last_completed = sdmac->desc.cookie;
+}
+
+static void mxc_sdma_handle_channel(struct sdma_channel *sdmac)
+{
+ complete(&sdmac->done);
+
+ /* not interested in channel 0 interrupts */
+ if (sdmac->channel == 0)
+ return;
+
+ if (sdmac->flags & IMX_DMA_SG_LOOP)
+ sdma_handle_channel_loop(sdmac);
+ else
+ mxc_sdma_handle_channel_normal(sdmac);
+}
+
+static irqreturn_t sdma_int_handler(int irq, void *dev_id)
+{
+ struct sdma_engine *sdma = dev_id;
+ u32 stat;
+
+ stat = __raw_readl(sdma->regs + SDMA_H_INTR);
+ __raw_writel(stat, sdma->regs + SDMA_H_INTR);
+
+ while (stat) {
+ int channel = fls(stat) - 1;
+ struct sdma_channel *sdmac = &sdma->channel[channel];
+
+ mxc_sdma_handle_channel(sdmac);
+
+ stat &= ~(1 << channel);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * sets the pc of SDMA script according to the peripheral type
+ */
+static void sdma_get_pc(struct sdma_channel *sdmac,
+ enum sdma_peripheral_type peripheral_type)
+{
+ struct sdma_engine *sdma = sdmac->sdma;
+ int per_2_emi = 0, emi_2_per = 0;
+ /*
+ * These are needed once we start to support transfers between
+ * two peripherals or memory-to-memory transfers
+ */
+ int per_2_per = 0, emi_2_emi = 0;
+
+ sdmac->pc_from_device = 0;
+ sdmac->pc_to_device = 0;
+
+ switch (peripheral_type) {
+ case IMX_DMATYPE_MEMORY:
+ emi_2_emi = sdma->script_addrs->ap_2_ap_addr;
+ break;
+ case IMX_DMATYPE_DSP:
+ emi_2_per = sdma->script_addrs->bp_2_ap_addr;
+ per_2_emi = sdma->script_addrs->ap_2_bp_addr;
+ break;
+ case IMX_DMATYPE_FIRI:
+ per_2_emi = sdma->script_addrs->firi_2_mcu_addr;
+ emi_2_per = sdma->script_addrs->mcu_2_firi_addr;
+ break;
+ case IMX_DMATYPE_UART:
+ per_2_emi = sdma->script_addrs->uart_2_mcu_addr;
+ emi_2_per = sdma->script_addrs->mcu_2_app_addr;
+ break;
+ case IMX_DMATYPE_UART_SP:
+ per_2_emi = sdma->script_addrs->uartsh_2_mcu_addr;
+ emi_2_per = sdma->script_addrs->mcu_2_shp_addr;
+ break;
+ case IMX_DMATYPE_ATA:
+ per_2_emi = sdma->script_addrs->ata_2_mcu_addr;
+ emi_2_per = sdma->script_addrs->mcu_2_ata_addr;
+ break;
+ case IMX_DMATYPE_CSPI:
+ case IMX_DMATYPE_EXT:
+ case IMX_DMATYPE_SSI:
+ per_2_emi = sdma->script_addrs->app_2_mcu_addr;
+ emi_2_per = sdma->script_addrs->mcu_2_app_addr;
+ break;
+ case IMX_DMATYPE_SSI_SP:
+ case IMX_DMATYPE_MMC:
+ case IMX_DMATYPE_SDHC:
+ case IMX_DMATYPE_CSPI_SP:
+ case IMX_DMATYPE_ESAI:
+ case IMX_DMATYPE_MSHC_SP:
+ per_2_emi = sdma->script_addrs->shp_2_mcu_addr;
+ emi_2_per = sdma->script_addrs->mcu_2_shp_addr;
+ break;
+ case IMX_DMATYPE_ASRC:
+ per_2_emi = sdma->script_addrs->asrc_2_mcu_addr;
+ emi_2_per = sdma->script_addrs->asrc_2_mcu_addr;
+ per_2_per = sdma->script_addrs->per_2_per_addr;
+ break;
+ case IMX_DMATYPE_MSHC:
+ per_2_emi = sdma->script_addrs->mshc_2_mcu_addr;
+ emi_2_per = sdma->script_addrs->mcu_2_mshc_addr;
+ break;
+ case IMX_DMATYPE_CCM:
+ per_2_emi = sdma->script_addrs->dptc_dvfs_addr;
+ break;
+ case IMX_DMATYPE_SPDIF:
+ per_2_emi = sdma->script_addrs->spdif_2_mcu_addr;
+ emi_2_per = sdma->script_addrs->mcu_2_spdif_addr;
+ break;
+ case IMX_DMATYPE_IPU_MEMORY:
+ emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr;
+ break;
+ default:
+ break;
+ }
+
+ sdmac->pc_from_device = per_2_emi;
+ sdmac->pc_to_device = emi_2_per;
+}
+
+static int sdma_load_context(struct sdma_channel *sdmac)
+{
+ struct sdma_engine *sdma = sdmac->sdma;
+ int channel = sdmac->channel;
+ int load_address;
+ struct sdma_context_data *context = sdma->context;
+ struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
+ int ret;
+
+ if (sdmac->direction == DMA_FROM_DEVICE) {
+ load_address = sdmac->pc_from_device;
+ } else {
+ load_address = sdmac->pc_to_device;
+ }
+
+ if (load_address < 0)
+ return load_address;
+
+ dev_dbg(sdma->dev, "load_address = %d\n", load_address);
+ dev_dbg(sdma->dev, "wml = 0x%08x\n", sdmac->watermark_level);
+ dev_dbg(sdma->dev, "shp_addr = 0x%08x\n", sdmac->shp_addr);
+ dev_dbg(sdma->dev, "per_addr = 0x%08x\n", sdmac->per_addr);
+ dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", sdmac->event_mask0);
+ dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", sdmac->event_mask1);
+
+ memset(context, 0, sizeof(*context));
+ context->channel_state.pc = load_address;
+
+ /* Send by context the event mask,base address for peripheral
+ * and watermark level
+ */
+ context->gReg[0] = sdmac->event_mask1;
+ context->gReg[1] = sdmac->event_mask0;
+ context->gReg[2] = sdmac->per_addr;
+ context->gReg[6] = sdmac->shp_addr;
+ context->gReg[7] = sdmac->watermark_level;
+
+ bd0->mode.command = C0_SETDM;
+ bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
+ bd0->mode.count = sizeof(*context) / 4;
+ bd0->buffer_addr = sdma->context_phys;
+ bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * channel;
+
+ ret = sdma_run_channel(&sdma->channel[0]);
+
+ return ret;
+}
+
+static void sdma_disable_channel(struct sdma_channel *sdmac)
+{
+ struct sdma_engine *sdma = sdmac->sdma;
+ int channel = sdmac->channel;
+
+ __raw_writel(1 << channel, sdma->regs + SDMA_H_STATSTOP);
+ sdmac->status = DMA_ERROR;
+}
+
+static int sdma_config_channel(struct sdma_channel *sdmac)
+{
+ int ret;
+
+ sdma_disable_channel(sdmac);
+
+ sdmac->event_mask0 = 0;
+ sdmac->event_mask1 = 0;
+ sdmac->shp_addr = 0;
+ sdmac->per_addr = 0;
+
+ if (sdmac->event_id0) {
+ if (sdmac->event_id0 > 32)
+ return -EINVAL;
+ sdma_event_enable(sdmac, sdmac->event_id0);
+ }
+
+ switch (sdmac->peripheral_type) {
+ case IMX_DMATYPE_DSP:
+ sdma_config_ownership(sdmac, false, true, true);
+ break;
+ case IMX_DMATYPE_MEMORY:
+ sdma_config_ownership(sdmac, false, true, false);
+ break;
+ default:
+ sdma_config_ownership(sdmac, true, true, false);
+ break;
+ }
+
+ sdma_get_pc(sdmac, sdmac->peripheral_type);
+
+ if ((sdmac->peripheral_type != IMX_DMATYPE_MEMORY) &&
+ (sdmac->peripheral_type != IMX_DMATYPE_DSP)) {
+ /* Handle multiple event channels differently */
+ if (sdmac->event_id1) {
+ sdmac->event_mask1 = 1 << (sdmac->event_id1 % 32);
+ if (sdmac->event_id1 > 31)
+ sdmac->watermark_level |= 1 << 31;
+ sdmac->event_mask0 = 1 << (sdmac->event_id0 % 32);
+ if (sdmac->event_id0 > 31)
+ sdmac->watermark_level |= 1 << 30;
+ } else {
+ sdmac->event_mask0 = 1 << sdmac->event_id0;
+ sdmac->event_mask1 = 1 << (sdmac->event_id0 - 32);
+ }
+ /* Watermark Level */
+ sdmac->watermark_level |= sdmac->watermark_level;
+ /* Address */
+ sdmac->shp_addr = sdmac->per_address;
+ } else {
+ sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */
+ }
+
+ ret = sdma_load_context(sdmac);
+
+ return ret;
+}
+
+static int sdma_set_channel_priority(struct sdma_channel *sdmac,
+ unsigned int priority)
+{
+ struct sdma_engine *sdma = sdmac->sdma;
+ int channel = sdmac->channel;
+
+ if (priority < MXC_SDMA_MIN_PRIORITY
+ || priority > MXC_SDMA_MAX_PRIORITY) {
+ return -EINVAL;
+ }
+
+ __raw_writel(priority, sdma->regs + SDMA_CHNPRI_0 + 4 * channel);
+
+ return 0;
+}
+
+static int sdma_request_channel(struct sdma_channel *sdmac)
+{
+ struct sdma_engine *sdma = sdmac->sdma;
+ int channel = sdmac->channel;
+ int ret = -EBUSY;
+
+ sdmac->bd = dma_alloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys, GFP_KERNEL);
+ if (!sdmac->bd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memset(sdmac->bd, 0, PAGE_SIZE);
+
+ sdma->channel_control[channel].base_bd_ptr = sdmac->bd_phys;
+ sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+
+ clk_enable(sdma->clk);
+
+ sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY);
+
+ init_completion(&sdmac->done);
+
+ sdmac->buf_tail = 0;
+
+ return 0;
+out:
+
+ return ret;
+}
+
+static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
+{
+ __raw_writel(1 << channel, sdma->regs + SDMA_H_START);
+}
+
+static dma_cookie_t sdma_assign_cookie(struct sdma_channel *sdma)
+{
+ dma_cookie_t cookie = sdma->chan.cookie;
+
+ if (++cookie < 0)
+ cookie = 1;
+
+ sdma->chan.cookie = cookie;
+ sdma->desc.cookie = cookie;
+
+ return cookie;
+}
+
+static struct sdma_channel *to_sdma_chan(struct dma_chan *chan)
+{
+ return container_of(chan, struct sdma_channel, chan);
+}
+
+static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct sdma_channel *sdmac = to_sdma_chan(tx->chan);
+ struct sdma_engine *sdma = sdmac->sdma;
+ dma_cookie_t cookie;
+
+ spin_lock_irq(&sdmac->lock);
+
+ cookie = sdma_assign_cookie(sdmac);
+
+ sdma_enable_channel(sdma, tx->chan->chan_id);
+
+ spin_unlock_irq(&sdmac->lock);
+
+ return cookie;
+}
+
+static int sdma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
+ struct imx_dma_data *data = chan->private;
+ int prio, ret;
+
+ /* No need to execute this for internal channel 0 */
+ if (chan->chan_id == 0)
+ return 0;
+
+ if (!data)
+ return -EINVAL;
+
+ switch (data->priority) {
+ case DMA_PRIO_HIGH:
+ prio = 3;
+ break;
+ case DMA_PRIO_MEDIUM:
+ prio = 2;
+ break;
+ case DMA_PRIO_LOW:
+ default:
+ prio = 1;
+ break;
+ }
+
+ sdmac->peripheral_type = data->peripheral_type;
+ sdmac->event_id0 = data->dma_request;
+ ret = sdma_set_channel_priority(sdmac, prio);
+ if (ret)
+ return ret;
+
+ ret = sdma_request_channel(sdmac);
+ if (ret)
+ return ret;
+
+ dma_async_tx_descriptor_init(&sdmac->desc, chan);
+ sdmac->desc.tx_submit = sdma_tx_submit;
+ /* txd.flags will be overwritten in prep funcs */
+ sdmac->desc.flags = DMA_CTRL_ACK;
+
+ return 0;
+}
+
+static void sdma_free_chan_resources(struct dma_chan *chan)
+{
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
+ struct sdma_engine *sdma = sdmac->sdma;
+
+ sdma_disable_channel(sdmac);
+
+ if (sdmac->event_id0)
+ sdma_event_disable(sdmac, sdmac->event_id0);
+ if (sdmac->event_id1)
+ sdma_event_disable(sdmac, sdmac->event_id1);
+
+ sdmac->event_id0 = 0;
+ sdmac->event_id1 = 0;
+
+ sdma_set_channel_priority(sdmac, 0);
+
+ dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys);
+
+ clk_disable(sdma->clk);
+}
+
+static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_data_direction direction,
+ unsigned long flags)
+{
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
+ struct sdma_engine *sdma = sdmac->sdma;
+ int ret, i, count;
+ int channel = chan->chan_id;
+ struct scatterlist *sg;
+
+ if (sdmac->status == DMA_IN_PROGRESS)
+ return NULL;
+ sdmac->status = DMA_IN_PROGRESS;
+
+ sdmac->flags = 0;
+
+ dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n",
+ sg_len, channel);
+
+ sdmac->direction = direction;
+ ret = sdma_load_context(sdmac);
+ if (ret)
+ goto err_out;
+
+ if (sg_len > NUM_BD) {
+ dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
+ channel, sg_len, NUM_BD);
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
+ int param;
+
+ bd->buffer_addr = sgl->dma_address;
+
+ count = sg->length;
+
+ if (count > 0xffff) {
+ dev_err(sdma->dev, "SDMA channel %d: maximum bytes for sg entry exceeded: %d > %d\n",
+ channel, count, 0xffff);
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ bd->mode.count = count;
+
+ if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) {
+ ret = -EINVAL;
+ goto err_out;
+ }
+ if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES)
+ bd->mode.command = 0;
+ else
+ bd->mode.command = sdmac->word_size;
+
+ param = BD_DONE | BD_EXTD | BD_CONT;
+
+ if (sdmac->flags & IMX_DMA_SG_LOOP) {
+ param |= BD_INTR;
+ if (i + 1 == sg_len)
+ param |= BD_WRAP;
+ }
+
+ if (i + 1 == sg_len)
+ param |= BD_INTR;
+
+ dev_dbg(sdma->dev, "entry %d: count: %d dma: 0x%08x %s%s\n",
+ i, count, sg->dma_address,
+ param & BD_WRAP ? "wrap" : "",
+ param & BD_INTR ? " intr" : "");
+
+ bd->mode.status = param;
+ }
+
+ sdmac->num_bd = sg_len;
+ sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+
+ return &sdmac->desc;
+err_out:
+ return NULL;
+}
+
+static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
+ struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+ size_t period_len, enum dma_data_direction direction)
+{
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
+ struct sdma_engine *sdma = sdmac->sdma;
+ int num_periods = buf_len / period_len;
+ int channel = chan->chan_id;
+ int ret, i = 0, buf = 0;
+
+ dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
+
+ if (sdmac->status == DMA_IN_PROGRESS)
+ return NULL;
+
+ sdmac->status = DMA_IN_PROGRESS;
+
+ sdmac->flags |= IMX_DMA_SG_LOOP;
+ sdmac->direction = direction;
+ ret = sdma_load_context(sdmac);
+ if (ret)
+ goto err_out;
+
+ if (num_periods > NUM_BD) {
+ dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
+ channel, num_periods, NUM_BD);
+ goto err_out;
+ }
+
+ if (period_len > 0xffff) {
+ dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %d > %d\n",
+ channel, period_len, 0xffff);
+ goto err_out;
+ }
+
+ while (buf < buf_len) {
+ struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
+ int param;
+
+ bd->buffer_addr = dma_addr;
+
+ bd->mode.count = period_len;
+
+ if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES)
+ goto err_out;
+ if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES)
+ bd->mode.command = 0;
+ else
+ bd->mode.command = sdmac->word_size;
+
+ param = BD_DONE | BD_EXTD | BD_CONT | BD_INTR;
+ if (i + 1 == num_periods)
+ param |= BD_WRAP;
+
+ dev_dbg(sdma->dev, "entry %d: count: %d dma: 0x%08x %s%s\n",
+ i, period_len, dma_addr,
+ param & BD_WRAP ? "wrap" : "",
+ param & BD_INTR ? " intr" : "");
+
+ bd->mode.status = param;
+
+ dma_addr += period_len;
+ buf += period_len;
+
+ i++;
+ }
+
+ sdmac->num_bd = num_periods;
+ sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+
+ return &sdmac->desc;
+err_out:
+ sdmac->status = DMA_ERROR;
+ return NULL;
+}
+
+static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
+ struct dma_slave_config *dmaengine_cfg = (void *)arg;
+
+ switch (cmd) {
+ case DMA_TERMINATE_ALL:
+ sdma_disable_channel(sdmac);
+ return 0;
+ case DMA_SLAVE_CONFIG:
+ if (dmaengine_cfg->direction == DMA_FROM_DEVICE) {
+ sdmac->per_address = dmaengine_cfg->src_addr;
+ sdmac->watermark_level = dmaengine_cfg->src_maxburst;
+ sdmac->word_size = dmaengine_cfg->src_addr_width;
+ } else {
+ sdmac->per_address = dmaengine_cfg->dst_addr;
+ sdmac->watermark_level = dmaengine_cfg->dst_maxburst;
+ sdmac->word_size = dmaengine_cfg->dst_addr_width;
+ }
+ return sdma_config_channel(sdmac);
+ default:
+ return -ENOSYS;
+ }
+
+ return -EINVAL;
+}
+
+static enum dma_status sdma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
+ dma_cookie_t last_used;
+ enum dma_status ret;
+
+ last_used = chan->cookie;
+
+ ret = dma_async_is_complete(cookie, sdmac->last_completed, last_used);
+ dma_set_tx_state(txstate, sdmac->last_completed, last_used, 0);
+
+ return ret;
+}
+
+static void sdma_issue_pending(struct dma_chan *chan)
+{
+ /*
+ * Nothing to do. We only have a single descriptor
+ */
+}
+
+static int __init sdma_init(struct sdma_engine *sdma,
+ void *ram_code, int ram_code_size)
+{
+ int i, ret;
+ dma_addr_t ccb_phys;
+
+ switch (sdma->version) {
+ case 1:
+ sdma->num_events = 32;
+ break;
+ case 2:
+ sdma->num_events = 48;
+ break;
+ default:
+ dev_err(sdma->dev, "Unknown version %d. aborting\n", sdma->version);
+ return -ENODEV;
+ }
+
+ clk_enable(sdma->clk);
+
+ /* Be sure SDMA has not started yet */
+ __raw_writel(0, sdma->regs + SDMA_H_C0PTR);
+
+ sdma->channel_control = dma_alloc_coherent(NULL,
+ MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) +
+ sizeof(struct sdma_context_data),
+ &ccb_phys, GFP_KERNEL);
+
+ if (!sdma->channel_control) {
+ ret = -ENOMEM;
+ goto err_dma_alloc;
+ }
+
+ sdma->context = (void *)sdma->channel_control +
+ MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control);
+ sdma->context_phys = ccb_phys +
+ MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control);
+
+ /* Zero-out the CCB structures array just allocated */
+ memset(sdma->channel_control, 0,
+ MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control));
+
+ /* disable all channels */
+ for (i = 0; i < sdma->num_events; i++)
+ __raw_writel(0, sdma->regs + chnenbl_ofs(sdma, i));
+
+ /* All channels have priority 0 */
+ for (i = 0; i < MAX_DMA_CHANNELS; i++)
+ __raw_writel(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
+
+ ret = sdma_request_channel(&sdma->channel[0]);
+ if (ret)
+ goto err_dma_alloc;
+
+ sdma_config_ownership(&sdma->channel[0], false, true, false);
+
+ /* Set Command Channel (Channel Zero) */
+ __raw_writel(0x4050, sdma->regs + SDMA_CHN0ADDR);
+
+ /* Set bits of CONFIG register but with static context switching */
+ /* FIXME: Check whether to set ACR bit depending on clock ratios */
+ __raw_writel(0, sdma->regs + SDMA_H_CONFIG);
+
+ __raw_writel(ccb_phys, sdma->regs + SDMA_H_C0PTR);
+
+ /* download the RAM image for SDMA */
+ sdma_load_script(sdma, ram_code,
+ ram_code_size,
+ sdma->script_addrs->ram_code_start_addr);
+
+ /* Set bits of CONFIG register with given context switching mode */
+ __raw_writel(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
+
+ /* Initializes channel's priorities */
+ sdma_set_channel_priority(&sdma->channel[0], 7);
+
+ clk_disable(sdma->clk);
+
+ return 0;
+
+err_dma_alloc:
+ clk_disable(sdma->clk);
+ dev_err(sdma->dev, "initialisation failed with %d\n", ret);
+ return ret;
+}
+
+static int __init sdma_probe(struct platform_device *pdev)
+{
+ int ret;
+ const struct firmware *fw;
+ const struct sdma_firmware_header *header;
+ const struct sdma_script_start_addrs *addr;
+ int irq;
+ unsigned short *ram_code;
+ struct resource *iores;
+ struct sdma_platform_data *pdata = pdev->dev.platform_data;
+ char *fwname;
+ int i;
+ dma_cap_mask_t mask;
+ struct sdma_engine *sdma;
+
+ sdma = kzalloc(sizeof(*sdma), GFP_KERNEL);
+ if (!sdma)
+ return -ENOMEM;
+
+ sdma->dev = &pdev->dev;
+
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!iores || irq < 0 || !pdata) {
+ ret = -EINVAL;
+ goto err_irq;
+ }
+
+ if (!request_mem_region(iores->start, resource_size(iores), pdev->name)) {
+ ret = -EBUSY;
+ goto err_request_region;
+ }
+
+ sdma->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(sdma->clk)) {
+ ret = PTR_ERR(sdma->clk);
+ goto err_clk;
+ }
+
+ sdma->regs = ioremap(iores->start, resource_size(iores));
+ if (!sdma->regs) {
+ ret = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ ret = request_irq(irq, sdma_int_handler, 0, "sdma", sdma);
+ if (ret)
+ goto err_request_irq;
+
+ fwname = kasprintf(GFP_KERNEL, "sdma-%s-to%d.bin",
+ pdata->cpu_name, pdata->to_version);
+ if (!fwname) {
+ ret = -ENOMEM;
+ goto err_cputype;
+ }
+
+ ret = request_firmware(&fw, fwname, &pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "request firmware \"%s\" failed with %d\n",
+ fwname, ret);
+ kfree(fwname);
+ goto err_cputype;
+ }
+ kfree(fwname);
+
+ if (fw->size < sizeof(*header))
+ goto err_firmware;
+
+ header = (struct sdma_firmware_header *)fw->data;
+
+ if (header->magic != SDMA_FIRMWARE_MAGIC)
+ goto err_firmware;
+ if (header->ram_code_start + header->ram_code_size > fw->size)
+ goto err_firmware;
+
+ addr = (void *)header + header->script_addrs_start;
+ ram_code = (void *)header + header->ram_code_start;
+ sdma->script_addrs = kmalloc(sizeof(*addr), GFP_KERNEL);
+ if (!sdma->script_addrs)
+ goto err_firmware;
+ memcpy(sdma->script_addrs, addr, sizeof(*addr));
+
+ sdma->version = pdata->sdma_version;
+
+ INIT_LIST_HEAD(&sdma->dma_device.channels);
+ /* Initialize channel parameters */
+ for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+ struct sdma_channel *sdmac = &sdma->channel[i];
+
+ sdmac->sdma = sdma;
+ spin_lock_init(&sdmac->lock);
+
+ dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
+ dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
+
+ sdmac->chan.device = &sdma->dma_device;
+ sdmac->chan.chan_id = i;
+ sdmac->channel = i;
+
+ /* Add the channel to the DMAC list */
+ list_add_tail(&sdmac->chan.device_node, &sdma->dma_device.channels);
+ }
+
+ ret = sdma_init(sdma, ram_code, header->ram_code_size);
+ if (ret)
+ goto err_init;
+
+ sdma->dma_device.dev = &pdev->dev;
+
+ sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources;
+ sdma->dma_device.device_free_chan_resources = sdma_free_chan_resources;
+ sdma->dma_device.device_tx_status = sdma_tx_status;
+ sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg;
+ sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic;
+ sdma->dma_device.device_control = sdma_control;
+ sdma->dma_device.device_issue_pending = sdma_issue_pending;
+
+ ret = dma_async_device_register(&sdma->dma_device);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to register\n");
+ goto err_init;
+ }
+
+ dev_info(&pdev->dev, "initialized (firmware %d.%d)\n",
+ header->version_major,
+ header->version_minor);
+
+ /* request channel 0. This is an internal control channel
+ * to the SDMA engine and not available to clients.
+ */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_request_channel(mask, NULL, NULL);
+
+ release_firmware(fw);
+
+ return 0;
+
+err_init:
+ kfree(sdma->script_addrs);
+err_firmware:
+ release_firmware(fw);
+err_cputype:
+ free_irq(irq, sdma);
+err_request_irq:
+ iounmap(sdma->regs);
+err_ioremap:
+ clk_put(sdma->clk);
+err_clk:
+ release_mem_region(iores->start, resource_size(iores));
+err_request_region:
+err_irq:
+ kfree(sdma);
+ return 0;
+}
+
+static int __exit sdma_remove(struct platform_device *pdev)
+{
+ return -EBUSY;
+}
+
+static struct platform_driver sdma_driver = {
+ .driver = {
+ .name = "imx-sdma",
+ },
+ .remove = __exit_p(sdma_remove),
+};
+
+static int __init sdma_module_init(void)
+{
+ return platform_driver_probe(&sdma_driver, sdma_probe);
+}
+subsys_initcall(sdma_module_init);
+
+MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("i.MX SDMA driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c
index c2591e8d9b6e..338bc4eed1f3 100644
--- a/drivers/dma/intel_mid_dma.c
+++ b/drivers/dma/intel_mid_dma.c
@@ -25,6 +25,7 @@
*/
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
#include <linux/intel_mid_dma.h>
#define MAX_CHAN 4 /*max ch across controllers*/
@@ -91,13 +92,13 @@ static int get_block_ts(int len, int tx_width, int block_size)
int byte_width = 0, block_ts = 0;
switch (tx_width) {
- case LNW_DMA_WIDTH_8BIT:
+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
byte_width = 1;
break;
- case LNW_DMA_WIDTH_16BIT:
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
byte_width = 2;
break;
- case LNW_DMA_WIDTH_32BIT:
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
default:
byte_width = 4;
break;
@@ -247,16 +248,17 @@ static void midc_dostart(struct intel_mid_dma_chan *midc,
struct middma_device *mid = to_middma_device(midc->chan.device);
/* channel is idle */
- if (midc->in_use && test_ch_en(midc->dma_base, midc->ch_id)) {
+ if (midc->busy && test_ch_en(midc->dma_base, midc->ch_id)) {
/*error*/
pr_err("ERR_MDMA: channel is busy in start\n");
/* The tasklet will hopefully advance the queue... */
return;
}
-
+ midc->busy = true;
/*write registers and en*/
iowrite32(first->sar, midc->ch_regs + SAR);
iowrite32(first->dar, midc->ch_regs + DAR);
+ iowrite32(first->lli_phys, midc->ch_regs + LLP);
iowrite32(first->cfg_hi, midc->ch_regs + CFG_HIGH);
iowrite32(first->cfg_lo, midc->ch_regs + CFG_LOW);
iowrite32(first->ctl_lo, midc->ch_regs + CTL_LOW);
@@ -264,9 +266,9 @@ static void midc_dostart(struct intel_mid_dma_chan *midc,
pr_debug("MDMA:TX SAR %x,DAR %x,CFGL %x,CFGH %x,CTLH %x, CTLL %x\n",
(int)first->sar, (int)first->dar, first->cfg_hi,
first->cfg_lo, first->ctl_hi, first->ctl_lo);
+ first->status = DMA_IN_PROGRESS;
iowrite32(ENABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
- first->status = DMA_IN_PROGRESS;
}
/**
@@ -283,20 +285,36 @@ static void midc_descriptor_complete(struct intel_mid_dma_chan *midc,
{
struct dma_async_tx_descriptor *txd = &desc->txd;
dma_async_tx_callback callback_txd = NULL;
+ struct intel_mid_dma_lli *llitem;
void *param_txd = NULL;
midc->completed = txd->cookie;
callback_txd = txd->callback;
param_txd = txd->callback_param;
- list_move(&desc->desc_node, &midc->free_list);
-
+ if (desc->lli != NULL) {
+ /*clear the DONE bit of completed LLI in memory*/
+ llitem = desc->lli + desc->current_lli;
+ llitem->ctl_hi &= CLEAR_DONE;
+ if (desc->current_lli < desc->lli_length-1)
+ (desc->current_lli)++;
+ else
+ desc->current_lli = 0;
+ }
spin_unlock_bh(&midc->lock);
if (callback_txd) {
pr_debug("MDMA: TXD callback set ... calling\n");
callback_txd(param_txd);
- spin_lock_bh(&midc->lock);
- return;
+ }
+ if (midc->raw_tfr) {
+ desc->status = DMA_SUCCESS;
+ if (desc->lli != NULL) {
+ pci_pool_free(desc->lli_pool, desc->lli,
+ desc->lli_phys);
+ pci_pool_destroy(desc->lli_pool);
+ }
+ list_move(&desc->desc_node, &midc->free_list);
+ midc->busy = false;
}
spin_lock_bh(&midc->lock);
@@ -317,14 +335,89 @@ static void midc_scan_descriptors(struct middma_device *mid,
/*tx is complete*/
list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
- if (desc->status == DMA_IN_PROGRESS) {
- desc->status = DMA_SUCCESS;
+ if (desc->status == DMA_IN_PROGRESS)
midc_descriptor_complete(midc, desc);
- }
}
return;
-}
+ }
+/**
+ * midc_lli_fill_sg - Helper function to convert
+ * SG list to Linked List Items.
+ *@midc: Channel
+ *@desc: DMA descriptor
+ *@sglist: Pointer to SG list
+ *@sglen: SG list length
+ *@flags: DMA transaction flags
+ *
+ * Walk through the SG list and convert the SG list into Linked
+ * List Items (LLI).
+ */
+static int midc_lli_fill_sg(struct intel_mid_dma_chan *midc,
+ struct intel_mid_dma_desc *desc,
+ struct scatterlist *sglist,
+ unsigned int sglen,
+ unsigned int flags)
+{
+ struct intel_mid_dma_slave *mids;
+ struct scatterlist *sg;
+ dma_addr_t lli_next, sg_phy_addr;
+ struct intel_mid_dma_lli *lli_bloc_desc;
+ union intel_mid_dma_ctl_lo ctl_lo;
+ union intel_mid_dma_ctl_hi ctl_hi;
+ int i;
+ pr_debug("MDMA: Entered midc_lli_fill_sg\n");
+ mids = midc->mid_slave;
+
+ lli_bloc_desc = desc->lli;
+ lli_next = desc->lli_phys;
+
+ ctl_lo.ctl_lo = desc->ctl_lo;
+ ctl_hi.ctl_hi = desc->ctl_hi;
+ for_each_sg(sglist, sg, sglen, i) {
+ /*Populate CTL_LOW and LLI values*/
+ if (i != sglen - 1) {
+ lli_next = lli_next +
+ sizeof(struct intel_mid_dma_lli);
+ } else {
+ /*Check for circular list, otherwise terminate LLI to ZERO*/
+ if (flags & DMA_PREP_CIRCULAR_LIST) {
+ pr_debug("MDMA: LLI is configured in circular mode\n");
+ lli_next = desc->lli_phys;
+ } else {
+ lli_next = 0;
+ ctl_lo.ctlx.llp_dst_en = 0;
+ ctl_lo.ctlx.llp_src_en = 0;
+ }
+ }
+ /*Populate CTL_HI values*/
+ ctl_hi.ctlx.block_ts = get_block_ts(sg->length,
+ desc->width,
+ midc->dma->block_size);
+ /*Populate SAR and DAR values*/
+ sg_phy_addr = sg_phys(sg);
+ if (desc->dirn == DMA_TO_DEVICE) {
+ lli_bloc_desc->sar = sg_phy_addr;
+ lli_bloc_desc->dar = mids->dma_slave.dst_addr;
+ } else if (desc->dirn == DMA_FROM_DEVICE) {
+ lli_bloc_desc->sar = mids->dma_slave.src_addr;
+ lli_bloc_desc->dar = sg_phy_addr;
+ }
+ /*Copy values into block descriptor in system memroy*/
+ lli_bloc_desc->llp = lli_next;
+ lli_bloc_desc->ctl_lo = ctl_lo.ctl_lo;
+ lli_bloc_desc->ctl_hi = ctl_hi.ctl_hi;
+
+ lli_bloc_desc++;
+ }
+ /*Copy very first LLI values to descriptor*/
+ desc->ctl_lo = desc->lli->ctl_lo;
+ desc->ctl_hi = desc->lli->ctl_hi;
+ desc->sar = desc->lli->sar;
+ desc->dar = desc->lli->dar;
+
+ return 0;
+}
/*****************************************************************************
DMA engine callback Functions*/
/**
@@ -349,12 +442,12 @@ static dma_cookie_t intel_mid_dma_tx_submit(struct dma_async_tx_descriptor *tx)
desc->txd.cookie = cookie;
- if (list_empty(&midc->active_list)) {
- midc_dostart(midc, desc);
+ if (list_empty(&midc->active_list))
list_add_tail(&desc->desc_node, &midc->active_list);
- } else {
+ else
list_add_tail(&desc->desc_node, &midc->queue);
- }
+
+ midc_dostart(midc, desc);
spin_unlock_bh(&midc->lock);
return cookie;
@@ -414,6 +507,23 @@ static enum dma_status intel_mid_dma_tx_status(struct dma_chan *chan,
return ret;
}
+static int dma_slave_control(struct dma_chan *chan, unsigned long arg)
+{
+ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
+ struct dma_slave_config *slave = (struct dma_slave_config *)arg;
+ struct intel_mid_dma_slave *mid_slave;
+
+ BUG_ON(!midc);
+ BUG_ON(!slave);
+ pr_debug("MDMA: slave control called\n");
+
+ mid_slave = to_intel_mid_dma_slave(slave);
+
+ BUG_ON(!mid_slave);
+
+ midc->mid_slave = mid_slave;
+ return 0;
+}
/**
* intel_mid_dma_device_control - DMA device control
* @chan: chan for DMA control
@@ -428,49 +538,41 @@ static int intel_mid_dma_device_control(struct dma_chan *chan,
struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
struct middma_device *mid = to_middma_device(chan->device);
struct intel_mid_dma_desc *desc, *_desc;
- LIST_HEAD(list);
+ union intel_mid_dma_cfg_lo cfg_lo;
+
+ if (cmd == DMA_SLAVE_CONFIG)
+ return dma_slave_control(chan, arg);
if (cmd != DMA_TERMINATE_ALL)
return -ENXIO;
spin_lock_bh(&midc->lock);
- if (midc->in_use == false) {
+ if (midc->busy == false) {
spin_unlock_bh(&midc->lock);
return 0;
}
- list_splice_init(&midc->free_list, &list);
- midc->descs_allocated = 0;
- midc->slave = NULL;
-
+ /*Suspend and disable the channel*/
+ cfg_lo.cfg_lo = ioread32(midc->ch_regs + CFG_LOW);
+ cfg_lo.cfgx.ch_susp = 1;
+ iowrite32(cfg_lo.cfg_lo, midc->ch_regs + CFG_LOW);
+ iowrite32(DISABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
+ midc->busy = false;
/* Disable interrupts */
disable_dma_interrupt(midc);
+ midc->descs_allocated = 0;
spin_unlock_bh(&midc->lock);
- list_for_each_entry_safe(desc, _desc, &list, desc_node) {
- pr_debug("MDMA: freeing descriptor %p\n", desc);
- pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
+ list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
+ if (desc->lli != NULL) {
+ pci_pool_free(desc->lli_pool, desc->lli,
+ desc->lli_phys);
+ pci_pool_destroy(desc->lli_pool);
+ }
+ list_move(&desc->desc_node, &midc->free_list);
}
return 0;
}
-/**
- * intel_mid_dma_prep_slave_sg - Prep slave sg txn
- * @chan: chan for DMA transfer
- * @sgl: scatter gather list
- * @sg_len: length of sg txn
- * @direction: DMA transfer dirtn
- * @flags: DMA flags
- *
- * Do DMA sg txn: NOT supported now
- */
-static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
- struct dma_chan *chan, struct scatterlist *sgl,
- unsigned int sg_len, enum dma_data_direction direction,
- unsigned long flags)
-{
- /*not supported now*/
- return NULL;
-}
/**
* intel_mid_dma_prep_memcpy - Prep memcpy txn
@@ -495,23 +597,24 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
union intel_mid_dma_ctl_hi ctl_hi;
union intel_mid_dma_cfg_lo cfg_lo;
union intel_mid_dma_cfg_hi cfg_hi;
- enum intel_mid_dma_width width = 0;
+ enum dma_slave_buswidth width;
pr_debug("MDMA: Prep for memcpy\n");
- WARN_ON(!chan);
+ BUG_ON(!chan);
if (!len)
return NULL;
- mids = chan->private;
- WARN_ON(!mids);
-
midc = to_intel_mid_dma_chan(chan);
- WARN_ON(!midc);
+ BUG_ON(!midc);
+
+ mids = midc->mid_slave;
+ BUG_ON(!mids);
pr_debug("MDMA:called for DMA %x CH %d Length %zu\n",
midc->dma->pci_id, midc->ch_id, len);
pr_debug("MDMA:Cfg passed Mode %x, Dirn %x, HS %x, Width %x\n",
- mids->cfg_mode, mids->dirn, mids->hs_mode, mids->src_width);
+ mids->cfg_mode, mids->dma_slave.direction,
+ mids->hs_mode, mids->dma_slave.src_addr_width);
/*calculate CFG_LO*/
if (mids->hs_mode == LNW_DMA_SW_HS) {
@@ -530,13 +633,13 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
if (midc->dma->pimr_mask) {
cfg_hi.cfgx.protctl = 0x0; /*default value*/
cfg_hi.cfgx.fifo_mode = 1;
- if (mids->dirn == DMA_TO_DEVICE) {
+ if (mids->dma_slave.direction == DMA_TO_DEVICE) {
cfg_hi.cfgx.src_per = 0;
if (mids->device_instance == 0)
cfg_hi.cfgx.dst_per = 3;
if (mids->device_instance == 1)
cfg_hi.cfgx.dst_per = 1;
- } else if (mids->dirn == DMA_FROM_DEVICE) {
+ } else if (mids->dma_slave.direction == DMA_FROM_DEVICE) {
if (mids->device_instance == 0)
cfg_hi.cfgx.src_per = 2;
if (mids->device_instance == 1)
@@ -552,7 +655,8 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
/*calculate CTL_HI*/
ctl_hi.ctlx.reser = 0;
- width = mids->src_width;
+ ctl_hi.ctlx.done = 0;
+ width = mids->dma_slave.src_addr_width;
ctl_hi.ctlx.block_ts = get_block_ts(len, width, midc->dma->block_size);
pr_debug("MDMA:calc len %d for block size %d\n",
@@ -560,21 +664,21 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
/*calculate CTL_LO*/
ctl_lo.ctl_lo = 0;
ctl_lo.ctlx.int_en = 1;
- ctl_lo.ctlx.dst_tr_width = mids->dst_width;
- ctl_lo.ctlx.src_tr_width = mids->src_width;
- ctl_lo.ctlx.dst_msize = mids->src_msize;
- ctl_lo.ctlx.src_msize = mids->dst_msize;
+ ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width;
+ ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width;
+ ctl_lo.ctlx.dst_msize = mids->dma_slave.src_maxburst;
+ ctl_lo.ctlx.src_msize = mids->dma_slave.dst_maxburst;
if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
ctl_lo.ctlx.tt_fc = 0;
ctl_lo.ctlx.sinc = 0;
ctl_lo.ctlx.dinc = 0;
} else {
- if (mids->dirn == DMA_TO_DEVICE) {
+ if (mids->dma_slave.direction == DMA_TO_DEVICE) {
ctl_lo.ctlx.sinc = 0;
ctl_lo.ctlx.dinc = 2;
ctl_lo.ctlx.tt_fc = 1;
- } else if (mids->dirn == DMA_FROM_DEVICE) {
+ } else if (mids->dma_slave.direction == DMA_FROM_DEVICE) {
ctl_lo.ctlx.sinc = 2;
ctl_lo.ctlx.dinc = 0;
ctl_lo.ctlx.tt_fc = 2;
@@ -597,7 +701,10 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
desc->ctl_lo = ctl_lo.ctl_lo;
desc->ctl_hi = ctl_hi.ctl_hi;
desc->width = width;
- desc->dirn = mids->dirn;
+ desc->dirn = mids->dma_slave.direction;
+ desc->lli_phys = 0;
+ desc->lli = NULL;
+ desc->lli_pool = NULL;
return &desc->txd;
err_desc_get:
@@ -605,6 +712,85 @@ err_desc_get:
midc_desc_put(midc, desc);
return NULL;
}
+/**
+ * intel_mid_dma_prep_slave_sg - Prep slave sg txn
+ * @chan: chan for DMA transfer
+ * @sgl: scatter gather list
+ * @sg_len: length of sg txn
+ * @direction: DMA transfer dirtn
+ * @flags: DMA flags
+ *
+ * Prepares LLI based periphral transfer
+ */
+static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_data_direction direction,
+ unsigned long flags)
+{
+ struct intel_mid_dma_chan *midc = NULL;
+ struct intel_mid_dma_slave *mids = NULL;
+ struct intel_mid_dma_desc *desc = NULL;
+ struct dma_async_tx_descriptor *txd = NULL;
+ union intel_mid_dma_ctl_lo ctl_lo;
+
+ pr_debug("MDMA: Prep for slave SG\n");
+
+ if (!sg_len) {
+ pr_err("MDMA: Invalid SG length\n");
+ return NULL;
+ }
+ midc = to_intel_mid_dma_chan(chan);
+ BUG_ON(!midc);
+
+ mids = midc->mid_slave;
+ BUG_ON(!mids);
+
+ if (!midc->dma->pimr_mask) {
+ pr_debug("MDMA: SG list is not supported by this controller\n");
+ return NULL;
+ }
+
+ pr_debug("MDMA: SG Length = %d, direction = %d, Flags = %#lx\n",
+ sg_len, direction, flags);
+
+ txd = intel_mid_dma_prep_memcpy(chan, 0, 0, sgl->length, flags);
+ if (NULL == txd) {
+ pr_err("MDMA: Prep memcpy failed\n");
+ return NULL;
+ }
+ desc = to_intel_mid_dma_desc(txd);
+ desc->dirn = direction;
+ ctl_lo.ctl_lo = desc->ctl_lo;
+ ctl_lo.ctlx.llp_dst_en = 1;
+ ctl_lo.ctlx.llp_src_en = 1;
+ desc->ctl_lo = ctl_lo.ctl_lo;
+ desc->lli_length = sg_len;
+ desc->current_lli = 0;
+ /* DMA coherent memory pool for LLI descriptors*/
+ desc->lli_pool = pci_pool_create("intel_mid_dma_lli_pool",
+ midc->dma->pdev,
+ (sizeof(struct intel_mid_dma_lli)*sg_len),
+ 32, 0);
+ if (NULL == desc->lli_pool) {
+ pr_err("MID_DMA:LLI pool create failed\n");
+ return NULL;
+ }
+
+ desc->lli = pci_pool_alloc(desc->lli_pool, GFP_KERNEL, &desc->lli_phys);
+ if (!desc->lli) {
+ pr_err("MID_DMA: LLI alloc failed\n");
+ pci_pool_destroy(desc->lli_pool);
+ return NULL;
+ }
+
+ midc_lli_fill_sg(midc, desc, sgl, sg_len, flags);
+ if (flags & DMA_PREP_INTERRUPT) {
+ iowrite32(UNMASK_INTR_REG(midc->ch_id),
+ midc->dma_base + MASK_BLOCK);
+ pr_debug("MDMA:Enabled Block interrupt\n");
+ }
+ return &desc->txd;
+}
/**
* intel_mid_dma_free_chan_resources - Frees dma resources
@@ -618,11 +804,11 @@ static void intel_mid_dma_free_chan_resources(struct dma_chan *chan)
struct middma_device *mid = to_middma_device(chan->device);
struct intel_mid_dma_desc *desc, *_desc;
- if (true == midc->in_use) {
+ if (true == midc->busy) {
/*trying to free ch in use!!!!!*/
pr_err("ERR_MDMA: trying to free ch in use\n");
}
-
+ pm_runtime_put(&mid->pdev->dev);
spin_lock_bh(&midc->lock);
midc->descs_allocated = 0;
list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
@@ -639,6 +825,7 @@ static void intel_mid_dma_free_chan_resources(struct dma_chan *chan)
}
spin_unlock_bh(&midc->lock);
midc->in_use = false;
+ midc->busy = false;
/* Disable CH interrupts */
iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_BLOCK);
iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_ERR);
@@ -659,11 +846,20 @@ static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan)
dma_addr_t phys;
int i = 0;
+ pm_runtime_get_sync(&mid->pdev->dev);
+
+ if (mid->state == SUSPENDED) {
+ if (dma_resume(mid->pdev)) {
+ pr_err("ERR_MDMA: resume failed");
+ return -EFAULT;
+ }
+ }
/* ASSERT: channel is idle */
if (test_ch_en(mid->dma_base, midc->ch_id)) {
/*ch is not idle*/
pr_err("ERR_MDMA: ch not idle\n");
+ pm_runtime_put(&mid->pdev->dev);
return -EIO;
}
midc->completed = chan->cookie = 1;
@@ -674,6 +870,7 @@ static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan)
desc = pci_pool_alloc(mid->dma_pool, GFP_KERNEL, &phys);
if (!desc) {
pr_err("ERR_MDMA: desc failed\n");
+ pm_runtime_put(&mid->pdev->dev);
return -ENOMEM;
/*check*/
}
@@ -686,7 +883,8 @@ static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan)
list_add_tail(&desc->desc_node, &midc->free_list);
}
spin_unlock_bh(&midc->lock);
- midc->in_use = false;
+ midc->in_use = true;
+ midc->busy = false;
pr_debug("MID_DMA: Desc alloc done ret: %d desc\n", i);
return i;
}
@@ -715,7 +913,7 @@ static void dma_tasklet(unsigned long data)
{
struct middma_device *mid = NULL;
struct intel_mid_dma_chan *midc = NULL;
- u32 status;
+ u32 status, raw_tfr, raw_block;
int i;
mid = (struct middma_device *)data;
@@ -724,8 +922,9 @@ static void dma_tasklet(unsigned long data)
return;
}
pr_debug("MDMA: in tasklet for device %x\n", mid->pci_id);
- status = ioread32(mid->dma_base + RAW_TFR);
- pr_debug("MDMA:RAW_TFR %x\n", status);
+ raw_tfr = ioread32(mid->dma_base + RAW_TFR);
+ raw_block = ioread32(mid->dma_base + RAW_BLOCK);
+ status = raw_tfr | raw_block;
status &= mid->intr_mask;
while (status) {
/*txn interrupt*/
@@ -741,15 +940,23 @@ static void dma_tasklet(unsigned long data)
}
pr_debug("MDMA:Tx complete interrupt %x, Ch No %d Index %d\n",
status, midc->ch_id, i);
+ midc->raw_tfr = raw_tfr;
+ midc->raw_block = raw_block;
+ spin_lock_bh(&midc->lock);
/*clearing this interrupts first*/
iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_TFR);
- iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_BLOCK);
-
- spin_lock_bh(&midc->lock);
+ if (raw_block) {
+ iowrite32((1 << midc->ch_id),
+ mid->dma_base + CLEAR_BLOCK);
+ }
midc_scan_descriptors(mid, midc);
pr_debug("MDMA:Scan of desc... complete, unmasking\n");
iowrite32(UNMASK_INTR_REG(midc->ch_id),
mid->dma_base + MASK_TFR);
+ if (raw_block) {
+ iowrite32(UNMASK_INTR_REG(midc->ch_id),
+ mid->dma_base + MASK_BLOCK);
+ }
spin_unlock_bh(&midc->lock);
}
@@ -804,9 +1011,14 @@ static void dma_tasklet2(unsigned long data)
static irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
{
struct middma_device *mid = data;
- u32 status;
+ u32 tfr_status, err_status;
int call_tasklet = 0;
+ tfr_status = ioread32(mid->dma_base + RAW_TFR);
+ err_status = ioread32(mid->dma_base + RAW_ERR);
+ if (!tfr_status && !err_status)
+ return IRQ_NONE;
+
/*DMA Interrupt*/
pr_debug("MDMA:Got an interrupt on irq %d\n", irq);
if (!mid) {
@@ -814,19 +1026,18 @@ static irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
return -EINVAL;
}
- status = ioread32(mid->dma_base + RAW_TFR);
- pr_debug("MDMA: Status %x, Mask %x\n", status, mid->intr_mask);
- status &= mid->intr_mask;
- if (status) {
+ pr_debug("MDMA: Status %x, Mask %x\n", tfr_status, mid->intr_mask);
+ tfr_status &= mid->intr_mask;
+ if (tfr_status) {
/*need to disable intr*/
- iowrite32((status << 8), mid->dma_base + MASK_TFR);
- pr_debug("MDMA: Calling tasklet %x\n", status);
+ iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_TFR);
+ iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_BLOCK);
+ pr_debug("MDMA: Calling tasklet %x\n", tfr_status);
call_tasklet = 1;
}
- status = ioread32(mid->dma_base + RAW_ERR);
- status &= mid->intr_mask;
- if (status) {
- iowrite32(MASK_INTR_REG(status), mid->dma_base + MASK_ERR);
+ err_status &= mid->intr_mask;
+ if (err_status) {
+ iowrite32(MASK_INTR_REG(err_status), mid->dma_base + MASK_ERR);
call_tasklet = 1;
}
if (call_tasklet)
@@ -856,7 +1067,6 @@ static int mid_setup_dma(struct pci_dev *pdev)
{
struct middma_device *dma = pci_get_drvdata(pdev);
int err, i;
- unsigned int irq_level;
/* DMA coherent memory pool for DMA descriptor allocations */
dma->dma_pool = pci_pool_create("intel_mid_dma_desc_pool", pdev,
@@ -884,6 +1094,7 @@ static int mid_setup_dma(struct pci_dev *pdev)
pr_debug("MDMA:Adding %d channel for this controller\n", dma->max_chan);
/*init CH structures*/
dma->intr_mask = 0;
+ dma->state = RUNNING;
for (i = 0; i < dma->max_chan; i++) {
struct intel_mid_dma_chan *midch = &dma->ch[i];
@@ -943,7 +1154,6 @@ static int mid_setup_dma(struct pci_dev *pdev)
/*register irq */
if (dma->pimr_mask) {
- irq_level = IRQF_SHARED;
pr_debug("MDMA:Requesting irq shared for DMAC1\n");
err = request_irq(pdev->irq, intel_mid_dma_interrupt1,
IRQF_SHARED, "INTEL_MID_DMAC1", dma);
@@ -951,10 +1161,9 @@ static int mid_setup_dma(struct pci_dev *pdev)
goto err_irq;
} else {
dma->intr_mask = 0x03;
- irq_level = 0;
pr_debug("MDMA:Requesting irq for DMAC2\n");
err = request_irq(pdev->irq, intel_mid_dma_interrupt2,
- 0, "INTEL_MID_DMAC2", dma);
+ IRQF_SHARED, "INTEL_MID_DMAC2", dma);
if (0 != err)
goto err_irq;
}
@@ -1070,6 +1279,9 @@ static int __devinit intel_mid_dma_probe(struct pci_dev *pdev,
if (err)
goto err_dma;
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_allow(&pdev->dev);
return 0;
err_dma:
@@ -1104,6 +1316,85 @@ static void __devexit intel_mid_dma_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
+/* Power Management */
+/*
+* dma_suspend - PCI suspend function
+*
+* @pci: PCI device structure
+* @state: PM message
+*
+* This function is called by OS when a power event occurs
+*/
+int dma_suspend(struct pci_dev *pci, pm_message_t state)
+{
+ int i;
+ struct middma_device *device = pci_get_drvdata(pci);
+ pr_debug("MDMA: dma_suspend called\n");
+
+ for (i = 0; i < device->max_chan; i++) {
+ if (device->ch[i].in_use)
+ return -EAGAIN;
+ }
+ device->state = SUSPENDED;
+ pci_set_drvdata(pci, device);
+ pci_save_state(pci);
+ pci_disable_device(pci);
+ pci_set_power_state(pci, PCI_D3hot);
+ return 0;
+}
+
+/**
+* dma_resume - PCI resume function
+*
+* @pci: PCI device structure
+*
+* This function is called by OS when a power event occurs
+*/
+int dma_resume(struct pci_dev *pci)
+{
+ int ret;
+ struct middma_device *device = pci_get_drvdata(pci);
+
+ pr_debug("MDMA: dma_resume called\n");
+ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+ ret = pci_enable_device(pci);
+ if (ret) {
+ pr_err("MDMA: device cant be enabled for %x\n", pci->device);
+ return ret;
+ }
+ device->state = RUNNING;
+ iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
+ pci_set_drvdata(pci, device);
+ return 0;
+}
+
+static int dma_runtime_suspend(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ return dma_suspend(pci_dev, PMSG_SUSPEND);
+}
+
+static int dma_runtime_resume(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ return dma_resume(pci_dev);
+}
+
+static int dma_runtime_idle(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct middma_device *device = pci_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < device->max_chan; i++) {
+ if (device->ch[i].in_use)
+ return -EAGAIN;
+ }
+
+ return pm_schedule_suspend(dev, 0);
+}
+
/******************************************************************************
* PCI stuff
*/
@@ -1116,11 +1407,24 @@ static struct pci_device_id intel_mid_dma_ids[] = {
};
MODULE_DEVICE_TABLE(pci, intel_mid_dma_ids);
+static const struct dev_pm_ops intel_mid_dma_pm = {
+ .runtime_suspend = dma_runtime_suspend,
+ .runtime_resume = dma_runtime_resume,
+ .runtime_idle = dma_runtime_idle,
+};
+
static struct pci_driver intel_mid_dma_pci = {
.name = "Intel MID DMA",
.id_table = intel_mid_dma_ids,
.probe = intel_mid_dma_probe,
.remove = __devexit_p(intel_mid_dma_remove),
+#ifdef CONFIG_PM
+ .suspend = dma_suspend,
+ .resume = dma_resume,
+ .driver = {
+ .pm = &intel_mid_dma_pm,
+ },
+#endif
};
static int __init intel_mid_dma_init(void)
diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h
index d81aa658ab09..709fecbdde79 100644
--- a/drivers/dma/intel_mid_dma_regs.h
+++ b/drivers/dma/intel_mid_dma_regs.h
@@ -29,11 +29,12 @@
#include <linux/dmapool.h>
#include <linux/pci_ids.h>
-#define INTEL_MID_DMA_DRIVER_VERSION "1.0.5"
+#define INTEL_MID_DMA_DRIVER_VERSION "1.1.0"
#define REG_BIT0 0x00000001
#define REG_BIT8 0x00000100
-
+#define INT_MASK_WE 0x8
+#define CLEAR_DONE 0xFFFFEFFF
#define UNMASK_INTR_REG(chan_num) \
((REG_BIT0 << chan_num) | (REG_BIT8 << chan_num))
#define MASK_INTR_REG(chan_num) (REG_BIT8 << chan_num)
@@ -41,6 +42,9 @@
#define ENABLE_CHANNEL(chan_num) \
((REG_BIT0 << chan_num) | (REG_BIT8 << chan_num))
+#define DISABLE_CHANNEL(chan_num) \
+ (REG_BIT8 << chan_num)
+
#define DESCS_PER_CHANNEL 16
/*DMA Registers*/
/*registers associated with channel programming*/
@@ -50,6 +54,7 @@
/*CH X REG = (DMA_CH_SIZE)*CH_NO + REG*/
#define SAR 0x00 /* Source Address Register*/
#define DAR 0x08 /* Destination Address Register*/
+#define LLP 0x10 /* Linked List Pointer Register*/
#define CTL_LOW 0x18 /* Control Register*/
#define CTL_HIGH 0x1C /* Control Register*/
#define CFG_LOW 0x40 /* Configuration Register Low*/
@@ -112,8 +117,8 @@ union intel_mid_dma_ctl_lo {
union intel_mid_dma_ctl_hi {
struct {
u32 block_ts:12; /*block transfer size*/
- /*configured by DMAC*/
- u32 reser:20;
+ u32 done:1; /*Done - updated by DMAC*/
+ u32 reser:19; /*configured by DMAC*/
} ctlx;
u32 ctl_hi;
@@ -152,6 +157,7 @@ union intel_mid_dma_cfg_hi {
u32 cfg_hi;
};
+
/**
* struct intel_mid_dma_chan - internal mid representation of a DMA channel
* @chan: dma_chan strcture represetation for mid chan
@@ -166,7 +172,10 @@ union intel_mid_dma_cfg_hi {
* @slave: dma slave struture
* @descs_allocated: total number of decsiptors allocated
* @dma: dma device struture pointer
+ * @busy: bool representing if ch is busy (active txn) or not
* @in_use: bool representing if ch is in use or not
+ * @raw_tfr: raw trf interrupt recieved
+ * @raw_block: raw block interrupt recieved
*/
struct intel_mid_dma_chan {
struct dma_chan chan;
@@ -178,10 +187,13 @@ struct intel_mid_dma_chan {
struct list_head active_list;
struct list_head queue;
struct list_head free_list;
- struct intel_mid_dma_slave *slave;
unsigned int descs_allocated;
struct middma_device *dma;
+ bool busy;
bool in_use;
+ u32 raw_tfr;
+ u32 raw_block;
+ struct intel_mid_dma_slave *mid_slave;
};
static inline struct intel_mid_dma_chan *to_intel_mid_dma_chan(
@@ -190,6 +202,10 @@ static inline struct intel_mid_dma_chan *to_intel_mid_dma_chan(
return container_of(chan, struct intel_mid_dma_chan, chan);
}
+enum intel_mid_dma_state {
+ RUNNING = 0,
+ SUSPENDED,
+};
/**
* struct middma_device - internal representation of a DMA device
* @pdev: PCI device
@@ -205,6 +221,7 @@ static inline struct intel_mid_dma_chan *to_intel_mid_dma_chan(
* @max_chan: max number of chs supported (from drv_data)
* @block_size: Block size of DMA transfer supported (from drv_data)
* @pimr_mask: MMIO register addr for periphral interrupt (from drv_data)
+ * @state: dma PM device state
*/
struct middma_device {
struct pci_dev *pdev;
@@ -220,6 +237,7 @@ struct middma_device {
int max_chan;
int block_size;
unsigned int pimr_mask;
+ enum intel_mid_dma_state state;
};
static inline struct middma_device *to_middma_device(struct dma_device *common)
@@ -238,14 +256,27 @@ struct intel_mid_dma_desc {
u32 cfg_lo;
u32 ctl_lo;
u32 ctl_hi;
+ struct pci_pool *lli_pool;
+ struct intel_mid_dma_lli *lli;
+ dma_addr_t lli_phys;
+ unsigned int lli_length;
+ unsigned int current_lli;
dma_addr_t next;
enum dma_data_direction dirn;
enum dma_status status;
- enum intel_mid_dma_width width; /*width of DMA txn*/
+ enum dma_slave_buswidth width; /*width of DMA txn*/
enum intel_mid_dma_mode cfg_mode; /*mode configuration*/
};
+struct intel_mid_dma_lli {
+ dma_addr_t sar;
+ dma_addr_t dar;
+ dma_addr_t llp;
+ u32 ctl_lo;
+ u32 ctl_hi;
+} __attribute__ ((packed));
+
static inline int test_ch_en(void __iomem *dma, u32 ch_no)
{
u32 en_reg = ioread32(dma + DMA_CHAN_EN);
@@ -257,4 +288,14 @@ static inline struct intel_mid_dma_desc *to_intel_mid_dma_desc
{
return container_of(txd, struct intel_mid_dma_desc, txd);
}
+
+static inline struct intel_mid_dma_slave *to_intel_mid_dma_slave
+ (struct dma_slave_config *slave)
+{
+ return container_of(slave, struct intel_mid_dma_slave, dma_slave);
+}
+
+
+int dma_resume(struct pci_dev *pci);
+
#endif /*__INTEL_MID_DMAC_REGS_H__*/
diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c
index 3533948b88ba..92b679024fed 100644
--- a/drivers/dma/pch_dma.c
+++ b/drivers/dma/pch_dma.c
@@ -926,6 +926,7 @@ static void __devexit pch_dma_remove(struct pci_dev *pdev)
static const struct pci_device_id pch_dma_id_table[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_DMA_8CH), 8 },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_DMA_4CH), 4 },
+ { 0, },
};
static struct pci_driver pch_dma_driver = {
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index 17e2600a00cf..fab68a553205 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -1,11 +1,8 @@
/*
- * driver/dma/ste_dma40.c
- *
- * Copyright (C) ST-Ericsson 2007-2010
+ * Copyright (C) ST-Ericsson SA 2007-2010
+ * Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
- * Author: Per Friden <per.friden@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
- *
*/
#include <linux/kernel.h>
@@ -14,6 +11,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/err.h>
#include <plat/ste_dma40.h>
@@ -32,6 +30,11 @@
/* Hardware requirement on LCLA alignment */
#define LCLA_ALIGNMENT 0x40000
+
+/* Max number of links per event group */
+#define D40_LCLA_LINK_PER_EVENT_GRP 128
+#define D40_LCLA_END D40_LCLA_LINK_PER_EVENT_GRP
+
/* Attempts before giving up to trying to get pages that are aligned */
#define MAX_LCLA_ALLOC_ATTEMPTS 256
@@ -41,7 +44,7 @@
#define D40_ALLOC_LOG_FREE 0
/* Hardware designer of the block */
-#define D40_PERIPHID2_DESIGNER 0x8
+#define D40_HW_DESIGNER 0x8
/**
* enum 40_command - The different commands and/or statuses.
@@ -84,18 +87,17 @@ struct d40_lli_pool {
* @lli_log: Same as above but for logical channels.
* @lli_pool: The pool with two entries pre-allocated.
* @lli_len: Number of llis of current descriptor.
- * @lli_count: Number of transfered llis.
- * @lli_tx_len: Max number of LLIs per transfer, there can be
- * many transfer for one descriptor.
+ * @lli_current: Number of transfered llis.
+ * @lcla_alloc: Number of LCLA entries allocated.
* @txd: DMA engine struct. Used for among other things for communication
* during a transfer.
* @node: List entry.
- * @dir: The transfer direction of this job.
* @is_in_client_list: true if the client owns this descriptor.
+ * @is_hw_linked: true if this job will automatically be continued for
+ * the previous one.
*
* This descriptor is used for both logical and physical transfers.
*/
-
struct d40_desc {
/* LLI physical */
struct d40_phy_lli_bidir lli_phy;
@@ -104,14 +106,14 @@ struct d40_desc {
struct d40_lli_pool lli_pool;
int lli_len;
- int lli_count;
- u32 lli_tx_len;
+ int lli_current;
+ int lcla_alloc;
struct dma_async_tx_descriptor txd;
struct list_head node;
- enum dma_data_direction dir;
bool is_in_client_list;
+ bool is_hw_linked;
};
/**
@@ -123,17 +125,14 @@ struct d40_desc {
* @pages: The number of pages needed for all physical channels.
* Only used later for clean-up on error
* @lock: Lock to protect the content in this struct.
- * @alloc_map: Bitmap mapping between physical channel and LCLA entries.
- * @num_blocks: The number of entries of alloc_map. Equals to the
- * number of physical channels.
+ * @alloc_map: big map over which LCLA entry is own by which job.
*/
struct d40_lcla_pool {
void *base;
void *base_unaligned;
int pages;
spinlock_t lock;
- u32 *alloc_map;
- int num_blocks;
+ struct d40_desc **alloc_map;
};
/**
@@ -146,9 +145,7 @@ struct d40_lcla_pool {
* this physical channel. Can also be free or physically allocated.
* @allocated_dst: Same as for src but is dst.
* allocated_dst and allocated_src uses the D40_ALLOC* defines as well as
- * event line number. Both allocated_src and allocated_dst can not be
- * allocated to a physical channel, since the interrupt handler has then
- * no way of figure out which one the interrupt belongs to.
+ * event line number.
*/
struct d40_phy_res {
spinlock_t lock;
@@ -178,6 +175,7 @@ struct d40_base;
* @active: Active descriptor.
* @queue: Queued 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.
* @src_def_cfg: Default cfg register setting for src.
* @dst_def_cfg: Default cfg register setting for dst.
@@ -201,12 +199,12 @@ struct d40_chan {
struct list_head active;
struct list_head queue;
struct stedma40_chan_cfg dma_cfg;
+ bool configured;
struct d40_base *base;
/* Default register configurations */
u32 src_def_cfg;
u32 dst_def_cfg;
struct d40_def_lcsp log_def;
- struct d40_lcla_elem lcla;
struct d40_log_lli_full *lcpa;
/* Runtime reconfiguration */
dma_addr_t runtime_addr;
@@ -234,7 +232,6 @@ struct d40_chan {
* @dma_both: dma_device channels that can do both memcpy and slave transfers.
* @dma_slave: dma_device channels that can do only do slave transfers.
* @dma_memcpy: dma_device channels that can do only do memcpy transfers.
- * @phy_chans: Room for all possible physical channels in system.
* @log_chans: Room for all possible logical channels in system.
* @lookup_log_chans: Used to map interrupt number to logical channel. Points
* to log_chans entries.
@@ -340,9 +337,6 @@ static int d40_pool_lli_alloc(struct d40_desc *d40d,
align);
d40d->lli_phy.dst = PTR_ALIGN(d40d->lli_phy.src + lli_len,
align);
-
- d40d->lli_phy.src_addr = virt_to_phys(d40d->lli_phy.src);
- d40d->lli_phy.dst_addr = virt_to_phys(d40d->lli_phy.dst);
}
return 0;
@@ -357,22 +351,67 @@ static void d40_pool_lli_free(struct d40_desc *d40d)
d40d->lli_log.dst = NULL;
d40d->lli_phy.src = NULL;
d40d->lli_phy.dst = NULL;
- d40d->lli_phy.src_addr = 0;
- d40d->lli_phy.dst_addr = 0;
}
-static dma_cookie_t d40_assign_cookie(struct d40_chan *d40c,
- struct d40_desc *desc)
+static int d40_lcla_alloc_one(struct d40_chan *d40c,
+ struct d40_desc *d40d)
{
- dma_cookie_t cookie = d40c->chan.cookie;
+ unsigned long flags;
+ int i;
+ int ret = -EINVAL;
+ int p;
- if (++cookie < 0)
- cookie = 1;
+ spin_lock_irqsave(&d40c->base->lcla_pool.lock, flags);
+
+ p = d40c->phy_chan->num * D40_LCLA_LINK_PER_EVENT_GRP;
- d40c->chan.cookie = cookie;
- desc->txd.cookie = cookie;
+ /*
+ * Allocate both src and dst at the same time, therefore the half
+ * start on 1 since 0 can't be used since zero is used as end marker.
+ */
+ for (i = 1 ; i < D40_LCLA_LINK_PER_EVENT_GRP / 2; i++) {
+ if (!d40c->base->lcla_pool.alloc_map[p + i]) {
+ d40c->base->lcla_pool.alloc_map[p + i] = d40d;
+ d40d->lcla_alloc++;
+ ret = i;
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&d40c->base->lcla_pool.lock, flags);
+
+ return ret;
+}
+
+static int d40_lcla_free_all(struct d40_chan *d40c,
+ struct d40_desc *d40d)
+{
+ unsigned long flags;
+ int i;
+ int ret = -EINVAL;
+
+ if (d40c->log_num == D40_PHY_CHAN)
+ return 0;
+
+ spin_lock_irqsave(&d40c->base->lcla_pool.lock, flags);
+
+ for (i = 1 ; i < D40_LCLA_LINK_PER_EVENT_GRP / 2; i++) {
+ if (d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num *
+ D40_LCLA_LINK_PER_EVENT_GRP + i] == d40d) {
+ d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num *
+ D40_LCLA_LINK_PER_EVENT_GRP + i] = NULL;
+ d40d->lcla_alloc--;
+ if (d40d->lcla_alloc == 0) {
+ ret = 0;
+ break;
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&d40c->base->lcla_pool.lock, flags);
+
+ return ret;
- return cookie;
}
static void d40_desc_remove(struct d40_desc *d40d)
@@ -382,28 +421,35 @@ static void d40_desc_remove(struct d40_desc *d40d)
static struct d40_desc *d40_desc_get(struct d40_chan *d40c)
{
- struct d40_desc *d;
- struct d40_desc *_d;
+ struct d40_desc *desc = NULL;
if (!list_empty(&d40c->client)) {
+ struct d40_desc *d;
+ struct d40_desc *_d;
+
list_for_each_entry_safe(d, _d, &d40c->client, node)
if (async_tx_test_ack(&d->txd)) {
d40_pool_lli_free(d);
d40_desc_remove(d);
+ desc = d;
+ memset(desc, 0, sizeof(*desc));
break;
}
- } else {
- d = kmem_cache_alloc(d40c->base->desc_slab, GFP_NOWAIT);
- if (d != NULL) {
- memset(d, 0, sizeof(struct d40_desc));
- INIT_LIST_HEAD(&d->node);
- }
}
- return d;
+
+ if (!desc)
+ desc = kmem_cache_zalloc(d40c->base->desc_slab, GFP_NOWAIT);
+
+ if (desc)
+ INIT_LIST_HEAD(&desc->node);
+
+ return desc;
}
static void d40_desc_free(struct d40_chan *d40c, struct d40_desc *d40d)
{
+
+ d40_lcla_free_all(d40c, d40d);
kmem_cache_free(d40c->base->desc_slab, d40d);
}
@@ -412,6 +458,59 @@ static void d40_desc_submit(struct d40_chan *d40c, struct d40_desc *desc)
list_add_tail(&desc->node, &d40c->active);
}
+static void d40_desc_load(struct d40_chan *d40c, struct d40_desc *d40d)
+{
+ int curr_lcla = -EINVAL, next_lcla;
+
+ if (d40c->log_num == D40_PHY_CHAN) {
+ d40_phy_lli_write(d40c->base->virtbase,
+ d40c->phy_chan->num,
+ d40d->lli_phy.dst,
+ d40d->lli_phy.src);
+ d40d->lli_current = d40d->lli_len;
+ } else {
+
+ if ((d40d->lli_len - d40d->lli_current) > 1)
+ curr_lcla = d40_lcla_alloc_one(d40c, d40d);
+
+ d40_log_lli_lcpa_write(d40c->lcpa,
+ &d40d->lli_log.dst[d40d->lli_current],
+ &d40d->lli_log.src[d40d->lli_current],
+ curr_lcla);
+
+ d40d->lli_current++;
+ for (; d40d->lli_current < d40d->lli_len; d40d->lli_current++) {
+ struct d40_log_lli *lcla;
+
+ if (d40d->lli_current + 1 < d40d->lli_len)
+ next_lcla = d40_lcla_alloc_one(d40c, d40d);
+ else
+ next_lcla = -EINVAL;
+
+ lcla = d40c->base->lcla_pool.base +
+ d40c->phy_chan->num * 1024 +
+ 8 * curr_lcla * 2;
+
+ d40_log_lli_lcla_write(lcla,
+ &d40d->lli_log.dst[d40d->lli_current],
+ &d40d->lli_log.src[d40d->lli_current],
+ next_lcla);
+
+ (void) dma_map_single(d40c->base->dev, lcla,
+ 2 * sizeof(struct d40_log_lli),
+ DMA_TO_DEVICE);
+
+ curr_lcla = next_lcla;
+
+ if (curr_lcla == -EINVAL) {
+ d40d->lli_current++;
+ break;
+ }
+
+ }
+ }
+}
+
static struct d40_desc *d40_first_active_get(struct d40_chan *d40c)
{
struct d40_desc *d;
@@ -443,68 +542,26 @@ static struct d40_desc *d40_first_queued(struct d40_chan *d40c)
return d;
}
-/* Support functions for logical channels */
-
-static int d40_lcla_id_get(struct d40_chan *d40c)
+static struct d40_desc *d40_last_queued(struct d40_chan *d40c)
{
- int src_id = 0;
- int dst_id = 0;
- struct d40_log_lli *lcla_lidx_base =
- d40c->base->lcla_pool.base + d40c->phy_chan->num * 1024;
- int i;
- int lli_per_log = d40c->base->plat_data->llis_per_log;
- unsigned long flags;
-
- if (d40c->lcla.src_id >= 0 && d40c->lcla.dst_id >= 0)
- return 0;
-
- if (d40c->base->lcla_pool.num_blocks > 32)
- return -EINVAL;
-
- spin_lock_irqsave(&d40c->base->lcla_pool.lock, flags);
-
- for (i = 0; i < d40c->base->lcla_pool.num_blocks; i++) {
- if (!(d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num] &
- (0x1 << i))) {
- d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num] |=
- (0x1 << i);
- break;
- }
- }
- src_id = i;
- if (src_id >= d40c->base->lcla_pool.num_blocks)
- goto err;
+ struct d40_desc *d;
- for (; i < d40c->base->lcla_pool.num_blocks; i++) {
- if (!(d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num] &
- (0x1 << i))) {
- d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num] |=
- (0x1 << i);
+ if (list_empty(&d40c->queue))
+ return NULL;
+ list_for_each_entry(d, &d40c->queue, node)
+ if (list_is_last(&d->node, &d40c->queue))
break;
- }
- }
-
- dst_id = i;
- if (dst_id == src_id)
- goto err;
-
- d40c->lcla.src_id = src_id;
- d40c->lcla.dst_id = dst_id;
- d40c->lcla.dst = lcla_lidx_base + dst_id * lli_per_log + 1;
- d40c->lcla.src = lcla_lidx_base + src_id * lli_per_log + 1;
-
- spin_unlock_irqrestore(&d40c->base->lcla_pool.lock, flags);
- return 0;
-err:
- spin_unlock_irqrestore(&d40c->base->lcla_pool.lock, flags);
- return -EINVAL;
+ return d;
}
+/* Support functions for logical channels */
+
static int d40_channel_execute_command(struct d40_chan *d40c,
enum d40_command command)
{
- int status, i;
+ u32 status;
+ int i;
void __iomem *active_reg;
int ret = 0;
unsigned long flags;
@@ -567,35 +624,19 @@ done:
static void d40_term_all(struct d40_chan *d40c)
{
struct d40_desc *d40d;
- unsigned long flags;
/* Release active descriptors */
while ((d40d = d40_first_active_get(d40c))) {
d40_desc_remove(d40d);
-
- /* Return desc to free-list */
d40_desc_free(d40c, d40d);
}
/* Release queued descriptors waiting for transfer */
while ((d40d = d40_first_queued(d40c))) {
d40_desc_remove(d40d);
-
- /* Return desc to free-list */
d40_desc_free(d40c, d40d);
}
- spin_lock_irqsave(&d40c->base->lcla_pool.lock, flags);
-
- d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num] &=
- (~(0x1 << d40c->lcla.dst_id));
- d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num] &=
- (~(0x1 << d40c->lcla.src_id));
-
- d40c->lcla.src_id = -1;
- d40c->lcla.dst_id = -1;
-
- spin_unlock_irqrestore(&d40c->base->lcla_pool.lock, flags);
d40c->pending_tx = 0;
d40c->busy = false;
@@ -640,45 +681,47 @@ static void d40_config_set_event(struct d40_chan *d40c, bool do_enable)
static u32 d40_chan_has_events(struct d40_chan *d40c)
{
- u32 val = 0;
+ u32 val;
- /* If SSLNK or SDLNK is zero all events are disabled */
- if ((d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM) ||
- (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_PERIPH))
- val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
- d40c->phy_chan->num * D40_DREG_PCDELTA +
- D40_CHAN_REG_SSLNK);
-
- if (d40c->dma_cfg.dir != STEDMA40_PERIPH_TO_MEM)
- val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
- d40c->phy_chan->num * D40_DREG_PCDELTA +
- D40_CHAN_REG_SDLNK);
+ val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SSLNK);
+
+ val |= readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SDLNK);
return val;
}
-static void d40_config_enable_lidx(struct d40_chan *d40c)
+static u32 d40_get_prmo(struct d40_chan *d40c)
{
- /* Set LIDX for lcla */
- writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) &
- D40_SREG_ELEM_LOG_LIDX_MASK,
- d40c->base->virtbase + D40_DREG_PCBASE +
- d40c->phy_chan->num * D40_DREG_PCDELTA + D40_CHAN_REG_SDELT);
-
- writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) &
- D40_SREG_ELEM_LOG_LIDX_MASK,
- d40c->base->virtbase + D40_DREG_PCBASE +
- d40c->phy_chan->num * D40_DREG_PCDELTA + D40_CHAN_REG_SSELT);
+ static const unsigned int phy_map[] = {
+ [STEDMA40_PCHAN_BASIC_MODE]
+ = D40_DREG_PRMO_PCHAN_BASIC,
+ [STEDMA40_PCHAN_MODULO_MODE]
+ = D40_DREG_PRMO_PCHAN_MODULO,
+ [STEDMA40_PCHAN_DOUBLE_DST_MODE]
+ = D40_DREG_PRMO_PCHAN_DOUBLE_DST,
+ };
+ static const unsigned int log_map[] = {
+ [STEDMA40_LCHAN_SRC_PHY_DST_LOG]
+ = D40_DREG_PRMO_LCHAN_SRC_PHY_DST_LOG,
+ [STEDMA40_LCHAN_SRC_LOG_DST_PHY]
+ = D40_DREG_PRMO_LCHAN_SRC_LOG_DST_PHY,
+ [STEDMA40_LCHAN_SRC_LOG_DST_LOG]
+ = D40_DREG_PRMO_LCHAN_SRC_LOG_DST_LOG,
+ };
+
+ if (d40c->log_num == D40_PHY_CHAN)
+ return phy_map[d40c->dma_cfg.mode_opt];
+ else
+ return log_map[d40c->dma_cfg.mode_opt];
}
-static int d40_config_write(struct d40_chan *d40c)
+static void d40_config_write(struct d40_chan *d40c)
{
u32 addr_base;
u32 var;
- int res;
-
- res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
- if (res)
- return res;
/* Odd addresses are even addresses + 4 */
addr_base = (d40c->phy_chan->num % 2) * 4;
@@ -688,8 +731,7 @@ static int d40_config_write(struct d40_chan *d40c)
writel(var, d40c->base->virtbase + D40_DREG_PRMSE + addr_base);
/* Setup operational mode option register */
- var = ((d40c->dma_cfg.channel_type >> STEDMA40_INFO_CH_MODE_OPT_POS) &
- 0x3) << D40_CHAN_POS(d40c->phy_chan->num);
+ var = d40_get_prmo(d40c) << D40_CHAN_POS(d40c->phy_chan->num);
writel(var, d40c->base->virtbase + D40_DREG_PRMOE + addr_base);
@@ -704,41 +746,181 @@ static int d40_config_write(struct d40_chan *d40c)
d40c->phy_chan->num * D40_DREG_PCDELTA +
D40_CHAN_REG_SDCFG);
- d40_config_enable_lidx(d40c);
+ /* Set LIDX for lcla */
+ writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) &
+ D40_SREG_ELEM_LOG_LIDX_MASK,
+ d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SDELT);
+
+ writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) &
+ D40_SREG_ELEM_LOG_LIDX_MASK,
+ d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SSELT);
+
+ }
+}
+
+static u32 d40_residue(struct d40_chan *d40c)
+{
+ u32 num_elt;
+
+ if (d40c->log_num != D40_PHY_CHAN)
+ num_elt = (readl(&d40c->lcpa->lcsp2) & D40_MEM_LCSP2_ECNT_MASK)
+ >> D40_MEM_LCSP2_ECNT_POS;
+ else
+ num_elt = (readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SDELT) &
+ D40_SREG_ELEM_PHY_ECNT_MASK) >>
+ D40_SREG_ELEM_PHY_ECNT_POS;
+ return num_elt * (1 << d40c->dma_cfg.dst_info.data_width);
+}
+
+static bool d40_tx_is_linked(struct d40_chan *d40c)
+{
+ bool is_link;
+
+ if (d40c->log_num != D40_PHY_CHAN)
+ is_link = readl(&d40c->lcpa->lcsp3) & D40_MEM_LCSP3_DLOS_MASK;
+ else
+ is_link = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SDLNK) &
+ D40_SREG_LNK_PHYS_LNK_MASK;
+ return is_link;
+}
+
+static int d40_pause(struct dma_chan *chan)
+{
+ struct d40_chan *d40c =
+ container_of(chan, struct d40_chan, chan);
+ int res = 0;
+ unsigned long flags;
+
+ if (!d40c->busy)
+ return 0;
+
+ spin_lock_irqsave(&d40c->lock, flags);
+
+ res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
+ if (res == 0) {
+ if (d40c->log_num != D40_PHY_CHAN) {
+ d40_config_set_event(d40c, false);
+ /* Resume the other logical channels if any */
+ if (d40_chan_has_events(d40c))
+ res = d40_channel_execute_command(d40c,
+ D40_DMA_RUN);
+ }
}
+
+ spin_unlock_irqrestore(&d40c->lock, flags);
return res;
}
-static void d40_desc_load(struct d40_chan *d40c, struct d40_desc *d40d)
+static int d40_resume(struct dma_chan *chan)
{
- if (d40d->lli_phy.dst && d40d->lli_phy.src) {
- d40_phy_lli_write(d40c->base->virtbase,
- d40c->phy_chan->num,
- d40d->lli_phy.dst,
- d40d->lli_phy.src);
- } else if (d40d->lli_log.dst && d40d->lli_log.src) {
- struct d40_log_lli *src = d40d->lli_log.src;
- struct d40_log_lli *dst = d40d->lli_log.dst;
- int s;
-
- src += d40d->lli_count;
- dst += d40d->lli_count;
- s = d40_log_lli_write(d40c->lcpa,
- d40c->lcla.src, d40c->lcla.dst,
- dst, src,
- d40c->base->plat_data->llis_per_log);
-
- /* If s equals to zero, the job is not linked */
- if (s > 0) {
- (void) dma_map_single(d40c->base->dev, d40c->lcla.src,
- s * sizeof(struct d40_log_lli),
- DMA_TO_DEVICE);
- (void) dma_map_single(d40c->base->dev, d40c->lcla.dst,
- s * sizeof(struct d40_log_lli),
- DMA_TO_DEVICE);
+ struct d40_chan *d40c =
+ container_of(chan, struct d40_chan, chan);
+ int res = 0;
+ unsigned long flags;
+
+ if (!d40c->busy)
+ return 0;
+
+ spin_lock_irqsave(&d40c->lock, flags);
+
+ if (d40c->base->rev == 0)
+ if (d40c->log_num != D40_PHY_CHAN) {
+ res = d40_channel_execute_command(d40c,
+ D40_DMA_SUSPEND_REQ);
+ goto no_suspend;
}
+
+ /* If bytes left to transfer or linked tx resume job */
+ if (d40_residue(d40c) || d40_tx_is_linked(d40c)) {
+
+ if (d40c->log_num != D40_PHY_CHAN)
+ d40_config_set_event(d40c, true);
+
+ res = d40_channel_execute_command(d40c, D40_DMA_RUN);
+ }
+
+no_suspend:
+ spin_unlock_irqrestore(&d40c->lock, flags);
+ return res;
+}
+
+static void d40_tx_submit_log(struct d40_chan *d40c, struct d40_desc *d40d)
+{
+ /* TODO: Write */
+}
+
+static void d40_tx_submit_phy(struct d40_chan *d40c, struct d40_desc *d40d)
+{
+ struct d40_desc *d40d_prev = NULL;
+ int i;
+ u32 val;
+
+ if (!list_empty(&d40c->queue))
+ d40d_prev = d40_last_queued(d40c);
+ else if (!list_empty(&d40c->active))
+ d40d_prev = d40_first_active_get(d40c);
+
+ if (!d40d_prev)
+ return;
+
+ /* Here we try to join this job with previous jobs */
+ val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SSLNK);
+
+ /* Figure out which link we're currently transmitting */
+ for (i = 0; i < d40d_prev->lli_len; i++)
+ if (val == d40d_prev->lli_phy.src[i].reg_lnk)
+ break;
+
+ val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SSELT) >> D40_SREG_ELEM_LOG_ECNT_POS;
+
+ if (i == (d40d_prev->lli_len - 1) && val > 0) {
+ /* Change the current one */
+ writel(virt_to_phys(d40d->lli_phy.src),
+ d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SSLNK);
+ writel(virt_to_phys(d40d->lli_phy.dst),
+ d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SDLNK);
+
+ d40d->is_hw_linked = true;
+
+ } else if (i < d40d_prev->lli_len) {
+ (void) dma_unmap_single(d40c->base->dev,
+ virt_to_phys(d40d_prev->lli_phy.src),
+ d40d_prev->lli_pool.size,
+ DMA_TO_DEVICE);
+
+ /* Keep the settings */
+ val = d40d_prev->lli_phy.src[d40d_prev->lli_len - 1].reg_lnk &
+ ~D40_SREG_LNK_PHYS_LNK_MASK;
+ d40d_prev->lli_phy.src[d40d_prev->lli_len - 1].reg_lnk =
+ val | virt_to_phys(d40d->lli_phy.src);
+
+ val = d40d_prev->lli_phy.dst[d40d_prev->lli_len - 1].reg_lnk &
+ ~D40_SREG_LNK_PHYS_LNK_MASK;
+ d40d_prev->lli_phy.dst[d40d_prev->lli_len - 1].reg_lnk =
+ val | virt_to_phys(d40d->lli_phy.dst);
+
+ (void) dma_map_single(d40c->base->dev,
+ d40d_prev->lli_phy.src,
+ d40d_prev->lli_pool.size,
+ DMA_TO_DEVICE);
+ d40d->is_hw_linked = true;
}
- d40d->lli_count += d40d->lli_tx_len;
}
static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx)
@@ -749,14 +931,28 @@ static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx)
struct d40_desc *d40d = container_of(tx, struct d40_desc, txd);
unsigned long flags;
+ (void) d40_pause(&d40c->chan);
+
spin_lock_irqsave(&d40c->lock, flags);
- tx->cookie = d40_assign_cookie(d40c, d40d);
+ d40c->chan.cookie++;
+
+ if (d40c->chan.cookie < 0)
+ d40c->chan.cookie = 1;
+
+ d40d->txd.cookie = d40c->chan.cookie;
+
+ if (d40c->log_num == D40_PHY_CHAN)
+ d40_tx_submit_phy(d40c, d40d);
+ else
+ d40_tx_submit_log(d40c, d40d);
d40_desc_queue(d40c, d40d);
spin_unlock_irqrestore(&d40c->lock, flags);
+ (void) d40_resume(&d40c->chan);
+
return tx->cookie;
}
@@ -796,14 +992,21 @@ static struct d40_desc *d40_queue_start(struct d40_chan *d40c)
/* Add to active queue */
d40_desc_submit(d40c, d40d);
- /* Initiate DMA job */
- d40_desc_load(d40c, d40d);
+ /*
+ * If this job is already linked in hw,
+ * do not submit it.
+ */
- /* Start dma job */
- err = d40_start(d40c);
+ if (!d40d->is_hw_linked) {
+ /* Initiate DMA job */
+ d40_desc_load(d40c, d40d);
- if (err)
- return NULL;
+ /* Start dma job */
+ err = d40_start(d40c);
+
+ if (err)
+ return NULL;
+ }
}
return d40d;
@@ -814,17 +1017,15 @@ static void dma_tc_handle(struct d40_chan *d40c)
{
struct d40_desc *d40d;
- if (!d40c->phy_chan)
- return;
-
/* Get first active entry from list */
d40d = d40_first_active_get(d40c);
if (d40d == NULL)
return;
- if (d40d->lli_count < d40d->lli_len) {
+ d40_lcla_free_all(d40c, d40d);
+ if (d40d->lli_current < d40d->lli_len) {
d40_desc_load(d40c, d40d);
/* Start dma job */
(void) d40_start(d40c);
@@ -842,7 +1043,7 @@ static void dma_tc_handle(struct d40_chan *d40c)
static void dma_tasklet(unsigned long data)
{
struct d40_chan *d40c = (struct d40_chan *) data;
- struct d40_desc *d40d_fin;
+ struct d40_desc *d40d;
unsigned long flags;
dma_async_tx_callback callback;
void *callback_param;
@@ -850,12 +1051,12 @@ static void dma_tasklet(unsigned long data)
spin_lock_irqsave(&d40c->lock, flags);
/* Get first active entry from list */
- d40d_fin = d40_first_active_get(d40c);
+ d40d = d40_first_active_get(d40c);
- if (d40d_fin == NULL)
+ if (d40d == NULL)
goto err;
- d40c->completed = d40d_fin->txd.cookie;
+ d40c->completed = d40d->txd.cookie;
/*
* If terminating a channel pending_tx is set to zero.
@@ -867,19 +1068,19 @@ static void dma_tasklet(unsigned long data)
}
/* Callback to client */
- callback = d40d_fin->txd.callback;
- callback_param = d40d_fin->txd.callback_param;
-
- if (async_tx_test_ack(&d40d_fin->txd)) {
- d40_pool_lli_free(d40d_fin);
- d40_desc_remove(d40d_fin);
- /* Return desc to free-list */
- d40_desc_free(d40c, d40d_fin);
+ callback = d40d->txd.callback;
+ callback_param = d40d->txd.callback_param;
+
+ if (async_tx_test_ack(&d40d->txd)) {
+ d40_pool_lli_free(d40d);
+ d40_desc_remove(d40d);
+ d40_desc_free(d40c, d40d);
} else {
- if (!d40d_fin->is_in_client_list) {
- d40_desc_remove(d40d_fin);
- list_add_tail(&d40d_fin->node, &d40c->client);
- d40d_fin->is_in_client_list = true;
+ if (!d40d->is_in_client_list) {
+ d40_desc_remove(d40d);
+ d40_lcla_free_all(d40c, d40d);
+ list_add_tail(&d40d->node, &d40c->client);
+ d40d->is_in_client_list = true;
}
}
@@ -890,7 +1091,7 @@ static void dma_tasklet(unsigned long data)
spin_unlock_irqrestore(&d40c->lock, flags);
- if (callback)
+ if (callback && (d40d->txd.flags & DMA_PREP_INTERRUPT))
callback(callback_param);
return;
@@ -919,7 +1120,6 @@ static irqreturn_t d40_handle_interrupt(int irq, void *data)
int i;
u32 regs[ARRAY_SIZE(il)];
- u32 tmp;
u32 idx;
u32 row;
long chan = -1;
@@ -946,9 +1146,7 @@ static irqreturn_t d40_handle_interrupt(int irq, void *data)
idx = chan & (BITS_PER_LONG - 1);
/* ACK interrupt */
- tmp = readl(base->virtbase + il[row].clr);
- tmp |= 1 << idx;
- writel(tmp, base->virtbase + il[row].clr);
+ writel(1 << idx, base->virtbase + il[row].clr);
if (il[row].offset == D40_PHY_CHAN)
d40c = base->lookup_phy_chans[idx];
@@ -971,24 +1169,47 @@ static irqreturn_t d40_handle_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
-
static int d40_validate_conf(struct d40_chan *d40c,
struct stedma40_chan_cfg *conf)
{
int res = 0;
u32 dst_event_group = D40_TYPE_TO_GROUP(conf->dst_dev_type);
u32 src_event_group = D40_TYPE_TO_GROUP(conf->src_dev_type);
- bool is_log = (conf->channel_type & STEDMA40_CHANNEL_IN_OPER_MODE)
- == STEDMA40_CHANNEL_IN_LOG_MODE;
+ bool is_log = conf->mode == STEDMA40_MODE_LOGICAL;
+
+ if (!conf->dir) {
+ dev_err(&d40c->chan.dev->device, "[%s] Invalid direction.\n",
+ __func__);
+ res = -EINVAL;
+ }
+
+ if (conf->dst_dev_type != STEDMA40_DEV_DST_MEMORY &&
+ d40c->base->plat_data->dev_tx[conf->dst_dev_type] == 0 &&
+ d40c->runtime_addr == 0) {
+
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Invalid TX channel address (%d)\n",
+ __func__, conf->dst_dev_type);
+ res = -EINVAL;
+ }
+
+ if (conf->src_dev_type != STEDMA40_DEV_SRC_MEMORY &&
+ d40c->base->plat_data->dev_rx[conf->src_dev_type] == 0 &&
+ d40c->runtime_addr == 0) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Invalid RX channel address (%d)\n",
+ __func__, conf->src_dev_type);
+ res = -EINVAL;
+ }
- if (d40c->dma_cfg.dir == STEDMA40_MEM_TO_PERIPH &&
+ if (conf->dir == STEDMA40_MEM_TO_PERIPH &&
dst_event_group == STEDMA40_DEV_DST_MEMORY) {
dev_err(&d40c->chan.dev->device, "[%s] Invalid dst\n",
__func__);
res = -EINVAL;
}
- if (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM &&
+ if (conf->dir == STEDMA40_PERIPH_TO_MEM &&
src_event_group == STEDMA40_DEV_SRC_MEMORY) {
dev_err(&d40c->chan.dev->device, "[%s] Invalid src\n",
__func__);
@@ -1082,7 +1303,6 @@ static bool d40_alloc_mask_free(struct d40_phy_res *phy, bool is_src,
spin_lock_irqsave(&phy->lock, flags);
if (!log_event_line) {
- /* Physical interrupts are masked per physical full channel */
phy->allocated_dst = D40_ALLOC_FREE;
phy->allocated_src = D40_ALLOC_FREE;
is_free = true;
@@ -1119,10 +1339,7 @@ static int d40_allocate_channel(struct d40_chan *d40c)
int j;
int log_num;
bool is_src;
- bool is_log = (d40c->dma_cfg.channel_type &
- STEDMA40_CHANNEL_IN_OPER_MODE)
- == STEDMA40_CHANNEL_IN_LOG_MODE;
-
+ bool is_log = d40c->dma_cfg.mode == STEDMA40_MODE_LOGICAL;
phys = d40c->base->phy_res;
@@ -1251,7 +1468,6 @@ static int d40_free_dma(struct d40_chan *d40c)
list_for_each_entry_safe(d, _d, &d40c->client, node) {
d40_pool_lli_free(d);
d40_desc_remove(d);
- /* Return desc to free-list */
d40_desc_free(d40c, d);
}
@@ -1324,37 +1540,12 @@ static int d40_free_dma(struct d40_chan *d40c)
return res;
}
d40c->phy_chan = NULL;
- /* Invalidate channel type */
- d40c->dma_cfg.channel_type = 0;
+ d40c->configured = false;
d40c->base->lookup_phy_chans[phy->num] = NULL;
return 0;
}
-static int d40_pause(struct dma_chan *chan)
-{
- struct d40_chan *d40c =
- container_of(chan, struct d40_chan, chan);
- int res;
- unsigned long flags;
-
- spin_lock_irqsave(&d40c->lock, flags);
-
- res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
- if (res == 0) {
- if (d40c->log_num != D40_PHY_CHAN) {
- d40_config_set_event(d40c, false);
- /* Resume the other logical channels if any */
- if (d40_chan_has_events(d40c))
- res = d40_channel_execute_command(d40c,
- D40_DMA_RUN);
- }
- }
-
- spin_unlock_irqrestore(&d40c->lock, flags);
- return res;
-}
-
static bool d40_is_paused(struct d40_chan *d40c)
{
bool is_paused = false;
@@ -1381,16 +1572,22 @@ static bool d40_is_paused(struct d40_chan *d40c)
}
if (d40c->dma_cfg.dir == STEDMA40_MEM_TO_PERIPH ||
- d40c->dma_cfg.dir == STEDMA40_MEM_TO_MEM)
+ d40c->dma_cfg.dir == STEDMA40_MEM_TO_MEM) {
event = D40_TYPE_TO_EVENT(d40c->dma_cfg.dst_dev_type);
- else if (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM)
+ status = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SDLNK);
+ } else if (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM) {
event = D40_TYPE_TO_EVENT(d40c->dma_cfg.src_dev_type);
- else {
+ status = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+ d40c->phy_chan->num * D40_DREG_PCDELTA +
+ D40_CHAN_REG_SSLNK);
+ } else {
dev_err(&d40c->chan.dev->device,
"[%s] Unknown direction\n", __func__);
goto _exit;
}
- status = d40_chan_has_events(d40c);
+
status = (status & D40_EVENTLINE_MASK(event)) >>
D40_EVENTLINE_POS(event);
@@ -1403,64 +1600,6 @@ _exit:
}
-static bool d40_tx_is_linked(struct d40_chan *d40c)
-{
- bool is_link;
-
- if (d40c->log_num != D40_PHY_CHAN)
- is_link = readl(&d40c->lcpa->lcsp3) & D40_MEM_LCSP3_DLOS_MASK;
- else
- is_link = readl(d40c->base->virtbase + D40_DREG_PCBASE +
- d40c->phy_chan->num * D40_DREG_PCDELTA +
- D40_CHAN_REG_SDLNK) &
- D40_SREG_LNK_PHYS_LNK_MASK;
- return is_link;
-}
-
-static u32 d40_residue(struct d40_chan *d40c)
-{
- u32 num_elt;
-
- if (d40c->log_num != D40_PHY_CHAN)
- num_elt = (readl(&d40c->lcpa->lcsp2) & D40_MEM_LCSP2_ECNT_MASK)
- >> D40_MEM_LCSP2_ECNT_POS;
- else
- num_elt = (readl(d40c->base->virtbase + D40_DREG_PCBASE +
- d40c->phy_chan->num * D40_DREG_PCDELTA +
- D40_CHAN_REG_SDELT) &
- D40_SREG_ELEM_PHY_ECNT_MASK) >>
- D40_SREG_ELEM_PHY_ECNT_POS;
- return num_elt * (1 << d40c->dma_cfg.dst_info.data_width);
-}
-
-static int d40_resume(struct dma_chan *chan)
-{
- struct d40_chan *d40c =
- container_of(chan, struct d40_chan, chan);
- int res = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&d40c->lock, flags);
-
- if (d40c->base->rev == 0)
- if (d40c->log_num != D40_PHY_CHAN) {
- res = d40_channel_execute_command(d40c,
- D40_DMA_SUSPEND_REQ);
- goto no_suspend;
- }
-
- /* If bytes left to transfer or linked tx resume job */
- if (d40_residue(d40c) || d40_tx_is_linked(d40c)) {
- if (d40c->log_num != D40_PHY_CHAN)
- d40_config_set_event(d40c, true);
- res = d40_channel_execute_command(d40c, D40_DMA_RUN);
- }
-
-no_suspend:
- spin_unlock_irqrestore(&d40c->lock, flags);
- return res;
-}
-
static u32 stedma40_residue(struct dma_chan *chan)
{
struct d40_chan *d40c =
@@ -1475,51 +1614,6 @@ static u32 stedma40_residue(struct dma_chan *chan)
return bytes_left;
}
-/* Public DMA functions in addition to the DMA engine framework */
-
-int stedma40_set_psize(struct dma_chan *chan,
- int src_psize,
- int dst_psize)
-{
- struct d40_chan *d40c =
- container_of(chan, struct d40_chan, chan);
- unsigned long flags;
-
- spin_lock_irqsave(&d40c->lock, flags);
-
- if (d40c->log_num != D40_PHY_CHAN) {
- d40c->log_def.lcsp1 &= ~D40_MEM_LCSP1_SCFG_PSIZE_MASK;
- d40c->log_def.lcsp3 &= ~D40_MEM_LCSP1_SCFG_PSIZE_MASK;
- d40c->log_def.lcsp1 |= src_psize <<
- D40_MEM_LCSP1_SCFG_PSIZE_POS;
- d40c->log_def.lcsp3 |= dst_psize <<
- D40_MEM_LCSP1_SCFG_PSIZE_POS;
- goto out;
- }
-
- if (src_psize == STEDMA40_PSIZE_PHY_1)
- d40c->src_def_cfg &= ~(1 << D40_SREG_CFG_PHY_PEN_POS);
- else {
- d40c->src_def_cfg |= 1 << D40_SREG_CFG_PHY_PEN_POS;
- d40c->src_def_cfg &= ~(STEDMA40_PSIZE_PHY_16 <<
- D40_SREG_CFG_PSIZE_POS);
- d40c->src_def_cfg |= src_psize << D40_SREG_CFG_PSIZE_POS;
- }
-
- if (dst_psize == STEDMA40_PSIZE_PHY_1)
- d40c->dst_def_cfg &= ~(1 << D40_SREG_CFG_PHY_PEN_POS);
- else {
- d40c->dst_def_cfg |= 1 << D40_SREG_CFG_PHY_PEN_POS;
- d40c->dst_def_cfg &= ~(STEDMA40_PSIZE_PHY_16 <<
- D40_SREG_CFG_PSIZE_POS);
- d40c->dst_def_cfg |= dst_psize << D40_SREG_CFG_PSIZE_POS;
- }
-out:
- spin_unlock_irqrestore(&d40c->lock, flags);
- return 0;
-}
-EXPORT_SYMBOL(stedma40_set_psize);
-
struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
struct scatterlist *sgl_dst,
struct scatterlist *sgl_src,
@@ -1545,21 +1639,10 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
goto err;
d40d->lli_len = sgl_len;
- d40d->lli_tx_len = d40d->lli_len;
+ d40d->lli_current = 0;
d40d->txd.flags = dma_flags;
if (d40c->log_num != D40_PHY_CHAN) {
- if (d40d->lli_len > d40c->base->plat_data->llis_per_log)
- d40d->lli_tx_len = d40c->base->plat_data->llis_per_log;
-
- if (sgl_len > 1)
- /*
- * Check if there is space available in lcla. If not,
- * split list into 1-length and run only in lcpa
- * space.
- */
- if (d40_lcla_id_get(d40c) != 0)
- d40d->lli_tx_len = 1;
if (d40_pool_lli_alloc(d40d, sgl_len, true) < 0) {
dev_err(&d40c->chan.dev->device,
@@ -1567,27 +1650,17 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
goto err;
}
- (void) d40_log_sg_to_lli(d40c->lcla.src_id,
- sgl_src,
+ (void) d40_log_sg_to_lli(sgl_src,
sgl_len,
d40d->lli_log.src,
d40c->log_def.lcsp1,
- d40c->dma_cfg.src_info.data_width,
- dma_flags & DMA_PREP_INTERRUPT,
- d40d->lli_tx_len,
- d40c->base->plat_data->llis_per_log);
+ d40c->dma_cfg.src_info.data_width);
- (void) d40_log_sg_to_lli(d40c->lcla.dst_id,
- sgl_dst,
+ (void) d40_log_sg_to_lli(sgl_dst,
sgl_len,
d40d->lli_log.dst,
d40c->log_def.lcsp3,
- d40c->dma_cfg.dst_info.data_width,
- dma_flags & DMA_PREP_INTERRUPT,
- d40d->lli_tx_len,
- d40c->base->plat_data->llis_per_log);
-
-
+ d40c->dma_cfg.dst_info.data_width);
} else {
if (d40_pool_lli_alloc(d40d, sgl_len, false) < 0) {
dev_err(&d40c->chan.dev->device,
@@ -1599,11 +1672,10 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
sgl_len,
0,
d40d->lli_phy.src,
- d40d->lli_phy.src_addr,
+ virt_to_phys(d40d->lli_phy.src),
d40c->src_def_cfg,
d40c->dma_cfg.src_info.data_width,
- d40c->dma_cfg.src_info.psize,
- true);
+ d40c->dma_cfg.src_info.psize);
if (res < 0)
goto err;
@@ -1612,11 +1684,10 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
sgl_len,
0,
d40d->lli_phy.dst,
- d40d->lli_phy.dst_addr,
+ virt_to_phys(d40d->lli_phy.dst),
d40c->dst_def_cfg,
d40c->dma_cfg.dst_info.data_width,
- d40c->dma_cfg.dst_info.psize,
- true);
+ d40c->dma_cfg.dst_info.psize);
if (res < 0)
goto err;
@@ -1633,6 +1704,8 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
return &d40d->txd;
err:
+ if (d40d)
+ d40_desc_free(d40c, d40d);
spin_unlock_irqrestore(&d40c->lock, flags);
return NULL;
}
@@ -1652,6 +1725,9 @@ bool stedma40_filter(struct dma_chan *chan, void *data)
} else
err = d40_config_memcpy(d40c);
+ if (!err)
+ d40c->configured = true;
+
return err == 0;
}
EXPORT_SYMBOL(stedma40_filter);
@@ -1668,11 +1744,8 @@ static int d40_alloc_chan_resources(struct dma_chan *chan)
d40c->completed = chan->cookie = 1;
- /*
- * If no dma configuration is set (channel_type == 0)
- * use default configuration (memcpy)
- */
- if (d40c->dma_cfg.channel_type == 0) {
+ /* If no dma configuration is set use default configuration (memcpy) */
+ if (!d40c->configured) {
err = d40_config_memcpy(d40c);
if (err) {
dev_err(&d40c->chan.dev->device,
@@ -1712,14 +1785,8 @@ static int d40_alloc_chan_resources(struct dma_chan *chan)
* resource is free. In case of multiple logical channels
* on the same physical resource, only the first write is necessary.
*/
- if (is_free_phy) {
- err = d40_config_write(d40c);
- if (err) {
- dev_err(&d40c->chan.dev->device,
- "[%s] Failed to configure channel\n",
- __func__);
- }
- }
+ if (is_free_phy)
+ d40_config_write(d40c);
fail:
spin_unlock_irqrestore(&d40c->lock, flags);
return err;
@@ -1790,23 +1857,21 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
goto err;
}
d40d->lli_len = 1;
- d40d->lli_tx_len = 1;
+ d40d->lli_current = 0;
d40_log_fill_lli(d40d->lli_log.src,
src,
size,
- 0,
d40c->log_def.lcsp1,
d40c->dma_cfg.src_info.data_width,
- false, true);
+ true);
d40_log_fill_lli(d40d->lli_log.dst,
dst,
size,
- 0,
d40c->log_def.lcsp3,
d40c->dma_cfg.dst_info.data_width,
- true, true);
+ true);
} else {
@@ -1851,12 +1916,25 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
err_fill_lli:
dev_err(&d40c->chan.dev->device,
"[%s] Failed filling in PHY LLI\n", __func__);
- d40_pool_lli_free(d40d);
err:
+ if (d40d)
+ d40_desc_free(d40c, d40d);
spin_unlock_irqrestore(&d40c->lock, flags);
return NULL;
}
+static struct dma_async_tx_descriptor *
+d40_prep_sg(struct dma_chan *chan,
+ struct scatterlist *dst_sg, unsigned int dst_nents,
+ struct scatterlist *src_sg, unsigned int src_nents,
+ unsigned long dma_flags)
+{
+ if (dst_nents != src_nents)
+ return NULL;
+
+ return stedma40_memcpy_sg(chan, dst_sg, src_sg, dst_nents, dma_flags);
+}
+
static int d40_prep_slave_sg_log(struct d40_desc *d40d,
struct d40_chan *d40c,
struct scatterlist *sgl,
@@ -1874,19 +1952,7 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d,
}
d40d->lli_len = sg_len;
- if (d40d->lli_len <= d40c->base->plat_data->llis_per_log)
- d40d->lli_tx_len = d40d->lli_len;
- else
- d40d->lli_tx_len = d40c->base->plat_data->llis_per_log;
-
- if (sg_len > 1)
- /*
- * Check if there is space available in lcla.
- * If not, split list into 1-length and run only
- * in lcpa space.
- */
- if (d40_lcla_id_get(d40c) != 0)
- d40d->lli_tx_len = 1;
+ d40d->lli_current = 0;
if (direction == DMA_FROM_DEVICE)
if (d40c->runtime_addr)
@@ -1902,16 +1968,13 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d,
else
return -EINVAL;
- total_size = d40_log_sg_to_dev(&d40c->lcla,
- sgl, sg_len,
+ total_size = d40_log_sg_to_dev(sgl, sg_len,
&d40d->lli_log,
&d40c->log_def,
d40c->dma_cfg.src_info.data_width,
d40c->dma_cfg.dst_info.data_width,
direction,
- dma_flags & DMA_PREP_INTERRUPT,
- dev_addr, d40d->lli_tx_len,
- d40c->base->plat_data->llis_per_log);
+ dev_addr);
if (total_size < 0)
return -EINVAL;
@@ -1937,7 +2000,7 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
}
d40d->lli_len = sgl_len;
- d40d->lli_tx_len = sgl_len;
+ d40d->lli_current = 0;
if (direction == DMA_FROM_DEVICE) {
dst_dev_addr = 0;
@@ -1958,11 +2021,10 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
sgl_len,
src_dev_addr,
d40d->lli_phy.src,
- d40d->lli_phy.src_addr,
+ virt_to_phys(d40d->lli_phy.src),
d40c->src_def_cfg,
d40c->dma_cfg.src_info.data_width,
- d40c->dma_cfg.src_info.psize,
- true);
+ d40c->dma_cfg.src_info.psize);
if (res < 0)
return res;
@@ -1970,11 +2032,10 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
sgl_len,
dst_dev_addr,
d40d->lli_phy.dst,
- d40d->lli_phy.dst_addr,
+ virt_to_phys(d40d->lli_phy.dst),
d40c->dst_def_cfg,
d40c->dma_cfg.dst_info.data_width,
- d40c->dma_cfg.dst_info.psize,
- true);
+ d40c->dma_cfg.dst_info.psize);
if (res < 0)
return res;
@@ -2001,17 +2062,11 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan,
return ERR_PTR(-EINVAL);
}
- if (d40c->dma_cfg.pre_transfer)
- d40c->dma_cfg.pre_transfer(chan,
- d40c->dma_cfg.pre_transfer_data,
- sg_dma_len(sgl));
-
spin_lock_irqsave(&d40c->lock, flags);
d40d = d40_desc_get(d40c);
- spin_unlock_irqrestore(&d40c->lock, flags);
if (d40d == NULL)
- return NULL;
+ goto err;
if (d40c->log_num != D40_PHY_CHAN)
err = d40_prep_slave_sg_log(d40d, d40c, sgl, sg_len,
@@ -2024,7 +2079,7 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan,
"[%s] Failed to prepare %s slave sg job: %d\n",
__func__,
d40c->log_num != D40_PHY_CHAN ? "log" : "phy", err);
- return NULL;
+ goto err;
}
d40d->txd.flags = dma_flags;
@@ -2033,7 +2088,14 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan,
d40d->txd.tx_submit = d40_tx_submit;
+ spin_unlock_irqrestore(&d40c->lock, flags);
return &d40d->txd;
+
+err:
+ if (d40d)
+ d40_desc_free(d40c, d40d);
+ spin_unlock_irqrestore(&d40c->lock, flags);
+ return NULL;
}
static enum dma_status d40_tx_status(struct dma_chan *chan,
@@ -2166,25 +2228,43 @@ static void d40_set_runtime_config(struct dma_chan *chan,
return;
}
- if (config_maxburst >= 16)
- psize = STEDMA40_PSIZE_LOG_16;
- else if (config_maxburst >= 8)
- psize = STEDMA40_PSIZE_LOG_8;
- else if (config_maxburst >= 4)
- psize = STEDMA40_PSIZE_LOG_4;
- else
- psize = STEDMA40_PSIZE_LOG_1;
+ if (d40c->log_num != D40_PHY_CHAN) {
+ if (config_maxburst >= 16)
+ psize = STEDMA40_PSIZE_LOG_16;
+ else if (config_maxburst >= 8)
+ psize = STEDMA40_PSIZE_LOG_8;
+ else if (config_maxburst >= 4)
+ psize = STEDMA40_PSIZE_LOG_4;
+ else
+ psize = STEDMA40_PSIZE_LOG_1;
+ } else {
+ if (config_maxburst >= 16)
+ psize = STEDMA40_PSIZE_PHY_16;
+ else if (config_maxburst >= 8)
+ psize = STEDMA40_PSIZE_PHY_8;
+ else if (config_maxburst >= 4)
+ psize = STEDMA40_PSIZE_PHY_4;
+ else
+ psize = STEDMA40_PSIZE_PHY_1;
+ }
/* Set up all the endpoint configs */
cfg->src_info.data_width = addr_width;
cfg->src_info.psize = psize;
- cfg->src_info.endianess = STEDMA40_LITTLE_ENDIAN;
+ cfg->src_info.big_endian = false;
cfg->src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL;
cfg->dst_info.data_width = addr_width;
cfg->dst_info.psize = psize;
- cfg->dst_info.endianess = STEDMA40_LITTLE_ENDIAN;
+ cfg->dst_info.big_endian = false;
cfg->dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL;
+ /* Fill in register values */
+ if (d40c->log_num != D40_PHY_CHAN)
+ d40_log_cfg(cfg, &d40c->log_def.lcsp1, &d40c->log_def.lcsp3);
+ else
+ d40_phy_cfg(cfg, &d40c->src_def_cfg,
+ &d40c->dst_def_cfg, false);
+
/* These settings will take precedence later */
d40c->runtime_addr = config_addr;
d40c->runtime_direction = config->direction;
@@ -2247,10 +2327,6 @@ static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma,
d40c->base = base;
d40c->chan.device = dma;
- /* Invalidate lcla element */
- d40c->lcla.src_id = -1;
- d40c->lcla.dst_id = -1;
-
spin_lock_init(&d40c->lock);
d40c->log_num = D40_PHY_CHAN;
@@ -2281,6 +2357,7 @@ static int __init d40_dmaengine_init(struct d40_base *base,
base->dma_slave.device_alloc_chan_resources = d40_alloc_chan_resources;
base->dma_slave.device_free_chan_resources = d40_free_chan_resources;
base->dma_slave.device_prep_dma_memcpy = d40_prep_memcpy;
+ base->dma_slave.device_prep_dma_sg = d40_prep_sg;
base->dma_slave.device_prep_slave_sg = d40_prep_slave_sg;
base->dma_slave.device_tx_status = d40_tx_status;
base->dma_slave.device_issue_pending = d40_issue_pending;
@@ -2301,10 +2378,12 @@ static int __init d40_dmaengine_init(struct d40_base *base,
dma_cap_zero(base->dma_memcpy.cap_mask);
dma_cap_set(DMA_MEMCPY, base->dma_memcpy.cap_mask);
+ dma_cap_set(DMA_SG, base->dma_slave.cap_mask);
base->dma_memcpy.device_alloc_chan_resources = d40_alloc_chan_resources;
base->dma_memcpy.device_free_chan_resources = d40_free_chan_resources;
base->dma_memcpy.device_prep_dma_memcpy = d40_prep_memcpy;
+ base->dma_slave.device_prep_dma_sg = d40_prep_sg;
base->dma_memcpy.device_prep_slave_sg = d40_prep_slave_sg;
base->dma_memcpy.device_tx_status = d40_tx_status;
base->dma_memcpy.device_issue_pending = d40_issue_pending;
@@ -2331,10 +2410,12 @@ static int __init d40_dmaengine_init(struct d40_base *base,
dma_cap_zero(base->dma_both.cap_mask);
dma_cap_set(DMA_SLAVE, base->dma_both.cap_mask);
dma_cap_set(DMA_MEMCPY, base->dma_both.cap_mask);
+ dma_cap_set(DMA_SG, base->dma_slave.cap_mask);
base->dma_both.device_alloc_chan_resources = d40_alloc_chan_resources;
base->dma_both.device_free_chan_resources = d40_free_chan_resources;
base->dma_both.device_prep_dma_memcpy = d40_prep_memcpy;
+ base->dma_slave.device_prep_dma_sg = d40_prep_sg;
base->dma_both.device_prep_slave_sg = d40_prep_slave_sg;
base->dma_both.device_tx_status = d40_tx_status;
base->dma_both.device_issue_pending = d40_issue_pending;
@@ -2387,9 +2468,11 @@ static int __init d40_phy_res_init(struct d40_base *base)
/* Mark disabled channels as occupied */
for (i = 0; base->plat_data->disabled_channels[i] != -1; i++) {
- base->phy_res[i].allocated_src = D40_ALLOC_PHY;
- base->phy_res[i].allocated_dst = D40_ALLOC_PHY;
- num_phy_chans_avail--;
+ int chan = base->plat_data->disabled_channels[i];
+
+ base->phy_res[chan].allocated_src = D40_ALLOC_PHY;
+ base->phy_res[chan].allocated_dst = D40_ALLOC_PHY;
+ num_phy_chans_avail--;
}
dev_info(base->dev, "%d of %d physical DMA channels available\n",
@@ -2441,6 +2524,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
int num_phy_chans;
int i;
u32 val;
+ u32 rev;
clk = clk_get(&pdev->dev, NULL);
@@ -2479,21 +2563,26 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
}
}
- /* Get silicon revision */
+ /* Get silicon revision and designer */
val = readl(virtbase + D40_DREG_PERIPHID2);
- if ((val & 0xf) != D40_PERIPHID2_DESIGNER) {
+ if ((val & D40_DREG_PERIPHID2_DESIGNER_MASK) !=
+ D40_HW_DESIGNER) {
dev_err(&pdev->dev,
"[%s] Unknown designer! Got %x wanted %x\n",
- __func__, val & 0xf, D40_PERIPHID2_DESIGNER);
+ __func__, val & D40_DREG_PERIPHID2_DESIGNER_MASK,
+ D40_HW_DESIGNER);
goto failure;
}
+ rev = (val & D40_DREG_PERIPHID2_REV_MASK) >>
+ D40_DREG_PERIPHID2_REV_POS;
+
/* The number of physical channels on this HW */
num_phy_chans = 4 * (readl(virtbase + D40_DREG_ICFG) & 0x7) + 4;
dev_info(&pdev->dev, "hardware revision: %d @ 0x%x\n",
- (val >> 4) & 0xf, res->start);
+ rev, res->start);
plat_data = pdev->dev.platform_data;
@@ -2515,7 +2604,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
goto failure;
}
- base->rev = (val >> 4) & 0xf;
+ base->rev = rev;
base->clk = clk;
base->num_phy_chans = num_phy_chans;
base->num_log_chans = num_log_chans;
@@ -2549,7 +2638,10 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
if (!base->lookup_log_chans)
goto failure;
}
- base->lcla_pool.alloc_map = kzalloc(num_phy_chans * sizeof(u32),
+
+ base->lcla_pool.alloc_map = kzalloc(num_phy_chans *
+ sizeof(struct d40_desc *) *
+ D40_LCLA_LINK_PER_EVENT_GRP,
GFP_KERNEL);
if (!base->lcla_pool.alloc_map)
goto failure;
@@ -2563,7 +2655,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
return base;
failure:
- if (clk) {
+ if (!IS_ERR(clk)) {
clk_disable(clk);
clk_put(clk);
}
@@ -2700,8 +2792,10 @@ static int __init d40_lcla_allocate(struct d40_base *base)
if (i < MAX_LCLA_ALLOC_ATTEMPTS) {
base->lcla_pool.base = (void *)page_list[i];
} else {
- /* After many attempts, no succees with finding the correct
- * alignment try with allocating a big buffer */
+ /*
+ * After many attempts and no succees with finding the correct
+ * alignment, try with allocating a big buffer.
+ */
dev_warn(base->dev,
"[%s] Failed to get %d pages @ 18 bit align.\n",
__func__, base->lcla_pool.pages);
@@ -2794,8 +2888,6 @@ static int __init d40_probe(struct platform_device *pdev)
spin_lock_init(&base->lcla_pool.lock);
- base->lcla_pool.num_blocks = base->num_phy_chans;
-
base->irq = platform_get_irq(pdev, 0);
ret = request_irq(base->irq, d40_handle_interrupt, 0, D40_NAME, base);
@@ -2823,8 +2915,9 @@ failure:
if (!base->lcla_pool.base_unaligned && base->lcla_pool.base)
free_pages((unsigned long)base->lcla_pool.base,
base->lcla_pool.pages);
- if (base->lcla_pool.base_unaligned)
- kfree(base->lcla_pool.base_unaligned);
+
+ kfree(base->lcla_pool.base_unaligned);
+
if (base->phy_lcpa)
release_mem_region(base->phy_lcpa,
base->lcpa_size);
diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c
index d937f76d6e2e..8557cb88b255 100644
--- a/drivers/dma/ste_dma40_ll.c
+++ b/drivers/dma/ste_dma40_ll.c
@@ -1,10 +1,8 @@
/*
- * driver/dma/ste_dma40_ll.c
- *
- * Copyright (C) ST-Ericsson 2007-2010
+ * Copyright (C) ST-Ericsson SA 2007-2010
+ * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
- * Author: Per Friden <per.friden@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*/
#include <linux/kernel.h>
@@ -39,16 +37,13 @@ void d40_log_cfg(struct stedma40_chan_cfg *cfg,
cfg->dir == STEDMA40_PERIPH_TO_PERIPH)
l3 |= 1 << D40_MEM_LCSP3_DCFG_MST_POS;
- l3 |= 1 << D40_MEM_LCSP3_DCFG_TIM_POS;
l3 |= 1 << D40_MEM_LCSP3_DCFG_EIM_POS;
l3 |= cfg->dst_info.psize << D40_MEM_LCSP3_DCFG_PSIZE_POS;
l3 |= cfg->dst_info.data_width << D40_MEM_LCSP3_DCFG_ESIZE_POS;
- l3 |= 1 << D40_MEM_LCSP3_DTCP_POS;
l1 |= 1 << D40_MEM_LCSP1_SCFG_EIM_POS;
l1 |= cfg->src_info.psize << D40_MEM_LCSP1_SCFG_PSIZE_POS;
l1 |= cfg->src_info.data_width << D40_MEM_LCSP1_SCFG_ESIZE_POS;
- l1 |= 1 << D40_MEM_LCSP1_STCP_POS;
*lcsp1 = l1;
*lcsp3 = l3;
@@ -113,13 +108,15 @@ void d40_phy_cfg(struct stedma40_chan_cfg *cfg,
src |= 1 << D40_SREG_CFG_LOG_GIM_POS;
}
- if (cfg->channel_type & STEDMA40_HIGH_PRIORITY_CHANNEL) {
+ if (cfg->high_priority) {
src |= 1 << D40_SREG_CFG_PRI_POS;
dst |= 1 << D40_SREG_CFG_PRI_POS;
}
- src |= cfg->src_info.endianess << D40_SREG_CFG_LBE_POS;
- dst |= cfg->dst_info.endianess << D40_SREG_CFG_LBE_POS;
+ if (cfg->src_info.big_endian)
+ src |= 1 << D40_SREG_CFG_LBE_POS;
+ if (cfg->dst_info.big_endian)
+ dst |= 1 << D40_SREG_CFG_LBE_POS;
*src_cfg = src;
*dst_cfg = dst;
@@ -197,8 +194,7 @@ int d40_phy_sg_to_lli(struct scatterlist *sg,
dma_addr_t lli_phys,
u32 reg_cfg,
u32 data_width,
- int psize,
- bool term_int)
+ int psize)
{
int total_size = 0;
int i;
@@ -238,7 +234,7 @@ int d40_phy_sg_to_lli(struct scatterlist *sg,
}
return total_size;
- err:
+err:
return err;
}
@@ -271,11 +267,59 @@ void d40_phy_lli_write(void __iomem *virtbase,
/* DMA logical lli operations */
+static void d40_log_lli_link(struct d40_log_lli *lli_dst,
+ struct d40_log_lli *lli_src,
+ int next)
+{
+ u32 slos = 0;
+ u32 dlos = 0;
+
+ if (next != -EINVAL) {
+ slos = next * 2;
+ dlos = next * 2 + 1;
+ } else {
+ lli_dst->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK;
+ lli_dst->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK;
+ }
+
+ lli_src->lcsp13 = (lli_src->lcsp13 & ~D40_MEM_LCSP1_SLOS_MASK) |
+ (slos << D40_MEM_LCSP1_SLOS_POS);
+
+ lli_dst->lcsp13 = (lli_dst->lcsp13 & ~D40_MEM_LCSP1_SLOS_MASK) |
+ (dlos << D40_MEM_LCSP1_SLOS_POS);
+}
+
+void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
+ struct d40_log_lli *lli_dst,
+ struct d40_log_lli *lli_src,
+ int next)
+{
+ d40_log_lli_link(lli_dst, lli_src, next);
+
+ writel(lli_src->lcsp02, &lcpa[0].lcsp0);
+ writel(lli_src->lcsp13, &lcpa[0].lcsp1);
+ writel(lli_dst->lcsp02, &lcpa[0].lcsp2);
+ writel(lli_dst->lcsp13, &lcpa[0].lcsp3);
+}
+
+void d40_log_lli_lcla_write(struct d40_log_lli *lcla,
+ struct d40_log_lli *lli_dst,
+ struct d40_log_lli *lli_src,
+ int next)
+{
+ d40_log_lli_link(lli_dst, lli_src, next);
+
+ writel(lli_src->lcsp02, &lcla[0].lcsp02);
+ writel(lli_src->lcsp13, &lcla[0].lcsp13);
+ writel(lli_dst->lcsp02, &lcla[1].lcsp02);
+ writel(lli_dst->lcsp13, &lcla[1].lcsp13);
+}
+
void d40_log_fill_lli(struct d40_log_lli *lli,
dma_addr_t data, u32 data_size,
- u32 lli_next_off, u32 reg_cfg,
+ u32 reg_cfg,
u32 data_width,
- bool term_int, bool addr_inc)
+ bool addr_inc)
{
lli->lcsp13 = reg_cfg;
@@ -290,165 +334,69 @@ void d40_log_fill_lli(struct d40_log_lli *lli,
if (addr_inc)
lli->lcsp13 |= D40_MEM_LCSP1_SCFG_INCR_MASK;
- lli->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK;
- /* If this scatter list entry is the last one, no next link */
- lli->lcsp13 |= (lli_next_off << D40_MEM_LCSP1_SLOS_POS) &
- D40_MEM_LCSP1_SLOS_MASK;
-
- if (term_int)
- lli->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK;
- else
- lli->lcsp13 &= ~D40_MEM_LCSP1_SCFG_TIM_MASK;
}
-int d40_log_sg_to_dev(struct d40_lcla_elem *lcla,
- struct scatterlist *sg,
+int d40_log_sg_to_dev(struct scatterlist *sg,
int sg_len,
struct d40_log_lli_bidir *lli,
struct d40_def_lcsp *lcsp,
u32 src_data_width,
u32 dst_data_width,
enum dma_data_direction direction,
- bool term_int, dma_addr_t dev_addr, int max_len,
- int llis_per_log)
+ dma_addr_t dev_addr)
{
int total_size = 0;
struct scatterlist *current_sg = sg;
int i;
- u32 next_lli_off_dst = 0;
- u32 next_lli_off_src = 0;
for_each_sg(sg, current_sg, sg_len, i) {
total_size += sg_dma_len(current_sg);
- /*
- * If this scatter list entry is the last one or
- * max length, terminate link.
- */
- if (sg_len - 1 == i || ((i+1) % max_len == 0)) {
- next_lli_off_src = 0;
- next_lli_off_dst = 0;
- } else {
- if (next_lli_off_dst == 0 &&
- next_lli_off_src == 0) {
- /* The first lli will be at next_lli_off */
- next_lli_off_dst = (lcla->dst_id *
- llis_per_log + 1);
- next_lli_off_src = (lcla->src_id *
- llis_per_log + 1);
- } else {
- next_lli_off_dst++;
- next_lli_off_src++;
- }
- }
-
if (direction == DMA_TO_DEVICE) {
d40_log_fill_lli(&lli->src[i],
sg_phys(current_sg),
sg_dma_len(current_sg),
- next_lli_off_src,
lcsp->lcsp1, src_data_width,
- false,
true);
d40_log_fill_lli(&lli->dst[i],
dev_addr,
sg_dma_len(current_sg),
- next_lli_off_dst,
lcsp->lcsp3, dst_data_width,
- /* No next == terminal interrupt */
- term_int && !next_lli_off_dst,
false);
} else {
d40_log_fill_lli(&lli->dst[i],
sg_phys(current_sg),
sg_dma_len(current_sg),
- next_lli_off_dst,
lcsp->lcsp3, dst_data_width,
- /* No next == terminal interrupt */
- term_int && !next_lli_off_dst,
true);
d40_log_fill_lli(&lli->src[i],
dev_addr,
sg_dma_len(current_sg),
- next_lli_off_src,
lcsp->lcsp1, src_data_width,
- false,
false);
}
}
return total_size;
}
-int d40_log_sg_to_lli(int lcla_id,
- struct scatterlist *sg,
+int d40_log_sg_to_lli(struct scatterlist *sg,
int sg_len,
struct d40_log_lli *lli_sg,
u32 lcsp13, /* src or dst*/
- u32 data_width,
- bool term_int, int max_len, int llis_per_log)
+ u32 data_width)
{
int total_size = 0;
struct scatterlist *current_sg = sg;
int i;
- u32 next_lli_off = 0;
for_each_sg(sg, current_sg, sg_len, i) {
total_size += sg_dma_len(current_sg);
- /*
- * If this scatter list entry is the last one or
- * max length, terminate link.
- */
- if (sg_len - 1 == i || ((i+1) % max_len == 0))
- next_lli_off = 0;
- else {
- if (next_lli_off == 0)
- /* The first lli will be at next_lli_off */
- next_lli_off = lcla_id * llis_per_log + 1;
- else
- next_lli_off++;
- }
-
d40_log_fill_lli(&lli_sg[i],
sg_phys(current_sg),
sg_dma_len(current_sg),
- next_lli_off,
lcsp13, data_width,
- term_int && !next_lli_off,
true);
}
return total_size;
}
-
-int d40_log_lli_write(struct d40_log_lli_full *lcpa,
- struct d40_log_lli *lcla_src,
- struct d40_log_lli *lcla_dst,
- struct d40_log_lli *lli_dst,
- struct d40_log_lli *lli_src,
- int llis_per_log)
-{
- u32 slos;
- u32 dlos;
- int i;
-
- writel(lli_src->lcsp02, &lcpa->lcsp0);
- writel(lli_src->lcsp13, &lcpa->lcsp1);
- writel(lli_dst->lcsp02, &lcpa->lcsp2);
- writel(lli_dst->lcsp13, &lcpa->lcsp3);
-
- slos = lli_src->lcsp13 & D40_MEM_LCSP1_SLOS_MASK;
- dlos = lli_dst->lcsp13 & D40_MEM_LCSP3_DLOS_MASK;
-
- for (i = 0; (i < llis_per_log) && slos && dlos; i++) {
- writel(lli_src[i + 1].lcsp02, &lcla_src[i].lcsp02);
- writel(lli_src[i + 1].lcsp13, &lcla_src[i].lcsp13);
- writel(lli_dst[i + 1].lcsp02, &lcla_dst[i].lcsp02);
- writel(lli_dst[i + 1].lcsp13, &lcla_dst[i].lcsp13);
-
- slos = lli_src[i + 1].lcsp13 & D40_MEM_LCSP1_SLOS_MASK;
- dlos = lli_dst[i + 1].lcsp13 & D40_MEM_LCSP3_DLOS_MASK;
- }
-
- return i;
-
-}
diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h
index 9c0fa2f5fe57..9e419b907544 100644
--- a/drivers/dma/ste_dma40_ll.h
+++ b/drivers/dma/ste_dma40_ll.h
@@ -1,10 +1,8 @@
/*
- * driver/dma/ste_dma40_ll.h
- *
- * Copyright (C) ST-Ericsson 2007-2010
+ * Copyright (C) ST-Ericsson SA 2007-2010
+ * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson SA
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson SA
* License terms: GNU General Public License (GPL) version 2
- * Author: Per Friden <per.friden@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*/
#ifndef STE_DMA40_LL_H
#define STE_DMA40_LL_H
@@ -132,6 +130,13 @@
#define D40_DREG_PRMSO 0x014
#define D40_DREG_PRMOE 0x018
#define D40_DREG_PRMOO 0x01C
+#define D40_DREG_PRMO_PCHAN_BASIC 0x1
+#define D40_DREG_PRMO_PCHAN_MODULO 0x2
+#define D40_DREG_PRMO_PCHAN_DOUBLE_DST 0x3
+#define D40_DREG_PRMO_LCHAN_SRC_PHY_DST_LOG 0x1
+#define D40_DREG_PRMO_LCHAN_SRC_LOG_DST_PHY 0x2
+#define D40_DREG_PRMO_LCHAN_SRC_LOG_DST_LOG 0x3
+
#define D40_DREG_LCPA 0x020
#define D40_DREG_LCLA 0x024
#define D40_DREG_ACTIVE 0x050
@@ -163,6 +168,9 @@
#define D40_DREG_PERIPHID0 0xFE0
#define D40_DREG_PERIPHID1 0xFE4
#define D40_DREG_PERIPHID2 0xFE8
+#define D40_DREG_PERIPHID2_REV_POS 4
+#define D40_DREG_PERIPHID2_REV_MASK (0xf << D40_DREG_PERIPHID2_REV_POS)
+#define D40_DREG_PERIPHID2_DESIGNER_MASK 0xf
#define D40_DREG_PERIPHID3 0xFEC
#define D40_DREG_CELLID0 0xFF0
#define D40_DREG_CELLID1 0xFF4
@@ -199,8 +207,6 @@ struct d40_phy_lli {
*
* @src: Register settings for src channel.
* @dst: Register settings for dst channel.
- * @dst_addr: Physical destination address.
- * @src_addr: Physical source address.
*
* All DMA transfers have a source and a destination.
*/
@@ -208,8 +214,6 @@ struct d40_phy_lli {
struct d40_phy_lli_bidir {
struct d40_phy_lli *src;
struct d40_phy_lli *dst;
- dma_addr_t dst_addr;
- dma_addr_t src_addr;
};
@@ -271,29 +275,16 @@ struct d40_def_lcsp {
u32 lcsp1;
};
-/**
- * struct d40_lcla_elem - Info for one LCA element.
- *
- * @src_id: logical channel src id
- * @dst_id: logical channel dst id
- * @src: LCPA formated src parameters
- * @dst: LCPA formated dst parameters
- *
- */
-struct d40_lcla_elem {
- int src_id;
- int dst_id;
- struct d40_log_lli *src;
- struct d40_log_lli *dst;
-};
-
/* Physical channels */
void d40_phy_cfg(struct stedma40_chan_cfg *cfg,
- u32 *src_cfg, u32 *dst_cfg, bool is_log);
+ u32 *src_cfg,
+ u32 *dst_cfg,
+ bool is_log);
void d40_log_cfg(struct stedma40_chan_cfg *cfg,
- u32 *lcsp1, u32 *lcsp2);
+ u32 *lcsp1,
+ u32 *lcsp2);
int d40_phy_sg_to_lli(struct scatterlist *sg,
int sg_len,
@@ -302,8 +293,7 @@ int d40_phy_sg_to_lli(struct scatterlist *sg,
dma_addr_t lli_phys,
u32 reg_cfg,
u32 data_width,
- int psize,
- bool term_int);
+ int psize);
int d40_phy_fill_lli(struct d40_phy_lli *lli,
dma_addr_t data,
@@ -323,35 +313,35 @@ void d40_phy_lli_write(void __iomem *virtbase,
/* Logical channels */
void d40_log_fill_lli(struct d40_log_lli *lli,
- dma_addr_t data, u32 data_size,
- u32 lli_next_off, u32 reg_cfg,
+ dma_addr_t data,
+ u32 data_size,
+ u32 reg_cfg,
u32 data_width,
- bool term_int, bool addr_inc);
+ bool addr_inc);
-int d40_log_sg_to_dev(struct d40_lcla_elem *lcla,
- struct scatterlist *sg,
+int d40_log_sg_to_dev(struct scatterlist *sg,
int sg_len,
struct d40_log_lli_bidir *lli,
struct d40_def_lcsp *lcsp,
u32 src_data_width,
u32 dst_data_width,
enum dma_data_direction direction,
- bool term_int, dma_addr_t dev_addr, int max_len,
- int llis_per_log);
-
-int d40_log_lli_write(struct d40_log_lli_full *lcpa,
- struct d40_log_lli *lcla_src,
- struct d40_log_lli *lcla_dst,
- struct d40_log_lli *lli_dst,
- struct d40_log_lli *lli_src,
- int llis_per_log);
-
-int d40_log_sg_to_lli(int lcla_id,
- struct scatterlist *sg,
+ dma_addr_t dev_addr);
+
+int d40_log_sg_to_lli(struct scatterlist *sg,
int sg_len,
struct d40_log_lli *lli_sg,
u32 lcsp13, /* src or dst*/
- u32 data_width,
- bool term_int, int max_len, int llis_per_log);
+ u32 data_width);
+
+void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
+ struct d40_log_lli *lli_dst,
+ struct d40_log_lli *lli_src,
+ int next);
+
+void d40_log_lli_lcla_write(struct d40_log_lli *lcla,
+ struct d40_log_lli *lli_dst,
+ struct d40_log_lli *lli_src,
+ int next);
#endif /* STE_DMA40_LLI_H */
diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c
index 2ec1ed56f204..3b88a4e7c98a 100644
--- a/drivers/dma/timb_dma.c
+++ b/drivers/dma/timb_dma.c
@@ -759,7 +759,7 @@ static int __devinit td_probe(struct platform_device *pdev)
pdata->channels + i;
/* even channels are RX, odd are TX */
- if (((i % 2) && pchan->rx) || (!(i % 2) && !pchan->rx)) {
+ if ((i % 2) == pchan->rx) {
dev_err(&pdev->dev, "Wrong channel configuration\n");
err = -EINVAL;
goto err_tasklet_kill;
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 9dbb28b9559f..f436a2fa9f38 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -209,6 +209,13 @@ config EDAC_I5100
Support for error detection and correction the Intel
San Clemente MCH.
+config EDAC_I7300
+ tristate "Intel Clarksboro MCH"
+ depends on EDAC_MM_EDAC && X86 && PCI
+ help
+ Support for error detection and correction the Intel
+ Clarksboro MCH (Intel 7300 chipset).
+
config EDAC_MPC85XX
tristate "Freescale MPC83xx / MPC85xx"
depends on EDAC_MM_EDAC && FSL_SOC && (PPC_83xx || PPC_85xx)
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 32c7bc93c525..b3781399b38a 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_EDAC_CPC925) += cpc925_edac.o
obj-$(CONFIG_EDAC_I5000) += i5000_edac.o
obj-$(CONFIG_EDAC_I5100) += i5100_edac.o
obj-$(CONFIG_EDAC_I5400) += i5400_edac.o
+obj-$(CONFIG_EDAC_I7300) += i7300_edac.o
obj-$(CONFIG_EDAC_I7CORE) += i7core_edac.o
obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o
obj-$(CONFIG_EDAC_E752X) += e752x_edac.o
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index ce7146677e9b..d7ca43a828bd 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -42,8 +42,10 @@
#if PAGE_SHIFT < 20
#define PAGES_TO_MiB( pages ) ( ( pages ) >> ( 20 - PAGE_SHIFT ) )
+#define MiB_TO_PAGES(mb) ((mb) >> (20 - PAGE_SHIFT))
#else /* PAGE_SHIFT > 20 */
#define PAGES_TO_MiB( pages ) ( ( pages ) << ( PAGE_SHIFT - 20 ) )
+#define MiB_TO_PAGES(mb) ((mb) >> (PAGE_SHIFT - 20))
#endif
#define edac_printk(level, prefix, fmt, arg...) \
@@ -328,7 +330,7 @@ struct csrow_info {
struct mcidev_sysfs_group {
const char *name; /* group name */
- struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */
+ const struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */
};
struct mcidev_sysfs_group_kobj {
@@ -336,7 +338,7 @@ struct mcidev_sysfs_group_kobj {
struct kobject kobj; /* kobj for the group */
- struct mcidev_sysfs_group *grp; /* group description table */
+ const struct mcidev_sysfs_group *grp; /* group description table */
struct mem_ctl_info *mci; /* the parent */
};
@@ -347,7 +349,7 @@ struct mcidev_sysfs_group_kobj {
struct mcidev_sysfs_attribute {
/* It should use either attr or grp */
struct attribute attr;
- struct mcidev_sysfs_group *grp; /* Points to a group of attributes */
+ const struct mcidev_sysfs_group *grp; /* Points to a group of attributes */
/* Ops for show/store values at the attribute - not used on group */
ssize_t (*show)(struct mem_ctl_info *,char *);
@@ -440,7 +442,7 @@ struct mem_ctl_info {
* If attributes are desired, then set to array of attributes
* If no attributes are desired, leave NULL
*/
- struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes;
+ const struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes;
/* work struct for this MC */
struct delayed_work work;
@@ -810,6 +812,7 @@ extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
extern int edac_mc_add_mc(struct mem_ctl_info *mci);
extern void edac_mc_free(struct mem_ctl_info *mci);
extern struct mem_ctl_info *edac_mc_find(int idx);
+extern struct mem_ctl_info *find_mci_by_dev(struct device *dev);
extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev);
extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
unsigned long page);
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c
index 2941dca91aae..400de071cabc 100644
--- a/drivers/edac/edac_device_sysfs.c
+++ b/drivers/edac/edac_device_sysfs.c
@@ -1,7 +1,7 @@
/*
* file for managing the edac_device class of devices for EDAC
*
- * (C) 2007 SoftwareBitMaker (http://www.softwarebitmaker.com)
+ * (C) 2007 SoftwareBitMaker
*
* This file may be distributed under the terms of the
* GNU General Public License.
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 6b21e25f7a84..ba6586a69ccc 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -207,6 +207,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
}
mci->op_state = OP_ALLOC;
+ INIT_LIST_HEAD(&mci->grp_kobj_list);
/*
* Initialize the 'root' kobj for the edac_mc controller
@@ -234,18 +235,24 @@ EXPORT_SYMBOL_GPL(edac_mc_alloc);
*/
void edac_mc_free(struct mem_ctl_info *mci)
{
+ debugf1("%s()\n", __func__);
+
edac_mc_unregister_sysfs_main_kobj(mci);
+
+ /* free the mci instance memory here */
+ kfree(mci);
}
EXPORT_SYMBOL_GPL(edac_mc_free);
-/*
+/**
* find_mci_by_dev
*
* scan list of controllers looking for the one that manages
* the 'dev' device
+ * @dev: pointer to a struct device related with the MCI
*/
-static struct mem_ctl_info *find_mci_by_dev(struct device *dev)
+struct mem_ctl_info *find_mci_by_dev(struct device *dev)
{
struct mem_ctl_info *mci;
struct list_head *item;
@@ -261,6 +268,7 @@ static struct mem_ctl_info *find_mci_by_dev(struct device *dev)
return NULL;
}
+EXPORT_SYMBOL_GPL(find_mci_by_dev);
/*
* handler for EDAC to check if NMI type handler has asserted interrupt
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index a4135860149b..dce61f7ba38b 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -631,9 +631,6 @@ static void edac_mci_control_release(struct kobject *kobj)
/* decrement the module ref count */
module_put(mci->owner);
-
- /* free the mci instance memory here */
- kfree(mci);
}
static struct kobj_type ktype_mci = {
@@ -713,6 +710,8 @@ fail_out:
*/
void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
{
+ debugf1("%s()\n", __func__);
+
/* delete the kobj from the mc_kset */
kobject_put(&mci->edac_mci_kobj);
}
@@ -760,8 +759,6 @@ static void edac_inst_grp_release(struct kobject *kobj)
grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj);
mci = grp->mci;
-
- kobject_put(&mci->edac_mci_kobj);
}
/* Intermediate show/store table */
@@ -784,7 +781,7 @@ static struct kobj_type ktype_inst_grp = {
* object tree.
*/
static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
- struct mcidev_sysfs_attribute *sysfs_attrib,
+ const struct mcidev_sysfs_attribute *sysfs_attrib,
struct kobject *kobj)
{
int err;
@@ -792,6 +789,7 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
debugf1("%s()\n", __func__);
while (sysfs_attrib) {
+ debugf1("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
if (sysfs_attrib->grp) {
struct mcidev_sysfs_group_kobj *grp_kobj;
@@ -799,10 +797,9 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
if (!grp_kobj)
return -ENOMEM;
- list_add_tail(&grp_kobj->list, &mci->grp_kobj_list);
-
grp_kobj->grp = sysfs_attrib->grp;
grp_kobj->mci = mci;
+ list_add_tail(&grp_kobj->list, &mci->grp_kobj_list);
debugf0("%s() grp %s, mci %p\n", __func__,
sysfs_attrib->grp->name, mci);
@@ -811,26 +808,28 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
&ktype_inst_grp,
&mci->edac_mci_kobj,
sysfs_attrib->grp->name);
- if (err)
+ if (err < 0) {
+ printk(KERN_ERR "kobject_init_and_add failed: %d\n", err);
return err;
-
+ }
err = edac_create_mci_instance_attributes(mci,
grp_kobj->grp->mcidev_attr,
&grp_kobj->kobj);
- if (err)
+ if (err < 0)
return err;
} else if (sysfs_attrib->attr.name) {
debugf0("%s() file %s\n", __func__,
sysfs_attrib->attr.name);
err = sysfs_create_file(kobj, &sysfs_attrib->attr);
+ if (err < 0) {
+ printk(KERN_ERR "sysfs_create_file failed: %d\n", err);
+ return err;
+ }
} else
break;
- if (err) {
- return err;
- }
sysfs_attrib++;
}
@@ -843,7 +842,7 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
* directory of this mci instance.
*/
static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
- struct mcidev_sysfs_attribute *sysfs_attrib,
+ const struct mcidev_sysfs_attribute *sysfs_attrib,
struct kobject *kobj, int count)
{
struct mcidev_sysfs_group_kobj *grp_kobj, *tmp;
@@ -855,13 +854,24 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
* Remove first all the atributes
*/
while (sysfs_attrib) {
+ debugf1("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
if (sysfs_attrib->grp) {
- list_for_each_entry(grp_kobj, &mci->grp_kobj_list,
- list)
- if (grp_kobj->grp == sysfs_attrib->grp)
+ debugf1("%s() seeking for group %s\n",
+ __func__, sysfs_attrib->grp->name);
+ list_for_each_entry(grp_kobj,
+ &mci->grp_kobj_list, list) {
+ debugf1("%s() grp_kobj->grp = %p\n",__func__, grp_kobj->grp);
+ if (grp_kobj->grp == sysfs_attrib->grp) {
edac_remove_mci_instance_attributes(mci,
grp_kobj->grp->mcidev_attr,
&grp_kobj->kobj, count + 1);
+ debugf0("%s() group %s\n", __func__,
+ sysfs_attrib->grp->name);
+ kobject_put(&grp_kobj->kobj);
+ }
+ }
+ debugf1("%s() end of seeking for group %s\n",
+ __func__, sysfs_attrib->grp->name);
} else if (sysfs_attrib->attr.name) {
debugf0("%s() file %s\n", __func__,
sysfs_attrib->attr.name);
@@ -871,15 +881,14 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
sysfs_attrib++;
}
- /*
- * Now that all attributes got removed, it is save to remove all groups
- */
- if (!count)
- list_for_each_entry_safe(grp_kobj, tmp, &mci->grp_kobj_list,
- list) {
- debugf0("%s() grp %s\n", __func__, grp_kobj->grp->name);
- kobject_put(&grp_kobj->kobj);
- }
+ /* Remove the group objects */
+ if (count)
+ return;
+ list_for_each_entry_safe(grp_kobj, tmp,
+ &mci->grp_kobj_list, list) {
+ list_del(&grp_kobj->list);
+ kfree(grp_kobj);
+ }
}
@@ -971,6 +980,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
debugf0("%s()\n", __func__);
/* remove all csrow kobjects */
+ debugf0("%s() unregister this mci kobj\n", __func__);
for (i = 0; i < mci->nr_csrows; i++) {
if (mci->csrows[i].nr_pages > 0) {
debugf0("%s() unreg csrow-%d\n", __func__, i);
@@ -978,20 +988,20 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
}
}
- debugf0("%s() remove_link\n", __func__);
+ /* remove this mci instance's attribtes */
+ if (mci->mc_driver_sysfs_attributes) {
+ debugf0("%s() unregister mci private attributes\n", __func__);
+ edac_remove_mci_instance_attributes(mci,
+ mci->mc_driver_sysfs_attributes,
+ &mci->edac_mci_kobj, 0);
+ }
/* remove the symlink */
+ debugf0("%s() remove_link\n", __func__);
sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
- debugf0("%s() remove_mci_instance\n", __func__);
-
- /* remove this mci instance's attribtes */
- edac_remove_mci_instance_attributes(mci,
- mci->mc_driver_sysfs_attributes,
- &mci->edac_mci_kobj, 0);
- debugf0("%s() unregister this mci kobj\n", __func__);
-
/* unregister this instance's kobject */
+ debugf0("%s() remove_mci_instance\n", __func__);
kobject_put(&mci->edac_mci_kobj);
}
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
new file mode 100644
index 000000000000..05523b504271
--- /dev/null
+++ b/drivers/edac/i7300_edac.c
@@ -0,0 +1,1247 @@
+/*
+ * Intel 7300 class Memory Controllers kernel module (Clarksboro)
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License version 2 only.
+ *
+ * Copyright (c) 2010 by:
+ * Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Red Hat Inc. http://www.redhat.com
+ *
+ * Intel 7300 Chipset Memory Controller Hub (MCH) - Datasheet
+ * http://www.intel.com/Assets/PDF/datasheet/318082.pdf
+ *
+ * TODO: The chipset allow checking for PCI Express errors also. Currently,
+ * the driver covers only memory error errors
+ *
+ * This driver uses "csrows" EDAC attribute to represent DIMM slot#
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include <linux/edac.h>
+#include <linux/mmzone.h>
+
+#include "edac_core.h"
+
+/*
+ * Alter this version for the I7300 module when modifications are made
+ */
+#define I7300_REVISION " Ver: 1.0.0 " __DATE__
+
+#define EDAC_MOD_STR "i7300_edac"
+
+#define i7300_printk(level, fmt, arg...) \
+ edac_printk(level, "i7300", fmt, ##arg)
+
+#define i7300_mc_printk(mci, level, fmt, arg...) \
+ edac_mc_chipset_printk(mci, level, "i7300", fmt, ##arg)
+
+/***********************************************
+ * i7300 Limit constants Structs and static vars
+ ***********************************************/
+
+/*
+ * Memory topology is organized as:
+ * Branch 0 - 2 channels: channels 0 and 1 (FDB0 PCI dev 21.0)
+ * Branch 1 - 2 channels: channels 2 and 3 (FDB1 PCI dev 22.0)
+ * Each channel can have to 8 DIMM sets (called as SLOTS)
+ * Slots should generally be filled in pairs
+ * Except on Single Channel mode of operation
+ * just slot 0/channel0 filled on this mode
+ * On normal operation mode, the two channels on a branch should be
+ * filled together for the same SLOT#
+ * When in mirrored mode, Branch 1 replicate memory at Branch 0, so, the four
+ * channels on both branches should be filled
+ */
+
+/* Limits for i7300 */
+#define MAX_SLOTS 8
+#define MAX_BRANCHES 2
+#define MAX_CH_PER_BRANCH 2
+#define MAX_CHANNELS (MAX_CH_PER_BRANCH * MAX_BRANCHES)
+#define MAX_MIR 3
+
+#define to_channel(ch, branch) ((((branch)) << 1) | (ch))
+
+#define to_csrow(slot, ch, branch) \
+ (to_channel(ch, branch) | ((slot) << 2))
+
+/* Device name and register DID (Device ID) */
+struct i7300_dev_info {
+ const char *ctl_name; /* name for this device */
+ u16 fsb_mapping_errors; /* DID for the branchmap,control */
+};
+
+/* Table of devices attributes supported by this driver */
+static const struct i7300_dev_info i7300_devs[] = {
+ {
+ .ctl_name = "I7300",
+ .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7300_MCH_ERR,
+ },
+};
+
+struct i7300_dimm_info {
+ int megabytes; /* size, 0 means not present */
+};
+
+/* driver private data structure */
+struct i7300_pvt {
+ struct pci_dev *pci_dev_16_0_fsb_ctlr; /* 16.0 */
+ struct pci_dev *pci_dev_16_1_fsb_addr_map; /* 16.1 */
+ struct pci_dev *pci_dev_16_2_fsb_err_regs; /* 16.2 */
+ struct pci_dev *pci_dev_2x_0_fbd_branch[MAX_BRANCHES]; /* 21.0 and 22.0 */
+
+ u16 tolm; /* top of low memory */
+ u64 ambase; /* AMB BAR */
+
+ u32 mc_settings; /* Report several settings */
+ u32 mc_settings_a;
+
+ u16 mir[MAX_MIR]; /* Memory Interleave Reg*/
+
+ u16 mtr[MAX_SLOTS][MAX_BRANCHES]; /* Memory Technlogy Reg */
+ u16 ambpresent[MAX_CHANNELS]; /* AMB present regs */
+
+ /* DIMM information matrix, allocating architecture maximums */
+ struct i7300_dimm_info dimm_info[MAX_SLOTS][MAX_CHANNELS];
+
+ /* Temporary buffer for use when preparing error messages */
+ char *tmp_prt_buffer;
+};
+
+/* FIXME: Why do we need to have this static? */
+static struct edac_pci_ctl_info *i7300_pci;
+
+/***************************************************
+ * i7300 Register definitions for memory enumeration
+ ***************************************************/
+
+/*
+ * Device 16,
+ * Function 0: System Address (not documented)
+ * Function 1: Memory Branch Map, Control, Errors Register
+ */
+
+ /* OFFSETS for Function 0 */
+#define AMBASE 0x48 /* AMB Mem Mapped Reg Region Base */
+#define MAXCH 0x56 /* Max Channel Number */
+#define MAXDIMMPERCH 0x57 /* Max DIMM PER Channel Number */
+
+ /* OFFSETS for Function 1 */
+#define MC_SETTINGS 0x40
+ #define IS_MIRRORED(mc) ((mc) & (1 << 16))
+ #define IS_ECC_ENABLED(mc) ((mc) & (1 << 5))
+ #define IS_RETRY_ENABLED(mc) ((mc) & (1 << 31))
+ #define IS_SCRBALGO_ENHANCED(mc) ((mc) & (1 << 8))
+
+#define MC_SETTINGS_A 0x58
+ #define IS_SINGLE_MODE(mca) ((mca) & (1 << 14))
+
+#define TOLM 0x6C
+
+#define MIR0 0x80
+#define MIR1 0x84
+#define MIR2 0x88
+
+/*
+ * Note: Other Intel EDAC drivers use AMBPRESENT to identify if the available
+ * memory. From datasheet item 7.3.1 (FB-DIMM technology & organization), it
+ * seems that we cannot use this information directly for the same usage.
+ * Each memory slot may have up to 2 AMB interfaces, one for income and another
+ * for outcome interface to the next slot.
+ * For now, the driver just stores the AMB present registers, but rely only at
+ * the MTR info to detect memory.
+ * Datasheet is also not clear about how to map each AMBPRESENT registers to
+ * one of the 4 available channels.
+ */
+#define AMBPRESENT_0 0x64
+#define AMBPRESENT_1 0x66
+
+const static u16 mtr_regs[MAX_SLOTS] = {
+ 0x80, 0x84, 0x88, 0x8c,
+ 0x82, 0x86, 0x8a, 0x8e
+};
+
+/*
+ * Defines to extract the vaious fields from the
+ * MTRx - Memory Technology Registers
+ */
+#define MTR_DIMMS_PRESENT(mtr) ((mtr) & (1 << 8))
+#define MTR_DIMMS_ETHROTTLE(mtr) ((mtr) & (1 << 7))
+#define MTR_DRAM_WIDTH(mtr) (((mtr) & (1 << 6)) ? 8 : 4)
+#define MTR_DRAM_BANKS(mtr) (((mtr) & (1 << 5)) ? 8 : 4)
+#define MTR_DIMM_RANKS(mtr) (((mtr) & (1 << 4)) ? 1 : 0)
+#define MTR_DIMM_ROWS(mtr) (((mtr) >> 2) & 0x3)
+#define MTR_DRAM_BANKS_ADDR_BITS 2
+#define MTR_DIMM_ROWS_ADDR_BITS(mtr) (MTR_DIMM_ROWS(mtr) + 13)
+#define MTR_DIMM_COLS(mtr) ((mtr) & 0x3)
+#define MTR_DIMM_COLS_ADDR_BITS(mtr) (MTR_DIMM_COLS(mtr) + 10)
+
+#ifdef CONFIG_EDAC_DEBUG
+/* MTR NUMROW */
+static const char *numrow_toString[] = {
+ "8,192 - 13 rows",
+ "16,384 - 14 rows",
+ "32,768 - 15 rows",
+ "65,536 - 16 rows"
+};
+
+/* MTR NUMCOL */
+static const char *numcol_toString[] = {
+ "1,024 - 10 columns",
+ "2,048 - 11 columns",
+ "4,096 - 12 columns",
+ "reserved"
+};
+#endif
+
+/************************************************
+ * i7300 Register definitions for error detection
+ ************************************************/
+
+/*
+ * Device 16.1: FBD Error Registers
+ */
+#define FERR_FAT_FBD 0x98
+static const char *ferr_fat_fbd_name[] = {
+ [22] = "Non-Redundant Fast Reset Timeout",
+ [2] = ">Tmid Thermal event with intelligent throttling disabled",
+ [1] = "Memory or FBD configuration CRC read error",
+ [0] = "Memory Write error on non-redundant retry or "
+ "FBD configuration Write error on retry",
+};
+#define GET_FBD_FAT_IDX(fbderr) (fbderr & (3 << 28))
+#define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
+
+#define FERR_NF_FBD 0xa0
+static const char *ferr_nf_fbd_name[] = {
+ [24] = "DIMM-Spare Copy Completed",
+ [23] = "DIMM-Spare Copy Initiated",
+ [22] = "Redundant Fast Reset Timeout",
+ [21] = "Memory Write error on redundant retry",
+ [18] = "SPD protocol Error",
+ [17] = "FBD Northbound parity error on FBD Sync Status",
+ [16] = "Correctable Patrol Data ECC",
+ [15] = "Correctable Resilver- or Spare-Copy Data ECC",
+ [14] = "Correctable Mirrored Demand Data ECC",
+ [13] = "Correctable Non-Mirrored Demand Data ECC",
+ [11] = "Memory or FBD configuration CRC read error",
+ [10] = "FBD Configuration Write error on first attempt",
+ [9] = "Memory Write error on first attempt",
+ [8] = "Non-Aliased Uncorrectable Patrol Data ECC",
+ [7] = "Non-Aliased Uncorrectable Resilver- or Spare-Copy Data ECC",
+ [6] = "Non-Aliased Uncorrectable Mirrored Demand Data ECC",
+ [5] = "Non-Aliased Uncorrectable Non-Mirrored Demand Data ECC",
+ [4] = "Aliased Uncorrectable Patrol Data ECC",
+ [3] = "Aliased Uncorrectable Resilver- or Spare-Copy Data ECC",
+ [2] = "Aliased Uncorrectable Mirrored Demand Data ECC",
+ [1] = "Aliased Uncorrectable Non-Mirrored Demand Data ECC",
+ [0] = "Uncorrectable Data ECC on Replay",
+};
+#define GET_FBD_NF_IDX(fbderr) (fbderr & (3 << 28))
+#define FERR_NF_FBD_ERR_MASK ((1 << 24) | (1 << 23) | (1 << 22) | (1 << 21) |\
+ (1 << 18) | (1 << 17) | (1 << 16) | (1 << 15) |\
+ (1 << 14) | (1 << 13) | (1 << 11) | (1 << 10) |\
+ (1 << 9) | (1 << 8) | (1 << 7) | (1 << 6) |\
+ (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) |\
+ (1 << 1) | (1 << 0))
+
+#define EMASK_FBD 0xa8
+#define EMASK_FBD_ERR_MASK ((1 << 27) | (1 << 26) | (1 << 25) | (1 << 24) |\
+ (1 << 22) | (1 << 21) | (1 << 20) | (1 << 19) |\
+ (1 << 18) | (1 << 17) | (1 << 16) | (1 << 14) |\
+ (1 << 13) | (1 << 12) | (1 << 11) | (1 << 10) |\
+ (1 << 9) | (1 << 8) | (1 << 7) | (1 << 6) |\
+ (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) |\
+ (1 << 1) | (1 << 0))
+
+/*
+ * Device 16.2: Global Error Registers
+ */
+
+#define FERR_GLOBAL_HI 0x48
+static const char *ferr_global_hi_name[] = {
+ [3] = "FSB 3 Fatal Error",
+ [2] = "FSB 2 Fatal Error",
+ [1] = "FSB 1 Fatal Error",
+ [0] = "FSB 0 Fatal Error",
+};
+#define ferr_global_hi_is_fatal(errno) 1
+
+#define FERR_GLOBAL_LO 0x40
+static const char *ferr_global_lo_name[] = {
+ [31] = "Internal MCH Fatal Error",
+ [30] = "Intel QuickData Technology Device Fatal Error",
+ [29] = "FSB1 Fatal Error",
+ [28] = "FSB0 Fatal Error",
+ [27] = "FBD Channel 3 Fatal Error",
+ [26] = "FBD Channel 2 Fatal Error",
+ [25] = "FBD Channel 1 Fatal Error",
+ [24] = "FBD Channel 0 Fatal Error",
+ [23] = "PCI Express Device 7Fatal Error",
+ [22] = "PCI Express Device 6 Fatal Error",
+ [21] = "PCI Express Device 5 Fatal Error",
+ [20] = "PCI Express Device 4 Fatal Error",
+ [19] = "PCI Express Device 3 Fatal Error",
+ [18] = "PCI Express Device 2 Fatal Error",
+ [17] = "PCI Express Device 1 Fatal Error",
+ [16] = "ESI Fatal Error",
+ [15] = "Internal MCH Non-Fatal Error",
+ [14] = "Intel QuickData Technology Device Non Fatal Error",
+ [13] = "FSB1 Non-Fatal Error",
+ [12] = "FSB 0 Non-Fatal Error",
+ [11] = "FBD Channel 3 Non-Fatal Error",
+ [10] = "FBD Channel 2 Non-Fatal Error",
+ [9] = "FBD Channel 1 Non-Fatal Error",
+ [8] = "FBD Channel 0 Non-Fatal Error",
+ [7] = "PCI Express Device 7 Non-Fatal Error",
+ [6] = "PCI Express Device 6 Non-Fatal Error",
+ [5] = "PCI Express Device 5 Non-Fatal Error",
+ [4] = "PCI Express Device 4 Non-Fatal Error",
+ [3] = "PCI Express Device 3 Non-Fatal Error",
+ [2] = "PCI Express Device 2 Non-Fatal Error",
+ [1] = "PCI Express Device 1 Non-Fatal Error",
+ [0] = "ESI Non-Fatal Error",
+};
+#define ferr_global_lo_is_fatal(errno) ((errno < 16) ? 0 : 1)
+
+#define NRECMEMA 0xbe
+ #define NRECMEMA_BANK(v) (((v) >> 12) & 7)
+ #define NRECMEMA_RANK(v) (((v) >> 8) & 15)
+
+#define NRECMEMB 0xc0
+ #define NRECMEMB_IS_WR(v) ((v) & (1 << 31))
+ #define NRECMEMB_CAS(v) (((v) >> 16) & 0x1fff)
+ #define NRECMEMB_RAS(v) ((v) & 0xffff)
+
+#define REDMEMA 0xdc
+
+#define REDMEMB 0x7c
+ #define IS_SECOND_CH(v) ((v) * (1 << 17))
+
+#define RECMEMA 0xe0
+ #define RECMEMA_BANK(v) (((v) >> 12) & 7)
+ #define RECMEMA_RANK(v) (((v) >> 8) & 15)
+
+#define RECMEMB 0xe4
+ #define RECMEMB_IS_WR(v) ((v) & (1 << 31))
+ #define RECMEMB_CAS(v) (((v) >> 16) & 0x1fff)
+ #define RECMEMB_RAS(v) ((v) & 0xffff)
+
+/********************************************
+ * i7300 Functions related to error detection
+ ********************************************/
+
+/**
+ * get_err_from_table() - Gets the error message from a table
+ * @table: table name (array of char *)
+ * @size: number of elements at the table
+ * @pos: position of the element to be returned
+ *
+ * This is a small routine that gets the pos-th element of a table. If the
+ * element doesn't exist (or it is empty), it returns "reserved".
+ * Instead of calling it directly, the better is to call via the macro
+ * GET_ERR_FROM_TABLE(), that automatically checks the table size via
+ * ARRAY_SIZE() macro
+ */
+static const char *get_err_from_table(const char *table[], int size, int pos)
+{
+ if (unlikely(pos >= size))
+ return "Reserved";
+
+ if (unlikely(!table[pos]))
+ return "Reserved";
+
+ return table[pos];
+}
+
+#define GET_ERR_FROM_TABLE(table, pos) \
+ get_err_from_table(table, ARRAY_SIZE(table), pos)
+
+/**
+ * i7300_process_error_global() - Retrieve the hardware error information from
+ * the hardware global error registers and
+ * sends it to dmesg
+ * @mci: struct mem_ctl_info pointer
+ */
+static void i7300_process_error_global(struct mem_ctl_info *mci)
+{
+ struct i7300_pvt *pvt;
+ u32 errnum, value;
+ unsigned long errors;
+ const char *specific;
+ bool is_fatal;
+
+ pvt = mci->pvt_info;
+
+ /* read in the 1st FATAL error register */
+ pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+ FERR_GLOBAL_HI, &value);
+ if (unlikely(value)) {
+ errors = value;
+ errnum = find_first_bit(&errors,
+ ARRAY_SIZE(ferr_global_hi_name));
+ specific = GET_ERR_FROM_TABLE(ferr_global_hi_name, errnum);
+ is_fatal = ferr_global_hi_is_fatal(errnum);
+
+ /* Clear the error bit */
+ pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+ FERR_GLOBAL_HI, value);
+
+ goto error_global;
+ }
+
+ pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+ FERR_GLOBAL_LO, &value);
+ if (unlikely(value)) {
+ errors = value;
+ errnum = find_first_bit(&errors,
+ ARRAY_SIZE(ferr_global_lo_name));
+ specific = GET_ERR_FROM_TABLE(ferr_global_lo_name, errnum);
+ is_fatal = ferr_global_lo_is_fatal(errnum);
+
+ /* Clear the error bit */
+ pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+ FERR_GLOBAL_LO, value);
+
+ goto error_global;
+ }
+ return;
+
+error_global:
+ i7300_mc_printk(mci, KERN_EMERG, "%s misc error: %s\n",
+ is_fatal ? "Fatal" : "NOT fatal", specific);
+}
+
+/**
+ * i7300_process_fbd_error() - Retrieve the hardware error information from
+ * the FBD error registers and sends it via
+ * EDAC error API calls
+ * @mci: struct mem_ctl_info pointer
+ */
+static void i7300_process_fbd_error(struct mem_ctl_info *mci)
+{
+ struct i7300_pvt *pvt;
+ u32 errnum, value;
+ u16 val16;
+ unsigned branch, channel, bank, rank, cas, ras;
+ u32 syndrome;
+
+ unsigned long errors;
+ const char *specific;
+ bool is_wr;
+
+ pvt = mci->pvt_info;
+
+ /* read in the 1st FATAL error register */
+ pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ FERR_FAT_FBD, &value);
+ if (unlikely(value & FERR_FAT_FBD_ERR_MASK)) {
+ errors = value & FERR_FAT_FBD_ERR_MASK ;
+ errnum = find_first_bit(&errors,
+ ARRAY_SIZE(ferr_fat_fbd_name));
+ specific = GET_ERR_FROM_TABLE(ferr_fat_fbd_name, errnum);
+
+ branch = (GET_FBD_FAT_IDX(value) == 2) ? 1 : 0;
+ pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map,
+ NRECMEMA, &val16);
+ bank = NRECMEMA_BANK(val16);
+ rank = NRECMEMA_RANK(val16);
+
+ pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ NRECMEMB, &value);
+
+ is_wr = NRECMEMB_IS_WR(value);
+ cas = NRECMEMB_CAS(value);
+ ras = NRECMEMB_RAS(value);
+
+ snprintf(pvt->tmp_prt_buffer, PAGE_SIZE,
+ "FATAL (Branch=%d DRAM-Bank=%d %s "
+ "RAS=%d CAS=%d Err=0x%lx (%s))",
+ branch, bank,
+ is_wr ? "RDWR" : "RD",
+ ras, cas,
+ errors, specific);
+
+ /* Call the helper to output message */
+ edac_mc_handle_fbd_ue(mci, rank, branch << 1,
+ (branch << 1) + 1,
+ pvt->tmp_prt_buffer);
+ }
+
+ /* read in the 1st NON-FATAL error register */
+ pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ FERR_NF_FBD, &value);
+ if (unlikely(value & FERR_NF_FBD_ERR_MASK)) {
+ errors = value & FERR_NF_FBD_ERR_MASK;
+ errnum = find_first_bit(&errors,
+ ARRAY_SIZE(ferr_nf_fbd_name));
+ specific = GET_ERR_FROM_TABLE(ferr_nf_fbd_name, errnum);
+
+ /* Clear the error bit */
+ pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+ FERR_GLOBAL_LO, value);
+
+ pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ REDMEMA, &syndrome);
+
+ branch = (GET_FBD_FAT_IDX(value) == 2) ? 1 : 0;
+ pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map,
+ RECMEMA, &val16);
+ bank = RECMEMA_BANK(val16);
+ rank = RECMEMA_RANK(val16);
+
+ pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ RECMEMB, &value);
+
+ is_wr = RECMEMB_IS_WR(value);
+ cas = RECMEMB_CAS(value);
+ ras = RECMEMB_RAS(value);
+
+ pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ REDMEMB, &value);
+
+ channel = (branch << 1);
+ if (IS_SECOND_CH(value))
+ channel++;
+
+ /* Form out message */
+ snprintf(pvt->tmp_prt_buffer, PAGE_SIZE,
+ "Corrected error (Branch=%d, Channel %d), "
+ " DRAM-Bank=%d %s "
+ "RAS=%d CAS=%d, CE Err=0x%lx, Syndrome=0x%08x(%s))",
+ branch, channel,
+ bank,
+ is_wr ? "RDWR" : "RD",
+ ras, cas,
+ errors, syndrome, specific);
+
+ /*
+ * Call the helper to output message
+ * NOTE: Errors are reported per-branch, and not per-channel
+ * Currently, we don't know how to identify the right
+ * channel.
+ */
+ edac_mc_handle_fbd_ce(mci, rank, channel,
+ pvt->tmp_prt_buffer);
+ }
+ return;
+}
+
+/**
+ * i7300_check_error() - Calls the error checking subroutines
+ * @mci: struct mem_ctl_info pointer
+ */
+static void i7300_check_error(struct mem_ctl_info *mci)
+{
+ i7300_process_error_global(mci);
+ i7300_process_fbd_error(mci);
+};
+
+/**
+ * i7300_clear_error() - Clears the error registers
+ * @mci: struct mem_ctl_info pointer
+ */
+static void i7300_clear_error(struct mem_ctl_info *mci)
+{
+ struct i7300_pvt *pvt = mci->pvt_info;
+ u32 value;
+ /*
+ * All error values are RWC - we need to read and write 1 to the
+ * bit that we want to cleanup
+ */
+
+ /* Clear global error registers */
+ pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+ FERR_GLOBAL_HI, &value);
+ pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+ FERR_GLOBAL_HI, value);
+
+ pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+ FERR_GLOBAL_LO, &value);
+ pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+ FERR_GLOBAL_LO, value);
+
+ /* Clear FBD error registers */
+ pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ FERR_FAT_FBD, &value);
+ pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ FERR_FAT_FBD, value);
+
+ pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ FERR_NF_FBD, &value);
+ pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ FERR_NF_FBD, value);
+}
+
+/**
+ * i7300_enable_error_reporting() - Enable the memory reporting logic at the
+ * hardware
+ * @mci: struct mem_ctl_info pointer
+ */
+static void i7300_enable_error_reporting(struct mem_ctl_info *mci)
+{
+ struct i7300_pvt *pvt = mci->pvt_info;
+ u32 fbd_error_mask;
+
+ /* Read the FBD Error Mask Register */
+ pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ EMASK_FBD, &fbd_error_mask);
+
+ /* Enable with a '0' */
+ fbd_error_mask &= ~(EMASK_FBD_ERR_MASK);
+
+ pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ EMASK_FBD, fbd_error_mask);
+}
+
+/************************************************
+ * i7300 Functions related to memory enumberation
+ ************************************************/
+
+/**
+ * decode_mtr() - Decodes the MTR descriptor, filling the edac structs
+ * @pvt: pointer to the private data struct used by i7300 driver
+ * @slot: DIMM slot (0 to 7)
+ * @ch: Channel number within the branch (0 or 1)
+ * @branch: Branch number (0 or 1)
+ * @dinfo: Pointer to DIMM info where dimm size is stored
+ * @p_csrow: Pointer to the struct csrow_info that corresponds to that element
+ */
+static int decode_mtr(struct i7300_pvt *pvt,
+ int slot, int ch, int branch,
+ struct i7300_dimm_info *dinfo,
+ struct csrow_info *p_csrow,
+ u32 *nr_pages)
+{
+ int mtr, ans, addrBits, channel;
+
+ channel = to_channel(ch, branch);
+
+ mtr = pvt->mtr[slot][branch];
+ ans = MTR_DIMMS_PRESENT(mtr) ? 1 : 0;
+
+ debugf2("\tMTR%d CH%d: DIMMs are %s (mtr)\n",
+ slot, channel,
+ ans ? "Present" : "NOT Present");
+
+ /* Determine if there is a DIMM present in this DIMM slot */
+ if (!ans)
+ return 0;
+
+ /* Start with the number of bits for a Bank
+ * on the DRAM */
+ addrBits = MTR_DRAM_BANKS_ADDR_BITS;
+ /* Add thenumber of ROW bits */
+ addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr);
+ /* add the number of COLUMN bits */
+ addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
+ /* add the number of RANK bits */
+ addrBits += MTR_DIMM_RANKS(mtr);
+
+ addrBits += 6; /* add 64 bits per DIMM */
+ addrBits -= 20; /* divide by 2^^20 */
+ addrBits -= 3; /* 8 bits per bytes */
+
+ dinfo->megabytes = 1 << addrBits;
+ *nr_pages = dinfo->megabytes << 8;
+
+ debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
+
+ debugf2("\t\tELECTRICAL THROTTLING is %s\n",
+ MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled");
+
+ debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
+ debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANKS(mtr) ? "double" : "single");
+ debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]);
+ debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
+ debugf2("\t\tSIZE: %d MB\n", dinfo->megabytes);
+
+ p_csrow->grain = 8;
+ p_csrow->mtype = MEM_FB_DDR2;
+ p_csrow->csrow_idx = slot;
+ p_csrow->page_mask = 0;
+
+ /*
+ * The type of error detection actually depends of the
+ * mode of operation. When it is just one single memory chip, at
+ * socket 0, channel 0, it uses 8-byte-over-32-byte SECDED+ code.
+ * In normal or mirrored mode, it uses Lockstep mode,
+ * with the possibility of using an extended algorithm for x8 memories
+ * See datasheet Sections 7.3.6 to 7.3.8
+ */
+
+ if (IS_SINGLE_MODE(pvt->mc_settings_a)) {
+ p_csrow->edac_mode = EDAC_SECDED;
+ debugf2("\t\tECC code is 8-byte-over-32-byte SECDED+ code\n");
+ } else {
+ debugf2("\t\tECC code is on Lockstep mode\n");
+ if (MTR_DRAM_WIDTH(mtr) == 8)
+ p_csrow->edac_mode = EDAC_S8ECD8ED;
+ else
+ p_csrow->edac_mode = EDAC_S4ECD4ED;
+ }
+
+ /* ask what device type on this row */
+ if (MTR_DRAM_WIDTH(mtr) == 8) {
+ debugf2("\t\tScrub algorithm for x8 is on %s mode\n",
+ IS_SCRBALGO_ENHANCED(pvt->mc_settings) ?
+ "enhanced" : "normal");
+
+ p_csrow->dtype = DEV_X8;
+ } else
+ p_csrow->dtype = DEV_X4;
+
+ return mtr;
+}
+
+/**
+ * print_dimm_size() - Prints dump of the memory organization
+ * @pvt: pointer to the private data struct used by i7300 driver
+ *
+ * Useful for debug. If debug is disabled, this routine do nothing
+ */
+static void print_dimm_size(struct i7300_pvt *pvt)
+{
+#ifdef CONFIG_EDAC_DEBUG
+ struct i7300_dimm_info *dinfo;
+ char *p;
+ int space, n;
+ int channel, slot;
+
+ space = PAGE_SIZE;
+ p = pvt->tmp_prt_buffer;
+
+ n = snprintf(p, space, " ");
+ p += n;
+ space -= n;
+ for (channel = 0; channel < MAX_CHANNELS; channel++) {
+ n = snprintf(p, space, "channel %d | ", channel);
+ p += n;
+ space -= n;
+ }
+ debugf2("%s\n", pvt->tmp_prt_buffer);
+ p = pvt->tmp_prt_buffer;
+ space = PAGE_SIZE;
+ n = snprintf(p, space, "-------------------------------"
+ "------------------------------");
+ p += n;
+ space -= n;
+ debugf2("%s\n", pvt->tmp_prt_buffer);
+ p = pvt->tmp_prt_buffer;
+ space = PAGE_SIZE;
+
+ for (slot = 0; slot < MAX_SLOTS; slot++) {
+ n = snprintf(p, space, "csrow/SLOT %d ", slot);
+ p += n;
+ space -= n;
+
+ for (channel = 0; channel < MAX_CHANNELS; channel++) {
+ dinfo = &pvt->dimm_info[slot][channel];
+ n = snprintf(p, space, "%4d MB | ", dinfo->megabytes);
+ p += n;
+ space -= n;
+ }
+
+ debugf2("%s\n", pvt->tmp_prt_buffer);
+ p = pvt->tmp_prt_buffer;
+ space = PAGE_SIZE;
+ }
+
+ n = snprintf(p, space, "-------------------------------"
+ "------------------------------");
+ p += n;
+ space -= n;
+ debugf2("%s\n", pvt->tmp_prt_buffer);
+ p = pvt->tmp_prt_buffer;
+ space = PAGE_SIZE;
+#endif
+}
+
+/**
+ * i7300_init_csrows() - Initialize the 'csrows' table within
+ * the mci control structure with the
+ * addressing of memory.
+ * @mci: struct mem_ctl_info pointer
+ */
+static int i7300_init_csrows(struct mem_ctl_info *mci)
+{
+ struct i7300_pvt *pvt;
+ struct i7300_dimm_info *dinfo;
+ struct csrow_info *p_csrow;
+ int rc = -ENODEV;
+ int mtr;
+ int ch, branch, slot, channel;
+ u32 last_page = 0, nr_pages;
+
+ pvt = mci->pvt_info;
+
+ debugf2("Memory Technology Registers:\n");
+
+ /* Get the AMB present registers for the four channels */
+ for (branch = 0; branch < MAX_BRANCHES; branch++) {
+ /* Read and dump branch 0's MTRs */
+ channel = to_channel(0, branch);
+ pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
+ AMBPRESENT_0,
+ &pvt->ambpresent[channel]);
+ debugf2("\t\tAMB-present CH%d = 0x%x:\n",
+ channel, pvt->ambpresent[channel]);
+
+ channel = to_channel(1, branch);
+ pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
+ AMBPRESENT_1,
+ &pvt->ambpresent[channel]);
+ debugf2("\t\tAMB-present CH%d = 0x%x:\n",
+ channel, pvt->ambpresent[channel]);
+ }
+
+ /* Get the set of MTR[0-7] regs by each branch */
+ for (slot = 0; slot < MAX_SLOTS; slot++) {
+ int where = mtr_regs[slot];
+ for (branch = 0; branch < MAX_BRANCHES; branch++) {
+ pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
+ where,
+ &pvt->mtr[slot][branch]);
+ for (ch = 0; ch < MAX_BRANCHES; ch++) {
+ int channel = to_channel(ch, branch);
+
+ dinfo = &pvt->dimm_info[slot][channel];
+ p_csrow = &mci->csrows[slot];
+
+ mtr = decode_mtr(pvt, slot, ch, branch,
+ dinfo, p_csrow, &nr_pages);
+ /* if no DIMMS on this row, continue */
+ if (!MTR_DIMMS_PRESENT(mtr))
+ continue;
+
+ /* Update per_csrow memory count */
+ p_csrow->nr_pages += nr_pages;
+ p_csrow->first_page = last_page;
+ last_page += nr_pages;
+ p_csrow->last_page = last_page;
+
+ rc = 0;
+ }
+ }
+ }
+
+ return rc;
+}
+
+/**
+ * decode_mir() - Decodes Memory Interleave Register (MIR) info
+ * @int mir_no: number of the MIR register to decode
+ * @mir: array with the MIR data cached on the driver
+ */
+static void decode_mir(int mir_no, u16 mir[MAX_MIR])
+{
+ if (mir[mir_no] & 3)
+ debugf2("MIR%d: limit= 0x%x Branch(es) that participate:"
+ " %s %s\n",
+ mir_no,
+ (mir[mir_no] >> 4) & 0xfff,
+ (mir[mir_no] & 1) ? "B0" : "",
+ (mir[mir_no] & 2) ? "B1" : "");
+}
+
+/**
+ * i7300_get_mc_regs() - Get the contents of the MC enumeration registers
+ * @mci: struct mem_ctl_info pointer
+ *
+ * Data read is cached internally for its usage when needed
+ */
+static int i7300_get_mc_regs(struct mem_ctl_info *mci)
+{
+ struct i7300_pvt *pvt;
+ u32 actual_tolm;
+ int i, rc;
+
+ pvt = mci->pvt_info;
+
+ pci_read_config_dword(pvt->pci_dev_16_0_fsb_ctlr, AMBASE,
+ (u32 *) &pvt->ambase);
+
+ debugf2("AMBASE= 0x%lx\n", (long unsigned int)pvt->ambase);
+
+ /* Get the Branch Map regs */
+ pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, TOLM, &pvt->tolm);
+ pvt->tolm >>= 12;
+ debugf2("TOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm,
+ pvt->tolm);
+
+ actual_tolm = (u32) ((1000l * pvt->tolm) >> (30 - 28));
+ debugf2("Actual TOLM byte addr=%u.%03u GB (0x%x)\n",
+ actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28);
+
+ /* Get memory controller settings */
+ pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS,
+ &pvt->mc_settings);
+ pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS_A,
+ &pvt->mc_settings_a);
+
+ if (IS_SINGLE_MODE(pvt->mc_settings_a))
+ debugf0("Memory controller operating on single mode\n");
+ else
+ debugf0("Memory controller operating on %s mode\n",
+ IS_MIRRORED(pvt->mc_settings) ? "mirrored" : "non-mirrored");
+
+ debugf0("Error detection is %s\n",
+ IS_ECC_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
+ debugf0("Retry is %s\n",
+ IS_RETRY_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
+
+ /* Get Memory Interleave Range registers */
+ pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR0,
+ &pvt->mir[0]);
+ pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR1,
+ &pvt->mir[1]);
+ pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR2,
+ &pvt->mir[2]);
+
+ /* Decode the MIR regs */
+ for (i = 0; i < MAX_MIR; i++)
+ decode_mir(i, pvt->mir);
+
+ rc = i7300_init_csrows(mci);
+ if (rc < 0)
+ return rc;
+
+ /* Go and determine the size of each DIMM and place in an
+ * orderly matrix */
+ print_dimm_size(pvt);
+
+ return 0;
+}
+
+/*************************************************
+ * i7300 Functions related to device probe/release
+ *************************************************/
+
+/**
+ * i7300_put_devices() - Release the PCI devices
+ * @mci: struct mem_ctl_info pointer
+ */
+static void i7300_put_devices(struct mem_ctl_info *mci)
+{
+ struct i7300_pvt *pvt;
+ int branch;
+
+ pvt = mci->pvt_info;
+
+ /* Decrement usage count for devices */
+ for (branch = 0; branch < MAX_CH_PER_BRANCH; branch++)
+ pci_dev_put(pvt->pci_dev_2x_0_fbd_branch[branch]);
+ pci_dev_put(pvt->pci_dev_16_2_fsb_err_regs);
+ pci_dev_put(pvt->pci_dev_16_1_fsb_addr_map);
+}
+
+/**
+ * i7300_get_devices() - Find and perform 'get' operation on the MCH's
+ * device/functions we want to reference for this driver
+ * @mci: struct mem_ctl_info pointer
+ *
+ * Access and prepare the several devices for usage:
+ * I7300 devices used by this driver:
+ * Device 16, functions 0,1 and 2: PCI_DEVICE_ID_INTEL_I7300_MCH_ERR
+ * Device 21 function 0: PCI_DEVICE_ID_INTEL_I7300_MCH_FB0
+ * Device 22 function 0: PCI_DEVICE_ID_INTEL_I7300_MCH_FB1
+ */
+static int __devinit i7300_get_devices(struct mem_ctl_info *mci)
+{
+ struct i7300_pvt *pvt;
+ struct pci_dev *pdev;
+
+ pvt = mci->pvt_info;
+
+ /* Attempt to 'get' the MCH register we want */
+ pdev = NULL;
+ while (!pvt->pci_dev_16_1_fsb_addr_map ||
+ !pvt->pci_dev_16_2_fsb_err_regs) {
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev);
+ if (!pdev) {
+ /* End of list, leave */
+ i7300_printk(KERN_ERR,
+ "'system address,Process Bus' "
+ "device not found:"
+ "vendor 0x%x device 0x%x ERR funcs "
+ "(broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
+ goto error;
+ }
+
+ /* Store device 16 funcs 1 and 2 */
+ switch (PCI_FUNC(pdev->devfn)) {
+ case 1:
+ pvt->pci_dev_16_1_fsb_addr_map = pdev;
+ break;
+ case 2:
+ pvt->pci_dev_16_2_fsb_err_regs = pdev;
+ break;
+ }
+ }
+
+ debugf1("System Address, processor bus- PCI Bus ID: %s %x:%x\n",
+ pci_name(pvt->pci_dev_16_0_fsb_ctlr),
+ pvt->pci_dev_16_0_fsb_ctlr->vendor,
+ pvt->pci_dev_16_0_fsb_ctlr->device);
+ debugf1("Branchmap, control and errors - PCI Bus ID: %s %x:%x\n",
+ pci_name(pvt->pci_dev_16_1_fsb_addr_map),
+ pvt->pci_dev_16_1_fsb_addr_map->vendor,
+ pvt->pci_dev_16_1_fsb_addr_map->device);
+ debugf1("FSB Error Regs - PCI Bus ID: %s %x:%x\n",
+ pci_name(pvt->pci_dev_16_2_fsb_err_regs),
+ pvt->pci_dev_16_2_fsb_err_regs->vendor,
+ pvt->pci_dev_16_2_fsb_err_regs->device);
+
+ pvt->pci_dev_2x_0_fbd_branch[0] = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I7300_MCH_FB0,
+ NULL);
+ if (!pvt->pci_dev_2x_0_fbd_branch[0]) {
+ i7300_printk(KERN_ERR,
+ "MC: 'BRANCH 0' device not found:"
+ "vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_FB0);
+ goto error;
+ }
+
+ pvt->pci_dev_2x_0_fbd_branch[1] = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I7300_MCH_FB1,
+ NULL);
+ if (!pvt->pci_dev_2x_0_fbd_branch[1]) {
+ i7300_printk(KERN_ERR,
+ "MC: 'BRANCH 1' device not found:"
+ "vendor 0x%x device 0x%x Func 0 "
+ "(broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I7300_MCH_FB1);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ i7300_put_devices(mci);
+ return -ENODEV;
+}
+
+/**
+ * i7300_init_one() - Probe for one instance of the device
+ * @pdev: struct pci_dev pointer
+ * @id: struct pci_device_id pointer - currently unused
+ */
+static int __devinit i7300_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct mem_ctl_info *mci;
+ struct i7300_pvt *pvt;
+ int num_channels;
+ int num_dimms_per_channel;
+ int num_csrows;
+ int rc;
+
+ /* wake up device */
+ rc = pci_enable_device(pdev);
+ if (rc == -EIO)
+ return rc;
+
+ debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n",
+ __func__,
+ pdev->bus->number,
+ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+
+ /* We only are looking for func 0 of the set */
+ if (PCI_FUNC(pdev->devfn) != 0)
+ return -ENODEV;
+
+ /* As we don't have a motherboard identification routine to determine
+ * actual number of slots/dimms per channel, we thus utilize the
+ * resource as specified by the chipset. Thus, we might have
+ * have more DIMMs per channel than actually on the mobo, but this
+ * allows the driver to support upto the chipset max, without
+ * some fancy mobo determination.
+ */
+ num_dimms_per_channel = MAX_SLOTS;
+ num_channels = MAX_CHANNELS;
+ num_csrows = MAX_SLOTS * MAX_CHANNELS;
+
+ debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n",
+ __func__, num_channels, num_dimms_per_channel, num_csrows);
+
+ /* allocate a new MC control structure */
+ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0);
+
+ if (mci == NULL)
+ return -ENOMEM;
+
+ debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+
+ mci->dev = &pdev->dev; /* record ptr to the generic device */
+
+ pvt = mci->pvt_info;
+ pvt->pci_dev_16_0_fsb_ctlr = pdev; /* Record this device in our private */
+
+ pvt->tmp_prt_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!pvt->tmp_prt_buffer) {
+ edac_mc_free(mci);
+ return -ENOMEM;
+ }
+
+ /* 'get' the pci devices we want to reserve for our use */
+ if (i7300_get_devices(mci))
+ goto fail0;
+
+ mci->mc_idx = 0;
+ mci->mtype_cap = MEM_FLAG_FB_DDR2;
+ mci->edac_ctl_cap = EDAC_FLAG_NONE;
+ mci->edac_cap = EDAC_FLAG_NONE;
+ mci->mod_name = "i7300_edac.c";
+ mci->mod_ver = I7300_REVISION;
+ mci->ctl_name = i7300_devs[0].ctl_name;
+ mci->dev_name = pci_name(pdev);
+ mci->ctl_page_to_phys = NULL;
+
+ /* Set the function pointer to an actual operation function */
+ mci->edac_check = i7300_check_error;
+
+ /* initialize the MC control structure 'csrows' table
+ * with the mapping and control information */
+ if (i7300_get_mc_regs(mci)) {
+ debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n"
+ " because i7300_init_csrows() returned nonzero "
+ "value\n");
+ mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */
+ } else {
+ debugf1("MC: Enable error reporting now\n");
+ i7300_enable_error_reporting(mci);
+ }
+
+ /* add this new MC control structure to EDAC's list of MCs */
+ if (edac_mc_add_mc(mci)) {
+ debugf0("MC: " __FILE__
+ ": %s(): failed edac_mc_add_mc()\n", __func__);
+ /* FIXME: perhaps some code should go here that disables error
+ * reporting if we just enabled it
+ */
+ goto fail1;
+ }
+
+ i7300_clear_error(mci);
+
+ /* allocating generic PCI control info */
+ i7300_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!i7300_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
+ return 0;
+
+ /* Error exit unwinding stack */
+fail1:
+
+ i7300_put_devices(mci);
+
+fail0:
+ kfree(pvt->tmp_prt_buffer);
+ edac_mc_free(mci);
+ return -ENODEV;
+}
+
+/**
+ * i7300_remove_one() - Remove the driver
+ * @pdev: struct pci_dev pointer
+ */
+static void __devexit i7300_remove_one(struct pci_dev *pdev)
+{
+ struct mem_ctl_info *mci;
+ char *tmp;
+
+ debugf0(__FILE__ ": %s()\n", __func__);
+
+ if (i7300_pci)
+ edac_pci_release_generic_ctl(i7300_pci);
+
+ mci = edac_mc_del_mc(&pdev->dev);
+ if (!mci)
+ return;
+
+ tmp = ((struct i7300_pvt *)mci->pvt_info)->tmp_prt_buffer;
+
+ /* retrieve references to resources, and free those resources */
+ i7300_put_devices(mci);
+
+ kfree(tmp);
+ edac_mc_free(mci);
+}
+
+/*
+ * pci_device_id: table for which devices we are looking for
+ *
+ * Has only 8086:360c PCI ID
+ */
+static const struct pci_device_id i7300_pci_tbl[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_ERR)},
+ {0,} /* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i7300_pci_tbl);
+
+/*
+ * i7300_driver: pci_driver structure for this module
+ */
+static struct pci_driver i7300_driver = {
+ .name = "i7300_edac",
+ .probe = i7300_init_one,
+ .remove = __devexit_p(i7300_remove_one),
+ .id_table = i7300_pci_tbl,
+};
+
+/**
+ * i7300_init() - Registers the driver
+ */
+static int __init i7300_init(void)
+{
+ int pci_rc;
+
+ debugf2("MC: " __FILE__ ": %s()\n", __func__);
+
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
+ pci_rc = pci_register_driver(&i7300_driver);
+
+ return (pci_rc < 0) ? pci_rc : 0;
+}
+
+/**
+ * i7300_init() - Unregisters the driver
+ */
+static void __exit i7300_exit(void)
+{
+ debugf2("MC: " __FILE__ ": %s()\n", __func__);
+ pci_unregister_driver(&i7300_driver);
+}
+
+module_init(i7300_init);
+module_exit(i7300_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("MC Driver for Intel I7300 memory controllers - "
+ I7300_REVISION);
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 0fd5b85a0f75..362861c15779 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -39,6 +39,14 @@
#include "edac_core.h"
+/* Static vars */
+static LIST_HEAD(i7core_edac_list);
+static DEFINE_MUTEX(i7core_edac_lock);
+static int probed;
+
+static int use_pci_fixup;
+module_param(use_pci_fixup, int, 0444);
+MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices");
/*
* This is used for Nehalem-EP and Nehalem-EX devices, where the non-core
* registers start at bus 255, and are not reported by BIOS.
@@ -212,8 +220,8 @@ struct pci_id_descr {
};
struct pci_id_table {
- struct pci_id_descr *descr;
- int n_devs;
+ const struct pci_id_descr *descr;
+ int n_devs;
};
struct i7core_dev {
@@ -235,8 +243,6 @@ struct i7core_pvt {
struct i7core_inject inject;
struct i7core_channel channel[NUM_CHANS];
- int channels; /* Number of active channels */
-
int ce_count_available;
int csrow_map[NUM_CHANS][MAX_DIMMS];
@@ -261,22 +267,22 @@ struct i7core_pvt {
/* Count indicator to show errors not got */
unsigned mce_overrun;
-};
-/* Static vars */
-static LIST_HEAD(i7core_edac_list);
-static DEFINE_MUTEX(i7core_edac_lock);
+ /* Struct to control EDAC polling */
+ struct edac_pci_ctl_info *i7core_pci;
+};
#define PCI_DESCR(device, function, device_id) \
.dev = (device), \
.func = (function), \
.dev_id = (device_id)
-struct pci_id_descr pci_dev_descr_i7core_nehalem[] = {
+static const struct pci_id_descr pci_dev_descr_i7core_nehalem[] = {
/* Memory controller */
{ PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) },
{ PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) },
- /* Exists only for RDIMM */
+
+ /* Exists only for RDIMM */
{ PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS), .optional = 1 },
{ PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) },
@@ -297,19 +303,9 @@ struct pci_id_descr pci_dev_descr_i7core_nehalem[] = {
{ PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) },
{ PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) },
{ PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC) },
-
- /* Generic Non-core registers */
- /*
- * This is the PCI device on i7core and on Xeon 35xx (8086:2c41)
- * On Xeon 55xx, however, it has a different id (8086:2c40). So,
- * the probing code needs to test for the other address in case of
- * failure of this one
- */
- { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NONCORE) },
-
};
-struct pci_id_descr pci_dev_descr_lynnfield[] = {
+static const struct pci_id_descr pci_dev_descr_lynnfield[] = {
{ PCI_DESCR( 3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR) },
{ PCI_DESCR( 3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD) },
{ PCI_DESCR( 3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST) },
@@ -323,15 +319,9 @@ struct pci_id_descr pci_dev_descr_lynnfield[] = {
{ PCI_DESCR( 5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) },
{ PCI_DESCR( 5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) },
{ PCI_DESCR( 5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC) },
-
- /*
- * This is the PCI device has an alternate address on some
- * processors like Core i7 860
- */
- { PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) },
};
-struct pci_id_descr pci_dev_descr_i7core_westmere[] = {
+static const struct pci_id_descr pci_dev_descr_i7core_westmere[] = {
/* Memory controller */
{ PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2) },
{ PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2) },
@@ -356,17 +346,14 @@ struct pci_id_descr pci_dev_descr_i7core_westmere[] = {
{ PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2) },
{ PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2) },
{ PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2) },
-
- /* Generic Non-core registers */
- { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2) },
-
};
-#define PCI_ID_TABLE_ENTRY(A) { A, ARRAY_SIZE(A) }
-struct pci_id_table pci_dev_table[] = {
+#define PCI_ID_TABLE_ENTRY(A) { .descr=A, .n_devs = ARRAY_SIZE(A) }
+static const struct pci_id_table pci_dev_table[] = {
PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_nehalem),
PCI_ID_TABLE_ENTRY(pci_dev_descr_lynnfield),
PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_westmere),
+ {0,} /* 0 terminated list. */
};
/*
@@ -378,8 +365,6 @@ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = {
{0,} /* 0 terminated list. */
};
-static struct edac_pci_ctl_info *i7core_pci;
-
/****************************************************************************
Anciliary status routines
****************************************************************************/
@@ -442,6 +427,36 @@ static struct i7core_dev *get_i7core_dev(u8 socket)
return NULL;
}
+static struct i7core_dev *alloc_i7core_dev(u8 socket,
+ const struct pci_id_table *table)
+{
+ struct i7core_dev *i7core_dev;
+
+ i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL);
+ if (!i7core_dev)
+ return NULL;
+
+ i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * table->n_devs,
+ GFP_KERNEL);
+ if (!i7core_dev->pdev) {
+ kfree(i7core_dev);
+ return NULL;
+ }
+
+ i7core_dev->socket = socket;
+ i7core_dev->n_devs = table->n_devs;
+ list_add_tail(&i7core_dev->list, &i7core_edac_list);
+
+ return i7core_dev;
+}
+
+static void free_i7core_dev(struct i7core_dev *i7core_dev)
+{
+ list_del(&i7core_dev->list);
+ kfree(i7core_dev->pdev);
+ kfree(i7core_dev);
+}
+
/****************************************************************************
Memory check routines
****************************************************************************/
@@ -484,7 +499,7 @@ static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot,
* to add a fake description for csrows.
* So, this driver is attributing one DIMM memory for one csrow.
*/
-static int i7core_get_active_channels(u8 socket, unsigned *channels,
+static int i7core_get_active_channels(const u8 socket, unsigned *channels,
unsigned *csrows)
{
struct pci_dev *pdev = NULL;
@@ -545,12 +560,13 @@ static int i7core_get_active_channels(u8 socket, unsigned *channels,
return 0;
}
-static int get_dimm_config(struct mem_ctl_info *mci, int *csrow)
+static int get_dimm_config(const struct mem_ctl_info *mci)
{
struct i7core_pvt *pvt = mci->pvt_info;
struct csrow_info *csr;
struct pci_dev *pdev;
int i, j;
+ int csrow = 0;
unsigned long last_page = 0;
enum edac_type mode;
enum mem_type mtype;
@@ -664,13 +680,9 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow)
RANKOFFSET(dimm_dod[j]),
banks, ranks, rows, cols);
-#if PAGE_SHIFT > 20
- npages = size >> (PAGE_SHIFT - 20);
-#else
- npages = size << (20 - PAGE_SHIFT);
-#endif
+ npages = MiB_TO_PAGES(size);
- csr = &mci->csrows[*csrow];
+ csr = &mci->csrows[csrow];
csr->first_page = last_page + 1;
last_page += npages;
csr->last_page = last_page;
@@ -678,13 +690,13 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow)
csr->page_mask = 0;
csr->grain = 8;
- csr->csrow_idx = *csrow;
+ csr->csrow_idx = csrow;
csr->nr_channels = 1;
csr->channels[0].chan_idx = i;
csr->channels[0].ce_count = 0;
- pvt->csrow_map[i][j] = *csrow;
+ pvt->csrow_map[i][j] = csrow;
switch (banks) {
case 4:
@@ -703,7 +715,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow)
csr->edac_mode = mode;
csr->mtype = mtype;
- (*csrow)++;
+ csrow++;
}
pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]);
@@ -736,7 +748,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow)
we're disabling error injection on all write calls to the sysfs nodes that
controls the error code injection.
*/
-static int disable_inject(struct mem_ctl_info *mci)
+static int disable_inject(const struct mem_ctl_info *mci)
{
struct i7core_pvt *pvt = mci->pvt_info;
@@ -921,7 +933,7 @@ DECLARE_ADDR_MATCH(bank, 32);
DECLARE_ADDR_MATCH(page, 0x10000);
DECLARE_ADDR_MATCH(col, 0x4000);
-static int write_and_test(struct pci_dev *dev, int where, u32 val)
+static int write_and_test(struct pci_dev *dev, const int where, const u32 val)
{
u32 read;
int count;
@@ -1120,35 +1132,34 @@ DECLARE_COUNTER(2);
* Sysfs struct
*/
-
-static struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = {
+static const struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = {
ATTR_ADDR_MATCH(channel),
ATTR_ADDR_MATCH(dimm),
ATTR_ADDR_MATCH(rank),
ATTR_ADDR_MATCH(bank),
ATTR_ADDR_MATCH(page),
ATTR_ADDR_MATCH(col),
- { .attr = { .name = NULL } }
+ { } /* End of list */
};
-static struct mcidev_sysfs_group i7core_inject_addrmatch = {
+static const struct mcidev_sysfs_group i7core_inject_addrmatch = {
.name = "inject_addrmatch",
.mcidev_attr = i7core_addrmatch_attrs,
};
-static struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = {
+static const struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = {
ATTR_COUNTER(0),
ATTR_COUNTER(1),
ATTR_COUNTER(2),
{ .attr = { .name = NULL } }
};
-static struct mcidev_sysfs_group i7core_udimm_counters = {
+static const struct mcidev_sysfs_group i7core_udimm_counters = {
.name = "all_channel_counts",
.mcidev_attr = i7core_udimm_counters_attrs,
};
-static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = {
+static const struct mcidev_sysfs_attribute i7core_sysfs_rdimm_attrs[] = {
{
.attr = {
.name = "inject_section",
@@ -1180,8 +1191,44 @@ static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = {
.show = i7core_inject_enable_show,
.store = i7core_inject_enable_store,
},
- { .attr = { .name = NULL } }, /* Reserved for udimm counters */
- { .attr = { .name = NULL } }
+ { } /* End of list */
+};
+
+static const struct mcidev_sysfs_attribute i7core_sysfs_udimm_attrs[] = {
+ {
+ .attr = {
+ .name = "inject_section",
+ .mode = (S_IRUGO | S_IWUSR)
+ },
+ .show = i7core_inject_section_show,
+ .store = i7core_inject_section_store,
+ }, {
+ .attr = {
+ .name = "inject_type",
+ .mode = (S_IRUGO | S_IWUSR)
+ },
+ .show = i7core_inject_type_show,
+ .store = i7core_inject_type_store,
+ }, {
+ .attr = {
+ .name = "inject_eccmask",
+ .mode = (S_IRUGO | S_IWUSR)
+ },
+ .show = i7core_inject_eccmask_show,
+ .store = i7core_inject_eccmask_store,
+ }, {
+ .grp = &i7core_inject_addrmatch,
+ }, {
+ .attr = {
+ .name = "inject_enable",
+ .mode = (S_IRUGO | S_IWUSR)
+ },
+ .show = i7core_inject_enable_show,
+ .store = i7core_inject_enable_store,
+ }, {
+ .grp = &i7core_udimm_counters,
+ },
+ { } /* End of list */
};
/****************************************************************************
@@ -1189,7 +1236,7 @@ static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = {
****************************************************************************/
/*
- * i7core_put_devices 'put' all the devices that we have
+ * i7core_put_all_devices 'put' all the devices that we have
* reserved via 'get'
*/
static void i7core_put_devices(struct i7core_dev *i7core_dev)
@@ -1206,23 +1253,23 @@ static void i7core_put_devices(struct i7core_dev *i7core_dev)
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
pci_dev_put(pdev);
}
- kfree(i7core_dev->pdev);
- list_del(&i7core_dev->list);
- kfree(i7core_dev);
}
static void i7core_put_all_devices(void)
{
struct i7core_dev *i7core_dev, *tmp;
- list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list)
+ list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) {
i7core_put_devices(i7core_dev);
+ free_i7core_dev(i7core_dev);
+ }
}
-static void __init i7core_xeon_pci_fixup(struct pci_id_table *table)
+static void __init i7core_xeon_pci_fixup(const struct pci_id_table *table)
{
struct pci_dev *pdev = NULL;
int i;
+
/*
* On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses
* aren't announced by acpi. So, we need to use a legacy scan probing
@@ -1257,16 +1304,18 @@ static unsigned i7core_pci_lastbus(void)
}
/*
- * i7core_get_devices Find and perform 'get' operation on the MCH's
+ * i7core_get_all_devices Find and perform 'get' operation on the MCH's
* device/functions we want to reference for this driver
*
* Need to 'get' device 16 func 1 and func 2
*/
-int i7core_get_onedevice(struct pci_dev **prev, int devno,
- struct pci_id_descr *dev_descr, unsigned n_devs,
- unsigned last_bus)
+static int i7core_get_onedevice(struct pci_dev **prev,
+ const struct pci_id_table *table,
+ const unsigned devno,
+ const unsigned last_bus)
{
struct i7core_dev *i7core_dev;
+ const struct pci_id_descr *dev_descr = &table->descr[devno];
struct pci_dev *pdev = NULL;
u8 bus = 0;
@@ -1275,20 +1324,6 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno,
pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
dev_descr->dev_id, *prev);
- /*
- * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs
- * is at addr 8086:2c40, instead of 8086:2c41. So, we need
- * to probe for the alternate address in case of failure
- */
- if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev)
- pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev);
-
- if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev)
- pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT,
- *prev);
-
if (!pdev) {
if (*prev) {
*prev = pdev;
@@ -1315,18 +1350,11 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno,
i7core_dev = get_i7core_dev(socket);
if (!i7core_dev) {
- i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL);
- if (!i7core_dev)
- return -ENOMEM;
- i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * n_devs,
- GFP_KERNEL);
- if (!i7core_dev->pdev) {
- kfree(i7core_dev);
+ i7core_dev = alloc_i7core_dev(socket, table);
+ if (!i7core_dev) {
+ pci_dev_put(pdev);
return -ENOMEM;
}
- i7core_dev->socket = socket;
- i7core_dev->n_devs = n_devs;
- list_add_tail(&i7core_dev->list, &i7core_edac_list);
}
if (i7core_dev->pdev[devno]) {
@@ -1368,27 +1396,31 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno,
dev_descr->func,
PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+ /*
+ * As stated on drivers/pci/search.c, the reference count for
+ * @from is always decremented if it is not %NULL. So, as we need
+ * to get all devices up to null, we need to do a get for the device
+ */
+ pci_dev_get(pdev);
+
*prev = pdev;
return 0;
}
-static int i7core_get_devices(struct pci_id_table *table)
+static int i7core_get_all_devices(void)
{
int i, rc, last_bus;
struct pci_dev *pdev = NULL;
- struct pci_id_descr *dev_descr;
+ const struct pci_id_table *table = pci_dev_table;
last_bus = i7core_pci_lastbus();
while (table && table->descr) {
- dev_descr = table->descr;
for (i = 0; i < table->n_devs; i++) {
pdev = NULL;
do {
- rc = i7core_get_onedevice(&pdev, i,
- &dev_descr[i],
- table->n_devs,
+ rc = i7core_get_onedevice(&pdev, table, i,
last_bus);
if (rc < 0) {
if (i == 0) {
@@ -1404,7 +1436,6 @@ static int i7core_get_devices(struct pci_id_table *table)
}
return 0;
- return 0;
}
static int mci_bind_devs(struct mem_ctl_info *mci,
@@ -1414,10 +1445,6 @@ static int mci_bind_devs(struct mem_ctl_info *mci,
struct pci_dev *pdev;
int i, func, slot;
- /* Associates i7core_dev and mci for future usage */
- pvt->i7core_dev = i7core_dev;
- i7core_dev->mci = mci;
-
pvt->is_registered = 0;
for (i = 0; i < i7core_dev->n_devs; i++) {
pdev = i7core_dev->pdev[i];
@@ -1448,15 +1475,6 @@ static int mci_bind_devs(struct mem_ctl_info *mci,
pvt->is_registered = 1;
}
- /*
- * Add extra nodes to count errors on udimm
- * For registered memory, this is not needed, since the counters
- * are already displayed at the standard locations
- */
- if (!pvt->is_registered)
- i7core_sysfs_attrs[ARRAY_SIZE(i7core_sysfs_attrs)-2].grp =
- &i7core_udimm_counters;
-
return 0;
error:
@@ -1470,7 +1488,9 @@ error:
Error check routines
****************************************************************************/
static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci,
- int chan, int dimm, int add)
+ const int chan,
+ const int dimm,
+ const int add)
{
char *msg;
struct i7core_pvt *pvt = mci->pvt_info;
@@ -1487,7 +1507,10 @@ static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci,
}
static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci,
- int chan, int new0, int new1, int new2)
+ const int chan,
+ const int new0,
+ const int new1,
+ const int new2)
{
struct i7core_pvt *pvt = mci->pvt_info;
int add0 = 0, add1 = 0, add2 = 0;
@@ -1641,7 +1664,7 @@ static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci)
* fields
*/
static void i7core_mce_output_error(struct mem_ctl_info *mci,
- struct mce *m)
+ const struct mce *m)
{
struct i7core_pvt *pvt = mci->pvt_info;
char *type, *optype, *err, *msg;
@@ -1845,28 +1868,85 @@ static int i7core_mce_check_error(void *priv, struct mce *mce)
return 1;
}
-static int i7core_register_mci(struct i7core_dev *i7core_dev,
- int num_channels, int num_csrows)
+static void i7core_pci_ctl_create(struct i7core_pvt *pvt)
+{
+ pvt->i7core_pci = edac_pci_create_generic_ctl(
+ &pvt->i7core_dev->pdev[0]->dev,
+ EDAC_MOD_STR);
+ if (unlikely(!pvt->i7core_pci))
+ pr_warn("Unable to setup PCI error report via EDAC\n");
+}
+
+static void i7core_pci_ctl_release(struct i7core_pvt *pvt)
+{
+ if (likely(pvt->i7core_pci))
+ edac_pci_release_generic_ctl(pvt->i7core_pci);
+ else
+ i7core_printk(KERN_ERR,
+ "Couldn't find mem_ctl_info for socket %d\n",
+ pvt->i7core_dev->socket);
+ pvt->i7core_pci = NULL;
+}
+
+static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
+{
+ struct mem_ctl_info *mci = i7core_dev->mci;
+ struct i7core_pvt *pvt;
+
+ if (unlikely(!mci || !mci->pvt_info)) {
+ debugf0("MC: " __FILE__ ": %s(): dev = %p\n",
+ __func__, &i7core_dev->pdev[0]->dev);
+
+ i7core_printk(KERN_ERR, "Couldn't find mci handler\n");
+ return;
+ }
+
+ pvt = mci->pvt_info;
+
+ debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
+ __func__, mci, &i7core_dev->pdev[0]->dev);
+
+ /* Disable MCE NMI handler */
+ edac_mce_unregister(&pvt->edac_mce);
+
+ /* Disable EDAC polling */
+ i7core_pci_ctl_release(pvt);
+
+ /* Remove MC sysfs nodes */
+ edac_mc_del_mc(mci->dev);
+
+ debugf1("%s: free mci struct\n", mci->ctl_name);
+ kfree(mci->ctl_name);
+ edac_mc_free(mci);
+ i7core_dev->mci = NULL;
+}
+
+static int i7core_register_mci(struct i7core_dev *i7core_dev)
{
struct mem_ctl_info *mci;
struct i7core_pvt *pvt;
- int csrow = 0;
- int rc;
+ int rc, channels, csrows;
+
+ /* Check the number of active and not disabled channels */
+ rc = i7core_get_active_channels(i7core_dev->socket, &channels, &csrows);
+ if (unlikely(rc < 0))
+ return rc;
/* allocate a new MC control structure */
- mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels,
- i7core_dev->socket);
+ mci = edac_mc_alloc(sizeof(*pvt), csrows, channels, i7core_dev->socket);
if (unlikely(!mci))
return -ENOMEM;
- debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
-
- /* record ptr to the generic device */
- mci->dev = &i7core_dev->pdev[0]->dev;
+ debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
+ __func__, mci, &i7core_dev->pdev[0]->dev);
pvt = mci->pvt_info;
memset(pvt, 0, sizeof(*pvt));
+ /* Associates i7core_dev and mci for future usage */
+ pvt->i7core_dev = i7core_dev;
+ i7core_dev->mci = mci;
+
/*
* FIXME: how to handle RDDR3 at MCI level? It is possible to have
* Mixed RDDR3/UDDR3 with Nehalem, provided that they are on different
@@ -1881,17 +1961,23 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev,
i7core_dev->socket);
mci->dev_name = pci_name(i7core_dev->pdev[0]);
mci->ctl_page_to_phys = NULL;
- mci->mc_driver_sysfs_attributes = i7core_sysfs_attrs;
- /* Set the function pointer to an actual operation function */
- mci->edac_check = i7core_check_error;
/* Store pci devices at mci for faster access */
rc = mci_bind_devs(mci, i7core_dev);
if (unlikely(rc < 0))
- goto fail;
+ goto fail0;
+
+ if (pvt->is_registered)
+ mci->mc_driver_sysfs_attributes = i7core_sysfs_rdimm_attrs;
+ else
+ mci->mc_driver_sysfs_attributes = i7core_sysfs_udimm_attrs;
/* Get dimm basic config */
- get_dimm_config(mci, &csrow);
+ get_dimm_config(mci);
+ /* record ptr to the generic device */
+ mci->dev = &i7core_dev->pdev[0]->dev;
+ /* Set the function pointer to an actual operation function */
+ mci->edac_check = i7core_check_error;
/* add this new MC control structure to EDAC's list of MCs */
if (unlikely(edac_mc_add_mc(mci))) {
@@ -1902,19 +1988,7 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev,
*/
rc = -EINVAL;
- goto fail;
- }
-
- /* allocating generic PCI control info */
- i7core_pci = edac_pci_create_generic_ctl(&i7core_dev->pdev[0]->dev,
- EDAC_MOD_STR);
- if (unlikely(!i7core_pci)) {
- printk(KERN_WARNING
- "%s(): Unable to create PCI control\n",
- __func__);
- printk(KERN_WARNING
- "%s(): PCI error report via EDAC not setup\n",
- __func__);
+ goto fail0;
}
/* Default error mask is any memory */
@@ -1925,19 +1999,28 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev,
pvt->inject.page = -1;
pvt->inject.col = -1;
+ /* allocating generic PCI control info */
+ i7core_pci_ctl_create(pvt);
+
/* Registers on edac_mce in order to receive memory errors */
pvt->edac_mce.priv = mci;
pvt->edac_mce.check_error = i7core_mce_check_error;
-
rc = edac_mce_register(&pvt->edac_mce);
if (unlikely(rc < 0)) {
debugf0("MC: " __FILE__
": %s(): failed edac_mce_register()\n", __func__);
+ goto fail1;
}
-fail:
- if (rc < 0)
- edac_mc_free(mci);
+ return 0;
+
+fail1:
+ i7core_pci_ctl_release(pvt);
+ edac_mc_del_mc(mci->dev);
+fail0:
+ kfree(mci->ctl_name);
+ edac_mc_free(mci);
+ i7core_dev->mci = NULL;
return rc;
}
@@ -1949,8 +2032,6 @@ fail:
* < 0 for error code
*/
-static int probed = 0;
-
static int __devinit i7core_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@@ -1965,25 +2046,16 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
*/
if (unlikely(probed >= 1)) {
mutex_unlock(&i7core_edac_lock);
- return -EINVAL;
+ return -ENODEV;
}
probed++;
- rc = i7core_get_devices(pci_dev_table);
+ rc = i7core_get_all_devices();
if (unlikely(rc < 0))
goto fail0;
list_for_each_entry(i7core_dev, &i7core_edac_list, list) {
- int channels;
- int csrows;
-
- /* Check the number of active and not disabled channels */
- rc = i7core_get_active_channels(i7core_dev->socket,
- &channels, &csrows);
- if (unlikely(rc < 0))
- goto fail1;
-
- rc = i7core_register_mci(i7core_dev, channels, csrows);
+ rc = i7core_register_mci(i7core_dev);
if (unlikely(rc < 0))
goto fail1;
}
@@ -1994,6 +2066,9 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
return 0;
fail1:
+ list_for_each_entry(i7core_dev, &i7core_edac_list, list)
+ i7core_unregister_mci(i7core_dev);
+
i7core_put_all_devices();
fail0:
mutex_unlock(&i7core_edac_lock);
@@ -2006,14 +2081,10 @@ fail0:
*/
static void __devexit i7core_remove(struct pci_dev *pdev)
{
- struct mem_ctl_info *mci;
- struct i7core_dev *i7core_dev, *tmp;
+ struct i7core_dev *i7core_dev;
debugf0(__FILE__ ": %s()\n", __func__);
- if (i7core_pci)
- edac_pci_release_generic_ctl(i7core_pci);
-
/*
* we have a trouble here: pdev value for removal will be wrong, since
* it will point to the X58 register used to detect that the machine
@@ -2023,22 +2094,18 @@ static void __devexit i7core_remove(struct pci_dev *pdev)
*/
mutex_lock(&i7core_edac_lock);
- list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) {
- mci = edac_mc_del_mc(&i7core_dev->pdev[0]->dev);
- if (mci) {
- struct i7core_pvt *pvt = mci->pvt_info;
-
- i7core_dev = pvt->i7core_dev;
- edac_mce_unregister(&pvt->edac_mce);
- kfree(mci->ctl_name);
- edac_mc_free(mci);
- i7core_put_devices(i7core_dev);
- } else {
- i7core_printk(KERN_ERR,
- "Couldn't find mci for socket %d\n",
- i7core_dev->socket);
- }
+
+ if (unlikely(!probed)) {
+ mutex_unlock(&i7core_edac_lock);
+ return;
}
+
+ list_for_each_entry(i7core_dev, &i7core_edac_list, list)
+ i7core_unregister_mci(i7core_dev);
+
+ /* Release PCI resources */
+ i7core_put_all_devices();
+
probed--;
mutex_unlock(&i7core_edac_lock);
@@ -2070,7 +2137,8 @@ static int __init i7core_init(void)
/* Ensure that the OPSTATE is set correctly for POLL or NMI */
opstate_init();
- i7core_xeon_pci_fixup(pci_dev_table);
+ if (use_pci_fixup)
+ i7core_xeon_pci_fixup(pci_dev_table);
pci_rc = pci_register_driver(&i7core_driver);
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c
index a2fa1feed724..678405ab04e4 100644
--- a/drivers/edac/i82443bxgx_edac.c
+++ b/drivers/edac/i82443bxgx_edac.c
@@ -12,7 +12,7 @@
* 440GX fix by Jason Uhlenkott <juhlenko@akamai.com>.
*
* Written with reference to 82443BX Host Bridge Datasheet:
- * http://www.intel.com/design/chipsets/440/documentation.htm
+ * http://download.intel.com/design/chipsets/datashts/29063301.pdf
* references to this document given in [].
*
* This module doesn't support the 440LX, but it may be possible to
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index fcf3ea28340b..40a222e19b2d 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -3,9 +3,6 @@ menu "IEEE 1394 (FireWire) support"
# firewire-core does not depend on PCI but is
# not useful without PCI controller driver
-comment "You can enable one or both FireWire driver stacks."
-comment "The newer stack is recommended."
-
config FIREWIRE
tristate "FireWire driver stack"
select CRC_ITU_T
@@ -64,8 +61,6 @@ config FIREWIRE_NET
To compile this driver as a module, say M here: The module will be
called firewire-net.
-source "drivers/ieee1394/Kconfig"
-
config FIREWIRE_NOSY
tristate "Nosy - a FireWire traffic sniffer for PCILynx cards"
depends on PCI
diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile
index 3c6a7fb20aa7..e3870d5c43dd 100644
--- a/drivers/firewire/Makefile
+++ b/drivers/firewire/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o
obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o
obj-$(CONFIG_FIREWIRE_NET) += firewire-net.o
obj-$(CONFIG_FIREWIRE_NOSY) += nosy.o
+obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o
diff --git a/drivers/ieee1394/init_ohci1394_dma.c b/drivers/firewire/init_ohci1394_dma.c
index ddaab6eb8ace..a9a347adb353 100644
--- a/drivers/ieee1394/init_ohci1394_dma.c
+++ b/drivers/firewire/init_ohci1394_dma.c
@@ -32,23 +32,41 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include <linux/interrupt.h> /* for ohci1394.h */
#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
#include <linux/pci.h> /* for PCI defines */
-#include <linux/init_ohci1394_dma.h>
+#include <linux/string.h>
+
#include <asm/pci-direct.h> /* for direct PCI config space access */
#include <asm/fixmap.h>
-#include "ieee1394_types.h"
-#include "ohci1394.h"
+#include <linux/init_ohci1394_dma.h>
+#include "ohci.h"
int __initdata init_ohci1394_dma_early;
+struct ohci {
+ void __iomem *registers;
+};
+
+static inline void reg_write(const struct ohci *ohci, int offset, u32 data)
+{
+ writel(data, ohci->registers + offset);
+}
+
+static inline u32 reg_read(const struct ohci *ohci, int offset)
+{
+ return readl(ohci->registers + offset);
+}
+
+#define OHCI_LOOP_COUNT 100 /* Number of loops for reg read waits */
+
/* Reads a PHY register of an OHCI-1394 controller */
-static inline u8 __init get_phy_reg(struct ti_ohci *ohci, u8 addr)
+static inline u8 __init get_phy_reg(struct ohci *ohci, u8 addr)
{
int i;
- quadlet_t r;
+ u32 r;
reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000);
@@ -63,22 +81,22 @@ static inline u8 __init get_phy_reg(struct ti_ohci *ohci, u8 addr)
}
/* Writes to a PHY register of an OHCI-1394 controller */
-static inline void __init set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data)
+static inline void __init set_phy_reg(struct ohci *ohci, u8 addr, u8 data)
{
int i;
reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000);
for (i = 0; i < OHCI_LOOP_COUNT; i++) {
- u32 r = reg_read(ohci, OHCI1394_PhyControl);
- if (!(r & 0x00004000))
+ if (!(reg_read(ohci, OHCI1394_PhyControl) & 0x00004000))
break;
mdelay(1);
}
}
/* Resets an OHCI-1394 controller (for sane state before initialization) */
-static inline void __init init_ohci1394_soft_reset(struct ti_ohci *ohci) {
+static inline void __init init_ohci1394_soft_reset(struct ohci *ohci)
+{
int i;
reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
@@ -91,10 +109,14 @@ static inline void __init init_ohci1394_soft_reset(struct ti_ohci *ohci) {
}
}
+#define OHCI1394_MAX_AT_REQ_RETRIES 0xf
+#define OHCI1394_MAX_AT_RESP_RETRIES 0x2
+#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8
+
/* Basic OHCI-1394 register and port inititalization */
-static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
+static inline void __init init_ohci1394_initialize(struct ohci *ohci)
{
- quadlet_t bus_options;
+ u32 bus_options;
int num_ports, i;
/* Put some defaults to these undefined bus options */
@@ -116,7 +138,7 @@ static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
/* enable phys */
reg_write(ohci, OHCI1394_LinkControlSet,
- OHCI1394_LinkControl_RcvPhyPkt);
+ OHCI1394_LinkControl_rcvPhyPkt);
/* Don't accept phy packets into AR request context */
reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
@@ -128,7 +150,7 @@ static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
/* Accept asyncronous transfer requests from all nodes for now */
- reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000);
+ reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
/* Specify asyncronous transfer retries */
reg_write(ohci, OHCI1394_ATRetries,
@@ -137,7 +159,8 @@ static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
(OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
/* We don't want hardware swapping */
- reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap);
+ reg_write(ohci, OHCI1394_HCControlClear,
+ OHCI1394_HCControl_noByteSwapData);
/* Enable link */
reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
@@ -164,11 +187,11 @@ static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
* has to be enabled after each bus reset when needed. We resort
* to polling here because on early boot, we have no interrupts.
*/
-static inline void __init init_ohci1394_wait_for_busresets(struct ti_ohci *ohci)
+static inline void __init init_ohci1394_wait_for_busresets(struct ohci *ohci)
{
int i, events;
- for (i=0; i < 9; i++) {
+ for (i = 0; i < 9; i++) {
mdelay(200);
events = reg_read(ohci, OHCI1394_IntEventSet);
if (events & OHCI1394_busReset)
@@ -182,18 +205,18 @@ static inline void __init init_ohci1394_wait_for_busresets(struct ti_ohci *ohci)
* This enables remote DMA access over IEEE1394 from every host for the low
* 4GB of address space. DMA accesses above 4GB are not available currently.
*/
-static inline void __init init_ohci1394_enable_physical_dma(struct ti_ohci *hci)
+static inline void __init init_ohci1394_enable_physical_dma(struct ohci *ohci)
{
- reg_write(hci, OHCI1394_PhyReqFilterHiSet, 0xffffffff);
- reg_write(hci, OHCI1394_PhyReqFilterLoSet, 0xffffffff);
- reg_write(hci, OHCI1394_PhyUpperBound, 0xffff0000);
+ reg_write(ohci, OHCI1394_PhyReqFilterHiSet, 0xffffffff);
+ reg_write(ohci, OHCI1394_PhyReqFilterLoSet, 0xffffffff);
+ reg_write(ohci, OHCI1394_PhyUpperBound, 0xffff0000);
}
/**
* init_ohci1394_reset_and_init_dma - init controller and enable DMA
* This initializes the given controller and enables physical DMA engine in it.
*/
-static inline void __init init_ohci1394_reset_and_init_dma(struct ti_ohci *ohci)
+static inline void __init init_ohci1394_reset_and_init_dma(struct ohci *ohci)
{
/* Start off with a soft reset, clears everything to a sane state. */
init_ohci1394_soft_reset(ohci);
@@ -225,7 +248,7 @@ static inline void __init init_ohci1394_reset_and_init_dma(struct ti_ohci *ohci)
static inline void __init init_ohci1394_controller(int num, int slot, int func)
{
unsigned long ohci_base;
- struct ti_ohci ohci;
+ struct ohci ohci;
printk(KERN_INFO "init_ohci1394_dma: initializing OHCI-1394"
" at %02x:%02x.%x\n", num, slot, func);
@@ -235,7 +258,7 @@ static inline void __init init_ohci1394_controller(int num, int slot, int func)
set_fixmap_nocache(FIX_OHCI1394_BASE, ohci_base);
- ohci.registers = (void *)fix_to_virt(FIX_OHCI1394_BASE);
+ ohci.registers = (void __iomem *)fix_to_virt(FIX_OHCI1394_BASE);
init_ohci1394_reset_and_init_dma(&ohci);
}
@@ -247,6 +270,7 @@ static inline void __init init_ohci1394_controller(int num, int slot, int func)
void __init init_ohci1394_dma_on_all_controllers(void)
{
int num, slot, func;
+ u32 class;
if (!early_pci_allowed())
return;
@@ -255,9 +279,9 @@ void __init init_ohci1394_dma_on_all_controllers(void)
for (num = 0; num < 32; num++) {
for (slot = 0; slot < 32; slot++) {
for (func = 0; func < 8; func++) {
- u32 class = read_pci_config(num,slot,func,
+ class = read_pci_config(num, slot, func,
PCI_CLASS_REVISION);
- if ((class == 0xffffffff))
+ if (class == 0xffffffff)
continue; /* No device at this func */
if (class>>8 != PCI_CLASS_SERIAL_FIREWIRE_OHCI)
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index 33f8421c71cc..18fdd9703b48 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -8,7 +8,6 @@
#include <linux/bug.h>
#include <linux/device.h>
-#include <linux/ethtool.h>
#include <linux/firewire.h>
#include <linux/firewire-constants.h>
#include <linux/highmem.h>
@@ -1361,17 +1360,6 @@ static int fwnet_change_mtu(struct net_device *net, int new_mtu)
return 0;
}
-static void fwnet_get_drvinfo(struct net_device *net,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, KBUILD_MODNAME);
- strcpy(info->bus_info, "ieee1394");
-}
-
-static const struct ethtool_ops fwnet_ethtool_ops = {
- .get_drvinfo = fwnet_get_drvinfo,
-};
-
static const struct net_device_ops fwnet_netdev_ops = {
.ndo_open = fwnet_open,
.ndo_stop = fwnet_stop,
@@ -1390,7 +1378,6 @@ static void fwnet_init_dev(struct net_device *net)
net->hard_header_len = FWNET_HLEN;
net->type = ARPHRD_IEEE1394;
net->tx_queue_len = 10;
- SET_ETHTOOL_OPS(net, &fwnet_ethtool_ops);
}
/* caller must hold fwnet_device_mutex */
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 88a3ae6cd023..e8b6a13515bd 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -74,7 +74,8 @@ config EFI_PCDP
You must also enable the appropriate drivers (serial, VGA, etc.)
- See <http://www.dig64.org/specifications/DIG64_HCDPv20_042804.pdf>
+ See DIG64_HCDPv20_042804.pdf available from
+ <http://www.dig64.org/specifications/>
config DELL_RBU
tristate "BIOS update support for DELL systems via sysfs"
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index b3d22d659990..e28e41668177 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -2,6 +2,7 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/ctype.h>
#include <linux/dmi.h>
#include <linux/efi.h>
#include <linux/bootmem.h>
@@ -361,6 +362,33 @@ static void __init dmi_decode(const struct dmi_header *dm, void *dummy)
}
}
+static void __init print_filtered(const char *info)
+{
+ const char *p;
+
+ if (!info)
+ return;
+
+ for (p = info; *p; p++)
+ if (isprint(*p))
+ printk(KERN_CONT "%c", *p);
+ else
+ printk(KERN_CONT "\\x%02x", *p & 0xff);
+}
+
+static void __init dmi_dump_ids(void)
+{
+ printk(KERN_DEBUG "DMI: ");
+ print_filtered(dmi_get_system_info(DMI_BOARD_NAME));
+ printk(KERN_CONT "/");
+ print_filtered(dmi_get_system_info(DMI_PRODUCT_NAME));
+ printk(KERN_CONT ", BIOS ");
+ print_filtered(dmi_get_system_info(DMI_BIOS_VERSION));
+ printk(KERN_CONT " ");
+ print_filtered(dmi_get_system_info(DMI_BIOS_DATE));
+ printk(KERN_CONT "\n");
+}
+
static int __init dmi_present(const char __iomem *p)
{
u8 buf[15];
@@ -381,8 +409,10 @@ static int __init dmi_present(const char __iomem *p)
buf[14] >> 4, buf[14] & 0xF);
else
printk(KERN_INFO "DMI present.\n");
- if (dmi_walk_early(dmi_decode) == 0)
+ if (dmi_walk_early(dmi_decode) == 0) {
+ dmi_dump_ids();
return 0;
+ }
}
return 1;
}
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
index f287fe79edc4..96c25d93eed1 100644
--- a/drivers/firmware/edd.c
+++ b/drivers/firmware/edd.c
@@ -15,7 +15,7 @@
* made in setup.S, copied to safe structures in setup.c,
* and presents it in sysfs.
*
- * Please see http://linux.dell.com/edd30/results.html for
+ * Please see http://linux.dell.com/edd/results.html for
* the list of BIOSs which have been reported to implement EDD.
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/firmware/pcdp.h b/drivers/firmware/pcdp.h
index ce910d68bd19..e5530608e00d 100644
--- a/drivers/firmware/pcdp.h
+++ b/drivers/firmware/pcdp.h
@@ -1,8 +1,8 @@
/*
* Definitions for PCDP-defined console devices
*
- * v1.0a: http://www.dig64.org/specifications/DIG64_HCDPv10a_01.pdf
- * v2.0: http://www.dig64.org/specifications/DIG64_PCDPv20.pdf
+ * For DIG64_HCDPv10a_01.pdf and DIG64_PCDPv20.pdf (v1.0a and v2.0 resp.),
+ * please see <http://www.dig64.org/specifications/>
*
* (c) Copyright 2002, 2004 Hewlett-Packard Development Company, L.P.
* Khalid Aziz <khalid.aziz@hp.com>
diff --git a/drivers/gpio/74x164.c b/drivers/gpio/74x164.c
new file mode 100644
index 000000000000..d91ff4c282e9
--- /dev/null
+++ b/drivers/gpio/74x164.c
@@ -0,0 +1,182 @@
+/*
+ * 74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver
+ *
+ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2010 Miguel Gaio <miguel.gaio@efixo.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/init.h>
+#include <linux/mutex.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/74x164.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#define GEN_74X164_GPIO_COUNT 8
+
+
+struct gen_74x164_chip {
+ struct spi_device *spi;
+ struct gpio_chip gpio_chip;
+ struct mutex lock;
+ u8 port_config;
+};
+
+static void gen_74x164_set_value(struct gpio_chip *, unsigned, int);
+
+static struct gen_74x164_chip *gpio_to_chip(struct gpio_chip *gc)
+{
+ return container_of(gc, struct gen_74x164_chip, gpio_chip);
+}
+
+static int __gen_74x164_write_config(struct gen_74x164_chip *chip)
+{
+ return spi_write(chip->spi,
+ &chip->port_config, sizeof(chip->port_config));
+}
+
+static int gen_74x164_direction_output(struct gpio_chip *gc,
+ unsigned offset, int val)
+{
+ gen_74x164_set_value(gc, offset, val);
+ return 0;
+}
+
+static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset)
+{
+ struct gen_74x164_chip *chip = gpio_to_chip(gc);
+ int ret;
+
+ mutex_lock(&chip->lock);
+ ret = (chip->port_config >> offset) & 0x1;
+ mutex_unlock(&chip->lock);
+
+ return ret;
+}
+
+static void gen_74x164_set_value(struct gpio_chip *gc,
+ unsigned offset, int val)
+{
+ struct gen_74x164_chip *chip = gpio_to_chip(gc);
+
+ mutex_lock(&chip->lock);
+ if (val)
+ chip->port_config |= (1 << offset);
+ else
+ chip->port_config &= ~(1 << offset);
+
+ __gen_74x164_write_config(chip);
+ mutex_unlock(&chip->lock);
+}
+
+static int __devinit gen_74x164_probe(struct spi_device *spi)
+{
+ struct gen_74x164_chip *chip;
+ struct gen_74x164_chip_platform_data *pdata;
+ int ret;
+
+ pdata = spi->dev.platform_data;
+ if (!pdata || !pdata->base) {
+ dev_dbg(&spi->dev, "incorrect or missing platform data\n");
+ return -EINVAL;
+ }
+
+ /*
+ * bits_per_word cannot be configured in platform data
+ */
+ spi->bits_per_word = 8;
+
+ ret = spi_setup(spi);
+ if (ret < 0)
+ return ret;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ mutex_init(&chip->lock);
+
+ dev_set_drvdata(&spi->dev, chip);
+
+ chip->spi = spi;
+
+ chip->gpio_chip.label = GEN_74X164_DRIVER_NAME,
+ chip->gpio_chip.direction_output = gen_74x164_direction_output;
+ chip->gpio_chip.get = gen_74x164_get_value;
+ chip->gpio_chip.set = gen_74x164_set_value;
+ chip->gpio_chip.base = pdata->base;
+ chip->gpio_chip.ngpio = GEN_74X164_GPIO_COUNT;
+ chip->gpio_chip.can_sleep = 1;
+ chip->gpio_chip.dev = &spi->dev;
+ chip->gpio_chip.owner = THIS_MODULE;
+
+ ret = __gen_74x164_write_config(chip);
+ if (ret) {
+ dev_err(&spi->dev, "Failed writing: %d\n", ret);
+ goto exit_destroy;
+ }
+
+ ret = gpiochip_add(&chip->gpio_chip);
+ if (ret)
+ goto exit_destroy;
+
+ return ret;
+
+exit_destroy:
+ dev_set_drvdata(&spi->dev, NULL);
+ mutex_destroy(&chip->lock);
+ kfree(chip);
+ return ret;
+}
+
+static int gen_74x164_remove(struct spi_device *spi)
+{
+ struct gen_74x164_chip *chip;
+ int ret;
+
+ chip = dev_get_drvdata(&spi->dev);
+ if (chip == NULL)
+ return -ENODEV;
+
+ dev_set_drvdata(&spi->dev, NULL);
+
+ ret = gpiochip_remove(&chip->gpio_chip);
+ if (!ret) {
+ mutex_destroy(&chip->lock);
+ kfree(chip);
+ } else
+ dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n",
+ ret);
+
+ return ret;
+}
+
+static struct spi_driver gen_74x164_driver = {
+ .driver = {
+ .name = GEN_74X164_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = gen_74x164_probe,
+ .remove = __devexit_p(gen_74x164_remove),
+};
+
+static int __init gen_74x164_init(void)
+{
+ return spi_register_driver(&gen_74x164_driver);
+}
+subsys_initcall(gen_74x164_init);
+
+static void __exit gen_74x164_exit(void)
+{
+ spi_unregister_driver(&gen_74x164_driver);
+}
+module_exit(gen_74x164_exit);
+
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_AUTHOR("Miguel Gaio <miguel.gaio@efixo.com>");
+MODULE_DESCRIPTION("GPIO expander driver for 74X164 8-bits shift register");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 510aa2054544..dd9b4ba8d32d 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -70,6 +70,11 @@ config GPIO_MAX730X
comment "Memory mapped GPIO expanders:"
+config GPIO_BASIC_MMIO
+ tristate "Basic memory-mapped GPIO controllers support"
+ help
+ Say yes here to support basic memory-mapped GPIO controllers.
+
config GPIO_IT8761E
tristate "IT8761E GPIO support"
depends on GPIOLIB
@@ -267,6 +272,13 @@ config GPIO_ADP5588
To compile this driver as a module, choose M here: the module will be
called adp5588-gpio.
+config GPIO_ADP5588_IRQ
+ bool "Interrupt controller support for ADP5588"
+ depends on GPIO_ADP5588=y
+ help
+ Say yes here to enable the adp5588 to be used as an interrupt
+ controller. It requires the driver to be built in the kernel.
+
comment "PCI GPIO expanders:"
config GPIO_CS5535
@@ -301,6 +313,14 @@ config GPIO_LANGWELL
help
Say Y here to support Intel Langwell/Penwell GPIO.
+config GPIO_PCH
+ tristate "PCH GPIO of Intel Topcliff"
+ depends on PCI
+ help
+ This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff
+ which is an IOH(Input/Output Hub) for x86 embedded processor.
+ This driver can access PCH GPIO device.
+
config GPIO_TIMBERDALE
bool "Support for timberdale GPIO IP"
depends on MFD_TIMBERDALE && GPIOLIB && HAS_IOMEM
@@ -339,6 +359,14 @@ config GPIO_MC33880
SPI driver for Freescale MC33880 high-side/low-side switch.
This provides GPIO interface supporting inputs and outputs.
+config GPIO_74X164
+ tristate "74x164 serial-in/parallel-out 8-bits shift register"
+ depends on SPI_MASTER
+ help
+ Platform driver for 74x164 compatible serial-in/parallel-out
+ 8-outputs shift registers. This driver can be used to provide access
+ to more gpio outputs.
+
comment "AC97 GPIO expanders:"
config GPIO_UCB1400
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index fc6019d93720..da2ecde5abdd 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_GPIOLIB) += gpiolib.o
obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o
obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o
+obj-$(CONFIG_GPIO_BASIC_MMIO) += basic_mmio_gpio.o
obj-$(CONFIG_GPIO_LANGWELL) += langwell_gpio.o
obj-$(CONFIG_GPIO_MAX730X) += max730x.o
obj-$(CONFIG_GPIO_MAX7300) += max7300.o
@@ -17,8 +18,10 @@ obj-$(CONFIG_GPIO_MAX7301) += max7301.o
obj-$(CONFIG_GPIO_MAX732X) += max732x.o
obj-$(CONFIG_GPIO_MC33880) += mc33880.o
obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o
+obj-$(CONFIG_GPIO_74X164) += 74x164.o
obj-$(CONFIG_GPIO_PCA953X) += pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o
+obj-$(CONFIG_GPIO_PCH) += pch_gpio.o
obj-$(CONFIG_GPIO_PL061) += pl061.o
obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o
obj-$(CONFIG_GPIO_TC35892) += tc35892-gpio.o
diff --git a/drivers/gpio/adp5588-gpio.c b/drivers/gpio/adp5588-gpio.c
index 2e8e9e24f887..0871f78af593 100644
--- a/drivers/gpio/adp5588-gpio.c
+++ b/drivers/gpio/adp5588-gpio.c
@@ -1,8 +1,8 @@
/*
* GPIO Chip driver for Analog Devices
- * ADP5588 I/O Expander and QWERTY Keypad Controller
+ * ADP5588/ADP5587 I/O Expander and QWERTY Keypad Controller
*
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
@@ -13,21 +13,34 @@
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/i2c/adp5588.h>
-#define DRV_NAME "adp5588-gpio"
-#define MAXGPIO 18
-#define ADP_BANK(offs) ((offs) >> 3)
-#define ADP_BIT(offs) (1u << ((offs) & 0x7))
+#define DRV_NAME "adp5588-gpio"
+
+/*
+ * Early pre 4.0 Silicon required to delay readout by at least 25ms,
+ * since the Event Counter Register updated 25ms after the interrupt
+ * asserted.
+ */
+#define WA_DELAYED_READOUT_REVID(rev) ((rev) < 4)
struct adp5588_gpio {
struct i2c_client *client;
struct gpio_chip gpio_chip;
struct mutex lock; /* protect cached dir, dat_out */
+ /* protect serialized access to the interrupt controller bus */
+ struct mutex irq_lock;
unsigned gpio_start;
+ unsigned irq_base;
uint8_t dat_out[3];
uint8_t dir[3];
+ uint8_t int_lvl[3];
+ uint8_t int_en[3];
+ uint8_t irq_mask[3];
+ uint8_t irq_stat[3];
};
static int adp5588_gpio_read(struct i2c_client *client, u8 reg)
@@ -55,8 +68,8 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
struct adp5588_gpio *dev =
container_of(chip, struct adp5588_gpio, gpio_chip);
- return !!(adp5588_gpio_read(dev->client, GPIO_DAT_STAT1 + ADP_BANK(off))
- & ADP_BIT(off));
+ return !!(adp5588_gpio_read(dev->client,
+ GPIO_DAT_STAT1 + ADP5588_BANK(off)) & ADP5588_BIT(off));
}
static void adp5588_gpio_set_value(struct gpio_chip *chip,
@@ -66,8 +79,8 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip,
struct adp5588_gpio *dev =
container_of(chip, struct adp5588_gpio, gpio_chip);
- bank = ADP_BANK(off);
- bit = ADP_BIT(off);
+ bank = ADP5588_BANK(off);
+ bit = ADP5588_BIT(off);
mutex_lock(&dev->lock);
if (val)
@@ -87,10 +100,10 @@ static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
struct adp5588_gpio *dev =
container_of(chip, struct adp5588_gpio, gpio_chip);
- bank = ADP_BANK(off);
+ bank = ADP5588_BANK(off);
mutex_lock(&dev->lock);
- dev->dir[bank] &= ~ADP_BIT(off);
+ dev->dir[bank] &= ~ADP5588_BIT(off);
ret = adp5588_gpio_write(dev->client, GPIO_DIR1 + bank, dev->dir[bank]);
mutex_unlock(&dev->lock);
@@ -105,8 +118,8 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
struct adp5588_gpio *dev =
container_of(chip, struct adp5588_gpio, gpio_chip);
- bank = ADP_BANK(off);
- bit = ADP_BIT(off);
+ bank = ADP5588_BANK(off);
+ bit = ADP5588_BIT(off);
mutex_lock(&dev->lock);
dev->dir[bank] |= bit;
@@ -125,6 +138,213 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
return ret;
}
+#ifdef CONFIG_GPIO_ADP5588_IRQ
+static int adp5588_gpio_to_irq(struct gpio_chip *chip, unsigned off)
+{
+ struct adp5588_gpio *dev =
+ container_of(chip, struct adp5588_gpio, gpio_chip);
+ return dev->irq_base + off;
+}
+
+static void adp5588_irq_bus_lock(unsigned int irq)
+{
+ struct adp5588_gpio *dev = get_irq_chip_data(irq);
+ mutex_lock(&dev->irq_lock);
+}
+
+ /*
+ * genirq core code can issue chip->mask/unmask from atomic context.
+ * This doesn't work for slow busses where an access needs to sleep.
+ * bus_sync_unlock() is therefore called outside the atomic context,
+ * syncs the current irq mask state with the slow external controller
+ * and unlocks the bus.
+ */
+
+static void adp5588_irq_bus_sync_unlock(unsigned int irq)
+{
+ struct adp5588_gpio *dev = get_irq_chip_data(irq);
+ int i;
+
+ for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++)
+ if (dev->int_en[i] ^ dev->irq_mask[i]) {
+ dev->int_en[i] = dev->irq_mask[i];
+ adp5588_gpio_write(dev->client, GPIO_INT_EN1 + i,
+ dev->int_en[i]);
+ }
+
+ mutex_unlock(&dev->irq_lock);
+}
+
+static void adp5588_irq_mask(unsigned int irq)
+{
+ struct adp5588_gpio *dev = get_irq_chip_data(irq);
+ unsigned gpio = irq - dev->irq_base;
+
+ dev->irq_mask[ADP5588_BANK(gpio)] &= ~ADP5588_BIT(gpio);
+}
+
+static void adp5588_irq_unmask(unsigned int irq)
+{
+ struct adp5588_gpio *dev = get_irq_chip_data(irq);
+ unsigned gpio = irq - dev->irq_base;
+
+ dev->irq_mask[ADP5588_BANK(gpio)] |= ADP5588_BIT(gpio);
+}
+
+static int adp5588_irq_set_type(unsigned int irq, unsigned int type)
+{
+ struct adp5588_gpio *dev = get_irq_chip_data(irq);
+ uint16_t gpio = irq - dev->irq_base;
+ unsigned bank, bit;
+
+ if ((type & IRQ_TYPE_EDGE_BOTH)) {
+ dev_err(&dev->client->dev, "irq %d: unsupported type %d\n",
+ irq, type);
+ return -EINVAL;
+ }
+
+ bank = ADP5588_BANK(gpio);
+ bit = ADP5588_BIT(gpio);
+
+ if (type & IRQ_TYPE_LEVEL_HIGH)
+ dev->int_lvl[bank] |= bit;
+ else if (type & IRQ_TYPE_LEVEL_LOW)
+ dev->int_lvl[bank] &= ~bit;
+ else
+ return -EINVAL;
+
+ adp5588_gpio_direction_input(&dev->gpio_chip, gpio);
+ adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + bank,
+ dev->int_lvl[bank]);
+
+ return 0;
+}
+
+static struct irq_chip adp5588_irq_chip = {
+ .name = "adp5588",
+ .mask = adp5588_irq_mask,
+ .unmask = adp5588_irq_unmask,
+ .bus_lock = adp5588_irq_bus_lock,
+ .bus_sync_unlock = adp5588_irq_bus_sync_unlock,
+ .set_type = adp5588_irq_set_type,
+};
+
+static int adp5588_gpio_read_intstat(struct i2c_client *client, u8 *buf)
+{
+ int ret = i2c_smbus_read_i2c_block_data(client, GPIO_INT_STAT1, 3, buf);
+
+ if (ret < 0)
+ dev_err(&client->dev, "Read INT_STAT Error\n");
+
+ return ret;
+}
+
+static irqreturn_t adp5588_irq_handler(int irq, void *devid)
+{
+ struct adp5588_gpio *dev = devid;
+ unsigned status, bank, bit, pending;
+ int ret;
+ status = adp5588_gpio_read(dev->client, INT_STAT);
+
+ if (status & ADP5588_GPI_INT) {
+ ret = adp5588_gpio_read_intstat(dev->client, dev->irq_stat);
+ if (ret < 0)
+ memset(dev->irq_stat, 0, ARRAY_SIZE(dev->irq_stat));
+
+ for (bank = 0; bank <= ADP5588_BANK(ADP5588_MAXGPIO);
+ bank++, bit = 0) {
+ pending = dev->irq_stat[bank] & dev->irq_mask[bank];
+
+ while (pending) {
+ if (pending & (1 << bit)) {
+ handle_nested_irq(dev->irq_base +
+ (bank << 3) + bit);
+ pending &= ~(1 << bit);
+
+ }
+ bit++;
+ }
+ }
+ }
+
+ adp5588_gpio_write(dev->client, INT_STAT, status); /* Status is W1C */
+
+ return IRQ_HANDLED;
+}
+
+static int adp5588_irq_setup(struct adp5588_gpio *dev)
+{
+ struct i2c_client *client = dev->client;
+ struct adp5588_gpio_platform_data *pdata = client->dev.platform_data;
+ unsigned gpio;
+ int ret;
+
+ adp5588_gpio_write(client, CFG, ADP5588_AUTO_INC);
+ adp5588_gpio_write(client, INT_STAT, -1); /* status is W1C */
+ adp5588_gpio_read_intstat(client, dev->irq_stat); /* read to clear */
+
+ dev->irq_base = pdata->irq_base;
+ mutex_init(&dev->irq_lock);
+
+ for (gpio = 0; gpio < dev->gpio_chip.ngpio; gpio++) {
+ int irq = gpio + dev->irq_base;
+ set_irq_chip_data(irq, dev);
+ set_irq_chip_and_handler(irq, &adp5588_irq_chip,
+ handle_level_irq);
+ set_irq_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+ /*
+ * ARM needs us to explicitly flag the IRQ as VALID,
+ * once we do so, it will also set the noprobe.
+ */
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ set_irq_noprobe(irq);
+#endif
+ }
+
+ ret = request_threaded_irq(client->irq,
+ NULL,
+ adp5588_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ dev_name(&client->dev), dev);
+ if (ret) {
+ dev_err(&client->dev, "failed to request irq %d\n",
+ client->irq);
+ goto out;
+ }
+
+ dev->gpio_chip.to_irq = adp5588_gpio_to_irq;
+ adp5588_gpio_write(client, CFG,
+ ADP5588_AUTO_INC | ADP5588_INT_CFG | ADP5588_GPI_INT);
+
+ return 0;
+
+out:
+ dev->irq_base = 0;
+ return ret;
+}
+
+static void adp5588_irq_teardown(struct adp5588_gpio *dev)
+{
+ if (dev->irq_base)
+ free_irq(dev->client->irq, dev);
+}
+
+#else
+static int adp5588_irq_setup(struct adp5588_gpio *dev)
+{
+ struct i2c_client *client = dev->client;
+ dev_warn(&client->dev, "interrupt support not compiled in\n");
+
+ return 0;
+}
+
+static void adp5588_irq_teardown(struct adp5588_gpio *dev)
+{
+}
+#endif /* CONFIG_GPIO_ADP5588_IRQ */
+
static int __devinit adp5588_gpio_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -160,37 +380,46 @@ static int __devinit adp5588_gpio_probe(struct i2c_client *client,
gc->can_sleep = 1;
gc->base = pdata->gpio_start;
- gc->ngpio = MAXGPIO;
+ gc->ngpio = ADP5588_MAXGPIO;
gc->label = client->name;
gc->owner = THIS_MODULE;
mutex_init(&dev->lock);
-
ret = adp5588_gpio_read(dev->client, DEV_ID);
if (ret < 0)
goto err;
revid = ret & ADP5588_DEVICE_ID_MASK;
- for (i = 0, ret = 0; i <= ADP_BANK(MAXGPIO); i++) {
+ for (i = 0, ret = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
dev->dat_out[i] = adp5588_gpio_read(client, GPIO_DAT_OUT1 + i);
dev->dir[i] = adp5588_gpio_read(client, GPIO_DIR1 + i);
ret |= adp5588_gpio_write(client, KP_GPIO1 + i, 0);
ret |= adp5588_gpio_write(client, GPIO_PULL1 + i,
(pdata->pullup_dis_mask >> (8 * i)) & 0xFF);
-
+ ret |= adp5588_gpio_write(client, GPIO_INT_EN1 + i, 0);
if (ret)
goto err;
}
+ if (pdata->irq_base) {
+ if (WA_DELAYED_READOUT_REVID(revid)) {
+ dev_warn(&client->dev, "GPIO int not supported\n");
+ } else {
+ ret = adp5588_irq_setup(dev);
+ if (ret)
+ goto err;
+ }
+ }
+
ret = gpiochip_add(&dev->gpio_chip);
if (ret)
- goto err;
+ goto err_irq;
- dev_info(&client->dev, "gpios %d..%d on a %s Rev. %d\n",
+ dev_info(&client->dev, "gpios %d..%d (IRQ Base %d) on a %s Rev. %d\n",
gc->base, gc->base + gc->ngpio - 1,
- client->name, revid);
+ pdata->irq_base, client->name, revid);
if (pdata->setup) {
ret = pdata->setup(client, gc->base, gc->ngpio, pdata->context);
@@ -199,8 +428,11 @@ static int __devinit adp5588_gpio_probe(struct i2c_client *client,
}
i2c_set_clientdata(client, dev);
+
return 0;
+err_irq:
+ adp5588_irq_teardown(dev);
err:
kfree(dev);
return ret;
@@ -222,6 +454,9 @@ static int __devexit adp5588_gpio_remove(struct i2c_client *client)
}
}
+ if (dev->irq_base)
+ free_irq(dev->client->irq, dev);
+
ret = gpiochip_remove(&dev->gpio_chip);
if (ret) {
dev_err(&client->dev, "gpiochip_remove failed %d\n", ret);
diff --git a/drivers/gpio/basic_mmio_gpio.c b/drivers/gpio/basic_mmio_gpio.c
new file mode 100644
index 000000000000..3addea65894e
--- /dev/null
+++ b/drivers/gpio/basic_mmio_gpio.c
@@ -0,0 +1,297 @@
+/*
+ * Driver for basic memory-mapped GPIO controllers.
+ *
+ * Copyright 2008 MontaVista Software, Inc.
+ * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@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 (at your
+ * option) any later version.
+ *
+ * ....``.```~~~~````.`.`.`.`.```````'',,,.........`````......`.......
+ * ...`` ```````..
+ * ..The simplest form of a GPIO controller that the driver supports is``
+ * `.just a single "data" register, where GPIO state can be read and/or `
+ * `,..written. ,,..``~~~~ .....``.`.`.~~.```.`.........``````.```````
+ * `````````
+ ___
+_/~~|___/~| . ```~~~~~~ ___/___\___ ,~.`.`.`.`````.~~...,,,,...
+__________|~$@~~~ %~ /o*o*o*o*o*o\ .. Implementing such a GPIO .
+o ` ~~~~\___/~~~~ ` controller in FPGA is ,.`
+ `....trivial..'~`.```.```
+ * ```````
+ * .```````~~~~`..`.``.``.
+ * . The driver supports `... ,..```.`~~~```````````````....````.``,,
+ * . big-endian notation, just`. .. A bit more sophisticated controllers ,
+ * . register the device with -be`. .with a pair of set/clear-bit registers ,
+ * `.. suffix. ```~~`````....`.` . affecting the data register and the .`
+ * ``.`.``...``` ```.. output pins are also supported.`
+ * ^^ `````.`````````.,``~``~``~~``````
+ * . ^^
+ * ,..`.`.`...````````````......`.`.`.`.`.`..`.`.`..
+ * .. The expectation is that in at least some cases . ,-~~~-,
+ * .this will be used with roll-your-own ASIC/FPGA .` \ /
+ * .logic in Verilog or VHDL. ~~~`````````..`````~~` \ /
+ * ..````````......``````````` \o_
+ * |
+ * ^^ / \
+ *
+ * ...`````~~`.....``.`..........``````.`.``.```........``.
+ * ` 8, 16, 32 and 64 bits registers are supported, and``.
+ * . the number of GPIOs is determined by the width of ~
+ * .. the registers. ,............```.`.`..`.`.~~~.`.`.`~
+ * `.......````.```
+ */
+
+#include <linux/init.h>
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/log2.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/basic_mmio_gpio.h>
+
+struct bgpio_chip {
+ struct gpio_chip gc;
+ void __iomem *reg_dat;
+ void __iomem *reg_set;
+ void __iomem *reg_clr;
+
+ /* Number of bits (GPIOs): <register width> * 8. */
+ int bits;
+
+ /*
+ * Some GPIO controllers work with the big-endian bits notation,
+ * e.g. in a 8-bits register, GPIO7 is the least significant bit.
+ */
+ int big_endian_bits;
+
+ /*
+ * Used to lock bgpio_chip->data. Also, this is needed to keep
+ * shadowed and real data registers writes together.
+ */
+ spinlock_t lock;
+
+ /* Shadowed data register to clear/set bits safely. */
+ unsigned long data;
+};
+
+static struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc)
+{
+ return container_of(gc, struct bgpio_chip, gc);
+}
+
+static unsigned long bgpio_in(struct bgpio_chip *bgc)
+{
+ switch (bgc->bits) {
+ case 8:
+ return __raw_readb(bgc->reg_dat);
+ case 16:
+ return __raw_readw(bgc->reg_dat);
+ case 32:
+ return __raw_readl(bgc->reg_dat);
+#if BITS_PER_LONG >= 64
+ case 64:
+ return __raw_readq(bgc->reg_dat);
+#endif
+ }
+ return -EINVAL;
+}
+
+static void bgpio_out(struct bgpio_chip *bgc, void __iomem *reg,
+ unsigned long data)
+{
+ switch (bgc->bits) {
+ case 8:
+ __raw_writeb(data, reg);
+ return;
+ case 16:
+ __raw_writew(data, reg);
+ return;
+ case 32:
+ __raw_writel(data, reg);
+ return;
+#if BITS_PER_LONG >= 64
+ case 64:
+ __raw_writeq(data, reg);
+ return;
+#endif
+ }
+}
+
+static unsigned long bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin)
+{
+ if (bgc->big_endian_bits)
+ return 1 << (bgc->bits - 1 - pin);
+ else
+ return 1 << pin;
+}
+
+static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+
+ return bgpio_in(bgc) & bgpio_pin2mask(bgc, gpio);
+}
+
+static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ unsigned long mask = bgpio_pin2mask(bgc, gpio);
+ unsigned long flags;
+
+ if (bgc->reg_set) {
+ if (val)
+ bgpio_out(bgc, bgc->reg_set, mask);
+ else
+ bgpio_out(bgc, bgc->reg_clr, mask);
+ return;
+ }
+
+ spin_lock_irqsave(&bgc->lock, flags);
+
+ if (val)
+ bgc->data |= mask;
+ else
+ bgc->data &= ~mask;
+
+ bgpio_out(bgc, bgc->reg_dat, bgc->data);
+
+ spin_unlock_irqrestore(&bgc->lock, flags);
+}
+
+static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ return 0;
+}
+
+static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ bgpio_set(gc, gpio, val);
+ return 0;
+}
+
+static int __devinit bgpio_probe(struct platform_device *pdev)
+{
+ const struct platform_device_id *platid = platform_get_device_id(pdev);
+ struct device *dev = &pdev->dev;
+ struct bgpio_pdata *pdata = dev_get_platdata(dev);
+ struct bgpio_chip *bgc;
+ struct resource *res_dat;
+ struct resource *res_set;
+ struct resource *res_clr;
+ resource_size_t dat_sz;
+ int bits;
+ int ret;
+
+ res_dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
+ if (!res_dat)
+ return -EINVAL;
+
+ dat_sz = resource_size(res_dat);
+ if (!is_power_of_2(dat_sz))
+ return -EINVAL;
+
+ bits = dat_sz * 8;
+ if (bits > BITS_PER_LONG)
+ return -EINVAL;
+
+ bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL);
+ if (!bgc)
+ return -ENOMEM;
+
+ bgc->reg_dat = devm_ioremap(dev, res_dat->start, dat_sz);
+ if (!bgc->reg_dat)
+ return -ENOMEM;
+
+ res_set = platform_get_resource_byname(pdev, IORESOURCE_MEM, "set");
+ res_clr = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clr");
+ if (res_set && res_clr) {
+ if (resource_size(res_set) != resource_size(res_clr) ||
+ resource_size(res_set) != dat_sz)
+ return -EINVAL;
+
+ bgc->reg_set = devm_ioremap(dev, res_set->start, dat_sz);
+ bgc->reg_clr = devm_ioremap(dev, res_clr->start, dat_sz);
+ if (!bgc->reg_set || !bgc->reg_clr)
+ return -ENOMEM;
+ } else if (res_set || res_clr) {
+ return -EINVAL;
+ }
+
+ spin_lock_init(&bgc->lock);
+
+ bgc->bits = bits;
+ bgc->big_endian_bits = !strcmp(platid->name, "basic-mmio-gpio-be");
+ bgc->data = bgpio_in(bgc);
+
+ bgc->gc.ngpio = bits;
+ bgc->gc.direction_input = bgpio_dir_in;
+ bgc->gc.direction_output = bgpio_dir_out;
+ bgc->gc.get = bgpio_get;
+ bgc->gc.set = bgpio_set;
+ bgc->gc.dev = dev;
+ bgc->gc.label = dev_name(dev);
+
+ if (pdata)
+ bgc->gc.base = pdata->base;
+ else
+ bgc->gc.base = -1;
+
+ dev_set_drvdata(dev, bgc);
+
+ ret = gpiochip_add(&bgc->gc);
+ if (ret)
+ dev_err(dev, "gpiochip_add() failed: %d\n", ret);
+
+ return ret;
+}
+
+static int __devexit bgpio_remove(struct platform_device *pdev)
+{
+ struct bgpio_chip *bgc = dev_get_drvdata(&pdev->dev);
+
+ return gpiochip_remove(&bgc->gc);
+}
+
+static const struct platform_device_id bgpio_id_table[] = {
+ { "basic-mmio-gpio", },
+ { "basic-mmio-gpio-be", },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, bgpio_id_table);
+
+static struct platform_driver bgpio_driver = {
+ .driver = {
+ .name = "basic-mmio-gpio",
+ },
+ .id_table = bgpio_id_table,
+ .probe = bgpio_probe,
+ .remove = __devexit_p(bgpio_remove),
+};
+
+static int __init bgpio_init(void)
+{
+ return platform_driver_register(&bgpio_driver);
+}
+module_init(bgpio_init);
+
+static void __exit bgpio_exit(void)
+{
+ platform_driver_unregister(&bgpio_driver);
+}
+module_exit(bgpio_exit);
+
+MODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers");
+MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c
index 8383a8d7f994..64db9dc3a275 100644
--- a/drivers/gpio/langwell_gpio.c
+++ b/drivers/gpio/langwell_gpio.c
@@ -18,10 +18,12 @@
/* Supports:
* Moorestown platform Langwell chip.
* Medfield platform Penwell chip.
+ * Whitney point.
*/
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/stddef.h>
@@ -158,15 +160,15 @@ static int lnw_irq_type(unsigned irq, unsigned type)
spin_unlock_irqrestore(&lnw->lock, flags);
return 0;
-};
+}
static void lnw_irq_unmask(unsigned irq)
{
-};
+}
static void lnw_irq_mask(unsigned irq)
{
-};
+}
static struct irq_chip lnw_irqchip = {
.name = "LNW-GPIO",
@@ -300,9 +302,88 @@ static struct pci_driver lnw_gpio_driver = {
.probe = lnw_gpio_probe,
};
+
+static int __devinit wp_gpio_probe(struct platform_device *pdev)
+{
+ struct lnw_gpio *lnw;
+ struct gpio_chip *gc;
+ struct resource *rc;
+ int retval = 0;
+
+ rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!rc)
+ return -EINVAL;
+
+ lnw = kzalloc(sizeof(struct lnw_gpio), GFP_KERNEL);
+ if (!lnw) {
+ dev_err(&pdev->dev,
+ "can't allocate whitneypoint_gpio chip data\n");
+ return -ENOMEM;
+ }
+ lnw->reg_base = ioremap_nocache(rc->start, resource_size(rc));
+ if (lnw->reg_base == NULL) {
+ retval = -EINVAL;
+ goto err_kmalloc;
+ }
+ spin_lock_init(&lnw->lock);
+ gc = &lnw->chip;
+ gc->label = dev_name(&pdev->dev);
+ gc->owner = THIS_MODULE;
+ gc->direction_input = lnw_gpio_direction_input;
+ gc->direction_output = lnw_gpio_direction_output;
+ gc->get = lnw_gpio_get;
+ gc->set = lnw_gpio_set;
+ gc->to_irq = NULL;
+ gc->base = 0;
+ gc->ngpio = 64;
+ gc->can_sleep = 0;
+ retval = gpiochip_add(gc);
+ if (retval) {
+ dev_err(&pdev->dev, "whitneypoint gpiochip_add error %d\n",
+ retval);
+ goto err_ioremap;
+ }
+ platform_set_drvdata(pdev, lnw);
+ return 0;
+err_ioremap:
+ iounmap(lnw->reg_base);
+err_kmalloc:
+ kfree(lnw);
+ return retval;
+}
+
+static int __devexit wp_gpio_remove(struct platform_device *pdev)
+{
+ struct lnw_gpio *lnw = platform_get_drvdata(pdev);
+ int err;
+ err = gpiochip_remove(&lnw->chip);
+ if (err)
+ dev_err(&pdev->dev, "failed to remove gpio_chip.\n");
+ iounmap(lnw->reg_base);
+ kfree(lnw);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static struct platform_driver wp_gpio_driver = {
+ .probe = wp_gpio_probe,
+ .remove = __devexit_p(wp_gpio_remove),
+ .driver = {
+ .name = "wp_gpio",
+ .owner = THIS_MODULE,
+ },
+};
+
static int __init lnw_gpio_init(void)
{
- return pci_register_driver(&lnw_gpio_driver);
+ int ret;
+ ret = pci_register_driver(&lnw_gpio_driver);
+ if (ret < 0)
+ return ret;
+ ret = platform_driver_register(&wp_gpio_driver);
+ if (ret < 0)
+ pci_unregister_driver(&lnw_gpio_driver);
+ return ret;
}
device_initcall(lnw_gpio_init);
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index a2b12aa1f2b9..501866662e05 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -345,7 +345,7 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid)
do {
level = __ffs(pending);
- handle_nested_irq(level + chip->irq_base);
+ generic_handle_irq(level + chip->irq_base);
pending &= ~(1 << level);
} while (pending);
@@ -360,7 +360,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
struct pca953x_platform_data *pdata = client->dev.platform_data;
int ret;
- if (pdata->irq_base && (id->driver_data & PCA953X_INT)) {
+ if (pdata->irq_base != -1
+ && (id->driver_data & PCA953X_INT)) {
int lvl;
ret = pca953x_read_reg(chip, PCA953X_INPUT,
@@ -383,7 +384,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
set_irq_chip_data(irq, chip);
set_irq_chip_and_handler(irq, &pca953x_irq_chip,
handle_edge_irq);
- set_irq_nested_thread(irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
@@ -394,6 +394,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
ret = request_threaded_irq(client->irq,
NULL,
pca953x_irq_handler,
+ IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
dev_name(&client->dev), chip);
if (ret) {
@@ -408,13 +409,13 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
return 0;
out_failed:
- chip->irq_base = 0;
+ chip->irq_base = -1;
return ret;
}
static void pca953x_irq_teardown(struct pca953x_chip *chip)
{
- if (chip->irq_base)
+ if (chip->irq_base != -1)
free_irq(chip->client->irq, chip);
}
#else /* CONFIG_GPIO_PCA953X_IRQ */
@@ -424,7 +425,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
struct i2c_client *client = chip->client;
struct pca953x_platform_data *pdata = client->dev.platform_data;
- if (pdata->irq_base && (id->driver_data & PCA953X_INT))
+ if (pdata->irq_base != -1 && (id->driver_data & PCA953X_INT))
dev_warn(&client->dev, "interrupt support not compiled in\n");
return 0;
diff --git a/drivers/gpio/pch_gpio.c b/drivers/gpio/pch_gpio.c
new file mode 100644
index 000000000000..0eba0a75c804
--- /dev/null
+++ b/drivers/gpio/pch_gpio.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/gpio.h>
+
+#define PCH_GPIO_ALL_PINS 0xfff /* Mask for GPIO pins 0 to 11 */
+#define GPIO_NUM_PINS 12 /* Specifies number of GPIO PINS GPIO0-GPIO11 */
+
+struct pch_regs {
+ u32 ien;
+ u32 istatus;
+ u32 idisp;
+ u32 iclr;
+ u32 imask;
+ u32 imaskclr;
+ u32 po;
+ u32 pi;
+ u32 pm;
+ u32 im0;
+ u32 im1;
+ u32 reserved[4];
+ u32 reset;
+};
+
+/**
+ * struct pch_gpio_reg_data - The register store data.
+ * @po_reg: To store contents of PO register.
+ * @pm_reg: To store contents of PM register.
+ */
+struct pch_gpio_reg_data {
+ u32 po_reg;
+ u32 pm_reg;
+};
+
+/**
+ * struct pch_gpio - GPIO private data structure.
+ * @base: PCI base address of Memory mapped I/O register.
+ * @reg: Memory mapped PCH GPIO register list.
+ * @dev: Pointer to device structure.
+ * @gpio: Data for GPIO infrastructure.
+ * @pch_gpio_reg: Memory mapped Register data is saved here
+ * when suspend.
+ */
+struct pch_gpio {
+ void __iomem *base;
+ struct pch_regs __iomem *reg;
+ struct device *dev;
+ struct gpio_chip gpio;
+ struct pch_gpio_reg_data pch_gpio_reg;
+ struct mutex lock;
+};
+
+static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
+{
+ u32 reg_val;
+ struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
+
+ mutex_lock(&chip->lock);
+ reg_val = ioread32(&chip->reg->po);
+ if (val)
+ reg_val |= (1 << nr);
+ else
+ reg_val &= ~(1 << nr);
+
+ iowrite32(reg_val, &chip->reg->po);
+ mutex_unlock(&chip->lock);
+}
+
+static int pch_gpio_get(struct gpio_chip *gpio, unsigned nr)
+{
+ struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
+
+ return ioread32(&chip->reg->pi) & (1 << nr);
+}
+
+static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
+ int val)
+{
+ struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
+ u32 pm;
+ u32 reg_val;
+
+ mutex_lock(&chip->lock);
+ pm = ioread32(&chip->reg->pm) & PCH_GPIO_ALL_PINS;
+ pm |= (1 << nr);
+ iowrite32(pm, &chip->reg->pm);
+
+ reg_val = ioread32(&chip->reg->po);
+ if (val)
+ reg_val |= (1 << nr);
+ else
+ reg_val &= ~(1 << nr);
+
+ mutex_unlock(&chip->lock);
+
+ return 0;
+}
+
+static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
+{
+ struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
+ u32 pm;
+
+ mutex_lock(&chip->lock);
+ pm = ioread32(&chip->reg->pm) & PCH_GPIO_ALL_PINS; /*bits 0-11*/
+ pm &= ~(1 << nr);
+ iowrite32(pm, &chip->reg->pm);
+ mutex_unlock(&chip->lock);
+
+ return 0;
+}
+
+/*
+ * Save register configuration and disable interrupts.
+ */
+static void pch_gpio_save_reg_conf(struct pch_gpio *chip)
+{
+ chip->pch_gpio_reg.po_reg = ioread32(&chip->reg->po);
+ chip->pch_gpio_reg.pm_reg = ioread32(&chip->reg->pm);
+}
+
+/*
+ * This function restores the register configuration of the GPIO device.
+ */
+static void pch_gpio_restore_reg_conf(struct pch_gpio *chip)
+{
+ /* to store contents of PO register */
+ iowrite32(chip->pch_gpio_reg.po_reg, &chip->reg->po);
+ /* to store contents of PM register */
+ iowrite32(chip->pch_gpio_reg.pm_reg, &chip->reg->pm);
+}
+
+static void pch_gpio_setup(struct pch_gpio *chip)
+{
+ struct gpio_chip *gpio = &chip->gpio;
+
+ gpio->label = dev_name(chip->dev);
+ gpio->owner = THIS_MODULE;
+ gpio->direction_input = pch_gpio_direction_input;
+ gpio->get = pch_gpio_get;
+ gpio->direction_output = pch_gpio_direction_output;
+ gpio->set = pch_gpio_set;
+ gpio->dbg_show = NULL;
+ gpio->base = -1;
+ gpio->ngpio = GPIO_NUM_PINS;
+ gpio->can_sleep = 0;
+}
+
+static int __devinit pch_gpio_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ s32 ret;
+ struct pch_gpio *chip;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL)
+ return -ENOMEM;
+
+ chip->dev = &pdev->dev;
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "%s : pci_enable_device FAILED", __func__);
+ goto err_pci_enable;
+ }
+
+ ret = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (ret) {
+ dev_err(&pdev->dev, "pci_request_regions FAILED-%d", ret);
+ goto err_request_regions;
+ }
+
+ chip->base = pci_iomap(pdev, 1, 0);
+ if (chip->base == 0) {
+ dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__);
+ ret = -ENOMEM;
+ goto err_iomap;
+ }
+
+ chip->reg = chip->base;
+ pci_set_drvdata(pdev, chip);
+ mutex_init(&chip->lock);
+ pch_gpio_setup(chip);
+ ret = gpiochip_add(&chip->gpio);
+ if (ret) {
+ dev_err(&pdev->dev, "PCH gpio: Failed to register GPIO\n");
+ goto err_gpiochip_add;
+ }
+
+ return 0;
+
+err_gpiochip_add:
+ pci_iounmap(pdev, chip->base);
+
+err_iomap:
+ pci_release_regions(pdev);
+
+err_request_regions:
+ pci_disable_device(pdev);
+
+err_pci_enable:
+ kfree(chip);
+ dev_err(&pdev->dev, "%s Failed returns %d\n", __func__, ret);
+ return ret;
+}
+
+static void __devexit pch_gpio_remove(struct pci_dev *pdev)
+{
+ int err;
+ struct pch_gpio *chip = pci_get_drvdata(pdev);
+
+ err = gpiochip_remove(&chip->gpio);
+ if (err)
+ dev_err(&pdev->dev, "Failed gpiochip_remove\n");
+
+ pci_iounmap(pdev, chip->base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ kfree(chip);
+}
+
+#ifdef CONFIG_PM
+static int pch_gpio_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ s32 ret;
+ struct pch_gpio *chip = pci_get_drvdata(pdev);
+
+ pch_gpio_save_reg_conf(chip);
+ pch_gpio_restore_reg_conf(chip);
+
+ ret = pci_save_state(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "pci_save_state Failed-%d\n", ret);
+ return ret;
+ }
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D0);
+ ret = pci_enable_wake(pdev, PCI_D0, 1);
+ if (ret)
+ dev_err(&pdev->dev, "pci_enable_wake Failed -%d\n", ret);
+
+ return 0;
+}
+
+static int pch_gpio_resume(struct pci_dev *pdev)
+{
+ s32 ret;
+ struct pch_gpio *chip = pci_get_drvdata(pdev);
+
+ ret = pci_enable_wake(pdev, PCI_D0, 0);
+
+ pci_set_power_state(pdev, PCI_D0);
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "pci_enable_device Failed-%d ", ret);
+ return ret;
+ }
+ pci_restore_state(pdev);
+
+ iowrite32(0x01, &chip->reg->reset);
+ iowrite32(0x00, &chip->reg->reset);
+ pch_gpio_restore_reg_conf(chip);
+
+ return 0;
+}
+#else
+#define pch_gpio_suspend NULL
+#define pch_gpio_resume NULL
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(pch_gpio_pcidev_id) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) },
+ { 0, }
+};
+
+static struct pci_driver pch_gpio_driver = {
+ .name = "pch_gpio",
+ .id_table = pch_gpio_pcidev_id,
+ .probe = pch_gpio_probe,
+ .remove = __devexit_p(pch_gpio_remove),
+ .suspend = pch_gpio_suspend,
+ .resume = pch_gpio_resume
+};
+
+static int __init pch_gpio_pci_init(void)
+{
+ return pci_register_driver(&pch_gpio_driver);
+}
+module_init(pch_gpio_pci_init);
+
+static void __exit pch_gpio_pci_exit(void)
+{
+ pci_unregister_driver(&pch_gpio_driver);
+}
+module_exit(pch_gpio_pci_exit);
+
+MODULE_DESCRIPTION("PCH GPIO PCI Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c
index ddd053108a13..45293662e950 100644
--- a/drivers/gpio/timbgpio.c
+++ b/drivers/gpio/timbgpio.c
@@ -47,6 +47,7 @@ struct timbgpio {
spinlock_t lock; /* mutual exclusion */
struct gpio_chip gpio;
int irq_base;
+ unsigned long last_ier;
};
static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index,
@@ -112,16 +113,24 @@ static void timbgpio_irq_disable(unsigned irq)
{
struct timbgpio *tgpio = get_irq_chip_data(irq);
int offset = irq - tgpio->irq_base;
+ unsigned long flags;
- timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 0);
+ spin_lock_irqsave(&tgpio->lock, flags);
+ tgpio->last_ier &= ~(1 << offset);
+ iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
+ spin_unlock_irqrestore(&tgpio->lock, flags);
}
static void timbgpio_irq_enable(unsigned irq)
{
struct timbgpio *tgpio = get_irq_chip_data(irq);
int offset = irq - tgpio->irq_base;
+ unsigned long flags;
- timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 1);
+ spin_lock_irqsave(&tgpio->lock, flags);
+ tgpio->last_ier |= 1 << offset;
+ iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
+ spin_unlock_irqrestore(&tgpio->lock, flags);
}
static int timbgpio_irq_type(unsigned irq, unsigned trigger)
@@ -194,8 +203,16 @@ static void timbgpio_irq(unsigned int irq, struct irq_desc *desc)
ipr = ioread32(tgpio->membase + TGPIO_IPR);
iowrite32(ipr, tgpio->membase + TGPIO_ICR);
+ /*
+ * Some versions of the hardware trash the IER register if more than
+ * one interrupt is received simultaneously.
+ */
+ iowrite32(0, tgpio->membase + TGPIO_IER);
+
for_each_set_bit(offset, &ipr, tgpio->gpio.ngpio)
generic_handle_irq(timbgpio_to_irq(&tgpio->gpio, offset));
+
+ iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
}
static struct irq_chip timbgpio_irqchip = {
diff --git a/drivers/gpio/xilinx_gpio.c b/drivers/gpio/xilinx_gpio.c
index 709690995d0d..846fbd5e31bf 100644
--- a/drivers/gpio/xilinx_gpio.c
+++ b/drivers/gpio/xilinx_gpio.c
@@ -171,13 +171,13 @@ static int __devinit xgpio_of_probe(struct device_node *np)
/* Update GPIO state shadow register with default value */
tree_info = of_get_property(np, "xlnx,dout-default", NULL);
if (tree_info)
- chip->gpio_state = *tree_info;
+ chip->gpio_state = be32_to_cpup(tree_info);
/* Update GPIO direction shadow register with default value */
chip->gpio_dir = 0xFFFFFFFF; /* By default, all pins are inputs */
tree_info = of_get_property(np, "xlnx,tri-default", NULL);
if (tree_info)
- chip->gpio_dir = *tree_info;
+ chip->gpio_dir = be32_to_cpup(tree_info);
/* Check device node and parent device node for device width */
chip->mmchip.gc.ngpio = 32; /* By default assume full GPIO controller */
@@ -186,7 +186,7 @@ static int __devinit xgpio_of_probe(struct device_node *np)
tree_info = of_get_property(np->parent,
"xlnx,gpio-width", NULL);
if (tree_info)
- chip->mmchip.gc.ngpio = *tree_info;
+ chip->mmchip.gc.ngpio = be32_to_cpup(tree_info);
spin_lock_init(&chip->gpio_lock);
diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile
index 30879df3daea..cc9277885dd0 100644
--- a/drivers/gpu/Makefile
+++ b/drivers/gpu/Makefile
@@ -1 +1 @@
-obj-y += drm/ vga/
+obj-y += drm/ vga/ stub/
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index f3a23a329f4e..997c43d04909 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -5,7 +5,7 @@
ccflags-y := -Iinclude/drm
drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
- drm_context.o drm_dma.o drm_drawable.o \
+ drm_context.o drm_dma.o \
drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c
index ba38e0147220..252fdb98b73a 100644
--- a/drivers/gpu/drm/drm_agpsupport.c
+++ b/drivers/gpu/drm/drm_agpsupport.c
@@ -193,7 +193,7 @@ int drm_agp_enable_ioctl(struct drm_device *dev, void *data,
* \return zero on success or a negative number on failure.
*
* Verifies the AGP device is present and has been acquired, allocates the
- * memory via alloc_agp() and creates a drm_agp_mem entry for it.
+ * memory via agp_allocate_memory() and creates a drm_agp_mem entry for it.
*/
int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
{
@@ -211,7 +211,7 @@ int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
type = (u32) request->type;
- if (!(memory = drm_alloc_agp(dev, pages, type))) {
+ if (!(memory = agp_allocate_memory(dev->agp->bridge, pages, type))) {
kfree(entry);
return -ENOMEM;
}
@@ -423,38 +423,6 @@ struct drm_agp_head *drm_agp_init(struct drm_device *dev)
return head;
}
-/** Calls agp_allocate_memory() */
-DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data * bridge,
- size_t pages, u32 type)
-{
- return agp_allocate_memory(bridge, pages, type);
-}
-
-/** Calls agp_free_memory() */
-int drm_agp_free_memory(DRM_AGP_MEM * handle)
-{
- if (!handle)
- return 0;
- agp_free_memory(handle);
- return 1;
-}
-
-/** Calls agp_bind_memory() */
-int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start)
-{
- if (!handle)
- return -EINVAL;
- return agp_bind_memory(handle, start);
-}
-
-/** Calls agp_unbind_memory() */
-int drm_agp_unbind_memory(DRM_AGP_MEM * handle)
-{
- if (!handle)
- return -EINVAL;
- return agp_unbind_memory(handle);
-}
-
/**
* Binds a collection of pages into AGP memory at the given offset, returning
* the AGP memory structure containing them.
@@ -474,7 +442,7 @@ drm_agp_bind_pages(struct drm_device *dev,
DRM_DEBUG("\n");
- mem = drm_agp_allocate_memory(dev->agp->bridge, num_pages,
+ mem = agp_allocate_memory(dev->agp->bridge, num_pages,
type);
if (mem == NULL) {
DRM_ERROR("Failed to allocate memory for %ld pages\n",
@@ -487,7 +455,7 @@ drm_agp_bind_pages(struct drm_device *dev,
mem->page_count = num_pages;
mem->is_flushed = true;
- ret = drm_agp_bind_memory(mem, gtt_offset / PAGE_SIZE);
+ ret = agp_bind_memory(mem, gtt_offset / PAGE_SIZE);
if (ret != 0) {
DRM_ERROR("Failed to bind AGP memory: %d\n", ret);
agp_free_memory(mem);
diff --git a/drivers/gpu/drm/drm_context.c b/drivers/gpu/drm/drm_context.c
index 2607753a320b..6d440fb894cf 100644
--- a/drivers/gpu/drm/drm_context.c
+++ b/drivers/gpu/drm/drm_context.c
@@ -333,14 +333,6 @@ int drm_addctx(struct drm_device *dev, void *data,
return -ENOMEM;
}
- if (ctx->handle != DRM_KERNEL_CONTEXT) {
- if (dev->driver->context_ctor)
- if (!dev->driver->context_ctor(dev, ctx->handle)) {
- DRM_DEBUG("Running out of ctxs or memory.\n");
- return -ENOMEM;
- }
- }
-
ctx_entry = kmalloc(sizeof(*ctx_entry), GFP_KERNEL);
if (!ctx_entry) {
DRM_DEBUG("out of memory\n");
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 37e0b4fa482a..6985cb1da72c 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1854,7 +1854,8 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
}
if (fb->funcs->dirty) {
- ret = fb->funcs->dirty(fb, flags, r->color, clips, num_clips);
+ ret = fb->funcs->dirty(fb, file_priv, flags, r->color,
+ clips, num_clips);
} else {
ret = -ENOSYS;
goto out_err2;
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index 677b275fa721..9d8c892d07c9 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -48,7 +48,6 @@ static struct drm_info_list drm_debugfs_list[] = {
{"queues", drm_queues_info, 0},
{"bufs", drm_bufs_info, 0},
{"gem_names", drm_gem_name_info, DRIVER_GEM},
- {"gem_objects", drm_gem_object_info, DRIVER_GEM},
#if DRM_DEBUG_CODE
{"vma", drm_vma_info, 0},
#endif
diff --git a/drivers/gpu/drm/drm_drawable.c b/drivers/gpu/drm/drm_drawable.c
deleted file mode 100644
index c53c9768cc11..000000000000
--- a/drivers/gpu/drm/drm_drawable.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/**
- * \file drm_drawable.c
- * IOCTLs for drawables
- *
- * \author Rickard E. (Rik) Faith <faith@valinux.com>
- * \author Gareth Hughes <gareth@valinux.com>
- * \author Michel Dänzer <michel@tungstengraphics.com>
- */
-
-/*
- * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include "drmP.h"
-
-/**
- * Allocate drawable ID and memory to store information about it.
- */
-int drm_adddraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- unsigned long irqflags;
- struct drm_draw *draw = data;
- int new_id = 0;
- int ret;
-
-again:
- if (idr_pre_get(&dev->drw_idr, GFP_KERNEL) == 0) {
- DRM_ERROR("Out of memory expanding drawable idr\n");
- return -ENOMEM;
- }
-
- spin_lock_irqsave(&dev->drw_lock, irqflags);
- ret = idr_get_new_above(&dev->drw_idr, NULL, 1, &new_id);
- if (ret == -EAGAIN) {
- spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- goto again;
- }
-
- spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-
- draw->handle = new_id;
-
- DRM_DEBUG("%d\n", draw->handle);
-
- return 0;
-}
-
-/**
- * Free drawable ID and memory to store information about it.
- */
-int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- struct drm_draw *draw = data;
- unsigned long irqflags;
- struct drm_drawable_info *info;
-
- spin_lock_irqsave(&dev->drw_lock, irqflags);
-
- info = drm_get_drawable_info(dev, draw->handle);
- if (info == NULL) {
- spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- return -EINVAL;
- }
- kfree(info->rects);
- kfree(info);
-
- idr_remove(&dev->drw_idr, draw->handle);
-
- spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- DRM_DEBUG("%d\n", draw->handle);
- return 0;
-}
-
-int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- struct drm_update_draw *update = data;
- unsigned long irqflags;
- struct drm_clip_rect *rects;
- struct drm_drawable_info *info;
- int err;
-
- info = idr_find(&dev->drw_idr, update->handle);
- if (!info) {
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
- if (IS_ERR(idr_replace(&dev->drw_idr, info, update->handle))) {
- DRM_ERROR("No such drawable %d\n", update->handle);
- kfree(info);
- return -EINVAL;
- }
- }
-
- switch (update->type) {
- case DRM_DRAWABLE_CLIPRECTS:
- if (update->num == 0)
- rects = NULL;
- else if (update->num != info->num_rects) {
- rects = kmalloc(update->num *
- sizeof(struct drm_clip_rect),
- GFP_KERNEL);
- } else
- rects = info->rects;
-
- if (update->num && !rects) {
- DRM_ERROR("Failed to allocate cliprect memory\n");
- err = -ENOMEM;
- goto error;
- }
-
- if (update->num && DRM_COPY_FROM_USER(rects,
- (struct drm_clip_rect __user *)
- (unsigned long)update->data,
- update->num *
- sizeof(*rects))) {
- DRM_ERROR("Failed to copy cliprects from userspace\n");
- err = -EFAULT;
- goto error;
- }
-
- spin_lock_irqsave(&dev->drw_lock, irqflags);
-
- if (rects != info->rects) {
- kfree(info->rects);
- }
-
- info->rects = rects;
- info->num_rects = update->num;
-
- spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-
- DRM_DEBUG("Updated %d cliprects for drawable %d\n",
- info->num_rects, update->handle);
- break;
- default:
- DRM_ERROR("Invalid update type %d\n", update->type);
- return -EINVAL;
- }
-
- return 0;
-
-error:
- if (rects != info->rects)
- kfree(rects);
-
- return err;
-}
-
-/**
- * Caller must hold the drawable spinlock!
- */
-struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev, drm_drawable_t id)
-{
- return idr_find(&dev->drw_idr, id);
-}
-EXPORT_SYMBOL(drm_get_drawable_info);
-
-static int drm_drawable_free(int idr, void *p, void *data)
-{
- struct drm_drawable_info *info = p;
-
- if (info) {
- kfree(info->rects);
- kfree(info);
- }
-
- return 0;
-}
-
-void drm_drawable_free_all(struct drm_device *dev)
-{
- idr_for_each(&dev->drw_idr, drm_drawable_free, NULL);
- idr_remove_all(&dev->drw_idr);
-}
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index ff6690f4fc87..271835a71570 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -91,8 +91,8 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_resctx, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_lock, DRM_AUTH),
DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_unlock, DRM_AUTH),
@@ -127,7 +127,7 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),
- DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED),
@@ -180,10 +180,6 @@ int drm_lastclose(struct drm_device * dev)
mutex_lock(&dev->struct_mutex);
- /* Free drawable information memory */
- drm_drawable_free_all(dev);
- del_timer(&dev->timer);
-
/* Clear AGP information */
if (drm_core_has_AGP(dev) && dev->agp &&
!drm_core_check_feature(dev, DRIVER_MODESET)) {
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 96e963108225..c1a26217a530 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -30,7 +30,6 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
#include "drmP.h"
#include "drm_edid.h"
#include "drm_edid_modes.h"
@@ -1268,34 +1267,51 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
}
#define HDMI_IDENTIFIER 0x000C03
+#define AUDIO_BLOCK 0x01
#define VENDOR_BLOCK 0x03
+#define EDID_BASIC_AUDIO (1 << 6)
+
/**
- * drm_detect_hdmi_monitor - detect whether monitor is hdmi.
- * @edid: monitor EDID information
- *
- * Parse the CEA extension according to CEA-861-B.
- * Return true if HDMI, false if not or unknown.
+ * Search EDID for CEA extension block.
*/
-bool drm_detect_hdmi_monitor(struct edid *edid)
+static u8 *drm_find_cea_extension(struct edid *edid)
{
- char *edid_ext = NULL;
- int i, hdmi_id;
- int start_offset, end_offset;
- bool is_hdmi = false;
+ u8 *edid_ext = NULL;
+ int i;
/* No EDID or EDID extensions */
if (edid == NULL || edid->extensions == 0)
- goto end;
+ return NULL;
/* Find CEA extension */
for (i = 0; i < edid->extensions; i++) {
- edid_ext = (char *)edid + EDID_LENGTH * (i + 1);
- /* This block is CEA extension */
- if (edid_ext[0] == 0x02)
+ edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1);
+ if (edid_ext[0] == CEA_EXT)
break;
}
if (i == edid->extensions)
+ return NULL;
+
+ return edid_ext;
+}
+
+/**
+ * drm_detect_hdmi_monitor - detect whether monitor is hdmi.
+ * @edid: monitor EDID information
+ *
+ * Parse the CEA extension according to CEA-861-B.
+ * Return true if HDMI, false if not or unknown.
+ */
+bool drm_detect_hdmi_monitor(struct edid *edid)
+{
+ u8 *edid_ext;
+ int i, hdmi_id;
+ int start_offset, end_offset;
+ bool is_hdmi = false;
+
+ edid_ext = drm_find_cea_extension(edid);
+ if (!edid_ext)
goto end;
/* Data block offset in CEA extension block */
@@ -1326,6 +1342,53 @@ end:
EXPORT_SYMBOL(drm_detect_hdmi_monitor);
/**
+ * drm_detect_monitor_audio - check monitor audio capability
+ *
+ * Monitor should have CEA extension block.
+ * If monitor has 'basic audio', but no CEA audio blocks, it's 'basic
+ * audio' only. If there is any audio extension block and supported
+ * audio format, assume at least 'basic audio' support, even if 'basic
+ * audio' is not defined in EDID.
+ *
+ */
+bool drm_detect_monitor_audio(struct edid *edid)
+{
+ u8 *edid_ext;
+ int i, j;
+ bool has_audio = false;
+ int start_offset, end_offset;
+
+ edid_ext = drm_find_cea_extension(edid);
+ if (!edid_ext)
+ goto end;
+
+ has_audio = ((edid_ext[3] & EDID_BASIC_AUDIO) != 0);
+
+ if (has_audio) {
+ DRM_DEBUG_KMS("Monitor has basic audio support\n");
+ goto end;
+ }
+
+ /* Data block offset in CEA extension block */
+ start_offset = 4;
+ end_offset = edid_ext[2];
+
+ for (i = start_offset; i < end_offset;
+ i += ((edid_ext[i] & 0x1f) + 1)) {
+ if ((edid_ext[i] >> 5) == AUDIO_BLOCK) {
+ has_audio = true;
+ for (j = 1; j < (edid_ext[i] & 0x1f); j += 3)
+ DRM_DEBUG_KMS("CEA audio format %d\n",
+ (edid_ext[i + j] >> 3) & 0xf);
+ goto end;
+ }
+ }
+end:
+ return has_audio;
+}
+EXPORT_SYMBOL(drm_detect_monitor_audio);
+
+/**
* drm_add_edid_modes - add modes from EDID data, if available
* @connector: connector we're probing
* @edid: edid data
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 6a5e403f9aa1..d2849e4ea4d0 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -242,6 +242,30 @@ static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
return 0;
}
+static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
+{
+ uint16_t *r_base, *g_base, *b_base;
+ int i;
+
+ r_base = crtc->gamma_store;
+ g_base = r_base + crtc->gamma_size;
+ b_base = g_base + crtc->gamma_size;
+
+ for (i = 0; i < crtc->gamma_size; i++)
+ helper->funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i);
+}
+
+static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
+{
+ uint16_t *r_base, *g_base, *b_base;
+
+ r_base = crtc->gamma_store;
+ g_base = r_base + crtc->gamma_size;
+ b_base = g_base + crtc->gamma_size;
+
+ crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
+}
+
int drm_fb_helper_debug_enter(struct fb_info *info)
{
struct drm_fb_helper *helper = info->par;
@@ -260,11 +284,12 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
continue;
funcs = mode_set->crtc->helper_private;
+ drm_fb_helper_save_lut_atomic(mode_set->crtc, helper);
funcs->mode_set_base_atomic(mode_set->crtc,
mode_set->fb,
mode_set->x,
- mode_set->y);
-
+ mode_set->y,
+ ENTER_ATOMIC_MODE_SET);
}
}
@@ -308,8 +333,9 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
continue;
}
+ drm_fb_helper_restore_lut_atomic(mode_set->crtc);
funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
- crtc->y);
+ crtc->y, LEAVE_ATOMIC_MODE_SET);
}
return 0;
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 5663d2719063..ea1c4b019ebf 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -92,12 +92,6 @@ drm_gem_init(struct drm_device *dev)
spin_lock_init(&dev->object_name_lock);
idr_init(&dev->object_name_idr);
- atomic_set(&dev->object_count, 0);
- atomic_set(&dev->object_memory, 0);
- atomic_set(&dev->pin_count, 0);
- atomic_set(&dev->pin_memory, 0);
- atomic_set(&dev->gtt_count, 0);
- atomic_set(&dev->gtt_memory, 0);
mm = kzalloc(sizeof(struct drm_gem_mm), GFP_KERNEL);
if (!mm) {
@@ -151,9 +145,6 @@ int drm_gem_object_init(struct drm_device *dev,
atomic_set(&obj->handle_count, 0);
obj->size = size;
- atomic_inc(&dev->object_count);
- atomic_add(obj->size, &dev->object_memory);
-
return 0;
}
EXPORT_SYMBOL(drm_gem_object_init);
@@ -180,8 +171,6 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size)
return obj;
fput:
/* Object_init mangles the global counters - readjust them. */
- atomic_dec(&dev->object_count);
- atomic_sub(obj->size, &dev->object_memory);
fput(obj->filp);
free:
kfree(obj);
@@ -436,10 +425,7 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
void
drm_gem_object_release(struct drm_gem_object *obj)
{
- struct drm_device *dev = obj->dev;
fput(obj->filp);
- atomic_dec(&dev->object_count);
- atomic_sub(obj->size, &dev->object_memory);
}
EXPORT_SYMBOL(drm_gem_object_release);
diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c
index 974e970ce3f8..3cdbaf379bb5 100644
--- a/drivers/gpu/drm/drm_info.c
+++ b/drivers/gpu/drm/drm_info.c
@@ -270,20 +270,6 @@ int drm_gem_name_info(struct seq_file *m, void *data)
return 0;
}
-int drm_gem_object_info(struct seq_file *m, void* data)
-{
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_device *dev = node->minor->dev;
-
- seq_printf(m, "%d objects\n", atomic_read(&dev->object_count));
- seq_printf(m, "%d object bytes\n", atomic_read(&dev->object_memory));
- seq_printf(m, "%d pinned\n", atomic_read(&dev->pin_count));
- seq_printf(m, "%d pin bytes\n", atomic_read(&dev->pin_memory));
- seq_printf(m, "%d gtt bytes\n", atomic_read(&dev->gtt_memory));
- seq_printf(m, "%d gtt total\n", dev->gtt_total);
- return 0;
-}
-
#if DRM_DEBUG_CODE
int drm_vma_info(struct seq_file *m, void *data)
diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c
index 9bf93bc9a32c..632ae243ede0 100644
--- a/drivers/gpu/drm/drm_lock.c
+++ b/drivers/gpu/drm/drm_lock.c
@@ -37,6 +37,8 @@
static int drm_notifier(void *priv);
+static int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context);
+
/**
* Lock ioctl.
*
@@ -124,9 +126,6 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
}
- if (dev->driver->dma_ready && (lock->flags & _DRM_LOCK_READY))
- dev->driver->dma_ready(dev);
-
if (dev->driver->dma_quiescent && (lock->flags & _DRM_LOCK_QUIESCENT))
{
if (dev->driver->dma_quiescent(dev)) {
@@ -136,12 +135,6 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
}
}
- if (dev->driver->kernel_context_switch &&
- dev->last_context != lock->context) {
- dev->driver->kernel_context_switch(dev, dev->last_context,
- lock->context);
- }
-
return 0;
}
@@ -169,15 +162,8 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
- /* kernel_context_switch isn't used by any of the x86 drm
- * modules but is required by the Sparc driver.
- */
- if (dev->driver->kernel_context_switch_unlock)
- dev->driver->kernel_context_switch_unlock(dev);
- else {
- if (drm_lock_free(&master->lock, lock->context)) {
- /* FIXME: Should really bail out here. */
- }
+ if (drm_lock_free(&master->lock, lock->context)) {
+ /* FIXME: Should really bail out here. */
}
unblock_all_signals();
@@ -193,6 +179,7 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
*
* Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction.
*/
+static
int drm_lock_take(struct drm_lock_data *lock_data,
unsigned int context)
{
@@ -229,7 +216,6 @@ int drm_lock_take(struct drm_lock_data *lock_data,
}
return 0;
}
-EXPORT_SYMBOL(drm_lock_take);
/**
* This takes a lock forcibly and hands it to context. Should ONLY be used
@@ -297,7 +283,6 @@ int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context)
wake_up_interruptible(&lock_data->lock_queue);
return 0;
}
-EXPORT_SYMBOL(drm_lock_free);
/**
* If we get here, it means that the process has called DRM_IOCTL_LOCK
@@ -360,7 +345,6 @@ void drm_idlelock_take(struct drm_lock_data *lock_data)
}
spin_unlock_bh(&lock_data->spinlock);
}
-EXPORT_SYMBOL(drm_idlelock_take);
void drm_idlelock_release(struct drm_lock_data *lock_data)
{
@@ -380,8 +364,6 @@ void drm_idlelock_release(struct drm_lock_data *lock_data)
}
spin_unlock_bh(&lock_data->spinlock);
}
-EXPORT_SYMBOL(drm_idlelock_release);
-
int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv)
{
@@ -390,5 +372,3 @@ int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv)
_DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) &&
master->lock.file_priv == file_priv);
}
-
-EXPORT_SYMBOL(drm_i_have_hw_lock);
diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c
index 7732268eced2..c9b805000a11 100644
--- a/drivers/gpu/drm/drm_memory.c
+++ b/drivers/gpu/drm/drm_memory.c
@@ -99,29 +99,23 @@ static void *agp_remap(unsigned long offset, unsigned long size,
return addr;
}
-/** Wrapper around agp_allocate_memory() */
-DRM_AGP_MEM *drm_alloc_agp(struct drm_device * dev, int pages, u32 type)
-{
- return drm_agp_allocate_memory(dev->agp->bridge, pages, type);
-}
-
/** Wrapper around agp_free_memory() */
-int drm_free_agp(DRM_AGP_MEM * handle, int pages)
+void drm_free_agp(DRM_AGP_MEM * handle, int pages)
{
- return drm_agp_free_memory(handle) ? 0 : -EINVAL;
+ agp_free_memory(handle);
}
EXPORT_SYMBOL(drm_free_agp);
/** Wrapper around agp_bind_memory() */
int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start)
{
- return drm_agp_bind_memory(handle, start);
+ return agp_bind_memory(handle, start);
}
/** Wrapper around agp_unbind_memory() */
int drm_unbind_agp(DRM_AGP_MEM * handle)
{
- return drm_agp_unbind_memory(handle);
+ return agp_unbind_memory(handle);
}
EXPORT_SYMBOL(drm_unbind_agp);
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 949326d2a8e5..58e65f92c232 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -76,7 +76,7 @@ EXPORT_SYMBOL(drm_mode_debug_printmodeline);
* according to the hdisplay, vdisplay, vrefresh.
* It is based from the VESA(TM) Coordinated Video Timing Generator by
* Graham Loveridge April 9, 2003 available at
- * http://www.vesa.org/public/CVT/CVTd6r1.xls
+ * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls
*
* And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c.
* What I have done is to translate it by using integer calculation.
diff --git a/drivers/gpu/drm/drm_proc.c b/drivers/gpu/drm/drm_proc.c
index a9ba6b69ad35..9e5b07efebb7 100644
--- a/drivers/gpu/drm/drm_proc.c
+++ b/drivers/gpu/drm/drm_proc.c
@@ -55,7 +55,6 @@ static struct drm_info_list drm_proc_list[] = {
{"queues", drm_queues_info, 0},
{"bufs", drm_bufs_info, 0},
{"gem_names", drm_gem_name_info, DRIVER_GEM},
- {"gem_objects", drm_gem_object_info, DRIVER_GEM},
#if DRM_DEBUG_CODE
{"vma", drm_vma_info, 0},
#endif
@@ -151,7 +150,6 @@ fail:
int drm_proc_init(struct drm_minor *minor, int minor_id,
struct proc_dir_entry *root)
{
- struct drm_device *dev = minor->dev;
char name[64];
int ret;
@@ -172,14 +170,6 @@ int drm_proc_init(struct drm_minor *minor, int minor_id,
return ret;
}
- if (dev->driver->proc_init) {
- ret = dev->driver->proc_init(minor);
- if (ret) {
- DRM_ERROR("DRM: Driver failed to initialize "
- "/proc/dri.\n");
- return ret;
- }
- }
return 0;
}
@@ -216,15 +206,11 @@ int drm_proc_remove_files(struct drm_info_list *files, int count,
*/
int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root)
{
- struct drm_device *dev = minor->dev;
char name[64];
if (!root || !minor->proc_root)
return 0;
- if (dev->driver->proc_cleanup)
- dev->driver->proc_cleanup(minor);
-
drm_proc_remove_files(drm_proc_list, DRM_PROC_ENTRIES, minor);
sprintf(name, "%d", minor->index);
diff --git a/drivers/gpu/drm/drm_scatter.c b/drivers/gpu/drm/drm_scatter.c
index 9034c4c6100d..d15e09b0ae0b 100644
--- a/drivers/gpu/drm/drm_scatter.c
+++ b/drivers/gpu/drm/drm_scatter.c
@@ -184,8 +184,6 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request)
drm_sg_cleanup(entry);
return -ENOMEM;
}
-EXPORT_SYMBOL(drm_sg_alloc);
-
int drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index d1ad57450df1..cdc89ee042cc 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -240,14 +240,10 @@ int drm_fill_in_dev(struct drm_device *dev,
INIT_LIST_HEAD(&dev->vblank_event_list);
spin_lock_init(&dev->count_lock);
- spin_lock_init(&dev->drw_lock);
spin_lock_init(&dev->event_lock);
- init_timer(&dev->timer);
mutex_init(&dev->struct_mutex);
mutex_init(&dev->ctxlist_mutex);
- idr_init(&dev->drw_idr);
-
if (drm_ht_create(&dev->map_hash, 12)) {
return -ENOMEM;
}
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c
index 5df450683aab..2c3fcbdfd8ff 100644
--- a/drivers/gpu/drm/drm_vm.c
+++ b/drivers/gpu/drm/drm_vm.c
@@ -523,14 +523,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
return 0;
}
-resource_size_t drm_core_get_map_ofs(struct drm_local_map * map)
-{
- return map->offset;
-}
-
-EXPORT_SYMBOL(drm_core_get_map_ofs);
-
-resource_size_t drm_core_get_reg_ofs(struct drm_device *dev)
+static resource_size_t drm_core_get_reg_ofs(struct drm_device *dev)
{
#ifdef __alpha__
return dev->hose->dense_mem_base - dev->hose->mem_space->start;
@@ -539,8 +532,6 @@ resource_size_t drm_core_get_reg_ofs(struct drm_device *dev)
#endif
}
-EXPORT_SYMBOL(drm_core_get_reg_ofs);
-
/**
* mmap DMA memory.
*
@@ -627,7 +618,7 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
#endif
case _DRM_FRAME_BUFFER:
case _DRM_REGISTERS:
- offset = dev->driver->get_reg_ofs(dev);
+ offset = drm_core_get_reg_ofs(dev);
vma->vm_flags |= VM_IO; /* not in core dump */
vma->vm_page_prot = drm_io_prot(map->type, vma);
#if !defined(__arm__)
diff --git a/drivers/gpu/drm/i810/i810_drv.c b/drivers/gpu/drm/i810/i810_drv.c
index fe69914ce507..88bcd331e7c5 100644
--- a/drivers/gpu/drm/i810/i810_drv.c
+++ b/drivers/gpu/drm/i810/i810_drv.c
@@ -52,8 +52,6 @@ static struct drm_driver driver = {
.device_is_agp = i810_driver_device_is_agp,
.reclaim_buffers_locked = i810_driver_reclaim_buffers_locked,
.dma_quiescent = i810_driver_dma_quiescent,
- .get_map_ofs = drm_core_get_map_ofs,
- .get_reg_ofs = drm_core_get_reg_ofs,
.ioctls = i810_ioctls,
.fops = {
.owner = THIS_MODULE,
diff --git a/drivers/gpu/drm/i830/i830_drv.c b/drivers/gpu/drm/i830/i830_drv.c
index 5b6298b24e24..f655ab7977da 100644
--- a/drivers/gpu/drm/i830/i830_drv.c
+++ b/drivers/gpu/drm/i830/i830_drv.c
@@ -57,8 +57,6 @@ static struct drm_driver driver = {
.device_is_agp = i830_driver_device_is_agp,
.reclaim_buffers_locked = i830_driver_reclaim_buffers_locked,
.dma_quiescent = i830_driver_dma_quiescent,
- .get_map_ofs = drm_core_get_map_ofs,
- .get_reg_ofs = drm_core_get_reg_ofs,
#if USE_IRQS
.irq_preinstall = i830_driver_irq_preinstall,
.irq_postinstall = i830_driver_irq_postinstall,
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 5c8e53458edb..fdc833d5cc7b 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -26,15 +26,17 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
intel_dvo.o \
intel_ringbuffer.o \
intel_overlay.o \
+ intel_opregion.o \
dvo_ch7xxx.o \
dvo_ch7017.o \
dvo_ivch.o \
dvo_tfp410.o \
dvo_sil164.o
-i915-$(CONFIG_ACPI) += i915_opregion.o
i915-$(CONFIG_COMPAT) += i915_ioc32.o
+i915-$(CONFIG_ACPI) += intel_acpi.o
+
obj-$(CONFIG_DRM_I915) += i915.o
CFLAGS_i915_trace_points.o := -I$(src)
diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c
index 14d59804acd7..af70337567ce 100644
--- a/drivers/gpu/drm/i915/dvo_ch7017.c
+++ b/drivers/gpu/drm/i915/dvo_ch7017.c
@@ -165,67 +165,44 @@ struct ch7017_priv {
static void ch7017_dump_regs(struct intel_dvo_device *dvo);
static void ch7017_dpms(struct intel_dvo_device *dvo, int mode);
-static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
+static bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val)
{
- struct i2c_adapter *adapter = dvo->i2c_bus;
- struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
- u8 out_buf[2];
- u8 in_buf[2];
-
struct i2c_msg msgs[] = {
{
.addr = dvo->slave_addr,
.flags = 0,
.len = 1,
- .buf = out_buf,
+ .buf = &addr,
},
{
.addr = dvo->slave_addr,
.flags = I2C_M_RD,
.len = 1,
- .buf = in_buf,
+ .buf = val,
}
};
-
- out_buf[0] = addr;
- out_buf[1] = 0;
-
- if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
- *val= in_buf[0];
- return true;
- };
-
- return false;
+ return i2c_transfer(dvo->i2c_bus, msgs, 2) == 2;
}
-static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
+static bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val)
{
- struct i2c_adapter *adapter = dvo->i2c_bus;
- struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
- uint8_t out_buf[2];
+ uint8_t buf[2] = { addr, val };
struct i2c_msg msg = {
.addr = dvo->slave_addr,
.flags = 0,
.len = 2,
- .buf = out_buf,
+ .buf = buf,
};
-
- out_buf[0] = addr;
- out_buf[1] = val;
-
- if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
- return true;
-
- return false;
+ return i2c_transfer(dvo->i2c_bus, &msg, 1) == 1;
}
/** Probes for a CH7017 on the given bus and slave address. */
static bool ch7017_init(struct intel_dvo_device *dvo,
struct i2c_adapter *adapter)
{
- struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
struct ch7017_priv *priv;
- uint8_t val;
+ const char *str;
+ u8 val;
priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL);
if (priv == NULL)
@@ -237,16 +214,27 @@ static bool ch7017_init(struct intel_dvo_device *dvo,
if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val))
goto fail;
- if (val != CH7017_DEVICE_ID_VALUE &&
- val != CH7018_DEVICE_ID_VALUE &&
- val != CH7019_DEVICE_ID_VALUE) {
+ switch (val) {
+ case CH7017_DEVICE_ID_VALUE:
+ str = "ch7017";
+ break;
+ case CH7018_DEVICE_ID_VALUE:
+ str = "ch7018";
+ break;
+ case CH7019_DEVICE_ID_VALUE:
+ str = "ch7019";
+ break;
+ default:
DRM_DEBUG_KMS("ch701x not detected, got %d: from %s "
- "Slave %d.\n",
- val, i2cbus->adapter.name,dvo->slave_addr);
+ "slave %d.\n",
+ val, adapter->name,dvo->slave_addr);
goto fail;
}
+ DRM_DEBUG_KMS("%s detected on %s, addr %d\n",
+ str, adapter->name, dvo->slave_addr);
return true;
+
fail:
kfree(priv);
return false;
@@ -368,7 +356,7 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, int mode)
}
/* XXX: Should actually wait for update power status somehow */
- udelay(20000);
+ msleep(20);
}
static void ch7017_dump_regs(struct intel_dvo_device *dvo)
diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c
index 6f1944b24441..7eaa94e4ff06 100644
--- a/drivers/gpu/drm/i915/dvo_ch7xxx.c
+++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c
@@ -113,7 +113,6 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
{
struct ch7xxx_priv *ch7xxx= dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
- struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[2];
u8 in_buf[2];
@@ -135,14 +134,14 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
out_buf[0] = addr;
out_buf[1] = 0;
- if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+ if (i2c_transfer(adapter, msgs, 2) == 2) {
*ch = in_buf[0];
return true;
};
if (!ch7xxx->quiet) {
DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
- addr, i2cbus->adapter.name, dvo->slave_addr);
+ addr, adapter->name, dvo->slave_addr);
}
return false;
}
@@ -152,7 +151,6 @@ static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
{
struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
- struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
uint8_t out_buf[2];
struct i2c_msg msg = {
.addr = dvo->slave_addr,
@@ -164,12 +162,12 @@ static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
out_buf[0] = addr;
out_buf[1] = ch;
- if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+ if (i2c_transfer(adapter, &msg, 1) == 1)
return true;
if (!ch7xxx->quiet) {
DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
- addr, i2cbus->adapter.name, dvo->slave_addr);
+ addr, adapter->name, dvo->slave_addr);
}
return false;
diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c
index a2ec3f487202..a12ed9414cc7 100644
--- a/drivers/gpu/drm/i915/dvo_ivch.c
+++ b/drivers/gpu/drm/i915/dvo_ivch.c
@@ -167,7 +167,6 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
{
struct ivch_priv *priv = dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
- struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[1];
u8 in_buf[2];
@@ -193,7 +192,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
out_buf[0] = addr;
- if (i2c_transfer(&i2cbus->adapter, msgs, 3) == 3) {
+ if (i2c_transfer(adapter, msgs, 3) == 3) {
*data = (in_buf[1] << 8) | in_buf[0];
return true;
};
@@ -201,7 +200,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
if (!priv->quiet) {
DRM_DEBUG_KMS("Unable to read register 0x%02x from "
"%s:%02x.\n",
- addr, i2cbus->adapter.name, dvo->slave_addr);
+ addr, adapter->name, dvo->slave_addr);
}
return false;
}
@@ -211,7 +210,6 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
{
struct ivch_priv *priv = dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
- struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[3];
struct i2c_msg msg = {
.addr = dvo->slave_addr,
@@ -224,12 +222,12 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
out_buf[1] = data & 0xff;
out_buf[2] = data >> 8;
- if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+ if (i2c_transfer(adapter, &msg, 1) == 1)
return true;
if (!priv->quiet) {
DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
- addr, i2cbus->adapter.name, dvo->slave_addr);
+ addr, adapter->name, dvo->slave_addr);
}
return false;
diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c
index 9b8e6765cf26..e4b4091df942 100644
--- a/drivers/gpu/drm/i915/dvo_sil164.c
+++ b/drivers/gpu/drm/i915/dvo_sil164.c
@@ -69,7 +69,6 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
{
struct sil164_priv *sil = dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
- struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[2];
u8 in_buf[2];
@@ -91,14 +90,14 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
out_buf[0] = addr;
out_buf[1] = 0;
- if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+ if (i2c_transfer(adapter, msgs, 2) == 2) {
*ch = in_buf[0];
return true;
};
if (!sil->quiet) {
DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
- addr, i2cbus->adapter.name, dvo->slave_addr);
+ addr, adapter->name, dvo->slave_addr);
}
return false;
}
@@ -107,7 +106,6 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
{
struct sil164_priv *sil= dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
- struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
uint8_t out_buf[2];
struct i2c_msg msg = {
.addr = dvo->slave_addr,
@@ -119,12 +117,12 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
out_buf[0] = addr;
out_buf[1] = ch;
- if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+ if (i2c_transfer(adapter, &msg, 1) == 1)
return true;
if (!sil->quiet) {
DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
- addr, i2cbus->adapter.name, dvo->slave_addr);
+ addr, adapter->name, dvo->slave_addr);
}
return false;
diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c
index 56f66426207f..8ab2855bb544 100644
--- a/drivers/gpu/drm/i915/dvo_tfp410.c
+++ b/drivers/gpu/drm/i915/dvo_tfp410.c
@@ -94,7 +94,6 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
{
struct tfp410_priv *tfp = dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
- struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[2];
u8 in_buf[2];
@@ -116,14 +115,14 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
out_buf[0] = addr;
out_buf[1] = 0;
- if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+ if (i2c_transfer(adapter, msgs, 2) == 2) {
*ch = in_buf[0];
return true;
};
if (!tfp->quiet) {
DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
- addr, i2cbus->adapter.name, dvo->slave_addr);
+ addr, adapter->name, dvo->slave_addr);
}
return false;
}
@@ -132,7 +131,6 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
{
struct tfp410_priv *tfp = dvo->dev_priv;
struct i2c_adapter *adapter = dvo->i2c_bus;
- struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
uint8_t out_buf[2];
struct i2c_msg msg = {
.addr = dvo->slave_addr,
@@ -144,12 +142,12 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
out_buf[0] = addr;
out_buf[1] = ch;
- if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+ if (i2c_transfer(adapter, &msg, 1) == 1)
return true;
if (!tfp->quiet) {
DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
- addr, i2cbus->adapter.name, dvo->slave_addr);
+ addr, adapter->name, dvo->slave_addr);
}
return false;
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 048149748fdc..1f4f3ceb63c7 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -40,9 +40,51 @@
#if defined(CONFIG_DEBUG_FS)
-#define ACTIVE_LIST 1
-#define FLUSHING_LIST 2
-#define INACTIVE_LIST 3
+enum {
+ ACTIVE_LIST,
+ FLUSHING_LIST,
+ INACTIVE_LIST,
+ PINNED_LIST,
+ DEFERRED_FREE_LIST,
+};
+
+static const char *yesno(int v)
+{
+ return v ? "yes" : "no";
+}
+
+static int i915_capabilities(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ const struct intel_device_info *info = INTEL_INFO(dev);
+
+ seq_printf(m, "gen: %d\n", info->gen);
+#define B(x) seq_printf(m, #x ": %s\n", yesno(info->x))
+ B(is_mobile);
+ B(is_i85x);
+ B(is_i915g);
+ B(is_i945gm);
+ B(is_g33);
+ B(need_gfx_hws);
+ B(is_g4x);
+ B(is_pineview);
+ B(is_broadwater);
+ B(is_crestline);
+ B(has_fbc);
+ B(has_rc6);
+ B(has_pipe_cxsr);
+ B(has_hotplug);
+ B(cursor_needs_physical);
+ B(has_overlay);
+ B(overlay_needs_physical);
+ B(supports_tv);
+ B(has_bsd_ring);
+ B(has_blt_ring);
+#undef B
+
+ return 0;
+}
static const char *get_pin_flag(struct drm_i915_gem_object *obj_priv)
{
@@ -64,6 +106,29 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj_priv)
}
}
+static void
+describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
+{
+ seq_printf(m, "%p: %s%s %8zd %08x %08x %d%s%s",
+ &obj->base,
+ get_pin_flag(obj),
+ get_tiling_flag(obj),
+ obj->base.size,
+ obj->base.read_domains,
+ obj->base.write_domain,
+ obj->last_rendering_seqno,
+ obj->dirty ? " dirty" : "",
+ obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
+ if (obj->base.name)
+ seq_printf(m, " (name: %d)", obj->base.name);
+ if (obj->fence_reg != I915_FENCE_REG_NONE)
+ seq_printf(m, " (fence: %d)", obj->fence_reg);
+ if (obj->gtt_space != NULL)
+ seq_printf(m, " (gtt_offset: %08x)", obj->gtt_offset);
+ if (obj->ring != NULL)
+ seq_printf(m, " (%s)", obj->ring->name);
+}
+
static int i915_gem_object_list_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -72,56 +137,80 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv;
- spinlock_t *lock = NULL;
+ size_t total_obj_size, total_gtt_size;
+ int count, ret;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
switch (list) {
case ACTIVE_LIST:
seq_printf(m, "Active:\n");
- lock = &dev_priv->mm.active_list_lock;
- head = &dev_priv->render_ring.active_list;
+ head = &dev_priv->mm.active_list;
break;
case INACTIVE_LIST:
seq_printf(m, "Inactive:\n");
head = &dev_priv->mm.inactive_list;
break;
+ case PINNED_LIST:
+ seq_printf(m, "Pinned:\n");
+ head = &dev_priv->mm.pinned_list;
+ break;
case FLUSHING_LIST:
seq_printf(m, "Flushing:\n");
head = &dev_priv->mm.flushing_list;
break;
+ case DEFERRED_FREE_LIST:
+ seq_printf(m, "Deferred free:\n");
+ head = &dev_priv->mm.deferred_free_list;
+ break;
default:
- DRM_INFO("Ooops, unexpected list\n");
- return 0;
+ mutex_unlock(&dev->struct_mutex);
+ return -EINVAL;
}
- if (lock)
- spin_lock(lock);
- list_for_each_entry(obj_priv, head, list)
- {
- seq_printf(m, " %p: %s %8zd %08x %08x %d%s%s",
- &obj_priv->base,
- get_pin_flag(obj_priv),
- obj_priv->base.size,
- obj_priv->base.read_domains,
- obj_priv->base.write_domain,
- obj_priv->last_rendering_seqno,
- obj_priv->dirty ? " dirty" : "",
- obj_priv->madv == I915_MADV_DONTNEED ? " purgeable" : "");
-
- if (obj_priv->base.name)
- seq_printf(m, " (name: %d)", obj_priv->base.name);
- if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
- seq_printf(m, " (fence: %d)", obj_priv->fence_reg);
- if (obj_priv->gtt_space != NULL)
- seq_printf(m, " (gtt_offset: %08x)", obj_priv->gtt_offset);
-
+ total_obj_size = total_gtt_size = count = 0;
+ list_for_each_entry(obj_priv, head, mm_list) {
+ seq_printf(m, " ");
+ describe_obj(m, obj_priv);
seq_printf(m, "\n");
+ total_obj_size += obj_priv->base.size;
+ total_gtt_size += obj_priv->gtt_space->size;
+ count++;
}
+ mutex_unlock(&dev->struct_mutex);
- if (lock)
- spin_unlock(lock);
+ seq_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n",
+ count, total_obj_size, total_gtt_size);
return 0;
}
+static int i915_gem_object_info(struct seq_file *m, void* data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
+
+ seq_printf(m, "%u objects\n", dev_priv->mm.object_count);
+ seq_printf(m, "%zu object bytes\n", dev_priv->mm.object_memory);
+ seq_printf(m, "%u pinned\n", dev_priv->mm.pin_count);
+ seq_printf(m, "%zu pin bytes\n", dev_priv->mm.pin_memory);
+ seq_printf(m, "%u objects in gtt\n", dev_priv->mm.gtt_count);
+ seq_printf(m, "%zu gtt bytes\n", dev_priv->mm.gtt_memory);
+ seq_printf(m, "%zu gtt total\n", dev_priv->mm.gtt_total);
+
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
+
static int i915_gem_pageflip_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -176,6 +265,11 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_request *gem_request;
+ int ret;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
seq_printf(m, "Request:\n");
list_for_each_entry(gem_request, &dev_priv->render_ring.request_list,
@@ -184,6 +278,8 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
gem_request->seqno,
(int) (jiffies - gem_request->emitted_jiffies));
}
+ mutex_unlock(&dev->struct_mutex);
+
return 0;
}
@@ -192,16 +288,24 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
+ int ret;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
if (dev_priv->render_ring.status_page.page_addr != NULL) {
seq_printf(m, "Current sequence: %d\n",
- i915_get_gem_seqno(dev, &dev_priv->render_ring));
+ dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring));
} else {
seq_printf(m, "Current sequence: hws uninitialized\n");
}
seq_printf(m, "Waiter sequence: %d\n",
dev_priv->mm.waiting_gem_seqno);
seq_printf(m, "IRQ sequence: %d\n", dev_priv->mm.irq_gem_seqno);
+
+ mutex_unlock(&dev->struct_mutex);
+
return 0;
}
@@ -211,6 +315,11 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
+ int ret;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
if (!HAS_PCH_SPLIT(dev)) {
seq_printf(m, "Interrupt enable: %08x\n",
@@ -247,7 +356,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
atomic_read(&dev_priv->irq_received));
if (dev_priv->render_ring.status_page.page_addr != NULL) {
seq_printf(m, "Current sequence: %d\n",
- i915_get_gem_seqno(dev, &dev_priv->render_ring));
+ dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring));
} else {
seq_printf(m, "Current sequence: hws uninitialized\n");
}
@@ -255,6 +364,8 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
dev_priv->mm.waiting_gem_seqno);
seq_printf(m, "IRQ sequence: %d\n",
dev_priv->mm.irq_gem_seqno);
+ mutex_unlock(&dev->struct_mutex);
+
return 0;
}
@@ -263,7 +374,11 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- int i;
+ int i, ret;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
seq_printf(m, "Reserved fences = %d\n", dev_priv->fence_reg_start);
seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs);
@@ -289,6 +404,7 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
seq_printf(m, "\n");
}
}
+ mutex_unlock(&dev->struct_mutex);
return 0;
}
@@ -313,16 +429,19 @@ static int i915_hws_info(struct seq_file *m, void *data)
return 0;
}
-static void i915_dump_pages(struct seq_file *m, struct page **pages, int page_count)
+static void i915_dump_object(struct seq_file *m,
+ struct io_mapping *mapping,
+ struct drm_i915_gem_object *obj_priv)
{
- int page, i;
- uint32_t *mem;
+ int page, page_count, i;
+ page_count = obj_priv->base.size / PAGE_SIZE;
for (page = 0; page < page_count; page++) {
- mem = kmap_atomic(pages[page], KM_USER0);
+ u32 *mem = io_mapping_map_wc(mapping,
+ obj_priv->gtt_offset + page * PAGE_SIZE);
for (i = 0; i < PAGE_SIZE; i += 4)
seq_printf(m, "%08x : %08x\n", i, mem[i / 4]);
- kunmap_atomic(mem, KM_USER0);
+ io_mapping_unmap(mem);
}
}
@@ -335,27 +454,20 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data)
struct drm_i915_gem_object *obj_priv;
int ret;
- spin_lock(&dev_priv->mm.active_list_lock);
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
- list_for_each_entry(obj_priv, &dev_priv->render_ring.active_list,
- list) {
+ list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
obj = &obj_priv->base;
if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) {
- ret = i915_gem_object_get_pages(obj, 0);
- if (ret) {
- DRM_ERROR("Failed to get pages: %d\n", ret);
- spin_unlock(&dev_priv->mm.active_list_lock);
- return ret;
- }
-
- seq_printf(m, "--- gtt_offset = 0x%08x\n", obj_priv->gtt_offset);
- i915_dump_pages(m, obj_priv->pages, obj->size / PAGE_SIZE);
-
- i915_gem_object_put_pages(obj);
+ seq_printf(m, "--- gtt_offset = 0x%08x\n",
+ obj_priv->gtt_offset);
+ i915_dump_object(m, dev_priv->mm.gtt_mapping, obj_priv);
}
}
- spin_unlock(&dev_priv->mm.active_list_lock);
+ mutex_unlock(&dev->struct_mutex);
return 0;
}
@@ -365,20 +477,24 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- u8 *virt;
- uint32_t *ptr, off;
+ int ret;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
if (!dev_priv->render_ring.gem_object) {
seq_printf(m, "No ringbuffer setup\n");
- return 0;
- }
-
- virt = dev_priv->render_ring.virtual_start;
+ } else {
+ u8 *virt = dev_priv->render_ring.virtual_start;
+ uint32_t off;
- for (off = 0; off < dev_priv->render_ring.size; off += 4) {
- ptr = (uint32_t *)(virt + off);
- seq_printf(m, "%08x : %08x\n", off, *ptr);
+ for (off = 0; off < dev_priv->render_ring.size; off += 4) {
+ uint32_t *ptr = (uint32_t *)(virt + off);
+ seq_printf(m, "%08x : %08x\n", off, *ptr);
+ }
}
+ mutex_unlock(&dev->struct_mutex);
return 0;
}
@@ -396,7 +512,7 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
seq_printf(m, "RingHead : %08x\n", head);
seq_printf(m, "RingTail : %08x\n", tail);
seq_printf(m, "RingSize : %08lx\n", dev_priv->render_ring.size);
- seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD));
+ seq_printf(m, "Acthd : %08x\n", I915_READ(INTEL_INFO(dev)->gen >= 4 ? ACTHD_I965 : ACTHD));
return 0;
}
@@ -458,7 +574,7 @@ static int i915_error_state(struct seq_file *m, void *unused)
seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr);
seq_printf(m, " INSTDONE: 0x%08x\n", error->instdone);
seq_printf(m, " ACTHD: 0x%08x\n", error->acthd);
- if (IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4) {
seq_printf(m, " INSTPS: 0x%08x\n", error->instps);
seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1);
}
@@ -642,6 +758,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
} else {
seq_printf(m, "FBC disabled: ");
switch (dev_priv->no_fbc_reason) {
+ case FBC_NO_OUTPUT:
+ seq_printf(m, "no outputs");
+ break;
case FBC_STOLEN_TOO_SMALL:
seq_printf(m, "not enough stolen memory");
break;
@@ -675,15 +794,17 @@ static int i915_sr_status(struct seq_file *m, void *unused)
drm_i915_private_t *dev_priv = dev->dev_private;
bool sr_enabled = false;
- if (IS_I965GM(dev) || IS_I945G(dev) || IS_I945GM(dev))
+ if (IS_GEN5(dev))
+ sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN;
+ else if (IS_CRESTLINE(dev) || IS_I945G(dev) || IS_I945GM(dev))
sr_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN;
else if (IS_I915GM(dev))
sr_enabled = I915_READ(INSTPM) & INSTPM_SELF_EN;
else if (IS_PINEVIEW(dev))
sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN;
- seq_printf(m, "self-refresh: %s\n", sr_enabled ? "enabled" :
- "disabled");
+ seq_printf(m, "self-refresh: %s\n",
+ sr_enabled ? "enabled" : "disabled");
return 0;
}
@@ -694,10 +815,16 @@ static int i915_emon_status(struct seq_file *m, void *unused)
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
unsigned long temp, chipset, gfx;
+ int ret;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
temp = i915_mch_val(dev_priv);
chipset = i915_chipset_val(dev_priv);
gfx = i915_gfx_val(dev_priv);
+ mutex_unlock(&dev->struct_mutex);
seq_printf(m, "GMCH temp: %ld\n", temp);
seq_printf(m, "Chipset power: %ld\n", chipset);
@@ -718,6 +845,68 @@ static int i915_gfxec(struct seq_file *m, void *unused)
return 0;
}
+static int i915_opregion(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_opregion *opregion = &dev_priv->opregion;
+ int ret;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
+
+ if (opregion->header)
+ seq_write(m, opregion->header, OPREGION_SIZE);
+
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
+static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_fbdev *ifbdev;
+ struct intel_framebuffer *fb;
+ int ret;
+
+ ret = mutex_lock_interruptible(&dev->mode_config.mutex);
+ if (ret)
+ return ret;
+
+ ifbdev = dev_priv->fbdev;
+ fb = to_intel_framebuffer(ifbdev->helper.fb);
+
+ seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, obj ",
+ fb->base.width,
+ fb->base.height,
+ fb->base.depth,
+ fb->base.bits_per_pixel);
+ describe_obj(m, to_intel_bo(fb->obj));
+ seq_printf(m, "\n");
+
+ list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) {
+ if (&fb->base == ifbdev->helper.fb)
+ continue;
+
+ seq_printf(m, "user size: %d x %d, depth %d, %d bpp, obj ",
+ fb->base.width,
+ fb->base.height,
+ fb->base.depth,
+ fb->base.bits_per_pixel);
+ describe_obj(m, to_intel_bo(fb->obj));
+ seq_printf(m, "\n");
+ }
+
+ mutex_unlock(&dev->mode_config.mutex);
+
+ return 0;
+}
+
static int
i915_wedged_open(struct inode *inode,
struct file *filp)
@@ -741,6 +930,9 @@ i915_wedged_read(struct file *filp,
"wedged : %d\n",
atomic_read(&dev_priv->mm.wedged));
+ if (len > sizeof (buf))
+ len = sizeof (buf);
+
return simple_read_from_buffer(ubuf, max, ppos, buf, len);
}
@@ -770,7 +962,7 @@ i915_wedged_write(struct file *filp,
atomic_set(&dev_priv->mm.wedged, val);
if (val) {
- DRM_WAKEUP(&dev_priv->irq_queue);
+ wake_up_all(&dev_priv->irq_queue);
queue_work(dev_priv->wq, &dev_priv->error_work);
}
@@ -824,9 +1016,13 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor)
}
static struct drm_info_list i915_debugfs_list[] = {
+ {"i915_capabilities", i915_capabilities, 0, 0},
+ {"i915_gem_objects", i915_gem_object_info, 0},
{"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
{"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST},
{"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST},
+ {"i915_gem_pinned", i915_gem_object_list_info, 0, (void *) PINNED_LIST},
+ {"i915_gem_deferred_free", i915_gem_object_list_info, 0, (void *) DEFERRED_FREE_LIST},
{"i915_gem_pageflip", i915_gem_pageflip_info, 0},
{"i915_gem_request", i915_gem_request_info, 0},
{"i915_gem_seqno", i915_gem_seqno_info, 0},
@@ -846,6 +1042,8 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_gfxec", i915_gfxec, 0},
{"i915_fbc_status", i915_fbc_status, 0},
{"i915_sr_status", i915_sr_status, 0},
+ {"i915_opregion", i915_opregion, 0},
+ {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
};
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 2dd2c93ebfa3..7a26f4dd21ae 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -40,8 +40,7 @@
#include <linux/pnp.h>
#include <linux/vga_switcheroo.h>
#include <linux/slab.h>
-
-extern int intel_max_stolen; /* from AGP driver */
+#include <acpi/video.h>
/**
* Sets up the hardware status page for devices that need a physical address
@@ -64,7 +63,7 @@ static int i915_init_phys_hws(struct drm_device *dev)
memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE);
- if (IS_I965G(dev))
+ if (INTEL_INFO(dev)->gen >= 4)
dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) &
0xf0;
@@ -133,8 +132,8 @@ static int i915_dma_cleanup(struct drm_device * dev)
mutex_lock(&dev->struct_mutex);
intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
- if (HAS_BSD(dev))
- intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
+ intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
+ intel_cleanup_ring_buffer(dev, &dev_priv->blt_ring);
mutex_unlock(&dev->struct_mutex);
/* Clear the HWS virtual address at teardown */
@@ -222,7 +221,7 @@ static int i915_dma_resume(struct drm_device * dev)
DRM_DEBUG_DRIVER("hw status page @ %p\n",
ring->status_page.page_addr);
if (ring->status_page.gfx_addr != 0)
- ring->setup_status_page(dev, ring);
+ intel_ring_setup_status_page(dev, ring);
else
I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
@@ -377,7 +376,7 @@ i915_emit_box(struct drm_device *dev,
return -EINVAL;
}
- if (IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4) {
BEGIN_LP_RING(4);
OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
@@ -481,7 +480,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
if (!IS_I830(dev) && !IS_845G(dev)) {
BEGIN_LP_RING(2);
- if (IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4) {
OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
OUT_RING(batch->start);
} else {
@@ -500,7 +499,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
}
- if (IS_G4X(dev) || IS_IRONLAKE(dev)) {
+ if (IS_G4X(dev) || IS_GEN5(dev)) {
BEGIN_LP_RING(2);
OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH | MI_INVALIDATE_ISP);
OUT_RING(MI_NOOP);
@@ -765,6 +764,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
case I915_PARAM_HAS_BSD:
value = HAS_BSD(dev);
break;
+ case I915_PARAM_HAS_BLT:
+ value = HAS_BLT(dev);
+ break;
default:
DRM_DEBUG_DRIVER("Unknown parameter %d\n",
param->param);
@@ -888,12 +890,12 @@ static int
intel_alloc_mchbar_resource(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+ int reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
u32 temp_lo, temp_hi = 0;
u64 mchbar_addr;
int ret;
- if (IS_I965G(dev))
+ if (INTEL_INFO(dev)->gen >= 4)
pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo);
mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
@@ -920,7 +922,7 @@ intel_alloc_mchbar_resource(struct drm_device *dev)
return ret;
}
- if (IS_I965G(dev))
+ if (INTEL_INFO(dev)->gen >= 4)
pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
upper_32_bits(dev_priv->mch_res.start));
@@ -934,7 +936,7 @@ static void
intel_setup_mchbar(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+ int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
u32 temp;
bool enabled;
@@ -971,7 +973,7 @@ static void
intel_teardown_mchbar(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+ int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
u32 temp;
if (dev_priv->mchbar_need_disable) {
@@ -990,174 +992,6 @@ intel_teardown_mchbar(struct drm_device *dev)
release_resource(&dev_priv->mch_res);
}
-/**
- * i915_probe_agp - get AGP bootup configuration
- * @pdev: PCI device
- * @aperture_size: returns AGP aperture configured size
- * @preallocated_size: returns size of BIOS preallocated AGP space
- *
- * Since Intel integrated graphics are UMA, the BIOS has to set aside
- * some RAM for the framebuffer at early boot. This code figures out
- * how much was set aside so we can use it for our own purposes.
- */
-static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
- uint32_t *preallocated_size,
- uint32_t *start)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u16 tmp = 0;
- unsigned long overhead;
- unsigned long stolen;
-
- /* Get the fb aperture size and "stolen" memory amount. */
- pci_read_config_word(dev_priv->bridge_dev, INTEL_GMCH_CTRL, &tmp);
-
- *aperture_size = 1024 * 1024;
- *preallocated_size = 1024 * 1024;
-
- switch (dev->pdev->device) {
- case PCI_DEVICE_ID_INTEL_82830_CGC:
- case PCI_DEVICE_ID_INTEL_82845G_IG:
- case PCI_DEVICE_ID_INTEL_82855GM_IG:
- case PCI_DEVICE_ID_INTEL_82865_IG:
- if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
- *aperture_size *= 64;
- else
- *aperture_size *= 128;
- break;
- default:
- /* 9xx supports large sizes, just look at the length */
- *aperture_size = pci_resource_len(dev->pdev, 2);
- break;
- }
-
- /*
- * Some of the preallocated space is taken by the GTT
- * and popup. GTT is 1K per MB of aperture size, and popup is 4K.
- */
- if (IS_G4X(dev) || IS_PINEVIEW(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev))
- overhead = 4096;
- else
- overhead = (*aperture_size / 1024) + 4096;
-
- if (IS_GEN6(dev)) {
- /* SNB has memory control reg at 0x50.w */
- pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &tmp);
-
- switch (tmp & SNB_GMCH_GMS_STOLEN_MASK) {
- case INTEL_855_GMCH_GMS_DISABLED:
- DRM_ERROR("video memory is disabled\n");
- return -1;
- case SNB_GMCH_GMS_STOLEN_32M:
- stolen = 32 * 1024 * 1024;
- break;
- case SNB_GMCH_GMS_STOLEN_64M:
- stolen = 64 * 1024 * 1024;
- break;
- case SNB_GMCH_GMS_STOLEN_96M:
- stolen = 96 * 1024 * 1024;
- break;
- case SNB_GMCH_GMS_STOLEN_128M:
- stolen = 128 * 1024 * 1024;
- break;
- case SNB_GMCH_GMS_STOLEN_160M:
- stolen = 160 * 1024 * 1024;
- break;
- case SNB_GMCH_GMS_STOLEN_192M:
- stolen = 192 * 1024 * 1024;
- break;
- case SNB_GMCH_GMS_STOLEN_224M:
- stolen = 224 * 1024 * 1024;
- break;
- case SNB_GMCH_GMS_STOLEN_256M:
- stolen = 256 * 1024 * 1024;
- break;
- case SNB_GMCH_GMS_STOLEN_288M:
- stolen = 288 * 1024 * 1024;
- break;
- case SNB_GMCH_GMS_STOLEN_320M:
- stolen = 320 * 1024 * 1024;
- break;
- case SNB_GMCH_GMS_STOLEN_352M:
- stolen = 352 * 1024 * 1024;
- break;
- case SNB_GMCH_GMS_STOLEN_384M:
- stolen = 384 * 1024 * 1024;
- break;
- case SNB_GMCH_GMS_STOLEN_416M:
- stolen = 416 * 1024 * 1024;
- break;
- case SNB_GMCH_GMS_STOLEN_448M:
- stolen = 448 * 1024 * 1024;
- break;
- case SNB_GMCH_GMS_STOLEN_480M:
- stolen = 480 * 1024 * 1024;
- break;
- case SNB_GMCH_GMS_STOLEN_512M:
- stolen = 512 * 1024 * 1024;
- break;
- default:
- DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
- tmp & SNB_GMCH_GMS_STOLEN_MASK);
- return -1;
- }
- } else {
- switch (tmp & INTEL_GMCH_GMS_MASK) {
- case INTEL_855_GMCH_GMS_DISABLED:
- DRM_ERROR("video memory is disabled\n");
- return -1;
- case INTEL_855_GMCH_GMS_STOLEN_1M:
- stolen = 1 * 1024 * 1024;
- break;
- case INTEL_855_GMCH_GMS_STOLEN_4M:
- stolen = 4 * 1024 * 1024;
- break;
- case INTEL_855_GMCH_GMS_STOLEN_8M:
- stolen = 8 * 1024 * 1024;
- break;
- case INTEL_855_GMCH_GMS_STOLEN_16M:
- stolen = 16 * 1024 * 1024;
- break;
- case INTEL_855_GMCH_GMS_STOLEN_32M:
- stolen = 32 * 1024 * 1024;
- break;
- case INTEL_915G_GMCH_GMS_STOLEN_48M:
- stolen = 48 * 1024 * 1024;
- break;
- case INTEL_915G_GMCH_GMS_STOLEN_64M:
- stolen = 64 * 1024 * 1024;
- break;
- case INTEL_GMCH_GMS_STOLEN_128M:
- stolen = 128 * 1024 * 1024;
- break;
- case INTEL_GMCH_GMS_STOLEN_256M:
- stolen = 256 * 1024 * 1024;
- break;
- case INTEL_GMCH_GMS_STOLEN_96M:
- stolen = 96 * 1024 * 1024;
- break;
- case INTEL_GMCH_GMS_STOLEN_160M:
- stolen = 160 * 1024 * 1024;
- break;
- case INTEL_GMCH_GMS_STOLEN_224M:
- stolen = 224 * 1024 * 1024;
- break;
- case INTEL_GMCH_GMS_STOLEN_352M:
- stolen = 352 * 1024 * 1024;
- break;
- default:
- DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
- tmp & INTEL_GMCH_GMS_MASK);
- return -1;
- }
- }
-
- *preallocated_size = stolen - overhead;
- *start = overhead;
-
- return 0;
-}
-
#define PTE_ADDRESS_MASK 0xfffff000
#define PTE_ADDRESS_MASK_HIGH 0x000000f0 /* i915+ */
#define PTE_MAPPING_TYPE_UNCACHED (0 << 1)
@@ -1181,11 +1015,11 @@ static unsigned long i915_gtt_to_phys(struct drm_device *dev,
{
unsigned long *gtt;
unsigned long entry, phys;
- int gtt_bar = IS_I9XX(dev) ? 0 : 1;
+ int gtt_bar = IS_GEN2(dev) ? 1 : 0;
int gtt_offset, gtt_size;
- if (IS_I965G(dev)) {
- if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4) {
+ if (IS_G4X(dev) || INTEL_INFO(dev)->gen > 4) {
gtt_offset = 2*1024*1024;
gtt_size = 2*1024*1024;
} else {
@@ -1210,10 +1044,8 @@ static unsigned long i915_gtt_to_phys(struct drm_device *dev,
DRM_DEBUG_DRIVER("GTT addr: 0x%08lx, PTE: 0x%08lx\n", gtt_addr, entry);
/* Mask out these reserved bits on this hardware. */
- if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev) ||
- IS_I945G(dev) || IS_I945GM(dev)) {
+ if (INTEL_INFO(dev)->gen < 4 && !IS_G33(dev))
entry &= ~PTE_ADDRESS_MASK_HIGH;
- }
/* If it's not a mapping type we know, then bail. */
if ((entry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_UNCACHED &&
@@ -1252,7 +1084,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
unsigned long ll_base = 0;
/* Leave 1M for line length buffer & misc. */
- compressed_fb = drm_mm_search_free(&dev_priv->vram, size, 4096, 0);
+ compressed_fb = drm_mm_search_free(&dev_priv->mm.vram, size, 4096, 0);
if (!compressed_fb) {
dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
i915_warn_stolen(dev);
@@ -1273,7 +1105,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
}
if (!(IS_GM45(dev) || IS_IRONLAKE_M(dev))) {
- compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096,
+ compressed_llb = drm_mm_search_free(&dev_priv->mm.vram, 4096,
4096, 0);
if (!compressed_llb) {
i915_warn_stolen(dev);
@@ -1343,10 +1175,8 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_
/* i915 resume handler doesn't set to D0 */
pci_set_power_state(dev->pdev, PCI_D0);
i915_resume(dev);
- drm_kms_helper_poll_enable(dev);
} else {
printk(KERN_ERR "i915: switched off\n");
- drm_kms_helper_poll_disable(dev);
i915_suspend(dev, pmm);
}
}
@@ -1363,23 +1193,14 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
}
static int i915_load_modeset_init(struct drm_device *dev,
- unsigned long prealloc_start,
unsigned long prealloc_size,
unsigned long agp_size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- int fb_bar = IS_I9XX(dev) ? 2 : 0;
int ret = 0;
- dev->mode_config.fb_base = pci_resource_start(dev->pdev, fb_bar) &
- 0xff000000;
-
- /* Basic memrange allocator for stolen space (aka vram) */
- drm_mm_init(&dev_priv->vram, 0, prealloc_size);
- DRM_INFO("set up %ldM of stolen space\n", prealloc_size / (1024*1024));
-
- /* We're off and running w/KMS */
- dev_priv->mm.suspended = 0;
+ /* Basic memrange allocator for stolen space (aka mm.vram) */
+ drm_mm_init(&dev_priv->mm.vram, 0, prealloc_size);
/* Let GEM Manage from end of prealloc space to end of aperture.
*
@@ -1414,7 +1235,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
*/
dev_priv->allow_batchbuffer = 1;
- ret = intel_init_bios(dev);
+ ret = intel_parse_bios(dev);
if (ret)
DRM_INFO("failed to find VBIOS tables\n");
@@ -1423,6 +1244,8 @@ static int i915_load_modeset_init(struct drm_device *dev,
if (ret)
goto cleanup_ringbuffer;
+ intel_register_dsm_handler();
+
ret = vga_switcheroo_register_client(dev->pdev,
i915_switcheroo_set_state,
i915_switcheroo_can_switch);
@@ -1443,17 +1266,15 @@ static int i915_load_modeset_init(struct drm_device *dev,
/* FIXME: do pre/post-mode set stuff in core KMS code */
dev->vblank_disable_allowed = 1;
- /*
- * Initialize the hardware status page IRQ location.
- */
-
- I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
-
ret = intel_fbdev_init(dev);
if (ret)
goto cleanup_irq;
drm_kms_helper_poll_init(dev);
+
+ /* We're off and running w/KMS */
+ dev_priv->mm.suspended = 0;
+
return 0;
cleanup_irq:
@@ -1907,7 +1728,7 @@ static struct drm_i915_private *i915_mch_dev;
* - dev_priv->fmax
* - dev_priv->gpu_busy
*/
-DEFINE_SPINLOCK(mchdev_lock);
+static DEFINE_SPINLOCK(mchdev_lock);
/**
* i915_read_mch_val - return value for IPS use
@@ -2062,7 +1883,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
struct drm_i915_private *dev_priv;
resource_size_t base, size;
int ret = 0, mmio_bar;
- uint32_t agp_size, prealloc_size, prealloc_start;
+ uint32_t agp_size, prealloc_size;
/* i915 has 4 more counters */
dev->counters += 4;
dev->types[6] = _DRM_STAT_IRQ;
@@ -2079,7 +1900,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dev_priv->info = (struct intel_device_info *) flags;
/* Add register map (needed for suspend/resume) */
- mmio_bar = IS_I9XX(dev) ? 0 : 1;
+ mmio_bar = IS_GEN2(dev) ? 1 : 0;
base = pci_resource_start(dev->pdev, mmio_bar);
size = pci_resource_len(dev->pdev, mmio_bar);
@@ -2121,17 +1942,32 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
"performance may suffer.\n");
}
- ret = i915_probe_agp(dev, &agp_size, &prealloc_size, &prealloc_start);
- if (ret)
+ dev_priv->mm.gtt = intel_gtt_get();
+ if (!dev_priv->mm.gtt) {
+ DRM_ERROR("Failed to initialize GTT\n");
+ ret = -ENODEV;
goto out_iomapfree;
-
- if (prealloc_size > intel_max_stolen) {
- DRM_INFO("detected %dM stolen memory, trimming to %dM\n",
- prealloc_size >> 20, intel_max_stolen >> 20);
- prealloc_size = intel_max_stolen;
}
- dev_priv->wq = create_singlethread_workqueue("i915");
+ prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT;
+ agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
+
+ /* The i915 workqueue is primarily used for batched retirement of
+ * requests (and thus managing bo) once the task has been completed
+ * by the GPU. i915_gem_retire_requests() is called directly when we
+ * need high-priority retirement, such as waiting for an explicit
+ * bo.
+ *
+ * It is also used for periodic low-priority events, such as
+ * idle-timers and hangcheck.
+ *
+ * All tasks on the workqueue are expected to acquire the dev mutex
+ * so there is no point in running more than one instance of the
+ * workqueue at any time: max_active = 1 and NON_REENTRANT.
+ */
+ dev_priv->wq = alloc_workqueue("i915",
+ WQ_UNBOUND | WQ_NON_REENTRANT,
+ 1);
if (dev_priv->wq == NULL) {
DRM_ERROR("Failed to create our workqueue.\n");
ret = -ENOMEM;
@@ -2159,13 +1995,18 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dev->driver->get_vblank_counter = i915_get_vblank_counter;
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
- if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) {
+ if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) {
dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
dev->driver->get_vblank_counter = gm45_get_vblank_counter;
}
/* Try to make sure MCHBAR is enabled before poking at it */
intel_setup_mchbar(dev);
+ intel_setup_gmbus(dev);
+ intel_opregion_setup(dev);
+
+ /* Make sure the bios did its job and set up vital registers */
+ intel_setup_bios(dev);
i915_gem_load(dev);
@@ -2178,7 +2019,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (IS_PINEVIEW(dev))
i915_pineview_get_mem_freq(dev);
- else if (IS_IRONLAKE(dev))
+ else if (IS_GEN5(dev))
i915_ironlake_get_mem_freq(dev);
/* On the 945G/GM, the chipset reports the MSI capability on the
@@ -2212,8 +2053,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
intel_detect_pch(dev);
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- ret = i915_load_modeset_init(dev, prealloc_start,
- prealloc_size, agp_size);
+ ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
if (ret < 0) {
DRM_ERROR("failed to init modeset\n");
goto out_workqueue_free;
@@ -2221,7 +2061,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
}
/* Must be done after probing outputs */
- intel_opregion_init(dev, 0);
+ intel_opregion_init(dev);
+ acpi_video_register();
setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed,
(unsigned long) dev);
@@ -2231,9 +2072,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dev_priv->mchdev_lock = &mchdev_lock;
spin_unlock(&mchdev_lock);
- /* XXX Prevent module unload due to memory corruption bugs. */
- __module_get(THIS_MODULE);
-
return 0;
out_workqueue_free:
@@ -2252,15 +2090,20 @@ free_priv:
int i915_driver_unload(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
-
- i915_destroy_error_state(dev);
+ int ret;
spin_lock(&mchdev_lock);
i915_mch_dev = NULL;
spin_unlock(&mchdev_lock);
- destroy_workqueue(dev_priv->wq);
- del_timer_sync(&dev_priv->hangcheck_timer);
+ mutex_lock(&dev->struct_mutex);
+ ret = i915_gpu_idle(dev);
+ if (ret)
+ DRM_ERROR("failed to idle hardware: %d\n", ret);
+ mutex_unlock(&dev->struct_mutex);
+
+ /* Cancel the retire work handler, which should be idle now. */
+ cancel_delayed_work_sync(&dev_priv->mm.retire_work);
io_mapping_free(dev_priv->mm.gtt_mapping);
if (dev_priv->mm.gtt_mtrr >= 0) {
@@ -2269,7 +2112,10 @@ int i915_driver_unload(struct drm_device *dev)
dev_priv->mm.gtt_mtrr = -1;
}
+ acpi_video_unregister();
+
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ intel_fbdev_fini(dev);
intel_modeset_cleanup(dev);
/*
@@ -2281,20 +2127,25 @@ int i915_driver_unload(struct drm_device *dev)
dev_priv->child_dev = NULL;
dev_priv->child_dev_num = 0;
}
- drm_irq_uninstall(dev);
+
vga_switcheroo_unregister_client(dev->pdev);
vga_client_register(dev->pdev, NULL, NULL, NULL);
}
+ /* Free error state after interrupts are fully disabled. */
+ del_timer_sync(&dev_priv->hangcheck_timer);
+ cancel_work_sync(&dev_priv->error_work);
+ i915_destroy_error_state(dev);
+
if (dev->pdev->msi_enabled)
pci_disable_msi(dev->pdev);
- if (dev_priv->regs != NULL)
- iounmap(dev_priv->regs);
-
- intel_opregion_free(dev, 0);
+ intel_opregion_fini(dev);
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ /* Flush any outstanding unpin_work. */
+ flush_workqueue(dev_priv->wq);
+
i915_gem_free_all_phys_object(dev);
mutex_lock(&dev->struct_mutex);
@@ -2302,34 +2153,41 @@ int i915_driver_unload(struct drm_device *dev)
mutex_unlock(&dev->struct_mutex);
if (I915_HAS_FBC(dev) && i915_powersave)
i915_cleanup_compression(dev);
- drm_mm_takedown(&dev_priv->vram);
- i915_gem_lastclose(dev);
+ drm_mm_takedown(&dev_priv->mm.vram);
intel_cleanup_overlay(dev);
+
+ if (!I915_NEED_GFX_HWS(dev))
+ i915_free_hws(dev);
}
+ if (dev_priv->regs != NULL)
+ iounmap(dev_priv->regs);
+
+ intel_teardown_gmbus(dev);
intel_teardown_mchbar(dev);
+ destroy_workqueue(dev_priv->wq);
+
pci_dev_put(dev_priv->bridge_dev);
kfree(dev->dev_private);
return 0;
}
-int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
+int i915_driver_open(struct drm_device *dev, struct drm_file *file)
{
- struct drm_i915_file_private *i915_file_priv;
+ struct drm_i915_file_private *file_priv;
DRM_DEBUG_DRIVER("\n");
- i915_file_priv = (struct drm_i915_file_private *)
- kmalloc(sizeof(*i915_file_priv), GFP_KERNEL);
-
- if (!i915_file_priv)
+ file_priv = kmalloc(sizeof(*file_priv), GFP_KERNEL);
+ if (!file_priv)
return -ENOMEM;
- file_priv->driver_priv = i915_file_priv;
+ file->driver_priv = file_priv;
- INIT_LIST_HEAD(&i915_file_priv->mm.request_list);
+ spin_lock_init(&file_priv->mm.lock);
+ INIT_LIST_HEAD(&file_priv->mm.request_list);
return 0;
}
@@ -2372,11 +2230,11 @@ void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
i915_mem_release(dev, file_priv, dev_priv->agp_heap);
}
-void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
+void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
{
- struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+ struct drm_i915_file_private *file_priv = file->driver_priv;
- kfree(i915_file_priv);
+ kfree(file_priv);
}
struct drm_ioctl_desc i915_ioctls[] = {
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 895ab896e336..3467dd420760 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -32,6 +32,7 @@
#include "drm.h"
#include "i915_drm.h"
#include "i915_drv.h"
+#include "intel_drv.h"
#include <linux/console.h>
#include "drm_crtc_helper.h"
@@ -61,86 +62,110 @@ extern int intel_agp_enabled;
.driver_data = (unsigned long) info }
static const struct intel_device_info intel_i830_info = {
- .gen = 2, .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1,
+ .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1,
+ .has_overlay = 1, .overlay_needs_physical = 1,
};
static const struct intel_device_info intel_845g_info = {
- .gen = 2, .is_i8xx = 1,
+ .gen = 2,
+ .has_overlay = 1, .overlay_needs_physical = 1,
};
static const struct intel_device_info intel_i85x_info = {
- .gen = 2, .is_i8xx = 1, .is_i85x = 1, .is_mobile = 1,
+ .gen = 2, .is_i85x = 1, .is_mobile = 1,
.cursor_needs_physical = 1,
+ .has_overlay = 1, .overlay_needs_physical = 1,
};
static const struct intel_device_info intel_i865g_info = {
- .gen = 2, .is_i8xx = 1,
+ .gen = 2,
+ .has_overlay = 1, .overlay_needs_physical = 1,
};
static const struct intel_device_info intel_i915g_info = {
- .gen = 3, .is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1,
+ .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1,
+ .has_overlay = 1, .overlay_needs_physical = 1,
};
static const struct intel_device_info intel_i915gm_info = {
- .gen = 3, .is_i9xx = 1, .is_mobile = 1,
+ .gen = 3, .is_mobile = 1,
.cursor_needs_physical = 1,
+ .has_overlay = 1, .overlay_needs_physical = 1,
+ .supports_tv = 1,
};
static const struct intel_device_info intel_i945g_info = {
- .gen = 3, .is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1,
+ .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1,
+ .has_overlay = 1, .overlay_needs_physical = 1,
};
static const struct intel_device_info intel_i945gm_info = {
- .gen = 3, .is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1,
+ .gen = 3, .is_i945gm = 1, .is_mobile = 1,
.has_hotplug = 1, .cursor_needs_physical = 1,
+ .has_overlay = 1, .overlay_needs_physical = 1,
+ .supports_tv = 1,
};
static const struct intel_device_info intel_i965g_info = {
- .gen = 4, .is_broadwater = 1, .is_i965g = 1, .is_i9xx = 1,
+ .gen = 4, .is_broadwater = 1,
.has_hotplug = 1,
+ .has_overlay = 1,
};
static const struct intel_device_info intel_i965gm_info = {
- .gen = 4, .is_crestline = 1, .is_i965g = 1, .is_i965gm = 1, .is_i9xx = 1,
+ .gen = 4, .is_crestline = 1,
.is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1,
+ .has_overlay = 1,
+ .supports_tv = 1,
};
static const struct intel_device_info intel_g33_info = {
- .gen = 3, .is_g33 = 1, .is_i9xx = 1,
+ .gen = 3, .is_g33 = 1,
.need_gfx_hws = 1, .has_hotplug = 1,
+ .has_overlay = 1,
};
static const struct intel_device_info intel_g45_info = {
- .gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, .need_gfx_hws = 1,
+ .gen = 4, .is_g4x = 1, .need_gfx_hws = 1,
.has_pipe_cxsr = 1, .has_hotplug = 1,
+ .has_bsd_ring = 1,
};
static const struct intel_device_info intel_gm45_info = {
- .gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1,
+ .gen = 4, .is_g4x = 1,
.is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1,
.has_pipe_cxsr = 1, .has_hotplug = 1,
+ .supports_tv = 1,
+ .has_bsd_ring = 1,
};
static const struct intel_device_info intel_pineview_info = {
- .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1,
+ .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1,
.need_gfx_hws = 1, .has_hotplug = 1,
+ .has_overlay = 1,
};
static const struct intel_device_info intel_ironlake_d_info = {
- .gen = 5, .is_ironlake = 1, .is_i965g = 1, .is_i9xx = 1,
+ .gen = 5,
.need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1,
+ .has_bsd_ring = 1,
};
static const struct intel_device_info intel_ironlake_m_info = {
- .gen = 5, .is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1,
+ .gen = 5, .is_mobile = 1,
.need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1,
+ .has_bsd_ring = 1,
};
static const struct intel_device_info intel_sandybridge_d_info = {
- .gen = 6, .is_i965g = 1, .is_i9xx = 1,
+ .gen = 6,
.need_gfx_hws = 1, .has_hotplug = 1,
+ .has_bsd_ring = 1,
+ .has_blt_ring = 1,
};
static const struct intel_device_info intel_sandybridge_m_info = {
- .gen = 6, .is_i965g = 1, .is_mobile = 1, .is_i9xx = 1,
+ .gen = 6, .is_mobile = 1,
.need_gfx_hws = 1, .has_hotplug = 1,
+ .has_bsd_ring = 1,
+ .has_blt_ring = 1,
};
static const struct pci_device_id pciidlist[] = { /* aka */
@@ -237,7 +262,7 @@ static int i915_drm_freeze(struct drm_device *dev)
i915_save_state(dev);
- intel_opregion_free(dev, 1);
+ intel_opregion_fini(dev);
/* Modeset on resume, not lid events */
dev_priv->modeset_on_lid = 0;
@@ -258,6 +283,8 @@ int i915_suspend(struct drm_device *dev, pm_message_t state)
if (state.event == PM_EVENT_PRETHAW)
return 0;
+ drm_kms_helper_poll_disable(dev);
+
error = i915_drm_freeze(dev);
if (error)
return error;
@@ -277,8 +304,7 @@ static int i915_drm_thaw(struct drm_device *dev)
int error = 0;
i915_restore_state(dev);
-
- intel_opregion_init(dev, 1);
+ intel_opregion_setup(dev);
/* KMS EnterVT equivalent */
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
@@ -294,6 +320,8 @@ static int i915_drm_thaw(struct drm_device *dev)
drm_helper_resume_force_mode(dev);
}
+ intel_opregion_init(dev);
+
dev_priv->modeset_on_lid = 0;
return error;
@@ -301,12 +329,79 @@ static int i915_drm_thaw(struct drm_device *dev)
int i915_resume(struct drm_device *dev)
{
+ int ret;
+
if (pci_enable_device(dev->pdev))
return -EIO;
pci_set_master(dev->pdev);
- return i915_drm_thaw(dev);
+ ret = i915_drm_thaw(dev);
+ if (ret)
+ return ret;
+
+ drm_kms_helper_poll_enable(dev);
+ return 0;
+}
+
+static int i8xx_do_reset(struct drm_device *dev, u8 flags)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (IS_I85X(dev))
+ return -ENODEV;
+
+ I915_WRITE(D_STATE, I915_READ(D_STATE) | DSTATE_GFX_RESET_I830);
+ POSTING_READ(D_STATE);
+
+ if (IS_I830(dev) || IS_845G(dev)) {
+ I915_WRITE(DEBUG_RESET_I830,
+ DEBUG_RESET_DISPLAY |
+ DEBUG_RESET_RENDER |
+ DEBUG_RESET_FULL);
+ POSTING_READ(DEBUG_RESET_I830);
+ msleep(1);
+
+ I915_WRITE(DEBUG_RESET_I830, 0);
+ POSTING_READ(DEBUG_RESET_I830);
+ }
+
+ msleep(1);
+
+ I915_WRITE(D_STATE, I915_READ(D_STATE) & ~DSTATE_GFX_RESET_I830);
+ POSTING_READ(D_STATE);
+
+ return 0;
+}
+
+static int i965_reset_complete(struct drm_device *dev)
+{
+ u8 gdrst;
+ pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
+ return gdrst & 0x1;
+}
+
+static int i965_do_reset(struct drm_device *dev, u8 flags)
+{
+ u8 gdrst;
+
+ /*
+ * Set the domains we want to reset (GRDOM/bits 2 and 3) as
+ * well as the reset bit (GR/bit 0). Setting the GR bit
+ * triggers the reset; when done, the hardware will clear it.
+ */
+ pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
+ pci_write_config_byte(dev->pdev, I965_GDRST, gdrst | flags | 0x1);
+
+ return wait_for(i965_reset_complete(dev), 500);
+}
+
+static int ironlake_do_reset(struct drm_device *dev, u8 flags)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
+ I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, gdrst | flags | 0x1);
+ return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
}
/**
@@ -325,54 +420,39 @@ int i915_resume(struct drm_device *dev)
* - re-init interrupt state
* - re-init display
*/
-int i965_reset(struct drm_device *dev, u8 flags)
+int i915_reset(struct drm_device *dev, u8 flags)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- unsigned long timeout;
- u8 gdrst;
/*
* We really should only reset the display subsystem if we actually
* need to
*/
bool need_display = true;
+ int ret;
mutex_lock(&dev->struct_mutex);
- /*
- * Clear request list
- */
- i915_gem_retire_requests(dev);
-
- if (need_display)
- i915_save_display(dev);
-
- if (IS_I965G(dev) || IS_G4X(dev)) {
- /*
- * Set the domains we want to reset, then the reset bit (bit 0).
- * Clear the reset bit after a while and wait for hardware status
- * bit (bit 1) to be set
- */
- pci_read_config_byte(dev->pdev, GDRST, &gdrst);
- pci_write_config_byte(dev->pdev, GDRST, gdrst | flags | ((flags == GDRST_FULL) ? 0x1 : 0x0));
- udelay(50);
- pci_write_config_byte(dev->pdev, GDRST, gdrst & 0xfe);
-
- /* ...we don't want to loop forever though, 500ms should be plenty */
- timeout = jiffies + msecs_to_jiffies(500);
- do {
- udelay(100);
- pci_read_config_byte(dev->pdev, GDRST, &gdrst);
- } while ((gdrst & 0x1) && time_after(timeout, jiffies));
-
- if (gdrst & 0x1) {
- WARN(true, "i915: Failed to reset chip\n");
- mutex_unlock(&dev->struct_mutex);
- return -EIO;
- }
- } else {
- DRM_ERROR("Error occurred. Don't know how to reset this chip.\n");
+ i915_gem_reset(dev);
+
+ ret = -ENODEV;
+ if (get_seconds() - dev_priv->last_gpu_reset < 5) {
+ DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
+ } else switch (INTEL_INFO(dev)->gen) {
+ case 5:
+ ret = ironlake_do_reset(dev, flags);
+ break;
+ case 4:
+ ret = i965_do_reset(dev, flags);
+ break;
+ case 2:
+ ret = i8xx_do_reset(dev, flags);
+ break;
+ }
+ dev_priv->last_gpu_reset = get_seconds();
+ if (ret) {
+ DRM_ERROR("Failed to reset chip.\n");
mutex_unlock(&dev->struct_mutex);
- return -ENODEV;
+ return ret;
}
/* Ok, now get things going again... */
@@ -400,13 +480,19 @@ int i965_reset(struct drm_device *dev, u8 flags)
mutex_lock(&dev->struct_mutex);
}
+ mutex_unlock(&dev->struct_mutex);
+
/*
- * Display needs restore too...
+ * Perform a full modeset as on later generations, e.g. Ironlake, we may
+ * need to retrain the display link and cannot just restore the register
+ * values.
*/
- if (need_display)
- i915_restore_display(dev);
+ if (need_display) {
+ mutex_lock(&dev->mode_config.mutex);
+ drm_helper_resume_force_mode(dev);
+ mutex_unlock(&dev->mode_config.mutex);
+ }
- mutex_unlock(&dev->struct_mutex);
return 0;
}
@@ -524,8 +610,6 @@ static struct drm_driver driver = {
.irq_uninstall = i915_driver_irq_uninstall,
.irq_handler = i915_driver_irq_handler,
.reclaim_buffers = drm_core_reclaim_buffers,
- .get_map_ofs = drm_core_get_map_ofs,
- .get_reg_ofs = drm_core_get_reg_ofs,
.master_create = i915_master_create,
.master_destroy = i915_master_destroy,
#if defined(CONFIG_DEBUG_FS)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index af4a263cf257..2c2c19b6285e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -34,6 +34,8 @@
#include "intel_bios.h"
#include "intel_ringbuffer.h"
#include <linux/io-mapping.h>
+#include <linux/i2c.h>
+#include <drm/intel-gtt.h>
/* General customization:
*/
@@ -73,11 +75,9 @@ enum plane {
#define DRIVER_PATCHLEVEL 0
#define WATCH_COHERENCY 0
-#define WATCH_BUF 0
#define WATCH_EXEC 0
-#define WATCH_LRU 0
#define WATCH_RELOC 0
-#define WATCH_INACTIVE 0
+#define WATCH_LISTS 0
#define WATCH_PWRITE 0
#define I915_GEM_PHYS_CURSOR_0 1
@@ -110,8 +110,9 @@ struct intel_opregion {
struct opregion_acpi *acpi;
struct opregion_swsci *swsci;
struct opregion_asle *asle;
- int enabled;
+ void *vbt;
};
+#define OPREGION_SIZE (8*1024)
struct intel_overlay;
struct intel_overlay_error_state;
@@ -125,13 +126,16 @@ struct drm_i915_master_private {
struct drm_i915_fence_reg {
struct drm_gem_object *obj;
struct list_head lru_list;
+ bool gpu;
};
struct sdvo_device_mapping {
+ u8 initialized;
u8 dvo_port;
u8 slave_addr;
u8 dvo_wiring;
- u8 initialized;
+ u8 i2c_pin;
+ u8 i2c_speed;
u8 ddc_pin;
};
@@ -193,28 +197,29 @@ struct drm_i915_display_funcs {
struct intel_device_info {
u8 gen;
u8 is_mobile : 1;
- u8 is_i8xx : 1;
u8 is_i85x : 1;
u8 is_i915g : 1;
- u8 is_i9xx : 1;
u8 is_i945gm : 1;
- u8 is_i965g : 1;
- u8 is_i965gm : 1;
u8 is_g33 : 1;
u8 need_gfx_hws : 1;
u8 is_g4x : 1;
u8 is_pineview : 1;
u8 is_broadwater : 1;
u8 is_crestline : 1;
- u8 is_ironlake : 1;
u8 has_fbc : 1;
u8 has_rc6 : 1;
u8 has_pipe_cxsr : 1;
u8 has_hotplug : 1;
u8 cursor_needs_physical : 1;
+ u8 has_overlay : 1;
+ u8 overlay_needs_physical : 1;
+ u8 supports_tv : 1;
+ u8 has_bsd_ring : 1;
+ u8 has_blt_ring : 1;
};
enum no_fbc_reason {
+ FBC_NO_OUTPUT, /* no outputs enabled to compress */
FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */
FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */
FBC_MODE_TOO_LARGE, /* mode too large for compression */
@@ -241,9 +246,16 @@ typedef struct drm_i915_private {
void __iomem *regs;
+ struct intel_gmbus {
+ struct i2c_adapter adapter;
+ struct i2c_adapter *force_bit;
+ u32 reg0;
+ } *gmbus;
+
struct pci_dev *bridge_dev;
struct intel_ring_buffer render_ring;
struct intel_ring_buffer bsd_ring;
+ struct intel_ring_buffer blt_ring;
uint32_t next_seqno;
drm_dma_handle_t *status_page_dmah;
@@ -263,6 +275,9 @@ typedef struct drm_i915_private {
int front_offset;
int current_page;
int page_flipping;
+#define I915_DEBUG_READ (1<<0)
+#define I915_DEBUG_WRITE (1<<1)
+ unsigned long debug_flags;
wait_queue_head_t irq_queue;
atomic_t irq_received;
@@ -289,24 +304,21 @@ typedef struct drm_i915_private {
unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
int vblank_pipe;
int num_pipe;
- u32 flush_rings;
-#define FLUSH_RENDER_RING 0x1
-#define FLUSH_BSD_RING 0x2
/* For hangcheck timer */
-#define DRM_I915_HANGCHECK_PERIOD 75 /* in jiffies */
+#define DRM_I915_HANGCHECK_PERIOD 250 /* in ms */
struct timer_list hangcheck_timer;
int hangcheck_count;
uint32_t last_acthd;
uint32_t last_instdone;
uint32_t last_instdone1;
- struct drm_mm vram;
-
unsigned long cfb_size;
unsigned long cfb_pitch;
+ unsigned long cfb_offset;
int cfb_fence;
int cfb_plane;
+ int cfb_y;
int irq_enabled;
@@ -316,8 +328,7 @@ typedef struct drm_i915_private {
struct intel_overlay *overlay;
/* LVDS info */
- int backlight_duty_cycle; /* restore backlight to this value */
- bool panel_wants_dither;
+ int backlight_level; /* restore backlight to this value */
struct drm_display_mode *panel_fixed_mode;
struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
@@ -328,13 +339,23 @@ typedef struct drm_i915_private {
unsigned int lvds_vbt:1;
unsigned int int_crt_support:1;
unsigned int lvds_use_ssc:1;
- unsigned int edp_support:1;
int lvds_ssc_freq;
- int edp_bpp;
+ struct {
+ int rate;
+ int lanes;
+ int preemphasis;
+ int vswing;
+
+ bool initialized;
+ bool support;
+ int bpp;
+ struct edp_power_seq pps;
+ } edp;
+ bool no_aux_handshake;
struct notifier_block lid_notifier;
- int crt_ddc_bus; /* 0 = unknown, else GPIO to use for CRT DDC */
+ int crt_ddc_pin;
struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
int num_fence_regs; /* 8 on pre-965, 16 otherwise */
@@ -344,6 +365,7 @@ typedef struct drm_i915_private {
spinlock_t error_lock;
struct drm_i915_error_state *first_error;
struct work_struct error_work;
+ struct completion error_completion;
struct workqueue_struct *wq;
/* Display functions */
@@ -507,6 +529,11 @@ typedef struct drm_i915_private {
u32 saveMCHBAR_RENDER_STANDBY;
struct {
+ /** Bridge to intel-gtt-ko */
+ struct intel_gtt *gtt;
+ /** Memory allocator for GTT stolen memory */
+ struct drm_mm vram;
+ /** Memory allocator for GTT */
struct drm_mm gtt_space;
struct io_mapping *gtt_mapping;
@@ -521,7 +548,16 @@ typedef struct drm_i915_private {
*/
struct list_head shrink_list;
- spinlock_t active_list_lock;
+ /**
+ * List of objects currently involved in rendering.
+ *
+ * Includes buffers having the contents of their GPU caches
+ * flushed, not necessarily primitives. last_rendering_seqno
+ * represents when the rendering involved will be completed.
+ *
+ * A reference is held on the buffer while on this list.
+ */
+ struct list_head active_list;
/**
* List of objects which are not in the ringbuffer but which
@@ -535,15 +571,6 @@ typedef struct drm_i915_private {
struct list_head flushing_list;
/**
- * List of objects currently pending a GPU write flush.
- *
- * All elements on this list will belong to either the
- * active_list or flushing_list, last_rendering_seqno can
- * be used to differentiate between the two elements.
- */
- struct list_head gpu_write_list;
-
- /**
* LRU list of objects which are not in the ringbuffer and
* are ready to unbind, but are still in the GTT.
*
@@ -555,6 +582,12 @@ typedef struct drm_i915_private {
*/
struct list_head inactive_list;
+ /**
+ * LRU list of objects which are not in the ringbuffer but
+ * are still pinned in the GTT.
+ */
+ struct list_head pinned_list;
+
/** LRU list of objects with fence regs on them. */
struct list_head fence_list;
@@ -611,6 +644,17 @@ typedef struct drm_i915_private {
/* storage for physical objects */
struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
+
+ uint32_t flush_rings;
+
+ /* accounting, useful for userland debugging */
+ size_t object_memory;
+ size_t pin_memory;
+ size_t gtt_memory;
+ size_t gtt_total;
+ u32 object_count;
+ u32 pin_count;
+ u32 gtt_count;
} mm;
struct sdvo_device_mapping sdvo_mappings[2];
/* indicate whether the LVDS_BORDER should be enabled or not */
@@ -626,8 +670,6 @@ typedef struct drm_i915_private {
/* Reclocking support */
bool render_reclock_avail;
bool lvds_downclock_avail;
- /* indicate whether the LVDS EDID is OK */
- bool lvds_edid_good;
/* indicates the reduced downclock for LVDS*/
int lvds_downclock;
struct work_struct idle_work;
@@ -661,6 +703,8 @@ typedef struct drm_i915_private {
struct drm_mm_node *compressed_fb;
struct drm_mm_node *compressed_llb;
+ unsigned long last_gpu_reset;
+
/* list of fbdev register on this device */
struct intel_fbdev *fbdev;
} drm_i915_private_t;
@@ -673,7 +717,8 @@ struct drm_i915_gem_object {
struct drm_mm_node *gtt_space;
/** This object's place on the active/flushing/inactive lists */
- struct list_head list;
+ struct list_head ring_list;
+ struct list_head mm_list;
/** This object's place on GPU write list */
struct list_head gpu_write_list;
/** This object's place on eviction list */
@@ -816,12 +861,14 @@ struct drm_i915_gem_request {
/** global list entry for this request */
struct list_head list;
+ struct drm_i915_file_private *file_priv;
/** file_priv list entry for this request */
struct list_head client_list;
};
struct drm_i915_file_private {
struct {
+ struct spinlock lock;
struct list_head request_list;
} mm;
};
@@ -862,7 +909,7 @@ extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
extern int i915_emit_box(struct drm_device *dev,
struct drm_clip_rect *boxes,
int i, int DR1, int DR4);
-extern int i965_reset(struct drm_device *dev, u8 flags);
+extern int i915_reset(struct drm_device *dev, u8 flags);
extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv);
extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv);
extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
@@ -871,7 +918,6 @@ extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
/* i915_irq.c */
void i915_hangcheck_elapsed(unsigned long data);
-void i915_destroy_error_state(struct drm_device *dev);
extern int i915_irq_emit(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int i915_irq_wait(struct drm_device *dev, void *data,
@@ -908,6 +954,12 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
void intel_enable_asle (struct drm_device *dev);
+#ifdef CONFIG_DEBUG_FS
+extern void i915_destroy_error_state(struct drm_device *dev);
+#else
+#define i915_destroy_error_state(x)
+#endif
+
/* i915_mem.c */
extern int i915_mem_alloc(struct drm_device *dev, void *data,
@@ -922,6 +974,7 @@ extern void i915_mem_takedown(struct mem_block **heap);
extern void i915_mem_release(struct drm_device * dev,
struct drm_file *file_priv, struct mem_block *heap);
/* i915_gem.c */
+int i915_gem_check_is_wedged(struct drm_device *dev);
int i915_gem_init_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int i915_gem_create_ioctl(struct drm_device *dev, void *data,
@@ -972,13 +1025,22 @@ void i915_gem_object_unpin(struct drm_gem_object *obj);
int i915_gem_object_unbind(struct drm_gem_object *obj);
void i915_gem_release_mmap(struct drm_gem_object *obj);
void i915_gem_lastclose(struct drm_device *dev);
-uint32_t i915_get_gem_seqno(struct drm_device *dev,
- struct intel_ring_buffer *ring);
-bool i915_seqno_passed(uint32_t seq1, uint32_t seq2);
-int i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
-int i915_gem_object_put_fence_reg(struct drm_gem_object *obj);
+
+/**
+ * Returns true if seq1 is later than seq2.
+ */
+static inline bool
+i915_seqno_passed(uint32_t seq1, uint32_t seq2)
+{
+ return (int32_t)(seq1 - seq2) >= 0;
+}
+
+int i915_gem_object_get_fence_reg(struct drm_gem_object *obj,
+ bool interruptible);
+int i915_gem_object_put_fence_reg(struct drm_gem_object *obj,
+ bool interruptible);
void i915_gem_retire_requests(struct drm_device *dev);
-void i915_gem_retire_work_handler(struct work_struct *work);
+void i915_gem_reset(struct drm_device *dev);
void i915_gem_clflush_object(struct drm_gem_object *obj);
int i915_gem_object_set_domain(struct drm_gem_object *obj,
uint32_t read_domains,
@@ -990,16 +1052,18 @@ int i915_gem_do_init(struct drm_device *dev, unsigned long start,
int i915_gpu_idle(struct drm_device *dev);
int i915_gem_idle(struct drm_device *dev);
uint32_t i915_add_request(struct drm_device *dev,
- struct drm_file *file_priv,
- uint32_t flush_domains,
- struct intel_ring_buffer *ring);
+ struct drm_file *file_priv,
+ struct drm_i915_gem_request *request,
+ struct intel_ring_buffer *ring);
int i915_do_wait_request(struct drm_device *dev,
- uint32_t seqno, int interruptible,
- struct intel_ring_buffer *ring);
+ uint32_t seqno,
+ bool interruptible,
+ struct intel_ring_buffer *ring);
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
int write);
-int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj);
+int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
+ bool pipelined);
int i915_gem_attach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj,
int id,
@@ -1007,10 +1071,7 @@ int i915_gem_attach_phys_object(struct drm_device *dev,
void i915_gem_detach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj);
void i915_gem_free_all_phys_object(struct drm_device *dev);
-int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
-void i915_gem_object_put_pages(struct drm_gem_object *obj);
void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv);
-int i915_gem_object_flush_write_domain(struct drm_gem_object *obj);
void i915_gem_shrinker_init(void);
void i915_gem_shrinker_exit(void);
@@ -1032,15 +1093,14 @@ bool i915_gem_object_fence_offset_ok(struct drm_gem_object *obj,
/* i915_gem_debug.c */
void i915_gem_dump_object(struct drm_gem_object *obj, int len,
const char *where, uint32_t mark);
-#if WATCH_INACTIVE
-void i915_verify_inactive(struct drm_device *dev, char *file, int line);
+#if WATCH_LISTS
+int i915_verify_lists(struct drm_device *dev);
#else
-#define i915_verify_inactive(dev, file, line)
+#define i915_verify_lists(dev) 0
#endif
void i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle);
void i915_gem_dump_object(struct drm_gem_object *obj, int len,
const char *where, uint32_t mark);
-void i915_dump_lru(struct drm_device *dev, const char *where);
/* i915_debugfs.c */
int i915_debugfs_init(struct drm_minor *minor);
@@ -1054,21 +1114,42 @@ extern int i915_restore_state(struct drm_device *dev);
extern int i915_save_state(struct drm_device *dev);
extern int i915_restore_state(struct drm_device *dev);
+/* intel_i2c.c */
+extern int intel_setup_gmbus(struct drm_device *dev);
+extern void intel_teardown_gmbus(struct drm_device *dev);
+extern void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed);
+extern void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit);
+extern inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
+{
+ return container_of(adapter, struct intel_gmbus, adapter)->force_bit;
+}
+extern void intel_i2c_reset(struct drm_device *dev);
+
+/* intel_opregion.c */
+extern int intel_opregion_setup(struct drm_device *dev);
#ifdef CONFIG_ACPI
-/* i915_opregion.c */
-extern int intel_opregion_init(struct drm_device *dev, int resume);
-extern void intel_opregion_free(struct drm_device *dev, int suspend);
-extern void opregion_asle_intr(struct drm_device *dev);
-extern void ironlake_opregion_gse_intr(struct drm_device *dev);
-extern void opregion_enable_asle(struct drm_device *dev);
+extern void intel_opregion_init(struct drm_device *dev);
+extern void intel_opregion_fini(struct drm_device *dev);
+extern void intel_opregion_asle_intr(struct drm_device *dev);
+extern void intel_opregion_gse_intr(struct drm_device *dev);
+extern void intel_opregion_enable_asle(struct drm_device *dev);
#else
-static inline int intel_opregion_init(struct drm_device *dev, int resume) { return 0; }
-static inline void intel_opregion_free(struct drm_device *dev, int suspend) { return; }
-static inline void opregion_asle_intr(struct drm_device *dev) { return; }
-static inline void ironlake_opregion_gse_intr(struct drm_device *dev) { return; }
-static inline void opregion_enable_asle(struct drm_device *dev) { return; }
+static inline void intel_opregion_init(struct drm_device *dev) { return; }
+static inline void intel_opregion_fini(struct drm_device *dev) { return; }
+static inline void intel_opregion_asle_intr(struct drm_device *dev) { return; }
+static inline void intel_opregion_gse_intr(struct drm_device *dev) { return; }
+static inline void intel_opregion_enable_asle(struct drm_device *dev) { return; }
#endif
+/* intel_acpi.c */
+#ifdef CONFIG_ACPI
+extern void intel_register_dsm_handler(void);
+extern void intel_unregister_dsm_handler(void);
+#else
+static inline void intel_register_dsm_handler(void) { return; }
+static inline void intel_unregister_dsm_handler(void) { return; }
+#endif /* CONFIG_ACPI */
+
/* modesetting */
extern void intel_modeset_init(struct drm_device *dev);
extern void intel_modeset_cleanup(struct drm_device *dev);
@@ -1084,8 +1165,10 @@ extern void intel_detect_pch (struct drm_device *dev);
extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
/* overlay */
+#ifdef CONFIG_DEBUG_FS
extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error);
+#endif
/**
* Lock test for when it's just for synchronization of ring access.
@@ -1099,8 +1182,26 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
LOCK_TEST_WITH_RETURN(dev, file_priv); \
} while (0)
-#define I915_READ(reg) readl(dev_priv->regs + (reg))
-#define I915_WRITE(reg, val) writel(val, dev_priv->regs + (reg))
+static inline u32 i915_read(struct drm_i915_private *dev_priv, u32 reg)
+{
+ u32 val;
+
+ val = readl(dev_priv->regs + reg);
+ if (dev_priv->debug_flags & I915_DEBUG_READ)
+ printk(KERN_ERR "read 0x%08x from 0x%08x\n", val, reg);
+ return val;
+}
+
+static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg,
+ u32 val)
+{
+ writel(val, dev_priv->regs + reg);
+ if (dev_priv->debug_flags & I915_DEBUG_WRITE)
+ printk(KERN_ERR "wrote 0x%08x to 0x%08x\n", val, reg);
+}
+
+#define I915_READ(reg) i915_read(dev_priv, (reg))
+#define I915_WRITE(reg, val) i915_write(dev_priv, (reg), (val))
#define I915_READ16(reg) readw(dev_priv->regs + (reg))
#define I915_WRITE16(reg, val) writel(val, dev_priv->regs + (reg))
#define I915_READ8(reg) readb(dev_priv->regs + (reg))
@@ -1110,6 +1211,11 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
#define POSTING_READ(reg) (void)I915_READ(reg)
#define POSTING_READ16(reg) (void)I915_READ16(reg)
+#define I915_DEBUG_ENABLE_IO() (dev_priv->debug_flags |= I915_DEBUG_READ | \
+ I915_DEBUG_WRITE)
+#define I915_DEBUG_DISABLE_IO() (dev_priv->debug_flags &= ~(I915_DEBUG_READ | \
+ I915_DEBUG_WRITE))
+
#define I915_VERBOSE 0
#define BEGIN_LP_RING(n) do { \
@@ -1166,8 +1272,6 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
#define IS_I915GM(dev) ((dev)->pci_device == 0x2592)
#define IS_I945G(dev) ((dev)->pci_device == 0x2772)
#define IS_I945GM(dev) (INTEL_INFO(dev)->is_i945gm)
-#define IS_I965G(dev) (INTEL_INFO(dev)->is_i965g)
-#define IS_I965GM(dev) (INTEL_INFO(dev)->is_i965gm)
#define IS_BROADWATER(dev) (INTEL_INFO(dev)->is_broadwater)
#define IS_CRESTLINE(dev) (INTEL_INFO(dev)->is_crestline)
#define IS_GM45(dev) ((dev)->pci_device == 0x2A42)
@@ -1178,8 +1282,6 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
#define IS_G33(dev) (INTEL_INFO(dev)->is_g33)
#define IS_IRONLAKE_D(dev) ((dev)->pci_device == 0x0042)
#define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046)
-#define IS_IRONLAKE(dev) (INTEL_INFO(dev)->is_ironlake)
-#define IS_I9XX(dev) (INTEL_INFO(dev)->is_i9xx)
#define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile)
#define IS_GEN2(dev) (INTEL_INFO(dev)->gen == 2)
@@ -1188,33 +1290,34 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
#define IS_GEN5(dev) (INTEL_INFO(dev)->gen == 5)
#define IS_GEN6(dev) (INTEL_INFO(dev)->gen == 6)
-#define HAS_BSD(dev) (IS_IRONLAKE(dev) || IS_G4X(dev))
+#define HAS_BSD(dev) (INTEL_INFO(dev)->has_bsd_ring)
+#define HAS_BLT(dev) (INTEL_INFO(dev)->has_blt_ring)
#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
+#define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay)
+#define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical)
+
/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
* rows, which changed the alignment requirements and fence programming.
*/
-#define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \
+#define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \
IS_I915GM(dev)))
-#define SUPPORTS_DIGITAL_OUTPUTS(dev) (IS_I9XX(dev) && !IS_PINEVIEW(dev))
-#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IRONLAKE(dev))
-#define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_IRONLAKE(dev))
+#define SUPPORTS_DIGITAL_OUTPUTS(dev) (!IS_GEN2(dev) && !IS_PINEVIEW(dev))
+#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_GEN5(dev))
+#define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_GEN5(dev))
#define SUPPORTS_EDP(dev) (IS_IRONLAKE_M(dev))
-#define SUPPORTS_TV(dev) (IS_I9XX(dev) && IS_MOBILE(dev) && \
- !IS_IRONLAKE(dev) && !IS_PINEVIEW(dev) && \
- !IS_GEN6(dev))
+#define SUPPORTS_TV(dev) (INTEL_INFO(dev)->supports_tv)
#define I915_HAS_HOTPLUG(dev) (INTEL_INFO(dev)->has_hotplug)
/* dsparb controlled by hw only */
#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IRONLAKE(dev))
-#define HAS_FW_BLC(dev) (IS_I9XX(dev) || IS_G4X(dev) || IS_IRONLAKE(dev))
+#define HAS_FW_BLC(dev) (INTEL_INFO(dev)->gen > 2)
#define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
#define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6)
-#define HAS_PCH_SPLIT(dev) (IS_IRONLAKE(dev) || \
- IS_GEN6(dev))
-#define HAS_PIPE_CONTROL(dev) (IS_IRONLAKE(dev) || IS_GEN6(dev))
+#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev))
+#define HAS_PIPE_CONTROL(dev) (IS_GEN5(dev) || IS_GEN6(dev))
#define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type)
#define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 90b1d6753b9d..8eb8453208b5 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -37,7 +37,9 @@
#include <linux/intel-gtt.h>
static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj);
-static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj);
+
+static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj,
+ bool pipelined);
static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj);
static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj);
static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj,
@@ -46,7 +48,8 @@ static int i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj,
uint64_t offset,
uint64_t size);
static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj);
-static int i915_gem_object_wait_rendering(struct drm_gem_object *obj);
+static int i915_gem_object_wait_rendering(struct drm_gem_object *obj,
+ bool interruptible);
static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
unsigned alignment);
static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
@@ -55,9 +58,111 @@ static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *o
struct drm_file *file_priv);
static void i915_gem_free_object_tail(struct drm_gem_object *obj);
+static int
+i915_gem_object_get_pages(struct drm_gem_object *obj,
+ gfp_t gfpmask);
+
+static void
+i915_gem_object_put_pages(struct drm_gem_object *obj);
+
static LIST_HEAD(shrink_list);
static DEFINE_SPINLOCK(shrink_list_lock);
+/* some bookkeeping */
+static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
+ size_t size)
+{
+ dev_priv->mm.object_count++;
+ dev_priv->mm.object_memory += size;
+}
+
+static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv,
+ size_t size)
+{
+ dev_priv->mm.object_count--;
+ dev_priv->mm.object_memory -= size;
+}
+
+static void i915_gem_info_add_gtt(struct drm_i915_private *dev_priv,
+ size_t size)
+{
+ dev_priv->mm.gtt_count++;
+ dev_priv->mm.gtt_memory += size;
+}
+
+static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv,
+ size_t size)
+{
+ dev_priv->mm.gtt_count--;
+ dev_priv->mm.gtt_memory -= size;
+}
+
+static void i915_gem_info_add_pin(struct drm_i915_private *dev_priv,
+ size_t size)
+{
+ dev_priv->mm.pin_count++;
+ dev_priv->mm.pin_memory += size;
+}
+
+static void i915_gem_info_remove_pin(struct drm_i915_private *dev_priv,
+ size_t size)
+{
+ dev_priv->mm.pin_count--;
+ dev_priv->mm.pin_memory -= size;
+}
+
+int
+i915_gem_check_is_wedged(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct completion *x = &dev_priv->error_completion;
+ unsigned long flags;
+ int ret;
+
+ if (!atomic_read(&dev_priv->mm.wedged))
+ return 0;
+
+ ret = wait_for_completion_interruptible(x);
+ if (ret)
+ return ret;
+
+ /* Success, we reset the GPU! */
+ if (!atomic_read(&dev_priv->mm.wedged))
+ return 0;
+
+ /* GPU is hung, bump the completion count to account for
+ * the token we just consumed so that we never hit zero and
+ * end up waiting upon a subsequent completion event that
+ * will never happen.
+ */
+ spin_lock_irqsave(&x->wait.lock, flags);
+ x->done++;
+ spin_unlock_irqrestore(&x->wait.lock, flags);
+ return -EIO;
+}
+
+static int i915_mutex_lock_interruptible(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret;
+
+ ret = i915_gem_check_is_wedged(dev);
+ if (ret)
+ return ret;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
+
+ if (atomic_read(&dev_priv->mm.wedged)) {
+ mutex_unlock(&dev->struct_mutex);
+ return -EAGAIN;
+ }
+
+ WARN_ON(i915_verify_lists(dev));
+ return 0;
+}
+
static inline bool
i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv)
{
@@ -66,7 +171,8 @@ i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv)
obj_priv->pin_count == 0;
}
-int i915_gem_do_init(struct drm_device *dev, unsigned long start,
+int i915_gem_do_init(struct drm_device *dev,
+ unsigned long start,
unsigned long end)
{
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -80,7 +186,7 @@ int i915_gem_do_init(struct drm_device *dev, unsigned long start,
drm_mm_init(&dev_priv->mm.gtt_space, start,
end - start);
- dev->gtt_total = (uint32_t) (end - start);
+ dev_priv->mm.gtt_total = end - start;
return 0;
}
@@ -103,14 +209,16 @@ int
i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_get_aperture *args = data;
if (!(dev->driver->driver_features & DRIVER_GEM))
return -ENODEV;
- args->aper_size = dev->gtt_total;
- args->aper_available_size = (args->aper_size -
- atomic_read(&dev->pin_memory));
+ mutex_lock(&dev->struct_mutex);
+ args->aper_size = dev_priv->mm.gtt_total;
+ args->aper_available_size = args->aper_size - dev_priv->mm.pin_memory;
+ mutex_unlock(&dev->struct_mutex);
return 0;
}
@@ -136,12 +244,17 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
return -ENOMEM;
ret = drm_gem_handle_create(file_priv, obj, &handle);
- /* drop reference from allocate - handle holds it now */
- drm_gem_object_unreference_unlocked(obj);
if (ret) {
+ drm_gem_object_release(obj);
+ i915_gem_info_remove_obj(dev->dev_private, obj->size);
+ kfree(obj);
return ret;
}
+ /* drop reference from allocate - handle holds it now */
+ drm_gem_object_unreference(obj);
+ trace_i915_gem_object_create(obj);
+
args->handle = handle;
return 0;
}
@@ -152,19 +265,14 @@ fast_shmem_read(struct page **pages,
char __user *data,
int length)
{
- char __iomem *vaddr;
- int unwritten;
-
- vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT], KM_USER0);
- if (vaddr == NULL)
- return -ENOMEM;
- unwritten = __copy_to_user_inatomic(data, vaddr + page_offset, length);
- kunmap_atomic(vaddr, KM_USER0);
+ char *vaddr;
+ int ret;
- if (unwritten)
- return -EFAULT;
+ vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT]);
+ ret = __copy_to_user_inatomic(data, vaddr + page_offset, length);
+ kunmap_atomic(vaddr);
- return 0;
+ return ret;
}
static int i915_gem_object_needs_bit17_swizzle(struct drm_gem_object *obj)
@@ -258,22 +366,10 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj,
loff_t offset, page_base;
char __user *user_data;
int page_offset, page_length;
- int ret;
user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
- mutex_lock(&dev->struct_mutex);
-
- ret = i915_gem_object_get_pages(obj, 0);
- if (ret != 0)
- goto fail_unlock;
-
- ret = i915_gem_object_set_cpu_read_domain_range(obj, args->offset,
- args->size);
- if (ret != 0)
- goto fail_put_pages;
-
obj_priv = to_intel_bo(obj);
offset = args->offset;
@@ -290,23 +386,17 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj,
if ((page_offset + remain) > PAGE_SIZE)
page_length = PAGE_SIZE - page_offset;
- ret = fast_shmem_read(obj_priv->pages,
- page_base, page_offset,
- user_data, page_length);
- if (ret)
- goto fail_put_pages;
+ if (fast_shmem_read(obj_priv->pages,
+ page_base, page_offset,
+ user_data, page_length))
+ return -EFAULT;
remain -= page_length;
user_data += page_length;
offset += page_length;
}
-fail_put_pages:
- i915_gem_object_put_pages(obj);
-fail_unlock:
- mutex_unlock(&dev->struct_mutex);
-
- return ret;
+ return 0;
}
static int
@@ -367,31 +457,28 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
num_pages = last_data_page - first_data_page + 1;
- user_pages = drm_calloc_large(num_pages, sizeof(struct page *));
+ user_pages = drm_malloc_ab(num_pages, sizeof(struct page *));
if (user_pages == NULL)
return -ENOMEM;
+ mutex_unlock(&dev->struct_mutex);
down_read(&mm->mmap_sem);
pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr,
num_pages, 1, 0, user_pages, NULL);
up_read(&mm->mmap_sem);
+ mutex_lock(&dev->struct_mutex);
if (pinned_pages < num_pages) {
ret = -EFAULT;
- goto fail_put_user_pages;
+ goto out;
}
- do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
-
- mutex_lock(&dev->struct_mutex);
-
- ret = i915_gem_object_get_pages_or_evict(obj);
+ ret = i915_gem_object_set_cpu_read_domain_range(obj,
+ args->offset,
+ args->size);
if (ret)
- goto fail_unlock;
+ goto out;
- ret = i915_gem_object_set_cpu_read_domain_range(obj, args->offset,
- args->size);
- if (ret != 0)
- goto fail_put_pages;
+ do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
obj_priv = to_intel_bo(obj);
offset = args->offset;
@@ -436,11 +523,7 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
offset += page_length;
}
-fail_put_pages:
- i915_gem_object_put_pages(obj);
-fail_unlock:
- mutex_unlock(&dev->struct_mutex);
-fail_put_user_pages:
+out:
for (i = 0; i < pinned_pages; i++) {
SetPageDirty(user_pages[i]);
page_cache_release(user_pages[i]);
@@ -462,37 +545,64 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
struct drm_i915_gem_pread *args = data;
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
- int ret;
+ int ret = 0;
+
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return ret;
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
- if (obj == NULL)
- return -ENOENT;
+ if (obj == NULL) {
+ ret = -ENOENT;
+ goto unlock;
+ }
obj_priv = to_intel_bo(obj);
/* Bounds check source. */
if (args->offset > obj->size || args->size > obj->size - args->offset) {
ret = -EINVAL;
- goto err;
+ goto out;
}
+ if (args->size == 0)
+ goto out;
+
if (!access_ok(VERIFY_WRITE,
(char __user *)(uintptr_t)args->data_ptr,
args->size)) {
ret = -EFAULT;
- goto err;
+ goto out;
}
- if (i915_gem_object_needs_bit17_swizzle(obj)) {
- ret = i915_gem_shmem_pread_slow(dev, obj, args, file_priv);
- } else {
- ret = i915_gem_shmem_pread_fast(dev, obj, args, file_priv);
- if (ret != 0)
- ret = i915_gem_shmem_pread_slow(dev, obj, args,
- file_priv);
+ ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr,
+ args->size);
+ if (ret) {
+ ret = -EFAULT;
+ goto out;
}
-err:
- drm_gem_object_unreference_unlocked(obj);
+ ret = i915_gem_object_get_pages_or_evict(obj);
+ if (ret)
+ goto out;
+
+ ret = i915_gem_object_set_cpu_read_domain_range(obj,
+ args->offset,
+ args->size);
+ if (ret)
+ goto out_put;
+
+ ret = -EFAULT;
+ if (!i915_gem_object_needs_bit17_swizzle(obj))
+ ret = i915_gem_shmem_pread_fast(dev, obj, args, file_priv);
+ if (ret == -EFAULT)
+ ret = i915_gem_shmem_pread_slow(dev, obj, args, file_priv);
+
+out_put:
+ i915_gem_object_put_pages(obj);
+out:
+ drm_gem_object_unreference(obj);
+unlock:
+ mutex_unlock(&dev->struct_mutex);
return ret;
}
@@ -509,13 +619,11 @@ fast_user_write(struct io_mapping *mapping,
char *vaddr_atomic;
unsigned long unwritten;
- vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base, KM_USER0);
+ vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base);
unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + page_offset,
user_data, length);
- io_mapping_unmap_atomic(vaddr_atomic, KM_USER0);
- if (unwritten)
- return -EFAULT;
- return 0;
+ io_mapping_unmap_atomic(vaddr_atomic);
+ return unwritten;
}
/* Here's the write path which can sleep for
@@ -548,18 +656,14 @@ fast_shmem_write(struct page **pages,
char __user *data,
int length)
{
- char __iomem *vaddr;
- unsigned long unwritten;
+ char *vaddr;
+ int ret;
- vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT], KM_USER0);
- if (vaddr == NULL)
- return -ENOMEM;
- unwritten = __copy_from_user_inatomic(vaddr + page_offset, data, length);
- kunmap_atomic(vaddr, KM_USER0);
+ vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT]);
+ ret = __copy_from_user_inatomic(vaddr + page_offset, data, length);
+ kunmap_atomic(vaddr);
- if (unwritten)
- return -EFAULT;
- return 0;
+ return ret;
}
/**
@@ -577,22 +681,10 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
loff_t offset, page_base;
char __user *user_data;
int page_offset, page_length;
- int ret;
user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
-
- mutex_lock(&dev->struct_mutex);
- ret = i915_gem_object_pin(obj, 0);
- if (ret) {
- mutex_unlock(&dev->struct_mutex);
- return ret;
- }
- ret = i915_gem_object_set_to_gtt_domain(obj, 1);
- if (ret)
- goto fail;
-
obj_priv = to_intel_bo(obj);
offset = obj_priv->gtt_offset + args->offset;
@@ -609,26 +701,21 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
if ((page_offset + remain) > PAGE_SIZE)
page_length = PAGE_SIZE - page_offset;
- ret = fast_user_write (dev_priv->mm.gtt_mapping, page_base,
- page_offset, user_data, page_length);
-
/* If we get a fault while copying data, then (presumably) our
* source page isn't available. Return the error and we'll
* retry in the slow path.
*/
- if (ret)
- goto fail;
+ if (fast_user_write(dev_priv->mm.gtt_mapping, page_base,
+ page_offset, user_data, page_length))
+
+ return -EFAULT;
remain -= page_length;
user_data += page_length;
offset += page_length;
}
-fail:
- i915_gem_object_unpin(obj);
- mutex_unlock(&dev->struct_mutex);
-
- return ret;
+ return 0;
}
/**
@@ -665,27 +752,24 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
num_pages = last_data_page - first_data_page + 1;
- user_pages = drm_calloc_large(num_pages, sizeof(struct page *));
+ user_pages = drm_malloc_ab(num_pages, sizeof(struct page *));
if (user_pages == NULL)
return -ENOMEM;
+ mutex_unlock(&dev->struct_mutex);
down_read(&mm->mmap_sem);
pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr,
num_pages, 0, 0, user_pages, NULL);
up_read(&mm->mmap_sem);
+ mutex_lock(&dev->struct_mutex);
if (pinned_pages < num_pages) {
ret = -EFAULT;
goto out_unpin_pages;
}
- mutex_lock(&dev->struct_mutex);
- ret = i915_gem_object_pin(obj, 0);
- if (ret)
- goto out_unlock;
-
ret = i915_gem_object_set_to_gtt_domain(obj, 1);
if (ret)
- goto out_unpin_object;
+ goto out_unpin_pages;
obj_priv = to_intel_bo(obj);
offset = obj_priv->gtt_offset + args->offset;
@@ -721,10 +805,6 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
data_ptr += page_length;
}
-out_unpin_object:
- i915_gem_object_unpin(obj);
-out_unlock:
- mutex_unlock(&dev->struct_mutex);
out_unpin_pages:
for (i = 0; i < pinned_pages; i++)
page_cache_release(user_pages[i]);
@@ -747,21 +827,10 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
loff_t offset, page_base;
char __user *user_data;
int page_offset, page_length;
- int ret;
user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
- mutex_lock(&dev->struct_mutex);
-
- ret = i915_gem_object_get_pages(obj, 0);
- if (ret != 0)
- goto fail_unlock;
-
- ret = i915_gem_object_set_to_cpu_domain(obj, 1);
- if (ret != 0)
- goto fail_put_pages;
-
obj_priv = to_intel_bo(obj);
offset = args->offset;
obj_priv->dirty = 1;
@@ -779,23 +848,17 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
if ((page_offset + remain) > PAGE_SIZE)
page_length = PAGE_SIZE - page_offset;
- ret = fast_shmem_write(obj_priv->pages,
+ if (fast_shmem_write(obj_priv->pages,
page_base, page_offset,
- user_data, page_length);
- if (ret)
- goto fail_put_pages;
+ user_data, page_length))
+ return -EFAULT;
remain -= page_length;
user_data += page_length;
offset += page_length;
}
-fail_put_pages:
- i915_gem_object_put_pages(obj);
-fail_unlock:
- mutex_unlock(&dev->struct_mutex);
-
- return ret;
+ return 0;
}
/**
@@ -833,30 +896,26 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
num_pages = last_data_page - first_data_page + 1;
- user_pages = drm_calloc_large(num_pages, sizeof(struct page *));
+ user_pages = drm_malloc_ab(num_pages, sizeof(struct page *));
if (user_pages == NULL)
return -ENOMEM;
+ mutex_unlock(&dev->struct_mutex);
down_read(&mm->mmap_sem);
pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr,
num_pages, 0, 0, user_pages, NULL);
up_read(&mm->mmap_sem);
+ mutex_lock(&dev->struct_mutex);
if (pinned_pages < num_pages) {
ret = -EFAULT;
- goto fail_put_user_pages;
+ goto out;
}
- do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
-
- mutex_lock(&dev->struct_mutex);
-
- ret = i915_gem_object_get_pages_or_evict(obj);
+ ret = i915_gem_object_set_to_cpu_domain(obj, 1);
if (ret)
- goto fail_unlock;
+ goto out;
- ret = i915_gem_object_set_to_cpu_domain(obj, 1);
- if (ret != 0)
- goto fail_put_pages;
+ do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
obj_priv = to_intel_bo(obj);
offset = args->offset;
@@ -902,11 +961,7 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
offset += page_length;
}
-fail_put_pages:
- i915_gem_object_put_pages(obj);
-fail_unlock:
- mutex_unlock(&dev->struct_mutex);
-fail_put_user_pages:
+out:
for (i = 0; i < pinned_pages; i++)
page_cache_release(user_pages[i]);
drm_free_large(user_pages);
@@ -921,29 +976,46 @@ fail_put_user_pages:
*/
int
i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+ struct drm_file *file)
{
struct drm_i915_gem_pwrite *args = data;
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
int ret = 0;
- obj = drm_gem_object_lookup(dev, file_priv, args->handle);
- if (obj == NULL)
- return -ENOENT;
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return ret;
+
+ obj = drm_gem_object_lookup(dev, file, args->handle);
+ if (obj == NULL) {
+ ret = -ENOENT;
+ goto unlock;
+ }
obj_priv = to_intel_bo(obj);
+
/* Bounds check destination. */
if (args->offset > obj->size || args->size > obj->size - args->offset) {
ret = -EINVAL;
- goto err;
+ goto out;
}
+ if (args->size == 0)
+ goto out;
+
if (!access_ok(VERIFY_READ,
(char __user *)(uintptr_t)args->data_ptr,
args->size)) {
ret = -EFAULT;
- goto err;
+ goto out;
+ }
+
+ ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr,
+ args->size);
+ if (ret) {
+ ret = -EFAULT;
+ goto out;
}
/* We can only do the GTT pwrite on untiled buffers, as otherwise
@@ -953,32 +1025,47 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
* perspective, requiring manual detiling by the client.
*/
if (obj_priv->phys_obj)
- ret = i915_gem_phys_pwrite(dev, obj, args, file_priv);
+ ret = i915_gem_phys_pwrite(dev, obj, args, file);
else if (obj_priv->tiling_mode == I915_TILING_NONE &&
- dev->gtt_total != 0 &&
+ obj_priv->gtt_space &&
obj->write_domain != I915_GEM_DOMAIN_CPU) {
- ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file_priv);
- if (ret == -EFAULT) {
- ret = i915_gem_gtt_pwrite_slow(dev, obj, args,
- file_priv);
- }
- } else if (i915_gem_object_needs_bit17_swizzle(obj)) {
- ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file_priv);
+ ret = i915_gem_object_pin(obj, 0);
+ if (ret)
+ goto out;
+
+ ret = i915_gem_object_set_to_gtt_domain(obj, 1);
+ if (ret)
+ goto out_unpin;
+
+ ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file);
+ if (ret == -EFAULT)
+ ret = i915_gem_gtt_pwrite_slow(dev, obj, args, file);
+
+out_unpin:
+ i915_gem_object_unpin(obj);
} else {
- ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file_priv);
- if (ret == -EFAULT) {
- ret = i915_gem_shmem_pwrite_slow(dev, obj, args,
- file_priv);
- }
- }
+ ret = i915_gem_object_get_pages_or_evict(obj);
+ if (ret)
+ goto out;
-#if WATCH_PWRITE
- if (ret)
- DRM_INFO("pwrite failed %d\n", ret);
-#endif
+ ret = i915_gem_object_set_to_cpu_domain(obj, 1);
+ if (ret)
+ goto out_put;
-err:
- drm_gem_object_unreference_unlocked(obj);
+ ret = -EFAULT;
+ if (!i915_gem_object_needs_bit17_swizzle(obj))
+ ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file);
+ if (ret == -EFAULT)
+ ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file);
+
+out_put:
+ i915_gem_object_put_pages(obj);
+ }
+
+out:
+ drm_gem_object_unreference(obj);
+unlock:
+ mutex_unlock(&dev->struct_mutex);
return ret;
}
@@ -1014,19 +1101,19 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
if (write_domain != 0 && read_domains != write_domain)
return -EINVAL;
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return ret;
+
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
- if (obj == NULL)
- return -ENOENT;
+ if (obj == NULL) {
+ ret = -ENOENT;
+ goto unlock;
+ }
obj_priv = to_intel_bo(obj);
- mutex_lock(&dev->struct_mutex);
-
intel_mark_busy(dev, obj);
-#if WATCH_BUF
- DRM_INFO("set_domain_ioctl %p(%zd), %08x %08x\n",
- obj, obj->size, read_domains, write_domain);
-#endif
if (read_domains & I915_GEM_DOMAIN_GTT) {
ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);
@@ -1050,12 +1137,12 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0);
}
-
/* Maintain LRU order of "inactive" objects */
if (ret == 0 && i915_gem_object_is_inactive(obj_priv))
- list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+ list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
drm_gem_object_unreference(obj);
+unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
}
@@ -1069,30 +1156,27 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
{
struct drm_i915_gem_sw_finish *args = data;
struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
int ret = 0;
if (!(dev->driver->driver_features & DRIVER_GEM))
return -ENODEV;
- mutex_lock(&dev->struct_mutex);
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return ret;
+
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL) {
- mutex_unlock(&dev->struct_mutex);
- return -ENOENT;
+ ret = -ENOENT;
+ goto unlock;
}
-#if WATCH_BUF
- DRM_INFO("%s: sw_finish %d (%p %zd)\n",
- __func__, args->handle, obj, obj->size);
-#endif
- obj_priv = to_intel_bo(obj);
-
/* Pinned buffers may be scanout, so flush the cache */
- if (obj_priv->pin_count)
+ if (to_intel_bo(obj)->pin_count)
i915_gem_object_flush_cpu_write_domain(obj);
drm_gem_object_unreference(obj);
+unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
}
@@ -1181,13 +1265,13 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
/* Need a new fence register? */
if (obj_priv->tiling_mode != I915_TILING_NONE) {
- ret = i915_gem_object_get_fence_reg(obj);
+ ret = i915_gem_object_get_fence_reg(obj, true);
if (ret)
goto unlock;
}
if (i915_gem_object_is_inactive(obj_priv))
- list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+ list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) +
page_offset;
@@ -1246,7 +1330,7 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj)
obj->size / PAGE_SIZE, 0, 0);
if (!list->file_offset_node) {
DRM_ERROR("failed to allocate offset for bo %d\n", obj->name);
- ret = -ENOMEM;
+ ret = -ENOSPC;
goto out_free_list;
}
@@ -1258,9 +1342,9 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj)
}
list->hash.key = list->file_offset_node->start;
- if (drm_ht_insert_item(&mm->offset_hash, &list->hash)) {
+ ret = drm_ht_insert_item(&mm->offset_hash, &list->hash);
+ if (ret) {
DRM_ERROR("failed to add to map hash\n");
- ret = -ENOMEM;
goto out_free_mm;
}
@@ -1345,14 +1429,14 @@ i915_gem_get_gtt_alignment(struct drm_gem_object *obj)
* Minimum alignment is 4k (GTT page size), but might be greater
* if a fence register is needed for the object.
*/
- if (IS_I965G(dev) || obj_priv->tiling_mode == I915_TILING_NONE)
+ if (INTEL_INFO(dev)->gen >= 4 || obj_priv->tiling_mode == I915_TILING_NONE)
return 4096;
/*
* Previous chips need to be aligned to the size of the smallest
* fence register that can contain the object.
*/
- if (IS_I9XX(dev))
+ if (INTEL_INFO(dev)->gen == 3)
start = 1024*1024;
else
start = 512*1024;
@@ -1390,29 +1474,27 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
if (!(dev->driver->driver_features & DRIVER_GEM))
return -ENODEV;
- obj = drm_gem_object_lookup(dev, file_priv, args->handle);
- if (obj == NULL)
- return -ENOENT;
-
- mutex_lock(&dev->struct_mutex);
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return ret;
+ obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (obj == NULL) {
+ ret = -ENOENT;
+ goto unlock;
+ }
obj_priv = to_intel_bo(obj);
if (obj_priv->madv != I915_MADV_WILLNEED) {
DRM_ERROR("Attempting to mmap a purgeable buffer\n");
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
-
if (!obj_priv->mmap_offset) {
ret = i915_gem_create_mmap_offset(obj);
- if (ret) {
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
- return ret;
- }
+ if (ret)
+ goto out;
}
args->offset = obj_priv->mmap_offset;
@@ -1423,20 +1505,18 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
*/
if (!obj_priv->agp_mem) {
ret = i915_gem_object_bind_to_gtt(obj, 0);
- if (ret) {
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
- return ret;
- }
+ if (ret)
+ goto out;
}
+out:
drm_gem_object_unreference(obj);
+unlock:
mutex_unlock(&dev->struct_mutex);
-
- return 0;
+ return ret;
}
-void
+static void
i915_gem_object_put_pages(struct drm_gem_object *obj)
{
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
@@ -1470,13 +1550,25 @@ i915_gem_object_put_pages(struct drm_gem_object *obj)
obj_priv->pages = NULL;
}
+static uint32_t
+i915_gem_next_request_seqno(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ ring->outstanding_lazy_request = true;
+ return dev_priv->next_seqno;
+}
+
static void
-i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno,
+i915_gem_object_move_to_active(struct drm_gem_object *obj,
struct intel_ring_buffer *ring)
{
struct drm_device *dev = obj->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ uint32_t seqno = i915_gem_next_request_seqno(dev, ring);
+
BUG_ON(ring == NULL);
obj_priv->ring = ring;
@@ -1485,10 +1577,10 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno,
drm_gem_object_reference(obj);
obj_priv->active = 1;
}
+
/* Move from whatever list we were on to the tail of execution. */
- spin_lock(&dev_priv->mm.active_list_lock);
- list_move_tail(&obj_priv->list, &ring->active_list);
- spin_unlock(&dev_priv->mm.active_list_lock);
+ list_move_tail(&obj_priv->mm_list, &dev_priv->mm.active_list);
+ list_move_tail(&obj_priv->ring_list, &ring->active_list);
obj_priv->last_rendering_seqno = seqno;
}
@@ -1500,7 +1592,8 @@ i915_gem_object_move_to_flushing(struct drm_gem_object *obj)
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
BUG_ON(!obj_priv->active);
- list_move_tail(&obj_priv->list, &dev_priv->mm.flushing_list);
+ list_move_tail(&obj_priv->mm_list, &dev_priv->mm.flushing_list);
+ list_del_init(&obj_priv->ring_list);
obj_priv->last_rendering_seqno = 0;
}
@@ -1538,11 +1631,11 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- i915_verify_inactive(dev, __FILE__, __LINE__);
if (obj_priv->pin_count != 0)
- list_del_init(&obj_priv->list);
+ list_move_tail(&obj_priv->mm_list, &dev_priv->mm.pinned_list);
else
- list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+ list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
+ list_del_init(&obj_priv->ring_list);
BUG_ON(!list_empty(&obj_priv->gpu_write_list));
@@ -1552,30 +1645,28 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
obj_priv->active = 0;
drm_gem_object_unreference(obj);
}
- i915_verify_inactive(dev, __FILE__, __LINE__);
+ WARN_ON(i915_verify_lists(dev));
}
static void
i915_gem_process_flushing_list(struct drm_device *dev,
- uint32_t flush_domains, uint32_t seqno,
+ uint32_t flush_domains,
struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv, *next;
list_for_each_entry_safe(obj_priv, next,
- &dev_priv->mm.gpu_write_list,
+ &ring->gpu_write_list,
gpu_write_list) {
struct drm_gem_object *obj = &obj_priv->base;
- if ((obj->write_domain & flush_domains) ==
- obj->write_domain &&
- obj_priv->ring->ring_flag == ring->ring_flag) {
+ if (obj->write_domain & flush_domains) {
uint32_t old_write_domain = obj->write_domain;
obj->write_domain = 0;
list_del_init(&obj_priv->gpu_write_list);
- i915_gem_object_move_to_active(obj, seqno, ring);
+ i915_gem_object_move_to_active(obj, ring);
/* update the fence lru list */
if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
@@ -1593,23 +1684,27 @@ i915_gem_process_flushing_list(struct drm_device *dev,
}
uint32_t
-i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
- uint32_t flush_domains, struct intel_ring_buffer *ring)
+i915_add_request(struct drm_device *dev,
+ struct drm_file *file,
+ struct drm_i915_gem_request *request,
+ struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_file_private *i915_file_priv = NULL;
- struct drm_i915_gem_request *request;
+ struct drm_i915_file_private *file_priv = NULL;
uint32_t seqno;
int was_empty;
- if (file_priv != NULL)
- i915_file_priv = file_priv->driver_priv;
+ if (file != NULL)
+ file_priv = file->driver_priv;
- request = kzalloc(sizeof(*request), GFP_KERNEL);
- if (request == NULL)
- return 0;
+ if (request == NULL) {
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL)
+ return 0;
+ }
- seqno = ring->add_request(dev, ring, file_priv, flush_domains);
+ seqno = ring->add_request(dev, ring, 0);
+ ring->outstanding_lazy_request = false;
request->seqno = seqno;
request->ring = ring;
@@ -1617,23 +1712,20 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
was_empty = list_empty(&ring->request_list);
list_add_tail(&request->list, &ring->request_list);
- if (i915_file_priv) {
+ if (file_priv) {
+ spin_lock(&file_priv->mm.lock);
+ request->file_priv = file_priv;
list_add_tail(&request->client_list,
- &i915_file_priv->mm.request_list);
- } else {
- INIT_LIST_HEAD(&request->client_list);
+ &file_priv->mm.request_list);
+ spin_unlock(&file_priv->mm.lock);
}
- /* Associate any objects on the flushing list matching the write
- * domain we're flushing with our flush.
- */
- if (flush_domains != 0)
- i915_gem_process_flushing_list(dev, flush_domains, seqno, ring);
-
if (!dev_priv->mm.suspended) {
- mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+ mod_timer(&dev_priv->hangcheck_timer,
+ jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
if (was_empty)
- queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
+ queue_delayed_work(dev_priv->wq,
+ &dev_priv->mm.retire_work, HZ);
}
return seqno;
}
@@ -1644,91 +1736,105 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
* Ensures that all commands in the ring are finished
* before signalling the CPU
*/
-static uint32_t
+static void
i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring)
{
uint32_t flush_domains = 0;
/* The sampler always gets flushed on i965 (sigh) */
- if (IS_I965G(dev))
+ if (INTEL_INFO(dev)->gen >= 4)
flush_domains |= I915_GEM_DOMAIN_SAMPLER;
ring->flush(dev, ring,
I915_GEM_DOMAIN_COMMAND, flush_domains);
- return flush_domains;
}
-/**
- * Moves buffers associated only with the given active seqno from the active
- * to inactive list, potentially freeing them.
- */
-static void
-i915_gem_retire_request(struct drm_device *dev,
- struct drm_i915_gem_request *request)
+static inline void
+i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_file_private *file_priv = request->file_priv;
- trace_i915_gem_request_retire(dev, request->seqno);
+ if (!file_priv)
+ return;
- /* Move any buffers on the active list that are no longer referenced
- * by the ringbuffer to the flushing/inactive lists as appropriate.
- */
- spin_lock(&dev_priv->mm.active_list_lock);
- while (!list_empty(&request->ring->active_list)) {
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
+ spin_lock(&file_priv->mm.lock);
+ list_del(&request->client_list);
+ request->file_priv = NULL;
+ spin_unlock(&file_priv->mm.lock);
+}
- obj_priv = list_first_entry(&request->ring->active_list,
- struct drm_i915_gem_object,
- list);
- obj = &obj_priv->base;
+static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
+ struct intel_ring_buffer *ring)
+{
+ while (!list_empty(&ring->request_list)) {
+ struct drm_i915_gem_request *request;
- /* If the seqno being retired doesn't match the oldest in the
- * list, then the oldest in the list must still be newer than
- * this seqno.
- */
- if (obj_priv->last_rendering_seqno != request->seqno)
- goto out;
+ request = list_first_entry(&ring->request_list,
+ struct drm_i915_gem_request,
+ list);
-#if WATCH_LRU
- DRM_INFO("%s: retire %d moves to inactive list %p\n",
- __func__, request->seqno, obj);
-#endif
+ list_del(&request->list);
+ i915_gem_request_remove_from_client(request);
+ kfree(request);
+ }
- if (obj->write_domain != 0)
- i915_gem_object_move_to_flushing(obj);
- else {
- /* Take a reference on the object so it won't be
- * freed while the spinlock is held. The list
- * protection for this spinlock is safe when breaking
- * the lock like this since the next thing we do
- * is just get the head of the list again.
- */
- drm_gem_object_reference(obj);
- i915_gem_object_move_to_inactive(obj);
- spin_unlock(&dev_priv->mm.active_list_lock);
- drm_gem_object_unreference(obj);
- spin_lock(&dev_priv->mm.active_list_lock);
- }
+ while (!list_empty(&ring->active_list)) {
+ struct drm_i915_gem_object *obj_priv;
+
+ obj_priv = list_first_entry(&ring->active_list,
+ struct drm_i915_gem_object,
+ ring_list);
+
+ obj_priv->base.write_domain = 0;
+ list_del_init(&obj_priv->gpu_write_list);
+ i915_gem_object_move_to_inactive(&obj_priv->base);
}
-out:
- spin_unlock(&dev_priv->mm.active_list_lock);
}
-/**
- * Returns true if seq1 is later than seq2.
- */
-bool
-i915_seqno_passed(uint32_t seq1, uint32_t seq2)
+void i915_gem_reset(struct drm_device *dev)
{
- return (int32_t)(seq1 - seq2) >= 0;
-}
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv;
+ int i;
-uint32_t
-i915_get_gem_seqno(struct drm_device *dev,
- struct intel_ring_buffer *ring)
-{
- return ring->get_gem_seqno(dev, ring);
+ i915_gem_reset_ring_lists(dev_priv, &dev_priv->render_ring);
+ i915_gem_reset_ring_lists(dev_priv, &dev_priv->bsd_ring);
+ i915_gem_reset_ring_lists(dev_priv, &dev_priv->blt_ring);
+
+ /* Remove anything from the flushing lists. The GPU cache is likely
+ * to be lost on reset along with the data, so simply move the
+ * lost bo to the inactive list.
+ */
+ while (!list_empty(&dev_priv->mm.flushing_list)) {
+ obj_priv = list_first_entry(&dev_priv->mm.flushing_list,
+ struct drm_i915_gem_object,
+ mm_list);
+
+ obj_priv->base.write_domain = 0;
+ list_del_init(&obj_priv->gpu_write_list);
+ i915_gem_object_move_to_inactive(&obj_priv->base);
+ }
+
+ /* Move everything out of the GPU domains to ensure we do any
+ * necessary invalidation upon reuse.
+ */
+ list_for_each_entry(obj_priv,
+ &dev_priv->mm.inactive_list,
+ mm_list)
+ {
+ obj_priv->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
+ }
+
+ /* The fence registers are invalidated so clear them out */
+ for (i = 0; i < 16; i++) {
+ struct drm_i915_fence_reg *reg;
+
+ reg = &dev_priv->fence_regs[i];
+ if (!reg->obj)
+ continue;
+
+ i915_gem_clear_fence_reg(reg->obj);
+ }
}
/**
@@ -1741,38 +1847,58 @@ i915_gem_retire_requests_ring(struct drm_device *dev,
drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t seqno;
- if (!ring->status_page.page_addr
- || list_empty(&ring->request_list))
+ if (!ring->status_page.page_addr ||
+ list_empty(&ring->request_list))
return;
- seqno = i915_get_gem_seqno(dev, ring);
+ WARN_ON(i915_verify_lists(dev));
+ seqno = ring->get_seqno(dev, ring);
while (!list_empty(&ring->request_list)) {
struct drm_i915_gem_request *request;
- uint32_t retiring_seqno;
request = list_first_entry(&ring->request_list,
struct drm_i915_gem_request,
list);
- retiring_seqno = request->seqno;
- if (i915_seqno_passed(seqno, retiring_seqno) ||
- atomic_read(&dev_priv->mm.wedged)) {
- i915_gem_retire_request(dev, request);
+ if (!i915_seqno_passed(seqno, request->seqno))
+ break;
+
+ trace_i915_gem_request_retire(dev, request->seqno);
+
+ list_del(&request->list);
+ i915_gem_request_remove_from_client(request);
+ kfree(request);
+ }
+
+ /* Move any buffers on the active list that are no longer referenced
+ * by the ringbuffer to the flushing/inactive lists as appropriate.
+ */
+ while (!list_empty(&ring->active_list)) {
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+
+ obj_priv = list_first_entry(&ring->active_list,
+ struct drm_i915_gem_object,
+ ring_list);
- list_del(&request->list);
- list_del(&request->client_list);
- kfree(request);
- } else
+ if (!i915_seqno_passed(seqno, obj_priv->last_rendering_seqno))
break;
+
+ obj = &obj_priv->base;
+ if (obj->write_domain != 0)
+ i915_gem_object_move_to_flushing(obj);
+ else
+ i915_gem_object_move_to_inactive(obj);
}
if (unlikely (dev_priv->trace_irq_seqno &&
i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) {
-
ring->user_irq_put(dev, ring);
dev_priv->trace_irq_seqno = 0;
}
+
+ WARN_ON(i915_verify_lists(dev));
}
void
@@ -1790,16 +1916,16 @@ i915_gem_retire_requests(struct drm_device *dev)
*/
list_for_each_entry_safe(obj_priv, tmp,
&dev_priv->mm.deferred_free_list,
- list)
+ mm_list)
i915_gem_free_object_tail(&obj_priv->base);
}
i915_gem_retire_requests_ring(dev, &dev_priv->render_ring);
- if (HAS_BSD(dev))
- i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring);
+ i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring);
+ i915_gem_retire_requests_ring(dev, &dev_priv->blt_ring);
}
-void
+static void
i915_gem_retire_work_handler(struct work_struct *work)
{
drm_i915_private_t *dev_priv;
@@ -1809,20 +1935,25 @@ i915_gem_retire_work_handler(struct work_struct *work)
mm.retire_work.work);
dev = dev_priv->dev;
- mutex_lock(&dev->struct_mutex);
+ /* Come back later if the device is busy... */
+ if (!mutex_trylock(&dev->struct_mutex)) {
+ queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
+ return;
+ }
+
i915_gem_retire_requests(dev);
if (!dev_priv->mm.suspended &&
(!list_empty(&dev_priv->render_ring.request_list) ||
- (HAS_BSD(dev) &&
- !list_empty(&dev_priv->bsd_ring.request_list))))
+ !list_empty(&dev_priv->bsd_ring.request_list) ||
+ !list_empty(&dev_priv->blt_ring.request_list)))
queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
mutex_unlock(&dev->struct_mutex);
}
int
i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
- int interruptible, struct intel_ring_buffer *ring)
+ bool interruptible, struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = dev->dev_private;
u32 ier;
@@ -1831,9 +1962,16 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
BUG_ON(seqno == 0);
if (atomic_read(&dev_priv->mm.wedged))
- return -EIO;
+ return -EAGAIN;
- if (!i915_seqno_passed(ring->get_gem_seqno(dev, ring), seqno)) {
+ if (ring->outstanding_lazy_request) {
+ seqno = i915_add_request(dev, NULL, NULL, ring);
+ if (seqno == 0)
+ return -ENOMEM;
+ }
+ BUG_ON(seqno == dev_priv->next_seqno);
+
+ if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) {
if (HAS_PCH_SPLIT(dev))
ier = I915_READ(DEIER) | I915_READ(GTIER);
else
@@ -1852,12 +1990,12 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
if (interruptible)
ret = wait_event_interruptible(ring->irq_queue,
i915_seqno_passed(
- ring->get_gem_seqno(dev, ring), seqno)
+ ring->get_seqno(dev, ring), seqno)
|| atomic_read(&dev_priv->mm.wedged));
else
wait_event(ring->irq_queue,
i915_seqno_passed(
- ring->get_gem_seqno(dev, ring), seqno)
+ ring->get_seqno(dev, ring), seqno)
|| atomic_read(&dev_priv->mm.wedged));
ring->user_irq_put(dev, ring);
@@ -1866,11 +2004,12 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
trace_i915_gem_request_wait_end(dev, seqno);
}
if (atomic_read(&dev_priv->mm.wedged))
- ret = -EIO;
+ ret = -EAGAIN;
if (ret && ret != -ERESTARTSYS)
- DRM_ERROR("%s returns %d (awaiting %d at %d)\n",
- __func__, ret, seqno, ring->get_gem_seqno(dev, ring));
+ DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n",
+ __func__, ret, seqno, ring->get_seqno(dev, ring),
+ dev_priv->next_seqno);
/* Directly dispatch request retiring. While we have the work queue
* to handle this, the waiter on a request often wants an associated
@@ -1889,27 +2028,48 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
*/
static int
i915_wait_request(struct drm_device *dev, uint32_t seqno,
- struct intel_ring_buffer *ring)
+ struct intel_ring_buffer *ring)
{
return i915_do_wait_request(dev, seqno, 1, ring);
}
static void
+i915_gem_flush_ring(struct drm_device *dev,
+ struct drm_file *file_priv,
+ struct intel_ring_buffer *ring,
+ uint32_t invalidate_domains,
+ uint32_t flush_domains)
+{
+ ring->flush(dev, ring, invalidate_domains, flush_domains);
+ i915_gem_process_flushing_list(dev, flush_domains, ring);
+}
+
+static void
i915_gem_flush(struct drm_device *dev,
+ struct drm_file *file_priv,
uint32_t invalidate_domains,
- uint32_t flush_domains)
+ uint32_t flush_domains,
+ uint32_t flush_rings)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+
if (flush_domains & I915_GEM_DOMAIN_CPU)
drm_agp_chipset_flush(dev);
- dev_priv->render_ring.flush(dev, &dev_priv->render_ring,
- invalidate_domains,
- flush_domains);
-
- if (HAS_BSD(dev))
- dev_priv->bsd_ring.flush(dev, &dev_priv->bsd_ring,
- invalidate_domains,
- flush_domains);
+
+ if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) {
+ if (flush_rings & RING_RENDER)
+ i915_gem_flush_ring(dev, file_priv,
+ &dev_priv->render_ring,
+ invalidate_domains, flush_domains);
+ if (flush_rings & RING_BSD)
+ i915_gem_flush_ring(dev, file_priv,
+ &dev_priv->bsd_ring,
+ invalidate_domains, flush_domains);
+ if (flush_rings & RING_BLT)
+ i915_gem_flush_ring(dev, file_priv,
+ &dev_priv->blt_ring,
+ invalidate_domains, flush_domains);
+ }
}
/**
@@ -1917,7 +2077,8 @@ i915_gem_flush(struct drm_device *dev,
* safe to unbind from the GTT or access from the CPU.
*/
static int
-i915_gem_object_wait_rendering(struct drm_gem_object *obj)
+i915_gem_object_wait_rendering(struct drm_gem_object *obj,
+ bool interruptible)
{
struct drm_device *dev = obj->dev;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
@@ -1932,13 +2093,11 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj)
* it.
*/
if (obj_priv->active) {
-#if WATCH_BUF
- DRM_INFO("%s: object %p wait for seqno %08x\n",
- __func__, obj, obj_priv->last_rendering_seqno);
-#endif
- ret = i915_wait_request(dev,
- obj_priv->last_rendering_seqno, obj_priv->ring);
- if (ret != 0)
+ ret = i915_do_wait_request(dev,
+ obj_priv->last_rendering_seqno,
+ interruptible,
+ obj_priv->ring);
+ if (ret)
return ret;
}
@@ -1952,14 +2111,10 @@ int
i915_gem_object_unbind(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int ret = 0;
-#if WATCH_BUF
- DRM_INFO("%s:%d %p\n", __func__, __LINE__, obj);
- DRM_INFO("gtt_space %p\n", obj_priv->gtt_space);
-#endif
if (obj_priv->gtt_space == NULL)
return 0;
@@ -1984,33 +2139,27 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
* should be safe and we need to cleanup or else we might
* cause memory corruption through use-after-free.
*/
+ if (ret) {
+ i915_gem_clflush_object(obj);
+ obj->read_domains = obj->write_domain = I915_GEM_DOMAIN_CPU;
+ }
/* release the fence reg _after_ flushing */
if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
i915_gem_clear_fence_reg(obj);
- if (obj_priv->agp_mem != NULL) {
- drm_unbind_agp(obj_priv->agp_mem);
- drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE);
- obj_priv->agp_mem = NULL;
- }
+ drm_unbind_agp(obj_priv->agp_mem);
+ drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE);
i915_gem_object_put_pages(obj);
BUG_ON(obj_priv->pages_refcount);
- if (obj_priv->gtt_space) {
- atomic_dec(&dev->gtt_count);
- atomic_sub(obj->size, &dev->gtt_memory);
-
- drm_mm_put_block(obj_priv->gtt_space);
- obj_priv->gtt_space = NULL;
- }
+ i915_gem_info_remove_gtt(dev_priv, obj->size);
+ list_del_init(&obj_priv->mm_list);
- /* Remove ourselves from the LRU list if present. */
- spin_lock(&dev_priv->mm.active_list_lock);
- if (!list_empty(&obj_priv->list))
- list_del_init(&obj_priv->list);
- spin_unlock(&dev_priv->mm.active_list_lock);
+ drm_mm_put_block(obj_priv->gtt_space);
+ obj_priv->gtt_space = NULL;
+ obj_priv->gtt_offset = 0;
if (i915_gem_object_is_purgeable(obj_priv))
i915_gem_object_truncate(obj);
@@ -2020,48 +2169,50 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
return ret;
}
+static int i915_ring_idle(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ if (list_empty(&ring->gpu_write_list))
+ return 0;
+
+ i915_gem_flush_ring(dev, NULL, ring,
+ I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+ return i915_wait_request(dev,
+ i915_gem_next_request_seqno(dev, ring),
+ ring);
+}
+
int
i915_gpu_idle(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
bool lists_empty;
- uint32_t seqno1, seqno2;
int ret;
- spin_lock(&dev_priv->mm.active_list_lock);
lists_empty = (list_empty(&dev_priv->mm.flushing_list) &&
list_empty(&dev_priv->render_ring.active_list) &&
- (!HAS_BSD(dev) ||
- list_empty(&dev_priv->bsd_ring.active_list)));
- spin_unlock(&dev_priv->mm.active_list_lock);
-
+ list_empty(&dev_priv->bsd_ring.active_list) &&
+ list_empty(&dev_priv->blt_ring.active_list));
if (lists_empty)
return 0;
/* Flush everything onto the inactive list. */
- i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
- seqno1 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS,
- &dev_priv->render_ring);
- if (seqno1 == 0)
- return -ENOMEM;
- ret = i915_wait_request(dev, seqno1, &dev_priv->render_ring);
-
- if (HAS_BSD(dev)) {
- seqno2 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS,
- &dev_priv->bsd_ring);
- if (seqno2 == 0)
- return -ENOMEM;
+ ret = i915_ring_idle(dev, &dev_priv->render_ring);
+ if (ret)
+ return ret;
- ret = i915_wait_request(dev, seqno2, &dev_priv->bsd_ring);
- if (ret)
- return ret;
- }
+ ret = i915_ring_idle(dev, &dev_priv->bsd_ring);
+ if (ret)
+ return ret;
+ ret = i915_ring_idle(dev, &dev_priv->blt_ring);
+ if (ret)
+ return ret;
- return ret;
+ return 0;
}
-int
+static int
i915_gem_object_get_pages(struct drm_gem_object *obj,
gfp_t gfpmask)
{
@@ -2241,7 +2392,8 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val);
}
-static int i915_find_fence_reg(struct drm_device *dev)
+static int i915_find_fence_reg(struct drm_device *dev,
+ bool interruptible)
{
struct drm_i915_fence_reg *reg = NULL;
struct drm_i915_gem_object *obj_priv = NULL;
@@ -2286,7 +2438,7 @@ static int i915_find_fence_reg(struct drm_device *dev)
* private reference to obj like the other callers of put_fence_reg
* (set_tiling ioctl) do. */
drm_gem_object_reference(obj);
- ret = i915_gem_object_put_fence_reg(obj);
+ ret = i915_gem_object_put_fence_reg(obj, interruptible);
drm_gem_object_unreference(obj);
if (ret != 0)
return ret;
@@ -2308,7 +2460,8 @@ static int i915_find_fence_reg(struct drm_device *dev)
* and tiling format.
*/
int
-i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
+i915_gem_object_get_fence_reg(struct drm_gem_object *obj,
+ bool interruptible)
{
struct drm_device *dev = obj->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2343,7 +2496,7 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
break;
}
- ret = i915_find_fence_reg(dev);
+ ret = i915_find_fence_reg(dev, interruptible);
if (ret < 0)
return ret;
@@ -2421,15 +2574,19 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj)
* i915_gem_object_put_fence_reg - waits on outstanding fenced access
* to the buffer to finish, and then resets the fence register.
* @obj: tiled object holding a fence register.
+ * @bool: whether the wait upon the fence is interruptible
*
* Zeroes out the fence register itself and clears out the associated
* data structures in dev_priv and obj_priv.
*/
int
-i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
+i915_gem_object_put_fence_reg(struct drm_gem_object *obj,
+ bool interruptible)
{
struct drm_device *dev = obj->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ struct drm_i915_fence_reg *reg;
if (obj_priv->fence_reg == I915_FENCE_REG_NONE)
return 0;
@@ -2444,20 +2601,23 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
* therefore we must wait for any outstanding access to complete
* before clearing the fence.
*/
- if (!IS_I965G(dev)) {
+ reg = &dev_priv->fence_regs[obj_priv->fence_reg];
+ if (reg->gpu) {
int ret;
- ret = i915_gem_object_flush_gpu_write_domain(obj);
- if (ret != 0)
+ ret = i915_gem_object_flush_gpu_write_domain(obj, true);
+ if (ret)
return ret;
- ret = i915_gem_object_wait_rendering(obj);
- if (ret != 0)
+ ret = i915_gem_object_wait_rendering(obj, interruptible);
+ if (ret)
return ret;
+
+ reg->gpu = false;
}
i915_gem_object_flush_gtt_write_domain(obj);
- i915_gem_clear_fence_reg (obj);
+ i915_gem_clear_fence_reg(obj);
return 0;
}
@@ -2490,7 +2650,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
/* If the object is bigger than the entire aperture, reject it early
* before evicting everything in a vain attempt to find space.
*/
- if (obj->size > dev->gtt_total) {
+ if (obj->size > dev_priv->mm.gtt_total) {
DRM_ERROR("Attempting to bind an object larger than the aperture\n");
return -E2BIG;
}
@@ -2498,19 +2658,13 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
search_free:
free_space = drm_mm_search_free(&dev_priv->mm.gtt_space,
obj->size, alignment, 0);
- if (free_space != NULL) {
+ if (free_space != NULL)
obj_priv->gtt_space = drm_mm_get_block(free_space, obj->size,
alignment);
- if (obj_priv->gtt_space != NULL)
- obj_priv->gtt_offset = obj_priv->gtt_space->start;
- }
if (obj_priv->gtt_space == NULL) {
/* If the gtt is empty and we're still having trouble
* fitting our object in, we're out of memory.
*/
-#if WATCH_LRU
- DRM_INFO("%s: GTT full, evicting something\n", __func__);
-#endif
ret = i915_gem_evict_something(dev, obj->size, alignment);
if (ret)
return ret;
@@ -2518,10 +2672,6 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
goto search_free;
}
-#if WATCH_BUF
- DRM_INFO("Binding object of size %zd at 0x%08x\n",
- obj->size, obj_priv->gtt_offset);
-#endif
ret = i915_gem_object_get_pages(obj, gfpmask);
if (ret) {
drm_mm_put_block(obj_priv->gtt_space);
@@ -2553,7 +2703,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
obj_priv->agp_mem = drm_agp_bind_pages(dev,
obj_priv->pages,
obj->size >> PAGE_SHIFT,
- obj_priv->gtt_offset,
+ obj_priv->gtt_space->start,
obj_priv->agp_type);
if (obj_priv->agp_mem == NULL) {
i915_gem_object_put_pages(obj);
@@ -2566,11 +2716,10 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
goto search_free;
}
- atomic_inc(&dev->gtt_count);
- atomic_add(obj->size, &dev->gtt_memory);
/* keep track of bounds object by adding it to the inactive list */
- list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+ list_add_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
+ i915_gem_info_add_gtt(dev_priv, obj->size);
/* Assert that the object is not currently in any GPU domain. As it
* wasn't in the GTT, there shouldn't be any way it could have been in
@@ -2579,6 +2728,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS);
BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS);
+ obj_priv->gtt_offset = obj_priv->gtt_space->start;
trace_i915_gem_object_bind(obj, obj_priv->gtt_offset);
return 0;
@@ -2603,25 +2753,30 @@ i915_gem_clflush_object(struct drm_gem_object *obj)
/** Flushes any GPU write domain for the object if it's dirty. */
static int
-i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
+i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj,
+ bool pipelined)
{
struct drm_device *dev = obj->dev;
uint32_t old_write_domain;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
return 0;
/* Queue the GPU write cache flushing we need. */
old_write_domain = obj->write_domain;
- i915_gem_flush(dev, 0, obj->write_domain);
- if (i915_add_request(dev, NULL, obj->write_domain, obj_priv->ring) == 0)
- return -ENOMEM;
+ i915_gem_flush_ring(dev, NULL,
+ to_intel_bo(obj)->ring,
+ 0, obj->write_domain);
+ BUG_ON(obj->write_domain);
trace_i915_gem_object_change_domain(obj,
obj->read_domains,
old_write_domain);
- return 0;
+
+ if (pipelined)
+ return 0;
+
+ return i915_gem_object_wait_rendering(obj, true);
}
/** Flushes the GTT write domain for the object if it's dirty. */
@@ -2665,26 +2820,6 @@ i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj)
old_write_domain);
}
-int
-i915_gem_object_flush_write_domain(struct drm_gem_object *obj)
-{
- int ret = 0;
-
- switch (obj->write_domain) {
- case I915_GEM_DOMAIN_GTT:
- i915_gem_object_flush_gtt_write_domain(obj);
- break;
- case I915_GEM_DOMAIN_CPU:
- i915_gem_object_flush_cpu_write_domain(obj);
- break;
- default:
- ret = i915_gem_object_flush_gpu_write_domain(obj);
- break;
- }
-
- return ret;
-}
-
/**
* Moves a single object to the GTT read, and possibly write domain.
*
@@ -2702,32 +2837,28 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write)
if (obj_priv->gtt_space == NULL)
return -EINVAL;
- ret = i915_gem_object_flush_gpu_write_domain(obj);
+ ret = i915_gem_object_flush_gpu_write_domain(obj, false);
if (ret != 0)
return ret;
- /* Wait on any GPU rendering and flushing to occur. */
- ret = i915_gem_object_wait_rendering(obj);
- if (ret != 0)
- return ret;
+ i915_gem_object_flush_cpu_write_domain(obj);
+
+ if (write) {
+ ret = i915_gem_object_wait_rendering(obj, true);
+ if (ret)
+ return ret;
+ }
old_write_domain = obj->write_domain;
old_read_domains = obj->read_domains;
- /* If we're writing through the GTT domain, then CPU and GPU caches
- * will need to be invalidated at next use.
- */
- if (write)
- obj->read_domains &= I915_GEM_DOMAIN_GTT;
-
- i915_gem_object_flush_cpu_write_domain(obj);
-
/* It should now be out of any other write domains, and we can update
* the domain values for our changes.
*/
BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
obj->read_domains |= I915_GEM_DOMAIN_GTT;
if (write) {
+ obj->read_domains = I915_GEM_DOMAIN_GTT;
obj->write_domain = I915_GEM_DOMAIN_GTT;
obj_priv->dirty = 1;
}
@@ -2744,51 +2875,36 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write)
* wait, as in modesetting process we're not supposed to be interrupted.
*/
int
-i915_gem_object_set_to_display_plane(struct drm_gem_object *obj)
+i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
+ bool pipelined)
{
- struct drm_device *dev = obj->dev;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- uint32_t old_write_domain, old_read_domains;
+ uint32_t old_read_domains;
int ret;
/* Not valid to be called on unbound objects. */
if (obj_priv->gtt_space == NULL)
return -EINVAL;
- ret = i915_gem_object_flush_gpu_write_domain(obj);
+ ret = i915_gem_object_flush_gpu_write_domain(obj, true);
if (ret)
return ret;
- /* Wait on any GPU rendering and flushing to occur. */
- if (obj_priv->active) {
-#if WATCH_BUF
- DRM_INFO("%s: object %p wait for seqno %08x\n",
- __func__, obj, obj_priv->last_rendering_seqno);
-#endif
- ret = i915_do_wait_request(dev,
- obj_priv->last_rendering_seqno,
- 0,
- obj_priv->ring);
- if (ret != 0)
+ /* Currently, we are always called from an non-interruptible context. */
+ if (!pipelined) {
+ ret = i915_gem_object_wait_rendering(obj, false);
+ if (ret)
return ret;
}
i915_gem_object_flush_cpu_write_domain(obj);
- old_write_domain = obj->write_domain;
old_read_domains = obj->read_domains;
-
- /* It should now be out of any other write domains, and we can update
- * the domain values for our changes.
- */
- BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
- obj->read_domains = I915_GEM_DOMAIN_GTT;
- obj->write_domain = I915_GEM_DOMAIN_GTT;
- obj_priv->dirty = 1;
+ obj->read_domains |= I915_GEM_DOMAIN_GTT;
trace_i915_gem_object_change_domain(obj,
old_read_domains,
- old_write_domain);
+ obj->write_domain);
return 0;
}
@@ -2805,12 +2921,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
uint32_t old_write_domain, old_read_domains;
int ret;
- ret = i915_gem_object_flush_gpu_write_domain(obj);
- if (ret)
- return ret;
-
- /* Wait on any GPU rendering and flushing to occur. */
- ret = i915_gem_object_wait_rendering(obj);
+ ret = i915_gem_object_flush_gpu_write_domain(obj, false);
if (ret != 0)
return ret;
@@ -2821,6 +2932,12 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
*/
i915_gem_object_set_to_full_cpu_read_domain(obj);
+ if (write) {
+ ret = i915_gem_object_wait_rendering(obj, true);
+ if (ret)
+ return ret;
+ }
+
old_write_domain = obj->write_domain;
old_read_domains = obj->read_domains;
@@ -2840,7 +2957,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
* need to be invalidated at next use.
*/
if (write) {
- obj->read_domains &= I915_GEM_DOMAIN_CPU;
+ obj->read_domains = I915_GEM_DOMAIN_CPU;
obj->write_domain = I915_GEM_DOMAIN_CPU;
}
@@ -2963,26 +3080,18 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
* drm_agp_chipset_flush
*/
static void
-i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
+i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
+ struct intel_ring_buffer *ring)
{
struct drm_device *dev = obj->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
uint32_t invalidate_domains = 0;
uint32_t flush_domains = 0;
uint32_t old_read_domains;
- BUG_ON(obj->pending_read_domains & I915_GEM_DOMAIN_CPU);
- BUG_ON(obj->pending_write_domain == I915_GEM_DOMAIN_CPU);
-
intel_mark_busy(dev, obj);
-#if WATCH_BUF
- DRM_INFO("%s: object %p read %08x -> %08x write %08x -> %08x\n",
- __func__, obj,
- obj->read_domains, obj->pending_read_domains,
- obj->write_domain, obj->pending_write_domain);
-#endif
/*
* If the object isn't moving to a new write domain,
* let the object stay in multiple read domains
@@ -3009,13 +3118,8 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
* stale data. That is, any new read domains.
*/
invalidate_domains |= obj->pending_read_domains & ~obj->read_domains;
- if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) {
-#if WATCH_BUF
- DRM_INFO("%s: CPU domain flush %08x invalidate %08x\n",
- __func__, flush_domains, invalidate_domains);
-#endif
+ if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU)
i915_gem_clflush_object(obj);
- }
old_read_domains = obj->read_domains;
@@ -3029,21 +3133,12 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
obj->pending_write_domain = obj->write_domain;
obj->read_domains = obj->pending_read_domains;
- if (flush_domains & I915_GEM_GPU_DOMAINS) {
- if (obj_priv->ring == &dev_priv->render_ring)
- dev_priv->flush_rings |= FLUSH_RENDER_RING;
- else if (obj_priv->ring == &dev_priv->bsd_ring)
- dev_priv->flush_rings |= FLUSH_BSD_RING;
- }
-
dev->invalidate_domains |= invalidate_domains;
dev->flush_domains |= flush_domains;
-#if WATCH_BUF
- DRM_INFO("%s: read %08x write %08x invalidate %08x flush %08x\n",
- __func__,
- obj->read_domains, obj->write_domain,
- dev->invalidate_domains, dev->flush_domains);
-#endif
+ if (flush_domains & I915_GEM_GPU_DOMAINS)
+ dev_priv->mm.flush_rings |= obj_priv->ring->id;
+ if (invalidate_domains & I915_GEM_GPU_DOMAINS)
+ dev_priv->mm.flush_rings |= ring->id;
trace_i915_gem_object_change_domain(obj,
old_read_domains,
@@ -3106,12 +3201,7 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj,
if (offset == 0 && size == obj->size)
return i915_gem_object_set_to_cpu_domain(obj, 0);
- ret = i915_gem_object_flush_gpu_write_domain(obj);
- if (ret)
- return ret;
-
- /* Wait on any GPU rendering and flushing to occur. */
- ret = i915_gem_object_wait_rendering(obj);
+ ret = i915_gem_object_flush_gpu_write_domain(obj, false);
if (ret != 0)
return ret;
i915_gem_object_flush_gtt_write_domain(obj);
@@ -3164,66 +3254,42 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj,
* Pin an object to the GTT and evaluate the relocations landing in it.
*/
static int
-i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
- struct drm_file *file_priv,
- struct drm_i915_gem_exec_object2 *entry,
- struct drm_i915_gem_relocation_entry *relocs)
+i915_gem_execbuffer_relocate(struct drm_i915_gem_object *obj,
+ struct drm_file *file_priv,
+ struct drm_i915_gem_exec_object2 *entry)
{
- struct drm_device *dev = obj->dev;
+ struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- int i, ret;
- void __iomem *reloc_page;
- bool need_fence;
-
- need_fence = entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
- obj_priv->tiling_mode != I915_TILING_NONE;
-
- /* Check fence reg constraints and rebind if necessary */
- if (need_fence &&
- !i915_gem_object_fence_offset_ok(obj,
- obj_priv->tiling_mode)) {
- ret = i915_gem_object_unbind(obj);
- if (ret)
- return ret;
- }
+ struct drm_i915_gem_relocation_entry __user *user_relocs;
+ struct drm_gem_object *target_obj = NULL;
+ uint32_t target_handle = 0;
+ int i, ret = 0;
- /* Choose the GTT offset for our buffer and put it there. */
- ret = i915_gem_object_pin(obj, (uint32_t) entry->alignment);
- if (ret)
- return ret;
+ user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr;
+ for (i = 0; i < entry->relocation_count; i++) {
+ struct drm_i915_gem_relocation_entry reloc;
+ uint32_t target_offset;
- /*
- * Pre-965 chips need a fence register set up in order to
- * properly handle blits to/from tiled surfaces.
- */
- if (need_fence) {
- ret = i915_gem_object_get_fence_reg(obj);
- if (ret != 0) {
- i915_gem_object_unpin(obj);
- return ret;
+ if (__copy_from_user_inatomic(&reloc,
+ user_relocs+i,
+ sizeof(reloc))) {
+ ret = -EFAULT;
+ break;
}
- }
- entry->offset = obj_priv->gtt_offset;
+ if (reloc.target_handle != target_handle) {
+ drm_gem_object_unreference(target_obj);
- /* Apply the relocations, using the GTT aperture to avoid cache
- * flushing requirements.
- */
- for (i = 0; i < entry->relocation_count; i++) {
- struct drm_i915_gem_relocation_entry *reloc= &relocs[i];
- struct drm_gem_object *target_obj;
- struct drm_i915_gem_object *target_obj_priv;
- uint32_t reloc_val, reloc_offset;
- uint32_t __iomem *reloc_entry;
-
- target_obj = drm_gem_object_lookup(obj->dev, file_priv,
- reloc->target_handle);
- if (target_obj == NULL) {
- i915_gem_object_unpin(obj);
- return -ENOENT;
+ target_obj = drm_gem_object_lookup(dev, file_priv,
+ reloc.target_handle);
+ if (target_obj == NULL) {
+ ret = -ENOENT;
+ break;
+ }
+
+ target_handle = reloc.target_handle;
}
- target_obj_priv = to_intel_bo(target_obj);
+ target_offset = to_intel_bo(target_obj)->gtt_offset;
#if WATCH_RELOC
DRM_INFO("%s: obj %p offset %08x target %d "
@@ -3231,268 +3297,266 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
"presumed %08x delta %08x\n",
__func__,
obj,
- (int) reloc->offset,
- (int) reloc->target_handle,
- (int) reloc->read_domains,
- (int) reloc->write_domain,
- (int) target_obj_priv->gtt_offset,
- (int) reloc->presumed_offset,
- reloc->delta);
+ (int) reloc.offset,
+ (int) reloc.target_handle,
+ (int) reloc.read_domains,
+ (int) reloc.write_domain,
+ (int) target_offset,
+ (int) reloc.presumed_offset,
+ reloc.delta);
#endif
/* The target buffer should have appeared before us in the
* exec_object list, so it should have a GTT space bound by now.
*/
- if (target_obj_priv->gtt_space == NULL) {
+ if (target_offset == 0) {
DRM_ERROR("No GTT space found for object %d\n",
- reloc->target_handle);
- drm_gem_object_unreference(target_obj);
- i915_gem_object_unpin(obj);
- return -EINVAL;
+ reloc.target_handle);
+ ret = -EINVAL;
+ break;
}
/* Validate that the target is in a valid r/w GPU domain */
- if (reloc->write_domain & (reloc->write_domain - 1)) {
+ if (reloc.write_domain & (reloc.write_domain - 1)) {
DRM_ERROR("reloc with multiple write domains: "
"obj %p target %d offset %d "
"read %08x write %08x",
- obj, reloc->target_handle,
- (int) reloc->offset,
- reloc->read_domains,
- reloc->write_domain);
- drm_gem_object_unreference(target_obj);
- i915_gem_object_unpin(obj);
- return -EINVAL;
+ obj, reloc.target_handle,
+ (int) reloc.offset,
+ reloc.read_domains,
+ reloc.write_domain);
+ ret = -EINVAL;
+ break;
}
- if (reloc->write_domain & I915_GEM_DOMAIN_CPU ||
- reloc->read_domains & I915_GEM_DOMAIN_CPU) {
+ if (reloc.write_domain & I915_GEM_DOMAIN_CPU ||
+ reloc.read_domains & I915_GEM_DOMAIN_CPU) {
DRM_ERROR("reloc with read/write CPU domains: "
"obj %p target %d offset %d "
"read %08x write %08x",
- obj, reloc->target_handle,
- (int) reloc->offset,
- reloc->read_domains,
- reloc->write_domain);
- drm_gem_object_unreference(target_obj);
- i915_gem_object_unpin(obj);
- return -EINVAL;
+ obj, reloc.target_handle,
+ (int) reloc.offset,
+ reloc.read_domains,
+ reloc.write_domain);
+ ret = -EINVAL;
+ break;
}
- if (reloc->write_domain && target_obj->pending_write_domain &&
- reloc->write_domain != target_obj->pending_write_domain) {
+ if (reloc.write_domain && target_obj->pending_write_domain &&
+ reloc.write_domain != target_obj->pending_write_domain) {
DRM_ERROR("Write domain conflict: "
"obj %p target %d offset %d "
"new %08x old %08x\n",
- obj, reloc->target_handle,
- (int) reloc->offset,
- reloc->write_domain,
+ obj, reloc.target_handle,
+ (int) reloc.offset,
+ reloc.write_domain,
target_obj->pending_write_domain);
- drm_gem_object_unreference(target_obj);
- i915_gem_object_unpin(obj);
- return -EINVAL;
+ ret = -EINVAL;
+ break;
}
- target_obj->pending_read_domains |= reloc->read_domains;
- target_obj->pending_write_domain |= reloc->write_domain;
+ target_obj->pending_read_domains |= reloc.read_domains;
+ target_obj->pending_write_domain |= reloc.write_domain;
/* If the relocation already has the right value in it, no
* more work needs to be done.
*/
- if (target_obj_priv->gtt_offset == reloc->presumed_offset) {
- drm_gem_object_unreference(target_obj);
+ if (target_offset == reloc.presumed_offset)
continue;
- }
/* Check that the relocation address is valid... */
- if (reloc->offset > obj->size - 4) {
+ if (reloc.offset > obj->base.size - 4) {
DRM_ERROR("Relocation beyond object bounds: "
"obj %p target %d offset %d size %d.\n",
- obj, reloc->target_handle,
- (int) reloc->offset, (int) obj->size);
- drm_gem_object_unreference(target_obj);
- i915_gem_object_unpin(obj);
- return -EINVAL;
+ obj, reloc.target_handle,
+ (int) reloc.offset, (int) obj->base.size);
+ ret = -EINVAL;
+ break;
}
- if (reloc->offset & 3) {
+ if (reloc.offset & 3) {
DRM_ERROR("Relocation not 4-byte aligned: "
"obj %p target %d offset %d.\n",
- obj, reloc->target_handle,
- (int) reloc->offset);
- drm_gem_object_unreference(target_obj);
- i915_gem_object_unpin(obj);
- return -EINVAL;
+ obj, reloc.target_handle,
+ (int) reloc.offset);
+ ret = -EINVAL;
+ break;
}
/* and points to somewhere within the target object. */
- if (reloc->delta >= target_obj->size) {
+ if (reloc.delta >= target_obj->size) {
DRM_ERROR("Relocation beyond target object bounds: "
"obj %p target %d delta %d size %d.\n",
- obj, reloc->target_handle,
- (int) reloc->delta, (int) target_obj->size);
- drm_gem_object_unreference(target_obj);
- i915_gem_object_unpin(obj);
- return -EINVAL;
- }
-
- ret = i915_gem_object_set_to_gtt_domain(obj, 1);
- if (ret != 0) {
- drm_gem_object_unreference(target_obj);
- i915_gem_object_unpin(obj);
- return -EINVAL;
+ obj, reloc.target_handle,
+ (int) reloc.delta, (int) target_obj->size);
+ ret = -EINVAL;
+ break;
}
- /* Map the page containing the relocation we're going to
- * perform.
- */
- reloc_offset = obj_priv->gtt_offset + reloc->offset;
- reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
- (reloc_offset &
- ~(PAGE_SIZE - 1)),
- KM_USER0);
- reloc_entry = (uint32_t __iomem *)(reloc_page +
- (reloc_offset & (PAGE_SIZE - 1)));
- reloc_val = target_obj_priv->gtt_offset + reloc->delta;
-
-#if WATCH_BUF
- DRM_INFO("Applied relocation: %p@0x%08x %08x -> %08x\n",
- obj, (unsigned int) reloc->offset,
- readl(reloc_entry), reloc_val);
-#endif
- writel(reloc_val, reloc_entry);
- io_mapping_unmap_atomic(reloc_page, KM_USER0);
-
- /* The updated presumed offset for this entry will be
- * copied back out to the user.
- */
- reloc->presumed_offset = target_obj_priv->gtt_offset;
-
- drm_gem_object_unreference(target_obj);
- }
-
-#if WATCH_BUF
- if (0)
- i915_gem_dump_object(obj, 128, __func__, ~0);
-#endif
- return 0;
-}
+ reloc.delta += target_offset;
+ if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) {
+ uint32_t page_offset = reloc.offset & ~PAGE_MASK;
+ char *vaddr;
-/* Throttle our rendering by waiting until the ring has completed our requests
- * emitted over 20 msec ago.
- *
- * Note that if we were to use the current jiffies each time around the loop,
- * we wouldn't escape the function with any frames outstanding if the time to
- * render a frame was over 20ms.
- *
- * This should get us reasonable parallelism between CPU and GPU but also
- * relatively low latency when blocking on a particular request to finish.
- */
-static int
-i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv)
-{
- struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
- int ret = 0;
- unsigned long recent_enough = jiffies - msecs_to_jiffies(20);
-
- mutex_lock(&dev->struct_mutex);
- while (!list_empty(&i915_file_priv->mm.request_list)) {
- struct drm_i915_gem_request *request;
+ vaddr = kmap_atomic(obj->pages[reloc.offset >> PAGE_SHIFT]);
+ *(uint32_t *)(vaddr + page_offset) = reloc.delta;
+ kunmap_atomic(vaddr);
+ } else {
+ uint32_t __iomem *reloc_entry;
+ void __iomem *reloc_page;
- request = list_first_entry(&i915_file_priv->mm.request_list,
- struct drm_i915_gem_request,
- client_list);
+ ret = i915_gem_object_set_to_gtt_domain(&obj->base, 1);
+ if (ret)
+ break;
- if (time_after_eq(request->emitted_jiffies, recent_enough))
- break;
+ /* Map the page containing the relocation we're going to perform. */
+ reloc.offset += obj->gtt_offset;
+ reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
+ reloc.offset & PAGE_MASK);
+ reloc_entry = (uint32_t __iomem *)
+ (reloc_page + (reloc.offset & ~PAGE_MASK));
+ iowrite32(reloc.delta, reloc_entry);
+ io_mapping_unmap_atomic(reloc_page);
+ }
- ret = i915_wait_request(dev, request->seqno, request->ring);
- if (ret != 0)
- break;
+ /* and update the user's relocation entry */
+ reloc.presumed_offset = target_offset;
+ if (__copy_to_user_inatomic(&user_relocs[i].presumed_offset,
+ &reloc.presumed_offset,
+ sizeof(reloc.presumed_offset))) {
+ ret = -EFAULT;
+ break;
+ }
}
- mutex_unlock(&dev->struct_mutex);
+ drm_gem_object_unreference(target_obj);
return ret;
}
static int
-i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object2 *exec_list,
- uint32_t buffer_count,
- struct drm_i915_gem_relocation_entry **relocs)
+i915_gem_execbuffer_pin(struct drm_device *dev,
+ struct drm_file *file,
+ struct drm_gem_object **object_list,
+ struct drm_i915_gem_exec_object2 *exec_list,
+ int count)
{
- uint32_t reloc_count = 0, reloc_index = 0, i;
- int ret;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret, i, retry;
- *relocs = NULL;
- for (i = 0; i < buffer_count; i++) {
- if (reloc_count + exec_list[i].relocation_count < reloc_count)
- return -EINVAL;
- reloc_count += exec_list[i].relocation_count;
- }
+ /* attempt to pin all of the buffers into the GTT */
+ for (retry = 0; retry < 2; retry++) {
+ ret = 0;
+ for (i = 0; i < count; i++) {
+ struct drm_i915_gem_exec_object2 *entry = &exec_list[i];
+ struct drm_i915_gem_object *obj= to_intel_bo(object_list[i]);
+ bool need_fence =
+ entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
+ obj->tiling_mode != I915_TILING_NONE;
+
+ /* Check fence reg constraints and rebind if necessary */
+ if (need_fence &&
+ !i915_gem_object_fence_offset_ok(&obj->base,
+ obj->tiling_mode)) {
+ ret = i915_gem_object_unbind(&obj->base);
+ if (ret)
+ break;
+ }
- *relocs = drm_calloc_large(reloc_count, sizeof(**relocs));
- if (*relocs == NULL) {
- DRM_ERROR("failed to alloc relocs, count %d\n", reloc_count);
- return -ENOMEM;
- }
+ ret = i915_gem_object_pin(&obj->base, entry->alignment);
+ if (ret)
+ break;
- for (i = 0; i < buffer_count; i++) {
- struct drm_i915_gem_relocation_entry __user *user_relocs;
+ /*
+ * Pre-965 chips need a fence register set up in order
+ * to properly handle blits to/from tiled surfaces.
+ */
+ if (need_fence) {
+ ret = i915_gem_object_get_fence_reg(&obj->base, true);
+ if (ret) {
+ i915_gem_object_unpin(&obj->base);
+ break;
+ }
- user_relocs = (void __user *)(uintptr_t)exec_list[i].relocs_ptr;
+ dev_priv->fence_regs[obj->fence_reg].gpu = true;
+ }
- ret = copy_from_user(&(*relocs)[reloc_index],
- user_relocs,
- exec_list[i].relocation_count *
- sizeof(**relocs));
- if (ret != 0) {
- drm_free_large(*relocs);
- *relocs = NULL;
- return -EFAULT;
+ entry->offset = obj->gtt_offset;
}
- reloc_index += exec_list[i].relocation_count;
+ while (i--)
+ i915_gem_object_unpin(object_list[i]);
+
+ if (ret == 0)
+ break;
+
+ if (ret != -ENOSPC || retry)
+ return ret;
+
+ ret = i915_gem_evict_everything(dev);
+ if (ret)
+ return ret;
}
return 0;
}
+/* Throttle our rendering by waiting until the ring has completed our requests
+ * emitted over 20 msec ago.
+ *
+ * Note that if we were to use the current jiffies each time around the loop,
+ * we wouldn't escape the function with any frames outstanding if the time to
+ * render a frame was over 20ms.
+ *
+ * This should get us reasonable parallelism between CPU and GPU but also
+ * relatively low latency when blocking on a particular request to finish.
+ */
static int
-i915_gem_put_relocs_to_user(struct drm_i915_gem_exec_object2 *exec_list,
- uint32_t buffer_count,
- struct drm_i915_gem_relocation_entry *relocs)
+i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
{
- uint32_t reloc_count = 0, i;
- int ret = 0;
-
- if (relocs == NULL)
- return 0;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_file_private *file_priv = file->driver_priv;
+ unsigned long recent_enough = jiffies - msecs_to_jiffies(20);
+ struct drm_i915_gem_request *request;
+ struct intel_ring_buffer *ring = NULL;
+ u32 seqno = 0;
+ int ret;
- for (i = 0; i < buffer_count; i++) {
- struct drm_i915_gem_relocation_entry __user *user_relocs;
- int unwritten;
+ spin_lock(&file_priv->mm.lock);
+ list_for_each_entry(request, &file_priv->mm.request_list, client_list) {
+ if (time_after_eq(request->emitted_jiffies, recent_enough))
+ break;
- user_relocs = (void __user *)(uintptr_t)exec_list[i].relocs_ptr;
+ ring = request->ring;
+ seqno = request->seqno;
+ }
+ spin_unlock(&file_priv->mm.lock);
- unwritten = copy_to_user(user_relocs,
- &relocs[reloc_count],
- exec_list[i].relocation_count *
- sizeof(*relocs));
+ if (seqno == 0)
+ return 0;
- if (unwritten) {
- ret = -EFAULT;
- goto err;
- }
+ ret = 0;
+ if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) {
+ /* And wait for the seqno passing without holding any locks and
+ * causing extra latency for others. This is safe as the irq
+ * generation is designed to be run atomically and so is
+ * lockless.
+ */
+ ring->user_irq_get(dev, ring);
+ ret = wait_event_interruptible(ring->irq_queue,
+ i915_seqno_passed(ring->get_seqno(dev, ring), seqno)
+ || atomic_read(&dev_priv->mm.wedged));
+ ring->user_irq_put(dev, ring);
- reloc_count += exec_list[i].relocation_count;
+ if (ret == 0 && atomic_read(&dev_priv->mm.wedged))
+ ret = -EIO;
}
-err:
- drm_free_large(relocs);
+ if (ret == 0)
+ queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
return ret;
}
static int
-i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer2 *exec,
- uint64_t exec_offset)
+i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec,
+ uint64_t exec_offset)
{
uint32_t exec_start, exec_len;
@@ -3509,44 +3573,32 @@ i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer2 *exec,
}
static int
-i915_gem_wait_for_pending_flip(struct drm_device *dev,
- struct drm_gem_object **object_list,
- int count)
+validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
+ int count)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv;
- DEFINE_WAIT(wait);
- int i, ret = 0;
+ int i;
- for (;;) {
- prepare_to_wait(&dev_priv->pending_flip_queue,
- &wait, TASK_INTERRUPTIBLE);
- for (i = 0; i < count; i++) {
- obj_priv = to_intel_bo(object_list[i]);
- if (atomic_read(&obj_priv->pending_flip) > 0)
- break;
- }
- if (i == count)
- break;
+ for (i = 0; i < count; i++) {
+ char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr;
+ size_t length = exec[i].relocation_count * sizeof(struct drm_i915_gem_relocation_entry);
- if (!signal_pending(current)) {
- mutex_unlock(&dev->struct_mutex);
- schedule();
- mutex_lock(&dev->struct_mutex);
- continue;
- }
- ret = -ERESTARTSYS;
- break;
+ if (!access_ok(VERIFY_READ, ptr, length))
+ return -EFAULT;
+
+ /* we may also need to update the presumed offsets */
+ if (!access_ok(VERIFY_WRITE, ptr, length))
+ return -EFAULT;
+
+ if (fault_in_pages_readable(ptr, length))
+ return -EFAULT;
}
- finish_wait(&dev_priv->pending_flip_queue, &wait);
- return ret;
+ return 0;
}
-
-int
+static int
i915_gem_do_execbuffer(struct drm_device *dev, void *data,
- struct drm_file *file_priv,
+ struct drm_file *file,
struct drm_i915_gem_execbuffer2 *args,
struct drm_i915_gem_exec_object2 *exec_list)
{
@@ -3555,26 +3607,47 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
struct drm_gem_object *batch_obj;
struct drm_i915_gem_object *obj_priv;
struct drm_clip_rect *cliprects = NULL;
- struct drm_i915_gem_relocation_entry *relocs = NULL;
- int ret = 0, ret2, i, pinned = 0;
+ struct drm_i915_gem_request *request = NULL;
+ int ret, i, flips;
uint64_t exec_offset;
- uint32_t seqno, flush_domains, reloc_index;
- int pin_tries, flips;
struct intel_ring_buffer *ring = NULL;
+ ret = i915_gem_check_is_wedged(dev);
+ if (ret)
+ return ret;
+
+ ret = validate_exec_list(exec_list, args->buffer_count);
+ if (ret)
+ return ret;
+
#if WATCH_EXEC
DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
(int) args->buffers_ptr, args->buffer_count, args->batch_len);
#endif
- if (args->flags & I915_EXEC_BSD) {
+ switch (args->flags & I915_EXEC_RING_MASK) {
+ case I915_EXEC_DEFAULT:
+ case I915_EXEC_RENDER:
+ ring = &dev_priv->render_ring;
+ break;
+ case I915_EXEC_BSD:
if (!HAS_BSD(dev)) {
- DRM_ERROR("execbuf with wrong flag\n");
+ DRM_ERROR("execbuf with invalid ring (BSD)\n");
return -EINVAL;
}
ring = &dev_priv->bsd_ring;
- } else {
- ring = &dev_priv->render_ring;
+ break;
+ case I915_EXEC_BLT:
+ if (!HAS_BLT(dev)) {
+ DRM_ERROR("execbuf with invalid ring (BLT)\n");
+ return -EINVAL;
+ }
+ ring = &dev_priv->blt_ring;
+ break;
+ default:
+ DRM_ERROR("execbuf with unknown ring: %d\n",
+ (int)(args->flags & I915_EXEC_RING_MASK));
+ return -EINVAL;
}
if (args->buffer_count < 1) {
@@ -3609,20 +3682,15 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
}
}
- ret = i915_gem_get_relocs_from_user(exec_list, args->buffer_count,
- &relocs);
- if (ret != 0)
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL) {
+ ret = -ENOMEM;
goto pre_mutex_err;
+ }
- mutex_lock(&dev->struct_mutex);
-
- i915_verify_inactive(dev, __FILE__, __LINE__);
-
- if (atomic_read(&dev_priv->mm.wedged)) {
- mutex_unlock(&dev->struct_mutex);
- ret = -EIO;
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
goto pre_mutex_err;
- }
if (dev_priv->mm.suspended) {
mutex_unlock(&dev->struct_mutex);
@@ -3631,9 +3699,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
}
/* Look up object handles */
- flips = 0;
for (i = 0; i < args->buffer_count; i++) {
- object_list[i] = drm_gem_object_lookup(dev, file_priv,
+ object_list[i] = drm_gem_object_lookup(dev, file,
exec_list[i].handle);
if (object_list[i] == NULL) {
DRM_ERROR("Invalid object handle %d at index %d\n",
@@ -3654,75 +3721,22 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
goto err;
}
obj_priv->in_execbuffer = true;
- flips += atomic_read(&obj_priv->pending_flip);
}
- if (flips > 0) {
- ret = i915_gem_wait_for_pending_flip(dev, object_list,
- args->buffer_count);
- if (ret)
- goto err;
- }
-
- /* Pin and relocate */
- for (pin_tries = 0; ; pin_tries++) {
- ret = 0;
- reloc_index = 0;
-
- for (i = 0; i < args->buffer_count; i++) {
- object_list[i]->pending_read_domains = 0;
- object_list[i]->pending_write_domain = 0;
- ret = i915_gem_object_pin_and_relocate(object_list[i],
- file_priv,
- &exec_list[i],
- &relocs[reloc_index]);
- if (ret)
- break;
- pinned = i + 1;
- reloc_index += exec_list[i].relocation_count;
- }
- /* success */
- if (ret == 0)
- break;
-
- /* error other than GTT full, or we've already tried again */
- if (ret != -ENOSPC || pin_tries >= 1) {
- if (ret != -ERESTARTSYS) {
- unsigned long long total_size = 0;
- int num_fences = 0;
- for (i = 0; i < args->buffer_count; i++) {
- obj_priv = to_intel_bo(object_list[i]);
-
- total_size += object_list[i]->size;
- num_fences +=
- exec_list[i].flags & EXEC_OBJECT_NEEDS_FENCE &&
- obj_priv->tiling_mode != I915_TILING_NONE;
- }
- DRM_ERROR("Failed to pin buffer %d of %d, total %llu bytes, %d fences: %d\n",
- pinned+1, args->buffer_count,
- total_size, num_fences,
- ret);
- DRM_ERROR("%d objects [%d pinned], "
- "%d object bytes [%d pinned], "
- "%d/%d gtt bytes\n",
- atomic_read(&dev->object_count),
- atomic_read(&dev->pin_count),
- atomic_read(&dev->object_memory),
- atomic_read(&dev->pin_memory),
- atomic_read(&dev->gtt_memory),
- dev->gtt_total);
- }
- goto err;
- }
-
- /* unpin all of our buffers */
- for (i = 0; i < pinned; i++)
- i915_gem_object_unpin(object_list[i]);
- pinned = 0;
+ /* Move the objects en-masse into the GTT, evicting if necessary. */
+ ret = i915_gem_execbuffer_pin(dev, file,
+ object_list, exec_list,
+ args->buffer_count);
+ if (ret)
+ goto err;
- /* evict everyone we can from the aperture */
- ret = i915_gem_evict_everything(dev);
- if (ret && ret != -ENOSPC)
+ /* The objects are in their final locations, apply the relocations. */
+ for (i = 0; i < args->buffer_count; i++) {
+ struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]);
+ obj->base.pending_read_domains = 0;
+ obj->base.pending_write_domain = 0;
+ ret = i915_gem_execbuffer_relocate(obj, file, &exec_list[i]);
+ if (ret)
goto err;
}
@@ -3735,33 +3749,29 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
}
batch_obj->pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
- /* Sanity check the batch buffer, prior to moving objects */
- exec_offset = exec_list[args->buffer_count - 1].offset;
- ret = i915_gem_check_execbuffer (args, exec_offset);
+ /* Sanity check the batch buffer */
+ exec_offset = to_intel_bo(batch_obj)->gtt_offset;
+ ret = i915_gem_check_execbuffer(args, exec_offset);
if (ret != 0) {
DRM_ERROR("execbuf with invalid offset/length\n");
goto err;
}
- i915_verify_inactive(dev, __FILE__, __LINE__);
-
/* Zero the global flush/invalidate flags. These
* will be modified as new domains are computed
* for each object
*/
dev->invalidate_domains = 0;
dev->flush_domains = 0;
- dev_priv->flush_rings = 0;
+ dev_priv->mm.flush_rings = 0;
for (i = 0; i < args->buffer_count; i++) {
struct drm_gem_object *obj = object_list[i];
/* Compute new gpu domains and update invalidate/flush */
- i915_gem_object_set_to_gpu_domain(obj);
+ i915_gem_object_set_to_gpu_domain(obj, ring);
}
- i915_verify_inactive(dev, __FILE__, __LINE__);
-
if (dev->invalidate_domains | dev->flush_domains) {
#if WATCH_EXEC
DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n",
@@ -3769,38 +3779,21 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
dev->invalidate_domains,
dev->flush_domains);
#endif
- i915_gem_flush(dev,
+ i915_gem_flush(dev, file,
dev->invalidate_domains,
- dev->flush_domains);
- if (dev_priv->flush_rings & FLUSH_RENDER_RING)
- (void)i915_add_request(dev, file_priv,
- dev->flush_domains,
- &dev_priv->render_ring);
- if (dev_priv->flush_rings & FLUSH_BSD_RING)
- (void)i915_add_request(dev, file_priv,
- dev->flush_domains,
- &dev_priv->bsd_ring);
+ dev->flush_domains,
+ dev_priv->mm.flush_rings);
}
for (i = 0; i < args->buffer_count; i++) {
struct drm_gem_object *obj = object_list[i];
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
uint32_t old_write_domain = obj->write_domain;
-
obj->write_domain = obj->pending_write_domain;
- if (obj->write_domain)
- list_move_tail(&obj_priv->gpu_write_list,
- &dev_priv->mm.gpu_write_list);
- else
- list_del_init(&obj_priv->gpu_write_list);
-
trace_i915_gem_object_change_domain(obj,
obj->read_domains,
old_write_domain);
}
- i915_verify_inactive(dev, __FILE__, __LINE__);
-
#if WATCH_COHERENCY
for (i = 0; i < args->buffer_count; i++) {
i915_gem_object_check_coherency(object_list[i],
@@ -3815,9 +3808,38 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
~0);
#endif
+ /* Check for any pending flips. As we only maintain a flip queue depth
+ * of 1, we can simply insert a WAIT for the next display flip prior
+ * to executing the batch and avoid stalling the CPU.
+ */
+ flips = 0;
+ for (i = 0; i < args->buffer_count; i++) {
+ if (object_list[i]->write_domain)
+ flips |= atomic_read(&to_intel_bo(object_list[i])->pending_flip);
+ }
+ if (flips) {
+ int plane, flip_mask;
+
+ for (plane = 0; flips >> plane; plane++) {
+ if (((flips >> plane) & 1) == 0)
+ continue;
+
+ if (plane)
+ flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
+ else
+ flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
+
+ intel_ring_begin(dev, ring, 2);
+ intel_ring_emit(dev, ring,
+ MI_WAIT_FOR_EVENT | flip_mask);
+ intel_ring_emit(dev, ring, MI_NOOP);
+ intel_ring_advance(dev, ring);
+ }
+ }
+
/* Exec the batchbuffer */
ret = ring->dispatch_gem_execbuffer(dev, ring, args,
- cliprects, exec_offset);
+ cliprects, exec_offset);
if (ret) {
DRM_ERROR("dispatch failed %d\n", ret);
goto err;
@@ -3827,38 +3849,21 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
* Ensure that the commands in the batch buffer are
* finished before the interrupt fires
*/
- flush_domains = i915_retire_commands(dev, ring);
-
- i915_verify_inactive(dev, __FILE__, __LINE__);
+ i915_retire_commands(dev, ring);
- /*
- * Get a seqno representing the execution of the current buffer,
- * which we can wait on. We would like to mitigate these interrupts,
- * likely by only creating seqnos occasionally (so that we have
- * *some* interrupts representing completion of buffers that we can
- * wait on when trying to clear up gtt space).
- */
- seqno = i915_add_request(dev, file_priv, flush_domains, ring);
- BUG_ON(seqno == 0);
for (i = 0; i < args->buffer_count; i++) {
struct drm_gem_object *obj = object_list[i];
- obj_priv = to_intel_bo(obj);
- i915_gem_object_move_to_active(obj, seqno, ring);
-#if WATCH_LRU
- DRM_INFO("%s: move to exec list %p\n", __func__, obj);
-#endif
+ i915_gem_object_move_to_active(obj, ring);
+ if (obj->write_domain)
+ list_move_tail(&to_intel_bo(obj)->gpu_write_list,
+ &ring->gpu_write_list);
}
-#if WATCH_LRU
- i915_dump_lru(dev, __func__);
-#endif
- i915_verify_inactive(dev, __FILE__, __LINE__);
+ i915_add_request(dev, file, request, ring);
+ request = NULL;
err:
- for (i = 0; i < pinned; i++)
- i915_gem_object_unpin(object_list[i]);
-
for (i = 0; i < args->buffer_count; i++) {
if (object_list[i]) {
obj_priv = to_intel_bo(object_list[i]);
@@ -3870,22 +3875,9 @@ err:
mutex_unlock(&dev->struct_mutex);
pre_mutex_err:
- /* Copy the updated relocations out regardless of current error
- * state. Failure to update the relocs would mean that the next
- * time userland calls execbuf, it would do so with presumed offset
- * state that didn't match the actual object state.
- */
- ret2 = i915_gem_put_relocs_to_user(exec_list, args->buffer_count,
- relocs);
- if (ret2 != 0) {
- DRM_ERROR("Failed to copy relocations back out: %d\n", ret2);
-
- if (ret == 0)
- ret = ret2;
- }
-
drm_free_large(object_list);
kfree(cliprects);
+ kfree(request);
return ret;
}
@@ -3942,7 +3934,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
exec2_list[i].relocs_ptr = exec_list[i].relocs_ptr;
exec2_list[i].alignment = exec_list[i].alignment;
exec2_list[i].offset = exec_list[i].offset;
- if (!IS_I965G(dev))
+ if (INTEL_INFO(dev)->gen < 4)
exec2_list[i].flags = EXEC_OBJECT_NEEDS_FENCE;
else
exec2_list[i].flags = 0;
@@ -4039,12 +4031,12 @@ int
i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
{
struct drm_device *dev = obj->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int ret;
BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT);
-
- i915_verify_inactive(dev, __FILE__, __LINE__);
+ WARN_ON(i915_verify_lists(dev));
if (obj_priv->gtt_space != NULL) {
if (alignment == 0)
@@ -4072,14 +4064,13 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
* remove it from the inactive list
*/
if (obj_priv->pin_count == 1) {
- atomic_inc(&dev->pin_count);
- atomic_add(obj->size, &dev->pin_memory);
- if (!obj_priv->active &&
- (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
- list_del_init(&obj_priv->list);
+ i915_gem_info_add_pin(dev_priv, obj->size);
+ if (!obj_priv->active)
+ list_move_tail(&obj_priv->mm_list,
+ &dev_priv->mm.pinned_list);
}
- i915_verify_inactive(dev, __FILE__, __LINE__);
+ WARN_ON(i915_verify_lists(dev));
return 0;
}
@@ -4090,7 +4081,7 @@ i915_gem_object_unpin(struct drm_gem_object *obj)
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- i915_verify_inactive(dev, __FILE__, __LINE__);
+ WARN_ON(i915_verify_lists(dev));
obj_priv->pin_count--;
BUG_ON(obj_priv->pin_count < 0);
BUG_ON(obj_priv->gtt_space == NULL);
@@ -4100,14 +4091,12 @@ i915_gem_object_unpin(struct drm_gem_object *obj)
* the inactive list
*/
if (obj_priv->pin_count == 0) {
- if (!obj_priv->active &&
- (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
- list_move_tail(&obj_priv->list,
+ if (!obj_priv->active)
+ list_move_tail(&obj_priv->mm_list,
&dev_priv->mm.inactive_list);
- atomic_dec(&dev->pin_count);
- atomic_sub(obj->size, &dev->pin_memory);
+ i915_gem_info_remove_pin(dev_priv, obj->size);
}
- i915_verify_inactive(dev, __FILE__, __LINE__);
+ WARN_ON(i915_verify_lists(dev));
}
int
@@ -4119,41 +4108,36 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
struct drm_i915_gem_object *obj_priv;
int ret;
- mutex_lock(&dev->struct_mutex);
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return ret;
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL) {
- DRM_ERROR("Bad handle in i915_gem_pin_ioctl(): %d\n",
- args->handle);
- mutex_unlock(&dev->struct_mutex);
- return -ENOENT;
+ ret = -ENOENT;
+ goto unlock;
}
obj_priv = to_intel_bo(obj);
if (obj_priv->madv != I915_MADV_WILLNEED) {
DRM_ERROR("Attempting to pin a purgeable buffer\n");
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (obj_priv->pin_filp != NULL && obj_priv->pin_filp != file_priv) {
DRM_ERROR("Already pinned in i915_gem_pin_ioctl(): %d\n",
args->handle);
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
obj_priv->user_pin_count++;
obj_priv->pin_filp = file_priv;
if (obj_priv->user_pin_count == 1) {
ret = i915_gem_object_pin(obj, args->alignment);
- if (ret != 0) {
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
- return ret;
- }
+ if (ret)
+ goto out;
}
/* XXX - flush the CPU caches for pinned objects
@@ -4161,10 +4145,11 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
*/
i915_gem_object_flush_cpu_write_domain(obj);
args->offset = obj_priv->gtt_offset;
+out:
drm_gem_object_unreference(obj);
+unlock:
mutex_unlock(&dev->struct_mutex);
-
- return 0;
+ return ret;
}
int
@@ -4174,24 +4159,24 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
struct drm_i915_gem_pin *args = data;
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
+ int ret;
- mutex_lock(&dev->struct_mutex);
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return ret;
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL) {
- DRM_ERROR("Bad handle in i915_gem_unpin_ioctl(): %d\n",
- args->handle);
- mutex_unlock(&dev->struct_mutex);
- return -ENOENT;
+ ret = -ENOENT;
+ goto unlock;
}
-
obj_priv = to_intel_bo(obj);
+
if (obj_priv->pin_filp != file_priv) {
DRM_ERROR("Not pinned by caller in i915_gem_pin_ioctl(): %d\n",
args->handle);
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
obj_priv->user_pin_count--;
if (obj_priv->user_pin_count == 0) {
@@ -4199,9 +4184,11 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
i915_gem_object_unpin(obj);
}
+out:
drm_gem_object_unreference(obj);
+unlock:
mutex_unlock(&dev->struct_mutex);
- return 0;
+ return ret;
}
int
@@ -4211,22 +4198,24 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
struct drm_i915_gem_busy *args = data;
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
+ int ret;
+
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return ret;
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL) {
- DRM_ERROR("Bad handle in i915_gem_busy_ioctl(): %d\n",
- args->handle);
- return -ENOENT;
+ ret = -ENOENT;
+ goto unlock;
}
-
- mutex_lock(&dev->struct_mutex);
+ obj_priv = to_intel_bo(obj);
/* Count all active objects as busy, even if they are currently not used
* by the gpu. Users of this interface expect objects to eventually
* become non-busy without any further actions, therefore emit any
* necessary flushes here.
*/
- obj_priv = to_intel_bo(obj);
args->busy = obj_priv->active;
if (args->busy) {
/* Unconditionally flush objects, even when the gpu still uses this
@@ -4234,10 +4223,10 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
* use this buffer rather sooner than later, so issuing the required
* flush earlier is beneficial.
*/
- if (obj->write_domain) {
- i915_gem_flush(dev, 0, obj->write_domain);
- (void)i915_add_request(dev, file_priv, obj->write_domain, obj_priv->ring);
- }
+ if (obj->write_domain & I915_GEM_GPU_DOMAINS)
+ i915_gem_flush_ring(dev, file_priv,
+ obj_priv->ring,
+ 0, obj->write_domain);
/* Update the active list for the hardware's current position.
* Otherwise this only updates on a delayed timer or when irqs
@@ -4250,8 +4239,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
}
drm_gem_object_unreference(obj);
+unlock:
mutex_unlock(&dev->struct_mutex);
- return 0;
+ return ret;
}
int
@@ -4268,6 +4258,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
struct drm_i915_gem_madvise *args = data;
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
+ int ret;
switch (args->madv) {
case I915_MADV_DONTNEED:
@@ -4277,22 +4268,20 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
}
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return ret;
+
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL) {
- DRM_ERROR("Bad handle in i915_gem_madvise_ioctl(): %d\n",
- args->handle);
- return -ENOENT;
+ ret = -ENOENT;
+ goto unlock;
}
-
- mutex_lock(&dev->struct_mutex);
obj_priv = to_intel_bo(obj);
if (obj_priv->pin_count) {
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
-
- DRM_ERROR("Attempted i915_gem_madvise_ioctl() on a pinned object\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (obj_priv->madv != __I915_MADV_PURGED)
@@ -4305,15 +4294,17 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
args->retained = obj_priv->madv != __I915_MADV_PURGED;
+out:
drm_gem_object_unreference(obj);
+unlock:
mutex_unlock(&dev->struct_mutex);
-
- return 0;
+ return ret;
}
struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev,
size_t size)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj;
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
@@ -4325,18 +4316,19 @@ struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev,
return NULL;
}
+ i915_gem_info_add_obj(dev_priv, size);
+
obj->base.write_domain = I915_GEM_DOMAIN_CPU;
obj->base.read_domains = I915_GEM_DOMAIN_CPU;
obj->agp_type = AGP_USER_MEMORY;
obj->base.driver_private = NULL;
obj->fence_reg = I915_FENCE_REG_NONE;
- INIT_LIST_HEAD(&obj->list);
+ INIT_LIST_HEAD(&obj->mm_list);
+ INIT_LIST_HEAD(&obj->ring_list);
INIT_LIST_HEAD(&obj->gpu_write_list);
obj->madv = I915_MADV_WILLNEED;
- trace_i915_gem_object_create(&obj->base);
-
return &obj->base;
}
@@ -4356,7 +4348,7 @@ static void i915_gem_free_object_tail(struct drm_gem_object *obj)
ret = i915_gem_object_unbind(obj);
if (ret == -ERESTARTSYS) {
- list_move(&obj_priv->list,
+ list_move(&obj_priv->mm_list,
&dev_priv->mm.deferred_free_list);
return;
}
@@ -4365,6 +4357,7 @@ static void i915_gem_free_object_tail(struct drm_gem_object *obj)
i915_gem_free_mmap_offset(obj);
drm_gem_object_release(obj);
+ i915_gem_info_remove_obj(dev_priv, obj->size);
kfree(obj_priv->page_cpu_valid);
kfree(obj_priv->bit_17);
@@ -4395,10 +4388,7 @@ i915_gem_idle(struct drm_device *dev)
mutex_lock(&dev->struct_mutex);
- if (dev_priv->mm.suspended ||
- (dev_priv->render_ring.gem_object == NULL) ||
- (HAS_BSD(dev) &&
- dev_priv->bsd_ring.gem_object == NULL)) {
+ if (dev_priv->mm.suspended) {
mutex_unlock(&dev->struct_mutex);
return 0;
}
@@ -4423,7 +4413,7 @@ i915_gem_idle(struct drm_device *dev)
* And not confound mm.suspended!
*/
dev_priv->mm.suspended = 1;
- del_timer(&dev_priv->hangcheck_timer);
+ del_timer_sync(&dev_priv->hangcheck_timer);
i915_kernel_lost_context(dev);
i915_gem_cleanup_ringbuffer(dev);
@@ -4503,36 +4493,34 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
- dev_priv->render_ring = render_ring;
-
- if (!I915_NEED_GFX_HWS(dev)) {
- dev_priv->render_ring.status_page.page_addr
- = dev_priv->status_page_dmah->vaddr;
- memset(dev_priv->render_ring.status_page.page_addr,
- 0, PAGE_SIZE);
- }
-
if (HAS_PIPE_CONTROL(dev)) {
ret = i915_gem_init_pipe_control(dev);
if (ret)
return ret;
}
- ret = intel_init_ring_buffer(dev, &dev_priv->render_ring);
+ ret = intel_init_render_ring_buffer(dev);
if (ret)
goto cleanup_pipe_control;
if (HAS_BSD(dev)) {
- dev_priv->bsd_ring = bsd_ring;
- ret = intel_init_ring_buffer(dev, &dev_priv->bsd_ring);
+ ret = intel_init_bsd_ring_buffer(dev);
if (ret)
goto cleanup_render_ring;
}
+ if (HAS_BLT(dev)) {
+ ret = intel_init_blt_ring_buffer(dev);
+ if (ret)
+ goto cleanup_bsd_ring;
+ }
+
dev_priv->next_seqno = 1;
return 0;
+cleanup_bsd_ring:
+ intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
cleanup_render_ring:
intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
cleanup_pipe_control:
@@ -4547,8 +4535,8 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
- if (HAS_BSD(dev))
- intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
+ intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
+ intel_cleanup_ring_buffer(dev, &dev_priv->blt_ring);
if (HAS_PIPE_CONTROL(dev))
i915_gem_cleanup_pipe_control(dev);
}
@@ -4577,15 +4565,15 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
return ret;
}
- spin_lock(&dev_priv->mm.active_list_lock);
+ BUG_ON(!list_empty(&dev_priv->mm.active_list));
BUG_ON(!list_empty(&dev_priv->render_ring.active_list));
- BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.active_list));
- spin_unlock(&dev_priv->mm.active_list_lock);
-
+ BUG_ON(!list_empty(&dev_priv->bsd_ring.active_list));
+ BUG_ON(!list_empty(&dev_priv->blt_ring.active_list));
BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
BUG_ON(!list_empty(&dev_priv->render_ring.request_list));
- BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.request_list));
+ BUG_ON(!list_empty(&dev_priv->bsd_ring.request_list));
+ BUG_ON(!list_empty(&dev_priv->blt_ring.request_list));
mutex_unlock(&dev->struct_mutex);
ret = drm_irq_install(dev);
@@ -4627,28 +4615,34 @@ i915_gem_lastclose(struct drm_device *dev)
DRM_ERROR("failed to idle hardware: %d\n", ret);
}
+static void
+init_ring_lists(struct intel_ring_buffer *ring)
+{
+ INIT_LIST_HEAD(&ring->active_list);
+ INIT_LIST_HEAD(&ring->request_list);
+ INIT_LIST_HEAD(&ring->gpu_write_list);
+}
+
void
i915_gem_load(struct drm_device *dev)
{
int i;
drm_i915_private_t *dev_priv = dev->dev_private;
- spin_lock_init(&dev_priv->mm.active_list_lock);
+ INIT_LIST_HEAD(&dev_priv->mm.active_list);
INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
- INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list);
INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
+ INIT_LIST_HEAD(&dev_priv->mm.pinned_list);
INIT_LIST_HEAD(&dev_priv->mm.fence_list);
INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list);
- INIT_LIST_HEAD(&dev_priv->render_ring.active_list);
- INIT_LIST_HEAD(&dev_priv->render_ring.request_list);
- if (HAS_BSD(dev)) {
- INIT_LIST_HEAD(&dev_priv->bsd_ring.active_list);
- INIT_LIST_HEAD(&dev_priv->bsd_ring.request_list);
- }
+ init_ring_lists(&dev_priv->render_ring);
+ init_ring_lists(&dev_priv->bsd_ring);
+ init_ring_lists(&dev_priv->blt_ring);
for (i = 0; i < 16; i++)
INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list);
INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
i915_gem_retire_work_handler);
+ init_completion(&dev_priv->error_completion);
spin_lock(&shrink_list_lock);
list_add(&dev_priv->mm.shrink_list, &shrink_list);
spin_unlock(&shrink_list_lock);
@@ -4667,21 +4661,30 @@ i915_gem_load(struct drm_device *dev)
if (!drm_core_check_feature(dev, DRIVER_MODESET))
dev_priv->fence_reg_start = 3;
- if (IS_I965G(dev) || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+ if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
dev_priv->num_fence_regs = 16;
else
dev_priv->num_fence_regs = 8;
/* Initialize fence registers to zero */
- if (IS_I965G(dev)) {
+ switch (INTEL_INFO(dev)->gen) {
+ case 6:
+ for (i = 0; i < 16; i++)
+ I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), 0);
+ break;
+ case 5:
+ case 4:
for (i = 0; i < 16; i++)
I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0);
- } else {
- for (i = 0; i < 8; i++)
- I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
+ break;
+ case 3:
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
for (i = 0; i < 8; i++)
I915_WRITE(FENCE_REG_945_8 + (i * 4), 0);
+ case 2:
+ for (i = 0; i < 8; i++)
+ I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
+ break;
}
i915_gem_detect_bit_6_swizzle(dev);
init_waitqueue_head(&dev_priv->pending_flip_queue);
@@ -4691,8 +4694,8 @@ i915_gem_load(struct drm_device *dev)
* Create a physically contiguous memory object for this object
* e.g. for cursor + overlay regs
*/
-int i915_gem_init_phys_object(struct drm_device *dev,
- int id, int size, int align)
+static int i915_gem_init_phys_object(struct drm_device *dev,
+ int id, int size, int align)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_phys_object *phys_obj;
@@ -4724,7 +4727,7 @@ kfree_obj:
return ret;
}
-void i915_gem_free_phys_object(struct drm_device *dev, int id)
+static void i915_gem_free_phys_object(struct drm_device *dev, int id)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_phys_object *phys_obj;
@@ -4772,11 +4775,11 @@ void i915_gem_detach_phys_object(struct drm_device *dev,
page_count = obj->size / PAGE_SIZE;
for (i = 0; i < page_count; i++) {
- char *dst = kmap_atomic(obj_priv->pages[i], KM_USER0);
+ char *dst = kmap_atomic(obj_priv->pages[i]);
char *src = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
memcpy(dst, src, PAGE_SIZE);
- kunmap_atomic(dst, KM_USER0);
+ kunmap_atomic(dst);
}
drm_clflush_pages(obj_priv->pages, page_count);
drm_agp_chipset_flush(dev);
@@ -4833,11 +4836,11 @@ i915_gem_attach_phys_object(struct drm_device *dev,
page_count = obj->size / PAGE_SIZE;
for (i = 0; i < page_count; i++) {
- char *src = kmap_atomic(obj_priv->pages[i], KM_USER0);
+ char *src = kmap_atomic(obj_priv->pages[i]);
char *dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
memcpy(dst, src, PAGE_SIZE);
- kunmap_atomic(src, KM_USER0);
+ kunmap_atomic(src);
}
i915_gem_object_put_pages(obj);
@@ -4869,18 +4872,25 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
return 0;
}
-void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv)
+void i915_gem_release(struct drm_device *dev, struct drm_file *file)
{
- struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+ struct drm_i915_file_private *file_priv = file->driver_priv;
/* Clean up our request list when the client is going away, so that
* later retire_requests won't dereference our soon-to-be-gone
* file_priv.
*/
- mutex_lock(&dev->struct_mutex);
- while (!list_empty(&i915_file_priv->mm.request_list))
- list_del_init(i915_file_priv->mm.request_list.next);
- mutex_unlock(&dev->struct_mutex);
+ spin_lock(&file_priv->mm.lock);
+ while (!list_empty(&file_priv->mm.request_list)) {
+ struct drm_i915_gem_request *request;
+
+ request = list_first_entry(&file_priv->mm.request_list,
+ struct drm_i915_gem_request,
+ client_list);
+ list_del(&request->client_list);
+ request->file_priv = NULL;
+ }
+ spin_unlock(&file_priv->mm.lock);
}
static int
@@ -4889,12 +4899,10 @@ i915_gpu_is_active(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
int lists_empty;
- spin_lock(&dev_priv->mm.active_list_lock);
lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
- list_empty(&dev_priv->render_ring.active_list);
- if (HAS_BSD(dev))
- lists_empty &= list_empty(&dev_priv->bsd_ring.active_list);
- spin_unlock(&dev_priv->mm.active_list_lock);
+ list_empty(&dev_priv->render_ring.active_list) &&
+ list_empty(&dev_priv->bsd_ring.active_list) &&
+ list_empty(&dev_priv->blt_ring.active_list);
return !lists_empty;
}
@@ -4916,7 +4924,7 @@ i915_gem_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
if (mutex_trylock(&dev->struct_mutex)) {
list_for_each_entry(obj_priv,
&dev_priv->mm.inactive_list,
- list)
+ mm_list)
cnt++;
mutex_unlock(&dev->struct_mutex);
}
@@ -4942,7 +4950,7 @@ rescan:
list_for_each_entry_safe(obj_priv, next_obj,
&dev_priv->mm.inactive_list,
- list) {
+ mm_list) {
if (i915_gem_object_is_purgeable(obj_priv)) {
i915_gem_object_unbind(&obj_priv->base);
if (--nr_to_scan <= 0)
@@ -4971,7 +4979,7 @@ rescan:
list_for_each_entry_safe(obj_priv, next_obj,
&dev_priv->mm.inactive_list,
- list) {
+ mm_list) {
if (nr_to_scan > 0) {
i915_gem_object_unbind(&obj_priv->base);
nr_to_scan--;
diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c
index 80f380b1d951..48644b840a8d 100644
--- a/drivers/gpu/drm/i915/i915_gem_debug.c
+++ b/drivers/gpu/drm/i915/i915_gem_debug.c
@@ -30,29 +30,112 @@
#include "i915_drm.h"
#include "i915_drv.h"
-#if WATCH_INACTIVE
-void
-i915_verify_inactive(struct drm_device *dev, char *file, int line)
+#if WATCH_LISTS
+int
+i915_verify_lists(struct drm_device *dev)
{
+ static int warned;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
-
- list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
- obj = &obj_priv->base;
- if (obj_priv->pin_count || obj_priv->active ||
- (obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
- I915_GEM_DOMAIN_GTT)))
- DRM_ERROR("inactive %p (p %d a %d w %x) %s:%d\n",
+ struct drm_i915_gem_object *obj;
+ int err = 0;
+
+ if (warned)
+ return 0;
+
+ list_for_each_entry(obj, &dev_priv->render_ring.active_list, list) {
+ if (obj->base.dev != dev ||
+ !atomic_read(&obj->base.refcount.refcount)) {
+ DRM_ERROR("freed render active %p\n", obj);
+ err++;
+ break;
+ } else if (!obj->active ||
+ (obj->base.read_domains & I915_GEM_GPU_DOMAINS) == 0) {
+ DRM_ERROR("invalid render active %p (a %d r %x)\n",
+ obj,
+ obj->active,
+ obj->base.read_domains);
+ err++;
+ } else if (obj->base.write_domain && list_empty(&obj->gpu_write_list)) {
+ DRM_ERROR("invalid render active %p (w %x, gwl %d)\n",
+ obj,
+ obj->base.write_domain,
+ !list_empty(&obj->gpu_write_list));
+ err++;
+ }
+ }
+
+ list_for_each_entry(obj, &dev_priv->mm.flushing_list, list) {
+ if (obj->base.dev != dev ||
+ !atomic_read(&obj->base.refcount.refcount)) {
+ DRM_ERROR("freed flushing %p\n", obj);
+ err++;
+ break;
+ } else if (!obj->active ||
+ (obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0 ||
+ list_empty(&obj->gpu_write_list)){
+ DRM_ERROR("invalid flushing %p (a %d w %x gwl %d)\n",
obj,
- obj_priv->pin_count, obj_priv->active,
- obj->write_domain, file, line);
+ obj->active,
+ obj->base.write_domain,
+ !list_empty(&obj->gpu_write_list));
+ err++;
+ }
+ }
+
+ list_for_each_entry(obj, &dev_priv->mm.gpu_write_list, gpu_write_list) {
+ if (obj->base.dev != dev ||
+ !atomic_read(&obj->base.refcount.refcount)) {
+ DRM_ERROR("freed gpu write %p\n", obj);
+ err++;
+ break;
+ } else if (!obj->active ||
+ (obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0) {
+ DRM_ERROR("invalid gpu write %p (a %d w %x)\n",
+ obj,
+ obj->active,
+ obj->base.write_domain);
+ err++;
+ }
+ }
+
+ list_for_each_entry(obj, &dev_priv->mm.inactive_list, list) {
+ if (obj->base.dev != dev ||
+ !atomic_read(&obj->base.refcount.refcount)) {
+ DRM_ERROR("freed inactive %p\n", obj);
+ err++;
+ break;
+ } else if (obj->pin_count || obj->active ||
+ (obj->base.write_domain & I915_GEM_GPU_DOMAINS)) {
+ DRM_ERROR("invalid inactive %p (p %d a %d w %x)\n",
+ obj,
+ obj->pin_count, obj->active,
+ obj->base.write_domain);
+ err++;
+ }
}
+
+ list_for_each_entry(obj, &dev_priv->mm.pinned_list, list) {
+ if (obj->base.dev != dev ||
+ !atomic_read(&obj->base.refcount.refcount)) {
+ DRM_ERROR("freed pinned %p\n", obj);
+ err++;
+ break;
+ } else if (!obj->pin_count || obj->active ||
+ (obj->base.write_domain & I915_GEM_GPU_DOMAINS)) {
+ DRM_ERROR("invalid pinned %p (p %d a %d w %x)\n",
+ obj,
+ obj->pin_count, obj->active,
+ obj->base.write_domain);
+ err++;
+ }
+ }
+
+ return warned = err;
}
#endif /* WATCH_INACTIVE */
-#if WATCH_BUF | WATCH_EXEC | WATCH_PWRITE
+#if WATCH_EXEC | WATCH_PWRITE
static void
i915_gem_dump_page(struct page *page, uint32_t start, uint32_t end,
uint32_t bias, uint32_t mark)
@@ -97,41 +180,6 @@ i915_gem_dump_object(struct drm_gem_object *obj, int len,
}
#endif
-#if WATCH_LRU
-void
-i915_dump_lru(struct drm_device *dev, const char *where)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv;
-
- DRM_INFO("active list %s {\n", where);
- spin_lock(&dev_priv->mm.active_list_lock);
- list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
- list)
- {
- DRM_INFO(" %p: %08x\n", obj_priv,
- obj_priv->last_rendering_seqno);
- }
- spin_unlock(&dev_priv->mm.active_list_lock);
- DRM_INFO("}\n");
- DRM_INFO("flushing list %s {\n", where);
- list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
- list)
- {
- DRM_INFO(" %p: %08x\n", obj_priv,
- obj_priv->last_rendering_seqno);
- }
- DRM_INFO("}\n");
- DRM_INFO("inactive %s {\n", where);
- list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
- DRM_INFO(" %p: %08x\n", obj_priv,
- obj_priv->last_rendering_seqno);
- }
- DRM_INFO("}\n");
-}
-#endif
-
-
#if WATCH_COHERENCY
void
i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index 5c428fa3e0b3..43a4013f53fa 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -31,49 +31,6 @@
#include "i915_drv.h"
#include "i915_drm.h"
-static struct drm_i915_gem_object *
-i915_gem_next_active_object(struct drm_device *dev,
- struct list_head **render_iter,
- struct list_head **bsd_iter)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *render_obj = NULL, *bsd_obj = NULL;
-
- if (*render_iter != &dev_priv->render_ring.active_list)
- render_obj = list_entry(*render_iter,
- struct drm_i915_gem_object,
- list);
-
- if (HAS_BSD(dev)) {
- if (*bsd_iter != &dev_priv->bsd_ring.active_list)
- bsd_obj = list_entry(*bsd_iter,
- struct drm_i915_gem_object,
- list);
-
- if (render_obj == NULL) {
- *bsd_iter = (*bsd_iter)->next;
- return bsd_obj;
- }
-
- if (bsd_obj == NULL) {
- *render_iter = (*render_iter)->next;
- return render_obj;
- }
-
- /* XXX can we handle seqno wrapping? */
- if (render_obj->last_rendering_seqno < bsd_obj->last_rendering_seqno) {
- *render_iter = (*render_iter)->next;
- return render_obj;
- } else {
- *bsd_iter = (*bsd_iter)->next;
- return bsd_obj;
- }
- } else {
- *render_iter = (*render_iter)->next;
- return render_obj;
- }
-}
-
static bool
mark_free(struct drm_i915_gem_object *obj_priv,
struct list_head *unwind)
@@ -83,18 +40,12 @@ mark_free(struct drm_i915_gem_object *obj_priv,
return drm_mm_scan_add_block(obj_priv->gtt_space);
}
-#define i915_for_each_active_object(OBJ, R, B) \
- *(R) = dev_priv->render_ring.active_list.next; \
- *(B) = dev_priv->bsd_ring.active_list.next; \
- while (((OBJ) = i915_gem_next_active_object(dev, (R), (B))) != NULL)
-
int
i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct list_head eviction_list, unwind_list;
struct drm_i915_gem_object *obj_priv;
- struct list_head *render_iter, *bsd_iter;
int ret = 0;
i915_gem_retire_requests(dev);
@@ -131,13 +82,13 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen
drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment);
/* First see if there is a large enough contiguous idle region... */
- list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
+ list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, mm_list) {
if (mark_free(obj_priv, &unwind_list))
goto found;
}
/* Now merge in the soon-to-be-expired objects... */
- i915_for_each_active_object(obj_priv, &render_iter, &bsd_iter) {
+ list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
/* Does the object require an outstanding flush? */
if (obj_priv->base.write_domain || obj_priv->pin_count)
continue;
@@ -147,14 +98,14 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen
}
/* Finally add anything with a pending flush (in order of retirement) */
- list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) {
+ list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, mm_list) {
if (obj_priv->pin_count)
continue;
if (mark_free(obj_priv, &unwind_list))
goto found;
}
- i915_for_each_active_object(obj_priv, &render_iter, &bsd_iter) {
+ list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
if (! obj_priv->base.write_domain || obj_priv->pin_count)
continue;
@@ -212,14 +163,11 @@ i915_gem_evict_everything(struct drm_device *dev)
int ret;
bool lists_empty;
- spin_lock(&dev_priv->mm.active_list_lock);
lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
list_empty(&dev_priv->mm.flushing_list) &&
list_empty(&dev_priv->render_ring.active_list) &&
- (!HAS_BSD(dev)
- || list_empty(&dev_priv->bsd_ring.active_list)));
- spin_unlock(&dev_priv->mm.active_list_lock);
-
+ list_empty(&dev_priv->bsd_ring.active_list) &&
+ list_empty(&dev_priv->blt_ring.active_list));
if (lists_empty)
return -ENOSPC;
@@ -234,13 +182,11 @@ i915_gem_evict_everything(struct drm_device *dev)
if (ret)
return ret;
- spin_lock(&dev_priv->mm.active_list_lock);
lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
list_empty(&dev_priv->mm.flushing_list) &&
list_empty(&dev_priv->render_ring.active_list) &&
- (!HAS_BSD(dev)
- || list_empty(&dev_priv->bsd_ring.active_list)));
- spin_unlock(&dev_priv->mm.active_list_lock);
+ list_empty(&dev_priv->bsd_ring.active_list) &&
+ list_empty(&dev_priv->blt_ring.active_list));
BUG_ON(!lists_empty);
return 0;
@@ -258,7 +204,7 @@ i915_gem_evict_inactive(struct drm_device *dev)
obj = &list_first_entry(&dev_priv->mm.inactive_list,
struct drm_i915_gem_object,
- list)->base;
+ mm_list)->base;
ret = i915_gem_object_unbind(obj);
if (ret != 0) {
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 710eca70b323..af352de70be1 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -92,13 +92,13 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
- if (IS_IRONLAKE(dev) || IS_GEN6(dev)) {
+ if (IS_GEN5(dev) || IS_GEN6(dev)) {
/* On Ironlake whatever DRAM config, GPU always do
* same swizzling setup.
*/
swizzle_x = I915_BIT_6_SWIZZLE_9_10;
swizzle_y = I915_BIT_6_SWIZZLE_9;
- } else if (!IS_I9XX(dev)) {
+ } else if (IS_GEN2(dev)) {
/* As far as we know, the 865 doesn't have these bit 6
* swizzling issues.
*/
@@ -190,19 +190,19 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
if (tiling_mode == I915_TILING_NONE)
return true;
- if (!IS_I9XX(dev) ||
+ if (IS_GEN2(dev) ||
(tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)))
tile_width = 128;
else
tile_width = 512;
/* check maximum stride & object size */
- if (IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4) {
/* i965 stores the end address of the gtt mapping in the fence
* reg, so dont bother to check the size */
if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
return false;
- } else if (IS_GEN3(dev) || IS_GEN2(dev)) {
+ } else {
if (stride > 8192)
return false;
@@ -216,7 +216,7 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
}
/* 965+ just needs multiples of tile width */
- if (IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4) {
if (stride & (tile_width - 1))
return false;
return true;
@@ -244,16 +244,18 @@ i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode)
if (tiling_mode == I915_TILING_NONE)
return true;
- if (!IS_I965G(dev)) {
- if (obj_priv->gtt_offset & (obj->size - 1))
+ if (INTEL_INFO(dev)->gen >= 4)
+ return true;
+
+ if (obj_priv->gtt_offset & (obj->size - 1))
+ return false;
+
+ if (IS_GEN3(dev)) {
+ if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
+ return false;
+ } else {
+ if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
return false;
- if (IS_I9XX(dev)) {
- if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
- return false;
- } else {
- if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
- return false;
- }
}
return true;
@@ -271,7 +273,11 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
- int ret = 0;
+ int ret;
+
+ ret = i915_gem_check_is_wedged(dev);
+ if (ret)
+ return ret;
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL)
@@ -328,7 +334,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode))
ret = i915_gem_object_unbind(obj);
else if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
- ret = i915_gem_object_put_fence_reg(obj);
+ ret = i915_gem_object_put_fence_reg(obj, true);
else
i915_gem_release_mmap(obj);
@@ -399,16 +405,14 @@ i915_gem_get_tiling(struct drm_device *dev, void *data,
* bit 17 of its physical address and therefore being interpreted differently
* by the GPU.
*/
-static int
+static void
i915_gem_swizzle_page(struct page *page)
{
+ char temp[64];
char *vaddr;
int i;
- char temp[64];
vaddr = kmap(page);
- if (vaddr == NULL)
- return -ENOMEM;
for (i = 0; i < PAGE_SIZE; i += 128) {
memcpy(temp, &vaddr[i], 64);
@@ -417,8 +421,6 @@ i915_gem_swizzle_page(struct page *page)
}
kunmap(page);
-
- return 0;
}
void
@@ -440,11 +442,7 @@ i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj)
char new_bit_17 = page_to_phys(obj_priv->pages[i]) >> 17;
if ((new_bit_17 & 0x1) !=
(test_bit(i, obj_priv->bit_17) != 0)) {
- int ret = i915_gem_swizzle_page(obj_priv->pages[i]);
- if (ret != 0) {
- DRM_ERROR("Failed to swizzle page\n");
- return;
- }
+ i915_gem_swizzle_page(obj_priv->pages[i]);
set_page_dirty(obj_priv->pages[i]);
}
}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 744225ebb4b2..729fd0c91d7b 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -85,7 +85,7 @@ ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask)
}
/* For display hotplug interrupt */
-void
+static void
ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
{
if ((dev_priv->irq_mask_reg & mask) != 0) {
@@ -172,7 +172,7 @@ void intel_enable_asle (struct drm_device *dev)
else {
i915_enable_pipestat(dev_priv, 1,
PIPE_LEGACY_BLC_EVENT_ENABLE);
- if (IS_I965G(dev))
+ if (INTEL_INFO(dev)->gen >= 4)
i915_enable_pipestat(dev_priv, 0,
PIPE_LEGACY_BLC_EVENT_ENABLE);
}
@@ -191,12 +191,7 @@ static int
i915_pipe_enabled(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
-
- if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
- return 1;
-
- return 0;
+ return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE;
}
/* Called from drm generic code, passed a 'crtc', which
@@ -207,10 +202,7 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long high_frame;
unsigned long low_frame;
- u32 high1, high2, low, count;
-
- high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
- low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+ u32 high1, high2, low;
if (!i915_pipe_enabled(dev, pipe)) {
DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
@@ -218,23 +210,23 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
return 0;
}
+ high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
+ low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+
/*
* High & low register fields aren't synchronized, so make sure
* we get a low value that's stable across two reads of the high
* register.
*/
do {
- high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
- PIPE_FRAME_HIGH_SHIFT);
- low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
- PIPE_FRAME_LOW_SHIFT);
- high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
- PIPE_FRAME_HIGH_SHIFT);
+ high1 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK;
+ low = I915_READ(low_frame) & PIPE_FRAME_LOW_MASK;
+ high2 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK;
} while (high1 != high2);
- count = (high1 << 8) | low;
-
- return count;
+ high1 >>= PIPE_FRAME_HIGH_SHIFT;
+ low >>= PIPE_FRAME_LOW_SHIFT;
+ return (high1 << 8) | low;
}
u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
@@ -260,16 +252,12 @@ static void i915_hotplug_work_func(struct work_struct *work)
hotplug_work);
struct drm_device *dev = dev_priv->dev;
struct drm_mode_config *mode_config = &dev->mode_config;
- struct drm_encoder *encoder;
-
- if (mode_config->num_encoder) {
- list_for_each_entry(encoder, &mode_config->encoder_list, head) {
- struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-
- if (intel_encoder->hot_plug)
- (*intel_encoder->hot_plug) (intel_encoder);
- }
- }
+ struct intel_encoder *encoder;
+
+ list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
+ if (encoder->hot_plug)
+ encoder->hot_plug(encoder);
+
/* Just fire off a uevent and let userspace tell us what to do */
drm_helper_hpd_irq_event(dev);
}
@@ -305,13 +293,30 @@ static void i915_handle_rps_change(struct drm_device *dev)
return;
}
-irqreturn_t ironlake_irq_handler(struct drm_device *dev)
+static void notify_ring(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 seqno = ring->get_seqno(dev, ring);
+ ring->irq_gem_seqno = seqno;
+ trace_i915_gem_request_complete(dev, seqno);
+ wake_up_all(&ring->irq_queue);
+ dev_priv->hangcheck_count = 0;
+ mod_timer(&dev_priv->hangcheck_timer,
+ jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
+}
+
+static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int ret = IRQ_NONE;
u32 de_iir, gt_iir, de_ier, pch_iir;
+ u32 hotplug_mask;
struct drm_i915_master_private *master_priv;
- struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
+ u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
+
+ if (IS_GEN6(dev))
+ bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT;
/* disable master interrupt before clearing iir */
de_ier = I915_READ(DEIER);
@@ -325,6 +330,11 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
if (de_iir == 0 && gt_iir == 0 && pch_iir == 0)
goto done;
+ if (HAS_PCH_CPT(dev))
+ hotplug_mask = SDE_HOTPLUG_MASK_CPT;
+ else
+ hotplug_mask = SDE_HOTPLUG_MASK;
+
ret = IRQ_HANDLED;
if (dev->primary->master) {
@@ -334,29 +344,24 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
READ_BREADCRUMB(dev_priv);
}
- if (gt_iir & GT_PIPE_NOTIFY) {
- u32 seqno = render_ring->get_gem_seqno(dev, render_ring);
- render_ring->irq_gem_seqno = seqno;
- trace_i915_gem_request_complete(dev, seqno);
- DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
- dev_priv->hangcheck_count = 0;
- mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
- }
- if (gt_iir & GT_BSD_USER_INTERRUPT)
- DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
-
+ if (gt_iir & GT_PIPE_NOTIFY)
+ notify_ring(dev, &dev_priv->render_ring);
+ if (gt_iir & bsd_usr_interrupt)
+ notify_ring(dev, &dev_priv->bsd_ring);
+ if (HAS_BLT(dev) && gt_iir & GT_BLT_USER_INTERRUPT)
+ notify_ring(dev, &dev_priv->blt_ring);
if (de_iir & DE_GSE)
- ironlake_opregion_gse_intr(dev);
+ intel_opregion_gse_intr(dev);
if (de_iir & DE_PLANEA_FLIP_DONE) {
intel_prepare_page_flip(dev, 0);
- intel_finish_page_flip(dev, 0);
+ intel_finish_page_flip_plane(dev, 0);
}
if (de_iir & DE_PLANEB_FLIP_DONE) {
intel_prepare_page_flip(dev, 1);
- intel_finish_page_flip(dev, 1);
+ intel_finish_page_flip_plane(dev, 1);
}
if (de_iir & DE_PIPEA_VBLANK)
@@ -366,10 +371,8 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
drm_handle_vblank(dev, 1);
/* check event from PCH */
- if ((de_iir & DE_PCH_EVENT) &&
- (pch_iir & SDE_HOTPLUG_MASK)) {
+ if ((de_iir & DE_PCH_EVENT) && (pch_iir & hotplug_mask))
queue_work(dev_priv->wq, &dev_priv->hotplug_work);
- }
if (de_iir & DE_PCU_EVENT) {
I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
@@ -404,23 +407,20 @@ static void i915_error_work_func(struct work_struct *work)
char *reset_event[] = { "RESET=1", NULL };
char *reset_done_event[] = { "ERROR=0", NULL };
- DRM_DEBUG_DRIVER("generating error event\n");
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
if (atomic_read(&dev_priv->mm.wedged)) {
- if (IS_I965G(dev)) {
- DRM_DEBUG_DRIVER("resetting chip\n");
- kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event);
- if (!i965_reset(dev, GDRST_RENDER)) {
- atomic_set(&dev_priv->mm.wedged, 0);
- kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
- }
- } else {
- DRM_DEBUG_DRIVER("reboot required\n");
+ DRM_DEBUG_DRIVER("resetting chip\n");
+ kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event);
+ if (!i915_reset(dev, GRDOM_RENDER)) {
+ atomic_set(&dev_priv->mm.wedged, 0);
+ kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
}
+ complete_all(&dev_priv->error_completion);
}
}
+#ifdef CONFIG_DEBUG_FS
static struct drm_i915_error_object *
i915_error_object_create(struct drm_device *dev,
struct drm_gem_object *src)
@@ -456,10 +456,9 @@ i915_error_object_create(struct drm_device *dev,
local_irq_save(flags);
s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
- reloc_offset,
- KM_IRQ0);
+ reloc_offset);
memcpy_fromio(d, s, PAGE_SIZE);
- io_mapping_unmap_atomic(s, KM_IRQ0);
+ io_mapping_unmap_atomic(s);
local_irq_restore(flags);
dst->pages[page] = d;
@@ -511,7 +510,7 @@ i915_get_bbaddr(struct drm_device *dev, u32 *ring)
if (IS_I830(dev) || IS_845G(dev))
cmd = MI_BATCH_BUFFER;
- else if (IS_I965G(dev))
+ else if (INTEL_INFO(dev)->gen >= 4)
cmd = (MI_BATCH_BUFFER_START | (2 << 6) |
MI_BATCH_NON_SECURE_I965);
else
@@ -584,13 +583,16 @@ static void i915_capture_error_state(struct drm_device *dev)
return;
}
- error->seqno = i915_get_gem_seqno(dev, &dev_priv->render_ring);
+ DRM_DEBUG_DRIVER("generating error event\n");
+
+ error->seqno =
+ dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring);
error->eir = I915_READ(EIR);
error->pgtbl_er = I915_READ(PGTBL_ER);
error->pipeastat = I915_READ(PIPEASTAT);
error->pipebstat = I915_READ(PIPEBSTAT);
error->instpm = I915_READ(INSTPM);
- if (!IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen < 4) {
error->ipeir = I915_READ(IPEIR);
error->ipehr = I915_READ(IPEHR);
error->instdone = I915_READ(INSTDONE);
@@ -612,9 +614,7 @@ static void i915_capture_error_state(struct drm_device *dev)
batchbuffer[0] = NULL;
batchbuffer[1] = NULL;
count = 0;
- list_for_each_entry(obj_priv,
- &dev_priv->render_ring.active_list, list) {
-
+ list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
struct drm_gem_object *obj = &obj_priv->base;
if (batchbuffer[0] == NULL &&
@@ -631,7 +631,7 @@ static void i915_capture_error_state(struct drm_device *dev)
}
/* Scan the other lists for completeness for those bizarre errors. */
if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) {
- list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) {
+ list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, mm_list) {
struct drm_gem_object *obj = &obj_priv->base;
if (batchbuffer[0] == NULL &&
@@ -649,7 +649,7 @@ static void i915_capture_error_state(struct drm_device *dev)
}
}
if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) {
- list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
+ list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, mm_list) {
struct drm_gem_object *obj = &obj_priv->base;
if (batchbuffer[0] == NULL &&
@@ -668,7 +668,7 @@ static void i915_capture_error_state(struct drm_device *dev)
}
/* We need to copy these to an anonymous buffer as the simplest
- * method to avoid being overwritten by userpace.
+ * method to avoid being overwritten by userspace.
*/
error->batchbuffer[0] = i915_error_object_create(dev, batchbuffer[0]);
if (batchbuffer[1] != batchbuffer[0])
@@ -690,8 +690,7 @@ static void i915_capture_error_state(struct drm_device *dev)
if (error->active_bo) {
int i = 0;
- list_for_each_entry(obj_priv,
- &dev_priv->render_ring.active_list, list) {
+ list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
struct drm_gem_object *obj = &obj_priv->base;
error->active_bo[i].size = obj->size;
@@ -744,6 +743,9 @@ void i915_destroy_error_state(struct drm_device *dev)
if (error)
i915_error_state_free(dev, error);
}
+#else
+#define i915_capture_error_state(x)
+#endif
static void i915_report_and_clear_eir(struct drm_device *dev)
{
@@ -785,7 +787,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
}
}
- if (IS_I9XX(dev)) {
+ if (!IS_GEN2(dev)) {
if (eir & I915_ERROR_PAGE_TABLE) {
u32 pgtbl_err = I915_READ(PGTBL_ER);
printk(KERN_ERR "page table error\n");
@@ -811,7 +813,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
printk(KERN_ERR "instruction error\n");
printk(KERN_ERR " INSTPM: 0x%08x\n",
I915_READ(INSTPM));
- if (!IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen < 4) {
u32 ipeir = I915_READ(IPEIR);
printk(KERN_ERR " IPEIR: 0x%08x\n",
@@ -876,12 +878,17 @@ static void i915_handle_error(struct drm_device *dev, bool wedged)
i915_report_and_clear_eir(dev);
if (wedged) {
+ INIT_COMPLETION(dev_priv->error_completion);
atomic_set(&dev_priv->mm.wedged, 1);
/*
* Wakeup waiting processes so they don't hang
*/
- DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
+ wake_up_all(&dev_priv->render_ring.irq_queue);
+ if (HAS_BSD(dev))
+ wake_up_all(&dev_priv->bsd_ring.irq_queue);
+ if (HAS_BLT(dev))
+ wake_up_all(&dev_priv->blt_ring.irq_queue);
}
queue_work(dev_priv->wq, &dev_priv->error_work);
@@ -912,7 +919,7 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe)
/* Potential stall - if we see that the flip has happened, assume a missed interrupt */
obj_priv = to_intel_bo(work->pending_flip_obj);
- if(IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4) {
int dspsurf = intel_crtc->plane == 0 ? DSPASURF : DSPBSURF;
stall_detected = I915_READ(dspsurf) == obj_priv->gtt_offset;
} else {
@@ -942,7 +949,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
unsigned long irqflags;
int irq_received;
int ret = IRQ_NONE;
- struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
atomic_inc(&dev_priv->irq_received);
@@ -951,7 +957,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
iir = I915_READ(IIR);
- if (IS_I965G(dev))
+ if (INTEL_INFO(dev)->gen >= 4)
vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS;
else
vblank_status = PIPE_VBLANK_INTERRUPT_STATUS;
@@ -1019,18 +1025,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
READ_BREADCRUMB(dev_priv);
}
- if (iir & I915_USER_INTERRUPT) {
- u32 seqno =
- render_ring->get_gem_seqno(dev, render_ring);
- render_ring->irq_gem_seqno = seqno;
- trace_i915_gem_request_complete(dev, seqno);
- DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
- dev_priv->hangcheck_count = 0;
- mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
- }
-
+ if (iir & I915_USER_INTERRUPT)
+ notify_ring(dev, &dev_priv->render_ring);
if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT))
- DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
+ notify_ring(dev, &dev_priv->bsd_ring);
if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
intel_prepare_page_flip(dev, 0);
@@ -1065,7 +1063,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
if ((pipea_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
(pipeb_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
(iir & I915_ASLE_INTERRUPT))
- opregion_asle_intr(dev);
+ intel_opregion_asle_intr(dev);
/* With MSI, interrupts are only generated when iir
* transitions from zero to nonzero. If another bit got
@@ -1207,18 +1205,15 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
- int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
- u32 pipeconf;
- pipeconf = I915_READ(pipeconf_reg);
- if (!(pipeconf & PIPEACONF_ENABLE))
+ if (!i915_pipe_enabled(dev, pipe))
return -EINVAL;
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
if (HAS_PCH_SPLIT(dev))
ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
- else if (IS_I965G(dev))
+ else if (INTEL_INFO(dev)->gen >= 4)
i915_enable_pipestat(dev_priv, pipe,
PIPE_START_VBLANK_INTERRUPT_ENABLE);
else
@@ -1252,7 +1247,7 @@ void i915_enable_interrupt (struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
if (!HAS_PCH_SPLIT(dev))
- opregion_enable_asle(dev);
+ intel_opregion_enable_asle(dev);
dev_priv->irq_enabled = 1;
}
@@ -1311,7 +1306,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
return -EINVAL;
}
-struct drm_i915_gem_request *
+static struct drm_i915_gem_request *
i915_get_tail_request(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -1331,11 +1326,7 @@ void i915_hangcheck_elapsed(unsigned long data)
drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t acthd, instdone, instdone1;
- /* No reset support on this chip yet. */
- if (IS_GEN6(dev))
- return;
-
- if (!IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen < 4) {
acthd = I915_READ(ACTHD);
instdone = I915_READ(INSTDONE);
instdone1 = 0;
@@ -1347,9 +1338,8 @@ void i915_hangcheck_elapsed(unsigned long data)
/* If all work is done then ACTHD clearly hasn't advanced. */
if (list_empty(&dev_priv->render_ring.request_list) ||
- i915_seqno_passed(i915_get_gem_seqno(dev,
- &dev_priv->render_ring),
- i915_get_tail_request(dev)->seqno)) {
+ i915_seqno_passed(dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring),
+ i915_get_tail_request(dev)->seqno)) {
bool missed_wakeup = false;
dev_priv->hangcheck_count = 0;
@@ -1357,13 +1347,19 @@ void i915_hangcheck_elapsed(unsigned long data)
/* Issue a wake-up to catch stuck h/w. */
if (dev_priv->render_ring.waiting_gem_seqno &&
waitqueue_active(&dev_priv->render_ring.irq_queue)) {
- DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
+ wake_up_all(&dev_priv->render_ring.irq_queue);
missed_wakeup = true;
}
if (dev_priv->bsd_ring.waiting_gem_seqno &&
waitqueue_active(&dev_priv->bsd_ring.irq_queue)) {
- DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
+ wake_up_all(&dev_priv->bsd_ring.irq_queue);
+ missed_wakeup = true;
+ }
+
+ if (dev_priv->blt_ring.waiting_gem_seqno &&
+ waitqueue_active(&dev_priv->blt_ring.irq_queue)) {
+ wake_up_all(&dev_priv->blt_ring.irq_queue);
missed_wakeup = true;
}
@@ -1377,6 +1373,21 @@ void i915_hangcheck_elapsed(unsigned long data)
dev_priv->last_instdone1 == instdone1) {
if (dev_priv->hangcheck_count++ > 1) {
DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
+
+ if (!IS_GEN2(dev)) {
+ /* Is the chip hanging on a WAIT_FOR_EVENT?
+ * If so we can simply poke the RB_WAIT bit
+ * and break the hang. This should work on
+ * all but the second generation chipsets.
+ */
+ u32 tmp = I915_READ(PRB0_CTL);
+ if (tmp & RING_WAIT) {
+ I915_WRITE(PRB0_CTL, tmp);
+ POSTING_READ(PRB0_CTL);
+ goto out;
+ }
+ }
+
i915_handle_error(dev, true);
return;
}
@@ -1388,8 +1399,10 @@ void i915_hangcheck_elapsed(unsigned long data)
dev_priv->last_instdone1 = instdone1;
}
+out:
/* Reset timer case chip hangs without another request being added */
- mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+ mod_timer(&dev_priv->hangcheck_timer,
+ jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
}
/* drm_dma.h hooks
@@ -1424,8 +1437,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
u32 render_mask = GT_PIPE_NOTIFY | GT_BSD_USER_INTERRUPT;
- u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
- SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
+ u32 hotplug_mask;
dev_priv->irq_mask_reg = ~display_mask;
dev_priv->de_irq_enable_reg = display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK;
@@ -1436,20 +1448,35 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
(void) I915_READ(DEIER);
- /* Gen6 only needs render pipe_control now */
- if (IS_GEN6(dev))
- render_mask = GT_PIPE_NOTIFY;
+ if (IS_GEN6(dev)) {
+ render_mask =
+ GT_PIPE_NOTIFY |
+ GT_GEN6_BSD_USER_INTERRUPT |
+ GT_BLT_USER_INTERRUPT;
+ }
dev_priv->gt_irq_mask_reg = ~render_mask;
dev_priv->gt_irq_enable_reg = render_mask;
I915_WRITE(GTIIR, I915_READ(GTIIR));
I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
- if (IS_GEN6(dev))
+ if (IS_GEN6(dev)) {
I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT);
+ I915_WRITE(GEN6_BSD_IMR, ~GEN6_BSD_IMR_USER_INTERRUPT);
+ I915_WRITE(GEN6_BLITTER_IMR, ~GEN6_BLITTER_USER_INTERRUPT);
+ }
+
I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg);
(void) I915_READ(GTIER);
+ if (HAS_PCH_CPT(dev)) {
+ hotplug_mask = SDE_CRT_HOTPLUG_CPT | SDE_PORTB_HOTPLUG_CPT |
+ SDE_PORTC_HOTPLUG_CPT | SDE_PORTD_HOTPLUG_CPT ;
+ } else {
+ hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
+ SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
+ }
+
dev_priv->pch_irq_mask_reg = ~hotplug_mask;
dev_priv->pch_irq_enable_reg = hotplug_mask;
@@ -1506,9 +1533,10 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
u32 error_mask;
DRM_INIT_WAITQUEUE(&dev_priv->render_ring.irq_queue);
-
if (HAS_BSD(dev))
DRM_INIT_WAITQUEUE(&dev_priv->bsd_ring.irq_queue);
+ if (HAS_BLT(dev))
+ DRM_INIT_WAITQUEUE(&dev_priv->blt_ring.irq_queue);
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
@@ -1578,7 +1606,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
}
- opregion_enable_asle(dev);
+ intel_opregion_enable_asle(dev);
return 0;
}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 4f5e15577e89..25ed911a3112 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -25,52 +25,16 @@
#ifndef _I915_REG_H_
#define _I915_REG_H_
+#define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a)))
+
/*
* The Bridge device's PCI config space has information about the
* fb aperture size and the amount of pre-reserved memory.
+ * This is all handled in the intel-gtt.ko module. i915.ko only
+ * cares about the vga bit for the vga rbiter.
*/
#define INTEL_GMCH_CTRL 0x52
#define INTEL_GMCH_VGA_DISABLE (1 << 1)
-#define INTEL_GMCH_ENABLED 0x4
-#define INTEL_GMCH_MEM_MASK 0x1
-#define INTEL_GMCH_MEM_64M 0x1
-#define INTEL_GMCH_MEM_128M 0
-
-#define INTEL_GMCH_GMS_MASK (0xf << 4)
-#define INTEL_855_GMCH_GMS_DISABLED (0x0 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_1M (0x1 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_4M (0x2 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_8M (0x3 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_16M (0x4 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_32M (0x5 << 4)
-
-#define INTEL_915G_GMCH_GMS_STOLEN_48M (0x6 << 4)
-#define INTEL_915G_GMCH_GMS_STOLEN_64M (0x7 << 4)
-#define INTEL_GMCH_GMS_STOLEN_128M (0x8 << 4)
-#define INTEL_GMCH_GMS_STOLEN_256M (0x9 << 4)
-#define INTEL_GMCH_GMS_STOLEN_96M (0xa << 4)
-#define INTEL_GMCH_GMS_STOLEN_160M (0xb << 4)
-#define INTEL_GMCH_GMS_STOLEN_224M (0xc << 4)
-#define INTEL_GMCH_GMS_STOLEN_352M (0xd << 4)
-
-#define SNB_GMCH_CTRL 0x50
-#define SNB_GMCH_GMS_STOLEN_MASK 0xF8
-#define SNB_GMCH_GMS_STOLEN_32M (1 << 3)
-#define SNB_GMCH_GMS_STOLEN_64M (2 << 3)
-#define SNB_GMCH_GMS_STOLEN_96M (3 << 3)
-#define SNB_GMCH_GMS_STOLEN_128M (4 << 3)
-#define SNB_GMCH_GMS_STOLEN_160M (5 << 3)
-#define SNB_GMCH_GMS_STOLEN_192M (6 << 3)
-#define SNB_GMCH_GMS_STOLEN_224M (7 << 3)
-#define SNB_GMCH_GMS_STOLEN_256M (8 << 3)
-#define SNB_GMCH_GMS_STOLEN_288M (9 << 3)
-#define SNB_GMCH_GMS_STOLEN_320M (0xa << 3)
-#define SNB_GMCH_GMS_STOLEN_352M (0xb << 3)
-#define SNB_GMCH_GMS_STOLEN_384M (0xc << 3)
-#define SNB_GMCH_GMS_STOLEN_416M (0xd << 3)
-#define SNB_GMCH_GMS_STOLEN_448M (0xe << 3)
-#define SNB_GMCH_GMS_STOLEN_480M (0xf << 3)
-#define SNB_GMCH_GMS_STOLEN_512M (0x10 << 3)
/* PCI config space */
@@ -106,10 +70,13 @@
#define I915_GC_RENDER_CLOCK_200_MHZ (1 << 0)
#define I915_GC_RENDER_CLOCK_333_MHZ (4 << 0)
#define LBB 0xf4
-#define GDRST 0xc0
-#define GDRST_FULL (0<<2)
-#define GDRST_RENDER (1<<2)
-#define GDRST_MEDIA (3<<2)
+
+/* Graphics reset regs */
+#define I965_GDRST 0xc0 /* PCI config register */
+#define ILK_GDSR 0x2ca4 /* MCHBAR offset */
+#define GRDOM_FULL (0<<2)
+#define GRDOM_RENDER (1<<2)
+#define GRDOM_MEDIA (3<<2)
/* VGA stuff */
@@ -192,11 +159,11 @@
#define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1)
#define MI_STORE_DWORD_INDEX_SHIFT 2
#define MI_LOAD_REGISTER_IMM MI_INSTR(0x22, 1)
+#define MI_FLUSH_DW MI_INSTR(0x26, 2) /* for GEN6 */
#define MI_BATCH_BUFFER MI_INSTR(0x30, 1)
#define MI_BATCH_NON_SECURE (1)
#define MI_BATCH_NON_SECURE_I965 (1<<8)
#define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0)
-
/*
* 3D instructions used by the kernel
*/
@@ -249,6 +216,16 @@
#define PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */
#define PIPE_CONTROL_STALL_EN (1<<1) /* in addr word, Ironlake+ only */
+
+/*
+ * Reset registers
+ */
+#define DEBUG_RESET_I830 0x6070
+#define DEBUG_RESET_FULL (1<<7)
+#define DEBUG_RESET_RENDER (1<<8)
+#define DEBUG_RESET_DISPLAY (1<<9)
+
+
/*
* Fence registers
*/
@@ -283,6 +260,17 @@
#define PRB0_HEAD 0x02034
#define PRB0_START 0x02038
#define PRB0_CTL 0x0203c
+#define RENDER_RING_BASE 0x02000
+#define BSD_RING_BASE 0x04000
+#define GEN6_BSD_RING_BASE 0x12000
+#define BLT_RING_BASE 0x22000
+#define RING_TAIL(base) ((base)+0x30)
+#define RING_HEAD(base) ((base)+0x34)
+#define RING_START(base) ((base)+0x38)
+#define RING_CTL(base) ((base)+0x3c)
+#define RING_HWS_PGA(base) ((base)+0x80)
+#define RING_HWS_PGA_GEN6(base) ((base)+0x2080)
+#define RING_ACTHD(base) ((base)+0x74)
#define TAIL_ADDR 0x001FFFF8
#define HEAD_WRAP_COUNT 0xFFE00000
#define HEAD_WRAP_ONE 0x00200000
@@ -295,6 +283,8 @@
#define RING_VALID_MASK 0x00000001
#define RING_VALID 0x00000001
#define RING_INVALID 0x00000000
+#define RING_WAIT_I8XX (1<<0) /* gen2, PRBx_HEAD */
+#define RING_WAIT (1<<11) /* gen3+, PRBx_CTL */
#define PRB1_TAIL 0x02040 /* 915+ only */
#define PRB1_HEAD 0x02044 /* 915+ only */
#define PRB1_START 0x02048 /* 915+ only */
@@ -306,7 +296,6 @@
#define INSTDONE1 0x0207c /* 965+ only */
#define ACTHD_I965 0x02074
#define HWS_PGA 0x02080
-#define HWS_PGA_GEN6 0x04080
#define HWS_ADDRESS_MASK 0xfffff000
#define HWS_START_ADDRESS_SHIFT 4
#define PWRCTXA 0x2088 /* 965GM+ only */
@@ -464,17 +453,17 @@
#define GEN6_BLITTER_COMMAND_PARSER_MASTER_ERROR (1 << 25)
#define GEN6_BLITTER_SYNC_STATUS (1 << 24)
#define GEN6_BLITTER_USER_INTERRUPT (1 << 22)
-/*
- * BSD (bit stream decoder instruction and interrupt control register defines
- * (G4X and Ironlake only)
- */
-#define BSD_RING_TAIL 0x04030
-#define BSD_RING_HEAD 0x04034
-#define BSD_RING_START 0x04038
-#define BSD_RING_CTL 0x0403c
-#define BSD_RING_ACTHD 0x04074
-#define BSD_HWS_PGA 0x04080
+#define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050
+#define GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK (1 << 16)
+#define GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE (1 << 0)
+#define GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE 0
+#define GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR (1 << 3)
+
+#define GEN6_BSD_IMR 0x120a8
+#define GEN6_BSD_IMR_USER_INTERRUPT (1 << 12)
+
+#define GEN6_BSD_RNCID 0x12198
/*
* Framebuffer compression (915+ only)
@@ -579,12 +568,51 @@
# define GPIO_DATA_VAL_IN (1 << 12)
# define GPIO_DATA_PULLUP_DISABLE (1 << 13)
-#define GMBUS0 0x5100
-#define GMBUS1 0x5104
-#define GMBUS2 0x5108
-#define GMBUS3 0x510c
-#define GMBUS4 0x5110
-#define GMBUS5 0x5120
+#define GMBUS0 0x5100 /* clock/port select */
+#define GMBUS_RATE_100KHZ (0<<8)
+#define GMBUS_RATE_50KHZ (1<<8)
+#define GMBUS_RATE_400KHZ (2<<8) /* reserved on Pineview */
+#define GMBUS_RATE_1MHZ (3<<8) /* reserved on Pineview */
+#define GMBUS_HOLD_EXT (1<<7) /* 300ns hold time, rsvd on Pineview */
+#define GMBUS_PORT_DISABLED 0
+#define GMBUS_PORT_SSC 1
+#define GMBUS_PORT_VGADDC 2
+#define GMBUS_PORT_PANEL 3
+#define GMBUS_PORT_DPC 4 /* HDMIC */
+#define GMBUS_PORT_DPB 5 /* SDVO, HDMIB */
+ /* 6 reserved */
+#define GMBUS_PORT_DPD 7 /* HDMID */
+#define GMBUS_NUM_PORTS 8
+#define GMBUS1 0x5104 /* command/status */
+#define GMBUS_SW_CLR_INT (1<<31)
+#define GMBUS_SW_RDY (1<<30)
+#define GMBUS_ENT (1<<29) /* enable timeout */
+#define GMBUS_CYCLE_NONE (0<<25)
+#define GMBUS_CYCLE_WAIT (1<<25)
+#define GMBUS_CYCLE_INDEX (2<<25)
+#define GMBUS_CYCLE_STOP (4<<25)
+#define GMBUS_BYTE_COUNT_SHIFT 16
+#define GMBUS_SLAVE_INDEX_SHIFT 8
+#define GMBUS_SLAVE_ADDR_SHIFT 1
+#define GMBUS_SLAVE_READ (1<<0)
+#define GMBUS_SLAVE_WRITE (0<<0)
+#define GMBUS2 0x5108 /* status */
+#define GMBUS_INUSE (1<<15)
+#define GMBUS_HW_WAIT_PHASE (1<<14)
+#define GMBUS_STALL_TIMEOUT (1<<13)
+#define GMBUS_INT (1<<12)
+#define GMBUS_HW_RDY (1<<11)
+#define GMBUS_SATOER (1<<10)
+#define GMBUS_ACTIVE (1<<9)
+#define GMBUS3 0x510c /* data buffer bytes 3-0 */
+#define GMBUS4 0x5110 /* interrupt mask (Pineview+) */
+#define GMBUS_SLAVE_TIMEOUT_EN (1<<4)
+#define GMBUS_NAK_EN (1<<3)
+#define GMBUS_IDLE_EN (1<<2)
+#define GMBUS_HW_WAIT_EN (1<<1)
+#define GMBUS_HW_RDY_EN (1<<0)
+#define GMBUS5 0x5120 /* byte index */
+#define GMBUS_2BYTE_INDEX_EN (1<<31)
/*
* Clock control & power management
@@ -603,6 +631,7 @@
#define VGA1_PD_P1_MASK (0x1f << 8)
#define DPLL_A 0x06014
#define DPLL_B 0x06018
+#define DPLL(pipe) _PIPE(pipe, DPLL_A, DPLL_B)
#define DPLL_VCO_ENABLE (1 << 31)
#define DPLL_DVO_HIGH_SPEED (1 << 30)
#define DPLL_SYNCLOCK_ENABLE (1 << 29)
@@ -633,31 +662,6 @@
#define LVDS 0x61180
#define LVDS_ON (1<<31)
-#define ADPA 0x61100
-#define ADPA_DPMS_MASK (~(3<<10))
-#define ADPA_DPMS_ON (0<<10)
-#define ADPA_DPMS_SUSPEND (1<<10)
-#define ADPA_DPMS_STANDBY (2<<10)
-#define ADPA_DPMS_OFF (3<<10)
-
-#define RING_TAIL 0x00
-#define TAIL_ADDR 0x001FFFF8
-#define RING_HEAD 0x04
-#define HEAD_WRAP_COUNT 0xFFE00000
-#define HEAD_WRAP_ONE 0x00200000
-#define HEAD_ADDR 0x001FFFFC
-#define RING_START 0x08
-#define START_ADDR 0xFFFFF000
-#define RING_LEN 0x0C
-#define RING_NR_PAGES 0x001FF000
-#define RING_REPORT_MASK 0x00000006
-#define RING_REPORT_64K 0x00000002
-#define RING_REPORT_128K 0x00000004
-#define RING_NO_REPORT 0x00000000
-#define RING_VALID_MASK 0x00000001
-#define RING_VALID 0x00000001
-#define RING_INVALID 0x00000000
-
/* Scratch pad debug 0 reg:
*/
#define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000
@@ -736,10 +740,13 @@
#define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f
#define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0
#define DPLL_B_MD 0x06020 /* 965+ only */
+#define DPLL_MD(pipe) _PIPE(pipe, DPLL_A_MD, DPLL_B_MD)
#define FPA0 0x06040
#define FPA1 0x06044
#define FPB0 0x06048
#define FPB1 0x0604c
+#define FP0(pipe) _PIPE(pipe, FPA0, FPB0)
+#define FP1(pipe) _PIPE(pipe, FPA1, FPB1)
#define FP_N_DIV_MASK 0x003f0000
#define FP_N_PINEVIEW_DIV_MASK 0x00ff0000
#define FP_N_DIV_SHIFT 16
@@ -760,6 +767,7 @@
#define DPLLA_TEST_M_BYPASS (1 << 2)
#define DPLLA_INPUT_BUFFER_ENABLE (1 << 0)
#define D_STATE 0x6104
+#define DSTATE_GFX_RESET_I830 (1<<6)
#define DSTATE_PLL_D3_OFF (1<<3)
#define DSTATE_GFX_CLOCK_GATING (1<<1)
#define DSTATE_DOT_CLOCK_GATING (1<<0)
@@ -926,6 +934,8 @@
#define CLKCFG_MEM_800 (3 << 4)
#define CLKCFG_MEM_MASK (7 << 4)
+#define TSC1 0x11001
+#define TSE (1<<0)
#define TR1 0x11006
#define TSFS 0x11020
#define TSFS_SLOPE_MASK 0x0000ff00
@@ -1070,6 +1080,8 @@
#define MEMSTAT_SRC_CTL_STDBY 3
#define RCPREVBSYTUPAVG 0x113b8
#define RCPREVBSYTDNAVG 0x113bc
+#define PMMISC 0x11214
+#define MCPPCE_EN (1<<0) /* enable PM_MSG from PCH->MPC */
#define SDEW 0x1124c
#define CSIEW0 0x11250
#define CSIEW1 0x11254
@@ -1150,6 +1162,15 @@
#define PIPEBSRC 0x6101c
#define BCLRPAT_B 0x61020
+#define HTOTAL(pipe) _PIPE(pipe, HTOTAL_A, HTOTAL_B)
+#define HBLANK(pipe) _PIPE(pipe, HBLANK_A, HBLANK_B)
+#define HSYNC(pipe) _PIPE(pipe, HSYNC_A, HSYNC_B)
+#define VTOTAL(pipe) _PIPE(pipe, VTOTAL_A, VTOTAL_B)
+#define VBLANK(pipe) _PIPE(pipe, VBLANK_A, VBLANK_B)
+#define VSYNC(pipe) _PIPE(pipe, VSYNC_A, VSYNC_B)
+#define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC)
+#define BCLRPAT(pipe) _PIPE(pipe, BCLRPAT_A, BCLRPAT_B)
+
/* VGA port control */
#define ADPA 0x61100
#define ADPA_DAC_ENABLE (1<<31)
@@ -1173,6 +1194,7 @@
#define ADPA_DPMS_STANDBY (2<<10)
#define ADPA_DPMS_OFF (3<<10)
+
/* Hotplug control (945+ only) */
#define PORT_HOTPLUG_EN 0x61110
#define HDMIB_HOTPLUG_INT_EN (1 << 29)
@@ -1331,6 +1353,22 @@
#define LVDS_B0B3_POWER_DOWN (0 << 2)
#define LVDS_B0B3_POWER_UP (3 << 2)
+/* Video Data Island Packet control */
+#define VIDEO_DIP_DATA 0x61178
+#define VIDEO_DIP_CTL 0x61170
+#define VIDEO_DIP_ENABLE (1 << 31)
+#define VIDEO_DIP_PORT_B (1 << 29)
+#define VIDEO_DIP_PORT_C (2 << 29)
+#define VIDEO_DIP_ENABLE_AVI (1 << 21)
+#define VIDEO_DIP_ENABLE_VENDOR (2 << 21)
+#define VIDEO_DIP_ENABLE_SPD (8 << 21)
+#define VIDEO_DIP_SELECT_AVI (0 << 19)
+#define VIDEO_DIP_SELECT_VENDOR (1 << 19)
+#define VIDEO_DIP_SELECT_SPD (3 << 19)
+#define VIDEO_DIP_FREQ_ONCE (0 << 16)
+#define VIDEO_DIP_FREQ_VSYNC (1 << 16)
+#define VIDEO_DIP_FREQ_2VSYNC (2 << 16)
+
/* Panel power sequencing */
#define PP_STATUS 0x61200
#define PP_ON (1 << 31)
@@ -1346,6 +1384,9 @@
#define PP_SEQUENCE_ON (1 << 28)
#define PP_SEQUENCE_OFF (2 << 28)
#define PP_SEQUENCE_MASK 0x30000000
+#define PP_CYCLE_DELAY_ACTIVE (1 << 27)
+#define PP_SEQUENCE_STATE_ON_IDLE (1 << 3)
+#define PP_SEQUENCE_STATE_MASK 0x0000000f
#define PP_CONTROL 0x61204
#define POWER_TARGET_ON (1 << 0)
#define PP_ON_DELAYS 0x61208
@@ -1481,6 +1522,7 @@
# define TV_TEST_MODE_MASK (7 << 0)
#define TV_DAC 0x68004
+# define TV_DAC_SAVE 0x00ffff00
/**
* Reports that DAC state change logic has reported change (RO).
*
@@ -2075,29 +2117,35 @@
/* Display & cursor control */
-/* dithering flag on Ironlake */
-#define PIPE_ENABLE_DITHER (1 << 4)
-#define PIPE_DITHER_TYPE_MASK (3 << 2)
-#define PIPE_DITHER_TYPE_SPATIAL (0 << 2)
-#define PIPE_DITHER_TYPE_ST01 (1 << 2)
/* Pipe A */
#define PIPEADSL 0x70000
-#define DSL_LINEMASK 0x00000fff
+#define DSL_LINEMASK 0x00000fff
#define PIPEACONF 0x70008
-#define PIPEACONF_ENABLE (1<<31)
-#define PIPEACONF_DISABLE 0
-#define PIPEACONF_DOUBLE_WIDE (1<<30)
+#define PIPECONF_ENABLE (1<<31)
+#define PIPECONF_DISABLE 0
+#define PIPECONF_DOUBLE_WIDE (1<<30)
#define I965_PIPECONF_ACTIVE (1<<30)
-#define PIPEACONF_SINGLE_WIDE 0
-#define PIPEACONF_PIPE_UNLOCKED 0
-#define PIPEACONF_PIPE_LOCKED (1<<25)
-#define PIPEACONF_PALETTE 0
-#define PIPEACONF_GAMMA (1<<24)
+#define PIPECONF_SINGLE_WIDE 0
+#define PIPECONF_PIPE_UNLOCKED 0
+#define PIPECONF_PIPE_LOCKED (1<<25)
+#define PIPECONF_PALETTE 0
+#define PIPECONF_GAMMA (1<<24)
#define PIPECONF_FORCE_BORDER (1<<25)
#define PIPECONF_PROGRESSIVE (0 << 21)
#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21)
#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21)
#define PIPECONF_CXSR_DOWNCLOCK (1<<16)
+#define PIPECONF_BPP_MASK (0x000000e0)
+#define PIPECONF_BPP_8 (0<<5)
+#define PIPECONF_BPP_10 (1<<5)
+#define PIPECONF_BPP_6 (2<<5)
+#define PIPECONF_BPP_12 (3<<5)
+#define PIPECONF_DITHER_EN (1<<4)
+#define PIPECONF_DITHER_TYPE_MASK (0x0000000c)
+#define PIPECONF_DITHER_TYPE_SP (0<<2)
+#define PIPECONF_DITHER_TYPE_ST1 (1<<2)
+#define PIPECONF_DITHER_TYPE_ST2 (2<<2)
+#define PIPECONF_DITHER_TYPE_TEMP (3<<2)
#define PIPEASTAT 0x70024
#define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31)
#define PIPE_CRC_ERROR_ENABLE (1UL<<29)
@@ -2128,12 +2176,15 @@
#define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */
#define PIPE_VBLANK_INTERRUPT_STATUS (1UL<<1)
#define PIPE_OVERLAY_UPDATED_STATUS (1UL<<0)
-#define PIPE_BPC_MASK (7 << 5) /* Ironlake */
+#define PIPE_BPC_MASK (7 << 5) /* Ironlake */
#define PIPE_8BPC (0 << 5)
#define PIPE_10BPC (1 << 5)
#define PIPE_6BPC (2 << 5)
#define PIPE_12BPC (3 << 5)
+#define PIPECONF(pipe) _PIPE(pipe, PIPEACONF, PIPEBCONF)
+#define PIPEDSL(pipe) _PIPE(pipe, PIPEADSL, PIPEBDSL)
+
#define DSPARB 0x70030
#define DSPARB_CSTART_MASK (0x7f << 7)
#define DSPARB_CSTART_SHIFT 7
@@ -2206,8 +2257,8 @@
#define WM1_LP_SR_EN (1<<31)
#define WM1_LP_LATENCY_SHIFT 24
#define WM1_LP_LATENCY_MASK (0x7f<<24)
-#define WM1_LP_FBC_LP1_MASK (0xf<<20)
-#define WM1_LP_FBC_LP1_SHIFT 20
+#define WM1_LP_FBC_MASK (0xf<<20)
+#define WM1_LP_FBC_SHIFT 20
#define WM1_LP_SR_MASK (0x1ff<<8)
#define WM1_LP_SR_SHIFT 8
#define WM1_LP_CURSOR_MASK (0x3f)
@@ -2333,6 +2384,14 @@
#define DSPASURF 0x7019C /* 965+ only */
#define DSPATILEOFF 0x701A4 /* 965+ only */
+#define DSPCNTR(plane) _PIPE(plane, DSPACNTR, DSPBCNTR)
+#define DSPADDR(plane) _PIPE(plane, DSPAADDR, DSPBADDR)
+#define DSPSTRIDE(plane) _PIPE(plane, DSPASTRIDE, DSPBSTRIDE)
+#define DSPPOS(plane) _PIPE(plane, DSPAPOS, DSPBPOS)
+#define DSPSIZE(plane) _PIPE(plane, DSPASIZE, DSPBSIZE)
+#define DSPSURF(plane) _PIPE(plane, DSPASURF, DSPBSURF)
+#define DSPTILEOFF(plane) _PIPE(plane, DSPATILEOFF, DSPBTILEOFF)
+
/* VBIOS flags */
#define SWF00 0x71410
#define SWF01 0x71414
@@ -2397,6 +2456,7 @@
#define RR_HW_HIGH_POWER_FRAMES_MASK 0xff00
#define FDI_PLL_BIOS_0 0x46000
+#define FDI_PLL_FB_CLOCK_MASK 0xff
#define FDI_PLL_BIOS_1 0x46004
#define FDI_PLL_BIOS_2 0x46008
#define DISPLAY_PORT_PLL_BIOS_0 0x4600c
@@ -2420,46 +2480,47 @@
#define PIPEA_DATA_M1 0x60030
#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */
#define TU_SIZE_MASK 0x7e000000
-#define PIPEA_DATA_M1_OFFSET 0
+#define PIPE_DATA_M1_OFFSET 0
#define PIPEA_DATA_N1 0x60034
-#define PIPEA_DATA_N1_OFFSET 0
+#define PIPE_DATA_N1_OFFSET 0
#define PIPEA_DATA_M2 0x60038
-#define PIPEA_DATA_M2_OFFSET 0
+#define PIPE_DATA_M2_OFFSET 0
#define PIPEA_DATA_N2 0x6003c
-#define PIPEA_DATA_N2_OFFSET 0
+#define PIPE_DATA_N2_OFFSET 0
#define PIPEA_LINK_M1 0x60040
-#define PIPEA_LINK_M1_OFFSET 0
+#define PIPE_LINK_M1_OFFSET 0
#define PIPEA_LINK_N1 0x60044
-#define PIPEA_LINK_N1_OFFSET 0
+#define PIPE_LINK_N1_OFFSET 0
#define PIPEA_LINK_M2 0x60048
-#define PIPEA_LINK_M2_OFFSET 0
+#define PIPE_LINK_M2_OFFSET 0
#define PIPEA_LINK_N2 0x6004c
-#define PIPEA_LINK_N2_OFFSET 0
+#define PIPE_LINK_N2_OFFSET 0
/* PIPEB timing regs are same start from 0x61000 */
#define PIPEB_DATA_M1 0x61030
-#define PIPEB_DATA_M1_OFFSET 0
#define PIPEB_DATA_N1 0x61034
-#define PIPEB_DATA_N1_OFFSET 0
#define PIPEB_DATA_M2 0x61038
-#define PIPEB_DATA_M2_OFFSET 0
#define PIPEB_DATA_N2 0x6103c
-#define PIPEB_DATA_N2_OFFSET 0
#define PIPEB_LINK_M1 0x61040
-#define PIPEB_LINK_M1_OFFSET 0
#define PIPEB_LINK_N1 0x61044
-#define PIPEB_LINK_N1_OFFSET 0
#define PIPEB_LINK_M2 0x61048
-#define PIPEB_LINK_M2_OFFSET 0
#define PIPEB_LINK_N2 0x6104c
-#define PIPEB_LINK_N2_OFFSET 0
+
+#define PIPE_DATA_M1(pipe) _PIPE(pipe, PIPEA_DATA_M1, PIPEB_DATA_M1)
+#define PIPE_DATA_N1(pipe) _PIPE(pipe, PIPEA_DATA_N1, PIPEB_DATA_N1)
+#define PIPE_DATA_M2(pipe) _PIPE(pipe, PIPEA_DATA_M2, PIPEB_DATA_M2)
+#define PIPE_DATA_N2(pipe) _PIPE(pipe, PIPEA_DATA_N2, PIPEB_DATA_N2)
+#define PIPE_LINK_M1(pipe) _PIPE(pipe, PIPEA_LINK_M1, PIPEB_LINK_M1)
+#define PIPE_LINK_N1(pipe) _PIPE(pipe, PIPEA_LINK_N1, PIPEB_LINK_N1)
+#define PIPE_LINK_M2(pipe) _PIPE(pipe, PIPEA_LINK_M2, PIPEB_LINK_M2)
+#define PIPE_LINK_N2(pipe) _PIPE(pipe, PIPEA_LINK_N2, PIPEB_LINK_N2)
/* CPU panel fitter */
#define PFA_CTL_1 0x68080
@@ -2516,7 +2577,8 @@
#define GT_SYNC_STATUS (1 << 2)
#define GT_USER_INTERRUPT (1 << 0)
#define GT_BSD_USER_INTERRUPT (1 << 5)
-
+#define GT_GEN6_BSD_USER_INTERRUPT (1 << 12)
+#define GT_BLT_USER_INTERRUPT (1 << 22)
#define GTISR 0x44010
#define GTIMR 0x44014
@@ -2551,6 +2613,10 @@
#define SDE_PORTD_HOTPLUG_CPT (1 << 23)
#define SDE_PORTC_HOTPLUG_CPT (1 << 22)
#define SDE_PORTB_HOTPLUG_CPT (1 << 21)
+#define SDE_HOTPLUG_MASK_CPT (SDE_CRT_HOTPLUG_CPT | \
+ SDE_PORTD_HOTPLUG_CPT | \
+ SDE_PORTC_HOTPLUG_CPT | \
+ SDE_PORTB_HOTPLUG_CPT)
#define SDEISR 0xc4000
#define SDEIMR 0xc4004
@@ -2600,11 +2666,14 @@
#define PCH_DPLL_A 0xc6014
#define PCH_DPLL_B 0xc6018
+#define PCH_DPLL(pipe) _PIPE(pipe, PCH_DPLL_A, PCH_DPLL_B)
#define PCH_FPA0 0xc6040
#define PCH_FPA1 0xc6044
#define PCH_FPB0 0xc6048
#define PCH_FPB1 0xc604c
+#define PCH_FP0(pipe) _PIPE(pipe, PCH_FPA0, PCH_FPB0)
+#define PCH_FP1(pipe) _PIPE(pipe, PCH_FPA1, PCH_FPB1)
#define PCH_DPLL_TEST 0xc606c
@@ -2690,6 +2759,13 @@
#define TRANS_VBLANK_B 0xe1010
#define TRANS_VSYNC_B 0xe1014
+#define TRANS_HTOTAL(pipe) _PIPE(pipe, TRANS_HTOTAL_A, TRANS_HTOTAL_B)
+#define TRANS_HBLANK(pipe) _PIPE(pipe, TRANS_HBLANK_A, TRANS_HBLANK_B)
+#define TRANS_HSYNC(pipe) _PIPE(pipe, TRANS_HSYNC_A, TRANS_HSYNC_B)
+#define TRANS_VTOTAL(pipe) _PIPE(pipe, TRANS_VTOTAL_A, TRANS_VTOTAL_B)
+#define TRANS_VBLANK(pipe) _PIPE(pipe, TRANS_VBLANK_A, TRANS_VBLANK_B)
+#define TRANS_VSYNC(pipe) _PIPE(pipe, TRANS_VSYNC_A, TRANS_VSYNC_B)
+
#define TRANSB_DATA_M1 0xe1030
#define TRANSB_DATA_N1 0xe1034
#define TRANSB_DATA_M2 0xe1038
@@ -2701,6 +2777,7 @@
#define TRANSACONF 0xf0008
#define TRANSBCONF 0xf1008
+#define TRANSCONF(plane) _PIPE(plane, TRANSACONF, TRANSBCONF)
#define TRANS_DISABLE (0<<31)
#define TRANS_ENABLE (1<<31)
#define TRANS_STATE_MASK (1<<30)
@@ -2721,10 +2798,15 @@
#define FDI_RXA_CHICKEN 0xc200c
#define FDI_RXB_CHICKEN 0xc2010
#define FDI_RX_PHASE_SYNC_POINTER_ENABLE (1)
+#define FDI_RX_CHICKEN(pipe) _PIPE(pipe, FDI_RXA_CHICKEN, FDI_RXB_CHICKEN)
+
+#define SOUTH_DSPCLK_GATE_D 0xc2020
+#define PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29)
/* CPU: FDI_TX */
#define FDI_TXA_CTL 0x60100
#define FDI_TXB_CTL 0x61100
+#define FDI_TX_CTL(pipe) _PIPE(pipe, FDI_TXA_CTL, FDI_TXB_CTL)
#define FDI_TX_DISABLE (0<<31)
#define FDI_TX_ENABLE (1<<31)
#define FDI_LINK_TRAIN_PATTERN_1 (0<<28)
@@ -2766,8 +2848,8 @@
/* FDI_RX, FDI_X is hard-wired to Transcoder_X */
#define FDI_RXA_CTL 0xf000c
#define FDI_RXB_CTL 0xf100c
+#define FDI_RX_CTL(pipe) _PIPE(pipe, FDI_RXA_CTL, FDI_RXB_CTL)
#define FDI_RX_ENABLE (1<<31)
-#define FDI_RX_DISABLE (0<<31)
/* train, dp width same as FDI_TX */
#define FDI_DP_PORT_WIDTH_X8 (7<<19)
#define FDI_8BPC (0<<16)
@@ -2782,8 +2864,7 @@
#define FDI_FS_ERR_REPORT_ENABLE (1<<9)
#define FDI_FE_ERR_REPORT_ENABLE (1<<8)
#define FDI_RX_ENHANCE_FRAME_ENABLE (1<<6)
-#define FDI_SEL_RAWCLK (0<<4)
-#define FDI_SEL_PCDCLK (1<<4)
+#define FDI_PCDCLK (1<<4)
/* CPT */
#define FDI_AUTO_TRAINING (1<<10)
#define FDI_LINK_TRAIN_PATTERN_1_CPT (0<<8)
@@ -2798,6 +2879,9 @@
#define FDI_RXA_TUSIZE2 0xf0038
#define FDI_RXB_TUSIZE1 0xf1030
#define FDI_RXB_TUSIZE2 0xf1038
+#define FDI_RX_MISC(pipe) _PIPE(pipe, FDI_RXA_MISC, FDI_RXB_MISC)
+#define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, FDI_RXA_TUSIZE1, FDI_RXB_TUSIZE1)
+#define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, FDI_RXA_TUSIZE2, FDI_RXB_TUSIZE2)
/* FDI_RX interrupt register format */
#define FDI_RX_INTER_LANE_ALIGN (1<<10)
@@ -2816,6 +2900,8 @@
#define FDI_RXA_IMR 0xf0018
#define FDI_RXB_IIR 0xf1014
#define FDI_RXB_IMR 0xf1018
+#define FDI_RX_IIR(pipe) _PIPE(pipe, FDI_RXA_IIR, FDI_RXB_IIR)
+#define FDI_RX_IMR(pipe) _PIPE(pipe, FDI_RXA_IMR, FDI_RXB_IMR)
#define FDI_PLL_CTL_1 0xfe000
#define FDI_PLL_CTL_2 0xfe004
@@ -2935,6 +3021,7 @@
#define TRANS_DP_CTL_A 0xe0300
#define TRANS_DP_CTL_B 0xe1300
#define TRANS_DP_CTL_C 0xe2300
+#define TRANS_DP_CTL(pipe) (TRANS_DP_CTL_A + (pipe) * 0x01000)
#define TRANS_DP_OUTPUT_ENABLE (1<<31)
#define TRANS_DP_PORT_SEL_B (0<<29)
#define TRANS_DP_PORT_SEL_C (1<<29)
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 31f08581e93a..989c19d2d959 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -256,7 +256,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
dev_priv->saveFPA1 = I915_READ(FPA1);
dev_priv->saveDPLL_A = I915_READ(DPLL_A);
}
- if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD);
dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A);
dev_priv->saveHBLANK_A = I915_READ(HBLANK_A);
@@ -294,7 +294,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
dev_priv->saveDSPASIZE = I915_READ(DSPASIZE);
dev_priv->saveDSPAPOS = I915_READ(DSPAPOS);
dev_priv->saveDSPAADDR = I915_READ(DSPAADDR);
- if (IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4) {
dev_priv->saveDSPASURF = I915_READ(DSPASURF);
dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF);
}
@@ -313,7 +313,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
dev_priv->saveFPB1 = I915_READ(FPB1);
dev_priv->saveDPLL_B = I915_READ(DPLL_B);
}
- if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD);
dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B);
dev_priv->saveHBLANK_B = I915_READ(HBLANK_B);
@@ -351,7 +351,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE);
dev_priv->saveDSPBPOS = I915_READ(DSPBPOS);
dev_priv->saveDSPBADDR = I915_READ(DSPBADDR);
- if (IS_I965GM(dev) || IS_GM45(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4) {
dev_priv->saveDSPBSURF = I915_READ(DSPBSURF);
dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF);
}
@@ -404,7 +404,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A);
POSTING_READ(dpll_a_reg);
udelay(150);
- if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
POSTING_READ(DPLL_A_MD);
}
@@ -448,7 +448,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR);
I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
- if (IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4) {
I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
}
@@ -473,7 +473,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B);
POSTING_READ(dpll_b_reg);
udelay(150);
- if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
POSTING_READ(DPLL_B_MD);
}
@@ -517,7 +517,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR);
I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
- if (IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4) {
I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
}
@@ -550,7 +550,7 @@ void i915_save_display(struct drm_device *dev)
dev_priv->saveCURBCNTR = I915_READ(CURBCNTR);
dev_priv->saveCURBPOS = I915_READ(CURBPOS);
dev_priv->saveCURBBASE = I915_READ(CURBBASE);
- if (!IS_I9XX(dev))
+ if (IS_GEN2(dev))
dev_priv->saveCURSIZE = I915_READ(CURSIZE);
/* CRT state */
@@ -573,7 +573,7 @@ void i915_save_display(struct drm_device *dev)
dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
dev_priv->saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL);
- if (IS_I965G(dev))
+ if (INTEL_INFO(dev)->gen >= 4)
dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
if (IS_MOBILE(dev) && !IS_I830(dev))
dev_priv->saveLVDS = I915_READ(LVDS);
@@ -664,7 +664,7 @@ void i915_restore_display(struct drm_device *dev)
I915_WRITE(CURBPOS, dev_priv->saveCURBPOS);
I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR);
I915_WRITE(CURBBASE, dev_priv->saveCURBBASE);
- if (!IS_I9XX(dev))
+ if (IS_GEN2(dev))
I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
/* CRT state */
@@ -674,7 +674,7 @@ void i915_restore_display(struct drm_device *dev)
I915_WRITE(ADPA, dev_priv->saveADPA);
/* LVDS state */
- if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2);
if (HAS_PCH_SPLIT(dev)) {
@@ -878,9 +878,7 @@ int i915_restore_state(struct drm_device *dev)
for (i = 0; i < 3; i++)
I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
- /* I2C state */
- intel_i2c_reset_gmbus(dev);
+ intel_i2c_reset(dev);
return 0;
}
-
diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c
new file mode 100644
index 000000000000..65c88f9ba12c
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_acpi.c
@@ -0,0 +1,286 @@
+/*
+ * Intel ACPI functions
+ *
+ * _DSM related code stolen from nouveau_acpi.c.
+ */
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <linux/vga_switcheroo.h>
+#include <acpi/acpi_drivers.h>
+
+#include "drmP.h"
+
+#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
+
+#define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */
+#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
+
+static struct intel_dsm_priv {
+ acpi_handle dhandle;
+} intel_dsm_priv;
+
+static const u8 intel_dsm_guid[] = {
+ 0xd3, 0x73, 0xd8, 0x7e,
+ 0xd0, 0xc2,
+ 0x4f, 0x4e,
+ 0xa8, 0x54,
+ 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c
+};
+
+static int intel_dsm(acpi_handle handle, int func, int arg)
+{
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_object_list input;
+ union acpi_object params[4];
+ union acpi_object *obj;
+ u32 result;
+ int ret = 0;
+
+ input.count = 4;
+ input.pointer = params;
+ params[0].type = ACPI_TYPE_BUFFER;
+ params[0].buffer.length = sizeof(intel_dsm_guid);
+ params[0].buffer.pointer = (char *)intel_dsm_guid;
+ params[1].type = ACPI_TYPE_INTEGER;
+ params[1].integer.value = INTEL_DSM_REVISION_ID;
+ params[2].type = ACPI_TYPE_INTEGER;
+ params[2].integer.value = func;
+ params[3].type = ACPI_TYPE_INTEGER;
+ params[3].integer.value = arg;
+
+ ret = acpi_evaluate_object(handle, "_DSM", &input, &output);
+ if (ret) {
+ DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
+ return ret;
+ }
+
+ obj = (union acpi_object *)output.pointer;
+
+ result = 0;
+ switch (obj->type) {
+ case ACPI_TYPE_INTEGER:
+ result = obj->integer.value;
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ if (obj->buffer.length == 4) {
+ result =(obj->buffer.pointer[0] |
+ (obj->buffer.pointer[1] << 8) |
+ (obj->buffer.pointer[2] << 16) |
+ (obj->buffer.pointer[3] << 24));
+ break;
+ }
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (result == 0x80000002)
+ ret = -ENODEV;
+
+ kfree(output.pointer);
+ return ret;
+}
+
+static char *intel_dsm_port_name(u8 id)
+{
+ switch (id) {
+ case 0:
+ return "Reserved";
+ case 1:
+ return "Analog VGA";
+ case 2:
+ return "LVDS";
+ case 3:
+ return "Reserved";
+ case 4:
+ return "HDMI/DVI_B";
+ case 5:
+ return "HDMI/DVI_C";
+ case 6:
+ return "HDMI/DVI_D";
+ case 7:
+ return "DisplayPort_A";
+ case 8:
+ return "DisplayPort_B";
+ case 9:
+ return "DisplayPort_C";
+ case 0xa:
+ return "DisplayPort_D";
+ case 0xb:
+ case 0xc:
+ case 0xd:
+ return "Reserved";
+ case 0xe:
+ return "WiDi";
+ default:
+ return "bad type";
+ }
+}
+
+static char *intel_dsm_mux_type(u8 type)
+{
+ switch (type) {
+ case 0:
+ return "unknown";
+ case 1:
+ return "No MUX, iGPU only";
+ case 2:
+ return "No MUX, dGPU only";
+ case 3:
+ return "MUXed between iGPU and dGPU";
+ default:
+ return "bad type";
+ }
+}
+
+static void intel_dsm_platform_mux_info(void)
+{
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_object_list input;
+ union acpi_object params[4];
+ union acpi_object *pkg;
+ int i, ret;
+
+ input.count = 4;
+ input.pointer = params;
+ params[0].type = ACPI_TYPE_BUFFER;
+ params[0].buffer.length = sizeof(intel_dsm_guid);
+ params[0].buffer.pointer = (char *)intel_dsm_guid;
+ params[1].type = ACPI_TYPE_INTEGER;
+ params[1].integer.value = INTEL_DSM_REVISION_ID;
+ params[2].type = ACPI_TYPE_INTEGER;
+ params[2].integer.value = INTEL_DSM_FN_PLATFORM_MUX_INFO;
+ params[3].type = ACPI_TYPE_INTEGER;
+ params[3].integer.value = 0;
+
+ ret = acpi_evaluate_object(intel_dsm_priv.dhandle, "_DSM", &input,
+ &output);
+ if (ret) {
+ DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
+ goto out;
+ }
+
+ pkg = (union acpi_object *)output.pointer;
+
+ if (pkg->type == ACPI_TYPE_PACKAGE) {
+ union acpi_object *connector_count = &pkg->package.elements[0];
+ DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
+ (unsigned long long)connector_count->integer.value);
+ for (i = 1; i < pkg->package.count; i++) {
+ union acpi_object *obj = &pkg->package.elements[i];
+ union acpi_object *connector_id =
+ &obj->package.elements[0];
+ union acpi_object *info = &obj->package.elements[1];
+ DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
+ (unsigned long long)connector_id->integer.value);
+ DRM_DEBUG_DRIVER(" port id: %s\n",
+ intel_dsm_port_name(info->buffer.pointer[0]));
+ DRM_DEBUG_DRIVER(" display mux info: %s\n",
+ intel_dsm_mux_type(info->buffer.pointer[1]));
+ DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n",
+ intel_dsm_mux_type(info->buffer.pointer[2]));
+ DRM_DEBUG_DRIVER(" hpd mux info: %s\n",
+ intel_dsm_mux_type(info->buffer.pointer[3]));
+ }
+ } else {
+ DRM_ERROR("MUX INFO call failed\n");
+ }
+
+out:
+ kfree(output.pointer);
+}
+
+static int intel_dsm_switchto(enum vga_switcheroo_client_id id)
+{
+ return 0;
+}
+
+static int intel_dsm_power_state(enum vga_switcheroo_client_id id,
+ enum vga_switcheroo_state state)
+{
+ return 0;
+}
+
+static int intel_dsm_init(void)
+{
+ return 0;
+}
+
+static int intel_dsm_get_client_id(struct pci_dev *pdev)
+{
+ if (intel_dsm_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
+ return VGA_SWITCHEROO_IGD;
+ else
+ return VGA_SWITCHEROO_DIS;
+}
+
+static struct vga_switcheroo_handler intel_dsm_handler = {
+ .switchto = intel_dsm_switchto,
+ .power_state = intel_dsm_power_state,
+ .init = intel_dsm_init,
+ .get_client_id = intel_dsm_get_client_id,
+};
+
+static bool intel_dsm_pci_probe(struct pci_dev *pdev)
+{
+ acpi_handle dhandle, intel_handle;
+ acpi_status status;
+ int ret;
+
+ dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
+ if (!dhandle)
+ return false;
+
+ status = acpi_get_handle(dhandle, "_DSM", &intel_handle);
+ if (ACPI_FAILURE(status)) {
+ DRM_DEBUG_KMS("no _DSM method for intel device\n");
+ return false;
+ }
+
+ ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS, 0);
+ if (ret < 0) {
+ DRM_ERROR("failed to get supported _DSM functions\n");
+ return false;
+ }
+
+ intel_dsm_priv.dhandle = dhandle;
+
+ intel_dsm_platform_mux_info();
+ return true;
+}
+
+static bool intel_dsm_detect(void)
+{
+ char acpi_method_name[255] = { 0 };
+ struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
+ struct pci_dev *pdev = NULL;
+ bool has_dsm = false;
+ int vga_count = 0;
+
+ while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
+ vga_count++;
+ has_dsm |= intel_dsm_pci_probe(pdev);
+ }
+
+ if (vga_count == 2 && has_dsm) {
+ acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
+ DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n",
+ acpi_method_name);
+ return true;
+ }
+
+ return false;
+}
+
+void intel_register_dsm_handler(void)
+{
+ if (!intel_dsm_detect())
+ return;
+
+ vga_switcheroo_register_handler(&intel_dsm_handler);
+}
+
+void intel_unregister_dsm_handler(void)
+{
+ vga_switcheroo_unregister_handler();
+}
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 96f75d7f6633..b0b1200ed650 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -24,6 +24,7 @@
* Eric Anholt <eric@anholt.net>
*
*/
+#include <drm/drm_dp_helper.h>
#include "drmP.h"
#include "drm.h"
#include "i915_drm.h"
@@ -129,10 +130,6 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
int i, temp_downclock;
struct drm_display_mode *temp_mode;
- /* Defaults if we can't find VBT info */
- dev_priv->lvds_dither = 0;
- dev_priv->lvds_vbt = 0;
-
lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
if (!lvds_options)
return;
@@ -140,6 +137,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
dev_priv->lvds_dither = lvds_options->pixel_dither;
if (lvds_options->panel_type == 0xff)
return;
+
panel_type = lvds_options->panel_type;
lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
@@ -169,6 +167,8 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
((unsigned char *)entry + dvo_timing_offset);
panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
+ if (!panel_fixed_mode)
+ return;
fill_detail_timing_data(panel_fixed_mode, dvo_timing);
@@ -230,8 +230,6 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv,
struct lvds_dvo_timing *dvo_timing;
struct drm_display_mode *panel_fixed_mode;
- dev_priv->sdvo_lvds_vbt_mode = NULL;
-
sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS);
if (!sdvo_lvds_options)
return;
@@ -260,10 +258,6 @@ parse_general_features(struct drm_i915_private *dev_priv,
struct drm_device *dev = dev_priv->dev;
struct bdb_general_features *general;
- /* Set sensible defaults in case we can't find the general block */
- dev_priv->int_tv_support = 1;
- dev_priv->int_crt_support = 1;
-
general = find_section(bdb, BDB_GENERAL_FEATURES);
if (general) {
dev_priv->int_tv_support = general->int_tv_support;
@@ -271,10 +265,10 @@ parse_general_features(struct drm_i915_private *dev_priv,
dev_priv->lvds_use_ssc = general->enable_ssc;
if (dev_priv->lvds_use_ssc) {
- if (IS_I85X(dev_priv->dev))
+ if (IS_I85X(dev))
dev_priv->lvds_ssc_freq =
general->ssc_freq ? 66 : 48;
- else if (IS_IRONLAKE(dev_priv->dev) || IS_GEN6(dev))
+ else if (IS_GEN5(dev) || IS_GEN6(dev))
dev_priv->lvds_ssc_freq =
general->ssc_freq ? 100 : 120;
else
@@ -289,14 +283,6 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
struct bdb_header *bdb)
{
struct bdb_general_definitions *general;
- const int crt_bus_map_table[] = {
- GPIOB,
- GPIOA,
- GPIOC,
- GPIOD,
- GPIOE,
- GPIOF,
- };
general = find_section(bdb, BDB_GENERAL_DEFINITIONS);
if (general) {
@@ -304,10 +290,8 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
if (block_size >= sizeof(*general)) {
int bus_pin = general->crt_ddc_gmbus_pin;
DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin);
- if ((bus_pin >= 1) && (bus_pin <= 6)) {
- dev_priv->crt_ddc_bus =
- crt_bus_map_table[bus_pin-1];
- }
+ if (bus_pin >= 1 && bus_pin <= 6)
+ dev_priv->crt_ddc_pin = bus_pin;
} else {
DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n",
block_size);
@@ -317,7 +301,7 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
static void
parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
- struct bdb_header *bdb)
+ struct bdb_header *bdb)
{
struct sdvo_device_mapping *p_mapping;
struct bdb_general_definitions *p_defs;
@@ -327,7 +311,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
if (!p_defs) {
- DRM_DEBUG_KMS("No general definition block is found\n");
+ DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n");
return;
}
/* judge whether the size of child device meets the requirements.
@@ -377,7 +361,16 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
p_mapping->slave_addr = p_child->slave_addr;
p_mapping->dvo_wiring = p_child->dvo_wiring;
p_mapping->ddc_pin = p_child->ddc_pin;
+ p_mapping->i2c_pin = p_child->i2c_pin;
+ p_mapping->i2c_speed = p_child->i2c_speed;
p_mapping->initialized = 1;
+ DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d, i2c_speed=%d\n",
+ p_mapping->dvo_port,
+ p_mapping->slave_addr,
+ p_mapping->dvo_wiring,
+ p_mapping->ddc_pin,
+ p_mapping->i2c_pin,
+ p_mapping->i2c_speed);
} else {
DRM_DEBUG_KMS("Maybe one SDVO port is shared by "
"two SDVO device.\n");
@@ -409,14 +402,11 @@ parse_driver_features(struct drm_i915_private *dev_priv,
if (!driver)
return;
- if (driver && SUPPORTS_EDP(dev) &&
- driver->lvds_config == BDB_DRIVER_FEATURE_EDP) {
- dev_priv->edp_support = 1;
- } else {
- dev_priv->edp_support = 0;
- }
+ if (SUPPORTS_EDP(dev) &&
+ driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
+ dev_priv->edp.support = 1;
- if (driver && driver->dual_frequency)
+ if (driver->dual_frequency)
dev_priv->render_reclock_avail = true;
}
@@ -424,27 +414,78 @@ static void
parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
{
struct bdb_edp *edp;
+ struct edp_power_seq *edp_pps;
+ struct edp_link_params *edp_link_params;
edp = find_section(bdb, BDB_EDP);
if (!edp) {
- if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp_support) {
+ if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) {
DRM_DEBUG_KMS("No eDP BDB found but eDP panel "
- "supported, assume 18bpp panel color "
- "depth.\n");
- dev_priv->edp_bpp = 18;
+ "supported, assume %dbpp panel color "
+ "depth.\n",
+ dev_priv->edp.bpp);
}
return;
}
switch ((edp->color_depth >> (panel_type * 2)) & 3) {
case EDP_18BPP:
- dev_priv->edp_bpp = 18;
+ dev_priv->edp.bpp = 18;
break;
case EDP_24BPP:
- dev_priv->edp_bpp = 24;
+ dev_priv->edp.bpp = 24;
break;
case EDP_30BPP:
- dev_priv->edp_bpp = 30;
+ dev_priv->edp.bpp = 30;
+ break;
+ }
+
+ /* Get the eDP sequencing and link info */
+ edp_pps = &edp->power_seqs[panel_type];
+ edp_link_params = &edp->link_params[panel_type];
+
+ dev_priv->edp.pps = *edp_pps;
+
+ dev_priv->edp.rate = edp_link_params->rate ? DP_LINK_BW_2_7 :
+ DP_LINK_BW_1_62;
+ switch (edp_link_params->lanes) {
+ case 0:
+ dev_priv->edp.lanes = 1;
+ break;
+ case 1:
+ dev_priv->edp.lanes = 2;
+ break;
+ case 3:
+ default:
+ dev_priv->edp.lanes = 4;
+ break;
+ }
+ switch (edp_link_params->preemphasis) {
+ case 0:
+ dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
+ break;
+ case 1:
+ dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
+ break;
+ case 2:
+ dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
+ break;
+ case 3:
+ dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
+ break;
+ }
+ switch (edp_link_params->vswing) {
+ case 0:
+ dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400;
+ break;
+ case 1:
+ dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600;
+ break;
+ case 2:
+ dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800;
+ break;
+ case 3:
+ dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200;
break;
}
}
@@ -460,7 +501,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
if (!p_defs) {
- DRM_DEBUG_KMS("No general definition block is found\n");
+ DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
return;
}
/* judge whether the size of child device meets the requirements.
@@ -513,50 +554,83 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
}
return;
}
+
+static void
+init_vbt_defaults(struct drm_i915_private *dev_priv)
+{
+ dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC;
+
+ /* LFP panel data */
+ dev_priv->lvds_dither = 1;
+ dev_priv->lvds_vbt = 0;
+
+ /* SDVO panel data */
+ dev_priv->sdvo_lvds_vbt_mode = NULL;
+
+ /* general features */
+ dev_priv->int_tv_support = 1;
+ dev_priv->int_crt_support = 1;
+ dev_priv->lvds_use_ssc = 0;
+
+ /* eDP data */
+ dev_priv->edp.bpp = 18;
+}
+
/**
- * intel_init_bios - initialize VBIOS settings & find VBT
+ * intel_parse_bios - find VBT and initialize settings from the BIOS
* @dev: DRM device
*
* Loads the Video BIOS and checks that the VBT exists. Sets scratch registers
* to appropriate values.
*
- * VBT existence is a sanity check that is relied on by other i830_bios.c code.
- * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may
- * feed an updated VBT back through that, compared to what we'll fetch using
- * this method of groping around in the BIOS data.
- *
* Returns 0 on success, nonzero on failure.
*/
bool
-intel_init_bios(struct drm_device *dev)
+intel_parse_bios(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct pci_dev *pdev = dev->pdev;
- struct vbt_header *vbt = NULL;
- struct bdb_header *bdb;
- u8 __iomem *bios;
- size_t size;
- int i;
-
- bios = pci_map_rom(pdev, &size);
- if (!bios)
- return -1;
-
- /* Scour memory looking for the VBT signature */
- for (i = 0; i + 4 < size; i++) {
- if (!memcmp(bios + i, "$VBT", 4)) {
- vbt = (struct vbt_header *)(bios + i);
- break;
- }
+ struct bdb_header *bdb = NULL;
+ u8 __iomem *bios = NULL;
+
+ init_vbt_defaults(dev_priv);
+
+ /* XXX Should this validation be moved to intel_opregion.c? */
+ if (dev_priv->opregion.vbt) {
+ struct vbt_header *vbt = dev_priv->opregion.vbt;
+ if (memcmp(vbt->signature, "$VBT", 4) == 0) {
+ DRM_DEBUG_DRIVER("Using VBT from OpRegion: %20s\n",
+ vbt->signature);
+ bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset);
+ } else
+ dev_priv->opregion.vbt = NULL;
}
- if (!vbt) {
- DRM_ERROR("VBT signature missing\n");
- pci_unmap_rom(pdev, bios);
- return -1;
- }
+ if (bdb == NULL) {
+ struct vbt_header *vbt = NULL;
+ size_t size;
+ int i;
- bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
+ bios = pci_map_rom(pdev, &size);
+ if (!bios)
+ return -1;
+
+ /* Scour memory looking for the VBT signature */
+ for (i = 0; i + 4 < size; i++) {
+ if (!memcmp(bios + i, "$VBT", 4)) {
+ vbt = (struct vbt_header *)(bios + i);
+ break;
+ }
+ }
+
+ if (!vbt) {
+ DRM_ERROR("VBT signature missing\n");
+ pci_unmap_rom(pdev, bios);
+ return -1;
+ }
+
+ bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
+ }
/* Grab useful general definitions */
parse_general_features(dev_priv, bdb);
@@ -568,7 +642,25 @@ intel_init_bios(struct drm_device *dev)
parse_driver_features(dev_priv, bdb);
parse_edp(dev_priv, bdb);
- pci_unmap_rom(pdev, bios);
+ if (bios)
+ pci_unmap_rom(pdev, bios);
return 0;
}
+
+/* Ensure that vital registers have been initialised, even if the BIOS
+ * is absent or just failing to do its job.
+ */
+void intel_setup_bios(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ /* Set the Panel Power On/Off timings if uninitialized. */
+ if ((I915_READ(PP_ON_DELAYS) == 0) && (I915_READ(PP_OFF_DELAYS) == 0)) {
+ /* Set T2 to 40ms and T5 to 200ms */
+ I915_WRITE(PP_ON_DELAYS, 0x019007d0);
+
+ /* Set T3 to 35ms and Tx to 200ms */
+ I915_WRITE(PP_OFF_DELAYS, 0x015e07d0);
+ }
+}
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index 4c18514f6f80..5f8e4edcbbb9 100644
--- a/drivers/gpu/drm/i915/intel_bios.h
+++ b/drivers/gpu/drm/i915/intel_bios.h
@@ -197,7 +197,8 @@ struct bdb_general_features {
struct child_device_config {
u16 handle;
u16 device_type;
- u8 device_id[10]; /* See DEVICE_TYPE_* above */
+ u8 i2c_speed;
+ u8 rsvd[9];
u16 addin_offset;
u8 dvo_port; /* See Device_PORT_* above */
u8 i2c_pin;
@@ -466,7 +467,8 @@ struct bdb_edp {
struct edp_link_params link_params[16];
} __attribute__ ((packed));
-bool intel_init_bios(struct drm_device *dev);
+void intel_setup_bios(struct drm_device *dev);
+bool intel_parse_bios(struct drm_device *dev);
/*
* Driver<->VBIOS interaction occurs through scratch bits in
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 197d4f32585a..c55c77043357 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -79,7 +79,7 @@ static int intel_crt_mode_valid(struct drm_connector *connector,
if (mode->clock < 25000)
return MODE_CLOCK_LOW;
- if (!IS_I9XX(dev))
+ if (IS_GEN2(dev))
max_clock = 350000;
else
max_clock = 400000;
@@ -123,7 +123,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
* Disable separate mode multiplier used when cloning SDVO to CRT
* XXX this needs to be adjusted when we really are cloning
*/
- if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
dpll_md = I915_READ(dpll_md_reg);
I915_WRITE(dpll_md_reg,
dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
@@ -187,11 +187,12 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
I915_WRITE(PCH_ADPA, adpa);
if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
- 1000, 1))
+ 1000))
DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
if (turn_off_dac) {
- I915_WRITE(PCH_ADPA, temp);
+ /* Make sure hotplug is enabled */
+ I915_WRITE(PCH_ADPA, temp | ADPA_CRT_HOTPLUG_ENABLE);
(void)I915_READ(PCH_ADPA);
}
@@ -244,7 +245,7 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
/* wait for FORCE_DETECT to go off */
if (wait_for((I915_READ(PORT_HOTPLUG_EN) &
CRT_HOTPLUG_FORCE_DETECT) == 0,
- 1000, 1))
+ 1000))
DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off");
}
@@ -261,21 +262,47 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
return ret;
}
+static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus)
+{
+ u8 buf;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = 0xA0,
+ .flags = 0,
+ .len = 1,
+ .buf = &buf,
+ },
+ };
+ /* DDC monitor detect: Does it ACK a write to 0xA0? */
+ return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1;
+}
+
static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
{
- struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
+ struct drm_i915_private *dev_priv = encoder->dev->dev_private;
/* CRT should always be at 0, but check anyway */
if (intel_encoder->type != INTEL_OUTPUT_ANALOG)
return false;
- return intel_ddc_probe(intel_encoder);
+ if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) {
+ DRM_DEBUG_KMS("CRT detected via DDC:0xa0\n");
+ return true;
+ }
+
+ if (intel_ddc_probe(intel_encoder, dev_priv->crt_ddc_pin)) {
+ DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
+ return true;
+ }
+
+ return false;
}
static enum drm_connector_status
intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder)
{
- struct drm_encoder *encoder = &intel_encoder->enc;
+ struct drm_encoder *encoder = &intel_encoder->base;
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -295,6 +322,8 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder
uint8_t st00;
enum drm_connector_status status;
+ DRM_DEBUG_KMS("starting load-detect on CRT\n");
+
if (pipe == 0) {
bclrpat_reg = BCLRPAT_A;
vtotal_reg = VTOTAL_A;
@@ -324,9 +353,10 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder
/* Set the border color to purple. */
I915_WRITE(bclrpat_reg, 0x500050);
- if (IS_I9XX(dev)) {
+ if (!IS_GEN2(dev)) {
uint32_t pipeconf = I915_READ(pipeconf_reg);
I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
+ POSTING_READ(pipeconf_reg);
/* Wait for next Vblank to substitue
* border color for Color info */
intel_wait_for_vblank(dev, pipe);
@@ -404,34 +434,37 @@ static enum drm_connector_status
intel_crt_detect(struct drm_connector *connector, bool force)
{
struct drm_device *dev = connector->dev;
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_encoder *encoder = intel_attached_encoder(connector);
struct drm_crtc *crtc;
int dpms_mode;
enum drm_connector_status status;
- if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
- if (intel_crt_detect_hotplug(connector))
+ if (I915_HAS_HOTPLUG(dev)) {
+ if (intel_crt_detect_hotplug(connector)) {
+ DRM_DEBUG_KMS("CRT detected via hotplug\n");
return connector_status_connected;
- else
+ } else
return connector_status_disconnected;
}
- if (intel_crt_detect_ddc(encoder))
+ if (intel_crt_detect_ddc(&encoder->base))
return connector_status_connected;
if (!force)
return connector->status;
/* for pre-945g platforms use load detect */
- if (encoder->crtc && encoder->crtc->enabled) {
- status = intel_crt_load_detect(encoder->crtc, intel_encoder);
+ if (encoder->base.crtc && encoder->base.crtc->enabled) {
+ status = intel_crt_load_detect(encoder->base.crtc, encoder);
} else {
- crtc = intel_get_load_detect_pipe(intel_encoder, connector,
+ crtc = intel_get_load_detect_pipe(encoder, connector,
NULL, &dpms_mode);
if (crtc) {
- status = intel_crt_load_detect(crtc, intel_encoder);
- intel_release_load_detect_pipe(intel_encoder,
+ if (intel_crt_detect_ddc(&encoder->base))
+ status = connector_status_connected;
+ else
+ status = intel_crt_load_detect(crtc, encoder);
+ intel_release_load_detect_pipe(encoder,
connector, dpms_mode);
} else
status = connector_status_unknown;
@@ -449,32 +482,18 @@ static void intel_crt_destroy(struct drm_connector *connector)
static int intel_crt_get_modes(struct drm_connector *connector)
{
- int ret;
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
- struct i2c_adapter *ddc_bus;
struct drm_device *dev = connector->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret;
-
- ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
+ ret = intel_ddc_get_modes(connector,
+ &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
if (ret || !IS_G4X(dev))
- goto end;
+ return ret;
/* Try to probe digital port for output in DVI-I -> VGA mode. */
- ddc_bus = intel_i2c_create(connector->dev, GPIOD, "CRTDDC_D");
-
- if (!ddc_bus) {
- dev_printk(KERN_ERR, &connector->dev->pdev->dev,
- "DDC bus registration failed for CRTDDC_D.\n");
- goto end;
- }
- /* Try to get modes by GPIOD port */
- ret = intel_ddc_get_modes(connector, ddc_bus);
- intel_i2c_destroy(ddc_bus);
-
-end:
- return ret;
-
+ return intel_ddc_get_modes(connector,
+ &dev_priv->gmbus[GMBUS_PORT_DPB].adapter);
}
static int intel_crt_set_property(struct drm_connector *connector,
@@ -507,7 +526,7 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = {
static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = {
.mode_valid = intel_crt_mode_valid,
.get_modes = intel_crt_get_modes,
- .best_encoder = intel_attached_encoder,
+ .best_encoder = intel_best_encoder,
};
static const struct drm_encoder_funcs intel_crt_enc_funcs = {
@@ -520,7 +539,6 @@ void intel_crt_init(struct drm_device *dev)
struct intel_encoder *intel_encoder;
struct intel_connector *intel_connector;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 i2c_reg;
intel_encoder = kzalloc(sizeof(struct intel_encoder), GFP_KERNEL);
if (!intel_encoder)
@@ -536,27 +554,10 @@ void intel_crt_init(struct drm_device *dev)
drm_connector_init(dev, &intel_connector->base,
&intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
- drm_encoder_init(dev, &intel_encoder->enc, &intel_crt_enc_funcs,
+ drm_encoder_init(dev, &intel_encoder->base, &intel_crt_enc_funcs,
DRM_MODE_ENCODER_DAC);
- drm_mode_connector_attach_encoder(&intel_connector->base,
- &intel_encoder->enc);
-
- /* Set up the DDC bus. */
- if (HAS_PCH_SPLIT(dev))
- i2c_reg = PCH_GPIOA;
- else {
- i2c_reg = GPIOA;
- /* Use VBT information for CRT DDC if available */
- if (dev_priv->crt_ddc_bus != 0)
- i2c_reg = dev_priv->crt_ddc_bus;
- }
- intel_encoder->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A");
- if (!intel_encoder->ddc_bus) {
- dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
- "failed.\n");
- return;
- }
+ intel_connector_attach_encoder(intel_connector, intel_encoder);
intel_encoder->type = INTEL_OUTPUT_ANALOG;
intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
@@ -566,7 +567,7 @@ void intel_crt_init(struct drm_device *dev)
connector->interlace_allowed = 1;
connector->doublescan_allowed = 0;
- drm_encoder_helper_add(&intel_encoder->enc, &intel_crt_helper_funcs);
+ drm_encoder_helper_add(&intel_encoder->base, &intel_crt_helper_funcs);
drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
drm_sysfs_connector_add(connector);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 979228594599..990f065374b2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -43,8 +43,8 @@
bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
static void intel_update_watermarks(struct drm_device *dev);
-static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule);
-static void intel_crtc_update_cursor(struct drm_crtc *crtc);
+static void intel_increase_pllclock(struct drm_crtc *crtc);
+static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
typedef struct {
/* given values */
@@ -342,6 +342,16 @@ static bool
intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock);
+static inline u32 /* units of 100MHz */
+intel_fdi_link_freq(struct drm_device *dev)
+{
+ if (IS_GEN5(dev)) {
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ return (I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK) + 2;
+ } else
+ return 27;
+}
+
static const intel_limit_t intel_limits_i8xx_dvo = {
.dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX },
.vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX },
@@ -701,16 +711,16 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
limit = intel_ironlake_limit(crtc);
else if (IS_G4X(dev)) {
limit = intel_g4x_limit(crtc);
- } else if (IS_I9XX(dev) && !IS_PINEVIEW(dev)) {
- if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
- limit = &intel_limits_i9xx_lvds;
- else
- limit = &intel_limits_i9xx_sdvo;
} else if (IS_PINEVIEW(dev)) {
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
limit = &intel_limits_pineview_lvds;
else
limit = &intel_limits_pineview_sdvo;
+ } else if (!IS_GEN2(dev)) {
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+ limit = &intel_limits_i9xx_lvds;
+ else
+ limit = &intel_limits_i9xx_sdvo;
} else {
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
limit = &intel_limits_i8xx_lvds;
@@ -744,20 +754,17 @@ static void intel_clock(struct drm_device *dev, int refclk, intel_clock_t *clock
/**
* Returns whether any output on the specified pipe is of the specified type
*/
-bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
+bool intel_pipe_has_type(struct drm_crtc *crtc, int type)
{
- struct drm_device *dev = crtc->dev;
- struct drm_mode_config *mode_config = &dev->mode_config;
- struct drm_encoder *l_entry;
+ struct drm_device *dev = crtc->dev;
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ struct intel_encoder *encoder;
+
+ list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
+ if (encoder->base.crtc == crtc && encoder->type == type)
+ return true;
- list_for_each_entry(l_entry, &mode_config->encoder_list, head) {
- if (l_entry && l_entry->crtc == crtc) {
- struct intel_encoder *intel_encoder = enc_to_intel_encoder(l_entry);
- if (intel_encoder->type == type)
- return true;
- }
- }
- return false;
+ return false;
}
#define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0)
@@ -928,10 +935,6 @@ intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
struct drm_device *dev = crtc->dev;
intel_clock_t clock;
- /* return directly when it is eDP */
- if (HAS_eDP)
- return true;
-
if (target < 200000) {
clock.n = 1;
clock.p1 = 2;
@@ -955,26 +958,26 @@ static bool
intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock)
{
- intel_clock_t clock;
- if (target < 200000) {
- clock.p1 = 2;
- clock.p2 = 10;
- clock.n = 2;
- clock.m1 = 23;
- clock.m2 = 8;
- } else {
- clock.p1 = 1;
- clock.p2 = 10;
- clock.n = 1;
- clock.m1 = 14;
- clock.m2 = 2;
- }
- clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
- clock.p = (clock.p1 * clock.p2);
- clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
- clock.vco = 0;
- memcpy(best_clock, &clock, sizeof(intel_clock_t));
- return true;
+ intel_clock_t clock;
+ if (target < 200000) {
+ clock.p1 = 2;
+ clock.p2 = 10;
+ clock.n = 2;
+ clock.m1 = 23;
+ clock.m2 = 8;
+ } else {
+ clock.p1 = 1;
+ clock.p2 = 10;
+ clock.n = 1;
+ clock.m1 = 14;
+ clock.m2 = 2;
+ }
+ clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
+ clock.p = (clock.p1 * clock.p2);
+ clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
+ clock.vco = 0;
+ memcpy(best_clock, &clock, sizeof(intel_clock_t));
+ return true;
}
/**
@@ -1007,9 +1010,9 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
I915_READ(pipestat_reg) | PIPE_VBLANK_INTERRUPT_STATUS);
/* Wait for vblank interrupt bit to set */
- if (wait_for((I915_READ(pipestat_reg) &
- PIPE_VBLANK_INTERRUPT_STATUS),
- 50, 0))
+ if (wait_for(I915_READ(pipestat_reg) &
+ PIPE_VBLANK_INTERRUPT_STATUS,
+ 50))
DRM_DEBUG_KMS("vblank wait timed out\n");
}
@@ -1028,36 +1031,35 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
* Otherwise:
* wait for the display line value to settle (it usually
* ends up stopping at the start of the next frame).
- *
+ *
*/
-static void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
+void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
if (INTEL_INFO(dev)->gen >= 4) {
- int pipeconf_reg = (pipe == 0 ? PIPEACONF : PIPEBCONF);
+ int reg = PIPECONF(pipe);
/* Wait for the Pipe State to go off */
- if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0,
- 100, 0))
+ if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0,
+ 100))
DRM_DEBUG_KMS("pipe_off wait timed out\n");
} else {
u32 last_line;
- int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL);
+ int reg = PIPEDSL(pipe);
unsigned long timeout = jiffies + msecs_to_jiffies(100);
/* Wait for the display line to settle */
do {
- last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK;
+ last_line = I915_READ(reg) & DSL_LINEMASK;
mdelay(5);
- } while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) &&
+ } while (((I915_READ(reg) & DSL_LINEMASK) != last_line) &&
time_after(timeout, jiffies));
if (time_after(jiffies, timeout))
DRM_DEBUG_KMS("pipe_off wait timed out\n");
}
}
-/* Parameters have changed, update FBC info */
static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
{
struct drm_device *dev = crtc->dev;
@@ -1069,6 +1071,14 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
int plane, i;
u32 fbc_ctl, fbc_ctl2;
+ if (fb->pitch == dev_priv->cfb_pitch &&
+ obj_priv->fence_reg == dev_priv->cfb_fence &&
+ intel_crtc->plane == dev_priv->cfb_plane &&
+ I915_READ(FBC_CONTROL) & FBC_CTL_EN)
+ return;
+
+ i8xx_disable_fbc(dev);
+
dev_priv->cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;
if (fb->pitch < dev_priv->cfb_pitch)
@@ -1102,7 +1112,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
I915_WRITE(FBC_CONTROL, fbc_ctl);
DRM_DEBUG_KMS("enabled FBC, pitch %ld, yoff %d, plane %d, ",
- dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
+ dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
}
void i8xx_disable_fbc(struct drm_device *dev)
@@ -1110,19 +1120,16 @@ void i8xx_disable_fbc(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
u32 fbc_ctl;
- if (!I915_HAS_FBC(dev))
- return;
-
- if (!(I915_READ(FBC_CONTROL) & FBC_CTL_EN))
- return; /* Already off, just return */
-
/* Disable compression */
fbc_ctl = I915_READ(FBC_CONTROL);
+ if ((fbc_ctl & FBC_CTL_EN) == 0)
+ return;
+
fbc_ctl &= ~FBC_CTL_EN;
I915_WRITE(FBC_CONTROL, fbc_ctl);
/* Wait for compressing bit to clear */
- if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10, 0)) {
+ if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
DRM_DEBUG_KMS("FBC idle timed out\n");
return;
}
@@ -1145,14 +1152,27 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int plane = (intel_crtc->plane == 0 ? DPFC_CTL_PLANEA :
- DPFC_CTL_PLANEB);
+ int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
unsigned long stall_watermark = 200;
u32 dpfc_ctl;
+ dpfc_ctl = I915_READ(DPFC_CONTROL);
+ if (dpfc_ctl & DPFC_CTL_EN) {
+ if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
+ dev_priv->cfb_fence == obj_priv->fence_reg &&
+ dev_priv->cfb_plane == intel_crtc->plane &&
+ dev_priv->cfb_y == crtc->y)
+ return;
+
+ I915_WRITE(DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
+ POSTING_READ(DPFC_CONTROL);
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
+ }
+
dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
dev_priv->cfb_fence = obj_priv->fence_reg;
dev_priv->cfb_plane = intel_crtc->plane;
+ dev_priv->cfb_y = crtc->y;
dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
if (obj_priv->tiling_mode != I915_TILING_NONE) {
@@ -1162,7 +1182,6 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
I915_WRITE(DPFC_CHICKEN, ~DPFC_HT_MODIFY);
}
- I915_WRITE(DPFC_CONTROL, dpfc_ctl);
I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
(stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
(interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
@@ -1181,10 +1200,12 @@ void g4x_disable_fbc(struct drm_device *dev)
/* Disable compression */
dpfc_ctl = I915_READ(DPFC_CONTROL);
- dpfc_ctl &= ~DPFC_CTL_EN;
- I915_WRITE(DPFC_CONTROL, dpfc_ctl);
+ if (dpfc_ctl & DPFC_CTL_EN) {
+ dpfc_ctl &= ~DPFC_CTL_EN;
+ I915_WRITE(DPFC_CONTROL, dpfc_ctl);
- DRM_DEBUG_KMS("disabled FBC\n");
+ DRM_DEBUG_KMS("disabled FBC\n");
+ }
}
static bool g4x_fbc_enabled(struct drm_device *dev)
@@ -1202,16 +1223,30 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int plane = (intel_crtc->plane == 0) ? DPFC_CTL_PLANEA :
- DPFC_CTL_PLANEB;
+ int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
unsigned long stall_watermark = 200;
u32 dpfc_ctl;
+ dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
+ if (dpfc_ctl & DPFC_CTL_EN) {
+ if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
+ dev_priv->cfb_fence == obj_priv->fence_reg &&
+ dev_priv->cfb_plane == intel_crtc->plane &&
+ dev_priv->cfb_offset == obj_priv->gtt_offset &&
+ dev_priv->cfb_y == crtc->y)
+ return;
+
+ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
+ POSTING_READ(ILK_DPFC_CONTROL);
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
+ }
+
dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
dev_priv->cfb_fence = obj_priv->fence_reg;
dev_priv->cfb_plane = intel_crtc->plane;
+ dev_priv->cfb_offset = obj_priv->gtt_offset;
+ dev_priv->cfb_y = crtc->y;
- dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
dpfc_ctl &= DPFC_RESERVED;
dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
if (obj_priv->tiling_mode != I915_TILING_NONE) {
@@ -1221,15 +1256,13 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
I915_WRITE(ILK_DPFC_CHICKEN, ~DPFC_HT_MODIFY);
}
- I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
(stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
(interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
I915_WRITE(ILK_FBC_RT_BASE, obj_priv->gtt_offset | ILK_FBC_RT_VALID);
/* enable it... */
- I915_WRITE(ILK_DPFC_CONTROL, I915_READ(ILK_DPFC_CONTROL) |
- DPFC_CTL_EN);
+ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
}
@@ -1241,10 +1274,12 @@ void ironlake_disable_fbc(struct drm_device *dev)
/* Disable compression */
dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
- dpfc_ctl &= ~DPFC_CTL_EN;
- I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
+ if (dpfc_ctl & DPFC_CTL_EN) {
+ dpfc_ctl &= ~DPFC_CTL_EN;
+ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
- DRM_DEBUG_KMS("disabled FBC\n");
+ DRM_DEBUG_KMS("disabled FBC\n");
+ }
}
static bool ironlake_fbc_enabled(struct drm_device *dev)
@@ -1286,8 +1321,7 @@ void intel_disable_fbc(struct drm_device *dev)
/**
* intel_update_fbc - enable/disable FBC as needed
- * @crtc: CRTC to point the compressor at
- * @mode: mode in use
+ * @dev: the drm_device
*
* Set up the framebuffer compression hardware at mode set time. We
* enable it if possible:
@@ -1304,18 +1338,14 @@ void intel_disable_fbc(struct drm_device *dev)
*
* We need to enable/disable FBC on a global basis.
*/
-static void intel_update_fbc(struct drm_crtc *crtc,
- struct drm_display_mode *mode)
+static void intel_update_fbc(struct drm_device *dev)
{
- struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_framebuffer *fb = crtc->fb;
+ struct drm_crtc *crtc = NULL, *tmp_crtc;
+ struct intel_crtc *intel_crtc;
+ struct drm_framebuffer *fb;
struct intel_framebuffer *intel_fb;
struct drm_i915_gem_object *obj_priv;
- struct drm_crtc *tmp_crtc;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int plane = intel_crtc->plane;
- int crtcs_enabled = 0;
DRM_DEBUG_KMS("\n");
@@ -1325,12 +1355,6 @@ static void intel_update_fbc(struct drm_crtc *crtc,
if (!I915_HAS_FBC(dev))
return;
- if (!crtc->fb)
- return;
-
- intel_fb = to_intel_framebuffer(fb);
- obj_priv = to_intel_bo(intel_fb->obj);
-
/*
* If FBC is already on, we just have to verify that we can
* keep it that way...
@@ -1341,35 +1365,47 @@ static void intel_update_fbc(struct drm_crtc *crtc,
* - going to an unsupported config (interlace, pixel multiply, etc.)
*/
list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) {
- if (tmp_crtc->enabled)
- crtcs_enabled++;
+ if (tmp_crtc->enabled) {
+ if (crtc) {
+ DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
+ dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
+ goto out_disable;
+ }
+ crtc = tmp_crtc;
+ }
}
- DRM_DEBUG_KMS("%d pipes active\n", crtcs_enabled);
- if (crtcs_enabled > 1) {
- DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
- dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
+
+ if (!crtc || crtc->fb == NULL) {
+ DRM_DEBUG_KMS("no output, disabling\n");
+ dev_priv->no_fbc_reason = FBC_NO_OUTPUT;
goto out_disable;
}
+
+ intel_crtc = to_intel_crtc(crtc);
+ fb = crtc->fb;
+ intel_fb = to_intel_framebuffer(fb);
+ obj_priv = to_intel_bo(intel_fb->obj);
+
if (intel_fb->obj->size > dev_priv->cfb_size) {
DRM_DEBUG_KMS("framebuffer too large, disabling "
- "compression\n");
+ "compression\n");
dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
goto out_disable;
}
- if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
- (mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
+ if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) ||
+ (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) {
DRM_DEBUG_KMS("mode incompatible with compression, "
- "disabling\n");
+ "disabling\n");
dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
goto out_disable;
}
- if ((mode->hdisplay > 2048) ||
- (mode->vdisplay > 1536)) {
+ if ((crtc->mode.hdisplay > 2048) ||
+ (crtc->mode.vdisplay > 1536)) {
DRM_DEBUG_KMS("mode too large for compression, disabling\n");
dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE;
goto out_disable;
}
- if ((IS_I915GM(dev) || IS_I945GM(dev)) && plane != 0) {
+ if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) {
DRM_DEBUG_KMS("plane not 0, disabling compression\n");
dev_priv->no_fbc_reason = FBC_BAD_PLANE;
goto out_disable;
@@ -1384,18 +1420,7 @@ static void intel_update_fbc(struct drm_crtc *crtc,
if (in_dbg_master())
goto out_disable;
- if (intel_fbc_enabled(dev)) {
- /* We can re-enable it in this case, but need to update pitch */
- if ((fb->pitch > dev_priv->cfb_pitch) ||
- (obj_priv->fence_reg != dev_priv->cfb_fence) ||
- (plane != dev_priv->cfb_plane))
- intel_disable_fbc(dev);
- }
-
- /* Now try to turn it back on if possible */
- if (!intel_fbc_enabled(dev))
- intel_enable_fbc(crtc, 500);
-
+ intel_enable_fbc(crtc, 500);
return;
out_disable:
@@ -1407,7 +1432,9 @@ out_disable:
}
int
-intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
+intel_pin_and_fence_fb_obj(struct drm_device *dev,
+ struct drm_gem_object *obj,
+ bool pipelined)
{
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
u32 alignment;
@@ -1417,7 +1444,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
case I915_TILING_NONE:
if (IS_BROADWATER(dev) || IS_CRESTLINE(dev))
alignment = 128 * 1024;
- else if (IS_I965G(dev))
+ else if (INTEL_INFO(dev)->gen >= 4)
alignment = 4 * 1024;
else
alignment = 64 * 1024;
@@ -1435,9 +1462,13 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
}
ret = i915_gem_object_pin(obj, alignment);
- if (ret != 0)
+ if (ret)
return ret;
+ ret = i915_gem_object_set_to_display_plane(obj, pipelined);
+ if (ret)
+ goto err_unpin;
+
/* Install a fence for tiled scan-out. Pre-i965 always needs a
* fence, whereas 965+ only requires a fence if using
* framebuffer compression. For simplicity, we always install
@@ -1445,20 +1476,22 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
*/
if (obj_priv->fence_reg == I915_FENCE_REG_NONE &&
obj_priv->tiling_mode != I915_TILING_NONE) {
- ret = i915_gem_object_get_fence_reg(obj);
- if (ret != 0) {
- i915_gem_object_unpin(obj);
- return ret;
- }
+ ret = i915_gem_object_get_fence_reg(obj, false);
+ if (ret)
+ goto err_unpin;
}
return 0;
+
+err_unpin:
+ i915_gem_object_unpin(obj);
+ return ret;
}
/* Assume fb object is pinned & idle & fenced and just update base pointers */
static int
intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
- int x, int y)
+ int x, int y, enum mode_set_atomic state)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1468,12 +1501,8 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
struct drm_gem_object *obj;
int plane = intel_crtc->plane;
unsigned long Start, Offset;
- int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR);
- int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF);
- int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
- int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF);
- int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
u32 dspcntr;
+ u32 reg;
switch (plane) {
case 0:
@@ -1488,7 +1517,8 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
obj = intel_fb->obj;
obj_priv = to_intel_bo(obj);
- dspcntr = I915_READ(dspcntr_reg);
+ reg = DSPCNTR(plane);
+ dspcntr = I915_READ(reg);
/* Mask out pixel format bits in case we change it */
dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
switch (fb->bits_per_pixel) {
@@ -1509,7 +1539,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
DRM_ERROR("Unknown color depth\n");
return -EINVAL;
}
- if (IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4) {
if (obj_priv->tiling_mode != I915_TILING_NONE)
dspcntr |= DISPPLANE_TILED;
else
@@ -1520,28 +1550,24 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
/* must disable */
dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
- I915_WRITE(dspcntr_reg, dspcntr);
+ I915_WRITE(reg, dspcntr);
Start = obj_priv->gtt_offset;
Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8);
DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
Start, Offset, x, y, fb->pitch);
- I915_WRITE(dspstride, fb->pitch);
- if (IS_I965G(dev)) {
- I915_WRITE(dspsurf, Start);
- I915_WRITE(dsptileoff, (y << 16) | x);
- I915_WRITE(dspbase, Offset);
- } else {
- I915_WRITE(dspbase, Start + Offset);
- }
- POSTING_READ(dspbase);
-
- if (IS_I965G(dev) || plane == 0)
- intel_update_fbc(crtc, &crtc->mode);
+ I915_WRITE(DSPSTRIDE(plane), fb->pitch);
+ if (INTEL_INFO(dev)->gen >= 4) {
+ I915_WRITE(DSPSURF(plane), Start);
+ I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
+ I915_WRITE(DSPADDR(plane), Offset);
+ } else
+ I915_WRITE(DSPADDR(plane), Start + Offset);
+ POSTING_READ(reg);
- intel_wait_for_vblank(dev, intel_crtc->pipe);
- intel_increase_pllclock(crtc, true);
+ intel_update_fbc(dev);
+ intel_increase_pllclock(crtc);
return 0;
}
@@ -1553,11 +1579,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_device *dev = crtc->dev;
struct drm_i915_master_private *master_priv;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct intel_framebuffer *intel_fb;
- struct drm_i915_gem_object *obj_priv;
- struct drm_gem_object *obj;
- int pipe = intel_crtc->pipe;
- int plane = intel_crtc->plane;
int ret;
/* no fb bound */
@@ -1566,45 +1587,42 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
return 0;
}
- switch (plane) {
+ switch (intel_crtc->plane) {
case 0:
case 1:
break;
default:
- DRM_ERROR("Can't update plane %d in SAREA\n", plane);
return -EINVAL;
}
- intel_fb = to_intel_framebuffer(crtc->fb);
- obj = intel_fb->obj;
- obj_priv = to_intel_bo(obj);
-
mutex_lock(&dev->struct_mutex);
- ret = intel_pin_and_fence_fb_obj(dev, obj);
+ ret = intel_pin_and_fence_fb_obj(dev,
+ to_intel_framebuffer(crtc->fb)->obj,
+ false);
if (ret != 0) {
mutex_unlock(&dev->struct_mutex);
return ret;
}
- ret = i915_gem_object_set_to_display_plane(obj);
- if (ret != 0) {
- i915_gem_object_unpin(obj);
- mutex_unlock(&dev->struct_mutex);
- return ret;
+ if (old_fb) {
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_gem_object *obj = to_intel_framebuffer(old_fb)->obj;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+
+ wait_event(dev_priv->pending_flip_queue,
+ atomic_read(&obj_priv->pending_flip) == 0);
}
- ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y);
+ ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
+ LEAVE_ATOMIC_MODE_SET);
if (ret) {
- i915_gem_object_unpin(obj);
+ i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
mutex_unlock(&dev->struct_mutex);
return ret;
}
- if (old_fb) {
- intel_fb = to_intel_framebuffer(old_fb);
- obj_priv = to_intel_bo(intel_fb->obj);
- i915_gem_object_unpin(intel_fb->obj);
- }
+ if (old_fb)
+ i915_gem_object_unpin(to_intel_framebuffer(old_fb)->obj);
mutex_unlock(&dev->struct_mutex);
@@ -1615,7 +1633,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
if (!master_priv->sarea_priv)
return 0;
- if (pipe) {
+ if (intel_crtc->pipe) {
master_priv->sarea_priv->pipeB_x = x;
master_priv->sarea_priv->pipeB_y = y;
} else {
@@ -1626,7 +1644,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
return 0;
}
-static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock)
+static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1659,6 +1677,7 @@ static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock)
}
I915_WRITE(DP_A, dpa_ctl);
+ POSTING_READ(DP_A);
udelay(500);
}
@@ -1669,84 +1688,109 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
- int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
- int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
- int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
- u32 temp, tries = 0;
+ u32 reg, temp, tries;
/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
for train result */
- temp = I915_READ(fdi_rx_imr_reg);
+ reg = FDI_RX_IMR(pipe);
+ temp = I915_READ(reg);
temp &= ~FDI_RX_SYMBOL_LOCK;
temp &= ~FDI_RX_BIT_LOCK;
- I915_WRITE(fdi_rx_imr_reg, temp);
- I915_READ(fdi_rx_imr_reg);
+ I915_WRITE(reg, temp);
+ I915_READ(reg);
udelay(150);
/* enable CPU FDI TX and PCH FDI RX */
- temp = I915_READ(fdi_tx_reg);
- temp |= FDI_TX_ENABLE;
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
temp &= ~(7 << 19);
temp |= (intel_crtc->fdi_lanes - 1) << 19;
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_1;
- I915_WRITE(fdi_tx_reg, temp);
- I915_READ(fdi_tx_reg);
+ I915_WRITE(reg, temp | FDI_TX_ENABLE);
- temp = I915_READ(fdi_rx_reg);
+ reg = FDI_RX_CTL(pipe);
+ temp = I915_READ(reg);
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_1;
- I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
- I915_READ(fdi_rx_reg);
+ I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+ POSTING_READ(reg);
udelay(150);
+ /* Ironlake workaround, enable clock pointer after FDI enable*/
+ I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_ENABLE);
+
+ reg = FDI_RX_IIR(pipe);
for (tries = 0; tries < 5; tries++) {
- temp = I915_READ(fdi_rx_iir_reg);
+ temp = I915_READ(reg);
DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
if ((temp & FDI_RX_BIT_LOCK)) {
DRM_DEBUG_KMS("FDI train 1 done.\n");
- I915_WRITE(fdi_rx_iir_reg,
- temp | FDI_RX_BIT_LOCK);
+ I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
break;
}
}
if (tries == 5)
- DRM_DEBUG_KMS("FDI train 1 fail!\n");
+ DRM_ERROR("FDI train 1 fail!\n");
/* Train 2 */
- temp = I915_READ(fdi_tx_reg);
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_2;
- I915_WRITE(fdi_tx_reg, temp);
+ I915_WRITE(reg, temp);
- temp = I915_READ(fdi_rx_reg);
+ reg = FDI_RX_CTL(pipe);
+ temp = I915_READ(reg);
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_2;
- I915_WRITE(fdi_rx_reg, temp);
- udelay(150);
+ I915_WRITE(reg, temp);
- tries = 0;
+ POSTING_READ(reg);
+ udelay(150);
+ reg = FDI_RX_IIR(pipe);
for (tries = 0; tries < 5; tries++) {
- temp = I915_READ(fdi_rx_iir_reg);
+ temp = I915_READ(reg);
DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
if (temp & FDI_RX_SYMBOL_LOCK) {
- I915_WRITE(fdi_rx_iir_reg,
- temp | FDI_RX_SYMBOL_LOCK);
+ I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
DRM_DEBUG_KMS("FDI train 2 done.\n");
break;
}
}
if (tries == 5)
- DRM_DEBUG_KMS("FDI train 2 fail!\n");
+ DRM_ERROR("FDI train 2 fail!\n");
DRM_DEBUG_KMS("FDI train done\n");
+
+ /* enable normal train */
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+ I915_WRITE(reg, temp);
+
+ reg = FDI_RX_CTL(pipe);
+ temp = I915_READ(reg);
+ if (HAS_PCH_CPT(dev)) {
+ temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+ temp |= FDI_LINK_TRAIN_NORMAL_CPT;
+ } else {
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ temp |= FDI_LINK_TRAIN_NONE;
+ }
+ I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
+
+ /* wait one idle pattern time */
+ POSTING_READ(reg);
+ udelay(1000);
}
-static int snb_b_fdi_train_param [] = {
+static const int const snb_b_fdi_train_param [] = {
FDI_LINK_TRAIN_400MV_0DB_SNB_B,
FDI_LINK_TRAIN_400MV_6DB_SNB_B,
FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
@@ -1760,24 +1804,22 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
- int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
- int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
- int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
- u32 temp, i;
+ u32 reg, temp, i;
/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
for train result */
- temp = I915_READ(fdi_rx_imr_reg);
+ reg = FDI_RX_IMR(pipe);
+ temp = I915_READ(reg);
temp &= ~FDI_RX_SYMBOL_LOCK;
temp &= ~FDI_RX_BIT_LOCK;
- I915_WRITE(fdi_rx_imr_reg, temp);
- I915_READ(fdi_rx_imr_reg);
+ I915_WRITE(reg, temp);
+
+ POSTING_READ(reg);
udelay(150);
/* enable CPU FDI TX and PCH FDI RX */
- temp = I915_READ(fdi_tx_reg);
- temp |= FDI_TX_ENABLE;
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
temp &= ~(7 << 19);
temp |= (intel_crtc->fdi_lanes - 1) << 19;
temp &= ~FDI_LINK_TRAIN_NONE;
@@ -1785,10 +1827,10 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
/* SNB-B */
temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
- I915_WRITE(fdi_tx_reg, temp);
- I915_READ(fdi_tx_reg);
+ I915_WRITE(reg, temp | FDI_TX_ENABLE);
- temp = I915_READ(fdi_rx_reg);
+ reg = FDI_RX_CTL(pipe);
+ temp = I915_READ(reg);
if (HAS_PCH_CPT(dev)) {
temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
@@ -1796,32 +1838,37 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_1;
}
- I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
- I915_READ(fdi_rx_reg);
+ I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+ POSTING_READ(reg);
udelay(150);
for (i = 0; i < 4; i++ ) {
- temp = I915_READ(fdi_tx_reg);
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
temp |= snb_b_fdi_train_param[i];
- I915_WRITE(fdi_tx_reg, temp);
+ I915_WRITE(reg, temp);
+
+ POSTING_READ(reg);
udelay(500);
- temp = I915_READ(fdi_rx_iir_reg);
+ reg = FDI_RX_IIR(pipe);
+ temp = I915_READ(reg);
DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
if (temp & FDI_RX_BIT_LOCK) {
- I915_WRITE(fdi_rx_iir_reg,
- temp | FDI_RX_BIT_LOCK);
+ I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
DRM_DEBUG_KMS("FDI train 1 done.\n");
break;
}
}
if (i == 4)
- DRM_DEBUG_KMS("FDI train 1 fail!\n");
+ DRM_ERROR("FDI train 1 fail!\n");
/* Train 2 */
- temp = I915_READ(fdi_tx_reg);
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_2;
if (IS_GEN6(dev)) {
@@ -1829,9 +1876,10 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
/* SNB-B */
temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
}
- I915_WRITE(fdi_tx_reg, temp);
+ I915_WRITE(reg, temp);
- temp = I915_READ(fdi_rx_reg);
+ reg = FDI_RX_CTL(pipe);
+ temp = I915_READ(reg);
if (HAS_PCH_CPT(dev)) {
temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
@@ -1839,535 +1887,593 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_2;
}
- I915_WRITE(fdi_rx_reg, temp);
+ I915_WRITE(reg, temp);
+
+ POSTING_READ(reg);
udelay(150);
for (i = 0; i < 4; i++ ) {
- temp = I915_READ(fdi_tx_reg);
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
temp |= snb_b_fdi_train_param[i];
- I915_WRITE(fdi_tx_reg, temp);
+ I915_WRITE(reg, temp);
+
+ POSTING_READ(reg);
udelay(500);
- temp = I915_READ(fdi_rx_iir_reg);
+ reg = FDI_RX_IIR(pipe);
+ temp = I915_READ(reg);
DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
if (temp & FDI_RX_SYMBOL_LOCK) {
- I915_WRITE(fdi_rx_iir_reg,
- temp | FDI_RX_SYMBOL_LOCK);
+ I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
DRM_DEBUG_KMS("FDI train 2 done.\n");
break;
}
}
if (i == 4)
- DRM_DEBUG_KMS("FDI train 2 fail!\n");
+ DRM_ERROR("FDI train 2 fail!\n");
DRM_DEBUG_KMS("FDI train done.\n");
}
-static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
+static void ironlake_fdi_enable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- int plane = intel_crtc->plane;
- int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
- int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
- int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
- int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
- int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
- int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
- int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
- int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
- int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
- int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
- int cpu_vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
- int cpu_vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
- int cpu_vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
- int trans_htot_reg = (pipe == 0) ? TRANS_HTOTAL_A : TRANS_HTOTAL_B;
- int trans_hblank_reg = (pipe == 0) ? TRANS_HBLANK_A : TRANS_HBLANK_B;
- int trans_hsync_reg = (pipe == 0) ? TRANS_HSYNC_A : TRANS_HSYNC_B;
- int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B;
- int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B;
- int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
- int trans_dpll_sel = (pipe == 0) ? 0 : 1;
- u32 temp;
- u32 pipe_bpc;
-
- temp = I915_READ(pipeconf_reg);
- pipe_bpc = temp & PIPE_BPC_MASK;
+ u32 reg, temp;
- /* XXX: When our outputs are all unaware of DPMS modes other than off
- * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
- */
- switch (mode) {
- case DRM_MODE_DPMS_ON:
- case DRM_MODE_DPMS_STANDBY:
- case DRM_MODE_DPMS_SUSPEND:
- DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane);
+ /* Write the TU size bits so error detection works */
+ I915_WRITE(FDI_RX_TUSIZE1(pipe),
+ I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
- if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
- temp = I915_READ(PCH_LVDS);
- if ((temp & LVDS_PORT_EN) == 0) {
- I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
- POSTING_READ(PCH_LVDS);
- }
- }
+ /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
+ reg = FDI_RX_CTL(pipe);
+ temp = I915_READ(reg);
+ temp &= ~((0x7 << 19) | (0x7 << 16));
+ temp |= (intel_crtc->fdi_lanes - 1) << 19;
+ temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+ I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
- if (!HAS_eDP) {
+ POSTING_READ(reg);
+ udelay(200);
- /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
- temp = I915_READ(fdi_rx_reg);
- /*
- * make the BPC in FDI Rx be consistent with that in
- * pipeconf reg.
- */
- temp &= ~(0x7 << 16);
- temp |= (pipe_bpc << 11);
- temp &= ~(7 << 19);
- temp |= (intel_crtc->fdi_lanes - 1) << 19;
- I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
- I915_READ(fdi_rx_reg);
- udelay(200);
+ /* Switch from Rawclk to PCDclk */
+ temp = I915_READ(reg);
+ I915_WRITE(reg, temp | FDI_PCDCLK);
- /* Switch from Rawclk to PCDclk */
- temp = I915_READ(fdi_rx_reg);
- I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK);
- I915_READ(fdi_rx_reg);
- udelay(200);
+ POSTING_READ(reg);
+ udelay(200);
- /* Enable CPU FDI TX PLL, always on for Ironlake */
- temp = I915_READ(fdi_tx_reg);
- if ((temp & FDI_TX_PLL_ENABLE) == 0) {
- I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
- I915_READ(fdi_tx_reg);
- udelay(100);
- }
- }
+ /* Enable CPU FDI TX PLL, always on for Ironlake */
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
+ if ((temp & FDI_TX_PLL_ENABLE) == 0) {
+ I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
- /* Enable panel fitting for LVDS */
- if (dev_priv->pch_pf_size &&
- (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)
- || HAS_eDP || intel_pch_has_edp(crtc))) {
- /* Force use of hard-coded filter coefficients
- * as some pre-programmed values are broken,
- * e.g. x201.
- */
- I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1,
- PF_ENABLE | PF_FILTER_MED_3x3);
- I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS,
- dev_priv->pch_pf_pos);
- I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ,
- dev_priv->pch_pf_size);
- }
+ POSTING_READ(reg);
+ udelay(100);
+ }
+}
- /* Enable CPU pipe */
- temp = I915_READ(pipeconf_reg);
- if ((temp & PIPEACONF_ENABLE) == 0) {
- I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
- I915_READ(pipeconf_reg);
- udelay(100);
- }
+static void intel_flush_display_plane(struct drm_device *dev,
+ int plane)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 reg = DSPADDR(plane);
+ I915_WRITE(reg, I915_READ(reg));
+}
- /* configure and enable CPU plane */
- temp = I915_READ(dspcntr_reg);
- if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
- I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
- /* Flush the plane changes */
- I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
- }
+/*
+ * When we disable a pipe, we need to clear any pending scanline wait events
+ * to avoid hanging the ring, which we assume we are waiting on.
+ */
+static void intel_clear_scanline_wait(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 tmp;
- if (!HAS_eDP) {
- /* For PCH output, training FDI link */
- if (IS_GEN6(dev))
- gen6_fdi_link_train(crtc);
- else
- ironlake_fdi_link_train(crtc);
+ if (IS_GEN2(dev))
+ /* Can't break the hang on i8xx */
+ return;
- /* enable PCH DPLL */
- temp = I915_READ(pch_dpll_reg);
- if ((temp & DPLL_VCO_ENABLE) == 0) {
- I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
- I915_READ(pch_dpll_reg);
- }
- udelay(200);
+ tmp = I915_READ(PRB0_CTL);
+ if (tmp & RING_WAIT) {
+ I915_WRITE(PRB0_CTL, tmp);
+ POSTING_READ(PRB0_CTL);
+ }
+}
- if (HAS_PCH_CPT(dev)) {
- /* Be sure PCH DPLL SEL is set */
- temp = I915_READ(PCH_DPLL_SEL);
- if (trans_dpll_sel == 0 &&
- (temp & TRANSA_DPLL_ENABLE) == 0)
- temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
- else if (trans_dpll_sel == 1 &&
- (temp & TRANSB_DPLL_ENABLE) == 0)
- temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
- I915_WRITE(PCH_DPLL_SEL, temp);
- I915_READ(PCH_DPLL_SEL);
- }
+static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
+{
+ struct drm_i915_gem_object *obj_priv;
+ struct drm_i915_private *dev_priv;
- /* set transcoder timing */
- I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg));
- I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg));
- I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg));
-
- I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg));
- I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg));
- I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg));
-
- /* enable normal train */
- temp = I915_READ(fdi_tx_reg);
- temp &= ~FDI_LINK_TRAIN_NONE;
- I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
- FDI_TX_ENHANCE_FRAME_ENABLE);
- I915_READ(fdi_tx_reg);
-
- temp = I915_READ(fdi_rx_reg);
- if (HAS_PCH_CPT(dev)) {
- temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
- temp |= FDI_LINK_TRAIN_NORMAL_CPT;
- } else {
- temp &= ~FDI_LINK_TRAIN_NONE;
- temp |= FDI_LINK_TRAIN_NONE;
- }
- I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
- I915_READ(fdi_rx_reg);
+ if (crtc->fb == NULL)
+ return;
- /* wait one idle pattern time */
- udelay(100);
+ obj_priv = to_intel_bo(to_intel_framebuffer(crtc->fb)->obj);
+ dev_priv = crtc->dev->dev_private;
+ wait_event(dev_priv->pending_flip_queue,
+ atomic_read(&obj_priv->pending_flip) == 0);
+}
- /* For PCH DP, enable TRANS_DP_CTL */
- if (HAS_PCH_CPT(dev) &&
- intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
- int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B;
- int reg;
-
- reg = I915_READ(trans_dp_ctl);
- reg &= ~(TRANS_DP_PORT_SEL_MASK |
- TRANS_DP_SYNC_MASK);
- reg |= (TRANS_DP_OUTPUT_ENABLE |
- TRANS_DP_ENH_FRAMING);
-
- if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
- reg |= TRANS_DP_HSYNC_ACTIVE_HIGH;
- if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
- reg |= TRANS_DP_VSYNC_ACTIVE_HIGH;
-
- switch (intel_trans_dp_port_sel(crtc)) {
- case PCH_DP_B:
- reg |= TRANS_DP_PORT_SEL_B;
- break;
- case PCH_DP_C:
- reg |= TRANS_DP_PORT_SEL_C;
- break;
- case PCH_DP_D:
- reg |= TRANS_DP_PORT_SEL_D;
- break;
- default:
- DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n");
- reg |= TRANS_DP_PORT_SEL_B;
- break;
- }
+static void ironlake_crtc_enable(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+ int plane = intel_crtc->plane;
+ u32 reg, temp;
- I915_WRITE(trans_dp_ctl, reg);
- POSTING_READ(trans_dp_ctl);
- }
+ if (intel_crtc->active)
+ return;
- /* enable PCH transcoder */
- temp = I915_READ(transconf_reg);
- /*
- * make the BPC in transcoder be consistent with
- * that in pipeconf reg.
- */
- temp &= ~PIPE_BPC_MASK;
- temp |= pipe_bpc;
- I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
- I915_READ(transconf_reg);
+ intel_crtc->active = true;
+ intel_update_watermarks(dev);
- if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 100, 1))
- DRM_ERROR("failed to enable transcoder\n");
- }
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+ temp = I915_READ(PCH_LVDS);
+ if ((temp & LVDS_PORT_EN) == 0)
+ I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
+ }
- intel_crtc_load_lut(crtc);
+ ironlake_fdi_enable(crtc);
- intel_update_fbc(crtc, &crtc->mode);
- break;
+ /* Enable panel fitting for LVDS */
+ if (dev_priv->pch_pf_size &&
+ (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || HAS_eDP)) {
+ /* Force use of hard-coded filter coefficients
+ * as some pre-programmed values are broken,
+ * e.g. x201.
+ */
+ I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1,
+ PF_ENABLE | PF_FILTER_MED_3x3);
+ I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS,
+ dev_priv->pch_pf_pos);
+ I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ,
+ dev_priv->pch_pf_size);
+ }
+
+ /* Enable CPU pipe */
+ reg = PIPECONF(pipe);
+ temp = I915_READ(reg);
+ if ((temp & PIPECONF_ENABLE) == 0) {
+ I915_WRITE(reg, temp | PIPECONF_ENABLE);
+ POSTING_READ(reg);
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
+ }
+
+ /* configure and enable CPU plane */
+ reg = DSPCNTR(plane);
+ temp = I915_READ(reg);
+ if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+ I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE);
+ intel_flush_display_plane(dev, plane);
+ }
+
+ /* For PCH output, training FDI link */
+ if (IS_GEN6(dev))
+ gen6_fdi_link_train(crtc);
+ else
+ ironlake_fdi_link_train(crtc);
+
+ /* enable PCH DPLL */
+ reg = PCH_DPLL(pipe);
+ temp = I915_READ(reg);
+ if ((temp & DPLL_VCO_ENABLE) == 0) {
+ I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
+ POSTING_READ(reg);
+ udelay(200);
+ }
- case DRM_MODE_DPMS_OFF:
- DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane);
+ if (HAS_PCH_CPT(dev)) {
+ /* Be sure PCH DPLL SEL is set */
+ temp = I915_READ(PCH_DPLL_SEL);
+ if (pipe == 0 && (temp & TRANSA_DPLL_ENABLE) == 0)
+ temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+ else if (pipe == 1 && (temp & TRANSB_DPLL_ENABLE) == 0)
+ temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+ I915_WRITE(PCH_DPLL_SEL, temp);
+ }
- drm_vblank_off(dev, pipe);
- /* Disable display plane */
- temp = I915_READ(dspcntr_reg);
- if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
- I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
- /* Flush the plane changes */
- I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
- I915_READ(dspbase_reg);
+ /* set transcoder timing */
+ I915_WRITE(TRANS_HTOTAL(pipe), I915_READ(HTOTAL(pipe)));
+ I915_WRITE(TRANS_HBLANK(pipe), I915_READ(HBLANK(pipe)));
+ I915_WRITE(TRANS_HSYNC(pipe), I915_READ(HSYNC(pipe)));
+
+ I915_WRITE(TRANS_VTOTAL(pipe), I915_READ(VTOTAL(pipe)));
+ I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe)));
+ I915_WRITE(TRANS_VSYNC(pipe), I915_READ(VSYNC(pipe)));
+
+ /* For PCH DP, enable TRANS_DP_CTL */
+ if (HAS_PCH_CPT(dev) &&
+ intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+ reg = TRANS_DP_CTL(pipe);
+ temp = I915_READ(reg);
+ temp &= ~(TRANS_DP_PORT_SEL_MASK |
+ TRANS_DP_SYNC_MASK);
+ temp |= (TRANS_DP_OUTPUT_ENABLE |
+ TRANS_DP_ENH_FRAMING);
+
+ if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
+ temp |= TRANS_DP_HSYNC_ACTIVE_HIGH;
+ if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
+ temp |= TRANS_DP_VSYNC_ACTIVE_HIGH;
+
+ switch (intel_trans_dp_port_sel(crtc)) {
+ case PCH_DP_B:
+ temp |= TRANS_DP_PORT_SEL_B;
+ break;
+ case PCH_DP_C:
+ temp |= TRANS_DP_PORT_SEL_C;
+ break;
+ case PCH_DP_D:
+ temp |= TRANS_DP_PORT_SEL_D;
+ break;
+ default:
+ DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n");
+ temp |= TRANS_DP_PORT_SEL_B;
+ break;
}
- if (dev_priv->cfb_plane == plane &&
- dev_priv->display.disable_fbc)
- dev_priv->display.disable_fbc(dev);
+ I915_WRITE(reg, temp);
+ }
- /* disable cpu pipe, disable after all planes disabled */
- temp = I915_READ(pipeconf_reg);
- if ((temp & PIPEACONF_ENABLE) != 0) {
- I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+ /* enable PCH transcoder */
+ reg = TRANSCONF(pipe);
+ temp = I915_READ(reg);
+ /*
+ * make the BPC in transcoder be consistent with
+ * that in pipeconf reg.
+ */
+ temp &= ~PIPE_BPC_MASK;
+ temp |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK;
+ I915_WRITE(reg, temp | TRANS_ENABLE);
+ if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100))
+ DRM_ERROR("failed to enable transcoder %d\n", pipe);
- /* wait for cpu pipe off, pipe state */
- if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50, 1))
- DRM_ERROR("failed to turn off cpu pipe\n");
- } else
- DRM_DEBUG_KMS("crtc %d is disabled\n", pipe);
+ intel_crtc_load_lut(crtc);
+ intel_update_fbc(dev);
+ intel_crtc_update_cursor(crtc, true);
+}
- udelay(100);
+static void ironlake_crtc_disable(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+ int plane = intel_crtc->plane;
+ u32 reg, temp;
+
+ if (!intel_crtc->active)
+ return;
- /* Disable PF */
- I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0);
- I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0);
+ intel_crtc_wait_for_pending_flips(crtc);
+ drm_vblank_off(dev, pipe);
+ intel_crtc_update_cursor(crtc, false);
- /* disable CPU FDI tx and PCH FDI rx */
- temp = I915_READ(fdi_tx_reg);
- I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE);
- I915_READ(fdi_tx_reg);
+ /* Disable display plane */
+ reg = DSPCNTR(plane);
+ temp = I915_READ(reg);
+ if (temp & DISPLAY_PLANE_ENABLE) {
+ I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE);
+ intel_flush_display_plane(dev, plane);
+ }
- temp = I915_READ(fdi_rx_reg);
- /* BPC in FDI rx is consistent with that in pipeconf */
- temp &= ~(0x07 << 16);
- temp |= (pipe_bpc << 11);
- I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE);
- I915_READ(fdi_rx_reg);
+ if (dev_priv->cfb_plane == plane &&
+ dev_priv->display.disable_fbc)
+ dev_priv->display.disable_fbc(dev);
- udelay(100);
+ /* disable cpu pipe, disable after all planes disabled */
+ reg = PIPECONF(pipe);
+ temp = I915_READ(reg);
+ if (temp & PIPECONF_ENABLE) {
+ I915_WRITE(reg, temp & ~PIPECONF_ENABLE);
+ POSTING_READ(reg);
+ /* wait for cpu pipe off, pipe state */
+ intel_wait_for_pipe_off(dev, intel_crtc->pipe);
+ }
+
+ /* Disable PF */
+ I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0);
+ I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0);
+
+ /* disable CPU FDI tx and PCH FDI rx */
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
+ I915_WRITE(reg, temp & ~FDI_TX_ENABLE);
+ POSTING_READ(reg);
+
+ reg = FDI_RX_CTL(pipe);
+ temp = I915_READ(reg);
+ temp &= ~(0x7 << 16);
+ temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+ I915_WRITE(reg, temp & ~FDI_RX_ENABLE);
+
+ POSTING_READ(reg);
+ udelay(100);
+
+ /* Ironlake workaround, disable clock pointer after downing FDI */
+ I915_WRITE(FDI_RX_CHICKEN(pipe),
+ I915_READ(FDI_RX_CHICKEN(pipe) &
+ ~FDI_RX_PHASE_SYNC_POINTER_ENABLE));
+
+ /* still set train pattern 1 */
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ temp |= FDI_LINK_TRAIN_PATTERN_1;
+ I915_WRITE(reg, temp);
- /* still set train pattern 1 */
- temp = I915_READ(fdi_tx_reg);
+ reg = FDI_RX_CTL(pipe);
+ temp = I915_READ(reg);
+ if (HAS_PCH_CPT(dev)) {
+ temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+ temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+ } else {
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_1;
- I915_WRITE(fdi_tx_reg, temp);
- POSTING_READ(fdi_tx_reg);
-
- temp = I915_READ(fdi_rx_reg);
- if (HAS_PCH_CPT(dev)) {
- temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
- temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
- } else {
- temp &= ~FDI_LINK_TRAIN_NONE;
- temp |= FDI_LINK_TRAIN_PATTERN_1;
- }
- I915_WRITE(fdi_rx_reg, temp);
- POSTING_READ(fdi_rx_reg);
+ }
+ /* BPC in FDI rx is consistent with that in PIPECONF */
+ temp &= ~(0x07 << 16);
+ temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+ I915_WRITE(reg, temp);
- udelay(100);
+ POSTING_READ(reg);
+ udelay(100);
- if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
- temp = I915_READ(PCH_LVDS);
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+ temp = I915_READ(PCH_LVDS);
+ if (temp & LVDS_PORT_EN) {
I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN);
- I915_READ(PCH_LVDS);
+ POSTING_READ(PCH_LVDS);
udelay(100);
}
+ }
- /* disable PCH transcoder */
- temp = I915_READ(transconf_reg);
- if ((temp & TRANS_ENABLE) != 0) {
- I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);
+ /* disable PCH transcoder */
+ reg = TRANSCONF(plane);
+ temp = I915_READ(reg);
+ if (temp & TRANS_ENABLE) {
+ I915_WRITE(reg, temp & ~TRANS_ENABLE);
+ /* wait for PCH transcoder off, transcoder state */
+ if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50))
+ DRM_ERROR("failed to disable transcoder\n");
+ }
- /* wait for PCH transcoder off, transcoder state */
- if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50, 1))
- DRM_ERROR("failed to disable transcoder\n");
- }
+ if (HAS_PCH_CPT(dev)) {
+ /* disable TRANS_DP_CTL */
+ reg = TRANS_DP_CTL(pipe);
+ temp = I915_READ(reg);
+ temp &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK);
+ I915_WRITE(reg, temp);
- temp = I915_READ(transconf_reg);
- /* BPC in transcoder is consistent with that in pipeconf */
- temp &= ~PIPE_BPC_MASK;
- temp |= pipe_bpc;
- I915_WRITE(transconf_reg, temp);
- I915_READ(transconf_reg);
- udelay(100);
+ /* disable DPLL_SEL */
+ temp = I915_READ(PCH_DPLL_SEL);
+ if (pipe == 0)
+ temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
+ else
+ temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+ I915_WRITE(PCH_DPLL_SEL, temp);
+ }
- if (HAS_PCH_CPT(dev)) {
- /* disable TRANS_DP_CTL */
- int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B;
- int reg;
+ /* disable PCH DPLL */
+ reg = PCH_DPLL(pipe);
+ temp = I915_READ(reg);
+ I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE);
- reg = I915_READ(trans_dp_ctl);
- reg &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK);
- I915_WRITE(trans_dp_ctl, reg);
- POSTING_READ(trans_dp_ctl);
+ /* Switch from PCDclk to Rawclk */
+ reg = FDI_RX_CTL(pipe);
+ temp = I915_READ(reg);
+ I915_WRITE(reg, temp & ~FDI_PCDCLK);
- /* disable DPLL_SEL */
- temp = I915_READ(PCH_DPLL_SEL);
- if (trans_dpll_sel == 0)
- temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
- else
- temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
- I915_WRITE(PCH_DPLL_SEL, temp);
- I915_READ(PCH_DPLL_SEL);
+ /* Disable CPU FDI TX PLL */
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
+ I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE);
- }
+ POSTING_READ(reg);
+ udelay(100);
- /* disable PCH DPLL */
- temp = I915_READ(pch_dpll_reg);
- I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE);
- I915_READ(pch_dpll_reg);
-
- /* Switch from PCDclk to Rawclk */
- temp = I915_READ(fdi_rx_reg);
- temp &= ~FDI_SEL_PCDCLK;
- I915_WRITE(fdi_rx_reg, temp);
- I915_READ(fdi_rx_reg);
-
- /* Disable CPU FDI TX PLL */
- temp = I915_READ(fdi_tx_reg);
- I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE);
- I915_READ(fdi_tx_reg);
- udelay(100);
+ reg = FDI_RX_CTL(pipe);
+ temp = I915_READ(reg);
+ I915_WRITE(reg, temp & ~FDI_RX_PLL_ENABLE);
- temp = I915_READ(fdi_rx_reg);
- temp &= ~FDI_RX_PLL_ENABLE;
- I915_WRITE(fdi_rx_reg, temp);
- I915_READ(fdi_rx_reg);
+ /* Wait for the clocks to turn off. */
+ POSTING_READ(reg);
+ udelay(100);
- /* Wait for the clocks to turn off. */
- udelay(100);
+ intel_crtc->active = false;
+ intel_update_watermarks(dev);
+ intel_update_fbc(dev);
+ intel_clear_scanline_wait(dev);
+}
+
+static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+ int plane = intel_crtc->plane;
+
+ /* XXX: When our outputs are all unaware of DPMS modes other than off
+ * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
+ */
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane);
+ ironlake_crtc_enable(crtc);
+ break;
+
+ case DRM_MODE_DPMS_OFF:
+ DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane);
+ ironlake_crtc_disable(crtc);
break;
}
}
static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable)
{
- struct intel_overlay *overlay;
- int ret;
-
if (!enable && intel_crtc->overlay) {
- overlay = intel_crtc->overlay;
- mutex_lock(&overlay->dev->struct_mutex);
- for (;;) {
- ret = intel_overlay_switch_off(overlay);
- if (ret == 0)
- break;
+ struct drm_device *dev = intel_crtc->base.dev;
- ret = intel_overlay_recover_from_interrupt(overlay, 0);
- if (ret != 0) {
- /* overlay doesn't react anymore. Usually
- * results in a black screen and an unkillable
- * X server. */
- BUG();
- overlay->hw_wedged = HW_WEDGED;
- break;
- }
- }
- mutex_unlock(&overlay->dev->struct_mutex);
+ mutex_lock(&dev->struct_mutex);
+ (void) intel_overlay_switch_off(intel_crtc->overlay, false);
+ mutex_unlock(&dev->struct_mutex);
}
- /* Let userspace switch the overlay on again. In most cases userspace
- * has to recompute where to put it anyway. */
- return;
+ /* Let userspace switch the overlay on again. In most cases userspace
+ * has to recompute where to put it anyway.
+ */
}
-static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
+static void i9xx_crtc_enable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
- int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
- int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
- int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
- int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
- u32 temp;
+ u32 reg, temp;
- /* XXX: When our outputs are all unaware of DPMS modes other than off
- * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
- */
- switch (mode) {
- case DRM_MODE_DPMS_ON:
- case DRM_MODE_DPMS_STANDBY:
- case DRM_MODE_DPMS_SUSPEND:
- /* Enable the DPLL */
- temp = I915_READ(dpll_reg);
- if ((temp & DPLL_VCO_ENABLE) == 0) {
- I915_WRITE(dpll_reg, temp);
- I915_READ(dpll_reg);
- /* Wait for the clocks to stabilize. */
- udelay(150);
- I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
- I915_READ(dpll_reg);
- /* Wait for the clocks to stabilize. */
- udelay(150);
- I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
- I915_READ(dpll_reg);
- /* Wait for the clocks to stabilize. */
- udelay(150);
- }
+ if (intel_crtc->active)
+ return;
- /* Enable the pipe */
- temp = I915_READ(pipeconf_reg);
- if ((temp & PIPEACONF_ENABLE) == 0)
- I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
-
- /* Enable the plane */
- temp = I915_READ(dspcntr_reg);
- if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
- I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
- /* Flush the plane changes */
- I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
- }
+ intel_crtc->active = true;
+ intel_update_watermarks(dev);
- intel_crtc_load_lut(crtc);
+ /* Enable the DPLL */
+ reg = DPLL(pipe);
+ temp = I915_READ(reg);
+ if ((temp & DPLL_VCO_ENABLE) == 0) {
+ I915_WRITE(reg, temp);
+
+ /* Wait for the clocks to stabilize. */
+ POSTING_READ(reg);
+ udelay(150);
- if ((IS_I965G(dev) || plane == 0))
- intel_update_fbc(crtc, &crtc->mode);
+ I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
- /* Give the overlay scaler a chance to enable if it's on this pipe */
- intel_crtc_dpms_overlay(intel_crtc, true);
- break;
- case DRM_MODE_DPMS_OFF:
- /* Give the overlay scaler a chance to disable if it's on this pipe */
- intel_crtc_dpms_overlay(intel_crtc, false);
- drm_vblank_off(dev, pipe);
-
- if (dev_priv->cfb_plane == plane &&
- dev_priv->display.disable_fbc)
- dev_priv->display.disable_fbc(dev);
-
- /* Disable display plane */
- temp = I915_READ(dspcntr_reg);
- if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
- I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
- /* Flush the plane changes */
- I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
- I915_READ(dspbase_reg);
- }
+ /* Wait for the clocks to stabilize. */
+ POSTING_READ(reg);
+ udelay(150);
- /* Don't disable pipe A or pipe A PLLs if needed */
- if (pipeconf_reg == PIPEACONF &&
- (dev_priv->quirks & QUIRK_PIPEA_FORCE)) {
- /* Wait for vblank for the disable to take effect */
+ I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
+
+ /* Wait for the clocks to stabilize. */
+ POSTING_READ(reg);
+ udelay(150);
+ }
+
+ /* Enable the pipe */
+ reg = PIPECONF(pipe);
+ temp = I915_READ(reg);
+ if ((temp & PIPECONF_ENABLE) == 0)
+ I915_WRITE(reg, temp | PIPECONF_ENABLE);
+
+ /* Enable the plane */
+ reg = DSPCNTR(plane);
+ temp = I915_READ(reg);
+ if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+ I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE);
+ intel_flush_display_plane(dev, plane);
+ }
+
+ intel_crtc_load_lut(crtc);
+ intel_update_fbc(dev);
+
+ /* Give the overlay scaler a chance to enable if it's on this pipe */
+ intel_crtc_dpms_overlay(intel_crtc, true);
+ intel_crtc_update_cursor(crtc, true);
+}
+
+static void i9xx_crtc_disable(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+ int plane = intel_crtc->plane;
+ u32 reg, temp;
+
+ if (!intel_crtc->active)
+ return;
+
+ /* Give the overlay scaler a chance to disable if it's on this pipe */
+ intel_crtc_wait_for_pending_flips(crtc);
+ drm_vblank_off(dev, pipe);
+ intel_crtc_dpms_overlay(intel_crtc, false);
+ intel_crtc_update_cursor(crtc, false);
+
+ if (dev_priv->cfb_plane == plane &&
+ dev_priv->display.disable_fbc)
+ dev_priv->display.disable_fbc(dev);
+
+ /* Disable display plane */
+ reg = DSPCNTR(plane);
+ temp = I915_READ(reg);
+ if (temp & DISPLAY_PLANE_ENABLE) {
+ I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE);
+ /* Flush the plane changes */
+ intel_flush_display_plane(dev, plane);
+
+ /* Wait for vblank for the disable to take effect */
+ if (IS_GEN2(dev))
intel_wait_for_vblank(dev, pipe);
- goto skip_pipe_off;
- }
+ }
- /* Next, disable display pipes */
- temp = I915_READ(pipeconf_reg);
- if ((temp & PIPEACONF_ENABLE) != 0) {
- I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
- I915_READ(pipeconf_reg);
- }
+ /* Don't disable pipe A or pipe A PLLs if needed */
+ if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
+ goto done;
+
+ /* Next, disable display pipes */
+ reg = PIPECONF(pipe);
+ temp = I915_READ(reg);
+ if (temp & PIPECONF_ENABLE) {
+ I915_WRITE(reg, temp & ~PIPECONF_ENABLE);
/* Wait for the pipe to turn off */
+ POSTING_READ(reg);
intel_wait_for_pipe_off(dev, pipe);
+ }
+
+ reg = DPLL(pipe);
+ temp = I915_READ(reg);
+ if (temp & DPLL_VCO_ENABLE) {
+ I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE);
- temp = I915_READ(dpll_reg);
- if ((temp & DPLL_VCO_ENABLE) != 0) {
- I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE);
- I915_READ(dpll_reg);
- }
- skip_pipe_off:
/* Wait for the clocks to turn off. */
+ POSTING_READ(reg);
udelay(150);
+ }
+
+done:
+ intel_crtc->active = false;
+ intel_update_fbc(dev);
+ intel_update_watermarks(dev);
+ intel_clear_scanline_wait(dev);
+}
+
+static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+ /* XXX: When our outputs are all unaware of DPMS modes other than off
+ * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
+ */
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ i9xx_crtc_enable(crtc);
+ break;
+ case DRM_MODE_DPMS_OFF:
+ i9xx_crtc_disable(crtc);
break;
}
}
@@ -2388,26 +2494,9 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
return;
intel_crtc->dpms_mode = mode;
- intel_crtc->cursor_on = mode == DRM_MODE_DPMS_ON;
-
- /* When switching on the display, ensure that SR is disabled
- * with multiple pipes prior to enabling to new pipe.
- *
- * When switching off the display, make sure the cursor is
- * properly hidden prior to disabling the pipe.
- */
- if (mode == DRM_MODE_DPMS_ON)
- intel_update_watermarks(dev);
- else
- intel_crtc_update_cursor(crtc);
dev_priv->display.dpms(crtc, mode);
- if (mode == DRM_MODE_DPMS_ON)
- intel_crtc_update_cursor(crtc);
- else
- intel_update_watermarks(dev);
-
if (!dev->primary->master)
return;
@@ -2432,16 +2521,46 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
}
}
-static void intel_crtc_prepare (struct drm_crtc *crtc)
+static void intel_crtc_disable(struct drm_crtc *crtc)
{
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+ struct drm_device *dev = crtc->dev;
+
crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+
+ if (crtc->fb) {
+ mutex_lock(&dev->struct_mutex);
+ i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+ mutex_unlock(&dev->struct_mutex);
+ }
}
-static void intel_crtc_commit (struct drm_crtc *crtc)
+/* Prepare for a mode set.
+ *
+ * Note we could be a lot smarter here. We need to figure out which outputs
+ * will be enabled, which disabled (in short, how the config will changes)
+ * and perform the minimum necessary steps to accomplish that, e.g. updating
+ * watermarks, FBC configuration, making sure PLLs are programmed correctly,
+ * panel fitting is in the proper state, etc.
+ */
+static void i9xx_crtc_prepare(struct drm_crtc *crtc)
{
- struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
- crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+ i9xx_crtc_disable(crtc);
+}
+
+static void i9xx_crtc_commit(struct drm_crtc *crtc)
+{
+ i9xx_crtc_enable(crtc);
+}
+
+static void ironlake_crtc_prepare(struct drm_crtc *crtc)
+{
+ ironlake_crtc_disable(crtc);
+}
+
+static void ironlake_crtc_commit(struct drm_crtc *crtc)
+{
+ ironlake_crtc_enable(crtc);
}
void intel_encoder_prepare (struct drm_encoder *encoder)
@@ -2460,13 +2579,7 @@ void intel_encoder_commit (struct drm_encoder *encoder)
void intel_encoder_destroy(struct drm_encoder *encoder)
{
- struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-
- if (intel_encoder->ddc_bus)
- intel_i2c_destroy(intel_encoder->ddc_bus);
-
- if (intel_encoder->i2c_bus)
- intel_i2c_destroy(intel_encoder->i2c_bus);
+ struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
drm_encoder_cleanup(encoder);
kfree(intel_encoder);
@@ -2557,33 +2670,6 @@ static int i830_get_display_clock_speed(struct drm_device *dev)
return 133000;
}
-/**
- * Return the pipe currently connected to the panel fitter,
- * or -1 if the panel fitter is not present or not in use
- */
-int intel_panel_fitter_pipe (struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 pfit_control;
-
- /* i830 doesn't have a panel fitter */
- if (IS_I830(dev))
- return -1;
-
- pfit_control = I915_READ(PFIT_CONTROL);
-
- /* See if the panel fitter is in use */
- if ((pfit_control & PFIT_ENABLE) == 0)
- return -1;
-
- /* 965 can place panel fitter on either pipe */
- if (IS_I965G(dev))
- return (pfit_control >> 29) & 0x3;
-
- /* older chips can only use pipe 1 */
- return 1;
-}
-
struct fdi_m_n {
u32 tu;
u32 gmch_m;
@@ -2902,7 +2988,7 @@ static int i9xx_get_fifo_size(struct drm_device *dev, int plane)
size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size;
DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
- plane ? "B" : "A", size);
+ plane ? "B" : "A", size);
return size;
}
@@ -2919,7 +3005,7 @@ static int i85x_get_fifo_size(struct drm_device *dev, int plane)
size >>= 1; /* Convert to cachelines */
DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
- plane ? "B" : "A", size);
+ plane ? "B" : "A", size);
return size;
}
@@ -2934,8 +3020,8 @@ static int i845_get_fifo_size(struct drm_device *dev, int plane)
size >>= 2; /* Convert to cachelines */
DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
- plane ? "B" : "A",
- size);
+ plane ? "B" : "A",
+ size);
return size;
}
@@ -2950,14 +3036,14 @@ static int i830_get_fifo_size(struct drm_device *dev, int plane)
size >>= 1; /* Convert to cachelines */
DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
- plane ? "B" : "A", size);
+ plane ? "B" : "A", size);
return size;
}
static void pineview_update_wm(struct drm_device *dev, int planea_clock,
- int planeb_clock, int sr_hdisplay, int unused,
- int pixel_size)
+ int planeb_clock, int sr_hdisplay, int unused,
+ int pixel_size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
const struct cxsr_latency *latency;
@@ -3069,13 +3155,13 @@ static void g4x_update_wm(struct drm_device *dev, int planea_clock,
/* Use ns/us then divide to preserve precision */
sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
- pixel_size * sr_hdisplay;
+ pixel_size * sr_hdisplay;
sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
entries_required = (((sr_latency_ns / line_time_us) +
1000) / 1000) * pixel_size * 64;
entries_required = DIV_ROUND_UP(entries_required,
- g4x_cursor_wm_info.cacheline_size);
+ g4x_cursor_wm_info.cacheline_size);
cursor_sr = entries_required + g4x_cursor_wm_info.guard_size;
if (cursor_sr > g4x_cursor_wm_info.max_wm)
@@ -3087,7 +3173,7 @@ static void g4x_update_wm(struct drm_device *dev, int planea_clock,
} else {
/* Turn off self refresh if both pipes are enabled */
I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
- & ~FW_BLC_SELF_EN);
+ & ~FW_BLC_SELF_EN);
}
DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, SR %d\n",
@@ -3125,7 +3211,7 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
/* Use ns/us then divide to preserve precision */
sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
- pixel_size * sr_hdisplay;
+ pixel_size * sr_hdisplay;
sr_entries = DIV_ROUND_UP(sr_entries, I915_FIFO_LINE_SIZE);
DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
srwm = I965_FIFO_SIZE - sr_entries;
@@ -3134,11 +3220,11 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
srwm &= 0x1ff;
sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
- pixel_size * 64;
+ pixel_size * 64;
sr_entries = DIV_ROUND_UP(sr_entries,
i965_cursor_wm_info.cacheline_size);
cursor_sr = i965_cursor_wm_info.fifo_size -
- (sr_entries + i965_cursor_wm_info.guard_size);
+ (sr_entries + i965_cursor_wm_info.guard_size);
if (cursor_sr > i965_cursor_wm_info.max_wm)
cursor_sr = i965_cursor_wm_info.max_wm;
@@ -3146,11 +3232,11 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
"cursor %d\n", srwm, cursor_sr);
- if (IS_I965GM(dev))
+ if (IS_CRESTLINE(dev))
I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
} else {
/* Turn off self refresh if both pipes are enabled */
- if (IS_I965GM(dev))
+ if (IS_CRESTLINE(dev))
I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
& ~FW_BLC_SELF_EN);
}
@@ -3180,9 +3266,9 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
int sr_clock, sr_entries = 0;
/* Create copies of the base settings for each pipe */
- if (IS_I965GM(dev) || IS_I945GM(dev))
+ if (IS_CRESTLINE(dev) || IS_I945GM(dev))
planea_params = planeb_params = i945_wm_info;
- else if (IS_I9XX(dev))
+ else if (!IS_GEN2(dev))
planea_params = planeb_params = i915_wm_info;
else
planea_params = planeb_params = i855_wm_info;
@@ -3217,7 +3303,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
/* Use ns/us then divide to preserve precision */
sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
- pixel_size * sr_hdisplay;
+ pixel_size * sr_hdisplay;
sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
DRM_DEBUG_KMS("self-refresh entries: %d\n", sr_entries);
srwm = total_size - sr_entries;
@@ -3242,7 +3328,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
}
DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
- planea_wm, planeb_wm, cwm, srwm);
+ planea_wm, planeb_wm, cwm, srwm);
fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f);
fwater_hi = (cwm & 0x1f);
@@ -3276,146 +3362,130 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused,
#define ILK_LP0_PLANE_LATENCY 700
#define ILK_LP0_CURSOR_LATENCY 1300
-static void ironlake_update_wm(struct drm_device *dev, int planea_clock,
- int planeb_clock, int sr_hdisplay, int sr_htotal,
- int pixel_size)
+static bool ironlake_compute_wm0(struct drm_device *dev,
+ int pipe,
+ int *plane_wm,
+ int *cursor_wm)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
- int sr_wm, cursor_wm;
- unsigned long line_time_us;
- int sr_clock, entries_required;
- u32 reg_value;
- int line_count;
- int planea_htotal = 0, planeb_htotal = 0;
struct drm_crtc *crtc;
+ int htotal, hdisplay, clock, pixel_size = 0;
+ int line_time_us, line_count, entries;
- /* Need htotal for all active display plane */
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) {
- if (intel_crtc->plane == 0)
- planea_htotal = crtc->mode.htotal;
- else
- planeb_htotal = crtc->mode.htotal;
- }
- }
-
- /* Calculate and update the watermark for plane A */
- if (planea_clock) {
- entries_required = ((planea_clock / 1000) * pixel_size *
- ILK_LP0_PLANE_LATENCY) / 1000;
- entries_required = DIV_ROUND_UP(entries_required,
- ironlake_display_wm_info.cacheline_size);
- planea_wm = entries_required +
- ironlake_display_wm_info.guard_size;
-
- if (planea_wm > (int)ironlake_display_wm_info.max_wm)
- planea_wm = ironlake_display_wm_info.max_wm;
-
- /* Use the large buffer method to calculate cursor watermark */
- line_time_us = (planea_htotal * 1000) / planea_clock;
-
- /* Use ns/us then divide to preserve precision */
- line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
-
- /* calculate the cursor watermark for cursor A */
- entries_required = line_count * 64 * pixel_size;
- entries_required = DIV_ROUND_UP(entries_required,
- ironlake_cursor_wm_info.cacheline_size);
- cursora_wm = entries_required + ironlake_cursor_wm_info.guard_size;
- if (cursora_wm > ironlake_cursor_wm_info.max_wm)
- cursora_wm = ironlake_cursor_wm_info.max_wm;
-
- reg_value = I915_READ(WM0_PIPEA_ILK);
- reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
- reg_value |= (planea_wm << WM0_PIPE_PLANE_SHIFT) |
- (cursora_wm & WM0_PIPE_CURSOR_MASK);
- I915_WRITE(WM0_PIPEA_ILK, reg_value);
- DRM_DEBUG_KMS("FIFO watermarks For pipe A - plane %d, "
- "cursor: %d\n", planea_wm, cursora_wm);
- }
- /* Calculate and update the watermark for plane B */
- if (planeb_clock) {
- entries_required = ((planeb_clock / 1000) * pixel_size *
- ILK_LP0_PLANE_LATENCY) / 1000;
- entries_required = DIV_ROUND_UP(entries_required,
- ironlake_display_wm_info.cacheline_size);
- planeb_wm = entries_required +
- ironlake_display_wm_info.guard_size;
-
- if (planeb_wm > (int)ironlake_display_wm_info.max_wm)
- planeb_wm = ironlake_display_wm_info.max_wm;
+ crtc = intel_get_crtc_for_pipe(dev, pipe);
+ if (crtc->fb == NULL || !crtc->enabled)
+ return false;
- /* Use the large buffer method to calculate cursor watermark */
- line_time_us = (planeb_htotal * 1000) / planeb_clock;
+ htotal = crtc->mode.htotal;
+ hdisplay = crtc->mode.hdisplay;
+ clock = crtc->mode.clock;
+ pixel_size = crtc->fb->bits_per_pixel / 8;
+
+ /* Use the small buffer method to calculate plane watermark */
+ entries = ((clock * pixel_size / 1000) * ILK_LP0_PLANE_LATENCY) / 1000;
+ entries = DIV_ROUND_UP(entries,
+ ironlake_display_wm_info.cacheline_size);
+ *plane_wm = entries + ironlake_display_wm_info.guard_size;
+ if (*plane_wm > (int)ironlake_display_wm_info.max_wm)
+ *plane_wm = ironlake_display_wm_info.max_wm;
+
+ /* Use the large buffer method to calculate cursor watermark */
+ line_time_us = ((htotal * 1000) / clock);
+ line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
+ entries = line_count * 64 * pixel_size;
+ entries = DIV_ROUND_UP(entries,
+ ironlake_cursor_wm_info.cacheline_size);
+ *cursor_wm = entries + ironlake_cursor_wm_info.guard_size;
+ if (*cursor_wm > ironlake_cursor_wm_info.max_wm)
+ *cursor_wm = ironlake_cursor_wm_info.max_wm;
- /* Use ns/us then divide to preserve precision */
- line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
+ return true;
+}
- /* calculate the cursor watermark for cursor B */
- entries_required = line_count * 64 * pixel_size;
- entries_required = DIV_ROUND_UP(entries_required,
- ironlake_cursor_wm_info.cacheline_size);
- cursorb_wm = entries_required + ironlake_cursor_wm_info.guard_size;
- if (cursorb_wm > ironlake_cursor_wm_info.max_wm)
- cursorb_wm = ironlake_cursor_wm_info.max_wm;
+static void ironlake_update_wm(struct drm_device *dev,
+ int planea_clock, int planeb_clock,
+ int sr_hdisplay, int sr_htotal,
+ int pixel_size)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int plane_wm, cursor_wm, enabled;
+ int tmp;
+
+ enabled = 0;
+ if (ironlake_compute_wm0(dev, 0, &plane_wm, &cursor_wm)) {
+ I915_WRITE(WM0_PIPEA_ILK,
+ (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+ DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
+ " plane %d, " "cursor: %d\n",
+ plane_wm, cursor_wm);
+ enabled++;
+ }
- reg_value = I915_READ(WM0_PIPEB_ILK);
- reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
- reg_value |= (planeb_wm << WM0_PIPE_PLANE_SHIFT) |
- (cursorb_wm & WM0_PIPE_CURSOR_MASK);
- I915_WRITE(WM0_PIPEB_ILK, reg_value);
- DRM_DEBUG_KMS("FIFO watermarks For pipe B - plane %d, "
- "cursor: %d\n", planeb_wm, cursorb_wm);
+ if (ironlake_compute_wm0(dev, 1, &plane_wm, &cursor_wm)) {
+ I915_WRITE(WM0_PIPEB_ILK,
+ (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+ DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
+ " plane %d, cursor: %d\n",
+ plane_wm, cursor_wm);
+ enabled++;
}
/*
* Calculate and update the self-refresh watermark only when one
* display plane is used.
*/
- if (!planea_clock || !planeb_clock) {
-
+ tmp = 0;
+ if (enabled == 1 && /* XXX disabled due to buggy implmentation? */ 0) {
+ unsigned long line_time_us;
+ int small, large, plane_fbc;
+ int sr_clock, entries;
+ int line_count, line_size;
/* Read the self-refresh latency. The unit is 0.5us */
int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK;
sr_clock = planea_clock ? planea_clock : planeb_clock;
- line_time_us = ((sr_htotal * 1000) / sr_clock);
+ line_time_us = (sr_htotal * 1000) / sr_clock;
/* Use ns/us then divide to preserve precision */
line_count = ((ilk_sr_latency * 500) / line_time_us + 1000)
- / 1000;
+ / 1000;
+ line_size = sr_hdisplay * pixel_size;
- /* calculate the self-refresh watermark for display plane */
- entries_required = line_count * sr_hdisplay * pixel_size;
- entries_required = DIV_ROUND_UP(entries_required,
- ironlake_display_srwm_info.cacheline_size);
- sr_wm = entries_required +
- ironlake_display_srwm_info.guard_size;
+ /* Use the minimum of the small and large buffer method for primary */
+ small = ((sr_clock * pixel_size / 1000) * (ilk_sr_latency * 500)) / 1000;
+ large = line_count * line_size;
- /* calculate the self-refresh watermark for display cursor */
- entries_required = line_count * pixel_size * 64;
- entries_required = DIV_ROUND_UP(entries_required,
- ironlake_cursor_srwm_info.cacheline_size);
- cursor_wm = entries_required +
- ironlake_cursor_srwm_info.guard_size;
+ entries = DIV_ROUND_UP(min(small, large),
+ ironlake_display_srwm_info.cacheline_size);
- /* configure watermark and enable self-refresh */
- reg_value = I915_READ(WM1_LP_ILK);
- reg_value &= ~(WM1_LP_LATENCY_MASK | WM1_LP_SR_MASK |
- WM1_LP_CURSOR_MASK);
- reg_value |= (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
- (sr_wm << WM1_LP_SR_SHIFT) | cursor_wm;
+ plane_fbc = entries * 64;
+ plane_fbc = DIV_ROUND_UP(plane_fbc, line_size);
- I915_WRITE(WM1_LP_ILK, reg_value);
- DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
- "cursor %d\n", sr_wm, cursor_wm);
+ plane_wm = entries + ironlake_display_srwm_info.guard_size;
+ if (plane_wm > (int)ironlake_display_srwm_info.max_wm)
+ plane_wm = ironlake_display_srwm_info.max_wm;
- } else {
- /* Turn off self refresh if both pipes are enabled */
- I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN);
- }
+ /* calculate the self-refresh watermark for display cursor */
+ entries = line_count * pixel_size * 64;
+ entries = DIV_ROUND_UP(entries,
+ ironlake_cursor_srwm_info.cacheline_size);
+
+ cursor_wm = entries + ironlake_cursor_srwm_info.guard_size;
+ if (cursor_wm > (int)ironlake_cursor_srwm_info.max_wm)
+ cursor_wm = ironlake_cursor_srwm_info.max_wm;
+
+ /* configure watermark and enable self-refresh */
+ tmp = (WM1_LP_SR_EN |
+ (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
+ (plane_fbc << WM1_LP_FBC_SHIFT) |
+ (plane_wm << WM1_LP_SR_SHIFT) |
+ cursor_wm);
+ DRM_DEBUG_KMS("self-refresh watermark: display plane %d, fbc lines %d,"
+ " cursor %d\n", plane_wm, plane_fbc, cursor_wm);
+ }
+ I915_WRITE(WM1_LP_ILK, tmp);
+ /* XXX setup WM2 and WM3 */
}
+
/**
* intel_update_watermarks - update FIFO watermark values based on current modes
*
@@ -3447,7 +3517,7 @@ static void ironlake_update_wm(struct drm_device *dev, int planea_clock,
*
* We don't use the sprite, so we can ignore that. And on Crestline we have
* to set the non-SR watermarks to 8.
- */
+ */
static void intel_update_watermarks(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3463,15 +3533,15 @@ static void intel_update_watermarks(struct drm_device *dev)
/* Get the clock config from both planes */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) {
+ if (intel_crtc->active) {
enabled++;
if (intel_crtc->plane == 0) {
DRM_DEBUG_KMS("plane A (pipe %d) clock: %d\n",
- intel_crtc->pipe, crtc->mode.clock);
+ intel_crtc->pipe, crtc->mode.clock);
planea_clock = crtc->mode.clock;
} else {
DRM_DEBUG_KMS("plane B (pipe %d) clock: %d\n",
- intel_crtc->pipe, crtc->mode.clock);
+ intel_crtc->pipe, crtc->mode.clock);
planeb_clock = crtc->mode.clock;
}
sr_hdisplay = crtc->mode.hdisplay;
@@ -3502,62 +3572,35 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
- int fp_reg = (pipe == 0) ? FPA0 : FPB0;
- int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
- int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
- int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
- int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
- int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
- int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
- int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
- int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
- int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
- int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
- int dspsize_reg = (plane == 0) ? DSPASIZE : DSPBSIZE;
- int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS;
- int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
+ u32 fp_reg, dpll_reg;
int refclk, num_connectors = 0;
intel_clock_t clock, reduced_clock;
- u32 dpll = 0, fp = 0, fp2 = 0, dspcntr, pipeconf;
+ u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
struct intel_encoder *has_edp_encoder = NULL;
struct drm_mode_config *mode_config = &dev->mode_config;
- struct drm_encoder *encoder;
+ struct intel_encoder *encoder;
const intel_limit_t *limit;
int ret;
struct fdi_m_n m_n = {0};
- int data_m1_reg = (pipe == 0) ? PIPEA_DATA_M1 : PIPEB_DATA_M1;
- int data_n1_reg = (pipe == 0) ? PIPEA_DATA_N1 : PIPEB_DATA_N1;
- int link_m1_reg = (pipe == 0) ? PIPEA_LINK_M1 : PIPEB_LINK_M1;
- int link_n1_reg = (pipe == 0) ? PIPEA_LINK_N1 : PIPEB_LINK_N1;
- int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0;
- int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
- int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
- int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
- int trans_dpll_sel = (pipe == 0) ? 0 : 1;
- int lvds_reg = LVDS;
- u32 temp;
- int sdvo_pixel_multiply;
+ u32 reg, temp;
int target_clock;
drm_vblank_pre_modeset(dev, pipe);
- list_for_each_entry(encoder, &mode_config->encoder_list, head) {
- struct intel_encoder *intel_encoder;
-
- if (encoder->crtc != crtc)
+ list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+ if (encoder->base.crtc != crtc)
continue;
- intel_encoder = enc_to_intel_encoder(encoder);
- switch (intel_encoder->type) {
+ switch (encoder->type) {
case INTEL_OUTPUT_LVDS:
is_lvds = true;
break;
case INTEL_OUTPUT_SDVO:
case INTEL_OUTPUT_HDMI:
is_sdvo = true;
- if (intel_encoder->needs_tv_clock)
+ if (encoder->needs_tv_clock)
is_tv = true;
break;
case INTEL_OUTPUT_DVO:
@@ -3573,7 +3616,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
is_dp = true;
break;
case INTEL_OUTPUT_EDP:
- has_edp_encoder = intel_encoder;
+ has_edp_encoder = encoder;
break;
}
@@ -3583,15 +3626,15 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2) {
refclk = dev_priv->lvds_ssc_freq * 1000;
DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
- refclk / 1000);
- } else if (IS_I9XX(dev)) {
+ refclk / 1000);
+ } else if (!IS_GEN2(dev)) {
refclk = 96000;
- if (HAS_PCH_SPLIT(dev))
+ if (HAS_PCH_SPLIT(dev) &&
+ (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)))
refclk = 120000; /* 120Mhz refclk */
} else {
refclk = 48000;
}
-
/*
* Returns a set of divisors for the desired target clock with the given
@@ -3607,13 +3650,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
}
/* Ensure that the cursor is valid for the new mode before changing... */
- intel_crtc_update_cursor(crtc);
+ intel_crtc_update_cursor(crtc, true);
if (is_lvds && dev_priv->lvds_downclock_avail) {
has_reduced_clock = limit->find_pll(limit, crtc,
- dev_priv->lvds_downclock,
- refclk,
- &reduced_clock);
+ dev_priv->lvds_downclock,
+ refclk,
+ &reduced_clock);
if (has_reduced_clock && (clock.p != reduced_clock.p)) {
/*
* If the different P is found, it means that we can't
@@ -3622,7 +3665,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
* feature.
*/
DRM_DEBUG_KMS("Different P is found for "
- "LVDS clock/downclock\n");
+ "LVDS clock/downclock\n");
has_reduced_clock = 0;
}
}
@@ -3630,14 +3673,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
this mirrors vbios setting. */
if (is_sdvo && is_tv) {
if (adjusted_mode->clock >= 100000
- && adjusted_mode->clock < 140500) {
+ && adjusted_mode->clock < 140500) {
clock.p1 = 2;
clock.p2 = 10;
clock.n = 3;
clock.m1 = 16;
clock.m2 = 8;
} else if (adjusted_mode->clock >= 140500
- && adjusted_mode->clock <= 200000) {
+ && adjusted_mode->clock <= 200000) {
clock.p1 = 1;
clock.p2 = 10;
clock.n = 6;
@@ -3649,34 +3692,41 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* FDI link */
if (HAS_PCH_SPLIT(dev)) {
int lane = 0, link_bw, bpp;
- /* eDP doesn't require FDI link, so just set DP M/N
+ /* CPU eDP doesn't require FDI link, so just set DP M/N
according to current link config */
- if (has_edp_encoder) {
+ if (has_edp_encoder && !intel_encoder_is_pch_edp(&encoder->base)) {
target_clock = mode->clock;
intel_edp_link_config(has_edp_encoder,
&lane, &link_bw);
} else {
- /* DP over FDI requires target mode clock
+ /* [e]DP over FDI requires target mode clock
instead of link clock */
- if (is_dp)
+ if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
target_clock = mode->clock;
else
target_clock = adjusted_mode->clock;
- link_bw = 270000;
+
+ /* FDI is a binary signal running at ~2.7GHz, encoding
+ * each output octet as 10 bits. The actual frequency
+ * is stored as a divider into a 100MHz clock, and the
+ * mode pixel clock is stored in units of 1KHz.
+ * Hence the bw of each lane in terms of the mode signal
+ * is:
+ */
+ link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
}
/* determine panel color depth */
- temp = I915_READ(pipeconf_reg);
+ temp = I915_READ(PIPECONF(pipe));
temp &= ~PIPE_BPC_MASK;
if (is_lvds) {
- int lvds_reg = I915_READ(PCH_LVDS);
/* the BPC will be 6 if it is 18-bit LVDS panel */
- if ((lvds_reg & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
+ if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
temp |= PIPE_8BPC;
else
temp |= PIPE_6BPC;
- } else if (has_edp_encoder || (is_dp && intel_pch_has_edp(crtc))) {
- switch (dev_priv->edp_bpp/3) {
+ } else if (has_edp_encoder) {
+ switch (dev_priv->edp.bpp/3) {
case 8:
temp |= PIPE_8BPC;
break;
@@ -3692,8 +3742,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
}
} else
temp |= PIPE_8BPC;
- I915_WRITE(pipeconf_reg, temp);
- I915_READ(pipeconf_reg);
+ I915_WRITE(PIPECONF(pipe), temp);
switch (temp & PIPE_BPC_MASK) {
case PIPE_8BPC:
@@ -3738,33 +3787,39 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Always enable nonspread source */
temp &= ~DREF_NONSPREAD_SOURCE_MASK;
temp |= DREF_NONSPREAD_SOURCE_ENABLE;
- I915_WRITE(PCH_DREF_CONTROL, temp);
- POSTING_READ(PCH_DREF_CONTROL);
-
temp &= ~DREF_SSC_SOURCE_MASK;
temp |= DREF_SSC_SOURCE_ENABLE;
I915_WRITE(PCH_DREF_CONTROL, temp);
- POSTING_READ(PCH_DREF_CONTROL);
+ POSTING_READ(PCH_DREF_CONTROL);
udelay(200);
if (has_edp_encoder) {
if (dev_priv->lvds_use_ssc) {
temp |= DREF_SSC1_ENABLE;
I915_WRITE(PCH_DREF_CONTROL, temp);
- POSTING_READ(PCH_DREF_CONTROL);
- udelay(200);
-
- temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
- temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
- I915_WRITE(PCH_DREF_CONTROL, temp);
POSTING_READ(PCH_DREF_CONTROL);
+ udelay(200);
+ }
+ temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+
+ /* Enable CPU source on CPU attached eDP */
+ if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+ if (dev_priv->lvds_use_ssc)
+ temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+ else
+ temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
} else {
- temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
- I915_WRITE(PCH_DREF_CONTROL, temp);
- POSTING_READ(PCH_DREF_CONTROL);
+ /* Enable SSC on PCH eDP if needed */
+ if (dev_priv->lvds_use_ssc) {
+ DRM_ERROR("enabling SSC on PCH\n");
+ temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
+ }
}
+ I915_WRITE(PCH_DREF_CONTROL, temp);
+ POSTING_READ(PCH_DREF_CONTROL);
+ udelay(200);
}
}
@@ -3780,23 +3835,26 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
reduced_clock.m2;
}
+ dpll = 0;
if (!HAS_PCH_SPLIT(dev))
dpll = DPLL_VGA_MODE_DIS;
- if (IS_I9XX(dev)) {
+ if (!IS_GEN2(dev)) {
if (is_lvds)
dpll |= DPLLB_MODE_LVDS;
else
dpll |= DPLLB_MODE_DAC_SERIAL;
if (is_sdvo) {
+ int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+ if (pixel_multiplier > 1) {
+ if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+ dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
+ else if (HAS_PCH_SPLIT(dev))
+ dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
+ }
dpll |= DPLL_DVO_HIGH_SPEED;
- sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
- if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
- dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
- else if (HAS_PCH_SPLIT(dev))
- dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
}
- if (is_dp)
+ if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
dpll |= DPLL_DVO_HIGH_SPEED;
/* compute bitmask from p1 value */
@@ -3824,7 +3882,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
break;
}
- if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
} else {
if (is_lvds) {
@@ -3851,7 +3909,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
dpll |= PLL_REF_INPUT_DREFCLK;
/* setup pipeconf */
- pipeconf = I915_READ(pipeconf_reg);
+ pipeconf = I915_READ(PIPECONF(pipe));
/* Set up the display plane register */
dspcntr = DISPPLANE_GAMMA_ENABLE;
@@ -3865,7 +3923,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
dspcntr |= DISPPLANE_SEL_PIPE_B;
}
- if (pipe == 0 && !IS_I965G(dev)) {
+ if (pipe == 0 && INTEL_INFO(dev)->gen < 4) {
/* Enable pixel doubling when the dot clock is > 90% of the (display)
* core speed.
*
@@ -3874,51 +3932,47 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
*/
if (mode->clock >
dev_priv->display.get_display_clock_speed(dev) * 9 / 10)
- pipeconf |= PIPEACONF_DOUBLE_WIDE;
+ pipeconf |= PIPECONF_DOUBLE_WIDE;
else
- pipeconf &= ~PIPEACONF_DOUBLE_WIDE;
+ pipeconf &= ~PIPECONF_DOUBLE_WIDE;
}
dspcntr |= DISPLAY_PLANE_ENABLE;
- pipeconf |= PIPEACONF_ENABLE;
+ pipeconf |= PIPECONF_ENABLE;
dpll |= DPLL_VCO_ENABLE;
-
- /* Disable the panel fitter if it was on our pipe */
- if (!HAS_PCH_SPLIT(dev) && intel_panel_fitter_pipe(dev) == pipe)
- I915_WRITE(PFIT_CONTROL, 0);
-
DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
drm_mode_debug_printmodeline(mode);
/* assign to Ironlake registers */
if (HAS_PCH_SPLIT(dev)) {
- fp_reg = pch_fp_reg;
- dpll_reg = pch_dpll_reg;
+ fp_reg = PCH_FP0(pipe);
+ dpll_reg = PCH_DPLL(pipe);
+ } else {
+ fp_reg = FP0(pipe);
+ dpll_reg = DPLL(pipe);
}
- if (!has_edp_encoder) {
+ /* PCH eDP needs FDI, but CPU eDP does not */
+ if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
I915_WRITE(fp_reg, fp);
I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
- I915_READ(dpll_reg);
+
+ POSTING_READ(dpll_reg);
udelay(150);
}
/* enable transcoder DPLL */
if (HAS_PCH_CPT(dev)) {
temp = I915_READ(PCH_DPLL_SEL);
- if (trans_dpll_sel == 0)
- temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+ if (pipe == 0)
+ temp |= TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL;
else
- temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+ temp |= TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL;
I915_WRITE(PCH_DPLL_SEL, temp);
- I915_READ(PCH_DPLL_SEL);
- udelay(150);
- }
- if (HAS_PCH_SPLIT(dev)) {
- pipeconf &= ~PIPE_ENABLE_DITHER;
- pipeconf &= ~PIPE_DITHER_TYPE_MASK;
+ POSTING_READ(PCH_DPLL_SEL);
+ udelay(150);
}
/* The LVDS pin pair needs to be on before the DPLLs are enabled.
@@ -3926,58 +3980,60 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
* things on.
*/
if (is_lvds) {
- u32 lvds;
-
+ reg = LVDS;
if (HAS_PCH_SPLIT(dev))
- lvds_reg = PCH_LVDS;
+ reg = PCH_LVDS;
- lvds = I915_READ(lvds_reg);
- lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+ temp = I915_READ(reg);
+ temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
if (pipe == 1) {
if (HAS_PCH_CPT(dev))
- lvds |= PORT_TRANS_B_SEL_CPT;
+ temp |= PORT_TRANS_B_SEL_CPT;
else
- lvds |= LVDS_PIPEB_SELECT;
+ temp |= LVDS_PIPEB_SELECT;
} else {
if (HAS_PCH_CPT(dev))
- lvds &= ~PORT_TRANS_SEL_MASK;
+ temp &= ~PORT_TRANS_SEL_MASK;
else
- lvds &= ~LVDS_PIPEB_SELECT;
+ temp &= ~LVDS_PIPEB_SELECT;
}
/* set the corresponsding LVDS_BORDER bit */
- lvds |= dev_priv->lvds_border_bits;
+ temp |= dev_priv->lvds_border_bits;
/* Set the B0-B3 data pairs corresponding to whether we're going to
* set the DPLLs for dual-channel mode or not.
*/
if (clock.p2 == 7)
- lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
+ temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
else
- lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
+ temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
/* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
* appropriately here, but we need to look more thoroughly into how
* panels behave in the two modes.
*/
- /* set the dithering flag */
- if (IS_I965G(dev)) {
- if (dev_priv->lvds_dither) {
- if (HAS_PCH_SPLIT(dev)) {
- pipeconf |= PIPE_ENABLE_DITHER;
- pipeconf |= PIPE_DITHER_TYPE_ST01;
- } else
- lvds |= LVDS_ENABLE_DITHER;
- } else {
- if (!HAS_PCH_SPLIT(dev)) {
- lvds &= ~LVDS_ENABLE_DITHER;
- }
- }
+ /* set the dithering flag on non-PCH LVDS as needed */
+ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
+ if (dev_priv->lvds_dither)
+ temp |= LVDS_ENABLE_DITHER;
+ else
+ temp &= ~LVDS_ENABLE_DITHER;
}
- I915_WRITE(lvds_reg, lvds);
- I915_READ(lvds_reg);
+ I915_WRITE(reg, temp);
}
- if (is_dp)
+
+ /* set the dithering flag and clear for anything other than a panel. */
+ if (HAS_PCH_SPLIT(dev)) {
+ pipeconf &= ~PIPECONF_DITHER_EN;
+ pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
+ if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) {
+ pipeconf |= PIPECONF_DITHER_EN;
+ pipeconf |= PIPECONF_DITHER_TYPE_ST1;
+ }
+ }
+
+ if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
intel_dp_set_m_n(crtc, mode, adjusted_mode);
- else if (HAS_PCH_SPLIT(dev)) {
+ } else if (HAS_PCH_SPLIT(dev)) {
/* For non-DP output, clear any trans DP clock recovery setting.*/
if (pipe == 0) {
I915_WRITE(TRANSA_DATA_M1, 0);
@@ -3992,29 +4048,35 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
}
}
- if (!has_edp_encoder) {
+ if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
I915_WRITE(fp_reg, fp);
I915_WRITE(dpll_reg, dpll);
- I915_READ(dpll_reg);
+
/* Wait for the clocks to stabilize. */
+ POSTING_READ(dpll_reg);
udelay(150);
- if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
+ temp = 0;
if (is_sdvo) {
- sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
- I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
- ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
- } else
- I915_WRITE(dpll_md_reg, 0);
+ temp = intel_mode_get_pixel_multiplier(adjusted_mode);
+ if (temp > 1)
+ temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+ else
+ temp = 0;
+ }
+ I915_WRITE(DPLL_MD(pipe), temp);
} else {
/* write it again -- the BIOS does, after all */
I915_WRITE(dpll_reg, dpll);
}
- I915_READ(dpll_reg);
+
/* Wait for the clocks to stabilize. */
+ POSTING_READ(dpll_reg);
udelay(150);
}
+ intel_crtc->lowfreq_avail = false;
if (is_lvds && has_reduced_clock && i915_powersave) {
I915_WRITE(fp_reg + 4, fp2);
intel_crtc->lowfreq_avail = true;
@@ -4024,7 +4086,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
}
} else {
I915_WRITE(fp_reg + 4, fp);
- intel_crtc->lowfreq_avail = false;
if (HAS_PIPE_CXSR(dev)) {
DRM_DEBUG_KMS("disabling CxSR downclocking\n");
pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
@@ -4043,70 +4104,62 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
} else
pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */
- I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
+ I915_WRITE(HTOTAL(pipe),
+ (adjusted_mode->crtc_hdisplay - 1) |
((adjusted_mode->crtc_htotal - 1) << 16));
- I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
+ I915_WRITE(HBLANK(pipe),
+ (adjusted_mode->crtc_hblank_start - 1) |
((adjusted_mode->crtc_hblank_end - 1) << 16));
- I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
+ I915_WRITE(HSYNC(pipe),
+ (adjusted_mode->crtc_hsync_start - 1) |
((adjusted_mode->crtc_hsync_end - 1) << 16));
- I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
+
+ I915_WRITE(VTOTAL(pipe),
+ (adjusted_mode->crtc_vdisplay - 1) |
((adjusted_mode->crtc_vtotal - 1) << 16));
- I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
+ I915_WRITE(VBLANK(pipe),
+ (adjusted_mode->crtc_vblank_start - 1) |
((adjusted_mode->crtc_vblank_end - 1) << 16));
- I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
+ I915_WRITE(VSYNC(pipe),
+ (adjusted_mode->crtc_vsync_start - 1) |
((adjusted_mode->crtc_vsync_end - 1) << 16));
- /* pipesrc and dspsize control the size that is scaled from, which should
- * always be the user's requested size.
+
+ /* pipesrc and dspsize control the size that is scaled from,
+ * which should always be the user's requested size.
*/
if (!HAS_PCH_SPLIT(dev)) {
- I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) |
- (mode->hdisplay - 1));
- I915_WRITE(dsppos_reg, 0);
+ I915_WRITE(DSPSIZE(plane),
+ ((mode->vdisplay - 1) << 16) |
+ (mode->hdisplay - 1));
+ I915_WRITE(DSPPOS(plane), 0);
}
- I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+ I915_WRITE(PIPESRC(pipe),
+ ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
if (HAS_PCH_SPLIT(dev)) {
- I915_WRITE(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m);
- I915_WRITE(data_n1_reg, TU_SIZE(m_n.tu) | m_n.gmch_n);
- I915_WRITE(link_m1_reg, m_n.link_m);
- I915_WRITE(link_n1_reg, m_n.link_n);
+ I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
+ I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n);
+ I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
+ I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
- if (has_edp_encoder) {
+ if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
ironlake_set_pll_edp(crtc, adjusted_mode->clock);
- } else {
- /* enable FDI RX PLL too */
- temp = I915_READ(fdi_rx_reg);
- I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
- I915_READ(fdi_rx_reg);
- udelay(200);
-
- /* enable FDI TX PLL too */
- temp = I915_READ(fdi_tx_reg);
- I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
- I915_READ(fdi_tx_reg);
-
- /* enable FDI RX PCDCLK */
- temp = I915_READ(fdi_rx_reg);
- I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK);
- I915_READ(fdi_rx_reg);
- udelay(200);
}
}
- I915_WRITE(pipeconf_reg, pipeconf);
- I915_READ(pipeconf_reg);
+ I915_WRITE(PIPECONF(pipe), pipeconf);
+ POSTING_READ(PIPECONF(pipe));
intel_wait_for_vblank(dev, pipe);
- if (IS_IRONLAKE(dev)) {
+ if (IS_GEN5(dev)) {
/* enable address swizzle for tiling buffer */
temp = I915_READ(DISP_ARB_CTL);
I915_WRITE(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING);
}
- I915_WRITE(dspcntr_reg, dspcntr);
+ I915_WRITE(DSPCNTR(plane), dspcntr);
- /* Flush the plane changes */
ret = intel_pipe_set_base(crtc, x, y, old_fb);
intel_update_watermarks(dev);
@@ -4199,7 +4252,8 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
}
/* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
-static void intel_crtc_update_cursor(struct drm_crtc *crtc)
+static void intel_crtc_update_cursor(struct drm_crtc *crtc,
+ bool on)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4212,7 +4266,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc)
pos = 0;
- if (intel_crtc->cursor_on && crtc->fb) {
+ if (on && crtc->enabled && crtc->fb) {
base = intel_crtc->cursor_addr;
if (x > (int) crtc->fb->width)
base = 0;
@@ -4324,7 +4378,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
addr = obj_priv->phys_obj->handle->busaddr;
}
- if (!IS_I9XX(dev))
+ if (IS_GEN2(dev))
I915_WRITE(CURSIZE, (height << 12) | width);
finish:
@@ -4344,7 +4398,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
intel_crtc->cursor_width = width;
intel_crtc->cursor_height = height;
- intel_crtc_update_cursor(crtc);
+ intel_crtc_update_cursor(crtc, true);
return 0;
fail_unpin:
@@ -4363,7 +4417,7 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
intel_crtc->cursor_x = x;
intel_crtc->cursor_y = y;
- intel_crtc_update_cursor(crtc);
+ intel_crtc_update_cursor(crtc, true);
return 0;
}
@@ -4432,7 +4486,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
struct intel_crtc *intel_crtc;
struct drm_crtc *possible_crtc;
struct drm_crtc *supported_crtc =NULL;
- struct drm_encoder *encoder = &intel_encoder->enc;
+ struct drm_encoder *encoder = &intel_encoder->base;
struct drm_crtc *crtc = NULL;
struct drm_device *dev = encoder->dev;
struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
@@ -4513,7 +4567,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
struct drm_connector *connector, int dpms_mode)
{
- struct drm_encoder *encoder = &intel_encoder->enc;
+ struct drm_encoder *encoder = &intel_encoder->base;
struct drm_device *dev = encoder->dev;
struct drm_crtc *crtc = encoder->crtc;
struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
@@ -4559,7 +4613,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
}
- if (IS_I9XX(dev)) {
+ if (!IS_GEN2(dev)) {
if (IS_PINEVIEW(dev))
clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >>
DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW);
@@ -4663,8 +4717,6 @@ static void intel_gpu_idle_timer(unsigned long arg)
struct drm_device *dev = (struct drm_device *)arg;
drm_i915_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG_DRIVER("idle timer fired, downclocking\n");
-
dev_priv->busy = false;
queue_work(dev_priv->wq, &dev_priv->idle_work);
@@ -4678,14 +4730,12 @@ static void intel_crtc_idle_timer(unsigned long arg)
struct drm_crtc *crtc = &intel_crtc->base;
drm_i915_private_t *dev_priv = crtc->dev->dev_private;
- DRM_DEBUG_DRIVER("idle timer fired, downclocking\n");
-
intel_crtc->busy = false;
queue_work(dev_priv->wq, &dev_priv->idle_work);
}
-static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
+static void intel_increase_pllclock(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -4720,9 +4770,8 @@ static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
}
/* Schedule downclock */
- if (schedule)
- mod_timer(&intel_crtc->idle_timer, jiffies +
- msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
+ mod_timer(&intel_crtc->idle_timer, jiffies +
+ msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
}
static void intel_decrease_pllclock(struct drm_crtc *crtc)
@@ -4858,7 +4907,7 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
}
/* Non-busy -> busy, upclock */
- intel_increase_pllclock(crtc, true);
+ intel_increase_pllclock(crtc);
intel_crtc->busy = true;
} else {
/* Busy -> busy, put off timer */
@@ -4872,8 +4921,22 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
static void intel_crtc_destroy(struct drm_crtc *crtc)
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct intel_unpin_work *work;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ work = intel_crtc->unpin_work;
+ intel_crtc->unpin_work = NULL;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ if (work) {
+ cancel_work_sync(&work->work);
+ kfree(work);
+ }
drm_crtc_cleanup(crtc);
+
kfree(intel_crtc);
}
@@ -4928,12 +4991,11 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
spin_unlock_irqrestore(&dev->event_lock, flags);
- obj_priv = to_intel_bo(work->pending_flip_obj);
-
- /* Initial scanout buffer will have a 0 pending flip count */
- if ((atomic_read(&obj_priv->pending_flip) == 0) ||
- atomic_dec_and_test(&obj_priv->pending_flip))
- DRM_WAKEUP(&dev_priv->pending_flip_queue);
+ obj_priv = to_intel_bo(work->old_fb_obj);
+ atomic_clear_mask(1 << intel_crtc->plane,
+ &obj_priv->pending_flip.counter);
+ if (atomic_read(&obj_priv->pending_flip) == 0)
+ wake_up(&dev_priv->pending_flip_queue);
schedule_work(&work->work);
trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
@@ -5014,7 +5076,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
obj = intel_fb->obj;
mutex_lock(&dev->struct_mutex);
- ret = intel_pin_and_fence_fb_obj(dev, obj);
+ ret = intel_pin_and_fence_fb_obj(dev, obj, true);
if (ret)
goto cleanup_work;
@@ -5023,29 +5085,33 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
drm_gem_object_reference(obj);
crtc->fb = fb;
- ret = i915_gem_object_flush_write_domain(obj);
- if (ret)
- goto cleanup_objs;
ret = drm_vblank_get(dev, intel_crtc->pipe);
if (ret)
goto cleanup_objs;
- obj_priv = to_intel_bo(obj);
- atomic_inc(&obj_priv->pending_flip);
+ /* Block clients from rendering to the new back buffer until
+ * the flip occurs and the object is no longer visible.
+ */
+ atomic_add(1 << intel_crtc->plane,
+ &to_intel_bo(work->old_fb_obj)->pending_flip);
+
work->pending_flip_obj = obj;
+ obj_priv = to_intel_bo(obj);
if (IS_GEN3(dev) || IS_GEN2(dev)) {
u32 flip_mask;
+ /* Can't queue multiple flips, so wait for the previous
+ * one to finish before executing the next.
+ */
+ BEGIN_LP_RING(2);
if (intel_crtc->plane)
flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
else
flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
-
- BEGIN_LP_RING(2);
OUT_RING(MI_WAIT_FOR_EVENT | flip_mask);
- OUT_RING(0);
+ OUT_RING(MI_NOOP);
ADVANCE_LP_RING();
}
@@ -5126,15 +5192,14 @@ cleanup_work:
return ret;
}
-static const struct drm_crtc_helper_funcs intel_helper_funcs = {
+static struct drm_crtc_helper_funcs intel_helper_funcs = {
.dpms = intel_crtc_dpms,
.mode_fixup = intel_crtc_mode_fixup,
.mode_set = intel_crtc_mode_set,
.mode_set_base = intel_pipe_set_base,
.mode_set_base_atomic = intel_pipe_set_base_atomic,
- .prepare = intel_crtc_prepare,
- .commit = intel_crtc_commit,
.load_lut = intel_crtc_load_lut,
+ .disable = intel_crtc_disable,
};
static const struct drm_crtc_funcs intel_crtc_funcs = {
@@ -5160,8 +5225,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
- intel_crtc->pipe = pipe;
- intel_crtc->plane = pipe;
for (i = 0; i < 256; i++) {
intel_crtc->lut_r[i] = i;
intel_crtc->lut_g[i] = i;
@@ -5171,9 +5234,9 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
/* Swap pipes & planes for FBC on pre-965 */
intel_crtc->pipe = pipe;
intel_crtc->plane = pipe;
- if (IS_MOBILE(dev) && (IS_I9XX(dev) && !IS_I965G(dev))) {
+ if (IS_MOBILE(dev) && IS_GEN3(dev)) {
DRM_DEBUG_KMS("swapping pipes & planes for FBC\n");
- intel_crtc->plane = ((pipe == 0) ? 1 : 0);
+ intel_crtc->plane = !pipe;
}
BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
@@ -5183,6 +5246,16 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
intel_crtc->cursor_addr = 0;
intel_crtc->dpms_mode = -1;
+ intel_crtc->active = true; /* force the pipe off on setup_init_config */
+
+ if (HAS_PCH_SPLIT(dev)) {
+ intel_helper_funcs.prepare = ironlake_crtc_prepare;
+ intel_helper_funcs.commit = ironlake_crtc_commit;
+ } else {
+ intel_helper_funcs.prepare = i9xx_crtc_prepare;
+ intel_helper_funcs.commit = i9xx_crtc_commit;
+ }
+
drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
intel_crtc->busy = false;
@@ -5218,38 +5291,25 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
return 0;
}
-struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
-{
- struct drm_crtc *crtc = NULL;
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- if (intel_crtc->pipe == pipe)
- break;
- }
- return crtc;
-}
-
static int intel_encoder_clones(struct drm_device *dev, int type_mask)
{
+ struct intel_encoder *encoder;
int index_mask = 0;
- struct drm_encoder *encoder;
int entry = 0;
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
- if (type_mask & intel_encoder->clone_mask)
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+ if (type_mask & encoder->clone_mask)
index_mask |= (1 << entry);
entry++;
}
+
return index_mask;
}
-
static void intel_setup_outputs(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_encoder *encoder;
+ struct intel_encoder *encoder;
bool dpd_is_edp = false;
if (IS_MOBILE(dev) && !IS_I830(dev))
@@ -5338,12 +5398,10 @@ static void intel_setup_outputs(struct drm_device *dev)
if (SUPPORTS_TV(dev))
intel_tv_init(dev);
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-
- encoder->possible_crtcs = intel_encoder->crtc_mask;
- encoder->possible_clones = intel_encoder_clones(dev,
- intel_encoder->clone_mask);
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+ encoder->base.possible_crtcs = encoder->crtc_mask;
+ encoder->base.possible_clones =
+ intel_encoder_clones(dev, encoder->clone_mask);
}
}
@@ -5377,8 +5435,25 @@ int intel_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd *mode_cmd,
struct drm_gem_object *obj)
{
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int ret;
+ if (obj_priv->tiling_mode == I915_TILING_Y)
+ return -EINVAL;
+
+ if (mode_cmd->pitch & 63)
+ return -EINVAL;
+
+ switch (mode_cmd->bpp) {
+ case 8:
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ return -EINVAL;
+ }
+
ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
if (ret) {
DRM_ERROR("framebuffer init failed %d\n", ret);
@@ -5487,6 +5562,10 @@ void ironlake_enable_drps(struct drm_device *dev)
u32 rgvmodectl = I915_READ(MEMMODECTL);
u8 fmax, fmin, fstart, vstart;
+ /* Enable temp reporting */
+ I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN);
+ I915_WRITE16(TSC1, I915_READ(TSC1) | TSE);
+
/* 100ms RC evaluation intervals */
I915_WRITE(RCUPEI, 100000);
I915_WRITE(RCDNEI, 100000);
@@ -5529,7 +5608,7 @@ void ironlake_enable_drps(struct drm_device *dev)
rgvmodectl |= MEMMODE_SWMODE_EN;
I915_WRITE(MEMMODECTL, rgvmodectl);
- if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 1, 0))
+ if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
DRM_ERROR("stuck trying to change perf mode\n");
msleep(1);
@@ -5660,7 +5739,7 @@ void intel_init_clock_gating(struct drm_device *dev)
if (HAS_PCH_SPLIT(dev)) {
uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
- if (IS_IRONLAKE(dev)) {
+ if (IS_GEN5(dev)) {
/* Required for FBC */
dspclk_gate |= DPFDUNIT_CLOCK_GATE_DISABLE;
/* Required for CxSR */
@@ -5674,13 +5753,20 @@ void intel_init_clock_gating(struct drm_device *dev)
I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
/*
+ * On Ibex Peak and Cougar Point, we need to disable clock
+ * gating for the panel power sequencer or it will fail to
+ * start up when no ports are active.
+ */
+ I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+
+ /*
* According to the spec the following bits should be set in
* order to enable memory self-refresh
* The bit 22/21 of 0x42004
* The bit 5 of 0x42020
* The bit 15 of 0x45000
*/
- if (IS_IRONLAKE(dev)) {
+ if (IS_GEN5(dev)) {
I915_WRITE(ILK_DISPLAY_CHICKEN2,
(I915_READ(ILK_DISPLAY_CHICKEN2) |
ILK_DPARB_GATE | ILK_VSDPFD_FULL));
@@ -5728,20 +5814,20 @@ void intel_init_clock_gating(struct drm_device *dev)
if (IS_GM45(dev))
dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
- } else if (IS_I965GM(dev)) {
+ } else if (IS_CRESTLINE(dev)) {
I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
I915_WRITE(RENCLK_GATE_D2, 0);
I915_WRITE(DSPCLK_GATE_D, 0);
I915_WRITE(RAMCLK_GATE_D, 0);
I915_WRITE16(DEUC, 0);
- } else if (IS_I965G(dev)) {
+ } else if (IS_BROADWATER(dev)) {
I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
I965_RCC_CLOCK_GATE_DISABLE |
I965_RCPB_CLOCK_GATE_DISABLE |
I965_ISC_CLOCK_GATE_DISABLE |
I965_FBC_CLOCK_GATE_DISABLE);
I915_WRITE(RENCLK_GATE_D2, 0);
- } else if (IS_I9XX(dev)) {
+ } else if (IS_GEN3(dev)) {
u32 dstate = I915_READ(D_STATE);
dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
@@ -5823,7 +5909,7 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.fbc_enabled = g4x_fbc_enabled;
dev_priv->display.enable_fbc = g4x_enable_fbc;
dev_priv->display.disable_fbc = g4x_disable_fbc;
- } else if (IS_I965GM(dev)) {
+ } else if (IS_CRESTLINE(dev)) {
dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
dev_priv->display.enable_fbc = i8xx_enable_fbc;
dev_priv->display.disable_fbc = i8xx_disable_fbc;
@@ -5856,7 +5942,7 @@ static void intel_init_display(struct drm_device *dev)
/* For FIFO watermark updates */
if (HAS_PCH_SPLIT(dev)) {
- if (IS_IRONLAKE(dev)) {
+ if (IS_GEN5(dev)) {
if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK)
dev_priv->display.update_wm = ironlake_update_wm;
else {
@@ -5883,9 +5969,9 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.update_wm = pineview_update_wm;
} else if (IS_G4X(dev))
dev_priv->display.update_wm = g4x_update_wm;
- else if (IS_I965G(dev))
+ else if (IS_GEN4(dev))
dev_priv->display.update_wm = i965_update_wm;
- else if (IS_I9XX(dev)) {
+ else if (IS_GEN3(dev)) {
dev_priv->display.update_wm = i9xx_update_wm;
dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
} else if (IS_I85X(dev)) {
@@ -5999,24 +6085,24 @@ void intel_modeset_init(struct drm_device *dev)
intel_init_display(dev);
- if (IS_I965G(dev)) {
- dev->mode_config.max_width = 8192;
- dev->mode_config.max_height = 8192;
- } else if (IS_I9XX(dev)) {
+ if (IS_GEN2(dev)) {
+ dev->mode_config.max_width = 2048;
+ dev->mode_config.max_height = 2048;
+ } else if (IS_GEN3(dev)) {
dev->mode_config.max_width = 4096;
dev->mode_config.max_height = 4096;
} else {
- dev->mode_config.max_width = 2048;
- dev->mode_config.max_height = 2048;
+ dev->mode_config.max_width = 8192;
+ dev->mode_config.max_height = 8192;
}
/* set memory base */
- if (IS_I9XX(dev))
- dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2);
- else
+ if (IS_GEN2(dev))
dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0);
+ else
+ dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2);
- if (IS_MOBILE(dev) || IS_I9XX(dev))
+ if (IS_MOBILE(dev) || !IS_GEN2(dev))
dev_priv->num_pipe = 2;
else
dev_priv->num_pipe = 1;
@@ -6052,10 +6138,11 @@ void intel_modeset_cleanup(struct drm_device *dev)
struct drm_crtc *crtc;
struct intel_crtc *intel_crtc;
+ drm_kms_helper_poll_fini(dev);
mutex_lock(&dev->struct_mutex);
- drm_kms_helper_poll_fini(dev);
- intel_fbdev_fini(dev);
+ intel_unregister_dsm_handler();
+
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
/* Skip inactive CRTCs */
@@ -6063,12 +6150,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
continue;
intel_crtc = to_intel_crtc(crtc);
- intel_increase_pllclock(crtc, false);
- del_timer_sync(&intel_crtc->idle_timer);
+ intel_increase_pllclock(crtc);
}
- del_timer_sync(&dev_priv->idle_timer);
-
if (dev_priv->display.disable_fbc)
dev_priv->display.disable_fbc(dev);
@@ -6097,33 +6181,36 @@ void intel_modeset_cleanup(struct drm_device *dev)
mutex_unlock(&dev->struct_mutex);
+ /* Disable the irq before mode object teardown, for the irq might
+ * enqueue unpin/hotplug work. */
+ drm_irq_uninstall(dev);
+ cancel_work_sync(&dev_priv->hotplug_work);
+
+ /* Shut off idle work before the crtcs get freed. */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ intel_crtc = to_intel_crtc(crtc);
+ del_timer_sync(&intel_crtc->idle_timer);
+ }
+ del_timer_sync(&dev_priv->idle_timer);
+ cancel_work_sync(&dev_priv->idle_work);
+
drm_mode_config_cleanup(dev);
}
-
/*
* Return which encoder is currently attached for connector.
*/
-struct drm_encoder *intel_attached_encoder (struct drm_connector *connector)
+struct drm_encoder *intel_best_encoder(struct drm_connector *connector)
{
- struct drm_mode_object *obj;
- struct drm_encoder *encoder;
- int i;
-
- for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
- if (connector->encoder_ids[i] == 0)
- break;
-
- obj = drm_mode_object_find(connector->dev,
- connector->encoder_ids[i],
- DRM_MODE_OBJECT_ENCODER);
- if (!obj)
- continue;
+ return &intel_attached_encoder(connector)->base;
+}
- encoder = obj_to_encoder(obj);
- return encoder;
- }
- return NULL;
+void intel_connector_attach_encoder(struct intel_connector *connector,
+ struct intel_encoder *encoder)
+{
+ connector->encoder = encoder;
+ drm_mode_connector_attach_encoder(&connector->base,
+ &encoder->base);
}
/*
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 9ab8708ac6ba..891f4f1d63b1 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -42,15 +42,13 @@
#define DP_LINK_CONFIGURATION_SIZE 9
-#define IS_eDP(i) ((i)->base.type == INTEL_OUTPUT_EDP)
-#define IS_PCH_eDP(i) ((i)->is_pch_edp)
-
struct intel_dp {
struct intel_encoder base;
uint32_t output_reg;
uint32_t DP;
uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE];
bool has_audio;
+ int force_audio;
int dpms_mode;
uint8_t link_bw;
uint8_t lane_count;
@@ -58,14 +56,69 @@ struct intel_dp {
struct i2c_adapter adapter;
struct i2c_algo_dp_aux_data algo;
bool is_pch_edp;
+ uint8_t train_set[4];
+ uint8_t link_status[DP_LINK_STATUS_SIZE];
+
+ struct drm_property *force_audio_property;
};
+/**
+ * is_edp - is the given port attached to an eDP panel (either CPU or PCH)
+ * @intel_dp: DP struct
+ *
+ * If a CPU or PCH DP output is attached to an eDP panel, this function
+ * will return true, and false otherwise.
+ */
+static bool is_edp(struct intel_dp *intel_dp)
+{
+ return intel_dp->base.type == INTEL_OUTPUT_EDP;
+}
+
+/**
+ * is_pch_edp - is the port on the PCH and attached to an eDP panel?
+ * @intel_dp: DP struct
+ *
+ * Returns true if the given DP struct corresponds to a PCH DP port attached
+ * to an eDP panel, false otherwise. Helpful for determining whether we
+ * may need FDI resources for a given DP output or not.
+ */
+static bool is_pch_edp(struct intel_dp *intel_dp)
+{
+ return intel_dp->is_pch_edp;
+}
+
static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
{
- return container_of(enc_to_intel_encoder(encoder), struct intel_dp, base);
+ return container_of(encoder, struct intel_dp, base.base);
+}
+
+static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
+{
+ return container_of(intel_attached_encoder(connector),
+ struct intel_dp, base);
+}
+
+/**
+ * intel_encoder_is_pch_edp - is the given encoder a PCH attached eDP?
+ * @encoder: DRM encoder
+ *
+ * Return true if @encoder corresponds to a PCH attached eDP panel. Needed
+ * by intel_display.c.
+ */
+bool intel_encoder_is_pch_edp(struct drm_encoder *encoder)
+{
+ struct intel_dp *intel_dp;
+
+ if (!encoder)
+ return false;
+
+ intel_dp = enc_to_intel_dp(encoder);
+
+ return is_pch_edp(intel_dp);
}
-static void intel_dp_link_train(struct intel_dp *intel_dp);
+static void intel_dp_start_link_train(struct intel_dp *intel_dp);
+static void intel_dp_complete_link_train(struct intel_dp *intel_dp);
static void intel_dp_link_down(struct intel_dp *intel_dp);
void
@@ -129,8 +182,8 @@ intel_dp_link_required(struct drm_device *dev, struct intel_dp *intel_dp, int pi
{
struct drm_i915_private *dev_priv = dev->dev_private;
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
- return (pixel_clock * dev_priv->edp_bpp) / 8;
+ if (is_edp(intel_dp))
+ return (pixel_clock * dev_priv->edp.bpp + 7) / 8;
else
return pixel_clock * 3;
}
@@ -145,15 +198,13 @@ static int
intel_dp_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp));
int max_lanes = intel_dp_max_lane_count(intel_dp);
- if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
- dev_priv->panel_fixed_mode) {
+ if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) {
if (mode->hdisplay > dev_priv->panel_fixed_mode->hdisplay)
return MODE_PANEL;
@@ -163,7 +214,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
/* only refuse the mode on non eDP since we have seen some wierd eDP panels
which are outside spec tolerances but somehow work by magic */
- if (!IS_eDP(intel_dp) &&
+ if (!is_edp(intel_dp) &&
(intel_dp_link_required(connector->dev, intel_dp, mode->clock)
> intel_dp_max_data_rate(max_link_clock, max_lanes)))
return MODE_CLOCK_HIGH;
@@ -233,7 +284,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
uint8_t *recv, int recv_size)
{
uint32_t output_reg = intel_dp->output_reg;
- struct drm_device *dev = intel_dp->base.enc.dev;
+ struct drm_device *dev = intel_dp->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t ch_ctl = output_reg + 0x10;
uint32_t ch_data = ch_ctl + 4;
@@ -246,8 +297,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
/* The clock divider is based off the hrawclk,
* and would like to run at 2MHz. So, take the
* hrawclk value and divide by 2 and use that
+ *
+ * Note that PCH attached eDP panels should use a 125MHz input
+ * clock divider.
*/
- if (IS_eDP(intel_dp)) {
+ if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) {
if (IS_GEN6(dev))
aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */
else
@@ -519,8 +573,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0;
static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
- if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
- dev_priv->panel_fixed_mode) {
+ if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) {
intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN,
mode, adjusted_mode);
@@ -531,6 +584,17 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
mode->clock = dev_priv->panel_fixed_mode->clock;
}
+ /* Just use VBT values for eDP */
+ if (is_edp(intel_dp)) {
+ intel_dp->lane_count = dev_priv->edp.lanes;
+ intel_dp->link_bw = dev_priv->edp.rate;
+ adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw);
+ DRM_DEBUG_KMS("eDP link bw %02x lane count %d clock %d\n",
+ intel_dp->link_bw, intel_dp->lane_count,
+ adjusted_mode->clock);
+ return true;
+ }
+
for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
for (clock = 0; clock <= max_clock; clock++) {
int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count);
@@ -549,19 +613,6 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
}
}
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
- /* okay we failed just pick the highest */
- intel_dp->lane_count = max_lane_count;
- intel_dp->link_bw = bws[max_clock];
- adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw);
- DRM_DEBUG_KMS("Force picking display port link bw %02x lane "
- "count %d clock %d\n",
- intel_dp->link_bw, intel_dp->lane_count,
- adjusted_mode->clock);
-
- return true;
- }
-
return false;
}
@@ -598,25 +649,6 @@ intel_dp_compute_m_n(int bpp,
intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
}
-bool intel_pch_has_edp(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_mode_config *mode_config = &dev->mode_config;
- struct drm_encoder *encoder;
-
- list_for_each_entry(encoder, &mode_config->encoder_list, head) {
- struct intel_dp *intel_dp;
-
- if (encoder->crtc != crtc)
- continue;
-
- intel_dp = enc_to_intel_dp(encoder);
- if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT)
- return intel_dp->is_pch_edp;
- }
- return false;
-}
-
void
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -641,8 +673,10 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
intel_dp = enc_to_intel_dp(encoder);
if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) {
lane_count = intel_dp->lane_count;
- if (IS_PCH_eDP(intel_dp))
- bpp = dev_priv->edp_bpp;
+ break;
+ } else if (is_edp(intel_dp)) {
+ lane_count = dev_priv->edp.lanes;
+ bpp = dev_priv->edp.bpp;
break;
}
}
@@ -698,7 +732,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
{
struct drm_device *dev = encoder->dev;
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
- struct drm_crtc *crtc = intel_dp->base.enc.crtc;
+ struct drm_crtc *crtc = intel_dp->base.base.crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
intel_dp->DP = (DP_VOLTAGE_0_4 |
@@ -709,7 +743,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
intel_dp->DP |= DP_SYNC_VS_HIGH;
- if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+ if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
else
intel_dp->DP |= DP_LINK_TRAIN_OFF;
@@ -744,7 +778,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
if (intel_crtc->pipe == 1 && !HAS_PCH_CPT(dev))
intel_dp->DP |= DP_PIPEB_SELECT;
- if (IS_eDP(intel_dp)) {
+ if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) {
/* don't miss out required setting for eDP */
intel_dp->DP |= DP_PLL_ENABLE;
if (adjusted_mode->clock < 200000)
@@ -754,13 +788,15 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
}
}
-static void ironlake_edp_panel_on (struct drm_device *dev)
+/* Returns true if the panel was already on when called */
+static bool ironlake_edp_panel_on (struct intel_dp *intel_dp)
{
+ struct drm_device *dev = intel_dp->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 pp;
+ u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_STATE_ON_IDLE;
if (I915_READ(PCH_PP_STATUS) & PP_ON)
- return;
+ return true;
pp = I915_READ(PCH_PP_CONTROL);
@@ -771,21 +807,30 @@ static void ironlake_edp_panel_on (struct drm_device *dev)
pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON;
I915_WRITE(PCH_PP_CONTROL, pp);
+ POSTING_READ(PCH_PP_CONTROL);
+
+ /* Ouch. We need to wait here for some panels, like Dell e6510
+ * https://bugs.freedesktop.org/show_bug.cgi?id=29278i
+ */
+ msleep(300);
- if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000, 10))
+ if (wait_for((I915_READ(PCH_PP_STATUS) & idle_on_mask) == idle_on_mask,
+ 5000))
DRM_ERROR("panel on wait timed out: 0x%08x\n",
I915_READ(PCH_PP_STATUS));
- pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD);
pp |= PANEL_POWER_RESET; /* restore panel reset bit */
I915_WRITE(PCH_PP_CONTROL, pp);
POSTING_READ(PCH_PP_CONTROL);
+
+ return false;
}
static void ironlake_edp_panel_off (struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 pp;
+ u32 pp, idle_off_mask = PP_ON | PP_SEQUENCE_MASK |
+ PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK;
pp = I915_READ(PCH_PP_CONTROL);
@@ -796,15 +841,20 @@ static void ironlake_edp_panel_off (struct drm_device *dev)
pp &= ~POWER_TARGET_ON;
I915_WRITE(PCH_PP_CONTROL, pp);
+ POSTING_READ(PCH_PP_CONTROL);
- if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000, 10))
+ if (wait_for((I915_READ(PCH_PP_STATUS) & idle_off_mask) == 0, 5000))
DRM_ERROR("panel off wait timed out: 0x%08x\n",
I915_READ(PCH_PP_STATUS));
- /* Make sure VDD is enabled so DP AUX will work */
- pp |= EDP_FORCE_VDD | PANEL_POWER_RESET; /* restore panel reset bit */
+ pp |= PANEL_POWER_RESET; /* restore panel reset bit */
I915_WRITE(PCH_PP_CONTROL, pp);
POSTING_READ(PCH_PP_CONTROL);
+
+ /* Ouch. We need to wait here for some panels, like Dell e6510
+ * https://bugs.freedesktop.org/show_bug.cgi?id=29278i
+ */
+ msleep(300);
}
static void ironlake_edp_backlight_on (struct drm_device *dev)
@@ -813,6 +863,13 @@ static void ironlake_edp_backlight_on (struct drm_device *dev)
u32 pp;
DRM_DEBUG_KMS("\n");
+ /*
+ * If we enable the backlight right away following a panel power
+ * on, we may see slight flicker as the panel syncs with the eDP
+ * link. So delay a bit to make sure the image is solid before
+ * allowing it to appear.
+ */
+ msleep(300);
pp = I915_READ(PCH_PP_CONTROL);
pp |= EDP_BLC_ENABLE;
I915_WRITE(PCH_PP_CONTROL, pp);
@@ -837,8 +894,10 @@ static void ironlake_edp_pll_on(struct drm_encoder *encoder)
DRM_DEBUG_KMS("\n");
dpa_ctl = I915_READ(DP_A);
- dpa_ctl &= ~DP_PLL_ENABLE;
+ dpa_ctl |= DP_PLL_ENABLE;
I915_WRITE(DP_A, dpa_ctl);
+ POSTING_READ(DP_A);
+ udelay(200);
}
static void ironlake_edp_pll_off(struct drm_encoder *encoder)
@@ -848,8 +907,9 @@ static void ironlake_edp_pll_off(struct drm_encoder *encoder)
u32 dpa_ctl;
dpa_ctl = I915_READ(DP_A);
- dpa_ctl |= DP_PLL_ENABLE;
+ dpa_ctl &= ~DP_PLL_ENABLE;
I915_WRITE(DP_A, dpa_ctl);
+ POSTING_READ(DP_A);
udelay(200);
}
@@ -857,29 +917,31 @@ static void intel_dp_prepare(struct drm_encoder *encoder)
{
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t dp_reg = I915_READ(intel_dp->output_reg);
- if (IS_eDP(intel_dp)) {
+ if (is_edp(intel_dp)) {
ironlake_edp_backlight_off(dev);
- ironlake_edp_panel_on(dev);
- ironlake_edp_pll_on(encoder);
+ ironlake_edp_panel_on(intel_dp);
+ if (!is_pch_edp(intel_dp))
+ ironlake_edp_pll_on(encoder);
+ else
+ ironlake_edp_pll_off(encoder);
}
- if (dp_reg & DP_PORT_EN)
- intel_dp_link_down(intel_dp);
+ intel_dp_link_down(intel_dp);
}
static void intel_dp_commit(struct drm_encoder *encoder)
{
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t dp_reg = I915_READ(intel_dp->output_reg);
- if (!(dp_reg & DP_PORT_EN)) {
- intel_dp_link_train(intel_dp);
- }
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+ intel_dp_start_link_train(intel_dp);
+
+ if (is_edp(intel_dp))
+ ironlake_edp_panel_on(intel_dp);
+
+ intel_dp_complete_link_train(intel_dp);
+
+ if (is_edp(intel_dp))
ironlake_edp_backlight_on(dev);
}
@@ -892,22 +954,22 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
uint32_t dp_reg = I915_READ(intel_dp->output_reg);
if (mode != DRM_MODE_DPMS_ON) {
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
+ if (is_edp(intel_dp))
ironlake_edp_backlight_off(dev);
+ intel_dp_link_down(intel_dp);
+ if (is_edp(intel_dp))
ironlake_edp_panel_off(dev);
- }
- if (dp_reg & DP_PORT_EN)
- intel_dp_link_down(intel_dp);
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+ if (is_edp(intel_dp) && !is_pch_edp(intel_dp))
ironlake_edp_pll_off(encoder);
} else {
+ if (is_edp(intel_dp))
+ ironlake_edp_panel_on(intel_dp);
if (!(dp_reg & DP_PORT_EN)) {
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
- ironlake_edp_panel_on(dev);
- intel_dp_link_train(intel_dp);
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
- ironlake_edp_backlight_on(dev);
+ intel_dp_start_link_train(intel_dp);
+ intel_dp_complete_link_train(intel_dp);
}
+ if (is_edp(intel_dp))
+ ironlake_edp_backlight_on(dev);
}
intel_dp->dpms_mode = mode;
}
@@ -917,14 +979,13 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
* link status information
*/
static bool
-intel_dp_get_link_status(struct intel_dp *intel_dp,
- uint8_t link_status[DP_LINK_STATUS_SIZE])
+intel_dp_get_link_status(struct intel_dp *intel_dp)
{
int ret;
ret = intel_dp_aux_native_read(intel_dp,
DP_LANE0_1_STATUS,
- link_status, DP_LINK_STATUS_SIZE);
+ intel_dp->link_status, DP_LINK_STATUS_SIZE);
if (ret != DP_LINK_STATUS_SIZE)
return false;
return true;
@@ -999,18 +1060,15 @@ intel_dp_pre_emphasis_max(uint8_t voltage_swing)
}
static void
-intel_get_adjust_train(struct intel_dp *intel_dp,
- uint8_t link_status[DP_LINK_STATUS_SIZE],
- int lane_count,
- uint8_t train_set[4])
+intel_get_adjust_train(struct intel_dp *intel_dp)
{
uint8_t v = 0;
uint8_t p = 0;
int lane;
- for (lane = 0; lane < lane_count; lane++) {
- uint8_t this_v = intel_get_adjust_request_voltage(link_status, lane);
- uint8_t this_p = intel_get_adjust_request_pre_emphasis(link_status, lane);
+ for (lane = 0; lane < intel_dp->lane_count; lane++) {
+ uint8_t this_v = intel_get_adjust_request_voltage(intel_dp->link_status, lane);
+ uint8_t this_p = intel_get_adjust_request_pre_emphasis(intel_dp->link_status, lane);
if (this_v > v)
v = this_v;
@@ -1025,15 +1083,25 @@ intel_get_adjust_train(struct intel_dp *intel_dp,
p = intel_dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
for (lane = 0; lane < 4; lane++)
- train_set[lane] = v | p;
+ intel_dp->train_set[lane] = v | p;
}
static uint32_t
-intel_dp_signal_levels(uint8_t train_set, int lane_count)
+intel_dp_signal_levels(struct intel_dp *intel_dp)
{
- uint32_t signal_levels = 0;
+ struct drm_device *dev = intel_dp->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t signal_levels = 0;
+ u8 train_set = intel_dp->train_set[0];
+ u32 vswing = train_set & DP_TRAIN_VOLTAGE_SWING_MASK;
+ u32 preemphasis = train_set & DP_TRAIN_PRE_EMPHASIS_MASK;
+
+ if (is_edp(intel_dp)) {
+ vswing = dev_priv->edp.vswing;
+ preemphasis = dev_priv->edp.preemphasis;
+ }
- switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+ switch (vswing) {
case DP_TRAIN_VOLTAGE_SWING_400:
default:
signal_levels |= DP_VOLTAGE_0_4;
@@ -1048,7 +1116,7 @@ intel_dp_signal_levels(uint8_t train_set, int lane_count)
signal_levels |= DP_VOLTAGE_1_2;
break;
}
- switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
+ switch (preemphasis) {
case DP_TRAIN_PRE_EMPHASIS_0:
default:
signal_levels |= DP_PRE_EMPHASIS_0;
@@ -1116,18 +1184,18 @@ intel_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count
DP_LANE_CHANNEL_EQ_DONE|\
DP_LANE_SYMBOL_LOCKED)
static bool
-intel_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
+intel_channel_eq_ok(struct intel_dp *intel_dp)
{
uint8_t lane_align;
uint8_t lane_status;
int lane;
- lane_align = intel_dp_link_status(link_status,
+ lane_align = intel_dp_link_status(intel_dp->link_status,
DP_LANE_ALIGN_STATUS_UPDATED);
if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
return false;
- for (lane = 0; lane < lane_count; lane++) {
- lane_status = intel_get_lane_status(link_status, lane);
+ for (lane = 0; lane < intel_dp->lane_count; lane++) {
+ lane_status = intel_get_lane_status(intel_dp->link_status, lane);
if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS)
return false;
}
@@ -1135,159 +1203,194 @@ intel_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
}
static bool
+intel_dp_aux_handshake_required(struct intel_dp *intel_dp)
+{
+ struct drm_device *dev = intel_dp->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (is_edp(intel_dp) && dev_priv->no_aux_handshake)
+ return false;
+
+ return true;
+}
+
+static bool
intel_dp_set_link_train(struct intel_dp *intel_dp,
uint32_t dp_reg_value,
- uint8_t dp_train_pat,
- uint8_t train_set[4])
+ uint8_t dp_train_pat)
{
- struct drm_device *dev = intel_dp->base.enc.dev;
+ struct drm_device *dev = intel_dp->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
I915_WRITE(intel_dp->output_reg, dp_reg_value);
POSTING_READ(intel_dp->output_reg);
+ if (!intel_dp_aux_handshake_required(intel_dp))
+ return true;
+
intel_dp_aux_native_write_1(intel_dp,
DP_TRAINING_PATTERN_SET,
dp_train_pat);
ret = intel_dp_aux_native_write(intel_dp,
- DP_TRAINING_LANE0_SET, train_set, 4);
+ DP_TRAINING_LANE0_SET,
+ intel_dp->train_set, 4);
if (ret != 4)
return false;
return true;
}
+/* Enable corresponding port and start training pattern 1 */
static void
-intel_dp_link_train(struct intel_dp *intel_dp)
+intel_dp_start_link_train(struct intel_dp *intel_dp)
{
- struct drm_device *dev = intel_dp->base.enc.dev;
+ struct drm_device *dev = intel_dp->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- uint8_t train_set[4];
- uint8_t link_status[DP_LINK_STATUS_SIZE];
+ struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
int i;
uint8_t voltage;
bool clock_recovery = false;
- bool channel_eq = false;
int tries;
u32 reg;
uint32_t DP = intel_dp->DP;
- struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc);
/* Enable output, wait for it to become active */
I915_WRITE(intel_dp->output_reg, intel_dp->DP);
POSTING_READ(intel_dp->output_reg);
intel_wait_for_vblank(dev, intel_crtc->pipe);
- /* Write the link configuration data */
- intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
- intel_dp->link_configuration,
- DP_LINK_CONFIGURATION_SIZE);
+ if (intel_dp_aux_handshake_required(intel_dp))
+ /* Write the link configuration data */
+ intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
+ intel_dp->link_configuration,
+ DP_LINK_CONFIGURATION_SIZE);
DP |= DP_PORT_EN;
- if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+ if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
DP &= ~DP_LINK_TRAIN_MASK_CPT;
else
DP &= ~DP_LINK_TRAIN_MASK;
- memset(train_set, 0, 4);
+ memset(intel_dp->train_set, 0, 4);
voltage = 0xff;
tries = 0;
clock_recovery = false;
for (;;) {
- /* Use train_set[0] to set the voltage and pre emphasis values */
+ /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
uint32_t signal_levels;
- if (IS_GEN6(dev) && IS_eDP(intel_dp)) {
- signal_levels = intel_gen6_edp_signal_levels(train_set[0]);
+ if (IS_GEN6(dev) && is_edp(intel_dp)) {
+ signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
} else {
- signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count);
+ signal_levels = intel_dp_signal_levels(intel_dp);
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
}
- if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+ if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
reg = DP | DP_LINK_TRAIN_PAT_1_CPT;
else
reg = DP | DP_LINK_TRAIN_PAT_1;
if (!intel_dp_set_link_train(intel_dp, reg,
- DP_TRAINING_PATTERN_1, train_set))
+ DP_TRAINING_PATTERN_1))
break;
/* Set training pattern 1 */
- udelay(100);
- if (!intel_dp_get_link_status(intel_dp, link_status))
+ udelay(500);
+ if (intel_dp_aux_handshake_required(intel_dp)) {
break;
+ } else {
+ if (!intel_dp_get_link_status(intel_dp))
+ break;
- if (intel_clock_recovery_ok(link_status, intel_dp->lane_count)) {
- clock_recovery = true;
- break;
- }
-
- /* Check to see if we've tried the max voltage */
- for (i = 0; i < intel_dp->lane_count; i++)
- if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+ if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
+ clock_recovery = true;
break;
- if (i == intel_dp->lane_count)
- break;
+ }
- /* Check to see if we've tried the same voltage 5 times */
- if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
- ++tries;
- if (tries == 5)
+ /* Check to see if we've tried the max voltage */
+ for (i = 0; i < intel_dp->lane_count; i++)
+ if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+ break;
+ if (i == intel_dp->lane_count)
break;
- } else
- tries = 0;
- voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
- /* Compute new train_set as requested by target */
- intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set);
+ /* Check to see if we've tried the same voltage 5 times */
+ if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+ ++tries;
+ if (tries == 5)
+ break;
+ } else
+ tries = 0;
+ voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+
+ /* Compute new intel_dp->train_set as requested by target */
+ intel_get_adjust_train(intel_dp);
+ }
}
+ intel_dp->DP = DP;
+}
+
+static void
+intel_dp_complete_link_train(struct intel_dp *intel_dp)
+{
+ struct drm_device *dev = intel_dp->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ bool channel_eq = false;
+ int tries;
+ u32 reg;
+ uint32_t DP = intel_dp->DP;
+
/* channel equalization */
tries = 0;
channel_eq = false;
for (;;) {
- /* Use train_set[0] to set the voltage and pre emphasis values */
+ /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
uint32_t signal_levels;
- if (IS_GEN6(dev) && IS_eDP(intel_dp)) {
- signal_levels = intel_gen6_edp_signal_levels(train_set[0]);
+ if (IS_GEN6(dev) && is_edp(intel_dp)) {
+ signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
} else {
- signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count);
+ signal_levels = intel_dp_signal_levels(intel_dp);
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
}
- if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+ if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
reg = DP | DP_LINK_TRAIN_PAT_2_CPT;
else
reg = DP | DP_LINK_TRAIN_PAT_2;
/* channel eq pattern */
if (!intel_dp_set_link_train(intel_dp, reg,
- DP_TRAINING_PATTERN_2, train_set))
+ DP_TRAINING_PATTERN_2))
break;
- udelay(400);
- if (!intel_dp_get_link_status(intel_dp, link_status))
- break;
+ udelay(500);
- if (intel_channel_eq_ok(link_status, intel_dp->lane_count)) {
- channel_eq = true;
+ if (!intel_dp_aux_handshake_required(intel_dp)) {
break;
- }
+ } else {
+ if (!intel_dp_get_link_status(intel_dp))
+ break;
- /* Try 5 times */
- if (tries > 5)
- break;
+ if (intel_channel_eq_ok(intel_dp)) {
+ channel_eq = true;
+ break;
+ }
- /* Compute new train_set as requested by target */
- intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set);
- ++tries;
- }
+ /* Try 5 times */
+ if (tries > 5)
+ break;
- if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+ /* Compute new intel_dp->train_set as requested by target */
+ intel_get_adjust_train(intel_dp);
+ ++tries;
+ }
+ }
+ if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
reg = DP | DP_LINK_TRAIN_OFF_CPT;
else
reg = DP | DP_LINK_TRAIN_OFF;
@@ -1301,32 +1404,31 @@ intel_dp_link_train(struct intel_dp *intel_dp)
static void
intel_dp_link_down(struct intel_dp *intel_dp)
{
- struct drm_device *dev = intel_dp->base.enc.dev;
+ struct drm_device *dev = intel_dp->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t DP = intel_dp->DP;
DRM_DEBUG_KMS("\n");
- if (IS_eDP(intel_dp)) {
+ if (is_edp(intel_dp)) {
DP &= ~DP_PLL_ENABLE;
I915_WRITE(intel_dp->output_reg, DP);
POSTING_READ(intel_dp->output_reg);
udelay(100);
}
- if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) {
+ if (HAS_PCH_CPT(dev) && !is_edp(intel_dp)) {
DP &= ~DP_LINK_TRAIN_MASK_CPT;
I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
- POSTING_READ(intel_dp->output_reg);
} else {
DP &= ~DP_LINK_TRAIN_MASK;
I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
- POSTING_READ(intel_dp->output_reg);
}
+ POSTING_READ(intel_dp->output_reg);
- udelay(17000);
+ msleep(17);
- if (IS_eDP(intel_dp))
+ if (is_edp(intel_dp))
DP |= DP_LINK_TRAIN_OFF;
I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
POSTING_READ(intel_dp->output_reg);
@@ -1344,32 +1446,34 @@ intel_dp_link_down(struct intel_dp *intel_dp)
static void
intel_dp_check_link_status(struct intel_dp *intel_dp)
{
- uint8_t link_status[DP_LINK_STATUS_SIZE];
-
- if (!intel_dp->base.enc.crtc)
+ if (!intel_dp->base.base.crtc)
return;
- if (!intel_dp_get_link_status(intel_dp, link_status)) {
+ if (!intel_dp_get_link_status(intel_dp)) {
intel_dp_link_down(intel_dp);
return;
}
- if (!intel_channel_eq_ok(link_status, intel_dp->lane_count))
- intel_dp_link_train(intel_dp);
+ if (!intel_channel_eq_ok(intel_dp)) {
+ intel_dp_start_link_train(intel_dp);
+ intel_dp_complete_link_train(intel_dp);
+ }
}
static enum drm_connector_status
-ironlake_dp_detect(struct drm_connector *connector)
+ironlake_dp_detect(struct intel_dp *intel_dp)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
enum drm_connector_status status;
+ /* Can't disconnect eDP */
+ if (is_edp(intel_dp))
+ return connector_status_connected;
+
status = connector_status_disconnected;
if (intel_dp_aux_native_read(intel_dp,
0x000, intel_dp->dpcd,
- sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd))
- {
+ sizeof (intel_dp->dpcd))
+ == sizeof(intel_dp->dpcd)) {
if (intel_dp->dpcd[0] != 0)
status = connector_status_connected;
}
@@ -1378,26 +1482,13 @@ ironlake_dp_detect(struct drm_connector *connector)
return status;
}
-/**
- * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
- *
- * \return true if DP port is connected.
- * \return false if DP port is disconnected.
- */
static enum drm_connector_status
-intel_dp_detect(struct drm_connector *connector, bool force)
+g4x_dp_detect(struct intel_dp *intel_dp)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
- struct drm_device *dev = intel_dp->base.enc.dev;
+ struct drm_device *dev = intel_dp->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t temp, bit;
enum drm_connector_status status;
-
- intel_dp->has_audio = false;
-
- if (HAS_PCH_SPLIT(dev))
- return ironlake_dp_detect(connector);
+ uint32_t temp, bit;
switch (intel_dp->output_reg) {
case DP_B:
@@ -1419,31 +1510,66 @@ intel_dp_detect(struct drm_connector *connector, bool force)
return connector_status_disconnected;
status = connector_status_disconnected;
- if (intel_dp_aux_native_read(intel_dp,
- 0x000, intel_dp->dpcd,
+ if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd,
sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd))
{
if (intel_dp->dpcd[0] != 0)
status = connector_status_connected;
}
- return status;
+
+ return bit;
+}
+
+/**
+ * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
+ *
+ * \return true if DP port is connected.
+ * \return false if DP port is disconnected.
+ */
+static enum drm_connector_status
+intel_dp_detect(struct drm_connector *connector, bool force)
+{
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
+ struct drm_device *dev = intel_dp->base.base.dev;
+ enum drm_connector_status status;
+ struct edid *edid = NULL;
+
+ intel_dp->has_audio = false;
+
+ if (HAS_PCH_SPLIT(dev))
+ status = ironlake_dp_detect(intel_dp);
+ else
+ status = g4x_dp_detect(intel_dp);
+ if (status != connector_status_connected)
+ return status;
+
+ if (intel_dp->force_audio) {
+ intel_dp->has_audio = intel_dp->force_audio > 0;
+ } else {
+ edid = drm_get_edid(connector, &intel_dp->adapter);
+ if (edid) {
+ intel_dp->has_audio = drm_detect_monitor_audio(edid);
+ connector->display_info.raw_edid = NULL;
+ kfree(edid);
+ }
+ }
+
+ return connector_status_connected;
}
static int intel_dp_get_modes(struct drm_connector *connector)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
- struct drm_device *dev = intel_dp->base.enc.dev;
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
+ struct drm_device *dev = intel_dp->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
/* We should parse the EDID data and find out if it has an audio sink
*/
- ret = intel_ddc_get_modes(connector, intel_dp->base.ddc_bus);
+ ret = intel_ddc_get_modes(connector, &intel_dp->adapter);
if (ret) {
- if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
- !dev_priv->panel_fixed_mode) {
+ if (is_edp(intel_dp) && !dev_priv->panel_fixed_mode) {
struct drm_display_mode *newmode;
list_for_each_entry(newmode, &connector->probed_modes,
head) {
@@ -1459,7 +1585,7 @@ static int intel_dp_get_modes(struct drm_connector *connector)
}
/* if eDP has no EDID, try to use fixed panel mode from VBT */
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
+ if (is_edp(intel_dp)) {
if (dev_priv->panel_fixed_mode != NULL) {
struct drm_display_mode *mode;
mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
@@ -1470,6 +1596,46 @@ static int intel_dp_get_modes(struct drm_connector *connector)
return 0;
}
+static int
+intel_dp_set_property(struct drm_connector *connector,
+ struct drm_property *property,
+ uint64_t val)
+{
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
+ int ret;
+
+ ret = drm_connector_property_set_value(connector, property, val);
+ if (ret)
+ return ret;
+
+ if (property == intel_dp->force_audio_property) {
+ if (val == intel_dp->force_audio)
+ return 0;
+
+ intel_dp->force_audio = val;
+
+ if (val > 0 && intel_dp->has_audio)
+ return 0;
+ if (val < 0 && !intel_dp->has_audio)
+ return 0;
+
+ intel_dp->has_audio = val > 0;
+ goto done;
+ }
+
+ return -EINVAL;
+
+done:
+ if (intel_dp->base.base.crtc) {
+ struct drm_crtc *crtc = intel_dp->base.base.crtc;
+ drm_crtc_helper_set_mode(crtc, &crtc->mode,
+ crtc->x, crtc->y,
+ crtc->fb);
+ }
+
+ return 0;
+}
+
static void
intel_dp_destroy (struct drm_connector *connector)
{
@@ -1478,6 +1644,15 @@ intel_dp_destroy (struct drm_connector *connector)
kfree(connector);
}
+static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
+{
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+ i2c_del_adapter(&intel_dp->adapter);
+ drm_encoder_cleanup(encoder);
+ kfree(intel_dp);
+}
+
static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
.dpms = intel_dp_dpms,
.mode_fixup = intel_dp_mode_fixup,
@@ -1490,20 +1665,21 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.detect = intel_dp_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
+ .set_property = intel_dp_set_property,
.destroy = intel_dp_destroy,
};
static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
.get_modes = intel_dp_get_modes,
.mode_valid = intel_dp_mode_valid,
- .best_encoder = intel_attached_encoder,
+ .best_encoder = intel_best_encoder,
};
static const struct drm_encoder_funcs intel_dp_enc_funcs = {
- .destroy = intel_encoder_destroy,
+ .destroy = intel_dp_encoder_destroy,
};
-void
+static void
intel_dp_hot_plug(struct intel_encoder *intel_encoder)
{
struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base);
@@ -1554,6 +1730,20 @@ bool intel_dpd_is_edp(struct drm_device *dev)
return false;
}
+static void
+intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+
+ intel_dp->force_audio_property =
+ drm_property_create(dev, DRM_MODE_PROP_RANGE, "force_audio", 2);
+ if (intel_dp->force_audio_property) {
+ intel_dp->force_audio_property->values[0] = -1;
+ intel_dp->force_audio_property->values[1] = 1;
+ drm_connector_attach_property(connector, intel_dp->force_audio_property, 0);
+ }
+}
+
void
intel_dp_init(struct drm_device *dev, int output_reg)
{
@@ -1580,7 +1770,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
if (intel_dpd_is_edp(dev))
intel_dp->is_pch_edp = true;
- if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) {
+ if (output_reg == DP_A || is_pch_edp(intel_dp)) {
type = DRM_MODE_CONNECTOR_eDP;
intel_encoder->type = INTEL_OUTPUT_EDP;
} else {
@@ -1601,7 +1791,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
else if (output_reg == DP_D || output_reg == PCH_DP_D)
intel_encoder->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
- if (IS_eDP(intel_dp))
+ if (is_edp(intel_dp))
intel_encoder->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
@@ -1612,12 +1802,11 @@ intel_dp_init(struct drm_device *dev, int output_reg)
intel_dp->has_audio = false;
intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
- drm_encoder_init(dev, &intel_encoder->enc, &intel_dp_enc_funcs,
+ drm_encoder_init(dev, &intel_encoder->base, &intel_dp_enc_funcs,
DRM_MODE_ENCODER_TMDS);
- drm_encoder_helper_add(&intel_encoder->enc, &intel_dp_helper_funcs);
+ drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs);
- drm_mode_connector_attach_encoder(&intel_connector->base,
- &intel_encoder->enc);
+ intel_connector_attach_encoder(intel_connector, intel_encoder);
drm_sysfs_connector_add(connector);
/* Set up the DDC bus. */
@@ -1647,10 +1836,29 @@ intel_dp_init(struct drm_device *dev, int output_reg)
intel_dp_i2c_init(intel_dp, intel_connector, name);
- intel_encoder->ddc_bus = &intel_dp->adapter;
+ /* Cache some DPCD data in the eDP case */
+ if (is_edp(intel_dp)) {
+ int ret;
+ bool was_on;
+
+ was_on = ironlake_edp_panel_on(intel_dp);
+ ret = intel_dp_aux_native_read(intel_dp, DP_DPCD_REV,
+ intel_dp->dpcd,
+ sizeof(intel_dp->dpcd));
+ if (ret == sizeof(intel_dp->dpcd)) {
+ if (intel_dp->dpcd[0] >= 0x11)
+ dev_priv->no_aux_handshake = intel_dp->dpcd[3] &
+ DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
+ } else {
+ DRM_ERROR("failed to retrieve link info\n");
+ }
+ if (!was_on)
+ ironlake_edp_panel_off(dev);
+ }
+
intel_encoder->hot_plug = intel_dp_hot_plug;
- if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) {
+ if (is_edp(intel_dp)) {
/* initialize panel mode from VBT if available for eDP */
if (dev_priv->lfp_lvds_vbt_mode) {
dev_priv->panel_fixed_mode =
@@ -1662,6 +1870,8 @@ intel_dp_init(struct drm_device *dev, int output_reg)
}
}
+ intel_dp_add_properties(intel_dp, connector);
+
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
* 0xd. Failure to do so will result in spurious interrupts being
* generated on the port when a cable is not attached.
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8828b3ac6414..9af9f86a8765 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -26,14 +26,12 @@
#define __INTEL_DRV_H__
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
-#include <linux/i2c-algo-bit.h>
#include "i915_drv.h"
#include "drm_crtc.h"
-
#include "drm_crtc_helper.h"
+#include "drm_fb_helper.h"
-#define wait_for(COND, MS, W) ({ \
+#define _wait_for(COND, MS, W) ({ \
unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \
int ret__ = 0; \
while (! (COND)) { \
@@ -41,11 +39,24 @@
ret__ = -ETIMEDOUT; \
break; \
} \
- if (W) msleep(W); \
+ if (W && !in_dbg_master()) msleep(W); \
} \
ret__; \
})
+#define wait_for(COND, MS) _wait_for(COND, MS, 1)
+#define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0)
+
+#define MSLEEP(x) do { \
+ if (in_dbg_master()) \
+ mdelay(x); \
+ else \
+ msleep(x); \
+} while(0)
+
+#define KHz(x) (1000*x)
+#define MHz(x) KHz(1000*x)
+
/*
* Display related stuff
*/
@@ -96,24 +107,39 @@
#define INTEL_DVO_CHIP_TMDS 2
#define INTEL_DVO_CHIP_TVOUT 4
-struct intel_i2c_chan {
- struct drm_device *drm_dev; /* for getting at dev. private (mmio etc.) */
- u32 reg; /* GPIO reg */
- struct i2c_adapter adapter;
- struct i2c_algo_bit_data algo;
-};
+/* drm_display_mode->private_flags */
+#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0)
+#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)
+
+static inline void
+intel_mode_set_pixel_multiplier(struct drm_display_mode *mode,
+ int multiplier)
+{
+ mode->clock *= multiplier;
+ mode->private_flags |= multiplier;
+}
+
+static inline int
+intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode)
+{
+ return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT;
+}
struct intel_framebuffer {
struct drm_framebuffer base;
struct drm_gem_object *obj;
};
+struct intel_fbdev {
+ struct drm_fb_helper helper;
+ struct intel_framebuffer ifb;
+ struct list_head fbdev_list;
+ struct drm_display_mode *our_mode;
+};
struct intel_encoder {
- struct drm_encoder enc;
+ struct drm_encoder base;
int type;
- struct i2c_adapter *i2c_bus;
- struct i2c_adapter *ddc_bus;
bool load_detect_temp;
bool needs_tv_clock;
void (*hot_plug)(struct intel_encoder *);
@@ -123,32 +149,7 @@ struct intel_encoder {
struct intel_connector {
struct drm_connector base;
-};
-
-struct intel_crtc;
-struct intel_overlay {
- struct drm_device *dev;
- struct intel_crtc *crtc;
- struct drm_i915_gem_object *vid_bo;
- struct drm_i915_gem_object *old_vid_bo;
- int active;
- int pfit_active;
- u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
- u32 color_key;
- u32 brightness, contrast, saturation;
- u32 old_xscale, old_yscale;
- /* register access */
- u32 flip_addr;
- struct drm_i915_gem_object *reg_bo;
- void *virt_addr;
- /* flip handling */
- uint32_t last_flip_req;
- int hw_wedged;
-#define HW_WEDGED 1
-#define NEEDS_WAIT_FOR_FLIP 2
-#define RELEASE_OLD_VID 3
-#define SWITCH_OFF_STAGE_1 4
-#define SWITCH_OFF_STAGE_2 5
+ struct intel_encoder *encoder;
};
struct intel_crtc {
@@ -157,6 +158,7 @@ struct intel_crtc {
enum plane plane;
u8 lut_r[256], lut_g[256], lut_b[256];
int dpms_mode;
+ bool active; /* is the crtc on? independent of the dpms mode */
bool busy; /* is scanout buffer being updated frequently? */
struct timer_list idle_timer;
bool lowfreq_avail;
@@ -168,14 +170,53 @@ struct intel_crtc {
uint32_t cursor_addr;
int16_t cursor_x, cursor_y;
int16_t cursor_width, cursor_height;
- bool cursor_visible, cursor_on;
+ bool cursor_visible;
};
#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
#define to_intel_connector(x) container_of(x, struct intel_connector, base)
-#define enc_to_intel_encoder(x) container_of(x, struct intel_encoder, enc)
+#define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
#define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
+#define DIP_TYPE_AVI 0x82
+#define DIP_VERSION_AVI 0x2
+#define DIP_LEN_AVI 13
+
+struct dip_infoframe {
+ uint8_t type; /* HB0 */
+ uint8_t ver; /* HB1 */
+ uint8_t len; /* HB2 - body len, not including checksum */
+ uint8_t ecc; /* Header ECC */
+ uint8_t checksum; /* PB0 */
+ union {
+ struct {
+ /* PB1 - Y 6:5, A 4:4, B 3:2, S 1:0 */
+ uint8_t Y_A_B_S;
+ /* PB2 - C 7:6, M 5:4, R 3:0 */
+ uint8_t C_M_R;
+ /* PB3 - ITC 7:7, EC 6:4, Q 3:2, SC 1:0 */
+ uint8_t ITC_EC_Q_SC;
+ /* PB4 - VIC 6:0 */
+ uint8_t VIC;
+ /* PB5 - PR 3:0 */
+ uint8_t PR;
+ /* PB6 to PB13 */
+ uint16_t top_bar_end;
+ uint16_t bottom_bar_start;
+ uint16_t left_bar_end;
+ uint16_t right_bar_start;
+ } avi;
+ uint8_t payload[27];
+ } __attribute__ ((packed)) body;
+} __attribute__((packed));
+
+static inline struct drm_crtc *
+intel_get_crtc_for_pipe(struct drm_device *dev, int pipe)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ return dev_priv->pipe_to_crtc_mapping[pipe];
+}
+
struct intel_unpin_work {
struct work_struct work;
struct drm_device *dev;
@@ -186,16 +227,12 @@ struct intel_unpin_work {
bool enable_stall_check;
};
-struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
- const char *name);
-void intel_i2c_destroy(struct i2c_adapter *adapter);
int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
-extern bool intel_ddc_probe(struct intel_encoder *intel_encoder);
-void intel_i2c_quirk_set(struct drm_device *dev, bool enable);
-void intel_i2c_reset_gmbus(struct drm_device *dev);
+extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
extern void intel_crt_init(struct drm_device *dev);
extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
+void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
extern bool intel_sdvo_init(struct drm_device *dev, int output_device);
extern void intel_dvo_init(struct drm_device *dev);
extern void intel_tv_init(struct drm_device *dev);
@@ -205,32 +242,41 @@ extern void intel_dp_init(struct drm_device *dev, int dp_reg);
void
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
-extern bool intel_pch_has_edp(struct drm_crtc *crtc);
extern bool intel_dpd_is_edp(struct drm_device *dev);
extern void intel_edp_link_config (struct intel_encoder *, int *, int *);
+extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder);
-
+/* intel_panel.c */
extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
struct drm_display_mode *adjusted_mode);
extern void intel_pch_panel_fitting(struct drm_device *dev,
int fitting_mode,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
+extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
+extern u32 intel_panel_get_backlight(struct drm_device *dev);
+extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
-extern int intel_panel_fitter_pipe (struct drm_device *dev);
extern void intel_crtc_load_lut(struct drm_crtc *crtc);
extern void intel_encoder_prepare (struct drm_encoder *encoder);
extern void intel_encoder_commit (struct drm_encoder *encoder);
extern void intel_encoder_destroy(struct drm_encoder *encoder);
-extern struct drm_encoder *intel_attached_encoder(struct drm_connector *connector);
+static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector)
+{
+ return to_intel_connector(connector)->encoder;
+}
+
+extern void intel_connector_attach_encoder(struct intel_connector *connector,
+ struct intel_encoder *encoder);
+extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector);
extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
struct drm_crtc *crtc);
int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
-extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe);
+extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
struct drm_connector *connector,
struct drm_display_mode *mode,
@@ -252,7 +298,8 @@ extern void ironlake_enable_drps(struct drm_device *dev);
extern void ironlake_disable_drps(struct drm_device *dev);
extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
- struct drm_gem_object *obj);
+ struct drm_gem_object *obj,
+ bool pipelined);
extern int intel_framebuffer_init(struct drm_device *dev,
struct intel_framebuffer *ifb,
@@ -267,9 +314,8 @@ extern void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
extern void intel_setup_overlay(struct drm_device *dev);
extern void intel_cleanup_overlay(struct drm_device *dev);
-extern int intel_overlay_switch_off(struct intel_overlay *overlay);
-extern int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
- int interruptible);
+extern int intel_overlay_switch_off(struct intel_overlay *overlay,
+ bool interruptible);
extern int intel_overlay_put_image(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int intel_overlay_attrs(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index 7c9ec1472d46..ea373283c93b 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -72,7 +72,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
.name = "ch7017",
.dvo_reg = DVOC,
.slave_addr = 0x75,
- .gpio = GPIOE,
+ .gpio = GMBUS_PORT_DPB,
.dev_ops = &ch7017_ops,
}
};
@@ -88,7 +88,13 @@ struct intel_dvo {
static struct intel_dvo *enc_to_intel_dvo(struct drm_encoder *encoder)
{
- return container_of(enc_to_intel_encoder(encoder), struct intel_dvo, base);
+ return container_of(encoder, struct intel_dvo, base.base);
+}
+
+static struct intel_dvo *intel_attached_dvo(struct drm_connector *connector)
+{
+ return container_of(intel_attached_encoder(connector),
+ struct intel_dvo, base);
}
static void intel_dvo_dpms(struct drm_encoder *encoder, int mode)
@@ -112,8 +118,7 @@ static void intel_dvo_dpms(struct drm_encoder *encoder, int mode)
static int intel_dvo_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+ struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
return MODE_NO_DBLESCAN;
@@ -224,23 +229,22 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder,
static enum drm_connector_status
intel_dvo_detect(struct drm_connector *connector, bool force)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
-
+ struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);
}
static int intel_dvo_get_modes(struct drm_connector *connector)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+ struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
+ struct drm_i915_private *dev_priv = connector->dev->dev_private;
/* We should probably have an i2c driver get_modes function for those
* devices which will have a fixed set of modes determined by the chip
* (TV-out, for example), but for now with just TMDS and LVDS,
* that's not the case.
*/
- intel_ddc_get_modes(connector, intel_dvo->base.ddc_bus);
+ intel_ddc_get_modes(connector,
+ &dev_priv->gmbus[GMBUS_PORT_DPC].adapter);
if (!list_empty(&connector->probed_modes))
return 1;
@@ -281,7 +285,7 @@ static const struct drm_connector_funcs intel_dvo_connector_funcs = {
static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = {
.mode_valid = intel_dvo_mode_valid,
.get_modes = intel_dvo_get_modes,
- .best_encoder = intel_attached_encoder,
+ .best_encoder = intel_best_encoder,
};
static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
@@ -311,8 +315,7 @@ intel_dvo_get_current_mode(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+ struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
uint32_t dvo_val = I915_READ(intel_dvo->dev.dvo_reg);
struct drm_display_mode *mode = NULL;
@@ -323,7 +326,7 @@ intel_dvo_get_current_mode(struct drm_connector *connector)
struct drm_crtc *crtc;
int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0;
- crtc = intel_get_crtc_from_pipe(dev, pipe);
+ crtc = intel_get_crtc_for_pipe(dev, pipe);
if (crtc) {
mode = intel_crtc_mode_get(dev, crtc);
if (mode) {
@@ -341,11 +344,10 @@ intel_dvo_get_current_mode(struct drm_connector *connector)
void intel_dvo_init(struct drm_device *dev)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *intel_encoder;
struct intel_dvo *intel_dvo;
struct intel_connector *intel_connector;
- struct i2c_adapter *i2cbus = NULL;
- int ret = 0;
int i;
int encoder_type = DRM_MODE_ENCODER_NONE;
@@ -360,16 +362,14 @@ void intel_dvo_init(struct drm_device *dev)
}
intel_encoder = &intel_dvo->base;
-
- /* Set up the DDC bus */
- intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D");
- if (!intel_encoder->ddc_bus)
- goto free_intel;
+ drm_encoder_init(dev, &intel_encoder->base,
+ &intel_dvo_enc_funcs, encoder_type);
/* Now, try to find a controller */
for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
struct drm_connector *connector = &intel_connector->base;
const struct intel_dvo_device *dvo = &intel_dvo_devices[i];
+ struct i2c_adapter *i2c;
int gpio;
/* Allow the I2C driver info to specify the GPIO to be used in
@@ -379,24 +379,18 @@ void intel_dvo_init(struct drm_device *dev)
if (dvo->gpio != 0)
gpio = dvo->gpio;
else if (dvo->type == INTEL_DVO_CHIP_LVDS)
- gpio = GPIOB;
+ gpio = GMBUS_PORT_SSC;
else
- gpio = GPIOE;
+ gpio = GMBUS_PORT_DPB;
/* Set up the I2C bus necessary for the chip we're probing.
* It appears that everything is on GPIOE except for panels
* on i830 laptops, which are on GPIOB (DVOA).
*/
- if (i2cbus != NULL)
- intel_i2c_destroy(i2cbus);
- if (!(i2cbus = intel_i2c_create(dev, gpio,
- gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) {
- continue;
- }
+ i2c = &dev_priv->gmbus[gpio].adapter;
intel_dvo->dev = *dvo;
- ret = dvo->dev_ops->init(&intel_dvo->dev, i2cbus);
- if (!ret)
+ if (!dvo->dev_ops->init(&intel_dvo->dev, i2c))
continue;
intel_encoder->type = INTEL_OUTPUT_DVO;
@@ -427,13 +421,10 @@ void intel_dvo_init(struct drm_device *dev)
connector->interlace_allowed = false;
connector->doublescan_allowed = false;
- drm_encoder_init(dev, &intel_encoder->enc,
- &intel_dvo_enc_funcs, encoder_type);
- drm_encoder_helper_add(&intel_encoder->enc,
+ drm_encoder_helper_add(&intel_encoder->base,
&intel_dvo_helper_funcs);
- drm_mode_connector_attach_encoder(&intel_connector->base,
- &intel_encoder->enc);
+ intel_connector_attach_encoder(intel_connector, intel_encoder);
if (dvo->type == INTEL_DVO_CHIP_LVDS) {
/* For our LVDS chipsets, we should hopefully be able
* to dig the fixed panel mode out of the BIOS data.
@@ -451,11 +442,7 @@ void intel_dvo_init(struct drm_device *dev)
return;
}
- intel_i2c_destroy(intel_encoder->ddc_bus);
- /* Didn't find a chip, so tear down. */
- if (i2cbus != NULL)
- intel_i2c_destroy(i2cbus);
-free_intel:
+ drm_encoder_cleanup(&intel_encoder->base);
kfree(intel_dvo);
kfree(intel_connector);
}
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index b61966c126d3..af2a1dddc28e 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -44,13 +44,6 @@
#include "i915_drm.h"
#include "i915_drv.h"
-struct intel_fbdev {
- struct drm_fb_helper helper;
- struct intel_framebuffer ifb;
- struct list_head fbdev_list;
- struct drm_display_mode *our_mode;
-};
-
static struct fb_ops intelfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = drm_fb_helper_check_var,
@@ -75,7 +68,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
struct drm_gem_object *fbo = NULL;
struct drm_i915_gem_object *obj_priv;
struct device *device = &dev->pdev->dev;
- int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1;
+ int size, ret, mmio_bar = IS_GEN2(dev) ? 1 : 0;
/* we don't do packed 24bpp */
if (sizes->surface_bpp == 24)
@@ -100,19 +93,13 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
mutex_lock(&dev->struct_mutex);
- ret = intel_pin_and_fence_fb_obj(dev, fbo);
+ /* Flush everything out, we'll be doing GTT only from now on */
+ ret = intel_pin_and_fence_fb_obj(dev, fbo, false);
if (ret) {
DRM_ERROR("failed to pin fb: %d\n", ret);
goto out_unref;
}
- /* Flush everything out, we'll be doing GTT only from now on */
- ret = i915_gem_object_set_to_gtt_domain(fbo, 1);
- if (ret) {
- DRM_ERROR("failed to bind fb: %d.\n", ret);
- goto out_unpin;
- }
-
info = framebuffer_alloc(0, device);
if (!info) {
ret = -ENOMEM;
@@ -142,7 +129,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
goto out_unpin;
}
info->apertures->ranges[0].base = dev->mode_config.fb_base;
- if (IS_I9XX(dev))
+ if (!IS_GEN2(dev))
info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 2);
else
info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0);
@@ -219,8 +206,8 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
.fb_probe = intel_fb_find_or_create_single,
};
-int intel_fbdev_destroy(struct drm_device *dev,
- struct intel_fbdev *ifbdev)
+static void intel_fbdev_destroy(struct drm_device *dev,
+ struct intel_fbdev *ifbdev)
{
struct fb_info *info;
struct intel_framebuffer *ifb = &ifbdev->ifb;
@@ -238,11 +225,9 @@ int intel_fbdev_destroy(struct drm_device *dev,
drm_framebuffer_cleanup(&ifb->base);
if (ifb->obj) {
- drm_gem_object_unreference(ifb->obj);
+ drm_gem_object_unreference_unlocked(ifb->obj);
ifb->obj = NULL;
}
-
- return 0;
}
int intel_fbdev_init(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 926934a482ec..0d0273e7b029 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -40,12 +40,76 @@
struct intel_hdmi {
struct intel_encoder base;
u32 sdvox_reg;
+ int ddc_bus;
bool has_hdmi_sink;
+ bool has_audio;
+ int force_audio;
+ struct drm_property *force_audio_property;
};
static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
{
- return container_of(enc_to_intel_encoder(encoder), struct intel_hdmi, base);
+ return container_of(encoder, struct intel_hdmi, base.base);
+}
+
+static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
+{
+ return container_of(intel_attached_encoder(connector),
+ struct intel_hdmi, base);
+}
+
+void intel_dip_infoframe_csum(struct dip_infoframe *avi_if)
+{
+ uint8_t *data = (uint8_t *)avi_if;
+ uint8_t sum = 0;
+ unsigned i;
+
+ avi_if->checksum = 0;
+ avi_if->ecc = 0;
+
+ for (i = 0; i < sizeof(*avi_if); i++)
+ sum += data[i];
+
+ avi_if->checksum = 0x100 - sum;
+}
+
+static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
+{
+ struct dip_infoframe avi_if = {
+ .type = DIP_TYPE_AVI,
+ .ver = DIP_VERSION_AVI,
+ .len = DIP_LEN_AVI,
+ };
+ uint32_t *data = (uint32_t *)&avi_if;
+ struct drm_device *dev = encoder->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+ u32 port;
+ unsigned i;
+
+ if (!intel_hdmi->has_hdmi_sink)
+ return;
+
+ /* XXX first guess at handling video port, is this corrent? */
+ if (intel_hdmi->sdvox_reg == SDVOB)
+ port = VIDEO_DIP_PORT_B;
+ else if (intel_hdmi->sdvox_reg == SDVOC)
+ port = VIDEO_DIP_PORT_C;
+ else
+ return;
+
+ I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port |
+ VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC);
+
+ intel_dip_infoframe_csum(&avi_if);
+ for (i = 0; i < sizeof(avi_if); i += 4) {
+ I915_WRITE(VIDEO_DIP_DATA, *data);
+ data++;
+ }
+
+ I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port |
+ VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC |
+ VIDEO_DIP_ENABLE_AVI);
}
static void intel_hdmi_mode_set(struct drm_encoder *encoder,
@@ -65,10 +129,13 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
- if (intel_hdmi->has_hdmi_sink) {
+ /* Required on CPT */
+ if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev))
+ sdvox |= HDMI_MODE_SELECT;
+
+ if (intel_hdmi->has_audio) {
sdvox |= SDVO_AUDIO_ENABLE;
- if (HAS_PCH_CPT(dev))
- sdvox |= HDMI_MODE_SELECT;
+ sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC;
}
if (intel_crtc->pipe == 1) {
@@ -80,6 +147,8 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
POSTING_READ(intel_hdmi->sdvox_reg);
+
+ intel_hdmi_set_avi_infoframe(encoder);
}
static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
@@ -141,36 +210,85 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
static enum drm_connector_status
intel_hdmi_detect(struct drm_connector *connector, bool force)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
- struct edid *edid = NULL;
+ struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+ struct drm_i915_private *dev_priv = connector->dev->dev_private;
+ struct edid *edid;
enum drm_connector_status status = connector_status_disconnected;
intel_hdmi->has_hdmi_sink = false;
- edid = drm_get_edid(connector, intel_hdmi->base.ddc_bus);
+ intel_hdmi->has_audio = false;
+ edid = drm_get_edid(connector,
+ &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
if (edid) {
if (edid->input & DRM_EDID_INPUT_DIGITAL) {
status = connector_status_connected;
intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
+ intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
}
connector->display_info.raw_edid = NULL;
kfree(edid);
}
+ if (status == connector_status_connected) {
+ if (intel_hdmi->force_audio)
+ intel_hdmi->has_audio = intel_hdmi->force_audio > 0;
+ }
+
return status;
}
static int intel_hdmi_get_modes(struct drm_connector *connector)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+ struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+ struct drm_i915_private *dev_priv = connector->dev->dev_private;
/* We should parse the EDID data and find out if it's an HDMI sink so
* we can send audio to it.
*/
- return intel_ddc_get_modes(connector, intel_hdmi->base.ddc_bus);
+ return intel_ddc_get_modes(connector,
+ &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
+}
+
+static int
+intel_hdmi_set_property(struct drm_connector *connector,
+ struct drm_property *property,
+ uint64_t val)
+{
+ struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+ int ret;
+
+ ret = drm_connector_property_set_value(connector, property, val);
+ if (ret)
+ return ret;
+
+ if (property == intel_hdmi->force_audio_property) {
+ if (val == intel_hdmi->force_audio)
+ return 0;
+
+ intel_hdmi->force_audio = val;
+
+ if (val > 0 && intel_hdmi->has_audio)
+ return 0;
+ if (val < 0 && !intel_hdmi->has_audio)
+ return 0;
+
+ intel_hdmi->has_audio = val > 0;
+ goto done;
+ }
+
+ return -EINVAL;
+
+done:
+ if (intel_hdmi->base.base.crtc) {
+ struct drm_crtc *crtc = intel_hdmi->base.base.crtc;
+ drm_crtc_helper_set_mode(crtc, &crtc->mode,
+ crtc->x, crtc->y,
+ crtc->fb);
+ }
+
+ return 0;
}
static void intel_hdmi_destroy(struct drm_connector *connector)
@@ -192,19 +310,34 @@ static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.detect = intel_hdmi_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
+ .set_property = intel_hdmi_set_property,
.destroy = intel_hdmi_destroy,
};
static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
.get_modes = intel_hdmi_get_modes,
.mode_valid = intel_hdmi_mode_valid,
- .best_encoder = intel_attached_encoder,
+ .best_encoder = intel_best_encoder,
};
static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
.destroy = intel_encoder_destroy,
};
+static void
+intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+
+ intel_hdmi->force_audio_property =
+ drm_property_create(dev, DRM_MODE_PROP_RANGE, "force_audio", 2);
+ if (intel_hdmi->force_audio_property) {
+ intel_hdmi->force_audio_property->values[0] = -1;
+ intel_hdmi->force_audio_property->values[1] = 1;
+ drm_connector_attach_property(connector, intel_hdmi->force_audio_property, 0);
+ }
+}
+
void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -224,6 +357,9 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
}
intel_encoder = &intel_hdmi->base;
+ drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
+ DRM_MODE_ENCODER_TMDS);
+
connector = &intel_connector->base;
drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
@@ -239,39 +375,33 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
/* Set up the DDC bus. */
if (sdvox_reg == SDVOB) {
intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
- intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB");
+ intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == SDVOC) {
intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
- intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC");
+ intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == HDMIB) {
intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
- intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
- "HDMIB");
+ intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == HDMIC) {
intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
- intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
- "HDMIC");
+ intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == HDMID) {
intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
- intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
- "HDMID");
+ intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
}
- if (!intel_encoder->ddc_bus)
- goto err_connector;
intel_hdmi->sdvox_reg = sdvox_reg;
- drm_encoder_init(dev, &intel_encoder->enc, &intel_hdmi_enc_funcs,
- DRM_MODE_ENCODER_TMDS);
- drm_encoder_helper_add(&intel_encoder->enc, &intel_hdmi_helper_funcs);
+ drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
+
+ intel_hdmi_add_properties(intel_hdmi, connector);
- drm_mode_connector_attach_encoder(&intel_connector->base,
- &intel_encoder->enc);
+ intel_connector_attach_encoder(intel_connector, intel_encoder);
drm_sysfs_connector_add(connector);
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
@@ -282,13 +412,4 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
u32 temp = I915_READ(PEG_BAND_GAP_DATA);
I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
}
-
- return;
-
-err_connector:
- drm_connector_cleanup(connector);
- kfree(intel_hdmi);
- kfree(intel_connector);
-
- return;
}
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index c2649c7df14c..2be4f728ed0c 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
- * Copyright © 2006-2008 Intel Corporation
+ * Copyright © 2006-2008,2010 Intel Corporation
* Jesse Barnes <jesse.barnes@intel.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -24,10 +24,9 @@
*
* Authors:
* Eric Anholt <eric@anholt.net>
+ * Chris Wilson <chris@chris-wilson.co.uk>
*/
#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
#include "drmP.h"
#include "drm.h"
@@ -35,79 +34,106 @@
#include "i915_drm.h"
#include "i915_drv.h"
-void intel_i2c_quirk_set(struct drm_device *dev, bool enable)
+/* Intel GPIO access functions */
+
+#define I2C_RISEFALL_TIME 20
+
+static inline struct intel_gmbus *
+to_intel_gmbus(struct i2c_adapter *i2c)
+{
+ return container_of(i2c, struct intel_gmbus, adapter);
+}
+
+struct intel_gpio {
+ struct i2c_adapter adapter;
+ struct i2c_algo_bit_data algo;
+ struct drm_i915_private *dev_priv;
+ u32 reg;
+};
+
+void
+intel_i2c_reset(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ if (HAS_PCH_SPLIT(dev))
+ I915_WRITE(PCH_GMBUS0, 0);
+ else
+ I915_WRITE(GMBUS0, 0);
+}
+
+static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable)
+{
+ u32 val;
/* When using bit bashing for I2C, this bit needs to be set to 1 */
- if (!IS_PINEVIEW(dev))
+ if (!IS_PINEVIEW(dev_priv->dev))
return;
+
+ val = I915_READ(DSPCLK_GATE_D);
if (enable)
- I915_WRITE(DSPCLK_GATE_D,
- I915_READ(DSPCLK_GATE_D) | DPCUNIT_CLOCK_GATE_DISABLE);
+ val |= DPCUNIT_CLOCK_GATE_DISABLE;
else
- I915_WRITE(DSPCLK_GATE_D,
- I915_READ(DSPCLK_GATE_D) & (~DPCUNIT_CLOCK_GATE_DISABLE));
+ val &= ~DPCUNIT_CLOCK_GATE_DISABLE;
+ I915_WRITE(DSPCLK_GATE_D, val);
}
-/*
- * Intel GPIO access functions
- */
+static u32 get_reserved(struct intel_gpio *gpio)
+{
+ struct drm_i915_private *dev_priv = gpio->dev_priv;
+ struct drm_device *dev = dev_priv->dev;
+ u32 reserved = 0;
-#define I2C_RISEFALL_TIME 20
+ /* On most chips, these bits must be preserved in software. */
+ if (!IS_I830(dev) && !IS_845G(dev))
+ reserved = I915_READ(gpio->reg) & (GPIO_DATA_PULLUP_DISABLE |
+ GPIO_CLOCK_PULLUP_DISABLE);
+
+ return reserved;
+}
static int get_clock(void *data)
{
- struct intel_i2c_chan *chan = data;
- struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
- u32 val;
-
- val = I915_READ(chan->reg);
- return ((val & GPIO_CLOCK_VAL_IN) != 0);
+ struct intel_gpio *gpio = data;
+ struct drm_i915_private *dev_priv = gpio->dev_priv;
+ u32 reserved = get_reserved(gpio);
+ I915_WRITE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK);
+ I915_WRITE(gpio->reg, reserved);
+ return (I915_READ(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0;
}
static int get_data(void *data)
{
- struct intel_i2c_chan *chan = data;
- struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
- u32 val;
-
- val = I915_READ(chan->reg);
- return ((val & GPIO_DATA_VAL_IN) != 0);
+ struct intel_gpio *gpio = data;
+ struct drm_i915_private *dev_priv = gpio->dev_priv;
+ u32 reserved = get_reserved(gpio);
+ I915_WRITE(gpio->reg, reserved | GPIO_DATA_DIR_MASK);
+ I915_WRITE(gpio->reg, reserved);
+ return (I915_READ(gpio->reg) & GPIO_DATA_VAL_IN) != 0;
}
static void set_clock(void *data, int state_high)
{
- struct intel_i2c_chan *chan = data;
- struct drm_device *dev = chan->drm_dev;
- struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
- u32 reserved = 0, clock_bits;
-
- /* On most chips, these bits must be preserved in software. */
- if (!IS_I830(dev) && !IS_845G(dev))
- reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE |
- GPIO_CLOCK_PULLUP_DISABLE);
+ struct intel_gpio *gpio = data;
+ struct drm_i915_private *dev_priv = gpio->dev_priv;
+ u32 reserved = get_reserved(gpio);
+ u32 clock_bits;
if (state_high)
clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK;
else
clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
GPIO_CLOCK_VAL_MASK;
- I915_WRITE(chan->reg, reserved | clock_bits);
- udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */
+
+ I915_WRITE(gpio->reg, reserved | clock_bits);
+ POSTING_READ(gpio->reg);
}
static void set_data(void *data, int state_high)
{
- struct intel_i2c_chan *chan = data;
- struct drm_device *dev = chan->drm_dev;
- struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
- u32 reserved = 0, data_bits;
-
- /* On most chips, these bits must be preserved in software. */
- if (!IS_I830(dev) && !IS_845G(dev))
- reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE |
- GPIO_CLOCK_PULLUP_DISABLE);
+ struct intel_gpio *gpio = data;
+ struct drm_i915_private *dev_priv = gpio->dev_priv;
+ u32 reserved = get_reserved(gpio);
+ u32 data_bits;
if (state_high)
data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK;
@@ -115,109 +141,313 @@ static void set_data(void *data, int state_high)
data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
GPIO_DATA_VAL_MASK;
- I915_WRITE(chan->reg, reserved | data_bits);
- udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */
+ I915_WRITE(gpio->reg, reserved | data_bits);
+ POSTING_READ(gpio->reg);
}
-/* Clears the GMBUS setup. Our driver doesn't make use of the GMBUS I2C
- * engine, but if the BIOS leaves it enabled, then that can break our use
- * of the bit-banging I2C interfaces. This is notably the case with the
- * Mac Mini in EFI mode.
- */
-void
-intel_i2c_reset_gmbus(struct drm_device *dev)
+static struct i2c_adapter *
+intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
+ static const int map_pin_to_reg[] = {
+ 0,
+ GPIOB,
+ GPIOA,
+ GPIOC,
+ GPIOD,
+ GPIOE,
+ 0,
+ GPIOF,
+ };
+ struct intel_gpio *gpio;
- if (HAS_PCH_SPLIT(dev)) {
- I915_WRITE(PCH_GMBUS0, 0);
- } else {
- I915_WRITE(GMBUS0, 0);
+ if (pin < 1 || pin > 7)
+ return NULL;
+
+ gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL);
+ if (gpio == NULL)
+ return NULL;
+
+ gpio->reg = map_pin_to_reg[pin];
+ if (HAS_PCH_SPLIT(dev_priv->dev))
+ gpio->reg += PCH_GPIOA - GPIOA;
+ gpio->dev_priv = dev_priv;
+
+ snprintf(gpio->adapter.name, I2C_NAME_SIZE, "GPIO%c", "?BACDEF?"[pin]);
+ gpio->adapter.owner = THIS_MODULE;
+ gpio->adapter.algo_data = &gpio->algo;
+ gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev;
+ gpio->algo.setsda = set_data;
+ gpio->algo.setscl = set_clock;
+ gpio->algo.getsda = get_data;
+ gpio->algo.getscl = get_clock;
+ gpio->algo.udelay = I2C_RISEFALL_TIME;
+ gpio->algo.timeout = usecs_to_jiffies(2200);
+ gpio->algo.data = gpio;
+
+ if (i2c_bit_add_bus(&gpio->adapter))
+ goto out_free;
+
+ return &gpio->adapter;
+
+out_free:
+ kfree(gpio);
+ return NULL;
+}
+
+static int
+intel_i2c_quirk_xfer(struct drm_i915_private *dev_priv,
+ struct i2c_adapter *adapter,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct intel_gpio *gpio = container_of(adapter,
+ struct intel_gpio,
+ adapter);
+ int ret;
+
+ intel_i2c_reset(dev_priv->dev);
+
+ intel_i2c_quirk_set(dev_priv, true);
+ set_data(gpio, 1);
+ set_clock(gpio, 1);
+ udelay(I2C_RISEFALL_TIME);
+
+ ret = adapter->algo->master_xfer(adapter, msgs, num);
+
+ set_data(gpio, 1);
+ set_clock(gpio, 1);
+ intel_i2c_quirk_set(dev_priv, false);
+
+ return ret;
+}
+
+static int
+gmbus_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct intel_gmbus *bus = container_of(adapter,
+ struct intel_gmbus,
+ adapter);
+ struct drm_i915_private *dev_priv = adapter->algo_data;
+ int i, reg_offset;
+
+ if (bus->force_bit)
+ return intel_i2c_quirk_xfer(dev_priv,
+ bus->force_bit, msgs, num);
+
+ reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0;
+
+ I915_WRITE(GMBUS0 + reg_offset, bus->reg0);
+
+ for (i = 0; i < num; i++) {
+ u16 len = msgs[i].len;
+ u8 *buf = msgs[i].buf;
+
+ if (msgs[i].flags & I2C_M_RD) {
+ I915_WRITE(GMBUS1 + reg_offset,
+ GMBUS_CYCLE_WAIT | (i + 1 == num ? GMBUS_CYCLE_STOP : 0) |
+ (len << GMBUS_BYTE_COUNT_SHIFT) |
+ (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
+ GMBUS_SLAVE_READ | GMBUS_SW_RDY);
+ POSTING_READ(GMBUS2+reg_offset);
+ do {
+ u32 val, loop = 0;
+
+ if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
+ goto timeout;
+ if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+ return 0;
+
+ val = I915_READ(GMBUS3 + reg_offset);
+ do {
+ *buf++ = val & 0xff;
+ val >>= 8;
+ } while (--len && ++loop < 4);
+ } while (len);
+ } else {
+ u32 val, loop;
+
+ val = loop = 0;
+ do {
+ val |= *buf++ << (8 * loop);
+ } while (--len && ++loop < 4);
+
+ I915_WRITE(GMBUS3 + reg_offset, val);
+ I915_WRITE(GMBUS1 + reg_offset,
+ (i + 1 == num ? GMBUS_CYCLE_STOP : GMBUS_CYCLE_WAIT) |
+ (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) |
+ (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
+ GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
+ POSTING_READ(GMBUS2+reg_offset);
+
+ while (len) {
+ if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
+ goto timeout;
+ if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+ return 0;
+
+ val = loop = 0;
+ do {
+ val |= *buf++ << (8 * loop);
+ } while (--len && ++loop < 4);
+
+ I915_WRITE(GMBUS3 + reg_offset, val);
+ POSTING_READ(GMBUS2+reg_offset);
+ }
+ }
+
+ if (i + 1 < num && wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50))
+ goto timeout;
+ if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+ return 0;
}
+
+ return num;
+
+timeout:
+ DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n",
+ bus->reg0 & 0xff, bus->adapter.name);
+ /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
+ bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff);
+ if (!bus->force_bit)
+ return -ENOMEM;
+
+ return intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num);
}
+static u32 gmbus_func(struct i2c_adapter *adapter)
+{
+ struct intel_gmbus *bus = container_of(adapter,
+ struct intel_gmbus,
+ adapter);
+
+ if (bus->force_bit)
+ bus->force_bit->algo->functionality(bus->force_bit);
+
+ return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ /* I2C_FUNC_10BIT_ADDR | */
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL);
+}
+
+static const struct i2c_algorithm gmbus_algorithm = {
+ .master_xfer = gmbus_xfer,
+ .functionality = gmbus_func
+};
+
/**
- * intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg
+ * intel_gmbus_setup - instantiate all Intel i2c GMBuses
* @dev: DRM device
- * @output: driver specific output device
- * @reg: GPIO reg to use
- * @name: name for this bus
- * @slave_addr: slave address (if fixed)
- *
- * Creates and registers a new i2c bus with the Linux i2c layer, for use
- * in output probing and control (e.g. DDC or SDVO control functions).
- *
- * Possible values for @reg include:
- * %GPIOA
- * %GPIOB
- * %GPIOC
- * %GPIOD
- * %GPIOE
- * %GPIOF
- * %GPIOG
- * %GPIOH
- * see PRM for details on how these different busses are used.
*/
-struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
- const char *name)
+int intel_setup_gmbus(struct drm_device *dev)
{
- struct intel_i2c_chan *chan;
+ static const char *names[GMBUS_NUM_PORTS] = {
+ "disabled",
+ "ssc",
+ "vga",
+ "panel",
+ "dpc",
+ "dpb",
+ "reserved"
+ "dpd",
+ };
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret, i;
- chan = kzalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL);
- if (!chan)
- goto out_free;
+ dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS,
+ GFP_KERNEL);
+ if (dev_priv->gmbus == NULL)
+ return -ENOMEM;
- chan->drm_dev = dev;
- chan->reg = reg;
- snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name);
- chan->adapter.owner = THIS_MODULE;
- chan->adapter.algo_data = &chan->algo;
- chan->adapter.dev.parent = &dev->pdev->dev;
- chan->algo.setsda = set_data;
- chan->algo.setscl = set_clock;
- chan->algo.getsda = get_data;
- chan->algo.getscl = get_clock;
- chan->algo.udelay = 20;
- chan->algo.timeout = usecs_to_jiffies(2200);
- chan->algo.data = chan;
-
- i2c_set_adapdata(&chan->adapter, chan);
-
- if(i2c_bit_add_bus(&chan->adapter))
- goto out_free;
+ for (i = 0; i < GMBUS_NUM_PORTS; i++) {
+ struct intel_gmbus *bus = &dev_priv->gmbus[i];
- intel_i2c_reset_gmbus(dev);
+ bus->adapter.owner = THIS_MODULE;
+ bus->adapter.class = I2C_CLASS_DDC;
+ snprintf(bus->adapter.name,
+ I2C_NAME_SIZE,
+ "gmbus %s",
+ names[i]);
- /* JJJ: raise SCL and SDA? */
- intel_i2c_quirk_set(dev, true);
- set_data(chan, 1);
- set_clock(chan, 1);
- intel_i2c_quirk_set(dev, false);
- udelay(20);
+ bus->adapter.dev.parent = &dev->pdev->dev;
+ bus->adapter.algo_data = dev_priv;
- return &chan->adapter;
+ bus->adapter.algo = &gmbus_algorithm;
+ ret = i2c_add_adapter(&bus->adapter);
+ if (ret)
+ goto err;
-out_free:
- kfree(chan);
- return NULL;
+ /* By default use a conservative clock rate */
+ bus->reg0 = i | GMBUS_RATE_100KHZ;
+
+ /* XXX force bit banging until GMBUS is fully debugged */
+ bus->force_bit = intel_gpio_create(dev_priv, i);
+ }
+
+ intel_i2c_reset(dev_priv->dev);
+
+ return 0;
+
+err:
+ while (--i) {
+ struct intel_gmbus *bus = &dev_priv->gmbus[i];
+ i2c_del_adapter(&bus->adapter);
+ }
+ kfree(dev_priv->gmbus);
+ dev_priv->gmbus = NULL;
+ return ret;
}
-/**
- * intel_i2c_destroy - unregister and free i2c bus resources
- * @output: channel to free
- *
- * Unregister the adapter from the i2c layer, then free the structure.
- */
-void intel_i2c_destroy(struct i2c_adapter *adapter)
+void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed)
+{
+ struct intel_gmbus *bus = to_intel_gmbus(adapter);
+
+ /* speed:
+ * 0x0 = 100 KHz
+ * 0x1 = 50 KHz
+ * 0x2 = 400 KHz
+ * 0x3 = 1000 Khz
+ */
+ bus->reg0 = (bus->reg0 & ~(0x3 << 8)) | (speed << 8);
+}
+
+void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit)
+{
+ struct intel_gmbus *bus = to_intel_gmbus(adapter);
+
+ if (force_bit) {
+ if (bus->force_bit == NULL) {
+ struct drm_i915_private *dev_priv = adapter->algo_data;
+ bus->force_bit = intel_gpio_create(dev_priv,
+ bus->reg0 & 0xff);
+ }
+ } else {
+ if (bus->force_bit) {
+ i2c_del_adapter(bus->force_bit);
+ kfree(bus->force_bit);
+ bus->force_bit = NULL;
+ }
+ }
+}
+
+void intel_teardown_gmbus(struct drm_device *dev)
{
- struct intel_i2c_chan *chan;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int i;
- if (!adapter)
+ if (dev_priv->gmbus == NULL)
return;
- chan = container_of(adapter,
- struct intel_i2c_chan,
- adapter);
- i2c_del_adapter(&chan->adapter);
- kfree(chan);
+ for (i = 0; i < GMBUS_NUM_PORTS; i++) {
+ struct intel_gmbus *bus = &dev_priv->gmbus[i];
+ if (bus->force_bit) {
+ i2c_del_adapter(bus->force_bit);
+ kfree(bus->force_bit);
+ }
+ i2c_del_adapter(&bus->adapter);
+ }
+
+ kfree(dev_priv->gmbus);
+ dev_priv->gmbus = NULL;
}
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 6ec39a86ed06..f1a649990ea9 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -43,102 +43,76 @@
/* Private structure for the integrated LVDS support */
struct intel_lvds {
struct intel_encoder base;
+
+ struct edid *edid;
+
int fitting_mode;
u32 pfit_control;
u32 pfit_pgm_ratios;
+ bool pfit_dirty;
+
+ struct drm_display_mode *fixed_mode;
};
-static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder)
+static struct intel_lvds *to_intel_lvds(struct drm_encoder *encoder)
{
- return container_of(enc_to_intel_encoder(encoder), struct intel_lvds, base);
-}
-
-/**
- * Sets the backlight level.
- *
- * \param level backlight level, from 0 to intel_lvds_get_max_backlight().
- */
-static void intel_lvds_set_backlight(struct drm_device *dev, int level)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 blc_pwm_ctl, reg;
-
- if (HAS_PCH_SPLIT(dev))
- reg = BLC_PWM_CPU_CTL;
- else
- reg = BLC_PWM_CTL;
-
- blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK;
- I915_WRITE(reg, (blc_pwm_ctl |
- (level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
+ return container_of(encoder, struct intel_lvds, base.base);
}
-/**
- * Returns the maximum level of the backlight duty cycle field.
- */
-static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
+static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 reg;
-
- if (HAS_PCH_SPLIT(dev))
- reg = BLC_PWM_PCH_CTL2;
- else
- reg = BLC_PWM_CTL;
-
- return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >>
- BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
+ return container_of(intel_attached_encoder(connector),
+ struct intel_lvds, base);
}
/**
* Sets the power state for the panel.
*/
-static void intel_lvds_set_power(struct drm_device *dev, bool on)
+static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on)
{
+ struct drm_device *dev = intel_lvds->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 ctl_reg, status_reg, lvds_reg;
+ u32 ctl_reg, lvds_reg;
if (HAS_PCH_SPLIT(dev)) {
ctl_reg = PCH_PP_CONTROL;
- status_reg = PCH_PP_STATUS;
lvds_reg = PCH_LVDS;
} else {
ctl_reg = PP_CONTROL;
- status_reg = PP_STATUS;
lvds_reg = LVDS;
}
if (on) {
I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
- POSTING_READ(lvds_reg);
-
- I915_WRITE(ctl_reg, I915_READ(ctl_reg) |
- POWER_TARGET_ON);
- if (wait_for(I915_READ(status_reg) & PP_ON, 1000, 0))
- DRM_ERROR("timed out waiting to enable LVDS pipe");
-
- intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
+ I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
+ intel_panel_set_backlight(dev, dev_priv->backlight_level);
} else {
- intel_lvds_set_backlight(dev, 0);
+ dev_priv->backlight_level = intel_panel_get_backlight(dev);
+
+ intel_panel_set_backlight(dev, 0);
+ I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
- I915_WRITE(ctl_reg, I915_READ(ctl_reg) &
- ~POWER_TARGET_ON);
- if (wait_for((I915_READ(status_reg) & PP_ON) == 0, 1000, 0))
- DRM_ERROR("timed out waiting for LVDS pipe to turn off");
+ if (intel_lvds->pfit_control) {
+ if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
+ DRM_ERROR("timed out waiting for panel to power off\n");
+ I915_WRITE(PFIT_CONTROL, 0);
+ intel_lvds->pfit_control = 0;
+ intel_lvds->pfit_dirty = false;
+ }
I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
- POSTING_READ(lvds_reg);
}
+ POSTING_READ(lvds_reg);
}
static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
{
- struct drm_device *dev = encoder->dev;
+ struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
if (mode == DRM_MODE_DPMS_ON)
- intel_lvds_set_power(dev, true);
+ intel_lvds_set_power(intel_lvds, true);
else
- intel_lvds_set_power(dev, false);
+ intel_lvds_set_power(intel_lvds, false);
/* XXX: We never power down the LVDS pairs. */
}
@@ -146,16 +120,13 @@ static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
static int intel_lvds_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct drm_device *dev = connector->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode;
+ struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
+ struct drm_display_mode *fixed_mode = intel_lvds->fixed_mode;
- if (fixed_mode) {
- if (mode->hdisplay > fixed_mode->hdisplay)
- return MODE_PANEL;
- if (mode->vdisplay > fixed_mode->vdisplay)
- return MODE_PANEL;
- }
+ if (mode->hdisplay > fixed_mode->hdisplay)
+ return MODE_PANEL;
+ if (mode->vdisplay > fixed_mode->vdisplay)
+ return MODE_PANEL;
return MODE_OK;
}
@@ -223,12 +194,12 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
+ struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
struct drm_encoder *tmp_encoder;
u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
/* Should never happen!! */
- if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
+ if (INTEL_INFO(dev)->gen < 4 && intel_crtc->pipe == 0) {
DRM_ERROR("Can't support LVDS on pipe A\n");
return false;
}
@@ -241,9 +212,6 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
return false;
}
}
- /* If we don't have a panel mode, there is nothing we can do */
- if (dev_priv->panel_fixed_mode == NULL)
- return true;
/*
* We have timings from the BIOS for the panel, put them in
@@ -251,7 +219,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
* with the panel scaling set up to source from the H/VDisplay
* of the original mode.
*/
- intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
+ intel_fixed_panel_mode(intel_lvds->fixed_mode, adjusted_mode);
if (HAS_PCH_SPLIT(dev)) {
intel_pch_panel_fitting(dev, intel_lvds->fitting_mode,
@@ -260,8 +228,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
}
/* Make sure pre-965s set dither correctly */
- if (!IS_I965G(dev)) {
- if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
+ if (INTEL_INFO(dev)->gen < 4) {
+ if (dev_priv->lvds_dither)
pfit_control |= PANEL_8TO6_DITHER_ENABLE;
}
@@ -271,7 +239,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
goto out;
/* 965+ wants fuzzy fitting */
- if (IS_I965G(dev))
+ if (INTEL_INFO(dev)->gen >= 4)
pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
PFIT_FILTER_FUZZY);
@@ -297,7 +265,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
case DRM_MODE_SCALE_ASPECT:
/* Scale but preserve the aspect ratio */
- if (IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4) {
u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
@@ -356,7 +324,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
* Fortunately this is all done for us in hw.
*/
pfit_control |= PFIT_ENABLE;
- if (IS_I965G(dev))
+ if (INTEL_INFO(dev)->gen >= 4)
pfit_control |= PFIT_SCALING_AUTO;
else
pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
@@ -369,8 +337,12 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
}
out:
- intel_lvds->pfit_control = pfit_control;
- intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios;
+ if (pfit_control != intel_lvds->pfit_control ||
+ pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) {
+ intel_lvds->pfit_control = pfit_control;
+ intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios;
+ intel_lvds->pfit_dirty = true;
+ }
dev_priv->lvds_border_bits = border;
/*
@@ -386,30 +358,60 @@ static void intel_lvds_prepare(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 reg;
-
- if (HAS_PCH_SPLIT(dev))
- reg = BLC_PWM_CPU_CTL;
- else
- reg = BLC_PWM_CTL;
-
- dev_priv->saveBLC_PWM_CTL = I915_READ(reg);
- dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
- BACKLIGHT_DUTY_CYCLE_MASK);
+ struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
+
+ dev_priv->backlight_level = intel_panel_get_backlight(dev);
+
+ /* We try to do the minimum that is necessary in order to unlock
+ * the registers for mode setting.
+ *
+ * On Ironlake, this is quite simple as we just set the unlock key
+ * and ignore all subtleties. (This may cause some issues...)
+ *
+ * Prior to Ironlake, we must disable the pipe if we want to adjust
+ * the panel fitter. However at all other times we can just reset
+ * the registers regardless.
+ */
- intel_lvds_set_power(dev, false);
+ if (HAS_PCH_SPLIT(dev)) {
+ I915_WRITE(PCH_PP_CONTROL,
+ I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
+ } else if (intel_lvds->pfit_dirty) {
+ I915_WRITE(PP_CONTROL,
+ (I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS)
+ & ~POWER_TARGET_ON);
+ } else {
+ I915_WRITE(PP_CONTROL,
+ I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
+ }
}
-static void intel_lvds_commit( struct drm_encoder *encoder)
+static void intel_lvds_commit(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
- if (dev_priv->backlight_duty_cycle == 0)
- dev_priv->backlight_duty_cycle =
- intel_lvds_get_max_backlight(dev);
+ if (dev_priv->backlight_level == 0)
+ dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
+
+ /* Undo any unlocking done in prepare to prevent accidental
+ * adjustment of the registers.
+ */
+ if (HAS_PCH_SPLIT(dev)) {
+ u32 val = I915_READ(PCH_PP_CONTROL);
+ if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
+ I915_WRITE(PCH_PP_CONTROL, val & 0x3);
+ } else {
+ u32 val = I915_READ(PP_CONTROL);
+ if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
+ I915_WRITE(PP_CONTROL, val & 0x3);
+ }
- intel_lvds_set_power(dev, true);
+ /* Always do a full power on as we do not know what state
+ * we were left in.
+ */
+ intel_lvds_set_power(intel_lvds, true);
}
static void intel_lvds_mode_set(struct drm_encoder *encoder,
@@ -418,7 +420,7 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
{
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
+ struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
/*
* The LVDS pin pair will already have been turned on in the
@@ -429,13 +431,23 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
if (HAS_PCH_SPLIT(dev))
return;
+ if (!intel_lvds->pfit_dirty)
+ return;
+
/*
* Enable automatic panel scaling so that non-native modes fill the
* screen. Should be enabled before the pipe is enabled, according to
* register description and PRM.
*/
+ DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
+ intel_lvds->pfit_control,
+ intel_lvds->pfit_pgm_ratios);
+ if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
+ DRM_ERROR("timed out waiting for panel to power off\n");
+
I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
+ intel_lvds->pfit_dirty = false;
}
/**
@@ -465,38 +477,22 @@ intel_lvds_detect(struct drm_connector *connector, bool force)
*/
static int intel_lvds_get_modes(struct drm_connector *connector)
{
+ struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
struct drm_device *dev = connector->dev;
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
- struct drm_i915_private *dev_priv = dev->dev_private;
- int ret = 0;
-
- if (dev_priv->lvds_edid_good) {
- ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
+ struct drm_display_mode *mode;
- if (ret)
- return ret;
+ if (intel_lvds->edid) {
+ drm_mode_connector_update_edid_property(connector,
+ intel_lvds->edid);
+ return drm_add_edid_modes(connector, intel_lvds->edid);
}
- /* Didn't get an EDID, so
- * Set wide sync ranges so we get all modes
- * handed to valid_mode for checking
- */
- connector->display_info.min_vfreq = 0;
- connector->display_info.max_vfreq = 200;
- connector->display_info.min_hfreq = 0;
- connector->display_info.max_hfreq = 200;
-
- if (dev_priv->panel_fixed_mode != NULL) {
- struct drm_display_mode *mode;
-
- mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
- drm_mode_probed_add(connector, mode);
-
- return 1;
- }
+ mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode);
+ if (mode == 0)
+ return 0;
- return 0;
+ drm_mode_probed_add(connector, mode);
+ return 1;
}
static int intel_no_modeset_on_lid_dmi_callback(const struct dmi_system_id *id)
@@ -587,18 +583,17 @@ static int intel_lvds_set_property(struct drm_connector *connector,
struct drm_property *property,
uint64_t value)
{
+ struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
struct drm_device *dev = connector->dev;
- if (property == dev->mode_config.scaling_mode_property &&
- connector->encoder) {
- struct drm_crtc *crtc = connector->encoder->crtc;
- struct drm_encoder *encoder = connector->encoder;
- struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
+ if (property == dev->mode_config.scaling_mode_property) {
+ struct drm_crtc *crtc = intel_lvds->base.base.crtc;
if (value == DRM_MODE_SCALE_NONE) {
DRM_DEBUG_KMS("no scaling not supported\n");
- return 0;
+ return -EINVAL;
}
+
if (intel_lvds->fitting_mode == value) {
/* the LVDS scaling property is not changed */
return 0;
@@ -628,7 +623,7 @@ static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = {
static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
.get_modes = intel_lvds_get_modes,
.mode_valid = intel_lvds_mode_valid,
- .best_encoder = intel_attached_encoder,
+ .best_encoder = intel_best_encoder,
};
static const struct drm_connector_funcs intel_lvds_connector_funcs = {
@@ -726,16 +721,14 @@ static const struct dmi_system_id intel_no_lvds[] = {
* Find the reduced downclock for LVDS in EDID.
*/
static void intel_find_lvds_downclock(struct drm_device *dev,
- struct drm_connector *connector)
+ struct drm_display_mode *fixed_mode,
+ struct drm_connector *connector)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_display_mode *scan, *panel_fixed_mode;
+ struct drm_display_mode *scan;
int temp_downclock;
- panel_fixed_mode = dev_priv->panel_fixed_mode;
- temp_downclock = panel_fixed_mode->clock;
-
- mutex_lock(&dev->mode_config.mutex);
+ temp_downclock = fixed_mode->clock;
list_for_each_entry(scan, &connector->probed_modes, head) {
/*
* If one mode has the same resolution with the fixed_panel
@@ -744,14 +737,14 @@ static void intel_find_lvds_downclock(struct drm_device *dev,
* case we can set the different FPx0/1 to dynamically select
* between low and high frequency.
*/
- if (scan->hdisplay == panel_fixed_mode->hdisplay &&
- scan->hsync_start == panel_fixed_mode->hsync_start &&
- scan->hsync_end == panel_fixed_mode->hsync_end &&
- scan->htotal == panel_fixed_mode->htotal &&
- scan->vdisplay == panel_fixed_mode->vdisplay &&
- scan->vsync_start == panel_fixed_mode->vsync_start &&
- scan->vsync_end == panel_fixed_mode->vsync_end &&
- scan->vtotal == panel_fixed_mode->vtotal) {
+ if (scan->hdisplay == fixed_mode->hdisplay &&
+ scan->hsync_start == fixed_mode->hsync_start &&
+ scan->hsync_end == fixed_mode->hsync_end &&
+ scan->htotal == fixed_mode->htotal &&
+ scan->vdisplay == fixed_mode->vdisplay &&
+ scan->vsync_start == fixed_mode->vsync_start &&
+ scan->vsync_end == fixed_mode->vsync_end &&
+ scan->vtotal == fixed_mode->vtotal) {
if (scan->clock < temp_downclock) {
/*
* The downclock is already found. But we
@@ -761,17 +754,14 @@ static void intel_find_lvds_downclock(struct drm_device *dev,
}
}
}
- mutex_unlock(&dev->mode_config.mutex);
- if (temp_downclock < panel_fixed_mode->clock &&
- i915_lvds_downclock) {
+ if (temp_downclock < fixed_mode->clock && i915_lvds_downclock) {
/* We found the downclock for LVDS. */
dev_priv->lvds_downclock_avail = 1;
dev_priv->lvds_downclock = temp_downclock;
DRM_DEBUG_KMS("LVDS downclock is found in EDID. "
- "Normal clock %dKhz, downclock %dKhz\n",
- panel_fixed_mode->clock, temp_downclock);
+ "Normal clock %dKhz, downclock %dKhz\n",
+ fixed_mode->clock, temp_downclock);
}
- return;
}
/*
@@ -780,38 +770,67 @@ static void intel_find_lvds_downclock(struct drm_device *dev,
* If it is present, return 1.
* If it is not present, return false.
* If no child dev is parsed from VBT, it assumes that the LVDS is present.
- * Note: The addin_offset should also be checked for LVDS panel.
- * Only when it is non-zero, it is assumed that it is present.
*/
-static int lvds_is_present_in_vbt(struct drm_device *dev)
+static bool lvds_is_present_in_vbt(struct drm_device *dev,
+ u8 *i2c_pin)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct child_device_config *p_child;
- int i, ret;
+ int i;
if (!dev_priv->child_dev_num)
- return 1;
+ return true;
- ret = 0;
for (i = 0; i < dev_priv->child_dev_num; i++) {
- p_child = dev_priv->child_dev + i;
- /*
- * If the device type is not LFP, continue.
- * If the device type is 0x22, it is also regarded as LFP.
+ struct child_device_config *child = dev_priv->child_dev + i;
+
+ /* If the device type is not LFP, continue.
+ * We have to check both the new identifiers as well as the
+ * old for compatibility with some BIOSes.
*/
- if (p_child->device_type != DEVICE_TYPE_INT_LFP &&
- p_child->device_type != DEVICE_TYPE_LFP)
+ if (child->device_type != DEVICE_TYPE_INT_LFP &&
+ child->device_type != DEVICE_TYPE_LFP)
continue;
- /* The addin_offset should be checked. Only when it is
- * non-zero, it is regarded as present.
+ if (child->i2c_pin)
+ *i2c_pin = child->i2c_pin;
+
+ /* However, we cannot trust the BIOS writers to populate
+ * the VBT correctly. Since LVDS requires additional
+ * information from AIM blocks, a non-zero addin offset is
+ * a good indicator that the LVDS is actually present.
*/
- if (p_child->addin_offset) {
- ret = 1;
- break;
- }
+ if (child->addin_offset)
+ return true;
+
+ /* But even then some BIOS writers perform some black magic
+ * and instantiate the device without reference to any
+ * additional data. Trust that if the VBT was written into
+ * the OpRegion then they have validated the LVDS's existence.
+ */
+ if (dev_priv->opregion.vbt)
+ return true;
}
- return ret;
+
+ return false;
+}
+
+static bool intel_lvds_ddc_probe(struct drm_device *dev, u8 pin)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u8 buf = 0;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = 0xA0,
+ .flags = 0,
+ .len = 1,
+ .buf = &buf,
+ },
+ };
+ struct i2c_adapter *i2c = &dev_priv->gmbus[pin].adapter;
+ /* XXX this only appears to work when using GMBUS */
+ if (intel_gmbus_is_forced_bit(i2c))
+ return true;
+ return i2c_transfer(i2c, msgs, 1) == 1;
}
/**
@@ -832,13 +851,15 @@ void intel_lvds_init(struct drm_device *dev)
struct drm_display_mode *scan; /* *modes, *bios_mode; */
struct drm_crtc *crtc;
u32 lvds;
- int pipe, gpio = GPIOC;
+ int pipe;
+ u8 pin;
/* Skip init on machines we know falsely report LVDS */
if (dmi_check_system(intel_no_lvds))
return;
- if (!lvds_is_present_in_vbt(dev)) {
+ pin = GMBUS_PORT_PANEL;
+ if (!lvds_is_present_in_vbt(dev, &pin)) {
DRM_DEBUG_KMS("LVDS is not present in VBT\n");
return;
}
@@ -846,11 +867,15 @@ void intel_lvds_init(struct drm_device *dev)
if (HAS_PCH_SPLIT(dev)) {
if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
return;
- if (dev_priv->edp_support) {
+ if (dev_priv->edp.support) {
DRM_DEBUG_KMS("disable LVDS for eDP support\n");
return;
}
- gpio = PCH_GPIOC;
+ }
+
+ if (!intel_lvds_ddc_probe(dev, pin)) {
+ DRM_DEBUG_KMS("LVDS did not respond to DDC probe\n");
+ return;
}
intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL);
@@ -864,16 +889,20 @@ void intel_lvds_init(struct drm_device *dev)
return;
}
+ if (!HAS_PCH_SPLIT(dev)) {
+ intel_lvds->pfit_control = I915_READ(PFIT_CONTROL);
+ }
+
intel_encoder = &intel_lvds->base;
- encoder = &intel_encoder->enc;
+ encoder = &intel_encoder->base;
connector = &intel_connector->base;
drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
- drm_encoder_init(dev, &intel_encoder->enc, &intel_lvds_enc_funcs,
+ drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs,
DRM_MODE_ENCODER_LVDS);
- drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc);
+ intel_connector_attach_encoder(intel_connector, intel_encoder);
intel_encoder->type = INTEL_OUTPUT_LVDS;
intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
@@ -904,43 +933,41 @@ void intel_lvds_init(struct drm_device *dev)
* if closed, act like it's not there for now
*/
- /* Set up the DDC bus. */
- intel_encoder->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C");
- if (!intel_encoder->ddc_bus) {
- dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
- "failed.\n");
- goto failed;
- }
-
/*
* Attempt to get the fixed panel mode from DDC. Assume that the
* preferred mode is the right one.
*/
- dev_priv->lvds_edid_good = true;
+ intel_lvds->edid = drm_get_edid(connector,
+ &dev_priv->gmbus[pin].adapter);
- if (!intel_ddc_get_modes(connector, intel_encoder->ddc_bus))
- dev_priv->lvds_edid_good = false;
+ if (!intel_lvds->edid) {
+ /* Didn't get an EDID, so
+ * Set wide sync ranges so we get all modes
+ * handed to valid_mode for checking
+ */
+ connector->display_info.min_vfreq = 0;
+ connector->display_info.max_vfreq = 200;
+ connector->display_info.min_hfreq = 0;
+ connector->display_info.max_hfreq = 200;
+ }
list_for_each_entry(scan, &connector->probed_modes, head) {
- mutex_lock(&dev->mode_config.mutex);
if (scan->type & DRM_MODE_TYPE_PREFERRED) {
- dev_priv->panel_fixed_mode =
+ intel_lvds->fixed_mode =
drm_mode_duplicate(dev, scan);
- mutex_unlock(&dev->mode_config.mutex);
- intel_find_lvds_downclock(dev, connector);
+ intel_find_lvds_downclock(dev,
+ intel_lvds->fixed_mode,
+ connector);
goto out;
}
- mutex_unlock(&dev->mode_config.mutex);
}
/* Failed to get EDID, what about VBT? */
if (dev_priv->lfp_lvds_vbt_mode) {
- mutex_lock(&dev->mode_config.mutex);
- dev_priv->panel_fixed_mode =
+ intel_lvds->fixed_mode =
drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
- mutex_unlock(&dev->mode_config.mutex);
- if (dev_priv->panel_fixed_mode) {
- dev_priv->panel_fixed_mode->type |=
+ if (intel_lvds->fixed_mode) {
+ intel_lvds->fixed_mode->type |=
DRM_MODE_TYPE_PREFERRED;
goto out;
}
@@ -958,19 +985,19 @@ void intel_lvds_init(struct drm_device *dev)
lvds = I915_READ(LVDS);
pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
- crtc = intel_get_crtc_from_pipe(dev, pipe);
+ crtc = intel_get_crtc_for_pipe(dev, pipe);
if (crtc && (lvds & LVDS_PORT_EN)) {
- dev_priv->panel_fixed_mode = intel_crtc_mode_get(dev, crtc);
- if (dev_priv->panel_fixed_mode) {
- dev_priv->panel_fixed_mode->type |=
+ intel_lvds->fixed_mode = intel_crtc_mode_get(dev, crtc);
+ if (intel_lvds->fixed_mode) {
+ intel_lvds->fixed_mode->type |=
DRM_MODE_TYPE_PREFERRED;
goto out;
}
}
/* If we still don't have a mode after all that, give up. */
- if (!dev_priv->panel_fixed_mode)
+ if (!intel_lvds->fixed_mode)
goto failed;
out:
@@ -997,8 +1024,6 @@ out:
failed:
DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
- if (intel_encoder->ddc_bus)
- intel_i2c_destroy(intel_encoder->ddc_bus);
drm_connector_cleanup(connector);
drm_encoder_cleanup(encoder);
kfree(intel_lvds);
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c
index 4b1fd3d9c73c..f70b7cf32bff 100644
--- a/drivers/gpu/drm/i915/intel_modes.c
+++ b/drivers/gpu/drm/i915/intel_modes.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
- * Copyright (c) 2007 Intel Corporation
+ * Copyright (c) 2007, 2010 Intel Corporation
* Jesse Barnes <jesse.barnes@intel.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -34,11 +34,11 @@
* intel_ddc_probe
*
*/
-bool intel_ddc_probe(struct intel_encoder *intel_encoder)
+bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus)
{
+ struct drm_i915_private *dev_priv = intel_encoder->base.dev->dev_private;
u8 out_buf[] = { 0x0, 0x0};
u8 buf[2];
- int ret;
struct i2c_msg msgs[] = {
{
.addr = 0x50,
@@ -54,13 +54,7 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder)
}
};
- intel_i2c_quirk_set(intel_encoder->enc.dev, true);
- ret = i2c_transfer(intel_encoder->ddc_bus, msgs, 2);
- intel_i2c_quirk_set(intel_encoder->enc.dev, false);
- if (ret == 2)
- return true;
-
- return false;
+ return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 2) == 2;
}
/**
@@ -76,9 +70,7 @@ int intel_ddc_get_modes(struct drm_connector *connector,
struct edid *edid;
int ret = 0;
- intel_i2c_quirk_set(connector->dev, true);
edid = drm_get_edid(connector, adapter);
- intel_i2c_quirk_set(connector->dev, false);
if (edid) {
drm_mode_connector_update_edid_property(connector, edid);
ret = drm_add_edid_modes(connector, edid);
diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
index ea5d3fea4b61..917c7dc3cd6b 100644
--- a/drivers/gpu/drm/i915/i915_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -31,17 +31,16 @@
#include "drmP.h"
#include "i915_drm.h"
#include "i915_drv.h"
+#include "intel_drv.h"
#define PCI_ASLE 0xe4
-#define PCI_LBPC 0xf4
#define PCI_ASLS 0xfc
-#define OPREGION_SZ (8*1024)
#define OPREGION_HEADER_OFFSET 0
#define OPREGION_ACPI_OFFSET 0x100
#define OPREGION_SWSCI_OFFSET 0x200
#define OPREGION_ASLE_OFFSET 0x300
-#define OPREGION_VBT_OFFSET 0x1000
+#define OPREGION_VBT_OFFSET 0x400
#define OPREGION_SIGNATURE "IntelGraphicsMem"
#define MBOX_ACPI (1<<0)
@@ -143,40 +142,22 @@ struct opregion_asle {
#define ACPI_DIGITAL_OUTPUT (3<<8)
#define ACPI_LVDS_OUTPUT (4<<8)
+#ifdef CONFIG_ACPI
static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct opregion_asle *asle = dev_priv->opregion.asle;
- u32 blc_pwm_ctl, blc_pwm_ctl2;
- u32 max_backlight, level, shift;
+ u32 max;
if (!(bclp & ASLE_BCLP_VALID))
return ASLE_BACKLIGHT_FAILED;
bclp &= ASLE_BCLP_MSK;
- if (bclp < 0 || bclp > 255)
+ if (bclp > 255)
return ASLE_BACKLIGHT_FAILED;
- blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
- blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2);
-
- if (IS_I965G(dev) && (blc_pwm_ctl2 & BLM_COMBINATION_MODE))
- pci_write_config_dword(dev->pdev, PCI_LBPC, bclp);
- else {
- if (IS_PINEVIEW(dev)) {
- blc_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
- max_backlight = (blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >>
- BACKLIGHT_MODULATION_FREQ_SHIFT;
- shift = BACKLIGHT_DUTY_CYCLE_SHIFT + 1;
- } else {
- blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
- max_backlight = ((blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >>
- BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
- shift = BACKLIGHT_DUTY_CYCLE_SHIFT;
- }
- level = (bclp * max_backlight) / 255;
- I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | (level << shift));
- }
+ max = intel_panel_get_max_backlight(dev);
+ intel_panel_set_backlight(dev, bclp * max / 255);
asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
return 0;
@@ -211,7 +192,7 @@ static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
return 0;
}
-void opregion_asle_intr(struct drm_device *dev)
+void intel_opregion_asle_intr(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct opregion_asle *asle = dev_priv->opregion.asle;
@@ -243,37 +224,8 @@ void opregion_asle_intr(struct drm_device *dev)
asle->aslc = asle_stat;
}
-static u32 asle_set_backlight_ironlake(struct drm_device *dev, u32 bclp)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct opregion_asle *asle = dev_priv->opregion.asle;
- u32 cpu_pwm_ctl, pch_pwm_ctl2;
- u32 max_backlight, level;
-
- if (!(bclp & ASLE_BCLP_VALID))
- return ASLE_BACKLIGHT_FAILED;
-
- bclp &= ASLE_BCLP_MSK;
- if (bclp < 0 || bclp > 255)
- return ASLE_BACKLIGHT_FAILED;
-
- cpu_pwm_ctl = I915_READ(BLC_PWM_CPU_CTL);
- pch_pwm_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
- /* get the max PWM frequency */
- max_backlight = (pch_pwm_ctl2 >> 16) & BACKLIGHT_DUTY_CYCLE_MASK;
- /* calculate the expected PMW frequency */
- level = (bclp * max_backlight) / 255;
- /* reserve the high 16 bits */
- cpu_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK);
- /* write the updated PWM frequency */
- I915_WRITE(BLC_PWM_CPU_CTL, cpu_pwm_ctl | level);
-
- asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
-
- return 0;
-}
-
-void ironlake_opregion_gse_intr(struct drm_device *dev)
+/* Only present on Ironlake+ */
+void intel_opregion_gse_intr(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct opregion_asle *asle = dev_priv->opregion.asle;
@@ -296,7 +248,7 @@ void ironlake_opregion_gse_intr(struct drm_device *dev)
}
if (asle_req & ASLE_SET_BACKLIGHT)
- asle_stat |= asle_set_backlight_ironlake(dev, asle->bclp);
+ asle_stat |= asle_set_backlight(dev, asle->bclp);
if (asle_req & ASLE_SET_PFIT) {
DRM_DEBUG_DRIVER("Pfit is not supported\n");
@@ -315,7 +267,7 @@ void ironlake_opregion_gse_intr(struct drm_device *dev)
#define ASLE_PFIT_EN (1<<2)
#define ASLE_PFMB_EN (1<<3)
-void opregion_enable_asle(struct drm_device *dev)
+void intel_opregion_enable_asle(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct opregion_asle *asle = dev_priv->opregion.asle;
@@ -464,7 +416,58 @@ blind_set:
goto end;
}
-int intel_opregion_init(struct drm_device *dev, int resume)
+void intel_opregion_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_opregion *opregion = &dev_priv->opregion;
+
+ if (!opregion->header)
+ return;
+
+ if (opregion->acpi) {
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ intel_didl_outputs(dev);
+
+ /* Notify BIOS we are ready to handle ACPI video ext notifs.
+ * Right now, all the events are handled by the ACPI video module.
+ * We don't actually need to do anything with them. */
+ opregion->acpi->csts = 0;
+ opregion->acpi->drdy = 1;
+
+ system_opregion = opregion;
+ register_acpi_notifier(&intel_opregion_notifier);
+ }
+
+ if (opregion->asle)
+ intel_opregion_enable_asle(dev);
+}
+
+void intel_opregion_fini(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_opregion *opregion = &dev_priv->opregion;
+
+ if (!opregion->header)
+ return;
+
+ if (opregion->acpi) {
+ opregion->acpi->drdy = 0;
+
+ system_opregion = NULL;
+ unregister_acpi_notifier(&intel_opregion_notifier);
+ }
+
+ /* just clear all opregion memory pointers now */
+ iounmap(opregion->header);
+ opregion->header = NULL;
+ opregion->acpi = NULL;
+ opregion->swsci = NULL;
+ opregion->asle = NULL;
+ opregion->vbt = NULL;
+}
+#endif
+
+int intel_opregion_setup(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_opregion *opregion = &dev_priv->opregion;
@@ -479,29 +482,23 @@ int intel_opregion_init(struct drm_device *dev, int resume)
return -ENOTSUPP;
}
- base = ioremap(asls, OPREGION_SZ);
+ base = ioremap(asls, OPREGION_SIZE);
if (!base)
return -ENOMEM;
- opregion->header = base;
- if (memcmp(opregion->header->signature, OPREGION_SIGNATURE, 16)) {
+ if (memcmp(base, OPREGION_SIGNATURE, 16)) {
DRM_DEBUG_DRIVER("opregion signature mismatch\n");
err = -EINVAL;
goto err_out;
}
+ opregion->header = base;
+ opregion->vbt = base + OPREGION_VBT_OFFSET;
mboxes = opregion->header->mboxes;
if (mboxes & MBOX_ACPI) {
DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
opregion->acpi = base + OPREGION_ACPI_OFFSET;
- if (drm_core_check_feature(dev, DRIVER_MODESET))
- intel_didl_outputs(dev);
- } else {
- DRM_DEBUG_DRIVER("Public ACPI methods not supported\n");
- err = -ENOTSUPP;
- goto err_out;
}
- opregion->enabled = 1;
if (mboxes & MBOX_SWSCI) {
DRM_DEBUG_DRIVER("SWSCI supported\n");
@@ -510,53 +507,11 @@ int intel_opregion_init(struct drm_device *dev, int resume)
if (mboxes & MBOX_ASLE) {
DRM_DEBUG_DRIVER("ASLE supported\n");
opregion->asle = base + OPREGION_ASLE_OFFSET;
- opregion_enable_asle(dev);
}
- if (!resume)
- acpi_video_register();
-
-
- /* Notify BIOS we are ready to handle ACPI video ext notifs.
- * Right now, all the events are handled by the ACPI video module.
- * We don't actually need to do anything with them. */
- opregion->acpi->csts = 0;
- opregion->acpi->drdy = 1;
-
- system_opregion = opregion;
- register_acpi_notifier(&intel_opregion_notifier);
-
return 0;
err_out:
iounmap(opregion->header);
- opregion->header = NULL;
- acpi_video_register();
return err;
}
-
-void intel_opregion_free(struct drm_device *dev, int suspend)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_opregion *opregion = &dev_priv->opregion;
-
- if (!opregion->enabled)
- return;
-
- if (!suspend)
- acpi_video_unregister();
-
- opregion->acpi->drdy = 0;
-
- system_opregion = NULL;
- unregister_acpi_notifier(&intel_opregion_notifier);
-
- /* just clear all opregion memory pointers now */
- iounmap(opregion->header);
- opregion->header = NULL;
- opregion->acpi = NULL;
- opregion->swsci = NULL;
- opregion->asle = NULL;
-
- opregion->enabled = 0;
-}
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 1d306a458be6..afb96d25219a 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -170,57 +170,143 @@ struct overlay_registers {
u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
};
-/* overlay flip addr flag */
-#define OFC_UPDATE 0x1
-
-#define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev))
-#define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IRONLAKE(dev) && !IS_GEN6(dev))
-
+struct intel_overlay {
+ struct drm_device *dev;
+ struct intel_crtc *crtc;
+ struct drm_i915_gem_object *vid_bo;
+ struct drm_i915_gem_object *old_vid_bo;
+ int active;
+ int pfit_active;
+ u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
+ u32 color_key;
+ u32 brightness, contrast, saturation;
+ u32 old_xscale, old_yscale;
+ /* register access */
+ u32 flip_addr;
+ struct drm_i915_gem_object *reg_bo;
+ /* flip handling */
+ uint32_t last_flip_req;
+ void (*flip_tail)(struct intel_overlay *);
+};
-static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
+static struct overlay_registers *
+intel_overlay_map_regs(struct intel_overlay *overlay)
{
drm_i915_private_t *dev_priv = overlay->dev->dev_private;
struct overlay_registers *regs;
- /* no recursive mappings */
- BUG_ON(overlay->virt_addr);
+ if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+ regs = overlay->reg_bo->phys_obj->handle->vaddr;
+ else
+ regs = io_mapping_map_wc(dev_priv->mm.gtt_mapping,
+ overlay->reg_bo->gtt_offset);
- if (OVERLAY_NONPHYSICAL(overlay->dev)) {
- regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
- overlay->reg_bo->gtt_offset,
- KM_USER0);
+ return regs;
+}
- if (!regs) {
- DRM_ERROR("failed to map overlay regs in GTT\n");
- return NULL;
- }
- } else
- regs = overlay->reg_bo->phys_obj->handle->vaddr;
+static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
+ struct overlay_registers *regs)
+{
+ if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+ io_mapping_unmap(regs);
+}
+
+static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
+ struct drm_i915_gem_request *request,
+ bool interruptible,
+ void (*tail)(struct intel_overlay *))
+{
+ struct drm_device *dev = overlay->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int ret;
- return overlay->virt_addr = regs;
+ BUG_ON(overlay->last_flip_req);
+ overlay->last_flip_req =
+ i915_add_request(dev, NULL, request, &dev_priv->render_ring);
+ if (overlay->last_flip_req == 0)
+ return -ENOMEM;
+
+ overlay->flip_tail = tail;
+ ret = i915_do_wait_request(dev,
+ overlay->last_flip_req, true,
+ &dev_priv->render_ring);
+ if (ret)
+ return ret;
+
+ overlay->last_flip_req = 0;
+ return 0;
}
-static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay)
+/* Workaround for i830 bug where pipe a must be enable to change control regs */
+static int
+i830_activate_pipe_a(struct drm_device *dev)
{
- if (OVERLAY_NONPHYSICAL(overlay->dev))
- io_mapping_unmap_atomic(overlay->virt_addr, KM_USER0);
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_crtc *crtc;
+ struct drm_crtc_helper_funcs *crtc_funcs;
+ struct drm_display_mode vesa_640x480 = {
+ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
+ 752, 800, 0, 480, 489, 492, 525, 0,
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
+ }, *mode;
+
+ crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]);
+ if (crtc->dpms_mode == DRM_MODE_DPMS_ON)
+ return 0;
- overlay->virt_addr = NULL;
+ /* most i8xx have pipe a forced on, so don't trust dpms mode */
+ if (I915_READ(PIPEACONF) & PIPECONF_ENABLE)
+ return 0;
- return;
+ crtc_funcs = crtc->base.helper_private;
+ if (crtc_funcs->dpms == NULL)
+ return 0;
+
+ DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n");
+
+ mode = drm_mode_duplicate(dev, &vesa_640x480);
+ drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+ if(!drm_crtc_helper_set_mode(&crtc->base, mode,
+ crtc->base.x, crtc->base.y,
+ crtc->base.fb))
+ return 0;
+
+ crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON);
+ return 1;
+}
+
+static void
+i830_deactivate_pipe_a(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0];
+ struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+
+ crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
}
/* overlay needs to be disable in OCMD reg */
static int intel_overlay_on(struct intel_overlay *overlay)
{
struct drm_device *dev = overlay->dev;
+ struct drm_i915_gem_request *request;
+ int pipe_a_quirk = 0;
int ret;
- drm_i915_private_t *dev_priv = dev->dev_private;
BUG_ON(overlay->active);
-
overlay->active = 1;
- overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP;
+
+ if (IS_I830(dev)) {
+ pipe_a_quirk = i830_activate_pipe_a(dev);
+ if (pipe_a_quirk < 0)
+ return pipe_a_quirk;
+ }
+
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
BEGIN_LP_RING(4);
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
@@ -229,32 +315,30 @@ static int intel_overlay_on(struct intel_overlay *overlay)
OUT_RING(MI_NOOP);
ADVANCE_LP_RING();
- overlay->last_flip_req =
- i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
- if (overlay->last_flip_req == 0)
- return -ENOMEM;
-
- ret = i915_do_wait_request(dev,
- overlay->last_flip_req, 1, &dev_priv->render_ring);
- if (ret != 0)
- return ret;
+ ret = intel_overlay_do_wait_request(overlay, request, true, NULL);
+out:
+ if (pipe_a_quirk)
+ i830_deactivate_pipe_a(dev);
- overlay->hw_wedged = 0;
- overlay->last_flip_req = 0;
- return 0;
+ return ret;
}
/* overlay needs to be enabled in OCMD reg */
-static void intel_overlay_continue(struct intel_overlay *overlay,
- bool load_polyphase_filter)
+static int intel_overlay_continue(struct intel_overlay *overlay,
+ bool load_polyphase_filter)
{
struct drm_device *dev = overlay->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_request *request;
u32 flip_addr = overlay->flip_addr;
u32 tmp;
BUG_ON(!overlay->active);
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL)
+ return -ENOMEM;
+
if (load_polyphase_filter)
flip_addr |= OFC_UPDATE;
@@ -269,220 +353,132 @@ static void intel_overlay_continue(struct intel_overlay *overlay,
ADVANCE_LP_RING();
overlay->last_flip_req =
- i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
+ i915_add_request(dev, NULL, request, &dev_priv->render_ring);
+ return 0;
}
-static int intel_overlay_wait_flip(struct intel_overlay *overlay)
+static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
{
- struct drm_device *dev = overlay->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
- int ret;
- u32 tmp;
-
- if (overlay->last_flip_req != 0) {
- ret = i915_do_wait_request(dev, overlay->last_flip_req,
- 1, &dev_priv->render_ring);
- if (ret == 0) {
- overlay->last_flip_req = 0;
-
- tmp = I915_READ(ISR);
+ struct drm_gem_object *obj = &overlay->old_vid_bo->base;
- if (!(tmp & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT))
- return 0;
- }
- }
+ i915_gem_object_unpin(obj);
+ drm_gem_object_unreference(obj);
- /* synchronous slowpath */
- overlay->hw_wedged = RELEASE_OLD_VID;
+ overlay->old_vid_bo = NULL;
+}
- BEGIN_LP_RING(2);
- OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
- OUT_RING(MI_NOOP);
- ADVANCE_LP_RING();
+static void intel_overlay_off_tail(struct intel_overlay *overlay)
+{
+ struct drm_gem_object *obj;
- overlay->last_flip_req =
- i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
- if (overlay->last_flip_req == 0)
- return -ENOMEM;
+ /* never have the overlay hw on without showing a frame */
+ BUG_ON(!overlay->vid_bo);
+ obj = &overlay->vid_bo->base;
- ret = i915_do_wait_request(dev, overlay->last_flip_req,
- 1, &dev_priv->render_ring);
- if (ret != 0)
- return ret;
+ i915_gem_object_unpin(obj);
+ drm_gem_object_unreference(obj);
+ overlay->vid_bo = NULL;
- overlay->hw_wedged = 0;
- overlay->last_flip_req = 0;
- return 0;
+ overlay->crtc->overlay = NULL;
+ overlay->crtc = NULL;
+ overlay->active = 0;
}
/* overlay needs to be disabled in OCMD reg */
-static int intel_overlay_off(struct intel_overlay *overlay)
+static int intel_overlay_off(struct intel_overlay *overlay,
+ bool interruptible)
{
- u32 flip_addr = overlay->flip_addr;
struct drm_device *dev = overlay->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
- int ret;
+ u32 flip_addr = overlay->flip_addr;
+ struct drm_i915_gem_request *request;
BUG_ON(!overlay->active);
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL)
+ return -ENOMEM;
+
/* According to intel docs the overlay hw may hang (when switching
* off) without loading the filter coeffs. It is however unclear whether
* this applies to the disabling of the overlay or to the switching off
* of the hw. Do it in both cases */
flip_addr |= OFC_UPDATE;
+ BEGIN_LP_RING(6);
/* wait for overlay to go idle */
- overlay->hw_wedged = SWITCH_OFF_STAGE_1;
-
- BEGIN_LP_RING(4);
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
OUT_RING(flip_addr);
- OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
- OUT_RING(MI_NOOP);
- ADVANCE_LP_RING();
-
- overlay->last_flip_req =
- i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
- if (overlay->last_flip_req == 0)
- return -ENOMEM;
-
- ret = i915_do_wait_request(dev, overlay->last_flip_req,
- 1, &dev_priv->render_ring);
- if (ret != 0)
- return ret;
-
+ OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
/* turn overlay off */
- overlay->hw_wedged = SWITCH_OFF_STAGE_2;
-
- BEGIN_LP_RING(4);
- OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
+ OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
OUT_RING(flip_addr);
- OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
- OUT_RING(MI_NOOP);
+ OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
ADVANCE_LP_RING();
- overlay->last_flip_req =
- i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
- if (overlay->last_flip_req == 0)
- return -ENOMEM;
-
- ret = i915_do_wait_request(dev, overlay->last_flip_req,
- 1, &dev_priv->render_ring);
- if (ret != 0)
- return ret;
-
- overlay->hw_wedged = 0;
- overlay->last_flip_req = 0;
- return ret;
-}
-
-static void intel_overlay_off_tail(struct intel_overlay *overlay)
-{
- struct drm_gem_object *obj;
-
- /* never have the overlay hw on without showing a frame */
- BUG_ON(!overlay->vid_bo);
- obj = &overlay->vid_bo->base;
-
- i915_gem_object_unpin(obj);
- drm_gem_object_unreference(obj);
- overlay->vid_bo = NULL;
-
- overlay->crtc->overlay = NULL;
- overlay->crtc = NULL;
- overlay->active = 0;
+ return intel_overlay_do_wait_request(overlay, request, interruptible,
+ intel_overlay_off_tail);
}
/* recover from an interruption due to a signal
* We have to be careful not to repeat work forever an make forward progess. */
-int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
- int interruptible)
+static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
+ bool interruptible)
{
struct drm_device *dev = overlay->dev;
- struct drm_gem_object *obj;
drm_i915_private_t *dev_priv = dev->dev_private;
- u32 flip_addr;
int ret;
- if (overlay->hw_wedged == HW_WEDGED)
- return -EIO;
-
- if (overlay->last_flip_req == 0) {
- overlay->last_flip_req =
- i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
- if (overlay->last_flip_req == 0)
- return -ENOMEM;
- }
+ if (overlay->last_flip_req == 0)
+ return 0;
ret = i915_do_wait_request(dev, overlay->last_flip_req,
- interruptible, &dev_priv->render_ring);
- if (ret != 0)
+ interruptible, &dev_priv->render_ring);
+ if (ret)
return ret;
- switch (overlay->hw_wedged) {
- case RELEASE_OLD_VID:
- obj = &overlay->old_vid_bo->base;
- i915_gem_object_unpin(obj);
- drm_gem_object_unreference(obj);
- overlay->old_vid_bo = NULL;
- break;
- case SWITCH_OFF_STAGE_1:
- flip_addr = overlay->flip_addr;
- flip_addr |= OFC_UPDATE;
-
- overlay->hw_wedged = SWITCH_OFF_STAGE_2;
-
- BEGIN_LP_RING(4);
- OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
- OUT_RING(flip_addr);
- OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
- OUT_RING(MI_NOOP);
- ADVANCE_LP_RING();
-
- overlay->last_flip_req = i915_add_request(dev, NULL,
- 0, &dev_priv->render_ring);
- if (overlay->last_flip_req == 0)
- return -ENOMEM;
-
- ret = i915_do_wait_request(dev, overlay->last_flip_req,
- interruptible, &dev_priv->render_ring);
- if (ret != 0)
- return ret;
-
- case SWITCH_OFF_STAGE_2:
- intel_overlay_off_tail(overlay);
- break;
- default:
- BUG_ON(overlay->hw_wedged != NEEDS_WAIT_FOR_FLIP);
- }
+ if (overlay->flip_tail)
+ overlay->flip_tail(overlay);
- overlay->hw_wedged = 0;
overlay->last_flip_req = 0;
return 0;
}
/* Wait for pending overlay flip and release old frame.
* Needs to be called before the overlay register are changed
- * via intel_overlay_(un)map_regs_atomic */
+ * via intel_overlay_(un)map_regs
+ */
static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
{
+ struct drm_device *dev = overlay->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
- struct drm_gem_object *obj;
- /* only wait if there is actually an old frame to release to
- * guarantee forward progress */
+ /* Only wait if there is actually an old frame to release to
+ * guarantee forward progress.
+ */
if (!overlay->old_vid_bo)
return 0;
- ret = intel_overlay_wait_flip(overlay);
- if (ret != 0)
- return ret;
+ if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
+ struct drm_i915_gem_request *request;
- obj = &overlay->old_vid_bo->base;
- i915_gem_object_unpin(obj);
- drm_gem_object_unreference(obj);
- overlay->old_vid_bo = NULL;
+ /* synchronous slowpath */
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL)
+ return -ENOMEM;
+ BEGIN_LP_RING(2);
+ OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+ OUT_RING(MI_NOOP);
+ ADVANCE_LP_RING();
+
+ ret = intel_overlay_do_wait_request(overlay, request, true,
+ intel_overlay_release_old_vid_tail);
+ if (ret)
+ return ret;
+ }
+
+ intel_overlay_release_old_vid_tail(overlay);
return 0;
}
@@ -506,65 +502,65 @@ struct put_image_params {
static int packed_depth_bytes(u32 format)
{
switch (format & I915_OVERLAY_DEPTH_MASK) {
- case I915_OVERLAY_YUV422:
- return 4;
- case I915_OVERLAY_YUV411:
- /* return 6; not implemented */
- default:
- return -EINVAL;
+ case I915_OVERLAY_YUV422:
+ return 4;
+ case I915_OVERLAY_YUV411:
+ /* return 6; not implemented */
+ default:
+ return -EINVAL;
}
}
static int packed_width_bytes(u32 format, short width)
{
switch (format & I915_OVERLAY_DEPTH_MASK) {
- case I915_OVERLAY_YUV422:
- return width << 1;
- default:
- return -EINVAL;
+ case I915_OVERLAY_YUV422:
+ return width << 1;
+ default:
+ return -EINVAL;
}
}
static int uv_hsubsampling(u32 format)
{
switch (format & I915_OVERLAY_DEPTH_MASK) {
- case I915_OVERLAY_YUV422:
- case I915_OVERLAY_YUV420:
- return 2;
- case I915_OVERLAY_YUV411:
- case I915_OVERLAY_YUV410:
- return 4;
- default:
- return -EINVAL;
+ case I915_OVERLAY_YUV422:
+ case I915_OVERLAY_YUV420:
+ return 2;
+ case I915_OVERLAY_YUV411:
+ case I915_OVERLAY_YUV410:
+ return 4;
+ default:
+ return -EINVAL;
}
}
static int uv_vsubsampling(u32 format)
{
switch (format & I915_OVERLAY_DEPTH_MASK) {
- case I915_OVERLAY_YUV420:
- case I915_OVERLAY_YUV410:
- return 2;
- case I915_OVERLAY_YUV422:
- case I915_OVERLAY_YUV411:
- return 1;
- default:
- return -EINVAL;
+ case I915_OVERLAY_YUV420:
+ case I915_OVERLAY_YUV410:
+ return 2;
+ case I915_OVERLAY_YUV422:
+ case I915_OVERLAY_YUV411:
+ return 1;
+ default:
+ return -EINVAL;
}
}
static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width)
{
u32 mask, shift, ret;
- if (IS_I9XX(dev)) {
- mask = 0x3f;
- shift = 6;
- } else {
+ if (IS_GEN2(dev)) {
mask = 0x1f;
shift = 5;
+ } else {
+ mask = 0x3f;
+ shift = 6;
}
ret = ((offset + width + mask) >> shift) - (offset >> shift);
- if (IS_I9XX(dev))
+ if (!IS_GEN2(dev))
ret <<= 1;
ret -=1;
return ret << 2;
@@ -587,7 +583,9 @@ static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
- 0xb000, 0x3000, 0x0800, 0x3000, 0xb000};
+ 0xb000, 0x3000, 0x0800, 0x3000, 0xb000
+};
+
static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
@@ -597,7 +595,8 @@ static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
- 0x3000, 0x0800, 0x3000};
+ 0x3000, 0x0800, 0x3000
+};
static void update_polyphase_filter(struct overlay_registers *regs)
{
@@ -630,29 +629,31 @@ static bool update_scaling_factors(struct intel_overlay *overlay,
yscale = 1 << FP_SHIFT;
/*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
- xscale_UV = xscale/uv_hscale;
- yscale_UV = yscale/uv_vscale;
- /* make the Y scale to UV scale ratio an exact multiply */
- xscale = xscale_UV * uv_hscale;
- yscale = yscale_UV * uv_vscale;
+ xscale_UV = xscale/uv_hscale;
+ yscale_UV = yscale/uv_vscale;
+ /* make the Y scale to UV scale ratio an exact multiply */
+ xscale = xscale_UV * uv_hscale;
+ yscale = yscale_UV * uv_vscale;
/*} else {
- xscale_UV = 0;
- yscale_UV = 0;
- }*/
+ xscale_UV = 0;
+ yscale_UV = 0;
+ }*/
if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
scale_changed = true;
overlay->old_xscale = xscale;
overlay->old_yscale = yscale;
- regs->YRGBSCALE = ((yscale & FRACT_MASK) << 20)
- | ((xscale >> FP_SHIFT) << 16)
- | ((xscale & FRACT_MASK) << 3);
- regs->UVSCALE = ((yscale_UV & FRACT_MASK) << 20)
- | ((xscale_UV >> FP_SHIFT) << 16)
- | ((xscale_UV & FRACT_MASK) << 3);
- regs->UVSCALEV = ((yscale >> FP_SHIFT) << 16)
- | ((yscale_UV >> FP_SHIFT) << 0);
+ regs->YRGBSCALE = (((yscale & FRACT_MASK) << 20) |
+ ((xscale >> FP_SHIFT) << 16) |
+ ((xscale & FRACT_MASK) << 3));
+
+ regs->UVSCALE = (((yscale_UV & FRACT_MASK) << 20) |
+ ((xscale_UV >> FP_SHIFT) << 16) |
+ ((xscale_UV & FRACT_MASK) << 3));
+
+ regs->UVSCALEV = ((((yscale >> FP_SHIFT) << 16) |
+ ((yscale_UV >> FP_SHIFT) << 0)));
if (scale_changed)
update_polyphase_filter(regs);
@@ -664,22 +665,28 @@ static void update_colorkey(struct intel_overlay *overlay,
struct overlay_registers *regs)
{
u32 key = overlay->color_key;
+
switch (overlay->crtc->base.fb->bits_per_pixel) {
- case 8:
- regs->DCLRKV = 0;
- regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
- case 16:
- if (overlay->crtc->base.fb->depth == 15) {
- regs->DCLRKV = RGB15_TO_COLORKEY(key);
- regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
- } else {
- regs->DCLRKV = RGB16_TO_COLORKEY(key);
- regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
- }
- case 24:
- case 32:
- regs->DCLRKV = key;
- regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
+ case 8:
+ regs->DCLRKV = 0;
+ regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
+ break;
+
+ case 16:
+ if (overlay->crtc->base.fb->depth == 15) {
+ regs->DCLRKV = RGB15_TO_COLORKEY(key);
+ regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
+ } else {
+ regs->DCLRKV = RGB16_TO_COLORKEY(key);
+ regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
+ }
+ break;
+
+ case 24:
+ case 32:
+ regs->DCLRKV = key;
+ regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
+ break;
}
}
@@ -689,48 +696,48 @@ static u32 overlay_cmd_reg(struct put_image_params *params)
if (params->format & I915_OVERLAY_YUV_PLANAR) {
switch (params->format & I915_OVERLAY_DEPTH_MASK) {
- case I915_OVERLAY_YUV422:
- cmd |= OCMD_YUV_422_PLANAR;
- break;
- case I915_OVERLAY_YUV420:
- cmd |= OCMD_YUV_420_PLANAR;
- break;
- case I915_OVERLAY_YUV411:
- case I915_OVERLAY_YUV410:
- cmd |= OCMD_YUV_410_PLANAR;
- break;
+ case I915_OVERLAY_YUV422:
+ cmd |= OCMD_YUV_422_PLANAR;
+ break;
+ case I915_OVERLAY_YUV420:
+ cmd |= OCMD_YUV_420_PLANAR;
+ break;
+ case I915_OVERLAY_YUV411:
+ case I915_OVERLAY_YUV410:
+ cmd |= OCMD_YUV_410_PLANAR;
+ break;
}
} else { /* YUV packed */
switch (params->format & I915_OVERLAY_DEPTH_MASK) {
- case I915_OVERLAY_YUV422:
- cmd |= OCMD_YUV_422_PACKED;
- break;
- case I915_OVERLAY_YUV411:
- cmd |= OCMD_YUV_411_PACKED;
- break;
+ case I915_OVERLAY_YUV422:
+ cmd |= OCMD_YUV_422_PACKED;
+ break;
+ case I915_OVERLAY_YUV411:
+ cmd |= OCMD_YUV_411_PACKED;
+ break;
}
switch (params->format & I915_OVERLAY_SWAP_MASK) {
- case I915_OVERLAY_NO_SWAP:
- break;
- case I915_OVERLAY_UV_SWAP:
- cmd |= OCMD_UV_SWAP;
- break;
- case I915_OVERLAY_Y_SWAP:
- cmd |= OCMD_Y_SWAP;
- break;
- case I915_OVERLAY_Y_AND_UV_SWAP:
- cmd |= OCMD_Y_AND_UV_SWAP;
- break;
+ case I915_OVERLAY_NO_SWAP:
+ break;
+ case I915_OVERLAY_UV_SWAP:
+ cmd |= OCMD_UV_SWAP;
+ break;
+ case I915_OVERLAY_Y_SWAP:
+ cmd |= OCMD_Y_SWAP;
+ break;
+ case I915_OVERLAY_Y_AND_UV_SWAP:
+ cmd |= OCMD_Y_AND_UV_SWAP;
+ break;
}
}
return cmd;
}
-int intel_overlay_do_put_image(struct intel_overlay *overlay,
- struct drm_gem_object *new_bo,
- struct put_image_params *params)
+static int intel_overlay_do_put_image(struct intel_overlay *overlay,
+ struct drm_gem_object *new_bo,
+ struct put_image_params *params)
{
int ret, tmp_width;
struct overlay_registers *regs;
@@ -755,24 +762,24 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay,
goto out_unpin;
if (!overlay->active) {
- regs = intel_overlay_map_regs_atomic(overlay);
+ regs = intel_overlay_map_regs(overlay);
if (!regs) {
ret = -ENOMEM;
goto out_unpin;
}
regs->OCONFIG = OCONF_CC_OUT_8BIT;
- if (IS_I965GM(overlay->dev))
+ if (IS_GEN4(overlay->dev))
regs->OCONFIG |= OCONF_CSC_MODE_BT709;
regs->OCONFIG |= overlay->crtc->pipe == 0 ?
OCONF_PIPE_A : OCONF_PIPE_B;
- intel_overlay_unmap_regs_atomic(overlay);
+ intel_overlay_unmap_regs(overlay, regs);
ret = intel_overlay_on(overlay);
if (ret != 0)
goto out_unpin;
}
- regs = intel_overlay_map_regs_atomic(overlay);
+ regs = intel_overlay_map_regs(overlay);
if (!regs) {
ret = -ENOMEM;
goto out_unpin;
@@ -788,7 +795,7 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay,
regs->SWIDTH = params->src_w;
regs->SWIDTHSW = calc_swidthsw(overlay->dev,
- params->offset_Y, tmp_width);
+ params->offset_Y, tmp_width);
regs->SHEIGHT = params->src_h;
regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y;
regs->OSTRIDE = params->stride_Y;
@@ -799,9 +806,9 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay,
u32 tmp_U, tmp_V;
regs->SWIDTH |= (params->src_w/uv_hscale) << 16;
tmp_U = calc_swidthsw(overlay->dev, params->offset_U,
- params->src_w/uv_hscale);
+ params->src_w/uv_hscale);
tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
- params->src_w/uv_hscale);
+ params->src_w/uv_hscale);
regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16;
regs->SHEIGHT |= (params->src_h/uv_vscale) << 16;
regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U;
@@ -815,9 +822,11 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay,
regs->OCMD = overlay_cmd_reg(params);
- intel_overlay_unmap_regs_atomic(overlay);
+ intel_overlay_unmap_regs(overlay, regs);
- intel_overlay_continue(overlay, scale_changed);
+ ret = intel_overlay_continue(overlay, scale_changed);
+ if (ret)
+ goto out_unpin;
overlay->old_vid_bo = overlay->vid_bo;
overlay->vid_bo = to_intel_bo(new_bo);
@@ -829,20 +838,19 @@ out_unpin:
return ret;
}
-int intel_overlay_switch_off(struct intel_overlay *overlay)
+int intel_overlay_switch_off(struct intel_overlay *overlay,
+ bool interruptible)
{
- int ret;
struct overlay_registers *regs;
struct drm_device *dev = overlay->dev;
+ int ret;
BUG_ON(!mutex_is_locked(&dev->struct_mutex));
BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
- if (overlay->hw_wedged) {
- ret = intel_overlay_recover_from_interrupt(overlay, 1);
- if (ret != 0)
- return ret;
- }
+ ret = intel_overlay_recover_from_interrupt(overlay, interruptible);
+ if (ret != 0)
+ return ret;
if (!overlay->active)
return 0;
@@ -851,33 +859,29 @@ int intel_overlay_switch_off(struct intel_overlay *overlay)
if (ret != 0)
return ret;
- regs = intel_overlay_map_regs_atomic(overlay);
+ regs = intel_overlay_map_regs(overlay);
regs->OCMD = 0;
- intel_overlay_unmap_regs_atomic(overlay);
+ intel_overlay_unmap_regs(overlay, regs);
- ret = intel_overlay_off(overlay);
+ ret = intel_overlay_off(overlay, interruptible);
if (ret != 0)
return ret;
intel_overlay_off_tail(overlay);
-
return 0;
}
static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
struct intel_crtc *crtc)
{
- drm_i915_private_t *dev_priv = overlay->dev->dev_private;
- u32 pipeconf;
- int pipeconf_reg = (crtc->pipe == 0) ? PIPEACONF : PIPEBCONF;
+ drm_i915_private_t *dev_priv = overlay->dev->dev_private;
- if (!crtc->base.enabled || crtc->dpms_mode != DRM_MODE_DPMS_ON)
+ if (!crtc->active)
return -EINVAL;
- pipeconf = I915_READ(pipeconf_reg);
-
/* can't use the overlay with double wide pipe */
- if (!IS_I965G(overlay->dev) && pipeconf & PIPEACONF_DOUBLE_WIDE)
+ if (INTEL_INFO(overlay->dev)->gen < 4 &&
+ (I915_READ(PIPECONF(crtc->pipe)) & (PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE)) != PIPECONF_ENABLE)
return -EINVAL;
return 0;
@@ -886,20 +890,22 @@ static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
{
struct drm_device *dev = overlay->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
- u32 ratio;
+ drm_i915_private_t *dev_priv = dev->dev_private;
u32 pfit_control = I915_READ(PFIT_CONTROL);
+ u32 ratio;
/* XXX: This is not the same logic as in the xorg driver, but more in
- * line with the intel documentation for the i965 */
- if (!IS_I965G(dev) && (pfit_control & VERT_AUTO_SCALE)) {
- ratio = I915_READ(PFIT_AUTO_RATIOS) >> PFIT_VERT_SCALE_SHIFT;
- } else { /* on i965 use the PGM reg to read out the autoscaler values */
- ratio = I915_READ(PFIT_PGM_RATIOS);
- if (IS_I965G(dev))
- ratio >>= PFIT_VERT_SCALE_SHIFT_965;
+ * line with the intel documentation for the i965
+ */
+ if (INTEL_INFO(dev)->gen >= 4) {
+ /* on i965 use the PGM reg to read out the autoscaler values */
+ ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965;
+ } else {
+ if (pfit_control & VERT_AUTO_SCALE)
+ ratio = I915_READ(PFIT_AUTO_RATIOS);
else
- ratio >>= PFIT_VERT_SCALE_SHIFT;
+ ratio = I915_READ(PFIT_PGM_RATIOS);
+ ratio >>= PFIT_VERT_SCALE_SHIFT;
}
overlay->pfit_vscale_ratio = ratio;
@@ -910,12 +916,10 @@ static int check_overlay_dst(struct intel_overlay *overlay,
{
struct drm_display_mode *mode = &overlay->crtc->base.mode;
- if ((rec->dst_x < mode->crtc_hdisplay)
- && (rec->dst_x + rec->dst_width
- <= mode->crtc_hdisplay)
- && (rec->dst_y < mode->crtc_vdisplay)
- && (rec->dst_y + rec->dst_height
- <= mode->crtc_vdisplay))
+ if (rec->dst_x < mode->crtc_hdisplay &&
+ rec->dst_x + rec->dst_width <= mode->crtc_hdisplay &&
+ rec->dst_y < mode->crtc_vdisplay &&
+ rec->dst_y + rec->dst_height <= mode->crtc_vdisplay)
return 0;
else
return -EINVAL;
@@ -940,53 +944,57 @@ static int check_overlay_src(struct drm_device *dev,
struct drm_intel_overlay_put_image *rec,
struct drm_gem_object *new_bo)
{
- u32 stride_mask;
- int depth;
int uv_hscale = uv_hsubsampling(rec->flags);
int uv_vscale = uv_vsubsampling(rec->flags);
- size_t tmp;
+ u32 stride_mask, depth, tmp;
/* check src dimensions */
if (IS_845G(dev) || IS_I830(dev)) {
- if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY
- || rec->src_width > IMAGE_MAX_WIDTH_LEGACY)
+ if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY ||
+ rec->src_width > IMAGE_MAX_WIDTH_LEGACY)
return -EINVAL;
} else {
- if (rec->src_height > IMAGE_MAX_HEIGHT
- || rec->src_width > IMAGE_MAX_WIDTH)
+ if (rec->src_height > IMAGE_MAX_HEIGHT ||
+ rec->src_width > IMAGE_MAX_WIDTH)
return -EINVAL;
}
+
/* better safe than sorry, use 4 as the maximal subsampling ratio */
- if (rec->src_height < N_VERT_Y_TAPS*4
- || rec->src_width < N_HORIZ_Y_TAPS*4)
+ if (rec->src_height < N_VERT_Y_TAPS*4 ||
+ rec->src_width < N_HORIZ_Y_TAPS*4)
return -EINVAL;
/* check alignment constraints */
switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
- case I915_OVERLAY_RGB:
- /* not implemented */
+ case I915_OVERLAY_RGB:
+ /* not implemented */
+ return -EINVAL;
+
+ case I915_OVERLAY_YUV_PACKED:
+ if (uv_vscale != 1)
return -EINVAL;
- case I915_OVERLAY_YUV_PACKED:
- depth = packed_depth_bytes(rec->flags);
- if (uv_vscale != 1)
- return -EINVAL;
- if (depth < 0)
- return depth;
- /* ignore UV planes */
- rec->stride_UV = 0;
- rec->offset_U = 0;
- rec->offset_V = 0;
- /* check pixel alignment */
- if (rec->offset_Y % depth)
- return -EINVAL;
- break;
- case I915_OVERLAY_YUV_PLANAR:
- if (uv_vscale < 0 || uv_hscale < 0)
- return -EINVAL;
- /* no offset restrictions for planar formats */
- break;
- default:
+
+ depth = packed_depth_bytes(rec->flags);
+ if (depth < 0)
+ return depth;
+
+ /* ignore UV planes */
+ rec->stride_UV = 0;
+ rec->offset_U = 0;
+ rec->offset_V = 0;
+ /* check pixel alignment */
+ if (rec->offset_Y % depth)
return -EINVAL;
+ break;
+
+ case I915_OVERLAY_YUV_PLANAR:
+ if (uv_vscale < 0 || uv_hscale < 0)
+ return -EINVAL;
+ /* no offset restrictions for planar formats */
+ break;
+
+ default:
+ return -EINVAL;
}
if (rec->src_width % uv_hscale)
@@ -1000,47 +1008,74 @@ static int check_overlay_src(struct drm_device *dev,
if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
return -EINVAL;
- if (IS_I965G(dev) && rec->stride_Y < 512)
+ if (IS_GEN4(dev) && rec->stride_Y < 512)
return -EINVAL;
tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
- 4 : 8;
- if (rec->stride_Y > tmp*1024 || rec->stride_UV > 2*1024)
+ 4096 : 8192;
+ if (rec->stride_Y > tmp || rec->stride_UV > 2*1024)
return -EINVAL;
/* check buffer dimensions */
switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
- case I915_OVERLAY_RGB:
- case I915_OVERLAY_YUV_PACKED:
- /* always 4 Y values per depth pixels */
- if (packed_width_bytes(rec->flags, rec->src_width)
- > rec->stride_Y)
- return -EINVAL;
-
- tmp = rec->stride_Y*rec->src_height;
- if (rec->offset_Y + tmp > new_bo->size)
- return -EINVAL;
- break;
- case I915_OVERLAY_YUV_PLANAR:
- if (rec->src_width > rec->stride_Y)
- return -EINVAL;
- if (rec->src_width/uv_hscale > rec->stride_UV)
- return -EINVAL;
-
- tmp = rec->stride_Y*rec->src_height;
- if (rec->offset_Y + tmp > new_bo->size)
- return -EINVAL;
- tmp = rec->stride_UV*rec->src_height;
- tmp /= uv_vscale;
- if (rec->offset_U + tmp > new_bo->size
- || rec->offset_V + tmp > new_bo->size)
- return -EINVAL;
- break;
+ case I915_OVERLAY_RGB:
+ case I915_OVERLAY_YUV_PACKED:
+ /* always 4 Y values per depth pixels */
+ if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y)
+ return -EINVAL;
+
+ tmp = rec->stride_Y*rec->src_height;
+ if (rec->offset_Y + tmp > new_bo->size)
+ return -EINVAL;
+ break;
+
+ case I915_OVERLAY_YUV_PLANAR:
+ if (rec->src_width > rec->stride_Y)
+ return -EINVAL;
+ if (rec->src_width/uv_hscale > rec->stride_UV)
+ return -EINVAL;
+
+ tmp = rec->stride_Y * rec->src_height;
+ if (rec->offset_Y + tmp > new_bo->size)
+ return -EINVAL;
+
+ tmp = rec->stride_UV * (rec->src_height / uv_vscale);
+ if (rec->offset_U + tmp > new_bo->size ||
+ rec->offset_V + tmp > new_bo->size)
+ return -EINVAL;
+ break;
}
return 0;
}
+/**
+ * Return the pipe currently connected to the panel fitter,
+ * or -1 if the panel fitter is not present or not in use
+ */
+static int intel_panel_fitter_pipe(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 pfit_control;
+
+ /* i830 doesn't have a panel fitter */
+ if (IS_I830(dev))
+ return -1;
+
+ pfit_control = I915_READ(PFIT_CONTROL);
+
+ /* See if the panel fitter is in use */
+ if ((pfit_control & PFIT_ENABLE) == 0)
+ return -1;
+
+ /* 965 can place panel fitter on either pipe */
+ if (IS_GEN4(dev))
+ return (pfit_control >> 29) & 0x3;
+
+ /* older chips can only use pipe 1 */
+ return 1;
+}
+
int intel_overlay_put_image(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
@@ -1068,7 +1103,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
mutex_lock(&dev->mode_config.mutex);
mutex_lock(&dev->struct_mutex);
- ret = intel_overlay_switch_off(overlay);
+ ret = intel_overlay_switch_off(overlay, true);
mutex_unlock(&dev->struct_mutex);
mutex_unlock(&dev->mode_config.mutex);
@@ -1081,7 +1116,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
return -ENOMEM;
drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id,
- DRM_MODE_OBJECT_CRTC);
+ DRM_MODE_OBJECT_CRTC);
if (!drmmode_obj) {
ret = -ENOENT;
goto out_free;
@@ -1089,7 +1124,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
new_bo = drm_gem_object_lookup(dev, file_priv,
- put_image_rec->bo_handle);
+ put_image_rec->bo_handle);
if (!new_bo) {
ret = -ENOENT;
goto out_free;
@@ -1098,15 +1133,13 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
mutex_lock(&dev->mode_config.mutex);
mutex_lock(&dev->struct_mutex);
- if (overlay->hw_wedged) {
- ret = intel_overlay_recover_from_interrupt(overlay, 1);
- if (ret != 0)
- goto out_unlock;
- }
+ ret = intel_overlay_recover_from_interrupt(overlay, true);
+ if (ret != 0)
+ goto out_unlock;
if (overlay->crtc != crtc) {
struct drm_display_mode *mode = &crtc->base.mode;
- ret = intel_overlay_switch_off(overlay);
+ ret = intel_overlay_switch_off(overlay, true);
if (ret != 0)
goto out_unlock;
@@ -1117,9 +1150,9 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
overlay->crtc = crtc;
crtc->overlay = overlay;
- if (intel_panel_fitter_pipe(dev) == crtc->pipe
- /* and line to wide, i.e. one-line-mode */
- && mode->hdisplay > 1024) {
+ /* line too wide, i.e. one-line-mode */
+ if (mode->hdisplay > 1024 &&
+ intel_panel_fitter_pipe(dev) == crtc->pipe) {
overlay->pfit_active = 1;
update_pfit_vscale_ratio(overlay);
} else
@@ -1132,10 +1165,10 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
if (overlay->pfit_active) {
params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
- overlay->pfit_vscale_ratio);
+ overlay->pfit_vscale_ratio);
/* shifting right rounds downwards, so add 1 */
params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
- overlay->pfit_vscale_ratio) + 1;
+ overlay->pfit_vscale_ratio) + 1;
} else {
params->dst_y = put_image_rec->dst_y;
params->dst_h = put_image_rec->dst_height;
@@ -1147,8 +1180,8 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
params->src_h = put_image_rec->src_height;
params->src_scan_w = put_image_rec->src_scan_width;
params->src_scan_h = put_image_rec->src_scan_height;
- if (params->src_scan_h > params->src_h
- || params->src_scan_w > params->src_w) {
+ if (params->src_scan_h > params->src_h ||
+ params->src_scan_w > params->src_w) {
ret = -EINVAL;
goto out_unlock;
}
@@ -1204,7 +1237,7 @@ static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
return false;
for (i = 0; i < 3; i++) {
- if (((gamma1 >> i * 8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
+ if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
return false;
}
@@ -1225,16 +1258,18 @@ static bool check_gamma5_errata(u32 gamma5)
static int check_gamma(struct drm_intel_overlay_attrs *attrs)
{
- if (!check_gamma_bounds(0, attrs->gamma0)
- || !check_gamma_bounds(attrs->gamma0, attrs->gamma1)
- || !check_gamma_bounds(attrs->gamma1, attrs->gamma2)
- || !check_gamma_bounds(attrs->gamma2, attrs->gamma3)
- || !check_gamma_bounds(attrs->gamma3, attrs->gamma4)
- || !check_gamma_bounds(attrs->gamma4, attrs->gamma5)
- || !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
+ if (!check_gamma_bounds(0, attrs->gamma0) ||
+ !check_gamma_bounds(attrs->gamma0, attrs->gamma1) ||
+ !check_gamma_bounds(attrs->gamma1, attrs->gamma2) ||
+ !check_gamma_bounds(attrs->gamma2, attrs->gamma3) ||
+ !check_gamma_bounds(attrs->gamma3, attrs->gamma4) ||
+ !check_gamma_bounds(attrs->gamma4, attrs->gamma5) ||
+ !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
return -EINVAL;
+
if (!check_gamma5_errata(attrs->gamma5))
return -EINVAL;
+
return 0;
}
@@ -1261,13 +1296,14 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
mutex_lock(&dev->mode_config.mutex);
mutex_lock(&dev->struct_mutex);
+ ret = -EINVAL;
if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
- attrs->color_key = overlay->color_key;
+ attrs->color_key = overlay->color_key;
attrs->brightness = overlay->brightness;
- attrs->contrast = overlay->contrast;
+ attrs->contrast = overlay->contrast;
attrs->saturation = overlay->saturation;
- if (IS_I9XX(dev)) {
+ if (!IS_GEN2(dev)) {
attrs->gamma0 = I915_READ(OGAMC0);
attrs->gamma1 = I915_READ(OGAMC1);
attrs->gamma2 = I915_READ(OGAMC2);
@@ -1275,29 +1311,20 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
attrs->gamma4 = I915_READ(OGAMC4);
attrs->gamma5 = I915_READ(OGAMC5);
}
- ret = 0;
} else {
- overlay->color_key = attrs->color_key;
- if (attrs->brightness >= -128 && attrs->brightness <= 127) {
- overlay->brightness = attrs->brightness;
- } else {
- ret = -EINVAL;
+ if (attrs->brightness < -128 || attrs->brightness > 127)
goto out_unlock;
- }
- if (attrs->contrast <= 255) {
- overlay->contrast = attrs->contrast;
- } else {
- ret = -EINVAL;
+ if (attrs->contrast > 255)
goto out_unlock;
- }
- if (attrs->saturation <= 1023) {
- overlay->saturation = attrs->saturation;
- } else {
- ret = -EINVAL;
+ if (attrs->saturation > 1023)
goto out_unlock;
- }
- regs = intel_overlay_map_regs_atomic(overlay);
+ overlay->color_key = attrs->color_key;
+ overlay->brightness = attrs->brightness;
+ overlay->contrast = attrs->contrast;
+ overlay->saturation = attrs->saturation;
+
+ regs = intel_overlay_map_regs(overlay);
if (!regs) {
ret = -ENOMEM;
goto out_unlock;
@@ -1305,13 +1332,11 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
update_reg_attrs(overlay, regs);
- intel_overlay_unmap_regs_atomic(overlay);
+ intel_overlay_unmap_regs(overlay, regs);
if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
- if (!IS_I9XX(dev)) {
- ret = -EINVAL;
+ if (IS_GEN2(dev))
goto out_unlock;
- }
if (overlay->active) {
ret = -EBUSY;
@@ -1319,7 +1344,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
}
ret = check_gamma(attrs);
- if (ret != 0)
+ if (ret)
goto out_unlock;
I915_WRITE(OGAMC0, attrs->gamma0);
@@ -1329,9 +1354,9 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
I915_WRITE(OGAMC4, attrs->gamma4);
I915_WRITE(OGAMC5, attrs->gamma5);
}
- ret = 0;
}
+ ret = 0;
out_unlock:
mutex_unlock(&dev->struct_mutex);
mutex_unlock(&dev->mode_config.mutex);
@@ -1347,7 +1372,7 @@ void intel_setup_overlay(struct drm_device *dev)
struct overlay_registers *regs;
int ret;
- if (!OVERLAY_EXISTS(dev))
+ if (!HAS_OVERLAY(dev))
return;
overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL);
@@ -1360,22 +1385,28 @@ void intel_setup_overlay(struct drm_device *dev)
goto out_free;
overlay->reg_bo = to_intel_bo(reg_bo);
- if (OVERLAY_NONPHYSICAL(dev)) {
- ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
- if (ret) {
- DRM_ERROR("failed to pin overlay register bo\n");
- goto out_free_bo;
- }
- overlay->flip_addr = overlay->reg_bo->gtt_offset;
- } else {
+ if (OVERLAY_NEEDS_PHYSICAL(dev)) {
ret = i915_gem_attach_phys_object(dev, reg_bo,
I915_GEM_PHYS_OVERLAY_REGS,
- 0);
+ PAGE_SIZE);
if (ret) {
DRM_ERROR("failed to attach phys overlay regs\n");
goto out_free_bo;
}
overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr;
+ } else {
+ ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
+ if (ret) {
+ DRM_ERROR("failed to pin overlay register bo\n");
+ goto out_free_bo;
+ }
+ overlay->flip_addr = overlay->reg_bo->gtt_offset;
+
+ ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
+ if (ret) {
+ DRM_ERROR("failed to move overlay register bo into the GTT\n");
+ goto out_unpin_bo;
+ }
}
/* init all values */
@@ -1384,21 +1415,22 @@ void intel_setup_overlay(struct drm_device *dev)
overlay->contrast = 75;
overlay->saturation = 146;
- regs = intel_overlay_map_regs_atomic(overlay);
+ regs = intel_overlay_map_regs(overlay);
if (!regs)
goto out_free_bo;
memset(regs, 0, sizeof(struct overlay_registers));
update_polyphase_filter(regs);
-
update_reg_attrs(overlay, regs);
- intel_overlay_unmap_regs_atomic(overlay);
+ intel_overlay_unmap_regs(overlay, regs);
dev_priv->overlay = overlay;
DRM_INFO("initialized overlay support\n");
return;
+out_unpin_bo:
+ i915_gem_object_unpin(reg_bo);
out_free_bo:
drm_gem_object_unreference(reg_bo);
out_free:
@@ -1408,18 +1440,23 @@ out_free:
void intel_cleanup_overlay(struct drm_device *dev)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_private_t *dev_priv = dev->dev_private;
- if (dev_priv->overlay) {
- /* The bo's should be free'd by the generic code already.
- * Furthermore modesetting teardown happens beforehand so the
- * hardware should be off already */
- BUG_ON(dev_priv->overlay->active);
+ if (!dev_priv->overlay)
+ return;
- kfree(dev_priv->overlay);
- }
+ /* The bo's should be free'd by the generic code already.
+ * Furthermore modesetting teardown happens beforehand so the
+ * hardware should be off already */
+ BUG_ON(dev_priv->overlay->active);
+
+ drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base);
+ kfree(dev_priv->overlay);
}
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
struct intel_overlay_error_state {
struct overlay_registers regs;
unsigned long base;
@@ -1427,6 +1464,29 @@ struct intel_overlay_error_state {
u32 isr;
};
+static struct overlay_registers *
+intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
+{
+ drm_i915_private_t *dev_priv = overlay->dev->dev_private;
+ struct overlay_registers *regs;
+
+ if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+ regs = overlay->reg_bo->phys_obj->handle->vaddr;
+ else
+ regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
+ overlay->reg_bo->gtt_offset);
+
+ return regs;
+}
+
+static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,
+ struct overlay_registers *regs)
+{
+ if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+ io_mapping_unmap_atomic(regs);
+}
+
+
struct intel_overlay_error_state *
intel_overlay_capture_error_state(struct drm_device *dev)
{
@@ -1444,17 +1504,17 @@ intel_overlay_capture_error_state(struct drm_device *dev)
error->dovsta = I915_READ(DOVSTA);
error->isr = I915_READ(ISR);
- if (OVERLAY_NONPHYSICAL(overlay->dev))
- error->base = (long) overlay->reg_bo->gtt_offset;
- else
+ if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr;
+ else
+ error->base = (long) overlay->reg_bo->gtt_offset;
regs = intel_overlay_map_regs_atomic(overlay);
if (!regs)
goto err;
memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
- intel_overlay_unmap_regs_atomic(overlay);
+ intel_overlay_unmap_regs_atomic(overlay, regs);
return error;
@@ -1515,3 +1575,4 @@ intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_s
P(UVSCALEV);
#undef P
}
+#endif
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index e7f5299d9d57..92ff8f385278 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -30,6 +30,8 @@
#include "intel_drv.h"
+#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
+
void
intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
struct drm_display_mode *adjusted_mode)
@@ -109,3 +111,110 @@ done:
dev_priv->pch_pf_pos = (x << 16) | y;
dev_priv->pch_pf_size = (width << 16) | height;
}
+
+static int is_backlight_combination_mode(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (INTEL_INFO(dev)->gen >= 4)
+ return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
+
+ if (IS_GEN2(dev))
+ return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
+
+ return 0;
+}
+
+u32 intel_panel_get_max_backlight(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 max;
+
+ if (HAS_PCH_SPLIT(dev)) {
+ max = I915_READ(BLC_PWM_PCH_CTL2) >> 16;
+ } else {
+ max = I915_READ(BLC_PWM_CTL);
+ if (IS_PINEVIEW(dev)) {
+ max >>= 17;
+ } else {
+ max >>= 16;
+ if (INTEL_INFO(dev)->gen < 4)
+ max &= ~1;
+ }
+
+ if (is_backlight_combination_mode(dev))
+ max *= 0xff;
+ }
+
+ if (max == 0) {
+ /* XXX add code here to query mode clock or hardware clock
+ * and program max PWM appropriately.
+ */
+ DRM_ERROR("fixme: max PWM is zero.\n");
+ max = 1;
+ }
+
+ DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
+ return max;
+}
+
+u32 intel_panel_get_backlight(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 val;
+
+ if (HAS_PCH_SPLIT(dev)) {
+ val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+ } else {
+ val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+ if (IS_PINEVIEW(dev))
+ val >>= 1;
+
+ if (is_backlight_combination_mode(dev)){
+ u8 lbpc;
+
+ val &= ~1;
+ pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
+ val *= lbpc;
+ val >>= 1;
+ }
+ }
+
+ DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
+ return val;
+}
+
+static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+ I915_WRITE(BLC_PWM_CPU_CTL, val | level);
+}
+
+void intel_panel_set_backlight(struct drm_device *dev, u32 level)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 tmp;
+
+ DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
+
+ if (HAS_PCH_SPLIT(dev))
+ return intel_pch_panel_set_backlight(dev, level);
+
+ if (is_backlight_combination_mode(dev)){
+ u32 max = intel_panel_get_max_backlight(dev);
+ u8 lpbc;
+
+ lpbc = level * 0xfe / max + 1;
+ level /= lpbc;
+ pci_write_config_byte(dev->pdev, PCI_LBPC, lpbc);
+ }
+
+ tmp = I915_READ(BLC_PWM_CTL);
+ if (IS_PINEVIEW(dev)) {
+ tmp &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
+ level <<= 1;
+ } else
+ tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
+ I915_WRITE(BLC_PWM_CTL, tmp | level);
+}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index cb3508f78bc3..09f2dc353ae2 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -32,6 +32,7 @@
#include "i915_drv.h"
#include "i915_drm.h"
#include "i915_trace.h"
+#include "intel_drv.h"
static u32 i915_gem_get_seqno(struct drm_device *dev)
{
@@ -49,9 +50,9 @@ static u32 i915_gem_get_seqno(struct drm_device *dev)
static void
render_ring_flush(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- u32 invalidate_domains,
- u32 flush_domains)
+ struct intel_ring_buffer *ring,
+ u32 invalidate_domains,
+ u32 flush_domains)
{
drm_i915_private_t *dev_priv = dev->dev_private;
u32 cmd;
@@ -97,7 +98,7 @@ render_ring_flush(struct drm_device *dev,
if ((invalidate_domains|flush_domains) &
I915_GEM_DOMAIN_RENDER)
cmd &= ~MI_NO_WRITE_FLUSH;
- if (!IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen < 4) {
/*
* On the 965, the sampler cache always gets flushed
* and this bit is reserved.
@@ -118,38 +119,26 @@ render_ring_flush(struct drm_device *dev,
}
}
-static unsigned int render_ring_get_head(struct drm_device *dev,
- struct intel_ring_buffer *ring)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- return I915_READ(PRB0_HEAD) & HEAD_ADDR;
-}
-
-static unsigned int render_ring_get_tail(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+static void ring_write_tail(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ u32 value)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- return I915_READ(PRB0_TAIL) & TAIL_ADDR;
+ I915_WRITE_TAIL(ring, value);
}
-static unsigned int render_ring_get_active_head(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+u32 intel_ring_get_active_head(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
+ u32 acthd_reg = INTEL_INFO(dev)->gen >= 4 ?
+ RING_ACTHD(ring->mmio_base) : ACTHD;
return I915_READ(acthd_reg);
}
-static void render_ring_advance_ring(struct drm_device *dev,
- struct intel_ring_buffer *ring)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- I915_WRITE(PRB0_TAIL, ring->tail);
-}
-
static int init_ring_common(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ struct intel_ring_buffer *ring)
{
u32 head;
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -157,57 +146,57 @@ static int init_ring_common(struct drm_device *dev,
obj_priv = to_intel_bo(ring->gem_object);
/* Stop the ring if it's running. */
- I915_WRITE(ring->regs.ctl, 0);
- I915_WRITE(ring->regs.head, 0);
- I915_WRITE(ring->regs.tail, 0);
+ I915_WRITE_CTL(ring, 0);
+ I915_WRITE_HEAD(ring, 0);
+ ring->write_tail(dev, ring, 0);
/* Initialize the ring. */
- I915_WRITE(ring->regs.start, obj_priv->gtt_offset);
- head = ring->get_head(dev, ring);
+ I915_WRITE_START(ring, obj_priv->gtt_offset);
+ head = I915_READ_HEAD(ring) & HEAD_ADDR;
/* G45 ring initialization fails to reset head to zero */
if (head != 0) {
DRM_ERROR("%s head not reset to zero "
"ctl %08x head %08x tail %08x start %08x\n",
ring->name,
- I915_READ(ring->regs.ctl),
- I915_READ(ring->regs.head),
- I915_READ(ring->regs.tail),
- I915_READ(ring->regs.start));
+ I915_READ_CTL(ring),
+ I915_READ_HEAD(ring),
+ I915_READ_TAIL(ring),
+ I915_READ_START(ring));
- I915_WRITE(ring->regs.head, 0);
+ I915_WRITE_HEAD(ring, 0);
DRM_ERROR("%s head forced to zero "
"ctl %08x head %08x tail %08x start %08x\n",
ring->name,
- I915_READ(ring->regs.ctl),
- I915_READ(ring->regs.head),
- I915_READ(ring->regs.tail),
- I915_READ(ring->regs.start));
+ I915_READ_CTL(ring),
+ I915_READ_HEAD(ring),
+ I915_READ_TAIL(ring),
+ I915_READ_START(ring));
}
- I915_WRITE(ring->regs.ctl,
+ I915_WRITE_CTL(ring,
((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES)
| RING_NO_REPORT | RING_VALID);
- head = I915_READ(ring->regs.head) & HEAD_ADDR;
+ head = I915_READ_HEAD(ring) & HEAD_ADDR;
/* If the head is still not zero, the ring is dead */
if (head != 0) {
DRM_ERROR("%s initialization failed "
"ctl %08x head %08x tail %08x start %08x\n",
ring->name,
- I915_READ(ring->regs.ctl),
- I915_READ(ring->regs.head),
- I915_READ(ring->regs.tail),
- I915_READ(ring->regs.start));
+ I915_READ_CTL(ring),
+ I915_READ_HEAD(ring),
+ I915_READ_TAIL(ring),
+ I915_READ_START(ring));
return -EIO;
}
if (!drm_core_check_feature(dev, DRIVER_MODESET))
i915_kernel_lost_context(dev);
else {
- ring->head = ring->get_head(dev, ring);
- ring->tail = ring->get_tail(dev, ring);
+ ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+ ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->size;
@@ -216,13 +205,13 @@ static int init_ring_common(struct drm_device *dev,
}
static int init_render_ring(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int ret = init_ring_common(dev, ring);
int mode;
- if (IS_I9XX(dev) && !IS_GEN3(dev)) {
+ if (INTEL_INFO(dev)->gen > 3) {
mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
if (IS_GEN6(dev))
mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;
@@ -250,9 +239,8 @@ do { \
*/
static u32
render_ring_add_request(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- struct drm_file *file_priv,
- u32 flush_domains)
+ struct intel_ring_buffer *ring,
+ u32 flush_domains)
{
drm_i915_private_t *dev_priv = dev->dev_private;
u32 seqno;
@@ -315,8 +303,8 @@ render_ring_add_request(struct drm_device *dev,
}
static u32
-render_ring_get_gem_seqno(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+render_ring_get_seqno(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
if (HAS_PIPE_CONTROL(dev))
@@ -327,7 +315,7 @@ render_ring_get_gem_seqno(struct drm_device *dev,
static void
render_ring_get_user_irq(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
@@ -344,7 +332,7 @@ render_ring_get_user_irq(struct drm_device *dev,
static void
render_ring_put_user_irq(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
@@ -360,21 +348,23 @@ render_ring_put_user_irq(struct drm_device *dev,
spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
}
-static void render_setup_status_page(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+void intel_ring_setup_status_page(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = dev->dev_private;
if (IS_GEN6(dev)) {
- I915_WRITE(HWS_PGA_GEN6, ring->status_page.gfx_addr);
- I915_READ(HWS_PGA_GEN6); /* posting read */
+ I915_WRITE(RING_HWS_PGA_GEN6(ring->mmio_base),
+ ring->status_page.gfx_addr);
+ I915_READ(RING_HWS_PGA_GEN6(ring->mmio_base)); /* posting read */
} else {
- I915_WRITE(HWS_PGA, ring->status_page.gfx_addr);
- I915_READ(HWS_PGA); /* posting read */
+ I915_WRITE(RING_HWS_PGA(ring->mmio_base),
+ ring->status_page.gfx_addr);
+ I915_READ(RING_HWS_PGA(ring->mmio_base)); /* posting read */
}
}
-void
+static void
bsd_ring_flush(struct drm_device *dev,
struct intel_ring_buffer *ring,
u32 invalidate_domains,
@@ -386,45 +376,16 @@ bsd_ring_flush(struct drm_device *dev,
intel_ring_advance(dev, ring);
}
-static inline unsigned int bsd_ring_get_head(struct drm_device *dev,
- struct intel_ring_buffer *ring)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- return I915_READ(BSD_RING_HEAD) & HEAD_ADDR;
-}
-
-static inline unsigned int bsd_ring_get_tail(struct drm_device *dev,
- struct intel_ring_buffer *ring)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- return I915_READ(BSD_RING_TAIL) & TAIL_ADDR;
-}
-
-static inline unsigned int bsd_ring_get_active_head(struct drm_device *dev,
- struct intel_ring_buffer *ring)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- return I915_READ(BSD_RING_ACTHD);
-}
-
-static inline void bsd_ring_advance_ring(struct drm_device *dev,
- struct intel_ring_buffer *ring)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- I915_WRITE(BSD_RING_TAIL, ring->tail);
-}
-
static int init_bsd_ring(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ struct intel_ring_buffer *ring)
{
return init_ring_common(dev, ring);
}
static u32
-bsd_ring_add_request(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- struct drm_file *file_priv,
- u32 flush_domains)
+ring_add_request(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ u32 flush_domains)
{
u32 seqno;
@@ -443,40 +404,32 @@ bsd_ring_add_request(struct drm_device *dev,
return seqno;
}
-static void bsd_setup_status_page(struct drm_device *dev,
- struct intel_ring_buffer *ring)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- I915_WRITE(BSD_HWS_PGA, ring->status_page.gfx_addr);
- I915_READ(BSD_HWS_PGA);
-}
-
static void
bsd_ring_get_user_irq(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ struct intel_ring_buffer *ring)
{
/* do nothing */
}
static void
bsd_ring_put_user_irq(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ struct intel_ring_buffer *ring)
{
/* do nothing */
}
static u32
-bsd_ring_get_gem_seqno(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ring_status_page_get_seqno(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
{
return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
}
static int
-bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- struct drm_i915_gem_execbuffer2 *exec,
- struct drm_clip_rect *cliprects,
- uint64_t exec_offset)
+ring_dispatch_gem_execbuffer(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ struct drm_i915_gem_execbuffer2 *exec,
+ struct drm_clip_rect *cliprects,
+ uint64_t exec_offset)
{
uint32_t exec_start;
exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
@@ -488,13 +441,12 @@ bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev,
return 0;
}
-
static int
render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- struct drm_i915_gem_execbuffer2 *exec,
- struct drm_clip_rect *cliprects,
- uint64_t exec_offset)
+ struct intel_ring_buffer *ring,
+ struct drm_i915_gem_execbuffer2 *exec,
+ struct drm_clip_rect *cliprects,
+ uint64_t exec_offset)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int nbox = exec->num_cliprects;
@@ -523,8 +475,8 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
intel_ring_emit(dev, ring, exec_start + exec_len - 4);
intel_ring_emit(dev, ring, 0);
} else {
- intel_ring_begin(dev, ring, 4);
- if (IS_I965G(dev)) {
+ intel_ring_begin(dev, ring, 2);
+ if (INTEL_INFO(dev)->gen >= 4) {
intel_ring_emit(dev, ring,
MI_BATCH_BUFFER_START | (2 << 6)
| MI_BATCH_NON_SECURE_I965);
@@ -539,7 +491,7 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
intel_ring_advance(dev, ring);
}
- if (IS_G4X(dev) || IS_IRONLAKE(dev)) {
+ if (IS_G4X(dev) || IS_GEN5(dev)) {
intel_ring_begin(dev, ring, 2);
intel_ring_emit(dev, ring, MI_FLUSH |
MI_NO_WRITE_FLUSH |
@@ -553,7 +505,7 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
}
static void cleanup_status_page(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_gem_object *obj;
@@ -573,7 +525,7 @@ static void cleanup_status_page(struct drm_device *dev,
}
static int init_status_page(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_gem_object *obj;
@@ -603,7 +555,7 @@ static int init_status_page(struct drm_device *dev,
ring->status_page.obj = obj;
memset(ring->status_page.page_addr, 0, PAGE_SIZE);
- ring->setup_status_page(dev, ring);
+ intel_ring_setup_status_page(dev, ring);
DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
ring->name, ring->status_page.gfx_addr);
@@ -617,15 +569,18 @@ err:
return ret;
}
-
int intel_init_ring_buffer(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ struct intel_ring_buffer *ring)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv;
struct drm_gem_object *obj;
int ret;
ring->dev = dev;
+ INIT_LIST_HEAD(&ring->active_list);
+ INIT_LIST_HEAD(&ring->request_list);
+ INIT_LIST_HEAD(&ring->gpu_write_list);
if (I915_NEED_GFX_HWS(dev)) {
ret = init_status_page(dev, ring);
@@ -642,7 +597,7 @@ int intel_init_ring_buffer(struct drm_device *dev,
ring->gem_object = obj;
- ret = i915_gem_object_pin(obj, ring->alignment);
+ ret = i915_gem_object_pin(obj, PAGE_SIZE);
if (ret)
goto err_unref;
@@ -668,14 +623,12 @@ int intel_init_ring_buffer(struct drm_device *dev,
if (!drm_core_check_feature(dev, DRIVER_MODESET))
i915_kernel_lost_context(dev);
else {
- ring->head = ring->get_head(dev, ring);
- ring->tail = ring->get_tail(dev, ring);
+ ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+ ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->size;
}
- INIT_LIST_HEAD(&ring->active_list);
- INIT_LIST_HEAD(&ring->request_list);
return ret;
err_unmap:
@@ -691,7 +644,7 @@ err_hws:
}
void intel_cleanup_ring_buffer(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ struct intel_ring_buffer *ring)
{
if (ring->gem_object == NULL)
return;
@@ -704,8 +657,8 @@ void intel_cleanup_ring_buffer(struct drm_device *dev,
cleanup_status_page(dev, ring);
}
-int intel_wrap_ring_buffer(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+static int intel_wrap_ring_buffer(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
{
unsigned int *virt;
int rem;
@@ -731,14 +684,15 @@ int intel_wrap_ring_buffer(struct drm_device *dev,
}
int intel_wait_ring_buffer(struct drm_device *dev,
- struct intel_ring_buffer *ring, int n)
+ struct intel_ring_buffer *ring, int n)
{
unsigned long end;
+ drm_i915_private_t *dev_priv = dev->dev_private;
trace_i915_ring_wait_begin (dev);
end = jiffies + 3 * HZ;
do {
- ring->head = ring->get_head(dev, ring);
+ ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->size;
@@ -753,14 +707,15 @@ int intel_wait_ring_buffer(struct drm_device *dev,
master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
}
- yield();
+ msleep(1);
} while (!time_after(jiffies, end));
trace_i915_ring_wait_end (dev);
return -EBUSY;
}
void intel_ring_begin(struct drm_device *dev,
- struct intel_ring_buffer *ring, int num_dwords)
+ struct intel_ring_buffer *ring,
+ int num_dwords)
{
int n = 4*num_dwords;
if (unlikely(ring->tail + n > ring->size))
@@ -772,97 +727,181 @@ void intel_ring_begin(struct drm_device *dev,
}
void intel_ring_advance(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+ struct intel_ring_buffer *ring)
{
ring->tail &= ring->size - 1;
- ring->advance_ring(dev, ring);
-}
-
-void intel_fill_struct(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- void *data,
- unsigned int len)
-{
- unsigned int *virt = ring->virtual_start + ring->tail;
- BUG_ON((len&~(4-1)) != 0);
- intel_ring_begin(dev, ring, len/4);
- memcpy(virt, data, len);
- ring->tail += len;
- ring->tail &= ring->size - 1;
- ring->space -= len;
- intel_ring_advance(dev, ring);
+ ring->write_tail(dev, ring, ring->tail);
}
-struct intel_ring_buffer render_ring = {
+static const struct intel_ring_buffer render_ring = {
.name = "render ring",
- .regs = {
- .ctl = PRB0_CTL,
- .head = PRB0_HEAD,
- .tail = PRB0_TAIL,
- .start = PRB0_START
- },
- .ring_flag = I915_EXEC_RENDER,
+ .id = RING_RENDER,
+ .mmio_base = RENDER_RING_BASE,
.size = 32 * PAGE_SIZE,
- .alignment = PAGE_SIZE,
- .virtual_start = NULL,
- .dev = NULL,
- .gem_object = NULL,
- .head = 0,
- .tail = 0,
- .space = 0,
- .user_irq_refcount = 0,
- .irq_gem_seqno = 0,
- .waiting_gem_seqno = 0,
- .setup_status_page = render_setup_status_page,
.init = init_render_ring,
- .get_head = render_ring_get_head,
- .get_tail = render_ring_get_tail,
- .get_active_head = render_ring_get_active_head,
- .advance_ring = render_ring_advance_ring,
+ .write_tail = ring_write_tail,
.flush = render_ring_flush,
.add_request = render_ring_add_request,
- .get_gem_seqno = render_ring_get_gem_seqno,
+ .get_seqno = render_ring_get_seqno,
.user_irq_get = render_ring_get_user_irq,
.user_irq_put = render_ring_put_user_irq,
.dispatch_gem_execbuffer = render_ring_dispatch_gem_execbuffer,
- .status_page = {NULL, 0, NULL},
- .map = {0,}
};
/* ring buffer for bit-stream decoder */
-struct intel_ring_buffer bsd_ring = {
+static const struct intel_ring_buffer bsd_ring = {
.name = "bsd ring",
- .regs = {
- .ctl = BSD_RING_CTL,
- .head = BSD_RING_HEAD,
- .tail = BSD_RING_TAIL,
- .start = BSD_RING_START
- },
- .ring_flag = I915_EXEC_BSD,
+ .id = RING_BSD,
+ .mmio_base = BSD_RING_BASE,
.size = 32 * PAGE_SIZE,
- .alignment = PAGE_SIZE,
- .virtual_start = NULL,
- .dev = NULL,
- .gem_object = NULL,
- .head = 0,
- .tail = 0,
- .space = 0,
- .user_irq_refcount = 0,
- .irq_gem_seqno = 0,
- .waiting_gem_seqno = 0,
- .setup_status_page = bsd_setup_status_page,
.init = init_bsd_ring,
- .get_head = bsd_ring_get_head,
- .get_tail = bsd_ring_get_tail,
- .get_active_head = bsd_ring_get_active_head,
- .advance_ring = bsd_ring_advance_ring,
+ .write_tail = ring_write_tail,
.flush = bsd_ring_flush,
- .add_request = bsd_ring_add_request,
- .get_gem_seqno = bsd_ring_get_gem_seqno,
+ .add_request = ring_add_request,
+ .get_seqno = ring_status_page_get_seqno,
.user_irq_get = bsd_ring_get_user_irq,
.user_irq_put = bsd_ring_put_user_irq,
- .dispatch_gem_execbuffer = bsd_ring_dispatch_gem_execbuffer,
- .status_page = {NULL, 0, NULL},
- .map = {0,}
+ .dispatch_gem_execbuffer = ring_dispatch_gem_execbuffer,
};
+
+
+static void gen6_bsd_ring_write_tail(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ u32 value)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ /* Every tail move must follow the sequence below */
+ I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
+ GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK |
+ GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE);
+ I915_WRITE(GEN6_BSD_RNCID, 0x0);
+
+ if (wait_for((I915_READ(GEN6_BSD_SLEEP_PSMI_CONTROL) &
+ GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR) == 0,
+ 50))
+ DRM_ERROR("timed out waiting for IDLE Indicator\n");
+
+ I915_WRITE_TAIL(ring, value);
+ I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
+ GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK |
+ GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE);
+}
+
+static void gen6_ring_flush(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ u32 invalidate_domains,
+ u32 flush_domains)
+{
+ intel_ring_begin(dev, ring, 4);
+ intel_ring_emit(dev, ring, MI_FLUSH_DW);
+ intel_ring_emit(dev, ring, 0);
+ intel_ring_emit(dev, ring, 0);
+ intel_ring_emit(dev, ring, 0);
+ intel_ring_advance(dev, ring);
+}
+
+static int
+gen6_ring_dispatch_gem_execbuffer(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ struct drm_i915_gem_execbuffer2 *exec,
+ struct drm_clip_rect *cliprects,
+ uint64_t exec_offset)
+{
+ uint32_t exec_start;
+
+ exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
+
+ intel_ring_begin(dev, ring, 2);
+ intel_ring_emit(dev, ring,
+ MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965);
+ /* bit0-7 is the length on GEN6+ */
+ intel_ring_emit(dev, ring, exec_start);
+ intel_ring_advance(dev, ring);
+
+ return 0;
+}
+
+/* ring buffer for Video Codec for Gen6+ */
+static const struct intel_ring_buffer gen6_bsd_ring = {
+ .name = "gen6 bsd ring",
+ .id = RING_BSD,
+ .mmio_base = GEN6_BSD_RING_BASE,
+ .size = 32 * PAGE_SIZE,
+ .init = init_bsd_ring,
+ .write_tail = gen6_bsd_ring_write_tail,
+ .flush = gen6_ring_flush,
+ .add_request = ring_add_request,
+ .get_seqno = ring_status_page_get_seqno,
+ .user_irq_get = bsd_ring_get_user_irq,
+ .user_irq_put = bsd_ring_put_user_irq,
+ .dispatch_gem_execbuffer = gen6_ring_dispatch_gem_execbuffer,
+};
+
+/* Blitter support (SandyBridge+) */
+
+static void
+blt_ring_get_user_irq(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ /* do nothing */
+}
+static void
+blt_ring_put_user_irq(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ /* do nothing */
+}
+
+static const struct intel_ring_buffer gen6_blt_ring = {
+ .name = "blt ring",
+ .id = RING_BLT,
+ .mmio_base = BLT_RING_BASE,
+ .size = 32 * PAGE_SIZE,
+ .init = init_ring_common,
+ .write_tail = ring_write_tail,
+ .flush = gen6_ring_flush,
+ .add_request = ring_add_request,
+ .get_seqno = ring_status_page_get_seqno,
+ .user_irq_get = blt_ring_get_user_irq,
+ .user_irq_put = blt_ring_put_user_irq,
+ .dispatch_gem_execbuffer = gen6_ring_dispatch_gem_execbuffer,
+};
+
+int intel_init_render_ring_buffer(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ dev_priv->render_ring = render_ring;
+
+ if (!I915_NEED_GFX_HWS(dev)) {
+ dev_priv->render_ring.status_page.page_addr
+ = dev_priv->status_page_dmah->vaddr;
+ memset(dev_priv->render_ring.status_page.page_addr,
+ 0, PAGE_SIZE);
+ }
+
+ return intel_init_ring_buffer(dev, &dev_priv->render_ring);
+}
+
+int intel_init_bsd_ring_buffer(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ if (IS_GEN6(dev))
+ dev_priv->bsd_ring = gen6_bsd_ring;
+ else
+ dev_priv->bsd_ring = bsd_ring;
+
+ return intel_init_ring_buffer(dev, &dev_priv->bsd_ring);
+}
+
+int intel_init_blt_ring_buffer(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ dev_priv->blt_ring = gen6_blt_ring;
+
+ return intel_init_ring_buffer(dev, &dev_priv->blt_ring);
+}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 525e7d3edda8..a05aff0e5764 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -7,25 +7,32 @@ struct intel_hw_status_page {
struct drm_gem_object *obj;
};
+#define I915_READ_TAIL(ring) I915_READ(RING_TAIL(ring->mmio_base))
+#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL(ring->mmio_base), val)
+#define I915_READ_START(ring) I915_READ(RING_START(ring->mmio_base))
+#define I915_WRITE_START(ring, val) I915_WRITE(RING_START(ring->mmio_base), val)
+#define I915_READ_HEAD(ring) I915_READ(RING_HEAD(ring->mmio_base))
+#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD(ring->mmio_base), val)
+#define I915_READ_CTL(ring) I915_READ(RING_CTL(ring->mmio_base))
+#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL(ring->mmio_base), val)
+
struct drm_i915_gem_execbuffer2;
struct intel_ring_buffer {
const char *name;
- struct ring_regs {
- u32 ctl;
- u32 head;
- u32 tail;
- u32 start;
- } regs;
- unsigned int ring_flag;
+ enum intel_ring_id {
+ RING_RENDER = 0x1,
+ RING_BSD = 0x2,
+ RING_BLT = 0x4,
+ } id;
+ u32 mmio_base;
unsigned long size;
- unsigned int alignment;
void *virtual_start;
struct drm_device *dev;
struct drm_gem_object *gem_object;
unsigned int head;
unsigned int tail;
- unsigned int space;
+ int space;
struct intel_hw_status_page status_page;
u32 irq_gem_seqno; /* last seq seem at irq time */
@@ -35,30 +42,22 @@ struct intel_ring_buffer {
struct intel_ring_buffer *ring);
void (*user_irq_put)(struct drm_device *dev,
struct intel_ring_buffer *ring);
- void (*setup_status_page)(struct drm_device *dev,
- struct intel_ring_buffer *ring);
int (*init)(struct drm_device *dev,
struct intel_ring_buffer *ring);
- unsigned int (*get_head)(struct drm_device *dev,
- struct intel_ring_buffer *ring);
- unsigned int (*get_tail)(struct drm_device *dev,
- struct intel_ring_buffer *ring);
- unsigned int (*get_active_head)(struct drm_device *dev,
- struct intel_ring_buffer *ring);
- void (*advance_ring)(struct drm_device *dev,
- struct intel_ring_buffer *ring);
+ void (*write_tail)(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ u32 value);
void (*flush)(struct drm_device *dev,
struct intel_ring_buffer *ring,
u32 invalidate_domains,
u32 flush_domains);
u32 (*add_request)(struct drm_device *dev,
struct intel_ring_buffer *ring,
- struct drm_file *file_priv,
u32 flush_domains);
- u32 (*get_gem_seqno)(struct drm_device *dev,
- struct intel_ring_buffer *ring);
+ u32 (*get_seqno)(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
int (*dispatch_gem_execbuffer)(struct drm_device *dev,
struct intel_ring_buffer *ring,
struct drm_i915_gem_execbuffer2 *exec,
@@ -83,6 +82,20 @@ struct intel_ring_buffer {
*/
struct list_head request_list;
+ /**
+ * List of objects currently pending a GPU write flush.
+ *
+ * All elements on this list will belong to either the
+ * active_list or flushing_list, last_rendering_seqno can
+ * be used to differentiate between the two elements.
+ */
+ struct list_head gpu_write_list;
+
+ /**
+ * Do we have some not yet emitted requests outstanding?
+ */
+ bool outstanding_lazy_request;
+
wait_queue_head_t irq_queue;
drm_local_map_t map;
};
@@ -96,15 +109,13 @@ intel_read_status_page(struct intel_ring_buffer *ring,
}
int intel_init_ring_buffer(struct drm_device *dev,
- struct intel_ring_buffer *ring);
+ struct intel_ring_buffer *ring);
void intel_cleanup_ring_buffer(struct drm_device *dev,
- struct intel_ring_buffer *ring);
+ struct intel_ring_buffer *ring);
int intel_wait_ring_buffer(struct drm_device *dev,
- struct intel_ring_buffer *ring, int n);
-int intel_wrap_ring_buffer(struct drm_device *dev,
- struct intel_ring_buffer *ring);
+ struct intel_ring_buffer *ring, int n);
void intel_ring_begin(struct drm_device *dev,
- struct intel_ring_buffer *ring, int n);
+ struct intel_ring_buffer *ring, int n);
static inline void intel_ring_emit(struct drm_device *dev,
struct intel_ring_buffer *ring,
@@ -115,17 +126,19 @@ static inline void intel_ring_emit(struct drm_device *dev,
ring->tail += 4;
}
-void intel_fill_struct(struct drm_device *dev,
- struct intel_ring_buffer *ring,
- void *data,
- unsigned int len);
void intel_ring_advance(struct drm_device *dev,
struct intel_ring_buffer *ring);
u32 intel_ring_get_seqno(struct drm_device *dev,
struct intel_ring_buffer *ring);
-extern struct intel_ring_buffer render_ring;
-extern struct intel_ring_buffer bsd_ring;
+int intel_init_render_ring_buffer(struct drm_device *dev);
+int intel_init_bsd_ring_buffer(struct drm_device *dev);
+int intel_init_blt_ring_buffer(struct drm_device *dev);
+
+u32 intel_ring_get_active_head(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
+void intel_ring_setup_status_page(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
#endif /* _INTEL_RINGBUFFER_H_ */
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index ee73e428a84a..de158b76bcd5 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -65,8 +65,11 @@ static const char *tv_format_names[] = {
struct intel_sdvo {
struct intel_encoder base;
+ struct i2c_adapter *i2c;
u8 slave_addr;
+ struct i2c_adapter ddc;
+
/* Register for the SDVO device: SDVOB or SDVOC */
int sdvo_reg;
@@ -104,34 +107,24 @@ struct intel_sdvo {
* This is set if we treat the device as HDMI, instead of DVI.
*/
bool is_hdmi;
+ bool has_audio;
/**
- * This is set if we detect output of sdvo device as LVDS.
+ * This is set if we detect output of sdvo device as LVDS and
+ * have a valid fixed mode to use with the panel.
*/
bool is_lvds;
/**
- * This is sdvo flags for input timing.
- */
- uint8_t sdvo_flags;
-
- /**
* This is sdvo fixed pannel mode pointer
*/
struct drm_display_mode *sdvo_lvds_fixed_mode;
- /*
- * supported encoding mode, used to determine whether HDMI is
- * supported
- */
- struct intel_sdvo_encode encode;
-
/* DDC bus used by this SDVO encoder */
uint8_t ddc_bus;
- /* Mac mini hack -- use the same DDC as the analog connector */
- struct i2c_adapter *analog_ddc_bus;
-
+ /* Input timings for adjusted_mode */
+ struct intel_sdvo_dtd input_dtd;
};
struct intel_sdvo_connector {
@@ -140,11 +133,15 @@ struct intel_sdvo_connector {
/* Mark the type of connector */
uint16_t output_flag;
+ int force_audio;
+
/* This contains all current supported TV format */
u8 tv_format_supported[TV_FORMAT_NUM];
int format_supported_num;
struct drm_property *tv_format;
+ struct drm_property *force_audio_property;
+
/* add the property for the SDVO-TV */
struct drm_property *left;
struct drm_property *right;
@@ -186,9 +183,15 @@ struct intel_sdvo_connector {
u32 cur_dot_crawl, max_dot_crawl;
};
-static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder)
+static struct intel_sdvo *to_intel_sdvo(struct drm_encoder *encoder)
+{
+ return container_of(encoder, struct intel_sdvo, base.base);
+}
+
+static struct intel_sdvo *intel_attached_sdvo(struct drm_connector *connector)
{
- return container_of(enc_to_intel_encoder(encoder), struct intel_sdvo, base);
+ return container_of(intel_attached_encoder(connector),
+ struct intel_sdvo, base);
}
static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector *connector)
@@ -213,7 +216,7 @@ intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
*/
static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
{
- struct drm_device *dev = intel_sdvo->base.enc.dev;
+ struct drm_device *dev = intel_sdvo->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 bval = val, cval = val;
int i;
@@ -245,49 +248,29 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)
{
- u8 out_buf[2] = { addr, 0 };
- u8 buf[2];
struct i2c_msg msgs[] = {
{
- .addr = intel_sdvo->slave_addr >> 1,
+ .addr = intel_sdvo->slave_addr,
.flags = 0,
.len = 1,
- .buf = out_buf,
+ .buf = &addr,
},
{
- .addr = intel_sdvo->slave_addr >> 1,
+ .addr = intel_sdvo->slave_addr,
.flags = I2C_M_RD,
.len = 1,
- .buf = buf,
+ .buf = ch,
}
};
int ret;
- if ((ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 2)) == 2)
- {
- *ch = buf[0];
+ if ((ret = i2c_transfer(intel_sdvo->i2c, msgs, 2)) == 2)
return true;
- }
DRM_DEBUG_KMS("i2c transfer returned %d\n", ret);
return false;
}
-static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, u8 ch)
-{
- u8 out_buf[2] = { addr, ch };
- struct i2c_msg msgs[] = {
- {
- .addr = intel_sdvo->slave_addr >> 1,
- .flags = 0,
- .len = 2,
- .buf = out_buf,
- }
- };
-
- return i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 1) == 1;
-}
-
#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
/** Mapping of command numbers to names, for debug output */
static const struct _sdvo_cmd_name {
@@ -432,22 +415,6 @@ static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,
DRM_LOG_KMS("\n");
}
-static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
- const void *args, int args_len)
-{
- int i;
-
- intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
-
- for (i = 0; i < args_len; i++) {
- if (!intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0 - i,
- ((u8*)args)[i]))
- return false;
- }
-
- return intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_OPCODE, cmd);
-}
-
static const char *cmd_status_names[] = {
"Power on",
"Success",
@@ -458,54 +425,115 @@ static const char *cmd_status_names[] = {
"Scaling not supported"
};
-static void intel_sdvo_debug_response(struct intel_sdvo *intel_sdvo,
- void *response, int response_len,
- u8 status)
+static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
+ const void *args, int args_len)
{
- int i;
+ u8 buf[args_len*2 + 2], status;
+ struct i2c_msg msgs[args_len + 3];
+ int i, ret;
- DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
- for (i = 0; i < response_len; i++)
- DRM_LOG_KMS("%02X ", ((u8 *)response)[i]);
- for (; i < 8; i++)
- DRM_LOG_KMS(" ");
- if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
- DRM_LOG_KMS("(%s)", cmd_status_names[status]);
- else
- DRM_LOG_KMS("(??? %d)", status);
- DRM_LOG_KMS("\n");
+ intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
+
+ for (i = 0; i < args_len; i++) {
+ msgs[i].addr = intel_sdvo->slave_addr;
+ msgs[i].flags = 0;
+ msgs[i].len = 2;
+ msgs[i].buf = buf + 2 *i;
+ buf[2*i + 0] = SDVO_I2C_ARG_0 - i;
+ buf[2*i + 1] = ((u8*)args)[i];
+ }
+ msgs[i].addr = intel_sdvo->slave_addr;
+ msgs[i].flags = 0;
+ msgs[i].len = 2;
+ msgs[i].buf = buf + 2*i;
+ buf[2*i + 0] = SDVO_I2C_OPCODE;
+ buf[2*i + 1] = cmd;
+
+ /* the following two are to read the response */
+ status = SDVO_I2C_CMD_STATUS;
+ msgs[i+1].addr = intel_sdvo->slave_addr;
+ msgs[i+1].flags = 0;
+ msgs[i+1].len = 1;
+ msgs[i+1].buf = &status;
+
+ msgs[i+2].addr = intel_sdvo->slave_addr;
+ msgs[i+2].flags = I2C_M_RD;
+ msgs[i+2].len = 1;
+ msgs[i+2].buf = &status;
+
+ ret = i2c_transfer(intel_sdvo->i2c, msgs, i+3);
+ if (ret < 0) {
+ DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
+ return false;
+ }
+ if (ret != i+3) {
+ /* failure in I2C transfer */
+ DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3);
+ return false;
+ }
+
+ i = 3;
+ while (status == SDVO_CMD_STATUS_PENDING && i--) {
+ if (!intel_sdvo_read_byte(intel_sdvo,
+ SDVO_I2C_CMD_STATUS,
+ &status))
+ return false;
+ }
+ if (status != SDVO_CMD_STATUS_SUCCESS) {
+ DRM_DEBUG_KMS("command returns response %s [%d]\n",
+ status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP ? cmd_status_names[status] : "???",
+ status);
+ return false;
+ }
+
+ return true;
}
static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
void *response, int response_len)
{
- int i;
+ u8 retry = 5;
u8 status;
- u8 retry = 50;
-
- while (retry--) {
- /* Read the command response */
- for (i = 0; i < response_len; i++) {
- if (!intel_sdvo_read_byte(intel_sdvo,
- SDVO_I2C_RETURN_0 + i,
- &((u8 *)response)[i]))
- return false;
- }
+ int i;
- /* read the return status */
- if (!intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS,
+ /*
+ * The documentation states that all commands will be
+ * processed within 15µs, and that we need only poll
+ * the status byte a maximum of 3 times in order for the
+ * command to be complete.
+ *
+ * Check 5 times in case the hardware failed to read the docs.
+ */
+ do {
+ if (!intel_sdvo_read_byte(intel_sdvo,
+ SDVO_I2C_CMD_STATUS,
&status))
return false;
+ } while (status == SDVO_CMD_STATUS_PENDING && --retry);
- intel_sdvo_debug_response(intel_sdvo, response, response_len,
- status);
- if (status != SDVO_CMD_STATUS_PENDING)
- break;
+ DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
+ if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
+ DRM_LOG_KMS("(%s)", cmd_status_names[status]);
+ else
+ DRM_LOG_KMS("(??? %d)", status);
- mdelay(50);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ goto log_fail;
+
+ /* Read the command response */
+ for (i = 0; i < response_len; i++) {
+ if (!intel_sdvo_read_byte(intel_sdvo,
+ SDVO_I2C_RETURN_0 + i,
+ &((u8 *)response)[i]))
+ goto log_fail;
+ DRM_LOG_KMS(" %02X", ((u8 *)response)[i]);
}
+ DRM_LOG_KMS("\n");
+ return true;
- return status == SDVO_CMD_STATUS_SUCCESS;
+log_fail:
+ DRM_LOG_KMS("\n");
+ return false;
}
static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
@@ -518,71 +546,17 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
return 4;
}
-/**
- * Try to read the response after issuie the DDC switch command. But it
- * is noted that we must do the action of reading response and issuing DDC
- * switch command in one I2C transaction. Otherwise when we try to start
- * another I2C transaction after issuing the DDC bus switch, it will be
- * switched to the internal SDVO register.
- */
-static void intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
- u8 target)
+static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
+ u8 ddc_bus)
{
- u8 out_buf[2], cmd_buf[2], ret_value[2], ret;
- struct i2c_msg msgs[] = {
- {
- .addr = intel_sdvo->slave_addr >> 1,
- .flags = 0,
- .len = 2,
- .buf = out_buf,
- },
- /* the following two are to read the response */
- {
- .addr = intel_sdvo->slave_addr >> 1,
- .flags = 0,
- .len = 1,
- .buf = cmd_buf,
- },
- {
- .addr = intel_sdvo->slave_addr >> 1,
- .flags = I2C_M_RD,
- .len = 1,
- .buf = ret_value,
- },
- };
-
- intel_sdvo_debug_write(intel_sdvo, SDVO_CMD_SET_CONTROL_BUS_SWITCH,
- &target, 1);
- /* write the DDC switch command argument */
- intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0, target);
-
- out_buf[0] = SDVO_I2C_OPCODE;
- out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH;
- cmd_buf[0] = SDVO_I2C_CMD_STATUS;
- cmd_buf[1] = 0;
- ret_value[0] = 0;
- ret_value[1] = 0;
-
- ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 3);
- if (ret != 3) {
- /* failure in I2C transfer */
- DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
- return;
- }
- if (ret_value[0] != SDVO_CMD_STATUS_SUCCESS) {
- DRM_DEBUG_KMS("DDC switch command returns response %d\n",
- ret_value[0]);
- return;
- }
- return;
+ return intel_sdvo_write_cmd(intel_sdvo,
+ SDVO_CMD_SET_CONTROL_BUS_SWITCH,
+ &ddc_bus, 1);
}
static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len)
{
- if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len))
- return false;
-
- return intel_sdvo_read_response(intel_sdvo, NULL, 0);
+ return intel_sdvo_write_cmd(intel_sdvo, cmd, data, len);
}
static bool
@@ -819,17 +793,13 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
mode->flags |= DRM_MODE_FLAG_PVSYNC;
}
-static bool intel_sdvo_get_supp_encode(struct intel_sdvo *intel_sdvo,
- struct intel_sdvo_encode *encode)
+static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo)
{
- if (intel_sdvo_get_value(intel_sdvo,
- SDVO_CMD_GET_SUPP_ENCODE,
- encode, sizeof(*encode)))
- return true;
+ struct intel_sdvo_encode encode;
- /* non-support means DVI */
- memset(encode, 0, sizeof(*encode));
- return false;
+ return intel_sdvo_get_value(intel_sdvo,
+ SDVO_CMD_GET_SUPP_ENCODE,
+ &encode, sizeof(encode));
}
static bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo,
@@ -874,115 +844,33 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo)
}
#endif
-static bool intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo,
- int index,
- uint8_t *data, int8_t size, uint8_t tx_rate)
-{
- uint8_t set_buf_index[2];
-
- set_buf_index[0] = index;
- set_buf_index[1] = 0;
-
- if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX,
- set_buf_index, 2))
- return false;
-
- for (; size > 0; size -= 8) {
- if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 8))
- return false;
-
- data += 8;
- }
-
- return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1);
-}
-
-static uint8_t intel_sdvo_calc_hbuf_csum(uint8_t *data, uint8_t size)
-{
- uint8_t csum = 0;
- int i;
-
- for (i = 0; i < size; i++)
- csum += data[i];
-
- return 0x100 - csum;
-}
-
-#define DIP_TYPE_AVI 0x82
-#define DIP_VERSION_AVI 0x2
-#define DIP_LEN_AVI 13
-
-struct dip_infoframe {
- uint8_t type;
- uint8_t version;
- uint8_t len;
- uint8_t checksum;
- union {
- struct {
- /* Packet Byte #1 */
- uint8_t S:2;
- uint8_t B:2;
- uint8_t A:1;
- uint8_t Y:2;
- uint8_t rsvd1:1;
- /* Packet Byte #2 */
- uint8_t R:4;
- uint8_t M:2;
- uint8_t C:2;
- /* Packet Byte #3 */
- uint8_t SC:2;
- uint8_t Q:2;
- uint8_t EC:3;
- uint8_t ITC:1;
- /* Packet Byte #4 */
- uint8_t VIC:7;
- uint8_t rsvd2:1;
- /* Packet Byte #5 */
- uint8_t PR:4;
- uint8_t rsvd3:4;
- /* Packet Byte #6~13 */
- uint16_t top_bar_end;
- uint16_t bottom_bar_start;
- uint16_t left_bar_end;
- uint16_t right_bar_start;
- } avi;
- struct {
- /* Packet Byte #1 */
- uint8_t channel_count:3;
- uint8_t rsvd1:1;
- uint8_t coding_type:4;
- /* Packet Byte #2 */
- uint8_t sample_size:2; /* SS0, SS1 */
- uint8_t sample_frequency:3;
- uint8_t rsvd2:3;
- /* Packet Byte #3 */
- uint8_t coding_type_private:5;
- uint8_t rsvd3:3;
- /* Packet Byte #4 */
- uint8_t channel_allocation;
- /* Packet Byte #5 */
- uint8_t rsvd4:3;
- uint8_t level_shift:4;
- uint8_t downmix_inhibit:1;
- } audio;
- uint8_t payload[28];
- } __attribute__ ((packed)) u;
-} __attribute__((packed));
-
-static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
- struct drm_display_mode * mode)
+static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
{
struct dip_infoframe avi_if = {
.type = DIP_TYPE_AVI,
- .version = DIP_VERSION_AVI,
+ .ver = DIP_VERSION_AVI,
.len = DIP_LEN_AVI,
};
+ uint8_t tx_rate = SDVO_HBUF_TX_VSYNC;
+ uint8_t set_buf_index[2] = { 1, 0 };
+ uint64_t *data = (uint64_t *)&avi_if;
+ unsigned i;
+
+ intel_dip_infoframe_csum(&avi_if);
+
+ if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX,
+ set_buf_index, 2))
+ return false;
- avi_if.checksum = intel_sdvo_calc_hbuf_csum((uint8_t *)&avi_if,
- 4 + avi_if.len);
- return intel_sdvo_set_hdmi_buf(intel_sdvo, 1, (uint8_t *)&avi_if,
- 4 + avi_if.len,
- SDVO_HBUF_TX_VSYNC);
+ for (i = 0; i < sizeof(avi_if); i += 8) {
+ if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA,
+ data, 8))
+ return false;
+ data++;
+ }
+
+ return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE,
+ &tx_rate, 1);
}
static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo)
@@ -1022,8 +910,6 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct intel_sdvo_dtd input_dtd;
-
/* Reset the input timing to the screen. Assume always input 0. */
if (!intel_sdvo_set_target_input(intel_sdvo))
return false;
@@ -1035,14 +921,12 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,
return false;
if (!intel_sdvo_get_preferred_input_timing(intel_sdvo,
- &input_dtd))
+ &intel_sdvo->input_dtd))
return false;
- intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
- intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags;
+ intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd);
drm_mode_set_crtcinfo(adjusted_mode, 0);
- mode->clock = adjusted_mode->clock;
return true;
}
@@ -1050,7 +934,8 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+ struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
+ int multiplier;
/* We need to construct preferred input timings based on our
* output timings. To do that, we have to set the output
@@ -1065,10 +950,8 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
mode,
adjusted_mode);
} else if (intel_sdvo->is_lvds) {
- drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, 0);
-
if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
- intel_sdvo->sdvo_lvds_fixed_mode))
+ intel_sdvo->sdvo_lvds_fixed_mode))
return false;
(void) intel_sdvo_set_input_timings_for_mode(intel_sdvo,
@@ -1077,9 +960,10 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
}
/* Make the CRTC code factor in the SDVO pixel multiplier. The
- * SDVO device will be told of the multiplier during mode_set.
+ * SDVO device will factor out the multiplier during mode_set.
*/
- adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
+ multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode);
+ intel_mode_set_pixel_multiplier(adjusted_mode, multiplier);
return true;
}
@@ -1092,11 +976,12 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc = encoder->crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
- u32 sdvox = 0;
- int sdvo_pixel_multiply, rate;
+ struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
+ u32 sdvox;
struct intel_sdvo_in_out_map in_out;
struct intel_sdvo_dtd input_dtd;
+ int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+ int rate;
if (!mode)
return;
@@ -1114,28 +999,23 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
SDVO_CMD_SET_IN_OUT_MAP,
&in_out, sizeof(in_out));
- if (intel_sdvo->is_hdmi) {
- if (!intel_sdvo_set_avi_infoframe(intel_sdvo, mode))
- return;
-
- sdvox |= SDVO_AUDIO_ENABLE;
- }
+ /* Set the output timings to the screen */
+ if (!intel_sdvo_set_target_output(intel_sdvo,
+ intel_sdvo->attached_output))
+ return;
/* We have tried to get input timing in mode_fixup, and filled into
- adjusted_mode */
- intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
- if (intel_sdvo->is_tv || intel_sdvo->is_lvds)
- input_dtd.part2.sdvo_flags = intel_sdvo->sdvo_flags;
-
- /* If it's a TV, we already set the output timing in mode_fixup.
- * Otherwise, the output timing is equal to the input timing.
+ * adjusted_mode.
*/
- if (!intel_sdvo->is_tv && !intel_sdvo->is_lvds) {
+ if (intel_sdvo->is_tv || intel_sdvo->is_lvds) {
+ input_dtd = intel_sdvo->input_dtd;
+ } else {
/* Set the output timing to the screen */
if (!intel_sdvo_set_target_output(intel_sdvo,
intel_sdvo->attached_output))
return;
+ intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
(void) intel_sdvo_set_output_timing(intel_sdvo, &input_dtd);
}
@@ -1143,31 +1023,18 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
if (!intel_sdvo_set_target_input(intel_sdvo))
return;
- if (intel_sdvo->is_tv) {
- if (!intel_sdvo_set_tv_format(intel_sdvo))
- return;
- }
+ if (intel_sdvo->is_hdmi &&
+ !intel_sdvo_set_avi_infoframe(intel_sdvo))
+ return;
- /* We would like to use intel_sdvo_create_preferred_input_timing() to
- * provide the device with a timing it can support, if it supports that
- * feature. However, presumably we would need to adjust the CRTC to
- * output the preferred timing, and we don't support that currently.
- */
-#if 0
- success = intel_sdvo_create_preferred_input_timing(encoder, clock,
- width, height);
- if (success) {
- struct intel_sdvo_dtd *input_dtd;
+ if (intel_sdvo->is_tv &&
+ !intel_sdvo_set_tv_format(intel_sdvo))
+ return;
- intel_sdvo_get_preferred_input_timing(encoder, &input_dtd);
- intel_sdvo_set_input_timing(encoder, &input_dtd);
- }
-#else
(void) intel_sdvo_set_input_timing(intel_sdvo, &input_dtd);
-#endif
- sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode);
- switch (sdvo_pixel_multiply) {
+ switch (pixel_multiplier) {
+ default:
case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break;
case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break;
@@ -1176,14 +1043,14 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
return;
/* Set the SDVO control regs. */
- if (IS_I965G(dev)) {
- sdvox |= SDVO_BORDER_ENABLE;
+ if (INTEL_INFO(dev)->gen >= 4) {
+ sdvox = SDVO_BORDER_ENABLE;
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
} else {
- sdvox |= I915_READ(intel_sdvo->sdvo_reg);
+ sdvox = I915_READ(intel_sdvo->sdvo_reg);
switch (intel_sdvo->sdvo_reg) {
case SDVOB:
sdvox &= SDVOB_PRESERVE_MASK;
@@ -1196,16 +1063,18 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
}
if (intel_crtc->pipe == 1)
sdvox |= SDVO_PIPE_B_SELECT;
+ if (intel_sdvo->has_audio)
+ sdvox |= SDVO_AUDIO_ENABLE;
- if (IS_I965G(dev)) {
+ if (INTEL_INFO(dev)->gen >= 4) {
/* done in crtc_mode_set as the dpll_md reg must be written early */
} else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
/* done in crtc_mode_set as it lives inside the dpll register */
} else {
- sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
+ sdvox |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT;
}
- if (intel_sdvo->sdvo_flags & SDVO_NEED_TO_STALL)
+ if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL)
sdvox |= SDVO_STALL_SELECT;
intel_sdvo_write_sdvox(intel_sdvo, sdvox);
}
@@ -1214,7 +1083,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+ struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
u32 temp;
@@ -1260,8 +1129,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
static int intel_sdvo_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+ struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
return MODE_NO_DBLESCAN;
@@ -1285,7 +1153,38 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector,
static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps)
{
- return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DEVICE_CAPS, caps, sizeof(*caps));
+ if (!intel_sdvo_get_value(intel_sdvo,
+ SDVO_CMD_GET_DEVICE_CAPS,
+ caps, sizeof(*caps)))
+ return false;
+
+ DRM_DEBUG_KMS("SDVO capabilities:\n"
+ " vendor_id: %d\n"
+ " device_id: %d\n"
+ " device_rev_id: %d\n"
+ " sdvo_version_major: %d\n"
+ " sdvo_version_minor: %d\n"
+ " sdvo_inputs_mask: %d\n"
+ " smooth_scaling: %d\n"
+ " sharp_scaling: %d\n"
+ " up_scaling: %d\n"
+ " down_scaling: %d\n"
+ " stall_support: %d\n"
+ " output_flags: %d\n",
+ caps->vendor_id,
+ caps->device_id,
+ caps->device_rev_id,
+ caps->sdvo_version_major,
+ caps->sdvo_version_minor,
+ caps->sdvo_inputs_mask,
+ caps->smooth_scaling,
+ caps->sharp_scaling,
+ caps->up_scaling,
+ caps->down_scaling,
+ caps->stall_support,
+ caps->output_flags);
+
+ return true;
}
/* No use! */
@@ -1389,22 +1288,33 @@ intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo)
return (caps > 1);
}
+static struct edid *
+intel_sdvo_get_edid(struct drm_connector *connector)
+{
+ struct intel_sdvo *sdvo = intel_attached_sdvo(connector);
+ return drm_get_edid(connector, &sdvo->ddc);
+}
+
static struct drm_connector *
intel_find_analog_connector(struct drm_device *dev)
{
struct drm_connector *connector;
- struct drm_encoder *encoder;
- struct intel_sdvo *intel_sdvo;
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- intel_sdvo = enc_to_intel_sdvo(encoder);
- if (intel_sdvo->base.type == INTEL_OUTPUT_ANALOG) {
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (encoder == intel_attached_encoder(connector))
+ struct intel_sdvo *encoder;
+
+ list_for_each_entry(encoder,
+ &dev->mode_config.encoder_list,
+ base.base.head) {
+ if (encoder->base.type == INTEL_OUTPUT_ANALOG) {
+ list_for_each_entry(connector,
+ &dev->mode_config.connector_list,
+ head) {
+ if (&encoder->base ==
+ intel_attached_encoder(connector))
return connector;
}
}
}
+
return NULL;
}
@@ -1424,64 +1334,72 @@ intel_analog_is_connected(struct drm_device *dev)
return true;
}
+/* Mac mini hack -- use the same DDC as the analog connector */
+static struct edid *
+intel_sdvo_get_analog_edid(struct drm_connector *connector)
+{
+ struct drm_i915_private *dev_priv = connector->dev->dev_private;
+
+ if (!intel_analog_is_connected(connector->dev))
+ return NULL;
+
+ return drm_get_edid(connector, &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
+}
+
enum drm_connector_status
intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
- struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
- enum drm_connector_status status = connector_status_connected;
- struct edid *edid = NULL;
+ struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+ enum drm_connector_status status;
+ struct edid *edid;
- edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus);
+ edid = intel_sdvo_get_edid(connector);
- /* This is only applied to SDVO cards with multiple outputs */
if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) {
- uint8_t saved_ddc, temp_ddc;
- saved_ddc = intel_sdvo->ddc_bus;
- temp_ddc = intel_sdvo->ddc_bus >> 1;
+ u8 ddc, saved_ddc = intel_sdvo->ddc_bus;
+
/*
* Don't use the 1 as the argument of DDC bus switch to get
* the EDID. It is used for SDVO SPD ROM.
*/
- while(temp_ddc > 1) {
- intel_sdvo->ddc_bus = temp_ddc;
- edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus);
- if (edid) {
- /*
- * When we can get the EDID, maybe it is the
- * correct DDC bus. Update it.
- */
- intel_sdvo->ddc_bus = temp_ddc;
+ for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) {
+ intel_sdvo->ddc_bus = ddc;
+ edid = intel_sdvo_get_edid(connector);
+ if (edid)
break;
- }
- temp_ddc >>= 1;
}
+ /*
+ * If we found the EDID on the other bus,
+ * assume that is the correct DDC bus.
+ */
if (edid == NULL)
intel_sdvo->ddc_bus = saved_ddc;
}
- /* when there is no edid and no monitor is connected with VGA
- * port, try to use the CRT ddc to read the EDID for DVI-connector
+
+ /*
+ * When there is no edid and no monitor is connected with VGA
+ * port, try to use the CRT ddc to read the EDID for DVI-connector.
*/
- if (edid == NULL && intel_sdvo->analog_ddc_bus &&
- !intel_analog_is_connected(connector->dev))
- edid = drm_get_edid(connector, intel_sdvo->analog_ddc_bus);
+ if (edid == NULL)
+ edid = intel_sdvo_get_analog_edid(connector);
+ status = connector_status_unknown;
if (edid != NULL) {
- bool is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL);
- bool need_digital = !!(intel_sdvo_connector->output_flag & SDVO_TMDS_MASK);
-
/* DDC bus is shared, match EDID to connector type */
- if (is_digital && need_digital)
+ if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+ status = connector_status_connected;
intel_sdvo->is_hdmi = drm_detect_hdmi_monitor(edid);
- else if (is_digital != need_digital)
- status = connector_status_disconnected;
-
+ intel_sdvo->has_audio = drm_detect_monitor_audio(edid);
+ }
connector->display_info.raw_edid = NULL;
- } else
- status = connector_status_disconnected;
-
- kfree(edid);
+ kfree(edid);
+ }
+
+ if (status == connector_status_connected) {
+ struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
+ if (intel_sdvo_connector->force_audio)
+ intel_sdvo->has_audio = intel_sdvo_connector->force_audio > 0;
+ }
return status;
}
@@ -1490,13 +1408,12 @@ static enum drm_connector_status
intel_sdvo_detect(struct drm_connector *connector, bool force)
{
uint16_t response;
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+ struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
enum drm_connector_status ret;
if (!intel_sdvo_write_cmd(intel_sdvo,
- SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0))
+ SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0))
return connector_status_unknown;
if (intel_sdvo->is_tv) {
/* add 30ms delay when the output type is SDVO-TV */
@@ -1505,7 +1422,9 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
if (!intel_sdvo_read_response(intel_sdvo, &response, 2))
return connector_status_unknown;
- DRM_DEBUG_KMS("SDVO response %d %d\n", response & 0xff, response >> 8);
+ DRM_DEBUG_KMS("SDVO response %d %d [%x]\n",
+ response & 0xff, response >> 8,
+ intel_sdvo_connector->output_flag);
if (response == 0)
return connector_status_disconnected;
@@ -1538,12 +1457,10 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
- int num_modes;
+ struct edid *edid;
/* set the bus switch and get the modes */
- num_modes = intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus);
+ edid = intel_sdvo_get_edid(connector);
/*
* Mac mini hack. On this device, the DVI-I connector shares one DDC
@@ -1551,12 +1468,14 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
* DDC fails, check to see if the analog output is disconnected, in
* which case we'll look there for the digital DDC data.
*/
- if (num_modes == 0 &&
- intel_sdvo->analog_ddc_bus &&
- !intel_analog_is_connected(connector->dev)) {
- /* Switch to the analog ddc bus and try that
- */
- (void) intel_ddc_get_modes(connector, intel_sdvo->analog_ddc_bus);
+ if (edid == NULL)
+ edid = intel_sdvo_get_analog_edid(connector);
+
+ if (edid != NULL) {
+ drm_mode_connector_update_edid_property(connector, edid);
+ drm_add_edid_modes(connector, edid);
+ connector->display_info.raw_edid = NULL;
+ kfree(edid);
}
}
@@ -1627,8 +1546,7 @@ struct drm_display_mode sdvo_tv_modes[] = {
static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+ struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
struct intel_sdvo_sdtv_resolution_request tv_res;
uint32_t reply = 0, format_map = 0;
int i;
@@ -1644,7 +1562,8 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
return;
BUILD_BUG_ON(sizeof(tv_res) != 3);
- if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
+ if (!intel_sdvo_write_cmd(intel_sdvo,
+ SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
&tv_res, sizeof(tv_res)))
return;
if (!intel_sdvo_read_response(intel_sdvo, &reply, 3))
@@ -1662,8 +1581,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+ struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
struct drm_i915_private *dev_priv = connector->dev->dev_private;
struct drm_display_mode *newmode;
@@ -1672,7 +1590,7 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
* Assume that the preferred modes are
* arranged in priority order.
*/
- intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus);
+ intel_ddc_get_modes(connector, intel_sdvo->i2c);
if (list_empty(&connector->probed_modes) == false)
goto end;
@@ -1693,6 +1611,10 @@ end:
if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
intel_sdvo->sdvo_lvds_fixed_mode =
drm_mode_duplicate(connector->dev, newmode);
+
+ drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode,
+ 0);
+
intel_sdvo->is_lvds = true;
break;
}
@@ -1775,8 +1697,7 @@ intel_sdvo_set_property(struct drm_connector *connector,
struct drm_property *property,
uint64_t val)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+ struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
uint16_t temp_value;
uint8_t cmd;
@@ -1786,6 +1707,21 @@ intel_sdvo_set_property(struct drm_connector *connector,
if (ret)
return ret;
+ if (property == intel_sdvo_connector->force_audio_property) {
+ if (val == intel_sdvo_connector->force_audio)
+ return 0;
+
+ intel_sdvo_connector->force_audio = val;
+
+ if (val > 0 && intel_sdvo->has_audio)
+ return 0;
+ if (val < 0 && !intel_sdvo->has_audio)
+ return 0;
+
+ intel_sdvo->has_audio = val > 0;
+ goto done;
+ }
+
#define CHECK_PROPERTY(name, NAME) \
if (intel_sdvo_connector->name == property) { \
if (intel_sdvo_connector->cur_##name == temp_value) return 0; \
@@ -1879,9 +1815,8 @@ set_value:
done:
- if (encoder->crtc) {
- struct drm_crtc *crtc = encoder->crtc;
-
+ if (intel_sdvo->base.base.crtc) {
+ struct drm_crtc *crtc = intel_sdvo->base.base.crtc;
drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
crtc->y, crtc->fb);
}
@@ -1909,20 +1844,18 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
.get_modes = intel_sdvo_get_modes,
.mode_valid = intel_sdvo_mode_valid,
- .best_encoder = intel_attached_encoder,
+ .best_encoder = intel_best_encoder,
};
static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
{
- struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-
- if (intel_sdvo->analog_ddc_bus)
- intel_i2c_destroy(intel_sdvo->analog_ddc_bus);
+ struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
if (intel_sdvo->sdvo_lvds_fixed_mode != NULL)
drm_mode_destroy(encoder->dev,
intel_sdvo->sdvo_lvds_fixed_mode);
+ i2c_del_adapter(&intel_sdvo->ddc);
intel_encoder_destroy(encoder);
}
@@ -1990,53 +1923,48 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv,
intel_sdvo_guess_ddc_bus(sdvo);
}
-static bool
-intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device)
+static void
+intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
+ struct intel_sdvo *sdvo, u32 reg)
{
- return intel_sdvo_set_target_output(intel_sdvo,
- device == 0 ? SDVO_OUTPUT_TMDS0 : SDVO_OUTPUT_TMDS1) &&
- intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE,
- &intel_sdvo->is_hdmi, 1);
-}
+ struct sdvo_device_mapping *mapping;
+ u8 pin, speed;
-static struct intel_sdvo *
-intel_sdvo_chan_to_intel_sdvo(struct intel_i2c_chan *chan)
-{
- struct drm_device *dev = chan->drm_dev;
- struct drm_encoder *encoder;
+ if (IS_SDVOB(reg))
+ mapping = &dev_priv->sdvo_mappings[0];
+ else
+ mapping = &dev_priv->sdvo_mappings[1];
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
- if (intel_sdvo->base.ddc_bus == &chan->adapter)
- return intel_sdvo;
+ pin = GMBUS_PORT_DPB;
+ speed = GMBUS_RATE_1MHZ >> 8;
+ if (mapping->initialized) {
+ pin = mapping->i2c_pin;
+ speed = mapping->i2c_speed;
}
- return NULL;
+ sdvo->i2c = &dev_priv->gmbus[pin].adapter;
+ intel_gmbus_set_speed(sdvo->i2c, speed);
+ intel_gmbus_force_bit(sdvo->i2c, true);
}
-static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
- struct i2c_msg msgs[], int num)
+static bool
+intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo, int device)
{
- struct intel_sdvo *intel_sdvo;
- struct i2c_algo_bit_data *algo_data;
- const struct i2c_algorithm *algo;
+ int is_hdmi;
- algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data;
- intel_sdvo =
- intel_sdvo_chan_to_intel_sdvo((struct intel_i2c_chan *)
- (algo_data->data));
- if (intel_sdvo == NULL)
- return -EINVAL;
+ if (!intel_sdvo_check_supp_encode(intel_sdvo))
+ return false;
- algo = intel_sdvo->base.i2c_bus->algo;
+ if (!intel_sdvo_set_target_output(intel_sdvo,
+ device == 0 ? SDVO_OUTPUT_TMDS0 : SDVO_OUTPUT_TMDS1))
+ return false;
- intel_sdvo_set_control_bus_switch(intel_sdvo, intel_sdvo->ddc_bus);
- return algo->master_xfer(i2c_adap, msgs, num);
-}
+ is_hdmi = 0;
+ if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE, &is_hdmi, 1))
+ return false;
-static struct i2c_algorithm intel_sdvo_i2c_bit_algo = {
- .master_xfer = intel_sdvo_master_xfer,
-};
+ return !!is_hdmi;
+}
static u8
intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg)
@@ -2076,26 +2004,44 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg)
}
static void
-intel_sdvo_connector_init(struct drm_encoder *encoder,
- struct drm_connector *connector)
+intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
+ struct intel_sdvo *encoder)
{
- drm_connector_init(encoder->dev, connector, &intel_sdvo_connector_funcs,
- connector->connector_type);
+ drm_connector_init(encoder->base.base.dev,
+ &connector->base.base,
+ &intel_sdvo_connector_funcs,
+ connector->base.base.connector_type);
+
+ drm_connector_helper_add(&connector->base.base,
+ &intel_sdvo_connector_helper_funcs);
+
+ connector->base.base.interlace_allowed = 0;
+ connector->base.base.doublescan_allowed = 0;
+ connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
- drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
+ intel_connector_attach_encoder(&connector->base, &encoder->base);
+ drm_sysfs_connector_add(&connector->base.base);
+}
- connector->interlace_allowed = 0;
- connector->doublescan_allowed = 0;
- connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+static void
+intel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector)
+{
+ struct drm_device *dev = connector->base.base.dev;
- drm_mode_connector_attach_encoder(connector, encoder);
- drm_sysfs_connector_add(connector);
+ connector->force_audio_property =
+ drm_property_create(dev, DRM_MODE_PROP_RANGE, "force_audio", 2);
+ if (connector->force_audio_property) {
+ connector->force_audio_property->values[0] = -1;
+ connector->force_audio_property->values[1] = 1;
+ drm_connector_attach_property(&connector->base.base,
+ connector->force_audio_property, 0);
+ }
}
static bool
intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
{
- struct drm_encoder *encoder = &intel_sdvo->base.enc;
+ struct drm_encoder *encoder = &intel_sdvo->base.base;
struct drm_connector *connector;
struct intel_connector *intel_connector;
struct intel_sdvo_connector *intel_sdvo_connector;
@@ -2118,19 +2064,20 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
connector->connector_type = DRM_MODE_CONNECTOR_DVID;
- if (intel_sdvo_get_supp_encode(intel_sdvo, &intel_sdvo->encode)
- && intel_sdvo_get_digital_encoding_mode(intel_sdvo, device)
- && intel_sdvo->is_hdmi) {
+ if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) {
/* enable hdmi encoding mode if supported */
intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
intel_sdvo_set_colorimetry(intel_sdvo,
SDVO_COLORIMETRY_RGB256);
connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
+ intel_sdvo->is_hdmi = true;
}
intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
(1 << INTEL_ANALOG_CLONE_BIT));
- intel_sdvo_connector_init(encoder, connector);
+ intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
+
+ intel_sdvo_add_hdmi_properties(intel_sdvo_connector);
return true;
}
@@ -2138,36 +2085,36 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
static bool
intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
{
- struct drm_encoder *encoder = &intel_sdvo->base.enc;
- struct drm_connector *connector;
- struct intel_connector *intel_connector;
- struct intel_sdvo_connector *intel_sdvo_connector;
+ struct drm_encoder *encoder = &intel_sdvo->base.base;
+ struct drm_connector *connector;
+ struct intel_connector *intel_connector;
+ struct intel_sdvo_connector *intel_sdvo_connector;
intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
if (!intel_sdvo_connector)
return false;
intel_connector = &intel_sdvo_connector->base;
- connector = &intel_connector->base;
- encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
- connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
+ connector = &intel_connector->base;
+ encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
+ connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
- intel_sdvo->controlled_output |= type;
- intel_sdvo_connector->output_flag = type;
+ intel_sdvo->controlled_output |= type;
+ intel_sdvo_connector->output_flag = type;
- intel_sdvo->is_tv = true;
- intel_sdvo->base.needs_tv_clock = true;
- intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
+ intel_sdvo->is_tv = true;
+ intel_sdvo->base.needs_tv_clock = true;
+ intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
- intel_sdvo_connector_init(encoder, connector);
+ intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
- if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
+ if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
goto err;
- if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
+ if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
goto err;
- return true;
+ return true;
err:
intel_sdvo_destroy(connector);
@@ -2177,43 +2124,44 @@ err:
static bool
intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
{
- struct drm_encoder *encoder = &intel_sdvo->base.enc;
- struct drm_connector *connector;
- struct intel_connector *intel_connector;
- struct intel_sdvo_connector *intel_sdvo_connector;
+ struct drm_encoder *encoder = &intel_sdvo->base.base;
+ struct drm_connector *connector;
+ struct intel_connector *intel_connector;
+ struct intel_sdvo_connector *intel_sdvo_connector;
intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
if (!intel_sdvo_connector)
return false;
intel_connector = &intel_sdvo_connector->base;
- connector = &intel_connector->base;
+ connector = &intel_connector->base;
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
- encoder->encoder_type = DRM_MODE_ENCODER_DAC;
- connector->connector_type = DRM_MODE_CONNECTOR_VGA;
-
- if (device == 0) {
- intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0;
- intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
- } else if (device == 1) {
- intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1;
- intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
- }
-
- intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+ encoder->encoder_type = DRM_MODE_ENCODER_DAC;
+ connector->connector_type = DRM_MODE_CONNECTOR_VGA;
+
+ if (device == 0) {
+ intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0;
+ intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
+ } else if (device == 1) {
+ intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1;
+ intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
+ }
+
+ intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
(1 << INTEL_ANALOG_CLONE_BIT));
- intel_sdvo_connector_init(encoder, connector);
- return true;
+ intel_sdvo_connector_init(intel_sdvo_connector,
+ intel_sdvo);
+ return true;
}
static bool
intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
{
- struct drm_encoder *encoder = &intel_sdvo->base.enc;
- struct drm_connector *connector;
- struct intel_connector *intel_connector;
- struct intel_sdvo_connector *intel_sdvo_connector;
+ struct drm_encoder *encoder = &intel_sdvo->base.base;
+ struct drm_connector *connector;
+ struct intel_connector *intel_connector;
+ struct intel_sdvo_connector *intel_sdvo_connector;
intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
if (!intel_sdvo_connector)
@@ -2221,22 +2169,22 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
intel_connector = &intel_sdvo_connector->base;
connector = &intel_connector->base;
- encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
- connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
-
- if (device == 0) {
- intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0;
- intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
- } else if (device == 1) {
- intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1;
- intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
- }
-
- intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) |
+ encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
+ connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
+
+ if (device == 0) {
+ intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0;
+ intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
+ } else if (device == 1) {
+ intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1;
+ intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
+ }
+
+ intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) |
(1 << INTEL_SDVO_LVDS_CLONE_BIT));
- intel_sdvo_connector_init(encoder, connector);
- if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
+ intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
+ if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
goto err;
return true;
@@ -2307,7 +2255,7 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
struct intel_sdvo_connector *intel_sdvo_connector,
int type)
{
- struct drm_device *dev = intel_sdvo->base.enc.dev;
+ struct drm_device *dev = intel_sdvo->base.base.dev;
struct intel_sdvo_tv_format format;
uint32_t format_map, i;
@@ -2373,7 +2321,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
struct intel_sdvo_connector *intel_sdvo_connector,
struct intel_sdvo_enhancements_reply enhancements)
{
- struct drm_device *dev = intel_sdvo->base.enc.dev;
+ struct drm_device *dev = intel_sdvo->base.base.dev;
struct drm_connector *connector = &intel_sdvo_connector->base.base;
uint16_t response, data_value[2];
@@ -2502,7 +2450,7 @@ intel_sdvo_create_enhance_property_lvds(struct intel_sdvo *intel_sdvo,
struct intel_sdvo_connector *intel_sdvo_connector,
struct intel_sdvo_enhancements_reply enhancements)
{
- struct drm_device *dev = intel_sdvo->base.enc.dev;
+ struct drm_device *dev = intel_sdvo->base.base.dev;
struct drm_connector *connector = &intel_sdvo_connector->base.base;
uint16_t response, data_value[2];
@@ -2535,7 +2483,43 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
return intel_sdvo_create_enhance_property_lvds(intel_sdvo, intel_sdvo_connector, enhancements.reply);
else
return true;
+}
+
+static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct intel_sdvo *sdvo = adapter->algo_data;
+ if (!intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus))
+ return -EIO;
+
+ return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num);
+}
+
+static u32 intel_sdvo_ddc_proxy_func(struct i2c_adapter *adapter)
+{
+ struct intel_sdvo *sdvo = adapter->algo_data;
+ return sdvo->i2c->algo->functionality(sdvo->i2c);
+}
+
+static const struct i2c_algorithm intel_sdvo_ddc_proxy = {
+ .master_xfer = intel_sdvo_ddc_proxy_xfer,
+ .functionality = intel_sdvo_ddc_proxy_func
+};
+
+static bool
+intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo,
+ struct drm_device *dev)
+{
+ sdvo->ddc.owner = THIS_MODULE;
+ sdvo->ddc.class = I2C_CLASS_DDC;
+ snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy");
+ sdvo->ddc.dev.parent = &dev->pdev->dev;
+ sdvo->ddc.algo_data = sdvo;
+ sdvo->ddc.algo = &intel_sdvo_ddc_proxy;
+
+ return i2c_add_adapter(&sdvo->ddc) == 0;
}
bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
@@ -2543,95 +2527,66 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *intel_encoder;
struct intel_sdvo *intel_sdvo;
- u8 ch[0x40];
int i;
- u32 i2c_reg, ddc_reg, analog_ddc_reg;
intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL);
if (!intel_sdvo)
return false;
+ if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) {
+ kfree(intel_sdvo);
+ return false;
+ }
+
intel_sdvo->sdvo_reg = sdvo_reg;
intel_encoder = &intel_sdvo->base;
intel_encoder->type = INTEL_OUTPUT_SDVO;
+ /* encoder type will be decided later */
+ drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0);
- if (HAS_PCH_SPLIT(dev)) {
- i2c_reg = PCH_GPIOE;
- ddc_reg = PCH_GPIOE;
- analog_ddc_reg = PCH_GPIOA;
- } else {
- i2c_reg = GPIOE;
- ddc_reg = GPIOE;
- analog_ddc_reg = GPIOA;
- }
-
- /* setup the DDC bus. */
- if (IS_SDVOB(sdvo_reg))
- intel_encoder->i2c_bus = intel_i2c_create(dev, i2c_reg, "SDVOCTRL_E for SDVOB");
- else
- intel_encoder->i2c_bus = intel_i2c_create(dev, i2c_reg, "SDVOCTRL_E for SDVOC");
-
- if (!intel_encoder->i2c_bus)
- goto err_inteloutput;
-
- intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg);
-
- /* Save the bit-banging i2c functionality for use by the DDC wrapper */
- intel_sdvo_i2c_bit_algo.functionality = intel_encoder->i2c_bus->algo->functionality;
+ intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1;
+ intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
/* Read the regs to test if we can talk to the device */
for (i = 0; i < 0x40; i++) {
- if (!intel_sdvo_read_byte(intel_sdvo, i, &ch[i])) {
+ u8 byte;
+
+ if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) {
DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n",
IS_SDVOB(sdvo_reg) ? 'B' : 'C');
- goto err_i2c;
+ goto err;
}
}
- /* setup the DDC bus. */
- if (IS_SDVOB(sdvo_reg)) {
- intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOB DDC BUS");
- intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg,
- "SDVOB/VGA DDC BUS");
+ if (IS_SDVOB(sdvo_reg))
dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
- } else {
- intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOC DDC BUS");
- intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg,
- "SDVOC/VGA DDC BUS");
+ else
dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
- }
- if (intel_encoder->ddc_bus == NULL || intel_sdvo->analog_ddc_bus == NULL)
- goto err_i2c;
- /* Wrap with our custom algo which switches to DDC mode */
- intel_encoder->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
-
- /* encoder type will be decided later */
- drm_encoder_init(dev, &intel_encoder->enc, &intel_sdvo_enc_funcs, 0);
- drm_encoder_helper_add(&intel_encoder->enc, &intel_sdvo_helper_funcs);
+ drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);
/* In default case sdvo lvds is false */
if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
- goto err_enc;
+ goto err;
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",
IS_SDVOB(sdvo_reg) ? 'B' : 'C');
- goto err_enc;
+ goto err;
}
intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);
/* Set the input timing to the screen. Assume always input 0. */
if (!intel_sdvo_set_target_input(intel_sdvo))
- goto err_enc;
+ goto err;
if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,
&intel_sdvo->pixel_clock_min,
&intel_sdvo->pixel_clock_max))
- goto err_enc;
+ goto err;
DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, "
"clock range %dMHz - %dMHz, "
@@ -2651,16 +2606,9 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
return true;
-err_enc:
- drm_encoder_cleanup(&intel_encoder->enc);
-err_i2c:
- if (intel_sdvo->analog_ddc_bus != NULL)
- intel_i2c_destroy(intel_sdvo->analog_ddc_bus);
- if (intel_encoder->ddc_bus != NULL)
- intel_i2c_destroy(intel_encoder->ddc_bus);
- if (intel_encoder->i2c_bus != NULL)
- intel_i2c_destroy(intel_encoder->i2c_bus);
-err_inteloutput:
+err:
+ drm_encoder_cleanup(&intel_encoder->base);
+ i2c_del_adapter(&intel_sdvo->ddc);
kfree(intel_sdvo);
return false;
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 4a117e318a73..2f7681989316 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -48,7 +48,7 @@ struct intel_tv {
struct intel_encoder base;
int type;
- char *tv_format;
+ const char *tv_format;
int margin[4];
u32 save_TV_H_CTL_1;
u32 save_TV_H_CTL_2;
@@ -350,7 +350,7 @@ static const struct video_levels component_levels = {
struct tv_mode {
- char *name;
+ const char *name;
int clock;
int refresh; /* in millihertz (for precision) */
u32 oversample;
@@ -900,7 +900,14 @@ static const struct tv_mode tv_modes[] = {
static struct intel_tv *enc_to_intel_tv(struct drm_encoder *encoder)
{
- return container_of(enc_to_intel_encoder(encoder), struct intel_tv, base);
+ return container_of(encoder, struct intel_tv, base.base);
+}
+
+static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
+{
+ return container_of(intel_attached_encoder(connector),
+ struct intel_tv,
+ base);
}
static void
@@ -922,7 +929,7 @@ intel_tv_dpms(struct drm_encoder *encoder, int mode)
}
static const struct tv_mode *
-intel_tv_mode_lookup (char *tv_format)
+intel_tv_mode_lookup(const char *tv_format)
{
int i;
@@ -936,22 +943,23 @@ intel_tv_mode_lookup (char *tv_format)
}
static const struct tv_mode *
-intel_tv_mode_find (struct intel_tv *intel_tv)
+intel_tv_mode_find(struct intel_tv *intel_tv)
{
return intel_tv_mode_lookup(intel_tv->tv_format);
}
static enum drm_mode_status
-intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode)
+intel_tv_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+ struct intel_tv *intel_tv = intel_attached_tv(connector);
const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
/* Ensure TV refresh is close to desired refresh */
if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
< 1000)
return MODE_OK;
+
return MODE_CLOCK_RANGE;
}
@@ -1131,7 +1139,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
color_conversion->av);
}
- if (IS_I965G(dev))
+ if (INTEL_INFO(dev)->gen >= 4)
I915_WRITE(TV_CLR_KNOBS, 0x00404000);
else
I915_WRITE(TV_CLR_KNOBS, 0x00606000);
@@ -1157,12 +1165,12 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
/* Wait for vblank for the disable to take effect */
- if (!IS_I9XX(dev))
+ if (IS_GEN2(dev))
intel_wait_for_vblank(dev, intel_crtc->pipe);
- I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
+ I915_WRITE(pipeconf_reg, pipeconf & ~PIPECONF_ENABLE);
/* Wait for vblank for the disable to take effect. */
- intel_wait_for_vblank(dev, intel_crtc->pipe);
+ intel_wait_for_pipe_off(dev, intel_crtc->pipe);
/* Filter ctl must be set before TV_WIN_SIZE */
I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
@@ -1196,7 +1204,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
for (i = 0; i < 43; i++)
I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
- I915_WRITE(TV_DAC, 0);
+ I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
I915_WRITE(TV_CTL, tv_ctl);
}
@@ -1228,15 +1236,13 @@ static const struct drm_display_mode reported_modes[] = {
static int
intel_tv_detect_type (struct intel_tv *intel_tv)
{
- struct drm_encoder *encoder = &intel_tv->base.enc;
+ struct drm_encoder *encoder = &intel_tv->base.base;
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long irqflags;
u32 tv_ctl, save_tv_ctl;
u32 tv_dac, save_tv_dac;
- int type = DRM_MODE_CONNECTOR_Unknown;
-
- tv_dac = I915_READ(TV_DAC);
+ int type;
/* Disable TV interrupts around load detect or we'll recurse */
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
@@ -1244,19 +1250,14 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
- /*
- * Detect TV by polling)
- */
- save_tv_dac = tv_dac;
- tv_ctl = I915_READ(TV_CTL);
- save_tv_ctl = tv_ctl;
- tv_ctl &= ~TV_ENC_ENABLE;
- tv_ctl &= ~TV_TEST_MODE_MASK;
+ save_tv_dac = tv_dac = I915_READ(TV_DAC);
+ save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
+
+ /* Poll for TV detection */
+ tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK);
tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
- tv_dac &= ~TVDAC_SENSE_MASK;
- tv_dac &= ~DAC_A_MASK;
- tv_dac &= ~DAC_B_MASK;
- tv_dac &= ~DAC_C_MASK;
+
+ tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
tv_dac |= (TVDAC_STATE_CHG_EN |
TVDAC_A_SENSE_CTL |
TVDAC_B_SENSE_CTL |
@@ -1265,37 +1266,40 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
DAC_A_0_7_V |
DAC_B_0_7_V |
DAC_C_0_7_V);
+
I915_WRITE(TV_CTL, tv_ctl);
I915_WRITE(TV_DAC, tv_dac);
POSTING_READ(TV_DAC);
- msleep(20);
- tv_dac = I915_READ(TV_DAC);
- I915_WRITE(TV_DAC, save_tv_dac);
- I915_WRITE(TV_CTL, save_tv_ctl);
- POSTING_READ(TV_CTL);
- msleep(20);
+ intel_wait_for_vblank(intel_tv->base.base.dev,
+ to_intel_crtc(intel_tv->base.base.crtc)->pipe);
- /*
- * A B C
- * 0 1 1 Composite
- * 1 0 X svideo
- * 0 0 0 Component
- */
- if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
- DRM_DEBUG_KMS("Detected Composite TV connection\n");
- type = DRM_MODE_CONNECTOR_Composite;
- } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
- DRM_DEBUG_KMS("Detected S-Video TV connection\n");
- type = DRM_MODE_CONNECTOR_SVIDEO;
- } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
- DRM_DEBUG_KMS("Detected Component TV connection\n");
- type = DRM_MODE_CONNECTOR_Component;
- } else {
- DRM_DEBUG_KMS("No TV connection detected\n");
- type = -1;
+ type = -1;
+ if (wait_for((tv_dac = I915_READ(TV_DAC)) & TVDAC_STATE_CHG, 20) == 0) {
+ DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
+ /*
+ * A B C
+ * 0 1 1 Composite
+ * 1 0 X svideo
+ * 0 0 0 Component
+ */
+ if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
+ DRM_DEBUG_KMS("Detected Composite TV connection\n");
+ type = DRM_MODE_CONNECTOR_Composite;
+ } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
+ DRM_DEBUG_KMS("Detected S-Video TV connection\n");
+ type = DRM_MODE_CONNECTOR_SVIDEO;
+ } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
+ DRM_DEBUG_KMS("Detected Component TV connection\n");
+ type = DRM_MODE_CONNECTOR_Component;
+ } else {
+ DRM_DEBUG_KMS("Unrecognised TV connection\n");
+ }
}
+ I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
+ I915_WRITE(TV_CTL, save_tv_ctl);
+
/* Restore interrupt config */
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
i915_enable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE |
@@ -1311,8 +1315,7 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
*/
static void intel_tv_find_better_format(struct drm_connector *connector)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+ struct intel_tv *intel_tv = intel_attached_tv(connector);
const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
int i;
@@ -1344,14 +1347,13 @@ static enum drm_connector_status
intel_tv_detect(struct drm_connector *connector, bool force)
{
struct drm_display_mode mode;
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+ struct intel_tv *intel_tv = intel_attached_tv(connector);
int type;
mode = reported_modes[0];
drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
- if (encoder->crtc && encoder->crtc->enabled) {
+ if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
type = intel_tv_detect_type(intel_tv);
} else if (force) {
struct drm_crtc *crtc;
@@ -1375,11 +1377,10 @@ intel_tv_detect(struct drm_connector *connector, bool force)
return connector_status_connected;
}
-static struct input_res {
- char *name;
+static const struct input_res {
+ const char *name;
int w, h;
-} input_res_table[] =
-{
+} input_res_table[] = {
{"640x480", 640, 480},
{"800x600", 800, 600},
{"1024x768", 1024, 768},
@@ -1396,8 +1397,7 @@ static void
intel_tv_chose_preferred_modes(struct drm_connector *connector,
struct drm_display_mode *mode_ptr)
{
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+ struct intel_tv *intel_tv = intel_attached_tv(connector);
const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
@@ -1422,15 +1422,14 @@ static int
intel_tv_get_modes(struct drm_connector *connector)
{
struct drm_display_mode *mode_ptr;
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+ struct intel_tv *intel_tv = intel_attached_tv(connector);
const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
int j, count = 0;
u64 tmp;
for (j = 0; j < ARRAY_SIZE(input_res_table);
j++) {
- struct input_res *input = &input_res_table[j];
+ const struct input_res *input = &input_res_table[j];
unsigned int hactive_s = input->w;
unsigned int vactive_s = input->h;
@@ -1488,9 +1487,8 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop
uint64_t val)
{
struct drm_device *dev = connector->dev;
- struct drm_encoder *encoder = intel_attached_encoder(connector);
- struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
- struct drm_crtc *crtc = encoder->crtc;
+ struct intel_tv *intel_tv = intel_attached_tv(connector);
+ struct drm_crtc *crtc = intel_tv->base.base.crtc;
int ret = 0;
bool changed = false;
@@ -1555,7 +1553,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
.mode_valid = intel_tv_mode_valid,
.get_modes = intel_tv_get_modes,
- .best_encoder = intel_attached_encoder,
+ .best_encoder = intel_best_encoder,
};
static const struct drm_encoder_funcs intel_tv_enc_funcs = {
@@ -1607,7 +1605,7 @@ intel_tv_init(struct drm_device *dev)
struct intel_encoder *intel_encoder;
struct intel_connector *intel_connector;
u32 tv_dac_on, tv_dac_off, save_tv_dac;
- char **tv_format_names;
+ char *tv_format_names[ARRAY_SIZE(tv_modes)];
int i, initial_mode = 0;
if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
@@ -1661,15 +1659,15 @@ intel_tv_init(struct drm_device *dev)
drm_connector_init(dev, connector, &intel_tv_connector_funcs,
DRM_MODE_CONNECTOR_SVIDEO);
- drm_encoder_init(dev, &intel_encoder->enc, &intel_tv_enc_funcs,
+ drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
DRM_MODE_ENCODER_TVDAC);
- drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc);
+ intel_connector_attach_encoder(intel_connector, intel_encoder);
intel_encoder->type = INTEL_OUTPUT_TVOUT;
intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT);
- intel_encoder->enc.possible_crtcs = ((1 << 0) | (1 << 1));
- intel_encoder->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
+ intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
+ intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
/* BIOS margin values */
@@ -1678,21 +1676,19 @@ intel_tv_init(struct drm_device *dev)
intel_tv->margin[TV_MARGIN_RIGHT] = 46;
intel_tv->margin[TV_MARGIN_BOTTOM] = 37;
- intel_tv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL);
+ intel_tv->tv_format = tv_modes[initial_mode].name;
- drm_encoder_helper_add(&intel_encoder->enc, &intel_tv_helper_funcs);
+ drm_encoder_helper_add(&intel_encoder->base, &intel_tv_helper_funcs);
drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
connector->interlace_allowed = false;
connector->doublescan_allowed = false;
/* Create TV properties then attach current values */
- tv_format_names = kmalloc(sizeof(char *) * ARRAY_SIZE(tv_modes),
- GFP_KERNEL);
- if (!tv_format_names)
- goto out;
for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
- tv_format_names[i] = tv_modes[i].name;
- drm_mode_create_tv_properties(dev, ARRAY_SIZE(tv_modes), tv_format_names);
+ tv_format_names[i] = (char *)tv_modes[i].name;
+ drm_mode_create_tv_properties(dev,
+ ARRAY_SIZE(tv_modes),
+ tv_format_names);
drm_connector_attach_property(connector, dev->mode_config.tv_mode_property,
initial_mode);
@@ -1708,6 +1704,5 @@ intel_tv_init(struct drm_device *dev)
drm_connector_attach_property(connector,
dev->mode_config.tv_bottom_margin_property,
intel_tv->margin[TV_MARGIN_BOTTOM]);
-out:
drm_sysfs_connector_add(connector);
}
diff --git a/drivers/gpu/drm/mga/mga_drv.c b/drivers/gpu/drm/mga/mga_drv.c
index ac64f0b0392e..0aaf5f67a436 100644
--- a/drivers/gpu/drm/mga/mga_drv.c
+++ b/drivers/gpu/drm/mga/mga_drv.c
@@ -60,8 +60,6 @@ static struct drm_driver driver = {
.irq_uninstall = mga_driver_irq_uninstall,
.irq_handler = mga_driver_irq_handler,
.reclaim_buffers = drm_core_reclaim_buffers,
- .get_map_ofs = drm_core_get_map_ofs,
- .get_reg_ofs = drm_core_get_reg_ofs,
.ioctls = mga_ioctls,
.dma_ioctl = mga_dma_buffers,
.fops = {
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index d2d28048efb2..72730e9ca06c 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -10,6 +10,7 @@ config DRM_NOUVEAU
select FB
select FRAMEBUFFER_CONSOLE if !EMBEDDED
select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
+ select ACPI_VIDEO if ACPI
help
Choose this option for open-source nVidia support.
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index e9b06e4ef2a2..23fa82d667d6 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -9,7 +9,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \
nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
- nouveau_dp.o \
+ nouveau_dp.o nouveau_ramht.o \
+ nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o \
nv04_timer.o \
nv04_mc.o nv40_mc.o nv50_mc.o \
nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \
@@ -23,7 +24,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \
nv10_gpio.o nv50_gpio.o \
- nv50_calc.o
+ nv50_calc.o \
+ nv04_pm.o nv50_pm.o nva3_pm.o
nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index c17a055ee3e5..119152606e4c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -292,6 +292,6 @@ nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
if (ret < 0)
return ret;
- nv_connector->edid = edid;
+ nv_connector->edid = kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index 974b0f8ae048..5f21030a293b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -43,9 +43,6 @@
#define BIOSLOG(sip, fmt, arg...) NV_DEBUG(sip->dev, fmt, ##arg)
#define LOG_OLD_VALUE(x)
-#define ROM16(x) le16_to_cpu(*(uint16_t *)&(x))
-#define ROM32(x) le32_to_cpu(*(uint32_t *)&(x))
-
struct init_exec {
bool execute;
bool repeat;
@@ -272,12 +269,6 @@ struct init_tbl_entry {
int (*handler)(struct nvbios *, uint16_t, struct init_exec *);
};
-struct bit_entry {
- uint8_t id[2];
- uint16_t length;
- uint16_t offset;
-};
-
static int parse_init_table(struct nvbios *, unsigned int, struct init_exec *);
#define MACRO_INDEX_SIZE 2
@@ -1231,7 +1222,7 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
return 3;
}
- if (cond & 1)
+ if (!(cond & 1))
iexec->execute = false;
}
break;
@@ -2167,11 +2158,11 @@ peek_fb(struct drm_device *dev, struct io_mapping *fb,
if (off < pci_resource_len(dev->pdev, 1)) {
uint8_t __iomem *p =
- io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);
+ io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
val = ioread32(p + (off & ~PAGE_MASK));
- io_mapping_unmap_atomic(p, KM_USER0);
+ io_mapping_unmap_atomic(p);
}
return val;
@@ -2183,12 +2174,12 @@ poke_fb(struct drm_device *dev, struct io_mapping *fb,
{
if (off < pci_resource_len(dev->pdev, 1)) {
uint8_t __iomem *p =
- io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);
+ io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
iowrite32(val, p + (off & ~PAGE_MASK));
wmb();
- io_mapping_unmap_atomic(p, KM_USER0);
+ io_mapping_unmap_atomic(p);
}
}
@@ -4675,6 +4666,92 @@ int run_tmds_table(struct drm_device *dev, struct dcb_entry *dcbent, int head, i
return 0;
}
+struct pll_mapping {
+ u8 type;
+ u32 reg;
+};
+
+static struct pll_mapping nv04_pll_mapping[] = {
+ { PLL_CORE , NV_PRAMDAC_NVPLL_COEFF },
+ { PLL_MEMORY, NV_PRAMDAC_MPLL_COEFF },
+ { PLL_VPLL0 , NV_PRAMDAC_VPLL_COEFF },
+ { PLL_VPLL1 , NV_RAMDAC_VPLL2 },
+ {}
+};
+
+static struct pll_mapping nv40_pll_mapping[] = {
+ { PLL_CORE , 0x004000 },
+ { PLL_MEMORY, 0x004020 },
+ { PLL_VPLL0 , NV_PRAMDAC_VPLL_COEFF },
+ { PLL_VPLL1 , NV_RAMDAC_VPLL2 },
+ {}
+};
+
+static struct pll_mapping nv50_pll_mapping[] = {
+ { PLL_CORE , 0x004028 },
+ { PLL_SHADER, 0x004020 },
+ { PLL_UNK03 , 0x004000 },
+ { PLL_MEMORY, 0x004008 },
+ { PLL_UNK40 , 0x00e810 },
+ { PLL_UNK41 , 0x00e818 },
+ { PLL_UNK42 , 0x00e824 },
+ { PLL_VPLL0 , 0x614100 },
+ { PLL_VPLL1 , 0x614900 },
+ {}
+};
+
+static struct pll_mapping nv84_pll_mapping[] = {
+ { PLL_CORE , 0x004028 },
+ { PLL_SHADER, 0x004020 },
+ { PLL_MEMORY, 0x004008 },
+ { PLL_UNK05 , 0x004030 },
+ { PLL_UNK41 , 0x00e818 },
+ { PLL_VPLL0 , 0x614100 },
+ { PLL_VPLL1 , 0x614900 },
+ {}
+};
+
+u32
+get_pll_register(struct drm_device *dev, enum pll_types type)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvbios *bios = &dev_priv->vbios;
+ struct pll_mapping *map;
+ int i;
+
+ if (dev_priv->card_type < NV_40)
+ map = nv04_pll_mapping;
+ else
+ if (dev_priv->card_type < NV_50)
+ map = nv40_pll_mapping;
+ else {
+ u8 *plim = &bios->data[bios->pll_limit_tbl_ptr];
+
+ if (plim[0] >= 0x30) {
+ u8 *entry = plim + plim[1];
+ for (i = 0; i < plim[3]; i++, entry += plim[2]) {
+ if (entry[0] == type)
+ return ROM32(entry[3]);
+ }
+
+ return 0;
+ }
+
+ if (dev_priv->chipset == 0x50)
+ map = nv50_pll_mapping;
+ else
+ map = nv84_pll_mapping;
+ }
+
+ while (map->reg) {
+ if (map->type == type)
+ return map->reg;
+ map++;
+ }
+
+ return 0;
+}
+
int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims *pll_lim)
{
/*
@@ -4750,6 +4827,17 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
/* initialize all members to zero */
memset(pll_lim, 0, sizeof(struct pll_lims));
+ /* if we were passed a type rather than a register, figure
+ * out the register and store it
+ */
+ if (limit_match > PLL_MAX)
+ pll_lim->reg = limit_match;
+ else {
+ pll_lim->reg = get_pll_register(dev, limit_match);
+ if (!pll_lim->reg)
+ return -ENOENT;
+ }
+
if (pll_lim_ver == 0x10 || pll_lim_ver == 0x11) {
uint8_t *pll_rec = &bios->data[bios->pll_limit_tbl_ptr + headerlen + recordlen * pllindex];
@@ -4785,7 +4873,6 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
pll_lim->max_usable_log2p = 0x6;
} else if (pll_lim_ver == 0x20 || pll_lim_ver == 0x21) {
uint16_t plloffs = bios->pll_limit_tbl_ptr + headerlen;
- uint32_t reg = 0; /* default match */
uint8_t *pll_rec;
int i;
@@ -4797,37 +4884,22 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
NV_WARN(dev, "Default PLL limit entry has non-zero "
"register field\n");
- if (limit_match > MAX_PLL_TYPES)
- /* we've been passed a reg as the match */
- reg = limit_match;
- else /* limit match is a pll type */
- for (i = 1; i < entries && !reg; i++) {
- uint32_t cmpreg = ROM32(bios->data[plloffs + recordlen * i]);
-
- if (limit_match == NVPLL &&
- (cmpreg == NV_PRAMDAC_NVPLL_COEFF || cmpreg == 0x4000))
- reg = cmpreg;
- if (limit_match == MPLL &&
- (cmpreg == NV_PRAMDAC_MPLL_COEFF || cmpreg == 0x4020))
- reg = cmpreg;
- if (limit_match == VPLL1 &&
- (cmpreg == NV_PRAMDAC_VPLL_COEFF || cmpreg == 0x4010))
- reg = cmpreg;
- if (limit_match == VPLL2 &&
- (cmpreg == NV_RAMDAC_VPLL2 || cmpreg == 0x4018))
- reg = cmpreg;
- }
-
for (i = 1; i < entries; i++)
- if (ROM32(bios->data[plloffs + recordlen * i]) == reg) {
+ if (ROM32(bios->data[plloffs + recordlen * i]) == pll_lim->reg) {
pllindex = i;
break;
}
+ if ((dev_priv->card_type >= NV_50) && (pllindex == 0)) {
+ NV_ERROR(dev, "Register 0x%08x not found in PLL "
+ "limits table", pll_lim->reg);
+ return -ENOENT;
+ }
+
pll_rec = &bios->data[plloffs + recordlen * pllindex];
BIOSLOG(bios, "Loading PLL limits for reg 0x%08x\n",
- pllindex ? reg : 0);
+ pllindex ? pll_lim->reg : 0);
/*
* Frequencies are stored in tables in MHz, kHz are more
@@ -4877,8 +4949,8 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
if (cv == 0x51 && !pll_lim->refclk) {
uint32_t sel_clk = bios_rd32(bios, NV_PRAMDAC_SEL_CLK);
- if (((limit_match == NV_PRAMDAC_VPLL_COEFF || limit_match == VPLL1) && sel_clk & 0x20) ||
- ((limit_match == NV_RAMDAC_VPLL2 || limit_match == VPLL2) && sel_clk & 0x80)) {
+ if ((pll_lim->reg == NV_PRAMDAC_VPLL_COEFF && sel_clk & 0x20) ||
+ (pll_lim->reg == NV_RAMDAC_VPLL2 && sel_clk & 0x80)) {
if (bios_idxprt_rd(bios, NV_CIO_CRX__COLOR, NV_CIO_CRE_CHIP_ID_INDEX) < 0xa3)
pll_lim->refclk = 200000;
else
@@ -4891,10 +4963,10 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
int i;
BIOSLOG(bios, "Loading PLL limits for register 0x%08x\n",
- limit_match);
+ pll_lim->reg);
for (i = 0; i < entries; i++, entry += recordlen) {
- if (ROM32(entry[3]) == limit_match) {
+ if (ROM32(entry[3]) == pll_lim->reg) {
record = &bios->data[ROM16(entry[1])];
break;
}
@@ -4902,7 +4974,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
if (!record) {
NV_ERROR(dev, "Register 0x%08x not found in PLL "
- "limits table", limit_match);
+ "limits table", pll_lim->reg);
return -ENOENT;
}
@@ -4931,10 +5003,10 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
int i;
BIOSLOG(bios, "Loading PLL limits for register 0x%08x\n",
- limit_match);
+ pll_lim->reg);
for (i = 0; i < entries; i++, entry += recordlen) {
- if (ROM32(entry[3]) == limit_match) {
+ if (ROM32(entry[3]) == pll_lim->reg) {
record = &bios->data[ROM16(entry[1])];
break;
}
@@ -4942,7 +5014,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
if (!record) {
NV_ERROR(dev, "Register 0x%08x not found in PLL "
- "limits table", limit_match);
+ "limits table", pll_lim->reg);
return -ENOENT;
}
@@ -5293,7 +5365,7 @@ parse_bit_M_tbl_entry(struct drm_device *dev, struct nvbios *bios,
if (bitentry->length < 0x5)
return 0;
- if (bitentry->id[1] < 2) {
+ if (bitentry->version < 2) {
bios->ram_restrict_group_count = bios->data[bitentry->offset + 2];
bios->ram_restrict_tbl_ptr = ROM16(bios->data[bitentry->offset + 3]);
} else {
@@ -5403,27 +5475,40 @@ struct bit_table {
#define BIT_TABLE(id, funcid) ((struct bit_table){ id, parse_bit_##funcid##_tbl_entry })
+int
+bit_table(struct drm_device *dev, u8 id, struct bit_entry *bit)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvbios *bios = &dev_priv->vbios;
+ u8 entries, *entry;
+
+ entries = bios->data[bios->offset + 10];
+ entry = &bios->data[bios->offset + 12];
+ while (entries--) {
+ if (entry[0] == id) {
+ bit->id = entry[0];
+ bit->version = entry[1];
+ bit->length = ROM16(entry[2]);
+ bit->offset = ROM16(entry[4]);
+ bit->data = ROMPTR(bios, entry[4]);
+ return 0;
+ }
+
+ entry += bios->data[bios->offset + 9];
+ }
+
+ return -ENOENT;
+}
+
static int
parse_bit_table(struct nvbios *bios, const uint16_t bitoffset,
struct bit_table *table)
{
struct drm_device *dev = bios->dev;
- uint8_t maxentries = bios->data[bitoffset + 4];
- int i, offset;
struct bit_entry bitentry;
- for (i = 0, offset = bitoffset + 6; i < maxentries; i++, offset += 6) {
- bitentry.id[0] = bios->data[offset];
-
- if (bitentry.id[0] != table->id)
- continue;
-
- bitentry.id[1] = bios->data[offset + 1];
- bitentry.length = ROM16(bios->data[offset + 2]);
- bitentry.offset = ROM16(bios->data[offset + 4]);
-
+ if (bit_table(dev, table->id, &bitentry) == 0)
return table->parse_fn(dev, bios, &bitentry);
- }
NV_INFO(dev, "BIT table '%c' not found\n", table->id);
return -ENOSYS;
@@ -5683,8 +5768,14 @@ static uint16_t findstr(uint8_t *data, int n, const uint8_t *str, int len)
static struct dcb_gpio_entry *
new_gpio_entry(struct nvbios *bios)
{
+ struct drm_device *dev = bios->dev;
struct dcb_gpio_table *gpio = &bios->dcb.gpio;
+ if (gpio->entries >= DCB_MAX_NUM_GPIO_ENTRIES) {
+ NV_ERROR(dev, "exceeded maximum number of gpio entries!!\n");
+ return NULL;
+ }
+
return &gpio->entry[gpio->entries++];
}
@@ -5706,113 +5797,90 @@ nouveau_bios_gpio_entry(struct drm_device *dev, enum dcb_gpio_tag tag)
}
static void
-parse_dcb30_gpio_entry(struct nvbios *bios, uint16_t offset)
-{
- struct dcb_gpio_entry *gpio;
- uint16_t ent = ROM16(bios->data[offset]);
- uint8_t line = ent & 0x1f,
- tag = ent >> 5 & 0x3f,
- flags = ent >> 11 & 0x1f;
-
- if (tag == 0x3f)
- return;
-
- gpio = new_gpio_entry(bios);
-
- gpio->tag = tag;
- gpio->line = line;
- gpio->invert = flags != 4;
- gpio->entry = ent;
-}
-
-static void
-parse_dcb40_gpio_entry(struct nvbios *bios, uint16_t offset)
-{
- uint32_t entry = ROM32(bios->data[offset]);
- struct dcb_gpio_entry *gpio;
-
- if ((entry & 0x0000ff00) == 0x0000ff00)
- return;
-
- gpio = new_gpio_entry(bios);
- gpio->tag = (entry & 0x0000ff00) >> 8;
- gpio->line = (entry & 0x0000001f) >> 0;
- gpio->state_default = (entry & 0x01000000) >> 24;
- gpio->state[0] = (entry & 0x18000000) >> 27;
- gpio->state[1] = (entry & 0x60000000) >> 29;
- gpio->entry = entry;
-}
-
-static void
parse_dcb_gpio_table(struct nvbios *bios)
{
struct drm_device *dev = bios->dev;
- uint16_t gpio_table_ptr = bios->dcb.gpio_table_ptr;
- uint8_t *gpio_table = &bios->data[gpio_table_ptr];
- int header_len = gpio_table[1],
- entries = gpio_table[2],
- entry_len = gpio_table[3];
- void (*parse_entry)(struct nvbios *, uint16_t) = NULL;
+ struct dcb_gpio_entry *e;
+ u8 headerlen, entries, recordlen;
+ u8 *dcb, *gpio = NULL, *entry;
int i;
- if (bios->dcb.version >= 0x40) {
- if (gpio_table_ptr && entry_len != 4) {
- NV_WARN(dev, "Invalid DCB GPIO table entry length.\n");
- return;
- }
+ dcb = ROMPTR(bios, bios->data[0x36]);
+ if (dcb[0] >= 0x30) {
+ gpio = ROMPTR(bios, dcb[10]);
+ if (!gpio)
+ goto no_table;
- parse_entry = parse_dcb40_gpio_entry;
+ headerlen = gpio[1];
+ entries = gpio[2];
+ recordlen = gpio[3];
+ } else
+ if (dcb[0] >= 0x22 && dcb[-1] >= 0x13) {
+ gpio = ROMPTR(bios, dcb[-15]);
+ if (!gpio)
+ goto no_table;
+
+ headerlen = 3;
+ entries = gpio[2];
+ recordlen = gpio[1];
+ } else
+ if (dcb[0] >= 0x22) {
+ /* No GPIO table present, parse the TVDAC GPIO data. */
+ uint8_t *tvdac_gpio = &dcb[-5];
- } else if (bios->dcb.version >= 0x30) {
- if (gpio_table_ptr && entry_len != 2) {
- NV_WARN(dev, "Invalid DCB GPIO table entry length.\n");
- return;
+ if (tvdac_gpio[0] & 1) {
+ e = new_gpio_entry(bios);
+ e->tag = DCB_GPIO_TVDAC0;
+ e->line = tvdac_gpio[1] >> 4;
+ e->invert = tvdac_gpio[0] & 2;
}
- parse_entry = parse_dcb30_gpio_entry;
-
- } else if (bios->dcb.version >= 0x22) {
- /*
- * DCBs older than v3.0 don't really have a GPIO
- * table, instead they keep some GPIO info at fixed
- * locations.
- */
- uint16_t dcbptr = ROM16(bios->data[0x36]);
- uint8_t *tvdac_gpio = &bios->data[dcbptr - 5];
+ goto no_table;
+ } else {
+ NV_DEBUG(dev, "no/unknown gpio table on DCB 0x%02x\n", dcb[0]);
+ goto no_table;
+ }
- if (tvdac_gpio[0] & 1) {
- struct dcb_gpio_entry *gpio = new_gpio_entry(bios);
+ entry = gpio + headerlen;
+ for (i = 0; i < entries; i++, entry += recordlen) {
+ e = new_gpio_entry(bios);
+ if (!e)
+ break;
- gpio->tag = DCB_GPIO_TVDAC0;
- gpio->line = tvdac_gpio[1] >> 4;
- gpio->invert = tvdac_gpio[0] & 2;
- }
- } else {
- /*
- * No systematic way to store GPIO info on pre-v2.2
- * DCBs, try to match the PCI device IDs.
- */
+ if (gpio[0] < 0x40) {
+ e->entry = ROM16(entry[0]);
+ e->tag = (e->entry & 0x07e0) >> 5;
+ if (e->tag == 0x3f) {
+ bios->dcb.gpio.entries--;
+ continue;
+ }
- /* Apple iMac G4 NV18 */
- if (nv_match_device(dev, 0x0189, 0x10de, 0x0010)) {
- struct dcb_gpio_entry *gpio = new_gpio_entry(bios);
+ e->line = (e->entry & 0x001f);
+ e->invert = ((e->entry & 0xf800) >> 11) != 4;
+ } else {
+ e->entry = ROM32(entry[0]);
+ e->tag = (e->entry & 0x0000ff00) >> 8;
+ if (e->tag == 0xff) {
+ bios->dcb.gpio.entries--;
+ continue;
+ }
- gpio->tag = DCB_GPIO_TVDAC0;
- gpio->line = 4;
+ e->line = (e->entry & 0x0000001f) >> 0;
+ e->state_default = (e->entry & 0x01000000) >> 24;
+ e->state[0] = (e->entry & 0x18000000) >> 27;
+ e->state[1] = (e->entry & 0x60000000) >> 29;
}
-
}
- if (!gpio_table_ptr)
- return;
-
- if (entries > DCB_MAX_NUM_GPIO_ENTRIES) {
- NV_WARN(dev, "Too many entries in the DCB GPIO table.\n");
- entries = DCB_MAX_NUM_GPIO_ENTRIES;
+no_table:
+ /* Apple iMac G4 NV18 */
+ if (nv_match_device(dev, 0x0189, 0x10de, 0x0010)) {
+ e = new_gpio_entry(bios);
+ if (e) {
+ e->tag = DCB_GPIO_TVDAC0;
+ e->line = 4;
+ }
}
-
- for (i = 0; i < entries; i++)
- parse_entry(bios, gpio_table_ptr + header_len + entry_len * i);
}
struct dcb_connector_table_entry *
@@ -6680,6 +6748,8 @@ static int nouveau_parse_vbios_struct(struct drm_device *dev)
bit_signature, sizeof(bit_signature));
if (offset) {
NV_TRACE(dev, "BIT BIOS found\n");
+ bios->type = NVBIOS_BIT;
+ bios->offset = offset;
return parse_bit_structure(bios, offset + 6);
}
@@ -6687,6 +6757,8 @@ static int nouveau_parse_vbios_struct(struct drm_device *dev)
bmp_signature, sizeof(bmp_signature));
if (offset) {
NV_TRACE(dev, "BMP BIOS found\n");
+ bios->type = NVBIOS_BMP;
+ bios->offset = offset;
return parse_bmp_structure(dev, bios, offset);
}
@@ -6806,6 +6878,8 @@ nouveau_bios_init(struct drm_device *dev)
"running VBIOS init tables.\n");
bios->execute = true;
}
+ if (nouveau_force_post)
+ bios->execute = true;
ret = nouveau_run_vbios_init(dev);
if (ret)
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
index c1de2f3fcb0e..50a648e01c49 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
@@ -34,6 +34,20 @@
#define DCB_LOC_ON_CHIP 0
+#define ROM16(x) le16_to_cpu(*(uint16_t *)&(x))
+#define ROM32(x) le32_to_cpu(*(uint32_t *)&(x))
+#define ROMPTR(bios, x) (ROM16(x) ? &(bios)->data[ROM16(x)] : NULL)
+
+struct bit_entry {
+ uint8_t id;
+ uint8_t version;
+ uint16_t length;
+ uint16_t offset;
+ uint8_t *data;
+};
+
+int bit_table(struct drm_device *, u8 id, struct bit_entry *);
+
struct dcb_i2c_entry {
uint32_t entry;
uint8_t port_type;
@@ -170,16 +184,28 @@ enum LVDS_script {
LVDS_PANEL_OFF
};
-/* changing these requires matching changes to reg tables in nv_get_clock */
-#define MAX_PLL_TYPES 4
+/* these match types in pll limits table version 0x40,
+ * nouveau uses them on all chipsets internally where a
+ * specific pll needs to be referenced, but the exact
+ * register isn't known.
+ */
enum pll_types {
- NVPLL,
- MPLL,
- VPLL1,
- VPLL2
+ PLL_CORE = 0x01,
+ PLL_SHADER = 0x02,
+ PLL_UNK03 = 0x03,
+ PLL_MEMORY = 0x04,
+ PLL_UNK05 = 0x05,
+ PLL_UNK40 = 0x40,
+ PLL_UNK41 = 0x41,
+ PLL_UNK42 = 0x42,
+ PLL_VPLL0 = 0x80,
+ PLL_VPLL1 = 0x81,
+ PLL_MAX = 0xff
};
struct pll_lims {
+ u32 reg;
+
struct {
int minfreq;
int maxfreq;
@@ -212,6 +238,11 @@ struct pll_lims {
struct nvbios {
struct drm_device *dev;
+ enum {
+ NVBIOS_BMP,
+ NVBIOS_BIT
+ } type;
+ uint16_t offset;
uint8_t chip_version;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index f6f44779d82f..80353e2b8409 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -36,21 +36,6 @@
#include <linux/log2.h>
#include <linux/slab.h>
-int
-nouveau_bo_sync_gpu(struct nouveau_bo *nvbo, struct nouveau_channel *chan)
-{
- struct nouveau_fence *prev_fence = nvbo->bo.sync_obj;
- int ret;
-
- if (!prev_fence || nouveau_fence_channel(prev_fence) == chan)
- return 0;
-
- spin_lock(&nvbo->bo.lock);
- ret = ttm_bo_wait(&nvbo->bo, false, false, false);
- spin_unlock(&nvbo->bo.lock);
- return ret;
-}
-
static void
nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
{
@@ -58,8 +43,6 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
struct drm_device *dev = dev_priv->dev;
struct nouveau_bo *nvbo = nouveau_bo(bo);
- ttm_bo_kunmap(&nvbo->kmap);
-
if (unlikely(nvbo->gem))
DRM_ERROR("bo %p still attached to GEM object\n", bo);
@@ -164,8 +147,6 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
nouveau_bo_fixup_align(dev, tile_mode, tile_flags, &align, &size);
align >>= PAGE_SHIFT;
- nvbo->placement.fpfn = 0;
- nvbo->placement.lpfn = mappable ? dev_priv->fb_mappable_pages : 0;
nouveau_bo_placement_set(nvbo, flags, 0);
nvbo->channel = chan;
@@ -305,7 +286,8 @@ nouveau_bo_map(struct nouveau_bo *nvbo)
void
nouveau_bo_unmap(struct nouveau_bo *nvbo)
{
- ttm_bo_kunmap(&nvbo->kmap);
+ if (nvbo)
+ ttm_bo_kunmap(&nvbo->kmap);
}
u16
@@ -399,14 +381,19 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
man->default_caching = TTM_PL_FLAG_CACHED;
break;
case TTM_PL_VRAM:
+ man->func = &ttm_bo_manager_func;
man->flags = TTM_MEMTYPE_FLAG_FIXED |
TTM_MEMTYPE_FLAG_MAPPABLE;
man->available_caching = TTM_PL_FLAG_UNCACHED |
TTM_PL_FLAG_WC;
man->default_caching = TTM_PL_FLAG_WC;
- man->gpu_offset = dev_priv->vm_vram_base;
+ if (dev_priv->card_type == NV_50)
+ man->gpu_offset = 0x40000000;
+ else
+ man->gpu_offset = 0;
break;
case TTM_PL_TT:
+ man->func = &ttm_bo_manager_func;
switch (dev_priv->gart_info.type) {
case NOUVEAU_GART_AGP:
man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
@@ -469,19 +456,26 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan,
if (ret)
return ret;
- ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL,
- evict || (nvbo->channel &&
- nvbo->channel != chan),
+ if (nvbo->channel) {
+ ret = nouveau_fence_sync(fence, nvbo->channel);
+ if (ret)
+ goto out;
+ }
+
+ ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, evict,
no_wait_reserve, no_wait_gpu, new_mem);
+out:
nouveau_fence_unref((void *)&fence);
return ret;
}
static inline uint32_t
-nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan,
- struct ttm_mem_reg *mem)
+nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo,
+ struct nouveau_channel *chan, struct ttm_mem_reg *mem)
{
- if (chan == nouveau_bdev(nvbo->bo.bdev)->channel) {
+ struct nouveau_bo *nvbo = nouveau_bo(bo);
+
+ if (nvbo->no_vm) {
if (mem->mem_type == TTM_PL_TT)
return NvDmaGART;
return NvDmaVRAM;
@@ -493,86 +487,181 @@ nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan,
}
static int
-nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
- bool no_wait_reserve, bool no_wait_gpu,
- struct ttm_mem_reg *new_mem)
+nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
{
- struct nouveau_bo *nvbo = nouveau_bo(bo);
struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
- struct ttm_mem_reg *old_mem = &bo->mem;
- struct nouveau_channel *chan;
- uint64_t src_offset, dst_offset;
- uint32_t page_count;
+ struct nouveau_bo *nvbo = nouveau_bo(bo);
+ u64 length = (new_mem->num_pages << PAGE_SHIFT);
+ u64 src_offset, dst_offset;
int ret;
- chan = nvbo->channel;
- if (!chan || nvbo->tile_flags || nvbo->no_vm)
- chan = dev_priv->channel;
-
- src_offset = old_mem->mm_node->start << PAGE_SHIFT;
- dst_offset = new_mem->mm_node->start << PAGE_SHIFT;
- if (chan != dev_priv->channel) {
- if (old_mem->mem_type == TTM_PL_TT)
- src_offset += dev_priv->vm_gart_base;
- else
+ src_offset = old_mem->start << PAGE_SHIFT;
+ dst_offset = new_mem->start << PAGE_SHIFT;
+ if (!nvbo->no_vm) {
+ if (old_mem->mem_type == TTM_PL_VRAM)
src_offset += dev_priv->vm_vram_base;
-
- if (new_mem->mem_type == TTM_PL_TT)
- dst_offset += dev_priv->vm_gart_base;
else
+ src_offset += dev_priv->vm_gart_base;
+
+ if (new_mem->mem_type == TTM_PL_VRAM)
dst_offset += dev_priv->vm_vram_base;
+ else
+ dst_offset += dev_priv->vm_gart_base;
}
ret = RING_SPACE(chan, 3);
if (ret)
return ret;
- BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_SOURCE, 2);
- OUT_RING(chan, nouveau_bo_mem_ctxdma(nvbo, chan, old_mem));
- OUT_RING(chan, nouveau_bo_mem_ctxdma(nvbo, chan, new_mem));
- if (dev_priv->card_type >= NV_50) {
- ret = RING_SPACE(chan, 4);
+ BEGIN_RING(chan, NvSubM2MF, 0x0184, 2);
+ OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, old_mem));
+ OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, new_mem));
+
+ while (length) {
+ u32 amount, stride, height;
+
+ amount = min(length, (u64)(4 * 1024 * 1024));
+ stride = 16 * 4;
+ height = amount / stride;
+
+ if (new_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) {
+ ret = RING_SPACE(chan, 8);
+ if (ret)
+ return ret;
+
+ BEGIN_RING(chan, NvSubM2MF, 0x0200, 7);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, stride);
+ OUT_RING (chan, height);
+ OUT_RING (chan, 1);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, 0);
+ } else {
+ ret = RING_SPACE(chan, 2);
+ if (ret)
+ return ret;
+
+ BEGIN_RING(chan, NvSubM2MF, 0x0200, 1);
+ OUT_RING (chan, 1);
+ }
+ if (old_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) {
+ ret = RING_SPACE(chan, 8);
+ if (ret)
+ return ret;
+
+ BEGIN_RING(chan, NvSubM2MF, 0x021c, 7);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, stride);
+ OUT_RING (chan, height);
+ OUT_RING (chan, 1);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, 0);
+ } else {
+ ret = RING_SPACE(chan, 2);
+ if (ret)
+ return ret;
+
+ BEGIN_RING(chan, NvSubM2MF, 0x021c, 1);
+ OUT_RING (chan, 1);
+ }
+
+ ret = RING_SPACE(chan, 14);
if (ret)
return ret;
- BEGIN_RING(chan, NvSubM2MF, 0x0200, 1);
- OUT_RING(chan, 1);
- BEGIN_RING(chan, NvSubM2MF, 0x021c, 1);
- OUT_RING(chan, 1);
+
+ BEGIN_RING(chan, NvSubM2MF, 0x0238, 2);
+ OUT_RING (chan, upper_32_bits(src_offset));
+ OUT_RING (chan, upper_32_bits(dst_offset));
+ BEGIN_RING(chan, NvSubM2MF, 0x030c, 8);
+ OUT_RING (chan, lower_32_bits(src_offset));
+ OUT_RING (chan, lower_32_bits(dst_offset));
+ OUT_RING (chan, stride);
+ OUT_RING (chan, stride);
+ OUT_RING (chan, stride);
+ OUT_RING (chan, height);
+ OUT_RING (chan, 0x00000101);
+ OUT_RING (chan, 0x00000000);
+ BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1);
+ OUT_RING (chan, 0);
+
+ length -= amount;
+ src_offset += amount;
+ dst_offset += amount;
}
+ return 0;
+}
+
+static int
+nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
+{
+ u32 src_offset = old_mem->start << PAGE_SHIFT;
+ u32 dst_offset = new_mem->start << PAGE_SHIFT;
+ u32 page_count = new_mem->num_pages;
+ int ret;
+
+ ret = RING_SPACE(chan, 3);
+ if (ret)
+ return ret;
+
+ BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_SOURCE, 2);
+ OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, old_mem));
+ OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, new_mem));
+
page_count = new_mem->num_pages;
while (page_count) {
int line_count = (page_count > 2047) ? 2047 : page_count;
- if (dev_priv->card_type >= NV_50) {
- ret = RING_SPACE(chan, 3);
- if (ret)
- return ret;
- BEGIN_RING(chan, NvSubM2MF, 0x0238, 2);
- OUT_RING(chan, upper_32_bits(src_offset));
- OUT_RING(chan, upper_32_bits(dst_offset));
- }
ret = RING_SPACE(chan, 11);
if (ret)
return ret;
+
BEGIN_RING(chan, NvSubM2MF,
NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
- OUT_RING(chan, lower_32_bits(src_offset));
- OUT_RING(chan, lower_32_bits(dst_offset));
- OUT_RING(chan, PAGE_SIZE); /* src_pitch */
- OUT_RING(chan, PAGE_SIZE); /* dst_pitch */
- OUT_RING(chan, PAGE_SIZE); /* line_length */
- OUT_RING(chan, line_count);
- OUT_RING(chan, (1<<8)|(1<<0));
- OUT_RING(chan, 0);
+ OUT_RING (chan, src_offset);
+ OUT_RING (chan, dst_offset);
+ OUT_RING (chan, PAGE_SIZE); /* src_pitch */
+ OUT_RING (chan, PAGE_SIZE); /* dst_pitch */
+ OUT_RING (chan, PAGE_SIZE); /* line_length */
+ OUT_RING (chan, line_count);
+ OUT_RING (chan, 0x00000101);
+ OUT_RING (chan, 0x00000000);
BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1);
- OUT_RING(chan, 0);
+ OUT_RING (chan, 0);
page_count -= line_count;
src_offset += (PAGE_SIZE * line_count);
dst_offset += (PAGE_SIZE * line_count);
}
+ return 0;
+}
+
+static int
+nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
+ bool no_wait_reserve, bool no_wait_gpu,
+ struct ttm_mem_reg *new_mem)
+{
+ struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
+ struct nouveau_bo *nvbo = nouveau_bo(bo);
+ struct nouveau_channel *chan;
+ int ret;
+
+ chan = nvbo->channel;
+ if (!chan || nvbo->no_vm)
+ chan = dev_priv->channel;
+
+ if (dev_priv->card_type < NV_50)
+ ret = nv04_bo_move_m2mf(chan, bo, &bo->mem, new_mem);
+ else
+ ret = nv50_bo_move_m2mf(chan, bo, &bo->mem, new_mem);
+ if (ret)
+ return ret;
+
return nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait_reserve, no_wait_gpu, new_mem);
}
@@ -606,12 +695,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
out:
- if (tmp_mem.mm_node) {
- spin_lock(&bo->bdev->glob->lru_lock);
- drm_mm_put_block(tmp_mem.mm_node);
- spin_unlock(&bo->bdev->glob->lru_lock);
- }
-
+ ttm_bo_mem_put(bo, &tmp_mem);
return ret;
}
@@ -644,12 +728,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
goto out;
out:
- if (tmp_mem.mm_node) {
- spin_lock(&bo->bdev->glob->lru_lock);
- drm_mm_put_block(tmp_mem.mm_node);
- spin_unlock(&bo->bdev->glob->lru_lock);
- }
-
+ ttm_bo_mem_put(bo, &tmp_mem);
return ret;
}
@@ -669,7 +748,7 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem,
return 0;
}
- offset = new_mem->mm_node->start << PAGE_SHIFT;
+ offset = new_mem->start << PAGE_SHIFT;
if (dev_priv->card_type == NV_50) {
ret = nv50_mem_vm_bind_linear(dev,
@@ -719,12 +798,6 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
if (ret)
return ret;
- /* Software copy if the card isn't up and running yet. */
- if (!dev_priv->channel) {
- ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
- goto out;
- }
-
/* Fake bo copy. */
if (old_mem->mem_type == TTM_PL_SYSTEM && !bo->ttm) {
BUG_ON(bo->mem.mm_node != NULL);
@@ -733,6 +806,12 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
goto out;
}
+ /* Software copy if the card isn't up and running yet. */
+ if (!dev_priv->channel) {
+ ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
+ goto out;
+ }
+
/* Hardware assisted copy. */
if (new_mem->mem_type == TTM_PL_SYSTEM)
ret = nouveau_bo_move_flipd(bo, evict, intr, no_wait_reserve, no_wait_gpu, new_mem);
@@ -783,14 +862,14 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
case TTM_PL_TT:
#if __OS_HAS_AGP
if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
- mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
+ mem->bus.offset = mem->start << PAGE_SHIFT;
mem->bus.base = dev_priv->gart_info.aper_base;
mem->bus.is_iomem = true;
}
#endif
break;
case TTM_PL_VRAM:
- mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
+ mem->bus.offset = mem->start << PAGE_SHIFT;
mem->bus.base = pci_resource_start(dev->pdev, 1);
mem->bus.is_iomem = true;
break;
@@ -808,7 +887,26 @@ nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
static int
nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
{
- return 0;
+ struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
+ struct nouveau_bo *nvbo = nouveau_bo(bo);
+
+ /* as long as the bo isn't in vram, and isn't tiled, we've got
+ * nothing to do here.
+ */
+ if (bo->mem.mem_type != TTM_PL_VRAM) {
+ if (dev_priv->card_type < NV_50 || !nvbo->tile_flags)
+ return 0;
+ }
+
+ /* make sure bo is in mappable vram */
+ if (bo->mem.start + bo->mem.num_pages < dev_priv->fb_mappable_pages)
+ return 0;
+
+
+ nvbo->placement.fpfn = 0;
+ nvbo->placement.lpfn = dev_priv->fb_mappable_pages;
+ nouveau_bo_placement_set(nvbo, TTM_PL_VRAM, 0);
+ return ttm_bo_validate(bo, &nvbo->placement, false, true, false);
}
struct ttm_bo_driver nouveau_bo_driver = {
diff --git a/drivers/gpu/drm/nouveau/nouveau_calc.c b/drivers/gpu/drm/nouveau/nouveau_calc.c
index ca85da784846..dad96cce5e39 100644
--- a/drivers/gpu/drm/nouveau/nouveau_calc.c
+++ b/drivers/gpu/drm/nouveau/nouveau_calc.c
@@ -198,8 +198,8 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp,
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv_fifo_info fifo_data;
struct nv_sim_state sim_data;
- int MClk = nouveau_hw_get_clock(dev, MPLL);
- int NVClk = nouveau_hw_get_clock(dev, NVPLL);
+ int MClk = nouveau_hw_get_clock(dev, PLL_MEMORY);
+ int NVClk = nouveau_hw_get_clock(dev, PLL_CORE);
uint32_t cfg1 = nvReadFB(dev, NV04_PFB_CFG1);
sim_data.pclk_khz = VClk;
@@ -234,7 +234,7 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp,
}
static void
-nv30_update_arb(int *burst, int *lwm)
+nv20_update_arb(int *burst, int *lwm)
{
unsigned int fifo_size, burst_size, graphics_lwm;
@@ -251,14 +251,14 @@ nouveau_calc_arb(struct drm_device *dev, int vclk, int bpp, int *burst, int *lwm
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- if (dev_priv->card_type < NV_30)
+ if (dev_priv->card_type < NV_20)
nv04_update_arb(dev, vclk, bpp, burst, lwm);
else if ((dev->pci_device & 0xfff0) == 0x0240 /*CHIPSET_C51*/ ||
(dev->pci_device & 0xfff0) == 0x03d0 /*CHIPSET_C512*/) {
*burst = 128;
*lwm = 0x0480;
} else
- nv30_update_arb(burst, lwm);
+ nv20_update_arb(burst, lwm);
}
static int
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
index 0480f064f2c1..373950e34814 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
@@ -48,14 +48,14 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
dev_priv->gart_info.aper_size,
NV_DMA_ACCESS_RO, &pushbuf,
NULL);
- chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
+ chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT;
} else
if (dev_priv->card_type != NV_04) {
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
dev_priv->fb_available_size,
NV_DMA_ACCESS_RO,
NV_DMA_TARGET_VIDMEM, &pushbuf);
- chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
+ chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT;
} else {
/* NV04 cmdbuf hack, from original ddx.. not sure of it's
* exact reason for existing :) PCI access to cmdbuf in
@@ -67,17 +67,11 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
dev_priv->fb_available_size,
NV_DMA_ACCESS_RO,
NV_DMA_TARGET_PCI, &pushbuf);
- chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
- }
-
- ret = nouveau_gpuobj_ref_add(dev, chan, 0, pushbuf, &chan->pushbuf);
- if (ret) {
- NV_ERROR(dev, "Error referencing pushbuf ctxdma: %d\n", ret);
- if (pushbuf != dev_priv->gart_info.sg_ctxdma)
- nouveau_gpuobj_del(dev, &pushbuf);
- return ret;
+ chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT;
}
+ nouveau_gpuobj_ref(pushbuf, &chan->pushbuf);
+ nouveau_gpuobj_ref(NULL, &pushbuf);
return 0;
}
@@ -229,7 +223,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
ret = nouveau_dma_init(chan);
if (!ret)
- ret = nouveau_fence_init(chan);
+ ret = nouveau_fence_channel_init(chan);
if (ret) {
nouveau_channel_free(chan);
return ret;
@@ -276,7 +270,7 @@ nouveau_channel_free(struct nouveau_channel *chan)
* above attempts at idling were OK, but if we failed this'll tell TTM
* we're done with the buffers.
*/
- nouveau_fence_fini(chan);
+ nouveau_fence_channel_fini(chan);
/* This will prevent pfifo from switching channels. */
pfifo->reassign(dev, false);
@@ -308,8 +302,9 @@ nouveau_channel_free(struct nouveau_channel *chan)
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
/* Release the channel's resources */
- nouveau_gpuobj_ref_del(dev, &chan->pushbuf);
+ nouveau_gpuobj_ref(NULL, &chan->pushbuf);
if (chan->pushbuf_bo) {
+ nouveau_bo_unmap(chan->pushbuf_bo);
nouveau_bo_unpin(chan->pushbuf_bo);
nouveau_bo_ref(NULL, &chan->pushbuf_bo);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index fc737037f751..0871495096fa 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -76,6 +76,22 @@ nouveau_encoder_connector_get(struct nouveau_encoder *encoder)
return NULL;
}
+/*TODO: This could use improvement, and learn to handle the fixed
+ * BIOS tables etc. It's fine currently, for its only user.
+ */
+int
+nouveau_connector_bpp(struct drm_connector *connector)
+{
+ struct nouveau_connector *nv_connector = nouveau_connector(connector);
+
+ if (nv_connector->edid && nv_connector->edid->revision >= 4) {
+ u8 bpc = ((nv_connector->edid->input & 0x70) >> 3) + 4;
+ if (bpc > 4)
+ return bpc;
+ }
+
+ return 18;
+}
static void
nouveau_connector_destroy(struct drm_connector *drm_connector)
@@ -130,6 +146,36 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
return NULL;
}
+static struct nouveau_encoder *
+nouveau_connector_of_detect(struct drm_connector *connector)
+{
+#ifdef __powerpc__
+ struct drm_device *dev = connector->dev;
+ struct nouveau_connector *nv_connector = nouveau_connector(connector);
+ struct nouveau_encoder *nv_encoder;
+ struct device_node *cn, *dn = pci_device_to_OF_node(dev->pdev);
+
+ if (!dn ||
+ !((nv_encoder = find_encoder_by_type(connector, OUTPUT_TMDS)) ||
+ (nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG))))
+ return NULL;
+
+ for_each_child_of_node(dn, cn) {
+ const char *name = of_get_property(cn, "name", NULL);
+ const void *edid = of_get_property(cn, "EDID", NULL);
+ int idx = name ? name[strlen(name) - 1] - 'A' : 0;
+
+ if (nv_encoder->dcb->i2c_index == idx && edid) {
+ nv_connector->edid =
+ kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
+ of_node_put(cn);
+ return nv_encoder;
+ }
+ }
+#endif
+ return NULL;
+}
+
static void
nouveau_connector_set_encoder(struct drm_connector *connector,
struct nouveau_encoder *nv_encoder)
@@ -225,6 +271,12 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
return connector_status_connected;
}
+ nv_encoder = nouveau_connector_of_detect(connector);
+ if (nv_encoder) {
+ nouveau_connector_set_encoder(connector, nv_encoder);
+ return connector_status_connected;
+ }
+
detect_analog:
nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG);
if (!nv_encoder && !nouveau_tv_disable)
@@ -630,7 +682,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
else
max_clock = nv_encoder->dp.link_nr * 162000;
- clock *= 3;
+ clock = clock * nouveau_connector_bpp(connector) / 8;
break;
default:
BUG_ON(1);
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
index 0d2e668ccfe5..c21ed6b16f88 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -55,4 +55,7 @@ nouveau_connector_create(struct drm_device *, int index);
void
nouveau_connector_set_polling(struct drm_connector *);
+int
+nouveau_connector_bpp(struct drm_connector *);
+
#endif /* __NOUVEAU_CONNECTOR_H__ */
diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
index 7933de4aff2e..8e1592368cce 100644
--- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c
+++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
@@ -157,7 +157,23 @@ nouveau_debugfs_vbios_image(struct seq_file *m, void *data)
return 0;
}
+static int
+nouveau_debugfs_evict_vram(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_nouveau_private *dev_priv = node->minor->dev->dev_private;
+ int ret;
+
+ ret = ttm_bo_evict_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
+ if (ret)
+ seq_printf(m, "failed: %d", ret);
+ else
+ seq_printf(m, "succeeded\n");
+ return 0;
+}
+
static struct drm_info_list nouveau_debugfs_list[] = {
+ { "evict_vram", nouveau_debugfs_evict_vram, 0, NULL },
{ "chipset", nouveau_debugfs_chipset_info, 0, NULL },
{ "memory", nouveau_debugfs_memory_info, 0, NULL },
{ "vbios.rom", nouveau_debugfs_vbios_image, 0, NULL },
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c
index 2e3c6caa97ee..82581e600dcd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.c
@@ -28,6 +28,7 @@
#include "drm.h"
#include "nouveau_drv.h"
#include "nouveau_dma.h"
+#include "nouveau_ramht.h"
void
nouveau_dma_pre_init(struct nouveau_channel *chan)
@@ -58,26 +59,17 @@ nouveau_dma_init(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *m2mf = NULL;
- struct nouveau_gpuobj *nvsw = NULL;
+ struct nouveau_gpuobj *obj = NULL;
int ret, i;
/* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */
ret = nouveau_gpuobj_gr_new(chan, dev_priv->card_type < NV_50 ?
- 0x0039 : 0x5039, &m2mf);
+ 0x0039 : 0x5039, &obj);
if (ret)
return ret;
- ret = nouveau_gpuobj_ref_add(dev, chan, NvM2MF, m2mf, NULL);
- if (ret)
- return ret;
-
- /* Create an NV_SW object for various sync purposes */
- ret = nouveau_gpuobj_sw_new(chan, NV_SW, &nvsw);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_ref_add(dev, chan, NvSw, nvsw, NULL);
+ ret = nouveau_ramht_insert(chan, NvM2MF, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
if (ret)
return ret;
@@ -91,11 +83,6 @@ nouveau_dma_init(struct nouveau_channel *chan)
if (ret)
return ret;
- /* Map M2MF notifier object - fbcon. */
- ret = nouveau_bo_map(chan->notifier_bo);
- if (ret)
- return ret;
-
/* Insert NOPS for NOUVEAU_DMA_SKIPS */
ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
if (ret)
@@ -113,13 +100,6 @@ nouveau_dma_init(struct nouveau_channel *chan)
BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
OUT_RING(chan, NvNotify0);
- /* Initialise NV_SW */
- ret = RING_SPACE(chan, 2);
- if (ret)
- return ret;
- BEGIN_RING(chan, NvSubSw, 0, 1);
- OUT_RING(chan, NvSw);
-
/* Sit back and pray the channel works.. */
FIRE_RING(chan);
@@ -217,7 +197,7 @@ nv50_dma_push_wait(struct nouveau_channel *chan, int count)
chan->dma.ib_free = get - chan->dma.ib_put;
if (chan->dma.ib_free <= 0)
- chan->dma.ib_free += chan->dma.ib_max + 1;
+ chan->dma.ib_free += chan->dma.ib_max;
}
return 0;
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h
index 8b05c15866d5..d578c21d3c8d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.h
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.h
@@ -72,6 +72,7 @@ enum {
NvGdiRect = 0x8000000c,
NvImageBlit = 0x8000000d,
NvSw = 0x8000000e,
+ NvSema = 0x8000000f,
/* G80+ display objects */
NvEvoVRAM = 0x01000000,
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 8a1b188b4cd1..4562f309ae3d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -317,7 +317,8 @@ train:
return false;
config[0] = nv_encoder->dp.link_nr;
- if (nv_encoder->dp.dpcd_version >= 0x11)
+ if (nv_encoder->dp.dpcd_version >= 0x11 &&
+ nv_encoder->dp.enhanced_frame)
config[0] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
ret = nouveau_dp_lane_count_set(encoder, config[0]);
@@ -468,10 +469,12 @@ nouveau_dp_detect(struct drm_encoder *encoder)
!nv_encoder->dcb->dpconf.link_bw)
nv_encoder->dp.link_bw = DP_LINK_BW_1_62;
- nv_encoder->dp.link_nr = dpcd[2] & 0xf;
+ nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK;
if (nv_encoder->dp.link_nr > nv_encoder->dcb->dpconf.link_nr)
nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr;
+ nv_encoder->dp.enhanced_frame = (dpcd[2] & DP_ENHANCED_FRAME_CAP);
+
return true;
}
@@ -524,7 +527,8 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x80000000);
nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl);
nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x00010000);
- if (!nv_wait(NV50_AUXCH_CTRL(index), 0x00010000, 0x00000000)) {
+ if (!nv_wait(dev, NV50_AUXCH_CTRL(index),
+ 0x00010000, 0x00000000)) {
NV_ERROR(dev, "expected bit 16 == 0, got 0x%08x\n",
nv_rd32(dev, NV50_AUXCH_CTRL(index)));
ret = -EBUSY;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index eb15345162a0..90875494a65a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -31,13 +31,14 @@
#include "nouveau_hw.h"
#include "nouveau_fb.h"
#include "nouveau_fbcon.h"
+#include "nouveau_pm.h"
#include "nv50_display.h"
#include "drm_pciids.h"
-MODULE_PARM_DESC(noagp, "Disable AGP");
-int nouveau_noagp;
-module_param_named(noagp, nouveau_noagp, int, 0400);
+MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)");
+int nouveau_agpmode = -1;
+module_param_named(agpmode, nouveau_agpmode, int, 0400);
MODULE_PARM_DESC(modeset, "Enable kernel modesetting");
static int nouveau_modeset = -1; /* kms */
@@ -79,6 +80,10 @@ MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration");
int nouveau_nofbaccel = 0;
module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400);
+MODULE_PARM_DESC(force_post, "Force POST");
+int nouveau_force_post = 0;
+module_param_named(force_post, nouveau_force_post, int, 0400);
+
MODULE_PARM_DESC(override_conntype, "Ignore DCB connector type");
int nouveau_override_conntype = 0;
module_param_named(override_conntype, nouveau_override_conntype, int, 0400);
@@ -102,6 +107,14 @@ MODULE_PARM_DESC(reg_debug, "Register access debug bitmask:\n"
int nouveau_reg_debug;
module_param_named(reg_debug, nouveau_reg_debug, int, 0600);
+MODULE_PARM_DESC(perflvl, "Performance level (default: boot)\n");
+char *nouveau_perflvl;
+module_param_named(perflvl, nouveau_perflvl, charp, 0400);
+
+MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)\n");
+int nouveau_perflvl_wr;
+module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400);
+
int nouveau_fbpercrtc;
#if 0
module_param_named(fbpercrtc, nouveau_fbpercrtc, int, 0400);
@@ -271,6 +284,8 @@ nouveau_pci_resume(struct pci_dev *pdev)
if (ret)
return ret;
+ nouveau_pm_resume(dev);
+
if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
ret = nouveau_mem_init_agp(dev);
if (ret) {
@@ -379,8 +394,6 @@ static struct drm_driver driver = {
.irq_uninstall = nouveau_irq_uninstall,
.irq_handler = nouveau_irq_handler,
.reclaim_buffers = drm_core_reclaim_buffers,
- .get_map_ofs = drm_core_get_map_ofs,
- .get_reg_ofs = drm_core_get_reg_ofs,
.ioctls = nouveau_ioctls,
.fops = {
.owner = THIS_MODULE,
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index b1be617373b6..3a07e580d27a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -133,22 +133,24 @@ enum nouveau_flags {
#define NVOBJ_ENGINE_DISPLAY 2
#define NVOBJ_ENGINE_INT 0xdeadbeef
-#define NVOBJ_FLAG_ALLOW_NO_REFS (1 << 0)
#define NVOBJ_FLAG_ZERO_ALLOC (1 << 1)
#define NVOBJ_FLAG_ZERO_FREE (1 << 2)
-#define NVOBJ_FLAG_FAKE (1 << 3)
struct nouveau_gpuobj {
+ struct drm_device *dev;
+ struct kref refcount;
struct list_head list;
- struct nouveau_channel *im_channel;
struct drm_mm_node *im_pramin;
struct nouveau_bo *im_backing;
- uint32_t im_backing_start;
uint32_t *im_backing_suspend;
int im_bound;
uint32_t flags;
- int refcount;
+
+ u32 size;
+ u32 pinst;
+ u32 cinst;
+ u64 vinst;
uint32_t engine;
uint32_t class;
@@ -157,16 +159,6 @@ struct nouveau_gpuobj {
void *priv;
};
-struct nouveau_gpuobj_ref {
- struct list_head list;
-
- struct nouveau_gpuobj *gpuobj;
- uint32_t instance;
-
- struct nouveau_channel *channel;
- int handle;
-};
-
struct nouveau_channel {
struct drm_device *dev;
int id;
@@ -192,33 +184,32 @@ struct nouveau_channel {
} fence;
/* DMA push buffer */
- struct nouveau_gpuobj_ref *pushbuf;
- struct nouveau_bo *pushbuf_bo;
- uint32_t pushbuf_base;
+ struct nouveau_gpuobj *pushbuf;
+ struct nouveau_bo *pushbuf_bo;
+ uint32_t pushbuf_base;
/* Notifier memory */
struct nouveau_bo *notifier_bo;
struct drm_mm notifier_heap;
/* PFIFO context */
- struct nouveau_gpuobj_ref *ramfc;
- struct nouveau_gpuobj_ref *cache;
+ struct nouveau_gpuobj *ramfc;
+ struct nouveau_gpuobj *cache;
/* PGRAPH context */
/* XXX may be merge 2 pointers as private data ??? */
- struct nouveau_gpuobj_ref *ramin_grctx;
+ struct nouveau_gpuobj *ramin_grctx;
void *pgraph_ctx;
/* NV50 VM */
- struct nouveau_gpuobj *vm_pd;
- struct nouveau_gpuobj_ref *vm_gart_pt;
- struct nouveau_gpuobj_ref *vm_vram_pt[NV50_VM_VRAM_NR];
+ struct nouveau_gpuobj *vm_pd;
+ struct nouveau_gpuobj *vm_gart_pt;
+ struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
/* Objects */
- struct nouveau_gpuobj_ref *ramin; /* Private instmem */
- struct drm_mm ramin_heap; /* Private PRAMIN heap */
- struct nouveau_gpuobj_ref *ramht; /* Hash table */
- struct list_head ramht_refs; /* Objects referenced by RAMHT */
+ struct nouveau_gpuobj *ramin; /* Private instmem */
+ struct drm_mm ramin_heap; /* Private PRAMIN heap */
+ struct nouveau_ramht *ramht; /* Hash table */
/* GPU object info for stuff used in-kernel (mm_enabled) */
uint32_t m2mf_ntfy;
@@ -296,7 +287,7 @@ struct nouveau_fb_engine {
struct nouveau_fifo_engine {
int channels;
- struct nouveau_gpuobj_ref *playlist[2];
+ struct nouveau_gpuobj *playlist[2];
int cur_playlist;
int (*init)(struct drm_device *);
@@ -305,7 +296,6 @@ struct nouveau_fifo_engine {
void (*disable)(struct drm_device *);
void (*enable)(struct drm_device *);
bool (*reassign)(struct drm_device *, bool enable);
- bool (*cache_flush)(struct drm_device *dev);
bool (*cache_pull)(struct drm_device *dev, bool enable);
int (*channel_id)(struct drm_device *);
@@ -334,7 +324,7 @@ struct nouveau_pgraph_engine {
int grctx_size;
/* NV2x/NV3x context table (0x400780) */
- struct nouveau_gpuobj_ref *ctx_table;
+ struct nouveau_gpuobj *ctx_table;
int (*init)(struct drm_device *);
void (*takedown)(struct drm_device *);
@@ -369,6 +359,91 @@ struct nouveau_gpio_engine {
void (*irq_enable)(struct drm_device *, enum dcb_gpio_tag, bool on);
};
+struct nouveau_pm_voltage_level {
+ u8 voltage;
+ u8 vid;
+};
+
+struct nouveau_pm_voltage {
+ bool supported;
+ u8 vid_mask;
+
+ struct nouveau_pm_voltage_level *level;
+ int nr_level;
+};
+
+#define NOUVEAU_PM_MAX_LEVEL 8
+struct nouveau_pm_level {
+ struct device_attribute dev_attr;
+ char name[32];
+ int id;
+
+ u32 core;
+ u32 memory;
+ u32 shader;
+ u32 unk05;
+
+ u8 voltage;
+ u8 fanspeed;
+
+ u16 memscript;
+};
+
+struct nouveau_pm_temp_sensor_constants {
+ u16 offset_constant;
+ s16 offset_mult;
+ u16 offset_div;
+ u16 slope_mult;
+ u16 slope_div;
+};
+
+struct nouveau_pm_threshold_temp {
+ s16 critical;
+ s16 down_clock;
+ s16 fan_boost;
+};
+
+struct nouveau_pm_memtiming {
+ u32 reg_100220;
+ u32 reg_100224;
+ u32 reg_100228;
+ u32 reg_10022c;
+ u32 reg_100230;
+ u32 reg_100234;
+ u32 reg_100238;
+ u32 reg_10023c;
+};
+
+struct nouveau_pm_memtimings {
+ bool supported;
+ struct nouveau_pm_memtiming *timing;
+ int nr_timing;
+};
+
+struct nouveau_pm_engine {
+ struct nouveau_pm_voltage voltage;
+ struct nouveau_pm_level perflvl[NOUVEAU_PM_MAX_LEVEL];
+ int nr_perflvl;
+ struct nouveau_pm_memtimings memtimings;
+ struct nouveau_pm_temp_sensor_constants sensor_constants;
+ struct nouveau_pm_threshold_temp threshold_temp;
+
+ struct nouveau_pm_level boot;
+ struct nouveau_pm_level *cur;
+
+ struct device *hwmon;
+
+ int (*clock_get)(struct drm_device *, u32 id);
+ void *(*clock_pre)(struct drm_device *, struct nouveau_pm_level *,
+ u32 id, int khz);
+ void (*clock_set)(struct drm_device *, void *);
+ int (*voltage_get)(struct drm_device *);
+ int (*voltage_set)(struct drm_device *, int voltage);
+ int (*fanspeed_get)(struct drm_device *);
+ int (*fanspeed_set)(struct drm_device *, int fanspeed);
+ int (*temp_get)(struct drm_device *);
+};
+
struct nouveau_engine {
struct nouveau_instmem_engine instmem;
struct nouveau_mc_engine mc;
@@ -378,6 +453,7 @@ struct nouveau_engine {
struct nouveau_fifo_engine fifo;
struct nouveau_display_engine display;
struct nouveau_gpio_engine gpio;
+ struct nouveau_pm_engine pm;
};
struct nouveau_pll_vals {
@@ -522,8 +598,14 @@ struct drm_nouveau_private {
int flags;
void __iomem *mmio;
+
+ spinlock_t ramin_lock;
void __iomem *ramin;
- uint32_t ramin_size;
+ u32 ramin_size;
+ u32 ramin_base;
+ bool ramin_available;
+ struct drm_mm ramin_heap;
+ struct list_head gpuobj_list;
struct nouveau_bo *vga_ram;
@@ -540,6 +622,12 @@ struct drm_nouveau_private {
atomic_t validate_sequence;
} ttm;
+ struct {
+ spinlock_t lock;
+ struct drm_mm heap;
+ struct nouveau_bo *bo;
+ } fence;
+
int fifo_alloc_count;
struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR];
@@ -550,15 +638,11 @@ struct drm_nouveau_private {
spinlock_t context_switch_lock;
/* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */
- struct nouveau_gpuobj *ramht;
+ struct nouveau_ramht *ramht;
+ struct nouveau_gpuobj *ramfc;
+ struct nouveau_gpuobj *ramro;
+
uint32_t ramin_rsvd_vram;
- uint32_t ramht_offset;
- uint32_t ramht_size;
- uint32_t ramht_bits;
- uint32_t ramfc_offset;
- uint32_t ramfc_size;
- uint32_t ramro_offset;
- uint32_t ramro_size;
struct {
enum {
@@ -576,14 +660,12 @@ struct drm_nouveau_private {
} gart_info;
/* nv10-nv40 tiling regions */
- struct {
- struct nouveau_tile_reg reg[NOUVEAU_MAX_TILE_NR];
- spinlock_t lock;
- } tile;
+ struct nouveau_tile_reg tile[NOUVEAU_MAX_TILE_NR];
/* VRAM/fb configuration */
uint64_t vram_size;
uint64_t vram_sys_base;
+ u32 vram_rblock_size;
uint64_t fb_phys;
uint64_t fb_available_size;
@@ -600,10 +682,6 @@ struct drm_nouveau_private {
struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
int vm_vram_pt_nr;
- struct drm_mm ramin_heap;
-
- struct list_head gpuobj_list;
-
struct nvbios vbios;
struct nv04_mode_state mode_reg;
@@ -634,6 +712,12 @@ struct drm_nouveau_private {
};
static inline struct drm_nouveau_private *
+nouveau_private(struct drm_device *dev)
+{
+ return dev->dev_private;
+}
+
+static inline struct drm_nouveau_private *
nouveau_bdev(struct ttm_bo_device *bd)
{
return container_of(bd, struct drm_nouveau_private, ttm.bdev);
@@ -669,7 +753,7 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo)
} while (0)
/* nouveau_drv.c */
-extern int nouveau_noagp;
+extern int nouveau_agpmode;
extern int nouveau_duallink;
extern int nouveau_uscript_lvds;
extern int nouveau_uscript_tmds;
@@ -683,7 +767,10 @@ extern char *nouveau_vbios;
extern int nouveau_ignorelid;
extern int nouveau_nofbaccel;
extern int nouveau_noaccel;
+extern int nouveau_force_post;
extern int nouveau_override_conntype;
+extern char *nouveau_perflvl;
+extern int nouveau_perflvl_wr;
extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state);
extern int nouveau_pci_resume(struct pci_dev *pdev);
@@ -704,8 +791,10 @@ extern bool nouveau_wait_for_idle(struct drm_device *);
extern int nouveau_card_init(struct drm_device *);
/* nouveau_mem.c */
-extern int nouveau_mem_detect(struct drm_device *dev);
-extern int nouveau_mem_init(struct drm_device *);
+extern int nouveau_mem_vram_init(struct drm_device *);
+extern void nouveau_mem_vram_fini(struct drm_device *);
+extern int nouveau_mem_gart_init(struct drm_device *);
+extern void nouveau_mem_gart_fini(struct drm_device *);
extern int nouveau_mem_init_agp(struct drm_device *);
extern int nouveau_mem_reset_agp(struct drm_device *);
extern void nouveau_mem_close(struct drm_device *);
@@ -749,7 +838,6 @@ extern void nouveau_channel_free(struct nouveau_channel *);
extern int nouveau_gpuobj_early_init(struct drm_device *);
extern int nouveau_gpuobj_init(struct drm_device *);
extern void nouveau_gpuobj_takedown(struct drm_device *);
-extern void nouveau_gpuobj_late_takedown(struct drm_device *);
extern int nouveau_gpuobj_suspend(struct drm_device *dev);
extern void nouveau_gpuobj_suspend_cleanup(struct drm_device *dev);
extern void nouveau_gpuobj_resume(struct drm_device *dev);
@@ -759,24 +847,11 @@ extern void nouveau_gpuobj_channel_takedown(struct nouveau_channel *);
extern int nouveau_gpuobj_new(struct drm_device *, struct nouveau_channel *,
uint32_t size, int align, uint32_t flags,
struct nouveau_gpuobj **);
-extern int nouveau_gpuobj_del(struct drm_device *, struct nouveau_gpuobj **);
-extern int nouveau_gpuobj_ref_add(struct drm_device *, struct nouveau_channel *,
- uint32_t handle, struct nouveau_gpuobj *,
- struct nouveau_gpuobj_ref **);
-extern int nouveau_gpuobj_ref_del(struct drm_device *,
- struct nouveau_gpuobj_ref **);
-extern int nouveau_gpuobj_ref_find(struct nouveau_channel *, uint32_t handle,
- struct nouveau_gpuobj_ref **ref_ret);
-extern int nouveau_gpuobj_new_ref(struct drm_device *,
- struct nouveau_channel *alloc_chan,
- struct nouveau_channel *ref_chan,
- uint32_t handle, uint32_t size, int align,
- uint32_t flags, struct nouveau_gpuobj_ref **);
-extern int nouveau_gpuobj_new_fake(struct drm_device *,
- uint32_t p_offset, uint32_t b_offset,
- uint32_t size, uint32_t flags,
- struct nouveau_gpuobj **,
- struct nouveau_gpuobj_ref**);
+extern void nouveau_gpuobj_ref(struct nouveau_gpuobj *,
+ struct nouveau_gpuobj **);
+extern int nouveau_gpuobj_new_fake(struct drm_device *, u32 pinst, u64 vinst,
+ u32 size, u32 flags,
+ struct nouveau_gpuobj **);
extern int nouveau_gpuobj_dma_new(struct nouveau_channel *, int class,
uint64_t offset, uint64_t size, int access,
int target, struct nouveau_gpuobj **);
@@ -879,6 +954,7 @@ extern struct dcb_gpio_entry *nouveau_bios_gpio_entry(struct drm_device *,
enum dcb_gpio_tag);
extern struct dcb_connector_table_entry *
nouveau_bios_connector_entry(struct drm_device *, int index);
+extern u32 get_pll_register(struct drm_device *, enum pll_types);
extern int get_pll_limits(struct drm_device *, uint32_t limit_match,
struct pll_lims *);
extern int nouveau_bios_run_display_table(struct drm_device *,
@@ -925,10 +1001,10 @@ extern int nv40_fb_init(struct drm_device *);
extern void nv40_fb_takedown(struct drm_device *);
extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t,
uint32_t, uint32_t);
-
/* nv50_fb.c */
extern int nv50_fb_init(struct drm_device *);
extern void nv50_fb_takedown(struct drm_device *);
+extern void nv50_fb_vm_trap(struct drm_device *, int display, const char *);
/* nvc0_fb.c */
extern int nvc0_fb_init(struct drm_device *);
@@ -939,7 +1015,6 @@ extern int nv04_fifo_init(struct drm_device *);
extern void nv04_fifo_disable(struct drm_device *);
extern void nv04_fifo_enable(struct drm_device *);
extern bool nv04_fifo_reassign(struct drm_device *, bool);
-extern bool nv04_fifo_cache_flush(struct drm_device *);
extern bool nv04_fifo_cache_pull(struct drm_device *, bool);
extern int nv04_fifo_channel_id(struct drm_device *);
extern int nv04_fifo_create_context(struct nouveau_channel *);
@@ -977,7 +1052,6 @@ extern void nvc0_fifo_takedown(struct drm_device *);
extern void nvc0_fifo_disable(struct drm_device *);
extern void nvc0_fifo_enable(struct drm_device *);
extern bool nvc0_fifo_reassign(struct drm_device *, bool);
-extern bool nvc0_fifo_cache_flush(struct drm_device *);
extern bool nvc0_fifo_cache_pull(struct drm_device *, bool);
extern int nvc0_fifo_channel_id(struct drm_device *);
extern int nvc0_fifo_create_context(struct nouveau_channel *);
@@ -1169,15 +1243,21 @@ extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *);
/* nouveau_fence.c */
struct nouveau_fence;
-extern int nouveau_fence_init(struct nouveau_channel *);
-extern void nouveau_fence_fini(struct nouveau_channel *);
+extern int nouveau_fence_init(struct drm_device *);
+extern void nouveau_fence_fini(struct drm_device *);
+extern int nouveau_fence_channel_init(struct nouveau_channel *);
+extern void nouveau_fence_channel_fini(struct nouveau_channel *);
extern void nouveau_fence_update(struct nouveau_channel *);
extern int nouveau_fence_new(struct nouveau_channel *, struct nouveau_fence **,
bool emit);
extern int nouveau_fence_emit(struct nouveau_fence *);
+extern void nouveau_fence_work(struct nouveau_fence *fence,
+ void (*work)(void *priv, bool signalled),
+ void *priv);
struct nouveau_channel *nouveau_fence_channel(struct nouveau_fence *);
extern bool nouveau_fence_signalled(void *obj, void *arg);
extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr);
+extern int nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *);
extern int nouveau_fence_flush(void *obj, void *arg);
extern void nouveau_fence_unref(void **obj);
extern void *nouveau_fence_ref(void *obj);
@@ -1255,12 +1335,11 @@ static inline void nv_wr32(struct drm_device *dev, unsigned reg, u32 val)
iowrite32_native(val, dev_priv->mmio + reg);
}
-static inline void nv_mask(struct drm_device *dev, u32 reg, u32 mask, u32 val)
+static inline u32 nv_mask(struct drm_device *dev, u32 reg, u32 mask, u32 val)
{
u32 tmp = nv_rd32(dev, reg);
- tmp &= ~mask;
- tmp |= val;
- nv_wr32(dev, reg, tmp);
+ nv_wr32(dev, reg, (tmp & ~mask) | val);
+ return tmp;
}
static inline u8 nv_rd08(struct drm_device *dev, unsigned reg)
@@ -1275,7 +1354,7 @@ static inline void nv_wr08(struct drm_device *dev, unsigned reg, u8 val)
iowrite8(val, dev_priv->mmio + reg);
}
-#define nv_wait(reg, mask, val) \
+#define nv_wait(dev, reg, mask, val) \
nouveau_wait_until(dev, 2000000000ULL, (reg), (mask), (val))
/* PRAMIN access */
@@ -1292,17 +1371,8 @@ static inline void nv_wi32(struct drm_device *dev, unsigned offset, u32 val)
}
/* object access */
-static inline u32 nv_ro32(struct drm_device *dev, struct nouveau_gpuobj *obj,
- unsigned index)
-{
- return nv_ri32(dev, obj->im_pramin->start + index * 4);
-}
-
-static inline void nv_wo32(struct drm_device *dev, struct nouveau_gpuobj *obj,
- unsigned index, u32 val)
-{
- nv_wi32(dev, obj->im_pramin->start + index * 4, val);
-}
+extern u32 nv_ro32(struct nouveau_gpuobj *, u32 offset);
+extern void nv_wo32(struct nouveau_gpuobj *, u32 offset, u32 val);
/*
* Logging
@@ -1403,6 +1473,7 @@ nv_match_device(struct drm_device *dev, unsigned device,
#define NV_SW_SEMAPHORE_OFFSET 0x00000064
#define NV_SW_SEMAPHORE_ACQUIRE 0x00000068
#define NV_SW_SEMAPHORE_RELEASE 0x0000006c
+#define NV_SW_YIELD 0x00000080
#define NV_SW_DMA_VBLSEM 0x0000018c
#define NV_SW_VBLSEM_OFFSET 0x00000400
#define NV_SW_VBLSEM_RELEASE_VALUE 0x00000404
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
index 7c82d68bc155..ae69b61d93db 100644
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -55,6 +55,7 @@ struct nouveau_encoder {
int dpcd_version;
int link_nr;
int link_bw;
+ bool enhanced_frame;
} dp;
};
};
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index dbd30b2e43fd..02a4d1fd4845 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -104,6 +104,8 @@ static struct fb_ops nouveau_fbcon_ops = {
.fb_pan_display = drm_fb_helper_pan_display,
.fb_blank = drm_fb_helper_blank,
.fb_setcmap = drm_fb_helper_setcmap,
+ .fb_debug_enter = drm_fb_helper_debug_enter,
+ .fb_debug_leave = drm_fb_helper_debug_leave,
};
static struct fb_ops nv04_fbcon_ops = {
@@ -117,6 +119,8 @@ static struct fb_ops nv04_fbcon_ops = {
.fb_pan_display = drm_fb_helper_pan_display,
.fb_blank = drm_fb_helper_blank,
.fb_setcmap = drm_fb_helper_setcmap,
+ .fb_debug_enter = drm_fb_helper_debug_enter,
+ .fb_debug_leave = drm_fb_helper_debug_leave,
};
static struct fb_ops nv50_fbcon_ops = {
@@ -130,6 +134,8 @@ static struct fb_ops nv50_fbcon_ops = {
.fb_pan_display = drm_fb_helper_pan_display,
.fb_blank = drm_fb_helper_blank,
.fb_setcmap = drm_fb_helper_setcmap,
+ .fb_debug_enter = drm_fb_helper_debug_enter,
+ .fb_debug_leave = drm_fb_helper_debug_leave,
};
static void nouveau_fbcon_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 87ac21ec23d2..441b12420bb1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -28,9 +28,11 @@
#include "drm.h"
#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
#include "nouveau_dma.h"
-#define USE_REFCNT (dev_priv->card_type >= NV_10)
+#define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10)
+#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17)
struct nouveau_fence {
struct nouveau_channel *channel;
@@ -39,6 +41,15 @@ struct nouveau_fence {
uint32_t sequence;
bool signalled;
+
+ void (*work)(void *priv, bool signalled);
+ void *priv;
+};
+
+struct nouveau_semaphore {
+ struct kref ref;
+ struct drm_device *dev;
+ struct drm_mm_node *mem;
};
static inline struct nouveau_fence *
@@ -59,14 +70,13 @@ nouveau_fence_del(struct kref *ref)
void
nouveau_fence_update(struct nouveau_channel *chan)
{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
- struct list_head *entry, *tmp;
- struct nouveau_fence *fence;
+ struct drm_device *dev = chan->dev;
+ struct nouveau_fence *tmp, *fence;
uint32_t sequence;
spin_lock(&chan->fence.lock);
- if (USE_REFCNT)
+ if (USE_REFCNT(dev))
sequence = nvchan_rd32(chan, 0x48);
else
sequence = atomic_read(&chan->fence.last_sequence_irq);
@@ -75,12 +85,14 @@ nouveau_fence_update(struct nouveau_channel *chan)
goto out;
chan->fence.sequence_ack = sequence;
- list_for_each_safe(entry, tmp, &chan->fence.pending) {
- fence = list_entry(entry, struct nouveau_fence, entry);
-
+ list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
sequence = fence->sequence;
fence->signalled = true;
list_del(&fence->entry);
+
+ if (unlikely(fence->work))
+ fence->work(fence->priv, true);
+
kref_put(&fence->refcount, nouveau_fence_del);
if (sequence == chan->fence.sequence_ack)
@@ -121,8 +133,8 @@ nouveau_fence_channel(struct nouveau_fence *fence)
int
nouveau_fence_emit(struct nouveau_fence *fence)
{
- struct drm_nouveau_private *dev_priv = fence->channel->dev->dev_private;
struct nouveau_channel *chan = fence->channel;
+ struct drm_device *dev = chan->dev;
int ret;
ret = RING_SPACE(chan, 2);
@@ -143,7 +155,7 @@ nouveau_fence_emit(struct nouveau_fence *fence)
list_add_tail(&fence->entry, &chan->fence.pending);
spin_unlock(&chan->fence.lock);
- BEGIN_RING(chan, NvSubSw, USE_REFCNT ? 0x0050 : 0x0150, 1);
+ BEGIN_RING(chan, NvSubSw, USE_REFCNT(dev) ? 0x0050 : 0x0150, 1);
OUT_RING(chan, fence->sequence);
FIRE_RING(chan);
@@ -151,6 +163,25 @@ nouveau_fence_emit(struct nouveau_fence *fence)
}
void
+nouveau_fence_work(struct nouveau_fence *fence,
+ void (*work)(void *priv, bool signalled),
+ void *priv)
+{
+ BUG_ON(fence->work);
+
+ spin_lock(&fence->channel->fence.lock);
+
+ if (fence->signalled) {
+ work(priv, true);
+ } else {
+ fence->work = work;
+ fence->priv = priv;
+ }
+
+ spin_unlock(&fence->channel->fence.lock);
+}
+
+void
nouveau_fence_unref(void **sync_obj)
{
struct nouveau_fence *fence = nouveau_fence(*sync_obj);
@@ -213,6 +244,162 @@ nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
return ret;
}
+static struct nouveau_semaphore *
+alloc_semaphore(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_semaphore *sema;
+
+ if (!USE_SEMA(dev))
+ return NULL;
+
+ sema = kmalloc(sizeof(*sema), GFP_KERNEL);
+ if (!sema)
+ goto fail;
+
+ spin_lock(&dev_priv->fence.lock);
+ sema->mem = drm_mm_search_free(&dev_priv->fence.heap, 4, 0, 0);
+ if (sema->mem)
+ sema->mem = drm_mm_get_block(sema->mem, 4, 0);
+ spin_unlock(&dev_priv->fence.lock);
+
+ if (!sema->mem)
+ goto fail;
+
+ kref_init(&sema->ref);
+ sema->dev = dev;
+ nouveau_bo_wr32(dev_priv->fence.bo, sema->mem->start / 4, 0);
+
+ return sema;
+fail:
+ kfree(sema);
+ return NULL;
+}
+
+static void
+free_semaphore(struct kref *ref)
+{
+ struct nouveau_semaphore *sema =
+ container_of(ref, struct nouveau_semaphore, ref);
+ struct drm_nouveau_private *dev_priv = sema->dev->dev_private;
+
+ spin_lock(&dev_priv->fence.lock);
+ drm_mm_put_block(sema->mem);
+ spin_unlock(&dev_priv->fence.lock);
+
+ kfree(sema);
+}
+
+static void
+semaphore_work(void *priv, bool signalled)
+{
+ struct nouveau_semaphore *sema = priv;
+ struct drm_nouveau_private *dev_priv = sema->dev->dev_private;
+
+ if (unlikely(!signalled))
+ nouveau_bo_wr32(dev_priv->fence.bo, sema->mem->start / 4, 1);
+
+ kref_put(&sema->ref, free_semaphore);
+}
+
+static int
+emit_semaphore(struct nouveau_channel *chan, int method,
+ struct nouveau_semaphore *sema)
+{
+ struct drm_nouveau_private *dev_priv = sema->dev->dev_private;
+ struct nouveau_fence *fence;
+ bool smart = (dev_priv->card_type >= NV_50);
+ int ret;
+
+ ret = RING_SPACE(chan, smart ? 8 : 4);
+ if (ret)
+ return ret;
+
+ if (smart) {
+ BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1);
+ OUT_RING(chan, NvSema);
+ }
+ BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 1);
+ OUT_RING(chan, sema->mem->start);
+
+ if (smart && method == NV_SW_SEMAPHORE_ACQUIRE) {
+ /*
+ * NV50 tries to be too smart and context-switch
+ * between semaphores instead of doing a "first come,
+ * first served" strategy like previous cards
+ * do.
+ *
+ * That's bad because the ACQUIRE latency can get as
+ * large as the PFIFO context time slice in the
+ * typical DRI2 case where you have several
+ * outstanding semaphores at the same moment.
+ *
+ * If we're going to ACQUIRE, force the card to
+ * context switch before, just in case the matching
+ * RELEASE is already scheduled to be executed in
+ * another channel.
+ */
+ BEGIN_RING(chan, NvSubSw, NV_SW_YIELD, 1);
+ OUT_RING(chan, 0);
+ }
+
+ BEGIN_RING(chan, NvSubSw, method, 1);
+ OUT_RING(chan, 1);
+
+ if (smart && method == NV_SW_SEMAPHORE_RELEASE) {
+ /*
+ * Force the card to context switch, there may be
+ * another channel waiting for the semaphore we just
+ * released.
+ */
+ BEGIN_RING(chan, NvSubSw, NV_SW_YIELD, 1);
+ OUT_RING(chan, 0);
+ }
+
+ /* Delay semaphore destruction until its work is done */
+ ret = nouveau_fence_new(chan, &fence, true);
+ if (ret)
+ return ret;
+
+ kref_get(&sema->ref);
+ nouveau_fence_work(fence, semaphore_work, sema);
+ nouveau_fence_unref((void *)&fence);
+
+ return 0;
+}
+
+int
+nouveau_fence_sync(struct nouveau_fence *fence,
+ struct nouveau_channel *wchan)
+{
+ struct nouveau_channel *chan = nouveau_fence_channel(fence);
+ struct drm_device *dev = wchan->dev;
+ struct nouveau_semaphore *sema;
+ int ret;
+
+ if (likely(!fence || chan == wchan ||
+ nouveau_fence_signalled(fence, NULL)))
+ return 0;
+
+ sema = alloc_semaphore(dev);
+ if (!sema) {
+ /* Early card or broken userspace, fall back to
+ * software sync. */
+ return nouveau_fence_wait(fence, NULL, false, false);
+ }
+
+ /* Make wchan wait until it gets signalled */
+ ret = emit_semaphore(wchan, NV_SW_SEMAPHORE_ACQUIRE, sema);
+ if (ret)
+ goto out;
+
+ /* Signal the semaphore from chan */
+ ret = emit_semaphore(chan, NV_SW_SEMAPHORE_RELEASE, sema);
+out:
+ kref_put(&sema->ref, free_semaphore);
+ return ret;
+}
+
int
nouveau_fence_flush(void *sync_obj, void *sync_arg)
{
@@ -220,26 +407,123 @@ nouveau_fence_flush(void *sync_obj, void *sync_arg)
}
int
-nouveau_fence_init(struct nouveau_channel *chan)
+nouveau_fence_channel_init(struct nouveau_channel *chan)
{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *obj = NULL;
+ int ret;
+
+ /* Create an NV_SW object for various sync purposes */
+ ret = nouveau_gpuobj_sw_new(chan, NV_SW, &obj);
+ if (ret)
+ return ret;
+
+ ret = nouveau_ramht_insert(chan, NvSw, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ if (ret)
+ return ret;
+
+ ret = RING_SPACE(chan, 2);
+ if (ret)
+ return ret;
+ BEGIN_RING(chan, NvSubSw, 0, 1);
+ OUT_RING(chan, NvSw);
+
+ /* Create a DMA object for the shared cross-channel sync area. */
+ if (USE_SEMA(dev)) {
+ struct drm_mm_node *mem = dev_priv->fence.bo->bo.mem.mm_node;
+
+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
+ mem->start << PAGE_SHIFT,
+ mem->size << PAGE_SHIFT,
+ NV_DMA_ACCESS_RW,
+ NV_DMA_TARGET_VIDMEM, &obj);
+ if (ret)
+ return ret;
+
+ ret = nouveau_ramht_insert(chan, NvSema, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ if (ret)
+ return ret;
+
+ ret = RING_SPACE(chan, 2);
+ if (ret)
+ return ret;
+ BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1);
+ OUT_RING(chan, NvSema);
+ }
+
+ FIRE_RING(chan);
+
INIT_LIST_HEAD(&chan->fence.pending);
spin_lock_init(&chan->fence.lock);
atomic_set(&chan->fence.last_sequence_irq, 0);
+
return 0;
}
void
-nouveau_fence_fini(struct nouveau_channel *chan)
+nouveau_fence_channel_fini(struct nouveau_channel *chan)
{
- struct list_head *entry, *tmp;
- struct nouveau_fence *fence;
-
- list_for_each_safe(entry, tmp, &chan->fence.pending) {
- fence = list_entry(entry, struct nouveau_fence, entry);
+ struct nouveau_fence *tmp, *fence;
+ list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
fence->signalled = true;
list_del(&fence->entry);
+
+ if (unlikely(fence->work))
+ fence->work(fence->priv, false);
+
kref_put(&fence->refcount, nouveau_fence_del);
}
}
+int
+nouveau_fence_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int ret;
+
+ /* Create a shared VRAM heap for cross-channel sync. */
+ if (USE_SEMA(dev)) {
+ ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM,
+ 0, 0, false, true, &dev_priv->fence.bo);
+ if (ret)
+ return ret;
+
+ ret = nouveau_bo_pin(dev_priv->fence.bo, TTM_PL_FLAG_VRAM);
+ if (ret)
+ goto fail;
+
+ ret = nouveau_bo_map(dev_priv->fence.bo);
+ if (ret)
+ goto fail;
+
+ ret = drm_mm_init(&dev_priv->fence.heap, 0,
+ dev_priv->fence.bo->bo.mem.size);
+ if (ret)
+ goto fail;
+
+ spin_lock_init(&dev_priv->fence.lock);
+ }
+
+ return 0;
+fail:
+ nouveau_bo_unmap(dev_priv->fence.bo);
+ nouveau_bo_ref(NULL, &dev_priv->fence.bo);
+ return ret;
+}
+
+void
+nouveau_fence_fini(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (USE_SEMA(dev)) {
+ drm_mm_takedown(&dev_priv->fence.heap);
+ nouveau_bo_unmap(dev_priv->fence.bo);
+ nouveau_bo_unpin(dev_priv->fence.bo);
+ nouveau_bo_ref(NULL, &dev_priv->fence.bo);
+ }
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 19620a6709f5..5c4c929d7f74 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -362,7 +362,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
list_for_each_entry(nvbo, list, entry) {
struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index];
- ret = nouveau_bo_sync_gpu(nvbo, chan);
+ ret = nouveau_fence_sync(nvbo->bo.sync_obj, chan);
if (unlikely(ret)) {
NV_ERROR(dev, "fail pre-validate sync\n");
return ret;
@@ -385,7 +385,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
return ret;
}
- ret = nouveau_bo_sync_gpu(nvbo, chan);
+ ret = nouveau_fence_sync(nvbo->bo.sync_obj, chan);
if (unlikely(ret)) {
NV_ERROR(dev, "fail post-validate sync\n");
return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.h b/drivers/gpu/drm/nouveau/nouveau_grctx.h
index 5d39c4ce8006..4a8ad1307fa4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_grctx.h
+++ b/drivers/gpu/drm/nouveau/nouveau_grctx.h
@@ -126,7 +126,7 @@ gr_def(struct nouveau_grctx *ctx, uint32_t reg, uint32_t val)
reg = (reg - 0x00400000) / 4;
reg = (reg - ctx->ctxprog_reg) + ctx->ctxvals_base;
- nv_wo32(ctx->dev, ctx->data, reg, val);
+ nv_wo32(ctx->data, reg * 4, val);
}
#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c
index 7b613682e400..bed669a54a2d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_hw.c
+++ b/drivers/gpu/drm/nouveau/nouveau_hw.c
@@ -305,7 +305,7 @@ setPLL_double_lowregs(struct drm_device *dev, uint32_t NMNMreg,
bool mpll = Preg == 0x4020;
uint32_t oldPval = nvReadMC(dev, Preg);
uint32_t NMNM = pv->NM2 << 16 | pv->NM1;
- uint32_t Pval = (oldPval & (mpll ? ~(0x11 << 16) : ~(1 << 16))) |
+ uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) |
0xc << 28 | pv->log2P << 16;
uint32_t saved4600 = 0;
/* some cards have different maskc040s */
@@ -427,22 +427,12 @@ nouveau_hw_get_pllvals(struct drm_device *dev, enum pll_types plltype,
struct nouveau_pll_vals *pllvals)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- const uint32_t nv04_regs[MAX_PLL_TYPES] = { NV_PRAMDAC_NVPLL_COEFF,
- NV_PRAMDAC_MPLL_COEFF,
- NV_PRAMDAC_VPLL_COEFF,
- NV_RAMDAC_VPLL2 };
- const uint32_t nv40_regs[MAX_PLL_TYPES] = { 0x4000,
- 0x4020,
- NV_PRAMDAC_VPLL_COEFF,
- NV_RAMDAC_VPLL2 };
- uint32_t reg1, pll1, pll2 = 0;
+ uint32_t reg1 = get_pll_register(dev, plltype), pll1, pll2 = 0;
struct pll_lims pll_lim;
int ret;
- if (dev_priv->card_type < NV_40)
- reg1 = nv04_regs[plltype];
- else
- reg1 = nv40_regs[plltype];
+ if (reg1 == 0)
+ return -ENOENT;
pll1 = nvReadMC(dev, reg1);
@@ -491,8 +481,10 @@ int
nouveau_hw_get_clock(struct drm_device *dev, enum pll_types plltype)
{
struct nouveau_pll_vals pllvals;
+ int ret;
- if (plltype == MPLL && (dev->pci_device & 0x0ff0) == CHIPSET_NFORCE) {
+ if (plltype == PLL_MEMORY &&
+ (dev->pci_device & 0x0ff0) == CHIPSET_NFORCE) {
uint32_t mpllP;
pci_read_config_dword(pci_get_bus_and_slot(0, 3), 0x6c, &mpllP);
@@ -501,14 +493,17 @@ nouveau_hw_get_clock(struct drm_device *dev, enum pll_types plltype)
return 400000 / mpllP;
} else
- if (plltype == MPLL && (dev->pci_device & 0xff0) == CHIPSET_NFORCE2) {
+ if (plltype == PLL_MEMORY &&
+ (dev->pci_device & 0xff0) == CHIPSET_NFORCE2) {
uint32_t clock;
pci_read_config_dword(pci_get_bus_and_slot(0, 5), 0x4c, &clock);
return clock;
}
- nouveau_hw_get_pllvals(dev, plltype, &pllvals);
+ ret = nouveau_hw_get_pllvals(dev, plltype, &pllvals);
+ if (ret)
+ return ret;
return nouveau_hw_pllvals_to_clk(&pllvals);
}
@@ -526,9 +521,9 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head)
struct nouveau_pll_vals pv;
uint32_t pllreg = head ? NV_RAMDAC_VPLL2 : NV_PRAMDAC_VPLL_COEFF;
- if (get_pll_limits(dev, head ? VPLL2 : VPLL1, &pll_lim))
+ if (get_pll_limits(dev, pllreg, &pll_lim))
return;
- nouveau_hw_get_pllvals(dev, head ? VPLL2 : VPLL1, &pv);
+ nouveau_hw_get_pllvals(dev, pllreg, &pv);
if (pv.M1 >= pll_lim.vco1.min_m && pv.M1 <= pll_lim.vco1.max_m &&
pv.N1 >= pll_lim.vco1.min_n && pv.N1 <= pll_lim.vco1.max_n &&
@@ -661,7 +656,7 @@ nv_save_state_ramdac(struct drm_device *dev, int head,
if (dev_priv->card_type >= NV_10)
regp->nv10_cursync = NVReadRAMDAC(dev, head, NV_RAMDAC_NV10_CURSYNC);
- nouveau_hw_get_pllvals(dev, head ? VPLL2 : VPLL1, &regp->pllvals);
+ nouveau_hw_get_pllvals(dev, head ? PLL_VPLL1 : PLL_VPLL0, &regp->pllvals);
state->pllsel = NVReadRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT);
if (nv_two_heads(dev))
state->sel_clk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK);
@@ -866,10 +861,11 @@ nv_save_state_ext(struct drm_device *dev, int head,
rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
rd_cio_state(dev, head, regp, NV_CIO_CRE_21);
- if (dev_priv->card_type >= NV_30) {
+ if (dev_priv->card_type >= NV_20)
rd_cio_state(dev, head, regp, NV_CIO_CRE_47);
+
+ if (dev_priv->card_type >= NV_30)
rd_cio_state(dev, head, regp, 0x9f);
- }
rd_cio_state(dev, head, regp, NV_CIO_CRE_49);
rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
@@ -976,10 +972,11 @@ nv_load_state_ext(struct drm_device *dev, int head,
wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
- if (dev_priv->card_type >= NV_30) {
+ if (dev_priv->card_type >= NV_20)
wr_cio_state(dev, head, regp, NV_CIO_CRE_47);
+
+ if (dev_priv->card_type >= NV_30)
wr_cio_state(dev, head, regp, 0x9f);
- }
wr_cio_state(dev, head, regp, NV_CIO_CRE_49);
wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c
index 84614858728b..fdd7e3de79c8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.c
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c
@@ -299,7 +299,10 @@ nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr)
int
nouveau_i2c_identify(struct drm_device *dev, const char *what,
- struct i2c_board_info *info, int index)
+ struct i2c_board_info *info,
+ bool (*match)(struct nouveau_i2c_chan *,
+ struct i2c_board_info *),
+ int index)
{
struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, index);
int i;
@@ -307,7 +310,8 @@ nouveau_i2c_identify(struct drm_device *dev, const char *what,
NV_DEBUG(dev, "Probing %ss on I2C bus: %d\n", what, index);
for (i = 0; info[i].addr; i++) {
- if (nouveau_probe_i2c_addr(i2c, info[i].addr)) {
+ if (nouveau_probe_i2c_addr(i2c, info[i].addr) &&
+ (!match || match(i2c, &info[i]))) {
NV_INFO(dev, "Detected %s: %s\n", what, info[i].type);
return i;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.h b/drivers/gpu/drm/nouveau/nouveau_i2c.h
index f71cb32f7571..422b62fd8272 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.h
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.h
@@ -24,7 +24,6 @@
#define __NOUVEAU_I2C_H__
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
#include "drm_dp_helper.h"
@@ -44,7 +43,10 @@ void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *);
struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index);
bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr);
int nouveau_i2c_identify(struct drm_device *dev, const char *what,
- struct i2c_board_info *info, int index);
+ struct i2c_board_info *info,
+ bool (*match)(struct nouveau_i2c_chan *,
+ struct i2c_board_info *),
+ int index);
extern const struct i2c_algorithm nouveau_dp_i2c_algo;
diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
index 794b0ee30cf6..6fd51a51c608 100644
--- a/drivers/gpu/drm/nouveau/nouveau_irq.c
+++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -35,6 +35,7 @@
#include "nouveau_drm.h"
#include "nouveau_drv.h"
#include "nouveau_reg.h"
+#include "nouveau_ramht.h"
#include <linux/ratelimit.h>
/* needed for hotplug irq */
@@ -106,15 +107,16 @@ nouveau_fifo_swmthd(struct nouveau_channel *chan, uint32_t addr, uint32_t data)
const int mthd = addr & 0x1ffc;
if (mthd == 0x0000) {
- struct nouveau_gpuobj_ref *ref = NULL;
+ struct nouveau_gpuobj *gpuobj;
- if (nouveau_gpuobj_ref_find(chan, data, &ref))
+ gpuobj = nouveau_ramht_find(chan, data);
+ if (!gpuobj)
return false;
- if (ref->gpuobj->engine != NVOBJ_ENGINE_SW)
+ if (gpuobj->engine != NVOBJ_ENGINE_SW)
return false;
- chan->sw_subchannel[subc] = ref->gpuobj->class;
+ chan->sw_subchannel[subc] = gpuobj->class;
nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_rd32(dev,
NV04_PFIFO_CACHE1_ENGINE) & ~(0xf << subc * 4));
return true;
@@ -200,16 +202,45 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
}
if (status & NV_PFIFO_INTR_DMA_PUSHER) {
- NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d\n", chid);
+ u32 get = nv_rd32(dev, 0x003244);
+ u32 put = nv_rd32(dev, 0x003240);
+ u32 push = nv_rd32(dev, 0x003220);
+ u32 state = nv_rd32(dev, 0x003228);
+
+ if (dev_priv->card_type == NV_50) {
+ u32 ho_get = nv_rd32(dev, 0x003328);
+ u32 ho_put = nv_rd32(dev, 0x003320);
+ u32 ib_get = nv_rd32(dev, 0x003334);
+ u32 ib_put = nv_rd32(dev, 0x003330);
+
+ NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
+ "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
+ "State 0x%08x Push 0x%08x\n",
+ chid, ho_get, get, ho_put, put, ib_get, ib_put,
+ state, push);
+
+ /* METHOD_COUNT, in DMA_STATE on earlier chipsets */
+ nv_wr32(dev, 0x003364, 0x00000000);
+ if (get != put || ho_get != ho_put) {
+ nv_wr32(dev, 0x003244, put);
+ nv_wr32(dev, 0x003328, ho_put);
+ } else
+ if (ib_get != ib_put) {
+ nv_wr32(dev, 0x003334, ib_put);
+ }
+ } else {
+ NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x "
+ "Put 0x%08x State 0x%08x Push 0x%08x\n",
+ chid, get, put, state, push);
- status &= ~NV_PFIFO_INTR_DMA_PUSHER;
- nv_wr32(dev, NV03_PFIFO_INTR_0,
- NV_PFIFO_INTR_DMA_PUSHER);
+ if (get != put)
+ nv_wr32(dev, 0x003244, put);
+ }
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_STATE, 0x00000000);
- if (nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT) != get)
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET,
- get + 4);
+ nv_wr32(dev, 0x003228, 0x00000000);
+ nv_wr32(dev, 0x003220, 0x00000001);
+ nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
+ status &= ~NV_PFIFO_INTR_DMA_PUSHER;
}
if (status & NV_PFIFO_INTR_SEMAPHORE) {
@@ -226,6 +257,14 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
}
+ if (dev_priv->card_type == NV_50) {
+ if (status & 0x00000010) {
+ nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT");
+ status &= ~0x00000010;
+ nv_wr32(dev, 0x002100, 0x00000010);
+ }
+ }
+
if (status) {
NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
status, chid);
@@ -357,7 +396,7 @@ nouveau_graph_chid_from_grctx(struct drm_device *dev)
if (!chan || !chan->ramin_grctx)
continue;
- if (inst == chan->ramin_grctx->instance)
+ if (inst == chan->ramin_grctx->pinst)
break;
}
} else {
@@ -369,7 +408,7 @@ nouveau_graph_chid_from_grctx(struct drm_device *dev)
if (!chan || !chan->ramin)
continue;
- if (inst == chan->ramin->instance)
+ if (inst == chan->ramin->vinst)
break;
}
}
@@ -605,40 +644,6 @@ nouveau_pgraph_irq_handler(struct drm_device *dev)
nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING);
}
-static void
-nv50_pfb_vm_trap(struct drm_device *dev, int display, const char *name)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t trap[6];
- int i, ch;
- uint32_t idx = nv_rd32(dev, 0x100c90);
- if (idx & 0x80000000) {
- idx &= 0xffffff;
- if (display) {
- for (i = 0; i < 6; i++) {
- nv_wr32(dev, 0x100c90, idx | i << 24);
- trap[i] = nv_rd32(dev, 0x100c94);
- }
- for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) {
- struct nouveau_channel *chan = dev_priv->fifos[ch];
-
- if (!chan || !chan->ramin)
- continue;
-
- if (trap[1] == chan->ramin->instance >> 12)
- break;
- }
- NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x %08x channel %d\n",
- name, (trap[5]&0x100?"read":"write"),
- trap[5]&0xff, trap[4]&0xffff,
- trap[3]&0xffff, trap[0], trap[2], ch);
- }
- nv_wr32(dev, 0x100c90, idx | 0x80000000);
- } else if (display) {
- NV_INFO(dev, "%s - no VM fault?\n", name);
- }
-}
-
static struct nouveau_enum_names nv50_mp_exec_error_names[] =
{
{ 3, "STACK_UNDERFLOW" },
@@ -711,7 +716,7 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
tps++;
switch (type) {
case 6: /* texture error... unknown for now */
- nv50_pfb_vm_trap(dev, display, name);
+ nv50_fb_vm_trap(dev, display, name);
if (display) {
NV_ERROR(dev, "magic set %d:\n", i);
for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
@@ -734,7 +739,7 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14);
uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18);
uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c);
- nv50_pfb_vm_trap(dev, display, name);
+ nv50_fb_vm_trap(dev, display, name);
/* 2d engine destination */
if (ustatus & 0x00000010) {
if (display) {
@@ -817,7 +822,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
/* Known to be triggered by screwed up NOTIFY and COND... */
if (ustatus & 0x00000001) {
- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_FAULT");
+ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_FAULT");
nv_wr32(dev, 0x400500, 0);
if (nv_rd32(dev, 0x400808) & 0x80000000) {
if (display) {
@@ -842,7 +847,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
ustatus &= ~0x00000001;
}
if (ustatus & 0x00000002) {
- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_QUERY");
+ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_QUERY");
nv_wr32(dev, 0x400500, 0);
if (nv_rd32(dev, 0x40084c) & 0x80000000) {
if (display) {
@@ -884,15 +889,15 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
NV_INFO(dev, "PGRAPH_TRAP_M2MF - no ustatus?\n");
}
if (ustatus & 0x00000001) {
- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_NOTIFY");
+ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_NOTIFY");
ustatus &= ~0x00000001;
}
if (ustatus & 0x00000002) {
- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_IN");
+ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_IN");
ustatus &= ~0x00000002;
}
if (ustatus & 0x00000004) {
- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_OUT");
+ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_OUT");
ustatus &= ~0x00000004;
}
NV_INFO (dev, "PGRAPH_TRAP_M2MF - %08x %08x %08x %08x\n",
@@ -917,7 +922,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
NV_INFO(dev, "PGRAPH_TRAP_VFETCH - no ustatus?\n");
}
if (ustatus & 0x00000001) {
- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_VFETCH_FAULT");
+ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_VFETCH_FAULT");
NV_INFO (dev, "PGRAPH_TRAP_VFETCH_FAULT - %08x %08x %08x %08x\n",
nv_rd32(dev, 0x400c00),
nv_rd32(dev, 0x400c08),
@@ -939,7 +944,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - no ustatus?\n");
}
if (ustatus & 0x00000001) {
- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_STRMOUT_FAULT");
+ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_STRMOUT_FAULT");
NV_INFO (dev, "PGRAPH_TRAP_STRMOUT_FAULT - %08x %08x %08x %08x\n",
nv_rd32(dev, 0x401804),
nv_rd32(dev, 0x401808),
@@ -964,7 +969,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
NV_INFO(dev, "PGRAPH_TRAP_CCACHE - no ustatus?\n");
}
if (ustatus & 0x00000001) {
- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_CCACHE_FAULT");
+ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_CCACHE_FAULT");
NV_INFO (dev, "PGRAPH_TRAP_CCACHE_FAULT - %08x %08x %08x %08x %08x %08x %08x\n",
nv_rd32(dev, 0x405800),
nv_rd32(dev, 0x405804),
@@ -986,7 +991,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
* remaining, so try to handle it anyway. Perhaps related to that
* unknown DMA slot on tesla? */
if (status & 0x20) {
- nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_UNKC04");
+ nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_UNKC04");
ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff;
if (display)
NV_INFO(dev, "PGRAPH_TRAP_UNKC04 - Unhandled ustatus 0x%08x\n", ustatus);
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index 9689d4147686..a163c7c612e7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -35,6 +35,8 @@
#include "drm_sarea.h"
#include "nouveau_drv.h"
+#define MIN(a,b) a < b ? a : b
+
/*
* NV10-NV40 tiling helpers
*/
@@ -47,18 +49,14 @@ nv10_mem_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+ struct nouveau_tile_reg *tile = &dev_priv->tile[i];
tile->addr = addr;
tile->size = size;
tile->used = !!pitch;
nouveau_fence_unref((void **)&tile->fence);
- if (!pfifo->cache_flush(dev))
- return;
-
pfifo->reassign(dev, false);
- pfifo->cache_flush(dev);
pfifo->cache_pull(dev, false);
nouveau_wait_for_idle(dev);
@@ -76,34 +74,36 @@ nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size,
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
- struct nouveau_tile_reg *tile = dev_priv->tile.reg, *found = NULL;
- int i;
+ struct nouveau_tile_reg *found = NULL;
+ unsigned long i, flags;
- spin_lock(&dev_priv->tile.lock);
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
for (i = 0; i < pfb->num_tiles; i++) {
- if (tile[i].used)
+ struct nouveau_tile_reg *tile = &dev_priv->tile[i];
+
+ if (tile->used)
/* Tile region in use. */
continue;
- if (tile[i].fence &&
- !nouveau_fence_signalled(tile[i].fence, NULL))
+ if (tile->fence &&
+ !nouveau_fence_signalled(tile->fence, NULL))
/* Pending tile region. */
continue;
- if (max(tile[i].addr, addr) <
- min(tile[i].addr + tile[i].size, addr + size))
+ if (max(tile->addr, addr) <
+ min(tile->addr + tile->size, addr + size))
/* Kill an intersecting tile region. */
nv10_mem_set_region_tiling(dev, i, 0, 0, 0);
if (pitch && !found) {
/* Free tile region. */
nv10_mem_set_region_tiling(dev, i, addr, size, pitch);
- found = &tile[i];
+ found = tile;
}
}
- spin_unlock(&dev_priv->tile.lock);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return found;
}
@@ -169,8 +169,9 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
virt += (end - pte);
while (pte < end) {
- nv_wo32(dev, pgt, pte++, offset_l);
- nv_wo32(dev, pgt, pte++, offset_h);
+ nv_wo32(pgt, (pte * 4) + 0, offset_l);
+ nv_wo32(pgt, (pte * 4) + 4, offset_h);
+ pte += 2;
}
}
}
@@ -203,8 +204,10 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
pages -= (end - pte);
virt += (end - pte) << 15;
- while (pte < end)
- nv_wo32(dev, pgt, pte++, 0);
+ while (pte < end) {
+ nv_wo32(pgt, (pte * 4), 0);
+ pte++;
+ }
}
dev_priv->engine.instmem.flush(dev);
@@ -218,7 +221,7 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
* Cleanup everything
*/
void
-nouveau_mem_close(struct drm_device *dev)
+nouveau_mem_vram_fini(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -229,6 +232,19 @@ nouveau_mem_close(struct drm_device *dev)
nouveau_ttm_global_release(dev_priv);
+ if (dev_priv->fb_mtrr >= 0) {
+ drm_mtrr_del(dev_priv->fb_mtrr,
+ pci_resource_start(dev->pdev, 1),
+ pci_resource_len(dev->pdev, 1), DRM_MTRR_WC);
+ dev_priv->fb_mtrr = -1;
+ }
+}
+
+void
+nouveau_mem_gart_fini(struct drm_device *dev)
+{
+ nouveau_sgdma_takedown(dev);
+
if (drm_core_has_AGP(dev) && dev->agp) {
struct drm_agp_mem *entry, *tempe;
@@ -248,13 +264,6 @@ nouveau_mem_close(struct drm_device *dev)
dev->agp->acquired = 0;
dev->agp->enabled = 0;
}
-
- if (dev_priv->fb_mtrr) {
- drm_mtrr_del(dev_priv->fb_mtrr,
- pci_resource_start(dev->pdev, 1),
- pci_resource_len(dev->pdev, 1), DRM_MTRR_WC);
- dev_priv->fb_mtrr = -1;
- }
}
static uint32_t
@@ -305,8 +314,62 @@ nouveau_mem_detect_nforce(struct drm_device *dev)
return 0;
}
-/* returns the amount of FB ram in bytes */
-int
+static void
+nv50_vram_preinit(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int i, parts, colbits, rowbitsa, rowbitsb, banks;
+ u64 rowsize, predicted;
+ u32 r0, r4, rt, ru;
+
+ r0 = nv_rd32(dev, 0x100200);
+ r4 = nv_rd32(dev, 0x100204);
+ rt = nv_rd32(dev, 0x100250);
+ ru = nv_rd32(dev, 0x001540);
+ NV_DEBUG(dev, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru);
+
+ for (i = 0, parts = 0; i < 8; i++) {
+ if (ru & (0x00010000 << i))
+ parts++;
+ }
+
+ colbits = (r4 & 0x0000f000) >> 12;
+ rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
+ rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
+ banks = ((r4 & 0x01000000) ? 8 : 4);
+
+ rowsize = parts * banks * (1 << colbits) * 8;
+ predicted = rowsize << rowbitsa;
+ if (r0 & 0x00000004)
+ predicted += rowsize << rowbitsb;
+
+ if (predicted != dev_priv->vram_size) {
+ NV_WARN(dev, "memory controller reports %dMiB VRAM\n",
+ (u32)(dev_priv->vram_size >> 20));
+ NV_WARN(dev, "we calculated %dMiB VRAM\n",
+ (u32)(predicted >> 20));
+ }
+
+ dev_priv->vram_rblock_size = rowsize >> 12;
+ if (rt & 1)
+ dev_priv->vram_rblock_size *= 3;
+
+ NV_DEBUG(dev, "rblock %lld bytes\n",
+ (u64)dev_priv->vram_rblock_size << 12);
+}
+
+static void
+nvaa_vram_preinit(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ /* To our knowledge, there's no large scale reordering of pages
+ * that occurs on IGP chipsets.
+ */
+ dev_priv->vram_rblock_size = 1;
+}
+
+static int
nouveau_mem_detect(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -325,9 +388,18 @@ nouveau_mem_detect(struct drm_device *dev)
dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA);
dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32;
dev_priv->vram_size &= 0xffffffff00ll;
- if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) {
+
+ switch (dev_priv->chipset) {
+ case 0xaa:
+ case 0xac:
+ case 0xaf:
dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10);
dev_priv->vram_sys_base <<= 12;
+ nvaa_vram_preinit(dev);
+ break;
+ default:
+ nv50_vram_preinit(dev);
+ break;
}
} else {
dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20;
@@ -345,6 +417,33 @@ nouveau_mem_detect(struct drm_device *dev)
return -ENOMEM;
}
+#if __OS_HAS_AGP
+static unsigned long
+get_agp_mode(struct drm_device *dev, unsigned long mode)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ /*
+ * FW seems to be broken on nv18, it makes the card lock up
+ * randomly.
+ */
+ if (dev_priv->chipset == 0x18)
+ mode &= ~PCI_AGP_COMMAND_FW;
+
+ /*
+ * AGP mode set in the command line.
+ */
+ if (nouveau_agpmode > 0) {
+ bool agpv3 = mode & 0x8;
+ int rate = agpv3 ? nouveau_agpmode / 4 : nouveau_agpmode;
+
+ mode = (mode & ~0x7) | (rate & 0x7);
+ }
+
+ return mode;
+}
+#endif
+
int
nouveau_mem_reset_agp(struct drm_device *dev)
{
@@ -355,7 +454,8 @@ nouveau_mem_reset_agp(struct drm_device *dev)
/* First of all, disable fast writes, otherwise if it's
* already enabled in the AGP bridge and we disable the card's
* AGP controller we might be locking ourselves out of it. */
- if (nv_rd32(dev, NV04_PBUS_PCI_NV_19) & PCI_AGP_COMMAND_FW) {
+ if ((nv_rd32(dev, NV04_PBUS_PCI_NV_19) |
+ dev->agp->mode) & PCI_AGP_COMMAND_FW) {
struct drm_agp_info info;
struct drm_agp_mode mode;
@@ -363,7 +463,7 @@ nouveau_mem_reset_agp(struct drm_device *dev)
if (ret)
return ret;
- mode.mode = info.mode & ~PCI_AGP_COMMAND_FW;
+ mode.mode = get_agp_mode(dev, info.mode) & ~PCI_AGP_COMMAND_FW;
ret = drm_agp_enable(dev, mode);
if (ret)
return ret;
@@ -418,7 +518,7 @@ nouveau_mem_init_agp(struct drm_device *dev)
}
/* see agp.h for the AGPSTAT_* modes available */
- mode.mode = info.mode;
+ mode.mode = get_agp_mode(dev, info.mode);
ret = drm_agp_enable(dev, mode);
if (ret) {
NV_ERROR(dev, "Unable to enable AGP: %d\n", ret);
@@ -433,24 +533,27 @@ nouveau_mem_init_agp(struct drm_device *dev)
}
int
-nouveau_mem_init(struct drm_device *dev)
+nouveau_mem_vram_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
- int ret, dma_bits = 32;
-
- dev_priv->fb_phys = pci_resource_start(dev->pdev, 1);
- dev_priv->gart_info.type = NOUVEAU_GART_NONE;
+ int ret, dma_bits;
if (dev_priv->card_type >= NV_50 &&
pci_dma_supported(dev->pdev, DMA_BIT_MASK(40)))
dma_bits = 40;
+ else
+ dma_bits = 32;
ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(dma_bits));
- if (ret) {
- NV_ERROR(dev, "Error setting DMA mask: %d\n", ret);
+ if (ret)
return ret;
- }
+
+ ret = nouveau_mem_detect(dev);
+ if (ret)
+ return ret;
+
+ dev_priv->fb_phys = pci_resource_start(dev->pdev, 1);
ret = nouveau_ttm_global_init(dev_priv);
if (ret)
@@ -465,8 +568,6 @@ nouveau_mem_init(struct drm_device *dev)
return ret;
}
- spin_lock_init(&dev_priv->tile.lock);
-
dev_priv->fb_available_size = dev_priv->vram_size;
dev_priv->fb_mappable_pages = dev_priv->fb_available_size;
if (dev_priv->fb_mappable_pages > pci_resource_len(dev->pdev, 1))
@@ -474,7 +575,16 @@ nouveau_mem_init(struct drm_device *dev)
pci_resource_len(dev->pdev, 1);
dev_priv->fb_mappable_pages >>= PAGE_SHIFT;
- /* remove reserved space at end of vram from available amount */
+ /* reserve space at end of VRAM for PRAMIN */
+ if (dev_priv->chipset == 0x40 || dev_priv->chipset == 0x47 ||
+ dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b)
+ dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024);
+ else
+ if (dev_priv->card_type >= NV_40)
+ dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024);
+ else
+ dev_priv->ramin_rsvd_vram = (512 * 1024);
+
dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram;
dev_priv->fb_aper_free = dev_priv->fb_available_size;
@@ -495,9 +605,23 @@ nouveau_mem_init(struct drm_device *dev)
nouveau_bo_ref(NULL, &dev_priv->vga_ram);
}
- /* GART */
+ dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1),
+ pci_resource_len(dev->pdev, 1),
+ DRM_MTRR_WC);
+ return 0;
+}
+
+int
+nouveau_mem_gart_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
+ int ret;
+
+ dev_priv->gart_info.type = NOUVEAU_GART_NONE;
+
#if !defined(__powerpc__) && !defined(__ia64__)
- if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) {
+ if (drm_device_is_agp(dev) && dev->agp && nouveau_agpmode) {
ret = nouveau_mem_init_agp(dev);
if (ret)
NV_ERROR(dev, "Error initialising AGP: %d\n", ret);
@@ -523,11 +647,150 @@ nouveau_mem_init(struct drm_device *dev)
return ret;
}
- dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1),
- pci_resource_len(dev->pdev, 1),
- DRM_MTRR_WC);
-
return 0;
}
+void
+nouveau_mem_timing_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
+ struct nvbios *bios = &dev_priv->vbios;
+ struct bit_entry P;
+ u8 tUNK_0, tUNK_1, tUNK_2;
+ u8 tRP; /* Byte 3 */
+ u8 tRAS; /* Byte 5 */
+ u8 tRFC; /* Byte 7 */
+ u8 tRC; /* Byte 9 */
+ u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14;
+ u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21;
+ u8 *mem = NULL, *entry;
+ int i, recordlen, entries;
+
+ if (bios->type == NVBIOS_BIT) {
+ if (bit_table(dev, 'P', &P))
+ return;
+
+ if (P.version == 1)
+ mem = ROMPTR(bios, P.data[4]);
+ else
+ if (P.version == 2)
+ mem = ROMPTR(bios, P.data[8]);
+ else {
+ NV_WARN(dev, "unknown mem for BIT P %d\n", P.version);
+ }
+ } else {
+ NV_DEBUG(dev, "BMP version too old for memory\n");
+ return;
+ }
+
+ if (!mem) {
+ NV_DEBUG(dev, "memory timing table pointer invalid\n");
+ return;
+ }
+ if (mem[0] != 0x10) {
+ NV_WARN(dev, "memory timing table 0x%02x unknown\n", mem[0]);
+ return;
+ }
+
+ /* validate record length */
+ entries = mem[2];
+ recordlen = mem[3];
+ if (recordlen < 15) {
+ NV_ERROR(dev, "mem timing table length unknown: %d\n", mem[3]);
+ return;
+ }
+
+ /* parse vbios entries into common format */
+ memtimings->timing =
+ kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL);
+ if (!memtimings->timing)
+ return;
+
+ entry = mem + mem[1];
+ for (i = 0; i < entries; i++, entry += recordlen) {
+ struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i];
+ if (entry[0] == 0)
+ continue;
+
+ tUNK_18 = 1;
+ tUNK_19 = 1;
+ tUNK_20 = 0;
+ tUNK_21 = 0;
+ switch (MIN(recordlen,21)) {
+ case 21:
+ tUNK_21 = entry[21];
+ case 20:
+ tUNK_20 = entry[20];
+ case 19:
+ tUNK_19 = entry[19];
+ case 18:
+ tUNK_18 = entry[18];
+ default:
+ tUNK_0 = entry[0];
+ tUNK_1 = entry[1];
+ tUNK_2 = entry[2];
+ tRP = entry[3];
+ tRAS = entry[5];
+ tRFC = entry[7];
+ tRC = entry[9];
+ tUNK_10 = entry[10];
+ tUNK_11 = entry[11];
+ tUNK_12 = entry[12];
+ tUNK_13 = entry[13];
+ tUNK_14 = entry[14];
+ break;
+ }
+
+ timing->reg_100220 = (tRC << 24 | tRFC << 16 | tRAS << 8 | tRP);
+
+ /* XXX: I don't trust the -1's and +1's... they must come
+ * from somewhere! */
+ timing->reg_100224 = ((tUNK_0 + tUNK_19 + 1) << 24 |
+ tUNK_18 << 16 |
+ (tUNK_1 + tUNK_19 + 1) << 8 |
+ (tUNK_2 - 1));
+
+ timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
+ if(recordlen > 19) {
+ timing->reg_100228 += (tUNK_19 - 1) << 24;
+ } else {
+ timing->reg_100228 += tUNK_12 << 24;
+ }
+
+ /* XXX: reg_10022c */
+
+ timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
+ tUNK_13 << 8 | tUNK_13);
+
+ /* XXX: +6? */
+ timing->reg_100234 = (tRAS << 24 | (tUNK_19 + 6) << 8 | tRC);
+ if(tUNK_10 > tUNK_11) {
+ timing->reg_100234 += tUNK_10 << 16;
+ } else {
+ timing->reg_100234 += tUNK_11 << 16;
+ }
+
+ /* XXX; reg_100238, reg_10023c */
+ NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
+ timing->reg_100220, timing->reg_100224,
+ timing->reg_100228, timing->reg_10022c);
+ NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n",
+ timing->reg_100230, timing->reg_100234,
+ timing->reg_100238, timing->reg_10023c);
+ }
+
+ memtimings->nr_timing = entries;
+ memtimings->supported = true;
+}
+
+void
+nouveau_mem_timing_fini(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings;
+
+ kfree(mem->timing);
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c
index 3ec181ff50ce..2cc59f8c658b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_notifier.c
+++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c
@@ -28,6 +28,7 @@
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
int
nouveau_notifier_init_channel(struct nouveau_channel *chan)
@@ -112,7 +113,7 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
return -ENOMEM;
}
- offset = chan->notifier_bo->bo.mem.mm_node->start << PAGE_SHIFT;
+ offset = chan->notifier_bo->bo.mem.start << PAGE_SHIFT;
if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM) {
target = NV_DMA_TARGET_VIDMEM;
} else
@@ -146,11 +147,11 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
nobj->dtor = nouveau_notifier_gpuobj_dtor;
nobj->priv = mem;
- ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL);
+ ret = nouveau_ramht_insert(chan, handle, nobj);
+ nouveau_gpuobj_ref(NULL, &nobj);
if (ret) {
- nouveau_gpuobj_del(dev, &nobj);
drm_mm_put_block(mem);
- NV_ERROR(dev, "Error referencing notifier ctxdma: %d\n", ret);
+ NV_ERROR(dev, "Error adding notifier to ramht: %d\n", ret);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c
index b6bcb254f4ab..896cf8634144 100644
--- a/drivers/gpu/drm/nouveau/nouveau_object.c
+++ b/drivers/gpu/drm/nouveau/nouveau_object.c
@@ -34,6 +34,7 @@
#include "drm.h"
#include "nouveau_drv.h"
#include "nouveau_drm.h"
+#include "nouveau_ramht.h"
/* NVidia uses context objects to drive drawing operations.
@@ -65,137 +66,6 @@
The key into the hash table depends on the object handle and channel id and
is given as:
*/
-static uint32_t
-nouveau_ramht_hash_handle(struct drm_device *dev, int channel, uint32_t handle)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t hash = 0;
- int i;
-
- NV_DEBUG(dev, "ch%d handle=0x%08x\n", channel, handle);
-
- for (i = 32; i > 0; i -= dev_priv->ramht_bits) {
- hash ^= (handle & ((1 << dev_priv->ramht_bits) - 1));
- handle >>= dev_priv->ramht_bits;
- }
-
- if (dev_priv->card_type < NV_50)
- hash ^= channel << (dev_priv->ramht_bits - 4);
- hash <<= 3;
-
- NV_DEBUG(dev, "hash=0x%08x\n", hash);
- return hash;
-}
-
-static int
-nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht,
- uint32_t offset)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t ctx = nv_ro32(dev, ramht, (offset + 4)/4);
-
- if (dev_priv->card_type < NV_40)
- return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0);
- return (ctx != 0);
-}
-
-static int
-nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
- struct nouveau_channel *chan = ref->channel;
- struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL;
- uint32_t ctx, co, ho;
-
- if (!ramht) {
- NV_ERROR(dev, "No hash table!\n");
- return -EINVAL;
- }
-
- if (dev_priv->card_type < NV_40) {
- ctx = NV_RAMHT_CONTEXT_VALID | (ref->instance >> 4) |
- (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) |
- (ref->gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT);
- } else
- if (dev_priv->card_type < NV_50) {
- ctx = (ref->instance >> 4) |
- (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) |
- (ref->gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
- } else {
- if (ref->gpuobj->engine == NVOBJ_ENGINE_DISPLAY) {
- ctx = (ref->instance << 10) | 2;
- } else {
- ctx = (ref->instance >> 4) |
- ((ref->gpuobj->engine <<
- NV40_RAMHT_CONTEXT_ENGINE_SHIFT));
- }
- }
-
- co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
- do {
- if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
- NV_DEBUG(dev,
- "insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
- chan->id, co, ref->handle, ctx);
- nv_wo32(dev, ramht, (co + 0)/4, ref->handle);
- nv_wo32(dev, ramht, (co + 4)/4, ctx);
-
- list_add_tail(&ref->list, &chan->ramht_refs);
- instmem->flush(dev);
- return 0;
- }
- NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n",
- chan->id, co, nv_ro32(dev, ramht, co/4));
-
- co += 8;
- if (co >= dev_priv->ramht_size)
- co = 0;
- } while (co != ho);
-
- NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
- return -ENOMEM;
-}
-
-static void
-nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
- struct nouveau_channel *chan = ref->channel;
- struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL;
- uint32_t co, ho;
-
- if (!ramht) {
- NV_ERROR(dev, "No hash table!\n");
- return;
- }
-
- co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
- do {
- if (nouveau_ramht_entry_valid(dev, ramht, co) &&
- (ref->handle == nv_ro32(dev, ramht, (co/4)))) {
- NV_DEBUG(dev,
- "remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
- chan->id, co, ref->handle,
- nv_ro32(dev, ramht, (co + 4)));
- nv_wo32(dev, ramht, (co + 0)/4, 0x00000000);
- nv_wo32(dev, ramht, (co + 4)/4, 0x00000000);
-
- list_del(&ref->list);
- instmem->flush(dev);
- return;
- }
-
- co += 8;
- if (co >= dev_priv->ramht_size)
- co = 0;
- } while (co != ho);
- list_del(&ref->list);
-
- NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
- chan->id, ref->handle);
-}
int
nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
@@ -205,7 +75,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine = &dev_priv->engine;
struct nouveau_gpuobj *gpuobj;
- struct drm_mm *pramin = NULL;
+ struct drm_mm_node *ramin = NULL;
int ret;
NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n",
@@ -218,69 +88,102 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
if (!gpuobj)
return -ENOMEM;
NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
+ gpuobj->dev = dev;
gpuobj->flags = flags;
- gpuobj->im_channel = chan;
+ kref_init(&gpuobj->refcount);
+ gpuobj->size = size;
+ spin_lock(&dev_priv->ramin_lock);
list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+ spin_unlock(&dev_priv->ramin_lock);
- /* Choose between global instmem heap, and per-channel private
- * instmem heap. On <NV50 allow requests for private instmem
- * to be satisfied from global heap if no per-channel area
- * available.
- */
if (chan) {
NV_DEBUG(dev, "channel heap\n");
- pramin = &chan->ramin_heap;
+
+ ramin = drm_mm_search_free(&chan->ramin_heap, size, align, 0);
+ if (ramin)
+ ramin = drm_mm_get_block(ramin, size, align);
+
+ if (!ramin) {
+ nouveau_gpuobj_ref(NULL, &gpuobj);
+ return -ENOMEM;
+ }
} else {
NV_DEBUG(dev, "global heap\n");
- pramin = &dev_priv->ramin_heap;
+ /* allocate backing pages, sets vinst */
ret = engine->instmem.populate(dev, gpuobj, &size);
if (ret) {
- nouveau_gpuobj_del(dev, &gpuobj);
+ nouveau_gpuobj_ref(NULL, &gpuobj);
return ret;
}
- }
- /* Allocate a chunk of the PRAMIN aperture */
- gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0);
- if (gpuobj->im_pramin)
- gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align);
+ /* try and get aperture space */
+ do {
+ if (drm_mm_pre_get(&dev_priv->ramin_heap))
+ return -ENOMEM;
+
+ spin_lock(&dev_priv->ramin_lock);
+ ramin = drm_mm_search_free(&dev_priv->ramin_heap, size,
+ align, 0);
+ if (ramin == NULL) {
+ spin_unlock(&dev_priv->ramin_lock);
+ nouveau_gpuobj_ref(NULL, &gpuobj);
+ return ret;
+ }
- if (!gpuobj->im_pramin) {
- nouveau_gpuobj_del(dev, &gpuobj);
- return -ENOMEM;
+ ramin = drm_mm_get_block_atomic(ramin, size, align);
+ spin_unlock(&dev_priv->ramin_lock);
+ } while (ramin == NULL);
+
+ /* on nv50 it's ok to fail, we have a fallback path */
+ if (!ramin && dev_priv->card_type < NV_50) {
+ nouveau_gpuobj_ref(NULL, &gpuobj);
+ return -ENOMEM;
+ }
}
- if (!chan) {
+ /* if we got a chunk of the aperture, map pages into it */
+ gpuobj->im_pramin = ramin;
+ if (!chan && gpuobj->im_pramin && dev_priv->ramin_available) {
ret = engine->instmem.bind(dev, gpuobj);
if (ret) {
- nouveau_gpuobj_del(dev, &gpuobj);
+ nouveau_gpuobj_ref(NULL, &gpuobj);
return ret;
}
}
+ /* calculate the various different addresses for the object */
+ if (chan) {
+ gpuobj->pinst = chan->ramin->pinst;
+ if (gpuobj->pinst != ~0)
+ gpuobj->pinst += gpuobj->im_pramin->start;
+
+ if (dev_priv->card_type < NV_50) {
+ gpuobj->cinst = gpuobj->pinst;
+ } else {
+ gpuobj->cinst = gpuobj->im_pramin->start;
+ gpuobj->vinst = gpuobj->im_pramin->start +
+ chan->ramin->vinst;
+ }
+ } else {
+ if (gpuobj->im_pramin)
+ gpuobj->pinst = gpuobj->im_pramin->start;
+ else
+ gpuobj->pinst = ~0;
+ gpuobj->cinst = 0xdeadbeef;
+ }
+
if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
int i;
- for (i = 0; i < gpuobj->im_pramin->size; i += 4)
- nv_wo32(dev, gpuobj, i/4, 0);
+ for (i = 0; i < gpuobj->size; i += 4)
+ nv_wo32(gpuobj, i, 0);
engine->instmem.flush(dev);
}
- *gpuobj_ret = gpuobj;
- return 0;
-}
-
-int
-nouveau_gpuobj_early_init(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- NV_DEBUG(dev, "\n");
-
- INIT_LIST_HEAD(&dev_priv->gpuobj_list);
+ *gpuobj_ret = gpuobj;
return 0;
}
@@ -288,18 +191,12 @@ int
nouveau_gpuobj_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- int ret;
NV_DEBUG(dev, "\n");
- if (dev_priv->card_type < NV_50) {
- ret = nouveau_gpuobj_new_fake(dev,
- dev_priv->ramht_offset, ~0, dev_priv->ramht_size,
- NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ALLOW_NO_REFS,
- &dev_priv->ramht, NULL);
- if (ret)
- return ret;
- }
+ INIT_LIST_HEAD(&dev_priv->gpuobj_list);
+ spin_lock_init(&dev_priv->ramin_lock);
+ dev_priv->ramin_base = ~0;
return 0;
}
@@ -311,297 +208,89 @@ nouveau_gpuobj_takedown(struct drm_device *dev)
NV_DEBUG(dev, "\n");
- nouveau_gpuobj_del(dev, &dev_priv->ramht);
+ BUG_ON(!list_empty(&dev_priv->gpuobj_list));
}
-void
-nouveau_gpuobj_late_takedown(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *gpuobj = NULL;
- struct list_head *entry, *tmp;
-
- NV_DEBUG(dev, "\n");
-
- list_for_each_safe(entry, tmp, &dev_priv->gpuobj_list) {
- gpuobj = list_entry(entry, struct nouveau_gpuobj, list);
-
- NV_ERROR(dev, "gpuobj %p still exists at takedown, refs=%d\n",
- gpuobj, gpuobj->refcount);
- gpuobj->refcount = 0;
- nouveau_gpuobj_del(dev, &gpuobj);
- }
-}
-int
-nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
+static void
+nouveau_gpuobj_del(struct kref *ref)
{
+ struct nouveau_gpuobj *gpuobj =
+ container_of(ref, struct nouveau_gpuobj, refcount);
+ struct drm_device *dev = gpuobj->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine = &dev_priv->engine;
- struct nouveau_gpuobj *gpuobj;
int i;
- NV_DEBUG(dev, "gpuobj %p\n", pgpuobj ? *pgpuobj : NULL);
-
- if (!dev_priv || !pgpuobj || !(*pgpuobj))
- return -EINVAL;
- gpuobj = *pgpuobj;
-
- if (gpuobj->refcount != 0) {
- NV_ERROR(dev, "gpuobj refcount is %d\n", gpuobj->refcount);
- return -EINVAL;
- }
+ NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) {
- for (i = 0; i < gpuobj->im_pramin->size; i += 4)
- nv_wo32(dev, gpuobj, i/4, 0);
+ for (i = 0; i < gpuobj->size; i += 4)
+ nv_wo32(gpuobj, i, 0);
engine->instmem.flush(dev);
}
if (gpuobj->dtor)
gpuobj->dtor(dev, gpuobj);
- if (gpuobj->im_backing && !(gpuobj->flags & NVOBJ_FLAG_FAKE))
+ if (gpuobj->im_backing)
engine->instmem.clear(dev, gpuobj);
- if (gpuobj->im_pramin) {
- if (gpuobj->flags & NVOBJ_FLAG_FAKE)
- kfree(gpuobj->im_pramin);
- else
- drm_mm_put_block(gpuobj->im_pramin);
- }
-
+ spin_lock(&dev_priv->ramin_lock);
+ if (gpuobj->im_pramin)
+ drm_mm_put_block(gpuobj->im_pramin);
list_del(&gpuobj->list);
+ spin_unlock(&dev_priv->ramin_lock);
- *pgpuobj = NULL;
kfree(gpuobj);
- return 0;
}
-static int
-nouveau_gpuobj_instance_get(struct drm_device *dev,
- struct nouveau_channel *chan,
- struct nouveau_gpuobj *gpuobj, uint32_t *inst)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *cpramin;
-
- /* <NV50 use PRAMIN address everywhere */
- if (dev_priv->card_type < NV_50) {
- *inst = gpuobj->im_pramin->start;
- return 0;
- }
-
- if (chan && gpuobj->im_channel != chan) {
- NV_ERROR(dev, "Channel mismatch: obj %d, ref %d\n",
- gpuobj->im_channel->id, chan->id);
- return -EINVAL;
- }
-
- /* NV50 channel-local instance */
- if (chan) {
- cpramin = chan->ramin->gpuobj;
- *inst = gpuobj->im_pramin->start - cpramin->im_pramin->start;
- return 0;
- }
-
- /* NV50 global (VRAM) instance */
- if (!gpuobj->im_channel) {
- /* ...from global heap */
- if (!gpuobj->im_backing) {
- NV_ERROR(dev, "AII, no VRAM backing gpuobj\n");
- return -EINVAL;
- }
- *inst = gpuobj->im_backing_start;
- return 0;
- } else {
- /* ...from local heap */
- cpramin = gpuobj->im_channel->ramin->gpuobj;
- *inst = cpramin->im_backing_start +
- (gpuobj->im_pramin->start - cpramin->im_pramin->start);
- return 0;
- }
-
- return -EINVAL;
-}
-
-int
-nouveau_gpuobj_ref_add(struct drm_device *dev, struct nouveau_channel *chan,
- uint32_t handle, struct nouveau_gpuobj *gpuobj,
- struct nouveau_gpuobj_ref **ref_ret)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj_ref *ref;
- uint32_t instance;
- int ret;
-
- NV_DEBUG(dev, "ch%d h=0x%08x gpuobj=%p\n",
- chan ? chan->id : -1, handle, gpuobj);
-
- if (!dev_priv || !gpuobj || (ref_ret && *ref_ret != NULL))
- return -EINVAL;
-
- if (!chan && !ref_ret)
- return -EINVAL;
-
- if (gpuobj->engine == NVOBJ_ENGINE_SW && !gpuobj->im_pramin) {
- /* sw object */
- instance = 0x40;
- } else {
- ret = nouveau_gpuobj_instance_get(dev, chan, gpuobj, &instance);
- if (ret)
- return ret;
- }
-
- ref = kzalloc(sizeof(*ref), GFP_KERNEL);
- if (!ref)
- return -ENOMEM;
- INIT_LIST_HEAD(&ref->list);
- ref->gpuobj = gpuobj;
- ref->channel = chan;
- ref->instance = instance;
-
- if (!ref_ret) {
- ref->handle = handle;
-
- ret = nouveau_ramht_insert(dev, ref);
- if (ret) {
- kfree(ref);
- return ret;
- }
- } else {
- ref->handle = ~0;
- *ref_ret = ref;
- }
-
- ref->gpuobj->refcount++;
- return 0;
-}
-
-int nouveau_gpuobj_ref_del(struct drm_device *dev, struct nouveau_gpuobj_ref **pref)
-{
- struct nouveau_gpuobj_ref *ref;
-
- NV_DEBUG(dev, "ref %p\n", pref ? *pref : NULL);
-
- if (!dev || !pref || *pref == NULL)
- return -EINVAL;
- ref = *pref;
-
- if (ref->handle != ~0)
- nouveau_ramht_remove(dev, ref);
-
- if (ref->gpuobj) {
- ref->gpuobj->refcount--;
-
- if (ref->gpuobj->refcount == 0) {
- if (!(ref->gpuobj->flags & NVOBJ_FLAG_ALLOW_NO_REFS))
- nouveau_gpuobj_del(dev, &ref->gpuobj);
- }
- }
-
- *pref = NULL;
- kfree(ref);
- return 0;
-}
-
-int
-nouveau_gpuobj_new_ref(struct drm_device *dev,
- struct nouveau_channel *oc, struct nouveau_channel *rc,
- uint32_t handle, uint32_t size, int align,
- uint32_t flags, struct nouveau_gpuobj_ref **ref)
-{
- struct nouveau_gpuobj *gpuobj = NULL;
- int ret;
-
- ret = nouveau_gpuobj_new(dev, oc, size, align, flags, &gpuobj);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_ref_add(dev, rc, handle, gpuobj, ref);
- if (ret) {
- nouveau_gpuobj_del(dev, &gpuobj);
- return ret;
- }
-
- return 0;
-}
-
-int
-nouveau_gpuobj_ref_find(struct nouveau_channel *chan, uint32_t handle,
- struct nouveau_gpuobj_ref **ref_ret)
+void
+nouveau_gpuobj_ref(struct nouveau_gpuobj *ref, struct nouveau_gpuobj **ptr)
{
- struct nouveau_gpuobj_ref *ref;
- struct list_head *entry, *tmp;
-
- list_for_each_safe(entry, tmp, &chan->ramht_refs) {
- ref = list_entry(entry, struct nouveau_gpuobj_ref, list);
+ if (ref)
+ kref_get(&ref->refcount);
- if (ref->handle == handle) {
- if (ref_ret)
- *ref_ret = ref;
- return 0;
- }
- }
+ if (*ptr)
+ kref_put(&(*ptr)->refcount, nouveau_gpuobj_del);
- return -EINVAL;
+ *ptr = ref;
}
int
-nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
- uint32_t b_offset, uint32_t size,
- uint32_t flags, struct nouveau_gpuobj **pgpuobj,
- struct nouveau_gpuobj_ref **pref)
+nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst,
+ u32 size, u32 flags, struct nouveau_gpuobj **pgpuobj)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *gpuobj = NULL;
int i;
NV_DEBUG(dev,
- "p_offset=0x%08x b_offset=0x%08x size=0x%08x flags=0x%08x\n",
- p_offset, b_offset, size, flags);
+ "pinst=0x%08x vinst=0x%010llx size=0x%08x flags=0x%08x\n",
+ pinst, vinst, size, flags);
gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
if (!gpuobj)
return -ENOMEM;
NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
- gpuobj->im_channel = NULL;
- gpuobj->flags = flags | NVOBJ_FLAG_FAKE;
-
- list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
-
- if (p_offset != ~0) {
- gpuobj->im_pramin = kzalloc(sizeof(struct drm_mm_node),
- GFP_KERNEL);
- if (!gpuobj->im_pramin) {
- nouveau_gpuobj_del(dev, &gpuobj);
- return -ENOMEM;
- }
- gpuobj->im_pramin->start = p_offset;
- gpuobj->im_pramin->size = size;
- }
-
- if (b_offset != ~0) {
- gpuobj->im_backing = (struct nouveau_bo *)-1;
- gpuobj->im_backing_start = b_offset;
- }
+ gpuobj->dev = dev;
+ gpuobj->flags = flags;
+ kref_init(&gpuobj->refcount);
+ gpuobj->size = size;
+ gpuobj->pinst = pinst;
+ gpuobj->cinst = 0xdeadbeef;
+ gpuobj->vinst = vinst;
if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
- for (i = 0; i < gpuobj->im_pramin->size; i += 4)
- nv_wo32(dev, gpuobj, i/4, 0);
+ for (i = 0; i < gpuobj->size; i += 4)
+ nv_wo32(gpuobj, i, 0);
dev_priv->engine.instmem.flush(dev);
}
- if (pref) {
- i = nouveau_gpuobj_ref_add(dev, NULL, 0, gpuobj, pref);
- if (i) {
- nouveau_gpuobj_del(dev, &gpuobj);
- return i;
- }
- }
-
- if (pgpuobj)
- *pgpuobj = gpuobj;
+ spin_lock(&dev_priv->ramin_lock);
+ list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+ spin_unlock(&dev_priv->ramin_lock);
+ *pgpuobj = gpuobj;
return 0;
}
@@ -685,14 +374,12 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
adjust = offset & 0x00000fff;
frame = offset & ~0x00000fff;
- nv_wo32(dev, *gpuobj, 0, ((1<<12) | (1<<13) |
- (adjust << 20) |
- (access << 14) |
- (target << 16) |
- class));
- nv_wo32(dev, *gpuobj, 1, size - 1);
- nv_wo32(dev, *gpuobj, 2, frame | pte_flags);
- nv_wo32(dev, *gpuobj, 3, frame | pte_flags);
+ nv_wo32(*gpuobj, 0, ((1<<12) | (1<<13) | (adjust << 20) |
+ (access << 14) | (target << 16) |
+ class));
+ nv_wo32(*gpuobj, 4, size - 1);
+ nv_wo32(*gpuobj, 8, frame | pte_flags);
+ nv_wo32(*gpuobj, 12, frame | pte_flags);
} else {
uint64_t limit = offset + size - 1;
uint32_t flags0, flags5;
@@ -705,12 +392,12 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
flags5 = 0x00080000;
}
- nv_wo32(dev, *gpuobj, 0, flags0 | class);
- nv_wo32(dev, *gpuobj, 1, lower_32_bits(limit));
- nv_wo32(dev, *gpuobj, 2, lower_32_bits(offset));
- nv_wo32(dev, *gpuobj, 3, ((upper_32_bits(limit) & 0xff) << 24) |
- (upper_32_bits(offset) & 0xff));
- nv_wo32(dev, *gpuobj, 5, flags5);
+ nv_wo32(*gpuobj, 0, flags0 | class);
+ nv_wo32(*gpuobj, 4, lower_32_bits(limit));
+ nv_wo32(*gpuobj, 8, lower_32_bits(offset));
+ nv_wo32(*gpuobj, 12, ((upper_32_bits(limit) & 0xff) << 24) |
+ (upper_32_bits(offset) & 0xff));
+ nv_wo32(*gpuobj, 20, flags5);
}
instmem->flush(dev);
@@ -741,7 +428,7 @@ nouveau_gpuobj_gart_dma_new(struct nouveau_channel *chan,
*o_ret = 0;
} else
if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA) {
- *gpuobj = dev_priv->gart_info.sg_ctxdma;
+ nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, gpuobj);
if (offset & ~0xffffffffULL) {
NV_ERROR(dev, "obj offset exceeds 32-bits\n");
return -EINVAL;
@@ -829,25 +516,25 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class,
}
if (dev_priv->card_type >= NV_50) {
- nv_wo32(dev, *gpuobj, 0, class);
- nv_wo32(dev, *gpuobj, 5, 0x00010000);
+ nv_wo32(*gpuobj, 0, class);
+ nv_wo32(*gpuobj, 20, 0x00010000);
} else {
switch (class) {
case NV_CLASS_NULL:
- nv_wo32(dev, *gpuobj, 0, 0x00001030);
- nv_wo32(dev, *gpuobj, 1, 0xFFFFFFFF);
+ nv_wo32(*gpuobj, 0, 0x00001030);
+ nv_wo32(*gpuobj, 4, 0xFFFFFFFF);
break;
default:
if (dev_priv->card_type >= NV_40) {
- nv_wo32(dev, *gpuobj, 0, class);
+ nv_wo32(*gpuobj, 0, class);
#ifdef __BIG_ENDIAN
- nv_wo32(dev, *gpuobj, 2, 0x01000000);
+ nv_wo32(*gpuobj, 8, 0x01000000);
#endif
} else {
#ifdef __BIG_ENDIAN
- nv_wo32(dev, *gpuobj, 0, class | 0x00080000);
+ nv_wo32(*gpuobj, 0, class | 0x00080000);
#else
- nv_wo32(dev, *gpuobj, 0, class);
+ nv_wo32(*gpuobj, 0, class);
#endif
}
}
@@ -873,10 +560,15 @@ nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
if (!gpuobj)
return -ENOMEM;
+ gpuobj->dev = chan->dev;
gpuobj->engine = NVOBJ_ENGINE_SW;
gpuobj->class = class;
+ kref_init(&gpuobj->refcount);
+ gpuobj->cinst = 0x40;
+ spin_lock(&dev_priv->ramin_lock);
list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+ spin_unlock(&dev_priv->ramin_lock);
*gpuobj_ret = gpuobj;
return 0;
}
@@ -886,7 +578,6 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *pramin = NULL;
uint32_t size;
uint32_t base;
int ret;
@@ -911,18 +602,16 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
size += 0x1000;
}
- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0,
- &chan->ramin);
+ ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin);
if (ret) {
NV_ERROR(dev, "Error allocating channel PRAMIN: %d\n", ret);
return ret;
}
- pramin = chan->ramin->gpuobj;
- ret = drm_mm_init(&chan->ramin_heap, pramin->im_pramin->start + base, size);
+ ret = drm_mm_init(&chan->ramin_heap, base, size);
if (ret) {
NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret);
- nouveau_gpuobj_ref_del(dev, &chan->ramin);
+ nouveau_gpuobj_ref(NULL, &chan->ramin);
return ret;
}
@@ -939,8 +628,6 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
struct nouveau_gpuobj *vram = NULL, *tt = NULL;
int ret, i;
- INIT_LIST_HEAD(&chan->ramht_refs);
-
NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
/* Allocate a chunk of memory for per-channel object storage */
@@ -956,41 +643,38 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
* locations determined during init.
*/
if (dev_priv->card_type >= NV_50) {
- uint32_t vm_offset, pde;
+ u32 pgd_offs = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200;
+ u64 vm_vinst = chan->ramin->vinst + pgd_offs;
+ u32 vm_pinst = chan->ramin->pinst;
+ u32 pde;
- vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200;
- vm_offset += chan->ramin->gpuobj->im_pramin->start;
+ if (vm_pinst != ~0)
+ vm_pinst += pgd_offs;
- ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000,
- 0, &chan->vm_pd, NULL);
+ ret = nouveau_gpuobj_new_fake(dev, vm_pinst, vm_vinst, 0x4000,
+ 0, &chan->vm_pd);
if (ret)
return ret;
for (i = 0; i < 0x4000; i += 8) {
- nv_wo32(dev, chan->vm_pd, (i+0)/4, 0x00000000);
- nv_wo32(dev, chan->vm_pd, (i+4)/4, 0xdeadcafe);
+ nv_wo32(chan->vm_pd, i + 0, 0x00000000);
+ nv_wo32(chan->vm_pd, i + 4, 0xdeadcafe);
}
- pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 2;
- ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
- dev_priv->gart_info.sg_ctxdma,
- &chan->vm_gart_pt);
- if (ret)
- return ret;
- nv_wo32(dev, chan->vm_pd, pde++,
- chan->vm_gart_pt->instance | 0x03);
- nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
+ nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma,
+ &chan->vm_gart_pt);
+ pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 8;
+ nv_wo32(chan->vm_pd, pde + 0, chan->vm_gart_pt->vinst | 3);
+ nv_wo32(chan->vm_pd, pde + 4, 0x00000000);
- pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 2;
+ pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 8;
for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
- ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
- dev_priv->vm_vram_pt[i],
- &chan->vm_vram_pt[i]);
- if (ret)
- return ret;
+ nouveau_gpuobj_ref(dev_priv->vm_vram_pt[i],
+ &chan->vm_vram_pt[i]);
- nv_wo32(dev, chan->vm_pd, pde++,
- chan->vm_vram_pt[i]->instance | 0x61);
- nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
+ nv_wo32(chan->vm_pd, pde + 0,
+ chan->vm_vram_pt[i]->vinst | 0x61);
+ nv_wo32(chan->vm_pd, pde + 4, 0x00000000);
+ pde += 8;
}
instmem->flush(dev);
@@ -998,15 +682,17 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
/* RAMHT */
if (dev_priv->card_type < NV_50) {
- ret = nouveau_gpuobj_ref_add(dev, NULL, 0, dev_priv->ramht,
- &chan->ramht);
+ nouveau_ramht_ref(dev_priv->ramht, &chan->ramht, NULL);
+ } else {
+ struct nouveau_gpuobj *ramht = NULL;
+
+ ret = nouveau_gpuobj_new(dev, chan, 0x8000, 16,
+ NVOBJ_FLAG_ZERO_ALLOC, &ramht);
if (ret)
return ret;
- } else {
- ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0,
- 0x8000, 16,
- NVOBJ_FLAG_ZERO_ALLOC,
- &chan->ramht);
+
+ ret = nouveau_ramht_new(dev, ramht, &chan->ramht);
+ nouveau_gpuobj_ref(NULL, &ramht);
if (ret)
return ret;
}
@@ -1023,24 +709,32 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
}
} else {
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
- 0, dev_priv->fb_available_size,
- NV_DMA_ACCESS_RW,
- NV_DMA_TARGET_VIDMEM, &vram);
+ 0, dev_priv->fb_available_size,
+ NV_DMA_ACCESS_RW,
+ NV_DMA_TARGET_VIDMEM, &vram);
if (ret) {
NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
return ret;
}
}
- ret = nouveau_gpuobj_ref_add(dev, chan, vram_h, vram, NULL);
+ ret = nouveau_ramht_insert(chan, vram_h, vram);
+ nouveau_gpuobj_ref(NULL, &vram);
if (ret) {
- NV_ERROR(dev, "Error referencing VRAM ctxdma: %d\n", ret);
+ NV_ERROR(dev, "Error adding VRAM ctxdma to RAMHT: %d\n", ret);
return ret;
}
/* TT memory ctxdma */
if (dev_priv->card_type >= NV_50) {
- tt = vram;
+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
+ 0, dev_priv->vm_end,
+ NV_DMA_ACCESS_RW,
+ NV_DMA_TARGET_AGP, &tt);
+ if (ret) {
+ NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
+ return ret;
+ }
} else
if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) {
ret = nouveau_gpuobj_gart_dma_new(chan, 0,
@@ -1056,9 +750,10 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
return ret;
}
- ret = nouveau_gpuobj_ref_add(dev, chan, tt_h, tt, NULL);
+ ret = nouveau_ramht_insert(chan, tt_h, tt);
+ nouveau_gpuobj_ref(NULL, &tt);
if (ret) {
- NV_ERROR(dev, "Error referencing TT ctxdma: %d\n", ret);
+ NV_ERROR(dev, "Error adding TT ctxdma to RAMHT: %d\n", ret);
return ret;
}
@@ -1070,33 +765,23 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
{
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct drm_device *dev = chan->dev;
- struct list_head *entry, *tmp;
- struct nouveau_gpuobj_ref *ref;
int i;
NV_DEBUG(dev, "ch%d\n", chan->id);
- if (!chan->ramht_refs.next)
+ if (!chan->ramht)
return;
- list_for_each_safe(entry, tmp, &chan->ramht_refs) {
- ref = list_entry(entry, struct nouveau_gpuobj_ref, list);
-
- nouveau_gpuobj_ref_del(dev, &ref);
- }
-
- nouveau_gpuobj_ref_del(dev, &chan->ramht);
+ nouveau_ramht_ref(NULL, &chan->ramht, chan);
- nouveau_gpuobj_del(dev, &chan->vm_pd);
- nouveau_gpuobj_ref_del(dev, &chan->vm_gart_pt);
+ nouveau_gpuobj_ref(NULL, &chan->vm_pd);
+ nouveau_gpuobj_ref(NULL, &chan->vm_gart_pt);
for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
- nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);
+ nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]);
if (chan->ramin_heap.free_stack.next)
drm_mm_takedown(&chan->ramin_heap);
- if (chan->ramin)
- nouveau_gpuobj_ref_del(dev, &chan->ramin);
-
+ nouveau_gpuobj_ref(NULL, &chan->ramin);
}
int
@@ -1117,17 +802,17 @@ nouveau_gpuobj_suspend(struct drm_device *dev)
}
list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) {
- if (!gpuobj->im_backing || (gpuobj->flags & NVOBJ_FLAG_FAKE))
+ if (!gpuobj->im_backing)
continue;
- gpuobj->im_backing_suspend = vmalloc(gpuobj->im_pramin->size);
+ gpuobj->im_backing_suspend = vmalloc(gpuobj->size);
if (!gpuobj->im_backing_suspend) {
nouveau_gpuobj_resume(dev);
return -ENOMEM;
}
- for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
- gpuobj->im_backing_suspend[i] = nv_ro32(dev, gpuobj, i);
+ for (i = 0; i < gpuobj->size; i += 4)
+ gpuobj->im_backing_suspend[i/4] = nv_ro32(gpuobj, i);
}
return 0;
@@ -1172,8 +857,8 @@ nouveau_gpuobj_resume(struct drm_device *dev)
if (!gpuobj->im_backing_suspend)
continue;
- for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
- nv_wo32(dev, gpuobj, i, gpuobj->im_backing_suspend[i]);
+ for (i = 0; i < gpuobj->size; i += 4)
+ nv_wo32(gpuobj, i, gpuobj->im_backing_suspend[i/4]);
dev_priv->engine.instmem.flush(dev);
}
@@ -1208,25 +893,24 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
return -EPERM;
}
- if (nouveau_gpuobj_ref_find(chan, init->handle, NULL) == 0)
+ if (nouveau_ramht_find(chan, init->handle))
return -EEXIST;
if (!grc->software)
ret = nouveau_gpuobj_gr_new(chan, grc->id, &gr);
else
ret = nouveau_gpuobj_sw_new(chan, grc->id, &gr);
-
if (ret) {
NV_ERROR(dev, "Error creating object: %d (%d/0x%08x)\n",
ret, init->channel, init->handle);
return ret;
}
- ret = nouveau_gpuobj_ref_add(dev, chan, init->handle, gr, NULL);
+ ret = nouveau_ramht_insert(chan, init->handle, gr);
+ nouveau_gpuobj_ref(NULL, &gr);
if (ret) {
NV_ERROR(dev, "Error referencing object: %d (%d/0x%08x)\n",
ret, init->channel, init->handle);
- nouveau_gpuobj_del(dev, &gr);
return ret;
}
@@ -1237,16 +921,62 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_nouveau_gpuobj_free *objfree = data;
- struct nouveau_gpuobj_ref *ref;
+ struct nouveau_gpuobj *gpuobj;
struct nouveau_channel *chan;
- int ret;
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan);
- ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref);
- if (ret)
- return ret;
- nouveau_gpuobj_ref_del(dev, &ref);
+ gpuobj = nouveau_ramht_find(chan, objfree->handle);
+ if (!gpuobj)
+ return -ENOENT;
+ nouveau_ramht_remove(chan, objfree->handle);
return 0;
}
+
+u32
+nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset)
+{
+ struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
+ struct drm_device *dev = gpuobj->dev;
+
+ if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
+ u64 ptr = gpuobj->vinst + offset;
+ u32 base = ptr >> 16;
+ u32 val;
+
+ spin_lock(&dev_priv->ramin_lock);
+ if (dev_priv->ramin_base != base) {
+ dev_priv->ramin_base = base;
+ nv_wr32(dev, 0x001700, dev_priv->ramin_base);
+ }
+ val = nv_rd32(dev, 0x700000 + (ptr & 0xffff));
+ spin_unlock(&dev_priv->ramin_lock);
+ return val;
+ }
+
+ return nv_ri32(dev, gpuobj->pinst + offset);
+}
+
+void
+nv_wo32(struct nouveau_gpuobj *gpuobj, u32 offset, u32 val)
+{
+ struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
+ struct drm_device *dev = gpuobj->dev;
+
+ if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
+ u64 ptr = gpuobj->vinst + offset;
+ u32 base = ptr >> 16;
+
+ spin_lock(&dev_priv->ramin_lock);
+ if (dev_priv->ramin_base != base) {
+ dev_priv->ramin_base = base;
+ nv_wr32(dev, 0x001700, dev_priv->ramin_base);
+ }
+ nv_wr32(dev, 0x700000 + (ptr & 0xffff), val);
+ spin_unlock(&dev_priv->ramin_lock);
+ return;
+ }
+
+ nv_wi32(dev, gpuobj->pinst + offset, val);
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c
new file mode 100644
index 000000000000..ac62a1b8c4fc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_perf.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_pm.h"
+
+static void
+legacy_perf_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvbios *bios = &dev_priv->vbios;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ char *perf, *entry, *bmp = &bios->data[bios->offset];
+ int headerlen, use_straps;
+
+ if (bmp[5] < 0x5 || bmp[6] < 0x14) {
+ NV_DEBUG(dev, "BMP version too old for perf\n");
+ return;
+ }
+
+ perf = ROMPTR(bios, bmp[0x73]);
+ if (!perf) {
+ NV_DEBUG(dev, "No memclock table pointer found.\n");
+ return;
+ }
+
+ switch (perf[0]) {
+ case 0x12:
+ case 0x14:
+ case 0x18:
+ use_straps = 0;
+ headerlen = 1;
+ break;
+ case 0x01:
+ use_straps = perf[1] & 1;
+ headerlen = (use_straps ? 8 : 2);
+ break;
+ default:
+ NV_WARN(dev, "Unknown memclock table version %x.\n", perf[0]);
+ return;
+ }
+
+ entry = perf + headerlen;
+ if (use_straps)
+ entry += (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x3c) >> 1;
+
+ sprintf(pm->perflvl[0].name, "performance_level_0");
+ pm->perflvl[0].memory = ROM16(entry[0]) * 20;
+ pm->nr_perflvl = 1;
+}
+
+void
+nouveau_perf_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nvbios *bios = &dev_priv->vbios;
+ struct bit_entry P;
+ u8 version, headerlen, recordlen, entries;
+ u8 *perf, *entry;
+ int vid, i;
+
+ if (bios->type == NVBIOS_BIT) {
+ if (bit_table(dev, 'P', &P))
+ return;
+
+ if (P.version != 1 && P.version != 2) {
+ NV_WARN(dev, "unknown perf for BIT P %d\n", P.version);
+ return;
+ }
+
+ perf = ROMPTR(bios, P.data[0]);
+ version = perf[0];
+ headerlen = perf[1];
+ if (version < 0x40) {
+ recordlen = perf[3] + (perf[4] * perf[5]);
+ entries = perf[2];
+ } else {
+ recordlen = perf[2] + (perf[3] * perf[4]);
+ entries = perf[5];
+ }
+ } else {
+ if (bios->data[bios->offset + 6] < 0x25) {
+ legacy_perf_init(dev);
+ return;
+ }
+
+ perf = ROMPTR(bios, bios->data[bios->offset + 0x94]);
+ if (!perf) {
+ NV_DEBUG(dev, "perf table pointer invalid\n");
+ return;
+ }
+
+ version = perf[1];
+ headerlen = perf[0];
+ recordlen = perf[3];
+ entries = perf[2];
+ }
+
+ entry = perf + headerlen;
+ for (i = 0; i < entries; i++) {
+ struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
+
+ if (entry[0] == 0xff) {
+ entry += recordlen;
+ continue;
+ }
+
+ switch (version) {
+ case 0x12:
+ case 0x13:
+ case 0x15:
+ perflvl->fanspeed = entry[55];
+ perflvl->voltage = entry[56];
+ perflvl->core = ROM32(entry[1]) * 10;
+ perflvl->memory = ROM32(entry[5]) * 20;
+ break;
+ case 0x21:
+ case 0x23:
+ case 0x24:
+ perflvl->fanspeed = entry[4];
+ perflvl->voltage = entry[5];
+ perflvl->core = ROM16(entry[6]) * 1000;
+
+ if (dev_priv->chipset == 0x49 ||
+ dev_priv->chipset == 0x4b)
+ perflvl->memory = ROM16(entry[11]) * 1000;
+ else
+ perflvl->memory = ROM16(entry[11]) * 2000;
+
+ break;
+ case 0x25:
+ perflvl->fanspeed = entry[4];
+ perflvl->voltage = entry[5];
+ perflvl->core = ROM16(entry[6]) * 1000;
+ perflvl->shader = ROM16(entry[10]) * 1000;
+ perflvl->memory = ROM16(entry[12]) * 1000;
+ break;
+ case 0x30:
+ perflvl->memscript = ROM16(entry[2]);
+ case 0x35:
+ perflvl->fanspeed = entry[6];
+ perflvl->voltage = entry[7];
+ perflvl->core = ROM16(entry[8]) * 1000;
+ perflvl->shader = ROM16(entry[10]) * 1000;
+ perflvl->memory = ROM16(entry[12]) * 1000;
+ /*XXX: confirm on 0x35 */
+ perflvl->unk05 = ROM16(entry[16]) * 1000;
+ break;
+ case 0x40:
+#define subent(n) entry[perf[2] + ((n) * perf[3])]
+ perflvl->fanspeed = 0; /*XXX*/
+ perflvl->voltage = entry[2];
+ perflvl->core = (ROM16(subent(0)) & 0xfff) * 1000;
+ perflvl->shader = (ROM16(subent(1)) & 0xfff) * 1000;
+ perflvl->memory = (ROM16(subent(2)) & 0xfff) * 1000;
+ break;
+ }
+
+ /* make sure vid is valid */
+ if (pm->voltage.supported && perflvl->voltage) {
+ vid = nouveau_volt_vid_lookup(dev, perflvl->voltage);
+ if (vid < 0) {
+ NV_DEBUG(dev, "drop perflvl %d, bad vid\n", i);
+ entry += recordlen;
+ continue;
+ }
+ }
+
+ snprintf(perflvl->name, sizeof(perflvl->name),
+ "performance_level_%d", i);
+ perflvl->id = i;
+ pm->nr_perflvl++;
+
+ entry += recordlen;
+ }
+}
+
+void
+nouveau_perf_fini(struct drm_device *dev)
+{
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
new file mode 100644
index 000000000000..1c99c55d6d46
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -0,0 +1,518 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_pm.h"
+
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+static int
+nouveau_pm_clock_set(struct drm_device *dev, struct nouveau_pm_level *perflvl,
+ u8 id, u32 khz)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ void *pre_state;
+
+ if (khz == 0)
+ return 0;
+
+ pre_state = pm->clock_pre(dev, perflvl, id, khz);
+ if (IS_ERR(pre_state))
+ return PTR_ERR(pre_state);
+
+ if (pre_state)
+ pm->clock_set(dev, pre_state);
+ return 0;
+}
+
+static int
+nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ int ret;
+
+ if (perflvl == pm->cur)
+ return 0;
+
+ if (pm->voltage.supported && pm->voltage_set && perflvl->voltage) {
+ ret = pm->voltage_set(dev, perflvl->voltage);
+ if (ret) {
+ NV_ERROR(dev, "voltage_set %d failed: %d\n",
+ perflvl->voltage, ret);
+ }
+ }
+
+ nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl->core);
+ nouveau_pm_clock_set(dev, perflvl, PLL_SHADER, perflvl->shader);
+ nouveau_pm_clock_set(dev, perflvl, PLL_MEMORY, perflvl->memory);
+ nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl->unk05);
+
+ pm->cur = perflvl;
+ return 0;
+}
+
+static int
+nouveau_pm_profile_set(struct drm_device *dev, const char *profile)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_level *perflvl = NULL;
+
+ /* safety precaution, for now */
+ if (nouveau_perflvl_wr != 7777)
+ return -EPERM;
+
+ if (!pm->clock_set)
+ return -EINVAL;
+
+ if (!strncmp(profile, "boot", 4))
+ perflvl = &pm->boot;
+ else {
+ int pl = simple_strtol(profile, NULL, 10);
+ int i;
+
+ for (i = 0; i < pm->nr_perflvl; i++) {
+ if (pm->perflvl[i].id == pl) {
+ perflvl = &pm->perflvl[i];
+ break;
+ }
+ }
+
+ if (!perflvl)
+ return -EINVAL;
+ }
+
+ NV_INFO(dev, "setting performance level: %s\n", profile);
+ return nouveau_pm_perflvl_set(dev, perflvl);
+}
+
+static int
+nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ int ret;
+
+ if (!pm->clock_get)
+ return -EINVAL;
+
+ memset(perflvl, 0, sizeof(*perflvl));
+
+ ret = pm->clock_get(dev, PLL_CORE);
+ if (ret > 0)
+ perflvl->core = ret;
+
+ ret = pm->clock_get(dev, PLL_MEMORY);
+ if (ret > 0)
+ perflvl->memory = ret;
+
+ ret = pm->clock_get(dev, PLL_SHADER);
+ if (ret > 0)
+ perflvl->shader = ret;
+
+ ret = pm->clock_get(dev, PLL_UNK05);
+ if (ret > 0)
+ perflvl->unk05 = ret;
+
+ if (pm->voltage.supported && pm->voltage_get) {
+ ret = pm->voltage_get(dev);
+ if (ret > 0)
+ perflvl->voltage = ret;
+ }
+
+ return 0;
+}
+
+static void
+nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
+{
+ char c[16], s[16], v[16], f[16];
+
+ c[0] = '\0';
+ if (perflvl->core)
+ snprintf(c, sizeof(c), " core %dMHz", perflvl->core / 1000);
+
+ s[0] = '\0';
+ if (perflvl->shader)
+ snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000);
+
+ v[0] = '\0';
+ if (perflvl->voltage)
+ snprintf(v, sizeof(v), " voltage %dmV", perflvl->voltage * 10);
+
+ f[0] = '\0';
+ if (perflvl->fanspeed)
+ snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed);
+
+ snprintf(ptr, len, "memory %dMHz%s%s%s%s\n", perflvl->memory / 1000,
+ c, s, v, f);
+}
+
+static ssize_t
+nouveau_pm_get_perflvl_info(struct device *d,
+ struct device_attribute *a, char *buf)
+{
+ struct nouveau_pm_level *perflvl = (struct nouveau_pm_level *)a;
+ char *ptr = buf;
+ int len = PAGE_SIZE;
+
+ snprintf(ptr, len, "%d: ", perflvl->id);
+ ptr += strlen(buf);
+ len -= strlen(buf);
+
+ nouveau_pm_perflvl_info(perflvl, ptr, len);
+ return strlen(buf);
+}
+
+static ssize_t
+nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf)
+{
+ struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_level cur;
+ int len = PAGE_SIZE, ret;
+ char *ptr = buf;
+
+ if (!pm->cur)
+ snprintf(ptr, len, "setting: boot\n");
+ else if (pm->cur == &pm->boot)
+ snprintf(ptr, len, "setting: boot\nc: ");
+ else
+ snprintf(ptr, len, "setting: static %d\nc: ", pm->cur->id);
+ ptr += strlen(buf);
+ len -= strlen(buf);
+
+ ret = nouveau_pm_perflvl_get(dev, &cur);
+ if (ret == 0)
+ nouveau_pm_perflvl_info(&cur, ptr, len);
+ return strlen(buf);
+}
+
+static ssize_t
+nouveau_pm_set_perflvl(struct device *d, struct device_attribute *a,
+ const char *buf, size_t count)
+{
+ struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+ int ret;
+
+ ret = nouveau_pm_profile_set(dev, buf);
+ if (ret)
+ return ret;
+ return strlen(buf);
+}
+
+static DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR,
+ nouveau_pm_get_perflvl, nouveau_pm_set_perflvl);
+
+static int
+nouveau_sysfs_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct device *d = &dev->pdev->dev;
+ int ret, i;
+
+ ret = device_create_file(d, &dev_attr_performance_level);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < pm->nr_perflvl; i++) {
+ struct nouveau_pm_level *perflvl = &pm->perflvl[i];
+
+ perflvl->dev_attr.attr.name = perflvl->name;
+ perflvl->dev_attr.attr.mode = S_IRUGO;
+ perflvl->dev_attr.show = nouveau_pm_get_perflvl_info;
+ perflvl->dev_attr.store = NULL;
+ sysfs_attr_init(&perflvl->dev_attr.attr);
+
+ ret = device_create_file(d, &perflvl->dev_attr);
+ if (ret) {
+ NV_ERROR(dev, "failed pervlvl %d sysfs: %d\n",
+ perflvl->id, i);
+ perflvl->dev_attr.attr.name = NULL;
+ nouveau_pm_fini(dev);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void
+nouveau_sysfs_fini(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct device *d = &dev->pdev->dev;
+ int i;
+
+ device_remove_file(d, &dev_attr_performance_level);
+ for (i = 0; i < pm->nr_perflvl; i++) {
+ struct nouveau_pm_level *pl = &pm->perflvl[i];
+
+ if (!pl->dev_attr.attr.name)
+ break;
+
+ device_remove_file(d, &pl->dev_attr);
+ }
+}
+
+static ssize_t
+nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
+{
+ struct drm_device *dev = dev_get_drvdata(d);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", pm->temp_get(dev)*1000);
+}
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp,
+ NULL, 0);
+
+static ssize_t
+nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf)
+{
+ struct drm_device *dev = dev_get_drvdata(d);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", temp->down_clock*1000);
+}
+static ssize_t
+nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a,
+ const char *buf, size_t count)
+{
+ struct drm_device *dev = dev_get_drvdata(d);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+ long value;
+
+ if (strict_strtol(buf, 10, &value) == -EINVAL)
+ return count;
+
+ temp->down_clock = value/1000;
+
+ nouveau_temp_safety_checks(dev);
+
+ return count;
+}
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp,
+ nouveau_hwmon_set_max_temp,
+ 0);
+
+static ssize_t
+nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a,
+ char *buf)
+{
+ struct drm_device *dev = dev_get_drvdata(d);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", temp->critical*1000);
+}
+static ssize_t
+nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
+ const char *buf,
+ size_t count)
+{
+ struct drm_device *dev = dev_get_drvdata(d);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+ long value;
+
+ if (strict_strtol(buf, 10, &value) == -EINVAL)
+ return count;
+
+ temp->critical = value/1000;
+
+ nouveau_temp_safety_checks(dev);
+
+ return count;
+}
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR,
+ nouveau_hwmon_critical_temp,
+ nouveau_hwmon_set_critical_temp,
+ 0);
+
+static ssize_t nouveau_hwmon_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "nouveau\n");
+}
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, nouveau_hwmon_show_name, NULL, 0);
+
+static ssize_t nouveau_hwmon_show_update_rate(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "1000\n");
+}
+static SENSOR_DEVICE_ATTR(update_rate, S_IRUGO,
+ nouveau_hwmon_show_update_rate,
+ NULL, 0);
+
+static struct attribute *hwmon_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_name.dev_attr.attr,
+ &sensor_dev_attr_update_rate.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group hwmon_attrgroup = {
+ .attrs = hwmon_attributes,
+};
+
+static int
+nouveau_hwmon_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct device *hwmon_dev;
+ int ret;
+
+ if (!pm->temp_get)
+ return -ENODEV;
+
+ hwmon_dev = hwmon_device_register(&dev->pdev->dev);
+ if (IS_ERR(hwmon_dev)) {
+ ret = PTR_ERR(hwmon_dev);
+ NV_ERROR(dev,
+ "Unable to register hwmon device: %d\n", ret);
+ return ret;
+ }
+ dev_set_drvdata(hwmon_dev, dev);
+ ret = sysfs_create_group(&hwmon_dev->kobj,
+ &hwmon_attrgroup);
+ if (ret) {
+ NV_ERROR(dev,
+ "Unable to create hwmon sysfs file: %d\n", ret);
+ hwmon_device_unregister(hwmon_dev);
+ return ret;
+ }
+
+ pm->hwmon = hwmon_dev;
+
+ return 0;
+}
+
+static void
+nouveau_hwmon_fini(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+
+ if (pm->hwmon) {
+ sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup);
+ hwmon_device_unregister(pm->hwmon);
+ }
+}
+
+int
+nouveau_pm_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ char info[256];
+ int ret, i;
+
+ nouveau_volt_init(dev);
+ nouveau_perf_init(dev);
+ nouveau_temp_init(dev);
+ nouveau_mem_timing_init(dev);
+
+ NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl);
+ for (i = 0; i < pm->nr_perflvl; i++) {
+ nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info));
+ NV_INFO(dev, "%d: %s", pm->perflvl[i].id, info);
+ }
+
+ /* determine current ("boot") performance level */
+ ret = nouveau_pm_perflvl_get(dev, &pm->boot);
+ if (ret == 0) {
+ pm->cur = &pm->boot;
+
+ nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
+ NV_INFO(dev, "c: %s", info);
+ }
+
+ /* switch performance levels now if requested */
+ if (nouveau_perflvl != NULL) {
+ ret = nouveau_pm_profile_set(dev, nouveau_perflvl);
+ if (ret) {
+ NV_ERROR(dev, "error setting perflvl \"%s\": %d\n",
+ nouveau_perflvl, ret);
+ }
+ }
+
+ nouveau_sysfs_init(dev);
+ nouveau_hwmon_init(dev);
+
+ return 0;
+}
+
+void
+nouveau_pm_fini(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+
+ if (pm->cur != &pm->boot)
+ nouveau_pm_perflvl_set(dev, &pm->boot);
+
+ nouveau_mem_timing_fini(dev);
+ nouveau_temp_fini(dev);
+ nouveau_perf_fini(dev);
+ nouveau_volt_fini(dev);
+
+ nouveau_hwmon_fini(dev);
+ nouveau_sysfs_fini(dev);
+}
+
+void
+nouveau_pm_resume(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_level *perflvl;
+
+ if (pm->cur == &pm->boot)
+ return;
+
+ perflvl = pm->cur;
+ pm->cur = &pm->boot;
+ nouveau_pm_perflvl_set(dev, perflvl);
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h
new file mode 100644
index 000000000000..4a9838ddacec
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifndef __NOUVEAU_PM_H__
+#define __NOUVEAU_PM_H__
+
+/* nouveau_pm.c */
+int nouveau_pm_init(struct drm_device *dev);
+void nouveau_pm_fini(struct drm_device *dev);
+void nouveau_pm_resume(struct drm_device *dev);
+
+/* nouveau_volt.c */
+void nouveau_volt_init(struct drm_device *);
+void nouveau_volt_fini(struct drm_device *);
+int nouveau_volt_vid_lookup(struct drm_device *, int voltage);
+int nouveau_volt_lvl_lookup(struct drm_device *, int vid);
+int nouveau_voltage_gpio_get(struct drm_device *);
+int nouveau_voltage_gpio_set(struct drm_device *, int voltage);
+
+/* nouveau_perf.c */
+void nouveau_perf_init(struct drm_device *);
+void nouveau_perf_fini(struct drm_device *);
+
+/* nouveau_mem.c */
+void nouveau_mem_timing_init(struct drm_device *);
+void nouveau_mem_timing_fini(struct drm_device *);
+
+/* nv04_pm.c */
+int nv04_pm_clock_get(struct drm_device *, u32 id);
+void *nv04_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *,
+ u32 id, int khz);
+void nv04_pm_clock_set(struct drm_device *, void *);
+
+/* nv50_pm.c */
+int nv50_pm_clock_get(struct drm_device *, u32 id);
+void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *,
+ u32 id, int khz);
+void nv50_pm_clock_set(struct drm_device *, void *);
+
+/* nva3_pm.c */
+int nva3_pm_clock_get(struct drm_device *, u32 id);
+void *nva3_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *,
+ u32 id, int khz);
+void nva3_pm_clock_set(struct drm_device *, void *);
+
+/* nouveau_temp.c */
+void nouveau_temp_init(struct drm_device *dev);
+void nouveau_temp_fini(struct drm_device *dev);
+void nouveau_temp_safety_checks(struct drm_device *dev);
+int nv40_temp_get(struct drm_device *dev);
+int nv84_temp_get(struct drm_device *dev);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.c b/drivers/gpu/drm/nouveau/nouveau_ramht.c
new file mode 100644
index 000000000000..7f16697cc96c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_ramht.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
+
+static u32
+nouveau_ramht_hash_handle(struct nouveau_channel *chan, u32 handle)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_ramht *ramht = chan->ramht;
+ u32 hash = 0;
+ int i;
+
+ NV_DEBUG(dev, "ch%d handle=0x%08x\n", chan->id, handle);
+
+ for (i = 32; i > 0; i -= ramht->bits) {
+ hash ^= (handle & ((1 << ramht->bits) - 1));
+ handle >>= ramht->bits;
+ }
+
+ if (dev_priv->card_type < NV_50)
+ hash ^= chan->id << (ramht->bits - 4);
+ hash <<= 3;
+
+ NV_DEBUG(dev, "hash=0x%08x\n", hash);
+ return hash;
+}
+
+static int
+nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht,
+ u32 offset)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u32 ctx = nv_ro32(ramht, offset + 4);
+
+ if (dev_priv->card_type < NV_40)
+ return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0);
+ return (ctx != 0);
+}
+
+static int
+nouveau_ramht_entry_same_channel(struct nouveau_channel *chan,
+ struct nouveau_gpuobj *ramht, u32 offset)
+{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ u32 ctx = nv_ro32(ramht, offset + 4);
+
+ if (dev_priv->card_type >= NV_50)
+ return true;
+ else if (dev_priv->card_type >= NV_40)
+ return chan->id ==
+ ((ctx >> NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) & 0x1f);
+ else
+ return chan->id ==
+ ((ctx >> NV_RAMHT_CONTEXT_CHANNEL_SHIFT) & 0x1f);
+}
+
+int
+nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
+ struct nouveau_gpuobj *gpuobj)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
+ struct nouveau_ramht_entry *entry;
+ struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
+ unsigned long flags;
+ u32 ctx, co, ho;
+
+ if (nouveau_ramht_find(chan, handle))
+ return -EEXIST;
+
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+ entry->channel = chan;
+ entry->gpuobj = NULL;
+ entry->handle = handle;
+ nouveau_gpuobj_ref(gpuobj, &entry->gpuobj);
+
+ if (dev_priv->card_type < NV_40) {
+ ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->cinst >> 4) |
+ (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) |
+ (gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT);
+ } else
+ if (dev_priv->card_type < NV_50) {
+ ctx = (gpuobj->cinst >> 4) |
+ (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) |
+ (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
+ } else {
+ if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) {
+ ctx = (gpuobj->cinst << 10) | 2;
+ } else {
+ ctx = (gpuobj->cinst >> 4) |
+ ((gpuobj->engine <<
+ NV40_RAMHT_CONTEXT_ENGINE_SHIFT));
+ }
+ }
+
+ spin_lock_irqsave(&chan->ramht->lock, flags);
+ list_add(&entry->head, &chan->ramht->entries);
+
+ co = ho = nouveau_ramht_hash_handle(chan, handle);
+ do {
+ if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
+ NV_DEBUG(dev,
+ "insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
+ chan->id, co, handle, ctx);
+ nv_wo32(ramht, co + 0, handle);
+ nv_wo32(ramht, co + 4, ctx);
+
+ spin_unlock_irqrestore(&chan->ramht->lock, flags);
+ instmem->flush(dev);
+ return 0;
+ }
+ NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n",
+ chan->id, co, nv_ro32(ramht, co));
+
+ co += 8;
+ if (co >= ramht->size)
+ co = 0;
+ } while (co != ho);
+
+ NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
+ list_del(&entry->head);
+ spin_unlock_irqrestore(&chan->ramht->lock, flags);
+ kfree(entry);
+ return -ENOMEM;
+}
+
+static void
+nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
+ struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
+ struct nouveau_ramht_entry *entry, *tmp;
+ u32 co, ho;
+
+ list_for_each_entry_safe(entry, tmp, &chan->ramht->entries, head) {
+ if (entry->channel != chan || entry->handle != handle)
+ continue;
+
+ nouveau_gpuobj_ref(NULL, &entry->gpuobj);
+ list_del(&entry->head);
+ kfree(entry);
+ break;
+ }
+
+ co = ho = nouveau_ramht_hash_handle(chan, handle);
+ do {
+ if (nouveau_ramht_entry_valid(dev, ramht, co) &&
+ nouveau_ramht_entry_same_channel(chan, ramht, co) &&
+ (handle == nv_ro32(ramht, co))) {
+ NV_DEBUG(dev,
+ "remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
+ chan->id, co, handle, nv_ro32(ramht, co + 4));
+ nv_wo32(ramht, co + 0, 0x00000000);
+ nv_wo32(ramht, co + 4, 0x00000000);
+ instmem->flush(dev);
+ return;
+ }
+
+ co += 8;
+ if (co >= ramht->size)
+ co = 0;
+ } while (co != ho);
+
+ NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
+ chan->id, handle);
+}
+
+void
+nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle)
+{
+ struct nouveau_ramht *ramht = chan->ramht;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ramht->lock, flags);
+ nouveau_ramht_remove_locked(chan, handle);
+ spin_unlock_irqrestore(&ramht->lock, flags);
+}
+
+struct nouveau_gpuobj *
+nouveau_ramht_find(struct nouveau_channel *chan, u32 handle)
+{
+ struct nouveau_ramht *ramht = chan->ramht;
+ struct nouveau_ramht_entry *entry;
+ struct nouveau_gpuobj *gpuobj = NULL;
+ unsigned long flags;
+
+ if (unlikely(!chan->ramht))
+ return NULL;
+
+ spin_lock_irqsave(&ramht->lock, flags);
+ list_for_each_entry(entry, &chan->ramht->entries, head) {
+ if (entry->channel == chan && entry->handle == handle) {
+ gpuobj = entry->gpuobj;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&ramht->lock, flags);
+
+ return gpuobj;
+}
+
+int
+nouveau_ramht_new(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
+ struct nouveau_ramht **pramht)
+{
+ struct nouveau_ramht *ramht;
+
+ ramht = kzalloc(sizeof(*ramht), GFP_KERNEL);
+ if (!ramht)
+ return -ENOMEM;
+
+ ramht->dev = dev;
+ kref_init(&ramht->refcount);
+ ramht->bits = drm_order(gpuobj->size / 8);
+ INIT_LIST_HEAD(&ramht->entries);
+ spin_lock_init(&ramht->lock);
+ nouveau_gpuobj_ref(gpuobj, &ramht->gpuobj);
+
+ *pramht = ramht;
+ return 0;
+}
+
+static void
+nouveau_ramht_del(struct kref *ref)
+{
+ struct nouveau_ramht *ramht =
+ container_of(ref, struct nouveau_ramht, refcount);
+
+ nouveau_gpuobj_ref(NULL, &ramht->gpuobj);
+ kfree(ramht);
+}
+
+void
+nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr,
+ struct nouveau_channel *chan)
+{
+ struct nouveau_ramht_entry *entry, *tmp;
+ struct nouveau_ramht *ramht;
+ unsigned long flags;
+
+ if (ref)
+ kref_get(&ref->refcount);
+
+ ramht = *ptr;
+ if (ramht) {
+ spin_lock_irqsave(&ramht->lock, flags);
+ list_for_each_entry_safe(entry, tmp, &ramht->entries, head) {
+ if (entry->channel != chan)
+ continue;
+
+ nouveau_ramht_remove_locked(chan, entry->handle);
+ }
+ spin_unlock_irqrestore(&ramht->lock, flags);
+
+ kref_put(&ramht->refcount, nouveau_ramht_del);
+ }
+ *ptr = ref;
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.h b/drivers/gpu/drm/nouveau/nouveau_ramht.h
new file mode 100644
index 000000000000..b79cb5e1a8f1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_ramht.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifndef __NOUVEAU_RAMHT_H__
+#define __NOUVEAU_RAMHT_H__
+
+struct nouveau_ramht_entry {
+ struct list_head head;
+ struct nouveau_channel *channel;
+ struct nouveau_gpuobj *gpuobj;
+ u32 handle;
+};
+
+struct nouveau_ramht {
+ struct drm_device *dev;
+ struct kref refcount;
+ spinlock_t lock;
+ struct nouveau_gpuobj *gpuobj;
+ struct list_head entries;
+ int bits;
+};
+
+extern int nouveau_ramht_new(struct drm_device *, struct nouveau_gpuobj *,
+ struct nouveau_ramht **);
+extern void nouveau_ramht_ref(struct nouveau_ramht *, struct nouveau_ramht **,
+ struct nouveau_channel *unref_channel);
+
+extern int nouveau_ramht_insert(struct nouveau_channel *, u32 handle,
+ struct nouveau_gpuobj *);
+extern void nouveau_ramht_remove(struct nouveau_channel *, u32 handle);
+extern struct nouveau_gpuobj *
+nouveau_ramht_find(struct nouveau_channel *chan, u32 handle);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index 21a6e453b975..1b42541ca9e5 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -551,6 +551,8 @@
#define NV10_PFIFO_CACHE1_DMA_SUBROUTINE 0x0000324C
#define NV03_PFIFO_CACHE1_PULL0 0x00003240
#define NV04_PFIFO_CACHE1_PULL0 0x00003250
+# define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED 0x00000010
+# define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY 0x00001000
#define NV03_PFIFO_CACHE1_PULL1 0x00003250
#define NV04_PFIFO_CACHE1_PULL1 0x00003254
#define NV04_PFIFO_CACHE1_HASH 0x00003258
@@ -785,15 +787,12 @@
#define NV50_PDISPLAY_DAC_MODE_CTRL_C(i) (0x00610b5c + (i) * 0x8)
#define NV50_PDISPLAY_SOR_MODE_CTRL_P(i) (0x00610b70 + (i) * 0x8)
#define NV50_PDISPLAY_SOR_MODE_CTRL_C(i) (0x00610b74 + (i) * 0x8)
+#define NV50_PDISPLAY_EXT_MODE_CTRL_P(i) (0x00610b80 + (i) * 0x8)
+#define NV50_PDISPLAY_EXT_MODE_CTRL_C(i) (0x00610b84 + (i) * 0x8)
#define NV50_PDISPLAY_DAC_MODE_CTRL2_P(i) (0x00610bdc + (i) * 0x8)
#define NV50_PDISPLAY_DAC_MODE_CTRL2_C(i) (0x00610be0 + (i) * 0x8)
-
#define NV90_PDISPLAY_SOR_MODE_CTRL_P(i) (0x00610794 + (i) * 0x8)
#define NV90_PDISPLAY_SOR_MODE_CTRL_C(i) (0x00610798 + (i) * 0x8)
-#define NV90_PDISPLAY_DAC_MODE_CTRL_P(i) (0x00610b58 + (i) * 0x8)
-#define NV90_PDISPLAY_DAC_MODE_CTRL_C(i) (0x00610b5c + (i) * 0x8)
-#define NV90_PDISPLAY_DAC_MODE_CTRL2_P(i) (0x00610b80 + (i) * 0x8)
-#define NV90_PDISPLAY_DAC_MODE_CTRL2_C(i) (0x00610b84 + (i) * 0x8)
#define NV50_PDISPLAY_CRTC_CLK 0x00614000
#define NV50_PDISPLAY_CRTC_CLK_CTRL1(i) ((i) * 0x800 + 0x614100)
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
index 6b9187d7f67d..288bacac7e5a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -95,9 +95,9 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
unsigned i, j, pte;
- NV_DEBUG(dev, "pg=0x%lx\n", mem->mm_node->start);
+ NV_DEBUG(dev, "pg=0x%lx\n", mem->start);
- pte = nouveau_sgdma_pte(nvbe->dev, mem->mm_node->start << PAGE_SHIFT);
+ pte = nouveau_sgdma_pte(nvbe->dev, mem->start << PAGE_SHIFT);
nvbe->pte_start = pte;
for (i = 0; i < nvbe->nr_pages; i++) {
dma_addr_t dma_offset = nvbe->pages[i];
@@ -105,11 +105,13 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
uint32_t offset_h = upper_32_bits(dma_offset);
for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++) {
- if (dev_priv->card_type < NV_50)
- nv_wo32(dev, gpuobj, pte++, offset_l | 3);
- else {
- nv_wo32(dev, gpuobj, pte++, offset_l | 0x21);
- nv_wo32(dev, gpuobj, pte++, offset_h & 0xff);
+ if (dev_priv->card_type < NV_50) {
+ nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 3);
+ pte += 1;
+ } else {
+ nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 0x21);
+ nv_wo32(gpuobj, (pte * 4) + 4, offset_h & 0xff);
+ pte += 2;
}
dma_offset += NV_CTXDMA_PAGE_SIZE;
@@ -145,11 +147,13 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
dma_addr_t dma_offset = dev_priv->gart_info.sg_dummy_bus;
for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++) {
- if (dev_priv->card_type < NV_50)
- nv_wo32(dev, gpuobj, pte++, dma_offset | 3);
- else {
- nv_wo32(dev, gpuobj, pte++, dma_offset | 0x21);
- nv_wo32(dev, gpuobj, pte++, 0x00000000);
+ if (dev_priv->card_type < NV_50) {
+ nv_wo32(gpuobj, (pte * 4) + 0, dma_offset | 3);
+ pte += 1;
+ } else {
+ nv_wo32(gpuobj, (pte * 4) + 0, 0x00000000);
+ nv_wo32(gpuobj, (pte * 4) + 4, 0x00000000);
+ pte += 2;
}
dma_offset += NV_CTXDMA_PAGE_SIZE;
@@ -230,7 +234,6 @@ nouveau_sgdma_init(struct drm_device *dev)
}
ret = nouveau_gpuobj_new(dev, NULL, obj_size, 16,
- NVOBJ_FLAG_ALLOW_NO_REFS |
NVOBJ_FLAG_ZERO_ALLOC |
NVOBJ_FLAG_ZERO_FREE, &gpuobj);
if (ret) {
@@ -239,9 +242,9 @@ nouveau_sgdma_init(struct drm_device *dev)
}
dev_priv->gart_info.sg_dummy_page =
- alloc_page(GFP_KERNEL|__GFP_DMA32);
+ alloc_page(GFP_KERNEL|__GFP_DMA32|__GFP_ZERO);
if (!dev_priv->gart_info.sg_dummy_page) {
- nouveau_gpuobj_del(dev, &gpuobj);
+ nouveau_gpuobj_ref(NULL, &gpuobj);
return -ENOMEM;
}
@@ -250,29 +253,34 @@ nouveau_sgdma_init(struct drm_device *dev)
pci_map_page(pdev, dev_priv->gart_info.sg_dummy_page, 0,
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
if (pci_dma_mapping_error(pdev, dev_priv->gart_info.sg_dummy_bus)) {
- nouveau_gpuobj_del(dev, &gpuobj);
+ nouveau_gpuobj_ref(NULL, &gpuobj);
return -EFAULT;
}
if (dev_priv->card_type < NV_50) {
+ /* special case, allocated from global instmem heap so
+ * cinst is invalid, we use it on all channels though so
+ * cinst needs to be valid, set it the same as pinst
+ */
+ gpuobj->cinst = gpuobj->pinst;
+
/* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and
* confirmed to work on c51. Perhaps means NV_DMA_TARGET_PCIE
* on those cards? */
- nv_wo32(dev, gpuobj, 0, NV_CLASS_DMA_IN_MEMORY |
- (1 << 12) /* PT present */ |
- (0 << 13) /* PT *not* linear */ |
- (NV_DMA_ACCESS_RW << 14) |
- (NV_DMA_TARGET_PCI << 16));
- nv_wo32(dev, gpuobj, 1, aper_size - 1);
+ nv_wo32(gpuobj, 0, NV_CLASS_DMA_IN_MEMORY |
+ (1 << 12) /* PT present */ |
+ (0 << 13) /* PT *not* linear */ |
+ (NV_DMA_ACCESS_RW << 14) |
+ (NV_DMA_TARGET_PCI << 16));
+ nv_wo32(gpuobj, 4, aper_size - 1);
for (i = 2; i < 2 + (aper_size >> 12); i++) {
- nv_wo32(dev, gpuobj, i,
- dev_priv->gart_info.sg_dummy_bus | 3);
+ nv_wo32(gpuobj, i * 4,
+ dev_priv->gart_info.sg_dummy_bus | 3);
}
} else {
for (i = 0; i < obj_size; i += 8) {
- nv_wo32(dev, gpuobj, (i+0)/4,
- dev_priv->gart_info.sg_dummy_bus | 0x21);
- nv_wo32(dev, gpuobj, (i+4)/4, 0);
+ nv_wo32(gpuobj, i + 0, 0x00000000);
+ nv_wo32(gpuobj, i + 4, 0x00000000);
}
}
dev_priv->engine.instmem.flush(dev);
@@ -298,7 +306,7 @@ nouveau_sgdma_takedown(struct drm_device *dev)
dev_priv->gart_info.sg_dummy_bus = 0;
}
- nouveau_gpuobj_del(dev, &dev_priv->gart_info.sg_ctxdma);
+ nouveau_gpuobj_ref(NULL, &dev_priv->gart_info.sg_ctxdma);
}
int
@@ -308,9 +316,9 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page)
struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
int pte;
- pte = (offset >> NV_CTXDMA_PAGE_SHIFT);
+ pte = (offset >> NV_CTXDMA_PAGE_SHIFT) << 2;
if (dev_priv->card_type < NV_50) {
- *page = nv_ro32(dev, gpuobj, (pte + 2)) & ~NV_CTXDMA_PAGE_MASK;
+ *page = nv_ro32(gpuobj, (pte + 8)) & ~NV_CTXDMA_PAGE_MASK;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 989322be3728..ed7757f14083 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -35,6 +35,8 @@
#include "nouveau_drv.h"
#include "nouveau_drm.h"
#include "nouveau_fbcon.h"
+#include "nouveau_ramht.h"
+#include "nouveau_pm.h"
#include "nv50_display.h"
static void nouveau_stub_takedown(struct drm_device *dev) {}
@@ -78,7 +80,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.disable = nv04_fifo_disable;
engine->fifo.enable = nv04_fifo_enable;
engine->fifo.reassign = nv04_fifo_reassign;
- engine->fifo.cache_flush = nv04_fifo_cache_flush;
engine->fifo.cache_pull = nv04_fifo_cache_pull;
engine->fifo.channel_id = nv04_fifo_channel_id;
engine->fifo.create_context = nv04_fifo_create_context;
@@ -95,6 +96,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->gpio.get = NULL;
engine->gpio.set = NULL;
engine->gpio.irq_enable = NULL;
+ engine->pm.clock_get = nv04_pm_clock_get;
+ engine->pm.clock_pre = nv04_pm_clock_pre;
+ engine->pm.clock_set = nv04_pm_clock_set;
break;
case 0x10:
engine->instmem.init = nv04_instmem_init;
@@ -130,7 +134,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.disable = nv04_fifo_disable;
engine->fifo.enable = nv04_fifo_enable;
engine->fifo.reassign = nv04_fifo_reassign;
- engine->fifo.cache_flush = nv04_fifo_cache_flush;
engine->fifo.cache_pull = nv04_fifo_cache_pull;
engine->fifo.channel_id = nv10_fifo_channel_id;
engine->fifo.create_context = nv10_fifo_create_context;
@@ -147,6 +150,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->gpio.get = nv10_gpio_get;
engine->gpio.set = nv10_gpio_set;
engine->gpio.irq_enable = NULL;
+ engine->pm.clock_get = nv04_pm_clock_get;
+ engine->pm.clock_pre = nv04_pm_clock_pre;
+ engine->pm.clock_set = nv04_pm_clock_set;
break;
case 0x20:
engine->instmem.init = nv04_instmem_init;
@@ -182,7 +188,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.disable = nv04_fifo_disable;
engine->fifo.enable = nv04_fifo_enable;
engine->fifo.reassign = nv04_fifo_reassign;
- engine->fifo.cache_flush = nv04_fifo_cache_flush;
engine->fifo.cache_pull = nv04_fifo_cache_pull;
engine->fifo.channel_id = nv10_fifo_channel_id;
engine->fifo.create_context = nv10_fifo_create_context;
@@ -199,6 +204,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->gpio.get = nv10_gpio_get;
engine->gpio.set = nv10_gpio_set;
engine->gpio.irq_enable = NULL;
+ engine->pm.clock_get = nv04_pm_clock_get;
+ engine->pm.clock_pre = nv04_pm_clock_pre;
+ engine->pm.clock_set = nv04_pm_clock_set;
break;
case 0x30:
engine->instmem.init = nv04_instmem_init;
@@ -234,7 +242,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.disable = nv04_fifo_disable;
engine->fifo.enable = nv04_fifo_enable;
engine->fifo.reassign = nv04_fifo_reassign;
- engine->fifo.cache_flush = nv04_fifo_cache_flush;
engine->fifo.cache_pull = nv04_fifo_cache_pull;
engine->fifo.channel_id = nv10_fifo_channel_id;
engine->fifo.create_context = nv10_fifo_create_context;
@@ -251,6 +258,11 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->gpio.get = nv10_gpio_get;
engine->gpio.set = nv10_gpio_set;
engine->gpio.irq_enable = NULL;
+ engine->pm.clock_get = nv04_pm_clock_get;
+ engine->pm.clock_pre = nv04_pm_clock_pre;
+ engine->pm.clock_set = nv04_pm_clock_set;
+ engine->pm.voltage_get = nouveau_voltage_gpio_get;
+ engine->pm.voltage_set = nouveau_voltage_gpio_set;
break;
case 0x40:
case 0x60:
@@ -287,7 +299,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.disable = nv04_fifo_disable;
engine->fifo.enable = nv04_fifo_enable;
engine->fifo.reassign = nv04_fifo_reassign;
- engine->fifo.cache_flush = nv04_fifo_cache_flush;
engine->fifo.cache_pull = nv04_fifo_cache_pull;
engine->fifo.channel_id = nv10_fifo_channel_id;
engine->fifo.create_context = nv40_fifo_create_context;
@@ -304,6 +315,12 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->gpio.get = nv10_gpio_get;
engine->gpio.set = nv10_gpio_set;
engine->gpio.irq_enable = NULL;
+ engine->pm.clock_get = nv04_pm_clock_get;
+ engine->pm.clock_pre = nv04_pm_clock_pre;
+ engine->pm.clock_set = nv04_pm_clock_set;
+ engine->pm.voltage_get = nouveau_voltage_gpio_get;
+ engine->pm.voltage_set = nouveau_voltage_gpio_set;
+ engine->pm.temp_get = nv40_temp_get;
break;
case 0x50:
case 0x80: /* gotta love NVIDIA's consistency.. */
@@ -358,6 +375,27 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->gpio.get = nv50_gpio_get;
engine->gpio.set = nv50_gpio_set;
engine->gpio.irq_enable = nv50_gpio_irq_enable;
+ switch (dev_priv->chipset) {
+ case 0xa3:
+ case 0xa5:
+ case 0xa8:
+ case 0xaf:
+ engine->pm.clock_get = nva3_pm_clock_get;
+ engine->pm.clock_pre = nva3_pm_clock_pre;
+ engine->pm.clock_set = nva3_pm_clock_set;
+ break;
+ default:
+ engine->pm.clock_get = nv50_pm_clock_get;
+ engine->pm.clock_pre = nv50_pm_clock_pre;
+ engine->pm.clock_set = nv50_pm_clock_set;
+ break;
+ }
+ engine->pm.voltage_get = nouveau_voltage_gpio_get;
+ engine->pm.voltage_set = nouveau_voltage_gpio_set;
+ if (dev_priv->chipset >= 0x84)
+ engine->pm.temp_get = nv84_temp_get;
+ else
+ engine->pm.temp_get = nv40_temp_get;
break;
case 0xC0:
engine->instmem.init = nvc0_instmem_init;
@@ -437,16 +475,14 @@ static int
nouveau_card_init_channel(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *gpuobj;
+ struct nouveau_gpuobj *gpuobj = NULL;
int ret;
ret = nouveau_channel_alloc(dev, &dev_priv->channel,
- (struct drm_file *)-2,
- NvDmaFB, NvDmaTT);
+ (struct drm_file *)-2, NvDmaFB, NvDmaTT);
if (ret)
return ret;
- gpuobj = NULL;
ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY,
0, dev_priv->vram_size,
NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM,
@@ -454,26 +490,25 @@ nouveau_card_init_channel(struct drm_device *dev)
if (ret)
goto out_err;
- ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaVRAM,
- gpuobj, NULL);
+ ret = nouveau_ramht_insert(dev_priv->channel, NvDmaVRAM, gpuobj);
+ nouveau_gpuobj_ref(NULL, &gpuobj);
if (ret)
goto out_err;
- gpuobj = NULL;
ret = nouveau_gpuobj_gart_dma_new(dev_priv->channel, 0,
dev_priv->gart_info.aper_size,
NV_DMA_ACCESS_RW, &gpuobj, NULL);
if (ret)
goto out_err;
- ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaGART,
- gpuobj, NULL);
+ ret = nouveau_ramht_insert(dev_priv->channel, NvDmaGART, gpuobj);
+ nouveau_gpuobj_ref(NULL, &gpuobj);
if (ret)
goto out_err;
return 0;
+
out_err:
- nouveau_gpuobj_del(dev, &gpuobj);
nouveau_channel_free(dev_priv->channel);
dev_priv->channel = NULL;
return ret;
@@ -534,35 +569,28 @@ nouveau_card_init(struct drm_device *dev)
if (ret)
goto out_display_early;
- ret = nouveau_mem_detect(dev);
+ nouveau_pm_init(dev);
+
+ ret = nouveau_mem_vram_init(dev);
if (ret)
goto out_bios;
- ret = nouveau_gpuobj_early_init(dev);
+ ret = nouveau_gpuobj_init(dev);
if (ret)
- goto out_bios;
+ goto out_vram;
- /* Initialise instance memory, must happen before mem_init so we
- * know exactly how much VRAM we're able to use for "normal"
- * purposes.
- */
ret = engine->instmem.init(dev);
if (ret)
- goto out_gpuobj_early;
+ goto out_gpuobj;
- /* Setup the memory manager */
- ret = nouveau_mem_init(dev);
+ ret = nouveau_mem_gart_init(dev);
if (ret)
goto out_instmem;
- ret = nouveau_gpuobj_init(dev);
- if (ret)
- goto out_mem;
-
/* PMC */
ret = engine->mc.init(dev);
if (ret)
- goto out_gpuobj;
+ goto out_gart;
/* PGPIO */
ret = engine->gpio.init(dev);
@@ -611,9 +639,13 @@ nouveau_card_init(struct drm_device *dev)
/* what about PVIDEO/PCRTC/PRAMDAC etc? */
if (!engine->graph.accel_blocked) {
- ret = nouveau_card_init_channel(dev);
+ ret = nouveau_fence_init(dev);
if (ret)
goto out_irq;
+
+ ret = nouveau_card_init_channel(dev);
+ if (ret)
+ goto out_fence;
}
ret = nouveau_backlight_init(dev);
@@ -624,6 +656,8 @@ nouveau_card_init(struct drm_device *dev)
drm_kms_helper_poll_init(dev);
return 0;
+out_fence:
+ nouveau_fence_fini(dev);
out_irq:
drm_irq_uninstall(dev);
out_display:
@@ -642,16 +676,16 @@ out_gpio:
engine->gpio.takedown(dev);
out_mc:
engine->mc.takedown(dev);
-out_gpuobj:
- nouveau_gpuobj_takedown(dev);
-out_mem:
- nouveau_sgdma_takedown(dev);
- nouveau_mem_close(dev);
+out_gart:
+ nouveau_mem_gart_fini(dev);
out_instmem:
engine->instmem.takedown(dev);
-out_gpuobj_early:
- nouveau_gpuobj_late_takedown(dev);
+out_gpuobj:
+ nouveau_gpuobj_takedown(dev);
+out_vram:
+ nouveau_mem_vram_fini(dev);
out_bios:
+ nouveau_pm_fini(dev);
nouveau_bios_takedown(dev);
out_display_early:
engine->display.late_takedown(dev);
@@ -667,7 +701,8 @@ static void nouveau_card_takedown(struct drm_device *dev)
nouveau_backlight_exit(dev);
- if (dev_priv->channel) {
+ if (!engine->graph.accel_blocked) {
+ nouveau_fence_fini(dev);
nouveau_channel_free(dev_priv->channel);
dev_priv->channel = NULL;
}
@@ -686,15 +721,15 @@ static void nouveau_card_takedown(struct drm_device *dev)
ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
mutex_unlock(&dev->struct_mutex);
- nouveau_sgdma_takedown(dev);
+ nouveau_mem_gart_fini(dev);
- nouveau_gpuobj_takedown(dev);
- nouveau_mem_close(dev);
engine->instmem.takedown(dev);
+ nouveau_gpuobj_takedown(dev);
+ nouveau_mem_vram_fini(dev);
drm_irq_uninstall(dev);
- nouveau_gpuobj_late_takedown(dev);
+ nouveau_pm_fini(dev);
nouveau_bios_takedown(dev);
vga_client_register(dev->pdev, NULL, NULL, NULL);
@@ -1057,7 +1092,7 @@ bool nouveau_wait_until(struct drm_device *dev, uint64_t timeout,
/* Waits for PGRAPH to go completely idle */
bool nouveau_wait_for_idle(struct drm_device *dev)
{
- if (!nv_wait(NV04_PGRAPH_STATUS, 0xffffffff, 0x00000000)) {
+ if (!nv_wait(dev, NV04_PGRAPH_STATUS, 0xffffffff, 0x00000000)) {
NV_ERROR(dev, "PGRAPH idle timed out with status 0x%08x\n",
nv_rd32(dev, NV04_PGRAPH_STATUS));
return false;
diff --git a/drivers/gpu/drm/nouveau/nouveau_temp.c b/drivers/gpu/drm/nouveau/nouveau_temp.c
new file mode 100644
index 000000000000..16bbbf1eff63
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_temp.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2010 PathScale inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_pm.h"
+
+static void
+nouveau_temp_vbios_parse(struct drm_device *dev, u8 *temp)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
+ struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
+ int i, headerlen, recordlen, entries;
+
+ if (!temp) {
+ NV_DEBUG(dev, "temperature table pointer invalid\n");
+ return;
+ }
+
+ /* Set the default sensor's contants */
+ sensor->offset_constant = 0;
+ sensor->offset_mult = 1;
+ sensor->offset_div = 1;
+ sensor->slope_mult = 1;
+ sensor->slope_div = 1;
+
+ /* Set the default temperature thresholds */
+ temps->critical = 110;
+ temps->down_clock = 100;
+ temps->fan_boost = 90;
+
+ /* Set the known default values to setup the temperature sensor */
+ if (dev_priv->card_type >= NV_40) {
+ switch (dev_priv->chipset) {
+ case 0x43:
+ sensor->offset_mult = 32060;
+ sensor->offset_div = 1000;
+ sensor->slope_mult = 792;
+ sensor->slope_div = 1000;
+ break;
+
+ case 0x44:
+ case 0x47:
+ case 0x4a:
+ sensor->offset_mult = 27839;
+ sensor->offset_div = 1000;
+ sensor->slope_mult = 780;
+ sensor->slope_div = 1000;
+ break;
+
+ case 0x46:
+ sensor->offset_mult = -24775;
+ sensor->offset_div = 100;
+ sensor->slope_mult = 467;
+ sensor->slope_div = 10000;
+ break;
+
+ case 0x49:
+ sensor->offset_mult = -25051;
+ sensor->offset_div = 100;
+ sensor->slope_mult = 458;
+ sensor->slope_div = 10000;
+ break;
+
+ case 0x4b:
+ sensor->offset_mult = -24088;
+ sensor->offset_div = 100;
+ sensor->slope_mult = 442;
+ sensor->slope_div = 10000;
+ break;
+
+ case 0x50:
+ sensor->offset_mult = -22749;
+ sensor->offset_div = 100;
+ sensor->slope_mult = 431;
+ sensor->slope_div = 10000;
+ break;
+ }
+ }
+
+ headerlen = temp[1];
+ recordlen = temp[2];
+ entries = temp[3];
+ temp = temp + headerlen;
+
+ /* Read the entries from the table */
+ for (i = 0; i < entries; i++) {
+ u16 value = ROM16(temp[1]);
+
+ switch (temp[0]) {
+ case 0x01:
+ if ((value & 0x8f) == 0)
+ sensor->offset_constant = (value >> 9) & 0x7f;
+ break;
+
+ case 0x04:
+ if ((value & 0xf00f) == 0xa000) /* core */
+ temps->critical = (value&0x0ff0) >> 4;
+ break;
+
+ case 0x07:
+ if ((value & 0xf00f) == 0xa000) /* core */
+ temps->down_clock = (value&0x0ff0) >> 4;
+ break;
+
+ case 0x08:
+ if ((value & 0xf00f) == 0xa000) /* core */
+ temps->fan_boost = (value&0x0ff0) >> 4;
+ break;
+
+ case 0x10:
+ sensor->offset_mult = value;
+ break;
+
+ case 0x11:
+ sensor->offset_div = value;
+ break;
+
+ case 0x12:
+ sensor->slope_mult = value;
+ break;
+
+ case 0x13:
+ sensor->slope_div = value;
+ break;
+ }
+ temp += recordlen;
+ }
+
+ nouveau_temp_safety_checks(dev);
+}
+
+static int
+nv40_sensor_setup(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
+ u32 offset = sensor->offset_mult / sensor->offset_div;
+ u32 sensor_calibration;
+
+ /* set up the sensors */
+ sensor_calibration = 120 - offset - sensor->offset_constant;
+ sensor_calibration = sensor_calibration * sensor->slope_div /
+ sensor->slope_mult;
+
+ if (dev_priv->chipset >= 0x46)
+ sensor_calibration |= 0x80000000;
+ else
+ sensor_calibration |= 0x10000000;
+
+ nv_wr32(dev, 0x0015b0, sensor_calibration);
+
+ /* Wait for the sensor to update */
+ msleep(5);
+
+ /* read */
+ return nv_rd32(dev, 0x0015b4) & 0x1fff;
+}
+
+int
+nv40_temp_get(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
+ int offset = sensor->offset_mult / sensor->offset_div;
+ int core_temp;
+
+ if (dev_priv->chipset >= 0x50) {
+ core_temp = nv_rd32(dev, 0x20008);
+ } else {
+ core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff;
+ /* Setup the sensor if the temperature is 0 */
+ if (core_temp == 0)
+ core_temp = nv40_sensor_setup(dev);
+ }
+
+ core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
+ core_temp = core_temp + offset + sensor->offset_constant;
+
+ return core_temp;
+}
+
+int
+nv84_temp_get(struct drm_device *dev)
+{
+ return nv_rd32(dev, 0x20400);
+}
+
+void
+nouveau_temp_safety_checks(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
+
+ if (temps->critical > 120)
+ temps->critical = 120;
+ else if (temps->critical < 80)
+ temps->critical = 80;
+
+ if (temps->down_clock > 110)
+ temps->down_clock = 110;
+ else if (temps->down_clock < 60)
+ temps->down_clock = 60;
+
+ if (temps->fan_boost > 100)
+ temps->fan_boost = 100;
+ else if (temps->fan_boost < 40)
+ temps->fan_boost = 40;
+}
+
+static bool
+probe_monitoring_device(struct nouveau_i2c_chan *i2c,
+ struct i2c_board_info *info)
+{
+ char modalias[16] = "i2c:";
+ struct i2c_client *client;
+
+ strlcat(modalias, info->type, sizeof(modalias));
+ request_module(modalias);
+
+ client = i2c_new_device(&i2c->adapter, info);
+ if (!client)
+ return false;
+
+ if (!client->driver || client->driver->detect(client, info)) {
+ i2c_unregister_device(client);
+ return false;
+ }
+
+ return true;
+}
+
+static void
+nouveau_temp_probe_i2c(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct dcb_table *dcb = &dev_priv->vbios.dcb;
+ struct i2c_board_info info[] = {
+ { I2C_BOARD_INFO("w83l785ts", 0x2d) },
+ { I2C_BOARD_INFO("w83781d", 0x2d) },
+ { I2C_BOARD_INFO("f75375", 0x2e) },
+ { I2C_BOARD_INFO("adt7473", 0x2e) },
+ { I2C_BOARD_INFO("lm99", 0x4c) },
+ { }
+ };
+ int idx = (dcb->version >= 0x40 ?
+ dcb->i2c_default_indices & 0xf : 2);
+
+ nouveau_i2c_identify(dev, "monitoring device", info,
+ probe_monitoring_device, idx);
+}
+
+void
+nouveau_temp_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvbios *bios = &dev_priv->vbios;
+ struct bit_entry P;
+ u8 *temp = NULL;
+
+ if (bios->type == NVBIOS_BIT) {
+ if (bit_table(dev, 'P', &P))
+ return;
+
+ if (P.version == 1)
+ temp = ROMPTR(bios, P.data[12]);
+ else if (P.version == 2)
+ temp = ROMPTR(bios, P.data[16]);
+ else
+ NV_WARN(dev, "unknown temp for BIT P %d\n", P.version);
+
+ nouveau_temp_vbios_parse(dev, temp);
+ }
+
+ nouveau_temp_probe_i2c(dev);
+}
+
+void
+nouveau_temp_fini(struct drm_device *dev)
+{
+
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_volt.c b/drivers/gpu/drm/nouveau/nouveau_volt.c
new file mode 100644
index 000000000000..04fdc00a67d5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_volt.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_pm.h"
+
+static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a };
+static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]);
+
+int
+nouveau_voltage_gpio_get(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio;
+ struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+ u8 vid = 0;
+ int i;
+
+ for (i = 0; i < nr_vidtag; i++) {
+ if (!(volt->vid_mask & (1 << i)))
+ continue;
+
+ vid |= gpio->get(dev, vidtag[i]) << i;
+ }
+
+ return nouveau_volt_lvl_lookup(dev, vid);
+}
+
+int
+nouveau_voltage_gpio_set(struct drm_device *dev, int voltage)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio;
+ struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+ int vid, i;
+
+ vid = nouveau_volt_vid_lookup(dev, voltage);
+ if (vid < 0)
+ return vid;
+
+ for (i = 0; i < nr_vidtag; i++) {
+ if (!(volt->vid_mask & (1 << i)))
+ continue;
+
+ gpio->set(dev, vidtag[i], !!(vid & (1 << i)));
+ }
+
+ return 0;
+}
+
+int
+nouveau_volt_vid_lookup(struct drm_device *dev, int voltage)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+ int i;
+
+ for (i = 0; i < volt->nr_level; i++) {
+ if (volt->level[i].voltage == voltage)
+ return volt->level[i].vid;
+ }
+
+ return -ENOENT;
+}
+
+int
+nouveau_volt_lvl_lookup(struct drm_device *dev, int vid)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+ int i;
+
+ for (i = 0; i < volt->nr_level; i++) {
+ if (volt->level[i].vid == vid)
+ return volt->level[i].voltage;
+ }
+
+ return -ENOENT;
+}
+
+void
+nouveau_volt_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_voltage *voltage = &pm->voltage;
+ struct nvbios *bios = &dev_priv->vbios;
+ struct bit_entry P;
+ u8 *volt = NULL, *entry;
+ int i, headerlen, recordlen, entries, vidmask, vidshift;
+
+ if (bios->type == NVBIOS_BIT) {
+ if (bit_table(dev, 'P', &P))
+ return;
+
+ if (P.version == 1)
+ volt = ROMPTR(bios, P.data[16]);
+ else
+ if (P.version == 2)
+ volt = ROMPTR(bios, P.data[12]);
+ else {
+ NV_WARN(dev, "unknown volt for BIT P %d\n", P.version);
+ }
+ } else {
+ if (bios->data[bios->offset + 6] < 0x27) {
+ NV_DEBUG(dev, "BMP version too old for voltage\n");
+ return;
+ }
+
+ volt = ROMPTR(bios, bios->data[bios->offset + 0x98]);
+ }
+
+ if (!volt) {
+ NV_DEBUG(dev, "voltage table pointer invalid\n");
+ return;
+ }
+
+ switch (volt[0]) {
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ headerlen = 5;
+ recordlen = volt[1];
+ entries = volt[2];
+ vidshift = 0;
+ vidmask = volt[4];
+ break;
+ case 0x20:
+ headerlen = volt[1];
+ recordlen = volt[3];
+ entries = volt[2];
+ vidshift = 0; /* could be vidshift like 0x30? */
+ vidmask = volt[5];
+ break;
+ case 0x30:
+ headerlen = volt[1];
+ recordlen = volt[2];
+ entries = volt[3];
+ vidshift = hweight8(volt[5]);
+ vidmask = volt[4];
+ break;
+ default:
+ NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]);
+ return;
+ }
+
+ /* validate vid mask */
+ voltage->vid_mask = vidmask;
+ if (!voltage->vid_mask)
+ return;
+
+ i = 0;
+ while (vidmask) {
+ if (i > nr_vidtag) {
+ NV_DEBUG(dev, "vid bit %d unknown\n", i);
+ return;
+ }
+
+ if (!nouveau_bios_gpio_entry(dev, vidtag[i])) {
+ NV_DEBUG(dev, "vid bit %d has no gpio tag\n", i);
+ return;
+ }
+
+ vidmask >>= 1;
+ i++;
+ }
+
+ /* parse vbios entries into common format */
+ voltage->level = kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL);
+ if (!voltage->level)
+ return;
+
+ entry = volt + headerlen;
+ for (i = 0; i < entries; i++, entry += recordlen) {
+ voltage->level[i].voltage = entry[0];
+ voltage->level[i].vid = entry[1] >> vidshift;
+ }
+ voltage->nr_level = entries;
+ voltage->supported = true;
+}
+
+void
+nouveau_volt_fini(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+
+ kfree(volt->level);
+}
diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
index 497df8765f28..c71abc2a34d5 100644
--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -33,6 +33,7 @@
#include "nouveau_fb.h"
#include "nouveau_hw.h"
#include "nvreg.h"
+#include "nouveau_fbcon.h"
static int
nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
@@ -109,7 +110,7 @@ static void nv_crtc_calc_state_ext(struct drm_crtc *crtc, struct drm_display_mod
struct nouveau_pll_vals *pv = &regp->pllvals;
struct pll_lims pll_lim;
- if (get_pll_limits(dev, nv_crtc->index ? VPLL2 : VPLL1, &pll_lim))
+ if (get_pll_limits(dev, nv_crtc->index ? PLL_VPLL1 : PLL_VPLL0, &pll_lim))
return;
/* NM2 == 0 is used to determine single stage mode on two stage plls */
@@ -718,6 +719,7 @@ static void nv_crtc_destroy(struct drm_crtc *crtc)
drm_crtc_cleanup(crtc);
+ nouveau_bo_unmap(nv_crtc->cursor.nvbo);
nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
kfree(nv_crtc);
}
@@ -768,8 +770,9 @@ nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start,
}
static int
-nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
+nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
+ struct drm_framebuffer *passed_fb,
+ int x, int y, bool atomic)
{
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_device *dev = crtc->dev;
@@ -780,13 +783,26 @@ nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
int arb_burst, arb_lwm;
int ret;
- ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
- if (ret)
- return ret;
+ /* 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.)
+ */
+ if (atomic) {
+ drm_fb = passed_fb;
+ fb = nouveau_framebuffer(passed_fb);
+ }
+ else {
+ /* If not atomic, we can go ahead and pin, and unpin the
+ * old fb we were passed.
+ */
+ ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
+ if (ret)
+ return ret;
- if (old_fb) {
- struct nouveau_framebuffer *ofb = nouveau_framebuffer(old_fb);
- nouveau_bo_unpin(ofb->nvbo);
+ if (passed_fb) {
+ struct nouveau_framebuffer *ofb = nouveau_framebuffer(passed_fb);
+ nouveau_bo_unpin(ofb->nvbo);
+ }
}
nv_crtc->fb.offset = fb->nvbo->bo.offset;
@@ -826,7 +842,7 @@ nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_FF_INDEX);
crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_FFLWM__INDEX);
- if (dev_priv->card_type >= NV_30) {
+ if (dev_priv->card_type >= NV_20) {
regp->CRTC[NV_CIO_CRE_47] = arb_lwm >> 8;
crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_47);
}
@@ -834,6 +850,29 @@ nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
return 0;
}
+static int
+nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ return nv04_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
+}
+
+static int
+nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y, enum mode_set_atomic state)
+{
+ struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
+ struct drm_device *dev = dev_priv->dev;
+
+ if (state == ENTER_ATOMIC_MODE_SET)
+ nouveau_fbcon_save_disable_accel(dev);
+ else
+ nouveau_fbcon_restore_accel(dev);
+
+ return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true);
+}
+
static void nv04_cursor_upload(struct drm_device *dev, struct nouveau_bo *src,
struct nouveau_bo *dst)
{
@@ -962,6 +1001,7 @@ static const struct drm_crtc_helper_funcs nv04_crtc_helper_funcs = {
.mode_fixup = nv_crtc_mode_fixup,
.mode_set = nv_crtc_mode_set,
.mode_set_base = nv04_crtc_mode_set_base,
+ .mode_set_base_atomic = nv04_crtc_mode_set_base_atomic,
.load_lut = nv_crtc_gamma_load,
};
diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c
index ea3627041ecf..ba6423f2ffcc 100644
--- a/drivers/gpu/drm/nouveau/nv04_dac.c
+++ b/drivers/gpu/drm/nouveau/nv04_dac.c
@@ -291,6 +291,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
msleep(5);
sample = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);
+ /* do it again just in case it's a residual current */
+ sample &= NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);
temp = NVReadRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL);
NVWriteRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL,
@@ -343,22 +345,13 @@ static void nv04_dac_prepare(struct drm_encoder *encoder)
{
struct drm_encoder_helper_funcs *helper = encoder->helper_private;
struct drm_device *dev = encoder->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
int head = nouveau_crtc(encoder->crtc)->index;
- struct nv04_crtc_reg *crtcstate = dev_priv->mode_reg.crtc_reg;
helper->dpms(encoder, DRM_MODE_DPMS_OFF);
nv04_dfp_disable(dev, head);
-
- /* Some NV4x have unknown values (0x3f, 0x50, 0x54, 0x6b, 0x79, 0x7f)
- * at LCD__INDEX which we don't alter
- */
- if (!(crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] & 0x44))
- crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] = 0;
}
-
static void nv04_dac_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c
index 0d3206a7046c..c936403b26e2 100644
--- a/drivers/gpu/drm/nouveau/nv04_dfp.c
+++ b/drivers/gpu/drm/nouveau/nv04_dfp.c
@@ -104,6 +104,8 @@ void nv04_dfp_disable(struct drm_device *dev, int head)
}
/* don't inadvertently turn it on when state written later */
crtcstate[head].fp_control = FP_TG_CONTROL_OFF;
+ crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] &=
+ ~NV_CIO_CRE_LCD_ROUTE_MASK;
}
void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode)
@@ -253,26 +255,21 @@ static void nv04_dfp_prepare(struct drm_encoder *encoder)
nv04_dfp_prepare_sel_clk(dev, nv_encoder, head);
- /* Some NV4x have unknown values (0x3f, 0x50, 0x54, 0x6b, 0x79, 0x7f)
- * at LCD__INDEX which we don't alter
- */
- if (!(*cr_lcd & 0x44)) {
- *cr_lcd = 0x3;
-
- if (nv_two_heads(dev)) {
- if (nv_encoder->dcb->location == DCB_LOC_ON_CHIP)
- *cr_lcd |= head ? 0x0 : 0x8;
- else {
- *cr_lcd |= (nv_encoder->dcb->or << 4) & 0x30;
- if (nv_encoder->dcb->type == OUTPUT_LVDS)
- *cr_lcd |= 0x30;
- if ((*cr_lcd & 0x30) == (*cr_lcd_oth & 0x30)) {
- /* avoid being connected to both crtcs */
- *cr_lcd_oth &= ~0x30;
- NVWriteVgaCrtc(dev, head ^ 1,
- NV_CIO_CRE_LCD__INDEX,
- *cr_lcd_oth);
- }
+ *cr_lcd = (*cr_lcd & ~NV_CIO_CRE_LCD_ROUTE_MASK) | 0x3;
+
+ if (nv_two_heads(dev)) {
+ if (nv_encoder->dcb->location == DCB_LOC_ON_CHIP)
+ *cr_lcd |= head ? 0x0 : 0x8;
+ else {
+ *cr_lcd |= (nv_encoder->dcb->or << 4) & 0x30;
+ if (nv_encoder->dcb->type == OUTPUT_LVDS)
+ *cr_lcd |= 0x30;
+ if ((*cr_lcd & 0x30) == (*cr_lcd_oth & 0x30)) {
+ /* avoid being connected to both crtcs */
+ *cr_lcd_oth &= ~0x30;
+ NVWriteVgaCrtc(dev, head ^ 1,
+ NV_CIO_CRE_LCD__INDEX,
+ *cr_lcd_oth);
}
}
}
@@ -640,7 +637,7 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder)
get_tmds_slave(encoder))
return;
- type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2);
+ type = nouveau_i2c_identify(dev, "TMDS transmitter", info, NULL, 2);
if (type < 0)
return;
diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c
index 1eeac4fae73d..33e4c9388bc1 100644
--- a/drivers/gpu/drm/nouveau/nv04_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c
@@ -25,6 +25,7 @@
#include "drmP.h"
#include "nouveau_drv.h"
#include "nouveau_dma.h"
+#include "nouveau_ramht.h"
#include "nouveau_fbcon.h"
void
@@ -169,11 +170,9 @@ nv04_fbcon_grobj_new(struct drm_device *dev, int class, uint32_t handle)
if (ret)
return ret;
- ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, handle, obj, NULL);
- if (ret)
- return ret;
-
- return 0;
+ ret = nouveau_ramht_insert(dev_priv->channel, handle, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ return ret;
}
int
diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c
index 06cedd99c26a..708293b7ddcd 100644
--- a/drivers/gpu/drm/nouveau/nv04_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv04_fifo.c
@@ -27,8 +27,9 @@
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
-#define NV04_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV04_RAMFC__SIZE))
+#define NV04_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV04_RAMFC__SIZE))
#define NV04_RAMFC__SIZE 32
#define NV04_RAMFC_DMA_PUT 0x00
#define NV04_RAMFC_DMA_GET 0x04
@@ -38,10 +39,8 @@
#define NV04_RAMFC_ENGINE 0x14
#define NV04_RAMFC_PULL1_ENGINE 0x18
-#define RAMFC_WR(offset, val) nv_wo32(dev, chan->ramfc->gpuobj, \
- NV04_RAMFC_##offset/4, (val))
-#define RAMFC_RD(offset) nv_ro32(dev, chan->ramfc->gpuobj, \
- NV04_RAMFC_##offset/4)
+#define RAMFC_WR(offset, val) nv_wo32(chan->ramfc, NV04_RAMFC_##offset, (val))
+#define RAMFC_RD(offset) nv_ro32(chan->ramfc, NV04_RAMFC_##offset)
void
nv04_fifo_disable(struct drm_device *dev)
@@ -72,37 +71,32 @@ nv04_fifo_reassign(struct drm_device *dev, bool enable)
}
bool
-nv04_fifo_cache_flush(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
- uint64_t start = ptimer->read(dev);
-
- do {
- if (nv_rd32(dev, NV03_PFIFO_CACHE1_GET) ==
- nv_rd32(dev, NV03_PFIFO_CACHE1_PUT))
- return true;
-
- } while (ptimer->read(dev) - start < 100000000);
-
- NV_ERROR(dev, "Timeout flushing the PFIFO cache.\n");
-
- return false;
-}
-
-bool
nv04_fifo_cache_pull(struct drm_device *dev, bool enable)
{
- uint32_t pull = nv_rd32(dev, NV04_PFIFO_CACHE1_PULL0);
+ int pull = nv_mask(dev, NV04_PFIFO_CACHE1_PULL0, 1, enable);
+
+ if (!enable) {
+ /* In some cases the PFIFO puller may be left in an
+ * inconsistent state if you try to stop it when it's
+ * busy translating handles. Sometimes you get a
+ * PFIFO_CACHE_ERROR, sometimes it just fails silently
+ * sending incorrect instance offsets to PGRAPH after
+ * it's started up again. To avoid the latter we
+ * invalidate the most recently calculated instance.
+ */
+ if (!nv_wait(dev, NV04_PFIFO_CACHE1_PULL0,
+ NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0))
+ NV_ERROR(dev, "Timeout idling the PFIFO puller.\n");
+
+ if (nv_rd32(dev, NV04_PFIFO_CACHE1_PULL0) &
+ NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
+ nv_wr32(dev, NV03_PFIFO_INTR_0,
+ NV_PFIFO_INTR_CACHE_ERROR);
- if (enable) {
- nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, pull | 1);
- } else {
- nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, pull & ~1);
nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0);
}
- return !!(pull & 1);
+ return pull & 1;
}
int
@@ -130,7 +124,7 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
NV04_RAMFC__SIZE,
NVOBJ_FLAG_ZERO_ALLOC |
NVOBJ_FLAG_ZERO_FREE,
- NULL, &chan->ramfc);
+ &chan->ramfc);
if (ret)
return ret;
@@ -139,7 +133,7 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
/* Setup initial state */
RAMFC_WR(DMA_PUT, chan->pushbuf_base);
RAMFC_WR(DMA_GET, chan->pushbuf_base);
- RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4);
+ RAMFC_WR(DMA_INSTANCE, chan->pushbuf->pinst >> 4);
RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
@@ -161,7 +155,7 @@ nv04_fifo_destroy_context(struct nouveau_channel *chan)
nv_wr32(dev, NV04_PFIFO_MODE,
nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
- nouveau_gpuobj_ref_del(dev, &chan->ramfc);
+ nouveau_gpuobj_ref(NULL, &chan->ramfc);
}
static void
@@ -264,10 +258,10 @@ nv04_fifo_init_ramxx(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private;
nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
- ((dev_priv->ramht_bits - 9) << 16) |
- (dev_priv->ramht_offset >> 8));
- nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8);
- nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc_offset >> 8);
+ ((dev_priv->ramht->bits - 9) << 16) |
+ (dev_priv->ramht->gpuobj->pinst >> 8));
+ nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8);
+ nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc->pinst >> 8);
}
static void
diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c
index 4408232d33f1..0b5ae297abde 100644
--- a/drivers/gpu/drm/nouveau/nv04_instmem.c
+++ b/drivers/gpu/drm/nouveau/nv04_instmem.c
@@ -1,6 +1,7 @@
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
/* returns the size of fifo context */
static int
@@ -17,102 +18,51 @@ nouveau_fifo_ctx_size(struct drm_device *dev)
return 32;
}
-static void
-nv04_instmem_determine_amount(struct drm_device *dev)
+int nv04_instmem_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- int i;
+ struct nouveau_gpuobj *ramht = NULL;
+ u32 offset, length;
+ int ret;
- /* Figure out how much instance memory we need */
- if (dev_priv->card_type >= NV_40) {
- /* We'll want more instance memory than this on some NV4x cards.
- * There's a 16MB aperture to play with that maps onto the end
- * of vram. For now, only reserve a small piece until we know
- * more about what each chipset requires.
- */
- switch (dev_priv->chipset) {
- case 0x40:
- case 0x47:
- case 0x49:
- case 0x4b:
- dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024);
- break;
- default:
- dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024);
- break;
- }
- } else {
- /*XXX: what *are* the limits on <NV40 cards?
- */
- dev_priv->ramin_rsvd_vram = (512 * 1024);
- }
- NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10);
+ /* RAMIN always available */
+ dev_priv->ramin_available = true;
- /* Clear all of it, except the BIOS image that's in the first 64KiB */
- for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4)
- nv_wi32(dev, i, 0x00000000);
-}
+ /* Setup shared RAMHT */
+ ret = nouveau_gpuobj_new_fake(dev, 0x10000, ~0, 4096,
+ NVOBJ_FLAG_ZERO_ALLOC, &ramht);
+ if (ret)
+ return ret;
-static void
-nv04_instmem_configure_fixed_tables(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_engine *engine = &dev_priv->engine;
+ ret = nouveau_ramht_new(dev, ramht, &dev_priv->ramht);
+ nouveau_gpuobj_ref(NULL, &ramht);
+ if (ret)
+ return ret;
- /* FIFO hash table (RAMHT)
- * use 4k hash table at RAMIN+0x10000
- * TODO: extend the hash table
- */
- dev_priv->ramht_offset = 0x10000;
- dev_priv->ramht_bits = 9;
- dev_priv->ramht_size = (1 << dev_priv->ramht_bits); /* nr entries */
- dev_priv->ramht_size *= 8; /* 2 32-bit values per entry in RAMHT */
- NV_DEBUG(dev, "RAMHT offset=0x%x, size=%d\n", dev_priv->ramht_offset,
- dev_priv->ramht_size);
-
- /* FIFO runout table (RAMRO) - 512k at 0x11200 */
- dev_priv->ramro_offset = 0x11200;
- dev_priv->ramro_size = 512;
- NV_DEBUG(dev, "RAMRO offset=0x%x, size=%d\n", dev_priv->ramro_offset,
- dev_priv->ramro_size);
-
- /* FIFO context table (RAMFC)
- * NV40 : Not sure exactly how to position RAMFC on some cards,
- * 0x30002 seems to position it at RAMIN+0x20000 on these
- * cards. RAMFC is 4kb (32 fifos, 128byte entries).
- * Others: Position RAMFC at RAMIN+0x11400
- */
- dev_priv->ramfc_size = engine->fifo.channels *
- nouveau_fifo_ctx_size(dev);
+ /* And RAMRO */
+ ret = nouveau_gpuobj_new_fake(dev, 0x11200, ~0, 512,
+ NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->ramro);
+ if (ret)
+ return ret;
+
+ /* And RAMFC */
+ length = dev_priv->engine.fifo.channels * nouveau_fifo_ctx_size(dev);
switch (dev_priv->card_type) {
case NV_40:
- dev_priv->ramfc_offset = 0x20000;
+ offset = 0x20000;
break;
- case NV_30:
- case NV_20:
- case NV_10:
- case NV_04:
default:
- dev_priv->ramfc_offset = 0x11400;
+ offset = 0x11400;
break;
}
- NV_DEBUG(dev, "RAMFC offset=0x%x, size=%d\n", dev_priv->ramfc_offset,
- dev_priv->ramfc_size);
-}
-int nv04_instmem_init(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t offset;
- int ret;
-
- nv04_instmem_determine_amount(dev);
- nv04_instmem_configure_fixed_tables(dev);
+ ret = nouveau_gpuobj_new_fake(dev, offset, ~0, length,
+ NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->ramfc);
+ if (ret)
+ return ret;
- /* Create a heap to manage RAMIN allocations, we don't allocate
- * the space that was reserved for RAMHT/FC/RO.
- */
- offset = dev_priv->ramfc_offset + dev_priv->ramfc_size;
+ /* Only allow space after RAMFC to be used for object allocation */
+ offset += length;
/* It appears RAMRO (or something?) is controlled by 0x2220/0x2230
* on certain NV4x chipsets as well as RAMFC. When 0x2230 == 0
@@ -140,46 +90,34 @@ int nv04_instmem_init(struct drm_device *dev)
void
nv04_instmem_takedown(struct drm_device *dev)
{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ nouveau_ramht_ref(NULL, &dev_priv->ramht, NULL);
+ nouveau_gpuobj_ref(NULL, &dev_priv->ramro);
+ nouveau_gpuobj_ref(NULL, &dev_priv->ramfc);
}
int
-nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, uint32_t *sz)
+nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
+ uint32_t *sz)
{
- if (gpuobj->im_backing)
- return -EINVAL;
-
return 0;
}
void
nv04_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if (gpuobj && gpuobj->im_backing) {
- if (gpuobj->im_bound)
- dev_priv->engine.instmem.unbind(dev, gpuobj);
- gpuobj->im_backing = NULL;
- }
}
int
nv04_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
{
- if (!gpuobj->im_pramin || gpuobj->im_bound)
- return -EINVAL;
-
- gpuobj->im_bound = 1;
return 0;
}
int
nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
{
- if (gpuobj->im_bound == 0)
- return -EINVAL;
-
- gpuobj->im_bound = 0;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c
new file mode 100644
index 000000000000..6a6eb697d38e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv04_pm.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_hw.h"
+#include "nouveau_pm.h"
+
+struct nv04_pm_state {
+ struct pll_lims pll;
+ struct nouveau_pll_vals calc;
+};
+
+int
+nv04_pm_clock_get(struct drm_device *dev, u32 id)
+{
+ return nouveau_hw_get_clock(dev, id);
+}
+
+void *
+nv04_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
+ u32 id, int khz)
+{
+ struct nv04_pm_state *state;
+ int ret;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return ERR_PTR(-ENOMEM);
+
+ ret = get_pll_limits(dev, id, &state->pll);
+ if (ret) {
+ kfree(state);
+ return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+ }
+
+ ret = nouveau_calc_pll_mnp(dev, &state->pll, khz, &state->calc);
+ if (!ret) {
+ kfree(state);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return state;
+}
+
+void
+nv04_pm_clock_set(struct drm_device *dev, void *pre_state)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv04_pm_state *state = pre_state;
+ u32 reg = state->pll.reg;
+
+ /* thank the insane nouveau_hw_setpll() interface for this */
+ if (dev_priv->card_type >= NV_40)
+ reg += 4;
+
+ nouveau_hw_setpll(dev, reg, &state->calc);
+ kfree(state);
+}
+
diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c
index 0b5d012d7c28..3eb605ddfd03 100644
--- a/drivers/gpu/drm/nouveau/nv04_tv.c
+++ b/drivers/gpu/drm/nouveau/nv04_tv.c
@@ -49,8 +49,8 @@ static struct i2c_board_info nv04_tv_encoder_info[] = {
int nv04_tv_identify(struct drm_device *dev, int i2c_index)
{
- return nouveau_i2c_identify(dev, "TV encoder",
- nv04_tv_encoder_info, i2c_index);
+ return nouveau_i2c_identify(dev, "TV encoder", nv04_tv_encoder_info,
+ NULL, i2c_index);
}
@@ -99,12 +99,10 @@ static void nv04_tv_bind(struct drm_device *dev, int head, bool bind)
state->tv_setup = 0;
- if (bind) {
- state->CRTC[NV_CIO_CRE_LCD__INDEX] = 0;
+ if (bind)
state->CRTC[NV_CIO_CRE_49] |= 0x10;
- } else {
+ else
state->CRTC[NV_CIO_CRE_49] &= ~0x10;
- }
NVWriteVgaCrtc(dev, head, NV_CIO_CRE_LCD__INDEX,
state->CRTC[NV_CIO_CRE_LCD__INDEX]);
diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c
index 7a4069cf5d0b..f1b03ad58fd5 100644
--- a/drivers/gpu/drm/nouveau/nv10_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv10_fifo.c
@@ -27,8 +27,9 @@
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
-#define NV10_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV10_RAMFC__SIZE))
+#define NV10_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV10_RAMFC__SIZE))
#define NV10_RAMFC__SIZE ((dev_priv->chipset) >= 0x17 ? 64 : 32)
int
@@ -48,7 +49,7 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
ret = nouveau_gpuobj_new_fake(dev, NV10_RAMFC(chan->id), ~0,
NV10_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_ZERO_FREE, NULL, &chan->ramfc);
+ NVOBJ_FLAG_ZERO_FREE, &chan->ramfc);
if (ret)
return ret;
@@ -57,7 +58,7 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
*/
nv_wi32(dev, fc + 0, chan->pushbuf_base);
nv_wi32(dev, fc + 4, chan->pushbuf_base);
- nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
+ nv_wi32(dev, fc + 12, chan->pushbuf->pinst >> 4);
nv_wi32(dev, fc + 20, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
@@ -80,7 +81,7 @@ nv10_fifo_destroy_context(struct nouveau_channel *chan)
nv_wr32(dev, NV04_PFIFO_MODE,
nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
- nouveau_gpuobj_ref_del(dev, &chan->ramfc);
+ nouveau_gpuobj_ref(NULL, &chan->ramfc);
}
static void
@@ -202,14 +203,14 @@ nv10_fifo_init_ramxx(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private;
nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
- ((dev_priv->ramht_bits - 9) << 16) |
- (dev_priv->ramht_offset >> 8));
- nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8);
+ ((dev_priv->ramht->bits - 9) << 16) |
+ (dev_priv->ramht->gpuobj->pinst >> 8));
+ nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8);
if (dev_priv->chipset < 0x17) {
- nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc_offset >> 8);
+ nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc->pinst >> 8);
} else {
- nv_wr32(dev, NV03_PFIFO_RAMFC, (dev_priv->ramfc_offset >> 8) |
+ nv_wr32(dev, NV03_PFIFO_RAMFC, (dev_priv->ramfc->pinst >> 8) |
(1 << 16) /* 64 Bytes entry*/);
/* XXX nvidia blob set bit 18, 21,23 for nv20 & nv30 */
}
diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c
index b2f6a57c0cc5..8e68c9731159 100644
--- a/drivers/gpu/drm/nouveau/nv10_graph.c
+++ b/drivers/gpu/drm/nouveau/nv10_graph.c
@@ -803,7 +803,7 @@ nv10_graph_context_switch(struct drm_device *dev)
/* Load context for next channel */
chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
chan = dev_priv->fifos[chid];
- if (chan)
+ if (chan && chan->pgraph_ctx)
nv10_graph_load_context(chan);
pgraph->fifo_access(dev, true);
diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c
index 13cdc05b7c2d..28119fd19d03 100644
--- a/drivers/gpu/drm/nouveau/nv17_tv.c
+++ b/drivers/gpu/drm/nouveau/nv17_tv.c
@@ -193,55 +193,56 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector)
}
}
-static const struct {
- int hdisplay;
- int vdisplay;
-} modes[] = {
- { 640, 400 },
- { 640, 480 },
- { 720, 480 },
- { 720, 576 },
- { 800, 600 },
- { 1024, 768 },
- { 1280, 720 },
- { 1280, 1024 },
- { 1920, 1080 }
-};
-
-static int nv17_tv_get_modes(struct drm_encoder *encoder,
- struct drm_connector *connector)
+static int nv17_tv_get_ld_modes(struct drm_encoder *encoder,
+ struct drm_connector *connector)
{
struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
- struct drm_display_mode *mode;
- struct drm_display_mode *output_mode;
+ struct drm_display_mode *mode, *tv_mode;
int n = 0;
- int i;
-
- if (tv_norm->kind != CTV_ENC_MODE) {
- struct drm_display_mode *tv_mode;
- for (tv_mode = nv17_tv_modes; tv_mode->hdisplay; tv_mode++) {
- mode = drm_mode_duplicate(encoder->dev, tv_mode);
+ for (tv_mode = nv17_tv_modes; tv_mode->hdisplay; tv_mode++) {
+ mode = drm_mode_duplicate(encoder->dev, tv_mode);
- mode->clock = tv_norm->tv_enc_mode.vrefresh *
- mode->htotal / 1000 *
- mode->vtotal / 1000;
+ mode->clock = tv_norm->tv_enc_mode.vrefresh *
+ mode->htotal / 1000 *
+ mode->vtotal / 1000;
- if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
- mode->clock *= 2;
+ if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+ mode->clock *= 2;
- if (mode->hdisplay == tv_norm->tv_enc_mode.hdisplay &&
- mode->vdisplay == tv_norm->tv_enc_mode.vdisplay)
- mode->type |= DRM_MODE_TYPE_PREFERRED;
+ if (mode->hdisplay == tv_norm->tv_enc_mode.hdisplay &&
+ mode->vdisplay == tv_norm->tv_enc_mode.vdisplay)
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
- drm_mode_probed_add(connector, mode);
- n++;
- }
- return n;
+ drm_mode_probed_add(connector, mode);
+ n++;
}
- /* tv_norm->kind == CTV_ENC_MODE */
- output_mode = &tv_norm->ctv_enc_mode.mode;
+ return n;
+}
+
+static int nv17_tv_get_hd_modes(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
+ struct drm_display_mode *output_mode = &tv_norm->ctv_enc_mode.mode;
+ struct drm_display_mode *mode;
+ const struct {
+ int hdisplay;
+ int vdisplay;
+ } modes[] = {
+ { 640, 400 },
+ { 640, 480 },
+ { 720, 480 },
+ { 720, 576 },
+ { 800, 600 },
+ { 1024, 768 },
+ { 1280, 720 },
+ { 1280, 1024 },
+ { 1920, 1080 }
+ };
+ int i, n = 0;
+
for (i = 0; i < ARRAY_SIZE(modes); i++) {
if (modes[i].hdisplay > output_mode->hdisplay ||
modes[i].vdisplay > output_mode->vdisplay)
@@ -251,11 +252,12 @@ static int nv17_tv_get_modes(struct drm_encoder *encoder,
modes[i].vdisplay == output_mode->vdisplay) {
mode = drm_mode_duplicate(encoder->dev, output_mode);
mode->type |= DRM_MODE_TYPE_PREFERRED;
+
} else {
mode = drm_cvt_mode(encoder->dev, modes[i].hdisplay,
- modes[i].vdisplay, 60, false,
- output_mode->flags & DRM_MODE_FLAG_INTERLACE,
- false);
+ modes[i].vdisplay, 60, false,
+ (output_mode->flags &
+ DRM_MODE_FLAG_INTERLACE), false);
}
/* CVT modes are sometimes unsuitable... */
@@ -266,6 +268,7 @@ static int nv17_tv_get_modes(struct drm_encoder *encoder,
- mode->hdisplay) * 9 / 10) & ~7;
mode->hsync_end = mode->hsync_start + 8;
}
+
if (output_mode->vdisplay >= 1024) {
mode->vtotal = output_mode->vtotal;
mode->vsync_start = output_mode->vsync_start;
@@ -276,9 +279,21 @@ static int nv17_tv_get_modes(struct drm_encoder *encoder,
drm_mode_probed_add(connector, mode);
n++;
}
+
return n;
}
+static int nv17_tv_get_modes(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
+
+ if (tv_norm->kind == CTV_ENC_MODE)
+ return nv17_tv_get_hd_modes(encoder, connector);
+ else
+ return nv17_tv_get_ld_modes(encoder, connector);
+}
+
static int nv17_tv_mode_valid(struct drm_encoder *encoder,
struct drm_display_mode *mode)
{
@@ -408,15 +423,8 @@ static void nv17_tv_prepare(struct drm_encoder *encoder)
}
- /* Some NV4x have unknown values (0x3f, 0x50, 0x54, 0x6b, 0x79, 0x7f)
- * at LCD__INDEX which we don't alter
- */
- if (!(*cr_lcd & 0x44)) {
- if (tv_norm->kind == CTV_ENC_MODE)
- *cr_lcd = 0x1 | (head ? 0x0 : 0x8);
- else
- *cr_lcd = 0;
- }
+ if (tv_norm->kind == CTV_ENC_MODE)
+ *cr_lcd |= 0x1 | (head ? 0x0 : 0x8);
/* Set the DACCLK register */
dacclk = (NVReadRAMDAC(dev, 0, dacclk_off) & ~0x30) | 0x1;
diff --git a/drivers/gpu/drm/nouveau/nv17_tv.h b/drivers/gpu/drm/nouveau/nv17_tv.h
index c00977cedabd..6bf03840f9eb 100644
--- a/drivers/gpu/drm/nouveau/nv17_tv.h
+++ b/drivers/gpu/drm/nouveau/nv17_tv.h
@@ -127,7 +127,8 @@ void nv17_ctv_update_rescaler(struct drm_encoder *encoder);
/* TV hardware access functions */
-static inline void nv_write_ptv(struct drm_device *dev, uint32_t reg, uint32_t val)
+static inline void nv_write_ptv(struct drm_device *dev, uint32_t reg,
+ uint32_t val)
{
nv_wr32(dev, reg, val);
}
@@ -137,7 +138,8 @@ static inline uint32_t nv_read_ptv(struct drm_device *dev, uint32_t reg)
return nv_rd32(dev, reg);
}
-static inline void nv_write_tv_enc(struct drm_device *dev, uint8_t reg, uint8_t val)
+static inline void nv_write_tv_enc(struct drm_device *dev, uint8_t reg,
+ uint8_t val)
{
nv_write_ptv(dev, NV_PTV_TV_INDEX, reg);
nv_write_ptv(dev, NV_PTV_TV_DATA, val);
@@ -149,8 +151,11 @@ static inline uint8_t nv_read_tv_enc(struct drm_device *dev, uint8_t reg)
return nv_read_ptv(dev, NV_PTV_TV_DATA);
}
-#define nv_load_ptv(dev, state, reg) nv_write_ptv(dev, NV_PTV_OFFSET + 0x##reg, state->ptv_##reg)
-#define nv_save_ptv(dev, state, reg) state->ptv_##reg = nv_read_ptv(dev, NV_PTV_OFFSET + 0x##reg)
-#define nv_load_tv_enc(dev, state, reg) nv_write_tv_enc(dev, 0x##reg, state->tv_enc[0x##reg])
+#define nv_load_ptv(dev, state, reg) \
+ nv_write_ptv(dev, NV_PTV_OFFSET + 0x##reg, state->ptv_##reg)
+#define nv_save_ptv(dev, state, reg) \
+ state->ptv_##reg = nv_read_ptv(dev, NV_PTV_OFFSET + 0x##reg)
+#define nv_load_tv_enc(dev, state, reg) \
+ nv_write_tv_enc(dev, 0x##reg, state->tv_enc[0x##reg])
#endif
diff --git a/drivers/gpu/drm/nouveau/nv17_tv_modes.c b/drivers/gpu/drm/nouveau/nv17_tv_modes.c
index d64683d97e0d..9d3893c50a41 100644
--- a/drivers/gpu/drm/nouveau/nv17_tv_modes.c
+++ b/drivers/gpu/drm/nouveau/nv17_tv_modes.c
@@ -336,12 +336,17 @@ static void tv_setup_filter(struct drm_encoder *encoder)
struct filter_params *p = &fparams[k][j];
for (i = 0; i < 7; i++) {
- int64_t c = (p->k1 + p->ki*i + p->ki2*i*i + p->ki3*i*i*i)
- + (p->kr + p->kir*i + p->ki2r*i*i + p->ki3r*i*i*i)*rs[k]
- + (p->kf + p->kif*i + p->ki2f*i*i + p->ki3f*i*i*i)*flicker
- + (p->krf + p->kirf*i + p->ki2rf*i*i + p->ki3rf*i*i*i)*flicker*rs[k];
-
- (*filters[k])[j][i] = (c + id5/2) >> 39 & (0x1 << 31 | 0x7f << 9);
+ int64_t c = (p->k1 + p->ki*i + p->ki2*i*i +
+ p->ki3*i*i*i)
+ + (p->kr + p->kir*i + p->ki2r*i*i +
+ p->ki3r*i*i*i) * rs[k]
+ + (p->kf + p->kif*i + p->ki2f*i*i +
+ p->ki3f*i*i*i) * flicker
+ + (p->krf + p->kirf*i + p->ki2rf*i*i +
+ p->ki3rf*i*i*i) * flicker * rs[k];
+
+ (*filters[k])[j][i] = (c + id5/2) >> 39
+ & (0x1 << 31 | 0x7f << 9);
}
}
}
@@ -349,7 +354,8 @@ static void tv_setup_filter(struct drm_encoder *encoder)
/* Hardware state saving/restoring */
-static void tv_save_filter(struct drm_device *dev, uint32_t base, uint32_t regs[4][7])
+static void tv_save_filter(struct drm_device *dev, uint32_t base,
+ uint32_t regs[4][7])
{
int i, j;
uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c };
@@ -360,7 +366,8 @@ static void tv_save_filter(struct drm_device *dev, uint32_t base, uint32_t regs[
}
}
-static void tv_load_filter(struct drm_device *dev, uint32_t base, uint32_t regs[4][7])
+static void tv_load_filter(struct drm_device *dev, uint32_t base,
+ uint32_t regs[4][7])
{
int i, j;
uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c };
@@ -504,10 +511,10 @@ void nv17_tv_update_properties(struct drm_encoder *encoder)
break;
}
- regs->tv_enc[0x20] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x20], 255,
- tv_enc->saturation);
- regs->tv_enc[0x22] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x22], 255,
- tv_enc->saturation);
+ regs->tv_enc[0x20] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x20],
+ 255, tv_enc->saturation);
+ regs->tv_enc[0x22] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x22],
+ 255, tv_enc->saturation);
regs->tv_enc[0x25] = tv_enc->hue * 255 / 100;
nv_load_ptv(dev, regs, 204);
@@ -541,7 +548,8 @@ void nv17_ctv_update_rescaler(struct drm_encoder *encoder)
int head = nouveau_crtc(encoder->crtc)->index;
struct nv04_crtc_reg *regs = &dev_priv->mode_reg.crtc_reg[head];
struct drm_display_mode *crtc_mode = &encoder->crtc->mode;
- struct drm_display_mode *output_mode = &get_tv_norm(encoder)->ctv_enc_mode.mode;
+ struct drm_display_mode *output_mode =
+ &get_tv_norm(encoder)->ctv_enc_mode.mode;
int overscan, hmargin, vmargin, hratio, vratio;
/* The rescaler doesn't do the right thing for interlaced modes. */
@@ -553,13 +561,15 @@ void nv17_ctv_update_rescaler(struct drm_encoder *encoder)
hmargin = (output_mode->hdisplay - crtc_mode->hdisplay) / 2;
vmargin = (output_mode->vdisplay - crtc_mode->vdisplay) / 2;
- hmargin = interpolate(0, min(hmargin, output_mode->hdisplay/20), hmargin,
- overscan);
- vmargin = interpolate(0, min(vmargin, output_mode->vdisplay/20), vmargin,
- overscan);
+ hmargin = interpolate(0, min(hmargin, output_mode->hdisplay/20),
+ hmargin, overscan);
+ vmargin = interpolate(0, min(vmargin, output_mode->vdisplay/20),
+ vmargin, overscan);
- hratio = crtc_mode->hdisplay * 0x800 / (output_mode->hdisplay - 2*hmargin);
- vratio = crtc_mode->vdisplay * 0x800 / (output_mode->vdisplay - 2*vmargin) & ~3;
+ hratio = crtc_mode->hdisplay * 0x800 /
+ (output_mode->hdisplay - 2*hmargin);
+ vratio = crtc_mode->vdisplay * 0x800 /
+ (output_mode->vdisplay - 2*vmargin) & ~3;
regs->fp_horiz_regs[FP_VALID_START] = hmargin;
regs->fp_horiz_regs[FP_VALID_END] = output_mode->hdisplay - hmargin - 1;
diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
index 17f309b36c91..12ab9cd56eca 100644
--- a/drivers/gpu/drm/nouveau/nv20_graph.c
+++ b/drivers/gpu/drm/nouveau/nv20_graph.c
@@ -37,49 +37,49 @@ nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
{
int i;
- nv_wo32(dev, ctx, 0x033c/4, 0xffff0000);
- nv_wo32(dev, ctx, 0x03a0/4, 0x0fff0000);
- nv_wo32(dev, ctx, 0x03a4/4, 0x0fff0000);
- nv_wo32(dev, ctx, 0x047c/4, 0x00000101);
- nv_wo32(dev, ctx, 0x0490/4, 0x00000111);
- nv_wo32(dev, ctx, 0x04a8/4, 0x44400000);
+ nv_wo32(ctx, 0x033c, 0xffff0000);
+ nv_wo32(ctx, 0x03a0, 0x0fff0000);
+ nv_wo32(ctx, 0x03a4, 0x0fff0000);
+ nv_wo32(ctx, 0x047c, 0x00000101);
+ nv_wo32(ctx, 0x0490, 0x00000111);
+ nv_wo32(ctx, 0x04a8, 0x44400000);
for (i = 0x04d4; i <= 0x04e0; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00030303);
+ nv_wo32(ctx, i, 0x00030303);
for (i = 0x04f4; i <= 0x0500; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00080000);
+ nv_wo32(ctx, i, 0x00080000);
for (i = 0x050c; i <= 0x0518; i += 4)
- nv_wo32(dev, ctx, i/4, 0x01012000);
+ nv_wo32(ctx, i, 0x01012000);
for (i = 0x051c; i <= 0x0528; i += 4)
- nv_wo32(dev, ctx, i/4, 0x000105b8);
+ nv_wo32(ctx, i, 0x000105b8);
for (i = 0x052c; i <= 0x0538; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00080008);
+ nv_wo32(ctx, i, 0x00080008);
for (i = 0x055c; i <= 0x0598; i += 4)
- nv_wo32(dev, ctx, i/4, 0x07ff0000);
- nv_wo32(dev, ctx, 0x05a4/4, 0x4b7fffff);
- nv_wo32(dev, ctx, 0x05fc/4, 0x00000001);
- nv_wo32(dev, ctx, 0x0604/4, 0x00004000);
- nv_wo32(dev, ctx, 0x0610/4, 0x00000001);
- nv_wo32(dev, ctx, 0x0618/4, 0x00040000);
- nv_wo32(dev, ctx, 0x061c/4, 0x00010000);
+ nv_wo32(ctx, i, 0x07ff0000);
+ nv_wo32(ctx, 0x05a4, 0x4b7fffff);
+ nv_wo32(ctx, 0x05fc, 0x00000001);
+ nv_wo32(ctx, 0x0604, 0x00004000);
+ nv_wo32(ctx, 0x0610, 0x00000001);
+ nv_wo32(ctx, 0x0618, 0x00040000);
+ nv_wo32(ctx, 0x061c, 0x00010000);
for (i = 0x1c1c; i <= 0x248c; i += 16) {
- nv_wo32(dev, ctx, (i + 0)/4, 0x10700ff9);
- nv_wo32(dev, ctx, (i + 4)/4, 0x0436086c);
- nv_wo32(dev, ctx, (i + 8)/4, 0x000c001b);
+ nv_wo32(ctx, (i + 0), 0x10700ff9);
+ nv_wo32(ctx, (i + 4), 0x0436086c);
+ nv_wo32(ctx, (i + 8), 0x000c001b);
}
- nv_wo32(dev, ctx, 0x281c/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x2830/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x285c/4, 0x40000000);
- nv_wo32(dev, ctx, 0x2860/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x2864/4, 0x3f000000);
- nv_wo32(dev, ctx, 0x286c/4, 0x40000000);
- nv_wo32(dev, ctx, 0x2870/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x2878/4, 0xbf800000);
- nv_wo32(dev, ctx, 0x2880/4, 0xbf800000);
- nv_wo32(dev, ctx, 0x34a4/4, 0x000fe000);
- nv_wo32(dev, ctx, 0x3530/4, 0x000003f8);
- nv_wo32(dev, ctx, 0x3540/4, 0x002fe000);
+ nv_wo32(ctx, 0x281c, 0x3f800000);
+ nv_wo32(ctx, 0x2830, 0x3f800000);
+ nv_wo32(ctx, 0x285c, 0x40000000);
+ nv_wo32(ctx, 0x2860, 0x3f800000);
+ nv_wo32(ctx, 0x2864, 0x3f000000);
+ nv_wo32(ctx, 0x286c, 0x40000000);
+ nv_wo32(ctx, 0x2870, 0x3f800000);
+ nv_wo32(ctx, 0x2878, 0xbf800000);
+ nv_wo32(ctx, 0x2880, 0xbf800000);
+ nv_wo32(ctx, 0x34a4, 0x000fe000);
+ nv_wo32(ctx, 0x3530, 0x000003f8);
+ nv_wo32(ctx, 0x3540, 0x002fe000);
for (i = 0x355c; i <= 0x3578; i += 4)
- nv_wo32(dev, ctx, i/4, 0x001c527c);
+ nv_wo32(ctx, i, 0x001c527c);
}
static void
@@ -87,58 +87,58 @@ nv25_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
{
int i;
- nv_wo32(dev, ctx, 0x035c/4, 0xffff0000);
- nv_wo32(dev, ctx, 0x03c0/4, 0x0fff0000);
- nv_wo32(dev, ctx, 0x03c4/4, 0x0fff0000);
- nv_wo32(dev, ctx, 0x049c/4, 0x00000101);
- nv_wo32(dev, ctx, 0x04b0/4, 0x00000111);
- nv_wo32(dev, ctx, 0x04c8/4, 0x00000080);
- nv_wo32(dev, ctx, 0x04cc/4, 0xffff0000);
- nv_wo32(dev, ctx, 0x04d0/4, 0x00000001);
- nv_wo32(dev, ctx, 0x04e4/4, 0x44400000);
- nv_wo32(dev, ctx, 0x04fc/4, 0x4b800000);
+ nv_wo32(ctx, 0x035c, 0xffff0000);
+ nv_wo32(ctx, 0x03c0, 0x0fff0000);
+ nv_wo32(ctx, 0x03c4, 0x0fff0000);
+ nv_wo32(ctx, 0x049c, 0x00000101);
+ nv_wo32(ctx, 0x04b0, 0x00000111);
+ nv_wo32(ctx, 0x04c8, 0x00000080);
+ nv_wo32(ctx, 0x04cc, 0xffff0000);
+ nv_wo32(ctx, 0x04d0, 0x00000001);
+ nv_wo32(ctx, 0x04e4, 0x44400000);
+ nv_wo32(ctx, 0x04fc, 0x4b800000);
for (i = 0x0510; i <= 0x051c; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00030303);
+ nv_wo32(ctx, i, 0x00030303);
for (i = 0x0530; i <= 0x053c; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00080000);
+ nv_wo32(ctx, i, 0x00080000);
for (i = 0x0548; i <= 0x0554; i += 4)
- nv_wo32(dev, ctx, i/4, 0x01012000);
+ nv_wo32(ctx, i, 0x01012000);
for (i = 0x0558; i <= 0x0564; i += 4)
- nv_wo32(dev, ctx, i/4, 0x000105b8);
+ nv_wo32(ctx, i, 0x000105b8);
for (i = 0x0568; i <= 0x0574; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00080008);
+ nv_wo32(ctx, i, 0x00080008);
for (i = 0x0598; i <= 0x05d4; i += 4)
- nv_wo32(dev, ctx, i/4, 0x07ff0000);
- nv_wo32(dev, ctx, 0x05e0/4, 0x4b7fffff);
- nv_wo32(dev, ctx, 0x0620/4, 0x00000080);
- nv_wo32(dev, ctx, 0x0624/4, 0x30201000);
- nv_wo32(dev, ctx, 0x0628/4, 0x70605040);
- nv_wo32(dev, ctx, 0x062c/4, 0xb0a09080);
- nv_wo32(dev, ctx, 0x0630/4, 0xf0e0d0c0);
- nv_wo32(dev, ctx, 0x0664/4, 0x00000001);
- nv_wo32(dev, ctx, 0x066c/4, 0x00004000);
- nv_wo32(dev, ctx, 0x0678/4, 0x00000001);
- nv_wo32(dev, ctx, 0x0680/4, 0x00040000);
- nv_wo32(dev, ctx, 0x0684/4, 0x00010000);
+ nv_wo32(ctx, i, 0x07ff0000);
+ nv_wo32(ctx, 0x05e0, 0x4b7fffff);
+ nv_wo32(ctx, 0x0620, 0x00000080);
+ nv_wo32(ctx, 0x0624, 0x30201000);
+ nv_wo32(ctx, 0x0628, 0x70605040);
+ nv_wo32(ctx, 0x062c, 0xb0a09080);
+ nv_wo32(ctx, 0x0630, 0xf0e0d0c0);
+ nv_wo32(ctx, 0x0664, 0x00000001);
+ nv_wo32(ctx, 0x066c, 0x00004000);
+ nv_wo32(ctx, 0x0678, 0x00000001);
+ nv_wo32(ctx, 0x0680, 0x00040000);
+ nv_wo32(ctx, 0x0684, 0x00010000);
for (i = 0x1b04; i <= 0x2374; i += 16) {
- nv_wo32(dev, ctx, (i + 0)/4, 0x10700ff9);
- nv_wo32(dev, ctx, (i + 4)/4, 0x0436086c);
- nv_wo32(dev, ctx, (i + 8)/4, 0x000c001b);
+ nv_wo32(ctx, (i + 0), 0x10700ff9);
+ nv_wo32(ctx, (i + 4), 0x0436086c);
+ nv_wo32(ctx, (i + 8), 0x000c001b);
}
- nv_wo32(dev, ctx, 0x2704/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x2718/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x2744/4, 0x40000000);
- nv_wo32(dev, ctx, 0x2748/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x274c/4, 0x3f000000);
- nv_wo32(dev, ctx, 0x2754/4, 0x40000000);
- nv_wo32(dev, ctx, 0x2758/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x2760/4, 0xbf800000);
- nv_wo32(dev, ctx, 0x2768/4, 0xbf800000);
- nv_wo32(dev, ctx, 0x308c/4, 0x000fe000);
- nv_wo32(dev, ctx, 0x3108/4, 0x000003f8);
- nv_wo32(dev, ctx, 0x3468/4, 0x002fe000);
+ nv_wo32(ctx, 0x2704, 0x3f800000);
+ nv_wo32(ctx, 0x2718, 0x3f800000);
+ nv_wo32(ctx, 0x2744, 0x40000000);
+ nv_wo32(ctx, 0x2748, 0x3f800000);
+ nv_wo32(ctx, 0x274c, 0x3f000000);
+ nv_wo32(ctx, 0x2754, 0x40000000);
+ nv_wo32(ctx, 0x2758, 0x3f800000);
+ nv_wo32(ctx, 0x2760, 0xbf800000);
+ nv_wo32(ctx, 0x2768, 0xbf800000);
+ nv_wo32(ctx, 0x308c, 0x000fe000);
+ nv_wo32(ctx, 0x3108, 0x000003f8);
+ nv_wo32(ctx, 0x3468, 0x002fe000);
for (i = 0x3484; i <= 0x34a0; i += 4)
- nv_wo32(dev, ctx, i/4, 0x001c527c);
+ nv_wo32(ctx, i, 0x001c527c);
}
static void
@@ -146,49 +146,49 @@ nv2a_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
{
int i;
- nv_wo32(dev, ctx, 0x033c/4, 0xffff0000);
- nv_wo32(dev, ctx, 0x03a0/4, 0x0fff0000);
- nv_wo32(dev, ctx, 0x03a4/4, 0x0fff0000);
- nv_wo32(dev, ctx, 0x047c/4, 0x00000101);
- nv_wo32(dev, ctx, 0x0490/4, 0x00000111);
- nv_wo32(dev, ctx, 0x04a8/4, 0x44400000);
+ nv_wo32(ctx, 0x033c, 0xffff0000);
+ nv_wo32(ctx, 0x03a0, 0x0fff0000);
+ nv_wo32(ctx, 0x03a4, 0x0fff0000);
+ nv_wo32(ctx, 0x047c, 0x00000101);
+ nv_wo32(ctx, 0x0490, 0x00000111);
+ nv_wo32(ctx, 0x04a8, 0x44400000);
for (i = 0x04d4; i <= 0x04e0; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00030303);
+ nv_wo32(ctx, i, 0x00030303);
for (i = 0x04f4; i <= 0x0500; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00080000);
+ nv_wo32(ctx, i, 0x00080000);
for (i = 0x050c; i <= 0x0518; i += 4)
- nv_wo32(dev, ctx, i/4, 0x01012000);
+ nv_wo32(ctx, i, 0x01012000);
for (i = 0x051c; i <= 0x0528; i += 4)
- nv_wo32(dev, ctx, i/4, 0x000105b8);
+ nv_wo32(ctx, i, 0x000105b8);
for (i = 0x052c; i <= 0x0538; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00080008);
+ nv_wo32(ctx, i, 0x00080008);
for (i = 0x055c; i <= 0x0598; i += 4)
- nv_wo32(dev, ctx, i/4, 0x07ff0000);
- nv_wo32(dev, ctx, 0x05a4/4, 0x4b7fffff);
- nv_wo32(dev, ctx, 0x05fc/4, 0x00000001);
- nv_wo32(dev, ctx, 0x0604/4, 0x00004000);
- nv_wo32(dev, ctx, 0x0610/4, 0x00000001);
- nv_wo32(dev, ctx, 0x0618/4, 0x00040000);
- nv_wo32(dev, ctx, 0x061c/4, 0x00010000);
+ nv_wo32(ctx, i, 0x07ff0000);
+ nv_wo32(ctx, 0x05a4, 0x4b7fffff);
+ nv_wo32(ctx, 0x05fc, 0x00000001);
+ nv_wo32(ctx, 0x0604, 0x00004000);
+ nv_wo32(ctx, 0x0610, 0x00000001);
+ nv_wo32(ctx, 0x0618, 0x00040000);
+ nv_wo32(ctx, 0x061c, 0x00010000);
for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */
- nv_wo32(dev, ctx, (i + 0)/4, 0x10700ff9);
- nv_wo32(dev, ctx, (i + 4)/4, 0x0436086c);
- nv_wo32(dev, ctx, (i + 8)/4, 0x000c001b);
+ nv_wo32(ctx, (i + 0), 0x10700ff9);
+ nv_wo32(ctx, (i + 4), 0x0436086c);
+ nv_wo32(ctx, (i + 8), 0x000c001b);
}
- nv_wo32(dev, ctx, 0x269c/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x26b0/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x26dc/4, 0x40000000);
- nv_wo32(dev, ctx, 0x26e0/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x26e4/4, 0x3f000000);
- nv_wo32(dev, ctx, 0x26ec/4, 0x40000000);
- nv_wo32(dev, ctx, 0x26f0/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x26f8/4, 0xbf800000);
- nv_wo32(dev, ctx, 0x2700/4, 0xbf800000);
- nv_wo32(dev, ctx, 0x3024/4, 0x000fe000);
- nv_wo32(dev, ctx, 0x30a0/4, 0x000003f8);
- nv_wo32(dev, ctx, 0x33fc/4, 0x002fe000);
+ nv_wo32(ctx, 0x269c, 0x3f800000);
+ nv_wo32(ctx, 0x26b0, 0x3f800000);
+ nv_wo32(ctx, 0x26dc, 0x40000000);
+ nv_wo32(ctx, 0x26e0, 0x3f800000);
+ nv_wo32(ctx, 0x26e4, 0x3f000000);
+ nv_wo32(ctx, 0x26ec, 0x40000000);
+ nv_wo32(ctx, 0x26f0, 0x3f800000);
+ nv_wo32(ctx, 0x26f8, 0xbf800000);
+ nv_wo32(ctx, 0x2700, 0xbf800000);
+ nv_wo32(ctx, 0x3024, 0x000fe000);
+ nv_wo32(ctx, 0x30a0, 0x000003f8);
+ nv_wo32(ctx, 0x33fc, 0x002fe000);
for (i = 0x341c; i <= 0x3438; i += 4)
- nv_wo32(dev, ctx, i/4, 0x001c527c);
+ nv_wo32(ctx, i, 0x001c527c);
}
static void
@@ -196,57 +196,57 @@ nv30_31_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
{
int i;
- nv_wo32(dev, ctx, 0x0410/4, 0x00000101);
- nv_wo32(dev, ctx, 0x0424/4, 0x00000111);
- nv_wo32(dev, ctx, 0x0428/4, 0x00000060);
- nv_wo32(dev, ctx, 0x0444/4, 0x00000080);
- nv_wo32(dev, ctx, 0x0448/4, 0xffff0000);
- nv_wo32(dev, ctx, 0x044c/4, 0x00000001);
- nv_wo32(dev, ctx, 0x0460/4, 0x44400000);
- nv_wo32(dev, ctx, 0x048c/4, 0xffff0000);
+ nv_wo32(ctx, 0x0410, 0x00000101);
+ nv_wo32(ctx, 0x0424, 0x00000111);
+ nv_wo32(ctx, 0x0428, 0x00000060);
+ nv_wo32(ctx, 0x0444, 0x00000080);
+ nv_wo32(ctx, 0x0448, 0xffff0000);
+ nv_wo32(ctx, 0x044c, 0x00000001);
+ nv_wo32(ctx, 0x0460, 0x44400000);
+ nv_wo32(ctx, 0x048c, 0xffff0000);
for (i = 0x04e0; i < 0x04e8; i += 4)
- nv_wo32(dev, ctx, i/4, 0x0fff0000);
- nv_wo32(dev, ctx, 0x04ec/4, 0x00011100);
+ nv_wo32(ctx, i, 0x0fff0000);
+ nv_wo32(ctx, 0x04ec, 0x00011100);
for (i = 0x0508; i < 0x0548; i += 4)
- nv_wo32(dev, ctx, i/4, 0x07ff0000);
- nv_wo32(dev, ctx, 0x0550/4, 0x4b7fffff);
- nv_wo32(dev, ctx, 0x058c/4, 0x00000080);
- nv_wo32(dev, ctx, 0x0590/4, 0x30201000);
- nv_wo32(dev, ctx, 0x0594/4, 0x70605040);
- nv_wo32(dev, ctx, 0x0598/4, 0xb8a89888);
- nv_wo32(dev, ctx, 0x059c/4, 0xf8e8d8c8);
- nv_wo32(dev, ctx, 0x05b0/4, 0xb0000000);
+ nv_wo32(ctx, i, 0x07ff0000);
+ nv_wo32(ctx, 0x0550, 0x4b7fffff);
+ nv_wo32(ctx, 0x058c, 0x00000080);
+ nv_wo32(ctx, 0x0590, 0x30201000);
+ nv_wo32(ctx, 0x0594, 0x70605040);
+ nv_wo32(ctx, 0x0598, 0xb8a89888);
+ nv_wo32(ctx, 0x059c, 0xf8e8d8c8);
+ nv_wo32(ctx, 0x05b0, 0xb0000000);
for (i = 0x0600; i < 0x0640; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00010588);
+ nv_wo32(ctx, i, 0x00010588);
for (i = 0x0640; i < 0x0680; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00030303);
+ nv_wo32(ctx, i, 0x00030303);
for (i = 0x06c0; i < 0x0700; i += 4)
- nv_wo32(dev, ctx, i/4, 0x0008aae4);
+ nv_wo32(ctx, i, 0x0008aae4);
for (i = 0x0700; i < 0x0740; i += 4)
- nv_wo32(dev, ctx, i/4, 0x01012000);
+ nv_wo32(ctx, i, 0x01012000);
for (i = 0x0740; i < 0x0780; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00080008);
- nv_wo32(dev, ctx, 0x085c/4, 0x00040000);
- nv_wo32(dev, ctx, 0x0860/4, 0x00010000);
+ nv_wo32(ctx, i, 0x00080008);
+ nv_wo32(ctx, 0x085c, 0x00040000);
+ nv_wo32(ctx, 0x0860, 0x00010000);
for (i = 0x0864; i < 0x0874; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00040004);
+ nv_wo32(ctx, i, 0x00040004);
for (i = 0x1f18; i <= 0x3088 ; i += 16) {
- nv_wo32(dev, ctx, i/4 + 0, 0x10700ff9);
- nv_wo32(dev, ctx, i/4 + 1, 0x0436086c);
- nv_wo32(dev, ctx, i/4 + 2, 0x000c001b);
+ nv_wo32(ctx, i + 0, 0x10700ff9);
+ nv_wo32(ctx, i + 1, 0x0436086c);
+ nv_wo32(ctx, i + 2, 0x000c001b);
}
for (i = 0x30b8; i < 0x30c8; i += 4)
- nv_wo32(dev, ctx, i/4, 0x0000ffff);
- nv_wo32(dev, ctx, 0x344c/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x3808/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x381c/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x3848/4, 0x40000000);
- nv_wo32(dev, ctx, 0x384c/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x3850/4, 0x3f000000);
- nv_wo32(dev, ctx, 0x3858/4, 0x40000000);
- nv_wo32(dev, ctx, 0x385c/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x3864/4, 0xbf800000);
- nv_wo32(dev, ctx, 0x386c/4, 0xbf800000);
+ nv_wo32(ctx, i, 0x0000ffff);
+ nv_wo32(ctx, 0x344c, 0x3f800000);
+ nv_wo32(ctx, 0x3808, 0x3f800000);
+ nv_wo32(ctx, 0x381c, 0x3f800000);
+ nv_wo32(ctx, 0x3848, 0x40000000);
+ nv_wo32(ctx, 0x384c, 0x3f800000);
+ nv_wo32(ctx, 0x3850, 0x3f000000);
+ nv_wo32(ctx, 0x3858, 0x40000000);
+ nv_wo32(ctx, 0x385c, 0x3f800000);
+ nv_wo32(ctx, 0x3864, 0xbf800000);
+ nv_wo32(ctx, 0x386c, 0xbf800000);
}
static void
@@ -254,57 +254,57 @@ nv34_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
{
int i;
- nv_wo32(dev, ctx, 0x040c/4, 0x01000101);
- nv_wo32(dev, ctx, 0x0420/4, 0x00000111);
- nv_wo32(dev, ctx, 0x0424/4, 0x00000060);
- nv_wo32(dev, ctx, 0x0440/4, 0x00000080);
- nv_wo32(dev, ctx, 0x0444/4, 0xffff0000);
- nv_wo32(dev, ctx, 0x0448/4, 0x00000001);
- nv_wo32(dev, ctx, 0x045c/4, 0x44400000);
- nv_wo32(dev, ctx, 0x0480/4, 0xffff0000);
+ nv_wo32(ctx, 0x040c, 0x01000101);
+ nv_wo32(ctx, 0x0420, 0x00000111);
+ nv_wo32(ctx, 0x0424, 0x00000060);
+ nv_wo32(ctx, 0x0440, 0x00000080);
+ nv_wo32(ctx, 0x0444, 0xffff0000);
+ nv_wo32(ctx, 0x0448, 0x00000001);
+ nv_wo32(ctx, 0x045c, 0x44400000);
+ nv_wo32(ctx, 0x0480, 0xffff0000);
for (i = 0x04d4; i < 0x04dc; i += 4)
- nv_wo32(dev, ctx, i/4, 0x0fff0000);
- nv_wo32(dev, ctx, 0x04e0/4, 0x00011100);
+ nv_wo32(ctx, i, 0x0fff0000);
+ nv_wo32(ctx, 0x04e0, 0x00011100);
for (i = 0x04fc; i < 0x053c; i += 4)
- nv_wo32(dev, ctx, i/4, 0x07ff0000);
- nv_wo32(dev, ctx, 0x0544/4, 0x4b7fffff);
- nv_wo32(dev, ctx, 0x057c/4, 0x00000080);
- nv_wo32(dev, ctx, 0x0580/4, 0x30201000);
- nv_wo32(dev, ctx, 0x0584/4, 0x70605040);
- nv_wo32(dev, ctx, 0x0588/4, 0xb8a89888);
- nv_wo32(dev, ctx, 0x058c/4, 0xf8e8d8c8);
- nv_wo32(dev, ctx, 0x05a0/4, 0xb0000000);
+ nv_wo32(ctx, i, 0x07ff0000);
+ nv_wo32(ctx, 0x0544, 0x4b7fffff);
+ nv_wo32(ctx, 0x057c, 0x00000080);
+ nv_wo32(ctx, 0x0580, 0x30201000);
+ nv_wo32(ctx, 0x0584, 0x70605040);
+ nv_wo32(ctx, 0x0588, 0xb8a89888);
+ nv_wo32(ctx, 0x058c, 0xf8e8d8c8);
+ nv_wo32(ctx, 0x05a0, 0xb0000000);
for (i = 0x05f0; i < 0x0630; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00010588);
+ nv_wo32(ctx, i, 0x00010588);
for (i = 0x0630; i < 0x0670; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00030303);
+ nv_wo32(ctx, i, 0x00030303);
for (i = 0x06b0; i < 0x06f0; i += 4)
- nv_wo32(dev, ctx, i/4, 0x0008aae4);
+ nv_wo32(ctx, i, 0x0008aae4);
for (i = 0x06f0; i < 0x0730; i += 4)
- nv_wo32(dev, ctx, i/4, 0x01012000);
+ nv_wo32(ctx, i, 0x01012000);
for (i = 0x0730; i < 0x0770; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00080008);
- nv_wo32(dev, ctx, 0x0850/4, 0x00040000);
- nv_wo32(dev, ctx, 0x0854/4, 0x00010000);
+ nv_wo32(ctx, i, 0x00080008);
+ nv_wo32(ctx, 0x0850, 0x00040000);
+ nv_wo32(ctx, 0x0854, 0x00010000);
for (i = 0x0858; i < 0x0868; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00040004);
+ nv_wo32(ctx, i, 0x00040004);
for (i = 0x15ac; i <= 0x271c ; i += 16) {
- nv_wo32(dev, ctx, i/4 + 0, 0x10700ff9);
- nv_wo32(dev, ctx, i/4 + 1, 0x0436086c);
- nv_wo32(dev, ctx, i/4 + 2, 0x000c001b);
+ nv_wo32(ctx, i + 0, 0x10700ff9);
+ nv_wo32(ctx, i + 1, 0x0436086c);
+ nv_wo32(ctx, i + 2, 0x000c001b);
}
for (i = 0x274c; i < 0x275c; i += 4)
- nv_wo32(dev, ctx, i/4, 0x0000ffff);
- nv_wo32(dev, ctx, 0x2ae0/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x2e9c/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x2eb0/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x2edc/4, 0x40000000);
- nv_wo32(dev, ctx, 0x2ee0/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x2ee4/4, 0x3f000000);
- nv_wo32(dev, ctx, 0x2eec/4, 0x40000000);
- nv_wo32(dev, ctx, 0x2ef0/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x2ef8/4, 0xbf800000);
- nv_wo32(dev, ctx, 0x2f00/4, 0xbf800000);
+ nv_wo32(ctx, i, 0x0000ffff);
+ nv_wo32(ctx, 0x2ae0, 0x3f800000);
+ nv_wo32(ctx, 0x2e9c, 0x3f800000);
+ nv_wo32(ctx, 0x2eb0, 0x3f800000);
+ nv_wo32(ctx, 0x2edc, 0x40000000);
+ nv_wo32(ctx, 0x2ee0, 0x3f800000);
+ nv_wo32(ctx, 0x2ee4, 0x3f000000);
+ nv_wo32(ctx, 0x2eec, 0x40000000);
+ nv_wo32(ctx, 0x2ef0, 0x3f800000);
+ nv_wo32(ctx, 0x2ef8, 0xbf800000);
+ nv_wo32(ctx, 0x2f00, 0xbf800000);
}
static void
@@ -312,57 +312,57 @@ nv35_36_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
{
int i;
- nv_wo32(dev, ctx, 0x040c/4, 0x00000101);
- nv_wo32(dev, ctx, 0x0420/4, 0x00000111);
- nv_wo32(dev, ctx, 0x0424/4, 0x00000060);
- nv_wo32(dev, ctx, 0x0440/4, 0x00000080);
- nv_wo32(dev, ctx, 0x0444/4, 0xffff0000);
- nv_wo32(dev, ctx, 0x0448/4, 0x00000001);
- nv_wo32(dev, ctx, 0x045c/4, 0x44400000);
- nv_wo32(dev, ctx, 0x0488/4, 0xffff0000);
+ nv_wo32(ctx, 0x040c, 0x00000101);
+ nv_wo32(ctx, 0x0420, 0x00000111);
+ nv_wo32(ctx, 0x0424, 0x00000060);
+ nv_wo32(ctx, 0x0440, 0x00000080);
+ nv_wo32(ctx, 0x0444, 0xffff0000);
+ nv_wo32(ctx, 0x0448, 0x00000001);
+ nv_wo32(ctx, 0x045c, 0x44400000);
+ nv_wo32(ctx, 0x0488, 0xffff0000);
for (i = 0x04dc; i < 0x04e4; i += 4)
- nv_wo32(dev, ctx, i/4, 0x0fff0000);
- nv_wo32(dev, ctx, 0x04e8/4, 0x00011100);
+ nv_wo32(ctx, i, 0x0fff0000);
+ nv_wo32(ctx, 0x04e8, 0x00011100);
for (i = 0x0504; i < 0x0544; i += 4)
- nv_wo32(dev, ctx, i/4, 0x07ff0000);
- nv_wo32(dev, ctx, 0x054c/4, 0x4b7fffff);
- nv_wo32(dev, ctx, 0x0588/4, 0x00000080);
- nv_wo32(dev, ctx, 0x058c/4, 0x30201000);
- nv_wo32(dev, ctx, 0x0590/4, 0x70605040);
- nv_wo32(dev, ctx, 0x0594/4, 0xb8a89888);
- nv_wo32(dev, ctx, 0x0598/4, 0xf8e8d8c8);
- nv_wo32(dev, ctx, 0x05ac/4, 0xb0000000);
+ nv_wo32(ctx, i, 0x07ff0000);
+ nv_wo32(ctx, 0x054c, 0x4b7fffff);
+ nv_wo32(ctx, 0x0588, 0x00000080);
+ nv_wo32(ctx, 0x058c, 0x30201000);
+ nv_wo32(ctx, 0x0590, 0x70605040);
+ nv_wo32(ctx, 0x0594, 0xb8a89888);
+ nv_wo32(ctx, 0x0598, 0xf8e8d8c8);
+ nv_wo32(ctx, 0x05ac, 0xb0000000);
for (i = 0x0604; i < 0x0644; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00010588);
+ nv_wo32(ctx, i, 0x00010588);
for (i = 0x0644; i < 0x0684; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00030303);
+ nv_wo32(ctx, i, 0x00030303);
for (i = 0x06c4; i < 0x0704; i += 4)
- nv_wo32(dev, ctx, i/4, 0x0008aae4);
+ nv_wo32(ctx, i, 0x0008aae4);
for (i = 0x0704; i < 0x0744; i += 4)
- nv_wo32(dev, ctx, i/4, 0x01012000);
+ nv_wo32(ctx, i, 0x01012000);
for (i = 0x0744; i < 0x0784; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00080008);
- nv_wo32(dev, ctx, 0x0860/4, 0x00040000);
- nv_wo32(dev, ctx, 0x0864/4, 0x00010000);
+ nv_wo32(ctx, i, 0x00080008);
+ nv_wo32(ctx, 0x0860, 0x00040000);
+ nv_wo32(ctx, 0x0864, 0x00010000);
for (i = 0x0868; i < 0x0878; i += 4)
- nv_wo32(dev, ctx, i/4, 0x00040004);
+ nv_wo32(ctx, i, 0x00040004);
for (i = 0x1f1c; i <= 0x308c ; i += 16) {
- nv_wo32(dev, ctx, i/4 + 0, 0x10700ff9);
- nv_wo32(dev, ctx, i/4 + 1, 0x0436086c);
- nv_wo32(dev, ctx, i/4 + 2, 0x000c001b);
+ nv_wo32(ctx, i + 0, 0x10700ff9);
+ nv_wo32(ctx, i + 4, 0x0436086c);
+ nv_wo32(ctx, i + 8, 0x000c001b);
}
for (i = 0x30bc; i < 0x30cc; i += 4)
- nv_wo32(dev, ctx, i/4, 0x0000ffff);
- nv_wo32(dev, ctx, 0x3450/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x380c/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x3820/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x384c/4, 0x40000000);
- nv_wo32(dev, ctx, 0x3850/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x3854/4, 0x3f000000);
- nv_wo32(dev, ctx, 0x385c/4, 0x40000000);
- nv_wo32(dev, ctx, 0x3860/4, 0x3f800000);
- nv_wo32(dev, ctx, 0x3868/4, 0xbf800000);
- nv_wo32(dev, ctx, 0x3870/4, 0xbf800000);
+ nv_wo32(ctx, i, 0x0000ffff);
+ nv_wo32(ctx, 0x3450, 0x3f800000);
+ nv_wo32(ctx, 0x380c, 0x3f800000);
+ nv_wo32(ctx, 0x3820, 0x3f800000);
+ nv_wo32(ctx, 0x384c, 0x40000000);
+ nv_wo32(ctx, 0x3850, 0x3f800000);
+ nv_wo32(ctx, 0x3854, 0x3f000000);
+ nv_wo32(ctx, 0x385c, 0x40000000);
+ nv_wo32(ctx, 0x3860, 0x3f800000);
+ nv_wo32(ctx, 0x3868, 0xbf800000);
+ nv_wo32(ctx, 0x3870, 0xbf800000);
}
int
@@ -372,7 +372,7 @@ nv20_graph_create_context(struct nouveau_channel *chan)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *);
- unsigned int idoffs = 0x28/4;
+ unsigned int idoffs = 0x28;
int ret;
switch (dev_priv->chipset) {
@@ -403,21 +403,19 @@ nv20_graph_create_context(struct nouveau_channel *chan)
BUG_ON(1);
}
- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
- 16, NVOBJ_FLAG_ZERO_ALLOC,
- &chan->ramin_grctx);
+ ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
+ NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
if (ret)
return ret;
/* Initialise default context values */
- ctx_init(dev, chan->ramin_grctx->gpuobj);
+ ctx_init(dev, chan->ramin_grctx);
/* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
- nv_wo32(dev, chan->ramin_grctx->gpuobj, idoffs,
- (chan->id << 24) | 0x1); /* CTX_USER */
+ nv_wo32(chan->ramin_grctx, idoffs,
+ (chan->id << 24) | 0x1); /* CTX_USER */
- nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id,
- chan->ramin_grctx->instance >> 4);
+ nv_wo32(pgraph->ctx_table, chan->id * 4, chan->ramin_grctx->pinst >> 4);
return 0;
}
@@ -428,10 +426,8 @@ nv20_graph_destroy_context(struct nouveau_channel *chan)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- if (chan->ramin_grctx)
- nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
-
- nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id, 0);
+ nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
+ nv_wo32(pgraph->ctx_table, chan->id * 4, 0);
}
int
@@ -442,7 +438,7 @@ nv20_graph_load_context(struct nouveau_channel *chan)
if (!chan->ramin_grctx)
return -EINVAL;
- inst = chan->ramin_grctx->instance >> 4;
+ inst = chan->ramin_grctx->pinst >> 4;
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
@@ -465,7 +461,7 @@ nv20_graph_unload_context(struct drm_device *dev)
chan = pgraph->channel(dev);
if (!chan)
return 0;
- inst = chan->ramin_grctx->instance >> 4;
+ inst = chan->ramin_grctx->pinst >> 4;
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
@@ -552,15 +548,15 @@ nv20_graph_init(struct drm_device *dev)
if (!pgraph->ctx_table) {
/* Create Context Pointer Table */
- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16,
- NVOBJ_FLAG_ZERO_ALLOC,
- &pgraph->ctx_table);
+ ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &pgraph->ctx_table);
if (ret)
return ret;
}
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
- pgraph->ctx_table->instance >> 4);
+ pgraph->ctx_table->pinst >> 4);
nv20_graph_rdi(dev);
@@ -646,7 +642,7 @@ nv20_graph_takedown(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- nouveau_gpuobj_ref_del(dev, &pgraph->ctx_table);
+ nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
}
int
@@ -681,15 +677,15 @@ nv30_graph_init(struct drm_device *dev)
if (!pgraph->ctx_table) {
/* Create Context Pointer Table */
- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16,
- NVOBJ_FLAG_ZERO_ALLOC,
- &pgraph->ctx_table);
+ ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &pgraph->ctx_table);
if (ret)
return ret;
}
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
- pgraph->ctx_table->instance >> 4);
+ pgraph->ctx_table->pinst >> 4);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c
index 2b67f1835c39..d337b8b28cdd 100644
--- a/drivers/gpu/drm/nouveau/nv40_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv40_fifo.c
@@ -27,8 +27,9 @@
#include "drmP.h"
#include "nouveau_drv.h"
#include "nouveau_drm.h"
+#include "nouveau_ramht.h"
-#define NV40_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV40_RAMFC__SIZE))
+#define NV40_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV40_RAMFC__SIZE))
#define NV40_RAMFC__SIZE 128
int
@@ -42,7 +43,7 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
ret = nouveau_gpuobj_new_fake(dev, NV40_RAMFC(chan->id), ~0,
NV40_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_ZERO_FREE, NULL, &chan->ramfc);
+ NVOBJ_FLAG_ZERO_FREE, &chan->ramfc);
if (ret)
return ret;
@@ -50,7 +51,7 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
nv_wi32(dev, fc + 0, chan->pushbuf_base);
nv_wi32(dev, fc + 4, chan->pushbuf_base);
- nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
+ nv_wi32(dev, fc + 12, chan->pushbuf->pinst >> 4);
nv_wi32(dev, fc + 24, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
@@ -58,7 +59,7 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
NV_PFIFO_CACHE1_BIG_ENDIAN |
#endif
0x30000000 /* no idea.. */);
- nv_wi32(dev, fc + 56, chan->ramin_grctx->instance >> 4);
+ nv_wi32(dev, fc + 56, chan->ramin_grctx->pinst >> 4);
nv_wi32(dev, fc + 60, 0x0001FFFF);
/* enable the fifo dma operation */
@@ -77,8 +78,7 @@ nv40_fifo_destroy_context(struct nouveau_channel *chan)
nv_wr32(dev, NV04_PFIFO_MODE,
nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
- if (chan->ramfc)
- nouveau_gpuobj_ref_del(dev, &chan->ramfc);
+ nouveau_gpuobj_ref(NULL, &chan->ramfc);
}
static void
@@ -241,9 +241,9 @@ nv40_fifo_init_ramxx(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private;
nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
- ((dev_priv->ramht_bits - 9) << 16) |
- (dev_priv->ramht_offset >> 8));
- nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8);
+ ((dev_priv->ramht->bits - 9) << 16) |
+ (dev_priv->ramht->gpuobj->pinst >> 8));
+ nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8);
switch (dev_priv->chipset) {
case 0x47:
@@ -271,7 +271,7 @@ nv40_fifo_init_ramxx(struct drm_device *dev)
nv_wr32(dev, 0x2230, 0);
nv_wr32(dev, NV40_PFIFO_RAMFC,
((dev_priv->vram_size - 512 * 1024 +
- dev_priv->ramfc_offset) >> 16) | (3 << 16));
+ dev_priv->ramfc->pinst) >> 16) | (3 << 16));
break;
}
}
diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
index fd7d2b501316..7ee1b91569b8 100644
--- a/drivers/gpu/drm/nouveau/nv40_graph.c
+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
@@ -45,7 +45,7 @@ nv40_graph_channel(struct drm_device *dev)
struct nouveau_channel *chan = dev_priv->fifos[i];
if (chan && chan->ramin_grctx &&
- chan->ramin_grctx->instance == inst)
+ chan->ramin_grctx->pinst == inst)
return chan;
}
@@ -61,27 +61,25 @@ nv40_graph_create_context(struct nouveau_channel *chan)
struct nouveau_grctx ctx = {};
int ret;
- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
- 16, NVOBJ_FLAG_ZERO_ALLOC,
- &chan->ramin_grctx);
+ ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
+ NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
if (ret)
return ret;
/* Initialise default context values */
ctx.dev = chan->dev;
ctx.mode = NOUVEAU_GRCTX_VALS;
- ctx.data = chan->ramin_grctx->gpuobj;
+ ctx.data = chan->ramin_grctx;
nv40_grctx_init(&ctx);
- nv_wo32(dev, chan->ramin_grctx->gpuobj, 0,
- chan->ramin_grctx->gpuobj->im_pramin->start);
+ nv_wo32(chan->ramin_grctx, 0, chan->ramin_grctx->pinst);
return 0;
}
void
nv40_graph_destroy_context(struct nouveau_channel *chan)
{
- nouveau_gpuobj_ref_del(chan->dev, &chan->ramin_grctx);
+ nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
}
static int
@@ -135,7 +133,7 @@ nv40_graph_load_context(struct nouveau_channel *chan)
if (!chan->ramin_grctx)
return -EINVAL;
- inst = chan->ramin_grctx->instance >> 4;
+ inst = chan->ramin_grctx->pinst >> 4;
ret = nv40_graph_transfer_context(dev, inst, 0);
if (ret)
diff --git a/drivers/gpu/drm/nouveau/nv40_grctx.c b/drivers/gpu/drm/nouveau/nv40_grctx.c
index 9b5c97469588..ce585093264e 100644
--- a/drivers/gpu/drm/nouveau/nv40_grctx.c
+++ b/drivers/gpu/drm/nouveau/nv40_grctx.c
@@ -596,13 +596,13 @@ nv40_graph_construct_shader(struct nouveau_grctx *ctx)
offset += 0x0280/4;
for (i = 0; i < 16; i++, offset += 2)
- nv_wo32(dev, obj, offset, 0x3f800000);
+ nv_wo32(obj, offset * 4, 0x3f800000);
for (vs = 0; vs < vs_nr; vs++, offset += vs_len) {
for (i = 0; i < vs_nr_b0 * 6; i += 6)
- nv_wo32(dev, obj, offset + b0_offset + i, 0x00000001);
+ nv_wo32(obj, (offset + b0_offset + i) * 4, 0x00000001);
for (i = 0; i < vs_nr_b1 * 4; i += 4)
- nv_wo32(dev, obj, offset + b1_offset + i, 0x3f800000);
+ nv_wo32(obj, (offset + b1_offset + i) * 4, 0x3f800000);
}
}
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index bfd4ca2fe7ef..16380d52cd88 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -104,8 +104,7 @@ nv50_crtc_blank(struct nouveau_crtc *nv_crtc, bool blanked)
OUT_RING(evo, nv_crtc->lut.depth == 8 ?
NV50_EVO_CRTC_CLUT_MODE_OFF :
NV50_EVO_CRTC_CLUT_MODE_ON);
- OUT_RING(evo, (nv_crtc->lut.nvbo->bo.mem.mm_node->start <<
- PAGE_SHIFT) >> 8);
+ OUT_RING(evo, (nv_crtc->lut.nvbo->bo.mem.start << PAGE_SHIFT) >> 8);
if (dev_priv->chipset != 0x50) {
BEGIN_RING(evo, 0, NV84_EVO_CRTC(index, CLUT_DMA), 1);
OUT_RING(evo, NvEvoVRAM);
@@ -266,15 +265,10 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct pll_lims pll;
- uint32_t reg, reg1, reg2;
+ uint32_t reg1, reg2;
int ret, N1, M1, N2, M2, P;
- if (dev_priv->chipset < NV_C0)
- reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head);
- else
- reg = 0x614140 + (head * 0x800);
-
- ret = get_pll_limits(dev, reg, &pll);
+ ret = get_pll_limits(dev, PLL_VPLL0 + head, &pll);
if (ret)
return ret;
@@ -286,11 +280,11 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
NV_DEBUG(dev, "pclk %d out %d NM1 %d %d NM2 %d %d P %d\n",
pclk, ret, N1, M1, N2, M2, P);
- reg1 = nv_rd32(dev, reg + 4) & 0xff00ff00;
- reg2 = nv_rd32(dev, reg + 8) & 0x8000ff00;
- nv_wr32(dev, reg, 0x10000611);
- nv_wr32(dev, reg + 4, reg1 | (M1 << 16) | N1);
- nv_wr32(dev, reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
+ reg1 = nv_rd32(dev, pll.reg + 4) & 0xff00ff00;
+ reg2 = nv_rd32(dev, pll.reg + 8) & 0x8000ff00;
+ nv_wr32(dev, pll.reg + 0, 0x10000611);
+ nv_wr32(dev, pll.reg + 4, reg1 | (M1 << 16) | N1);
+ nv_wr32(dev, pll.reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
} else
if (dev_priv->chipset < NV_C0) {
ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
@@ -300,10 +294,10 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n",
pclk, ret, N1, N2, M1, P);
- reg1 = nv_rd32(dev, reg + 4) & 0xffc00000;
- nv_wr32(dev, reg, 0x50000610);
- nv_wr32(dev, reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
- nv_wr32(dev, reg + 8, N2);
+ reg1 = nv_rd32(dev, pll.reg + 4) & 0xffc00000;
+ nv_wr32(dev, pll.reg + 0, 0x50000610);
+ nv_wr32(dev, pll.reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
+ nv_wr32(dev, pll.reg + 8, N2);
} else {
ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
if (ret <= 0)
@@ -312,9 +306,9 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n",
pclk, ret, N1, N2, M1, P);
- nv_mask(dev, reg + 0x0c, 0x00000000, 0x00000100);
- nv_wr32(dev, reg + 0x04, (P << 16) | (N1 << 8) | M1);
- nv_wr32(dev, reg + 0x10, N2 << 16);
+ nv_mask(dev, pll.reg + 0x0c, 0x00000000, 0x00000100);
+ nv_wr32(dev, pll.reg + 0x04, (P << 16) | (N1 << 8) | M1);
+ nv_wr32(dev, pll.reg + 0x10, N2 << 16);
}
return 0;
@@ -338,7 +332,9 @@ nv50_crtc_destroy(struct drm_crtc *crtc)
nv50_cursor_fini(nv_crtc);
+ nouveau_bo_unmap(nv_crtc->lut.nvbo);
nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
+ nouveau_bo_unmap(nv_crtc->cursor.nvbo);
nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
kfree(nv_crtc->mode);
kfree(nv_crtc);
@@ -491,8 +487,9 @@ nv50_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
}
static int
-nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb, bool update)
+nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
+ struct drm_framebuffer *passed_fb,
+ int x, int y, bool update, bool atomic)
{
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_device *dev = nv_crtc->base.dev;
@@ -504,6 +501,28 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, int x, int y,
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
+ /* 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.)
+ */
+ if (atomic) {
+ drm_fb = passed_fb;
+ fb = nouveau_framebuffer(passed_fb);
+ }
+ else {
+ /* If not atomic, we can go ahead and pin, and unpin the
+ * old fb we were passed.
+ */
+ ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
+ if (ret)
+ return ret;
+
+ if (passed_fb) {
+ struct nouveau_framebuffer *ofb = nouveau_framebuffer(passed_fb);
+ nouveau_bo_unpin(ofb->nvbo);
+ }
+ }
+
switch (drm_fb->depth) {
case 8:
format = NV50_EVO_CRTC_FB_DEPTH_8;
@@ -526,15 +545,6 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, int x, int y,
return -EINVAL;
}
- ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
- if (ret)
- return ret;
-
- if (old_fb) {
- struct nouveau_framebuffer *ofb = nouveau_framebuffer(old_fb);
- nouveau_bo_unpin(ofb->nvbo);
- }
-
nv_crtc->fb.offset = fb->nvbo->bo.offset - dev_priv->vm_vram_base;
nv_crtc->fb.tile_flags = fb->nvbo->tile_flags;
nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8;
@@ -685,14 +695,22 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
nv_crtc->set_dither(nv_crtc, nv_connector->use_dithering, false);
nv_crtc->set_scale(nv_crtc, nv_connector->scaling_mode, false);
- return nv50_crtc_do_mode_set_base(crtc, x, y, old_fb, false);
+ return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false, false);
}
static int
nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
- return nv50_crtc_do_mode_set_base(crtc, x, y, old_fb, true);
+ return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, true, false);
+}
+
+static int
+nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y, enum mode_set_atomic state)
+{
+ return nv50_crtc_do_mode_set_base(crtc, fb, x, y, true, true);
}
static const struct drm_crtc_helper_funcs nv50_crtc_helper_funcs = {
@@ -702,6 +720,7 @@ static const struct drm_crtc_helper_funcs nv50_crtc_helper_funcs = {
.mode_fixup = nv50_crtc_mode_fixup,
.mode_set = nv50_crtc_mode_set,
.mode_set_base = nv50_crtc_mode_set_base,
+ .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic,
.load_lut = nv50_crtc_lut_load,
};
diff --git a/drivers/gpu/drm/nouveau/nv50_cursor.c b/drivers/gpu/drm/nouveau/nv50_cursor.c
index 03ad7ab14f09..1b9ce3021aa3 100644
--- a/drivers/gpu/drm/nouveau/nv50_cursor.c
+++ b/drivers/gpu/drm/nouveau/nv50_cursor.c
@@ -147,7 +147,7 @@ nv50_cursor_fini(struct nouveau_crtc *nv_crtc)
NV_DEBUG_KMS(dev, "\n");
nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), 0);
- if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx),
+ if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx),
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) {
NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n");
NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n",
diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c
index 1bc085962945..875414b09ade 100644
--- a/drivers/gpu/drm/nouveau/nv50_dac.c
+++ b/drivers/gpu/drm/nouveau/nv50_dac.c
@@ -79,7 +79,7 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
nv_wr32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
0x00150000 | NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
- if (!nv_wait(NV50_PDISPLAY_DAC_DPMS_CTRL(or),
+ if (!nv_wait(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) {
NV_ERROR(dev, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
NV_ERROR(dev, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
@@ -130,7 +130,7 @@ nv50_dac_dpms(struct drm_encoder *encoder, int mode)
NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
/* wait for it to be done */
- if (!nv_wait(NV50_PDISPLAY_DAC_DPMS_CTRL(or),
+ if (!nv_wait(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) {
NV_ERROR(dev, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
NV_ERROR(dev, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 612fa6d6a0cb..55c9663ef2bf 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -30,8 +30,22 @@
#include "nouveau_connector.h"
#include "nouveau_fb.h"
#include "nouveau_fbcon.h"
+#include "nouveau_ramht.h"
#include "drm_crtc_helper.h"
+static inline int
+nv50_sor_nr(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->chipset < 0x90 ||
+ dev_priv->chipset == 0x92 ||
+ dev_priv->chipset == 0xa0)
+ return 2;
+
+ return 4;
+}
+
static void
nv50_evo_channel_del(struct nouveau_channel **pchan)
{
@@ -42,6 +56,7 @@ nv50_evo_channel_del(struct nouveau_channel **pchan)
*pchan = NULL;
nouveau_gpuobj_channel_takedown(chan);
+ nouveau_bo_unmap(chan->pushbuf_bo);
nouveau_bo_ref(NULL, &chan->pushbuf_bo);
if (chan->user)
@@ -65,23 +80,23 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name,
return ret;
obj->engine = NVOBJ_ENGINE_DISPLAY;
- ret = nouveau_gpuobj_ref_add(dev, evo, name, obj, NULL);
- if (ret) {
- nouveau_gpuobj_del(dev, &obj);
- return ret;
- }
-
- nv_wo32(dev, obj, 0, (tile_flags << 22) | (magic_flags << 16) | class);
- nv_wo32(dev, obj, 1, limit);
- nv_wo32(dev, obj, 2, offset);
- nv_wo32(dev, obj, 3, 0x00000000);
- nv_wo32(dev, obj, 4, 0x00000000);
+ nv_wo32(obj, 0, (tile_flags << 22) | (magic_flags << 16) | class);
+ nv_wo32(obj, 4, limit);
+ nv_wo32(obj, 8, offset);
+ nv_wo32(obj, 12, 0x00000000);
+ nv_wo32(obj, 16, 0x00000000);
if (dev_priv->card_type < NV_C0)
- nv_wo32(dev, obj, 5, 0x00010000);
+ nv_wo32(obj, 20, 0x00010000);
else
- nv_wo32(dev, obj, 5, 0x00020000);
+ nv_wo32(obj, 20, 0x00020000);
dev_priv->engine.instmem.flush(dev);
+ ret = nouveau_ramht_insert(evo, name, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ if (ret) {
+ return ret;
+ }
+
return 0;
}
@@ -89,6 +104,7 @@ static int
nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *ramht = NULL;
struct nouveau_channel *chan;
int ret;
@@ -102,32 +118,35 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
chan->user_get = 4;
chan->user_put = 0;
- INIT_LIST_HEAD(&chan->ramht_refs);
-
- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32768, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin);
+ ret = nouveau_gpuobj_new(dev, NULL, 32768, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin);
if (ret) {
NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret);
nv50_evo_channel_del(pchan);
return ret;
}
- ret = drm_mm_init(&chan->ramin_heap,
- chan->ramin->gpuobj->im_pramin->start, 32768);
+ ret = drm_mm_init(&chan->ramin_heap, 0, 32768);
if (ret) {
NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret);
nv50_evo_channel_del(pchan);
return ret;
}
- ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 4096, 16,
- 0, &chan->ramht);
+ ret = nouveau_gpuobj_new(dev, chan, 4096, 16, 0, &ramht);
if (ret) {
NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret);
nv50_evo_channel_del(pchan);
return ret;
}
+ ret = nouveau_ramht_new(dev, ramht, &chan->ramht);
+ nouveau_gpuobj_ref(NULL, &ramht);
+ if (ret) {
+ nv50_evo_channel_del(pchan);
+ return ret;
+ }
+
if (dev_priv->chipset != 0x50) {
ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB16, 0x70, 0x19,
0, 0xffffffff);
@@ -227,11 +246,11 @@ nv50_display_init(struct drm_device *dev)
nv_wr32(dev, 0x006101d0 + (i * 0x04), val);
}
/* SOR */
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < nv50_sor_nr(dev); i++) {
val = nv_rd32(dev, 0x0061c000 + (i * 0x800));
nv_wr32(dev, 0x006101e0 + (i * 0x04), val);
}
- /* Something not yet in use, tv-out maybe. */
+ /* EXT */
for (i = 0; i < 3; i++) {
val = nv_rd32(dev, 0x0061e000 + (i * 0x800));
nv_wr32(dev, 0x006101f0 + (i * 0x04), val);
@@ -260,7 +279,7 @@ nv50_display_init(struct drm_device *dev)
if (nv_rd32(dev, NV50_PDISPLAY_INTR_1) & 0x100) {
nv_wr32(dev, NV50_PDISPLAY_INTR_1, 0x100);
nv_wr32(dev, 0x006194e8, nv_rd32(dev, 0x006194e8) & ~1);
- if (!nv_wait(0x006194e8, 2, 0)) {
+ if (!nv_wait(dev, 0x006194e8, 2, 0)) {
NV_ERROR(dev, "timeout: (0x6194e8 & 2) != 0\n");
NV_ERROR(dev, "0x6194e8 = 0x%08x\n",
nv_rd32(dev, 0x6194e8));
@@ -291,7 +310,8 @@ nv50_display_init(struct drm_device *dev)
nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, NV50_PDISPLAY_CTRL_STATE_ENABLE);
nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1000b03);
- if (!nv_wait(NV50_PDISPLAY_CHANNEL_STAT(0), 0x40000000, 0x40000000)) {
+ if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0),
+ 0x40000000, 0x40000000)) {
NV_ERROR(dev, "timeout: (0x610200 & 0x40000000) == 0x40000000\n");
NV_ERROR(dev, "0x610200 = 0x%08x\n",
nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0)));
@@ -300,7 +320,7 @@ nv50_display_init(struct drm_device *dev)
for (i = 0; i < 2; i++) {
nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000);
- if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+ if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) {
NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n");
NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n",
@@ -310,7 +330,7 @@ nv50_display_init(struct drm_device *dev)
nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON);
- if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+ if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS,
NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE)) {
NV_ERROR(dev, "timeout: "
@@ -321,16 +341,16 @@ nv50_display_init(struct drm_device *dev)
}
}
- nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->instance >> 8) | 9);
+ nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9);
/* initialise fifo */
nv_wr32(dev, NV50_PDISPLAY_CHANNEL_DMA_CB(0),
- ((evo->pushbuf_bo->bo.mem.mm_node->start << PAGE_SHIFT) >> 8) |
+ ((evo->pushbuf_bo->bo.mem.start << PAGE_SHIFT) >> 8) |
NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION_VRAM |
NV50_PDISPLAY_CHANNEL_DMA_CB_VALID);
nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK2(0), 0x00010000);
nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK3(0), 0x00000002);
- if (!nv_wait(0x610200, 0x80000000, 0x00000000)) {
+ if (!nv_wait(dev, 0x610200, 0x80000000, 0x00000000)) {
NV_ERROR(dev, "timeout: (0x610200 & 0x80000000) == 0\n");
NV_ERROR(dev, "0x610200 = 0x%08x\n", nv_rd32(dev, 0x610200));
return -EBUSY;
@@ -370,7 +390,7 @@ nv50_display_init(struct drm_device *dev)
BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK082C), 1);
OUT_RING(evo, 0);
FIRE_RING(evo);
- if (!nv_wait(0x640004, 0xffffffff, evo->dma.put << 2))
+ if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2))
NV_ERROR(dev, "evo pushbuf stalled\n");
/* enable clock change interrupts. */
@@ -424,7 +444,7 @@ static int nv50_display_disable(struct drm_device *dev)
continue;
nv_wr32(dev, NV50_PDISPLAY_INTR_1, mask);
- if (!nv_wait(NV50_PDISPLAY_INTR_1, mask, mask)) {
+ if (!nv_wait(dev, NV50_PDISPLAY_INTR_1, mask, mask)) {
NV_ERROR(dev, "timeout: (0x610024 & 0x%08x) == "
"0x%08x\n", mask, mask);
NV_ERROR(dev, "0x610024 = 0x%08x\n",
@@ -434,14 +454,14 @@ static int nv50_display_disable(struct drm_device *dev)
nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0);
nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, 0);
- if (!nv_wait(NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) {
+ if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) {
NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) == 0\n");
NV_ERROR(dev, "0x610200 = 0x%08x\n",
nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0)));
}
for (i = 0; i < 3; i++) {
- if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_STATE(i),
+ if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i),
NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) {
NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", i);
NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", i,
@@ -710,7 +730,7 @@ nv50_display_unk10_handler(struct drm_device *dev)
or = i;
}
- for (i = 0; type == OUTPUT_ANY && i < 4; i++) {
+ for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
if (dev_priv->chipset < 0x90 ||
dev_priv->chipset == 0x92 ||
dev_priv->chipset == 0xa0)
@@ -841,7 +861,7 @@ nv50_display_unk20_handler(struct drm_device *dev)
or = i;
}
- for (i = 0; type == OUTPUT_ANY && i < 4; i++) {
+ for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
if (dev_priv->chipset < 0x90 ||
dev_priv->chipset == 0x92 ||
dev_priv->chipset == 0xa0)
diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c
index 32611bd30e6d..cd1988b15d2c 100644
--- a/drivers/gpu/drm/nouveau/nv50_fb.c
+++ b/drivers/gpu/drm/nouveau/nv50_fb.c
@@ -20,6 +20,7 @@ nv50_fb_init(struct drm_device *dev)
case 0x50:
nv_wr32(dev, 0x100c90, 0x0707ff);
break;
+ case 0xa3:
case 0xa5:
case 0xa8:
nv_wr32(dev, 0x100c90, 0x0d0fff);
@@ -36,3 +37,42 @@ void
nv50_fb_takedown(struct drm_device *dev)
{
}
+
+void
+nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u32 trap[6], idx, chinst;
+ int i, ch;
+
+ idx = nv_rd32(dev, 0x100c90);
+ if (!(idx & 0x80000000))
+ return;
+ idx &= 0x00ffffff;
+
+ for (i = 0; i < 6; i++) {
+ nv_wr32(dev, 0x100c90, idx | i << 24);
+ trap[i] = nv_rd32(dev, 0x100c94);
+ }
+ nv_wr32(dev, 0x100c90, idx | 0x80000000);
+
+ if (!display)
+ return;
+
+ chinst = (trap[2] << 16) | trap[1];
+ for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) {
+ struct nouveau_channel *chan = dev_priv->fifos[ch];
+
+ if (!chan || !chan->ramin)
+ continue;
+
+ if (chinst == chan->ramin->vinst >> 12)
+ break;
+ }
+
+ NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x "
+ "channel %d (0x%08x)\n",
+ name, (trap[5] & 0x100 ? "read" : "write"),
+ trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff,
+ trap[0], ch, chinst);
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c
index 6bf025c6fc6f..6dcf048eddbc 100644
--- a/drivers/gpu/drm/nouveau/nv50_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c
@@ -1,6 +1,7 @@
#include "drmP.h"
#include "nouveau_drv.h"
#include "nouveau_dma.h"
+#include "nouveau_ramht.h"
#include "nouveau_fbcon.h"
void
@@ -193,7 +194,8 @@ nv50_fbcon_accel_init(struct fb_info *info)
if (ret)
return ret;
- ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, Nv2D, eng2d, NULL);
+ ret = nouveau_ramht_insert(dev_priv->channel, Nv2D, eng2d);
+ nouveau_gpuobj_ref(NULL, &eng2d);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c
index fb0281ae8f90..a46a961102f3 100644
--- a/drivers/gpu/drm/nouveau/nv50_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv50_fifo.c
@@ -27,13 +27,14 @@
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
static void
nv50_fifo_playlist_update(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nouveau_gpuobj_ref *cur;
+ struct nouveau_gpuobj *cur;
int i, nr;
NV_DEBUG(dev, "\n");
@@ -43,12 +44,14 @@ nv50_fifo_playlist_update(struct drm_device *dev)
/* We never schedule channel 0 or 127 */
for (i = 1, nr = 0; i < 127; i++) {
- if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc)
- nv_wo32(dev, cur->gpuobj, nr++, i);
+ if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc) {
+ nv_wo32(cur, (nr * 4), i);
+ nr++;
+ }
}
dev_priv->engine.instmem.flush(dev);
- nv_wr32(dev, 0x32f4, cur->instance >> 12);
+ nv_wr32(dev, 0x32f4, cur->vinst >> 12);
nv_wr32(dev, 0x32ec, nr);
nv_wr32(dev, 0x2500, 0x101);
}
@@ -63,9 +66,9 @@ nv50_fifo_channel_enable(struct drm_device *dev, int channel)
NV_DEBUG(dev, "ch%d\n", channel);
if (dev_priv->chipset == 0x50)
- inst = chan->ramfc->instance >> 12;
+ inst = chan->ramfc->vinst >> 12;
else
- inst = chan->ramfc->instance >> 8;
+ inst = chan->ramfc->vinst >> 8;
nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst |
NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED);
@@ -163,19 +166,19 @@ nv50_fifo_init(struct drm_device *dev)
goto just_reset;
}
- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC,
- &pfifo->playlist[0]);
+ ret = nouveau_gpuobj_new(dev, NULL, 128*4, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &pfifo->playlist[0]);
if (ret) {
NV_ERROR(dev, "error creating playlist 0: %d\n", ret);
return ret;
}
- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC,
- &pfifo->playlist[1]);
+ ret = nouveau_gpuobj_new(dev, NULL, 128*4, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &pfifo->playlist[1]);
if (ret) {
- nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
+ nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]);
NV_ERROR(dev, "error creating playlist 1: %d\n", ret);
return ret;
}
@@ -203,8 +206,8 @@ nv50_fifo_takedown(struct drm_device *dev)
if (!pfifo->playlist[0])
return;
- nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
- nouveau_gpuobj_ref_del(dev, &pfifo->playlist[1]);
+ nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]);
+ nouveau_gpuobj_ref(NULL, &pfifo->playlist[1]);
}
int
@@ -226,59 +229,54 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
NV_DEBUG(dev, "ch%d\n", chan->id);
if (dev_priv->chipset == 0x50) {
- uint32_t ramin_poffset = chan->ramin->gpuobj->im_pramin->start;
- uint32_t ramin_voffset = chan->ramin->gpuobj->im_backing_start;
-
- ret = nouveau_gpuobj_new_fake(dev, ramin_poffset, ramin_voffset,
- 0x100, NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_ZERO_FREE, &ramfc,
+ ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst,
+ chan->ramin->vinst, 0x100,
+ NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE,
&chan->ramfc);
if (ret)
return ret;
- ret = nouveau_gpuobj_new_fake(dev, ramin_poffset + 0x0400,
- ramin_voffset + 0x0400, 4096,
- 0, NULL, &chan->cache);
+ ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst + 0x0400,
+ chan->ramin->vinst + 0x0400,
+ 4096, 0, &chan->cache);
if (ret)
return ret;
} else {
- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 0x100, 256,
- NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_ZERO_FREE,
- &chan->ramfc);
+ ret = nouveau_gpuobj_new(dev, chan, 0x100, 256,
+ NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &chan->ramfc);
if (ret)
return ret;
- ramfc = chan->ramfc->gpuobj;
- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 4096, 1024,
- 0, &chan->cache);
+ ret = nouveau_gpuobj_new(dev, chan, 4096, 1024,
+ 0, &chan->cache);
if (ret)
return ret;
}
+ ramfc = chan->ramfc;
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4);
- nv_wo32(dev, ramfc, 0x80/4, (0 << 27) /* 4KiB */ |
- (4 << 24) /* SEARCH_FULL */ |
- (chan->ramht->instance >> 4));
- nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff);
- nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff);
- nv_wo32(dev, ramfc, 0x40/4, 0x00000000);
- nv_wo32(dev, ramfc, 0x7c/4, 0x30000001);
- nv_wo32(dev, ramfc, 0x78/4, 0x00000000);
- nv_wo32(dev, ramfc, 0x3c/4, 0x403f6078);
- nv_wo32(dev, ramfc, 0x50/4, chan->pushbuf_base +
- chan->dma.ib_base * 4);
- nv_wo32(dev, ramfc, 0x54/4, drm_order(chan->dma.ib_max + 1) << 16);
+ nv_wo32(ramfc, 0x48, chan->pushbuf->cinst >> 4);
+ nv_wo32(ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+ (4 << 24) /* SEARCH_FULL */ |
+ (chan->ramht->gpuobj->cinst >> 4));
+ nv_wo32(ramfc, 0x44, 0x2101ffff);
+ nv_wo32(ramfc, 0x60, 0x7fffffff);
+ nv_wo32(ramfc, 0x40, 0x00000000);
+ nv_wo32(ramfc, 0x7c, 0x30000001);
+ nv_wo32(ramfc, 0x78, 0x00000000);
+ nv_wo32(ramfc, 0x3c, 0x403f6078);
+ nv_wo32(ramfc, 0x50, chan->pushbuf_base + chan->dma.ib_base * 4);
+ nv_wo32(ramfc, 0x54, drm_order(chan->dma.ib_max + 1) << 16);
if (dev_priv->chipset != 0x50) {
- nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id);
- nv_wo32(dev, chan->ramin->gpuobj, 1,
- chan->ramfc->instance >> 8);
+ nv_wo32(chan->ramin, 0, chan->id);
+ nv_wo32(chan->ramin, 4, chan->ramfc->vinst >> 8);
- nv_wo32(dev, ramfc, 0x88/4, chan->cache->instance >> 10);
- nv_wo32(dev, ramfc, 0x98/4, chan->ramin->instance >> 12);
+ nv_wo32(ramfc, 0x88, chan->cache->vinst >> 10);
+ nv_wo32(ramfc, 0x98, chan->ramin->vinst >> 12);
}
dev_priv->engine.instmem.flush(dev);
@@ -293,12 +291,13 @@ void
nv50_fifo_destroy_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
- struct nouveau_gpuobj_ref *ramfc = chan->ramfc;
+ struct nouveau_gpuobj *ramfc = NULL;
NV_DEBUG(dev, "ch%d\n", chan->id);
/* This will ensure the channel is seen as disabled. */
- chan->ramfc = NULL;
+ nouveau_gpuobj_ref(chan->ramfc, &ramfc);
+ nouveau_gpuobj_ref(NULL, &chan->ramfc);
nv50_fifo_channel_disable(dev, chan->id);
/* Dummy channel, also used on ch 127 */
@@ -306,8 +305,8 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan)
nv50_fifo_channel_disable(dev, 127);
nv50_fifo_playlist_update(dev);
- nouveau_gpuobj_ref_del(dev, &ramfc);
- nouveau_gpuobj_ref_del(dev, &chan->cache);
+ nouveau_gpuobj_ref(NULL, &ramfc);
+ nouveau_gpuobj_ref(NULL, &chan->cache);
}
int
@@ -315,63 +314,63 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *ramfc = chan->ramfc->gpuobj;
- struct nouveau_gpuobj *cache = chan->cache->gpuobj;
+ struct nouveau_gpuobj *ramfc = chan->ramfc;
+ struct nouveau_gpuobj *cache = chan->cache;
int ptr, cnt;
NV_DEBUG(dev, "ch%d\n", chan->id);
- nv_wr32(dev, 0x3330, nv_ro32(dev, ramfc, 0x00/4));
- nv_wr32(dev, 0x3334, nv_ro32(dev, ramfc, 0x04/4));
- nv_wr32(dev, 0x3240, nv_ro32(dev, ramfc, 0x08/4));
- nv_wr32(dev, 0x3320, nv_ro32(dev, ramfc, 0x0c/4));
- nv_wr32(dev, 0x3244, nv_ro32(dev, ramfc, 0x10/4));
- nv_wr32(dev, 0x3328, nv_ro32(dev, ramfc, 0x14/4));
- nv_wr32(dev, 0x3368, nv_ro32(dev, ramfc, 0x18/4));
- nv_wr32(dev, 0x336c, nv_ro32(dev, ramfc, 0x1c/4));
- nv_wr32(dev, 0x3370, nv_ro32(dev, ramfc, 0x20/4));
- nv_wr32(dev, 0x3374, nv_ro32(dev, ramfc, 0x24/4));
- nv_wr32(dev, 0x3378, nv_ro32(dev, ramfc, 0x28/4));
- nv_wr32(dev, 0x337c, nv_ro32(dev, ramfc, 0x2c/4));
- nv_wr32(dev, 0x3228, nv_ro32(dev, ramfc, 0x30/4));
- nv_wr32(dev, 0x3364, nv_ro32(dev, ramfc, 0x34/4));
- nv_wr32(dev, 0x32a0, nv_ro32(dev, ramfc, 0x38/4));
- nv_wr32(dev, 0x3224, nv_ro32(dev, ramfc, 0x3c/4));
- nv_wr32(dev, 0x324c, nv_ro32(dev, ramfc, 0x40/4));
- nv_wr32(dev, 0x2044, nv_ro32(dev, ramfc, 0x44/4));
- nv_wr32(dev, 0x322c, nv_ro32(dev, ramfc, 0x48/4));
- nv_wr32(dev, 0x3234, nv_ro32(dev, ramfc, 0x4c/4));
- nv_wr32(dev, 0x3340, nv_ro32(dev, ramfc, 0x50/4));
- nv_wr32(dev, 0x3344, nv_ro32(dev, ramfc, 0x54/4));
- nv_wr32(dev, 0x3280, nv_ro32(dev, ramfc, 0x58/4));
- nv_wr32(dev, 0x3254, nv_ro32(dev, ramfc, 0x5c/4));
- nv_wr32(dev, 0x3260, nv_ro32(dev, ramfc, 0x60/4));
- nv_wr32(dev, 0x3264, nv_ro32(dev, ramfc, 0x64/4));
- nv_wr32(dev, 0x3268, nv_ro32(dev, ramfc, 0x68/4));
- nv_wr32(dev, 0x326c, nv_ro32(dev, ramfc, 0x6c/4));
- nv_wr32(dev, 0x32e4, nv_ro32(dev, ramfc, 0x70/4));
- nv_wr32(dev, 0x3248, nv_ro32(dev, ramfc, 0x74/4));
- nv_wr32(dev, 0x2088, nv_ro32(dev, ramfc, 0x78/4));
- nv_wr32(dev, 0x2058, nv_ro32(dev, ramfc, 0x7c/4));
- nv_wr32(dev, 0x2210, nv_ro32(dev, ramfc, 0x80/4));
-
- cnt = nv_ro32(dev, ramfc, 0x84/4);
+ nv_wr32(dev, 0x3330, nv_ro32(ramfc, 0x00));
+ nv_wr32(dev, 0x3334, nv_ro32(ramfc, 0x04));
+ nv_wr32(dev, 0x3240, nv_ro32(ramfc, 0x08));
+ nv_wr32(dev, 0x3320, nv_ro32(ramfc, 0x0c));
+ nv_wr32(dev, 0x3244, nv_ro32(ramfc, 0x10));
+ nv_wr32(dev, 0x3328, nv_ro32(ramfc, 0x14));
+ nv_wr32(dev, 0x3368, nv_ro32(ramfc, 0x18));
+ nv_wr32(dev, 0x336c, nv_ro32(ramfc, 0x1c));
+ nv_wr32(dev, 0x3370, nv_ro32(ramfc, 0x20));
+ nv_wr32(dev, 0x3374, nv_ro32(ramfc, 0x24));
+ nv_wr32(dev, 0x3378, nv_ro32(ramfc, 0x28));
+ nv_wr32(dev, 0x337c, nv_ro32(ramfc, 0x2c));
+ nv_wr32(dev, 0x3228, nv_ro32(ramfc, 0x30));
+ nv_wr32(dev, 0x3364, nv_ro32(ramfc, 0x34));
+ nv_wr32(dev, 0x32a0, nv_ro32(ramfc, 0x38));
+ nv_wr32(dev, 0x3224, nv_ro32(ramfc, 0x3c));
+ nv_wr32(dev, 0x324c, nv_ro32(ramfc, 0x40));
+ nv_wr32(dev, 0x2044, nv_ro32(ramfc, 0x44));
+ nv_wr32(dev, 0x322c, nv_ro32(ramfc, 0x48));
+ nv_wr32(dev, 0x3234, nv_ro32(ramfc, 0x4c));
+ nv_wr32(dev, 0x3340, nv_ro32(ramfc, 0x50));
+ nv_wr32(dev, 0x3344, nv_ro32(ramfc, 0x54));
+ nv_wr32(dev, 0x3280, nv_ro32(ramfc, 0x58));
+ nv_wr32(dev, 0x3254, nv_ro32(ramfc, 0x5c));
+ nv_wr32(dev, 0x3260, nv_ro32(ramfc, 0x60));
+ nv_wr32(dev, 0x3264, nv_ro32(ramfc, 0x64));
+ nv_wr32(dev, 0x3268, nv_ro32(ramfc, 0x68));
+ nv_wr32(dev, 0x326c, nv_ro32(ramfc, 0x6c));
+ nv_wr32(dev, 0x32e4, nv_ro32(ramfc, 0x70));
+ nv_wr32(dev, 0x3248, nv_ro32(ramfc, 0x74));
+ nv_wr32(dev, 0x2088, nv_ro32(ramfc, 0x78));
+ nv_wr32(dev, 0x2058, nv_ro32(ramfc, 0x7c));
+ nv_wr32(dev, 0x2210, nv_ro32(ramfc, 0x80));
+
+ cnt = nv_ro32(ramfc, 0x84);
for (ptr = 0; ptr < cnt; ptr++) {
nv_wr32(dev, NV40_PFIFO_CACHE1_METHOD(ptr),
- nv_ro32(dev, cache, (ptr * 2) + 0));
+ nv_ro32(cache, (ptr * 8) + 0));
nv_wr32(dev, NV40_PFIFO_CACHE1_DATA(ptr),
- nv_ro32(dev, cache, (ptr * 2) + 1));
+ nv_ro32(cache, (ptr * 8) + 4));
}
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, cnt << 2);
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
/* guessing that all the 0x34xx regs aren't on NV50 */
if (dev_priv->chipset != 0x50) {
- nv_wr32(dev, 0x340c, nv_ro32(dev, ramfc, 0x88/4));
- nv_wr32(dev, 0x3400, nv_ro32(dev, ramfc, 0x8c/4));
- nv_wr32(dev, 0x3404, nv_ro32(dev, ramfc, 0x90/4));
- nv_wr32(dev, 0x3408, nv_ro32(dev, ramfc, 0x94/4));
- nv_wr32(dev, 0x3410, nv_ro32(dev, ramfc, 0x98/4));
+ nv_wr32(dev, 0x340c, nv_ro32(ramfc, 0x88));
+ nv_wr32(dev, 0x3400, nv_ro32(ramfc, 0x8c));
+ nv_wr32(dev, 0x3404, nv_ro32(ramfc, 0x90));
+ nv_wr32(dev, 0x3408, nv_ro32(ramfc, 0x94));
+ nv_wr32(dev, 0x3410, nv_ro32(ramfc, 0x98));
}
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16));
@@ -399,62 +398,63 @@ nv50_fifo_unload_context(struct drm_device *dev)
return -EINVAL;
}
NV_DEBUG(dev, "ch%d\n", chan->id);
- ramfc = chan->ramfc->gpuobj;
- cache = chan->cache->gpuobj;
-
- nv_wo32(dev, ramfc, 0x00/4, nv_rd32(dev, 0x3330));
- nv_wo32(dev, ramfc, 0x04/4, nv_rd32(dev, 0x3334));
- nv_wo32(dev, ramfc, 0x08/4, nv_rd32(dev, 0x3240));
- nv_wo32(dev, ramfc, 0x0c/4, nv_rd32(dev, 0x3320));
- nv_wo32(dev, ramfc, 0x10/4, nv_rd32(dev, 0x3244));
- nv_wo32(dev, ramfc, 0x14/4, nv_rd32(dev, 0x3328));
- nv_wo32(dev, ramfc, 0x18/4, nv_rd32(dev, 0x3368));
- nv_wo32(dev, ramfc, 0x1c/4, nv_rd32(dev, 0x336c));
- nv_wo32(dev, ramfc, 0x20/4, nv_rd32(dev, 0x3370));
- nv_wo32(dev, ramfc, 0x24/4, nv_rd32(dev, 0x3374));
- nv_wo32(dev, ramfc, 0x28/4, nv_rd32(dev, 0x3378));
- nv_wo32(dev, ramfc, 0x2c/4, nv_rd32(dev, 0x337c));
- nv_wo32(dev, ramfc, 0x30/4, nv_rd32(dev, 0x3228));
- nv_wo32(dev, ramfc, 0x34/4, nv_rd32(dev, 0x3364));
- nv_wo32(dev, ramfc, 0x38/4, nv_rd32(dev, 0x32a0));
- nv_wo32(dev, ramfc, 0x3c/4, nv_rd32(dev, 0x3224));
- nv_wo32(dev, ramfc, 0x40/4, nv_rd32(dev, 0x324c));
- nv_wo32(dev, ramfc, 0x44/4, nv_rd32(dev, 0x2044));
- nv_wo32(dev, ramfc, 0x48/4, nv_rd32(dev, 0x322c));
- nv_wo32(dev, ramfc, 0x4c/4, nv_rd32(dev, 0x3234));
- nv_wo32(dev, ramfc, 0x50/4, nv_rd32(dev, 0x3340));
- nv_wo32(dev, ramfc, 0x54/4, nv_rd32(dev, 0x3344));
- nv_wo32(dev, ramfc, 0x58/4, nv_rd32(dev, 0x3280));
- nv_wo32(dev, ramfc, 0x5c/4, nv_rd32(dev, 0x3254));
- nv_wo32(dev, ramfc, 0x60/4, nv_rd32(dev, 0x3260));
- nv_wo32(dev, ramfc, 0x64/4, nv_rd32(dev, 0x3264));
- nv_wo32(dev, ramfc, 0x68/4, nv_rd32(dev, 0x3268));
- nv_wo32(dev, ramfc, 0x6c/4, nv_rd32(dev, 0x326c));
- nv_wo32(dev, ramfc, 0x70/4, nv_rd32(dev, 0x32e4));
- nv_wo32(dev, ramfc, 0x74/4, nv_rd32(dev, 0x3248));
- nv_wo32(dev, ramfc, 0x78/4, nv_rd32(dev, 0x2088));
- nv_wo32(dev, ramfc, 0x7c/4, nv_rd32(dev, 0x2058));
- nv_wo32(dev, ramfc, 0x80/4, nv_rd32(dev, 0x2210));
+ ramfc = chan->ramfc;
+ cache = chan->cache;
+
+ nv_wo32(ramfc, 0x00, nv_rd32(dev, 0x3330));
+ nv_wo32(ramfc, 0x04, nv_rd32(dev, 0x3334));
+ nv_wo32(ramfc, 0x08, nv_rd32(dev, 0x3240));
+ nv_wo32(ramfc, 0x0c, nv_rd32(dev, 0x3320));
+ nv_wo32(ramfc, 0x10, nv_rd32(dev, 0x3244));
+ nv_wo32(ramfc, 0x14, nv_rd32(dev, 0x3328));
+ nv_wo32(ramfc, 0x18, nv_rd32(dev, 0x3368));
+ nv_wo32(ramfc, 0x1c, nv_rd32(dev, 0x336c));
+ nv_wo32(ramfc, 0x20, nv_rd32(dev, 0x3370));
+ nv_wo32(ramfc, 0x24, nv_rd32(dev, 0x3374));
+ nv_wo32(ramfc, 0x28, nv_rd32(dev, 0x3378));
+ nv_wo32(ramfc, 0x2c, nv_rd32(dev, 0x337c));
+ nv_wo32(ramfc, 0x30, nv_rd32(dev, 0x3228));
+ nv_wo32(ramfc, 0x34, nv_rd32(dev, 0x3364));
+ nv_wo32(ramfc, 0x38, nv_rd32(dev, 0x32a0));
+ nv_wo32(ramfc, 0x3c, nv_rd32(dev, 0x3224));
+ nv_wo32(ramfc, 0x40, nv_rd32(dev, 0x324c));
+ nv_wo32(ramfc, 0x44, nv_rd32(dev, 0x2044));
+ nv_wo32(ramfc, 0x48, nv_rd32(dev, 0x322c));
+ nv_wo32(ramfc, 0x4c, nv_rd32(dev, 0x3234));
+ nv_wo32(ramfc, 0x50, nv_rd32(dev, 0x3340));
+ nv_wo32(ramfc, 0x54, nv_rd32(dev, 0x3344));
+ nv_wo32(ramfc, 0x58, nv_rd32(dev, 0x3280));
+ nv_wo32(ramfc, 0x5c, nv_rd32(dev, 0x3254));
+ nv_wo32(ramfc, 0x60, nv_rd32(dev, 0x3260));
+ nv_wo32(ramfc, 0x64, nv_rd32(dev, 0x3264));
+ nv_wo32(ramfc, 0x68, nv_rd32(dev, 0x3268));
+ nv_wo32(ramfc, 0x6c, nv_rd32(dev, 0x326c));
+ nv_wo32(ramfc, 0x70, nv_rd32(dev, 0x32e4));
+ nv_wo32(ramfc, 0x74, nv_rd32(dev, 0x3248));
+ nv_wo32(ramfc, 0x78, nv_rd32(dev, 0x2088));
+ nv_wo32(ramfc, 0x7c, nv_rd32(dev, 0x2058));
+ nv_wo32(ramfc, 0x80, nv_rd32(dev, 0x2210));
put = (nv_rd32(dev, NV03_PFIFO_CACHE1_PUT) & 0x7ff) >> 2;
get = (nv_rd32(dev, NV03_PFIFO_CACHE1_GET) & 0x7ff) >> 2;
ptr = 0;
while (put != get) {
- nv_wo32(dev, cache, ptr++,
- nv_rd32(dev, NV40_PFIFO_CACHE1_METHOD(get)));
- nv_wo32(dev, cache, ptr++,
- nv_rd32(dev, NV40_PFIFO_CACHE1_DATA(get)));
+ nv_wo32(cache, ptr + 0,
+ nv_rd32(dev, NV40_PFIFO_CACHE1_METHOD(get)));
+ nv_wo32(cache, ptr + 4,
+ nv_rd32(dev, NV40_PFIFO_CACHE1_DATA(get)));
get = (get + 1) & 0x1ff;
+ ptr += 8;
}
/* guessing that all the 0x34xx regs aren't on NV50 */
if (dev_priv->chipset != 0x50) {
- nv_wo32(dev, ramfc, 0x84/4, ptr >> 1);
- nv_wo32(dev, ramfc, 0x88/4, nv_rd32(dev, 0x340c));
- nv_wo32(dev, ramfc, 0x8c/4, nv_rd32(dev, 0x3400));
- nv_wo32(dev, ramfc, 0x90/4, nv_rd32(dev, 0x3404));
- nv_wo32(dev, ramfc, 0x94/4, nv_rd32(dev, 0x3408));
- nv_wo32(dev, ramfc, 0x98/4, nv_rd32(dev, 0x3410));
+ nv_wo32(ramfc, 0x84, ptr >> 3);
+ nv_wo32(ramfc, 0x88, nv_rd32(dev, 0x340c));
+ nv_wo32(ramfc, 0x8c, nv_rd32(dev, 0x3400));
+ nv_wo32(ramfc, 0x90, nv_rd32(dev, 0x3404));
+ nv_wo32(ramfc, 0x94, nv_rd32(dev, 0x3408));
+ nv_wo32(ramfc, 0x98, nv_rd32(dev, 0x3410));
}
dev_priv->engine.instmem.flush(dev);
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
index 1413028e1580..cbf5ae2f67d4 100644
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
@@ -27,7 +27,7 @@
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
-
+#include "nouveau_ramht.h"
#include "nouveau_grctx.h"
static void
@@ -181,7 +181,7 @@ nv50_graph_channel(struct drm_device *dev)
/* Be sure we're not in the middle of a context switch or bad things
* will happen, such as unloading the wrong pgraph context.
*/
- if (!nv_wait(0x400300, 0x00000001, 0x00000000))
+ if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000))
NV_ERROR(dev, "Ctxprog is still running\n");
inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
@@ -192,7 +192,7 @@ nv50_graph_channel(struct drm_device *dev)
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
struct nouveau_channel *chan = dev_priv->fifos[i];
- if (chan && chan->ramin && chan->ramin->instance == inst)
+ if (chan && chan->ramin && chan->ramin->vinst == inst)
return chan;
}
@@ -204,36 +204,34 @@ nv50_graph_create_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
- struct nouveau_gpuobj *obj;
+ struct nouveau_gpuobj *ramin = chan->ramin;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_grctx ctx = {};
int hdr, ret;
NV_DEBUG(dev, "ch%d\n", chan->id);
- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
- 0x1000, NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
+ ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
if (ret)
return ret;
- obj = chan->ramin_grctx->gpuobj;
hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
- nv_wo32(dev, ramin, (hdr + 0x00)/4, 0x00190002);
- nv_wo32(dev, ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance +
- pgraph->grctx_size - 1);
- nv_wo32(dev, ramin, (hdr + 0x08)/4, chan->ramin_grctx->instance);
- nv_wo32(dev, ramin, (hdr + 0x0c)/4, 0);
- nv_wo32(dev, ramin, (hdr + 0x10)/4, 0);
- nv_wo32(dev, ramin, (hdr + 0x14)/4, 0x00010000);
+ nv_wo32(ramin, hdr + 0x00, 0x00190002);
+ nv_wo32(ramin, hdr + 0x04, chan->ramin_grctx->vinst +
+ pgraph->grctx_size - 1);
+ nv_wo32(ramin, hdr + 0x08, chan->ramin_grctx->vinst);
+ nv_wo32(ramin, hdr + 0x0c, 0);
+ nv_wo32(ramin, hdr + 0x10, 0);
+ nv_wo32(ramin, hdr + 0x14, 0x00010000);
ctx.dev = chan->dev;
ctx.mode = NOUVEAU_GRCTX_VALS;
- ctx.data = obj;
+ ctx.data = chan->ramin_grctx;
nv50_grctx_init(&ctx);
- nv_wo32(dev, obj, 0x00000/4, chan->ramin->instance >> 12);
+ nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12);
dev_priv->engine.instmem.flush(dev);
return 0;
@@ -248,14 +246,14 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
NV_DEBUG(dev, "ch%d\n", chan->id);
- if (!chan->ramin || !chan->ramin->gpuobj)
+ if (!chan->ramin)
return;
for (i = hdr; i < hdr + 24; i += 4)
- nv_wo32(dev, chan->ramin->gpuobj, i/4, 0);
+ nv_wo32(chan->ramin, i, 0);
dev_priv->engine.instmem.flush(dev);
- nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
+ nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
}
static int
@@ -282,7 +280,7 @@ nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst)
int
nv50_graph_load_context(struct nouveau_channel *chan)
{
- uint32_t inst = chan->ramin->instance >> 12;
+ uint32_t inst = chan->ramin->vinst >> 12;
NV_DEBUG(chan->dev, "ch%d\n", chan->id);
return nv50_graph_do_load_context(chan->dev, inst);
@@ -327,15 +325,16 @@ static int
nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan, int grclass,
int mthd, uint32_t data)
{
- struct nouveau_gpuobj_ref *ref = NULL;
+ struct nouveau_gpuobj *gpuobj;
- if (nouveau_gpuobj_ref_find(chan, data, &ref))
+ gpuobj = nouveau_ramht_find(chan, data);
+ if (!gpuobj)
return -ENOENT;
- if (nouveau_notifier_offset(ref->gpuobj, NULL))
+ if (nouveau_notifier_offset(gpuobj, NULL))
return -EINVAL;
- chan->nvsw.vblsem = ref->gpuobj;
+ chan->nvsw.vblsem = gpuobj;
chan->nvsw.vblsem_offset = ~0;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c
index 42a8fb20c1e6..336aab2a24a6 100644
--- a/drivers/gpu/drm/nouveau/nv50_grctx.c
+++ b/drivers/gpu/drm/nouveau/nv50_grctx.c
@@ -103,6 +103,9 @@
#include "nouveau_drv.h"
#include "nouveau_grctx.h"
+#define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf)
+#define IS_NVAAF(x) ((x) >= 0xaa && (x) <= 0xac)
+
/*
* This code deals with PGRAPH contexts on NV50 family cards. Like NV40, it's
* the GPU itself that does context-switching, but it needs a special
@@ -182,6 +185,7 @@ nv50_grctx_init(struct nouveau_grctx *ctx)
case 0xa8:
case 0xaa:
case 0xac:
+ case 0xaf:
break;
default:
NV_ERROR(ctx->dev, "I don't know how to make a ctxprog for "
@@ -268,6 +272,9 @@ nv50_grctx_init(struct nouveau_grctx *ctx)
*/
static void
+nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx);
+
+static void
nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
@@ -286,7 +293,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
gr_def(ctx, 0x400840, 0xffe806a8);
}
gr_def(ctx, 0x400844, 0x00000002);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ if (IS_NVA3F(dev_priv->chipset))
gr_def(ctx, 0x400894, 0x00001000);
gr_def(ctx, 0x4008e8, 0x00000003);
gr_def(ctx, 0x4008ec, 0x00001000);
@@ -299,13 +306,15 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
if (dev_priv->chipset >= 0xa0)
cp_ctx(ctx, 0x400b00, 0x1);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
+ if (IS_NVA3F(dev_priv->chipset)) {
cp_ctx(ctx, 0x400b10, 0x1);
gr_def(ctx, 0x400b10, 0x0001629d);
cp_ctx(ctx, 0x400b20, 0x1);
gr_def(ctx, 0x400b20, 0x0001629d);
}
+ nv50_graph_construct_mmio_ddata(ctx);
+
/* 0C00: VFETCH */
cp_ctx(ctx, 0x400c08, 0x2);
gr_def(ctx, 0x400c08, 0x0000fe0c);
@@ -314,7 +323,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
if (dev_priv->chipset < 0xa0) {
cp_ctx(ctx, 0x401008, 0x4);
gr_def(ctx, 0x401014, 0x00001000);
- } else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa) {
+ } else if (!IS_NVA3F(dev_priv->chipset)) {
cp_ctx(ctx, 0x401008, 0x5);
gr_def(ctx, 0x401018, 0x00001000);
} else {
@@ -368,10 +377,13 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
case 0xa3:
case 0xa5:
case 0xa8:
+ case 0xaf:
gr_def(ctx, 0x401c00, 0x142500df);
break;
}
+ /* 2000 */
+
/* 2400 */
cp_ctx(ctx, 0x402400, 0x1);
if (dev_priv->chipset == 0x50)
@@ -380,12 +392,12 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
cp_ctx(ctx, 0x402408, 0x2);
gr_def(ctx, 0x402408, 0x00000600);
- /* 2800 */
+ /* 2800: CSCHED */
cp_ctx(ctx, 0x402800, 0x1);
if (dev_priv->chipset == 0x50)
gr_def(ctx, 0x402800, 0x00000006);
- /* 2C00 */
+ /* 2C00: ZCULL */
cp_ctx(ctx, 0x402c08, 0x6);
if (dev_priv->chipset != 0x50)
gr_def(ctx, 0x402c14, 0x01000000);
@@ -396,23 +408,23 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
cp_ctx(ctx, 0x402ca0, 0x2);
if (dev_priv->chipset < 0xa0)
gr_def(ctx, 0x402ca0, 0x00000400);
- else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa)
+ else if (!IS_NVA3F(dev_priv->chipset))
gr_def(ctx, 0x402ca0, 0x00000800);
else
gr_def(ctx, 0x402ca0, 0x00000400);
cp_ctx(ctx, 0x402cac, 0x4);
- /* 3000 */
+ /* 3000: ENG2D */
cp_ctx(ctx, 0x403004, 0x1);
gr_def(ctx, 0x403004, 0x00000001);
- /* 3404 */
+ /* 3400 */
if (dev_priv->chipset >= 0xa0) {
cp_ctx(ctx, 0x403404, 0x1);
gr_def(ctx, 0x403404, 0x00000001);
}
- /* 5000 */
+ /* 5000: CCACHE */
cp_ctx(ctx, 0x405000, 0x1);
switch (dev_priv->chipset) {
case 0x50:
@@ -425,6 +437,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
case 0xa8:
case 0xaa:
case 0xac:
+ case 0xaf:
gr_def(ctx, 0x405000, 0x000e0080);
break;
case 0x86:
@@ -441,210 +454,6 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
cp_ctx(ctx, 0x405024, 0x1);
cp_ctx(ctx, 0x40502c, 0x1);
- /* 5400 or maybe 4800 */
- if (dev_priv->chipset == 0x50) {
- offset = 0x405400;
- cp_ctx(ctx, 0x405400, 0xea);
- } else if (dev_priv->chipset < 0x94) {
- offset = 0x405400;
- cp_ctx(ctx, 0x405400, 0xcb);
- } else if (dev_priv->chipset < 0xa0) {
- offset = 0x405400;
- cp_ctx(ctx, 0x405400, 0xcc);
- } else if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
- offset = 0x404800;
- cp_ctx(ctx, 0x404800, 0xda);
- } else {
- offset = 0x405400;
- cp_ctx(ctx, 0x405400, 0xd4);
- }
- gr_def(ctx, offset + 0x0c, 0x00000002);
- gr_def(ctx, offset + 0x10, 0x00000001);
- if (dev_priv->chipset >= 0x94)
- offset += 4;
- gr_def(ctx, offset + 0x1c, 0x00000001);
- gr_def(ctx, offset + 0x20, 0x00000100);
- gr_def(ctx, offset + 0x38, 0x00000002);
- gr_def(ctx, offset + 0x3c, 0x00000001);
- gr_def(ctx, offset + 0x40, 0x00000001);
- gr_def(ctx, offset + 0x50, 0x00000001);
- gr_def(ctx, offset + 0x54, 0x003fffff);
- gr_def(ctx, offset + 0x58, 0x00001fff);
- gr_def(ctx, offset + 0x60, 0x00000001);
- gr_def(ctx, offset + 0x64, 0x00000001);
- gr_def(ctx, offset + 0x6c, 0x00000001);
- gr_def(ctx, offset + 0x70, 0x00000001);
- gr_def(ctx, offset + 0x74, 0x00000001);
- gr_def(ctx, offset + 0x78, 0x00000004);
- gr_def(ctx, offset + 0x7c, 0x00000001);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- offset += 4;
- gr_def(ctx, offset + 0x80, 0x00000001);
- gr_def(ctx, offset + 0x84, 0x00000001);
- gr_def(ctx, offset + 0x88, 0x00000007);
- gr_def(ctx, offset + 0x8c, 0x00000001);
- gr_def(ctx, offset + 0x90, 0x00000007);
- gr_def(ctx, offset + 0x94, 0x00000001);
- gr_def(ctx, offset + 0x98, 0x00000001);
- gr_def(ctx, offset + 0x9c, 0x00000001);
- if (dev_priv->chipset == 0x50) {
- gr_def(ctx, offset + 0xb0, 0x00000001);
- gr_def(ctx, offset + 0xb4, 0x00000001);
- gr_def(ctx, offset + 0xbc, 0x00000001);
- gr_def(ctx, offset + 0xc0, 0x0000000a);
- gr_def(ctx, offset + 0xd0, 0x00000040);
- gr_def(ctx, offset + 0xd8, 0x00000002);
- gr_def(ctx, offset + 0xdc, 0x00000100);
- gr_def(ctx, offset + 0xe0, 0x00000001);
- gr_def(ctx, offset + 0xe4, 0x00000100);
- gr_def(ctx, offset + 0x100, 0x00000001);
- gr_def(ctx, offset + 0x124, 0x00000004);
- gr_def(ctx, offset + 0x13c, 0x00000001);
- gr_def(ctx, offset + 0x140, 0x00000100);
- gr_def(ctx, offset + 0x148, 0x00000001);
- gr_def(ctx, offset + 0x154, 0x00000100);
- gr_def(ctx, offset + 0x158, 0x00000001);
- gr_def(ctx, offset + 0x15c, 0x00000100);
- gr_def(ctx, offset + 0x164, 0x00000001);
- gr_def(ctx, offset + 0x170, 0x00000100);
- gr_def(ctx, offset + 0x174, 0x00000001);
- gr_def(ctx, offset + 0x17c, 0x00000001);
- gr_def(ctx, offset + 0x188, 0x00000002);
- gr_def(ctx, offset + 0x190, 0x00000001);
- gr_def(ctx, offset + 0x198, 0x00000001);
- gr_def(ctx, offset + 0x1ac, 0x00000003);
- offset += 0xd0;
- } else {
- gr_def(ctx, offset + 0xb0, 0x00000001);
- gr_def(ctx, offset + 0xb4, 0x00000100);
- gr_def(ctx, offset + 0xbc, 0x00000001);
- gr_def(ctx, offset + 0xc8, 0x00000100);
- gr_def(ctx, offset + 0xcc, 0x00000001);
- gr_def(ctx, offset + 0xd0, 0x00000100);
- gr_def(ctx, offset + 0xd8, 0x00000001);
- gr_def(ctx, offset + 0xe4, 0x00000100);
- }
- gr_def(ctx, offset + 0xf8, 0x00000004);
- gr_def(ctx, offset + 0xfc, 0x00000070);
- gr_def(ctx, offset + 0x100, 0x00000080);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- offset += 4;
- gr_def(ctx, offset + 0x114, 0x0000000c);
- if (dev_priv->chipset == 0x50)
- offset -= 4;
- gr_def(ctx, offset + 0x11c, 0x00000008);
- gr_def(ctx, offset + 0x120, 0x00000014);
- if (dev_priv->chipset == 0x50) {
- gr_def(ctx, offset + 0x124, 0x00000026);
- offset -= 0x18;
- } else {
- gr_def(ctx, offset + 0x128, 0x00000029);
- gr_def(ctx, offset + 0x12c, 0x00000027);
- gr_def(ctx, offset + 0x130, 0x00000026);
- gr_def(ctx, offset + 0x134, 0x00000008);
- gr_def(ctx, offset + 0x138, 0x00000004);
- gr_def(ctx, offset + 0x13c, 0x00000027);
- }
- gr_def(ctx, offset + 0x148, 0x00000001);
- gr_def(ctx, offset + 0x14c, 0x00000002);
- gr_def(ctx, offset + 0x150, 0x00000003);
- gr_def(ctx, offset + 0x154, 0x00000004);
- gr_def(ctx, offset + 0x158, 0x00000005);
- gr_def(ctx, offset + 0x15c, 0x00000006);
- gr_def(ctx, offset + 0x160, 0x00000007);
- gr_def(ctx, offset + 0x164, 0x00000001);
- gr_def(ctx, offset + 0x1a8, 0x000000cf);
- if (dev_priv->chipset == 0x50)
- offset -= 4;
- gr_def(ctx, offset + 0x1d8, 0x00000080);
- gr_def(ctx, offset + 0x1dc, 0x00000004);
- gr_def(ctx, offset + 0x1e0, 0x00000004);
- if (dev_priv->chipset == 0x50)
- offset -= 4;
- else
- gr_def(ctx, offset + 0x1e4, 0x00000003);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
- gr_def(ctx, offset + 0x1ec, 0x00000003);
- offset += 8;
- }
- gr_def(ctx, offset + 0x1e8, 0x00000001);
- if (dev_priv->chipset == 0x50)
- offset -= 4;
- gr_def(ctx, offset + 0x1f4, 0x00000012);
- gr_def(ctx, offset + 0x1f8, 0x00000010);
- gr_def(ctx, offset + 0x1fc, 0x0000000c);
- gr_def(ctx, offset + 0x200, 0x00000001);
- gr_def(ctx, offset + 0x210, 0x00000004);
- gr_def(ctx, offset + 0x214, 0x00000002);
- gr_def(ctx, offset + 0x218, 0x00000004);
- if (dev_priv->chipset >= 0xa0)
- offset += 4;
- gr_def(ctx, offset + 0x224, 0x003fffff);
- gr_def(ctx, offset + 0x228, 0x00001fff);
- if (dev_priv->chipset == 0x50)
- offset -= 0x20;
- else if (dev_priv->chipset >= 0xa0) {
- gr_def(ctx, offset + 0x250, 0x00000001);
- gr_def(ctx, offset + 0x254, 0x00000001);
- gr_def(ctx, offset + 0x258, 0x00000002);
- offset += 0x10;
- }
- gr_def(ctx, offset + 0x250, 0x00000004);
- gr_def(ctx, offset + 0x254, 0x00000014);
- gr_def(ctx, offset + 0x258, 0x00000001);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- offset += 4;
- gr_def(ctx, offset + 0x264, 0x00000002);
- if (dev_priv->chipset >= 0xa0)
- offset += 8;
- gr_def(ctx, offset + 0x270, 0x00000001);
- gr_def(ctx, offset + 0x278, 0x00000002);
- gr_def(ctx, offset + 0x27c, 0x00001000);
- if (dev_priv->chipset == 0x50)
- offset -= 0xc;
- else {
- gr_def(ctx, offset + 0x280, 0x00000e00);
- gr_def(ctx, offset + 0x284, 0x00001000);
- gr_def(ctx, offset + 0x288, 0x00001e00);
- }
- gr_def(ctx, offset + 0x290, 0x00000001);
- gr_def(ctx, offset + 0x294, 0x00000001);
- gr_def(ctx, offset + 0x298, 0x00000001);
- gr_def(ctx, offset + 0x29c, 0x00000001);
- gr_def(ctx, offset + 0x2a0, 0x00000001);
- gr_def(ctx, offset + 0x2b0, 0x00000200);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
- gr_def(ctx, offset + 0x2b4, 0x00000200);
- offset += 4;
- }
- if (dev_priv->chipset < 0xa0) {
- gr_def(ctx, offset + 0x2b8, 0x00000001);
- gr_def(ctx, offset + 0x2bc, 0x00000070);
- gr_def(ctx, offset + 0x2c0, 0x00000080);
- gr_def(ctx, offset + 0x2cc, 0x00000001);
- gr_def(ctx, offset + 0x2d0, 0x00000070);
- gr_def(ctx, offset + 0x2d4, 0x00000080);
- } else {
- gr_def(ctx, offset + 0x2b8, 0x00000001);
- gr_def(ctx, offset + 0x2bc, 0x000000f0);
- gr_def(ctx, offset + 0x2c0, 0x000000ff);
- gr_def(ctx, offset + 0x2cc, 0x00000001);
- gr_def(ctx, offset + 0x2d0, 0x000000f0);
- gr_def(ctx, offset + 0x2d4, 0x000000ff);
- gr_def(ctx, offset + 0x2dc, 0x00000009);
- offset += 4;
- }
- gr_def(ctx, offset + 0x2e4, 0x00000001);
- gr_def(ctx, offset + 0x2e8, 0x000000cf);
- gr_def(ctx, offset + 0x2f0, 0x00000001);
- gr_def(ctx, offset + 0x300, 0x000000cf);
- gr_def(ctx, offset + 0x308, 0x00000002);
- gr_def(ctx, offset + 0x310, 0x00000001);
- gr_def(ctx, offset + 0x318, 0x00000001);
- gr_def(ctx, offset + 0x320, 0x000000cf);
- gr_def(ctx, offset + 0x324, 0x000000cf);
- gr_def(ctx, offset + 0x328, 0x00000001);
-
/* 6000? */
if (dev_priv->chipset == 0x50)
cp_ctx(ctx, 0x4063e0, 0x1);
@@ -661,7 +470,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
gr_def(ctx, 0x406818, 0x00000f80);
else
gr_def(ctx, 0x406818, 0x00001f80);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+ if (IS_NVA3F(dev_priv->chipset))
gr_def(ctx, 0x40681c, 0x00000030);
cp_ctx(ctx, 0x406830, 0x3);
}
@@ -706,7 +515,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
if (dev_priv->chipset < 0xa0)
cp_ctx(ctx, 0x407094 + (i<<8), 1);
- else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa)
+ else if (!IS_NVA3F(dev_priv->chipset))
cp_ctx(ctx, 0x407094 + (i<<8), 3);
else {
cp_ctx(ctx, 0x407094 + (i<<8), 4);
@@ -799,6 +608,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
case 0xa8:
case 0xaa:
case 0xac:
+ case 0xaf:
gr_def(ctx, offset + 0x1c, 0x300c0000);
break;
}
@@ -825,7 +635,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
gr_def(ctx, base + 0x304, 0x00007070);
else if (dev_priv->chipset < 0xa0)
gr_def(ctx, base + 0x304, 0x00027070);
- else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa)
+ else if (!IS_NVA3F(dev_priv->chipset))
gr_def(ctx, base + 0x304, 0x01127070);
else
gr_def(ctx, base + 0x304, 0x05127070);
@@ -849,7 +659,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
if (dev_priv->chipset < 0xa0) {
cp_ctx(ctx, base + 0x340, 9);
offset = base + 0x340;
- } else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) {
+ } else if (!IS_NVA3F(dev_priv->chipset)) {
cp_ctx(ctx, base + 0x33c, 0xb);
offset = base + 0x344;
} else {
@@ -880,7 +690,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
gr_def(ctx, offset + 0x0, 0x000001f0);
gr_def(ctx, offset + 0x4, 0x00000001);
gr_def(ctx, offset + 0x8, 0x00000003);
- if (dev_priv->chipset == 0x50 || dev_priv->chipset >= 0xaa)
+ if (dev_priv->chipset == 0x50 || IS_NVAAF(dev_priv->chipset))
gr_def(ctx, offset + 0xc, 0x00008000);
gr_def(ctx, offset + 0x14, 0x00039e00);
cp_ctx(ctx, offset + 0x1c, 2);
@@ -892,7 +702,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
if (dev_priv->chipset >= 0xa0) {
cp_ctx(ctx, base + 0x54c, 2);
- if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa)
+ if (!IS_NVA3F(dev_priv->chipset))
gr_def(ctx, base + 0x54c, 0x003fe006);
else
gr_def(ctx, base + 0x54c, 0x003fe007);
@@ -948,6 +758,336 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
}
}
+static void
+dd_emit(struct nouveau_grctx *ctx, int num, uint32_t val) {
+ int i;
+ if (val && ctx->mode == NOUVEAU_GRCTX_VALS)
+ for (i = 0; i < num; i++)
+ nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + i), val);
+ ctx->ctxvals_pos += num;
+}
+
+static void
+nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ int base, num;
+ base = ctx->ctxvals_pos;
+
+ /* tesla state */
+ dd_emit(ctx, 1, 0); /* 00000001 UNK0F90 */
+ dd_emit(ctx, 1, 0); /* 00000001 UNK135C */
+
+ /* SRC_TIC state */
+ dd_emit(ctx, 1, 0); /* 00000007 SRC_TILE_MODE_Z */
+ dd_emit(ctx, 1, 2); /* 00000007 SRC_TILE_MODE_Y */
+ dd_emit(ctx, 1, 1); /* 00000001 SRC_LINEAR #1 */
+ dd_emit(ctx, 1, 0); /* 000000ff SRC_ADDRESS_HIGH */
+ dd_emit(ctx, 1, 0); /* 00000001 SRC_SRGB */
+ if (dev_priv->chipset >= 0x94)
+ dd_emit(ctx, 1, 0); /* 00000003 eng2d UNK0258 */
+ dd_emit(ctx, 1, 1); /* 00000fff SRC_DEPTH */
+ dd_emit(ctx, 1, 0x100); /* 0000ffff SRC_HEIGHT */
+
+ /* turing state */
+ dd_emit(ctx, 1, 0); /* 0000000f TEXTURES_LOG2 */
+ dd_emit(ctx, 1, 0); /* 0000000f SAMPLERS_LOG2 */
+ dd_emit(ctx, 1, 0); /* 000000ff CB_DEF_ADDRESS_HIGH */
+ dd_emit(ctx, 1, 0); /* ffffffff CB_DEF_ADDRESS_LOW */
+ dd_emit(ctx, 1, 0); /* ffffffff SHARED_SIZE */
+ dd_emit(ctx, 1, 2); /* ffffffff REG_MODE */
+ dd_emit(ctx, 1, 1); /* 0000ffff BLOCK_ALLOC_THREADS */
+ dd_emit(ctx, 1, 1); /* 00000001 LANES32 */
+ dd_emit(ctx, 1, 0); /* 000000ff UNK370 */
+ dd_emit(ctx, 1, 0); /* 000000ff USER_PARAM_UNK */
+ dd_emit(ctx, 1, 0); /* 000000ff USER_PARAM_COUNT */
+ dd_emit(ctx, 1, 1); /* 000000ff UNK384 bits 8-15 */
+ dd_emit(ctx, 1, 0x3fffff); /* 003fffff TIC_LIMIT */
+ dd_emit(ctx, 1, 0x1fff); /* 000fffff TSC_LIMIT */
+ dd_emit(ctx, 1, 0); /* 0000ffff CB_ADDR_INDEX */
+ dd_emit(ctx, 1, 1); /* 000007ff BLOCKDIM_X */
+ dd_emit(ctx, 1, 1); /* 000007ff BLOCKDIM_XMY */
+ dd_emit(ctx, 1, 0); /* 00000001 BLOCKDIM_XMY_OVERFLOW */
+ dd_emit(ctx, 1, 1); /* 0003ffff BLOCKDIM_XMYMZ */
+ dd_emit(ctx, 1, 1); /* 000007ff BLOCKDIM_Y */
+ dd_emit(ctx, 1, 1); /* 0000007f BLOCKDIM_Z */
+ dd_emit(ctx, 1, 4); /* 000000ff CP_REG_ALLOC_TEMP */
+ dd_emit(ctx, 1, 1); /* 00000001 BLOCKDIM_DIRTY */
+ if (IS_NVA3F(dev_priv->chipset))
+ dd_emit(ctx, 1, 0); /* 00000003 UNK03E8 */
+ dd_emit(ctx, 1, 1); /* 0000007f BLOCK_ALLOC_HALFWARPS */
+ dd_emit(ctx, 1, 1); /* 00000007 LOCAL_WARPS_NO_CLAMP */
+ dd_emit(ctx, 1, 7); /* 00000007 LOCAL_WARPS_LOG_ALLOC */
+ dd_emit(ctx, 1, 1); /* 00000007 STACK_WARPS_NO_CLAMP */
+ dd_emit(ctx, 1, 7); /* 00000007 STACK_WARPS_LOG_ALLOC */
+ dd_emit(ctx, 1, 1); /* 00001fff BLOCK_ALLOC_REGSLOTS_PACKED */
+ dd_emit(ctx, 1, 1); /* 00001fff BLOCK_ALLOC_REGSLOTS_STRIDED */
+ dd_emit(ctx, 1, 1); /* 000007ff BLOCK_ALLOC_THREADS */
+
+ /* compat 2d state */
+ if (dev_priv->chipset == 0x50) {
+ dd_emit(ctx, 4, 0); /* 0000ffff clip X, Y, W, H */
+
+ dd_emit(ctx, 1, 1); /* ffffffff chroma COLOR_FORMAT */
+
+ dd_emit(ctx, 1, 1); /* ffffffff pattern COLOR_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff pattern SHAPE */
+ dd_emit(ctx, 1, 1); /* ffffffff pattern PATTERN_SELECT */
+
+ dd_emit(ctx, 1, 0xa); /* ffffffff surf2d SRC_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff surf2d DMA_SRC */
+ dd_emit(ctx, 1, 0); /* 000000ff surf2d SRC_ADDRESS_HIGH */
+ dd_emit(ctx, 1, 0); /* ffffffff surf2d SRC_ADDRESS_LOW */
+ dd_emit(ctx, 1, 0x40); /* 0000ffff surf2d SRC_PITCH */
+ dd_emit(ctx, 1, 0); /* 0000000f surf2d SRC_TILE_MODE_Z */
+ dd_emit(ctx, 1, 2); /* 0000000f surf2d SRC_TILE_MODE_Y */
+ dd_emit(ctx, 1, 0x100); /* ffffffff surf2d SRC_HEIGHT */
+ dd_emit(ctx, 1, 1); /* 00000001 surf2d SRC_LINEAR */
+ dd_emit(ctx, 1, 0x100); /* ffffffff surf2d SRC_WIDTH */
+
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_B_X */
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_B_Y */
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_C_X */
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_C_Y */
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_D_X */
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_D_Y */
+ dd_emit(ctx, 1, 1); /* ffffffff gdirect COLOR_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff gdirect OPERATION */
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect POINT_X */
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect POINT_Y */
+
+ dd_emit(ctx, 1, 0); /* 0000ffff blit SRC_Y */
+ dd_emit(ctx, 1, 0); /* ffffffff blit OPERATION */
+
+ dd_emit(ctx, 1, 0); /* ffffffff ifc OPERATION */
+
+ dd_emit(ctx, 1, 0); /* ffffffff iifc INDEX_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff iifc LUT_OFFSET */
+ dd_emit(ctx, 1, 4); /* ffffffff iifc COLOR_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff iifc OPERATION */
+ }
+
+ /* m2mf state */
+ dd_emit(ctx, 1, 0); /* ffffffff m2mf LINE_COUNT */
+ dd_emit(ctx, 1, 0); /* ffffffff m2mf LINE_LENGTH_IN */
+ dd_emit(ctx, 2, 0); /* ffffffff m2mf OFFSET_IN, OFFSET_OUT */
+ dd_emit(ctx, 1, 1); /* ffffffff m2mf TILING_DEPTH_OUT */
+ dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_HEIGHT_OUT */
+ dd_emit(ctx, 1, 0); /* ffffffff m2mf TILING_POSITION_OUT_Z */
+ dd_emit(ctx, 1, 1); /* 00000001 m2mf LINEAR_OUT */
+ dd_emit(ctx, 2, 0); /* 0000ffff m2mf TILING_POSITION_OUT_X, Y */
+ dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_PITCH_OUT */
+ dd_emit(ctx, 1, 1); /* ffffffff m2mf TILING_DEPTH_IN */
+ dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_HEIGHT_IN */
+ dd_emit(ctx, 1, 0); /* ffffffff m2mf TILING_POSITION_IN_Z */
+ dd_emit(ctx, 1, 1); /* 00000001 m2mf LINEAR_IN */
+ dd_emit(ctx, 2, 0); /* 0000ffff m2mf TILING_POSITION_IN_X, Y */
+ dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_PITCH_IN */
+
+ /* more compat 2d state */
+ if (dev_priv->chipset == 0x50) {
+ dd_emit(ctx, 1, 1); /* ffffffff line COLOR_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff line OPERATION */
+
+ dd_emit(ctx, 1, 1); /* ffffffff triangle COLOR_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff triangle OPERATION */
+
+ dd_emit(ctx, 1, 0); /* 0000000f sifm TILE_MODE_Z */
+ dd_emit(ctx, 1, 2); /* 0000000f sifm TILE_MODE_Y */
+ dd_emit(ctx, 1, 0); /* 000000ff sifm FORMAT_FILTER */
+ dd_emit(ctx, 1, 1); /* 000000ff sifm FORMAT_ORIGIN */
+ dd_emit(ctx, 1, 0); /* 0000ffff sifm SRC_PITCH */
+ dd_emit(ctx, 1, 1); /* 00000001 sifm SRC_LINEAR */
+ dd_emit(ctx, 1, 0); /* 000000ff sifm SRC_OFFSET_HIGH */
+ dd_emit(ctx, 1, 0); /* ffffffff sifm SRC_OFFSET */
+ dd_emit(ctx, 1, 0); /* 0000ffff sifm SRC_HEIGHT */
+ dd_emit(ctx, 1, 0); /* 0000ffff sifm SRC_WIDTH */
+ dd_emit(ctx, 1, 3); /* ffffffff sifm COLOR_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff sifm OPERATION */
+
+ dd_emit(ctx, 1, 0); /* ffffffff sifc OPERATION */
+ }
+
+ /* tesla state */
+ dd_emit(ctx, 1, 0); /* 0000000f GP_TEXTURES_LOG2 */
+ dd_emit(ctx, 1, 0); /* 0000000f GP_SAMPLERS_LOG2 */
+ dd_emit(ctx, 1, 0); /* 000000ff */
+ dd_emit(ctx, 1, 0); /* ffffffff */
+ dd_emit(ctx, 1, 4); /* 000000ff UNK12B0_0 */
+ dd_emit(ctx, 1, 0x70); /* 000000ff UNK12B0_1 */
+ dd_emit(ctx, 1, 0x80); /* 000000ff UNK12B0_3 */
+ dd_emit(ctx, 1, 0); /* 000000ff UNK12B0_2 */
+ dd_emit(ctx, 1, 0); /* 0000000f FP_TEXTURES_LOG2 */
+ dd_emit(ctx, 1, 0); /* 0000000f FP_SAMPLERS_LOG2 */
+ if (IS_NVA3F(dev_priv->chipset)) {
+ dd_emit(ctx, 1, 0); /* ffffffff */
+ dd_emit(ctx, 1, 0); /* 0000007f MULTISAMPLE_SAMPLES_LOG2 */
+ } else {
+ dd_emit(ctx, 1, 0); /* 0000000f MULTISAMPLE_SAMPLES_LOG2 */
+ }
+ dd_emit(ctx, 1, 0xc); /* 000000ff SEMANTIC_COLOR.BFC0_ID */
+ if (dev_priv->chipset != 0x50)
+ dd_emit(ctx, 1, 0); /* 00000001 SEMANTIC_COLOR.CLMP_EN */
+ dd_emit(ctx, 1, 8); /* 000000ff SEMANTIC_COLOR.COLR_NR */
+ dd_emit(ctx, 1, 0x14); /* 000000ff SEMANTIC_COLOR.FFC0_ID */
+ if (dev_priv->chipset == 0x50) {
+ dd_emit(ctx, 1, 0); /* 000000ff SEMANTIC_LAYER */
+ dd_emit(ctx, 1, 0); /* 00000001 */
+ } else {
+ dd_emit(ctx, 1, 0); /* 00000001 SEMANTIC_PTSZ.ENABLE */
+ dd_emit(ctx, 1, 0x29); /* 000000ff SEMANTIC_PTSZ.PTSZ_ID */
+ dd_emit(ctx, 1, 0x27); /* 000000ff SEMANTIC_PRIM */
+ dd_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */
+ dd_emit(ctx, 1, 8); /* 0000000f SMENATIC_CLIP.CLIP_HIGH */
+ dd_emit(ctx, 1, 4); /* 000000ff SEMANTIC_CLIP.CLIP_LO */
+ dd_emit(ctx, 1, 0x27); /* 000000ff UNK0FD4 */
+ dd_emit(ctx, 1, 0); /* 00000001 UNK1900 */
+ }
+ dd_emit(ctx, 1, 0); /* 00000007 RT_CONTROL_MAP0 */
+ dd_emit(ctx, 1, 1); /* 00000007 RT_CONTROL_MAP1 */
+ dd_emit(ctx, 1, 2); /* 00000007 RT_CONTROL_MAP2 */
+ dd_emit(ctx, 1, 3); /* 00000007 RT_CONTROL_MAP3 */
+ dd_emit(ctx, 1, 4); /* 00000007 RT_CONTROL_MAP4 */
+ dd_emit(ctx, 1, 5); /* 00000007 RT_CONTROL_MAP5 */
+ dd_emit(ctx, 1, 6); /* 00000007 RT_CONTROL_MAP6 */
+ dd_emit(ctx, 1, 7); /* 00000007 RT_CONTROL_MAP7 */
+ dd_emit(ctx, 1, 1); /* 0000000f RT_CONTROL_COUNT */
+ dd_emit(ctx, 8, 0); /* 00000001 RT_HORIZ_UNK */
+ dd_emit(ctx, 8, 0); /* ffffffff RT_ADDRESS_LOW */
+ dd_emit(ctx, 1, 0xcf); /* 000000ff RT_FORMAT */
+ dd_emit(ctx, 7, 0); /* 000000ff RT_FORMAT */
+ if (dev_priv->chipset != 0x50)
+ dd_emit(ctx, 3, 0); /* 1, 1, 1 */
+ else
+ dd_emit(ctx, 2, 0); /* 1, 1 */
+ dd_emit(ctx, 1, 0); /* ffffffff GP_ENABLE */
+ dd_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT*/
+ dd_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */
+ dd_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ if (IS_NVA3F(dev_priv->chipset)) {
+ dd_emit(ctx, 1, 3); /* 00000003 */
+ dd_emit(ctx, 1, 0); /* 00000001 UNK1418. Alone. */
+ }
+ if (dev_priv->chipset != 0x50)
+ dd_emit(ctx, 1, 3); /* 00000003 UNK15AC */
+ dd_emit(ctx, 1, 1); /* ffffffff RASTERIZE_ENABLE */
+ dd_emit(ctx, 1, 0); /* 00000001 FP_CONTROL.EXPORTS_Z */
+ if (dev_priv->chipset != 0x50)
+ dd_emit(ctx, 1, 0); /* 00000001 FP_CONTROL.MULTIPLE_RESULTS */
+ dd_emit(ctx, 1, 0x12); /* 000000ff FP_INTERPOLANT_CTRL.COUNT */
+ dd_emit(ctx, 1, 0x10); /* 000000ff FP_INTERPOLANT_CTRL.COUNT_NONFLAT */
+ dd_emit(ctx, 1, 0xc); /* 000000ff FP_INTERPOLANT_CTRL.OFFSET */
+ dd_emit(ctx, 1, 1); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.W */
+ dd_emit(ctx, 1, 0); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.X */
+ dd_emit(ctx, 1, 0); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.Y */
+ dd_emit(ctx, 1, 0); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.Z */
+ dd_emit(ctx, 1, 4); /* 000000ff FP_RESULT_COUNT */
+ dd_emit(ctx, 1, 2); /* ffffffff REG_MODE */
+ dd_emit(ctx, 1, 4); /* 000000ff FP_REG_ALLOC_TEMP */
+ if (dev_priv->chipset >= 0xa0)
+ dd_emit(ctx, 1, 0); /* ffffffff */
+ dd_emit(ctx, 1, 0); /* 00000001 GP_BUILTIN_RESULT_EN.LAYER_IDX */
+ dd_emit(ctx, 1, 0); /* ffffffff STRMOUT_ENABLE */
+ dd_emit(ctx, 1, 0x3fffff); /* 003fffff TIC_LIMIT */
+ dd_emit(ctx, 1, 0x1fff); /* 000fffff TSC_LIMIT */
+ dd_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE*/
+ if (dev_priv->chipset != 0x50)
+ dd_emit(ctx, 8, 0); /* 00000001 */
+ if (dev_priv->chipset >= 0xa0) {
+ dd_emit(ctx, 1, 1); /* 00000007 VTX_ATTR_DEFINE.COMP */
+ dd_emit(ctx, 1, 1); /* 00000007 VTX_ATTR_DEFINE.SIZE */
+ dd_emit(ctx, 1, 2); /* 00000007 VTX_ATTR_DEFINE.TYPE */
+ dd_emit(ctx, 1, 0); /* 000000ff VTX_ATTR_DEFINE.ATTR */
+ }
+ dd_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ dd_emit(ctx, 1, 0x14); /* 0000001f ZETA_FORMAT */
+ dd_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ dd_emit(ctx, 1, 0); /* 0000000f VP_TEXTURES_LOG2 */
+ dd_emit(ctx, 1, 0); /* 0000000f VP_SAMPLERS_LOG2 */
+ if (IS_NVA3F(dev_priv->chipset))
+ dd_emit(ctx, 1, 0); /* 00000001 */
+ dd_emit(ctx, 1, 2); /* 00000003 POLYGON_MODE_BACK */
+ if (dev_priv->chipset >= 0xa0)
+ dd_emit(ctx, 1, 0); /* 00000003 VTX_ATTR_DEFINE.SIZE - 1 */
+ dd_emit(ctx, 1, 0); /* 0000ffff CB_ADDR_INDEX */
+ if (dev_priv->chipset >= 0xa0)
+ dd_emit(ctx, 1, 0); /* 00000003 */
+ dd_emit(ctx, 1, 0); /* 00000001 CULL_FACE_ENABLE */
+ dd_emit(ctx, 1, 1); /* 00000003 CULL_FACE */
+ dd_emit(ctx, 1, 0); /* 00000001 FRONT_FACE */
+ dd_emit(ctx, 1, 2); /* 00000003 POLYGON_MODE_FRONT */
+ dd_emit(ctx, 1, 0x1000); /* 00007fff UNK141C */
+ if (dev_priv->chipset != 0x50) {
+ dd_emit(ctx, 1, 0xe00); /* 7fff */
+ dd_emit(ctx, 1, 0x1000); /* 7fff */
+ dd_emit(ctx, 1, 0x1e00); /* 7fff */
+ }
+ dd_emit(ctx, 1, 0); /* 00000001 BEGIN_END_ACTIVE */
+ dd_emit(ctx, 1, 1); /* 00000001 POLYGON_MODE_??? */
+ dd_emit(ctx, 1, 1); /* 000000ff GP_REG_ALLOC_TEMP / 4 rounded up */
+ dd_emit(ctx, 1, 1); /* 000000ff FP_REG_ALLOC_TEMP... without /4? */
+ dd_emit(ctx, 1, 1); /* 000000ff VP_REG_ALLOC_TEMP / 4 rounded up */
+ dd_emit(ctx, 1, 1); /* 00000001 */
+ dd_emit(ctx, 1, 0); /* 00000001 */
+ dd_emit(ctx, 1, 0); /* 00000001 VTX_ATTR_MASK_UNK0 nonempty */
+ dd_emit(ctx, 1, 0); /* 00000001 VTX_ATTR_MASK_UNK1 nonempty */
+ dd_emit(ctx, 1, 0x200); /* 0003ffff GP_VERTEX_OUTPUT_COUNT*GP_REG_ALLOC_RESULT */
+ if (IS_NVA3F(dev_priv->chipset))
+ dd_emit(ctx, 1, 0x200);
+ dd_emit(ctx, 1, 0); /* 00000001 */
+ if (dev_priv->chipset < 0xa0) {
+ dd_emit(ctx, 1, 1); /* 00000001 */
+ dd_emit(ctx, 1, 0x70); /* 000000ff */
+ dd_emit(ctx, 1, 0x80); /* 000000ff */
+ dd_emit(ctx, 1, 0); /* 000000ff */
+ dd_emit(ctx, 1, 0); /* 00000001 */
+ dd_emit(ctx, 1, 1); /* 00000001 */
+ dd_emit(ctx, 1, 0x70); /* 000000ff */
+ dd_emit(ctx, 1, 0x80); /* 000000ff */
+ dd_emit(ctx, 1, 0); /* 000000ff */
+ } else {
+ dd_emit(ctx, 1, 1); /* 00000001 */
+ dd_emit(ctx, 1, 0xf0); /* 000000ff */
+ dd_emit(ctx, 1, 0xff); /* 000000ff */
+ dd_emit(ctx, 1, 0); /* 000000ff */
+ dd_emit(ctx, 1, 0); /* 00000001 */
+ dd_emit(ctx, 1, 1); /* 00000001 */
+ dd_emit(ctx, 1, 0xf0); /* 000000ff */
+ dd_emit(ctx, 1, 0xff); /* 000000ff */
+ dd_emit(ctx, 1, 0); /* 000000ff */
+ dd_emit(ctx, 1, 9); /* 0000003f UNK114C.COMP,SIZE */
+ }
+
+ /* eng2d state */
+ dd_emit(ctx, 1, 0); /* 00000001 eng2d COLOR_KEY_ENABLE */
+ dd_emit(ctx, 1, 0); /* 00000007 eng2d COLOR_KEY_FORMAT */
+ dd_emit(ctx, 1, 1); /* ffffffff eng2d DST_DEPTH */
+ dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d DST_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff eng2d DST_LAYER */
+ dd_emit(ctx, 1, 1); /* 00000001 eng2d DST_LINEAR */
+ dd_emit(ctx, 1, 0); /* 00000007 eng2d PATTERN_COLOR_FORMAT */
+ dd_emit(ctx, 1, 0); /* 00000007 eng2d OPERATION */
+ dd_emit(ctx, 1, 0); /* 00000003 eng2d PATTERN_SELECT */
+ dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d SIFC_FORMAT */
+ dd_emit(ctx, 1, 0); /* 00000001 eng2d SIFC_BITMAP_ENABLE */
+ dd_emit(ctx, 1, 2); /* 00000003 eng2d SIFC_BITMAP_UNK808 */
+ dd_emit(ctx, 1, 0); /* ffffffff eng2d BLIT_DU_DX_FRACT */
+ dd_emit(ctx, 1, 1); /* ffffffff eng2d BLIT_DU_DX_INT */
+ dd_emit(ctx, 1, 0); /* ffffffff eng2d BLIT_DV_DY_FRACT */
+ dd_emit(ctx, 1, 1); /* ffffffff eng2d BLIT_DV_DY_INT */
+ dd_emit(ctx, 1, 0); /* 00000001 eng2d BLIT_CONTROL_FILTER */
+ dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d DRAW_COLOR_FORMAT */
+ dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d SRC_FORMAT */
+ dd_emit(ctx, 1, 1); /* 00000001 eng2d SRC_LINEAR #2 */
+
+ num = ctx->ctxvals_pos - base;
+ ctx->ctxvals_pos = base;
+ if (IS_NVA3F(dev_priv->chipset))
+ cp_ctx(ctx, 0x404800, num);
+ else
+ cp_ctx(ctx, 0x405400, num);
+}
+
/*
* xfer areas. These are a pain.
*
@@ -990,28 +1130,33 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
* without the help of ctxprog.
*/
-static inline void
+static void
xf_emit(struct nouveau_grctx *ctx, int num, uint32_t val) {
int i;
if (val && ctx->mode == NOUVEAU_GRCTX_VALS)
for (i = 0; i < num; i++)
- nv_wo32(ctx->dev, ctx->data, ctx->ctxvals_pos + (i << 3), val);
+ nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + (i << 3)), val);
ctx->ctxvals_pos += num << 3;
}
/* Gene declarations... */
+static void nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx);
static void nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk1(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk2(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk3(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk4(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk5(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk6(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk7(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk8(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk9(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk10(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_clipid(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx);
static void nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx);
static void nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx);
@@ -1030,102 +1175,32 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
if (dev_priv->chipset < 0xa0) {
/* Strand 0 */
ctx->ctxvals_pos = offset;
- switch (dev_priv->chipset) {
- case 0x50:
- xf_emit(ctx, 0x99, 0);
- break;
- case 0x84:
- case 0x86:
- xf_emit(ctx, 0x384, 0);
- break;
- case 0x92:
- case 0x94:
- case 0x96:
- case 0x98:
- xf_emit(ctx, 0x380, 0);
- break;
- }
- nv50_graph_construct_gene_m2mf (ctx);
- switch (dev_priv->chipset) {
- case 0x50:
- case 0x84:
- case 0x86:
- case 0x98:
- xf_emit(ctx, 0x4c4, 0);
- break;
- case 0x92:
- case 0x94:
- case 0x96:
- xf_emit(ctx, 0x984, 0);
- break;
- }
- nv50_graph_construct_gene_unk5(ctx);
- if (dev_priv->chipset == 0x50)
- xf_emit(ctx, 0xa, 0);
- else
- xf_emit(ctx, 0xb, 0);
- nv50_graph_construct_gene_unk4(ctx);
- nv50_graph_construct_gene_unk3(ctx);
+ nv50_graph_construct_gene_dispatch(ctx);
+ nv50_graph_construct_gene_m2mf(ctx);
+ nv50_graph_construct_gene_unk24xx(ctx);
+ nv50_graph_construct_gene_clipid(ctx);
+ nv50_graph_construct_gene_zcull(ctx);
if ((ctx->ctxvals_pos-offset)/8 > size)
size = (ctx->ctxvals_pos-offset)/8;
/* Strand 1 */
ctx->ctxvals_pos = offset + 0x1;
- nv50_graph_construct_gene_unk6(ctx);
- nv50_graph_construct_gene_unk7(ctx);
- nv50_graph_construct_gene_unk8(ctx);
- switch (dev_priv->chipset) {
- case 0x50:
- case 0x92:
- xf_emit(ctx, 0xfb, 0);
- break;
- case 0x84:
- xf_emit(ctx, 0xd3, 0);
- break;
- case 0x94:
- case 0x96:
- xf_emit(ctx, 0xab, 0);
- break;
- case 0x86:
- case 0x98:
- xf_emit(ctx, 0x6b, 0);
- break;
- }
- xf_emit(ctx, 2, 0x4e3bfdf);
- xf_emit(ctx, 4, 0);
- xf_emit(ctx, 1, 0x0fac6881);
- xf_emit(ctx, 0xb, 0);
- xf_emit(ctx, 2, 0x4e3bfdf);
+ nv50_graph_construct_gene_vfetch(ctx);
+ nv50_graph_construct_gene_eng2d(ctx);
+ nv50_graph_construct_gene_csched(ctx);
+ nv50_graph_construct_gene_ropm1(ctx);
+ nv50_graph_construct_gene_ropm2(ctx);
if ((ctx->ctxvals_pos-offset)/8 > size)
size = (ctx->ctxvals_pos-offset)/8;
/* Strand 2 */
ctx->ctxvals_pos = offset + 0x2;
- switch (dev_priv->chipset) {
- case 0x50:
- case 0x92:
- xf_emit(ctx, 0xa80, 0);
- break;
- case 0x84:
- xf_emit(ctx, 0xa7e, 0);
- break;
- case 0x94:
- case 0x96:
- xf_emit(ctx, 0xa7c, 0);
- break;
- case 0x86:
- case 0x98:
- xf_emit(ctx, 0xa7a, 0);
- break;
- }
- xf_emit(ctx, 1, 0x3fffff);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 0x1fff);
- xf_emit(ctx, 0xe, 0);
- nv50_graph_construct_gene_unk9(ctx);
- nv50_graph_construct_gene_unk2(ctx);
- nv50_graph_construct_gene_unk1(ctx);
- nv50_graph_construct_gene_unk10(ctx);
+ nv50_graph_construct_gene_ccache(ctx);
+ nv50_graph_construct_gene_unk1cxx(ctx);
+ nv50_graph_construct_gene_strmout(ctx);
+ nv50_graph_construct_gene_unk14xx(ctx);
+ nv50_graph_construct_gene_unk10xx(ctx);
+ nv50_graph_construct_gene_unk34xx(ctx);
if ((ctx->ctxvals_pos-offset)/8 > size)
size = (ctx->ctxvals_pos-offset)/8;
@@ -1150,86 +1225,46 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
} else {
/* Strand 0 */
ctx->ctxvals_pos = offset;
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 0x385, 0);
- else
- xf_emit(ctx, 0x384, 0);
+ nv50_graph_construct_gene_dispatch(ctx);
nv50_graph_construct_gene_m2mf(ctx);
- xf_emit(ctx, 0x950, 0);
- nv50_graph_construct_gene_unk10(ctx);
- xf_emit(ctx, 1, 0x0fac6881);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 3, 0);
- }
- nv50_graph_construct_gene_unk8(ctx);
- if (dev_priv->chipset == 0xa0)
- xf_emit(ctx, 0x189, 0);
- else if (dev_priv->chipset == 0xa3)
- xf_emit(ctx, 0xd5, 0);
- else if (dev_priv->chipset == 0xa5)
- xf_emit(ctx, 0x99, 0);
- else if (dev_priv->chipset == 0xaa)
- xf_emit(ctx, 0x65, 0);
- else
- xf_emit(ctx, 0x6d, 0);
- nv50_graph_construct_gene_unk9(ctx);
+ nv50_graph_construct_gene_unk34xx(ctx);
+ nv50_graph_construct_gene_csched(ctx);
+ nv50_graph_construct_gene_unk1cxx(ctx);
+ nv50_graph_construct_gene_strmout(ctx);
if ((ctx->ctxvals_pos-offset)/8 > size)
size = (ctx->ctxvals_pos-offset)/8;
/* Strand 1 */
ctx->ctxvals_pos = offset + 1;
- nv50_graph_construct_gene_unk1(ctx);
+ nv50_graph_construct_gene_unk10xx(ctx);
if ((ctx->ctxvals_pos-offset)/8 > size)
size = (ctx->ctxvals_pos-offset)/8;
/* Strand 2 */
ctx->ctxvals_pos = offset + 2;
- if (dev_priv->chipset == 0xa0) {
- nv50_graph_construct_gene_unk2(ctx);
- }
- xf_emit(ctx, 0x36, 0);
- nv50_graph_construct_gene_unk5(ctx);
+ if (dev_priv->chipset == 0xa0)
+ nv50_graph_construct_gene_unk14xx(ctx);
+ nv50_graph_construct_gene_unk24xx(ctx);
if ((ctx->ctxvals_pos-offset)/8 > size)
size = (ctx->ctxvals_pos-offset)/8;
/* Strand 3 */
ctx->ctxvals_pos = offset + 3;
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
- nv50_graph_construct_gene_unk6(ctx);
+ nv50_graph_construct_gene_vfetch(ctx);
if ((ctx->ctxvals_pos-offset)/8 > size)
size = (ctx->ctxvals_pos-offset)/8;
/* Strand 4 */
ctx->ctxvals_pos = offset + 4;
- if (dev_priv->chipset == 0xa0)
- xf_emit(ctx, 0xa80, 0);
- else if (dev_priv->chipset == 0xa3)
- xf_emit(ctx, 0xa7c, 0);
- else
- xf_emit(ctx, 0xa7a, 0);
- xf_emit(ctx, 1, 0x3fffff);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 0x1fff);
+ nv50_graph_construct_gene_ccache(ctx);
if ((ctx->ctxvals_pos-offset)/8 > size)
size = (ctx->ctxvals_pos-offset)/8;
/* Strand 5 */
ctx->ctxvals_pos = offset + 5;
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x0fac6881);
- xf_emit(ctx, 0xb, 0);
- xf_emit(ctx, 2, 0x4e3bfdf);
- xf_emit(ctx, 3, 0);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 2, 0x4e3bfdf);
- xf_emit(ctx, 2, 0);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 1, 0);
+ nv50_graph_construct_gene_ropm2(ctx);
+ nv50_graph_construct_gene_ropm1(ctx);
+ /* per-ROP context */
for (i = 0; i < 8; i++)
if (units & (1<<(i+16)))
nv50_graph_construct_gene_ropc(ctx);
@@ -1238,10 +1273,9 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
/* Strand 6 */
ctx->ctxvals_pos = offset + 6;
- nv50_graph_construct_gene_unk3(ctx);
- xf_emit(ctx, 0xb, 0);
- nv50_graph_construct_gene_unk4(ctx);
- nv50_graph_construct_gene_unk7(ctx);
+ nv50_graph_construct_gene_zcull(ctx);
+ nv50_graph_construct_gene_clipid(ctx);
+ nv50_graph_construct_gene_eng2d(ctx);
if (units & (1 << 0))
nv50_graph_construct_xfer_tp(ctx);
if (units & (1 << 1))
@@ -1269,7 +1303,7 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
if (units & (1 << 9))
nv50_graph_construct_xfer_tp(ctx);
} else {
- nv50_graph_construct_gene_unk2(ctx);
+ nv50_graph_construct_gene_unk14xx(ctx);
}
if ((ctx->ctxvals_pos-offset)/8 > size)
size = (ctx->ctxvals_pos-offset)/8;
@@ -1290,9 +1324,70 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
*/
static void
+nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx)
+{
+ /* start of strand 0 */
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ /* SEEK */
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 5, 0);
+ else if (!IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 6, 0);
+ else
+ xf_emit(ctx, 4, 0);
+ /* SEEK */
+ /* the PGRAPH's internal FIFO */
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 8*3, 0);
+ else
+ xf_emit(ctx, 0x100*3, 0);
+ /* and another bonus slot?!? */
+ xf_emit(ctx, 3, 0);
+ /* and YET ANOTHER bonus slot? */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 3, 0);
+ /* SEEK */
+ /* CTX_SWITCH: caches of gr objects bound to subchannels. 8 values, last used index */
+ xf_emit(ctx, 9, 0);
+ /* SEEK */
+ xf_emit(ctx, 9, 0);
+ /* SEEK */
+ xf_emit(ctx, 9, 0);
+ /* SEEK */
+ xf_emit(ctx, 9, 0);
+ /* SEEK */
+ if (dev_priv->chipset < 0x90)
+ xf_emit(ctx, 4, 0);
+ /* SEEK */
+ xf_emit(ctx, 2, 0);
+ /* SEEK */
+ xf_emit(ctx, 6*2, 0);
+ xf_emit(ctx, 2, 0);
+ /* SEEK */
+ xf_emit(ctx, 2, 0);
+ /* SEEK */
+ xf_emit(ctx, 6*2, 0);
+ xf_emit(ctx, 2, 0);
+ /* SEEK */
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 0x1c, 0);
+ else if (dev_priv->chipset < 0xa0)
+ xf_emit(ctx, 0x1e, 0);
+ else
+ xf_emit(ctx, 0x22, 0);
+ /* SEEK */
+ xf_emit(ctx, 0x15, 0);
+}
+
+static void
nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx)
{
- /* m2mf state */
+ /* Strand 0, right after dispatch */
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ int smallm2mf = 0;
+ if (dev_priv->chipset < 0x92 || dev_priv->chipset == 0x98)
+ smallm2mf = 1;
+ /* SEEK */
xf_emit (ctx, 1, 0); /* DMA_NOTIFY instance >> 4 */
xf_emit (ctx, 1, 0); /* DMA_BUFFER_IN instance >> 4 */
xf_emit (ctx, 1, 0); /* DMA_BUFFER_OUT instance >> 4 */
@@ -1319,427 +1414,975 @@ nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx)
xf_emit (ctx, 1, 0); /* TILING_POSITION_OUT */
xf_emit (ctx, 1, 0); /* OFFSET_IN_HIGH */
xf_emit (ctx, 1, 0); /* OFFSET_OUT_HIGH */
+ /* SEEK */
+ if (smallm2mf)
+ xf_emit(ctx, 0x40, 0); /* 20 * ffffffff, 3ffff */
+ else
+ xf_emit(ctx, 0x100, 0); /* 80 * ffffffff, 3ffff */
+ xf_emit(ctx, 4, 0); /* 1f/7f, 0, 1f/7f, 0 [1f for smallm2mf, 7f otherwise] */
+ /* SEEK */
+ if (smallm2mf)
+ xf_emit(ctx, 0x400, 0); /* ffffffff */
+ else
+ xf_emit(ctx, 0x800, 0); /* ffffffff */
+ xf_emit(ctx, 4, 0); /* ff/1ff, 0, 0, 0 [ff for smallm2mf, 1ff otherwise] */
+ /* SEEK */
+ xf_emit(ctx, 0x40, 0); /* 20 * bits ffffffff, 3ffff */
+ xf_emit(ctx, 0x6, 0); /* 1f, 0, 1f, 0, 1f, 0 */
}
static void
-nv50_graph_construct_gene_unk1(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
- /* end of area 2 on pre-NVA0, area 1 on NVAx */
- xf_emit(ctx, 2, 4);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x80);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 0x80c14);
- xf_emit(ctx, 1, 0);
- if (dev_priv->chipset == 0x50)
- xf_emit(ctx, 1, 0x3ff);
- else
- xf_emit(ctx, 1, 0x7ff);
+ xf_emit(ctx, 2, 0); /* RO */
+ xf_emit(ctx, 0x800, 0); /* ffffffff */
switch (dev_priv->chipset) {
case 0x50:
- case 0x86:
- case 0x98:
- case 0xaa:
- case 0xac:
- xf_emit(ctx, 0x542, 0);
+ case 0x92:
+ case 0xa0:
+ xf_emit(ctx, 0x2b, 0);
break;
case 0x84:
- case 0x92:
+ xf_emit(ctx, 0x29, 0);
+ break;
case 0x94:
case 0x96:
- xf_emit(ctx, 0x942, 0);
- break;
- case 0xa0:
case 0xa3:
- xf_emit(ctx, 0x2042, 0);
+ xf_emit(ctx, 0x27, 0);
break;
+ case 0x86:
+ case 0x98:
case 0xa5:
case 0xa8:
- xf_emit(ctx, 0x842, 0);
+ case 0xaa:
+ case 0xac:
+ case 0xaf:
+ xf_emit(ctx, 0x25, 0);
break;
}
- xf_emit(ctx, 2, 4);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x80);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x27);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x26);
- xf_emit(ctx, 3, 0);
+ /* CB bindings, 0x80 of them. first word is address >> 8, second is
+ * size >> 4 | valid << 24 */
+ xf_emit(ctx, 0x100, 0); /* ffffffff CB_DEF */
+ xf_emit(ctx, 1, 0); /* 0000007f CB_ADDR_BUFFER */
+ xf_emit(ctx, 1, 0); /* 0 */
+ xf_emit(ctx, 0x30, 0); /* ff SET_PROGRAM_CB */
+ xf_emit(ctx, 1, 0); /* 3f last SET_PROGRAM_CB */
+ xf_emit(ctx, 4, 0); /* RO */
+ xf_emit(ctx, 0x100, 0); /* ffffffff */
+ xf_emit(ctx, 8, 0); /* 1f, 0, 0, ... */
+ xf_emit(ctx, 8, 0); /* ffffffff */
+ xf_emit(ctx, 4, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 3 */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_CODE_CB */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_TIC */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_TSC */
+ xf_emit(ctx, 1, 0); /* 00000001 LINKED_TSC */
+ xf_emit(ctx, 1, 0); /* 000000ff TIC_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff TIC_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0x3fffff); /* 003fffff TIC_LIMIT */
+ xf_emit(ctx, 1, 0); /* 000000ff TSC_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff TSC_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0x1fff); /* 000fffff TSC_LIMIT */
+ xf_emit(ctx, 1, 0); /* 000000ff VP_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff VP_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0); /* 00ffffff VP_START_ID */
+ xf_emit(ctx, 1, 0); /* 000000ff CB_DEF_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff CB_DEF_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0); /* 000000ff GP_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff GP_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0); /* 00ffffff GP_START_ID */
+ xf_emit(ctx, 1, 0); /* 000000ff FP_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff FP_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0); /* 00ffffff FP_START_ID */
}
static void
-nv50_graph_construct_gene_unk10(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx)
{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ int i;
/* end of area 2 on pre-NVA0, area 1 on NVAx */
- xf_emit(ctx, 0x10, 0x04000000);
- xf_emit(ctx, 0x24, 0);
- xf_emit(ctx, 2, 0x04e3bfdf);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 0x1fe21);
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */
+ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
+ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 1, 0x3ff);
+ else
+ xf_emit(ctx, 1, 0x7ff); /* 000007ff */
+ xf_emit(ctx, 1, 0); /* 111/113 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ for (i = 0; i < 8; i++) {
+ switch (dev_priv->chipset) {
+ case 0x50:
+ case 0x86:
+ case 0x98:
+ case 0xaa:
+ case 0xac:
+ xf_emit(ctx, 0xa0, 0); /* ffffffff */
+ break;
+ case 0x84:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ xf_emit(ctx, 0x120, 0);
+ break;
+ case 0xa5:
+ case 0xa8:
+ xf_emit(ctx, 0x100, 0); /* ffffffff */
+ break;
+ case 0xa0:
+ case 0xa3:
+ case 0xaf:
+ xf_emit(ctx, 0x400, 0); /* ffffffff */
+ break;
+ }
+ xf_emit(ctx, 4, 0); /* 3f, 0, 0, 0 */
+ xf_emit(ctx, 4, 0); /* ffffffff */
+ }
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_TEMP */
+ xf_emit(ctx, 1, 1); /* 00000001 RASTERIZE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 0x27); /* 000000ff UNK0FD4 */
+ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
+ xf_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+}
+
+static void
+nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ /* end of area 2 on pre-NVA0, area 1 on NVAx */
+ xf_emit(ctx, 1, 0); /* 00000001 VIEWPORT_CLIP_RECTS_EN */
+ xf_emit(ctx, 1, 0); /* 00000003 VIEWPORT_CLIP_MODE */
+ xf_emit(ctx, 0x10, 0x04000000); /* 07ffffff VIEWPORT_CLIP_HORIZ*8, VIEWPORT_CLIP_VERT*8 */
+ xf_emit(ctx, 1, 0); /* 00000001 POLYGON_STIPPLE_ENABLE */
+ xf_emit(ctx, 0x20, 0); /* ffffffff POLYGON_STIPPLE */
+ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0D64 */
+ xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0DF4 */
+ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0x1fe21); /* 0001ffff tesla UNK0FAC */
+ if (dev_priv->chipset >= 0xa0)
+ xf_emit(ctx, 1, 0x0fac6881);
+ if (IS_NVA3F(dev_priv->chipset)) {
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 3, 0);
+ }
}
static void
-nv50_graph_construct_gene_unk2(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
/* middle of area 2 on pre-NVA0, beginning of area 2 on NVA0, area 7 on >NVA0 */
if (dev_priv->chipset != 0x50) {
- xf_emit(ctx, 5, 0);
- xf_emit(ctx, 1, 0x80c14);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 0x804);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 2, 4);
- xf_emit(ctx, 1, 0x8100c12);
+ xf_emit(ctx, 5, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ xf_emit(ctx, 1, 0x804); /* 00000fff SEMANTIC_CLIP */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 2, 4); /* 7f, ff */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
}
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 2, 4);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x10);
- if (dev_priv->chipset == 0x50)
- xf_emit(ctx, 3, 0);
- else
- xf_emit(ctx, 4, 0);
- xf_emit(ctx, 1, 0x804);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0x1a);
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 1, 0); /* 000000ff VP_CLIP_DISTANCE_ENABLE */
if (dev_priv->chipset != 0x50)
- xf_emit(ctx, 1, 0x7f);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0x80c14);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x8100c12);
- xf_emit(ctx, 2, 4);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x10);
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0x8100c12);
- xf_emit(ctx, 6, 0);
- if (dev_priv->chipset == 0x50)
- xf_emit(ctx, 1, 0x3ff);
- else
- xf_emit(ctx, 1, 0x7ff);
- xf_emit(ctx, 1, 0x80c14);
- xf_emit(ctx, 0x38, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 0x10);
- xf_emit(ctx, 0x38, 0);
- xf_emit(ctx, 2, 0x88);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 0x16, 0);
- xf_emit(ctx, 1, 0x26);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 0x3f800000);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 4, 0);
- else
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 0x1a);
- xf_emit(ctx, 1, 0x10);
+ xf_emit(ctx, 1, 0); /* 3ff */
+ xf_emit(ctx, 1, 0); /* 000000ff tesla UNK1940 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0D7C */
+ xf_emit(ctx, 1, 0x804); /* 00000fff SEMANTIC_CLIP */
+ xf_emit(ctx, 1, 1); /* 00000001 VIEWPORT_TRANSFORM_EN */
+ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
if (dev_priv->chipset != 0x50)
- xf_emit(ctx, 0x28, 0);
+ xf_emit(ctx, 1, 0x7f); /* 000000ff tesla UNK0FFC */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 1); /* 00000001 SHADE_MODEL */
+ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0D7C */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0F8C */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 1); /* 00000001 VIEWPORT_TRANSFORM_EN */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 4, 0); /* ffffffff NOPERSPECTIVE_BITMAP */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 0); /* 0000000f */
+ if (dev_priv->chipset == 0x50)
+ xf_emit(ctx, 1, 0x3ff); /* 000003ff tesla UNK0D68 */
else
- xf_emit(ctx, 0x25, 0);
- xf_emit(ctx, 1, 0x52);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x26);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 2, 4);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x1a);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 0x00ffff00);
- xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x7ff); /* 000007ff tesla UNK0D68 */
+ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
+ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */
+ xf_emit(ctx, 0x30, 0); /* ffffffff VIEWPORT_SCALE: X0, Y0, Z0, X1, Y1, ... */
+ xf_emit(ctx, 3, 0); /* f, 0, 0 */
+ xf_emit(ctx, 3, 0); /* ffffffff last VIEWPORT_SCALE? */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 1); /* 00000001 VIEWPORT_TRANSFORM_EN */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1924 */
+ xf_emit(ctx, 1, 0x10); /* 000000ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 0x30, 0); /* ffffffff VIEWPORT_TRANSLATE */
+ xf_emit(ctx, 3, 0); /* f, 0, 0 */
+ xf_emit(ctx, 3, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 2, 0x88); /* 000001ff tesla UNK19D8 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1924 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 4); /* 0000000f CULL_MODE */
+ xf_emit(ctx, 2, 0); /* 07ffffff SCREEN_SCISSOR */
+ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */
+ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
+ xf_emit(ctx, 0x10, 0); /* 00000001 SCISSOR_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
+ xf_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 0); /* 0000000f */
+ xf_emit(ctx, 1, 0x3f800000); /* ffffffff LINE_WIDTH */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
+ xf_emit(ctx, 1, 0x10); /* 000000ff VIEW_VOLUME_CLIP_CTRL */
+ if (dev_priv->chipset != 0x50) {
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ }
+ xf_emit(ctx, 0x20, 0); /* 10xbits ffffffff, 3fffff. SCISSOR_* */
+ xf_emit(ctx, 1, 0); /* f */
+ xf_emit(ctx, 1, 0); /* 0? */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 003fffff */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 0x52); /* 000001ff SEMANTIC_PTSZ */
+ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
+ xf_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
+ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */
+ xf_emit(ctx, 1, 0); /* 0000000f */
}
static void
-nv50_graph_construct_gene_unk3(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
- /* end of area 0 on pre-NVA0, beginning of area 6 on NVAx */
- xf_emit(ctx, 1, 0x3f);
- xf_emit(ctx, 0xa, 0);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 2, 0x04000000);
- xf_emit(ctx, 8, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 4);
- if (dev_priv->chipset == 0x50)
- xf_emit(ctx, 0x10, 0);
- else
- xf_emit(ctx, 0x11, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0x1001);
- xf_emit(ctx, 4, 0xffff);
- xf_emit(ctx, 0x20, 0);
- xf_emit(ctx, 0x10, 0x3f800000);
- xf_emit(ctx, 1, 0x10);
- if (dev_priv->chipset == 0x50)
- xf_emit(ctx, 1, 0);
- else
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 3);
- xf_emit(ctx, 2, 0);
+ /* end of strand 0 on pre-NVA0, beginning of strand 6 on NVAx */
+ /* SEEK */
+ xf_emit(ctx, 1, 0x3f); /* 0000003f UNK1590 */
+ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_REF */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */
+ xf_emit(ctx, 2, 0x04000000); /* 07ffffff tesla UNK0D6C */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 0); /* 00000001 CLIPID_ENABLE */
+ xf_emit(ctx, 2, 0); /* ffffffff DEPTH_BOUNDS */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 4); /* 0000000f CULL_MODE */
+ xf_emit(ctx, 1, 0); /* 0000ffff */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK0FB0 */
+ xf_emit(ctx, 1, 0); /* 00000001 POLYGON_STIPPLE_ENABLE */
+ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
+ xf_emit(ctx, 1, 0); /* 000000ff CLEAR_STENCIL */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_REF */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ if (dev_priv->chipset != 0x50)
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1108 */
+ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0x1001); /* 00001fff ZETA_ARRAY_MODE */
+ /* SEEK */
+ xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */
+ xf_emit(ctx, 0x10, 0); /* 00000001 SCISSOR_ENABLE */
+ xf_emit(ctx, 0x10, 0); /* ffffffff DEPTH_RANGE_NEAR */
+ xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */
+ xf_emit(ctx, 1, 0x10); /* 7f/ff/3ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 1, 0); /* 00000001 VIEWPORT_CLIP_RECTS_EN */
+ xf_emit(ctx, 1, 3); /* 00000003 FP_CTRL_UNK196C */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1968 */
+ if (dev_priv->chipset != 0x50)
+ xf_emit(ctx, 1, 0); /* 0fffffff tesla UNK1104 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK151C */
}
static void
-nv50_graph_construct_gene_unk4(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_clipid(struct nouveau_grctx *ctx)
{
- /* middle of area 0 on pre-NVA0, middle of area 6 on NVAx */
- xf_emit(ctx, 2, 0x04000000);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x80);
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 0x80);
- xf_emit(ctx, 1, 0);
+ /* middle of strand 0 on pre-NVA0 [after 24xx], middle of area 6 on NVAx */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 00000007 UNK0FB4 */
+ /* SEEK */
+ xf_emit(ctx, 4, 0); /* 07ffffff CLIPID_REGION_HORIZ */
+ xf_emit(ctx, 4, 0); /* 07ffffff CLIPID_REGION_VERT */
+ xf_emit(ctx, 2, 0); /* 07ffffff SCREEN_SCISSOR */
+ xf_emit(ctx, 2, 0x04000000); /* 07ffffff UNK1508 */
+ xf_emit(ctx, 1, 0); /* 00000001 CLIPID_ENABLE */
+ xf_emit(ctx, 1, 0x80); /* 00003fff CLIPID_WIDTH */
+ xf_emit(ctx, 1, 0); /* 000000ff CLIPID_ID */
+ xf_emit(ctx, 1, 0); /* 000000ff CLIPID_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff CLIPID_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0x80); /* 00003fff CLIPID_HEIGHT */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_CLIPID */
}
static void
-nv50_graph_construct_gene_unk5(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
- /* middle of area 0 on pre-NVA0 [after m2mf], end of area 2 on NVAx */
- xf_emit(ctx, 2, 4);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 0x1c4d, 0);
+ int i;
+ /* middle of strand 0 on pre-NVA0 [after m2mf], end of strand 2 on NVAx */
+ /* SEEK */
+ xf_emit(ctx, 0x33, 0);
+ /* SEEK */
+ xf_emit(ctx, 2, 0);
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ /* SEEK */
+ if (IS_NVA3F(dev_priv->chipset)) {
+ xf_emit(ctx, 4, 0); /* RO */
+ xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+ xf_emit(ctx, 1, 0); /* 1ff */
+ xf_emit(ctx, 8, 0); /* 0? */
+ xf_emit(ctx, 9, 0); /* ffffffff, 7ff */
+
+ xf_emit(ctx, 4, 0); /* RO */
+ xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+ xf_emit(ctx, 1, 0); /* 1ff */
+ xf_emit(ctx, 8, 0); /* 0? */
+ xf_emit(ctx, 9, 0); /* ffffffff, 7ff */
+ }
else
- xf_emit(ctx, 0x1c4b, 0);
- xf_emit(ctx, 2, 4);
- xf_emit(ctx, 1, 0x8100c12);
+ {
+ xf_emit(ctx, 0xc, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+ xf_emit(ctx, 1, 0); /* 1ff */
+ xf_emit(ctx, 8, 0); /* 0? */
+
+ /* SEEK */
+ xf_emit(ctx, 0xc, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+ xf_emit(ctx, 1, 0); /* 1ff */
+ xf_emit(ctx, 8, 0); /* 0? */
+ }
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
if (dev_priv->chipset != 0x50)
- xf_emit(ctx, 1, 3);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x8100c12);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x80c14);
- xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */
+ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
+ xf_emit(ctx, 1, 1); /* 00000001 */
+ /* SEEK */
if (dev_priv->chipset >= 0xa0)
- xf_emit(ctx, 2, 4);
- xf_emit(ctx, 1, 0x80c14);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 0x8100c12);
- xf_emit(ctx, 1, 0x27);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 0x3c1, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 0x16, 0);
- xf_emit(ctx, 1, 0x8100c12);
- xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 2, 4); /* 000000ff */
+ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
+ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_ENABLE */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 1, 0x27); /* 000000ff SEMANTIC_PRIM_ID */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000000f */
+ xf_emit(ctx, 1, 1); /* 00000001 */
+ for (i = 0; i < 10; i++) {
+ /* SEEK */
+ xf_emit(ctx, 0x40, 0); /* ffffffff */
+ xf_emit(ctx, 0x10, 0); /* 3, 0, 0.... */
+ xf_emit(ctx, 0x10, 0); /* ffffffff */
+ }
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_CTRL */
+ xf_emit(ctx, 1, 1); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 4, 0); /* ffffffff NOPERSPECTIVE_BITMAP */
+ xf_emit(ctx, 0x10, 0); /* 00ffffff POINT_COORD_REPLACE_MAP */
+ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ if (dev_priv->chipset != 0x50)
+ xf_emit(ctx, 1, 0); /* 000003ff */
}
static void
-nv50_graph_construct_gene_unk6(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
- /* beginning of area 1 on pre-NVA0 [after m2mf], area 3 on NVAx */
- xf_emit(ctx, 4, 0);
- xf_emit(ctx, 1, 0xf);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 8, 0);
- else
- xf_emit(ctx, 4, 0);
- xf_emit(ctx, 1, 0x20);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 0x11, 0);
+ int acnt = 0x10, rep, i;
+ /* beginning of strand 1 on pre-NVA0, strand 3 on NVAx */
+ if (IS_NVA3F(dev_priv->chipset))
+ acnt = 0x20;
+ /* SEEK */
+ if (dev_priv->chipset >= 0xa0) {
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK13A4 */
+ xf_emit(ctx, 1, 1); /* 00000fff tesla UNK1318 */
+ }
+ xf_emit(ctx, 1, 0); /* ffffffff VERTEX_BUFFER_FIRST */
+ xf_emit(ctx, 1, 0); /* 00000001 PRIMITIVE_RESTART_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK0DE8 */
+ xf_emit(ctx, 1, 0); /* ffffffff PRIMITIVE_RESTART_INDEX */
+ xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, acnt/8, 0); /* ffffffff VTX_ATR_MASK_UNK0DD0 */
+ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */
+ xf_emit(ctx, 1, 0x20); /* 0000ffff tesla UNK129C */
+ xf_emit(ctx, 1, 0); /* 000000ff turing UNK370??? */
+ xf_emit(ctx, 1, 0); /* 0000ffff turing USER_PARAM_COUNT */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ /* SEEK */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 0xb, 0); /* RO */
else if (dev_priv->chipset >= 0xa0)
- xf_emit(ctx, 0xf, 0);
+ xf_emit(ctx, 0x9, 0); /* RO */
else
- xf_emit(ctx, 0xe, 0);
- xf_emit(ctx, 1, 0x1a);
- xf_emit(ctx, 0xd, 0);
- xf_emit(ctx, 2, 4);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 8);
- xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 0x8, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 00000001 EDGE_FLAG */
+ xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
+ /* SEEK */
+ xf_emit(ctx, 0xc, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 7f/ff */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_REG_ALLOC_RESULT */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */
+ xf_emit(ctx, 1, 4); /* 000001ff UNK1A28 */
+ xf_emit(ctx, 1, 8); /* 000001ff UNK0DF0 */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
if (dev_priv->chipset == 0x50)
- xf_emit(ctx, 1, 0x3ff);
+ xf_emit(ctx, 1, 0x3ff); /* 3ff tesla UNK0D68 */
else
- xf_emit(ctx, 1, 0x7ff);
+ xf_emit(ctx, 1, 0x7ff); /* 7ff tesla UNK0D68 */
if (dev_priv->chipset == 0xa8)
- xf_emit(ctx, 1, 0x1e00);
- xf_emit(ctx, 0xc, 0);
- xf_emit(ctx, 1, 0xf);
- if (dev_priv->chipset == 0x50)
- xf_emit(ctx, 0x125, 0);
- else if (dev_priv->chipset < 0xa0)
- xf_emit(ctx, 0x126, 0);
- else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa)
- xf_emit(ctx, 0x124, 0);
+ xf_emit(ctx, 1, 0x1e00); /* 7fff */
+ /* SEEK */
+ xf_emit(ctx, 0xc, 0); /* RO or close */
+ /* SEEK */
+ xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */
+ if (dev_priv->chipset > 0x50 && dev_priv->chipset < 0xa0)
+ xf_emit(ctx, 2, 0); /* ffffffff */
else
- xf_emit(ctx, 0x1f7, 0);
- xf_emit(ctx, 1, 0xf);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0FD8 */
+ /* SEEK */
+ if (IS_NVA3F(dev_priv->chipset)) {
+ xf_emit(ctx, 0x10, 0); /* 0? */
+ xf_emit(ctx, 2, 0); /* weird... */
+ xf_emit(ctx, 2, 0); /* RO */
+ } else {
+ xf_emit(ctx, 8, 0); /* 0? */
+ xf_emit(ctx, 1, 0); /* weird... */
+ xf_emit(ctx, 2, 0); /* RO */
+ }
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* ffffffff VB_ELEMENT_BASE */
+ xf_emit(ctx, 1, 0); /* ffffffff UNK1438 */
+ xf_emit(ctx, acnt, 0); /* 1 tesla UNK1000 */
+ if (dev_priv->chipset >= 0xa0)
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1118? */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_UNK90C */
+ xf_emit(ctx, 1, 0); /* f/1f */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_UNK90C */
+ xf_emit(ctx, 1, 0); /* f/1f */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* RO */
+ xf_emit(ctx, 2, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK111C? */
+ xf_emit(ctx, 1, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 000000ff UNK15F4_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff UNK15F4_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0); /* 000000ff UNK0F84_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff UNK0F84_ADDRESS_LOW */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* 00003fff VERTEX_ARRAY_ATTRIB_OFFSET */
+ xf_emit(ctx, 3, 0); /* f/1f */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* 00000fff VERTEX_ARRAY_STRIDE */
+ xf_emit(ctx, 3, 0); /* f/1f */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_LOW */
+ xf_emit(ctx, 3, 0); /* f/1f */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* 000000ff VERTEX_ARRAY_HIGH */
+ xf_emit(ctx, 3, 0); /* f/1f */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_LIMIT_LOW */
+ xf_emit(ctx, 3, 0); /* f/1f */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* 000000ff VERTEX_LIMIT_HIGH */
+ xf_emit(ctx, 3, 0); /* f/1f */
+ /* SEEK */
+ if (IS_NVA3F(dev_priv->chipset)) {
+ xf_emit(ctx, acnt, 0); /* f */
+ xf_emit(ctx, 3, 0); /* f/1f */
+ }
+ /* SEEK */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 2, 0); /* RO */
+ else
+ xf_emit(ctx, 5, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* ffff DMA_VTXBUF */
+ /* SEEK */
+ if (dev_priv->chipset < 0xa0) {
+ xf_emit(ctx, 0x41, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 0x11, 0); /* RO */
+ } else if (!IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 0x50, 0); /* RO */
else
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 0xa1, 0);
+ xf_emit(ctx, 0x58, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, 1, 1); /* 1 UNK0DEC */
+ /* SEEK */
+ xf_emit(ctx, acnt*4, 0); /* ffffffff VTX_ATTR */
+ xf_emit(ctx, 4, 0); /* f/1f, 0, 0, 0 */
+ /* SEEK */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 0x1d, 0); /* RO */
else
- xf_emit(ctx, 0x5a, 0);
- xf_emit(ctx, 1, 0xf);
+ xf_emit(ctx, 0x16, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */
+ /* SEEK */
if (dev_priv->chipset < 0xa0)
- xf_emit(ctx, 0x834, 0);
- else if (dev_priv->chipset == 0xa0)
- xf_emit(ctx, 0x1873, 0);
- else if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 0x8ba, 0);
+ xf_emit(ctx, 8, 0); /* RO */
+ else if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 0xc, 0); /* RO */
+ else
+ xf_emit(ctx, 7, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 0xa, 0); /* RO */
+ if (dev_priv->chipset == 0xa0)
+ rep = 0xc;
+ else
+ rep = 4;
+ for (i = 0; i < rep; i++) {
+ /* SEEK */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 0x20, 0); /* ffffffff */
+ xf_emit(ctx, 0x200, 0); /* ffffffff */
+ xf_emit(ctx, 4, 0); /* 7f/ff, 0, 0, 0 */
+ xf_emit(ctx, 4, 0); /* ffffffff */
+ }
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 113/111 */
+ xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, acnt/8, 0); /* ffffffff VTX_ATTR_MASK_UNK0DD0 */
+ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ /* SEEK */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 7, 0); /* weird... */
else
- xf_emit(ctx, 0x833, 0);
- xf_emit(ctx, 1, 0xf);
- xf_emit(ctx, 0xf, 0);
+ xf_emit(ctx, 5, 0); /* weird... */
}
static void
-nv50_graph_construct_gene_unk7(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
- /* middle of area 1 on pre-NVA0 [after m2mf], middle of area 6 on NVAx */
- xf_emit(ctx, 2, 0);
- if (dev_priv->chipset == 0x50)
- xf_emit(ctx, 2, 1);
- else
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 2, 0x100);
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 8);
- xf_emit(ctx, 5, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 3, 1);
- xf_emit(ctx, 1, 0xcf);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 6, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 3, 1);
- xf_emit(ctx, 4, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0x15);
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 0x4444480);
- xf_emit(ctx, 0x37, 0);
+ /* middle of strand 1 on pre-NVA0 [after vfetch], middle of strand 6 on NVAx */
+ /* SEEK */
+ xf_emit(ctx, 2, 0); /* 0001ffff CLIP_X, CLIP_Y */
+ xf_emit(ctx, 2, 0); /* 0000ffff CLIP_W, CLIP_H */
+ xf_emit(ctx, 1, 0); /* 00000001 CLIP_ENABLE */
+ if (dev_priv->chipset < 0xa0) {
+ /* this is useless on everything but the original NV50,
+ * guess they forgot to nuke it. Or just didn't bother. */
+ xf_emit(ctx, 2, 0); /* 0000ffff IFC_CLIP_X, Y */
+ xf_emit(ctx, 2, 1); /* 0000ffff IFC_CLIP_W, H */
+ xf_emit(ctx, 1, 0); /* 00000001 IFC_CLIP_ENABLE */
+ }
+ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
+ xf_emit(ctx, 1, 0x100); /* 0001ffff DST_WIDTH */
+ xf_emit(ctx, 1, 0x100); /* 0001ffff DST_HEIGHT */
+ xf_emit(ctx, 1, 0x11); /* 3f[NV50]/7f[NV84+] DST_FORMAT */
+ xf_emit(ctx, 1, 0); /* 0001ffff DRAW_POINT_X */
+ xf_emit(ctx, 1, 8); /* 0000000f DRAW_UNK58C */
+ xf_emit(ctx, 1, 0); /* 000fffff SIFC_DST_X_FRACT */
+ xf_emit(ctx, 1, 0); /* 0001ffff SIFC_DST_X_INT */
+ xf_emit(ctx, 1, 0); /* 000fffff SIFC_DST_Y_FRACT */
+ xf_emit(ctx, 1, 0); /* 0001ffff SIFC_DST_Y_INT */
+ xf_emit(ctx, 1, 0); /* 000fffff SIFC_DX_DU_FRACT */
+ xf_emit(ctx, 1, 1); /* 0001ffff SIFC_DX_DU_INT */
+ xf_emit(ctx, 1, 0); /* 000fffff SIFC_DY_DV_FRACT */
+ xf_emit(ctx, 1, 1); /* 0001ffff SIFC_DY_DV_INT */
+ xf_emit(ctx, 1, 1); /* 0000ffff SIFC_WIDTH */
+ xf_emit(ctx, 1, 1); /* 0000ffff SIFC_HEIGHT */
+ xf_emit(ctx, 1, 0xcf); /* 000000ff SIFC_FORMAT */
+ xf_emit(ctx, 1, 2); /* 00000003 SIFC_BITMAP_UNK808 */
+ xf_emit(ctx, 1, 0); /* 00000003 SIFC_BITMAP_LINE_PACK_MODE */
+ xf_emit(ctx, 1, 0); /* 00000001 SIFC_BITMAP_LSB_FIRST */
+ xf_emit(ctx, 1, 0); /* 00000001 SIFC_BITMAP_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000ffff BLIT_DST_X */
+ xf_emit(ctx, 1, 0); /* 0000ffff BLIT_DST_Y */
+ xf_emit(ctx, 1, 0); /* 000fffff BLIT_DU_DX_FRACT */
+ xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DU_DX_INT */
+ xf_emit(ctx, 1, 0); /* 000fffff BLIT_DV_DY_FRACT */
+ xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DV_DY_INT */
+ xf_emit(ctx, 1, 1); /* 0000ffff BLIT_DST_W */
+ xf_emit(ctx, 1, 1); /* 0000ffff BLIT_DST_H */
+ xf_emit(ctx, 1, 0); /* 000fffff BLIT_SRC_X_FRACT */
+ xf_emit(ctx, 1, 0); /* 0001ffff BLIT_SRC_X_INT */
+ xf_emit(ctx, 1, 0); /* 000fffff BLIT_SRC_Y_FRACT */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK888 */
+ xf_emit(ctx, 1, 4); /* 0000003f UNK884 */
+ xf_emit(ctx, 1, 0); /* 00000007 UNK880 */
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK0FB8 */
+ xf_emit(ctx, 1, 0x15); /* 000000ff tesla UNK128C */
+ xf_emit(ctx, 2, 0); /* 00000007, ffff0ff3 */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK260 */
+ xf_emit(ctx, 1, 0x4444480); /* 1fffffff UNK870 */
+ /* SEEK */
+ xf_emit(ctx, 0x10, 0);
+ /* SEEK */
+ xf_emit(ctx, 0x27, 0);
}
static void
-nv50_graph_construct_gene_unk8(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx)
{
- /* middle of area 1 on pre-NVA0 [after m2mf], middle of area 0 on NVAx */
- xf_emit(ctx, 4, 0);
- xf_emit(ctx, 1, 0x8100c12);
- xf_emit(ctx, 4, 0);
- xf_emit(ctx, 1, 0x100);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 0x10001);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x10001);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0x10001);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 2);
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ /* middle of strand 1 on pre-NVA0 [after eng2d], middle of strand 0 on NVAx */
+ /* SEEK */
+ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY... what is it doing here??? */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1924 */
+ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* ffffffff turing UNK364 */
+ xf_emit(ctx, 1, 0); /* 0000000f turing UNK36C */
+ xf_emit(ctx, 1, 0); /* 0000ffff USER_PARAM_COUNT */
+ xf_emit(ctx, 1, 0x100); /* 00ffffff turing UNK384 */
+ xf_emit(ctx, 1, 0); /* 0000000f turing UNK2A0 */
+ xf_emit(ctx, 1, 0); /* 0000ffff GRIDID */
+ xf_emit(ctx, 1, 0x10001); /* ffffffff GRIDDIM_XY */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0x10001); /* ffffffff BLOCKDIM_XY */
+ xf_emit(ctx, 1, 1); /* 0000ffff BLOCKDIM_Z */
+ xf_emit(ctx, 1, 0x10001); /* 00ffffff BLOCK_ALLOC */
+ xf_emit(ctx, 1, 1); /* 00000001 LANES32 */
+ xf_emit(ctx, 1, 4); /* 000000ff FP_REG_ALLOC_TEMP */
+ xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */
+ /* SEEK */
+ xf_emit(ctx, 0x40, 0); /* ffffffff USER_PARAM */
+ switch (dev_priv->chipset) {
+ case 0x50:
+ case 0x92:
+ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
+ xf_emit(ctx, 0x80, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 0x10*2, 0); /* ffffffff, 1f */
+ break;
+ case 0x84:
+ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
+ xf_emit(ctx, 0x60, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 0xc*2, 0); /* ffffffff, 1f */
+ break;
+ case 0x94:
+ case 0x96:
+ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
+ xf_emit(ctx, 0x40, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 8*2, 0); /* ffffffff, 1f */
+ break;
+ case 0x86:
+ case 0x98:
+ xf_emit(ctx, 4, 0); /* f, 0, 0, 0 */
+ xf_emit(ctx, 0x10, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 2*2, 0); /* ffffffff, 1f */
+ break;
+ case 0xa0:
+ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
+ xf_emit(ctx, 0xf0, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 0x1e*2, 0); /* ffffffff, 1f */
+ break;
+ case 0xa3:
+ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
+ xf_emit(ctx, 0x60, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 0xc*2, 0); /* ffffffff, 1f */
+ break;
+ case 0xa5:
+ case 0xaf:
+ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
+ xf_emit(ctx, 0x30, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 6*2, 0); /* ffffffff, 1f */
+ break;
+ case 0xaa:
+ xf_emit(ctx, 0x12, 0);
+ break;
+ case 0xa8:
+ case 0xac:
+ xf_emit(ctx, 4, 0); /* f, 0, 0, 0 */
+ xf_emit(ctx, 0x10, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 2*2, 0); /* ffffffff, 1f */
+ break;
+ }
+ xf_emit(ctx, 1, 0); /* 0000000f */
+ xf_emit(ctx, 1, 0); /* 00000000 */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 0000001f */
+ xf_emit(ctx, 4, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 00000003 turing UNK35C */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 4, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 00000003 turing UNK35C */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 000000ff */
}
static void
-nv50_graph_construct_gene_unk9(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
- /* middle of area 2 on pre-NVA0 [after m2mf], end of area 0 on NVAx */
- xf_emit(ctx, 1, 0x3f800000);
- xf_emit(ctx, 6, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 0x1a);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 0x12, 0);
- xf_emit(ctx, 1, 0x00ffff00);
- xf_emit(ctx, 6, 0);
- xf_emit(ctx, 1, 0xf);
- xf_emit(ctx, 7, 0);
- xf_emit(ctx, 1, 0x0fac6881);
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 0xf, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 2, 0);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 1, 3);
+ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */
+ xf_emit(ctx, 1, 0x3f800000); /* ffffffff LINE_WIDTH */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1658 */
+ xf_emit(ctx, 1, 0); /* 00000001 POLYGON_SMOOTH_ENABLE */
+ xf_emit(ctx, 3, 0); /* 00000001 POLYGON_OFFSET_*_ENABLE */
+ xf_emit(ctx, 1, 4); /* 0000000f CULL_MODE */
+ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_ENABLE */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK165C */
+ xf_emit(ctx, 0x10, 0); /* 00000001 SCISSOR_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
+ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */
+ xf_emit(ctx, 1, 0); /* ffffffff POLYGON_OFFSET_UNITS */
+ xf_emit(ctx, 1, 0); /* ffffffff POLYGON_OFFSET_FACTOR */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1668 */
+ xf_emit(ctx, 2, 0); /* 07ffffff SCREEN_SCISSOR */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 1, 0x11); /* 0000007f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 0000007f RT_FORMAT */
+ xf_emit(ctx, 8, 0); /* 00000001 RT_HORIZ_LINEAR */
+ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 3); /* 00000003 UNK16B4 */
else if (dev_priv->chipset >= 0xa0)
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 2, 0x04000000);
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 5);
- xf_emit(ctx, 1, 0x52);
- if (dev_priv->chipset == 0x50) {
- xf_emit(ctx, 0x13, 0);
- } else {
- xf_emit(ctx, 4, 0);
- xf_emit(ctx, 1, 1);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 0x11, 0);
- else
- xf_emit(ctx, 0x10, 0);
+ xf_emit(ctx, 1, 1); /* 00000001 UNK16B4 */
+ xf_emit(ctx, 1, 0); /* 00000003 MULTISAMPLE_CTRL */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0F90 */
+ xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */
+ xf_emit(ctx, 2, 0x04000000); /* 07ffffff tesla UNK0D6C */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
+ xf_emit(ctx, 1, 5); /* 0000000f UNK1408 */
+ xf_emit(ctx, 1, 0x52); /* 000001ff SEMANTIC_PTSZ */
+ xf_emit(ctx, 1, 0); /* ffffffff POINT_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 00000007 tesla UNK0FB4 */
+ if (dev_priv->chipset != 0x50) {
+ xf_emit(ctx, 1, 0); /* 3ff */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK1110 */
}
- xf_emit(ctx, 0x10, 0x3f800000);
- xf_emit(ctx, 1, 0x10);
- xf_emit(ctx, 0x26, 0);
- xf_emit(ctx, 1, 0x8100c12);
- xf_emit(ctx, 1, 5);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 4, 0xffff);
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1928 */
+ xf_emit(ctx, 0x10, 0); /* ffffffff DEPTH_RANGE_NEAR */
+ xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */
+ xf_emit(ctx, 1, 0x10); /* 000000ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 0x20, 0); /* 07ffffff VIEWPORT_HORIZ, then VIEWPORT_VERT. (W&0x3fff)<<13 | (X&0x1fff). */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK187C */
+ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 1, 5); /* 0000000f tesla UNK1220 */
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 000000ff tesla UNK1A20 */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */
+ xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */
if (dev_priv->chipset != 0x50)
- xf_emit(ctx, 1, 3);
+ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */
if (dev_priv->chipset < 0xa0)
- xf_emit(ctx, 0x1f, 0);
- else if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 0xc, 0);
- else
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 0x00ffff00);
- xf_emit(ctx, 1, 0x1a);
+ xf_emit(ctx, 0x1c, 0); /* RO */
+ else if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 0x9, 0);
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
+ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */
+ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
+ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
if (dev_priv->chipset != 0x50) {
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 3);
+ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */
+ xf_emit(ctx, 1, 0); /* 3ff */
}
+ /* XXX: the following block could belong either to unk1cxx, or
+ * to STRMOUT. Rather hard to tell. */
if (dev_priv->chipset < 0xa0)
- xf_emit(ctx, 0x26, 0);
+ xf_emit(ctx, 0x25, 0);
else
- xf_emit(ctx, 0x3c, 0);
- xf_emit(ctx, 1, 0x102);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 4, 4);
- if (dev_priv->chipset >= 0xa0)
- xf_emit(ctx, 8, 0);
- xf_emit(ctx, 2, 4);
- xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 0x3b, 0);
+}
+
+static void
+nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ xf_emit(ctx, 1, 0x102); /* 0000ffff STRMOUT_BUFFER_CTRL */
+ xf_emit(ctx, 1, 0); /* ffffffff STRMOUT_PRIMITIVE_COUNT */
+ xf_emit(ctx, 4, 4); /* 000000ff STRMOUT_NUM_ATTRIBS */
+ if (dev_priv->chipset >= 0xa0) {
+ xf_emit(ctx, 4, 0); /* ffffffff UNK1A8C */
+ xf_emit(ctx, 4, 0); /* ffffffff UNK1780 */
+ }
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
if (dev_priv->chipset == 0x50)
- xf_emit(ctx, 1, 0x3ff);
+ xf_emit(ctx, 1, 0x3ff); /* 000003ff tesla UNK0D68 */
else
- xf_emit(ctx, 1, 0x7ff);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x102);
- xf_emit(ctx, 9, 0);
- xf_emit(ctx, 4, 4);
- xf_emit(ctx, 0x2c, 0);
+ xf_emit(ctx, 1, 0x7ff); /* 000007ff tesla UNK0D68 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ /* SEEK */
+ xf_emit(ctx, 1, 0x102); /* 0000ffff STRMOUT_BUFFER_CTRL */
+ xf_emit(ctx, 1, 0); /* ffffffff STRMOUT_PRIMITIVE_COUNT */
+ xf_emit(ctx, 4, 0); /* 000000ff STRMOUT_ADDRESS_HIGH */
+ xf_emit(ctx, 4, 0); /* ffffffff STRMOUT_ADDRESS_LOW */
+ xf_emit(ctx, 4, 4); /* 000000ff STRMOUT_NUM_ATTRIBS */
+ if (dev_priv->chipset >= 0xa0) {
+ xf_emit(ctx, 4, 0); /* ffffffff UNK1A8C */
+ xf_emit(ctx, 4, 0); /* ffffffff UNK1780 */
+ }
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_STRMOUT */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */
+ xf_emit(ctx, 1, 0); /* 000000ff QUERY_ADDRESS_HIGH */
+ xf_emit(ctx, 2, 0); /* ffffffff QUERY_ADDRESS_LOW QUERY_COUNTER */
+ xf_emit(ctx, 2, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ /* SEEK */
+ xf_emit(ctx, 0x20, 0); /* ffffffff STRMOUT_MAP */
+ xf_emit(ctx, 1, 0); /* 0000000f */
+ xf_emit(ctx, 1, 0); /* 00000000? */
+ xf_emit(ctx, 2, 0); /* ffffffff */
+}
+
+static void
+nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0D64 */
+ xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0DF4 */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 0x11); /* 000000ff tesla UNK1968 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+}
+
+static void
+nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx)
+{
+ struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 2, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 000000ff QUERY_ADDRESS_HIGH */
+ xf_emit(ctx, 2, 0); /* ffffffff QUERY_ADDRESS_LOW, COUNTER */
+ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 7 */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */
+ xf_emit(ctx, 1, 0); /* 000000ff QUERY_ADDRESS_HIGH */
+ xf_emit(ctx, 2, 0); /* ffffffff QUERY_ADDRESS_LOW, COUNTER */
+ xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0D64 */
+ xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0DF4 */
+ xf_emit(ctx, 1, 0); /* 00000001 eng2d UNK260 */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 0x11); /* 000000ff tesla UNK1968 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
}
static void
@@ -1749,443 +2392,709 @@ nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx)
int magic2;
if (dev_priv->chipset == 0x50) {
magic2 = 0x00003e60;
- } else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) {
+ } else if (!IS_NVA3F(dev_priv->chipset)) {
magic2 = 0x001ffe67;
} else {
magic2 = 0x00087e67;
}
- xf_emit(ctx, 8, 0);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, magic2);
- xf_emit(ctx, 4, 0);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 7, 0);
- if (dev_priv->chipset >= 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 1, 0x15);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0x10);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 4, 0);
+ xf_emit(ctx, 1, 0); /* f/7 MUTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ if (dev_priv->chipset >= 0xa0 && !IS_NVAAF(dev_priv->chipset))
+ xf_emit(ctx, 1, 0x15); /* 000000ff */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
+ xf_emit(ctx, 1, 0x10); /* 3ff/ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x92 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa0) {
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 0x400);
- xf_emit(ctx, 1, 0x300);
- xf_emit(ctx, 1, 0x1001);
+ xf_emit(ctx, 3, 0); /* ff, ffffffff, ffffffff */
+ xf_emit(ctx, 1, 4); /* 7 */
+ xf_emit(ctx, 1, 0x400); /* fffffff */
+ xf_emit(ctx, 1, 0x300); /* ffff */
+ xf_emit(ctx, 1, 0x1001); /* 1fff */
if (dev_priv->chipset != 0xa0) {
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 1, 0);
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 0); /* 0000000f UNK15C8 */
else
- xf_emit(ctx, 1, 0x15);
+ xf_emit(ctx, 1, 0x15); /* ff */
}
- xf_emit(ctx, 3, 0);
}
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 8, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0x10);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 0x13, 0);
- xf_emit(ctx, 1, 0x10);
- xf_emit(ctx, 0x10, 0);
- xf_emit(ctx, 0x10, 0x3f800000);
- xf_emit(ctx, 0x19, 0);
- xf_emit(ctx, 1, 0x10);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x3f);
- xf_emit(ctx, 6, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
+ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_REF */
+ xf_emit(ctx, 2, 0); /* ffffffff DEPTH_BOUNDS */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000000f */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0FB0 */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_REF */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
+ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 0x10, 0); /* ffffffff DEPTH_RANGE_NEAR */
+ xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_REF */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 2, 0); /* ffffffff DEPTH_BOUNDS */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 000000ff CLEAR_STENCIL */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_REF */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
+ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 0x3f); /* 0000003f UNK1590 */
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 2, 0); /* ffff0ff3, ffff */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0FB0 */
+ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK19CC */
if (dev_priv->chipset >= 0xa0) {
xf_emit(ctx, 2, 0);
xf_emit(ctx, 1, 0x1001);
xf_emit(ctx, 0xb, 0);
} else {
- xf_emit(ctx, 0xc, 0);
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
}
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 7, 0);
- xf_emit(ctx, 1, 0xf);
- xf_emit(ctx, 7, 0);
- xf_emit(ctx, 1, 0x11);
- if (dev_priv->chipset == 0x50)
- xf_emit(ctx, 4, 0);
- else
- xf_emit(ctx, 6, 0);
- xf_emit(ctx, 3, 1);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, magic2);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x0fac6881);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 0x18, 1);
- xf_emit(ctx, 8, 2);
- xf_emit(ctx, 8, 1);
- xf_emit(ctx, 8, 2);
- xf_emit(ctx, 8, 1);
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 5, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 0x16, 0);
+ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f */
+ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
+ if (dev_priv->chipset != 0x50) {
+ xf_emit(ctx, 1, 0); /* 0000000f LOGIC_OP */
+ xf_emit(ctx, 1, 0); /* 000000ff */
+ }
+ xf_emit(ctx, 1, 0); /* 00000007 OPERATION */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */
+ xf_emit(ctx, 2, 1); /* 00000007 BLEND_EQUATION_RGB, ALPHA */
+ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ if (IS_NVA3F(dev_priv->chipset)) {
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK12E4 */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_RGB */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1140 */
+ xf_emit(ctx, 2, 0); /* 00000001 */
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, 0); /* 0000000f */
+ xf_emit(ctx, 1, 0); /* 00000003 */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 2, 0); /* 00000001 */
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ } else if (dev_priv->chipset >= 0xa0) {
+ xf_emit(ctx, 2, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0); /* 00000003 */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 2, 0); /* 00000001 */
} else {
- if (dev_priv->chipset >= 0xa0)
- xf_emit(ctx, 0x1b, 0);
- else
- xf_emit(ctx, 0x15, 0);
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1430 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
}
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 2, 1);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 2, 1);
+ xf_emit(ctx, 4, 0); /* ffffffff CLEAR_COLOR */
+ xf_emit(ctx, 4, 0); /* ffffffff BLEND_COLOR A R G B */
+ xf_emit(ctx, 1, 0); /* 00000fff eng2d UNK2B0 */
if (dev_priv->chipset >= 0xa0)
- xf_emit(ctx, 4, 0);
- else
- xf_emit(ctx, 3, 0);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
- xf_emit(ctx, 0x10, 1);
- xf_emit(ctx, 8, 2);
- xf_emit(ctx, 0x10, 1);
- xf_emit(ctx, 8, 2);
- xf_emit(ctx, 8, 1);
- xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 2, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
+ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK19C0 */
+ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000000f LOGIC_OP */
+ if (dev_priv->chipset >= 0xa0)
+ xf_emit(ctx, 1, 0); /* 00000001 UNK12E4? NVA3+ only? */
+ if (IS_NVA3F(dev_priv->chipset)) {
+ xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_RGB */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK15C4 */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1140 */
}
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 0x5b, 0);
+ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
+ xf_emit(ctx, 1, 0); /* 00000007 PATTERN_COLOR_FORMAT */
+ xf_emit(ctx, 2, 0); /* ffffffff PATTERN_MONO_COLOR */
+ xf_emit(ctx, 1, 0); /* 00000001 PATTERN_MONO_FORMAT */
+ xf_emit(ctx, 2, 0); /* ffffffff PATTERN_MONO_BITMAP */
+ xf_emit(ctx, 1, 0); /* 00000003 PATTERN_SELECT */
+ xf_emit(ctx, 1, 0); /* 000000ff ROP */
+ xf_emit(ctx, 1, 0); /* ffffffff BETA1 */
+ xf_emit(ctx, 1, 0); /* ffffffff BETA4 */
+ xf_emit(ctx, 1, 0); /* 00000007 OPERATION */
+ xf_emit(ctx, 0x50, 0); /* 10x ffffff, ffffff, ffffff, ffffff, 3 PATTERN */
}
static void
-nv50_graph_construct_xfer_tp_x1(struct nouveau_grctx *ctx)
+nv50_graph_construct_xfer_unk84xx(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
int magic3;
- if (dev_priv->chipset == 0x50)
+ switch (dev_priv->chipset) {
+ case 0x50:
magic3 = 0x1000;
- else if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa8)
+ break;
+ case 0x86:
+ case 0x98:
+ case 0xa8:
+ case 0xaa:
+ case 0xac:
+ case 0xaf:
magic3 = 0x1e00;
- else
+ break;
+ default:
magic3 = 0;
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 4);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 0x24, 0);
+ }
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 7f/ff[NVA0+] VP_REG_ALLOC_RESULT */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 0); /* 111/113[NVA0+] */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 0x1f, 0); /* ffffffff */
else if (dev_priv->chipset >= 0xa0)
- xf_emit(ctx, 0x14, 0);
+ xf_emit(ctx, 0x0f, 0); /* ffffffff */
else
- xf_emit(ctx, 0x15, 0);
- xf_emit(ctx, 2, 4);
+ xf_emit(ctx, 0x10, 0); /* fffffff VP_RESULT_MAP_1 up */
+ xf_emit(ctx, 2, 0); /* f/1f[NVA3], fffffff/ffffffff[NVA0+] */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_REG_ALLOC_RESULT */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */
if (dev_priv->chipset >= 0xa0)
- xf_emit(ctx, 1, 0x03020100);
+ xf_emit(ctx, 1, 0x03020100); /* ffffffff */
else
- xf_emit(ctx, 1, 0x00608080);
- xf_emit(ctx, 4, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 2, 4);
- xf_emit(ctx, 1, 0x80);
+ xf_emit(ctx, 1, 0x00608080); /* fffffff VP_RESULT_MAP_0 */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 2, 0); /* 111/113, 7f/ff */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
if (magic3)
- xf_emit(ctx, 1, magic3);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 0x24, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 0x80);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 0x03020100);
- xf_emit(ctx, 1, 3);
+ xf_emit(ctx, 1, magic3); /* 00007fff tesla UNK141C */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 0); /* 111/113 */
+ xf_emit(ctx, 0x1f, 0); /* ffffffff GP_RESULT_MAP_1 up */
+ xf_emit(ctx, 1, 0); /* 0000001f */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */
+ xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0x03020100); /* ffffffff GP_RESULT_MAP_0 */
+ xf_emit(ctx, 1, 3); /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
if (magic3)
- xf_emit(ctx, 1, magic3);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 4, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 3);
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, magic3); /* 7fff tesla UNK141C */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 0); /* 111/113 */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 3); /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
+ xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK13A0 */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_REG_ALLOC_RESULT */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 0); /* 111/113 */
if (dev_priv->chipset == 0x94 || dev_priv->chipset == 0x96)
- xf_emit(ctx, 0x1024, 0);
+ xf_emit(ctx, 0x1020, 0); /* 4 x (0x400 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
else if (dev_priv->chipset < 0xa0)
- xf_emit(ctx, 0xa24, 0);
- else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa)
- xf_emit(ctx, 0x214, 0);
+ xf_emit(ctx, 0xa20, 0); /* 4 x (0x280 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
+ else if (!IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 0x210, 0); /* ffffffff */
else
- xf_emit(ctx, 0x414, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 3);
- xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 0x410, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 3); /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
+ xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
}
static void
-nv50_graph_construct_xfer_tp_x2(struct nouveau_grctx *ctx)
+nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
int magic1, magic2;
if (dev_priv->chipset == 0x50) {
magic1 = 0x3ff;
magic2 = 0x00003e60;
- } else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) {
+ } else if (!IS_NVA3F(dev_priv->chipset)) {
magic1 = 0x7ff;
magic2 = 0x001ffe67;
} else {
magic1 = 0x7ff;
magic2 = 0x00087e67;
}
- xf_emit(ctx, 3, 0);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 0xc, 0);
- xf_emit(ctx, 1, 0xf);
- xf_emit(ctx, 0xb, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 4, 0xffff);
- xf_emit(ctx, 8, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 5, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 2, 0);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
- xf_emit(ctx, 1, 3);
- xf_emit(ctx, 1, 0);
- } else if (dev_priv->chipset >= 0xa0)
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 0xa, 0);
- xf_emit(ctx, 2, 1);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 2, 1);
- xf_emit(ctx, 1, 2);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 0x18, 1);
- xf_emit(ctx, 8, 2);
- xf_emit(ctx, 8, 1);
- xf_emit(ctx, 8, 2);
- xf_emit(ctx, 8, 1);
- xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* ffffffff ALPHA_TEST_REF */
+ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 1); /* 0000000f UNK16A0 */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 4, 0); /* ffffffff BLEND_COLOR */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK19C0 */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK0FDC */
+ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
+ xf_emit(ctx, 1, 0); /* ff[NV50]/3ff[NV84+] */
+ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
+ xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
+ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK19CC */
+ xf_emit(ctx, 1, 0); /* 7 */
+ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff COLOR_KEY */
+ xf_emit(ctx, 1, 0); /* 00000001 COLOR_KEY_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 COLOR_KEY_FORMAT */
+ xf_emit(ctx, 2, 0); /* ffffffff SIFC_BITMAP_COLOR */
+ xf_emit(ctx, 1, 1); /* 00000001 SIFC_BITMAP_WRITE_BIT0_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */
+ if (IS_NVA3F(dev_priv->chipset)) {
+ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK16B4 */
+ xf_emit(ctx, 1, 0); /* 00000003 */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1298 */
+ } else if (dev_priv->chipset >= 0xa0) {
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK16B4 */
+ xf_emit(ctx, 1, 0); /* 00000003 */
+ } else {
+ xf_emit(ctx, 1, 0); /* 00000003 MULTISAMPLE_CTRL */
}
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 7, 0);
- xf_emit(ctx, 1, 0x0fac6881);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 3, 0xcf);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 0xa, 0);
- xf_emit(ctx, 2, 1);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 2, 1);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 8, 1);
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 7, 0);
- xf_emit(ctx, 1, 0x0fac6881);
- xf_emit(ctx, 1, 0xf);
- xf_emit(ctx, 7, 0);
- xf_emit(ctx, 1, magic2);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 0x11);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 2, 1);
- else
- xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */
+ if (IS_NVA3F(dev_priv->chipset)) {
+ xf_emit(ctx, 1, 0); /* 00000001 UNK12E4 */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_SRC_RGB */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_DST_RGB */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_SRC_ALPHA */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_DST_ALPHA */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */
+ }
+ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */
+ xf_emit(ctx, 1, 0); /* 00000001 FRAMEBUFFER_SRGB */
+ xf_emit(ctx, 1, 0); /* 7 */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
+ xf_emit(ctx, 1, 0); /* 00000007 OPERATION */
+ xf_emit(ctx, 1, 0xcf); /* 000000ff SIFC_FORMAT */
+ xf_emit(ctx, 1, 0xcf); /* 000000ff DRAW_COLOR_FORMAT */
+ xf_emit(ctx, 1, 0xcf); /* 000000ff SRC_FORMAT */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ xf_emit(ctx, 1, 0); /* 7/f[NVA3] MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */
+ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 8, 1); /* 00000001 UNK19E0 */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
if(dev_priv->chipset == 0x50)
- xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0); /* ff */
else
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 5, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 4, 0);
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 7, 0);
- xf_emit(ctx, 1, 0x0fac6881);
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, magic1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 2, 0);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 0x28, 0);
- xf_emit(ctx, 8, 8);
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 7, 0);
- xf_emit(ctx, 1, 0x0fac6881);
- xf_emit(ctx, 8, 0x400);
- xf_emit(ctx, 8, 0x300);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0xf);
- xf_emit(ctx, 7, 0);
- xf_emit(ctx, 1, 0x20);
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 1, 0x100);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 0x40);
- xf_emit(ctx, 1, 0x100);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 3);
- xf_emit(ctx, 4, 0);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, magic2);
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 1, 0x0fac6881);
- xf_emit(ctx, 9, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 4, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0x400);
- xf_emit(ctx, 1, 0x300);
- xf_emit(ctx, 1, 0x1001);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 4, 0);
- else
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 7, 0);
- xf_emit(ctx, 1, 0x0fac6881);
- xf_emit(ctx, 1, 0xf);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
- xf_emit(ctx, 0x15, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 3, 0);
- } else
- xf_emit(ctx, 0x17, 0);
+ xf_emit(ctx, 3, 0); /* 1, 7, 3ff */
+ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
+ xf_emit(ctx, 1, 0); /* 000fffff BLIT_DU_DX_FRACT */
+ xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DU_DX_INT */
+ xf_emit(ctx, 1, 0); /* 000fffff BLIT_DV_DY_FRACT */
+ xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DV_DY_INT */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, magic1); /* 3ff/7ff tesla UNK0D68 */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 8, 0); /* 0000ffff DMA_COLOR */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_GLOBAL */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_LOCAL */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_STACK */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_DST */
+ xf_emit(ctx, 1, 0); /* 7 */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 8, 0); /* 000000ff RT_ADDRESS_HIGH */
+ xf_emit(ctx, 8, 0); /* ffffffff RT_LAYER_STRIDE */
+ xf_emit(ctx, 8, 0); /* ffffffff RT_ADDRESS_LOW */
+ xf_emit(ctx, 8, 8); /* 0000007f RT_TILE_MODE */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 8, 0x400); /* 0fffffff RT_HORIZ */
+ xf_emit(ctx, 8, 0x300); /* 0000ffff RT_VERT */
+ xf_emit(ctx, 1, 1); /* 00001fff RT_ARRAY_MODE */
+ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 1, 0x20); /* 00000fff DST_TILE_MODE */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
+ xf_emit(ctx, 1, 0x100); /* 0001ffff DST_HEIGHT */
+ xf_emit(ctx, 1, 0); /* 000007ff DST_LAYER */
+ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
+ xf_emit(ctx, 1, 0); /* ffffffff DST_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0); /* 000000ff DST_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0x40); /* 0007ffff DST_PITCH */
+ xf_emit(ctx, 1, 0x100); /* 0001ffff DST_WIDTH */
+ xf_emit(ctx, 1, 0); /* 0000ffff */
+ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK15AC */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
+ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_ZETA */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 2, 0); /* ffff, ff/3ff */
+ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0); /* ffffffff ZETA_LAYER_STRIDE */
+ xf_emit(ctx, 1, 0); /* 000000ff ZETA_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff ZETA_ADDRESS_LOW */
+ xf_emit(ctx, 1, 4); /* 00000007 ZETA_TILE_MODE */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0x400); /* 0fffffff ZETA_HORIZ */
+ xf_emit(ctx, 1, 0x300); /* 0000ffff ZETA_VERT */
+ xf_emit(ctx, 1, 0x1001); /* 00001fff ZETA_ARRAY_MODE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */
+ xf_emit(ctx, 1, 0); /* 00000001 FRAMEBUFFER_SRGB */
+ xf_emit(ctx, 1, 0); /* 7 */
+ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
+ if (IS_NVA3F(dev_priv->chipset)) {
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ }
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
if (dev_priv->chipset >= 0xa0)
- xf_emit(ctx, 1, 0x0fac6881);
- xf_emit(ctx, 1, magic2);
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 2, 1);
- xf_emit(ctx, 3, 0);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 2, 1);
- else
- xf_emit(ctx, 1, 1);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 2, 0);
- else if (dev_priv->chipset != 0x50)
- xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x0fac6881); /* fffffff */
+ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0FB0 */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK19CC */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ if (IS_NVA3F(dev_priv->chipset)) {
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, 0); /* 0000000f tesla UNK15C8 */
+ }
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ if (dev_priv->chipset >= 0xa0) {
+ xf_emit(ctx, 3, 0); /* 7/f, 1, ffff0ff3 */
+ xf_emit(ctx, 1, 0xfac6881); /* fffffff */
+ xf_emit(ctx, 4, 0); /* 1, 1, 1, 3ff */
+ xf_emit(ctx, 1, 4); /* 7 */
+ xf_emit(ctx, 1, 0); /* 1 */
+ xf_emit(ctx, 2, 1); /* 1 */
+ xf_emit(ctx, 2, 0); /* 7, f */
+ xf_emit(ctx, 1, 1); /* 1 */
+ xf_emit(ctx, 1, 0); /* 7/f */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 0x9, 0); /* 1 */
+ else
+ xf_emit(ctx, 0x8, 0); /* 1 */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 8, 1); /* 1 */
+ xf_emit(ctx, 1, 0x11); /* 7f */
+ xf_emit(ctx, 7, 0); /* 7f */
+ xf_emit(ctx, 1, 0xfac6881); /* fffffff */
+ xf_emit(ctx, 1, 0xf); /* f */
+ xf_emit(ctx, 7, 0); /* f */
+ xf_emit(ctx, 1, 0x11); /* 7f */
+ xf_emit(ctx, 1, 1); /* 1 */
+ xf_emit(ctx, 5, 0); /* 1, 7, 3ff, 3, 7 */
+ if (IS_NVA3F(dev_priv->chipset)) {
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ }
+ }
}
static void
-nv50_graph_construct_xfer_tp_x3(struct nouveau_grctx *ctx)
+nv50_graph_construct_xfer_tex(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 2, 0); /* 1 LINKED_TSC. yes, 2. */
+ if (dev_priv->chipset != 0x50)
+ xf_emit(ctx, 1, 0); /* 3 */
+ xf_emit(ctx, 1, 1); /* 1ffff BLIT_DU_DX_INT */
+ xf_emit(ctx, 1, 0); /* fffff BLIT_DU_DX_FRACT */
+ xf_emit(ctx, 1, 1); /* 1ffff BLIT_DV_DY_INT */
+ xf_emit(ctx, 1, 0); /* fffff BLIT_DV_DY_FRACT */
if (dev_priv->chipset == 0x50)
- xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0); /* 3 BLIT_CONTROL */
else
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 0x2a712488);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x4085c000);
- xf_emit(ctx, 1, 0x40);
- xf_emit(ctx, 1, 0x100);
- xf_emit(ctx, 1, 0x10100);
- xf_emit(ctx, 1, 0x02800000);
+ xf_emit(ctx, 2, 0); /* 3ff, 1 */
+ xf_emit(ctx, 1, 0x2a712488); /* ffffffff SRC_TIC_0 */
+ xf_emit(ctx, 1, 0); /* ffffffff SRC_TIC_1 */
+ xf_emit(ctx, 1, 0x4085c000); /* ffffffff SRC_TIC_2 */
+ xf_emit(ctx, 1, 0x40); /* ffffffff SRC_TIC_3 */
+ xf_emit(ctx, 1, 0x100); /* ffffffff SRC_TIC_4 */
+ xf_emit(ctx, 1, 0x10100); /* ffffffff SRC_TIC_5 */
+ xf_emit(ctx, 1, 0x02800000); /* ffffffff SRC_TIC_6 */
+ xf_emit(ctx, 1, 0); /* ffffffff SRC_TIC_7 */
+ if (dev_priv->chipset == 0x50) {
+ xf_emit(ctx, 1, 0); /* 00000001 turing UNK358 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34? */
+ xf_emit(ctx, 1, 0); /* 00000003 turing UNK37C tesla UNK1690 */
+ xf_emit(ctx, 1, 0); /* 00000003 BLIT_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000001 turing UNK32C tesla UNK0F94 */
+ } else if (!IS_NVAAF(dev_priv->chipset)) {
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34? */
+ xf_emit(ctx, 1, 0); /* 00000003 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ xf_emit(ctx, 1, 0); /* 00000003 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1664 / turing UNK03E8 */
+ xf_emit(ctx, 1, 0); /* 00000003 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ } else {
+ xf_emit(ctx, 0x6, 0);
+ }
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34 */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_TEXTURE */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_SRC */
}
static void
-nv50_graph_construct_xfer_tp_x4(struct nouveau_grctx *ctx)
+nv50_graph_construct_xfer_unk8cxx(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
- xf_emit(ctx, 2, 0x04e3bfdf);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x00ffff00);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 2, 1);
- else
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 0x00ffff00);
- xf_emit(ctx, 8, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0x30201000);
- xf_emit(ctx, 1, 0x70605040);
- xf_emit(ctx, 1, 0xb8a89888);
- xf_emit(ctx, 1, 0xf8e8d8c8);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x1a);
-}
-
-static void
-nv50_graph_construct_xfer_tp_x5(struct nouveau_grctx *ctx)
-{
- struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 0xfac6881);
- xf_emit(ctx, 4, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 2, 1);
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 1);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 0xb, 0);
- else
- xf_emit(ctx, 0xa, 0);
- xf_emit(ctx, 8, 1);
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 7, 0);
- xf_emit(ctx, 1, 0xfac6881);
- xf_emit(ctx, 1, 0xf);
- xf_emit(ctx, 7, 0);
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 1, 1);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
- xf_emit(ctx, 6, 0);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 6, 0);
- } else {
- xf_emit(ctx, 0xb, 0);
- }
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 2, 0); /* 7, ffff0ff3 */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE */
+ xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0D64 */
+ xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0DF4 */
+ xf_emit(ctx, 1, 1); /* 00000001 UNK15B4 */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
+ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK0F98 */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1668 */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
+ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */
+ xf_emit(ctx, 1, 0); /* 00000001 POLYGON_SMOOTH_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1658 */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE */
+ xf_emit(ctx, 1, 1); /* 00000001 UNK15B4 */
+ xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_ENABLE */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK165C */
+ xf_emit(ctx, 1, 0x30201000); /* ffffffff tesla UNK1670 */
+ xf_emit(ctx, 1, 0x70605040); /* ffffffff tesla UNK1670 */
+ xf_emit(ctx, 1, 0xb8a89888); /* ffffffff tesla UNK1670 */
+ xf_emit(ctx, 1, 0xf8e8d8c8); /* ffffffff tesla UNK1670 */
+ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */
+ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
}
static void
@@ -2193,108 +3102,136 @@ nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
if (dev_priv->chipset < 0xa0) {
- nv50_graph_construct_xfer_tp_x1(ctx);
- nv50_graph_construct_xfer_tp_x2(ctx);
- nv50_graph_construct_xfer_tp_x3(ctx);
- if (dev_priv->chipset == 0x50)
- xf_emit(ctx, 0xf, 0);
- else
- xf_emit(ctx, 0x12, 0);
- nv50_graph_construct_xfer_tp_x4(ctx);
+ nv50_graph_construct_xfer_unk84xx(ctx);
+ nv50_graph_construct_xfer_tprop(ctx);
+ nv50_graph_construct_xfer_tex(ctx);
+ nv50_graph_construct_xfer_unk8cxx(ctx);
} else {
- nv50_graph_construct_xfer_tp_x3(ctx);
- if (dev_priv->chipset < 0xaa)
- xf_emit(ctx, 0xc, 0);
- else
- xf_emit(ctx, 0xa, 0);
- nv50_graph_construct_xfer_tp_x2(ctx);
- nv50_graph_construct_xfer_tp_x5(ctx);
- nv50_graph_construct_xfer_tp_x4(ctx);
- nv50_graph_construct_xfer_tp_x1(ctx);
+ nv50_graph_construct_xfer_tex(ctx);
+ nv50_graph_construct_xfer_tprop(ctx);
+ nv50_graph_construct_xfer_unk8cxx(ctx);
+ nv50_graph_construct_xfer_unk84xx(ctx);
}
}
static void
-nv50_graph_construct_xfer_tp2(struct nouveau_grctx *ctx)
+nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
- int i, mpcnt;
- if (dev_priv->chipset == 0x98 || dev_priv->chipset == 0xaa)
- mpcnt = 1;
- else if (dev_priv->chipset < 0xa0 || dev_priv->chipset >= 0xa8)
- mpcnt = 2;
- else
- mpcnt = 3;
+ int i, mpcnt = 2;
+ switch (dev_priv->chipset) {
+ case 0x98:
+ case 0xaa:
+ mpcnt = 1;
+ break;
+ case 0x50:
+ case 0x84:
+ case 0x86:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ case 0xa8:
+ case 0xac:
+ mpcnt = 2;
+ break;
+ case 0xa0:
+ case 0xa3:
+ case 0xa5:
+ case 0xaf:
+ mpcnt = 3;
+ break;
+ }
for (i = 0; i < mpcnt; i++) {
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x80);
- xf_emit(ctx, 1, 0x80007004);
- xf_emit(ctx, 1, 0x04000400);
+ xf_emit(ctx, 1, 0); /* ff */
+ xf_emit(ctx, 1, 0x80); /* ffffffff tesla UNK1404 */
+ xf_emit(ctx, 1, 0x80007004); /* ffffffff tesla UNK12B0 */
+ xf_emit(ctx, 1, 0x04000400); /* ffffffff */
if (dev_priv->chipset >= 0xa0)
- xf_emit(ctx, 1, 0xc0);
- xf_emit(ctx, 1, 0x1000);
- xf_emit(ctx, 2, 0);
- if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa8) {
- xf_emit(ctx, 1, 0xe00);
- xf_emit(ctx, 1, 0x1e00);
+ xf_emit(ctx, 1, 0xc0); /* 00007fff tesla UNK152C */
+ xf_emit(ctx, 1, 0x1000); /* 0000ffff tesla UNK0D60 */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset == 0xa8 || IS_NVAAF(dev_priv->chipset)) {
+ xf_emit(ctx, 1, 0xe00); /* 7fff */
+ xf_emit(ctx, 1, 0x1e00); /* 7fff */
}
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 1); /* 000000ff VP_REG_ALLOC_TEMP */
+ xf_emit(ctx, 1, 0); /* 00000001 LINKED_TSC */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
if (dev_priv->chipset == 0x50)
- xf_emit(ctx, 2, 0x1000);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 2);
- if (dev_priv->chipset >= 0xaa)
- xf_emit(ctx, 0xb, 0);
+ xf_emit(ctx, 2, 0x1000); /* 7fff tesla UNK141C */
+ xf_emit(ctx, 1, 1); /* 000000ff GP_REG_ALLOC_TEMP */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 000000ff FP_REG_ALLOC_TEMP */
+ xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */
+ if (IS_NVAAF(dev_priv->chipset))
+ xf_emit(ctx, 0xb, 0); /* RO */
else if (dev_priv->chipset >= 0xa0)
- xf_emit(ctx, 0xc, 0);
+ xf_emit(ctx, 0xc, 0); /* RO */
else
- xf_emit(ctx, 0xa, 0);
+ xf_emit(ctx, 0xa, 0); /* RO */
}
- xf_emit(ctx, 1, 0x08100c12);
- xf_emit(ctx, 1, 0);
+ xf_emit(ctx, 1, 0x08100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
if (dev_priv->chipset >= 0xa0) {
- xf_emit(ctx, 1, 0x1fe21);
+ xf_emit(ctx, 1, 0x1fe21); /* 0003ffff tesla UNK0FAC */
}
- xf_emit(ctx, 5, 0);
- xf_emit(ctx, 4, 0xffff);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 2, 0x10001);
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 0x1fe21);
- xf_emit(ctx, 1, 0);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 4, 0);
- xf_emit(ctx, 1, 0x08100c12);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 8, 0);
- xf_emit(ctx, 1, 0xfac6881);
- xf_emit(ctx, 1, 0);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
- xf_emit(ctx, 1, 3);
- xf_emit(ctx, 3, 0);
- xf_emit(ctx, 1, 4);
- xf_emit(ctx, 9, 0);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 2, 1);
- xf_emit(ctx, 1, 2);
- xf_emit(ctx, 3, 1);
- xf_emit(ctx, 1, 0);
- if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
- xf_emit(ctx, 8, 2);
- xf_emit(ctx, 0x10, 1);
- xf_emit(ctx, 8, 2);
- xf_emit(ctx, 0x18, 1);
- xf_emit(ctx, 3, 0);
+ xf_emit(ctx, 3, 0); /* 7fff, 0, 0 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */
+ xf_emit(ctx, 1, 1); /* 00000001 LANES32 */
+ xf_emit(ctx, 1, 0x10001); /* 00ffffff BLOCK_ALLOC */
+ xf_emit(ctx, 1, 0x10001); /* ffffffff BLOCKDIM_XY */
+ xf_emit(ctx, 1, 1); /* 0000ffff BLOCKDIM_Z */
+ xf_emit(ctx, 1, 0); /* ffffffff SHARED_SIZE */
+ xf_emit(ctx, 1, 0x1fe21); /* 1ffff/3ffff[NVA0+] tesla UNk0FAC */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34 */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 0); /* 1 LINKED_TSC */
+ xf_emit(ctx, 1, 0); /* ff FP_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff FP_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0x08100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
+ xf_emit(ctx, 1, 0); /* 000000ff FRAG_COLOR_CLAMP_EN */
+ xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */
+ xf_emit(ctx, 1, 0x11); /* 0000007f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 0000007f RT_FORMAT */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0xfac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000003 MULTISAMPLE_CTRL */
+ if (IS_NVA3F(dev_priv->chipset))
+ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK16B4 */
+ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* 00000001 FRAMEBUFFER_SRGB */
+ xf_emit(ctx, 1, 4); /* ffffffff tesla UNK1400 */
+ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */
+ if (IS_NVA3F(dev_priv->chipset)) {
+ xf_emit(ctx, 1, 0); /* 00000001 UNK12E4 */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_RGB */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1928 */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */
}
- xf_emit(ctx, 1, 4);
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0F90 */
+ xf_emit(ctx, 1, 4); /* 000000ff FP_RESULT_COUNT */
+ /* XXX: demagic this part some day */
if (dev_priv->chipset == 0x50)
xf_emit(ctx, 0x3a0, 0);
else if (dev_priv->chipset < 0x94)
@@ -2303,9 +3240,9 @@ nv50_graph_construct_xfer_tp2(struct nouveau_grctx *ctx)
xf_emit(ctx, 0x39f, 0);
else
xf_emit(ctx, 0x3a3, 0);
- xf_emit(ctx, 1, 0x11);
- xf_emit(ctx, 1, 0);
- xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
+ xf_emit(ctx, 1, 0); /* 7 OPERATION */
+ xf_emit(ctx, 1, 1); /* 1 DST_LINEAR */
xf_emit(ctx, 0x2d, 0);
}
@@ -2323,52 +3260,56 @@ nv50_graph_construct_xfer2(struct nouveau_grctx *ctx)
if (dev_priv->chipset < 0xa0) {
for (i = 0; i < 8; i++) {
ctx->ctxvals_pos = offset + i;
+ /* that little bugger belongs to csched. No idea
+ * what it's doing here. */
if (i == 0)
- xf_emit(ctx, 1, 0x08100c12);
+ xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */
if (units & (1 << i))
- nv50_graph_construct_xfer_tp2(ctx);
+ nv50_graph_construct_xfer_mpc(ctx);
if ((ctx->ctxvals_pos-offset)/8 > size)
size = (ctx->ctxvals_pos-offset)/8;
}
} else {
/* Strand 0: TPs 0, 1 */
ctx->ctxvals_pos = offset;
- xf_emit(ctx, 1, 0x08100c12);
+ /* that little bugger belongs to csched. No idea
+ * what it's doing here. */
+ xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */
if (units & (1 << 0))
- nv50_graph_construct_xfer_tp2(ctx);
+ nv50_graph_construct_xfer_mpc(ctx);
if (units & (1 << 1))
- nv50_graph_construct_xfer_tp2(ctx);
+ nv50_graph_construct_xfer_mpc(ctx);
if ((ctx->ctxvals_pos-offset)/8 > size)
size = (ctx->ctxvals_pos-offset)/8;
- /* Strand 0: TPs 2, 3 */
+ /* Strand 1: TPs 2, 3 */
ctx->ctxvals_pos = offset + 1;
if (units & (1 << 2))
- nv50_graph_construct_xfer_tp2(ctx);
+ nv50_graph_construct_xfer_mpc(ctx);
if (units & (1 << 3))
- nv50_graph_construct_xfer_tp2(ctx);
+ nv50_graph_construct_xfer_mpc(ctx);
if ((ctx->ctxvals_pos-offset)/8 > size)
size = (ctx->ctxvals_pos-offset)/8;
- /* Strand 0: TPs 4, 5, 6 */
+ /* Strand 2: TPs 4, 5, 6 */
ctx->ctxvals_pos = offset + 2;
if (units & (1 << 4))
- nv50_graph_construct_xfer_tp2(ctx);
+ nv50_graph_construct_xfer_mpc(ctx);
if (units & (1 << 5))
- nv50_graph_construct_xfer_tp2(ctx);
+ nv50_graph_construct_xfer_mpc(ctx);
if (units & (1 << 6))
- nv50_graph_construct_xfer_tp2(ctx);
+ nv50_graph_construct_xfer_mpc(ctx);
if ((ctx->ctxvals_pos-offset)/8 > size)
size = (ctx->ctxvals_pos-offset)/8;
- /* Strand 0: TPs 7, 8, 9 */
+ /* Strand 3: TPs 7, 8, 9 */
ctx->ctxvals_pos = offset + 3;
if (units & (1 << 7))
- nv50_graph_construct_xfer_tp2(ctx);
+ nv50_graph_construct_xfer_mpc(ctx);
if (units & (1 << 8))
- nv50_graph_construct_xfer_tp2(ctx);
+ nv50_graph_construct_xfer_mpc(ctx);
if (units & (1 << 9))
- nv50_graph_construct_xfer_tp2(ctx);
+ nv50_graph_construct_xfer_mpc(ctx);
if ((ctx->ctxvals_pos-offset)/8 > size)
size = (ctx->ctxvals_pos-offset)/8;
}
diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c
index 91ef93cf1f35..a53fc974332b 100644
--- a/drivers/gpu/drm/nouveau/nv50_instmem.c
+++ b/drivers/gpu/drm/nouveau/nv50_instmem.c
@@ -32,39 +32,87 @@
struct nv50_instmem_priv {
uint32_t save1700[5]; /* 0x1700->0x1710 */
- struct nouveau_gpuobj_ref *pramin_pt;
- struct nouveau_gpuobj_ref *pramin_bar;
- struct nouveau_gpuobj_ref *fb_bar;
+ struct nouveau_gpuobj *pramin_pt;
+ struct nouveau_gpuobj *pramin_bar;
+ struct nouveau_gpuobj *fb_bar;
};
-#define NV50_INSTMEM_PAGE_SHIFT 12
-#define NV50_INSTMEM_PAGE_SIZE (1 << NV50_INSTMEM_PAGE_SHIFT)
-#define NV50_INSTMEM_PT_SIZE(a) (((a) >> 12) << 3)
+static void
+nv50_channel_del(struct nouveau_channel **pchan)
+{
+ struct nouveau_channel *chan;
-/*NOTE: - Assumes 0x1700 already covers the correct MiB of PRAMIN
- */
-#define BAR0_WI32(g, o, v) do { \
- uint32_t offset; \
- if ((g)->im_backing) { \
- offset = (g)->im_backing_start; \
- } else { \
- offset = chan->ramin->gpuobj->im_backing_start; \
- offset += (g)->im_pramin->start; \
- } \
- offset += (o); \
- nv_wr32(dev, NV_RAMIN + (offset & 0xfffff), (v)); \
-} while (0)
+ chan = *pchan;
+ *pchan = NULL;
+ if (!chan)
+ return;
+
+ nouveau_gpuobj_ref(NULL, &chan->ramfc);
+ nouveau_gpuobj_ref(NULL, &chan->vm_pd);
+ if (chan->ramin_heap.free_stack.next)
+ drm_mm_takedown(&chan->ramin_heap);
+ nouveau_gpuobj_ref(NULL, &chan->ramin);
+ kfree(chan);
+}
+
+static int
+nv50_channel_new(struct drm_device *dev, u32 size,
+ struct nouveau_channel **pchan)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u32 pgd = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200;
+ u32 fc = (dev_priv->chipset == 0x50) ? 0x0000 : 0x4200;
+ struct nouveau_channel *chan;
+ int ret;
+
+ chan = kzalloc(sizeof(*chan), GFP_KERNEL);
+ if (!chan)
+ return -ENOMEM;
+ chan->dev = dev;
+
+ ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin);
+ if (ret) {
+ nv50_channel_del(&chan);
+ return ret;
+ }
+
+ ret = drm_mm_init(&chan->ramin_heap, 0x6000, chan->ramin->size);
+ if (ret) {
+ nv50_channel_del(&chan);
+ return ret;
+ }
+
+ ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 :
+ chan->ramin->pinst + pgd,
+ chan->ramin->vinst + pgd,
+ 0x4000, NVOBJ_FLAG_ZERO_ALLOC,
+ &chan->vm_pd);
+ if (ret) {
+ nv50_channel_del(&chan);
+ return ret;
+ }
+
+ ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 :
+ chan->ramin->pinst + fc,
+ chan->ramin->vinst + fc, 0x100,
+ NVOBJ_FLAG_ZERO_ALLOC, &chan->ramfc);
+ if (ret) {
+ nv50_channel_del(&chan);
+ return ret;
+ }
+
+ *pchan = chan;
+ return 0;
+}
int
nv50_instmem_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_channel *chan;
- uint32_t c_offset, c_size, c_ramfc, c_vmpd, c_base, pt_size;
- uint32_t save_nv001700;
- uint64_t v;
struct nv50_instmem_priv *priv;
+ struct nouveau_channel *chan;
int ret, i;
+ u32 tmp;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -75,212 +123,115 @@ nv50_instmem_init(struct drm_device *dev)
for (i = 0x1700; i <= 0x1710; i += 4)
priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i);
- /* Reserve the last MiB of VRAM, we should probably try to avoid
- * setting up the below tables over the top of the VBIOS image at
- * some point.
- */
- dev_priv->ramin_rsvd_vram = 1 << 20;
- c_offset = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
- c_size = 128 << 10;
- c_vmpd = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x1400 : 0x200;
- c_ramfc = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x0 : 0x20;
- c_base = c_vmpd + 0x4000;
- pt_size = NV50_INSTMEM_PT_SIZE(dev_priv->ramin_size);
-
- NV_DEBUG(dev, " Rsvd VRAM base: 0x%08x\n", c_offset);
- NV_DEBUG(dev, " VBIOS image: 0x%08x\n",
- (nv_rd32(dev, 0x619f04) & ~0xff) << 8);
- NV_DEBUG(dev, " Aperture size: %d MiB\n", dev_priv->ramin_size >> 20);
- NV_DEBUG(dev, " PT size: %d KiB\n", pt_size >> 10);
-
- /* Determine VM layout, we need to do this first to make sure
- * we allocate enough memory for all the page tables.
- */
- dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK);
- dev_priv->vm_gart_size = NV50_VM_BLOCK;
-
- dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size;
- dev_priv->vm_vram_size = dev_priv->vram_size;
- if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM)
- dev_priv->vm_vram_size = NV50_VM_MAX_VRAM;
- dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK);
- dev_priv->vm_vram_pt_nr = dev_priv->vm_vram_size / NV50_VM_BLOCK;
-
- dev_priv->vm_end = dev_priv->vm_vram_base + dev_priv->vm_vram_size;
-
- NV_DEBUG(dev, "NV50VM: GART 0x%016llx-0x%016llx\n",
- dev_priv->vm_gart_base,
- dev_priv->vm_gart_base + dev_priv->vm_gart_size - 1);
- NV_DEBUG(dev, "NV50VM: VRAM 0x%016llx-0x%016llx\n",
- dev_priv->vm_vram_base,
- dev_priv->vm_vram_base + dev_priv->vm_vram_size - 1);
-
- c_size += dev_priv->vm_vram_pt_nr * (NV50_VM_BLOCK / 65536 * 8);
-
- /* Map BAR0 PRAMIN aperture over the memory we want to use */
- save_nv001700 = nv_rd32(dev, NV50_PUNK_BAR0_PRAMIN);
- nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, (c_offset >> 16));
-
- /* Create a fake channel, and use it as our "dummy" channels 0/127.
- * The main reason for creating a channel is so we can use the gpuobj
- * code. However, it's probably worth noting that NVIDIA also setup
- * their channels 0/127 with the same values they configure here.
- * So, there may be some other reason for doing this.
- *
- * Have to create the entire channel manually, as the real channel
- * creation code assumes we have PRAMIN access, and we don't until
- * we're done here.
- */
- chan = kzalloc(sizeof(*chan), GFP_KERNEL);
- if (!chan)
+ /* Global PRAMIN heap */
+ ret = drm_mm_init(&dev_priv->ramin_heap, 0, dev_priv->ramin_size);
+ if (ret) {
+ NV_ERROR(dev, "Failed to init RAMIN heap\n");
return -ENOMEM;
- chan->id = 0;
- chan->dev = dev;
- chan->file_priv = (struct drm_file *)-2;
- dev_priv->fifos[0] = dev_priv->fifos[127] = chan;
-
- INIT_LIST_HEAD(&chan->ramht_refs);
+ }
- /* Channel's PRAMIN object + heap */
- ret = nouveau_gpuobj_new_fake(dev, 0, c_offset, c_size, 0,
- NULL, &chan->ramin);
+ /* we need a channel to plug into the hw to control the BARs */
+ ret = nv50_channel_new(dev, 128*1024, &dev_priv->fifos[0]);
if (ret)
return ret;
+ chan = dev_priv->fifos[127] = dev_priv->fifos[0];
- if (drm_mm_init(&chan->ramin_heap, c_base, c_size - c_base))
- return -ENOMEM;
-
- /* RAMFC + zero channel's PRAMIN up to start of VM pagedir */
- ret = nouveau_gpuobj_new_fake(dev, c_ramfc, c_offset + c_ramfc,
- 0x4000, 0, NULL, &chan->ramfc);
+ /* allocate page table for PRAMIN BAR */
+ ret = nouveau_gpuobj_new(dev, chan, (dev_priv->ramin_size >> 12) * 8,
+ 0x1000, NVOBJ_FLAG_ZERO_ALLOC,
+ &priv->pramin_pt);
if (ret)
return ret;
- for (i = 0; i < c_vmpd; i += 4)
- BAR0_WI32(chan->ramin->gpuobj, i, 0);
+ nv_wo32(chan->vm_pd, 0x0000, priv->pramin_pt->vinst | 0x63);
+ nv_wo32(chan->vm_pd, 0x0004, 0);
- /* VM page directory */
- ret = nouveau_gpuobj_new_fake(dev, c_vmpd, c_offset + c_vmpd,
- 0x4000, 0, &chan->vm_pd, NULL);
+ /* DMA object for PRAMIN BAR */
+ ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->pramin_bar);
if (ret)
return ret;
- for (i = 0; i < 0x4000; i += 8) {
- BAR0_WI32(chan->vm_pd, i + 0x00, 0x00000000);
- BAR0_WI32(chan->vm_pd, i + 0x04, 0x00000000);
- }
-
- /* PRAMIN page table, cheat and map into VM at 0x0000000000.
- * We map the entire fake channel into the start of the PRAMIN BAR
- */
- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pt_size, 0x1000,
- 0, &priv->pramin_pt);
+ nv_wo32(priv->pramin_bar, 0x00, 0x7fc00000);
+ nv_wo32(priv->pramin_bar, 0x04, dev_priv->ramin_size - 1);
+ nv_wo32(priv->pramin_bar, 0x08, 0x00000000);
+ nv_wo32(priv->pramin_bar, 0x0c, 0x00000000);
+ nv_wo32(priv->pramin_bar, 0x10, 0x00000000);
+ nv_wo32(priv->pramin_bar, 0x14, 0x00000000);
+
+ /* map channel into PRAMIN, gpuobj didn't do it for us */
+ ret = nv50_instmem_bind(dev, chan->ramin);
if (ret)
return ret;
- v = c_offset | 1;
- if (dev_priv->vram_sys_base) {
- v += dev_priv->vram_sys_base;
- v |= 0x30;
- }
+ /* poke regs... */
+ nv_wr32(dev, 0x001704, 0x00000000 | (chan->ramin->vinst >> 12));
+ nv_wr32(dev, 0x001704, 0x40000000 | (chan->ramin->vinst >> 12));
+ nv_wr32(dev, 0x00170c, 0x80000000 | (priv->pramin_bar->cinst >> 4));
- i = 0;
- while (v < dev_priv->vram_sys_base + c_offset + c_size) {
- BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, lower_32_bits(v));
- BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, upper_32_bits(v));
- v += 0x1000;
- i += 8;
+ tmp = nv_ri32(dev, 0);
+ nv_wi32(dev, 0, ~tmp);
+ if (nv_ri32(dev, 0) != ~tmp) {
+ NV_ERROR(dev, "PRAMIN readback failed\n");
+ return -EIO;
}
+ nv_wi32(dev, 0, tmp);
- while (i < pt_size) {
- BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, 0x00000000);
- BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, 0x00000000);
- i += 8;
- }
+ dev_priv->ramin_available = true;
- BAR0_WI32(chan->vm_pd, 0x00, priv->pramin_pt->instance | 0x63);
- BAR0_WI32(chan->vm_pd, 0x04, 0x00000000);
+ /* Determine VM layout */
+ dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK);
+ dev_priv->vm_gart_size = NV50_VM_BLOCK;
+
+ dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size;
+ dev_priv->vm_vram_size = dev_priv->vram_size;
+ if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM)
+ dev_priv->vm_vram_size = NV50_VM_MAX_VRAM;
+ dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK);
+ dev_priv->vm_vram_pt_nr = dev_priv->vm_vram_size / NV50_VM_BLOCK;
+
+ dev_priv->vm_end = dev_priv->vm_vram_base + dev_priv->vm_vram_size;
+
+ NV_DEBUG(dev, "NV50VM: GART 0x%016llx-0x%016llx\n",
+ dev_priv->vm_gart_base,
+ dev_priv->vm_gart_base + dev_priv->vm_gart_size - 1);
+ NV_DEBUG(dev, "NV50VM: VRAM 0x%016llx-0x%016llx\n",
+ dev_priv->vm_vram_base,
+ dev_priv->vm_vram_base + dev_priv->vm_vram_size - 1);
/* VRAM page table(s), mapped into VM at +1GiB */
for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0,
- NV50_VM_BLOCK/65536*8, 0, 0,
- &chan->vm_vram_pt[i]);
+ ret = nouveau_gpuobj_new(dev, NULL, NV50_VM_BLOCK / 0x10000 * 8,
+ 0, NVOBJ_FLAG_ZERO_ALLOC,
+ &chan->vm_vram_pt[i]);
if (ret) {
- NV_ERROR(dev, "Error creating VRAM page tables: %d\n",
- ret);
+ NV_ERROR(dev, "Error creating VRAM PGT: %d\n", ret);
dev_priv->vm_vram_pt_nr = i;
return ret;
}
- dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i]->gpuobj;
+ dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i];
- for (v = 0; v < dev_priv->vm_vram_pt[i]->im_pramin->size;
- v += 4)
- BAR0_WI32(dev_priv->vm_vram_pt[i], v, 0);
-
- BAR0_WI32(chan->vm_pd, 0x10 + (i*8),
- chan->vm_vram_pt[i]->instance | 0x61);
- BAR0_WI32(chan->vm_pd, 0x14 + (i*8), 0);
+ nv_wo32(chan->vm_pd, 0x10 + (i*8),
+ chan->vm_vram_pt[i]->vinst | 0x61);
+ nv_wo32(chan->vm_pd, 0x14 + (i*8), 0);
}
- /* DMA object for PRAMIN BAR */
- ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 6*4, 16, 0,
- &priv->pramin_bar);
- if (ret)
- return ret;
- BAR0_WI32(priv->pramin_bar->gpuobj, 0x00, 0x7fc00000);
- BAR0_WI32(priv->pramin_bar->gpuobj, 0x04, dev_priv->ramin_size - 1);
- BAR0_WI32(priv->pramin_bar->gpuobj, 0x08, 0x00000000);
- BAR0_WI32(priv->pramin_bar->gpuobj, 0x0c, 0x00000000);
- BAR0_WI32(priv->pramin_bar->gpuobj, 0x10, 0x00000000);
- BAR0_WI32(priv->pramin_bar->gpuobj, 0x14, 0x00000000);
-
/* DMA object for FB BAR */
- ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 6*4, 16, 0,
- &priv->fb_bar);
+ ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->fb_bar);
if (ret)
return ret;
- BAR0_WI32(priv->fb_bar->gpuobj, 0x00, 0x7fc00000);
- BAR0_WI32(priv->fb_bar->gpuobj, 0x04, 0x40000000 +
- pci_resource_len(dev->pdev, 1) - 1);
- BAR0_WI32(priv->fb_bar->gpuobj, 0x08, 0x40000000);
- BAR0_WI32(priv->fb_bar->gpuobj, 0x0c, 0x00000000);
- BAR0_WI32(priv->fb_bar->gpuobj, 0x10, 0x00000000);
- BAR0_WI32(priv->fb_bar->gpuobj, 0x14, 0x00000000);
+ nv_wo32(priv->fb_bar, 0x00, 0x7fc00000);
+ nv_wo32(priv->fb_bar, 0x04, 0x40000000 +
+ pci_resource_len(dev->pdev, 1) - 1);
+ nv_wo32(priv->fb_bar, 0x08, 0x40000000);
+ nv_wo32(priv->fb_bar, 0x0c, 0x00000000);
+ nv_wo32(priv->fb_bar, 0x10, 0x00000000);
+ nv_wo32(priv->fb_bar, 0x14, 0x00000000);
- /* Poke the relevant regs, and pray it works :) */
- nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12));
- nv_wr32(dev, NV50_PUNK_UNK1710, 0);
- nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12) |
- NV50_PUNK_BAR_CFG_BASE_VALID);
- nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->instance >> 4) |
- NV50_PUNK_BAR1_CTXDMA_VALID);
- nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->instance >> 4) |
- NV50_PUNK_BAR3_CTXDMA_VALID);
+ dev_priv->engine.instmem.flush(dev);
+ nv_wr32(dev, 0x001708, 0x80000000 | (priv->fb_bar->cinst >> 4));
for (i = 0; i < 8; i++)
nv_wr32(dev, 0x1900 + (i*4), 0);
- /* Assume that praying isn't enough, check that we can re-read the
- * entire fake channel back from the PRAMIN BAR */
- for (i = 0; i < c_size; i += 4) {
- if (nv_rd32(dev, NV_RAMIN + i) != nv_ri32(dev, i)) {
- NV_ERROR(dev, "Error reading back PRAMIN at 0x%08x\n",
- i);
- return -EINVAL;
- }
- }
-
- nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700);
-
- /* Global PRAMIN heap */
- if (drm_mm_init(&dev_priv->ramin_heap, c_size, dev_priv->ramin_size - c_size)) {
- NV_ERROR(dev, "Failed to init RAMIN heap\n");
- }
-
- /*XXX: incorrect, but needed to make hash func "work" */
- dev_priv->ramht_offset = 0x10000;
- dev_priv->ramht_bits = 9;
- dev_priv->ramht_size = (1 << dev_priv->ramht_bits) * 8;
return 0;
}
@@ -297,29 +248,24 @@ nv50_instmem_takedown(struct drm_device *dev)
if (!priv)
return;
+ dev_priv->ramin_available = false;
+
/* Restore state from before init */
for (i = 0x1700; i <= 0x1710; i += 4)
nv_wr32(dev, i, priv->save1700[(i - 0x1700) / 4]);
- nouveau_gpuobj_ref_del(dev, &priv->fb_bar);
- nouveau_gpuobj_ref_del(dev, &priv->pramin_bar);
- nouveau_gpuobj_ref_del(dev, &priv->pramin_pt);
+ nouveau_gpuobj_ref(NULL, &priv->fb_bar);
+ nouveau_gpuobj_ref(NULL, &priv->pramin_bar);
+ nouveau_gpuobj_ref(NULL, &priv->pramin_pt);
/* Destroy dummy channel */
if (chan) {
- for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
- nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);
- dev_priv->vm_vram_pt[i] = NULL;
- }
+ for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
+ nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]);
dev_priv->vm_vram_pt_nr = 0;
- nouveau_gpuobj_del(dev, &chan->vm_pd);
- nouveau_gpuobj_ref_del(dev, &chan->ramfc);
- nouveau_gpuobj_ref_del(dev, &chan->ramin);
- drm_mm_takedown(&chan->ramin_heap);
-
- dev_priv->fifos[0] = dev_priv->fifos[127] = NULL;
- kfree(chan);
+ nv50_channel_del(&dev_priv->fifos[0]);
+ dev_priv->fifos[127] = NULL;
}
dev_priv->engine.instmem.priv = NULL;
@@ -331,14 +277,14 @@ nv50_instmem_suspend(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->fifos[0];
- struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
+ struct nouveau_gpuobj *ramin = chan->ramin;
int i;
- ramin->im_backing_suspend = vmalloc(ramin->im_pramin->size);
+ ramin->im_backing_suspend = vmalloc(ramin->size);
if (!ramin->im_backing_suspend)
return -ENOMEM;
- for (i = 0; i < ramin->im_pramin->size; i += 4)
+ for (i = 0; i < ramin->size; i += 4)
ramin->im_backing_suspend[i/4] = nv_ri32(dev, i);
return 0;
}
@@ -349,23 +295,25 @@ nv50_instmem_resume(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
struct nouveau_channel *chan = dev_priv->fifos[0];
- struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
+ struct nouveau_gpuobj *ramin = chan->ramin;
int i;
- nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, (ramin->im_backing_start >> 16));
- for (i = 0; i < ramin->im_pramin->size; i += 4)
- BAR0_WI32(ramin, i, ramin->im_backing_suspend[i/4]);
+ dev_priv->ramin_available = false;
+ dev_priv->ramin_base = ~0;
+ for (i = 0; i < ramin->size; i += 4)
+ nv_wo32(ramin, i, ramin->im_backing_suspend[i/4]);
+ dev_priv->ramin_available = true;
vfree(ramin->im_backing_suspend);
ramin->im_backing_suspend = NULL;
/* Poke the relevant regs, and pray it works :) */
- nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12));
+ nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12));
nv_wr32(dev, NV50_PUNK_UNK1710, 0);
- nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12) |
+ nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12) |
NV50_PUNK_BAR_CFG_BASE_VALID);
- nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->instance >> 4) |
+ nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->cinst >> 4) |
NV50_PUNK_BAR1_CTXDMA_VALID);
- nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->instance >> 4) |
+ nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->cinst >> 4) |
NV50_PUNK_BAR3_CTXDMA_VALID);
for (i = 0; i < 8; i++)
@@ -381,7 +329,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
if (gpuobj->im_backing)
return -EINVAL;
- *sz = ALIGN(*sz, NV50_INSTMEM_PAGE_SIZE);
+ *sz = ALIGN(*sz, 4096);
if (*sz == 0)
return -EINVAL;
@@ -399,9 +347,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
return ret;
}
- gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start;
- gpuobj->im_backing_start <<= PAGE_SHIFT;
-
+ gpuobj->vinst = gpuobj->im_backing->bo.mem.start << PAGE_SHIFT;
return 0;
}
@@ -424,7 +370,7 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
- struct nouveau_gpuobj *pramin_pt = priv->pramin_pt->gpuobj;
+ struct nouveau_gpuobj *pramin_pt = priv->pramin_pt;
uint32_t pte, pte_end;
uint64_t vram;
@@ -436,11 +382,11 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
pte = (gpuobj->im_pramin->start >> 12) << 1;
pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
- vram = gpuobj->im_backing_start;
+ vram = gpuobj->vinst;
NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
gpuobj->im_pramin->start, pte, pte_end);
- NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
+ NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst);
vram |= 1;
if (dev_priv->vram_sys_base) {
@@ -449,9 +395,10 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
}
while (pte < pte_end) {
- nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram));
- nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram));
- vram += NV50_INSTMEM_PAGE_SIZE;
+ nv_wo32(pramin_pt, (pte * 4) + 0, lower_32_bits(vram));
+ nv_wo32(pramin_pt, (pte * 4) + 4, upper_32_bits(vram));
+ vram += 0x1000;
+ pte += 2;
}
dev_priv->engine.instmem.flush(dev);
@@ -472,12 +419,17 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
if (gpuobj->im_bound == 0)
return -EINVAL;
+ /* can happen during late takedown */
+ if (unlikely(!dev_priv->ramin_available))
+ return 0;
+
pte = (gpuobj->im_pramin->start >> 12) << 1;
pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
while (pte < pte_end) {
- nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
- nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
+ nv_wo32(priv->pramin_pt, (pte * 4) + 0, 0x00000000);
+ nv_wo32(priv->pramin_pt, (pte * 4) + 4, 0x00000000);
+ pte += 2;
}
dev_priv->engine.instmem.flush(dev);
@@ -489,7 +441,7 @@ void
nv50_instmem_flush(struct drm_device *dev)
{
nv_wr32(dev, 0x00330c, 0x00000001);
- if (!nv_wait(0x00330c, 0x00000002, 0x00000000))
+ if (!nv_wait(dev, 0x00330c, 0x00000002, 0x00000000))
NV_ERROR(dev, "PRAMIN flush timeout\n");
}
@@ -497,7 +449,7 @@ void
nv84_instmem_flush(struct drm_device *dev)
{
nv_wr32(dev, 0x070000, 0x00000001);
- if (!nv_wait(0x070000, 0x00000002, 0x00000000))
+ if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000))
NV_ERROR(dev, "PRAMIN flush timeout\n");
}
@@ -505,7 +457,7 @@ void
nv50_vm_flush(struct drm_device *dev, int engine)
{
nv_wr32(dev, 0x100c80, (engine << 16) | 1);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000))
+ if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000))
NV_ERROR(dev, "vm flush timeout: engine %d\n", engine);
}
diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c
new file mode 100644
index 000000000000..7dbb305d7e63
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv50_pm.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_bios.h"
+#include "nouveau_pm.h"
+
+struct nv50_pm_state {
+ struct nouveau_pm_level *perflvl;
+ struct pll_lims pll;
+ enum pll_types type;
+ int N, M, P;
+};
+
+int
+nv50_pm_clock_get(struct drm_device *dev, u32 id)
+{
+ struct pll_lims pll;
+ int P, N, M, ret;
+ u32 reg0, reg1;
+
+ ret = get_pll_limits(dev, id, &pll);
+ if (ret)
+ return ret;
+
+ reg0 = nv_rd32(dev, pll.reg + 0);
+ reg1 = nv_rd32(dev, pll.reg + 4);
+ P = (reg0 & 0x00070000) >> 16;
+ N = (reg1 & 0x0000ff00) >> 8;
+ M = (reg1 & 0x000000ff);
+
+ return ((pll.refclk * N / M) >> P);
+}
+
+void *
+nv50_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
+ u32 id, int khz)
+{
+ struct nv50_pm_state *state;
+ int dummy, ret;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return ERR_PTR(-ENOMEM);
+ state->type = id;
+ state->perflvl = perflvl;
+
+ ret = get_pll_limits(dev, id, &state->pll);
+ if (ret < 0) {
+ kfree(state);
+ return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+ }
+
+ ret = nv50_calc_pll(dev, &state->pll, khz, &state->N, &state->M,
+ &dummy, &dummy, &state->P);
+ if (ret < 0) {
+ kfree(state);
+ return ERR_PTR(ret);
+ }
+
+ return state;
+}
+
+void
+nv50_pm_clock_set(struct drm_device *dev, void *pre_state)
+{
+ struct nv50_pm_state *state = pre_state;
+ struct nouveau_pm_level *perflvl = state->perflvl;
+ u32 reg = state->pll.reg, tmp;
+ struct bit_entry BIT_M;
+ u16 script;
+ int N = state->N;
+ int M = state->M;
+ int P = state->P;
+
+ if (state->type == PLL_MEMORY && perflvl->memscript &&
+ bit_table(dev, 'M', &BIT_M) == 0 &&
+ BIT_M.version == 1 && BIT_M.length >= 0x0b) {
+ script = ROM16(BIT_M.data[0x05]);
+ if (script)
+ nouveau_bios_run_init_table(dev, script, NULL);
+ script = ROM16(BIT_M.data[0x07]);
+ if (script)
+ nouveau_bios_run_init_table(dev, script, NULL);
+ script = ROM16(BIT_M.data[0x09]);
+ if (script)
+ nouveau_bios_run_init_table(dev, script, NULL);
+
+ nouveau_bios_run_init_table(dev, perflvl->memscript, NULL);
+ }
+
+ if (state->type == PLL_MEMORY) {
+ nv_wr32(dev, 0x100210, 0);
+ nv_wr32(dev, 0x1002dc, 1);
+ }
+
+ tmp = nv_rd32(dev, reg + 0) & 0xfff8ffff;
+ tmp |= 0x80000000 | (P << 16);
+ nv_wr32(dev, reg + 0, tmp);
+ nv_wr32(dev, reg + 4, (N << 8) | M);
+
+ if (state->type == PLL_MEMORY) {
+ nv_wr32(dev, 0x1002dc, 0);
+ nv_wr32(dev, 0x100210, 0x80000000);
+ }
+
+ kfree(state);
+}
+
diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
index bcd4cf84a7e6..b4a5ecb199f9 100644
--- a/drivers/gpu/drm/nouveau/nv50_sor.c
+++ b/drivers/gpu/drm/nouveau/nv50_sor.c
@@ -92,7 +92,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
}
/* wait for it to be done */
- if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_CTRL(or),
+ if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_CTRL(or),
NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING, 0)) {
NV_ERROR(dev, "timeout: SOR_DPMS_CTRL_PENDING(%d) == 0\n", or);
NV_ERROR(dev, "SOR_DPMS_CTRL(%d) = 0x%08x\n", or,
@@ -108,7 +108,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
nv_wr32(dev, NV50_PDISPLAY_SOR_DPMS_CTRL(or), val |
NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING);
- if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_STATE(or),
+ if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(or),
NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) {
NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", or);
NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", or,
diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c
new file mode 100644
index 000000000000..dbbafed36406
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nva3_pm.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_bios.h"
+#include "nouveau_pm.h"
+
+/*XXX: boards using limits 0x40 need fixing, the register layout
+ * is correct here, but, there's some other funny magic
+ * that modifies things, so it's not likely we'll set/read
+ * the correct timings yet.. working on it...
+ */
+
+struct nva3_pm_state {
+ struct pll_lims pll;
+ int N, M, P;
+};
+
+int
+nva3_pm_clock_get(struct drm_device *dev, u32 id)
+{
+ struct pll_lims pll;
+ int P, N, M, ret;
+ u32 reg;
+
+ ret = get_pll_limits(dev, id, &pll);
+ if (ret)
+ return ret;
+
+ reg = nv_rd32(dev, pll.reg + 4);
+ P = (reg & 0x003f0000) >> 16;
+ N = (reg & 0x0000ff00) >> 8;
+ M = (reg & 0x000000ff);
+ return pll.refclk * N / M / P;
+}
+
+void *
+nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
+ u32 id, int khz)
+{
+ struct nva3_pm_state *state;
+ int dummy, ret;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return ERR_PTR(-ENOMEM);
+
+ ret = get_pll_limits(dev, id, &state->pll);
+ if (ret < 0) {
+ kfree(state);
+ return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+ }
+
+ ret = nv50_calc_pll2(dev, &state->pll, khz, &state->N, &dummy,
+ &state->M, &state->P);
+ if (ret < 0) {
+ kfree(state);
+ return ERR_PTR(ret);
+ }
+
+ return state;
+}
+
+void
+nva3_pm_clock_set(struct drm_device *dev, void *pre_state)
+{
+ struct nva3_pm_state *state = pre_state;
+ u32 reg = state->pll.reg;
+
+ nv_wr32(dev, reg + 4, (state->P << 16) | (state->N << 8) | state->M);
+ kfree(state);
+}
+
diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c
index d64375871979..890c2b95fbc1 100644
--- a/drivers/gpu/drm/nouveau/nvc0_fifo.c
+++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c
@@ -43,12 +43,6 @@ nvc0_fifo_reassign(struct drm_device *dev, bool enable)
}
bool
-nvc0_fifo_cache_flush(struct drm_device *dev)
-{
- return true;
-}
-
-bool
nvc0_fifo_cache_pull(struct drm_device *dev, bool enable)
{
return false;
diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c
index 6b451f864783..13a0f78a9088 100644
--- a/drivers/gpu/drm/nouveau/nvc0_instmem.c
+++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c
@@ -50,8 +50,7 @@ nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
return ret;
}
- gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start;
- gpuobj->im_backing_start <<= PAGE_SHIFT;
+ gpuobj->vinst = gpuobj->im_backing->bo.mem.start << PAGE_SHIFT;
return 0;
}
@@ -84,11 +83,11 @@ nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
pte = gpuobj->im_pramin->start >> 12;
pte_end = (gpuobj->im_pramin->size >> 12) + pte;
- vram = gpuobj->im_backing_start;
+ vram = gpuobj->vinst;
NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
gpuobj->im_pramin->start, pte, pte_end);
- NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
+ NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst);
while (pte < pte_end) {
nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1);
@@ -134,7 +133,7 @@ void
nvc0_instmem_flush(struct drm_device *dev)
{
nv_wr32(dev, 0x070000, 1);
- if (!nv_wait(0x070000, 0x00000002, 0x00000000))
+ if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000))
NV_ERROR(dev, "PRAMIN flush timeout\n");
}
@@ -221,10 +220,6 @@ nvc0_instmem_init(struct drm_device *dev)
return -ENOMEM;
}
- /*XXX: incorrect, but needed to make hash func "work" */
- dev_priv->ramht_offset = 0x10000;
- dev_priv->ramht_bits = 9;
- dev_priv->ramht_size = (1 << dev_priv->ramht_bits) * 8;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvreg.h b/drivers/gpu/drm/nouveau/nvreg.h
index ad64673ace1f..881f8a585613 100644
--- a/drivers/gpu/drm/nouveau/nvreg.h
+++ b/drivers/gpu/drm/nouveau/nvreg.h
@@ -263,6 +263,7 @@
# define NV_CIO_CRE_HCUR_ADDR1_ADR 7:2
# define NV_CIO_CRE_LCD__INDEX 0x33
# define NV_CIO_CRE_LCD_LCD_SELECT 0:0
+# define NV_CIO_CRE_LCD_ROUTE_MASK 0x3b
# define NV_CIO_CRE_DDC0_STATUS__INDEX 0x36
# define NV_CIO_CRE_DDC0_WR__INDEX 0x37
# define NV_CIO_CRE_ILACE__INDEX 0x39 /* interlace */
diff --git a/drivers/gpu/drm/r128/r128_drv.c b/drivers/gpu/drm/r128/r128_drv.c
index d42c76c23714..18c3c71e41b1 100644
--- a/drivers/gpu/drm/r128/r128_drv.c
+++ b/drivers/gpu/drm/r128/r128_drv.c
@@ -56,8 +56,6 @@ static struct drm_driver driver = {
.irq_uninstall = r128_driver_irq_uninstall,
.irq_handler = r128_driver_irq_handler,
.reclaim_buffers = drm_core_reclaim_buffers,
- .get_map_ofs = drm_core_get_map_ofs,
- .get_reg_ofs = drm_core_get_reg_ofs,
.ioctls = r128_ioctls,
.dma_ioctl = r128_cce_buffers,
.fops = {
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index aebe00875041..6cae4f2028d2 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -65,7 +65,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \
r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \
r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \
- evergreen.o evergreen_cs.o
+ evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o
radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index cd0290f946cf..df2b6f2b35f8 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -398,65 +398,76 @@ static void atombios_disable_ss(struct drm_crtc *crtc)
union atom_enable_ss {
- ENABLE_LVDS_SS_PARAMETERS legacy;
+ ENABLE_LVDS_SS_PARAMETERS lvds_ss;
+ ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2;
ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
+ ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2;
};
-static void atombios_enable_ss(struct drm_crtc *crtc)
+static void atombios_crtc_program_ss(struct drm_crtc *crtc,
+ int enable,
+ int pll_id,
+ struct radeon_atom_ss *ss)
{
- struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
- struct drm_encoder *encoder = NULL;
- struct radeon_encoder *radeon_encoder = NULL;
- struct radeon_encoder_atom_dig *dig = NULL;
int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
union atom_enable_ss args;
- uint16_t percentage = 0;
- uint8_t type = 0, step = 0, delay = 0, range = 0;
- /* XXX add ss support for DCE4 */
- if (ASIC_IS_DCE4(rdev))
- return;
+ memset(&args, 0, sizeof(args));
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- if (encoder->crtc == crtc) {
- radeon_encoder = to_radeon_encoder(encoder);
- /* only enable spread spectrum on LVDS */
- if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
- dig = radeon_encoder->enc_priv;
- if (dig && dig->ss) {
- percentage = dig->ss->percentage;
- type = dig->ss->type;
- step = dig->ss->step;
- delay = dig->ss->delay;
- range = dig->ss->range;
- } else
- return;
- } else
- return;
+ if (ASIC_IS_DCE4(rdev)) {
+ args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
+ args.v2.ucSpreadSpectrumType = ss->type;
+ switch (pll_id) {
+ case ATOM_PPLL1:
+ args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL;
+ args.v2.usSpreadSpectrumAmount = ss->amount;
+ args.v2.usSpreadSpectrumStep = ss->step;
+ break;
+ case ATOM_PPLL2:
+ args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL;
+ args.v2.usSpreadSpectrumAmount = ss->amount;
+ args.v2.usSpreadSpectrumStep = ss->step;
break;
+ case ATOM_DCPLL:
+ args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL;
+ args.v2.usSpreadSpectrumAmount = 0;
+ args.v2.usSpreadSpectrumStep = 0;
+ break;
+ case ATOM_PPLL_INVALID:
+ return;
}
- }
-
- if (!radeon_encoder)
- return;
-
- memset(&args, 0, sizeof(args));
- if (ASIC_IS_AVIVO(rdev)) {
- args.v1.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
- args.v1.ucSpreadSpectrumType = type;
- args.v1.ucSpreadSpectrumStep = step;
- args.v1.ucSpreadSpectrumDelay = delay;
- args.v1.ucSpreadSpectrumRange = range;
- args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
- args.v1.ucEnable = ATOM_ENABLE;
+ args.v2.ucEnable = enable;
+ } else if (ASIC_IS_DCE3(rdev)) {
+ args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
+ args.v1.ucSpreadSpectrumType = ss->type;
+ args.v1.ucSpreadSpectrumStep = ss->step;
+ args.v1.ucSpreadSpectrumDelay = ss->delay;
+ args.v1.ucSpreadSpectrumRange = ss->range;
+ args.v1.ucPpll = pll_id;
+ args.v1.ucEnable = enable;
+ } else if (ASIC_IS_AVIVO(rdev)) {
+ if (enable == ATOM_DISABLE) {
+ atombios_disable_ss(crtc);
+ return;
+ }
+ args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
+ args.lvds_ss_2.ucSpreadSpectrumType = ss->type;
+ args.lvds_ss_2.ucSpreadSpectrumStep = ss->step;
+ args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay;
+ args.lvds_ss_2.ucSpreadSpectrumRange = ss->range;
+ args.lvds_ss_2.ucEnable = enable;
} else {
- args.legacy.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
- args.legacy.ucSpreadSpectrumType = type;
- args.legacy.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2;
- args.legacy.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4;
- args.legacy.ucEnable = ATOM_ENABLE;
+ if (enable == ATOM_DISABLE) {
+ atombios_disable_ss(crtc);
+ return;
+ }
+ args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
+ args.lvds_ss.ucSpreadSpectrumType = ss->type;
+ args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2;
+ args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4;
+ args.lvds_ss.ucEnable = enable;
}
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
@@ -468,7 +479,9 @@ union adjust_pixel_clock {
static u32 atombios_adjust_pll(struct drm_crtc *crtc,
struct drm_display_mode *mode,
- struct radeon_pll *pll)
+ struct radeon_pll *pll,
+ bool ss_enabled,
+ struct radeon_atom_ss *ss)
{
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
@@ -482,19 +495,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
/* reset the pll flags */
pll->flags = 0;
- /* select the PLL algo */
- if (ASIC_IS_AVIVO(rdev)) {
- if (radeon_new_pll == 0)
- pll->algo = PLL_ALGO_LEGACY;
- else
- pll->algo = PLL_ALGO_NEW;
- } else {
- if (radeon_new_pll == 1)
- pll->algo = PLL_ALGO_NEW;
- else
- pll->algo = PLL_ALGO_LEGACY;
- }
-
if (ASIC_IS_AVIVO(rdev)) {
if ((rdev->family == CHIP_RS600) ||
(rdev->family == CHIP_RS690) ||
@@ -531,29 +531,22 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
}
}
+ /* use recommended ref_div for ss */
+ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+ if (ss_enabled) {
+ if (ss->refdiv) {
+ pll->flags |= RADEON_PLL_USE_REF_DIV;
+ pll->reference_div = ss->refdiv;
+ }
+ }
+ }
+
if (ASIC_IS_AVIVO(rdev)) {
/* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
adjusted_clock = mode->clock * 2;
- if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
- pll->algo = PLL_ALGO_LEGACY;
+ if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER;
- }
- /* There is some evidence (often anecdotal) that RV515/RV620 LVDS
- * (on some boards at least) prefers the legacy algo. I'm not
- * sure whether this should handled generically or on a
- * case-by-case quirk basis. Both algos should work fine in the
- * majority of cases.
- */
- if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) &&
- ((rdev->family == CHIP_RV515) ||
- (rdev->family == CHIP_RV620))) {
- /* allow the user to overrride just in case */
- if (radeon_new_pll == 1)
- pll->algo = PLL_ALGO_NEW;
- else
- pll->algo = PLL_ALGO_LEGACY;
- }
} else {
if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
@@ -589,9 +582,9 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
args.v1.ucTransmitterID = radeon_encoder->encoder_id;
args.v1.ucEncodeMode = encoder_mode;
if (encoder_mode == ATOM_ENCODER_MODE_DP) {
- /* may want to enable SS on DP eventually */
- /* args.v1.ucConfig |=
- ADJUST_DISPLAY_CONFIG_SS_ENABLE;*/
+ if (ss_enabled)
+ args.v1.ucConfig |=
+ ADJUST_DISPLAY_CONFIG_SS_ENABLE;
} else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) {
args.v1.ucConfig |=
ADJUST_DISPLAY_CONFIG_SS_ENABLE;
@@ -608,11 +601,10 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
args.v3.sInput.ucDispPllConfig = 0;
if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-
if (encoder_mode == ATOM_ENCODER_MODE_DP) {
- /* may want to enable SS on DP/eDP eventually */
- /*args.v3.sInput.ucDispPllConfig |=
- DISPPLL_CONFIG_SS_ENABLE;*/
+ if (ss_enabled)
+ args.v3.sInput.ucDispPllConfig |=
+ DISPPLL_CONFIG_SS_ENABLE;
args.v3.sInput.ucDispPllConfig |=
DISPPLL_CONFIG_COHERENT_MODE;
/* 16200 or 27000 */
@@ -632,17 +624,17 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
}
} else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
if (encoder_mode == ATOM_ENCODER_MODE_DP) {
- /* may want to enable SS on DP/eDP eventually */
- /*args.v3.sInput.ucDispPllConfig |=
- DISPPLL_CONFIG_SS_ENABLE;*/
+ if (ss_enabled)
+ args.v3.sInput.ucDispPllConfig |=
+ DISPPLL_CONFIG_SS_ENABLE;
args.v3.sInput.ucDispPllConfig |=
DISPPLL_CONFIG_COHERENT_MODE;
/* 16200 or 27000 */
args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
} else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) {
- /* want to enable SS on LVDS eventually */
- /*args.v3.sInput.ucDispPllConfig |=
- DISPPLL_CONFIG_SS_ENABLE;*/
+ if (ss_enabled)
+ args.v3.sInput.ucDispPllConfig |=
+ DISPPLL_CONFIG_SS_ENABLE;
} else {
if (mode->clock > 165000)
args.v3.sInput.ucDispPllConfig |=
@@ -816,6 +808,8 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
struct radeon_pll *pll;
u32 adjusted_clock;
int encoder_mode = 0;
+ struct radeon_atom_ss ss;
+ bool ss_enabled = false;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc == crtc) {
@@ -842,25 +836,123 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
break;
}
+ if (radeon_encoder->active_device &
+ (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) {
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ struct drm_connector *connector =
+ radeon_get_connector_for_encoder(encoder);
+ struct radeon_connector *radeon_connector =
+ to_radeon_connector(connector);
+ struct radeon_connector_atom_dig *dig_connector =
+ radeon_connector->con_priv;
+ int dp_clock;
+
+ switch (encoder_mode) {
+ case ATOM_ENCODER_MODE_DP:
+ /* DP/eDP */
+ dp_clock = dig_connector->dp_clock / 10;
+ if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
+ if (ASIC_IS_DCE4(rdev))
+ ss_enabled =
+ radeon_atombios_get_asic_ss_info(rdev, &ss,
+ dig->lcd_ss_id,
+ dp_clock);
+ else
+ ss_enabled =
+ radeon_atombios_get_ppll_ss_info(rdev, &ss,
+ dig->lcd_ss_id);
+ } else {
+ if (ASIC_IS_DCE4(rdev))
+ ss_enabled =
+ radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_SS_ON_DP,
+ dp_clock);
+ else {
+ if (dp_clock == 16200) {
+ ss_enabled =
+ radeon_atombios_get_ppll_ss_info(rdev, &ss,
+ ATOM_DP_SS_ID2);
+ if (!ss_enabled)
+ ss_enabled =
+ radeon_atombios_get_ppll_ss_info(rdev, &ss,
+ ATOM_DP_SS_ID1);
+ } else
+ ss_enabled =
+ radeon_atombios_get_ppll_ss_info(rdev, &ss,
+ ATOM_DP_SS_ID1);
+ }
+ }
+ break;
+ case ATOM_ENCODER_MODE_LVDS:
+ if (ASIC_IS_DCE4(rdev))
+ ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss,
+ dig->lcd_ss_id,
+ mode->clock / 10);
+ else
+ ss_enabled = radeon_atombios_get_ppll_ss_info(rdev, &ss,
+ dig->lcd_ss_id);
+ break;
+ case ATOM_ENCODER_MODE_DVI:
+ if (ASIC_IS_DCE4(rdev))
+ ss_enabled =
+ radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_SS_ON_TMDS,
+ mode->clock / 10);
+ break;
+ case ATOM_ENCODER_MODE_HDMI:
+ if (ASIC_IS_DCE4(rdev))
+ ss_enabled =
+ radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_SS_ON_HDMI,
+ mode->clock / 10);
+ break;
+ default:
+ break;
+ }
+ }
+
/* adjust pixel clock as needed */
- adjusted_clock = atombios_adjust_pll(crtc, mode, pll);
+ adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss);
radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
&ref_div, &post_div);
+ atombios_crtc_program_ss(crtc, ATOM_DISABLE, radeon_crtc->pll_id, &ss);
+
atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
encoder_mode, radeon_encoder->encoder_id, mode->clock,
ref_div, fb_div, frac_fb_div, post_div);
+ if (ss_enabled) {
+ /* calculate ss amount and step size */
+ if (ASIC_IS_DCE4(rdev)) {
+ u32 step_size;
+ u32 amount = (((fb_div * 10) + frac_fb_div) * ss.percentage) / 10000;
+ ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;
+ ss.amount |= ((amount - (ss.amount * 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
+ ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;
+ if (ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD)
+ step_size = (4 * amount * ref_div * (ss.rate * 2048)) /
+ (125 * 25 * pll->reference_freq / 100);
+ else
+ step_size = (2 * amount * ref_div * (ss.rate * 2048)) /
+ (125 * 25 * pll->reference_freq / 100);
+ ss.step = step_size;
+ }
+
+ atombios_crtc_program_ss(crtc, ATOM_ENABLE, radeon_crtc->pll_id, &ss);
+ }
}
-static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
+static int evergreen_crtc_do_set_base(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y, int atomic)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_framebuffer *radeon_fb;
+ struct drm_framebuffer *target_fb;
struct drm_gem_object *obj;
struct radeon_bo *rbo;
uint64_t fb_location;
@@ -868,28 +960,43 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
int r;
/* no fb bound */
- if (!crtc->fb) {
+ if (!atomic && !crtc->fb) {
DRM_DEBUG_KMS("No FB bound\n");
return 0;
}
- radeon_fb = to_radeon_framebuffer(crtc->fb);
+ if (atomic) {
+ radeon_fb = to_radeon_framebuffer(fb);
+ target_fb = fb;
+ }
+ else {
+ radeon_fb = to_radeon_framebuffer(crtc->fb);
+ target_fb = crtc->fb;
+ }
- /* Pin framebuffer & get tilling informations */
+ /* If atomic, assume fb object is pinned & idle & fenced and
+ * just update base pointers
+ */
obj = radeon_fb->obj;
rbo = obj->driver_private;
r = radeon_bo_reserve(rbo, false);
if (unlikely(r != 0))
return r;
- r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
- if (unlikely(r != 0)) {
- radeon_bo_unreserve(rbo);
- return -EINVAL;
+
+ if (atomic)
+ fb_location = radeon_bo_gpu_offset(rbo);
+ else {
+ r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
+ if (unlikely(r != 0)) {
+ radeon_bo_unreserve(rbo);
+ return -EINVAL;
+ }
}
+
radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
radeon_bo_unreserve(rbo);
- switch (crtc->fb->bits_per_pixel) {
+ switch (target_fb->bits_per_pixel) {
case 8:
fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) |
EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED));
@@ -909,7 +1016,7 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
break;
default:
DRM_ERROR("Unsupported screen depth %d\n",
- crtc->fb->bits_per_pixel);
+ target_fb->bits_per_pixel);
return -EINVAL;
}
@@ -955,10 +1062,10 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0);
WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0);
- WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
- WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
+ WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width);
+ WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height);
- fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
+ fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8);
WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
@@ -977,8 +1084,8 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
else
WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
- if (old_fb && old_fb != crtc->fb) {
- radeon_fb = to_radeon_framebuffer(old_fb);
+ if (!atomic && fb && fb != crtc->fb) {
+ radeon_fb = to_radeon_framebuffer(fb);
rbo = radeon_fb->obj->driver_private;
r = radeon_bo_reserve(rbo, false);
if (unlikely(r != 0))
@@ -993,8 +1100,9 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
return 0;
}
-static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
+static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y, int atomic)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
@@ -1002,33 +1110,48 @@ static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct radeon_framebuffer *radeon_fb;
struct drm_gem_object *obj;
struct radeon_bo *rbo;
+ struct drm_framebuffer *target_fb;
uint64_t fb_location;
uint32_t fb_format, fb_pitch_pixels, tiling_flags;
int r;
/* no fb bound */
- if (!crtc->fb) {
+ if (!atomic && !crtc->fb) {
DRM_DEBUG_KMS("No FB bound\n");
return 0;
}
- radeon_fb = to_radeon_framebuffer(crtc->fb);
+ if (atomic) {
+ radeon_fb = to_radeon_framebuffer(fb);
+ target_fb = fb;
+ }
+ else {
+ radeon_fb = to_radeon_framebuffer(crtc->fb);
+ target_fb = crtc->fb;
+ }
- /* Pin framebuffer & get tilling informations */
obj = radeon_fb->obj;
rbo = obj->driver_private;
r = radeon_bo_reserve(rbo, false);
if (unlikely(r != 0))
return r;
- r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
- if (unlikely(r != 0)) {
- radeon_bo_unreserve(rbo);
- return -EINVAL;
+
+ /* If atomic, assume fb object is pinned & idle & fenced and
+ * just update base pointers
+ */
+ if (atomic)
+ fb_location = radeon_bo_gpu_offset(rbo);
+ else {
+ r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
+ if (unlikely(r != 0)) {
+ radeon_bo_unreserve(rbo);
+ return -EINVAL;
+ }
}
radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
radeon_bo_unreserve(rbo);
- switch (crtc->fb->bits_per_pixel) {
+ switch (target_fb->bits_per_pixel) {
case 8:
fb_format =
AVIVO_D1GRPH_CONTROL_DEPTH_8BPP |
@@ -1052,7 +1175,7 @@ static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
break;
default:
DRM_ERROR("Unsupported screen depth %d\n",
- crtc->fb->bits_per_pixel);
+ target_fb->bits_per_pixel);
return -EINVAL;
}
@@ -1093,10 +1216,10 @@ static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0);
WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0);
- WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
- WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
+ WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width);
+ WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height);
- fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
+ fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8);
WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
@@ -1115,8 +1238,8 @@ static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
else
WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
- if (old_fb && old_fb != crtc->fb) {
- radeon_fb = to_radeon_framebuffer(old_fb);
+ if (!atomic && fb && fb != crtc->fb) {
+ radeon_fb = to_radeon_framebuffer(fb);
rbo = radeon_fb->obj->driver_private;
r = radeon_bo_reserve(rbo, false);
if (unlikely(r != 0))
@@ -1138,11 +1261,26 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct radeon_device *rdev = dev->dev_private;
if (ASIC_IS_DCE4(rdev))
- return evergreen_crtc_set_base(crtc, x, y, old_fb);
+ return evergreen_crtc_do_set_base(crtc, old_fb, x, y, 0);
else if (ASIC_IS_AVIVO(rdev))
- return avivo_crtc_set_base(crtc, x, y, old_fb);
+ return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0);
else
- return radeon_crtc_set_base(crtc, x, y, old_fb);
+ return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0);
+}
+
+int atombios_crtc_set_base_atomic(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y, enum mode_set_atomic state)
+{
+ struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
+
+ if (ASIC_IS_DCE4(rdev))
+ return evergreen_crtc_do_set_base(crtc, fb, x, y, 1);
+ else if (ASIC_IS_AVIVO(rdev))
+ return avivo_crtc_do_set_base(crtc, fb, x, y, 1);
+ else
+ return radeon_crtc_do_set_base(crtc, fb, x, y, 1);
}
/* properly set additional regs when using atombios */
@@ -1230,12 +1368,19 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
}
}
- atombios_disable_ss(crtc);
/* always set DCPLL */
- if (ASIC_IS_DCE4(rdev))
+ if (ASIC_IS_DCE4(rdev)) {
+ struct radeon_atom_ss ss;
+ bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_SS_ON_DCPLL,
+ rdev->clock.default_dispclk);
+ if (ss_enabled)
+ atombios_crtc_program_ss(crtc, ATOM_DISABLE, ATOM_DCPLL, &ss);
atombios_crtc_set_dcpll(crtc);
+ if (ss_enabled)
+ atombios_crtc_program_ss(crtc, ATOM_ENABLE, ATOM_DCPLL, &ss);
+ }
atombios_crtc_set_pll(crtc, adjusted_mode);
- atombios_enable_ss(crtc);
if (ASIC_IS_DCE4(rdev))
atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
@@ -1311,6 +1456,7 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
.mode_fixup = atombios_crtc_mode_fixup,
.mode_set = atombios_crtc_mode_set,
.mode_set_base = atombios_crtc_set_base,
+ .mode_set_base_atomic = atombios_crtc_set_base_atomic,
.prepare = atombios_crtc_prepare,
.commit = atombios_crtc_commit,
.load_lut = radeon_crtc_load_lut,
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 2f93d46ae69a..f12a5b3ec050 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -32,6 +32,7 @@
#include "atom.h"
#include "avivod.h"
#include "evergreen_reg.h"
+#include "evergreen_blit_shaders.h"
#define EVERGREEN_PFP_UCODE_SIZE 1120
#define EVERGREEN_PM4_UCODE_SIZE 1376
@@ -284,9 +285,444 @@ void evergreen_hpd_fini(struct radeon_device *rdev)
}
}
+/* watermark setup */
+
+static u32 evergreen_line_buffer_adjust(struct radeon_device *rdev,
+ struct radeon_crtc *radeon_crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *other_mode)
+{
+ u32 tmp = 0;
+ /*
+ * Line Buffer Setup
+ * There are 3 line buffers, each one shared by 2 display controllers.
+ * DC_LB_MEMORY_SPLIT controls how that line buffer is shared between
+ * the display controllers. The paritioning is done via one of four
+ * preset allocations specified in bits 2:0:
+ * first display controller
+ * 0 - first half of lb (3840 * 2)
+ * 1 - first 3/4 of lb (5760 * 2)
+ * 2 - whole lb (7680 * 2)
+ * 3 - first 1/4 of lb (1920 * 2)
+ * second display controller
+ * 4 - second half of lb (3840 * 2)
+ * 5 - second 3/4 of lb (5760 * 2)
+ * 6 - whole lb (7680 * 2)
+ * 7 - last 1/4 of lb (1920 * 2)
+ */
+ if (mode && other_mode) {
+ if (mode->hdisplay > other_mode->hdisplay) {
+ if (mode->hdisplay > 2560)
+ tmp = 1; /* 3/4 */
+ else
+ tmp = 0; /* 1/2 */
+ } else if (other_mode->hdisplay > mode->hdisplay) {
+ if (other_mode->hdisplay > 2560)
+ tmp = 3; /* 1/4 */
+ else
+ tmp = 0; /* 1/2 */
+ } else
+ tmp = 0; /* 1/2 */
+ } else if (mode)
+ tmp = 2; /* whole */
+ else if (other_mode)
+ tmp = 3; /* 1/4 */
+
+ /* second controller of the pair uses second half of the lb */
+ if (radeon_crtc->crtc_id % 2)
+ tmp += 4;
+ WREG32(DC_LB_MEMORY_SPLIT + radeon_crtc->crtc_offset, tmp);
+
+ switch (tmp) {
+ case 0:
+ case 4:
+ default:
+ return 3840 * 2;
+ case 1:
+ case 5:
+ return 5760 * 2;
+ case 2:
+ case 6:
+ return 7680 * 2;
+ case 3:
+ case 7:
+ return 1920 * 2;
+ }
+}
+
+static u32 evergreen_get_number_of_dram_channels(struct radeon_device *rdev)
+{
+ u32 tmp = RREG32(MC_SHARED_CHMAP);
+
+ switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+ case 0:
+ default:
+ return 1;
+ case 1:
+ return 2;
+ case 2:
+ return 4;
+ case 3:
+ return 8;
+ }
+}
+
+struct evergreen_wm_params {
+ u32 dram_channels; /* number of dram channels */
+ u32 yclk; /* bandwidth per dram data pin in kHz */
+ u32 sclk; /* engine clock in kHz */
+ u32 disp_clk; /* display clock in kHz */
+ u32 src_width; /* viewport width */
+ u32 active_time; /* active display time in ns */
+ u32 blank_time; /* blank time in ns */
+ bool interlaced; /* mode is interlaced */
+ fixed20_12 vsc; /* vertical scale ratio */
+ u32 num_heads; /* number of active crtcs */
+ u32 bytes_per_pixel; /* bytes per pixel display + overlay */
+ u32 lb_size; /* line buffer allocated to pipe */
+ u32 vtaps; /* vertical scaler taps */
+};
+
+static u32 evergreen_dram_bandwidth(struct evergreen_wm_params *wm)
+{
+ /* Calculate DRAM Bandwidth and the part allocated to display. */
+ fixed20_12 dram_efficiency; /* 0.7 */
+ fixed20_12 yclk, dram_channels, bandwidth;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1000);
+ yclk.full = dfixed_const(wm->yclk);
+ yclk.full = dfixed_div(yclk, a);
+ dram_channels.full = dfixed_const(wm->dram_channels * 4);
+ a.full = dfixed_const(10);
+ dram_efficiency.full = dfixed_const(7);
+ dram_efficiency.full = dfixed_div(dram_efficiency, a);
+ bandwidth.full = dfixed_mul(dram_channels, yclk);
+ bandwidth.full = dfixed_mul(bandwidth, dram_efficiency);
+
+ return dfixed_trunc(bandwidth);
+}
+
+static u32 evergreen_dram_bandwidth_for_display(struct evergreen_wm_params *wm)
+{
+ /* Calculate DRAM Bandwidth and the part allocated to display. */
+ fixed20_12 disp_dram_allocation; /* 0.3 to 0.7 */
+ fixed20_12 yclk, dram_channels, bandwidth;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1000);
+ yclk.full = dfixed_const(wm->yclk);
+ yclk.full = dfixed_div(yclk, a);
+ dram_channels.full = dfixed_const(wm->dram_channels * 4);
+ a.full = dfixed_const(10);
+ disp_dram_allocation.full = dfixed_const(3); /* XXX worse case value 0.3 */
+ disp_dram_allocation.full = dfixed_div(disp_dram_allocation, a);
+ bandwidth.full = dfixed_mul(dram_channels, yclk);
+ bandwidth.full = dfixed_mul(bandwidth, disp_dram_allocation);
+
+ return dfixed_trunc(bandwidth);
+}
+
+static u32 evergreen_data_return_bandwidth(struct evergreen_wm_params *wm)
+{
+ /* Calculate the display Data return Bandwidth */
+ fixed20_12 return_efficiency; /* 0.8 */
+ fixed20_12 sclk, bandwidth;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1000);
+ sclk.full = dfixed_const(wm->sclk);
+ sclk.full = dfixed_div(sclk, a);
+ a.full = dfixed_const(10);
+ return_efficiency.full = dfixed_const(8);
+ return_efficiency.full = dfixed_div(return_efficiency, a);
+ a.full = dfixed_const(32);
+ bandwidth.full = dfixed_mul(a, sclk);
+ bandwidth.full = dfixed_mul(bandwidth, return_efficiency);
+
+ return dfixed_trunc(bandwidth);
+}
+
+static u32 evergreen_dmif_request_bandwidth(struct evergreen_wm_params *wm)
+{
+ /* Calculate the DMIF Request Bandwidth */
+ fixed20_12 disp_clk_request_efficiency; /* 0.8 */
+ fixed20_12 disp_clk, bandwidth;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1000);
+ disp_clk.full = dfixed_const(wm->disp_clk);
+ disp_clk.full = dfixed_div(disp_clk, a);
+ a.full = dfixed_const(10);
+ disp_clk_request_efficiency.full = dfixed_const(8);
+ disp_clk_request_efficiency.full = dfixed_div(disp_clk_request_efficiency, a);
+ a.full = dfixed_const(32);
+ bandwidth.full = dfixed_mul(a, disp_clk);
+ bandwidth.full = dfixed_mul(bandwidth, disp_clk_request_efficiency);
+
+ return dfixed_trunc(bandwidth);
+}
+
+static u32 evergreen_available_bandwidth(struct evergreen_wm_params *wm)
+{
+ /* Calculate the Available bandwidth. Display can use this temporarily but not in average. */
+ u32 dram_bandwidth = evergreen_dram_bandwidth(wm);
+ u32 data_return_bandwidth = evergreen_data_return_bandwidth(wm);
+ u32 dmif_req_bandwidth = evergreen_dmif_request_bandwidth(wm);
+
+ return min(dram_bandwidth, min(data_return_bandwidth, dmif_req_bandwidth));
+}
+
+static u32 evergreen_average_bandwidth(struct evergreen_wm_params *wm)
+{
+ /* Calculate the display mode Average Bandwidth
+ * DisplayMode should contain the source and destination dimensions,
+ * timing, etc.
+ */
+ fixed20_12 bpp;
+ fixed20_12 line_time;
+ fixed20_12 src_width;
+ fixed20_12 bandwidth;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1000);
+ line_time.full = dfixed_const(wm->active_time + wm->blank_time);
+ line_time.full = dfixed_div(line_time, a);
+ bpp.full = dfixed_const(wm->bytes_per_pixel);
+ src_width.full = dfixed_const(wm->src_width);
+ bandwidth.full = dfixed_mul(src_width, bpp);
+ bandwidth.full = dfixed_mul(bandwidth, wm->vsc);
+ bandwidth.full = dfixed_div(bandwidth, line_time);
+
+ return dfixed_trunc(bandwidth);
+}
+
+static u32 evergreen_latency_watermark(struct evergreen_wm_params *wm)
+{
+ /* First calcualte the latency in ns */
+ u32 mc_latency = 2000; /* 2000 ns. */
+ u32 available_bandwidth = evergreen_available_bandwidth(wm);
+ u32 worst_chunk_return_time = (512 * 8 * 1000) / available_bandwidth;
+ u32 cursor_line_pair_return_time = (128 * 4 * 1000) / available_bandwidth;
+ u32 dc_latency = 40000000 / wm->disp_clk; /* dc pipe latency */
+ u32 other_heads_data_return_time = ((wm->num_heads + 1) * worst_chunk_return_time) +
+ (wm->num_heads * cursor_line_pair_return_time);
+ u32 latency = mc_latency + other_heads_data_return_time + dc_latency;
+ u32 max_src_lines_per_dst_line, lb_fill_bw, line_fill_time;
+ fixed20_12 a, b, c;
+
+ if (wm->num_heads == 0)
+ return 0;
+
+ a.full = dfixed_const(2);
+ b.full = dfixed_const(1);
+ if ((wm->vsc.full > a.full) ||
+ ((wm->vsc.full > b.full) && (wm->vtaps >= 3)) ||
+ (wm->vtaps >= 5) ||
+ ((wm->vsc.full >= a.full) && wm->interlaced))
+ max_src_lines_per_dst_line = 4;
+ else
+ max_src_lines_per_dst_line = 2;
+
+ a.full = dfixed_const(available_bandwidth);
+ b.full = dfixed_const(wm->num_heads);
+ a.full = dfixed_div(a, b);
+
+ b.full = dfixed_const(1000);
+ c.full = dfixed_const(wm->disp_clk);
+ b.full = dfixed_div(c, b);
+ c.full = dfixed_const(wm->bytes_per_pixel);
+ b.full = dfixed_mul(b, c);
+
+ lb_fill_bw = min(dfixed_trunc(a), dfixed_trunc(b));
+
+ a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
+ b.full = dfixed_const(1000);
+ c.full = dfixed_const(lb_fill_bw);
+ b.full = dfixed_div(c, b);
+ a.full = dfixed_div(a, b);
+ line_fill_time = dfixed_trunc(a);
+
+ if (line_fill_time < wm->active_time)
+ return latency;
+ else
+ return latency + (line_fill_time - wm->active_time);
+
+}
+
+static bool evergreen_average_bandwidth_vs_dram_bandwidth_for_display(struct evergreen_wm_params *wm)
+{
+ if (evergreen_average_bandwidth(wm) <=
+ (evergreen_dram_bandwidth_for_display(wm) / wm->num_heads))
+ return true;
+ else
+ return false;
+};
+
+static bool evergreen_average_bandwidth_vs_available_bandwidth(struct evergreen_wm_params *wm)
+{
+ if (evergreen_average_bandwidth(wm) <=
+ (evergreen_available_bandwidth(wm) / wm->num_heads))
+ return true;
+ else
+ return false;
+};
+
+static bool evergreen_check_latency_hiding(struct evergreen_wm_params *wm)
+{
+ u32 lb_partitions = wm->lb_size / wm->src_width;
+ u32 line_time = wm->active_time + wm->blank_time;
+ u32 latency_tolerant_lines;
+ u32 latency_hiding;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1);
+ if (wm->vsc.full > a.full)
+ latency_tolerant_lines = 1;
+ else {
+ if (lb_partitions <= (wm->vtaps + 1))
+ latency_tolerant_lines = 1;
+ else
+ latency_tolerant_lines = 2;
+ }
+
+ latency_hiding = (latency_tolerant_lines * line_time + wm->blank_time);
+
+ if (evergreen_latency_watermark(wm) <= latency_hiding)
+ return true;
+ else
+ return false;
+}
+
+static void evergreen_program_watermarks(struct radeon_device *rdev,
+ struct radeon_crtc *radeon_crtc,
+ u32 lb_size, u32 num_heads)
+{
+ struct drm_display_mode *mode = &radeon_crtc->base.mode;
+ struct evergreen_wm_params wm;
+ u32 pixel_period;
+ u32 line_time = 0;
+ u32 latency_watermark_a = 0, latency_watermark_b = 0;
+ u32 priority_a_mark = 0, priority_b_mark = 0;
+ u32 priority_a_cnt = PRIORITY_OFF;
+ u32 priority_b_cnt = PRIORITY_OFF;
+ u32 pipe_offset = radeon_crtc->crtc_id * 16;
+ u32 tmp, arb_control3;
+ fixed20_12 a, b, c;
+
+ if (radeon_crtc->base.enabled && num_heads && mode) {
+ pixel_period = 1000000 / (u32)mode->clock;
+ line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
+ priority_a_cnt = 0;
+ priority_b_cnt = 0;
+
+ wm.yclk = rdev->pm.current_mclk * 10;
+ wm.sclk = rdev->pm.current_sclk * 10;
+ wm.disp_clk = mode->clock;
+ wm.src_width = mode->crtc_hdisplay;
+ wm.active_time = mode->crtc_hdisplay * pixel_period;
+ wm.blank_time = line_time - wm.active_time;
+ wm.interlaced = false;
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ wm.interlaced = true;
+ wm.vsc = radeon_crtc->vsc;
+ wm.vtaps = 1;
+ if (radeon_crtc->rmx_type != RMX_OFF)
+ wm.vtaps = 2;
+ wm.bytes_per_pixel = 4; /* XXX: get this from fb config */
+ wm.lb_size = lb_size;
+ wm.dram_channels = evergreen_get_number_of_dram_channels(rdev);
+ wm.num_heads = num_heads;
+
+ /* set for high clocks */
+ latency_watermark_a = min(evergreen_latency_watermark(&wm), (u32)65535);
+ /* set for low clocks */
+ /* wm.yclk = low clk; wm.sclk = low clk */
+ latency_watermark_b = min(evergreen_latency_watermark(&wm), (u32)65535);
+
+ /* possibly force display priority to high */
+ /* should really do this at mode validation time... */
+ if (!evergreen_average_bandwidth_vs_dram_bandwidth_for_display(&wm) ||
+ !evergreen_average_bandwidth_vs_available_bandwidth(&wm) ||
+ !evergreen_check_latency_hiding(&wm) ||
+ (rdev->disp_priority == 2)) {
+ DRM_INFO("force priority to high\n");
+ priority_a_cnt |= PRIORITY_ALWAYS_ON;
+ priority_b_cnt |= PRIORITY_ALWAYS_ON;
+ }
+
+ a.full = dfixed_const(1000);
+ b.full = dfixed_const(mode->clock);
+ b.full = dfixed_div(b, a);
+ c.full = dfixed_const(latency_watermark_a);
+ c.full = dfixed_mul(c, b);
+ c.full = dfixed_mul(c, radeon_crtc->hsc);
+ c.full = dfixed_div(c, a);
+ a.full = dfixed_const(16);
+ c.full = dfixed_div(c, a);
+ priority_a_mark = dfixed_trunc(c);
+ priority_a_cnt |= priority_a_mark & PRIORITY_MARK_MASK;
+
+ a.full = dfixed_const(1000);
+ b.full = dfixed_const(mode->clock);
+ b.full = dfixed_div(b, a);
+ c.full = dfixed_const(latency_watermark_b);
+ c.full = dfixed_mul(c, b);
+ c.full = dfixed_mul(c, radeon_crtc->hsc);
+ c.full = dfixed_div(c, a);
+ a.full = dfixed_const(16);
+ c.full = dfixed_div(c, a);
+ priority_b_mark = dfixed_trunc(c);
+ priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK;
+ }
+
+ /* select wm A */
+ arb_control3 = RREG32(PIPE0_ARBITRATION_CONTROL3 + pipe_offset);
+ tmp = arb_control3;
+ tmp &= ~LATENCY_WATERMARK_MASK(3);
+ tmp |= LATENCY_WATERMARK_MASK(1);
+ WREG32(PIPE0_ARBITRATION_CONTROL3 + pipe_offset, tmp);
+ WREG32(PIPE0_LATENCY_CONTROL + pipe_offset,
+ (LATENCY_LOW_WATERMARK(latency_watermark_a) |
+ LATENCY_HIGH_WATERMARK(line_time)));
+ /* select wm B */
+ tmp = RREG32(PIPE0_ARBITRATION_CONTROL3 + pipe_offset);
+ tmp &= ~LATENCY_WATERMARK_MASK(3);
+ tmp |= LATENCY_WATERMARK_MASK(2);
+ WREG32(PIPE0_ARBITRATION_CONTROL3 + pipe_offset, tmp);
+ WREG32(PIPE0_LATENCY_CONTROL + pipe_offset,
+ (LATENCY_LOW_WATERMARK(latency_watermark_b) |
+ LATENCY_HIGH_WATERMARK(line_time)));
+ /* restore original selection */
+ WREG32(PIPE0_ARBITRATION_CONTROL3 + pipe_offset, arb_control3);
+
+ /* write the priority marks */
+ WREG32(PRIORITY_A_CNT + radeon_crtc->crtc_offset, priority_a_cnt);
+ WREG32(PRIORITY_B_CNT + radeon_crtc->crtc_offset, priority_b_cnt);
+
+}
+
void evergreen_bandwidth_update(struct radeon_device *rdev)
{
- /* XXX */
+ struct drm_display_mode *mode0 = NULL;
+ struct drm_display_mode *mode1 = NULL;
+ u32 num_heads = 0, lb_size;
+ int i;
+
+ radeon_update_display_priority(rdev);
+
+ for (i = 0; i < rdev->num_crtc; i++) {
+ if (rdev->mode_info.crtcs[i]->base.enabled)
+ num_heads++;
+ }
+ for (i = 0; i < rdev->num_crtc; i += 2) {
+ mode0 = &rdev->mode_info.crtcs[i]->base.mode;
+ mode1 = &rdev->mode_info.crtcs[i+1]->base.mode;
+ lb_size = evergreen_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i], mode0, mode1);
+ evergreen_program_watermarks(rdev, rdev->mode_info.crtcs[i], lb_size, num_heads);
+ lb_size = evergreen_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i+1], mode1, mode0);
+ evergreen_program_watermarks(rdev, rdev->mode_info.crtcs[i+1], lb_size, num_heads);
+ }
}
static int evergreen_mc_wait_for_idle(struct radeon_device *rdev)
@@ -677,7 +1113,7 @@ static int evergreen_cp_load_microcode(struct radeon_device *rdev)
static int evergreen_cp_start(struct radeon_device *rdev)
{
- int r;
+ int r, i;
uint32_t cp_me;
r = radeon_ring_lock(rdev, 7);
@@ -697,16 +1133,39 @@ static int evergreen_cp_start(struct radeon_device *rdev)
cp_me = 0xff;
WREG32(CP_ME_CNTL, cp_me);
- r = radeon_ring_lock(rdev, 4);
+ r = radeon_ring_lock(rdev, evergreen_default_size + 15);
if (r) {
DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r);
return r;
}
- /* init some VGT regs */
- radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
- radeon_ring_write(rdev, (VGT_VERTEX_REUSE_BLOCK_CNTL - PACKET3_SET_CONTEXT_REG_START) >> 2);
- radeon_ring_write(rdev, 0xe);
- radeon_ring_write(rdev, 0x10);
+
+ /* setup clear context state */
+ radeon_ring_write(rdev, PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+ radeon_ring_write(rdev, PACKET3_PREAMBLE_BEGIN_CLEAR_STATE);
+
+ for (i = 0; i < evergreen_default_size; i++)
+ radeon_ring_write(rdev, evergreen_default_state[i]);
+
+ radeon_ring_write(rdev, PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+ radeon_ring_write(rdev, PACKET3_PREAMBLE_END_CLEAR_STATE);
+
+ /* set clear context state */
+ radeon_ring_write(rdev, PACKET3(PACKET3_CLEAR_STATE, 0));
+ radeon_ring_write(rdev, 0);
+
+ /* SQ_VTX_BASE_VTX_LOC */
+ radeon_ring_write(rdev, 0xc0026f00);
+ radeon_ring_write(rdev, 0x00000000);
+ radeon_ring_write(rdev, 0x00000000);
+ radeon_ring_write(rdev, 0x00000000);
+
+ /* Clear consts */
+ radeon_ring_write(rdev, 0xc0036f00);
+ radeon_ring_write(rdev, 0x00000bc4);
+ radeon_ring_write(rdev, 0xffffffff);
+ radeon_ring_write(rdev, 0xffffffff);
+ radeon_ring_write(rdev, 0xffffffff);
+
radeon_ring_unlock_commit(rdev);
return 0;
@@ -731,7 +1190,7 @@ int evergreen_cp_resume(struct radeon_device *rdev)
/* Set ring buffer size */
rb_bufsz = drm_order(rdev->cp.ring_size / 8);
- tmp = RB_NO_UPDATE | (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+ tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
#ifdef __BIG_ENDIAN
tmp |= BUF_SWAP_32BIT;
#endif
@@ -745,8 +1204,19 @@ int evergreen_cp_resume(struct radeon_device *rdev)
WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA);
WREG32(CP_RB_RPTR_WR, 0);
WREG32(CP_RB_WPTR, 0);
- WREG32(CP_RB_RPTR_ADDR, rdev->cp.gpu_addr & 0xFFFFFFFF);
- WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->cp.gpu_addr));
+
+ /* set the wb address wether it's enabled or not */
+ WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
+ WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF);
+ WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF);
+
+ if (rdev->wb.enabled)
+ WREG32(SCRATCH_UMSK, 0xff);
+ else {
+ tmp |= RB_NO_UPDATE;
+ WREG32(SCRATCH_UMSK, 0);
+ }
+
mdelay(1);
WREG32(CP_RB_CNTL, tmp);
@@ -1584,6 +2054,7 @@ int evergreen_irq_set(struct radeon_device *rdev)
if (rdev->irq.sw_int) {
DRM_DEBUG("evergreen_irq_set: sw int\n");
cp_int_cntl |= RB_INT_ENABLE;
+ cp_int_cntl |= TIME_STAMP_INT_ENABLE;
}
if (rdev->irq.crtc_vblank_int[0]) {
DRM_DEBUG("evergreen_irq_set: vblank 0\n");
@@ -1760,8 +2231,10 @@ static inline u32 evergreen_get_ih_wptr(struct radeon_device *rdev)
{
u32 wptr, tmp;
- /* XXX use writeback */
- wptr = RREG32(IH_RB_WPTR);
+ if (rdev->wb.enabled)
+ wptr = rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4];
+ else
+ wptr = RREG32(IH_RB_WPTR);
if (wptr & RB_OVERFLOW) {
/* When a ring buffer overflow happen start parsing interrupt
@@ -2000,6 +2473,7 @@ restart_ih:
break;
case 181: /* CP EOP event */
DRM_DEBUG("IH: CP EOP\n");
+ radeon_fence_process(rdev);
break;
case 233: /* GUI IDLE */
DRM_DEBUG("IH: CP EOP\n");
@@ -2048,26 +2522,18 @@ static int evergreen_startup(struct radeon_device *rdev)
return r;
}
evergreen_gpu_init(rdev);
-#if 0
- if (!rdev->r600_blit.shader_obj) {
- r = r600_blit_init(rdev);
- if (r) {
- DRM_ERROR("radeon: failed blitter (%d).\n", r);
- return r;
- }
- }
- r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
- if (unlikely(r != 0))
- return r;
- r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
- &rdev->r600_blit.shader_gpu_addr);
- radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+ r = evergreen_blit_init(rdev);
if (r) {
- DRM_ERROR("failed to pin blit object %d\n", r);
- return r;
+ evergreen_blit_fini(rdev);
+ rdev->asic->copy = NULL;
+ dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
}
-#endif
+
+ /* allocate wb buffer */
+ r = radeon_wb_init(rdev);
+ if (r)
+ return r;
/* Enable IRQ */
r = r600_irq_init(rdev);
@@ -2087,8 +2553,6 @@ static int evergreen_startup(struct radeon_device *rdev)
r = evergreen_cp_resume(rdev);
if (r)
return r;
- /* write back buffer are not vital so don't worry about failure */
- r600_wb_enable(rdev);
return 0;
}
@@ -2122,23 +2586,43 @@ int evergreen_resume(struct radeon_device *rdev)
int evergreen_suspend(struct radeon_device *rdev)
{
-#if 0
int r;
-#endif
+
/* FIXME: we should wait for ring to be empty */
r700_cp_stop(rdev);
rdev->cp.ready = false;
evergreen_irq_suspend(rdev);
- r600_wb_disable(rdev);
+ radeon_wb_disable(rdev);
evergreen_pcie_gart_disable(rdev);
-#if 0
+
/* unpin shaders bo */
r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
if (likely(r == 0)) {
radeon_bo_unpin(rdev->r600_blit.shader_obj);
radeon_bo_unreserve(rdev->r600_blit.shader_obj);
}
-#endif
+
+ return 0;
+}
+
+int evergreen_copy_blit(struct radeon_device *rdev,
+ uint64_t src_offset, uint64_t dst_offset,
+ unsigned num_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);
+ 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_blit_done_copy(rdev, fence);
+ mutex_unlock(&rdev->r600_blit.mutex);
return 0;
}
@@ -2246,8 +2730,8 @@ int evergreen_init(struct radeon_device *rdev)
if (r) {
dev_err(rdev->dev, "disabling GPU acceleration\n");
r700_cp_fini(rdev);
- r600_wb_fini(rdev);
r600_irq_fini(rdev);
+ radeon_wb_fini(rdev);
radeon_irq_kms_fini(rdev);
evergreen_pcie_gart_fini(rdev);
rdev->accel_working = false;
@@ -2269,10 +2753,10 @@ int evergreen_init(struct radeon_device *rdev)
void evergreen_fini(struct radeon_device *rdev)
{
- /*r600_blit_fini(rdev);*/
+ evergreen_blit_fini(rdev);
r700_cp_fini(rdev);
- r600_wb_fini(rdev);
r600_irq_fini(rdev);
+ radeon_wb_fini(rdev);
radeon_irq_kms_fini(rdev);
evergreen_pcie_gart_fini(rdev);
radeon_gem_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c
new file mode 100644
index 000000000000..ac3b6dde23db
--- /dev/null
+++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c
@@ -0,0 +1,774 @@
+/*
+ * Copyright 2010 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Alex Deucher <alexander.deucher@amd.com>
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+
+#include "evergreend.h"
+#include "evergreen_blit_shaders.h"
+
+#define DI_PT_RECTLIST 0x11
+#define DI_INDEX_SIZE_16_BIT 0x0
+#define DI_SRC_SEL_AUTO_INDEX 0x2
+
+#define FMT_8 0x1
+#define FMT_5_6_5 0x8
+#define FMT_8_8_8_8 0x1a
+#define COLOR_8 0x1
+#define COLOR_5_6_5 0x8
+#define COLOR_8_8_8_8 0x1a
+
+/* emits 17 */
+static void
+set_render_target(struct radeon_device *rdev, int format,
+ int w, int h, u64 gpu_addr)
+{
+ u32 cb_color_info;
+ int pitch, slice;
+
+ h = ALIGN(h, 8);
+ if (h < 8)
+ h = 8;
+
+ cb_color_info = ((format << 2) | (1 << 24));
+ pitch = (w / 8) - 1;
+ slice = ((w * h) / 64) - 1;
+
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 15));
+ radeon_ring_write(rdev, (CB_COLOR0_BASE - PACKET3_SET_CONTEXT_REG_START) >> 2);
+ radeon_ring_write(rdev, gpu_addr >> 8);
+ radeon_ring_write(rdev, pitch);
+ radeon_ring_write(rdev, slice);
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, cb_color_info);
+ radeon_ring_write(rdev, (1 << 4));
+ radeon_ring_write(rdev, (w - 1) | ((h - 1) << 16));
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, 0);
+}
+
+/* emits 5dw */
+static void
+cp_set_surface_sync(struct radeon_device *rdev,
+ u32 sync_type, u32 size,
+ u64 mc_addr)
+{
+ u32 cp_coher_size;
+
+ if (size == 0xffffffff)
+ cp_coher_size = 0xffffffff;
+ else
+ cp_coher_size = ((size + 255) >> 8);
+
+ radeon_ring_write(rdev, PACKET3(PACKET3_SURFACE_SYNC, 3));
+ radeon_ring_write(rdev, sync_type);
+ radeon_ring_write(rdev, cp_coher_size);
+ radeon_ring_write(rdev, mc_addr >> 8);
+ radeon_ring_write(rdev, 10); /* poll interval */
+}
+
+/* emits 11dw + 1 surface sync = 16dw */
+static void
+set_shaders(struct radeon_device *rdev)
+{
+ u64 gpu_addr;
+
+ /* VS */
+ gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.vs_offset;
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 3));
+ radeon_ring_write(rdev, (SQ_PGM_START_VS - PACKET3_SET_CONTEXT_REG_START) >> 2);
+ radeon_ring_write(rdev, gpu_addr >> 8);
+ radeon_ring_write(rdev, 2);
+ radeon_ring_write(rdev, 0);
+
+ /* PS */
+ gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.ps_offset;
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 4));
+ radeon_ring_write(rdev, (SQ_PGM_START_PS - PACKET3_SET_CONTEXT_REG_START) >> 2);
+ radeon_ring_write(rdev, gpu_addr >> 8);
+ radeon_ring_write(rdev, 1);
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, 2);
+
+ gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.vs_offset;
+ cp_set_surface_sync(rdev, PACKET3_SH_ACTION_ENA, 512, gpu_addr);
+}
+
+/* emits 10 + 1 sync (5) = 15 */
+static void
+set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr)
+{
+ u32 sq_vtx_constant_word2, sq_vtx_constant_word3;
+
+ /* high addr, stride */
+ sq_vtx_constant_word2 = ((upper_32_bits(gpu_addr) & 0xff) | (16 << 8));
+ /* xyzw swizzles */
+ sq_vtx_constant_word3 = (0 << 3) | (1 << 6) | (2 << 9) | (3 << 12);
+
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_RESOURCE, 8));
+ radeon_ring_write(rdev, 0x580);
+ radeon_ring_write(rdev, gpu_addr & 0xffffffff);
+ radeon_ring_write(rdev, 48 - 1); /* size */
+ radeon_ring_write(rdev, sq_vtx_constant_word2);
+ radeon_ring_write(rdev, sq_vtx_constant_word3);
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, SQ_TEX_VTX_VALID_BUFFER << 30);
+
+ if (rdev->family == CHIP_CEDAR)
+ cp_set_surface_sync(rdev,
+ PACKET3_TC_ACTION_ENA, 48, gpu_addr);
+ else
+ cp_set_surface_sync(rdev,
+ PACKET3_VC_ACTION_ENA, 48, gpu_addr);
+
+}
+
+/* emits 10 */
+static void
+set_tex_resource(struct radeon_device *rdev,
+ int format, int w, int h, int pitch,
+ u64 gpu_addr)
+{
+ u32 sq_tex_resource_word0, sq_tex_resource_word1;
+ u32 sq_tex_resource_word4, sq_tex_resource_word7;
+
+ if (h < 1)
+ h = 1;
+
+ sq_tex_resource_word0 = (1 << 0); /* 2D */
+ sq_tex_resource_word0 |= ((((pitch >> 3) - 1) << 6) |
+ ((w - 1) << 18));
+ sq_tex_resource_word1 = ((h - 1) << 0);
+ /* xyzw swizzles */
+ sq_tex_resource_word4 = (0 << 16) | (1 << 19) | (2 << 22) | (3 << 25);
+
+ sq_tex_resource_word7 = format | (SQ_TEX_VTX_VALID_TEXTURE << 30);
+
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_RESOURCE, 8));
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, sq_tex_resource_word0);
+ radeon_ring_write(rdev, sq_tex_resource_word1);
+ radeon_ring_write(rdev, gpu_addr >> 8);
+ radeon_ring_write(rdev, gpu_addr >> 8);
+ radeon_ring_write(rdev, sq_tex_resource_word4);
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, sq_tex_resource_word7);
+}
+
+/* emits 12 */
+static void
+set_scissors(struct radeon_device *rdev, int x1, int y1,
+ int x2, int y2)
+{
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
+ radeon_ring_write(rdev, (PA_SC_SCREEN_SCISSOR_TL - PACKET3_SET_CONTEXT_REG_START) >> 2);
+ radeon_ring_write(rdev, (x1 << 0) | (y1 << 16));
+ radeon_ring_write(rdev, (x2 << 0) | (y2 << 16));
+
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
+ radeon_ring_write(rdev, (PA_SC_GENERIC_SCISSOR_TL - PACKET3_SET_CONTEXT_REG_START) >> 2);
+ radeon_ring_write(rdev, (x1 << 0) | (y1 << 16) | (1 << 31));
+ radeon_ring_write(rdev, (x2 << 0) | (y2 << 16));
+
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
+ radeon_ring_write(rdev, (PA_SC_WINDOW_SCISSOR_TL - PACKET3_SET_CONTEXT_REG_START) >> 2);
+ radeon_ring_write(rdev, (x1 << 0) | (y1 << 16) | (1 << 31));
+ radeon_ring_write(rdev, (x2 << 0) | (y2 << 16));
+}
+
+/* emits 10 */
+static void
+draw_auto(struct radeon_device *rdev)
+{
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+ radeon_ring_write(rdev, (VGT_PRIMITIVE_TYPE - PACKET3_SET_CONFIG_REG_START) >> 2);
+ radeon_ring_write(rdev, DI_PT_RECTLIST);
+
+ radeon_ring_write(rdev, PACKET3(PACKET3_INDEX_TYPE, 0));
+ radeon_ring_write(rdev, DI_INDEX_SIZE_16_BIT);
+
+ radeon_ring_write(rdev, PACKET3(PACKET3_NUM_INSTANCES, 0));
+ radeon_ring_write(rdev, 1);
+
+ radeon_ring_write(rdev, PACKET3(PACKET3_DRAW_INDEX_AUTO, 1));
+ radeon_ring_write(rdev, 3);
+ radeon_ring_write(rdev, DI_SRC_SEL_AUTO_INDEX);
+
+}
+
+/* emits 30 */
+static void
+set_default_state(struct radeon_device *rdev)
+{
+ u32 sq_config, sq_gpr_resource_mgmt_1, sq_gpr_resource_mgmt_2, sq_gpr_resource_mgmt_3;
+ u32 sq_thread_resource_mgmt, sq_thread_resource_mgmt_2;
+ u32 sq_stack_resource_mgmt_1, sq_stack_resource_mgmt_2, sq_stack_resource_mgmt_3;
+ int num_ps_gprs, num_vs_gprs, num_temp_gprs;
+ int num_gs_gprs, num_es_gprs, num_hs_gprs, num_ls_gprs;
+ int num_ps_threads, num_vs_threads, num_gs_threads, num_es_threads;
+ int num_hs_threads, num_ls_threads;
+ int num_ps_stack_entries, num_vs_stack_entries, num_gs_stack_entries, num_es_stack_entries;
+ int num_hs_stack_entries, num_ls_stack_entries;
+
+ switch (rdev->family) {
+ case CHIP_CEDAR:
+ default:
+ num_ps_gprs = 93;
+ num_vs_gprs = 46;
+ num_temp_gprs = 4;
+ num_gs_gprs = 31;
+ num_es_gprs = 31;
+ num_hs_gprs = 23;
+ num_ls_gprs = 23;
+ num_ps_threads = 96;
+ num_vs_threads = 16;
+ num_gs_threads = 16;
+ num_es_threads = 16;
+ num_hs_threads = 16;
+ num_ls_threads = 16;
+ num_ps_stack_entries = 42;
+ num_vs_stack_entries = 42;
+ num_gs_stack_entries = 42;
+ num_es_stack_entries = 42;
+ num_hs_stack_entries = 42;
+ num_ls_stack_entries = 42;
+ break;
+ case CHIP_REDWOOD:
+ num_ps_gprs = 93;
+ num_vs_gprs = 46;
+ num_temp_gprs = 4;
+ num_gs_gprs = 31;
+ num_es_gprs = 31;
+ num_hs_gprs = 23;
+ num_ls_gprs = 23;
+ num_ps_threads = 128;
+ num_vs_threads = 20;
+ num_gs_threads = 20;
+ num_es_threads = 20;
+ num_hs_threads = 20;
+ num_ls_threads = 20;
+ num_ps_stack_entries = 42;
+ num_vs_stack_entries = 42;
+ num_gs_stack_entries = 42;
+ num_es_stack_entries = 42;
+ num_hs_stack_entries = 42;
+ num_ls_stack_entries = 42;
+ break;
+ case CHIP_JUNIPER:
+ num_ps_gprs = 93;
+ num_vs_gprs = 46;
+ num_temp_gprs = 4;
+ num_gs_gprs = 31;
+ num_es_gprs = 31;
+ num_hs_gprs = 23;
+ num_ls_gprs = 23;
+ num_ps_threads = 128;
+ num_vs_threads = 20;
+ num_gs_threads = 20;
+ num_es_threads = 20;
+ num_hs_threads = 20;
+ num_ls_threads = 20;
+ num_ps_stack_entries = 85;
+ num_vs_stack_entries = 85;
+ num_gs_stack_entries = 85;
+ num_es_stack_entries = 85;
+ num_hs_stack_entries = 85;
+ num_ls_stack_entries = 85;
+ break;
+ case CHIP_CYPRESS:
+ case CHIP_HEMLOCK:
+ num_ps_gprs = 93;
+ num_vs_gprs = 46;
+ num_temp_gprs = 4;
+ num_gs_gprs = 31;
+ num_es_gprs = 31;
+ num_hs_gprs = 23;
+ num_ls_gprs = 23;
+ num_ps_threads = 128;
+ num_vs_threads = 20;
+ num_gs_threads = 20;
+ num_es_threads = 20;
+ num_hs_threads = 20;
+ num_ls_threads = 20;
+ num_ps_stack_entries = 85;
+ num_vs_stack_entries = 85;
+ num_gs_stack_entries = 85;
+ num_es_stack_entries = 85;
+ num_hs_stack_entries = 85;
+ num_ls_stack_entries = 85;
+ break;
+ }
+
+ if (rdev->family == CHIP_CEDAR)
+ sq_config = 0;
+ else
+ sq_config = VC_ENABLE;
+
+ sq_config |= (EXPORT_SRC_C |
+ CS_PRIO(0) |
+ LS_PRIO(0) |
+ HS_PRIO(0) |
+ PS_PRIO(0) |
+ VS_PRIO(1) |
+ GS_PRIO(2) |
+ ES_PRIO(3));
+
+ sq_gpr_resource_mgmt_1 = (NUM_PS_GPRS(num_ps_gprs) |
+ NUM_VS_GPRS(num_vs_gprs) |
+ NUM_CLAUSE_TEMP_GPRS(num_temp_gprs));
+ sq_gpr_resource_mgmt_2 = (NUM_GS_GPRS(num_gs_gprs) |
+ NUM_ES_GPRS(num_es_gprs));
+ sq_gpr_resource_mgmt_3 = (NUM_HS_GPRS(num_hs_gprs) |
+ NUM_LS_GPRS(num_ls_gprs));
+ sq_thread_resource_mgmt = (NUM_PS_THREADS(num_ps_threads) |
+ NUM_VS_THREADS(num_vs_threads) |
+ NUM_GS_THREADS(num_gs_threads) |
+ NUM_ES_THREADS(num_es_threads));
+ sq_thread_resource_mgmt_2 = (NUM_HS_THREADS(num_hs_threads) |
+ NUM_LS_THREADS(num_ls_threads));
+ sq_stack_resource_mgmt_1 = (NUM_PS_STACK_ENTRIES(num_ps_stack_entries) |
+ NUM_VS_STACK_ENTRIES(num_vs_stack_entries));
+ sq_stack_resource_mgmt_2 = (NUM_GS_STACK_ENTRIES(num_gs_stack_entries) |
+ NUM_ES_STACK_ENTRIES(num_es_stack_entries));
+ sq_stack_resource_mgmt_3 = (NUM_HS_STACK_ENTRIES(num_hs_stack_entries) |
+ NUM_LS_STACK_ENTRIES(num_ls_stack_entries));
+
+ /* set clear context state */
+ radeon_ring_write(rdev, PACKET3(PACKET3_CLEAR_STATE, 0));
+ radeon_ring_write(rdev, 0);
+
+ /* disable dyn gprs */
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+ radeon_ring_write(rdev, (SQ_DYN_GPR_CNTL_PS_FLUSH_REQ - PACKET3_SET_CONFIG_REG_START) >> 2);
+ radeon_ring_write(rdev, 0);
+
+ /* SQ config */
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 11));
+ radeon_ring_write(rdev, (SQ_CONFIG - PACKET3_SET_CONFIG_REG_START) >> 2);
+ radeon_ring_write(rdev, sq_config);
+ radeon_ring_write(rdev, sq_gpr_resource_mgmt_1);
+ radeon_ring_write(rdev, sq_gpr_resource_mgmt_2);
+ radeon_ring_write(rdev, sq_gpr_resource_mgmt_3);
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, 0);
+ radeon_ring_write(rdev, sq_thread_resource_mgmt);
+ radeon_ring_write(rdev, sq_thread_resource_mgmt_2);
+ radeon_ring_write(rdev, sq_stack_resource_mgmt_1);
+ radeon_ring_write(rdev, sq_stack_resource_mgmt_2);
+ radeon_ring_write(rdev, sq_stack_resource_mgmt_3);
+
+ /* CONTEXT_CONTROL */
+ radeon_ring_write(rdev, 0xc0012800);
+ radeon_ring_write(rdev, 0x80000000);
+ radeon_ring_write(rdev, 0x80000000);
+
+ /* SQ_VTX_BASE_VTX_LOC */
+ radeon_ring_write(rdev, 0xc0026f00);
+ radeon_ring_write(rdev, 0x00000000);
+ radeon_ring_write(rdev, 0x00000000);
+ radeon_ring_write(rdev, 0x00000000);
+
+ /* SET_SAMPLER */
+ radeon_ring_write(rdev, 0xc0036e00);
+ radeon_ring_write(rdev, 0x00000000);
+ radeon_ring_write(rdev, 0x00000012);
+ radeon_ring_write(rdev, 0x00000000);
+ radeon_ring_write(rdev, 0x00000000);
+
+}
+
+static inline uint32_t i2f(uint32_t input)
+{
+ u32 result, i, exponent, fraction;
+
+ if ((input & 0x3fff) == 0)
+ result = 0; /* 0 is a special case */
+ else {
+ exponent = 140; /* exponent biased by 127; */
+ fraction = (input & 0x3fff) << 10; /* cheat and only
+ handle numbers below 2^^15 */
+ for (i = 0; i < 14; i++) {
+ if (fraction & 0x800000)
+ break;
+ else {
+ fraction = fraction << 1; /* keep
+ shifting left until top bit = 1 */
+ exponent = exponent - 1;
+ }
+ }
+ result = exponent << 23 | (fraction & 0x7fffff); /* mask
+ off top bit; assumed 1 */
+ }
+ return result;
+}
+
+int evergreen_blit_init(struct radeon_device *rdev)
+{
+ u32 obj_size;
+ int r;
+ void *ptr;
+
+ /* pin copy shader into vram if already initialized */
+ if (rdev->r600_blit.shader_obj)
+ goto done;
+
+ mutex_init(&rdev->r600_blit.mutex);
+ rdev->r600_blit.state_offset = 0;
+ rdev->r600_blit.state_len = 0;
+ obj_size = 0;
+
+ rdev->r600_blit.vs_offset = obj_size;
+ obj_size += evergreen_vs_size * 4;
+ obj_size = ALIGN(obj_size, 256);
+
+ rdev->r600_blit.ps_offset = obj_size;
+ obj_size += evergreen_ps_size * 4;
+ obj_size = ALIGN(obj_size, 256);
+
+ r = radeon_bo_create(rdev, NULL, obj_size, true, RADEON_GEM_DOMAIN_VRAM,
+ &rdev->r600_blit.shader_obj);
+ if (r) {
+ DRM_ERROR("evergreen failed to allocate shader\n");
+ return r;
+ }
+
+ DRM_DEBUG("evergreen blit allocated bo %08x vs %08x ps %08x\n",
+ obj_size,
+ rdev->r600_blit.vs_offset, rdev->r600_blit.ps_offset);
+
+ r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+ if (unlikely(r != 0))
+ return r;
+ r = radeon_bo_kmap(rdev->r600_blit.shader_obj, &ptr);
+ if (r) {
+ DRM_ERROR("failed to map blit object %d\n", r);
+ return r;
+ }
+
+ memcpy(ptr + rdev->r600_blit.vs_offset, evergreen_vs, evergreen_vs_size * 4);
+ memcpy(ptr + rdev->r600_blit.ps_offset, evergreen_ps, evergreen_ps_size * 4);
+ radeon_bo_kunmap(rdev->r600_blit.shader_obj);
+ radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+
+done:
+ r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+ if (unlikely(r != 0))
+ return r;
+ r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
+ &rdev->r600_blit.shader_gpu_addr);
+ radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+ if (r) {
+ dev_err(rdev->dev, "(%d) pin blit object failed\n", r);
+ return r;
+ }
+ rdev->mc.active_vram_size = rdev->mc.real_vram_size;
+ return 0;
+}
+
+void evergreen_blit_fini(struct radeon_device *rdev)
+{
+ int r;
+
+ rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
+ if (rdev->r600_blit.shader_obj == NULL)
+ return;
+ /* If we can't reserve the bo, unref should be enough to destroy
+ * it when it becomes idle.
+ */
+ r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+ if (!r) {
+ radeon_bo_unpin(rdev->r600_blit.shader_obj);
+ radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+ }
+ radeon_bo_unref(&rdev->r600_blit.shader_obj);
+}
+
+static int evergreen_vb_ib_get(struct radeon_device *rdev)
+{
+ int r;
+ r = radeon_ib_get(rdev, &rdev->r600_blit.vb_ib);
+ if (r) {
+ DRM_ERROR("failed to get IB for vertex buffer\n");
+ return r;
+ }
+
+ rdev->r600_blit.vb_total = 64*1024;
+ rdev->r600_blit.vb_used = 0;
+ return 0;
+}
+
+static void evergreen_vb_ib_put(struct radeon_device *rdev)
+{
+ radeon_fence_emit(rdev, rdev->r600_blit.vb_ib->fence);
+ radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
+}
+
+int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes)
+{
+ int r;
+ int ring_size, line_size;
+ int max_size;
+ /* loops of emits + fence emit possible */
+ int dwords_per_loop = 74, num_loops;
+
+ r = evergreen_vb_ib_get(rdev);
+ if (r)
+ return r;
+
+ /* 8 bpp vs 32 bpp for xfer unit */
+ if (size_bytes & 3)
+ line_size = 8192;
+ else
+ line_size = 8192 * 4;
+
+ max_size = 8192 * line_size;
+
+ /* major loops cover the max size transfer */
+ num_loops = ((size_bytes + max_size) / max_size);
+ /* minor loops cover the extra non aligned bits */
+ num_loops += ((size_bytes % line_size) ? 1 : 0);
+ /* calculate number of loops correctly */
+ ring_size = num_loops * dwords_per_loop;
+ /* set default + shaders */
+ ring_size += 46; /* shaders + def state */
+ ring_size += 10; /* fence emit for VB IB */
+ ring_size += 5; /* done copy */
+ ring_size += 10; /* fence emit for done copy */
+ r = radeon_ring_lock(rdev, ring_size);
+ if (r)
+ return r;
+
+ set_default_state(rdev); /* 30 */
+ set_shaders(rdev); /* 16 */
+ return 0;
+}
+
+void evergreen_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence)
+{
+ int r;
+
+ if (rdev->r600_blit.vb_ib)
+ evergreen_vb_ib_put(rdev);
+
+ if (fence)
+ r = radeon_fence_emit(rdev, fence);
+
+ radeon_ring_unlock_commit(rdev);
+}
+
+void evergreen_kms_blit_copy(struct radeon_device *rdev,
+ u64 src_gpu_addr, u64 dst_gpu_addr,
+ int size_bytes)
+{
+ int max_bytes;
+ u64 vb_gpu_addr;
+ u32 *vb;
+
+ DRM_DEBUG("emitting copy %16llx %16llx %d %d\n", src_gpu_addr, dst_gpu_addr,
+ size_bytes, rdev->r600_blit.vb_used);
+ vb = (u32 *)(rdev->r600_blit.vb_ib->ptr + rdev->r600_blit.vb_used);
+ if ((size_bytes & 3) || (src_gpu_addr & 3) || (dst_gpu_addr & 3)) {
+ max_bytes = 8192;
+
+ while (size_bytes) {
+ int cur_size = size_bytes;
+ int src_x = src_gpu_addr & 255;
+ int dst_x = dst_gpu_addr & 255;
+ int h = 1;
+ src_gpu_addr = src_gpu_addr & ~255ULL;
+ dst_gpu_addr = dst_gpu_addr & ~255ULL;
+
+ if (!src_x && !dst_x) {
+ h = (cur_size / max_bytes);
+ if (h > 8192)
+ h = 8192;
+ if (h == 0)
+ h = 1;
+ else
+ cur_size = max_bytes;
+ } else {
+ if (cur_size > max_bytes)
+ cur_size = max_bytes;
+ if (cur_size > (max_bytes - dst_x))
+ cur_size = (max_bytes - dst_x);
+ if (cur_size > (max_bytes - src_x))
+ cur_size = (max_bytes - src_x);
+ }
+
+ if ((rdev->r600_blit.vb_used + 48) > rdev->r600_blit.vb_total) {
+ WARN_ON(1);
+ }
+
+ vb[0] = i2f(dst_x);
+ vb[1] = 0;
+ vb[2] = i2f(src_x);
+ vb[3] = 0;
+
+ vb[4] = i2f(dst_x);
+ vb[5] = i2f(h);
+ vb[6] = i2f(src_x);
+ vb[7] = i2f(h);
+
+ vb[8] = i2f(dst_x + cur_size);
+ vb[9] = i2f(h);
+ vb[10] = i2f(src_x + cur_size);
+ vb[11] = i2f(h);
+
+ /* src 10 */
+ set_tex_resource(rdev, FMT_8,
+ src_x + cur_size, h, src_x + cur_size,
+ src_gpu_addr);
+
+ /* 5 */
+ cp_set_surface_sync(rdev,
+ PACKET3_TC_ACTION_ENA, (src_x + cur_size * h), src_gpu_addr);
+
+
+ /* dst 17 */
+ set_render_target(rdev, COLOR_8,
+ dst_x + cur_size, h,
+ dst_gpu_addr);
+
+ /* scissors 12 */
+ set_scissors(rdev, dst_x, 0, dst_x + cur_size, h);
+
+ /* 15 */
+ vb_gpu_addr = rdev->r600_blit.vb_ib->gpu_addr + rdev->r600_blit.vb_used;
+ set_vtx_resource(rdev, vb_gpu_addr);
+
+ /* draw 10 */
+ draw_auto(rdev);
+
+ /* 5 */
+ cp_set_surface_sync(rdev,
+ PACKET3_CB_ACTION_ENA | PACKET3_CB0_DEST_BASE_ENA,
+ cur_size * h, dst_gpu_addr);
+
+ vb += 12;
+ rdev->r600_blit.vb_used += 12 * 4;
+
+ src_gpu_addr += cur_size * h;
+ dst_gpu_addr += cur_size * h;
+ size_bytes -= cur_size * h;
+ }
+ } else {
+ max_bytes = 8192 * 4;
+
+ while (size_bytes) {
+ int cur_size = size_bytes;
+ int src_x = (src_gpu_addr & 255);
+ int dst_x = (dst_gpu_addr & 255);
+ int h = 1;
+ src_gpu_addr = src_gpu_addr & ~255ULL;
+ dst_gpu_addr = dst_gpu_addr & ~255ULL;
+
+ if (!src_x && !dst_x) {
+ h = (cur_size / max_bytes);
+ if (h > 8192)
+ h = 8192;
+ if (h == 0)
+ h = 1;
+ else
+ cur_size = max_bytes;
+ } else {
+ if (cur_size > max_bytes)
+ cur_size = max_bytes;
+ if (cur_size > (max_bytes - dst_x))
+ cur_size = (max_bytes - dst_x);
+ if (cur_size > (max_bytes - src_x))
+ cur_size = (max_bytes - src_x);
+ }
+
+ if ((rdev->r600_blit.vb_used + 48) > rdev->r600_blit.vb_total) {
+ WARN_ON(1);
+ }
+
+ vb[0] = i2f(dst_x / 4);
+ vb[1] = 0;
+ vb[2] = i2f(src_x / 4);
+ vb[3] = 0;
+
+ vb[4] = i2f(dst_x / 4);
+ vb[5] = i2f(h);
+ vb[6] = i2f(src_x / 4);
+ vb[7] = i2f(h);
+
+ vb[8] = i2f((dst_x + cur_size) / 4);
+ vb[9] = i2f(h);
+ vb[10] = i2f((src_x + cur_size) / 4);
+ vb[11] = i2f(h);
+
+ /* src 10 */
+ set_tex_resource(rdev, FMT_8_8_8_8,
+ (src_x + cur_size) / 4,
+ h, (src_x + cur_size) / 4,
+ src_gpu_addr);
+ /* 5 */
+ cp_set_surface_sync(rdev,
+ PACKET3_TC_ACTION_ENA, (src_x + cur_size * h), src_gpu_addr);
+
+ /* dst 17 */
+ set_render_target(rdev, COLOR_8_8_8_8,
+ (dst_x + cur_size) / 4, h,
+ dst_gpu_addr);
+
+ /* scissors 12 */
+ set_scissors(rdev, (dst_x / 4), 0, (dst_x + cur_size / 4), h);
+
+ /* Vertex buffer setup 15 */
+ vb_gpu_addr = rdev->r600_blit.vb_ib->gpu_addr + rdev->r600_blit.vb_used;
+ set_vtx_resource(rdev, vb_gpu_addr);
+
+ /* draw 10 */
+ draw_auto(rdev);
+
+ /* 5 */
+ cp_set_surface_sync(rdev,
+ PACKET3_CB_ACTION_ENA | PACKET3_CB0_DEST_BASE_ENA,
+ cur_size * h, dst_gpu_addr);
+
+ /* 74 ring dwords per loop */
+ vb += 12;
+ rdev->r600_blit.vb_used += 12 * 4;
+
+ src_gpu_addr += cur_size * h;
+ dst_gpu_addr += cur_size * h;
+ size_bytes -= cur_size * h;
+ }
+ }
+}
+
diff --git a/drivers/gpu/drm/radeon/evergreen_blit_shaders.c b/drivers/gpu/drm/radeon/evergreen_blit_shaders.c
new file mode 100644
index 000000000000..ef1d28c07fbf
--- /dev/null
+++ b/drivers/gpu/drm/radeon/evergreen_blit_shaders.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2010 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Alex Deucher <alexander.deucher@amd.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+/*
+ * evergreen cards need to use the 3D engine to blit data which requires
+ * quite a bit of hw state setup. Rather than pull the whole 3D driver
+ * (which normally generates the 3D state) into the DRM, we opt to use
+ * statically generated state tables. The regsiter state and shaders
+ * were hand generated to support blitting functionality. See the 3D
+ * driver or documentation for descriptions of the registers and
+ * shader instructions.
+ */
+
+const u32 evergreen_default_state[] =
+{
+ 0xc0016900,
+ 0x0000023b,
+ 0x00000000, /* SQ_LDS_ALLOC_PS */
+
+ 0xc0066900,
+ 0x00000240,
+ 0x00000000, /* SQ_ESGS_RING_ITEMSIZE */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+
+ 0xc0046900,
+ 0x00000247,
+ 0x00000000, /* SQ_GS_VERT_ITEMSIZE */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+
+ 0xc0026900,
+ 0x00000010,
+ 0x00000000, /* DB_Z_INFO */
+ 0x00000000, /* DB_STENCIL_INFO */
+
+ 0xc0016900,
+ 0x00000200,
+ 0x00000000, /* DB_DEPTH_CONTROL */
+
+ 0xc0066900,
+ 0x00000000,
+ 0x00000060, /* DB_RENDER_CONTROL */
+ 0x00000000, /* DB_COUNT_CONTROL */
+ 0x00000000, /* DB_DEPTH_VIEW */
+ 0x0000002a, /* DB_RENDER_OVERRIDE */
+ 0x00000000, /* DB_RENDER_OVERRIDE2 */
+ 0x00000000, /* DB_HTILE_DATA_BASE */
+
+ 0xc0026900,
+ 0x0000000a,
+ 0x00000000, /* DB_STENCIL_CLEAR */
+ 0x00000000, /* DB_DEPTH_CLEAR */
+
+ 0xc0016900,
+ 0x000002dc,
+ 0x0000aa00, /* DB_ALPHA_TO_MASK */
+
+ 0xc0016900,
+ 0x00000080,
+ 0x00000000, /* PA_SC_WINDOW_OFFSET */
+
+ 0xc00d6900,
+ 0x00000083,
+ 0x0000ffff, /* PA_SC_CLIPRECT_RULE */
+ 0x00000000, /* PA_SC_CLIPRECT_0_TL */
+ 0x20002000, /* PA_SC_CLIPRECT_0_BR */
+ 0x00000000,
+ 0x20002000,
+ 0x00000000,
+ 0x20002000,
+ 0x00000000,
+ 0x20002000,
+ 0xaaaaaaaa, /* PA_SC_EDGERULE */
+ 0x00000000, /* PA_SU_HARDWARE_SCREEN_OFFSET */
+ 0x0000000f, /* CB_TARGET_MASK */
+ 0x0000000f, /* CB_SHADER_MASK */
+
+ 0xc0226900,
+ 0x00000094,
+ 0x80000000, /* PA_SC_VPORT_SCISSOR_0_TL */
+ 0x20002000, /* PA_SC_VPORT_SCISSOR_0_BR */
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x00000000, /* PA_SC_VPORT_ZMIN_0 */
+ 0x3f800000, /* PA_SC_VPORT_ZMAX_0 */
+
+ 0xc0016900,
+ 0x000000d4,
+ 0x00000000, /* SX_MISC */
+
+ 0xc0026900,
+ 0x00000292,
+ 0x00000000, /* PA_SC_MODE_CNTL_0 */
+ 0x00000000, /* PA_SC_MODE_CNTL_1 */
+
+ 0xc0106900,
+ 0x00000300,
+ 0x00000000, /* PA_SC_LINE_CNTL */
+ 0x00000000, /* PA_SC_AA_CONFIG */
+ 0x00000005, /* PA_SU_VTX_CNTL */
+ 0x3f800000, /* PA_CL_GB_VERT_CLIP_ADJ */
+ 0x3f800000, /* PA_CL_GB_VERT_DISC_ADJ */
+ 0x3f800000, /* PA_CL_GB_HORZ_CLIP_ADJ */
+ 0x3f800000, /* PA_CL_GB_HORZ_DISC_ADJ */
+ 0x00000000, /* PA_SC_AA_SAMPLE_LOCS_0 */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* PA_SC_AA_SAMPLE_LOCS_7 */
+ 0xffffffff, /* PA_SC_AA_MASK */
+
+ 0xc00d6900,
+ 0x00000202,
+ 0x00cc0010, /* CB_COLOR_CONTROL */
+ 0x00000210, /* DB_SHADER_CONTROL */
+ 0x00010000, /* PA_CL_CLIP_CNTL */
+ 0x00000004, /* PA_SU_SC_MODE_CNTL */
+ 0x00000100, /* PA_CL_VTE_CNTL */
+ 0x00000000, /* PA_CL_VS_OUT_CNTL */
+ 0x00000000, /* PA_CL_NANINF_CNTL */
+ 0x00000000, /* PA_SU_LINE_STIPPLE_CNTL */
+ 0x00000000, /* PA_SU_LINE_STIPPLE_SCALE */
+ 0x00000000, /* PA_SU_PRIM_FILTER_CNTL */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* SQ_DYN_GPR_RESOURCE_LIMIT_1 */
+
+ 0xc0066900,
+ 0x000002de,
+ 0x00000000, /* PA_SU_POLY_OFFSET_DB_FMT_CNTL */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+
+ 0xc0016900,
+ 0x00000229,
+ 0x00000000, /* SQ_PGM_START_FS */
+
+ 0xc0016900,
+ 0x0000022a,
+ 0x00000000, /* SQ_PGM_RESOURCES_FS */
+
+ 0xc0096900,
+ 0x00000100,
+ 0x00ffffff, /* VGT_MAX_VTX_INDX */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* SX_ALPHA_TEST_CONTROL */
+ 0x00000000, /* CB_BLEND_RED */
+ 0x00000000, /* CB_BLEND_GREEN */
+ 0x00000000, /* CB_BLEND_BLUE */
+ 0x00000000, /* CB_BLEND_ALPHA */
+
+ 0xc0026900,
+ 0x000002a8,
+ 0x00000000, /* VGT_INSTANCE_STEP_RATE_0 */
+ 0x00000000, /* */
+
+ 0xc0026900,
+ 0x000002ad,
+ 0x00000000, /* VGT_REUSE_OFF */
+ 0x00000000, /* */
+
+ 0xc0116900,
+ 0x00000280,
+ 0x00000000, /* PA_SU_POINT_SIZE */
+ 0x00000000, /* PA_SU_POINT_MINMAX */
+ 0x00000008, /* PA_SU_LINE_CNTL */
+ 0x00000000, /* PA_SC_LINE_STIPPLE */
+ 0x00000000, /* VGT_OUTPUT_PATH_CNTL */
+ 0x00000000, /* VGT_HOS_CNTL */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* VGT_GS_MODE */
+
+ 0xc0016900,
+ 0x000002a1,
+ 0x00000000, /* VGT_PRIMITIVEID_EN */
+
+ 0xc0016900,
+ 0x000002a5,
+ 0x00000000, /* VGT_MULTI_PRIM_IB_RESET_EN */
+
+ 0xc0016900,
+ 0x000002d5,
+ 0x00000000, /* VGT_SHADER_STAGES_EN */
+
+ 0xc0026900,
+ 0x000002e5,
+ 0x00000000, /* VGT_STRMOUT_CONFIG */
+ 0x00000000, /* */
+
+ 0xc0016900,
+ 0x000001e0,
+ 0x00000000, /* CB_BLEND0_CONTROL */
+
+ 0xc0016900,
+ 0x000001b1,
+ 0x00000000, /* SPI_VS_OUT_CONFIG */
+
+ 0xc0016900,
+ 0x00000187,
+ 0x00000000, /* SPI_VS_OUT_ID_0 */
+
+ 0xc0016900,
+ 0x00000191,
+ 0x00000100, /* SPI_PS_INPUT_CNTL_0 */
+
+ 0xc00b6900,
+ 0x000001b3,
+ 0x20000001, /* SPI_PS_IN_CONTROL_0 */
+ 0x00000000, /* SPI_PS_IN_CONTROL_1 */
+ 0x00000000, /* SPI_INTERP_CONTROL_0 */
+ 0x00000000, /* SPI_INPUT_Z */
+ 0x00000000, /* SPI_FOG_CNTL */
+ 0x00100000, /* SPI_BARYC_CNTL */
+ 0x00000000, /* SPI_PS_IN_CONTROL_2 */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+ 0x00000000, /* */
+
+ 0xc0026900,
+ 0x00000316,
+ 0x0000000e, /* VGT_VERTEX_REUSE_BLOCK_CNTL */
+ 0x00000010, /* */
+};
+
+const u32 evergreen_vs[] =
+{
+ 0x00000004,
+ 0x80800400,
+ 0x0000a03c,
+ 0x95000688,
+ 0x00004000,
+ 0x15200688,
+ 0x00000000,
+ 0x00000000,
+ 0x3c000000,
+ 0x67961001,
+ 0x00080000,
+ 0x00000000,
+ 0x1c000000,
+ 0x67961000,
+ 0x00000008,
+ 0x00000000,
+};
+
+const u32 evergreen_ps[] =
+{
+ 0x00000003,
+ 0xa00c0000,
+ 0x00000008,
+ 0x80400000,
+ 0x00000000,
+ 0x95200688,
+ 0x00380400,
+ 0x00146b10,
+ 0x00380000,
+ 0x20146b10,
+ 0x00380400,
+ 0x40146b00,
+ 0x80380000,
+ 0x60146b00,
+ 0x00000000,
+ 0x00000000,
+ 0x00000010,
+ 0x000d1000,
+ 0xb0800000,
+ 0x00000000,
+};
+
+const u32 evergreen_ps_size = ARRAY_SIZE(evergreen_ps);
+const u32 evergreen_vs_size = ARRAY_SIZE(evergreen_vs);
+const u32 evergreen_default_size = ARRAY_SIZE(evergreen_default_state);
diff --git a/drivers/gpu/drm/radeon/evergreen_blit_shaders.h b/drivers/gpu/drm/radeon/evergreen_blit_shaders.h
new file mode 100644
index 000000000000..bb8d6c751595
--- /dev/null
+++ b/drivers/gpu/drm/radeon/evergreen_blit_shaders.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2009 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef EVERGREEN_BLIT_SHADERS_H
+#define EVERGREEN_BLIT_SHADERS_H
+
+extern const u32 evergreen_ps[];
+extern const u32 evergreen_vs[];
+extern const u32 evergreen_default_state[];
+
+extern const u32 evergreen_ps_size, evergreen_vs_size;
+extern const u32 evergreen_default_size;
+
+#endif
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index 9b7532dd30f7..113c70cc8b39 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -412,6 +412,19 @@
#define SOFT_RESET_REGBB (1 << 22)
#define SOFT_RESET_ORB (1 << 23)
+/* display watermarks */
+#define DC_LB_MEMORY_SPLIT 0x6b0c
+#define PRIORITY_A_CNT 0x6b18
+#define PRIORITY_MARK_MASK 0x7fff
+#define PRIORITY_OFF (1 << 16)
+#define PRIORITY_ALWAYS_ON (1 << 20)
+#define PRIORITY_B_CNT 0x6b1c
+#define PIPE0_ARBITRATION_CONTROL3 0x0bf0
+# define LATENCY_WATERMARK_MASK(x) ((x) << 16)
+#define PIPE0_LATENCY_CONTROL 0x0bf4
+# define LATENCY_LOW_WATERMARK(x) ((x) << 0)
+# define LATENCY_HIGH_WATERMARK(x) ((x) << 16)
+
#define IH_RB_CNTL 0x3e00
# define IH_RB_ENABLE (1 << 0)
# define IH_IB_SIZE(x) ((x) << 1) /* log2 */
@@ -645,6 +658,8 @@
#define PACKET3_EVENT_WRITE_EOP 0x47
#define PACKET3_EVENT_WRITE_EOS 0x48
#define PACKET3_PREAMBLE_CNTL 0x4A
+# define PACKET3_PREAMBLE_BEGIN_CLEAR_STATE (2 << 28)
+# define PACKET3_PREAMBLE_END_CLEAR_STATE (3 << 28)
#define PACKET3_RB_OFFSET 0x4B
#define PACKET3_ALU_PS_CONST_BUFFER_COPY 0x4C
#define PACKET3_ALU_VS_CONST_BUFFER_COPY 0x4D
@@ -802,6 +817,11 @@
#define SQ_ALU_CONST_CACHE_LS_14 0x28f78
#define SQ_ALU_CONST_CACHE_LS_15 0x28f7c
+#define PA_SC_SCREEN_SCISSOR_TL 0x28030
+#define PA_SC_GENERIC_SCISSOR_TL 0x28240
+#define PA_SC_WINDOW_SCISSOR_TL 0x28204
+#define VGT_PRIMITIVE_TYPE 0x8958
+
#define DB_DEPTH_CONTROL 0x28800
#define DB_DEPTH_VIEW 0x28008
#define DB_HTILE_DATA_BASE 0x28014
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index e59422320bb6..0e8f28a68927 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -675,67 +675,6 @@ void r100_fence_ring_emit(struct radeon_device *rdev,
radeon_ring_write(rdev, RADEON_SW_INT_FIRE);
}
-int r100_wb_init(struct radeon_device *rdev)
-{
- int r;
-
- if (rdev->wb.wb_obj == NULL) {
- r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true,
- RADEON_GEM_DOMAIN_GTT,
- &rdev->wb.wb_obj);
- if (r) {
- dev_err(rdev->dev, "(%d) create WB buffer failed\n", r);
- return r;
- }
- r = radeon_bo_reserve(rdev->wb.wb_obj, false);
- if (unlikely(r != 0))
- return r;
- r = radeon_bo_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT,
- &rdev->wb.gpu_addr);
- if (r) {
- dev_err(rdev->dev, "(%d) pin WB buffer failed\n", r);
- radeon_bo_unreserve(rdev->wb.wb_obj);
- return r;
- }
- r = radeon_bo_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb);
- radeon_bo_unreserve(rdev->wb.wb_obj);
- if (r) {
- dev_err(rdev->dev, "(%d) map WB buffer failed\n", r);
- return r;
- }
- }
- WREG32(R_000774_SCRATCH_ADDR, rdev->wb.gpu_addr);
- WREG32(R_00070C_CP_RB_RPTR_ADDR,
- S_00070C_RB_RPTR_ADDR((rdev->wb.gpu_addr + 1024) >> 2));
- WREG32(R_000770_SCRATCH_UMSK, 0xff);
- return 0;
-}
-
-void r100_wb_disable(struct radeon_device *rdev)
-{
- WREG32(R_000770_SCRATCH_UMSK, 0);
-}
-
-void r100_wb_fini(struct radeon_device *rdev)
-{
- int r;
-
- r100_wb_disable(rdev);
- if (rdev->wb.wb_obj) {
- r = radeon_bo_reserve(rdev->wb.wb_obj, false);
- if (unlikely(r != 0)) {
- dev_err(rdev->dev, "(%d) can't finish WB\n", r);
- return;
- }
- radeon_bo_kunmap(rdev->wb.wb_obj);
- radeon_bo_unpin(rdev->wb.wb_obj);
- radeon_bo_unreserve(rdev->wb.wb_obj);
- radeon_bo_unref(&rdev->wb.wb_obj);
- rdev->wb.wb = NULL;
- rdev->wb.wb_obj = NULL;
- }
-}
-
int r100_copy_blit(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
@@ -996,20 +935,32 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
WREG32(0x718, pre_write_timer | (pre_write_limit << 28));
tmp = (REG_SET(RADEON_RB_BUFSZ, rb_bufsz) |
REG_SET(RADEON_RB_BLKSZ, rb_blksz) |
- REG_SET(RADEON_MAX_FETCH, max_fetch) |
- RADEON_RB_NO_UPDATE);
+ REG_SET(RADEON_MAX_FETCH, max_fetch));
#ifdef __BIG_ENDIAN
tmp |= RADEON_BUF_SWAP_32BIT;
#endif
- WREG32(RADEON_CP_RB_CNTL, tmp);
+ WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_NO_UPDATE);
/* Set ring address */
DRM_INFO("radeon: ring at 0x%016lX\n", (unsigned long)rdev->cp.gpu_addr);
WREG32(RADEON_CP_RB_BASE, rdev->cp.gpu_addr);
/* Force read & write ptr to 0 */
- WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA);
+ 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);
+
+ /* set the wb address whether it's enabled or not */
+ WREG32(R_00070C_CP_RB_RPTR_ADDR,
+ S_00070C_RB_RPTR_ADDR((rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) >> 2));
+ WREG32(R_000774_SCRATCH_ADDR, rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET);
+
+ if (rdev->wb.enabled)
+ WREG32(R_000770_SCRATCH_UMSK, 0xff);
+ else {
+ tmp |= RADEON_RB_NO_UPDATE;
+ WREG32(R_000770_SCRATCH_UMSK, 0);
+ }
+
WREG32(RADEON_CP_RB_CNTL, tmp);
udelay(10);
rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
@@ -1052,6 +1003,7 @@ void r100_cp_disable(struct radeon_device *rdev)
rdev->cp.ready = false;
WREG32(RADEON_CP_CSQ_MODE, 0);
WREG32(RADEON_CP_CSQ_CNTL, 0);
+ WREG32(R_000770_SCRATCH_UMSK, 0);
if (r100_gui_wait_for_idle(rdev)) {
printk(KERN_WARNING "Failed to wait GUI idle while "
"programming pipes. Bad things might happen.\n");
@@ -2318,6 +2270,9 @@ void r100_vram_init_sizes(struct radeon_device *rdev)
/* Fix for RN50, M6, M7 with 8/16/32(??) MBs of VRAM -
* Novell bug 204882 + along with lots of ubuntu ones
*/
+ if (rdev->mc.aper_size > config_aper_size)
+ config_aper_size = rdev->mc.aper_size;
+
if (config_aper_size > rdev->mc.real_vram_size)
rdev->mc.mc_vram_size = config_aper_size;
else
@@ -3225,6 +3180,8 @@ static int r100_cs_track_texture_check(struct radeon_device *rdev,
for (u = 0; u < track->num_texture; u++) {
if (!track->textures[u].enabled)
continue;
+ if (track->textures[u].lookup_disable)
+ continue;
robj = track->textures[u].robj;
if (robj == NULL) {
DRM_ERROR("No texture bound to unit %u\n", u);
@@ -3459,6 +3416,7 @@ void r100_cs_track_clear(struct radeon_device *rdev, struct r100_cs_track *track
track->textures[i].robj = NULL;
/* CS IB emission code makes sure texture unit are disabled */
track->textures[i].enabled = false;
+ track->textures[i].lookup_disable = false;
track->textures[i].roundup_w = true;
track->textures[i].roundup_h = true;
if (track->separate_cube)
@@ -3737,6 +3695,12 @@ static int r100_startup(struct radeon_device *rdev)
if (r)
return r;
}
+
+ /* allocate wb buffer */
+ r = radeon_wb_init(rdev);
+ if (r)
+ return r;
+
/* Enable IRQ */
r100_irq_set(rdev);
rdev->config.r100.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -3746,9 +3710,6 @@ static int r100_startup(struct radeon_device *rdev)
dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
return r;
}
- r = r100_wb_init(rdev);
- if (r)
- dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
r = r100_ib_init(rdev);
if (r) {
dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -3782,7 +3743,7 @@ int r100_resume(struct radeon_device *rdev)
int r100_suspend(struct radeon_device *rdev)
{
r100_cp_disable(rdev);
- r100_wb_disable(rdev);
+ radeon_wb_disable(rdev);
r100_irq_disable(rdev);
if (rdev->flags & RADEON_IS_PCI)
r100_pci_gart_disable(rdev);
@@ -3792,7 +3753,7 @@ int r100_suspend(struct radeon_device *rdev)
void r100_fini(struct radeon_device *rdev)
{
r100_cp_fini(rdev);
- r100_wb_fini(rdev);
+ radeon_wb_fini(rdev);
r100_ib_fini(rdev);
radeon_gem_fini(rdev);
if (rdev->flags & RADEON_IS_PCI)
@@ -3905,7 +3866,7 @@ int r100_init(struct radeon_device *rdev)
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
r100_cp_fini(rdev);
- r100_wb_fini(rdev);
+ radeon_wb_fini(rdev);
r100_ib_fini(rdev);
radeon_irq_kms_fini(rdev);
if (rdev->flags & RADEON_IS_PCI)
diff --git a/drivers/gpu/drm/radeon/r100_track.h b/drivers/gpu/drm/radeon/r100_track.h
index f47cdca1c004..af65600e6564 100644
--- a/drivers/gpu/drm/radeon/r100_track.h
+++ b/drivers/gpu/drm/radeon/r100_track.h
@@ -46,6 +46,7 @@ struct r100_cs_track_texture {
unsigned height_11;
bool use_pitch;
bool enabled;
+ bool lookup_disable;
bool roundup_w;
bool roundup_h;
unsigned compress_format;
diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c
index 0266d72e0a4c..d2408c395619 100644
--- a/drivers/gpu/drm/radeon/r200.c
+++ b/drivers/gpu/drm/radeon/r200.c
@@ -447,6 +447,8 @@ int r200_packet0_check(struct radeon_cs_parser *p,
track->textures[i].width = 1 << ((idx_value >> RADEON_TXFORMAT_WIDTH_SHIFT) & RADEON_TXFORMAT_WIDTH_MASK);
track->textures[i].height = 1 << ((idx_value >> RADEON_TXFORMAT_HEIGHT_SHIFT) & RADEON_TXFORMAT_HEIGHT_MASK);
}
+ if (idx_value & R200_TXFORMAT_LOOKUP_DISABLE)
+ track->textures[i].lookup_disable = true;
switch ((idx_value & RADEON_TXFORMAT_FORMAT_MASK)) {
case R200_TXFORMAT_I8:
case R200_TXFORMAT_RGB332:
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index c827738ad7dd..34527e600fe9 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -1332,6 +1332,12 @@ static int r300_startup(struct radeon_device *rdev)
if (r)
return r;
}
+
+ /* allocate wb buffer */
+ r = radeon_wb_init(rdev);
+ if (r)
+ return r;
+
/* Enable IRQ */
r100_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -1341,9 +1347,6 @@ static int r300_startup(struct radeon_device *rdev)
dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
return r;
}
- r = r100_wb_init(rdev);
- if (r)
- dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
r = r100_ib_init(rdev);
if (r) {
dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -1379,7 +1382,7 @@ int r300_resume(struct radeon_device *rdev)
int r300_suspend(struct radeon_device *rdev)
{
r100_cp_disable(rdev);
- r100_wb_disable(rdev);
+ radeon_wb_disable(rdev);
r100_irq_disable(rdev);
if (rdev->flags & RADEON_IS_PCIE)
rv370_pcie_gart_disable(rdev);
@@ -1391,7 +1394,7 @@ int r300_suspend(struct radeon_device *rdev)
void r300_fini(struct radeon_device *rdev)
{
r100_cp_fini(rdev);
- r100_wb_fini(rdev);
+ radeon_wb_fini(rdev);
r100_ib_fini(rdev);
radeon_gem_fini(rdev);
if (rdev->flags & RADEON_IS_PCIE)
@@ -1484,7 +1487,7 @@ int r300_init(struct radeon_device *rdev)
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
r100_cp_fini(rdev);
- r100_wb_fini(rdev);
+ radeon_wb_fini(rdev);
r100_ib_fini(rdev);
radeon_irq_kms_fini(rdev);
if (rdev->flags & RADEON_IS_PCIE)
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
index 59f7bccc5be0..c387346f93a9 100644
--- a/drivers/gpu/drm/radeon/r420.c
+++ b/drivers/gpu/drm/radeon/r420.c
@@ -248,6 +248,12 @@ static int r420_startup(struct radeon_device *rdev)
return r;
}
r420_pipes_init(rdev);
+
+ /* allocate wb buffer */
+ r = radeon_wb_init(rdev);
+ if (r)
+ return r;
+
/* Enable IRQ */
r100_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -258,10 +264,6 @@ static int r420_startup(struct radeon_device *rdev)
return r;
}
r420_cp_errata_init(rdev);
- r = r100_wb_init(rdev);
- if (r) {
- dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
- }
r = r100_ib_init(rdev);
if (r) {
dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -302,7 +304,7 @@ int r420_suspend(struct radeon_device *rdev)
{
r420_cp_errata_fini(rdev);
r100_cp_disable(rdev);
- r100_wb_disable(rdev);
+ radeon_wb_disable(rdev);
r100_irq_disable(rdev);
if (rdev->flags & RADEON_IS_PCIE)
rv370_pcie_gart_disable(rdev);
@@ -314,7 +316,7 @@ int r420_suspend(struct radeon_device *rdev)
void r420_fini(struct radeon_device *rdev)
{
r100_cp_fini(rdev);
- r100_wb_fini(rdev);
+ radeon_wb_fini(rdev);
r100_ib_fini(rdev);
radeon_gem_fini(rdev);
if (rdev->flags & RADEON_IS_PCIE)
@@ -418,7 +420,7 @@ int r420_init(struct radeon_device *rdev)
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
r100_cp_fini(rdev);
- r100_wb_fini(rdev);
+ radeon_wb_fini(rdev);
r100_ib_fini(rdev);
radeon_irq_kms_fini(rdev);
if (rdev->flags & RADEON_IS_PCIE)
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index 1458dee902dd..3c8677f9e385 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -181,6 +181,12 @@ static int r520_startup(struct radeon_device *rdev)
if (r)
return r;
}
+
+ /* allocate wb buffer */
+ r = radeon_wb_init(rdev);
+ if (r)
+ return r;
+
/* Enable IRQ */
rs600_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -190,9 +196,6 @@ static int r520_startup(struct radeon_device *rdev)
dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
return r;
}
- r = r100_wb_init(rdev);
- if (r)
- dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
r = r100_ib_init(rdev);
if (r) {
dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -295,7 +298,7 @@ int r520_init(struct radeon_device *rdev)
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
r100_cp_fini(rdev);
- r100_wb_fini(rdev);
+ radeon_wb_fini(rdev);
r100_ib_fini(rdev);
radeon_irq_kms_fini(rdev);
rv370_pcie_gart_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 7b65e4efe8af..33952a12f0a3 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -1608,8 +1608,11 @@ void r600_gpu_init(struct radeon_device *rdev)
rdev->config.r600.tiling_npipes = rdev->config.r600.max_tile_pipes;
rdev->config.r600.tiling_nbanks = 4 << ((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT);
tiling_config |= BANK_TILING((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT);
- tiling_config |= GROUP_SIZE(0);
- rdev->config.r600.tiling_group_size = 256;
+ tiling_config |= GROUP_SIZE((ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT);
+ if ((ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT)
+ rdev->config.r600.tiling_group_size = 512;
+ else
+ rdev->config.r600.tiling_group_size = 256;
tmp = (ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
if (tmp > 3) {
tiling_config |= ROW_TILING(3);
@@ -1920,6 +1923,7 @@ void r600_cp_stop(struct radeon_device *rdev)
{
rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1));
+ WREG32(SCRATCH_UMSK, 0);
}
int r600_init_microcode(struct radeon_device *rdev)
@@ -2152,7 +2156,7 @@ int r600_cp_resume(struct radeon_device *rdev)
/* Set ring buffer size */
rb_bufsz = drm_order(rdev->cp.ring_size / 8);
- tmp = RB_NO_UPDATE | (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+ tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
#ifdef __BIG_ENDIAN
tmp |= BUF_SWAP_32BIT;
#endif
@@ -2166,8 +2170,19 @@ int r600_cp_resume(struct radeon_device *rdev)
WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA);
WREG32(CP_RB_RPTR_WR, 0);
WREG32(CP_RB_WPTR, 0);
- WREG32(CP_RB_RPTR_ADDR, rdev->cp.gpu_addr & 0xFFFFFFFF);
- WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->cp.gpu_addr));
+
+ /* set the wb address whether it's enabled or not */
+ WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
+ WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF);
+ WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF);
+
+ if (rdev->wb.enabled)
+ WREG32(SCRATCH_UMSK, 0xff);
+ else {
+ tmp |= RB_NO_UPDATE;
+ WREG32(SCRATCH_UMSK, 0);
+ }
+
mdelay(1);
WREG32(CP_RB_CNTL, tmp);
@@ -2219,9 +2234,10 @@ void r600_scratch_init(struct radeon_device *rdev)
int i;
rdev->scratch.num_reg = 7;
+ rdev->scratch.reg_base = SCRATCH_REG0;
for (i = 0; i < rdev->scratch.num_reg; i++) {
rdev->scratch.free[i] = true;
- rdev->scratch.reg[i] = SCRATCH_REG0 + (i * 4);
+ rdev->scratch.reg[i] = rdev->scratch.reg_base + (i * 4);
}
}
@@ -2265,88 +2281,34 @@ int r600_ring_test(struct radeon_device *rdev)
return r;
}
-void r600_wb_disable(struct radeon_device *rdev)
-{
- int r;
-
- WREG32(SCRATCH_UMSK, 0);
- if (rdev->wb.wb_obj) {
- r = radeon_bo_reserve(rdev->wb.wb_obj, false);
- if (unlikely(r != 0))
- return;
- radeon_bo_kunmap(rdev->wb.wb_obj);
- radeon_bo_unpin(rdev->wb.wb_obj);
- radeon_bo_unreserve(rdev->wb.wb_obj);
- }
-}
-
-void r600_wb_fini(struct radeon_device *rdev)
-{
- r600_wb_disable(rdev);
- if (rdev->wb.wb_obj) {
- radeon_bo_unref(&rdev->wb.wb_obj);
- rdev->wb.wb = NULL;
- rdev->wb.wb_obj = NULL;
- }
-}
-
-int r600_wb_enable(struct radeon_device *rdev)
-{
- int r;
-
- if (rdev->wb.wb_obj == NULL) {
- r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true,
- RADEON_GEM_DOMAIN_GTT, &rdev->wb.wb_obj);
- if (r) {
- dev_warn(rdev->dev, "(%d) create WB bo failed\n", r);
- return r;
- }
- r = radeon_bo_reserve(rdev->wb.wb_obj, false);
- if (unlikely(r != 0)) {
- r600_wb_fini(rdev);
- return r;
- }
- r = radeon_bo_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT,
- &rdev->wb.gpu_addr);
- if (r) {
- radeon_bo_unreserve(rdev->wb.wb_obj);
- dev_warn(rdev->dev, "(%d) pin WB bo failed\n", r);
- r600_wb_fini(rdev);
- return r;
- }
- r = radeon_bo_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb);
- radeon_bo_unreserve(rdev->wb.wb_obj);
- if (r) {
- dev_warn(rdev->dev, "(%d) map WB bo failed\n", r);
- r600_wb_fini(rdev);
- return r;
- }
- }
- WREG32(SCRATCH_ADDR, (rdev->wb.gpu_addr >> 8) & 0xFFFFFFFF);
- WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + 1024) & 0xFFFFFFFC);
- WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + 1024) & 0xFF);
- WREG32(SCRATCH_UMSK, 0xff);
- return 0;
-}
-
void r600_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence)
{
- /* Also consider EVENT_WRITE_EOP. it handles the interrupts + timestamps + events */
-
- radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0));
- radeon_ring_write(rdev, CACHE_FLUSH_AND_INV_EVENT);
- /* wait for 3D idle clean */
- radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
- radeon_ring_write(rdev, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
- radeon_ring_write(rdev, WAIT_3D_IDLE_bit | WAIT_3D_IDLECLEAN_bit);
- /* Emit fence sequence & fire IRQ */
- radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
- radeon_ring_write(rdev, ((rdev->fence_drv.scratch_reg - PACKET3_SET_CONFIG_REG_OFFSET) >> 2));
- radeon_ring_write(rdev, fence->seq);
- /* CP_INTERRUPT packet 3 no longer exists, use packet 0 */
- radeon_ring_write(rdev, PACKET0(CP_INT_STATUS, 0));
- radeon_ring_write(rdev, RB_INT_STAT);
+ if (rdev->wb.use_event) {
+ u64 addr = rdev->wb.gpu_addr + R600_WB_EVENT_OFFSET +
+ (u64)(rdev->fence_drv.scratch_reg - rdev->scratch.reg_base);
+ /* EVENT_WRITE_EOP - flush caches, send int */
+ radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
+ radeon_ring_write(rdev, EVENT_TYPE(CACHE_FLUSH_AND_INV_EVENT_TS) | EVENT_INDEX(5));
+ radeon_ring_write(rdev, addr & 0xffffffff);
+ radeon_ring_write(rdev, (upper_32_bits(addr) & 0xff) | DATA_SEL(1) | INT_SEL(2));
+ radeon_ring_write(rdev, fence->seq);
+ radeon_ring_write(rdev, 0);
+ } else {
+ radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0));
+ radeon_ring_write(rdev, EVENT_TYPE(CACHE_FLUSH_AND_INV_EVENT) | EVENT_INDEX(0));
+ /* wait for 3D idle clean */
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+ radeon_ring_write(rdev, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
+ radeon_ring_write(rdev, WAIT_3D_IDLE_bit | WAIT_3D_IDLECLEAN_bit);
+ /* Emit fence sequence & fire IRQ */
+ radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+ radeon_ring_write(rdev, ((rdev->fence_drv.scratch_reg - PACKET3_SET_CONFIG_REG_OFFSET) >> 2));
+ radeon_ring_write(rdev, fence->seq);
+ /* CP_INTERRUPT packet 3 no longer exists, use packet 0 */
+ radeon_ring_write(rdev, PACKET0(CP_INT_STATUS, 0));
+ radeon_ring_write(rdev, RB_INT_STAT);
+ }
}
int r600_copy_blit(struct radeon_device *rdev,
@@ -2428,19 +2390,12 @@ int r600_startup(struct radeon_device *rdev)
rdev->asic->copy = NULL;
dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
}
- /* pin copy shader into vram */
- if (rdev->r600_blit.shader_obj) {
- r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
- if (unlikely(r != 0))
- return r;
- r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
- &rdev->r600_blit.shader_gpu_addr);
- radeon_bo_unreserve(rdev->r600_blit.shader_obj);
- if (r) {
- dev_err(rdev->dev, "(%d) pin blit object failed\n", r);
- return r;
- }
- }
+
+ /* allocate wb buffer */
+ r = radeon_wb_init(rdev);
+ if (r)
+ return r;
+
/* Enable IRQ */
r = r600_irq_init(rdev);
if (r) {
@@ -2459,8 +2414,7 @@ int r600_startup(struct radeon_device *rdev)
r = r600_cp_resume(rdev);
if (r)
return r;
- /* write back buffer are not vital so don't worry about failure */
- r600_wb_enable(rdev);
+
return 0;
}
@@ -2519,7 +2473,7 @@ int r600_suspend(struct radeon_device *rdev)
r600_cp_stop(rdev);
rdev->cp.ready = false;
r600_irq_suspend(rdev);
- r600_wb_disable(rdev);
+ radeon_wb_disable(rdev);
r600_pcie_gart_disable(rdev);
/* unpin shaders bo */
if (rdev->r600_blit.shader_obj) {
@@ -2616,8 +2570,8 @@ int r600_init(struct radeon_device *rdev)
if (r) {
dev_err(rdev->dev, "disabling GPU acceleration\n");
r600_cp_fini(rdev);
- r600_wb_fini(rdev);
r600_irq_fini(rdev);
+ radeon_wb_fini(rdev);
radeon_irq_kms_fini(rdev);
r600_pcie_gart_fini(rdev);
rdev->accel_working = false;
@@ -2647,8 +2601,8 @@ void r600_fini(struct radeon_device *rdev)
r600_audio_fini(rdev);
r600_blit_fini(rdev);
r600_cp_fini(rdev);
- r600_wb_fini(rdev);
r600_irq_fini(rdev);
+ radeon_wb_fini(rdev);
radeon_irq_kms_fini(rdev);
r600_pcie_gart_fini(rdev);
radeon_agp_fini(rdev);
@@ -2983,10 +2937,13 @@ int r600_irq_init(struct radeon_device *rdev)
ih_rb_cntl = (IH_WPTR_OVERFLOW_ENABLE |
IH_WPTR_OVERFLOW_CLEAR |
(rb_bufsz << 1));
- /* WPTR writeback, not yet */
- /*ih_rb_cntl |= IH_WPTR_WRITEBACK_ENABLE;*/
- WREG32(IH_RB_WPTR_ADDR_LO, 0);
- WREG32(IH_RB_WPTR_ADDR_HI, 0);
+
+ if (rdev->wb.enabled)
+ ih_rb_cntl |= IH_WPTR_WRITEBACK_ENABLE;
+
+ /* set the writeback address whether it's enabled or not */
+ WREG32(IH_RB_WPTR_ADDR_LO, (rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFFFFFFFC);
+ WREG32(IH_RB_WPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFF);
WREG32(IH_RB_CNTL, ih_rb_cntl);
@@ -3070,6 +3027,7 @@ int r600_irq_set(struct radeon_device *rdev)
if (rdev->irq.sw_int) {
DRM_DEBUG("r600_irq_set: sw int\n");
cp_int_cntl |= RB_INT_ENABLE;
+ cp_int_cntl |= TIME_STAMP_INT_ENABLE;
}
if (rdev->irq.crtc_vblank_int[0]) {
DRM_DEBUG("r600_irq_set: vblank 0\n");
@@ -3244,8 +3202,10 @@ static inline u32 r600_get_ih_wptr(struct radeon_device *rdev)
{
u32 wptr, tmp;
- /* XXX use writeback */
- wptr = RREG32(IH_RB_WPTR);
+ if (rdev->wb.enabled)
+ wptr = rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4];
+ else
+ wptr = RREG32(IH_RB_WPTR);
if (wptr & RB_OVERFLOW) {
/* When a ring buffer overflow happen start parsing interrupt
@@ -3433,6 +3393,7 @@ restart_ih:
break;
case 181: /* CP EOP event */
DRM_DEBUG("IH: CP EOP\n");
+ radeon_fence_process(rdev);
break;
case 233: /* GUI IDLE */
DRM_DEBUG("IH: CP EOP\n");
diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c
index 3473c00781ff..8362974ef41a 100644
--- a/drivers/gpu/drm/radeon/r600_blit_kms.c
+++ b/drivers/gpu/drm/radeon/r600_blit_kms.c
@@ -472,9 +472,10 @@ int r600_blit_init(struct radeon_device *rdev)
u32 packet2s[16];
int num_packet2s = 0;
- /* don't reinitialize blit */
+ /* pin copy shader into vram if already initialized */
if (rdev->r600_blit.shader_obj)
- return 0;
+ goto done;
+
mutex_init(&rdev->r600_blit.mutex);
rdev->r600_blit.state_offset = 0;
@@ -532,6 +533,18 @@ int r600_blit_init(struct radeon_device *rdev)
memcpy(ptr + rdev->r600_blit.ps_offset, r6xx_ps, r6xx_ps_size * 4);
radeon_bo_kunmap(rdev->r600_blit.shader_obj);
radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+
+done:
+ r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+ if (unlikely(r != 0))
+ return r;
+ r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
+ &rdev->r600_blit.shader_gpu_addr);
+ radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+ if (r) {
+ dev_err(rdev->dev, "(%d) pin blit object failed\n", r);
+ return r;
+ }
rdev->mc.active_vram_size = rdev->mc.real_vram_size;
return 0;
}
@@ -554,7 +567,7 @@ void r600_blit_fini(struct radeon_device *rdev)
radeon_bo_unref(&rdev->r600_blit.shader_obj);
}
-int r600_vb_ib_get(struct radeon_device *rdev)
+static int r600_vb_ib_get(struct radeon_device *rdev)
{
int r;
r = radeon_ib_get(rdev, &rdev->r600_blit.vb_ib);
@@ -568,7 +581,7 @@ int r600_vb_ib_get(struct radeon_device *rdev)
return 0;
}
-void r600_vb_ib_put(struct radeon_device *rdev)
+static void r600_vb_ib_put(struct radeon_device *rdev)
{
radeon_fence_emit(rdev, rdev->r600_blit.vb_ib->fence);
radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
@@ -650,8 +663,8 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
int src_x = src_gpu_addr & 255;
int dst_x = dst_gpu_addr & 255;
int h = 1;
- src_gpu_addr = src_gpu_addr & ~255;
- dst_gpu_addr = dst_gpu_addr & ~255;
+ src_gpu_addr = src_gpu_addr & ~255ULL;
+ dst_gpu_addr = dst_gpu_addr & ~255ULL;
if (!src_x && !dst_x) {
h = (cur_size / max_bytes);
@@ -672,17 +685,6 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
if ((rdev->r600_blit.vb_used + 48) > rdev->r600_blit.vb_total) {
WARN_ON(1);
-
-#if 0
- r600_vb_ib_put(rdev);
-
- r600_nomm_put_vb(dev);
- r600_nomm_get_vb(dev);
- if (!dev_priv->blit_vb)
- return;
- set_shaders(dev);
- vb = r600_nomm_get_vb_ptr(dev);
-#endif
}
vb[0] = i2f(dst_x);
@@ -744,8 +746,8 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
int src_x = (src_gpu_addr & 255);
int dst_x = (dst_gpu_addr & 255);
int h = 1;
- src_gpu_addr = src_gpu_addr & ~255;
- dst_gpu_addr = dst_gpu_addr & ~255;
+ src_gpu_addr = src_gpu_addr & ~255ULL;
+ dst_gpu_addr = dst_gpu_addr & ~255ULL;
if (!src_x && !dst_x) {
h = (cur_size / max_bytes);
@@ -767,17 +769,6 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
if ((rdev->r600_blit.vb_used + 48) > rdev->r600_blit.vb_total) {
WARN_ON(1);
}
-#if 0
- if ((rdev->blit_vb->used + 48) > rdev->blit_vb->total) {
- r600_nomm_put_vb(dev);
- r600_nomm_get_vb(dev);
- if (!rdev->blit_vb)
- return;
-
- set_shaders(dev);
- vb = r600_nomm_get_vb_ptr(dev);
- }
-#endif
vb[0] = i2f(dst_x / 4);
vb[1] = 0;
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index 250a3a918193..37cc2aa9f923 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -170,6 +170,7 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
struct r600_cs_track *track = p->track;
u32 bpe = 0, pitch, slice_tile_max, size, tmp, height, pitch_align;
volatile u32 *ib = p->ib->ptr;
+ unsigned array_mode;
if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
dev_warn(p->dev, "FMASK or CMASK buffer are not supported by this kernel\n");
@@ -185,12 +186,12 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
/* pitch is the number of 8x8 tiles per row */
pitch = G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1;
slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1;
- height = size / (pitch * 8 * bpe);
+ slice_tile_max *= 64;
+ height = slice_tile_max / (pitch * 8);
if (height > 8192)
height = 8192;
- if (height > 7)
- height &= ~0x7;
- switch (G_0280A0_ARRAY_MODE(track->cb_color_info[i])) {
+ array_mode = G_0280A0_ARRAY_MODE(track->cb_color_info[i]);
+ switch (array_mode) {
case V_0280A0_ARRAY_LINEAR_GENERAL:
/* technically height & 0x7 */
break;
@@ -214,6 +215,9 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
__func__, __LINE__, pitch);
return -EINVAL;
}
+ /* avoid breaking userspace */
+ if (height > 7)
+ height &= ~0x7;
if (!IS_ALIGNED(height, 8)) {
dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
__func__, __LINE__, height);
@@ -222,13 +226,13 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
break;
case V_0280A0_ARRAY_2D_TILED_THIN1:
pitch_align = max((u32)track->nbanks,
- (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks));
+ (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks)) / 8;
if (!IS_ALIGNED(pitch, pitch_align)) {
dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
__func__, __LINE__, pitch);
return -EINVAL;
}
- if (!IS_ALIGNED((height / 8), track->nbanks)) {
+ if (!IS_ALIGNED((height / 8), track->npipes)) {
dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
__func__, __LINE__, height);
return -EINVAL;
@@ -243,8 +247,18 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
/* check offset */
tmp = height * pitch * 8 * bpe;
if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
- dev_warn(p->dev, "%s offset[%d] %d too big\n", __func__, i, track->cb_color_bo_offset[i]);
- return -EINVAL;
+ if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) {
+ /* the initial DDX does bad things with the CB size occasionally */
+ /* it rounds up height too far for slice tile max but the BO is smaller */
+ tmp = (height - 7) * 8 * bpe;
+ if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
+ dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
+ return -EINVAL;
+ }
+ } else {
+ dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
+ return -EINVAL;
+ }
}
if (!IS_ALIGNED(track->cb_color_bo_offset[i], track->group_size)) {
dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->cb_color_bo_offset[i]);
@@ -296,7 +310,7 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
/* Check depth buffer */
if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
G_028800_Z_ENABLE(track->db_depth_control)) {
- u32 nviews, bpe, ntiles, pitch, pitch_align, height, size;
+ u32 nviews, bpe, ntiles, pitch, pitch_align, height, size, slice_tile_max;
if (track->db_bo == NULL) {
dev_warn(p->dev, "z/stencil with no depth buffer\n");
return -EINVAL;
@@ -340,11 +354,11 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
} else {
size = radeon_bo_size(track->db_bo);
pitch = G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1;
- height = size / (pitch * 8 * bpe);
- height &= ~0x7;
- if (!height)
- height = 8;
-
+ slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
+ slice_tile_max *= 64;
+ height = slice_tile_max / (pitch * 8);
+ if (height > 8192)
+ height = 8192;
switch (G_028010_ARRAY_MODE(track->db_depth_info)) {
case V_028010_ARRAY_1D_TILED_THIN1:
pitch_align = (max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8);
@@ -353,6 +367,8 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
__func__, __LINE__, pitch);
return -EINVAL;
}
+ /* don't break userspace */
+ height &= ~0x7;
if (!IS_ALIGNED(height, 8)) {
dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
__func__, __LINE__, height);
@@ -361,13 +377,13 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
break;
case V_028010_ARRAY_2D_TILED_THIN1:
pitch_align = max((u32)track->nbanks,
- (u32)(((track->group_size / 8) / bpe) * track->nbanks));
+ (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8;
if (!IS_ALIGNED(pitch, pitch_align)) {
dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
__func__, __LINE__, pitch);
return -EINVAL;
}
- if ((height / 8) & (track->nbanks - 1)) {
+ if (!IS_ALIGNED((height / 8), track->npipes)) {
dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
__func__, __LINE__, height);
return -EINVAL;
@@ -1138,7 +1154,7 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 i
break;
case V_038000_ARRAY_2D_TILED_THIN1:
pitch_align = max((u32)track->nbanks,
- (u32)(((track->group_size / 8) / bpe) * track->nbanks));
+ (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8;
if (!IS_ALIGNED(pitch, pitch_align)) {
dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
__func__, __LINE__, pitch);
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index 858a1920c0d7..966a793e225b 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -474,6 +474,7 @@
#define VGT_VERTEX_REUSE_BLOCK_CNTL 0x28C58
#define VTX_REUSE_DEPTH_MASK 0x000000FF
#define VGT_EVENT_INITIATOR 0x28a90
+# define CACHE_FLUSH_AND_INV_EVENT_TS (0x14 << 0)
# define CACHE_FLUSH_AND_INV_EVENT (0x16 << 0)
#define VM_CONTEXT0_CNTL 0x1410
@@ -775,7 +776,27 @@
#define PACKET3_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16)
#define PACKET3_COND_WRITE 0x45
#define PACKET3_EVENT_WRITE 0x46
+#define EVENT_TYPE(x) ((x) << 0)
+#define EVENT_INDEX(x) ((x) << 8)
+ /* 0 - any non-TS event
+ * 1 - ZPASS_DONE
+ * 2 - SAMPLE_PIPELINESTAT
+ * 3 - SAMPLE_STREAMOUTSTAT*
+ * 4 - *S_PARTIAL_FLUSH
+ * 5 - TS events
+ */
#define PACKET3_EVENT_WRITE_EOP 0x47
+#define DATA_SEL(x) ((x) << 29)
+ /* 0 - discard
+ * 1 - send low 32bit data
+ * 2 - send 64bit data
+ * 3 - send 64bit counter value
+ */
+#define INT_SEL(x) ((x) << 24)
+ /* 0 - none
+ * 1 - interrupt only (DATA_SEL = 0)
+ * 2 - interrupt when data write is confirmed
+ */
#define PACKET3_ONE_REG_WRITE 0x57
#define PACKET3_SET_CONFIG_REG 0x68
#define PACKET3_SET_CONFIG_REG_OFFSET 0x00008000
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 9ff38c99a6ea..73f600d39ad4 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -88,7 +88,6 @@ extern int radeon_benchmarking;
extern int radeon_testing;
extern int radeon_connector_table;
extern int radeon_tv;
-extern int radeon_new_pll;
extern int radeon_audio;
extern int radeon_disp_priority;
extern int radeon_hw_i2c;
@@ -366,6 +365,7 @@ bool radeon_atombios_sideport_present(struct radeon_device *rdev);
*/
struct radeon_scratch {
unsigned num_reg;
+ uint32_t reg_base;
bool free[32];
uint32_t reg[32];
};
@@ -594,8 +594,15 @@ struct radeon_wb {
struct radeon_bo *wb_obj;
volatile uint32_t *wb;
uint64_t gpu_addr;
+ bool enabled;
+ bool use_event;
};
+#define RADEON_WB_SCRATCH_OFFSET 0
+#define RADEON_WB_CP_RPTR_OFFSET 1024
+#define R600_WB_IH_WPTR_OFFSET 2048
+#define R600_WB_EVENT_OFFSET 3072
+
/**
* struct radeon_pm - power management datas
* @max_bandwidth: maximum bandwidth the gpu has (MByte/s)
@@ -1124,6 +1131,12 @@ void r600_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence)
void r600_kms_blit_copy(struct radeon_device *rdev,
u64 src_gpu_addr, u64 dst_gpu_addr,
int size_bytes);
+/* evergreen blit */
+int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes);
+void evergreen_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence);
+void evergreen_kms_blit_copy(struct radeon_device *rdev,
+ u64 src_gpu_addr, u64 dst_gpu_addr,
+ int size_bytes);
static inline uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg)
{
@@ -1341,6 +1354,9 @@ extern void radeon_update_bandwidth_info(struct radeon_device *rdev);
extern void radeon_update_display_priority(struct radeon_device *rdev);
extern bool radeon_boot_test_post_card(struct radeon_device *rdev);
extern void radeon_scratch_init(struct radeon_device *rdev);
+extern void radeon_wb_fini(struct radeon_device *rdev);
+extern int radeon_wb_init(struct radeon_device *rdev);
+extern void radeon_wb_disable(struct radeon_device *rdev);
extern void radeon_surface_init(struct radeon_device *rdev);
extern int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data);
extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable);
@@ -1425,9 +1441,6 @@ extern int r600_pcie_gart_init(struct radeon_device *rdev);
extern void r600_pcie_gart_tlb_flush(struct radeon_device *rdev);
extern int r600_ib_test(struct radeon_device *rdev);
extern int r600_ring_test(struct radeon_device *rdev);
-extern void r600_wb_fini(struct radeon_device *rdev);
-extern int r600_wb_enable(struct radeon_device *rdev);
-extern void r600_wb_disable(struct radeon_device *rdev);
extern void r600_scratch_init(struct radeon_device *rdev);
extern int r600_blit_init(struct radeon_device *rdev);
extern void r600_blit_fini(struct radeon_device *rdev);
@@ -1465,6 +1478,8 @@ extern void r700_cp_stop(struct radeon_device *rdev);
extern void r700_cp_fini(struct radeon_device *rdev);
extern void evergreen_disable_interrupt_state(struct radeon_device *rdev);
extern int evergreen_irq_set(struct radeon_device *rdev);
+extern int evergreen_blit_init(struct radeon_device *rdev);
+extern void evergreen_blit_fini(struct radeon_device *rdev);
/* radeon_acpi.c */
#if defined(CONFIG_ACPI)
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 25e1dd197791..64fb89ecbf74 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -726,9 +726,9 @@ static struct radeon_asic evergreen_asic = {
.get_vblank_counter = &evergreen_get_vblank_counter,
.fence_ring_emit = &r600_fence_ring_emit,
.cs_parse = &evergreen_cs_parse,
- .copy_blit = NULL,
- .copy_dma = NULL,
- .copy = NULL,
+ .copy_blit = &evergreen_copy_blit,
+ .copy_dma = &evergreen_copy_blit,
+ .copy = &evergreen_copy_blit,
.get_engine_clock = &radeon_atom_get_engine_clock,
.set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index a5aff755f0d2..740988244143 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -108,9 +108,6 @@ void r100_irq_disable(struct radeon_device *rdev);
void r100_mc_stop(struct radeon_device *rdev, struct r100_mc_save *save);
void r100_mc_resume(struct radeon_device *rdev, struct r100_mc_save *save);
void r100_vram_init_sizes(struct radeon_device *rdev);
-void r100_wb_disable(struct radeon_device *rdev);
-void r100_wb_fini(struct radeon_device *rdev);
-int r100_wb_init(struct radeon_device *rdev);
int r100_cp_reset(struct radeon_device *rdev);
void r100_vga_render_disable(struct radeon_device *rdev);
void r100_restore_sanity(struct radeon_device *rdev);
@@ -257,11 +254,6 @@ void r600_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
int r600_cs_parse(struct radeon_cs_parser *p);
void r600_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence);
-int r600_copy_dma(struct radeon_device *rdev,
- uint64_t src_offset,
- uint64_t dst_offset,
- unsigned num_pages,
- struct radeon_fence *fence);
int r600_irq_process(struct radeon_device *rdev);
int r600_irq_set(struct radeon_device *rdev);
bool r600_gpu_is_lockup(struct radeon_device *rdev);
@@ -307,6 +299,9 @@ int evergreen_resume(struct radeon_device *rdev);
bool evergreen_gpu_is_lockup(struct radeon_device *rdev);
int evergreen_asic_reset(struct radeon_device *rdev);
void evergreen_bandwidth_update(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);
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_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 8e43ddae70cc..04cac7ec9039 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -1112,8 +1112,7 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
* pre-DCE 3.0 r6xx hardware. This might need to be adjusted per
* family.
*/
- if (!radeon_new_pll)
- p1pll->pll_out_min = 64800;
+ p1pll->pll_out_min = 64800;
}
p1pll->pll_in_min =
@@ -1277,36 +1276,27 @@ bool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder,
return false;
}
-static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct
- radeon_encoder
- *encoder,
- int id)
+bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
+ struct radeon_atom_ss *ss,
+ int id)
{
- struct drm_device *dev = encoder->base.dev;
- struct radeon_device *rdev = dev->dev_private;
struct radeon_mode_info *mode_info = &rdev->mode_info;
int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info);
- uint16_t data_offset;
+ uint16_t data_offset, size;
struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info;
uint8_t frev, crev;
- struct radeon_atom_ss *ss = NULL;
- int i;
-
- if (id > ATOM_MAX_SS_ENTRY)
- return NULL;
+ int i, num_indices;
- if (atom_parse_data_header(mode_info->atom_context, index, NULL,
+ memset(ss, 0, sizeof(struct radeon_atom_ss));
+ if (atom_parse_data_header(mode_info->atom_context, index, &size,
&frev, &crev, &data_offset)) {
ss_info =
(struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset);
- ss =
- kzalloc(sizeof(struct radeon_atom_ss), GFP_KERNEL);
-
- if (!ss)
- return NULL;
+ num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+ sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
- for (i = 0; i < ATOM_MAX_SS_ENTRY; i++) {
+ for (i = 0; i < num_indices; i++) {
if (ss_info->asSS_Info[i].ucSS_Id == id) {
ss->percentage =
le16_to_cpu(ss_info->asSS_Info[i].usSpreadSpectrumPercentage);
@@ -1315,11 +1305,88 @@ static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct
ss->delay = ss_info->asSS_Info[i].ucSS_Delay;
ss->range = ss_info->asSS_Info[i].ucSS_Range;
ss->refdiv = ss_info->asSS_Info[i].ucRecommendedRef_Div;
- break;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+union asic_ss_info {
+ struct _ATOM_ASIC_INTERNAL_SS_INFO info;
+ struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2;
+ struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3;
+};
+
+bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
+ struct radeon_atom_ss *ss,
+ int id, u32 clock)
+{
+ struct radeon_mode_info *mode_info = &rdev->mode_info;
+ int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+ uint16_t data_offset, size;
+ union asic_ss_info *ss_info;
+ uint8_t frev, crev;
+ int i, num_indices;
+
+ memset(ss, 0, sizeof(struct radeon_atom_ss));
+ if (atom_parse_data_header(mode_info->atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+
+ ss_info =
+ (union asic_ss_info *)(mode_info->atom_context->bios + data_offset);
+
+ switch (frev) {
+ case 1:
+ num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+ sizeof(ATOM_ASIC_SS_ASSIGNMENT);
+
+ for (i = 0; i < num_indices; i++) {
+ if ((ss_info->info.asSpreadSpectrum[i].ucClockIndication == id) &&
+ (clock <= ss_info->info.asSpreadSpectrum[i].ulTargetClockRange)) {
+ ss->percentage =
+ le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
+ ss->type = ss_info->info.asSpreadSpectrum[i].ucSpreadSpectrumMode;
+ ss->rate = le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadRateInKhz);
+ return true;
+ }
+ }
+ break;
+ case 2:
+ num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+ sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
+ for (i = 0; i < num_indices; i++) {
+ if ((ss_info->info_2.asSpreadSpectrum[i].ucClockIndication == id) &&
+ (clock <= ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange)) {
+ ss->percentage =
+ le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
+ ss->type = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode;
+ ss->rate = le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz);
+ return true;
+ }
}
+ break;
+ case 3:
+ num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+ sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
+ for (i = 0; i < num_indices; i++) {
+ if ((ss_info->info_3.asSpreadSpectrum[i].ucClockIndication == id) &&
+ (clock <= ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange)) {
+ ss->percentage =
+ le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
+ ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode;
+ ss->rate = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz);
+ return true;
+ }
+ }
+ break;
+ default:
+ DRM_ERROR("Unsupported ASIC_InternalSS_Info table: %d %d\n", frev, crev);
+ break;
}
+
}
- return ss;
+ return false;
}
union lvds_info {
@@ -1371,7 +1438,7 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth);
lvds->panel_pwr_delay =
le16_to_cpu(lvds_info->info.usOffDelayInMs);
- lvds->lvds_misc = lvds_info->info.ucLVDS_Misc;
+ lvds->lcd_misc = lvds_info->info.ucLVDS_Misc;
misc = le16_to_cpu(lvds_info->info.sLCDTiming.susModeMiscInfo.usAccess);
if (misc & ATOM_VSYNC_POLARITY)
@@ -1388,19 +1455,7 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
/* set crtc values */
drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
- lvds->ss = radeon_atombios_get_ss_info(encoder, lvds_info->info.ucSS_Id);
-
- if (ASIC_IS_AVIVO(rdev)) {
- if (radeon_new_pll == 0)
- lvds->pll_algo = PLL_ALGO_LEGACY;
- else
- lvds->pll_algo = PLL_ALGO_NEW;
- } else {
- if (radeon_new_pll == 1)
- lvds->pll_algo = PLL_ALGO_NEW;
- else
- lvds->pll_algo = PLL_ALGO_LEGACY;
- }
+ lvds->lcd_ss_id = lvds_info->info.ucSS_Id;
encoder->native_mode = lvds->native_mode;
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index ecc1a8fafbfd..4dac4b0a02ee 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -326,6 +326,34 @@ int radeon_connector_set_property(struct drm_connector *connector, struct drm_pr
}
}
+ if (property == rdev->mode_info.underscan_hborder_property) {
+ /* need to find digital encoder on connector */
+ encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
+ if (!encoder)
+ return 0;
+
+ radeon_encoder = to_radeon_encoder(encoder);
+
+ if (radeon_encoder->underscan_hborder != val) {
+ radeon_encoder->underscan_hborder = val;
+ radeon_property_change_mode(&radeon_encoder->base);
+ }
+ }
+
+ if (property == rdev->mode_info.underscan_vborder_property) {
+ /* need to find digital encoder on connector */
+ encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
+ if (!encoder)
+ return 0;
+
+ radeon_encoder = to_radeon_encoder(encoder);
+
+ if (radeon_encoder->underscan_vborder != val) {
+ radeon_encoder->underscan_vborder = val;
+ radeon_property_change_mode(&radeon_encoder->base);
+ }
+ }
+
if (property == rdev->mode_info.tv_std_property) {
encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TVDAC);
if (!encoder) {
@@ -635,6 +663,11 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
ret = connector_status_connected;
}
} else {
+
+ /* if we aren't forcing don't do destructive polling */
+ if (!force)
+ return connector->status;
+
if (radeon_connector->dac_load_detect && encoder) {
encoder_funcs = encoder->helper_private;
ret = encoder_funcs->detect(encoder, connector);
@@ -822,6 +855,11 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
if ((ret == connector_status_connected) && (radeon_connector->use_digital == true))
goto out;
+ if (!force) {
+ ret = connector->status;
+ goto out;
+ }
+
/* find analog encoder */
if (radeon_connector->dac_load_detect) {
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
@@ -1153,10 +1191,17 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.coherent_mode_property,
1);
- if (ASIC_IS_AVIVO(rdev))
+ if (ASIC_IS_AVIVO(rdev)) {
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.underscan_property,
UNDERSCAN_AUTO);
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.underscan_hborder_property,
+ 0);
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.underscan_vborder_property,
+ 0);
+ }
if (connector_type == DRM_MODE_CONNECTOR_DVII) {
radeon_connector->dac_load_detect = true;
drm_connector_attach_property(&radeon_connector->base,
@@ -1181,10 +1226,17 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.coherent_mode_property,
1);
- if (ASIC_IS_AVIVO(rdev))
+ if (ASIC_IS_AVIVO(rdev)) {
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.underscan_property,
UNDERSCAN_AUTO);
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.underscan_hborder_property,
+ 0);
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.underscan_vborder_property,
+ 0);
+ }
subpixel_order = SubPixelHorizontalRGB;
break;
case DRM_MODE_CONNECTOR_DisplayPort:
@@ -1212,10 +1264,17 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.coherent_mode_property,
1);
- if (ASIC_IS_AVIVO(rdev))
+ if (ASIC_IS_AVIVO(rdev)) {
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.underscan_property,
UNDERSCAN_AUTO);
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.underscan_hborder_property,
+ 0);
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.underscan_vborder_property,
+ 0);
+ }
break;
case DRM_MODE_CONNECTOR_SVIDEO:
case DRM_MODE_CONNECTOR_Composite:
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index fcc79b5d22d1..6d64a2705f12 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -268,7 +268,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
}
r = radeon_ib_schedule(rdev, parser.ib);
if (r) {
- DRM_ERROR("Faild to schedule IB !\n");
+ DRM_ERROR("Failed to schedule IB !\n");
}
radeon_cs_parser_fini(&parser, r);
mutex_unlock(&rdev->cs_mutex);
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index 3eef567b0421..017ac54920fb 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -118,22 +118,25 @@ static void radeon_show_cursor(struct drm_crtc *crtc)
}
static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
- uint32_t gpu_addr)
+ uint64_t gpu_addr)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct radeon_device *rdev = crtc->dev->dev_private;
if (ASIC_IS_DCE4(rdev)) {
- WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 0);
- WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, gpu_addr);
+ WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
+ upper_32_bits(gpu_addr));
+ WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+ gpu_addr & 0xffffffff);
} else if (ASIC_IS_AVIVO(rdev)) {
if (rdev->family >= CHIP_RV770) {
if (radeon_crtc->crtc_id)
- WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, 0);
+ WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
else
- WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, 0);
+ WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
}
- WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, gpu_addr);
+ WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+ gpu_addr & 0xffffffff);
} else {
radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr;
/* offset is from DISP(2)_BASE_ADDRESS */
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 256d204a6d24..8adfedfe547f 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -117,9 +117,10 @@ void radeon_scratch_init(struct radeon_device *rdev)
} else {
rdev->scratch.num_reg = 7;
}
+ rdev->scratch.reg_base = RADEON_SCRATCH_REG0;
for (i = 0; i < rdev->scratch.num_reg; i++) {
rdev->scratch.free[i] = true;
- rdev->scratch.reg[i] = RADEON_SCRATCH_REG0 + (i * 4);
+ rdev->scratch.reg[i] = rdev->scratch.reg_base + (i * 4);
}
}
@@ -149,6 +150,86 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
}
}
+void radeon_wb_disable(struct radeon_device *rdev)
+{
+ int r;
+
+ if (rdev->wb.wb_obj) {
+ r = radeon_bo_reserve(rdev->wb.wb_obj, false);
+ if (unlikely(r != 0))
+ return;
+ radeon_bo_kunmap(rdev->wb.wb_obj);
+ radeon_bo_unpin(rdev->wb.wb_obj);
+ radeon_bo_unreserve(rdev->wb.wb_obj);
+ }
+ rdev->wb.enabled = false;
+}
+
+void radeon_wb_fini(struct radeon_device *rdev)
+{
+ radeon_wb_disable(rdev);
+ if (rdev->wb.wb_obj) {
+ radeon_bo_unref(&rdev->wb.wb_obj);
+ rdev->wb.wb = NULL;
+ rdev->wb.wb_obj = NULL;
+ }
+}
+
+int radeon_wb_init(struct radeon_device *rdev)
+{
+ int r;
+
+ if (rdev->wb.wb_obj == NULL) {
+ r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true,
+ RADEON_GEM_DOMAIN_GTT, &rdev->wb.wb_obj);
+ if (r) {
+ dev_warn(rdev->dev, "(%d) create WB bo failed\n", r);
+ return r;
+ }
+ }
+ r = radeon_bo_reserve(rdev->wb.wb_obj, false);
+ if (unlikely(r != 0)) {
+ radeon_wb_fini(rdev);
+ return r;
+ }
+ r = radeon_bo_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT,
+ &rdev->wb.gpu_addr);
+ if (r) {
+ radeon_bo_unreserve(rdev->wb.wb_obj);
+ dev_warn(rdev->dev, "(%d) pin WB bo failed\n", r);
+ radeon_wb_fini(rdev);
+ return r;
+ }
+ r = radeon_bo_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb);
+ radeon_bo_unreserve(rdev->wb.wb_obj);
+ if (r) {
+ dev_warn(rdev->dev, "(%d) map WB bo failed\n", r);
+ radeon_wb_fini(rdev);
+ return r;
+ }
+
+ /* disable event_write fences */
+ rdev->wb.use_event = false;
+ /* disabled via module param */
+ if (radeon_no_wb == 1)
+ rdev->wb.enabled = false;
+ else {
+ /* often unreliable on AGP */
+ if (rdev->flags & RADEON_IS_AGP) {
+ rdev->wb.enabled = false;
+ } else {
+ rdev->wb.enabled = true;
+ /* event_write fences are only available on r600+ */
+ if (rdev->family >= CHIP_R600)
+ rdev->wb.use_event = true;
+ }
+ }
+
+ dev_info(rdev->dev, "WB %sabled\n", rdev->wb.enabled ? "en" : "dis");
+
+ return 0;
+}
+
/**
* radeon_vram_location - try to find VRAM location
* @rdev: radeon device structure holding all necessary informations
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index b92d2f2fcbed..0383631da69c 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -454,13 +454,13 @@ static inline uint32_t radeon_div(uint64_t n, uint32_t d)
return n;
}
-static void radeon_compute_pll_legacy(struct radeon_pll *pll,
- uint64_t freq,
- uint32_t *dot_clock_p,
- uint32_t *fb_div_p,
- uint32_t *frac_fb_div_p,
- uint32_t *ref_div_p,
- uint32_t *post_div_p)
+void radeon_compute_pll(struct radeon_pll *pll,
+ uint64_t freq,
+ uint32_t *dot_clock_p,
+ uint32_t *fb_div_p,
+ uint32_t *frac_fb_div_p,
+ uint32_t *ref_div_p,
+ uint32_t *post_div_p)
{
uint32_t min_ref_div = pll->min_ref_div;
uint32_t max_ref_div = pll->max_ref_div;
@@ -513,7 +513,7 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
max_fractional_feed_div = pll->max_frac_feedback_div;
}
- for (post_div = min_post_div; post_div <= max_post_div; ++post_div) {
+ for (post_div = max_post_div; post_div >= min_post_div; --post_div) {
uint32_t ref_div;
if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
@@ -631,214 +631,6 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
*post_div_p = best_post_div;
}
-static bool
-calc_fb_div(struct radeon_pll *pll,
- uint32_t freq,
- uint32_t post_div,
- uint32_t ref_div,
- uint32_t *fb_div,
- uint32_t *fb_div_frac)
-{
- fixed20_12 feedback_divider, a, b;
- u32 vco_freq;
-
- vco_freq = freq * post_div;
- /* feedback_divider = vco_freq * ref_div / pll->reference_freq; */
- a.full = dfixed_const(pll->reference_freq);
- feedback_divider.full = dfixed_const(vco_freq);
- feedback_divider.full = dfixed_div(feedback_divider, a);
- a.full = dfixed_const(ref_div);
- feedback_divider.full = dfixed_mul(feedback_divider, a);
-
- if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
- /* feedback_divider = floor((feedback_divider * 10.0) + 0.5) * 0.1; */
- a.full = dfixed_const(10);
- feedback_divider.full = dfixed_mul(feedback_divider, a);
- feedback_divider.full += dfixed_const_half(0);
- feedback_divider.full = dfixed_floor(feedback_divider);
- feedback_divider.full = dfixed_div(feedback_divider, a);
-
- /* *fb_div = floor(feedback_divider); */
- a.full = dfixed_floor(feedback_divider);
- *fb_div = dfixed_trunc(a);
- /* *fb_div_frac = fmod(feedback_divider, 1.0) * 10.0; */
- a.full = dfixed_const(10);
- b.full = dfixed_mul(feedback_divider, a);
-
- feedback_divider.full = dfixed_floor(feedback_divider);
- feedback_divider.full = dfixed_mul(feedback_divider, a);
- feedback_divider.full = b.full - feedback_divider.full;
- *fb_div_frac = dfixed_trunc(feedback_divider);
- } else {
- /* *fb_div = floor(feedback_divider + 0.5); */
- feedback_divider.full += dfixed_const_half(0);
- feedback_divider.full = dfixed_floor(feedback_divider);
-
- *fb_div = dfixed_trunc(feedback_divider);
- *fb_div_frac = 0;
- }
-
- if (((*fb_div) < pll->min_feedback_div) || ((*fb_div) > pll->max_feedback_div))
- return false;
- else
- return true;
-}
-
-static bool
-calc_fb_ref_div(struct radeon_pll *pll,
- uint32_t freq,
- uint32_t post_div,
- uint32_t *fb_div,
- uint32_t *fb_div_frac,
- uint32_t *ref_div)
-{
- fixed20_12 ffreq, max_error, error, pll_out, a;
- u32 vco;
- u32 pll_out_min, pll_out_max;
-
- if (pll->flags & RADEON_PLL_IS_LCD) {
- pll_out_min = pll->lcd_pll_out_min;
- pll_out_max = pll->lcd_pll_out_max;
- } else {
- pll_out_min = pll->pll_out_min;
- pll_out_max = pll->pll_out_max;
- }
-
- ffreq.full = dfixed_const(freq);
- /* max_error = ffreq * 0.0025; */
- a.full = dfixed_const(400);
- max_error.full = dfixed_div(ffreq, a);
-
- for ((*ref_div) = pll->min_ref_div; (*ref_div) < pll->max_ref_div; ++(*ref_div)) {
- if (calc_fb_div(pll, freq, post_div, (*ref_div), fb_div, fb_div_frac)) {
- vco = pll->reference_freq * (((*fb_div) * 10) + (*fb_div_frac));
- vco = vco / ((*ref_div) * 10);
-
- if ((vco < pll_out_min) || (vco > pll_out_max))
- continue;
-
- /* pll_out = vco / post_div; */
- a.full = dfixed_const(post_div);
- pll_out.full = dfixed_const(vco);
- pll_out.full = dfixed_div(pll_out, a);
-
- if (pll_out.full >= ffreq.full) {
- error.full = pll_out.full - ffreq.full;
- if (error.full <= max_error.full)
- return true;
- }
- }
- }
- return false;
-}
-
-static void radeon_compute_pll_new(struct radeon_pll *pll,
- uint64_t freq,
- uint32_t *dot_clock_p,
- uint32_t *fb_div_p,
- uint32_t *frac_fb_div_p,
- uint32_t *ref_div_p,
- uint32_t *post_div_p)
-{
- u32 fb_div = 0, fb_div_frac = 0, post_div = 0, ref_div = 0;
- u32 best_freq = 0, vco_frequency;
- u32 pll_out_min, pll_out_max;
-
- if (pll->flags & RADEON_PLL_IS_LCD) {
- pll_out_min = pll->lcd_pll_out_min;
- pll_out_max = pll->lcd_pll_out_max;
- } else {
- pll_out_min = pll->pll_out_min;
- pll_out_max = pll->pll_out_max;
- }
-
- /* freq = freq / 10; */
- do_div(freq, 10);
-
- if (pll->flags & RADEON_PLL_USE_POST_DIV) {
- post_div = pll->post_div;
- if ((post_div < pll->min_post_div) || (post_div > pll->max_post_div))
- goto done;
-
- vco_frequency = freq * post_div;
- if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
- goto done;
-
- if (pll->flags & RADEON_PLL_USE_REF_DIV) {
- ref_div = pll->reference_div;
- if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
- goto done;
- if (!calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
- goto done;
- }
- } else {
- for (post_div = pll->max_post_div; post_div >= pll->min_post_div; --post_div) {
- if (pll->flags & RADEON_PLL_LEGACY) {
- if ((post_div == 5) ||
- (post_div == 7) ||
- (post_div == 9) ||
- (post_div == 10) ||
- (post_div == 11))
- continue;
- }
-
- if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
- continue;
-
- vco_frequency = freq * post_div;
- if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
- continue;
- if (pll->flags & RADEON_PLL_USE_REF_DIV) {
- ref_div = pll->reference_div;
- if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
- goto done;
- if (calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
- break;
- } else {
- if (calc_fb_ref_div(pll, freq, post_div, &fb_div, &fb_div_frac, &ref_div))
- break;
- }
- }
- }
-
- best_freq = pll->reference_freq * 10 * fb_div;
- best_freq += pll->reference_freq * fb_div_frac;
- best_freq = best_freq / (ref_div * post_div);
-
-done:
- if (best_freq == 0)
- DRM_ERROR("Couldn't find valid PLL dividers\n");
-
- *dot_clock_p = best_freq / 10;
- *fb_div_p = fb_div;
- *frac_fb_div_p = fb_div_frac;
- *ref_div_p = ref_div;
- *post_div_p = post_div;
-
- DRM_DEBUG_KMS("%u %d.%d, %d, %d\n", *dot_clock_p, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p);
-}
-
-void radeon_compute_pll(struct radeon_pll *pll,
- uint64_t freq,
- uint32_t *dot_clock_p,
- uint32_t *fb_div_p,
- uint32_t *frac_fb_div_p,
- uint32_t *ref_div_p,
- uint32_t *post_div_p)
-{
- switch (pll->algo) {
- case PLL_ALGO_NEW:
- radeon_compute_pll_new(pll, freq, dot_clock_p, fb_div_p,
- frac_fb_div_p, ref_div_p, post_div_p);
- break;
- case PLL_ALGO_LEGACY:
- default:
- radeon_compute_pll_legacy(pll, freq, dot_clock_p, fb_div_p,
- frac_fb_div_p, ref_div_p, post_div_p);
- break;
- }
-}
-
static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
{
struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
@@ -1002,6 +794,24 @@ static int radeon_modeset_create_props(struct radeon_device *rdev)
radeon_underscan_enum_list[i].name);
}
+ rdev->mode_info.underscan_hborder_property =
+ drm_property_create(rdev->ddev,
+ DRM_MODE_PROP_RANGE,
+ "underscan hborder", 2);
+ if (!rdev->mode_info.underscan_hborder_property)
+ return -ENOMEM;
+ rdev->mode_info.underscan_hborder_property->values[0] = 0;
+ rdev->mode_info.underscan_hborder_property->values[1] = 128;
+
+ rdev->mode_info.underscan_vborder_property =
+ drm_property_create(rdev->ddev,
+ DRM_MODE_PROP_RANGE,
+ "underscan vborder", 2);
+ if (!rdev->mode_info.underscan_vborder_property)
+ return -ENOMEM;
+ rdev->mode_info.underscan_vborder_property->values[0] = 0;
+ rdev->mode_info.underscan_vborder_property->values[1] = 128;
+
return 0;
}
@@ -1159,8 +969,14 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
((radeon_encoder->underscan_type == UNDERSCAN_AUTO) &&
drm_detect_hdmi_monitor(radeon_connector->edid) &&
is_hdtv_mode(mode)))) {
- radeon_crtc->h_border = (mode->hdisplay >> 5) + 16;
- radeon_crtc->v_border = (mode->vdisplay >> 5) + 16;
+ if (radeon_encoder->underscan_hborder != 0)
+ radeon_crtc->h_border = radeon_encoder->underscan_hborder;
+ else
+ radeon_crtc->h_border = (mode->hdisplay >> 5) + 16;
+ if (radeon_encoder->underscan_vborder != 0)
+ radeon_crtc->v_border = radeon_encoder->underscan_vborder;
+ else
+ radeon_crtc->v_border = (mode->vdisplay >> 5) + 16;
radeon_crtc->rmx_type = RMX_FULL;
src_v = crtc->mode.vdisplay;
dst_v = crtc->mode.vdisplay - (radeon_crtc->v_border * 2);
@@ -1195,3 +1011,156 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
}
return true;
}
+
+/*
+ * Retrieve current video scanout position of crtc on a given gpu.
+ *
+ * \param rdev Device to query.
+ * \param crtc Crtc to query.
+ * \param *vpos Location where vertical scanout position should be stored.
+ * \param *hpos Location where horizontal scanout position should go.
+ *
+ * Returns vpos as a positive number while in active scanout area.
+ * Returns vpos as a negative number inside vblank, counting the number
+ * of scanlines to go until end of vblank, e.g., -1 means "one scanline
+ * until start of active scanout / end of vblank."
+ *
+ * \return Flags, or'ed together as follows:
+ *
+ * RADEON_SCANOUTPOS_VALID = Query successfull.
+ * RADEON_SCANOUTPOS_INVBL = Inside vblank.
+ * RADEON_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of
+ * this flag means that returned position may be offset by a constant but
+ * unknown small number of scanlines wrt. real scanout position.
+ *
+ */
+int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos)
+{
+ u32 stat_crtc = 0, vbl = 0, position = 0;
+ int vbl_start, vbl_end, vtotal, ret = 0;
+ bool in_vbl = true;
+
+ if (ASIC_IS_DCE4(rdev)) {
+ if (crtc == 0) {
+ vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+ EVERGREEN_CRTC0_REGISTER_OFFSET);
+ position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+ EVERGREEN_CRTC0_REGISTER_OFFSET);
+ ret |= RADEON_SCANOUTPOS_VALID;
+ }
+ if (crtc == 1) {
+ vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+ EVERGREEN_CRTC1_REGISTER_OFFSET);
+ position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+ EVERGREEN_CRTC1_REGISTER_OFFSET);
+ ret |= RADEON_SCANOUTPOS_VALID;
+ }
+ if (crtc == 2) {
+ vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+ EVERGREEN_CRTC2_REGISTER_OFFSET);
+ position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+ EVERGREEN_CRTC2_REGISTER_OFFSET);
+ ret |= RADEON_SCANOUTPOS_VALID;
+ }
+ if (crtc == 3) {
+ vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+ EVERGREEN_CRTC3_REGISTER_OFFSET);
+ position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+ EVERGREEN_CRTC3_REGISTER_OFFSET);
+ ret |= RADEON_SCANOUTPOS_VALID;
+ }
+ if (crtc == 4) {
+ vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+ EVERGREEN_CRTC4_REGISTER_OFFSET);
+ position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+ EVERGREEN_CRTC4_REGISTER_OFFSET);
+ ret |= RADEON_SCANOUTPOS_VALID;
+ }
+ if (crtc == 5) {
+ vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+ EVERGREEN_CRTC5_REGISTER_OFFSET);
+ position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+ EVERGREEN_CRTC5_REGISTER_OFFSET);
+ ret |= RADEON_SCANOUTPOS_VALID;
+ }
+ } else if (ASIC_IS_AVIVO(rdev)) {
+ if (crtc == 0) {
+ vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END);
+ position = RREG32(AVIVO_D1CRTC_STATUS_POSITION);
+ ret |= RADEON_SCANOUTPOS_VALID;
+ }
+ if (crtc == 1) {
+ vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END);
+ position = RREG32(AVIVO_D2CRTC_STATUS_POSITION);
+ ret |= RADEON_SCANOUTPOS_VALID;
+ }
+ } else {
+ /* Pre-AVIVO: Different encoding of scanout pos and vblank interval. */
+ if (crtc == 0) {
+ /* Assume vbl_end == 0, get vbl_start from
+ * upper 16 bits.
+ */
+ vbl = (RREG32(RADEON_CRTC_V_TOTAL_DISP) &
+ RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT;
+ /* Only retrieve vpos from upper 16 bits, set hpos == 0. */
+ position = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
+ stat_crtc = RREG32(RADEON_CRTC_STATUS);
+ if (!(stat_crtc & 1))
+ in_vbl = false;
+
+ ret |= RADEON_SCANOUTPOS_VALID;
+ }
+ if (crtc == 1) {
+ vbl = (RREG32(RADEON_CRTC2_V_TOTAL_DISP) &
+ RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT;
+ position = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
+ stat_crtc = RREG32(RADEON_CRTC2_STATUS);
+ if (!(stat_crtc & 1))
+ in_vbl = false;
+
+ ret |= RADEON_SCANOUTPOS_VALID;
+ }
+ }
+
+ /* Decode into vertical and horizontal scanout position. */
+ *vpos = position & 0x1fff;
+ *hpos = (position >> 16) & 0x1fff;
+
+ /* Valid vblank area boundaries from gpu retrieved? */
+ if (vbl > 0) {
+ /* Yes: Decode. */
+ ret |= RADEON_SCANOUTPOS_ACCURATE;
+ vbl_start = vbl & 0x1fff;
+ vbl_end = (vbl >> 16) & 0x1fff;
+ }
+ else {
+ /* No: Fake something reasonable which gives at least ok results. */
+ vbl_start = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vdisplay;
+ vbl_end = 0;
+ }
+
+ /* Test scanout position against vblank region. */
+ if ((*vpos < vbl_start) && (*vpos >= vbl_end))
+ in_vbl = false;
+
+ /* Check if inside vblank area and apply corrective offsets:
+ * vpos will then be >=0 in video scanout area, but negative
+ * within vblank area, counting down the number of lines until
+ * start of scanout.
+ */
+
+ /* Inside "upper part" of vblank area? Apply corrective offset if so: */
+ if (in_vbl && (*vpos >= vbl_start)) {
+ vtotal = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vtotal;
+ *vpos = *vpos - vtotal;
+ }
+
+ /* Correct for shifted end of vbl at vbl_end. */
+ *vpos = *vpos - vbl_end;
+
+ /* In vblank? */
+ if (in_vbl)
+ ret |= RADEON_SCANOUTPOS_INVBL;
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 29c1237c2e7b..88e4ea925900 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -47,9 +47,10 @@
* - 2.4.0 - add crtc id query
* - 2.5.0 - add get accel 2 to work around ddx breakage for evergreen
* - 2.6.0 - add tiling config query (r6xx+), add initial HiZ support (r300->r500)
+ * 2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs
*/
#define KMS_DRIVER_MAJOR 2
-#define KMS_DRIVER_MINOR 6
+#define KMS_DRIVER_MINOR 7
#define KMS_DRIVER_PATCHLEVEL 0
int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
int radeon_driver_unload_kms(struct drm_device *dev);
@@ -93,7 +94,6 @@ int radeon_benchmarking = 0;
int radeon_testing = 0;
int radeon_connector_table = 0;
int radeon_tv = 1;
-int radeon_new_pll = -1;
int radeon_audio = 1;
int radeon_disp_priority = 0;
int radeon_hw_i2c = 0;
@@ -131,9 +131,6 @@ module_param_named(connector_table, radeon_connector_table, int, 0444);
MODULE_PARM_DESC(tv, "TV enable (0 = disable)");
module_param_named(tv, radeon_tv, int, 0444);
-MODULE_PARM_DESC(new_pll, "Select new PLL code");
-module_param_named(new_pll, radeon_new_pll, int, 0444);
-
MODULE_PARM_DESC(audio, "Audio enable (0 = disable)");
module_param_named(audio, radeon_audio, int, 0444);
@@ -203,8 +200,6 @@ static struct drm_driver driver_old = {
.irq_uninstall = radeon_driver_irq_uninstall,
.irq_handler = radeon_driver_irq_handler,
.reclaim_buffers = drm_core_reclaim_buffers,
- .get_map_ofs = drm_core_get_map_ofs,
- .get_reg_ofs = drm_core_get_reg_ofs,
.ioctls = radeon_ioctls,
.dma_ioctl = radeon_cp_buffers,
.fops = {
@@ -291,8 +286,6 @@ static struct drm_driver kms_driver = {
.irq_uninstall = radeon_driver_irq_uninstall_kms,
.irq_handler = radeon_driver_irq_handler_kms,
.reclaim_buffers = drm_core_reclaim_buffers,
- .get_map_ofs = drm_core_get_map_ofs,
- .get_reg_ofs = drm_core_get_reg_ofs,
.ioctls = radeon_ioctls_kms,
.gem_init_object = radeon_gem_object_init,
.gem_free_object = radeon_gem_object_free,
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index 2c293e8304d6..ae58b6849a2e 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -529,9 +529,9 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
- if (dig->lvds_misc & ATOM_PANEL_MISC_DUAL)
+ if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL)
args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
- if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB)
+ if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
args.v1.ucMisc |= (1 << 1);
} else {
if (dig->linkb)
@@ -558,18 +558,18 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
args.v2.ucTemporal = 0;
args.v2.ucFRC = 0;
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
- if (dig->lvds_misc & ATOM_PANEL_MISC_DUAL)
+ if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL)
args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
- if (dig->lvds_misc & ATOM_PANEL_MISC_SPATIAL) {
+ if (dig->lcd_misc & ATOM_PANEL_MISC_SPATIAL) {
args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN;
- if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB)
+ if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH;
}
- if (dig->lvds_misc & ATOM_PANEL_MISC_TEMPORAL) {
+ if (dig->lcd_misc & ATOM_PANEL_MISC_TEMPORAL) {
args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN;
- if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB)
+ if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH;
- if (((dig->lvds_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2)
+ if (((dig->lcd_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2)
args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4;
}
} else {
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index 40b0c087b592..efa211898fe6 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -59,6 +59,8 @@ static struct fb_ops radeonfb_ops = {
.fb_pan_display = drm_fb_helper_pan_display,
.fb_blank = drm_fb_helper_blank,
.fb_setcmap = drm_fb_helper_setcmap,
+ .fb_debug_enter = drm_fb_helper_debug_enter,
+ .fb_debug_leave = drm_fb_helper_debug_leave,
};
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index b1f9a81b5d1d..216392d0353b 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -72,7 +72,15 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev)
bool wake = false;
unsigned long cjiffies;
- seq = RREG32(rdev->fence_drv.scratch_reg);
+ if (rdev->wb.enabled) {
+ u32 scratch_index;
+ if (rdev->wb.use_event)
+ 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;
+ seq = rdev->wb.wb[scratch_index/4];
+ } else
+ seq = RREG32(rdev->fence_drv.scratch_reg);
if (seq != rdev->fence_drv.last_seq) {
rdev->fence_drv.last_seq = seq;
rdev->fence_drv.last_jiffies = jiffies;
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index 305049afde15..ace2e6384d40 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -348,10 +348,25 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
+ return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0);
+}
+
+int radeon_crtc_set_base_atomic(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y, enum mode_set_atomic state)
+{
+ return radeon_crtc_do_set_base(crtc, fb, x, y, 1);
+}
+
+int radeon_crtc_do_set_base(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y, int atomic)
+{
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct radeon_framebuffer *radeon_fb;
+ struct drm_framebuffer *target_fb;
struct drm_gem_object *obj;
struct radeon_bo *rbo;
uint64_t base;
@@ -364,14 +379,21 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
DRM_DEBUG_KMS("\n");
/* no fb bound */
- if (!crtc->fb) {
+ if (!atomic && !crtc->fb) {
DRM_DEBUG_KMS("No FB bound\n");
return 0;
}
- radeon_fb = to_radeon_framebuffer(crtc->fb);
+ if (atomic) {
+ radeon_fb = to_radeon_framebuffer(fb);
+ target_fb = fb;
+ }
+ else {
+ radeon_fb = to_radeon_framebuffer(crtc->fb);
+ target_fb = crtc->fb;
+ }
- switch (crtc->fb->bits_per_pixel) {
+ switch (target_fb->bits_per_pixel) {
case 8:
format = 2;
break;
@@ -415,10 +437,10 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
crtc_offset_cntl = 0;
- pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
- crtc_pitch = (((pitch_pixels * crtc->fb->bits_per_pixel) +
- ((crtc->fb->bits_per_pixel * 8) - 1)) /
- (crtc->fb->bits_per_pixel * 8));
+ pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8);
+ crtc_pitch = (((pitch_pixels * target_fb->bits_per_pixel) +
+ ((target_fb->bits_per_pixel * 8) - 1)) /
+ (target_fb->bits_per_pixel * 8));
crtc_pitch |= crtc_pitch << 16;
@@ -443,14 +465,14 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
crtc_tile_x0_y0 = x | (y << 16);
base &= ~0x7ff;
} else {
- int byteshift = crtc->fb->bits_per_pixel >> 4;
+ int byteshift = target_fb->bits_per_pixel >> 4;
int tile_addr = (((y >> 3) * pitch_pixels + x) >> (8 - byteshift)) << 11;
base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8);
crtc_offset_cntl |= (y % 16);
}
} else {
int offset = y * pitch_pixels + x;
- switch (crtc->fb->bits_per_pixel) {
+ switch (target_fb->bits_per_pixel) {
case 8:
offset *= 1;
break;
@@ -496,8 +518,8 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset);
WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
- if (old_fb && old_fb != crtc->fb) {
- radeon_fb = to_radeon_framebuffer(old_fb);
+ if (!atomic && fb && fb != crtc->fb) {
+ radeon_fb = to_radeon_framebuffer(fb);
rbo = radeon_fb->obj->driver_private;
r = radeon_bo_reserve(rbo, false);
if (unlikely(r != 0))
@@ -717,10 +739,6 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
pll = &rdev->clock.p1pll;
pll->flags = RADEON_PLL_LEGACY;
- if (radeon_new_pll == 1)
- pll->algo = PLL_ALGO_NEW;
- else
- pll->algo = PLL_ALGO_LEGACY;
if (mode->clock > 200000) /* range limits??? */
pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
@@ -1040,6 +1058,7 @@ static const struct drm_crtc_helper_funcs legacy_helper_funcs = {
.mode_fixup = radeon_crtc_mode_fixup,
.mode_set = radeon_crtc_mode_set,
.mode_set_base = radeon_crtc_set_base,
+ .mode_set_base_atomic = radeon_crtc_set_base_atomic,
.prepare = radeon_crtc_prepare,
.commit = radeon_crtc_commit,
.load_lut = radeon_crtc_load_lut,
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 17a6602b5885..92457163d070 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -35,8 +35,8 @@
#include <drm_edid.h>
#include <drm_dp_helper.h>
#include <drm_fixed.h>
+#include <drm_crtc_helper.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
struct radeon_bo;
@@ -150,12 +150,6 @@ struct radeon_tmds_pll {
#define RADEON_PLL_USE_POST_DIV (1 << 12)
#define RADEON_PLL_IS_LCD (1 << 13)
-/* pll algo */
-enum radeon_pll_algo {
- PLL_ALGO_LEGACY,
- PLL_ALGO_NEW
-};
-
struct radeon_pll {
/* reference frequency */
uint32_t reference_freq;
@@ -188,8 +182,6 @@ struct radeon_pll {
/* pll id */
uint32_t id;
- /* pll algo */
- enum radeon_pll_algo algo;
};
struct radeon_i2c_chan {
@@ -241,6 +233,8 @@ struct radeon_mode_info {
struct drm_property *tmds_pll_property;
/* underscan */
struct drm_property *underscan_property;
+ struct drm_property *underscan_hborder_property;
+ struct drm_property *underscan_vborder_property;
/* hardcoded DFP edid from BIOS */
struct edid *bios_hardcoded_edid;
@@ -336,22 +330,24 @@ struct radeon_encoder_ext_tmds {
struct radeon_atom_ss {
uint16_t percentage;
uint8_t type;
- uint8_t step;
+ uint16_t step;
uint8_t delay;
uint8_t range;
uint8_t refdiv;
+ /* asic_ss */
+ uint16_t rate;
+ uint16_t amount;
};
struct radeon_encoder_atom_dig {
bool linkb;
/* atom dig */
bool coherent_mode;
- int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB */
- /* atom lvds */
- uint32_t lvds_misc;
+ int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB, etc. */
+ /* atom lvds/edp */
+ uint32_t lcd_misc;
uint16_t panel_pwr_delay;
- enum radeon_pll_algo pll_algo;
- struct radeon_atom_ss *ss;
+ uint32_t lcd_ss_id;
/* panel mode */
struct drm_display_mode native_mode;
};
@@ -370,6 +366,8 @@ struct radeon_encoder {
uint32_t pixel_clock;
enum radeon_rmx_type rmx_type;
enum radeon_underscan_type underscan_type;
+ uint32_t underscan_hborder;
+ uint32_t underscan_vborder;
struct drm_display_mode native_mode;
void *enc_priv;
int audio_polling_active;
@@ -436,6 +434,11 @@ struct radeon_framebuffer {
struct drm_gem_object *obj;
};
+/* radeon_get_crtc_scanoutpos() return flags */
+#define RADEON_SCANOUTPOS_VALID (1 << 0)
+#define RADEON_SCANOUTPOS_INVBL (1 << 1)
+#define RADEON_SCANOUTPOS_ACCURATE (1 << 2)
+
extern enum radeon_tv_std
radeon_combios_get_tv_info(struct radeon_device *rdev);
extern enum radeon_tv_std
@@ -491,6 +494,13 @@ extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector);
+extern bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
+ struct radeon_atom_ss *ss,
+ int id);
+extern bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
+ struct radeon_atom_ss *ss,
+ int id, u32 clock);
+
extern void radeon_compute_pll(struct radeon_pll *pll,
uint64_t freq,
uint32_t *dot_clock_p,
@@ -514,6 +524,10 @@ extern void radeon_encoder_set_active_device(struct drm_encoder *encoder);
extern void radeon_crtc_load_lut(struct drm_crtc *crtc);
extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb);
+extern int atombios_crtc_set_base_atomic(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y,
+ enum mode_set_atomic state);
extern int atombios_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
@@ -523,7 +537,13 @@ extern void atombios_crtc_dpms(struct drm_crtc *crtc, int mode);
extern int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb);
-
+extern int radeon_crtc_set_base_atomic(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y,
+ enum mode_set_atomic state);
+extern int radeon_crtc_do_set_base(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y, int atomic);
extern int radeon_crtc_cursor_set(struct drm_crtc *crtc,
struct drm_file *file_priv,
uint32_t handle,
@@ -532,6 +552,8 @@ extern int radeon_crtc_cursor_set(struct drm_crtc *crtc,
extern int radeon_crtc_cursor_move(struct drm_crtc *crtc,
int x, int y);
+extern int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos);
+
extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev);
extern struct edid *
radeon_combios_get_hardcoded_edid(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index b3b5306bb578..d7ab91416410 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -435,7 +435,7 @@ int radeon_bo_get_surface_reg(struct radeon_bo *bo)
out:
radeon_set_surface_reg(rdev, i, bo->tiling_flags, bo->pitch,
- bo->tbo.mem.mm_node->start << PAGE_SHIFT,
+ bo->tbo.mem.start << PAGE_SHIFT,
bo->tbo.num_pages << PAGE_SHIFT);
return 0;
}
@@ -532,7 +532,7 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
rdev = rbo->rdev;
if (bo->mem.mem_type == TTM_PL_VRAM) {
size = bo->mem.num_pages << PAGE_SHIFT;
- offset = bo->mem.mm_node->start << PAGE_SHIFT;
+ offset = bo->mem.start << PAGE_SHIFT;
if ((offset + size) > rdev->mc.visible_vram_size) {
/* hurrah the memory is not visible ! */
radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM);
@@ -540,7 +540,7 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
r = ttm_bo_validate(bo, &rbo->placement, false, true, false);
if (unlikely(r != 0))
return r;
- offset = bo->mem.mm_node->start << PAGE_SHIFT;
+ offset = bo->mem.start << PAGE_SHIFT;
/* this should not happen */
if ((offset + size) > rdev->mc.visible_vram_size)
return -EINVAL;
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index f87efec76236..8c9b2ef32c68 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -712,73 +712,21 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
static bool radeon_pm_in_vbl(struct radeon_device *rdev)
{
- u32 stat_crtc = 0, vbl = 0, position = 0;
+ int crtc, vpos, hpos, vbl_status;
bool in_vbl = true;
- if (ASIC_IS_DCE4(rdev)) {
- if (rdev->pm.active_crtcs & (1 << 0)) {
- vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
- EVERGREEN_CRTC0_REGISTER_OFFSET) & 0xfff;
- position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
- EVERGREEN_CRTC0_REGISTER_OFFSET) & 0xfff;
- }
- if (rdev->pm.active_crtcs & (1 << 1)) {
- vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
- EVERGREEN_CRTC1_REGISTER_OFFSET) & 0xfff;
- position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
- EVERGREEN_CRTC1_REGISTER_OFFSET) & 0xfff;
- }
- if (rdev->pm.active_crtcs & (1 << 2)) {
- vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
- EVERGREEN_CRTC2_REGISTER_OFFSET) & 0xfff;
- position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
- EVERGREEN_CRTC2_REGISTER_OFFSET) & 0xfff;
- }
- if (rdev->pm.active_crtcs & (1 << 3)) {
- vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
- EVERGREEN_CRTC3_REGISTER_OFFSET) & 0xfff;
- position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
- EVERGREEN_CRTC3_REGISTER_OFFSET) & 0xfff;
- }
- if (rdev->pm.active_crtcs & (1 << 4)) {
- vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
- EVERGREEN_CRTC4_REGISTER_OFFSET) & 0xfff;
- position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
- EVERGREEN_CRTC4_REGISTER_OFFSET) & 0xfff;
- }
- if (rdev->pm.active_crtcs & (1 << 5)) {
- vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
- EVERGREEN_CRTC5_REGISTER_OFFSET) & 0xfff;
- position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
- EVERGREEN_CRTC5_REGISTER_OFFSET) & 0xfff;
- }
- } else if (ASIC_IS_AVIVO(rdev)) {
- if (rdev->pm.active_crtcs & (1 << 0)) {
- vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END) & 0xfff;
- position = RREG32(AVIVO_D1CRTC_STATUS_POSITION) & 0xfff;
- }
- if (rdev->pm.active_crtcs & (1 << 1)) {
- vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END) & 0xfff;
- position = RREG32(AVIVO_D2CRTC_STATUS_POSITION) & 0xfff;
- }
- if (position < vbl && position > 1)
- in_vbl = false;
- } else {
- if (rdev->pm.active_crtcs & (1 << 0)) {
- stat_crtc = RREG32(RADEON_CRTC_STATUS);
- if (!(stat_crtc & 1))
- in_vbl = false;
- }
- if (rdev->pm.active_crtcs & (1 << 1)) {
- stat_crtc = RREG32(RADEON_CRTC2_STATUS);
- if (!(stat_crtc & 1))
+ /* Iterate over all active crtc's. All crtc's must be in vblank,
+ * otherwise return in_vbl == false.
+ */
+ for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) {
+ if (rdev->pm.active_crtcs & (1 << crtc)) {
+ vbl_status = radeon_get_crtc_scanoutpos(rdev, crtc, &vpos, &hpos);
+ if ((vbl_status & RADEON_SCANOUTPOS_VALID) &&
+ !(vbl_status & RADEON_SCANOUTPOS_INVBL))
in_vbl = false;
}
}
- if (position < vbl && position > 1)
- in_vbl = false;
-
return in_vbl;
}
diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h
index c332f46340d5..64928814de53 100644
--- a/drivers/gpu/drm/radeon/radeon_reg.h
+++ b/drivers/gpu/drm/radeon/radeon_reg.h
@@ -2836,6 +2836,7 @@
# define R200_TXFORMAT_ST_ROUTE_STQ5 (5 << 24)
# define R200_TXFORMAT_ST_ROUTE_MASK (7 << 24)
# define R200_TXFORMAT_ST_ROUTE_SHIFT 24
+# define R200_TXFORMAT_LOOKUP_DISABLE (1 << 27)
# define R200_TXFORMAT_ALPHA_MASK_ENABLE (1 << 28)
# define R200_TXFORMAT_CHROMA_KEY_ENABLE (1 << 29)
# define R200_TXFORMAT_CUBIC_MAP_ENABLE (1 << 30)
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index 261e98a276db..6ea798ce8218 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -247,10 +247,14 @@ void radeon_ib_pool_fini(struct radeon_device *rdev)
*/
void radeon_ring_free_size(struct radeon_device *rdev)
{
- if (rdev->family >= CHIP_R600)
- rdev->cp.rptr = RREG32(R600_CP_RB_RPTR);
- else
- rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
+ if (rdev->wb.enabled)
+ rdev->cp.rptr = rdev->wb.wb[RADEON_WB_CP_RPTR_OFFSET/4];
+ else {
+ if (rdev->family >= CHIP_R600)
+ rdev->cp.rptr = RREG32(R600_CP_RB_RPTR);
+ else
+ rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
+ }
/* This works because ring_size is a power of 2 */
rdev->cp.ring_free_dw = (rdev->cp.rptr + (rdev->cp.ring_size / 4));
rdev->cp.ring_free_dw -= rdev->cp.wptr;
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 84c53e41a88f..fe95bb35317e 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -152,6 +152,7 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
man->default_caching = TTM_PL_FLAG_CACHED;
break;
case TTM_PL_TT:
+ man->func = &ttm_bo_manager_func;
man->gpu_offset = rdev->mc.gtt_start;
man->available_caching = TTM_PL_MASK_CACHING;
man->default_caching = TTM_PL_FLAG_CACHED;
@@ -173,6 +174,7 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
break;
case TTM_PL_VRAM:
/* "On-card" video ram */
+ man->func = &ttm_bo_manager_func;
man->gpu_offset = rdev->mc.vram_start;
man->flags = TTM_MEMTYPE_FLAG_FIXED |
TTM_MEMTYPE_FLAG_MAPPABLE;
@@ -246,8 +248,8 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
if (unlikely(r)) {
return r;
}
- old_start = old_mem->mm_node->start << PAGE_SHIFT;
- new_start = new_mem->mm_node->start << PAGE_SHIFT;
+ old_start = old_mem->start << PAGE_SHIFT;
+ new_start = new_mem->start << PAGE_SHIFT;
switch (old_mem->mem_type) {
case TTM_PL_VRAM:
@@ -326,14 +328,7 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo,
}
r = ttm_bo_move_ttm(bo, true, no_wait_reserve, no_wait_gpu, new_mem);
out_cleanup:
- if (tmp_mem.mm_node) {
- struct ttm_bo_global *glob = rdev->mman.bdev.glob;
-
- spin_lock(&glob->lru_lock);
- drm_mm_put_block(tmp_mem.mm_node);
- spin_unlock(&glob->lru_lock);
- return r;
- }
+ ttm_bo_mem_put(bo, &tmp_mem);
return r;
}
@@ -372,14 +367,7 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo,
goto out_cleanup;
}
out_cleanup:
- if (tmp_mem.mm_node) {
- struct ttm_bo_global *glob = rdev->mman.bdev.glob;
-
- spin_lock(&glob->lru_lock);
- drm_mm_put_block(tmp_mem.mm_node);
- spin_unlock(&glob->lru_lock);
- return r;
- }
+ ttm_bo_mem_put(bo, &tmp_mem);
return r;
}
@@ -449,14 +437,14 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_
#if __OS_HAS_AGP
if (rdev->flags & RADEON_IS_AGP) {
/* RADEON_IS_AGP is set only if AGP is active */
- mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
+ mem->bus.offset = mem->start << PAGE_SHIFT;
mem->bus.base = rdev->mc.agp_base;
mem->bus.is_iomem = !rdev->ddev->agp->cant_use_aperture;
}
#endif
break;
case TTM_PL_VRAM:
- mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
+ mem->bus.offset = mem->start << PAGE_SHIFT;
/* check if it's visible */
if ((mem->bus.offset + mem->bus.size) > rdev->mc.visible_vram_size)
return -EINVAL;
@@ -631,7 +619,7 @@ int radeon_mmap(struct file *filp, struct vm_area_struct *vma)
return drm_mmap(filp, vma);
}
- file_priv = (struct drm_file *)filp->private_data;
+ file_priv = filp->private_data;
rdev = file_priv->minor->dev->dev_private;
if (rdev == NULL) {
return -EINVAL;
@@ -699,7 +687,7 @@ static int radeon_ttm_backend_bind(struct ttm_backend *backend,
int r;
gtt = container_of(backend, struct radeon_ttm_backend, backend);
- gtt->offset = bo_mem->mm_node->start << PAGE_SHIFT;
+ gtt->offset = bo_mem->start << PAGE_SHIFT;
if (!gtt->num_pages) {
WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", gtt->num_pages, bo_mem, backend);
}
@@ -798,9 +786,9 @@ static int radeon_ttm_debugfs_init(struct radeon_device *rdev)
radeon_mem_types_list[i].show = &radeon_mm_dump_table;
radeon_mem_types_list[i].driver_features = 0;
if (i == 0)
- radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_VRAM].manager;
+ radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_VRAM].priv;
else
- radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_TT].manager;
+ radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_TT].priv;
}
/* Add ttm page pool to debugfs */
diff --git a/drivers/gpu/drm/radeon/reg_srcs/evergreen b/drivers/gpu/drm/radeon/reg_srcs/evergreen
index f78fd592544d..ac40fd39d787 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/evergreen
+++ b/drivers/gpu/drm/radeon/reg_srcs/evergreen
@@ -22,6 +22,10 @@ evergreen 0x9400
0x00008B10 PA_SC_LINE_STIPPLE_STATE
0x00008BF0 PA_SC_ENHANCE
0x00008D8C SQ_DYN_GPR_CNTL_PS_FLUSH_REQ
+0x00008D90 SQ_DYN_GPR_OPTIMIZATION
+0x00008D94 SQ_DYN_GPR_SIMD_LOCK_EN
+0x00008D98 SQ_DYN_GPR_THREAD_LIMIT
+0x00008D9C SQ_DYN_GPR_LDS_LIMIT
0x00008C00 SQ_CONFIG
0x00008C04 SQ_GPR_RESOURCE_MGMT_1
0x00008C08 SQ_GPR_RESOURCE_MGMT_2
@@ -34,6 +38,10 @@ evergreen 0x9400
0x00008C24 SQ_STACK_RESOURCE_MGMT_2
0x00008C28 SQ_STACK_RESOURCE_MGMT_3
0x00008DF8 SQ_CONST_MEM_BASE
+0x00008E20 SQ_STATIC_THREAD_MGMT_1
+0x00008E24 SQ_STATIC_THREAD_MGMT_2
+0x00008E28 SQ_STATIC_THREAD_MGMT_3
+0x00008E2C SQ_LDS_RESOURCE_MGMT
0x00008E48 SQ_EX_ALLOC_TABLE_SLOTS
0x00009100 SPI_CONFIG_CNTL
0x0000913C SPI_CONFIG_CNTL_1
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index ae2b76b9a388..f683e51a2a06 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -397,6 +397,12 @@ static int rs400_startup(struct radeon_device *rdev)
r = rs400_gart_enable(rdev);
if (r)
return r;
+
+ /* allocate wb buffer */
+ r = radeon_wb_init(rdev);
+ if (r)
+ return r;
+
/* Enable IRQ */
r100_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -406,9 +412,6 @@ static int rs400_startup(struct radeon_device *rdev)
dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
return r;
}
- r = r100_wb_init(rdev);
- if (r)
- dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
r = r100_ib_init(rdev);
if (r) {
dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -443,7 +446,7 @@ int rs400_resume(struct radeon_device *rdev)
int rs400_suspend(struct radeon_device *rdev)
{
r100_cp_disable(rdev);
- r100_wb_disable(rdev);
+ radeon_wb_disable(rdev);
r100_irq_disable(rdev);
rs400_gart_disable(rdev);
return 0;
@@ -452,7 +455,7 @@ int rs400_suspend(struct radeon_device *rdev)
void rs400_fini(struct radeon_device *rdev)
{
r100_cp_fini(rdev);
- r100_wb_fini(rdev);
+ radeon_wb_fini(rdev);
r100_ib_fini(rdev);
radeon_gem_fini(rdev);
rs400_gart_fini(rdev);
@@ -526,7 +529,7 @@ int rs400_init(struct radeon_device *rdev)
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
r100_cp_fini(rdev);
- r100_wb_fini(rdev);
+ radeon_wb_fini(rdev);
r100_ib_fini(rdev);
rs400_gart_fini(rdev);
radeon_irq_kms_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 51d5f7b5ab21..b091a1f6fa4e 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -796,6 +796,12 @@ static int rs600_startup(struct radeon_device *rdev)
r = rs600_gart_enable(rdev);
if (r)
return r;
+
+ /* allocate wb buffer */
+ r = radeon_wb_init(rdev);
+ if (r)
+ return r;
+
/* Enable IRQ */
rs600_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -805,9 +811,6 @@ static int rs600_startup(struct radeon_device *rdev)
dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
return r;
}
- r = r100_wb_init(rdev);
- if (r)
- dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
r = r100_ib_init(rdev);
if (r) {
dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -848,7 +851,7 @@ int rs600_suspend(struct radeon_device *rdev)
{
r600_audio_fini(rdev);
r100_cp_disable(rdev);
- r100_wb_disable(rdev);
+ radeon_wb_disable(rdev);
rs600_irq_disable(rdev);
rs600_gart_disable(rdev);
return 0;
@@ -858,7 +861,7 @@ void rs600_fini(struct radeon_device *rdev)
{
r600_audio_fini(rdev);
r100_cp_fini(rdev);
- r100_wb_fini(rdev);
+ radeon_wb_fini(rdev);
r100_ib_fini(rdev);
radeon_gem_fini(rdev);
rs600_gart_fini(rdev);
@@ -932,7 +935,7 @@ int rs600_init(struct radeon_device *rdev)
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
r100_cp_fini(rdev);
- r100_wb_fini(rdev);
+ radeon_wb_fini(rdev);
r100_ib_fini(rdev);
rs600_gart_fini(rdev);
radeon_irq_kms_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index 4dc2a87ea680..0137d3e3728d 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -616,6 +616,12 @@ static int rs690_startup(struct radeon_device *rdev)
r = rs400_gart_enable(rdev);
if (r)
return r;
+
+ /* allocate wb buffer */
+ r = radeon_wb_init(rdev);
+ if (r)
+ return r;
+
/* Enable IRQ */
rs600_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -625,9 +631,6 @@ static int rs690_startup(struct radeon_device *rdev)
dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
return r;
}
- r = r100_wb_init(rdev);
- if (r)
- dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
r = r100_ib_init(rdev);
if (r) {
dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -668,7 +671,7 @@ int rs690_suspend(struct radeon_device *rdev)
{
r600_audio_fini(rdev);
r100_cp_disable(rdev);
- r100_wb_disable(rdev);
+ radeon_wb_disable(rdev);
rs600_irq_disable(rdev);
rs400_gart_disable(rdev);
return 0;
@@ -678,7 +681,7 @@ void rs690_fini(struct radeon_device *rdev)
{
r600_audio_fini(rdev);
r100_cp_fini(rdev);
- r100_wb_fini(rdev);
+ radeon_wb_fini(rdev);
r100_ib_fini(rdev);
radeon_gem_fini(rdev);
rs400_gart_fini(rdev);
@@ -753,7 +756,7 @@ int rs690_init(struct radeon_device *rdev)
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
r100_cp_fini(rdev);
- r100_wb_fini(rdev);
+ radeon_wb_fini(rdev);
r100_ib_fini(rdev);
rs400_gart_fini(rdev);
radeon_irq_kms_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index 4d6e86041a9f..5d569f41f4ae 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -386,6 +386,12 @@ static int rv515_startup(struct radeon_device *rdev)
if (r)
return r;
}
+
+ /* allocate wb buffer */
+ r = radeon_wb_init(rdev);
+ if (r)
+ return r;
+
/* Enable IRQ */
rs600_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -395,9 +401,6 @@ static int rv515_startup(struct radeon_device *rdev)
dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
return r;
}
- r = r100_wb_init(rdev);
- if (r)
- dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
r = r100_ib_init(rdev);
if (r) {
dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -431,7 +434,7 @@ int rv515_resume(struct radeon_device *rdev)
int rv515_suspend(struct radeon_device *rdev)
{
r100_cp_disable(rdev);
- r100_wb_disable(rdev);
+ radeon_wb_disable(rdev);
rs600_irq_disable(rdev);
if (rdev->flags & RADEON_IS_PCIE)
rv370_pcie_gart_disable(rdev);
@@ -447,7 +450,7 @@ void rv515_set_safe_registers(struct radeon_device *rdev)
void rv515_fini(struct radeon_device *rdev)
{
r100_cp_fini(rdev);
- r100_wb_fini(rdev);
+ radeon_wb_fini(rdev);
r100_ib_fini(rdev);
radeon_gem_fini(rdev);
rv370_pcie_gart_fini(rdev);
@@ -527,7 +530,7 @@ int rv515_init(struct radeon_device *rdev)
/* Somethings want wront with the accel init stop accel */
dev_err(rdev->dev, "Disabling GPU acceleration\n");
r100_cp_fini(rdev);
- r100_wb_fini(rdev);
+ radeon_wb_fini(rdev);
r100_ib_fini(rdev);
radeon_irq_kms_fini(rdev);
rv370_pcie_gart_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 9490da700749..245374e2b778 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -269,6 +269,7 @@ void r700_cp_stop(struct radeon_device *rdev)
{
rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT));
+ WREG32(SCRATCH_UMSK, 0);
}
static int rv770_cp_load_microcode(struct radeon_device *rdev)
@@ -643,10 +644,11 @@ static void rv770_gpu_init(struct radeon_device *rdev)
else
gb_tiling_config |= BANK_TILING((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT);
rdev->config.rv770.tiling_nbanks = 4 << ((gb_tiling_config >> 4) & 0x3);
-
- gb_tiling_config |= GROUP_SIZE(0);
- rdev->config.rv770.tiling_group_size = 256;
-
+ gb_tiling_config |= GROUP_SIZE((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT);
+ if ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT)
+ rdev->config.rv770.tiling_group_size = 512;
+ else
+ rdev->config.rv770.tiling_group_size = 256;
if (((mc_arb_ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT) > 3) {
gb_tiling_config |= ROW_TILING(3);
gb_tiling_config |= SAMPLE_SPLIT(3);
@@ -1030,19 +1032,12 @@ static int rv770_startup(struct radeon_device *rdev)
rdev->asic->copy = NULL;
dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
}
- /* pin copy shader into vram */
- if (rdev->r600_blit.shader_obj) {
- r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
- if (unlikely(r != 0))
- return r;
- r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
- &rdev->r600_blit.shader_gpu_addr);
- radeon_bo_unreserve(rdev->r600_blit.shader_obj);
- if (r) {
- DRM_ERROR("failed to pin blit object %d\n", r);
- return r;
- }
- }
+
+ /* allocate wb buffer */
+ r = radeon_wb_init(rdev);
+ if (r)
+ return r;
+
/* Enable IRQ */
r = r600_irq_init(rdev);
if (r) {
@@ -1061,8 +1056,7 @@ static int rv770_startup(struct radeon_device *rdev)
r = r600_cp_resume(rdev);
if (r)
return r;
- /* write back buffer are not vital so don't worry about failure */
- r600_wb_enable(rdev);
+
return 0;
}
@@ -1108,7 +1102,7 @@ int rv770_suspend(struct radeon_device *rdev)
r700_cp_stop(rdev);
rdev->cp.ready = false;
r600_irq_suspend(rdev);
- r600_wb_disable(rdev);
+ radeon_wb_disable(rdev);
rv770_pcie_gart_disable(rdev);
/* unpin shaders bo */
if (rdev->r600_blit.shader_obj) {
@@ -1203,8 +1197,8 @@ int rv770_init(struct radeon_device *rdev)
if (r) {
dev_err(rdev->dev, "disabling GPU acceleration\n");
r700_cp_fini(rdev);
- r600_wb_fini(rdev);
r600_irq_fini(rdev);
+ radeon_wb_fini(rdev);
radeon_irq_kms_fini(rdev);
rv770_pcie_gart_fini(rdev);
rdev->accel_working = false;
@@ -1236,8 +1230,8 @@ void rv770_fini(struct radeon_device *rdev)
{
r600_blit_fini(rdev);
r700_cp_fini(rdev);
- r600_wb_fini(rdev);
r600_irq_fini(rdev);
+ radeon_wb_fini(rdev);
radeon_irq_kms_fini(rdev);
rv770_pcie_gart_fini(rdev);
rv770_vram_scratch_fini(rdev);
diff --git a/drivers/gpu/drm/savage/savage_drv.c b/drivers/gpu/drm/savage/savage_drv.c
index 2a2830f5a840..fa64d25d4248 100644
--- a/drivers/gpu/drm/savage/savage_drv.c
+++ b/drivers/gpu/drm/savage/savage_drv.c
@@ -42,8 +42,6 @@ static struct drm_driver driver = {
.lastclose = savage_driver_lastclose,
.unload = savage_driver_unload,
.reclaim_buffers = savage_reclaim_buffers,
- .get_map_ofs = drm_core_get_map_ofs,
- .get_reg_ofs = drm_core_get_reg_ofs,
.ioctls = savage_ioctls,
.dma_ioctl = savage_bci_buffers,
.fops = {
diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c
index 4bb10ef6676a..4caf5d01cfd3 100644
--- a/drivers/gpu/drm/sis/sis_drv.c
+++ b/drivers/gpu/drm/sis/sis_drv.c
@@ -67,13 +67,10 @@ static struct drm_driver driver = {
.driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR,
.load = sis_driver_load,
.unload = sis_driver_unload,
- .context_dtor = NULL,
.dma_quiescent = sis_idle,
.reclaim_buffers = NULL,
.reclaim_buffers_idlelocked = sis_reclaim_buffers_locked,
.lastclose = sis_lastclose,
- .get_map_ofs = drm_core_get_map_ofs,
- .get_reg_ofs = drm_core_get_reg_ofs,
.ioctls = sis_ioctls,
.fops = {
.owner = THIS_MODULE,
diff --git a/drivers/gpu/drm/tdfx/tdfx_drv.c b/drivers/gpu/drm/tdfx/tdfx_drv.c
index 640567ef713d..b70fa91d761a 100644
--- a/drivers/gpu/drm/tdfx/tdfx_drv.c
+++ b/drivers/gpu/drm/tdfx/tdfx_drv.c
@@ -42,8 +42,6 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = {
.driver_features = DRIVER_USE_MTRR,
.reclaim_buffers = drm_core_reclaim_buffers,
- .get_map_ofs = drm_core_get_map_ofs,
- .get_reg_ofs = drm_core_get_reg_ofs,
.fops = {
.owner = THIS_MODULE,
.open = drm_open,
diff --git a/drivers/gpu/drm/ttm/Makefile b/drivers/gpu/drm/ttm/Makefile
index b256d4adfafe..f3cf6f02c997 100644
--- a/drivers/gpu/drm/ttm/Makefile
+++ b/drivers/gpu/drm/ttm/Makefile
@@ -4,6 +4,7 @@
ccflags-y := -Iinclude/drm
ttm-y := ttm_agp_backend.o ttm_memory.o ttm_tt.o ttm_bo.o \
ttm_bo_util.o ttm_bo_vm.o ttm_module.o \
- ttm_object.o ttm_lock.o ttm_execbuf_util.o ttm_page_alloc.o
+ ttm_object.o ttm_lock.o ttm_execbuf_util.o ttm_page_alloc.o \
+ ttm_bo_manager.o
obj-$(CONFIG_DRM_TTM) += ttm.o
diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c
index 4bf69c404491..f999e36f30b4 100644
--- a/drivers/gpu/drm/ttm/ttm_agp_backend.c
+++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c
@@ -74,6 +74,7 @@ static int ttm_agp_bind(struct ttm_backend *backend, struct ttm_mem_reg *bo_mem)
{
struct ttm_agp_backend *agp_be =
container_of(backend, struct ttm_agp_backend, backend);
+ struct drm_mm_node *node = bo_mem->mm_node;
struct agp_memory *mem = agp_be->mem;
int cached = (bo_mem->placement & TTM_PL_FLAG_CACHED);
int ret;
@@ -81,7 +82,7 @@ static int ttm_agp_bind(struct ttm_backend *backend, struct ttm_mem_reg *bo_mem)
mem->is_flushed = 1;
mem->type = (cached) ? AGP_USER_CACHED_MEMORY : AGP_USER_MEMORY;
- ret = agp_bind_memory(mem, bo_mem->mm_node->start);
+ ret = agp_bind_memory(mem, node->start);
if (ret)
printk(KERN_ERR TTM_PFX "AGP Bind memory failed.\n");
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index db809e034cc4..a1cb783c7131 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -84,11 +84,8 @@ static void ttm_mem_type_debug(struct ttm_bo_device *bdev, int mem_type)
man->available_caching);
printk(KERN_ERR TTM_PFX " default_caching: 0x%08X\n",
man->default_caching);
- if (mem_type != TTM_PL_SYSTEM) {
- spin_lock(&bdev->glob->lru_lock);
- drm_mm_debug_table(&man->manager, TTM_PFX);
- spin_unlock(&bdev->glob->lru_lock);
- }
+ if (mem_type != TTM_PL_SYSTEM)
+ (*man->func->debug)(man, TTM_PFX);
}
static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo,
@@ -169,18 +166,13 @@ static void ttm_bo_release_list(struct kref *list_kref)
int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo, bool interruptible)
{
-
if (interruptible) {
- int ret = 0;
-
- ret = wait_event_interruptible(bo->event_queue,
+ return wait_event_interruptible(bo->event_queue,
atomic_read(&bo->reserved) == 0);
- if (unlikely(ret != 0))
- return ret;
} else {
wait_event(bo->event_queue, atomic_read(&bo->reserved) == 0);
+ return 0;
}
- return 0;
}
EXPORT_SYMBOL(ttm_bo_wait_unreserved);
@@ -421,7 +413,7 @@ moved:
if (bo->mem.mm_node) {
spin_lock(&bo->lock);
- bo->offset = (bo->mem.mm_node->start << PAGE_SHIFT) +
+ bo->offset = (bo->mem.start << PAGE_SHIFT) +
bdev->man[bo->mem.mem_type].gpu_offset;
bo->cur_placement = bo->mem.placement;
spin_unlock(&bo->lock);
@@ -442,135 +434,144 @@ out_err:
}
/**
- * Call bo::reserved and with the lru lock held.
+ * Call bo::reserved.
* Will release GPU memory type usage on destruction.
- * This is the place to put in driver specific hooks.
- * Will release the bo::reserved lock and the
- * lru lock on exit.
+ * This is the place to put in driver specific hooks to release
+ * driver private resources.
+ * Will release the bo::reserved lock.
*/
static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
{
- struct ttm_bo_global *glob = bo->glob;
-
if (bo->ttm) {
-
- /**
- * Release the lru_lock, since we don't want to have
- * an atomic requirement on ttm_tt[unbind|destroy].
- */
-
- spin_unlock(&glob->lru_lock);
ttm_tt_unbind(bo->ttm);
ttm_tt_destroy(bo->ttm);
bo->ttm = NULL;
- spin_lock(&glob->lru_lock);
}
- if (bo->mem.mm_node) {
- drm_mm_put_block(bo->mem.mm_node);
- bo->mem.mm_node = NULL;
- }
+ ttm_bo_mem_put(bo, &bo->mem);
atomic_set(&bo->reserved, 0);
wake_up_all(&bo->event_queue);
- spin_unlock(&glob->lru_lock);
}
-
-/**
- * If bo idle, remove from delayed- and lru lists, and unref.
- * If not idle, and already on delayed list, do nothing.
- * If not idle, and not on delayed list, put on delayed list,
- * up the list_kref and schedule a delayed list check.
- */
-
-static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all)
+static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
{
struct ttm_bo_device *bdev = bo->bdev;
struct ttm_bo_global *glob = bo->glob;
- struct ttm_bo_driver *driver = bdev->driver;
+ struct ttm_bo_driver *driver;
+ void *sync_obj;
+ void *sync_obj_arg;
+ int put_count;
int ret;
spin_lock(&bo->lock);
-retry:
- (void) ttm_bo_wait(bo, false, false, !remove_all);
-
+ (void) ttm_bo_wait(bo, false, false, true);
if (!bo->sync_obj) {
- int put_count;
-
- spin_unlock(&bo->lock);
spin_lock(&glob->lru_lock);
- ret = ttm_bo_reserve_locked(bo, false, !remove_all, false, 0);
/**
- * Someone else has the object reserved. Bail and retry.
+ * Lock inversion between bo::reserve and bo::lock here,
+ * but that's OK, since we're only trylocking.
*/
- if (unlikely(ret == -EBUSY)) {
- spin_unlock(&glob->lru_lock);
- spin_lock(&bo->lock);
- goto requeue;
- }
-
- /**
- * We can re-check for sync object without taking
- * the bo::lock since setting the sync object requires
- * also bo::reserved. A busy object at this point may
- * be caused by another thread starting an accelerated
- * eviction.
- */
+ ret = ttm_bo_reserve_locked(bo, false, true, false, 0);
- if (unlikely(bo->sync_obj)) {
- atomic_set(&bo->reserved, 0);
- wake_up_all(&bo->event_queue);
- spin_unlock(&glob->lru_lock);
- spin_lock(&bo->lock);
- if (remove_all)
- goto retry;
- else
- goto requeue;
- }
+ if (unlikely(ret == -EBUSY))
+ goto queue;
+ spin_unlock(&bo->lock);
put_count = ttm_bo_del_from_lru(bo);
- if (!list_empty(&bo->ddestroy)) {
- list_del_init(&bo->ddestroy);
- ++put_count;
- }
-
+ spin_unlock(&glob->lru_lock);
ttm_bo_cleanup_memtype_use(bo);
while (put_count--)
kref_put(&bo->list_kref, ttm_bo_ref_bug);
- return 0;
+ return;
+ } else {
+ spin_lock(&glob->lru_lock);
}
-requeue:
+queue:
+ sync_obj = bo->sync_obj;
+ sync_obj_arg = bo->sync_obj_arg;
+ driver = bdev->driver;
+
+ kref_get(&bo->list_kref);
+ list_add_tail(&bo->ddestroy, &bdev->ddestroy);
+ spin_unlock(&glob->lru_lock);
+ spin_unlock(&bo->lock);
+
+ if (sync_obj)
+ driver->sync_obj_flush(sync_obj, sync_obj_arg);
+ schedule_delayed_work(&bdev->wq,
+ ((HZ / 100) < 1) ? 1 : HZ / 100);
+}
+
+/**
+ * function ttm_bo_cleanup_refs
+ * If bo idle, remove from delayed- and lru lists, and unref.
+ * If not idle, do nothing.
+ *
+ * @interruptible Any sleeps should occur interruptibly.
+ * @no_wait_reserve Never wait for reserve. Return -EBUSY instead.
+ * @no_wait_gpu Never wait for gpu. Return -EBUSY instead.
+ */
+
+static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo,
+ bool interruptible,
+ bool no_wait_reserve,
+ bool no_wait_gpu)
+{
+ struct ttm_bo_global *glob = bo->glob;
+ int put_count;
+ int ret = 0;
+
+retry:
+ spin_lock(&bo->lock);
+ ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu);
+ spin_unlock(&bo->lock);
+
+ if (unlikely(ret != 0))
+ return ret;
+
spin_lock(&glob->lru_lock);
- if (list_empty(&bo->ddestroy)) {
- void *sync_obj = bo->sync_obj;
- void *sync_obj_arg = bo->sync_obj_arg;
+ ret = ttm_bo_reserve_locked(bo, interruptible,
+ no_wait_reserve, false, 0);
- kref_get(&bo->list_kref);
- list_add_tail(&bo->ddestroy, &bdev->ddestroy);
+ if (unlikely(ret != 0) || list_empty(&bo->ddestroy)) {
spin_unlock(&glob->lru_lock);
- spin_unlock(&bo->lock);
+ return ret;
+ }
- if (sync_obj)
- driver->sync_obj_flush(sync_obj, sync_obj_arg);
- schedule_delayed_work(&bdev->wq,
- ((HZ / 100) < 1) ? 1 : HZ / 100);
- ret = 0;
+ /**
+ * We can re-check for sync object without taking
+ * the bo::lock since setting the sync object requires
+ * also bo::reserved. A busy object at this point may
+ * be caused by another thread recently starting an accelerated
+ * eviction.
+ */
- } else {
+ if (unlikely(bo->sync_obj)) {
+ atomic_set(&bo->reserved, 0);
+ wake_up_all(&bo->event_queue);
spin_unlock(&glob->lru_lock);
- spin_unlock(&bo->lock);
- ret = -EBUSY;
+ goto retry;
}
- return ret;
+ put_count = ttm_bo_del_from_lru(bo);
+ list_del_init(&bo->ddestroy);
+ ++put_count;
+
+ spin_unlock(&glob->lru_lock);
+ ttm_bo_cleanup_memtype_use(bo);
+
+ while (put_count--)
+ kref_put(&bo->list_kref, ttm_bo_ref_bug);
+
+ return 0;
}
/**
@@ -602,7 +603,8 @@ static int ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all)
}
spin_unlock(&glob->lru_lock);
- ret = ttm_bo_cleanup_refs(entry, remove_all);
+ ret = ttm_bo_cleanup_refs(entry, false, !remove_all,
+ !remove_all);
kref_put(&entry->list_kref, ttm_bo_release_list);
entry = nentry;
@@ -645,7 +647,7 @@ static void ttm_bo_release(struct kref *kref)
bo->vm_node = NULL;
}
write_unlock(&bdev->vm_lock);
- ttm_bo_cleanup_refs(bo, false);
+ ttm_bo_cleanup_refs_or_queue(bo);
kref_put(&bo->list_kref, ttm_bo_release_list);
write_lock(&bdev->vm_lock);
}
@@ -680,7 +682,6 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible,
bool no_wait_reserve, bool no_wait_gpu)
{
struct ttm_bo_device *bdev = bo->bdev;
- struct ttm_bo_global *glob = bo->glob;
struct ttm_mem_reg evict_mem;
struct ttm_placement placement;
int ret = 0;
@@ -726,12 +727,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible,
if (ret) {
if (ret != -ERESTARTSYS)
printk(KERN_ERR TTM_PFX "Buffer eviction failed\n");
- spin_lock(&glob->lru_lock);
- if (evict_mem.mm_node) {
- drm_mm_put_block(evict_mem.mm_node);
- evict_mem.mm_node = NULL;
- }
- spin_unlock(&glob->lru_lock);
+ ttm_bo_mem_put(bo, &evict_mem);
goto out;
}
bo->evicted = true;
@@ -759,6 +755,18 @@ retry:
bo = list_first_entry(&man->lru, struct ttm_buffer_object, lru);
kref_get(&bo->list_kref);
+ if (!list_empty(&bo->ddestroy)) {
+ spin_unlock(&glob->lru_lock);
+ ret = ttm_bo_cleanup_refs(bo, interruptible,
+ no_wait_reserve, no_wait_gpu);
+ kref_put(&bo->list_kref, ttm_bo_release_list);
+
+ if (likely(ret == 0 || ret == -ERESTARTSYS))
+ return ret;
+
+ goto retry;
+ }
+
ret = ttm_bo_reserve_locked(bo, false, no_wait_reserve, false, 0);
if (unlikely(ret == -EBUSY)) {
@@ -792,41 +800,14 @@ retry:
return ret;
}
-static int ttm_bo_man_get_node(struct ttm_buffer_object *bo,
- struct ttm_mem_type_manager *man,
- struct ttm_placement *placement,
- struct ttm_mem_reg *mem,
- struct drm_mm_node **node)
+void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem)
{
- struct ttm_bo_global *glob = bo->glob;
- unsigned long lpfn;
- int ret;
+ struct ttm_mem_type_manager *man = &bo->bdev->man[mem->mem_type];
- lpfn = placement->lpfn;
- if (!lpfn)
- lpfn = man->size;
- *node = NULL;
- do {
- ret = drm_mm_pre_get(&man->manager);
- if (unlikely(ret))
- return ret;
-
- spin_lock(&glob->lru_lock);
- *node = drm_mm_search_free_in_range(&man->manager,
- mem->num_pages, mem->page_alignment,
- placement->fpfn, lpfn, 1);
- if (unlikely(*node == NULL)) {
- spin_unlock(&glob->lru_lock);
- return 0;
- }
- *node = drm_mm_get_block_atomic_range(*node, mem->num_pages,
- mem->page_alignment,
- placement->fpfn,
- lpfn);
- spin_unlock(&glob->lru_lock);
- } while (*node == NULL);
- return 0;
+ if (mem->mm_node)
+ (*man->func->put_node)(man, mem);
}
+EXPORT_SYMBOL(ttm_bo_mem_put);
/**
* Repeatedly evict memory from the LRU for @mem_type until we create enough
@@ -843,14 +824,13 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
struct ttm_bo_device *bdev = bo->bdev;
struct ttm_bo_global *glob = bdev->glob;
struct ttm_mem_type_manager *man = &bdev->man[mem_type];
- struct drm_mm_node *node;
int ret;
do {
- ret = ttm_bo_man_get_node(bo, man, placement, mem, &node);
+ ret = (*man->func->get_node)(man, bo, placement, mem);
if (unlikely(ret != 0))
return ret;
- if (node)
+ if (mem->mm_node)
break;
spin_lock(&glob->lru_lock);
if (list_empty(&man->lru)) {
@@ -863,9 +843,8 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
if (unlikely(ret != 0))
return ret;
} while (1);
- if (node == NULL)
+ if (mem->mm_node == NULL)
return -ENOMEM;
- mem->mm_node = node;
mem->mem_type = mem_type;
return 0;
}
@@ -939,7 +918,6 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
bool type_found = false;
bool type_ok = false;
bool has_erestartsys = false;
- struct drm_mm_node *node = NULL;
int i, ret;
mem->mm_node = NULL;
@@ -973,17 +951,15 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
if (man->has_type && man->use_type) {
type_found = true;
- ret = ttm_bo_man_get_node(bo, man, placement, mem,
- &node);
+ ret = (*man->func->get_node)(man, bo, placement, mem);
if (unlikely(ret))
return ret;
}
- if (node)
+ if (mem->mm_node)
break;
}
- if ((type_ok && (mem_type == TTM_PL_SYSTEM)) || node) {
- mem->mm_node = node;
+ if ((type_ok && (mem_type == TTM_PL_SYSTEM)) || mem->mm_node) {
mem->mem_type = mem_type;
mem->placement = cur_flags;
return 0;
@@ -1053,7 +1029,6 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
bool interruptible, bool no_wait_reserve,
bool no_wait_gpu)
{
- struct ttm_bo_global *glob = bo->glob;
int ret = 0;
struct ttm_mem_reg mem;
@@ -1081,11 +1056,8 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
goto out_unlock;
ret = ttm_bo_handle_move_mem(bo, &mem, false, interruptible, no_wait_reserve, no_wait_gpu);
out_unlock:
- if (ret && mem.mm_node) {
- spin_lock(&glob->lru_lock);
- drm_mm_put_block(mem.mm_node);
- spin_unlock(&glob->lru_lock);
- }
+ if (ret && mem.mm_node)
+ ttm_bo_mem_put(bo, &mem);
return ret;
}
@@ -1093,11 +1065,10 @@ static int ttm_bo_mem_compat(struct ttm_placement *placement,
struct ttm_mem_reg *mem)
{
int i;
- struct drm_mm_node *node = mem->mm_node;
- if (node && placement->lpfn != 0 &&
- (node->start < placement->fpfn ||
- node->start + node->size > placement->lpfn))
+ if (mem->mm_node && placement->lpfn != 0 &&
+ (mem->start < placement->fpfn ||
+ mem->start + mem->num_pages > placement->lpfn))
return -1;
for (i = 0; i < placement->num_placement; i++) {
@@ -1341,7 +1312,6 @@ static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type)
{
- struct ttm_bo_global *glob = bdev->glob;
struct ttm_mem_type_manager *man;
int ret = -EINVAL;
@@ -1364,13 +1334,7 @@ int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type)
if (mem_type > 0) {
ttm_bo_force_list_clean(bdev, mem_type, false);
- spin_lock(&glob->lru_lock);
- if (drm_mm_clean(&man->manager))
- drm_mm_takedown(&man->manager);
- else
- ret = -EBUSY;
-
- spin_unlock(&glob->lru_lock);
+ ret = (*man->func->takedown)(man);
}
return ret;
@@ -1421,6 +1385,7 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
ret = bdev->driver->init_mem_type(bdev, type, man);
if (ret)
return ret;
+ man->bdev = bdev;
ret = 0;
if (type != TTM_PL_SYSTEM) {
@@ -1430,7 +1395,8 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
type);
return ret;
}
- ret = drm_mm_init(&man->manager, 0, p_size);
+
+ ret = (*man->func->init)(man, p_size);
if (ret)
return ret;
}
@@ -1824,6 +1790,13 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink)
struct ttm_buffer_object, swap);
kref_get(&bo->list_kref);
+ if (!list_empty(&bo->ddestroy)) {
+ spin_unlock(&glob->lru_lock);
+ (void) ttm_bo_cleanup_refs(bo, false, false, false);
+ kref_put(&bo->list_kref, ttm_bo_release_list);
+ continue;
+ }
+
/**
* Reserve buffer. Since we unlock while sleeping, we need
* to re-check that nobody removed us from the swap-list while
diff --git a/drivers/gpu/drm/ttm/ttm_bo_manager.c b/drivers/gpu/drm/ttm/ttm_bo_manager.c
new file mode 100644
index 000000000000..7410c190c891
--- /dev/null
+++ b/drivers/gpu/drm/ttm/ttm_bo_manager.c
@@ -0,0 +1,148 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#include "ttm/ttm_module.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_placement.h"
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <linux/module.h>
+
+static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
+ struct ttm_buffer_object *bo,
+ struct ttm_placement *placement,
+ struct ttm_mem_reg *mem)
+{
+ struct ttm_bo_global *glob = man->bdev->glob;
+ struct drm_mm *mm = man->priv;
+ struct drm_mm_node *node = NULL;
+ unsigned long lpfn;
+ int ret;
+
+ lpfn = placement->lpfn;
+ if (!lpfn)
+ lpfn = man->size;
+ do {
+ ret = drm_mm_pre_get(mm);
+ if (unlikely(ret))
+ return ret;
+
+ spin_lock(&glob->lru_lock);
+ node = drm_mm_search_free_in_range(mm,
+ mem->num_pages, mem->page_alignment,
+ placement->fpfn, lpfn, 1);
+ if (unlikely(node == NULL)) {
+ spin_unlock(&glob->lru_lock);
+ return 0;
+ }
+ node = drm_mm_get_block_atomic_range(node, mem->num_pages,
+ mem->page_alignment,
+ placement->fpfn,
+ lpfn);
+ spin_unlock(&glob->lru_lock);
+ } while (node == NULL);
+
+ mem->mm_node = node;
+ mem->start = node->start;
+ return 0;
+}
+
+static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man,
+ struct ttm_mem_reg *mem)
+{
+ struct ttm_bo_global *glob = man->bdev->glob;
+
+ if (mem->mm_node) {
+ spin_lock(&glob->lru_lock);
+ drm_mm_put_block(mem->mm_node);
+ spin_unlock(&glob->lru_lock);
+ mem->mm_node = NULL;
+ }
+}
+
+static int ttm_bo_man_init(struct ttm_mem_type_manager *man,
+ unsigned long p_size)
+{
+ struct drm_mm *mm;
+ int ret;
+
+ mm = kzalloc(sizeof(*mm), GFP_KERNEL);
+ if (!mm)
+ return -ENOMEM;
+
+ ret = drm_mm_init(mm, 0, p_size);
+ if (ret) {
+ kfree(mm);
+ return ret;
+ }
+
+ man->priv = mm;
+ return 0;
+}
+
+static int ttm_bo_man_takedown(struct ttm_mem_type_manager *man)
+{
+ struct ttm_bo_global *glob = man->bdev->glob;
+ struct drm_mm *mm = man->priv;
+ int ret = 0;
+
+ spin_lock(&glob->lru_lock);
+ if (drm_mm_clean(mm)) {
+ drm_mm_takedown(mm);
+ kfree(mm);
+ man->priv = NULL;
+ } else
+ ret = -EBUSY;
+ spin_unlock(&glob->lru_lock);
+ return ret;
+}
+
+static void ttm_bo_man_debug(struct ttm_mem_type_manager *man,
+ const char *prefix)
+{
+ struct ttm_bo_global *glob = man->bdev->glob;
+ struct drm_mm *mm = man->priv;
+
+ spin_lock(&glob->lru_lock);
+ drm_mm_debug_table(mm, prefix);
+ spin_unlock(&glob->lru_lock);
+}
+
+const struct ttm_mem_type_manager_func ttm_bo_manager_func = {
+ ttm_bo_man_init,
+ ttm_bo_man_takedown,
+ ttm_bo_man_get_node,
+ ttm_bo_man_put_node,
+ ttm_bo_man_debug
+};
+EXPORT_SYMBOL(ttm_bo_manager_func);
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index 3451a82adba7..3106d5bcce32 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -39,14 +39,7 @@
void ttm_bo_free_old_node(struct ttm_buffer_object *bo)
{
- struct ttm_mem_reg *old_mem = &bo->mem;
-
- if (old_mem->mm_node) {
- spin_lock(&bo->glob->lru_lock);
- drm_mm_put_block(old_mem->mm_node);
- spin_unlock(&bo->glob->lru_lock);
- }
- old_mem->mm_node = NULL;
+ ttm_bo_mem_put(bo, &bo->mem);
}
int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
@@ -170,7 +163,7 @@ static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src,
src = (void *)((unsigned long)src + (page << PAGE_SHIFT));
#ifdef CONFIG_X86
- dst = kmap_atomic_prot(d, KM_USER0, prot);
+ dst = kmap_atomic_prot(d, prot);
#else
if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
dst = vmap(&d, 1, 0, prot);
@@ -183,7 +176,7 @@ static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src,
memcpy_fromio(dst, src, PAGE_SIZE);
#ifdef CONFIG_X86
- kunmap_atomic(dst, KM_USER0);
+ kunmap_atomic(dst);
#else
if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
vunmap(dst);
@@ -206,7 +199,7 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst,
dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT));
#ifdef CONFIG_X86
- src = kmap_atomic_prot(s, KM_USER0, prot);
+ src = kmap_atomic_prot(s, prot);
#else
if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
src = vmap(&s, 1, 0, prot);
@@ -219,7 +212,7 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst,
memcpy_toio(dst, src, PAGE_SIZE);
#ifdef CONFIG_X86
- kunmap_atomic(src, KM_USER0);
+ kunmap_atomic(src);
#else
if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
vunmap(src);
@@ -263,8 +256,7 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
dir = 1;
if ((old_mem->mem_type == new_mem->mem_type) &&
- (new_mem->mm_node->start <
- old_mem->mm_node->start + old_mem->mm_node->size)) {
+ (new_mem->start < old_mem->start + old_mem->size)) {
dir = -1;
add = new_mem->num_pages - 1;
}
diff --git a/drivers/gpu/drm/via/via_drv.c b/drivers/gpu/drm/via/via_drv.c
index b8984a5ae521..e1ff4e7a6eb0 100644
--- a/drivers/gpu/drm/via/via_drv.c
+++ b/drivers/gpu/drm/via/via_drv.c
@@ -51,8 +51,6 @@ static struct drm_driver driver = {
.reclaim_buffers_locked = NULL,
.reclaim_buffers_idlelocked = via_reclaim_buffers_locked,
.lastclose = via_lastclose,
- .get_map_ofs = drm_core_get_map_ofs,
- .get_reg_ofs = drm_core_get_reg_ofs,
.ioctls = via_ioctls,
.fops = {
.owner = THIS_MODULE,
diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile
index 4505e17df3f5..c9281a1b1d3b 100644
--- a/drivers/gpu/drm/vmwgfx/Makefile
+++ b/drivers/gpu/drm/vmwgfx/Makefile
@@ -4,6 +4,6 @@ ccflags-y := -Iinclude/drm
vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \
vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
- vmwgfx_overlay.o vmwgfx_fence.o
+ vmwgfx_overlay.o vmwgfx_fence.o vmwgfx_gmrid_manager.o
obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
index c4f5114aee7c..80bc37b274e7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
@@ -39,6 +39,9 @@ static uint32_t vram_ne_placement_flags = TTM_PL_FLAG_VRAM |
static uint32_t sys_placement_flags = TTM_PL_FLAG_SYSTEM |
TTM_PL_FLAG_CACHED;
+static uint32_t gmr_placement_flags = VMW_PL_FLAG_GMR |
+ TTM_PL_FLAG_CACHED;
+
struct ttm_placement vmw_vram_placement = {
.fpfn = 0,
.lpfn = 0,
@@ -48,6 +51,20 @@ struct ttm_placement vmw_vram_placement = {
.busy_placement = &vram_placement_flags
};
+static uint32_t vram_gmr_placement_flags[] = {
+ TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED,
+ VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
+};
+
+struct ttm_placement vmw_vram_gmr_placement = {
+ .fpfn = 0,
+ .lpfn = 0,
+ .num_placement = 2,
+ .placement = vram_gmr_placement_flags,
+ .num_busy_placement = 1,
+ .busy_placement = &gmr_placement_flags
+};
+
struct ttm_placement vmw_vram_sys_placement = {
.fpfn = 0,
.lpfn = 0,
@@ -77,27 +94,52 @@ struct ttm_placement vmw_sys_placement = {
struct vmw_ttm_backend {
struct ttm_backend backend;
+ struct page **pages;
+ unsigned long num_pages;
+ struct vmw_private *dev_priv;
+ int gmr_id;
};
static int vmw_ttm_populate(struct ttm_backend *backend,
unsigned long num_pages, struct page **pages,
struct page *dummy_read_page)
{
+ struct vmw_ttm_backend *vmw_be =
+ container_of(backend, struct vmw_ttm_backend, backend);
+
+ vmw_be->pages = pages;
+ vmw_be->num_pages = num_pages;
+
return 0;
}
static int vmw_ttm_bind(struct ttm_backend *backend, struct ttm_mem_reg *bo_mem)
{
- return 0;
+ struct vmw_ttm_backend *vmw_be =
+ container_of(backend, struct vmw_ttm_backend, backend);
+
+ vmw_be->gmr_id = bo_mem->start;
+
+ return vmw_gmr_bind(vmw_be->dev_priv, vmw_be->pages,
+ vmw_be->num_pages, vmw_be->gmr_id);
}
static int vmw_ttm_unbind(struct ttm_backend *backend)
{
+ struct vmw_ttm_backend *vmw_be =
+ container_of(backend, struct vmw_ttm_backend, backend);
+
+ vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id);
return 0;
}
static void vmw_ttm_clear(struct ttm_backend *backend)
{
+ struct vmw_ttm_backend *vmw_be =
+ container_of(backend, struct vmw_ttm_backend, backend);
+
+ vmw_be->pages = NULL;
+ vmw_be->num_pages = 0;
}
static void vmw_ttm_destroy(struct ttm_backend *backend)
@@ -125,6 +167,7 @@ struct ttm_backend *vmw_ttm_backend_init(struct ttm_bo_device *bdev)
return NULL;
vmw_be->backend.func = &vmw_ttm_func;
+ vmw_be->dev_priv = container_of(bdev, struct vmw_private, bdev);
return &vmw_be->backend;
}
@@ -142,15 +185,28 @@ int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
/* System memory */
man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
- man->available_caching = TTM_PL_MASK_CACHING;
+ man->available_caching = TTM_PL_FLAG_CACHED;
man->default_caching = TTM_PL_FLAG_CACHED;
break;
case TTM_PL_VRAM:
/* "On-card" video ram */
+ man->func = &ttm_bo_manager_func;
man->gpu_offset = 0;
man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_MAPPABLE;
- man->available_caching = TTM_PL_MASK_CACHING;
- man->default_caching = TTM_PL_FLAG_WC;
+ man->available_caching = TTM_PL_FLAG_CACHED;
+ man->default_caching = TTM_PL_FLAG_CACHED;
+ break;
+ case VMW_PL_GMR:
+ /*
+ * "Guest Memory Regions" is an aperture like feature with
+ * one slot per bo. There is an upper limit of the number of
+ * slots as well as the bo size.
+ */
+ man->func = &vmw_gmrid_manager_func;
+ man->gpu_offset = 0;
+ man->flags = TTM_MEMTYPE_FLAG_CMA | TTM_MEMTYPE_FLAG_MAPPABLE;
+ man->available_caching = TTM_PL_FLAG_CACHED;
+ man->default_caching = TTM_PL_FLAG_CACHED;
break;
default:
DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
@@ -174,18 +230,6 @@ static int vmw_verify_access(struct ttm_buffer_object *bo, struct file *filp)
return 0;
}
-static void vmw_move_notify(struct ttm_buffer_object *bo,
- struct ttm_mem_reg *new_mem)
-{
- if (new_mem->mem_type != TTM_PL_SYSTEM)
- vmw_dmabuf_gmr_unbind(bo);
-}
-
-static void vmw_swap_notify(struct ttm_buffer_object *bo)
-{
- vmw_dmabuf_gmr_unbind(bo);
-}
-
static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
{
struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
@@ -200,10 +244,10 @@ static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg
return -EINVAL;
switch (mem->mem_type) {
case TTM_PL_SYSTEM:
- /* System memory */
+ case VMW_PL_GMR:
return 0;
case TTM_PL_VRAM:
- mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
+ mem->bus.offset = mem->start << PAGE_SHIFT;
mem->bus.base = dev_priv->vram_start;
mem->bus.is_iomem = true;
break;
@@ -276,8 +320,8 @@ struct ttm_bo_driver vmw_bo_driver = {
.sync_obj_flush = vmw_sync_obj_flush,
.sync_obj_unref = vmw_sync_obj_unref,
.sync_obj_ref = vmw_sync_obj_ref,
- .move_notify = vmw_move_notify,
- .swap_notify = vmw_swap_notify,
+ .move_notify = NULL,
+ .swap_notify = NULL,
.fault_reserve_notify = &vmw_ttm_fault_reserve_notify,
.io_mem_reserve = &vmw_ttm_io_mem_reserve,
.io_mem_free = &vmw_ttm_io_mem_free,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 2ef93df9e8ae..10ca97ee0206 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -260,13 +260,11 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
idr_init(&dev_priv->context_idr);
idr_init(&dev_priv->surface_idr);
idr_init(&dev_priv->stream_idr);
- ida_init(&dev_priv->gmr_ida);
mutex_init(&dev_priv->init_mutex);
init_waitqueue_head(&dev_priv->fence_queue);
init_waitqueue_head(&dev_priv->fifo_queue);
atomic_set(&dev_priv->fence_queue_waiters, 0);
atomic_set(&dev_priv->fifo_queue_waiters, 0);
- INIT_LIST_HEAD(&dev_priv->gmr_lru);
dev_priv->io_start = pci_resource_start(dev->pdev, 0);
dev_priv->vram_start = pci_resource_start(dev->pdev, 1);
@@ -341,6 +339,14 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
goto out_err2;
}
+ dev_priv->has_gmr = true;
+ if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR,
+ dev_priv->max_gmr_ids) != 0) {
+ DRM_INFO("No GMR memory available. "
+ "Graphics memory resources are very limited.\n");
+ dev_priv->has_gmr = false;
+ }
+
dev_priv->mmio_mtrr = drm_mtrr_add(dev_priv->mmio_start,
dev_priv->mmio_size, DRM_MTRR_WC);
@@ -440,13 +446,14 @@ out_err4:
out_err3:
drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start,
dev_priv->mmio_size, DRM_MTRR_WC);
+ if (dev_priv->has_gmr)
+ (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
(void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
out_err2:
(void)ttm_bo_device_release(&dev_priv->bdev);
out_err1:
vmw_ttm_global_release(dev_priv);
out_err0:
- ida_destroy(&dev_priv->gmr_ida);
idr_destroy(&dev_priv->surface_idr);
idr_destroy(&dev_priv->context_idr);
idr_destroy(&dev_priv->stream_idr);
@@ -478,10 +485,11 @@ static int vmw_driver_unload(struct drm_device *dev)
iounmap(dev_priv->mmio_virt);
drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start,
dev_priv->mmio_size, DRM_MTRR_WC);
+ if (dev_priv->has_gmr)
+ (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
(void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
(void)ttm_bo_device_release(&dev_priv->bdev);
vmw_ttm_global_release(dev_priv);
- ida_destroy(&dev_priv->gmr_ida);
idr_destroy(&dev_priv->surface_idr);
idr_destroy(&dev_priv->context_idr);
idr_destroy(&dev_priv->stream_idr);
@@ -597,6 +605,8 @@ static void vmw_lastclose(struct drm_device *dev)
static void vmw_master_init(struct vmw_master *vmaster)
{
ttm_lock_init(&vmaster->lock);
+ INIT_LIST_HEAD(&vmaster->fb_surf);
+ mutex_init(&vmaster->fb_surf_mutex);
}
static int vmw_master_create(struct drm_device *dev,
@@ -608,7 +618,7 @@ static int vmw_master_create(struct drm_device *dev,
if (unlikely(vmaster == NULL))
return -ENOMEM;
- ttm_lock_init(&vmaster->lock);
+ vmw_master_init(vmaster);
ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
master->driver_priv = vmaster;
@@ -699,6 +709,7 @@ static void vmw_master_drop(struct drm_device *dev,
vmw_fp->locked_master = drm_master_get(file_priv->master);
ret = ttm_vt_lock(&vmaster->lock, false, vmw_fp->tfile);
+ vmw_kms_idle_workqueues(vmaster);
if (unlikely((ret != 0))) {
DRM_ERROR("Unable to lock TTM at VT switch.\n");
@@ -751,15 +762,16 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
* Buffer contents is moved to swappable memory.
*/
ttm_bo_swapout_all(&dev_priv->bdev);
+
break;
case PM_POST_HIBERNATION:
case PM_POST_SUSPEND:
+ case PM_POST_RESTORE:
ttm_suspend_unlock(&vmaster->lock);
+
break;
case PM_RESTORE_PREPARE:
break;
- case PM_POST_RESTORE:
- break;
default:
break;
}
@@ -770,21 +782,98 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
* These might not be needed with the virtual SVGA device.
*/
-int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+ struct vmw_private *dev_priv = vmw_priv(dev);
+
+ if (dev_priv->num_3d_resources != 0) {
+ DRM_INFO("Can't suspend or hibernate "
+ "while 3D resources are active.\n");
+ return -EBUSY;
+ }
+
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
-int vmw_pci_resume(struct pci_dev *pdev)
+static int vmw_pci_resume(struct pci_dev *pdev)
{
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
return pci_enable_device(pdev);
}
+static int vmw_pm_suspend(struct device *kdev)
+{
+ struct pci_dev *pdev = to_pci_dev(kdev);
+ struct pm_message dummy;
+
+ dummy.event = 0;
+
+ return vmw_pci_suspend(pdev, dummy);
+}
+
+static int vmw_pm_resume(struct device *kdev)
+{
+ struct pci_dev *pdev = to_pci_dev(kdev);
+
+ return vmw_pci_resume(pdev);
+}
+
+static int vmw_pm_prepare(struct device *kdev)
+{
+ struct pci_dev *pdev = to_pci_dev(kdev);
+ struct drm_device *dev = pci_get_drvdata(pdev);
+ struct vmw_private *dev_priv = vmw_priv(dev);
+
+ /**
+ * Release 3d reference held by fbdev and potentially
+ * stop fifo.
+ */
+ dev_priv->suspended = true;
+ if (dev_priv->enable_fb)
+ vmw_3d_resource_dec(dev_priv);
+
+ if (dev_priv->num_3d_resources != 0) {
+
+ DRM_INFO("Can't suspend or hibernate "
+ "while 3D resources are active.\n");
+
+ if (dev_priv->enable_fb)
+ vmw_3d_resource_inc(dev_priv);
+ dev_priv->suspended = false;
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static void vmw_pm_complete(struct device *kdev)
+{
+ struct pci_dev *pdev = to_pci_dev(kdev);
+ struct drm_device *dev = pci_get_drvdata(pdev);
+ struct vmw_private *dev_priv = vmw_priv(dev);
+
+ /**
+ * Reclaim 3d reference held by fbdev and potentially
+ * start fifo.
+ */
+ if (dev_priv->enable_fb)
+ vmw_3d_resource_inc(dev_priv);
+
+ dev_priv->suspended = false;
+}
+
+static const struct dev_pm_ops vmw_pm_ops = {
+ .prepare = vmw_pm_prepare,
+ .complete = vmw_pm_complete,
+ .suspend = vmw_pm_suspend,
+ .resume = vmw_pm_resume,
+};
+
static struct drm_driver driver = {
.driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
DRIVER_MODESET,
@@ -798,8 +887,6 @@ static struct drm_driver driver = {
.irq_handler = vmw_irq_handler,
.get_vblank_counter = vmw_get_vblank_counter,
.reclaim_buffers_locked = NULL,
- .get_map_ofs = drm_core_get_map_ofs,
- .get_reg_ofs = drm_core_get_reg_ofs,
.ioctls = vmw_ioctls,
.num_ioctls = DRM_ARRAY_SIZE(vmw_ioctls),
.dma_quiescent = NULL, /*vmw_dma_quiescent, */
@@ -821,15 +908,16 @@ static struct drm_driver driver = {
.compat_ioctl = drm_compat_ioctl,
#endif
.llseek = noop_llseek,
- },
+ },
.pci_driver = {
- .name = VMWGFX_DRIVER_NAME,
- .id_table = vmw_pci_id_list,
- .probe = vmw_probe,
- .remove = vmw_remove,
- .suspend = vmw_pci_suspend,
- .resume = vmw_pci_resume
- },
+ .name = VMWGFX_DRIVER_NAME,
+ .id_table = vmw_pci_id_list,
+ .probe = vmw_probe,
+ .remove = vmw_remove,
+ .driver = {
+ .pm = &vmw_pm_ops
+ }
+ },
.name = VMWGFX_DRIVER_NAME,
.desc = VMWGFX_DRIVER_DESC,
.date = VMWGFX_DRIVER_DATE,
@@ -863,3 +951,7 @@ module_exit(vmwgfx_exit);
MODULE_AUTHOR("VMware Inc. and others");
MODULE_DESCRIPTION("Standalone drm driver for the VMware SVGA device");
MODULE_LICENSE("GPL and additional rights");
+MODULE_VERSION(__stringify(VMWGFX_DRIVER_MAJOR) "."
+ __stringify(VMWGFX_DRIVER_MINOR) "."
+ __stringify(VMWGFX_DRIVER_PATCHLEVEL) "."
+ "0");
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 58de6393f611..e7a58d055041 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -39,9 +39,9 @@
#include "ttm/ttm_execbuf_util.h"
#include "ttm/ttm_module.h"
-#define VMWGFX_DRIVER_DATE "20100209"
+#define VMWGFX_DRIVER_DATE "20100927"
#define VMWGFX_DRIVER_MAJOR 1
-#define VMWGFX_DRIVER_MINOR 2
+#define VMWGFX_DRIVER_MINOR 4
#define VMWGFX_DRIVER_PATCHLEVEL 0
#define VMWGFX_FILE_PAGE_OFFSET 0x00100000
#define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
@@ -49,6 +49,9 @@
#define VMWGFX_MAX_GMRS 2048
#define VMWGFX_MAX_DISPLAYS 16
+#define VMW_PL_GMR TTM_PL_PRIV0
+#define VMW_PL_FLAG_GMR TTM_PL_FLAG_PRIV0
+
struct vmw_fpriv {
struct drm_master *locked_master;
struct ttm_object_file *tfile;
@@ -57,8 +60,6 @@ struct vmw_fpriv {
struct vmw_dma_buffer {
struct ttm_buffer_object base;
struct list_head validate_list;
- struct list_head gmr_lru;
- uint32_t gmr_id;
bool gmr_bound;
uint32_t cur_validate_node;
bool on_validate_list;
@@ -151,6 +152,8 @@ struct vmw_overlay;
struct vmw_master {
struct ttm_lock lock;
+ struct mutex fb_surf_mutex;
+ struct list_head fb_surf;
};
struct vmw_vga_topology_state {
@@ -182,6 +185,7 @@ struct vmw_private {
uint32_t capabilities;
uint32_t max_gmr_descriptors;
uint32_t max_gmr_ids;
+ bool has_gmr;
struct mutex hw_mutex;
/*
@@ -264,14 +268,6 @@ struct vmw_private {
struct mutex cmdbuf_mutex;
/**
- * GMR management. Protected by the lru spinlock.
- */
-
- struct ida gmr_ida;
- struct list_head gmr_lru;
-
-
- /**
* Operating mode.
*/
@@ -286,6 +282,7 @@ struct vmw_private {
struct vmw_master *active_master;
struct vmw_master fbdev_master;
struct notifier_block pm_nb;
+ bool suspended;
struct mutex release_mutex;
uint32_t num_3d_resources;
@@ -331,7 +328,9 @@ void vmw_3d_resource_dec(struct vmw_private *dev_priv);
*/
extern int vmw_gmr_bind(struct vmw_private *dev_priv,
- struct ttm_buffer_object *bo);
+ struct page *pages[],
+ unsigned long num_pages,
+ int gmr_id);
extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id);
/**
@@ -380,14 +379,10 @@ extern uint32_t vmw_dmabuf_validate_node(struct ttm_buffer_object *bo,
extern void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo);
extern int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
uint32_t id, struct vmw_dma_buffer **out);
-extern uint32_t vmw_dmabuf_gmr(struct ttm_buffer_object *bo);
-extern void vmw_dmabuf_set_gmr(struct ttm_buffer_object *bo, uint32_t id);
-extern int vmw_gmr_id_alloc(struct vmw_private *dev_priv, uint32_t *p_id);
extern int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
struct vmw_dma_buffer *bo);
extern int vmw_dmabuf_from_vram(struct vmw_private *vmw_priv,
struct vmw_dma_buffer *bo);
-extern void vmw_dmabuf_gmr_unbind(struct ttm_buffer_object *bo);
extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
@@ -439,6 +434,7 @@ extern int vmw_mmap(struct file *filp, struct vm_area_struct *vma);
extern struct ttm_placement vmw_vram_placement;
extern struct ttm_placement vmw_vram_ne_placement;
extern struct ttm_placement vmw_vram_sys_placement;
+extern struct ttm_placement vmw_vram_gmr_placement;
extern struct ttm_placement vmw_sys_placement;
extern struct ttm_bo_driver vmw_bo_driver;
extern int vmw_dma_quiescent(struct drm_device *dev);
@@ -518,6 +514,10 @@ void vmw_kms_write_svga(struct vmw_private *vmw_priv,
unsigned bbp, unsigned depth);
int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+void vmw_kms_idle_workqueues(struct vmw_master *vmaster);
+bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv,
+ uint32_t pitch,
+ uint32_t height);
u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc);
/**
@@ -537,6 +537,12 @@ int vmw_overlay_num_overlays(struct vmw_private *dev_priv);
int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv);
/**
+ * GMR Id manager
+ */
+
+extern const struct ttm_mem_type_manager_func vmw_gmrid_manager_func;
+
+/**
* Inline helper functions
*/
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 8e396850513c..51d9f9f1d7f2 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -538,8 +538,11 @@ static void vmw_apply_relocations(struct vmw_sw_context *sw_context)
reloc = &sw_context->relocs[i];
validate = &sw_context->val_bufs[reloc->index];
bo = validate->bo;
- reloc->location->offset += bo->offset;
- reloc->location->gmrId = vmw_dmabuf_gmr(bo);
+ if (bo->mem.mem_type == TTM_PL_VRAM) {
+ reloc->location->offset += bo->offset;
+ reloc->location->gmrId = SVGA_GMR_FRAMEBUFFER;
+ } else
+ reloc->location->gmrId = bo->mem.start;
}
vmw_free_relocations(sw_context);
}
@@ -563,25 +566,14 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
{
int ret;
- if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL)
- return 0;
-
/**
- * Put BO in VRAM, only if there is space.
+ * Put BO in VRAM if there is space, otherwise as a GMR.
+ * If there is no space in VRAM and GMR ids are all used up,
+ * start evicting GMRs to make room. If the DMA buffer can't be
+ * used as a GMR, this will return -ENOMEM.
*/
- ret = ttm_bo_validate(bo, &vmw_vram_sys_placement, true, false, false);
- if (unlikely(ret == -ERESTARTSYS))
- return ret;
-
- /**
- * Otherwise, set it up as GMR.
- */
-
- if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL)
- return 0;
-
- ret = vmw_gmr_bind(dev_priv, bo);
+ ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, true, false, false);
if (likely(ret == 0 || ret == -ERESTARTSYS))
return ret;
@@ -590,6 +582,7 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
* previous contents.
*/
+ DRM_INFO("Falling through to VRAM.\n");
ret = ttm_bo_validate(bo, &vmw_vram_placement, true, false, false);
return ret;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
index 409e172f4abf..41d9a5b73c03 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
@@ -144,6 +144,13 @@ static int vmw_fb_check_var(struct fb_var_screeninfo *var,
return -EINVAL;
}
+ if (!vmw_kms_validate_mode_vram(vmw_priv,
+ info->fix.line_length,
+ var->yoffset + var->yres)) {
+ DRM_ERROR("Requested geom can not fit in framebuffer\n");
+ return -EINVAL;
+ }
+
return 0;
}
@@ -205,6 +212,9 @@ static void vmw_fb_dirty_flush(struct vmw_fb_par *par)
SVGAFifoCmdUpdate body;
} *cmd;
+ if (vmw_priv->suspended)
+ return;
+
spin_lock_irqsave(&par->dirty.lock, flags);
if (!par->dirty.active) {
spin_unlock_irqrestore(&par->dirty.lock, flags);
@@ -616,7 +626,8 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
goto err_unlock;
if (bo->mem.mem_type == TTM_PL_VRAM &&
- bo->mem.mm_node->start < bo->num_pages)
+ bo->mem.start < bo->num_pages &&
+ bo->mem.start > 0)
(void) ttm_bo_validate(bo, &vmw_sys_placement, false,
false, false);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
index 0fe31766e4cf..635c0ffee7fe 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
@@ -545,7 +545,7 @@ int vmw_fifo_mmap(struct file *filp, struct vm_area_struct *vma)
struct drm_file *file_priv;
struct vmw_private *dev_priv;
- file_priv = (struct drm_file *)filp->private_data;
+ file_priv = filp->private_data;
dev_priv = vmw_priv(file_priv->minor->dev);
if (vma->vm_pgoff != (dev_priv->mmio_start >> PAGE_SHIFT) ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
index 5f8908a5d7fd..de0c5948521d 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
@@ -146,7 +146,7 @@ static void vmw_gmr_fire_descriptors(struct vmw_private *dev_priv,
*/
static unsigned long vmw_gmr_count_descriptors(struct page *pages[],
- unsigned long num_pages)
+ unsigned long num_pages)
{
unsigned long prev_pfn = ~(0UL);
unsigned long pfn;
@@ -163,45 +163,33 @@ static unsigned long vmw_gmr_count_descriptors(struct page *pages[],
}
int vmw_gmr_bind(struct vmw_private *dev_priv,
- struct ttm_buffer_object *bo)
+ struct page *pages[],
+ unsigned long num_pages,
+ int gmr_id)
{
- struct ttm_tt *ttm = bo->ttm;
- unsigned long descriptors;
- int ret;
- uint32_t id;
struct list_head desc_pages;
+ int ret;
- if (!(dev_priv->capabilities & SVGA_CAP_GMR))
+ if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR)))
return -EINVAL;
- ret = ttm_tt_populate(ttm);
- if (unlikely(ret != 0))
- return ret;
-
- descriptors = vmw_gmr_count_descriptors(ttm->pages, ttm->num_pages);
- if (unlikely(descriptors > dev_priv->max_gmr_descriptors))
+ if (vmw_gmr_count_descriptors(pages, num_pages) >
+ dev_priv->max_gmr_descriptors)
return -EINVAL;
INIT_LIST_HEAD(&desc_pages);
- ret = vmw_gmr_build_descriptors(&desc_pages, ttm->pages,
- ttm->num_pages);
- if (unlikely(ret != 0))
- return ret;
- ret = vmw_gmr_id_alloc(dev_priv, &id);
+ ret = vmw_gmr_build_descriptors(&desc_pages, pages, num_pages);
if (unlikely(ret != 0))
- goto out_no_id;
+ return ret;
- vmw_gmr_fire_descriptors(dev_priv, id, &desc_pages);
+ vmw_gmr_fire_descriptors(dev_priv, gmr_id, &desc_pages);
vmw_gmr_free_descriptors(&desc_pages);
- vmw_dmabuf_set_gmr(bo, id);
- return 0;
-out_no_id:
- vmw_gmr_free_descriptors(&desc_pages);
- return ret;
+ return 0;
}
+
void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id)
{
mutex_lock(&dev_priv->hw_mutex);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
new file mode 100644
index 000000000000..ac6e0d1bd629
--- /dev/null
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
@@ -0,0 +1,137 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2007-2010 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#include "vmwgfx_drv.h"
+#include "ttm/ttm_module.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_placement.h"
+#include <linux/idr.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+
+struct vmwgfx_gmrid_man {
+ spinlock_t lock;
+ struct ida gmr_ida;
+ uint32_t max_gmr_ids;
+};
+
+static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man,
+ struct ttm_buffer_object *bo,
+ struct ttm_placement *placement,
+ struct ttm_mem_reg *mem)
+{
+ struct vmwgfx_gmrid_man *gman =
+ (struct vmwgfx_gmrid_man *)man->priv;
+ int ret;
+ int id;
+
+ mem->mm_node = NULL;
+
+ do {
+ if (unlikely(ida_pre_get(&gman->gmr_ida, GFP_KERNEL) == 0))
+ return -ENOMEM;
+
+ spin_lock(&gman->lock);
+ ret = ida_get_new(&gman->gmr_ida, &id);
+
+ if (unlikely(ret == 0 && id >= gman->max_gmr_ids)) {
+ ida_remove(&gman->gmr_ida, id);
+ spin_unlock(&gman->lock);
+ return 0;
+ }
+
+ spin_unlock(&gman->lock);
+
+ } while (ret == -EAGAIN);
+
+ if (likely(ret == 0)) {
+ mem->mm_node = gman;
+ mem->start = id;
+ }
+
+ return ret;
+}
+
+static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man,
+ struct ttm_mem_reg *mem)
+{
+ struct vmwgfx_gmrid_man *gman =
+ (struct vmwgfx_gmrid_man *)man->priv;
+
+ if (mem->mm_node) {
+ spin_lock(&gman->lock);
+ ida_remove(&gman->gmr_ida, mem->start);
+ spin_unlock(&gman->lock);
+ mem->mm_node = NULL;
+ }
+}
+
+static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man,
+ unsigned long p_size)
+{
+ struct vmwgfx_gmrid_man *gman =
+ kzalloc(sizeof(*gman), GFP_KERNEL);
+
+ if (unlikely(gman == NULL))
+ return -ENOMEM;
+
+ spin_lock_init(&gman->lock);
+ ida_init(&gman->gmr_ida);
+ gman->max_gmr_ids = p_size;
+ man->priv = (void *) gman;
+ return 0;
+}
+
+static int vmw_gmrid_man_takedown(struct ttm_mem_type_manager *man)
+{
+ struct vmwgfx_gmrid_man *gman =
+ (struct vmwgfx_gmrid_man *)man->priv;
+
+ if (gman) {
+ ida_destroy(&gman->gmr_ida);
+ kfree(gman);
+ }
+ return 0;
+}
+
+static void vmw_gmrid_man_debug(struct ttm_mem_type_manager *man,
+ const char *prefix)
+{
+ printk(KERN_INFO "%s: No debug info available for the GMR "
+ "id manager.\n", prefix);
+}
+
+const struct ttm_mem_type_manager_func vmw_gmrid_manager_func = {
+ vmw_gmrid_man_init,
+ vmw_gmrid_man_takedown,
+ vmw_gmrid_man_get_node,
+ vmw_gmrid_man_put_node,
+ vmw_gmrid_man_debug
+};
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index 1c7a316454d8..570d57775a58 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -54,6 +54,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
case DRM_VMW_PARAM_FIFO_CAPS:
param->value = dev_priv->fifo.capabilities;
break;
+ case DRM_VMW_PARAM_MAX_FB_SIZE:
+ param->value = dev_priv->vram_size;
+ break;
default:
DRM_ERROR("Illegal vmwgfx get param request: %d\n",
param->param);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index e882ba099f0c..87c6e6156d7d 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -332,18 +332,55 @@ struct vmw_framebuffer_surface {
struct delayed_work d_work;
struct mutex work_lock;
bool present_fs;
+ struct list_head head;
+ struct drm_master *master;
};
+/**
+ * vmw_kms_idle_workqueues - Flush workqueues on this master
+ *
+ * @vmaster - Pointer identifying the master, for the surfaces of which
+ * we idle the dirty work queues.
+ *
+ * This function should be called with the ttm lock held in exclusive mode
+ * to idle all dirty work queues before the fifo is taken down.
+ *
+ * The work task may actually requeue itself, but after the flush returns we're
+ * sure that there's nothing to present, since the ttm lock is held in
+ * exclusive mode, so the fifo will never get used.
+ */
+
+void vmw_kms_idle_workqueues(struct vmw_master *vmaster)
+{
+ struct vmw_framebuffer_surface *entry;
+
+ mutex_lock(&vmaster->fb_surf_mutex);
+ list_for_each_entry(entry, &vmaster->fb_surf, head) {
+ if (cancel_delayed_work_sync(&entry->d_work))
+ (void) entry->d_work.work.func(&entry->d_work.work);
+
+ (void) cancel_delayed_work_sync(&entry->d_work);
+ }
+ mutex_unlock(&vmaster->fb_surf_mutex);
+}
+
void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
{
- struct vmw_framebuffer_surface *vfb =
+ struct vmw_framebuffer_surface *vfbs =
vmw_framebuffer_to_vfbs(framebuffer);
+ struct vmw_master *vmaster = vmw_master(vfbs->master);
+
- cancel_delayed_work_sync(&vfb->d_work);
+ mutex_lock(&vmaster->fb_surf_mutex);
+ list_del(&vfbs->head);
+ mutex_unlock(&vmaster->fb_surf_mutex);
+
+ cancel_delayed_work_sync(&vfbs->d_work);
+ drm_master_put(&vfbs->master);
drm_framebuffer_cleanup(framebuffer);
- vmw_surface_unreference(&vfb->surface);
+ vmw_surface_unreference(&vfbs->surface);
- kfree(framebuffer);
+ kfree(vfbs);
}
static void vmw_framebuffer_present_fs_callback(struct work_struct *work)
@@ -362,6 +399,12 @@ static void vmw_framebuffer_present_fs_callback(struct work_struct *work)
SVGA3dCopyRect cr;
} *cmd;
+ /**
+ * Strictly we should take the ttm_lock in read mode before accessing
+ * the fifo, to make sure the fifo is present and up. However,
+ * instead we flush all workqueues under the ttm lock in exclusive mode
+ * before taking down the fifo.
+ */
mutex_lock(&vfbs->work_lock);
if (!vfbs->present_fs)
goto out_unlock;
@@ -392,17 +435,20 @@ out_unlock:
int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
+ struct drm_file *file_priv,
unsigned flags, unsigned color,
struct drm_clip_rect *clips,
unsigned num_clips)
{
struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
+ struct vmw_master *vmaster = vmw_master(file_priv->master);
struct vmw_framebuffer_surface *vfbs =
vmw_framebuffer_to_vfbs(framebuffer);
struct vmw_surface *surf = vfbs->surface;
struct drm_clip_rect norect;
SVGA3dCopyRect *cr;
int i, inc = 1;
+ int ret;
struct {
SVGA3dCmdHeader header;
@@ -410,6 +456,13 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
SVGA3dCopyRect cr;
} *cmd;
+ if (unlikely(vfbs->master != file_priv->master))
+ return -EINVAL;
+
+ ret = ttm_read_lock(&vmaster->lock, true);
+ if (unlikely(ret != 0))
+ return ret;
+
if (!num_clips ||
!(dev_priv->fifo.capabilities &
SVGA_FIFO_CAP_SCREEN_OBJECT)) {
@@ -425,6 +478,7 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
*/
vmw_framebuffer_present_fs_callback(&vfbs->d_work.work);
}
+ ttm_read_unlock(&vmaster->lock);
return 0;
}
@@ -442,6 +496,7 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cr));
if (unlikely(cmd == NULL)) {
DRM_ERROR("Fifo reserve failed.\n");
+ ttm_read_unlock(&vmaster->lock);
return -ENOMEM;
}
@@ -461,7 +516,7 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
}
vmw_fifo_commit(dev_priv, sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cr));
-
+ ttm_read_unlock(&vmaster->lock);
return 0;
}
@@ -471,16 +526,57 @@ static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = {
.create_handle = vmw_framebuffer_create_handle,
};
-int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
- struct vmw_surface *surface,
- struct vmw_framebuffer **out,
- unsigned width, unsigned height)
+static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
+ struct drm_file *file_priv,
+ struct vmw_surface *surface,
+ struct vmw_framebuffer **out,
+ const struct drm_mode_fb_cmd
+ *mode_cmd)
{
struct drm_device *dev = dev_priv->dev;
struct vmw_framebuffer_surface *vfbs;
+ enum SVGA3dSurfaceFormat format;
+ struct vmw_master *vmaster = vmw_master(file_priv->master);
int ret;
+ /*
+ * Sanity checks.
+ */
+
+ if (unlikely(surface->mip_levels[0] != 1 ||
+ surface->num_sizes != 1 ||
+ surface->sizes[0].width < mode_cmd->width ||
+ surface->sizes[0].height < mode_cmd->height ||
+ surface->sizes[0].depth != 1)) {
+ DRM_ERROR("Incompatible surface dimensions "
+ "for requested mode.\n");
+ return -EINVAL;
+ }
+
+ switch (mode_cmd->depth) {
+ case 32:
+ format = SVGA3D_A8R8G8B8;
+ break;
+ case 24:
+ format = SVGA3D_X8R8G8B8;
+ break;
+ case 16:
+ format = SVGA3D_R5G6B5;
+ break;
+ case 15:
+ format = SVGA3D_A1R5G5B5;
+ break;
+ default:
+ DRM_ERROR("Invalid color depth: %d\n", mode_cmd->depth);
+ return -EINVAL;
+ }
+
+ if (unlikely(format != surface->format)) {
+ DRM_ERROR("Invalid surface format for requested mode.\n");
+ return -EINVAL;
+ }
+
vfbs = kzalloc(sizeof(*vfbs), GFP_KERNEL);
if (!vfbs) {
ret = -ENOMEM;
@@ -498,16 +594,22 @@ int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
}
/* XXX get the first 3 from the surface info */
- vfbs->base.base.bits_per_pixel = 32;
- vfbs->base.base.pitch = width * 32 / 4;
- vfbs->base.base.depth = 24;
- vfbs->base.base.width = width;
- vfbs->base.base.height = height;
+ vfbs->base.base.bits_per_pixel = mode_cmd->bpp;
+ vfbs->base.base.pitch = mode_cmd->pitch;
+ vfbs->base.base.depth = mode_cmd->depth;
+ vfbs->base.base.width = mode_cmd->width;
+ vfbs->base.base.height = mode_cmd->height;
vfbs->base.pin = &vmw_surface_dmabuf_pin;
vfbs->base.unpin = &vmw_surface_dmabuf_unpin;
vfbs->surface = surface;
+ vfbs->master = drm_master_get(file_priv->master);
mutex_init(&vfbs->work_lock);
+
+ mutex_lock(&vmaster->fb_surf_mutex);
INIT_DELAYED_WORK(&vfbs->d_work, &vmw_framebuffer_present_fs_callback);
+ list_add_tail(&vfbs->head, &vmaster->fb_surf);
+ mutex_unlock(&vmaster->fb_surf_mutex);
+
*out = &vfbs->base;
return 0;
@@ -544,18 +646,25 @@ void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer)
}
int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
+ struct drm_file *file_priv,
unsigned flags, unsigned color,
struct drm_clip_rect *clips,
unsigned num_clips)
{
struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
+ struct vmw_master *vmaster = vmw_master(file_priv->master);
struct drm_clip_rect norect;
+ int ret;
struct {
uint32_t header;
SVGAFifoCmdUpdate body;
} *cmd;
int i, increment = 1;
+ ret = ttm_read_lock(&vmaster->lock, true);
+ if (unlikely(ret != 0))
+ return ret;
+
if (!num_clips) {
num_clips = 1;
clips = &norect;
@@ -570,6 +679,7 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd) * num_clips);
if (unlikely(cmd == NULL)) {
DRM_ERROR("Fifo reserve failed.\n");
+ ttm_read_unlock(&vmaster->lock);
return -ENOMEM;
}
@@ -582,6 +692,7 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
}
vmw_fifo_commit(dev_priv, sizeof(*cmd) * num_clips);
+ ttm_read_unlock(&vmaster->lock);
return 0;
}
@@ -659,16 +770,25 @@ static int vmw_framebuffer_dmabuf_unpin(struct vmw_framebuffer *vfb)
return vmw_dmabuf_from_vram(dev_priv, vfbd->buffer);
}
-int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
- struct vmw_dma_buffer *dmabuf,
- struct vmw_framebuffer **out,
- unsigned width, unsigned height)
+static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
+ struct vmw_dma_buffer *dmabuf,
+ struct vmw_framebuffer **out,
+ const struct drm_mode_fb_cmd
+ *mode_cmd)
{
struct drm_device *dev = dev_priv->dev;
struct vmw_framebuffer_dmabuf *vfbd;
+ unsigned int requested_size;
int ret;
+ requested_size = mode_cmd->height * mode_cmd->pitch;
+ if (unlikely(requested_size > dmabuf->base.num_pages * PAGE_SIZE)) {
+ DRM_ERROR("Screen buffer object size is too small "
+ "for requested mode.\n");
+ return -EINVAL;
+ }
+
vfbd = kzalloc(sizeof(*vfbd), GFP_KERNEL);
if (!vfbd) {
ret = -ENOMEM;
@@ -685,12 +805,11 @@ int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
goto out_err3;
}
- /* XXX get the first 3 from the surface info */
- vfbd->base.base.bits_per_pixel = 32;
- vfbd->base.base.pitch = width * vfbd->base.base.bits_per_pixel / 8;
- vfbd->base.base.depth = 24;
- vfbd->base.base.width = width;
- vfbd->base.base.height = height;
+ vfbd->base.base.bits_per_pixel = mode_cmd->bpp;
+ vfbd->base.base.pitch = mode_cmd->pitch;
+ vfbd->base.base.depth = mode_cmd->depth;
+ vfbd->base.base.width = mode_cmd->width;
+ vfbd->base.base.height = mode_cmd->height;
vfbd->base.pin = vmw_framebuffer_dmabuf_pin;
vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin;
vfbd->buffer = dmabuf;
@@ -719,8 +838,25 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
struct vmw_framebuffer *vfb = NULL;
struct vmw_surface *surface = NULL;
struct vmw_dma_buffer *bo = NULL;
+ u64 required_size;
int ret;
+ /**
+ * This code should be conditioned on Screen Objects not being used.
+ * If screen objects are used, we can allocate a GMR to hold the
+ * requested framebuffer.
+ */
+
+ required_size = mode_cmd->pitch * mode_cmd->height;
+ if (unlikely(required_size > (u64) dev_priv->vram_size)) {
+ DRM_ERROR("VRAM size is too small for requested mode.\n");
+ return NULL;
+ }
+
+ /**
+ * End conditioned code.
+ */
+
ret = vmw_user_surface_lookup_handle(dev_priv, tfile,
mode_cmd->handle, &surface);
if (ret)
@@ -729,8 +865,8 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
if (!surface->scanout)
goto err_not_scanout;
- ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb,
- mode_cmd->width, mode_cmd->height);
+ ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, surface,
+ &vfb, mode_cmd);
/* vmw_user_surface_lookup takes one ref so does new_fb */
vmw_surface_unreference(&surface);
@@ -751,7 +887,7 @@ try_dmabuf:
}
ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb,
- mode_cmd->width, mode_cmd->height);
+ mode_cmd);
/* vmw_user_dmabuf_lookup takes one ref so does new_fb */
vmw_dmabuf_unreference(&bo);
@@ -889,6 +1025,9 @@ int vmw_kms_save_vga(struct vmw_private *vmw_priv)
vmw_priv->num_displays = vmw_read(vmw_priv,
SVGA_REG_NUM_GUEST_DISPLAYS);
+ if (vmw_priv->num_displays == 0)
+ vmw_priv->num_displays = 1;
+
for (i = 0; i < vmw_priv->num_displays; ++i) {
save = &vmw_priv->vga_save[i];
vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, i);
@@ -997,6 +1136,13 @@ out_unlock:
return ret;
}
+bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv,
+ uint32_t pitch,
+ uint32_t height)
+{
+ return ((u64) pitch * (u64) height) < (u64) dev_priv->vram_size;
+}
+
u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc)
{
return 0;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 11cb39e3accb..a01c47ddb5bc 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -427,7 +427,9 @@ static int vmw_ldu_connector_fill_modes(struct drm_connector *connector,
{
struct vmw_legacy_display_unit *ldu = vmw_connector_to_ldu(connector);
struct drm_device *dev = connector->dev;
+ struct vmw_private *dev_priv = vmw_priv(dev);
struct drm_display_mode *mode = NULL;
+ struct drm_display_mode *bmode;
struct drm_display_mode prefmode = { DRM_MODE("preferred",
DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -443,22 +445,30 @@ static int vmw_ldu_connector_fill_modes(struct drm_connector *connector,
mode->hdisplay = ldu->pref_width;
mode->vdisplay = ldu->pref_height;
mode->vrefresh = drm_mode_vrefresh(mode);
- drm_mode_probed_add(connector, mode);
+ if (vmw_kms_validate_mode_vram(dev_priv, mode->hdisplay * 2,
+ mode->vdisplay)) {
+ drm_mode_probed_add(connector, mode);
- if (ldu->pref_mode) {
- list_del_init(&ldu->pref_mode->head);
- drm_mode_destroy(dev, ldu->pref_mode);
- }
+ if (ldu->pref_mode) {
+ list_del_init(&ldu->pref_mode->head);
+ drm_mode_destroy(dev, ldu->pref_mode);
+ }
- ldu->pref_mode = mode;
+ ldu->pref_mode = mode;
+ }
}
for (i = 0; vmw_ldu_connector_builtin[i].type != 0; i++) {
- if (vmw_ldu_connector_builtin[i].hdisplay > max_width ||
- vmw_ldu_connector_builtin[i].vdisplay > max_height)
+ bmode = &vmw_ldu_connector_builtin[i];
+ if (bmode->hdisplay > max_width ||
+ bmode->vdisplay > max_height)
+ continue;
+
+ if (!vmw_kms_validate_mode_vram(dev_priv, bmode->hdisplay * 2,
+ bmode->vdisplay))
continue;
- mode = drm_mode_duplicate(dev, &vmw_ldu_connector_builtin[i]);
+ mode = drm_mode_duplicate(dev, bmode);
if (!mode)
return 0;
mode->vrefresh = drm_mode_vrefresh(mode);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index c8c40e9979db..36e129f0023f 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -765,28 +765,11 @@ static size_t vmw_dmabuf_acc_size(struct ttm_bo_global *glob,
return bo_user_size + page_array_size;
}
-void vmw_dmabuf_gmr_unbind(struct ttm_buffer_object *bo)
-{
- struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
- struct ttm_bo_global *glob = bo->glob;
- struct vmw_private *dev_priv =
- container_of(bo->bdev, struct vmw_private, bdev);
-
- if (vmw_bo->gmr_bound) {
- vmw_gmr_unbind(dev_priv, vmw_bo->gmr_id);
- spin_lock(&glob->lru_lock);
- ida_remove(&dev_priv->gmr_ida, vmw_bo->gmr_id);
- spin_unlock(&glob->lru_lock);
- vmw_bo->gmr_bound = false;
- }
-}
-
void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo)
{
struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
struct ttm_bo_global *glob = bo->glob;
- vmw_dmabuf_gmr_unbind(bo);
ttm_mem_global_free(glob->mem_glob, bo->acc_size);
kfree(vmw_bo);
}
@@ -818,10 +801,7 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv,
memset(vmw_bo, 0, sizeof(*vmw_bo));
- INIT_LIST_HEAD(&vmw_bo->gmr_lru);
INIT_LIST_HEAD(&vmw_bo->validate_list);
- vmw_bo->gmr_id = 0;
- vmw_bo->gmr_bound = false;
ret = ttm_bo_init(bdev, &vmw_bo->base, size,
ttm_bo_type_device, placement,
@@ -835,7 +815,6 @@ static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo)
struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo);
struct ttm_bo_global *glob = bo->glob;
- vmw_dmabuf_gmr_unbind(bo);
ttm_mem_global_free(glob->mem_glob, bo->acc_size);
kfree(vmw_user_bo);
}
@@ -938,25 +917,6 @@ void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo)
vmw_bo->on_validate_list = false;
}
-uint32_t vmw_dmabuf_gmr(struct ttm_buffer_object *bo)
-{
- struct vmw_dma_buffer *vmw_bo;
-
- if (bo->mem.mem_type == TTM_PL_VRAM)
- return SVGA_GMR_FRAMEBUFFER;
-
- vmw_bo = vmw_dma_buffer(bo);
-
- return (vmw_bo->gmr_bound) ? vmw_bo->gmr_id : SVGA_GMR_NULL;
-}
-
-void vmw_dmabuf_set_gmr(struct ttm_buffer_object *bo, uint32_t id)
-{
- struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
- vmw_bo->gmr_bound = true;
- vmw_bo->gmr_id = id;
-}
-
int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
uint32_t handle, struct vmw_dma_buffer **out)
{
@@ -985,41 +945,6 @@ int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
return 0;
}
-/**
- * TODO: Implement a gmr id eviction mechanism. Currently we just fail
- * when we're out of ids, causing GMR space to be allocated
- * out of VRAM.
- */
-
-int vmw_gmr_id_alloc(struct vmw_private *dev_priv, uint32_t *p_id)
-{
- struct ttm_bo_global *glob = dev_priv->bdev.glob;
- int id;
- int ret;
-
- do {
- if (unlikely(ida_pre_get(&dev_priv->gmr_ida, GFP_KERNEL) == 0))
- return -ENOMEM;
-
- spin_lock(&glob->lru_lock);
- ret = ida_get_new(&dev_priv->gmr_ida, &id);
- spin_unlock(&glob->lru_lock);
- } while (ret == -EAGAIN);
-
- if (unlikely(ret != 0))
- return ret;
-
- if (unlikely(id >= dev_priv->max_gmr_ids)) {
- spin_lock(&glob->lru_lock);
- ida_remove(&dev_priv->gmr_ida, id);
- spin_unlock(&glob->lru_lock);
- return -EBUSY;
- }
-
- *p_id = (uint32_t) id;
- return 0;
-}
-
/*
* Stream management
*/
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
index 83123287c60c..1e8eedd901e0 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
@@ -39,7 +39,7 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma)
return drm_mmap(filp, vma);
}
- file_priv = (struct drm_file *)filp->private_data;
+ file_priv = filp->private_data;
dev_priv = vmw_priv(file_priv->minor->dev);
return ttm_bo_mmap(filp, vma, &dev_priv->bdev);
}
diff --git a/drivers/gpu/stub/Kconfig b/drivers/gpu/stub/Kconfig
new file mode 100644
index 000000000000..742c423567cf
--- /dev/null
+++ b/drivers/gpu/stub/Kconfig
@@ -0,0 +1,13 @@
+config STUB_POULSBO
+ tristate "Intel GMA500 Stub Driver"
+ depends on PCI
+ # Poulsbo stub depends on ACPI_VIDEO when ACPI is enabled
+ # but for select to work, need to select ACPI_VIDEO's dependencies, ick
+ select ACPI_VIDEO if ACPI
+ help
+ Choose this option if you have a system that has Intel GMA500
+ (Poulsbo) integrated graphics. If M is selected, the module will
+ be called Poulsbo. This driver is a stub driver for Poulsbo that
+ will call poulsbo.ko to enable the acpi backlight control sysfs
+ entry file because there have no poulsbo native driver can support
+ intel opregion.
diff --git a/drivers/gpu/stub/Makefile b/drivers/gpu/stub/Makefile
new file mode 100644
index 000000000000..cd940cc9d36d
--- /dev/null
+++ b/drivers/gpu/stub/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_STUB_POULSBO) += poulsbo.o
diff --git a/drivers/gpu/stub/poulsbo.c b/drivers/gpu/stub/poulsbo.c
new file mode 100644
index 000000000000..7edfd27b8dee
--- /dev/null
+++ b/drivers/gpu/stub/poulsbo.c
@@ -0,0 +1,64 @@
+/*
+ * Intel Poulsbo Stub driver
+ *
+ * Copyright (C) 2010 Novell <jlee@novell.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/module.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <acpi/video.h>
+
+#define DRIVER_NAME "poulsbo"
+
+enum {
+ CHIP_PSB_8108 = 0,
+ CHIP_PSB_8109 = 1,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
+ {0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PSB_8108}, \
+ {0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PSB_8109}, \
+ {0, 0, 0}
+};
+
+static int poulsbo_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ return acpi_video_register();
+}
+
+static void poulsbo_remove(struct pci_dev *pdev)
+{
+ acpi_video_unregister();
+}
+
+static struct pci_driver poulsbo_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pciidlist,
+ .probe = poulsbo_probe,
+ .remove = poulsbo_remove,
+};
+
+static int __init poulsbo_init(void)
+{
+ return pci_register_driver(&poulsbo_driver);
+}
+
+static void __exit poulsbo_exit(void)
+{
+ pci_unregister_driver(&poulsbo_driver);
+}
+
+module_init(poulsbo_init);
+module_exit(poulsbo_exit);
+
+MODULE_AUTHOR("Lee, Chun-Yi <jlee@novell.com>");
+MODULE_DESCRIPTION("Poulsbo Stub Driver");
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(pci, pciidlist);
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 6369ba7f96f8..3052e2969ad0 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -56,20 +56,20 @@ menu "Special HID drivers"
depends on HID
config HID_3M_PCT
- tristate "3M PCT"
+ tristate "3M PCT touchscreen"
depends on USB_HID
---help---
Support for 3M PCT touch screens.
config HID_A4TECH
- tristate "A4 tech" if EMBEDDED
+ tristate "A4 tech mice" if EMBEDDED
depends on USB_HID
default !EMBEDDED
---help---
Support for A4 tech X5 and WOP-35 / Trust 450L mice.
config HID_ACRUX_FF
- tristate "ACRUX force feedback support"
+ tristate "ACRUX force feedback"
depends on USB_HID
select INPUT_FF_MEMLESS
---help---
@@ -77,7 +77,7 @@ config HID_ACRUX_FF
game controllers.
config HID_APPLE
- tristate "Apple" if EMBEDDED
+ tristate "Apple {i,Power,Mac}Books" if EMBEDDED
depends on (USB_HID || BT_HIDP)
default !EMBEDDED
---help---
@@ -88,7 +88,7 @@ config HID_APPLE
MacBooks, MacBook Pros and Apple Aluminum.
config HID_BELKIN
- tristate "Belkin" if EMBEDDED
+ tristate "Belkin Flip KVM and Wireless keyboard" if EMBEDDED
depends on USB_HID
default !EMBEDDED
---help---
@@ -101,14 +101,14 @@ config HID_CANDO
Support for Cando dual touch panel.
config HID_CHERRY
- tristate "Cherry" if EMBEDDED
+ tristate "Cherry Cymotion keyboard" if EMBEDDED
depends on USB_HID
default !EMBEDDED
---help---
Support for Cherry Cymotion keyboard.
config HID_CHICONY
- tristate "Chicony" if EMBEDDED
+ tristate "Chicony Tactical pad" if EMBEDDED
depends on USB_HID
default !EMBEDDED
---help---
@@ -130,20 +130,20 @@ config HID_PRODIKEYS
and some additional multimedia keys.
config HID_CYPRESS
- tristate "Cypress" if EMBEDDED
+ tristate "Cypress mouse and barcode readers" if EMBEDDED
depends on USB_HID
default !EMBEDDED
---help---
Support for cypress mouse and barcode readers.
config HID_DRAGONRISE
- tristate "DragonRise Inc. support"
+ tristate "DragonRise Inc. game controller"
depends on USB_HID
---help---
Say Y here if you have DragonRise Inc.game controllers.
config DRAGONRISE_FF
- bool "DragonRise Inc. force feedback support"
+ bool "DragonRise Inc. force feedback"
depends on HID_DRAGONRISE
select INPUT_FF_MEMLESS
---help---
@@ -157,46 +157,58 @@ config HID_EGALAX
Support for the eGalax dual-touch panel.
config HID_ELECOM
- tristate "ELECOM"
+ tristate "ELECOM BM084 bluetooth mouse"
depends on BT_HIDP
---help---
Support for the ELECOM BM084 (bluetooth mouse).
config HID_EZKEY
- tristate "Ezkey" if EMBEDDED
+ tristate "Ezkey BTC 8193 keyboard" if EMBEDDED
depends on USB_HID
default !EMBEDDED
---help---
Support for Ezkey BTC 8193 keyboard.
config HID_KYE
- tristate "Kye" if EMBEDDED
+ tristate "Kye/Genius Ergo Mouse" if EMBEDDED
depends on USB_HID
default !EMBEDDED
---help---
Support for Kye/Genius Ergo Mouse.
+config HID_UCLOGIC
+ tristate "UC-Logic"
+ depends on USB_HID
+ ---help---
+ Support for UC-Logic tablets.
+
+config HID_WALTOP
+ tristate "Waltop"
+ depends on USB_HID
+ ---help---
+ Support for Waltop tablets.
+
config HID_GYRATION
- tristate "Gyration"
+ tristate "Gyration remote control"
depends on USB_HID
---help---
Support for Gyration remote control.
config HID_TWINHAN
- tristate "Twinhan"
+ tristate "Twinhan IR remote control"
depends on USB_HID
---help---
Support for Twinhan IR remote control.
config HID_KENSINGTON
- tristate "Kensington" if EMBEDDED
+ tristate "Kensington Slimblade Trackball" if EMBEDDED
depends on USB_HID
default !EMBEDDED
---help---
Support for Kensington Slimblade Trackball.
config HID_LOGITECH
- tristate "Logitech" if EMBEDDED
+ tristate "Logitech devices" if EMBEDDED
depends on USB_HID
default !EMBEDDED
---help---
@@ -220,12 +232,12 @@ config LOGITECH_FF
force feedback.
config LOGIRUMBLEPAD2_FF
- bool "Logitech Rumblepad 2 force feedback support"
+ bool "Logitech RumblePad/Rumblepad 2 force feedback support"
depends on HID_LOGITECH
select INPUT_FF_MEMLESS
help
Say Y here if you want to enable force feedback support for Logitech
- Rumblepad 2 devices.
+ RumblePad and Rumblepad 2 devices.
config LOGIG940_FF
bool "Logitech Flight System G940 force feedback support"
@@ -235,6 +247,14 @@ 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"
+ depends on HID_LOGITECH
+ select INPUT_FF_MEMLESS
+ help
+ Say Y here if you want to enable force feedback support for Logitech
+ Speed Force Wireless (Wii) devices.
+
config HID_MAGICMOUSE
tristate "Apple MagicMouse multi-touch support"
depends on BT_HIDP
@@ -245,39 +265,39 @@ config HID_MAGICMOUSE
Apple Wireless "Magic" Mouse.
config HID_MICROSOFT
- tristate "Microsoft" if EMBEDDED
+ tristate "Microsoft non-fully HID-compliant devices" if EMBEDDED
depends on USB_HID
default !EMBEDDED
---help---
Support for Microsoft devices that are not fully compliant with HID standard.
config HID_MOSART
- tristate "MosArt"
+ tristate "MosArt dual-touch panels"
depends on USB_HID
---help---
Support for MosArt dual-touch panels.
config HID_MONTEREY
- tristate "Monterey" if EMBEDDED
+ tristate "Monterey Genius KB29E keyboard" if EMBEDDED
depends on USB_HID
default !EMBEDDED
---help---
Support for Monterey Genius KB29E.
config HID_NTRIG
- tristate "NTrig"
+ tristate "N-Trig touch screen"
depends on USB_HID
---help---
Support for N-Trig touch screen.
config HID_ORTEK
- tristate "Ortek"
+ tristate "Ortek WKB-2000 wireless keyboard and mouse trackpad"
depends on USB_HID
---help---
Support for Ortek WKB-2000 wireless keyboard + mouse trackpad.
config HID_PANTHERLORD
- tristate "Pantherlord support"
+ tristate "Pantherlord/GreenAsia game controller"
depends on USB_HID
---help---
Say Y here if you have a PantherLord/GreenAsia based game controller
@@ -292,7 +312,7 @@ config PANTHERLORD_FF
or adapter and want to enable force feedback support for it.
config HID_PETALYNX
- tristate "Petalynx"
+ tristate "Petalynx Maxter remote control"
depends on USB_HID
---help---
Support for Petalynx Maxter remote control.
@@ -356,7 +376,7 @@ config HID_PICOLCD_LEDS
Provide access to PicoLCD's GPO pins via leds class.
config HID_QUANTA
- tristate "Quanta Optical Touch"
+ tristate "Quanta Optical Touch panels"
depends on USB_HID
---help---
Support for Quanta Optical Touch dual-touch panels.
@@ -376,32 +396,39 @@ config HID_ROCCAT_KONE
---help---
Support for Roccat Kone mouse.
+config HID_ROCCAT_PYRA
+ tristate "Roccat Pyra mouse support"
+ depends on USB_HID
+ select HID_ROCCAT
+ ---help---
+ Support for Roccat Pyra mouse.
+
config HID_SAMSUNG
- tristate "Samsung"
+ tristate "Samsung InfraRed remote control or keyboards"
depends on USB_HID
---help---
Support for Samsung InfraRed remote control or keyboards.
config HID_SONY
- tristate "Sony"
+ tristate "Sony PS3 controller"
depends on USB_HID
---help---
Support for Sony PS3 controller.
config HID_STANTUM
- tristate "Stantum"
+ tristate "Stantum multitouch panel"
depends on USB_HID
---help---
Support for Stantum multitouch panel.
config HID_SUNPLUS
- tristate "Sunplus"
+ tristate "Sunplus wireless desktop"
depends on USB_HID
---help---
Support for Sunplus wireless desktop.
config HID_GREENASIA
- tristate "GreenAsia (Product ID 0x12) support"
+ tristate "GreenAsia (Product ID 0x12) game controller support"
depends on USB_HID
---help---
Say Y here if you have a GreenAsia (Product ID 0x12) based game
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 46f037f3df80..c335605b9200 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -21,6 +21,9 @@ endif
ifdef CONFIG_LOGIG940_FF
hid-logitech-objs += hid-lg3ff.o
endif
+ifdef CONFIG_LOGIWII_FF
+ hid-logitech-objs += hid-lg4ff.o
+endif
obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
@@ -52,6 +55,7 @@ obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o
obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o
+obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
obj-$(CONFIG_HID_SONY) += hid-sony.o
@@ -61,9 +65,11 @@ obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o
obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o
+obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o
obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o
obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
obj-$(CONFIG_HID_WACOM) += hid-wacom.o
+obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/
diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c
index 2a0d56b7a02b..02d8cd3b1b1b 100644
--- a/drivers/hid/hid-3m-pct.c
+++ b/drivers/hid/hid-3m-pct.c
@@ -2,6 +2,8 @@
* HID driver for 3M PCT multitouch panels
*
* Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
+ * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
+ * Copyright (c) 2010 Canonical, Ltd.
*
*/
@@ -24,15 +26,26 @@ MODULE_LICENSE("GPL");
#include "hid-ids.h"
+#define MAX_SLOTS 60
+#define MAX_TRKID USHRT_MAX
+#define MAX_EVENTS 360
+
+/* estimated signal-to-noise ratios */
+#define SN_MOVE 2048
+#define SN_WIDTH 128
+
struct mmm_finger {
__s32 x, y, w, h;
- __u8 rank;
+ __u16 id;
+ bool prev_touch;
bool touch, valid;
};
struct mmm_data {
- struct mmm_finger f[10];
- __u8 curid, num;
+ struct mmm_finger f[MAX_SLOTS];
+ __u16 id;
+ __u8 curid;
+ __u8 nexp, nreal;
bool touch, valid;
};
@@ -40,6 +53,10 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
+ int f1 = field->logical_minimum;
+ int f2 = field->logical_maximum;
+ int df = f2 - f1;
+
switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_BUTTON:
@@ -50,18 +67,20 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_GD_X:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_X);
+ input_set_abs_params(hi->input, ABS_MT_POSITION_X,
+ f1, f2, df / SN_MOVE, 0);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_X,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
+ f1, f2, df / SN_MOVE, 0);
return 1;
case HID_GD_Y:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_Y);
+ input_set_abs_params(hi->input, ABS_MT_POSITION_Y,
+ f1, f2, df / SN_MOVE, 0);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_Y,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
+ f1, f2, df / SN_MOVE, 0);
return 1;
}
return 0;
@@ -81,21 +100,31 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_TIPSWITCH:
/* touchscreen emulation */
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+ input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
return 1;
case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MAJOR);
+ input_set_abs_params(hi->input, ABS_MT_TOUCH_MAJOR,
+ f1, f2, df / SN_WIDTH, 0);
return 1;
case HID_DG_HEIGHT:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MINOR);
+ input_set_abs_params(hi->input, ABS_MT_TOUCH_MINOR,
+ f1, f2, df / SN_WIDTH, 0);
input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
- 1, 1, 0, 0);
+ 0, 1, 0, 0);
return 1;
case HID_DG_CONTACTID:
- field->logical_maximum = 59;
+ field->logical_maximum = MAX_TRKID;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TRACKING_ID);
+ input_set_abs_params(hi->input, ABS_MT_TRACKING_ID,
+ 0, MAX_TRKID, 0, 0);
+ if (!hi->input->mt)
+ input_mt_create_slots(hi->input, MAX_SLOTS);
+ input_set_events_per_packet(hi->input, MAX_EVENTS);
return 1;
}
/* let hid-input decide for the others */
@@ -113,10 +142,10 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
+ /* tell hid-input to skip setup of these event types */
if (usage->type == EV_KEY || usage->type == EV_ABS)
- clear_bit(usage->code, *bit);
-
- return 0;
+ set_bit(usage->type, hi->input->evbit);
+ return -1;
}
/*
@@ -126,70 +155,49 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
{
struct mmm_finger *oldest = 0;
- bool pressed = false, released = false;
int i;
-
- /*
- * we need to iterate on all fingers to decide if we have a press
- * or a release event in our touchscreen emulation.
- */
- for (i = 0; i < 10; ++i) {
+ for (i = 0; i < MAX_SLOTS; ++i) {
struct mmm_finger *f = &md->f[i];
if (!f->valid) {
/* this finger is just placeholder data, ignore */
- } else if (f->touch) {
+ continue;
+ }
+ input_mt_slot(input, i);
+ if (f->touch) {
/* this finger is on the screen */
int wide = (f->w > f->h);
- input_event(input, EV_ABS, ABS_MT_TRACKING_ID, i);
+ /* divided by two to match visual scale of touch */
+ int major = max(f->w, f->h) >> 1;
+ int minor = min(f->w, f->h) >> 1;
+
+ if (!f->prev_touch)
+ f->id = md->id++;
+ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id);
input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
- input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR,
- wide ? f->w : f->h);
- input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR,
- wide ? f->h : f->w);
- input_mt_sync(input);
- /*
- * touchscreen emulation: maintain the age rank
- * of this finger, decide if we have a press
- */
- if (f->rank == 0) {
- f->rank = ++(md->num);
- if (f->rank == 1)
- pressed = true;
- }
- if (f->rank == 1)
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
+ /* touchscreen emulation: pick the oldest contact */
+ if (!oldest || ((f->id - oldest->id) & (SHRT_MAX + 1)))
oldest = f;
} else {
/* this finger took off the screen */
- /* touchscreen emulation: maintain age rank of others */
- int j;
-
- for (j = 0; j < 10; ++j) {
- struct mmm_finger *g = &md->f[j];
- if (g->rank > f->rank) {
- g->rank--;
- if (g->rank == 1)
- oldest = g;
- }
- }
- f->rank = 0;
- --(md->num);
- if (md->num == 0)
- released = true;
+ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1);
}
+ f->prev_touch = f->touch;
f->valid = 0;
}
/* touchscreen emulation */
if (oldest) {
- if (pressed)
- input_event(input, EV_KEY, BTN_TOUCH, 1);
+ input_event(input, EV_KEY, BTN_TOUCH, 1);
input_event(input, EV_ABS, ABS_X, oldest->x);
input_event(input, EV_ABS, ABS_Y, oldest->y);
- } else if (released) {
+ } else {
input_event(input, EV_KEY, BTN_TOUCH, 0);
}
+ input_sync(input);
}
/*
@@ -223,10 +231,12 @@ static int mmm_event(struct hid_device *hid, struct hid_field *field,
md->f[md->curid].h = value;
break;
case HID_DG_CONTACTID:
+ value = clamp_val(value, 0, MAX_SLOTS - 1);
if (md->valid) {
md->curid = value;
md->f[value].touch = md->touch;
md->f[value].valid = 1;
+ md->nreal++;
}
break;
case HID_GD_X:
@@ -238,7 +248,12 @@ static int mmm_event(struct hid_device *hid, struct hid_field *field,
md->f[md->curid].y = value;
break;
case HID_DG_CONTACTCOUNT:
- mmm_filter_event(md, input);
+ if (value)
+ md->nexp = value;
+ if (md->nreal >= md->nexp) {
+ mmm_filter_event(md, input);
+ md->nreal = 0;
+ }
break;
}
}
@@ -255,6 +270,8 @@ static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id)
int ret;
struct mmm_data *md;
+ hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
+
md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL);
if (!md) {
dev_err(&hdev->dev, "cannot allocate 3M data\n");
diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c
index 3a2b223c1da4..1666c1684e79 100644
--- a/drivers/hid/hid-a4tech.c
+++ b/drivers/hid/hid-a4tech.c
@@ -133,6 +133,8 @@ static const struct hid_device_id a4_devices[] = {
.driver_data = A4_2WHEEL_MOUSE_HACK_7 },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D),
.driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
+ { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649),
+ .driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
{ }
};
MODULE_DEVICE_TABLE(hid, a4_devices);
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index bba05d0a8980..eaeca564a8d3 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -246,17 +246,18 @@ static int apple_event(struct hid_device *hdev, struct hid_field *field,
/*
* MacBook JIS keyboard has wrong logical maximum
*/
-static void apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
struct apple_sc *asc = hid_get_drvdata(hdev);
- if ((asc->quirks & APPLE_RDESC_JIS) && rsize >= 60 &&
+ if ((asc->quirks & APPLE_RDESC_JIS) && *rsize >= 60 &&
rdesc[53] == 0x65 && rdesc[59] == 0x65) {
dev_info(&hdev->dev, "fixing up MacBook JIS keyboard report "
"descriptor\n");
rdesc[53] = rdesc[59] = 0xe7;
}
+ return rdesc;
}
static void apple_setup_input(struct input_dev *input)
diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c
index 24663a8717b1..e880086c2311 100644
--- a/drivers/hid/hid-cherry.c
+++ b/drivers/hid/hid-cherry.c
@@ -26,15 +26,16 @@
* Cherry Cymotion keyboard have an invalid HID report descriptor,
* that needs fixing before we can parse it.
*/
-static void ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
- if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
+ if (*rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
dev_info(&hdev->dev, "fixing up Cherry Cymotion report "
"descriptor\n");
rdesc[11] = rdesc[16] = 0xff;
rdesc[12] = rdesc[17] = 0x03;
}
+ return rdesc;
}
#define ch_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 3cb6632d4518..515345b11ac9 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -388,12 +388,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
__u32 data;
unsigned n;
- /* Local delimiter could have value 0, which allows size to be 0 */
- if (item->size == 0 && item->tag != HID_LOCAL_ITEM_TAG_DELIMITER) {
- dbg_hid("item data expected for local item\n");
- return -1;
- }
-
data = item_udata(item);
switch (item->tag) {
@@ -651,7 +645,7 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
};
if (device->driver->report_fixup)
- device->driver->report_fixup(device, start, size);
+ start = device->driver->report_fixup(device, start, &size);
device->rdesc = kmemdup(start, size, GFP_KERNEL);
if (device->rdesc == NULL)
@@ -1241,6 +1235,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
#if defined(CONFIG_HID_ACRUX_FF) || defined(CONFIG_HID_ACRUX_FF_MODULE)
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
#endif
@@ -1248,6 +1243,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) },
@@ -1327,6 +1323,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
@@ -1336,6 +1333,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ 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_G25_WHEEL) },
+ { 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) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
@@ -1371,12 +1369,15 @@ static const struct hid_device_id hid_blacklist[] = {
{ 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) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
@@ -1388,8 +1389,16 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
{ 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) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
@@ -1771,6 +1780,11 @@ static bool hid_ignore(struct hid_device *hdev)
hdev->product <= USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST)
return true;
break;
+ case USB_VENDOR_ID_HANWANG:
+ if (hdev->product >= USB_DEVICE_ID_HANWANG_TABLET_FIRST &&
+ hdev->product <= USB_DEVICE_ID_HANWANG_TABLET_LAST)
+ return true;
+ break;
}
if (hdev->type == HID_TYPE_USBMOUSE &&
diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c
index 998b6f443d7d..4cd0e2345991 100644
--- a/drivers/hid/hid-cypress.c
+++ b/drivers/hid/hid-cypress.c
@@ -31,16 +31,16 @@
* Some USB barcode readers from cypress have usage min and usage max in
* the wrong order
*/
-static void cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
unsigned int i;
if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX))
- return;
+ return rdesc;
- for (i = 0; i < rsize - 4; i++)
+ for (i = 0; i < *rsize - 4; i++)
if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) {
__u8 tmp;
@@ -50,6 +50,7 @@ static void cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
rdesc[i + 3] = rdesc[i + 1];
rdesc[i + 1] = tmp;
}
+ return rdesc;
}
static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 61a3e572224a..75c5e23d09d2 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -570,6 +570,8 @@ void hid_debug_event(struct hid_device *hdev, char *buf)
buf[i];
list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE;
}
+
+ wake_up_interruptible(&hdev->debug_wait);
}
EXPORT_SYMBOL_GPL(hid_debug_event);
diff --git a/drivers/hid/hid-egalax.c b/drivers/hid/hid-egalax.c
index 8ca7f65cf2f8..54b017ad258d 100644
--- a/drivers/hid/hid-egalax.c
+++ b/drivers/hid/hid-egalax.c
@@ -31,7 +31,7 @@ struct egalax_data {
bool first; /* is this the first finger in the frame? */
bool valid; /* valid finger data, or just placeholder? */
bool activity; /* at least one active finger previously? */
- __u16 lastx, lasty; /* latest valid (x, y) in the frame */
+ __u16 lastx, lasty, lastz; /* latest valid (x, y, z) in the frame */
};
static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
@@ -79,6 +79,10 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_TIPPRESSURE:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_PRESSURE);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_PRESSURE,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
return 1;
}
return 0;
@@ -109,8 +113,8 @@ static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
if (td->valid) {
/* emit multitouch events */
input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
- input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
- input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x >> 3);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y >> 3);
input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z);
input_mt_sync(input);
@@ -121,6 +125,7 @@ static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
*/
td->lastx = td->x;
td->lasty = td->y;
+ td->lastz = td->z;
}
/*
@@ -129,8 +134,9 @@ static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
* the oldest on the panel, the one we want for single touch
*/
if (!td->first && td->activity) {
- input_event(input, EV_ABS, ABS_X, td->lastx);
- input_event(input, EV_ABS, ABS_Y, td->lasty);
+ input_event(input, EV_ABS, ABS_X, td->lastx >> 3);
+ input_event(input, EV_ABS, ABS_Y, td->lasty >> 3);
+ input_event(input, EV_ABS, ABS_PRESSURE, td->lastz);
}
if (!td->valid) {
diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c
index 7a40878f46b4..6e31f305397d 100644
--- a/drivers/hid/hid-elecom.c
+++ b/drivers/hid/hid-elecom.c
@@ -20,14 +20,15 @@
#include "hid-ids.h"
-static void elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
- if (rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) {
+ if (*rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) {
dev_info(&hdev->dev, "Fixing up Elecom BM084 "
"report descriptor.\n");
rdesc[47] = 0x00;
}
+ return rdesc;
}
static const struct hid_device_id elecom_devices[] = {
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 855aa8e355f4..3341baa86a30 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -25,6 +25,7 @@
#define USB_VENDOR_ID_A4TECH 0x09da
#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006
#define USB_DEVICE_ID_A4TECH_X5_005D 0x000a
+#define USB_DEVICE_ID_A4TECH_RP_649 0x001a
#define USB_VENDOR_ID_AASHIMA 0x06d6
#define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025
@@ -63,6 +64,7 @@
#define USB_VENDOR_ID_APPLE 0x05ac
#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
+#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f
#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214
@@ -142,6 +144,7 @@
#define USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE 0x0051
#define USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE 0x00ff
#define USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK 0x00d3
+#define USB_DEVICE_ID_CH_AXIS_295 0x001c
#define USB_VENDOR_ID_CHERRY 0x046a
#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023
@@ -296,6 +299,10 @@
#define USB_DEVICE_ID_GYRATION_REMOTE_2 0x0003
#define USB_DEVICE_ID_GYRATION_REMOTE_3 0x0008
+#define USB_VENDOR_ID_HANWANG 0x0b57
+#define USB_DEVICE_ID_HANWANG_TABLET_FIRST 0x5000
+#define USB_DEVICE_ID_HANWANG_TABLET_LAST 0x8fff
+
#define USB_VENDOR_ID_HAPP 0x078b
#define USB_DEVICE_ID_UGCI_DRIVING 0x0010
#define USB_DEVICE_ID_UGCI_FLYING 0x0020
@@ -343,6 +350,7 @@
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
#define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD 0xc20a
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211
#define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218
@@ -354,6 +362,7 @@
#define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
#define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299
+#define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c
#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
#define USB_DEVICE_ID_S510_RECEIVER 0xc50c
#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
@@ -466,6 +475,8 @@
#define USB_VENDOR_ID_ROCCAT 0x1e7d
#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
+#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24
+#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6
#define USB_VENDOR_ID_SAITEK 0x06a3
#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
@@ -485,6 +496,12 @@
#define USB_VENDOR_ID_STANTUM 0x1f87
#define USB_DEVICE_ID_MTP 0x0002
+#define USB_VENDOR_ID_STANTUM_STM 0x0483
+#define USB_DEVICE_ID_MTP_STM 0x3261
+
+#define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403
+#define USB_DEVICE_ID_MTP_SITRONIX 0x5001
+
#define USB_VENDOR_ID_SUN 0x0430
#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
@@ -514,8 +531,10 @@
#define USB_VENDOR_ID_UCLOGIC 0x5543
#define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042
-#define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U 0x0003
#define USB_DEVICE_ID_UCLOGIC_TABLET_KNA5 0x6001
+#define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U 0x0003
+#define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004
+#define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005
#define USB_VENDOR_ID_VERNIER 0x08f7
#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001
@@ -527,6 +546,12 @@
#define USB_VENDOR_ID_WACOM 0x056a
#define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81
+#define USB_VENDOR_ID_WALTOP 0x172f
+#define USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH 0x0032
+#define USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH 0x0034
+#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH 0x0501
+#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH 0x0500
+
#define USB_VENDOR_ID_WISEGROUP 0x0925
#define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005
#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 6c03dcc5760a..bb0b3659437b 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -68,39 +68,52 @@ static const struct {
#define map_key_clear(c) hid_map_usage_clear(hidinput, usage, &bit, \
&max, EV_KEY, (c))
-static inline int match_scancode(unsigned int code, unsigned int scancode)
+static bool match_scancode(struct hid_usage *usage,
+ unsigned int cur_idx, unsigned int scancode)
{
- if (scancode == 0)
- return 1;
-
- return (code & (HID_USAGE_PAGE | HID_USAGE)) == scancode;
+ return (usage->hid & (HID_USAGE_PAGE | HID_USAGE)) == scancode;
}
-static inline int match_keycode(unsigned int code, unsigned int keycode)
+static bool match_keycode(struct hid_usage *usage,
+ unsigned int cur_idx, unsigned int keycode)
{
- if (keycode == 0)
- return 1;
+ /*
+ * We should exclude unmapped usages when doing lookup by keycode.
+ */
+ return (usage->type == EV_KEY && usage->code == keycode);
+}
- return code == keycode;
+static bool match_index(struct hid_usage *usage,
+ unsigned int cur_idx, unsigned int idx)
+{
+ return cur_idx == idx;
}
+typedef bool (*hid_usage_cmp_t)(struct hid_usage *usage,
+ unsigned int cur_idx, unsigned int val);
+
static struct hid_usage *hidinput_find_key(struct hid_device *hid,
- unsigned int scancode,
- unsigned int keycode)
+ hid_usage_cmp_t match,
+ unsigned int value,
+ unsigned int *usage_idx)
{
- int i, j, k;
+ unsigned int i, j, k, cur_idx = 0;
struct hid_report *report;
struct hid_usage *usage;
for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
for (i = 0; i < report->maxfield; i++) {
- for ( j = 0; j < report->field[i]->maxusage; j++) {
+ for (j = 0; j < report->field[i]->maxusage; j++) {
usage = report->field[i]->usage + j;
- if (usage->type == EV_KEY &&
- match_scancode(usage->hid, scancode) &&
- match_keycode(usage->code, keycode))
- return usage;
+ if (usage->type == EV_KEY || usage->type == 0) {
+ if (match(usage, cur_idx, value)) {
+ if (usage_idx)
+ *usage_idx = cur_idx;
+ return usage;
+ }
+ cur_idx++;
+ }
}
}
}
@@ -108,39 +121,68 @@ static struct hid_usage *hidinput_find_key(struct hid_device *hid,
return NULL;
}
+static struct hid_usage *hidinput_locate_usage(struct hid_device *hid,
+ const struct input_keymap_entry *ke,
+ unsigned int *index)
+{
+ struct hid_usage *usage;
+ unsigned int scancode;
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX)
+ usage = hidinput_find_key(hid, match_index, ke->index, index);
+ else if (input_scancode_to_scalar(ke, &scancode) == 0)
+ usage = hidinput_find_key(hid, match_scancode, scancode, index);
+ else
+ usage = NULL;
+
+ return usage;
+}
+
static int hidinput_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
+ struct input_keymap_entry *ke)
{
struct hid_device *hid = input_get_drvdata(dev);
struct hid_usage *usage;
+ unsigned int scancode, index;
- usage = hidinput_find_key(hid, scancode, 0);
+ usage = hidinput_locate_usage(hid, ke, &index);
if (usage) {
- *keycode = usage->code;
+ ke->keycode = usage->type == EV_KEY ?
+ usage->code : KEY_RESERVED;
+ ke->index = index;
+ scancode = usage->hid & (HID_USAGE_PAGE | HID_USAGE);
+ ke->len = sizeof(scancode);
+ memcpy(ke->scancode, &scancode, sizeof(scancode));
return 0;
}
+
return -EINVAL;
}
static int hidinput_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode)
{
struct hid_device *hid = input_get_drvdata(dev);
struct hid_usage *usage;
- int old_keycode;
- usage = hidinput_find_key(hid, scancode, 0);
+ usage = hidinput_locate_usage(hid, ke, NULL);
if (usage) {
- old_keycode = usage->code;
- usage->code = keycode;
+ *old_keycode = usage->type == EV_KEY ?
+ usage->code : KEY_RESERVED;
+ usage->code = ke->keycode;
- clear_bit(old_keycode, dev->keybit);
+ clear_bit(*old_keycode, dev->keybit);
set_bit(usage->code, dev->keybit);
- dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
- /* Set the keybit for the old keycode if the old keycode is used
- * by another key */
- if (hidinput_find_key (hid, 0, old_keycode))
- set_bit(old_keycode, dev->keybit);
+ dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n",
+ usage->code, usage->hid);
+
+ /*
+ * Set the keybit for the old keycode if the old keycode is used
+ * by another key
+ */
+ if (hidinput_find_key(hid, match_keycode, *old_keycode, NULL))
+ set_bit(*old_keycode, dev->keybit);
return 0;
}
@@ -149,6 +191,83 @@ static int hidinput_setkeycode(struct input_dev *dev,
}
+/**
+ * hidinput_calc_abs_res - calculate an absolute axis resolution
+ * @field: the HID report field to calculate resolution for
+ * @code: axis code
+ *
+ * The formula is:
+ * (logical_maximum - logical_minimum)
+ * resolution = ----------------------------------------------------------
+ * (physical_maximum - physical_minimum) * 10 ^ unit_exponent
+ *
+ * as seen in the HID specification v1.11 6.2.2.7 Global Items.
+ *
+ * Only exponent 1 length units are processed. Centimeters are converted to
+ * inches. Degrees are converted to radians.
+ */
+static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
+{
+ __s32 unit_exponent = field->unit_exponent;
+ __s32 logical_extents = field->logical_maximum -
+ field->logical_minimum;
+ __s32 physical_extents = field->physical_maximum -
+ field->physical_minimum;
+ __s32 prev;
+
+ /* Check if the extents are sane */
+ if (logical_extents <= 0 || physical_extents <= 0)
+ return 0;
+
+ /*
+ * Verify and convert units.
+ * See HID specification v1.11 6.2.2.7 Global Items for unit decoding
+ */
+ if (code == ABS_X || code == ABS_Y || code == ABS_Z) {
+ if (field->unit == 0x11) { /* If centimeters */
+ /* Convert to inches */
+ prev = logical_extents;
+ logical_extents *= 254;
+ if (logical_extents < prev)
+ return 0;
+ unit_exponent += 2;
+ } else if (field->unit != 0x13) { /* If not inches */
+ return 0;
+ }
+ } else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) {
+ if (field->unit == 0x14) { /* If degrees */
+ /* Convert to radians */
+ prev = logical_extents;
+ logical_extents *= 573;
+ if (logical_extents < prev)
+ return 0;
+ unit_exponent += 1;
+ } else if (field->unit != 0x12) { /* If not radians */
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+
+ /* Apply negative unit exponent */
+ for (; unit_exponent < 0; unit_exponent++) {
+ prev = logical_extents;
+ logical_extents *= 10;
+ if (logical_extents < prev)
+ return 0;
+ }
+ /* Apply positive unit exponent */
+ for (; unit_exponent > 0; unit_exponent--) {
+ prev = physical_extents;
+ physical_extents *= 10;
+ if (physical_extents < prev)
+ return 0;
+ }
+
+ /* Calculate resolution */
+ return logical_extents / physical_extents;
+}
+
static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
struct hid_usage *usage)
{
@@ -336,6 +455,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
map_key_clear(BTN_STYLUS);
break;
+ case 0x46: /* TabletPick */
+ map_key_clear(BTN_STYLUS2);
+ break;
+
default: goto unknown;
}
break;
@@ -537,6 +660,9 @@ mapped:
input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
else input_set_abs_params(input, usage->code, a, b, 0, 0);
+ input_abs_set_res(input, usage->code,
+ hidinput_calc_abs_res(field, usage->code));
+
/* use a larger default input buffer for MT devices */
if (usage->code == ABS_MT_POSITION_X && input->hint_events_per_packet == 0)
input_set_events_per_packet(input, 60);
@@ -659,6 +785,9 @@ void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
{
struct hid_input *hidinput;
+ if (hid->quirks & HID_QUIRK_NO_INPUT_SYNC)
+ return;
+
list_for_each_entry(hidinput, &hid->inputs, list)
input_sync(hidinput->input);
}
@@ -748,8 +877,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
hid->ll_driver->hidinput_input_event;
input_dev->open = hidinput_open;
input_dev->close = hidinput_close;
- input_dev->setkeycode = hidinput_setkeycode;
- input_dev->getkeycode = hidinput_getkeycode;
+ input_dev->setkeycode_new = hidinput_setkeycode;
+ input_dev->getkeycode_new = hidinput_getkeycode;
input_dev->name = hid->name;
input_dev->phys = hid->phys;
diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c
index f8871712b7b5..817247ee006c 100644
--- a/drivers/hid/hid-kye.c
+++ b/drivers/hid/hid-kye.c
@@ -23,10 +23,10 @@
* - report size 8 count 1 must be size 1 count 8 for button bitfield
* - change the button usage range to 4-7 for the extra buttons
*/
-static void kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
- if (rsize >= 74 &&
+ if (*rsize >= 74 &&
rdesc[61] == 0x05 && rdesc[62] == 0x08 &&
rdesc[63] == 0x19 && rdesc[64] == 0x08 &&
rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
@@ -40,6 +40,7 @@ static void kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
rdesc[72] = 0x01;
rdesc[74] = 0x08;
}
+ return rdesc;
}
static const struct hid_device_id kye_devices[] = {
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index f6433d8050a9..b629fba5a057 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -7,6 +7,7 @@
* Copyright (c) 2006-2007 Jiri Kosina
* Copyright (c) 2007 Paul Walmsley
* Copyright (c) 2008 Jiri Slaby
+ * Copyright (c) 2010 Hendrik Iben
*/
/*
@@ -19,6 +20,9 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
#include "hid-ids.h"
#include "hid-lg.h"
@@ -35,31 +39,43 @@
#define LG_FF2 0x400
#define LG_RDESC_REL_ABS 0x800
#define LG_FF3 0x1000
+#define LG_FF4 0x2000
/*
* Certain Logitech keyboards send in report #3 keys which are far
* above the logical maximum described in descriptor. This extends
* the original value of 0x28c of logical maximum to 0x104d
*/
-static void lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
- if ((quirks & LG_RDESC) && rsize >= 90 && rdesc[83] == 0x26 &&
+ if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
rdesc[84] == 0x8c && rdesc[85] == 0x02) {
dev_info(&hdev->dev, "fixing up Logitech keyboard report "
"descriptor\n");
rdesc[84] = rdesc[89] = 0x4d;
rdesc[85] = rdesc[90] = 0x10;
}
- if ((quirks & LG_RDESC_REL_ABS) && rsize >= 50 &&
+ if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
rdesc[49] == 0x81 && rdesc[50] == 0x06) {
dev_info(&hdev->dev, "fixing up rel/abs in Logitech "
"report descriptor\n");
rdesc[33] = rdesc[50] = 0x02;
}
+ if ((quirks & LG_FF4) && *rsize >= 101 &&
+ rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
+ rdesc[47] == 0x05 && rdesc[48] == 0x09) {
+ dev_info(&hdev->dev, "fixing up Logitech Speed Force Wireless "
+ "button descriptor\n");
+ rdesc[41] = 0x05;
+ rdesc[42] = 0x09;
+ rdesc[47] = 0x95;
+ rdesc[48] = 0x0B;
+ }
+ return rdesc;
}
#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
@@ -285,12 +301,33 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free;
}
+ if (quirks & LG_FF4) {
+ 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);
+
+ if (ret >= 0) {
+ /* insert a little delay of 10 jiffies ~ 40ms */
+ wait_queue_head_t wait;
+ init_waitqueue_head (&wait);
+ wait_event_interruptible_timeout(wait, 0, 10);
+
+ /* Select random Address */
+ buf[1] = 0xB2;
+ get_random_bytes(&buf[2], 2);
+
+ ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
+ }
+ }
+
if (quirks & LG_FF)
lgff_init(hdev);
if (quirks & LG_FF2)
lg2ff_init(hdev);
if (quirks & LG_FF3)
lg3ff_init(hdev);
+ if (quirks & LG_FF4)
+ lg4ff_init(hdev);
return 0;
err_free:
@@ -325,6 +362,8 @@ static const struct hid_device_id lg_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
.driver_data = LG_NOGET | LG_FF },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
+ .driver_data = LG_FF2 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
@@ -339,6 +378,8 @@ static const struct hid_device_id lg_devices[] = {
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
.driver_data = LG_FF },
+ { 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 ),
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h
index ce2ac8672624..b0100ba2ae0b 100644
--- a/drivers/hid/hid-lg.h
+++ b/drivers/hid/hid-lg.h
@@ -19,4 +19,10 @@ int lg3ff_init(struct hid_device *hdev);
static inline int lg3ff_init(struct hid_device *hdev) { return -1; }
#endif
+#ifdef CONFIG_LOGIWII_FF
+int lg4ff_init(struct hid_device *hdev);
+#else
+static inline int lg4ff_init(struct hid_device *hdev) { return -1; }
+#endif
+
#endif
diff --git a/drivers/hid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c
index d888f1e6794f..4258253c36b3 100644
--- a/drivers/hid/hid-lg2ff.c
+++ b/drivers/hid/hid-lg2ff.c
@@ -1,5 +1,5 @@
/*
- * Force feedback support for Logitech Rumblepad 2
+ * Force feedback support for Logitech RumblePad and Rumblepad 2
*
* Copyright (c) 2008 Anssi Hannula <anssi.hannula@gmail.com>
*/
@@ -110,7 +110,7 @@ int lg2ff_init(struct hid_device *hid)
usbhid_submit_report(hid, report, USB_DIR_OUT);
- dev_info(&hid->dev, "Force feedback for Logitech Rumblepad 2 by "
+ dev_info(&hid->dev, "Force feedback for Logitech RumblePad/Rumblepad 2 by "
"Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0;
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
new file mode 100644
index 000000000000..7eef5a2ce948
--- /dev/null
+++ b/drivers/hid/hid-lg4ff.c
@@ -0,0 +1,136 @@
+/*
+ * Force feedback support for Logitech Speed Force Wireless
+ *
+ * http://wiibrew.org/wiki/Logitech_USB_steering_wheel
+ *
+ * Copyright (c) 2010 Simon Wood <simon@mungewell.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/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+
+#include "usbhid/usbhid.h"
+#include "hid-lg.h"
+
+struct lg4ff_device {
+ struct hid_report *report;
+};
+
+static const signed short ff4_wheel_ac[] = {
+ FF_CONSTANT,
+ FF_AUTOCENTER,
+ -1
+};
+
+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;
+ struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+ int x;
+
+#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
+
+ switch (effect->type) {
+ case FF_CONSTANT:
+ 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[2] = x;
+ report->field[0]->value[3] = 0x00;
+ report->field[0]->value[4] = 0x00;
+ report->field[0]->value[5] = 0x08;
+ report->field[0]->value[6] = 0x00;
+ dbg_hid("Autocenter, x=0x%02X\n", x);
+
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+ break;
+ }
+ return 0;
+}
+
+static void hid_lg4ff_set_autocenter(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;
+
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+}
+
+
+int lg4ff_init(struct hid_device *hid)
+{
+ struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+ struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ 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;
+
+ /* Find the report to use */
+ if (list_empty(report_list)) {
+ err_hid("No output report found");
+ return -1;
+ }
+
+ /* Check that the report looks ok */
+ report = list_entry(report_list->next, struct hid_report, list);
+ if (!report) {
+ err_hid("NULL output report");
+ return -1;
+ }
+
+ field = report->field[0];
+ if (!field) {
+ err_hid("NULL field");
+ return -1;
+ }
+
+ for (i = 0; ff_bits[i] >= 0; i++)
+ set_bit(ff_bits[i], 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;
+
+ dev_info(&hid->dev, "Force feedback for Logitech Speed Force Wireless by "
+ "Simon Wood <simon@mungewell.org>\n");
+ return 0;
+}
+
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 319b0e57ee41..e6dc15171664 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -2,6 +2,7 @@
* Apple "Magic" Wireless Mouse driver
*
* Copyright (c) 2010 Michael Poole <mdpoole@troilus.org>
+ * Copyright (c) 2010 Chase Douglas <chase.douglas@canonical.com>
*/
/*
@@ -53,7 +54,9 @@ static bool report_undeciphered;
module_param(report_undeciphered, bool, 0644);
MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event");
-#define TOUCH_REPORT_ID 0x29
+#define TRACKPAD_REPORT_ID 0x28
+#define MOUSE_REPORT_ID 0x29
+#define DOUBLE_REPORT_ID 0xf7
/* These definitions are not precise, but they're close enough. (Bits
* 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem
* to be some kind of bit mask -- 0x20 may be a near-field reading,
@@ -67,15 +70,19 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
#define SCROLL_ACCEL_DEFAULT 7
+/* Single touch emulation should only begin when no touches are currently down.
+ * This is true when single_touch_id is equal to NO_TOUCHES. If multiple touches
+ * are down and the touch providing for single touch emulation is lifted,
+ * single_touch_id is equal to SINGLE_TOUCH_UP. While single touch emulation is
+ * occuring, single_touch_id corresponds with the tracking id of the touch used.
+ */
+#define NO_TOUCHES -1
+#define SINGLE_TOUCH_UP -2
+
/**
* struct magicmouse_sc - Tracks Magic Mouse-specific data.
* @input: Input device through which we report events.
* @quirks: Currently unused.
- * @last_timestamp: Timestamp from most recent (18-bit) touch report
- * (units of milliseconds over short windows, but seems to
- * increase faster when there are no touches).
- * @delta_time: 18-bit difference between the two most recent touch
- * reports from the mouse.
* @ntouches: Number of touches in most recent touch report.
* @scroll_accel: Number of consecutive scroll motions.
* @scroll_jiffies: Time of last scroll motion.
@@ -86,8 +93,6 @@ struct magicmouse_sc {
struct input_dev *input;
unsigned long quirks;
- int last_timestamp;
- int delta_time;
int ntouches;
int scroll_accel;
unsigned long scroll_jiffies;
@@ -98,9 +103,9 @@ struct magicmouse_sc {
short scroll_x;
short scroll_y;
u8 size;
- u8 down;
} touches[16];
int tracking_ids[16];
+ int single_touch_id;
};
static int magicmouse_firm_touch(struct magicmouse_sc *msc)
@@ -166,18 +171,35 @@ static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state)
static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata)
{
struct input_dev *input = msc->input;
- __s32 x_y = tdata[0] << 8 | tdata[1] << 16 | tdata[2] << 24;
- int misc = tdata[5] | tdata[6] << 8;
- int id = (misc >> 6) & 15;
- int x = x_y << 12 >> 20;
- int y = -(x_y >> 20);
- int down = (tdata[7] & TOUCH_STATE_MASK) != TOUCH_STATE_NONE;
+ int id, x, y, size, orientation, touch_major, touch_minor, state, down;
+
+ if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+ id = (tdata[6] << 2 | tdata[5] >> 6) & 0xf;
+ x = (tdata[1] << 28 | tdata[0] << 20) >> 20;
+ y = -((tdata[2] << 24 | tdata[1] << 16) >> 20);
+ size = tdata[5] & 0x3f;
+ orientation = (tdata[6] >> 2) - 32;
+ touch_major = tdata[3];
+ touch_minor = tdata[4];
+ state = tdata[7] & TOUCH_STATE_MASK;
+ down = state != TOUCH_STATE_NONE;
+ } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+ id = (tdata[7] << 2 | tdata[6] >> 6) & 0xf;
+ x = (tdata[1] << 27 | tdata[0] << 19) >> 19;
+ y = -((tdata[3] << 30 | tdata[2] << 22 | tdata[1] << 14) >> 19);
+ size = tdata[6] & 0x3f;
+ orientation = (tdata[7] >> 2) - 32;
+ touch_major = tdata[4];
+ touch_minor = tdata[5];
+ state = tdata[8] & TOUCH_STATE_MASK;
+ down = state != TOUCH_STATE_NONE;
+ }
/* Store tracking ID and other fields. */
msc->tracking_ids[raw_id] = id;
msc->touches[id].x = x;
msc->touches[id].y = y;
- msc->touches[id].size = misc & 63;
+ msc->touches[id].size = size;
/* If requested, emulate a scroll wheel by detecting small
* vertical touch motions.
@@ -188,7 +210,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
int step_y = msc->touches[id].scroll_y - y;
/* Calculate and apply the scroll motion. */
- switch (tdata[7] & TOUCH_STATE_MASK) {
+ switch (state) {
case TOUCH_STATE_START:
msc->touches[id].scroll_x = x;
msc->touches[id].scroll_y = y;
@@ -222,21 +244,28 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
}
}
+ if (down) {
+ msc->ntouches++;
+ if (msc->single_touch_id == NO_TOUCHES)
+ msc->single_touch_id = id;
+ } else if (msc->single_touch_id == id)
+ msc->single_touch_id = SINGLE_TOUCH_UP;
+
/* Generate the input events for this touch. */
if (report_touches && down) {
- int orientation = (misc >> 10) - 32;
-
- msc->touches[id].down = 1;
-
input_report_abs(input, ABS_MT_TRACKING_ID, id);
- input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]);
- input_report_abs(input, ABS_MT_TOUCH_MINOR, tdata[4]);
+ input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major << 2);
+ input_report_abs(input, ABS_MT_TOUCH_MINOR, touch_minor << 2);
input_report_abs(input, ABS_MT_ORIENTATION, orientation);
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
- if (report_undeciphered)
- input_event(input, EV_MSC, MSC_RAW, tdata[7]);
+ if (report_undeciphered) {
+ if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
+ input_event(input, EV_MSC, MSC_RAW, tdata[7]);
+ else /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+ input_event(input, EV_MSC, MSC_RAW, tdata[8]);
+ }
input_mt_sync(input);
}
@@ -247,39 +276,43 @@ static int magicmouse_raw_event(struct hid_device *hdev,
{
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
struct input_dev *input = msc->input;
- int x, y, ts, ii, clicks, last_up;
+ int x = 0, y = 0, ii, clicks = 0, npoints;
switch (data[0]) {
- case 0x10:
- if (size != 6)
+ case TRACKPAD_REPORT_ID:
+ /* Expect four bytes of prefix, and N*9 bytes of touch data. */
+ if (size < 4 || ((size - 4) % 9) != 0)
return 0;
- x = (__s16)(data[2] | data[3] << 8);
- y = (__s16)(data[4] | data[5] << 8);
+ npoints = (size - 4) / 9;
+ msc->ntouches = 0;
+ for (ii = 0; ii < npoints; ii++)
+ magicmouse_emit_touch(msc, ii, data + ii * 9 + 4);
+
+ /* We don't need an MT sync here because trackpad emits a
+ * BTN_TOUCH event in a new frame when all touches are released.
+ */
+ if (msc->ntouches == 0)
+ msc->single_touch_id = NO_TOUCHES;
+
clicks = data[1];
+
+ /* The following bits provide a device specific timestamp. They
+ * are unused here.
+ *
+ * ts = data[1] >> 6 | data[2] << 2 | data[3] << 10;
+ */
break;
- case TOUCH_REPORT_ID:
+ case MOUSE_REPORT_ID:
/* Expect six bytes of prefix, and N*8 bytes of touch data. */
if (size < 6 || ((size - 6) % 8) != 0)
return 0;
- ts = data[3] >> 6 | data[4] << 2 | data[5] << 10;
- msc->delta_time = (ts - msc->last_timestamp) & 0x3ffff;
- msc->last_timestamp = ts;
- msc->ntouches = (size - 6) / 8;
- for (ii = 0; ii < msc->ntouches; ii++)
+ npoints = (size - 6) / 8;
+ msc->ntouches = 0;
+ for (ii = 0; ii < npoints; ii++)
magicmouse_emit_touch(msc, ii, data + ii * 8 + 6);
- if (report_touches) {
- last_up = 1;
- for (ii = 0; ii < ARRAY_SIZE(msc->touches); ii++) {
- if (msc->touches[ii].down) {
- last_up = 0;
- msc->touches[ii].down = 0;
- }
- }
- if (last_up) {
- input_mt_sync(input);
- }
- }
+ if (report_touches && msc->ntouches == 0)
+ input_mt_sync(input);
/* When emulating three-button mode, it is important
* to have the current touch information before
@@ -288,68 +321,72 @@ static int magicmouse_raw_event(struct hid_device *hdev,
x = (int)(((data[3] & 0x0c) << 28) | (data[1] << 22)) >> 22;
y = (int)(((data[3] & 0x30) << 26) | (data[2] << 22)) >> 22;
clicks = data[3];
+
+ /* The following bits provide a device specific timestamp. They
+ * are unused here.
+ *
+ * ts = data[3] >> 6 | data[4] << 2 | data[5] << 10;
+ */
+ break;
+ case DOUBLE_REPORT_ID:
+ /* Sometimes the trackpad sends two touch reports in one
+ * packet.
+ */
+ magicmouse_raw_event(hdev, report, data + 2, data[1]);
+ magicmouse_raw_event(hdev, report, data + 2 + data[1],
+ size - 2 - data[1]);
break;
- case 0x20: /* Theoretically battery status (0-100), but I have
- * never seen it -- maybe it is only upon request.
- */
- case 0x60: /* Unknown, maybe laser on/off. */
- case 0x61: /* Laser reflection status change.
- * data[1]: 0 = spotted, 1 = lost
- */
default:
return 0;
}
- magicmouse_emit_buttons(msc, clicks & 3);
- input_report_rel(input, REL_X, x);
- input_report_rel(input, REL_Y, y);
+ if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+ magicmouse_emit_buttons(msc, clicks & 3);
+ input_report_rel(input, REL_X, x);
+ input_report_rel(input, REL_Y, y);
+ } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+ input_report_key(input, BTN_MOUSE, clicks & 1);
+ input_report_key(input, BTN_TOUCH, msc->ntouches > 0);
+ input_report_key(input, BTN_TOOL_FINGER, msc->ntouches == 1);
+ input_report_key(input, BTN_TOOL_DOUBLETAP, msc->ntouches == 2);
+ input_report_key(input, BTN_TOOL_TRIPLETAP, msc->ntouches == 3);
+ input_report_key(input, BTN_TOOL_QUADTAP, msc->ntouches == 4);
+ if (msc->single_touch_id >= 0) {
+ input_report_abs(input, ABS_X,
+ msc->touches[msc->single_touch_id].x);
+ input_report_abs(input, ABS_Y,
+ msc->touches[msc->single_touch_id].y);
+ }
+ }
+
input_sync(input);
return 1;
}
-static int magicmouse_input_open(struct input_dev *dev)
-{
- struct hid_device *hid = input_get_drvdata(dev);
-
- return hid->ll_driver->open(hid);
-}
-
-static void magicmouse_input_close(struct input_dev *dev)
-{
- struct hid_device *hid = input_get_drvdata(dev);
-
- hid->ll_driver->close(hid);
-}
-
static void magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev)
{
- input_set_drvdata(input, hdev);
- input->event = hdev->ll_driver->hidinput_input_event;
- input->open = magicmouse_input_open;
- input->close = magicmouse_input_close;
-
- input->name = hdev->name;
- input->phys = hdev->phys;
- input->uniq = hdev->uniq;
- input->id.bustype = hdev->bus;
- input->id.vendor = hdev->vendor;
- input->id.product = hdev->product;
- input->id.version = hdev->version;
- input->dev.parent = hdev->dev.parent;
-
__set_bit(EV_KEY, input->evbit);
- __set_bit(BTN_LEFT, input->keybit);
- __set_bit(BTN_RIGHT, input->keybit);
- if (emulate_3button)
- __set_bit(BTN_MIDDLE, input->keybit);
- __set_bit(BTN_TOOL_FINGER, input->keybit);
-
- __set_bit(EV_REL, input->evbit);
- __set_bit(REL_X, input->relbit);
- __set_bit(REL_Y, input->relbit);
- if (emulate_scroll_wheel) {
- __set_bit(REL_WHEEL, input->relbit);
- __set_bit(REL_HWHEEL, input->relbit);
+
+ if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+ __set_bit(BTN_LEFT, input->keybit);
+ __set_bit(BTN_RIGHT, input->keybit);
+ if (emulate_3button)
+ __set_bit(BTN_MIDDLE, input->keybit);
+
+ __set_bit(EV_REL, input->evbit);
+ __set_bit(REL_X, input->relbit);
+ __set_bit(REL_Y, input->relbit);
+ if (emulate_scroll_wheel) {
+ __set_bit(REL_WHEEL, input->relbit);
+ __set_bit(REL_HWHEEL, input->relbit);
+ }
+ } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+ __set_bit(BTN_MOUSE, input->keybit);
+ __set_bit(BTN_TOOL_FINGER, input->keybit);
+ __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
+ __set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
+ __set_bit(BTN_TOOL_QUADTAP, input->keybit);
+ __set_bit(BTN_TOUCH, input->keybit);
}
if (report_touches) {
@@ -359,16 +396,26 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 4, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 4, 0);
input_set_abs_params(input, ABS_MT_ORIENTATION, -32, 31, 1, 0);
- input_set_abs_params(input, ABS_MT_POSITION_X, -1100, 1358,
- 4, 0);
+
/* Note: Touch Y position from the device is inverted relative
* to how pointer motion is reported (and relative to how USB
* HID recommends the coordinates work). This driver keeps
* the origin at the same position, and just uses the additive
* inverse of the reported Y.
*/
- input_set_abs_params(input, ABS_MT_POSITION_Y, -1589, 2047,
- 4, 0);
+ 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);
+ } 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);
+ }
}
if (report_undeciphered) {
@@ -377,12 +424,22 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
}
}
+static int magicmouse_input_mapping(struct hid_device *hdev,
+ struct hid_input *hi, struct hid_field *field,
+ struct hid_usage *usage, unsigned long **bit, int *max)
+{
+ struct magicmouse_sc *msc = hid_get_drvdata(hdev);
+
+ if (!msc->input)
+ msc->input = hi->input;
+
+ return 0;
+}
+
static int magicmouse_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
- __u8 feature_1[] = { 0xd7, 0x01 };
- __u8 feature_2[] = { 0xf8, 0x01, 0x32 };
- struct input_dev *input;
+ __u8 feature[] = { 0xd7, 0x01 };
struct magicmouse_sc *msc;
struct hid_report *report;
int ret;
@@ -398,6 +455,8 @@ static int magicmouse_probe(struct hid_device *hdev,
msc->quirks = id->driver_data;
hid_set_drvdata(hdev, msc);
+ msc->single_touch_id = NO_TOUCHES;
+
ret = hid_parse(hdev);
if (ret) {
dev_err(&hdev->dev, "magicmouse hid parse failed\n");
@@ -410,10 +469,22 @@ static int magicmouse_probe(struct hid_device *hdev,
goto err_free;
}
- /* we are handling the input ourselves */
- hidinput_disconnect(hdev);
+ /* We do this after hid-input is done parsing reports so that
+ * hid-input uses the most natural button and axis IDs.
+ */
+ if (msc->input)
+ magicmouse_setup_input(msc->input, hdev);
+
+ if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
+ report = hid_register_report(hdev, HID_INPUT_REPORT,
+ MOUSE_REPORT_ID);
+ else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+ report = hid_register_report(hdev, HID_INPUT_REPORT,
+ TRACKPAD_REPORT_ID);
+ report = hid_register_report(hdev, HID_INPUT_REPORT,
+ DOUBLE_REPORT_ID);
+ }
- report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID);
if (!report) {
dev_err(&hdev->dev, "unable to register touch report\n");
ret = -ENOMEM;
@@ -421,39 +492,15 @@ static int magicmouse_probe(struct hid_device *hdev,
}
report->size = 6;
- ret = hdev->hid_output_raw_report(hdev, feature_1, sizeof(feature_1),
+ ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
HID_FEATURE_REPORT);
- if (ret != sizeof(feature_1)) {
- dev_err(&hdev->dev, "unable to request touch data (1:%d)\n",
- ret);
- goto err_stop_hw;
- }
- ret = hdev->hid_output_raw_report(hdev, feature_2,
- sizeof(feature_2), HID_FEATURE_REPORT);
- if (ret != sizeof(feature_2)) {
- dev_err(&hdev->dev, "unable to request touch data (2:%d)\n",
+ if (ret != sizeof(feature)) {
+ dev_err(&hdev->dev, "unable to request touch data (%d)\n",
ret);
goto err_stop_hw;
}
- input = input_allocate_device();
- if (!input) {
- dev_err(&hdev->dev, "can't alloc input device\n");
- ret = -ENOMEM;
- goto err_stop_hw;
- }
- magicmouse_setup_input(input, hdev);
-
- ret = input_register_device(input);
- if (ret) {
- dev_err(&hdev->dev, "input device registration failed\n");
- goto err_input;
- }
- msc->input = input;
-
return 0;
-err_input:
- input_free_device(input);
err_stop_hw:
hid_hw_stop(hdev);
err_free:
@@ -466,13 +513,14 @@ static void magicmouse_remove(struct hid_device *hdev)
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
hid_hw_stop(hdev);
- input_unregister_device(msc->input);
kfree(msc);
}
static const struct hid_device_id magic_mice[] = {
- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE),
- .driver_data = 0 },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+ USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+ USB_DEVICE_ID_APPLE_MAGICTRACKPAD), .driver_data = 0 },
{ }
};
MODULE_DEVICE_TABLE(hid, magic_mice);
@@ -483,6 +531,7 @@ static struct hid_driver magicmouse_driver = {
.probe = magicmouse_probe,
.remove = magicmouse_remove,
.raw_event = magicmouse_raw_event,
+ .input_mapping = magicmouse_input_mapping,
};
static int __init magicmouse_init(void)
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index 359cc447c6c6..dc618c33d0a2 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -33,18 +33,19 @@
* Microsoft Wireless Desktop Receiver (Model 1028) has
* 'Usage Min/Max' where it ought to have 'Physical Min/Max'
*/
-static void ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
- if ((quirks & MS_RDESC) && rsize == 571 && rdesc[557] == 0x19 &&
+ if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 &&
rdesc[559] == 0x29) {
dev_info(&hdev->dev, "fixing up Microsoft Wireless Receiver "
"Model 1028 report descriptor\n");
rdesc[557] = 0x35;
rdesc[559] = 0x45;
}
+ return rdesc;
}
#define ms_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c
index 2cd05aa244b9..c95c31e2d869 100644
--- a/drivers/hid/hid-monterey.c
+++ b/drivers/hid/hid-monterey.c
@@ -22,14 +22,15 @@
#include "hid-ids.h"
-static void mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
- if (rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
+ if (*rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
dev_info(&hdev->dev, "fixing up button/consumer in HID report "
"descriptor\n");
rdesc[30] = 0x0c;
}
+ return rdesc;
}
#define mr_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index fb69b8c4953f..69169efa1e16 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -90,6 +90,55 @@ struct ntrig_data {
};
+/*
+ * This function converts the 4 byte raw firmware code into
+ * a string containing 5 comma separated numbers.
+ */
+static int ntrig_version_string(unsigned char *raw, char *buf)
+{
+ __u8 a = (raw[1] & 0x0e) >> 1;
+ __u8 b = (raw[0] & 0x3c) >> 2;
+ __u8 c = ((raw[0] & 0x03) << 3) | ((raw[3] & 0xe0) >> 5);
+ __u8 d = ((raw[3] & 0x07) << 3) | ((raw[2] & 0xe0) >> 5);
+ __u8 e = raw[2] & 0x07;
+
+ /*
+ * As yet unmapped bits:
+ * 0b11000000 0b11110001 0b00011000 0b00011000
+ */
+
+ return sprintf(buf, "%u.%u.%u.%u.%u", a, b, c, d, e);
+}
+
+static void ntrig_report_version(struct hid_device *hdev)
+{
+ int ret;
+ char buf[20];
+ struct usb_device *usb_dev = hid_to_usb_dev(hdev);
+ unsigned char *data = kmalloc(8, GFP_KERNEL);
+
+ if (!data)
+ goto err_free;
+
+ ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE |
+ USB_DIR_IN,
+ 0x30c, 1, data, 8,
+ USB_CTRL_SET_TIMEOUT);
+
+ if (ret == 8) {
+ ret = ntrig_version_string(&data[2], buf);
+
+ dev_info(&hdev->dev,
+ "Firmware version: %s (%02x%02x %02x%02x)\n",
+ buf, data[2], data[3], data[4], data[5]);
+ }
+
+err_free:
+ kfree(data);
+}
+
static ssize_t show_phys_width(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -377,8 +426,8 @@ static struct attribute_group ntrig_attribute_group = {
*/
static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
{
struct ntrig_data *nd = hid_get_drvdata(hdev);
@@ -448,13 +497,13 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
/* width/height mapped on TouchMajor/TouchMinor/Orientation */
case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TOUCH_MAJOR);
+ EV_ABS, ABS_MT_TOUCH_MAJOR);
return 1;
case HID_DG_HEIGHT:
hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TOUCH_MINOR);
+ EV_ABS, ABS_MT_TOUCH_MINOR);
input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
- 0, 1, 0, 0);
+ 0, 1, 0, 0);
return 1;
}
return 0;
@@ -468,8 +517,8 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
}
static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
{
/* No special mappings needed for the pen and single touch */
if (field->physical)
@@ -489,7 +538,7 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
* and call input_mt_sync after each point if necessary
*/
static int ntrig_event (struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value)
+ struct hid_usage *usage, __s32 value)
{
struct input_dev *input = field->hidinput->input;
struct ntrig_data *nd = hid_get_drvdata(hid);
@@ -848,6 +897,8 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (report)
usbhid_submit_report(hdev, report, USB_DIR_OUT);
+ ntrig_report_version(hdev);
+
ret = sysfs_create_group(&hdev->dev.kobj,
&ntrig_attribute_group);
@@ -860,7 +911,7 @@ err_free:
static void ntrig_remove(struct hid_device *hdev)
{
sysfs_remove_group(&hdev->dev.kobj,
- &ntrig_attribute_group);
+ &ntrig_attribute_group);
hid_hw_stop(hdev);
kfree(hid_get_drvdata(hdev));
}
diff --git a/drivers/hid/hid-ortek.c b/drivers/hid/hid-ortek.c
index aa9a960f73a4..2e79716dca31 100644
--- a/drivers/hid/hid-ortek.c
+++ b/drivers/hid/hid-ortek.c
@@ -19,14 +19,15 @@
#include "hid-ids.h"
-static void ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
- if (rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) {
+ if (*rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) {
dev_info(&hdev->dev, "Fixing up Ortek WKB-2000 "
"report descriptor.\n");
rdesc[55] = 0x92;
}
+ return rdesc;
}
static const struct hid_device_id ortek_devices[] = {
diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c
index 500fbd0652dc..308d6ae48a3e 100644
--- a/drivers/hid/hid-petalynx.c
+++ b/drivers/hid/hid-petalynx.c
@@ -23,10 +23,10 @@
#include "hid-ids.h"
/* Petalynx Maxter Remote has maximum for consumer page set too low */
-static void pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
- if (rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
+ if (*rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
rdesc[41] == 0x00 && rdesc[59] == 0x26 &&
rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
dev_info(&hdev->dev, "fixing up Petalynx Maxter Remote report "
@@ -34,6 +34,7 @@ static void pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
rdesc[60] = 0xfa;
rdesc[40] = 0xfa;
}
+ return rdesc;
}
#define pl_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
index 845f428b8090..48eab84f53b5 100644
--- a/drivers/hid/hid-prodikeys.c
+++ b/drivers/hid/hid-prodikeys.c
@@ -740,10 +740,10 @@ int pcmidi_snd_terminate(struct pcmidi_snd *pm)
/*
* PC-MIDI report descriptor for report id is wrong.
*/
-static void pk_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *pk_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
- if (rsize == 178 &&
+ if (*rsize == 178 &&
rdesc[111] == 0x06 && rdesc[112] == 0x00 &&
rdesc[113] == 0xff) {
dev_info(&hdev->dev, "fixing up pc-midi keyboard report "
@@ -751,6 +751,7 @@ static void pk_report_fixup(struct hid_device *hdev, __u8 *rdesc,
rdesc[144] = 0x18; /* report 4: was 0x10 report count */
}
+ return rdesc;
}
static int pk_input_mapping(struct hid_device *hdev, struct hid_input *hi,
diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c
new file mode 100644
index 000000000000..9bf23047892a
--- /dev/null
+++ b/drivers/hid/hid-roccat-pyra.c
@@ -0,0 +1,968 @@
+/*
+ * Roccat Pyra driver for Linux
+ *
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * Roccat Pyra is a mobile gamer mouse which comes in wired and wireless
+ * variant. Wireless variant is not tested.
+ * Userland tools can be found at http://sourceforge.net/projects/roccat
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "hid-ids.h"
+#include "hid-roccat.h"
+#include "hid-roccat-pyra.h"
+
+static void profile_activated(struct pyra_device *pyra,
+ unsigned int new_profile)
+{
+ pyra->actual_profile = new_profile;
+ pyra->actual_cpi = pyra->profile_settings[pyra->actual_profile].y_cpi;
+}
+
+static int pyra_send_control(struct usb_device *usb_dev, int value,
+ enum pyra_control_requests request)
+{
+ int len;
+ struct pyra_control control;
+
+ if ((request == PYRA_CONTROL_REQUEST_PROFILE_SETTINGS ||
+ request == PYRA_CONTROL_REQUEST_PROFILE_BUTTONS) &&
+ (value < 0 || value > 4))
+ return -EINVAL;
+
+ control.command = PYRA_COMMAND_CONTROL;
+ control.value = value;
+ control.request = request;
+
+ len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_CONFIGURATION,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+ PYRA_USB_COMMAND_CONTROL, 0, (char *)&control,
+ sizeof(struct pyra_control),
+ USB_CTRL_SET_TIMEOUT);
+
+ if (len != sizeof(struct pyra_control))
+ return len;
+
+ return 0;
+}
+
+static int pyra_receive_control_status(struct usb_device *usb_dev)
+{
+ int len;
+ struct pyra_control control;
+
+ do {
+ msleep(10);
+
+ len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE |
+ USB_DIR_IN,
+ PYRA_USB_COMMAND_CONTROL, 0, (char *)&control,
+ sizeof(struct pyra_control),
+ USB_CTRL_SET_TIMEOUT);
+
+ /* requested too early, try again */
+ } while (len == -EPROTO);
+
+ if (len == sizeof(struct pyra_control) &&
+ control.command == PYRA_COMMAND_CONTROL &&
+ control.request == PYRA_CONTROL_REQUEST_STATUS &&
+ control.value == 1)
+ return 0;
+ else {
+ dev_err(&usb_dev->dev, "receive control status: "
+ "unknown response 0x%x 0x%x\n",
+ control.request, control.value);
+ return -EINVAL;
+ }
+}
+
+static int pyra_get_profile_settings(struct usb_device *usb_dev,
+ struct pyra_profile_settings *buf, int number)
+{
+ int retval;
+
+ retval = pyra_send_control(usb_dev, number,
+ PYRA_CONTROL_REQUEST_PROFILE_SETTINGS);
+
+ if (retval)
+ return retval;
+
+ retval = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ PYRA_USB_COMMAND_PROFILE_SETTINGS, 0, (char *)buf,
+ sizeof(struct pyra_profile_settings),
+ USB_CTRL_SET_TIMEOUT);
+
+ if (retval != sizeof(struct pyra_profile_settings))
+ return retval;
+
+ return 0;
+}
+
+static int pyra_get_profile_buttons(struct usb_device *usb_dev,
+ struct pyra_profile_buttons *buf, int number)
+{
+ int retval;
+
+ retval = pyra_send_control(usb_dev, number,
+ PYRA_CONTROL_REQUEST_PROFILE_BUTTONS);
+
+ if (retval)
+ return retval;
+
+ retval = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ PYRA_USB_COMMAND_PROFILE_BUTTONS, 0, (char *)buf,
+ sizeof(struct pyra_profile_buttons),
+ USB_CTRL_SET_TIMEOUT);
+
+ if (retval != sizeof(struct pyra_profile_buttons))
+ return retval;
+
+ return 0;
+}
+
+static int pyra_get_settings(struct usb_device *usb_dev,
+ struct pyra_settings *buf)
+{
+ int len;
+ len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ PYRA_USB_COMMAND_SETTINGS, 0, buf,
+ sizeof(struct pyra_settings), USB_CTRL_SET_TIMEOUT);
+ if (len != sizeof(struct pyra_settings))
+ return -EIO;
+ return 0;
+}
+
+static int pyra_get_info(struct usb_device *usb_dev, struct pyra_info *buf)
+{
+ int len;
+ len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ PYRA_USB_COMMAND_INFO, 0, buf,
+ sizeof(struct pyra_info), USB_CTRL_SET_TIMEOUT);
+ if (len != sizeof(struct pyra_info))
+ return -EIO;
+ return 0;
+}
+
+static int pyra_set_profile_settings(struct usb_device *usb_dev,
+ struct pyra_profile_settings const *settings)
+{
+ int len;
+ len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_CONFIGURATION,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+ PYRA_USB_COMMAND_PROFILE_SETTINGS, 0, (char *)settings,
+ sizeof(struct pyra_profile_settings),
+ USB_CTRL_SET_TIMEOUT);
+ if (len != sizeof(struct pyra_profile_settings))
+ return -EIO;
+ if (pyra_receive_control_status(usb_dev))
+ return -EIO;
+ return 0;
+}
+
+static int pyra_set_profile_buttons(struct usb_device *usb_dev,
+ struct pyra_profile_buttons const *buttons)
+{
+ int len;
+ len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_CONFIGURATION,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+ PYRA_USB_COMMAND_PROFILE_BUTTONS, 0, (char *)buttons,
+ sizeof(struct pyra_profile_buttons),
+ USB_CTRL_SET_TIMEOUT);
+ if (len != sizeof(struct pyra_profile_buttons))
+ return -EIO;
+ if (pyra_receive_control_status(usb_dev))
+ return -EIO;
+ return 0;
+}
+
+static int pyra_set_settings(struct usb_device *usb_dev,
+ struct pyra_settings const *settings)
+{
+ int len;
+ len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_CONFIGURATION,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+ PYRA_USB_COMMAND_SETTINGS, 0, (char *)settings,
+ sizeof(struct pyra_settings), USB_CTRL_SET_TIMEOUT);
+ if (len != sizeof(struct pyra_settings))
+ return -EIO;
+ if (pyra_receive_control_status(usb_dev))
+ return -EIO;
+ return 0;
+}
+
+static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count, int number)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+
+ if (off >= sizeof(struct pyra_profile_settings))
+ return 0;
+
+ if (off + count > sizeof(struct pyra_profile_settings))
+ count = sizeof(struct pyra_profile_settings) - off;
+
+ mutex_lock(&pyra->pyra_lock);
+ memcpy(buf, ((char const *)&pyra->profile_settings[number]) + off,
+ count);
+ mutex_unlock(&pyra->pyra_lock);
+
+ return count;
+}
+
+static ssize_t pyra_sysfs_read_profile1_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return pyra_sysfs_read_profilex_settings(fp, kobj,
+ attr, buf, off, count, 0);
+}
+
+static ssize_t pyra_sysfs_read_profile2_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return pyra_sysfs_read_profilex_settings(fp, kobj,
+ attr, buf, off, count, 1);
+}
+
+static ssize_t pyra_sysfs_read_profile3_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return pyra_sysfs_read_profilex_settings(fp, kobj,
+ attr, buf, off, count, 2);
+}
+
+static ssize_t pyra_sysfs_read_profile4_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return pyra_sysfs_read_profilex_settings(fp, kobj,
+ attr, buf, off, count, 3);
+}
+
+static ssize_t pyra_sysfs_read_profile5_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return pyra_sysfs_read_profilex_settings(fp, kobj,
+ attr, buf, off, count, 4);
+}
+
+static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count, int number)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+
+ if (off >= sizeof(struct pyra_profile_buttons))
+ return 0;
+
+ if (off + count > sizeof(struct pyra_profile_buttons))
+ count = sizeof(struct pyra_profile_buttons) - off;
+
+ mutex_lock(&pyra->pyra_lock);
+ memcpy(buf, ((char const *)&pyra->profile_buttons[number]) + off,
+ count);
+ mutex_unlock(&pyra->pyra_lock);
+
+ return count;
+}
+
+static ssize_t pyra_sysfs_read_profile1_buttons(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return pyra_sysfs_read_profilex_buttons(fp, kobj,
+ attr, buf, off, count, 0);
+}
+
+static ssize_t pyra_sysfs_read_profile2_buttons(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return pyra_sysfs_read_profilex_buttons(fp, kobj,
+ attr, buf, off, count, 1);
+}
+
+static ssize_t pyra_sysfs_read_profile3_buttons(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return pyra_sysfs_read_profilex_buttons(fp, kobj,
+ attr, buf, off, count, 2);
+}
+
+static ssize_t pyra_sysfs_read_profile4_buttons(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return pyra_sysfs_read_profilex_buttons(fp, kobj,
+ attr, buf, off, count, 3);
+}
+
+static ssize_t pyra_sysfs_read_profile5_buttons(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return pyra_sysfs_read_profilex_buttons(fp, kobj,
+ attr, buf, off, count, 4);
+}
+
+static ssize_t pyra_sysfs_write_profile_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval = 0;
+ int difference;
+ int profile_number;
+ struct pyra_profile_settings *profile_settings;
+
+ if (off != 0 || count != sizeof(struct pyra_profile_settings))
+ return -EINVAL;
+
+ profile_number = ((struct pyra_profile_settings const *)buf)->number;
+ profile_settings = &pyra->profile_settings[profile_number];
+
+ mutex_lock(&pyra->pyra_lock);
+ difference = memcmp(buf, profile_settings,
+ sizeof(struct pyra_profile_settings));
+ if (difference) {
+ retval = pyra_set_profile_settings(usb_dev,
+ (struct pyra_profile_settings const *)buf);
+ if (!retval)
+ memcpy(profile_settings, buf,
+ sizeof(struct pyra_profile_settings));
+ }
+ mutex_unlock(&pyra->pyra_lock);
+
+ if (retval)
+ return retval;
+
+ return sizeof(struct pyra_profile_settings);
+}
+
+static ssize_t pyra_sysfs_write_profile_buttons(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval = 0;
+ int difference;
+ int profile_number;
+ struct pyra_profile_buttons *profile_buttons;
+
+ if (off != 0 || count != sizeof(struct pyra_profile_buttons))
+ return -EINVAL;
+
+ profile_number = ((struct pyra_profile_buttons const *)buf)->number;
+ profile_buttons = &pyra->profile_buttons[profile_number];
+
+ mutex_lock(&pyra->pyra_lock);
+ difference = memcmp(buf, profile_buttons,
+ sizeof(struct pyra_profile_buttons));
+ if (difference) {
+ retval = pyra_set_profile_buttons(usb_dev,
+ (struct pyra_profile_buttons const *)buf);
+ if (!retval)
+ memcpy(profile_buttons, buf,
+ sizeof(struct pyra_profile_buttons));
+ }
+ mutex_unlock(&pyra->pyra_lock);
+
+ if (retval)
+ return retval;
+
+ return sizeof(struct pyra_profile_buttons);
+}
+
+static ssize_t pyra_sysfs_read_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+
+ if (off >= sizeof(struct pyra_settings))
+ return 0;
+
+ if (off + count > sizeof(struct pyra_settings))
+ count = sizeof(struct pyra_settings) - off;
+
+ mutex_lock(&pyra->pyra_lock);
+ memcpy(buf, ((char const *)&pyra->settings) + off, count);
+ mutex_unlock(&pyra->pyra_lock);
+
+ return count;
+}
+
+static ssize_t pyra_sysfs_write_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval = 0;
+ int difference;
+
+ if (off != 0 || count != sizeof(struct pyra_settings))
+ return -EINVAL;
+
+ mutex_lock(&pyra->pyra_lock);
+ difference = memcmp(buf, &pyra->settings, sizeof(struct pyra_settings));
+ 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)
+ return retval;
+
+ profile_activated(pyra, pyra->settings.startup_profile);
+
+ return sizeof(struct pyra_settings);
+}
+
+
+static ssize_t pyra_sysfs_show_actual_cpi(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+ return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_cpi);
+}
+
+static ssize_t pyra_sysfs_show_actual_profile(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+ return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_profile);
+}
+
+static ssize_t pyra_sysfs_show_firmware_version(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+ return snprintf(buf, PAGE_SIZE, "%d\n", pyra->firmware_version);
+}
+
+static ssize_t pyra_sysfs_show_startup_profile(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+ return snprintf(buf, PAGE_SIZE, "%d\n", pyra->settings.startup_profile);
+}
+
+static DEVICE_ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL);
+
+static DEVICE_ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL);
+
+static DEVICE_ATTR(firmware_version, 0440,
+ pyra_sysfs_show_firmware_version, NULL);
+
+static DEVICE_ATTR(startup_profile, 0440,
+ pyra_sysfs_show_startup_profile, NULL);
+
+static struct attribute *pyra_attributes[] = {
+ &dev_attr_actual_cpi.attr,
+ &dev_attr_actual_profile.attr,
+ &dev_attr_firmware_version.attr,
+ &dev_attr_startup_profile.attr,
+ NULL
+};
+
+static struct attribute_group pyra_attribute_group = {
+ .attrs = pyra_attributes
+};
+
+static struct bin_attribute pyra_profile_settings_attr = {
+ .attr = { .name = "profile_settings", .mode = 0220 },
+ .size = sizeof(struct pyra_profile_settings),
+ .write = pyra_sysfs_write_profile_settings
+};
+
+static struct bin_attribute pyra_profile1_settings_attr = {
+ .attr = { .name = "profile1_settings", .mode = 0440 },
+ .size = sizeof(struct pyra_profile_settings),
+ .read = pyra_sysfs_read_profile1_settings
+};
+
+static struct bin_attribute pyra_profile2_settings_attr = {
+ .attr = { .name = "profile2_settings", .mode = 0440 },
+ .size = sizeof(struct pyra_profile_settings),
+ .read = pyra_sysfs_read_profile2_settings
+};
+
+static struct bin_attribute pyra_profile3_settings_attr = {
+ .attr = { .name = "profile3_settings", .mode = 0440 },
+ .size = sizeof(struct pyra_profile_settings),
+ .read = pyra_sysfs_read_profile3_settings
+};
+
+static struct bin_attribute pyra_profile4_settings_attr = {
+ .attr = { .name = "profile4_settings", .mode = 0440 },
+ .size = sizeof(struct pyra_profile_settings),
+ .read = pyra_sysfs_read_profile4_settings
+};
+
+static struct bin_attribute pyra_profile5_settings_attr = {
+ .attr = { .name = "profile5_settings", .mode = 0440 },
+ .size = sizeof(struct pyra_profile_settings),
+ .read = pyra_sysfs_read_profile5_settings
+};
+
+static struct bin_attribute pyra_profile_buttons_attr = {
+ .attr = { .name = "profile_buttons", .mode = 0220 },
+ .size = sizeof(struct pyra_profile_buttons),
+ .write = pyra_sysfs_write_profile_buttons
+};
+
+static struct bin_attribute pyra_profile1_buttons_attr = {
+ .attr = { .name = "profile1_buttons", .mode = 0440 },
+ .size = sizeof(struct pyra_profile_buttons),
+ .read = pyra_sysfs_read_profile1_buttons
+};
+
+static struct bin_attribute pyra_profile2_buttons_attr = {
+ .attr = { .name = "profile2_buttons", .mode = 0440 },
+ .size = sizeof(struct pyra_profile_buttons),
+ .read = pyra_sysfs_read_profile2_buttons
+};
+
+static struct bin_attribute pyra_profile3_buttons_attr = {
+ .attr = { .name = "profile3_buttons", .mode = 0440 },
+ .size = sizeof(struct pyra_profile_buttons),
+ .read = pyra_sysfs_read_profile3_buttons
+};
+
+static struct bin_attribute pyra_profile4_buttons_attr = {
+ .attr = { .name = "profile4_buttons", .mode = 0440 },
+ .size = sizeof(struct pyra_profile_buttons),
+ .read = pyra_sysfs_read_profile4_buttons
+};
+
+static struct bin_attribute pyra_profile5_buttons_attr = {
+ .attr = { .name = "profile5_buttons", .mode = 0440 },
+ .size = sizeof(struct pyra_profile_buttons),
+ .read = pyra_sysfs_read_profile5_buttons
+};
+
+static struct bin_attribute pyra_settings_attr = {
+ .attr = { .name = "settings", .mode = 0660 },
+ .size = sizeof(struct pyra_settings),
+ .read = pyra_sysfs_read_settings,
+ .write = pyra_sysfs_write_settings
+};
+
+static int pyra_create_sysfs_attributes(struct usb_interface *intf)
+{
+ int retval;
+
+ retval = sysfs_create_group(&intf->dev.kobj, &pyra_attribute_group);
+ if (retval)
+ goto exit_1;
+
+ retval = sysfs_create_bin_file(&intf->dev.kobj,
+ &pyra_profile_settings_attr);
+ if (retval)
+ goto exit_2;
+
+ retval = sysfs_create_bin_file(&intf->dev.kobj,
+ &pyra_profile1_settings_attr);
+ if (retval)
+ goto exit_3;
+
+ retval = sysfs_create_bin_file(&intf->dev.kobj,
+ &pyra_profile2_settings_attr);
+ if (retval)
+ goto exit_4;
+
+ retval = sysfs_create_bin_file(&intf->dev.kobj,
+ &pyra_profile3_settings_attr);
+ if (retval)
+ goto exit_5;
+
+ retval = sysfs_create_bin_file(&intf->dev.kobj,
+ &pyra_profile4_settings_attr);
+ if (retval)
+ goto exit_6;
+
+ retval = sysfs_create_bin_file(&intf->dev.kobj,
+ &pyra_profile5_settings_attr);
+ if (retval)
+ goto exit_7;
+
+ retval = sysfs_create_bin_file(&intf->dev.kobj,
+ &pyra_profile_buttons_attr);
+ if (retval)
+ goto exit_8;
+
+ retval = sysfs_create_bin_file(&intf->dev.kobj,
+ &pyra_profile1_buttons_attr);
+ if (retval)
+ goto exit_9;
+
+ retval = sysfs_create_bin_file(&intf->dev.kobj,
+ &pyra_profile2_buttons_attr);
+ if (retval)
+ goto exit_10;
+
+ retval = sysfs_create_bin_file(&intf->dev.kobj,
+ &pyra_profile3_buttons_attr);
+ if (retval)
+ goto exit_11;
+
+ retval = sysfs_create_bin_file(&intf->dev.kobj,
+ &pyra_profile4_buttons_attr);
+ if (retval)
+ goto exit_12;
+
+ retval = sysfs_create_bin_file(&intf->dev.kobj,
+ &pyra_profile5_buttons_attr);
+ if (retval)
+ goto exit_13;
+
+ retval = sysfs_create_bin_file(&intf->dev.kobj,
+ &pyra_settings_attr);
+ if (retval)
+ goto exit_14;
+
+ return 0;
+
+exit_14:
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr);
+exit_13:
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr);
+exit_12:
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr);
+exit_11:
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr);
+exit_10:
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr);
+exit_9:
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr);
+exit_8:
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr);
+exit_7:
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr);
+exit_6:
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr);
+exit_5:
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr);
+exit_4:
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr);
+exit_3:
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr);
+exit_2:
+ sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group);
+exit_1:
+ return retval;
+}
+
+static void pyra_remove_sysfs_attributes(struct usb_interface *intf)
+{
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_settings_attr);
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr);
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr);
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr);
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr);
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr);
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr);
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr);
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr);
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr);
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr);
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr);
+ sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr);
+ sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group);
+}
+
+static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
+ struct pyra_device *pyra)
+{
+ struct pyra_info *info;
+ int retval, i;
+
+ mutex_init(&pyra->pyra_lock);
+
+ info = kmalloc(sizeof(struct pyra_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ retval = pyra_get_info(usb_dev, info);
+ if (retval) {
+ kfree(info);
+ return retval;
+ }
+ pyra->firmware_version = info->firmware_version;
+ kfree(info);
+
+ retval = pyra_get_settings(usb_dev, &pyra->settings);
+ if (retval)
+ return retval;
+
+ for (i = 0; i < 5; ++i) {
+ retval = pyra_get_profile_settings(usb_dev,
+ &pyra->profile_settings[i], i);
+ if (retval)
+ return retval;
+
+ retval = pyra_get_profile_buttons(usb_dev,
+ &pyra->profile_buttons[i], i);
+ if (retval)
+ return retval;
+ }
+
+ profile_activated(pyra, pyra->settings.startup_profile);
+
+ return 0;
+}
+
+static int pyra_init_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ struct pyra_device *pyra;
+ int retval;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ == USB_INTERFACE_PROTOCOL_MOUSE) {
+
+ pyra = kzalloc(sizeof(*pyra), GFP_KERNEL);
+ if (!pyra) {
+ dev_err(&hdev->dev, "can't alloc device descriptor\n");
+ return -ENOMEM;
+ }
+ hid_set_drvdata(hdev, pyra);
+
+ retval = pyra_init_pyra_device_struct(usb_dev, pyra);
+ if (retval) {
+ dev_err(&hdev->dev,
+ "couldn't init struct pyra_device\n");
+ goto exit_free;
+ }
+
+ retval = roccat_connect(hdev);
+ if (retval < 0) {
+ dev_err(&hdev->dev, "couldn't init char dev\n");
+ } else {
+ pyra->chrdev_minor = retval;
+ pyra->roccat_claimed = 1;
+ }
+
+ retval = pyra_create_sysfs_attributes(intf);
+ if (retval) {
+ dev_err(&hdev->dev, "cannot create sysfs files\n");
+ goto exit_free;
+ }
+ } else {
+ hid_set_drvdata(hdev, NULL);
+ }
+
+ return 0;
+exit_free:
+ kfree(pyra);
+ return retval;
+}
+
+static void pyra_remove_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct pyra_device *pyra;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ == USB_INTERFACE_PROTOCOL_MOUSE) {
+ pyra_remove_sysfs_attributes(intf);
+ pyra = hid_get_drvdata(hdev);
+ if (pyra->roccat_claimed)
+ roccat_disconnect(pyra->chrdev_minor);
+ kfree(hid_get_drvdata(hdev));
+ }
+}
+
+static int pyra_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int retval;
+
+ retval = hid_parse(hdev);
+ if (retval) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto exit;
+ }
+
+ retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (retval) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto exit;
+ }
+
+ retval = pyra_init_specials(hdev);
+ if (retval) {
+ dev_err(&hdev->dev, "couldn't install mouse\n");
+ goto exit_stop;
+ }
+ return 0;
+
+exit_stop:
+ hid_hw_stop(hdev);
+exit:
+ return retval;
+}
+
+static void pyra_remove(struct hid_device *hdev)
+{
+ pyra_remove_specials(hdev);
+ hid_hw_stop(hdev);
+}
+
+static void pyra_keep_values_up_to_date(struct pyra_device *pyra,
+ u8 const *data)
+{
+ struct pyra_mouse_event_button const *button_event;
+
+ switch (data[0]) {
+ case PYRA_MOUSE_REPORT_NUMBER_BUTTON:
+ button_event = (struct pyra_mouse_event_button const *)data;
+ switch (button_event->type) {
+ case PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2:
+ profile_activated(pyra, button_event->data1 - 1);
+ break;
+ case PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI:
+ pyra->actual_cpi = button_event->data1;
+ break;
+ }
+ break;
+ }
+}
+
+static void pyra_report_to_chrdev(struct pyra_device const *pyra,
+ u8 const *data)
+{
+ struct pyra_roccat_report roccat_report;
+ struct pyra_mouse_event_button const *button_event;
+
+ if (data[0] != PYRA_MOUSE_REPORT_NUMBER_BUTTON)
+ return;
+
+ button_event = (struct pyra_mouse_event_button const *)data;
+
+ switch (button_event->type) {
+ case PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2:
+ case PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI:
+ roccat_report.type = button_event->type;
+ roccat_report.value = button_event->data1;
+ roccat_report.key = 0;
+ roccat_report_event(pyra->chrdev_minor,
+ (uint8_t const *)&roccat_report,
+ sizeof(struct pyra_roccat_report));
+ break;
+ case PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO:
+ case PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT:
+ case PYRA_MOUSE_EVENT_BUTTON_TYPE_QUICKLAUNCH:
+ if (button_event->data2 == PYRA_MOUSE_EVENT_BUTTON_PRESS) {
+ roccat_report.type = button_event->type;
+ roccat_report.key = button_event->data1;
+ /*
+ * pyra reports profile numbers with range 1-5.
+ * Keeping this behaviour.
+ */
+ roccat_report.value = pyra->actual_profile + 1;
+ roccat_report_event(pyra->chrdev_minor,
+ (uint8_t const *)&roccat_report,
+ sizeof(struct pyra_roccat_report));
+ }
+ break;
+ }
+}
+
+static int pyra_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *data, int size)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct pyra_device *pyra = hid_get_drvdata(hdev);
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ != USB_INTERFACE_PROTOCOL_MOUSE)
+ return 0;
+
+ pyra_keep_values_up_to_date(pyra, data);
+
+ if (pyra->roccat_claimed)
+ pyra_report_to_chrdev(pyra, data);
+
+ return 0;
+}
+
+static const struct hid_device_id pyra_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT,
+ USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
+ /* TODO add USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS after testing */
+ { }
+};
+
+MODULE_DEVICE_TABLE(hid, pyra_devices);
+
+static struct hid_driver pyra_driver = {
+ .name = "pyra",
+ .id_table = pyra_devices,
+ .probe = pyra_probe,
+ .remove = pyra_remove,
+ .raw_event = pyra_raw_event
+};
+
+static int __init pyra_init(void)
+{
+ return hid_register_driver(&pyra_driver);
+}
+
+static void __exit pyra_exit(void)
+{
+ hid_unregister_driver(&pyra_driver);
+}
+
+module_init(pyra_init);
+module_exit(pyra_exit);
+
+MODULE_AUTHOR("Stefan Achatz");
+MODULE_DESCRIPTION("USB Roccat Pyra driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat-pyra.h b/drivers/hid/hid-roccat-pyra.h
new file mode 100644
index 000000000000..22f80a8f26f9
--- /dev/null
+++ b/drivers/hid/hid-roccat-pyra.h
@@ -0,0 +1,186 @@
+#ifndef __HID_ROCCAT_PYRA_H
+#define __HID_ROCCAT_PYRA_H
+
+/*
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * 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/types.h>
+
+#pragma pack(push)
+#pragma pack(1)
+
+struct pyra_b {
+ uint8_t command; /* PYRA_COMMAND_B */
+ uint8_t size; /* always 3 */
+ uint8_t unknown; /* 1 */
+};
+
+struct pyra_control {
+ uint8_t command; /* PYRA_COMMAND_CONTROL */
+ /*
+ * value is profile number for request_settings and request_buttons
+ * 1 if status ok for request_status
+ */
+ uint8_t value; /* Range 0-4 */
+ uint8_t request;
+};
+
+enum pyra_control_requests {
+ PYRA_CONTROL_REQUEST_STATUS = 0x00,
+ PYRA_CONTROL_REQUEST_PROFILE_SETTINGS = 0x10,
+ PYRA_CONTROL_REQUEST_PROFILE_BUTTONS = 0x20
+};
+
+struct pyra_settings {
+ uint8_t command; /* PYRA_COMMAND_SETTINGS */
+ uint8_t size; /* always 3 */
+ uint8_t startup_profile; /* Range 0-4! */
+};
+
+struct pyra_profile_settings {
+ uint8_t command; /* PYRA_COMMAND_PROFILE_SETTINGS */
+ uint8_t size; /* always 0xd */
+ uint8_t number; /* Range 0-4 */
+ uint8_t xysync;
+ uint8_t x_sensitivity; /* 0x1-0xa */
+ uint8_t y_sensitivity;
+ uint8_t x_cpi; /* unused */
+ uint8_t y_cpi; /* this value is for x and y */
+ uint8_t lightswitch; /* 0 = off, 1 = on */
+ uint8_t light_effect;
+ uint8_t handedness;
+ uint16_t checksum; /* byte sum */
+};
+
+struct pyra_profile_buttons {
+ uint8_t command; /* PYRA_COMMAND_PROFILE_BUTTONS */
+ uint8_t size; /* always 0x13 */
+ uint8_t number; /* Range 0-4 */
+ uint8_t buttons[14];
+ uint16_t checksum; /* byte sum */
+};
+
+struct pyra_info {
+ uint8_t command; /* PYRA_COMMAND_INFO */
+ uint8_t size; /* always 6 */
+ uint8_t firmware_version;
+ uint8_t unknown1; /* always 0 */
+ uint8_t unknown2; /* always 1 */
+ uint8_t unknown3; /* always 0 */
+};
+
+enum pyra_commands {
+ PYRA_COMMAND_CONTROL = 0x4,
+ PYRA_COMMAND_SETTINGS = 0x5,
+ PYRA_COMMAND_PROFILE_SETTINGS = 0x6,
+ PYRA_COMMAND_PROFILE_BUTTONS = 0x7,
+ PYRA_COMMAND_INFO = 0x9,
+ PYRA_COMMAND_B = 0xb
+};
+
+enum pyra_usb_commands {
+ PYRA_USB_COMMAND_CONTROL = 0x304,
+ PYRA_USB_COMMAND_SETTINGS = 0x305,
+ PYRA_USB_COMMAND_PROFILE_SETTINGS = 0x306,
+ PYRA_USB_COMMAND_PROFILE_BUTTONS = 0x307,
+ PYRA_USB_COMMAND_INFO = 0x309,
+ PYRA_USB_COMMAND_B = 0x30b /* writes 3 bytes */
+};
+
+enum pyra_mouse_report_numbers {
+ PYRA_MOUSE_REPORT_NUMBER_HID = 1,
+ PYRA_MOUSE_REPORT_NUMBER_AUDIO = 2,
+ PYRA_MOUSE_REPORT_NUMBER_BUTTON = 3,
+};
+
+struct pyra_mouse_event_button {
+ uint8_t report_number; /* always 3 */
+ uint8_t unknown; /* always 0 */
+ uint8_t type;
+ uint8_t data1;
+ uint8_t data2;
+};
+
+struct pyra_mouse_event_audio {
+ uint8_t report_number; /* always 2 */
+ uint8_t type;
+ uint8_t unused; /* always 0 */
+};
+
+/* hid audio controls */
+enum pyra_mouse_event_audio_types {
+ PYRA_MOUSE_EVENT_AUDIO_TYPE_MUTE = 0xe2,
+ PYRA_MOUSE_EVENT_AUDIO_TYPE_VOLUME_UP = 0xe9,
+ PYRA_MOUSE_EVENT_AUDIO_TYPE_VOLUME_DOWN = 0xea,
+};
+
+enum pyra_mouse_event_button_types {
+ /*
+ * Mouse sends tilt events on report_number 1 and 3
+ * Tilt events are sent repeatedly with 0.94s between first and second
+ * event and 0.22s on subsequent
+ */
+ PYRA_MOUSE_EVENT_BUTTON_TYPE_TILT = 0x10,
+
+ /*
+ * These are sent sequentially
+ * data1 contains new profile number in range 1-5
+ */
+ PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_1 = 0x20,
+ PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2 = 0x30,
+
+ /*
+ * data1 = button_number (rmp index)
+ * data2 = pressed/released
+ */
+ PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO = 0x40,
+ PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT = 0x50,
+
+ /*
+ * data1 = button_number (rmp index)
+ */
+ PYRA_MOUSE_EVENT_BUTTON_TYPE_QUICKLAUNCH = 0x60,
+
+ /* data1 = new cpi */
+ PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI = 0xb0,
+
+ /* data1 and data2 = new sensitivity */
+ PYRA_MOUSE_EVENT_BUTTON_TYPE_SENSITIVITY = 0xc0,
+
+ PYRA_MOUSE_EVENT_BUTTON_TYPE_MULTIMEDIA = 0xf0,
+};
+
+enum {
+ PYRA_MOUSE_EVENT_BUTTON_PRESS = 0,
+ PYRA_MOUSE_EVENT_BUTTON_RELEASE = 1,
+};
+
+struct pyra_roccat_report {
+ uint8_t type;
+ uint8_t value;
+ uint8_t key;
+};
+
+#pragma pack(pop)
+
+struct pyra_device {
+ int actual_profile;
+ int actual_cpi;
+ int firmware_version;
+ int roccat_claimed;
+ int chrdev_minor;
+ struct mutex pyra_lock;
+ struct pyra_settings settings;
+ struct pyra_profile_settings profile_settings[5];
+ struct pyra_profile_buttons profile_buttons[5];
+};
+
+#endif
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c
index bda0fd60c98d..35894444e000 100644
--- a/drivers/hid/hid-samsung.c
+++ b/drivers/hid/hid-samsung.c
@@ -61,10 +61,10 @@ static inline void samsung_irda_dev_trace(struct hid_device *hdev,
"descriptor\n", rsize);
}
-static void samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
- if (rsize == 184 && rdesc[175] == 0x25 && rdesc[176] == 0x40 &&
+ if (*rsize == 184 && rdesc[175] == 0x25 && rdesc[176] == 0x40 &&
rdesc[177] == 0x75 && rdesc[178] == 0x30 &&
rdesc[179] == 0x95 && rdesc[180] == 0x01 &&
rdesc[182] == 0x40) {
@@ -74,24 +74,25 @@ static void samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc,
rdesc[180] = 0x06;
rdesc[182] = 0x42;
} else
- if (rsize == 203 && rdesc[192] == 0x15 && rdesc[193] == 0x0 &&
+ if (*rsize == 203 && rdesc[192] == 0x15 && rdesc[193] == 0x0 &&
rdesc[194] == 0x25 && rdesc[195] == 0x12) {
samsung_irda_dev_trace(hdev, 203);
rdesc[193] = 0x1;
rdesc[195] = 0xf;
} else
- if (rsize == 135 && rdesc[124] == 0x15 && rdesc[125] == 0x0 &&
+ if (*rsize == 135 && rdesc[124] == 0x15 && rdesc[125] == 0x0 &&
rdesc[126] == 0x25 && rdesc[127] == 0x11) {
samsung_irda_dev_trace(hdev, 135);
rdesc[125] = 0x1;
rdesc[127] = 0xe;
} else
- if (rsize == 171 && rdesc[160] == 0x15 && rdesc[161] == 0x0 &&
+ if (*rsize == 171 && rdesc[160] == 0x15 && rdesc[161] == 0x0 &&
rdesc[162] == 0x25 && rdesc[163] == 0x01) {
samsung_irda_dev_trace(hdev, 171);
rdesc[161] = 0x1;
rdesc[163] = 0x3;
}
+ return rdesc;
}
#define samsung_kbd_mouse_map_key_clear(c) \
@@ -130,11 +131,12 @@ static int samsung_kbd_mouse_input_mapping(struct hid_device *hdev,
return 1;
}
-static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
if (USB_DEVICE_ID_SAMSUNG_IR_REMOTE == hdev->product)
- samsung_irda_report_fixup(hdev, rdesc, rsize);
+ rdesc = samsung_irda_report_fixup(hdev, rdesc, rsize);
+ return rdesc;
}
static int samsung_input_mapping(struct hid_device *hdev, struct hid_input *hi,
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 402d5574b574..677bb3da10e8 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -24,24 +24,46 @@
#include "hid-ids.h"
-#define VAIO_RDESC_CONSTANT 0x0001
+#define VAIO_RDESC_CONSTANT (1 << 0)
+#define SIXAXIS_CONTROLLER_USB (1 << 1)
+#define SIXAXIS_CONTROLLER_BT (1 << 2)
struct sony_sc {
unsigned long quirks;
};
/* Sony Vaio VGX has wrongly mouse pointer declared as constant */
-static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
struct sony_sc *sc = hid_get_drvdata(hdev);
if ((sc->quirks & VAIO_RDESC_CONSTANT) &&
- rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) {
+ *rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) {
dev_info(&hdev->dev, "Fixing up Sony Vaio VGX report "
"descriptor\n");
rdesc[55] = 0x06;
}
+ return rdesc;
+}
+
+static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
+ size_t count, unsigned char report_type)
+{
+ struct usb_interface *intf = to_usb_interface(hid->dev.parent);
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct usb_host_interface *interface = intf->cur_altsetting;
+ int report_id = buf[0];
+ int ret;
+
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ HID_REQ_SET_REPORT,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ ((report_type + 1) << 8) | report_id,
+ interface->desc.bInterfaceNumber, buf, count,
+ USB_CTRL_SET_TIMEOUT);
+
+ return ret;
}
/*
@@ -49,7 +71,7 @@ static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
* to "operational". Without this, the ps3 controller will not report any
* events.
*/
-static int sony_set_operational_usb(struct hid_device *hdev)
+static int sixaxis_set_operational_usb(struct hid_device *hdev)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct usb_device *dev = interface_to_usbdev(intf);
@@ -74,7 +96,7 @@ static int sony_set_operational_usb(struct hid_device *hdev)
return ret;
}
-static int sony_set_operational_bt(struct hid_device *hdev)
+static int sixaxis_set_operational_bt(struct hid_device *hdev)
{
unsigned char buf[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 };
return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
@@ -108,16 +130,14 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free;
}
- switch (hdev->bus) {
- case BUS_USB:
- ret = sony_set_operational_usb(hdev);
- break;
- case BUS_BLUETOOTH:
- ret = sony_set_operational_bt(hdev);
- break;
- default:
- ret = 0;
+ if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
+ hdev->hid_output_raw_report = sixaxis_usb_output_raw_report;
+ ret = sixaxis_set_operational_usb(hdev);
}
+ else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
+ ret = sixaxis_set_operational_bt(hdev);
+ else
+ ret = 0;
if (ret < 0)
goto err_stop;
@@ -137,8 +157,10 @@ static void sony_remove(struct hid_device *hdev)
}
static const struct hid_device_id sony_devices[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
+ .driver_data = SIXAXIS_CONTROLLER_USB },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
+ .driver_data = SIXAXIS_CONTROLLER_BT },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),
.driver_data = VAIO_RDESC_CONSTANT },
{ }
diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c
index 90df886c5e04..3171be28c3d5 100644
--- a/drivers/hid/hid-stantum.c
+++ b/drivers/hid/hid-stantum.c
@@ -249,6 +249,8 @@ static void stantum_remove(struct hid_device *hdev)
static const struct hid_device_id stantum_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX) },
{ }
};
MODULE_DEVICE_TABLE(hid, stantum_devices);
diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c
index 438107d9f1b2..164ed568f6cf 100644
--- a/drivers/hid/hid-sunplus.c
+++ b/drivers/hid/hid-sunplus.c
@@ -22,16 +22,17 @@
#include "hid-ids.h"
-static void sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
- if (rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
+ if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
rdesc[106] == 0x03) {
dev_info(&hdev->dev, "fixing up Sunplus Wireless Desktop "
"report descriptor\n");
rdesc[105] = rdesc[110] = 0x03;
rdesc[106] = rdesc[111] = 0x21;
}
+ return rdesc;
}
#define sp_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c
new file mode 100644
index 000000000000..05fdc85a76e5
--- /dev/null
+++ b/drivers/hid/hid-uclogic.c
@@ -0,0 +1,623 @@
+/*
+ * HID driver for UC-Logic devices not fully compliant with HID standard
+ *
+ * Copyright (c) 2010 Nikolai Kondrashov
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/*
+ * The original descriptors of WPXXXXU tablets have three report IDs, of
+ * which only two are used (8 and 9), and the remaining (7) seems to have
+ * the originally intended pen description which was abandoned for some
+ * reason. From this unused description it is possible to extract the
+ * actual physical extents and resolution. All the models use the same
+ * descriptor with different extents for the unused report ID.
+ *
+ * Here it is:
+ *
+ * Usage Page (Digitizer), ; Digitizer (0Dh)
+ * Usage (Pen), ; Pen (02h, application collection)
+ * Collection (Application),
+ * Report ID (7),
+ * Usage (Stylus), ; Stylus (20h, logical collection)
+ * Collection (Physical),
+ * Usage (Tip Switch), ; Tip switch (42h, momentary control)
+ * Usage (Barrel Switch), ; Barrel switch (44h, momentary control)
+ * Usage (Eraser), ; Eraser (45h, momentary control)
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Size (1),
+ * Report Count (3),
+ * Input (Variable),
+ * Report Count (3),
+ * Input (Constant, Variable),
+ * Usage (In Range), ; In range (32h, momentary control)
+ * Report Count (1),
+ * Input (Variable),
+ * Report Count (1),
+ * Input (Constant, Variable),
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (X), ; X (30h, dynamic value)
+ * Report Size (16),
+ * Report Count (1),
+ * Push,
+ * Unit Exponent (13),
+ * Unit (Inch^3),
+ * Physical Minimum (0),
+ * Physical Maximum (Xpm),
+ * Logical Maximum (Xlm),
+ * Input (Variable),
+ * Usage (Y), ; Y (31h, dynamic value)
+ * Physical Maximum (Ypm),
+ * Logical Maximum (Ylm),
+ * Input (Variable),
+ * Pop,
+ * Usage Page (Digitizer), ; Digitizer (0Dh)
+ * Usage (Tip Pressure), ; Tip pressure (30h, dynamic value)
+ * Logical Maximum (1023),
+ * Input (Variable),
+ * Report Size (16),
+ * End Collection,
+ * End Collection,
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (Mouse), ; Mouse (02h, application collection)
+ * Collection (Application),
+ * Report ID (8),
+ * Usage (Pointer), ; Pointer (01h, physical collection)
+ * Collection (Physical),
+ * Usage Page (Button), ; Button (09h)
+ * Usage Minimum (01h),
+ * Usage Maximum (03h),
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Count (3),
+ * Report Size (1),
+ * Input (Variable),
+ * Report Count (5),
+ * Input (Constant),
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (X), ; X (30h, dynamic value)
+ * Usage (Y), ; Y (31h, dynamic value)
+ * Usage (Wheel), ; Wheel (38h, dynamic value)
+ * Usage (00h),
+ * Logical Minimum (-127),
+ * Logical Maximum (127),
+ * Report Size (8),
+ * Report Count (4),
+ * Input (Variable, Relative),
+ * End Collection,
+ * End Collection,
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (Mouse), ; Mouse (02h, application collection)
+ * Collection (Application),
+ * Report ID (9),
+ * Usage (Pointer), ; Pointer (01h, physical collection)
+ * Collection (Physical),
+ * Usage Page (Button), ; Button (09h)
+ * Usage Minimum (01h),
+ * Usage Maximum (03h),
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Count (3),
+ * Report Size (1),
+ * Input (Variable),
+ * Report Count (5),
+ * Input (Constant),
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (X), ; X (30h, dynamic value)
+ * Usage (Y), ; Y (31h, dynamic value)
+ * Logical Minimum (0),
+ * Logical Maximum (32767),
+ * Physical Minimum (0),
+ * Physical Maximum (32767),
+ * Report Count (2),
+ * Report Size (16),
+ * Input (Variable),
+ * Usage Page (Digitizer), ; Digitizer (0Dh)
+ * Usage (Tip Pressure), ; Tip pressure (30h, dynamic value)
+ * Logical Maximum (1023),
+ * Report Count (1),
+ * Report Size (16),
+ * Input (Variable),
+ * End Collection,
+ * End Collection
+ *
+ * Here are the extents values for the WPXXXXU models:
+ *
+ * Xpm Xlm Ypm Ylm
+ * WP4030U 4000 8000 3000 6000
+ * WP5540U 5500 11000 4000 8000
+ * WP8060U 8000 16000 6000 12000
+ *
+ * This suggests that all of them have 2000 LPI resolution, as advertised.
+ */
+
+/* Size of the original descriptor of WPXXXXU tablets */
+#define WPXXXXU_RDESC_ORIG_SIZE 212
+
+/*
+ * Fixed WP4030U report descriptor.
+ * Although the hardware might actually support it, the mouse description
+ * has been removed, since there seems to be no devices having one and it
+ * wouldn't make much sense because of the working area size.
+ */
+static __u8 wp4030u_rdesc_fixed[] = {
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x02, /* Usage (Pen), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x09, /* Report ID (9), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xA0, /* Collection (Physical), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x05, /* Report Count (5), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x14, /* Logical Minimum (0), */
+ 0xA4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x34, /* Physical Minimum (0), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0xA0, 0x0F, /* Physical Maximum (4000), */
+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x46, 0xB8, 0x0B, /* Physical Maximum (3000), */
+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
+
+/* Fixed WP5540U report descriptor */
+static __u8 wp5540u_rdesc_fixed[] = {
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x02, /* Usage (Pen), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x09, /* Report ID (9), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xA0, /* Collection (Physical), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x05, /* Report Count (5), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x14, /* Logical Minimum (0), */
+ 0xA4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x34, /* Physical Minimum (0), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0x7C, 0x15, /* Physical Maximum (5500), */
+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x46, 0xA0, 0x0F, /* Physical Maximum (4000), */
+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0, /* End Collection, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x02, /* Usage (Mouse), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x08, /* Report ID (8), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0xA0, /* Collection (Physical), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x05, 0x09, /* Usage Page (Button), */
+ 0x19, 0x01, /* Usage Minimum (01h), */
+ 0x29, 0x03, /* Usage Maximum (03h), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x05, /* Report Count (5), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x15, 0x81, /* Logical Minimum (-127), */
+ 0x25, 0x7F, /* Logical Maximum (127), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x09, 0x38, /* Usage (Wheel), */
+ 0x15, 0xFF, /* Logical Minimum (-1), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
+
+/* Fixed WP8060U report descriptor */
+static __u8 wp8060u_rdesc_fixed[] = {
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x02, /* Usage (Pen), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x09, /* Report ID (9), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xA0, /* Collection (Physical), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x05, /* Report Count (5), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x14, /* Logical Minimum (0), */
+ 0xA4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x34, /* Physical Minimum (0), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */
+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x46, 0x70, 0x17, /* Physical Maximum (6000), */
+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0, /* End Collection, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x02, /* Usage (Mouse), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x08, /* Report ID (8), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0xA0, /* Collection (Physical), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x05, 0x09, /* Usage Page (Button), */
+ 0x19, 0x01, /* Usage Minimum (01h), */
+ 0x29, 0x03, /* Usage Maximum (03h), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x05, /* Report Count (5), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x15, 0x81, /* Logical Minimum (-127), */
+ 0x25, 0x7F, /* Logical Maximum (127), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x09, 0x38, /* Usage (Wheel), */
+ 0x15, 0xFF, /* Logical Minimum (-1), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
+
+/*
+ * Original PF1209 report descriptor.
+ *
+ * The descriptor is similar to WPXXXXU descriptors, with an addition of a
+ * feature report (ID 4) of unknown purpose.
+ *
+ * Although the advertised resolution is 4000 LPI the unused report ID
+ * (taken from WPXXXXU, it seems) states 2000 LPI, but it is probably
+ * incorrect and is a result of blind copying without understanding. Anyway
+ * the real logical extents are always scaled to 0..32767, which IMHO spoils
+ * the precision.
+ *
+ * Usage Page (Digitizer), ; Digitizer (0Dh)
+ * Usage (Pen), ; Pen (02h, application collection)
+ * Collection (Application),
+ * Report ID (7),
+ * Usage (Stylus), ; Stylus (20h, logical collection)
+ * Collection (Physical),
+ * Usage (Tip Switch), ; Tip switch (42h, momentary control)
+ * Usage (Barrel Switch), ; Barrel switch (44h, momentary control)
+ * Usage (Eraser), ; Eraser (45h, momentary control)
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Size (1),
+ * Report Count (3),
+ * Input (Variable),
+ * Report Count (3),
+ * Input (Constant, Variable),
+ * Usage (In Range), ; In range (32h, momentary control)
+ * Report Count (1),
+ * Input (Variable),
+ * Report Count (1),
+ * Input (Constant, Variable),
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (X), ; X (30h, dynamic value)
+ * Report Size (16),
+ * Report Count (1),
+ * Push,
+ * Unit Exponent (13),
+ * Unit (Inch^3),
+ * Physical Minimum (0),
+ * Physical Maximum (12000),
+ * Logical Maximum (24000),
+ * Input (Variable),
+ * Usage (Y), ; Y (31h, dynamic value)
+ * Physical Maximum (9000),
+ * Logical Maximum (18000),
+ * Input (Variable),
+ * Pop,
+ * Usage Page (Digitizer), ; Digitizer (0Dh)
+ * Usage (Tip Pressure), ; Tip pressure (30h, dynamic value)
+ * Logical Maximum (1023),
+ * Input (Variable),
+ * Report Size (16),
+ * End Collection,
+ * End Collection,
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (Mouse), ; Mouse (02h, application collection)
+ * Collection (Application),
+ * Report ID (8),
+ * Usage (Pointer), ; Pointer (01h, physical collection)
+ * Collection (Physical),
+ * Usage Page (Button), ; Button (09h)
+ * Usage Minimum (01h),
+ * Usage Maximum (03h),
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Count (3),
+ * Report Size (1),
+ * Input (Variable),
+ * Report Count (5),
+ * Input (Constant),
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (X), ; X (30h, dynamic value)
+ * Usage (Y), ; Y (31h, dynamic value)
+ * Usage (Wheel), ; Wheel (38h, dynamic value)
+ * Usage (00h),
+ * Logical Minimum (-127),
+ * Logical Maximum (127),
+ * Report Size (8),
+ * Report Count (4),
+ * Input (Variable, Relative),
+ * End Collection,
+ * End Collection,
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (Mouse), ; Mouse (02h, application collection)
+ * Collection (Application),
+ * Report ID (9),
+ * Usage (Pointer), ; Pointer (01h, physical collection)
+ * Collection (Physical),
+ * Usage Page (Button), ; Button (09h)
+ * Usage Minimum (01h),
+ * Usage Maximum (03h),
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Count (3),
+ * Report Size (1),
+ * Input (Variable),
+ * Report Count (5),
+ * Input (Constant),
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (X), ; X (30h, dynamic value)
+ * Usage (Y), ; Y (31h, dynamic value)
+ * Logical Minimum (0),
+ * Logical Maximum (32767),
+ * Physical Minimum (0),
+ * Physical Maximum (32767),
+ * Report Count (2),
+ * Report Size (16),
+ * Input (Variable),
+ * Usage Page (Digitizer), ; Digitizer (0Dh)
+ * Usage (Tip Pressure), ; Tip pressure (30h, dynamic value)
+ * Logical Maximum (1023),
+ * Report Count (1),
+ * Report Size (16),
+ * Input (Variable),
+ * End Collection,
+ * End Collection,
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (00h),
+ * Collection (Application),
+ * Report ID (4),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Usage (00h),
+ * Report Size (8),
+ * Report Count (3),
+ * Feature (Variable),
+ * End Collection
+ */
+
+/* Size of the original descriptor of PF1209 tablet */
+#define PF1209_RDESC_ORIG_SIZE 234
+
+/*
+ * Fixed PF1209 report descriptor
+ *
+ * The descriptor is fixed similarly to WP5540U and WP8060U, plus the
+ * feature report is removed, because its purpose is unknown and it is of no
+ * use to the generic HID driver anyway for now.
+ */
+static __u8 pf1209_rdesc_fixed[] = {
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x02, /* Usage (Pen), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x09, /* Report ID (9), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xA0, /* Collection (Physical), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x05, /* Report Count (5), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x14, /* Logical Minimum (0), */
+ 0xA4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x34, /* Physical Minimum (0), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0xE0, 0x2E, /* Physical Maximum (12000), */
+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x46, 0x28, 0x23, /* Physical Maximum (9000), */
+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0, /* End Collection, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x02, /* Usage (Mouse), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x08, /* Report ID (8), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0xA0, /* Collection (Physical), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x05, 0x09, /* Usage Page (Button), */
+ 0x19, 0x01, /* Usage Minimum (01h), */
+ 0x29, 0x03, /* Usage Maximum (03h), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x05, /* Report Count (5), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x15, 0x81, /* Logical Minimum (-127), */
+ 0x25, 0x7F, /* Logical Maximum (127), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x09, 0x38, /* Usage (Wheel), */
+ 0x15, 0xFF, /* Logical Minimum (-1), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
+
+static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ switch (hdev->product) {
+ case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
+ if (*rsize == PF1209_RDESC_ORIG_SIZE) {
+ rdesc = pf1209_rdesc_fixed;
+ *rsize = sizeof(pf1209_rdesc_fixed);
+ }
+ break;
+ case USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U:
+ if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
+ rdesc = wp4030u_rdesc_fixed;
+ *rsize = sizeof(wp4030u_rdesc_fixed);
+ }
+ break;
+ case USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U:
+ if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
+ rdesc = wp5540u_rdesc_fixed;
+ *rsize = sizeof(wp5540u_rdesc_fixed);
+ }
+ break;
+ case USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U:
+ if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
+ rdesc = wp8060u_rdesc_fixed;
+ *rsize = sizeof(wp8060u_rdesc_fixed);
+ }
+ break;
+ }
+
+ return rdesc;
+}
+
+static const struct hid_device_id uclogic_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
+ USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
+ USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
+ USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
+ USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, uclogic_devices);
+
+static struct hid_driver uclogic_driver = {
+ .name = "uclogic",
+ .id_table = uclogic_devices,
+ .report_fixup = uclogic_report_fixup,
+};
+
+static int __init uclogic_init(void)
+{
+ return hid_register_driver(&uclogic_driver);
+}
+
+static void __exit uclogic_exit(void)
+{
+ hid_unregister_driver(&uclogic_driver);
+}
+
+module_init(uclogic_init);
+module_exit(uclogic_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-waltop.c b/drivers/hid/hid-waltop.c
new file mode 100644
index 000000000000..b3a4163f2e67
--- /dev/null
+++ b/drivers/hid/hid-waltop.c
@@ -0,0 +1,1099 @@
+/*
+ * HID driver for Waltop devices not fully compliant with HID standard
+ *
+ * Copyright (c) 2010 Nikolai Kondrashov
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/*
+ * There exists an official driver on the manufacturer's website, which
+ * wasn't submitted to the kernel, for some reason. The official driver
+ * doesn't seem to support extra features of some tablets, like wheels.
+ *
+ * It shows that the feature report ID 2 could be used to control any waltop
+ * tablet input mode, switching it between "default", "tablet" and "ink".
+ *
+ * This driver only uses "default" mode for all the supported tablets. This
+ * mode tries to be HID-compatible (not very successfully), but cripples the
+ * resolution of some tablets.
+ *
+ * The "tablet" mode uses some proprietary, yet decipherable protocol, which
+ * represents the correct resolution, but is possibly HID-incompatible (i.e.
+ * indescribable by a report descriptor).
+ *
+ * The purpose of the "ink" mode is unknown.
+ *
+ * The feature reports needed for switching to each mode are these:
+ *
+ * 02 16 00 default
+ * 02 16 01 tablet
+ * 02 16 02 ink
+ */
+
+/*
+ * Original Slim Tablet 5.8 inch report descriptor.
+ *
+ * All the reports except the report with ID 16 (the stylus) are unused,
+ * possibly because the tablet is not configured to, or because they were
+ * just copied from a more capable model. The full purpose of features
+ * described for report ID 2 is unknown.
+ *
+ * The stylus buttons are described as three bit fields, whereas actually
+ * it's an "array", i.e. they're reported as button numbers (1, 2 and 3).
+ * The "eraser" field is not used. There is also a "push" without a "pop" in
+ * the stylus description.
+ *
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (Mouse), ; Mouse (02h, application collection)
+ * Collection (Application),
+ * Report ID (1),
+ * Usage (Pointer), ; Pointer (01h, physical collection)
+ * Collection (Physical),
+ * Usage Page (Button), ; Button (09h)
+ * Usage Minimum (01h),
+ * Usage Maximum (05h),
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Size (1),
+ * Report Count (5),
+ * Input (Variable),
+ * Report Size (3),
+ * Report Count (1),
+ * Input (Constant, Variable),
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (X), ; X (30h, dynamic value)
+ * Usage (Y), ; Y (31h, dynamic value)
+ * Usage (Wheel), ; Wheel (38h, dynamic value)
+ * Logical Minimum (-127),
+ * Logical Maximum (127),
+ * Report Size (8),
+ * Report Count (3),
+ * Input (Variable, Relative),
+ * End Collection,
+ * End Collection,
+ * Usage Page (Digitizer), ; Digitizer (0Dh)
+ * Usage (Pen), ; Pen (02h, application collection)
+ * Collection (Application),
+ * Report ID (2),
+ * Usage (Stylus), ; Stylus (20h, logical collection)
+ * Collection (Physical),
+ * Usage (00h),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (7),
+ * Input (Variable),
+ * Usage (Azimuth), ; Azimuth (3Fh, dynamic value)
+ * Usage (Altitude), ; Altitude (40h, dynamic value)
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (2),
+ * Feature (Variable),
+ * End Collection,
+ * Report ID (5),
+ * Usage Page (Digitizer), ; Digitizer (0Dh)
+ * Usage (Stylus), ; Stylus (20h, logical collection)
+ * Collection (Physical),
+ * Usage (00h),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (7),
+ * Input (Variable),
+ * End Collection,
+ * Report ID (10),
+ * Usage Page (Digitizer), ; Digitizer (0Dh)
+ * Usage (Stylus), ; Stylus (20h, logical collection)
+ * Collection (Physical),
+ * Usage (00h),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (3),
+ * Input (Variable),
+ * End Collection,
+ * Report ID (16),
+ * Usage (Stylus), ; Stylus (20h, logical collection)
+ * Collection (Physical),
+ * Usage (Tip Switch), ; Tip switch (42h, momentary control)
+ * Usage (Barrel Switch), ; Barrel switch (44h, momentary control)
+ * Usage (Invert), ; Invert (3Ch, momentary control)
+ * Usage (Eraser), ; Eraser (45h, momentary control)
+ * Usage (In Range), ; In range (32h, momentary control)
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Size (1),
+ * Report Count (5),
+ * Input (Variable),
+ * Report Count (3),
+ * Input (Constant, Variable),
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (X), ; X (30h, dynamic value)
+ * Report Size (16),
+ * Report Count (1),
+ * Push,
+ * Unit Exponent (13),
+ * Unit (Inch^3),
+ * Logical Minimum (0),
+ * Logical Maximum (10000),
+ * Physical Minimum (0),
+ * Physical Maximum (10000),
+ * Input (Variable),
+ * Usage (Y), ; Y (31h, dynamic value)
+ * Logical Maximum (6000),
+ * Physical Maximum (6000),
+ * Input (Variable),
+ * Usage Page (Digitizer), ; Digitizer (0Dh)
+ * Usage (Tip Pressure), ; Tip pressure (30h, dynamic value)
+ * Logical Minimum (0),
+ * Logical Maximum (1023),
+ * Physical Minimum (0),
+ * Physical Maximum (1023),
+ * Input (Variable),
+ * End Collection,
+ * End Collection
+ */
+
+/* Size of the original report descriptor of Slim Tablet 5.8 inch */
+#define SLIM_TABLET_5_8_INCH_RDESC_ORIG_SIZE 222
+
+/*
+ * Fixed Slim Tablet 5.8 inch descriptor.
+ *
+ * All the reports except the stylus report (ID 16) were removed as unused.
+ * The stylus buttons description was fixed.
+ */
+static __u8 slim_tablet_5_8_inch_rdesc_fixed[] = {
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x02, /* Usage (Pen), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x10, /* Report ID (16), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xA0, /* Collection (Physical), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x15, 0x01, /* Logical Minimum (1), */
+ 0x25, 0x03, /* Logical Maximum (3), */
+ 0x75, 0x04, /* Report Size (4), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x80, /* Input, */
+ 0x09, 0x32, /* Usage (In Range), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x14, /* Logical Minimum (0), */
+ 0xA4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x34, /* Physical Minimum (0), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0x88, 0x13, /* Physical Maximum (5000), */
+ 0x26, 0x10, 0x27, /* Logical Maximum (10000), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x46, 0xB8, 0x0B, /* Physical Maximum (3000), */
+ 0x26, 0x70, 0x17, /* Logical Maximum (6000), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
+
+/*
+ * Original Slim Tablet 12.1 inch report descriptor.
+ *
+ * The descriptor is similar to the Slim Tablet 5.8 inch descriptor with the
+ * addition of a keyboard report, seemingly unused. It may have get here
+ * from a Media Tablet - probably an unimplemented feature.
+ *
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (Mouse), ; Mouse (02h, application collection)
+ * Collection (Application),
+ * Report ID (1),
+ * Usage (Pointer), ; Pointer (01h, physical collection)
+ * Collection (Physical),
+ * Usage Page (Button), ; Button (09h)
+ * Usage Minimum (01h),
+ * Usage Maximum (05h),
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Size (1),
+ * Report Count (5),
+ * Input (Variable),
+ * Report Size (3),
+ * Report Count (1),
+ * Input (Constant, Variable),
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (X), ; X (30h, dynamic value)
+ * Usage (Y), ; Y (31h, dynamic value)
+ * Usage (Wheel), ; Wheel (38h, dynamic value)
+ * Logical Minimum (-127),
+ * Logical Maximum (127),
+ * Report Size (8),
+ * Report Count (3),
+ * Input (Variable, Relative),
+ * End Collection,
+ * End Collection,
+ * Usage Page (Digitizer), ; Digitizer (0Dh)
+ * Usage (Pen), ; Pen (02h, application collection)
+ * Collection (Application),
+ * Report ID (2),
+ * Usage (Stylus), ; Stylus (20h, logical collection)
+ * Collection (Physical),
+ * Usage (00h),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (7),
+ * Input (Variable),
+ * Usage (Azimuth), ; Azimuth (3Fh, dynamic value)
+ * Usage (Altitude), ; Altitude (40h, dynamic value)
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (2),
+ * Feature (Variable),
+ * End Collection,
+ * Report ID (5),
+ * Usage Page (Digitizer), ; Digitizer (0Dh)
+ * Usage (Stylus), ; Stylus (20h, logical collection)
+ * Collection (Physical),
+ * Usage (00h),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (7),
+ * Input (Variable),
+ * End Collection,
+ * Report ID (10),
+ * Usage Page (Digitizer), ; Digitizer (0Dh)
+ * Usage (Stylus), ; Stylus (20h, logical collection)
+ * Collection (Physical),
+ * Usage (00h),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (3),
+ * Input (Variable),
+ * End Collection,
+ * Report ID (16),
+ * Usage (Stylus), ; Stylus (20h, logical collection)
+ * Collection (Physical),
+ * Usage (Tip Switch), ; Tip switch (42h, momentary control)
+ * Usage (Barrel Switch), ; Barrel switch (44h, momentary control)
+ * Usage (Invert), ; Invert (3Ch, momentary control)
+ * Usage (Eraser), ; Eraser (45h, momentary control)
+ * Usage (In Range), ; In range (32h, momentary control)
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Size (1),
+ * Report Count (5),
+ * Input (Variable),
+ * Report Count (3),
+ * Input (Constant, Variable),
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (X), ; X (30h, dynamic value)
+ * Report Size (16),
+ * Report Count (1),
+ * Push,
+ * Unit Exponent (13),
+ * Unit (Inch^3),
+ * Logical Minimum (0),
+ * Logical Maximum (20000),
+ * Physical Minimum (0),
+ * Physical Maximum (20000),
+ * Input (Variable),
+ * Usage (Y), ; Y (31h, dynamic value)
+ * Logical Maximum (12500),
+ * Physical Maximum (12500),
+ * Input (Variable),
+ * Usage Page (Digitizer), ; Digitizer (0Dh)
+ * Usage (Tip Pressure), ; Tip pressure (30h, dynamic value)
+ * Logical Minimum (0),
+ * Logical Maximum (1023),
+ * Physical Minimum (0),
+ * Physical Maximum (1023),
+ * Input (Variable),
+ * End Collection,
+ * End Collection,
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (Keyboard), ; Keyboard (06h, application collection)
+ * Collection (Application),
+ * Report ID (13),
+ * Usage Page (Keyboard), ; Keyboard/keypad (07h)
+ * Usage Minimum (KB Leftcontrol), ; Keyboard left control
+ * ; (E0h, dynamic value)
+ * Usage Maximum (KB Right GUI), ; Keyboard right GUI (E7h, dynamic value)
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Size (1),
+ * Report Count (8),
+ * Input (Variable),
+ * Report Size (8),
+ * Report Count (1),
+ * Input (Constant),
+ * Usage Page (Keyboard), ; Keyboard/keypad (07h)
+ * Usage Minimum (None), ; No event (00h, selector)
+ * Usage Maximum (KB Application), ; Keyboard Application (65h, selector)
+ * Logical Minimum (0),
+ * Logical Maximum (101),
+ * Report Size (8),
+ * Report Count (5),
+ * Input,
+ * End Collection
+ */
+
+/* Size of the original report descriptor of Slim Tablet 12.1 inch */
+#define SLIM_TABLET_12_1_INCH_RDESC_ORIG_SIZE 269
+
+/*
+ * Fixed Slim Tablet 12.1 inch descriptor.
+ *
+ * All the reports except the stylus report (ID 16) were removed as unused.
+ * The stylus buttons description was fixed.
+ */
+static __u8 slim_tablet_12_1_inch_rdesc_fixed[] = {
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x02, /* Usage (Pen), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x10, /* Report ID (16), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xA0, /* Collection (Physical), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x15, 0x01, /* Logical Minimum (1), */
+ 0x25, 0x03, /* Logical Maximum (3), */
+ 0x75, 0x04, /* Report Size (4), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x80, /* Input, */
+ 0x09, 0x32, /* Usage (In Range), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x14, /* Logical Minimum (0), */
+ 0xA4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x34, /* Physical Minimum (0), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0x10, 0x27, /* Physical Maximum (10000), */
+ 0x26, 0x20, 0x4E, /* Logical Maximum (20000), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x46, 0x6A, 0x18, /* Physical Maximum (6250), */
+ 0x26, 0xD4, 0x30, /* Logical Maximum (12500), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
+
+/*
+ * Original Media Tablet 10.6 inch report descriptor.
+ *
+ * There are at least two versions of this model in the wild. They are
+ * represented by Genius G-Pen M609 (older version) and Genius G-Pen M609X
+ * (newer version).
+ *
+ * Both versions have the usual pen with two barrel buttons and two
+ * identical wheels with center buttons in the top corners of the tablet
+ * base. They also have buttons on the top, between the wheels, for
+ * selecting the wheels' functions and wide/standard mode. In the wide mode
+ * the whole working surface is sensed, in the standard mode a narrower area
+ * is sensed, but the logical report extents remain the same. These modes
+ * correspond roughly to 16:9 and 4:3 aspect ratios respectively.
+ *
+ * The older version has three wheel function buttons ("scroll", "zoom" and
+ * "volume") and two separate buttons for wide and standard mode. The newer
+ * version has four wheel function buttons (plus "brush") and only one
+ * button is used for selecting wide/standard mode. So, the total number of
+ * buttons remains the same, but one of the mode buttons is repurposed as a
+ * wheels' function button in the newer version.
+ *
+ * The wheel functions are:
+ * scroll - the wheels act as scroll wheels, the center buttons switch
+ * between vertical and horizontal scrolling;
+ * zoom - the wheels zoom in/out, the buttons supposedly reset to 100%;
+ * volume - the wheels control the sound volume, the buttons mute;
+ * brush - the wheels are supposed to control brush width in a graphics
+ * editor, the buttons do nothing.
+ *
+ * Below is the newer version's report descriptor. It may very well be that
+ * the older version's descriptor is different and thus it won't be
+ * supported.
+ *
+ * The mouse report (ID 1) only uses the wheel field for reporting the tablet
+ * wheels' scroll mode. The keyboard report (ID 13) is used to report the
+ * wheels' zoom and brush control functions as key presses. The report ID 12
+ * is used to report the wheels' volume control functions. The stylus report
+ * (ID 16) has the same problems as the Slim Tablet 5.8 inch report has.
+ *
+ * The rest of the reports are unused, at least in the default configuration.
+ * The purpose of the features is unknown.
+ *
+ * Usage Page (Desktop),
+ * Usage (Mouse),
+ * Collection (Application),
+ * Report ID (1),
+ * Usage (Pointer),
+ * Collection (Physical),
+ * Usage Page (Button),
+ * Usage Minimum (01h),
+ * Usage Maximum (05h),
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Size (1),
+ * Report Count (5),
+ * Input (Variable),
+ * Report Size (3),
+ * Report Count (1),
+ * Input (Constant, Variable),
+ * Usage Page (Desktop),
+ * Usage (X),
+ * Usage (Y),
+ * Usage (Wheel),
+ * Logical Minimum (-127),
+ * Logical Maximum (127),
+ * Report Size (8),
+ * Report Count (3),
+ * Input (Variable, Relative),
+ * End Collection,
+ * End Collection,
+ * Usage Page (Digitizer),
+ * Usage (Pen),
+ * Collection (Application),
+ * Report ID (2),
+ * Usage (Stylus),
+ * Collection (Physical),
+ * Usage (00h),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (7),
+ * Input (Variable),
+ * Usage (Azimuth),
+ * Usage (Altitude),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (2),
+ * Feature (Variable),
+ * End Collection,
+ * Report ID (5),
+ * Usage Page (Digitizer),
+ * Usage (Stylus),
+ * Collection (Physical),
+ * Usage (00h),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (7),
+ * Input (Variable),
+ * End Collection,
+ * Report ID (10),
+ * Usage Page (Digitizer),
+ * Usage (Stylus),
+ * Collection (Physical),
+ * Usage (00h),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (7),
+ * Input (Variable),
+ * End Collection,
+ * Report ID (16),
+ * Usage (Stylus),
+ * Collection (Physical),
+ * Usage (Tip Switch),
+ * Usage (Barrel Switch),
+ * Usage (Invert),
+ * Usage (Eraser),
+ * Usage (In Range),
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Size (1),
+ * Report Count (5),
+ * Input (Variable),
+ * Report Count (3),
+ * Input (Constant, Variable),
+ * Usage Page (Desktop),
+ * Usage (X),
+ * Report Size (16),
+ * Report Count (1),
+ * Push,
+ * Unit Exponent (13),
+ * Unit (Inch^3),
+ * Logical Minimum (0),
+ * Logical Maximum (18000),
+ * Physical Minimum (0),
+ * Physical Maximum (18000),
+ * Input (Variable),
+ * Usage (Y),
+ * Logical Maximum (11000),
+ * Physical Maximum (11000),
+ * Input (Variable),
+ * Usage Page (Digitizer),
+ * Usage (Tip Pressure),
+ * Logical Minimum (0),
+ * Logical Maximum (1023),
+ * Physical Minimum (0),
+ * Physical Maximum (1023),
+ * Input (Variable),
+ * End Collection,
+ * End Collection,
+ * Usage Page (Desktop),
+ * Usage (Keyboard),
+ * Collection (Application),
+ * Report ID (13),
+ * Usage Page (Keyboard),
+ * Usage Minimum (KB Leftcontrol),
+ * Usage Maximum (KB Right GUI),
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Size (1),
+ * Report Count (8),
+ * Input (Variable),
+ * Report Size (8),
+ * Report Count (1),
+ * Input (Constant),
+ * Usage Page (Keyboard),
+ * Usage Minimum (None),
+ * Usage Maximum (KB Application),
+ * Logical Minimum (0),
+ * Logical Maximum (101),
+ * Report Size (8),
+ * Report Count (5),
+ * Input,
+ * End Collection,
+ * Usage Page (Consumer),
+ * Usage (Consumer Control),
+ * Collection (Application),
+ * Report ID (12),
+ * Usage (Volume Inc),
+ * Usage (Volume Dec),
+ * Usage (Mute),
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Size (1),
+ * Report Count (3),
+ * Input (Variable, Relative),
+ * Report Size (5),
+ * Report Count (1),
+ * Input (Constant, Variable, Relative),
+ * End Collection
+ */
+
+/* Size of the original report descriptor of Media Tablet 10.6 inch */
+#define MEDIA_TABLET_10_6_INCH_RDESC_ORIG_SIZE 300
+
+/*
+ * Fixed Media Tablet 10.6 inch descriptor.
+ *
+ * The descriptions of reports unused in the default configuration are
+ * removed. The stylus report (ID 16) is fixed similarly to Slim Tablet 5.8
+ * inch. The unused mouse report (ID 1) fields are replaced with constant
+ * padding.
+ *
+ * The keyboard report (ID 13) is hacked to instead have an "array" field
+ * reporting consumer page controls, and all the unused bits are masked out
+ * with constant padding. The "brush" wheels' function is represented as "Scan
+ * Previous/Next Track" controls due to the lack of brush controls in the
+ * usage tables specification.
+ */
+static __u8 media_tablet_10_6_inch_rdesc_fixed[] = {
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x02, /* Usage (Pen), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x10, /* Report ID (16), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xA0, /* Collection (Physical), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x15, 0x01, /* Logical Minimum (1), */
+ 0x25, 0x03, /* Logical Maximum (3), */
+ 0x75, 0x04, /* Report Size (4), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x80, /* Input, */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x09, 0x32, /* Usage (In Range), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x14, /* Logical Minimum (0), */
+ 0xA4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x34, /* Physical Minimum (0), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0x28, 0x23, /* Physical Maximum (9000), */
+ 0x26, 0x50, 0x46, /* Logical Maximum (18000), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x46, 0x7C, 0x15, /* Physical Maximum (5500), */
+ 0x26, 0xF8, 0x2A, /* Logical Maximum (11000), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0, /* End Collection, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x02, /* Usage (Mouse), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x01, /* Report ID (1), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0xA0, /* Collection (Physical), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x15, 0xFF, /* Logical Minimum (-1), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x09, 0x38, /* Usage (Wheel), */
+ 0x0B, 0x38, 0x02, /* Usage (Consumer AC Pan), */
+ 0x0C, 0x00,
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0, /* End Collection, */
+ 0x05, 0x0C, /* Usage Page (Consumer), */
+ 0x09, 0x01, /* Usage (Consumer Control), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x0D, /* Report ID (13), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x0A, 0x2F, 0x02, /* Usage (AC Zoom), */
+ 0x0A, 0x2E, 0x02, /* Usage (AC Zoom Out), */
+ 0x0A, 0x2D, 0x02, /* Usage (AC Zoom In), */
+ 0x09, 0xB6, /* Usage (Scan Previous Track), */
+ 0x09, 0xB5, /* Usage (Scan Next Track), */
+ 0x08, /* Usage (00h), */
+ 0x08, /* Usage (00h), */
+ 0x08, /* Usage (00h), */
+ 0x08, /* Usage (00h), */
+ 0x08, /* Usage (00h), */
+ 0x0A, 0x2E, 0x02, /* Usage (AC Zoom Out), */
+ 0x0A, 0x2D, 0x02, /* Usage (AC Zoom In), */
+ 0x15, 0x0C, /* Logical Minimum (12), */
+ 0x25, 0x17, /* Logical Maximum (23), */
+ 0x75, 0x05, /* Report Size (5), */
+ 0x80, /* Input, */
+ 0x75, 0x03, /* Report Size (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x75, 0x20, /* Report Size (32), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0xC0, /* End Collection, */
+ 0x09, 0x01, /* Usage (Consumer Control), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x0C, /* Report ID (12), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x09, 0xE9, /* Usage (Volume Inc), */
+ 0x09, 0xEA, /* Usage (Volume Dec), */
+ 0x09, 0xE2, /* Usage (Mute), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x95, 0x35, /* Report Count (53), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0xC0 /* End Collection */
+};
+
+/*
+ * Original Media Tablet 14.1 inch report descriptor.
+ *
+ * There are at least two versions of this model in the wild. They are
+ * represented by Genius G-Pen M712 (older version) and Genius G-Pen M712X
+ * (newer version). The hardware difference between these versions is the same
+ * as between older and newer versions of Media Tablet 10.6 inch. The report
+ * descriptors are identical for both versions.
+ *
+ * The function, behavior and report descriptor of this tablet is similar to
+ * that of Media Tablet 10.6 inch. However, there is one more field (with
+ * Consumer AC Pan usage) in the mouse description. Then the tablet X and Y
+ * logical extents both get scaled to 0..16383 range (a hardware limit?),
+ * which kind of defeats the advertised 4000 LPI resolution, considering the
+ * physical extents of 12x7.25 inches. Plus, reports 5, 10 and 255 are used
+ * sometimes (while moving the pen) with unknown purpose. Also, the key codes
+ * generated for zoom in/out are different.
+ *
+ * Usage Page (Desktop),
+ * Usage (Mouse),
+ * Collection (Application),
+ * Report ID (1),
+ * Usage (Pointer),
+ * Collection (Physical),
+ * Usage Page (Button),
+ * Usage Minimum (01h),
+ * Usage Maximum (05h),
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Size (1),
+ * Report Count (5),
+ * Input (Variable),
+ * Report Size (3),
+ * Report Count (1),
+ * Input (Constant, Variable),
+ * Usage Page (Desktop),
+ * Usage (X),
+ * Usage (Y),
+ * Usage (Wheel),
+ * Logical Minimum (-127),
+ * Logical Maximum (127),
+ * Report Size (8),
+ * Report Count (3),
+ * Input (Variable, Relative),
+ * Usage Page (Consumer),
+ * Logical Minimum (-127),
+ * Logical Maximum (127),
+ * Report Size (8),
+ * Report Count (1),
+ * Usage (AC Pan),
+ * Input (Variable, Relative),
+ * End Collection,
+ * End Collection,
+ * Usage Page (Digitizer),
+ * Usage (Pen),
+ * Collection (Application),
+ * Report ID (2),
+ * Usage (Stylus),
+ * Collection (Physical),
+ * Usage (00h),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (7),
+ * Input (Variable),
+ * Usage (Azimuth),
+ * Usage (Altitude),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (2),
+ * Feature (Variable),
+ * End Collection,
+ * Report ID (5),
+ * Usage Page (Digitizer),
+ * Usage (Stylus),
+ * Collection (Physical),
+ * Usage (00h),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (7),
+ * Input (Variable),
+ * End Collection,
+ * Report ID (10),
+ * Usage Page (Digitizer),
+ * Usage (Stylus),
+ * Collection (Physical),
+ * Usage (00h),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Report Size (8),
+ * Report Count (7),
+ * Input (Variable),
+ * End Collection,
+ * Report ID (16),
+ * Usage (Stylus),
+ * Collection (Physical),
+ * Usage (Tip Switch),
+ * Usage (Barrel Switch),
+ * Usage (Invert),
+ * Usage (Eraser),
+ * Usage (In Range),
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Size (1),
+ * Report Count (5),
+ * Input (Variable),
+ * Report Count (3),
+ * Input (Constant, Variable),
+ * Usage Page (Desktop),
+ * Usage (X),
+ * Report Size (16),
+ * Report Count (1),
+ * Push,
+ * Unit Exponent (13),
+ * Unit (Inch^3),
+ * Logical Minimum (0),
+ * Logical Maximum (16383),
+ * Physical Minimum (0),
+ * Physical Maximum (16383),
+ * Input (Variable),
+ * Usage (Y),
+ * Input (Variable),
+ * Usage Page (Digitizer),
+ * Usage (Tip Pressure),
+ * Logical Minimum (0),
+ * Logical Maximum (1023),
+ * Physical Minimum (0),
+ * Physical Maximum (1023),
+ * Input (Variable),
+ * End Collection,
+ * End Collection,
+ * Usage Page (Desktop),
+ * Usage (Keyboard),
+ * Collection (Application),
+ * Report ID (13),
+ * Usage Page (Keyboard),
+ * Usage Minimum (KB Leftcontrol),
+ * Usage Maximum (KB Right GUI),
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Size (1),
+ * Report Count (8),
+ * Input (Variable),
+ * Report Size (8),
+ * Report Count (1),
+ * Input (Constant),
+ * Usage Page (Keyboard),
+ * Usage Minimum (None),
+ * Usage Maximum (KB Application),
+ * Logical Minimum (0),
+ * Logical Maximum (101),
+ * Report Size (8),
+ * Report Count (5),
+ * Input,
+ * End Collection,
+ * Usage Page (Consumer),
+ * Usage (Consumer Control),
+ * Collection (Application),
+ * Report ID (12),
+ * Usage (Volume Inc),
+ * Usage (Volume Dec),
+ * Usage (Mute),
+ * Logical Minimum (0),
+ * Logical Maximum (1),
+ * Report Size (1),
+ * Report Count (3),
+ * Input (Variable, Relative),
+ * Report Size (5),
+ * Report Count (1),
+ * Input (Constant, Variable, Relative),
+ * End Collection
+ */
+
+/* Size of the original report descriptor of Media Tablet 14.1 inch */
+#define MEDIA_TABLET_14_1_INCH_RDESC_ORIG_SIZE 309
+
+/*
+ * Fixed Media Tablet 14.1 inch descriptor.
+ * It is fixed similarly to the Media Tablet 10.6 inch descriptor.
+ */
+static __u8 media_tablet_14_1_inch_rdesc_fixed[] = {
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x02, /* Usage (Pen), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x10, /* Report ID (16), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xA0, /* Collection (Physical), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x15, 0x01, /* Logical Minimum (1), */
+ 0x25, 0x03, /* Logical Maximum (3), */
+ 0x75, 0x04, /* Report Size (4), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x80, /* Input, */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x09, 0x32, /* Usage (In Range), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x14, /* Logical Minimum (0), */
+ 0xA4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x34, /* Physical Minimum (0), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0xE0, 0x2E, /* Physical Maximum (12000), */
+ 0x26, 0xFF, 0x3F, /* Logical Maximum (16383), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x46, 0x52, 0x1C, /* Physical Maximum (7250), */
+ 0x26, 0xFF, 0x3F, /* Logical Maximum (16383), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0, /* End Collection, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x02, /* Usage (Mouse), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x01, /* Report ID (1), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0xA0, /* Collection (Physical), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x15, 0xFF, /* Logical Minimum (-1), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x09, 0x38, /* Usage (Wheel), */
+ 0x0B, 0x38, 0x02, /* Usage (Consumer AC Pan), */
+ 0x0C, 0x00,
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0xC0, /* End Collection, */
+ 0xC0, /* End Collection, */
+ 0x05, 0x0C, /* Usage Page (Consumer), */
+ 0x09, 0x01, /* Usage (Consumer Control), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x0D, /* Report ID (13), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x0A, 0x2F, 0x02, /* Usage (AC Zoom), */
+ 0x0A, 0x2E, 0x02, /* Usage (AC Zoom Out), */
+ 0x0A, 0x2D, 0x02, /* Usage (AC Zoom In), */
+ 0x09, 0xB6, /* Usage (Scan Previous Track), */
+ 0x09, 0xB5, /* Usage (Scan Next Track), */
+ 0x08, /* Usage (00h), */
+ 0x08, /* Usage (00h), */
+ 0x08, /* Usage (00h), */
+ 0x08, /* Usage (00h), */
+ 0x08, /* Usage (00h), */
+ 0x0A, 0x2E, 0x02, /* Usage (AC Zoom Out), */
+ 0x0A, 0x2D, 0x02, /* Usage (AC Zoom In), */
+ 0x15, 0x0C, /* Logical Minimum (12), */
+ 0x25, 0x17, /* Logical Maximum (23), */
+ 0x75, 0x05, /* Report Size (5), */
+ 0x80, /* Input, */
+ 0x75, 0x03, /* Report Size (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x75, 0x20, /* Report Size (32), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0xC0, /* End Collection, */
+ 0x09, 0x01, /* Usage (Consumer Control), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x0C, /* Report ID (12), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x09, 0xE9, /* Usage (Volume Inc), */
+ 0x09, 0xEA, /* Usage (Volume Dec), */
+ 0x09, 0xE2, /* Usage (Mute), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x75, 0x05, /* Report Size (5), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0xC0 /* End Collection */
+};
+
+static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ switch (hdev->product) {
+ case USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH:
+ if (*rsize == SLIM_TABLET_5_8_INCH_RDESC_ORIG_SIZE) {
+ rdesc = slim_tablet_5_8_inch_rdesc_fixed;
+ *rsize = sizeof(slim_tablet_5_8_inch_rdesc_fixed);
+ }
+ break;
+ case USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH:
+ if (*rsize == SLIM_TABLET_12_1_INCH_RDESC_ORIG_SIZE) {
+ rdesc = slim_tablet_12_1_inch_rdesc_fixed;
+ *rsize = sizeof(slim_tablet_12_1_inch_rdesc_fixed);
+ }
+ break;
+ case USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH:
+ if (*rsize == MEDIA_TABLET_10_6_INCH_RDESC_ORIG_SIZE) {
+ rdesc = media_tablet_10_6_inch_rdesc_fixed;
+ *rsize = sizeof(media_tablet_10_6_inch_rdesc_fixed);
+ }
+ break;
+ case USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH:
+ if (*rsize == MEDIA_TABLET_14_1_INCH_RDESC_ORIG_SIZE) {
+ rdesc = media_tablet_14_1_inch_rdesc_fixed;
+ *rsize = sizeof(media_tablet_14_1_inch_rdesc_fixed);
+ }
+ break;
+ }
+ return rdesc;
+}
+
+static const struct hid_device_id waltop_devices[] = {
+ { 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) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
+ USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
+ USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, waltop_devices);
+
+static struct hid_driver waltop_driver = {
+ .name = "waltop",
+ .id_table = waltop_devices,
+ .report_fixup = waltop_report_fixup,
+};
+
+static int __init waltop_init(void)
+{
+ return hid_register_driver(&waltop_driver);
+}
+
+static void __exit waltop_exit(void)
+{
+ hid_unregister_driver(&waltop_driver);
+}
+
+module_init(waltop_init);
+module_exit(waltop_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-zydacron.c b/drivers/hid/hid-zydacron.c
index 9e8d35a203e4..aac1f9273149 100644
--- a/drivers/hid/hid-zydacron.c
+++ b/drivers/hid/hid-zydacron.c
@@ -27,10 +27,10 @@ struct zc_device {
* Zydacron remote control has an invalid HID report descriptor,
* that needs fixing before we can parse it.
*/
-static void zc_report_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int rsize)
+static __u8 *zc_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
{
- if (rsize >= 253 &&
+ if (*rsize >= 253 &&
rdesc[0x96] == 0xbc && rdesc[0x97] == 0xff &&
rdesc[0xca] == 0xbc && rdesc[0xcb] == 0xff &&
rdesc[0xe1] == 0xbc && rdesc[0xe2] == 0xff) {
@@ -40,6 +40,7 @@ static void zc_report_fixup(struct hid_device *hdev, __u8 *rdesc,
rdesc[0x96] = rdesc[0xca] = rdesc[0xe1] = 0x0c;
rdesc[0x97] = rdesc[0xcb] = rdesc[0xe2] = 0x00;
}
+ return rdesc;
}
#define zc_map_key_clear(c) \
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 925992f549f0..8a4b32dca9f7 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -218,9 +218,13 @@ static int hidraw_release(struct inode * inode, struct file * file)
unsigned int minor = iminor(inode);
struct hidraw *dev;
struct hidraw_list *list = file->private_data;
+ int ret;
- if (!hidraw_table[minor])
- return -ENODEV;
+ mutex_lock(&minors_lock);
+ if (!hidraw_table[minor]) {
+ ret = -ENODEV;
+ goto unlock;
+ }
list_del(&list->node);
dev = hidraw_table[minor];
@@ -233,10 +237,12 @@ static int hidraw_release(struct inode * inode, struct file * file)
kfree(list->hidraw);
}
}
-
kfree(list);
+ ret = 0;
+unlock:
+ mutex_unlock(&minors_lock);
- return 0;
+ return ret;
}
static long hidraw_ioctl(struct file *file, unsigned int cmd,
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 599041a7f670..5489eab3a6bd 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -807,9 +807,10 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co
struct usb_host_interface *interface = intf->cur_altsetting;
int ret;
- if (usbhid->urbout) {
+ if (usbhid->urbout && report_type != HID_FEATURE_REPORT) {
int actual_length;
int skipped_report_id = 0;
+
if (buf[0] == 0x0) {
/* Don't send the Report ID */
buf++;
@@ -1469,9 +1470,6 @@ static int __init hid_init(void)
retval = usbhid_quirks_init(quirks_param);
if (retval)
goto usbhid_quirks_init_fail;
- retval = hiddev_init();
- if (retval)
- goto hiddev_init_fail;
retval = usb_register(&hid_driver);
if (retval)
goto usb_register_fail;
@@ -1479,8 +1477,6 @@ static int __init hid_init(void)
return 0;
usb_register_fail:
- hiddev_exit();
-hiddev_init_fail:
usbhid_quirks_exit();
usbhid_quirks_init_fail:
hid_unregister_driver(&hid_usb_driver);
@@ -1493,7 +1489,6 @@ no_queue:
static void __exit hid_exit(void)
{
usb_deregister(&hid_driver);
- hiddev_exit();
usbhid_quirks_exit();
hid_unregister_driver(&hid_usb_driver);
destroy_workqueue(resumption_waker);
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index f0260c699adb..2c185477eeb3 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -34,7 +34,6 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER, HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET },
- { USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
@@ -63,6 +62,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET },
@@ -72,6 +72,10 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U, HID_QUIRK_MULTI_INPUT },
+ { 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 },
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index dfcb27613ec5..fedd88df9a18 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -67,8 +67,6 @@ struct hiddev_list {
struct mutex thread_lock;
};
-static struct usb_driver hiddev_driver;
-
/*
* Find a report, given the report's type and ID. The ID can be specified
* indirectly by REPORT_ID_FIRST (which returns the first report of the given
@@ -926,41 +924,3 @@ void hiddev_disconnect(struct hid_device *hid)
kfree(hiddev);
}
}
-
-/* Currently this driver is a USB driver. It's not a conventional one in
- * the sense that it doesn't probe at the USB level. Instead it waits to
- * be connected by HID through the hiddev_connect / hiddev_disconnect
- * routines. The reason to register as a USB device is to gain part of the
- * minor number space from the USB major.
- *
- * In theory, should the HID code be generalized to more than one physical
- * medium (say, IEEE 1384), this driver will probably need to register its
- * own major number, and in doing so, no longer need to register with USB.
- * At that point the probe routine and hiddev_driver struct below will no
- * longer be useful.
- */
-
-
-/* We never attach in this manner, and rely on HID to connect us. This
- * is why there is no disconnect routine defined in the usb_driver either.
- */
-static int hiddev_usbd_probe(struct usb_interface *intf,
- const struct usb_device_id *hiddev_info)
-{
- return -ENODEV;
-}
-
-static /* const */ struct usb_driver hiddev_driver = {
- .name = "hiddev",
- .probe = hiddev_usbd_probe,
-};
-
-int __init hiddev_init(void)
-{
- return usb_register(&hiddev_driver);
-}
-
-void hiddev_exit(void)
-{
- usb_deregister(&hiddev_driver);
-}
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 97499d00615a..c357c835eb1e 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -399,6 +399,15 @@ config SENSORS_GL520SM
This driver can also be built as a module. If so, the module
will be called gl520sm.
+config SENSORS_GPIO_FAN
+ tristate "GPIO fan"
+ depends on GENERIC_GPIO
+ help
+ If you say yes here you get support for fans connected to GPIO lines.
+
+ This driver can also be built as a module. If so, the module
+ will be called gpio-fan.
+
config SENSORS_CORETEMP
tristate "Intel Core/Core2/Atom temperature sensor"
depends on X86 && PCI && EXPERIMENTAL
@@ -654,6 +663,17 @@ config SENSORS_LTC4245
This driver can also be built as a module. If so, the module will
be called ltc4245.
+config SENSORS_LTC4261
+ tristate "Linear Technology LTC4261"
+ depends on I2C && EXPERIMENTAL
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC4261
+ Negative Voltage Hot Swap Controller I2C interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc4261.
+
config SENSORS_LM95241
tristate "National Semiconductor LM95241 sensor chip"
depends on I2C
@@ -1088,26 +1108,6 @@ config SENSORS_ULTRA45
This driver provides support for the Ultra45 workstation environmental
sensors.
-config SENSORS_HDAPS
- tristate "IBM Hard Drive Active Protection System (hdaps)"
- depends on INPUT && X86
- select INPUT_POLLDEV
- default n
- help
- This driver provides support for the IBM Hard Drive Active Protection
- System (hdaps), which provides an accelerometer and other misc. data.
- ThinkPads starting with the R50, T41, and X40 are supported. The
- accelerometer data is readable via sysfs.
-
- This driver also provides an absolute input class device, allowing
- the laptop to act as a pinball machine-esque joystick.
-
- If your ThinkPad is not recognized by the driver, please update to latest
- BIOS. This is especially the case for some R52 ThinkPads.
-
- Say Y here if you have an applicable laptop and want to experience
- the awesome power of hdaps.
-
config SENSORS_LIS3_SPI
tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
depends on !ACPI && SPI_MASTER && INPUT
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index e3c2484f6c5f..d30f0f6870e0 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -51,8 +51,8 @@ obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o
obj-$(CONFIG_SENSORS_G760A) += g760a.o
obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
+obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o
obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
-obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
@@ -80,6 +80,7 @@ obj-$(CONFIG_SENSORS_LM93) += lm93.o
obj-$(CONFIG_SENSORS_LM95241) += lm95241.o
obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o
obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o
+obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o
obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c
index 251b63165e2a..60befc0ee65f 100644
--- a/drivers/hwmon/adm1025.c
+++ b/drivers/hwmon/adm1025.c
@@ -12,7 +12,7 @@
* resolution of about 0.5% of the nominal value). Temperature values are
* reported with a 1 deg resolution and a 3 deg accuracy. Complete
* datasheet can be obtained from Analog's website at:
- * http://www.analog.com/Analog_Root/productPage/productHome/0,2121,ADM1025,00.html
+ * http://www.onsemi.com/PowerSolutions/product.do?id=ADM1025
*
* This driver also supports the ADM1025A, which differs from the ADM1025
* only in that it has "open-drain VID inputs while the ADM1025 has
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index 65335b268fa9..4bf969c0a32b 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -6,7 +6,7 @@
Chip details at:
- <http://www.analog.com/UploadedFiles/Data_Sheets/779263102ADM1026_a.pdf>
+ <http://www.onsemi.com/PowerSolutions/product.do?id=ADM1026>
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/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index a23b17a78ace..42de98d73ff5 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -21,7 +21,6 @@
*/
#include <linux/module.h>
-#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
@@ -280,11 +279,9 @@ static int __devinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
case 0x1a:
dev_warn(dev, "TjMax is assumed as 100 C!\n");
return 100000;
- break;
case 0x17:
case 0x1c: /* Atom CPUs */
return adjust_tjmax(c, id, dev);
- break;
default:
dev_warn(dev, "CPU (model=0x%x) is not supported yet,"
" using default TjMax of 100C.\n", c->x86_model);
@@ -292,6 +289,15 @@ static int __devinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
}
}
+static void __devinit get_ucode_rev_on_cpu(void *edx)
+{
+ u32 eax;
+
+ wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+ sync_core();
+ rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx);
+}
+
static int __devinit coretemp_probe(struct platform_device *pdev)
{
struct coretemp_data *data;
@@ -327,8 +333,15 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
if ((c->x86_model == 0xe) && (c->x86_mask < 0xc)) {
/* check for microcode update */
- rdmsr_on_cpu(data->id, MSR_IA32_UCODE_REV, &eax, &edx);
- if (edx < 0x39) {
+ err = smp_call_function_single(data->id, get_ucode_rev_on_cpu,
+ &edx, 1);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Cannot determine microcode revision of "
+ "CPU#%u (%d)!\n", data->id, err);
+ err = -ENODEV;
+ goto exit_free;
+ } else if (edx < 0x39) {
err = -ENODEV;
dev_err(&pdev->dev,
"Errata AE18 not fixed, update BIOS or "
@@ -490,7 +503,7 @@ exit:
return err;
}
-static void coretemp_device_remove(unsigned int cpu)
+static void __cpuinit coretemp_device_remove(unsigned int cpu)
{
struct pdev_entry *p;
unsigned int i;
@@ -569,9 +582,8 @@ exit:
static void __exit coretemp_exit(void)
{
struct pdev_entry *p, *n;
-#ifdef CONFIG_HOTPLUG_CPU
+
unregister_hotcpu_notifier(&coretemp_cpu_notifier);
-#endif
mutex_lock(&pdev_list_mutex);
list_for_each_entry_safe(p, n, &pdev_list, list) {
platform_device_unregister(p->pdev);
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
index 9638d58f99fd..95cbfb3a7077 100644
--- a/drivers/hwmon/f75375s.c
+++ b/drivers/hwmon/f75375s.c
@@ -6,10 +6,10 @@
* Datasheets available at:
*
* f75375:
- * http://www.fintek.com.tw/files/productfiles/2005111152950.pdf
+ * http://www.fintek.com.tw/files/productfiles/F75375_V026P.pdf
*
* f75373:
- * http://www.fintek.com.tw/files/productfiles/2005111153128.pdf
+ * http://www.fintek.com.tw/files/productfiles/F75373_V025P.pdf
*
* 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/hwmon/g760a.c b/drivers/hwmon/g760a.c
index 1f63d1a3af5e..1d6a6fa31fb4 100644
--- a/drivers/hwmon/g760a.c
+++ b/drivers/hwmon/g760a.c
@@ -5,7 +5,7 @@
Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
Complete datasheet is available at GMT's website:
- http://www.gmt.com.tw/datasheet/g760a.pdf
+ http://www.gmt.com.tw/product/datasheet/EDS-760A.pdf
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/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
new file mode 100644
index 000000000000..aa701a183707
--- /dev/null
+++ b/drivers/hwmon/gpio-fan.c
@@ -0,0 +1,558 @@
+/*
+ * gpio-fan.c - Hwmon driver for fans connected to GPIO lines.
+ *
+ * Copyright (C) 2010 LaCie
+ *
+ * Author: Simon Guinot <sguinot@lacie.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/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/hwmon.h>
+#include <linux/gpio.h>
+#include <linux/gpio-fan.h>
+
+struct gpio_fan_data {
+ struct platform_device *pdev;
+ struct device *hwmon_dev;
+ struct mutex lock; /* lock GPIOs operations. */
+ int num_ctrl;
+ unsigned *ctrl;
+ int num_speed;
+ struct gpio_fan_speed *speed;
+ int speed_index;
+#ifdef CONFIG_PM
+ int resume_speed;
+#endif
+ bool pwm_enable;
+ struct gpio_fan_alarm *alarm;
+ struct work_struct alarm_work;
+};
+
+/*
+ * Alarm GPIO.
+ */
+
+static void fan_alarm_notify(struct work_struct *ws)
+{
+ struct gpio_fan_data *fan_data =
+ container_of(ws, struct gpio_fan_data, alarm_work);
+
+ sysfs_notify(&fan_data->pdev->dev.kobj, NULL, "fan1_alarm");
+ kobject_uevent(&fan_data->pdev->dev.kobj, KOBJ_CHANGE);
+}
+
+static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id)
+{
+ struct gpio_fan_data *fan_data = dev_id;
+
+ schedule_work(&fan_data->alarm_work);
+
+ return IRQ_NONE;
+}
+
+static ssize_t show_fan_alarm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+ struct gpio_fan_alarm *alarm = fan_data->alarm;
+ int value = gpio_get_value(alarm->gpio);
+
+ if (alarm->active_low)
+ value = !value;
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static DEVICE_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL);
+
+static int fan_alarm_init(struct gpio_fan_data *fan_data,
+ struct gpio_fan_alarm *alarm)
+{
+ int err;
+ int alarm_irq;
+ struct platform_device *pdev = fan_data->pdev;
+
+ fan_data->alarm = alarm;
+
+ err = gpio_request(alarm->gpio, "GPIO fan alarm");
+ if (err)
+ return err;
+
+ err = gpio_direction_input(alarm->gpio);
+ if (err)
+ goto err_free_gpio;
+
+ err = device_create_file(&pdev->dev, &dev_attr_fan1_alarm);
+ if (err)
+ goto err_free_gpio;
+
+ /*
+ * If the alarm GPIO don't support interrupts, just leave
+ * without initializing the fail notification support.
+ */
+ alarm_irq = gpio_to_irq(alarm->gpio);
+ if (alarm_irq < 0)
+ return 0;
+
+ INIT_WORK(&fan_data->alarm_work, fan_alarm_notify);
+ set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
+ err = request_irq(alarm_irq, fan_alarm_irq_handler, IRQF_SHARED,
+ "GPIO fan alarm", fan_data);
+ if (err)
+ goto err_free_sysfs;
+
+ return 0;
+
+err_free_sysfs:
+ device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
+err_free_gpio:
+ gpio_free(alarm->gpio);
+
+ return err;
+}
+
+static void fan_alarm_free(struct gpio_fan_data *fan_data)
+{
+ struct platform_device *pdev = fan_data->pdev;
+ int alarm_irq = gpio_to_irq(fan_data->alarm->gpio);
+
+ if (alarm_irq >= 0)
+ free_irq(alarm_irq, fan_data);
+ device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
+ gpio_free(fan_data->alarm->gpio);
+}
+
+/*
+ * Control GPIOs.
+ */
+
+/* Must be called with fan_data->lock held, except during initialization. */
+static void __set_fan_ctrl(struct gpio_fan_data *fan_data, int ctrl_val)
+{
+ int i;
+
+ for (i = 0; i < fan_data->num_ctrl; i++)
+ gpio_set_value(fan_data->ctrl[i], (ctrl_val >> i) & 1);
+}
+
+static int __get_fan_ctrl(struct gpio_fan_data *fan_data)
+{
+ int i;
+ int ctrl_val = 0;
+
+ for (i = 0; i < fan_data->num_ctrl; i++) {
+ int value;
+
+ value = gpio_get_value(fan_data->ctrl[i]);
+ ctrl_val |= (value << i);
+ }
+ return ctrl_val;
+}
+
+/* Must be called with fan_data->lock held, except during initialization. */
+static void set_fan_speed(struct gpio_fan_data *fan_data, int speed_index)
+{
+ if (fan_data->speed_index == speed_index)
+ return;
+
+ __set_fan_ctrl(fan_data, fan_data->speed[speed_index].ctrl_val);
+ fan_data->speed_index = speed_index;
+}
+
+static int get_fan_speed_index(struct gpio_fan_data *fan_data)
+{
+ int ctrl_val = __get_fan_ctrl(fan_data);
+ int i;
+
+ for (i = 0; i < fan_data->num_speed; i++)
+ if (fan_data->speed[i].ctrl_val == ctrl_val)
+ return i;
+
+ dev_warn(&fan_data->pdev->dev,
+ "missing speed array entry for GPIO value 0x%x\n", ctrl_val);
+
+ return -EINVAL;
+}
+
+static int rpm_to_speed_index(struct gpio_fan_data *fan_data, int rpm)
+{
+ struct gpio_fan_speed *speed = fan_data->speed;
+ int i;
+
+ for (i = 0; i < fan_data->num_speed; i++)
+ if (speed[i].rpm >= rpm)
+ return i;
+
+ return fan_data->num_speed - 1;
+}
+
+static ssize_t show_pwm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+ u8 pwm = fan_data->speed_index * 255 / (fan_data->num_speed - 1);
+
+ return sprintf(buf, "%d\n", pwm);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+ unsigned long pwm;
+ int speed_index;
+ int ret = count;
+
+ if (strict_strtoul(buf, 10, &pwm) || pwm > 255)
+ return -EINVAL;
+
+ mutex_lock(&fan_data->lock);
+
+ if (!fan_data->pwm_enable) {
+ ret = -EPERM;
+ goto exit_unlock;
+ }
+
+ speed_index = DIV_ROUND_UP(pwm * (fan_data->num_speed - 1), 255);
+ set_fan_speed(fan_data, speed_index);
+
+exit_unlock:
+ mutex_unlock(&fan_data->lock);
+
+ return ret;
+}
+
+static ssize_t show_pwm_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", fan_data->pwm_enable);
+}
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+ unsigned long val;
+
+ if (strict_strtoul(buf, 10, &val) || val > 1)
+ return -EINVAL;
+
+ if (fan_data->pwm_enable == val)
+ return count;
+
+ mutex_lock(&fan_data->lock);
+
+ fan_data->pwm_enable = val;
+
+ /* Disable manual control mode: set fan at full speed. */
+ if (val == 0)
+ set_fan_speed(fan_data, fan_data->num_speed - 1);
+
+ mutex_unlock(&fan_data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_rpm_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", fan_data->speed[0].rpm);
+}
+
+static ssize_t show_rpm_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n",
+ fan_data->speed[fan_data->num_speed - 1].rpm);
+}
+
+static ssize_t show_rpm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", fan_data->speed[fan_data->speed_index].rpm);
+}
+
+static ssize_t set_rpm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+ unsigned long rpm;
+ int ret = count;
+
+ if (strict_strtoul(buf, 10, &rpm))
+ return -EINVAL;
+
+ mutex_lock(&fan_data->lock);
+
+ if (!fan_data->pwm_enable) {
+ ret = -EPERM;
+ goto exit_unlock;
+ }
+
+ set_fan_speed(fan_data, rpm_to_speed_index(fan_data, rpm));
+
+exit_unlock:
+ mutex_unlock(&fan_data->lock);
+
+ return ret;
+}
+
+static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm);
+static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+ show_pwm_enable, set_pwm_enable);
+static DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL);
+static DEVICE_ATTR(fan1_min, S_IRUGO, show_rpm_min, NULL);
+static DEVICE_ATTR(fan1_max, S_IRUGO, show_rpm_max, NULL);
+static DEVICE_ATTR(fan1_input, S_IRUGO, show_rpm, NULL);
+static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, show_rpm, set_rpm);
+
+static struct attribute *gpio_fan_ctrl_attributes[] = {
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm1_enable.attr,
+ &dev_attr_pwm1_mode.attr,
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_target.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_max.attr,
+ NULL
+};
+
+static const struct attribute_group gpio_fan_ctrl_group = {
+ .attrs = gpio_fan_ctrl_attributes,
+};
+
+static int fan_ctrl_init(struct gpio_fan_data *fan_data,
+ struct gpio_fan_platform_data *pdata)
+{
+ struct platform_device *pdev = fan_data->pdev;
+ int num_ctrl = pdata->num_ctrl;
+ unsigned *ctrl = pdata->ctrl;
+ int i, err;
+
+ for (i = 0; i < num_ctrl; i++) {
+ err = gpio_request(ctrl[i], "GPIO fan control");
+ if (err)
+ goto err_free_gpio;
+
+ err = gpio_direction_output(ctrl[i], gpio_get_value(ctrl[i]));
+ if (err) {
+ gpio_free(ctrl[i]);
+ goto err_free_gpio;
+ }
+ }
+
+ err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
+ if (err)
+ goto err_free_gpio;
+
+ fan_data->num_ctrl = num_ctrl;
+ fan_data->ctrl = ctrl;
+ fan_data->num_speed = pdata->num_speed;
+ fan_data->speed = pdata->speed;
+ fan_data->pwm_enable = true; /* Enable manual fan speed control. */
+ fan_data->speed_index = get_fan_speed_index(fan_data);
+ if (fan_data->speed_index < 0) {
+ err = -ENODEV;
+ goto err_free_gpio;
+ }
+
+ return 0;
+
+err_free_gpio:
+ for (i = i - 1; i >= 0; i--)
+ gpio_free(ctrl[i]);
+
+ return err;
+}
+
+static void fan_ctrl_free(struct gpio_fan_data *fan_data)
+{
+ struct platform_device *pdev = fan_data->pdev;
+ int i;
+
+ sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
+ for (i = 0; i < fan_data->num_ctrl; i++)
+ gpio_free(fan_data->ctrl[i]);
+}
+
+/*
+ * Platform driver.
+ */
+
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "gpio-fan\n");
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static int __devinit gpio_fan_probe(struct platform_device *pdev)
+{
+ int err;
+ struct gpio_fan_data *fan_data;
+ struct gpio_fan_platform_data *pdata = pdev->dev.platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+
+ fan_data = kzalloc(sizeof(struct gpio_fan_data), GFP_KERNEL);
+ if (!fan_data)
+ return -ENOMEM;
+
+ fan_data->pdev = pdev;
+ platform_set_drvdata(pdev, fan_data);
+ mutex_init(&fan_data->lock);
+
+ /* Configure alarm GPIO if available. */
+ if (pdata->alarm) {
+ err = fan_alarm_init(fan_data, pdata->alarm);
+ if (err)
+ goto err_free_data;
+ }
+
+ /* Configure control GPIOs if available. */
+ if (pdata->ctrl && pdata->num_ctrl > 0) {
+ if (!pdata->speed || pdata->num_speed <= 1) {
+ err = -EINVAL;
+ goto err_free_alarm;
+ }
+ err = fan_ctrl_init(fan_data, pdata);
+ if (err)
+ goto err_free_alarm;
+ }
+
+ err = device_create_file(&pdev->dev, &dev_attr_name);
+ if (err)
+ goto err_free_ctrl;
+
+ /* Make this driver part of hwmon class. */
+ fan_data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(fan_data->hwmon_dev)) {
+ err = PTR_ERR(fan_data->hwmon_dev);
+ goto err_remove_name;
+ }
+
+ dev_info(&pdev->dev, "GPIO fan initialized\n");
+
+ return 0;
+
+err_remove_name:
+ device_remove_file(&pdev->dev, &dev_attr_name);
+err_free_ctrl:
+ if (fan_data->ctrl)
+ fan_ctrl_free(fan_data);
+err_free_alarm:
+ if (fan_data->alarm)
+ fan_alarm_free(fan_data);
+err_free_data:
+ platform_set_drvdata(pdev, NULL);
+ kfree(fan_data);
+
+ return err;
+}
+
+static int __devexit gpio_fan_remove(struct platform_device *pdev)
+{
+ struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(fan_data->hwmon_dev);
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ if (fan_data->alarm)
+ fan_alarm_free(fan_data);
+ if (fan_data->ctrl)
+ fan_ctrl_free(fan_data);
+ kfree(fan_data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int gpio_fan_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
+
+ if (fan_data->ctrl) {
+ fan_data->resume_speed = fan_data->speed_index;
+ set_fan_speed(fan_data, 0);
+ }
+
+ return 0;
+}
+
+static int gpio_fan_resume(struct platform_device *pdev)
+{
+ struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
+
+ if (fan_data->ctrl)
+ set_fan_speed(fan_data, fan_data->resume_speed);
+
+ return 0;
+}
+#else
+#define gpio_fan_suspend NULL
+#define gpio_fan_resume NULL
+#endif
+
+static struct platform_driver gpio_fan_driver = {
+ .probe = gpio_fan_probe,
+ .remove = __devexit_p(gpio_fan_remove),
+ .suspend = gpio_fan_suspend,
+ .resume = gpio_fan_resume,
+ .driver = {
+ .name = "gpio-fan",
+ },
+};
+
+static int __init gpio_fan_init(void)
+{
+ return platform_driver_register(&gpio_fan_driver);
+}
+
+static void __exit gpio_fan_exit(void)
+{
+ platform_driver_unregister(&gpio_fan_driver);
+}
+
+module_init(gpio_fan_init);
+module_exit(gpio_fan_exit);
+
+MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>");
+MODULE_DESCRIPTION("GPIO FAN driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-fan");
diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c
index 36e957532230..a56a78412fcb 100644
--- a/drivers/hwmon/hp_accel.c
+++ b/drivers/hwmon/hp_accel.c
@@ -146,7 +146,7 @@ int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val)
static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
{
- lis3_dev.ac = *((struct axis_conversion *)dmi->driver_data);
+ lis3_dev.ac = *((union axis_conversion *)dmi->driver_data);
printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident);
return 1;
@@ -154,16 +154,19 @@ static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
/* Represents, for each axis seen by userspace, the corresponding hw axis (+1).
* If the value is negative, the opposite of the hw value is used. */
-static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3};
-static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3};
-static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3};
-static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3};
-static struct axis_conversion lis3lv02d_axis_xy_swap = {2, 1, 3};
-static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3};
-static struct axis_conversion lis3lv02d_axis_xy_rotated_left_usd = {-2, 1, -3};
-static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3};
-static struct axis_conversion lis3lv02d_axis_xy_rotated_right = {2, -1, 3};
-static struct axis_conversion lis3lv02d_axis_xy_swap_yz_inverted = {2, -1, -3};
+#define DEFINE_CONV(name, x, y, z) \
+ static union axis_conversion lis3lv02d_axis_##name = \
+ { .as_array = { x, y, z } }
+DEFINE_CONV(normal, 1, 2, 3);
+DEFINE_CONV(y_inverted, 1, -2, 3);
+DEFINE_CONV(x_inverted, -1, 2, 3);
+DEFINE_CONV(z_inverted, 1, 2, -3);
+DEFINE_CONV(xy_swap, 2, 1, 3);
+DEFINE_CONV(xy_rotated_left, -2, 1, 3);
+DEFINE_CONV(xy_rotated_left_usd, -2, 1, -3);
+DEFINE_CONV(xy_swap_inverted, -2, -1, 3);
+DEFINE_CONV(xy_rotated_right, 2, -1, 3);
+DEFINE_CONV(xy_swap_yz_inverted, 2, -1, -3);
#define AXIS_DMI_MATCH(_ident, _name, _axis) { \
.ident = _ident, \
@@ -222,7 +225,7 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted),
AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap),
AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted),
- AXIS_DMI_MATCH("Mini5102", "HP Mini 5102", xy_rotated_left_usd),
+ AXIS_DMI_MATCH("Mini510x", "HP Mini 510", xy_rotated_left_usd),
{ NULL, }
/* Laptop models without axis info (yet):
* "NC6910" "HP Compaq 6910"
@@ -299,7 +302,10 @@ static int lis3lv02d_add(struct acpi_device *device)
lis3lv02d_enum_resources(device);
/* If possible use a "standard" axes order */
- if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
+ if (lis3_dev.ac.x && lis3_dev.ac.y && lis3_dev.ac.z) {
+ printk(KERN_INFO DRIVER_NAME ": Using custom axes %d,%d,%d\n",
+ lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z);
+ } else if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
printk(KERN_INFO DRIVER_NAME ": laptop model unknown, "
"using default axes configuration\n");
lis3_dev.ac = lis3lv02d_axis_normal;
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
index bf0862a803c0..2b2ca1694f95 100644
--- a/drivers/hwmon/hwmon-vid.c
+++ b/drivers/hwmon/hwmon-vid.c
@@ -38,7 +38,7 @@
* available at http://developer.intel.com/.
*
* AMD Athlon 64 and AMD Opteron Processors, AMD Publication 26094,
- * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/26094.PDF
+ * http://support.amd.com/us/Processor_TechDocs/26094.PDF
* Table 74. VID Code Voltages
* This corresponds to an arbitrary VRM code of 24 in the functions below.
* These CPU models (K8 revision <= E) have 5 VID pins. See also:
diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c
index fc591ae53107..0cee73a6124e 100644
--- a/drivers/hwmon/lis3lv02d.c
+++ b/drivers/hwmon/lis3lv02d.c
@@ -31,9 +31,11 @@
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/poll.h>
+#include <linux/slab.h>
#include <linux/freezer.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
+#include <linux/pm_runtime.h>
#include <asm/atomic.h>
#include "lis3lv02d.h"
@@ -43,6 +45,16 @@
#define MDPS_POLL_INTERVAL 50
#define MDPS_POLL_MIN 0
#define MDPS_POLL_MAX 2000
+
+#define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */
+
+#define SELFTEST_OK 0
+#define SELFTEST_FAIL -1
+#define SELFTEST_IRQ -2
+
+#define IRQ_LINE0 0
+#define IRQ_LINE1 1
+
/*
* The sensor can also generate interrupts (DRDY) but it's pretty pointless
* because they are generated even if the data do not change. So it's better
@@ -66,8 +78,10 @@
#define LIS3_SENSITIVITY_12B ((LIS3_ACCURACY * 1000) / 1024)
#define LIS3_SENSITIVITY_8B (18 * LIS3_ACCURACY)
-#define LIS3_DEFAULT_FUZZ 3
-#define LIS3_DEFAULT_FLAT 3
+#define LIS3_DEFAULT_FUZZ_12B 3
+#define LIS3_DEFAULT_FLAT_12B 3
+#define LIS3_DEFAULT_FUZZ_8B 1
+#define LIS3_DEFAULT_FLAT_8B 1
struct lis3lv02d lis3_dev = {
.misc_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait),
@@ -75,6 +89,30 @@ struct lis3lv02d lis3_dev = {
EXPORT_SYMBOL_GPL(lis3_dev);
+/* just like param_set_int() but does sanity-check so that it won't point
+ * over the axis array size
+ */
+static int param_set_axis(const char *val, const struct kernel_param *kp)
+{
+ int ret = param_set_int(val, kp);
+ if (!ret) {
+ int val = *(int *)kp->arg;
+ if (val < 0)
+ val = -val;
+ if (!val || val > 3)
+ return -EINVAL;
+ }
+ return ret;
+}
+
+static struct kernel_param_ops param_ops_axis = {
+ .set = param_set_axis,
+ .get = param_get_int,
+};
+
+module_param_array_named(axes, lis3_dev.ac.as_array, axis, NULL, 0644);
+MODULE_PARM_DESC(axes, "Axis-mapping for x,y,z directions");
+
static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg)
{
s8 lo;
@@ -123,9 +161,24 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
int position[3];
int i;
- position[0] = lis3->read_data(lis3, OUTX);
- position[1] = lis3->read_data(lis3, OUTY);
- position[2] = lis3->read_data(lis3, OUTZ);
+ if (lis3->blkread) {
+ if (lis3_dev.whoami == WAI_12B) {
+ u16 data[3];
+ lis3->blkread(lis3, OUTX_L, 6, (u8 *)data);
+ for (i = 0; i < 3; i++)
+ position[i] = (s16)le16_to_cpu(data[i]);
+ } else {
+ u8 data[5];
+ /* Data: x, dummy, y, dummy, z */
+ lis3->blkread(lis3, OUTX, 5, data);
+ for (i = 0; i < 3; i++)
+ position[i] = (s8)data[i * 2];
+ }
+ } else {
+ position[0] = lis3->read_data(lis3, OUTX);
+ position[1] = lis3->read_data(lis3, OUTY);
+ position[2] = lis3->read_data(lis3, OUTZ);
+ }
for (i = 0; i < 3; i++)
position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY;
@@ -138,6 +191,7 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
/* conversion btw sampling rate and the register values */
static int lis3_12_rates[4] = {40, 160, 640, 2560};
static int lis3_8_rates[2] = {100, 400};
+static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000};
/* ODR is Output Data Rate */
static int lis3lv02d_get_odr(void)
@@ -156,6 +210,9 @@ static int lis3lv02d_set_odr(int rate)
u8 ctrl;
int i, len, shift;
+ if (!rate)
+ return -EINVAL;
+
lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
ctrl &= ~lis3_dev.odr_mask;
len = 1 << hweight_long(lis3_dev.odr_mask); /* # of possible values */
@@ -172,19 +229,42 @@ static int lis3lv02d_set_odr(int rate)
static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
{
- u8 reg;
+ u8 ctlreg, reg;
s16 x, y, z;
u8 selftest;
int ret;
+ u8 ctrl_reg_data;
+ unsigned char irq_cfg;
mutex_lock(&lis3->mutex);
- if (lis3_dev.whoami == WAI_12B)
- selftest = CTRL1_ST;
- else
- selftest = CTRL1_STP;
- lis3->read(lis3, CTRL_REG1, &reg);
- lis3->write(lis3, CTRL_REG1, (reg | selftest));
+ irq_cfg = lis3->irq_cfg;
+ if (lis3_dev.whoami == WAI_8B) {
+ lis3->data_ready_count[IRQ_LINE0] = 0;
+ lis3->data_ready_count[IRQ_LINE1] = 0;
+
+ /* Change interrupt cfg to data ready for selftest */
+ atomic_inc(&lis3_dev.wake_thread);
+ lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY;
+ lis3->read(lis3, CTRL_REG3, &ctrl_reg_data);
+ lis3->write(lis3, CTRL_REG3, (ctrl_reg_data &
+ ~(LIS3_IRQ1_MASK | LIS3_IRQ2_MASK)) |
+ (LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
+ }
+
+ if (lis3_dev.whoami == WAI_3DC) {
+ ctlreg = CTRL_REG4;
+ selftest = CTRL4_ST0;
+ } else {
+ ctlreg = CTRL_REG1;
+ if (lis3_dev.whoami == WAI_12B)
+ selftest = CTRL1_ST;
+ else
+ selftest = CTRL1_STP;
+ }
+
+ lis3->read(lis3, ctlreg, &reg);
+ lis3->write(lis3, ctlreg, (reg | selftest));
msleep(lis3->pwron_delay / lis3lv02d_get_odr());
/* Read directly to avoid axis remap */
@@ -193,7 +273,7 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
z = lis3->read_data(lis3, OUTZ);
/* back to normal settings */
- lis3->write(lis3, CTRL_REG1, reg);
+ lis3->write(lis3, ctlreg, reg);
msleep(lis3->pwron_delay / lis3lv02d_get_odr());
results[0] = x - lis3->read_data(lis3, OUTX);
@@ -201,13 +281,33 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
results[2] = z - lis3->read_data(lis3, OUTZ);
ret = 0;
+
+ if (lis3_dev.whoami == WAI_8B) {
+ /* Restore original interrupt configuration */
+ atomic_dec(&lis3_dev.wake_thread);
+ lis3->write(lis3, CTRL_REG3, ctrl_reg_data);
+ lis3->irq_cfg = irq_cfg;
+
+ if ((irq_cfg & LIS3_IRQ1_MASK) &&
+ lis3->data_ready_count[IRQ_LINE0] < 2) {
+ ret = SELFTEST_IRQ;
+ goto fail;
+ }
+
+ if ((irq_cfg & LIS3_IRQ2_MASK) &&
+ lis3->data_ready_count[IRQ_LINE1] < 2) {
+ ret = SELFTEST_IRQ;
+ goto fail;
+ }
+ }
+
if (lis3->pdata) {
int i;
for (i = 0; i < 3; i++) {
/* Check against selftest acceptance limits */
if ((results[i] < lis3->pdata->st_min_limits[i]) ||
(results[i] > lis3->pdata->st_max_limits[i])) {
- ret = -EIO;
+ ret = SELFTEST_FAIL;
goto fail;
}
}
@@ -219,10 +319,46 @@ fail:
return ret;
}
+/*
+ * Order of registers in the list affects to order of the restore process.
+ * Perhaps it is a good idea to set interrupt enable register as a last one
+ * after all other configurations
+ */
+static u8 lis3_wai8_regs[] = { FF_WU_CFG_1, FF_WU_THS_1, FF_WU_DURATION_1,
+ FF_WU_CFG_2, FF_WU_THS_2, FF_WU_DURATION_2,
+ CLICK_CFG, CLICK_SRC, CLICK_THSY_X, CLICK_THSZ,
+ CLICK_TIMELIMIT, CLICK_LATENCY, CLICK_WINDOW,
+ CTRL_REG1, CTRL_REG2, CTRL_REG3};
+
+static u8 lis3_wai12_regs[] = {FF_WU_CFG, FF_WU_THS_L, FF_WU_THS_H,
+ FF_WU_DURATION, DD_CFG, DD_THSI_L, DD_THSI_H,
+ DD_THSE_L, DD_THSE_H,
+ CTRL_REG1, CTRL_REG3, CTRL_REG2};
+
+static inline void lis3_context_save(struct lis3lv02d *lis3)
+{
+ int i;
+ for (i = 0; i < lis3->regs_size; i++)
+ lis3->read(lis3, lis3->regs[i], &lis3->reg_cache[i]);
+ lis3->regs_stored = true;
+}
+
+static inline void lis3_context_restore(struct lis3lv02d *lis3)
+{
+ int i;
+ if (lis3->regs_stored)
+ for (i = 0; i < lis3->regs_size; i++)
+ lis3->write(lis3, lis3->regs[i], lis3->reg_cache[i]);
+}
+
void lis3lv02d_poweroff(struct lis3lv02d *lis3)
{
+ if (lis3->reg_ctrl)
+ lis3_context_save(lis3);
/* disable X,Y,Z axis and power down */
lis3->write(lis3, CTRL_REG1, 0x00);
+ if (lis3->reg_ctrl)
+ lis3->reg_ctrl(lis3, LIS3_REG_OFF);
}
EXPORT_SYMBOL_GPL(lis3lv02d_poweroff);
@@ -232,19 +368,24 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3)
lis3->init(lis3);
- /* LIS3 power on delay is quite long */
- msleep(lis3->pwron_delay / lis3lv02d_get_odr());
-
/*
* Common configuration
* BDU: (12 bits sensors only) LSB and MSB values are not updated until
* both have been read. So the value read will always be correct.
+ * Set BOOT bit to refresh factory tuning values.
*/
- if (lis3->whoami == WAI_12B) {
- lis3->read(lis3, CTRL_REG2, &reg);
- reg |= CTRL2_BDU;
- lis3->write(lis3, CTRL_REG2, reg);
- }
+ 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());
+
+ if (lis3->reg_ctrl)
+ lis3_context_restore(lis3);
}
EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
@@ -262,6 +403,27 @@ static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
mutex_unlock(&lis3_dev.mutex);
}
+static void lis3lv02d_joystick_open(struct input_polled_dev *pidev)
+{
+ if (lis3_dev.pm_dev)
+ pm_runtime_get_sync(lis3_dev.pm_dev);
+
+ if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev)
+ atomic_set(&lis3_dev.wake_thread, 1);
+ /*
+ * Update coordinates for the case where poll interval is 0 and
+ * the chip in running purely under interrupt control
+ */
+ lis3lv02d_joystick_poll(pidev);
+}
+
+static void lis3lv02d_joystick_close(struct input_polled_dev *pidev)
+{
+ atomic_set(&lis3_dev.wake_thread, 0);
+ if (lis3_dev.pm_dev)
+ pm_runtime_put(lis3_dev.pm_dev);
+}
+
static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
{
if (!test_bit(0, &lis3_dev.misc_opened))
@@ -277,8 +439,7 @@ static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
wake_up_interruptible(&lis3_dev.misc_wait);
kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN);
out:
- if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev &&
- lis3_dev.idev->input->users)
+ if (atomic_read(&lis3_dev.wake_thread))
return IRQ_WAKE_THREAD;
return IRQ_HANDLED;
}
@@ -309,44 +470,41 @@ static void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3)
mutex_unlock(&lis3->mutex);
}
-static void lis302dl_interrupt_handle_ff_wu(struct lis3lv02d *lis3)
+static inline void lis302dl_data_ready(struct lis3lv02d *lis3, int index)
{
- u8 wu1_src;
- u8 wu2_src;
-
- lis3->read(lis3, FF_WU_SRC_1, &wu1_src);
- lis3->read(lis3, FF_WU_SRC_2, &wu2_src);
+ int dummy;
- wu1_src = wu1_src & FF_WU_SRC_IA ? wu1_src : 0;
- wu2_src = wu2_src & FF_WU_SRC_IA ? wu2_src : 0;
-
- /* joystick poll is internally protected by the lis3->mutex. */
- if (wu1_src || wu2_src)
- lis3lv02d_joystick_poll(lis3_dev.idev);
+ /* Dummy read to ack interrupt */
+ lis3lv02d_get_xyz(lis3, &dummy, &dummy, &dummy);
+ lis3->data_ready_count[index]++;
}
static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
{
-
struct lis3lv02d *lis3 = data;
+ u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ1_MASK;
- if ((lis3->pdata->irq_cfg & LIS3_IRQ1_MASK) == LIS3_IRQ1_CLICK)
+ if (irq_cfg == LIS3_IRQ1_CLICK)
lis302dl_interrupt_handle_click(lis3);
+ else if (unlikely(irq_cfg == LIS3_IRQ1_DATA_READY))
+ lis302dl_data_ready(lis3, IRQ_LINE0);
else
- lis302dl_interrupt_handle_ff_wu(lis3);
+ lis3lv02d_joystick_poll(lis3->idev);
return IRQ_HANDLED;
}
static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
{
-
struct lis3lv02d *lis3 = data;
+ u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ2_MASK;
- if ((lis3->pdata->irq_cfg & LIS3_IRQ2_MASK) == LIS3_IRQ2_CLICK)
+ if (irq_cfg == LIS3_IRQ2_CLICK)
lis302dl_interrupt_handle_click(lis3);
+ else if (unlikely(irq_cfg == LIS3_IRQ2_DATA_READY))
+ lis302dl_data_ready(lis3, IRQ_LINE1);
else
- lis302dl_interrupt_handle_ff_wu(lis3);
+ lis3lv02d_joystick_poll(lis3->idev);
return IRQ_HANDLED;
}
@@ -356,6 +514,9 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
if (test_and_set_bit(0, &lis3_dev.misc_opened))
return -EBUSY; /* already open */
+ if (lis3_dev.pm_dev)
+ pm_runtime_get_sync(lis3_dev.pm_dev);
+
atomic_set(&lis3_dev.count, 0);
return 0;
}
@@ -364,6 +525,8 @@ static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
{
fasync_helper(-1, file, 0, &lis3_dev.async_queue);
clear_bit(0, &lis3_dev.misc_opened); /* release the device */
+ if (lis3_dev.pm_dev)
+ pm_runtime_put(lis3_dev.pm_dev);
return 0;
}
@@ -460,6 +623,8 @@ int lis3lv02d_joystick_enable(void)
return -ENOMEM;
lis3_dev.idev->poll = lis3lv02d_joystick_poll;
+ lis3_dev.idev->open = lis3lv02d_joystick_open;
+ lis3_dev.idev->close = lis3lv02d_joystick_close;
lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL;
lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN;
lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX;
@@ -473,8 +638,16 @@ int lis3lv02d_joystick_enable(void)
set_bit(EV_ABS, input_dev->evbit);
max_val = (lis3_dev.mdps_max_val * lis3_dev.scale) / LIS3_ACCURACY;
- fuzz = (LIS3_DEFAULT_FUZZ * lis3_dev.scale) / LIS3_ACCURACY;
- flat = (LIS3_DEFAULT_FLAT * lis3_dev.scale) / LIS3_ACCURACY;
+ if (lis3_dev.whoami == WAI_12B) {
+ fuzz = LIS3_DEFAULT_FUZZ_12B;
+ flat = LIS3_DEFAULT_FLAT_12B;
+ } else {
+ fuzz = LIS3_DEFAULT_FUZZ_8B;
+ flat = LIS3_DEFAULT_FLAT_8B;
+ }
+ fuzz = (fuzz * lis3_dev.scale) / LIS3_ACCURACY;
+ flat = (flat * lis3_dev.scale) / LIS3_ACCURACY;
+
input_set_abs_params(input_dev, ABS_X, -max_val, max_val, fuzz, flat);
input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat);
input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat);
@@ -512,14 +685,47 @@ void lis3lv02d_joystick_disable(void)
EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
/* Sysfs stuff */
+static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3)
+{
+ /*
+ * SYSFS functions are fast visitors so put-call
+ * immediately after the get-call. However, keep
+ * chip running for a while and schedule delayed
+ * suspend. This way periodic sysfs calls doesn't
+ * suffer from relatively long power up time.
+ */
+
+ if (lis3->pm_dev) {
+ pm_runtime_get_sync(lis3->pm_dev);
+ pm_runtime_put_noidle(lis3->pm_dev);
+ pm_schedule_suspend(lis3->pm_dev, LIS3_SYSFS_POWERDOWN_DELAY);
+ }
+}
+
static ssize_t lis3lv02d_selftest_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int result;
s16 values[3];
- result = lis3lv02d_selftest(&lis3_dev, values);
- return sprintf(buf, "%s %d %d %d\n", result == 0 ? "OK" : "FAIL",
+ static const char ok[] = "OK";
+ static const char fail[] = "FAIL";
+ static const char irq[] = "FAIL_IRQ";
+ const char *res;
+
+ lis3lv02d_sysfs_poweron(&lis3_dev);
+ switch (lis3lv02d_selftest(&lis3_dev, values)) {
+ case SELFTEST_FAIL:
+ res = fail;
+ break;
+ case SELFTEST_IRQ:
+ res = irq;
+ break;
+ case SELFTEST_OK:
+ default:
+ res = ok;
+ break;
+ }
+ return sprintf(buf, "%s %d %d %d\n", res,
values[0], values[1], values[2]);
}
@@ -528,6 +734,7 @@ static ssize_t lis3lv02d_position_show(struct device *dev,
{
int x, y, z;
+ lis3lv02d_sysfs_poweron(&lis3_dev);
mutex_lock(&lis3_dev.mutex);
lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
mutex_unlock(&lis3_dev.mutex);
@@ -537,6 +744,7 @@ static ssize_t lis3lv02d_position_show(struct device *dev,
static ssize_t lis3lv02d_rate_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ lis3lv02d_sysfs_poweron(&lis3_dev);
return sprintf(buf, "%d\n", lis3lv02d_get_odr());
}
@@ -549,6 +757,7 @@ static ssize_t lis3lv02d_rate_set(struct device *dev,
if (strict_strtoul(buf, 0, &rate))
return -EINVAL;
+ lis3lv02d_sysfs_poweron(&lis3_dev);
if (lis3lv02d_set_odr(rate))
return -EINVAL;
@@ -585,6 +794,18 @@ int lis3lv02d_remove_fs(struct lis3lv02d *lis3)
{
sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
platform_device_unregister(lis3->pdev);
+ if (lis3->pm_dev) {
+ /* Barrier after the sysfs remove */
+ pm_runtime_barrier(lis3->pm_dev);
+
+ /* SYSFS may have left chip running. Turn off if necessary */
+ if (!pm_runtime_suspended(lis3->pm_dev))
+ lis3lv02d_poweroff(&lis3_dev);
+
+ pm_runtime_disable(lis3->pm_dev);
+ pm_runtime_set_suspended(lis3->pm_dev);
+ }
+ kfree(lis3->reg_cache);
return 0;
}
EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
@@ -616,16 +837,16 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
if (p->wakeup_flags) {
dev->write(dev, FF_WU_CFG_1, p->wakeup_flags);
dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
- /* default to 2.5ms for now */
- dev->write(dev, FF_WU_DURATION_1, 1);
+ /* pdata value + 1 to keep this backward compatible*/
+ dev->write(dev, FF_WU_DURATION_1, p->duration1 + 1);
ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/
}
if (p->wakeup_flags2) {
dev->write(dev, FF_WU_CFG_2, p->wakeup_flags2);
dev->write(dev, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f);
- /* default to 2.5ms for now */
- dev->write(dev, FF_WU_DURATION_2, 1);
+ /* pdata value + 1 to keep this backward compatible*/
+ dev->write(dev, FF_WU_DURATION_2, p->duration2 + 1);
ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/
}
/* Configure hipass filters */
@@ -635,8 +856,8 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
err = request_threaded_irq(p->irq2,
NULL,
lis302dl_interrupt_thread2_8b,
- IRQF_TRIGGER_RISING |
- IRQF_ONESHOT,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT |
+ (p->irq_flags2 & IRQF_TRIGGER_MASK),
DRIVER_NAME, &lis3_dev);
if (err < 0)
printk(KERN_ERR DRIVER_NAME
@@ -652,6 +873,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
{
int err;
irq_handler_t thread_fn;
+ int irq_flags = 0;
dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I);
@@ -664,6 +886,8 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
dev->odrs = lis3_12_rates;
dev->odr_mask = CTRL1_DF0 | CTRL1_DF1;
dev->scale = LIS3_SENSITIVITY_12B;
+ dev->regs = lis3_wai12_regs;
+ dev->regs_size = ARRAY_SIZE(lis3_wai12_regs);
break;
case WAI_8B:
printk(KERN_INFO DRIVER_NAME ": 8 bits sensor found\n");
@@ -673,6 +897,17 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
dev->odrs = lis3_8_rates;
dev->odr_mask = CTRL1_DR;
dev->scale = LIS3_SENSITIVITY_8B;
+ dev->regs = lis3_wai8_regs;
+ dev->regs_size = ARRAY_SIZE(lis3_wai8_regs);
+ break;
+ case WAI_3DC:
+ printk(KERN_INFO DRIVER_NAME ": 8 bits 3DC sensor found\n");
+ dev->read_data = lis3lv02d_read_8;
+ dev->mdps_max_val = 128;
+ dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
+ dev->odrs = lis3_3dc_rates;
+ dev->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3;
+ dev->scale = LIS3_SENSITIVITY_8B;
break;
default:
printk(KERN_ERR DRIVER_NAME
@@ -680,11 +915,25 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
return -EINVAL;
}
+ dev->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs),
+ sizeof(lis3_wai12_regs)), GFP_KERNEL);
+
+ if (dev->reg_cache == NULL) {
+ printk(KERN_ERR DRIVER_NAME "out of memory\n");
+ return -ENOMEM;
+ }
+
mutex_init(&dev->mutex);
+ atomic_set(&dev->wake_thread, 0);
lis3lv02d_add_fs(dev);
lis3lv02d_poweron(dev);
+ if (dev->pm_dev) {
+ pm_runtime_set_active(dev->pm_dev);
+ pm_runtime_enable(dev->pm_dev);
+ }
+
if (lis3lv02d_joystick_enable())
printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n");
@@ -696,8 +945,14 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
if (dev->whoami == WAI_8B)
lis3lv02d_8b_configure(dev, p);
+ irq_flags = p->irq_flags1 & IRQF_TRIGGER_MASK;
+
+ dev->irq_cfg = p->irq_cfg;
if (p->irq_cfg)
dev->write(dev, CTRL_REG3, p->irq_cfg);
+
+ if (p->default_rate)
+ lis3lv02d_set_odr(p->default_rate);
}
/* bail if we did not get an IRQ from the bus layer */
@@ -725,7 +980,8 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
err = request_threaded_irq(dev->irq, lis302dl_interrupt,
thread_fn,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT |
+ irq_flags,
DRIVER_NAME, &lis3_dev);
if (err < 0) {
diff --git a/drivers/hwmon/lis3lv02d.h b/drivers/hwmon/lis3lv02d.h
index 854091380e33..a1939589eb2c 100644
--- a/drivers/hwmon/lis3lv02d.h
+++ b/drivers/hwmon/lis3lv02d.h
@@ -20,6 +20,7 @@
*/
#include <linux/platform_device.h>
#include <linux/input-polldev.h>
+#include <linux/regulator/consumer.h>
/*
* This driver tries to support the "digital" accelerometer chips from
@@ -45,6 +46,7 @@ enum lis3_reg {
CTRL_REG1 = 0x20,
CTRL_REG2 = 0x21,
CTRL_REG3 = 0x22,
+ CTRL_REG4 = 0x23,
HP_FILTER_RESET = 0x23,
STATUS_REG = 0x27,
OUTX_L = 0x28,
@@ -93,6 +95,7 @@ enum lis3lv02d_reg {
};
enum lis3_who_am_i {
+ WAI_3DC = 0x33, /* 8 bits: LIS3DC, HP3DC */
WAI_12B = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */
WAI_8B = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */
WAI_6B = 0x52, /* 6 bits: LIS331DLF - not supported */
@@ -118,6 +121,13 @@ enum lis3lv02d_ctrl1_8b {
CTRL1_DR = 0x80,
};
+enum lis3lv02d_ctrl1_3dc {
+ CTRL1_ODR0 = 0x10,
+ CTRL1_ODR1 = 0x20,
+ CTRL1_ODR2 = 0x40,
+ CTRL1_ODR3 = 0x80,
+};
+
enum lis3lv02d_ctrl2 {
CTRL2_DAS = 0x01,
CTRL2_SIM = 0x02,
@@ -129,9 +139,18 @@ enum lis3lv02d_ctrl2 {
CTRL2_FS = 0x80, /* Full Scale selection */
};
+enum lis3lv02d_ctrl4_3dc {
+ CTRL4_SIM = 0x01,
+ CTRL4_ST0 = 0x02,
+ CTRL4_ST1 = 0x04,
+ CTRL4_FS0 = 0x10,
+ CTRL4_FS1 = 0x20,
+};
+
enum lis302d_ctrl2 {
HP_FF_WU2 = 0x08,
HP_FF_WU1 = 0x04,
+ CTRL2_BOOT_8B = 0x40,
};
enum lis3lv02d_ctrl3 {
@@ -206,19 +225,33 @@ enum lis3lv02d_click_src_8b {
CLICK_IA = 0x40,
};
-struct axis_conversion {
- s8 x;
- s8 y;
- s8 z;
+enum lis3lv02d_reg_state {
+ LIS3_REG_OFF = 0x00,
+ LIS3_REG_ON = 0x01,
+};
+
+union axis_conversion {
+ struct {
+ int x, y, z;
+ };
+ int as_array[3];
+
};
struct lis3lv02d {
void *bus_priv; /* used by the bus layer only */
+ struct device *pm_dev; /* for pm_runtime purposes */
int (*init) (struct lis3lv02d *lis3);
int (*write) (struct lis3lv02d *lis3, int reg, u8 val);
int (*read) (struct lis3lv02d *lis3, int reg, u8 *ret);
+ int (*blkread) (struct lis3lv02d *lis3, int reg, int len, u8 *ret);
+ int (*reg_ctrl) (struct lis3lv02d *lis3, bool state);
int *odrs; /* Supported output data rates */
+ u8 *regs; /* Regs to store / restore */
+ int regs_size;
+ u8 *reg_cache;
+ bool regs_stored;
u8 odr_mask; /* ODR bit mask */
u8 whoami; /* indicates measurement precision */
s16 (*read_data) (struct lis3lv02d *lis3, int reg);
@@ -231,14 +264,18 @@ struct lis3lv02d {
struct input_polled_dev *idev; /* input device */
struct platform_device *pdev; /* platform device */
+ struct regulator_bulk_data regulators[2];
atomic_t count; /* interrupt count after last read */
- struct axis_conversion ac; /* hw -> logical axis */
+ union axis_conversion ac; /* hw -> logical axis */
int mapped_btns[3];
u32 irq; /* IRQ number */
struct fasync_struct *async_queue; /* queue for the misc device */
wait_queue_head_t misc_wait; /* Wait queue for the misc device */
unsigned long misc_opened; /* bit0: whether the device is open */
+ int data_ready_count[2];
+ atomic_t wake_thread;
+ unsigned char irq_cfg;
struct lis3lv02d_platform_data *pdata; /* for passing board config */
struct mutex mutex; /* Serialize poll and selftest */
diff --git a/drivers/hwmon/lis3lv02d_i2c.c b/drivers/hwmon/lis3lv02d_i2c.c
index 8e5933b72d19..9f4bae07f719 100644
--- a/drivers/hwmon/lis3lv02d_i2c.c
+++ b/drivers/hwmon/lis3lv02d_i2c.c
@@ -29,10 +29,30 @@
#include <linux/init.h>
#include <linux/err.h>
#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
#include "lis3lv02d.h"
#define DRV_NAME "lis3lv02d_i2c"
+static const char reg_vdd[] = "Vdd";
+static const char reg_vdd_io[] = "Vdd_IO";
+
+static int lis3_reg_ctrl(struct lis3lv02d *lis3, bool state)
+{
+ int ret;
+ if (state == LIS3_REG_OFF) {
+ ret = regulator_bulk_disable(ARRAY_SIZE(lis3->regulators),
+ lis3->regulators);
+ } else {
+ ret = regulator_bulk_enable(ARRAY_SIZE(lis3->regulators),
+ lis3->regulators);
+ /* Chip needs time to wakeup. Not mentioned in datasheet */
+ usleep_range(10000, 20000);
+ }
+ return ret;
+}
+
static inline s32 lis3_i2c_write(struct lis3lv02d *lis3, int reg, u8 value)
{
struct i2c_client *c = lis3->bus_priv;
@@ -46,24 +66,38 @@ static inline s32 lis3_i2c_read(struct lis3lv02d *lis3, int reg, u8 *v)
return 0;
}
+static inline s32 lis3_i2c_blockread(struct lis3lv02d *lis3, int reg, int len,
+ u8 *v)
+{
+ struct i2c_client *c = lis3->bus_priv;
+ reg |= (1 << 7); /* 7th bit enables address auto incrementation */
+ return i2c_smbus_read_i2c_block_data(c, reg, len, v);
+}
+
static int lis3_i2c_init(struct lis3lv02d *lis3)
{
u8 reg;
int ret;
+ if (lis3->reg_ctrl)
+ lis3_reg_ctrl(lis3, LIS3_REG_ON);
+
+ lis3->read(lis3, WHO_AM_I, &reg);
+ if (reg != lis3->whoami)
+ printk(KERN_ERR "lis3: power on failure\n");
+
/* power up the device */
ret = lis3->read(lis3, CTRL_REG1, &reg);
if (ret < 0)
return ret;
- reg |= CTRL1_PD0;
+ reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
return lis3->write(lis3, CTRL_REG1, reg);
}
/* Default axis mapping but it can be overwritten by platform data */
-static struct axis_conversion lis3lv02d_axis_map = { LIS3_DEV_X,
- LIS3_DEV_Y,
- LIS3_DEV_Z };
+static union axis_conversion lis3lv02d_axis_map =
+ { .as_array = { LIS3_DEV_X, LIS3_DEV_Y, LIS3_DEV_Z } };
static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
@@ -72,6 +106,15 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
if (pdata) {
+ /* Regulator control is optional */
+ if (pdata->driver_features & LIS3_USE_REGULATOR_CTRL)
+ lis3_dev.reg_ctrl = lis3_reg_ctrl;
+
+ if ((pdata->driver_features & LIS3_USE_BLOCK_READ) &&
+ (i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_I2C_BLOCK)))
+ lis3_dev.blkread = lis3_i2c_blockread;
+
if (pdata->axis_x)
lis3lv02d_axis_map.x = pdata->axis_x;
@@ -88,6 +131,16 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
goto fail;
}
+ if (lis3_dev.reg_ctrl) {
+ lis3_dev.regulators[0].supply = reg_vdd;
+ lis3_dev.regulators[1].supply = reg_vdd_io;
+ ret = regulator_bulk_get(&client->dev,
+ ARRAY_SIZE(lis3_dev.regulators),
+ lis3_dev.regulators);
+ if (ret < 0)
+ goto fail;
+ }
+
lis3_dev.pdata = pdata;
lis3_dev.bus_priv = client;
lis3_dev.init = lis3_i2c_init;
@@ -95,10 +148,24 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
lis3_dev.write = lis3_i2c_write;
lis3_dev.irq = client->irq;
lis3_dev.ac = lis3lv02d_axis_map;
+ lis3_dev.pm_dev = &client->dev;
i2c_set_clientdata(client, &lis3_dev);
+
+ /* Provide power over the init call */
+ if (lis3_dev.reg_ctrl)
+ lis3_reg_ctrl(&lis3_dev, LIS3_REG_ON);
+
ret = lis3lv02d_init_device(&lis3_dev);
+
+ if (lis3_dev.reg_ctrl)
+ lis3_reg_ctrl(&lis3_dev, LIS3_REG_OFF);
+
+ if (ret == 0)
+ return 0;
fail:
+ if (pdata && pdata->release_resources)
+ pdata->release_resources();
return ret;
}
@@ -111,14 +178,18 @@ static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client)
pdata->release_resources();
lis3lv02d_joystick_disable();
- lis3lv02d_poweroff(lis3);
+ lis3lv02d_remove_fs(&lis3_dev);
- return lis3lv02d_remove_fs(&lis3_dev);
+ if (lis3_dev.reg_ctrl)
+ regulator_bulk_free(ARRAY_SIZE(lis3->regulators),
+ lis3_dev.regulators);
+ return 0;
}
#ifdef CONFIG_PM
-static int lis3lv02d_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+static int lis3lv02d_i2c_suspend(struct device *dev)
{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
struct lis3lv02d *lis3 = i2c_get_clientdata(client);
if (!lis3->pdata || !lis3->pdata->wakeup_flags)
@@ -126,18 +197,21 @@ static int lis3lv02d_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
return 0;
}
-static int lis3lv02d_i2c_resume(struct i2c_client *client)
+static int lis3lv02d_i2c_resume(struct device *dev)
{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
struct lis3lv02d *lis3 = i2c_get_clientdata(client);
- if (!lis3->pdata || !lis3->pdata->wakeup_flags)
+ /*
+ * pm_runtime documentation says that devices should always
+ * be powered on at resume. Pm_runtime turns them off after system
+ * wide resume is complete.
+ */
+ if (!lis3->pdata || !lis3->pdata->wakeup_flags ||
+ pm_runtime_suspended(dev))
lis3lv02d_poweron(lis3);
- return 0;
-}
-static void lis3lv02d_i2c_shutdown(struct i2c_client *client)
-{
- lis3lv02d_i2c_suspend(client, PMSG_SUSPEND);
+ return 0;
}
#else
#define lis3lv02d_i2c_suspend NULL
@@ -145,6 +219,24 @@ static void lis3lv02d_i2c_shutdown(struct i2c_client *client)
#define lis3lv02d_i2c_shutdown NULL
#endif
+static int lis3_i2c_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+
+ lis3lv02d_poweroff(lis3);
+ return 0;
+}
+
+static int lis3_i2c_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+
+ lis3lv02d_poweron(lis3);
+ return 0;
+}
+
static const struct i2c_device_id lis3lv02d_id[] = {
{"lis3lv02d", 0 },
{}
@@ -152,14 +244,20 @@ static const struct i2c_device_id lis3lv02d_id[] = {
MODULE_DEVICE_TABLE(i2c, lis3lv02d_id);
+static const struct dev_pm_ops lis3_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(lis3lv02d_i2c_suspend,
+ lis3lv02d_i2c_resume)
+ SET_RUNTIME_PM_OPS(lis3_i2c_runtime_suspend,
+ lis3_i2c_runtime_resume,
+ NULL)
+};
+
static struct i2c_driver lis3lv02d_i2c_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+ .pm = &lis3_pm_ops,
},
- .suspend = lis3lv02d_i2c_suspend,
- .shutdown = lis3lv02d_i2c_shutdown,
- .resume = lis3lv02d_i2c_resume,
.probe = lis3lv02d_i2c_probe,
.remove = __devexit_p(lis3lv02d_i2c_remove),
.id_table = lis3lv02d_id,
diff --git a/drivers/hwmon/lis3lv02d_spi.c b/drivers/hwmon/lis3lv02d_spi.c
index b9be5e3a22b3..2549de1de4e2 100644
--- a/drivers/hwmon/lis3lv02d_spi.c
+++ b/drivers/hwmon/lis3lv02d_spi.c
@@ -50,11 +50,12 @@ static int lis3_spi_init(struct lis3lv02d *lis3)
if (ret < 0)
return ret;
- reg |= CTRL1_PD0;
+ reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
return lis3->write(lis3, CTRL_REG1, reg);
}
-static struct axis_conversion lis3lv02d_axis_normal = { 1, 2, 3 };
+static union axis_conversion lis3lv02d_axis_normal =
+ { .as_array = { 1, 2, 3 } };
static int __devinit lis302dl_spi_probe(struct spi_device *spi)
{
diff --git a/drivers/hwmon/ltc4261.c b/drivers/hwmon/ltc4261.c
new file mode 100644
index 000000000000..267626178678
--- /dev/null
+++ b/drivers/hwmon/ltc4261.c
@@ -0,0 +1,315 @@
+/*
+ * Driver for Linear Technology LTC4261 I2C Negative Voltage Hot Swap Controller
+ *
+ * Copyright (C) 2010 Ericsson AB.
+ *
+ * Derived from:
+ *
+ * Driver for Linear Technology LTC4245 I2C Multiple Supply Hot Swap Controller
+ * Copyright (C) 2008 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * Datasheet: http://cds.linear.com/docs/Datasheet/42612fb.pdf
+ *
+ * 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/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+/* chip registers */
+#define LTC4261_STATUS 0x00 /* readonly */
+#define LTC4261_FAULT 0x01
+#define LTC4261_ALERT 0x02
+#define LTC4261_CONTROL 0x03
+#define LTC4261_SENSE_H 0x04
+#define LTC4261_SENSE_L 0x05
+#define LTC4261_ADIN2_H 0x06
+#define LTC4261_ADIN2_L 0x07
+#define LTC4261_ADIN_H 0x08
+#define LTC4261_ADIN_L 0x09
+
+/*
+ * Fault register bits
+ */
+#define FAULT_OV (1<<0)
+#define FAULT_UV (1<<1)
+#define FAULT_OC (1<<2)
+
+struct ltc4261_data {
+ struct device *hwmon_dev;
+
+ struct mutex update_lock;
+ bool valid;
+ unsigned long last_updated; /* in jiffies */
+
+ /* Registers */
+ u8 regs[10];
+};
+
+static struct ltc4261_data *ltc4261_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ltc4261_data *data = i2c_get_clientdata(client);
+ struct ltc4261_data *ret = data;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ / 4) || !data->valid) {
+ int i;
+
+ /* Read registers -- 0x00 to 0x09 */
+ for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
+ int val;
+
+ val = i2c_smbus_read_byte_data(client, i);
+ if (unlikely(val < 0)) {
+ dev_dbg(dev,
+ "Failed to read ADC value: error %d",
+ val);
+ ret = ERR_PTR(val);
+ goto abort;
+ }
+ data->regs[i] = val;
+ }
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+abort:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+/* Return the voltage from the given register in mV or mA */
+static int ltc4261_get_value(struct ltc4261_data *data, u8 reg)
+{
+ u32 val;
+
+ val = (data->regs[reg] << 2) + (data->regs[reg + 1] >> 6);
+
+ switch (reg) {
+ case LTC4261_ADIN_H:
+ case LTC4261_ADIN2_H:
+ /* 2.5mV resolution. Convert to mV. */
+ val = val * 25 / 10;
+ break;
+ case LTC4261_SENSE_H:
+ /*
+ * 62.5uV resolution. Convert to current as measured with
+ * an 1 mOhm sense resistor, in mA. If a different sense
+ * resistor is installed, calculate the actual current by
+ * dividing the reported current by the sense resistor value
+ * in mOhm.
+ */
+ val = val * 625 / 10;
+ break;
+ default:
+ /* If we get here, the developer messed up */
+ WARN_ON_ONCE(1);
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+static ssize_t ltc4261_show_value(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct ltc4261_data *data = ltc4261_update_device(dev);
+ int value;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ value = ltc4261_get_value(data, attr->index);
+ return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+static ssize_t ltc4261_show_bool(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ltc4261_data *data = ltc4261_update_device(dev);
+ u8 fault;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ fault = data->regs[LTC4261_FAULT] & attr->index;
+ if (fault) /* Clear reported faults in chip register */
+ i2c_smbus_write_byte_data(client, LTC4261_FAULT, ~fault);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", fault ? 1 : 0);
+}
+
+/*
+ * These macros are used below in constructing device attribute objects
+ * for use with sysfs_create_group() to make a sysfs device file
+ * for each register.
+ */
+
+#define LTC4261_VALUE(name, ltc4261_cmd_idx) \
+ static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+ ltc4261_show_value, NULL, ltc4261_cmd_idx)
+
+#define LTC4261_BOOL(name, mask) \
+ static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+ ltc4261_show_bool, NULL, (mask))
+
+/*
+ * Input voltages.
+ */
+LTC4261_VALUE(in1_input, LTC4261_ADIN_H);
+LTC4261_VALUE(in2_input, LTC4261_ADIN2_H);
+
+/*
+ * Voltage alarms. The chip has only one set of voltage alarm status bits,
+ * triggered by input voltage alarms. In many designs, those alarms are
+ * associated with the ADIN2 sensor, due to the proximity of the ADIN2 pin
+ * to the OV pin. ADIN2 is, however, not available on all chip variants.
+ * To ensure that the alarm condition is reported to the user, report it
+ * with both voltage sensors.
+ */
+LTC4261_BOOL(in1_min_alarm, FAULT_UV);
+LTC4261_BOOL(in1_max_alarm, FAULT_OV);
+LTC4261_BOOL(in2_min_alarm, FAULT_UV);
+LTC4261_BOOL(in2_max_alarm, FAULT_OV);
+
+/* Currents (via sense resistor) */
+LTC4261_VALUE(curr1_input, LTC4261_SENSE_H);
+
+/* Overcurrent alarm */
+LTC4261_BOOL(curr1_max_alarm, FAULT_OC);
+
+static struct attribute *ltc4261_attributes[] = {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_max_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+ &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+
+ NULL,
+};
+
+static const struct attribute_group ltc4261_group = {
+ .attrs = ltc4261_attributes,
+};
+
+static int ltc4261_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct ltc4261_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ if (i2c_smbus_read_byte_data(client, LTC4261_STATUS) < 0) {
+ dev_err(&client->dev, "Failed to read register %d:%02x:%02x\n",
+ adapter->id, client->addr, LTC4261_STATUS);
+ return -ENODEV;
+ }
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto out_kzalloc;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /* Clear faults */
+ i2c_smbus_write_byte_data(client, LTC4261_FAULT, 0x00);
+
+ /* Register sysfs hooks */
+ ret = sysfs_create_group(&client->dev.kobj, &ltc4261_group);
+ if (ret)
+ goto out_sysfs_create_group;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ ret = PTR_ERR(data->hwmon_dev);
+ goto out_hwmon_device_register;
+ }
+
+ return 0;
+
+out_hwmon_device_register:
+ sysfs_remove_group(&client->dev.kobj, &ltc4261_group);
+out_sysfs_create_group:
+ kfree(data);
+out_kzalloc:
+ return ret;
+}
+
+static int ltc4261_remove(struct i2c_client *client)
+{
+ struct ltc4261_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &ltc4261_group);
+
+ kfree(data);
+
+ return 0;
+}
+
+static const struct i2c_device_id ltc4261_id[] = {
+ {"ltc4261", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc4261_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ltc4261_driver = {
+ .driver = {
+ .name = "ltc4261",
+ },
+ .probe = ltc4261_probe,
+ .remove = ltc4261_remove,
+ .id_table = ltc4261_id,
+};
+
+static int __init ltc4261_init(void)
+{
+ return i2c_add_driver(&ltc4261_driver);
+}
+
+static void __exit ltc4261_exit(void)
+{
+ i2c_del_driver(&ltc4261_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_DESCRIPTION("LTC4261 driver");
+MODULE_LICENSE("GPL");
+
+module_init(ltc4261_init);
+module_exit(ltc4261_exit);
diff --git a/drivers/hwmon/pkgtemp.c b/drivers/hwmon/pkgtemp.c
index f11903936c8b..0798210590bc 100644
--- a/drivers/hwmon/pkgtemp.c
+++ b/drivers/hwmon/pkgtemp.c
@@ -21,7 +21,6 @@
*/
#include <linux/module.h>
-#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
@@ -35,6 +34,7 @@
#include <linux/cpu.h>
#include <asm/msr.h>
#include <asm/processor.h>
+#include <asm/smp.h>
#define DRVNAME "pkgtemp"
@@ -339,8 +339,7 @@ exit:
return err;
}
-#ifdef CONFIG_HOTPLUG_CPU
-static void pkgtemp_device_remove(unsigned int cpu)
+static void __cpuinit pkgtemp_device_remove(unsigned int cpu)
{
struct pdev_entry *p;
unsigned int i;
@@ -387,12 +386,10 @@ static int __cpuinit pkgtemp_cpu_callback(struct notifier_block *nfb,
static struct notifier_block pkgtemp_cpu_notifier __refdata = {
.notifier_call = pkgtemp_cpu_callback,
};
-#endif /* !CONFIG_HOTPLUG_CPU */
static int __init pkgtemp_init(void)
{
int i, err = -ENODEV;
- struct pdev_entry *p, *n;
/* quick check if we run Intel */
if (cpu_data(0).x86_vendor != X86_VENDOR_INTEL)
@@ -402,31 +399,23 @@ static int __init pkgtemp_init(void)
if (err)
goto exit;
- for_each_online_cpu(i) {
- err = pkgtemp_device_add(i);
- if (err)
- goto exit_devices_unreg;
- }
+ for_each_online_cpu(i)
+ pkgtemp_device_add(i);
+
+#ifndef CONFIG_HOTPLUG_CPU
if (list_empty(&pdev_list)) {
err = -ENODEV;
goto exit_driver_unreg;
}
+#endif
-#ifdef CONFIG_HOTPLUG_CPU
register_hotcpu_notifier(&pkgtemp_cpu_notifier);
-#endif
return 0;
-exit_devices_unreg:
- mutex_lock(&pdev_list_mutex);
- list_for_each_entry_safe(p, n, &pdev_list, list) {
- platform_device_unregister(p->pdev);
- list_del(&p->list);
- kfree(p);
- }
- mutex_unlock(&pdev_list_mutex);
+#ifndef CONFIG_HOTPLUG_CPU
exit_driver_unreg:
platform_driver_unregister(&pkgtemp_driver);
+#endif
exit:
return err;
}
@@ -434,9 +423,8 @@ exit:
static void __exit pkgtemp_exit(void)
{
struct pdev_entry *p, *n;
-#ifdef CONFIG_HOTPLUG_CPU
+
unregister_hotcpu_notifier(&pkgtemp_cpu_notifier);
-#endif
mutex_lock(&pdev_list_mutex);
list_for_each_entry_safe(p, n, &pdev_list, list) {
platform_device_unregister(p->pdev);
diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c
index ffb793af680b..ec7fad747adc 100644
--- a/drivers/hwmon/via-cputemp.c
+++ b/drivers/hwmon/via-cputemp.c
@@ -22,10 +22,8 @@
*/
#include <linux/module.h>
-#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/jiffies.h>
#include <linux/hwmon.h>
#include <linux/sysfs.h>
#include <linux/hwmon-sysfs.h>
@@ -237,8 +235,7 @@ exit:
return err;
}
-#ifdef CONFIG_HOTPLUG_CPU
-static void via_cputemp_device_remove(unsigned int cpu)
+static void __cpuinit via_cputemp_device_remove(unsigned int cpu)
{
struct pdev_entry *p, *n;
mutex_lock(&pdev_list_mutex);
@@ -272,7 +269,6 @@ static int __cpuinit via_cputemp_cpu_callback(struct notifier_block *nfb,
static struct notifier_block via_cputemp_cpu_notifier __refdata = {
.notifier_call = via_cputemp_cpu_callback,
};
-#endif /* !CONFIG_HOTPLUG_CPU */
static int __init via_cputemp_init(void)
{
@@ -313,9 +309,7 @@ static int __init via_cputemp_init(void)
goto exit_driver_unreg;
}
-#ifdef CONFIG_HOTPLUG_CPU
register_hotcpu_notifier(&via_cputemp_cpu_notifier);
-#endif
return 0;
exit_devices_unreg:
@@ -335,9 +329,8 @@ exit:
static void __exit via_cputemp_exit(void)
{
struct pdev_entry *p, *n;
-#ifdef CONFIG_HOTPLUG_CPU
+
unregister_hotcpu_notifier(&via_cputemp_cpu_notifier);
-#endif
mutex_lock(&pdev_list_mutex);
list_for_each_entry_safe(p, n, &pdev_list, list) {
platform_device_unregister(p->pdev);
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 30f06e956bfb..b923074b2cbe 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -75,7 +75,8 @@ config I2C_HELPER_AUTO
In doubt, say Y.
config I2C_SMBUS
- tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO
+ tristate
+ prompt "SMBus-specific protocols" if !I2C_HELPER_AUTO
help
Say Y here if you want support for SMBus extensions to the I2C
specification. At the moment, the only supported extension is
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index c00fd66388f5..23ac61e2db39 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -9,6 +9,4 @@ obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
obj-$(CONFIG_I2C_MUX) += i2c-mux.o
obj-y += algos/ busses/ muxes/
-ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG
diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
index 7b2ce4a08524..3998dd620a03 100644
--- a/drivers/i2c/algos/Kconfig
+++ b/drivers/i2c/algos/Kconfig
@@ -15,3 +15,15 @@ config I2C_ALGOPCA
tristate "I2C PCA 9564 interfaces"
endmenu
+
+# In automatic configuration mode, we still have to define the
+# symbols to avoid unmet dependencies.
+
+if I2C_HELPER_AUTO
+config I2C_ALGOBIT
+ tristate
+config I2C_ALGOPCF
+ tristate
+config I2C_ALGOPCA
+ tristate
+endif
diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile
index 18b3e962ec09..215303f60d61 100644
--- a/drivers/i2c/algos/Makefile
+++ b/drivers/i2c/algos/Makefile
@@ -6,6 +6,4 @@ obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o
obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o
-ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_I2C_DEBUG_ALGO) := -DDEBUG
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index c3ef49230cba..033ad413f328 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -76,6 +76,4 @@ obj-$(CONFIG_I2C_STUB) += i2c-stub.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
-ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index af1e5e254b7b..6b6a6b1d7025 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -69,7 +69,7 @@ static struct pci_driver amd8111_driver;
* ACPI 2.0 chapter 13 access of registers of the EC
*/
-static unsigned int amd_ec_wait_write(struct amd_smbus *smbus)
+static int amd_ec_wait_write(struct amd_smbus *smbus)
{
int timeout = 500;
@@ -85,7 +85,7 @@ static unsigned int amd_ec_wait_write(struct amd_smbus *smbus)
return 0;
}
-static unsigned int amd_ec_wait_read(struct amd_smbus *smbus)
+static int amd_ec_wait_read(struct amd_smbus *smbus)
{
int timeout = 500;
@@ -101,7 +101,7 @@ static unsigned int amd_ec_wait_read(struct amd_smbus *smbus)
return 0;
}
-static unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address,
+static int amd_ec_read(struct amd_smbus *smbus, unsigned char address,
unsigned char *data)
{
int status;
@@ -124,7 +124,7 @@ static unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address,
return 0;
}
-static unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address,
+static int amd_ec_write(struct amd_smbus *smbus, unsigned char address,
unsigned char data)
{
int status;
@@ -196,7 +196,7 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
{
struct amd_smbus *smbus = adap->algo_data;
unsigned char protocol, len, pec, temp[2];
- int i;
+ int i, status;
protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ
: AMD_SMB_PRTCL_WRITE;
@@ -209,38 +209,62 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
break;
case I2C_SMBUS_BYTE:
- if (read_write == I2C_SMBUS_WRITE)
- amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE) {
+ status = amd_ec_write(smbus, AMD_SMB_CMD,
+ command);
+ if (status)
+ return status;
+ }
protocol |= AMD_SMB_PRTCL_BYTE;
break;
case I2C_SMBUS_BYTE_DATA:
- amd_ec_write(smbus, AMD_SMB_CMD, command);
- if (read_write == I2C_SMBUS_WRITE)
- amd_ec_write(smbus, AMD_SMB_DATA, data->byte);
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ if (read_write == I2C_SMBUS_WRITE) {
+ status = amd_ec_write(smbus, AMD_SMB_DATA,
+ data->byte);
+ if (status)
+ return status;
+ }
protocol |= AMD_SMB_PRTCL_BYTE_DATA;
break;
case I2C_SMBUS_WORD_DATA:
- amd_ec_write(smbus, AMD_SMB_CMD, command);
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
if (read_write == I2C_SMBUS_WRITE) {
- amd_ec_write(smbus, AMD_SMB_DATA,
- data->word & 0xff);
- amd_ec_write(smbus, AMD_SMB_DATA + 1,
- data->word >> 8);
+ status = amd_ec_write(smbus, AMD_SMB_DATA,
+ data->word & 0xff);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_DATA + 1,
+ data->word >> 8);
+ if (status)
+ return status;
}
protocol |= AMD_SMB_PRTCL_WORD_DATA | pec;
break;
case I2C_SMBUS_BLOCK_DATA:
- amd_ec_write(smbus, AMD_SMB_CMD, command);
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
if (read_write == I2C_SMBUS_WRITE) {
len = min_t(u8, data->block[0],
I2C_SMBUS_BLOCK_MAX);
- amd_ec_write(smbus, AMD_SMB_BCNT, len);
- for (i = 0; i < len; i++)
- amd_ec_write(smbus, AMD_SMB_DATA + i,
- data->block[i + 1]);
+ status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
+ if (status)
+ return status;
+ for (i = 0; i < len; i++) {
+ status =
+ amd_ec_write(smbus, AMD_SMB_DATA + i,
+ data->block[i + 1]);
+ if (status)
+ return status;
+ }
}
protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec;
break;
@@ -248,19 +272,35 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
case I2C_SMBUS_I2C_BLOCK_DATA:
len = min_t(u8, data->block[0],
I2C_SMBUS_BLOCK_MAX);
- amd_ec_write(smbus, AMD_SMB_CMD, command);
- amd_ec_write(smbus, AMD_SMB_BCNT, len);
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
+ if (status)
+ return status;
if (read_write == I2C_SMBUS_WRITE)
- for (i = 0; i < len; i++)
- amd_ec_write(smbus, AMD_SMB_DATA + i,
- data->block[i + 1]);
+ for (i = 0; i < len; i++) {
+ status =
+ amd_ec_write(smbus, AMD_SMB_DATA + i,
+ data->block[i + 1]);
+ if (status)
+ return status;
+ }
protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA;
break;
case I2C_SMBUS_PROC_CALL:
- amd_ec_write(smbus, AMD_SMB_CMD, command);
- amd_ec_write(smbus, AMD_SMB_DATA, data->word & 0xff);
- amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8);
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_DATA,
+ data->word & 0xff);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_DATA + 1,
+ data->word >> 8);
+ if (status)
+ return status;
protocol = AMD_SMB_PRTCL_PROC_CALL | pec;
read_write = I2C_SMBUS_READ;
break;
@@ -268,11 +308,18 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
case I2C_SMBUS_BLOCK_PROC_CALL:
len = min_t(u8, data->block[0],
I2C_SMBUS_BLOCK_MAX - 1);
- amd_ec_write(smbus, AMD_SMB_CMD, command);
- amd_ec_write(smbus, AMD_SMB_BCNT, len);
- for (i = 0; i < len; i++)
- amd_ec_write(smbus, AMD_SMB_DATA + i,
- data->block[i + 1]);
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
+ if (status)
+ return status;
+ for (i = 0; i < len; i++) {
+ status = amd_ec_write(smbus, AMD_SMB_DATA + i,
+ data->block[i + 1]);
+ if (status)
+ return status;
+ }
protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec;
read_write = I2C_SMBUS_READ;
break;
@@ -282,24 +329,29 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
return -EOPNOTSUPP;
}
- amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1);
- amd_ec_write(smbus, AMD_SMB_PRTCL, protocol);
+ status = amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_PRTCL, protocol);
+ if (status)
+ return status;
- /* FIXME this discards status from ec_read(); so temp[0] will
- * hold stack garbage ... the rest of this routine will act
- * nonsensically. Ignored ec_write() status might explain
- * some such failures...
- */
- amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+ status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+ if (status)
+ return status;
if (~temp[0] & AMD_SMB_STS_DONE) {
udelay(500);
- amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+ status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+ if (status)
+ return status;
}
if (~temp[0] & AMD_SMB_STS_DONE) {
msleep(1);
- amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+ status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+ if (status)
+ return status;
}
if ((~temp[0] & AMD_SMB_STS_DONE) || (temp[0] & AMD_SMB_STS_STATUS))
@@ -311,24 +363,35 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
switch (size) {
case I2C_SMBUS_BYTE:
case I2C_SMBUS_BYTE_DATA:
- amd_ec_read(smbus, AMD_SMB_DATA, &data->byte);
+ status = amd_ec_read(smbus, AMD_SMB_DATA, &data->byte);
+ if (status)
+ return status;
break;
case I2C_SMBUS_WORD_DATA:
case I2C_SMBUS_PROC_CALL:
- amd_ec_read(smbus, AMD_SMB_DATA, temp + 0);
- amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1);
+ status = amd_ec_read(smbus, AMD_SMB_DATA, temp + 0);
+ if (status)
+ return status;
+ status = amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1);
+ if (status)
+ return status;
data->word = (temp[1] << 8) | temp[0];
break;
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_BLOCK_PROC_CALL:
- amd_ec_read(smbus, AMD_SMB_BCNT, &len);
+ status = amd_ec_read(smbus, AMD_SMB_BCNT, &len);
+ if (status)
+ return status;
len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
case I2C_SMBUS_I2C_BLOCK_DATA:
- for (i = 0; i < len; i++)
- amd_ec_read(smbus, AMD_SMB_DATA + i,
- data->block + i + 1);
+ for (i = 0; i < len; i++) {
+ status = amd_ec_read(smbus, AMD_SMB_DATA + i,
+ data->block + i + 1);
+ if (status)
+ return status;
+ }
data->block[0] = len;
break;
}
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 89eedf45d30e..6e3c38240336 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -41,7 +41,6 @@
#include <asm/irq.h>
#include <linux/io.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/of_platform.h>
#include <linux/of_i2c.h>
diff --git a/drivers/i2c/busses/i2c-nuc900.c b/drivers/i2c/busses/i2c-nuc900.c
index 92d770d7bbc2..72434263787b 100644
--- a/drivers/i2c/busses/i2c-nuc900.c
+++ b/drivers/i2c/busses/i2c-nuc900.c
@@ -16,7 +16,6 @@
#include <linux/module.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/interrupt.h>
diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c
index 5f6d7f89e225..ace67995d7de 100644
--- a/drivers/i2c/busses/i2c-pca-platform.c
+++ b/drivers/i2c/busses/i2c-pca-platform.c
@@ -224,7 +224,7 @@ static int __devinit i2c_pca_pf_probe(struct platform_device *pdev)
if (irq) {
ret = request_irq(irq, i2c_pca_pf_handler,
- IRQF_TRIGGER_FALLING, i2c->adap.name, i2c);
+ IRQF_TRIGGER_FALLING, pdev->name, i2c);
if (ret)
goto e_reqirq;
}
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index c94e51b2651e..f4c19a97e0b3 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -22,7 +22,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/sched.h>
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index bf831bf81587..6a292ea5e35c 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -24,7 +24,6 @@
#include <linux/module.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/interrupt.h>
diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c
index 4f93da31d3ad..3cad8fecc3d3 100644
--- a/drivers/i2c/busses/i2c-sh7760.c
+++ b/drivers/i2c/busses/i2c-sh7760.c
@@ -101,12 +101,12 @@ struct cami2c {
static inline void OUT32(struct cami2c *cam, int reg, unsigned long val)
{
- ctrl_outl(val, (unsigned long)cam->iobase + reg);
+ __raw_writel(val, (unsigned long)cam->iobase + reg);
}
static inline unsigned long IN32(struct cami2c *cam, int reg)
{
- return ctrl_inl((unsigned long)cam->iobase + reg);
+ return __raw_readl((unsigned long)cam->iobase + reg);
}
static irqreturn_t sh7760_i2c_irq(int irq, void *ptr)
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 598c49acaeb5..2707f5e17158 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -538,15 +538,17 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
{
struct resource *res;
int ret = -ENXIO;
- int q, m;
- int k = 0;
- int n = 0;
+ int n, k = 0;
while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) {
for (n = res->start; hook && n <= res->end; n++) {
if (request_irq(n, sh_mobile_i2c_isr, IRQF_DISABLED,
- dev_name(&dev->dev), dev))
+ dev_name(&dev->dev), dev)) {
+ for (n--; n >= res->start; n--)
+ free_irq(n, dev);
+
goto rollback;
+ }
}
k++;
}
@@ -554,16 +556,17 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
if (hook)
return k > 0 ? 0 : -ENOENT;
- k--;
ret = 0;
rollback:
- for (q = k; k >= 0; k--) {
- for (m = n; m >= res->start; m--)
- free_irq(m, dev);
+ k--;
+
+ while (k >= 0) {
+ res = platform_get_resource(dev, IORESOURCE_IRQ, k);
+ for (n = res->start; n <= res->end; n++)
+ free_irq(n, dev);
- res = platform_get_resource(dev, IORESOURCE_IRQ, k - 1);
- m = res->end;
+ k--;
}
return ret;
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 4c6fff5f330d..0b012f1f8ac5 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -185,14 +185,8 @@ static int vt596_transaction(u8 size)
}
if (temp & 0x04) {
- int read = inb_p(SMBHSTADD) & 0x01;
result = -ENXIO;
- /* The quick and receive byte commands are used to probe
- for chips, so errors are expected, and we don't want
- to frighten the user. */
- if (!((size == VT596_QUICK && !read) ||
- (size == VT596_BYTE && read)))
- dev_err(&vt596_adapter.dev, "Transaction error!\n");
+ dev_dbg(&vt596_adapter.dev, "No response\n");
}
/* Resetting status register */
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 4cb4bb009950..53fab518b3da 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -560,7 +560,8 @@ static const struct pci_device_id scx200_pci[] __initconst = {
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA),
.driver_data = 1 },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA),
- .driver_data = 2 }
+ .driver_data = 2 },
+ { 0, }
};
static struct {
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index bea4c5021d26..d231f683f576 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -425,14 +425,14 @@ static int __i2c_check_addr_busy(struct device *dev, void *addrp)
/* walk up mux tree */
static int i2c_check_mux_parents(struct i2c_adapter *adapter, int addr)
{
+ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
int result;
result = device_for_each_child(&adapter->dev, &addr,
__i2c_check_addr_busy);
- if (!result && i2c_parent_is_i2c_adapter(adapter))
- result = i2c_check_mux_parents(
- to_i2c_adapter(adapter->dev.parent), addr);
+ if (!result && parent)
+ result = i2c_check_mux_parents(parent, addr);
return result;
}
@@ -453,11 +453,11 @@ static int i2c_check_mux_children(struct device *dev, void *addrp)
static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
{
+ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
int result = 0;
- if (i2c_parent_is_i2c_adapter(adapter))
- result = i2c_check_mux_parents(
- to_i2c_adapter(adapter->dev.parent), addr);
+ if (parent)
+ result = i2c_check_mux_parents(parent, addr);
if (!result)
result = device_for_each_child(&adapter->dev, &addr,
@@ -472,8 +472,10 @@ static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
*/
void i2c_lock_adapter(struct i2c_adapter *adapter)
{
- if (i2c_parent_is_i2c_adapter(adapter))
- i2c_lock_adapter(to_i2c_adapter(adapter->dev.parent));
+ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+
+ if (parent)
+ i2c_lock_adapter(parent);
else
rt_mutex_lock(&adapter->bus_lock);
}
@@ -485,8 +487,10 @@ EXPORT_SYMBOL_GPL(i2c_lock_adapter);
*/
static int i2c_trylock_adapter(struct i2c_adapter *adapter)
{
- if (i2c_parent_is_i2c_adapter(adapter))
- return i2c_trylock_adapter(to_i2c_adapter(adapter->dev.parent));
+ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+
+ if (parent)
+ return i2c_trylock_adapter(parent);
else
return rt_mutex_trylock(&adapter->bus_lock);
}
@@ -497,8 +501,10 @@ static int i2c_trylock_adapter(struct i2c_adapter *adapter)
*/
void i2c_unlock_adapter(struct i2c_adapter *adapter)
{
- if (i2c_parent_is_i2c_adapter(adapter))
- i2c_unlock_adapter(to_i2c_adapter(adapter->dev.parent));
+ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+
+ if (parent)
+ i2c_unlock_adapter(parent);
else
rt_mutex_unlock(&adapter->bus_lock);
}
@@ -677,8 +683,6 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
char *blank, end;
int res;
- dev_warn(dev, "The new_device interface is still experimental "
- "and may change in a near future\n");
memset(&info, 0, sizeof(struct i2c_board_info));
blank = strchr(buf, ' ');
@@ -1504,26 +1508,25 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
if (!driver->detect || !address_list)
return 0;
+ /* Stop here if the classes do not match */
+ if (!(adapter->class & driver->class))
+ return 0;
+
/* Set up a temporary client to help detect callback */
temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (!temp_client)
return -ENOMEM;
temp_client->adapter = adapter;
- /* Stop here if the classes do not match */
- if (!(adapter->class & driver->class))
- goto exit_free;
-
for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
"addr 0x%02x\n", adap_id, address_list[i]);
temp_client->addr = address_list[i];
err = i2c_detect_address(temp_client, driver);
- if (err)
- goto exit_free;
+ if (unlikely(err))
+ break;
}
- exit_free:
kfree(temp_client);
return err;
}
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 5f3a52d517c3..cec0f3ba97f8 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -192,13 +192,12 @@ static int i2cdev_check(struct device *dev, void *addrp)
/* walk up mux tree */
static int i2cdev_check_mux_parents(struct i2c_adapter *adapter, int addr)
{
+ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
int result;
result = device_for_each_child(&adapter->dev, &addr, i2cdev_check);
-
- if (!result && i2c_parent_is_i2c_adapter(adapter))
- result = i2cdev_check_mux_parents(
- to_i2c_adapter(adapter->dev.parent), addr);
+ if (!result && parent)
+ result = i2cdev_check_mux_parents(parent, addr);
return result;
}
@@ -222,11 +221,11 @@ static int i2cdev_check_mux_children(struct device *dev, void *addrp)
driver bound to it, as NOT busy. */
static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
{
+ struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
int result = 0;
- if (i2c_parent_is_i2c_adapter(adapter))
- result = i2cdev_check_mux_parents(
- to_i2c_adapter(adapter->dev.parent), addr);
+ if (parent)
+ result = i2cdev_check_mux_parents(parent, addr);
if (!result)
result = device_for_each_child(&adapter->dev, &addr,
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index 4c9a99c4fcb0..4d91d80bfd23 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -5,6 +5,16 @@
menu "Multiplexer I2C Chip support"
depends on I2C_MUX
+config I2C_MUX_PCA9541
+ tristate "NXP PCA9541 I2C Master Selector"
+ depends on EXPERIMENTAL
+ help
+ If you say yes here you get support for the NXP PCA9541
+ I2C Master Selector.
+
+ This driver can also be built as a module. If so, the module
+ will be called pca9541.
+
config I2C_MUX_PCA954x
tristate "Philips PCA954x I2C Mux/switches"
depends on EXPERIMENTAL
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
index bd83b5274815..d743806d9b42 100644
--- a/drivers/i2c/muxes/Makefile
+++ b/drivers/i2c/muxes/Makefile
@@ -1,8 +1,7 @@
#
# Makefile for multiplexer I2C chip drivers.
+obj-$(CONFIG_I2C_MUX_PCA9541) += pca9541.o
obj-$(CONFIG_I2C_MUX_PCA954x) += pca954x.o
-ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/muxes/pca9541.c b/drivers/i2c/muxes/pca9541.c
new file mode 100644
index 000000000000..ed699c5aa79d
--- /dev/null
+++ b/drivers/i2c/muxes/pca9541.c
@@ -0,0 +1,411 @@
+/*
+ * I2C multiplexer driver for PCA9541 bus master selector
+ *
+ * Copyright (c) 2010 Ericsson AB.
+ *
+ * Author: Guenter Roeck <guenter.roeck@ericsson.com>
+ *
+ * Derived from:
+ * pca954x.c
+ *
+ * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+
+#include <linux/i2c/pca954x.h>
+
+/*
+ * The PCA9541 is a bus master selector. It supports two I2C masters connected
+ * to a single slave bus.
+ *
+ * Before each bus transaction, a master has to acquire bus ownership. After the
+ * transaction is complete, bus ownership has to be released. This fits well
+ * into the I2C multiplexer framework, which provides select and release
+ * functions for this purpose. For this reason, this driver is modeled as
+ * single-channel I2C bus multiplexer.
+ *
+ * This driver assumes that the two bus masters are controlled by two different
+ * hosts. If a single host controls both masters, platform code has to ensure
+ * that only one of the masters is instantiated at any given time.
+ */
+
+#define PCA9541_CONTROL 0x01
+#define PCA9541_ISTAT 0x02
+
+#define PCA9541_CTL_MYBUS (1 << 0)
+#define PCA9541_CTL_NMYBUS (1 << 1)
+#define PCA9541_CTL_BUSON (1 << 2)
+#define PCA9541_CTL_NBUSON (1 << 3)
+#define PCA9541_CTL_BUSINIT (1 << 4)
+#define PCA9541_CTL_TESTON (1 << 6)
+#define PCA9541_CTL_NTESTON (1 << 7)
+
+#define PCA9541_ISTAT_INTIN (1 << 0)
+#define PCA9541_ISTAT_BUSINIT (1 << 1)
+#define PCA9541_ISTAT_BUSOK (1 << 2)
+#define PCA9541_ISTAT_BUSLOST (1 << 3)
+#define PCA9541_ISTAT_MYTEST (1 << 6)
+#define PCA9541_ISTAT_NMYTEST (1 << 7)
+
+#define BUSON (PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON)
+#define MYBUS (PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS)
+#define mybus(x) (!((x) & MYBUS) || ((x) & MYBUS) == MYBUS)
+#define busoff(x) (!((x) & BUSON) || ((x) & BUSON) == BUSON)
+
+/* arbitration timeouts, in jiffies */
+#define ARB_TIMEOUT (HZ / 8) /* 125 ms until forcing bus ownership */
+#define ARB2_TIMEOUT (HZ / 4) /* 250 ms until acquisition failure */
+
+/* arbitration retry delays, in us */
+#define SELECT_DELAY_SHORT 50
+#define SELECT_DELAY_LONG 1000
+
+struct pca9541 {
+ struct i2c_adapter *mux_adap;
+ unsigned long select_timeout;
+ unsigned long arb_timeout;
+};
+
+static const struct i2c_device_id pca9541_id[] = {
+ {"pca9541", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, pca9541_id);
+
+/*
+ * Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer()
+ * as they will try to lock the adapter a second time.
+ */
+static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val)
+{
+ struct i2c_adapter *adap = client->adapter;
+ int ret;
+
+ if (adap->algo->master_xfer) {
+ struct i2c_msg msg;
+ char buf[2];
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = 2;
+ buf[0] = command;
+ buf[1] = val;
+ msg.buf = buf;
+ ret = adap->algo->master_xfer(adap, &msg, 1);
+ } else {
+ union i2c_smbus_data data;
+
+ data.byte = val;
+ ret = adap->algo->smbus_xfer(adap, client->addr,
+ client->flags,
+ I2C_SMBUS_WRITE,
+ command,
+ I2C_SMBUS_BYTE_DATA, &data);
+ }
+
+ return ret;
+}
+
+/*
+ * Read from chip register. Don't use i2c_transfer()/i2c_smbus_xfer()
+ * as they will try to lock adapter a second time.
+ */
+static int pca9541_reg_read(struct i2c_client *client, u8 command)
+{
+ struct i2c_adapter *adap = client->adapter;
+ int ret;
+ u8 val;
+
+ if (adap->algo->master_xfer) {
+ struct i2c_msg msg[2] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &command
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = &val
+ }
+ };
+ ret = adap->algo->master_xfer(adap, msg, 2);
+ if (ret == 2)
+ ret = val;
+ else if (ret >= 0)
+ ret = -EIO;
+ } else {
+ union i2c_smbus_data data;
+
+ ret = adap->algo->smbus_xfer(adap, client->addr,
+ client->flags,
+ I2C_SMBUS_READ,
+ command,
+ I2C_SMBUS_BYTE_DATA, &data);
+ if (!ret)
+ ret = data.byte;
+ }
+ return ret;
+}
+
+/*
+ * Arbitration management functions
+ */
+
+/* Release bus. Also reset NTESTON and BUSINIT if it was set. */
+static void pca9541_release_bus(struct i2c_client *client)
+{
+ int reg;
+
+ reg = pca9541_reg_read(client, PCA9541_CONTROL);
+ if (reg >= 0 && !busoff(reg) && mybus(reg))
+ pca9541_reg_write(client, PCA9541_CONTROL,
+ (reg & PCA9541_CTL_NBUSON) >> 1);
+}
+
+/*
+ * Arbitration is defined as a two-step process. A bus master can only activate
+ * the slave bus if it owns it; otherwise it has to request ownership first.
+ * This multi-step process ensures that access contention is resolved
+ * gracefully.
+ *
+ * Bus Ownership Other master Action
+ * state requested access
+ * ----------------------------------------------------
+ * off - yes wait for arbitration timeout or
+ * for other master to drop request
+ * off no no take ownership
+ * off yes no turn on bus
+ * on yes - done
+ * on no - wait for arbitration timeout or
+ * for other master to release bus
+ *
+ * The main contention point occurs if the slave bus is off and both masters
+ * request ownership at the same time. In this case, one master will turn on
+ * the slave bus, believing that it owns it. The other master will request
+ * bus ownership. Result is that the bus is turned on, and master which did
+ * _not_ own the slave bus before ends up owning it.
+ */
+
+/* Control commands per PCA9541 datasheet */
+static const u8 pca9541_control[16] = {
+ 4, 0, 1, 5, 4, 4, 5, 5, 0, 0, 1, 1, 0, 4, 5, 1
+};
+
+/*
+ * Channel arbitration
+ *
+ * Return values:
+ * <0: error
+ * 0 : bus not acquired
+ * 1 : bus acquired
+ */
+static int pca9541_arbitrate(struct i2c_client *client)
+{
+ struct pca9541 *data = i2c_get_clientdata(client);
+ int reg;
+
+ reg = pca9541_reg_read(client, PCA9541_CONTROL);
+ if (reg < 0)
+ return reg;
+
+ if (busoff(reg)) {
+ int istat;
+ /*
+ * Bus is off. Request ownership or turn it on unless
+ * other master requested ownership.
+ */
+ istat = pca9541_reg_read(client, PCA9541_ISTAT);
+ if (!(istat & PCA9541_ISTAT_NMYTEST)
+ || time_is_before_eq_jiffies(data->arb_timeout)) {
+ /*
+ * Other master did not request ownership,
+ * or arbitration timeout expired. Take the bus.
+ */
+ pca9541_reg_write(client,
+ PCA9541_CONTROL,
+ pca9541_control[reg & 0x0f]
+ | PCA9541_CTL_NTESTON);
+ data->select_timeout = SELECT_DELAY_SHORT;
+ } else {
+ /*
+ * Other master requested ownership.
+ * Set extra long timeout to give it time to acquire it.
+ */
+ data->select_timeout = SELECT_DELAY_LONG * 2;
+ }
+ } else if (mybus(reg)) {
+ /*
+ * Bus is on, and we own it. We are done with acquisition.
+ * Reset NTESTON and BUSINIT, then return success.
+ */
+ if (reg & (PCA9541_CTL_NTESTON | PCA9541_CTL_BUSINIT))
+ pca9541_reg_write(client,
+ PCA9541_CONTROL,
+ reg & ~(PCA9541_CTL_NTESTON
+ | PCA9541_CTL_BUSINIT));
+ return 1;
+ } else {
+ /*
+ * Other master owns the bus.
+ * If arbitration timeout has expired, force ownership.
+ * Otherwise request it.
+ */
+ data->select_timeout = SELECT_DELAY_LONG;
+ if (time_is_before_eq_jiffies(data->arb_timeout)) {
+ /* Time is up, take the bus and reset it. */
+ pca9541_reg_write(client,
+ PCA9541_CONTROL,
+ pca9541_control[reg & 0x0f]
+ | PCA9541_CTL_BUSINIT
+ | PCA9541_CTL_NTESTON);
+ } else {
+ /* Request bus ownership if needed */
+ if (!(reg & PCA9541_CTL_NTESTON))
+ pca9541_reg_write(client,
+ PCA9541_CONTROL,
+ reg | PCA9541_CTL_NTESTON);
+ }
+ }
+ return 0;
+}
+
+static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
+{
+ struct pca9541 *data = i2c_get_clientdata(client);
+ int ret;
+ unsigned long timeout = jiffies + ARB2_TIMEOUT;
+ /* give up after this time */
+
+ data->arb_timeout = jiffies + ARB_TIMEOUT;
+ /* force bus ownership after this time */
+
+ do {
+ ret = pca9541_arbitrate(client);
+ if (ret)
+ return ret < 0 ? ret : 0;
+
+ if (data->select_timeout == SELECT_DELAY_SHORT)
+ udelay(data->select_timeout);
+ else
+ msleep(data->select_timeout / 1000);
+ } while (time_is_after_eq_jiffies(timeout));
+
+ return -ETIMEDOUT;
+}
+
+static int pca9541_release_chan(struct i2c_adapter *adap,
+ void *client, u32 chan)
+{
+ pca9541_release_bus(client);
+ return 0;
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+static int pca9541_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adap = client->adapter;
+ struct pca954x_platform_data *pdata = client->dev.platform_data;
+ struct pca9541 *data;
+ int force;
+ int ret = -ENODEV;
+
+ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
+ goto err;
+
+ data = kzalloc(sizeof(struct pca9541), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ i2c_set_clientdata(client, data);
+
+ /*
+ * I2C accesses are unprotected here.
+ * We have to lock the adapter before releasing the bus.
+ */
+ i2c_lock_adapter(adap);
+ pca9541_release_bus(client);
+ i2c_unlock_adapter(adap);
+
+ /* Create mux adapter */
+
+ force = 0;
+ if (pdata)
+ force = pdata->modes[0].adap_id;
+ data->mux_adap = i2c_add_mux_adapter(adap, client, force, 0,
+ pca9541_select_chan,
+ pca9541_release_chan);
+
+ if (data->mux_adap == NULL) {
+ dev_err(&client->dev, "failed to register master selector\n");
+ goto exit_free;
+ }
+
+ dev_info(&client->dev, "registered master selector for I2C %s\n",
+ client->name);
+
+ return 0;
+
+exit_free:
+ kfree(data);
+err:
+ return ret;
+}
+
+static int pca9541_remove(struct i2c_client *client)
+{
+ struct pca9541 *data = i2c_get_clientdata(client);
+
+ i2c_del_mux_adapter(data->mux_adap);
+
+ kfree(data);
+ return 0;
+}
+
+static struct i2c_driver pca9541_driver = {
+ .driver = {
+ .name = "pca9541",
+ .owner = THIS_MODULE,
+ },
+ .probe = pca9541_probe,
+ .remove = pca9541_remove,
+ .id_table = pca9541_id,
+};
+
+static int __init pca9541_init(void)
+{
+ return i2c_add_driver(&pca9541_driver);
+}
+
+static void __exit pca9541_exit(void)
+{
+ i2c_del_driver(&pca9541_driver);
+}
+
+module_init(pca9541_init);
+module_exit(pca9541_exit);
+
+MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_DESCRIPTION("PCA9541 I2C master selector driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c
index 6f9accf3189d..54e1ce73534b 100644
--- a/drivers/i2c/muxes/pca954x.c
+++ b/drivers/i2c/muxes/pca954x.c
@@ -181,8 +181,8 @@ static int pca954x_deselect_mux(struct i2c_adapter *adap,
/*
* I2C init/probing/exit functions
*/
-static int __devinit pca954x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int pca954x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
struct pca954x_platform_data *pdata = client->dev.platform_data;
@@ -255,7 +255,7 @@ err:
return ret;
}
-static int __devexit pca954x_remove(struct i2c_client *client)
+static int pca954x_remove(struct i2c_client *client)
{
struct pca954x *data = i2c_get_clientdata(client);
const struct chip_desc *chip = &chips[data->type];
@@ -279,7 +279,7 @@ static struct i2c_driver pca954x_driver = {
.owner = THIS_MODULE,
},
.probe = pca954x_probe,
- .remove = __devexit_p(pca954x_remove),
+ .remove = pca954x_remove,
.id_table = pca954x_id,
};
diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
index 45163693f737..97d98fbf5849 100644
--- a/drivers/ide/hpt366.c
+++ b/drivers/ide/hpt366.c
@@ -12,7 +12,7 @@
*
*
* HighPoint has its own drivers (open source except for the RAID part)
- * available from http://www.highpoint-tech.com/BIOS%20+%20Driver/.
+ * available from http://www.highpoint-tech.com/USA_new/service_support.htm
* This may be useful to anyone wanting to work on this driver, however do not
* trust them too much since the code tends to become less and less meaningful
* as the time passes... :-/
diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c
index d81e49680c3f..808bcdcbf8e1 100644
--- a/drivers/ide/ht6560b.c
+++ b/drivers/ide/ht6560b.c
@@ -10,7 +10,6 @@
* Author: Mikko Ala-Fossi <maf@iki.fi>
* Jan Evert van Grootheest <j.e.van.grootheest@caiway.nl>
*
- * Try: http://www.maf.iki.fi/~maf/ht6560b/
*/
#define DRV_NAME "ht6560b"
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 7c5b01ce51d2..274798068a54 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -435,12 +435,11 @@ static int idedisk_prep_fn(struct request_queue *q, struct request *rq)
if (!(rq->cmd_flags & REQ_FLUSH))
return BLKPREP_OK;
- cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
+ cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
/* FIXME: map struct ide_taskfile on rq->cmd[] */
BUG_ON(cmd == NULL);
- memset(cmd, 0, sizeof(*cmd));
if (ata_id_flush_ext_enabled(drive->id) &&
(drive->capacity64 >= (1UL << 28)))
cmd->tf.command = ATA_CMD_FLUSH_EXT;
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index cb3ccf3ed221..41665d2f9f93 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -74,7 +74,7 @@ static int max_cstate = MWAIT_MAX_NUM_CSTATES - 1;
static unsigned int mwait_substates;
/* Reliable LAPIC Timer States, bit 1 for C1 etc. */
-static unsigned int lapic_timer_reliable_states;
+static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */
static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
@@ -94,7 +94,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
.driver_data = (void *) 0x00,
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 3,
- .power_usage = 1000,
.target_residency = 6,
.enter = &intel_idle },
{ /* MWAIT C2 */
@@ -103,7 +102,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
.driver_data = (void *) 0x10,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 20,
- .power_usage = 500,
.target_residency = 80,
.enter = &intel_idle },
{ /* MWAIT C3 */
@@ -112,11 +110,46 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
.driver_data = (void *) 0x20,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 200,
- .power_usage = 350,
.target_residency = 800,
.enter = &intel_idle },
};
+static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
+ { /* MWAIT C0 */ },
+ { /* MWAIT C1 */
+ .name = "SNB-C1",
+ .desc = "MWAIT 0x00",
+ .driver_data = (void *) 0x00,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 1,
+ .target_residency = 4,
+ .enter = &intel_idle },
+ { /* MWAIT C2 */
+ .name = "SNB-C3",
+ .desc = "MWAIT 0x10",
+ .driver_data = (void *) 0x10,
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .exit_latency = 80,
+ .target_residency = 160,
+ .enter = &intel_idle },
+ { /* MWAIT C3 */
+ .name = "SNB-C6",
+ .desc = "MWAIT 0x20",
+ .driver_data = (void *) 0x20,
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .exit_latency = 104,
+ .target_residency = 208,
+ .enter = &intel_idle },
+ { /* MWAIT C4 */
+ .name = "SNB-C7",
+ .desc = "MWAIT 0x30",
+ .driver_data = (void *) 0x30,
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .exit_latency = 109,
+ .target_residency = 300,
+ .enter = &intel_idle },
+};
+
static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C0 */ },
{ /* MWAIT C1 */
@@ -125,7 +158,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
.driver_data = (void *) 0x00,
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 1,
- .power_usage = 1000,
.target_residency = 4,
.enter = &intel_idle },
{ /* MWAIT C2 */
@@ -134,7 +166,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
.driver_data = (void *) 0x10,
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 20,
- .power_usage = 500,
.target_residency = 80,
.enter = &intel_idle },
{ /* MWAIT C3 */ },
@@ -144,7 +175,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
.driver_data = (void *) 0x30,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 100,
- .power_usage = 250,
.target_residency = 400,
.enter = &intel_idle },
{ /* MWAIT C5 */ },
@@ -154,7 +184,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
.driver_data = (void *) 0x52,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 140,
- .power_usage = 150,
.target_residency = 560,
.enter = &intel_idle },
};
@@ -179,13 +208,10 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
local_irq_disable();
/*
- * If the state flag indicates that the TLB will be flushed or if this
- * is the deepest c-state supported, do a voluntary leave mm to avoid
- * costly and mostly unnecessary wakeups for flushing the user TLB's
- * associated with the active mm.
+ * leave_mm() to avoid costly and often unnecessary wakeups
+ * for flushing the user TLB's associated with the active mm.
*/
- if (state->flags & CPUIDLE_FLAG_TLB_FLUSHED ||
- (&dev->states[dev->state_count - 1] == state))
+ if (state->flags & CPUIDLE_FLAG_TLB_FLUSHED)
leave_mm(cpu);
if (!(lapic_timer_reliable_states & (1 << (cstate))))
@@ -269,9 +295,14 @@ static int intel_idle_probe(void)
case 0x1C: /* 28 - Atom Processor */
case 0x26: /* 38 - Lincroft Atom Processor */
- lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */
+ lapic_timer_reliable_states = (1 << 1); /* C1 */
cpuidle_state_table = atom_cstates;
break;
+
+ case 0x2A: /* SNB */
+ case 0x2D: /* SNB Xeon */
+ cpuidle_state_table = snb_cstates;
+ break;
#ifdef FUTURE_USE
case 0x17: /* 23 - Core 2 Duo */
lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
deleted file mode 100644
index e02096cf7d95..000000000000
--- a/drivers/ieee1394/Kconfig
+++ /dev/null
@@ -1,182 +0,0 @@
-config IEEE1394
- tristate "Legacy alternative FireWire driver stack"
- depends on PCI || BROKEN
- help
- IEEE 1394 describes a high performance serial bus, which is also
- known as FireWire(tm) or i.Link(tm) and is used for connecting all
- sorts of devices (most notably digital video cameras) to your
- computer.
-
- If you have FireWire hardware and want to use it, say Y here. This
- is the core support only, you will also need to select a driver for
- your IEEE 1394 adapter.
-
- To compile this driver as a module, say M here: the module will be
- called ieee1394.
-
- NOTE:
- ieee1394 is superseded by the newer firewire-core driver. See
- http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
- further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_OHCI1394
- tristate "OHCI-1394 controllers"
- depends on PCI && IEEE1394
- help
- Enable this driver if you have an IEEE 1394 controller based on the
- OHCI-1394 specification. The current driver is only tested with OHCI
- chipsets made by Texas Instruments and NEC. Most third-party vendors
- use one of these chipsets. It should work with any OHCI-1394
- compliant card, however.
-
- To compile this driver as a module, say M here: the module will be
- called ohci1394.
-
- NOTE:
- ohci1394 is superseded by the newer firewire-ohci driver. See
- http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
- further information on how to switch to the new FireWire drivers.
-
- If you want to install firewire-ohci and ohci1394 together, you
- should configure them only as modules and blacklist the driver(s)
- which you don't want to have auto-loaded. Add either
-
- blacklist ohci1394
- blacklist video1394
- blacklist dv1394
- or
- blacklist firewire-ohci
-
- to /etc/modprobe.conf or /etc/modprobe.d/* and update modprobe.conf
- depending on your distribution.
-
-comment "PCILynx controller requires I2C"
- depends on IEEE1394 && I2C=n
-
-config IEEE1394_PCILYNX
- tristate "PCILynx controller"
- depends on PCI && IEEE1394 && I2C
- select I2C_ALGOBIT
- help
- Say Y here if you have an IEEE-1394 controller with the Texas
- Instruments PCILynx chip. Note: this driver is written for revision
- 2 of this chip and may not work with revision 0.
-
- To compile this driver as a module, say M here: the module will be
- called pcilynx.
-
- Only some old and now very rare PCI and CardBus cards and
- PowerMacs G3 B&W contain the PCILynx controller. Therefore
- almost everybody can say N here.
-
-comment "SBP-2 support (for storage devices) requires SCSI"
- depends on IEEE1394 && SCSI=n
-
-config IEEE1394_SBP2
- tristate "Storage devices (SBP-2 protocol)"
- depends on IEEE1394 && SCSI
- help
- This option enables you to use SBP-2 devices connected to an IEEE
- 1394 bus. SBP-2 devices include storage devices like harddisks and
- DVD drives, also some other FireWire devices like scanners.
-
- You should also enable support for disks, CD-ROMs, etc. in the SCSI
- configuration section.
-
- To compile this driver as a module, say M here: the module will be
- called sbp2.
-
- NOTE:
- sbp2 is superseded by the newer firewire-sbp2 driver. See
- http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
- further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_SBP2_PHYS_DMA
- bool "Enable replacement for physical DMA in SBP2"
- depends on IEEE1394_SBP2 && VIRT_TO_BUS && EXPERIMENTAL
- help
- This builds sbp2 for use with non-OHCI host adapters which do not
- support physical DMA or for when ohci1394 is run with phys_dma=0.
- Physical DMA is data movement without assistance of the drivers'
- interrupt handlers. This option includes the interrupt handlers
- that are required in absence of this hardware feature.
-
- This option is buggy and currently broken on some architectures.
- If unsure, say N.
-
-config IEEE1394_ETH1394_ROM_ENTRY
- depends on IEEE1394
- bool
- default n
-
-config IEEE1394_ETH1394
- tristate "IP networking over 1394 (experimental)"
- depends on IEEE1394 && EXPERIMENTAL && INET
- select IEEE1394_ETH1394_ROM_ENTRY
- help
- This driver implements a functional majority of RFC 2734: IPv4 over
- 1394. It will provide IP connectivity with implementations of RFC
- 2734 found on other operating systems. It will not communicate with
- older versions of this driver found in stock kernels prior to 2.6.3.
- This driver is still considered experimental. It does not yet support
- MCAP, therefore multicast support is significantly limited.
-
- The module is called eth1394 although it does not emulate Ethernet.
-
- NOTE:
- eth1394 is superseded by the newer firewire-net driver. See
- http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
- further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_RAWIO
- tristate "raw1394 userspace interface"
- depends on IEEE1394
- help
- This option adds support for the raw1394 device file which enables
- direct communication of user programs with IEEE 1394 devices
- (isochronous and asynchronous). Almost all application programs
- which access FireWire require this option.
-
- To compile this driver as a module, say M here: the module will be
- called raw1394.
-
- NOTE:
- raw1394 is superseded by the newer firewire-core driver. See
- http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
- further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_VIDEO1394
- tristate "video1394 userspace interface"
- depends on IEEE1394 && IEEE1394_OHCI1394
- help
- This option adds support for the video1394 device files which enable
- isochronous communication of user programs with IEEE 1394 devices,
- especially video capture or export. This interface is used by all
- libdc1394 based programs and by several other programs, in addition to
- the raw1394 interface. It is generally not required for DV capture.
-
- To compile this driver as a module, say M here: the module will be
- called video1394.
-
- NOTE:
- video1394 is superseded by the newer firewire-core driver. See
- http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
- further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_DV1394
- tristate "dv1394 userspace interface (deprecated)"
- depends on IEEE1394 && IEEE1394_OHCI1394
- help
- The dv1394 driver is unsupported and may be removed from Linux in a
- future release. Its functionality is now provided by either
- raw1394 or firewire-core together with libraries such as libiec61883.
-
-config IEEE1394_VERBOSEDEBUG
- bool "Excessive debugging output"
- depends on IEEE1394
- help
- If you say Y here, you will get very verbose debugging logs from the
- ieee1394 drivers, including sent and received packet headers. This
- will quickly result in large amounts of data sent to the system log.
-
- Say Y if you really need the debugging output. Everyone else says N.
diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
deleted file mode 100644
index 1f8153b57503..000000000000
--- a/drivers/ieee1394/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Makefile for the Linux IEEE 1394 implementation
-#
-
-ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
- highlevel.o csr.o nodemgr.o dma.o iso.o \
- csr1212.o config_roms.o
-
-obj-$(CONFIG_IEEE1394) += ieee1394.o
-obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
-obj-$(CONFIG_IEEE1394_OHCI1394) += ohci1394.o
-obj-$(CONFIG_IEEE1394_VIDEO1394) += video1394.o
-obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o
-obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
-obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
-obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
-
-obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o
diff --git a/drivers/ieee1394/config_roms.c b/drivers/ieee1394/config_roms.c
deleted file mode 100644
index 1b981207fa76..000000000000
--- a/drivers/ieee1394/config_roms.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * ConfigROM entries
- *
- * Copyright (C) 2004 Ben Collins
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/types.h>
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "csr.h"
-#include "config_roms.h"
-
-struct hpsb_config_rom_entry {
- const char *name;
-
- /* Base initialization, called at module load */
- int (*init)(void);
-
- /* Cleanup called at module exit */
- void (*cleanup)(void);
-
- /* The flag added to host->config_roms */
- unsigned int flag;
-};
-
-/* The default host entry. This must succeed. */
-int hpsb_default_host_entry(struct hpsb_host *host)
-{
- struct csr1212_keyval *root;
- struct csr1212_keyval *vend_id = NULL;
- struct csr1212_keyval *text = NULL;
- char csr_name[128];
- int ret;
-
- sprintf(csr_name, "Linux - %s", host->driver->name);
- root = host->csr.rom->root_kv;
-
- vend_id = csr1212_new_immediate(CSR1212_KV_ID_VENDOR, host->csr.guid_hi >> 8);
- text = csr1212_new_string_descriptor_leaf(csr_name);
-
- if (!vend_id || !text) {
- if (vend_id)
- csr1212_release_keyval(vend_id);
- if (text)
- csr1212_release_keyval(text);
- csr1212_destroy_csr(host->csr.rom);
- return -ENOMEM;
- }
-
- csr1212_associate_keyval(vend_id, text);
- csr1212_release_keyval(text);
- ret = csr1212_attach_keyval_to_directory(root, vend_id);
- csr1212_release_keyval(vend_id);
- if (ret != CSR1212_SUCCESS) {
- csr1212_destroy_csr(host->csr.rom);
- return -ENOMEM;
- }
-
- host->update_config_rom = 1;
-
- return 0;
-}
-
-
-#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
-#include "eth1394.h"
-
-static struct csr1212_keyval *ip1394_ud;
-
-static int config_rom_ip1394_init(void)
-{
- struct csr1212_keyval *spec_id = NULL;
- struct csr1212_keyval *spec_desc = NULL;
- struct csr1212_keyval *ver = NULL;
- struct csr1212_keyval *ver_desc = NULL;
- int ret = -ENOMEM;
-
- ip1394_ud = csr1212_new_directory(CSR1212_KV_ID_UNIT);
-
- spec_id = csr1212_new_immediate(CSR1212_KV_ID_SPECIFIER_ID,
- ETHER1394_GASP_SPECIFIER_ID);
- spec_desc = csr1212_new_string_descriptor_leaf("IANA");
- ver = csr1212_new_immediate(CSR1212_KV_ID_VERSION,
- ETHER1394_GASP_VERSION);
- ver_desc = csr1212_new_string_descriptor_leaf("IPv4");
-
- if (!ip1394_ud || !spec_id || !spec_desc || !ver || !ver_desc)
- goto ip1394_fail;
-
- csr1212_associate_keyval(spec_id, spec_desc);
- csr1212_associate_keyval(ver, ver_desc);
- if (csr1212_attach_keyval_to_directory(ip1394_ud, spec_id)
- == CSR1212_SUCCESS &&
- csr1212_attach_keyval_to_directory(ip1394_ud, ver)
- == CSR1212_SUCCESS)
- ret = 0;
-
-ip1394_fail:
- if (ret && ip1394_ud) {
- csr1212_release_keyval(ip1394_ud);
- ip1394_ud = NULL;
- }
-
- if (spec_id)
- csr1212_release_keyval(spec_id);
- if (spec_desc)
- csr1212_release_keyval(spec_desc);
- if (ver)
- csr1212_release_keyval(ver);
- if (ver_desc)
- csr1212_release_keyval(ver_desc);
-
- return ret;
-}
-
-static void config_rom_ip1394_cleanup(void)
-{
- if (ip1394_ud) {
- csr1212_release_keyval(ip1394_ud);
- ip1394_ud = NULL;
- }
-}
-
-int hpsb_config_rom_ip1394_add(struct hpsb_host *host)
-{
- if (!ip1394_ud)
- return -ENODEV;
-
- if (csr1212_attach_keyval_to_directory(host->csr.rom->root_kv,
- ip1394_ud) != CSR1212_SUCCESS)
- return -ENOMEM;
-
- host->config_roms |= HPSB_CONFIG_ROM_ENTRY_IP1394;
- host->update_config_rom = 1;
- return 0;
-}
-EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_add);
-
-void hpsb_config_rom_ip1394_remove(struct hpsb_host *host)
-{
- csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, ip1394_ud);
- host->config_roms &= ~HPSB_CONFIG_ROM_ENTRY_IP1394;
- host->update_config_rom = 1;
-}
-EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_remove);
-
-static struct hpsb_config_rom_entry ip1394_entry = {
- .name = "ip1394",
- .init = config_rom_ip1394_init,
- .cleanup = config_rom_ip1394_cleanup,
- .flag = HPSB_CONFIG_ROM_ENTRY_IP1394,
-};
-
-#endif /* CONFIG_IEEE1394_ETH1394_ROM_ENTRY */
-
-static struct hpsb_config_rom_entry *const config_rom_entries[] = {
-#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
- &ip1394_entry,
-#endif
-};
-
-/* Initialize all config roms */
-int hpsb_init_config_roms(void)
-{
- int i, error = 0;
-
- for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
- if (config_rom_entries[i]->init()) {
- HPSB_ERR("Failed to initialize config rom entry `%s'",
- config_rom_entries[i]->name);
- error = -1;
- }
-
- return error;
-}
-
-/* Cleanup all config roms */
-void hpsb_cleanup_config_roms(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
- config_rom_entries[i]->cleanup();
-}
diff --git a/drivers/ieee1394/config_roms.h b/drivers/ieee1394/config_roms.h
deleted file mode 100644
index 1f5cd1f16c44..000000000000
--- a/drivers/ieee1394/config_roms.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _IEEE1394_CONFIG_ROMS_H
-#define _IEEE1394_CONFIG_ROMS_H
-
-struct hpsb_host;
-
-int hpsb_default_host_entry(struct hpsb_host *host);
-int hpsb_init_config_roms(void);
-void hpsb_cleanup_config_roms(void);
-
-/* List of flags to check if a host contains a certain extra config rom
- * entry. Available in the host->config_roms member. */
-#define HPSB_CONFIG_ROM_ENTRY_IP1394 0x00000001
-
-#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
-int hpsb_config_rom_ip1394_add(struct hpsb_host *host);
-void hpsb_config_rom_ip1394_remove(struct hpsb_host *host);
-#endif
-
-#endif /* _IEEE1394_CONFIG_ROMS_H */
diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c
deleted file mode 100644
index d696f69ebce5..000000000000
--- a/drivers/ieee1394/csr.c
+++ /dev/null
@@ -1,843 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * CSR implementation, iso/bus manager implementation.
- *
- * Copyright (C) 1999 Andreas E. Bombe
- * 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- * configuration ROM manipulation
- *
- */
-
-#include <linux/jiffies.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/param.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-
-#include "csr1212.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "highlevel.h"
-#include "ieee1394_core.h"
-
-/* Module Parameters */
-/* this module parameter can be used to disable mapping of the FCP registers */
-
-static int fcp = 1;
-module_param(fcp, int, 0444);
-MODULE_PARM_DESC(fcp, "Map FCP registers (default = 1, disable = 0).");
-
-static struct csr1212_keyval *node_cap = NULL;
-
-static void add_host(struct hpsb_host *host);
-static void remove_host(struct hpsb_host *host);
-static void host_reset(struct hpsb_host *host);
-static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
- u64 addr, size_t length, u16 fl);
-static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
- quadlet_t *data, u64 addr, size_t length, u16 flags);
-static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
- u64 addr, size_t length, u16 flags);
-static int write_regs(struct hpsb_host *host, int nodeid, int destid,
- quadlet_t *data, u64 addr, size_t length, u16 flags);
-static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
- u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl);
-static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
- u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl);
-static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
- u64 addr, size_t length, u16 fl);
-static u64 allocate_addr_range(u64 size, u32 alignment, void *__host);
-static void release_addr_range(u64 addr, void *__host);
-
-static struct hpsb_highlevel csr_highlevel = {
- .name = "standard registers",
- .add_host = add_host,
- .remove_host = remove_host,
- .host_reset = host_reset,
-};
-
-static const struct hpsb_address_ops map_ops = {
- .read = read_maps,
-};
-
-static const struct hpsb_address_ops fcp_ops = {
- .write = write_fcp,
-};
-
-static const struct hpsb_address_ops reg_ops = {
- .read = read_regs,
- .write = write_regs,
- .lock = lock_regs,
- .lock64 = lock64_regs,
-};
-
-static const struct hpsb_address_ops config_rom_ops = {
- .read = read_config_rom,
-};
-
-struct csr1212_bus_ops csr_bus_ops = {
- .allocate_addr_range = allocate_addr_range,
- .release_addr = release_addr_range,
-};
-
-
-static u16 csr_crc16(unsigned *data, int length)
-{
- int check=0, i;
- int shift, sum, next=0;
-
- for (i = length; i; i--) {
- for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
- sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf;
- next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
- }
- check = next & 0xffff;
- data++;
- }
-
- return check;
-}
-
-static void host_reset(struct hpsb_host *host)
-{
- host->csr.state &= 0x300;
-
- host->csr.bus_manager_id = 0x3f;
- host->csr.bandwidth_available = 4915;
- host->csr.channels_available_hi = 0xfffffffe; /* pre-alloc ch 31 per 1394a-2000 */
- host->csr.channels_available_lo = ~0;
- host->csr.broadcast_channel = 0x80000000 | 31;
-
- if (host->is_irm) {
- if (host->driver->hw_csr_reg) {
- host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
- }
- }
-
- host->csr.node_ids = host->node_id << 16;
-
- if (!host->is_root) {
- /* clear cmstr bit */
- host->csr.state &= ~0x100;
- }
-
- be32_add_cpu(&host->csr.topology_map[1], 1);
- host->csr.topology_map[2] = cpu_to_be32(host->node_count << 16
- | host->selfid_count);
- host->csr.topology_map[0] =
- cpu_to_be32((host->selfid_count + 2) << 16
- | csr_crc16(host->csr.topology_map + 1,
- host->selfid_count + 2));
-
- be32_add_cpu(&host->csr.speed_map[1], 1);
- host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16
- | csr_crc16(host->csr.speed_map+1,
- 0x3f1));
-}
-
-/*
- * HI == seconds (bits 0:2)
- * LO == fractions of a second in units of 125usec (bits 19:31)
- *
- * Convert SPLIT_TIMEOUT to jiffies.
- * The default and minimum as per 1394a-2000 clause 8.3.2.2.6 is 100ms.
- */
-static inline void calculate_expire(struct csr_control *csr)
-{
- unsigned int usecs = (csr->split_timeout_hi & 7) * 1000000 +
- (csr->split_timeout_lo >> 19) * 125;
-
- csr->expire = usecs_to_jiffies(usecs > 100000 ? usecs : 100000);
- HPSB_VERBOSE("CSR: setting expire to %lu, HZ=%u", csr->expire, HZ);
-}
-
-
-static void add_host(struct hpsb_host *host)
-{
- struct csr1212_keyval *root;
- quadlet_t bus_info[CSR_BUS_INFO_SIZE];
-
- hpsb_register_addrspace(&csr_highlevel, host, &reg_ops,
- CSR_REGISTER_BASE,
- CSR_REGISTER_BASE + CSR_CONFIG_ROM);
- hpsb_register_addrspace(&csr_highlevel, host, &config_rom_ops,
- CSR_REGISTER_BASE + CSR_CONFIG_ROM,
- CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
- if (fcp) {
- hpsb_register_addrspace(&csr_highlevel, host, &fcp_ops,
- CSR_REGISTER_BASE + CSR_FCP_COMMAND,
- CSR_REGISTER_BASE + CSR_FCP_END);
- }
- hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
- CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
- CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
- hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
- CSR_REGISTER_BASE + CSR_SPEED_MAP,
- CSR_REGISTER_BASE + CSR_SPEED_MAP_END);
-
- spin_lock_init(&host->csr.lock);
-
- host->csr.state = 0;
- host->csr.node_ids = 0;
- host->csr.split_timeout_hi = 0;
- host->csr.split_timeout_lo = 800 << 19;
- calculate_expire(&host->csr);
- host->csr.cycle_time = 0;
- host->csr.bus_time = 0;
- host->csr.bus_manager_id = 0x3f;
- host->csr.bandwidth_available = 4915;
- host->csr.channels_available_hi = 0xfffffffe; /* pre-alloc ch 31 per 1394a-2000 */
- host->csr.channels_available_lo = ~0;
- host->csr.broadcast_channel = 0x80000000 | 31;
-
- if (host->is_irm) {
- if (host->driver->hw_csr_reg) {
- host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
- }
- }
-
- if (host->csr.max_rec >= 9)
- host->csr.max_rom = 2;
- else if (host->csr.max_rec >= 5)
- host->csr.max_rom = 1;
- else
- host->csr.max_rom = 0;
-
- host->csr.generation = 2;
-
- bus_info[1] = IEEE1394_BUSID_MAGIC;
- bus_info[2] = cpu_to_be32((hpsb_disable_irm ? 0 : 1 << CSR_IRMC_SHIFT) |
- (1 << CSR_CMC_SHIFT) |
- (1 << CSR_ISC_SHIFT) |
- (0 << CSR_BMC_SHIFT) |
- (0 << CSR_PMC_SHIFT) |
- (host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
- (host->csr.max_rec << CSR_MAX_REC_SHIFT) |
- (host->csr.max_rom << CSR_MAX_ROM_SHIFT) |
- (host->csr.generation << CSR_GENERATION_SHIFT) |
- host->csr.lnk_spd);
-
- bus_info[3] = cpu_to_be32(host->csr.guid_hi);
- bus_info[4] = cpu_to_be32(host->csr.guid_lo);
-
- /* The hardware copy of the bus info block will be set later when a
- * bus reset is issued. */
-
- csr1212_init_local_csr(host->csr.rom, bus_info, host->csr.max_rom);
-
- root = host->csr.rom->root_kv;
-
- if(csr1212_attach_keyval_to_directory(root, node_cap) != CSR1212_SUCCESS) {
- HPSB_ERR("Failed to attach Node Capabilities to root directory");
- }
-
- host->update_config_rom = 1;
-}
-
-static void remove_host(struct hpsb_host *host)
-{
- quadlet_t bus_info[CSR_BUS_INFO_SIZE];
-
- bus_info[1] = IEEE1394_BUSID_MAGIC;
- bus_info[2] = cpu_to_be32((0 << CSR_IRMC_SHIFT) |
- (0 << CSR_CMC_SHIFT) |
- (0 << CSR_ISC_SHIFT) |
- (0 << CSR_BMC_SHIFT) |
- (0 << CSR_PMC_SHIFT) |
- (host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
- (host->csr.max_rec << CSR_MAX_REC_SHIFT) |
- (0 << CSR_MAX_ROM_SHIFT) |
- (0 << CSR_GENERATION_SHIFT) |
- host->csr.lnk_spd);
-
- bus_info[3] = cpu_to_be32(host->csr.guid_hi);
- bus_info[4] = cpu_to_be32(host->csr.guid_lo);
-
- csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, node_cap);
-
- csr1212_init_local_csr(host->csr.rom, bus_info, 0);
- host->update_config_rom = 1;
-}
-
-
-int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
- size_t buffersize, unsigned char rom_version)
-{
- unsigned long flags;
- int ret;
-
- HPSB_NOTICE("hpsb_update_config_rom() is deprecated");
-
- spin_lock_irqsave(&host->csr.lock, flags);
- if (rom_version != host->csr.generation)
- ret = -1;
- else if (buffersize > host->csr.rom->cache_head->size)
- ret = -2;
- else {
- /* Just overwrite the generated ConfigROM image with new data,
- * it can be regenerated later. */
- memcpy(host->csr.rom->cache_head->data, new_rom, buffersize);
- host->csr.rom->cache_head->len = buffersize;
-
- if (host->driver->set_hw_config_rom)
- host->driver->set_hw_config_rom(host, host->csr.rom->bus_info_data);
- /* Increment the generation number to keep some sort of sync
- * with the newer ConfigROM manipulation method. */
- host->csr.generation++;
- if (host->csr.generation > 0xf || host->csr.generation < 2)
- host->csr.generation = 2;
- ret=0;
- }
- spin_unlock_irqrestore(&host->csr.lock, flags);
- return ret;
-}
-
-
-/* Read topology / speed maps and configuration ROM */
-static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
- u64 addr, size_t length, u16 fl)
-{
- unsigned long flags;
- int csraddr = addr - CSR_REGISTER_BASE;
- const char *src;
-
- spin_lock_irqsave(&host->csr.lock, flags);
-
- if (csraddr < CSR_SPEED_MAP) {
- src = ((char *)host->csr.topology_map) + csraddr
- - CSR_TOPOLOGY_MAP;
- } else {
- src = ((char *)host->csr.speed_map) + csraddr - CSR_SPEED_MAP;
- }
-
- memcpy(buffer, src, length);
- spin_unlock_irqrestore(&host->csr.lock, flags);
- return RCODE_COMPLETE;
-}
-
-
-#define out if (--length == 0) break
-
-static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
- u64 addr, size_t length, u16 flags)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
- int oldcycle;
- quadlet_t ret;
-
- if ((csraddr | length) & 0x3)
- return RCODE_TYPE_ERROR;
-
- length /= 4;
-
- switch (csraddr) {
- case CSR_STATE_CLEAR:
- *(buf++) = cpu_to_be32(host->csr.state);
- out;
- case CSR_STATE_SET:
- *(buf++) = cpu_to_be32(host->csr.state);
- out;
- case CSR_NODE_IDS:
- *(buf++) = cpu_to_be32(host->csr.node_ids);
- out;
-
- case CSR_RESET_START:
- return RCODE_TYPE_ERROR;
-
- /* address gap - handled by default below */
-
- case CSR_SPLIT_TIMEOUT_HI:
- *(buf++) = cpu_to_be32(host->csr.split_timeout_hi);
- out;
- case CSR_SPLIT_TIMEOUT_LO:
- *(buf++) = cpu_to_be32(host->csr.split_timeout_lo);
- out;
-
- /* address gap */
- return RCODE_ADDRESS_ERROR;
-
- case CSR_CYCLE_TIME:
- oldcycle = host->csr.cycle_time;
- host->csr.cycle_time =
- host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
-
- if (oldcycle > host->csr.cycle_time) {
- /* cycle time wrapped around */
- host->csr.bus_time += 1 << 7;
- }
- *(buf++) = cpu_to_be32(host->csr.cycle_time);
- out;
- case CSR_BUS_TIME:
- oldcycle = host->csr.cycle_time;
- host->csr.cycle_time =
- host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
-
- if (oldcycle > host->csr.cycle_time) {
- /* cycle time wrapped around */
- host->csr.bus_time += (1 << 7);
- }
- *(buf++) = cpu_to_be32(host->csr.bus_time
- | (host->csr.cycle_time >> 25));
- out;
-
- /* address gap */
- return RCODE_ADDRESS_ERROR;
-
- case CSR_BUSY_TIMEOUT:
- /* not yet implemented */
- return RCODE_ADDRESS_ERROR;
-
- case CSR_BUS_MANAGER_ID:
- if (host->driver->hw_csr_reg)
- ret = host->driver->hw_csr_reg(host, 0, 0, 0);
- else
- ret = host->csr.bus_manager_id;
-
- *(buf++) = cpu_to_be32(ret);
- out;
- case CSR_BANDWIDTH_AVAILABLE:
- if (host->driver->hw_csr_reg)
- ret = host->driver->hw_csr_reg(host, 1, 0, 0);
- else
- ret = host->csr.bandwidth_available;
-
- *(buf++) = cpu_to_be32(ret);
- out;
- case CSR_CHANNELS_AVAILABLE_HI:
- if (host->driver->hw_csr_reg)
- ret = host->driver->hw_csr_reg(host, 2, 0, 0);
- else
- ret = host->csr.channels_available_hi;
-
- *(buf++) = cpu_to_be32(ret);
- out;
- case CSR_CHANNELS_AVAILABLE_LO:
- if (host->driver->hw_csr_reg)
- ret = host->driver->hw_csr_reg(host, 3, 0, 0);
- else
- ret = host->csr.channels_available_lo;
-
- *(buf++) = cpu_to_be32(ret);
- out;
-
- case CSR_BROADCAST_CHANNEL:
- *(buf++) = cpu_to_be32(host->csr.broadcast_channel);
- out;
-
- /* address gap to end - fall through to default */
- default:
- return RCODE_ADDRESS_ERROR;
- }
-
- return RCODE_COMPLETE;
-}
-
-static int write_regs(struct hpsb_host *host, int nodeid, int destid,
- quadlet_t *data, u64 addr, size_t length, u16 flags)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
-
- if ((csraddr | length) & 0x3)
- return RCODE_TYPE_ERROR;
-
- length /= 4;
-
- switch (csraddr) {
- case CSR_STATE_CLEAR:
- /* FIXME FIXME FIXME */
- printk("doh, someone wants to mess with state clear\n");
- out;
- case CSR_STATE_SET:
- printk("doh, someone wants to mess with state set\n");
- out;
-
- case CSR_NODE_IDS:
- host->csr.node_ids &= NODE_MASK << 16;
- host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16);
- host->node_id = host->csr.node_ids >> 16;
- host->driver->devctl(host, SET_BUS_ID, host->node_id >> 6);
- out;
-
- case CSR_RESET_START:
- /* FIXME - perform command reset */
- out;
-
- /* address gap */
- return RCODE_ADDRESS_ERROR;
-
- case CSR_SPLIT_TIMEOUT_HI:
- host->csr.split_timeout_hi =
- be32_to_cpu(*(data++)) & 0x00000007;
- calculate_expire(&host->csr);
- out;
- case CSR_SPLIT_TIMEOUT_LO:
- host->csr.split_timeout_lo =
- be32_to_cpu(*(data++)) & 0xfff80000;
- calculate_expire(&host->csr);
- out;
-
- /* address gap */
- return RCODE_ADDRESS_ERROR;
-
- case CSR_CYCLE_TIME:
- /* should only be set by cycle start packet, automatically */
- host->csr.cycle_time = be32_to_cpu(*data);
- host->driver->devctl(host, SET_CYCLE_COUNTER,
- be32_to_cpu(*(data++)));
- out;
- case CSR_BUS_TIME:
- host->csr.bus_time = be32_to_cpu(*(data++)) & 0xffffff80;
- out;
-
- /* address gap */
- return RCODE_ADDRESS_ERROR;
-
- case CSR_BUSY_TIMEOUT:
- /* not yet implemented */
- return RCODE_ADDRESS_ERROR;
-
- case CSR_BUS_MANAGER_ID:
- case CSR_BANDWIDTH_AVAILABLE:
- case CSR_CHANNELS_AVAILABLE_HI:
- case CSR_CHANNELS_AVAILABLE_LO:
- /* these are not writable, only lockable */
- return RCODE_TYPE_ERROR;
-
- case CSR_BROADCAST_CHANNEL:
- /* only the valid bit can be written */
- host->csr.broadcast_channel = (host->csr.broadcast_channel & ~0x40000000)
- | (be32_to_cpu(*data) & 0x40000000);
- out;
-
- /* address gap to end - fall through */
- default:
- return RCODE_ADDRESS_ERROR;
- }
-
- return RCODE_COMPLETE;
-}
-
-#undef out
-
-
-static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
- u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
- unsigned long flags;
- quadlet_t *regptr = NULL;
-
- if (csraddr & 0x3)
- return RCODE_TYPE_ERROR;
-
- if (csraddr < CSR_BUS_MANAGER_ID || csraddr > CSR_CHANNELS_AVAILABLE_LO
- || extcode != EXTCODE_COMPARE_SWAP)
- goto unsupported_lockreq;
-
- data = be32_to_cpu(data);
- arg = be32_to_cpu(arg);
-
- /* Is somebody releasing the broadcast_channel on us? */
- if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x1)) {
- /* Note: this is may not be the right way to handle
- * the problem, so we should look into the proper way
- * eventually. */
- HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
- "broadcast channel 31. Ignoring.",
- NODE_BUS_ARGS(host, nodeid));
-
- data &= ~0x1; /* keep broadcast channel allocated */
- }
-
- if (host->driver->hw_csr_reg) {
- quadlet_t old;
-
- old = host->driver->
- hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
- data, arg);
-
- *store = cpu_to_be32(old);
- return RCODE_COMPLETE;
- }
-
- spin_lock_irqsave(&host->csr.lock, flags);
-
- switch (csraddr) {
- case CSR_BUS_MANAGER_ID:
- regptr = &host->csr.bus_manager_id;
- *store = cpu_to_be32(*regptr);
- if (*regptr == arg)
- *regptr = data;
- break;
-
- case CSR_BANDWIDTH_AVAILABLE:
- {
- quadlet_t bandwidth;
- quadlet_t old;
- quadlet_t new;
-
- regptr = &host->csr.bandwidth_available;
- old = *regptr;
-
- /* bandwidth available algorithm adapted from IEEE 1394a-2000 spec */
- if (arg > 0x1fff) {
- *store = cpu_to_be32(old); /* change nothing */
- break;
- }
- data &= 0x1fff;
- if (arg >= data) {
- /* allocate bandwidth */
- bandwidth = arg - data;
- if (old >= bandwidth) {
- new = old - bandwidth;
- *store = cpu_to_be32(arg);
- *regptr = new;
- } else {
- *store = cpu_to_be32(old);
- }
- } else {
- /* deallocate bandwidth */
- bandwidth = data - arg;
- if (old + bandwidth < 0x2000) {
- new = old + bandwidth;
- *store = cpu_to_be32(arg);
- *regptr = new;
- } else {
- *store = cpu_to_be32(old);
- }
- }
- break;
- }
-
- case CSR_CHANNELS_AVAILABLE_HI:
- {
- /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
- quadlet_t affected_channels = arg ^ data;
-
- regptr = &host->csr.channels_available_hi;
-
- if ((arg & affected_channels) == (*regptr & affected_channels)) {
- *regptr ^= affected_channels;
- *store = cpu_to_be32(arg);
- } else {
- *store = cpu_to_be32(*regptr);
- }
-
- break;
- }
-
- case CSR_CHANNELS_AVAILABLE_LO:
- {
- /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
- quadlet_t affected_channels = arg ^ data;
-
- regptr = &host->csr.channels_available_lo;
-
- if ((arg & affected_channels) == (*regptr & affected_channels)) {
- *regptr ^= affected_channels;
- *store = cpu_to_be32(arg);
- } else {
- *store = cpu_to_be32(*regptr);
- }
- break;
- }
- }
-
- spin_unlock_irqrestore(&host->csr.lock, flags);
-
- return RCODE_COMPLETE;
-
- unsupported_lockreq:
- switch (csraddr) {
- case CSR_STATE_CLEAR:
- case CSR_STATE_SET:
- case CSR_RESET_START:
- case CSR_NODE_IDS:
- case CSR_SPLIT_TIMEOUT_HI:
- case CSR_SPLIT_TIMEOUT_LO:
- case CSR_CYCLE_TIME:
- case CSR_BUS_TIME:
- case CSR_BROADCAST_CHANNEL:
- return RCODE_TYPE_ERROR;
-
- case CSR_BUSY_TIMEOUT:
- /* not yet implemented - fall through */
- default:
- return RCODE_ADDRESS_ERROR;
- }
-}
-
-static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
- u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
- unsigned long flags;
-
- data = be64_to_cpu(data);
- arg = be64_to_cpu(arg);
-
- if (csraddr & 0x3)
- return RCODE_TYPE_ERROR;
-
- if (csraddr != CSR_CHANNELS_AVAILABLE
- || extcode != EXTCODE_COMPARE_SWAP)
- goto unsupported_lock64req;
-
- /* Is somebody releasing the broadcast_channel on us? */
- if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x100000000ULL)) {
- /* Note: this is may not be the right way to handle
- * the problem, so we should look into the proper way
- * eventually. */
- HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
- "broadcast channel 31. Ignoring.",
- NODE_BUS_ARGS(host, nodeid));
-
- data &= ~0x100000000ULL; /* keep broadcast channel allocated */
- }
-
- if (host->driver->hw_csr_reg) {
- quadlet_t data_hi, data_lo;
- quadlet_t arg_hi, arg_lo;
- quadlet_t old_hi, old_lo;
-
- data_hi = data >> 32;
- data_lo = data & 0xFFFFFFFF;
- arg_hi = arg >> 32;
- arg_lo = arg & 0xFFFFFFFF;
-
- old_hi = host->driver->hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
- data_hi, arg_hi);
-
- old_lo = host->driver->hw_csr_reg(host, ((csraddr + 4) - CSR_BUS_MANAGER_ID) >> 2,
- data_lo, arg_lo);
-
- *store = cpu_to_be64(((octlet_t)old_hi << 32) | old_lo);
- } else {
- octlet_t old;
- octlet_t affected_channels = arg ^ data;
-
- spin_lock_irqsave(&host->csr.lock, flags);
-
- old = ((octlet_t)host->csr.channels_available_hi << 32) | host->csr.channels_available_lo;
-
- if ((arg & affected_channels) == (old & affected_channels)) {
- host->csr.channels_available_hi ^= (affected_channels >> 32);
- host->csr.channels_available_lo ^= (affected_channels & 0xffffffff);
- *store = cpu_to_be64(arg);
- } else {
- *store = cpu_to_be64(old);
- }
-
- spin_unlock_irqrestore(&host->csr.lock, flags);
- }
-
- /* Is somebody erroneously releasing the broadcast_channel on us? */
- if (host->csr.channels_available_hi & 0x1)
- host->csr.channels_available_hi &= ~0x1;
-
- return RCODE_COMPLETE;
-
- unsupported_lock64req:
- switch (csraddr) {
- case CSR_STATE_CLEAR:
- case CSR_STATE_SET:
- case CSR_RESET_START:
- case CSR_NODE_IDS:
- case CSR_SPLIT_TIMEOUT_HI:
- case CSR_SPLIT_TIMEOUT_LO:
- case CSR_CYCLE_TIME:
- case CSR_BUS_TIME:
- case CSR_BUS_MANAGER_ID:
- case CSR_BROADCAST_CHANNEL:
- case CSR_BUSY_TIMEOUT:
- case CSR_BANDWIDTH_AVAILABLE:
- return RCODE_TYPE_ERROR;
-
- default:
- return RCODE_ADDRESS_ERROR;
- }
-}
-
-static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
- quadlet_t *data, u64 addr, size_t length, u16 flags)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
-
- if (length > 512)
- return RCODE_TYPE_ERROR;
-
- switch (csraddr) {
- case CSR_FCP_COMMAND:
- highlevel_fcp_request(host, nodeid, 0, (u8 *)data, length);
- break;
- case CSR_FCP_RESPONSE:
- highlevel_fcp_request(host, nodeid, 1, (u8 *)data, length);
- break;
- default:
- return RCODE_TYPE_ERROR;
- }
-
- return RCODE_COMPLETE;
-}
-
-static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
- u64 addr, size_t length, u16 fl)
-{
- u32 offset = addr - CSR1212_REGISTER_SPACE_BASE;
-
- if (csr1212_read(host->csr.rom, offset, buffer, length) == CSR1212_SUCCESS)
- return RCODE_COMPLETE;
- else
- return RCODE_ADDRESS_ERROR;
-}
-
-static u64 allocate_addr_range(u64 size, u32 alignment, void *__host)
-{
- struct hpsb_host *host = (struct hpsb_host*)__host;
-
- return hpsb_allocate_and_register_addrspace(&csr_highlevel,
- host,
- &config_rom_ops,
- size, alignment,
- CSR1212_UNITS_SPACE_BASE,
- CSR1212_UNITS_SPACE_END);
-}
-
-static void release_addr_range(u64 addr, void *__host)
-{
- struct hpsb_host *host = (struct hpsb_host*)__host;
- hpsb_unregister_addrspace(&csr_highlevel, host, addr);
-}
-
-
-int init_csr(void)
-{
- node_cap = csr1212_new_immediate(CSR1212_KV_ID_NODE_CAPABILITIES, 0x0083c0);
- if (!node_cap) {
- HPSB_ERR("Failed to allocate memory for Node Capabilties ConfigROM entry!");
- return -ENOMEM;
- }
-
- hpsb_register_highlevel(&csr_highlevel);
-
- return 0;
-}
-
-void cleanup_csr(void)
-{
- if (node_cap)
- csr1212_release_keyval(node_cap);
- hpsb_unregister_highlevel(&csr_highlevel);
-}
diff --git a/drivers/ieee1394/csr.h b/drivers/ieee1394/csr.h
deleted file mode 100644
index 90fb3f2192c3..000000000000
--- a/drivers/ieee1394/csr.h
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef _IEEE1394_CSR_H
-#define _IEEE1394_CSR_H
-
-#include <linux/spinlock_types.h>
-
-#include "csr1212.h"
-#include "ieee1394_types.h"
-
-#define CSR_REGISTER_BASE 0xfffff0000000ULL
-
-/* register offsets relative to CSR_REGISTER_BASE */
-#define CSR_STATE_CLEAR 0x0
-#define CSR_STATE_SET 0x4
-#define CSR_NODE_IDS 0x8
-#define CSR_RESET_START 0xc
-#define CSR_SPLIT_TIMEOUT_HI 0x18
-#define CSR_SPLIT_TIMEOUT_LO 0x1c
-#define CSR_CYCLE_TIME 0x200
-#define CSR_BUS_TIME 0x204
-#define CSR_BUSY_TIMEOUT 0x210
-#define CSR_BUS_MANAGER_ID 0x21c
-#define CSR_BANDWIDTH_AVAILABLE 0x220
-#define CSR_CHANNELS_AVAILABLE 0x224
-#define CSR_CHANNELS_AVAILABLE_HI 0x224
-#define CSR_CHANNELS_AVAILABLE_LO 0x228
-#define CSR_BROADCAST_CHANNEL 0x234
-#define CSR_CONFIG_ROM 0x400
-#define CSR_CONFIG_ROM_END 0x800
-#define CSR_FCP_COMMAND 0xB00
-#define CSR_FCP_RESPONSE 0xD00
-#define CSR_FCP_END 0xF00
-#define CSR_TOPOLOGY_MAP 0x1000
-#define CSR_TOPOLOGY_MAP_END 0x1400
-#define CSR_SPEED_MAP 0x2000
-#define CSR_SPEED_MAP_END 0x3000
-
-/* IEEE 1394 bus specific Configuration ROM Key IDs */
-#define IEEE1394_KV_ID_POWER_REQUIREMENTS (0x30)
-
-/* IEEE 1394 Bus Information Block specifics */
-#define CSR_BUS_INFO_SIZE (5 * sizeof(quadlet_t))
-
-#define CSR_IRMC_SHIFT 31
-#define CSR_CMC_SHIFT 30
-#define CSR_ISC_SHIFT 29
-#define CSR_BMC_SHIFT 28
-#define CSR_PMC_SHIFT 27
-#define CSR_CYC_CLK_ACC_SHIFT 16
-#define CSR_MAX_REC_SHIFT 12
-#define CSR_MAX_ROM_SHIFT 8
-#define CSR_GENERATION_SHIFT 4
-
-static inline void csr_set_bus_info_generation(struct csr1212_csr *csr, u8 gen)
-{
- csr->bus_info_data[2] &= ~cpu_to_be32(0xf << CSR_GENERATION_SHIFT);
- csr->bus_info_data[2] |= cpu_to_be32((u32)gen << CSR_GENERATION_SHIFT);
-}
-
-struct csr_control {
- spinlock_t lock;
-
- quadlet_t state;
- quadlet_t node_ids;
- quadlet_t split_timeout_hi, split_timeout_lo;
- unsigned long expire; /* Calculated from split_timeout */
- quadlet_t cycle_time;
- quadlet_t bus_time;
- quadlet_t bus_manager_id;
- quadlet_t bandwidth_available;
- quadlet_t channels_available_hi, channels_available_lo;
- quadlet_t broadcast_channel;
-
- /* Bus Info */
- quadlet_t guid_hi, guid_lo;
- u8 cyc_clk_acc;
- u8 max_rec;
- u8 max_rom;
- u8 generation; /* Only use values between 0x2 and 0xf */
- u8 lnk_spd;
-
- unsigned long gen_timestamp[16];
-
- struct csr1212_csr *rom;
-
- quadlet_t topology_map[256];
- quadlet_t speed_map[1024];
-};
-
-extern struct csr1212_bus_ops csr_bus_ops;
-
-int init_csr(void);
-void cleanup_csr(void);
-
-/* hpsb_update_config_rom() is deprecated */
-struct hpsb_host;
-int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
- size_t size, unsigned char rom_version);
-
-#endif /* _IEEE1394_CSR_H */
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
deleted file mode 100644
index e76cac64c533..000000000000
--- a/drivers/ieee1394/csr1212.c
+++ /dev/null
@@ -1,1467 +0,0 @@
-/*
- * csr1212.c -- IEEE 1212 Control and Status Register support for Linux
- *
- * Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
- * Steve Kinneberg <kinnebergsteve@acmsystems.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.
- * 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 name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-/* TODO List:
- * - Verify interface consistency: i.e., public functions that take a size
- * parameter expect size to be in bytes.
- */
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/kmemcheck.h>
-#include <linux/string.h>
-#include <asm/bug.h>
-#include <asm/byteorder.h>
-
-#include "csr1212.h"
-
-
-/* Permitted key type for each key id */
-#define __I (1 << CSR1212_KV_TYPE_IMMEDIATE)
-#define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET)
-#define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
-#define __L (1 << CSR1212_KV_TYPE_LEAF)
-static const u8 csr1212_key_id_type_map[0x30] = {
- __C, /* used by Apple iSight */
- __D | __L, /* Descriptor */
- __I | __D | __L, /* Bus_Dependent_Info */
- __I | __D | __L, /* Vendor */
- __I, /* Hardware_Version */
- 0, 0, /* Reserved */
- __D | __L | __I, /* Module */
- __I, 0, 0, 0, /* used by Apple iSight, Reserved */
- __I, /* Node_Capabilities */
- __L, /* EUI_64 */
- 0, 0, 0, /* Reserved */
- __D, /* Unit */
- __I, /* Specifier_ID */
- __I, /* Version */
- __I | __C | __D | __L, /* Dependent_Info */
- __L, /* Unit_Location */
- 0, /* Reserved */
- __I, /* Model */
- __D, /* Instance */
- __L, /* Keyword */
- __D, /* Feature */
- __L, /* Extended_ROM */
- __I, /* Extended_Key_Specifier_ID */
- __I, /* Extended_Key */
- __I | __C | __D | __L, /* Extended_Data */
- __L, /* Modifiable_Descriptor */
- __I, /* Directory_ID */
- __I, /* Revision */
-};
-#undef __I
-#undef __C
-#undef __D
-#undef __L
-
-
-#define quads_to_bytes(_q) ((_q) * sizeof(u32))
-#define bytes_to_quads(_b) DIV_ROUND_UP(_b, sizeof(u32))
-
-static void free_keyval(struct csr1212_keyval *kv)
-{
- if ((kv->key.type == CSR1212_KV_TYPE_LEAF) &&
- (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM))
- CSR1212_FREE(kv->value.leaf.data);
-
- CSR1212_FREE(kv);
-}
-
-static u16 csr1212_crc16(const u32 *buffer, size_t length)
-{
- int shift;
- u32 data;
- u16 sum, crc = 0;
-
- for (; length; length--) {
- data = be32_to_cpu(*buffer);
- buffer++;
- for (shift = 28; shift >= 0; shift -= 4 ) {
- sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
- crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
- }
- crc &= 0xffff;
- }
-
- return cpu_to_be16(crc);
-}
-
-/* Microsoft computes the CRC with the bytes in reverse order. */
-static u16 csr1212_msft_crc16(const u32 *buffer, size_t length)
-{
- int shift;
- u32 data;
- u16 sum, crc = 0;
-
- for (; length; length--) {
- data = le32_to_cpu(*buffer);
- buffer++;
- for (shift = 28; shift >= 0; shift -= 4 ) {
- sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
- crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
- }
- crc &= 0xffff;
- }
-
- return cpu_to_be16(crc);
-}
-
-static struct csr1212_dentry *
-csr1212_find_keyval(struct csr1212_keyval *dir, struct csr1212_keyval *kv)
-{
- struct csr1212_dentry *pos;
-
- for (pos = dir->value.directory.dentries_head;
- pos != NULL; pos = pos->next)
- if (pos->kv == kv)
- return pos;
- return NULL;
-}
-
-static struct csr1212_keyval *
-csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, u32 offset)
-{
- struct csr1212_keyval *kv;
-
- for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next)
- if (kv->offset == offset)
- return kv;
- return NULL;
-}
-
-
-/* Creation Routines */
-
-struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
- size_t bus_info_size, void *private)
-{
- struct csr1212_csr *csr;
-
- csr = CSR1212_MALLOC(sizeof(*csr));
- if (!csr)
- return NULL;
-
- csr->cache_head =
- csr1212_rom_cache_malloc(CSR1212_CONFIG_ROM_SPACE_OFFSET,
- CSR1212_CONFIG_ROM_SPACE_SIZE);
- if (!csr->cache_head) {
- CSR1212_FREE(csr);
- return NULL;
- }
-
- /* The keyval key id is not used for the root node, but a valid key id
- * that can be used for a directory needs to be passed to
- * csr1212_new_directory(). */
- csr->root_kv = csr1212_new_directory(CSR1212_KV_ID_VENDOR);
- if (!csr->root_kv) {
- CSR1212_FREE(csr->cache_head);
- CSR1212_FREE(csr);
- return NULL;
- }
-
- csr->bus_info_data = csr->cache_head->data;
- csr->bus_info_len = bus_info_size;
- csr->crc_len = bus_info_size;
- csr->ops = ops;
- csr->private = private;
- csr->cache_tail = csr->cache_head;
-
- return csr;
-}
-
-void csr1212_init_local_csr(struct csr1212_csr *csr,
- const u32 *bus_info_data, int max_rom)
-{
- static const int mr_map[] = { 4, 64, 1024, 0 };
-
- BUG_ON(max_rom & ~0x3);
- csr->max_rom = mr_map[max_rom];
- memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len);
-}
-
-static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key)
-{
- struct csr1212_keyval *kv;
-
- if (key < 0x30 && ((csr1212_key_id_type_map[key] & (1 << type)) == 0))
- return NULL;
-
- kv = CSR1212_MALLOC(sizeof(*kv));
- if (!kv)
- return NULL;
-
- atomic_set(&kv->refcnt, 1);
- kv->key.type = type;
- kv->key.id = key;
- kv->associate = NULL;
- kv->next = NULL;
- kv->prev = NULL;
- kv->offset = 0;
- kv->valid = 0;
- return kv;
-}
-
-struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value)
-{
- struct csr1212_keyval *kv;
-
- kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key);
- if (!kv)
- return NULL;
-
- kv->value.immediate = value;
- kv->valid = 1;
- return kv;
-}
-
-static struct csr1212_keyval *
-csr1212_new_leaf(u8 key, const void *data, size_t data_len)
-{
- struct csr1212_keyval *kv;
-
- kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key);
- if (!kv)
- return NULL;
-
- if (data_len > 0) {
- kv->value.leaf.data = CSR1212_MALLOC(data_len);
- if (!kv->value.leaf.data) {
- CSR1212_FREE(kv);
- return NULL;
- }
-
- if (data)
- memcpy(kv->value.leaf.data, data, data_len);
- } else {
- kv->value.leaf.data = NULL;
- }
-
- kv->value.leaf.len = bytes_to_quads(data_len);
- kv->offset = 0;
- kv->valid = 1;
-
- return kv;
-}
-
-static struct csr1212_keyval *
-csr1212_new_csr_offset(u8 key, u32 csr_offset)
-{
- struct csr1212_keyval *kv;
-
- kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key);
- if (!kv)
- return NULL;
-
- kv->value.csr_offset = csr_offset;
-
- kv->offset = 0;
- kv->valid = 1;
- return kv;
-}
-
-struct csr1212_keyval *csr1212_new_directory(u8 key)
-{
- struct csr1212_keyval *kv;
-
- kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key);
- if (!kv)
- return NULL;
-
- kv->value.directory.len = 0;
- kv->offset = 0;
- kv->value.directory.dentries_head = NULL;
- kv->value.directory.dentries_tail = NULL;
- kv->valid = 1;
- return kv;
-}
-
-void csr1212_associate_keyval(struct csr1212_keyval *kv,
- struct csr1212_keyval *associate)
-{
- BUG_ON(!kv || !associate || kv->key.id == CSR1212_KV_ID_DESCRIPTOR ||
- (associate->key.id != CSR1212_KV_ID_DESCRIPTOR &&
- associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO &&
- associate->key.id != CSR1212_KV_ID_EXTENDED_KEY &&
- associate->key.id != CSR1212_KV_ID_EXTENDED_DATA &&
- associate->key.id < 0x30) ||
- (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID &&
- associate->key.id != CSR1212_KV_ID_EXTENDED_KEY) ||
- (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
- associate->key.id != CSR1212_KV_ID_EXTENDED_DATA) ||
- (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
- kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) ||
- (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA &&
- kv->key.id != CSR1212_KV_ID_EXTENDED_KEY));
-
- if (kv->associate)
- csr1212_release_keyval(kv->associate);
-
- csr1212_keep_keyval(associate);
- kv->associate = associate;
-}
-
-static int __csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
- struct csr1212_keyval *kv,
- bool keep_keyval)
-{
- struct csr1212_dentry *dentry;
-
- BUG_ON(!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY);
-
- dentry = CSR1212_MALLOC(sizeof(*dentry));
- if (!dentry)
- return -ENOMEM;
-
- if (keep_keyval)
- csr1212_keep_keyval(kv);
- dentry->kv = kv;
-
- dentry->next = NULL;
- dentry->prev = dir->value.directory.dentries_tail;
-
- if (!dir->value.directory.dentries_head)
- dir->value.directory.dentries_head = dentry;
-
- if (dir->value.directory.dentries_tail)
- dir->value.directory.dentries_tail->next = dentry;
- dir->value.directory.dentries_tail = dentry;
-
- return CSR1212_SUCCESS;
-}
-
-int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
- struct csr1212_keyval *kv)
-{
- return __csr1212_attach_keyval_to_directory(dir, kv, true);
-}
-
-#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
- (&((kv)->value.leaf.data[1]))
-
-#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \
- ((kv)->value.leaf.data[0] = \
- cpu_to_be32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \
- ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)))
-#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \
- ((kv)->value.leaf.data[0] = \
- cpu_to_be32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \
- CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \
- ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)))
-
-static struct csr1212_keyval *
-csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id,
- const void *data, size_t data_len)
-{
- struct csr1212_keyval *kv;
-
- kv = csr1212_new_leaf(CSR1212_KV_ID_DESCRIPTOR, NULL,
- data_len + CSR1212_DESCRIPTOR_LEAF_OVERHEAD);
- if (!kv)
- return NULL;
-
- kmemcheck_annotate_variable(kv->value.leaf.data[0]);
- CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype);
- CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id);
-
- if (data)
- memcpy(CSR1212_DESCRIPTOR_LEAF_DATA(kv), data, data_len);
-
- return kv;
-}
-
-/* Check if string conforms to minimal ASCII as per IEEE 1212 clause 7.4 */
-static int csr1212_check_minimal_ascii(const char *s)
-{
- static const char minimal_ascii_table[] = {
- /* 1 2 4 8 16 32 64 128 */
- 128, /* --, --, --, --, --, --, --, 07, */
- 4 + 16 + 32, /* --, --, 0a, --, 0C, 0D, --, --, */
- 0, /* --, --, --, --, --, --, --, --, */
- 0, /* --, --, --, --, --, --, --, --, */
- 255 - 8 - 16, /* 20, 21, 22, --, --, 25, 26, 27, */
- 255, /* 28, 29, 2a, 2b, 2c, 2d, 2e, 2f, */
- 255, /* 30, 31, 32, 33, 34, 35, 36, 37, */
- 255, /* 38, 39, 3a, 3b, 3c, 3d, 3e, 3f, */
- 255, /* 40, 41, 42, 43, 44, 45, 46, 47, */
- 255, /* 48, 49, 4a, 4b, 4c, 4d, 4e, 4f, */
- 255, /* 50, 51, 52, 53, 54, 55, 56, 57, */
- 1 + 2 + 4 + 128, /* 58, 59, 5a, --, --, --, --, 5f, */
- 255 - 1, /* --, 61, 62, 63, 64, 65, 66, 67, */
- 255, /* 68, 69, 6a, 6b, 6c, 6d, 6e, 6f, */
- 255, /* 70, 71, 72, 73, 74, 75, 76, 77, */
- 1 + 2 + 4, /* 78, 79, 7a, --, --, --, --, --, */
- };
- int i, j;
-
- for (; *s; s++) {
- i = *s >> 3; /* i = *s / 8; */
- j = 1 << (*s & 3); /* j = 1 << (*s % 8); */
-
- if (i >= ARRAY_SIZE(minimal_ascii_table) ||
- !(minimal_ascii_table[i] & j))
- return -EINVAL;
- }
- return 0;
-}
-
-/* IEEE 1212 clause 7.5.4.1 textual descriptors (English, minimal ASCII) */
-struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s)
-{
- struct csr1212_keyval *kv;
- u32 *text;
- size_t str_len, quads;
-
- if (!s || !*s || csr1212_check_minimal_ascii(s))
- return NULL;
-
- str_len = strlen(s);
- quads = bytes_to_quads(str_len);
- kv = csr1212_new_descriptor_leaf(0, 0, NULL, quads_to_bytes(quads) +
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD);
- if (!kv)
- return NULL;
-
- kv->value.leaf.data[1] = 0; /* width, character_set, language */
- text = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv);
- text[quads - 1] = 0; /* padding */
- memcpy(text, s, str_len);
-
- return kv;
-}
-
-
-/* Destruction Routines */
-
-void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
- struct csr1212_keyval *kv)
-{
- struct csr1212_dentry *dentry;
-
- if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY)
- return;
-
- dentry = csr1212_find_keyval(dir, kv);
-
- if (!dentry)
- return;
-
- if (dentry->prev)
- dentry->prev->next = dentry->next;
- if (dentry->next)
- dentry->next->prev = dentry->prev;
- if (dir->value.directory.dentries_head == dentry)
- dir->value.directory.dentries_head = dentry->next;
- if (dir->value.directory.dentries_tail == dentry)
- dir->value.directory.dentries_tail = dentry->prev;
-
- CSR1212_FREE(dentry);
-
- csr1212_release_keyval(kv);
-}
-
-/* This function is used to free the memory taken by a keyval. If the given
- * keyval is a directory type, then any keyvals contained in that directory
- * will be destroyed as well if noone holds a reference on them. By means of
- * list manipulation, this routine will descend a directory structure in a
- * non-recursive manner. */
-void csr1212_release_keyval(struct csr1212_keyval *kv)
-{
- struct csr1212_keyval *k, *a;
- struct csr1212_dentry dentry;
- struct csr1212_dentry *head, *tail;
-
- if (!atomic_dec_and_test(&kv->refcnt))
- return;
-
- dentry.kv = kv;
- dentry.next = NULL;
- dentry.prev = NULL;
-
- head = &dentry;
- tail = head;
-
- while (head) {
- k = head->kv;
-
- while (k) {
- /* must not dec_and_test kv->refcnt again */
- if (k != kv && !atomic_dec_and_test(&k->refcnt))
- break;
-
- a = k->associate;
-
- if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) {
- /* If the current entry is a directory, move all
- * the entries to the destruction list. */
- if (k->value.directory.dentries_head) {
- tail->next =
- k->value.directory.dentries_head;
- k->value.directory.dentries_head->prev =
- tail;
- tail = k->value.directory.dentries_tail;
- }
- }
- free_keyval(k);
- k = a;
- }
-
- head = head->next;
- if (head) {
- if (head->prev && head->prev != &dentry)
- CSR1212_FREE(head->prev);
- head->prev = NULL;
- } else if (tail != &dentry) {
- CSR1212_FREE(tail);
- }
- }
-}
-
-void csr1212_destroy_csr(struct csr1212_csr *csr)
-{
- struct csr1212_csr_rom_cache *c, *oc;
- struct csr1212_cache_region *cr, *ocr;
-
- csr1212_release_keyval(csr->root_kv);
-
- c = csr->cache_head;
- while (c) {
- oc = c;
- cr = c->filled_head;
- while (cr) {
- ocr = cr;
- cr = cr->next;
- CSR1212_FREE(ocr);
- }
- c = c->next;
- CSR1212_FREE(oc);
- }
-
- CSR1212_FREE(csr);
-}
-
-
-/* CSR Image Creation */
-
-static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
-{
- struct csr1212_csr_rom_cache *cache;
- u64 csr_addr;
-
- BUG_ON(!csr || !csr->ops || !csr->ops->allocate_addr_range ||
- !csr->ops->release_addr || csr->max_rom < 1);
-
- /* ROM size must be a multiple of csr->max_rom */
- romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1);
-
- csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom,
- csr->private);
- if (csr_addr == CSR1212_INVALID_ADDR_SPACE)
- return -ENOMEM;
-
- if (csr_addr < CSR1212_REGISTER_SPACE_BASE) {
- /* Invalid address returned from allocate_addr_range(). */
- csr->ops->release_addr(csr_addr, csr->private);
- return -ENOMEM;
- }
-
- cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE,
- romsize);
- if (!cache) {
- csr->ops->release_addr(csr_addr, csr->private);
- return -ENOMEM;
- }
-
- cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF,
- CSR1212_KV_ID_EXTENDED_ROM);
- if (!cache->ext_rom) {
- csr->ops->release_addr(csr_addr, csr->private);
- CSR1212_FREE(cache);
- return -ENOMEM;
- }
-
- if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) !=
- CSR1212_SUCCESS) {
- csr1212_release_keyval(cache->ext_rom);
- csr->ops->release_addr(csr_addr, csr->private);
- CSR1212_FREE(cache);
- return -ENOMEM;
- }
- cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE;
- cache->ext_rom->value.leaf.len = -1;
- cache->ext_rom->value.leaf.data = cache->data;
-
- /* Add cache to tail of cache list */
- cache->prev = csr->cache_tail;
- csr->cache_tail->next = cache;
- csr->cache_tail = cache;
- return CSR1212_SUCCESS;
-}
-
-static void csr1212_remove_cache(struct csr1212_csr *csr,
- struct csr1212_csr_rom_cache *cache)
-{
- if (csr->cache_head == cache)
- csr->cache_head = cache->next;
- if (csr->cache_tail == cache)
- csr->cache_tail = cache->prev;
-
- if (cache->prev)
- cache->prev->next = cache->next;
- if (cache->next)
- cache->next->prev = cache->prev;
-
- if (cache->ext_rom) {
- csr1212_detach_keyval_from_directory(csr->root_kv,
- cache->ext_rom);
- csr1212_release_keyval(cache->ext_rom);
- }
-
- CSR1212_FREE(cache);
-}
-
-static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
- struct csr1212_keyval **layout_tail)
-{
- struct csr1212_dentry *dentry;
- struct csr1212_keyval *dkv;
- struct csr1212_keyval *last_extkey_spec = NULL;
- struct csr1212_keyval *last_extkey = NULL;
- int num_entries = 0;
-
- for (dentry = dir->value.directory.dentries_head; dentry;
- dentry = dentry->next) {
- for (dkv = dentry->kv; dkv; dkv = dkv->associate) {
- /* Special Case: Extended Key Specifier_ID */
- if (dkv->key.id ==
- CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
- if (last_extkey_spec == NULL)
- last_extkey_spec = dkv;
- else if (dkv->value.immediate !=
- last_extkey_spec->value.immediate)
- last_extkey_spec = dkv;
- else
- continue;
- /* Special Case: Extended Key */
- } else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
- if (last_extkey == NULL)
- last_extkey = dkv;
- else if (dkv->value.immediate !=
- last_extkey->value.immediate)
- last_extkey = dkv;
- else
- continue;
- }
-
- num_entries += 1;
-
- switch (dkv->key.type) {
- default:
- case CSR1212_KV_TYPE_IMMEDIATE:
- case CSR1212_KV_TYPE_CSR_OFFSET:
- break;
- case CSR1212_KV_TYPE_LEAF:
- case CSR1212_KV_TYPE_DIRECTORY:
- /* Remove from list */
- if (dkv->prev && (dkv->prev->next == dkv))
- dkv->prev->next = dkv->next;
- if (dkv->next && (dkv->next->prev == dkv))
- dkv->next->prev = dkv->prev;
- //if (dkv == *layout_tail)
- // *layout_tail = dkv->prev;
-
- /* Special case: Extended ROM leafs */
- if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
- dkv->value.leaf.len = -1;
- /* Don't add Extended ROM leafs in the
- * layout list, they are handled
- * differently. */
- break;
- }
-
- /* Add to tail of list */
- dkv->next = NULL;
- dkv->prev = *layout_tail;
- (*layout_tail)->next = dkv;
- *layout_tail = dkv;
- break;
- }
- }
- }
- return num_entries;
-}
-
-static size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
-{
- struct csr1212_keyval *ltail = kv;
- size_t agg_size = 0;
-
- while (kv) {
- switch (kv->key.type) {
- case CSR1212_KV_TYPE_LEAF:
- /* Add 1 quadlet for crc/len field */
- agg_size += kv->value.leaf.len + 1;
- break;
-
- case CSR1212_KV_TYPE_DIRECTORY:
- kv->value.directory.len =
- csr1212_generate_layout_subdir(kv, &ltail);
- /* Add 1 quadlet for crc/len field */
- agg_size += kv->value.directory.len + 1;
- break;
- }
- kv = kv->next;
- }
- return quads_to_bytes(agg_size);
-}
-
-static struct csr1212_keyval *
-csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
- struct csr1212_keyval *start_kv, int start_pos)
-{
- struct csr1212_keyval *kv = start_kv;
- struct csr1212_keyval *okv = start_kv;
- int pos = start_pos;
- int kv_len = 0, okv_len = 0;
-
- cache->layout_head = kv;
-
- while (kv && pos < cache->size) {
- /* Special case: Extended ROM leafs */
- if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
- kv->offset = cache->offset + pos;
-
- switch (kv->key.type) {
- case CSR1212_KV_TYPE_LEAF:
- kv_len = kv->value.leaf.len;
- break;
-
- case CSR1212_KV_TYPE_DIRECTORY:
- kv_len = kv->value.directory.len;
- break;
-
- default:
- /* Should never get here */
- WARN_ON(1);
- break;
- }
-
- pos += quads_to_bytes(kv_len + 1);
-
- if (pos <= cache->size) {
- okv = kv;
- okv_len = kv_len;
- kv = kv->next;
- }
- }
-
- cache->layout_tail = okv;
- cache->len = okv->offset - cache->offset + quads_to_bytes(okv_len + 1);
-
- return kv;
-}
-
-#define CSR1212_KV_KEY_SHIFT 24
-#define CSR1212_KV_KEY_TYPE_SHIFT 6
-#define CSR1212_KV_KEY_ID_MASK 0x3f
-#define CSR1212_KV_KEY_TYPE_MASK 0x3 /* after shift */
-
-static void
-csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u32 *data_buffer)
-{
- struct csr1212_dentry *dentry;
- struct csr1212_keyval *last_extkey_spec = NULL;
- struct csr1212_keyval *last_extkey = NULL;
- int index = 0;
-
- for (dentry = dir->value.directory.dentries_head;
- dentry;
- dentry = dentry->next) {
- struct csr1212_keyval *a;
-
- for (a = dentry->kv; a; a = a->associate) {
- u32 value = 0;
-
- /* Special Case: Extended Key Specifier_ID */
- if (a->key.id ==
- CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
- if (last_extkey_spec == NULL)
- last_extkey_spec = a;
- else if (a->value.immediate !=
- last_extkey_spec->value.immediate)
- last_extkey_spec = a;
- else
- continue;
-
- /* Special Case: Extended Key */
- } else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
- if (last_extkey == NULL)
- last_extkey = a;
- else if (a->value.immediate !=
- last_extkey->value.immediate)
- last_extkey = a;
- else
- continue;
- }
-
- switch (a->key.type) {
- case CSR1212_KV_TYPE_IMMEDIATE:
- value = a->value.immediate;
- break;
- case CSR1212_KV_TYPE_CSR_OFFSET:
- value = a->value.csr_offset;
- break;
- case CSR1212_KV_TYPE_LEAF:
- value = a->offset;
- value -= dir->offset + quads_to_bytes(1+index);
- value = bytes_to_quads(value);
- break;
- case CSR1212_KV_TYPE_DIRECTORY:
- value = a->offset;
- value -= dir->offset + quads_to_bytes(1+index);
- value = bytes_to_quads(value);
- break;
- default:
- /* Should never get here */
- WARN_ON(1);
- break;
- }
-
- value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) <<
- CSR1212_KV_KEY_SHIFT;
- value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) <<
- (CSR1212_KV_KEY_SHIFT +
- CSR1212_KV_KEY_TYPE_SHIFT);
- data_buffer[index] = cpu_to_be32(value);
- index++;
- }
- }
-}
-
-struct csr1212_keyval_img {
- u16 length;
- u16 crc;
-
- /* Must be last */
- u32 data[0]; /* older gcc can't handle [] which is standard */
-};
-
-static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
-{
- struct csr1212_keyval *kv, *nkv;
- struct csr1212_keyval_img *kvi;
-
- for (kv = cache->layout_head;
- kv != cache->layout_tail->next;
- kv = nkv) {
- kvi = (struct csr1212_keyval_img *)(cache->data +
- bytes_to_quads(kv->offset - cache->offset));
- switch (kv->key.type) {
- default:
- case CSR1212_KV_TYPE_IMMEDIATE:
- case CSR1212_KV_TYPE_CSR_OFFSET:
- /* Should never get here */
- WARN_ON(1);
- break;
-
- case CSR1212_KV_TYPE_LEAF:
- /* Don't copy over Extended ROM areas, they are
- * already filled out! */
- if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
- memcpy(kvi->data, kv->value.leaf.data,
- quads_to_bytes(kv->value.leaf.len));
-
- kvi->length = cpu_to_be16(kv->value.leaf.len);
- kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len);
- break;
-
- case CSR1212_KV_TYPE_DIRECTORY:
- csr1212_generate_tree_subdir(kv, kvi->data);
-
- kvi->length = cpu_to_be16(kv->value.directory.len);
- kvi->crc = csr1212_crc16(kvi->data,
- kv->value.directory.len);
- break;
- }
-
- nkv = kv->next;
- if (kv->prev)
- kv->prev->next = NULL;
- if (kv->next)
- kv->next->prev = NULL;
- kv->prev = NULL;
- kv->next = NULL;
- }
-}
-
-/* This size is arbitrarily chosen.
- * The struct overhead is subtracted for more economic allocations. */
-#define CSR1212_EXTENDED_ROM_SIZE (2048 - sizeof(struct csr1212_csr_rom_cache))
-
-int csr1212_generate_csr_image(struct csr1212_csr *csr)
-{
- struct csr1212_bus_info_block_img *bi;
- struct csr1212_csr_rom_cache *cache;
- struct csr1212_keyval *kv;
- size_t agg_size;
- int ret;
- int init_offset;
-
- BUG_ON(!csr);
-
- cache = csr->cache_head;
-
- bi = (struct csr1212_bus_info_block_img*)cache->data;
-
- bi->length = bytes_to_quads(csr->bus_info_len) - 1;
- bi->crc_length = bi->length;
- bi->crc = csr1212_crc16(bi->data, bi->crc_length);
-
- csr->root_kv->next = NULL;
- csr->root_kv->prev = NULL;
-
- agg_size = csr1212_generate_layout_order(csr->root_kv);
-
- init_offset = csr->bus_info_len;
-
- for (kv = csr->root_kv, cache = csr->cache_head;
- kv;
- cache = cache->next) {
- if (!cache) {
- /* Estimate approximate number of additional cache
- * regions needed (it assumes that the cache holding
- * the first 1K Config ROM space always exists). */
- int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE -
- (2 * sizeof(u32))) + 1;
-
- /* Add additional cache regions, extras will be
- * removed later */
- for (; est_c; est_c--) {
- ret = csr1212_append_new_cache(csr,
- CSR1212_EXTENDED_ROM_SIZE);
- if (ret != CSR1212_SUCCESS)
- return ret;
- }
- /* Need to re-layout for additional cache regions */
- agg_size = csr1212_generate_layout_order(csr->root_kv);
- kv = csr->root_kv;
- cache = csr->cache_head;
- init_offset = csr->bus_info_len;
- }
- kv = csr1212_generate_positions(cache, kv, init_offset);
- agg_size -= cache->len;
- init_offset = sizeof(u32);
- }
-
- /* Remove unused, excess cache regions */
- while (cache) {
- struct csr1212_csr_rom_cache *oc = cache;
-
- cache = cache->next;
- csr1212_remove_cache(csr, oc);
- }
-
- /* Go through the list backward so that when done, the correct CRC
- * will be calculated for the Extended ROM areas. */
- for (cache = csr->cache_tail; cache; cache = cache->prev) {
- /* Only Extended ROM caches should have this set. */
- if (cache->ext_rom) {
- int leaf_size;
-
- /* Make sure the Extended ROM leaf is a multiple of
- * max_rom in size. */
- BUG_ON(csr->max_rom < 1);
- leaf_size = (cache->len + (csr->max_rom - 1)) &
- ~(csr->max_rom - 1);
-
- /* Zero out the unused ROM region */
- memset(cache->data + bytes_to_quads(cache->len), 0x00,
- leaf_size - cache->len);
-
- /* Subtract leaf header */
- leaf_size -= sizeof(u32);
-
- /* Update the Extended ROM leaf length */
- cache->ext_rom->value.leaf.len =
- bytes_to_quads(leaf_size);
- } else {
- /* Zero out the unused ROM region */
- memset(cache->data + bytes_to_quads(cache->len), 0x00,
- cache->size - cache->len);
- }
-
- /* Copy the data into the cache buffer */
- csr1212_fill_cache(cache);
-
- if (cache != csr->cache_head) {
- /* Set the length and CRC of the extended ROM. */
- struct csr1212_keyval_img *kvi =
- (struct csr1212_keyval_img*)cache->data;
- u16 len = bytes_to_quads(cache->len) - 1;
-
- kvi->length = cpu_to_be16(len);
- kvi->crc = csr1212_crc16(kvi->data, len);
- }
- }
-
- return CSR1212_SUCCESS;
-}
-
-int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer, u32 len)
-{
- struct csr1212_csr_rom_cache *cache;
-
- for (cache = csr->cache_head; cache; cache = cache->next)
- if (offset >= cache->offset &&
- (offset + len) <= (cache->offset + cache->size)) {
- memcpy(buffer, &cache->data[
- bytes_to_quads(offset - cache->offset)],
- len);
- return CSR1212_SUCCESS;
- }
-
- return -ENOENT;
-}
-
-/*
- * Apparently there are many different wrong implementations of the CRC
- * algorithm. We don't fail, we just warn... approximately once per GUID.
- */
-static void
-csr1212_check_crc(const u32 *buffer, size_t length, u16 crc, __be32 *guid)
-{
- static u64 last_bad_eui64;
- u64 eui64 = ((u64)be32_to_cpu(guid[0]) << 32) | be32_to_cpu(guid[1]);
-
- if (csr1212_crc16(buffer, length) == crc ||
- csr1212_msft_crc16(buffer, length) == crc ||
- eui64 == last_bad_eui64)
- return;
-
- printk(KERN_DEBUG "ieee1394: config ROM CRC error\n");
- last_bad_eui64 = eui64;
-}
-
-/* Parse a chunk of data as a Config ROM */
-
-static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
-{
- struct csr1212_bus_info_block_img *bi;
- struct csr1212_cache_region *cr;
- int i;
- int ret;
-
- for (i = 0; i < csr->bus_info_len; i += sizeof(u32)) {
- ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
- &csr->cache_head->data[bytes_to_quads(i)],
- csr->private);
- if (ret != CSR1212_SUCCESS)
- return ret;
-
- /* check ROM header's info_length */
- if (i == 0 &&
- be32_to_cpu(csr->cache_head->data[0]) >> 24 !=
- bytes_to_quads(csr->bus_info_len) - 1)
- return -EINVAL;
- }
-
- bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
- csr->crc_len = quads_to_bytes(bi->crc_length);
-
- /* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that
- * is not always the case, so read the rest of the crc area 1 quadlet at
- * a time. */
- for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(u32)) {
- ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
- &csr->cache_head->data[bytes_to_quads(i)],
- csr->private);
- if (ret != CSR1212_SUCCESS)
- return ret;
- }
-
- csr1212_check_crc(bi->data, bi->crc_length, bi->crc,
- &csr->bus_info_data[3]);
-
- cr = CSR1212_MALLOC(sizeof(*cr));
- if (!cr)
- return -ENOMEM;
-
- cr->next = NULL;
- cr->prev = NULL;
- cr->offset_start = 0;
- cr->offset_end = csr->crc_len + 4;
-
- csr->cache_head->filled_head = cr;
- csr->cache_head->filled_tail = cr;
-
- return CSR1212_SUCCESS;
-}
-
-#define CSR1212_KV_KEY(q) (be32_to_cpu(q) >> CSR1212_KV_KEY_SHIFT)
-#define CSR1212_KV_KEY_TYPE(q) (CSR1212_KV_KEY(q) >> CSR1212_KV_KEY_TYPE_SHIFT)
-#define CSR1212_KV_KEY_ID(q) (CSR1212_KV_KEY(q) & CSR1212_KV_KEY_ID_MASK)
-#define CSR1212_KV_VAL_MASK 0xffffff
-#define CSR1212_KV_VAL(q) (be32_to_cpu(q) & CSR1212_KV_VAL_MASK)
-
-static int
-csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
-{
- int ret = CSR1212_SUCCESS;
- struct csr1212_keyval *k = NULL;
- u32 offset;
- bool keep_keyval = true;
-
- switch (CSR1212_KV_KEY_TYPE(ki)) {
- case CSR1212_KV_TYPE_IMMEDIATE:
- k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki),
- CSR1212_KV_VAL(ki));
- if (!k) {
- ret = -ENOMEM;
- goto out;
- }
- /* Don't keep local reference when parsing. */
- keep_keyval = false;
- break;
-
- case CSR1212_KV_TYPE_CSR_OFFSET:
- k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki),
- CSR1212_KV_VAL(ki));
- if (!k) {
- ret = -ENOMEM;
- goto out;
- }
- /* Don't keep local reference when parsing. */
- keep_keyval = false;
- break;
-
- default:
- /* Compute the offset from 0xffff f000 0000. */
- offset = quads_to_bytes(CSR1212_KV_VAL(ki)) + kv_pos;
- if (offset == kv_pos) {
- /* Uh-oh. Can't have a relative offset of 0 for Leaves
- * or Directories. The Config ROM image is most likely
- * messed up, so we'll just abort here. */
- ret = -EIO;
- goto out;
- }
-
- k = csr1212_find_keyval_offset(dir, offset);
-
- if (k)
- break; /* Found it. */
-
- if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY)
- k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki));
- else
- k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0);
-
- if (!k) {
- ret = -ENOMEM;
- goto out;
- }
- /* Don't keep local reference when parsing. */
- keep_keyval = false;
- /* Contents not read yet so it's not valid. */
- k->valid = 0;
- k->offset = offset;
-
- k->prev = dir;
- k->next = dir->next;
- dir->next->prev = k;
- dir->next = k;
- }
- ret = __csr1212_attach_keyval_to_directory(dir, k, keep_keyval);
-out:
- if (ret != CSR1212_SUCCESS && k != NULL)
- free_keyval(k);
- return ret;
-}
-
-int csr1212_parse_keyval(struct csr1212_keyval *kv,
- struct csr1212_csr_rom_cache *cache)
-{
- struct csr1212_keyval_img *kvi;
- int i;
- int ret = CSR1212_SUCCESS;
- int kvi_len;
-
- kvi = (struct csr1212_keyval_img*)
- &cache->data[bytes_to_quads(kv->offset - cache->offset)];
- kvi_len = be16_to_cpu(kvi->length);
-
- /* GUID is wrong in here in case of extended ROM. We don't care. */
- csr1212_check_crc(kvi->data, kvi_len, kvi->crc, &cache->data[3]);
-
- switch (kv->key.type) {
- case CSR1212_KV_TYPE_DIRECTORY:
- for (i = 0; i < kvi_len; i++) {
- u32 ki = kvi->data[i];
-
- /* Some devices put null entries in their unit
- * directories. If we come across such an entry,
- * then skip it. */
- if (ki == 0x0)
- continue;
- ret = csr1212_parse_dir_entry(kv, ki,
- kv->offset + quads_to_bytes(i + 1));
- }
- kv->value.directory.len = kvi_len;
- break;
-
- case CSR1212_KV_TYPE_LEAF:
- if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
- size_t size = quads_to_bytes(kvi_len);
-
- kv->value.leaf.data = CSR1212_MALLOC(size);
- if (!kv->value.leaf.data) {
- ret = -ENOMEM;
- goto out;
- }
-
- kv->value.leaf.len = kvi_len;
- memcpy(kv->value.leaf.data, kvi->data, size);
- }
- break;
- }
-
- kv->valid = 1;
-out:
- return ret;
-}
-
-static int
-csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
-{
- struct csr1212_cache_region *cr, *ncr, *newcr = NULL;
- struct csr1212_keyval_img *kvi = NULL;
- struct csr1212_csr_rom_cache *cache;
- int cache_index;
- u64 addr;
- u32 *cache_ptr;
- u16 kv_len = 0;
-
- BUG_ON(!csr || !kv || csr->max_rom < 1);
-
- /* First find which cache the data should be in (or go in if not read
- * yet). */
- for (cache = csr->cache_head; cache; cache = cache->next)
- if (kv->offset >= cache->offset &&
- kv->offset < (cache->offset + cache->size))
- break;
-
- if (!cache) {
- u32 q, cache_size;
-
- /* Only create a new cache for Extended ROM leaves. */
- if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
- return -EINVAL;
-
- if (csr->ops->bus_read(csr,
- CSR1212_REGISTER_SPACE_BASE + kv->offset,
- &q, csr->private))
- return -EIO;
-
- kv->value.leaf.len = be32_to_cpu(q) >> 16;
-
- cache_size = (quads_to_bytes(kv->value.leaf.len + 1) +
- (csr->max_rom - 1)) & ~(csr->max_rom - 1);
-
- cache = csr1212_rom_cache_malloc(kv->offset, cache_size);
- if (!cache)
- return -ENOMEM;
-
- kv->value.leaf.data = &cache->data[1];
- csr->cache_tail->next = cache;
- cache->prev = csr->cache_tail;
- cache->next = NULL;
- csr->cache_tail = cache;
- cache->filled_head =
- CSR1212_MALLOC(sizeof(*cache->filled_head));
- if (!cache->filled_head)
- return -ENOMEM;
-
- cache->filled_head->offset_start = 0;
- cache->filled_head->offset_end = sizeof(u32);
- cache->filled_tail = cache->filled_head;
- cache->filled_head->next = NULL;
- cache->filled_head->prev = NULL;
- cache->data[0] = q;
-
- /* Don't read the entire extended ROM now. Pieces of it will
- * be read when entries inside it are read. */
- return csr1212_parse_keyval(kv, cache);
- }
-
- cache_index = kv->offset - cache->offset;
-
- /* Now seach read portions of the cache to see if it is there. */
- for (cr = cache->filled_head; cr; cr = cr->next) {
- if (cache_index < cr->offset_start) {
- newcr = CSR1212_MALLOC(sizeof(*newcr));
- if (!newcr)
- return -ENOMEM;
-
- newcr->offset_start = cache_index & ~(csr->max_rom - 1);
- newcr->offset_end = newcr->offset_start;
- newcr->next = cr;
- newcr->prev = cr->prev;
- cr->prev = newcr;
- cr = newcr;
- break;
- } else if ((cache_index >= cr->offset_start) &&
- (cache_index < cr->offset_end)) {
- kvi = (struct csr1212_keyval_img*)
- (&cache->data[bytes_to_quads(cache_index)]);
- kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
- break;
- } else if (cache_index == cr->offset_end) {
- break;
- }
- }
-
- if (!cr) {
- cr = cache->filled_tail;
- newcr = CSR1212_MALLOC(sizeof(*newcr));
- if (!newcr)
- return -ENOMEM;
-
- newcr->offset_start = cache_index & ~(csr->max_rom - 1);
- newcr->offset_end = newcr->offset_start;
- newcr->prev = cr;
- newcr->next = cr->next;
- cr->next = newcr;
- cr = newcr;
- cache->filled_tail = newcr;
- }
-
- while(!kvi || cr->offset_end < cache_index + kv_len) {
- cache_ptr = &cache->data[bytes_to_quads(cr->offset_end &
- ~(csr->max_rom - 1))];
-
- addr = (CSR1212_CSR_ARCH_REG_SPACE_BASE + cache->offset +
- cr->offset_end) & ~(csr->max_rom - 1);
-
- if (csr->ops->bus_read(csr, addr, cache_ptr, csr->private))
- return -EIO;
-
- cr->offset_end += csr->max_rom - (cr->offset_end &
- (csr->max_rom - 1));
-
- if (!kvi && (cr->offset_end > cache_index)) {
- kvi = (struct csr1212_keyval_img*)
- (&cache->data[bytes_to_quads(cache_index)]);
- kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
- }
-
- if ((kv_len + (kv->offset - cache->offset)) > cache->size) {
- /* The Leaf or Directory claims its length extends
- * beyond the ConfigROM image region and thus beyond the
- * end of our cache region. Therefore, we abort now
- * rather than seg faulting later. */
- return -EIO;
- }
-
- ncr = cr->next;
-
- if (ncr && (cr->offset_end >= ncr->offset_start)) {
- /* consolidate region entries */
- ncr->offset_start = cr->offset_start;
-
- if (cr->prev)
- cr->prev->next = cr->next;
- ncr->prev = cr->prev;
- if (cache->filled_head == cr)
- cache->filled_head = ncr;
- CSR1212_FREE(cr);
- cr = ncr;
- }
- }
-
- return csr1212_parse_keyval(kv, cache);
-}
-
-struct csr1212_keyval *
-csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
-{
- if (!kv)
- return NULL;
- if (!kv->valid)
- if (csr1212_read_keyval(csr, kv) != CSR1212_SUCCESS)
- return NULL;
- return kv;
-}
-
-int csr1212_parse_csr(struct csr1212_csr *csr)
-{
- struct csr1212_dentry *dentry;
- int ret;
-
- BUG_ON(!csr || !csr->ops || !csr->ops->bus_read);
-
- ret = csr1212_parse_bus_info_block(csr);
- if (ret != CSR1212_SUCCESS)
- return ret;
-
- /*
- * There has been a buggy firmware with bus_info_block.max_rom > 0
- * spotted which actually only supported quadlet read requests to the
- * config ROM. Therefore read everything quadlet by quadlet regardless
- * of what the bus info block says.
- */
- csr->max_rom = 4;
-
- csr->cache_head->layout_head = csr->root_kv;
- csr->cache_head->layout_tail = csr->root_kv;
-
- csr->root_kv->offset = (CSR1212_CONFIG_ROM_SPACE_BASE & 0xffff) +
- csr->bus_info_len;
-
- csr->root_kv->valid = 0;
- csr->root_kv->next = csr->root_kv;
- csr->root_kv->prev = csr->root_kv;
- ret = csr1212_read_keyval(csr, csr->root_kv);
- if (ret != CSR1212_SUCCESS)
- return ret;
-
- /* Scan through the Root directory finding all extended ROM regions
- * and make cache regions for them */
- for (dentry = csr->root_kv->value.directory.dentries_head;
- dentry; dentry = dentry->next) {
- if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM &&
- !dentry->kv->valid) {
- ret = csr1212_read_keyval(csr, dentry->kv);
- if (ret != CSR1212_SUCCESS)
- return ret;
- }
- }
-
- return CSR1212_SUCCESS;
-}
diff --git a/drivers/ieee1394/csr1212.h b/drivers/ieee1394/csr1212.h
deleted file mode 100644
index a892d922dbc9..000000000000
--- a/drivers/ieee1394/csr1212.h
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * csr1212.h -- IEEE 1212 Control and Status Register support for Linux
- *
- * Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
- * Steve Kinneberg <kinnebergsteve@acmsystems.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.
- * 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 name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __CSR1212_H__
-#define __CSR1212_H__
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <asm/atomic.h>
-
-#define CSR1212_MALLOC(size) kmalloc((size), GFP_KERNEL)
-#define CSR1212_FREE(ptr) kfree(ptr)
-
-#define CSR1212_SUCCESS (0)
-
-
-/* CSR 1212 key types */
-#define CSR1212_KV_TYPE_IMMEDIATE 0
-#define CSR1212_KV_TYPE_CSR_OFFSET 1
-#define CSR1212_KV_TYPE_LEAF 2
-#define CSR1212_KV_TYPE_DIRECTORY 3
-
-
-/* CSR 1212 key ids */
-#define CSR1212_KV_ID_DESCRIPTOR 0x01
-#define CSR1212_KV_ID_BUS_DEPENDENT_INFO 0x02
-#define CSR1212_KV_ID_VENDOR 0x03
-#define CSR1212_KV_ID_HARDWARE_VERSION 0x04
-#define CSR1212_KV_ID_MODULE 0x07
-#define CSR1212_KV_ID_NODE_CAPABILITIES 0x0C
-#define CSR1212_KV_ID_EUI_64 0x0D
-#define CSR1212_KV_ID_UNIT 0x11
-#define CSR1212_KV_ID_SPECIFIER_ID 0x12
-#define CSR1212_KV_ID_VERSION 0x13
-#define CSR1212_KV_ID_DEPENDENT_INFO 0x14
-#define CSR1212_KV_ID_UNIT_LOCATION 0x15
-#define CSR1212_KV_ID_MODEL 0x17
-#define CSR1212_KV_ID_INSTANCE 0x18
-#define CSR1212_KV_ID_KEYWORD 0x19
-#define CSR1212_KV_ID_FEATURE 0x1A
-#define CSR1212_KV_ID_EXTENDED_ROM 0x1B
-#define CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID 0x1C
-#define CSR1212_KV_ID_EXTENDED_KEY 0x1D
-#define CSR1212_KV_ID_EXTENDED_DATA 0x1E
-#define CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR 0x1F
-#define CSR1212_KV_ID_DIRECTORY_ID 0x20
-#define CSR1212_KV_ID_REVISION 0x21
-
-
-/* IEEE 1212 Address space map */
-#define CSR1212_ALL_SPACE_BASE (0x000000000000ULL)
-#define CSR1212_ALL_SPACE_SIZE (1ULL << 48)
-#define CSR1212_ALL_SPACE_END (CSR1212_ALL_SPACE_BASE + CSR1212_ALL_SPACE_SIZE)
-
-#define CSR1212_MEMORY_SPACE_BASE (0x000000000000ULL)
-#define CSR1212_MEMORY_SPACE_SIZE ((256ULL * (1ULL << 40)) - (512ULL * (1ULL << 20)))
-#define CSR1212_MEMORY_SPACE_END (CSR1212_MEMORY_SPACE_BASE + CSR1212_MEMORY_SPACE_SIZE)
-
-#define CSR1212_PRIVATE_SPACE_BASE (0xffffe0000000ULL)
-#define CSR1212_PRIVATE_SPACE_SIZE (256ULL * (1ULL << 20))
-#define CSR1212_PRIVATE_SPACE_END (CSR1212_PRIVATE_SPACE_BASE + CSR1212_PRIVATE_SPACE_SIZE)
-
-#define CSR1212_REGISTER_SPACE_BASE (0xfffff0000000ULL)
-#define CSR1212_REGISTER_SPACE_SIZE (256ULL * (1ULL << 20))
-#define CSR1212_REGISTER_SPACE_END (CSR1212_REGISTER_SPACE_BASE + CSR1212_REGISTER_SPACE_SIZE)
-
-#define CSR1212_CSR_ARCH_REG_SPACE_BASE (0xfffff0000000ULL)
-#define CSR1212_CSR_ARCH_REG_SPACE_SIZE (512)
-#define CSR1212_CSR_ARCH_REG_SPACE_END (CSR1212_CSR_ARCH_REG_SPACE_BASE + CSR1212_CSR_ARCH_REG_SPACE_SIZE)
-#define CSR1212_CSR_ARCH_REG_SPACE_OFFSET (CSR1212_CSR_ARCH_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define CSR1212_CSR_BUS_DEP_REG_SPACE_BASE (0xfffff0000200ULL)
-#define CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE (512)
-#define CSR1212_CSR_BUS_DEP_REG_SPACE_END (CSR1212_CSR_BUS_DEP_REG_SPACE_BASE + CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE)
-#define CSR1212_CSR_BUS_DEP_REG_SPACE_OFFSET (CSR1212_CSR_BUS_DEP_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define CSR1212_CONFIG_ROM_SPACE_BASE (0xfffff0000400ULL)
-#define CSR1212_CONFIG_ROM_SPACE_SIZE (1024)
-#define CSR1212_CONFIG_ROM_SPACE_END (CSR1212_CONFIG_ROM_SPACE_BASE + CSR1212_CONFIG_ROM_SPACE_SIZE)
-#define CSR1212_CONFIG_ROM_SPACE_OFFSET (CSR1212_CONFIG_ROM_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define CSR1212_UNITS_SPACE_BASE (0xfffff0000800ULL)
-#define CSR1212_UNITS_SPACE_SIZE ((256ULL * (1ULL << 20)) - 2048)
-#define CSR1212_UNITS_SPACE_END (CSR1212_UNITS_SPACE_BASE + CSR1212_UNITS_SPACE_SIZE)
-#define CSR1212_UNITS_SPACE_OFFSET (CSR1212_UNITS_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define CSR1212_INVALID_ADDR_SPACE -1
-
-
-/* Config ROM image structures */
-struct csr1212_bus_info_block_img {
- u8 length;
- u8 crc_length;
- u16 crc;
-
- /* Must be last */
- u32 data[0]; /* older gcc can't handle [] which is standard */
-};
-
-struct csr1212_leaf {
- int len;
- u32 *data;
-};
-
-struct csr1212_dentry {
- struct csr1212_dentry *next, *prev;
- struct csr1212_keyval *kv;
-};
-
-struct csr1212_directory {
- int len;
- struct csr1212_dentry *dentries_head, *dentries_tail;
-};
-
-struct csr1212_keyval {
- struct {
- u8 type;
- u8 id;
- } key;
- union {
- u32 immediate;
- u32 csr_offset;
- struct csr1212_leaf leaf;
- struct csr1212_directory directory;
- } value;
- struct csr1212_keyval *associate;
- atomic_t refcnt;
-
- /* used in generating and/or parsing CSR image */
- struct csr1212_keyval *next, *prev; /* flat list of CSR elements */
- u32 offset; /* position in CSR from 0xffff f000 0000 */
- u8 valid; /* flag indicating keyval has valid data*/
-};
-
-
-struct csr1212_cache_region {
- struct csr1212_cache_region *next, *prev;
- u32 offset_start; /* inclusive */
- u32 offset_end; /* exclusive */
-};
-
-struct csr1212_csr_rom_cache {
- struct csr1212_csr_rom_cache *next, *prev;
- struct csr1212_cache_region *filled_head, *filled_tail;
- struct csr1212_keyval *layout_head, *layout_tail;
- size_t size;
- u32 offset;
- struct csr1212_keyval *ext_rom;
- size_t len;
-
- /* Must be last */
- u32 data[0]; /* older gcc can't handle [] which is standard */
-};
-
-struct csr1212_csr {
- size_t bus_info_len; /* bus info block length in bytes */
- size_t crc_len; /* crc length in bytes */
- __be32 *bus_info_data; /* bus info data incl bus name and EUI */
-
- void *private; /* private, bus specific data */
- struct csr1212_bus_ops *ops;
-
- struct csr1212_keyval *root_kv;
-
- int max_rom; /* max bytes readable in Config ROM region */
-
- /* Items below used for image parsing and generation */
- struct csr1212_csr_rom_cache *cache_head, *cache_tail;
-};
-
-struct csr1212_bus_ops {
- /* This function is used by csr1212 to read additional information
- * from remote nodes when parsing a Config ROM (i.e., read Config ROM
- * entries located in the Units Space. Must return 0 on success
- * anything else indicates an error. */
- int (*bus_read) (struct csr1212_csr *csr, u64 addr,
- void *buffer, void *private);
-
- /* This function is used by csr1212 to allocate a region in units space
- * in the event that Config ROM entries don't all fit in the predefined
- * 1K region. The void *private parameter is private member of struct
- * csr1212_csr. */
- u64 (*allocate_addr_range) (u64 size, u32 alignment, void *private);
-
- /* This function is used by csr1212 to release a region in units space
- * that is no longer needed. */
- void (*release_addr) (u64 addr, void *private);
-};
-
-
-/* Descriptor Leaf manipulation macros */
-#define CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT 24
-#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK 0xffffff
-#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
-
-#define CSR1212_DESCRIPTOR_LEAF_TYPE(kv) \
- (be32_to_cpu((kv)->value.leaf.data[0]) >> \
- CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)
-#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) \
- (be32_to_cpu((kv)->value.leaf.data[0]) & \
- CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)
-
-
-/* Text Descriptor Leaf manipulation macros */
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT 28
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK 0xf /* after shift */
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT 16
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK 0xfff /* after shift */
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
-
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) \
- (be32_to_cpu((kv)->value.leaf.data[1]) >> \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT)
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) \
- ((be32_to_cpu((kv)->value.leaf.data[1]) >> \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK)
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) \
- (be32_to_cpu((kv)->value.leaf.data[1]) & \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv) \
- (&((kv)->value.leaf.data[2]))
-
-
-/* The following 2 function are for creating new Configuration ROM trees. The
- * first function is used for both creating local trees and parsing remote
- * trees. The second function adds pertinent information to local Configuration
- * ROM trees - namely data for the bus information block. */
-extern struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
- size_t bus_info_size,
- void *private);
-extern void csr1212_init_local_csr(struct csr1212_csr *csr,
- const u32 *bus_info_data, int max_rom);
-
-
-/* Destroy a Configuration ROM tree and release all memory taken by the tree. */
-extern void csr1212_destroy_csr(struct csr1212_csr *csr);
-
-
-/* The following set of functions are fore creating new keyvals for placement in
- * a Configuration ROM tree. Code that creates new keyvals with these functions
- * must release those keyvals with csr1212_release_keyval() when they are no
- * longer needed. */
-extern struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value);
-extern struct csr1212_keyval *csr1212_new_directory(u8 key);
-extern struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s);
-
-
-/* The following function manages association between keyvals. Typically,
- * Descriptor Leaves and Directories will be associated with another keyval and
- * it is desirable for the Descriptor keyval to be place immediately after the
- * keyval that it is associated with.
- * Take care with subsequent ROM modifications: There is no function to remove
- * previously specified associations.
- */
-extern void csr1212_associate_keyval(struct csr1212_keyval *kv,
- struct csr1212_keyval *associate);
-
-
-/* The following functions manage the association of a keyval and directories.
- * A keyval may be attached to more than one directory. */
-extern int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
- struct csr1212_keyval *kv);
-extern void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
- struct csr1212_keyval *kv);
-
-
-/* Creates a complete Configuration ROM image in the list of caches available
- * via csr->cache_head. */
-extern int csr1212_generate_csr_image(struct csr1212_csr *csr);
-
-
-/* This is a convience function for reading a block of data out of one of the
- * caches in the csr->cache_head list. */
-extern int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer,
- u32 len);
-
-
-/* The following functions are in place for parsing Configuration ROM images.
- * csr1212_parse_keyval() is used should there be a need to directly parse a
- * Configuration ROM directly. */
-extern int csr1212_parse_keyval(struct csr1212_keyval *kv,
- struct csr1212_csr_rom_cache *cache);
-extern int csr1212_parse_csr(struct csr1212_csr *csr);
-
-
-/* This function allocates a new cache which may be used for either parsing or
- * generating sub-sets of Configuration ROM images. */
-static inline struct csr1212_csr_rom_cache *
-csr1212_rom_cache_malloc(u32 offset, size_t size)
-{
- struct csr1212_csr_rom_cache *cache;
-
- cache = CSR1212_MALLOC(sizeof(*cache) + size);
- if (!cache)
- return NULL;
-
- cache->next = NULL;
- cache->prev = NULL;
- cache->filled_head = NULL;
- cache->filled_tail = NULL;
- cache->layout_head = NULL;
- cache->layout_tail = NULL;
- cache->offset = offset;
- cache->size = size;
- cache->ext_rom = NULL;
-
- return cache;
-}
-
-
-/* This function ensures that a keyval contains data when referencing a keyval
- * created by parsing a Configuration ROM. */
-extern struct csr1212_keyval *
-csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv);
-
-
-/* This function increments the reference count for a keyval should there be a
- * need for code to retain a keyval that has been parsed. */
-static inline void csr1212_keep_keyval(struct csr1212_keyval *kv)
-{
- atomic_inc(&kv->refcnt);
- smp_mb__after_atomic_inc();
-}
-
-
-/* This function decrements a keyval's reference count and will destroy the
- * keyval when there are no more users of the keyval. This should be called by
- * any code that calls csr1212_keep_keyval() or any of the keyval creation
- * routines csr1212_new_*(). */
-extern void csr1212_release_keyval(struct csr1212_keyval *kv);
-
-
-/*
- * This macro allows for looping over the keyval entries in a directory and it
- * ensures that keyvals from remote ConfigROMs are parsed properly.
- *
- * struct csr1212_csr *_csr points to the CSR associated with dir.
- * struct csr1212_keyval *_kv points to the current keyval (loop index).
- * struct csr1212_keyval *_dir points to the directory to be looped.
- * struct csr1212_dentry *_pos is used internally for indexing.
- *
- * kv will be NULL upon exit of the loop.
- */
-#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos) \
- for (csr1212_get_keyval((_csr), (_dir)), \
- _pos = (_dir)->value.directory.dentries_head, \
- _kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL;\
- (_kv) && (_pos); \
- (_kv->associate == NULL) ? \
- ((_pos = _pos->next), (_kv = (_pos) ? \
- csr1212_get_keyval((_csr), _pos->kv) : \
- NULL)) : \
- (_kv = csr1212_get_keyval((_csr), _kv->associate)))
-
-#endif /* __CSR1212_H__ */
diff --git a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c
deleted file mode 100644
index d178699b194a..000000000000
--- a/drivers/ieee1394/dma.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * DMA region bookkeeping routines
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/scatterlist.h>
-
-#include "dma.h"
-
-/* dma_prog_region */
-
-void dma_prog_region_init(struct dma_prog_region *prog)
-{
- prog->kvirt = NULL;
- prog->dev = NULL;
- prog->n_pages = 0;
- prog->bus_addr = 0;
-}
-
-int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes,
- struct pci_dev *dev)
-{
- /* round up to page size */
- n_bytes = PAGE_ALIGN(n_bytes);
-
- prog->n_pages = n_bytes >> PAGE_SHIFT;
-
- prog->kvirt = pci_alloc_consistent(dev, n_bytes, &prog->bus_addr);
- if (!prog->kvirt) {
- printk(KERN_ERR
- "dma_prog_region_alloc: pci_alloc_consistent() failed\n");
- dma_prog_region_free(prog);
- return -ENOMEM;
- }
-
- prog->dev = dev;
-
- return 0;
-}
-
-void dma_prog_region_free(struct dma_prog_region *prog)
-{
- if (prog->kvirt) {
- pci_free_consistent(prog->dev, prog->n_pages << PAGE_SHIFT,
- prog->kvirt, prog->bus_addr);
- }
-
- prog->kvirt = NULL;
- prog->dev = NULL;
- prog->n_pages = 0;
- prog->bus_addr = 0;
-}
-
-/* dma_region */
-
-/**
- * dma_region_init - clear out all fields but do not allocate anything
- */
-void dma_region_init(struct dma_region *dma)
-{
- dma->kvirt = NULL;
- dma->dev = NULL;
- dma->n_pages = 0;
- dma->n_dma_pages = 0;
- dma->sglist = NULL;
-}
-
-/**
- * dma_region_alloc - allocate the buffer and map it to the IOMMU
- */
-int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
- struct pci_dev *dev, int direction)
-{
- unsigned int i;
-
- /* round up to page size */
- n_bytes = PAGE_ALIGN(n_bytes);
-
- dma->n_pages = n_bytes >> PAGE_SHIFT;
-
- dma->kvirt = vmalloc_32(n_bytes);
- if (!dma->kvirt) {
- printk(KERN_ERR "dma_region_alloc: vmalloc_32() failed\n");
- goto err;
- }
-
- /* Clear the ram out, no junk to the user */
- memset(dma->kvirt, 0, n_bytes);
-
- /* allocate scatter/gather list */
- dma->sglist = vmalloc(dma->n_pages * sizeof(*dma->sglist));
- if (!dma->sglist) {
- printk(KERN_ERR "dma_region_alloc: vmalloc(sglist) failed\n");
- goto err;
- }
-
- sg_init_table(dma->sglist, dma->n_pages);
-
- /* fill scatter/gather list with pages */
- for (i = 0; i < dma->n_pages; i++) {
- unsigned long va =
- (unsigned long)dma->kvirt + (i << PAGE_SHIFT);
-
- sg_set_page(&dma->sglist[i], vmalloc_to_page((void *)va),
- PAGE_SIZE, 0);
- }
-
- /* map sglist to the IOMMU */
- dma->n_dma_pages =
- pci_map_sg(dev, dma->sglist, dma->n_pages, direction);
-
- if (dma->n_dma_pages == 0) {
- printk(KERN_ERR "dma_region_alloc: pci_map_sg() failed\n");
- goto err;
- }
-
- dma->dev = dev;
- dma->direction = direction;
-
- return 0;
-
- err:
- dma_region_free(dma);
- return -ENOMEM;
-}
-
-/**
- * dma_region_free - unmap and free the buffer
- */
-void dma_region_free(struct dma_region *dma)
-{
- if (dma->n_dma_pages) {
- pci_unmap_sg(dma->dev, dma->sglist, dma->n_pages,
- dma->direction);
- dma->n_dma_pages = 0;
- dma->dev = NULL;
- }
-
- vfree(dma->sglist);
- dma->sglist = NULL;
-
- vfree(dma->kvirt);
- dma->kvirt = NULL;
- dma->n_pages = 0;
-}
-
-/* find the scatterlist index and remaining offset corresponding to a
- given offset from the beginning of the buffer */
-static inline int dma_region_find(struct dma_region *dma, unsigned long offset,
- unsigned int start, unsigned long *rem)
-{
- int i;
- unsigned long off = offset;
-
- for (i = start; i < dma->n_dma_pages; i++) {
- if (off < sg_dma_len(&dma->sglist[i])) {
- *rem = off;
- break;
- }
-
- off -= sg_dma_len(&dma->sglist[i]);
- }
-
- BUG_ON(i >= dma->n_dma_pages);
-
- return i;
-}
-
-/**
- * dma_region_offset_to_bus - get bus address of an offset within a DMA region
- *
- * Returns the DMA bus address of the byte with the given @offset relative to
- * the beginning of the @dma.
- */
-dma_addr_t dma_region_offset_to_bus(struct dma_region * dma,
- unsigned long offset)
-{
- unsigned long rem = 0;
-
- struct scatterlist *sg =
- &dma->sglist[dma_region_find(dma, offset, 0, &rem)];
- return sg_dma_address(sg) + rem;
-}
-
-/**
- * dma_region_sync_for_cpu - sync the CPU's view of the buffer
- */
-void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
- unsigned long len)
-{
- int first, last;
- unsigned long rem = 0;
-
- if (!len)
- len = 1;
-
- first = dma_region_find(dma, offset, 0, &rem);
- last = dma_region_find(dma, rem + len - 1, first, &rem);
-
- pci_dma_sync_sg_for_cpu(dma->dev, &dma->sglist[first], last - first + 1,
- dma->direction);
-}
-
-/**
- * dma_region_sync_for_device - sync the IO bus' view of the buffer
- */
-void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
- unsigned long len)
-{
- int first, last;
- unsigned long rem = 0;
-
- if (!len)
- len = 1;
-
- first = dma_region_find(dma, offset, 0, &rem);
- last = dma_region_find(dma, rem + len - 1, first, &rem);
-
- pci_dma_sync_sg_for_device(dma->dev, &dma->sglist[first],
- last - first + 1, dma->direction);
-}
-
-#ifdef CONFIG_MMU
-
-static int dma_region_pagefault(struct vm_area_struct *vma,
- struct vm_fault *vmf)
-{
- struct dma_region *dma = (struct dma_region *)vma->vm_private_data;
-
- if (!dma->kvirt)
- return VM_FAULT_SIGBUS;
-
- if (vmf->pgoff >= dma->n_pages)
- return VM_FAULT_SIGBUS;
-
- vmf->page = vmalloc_to_page(dma->kvirt + (vmf->pgoff << PAGE_SHIFT));
- get_page(vmf->page);
- return 0;
-}
-
-static const struct vm_operations_struct dma_region_vm_ops = {
- .fault = dma_region_pagefault,
-};
-
-/**
- * dma_region_mmap - map the buffer into a user space process
- */
-int dma_region_mmap(struct dma_region *dma, struct file *file,
- struct vm_area_struct *vma)
-{
- unsigned long size;
-
- if (!dma->kvirt)
- return -EINVAL;
-
- /* must be page-aligned (XXX: comment is wrong, we could allow pgoff) */
- if (vma->vm_pgoff != 0)
- return -EINVAL;
-
- /* check the length */
- size = vma->vm_end - vma->vm_start;
- if (size > (dma->n_pages << PAGE_SHIFT))
- return -EINVAL;
-
- vma->vm_ops = &dma_region_vm_ops;
- vma->vm_private_data = dma;
- vma->vm_file = file;
- vma->vm_flags |= VM_RESERVED | VM_ALWAYSDUMP;
-
- return 0;
-}
-
-#else /* CONFIG_MMU */
-
-int dma_region_mmap(struct dma_region *dma, struct file *file,
- struct vm_area_struct *vma)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_MMU */
diff --git a/drivers/ieee1394/dma.h b/drivers/ieee1394/dma.h
deleted file mode 100644
index 467373cab8e5..000000000000
--- a/drivers/ieee1394/dma.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * DMA region bookkeeping routines
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#ifndef IEEE1394_DMA_H
-#define IEEE1394_DMA_H
-
-#include <asm/types.h>
-
-struct file;
-struct pci_dev;
-struct scatterlist;
-struct vm_area_struct;
-
-/**
- * struct dma_prog_region - small contiguous DMA buffer
- * @kvirt: kernel virtual address
- * @dev: PCI device
- * @n_pages: number of kernel pages
- * @bus_addr: base bus address
- *
- * a small, physically contiguous DMA buffer with random-access, synchronous
- * usage characteristics
- */
-struct dma_prog_region {
- unsigned char *kvirt;
- struct pci_dev *dev;
- unsigned int n_pages;
- dma_addr_t bus_addr;
-};
-
-/* clear out all fields but do not allocate any memory */
-void dma_prog_region_init(struct dma_prog_region *prog);
-int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes,
- struct pci_dev *dev);
-void dma_prog_region_free(struct dma_prog_region *prog);
-
-static inline dma_addr_t dma_prog_region_offset_to_bus(
- struct dma_prog_region *prog, unsigned long offset)
-{
- return prog->bus_addr + offset;
-}
-
-/**
- * struct dma_region - large non-contiguous DMA buffer
- * @virt: kernel virtual address
- * @dev: PCI device
- * @n_pages: number of kernel pages
- * @n_dma_pages: number of IOMMU pages
- * @sglist: IOMMU mapping
- * @direction: PCI_DMA_TODEVICE, etc.
- *
- * a large, non-physically-contiguous DMA buffer with streaming, asynchronous
- * usage characteristics
- */
-struct dma_region {
- unsigned char *kvirt;
- struct pci_dev *dev;
- unsigned int n_pages;
- unsigned int n_dma_pages;
- struct scatterlist *sglist;
- int direction;
-};
-
-void dma_region_init(struct dma_region *dma);
-int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
- struct pci_dev *dev, int direction);
-void dma_region_free(struct dma_region *dma);
-void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
- unsigned long len);
-void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
- unsigned long len);
-int dma_region_mmap(struct dma_region *dma, struct file *file,
- struct vm_area_struct *vma);
-dma_addr_t dma_region_offset_to_bus(struct dma_region *dma,
- unsigned long offset);
-
-/**
- * dma_region_i - macro to index into a DMA region (or dma_prog_region)
- */
-#define dma_region_i(_dma, _type, _index) \
- ( ((_type*) ((_dma)->kvirt)) + (_index) )
-
-#endif /* IEEE1394_DMA_H */
diff --git a/drivers/ieee1394/dv1394-private.h b/drivers/ieee1394/dv1394-private.h
deleted file mode 100644
index 18b92cbf4a9f..000000000000
--- a/drivers/ieee1394/dv1394-private.h
+++ /dev/null
@@ -1,587 +0,0 @@
-/*
- * dv1394-private.h - DV input/output over IEEE 1394 on OHCI chips
- * Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
- * receive by Dan Dennedy <dan@dennedy.org>
- *
- * based on:
- * video1394.h - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- * Peter Schlaile <udbz@rz.uni-karlsruhe.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This 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 _DV_1394_PRIVATE_H
-#define _DV_1394_PRIVATE_H
-
-#include "ieee1394.h"
-#include "ohci1394.h"
-#include "dma.h"
-
-/* data structures private to the dv1394 driver */
-/* none of this is exposed to user-space */
-
-
-/*
- the 8-byte CIP (Common Isochronous Packet) header that precedes
- each packet of DV data.
-
- See the IEC 61883 standard.
-*/
-
-struct CIP_header { unsigned char b[8]; };
-
-static inline void fill_cip_header(struct CIP_header *cip,
- unsigned char source_node_id,
- unsigned long counter,
- enum pal_or_ntsc format,
- unsigned long timestamp)
-{
- cip->b[0] = source_node_id;
- cip->b[1] = 0x78; /* packet size in quadlets (480/4) - even for empty packets! */
- cip->b[2] = 0x00;
- cip->b[3] = counter;
-
- cip->b[4] = 0x80; /* const */
-
- switch(format) {
- case DV1394_PAL:
- cip->b[5] = 0x80;
- break;
- case DV1394_NTSC:
- cip->b[5] = 0x00;
- break;
- }
-
- cip->b[6] = timestamp >> 8;
- cip->b[7] = timestamp & 0xFF;
-}
-
-
-
-/*
- DMA commands used to program the OHCI's DMA engine
-
- See the Texas Instruments OHCI 1394 chipset documentation.
-*/
-
-struct output_more_immediate { __le32 q[8]; };
-struct output_more { __le32 q[4]; };
-struct output_last { __le32 q[4]; };
-struct input_more { __le32 q[4]; };
-struct input_last { __le32 q[4]; };
-
-/* outputs */
-
-static inline void fill_output_more_immediate(struct output_more_immediate *omi,
- unsigned char tag,
- unsigned char channel,
- unsigned char sync_tag,
- unsigned int payload_size)
-{
- omi->q[0] = cpu_to_le32(0x02000000 | 8); /* OUTPUT_MORE_IMMEDIATE; 8 is the size of the IT header */
- omi->q[1] = cpu_to_le32(0);
- omi->q[2] = cpu_to_le32(0);
- omi->q[3] = cpu_to_le32(0);
-
- /* IT packet header */
- omi->q[4] = cpu_to_le32( (0x0 << 16) /* IEEE1394_SPEED_100 */
- | (tag << 14)
- | (channel << 8)
- | (TCODE_ISO_DATA << 4)
- | (sync_tag) );
-
- /* reserved field; mimic behavior of my Sony DSR-40 */
- omi->q[5] = cpu_to_le32((payload_size << 16) | (0x7F << 8) | 0xA0);
-
- omi->q[6] = cpu_to_le32(0);
- omi->q[7] = cpu_to_le32(0);
-}
-
-static inline void fill_output_more(struct output_more *om,
- unsigned int data_size,
- unsigned long data_phys_addr)
-{
- om->q[0] = cpu_to_le32(data_size);
- om->q[1] = cpu_to_le32(data_phys_addr);
- om->q[2] = cpu_to_le32(0);
- om->q[3] = cpu_to_le32(0);
-}
-
-static inline void fill_output_last(struct output_last *ol,
- int want_timestamp,
- int want_interrupt,
- unsigned int data_size,
- unsigned long data_phys_addr)
-{
- u32 temp = 0;
- temp |= 1 << 28; /* OUTPUT_LAST */
-
- if (want_timestamp) /* controller will update timestamp at DMA time */
- temp |= 1 << 27;
-
- if (want_interrupt)
- temp |= 3 << 20;
-
- temp |= 3 << 18; /* must take branch */
- temp |= data_size;
-
- ol->q[0] = cpu_to_le32(temp);
- ol->q[1] = cpu_to_le32(data_phys_addr);
- ol->q[2] = cpu_to_le32(0);
- ol->q[3] = cpu_to_le32(0);
-}
-
-/* inputs */
-
-static inline void fill_input_more(struct input_more *im,
- int want_interrupt,
- unsigned int data_size,
- unsigned long data_phys_addr)
-{
- u32 temp = 2 << 28; /* INPUT_MORE */
- temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
- if (want_interrupt)
- temp |= 0 << 20; /* interrupts, i=0 in packet-per-buffer mode */
- temp |= 0x0 << 16; /* disable branch to address for packet-per-buffer mode */
- /* disable wait on sync field, not used in DV :-( */
- temp |= data_size;
-
- im->q[0] = cpu_to_le32(temp);
- im->q[1] = cpu_to_le32(data_phys_addr);
- im->q[2] = cpu_to_le32(0); /* branchAddress and Z not use in packet-per-buffer mode */
- im->q[3] = cpu_to_le32(0); /* xferStatus & resCount, resCount must be initialize to data_size */
-}
-
-static inline void fill_input_last(struct input_last *il,
- int want_interrupt,
- unsigned int data_size,
- unsigned long data_phys_addr)
-{
- u32 temp = 3 << 28; /* INPUT_LAST */
- temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
- if (want_interrupt)
- temp |= 3 << 20; /* enable interrupts */
- temp |= 0xC << 16; /* enable branch to address */
- /* disable wait on sync field, not used in DV :-( */
- temp |= data_size;
-
- il->q[0] = cpu_to_le32(temp);
- il->q[1] = cpu_to_le32(data_phys_addr);
- il->q[2] = cpu_to_le32(1); /* branchAddress (filled in later) and Z = 1 descriptor in next block */
- il->q[3] = cpu_to_le32(data_size); /* xferStatus & resCount, resCount must be initialize to data_size */
-}
-
-
-
-/*
- A "DMA descriptor block" consists of several contiguous DMA commands.
- struct DMA_descriptor_block encapsulates all of the commands necessary
- to send one packet of DV data.
-
- There are three different types of these blocks:
-
- 1) command to send an empty packet (CIP header only, no DV data):
-
- OUTPUT_MORE-Immediate <-- contains the iso header in-line
- OUTPUT_LAST <-- points to the CIP header
-
- 2) command to send a full packet when the DV data payload does NOT
- cross a page boundary:
-
- OUTPUT_MORE-Immediate <-- contains the iso header in-line
- OUTPUT_MORE <-- points to the CIP header
- OUTPUT_LAST <-- points to entire DV data payload
-
- 3) command to send a full packet when the DV payload DOES cross
- a page boundary:
-
- OUTPUT_MORE-Immediate <-- contains the iso header in-line
- OUTPUT_MORE <-- points to the CIP header
- OUTPUT_MORE <-- points to first part of DV data payload
- OUTPUT_LAST <-- points to second part of DV data payload
-
- This struct describes all three block types using unions.
-
- !!! It is vital that an even number of these descriptor blocks fit on one
- page of memory, since a block cannot cross a page boundary !!!
-
- */
-
-struct DMA_descriptor_block {
-
- union {
- struct {
- /* iso header, common to all output block types */
- struct output_more_immediate omi;
-
- union {
- /* empty packet */
- struct {
- struct output_last ol; /* CIP header */
- } empty;
-
- /* full packet */
- struct {
- struct output_more om; /* CIP header */
-
- union {
- /* payload does not cross page boundary */
- struct {
- struct output_last ol; /* data payload */
- } nocross;
-
- /* payload crosses page boundary */
- struct {
- struct output_more om; /* data payload */
- struct output_last ol; /* data payload */
- } cross;
- } u;
-
- } full;
- } u;
- } out;
-
- struct {
- struct input_last il;
- } in;
-
- } u;
-
- /* ensure that PAGE_SIZE % sizeof(struct DMA_descriptor_block) == 0
- by padding out to 128 bytes */
- u32 __pad__[12];
-};
-
-
-/* struct frame contains all data associated with one frame in the
- ringbuffer these are allocated when the DMA context is initialized
- do_dv1394_init(). They are re-used after the card finishes
- transmitting the frame. */
-
-struct video_card; /* forward declaration */
-
-struct frame {
-
- /* points to the struct video_card that owns this frame */
- struct video_card *video;
-
- /* index of this frame in video_card->frames[] */
- unsigned int frame_num;
-
- /* FRAME_CLEAR - DMA program not set up, waiting for data
- FRAME_READY - DMA program written, ready to transmit
-
- Changes to these should be locked against the interrupt
- */
- enum {
- FRAME_CLEAR = 0,
- FRAME_READY
- } state;
-
- /* whether this frame has been DMA'ed already; used only from
- the IRQ handler to determine whether the frame can be reset */
- int done;
-
-
- /* kernel virtual pointer to the start of this frame's data in
- the user ringbuffer. Use only for CPU access; to get the DMA
- bus address you must go through the video->user_dma mapping */
- unsigned long data;
-
- /* Max # of packets per frame */
-#define MAX_PACKETS 500
-
-
- /* a PAGE_SIZE memory pool for allocating CIP headers
- !header_pool must be aligned to PAGE_SIZE! */
- struct CIP_header *header_pool;
- dma_addr_t header_pool_dma;
-
-
- /* a physically contiguous memory pool for allocating DMA
- descriptor blocks; usually around 64KB in size
- !descriptor_pool must be aligned to PAGE_SIZE! */
- struct DMA_descriptor_block *descriptor_pool;
- dma_addr_t descriptor_pool_dma;
- unsigned long descriptor_pool_size;
-
-
- /* # of packets allocated for this frame */
- unsigned int n_packets;
-
-
- /* below are several pointers (kernel virtual addresses, not
- DMA bus addresses) to parts of the DMA program. These are
- set each time the DMA program is written in
- frame_prepare(). They are used later on, e.g. from the
- interrupt handler, to check the status of the frame */
-
- /* points to status/timestamp field of first DMA packet */
- /* (we'll check it later to monitor timestamp accuracy) */
- __le32 *frame_begin_timestamp;
-
- /* the timestamp we assigned to the first packet in the frame */
- u32 assigned_timestamp;
-
- /* pointer to the first packet's CIP header (where the timestamp goes) */
- struct CIP_header *cip_syt1;
-
- /* pointer to the second packet's CIP header
- (only set if the first packet was empty) */
- struct CIP_header *cip_syt2;
-
- /* in order to figure out what caused an interrupt,
- store pointers to the status fields of the two packets
- that can cause interrupts. We'll check these from the
- interrupt handler.
- */
- __le32 *mid_frame_timestamp;
- __le32 *frame_end_timestamp;
-
- /* branch address field of final packet. This is effectively
- the "tail" in the chain of DMA descriptor blocks.
- We will fill it with the address of the first DMA descriptor
- block in the subsequent frame, once it is ready.
- */
- __le32 *frame_end_branch;
-
- /* the number of descriptors in the first descriptor block
- of the frame. Needed to start DMA */
- int first_n_descriptors;
-};
-
-
-struct packet {
- __le16 timestamp;
- u16 invalid;
- u16 iso_header;
- __le16 data_length;
- u32 cip_h1;
- u32 cip_h2;
- unsigned char data[480];
- unsigned char padding[16]; /* force struct size =512 for page alignment */
-};
-
-
-/* allocate/free a frame */
-static struct frame* frame_new(unsigned int frame_num, struct video_card *video);
-static void frame_delete(struct frame *f);
-
-/* reset f so that it can be used again */
-static void frame_reset(struct frame *f);
-
-/* struct video_card contains all data associated with one instance
- of the dv1394 driver
-*/
-enum modes {
- MODE_RECEIVE,
- MODE_TRANSMIT
-};
-
-struct video_card {
-
- /* ohci card to which this instance corresponds */
- struct ti_ohci *ohci;
-
- /* OHCI card id; the link between the VFS inode and a specific video_card
- (essentially the device minor number) */
- int id;
-
- /* entry in dv1394_cards */
- struct list_head list;
-
- /* OHCI card IT DMA context number, -1 if not in use */
- int ohci_it_ctx;
- struct ohci1394_iso_tasklet it_tasklet;
-
- /* register offsets for current IT DMA context, 0 if not in use */
- u32 ohci_IsoXmitContextControlSet;
- u32 ohci_IsoXmitContextControlClear;
- u32 ohci_IsoXmitCommandPtr;
-
- /* OHCI card IR DMA context number, -1 if not in use */
- struct ohci1394_iso_tasklet ir_tasklet;
- int ohci_ir_ctx;
-
- /* register offsets for current IR DMA context, 0 if not in use */
- u32 ohci_IsoRcvContextControlSet;
- u32 ohci_IsoRcvContextControlClear;
- u32 ohci_IsoRcvCommandPtr;
- u32 ohci_IsoRcvContextMatch;
-
-
- /* CONCURRENCY CONTROL */
-
- /* there are THREE levels of locking associated with video_card. */
-
- /*
- 1) the 'open' flag - this prevents more than one process from
- opening the device. (the driver currently assumes only one opener).
- This is a regular int, but use test_and_set_bit() (on bit zero)
- for atomicity.
- */
- unsigned long open;
-
- /*
- 2) the spinlock - this provides mutual exclusion between the interrupt
- handler and process-context operations. Generally you must take the
- spinlock under the following conditions:
- 1) DMA (and hence the interrupt handler) may be running
- AND
- 2) you need to operate on the video_card, especially active_frame
-
- It is OK to play with video_card without taking the spinlock if
- you are certain that DMA is not running. Even if DMA is running,
- it is OK to *read* active_frame with the lock, then drop it
- immediately. This is safe because the interrupt handler will never
- advance active_frame onto a frame that is not READY (and the spinlock
- must be held while marking a frame READY).
-
- spinlock is also used to protect ohci_it_ctx and ohci_ir_ctx,
- which can be accessed from both process and interrupt context
- */
- spinlock_t spinlock;
-
- /* flag to prevent spurious interrupts (which OHCI seems to
- generate a lot :) from accessing the struct */
- int dma_running;
-
- /*
- 3) the sleeping mutex 'mtx' - this is used from process context only,
- to serialize various operations on the video_card. Even though only one
- open() is allowed, we still need to prevent multiple threads of execution
- from entering calls like read, write, ioctl, etc.
-
- I honestly can't think of a good reason to use dv1394 from several threads
- at once, but we need to serialize anyway to prevent oopses =).
-
- NOTE: if you need both spinlock and mtx, take mtx first to avoid deadlock!
- */
- struct mutex mtx;
-
- /* people waiting for buffer space, please form a line here... */
- wait_queue_head_t waitq;
-
- /* support asynchronous I/O signals (SIGIO) */
- struct fasync_struct *fasync;
-
- /* the large, non-contiguous (rvmalloc()) ringbuffer for DV
- data, exposed to user-space via mmap() */
- unsigned long dv_buf_size;
- struct dma_region dv_buf;
-
- /* next byte in the ringbuffer that a write() call will fill */
- size_t write_off;
-
- struct frame *frames[DV1394_MAX_FRAMES];
-
- /* n_frames also serves as an indicator that this struct video_card is
- initialized and ready to run DMA buffers */
-
- int n_frames;
-
- /* this is the frame that is currently "owned" by the OHCI DMA controller
- (set to -1 iff DMA is not running)
-
- ! must lock against the interrupt handler when accessing it !
-
- RULES:
-
- Only the interrupt handler may change active_frame if DMA
- is running; if not, process may change it
-
- If the next frame is READY, the interrupt handler will advance
- active_frame when the current frame is finished.
-
- If the next frame is CLEAR, the interrupt handler will re-transmit
- the current frame, and the dropped_frames counter will be incremented.
-
- The interrupt handler will NEVER advance active_frame to a
- frame that is not READY.
- */
- int active_frame;
- int first_run;
-
- /* the same locking rules apply to these three fields also: */
-
- /* altered ONLY from process context. Must check first_clear_frame->state;
- if it's READY, that means the ringbuffer is full with READY frames;
- if it's CLEAR, that means one or more ringbuffer frames are CLEAR */
- unsigned int first_clear_frame;
-
- /* altered both by process and interrupt */
- unsigned int n_clear_frames;
-
- /* only altered by the interrupt */
- unsigned int dropped_frames;
-
-
-
- /* the CIP accumulator and continuity counter are properties
- of the DMA stream as a whole (not a single frame), so they
- are stored here in the video_card */
-
- unsigned long cip_accum;
- unsigned long cip_n, cip_d;
- unsigned int syt_offset;
- unsigned int continuity_counter;
-
- enum pal_or_ntsc pal_or_ntsc;
-
- /* redundant, but simplifies the code somewhat */
- unsigned int frame_size; /* in bytes */
-
- /* the isochronous channel to use, -1 if video card is inactive */
- int channel;
-
-
- /* physically contiguous packet ringbuffer for receive */
- struct dma_region packet_buf;
- unsigned long packet_buf_size;
-
- unsigned int current_packet;
- int first_frame; /* received first start frame marker? */
- enum modes mode;
-};
-
-/*
- if the video_card is not initialized, then the ONLY fields that are valid are:
- ohci
- open
- n_frames
-*/
-
-static inline int video_card_initialized(struct video_card *v)
-{
- return v->n_frames > 0;
-}
-
-static int do_dv1394_init(struct video_card *video, struct dv1394_init *init);
-static int do_dv1394_init_default(struct video_card *video);
-static void do_dv1394_shutdown(struct video_card *video, int free_user_buf);
-
-
-/* NTSC empty packet rate accurate to within 0.01%,
- calibrated against a Sony DSR-40 DVCAM deck */
-
-#define CIP_N_NTSC 68000000
-#define CIP_D_NTSC 1068000000
-
-#define CIP_N_PAL 1
-#define CIP_D_PAL 16
-
-#endif /* _DV_1394_PRIVATE_H */
-
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
deleted file mode 100644
index c5a031b79d03..000000000000
--- a/drivers/ieee1394/dv1394.c
+++ /dev/null
@@ -1,2584 +0,0 @@
-/*
- * dv1394.c - DV input/output over IEEE 1394 on OHCI chips
- * Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
- * receive by Dan Dennedy <dan@dennedy.org>
- *
- * based on:
- * video1394.c - video driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- *
- * 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.
- */
-
-/*
- OVERVIEW
-
- I designed dv1394 as a "pipe" that you can use to shoot DV onto a
- FireWire bus. In transmission mode, dv1394 does the following:
-
- 1. accepts contiguous frames of DV data from user-space, via write()
- or mmap() (see dv1394.h for the complete API)
- 2. wraps IEC 61883 packets around the DV data, inserting
- empty synchronization packets as necessary
- 3. assigns accurate SYT timestamps to the outgoing packets
- 4. shoots them out using the OHCI card's IT DMA engine
-
- Thanks to Dan Dennedy, we now have a receive mode that does the following:
-
- 1. accepts raw IEC 61883 packets from the OHCI card
- 2. re-assembles the DV data payloads into contiguous frames,
- discarding empty packets
- 3. sends the DV data to user-space via read() or mmap()
-*/
-
-/*
- TODO:
-
- - tunable frame-drop behavior: either loop last frame, or halt transmission
-
- - use a scatter/gather buffer for DMA programs (f->descriptor_pool)
- so that we don't rely on allocating 64KB of contiguous kernel memory
- via pci_alloc_consistent()
-
- DONE:
- - during reception, better handling of dropped frames and continuity errors
- - during reception, prevent DMA from bypassing the irq tasklets
- - reduce irq rate during reception (1/250 packets).
- - add many more internal buffers during reception with scatter/gather dma.
- - add dbc (continuity) checking on receive, increment status.dropped_frames
- if not continuous.
- - restart IT DMA after a bus reset
- - safely obtain and release ISO Tx channels in cooperation with OHCI driver
- - map received DIF blocks to their proper location in DV frame (ensure
- recovery if dropped packet)
- - handle bus resets gracefully (OHCI card seems to take care of this itself(!))
- - do not allow resizing the user_buf once allocated; eliminate nuke_buffer_mappings
- - eliminated #ifdef DV1394_DEBUG_LEVEL by inventing macros debug_printk and irq_printk
- - added wmb() and mb() to places where PCI read/write ordering needs to be enforced
- - set video->id correctly
- - store video_cards in an array indexed by OHCI card ID, rather than a list
- - implement DMA context allocation to cooperate with other users of the OHCI
- - fix all XXX showstoppers
- - disable IR/IT DMA interrupts on shutdown
- - flush pci writes to the card by issuing a read
- - character device dispatching
- - switch over to the new kernel DMA API (pci_map_*()) (* needs testing on platforms with IOMMU!)
- - keep all video_cards in a list (for open() via chardev), set file->private_data = video
- - dv1394_poll should indicate POLLIN when receiving buffers are available
- - add proc fs interface to set cip_n, cip_d, syt_offset, and video signal
- - expose xmit and recv as separate devices (not exclusive)
- - expose NTSC and PAL as separate devices (can be overridden)
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/mutex.h>
-#include <linux/bitops.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/delay.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/string.h>
-#include <linux/compat.h>
-#include <linux/cdev.h>
-
-#include "dv1394.h"
-#include "dv1394-private.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_types.h"
-#include "nodemgr.h"
-#include "ohci1394.h"
-
-/* DEBUG LEVELS:
- 0 - no debugging messages
- 1 - some debugging messages, but none during DMA frame transmission
- 2 - lots of messages, including during DMA frame transmission
- (will cause underflows if your machine is too slow!)
-*/
-
-#define DV1394_DEBUG_LEVEL 0
-
-/* for debugging use ONLY: allow more than one open() of the device */
-/* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */
-
-#if DV1394_DEBUG_LEVEL >= 2
-#define irq_printk( args... ) printk( args )
-#else
-#define irq_printk( args... ) do {} while (0)
-#endif
-
-#if DV1394_DEBUG_LEVEL >= 1
-#define debug_printk( args... ) printk( args)
-#else
-#define debug_printk( args... ) do {} while (0)
-#endif
-
-/* issue a dummy PCI read to force the preceding write
- to be posted to the PCI bus immediately */
-
-static inline void flush_pci_write(struct ti_ohci *ohci)
-{
- mb();
- reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-}
-
-static void it_tasklet_func(unsigned long data);
-static void ir_tasklet_func(unsigned long data);
-
-#ifdef CONFIG_COMPAT
-static long dv1394_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg);
-#endif
-
-/* GLOBAL DATA */
-
-/* list of all video_cards */
-static LIST_HEAD(dv1394_cards);
-static DEFINE_SPINLOCK(dv1394_cards_lock);
-
-/* translate from a struct file* to the corresponding struct video_card* */
-
-static inline struct video_card* file_to_video_card(struct file *file)
-{
- return file->private_data;
-}
-
-/*** FRAME METHODS *********************************************************/
-
-static void frame_reset(struct frame *f)
-{
- f->state = FRAME_CLEAR;
- f->done = 0;
- f->n_packets = 0;
- f->frame_begin_timestamp = NULL;
- f->assigned_timestamp = 0;
- f->cip_syt1 = NULL;
- f->cip_syt2 = NULL;
- f->mid_frame_timestamp = NULL;
- f->frame_end_timestamp = NULL;
- f->frame_end_branch = NULL;
-}
-
-static struct frame* frame_new(unsigned int frame_num, struct video_card *video)
-{
- struct frame *f = kmalloc(sizeof(*f), GFP_KERNEL);
- if (!f)
- return NULL;
-
- f->video = video;
- f->frame_num = frame_num;
-
- f->header_pool = pci_alloc_consistent(f->video->ohci->dev, PAGE_SIZE, &f->header_pool_dma);
- if (!f->header_pool) {
- printk(KERN_ERR "dv1394: failed to allocate CIP header pool\n");
- kfree(f);
- return NULL;
- }
-
- debug_printk("dv1394: frame_new: allocated CIP header pool at virt 0x%08lx (contig) dma 0x%08lx size %ld\n",
- (unsigned long) f->header_pool, (unsigned long) f->header_pool_dma, PAGE_SIZE);
-
- f->descriptor_pool_size = MAX_PACKETS * sizeof(struct DMA_descriptor_block);
- /* make it an even # of pages */
- f->descriptor_pool_size += PAGE_SIZE - (f->descriptor_pool_size%PAGE_SIZE);
-
- f->descriptor_pool = pci_alloc_consistent(f->video->ohci->dev,
- f->descriptor_pool_size,
- &f->descriptor_pool_dma);
- if (!f->descriptor_pool) {
- pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma);
- kfree(f);
- return NULL;
- }
-
- debug_printk("dv1394: frame_new: allocated DMA program memory at virt 0x%08lx (contig) dma 0x%08lx size %ld\n",
- (unsigned long) f->descriptor_pool, (unsigned long) f->descriptor_pool_dma, f->descriptor_pool_size);
-
- f->data = 0;
- frame_reset(f);
-
- return f;
-}
-
-static void frame_delete(struct frame *f)
-{
- pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma);
- pci_free_consistent(f->video->ohci->dev, f->descriptor_pool_size, f->descriptor_pool, f->descriptor_pool_dma);
- kfree(f);
-}
-
-
-
-
-/*
- frame_prepare() - build the DMA program for transmitting
-
- Frame_prepare() must be called OUTSIDE the video->spinlock.
- However, frame_prepare() must still be serialized, so
- it should be called WITH the video->mtx taken.
- */
-
-static void frame_prepare(struct video_card *video, unsigned int this_frame)
-{
- struct frame *f = video->frames[this_frame];
- int last_frame;
-
- struct DMA_descriptor_block *block;
- dma_addr_t block_dma;
- struct CIP_header *cip;
- dma_addr_t cip_dma;
-
- unsigned int n_descriptors, full_packets, packets_per_frame, payload_size;
-
- /* these flags denote packets that need special attention */
- int empty_packet, first_packet, last_packet, mid_packet;
-
- __le32 *branch_address, *last_branch_address = NULL;
- unsigned long data_p;
- int first_packet_empty = 0;
- u32 cycleTimer, ct_sec, ct_cyc, ct_off;
- unsigned long irq_flags;
-
- irq_printk("frame_prepare( %d ) ---------------------\n", this_frame);
-
- full_packets = 0;
-
-
-
- if (video->pal_or_ntsc == DV1394_PAL)
- packets_per_frame = DV1394_PAL_PACKETS_PER_FRAME;
- else
- packets_per_frame = DV1394_NTSC_PACKETS_PER_FRAME;
-
- while ( full_packets < packets_per_frame ) {
- empty_packet = first_packet = last_packet = mid_packet = 0;
-
- data_p = f->data + full_packets * 480;
-
- /************************************************/
- /* allocate a descriptor block and a CIP header */
- /************************************************/
-
- /* note: these should NOT cross a page boundary (DMA restriction) */
-
- if (f->n_packets >= MAX_PACKETS) {
- printk(KERN_ERR "dv1394: FATAL ERROR: max packet count exceeded\n");
- return;
- }
-
- /* the block surely won't cross a page boundary,
- since an even number of descriptor_blocks fit on a page */
- block = &(f->descriptor_pool[f->n_packets]);
-
- /* DMA address of the block = offset of block relative
- to the kernel base address of the descriptor pool
- + DMA base address of the descriptor pool */
- block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
-
-
- /* the whole CIP pool fits on one page, so no worries about boundaries */
- if ( ((unsigned long) &(f->header_pool[f->n_packets]) - (unsigned long) f->header_pool)
- > PAGE_SIZE) {
- printk(KERN_ERR "dv1394: FATAL ERROR: no room to allocate CIP header\n");
- return;
- }
-
- cip = &(f->header_pool[f->n_packets]);
-
- /* DMA address of the CIP header = offset of cip
- relative to kernel base address of the header pool
- + DMA base address of the header pool */
- cip_dma = (unsigned long) cip % PAGE_SIZE + f->header_pool_dma;
-
- /* is this an empty packet? */
-
- if (video->cip_accum > (video->cip_d - video->cip_n)) {
- empty_packet = 1;
- payload_size = 8;
- video->cip_accum -= (video->cip_d - video->cip_n);
- } else {
- payload_size = 488;
- video->cip_accum += video->cip_n;
- }
-
- /* there are three important packets each frame:
-
- the first packet in the frame - we ask the card to record the timestamp when
- this packet is actually sent, so we can monitor
- how accurate our timestamps are. Also, the first
- packet serves as a semaphore to let us know that
- it's OK to free the *previous* frame's DMA buffer
-
- the last packet in the frame - this packet is used to detect buffer underflows.
- if this is the last ready frame, the last DMA block
- will have a branch back to the beginning of the frame
- (so that the card will re-send the frame on underflow).
- if this branch gets taken, we know that at least one
- frame has been dropped. When the next frame is ready,
- the branch is pointed to its first packet, and the
- semaphore is disabled.
-
- a "mid" packet slightly before the end of the frame - this packet should trigger
- an interrupt so we can go and assign a timestamp to the first packet
- in the next frame. We don't use the very last packet in the frame
- for this purpose, because that would leave very little time to set
- the timestamp before DMA starts on the next frame.
- */
-
- if (f->n_packets == 0) {
- first_packet = 1;
- } else if ( full_packets == (packets_per_frame-1) ) {
- last_packet = 1;
- } else if (f->n_packets == packets_per_frame) {
- mid_packet = 1;
- }
-
-
- /********************/
- /* setup CIP header */
- /********************/
-
- /* the timestamp will be written later from the
- mid-frame interrupt handler. For now we just
- store the address of the CIP header(s) that
- need a timestamp. */
-
- /* first packet in the frame needs a timestamp */
- if (first_packet) {
- f->cip_syt1 = cip;
- if (empty_packet)
- first_packet_empty = 1;
-
- } else if (first_packet_empty && (f->n_packets == 1) ) {
- /* if the first packet was empty, the second
- packet's CIP header also needs a timestamp */
- f->cip_syt2 = cip;
- }
-
- fill_cip_header(cip,
- /* the node ID number of the OHCI card */
- reg_read(video->ohci, OHCI1394_NodeID) & 0x3F,
- video->continuity_counter,
- video->pal_or_ntsc,
- 0xFFFF /* the timestamp is filled in later */);
-
- /* advance counter, only for full packets */
- if ( ! empty_packet )
- video->continuity_counter++;
-
- /******************************/
- /* setup DMA descriptor block */
- /******************************/
-
- /* first descriptor - OUTPUT_MORE_IMMEDIATE, for the controller's IT header */
- fill_output_more_immediate( &(block->u.out.omi), 1, video->channel, 0, payload_size);
-
- if (empty_packet) {
- /* second descriptor - OUTPUT_LAST for CIP header */
- fill_output_last( &(block->u.out.u.empty.ol),
-
- /* want completion status on all interesting packets */
- (first_packet || mid_packet || last_packet) ? 1 : 0,
-
- /* want interrupts on all interesting packets */
- (first_packet || mid_packet || last_packet) ? 1 : 0,
-
- sizeof(struct CIP_header), /* data size */
- cip_dma);
-
- if (first_packet)
- f->frame_begin_timestamp = &(block->u.out.u.empty.ol.q[3]);
- else if (mid_packet)
- f->mid_frame_timestamp = &(block->u.out.u.empty.ol.q[3]);
- else if (last_packet) {
- f->frame_end_timestamp = &(block->u.out.u.empty.ol.q[3]);
- f->frame_end_branch = &(block->u.out.u.empty.ol.q[2]);
- }
-
- branch_address = &(block->u.out.u.empty.ol.q[2]);
- n_descriptors = 3;
- if (first_packet)
- f->first_n_descriptors = n_descriptors;
-
- } else { /* full packet */
-
- /* second descriptor - OUTPUT_MORE for CIP header */
- fill_output_more( &(block->u.out.u.full.om),
- sizeof(struct CIP_header), /* data size */
- cip_dma);
-
-
- /* third (and possibly fourth) descriptor - for DV data */
- /* the 480-byte payload can cross a page boundary; if so,
- we need to split it into two DMA descriptors */
-
- /* does the 480-byte data payload cross a page boundary? */
- if ( (PAGE_SIZE- ((unsigned long)data_p % PAGE_SIZE) ) < 480 ) {
-
- /* page boundary crossed */
-
- fill_output_more( &(block->u.out.u.full.u.cross.om),
- /* data size - how much of data_p fits on the first page */
- PAGE_SIZE - (data_p % PAGE_SIZE),
-
- /* DMA address of data_p */
- dma_region_offset_to_bus(&video->dv_buf,
- data_p - (unsigned long) video->dv_buf.kvirt));
-
- fill_output_last( &(block->u.out.u.full.u.cross.ol),
-
- /* want completion status on all interesting packets */
- (first_packet || mid_packet || last_packet) ? 1 : 0,
-
- /* want interrupt on all interesting packets */
- (first_packet || mid_packet || last_packet) ? 1 : 0,
-
- /* data size - remaining portion of data_p */
- 480 - (PAGE_SIZE - (data_p % PAGE_SIZE)),
-
- /* DMA address of data_p + PAGE_SIZE - (data_p % PAGE_SIZE) */
- dma_region_offset_to_bus(&video->dv_buf,
- data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) video->dv_buf.kvirt));
-
- if (first_packet)
- f->frame_begin_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
- else if (mid_packet)
- f->mid_frame_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
- else if (last_packet) {
- f->frame_end_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
- f->frame_end_branch = &(block->u.out.u.full.u.cross.ol.q[2]);
- }
-
- branch_address = &(block->u.out.u.full.u.cross.ol.q[2]);
-
- n_descriptors = 5;
- if (first_packet)
- f->first_n_descriptors = n_descriptors;
-
- full_packets++;
-
- } else {
- /* fits on one page */
-
- fill_output_last( &(block->u.out.u.full.u.nocross.ol),
-
- /* want completion status on all interesting packets */
- (first_packet || mid_packet || last_packet) ? 1 : 0,
-
- /* want interrupt on all interesting packets */
- (first_packet || mid_packet || last_packet) ? 1 : 0,
-
- 480, /* data size (480 bytes of DV data) */
-
-
- /* DMA address of data_p */
- dma_region_offset_to_bus(&video->dv_buf,
- data_p - (unsigned long) video->dv_buf.kvirt));
-
- if (first_packet)
- f->frame_begin_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
- else if (mid_packet)
- f->mid_frame_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
- else if (last_packet) {
- f->frame_end_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
- f->frame_end_branch = &(block->u.out.u.full.u.nocross.ol.q[2]);
- }
-
- branch_address = &(block->u.out.u.full.u.nocross.ol.q[2]);
-
- n_descriptors = 4;
- if (first_packet)
- f->first_n_descriptors = n_descriptors;
-
- full_packets++;
- }
- }
-
- /* link this descriptor block into the DMA program by filling in
- the branch address of the previous block */
-
- /* note: we are not linked into the active DMA chain yet */
-
- if (last_branch_address) {
- *(last_branch_address) = cpu_to_le32(block_dma | n_descriptors);
- }
-
- last_branch_address = branch_address;
-
-
- f->n_packets++;
-
- }
-
- /* when we first assemble a new frame, set the final branch
- to loop back up to the top */
- *(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
-
- /* make the latest version of this frame visible to the PCI card */
- dma_region_sync_for_device(&video->dv_buf, f->data - (unsigned long) video->dv_buf.kvirt, video->frame_size);
-
- /* lock against DMA interrupt */
- spin_lock_irqsave(&video->spinlock, irq_flags);
-
- f->state = FRAME_READY;
-
- video->n_clear_frames--;
-
- last_frame = video->first_clear_frame - 1;
- if (last_frame == -1)
- last_frame = video->n_frames-1;
-
- video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
-
- irq_printk(" frame %d prepared, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n last=%d\n",
- this_frame, video->active_frame, video->n_clear_frames, video->first_clear_frame, last_frame);
-
- irq_printk(" begin_ts %08lx mid_ts %08lx end_ts %08lx end_br %08lx\n",
- (unsigned long) f->frame_begin_timestamp,
- (unsigned long) f->mid_frame_timestamp,
- (unsigned long) f->frame_end_timestamp,
- (unsigned long) f->frame_end_branch);
-
- if (video->active_frame != -1) {
-
- /* if DMA is already active, we are almost done */
- /* just link us onto the active DMA chain */
- if (video->frames[last_frame]->frame_end_branch) {
- u32 temp;
-
- /* point the previous frame's tail to this frame's head */
- *(video->frames[last_frame]->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
-
- /* this write MUST precede the next one, or we could silently drop frames */
- wmb();
-
- /* disable the want_status semaphore on the last packet */
- temp = le32_to_cpu(*(video->frames[last_frame]->frame_end_branch - 2));
- temp &= 0xF7CFFFFF;
- *(video->frames[last_frame]->frame_end_branch - 2) = cpu_to_le32(temp);
-
- /* flush these writes to memory ASAP */
- flush_pci_write(video->ohci);
-
- /* NOTE:
- ideally the writes should be "atomic": if
- the OHCI card reads the want_status flag in
- between them, we'll falsely report a
- dropped frame. Hopefully this window is too
- small to really matter, and the consequence
- is rather harmless. */
-
-
- irq_printk(" new frame %d linked onto DMA chain\n", this_frame);
-
- } else {
- printk(KERN_ERR "dv1394: last frame not ready???\n");
- }
-
- } else {
-
- u32 transmit_sec, transmit_cyc;
- u32 ts_cyc;
-
- /* DMA is stopped, so this is the very first frame */
- video->active_frame = this_frame;
-
- /* set CommandPtr to address and size of first descriptor block */
- reg_write(video->ohci, video->ohci_IsoXmitCommandPtr,
- video->frames[video->active_frame]->descriptor_pool_dma |
- f->first_n_descriptors);
-
- /* assign a timestamp based on the current cycle time...
- We'll tell the card to begin DMA 100 cycles from now,
- and assign a timestamp 103 cycles from now */
-
- cycleTimer = reg_read(video->ohci, OHCI1394_IsochronousCycleTimer);
-
- ct_sec = cycleTimer >> 25;
- ct_cyc = (cycleTimer >> 12) & 0x1FFF;
- ct_off = cycleTimer & 0xFFF;
-
- transmit_sec = ct_sec;
- transmit_cyc = ct_cyc + 100;
-
- transmit_sec += transmit_cyc/8000;
- transmit_cyc %= 8000;
-
- ts_cyc = transmit_cyc + 3;
- ts_cyc %= 8000;
-
- f->assigned_timestamp = (ts_cyc&0xF) << 12;
-
- /* now actually write the timestamp into the appropriate CIP headers */
- if (f->cip_syt1) {
- f->cip_syt1->b[6] = f->assigned_timestamp >> 8;
- f->cip_syt1->b[7] = f->assigned_timestamp & 0xFF;
- }
- if (f->cip_syt2) {
- f->cip_syt2->b[6] = f->assigned_timestamp >> 8;
- f->cip_syt2->b[7] = f->assigned_timestamp & 0xFF;
- }
-
- /* --- start DMA --- */
-
- /* clear all bits in ContextControl register */
-
- reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, 0xFFFFFFFF);
- wmb();
-
- /* the OHCI card has the ability to start ISO transmission on a
- particular cycle (start-on-cycle). This way we can ensure that
- the first DV frame will have an accurate timestamp.
-
- However, start-on-cycle only appears to work if the OHCI card
- is cycle master! Since the consequences of messing up the first
- timestamp are minimal*, just disable start-on-cycle for now.
-
- * my DV deck drops the first few frames before it "locks in;"
- so the first frame having an incorrect timestamp is inconsequential.
- */
-
-#if 0
- reg_write(video->ohci, video->ohci_IsoXmitContextControlSet,
- (1 << 31) /* enable start-on-cycle */
- | ( (transmit_sec & 0x3) << 29)
- | (transmit_cyc << 16));
- wmb();
-#endif
-
- video->dma_running = 1;
-
- /* set the 'run' bit */
- reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000);
- flush_pci_write(video->ohci);
-
- /* --- DMA should be running now --- */
-
- debug_printk(" Cycle = %4u ContextControl = %08x CmdPtr = %08x\n",
- (reg_read(video->ohci, OHCI1394_IsochronousCycleTimer) >> 12) & 0x1FFF,
- reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
- reg_read(video->ohci, video->ohci_IsoXmitCommandPtr));
-
- debug_printk(" DMA start - current cycle %4u, transmit cycle %4u (%2u), assigning ts cycle %2u\n",
- ct_cyc, transmit_cyc, transmit_cyc & 0xF, ts_cyc & 0xF);
-
-#if DV1394_DEBUG_LEVEL >= 2
- {
- /* check if DMA is really running */
- int i = 0;
- while (i < 20) {
- mb();
- mdelay(1);
- if (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) {
- printk("DMA ACTIVE after %d msec\n", i);
- break;
- }
- i++;
- }
-
- printk("set = %08x, cmdPtr = %08x\n",
- reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
- reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
- );
-
- if ( ! (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) {
- printk("DMA did NOT go active after 20ms, event = %x\n",
- reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & 0x1F);
- } else
- printk("DMA is RUNNING!\n");
- }
-#endif
-
- }
-
-
- spin_unlock_irqrestore(&video->spinlock, irq_flags);
-}
-
-
-
-/*** RECEIVE FUNCTIONS *****************************************************/
-
-/*
- frame method put_packet
-
- map and copy the packet data to its location in the frame
- based upon DIF section and sequence
-*/
-
-static void inline
-frame_put_packet (struct frame *f, struct packet *p)
-{
- int section_type = p->data[0] >> 5; /* section type is in bits 5 - 7 */
- int dif_sequence = p->data[1] >> 4; /* dif sequence number is in bits 4 - 7 */
- int dif_block = p->data[2];
-
- /* sanity check */
- if (dif_sequence > 11 || dif_block > 149) return;
-
- switch (section_type) {
- case 0: /* 1 Header block */
- memcpy( (void *) f->data + dif_sequence * 150 * 80, p->data, 480);
- break;
-
- case 1: /* 2 Subcode blocks */
- memcpy( (void *) f->data + dif_sequence * 150 * 80 + (1 + dif_block) * 80, p->data, 480);
- break;
-
- case 2: /* 3 VAUX blocks */
- memcpy( (void *) f->data + dif_sequence * 150 * 80 + (3 + dif_block) * 80, p->data, 480);
- break;
-
- case 3: /* 9 Audio blocks interleaved with video */
- memcpy( (void *) f->data + dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80, p->data, 480);
- break;
-
- case 4: /* 135 Video blocks interleaved with audio */
- memcpy( (void *) f->data + dif_sequence * 150 * 80 + (7 + (dif_block / 15) + dif_block) * 80, p->data, 480);
- break;
-
- default: /* we can not handle any other data */
- break;
- }
-}
-
-
-static void start_dma_receive(struct video_card *video)
-{
- if (video->first_run == 1) {
- video->first_run = 0;
-
- /* start DMA once all of the frames are READY */
- video->n_clear_frames = 0;
- video->first_clear_frame = -1;
- video->current_packet = 0;
- video->active_frame = 0;
-
- /* reset iso recv control register */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF);
- wmb();
-
- /* clear bufferFill, set isochHeader and speed (0=100) */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000);
-
- /* match on all tags, listen on channel */
- reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel);
-
- /* address and first descriptor block + Z=1 */
- reg_write(video->ohci, video->ohci_IsoRcvCommandPtr,
- video->frames[0]->descriptor_pool_dma | 1); /* Z=1 */
- wmb();
-
- video->dma_running = 1;
-
- /* run */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000);
- flush_pci_write(video->ohci);
-
- debug_printk("dv1394: DMA started\n");
-
-#if DV1394_DEBUG_LEVEL >= 2
- {
- int i;
-
- for (i = 0; i < 1000; ++i) {
- mdelay(1);
- if (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) {
- printk("DMA ACTIVE after %d msec\n", i);
- break;
- }
- }
- if ( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) {
- printk("DEAD, event = %x\n",
- reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
- } else
- printk("RUNNING!\n");
- }
-#endif
- } else if ( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) {
- debug_printk("DEAD, event = %x\n",
- reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
-
- /* wake */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
- }
-}
-
-
-/*
- receive_packets() - build the DMA program for receiving
-*/
-
-static void receive_packets(struct video_card *video)
-{
- struct DMA_descriptor_block *block = NULL;
- dma_addr_t block_dma = 0;
- struct packet *data = NULL;
- dma_addr_t data_dma = 0;
- __le32 *last_branch_address = NULL;
- unsigned long irq_flags;
- int want_interrupt = 0;
- struct frame *f = NULL;
- int i, j;
-
- spin_lock_irqsave(&video->spinlock, irq_flags);
-
- for (j = 0; j < video->n_frames; j++) {
-
- /* connect frames */
- if (j > 0 && f != NULL && f->frame_end_branch != NULL)
- *(f->frame_end_branch) = cpu_to_le32(video->frames[j]->descriptor_pool_dma | 1); /* set Z=1 */
-
- f = video->frames[j];
-
- for (i = 0; i < MAX_PACKETS; i++) {
- /* locate a descriptor block and packet from the buffer */
- block = &(f->descriptor_pool[i]);
- block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
-
- data = ((struct packet*)video->packet_buf.kvirt) + f->frame_num * MAX_PACKETS + i;
- data_dma = dma_region_offset_to_bus( &video->packet_buf,
- ((unsigned long) data - (unsigned long) video->packet_buf.kvirt) );
-
- /* setup DMA descriptor block */
- want_interrupt = ((i % (MAX_PACKETS/2)) == 0 || i == (MAX_PACKETS-1));
- fill_input_last( &(block->u.in.il), want_interrupt, 512, data_dma);
-
- /* link descriptors */
- last_branch_address = f->frame_end_branch;
-
- if (last_branch_address != NULL)
- *(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */
-
- f->frame_end_branch = &(block->u.in.il.q[2]);
- }
-
- } /* next j */
-
- spin_unlock_irqrestore(&video->spinlock, irq_flags);
-
-}
-
-
-
-/*** MANAGEMENT FUNCTIONS **************************************************/
-
-static int do_dv1394_init(struct video_card *video, struct dv1394_init *init)
-{
- unsigned long flags, new_buf_size;
- int i;
- u64 chan_mask;
- int retval = -EINVAL;
-
- debug_printk("dv1394: initialising %d\n", video->id);
- if (init->api_version != DV1394_API_VERSION)
- return -EINVAL;
-
- /* first sanitize all the parameters */
- if ( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) )
- return -EINVAL;
-
- if ( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) )
- return -EINVAL;
-
- if ( (init->syt_offset == 0) || (init->syt_offset > 50) )
- /* default SYT offset is 3 cycles */
- init->syt_offset = 3;
-
- if (init->channel > 63)
- init->channel = 63;
-
- chan_mask = (u64)1 << init->channel;
-
- /* calculate what size DMA buffer is needed */
- if (init->format == DV1394_NTSC)
- new_buf_size = DV1394_NTSC_FRAME_SIZE * init->n_frames;
- else
- new_buf_size = DV1394_PAL_FRAME_SIZE * init->n_frames;
-
- /* round up to PAGE_SIZE */
- if (new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE);
-
- /* don't allow the user to allocate the DMA buffer more than once */
- if (video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) {
- printk("dv1394: re-sizing the DMA buffer is not allowed\n");
- return -EINVAL;
- }
-
- /* shutdown the card if it's currently active */
- /* (the card should not be reset if the parameters are screwy) */
-
- do_dv1394_shutdown(video, 0);
-
- /* try to claim the ISO channel */
- spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
- if (video->ohci->ISO_channel_usage & chan_mask) {
- spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
- retval = -EBUSY;
- goto err;
- }
- video->ohci->ISO_channel_usage |= chan_mask;
- spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
-
- video->channel = init->channel;
-
- /* initialize misc. fields of video */
- video->n_frames = init->n_frames;
- video->pal_or_ntsc = init->format;
-
- video->cip_accum = 0;
- video->continuity_counter = 0;
-
- video->active_frame = -1;
- video->first_clear_frame = 0;
- video->n_clear_frames = video->n_frames;
- video->dropped_frames = 0;
-
- video->write_off = 0;
-
- video->first_run = 1;
- video->current_packet = -1;
- video->first_frame = 0;
-
- if (video->pal_or_ntsc == DV1394_NTSC) {
- video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC;
- video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC;
- video->frame_size = DV1394_NTSC_FRAME_SIZE;
- } else {
- video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL;
- video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL;
- video->frame_size = DV1394_PAL_FRAME_SIZE;
- }
-
- video->syt_offset = init->syt_offset;
-
- /* find and claim DMA contexts on the OHCI card */
-
- if (video->ohci_it_ctx == -1) {
- ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT,
- it_tasklet_func, (unsigned long) video);
-
- if (ohci1394_register_iso_tasklet(video->ohci, &video->it_tasklet) < 0) {
- printk(KERN_ERR "dv1394: could not find an available IT DMA context\n");
- retval = -EBUSY;
- goto err;
- }
-
- video->ohci_it_ctx = video->it_tasklet.context;
- debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
- }
-
- if (video->ohci_ir_ctx == -1) {
- ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE,
- ir_tasklet_func, (unsigned long) video);
-
- if (ohci1394_register_iso_tasklet(video->ohci, &video->ir_tasklet) < 0) {
- printk(KERN_ERR "dv1394: could not find an available IR DMA context\n");
- retval = -EBUSY;
- goto err;
- }
- video->ohci_ir_ctx = video->ir_tasklet.context;
- debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
- }
-
- /* allocate struct frames */
- for (i = 0; i < init->n_frames; i++) {
- video->frames[i] = frame_new(i, video);
-
- if (!video->frames[i]) {
- printk(KERN_ERR "dv1394: Cannot allocate frame structs\n");
- retval = -ENOMEM;
- goto err;
- }
- }
-
- if (!video->dv_buf.kvirt) {
- /* allocate the ringbuffer */
- retval = dma_region_alloc(&video->dv_buf, new_buf_size, video->ohci->dev, PCI_DMA_TODEVICE);
- if (retval)
- goto err;
-
- video->dv_buf_size = new_buf_size;
-
- debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n",
- video->n_frames, video->dv_buf.n_pages,
- video->dv_buf.n_dma_pages, video->dv_buf_size);
- }
-
- /* set up the frame->data pointers */
- for (i = 0; i < video->n_frames; i++)
- video->frames[i]->data = (unsigned long) video->dv_buf.kvirt + i * video->frame_size;
-
- if (!video->packet_buf.kvirt) {
- /* allocate packet buffer */
- video->packet_buf_size = sizeof(struct packet) * video->n_frames * MAX_PACKETS;
- if (video->packet_buf_size % PAGE_SIZE)
- video->packet_buf_size += PAGE_SIZE - (video->packet_buf_size % PAGE_SIZE);
-
- retval = dma_region_alloc(&video->packet_buf, video->packet_buf_size,
- video->ohci->dev, PCI_DMA_FROMDEVICE);
- if (retval)
- goto err;
-
- debug_printk("dv1394: Allocated %d packets in buffer, total %u pages (%u DMA pages), %lu bytes\n",
- video->n_frames*MAX_PACKETS, video->packet_buf.n_pages,
- video->packet_buf.n_dma_pages, video->packet_buf_size);
- }
-
- /* set up register offsets for IT context */
- /* IT DMA context registers are spaced 16 bytes apart */
- video->ohci_IsoXmitContextControlSet = OHCI1394_IsoXmitContextControlSet+16*video->ohci_it_ctx;
- video->ohci_IsoXmitContextControlClear = OHCI1394_IsoXmitContextControlClear+16*video->ohci_it_ctx;
- video->ohci_IsoXmitCommandPtr = OHCI1394_IsoXmitCommandPtr+16*video->ohci_it_ctx;
-
- /* enable interrupts for IT context */
- reg_write(video->ohci, OHCI1394_IsoXmitIntMaskSet, (1 << video->ohci_it_ctx));
- debug_printk("dv1394: interrupts enabled for IT context %d\n", video->ohci_it_ctx);
-
- /* set up register offsets for IR context */
- /* IR DMA context registers are spaced 32 bytes apart */
- video->ohci_IsoRcvContextControlSet = OHCI1394_IsoRcvContextControlSet+32*video->ohci_ir_ctx;
- video->ohci_IsoRcvContextControlClear = OHCI1394_IsoRcvContextControlClear+32*video->ohci_ir_ctx;
- video->ohci_IsoRcvCommandPtr = OHCI1394_IsoRcvCommandPtr+32*video->ohci_ir_ctx;
- video->ohci_IsoRcvContextMatch = OHCI1394_IsoRcvContextMatch+32*video->ohci_ir_ctx;
-
- /* enable interrupts for IR context */
- reg_write(video->ohci, OHCI1394_IsoRecvIntMaskSet, (1 << video->ohci_ir_ctx) );
- debug_printk("dv1394: interrupts enabled for IR context %d\n", video->ohci_ir_ctx);
-
- return 0;
-
-err:
- do_dv1394_shutdown(video, 1);
- return retval;
-}
-
-/* if the user doesn't bother to call ioctl(INIT) before starting
- mmap() or read()/write(), just give him some default values */
-
-static int do_dv1394_init_default(struct video_card *video)
-{
- struct dv1394_init init;
-
- init.api_version = DV1394_API_VERSION;
- init.n_frames = DV1394_MAX_FRAMES / 4;
- init.channel = video->channel;
- init.format = video->pal_or_ntsc;
- init.cip_n = video->cip_n;
- init.cip_d = video->cip_d;
- init.syt_offset = video->syt_offset;
-
- return do_dv1394_init(video, &init);
-}
-
-/* do NOT call from interrupt context */
-static void stop_dma(struct video_card *video)
-{
- unsigned long flags;
- int i;
-
- /* no interrupts */
- spin_lock_irqsave(&video->spinlock, flags);
-
- video->dma_running = 0;
-
- if ( (video->ohci_it_ctx == -1) && (video->ohci_ir_ctx == -1) )
- goto out;
-
- /* stop DMA if in progress */
- if ( (video->active_frame != -1) ||
- (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
- (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) & (1 << 10)) ) {
-
- /* clear the .run bits */
- reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15));
- reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15));
- flush_pci_write(video->ohci);
-
- video->active_frame = -1;
- video->first_run = 1;
-
- /* wait until DMA really stops */
- i = 0;
- while (i < 1000) {
-
- /* wait 0.1 millisecond */
- udelay(100);
-
- if ( (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
- (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) & (1 << 10)) ) {
- /* still active */
- debug_printk("dv1394: stop_dma: DMA not stopped yet\n" );
- mb();
- } else {
- debug_printk("dv1394: stop_dma: DMA stopped safely after %d ms\n", i/10);
- break;
- }
-
- i++;
- }
-
- if (i == 1000) {
- printk(KERN_ERR "dv1394: stop_dma: DMA still going after %d ms!\n", i/10);
- }
- }
- else
- debug_printk("dv1394: stop_dma: already stopped.\n");
-
-out:
- spin_unlock_irqrestore(&video->spinlock, flags);
-}
-
-
-
-static void do_dv1394_shutdown(struct video_card *video, int free_dv_buf)
-{
- int i;
-
- debug_printk("dv1394: shutdown...\n");
-
- /* stop DMA if in progress */
- stop_dma(video);
-
- /* release the DMA contexts */
- if (video->ohci_it_ctx != -1) {
- video->ohci_IsoXmitContextControlSet = 0;
- video->ohci_IsoXmitContextControlClear = 0;
- video->ohci_IsoXmitCommandPtr = 0;
-
- /* disable interrupts for IT context */
- reg_write(video->ohci, OHCI1394_IsoXmitIntMaskClear, (1 << video->ohci_it_ctx));
-
- /* remove tasklet */
- ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet);
- debug_printk("dv1394: IT context %d released\n", video->ohci_it_ctx);
- video->ohci_it_ctx = -1;
- }
-
- if (video->ohci_ir_ctx != -1) {
- video->ohci_IsoRcvContextControlSet = 0;
- video->ohci_IsoRcvContextControlClear = 0;
- video->ohci_IsoRcvCommandPtr = 0;
- video->ohci_IsoRcvContextMatch = 0;
-
- /* disable interrupts for IR context */
- reg_write(video->ohci, OHCI1394_IsoRecvIntMaskClear, (1 << video->ohci_ir_ctx));
-
- /* remove tasklet */
- ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet);
- debug_printk("dv1394: IR context %d released\n", video->ohci_ir_ctx);
- video->ohci_ir_ctx = -1;
- }
-
- /* release the ISO channel */
- if (video->channel != -1) {
- u64 chan_mask;
- unsigned long flags;
-
- chan_mask = (u64)1 << video->channel;
-
- spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
- video->ohci->ISO_channel_usage &= ~(chan_mask);
- spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
-
- video->channel = -1;
- }
-
- /* free the frame structs */
- for (i = 0; i < DV1394_MAX_FRAMES; i++) {
- if (video->frames[i])
- frame_delete(video->frames[i]);
- video->frames[i] = NULL;
- }
-
- video->n_frames = 0;
-
- /* we can't free the DMA buffer unless it is guaranteed that
- no more user-space mappings exist */
-
- if (free_dv_buf) {
- dma_region_free(&video->dv_buf);
- video->dv_buf_size = 0;
- }
-
- /* free packet buffer */
- dma_region_free(&video->packet_buf);
- video->packet_buf_size = 0;
-
- debug_printk("dv1394: shutdown OK\n");
-}
-
-/*
- **********************************
- *** MMAP() THEORY OF OPERATION ***
- **********************************
-
- The ringbuffer cannot be re-allocated or freed while
- a user program maintains a mapping of it. (note that a mapping
- can persist even after the device fd is closed!)
-
- So, only let the user process allocate the DMA buffer once.
- To resize or deallocate it, you must close the device file
- and open it again.
-
- Previously Dan M. hacked out a scheme that allowed the DMA
- buffer to change by forcefully unmapping it from the user's
- address space. It was prone to error because it's very hard to
- track all the places the buffer could have been mapped (we
- would have had to walk the vma list of every process in the
- system to be sure we found all the mappings!). Instead, we
- force the user to choose one buffer size and stick with
- it. This small sacrifice is worth the huge reduction in
- error-prone code in dv1394.
-*/
-
-static int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct video_card *video = file_to_video_card(file);
- int retval = -EINVAL;
-
- /*
- * We cannot use the blocking variant mutex_lock here because .mmap
- * is called with mmap_sem held, while .ioctl, .read, .write acquire
- * video->mtx and subsequently call copy_to/from_user which will
- * grab mmap_sem in case of a page fault.
- */
- if (!mutex_trylock(&video->mtx))
- return -EAGAIN;
-
- if ( ! video_card_initialized(video) ) {
- retval = do_dv1394_init_default(video);
- if (retval)
- goto out;
- }
-
- retval = dma_region_mmap(&video->dv_buf, file, vma);
-out:
- mutex_unlock(&video->mtx);
- return retval;
-}
-
-/*** DEVICE FILE INTERFACE *************************************************/
-
-/* no need to serialize, multiple threads OK */
-static unsigned int dv1394_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct video_card *video = file_to_video_card(file);
- unsigned int mask = 0;
- unsigned long flags;
-
- poll_wait(file, &video->waitq, wait);
-
- spin_lock_irqsave(&video->spinlock, flags);
- if ( video->n_frames == 0 ) {
-
- } else if ( video->active_frame == -1 ) {
- /* nothing going on */
- mask |= POLLOUT;
- } else {
- /* any clear/ready buffers? */
- if (video->n_clear_frames >0)
- mask |= POLLOUT | POLLIN;
- }
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- return mask;
-}
-
-static int dv1394_fasync(int fd, struct file *file, int on)
-{
- /* I just copied this code verbatim from Alan Cox's mouse driver example
- (Documentation/DocBook/) */
-
- struct video_card *video = file_to_video_card(file);
-
- return fasync_helper(fd, file, on, &video->fasync);
-}
-
-static ssize_t dv1394_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct video_card *video = file_to_video_card(file);
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- size_t cnt;
- unsigned long flags;
- int target_frame;
-
- /* serialize this to prevent multi-threaded mayhem */
- if (file->f_flags & O_NONBLOCK) {
- if (!mutex_trylock(&video->mtx))
- return -EAGAIN;
- } else {
- if (mutex_lock_interruptible(&video->mtx))
- return -ERESTARTSYS;
- }
-
- if ( !video_card_initialized(video) ) {
- ret = do_dv1394_init_default(video);
- if (ret) {
- mutex_unlock(&video->mtx);
- return ret;
- }
- }
-
- ret = 0;
- add_wait_queue(&video->waitq, &wait);
-
- while (count > 0) {
-
- /* must set TASK_INTERRUPTIBLE *before* checking for free
- buffers; otherwise we could miss a wakeup if the interrupt
- fires between the check and the schedule() */
-
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_lock_irqsave(&video->spinlock, flags);
-
- target_frame = video->first_clear_frame;
-
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- if (video->frames[target_frame]->state == FRAME_CLEAR) {
-
- /* how much room is left in the target frame buffer */
- cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);
-
- } else {
- /* buffer is already used */
- cnt = 0;
- }
-
- if (cnt > count)
- cnt = count;
-
- if (cnt <= 0) {
- /* no room left, gotta wait */
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
-
- schedule();
-
- continue; /* start over from 'while(count > 0)...' */
- }
-
- if (copy_from_user(video->dv_buf.kvirt + video->write_off, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
-
- video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
-
- if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames))
- frame_prepare(video, target_frame);
- }
-
- remove_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_RUNNING);
- mutex_unlock(&video->mtx);
- return ret;
-}
-
-
-static ssize_t dv1394_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct video_card *video = file_to_video_card(file);
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- size_t cnt;
- unsigned long flags;
- int target_frame;
-
- /* serialize this to prevent multi-threaded mayhem */
- if (file->f_flags & O_NONBLOCK) {
- if (!mutex_trylock(&video->mtx))
- return -EAGAIN;
- } else {
- if (mutex_lock_interruptible(&video->mtx))
- return -ERESTARTSYS;
- }
-
- if ( !video_card_initialized(video) ) {
- ret = do_dv1394_init_default(video);
- if (ret) {
- mutex_unlock(&video->mtx);
- return ret;
- }
- video->continuity_counter = -1;
-
- receive_packets(video);
-
- start_dma_receive(video);
- }
-
- ret = 0;
- add_wait_queue(&video->waitq, &wait);
-
- while (count > 0) {
-
- /* must set TASK_INTERRUPTIBLE *before* checking for free
- buffers; otherwise we could miss a wakeup if the interrupt
- fires between the check and the schedule() */
-
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_lock_irqsave(&video->spinlock, flags);
-
- target_frame = video->first_clear_frame;
-
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- if (target_frame >= 0 &&
- video->n_clear_frames > 0 &&
- video->frames[target_frame]->state == FRAME_CLEAR) {
-
- /* how much room is left in the target frame buffer */
- cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);
-
- } else {
- /* buffer is already used */
- cnt = 0;
- }
-
- if (cnt > count)
- cnt = count;
-
- if (cnt <= 0) {
- /* no room left, gotta wait */
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
-
- schedule();
-
- continue; /* start over from 'while(count > 0)...' */
- }
-
- if (copy_to_user(buffer, video->dv_buf.kvirt + video->write_off, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
-
- video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
-
- if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) {
- spin_lock_irqsave(&video->spinlock, flags);
- video->n_clear_frames--;
- video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
- spin_unlock_irqrestore(&video->spinlock, flags);
- }
- }
-
- remove_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_RUNNING);
- mutex_unlock(&video->mtx);
- return ret;
-}
-
-
-/*** DEVICE IOCTL INTERFACE ************************************************/
-
-static long dv1394_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct video_card *video = file_to_video_card(file);
- unsigned long flags;
- int ret = -EINVAL;
- void __user *argp = (void __user *)arg;
-
- DECLARE_WAITQUEUE(wait, current);
-
- /* serialize this to prevent multi-threaded mayhem */
- if (file->f_flags & O_NONBLOCK) {
- if (!mutex_trylock(&video->mtx))
- return -EAGAIN;
- } else {
- if (mutex_lock_interruptible(&video->mtx))
- return -ERESTARTSYS;
- }
-
- switch(cmd)
- {
- case DV1394_IOC_SUBMIT_FRAMES: {
- unsigned int n_submit;
-
- if ( !video_card_initialized(video) ) {
- ret = do_dv1394_init_default(video);
- if (ret)
- goto out;
- }
-
- n_submit = (unsigned int) arg;
-
- if (n_submit > video->n_frames) {
- ret = -EINVAL;
- goto out;
- }
-
- while (n_submit > 0) {
-
- add_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_lock_irqsave(&video->spinlock, flags);
-
- /* wait until video->first_clear_frame is really CLEAR */
- while (video->frames[video->first_clear_frame]->state != FRAME_CLEAR) {
-
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- if (signal_pending(current)) {
- remove_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_RUNNING);
- ret = -EINTR;
- goto out;
- }
-
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_lock_irqsave(&video->spinlock, flags);
- }
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- remove_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_RUNNING);
-
- frame_prepare(video, video->first_clear_frame);
-
- n_submit--;
- }
-
- ret = 0;
- break;
- }
-
- case DV1394_IOC_WAIT_FRAMES: {
- unsigned int n_wait;
-
- if ( !video_card_initialized(video) ) {
- ret = -EINVAL;
- goto out;
- }
-
- n_wait = (unsigned int) arg;
-
- /* since we re-run the last frame on underflow, we will
- never actually have n_frames clear frames; at most only
- n_frames - 1 */
-
- if (n_wait > (video->n_frames-1) ) {
- ret = -EINVAL;
- goto out;
- }
-
- add_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_lock_irqsave(&video->spinlock, flags);
-
- while (video->n_clear_frames < n_wait) {
-
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- if (signal_pending(current)) {
- remove_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_RUNNING);
- ret = -EINTR;
- goto out;
- }
-
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_lock_irqsave(&video->spinlock, flags);
- }
-
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- remove_wait_queue(&video->waitq, &wait);
- set_current_state(TASK_RUNNING);
- ret = 0;
- break;
- }
-
- case DV1394_IOC_RECEIVE_FRAMES: {
- unsigned int n_recv;
-
- if ( !video_card_initialized(video) ) {
- ret = -EINVAL;
- goto out;
- }
-
- n_recv = (unsigned int) arg;
-
- /* at least one frame must be active */
- if (n_recv > (video->n_frames-1) ) {
- ret = -EINVAL;
- goto out;
- }
-
- spin_lock_irqsave(&video->spinlock, flags);
-
- /* release the clear frames */
- video->n_clear_frames -= n_recv;
-
- /* advance the clear frame cursor */
- video->first_clear_frame = (video->first_clear_frame + n_recv) % video->n_frames;
-
- /* reset dropped_frames */
- video->dropped_frames = 0;
-
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- ret = 0;
- break;
- }
-
- case DV1394_IOC_START_RECEIVE: {
- if ( !video_card_initialized(video) ) {
- ret = do_dv1394_init_default(video);
- if (ret)
- goto out;
- }
-
- video->continuity_counter = -1;
-
- receive_packets(video);
-
- start_dma_receive(video);
-
- ret = 0;
- break;
- }
-
- case DV1394_IOC_INIT: {
- struct dv1394_init init;
- if (!argp) {
- ret = do_dv1394_init_default(video);
- } else {
- if (copy_from_user(&init, argp, sizeof(init))) {
- ret = -EFAULT;
- goto out;
- }
- ret = do_dv1394_init(video, &init);
- }
- break;
- }
-
- case DV1394_IOC_SHUTDOWN:
- do_dv1394_shutdown(video, 0);
- ret = 0;
- break;
-
-
- case DV1394_IOC_GET_STATUS: {
- struct dv1394_status status;
-
- if ( !video_card_initialized(video) ) {
- ret = -EINVAL;
- goto out;
- }
-
- status.init.api_version = DV1394_API_VERSION;
- status.init.channel = video->channel;
- status.init.n_frames = video->n_frames;
- status.init.format = video->pal_or_ntsc;
- status.init.cip_n = video->cip_n;
- status.init.cip_d = video->cip_d;
- status.init.syt_offset = video->syt_offset;
-
- status.first_clear_frame = video->first_clear_frame;
-
- /* the rest of the fields need to be locked against the interrupt */
- spin_lock_irqsave(&video->spinlock, flags);
-
- status.active_frame = video->active_frame;
- status.n_clear_frames = video->n_clear_frames;
-
- status.dropped_frames = video->dropped_frames;
-
- /* reset dropped_frames */
- video->dropped_frames = 0;
-
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- if (copy_to_user(argp, &status, sizeof(status))) {
- ret = -EFAULT;
- goto out;
- }
-
- ret = 0;
- break;
- }
-
- default:
- break;
- }
-
- out:
- mutex_unlock(&video->mtx);
- return ret;
-}
-
-/*** DEVICE FILE INTERFACE CONTINUED ***************************************/
-
-static int dv1394_open(struct inode *inode, struct file *file)
-{
- struct video_card *video = NULL;
-
- if (file->private_data) {
- video = file->private_data;
-
- } else {
- /* look up the card by ID */
- unsigned long flags;
- int idx = ieee1394_file_to_instance(file);
-
- spin_lock_irqsave(&dv1394_cards_lock, flags);
- if (!list_empty(&dv1394_cards)) {
- struct video_card *p;
- list_for_each_entry(p, &dv1394_cards, list) {
- if ((p->id) == idx) {
- video = p;
- break;
- }
- }
- }
- spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
- if (!video) {
- debug_printk("dv1394: OHCI card %d not found", idx);
- return -ENODEV;
- }
-
- file->private_data = (void*) video;
- }
-
-#ifndef DV1394_ALLOW_MORE_THAN_ONE_OPEN
-
- if ( test_and_set_bit(0, &video->open) ) {
- /* video is already open by someone else */
- return -EBUSY;
- }
-
-#endif
-
- printk(KERN_INFO "%s: NOTE, the dv1394 interface is unsupported "
- "and will not be available in the new firewire driver stack. "
- "Try libraw1394 based programs instead.\n", current->comm);
-
- return nonseekable_open(inode, file);
-}
-
-
-static int dv1394_release(struct inode *inode, struct file *file)
-{
- struct video_card *video = file_to_video_card(file);
-
- /* OK to free the DMA buffer, no more mappings can exist */
- do_dv1394_shutdown(video, 1);
-
- /* give someone else a turn */
- clear_bit(0, &video->open);
-
- return 0;
-}
-
-
-/*** DEVICE DRIVER HANDLERS ************************************************/
-
-static void it_tasklet_func(unsigned long data)
-{
- int wake = 0;
- struct video_card *video = (struct video_card*) data;
-
- spin_lock(&video->spinlock);
-
- if (!video->dma_running)
- goto out;
-
- irq_printk("ContextControl = %08x, CommandPtr = %08x\n",
- reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
- reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
- );
-
-
- if ( (video->ohci_it_ctx != -1) &&
- (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) {
-
- struct frame *f;
- unsigned int frame, i;
-
-
- if (video->active_frame == -1)
- frame = 0;
- else
- frame = video->active_frame;
-
- /* check all the DMA-able frames */
- for (i = 0; i < video->n_frames; i++, frame = (frame+1) % video->n_frames) {
-
- irq_printk("IRQ checking frame %d...", frame);
- f = video->frames[frame];
- if (f->state != FRAME_READY) {
- irq_printk("clear, skipping\n");
- /* we don't own this frame */
- continue;
- }
-
- irq_printk("DMA\n");
-
- /* check the frame begin semaphore to see if we can free the previous frame */
- if ( *(f->frame_begin_timestamp) ) {
- int prev_frame;
- struct frame *prev_f;
-
-
-
- /* don't reset, need this later *(f->frame_begin_timestamp) = 0; */
- irq_printk(" BEGIN\n");
-
- prev_frame = frame - 1;
- if (prev_frame == -1)
- prev_frame += video->n_frames;
- prev_f = video->frames[prev_frame];
-
- /* make sure we can actually garbage collect
- this frame */
- if ( (prev_f->state == FRAME_READY) &&
- prev_f->done && (!f->done) )
- {
- frame_reset(prev_f);
- video->n_clear_frames++;
- wake = 1;
- video->active_frame = frame;
-
- irq_printk(" BEGIN - freeing previous frame %d, new active frame is %d\n", prev_frame, frame);
- } else {
- irq_printk(" BEGIN - can't free yet\n");
- }
-
- f->done = 1;
- }
-
-
- /* see if we need to set the timestamp for the next frame */
- if ( *(f->mid_frame_timestamp) ) {
- struct frame *next_frame;
- u32 begin_ts, ts_cyc, ts_off;
-
- *(f->mid_frame_timestamp) = 0;
-
- begin_ts = le32_to_cpu(*(f->frame_begin_timestamp));
-
- irq_printk(" MIDDLE - first packet was sent at cycle %4u (%2u), assigned timestamp was (%2u) %4u\n",
- begin_ts & 0x1FFF, begin_ts & 0xF,
- f->assigned_timestamp >> 12, f->assigned_timestamp & 0xFFF);
-
- /* prepare next frame and assign timestamp */
- next_frame = video->frames[ (frame+1) % video->n_frames ];
-
- if (next_frame->state == FRAME_READY) {
- irq_printk(" MIDDLE - next frame is ready, good\n");
- } else {
- debug_printk("dv1394: Underflow! At least one frame has been dropped.\n");
- next_frame = f;
- }
-
- /* set the timestamp to the timestamp of the last frame sent,
- plus the length of the last frame sent, plus the syt latency */
- ts_cyc = begin_ts & 0xF;
- /* advance one frame, plus syt latency (typically 2-3) */
- ts_cyc += f->n_packets + video->syt_offset ;
-
- ts_off = 0;
-
- ts_cyc += ts_off/3072;
- ts_off %= 3072;
-
- next_frame->assigned_timestamp = ((ts_cyc&0xF) << 12) + ts_off;
- if (next_frame->cip_syt1) {
- next_frame->cip_syt1->b[6] = next_frame->assigned_timestamp >> 8;
- next_frame->cip_syt1->b[7] = next_frame->assigned_timestamp & 0xFF;
- }
- if (next_frame->cip_syt2) {
- next_frame->cip_syt2->b[6] = next_frame->assigned_timestamp >> 8;
- next_frame->cip_syt2->b[7] = next_frame->assigned_timestamp & 0xFF;
- }
-
- }
-
- /* see if the frame looped */
- if ( *(f->frame_end_timestamp) ) {
-
- *(f->frame_end_timestamp) = 0;
-
- debug_printk(" END - the frame looped at least once\n");
-
- video->dropped_frames++;
- }
-
- } /* for (each frame) */
- }
-
- if (wake) {
- kill_fasync(&video->fasync, SIGIO, POLL_OUT);
-
- /* wake readers/writers/ioctl'ers */
- wake_up_interruptible(&video->waitq);
- }
-
-out:
- spin_unlock(&video->spinlock);
-}
-
-static void ir_tasklet_func(unsigned long data)
-{
- int wake = 0;
- struct video_card *video = (struct video_card*) data;
-
- spin_lock(&video->spinlock);
-
- if (!video->dma_running)
- goto out;
-
- if ( (video->ohci_ir_ctx != -1) &&
- (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) {
-
- int sof=0; /* start-of-frame flag */
- struct frame *f;
- u16 packet_length;
- int i, dbc=0;
- struct DMA_descriptor_block *block = NULL;
- u16 xferstatus;
-
- int next_i, prev_i;
- struct DMA_descriptor_block *next = NULL;
- dma_addr_t next_dma = 0;
- struct DMA_descriptor_block *prev = NULL;
-
- /* loop over all descriptors in all frames */
- for (i = 0; i < video->n_frames*MAX_PACKETS; i++) {
- struct packet *p = dma_region_i(&video->packet_buf, struct packet, video->current_packet);
-
- /* make sure we are seeing the latest changes to p */
- dma_region_sync_for_cpu(&video->packet_buf,
- (unsigned long) p - (unsigned long) video->packet_buf.kvirt,
- sizeof(struct packet));
-
- packet_length = le16_to_cpu(p->data_length);
-
- /* get the descriptor based on packet_buffer cursor */
- f = video->frames[video->current_packet / MAX_PACKETS];
- block = &(f->descriptor_pool[video->current_packet % MAX_PACKETS]);
- xferstatus = le32_to_cpu(block->u.in.il.q[3]) >> 16;
- xferstatus &= 0x1F;
- irq_printk("ir_tasklet_func: xferStatus/resCount [%d] = 0x%08x\n", i, le32_to_cpu(block->u.in.il.q[3]) );
-
- /* get the current frame */
- f = video->frames[video->active_frame];
-
- /* exclude empty packet */
- if (packet_length > 8 && xferstatus == 0x11) {
- /* check for start of frame */
- /* DRD> Changed to check section type ([0]>>5==0)
- and dif sequence ([1]>>4==0) */
- sof = ( (p->data[0] >> 5) == 0 && (p->data[1] >> 4) == 0);
-
- dbc = (int) (p->cip_h1 >> 24);
- if ( video->continuity_counter != -1 && dbc > ((video->continuity_counter + 1) % 256) )
- {
- printk(KERN_WARNING "dv1394: discontinuity detected, dropping all frames\n" );
- video->dropped_frames += video->n_clear_frames + 1;
- video->first_frame = 0;
- video->n_clear_frames = 0;
- video->first_clear_frame = -1;
- }
- video->continuity_counter = dbc;
-
- if (!video->first_frame) {
- if (sof) {
- video->first_frame = 1;
- }
-
- } else if (sof) {
- /* close current frame */
- frame_reset(f); /* f->state = STATE_CLEAR */
- video->n_clear_frames++;
- if (video->n_clear_frames > video->n_frames) {
- video->dropped_frames++;
- printk(KERN_WARNING "dv1394: dropped a frame during reception\n" );
- video->n_clear_frames = video->n_frames-1;
- video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
- }
- if (video->first_clear_frame == -1)
- video->first_clear_frame = video->active_frame;
-
- /* get the next frame */
- video->active_frame = (video->active_frame + 1) % video->n_frames;
- f = video->frames[video->active_frame];
- irq_printk(" frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n",
- video->active_frame, video->n_clear_frames, video->first_clear_frame);
- }
- if (video->first_frame) {
- if (sof) {
- /* open next frame */
- f->state = FRAME_READY;
- }
-
- /* copy to buffer */
- if (f->n_packets > (video->frame_size / 480)) {
- printk(KERN_ERR "frame buffer overflow during receive\n");
- }
-
- frame_put_packet(f, p);
-
- } /* first_frame */
- }
-
- /* stop, end of ready packets */
- else if (xferstatus == 0) {
- break;
- }
-
- /* reset xferStatus & resCount */
- block->u.in.il.q[3] = cpu_to_le32(512);
-
- /* terminate dma chain at this (next) packet */
- next_i = video->current_packet;
- f = video->frames[next_i / MAX_PACKETS];
- next = &(f->descriptor_pool[next_i % MAX_PACKETS]);
- next_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
- next->u.in.il.q[0] |= cpu_to_le32(3 << 20); /* enable interrupt */
- next->u.in.il.q[2] = cpu_to_le32(0); /* disable branch */
-
- /* link previous to next */
- prev_i = (next_i == 0) ? (MAX_PACKETS * video->n_frames - 1) : (next_i - 1);
- f = video->frames[prev_i / MAX_PACKETS];
- prev = &(f->descriptor_pool[prev_i % MAX_PACKETS]);
- if (prev_i % (MAX_PACKETS/2)) {
- prev->u.in.il.q[0] &= ~cpu_to_le32(3 << 20); /* no interrupt */
- } else {
- prev->u.in.il.q[0] |= cpu_to_le32(3 << 20); /* enable interrupt */
- }
- prev->u.in.il.q[2] = cpu_to_le32(next_dma | 1); /* set Z=1 */
- wmb();
-
- /* wake up DMA in case it fell asleep */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
-
- /* advance packet_buffer cursor */
- video->current_packet = (video->current_packet + 1) % (MAX_PACKETS * video->n_frames);
-
- } /* for all packets */
-
- wake = 1; /* why the hell not? */
-
- } /* receive interrupt */
-
- if (wake) {
- kill_fasync(&video->fasync, SIGIO, POLL_IN);
-
- /* wake readers/writers/ioctl'ers */
- wake_up_interruptible(&video->waitq);
- }
-
-out:
- spin_unlock(&video->spinlock);
-}
-
-static struct cdev dv1394_cdev;
-static const struct file_operations dv1394_fops=
-{
- .owner = THIS_MODULE,
- .poll = dv1394_poll,
- .unlocked_ioctl = dv1394_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = dv1394_compat_ioctl,
-#endif
- .mmap = dv1394_mmap,
- .open = dv1394_open,
- .write = dv1394_write,
- .read = dv1394_read,
- .release = dv1394_release,
- .fasync = dv1394_fasync,
- .llseek = no_llseek,
-};
-
-
-/*** HOTPLUG STUFF **********************************************************/
-/*
- * Export information about protocols/devices supported by this driver.
- */
-#ifdef MODULE
-static const struct ieee1394_device_id dv1394_id_table[] = {
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = AVC_SW_VERSION_ENTRY & 0xffffff
- },
- { }
-};
-
-MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table);
-#endif /* MODULE */
-
-static struct hpsb_protocol_driver dv1394_driver = {
- .name = "dv1394",
-};
-
-
-/*** IEEE1394 HPSB CALLBACKS ***********************************************/
-
-static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes mode)
-{
- struct video_card *video;
- unsigned long flags;
- int i;
-
- video = kzalloc(sizeof(*video), GFP_KERNEL);
- if (!video) {
- printk(KERN_ERR "dv1394: cannot allocate video_card\n");
- return -1;
- }
-
- video->ohci = ohci;
- /* lower 2 bits of id indicate which of four "plugs"
- per host */
- video->id = ohci->host->id << 2;
- if (format == DV1394_NTSC)
- video->id |= mode;
- else
- video->id |= 2 + mode;
-
- video->ohci_it_ctx = -1;
- video->ohci_ir_ctx = -1;
-
- video->ohci_IsoXmitContextControlSet = 0;
- video->ohci_IsoXmitContextControlClear = 0;
- video->ohci_IsoXmitCommandPtr = 0;
-
- video->ohci_IsoRcvContextControlSet = 0;
- video->ohci_IsoRcvContextControlClear = 0;
- video->ohci_IsoRcvCommandPtr = 0;
- video->ohci_IsoRcvContextMatch = 0;
-
- video->n_frames = 0; /* flag that video is not initialized */
- video->channel = 63; /* default to broadcast channel */
- video->active_frame = -1;
-
- /* initialize the following */
- video->pal_or_ntsc = format;
- video->cip_n = 0; /* 0 = use builtin default */
- video->cip_d = 0;
- video->syt_offset = 0;
- video->mode = mode;
-
- for (i = 0; i < DV1394_MAX_FRAMES; i++)
- video->frames[i] = NULL;
-
- dma_region_init(&video->dv_buf);
- video->dv_buf_size = 0;
- dma_region_init(&video->packet_buf);
- video->packet_buf_size = 0;
-
- clear_bit(0, &video->open);
- spin_lock_init(&video->spinlock);
- video->dma_running = 0;
- mutex_init(&video->mtx);
- init_waitqueue_head(&video->waitq);
- video->fasync = NULL;
-
- spin_lock_irqsave(&dv1394_cards_lock, flags);
- INIT_LIST_HEAD(&video->list);
- list_add_tail(&video->list, &dv1394_cards);
- spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
- debug_printk("dv1394: dv1394_init() OK on ID %d\n", video->id);
- return 0;
-}
-
-static void dv1394_remove_host(struct hpsb_host *host)
-{
- struct video_card *video, *tmp_video;
- unsigned long flags;
- int found_ohci_card = 0;
-
- do {
- video = NULL;
- spin_lock_irqsave(&dv1394_cards_lock, flags);
- list_for_each_entry(tmp_video, &dv1394_cards, list) {
- if ((tmp_video->id >> 2) == host->id) {
- list_del(&tmp_video->list);
- video = tmp_video;
- found_ohci_card = 1;
- break;
- }
- }
- spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
- if (video) {
- do_dv1394_shutdown(video, 1);
- kfree(video);
- }
- } while (video);
-
- if (found_ohci_card)
- device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
- IEEE1394_MINOR_BLOCK_DV1394 * 16 + (host->id << 2)));
-}
-
-static void dv1394_add_host(struct hpsb_host *host)
-{
- struct ti_ohci *ohci;
- int id = host->id;
-
- /* We only work with the OHCI-1394 driver */
- if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
- return;
-
- ohci = (struct ti_ohci *)host->hostdata;
-
- device_create(hpsb_protocol_class, NULL,
- MKDEV(IEEE1394_MAJOR,
- IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)),
- NULL, "dv1394-%d", id);
-
- dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
- dv1394_init(ohci, DV1394_NTSC, MODE_TRANSMIT);
- dv1394_init(ohci, DV1394_PAL, MODE_RECEIVE);
- dv1394_init(ohci, DV1394_PAL, MODE_TRANSMIT);
-}
-
-
-/* Bus reset handler. In the event of a bus reset, we may need to
- re-start the DMA contexts - otherwise the user program would
- end up waiting forever.
-*/
-
-static void dv1394_host_reset(struct hpsb_host *host)
-{
- struct video_card *video = NULL, *tmp_vid;
- unsigned long flags;
-
- /* We only work with the OHCI-1394 driver */
- if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
- return;
-
- /* find the corresponding video_cards */
- spin_lock_irqsave(&dv1394_cards_lock, flags);
- list_for_each_entry(tmp_vid, &dv1394_cards, list) {
- if ((tmp_vid->id >> 2) == host->id) {
- video = tmp_vid;
- break;
- }
- }
- spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
- if (!video)
- return;
-
-
- spin_lock_irqsave(&video->spinlock, flags);
-
- if (!video->dma_running)
- goto out;
-
- /* check IT context */
- if (video->ohci_it_ctx != -1) {
- u32 ctx;
-
- ctx = reg_read(video->ohci, video->ohci_IsoXmitContextControlSet);
-
- /* if (RUN but not ACTIVE) */
- if ( (ctx & (1<<15)) &&
- !(ctx & (1<<10)) ) {
-
- debug_printk("dv1394: IT context stopped due to bus reset; waking it up\n");
-
- /* to be safe, assume a frame has been dropped. User-space programs
- should handle this condition like an underflow. */
- video->dropped_frames++;
-
- /* for some reason you must clear, then re-set the RUN bit to restart DMA */
-
- /* clear RUN */
- reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15));
- flush_pci_write(video->ohci);
-
- /* set RUN */
- reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 15));
- flush_pci_write(video->ohci);
-
- /* set the WAKE bit (just in case; this isn't strictly necessary) */
- reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 12));
- flush_pci_write(video->ohci);
-
- irq_printk("dv1394: AFTER IT restart ctx 0x%08x ptr 0x%08x\n",
- reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
- reg_read(video->ohci, video->ohci_IsoXmitCommandPtr));
- }
- }
-
- /* check IR context */
- if (video->ohci_ir_ctx != -1) {
- u32 ctx;
-
- ctx = reg_read(video->ohci, video->ohci_IsoRcvContextControlSet);
-
- /* if (RUN but not ACTIVE) */
- if ( (ctx & (1<<15)) &&
- !(ctx & (1<<10)) ) {
-
- debug_printk("dv1394: IR context stopped due to bus reset; waking it up\n");
-
- /* to be safe, assume a frame has been dropped. User-space programs
- should handle this condition like an overflow. */
- video->dropped_frames++;
-
- /* for some reason you must clear, then re-set the RUN bit to restart DMA */
- /* XXX this doesn't work for me, I can't get IR DMA to restart :[ */
-
- /* clear RUN */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15));
- flush_pci_write(video->ohci);
-
- /* set RUN */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 15));
- flush_pci_write(video->ohci);
-
- /* set the WAKE bit (just in case; this isn't strictly necessary) */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
- flush_pci_write(video->ohci);
-
- irq_printk("dv1394: AFTER IR restart ctx 0x%08x ptr 0x%08x\n",
- reg_read(video->ohci, video->ohci_IsoRcvContextControlSet),
- reg_read(video->ohci, video->ohci_IsoRcvCommandPtr));
- }
- }
-
-out:
- spin_unlock_irqrestore(&video->spinlock, flags);
-
- /* wake readers/writers/ioctl'ers */
- wake_up_interruptible(&video->waitq);
-}
-
-static struct hpsb_highlevel dv1394_highlevel = {
- .name = "dv1394",
- .add_host = dv1394_add_host,
- .remove_host = dv1394_remove_host,
- .host_reset = dv1394_host_reset,
-};
-
-#ifdef CONFIG_COMPAT
-
-#define DV1394_IOC32_INIT _IOW('#', 0x06, struct dv1394_init32)
-#define DV1394_IOC32_GET_STATUS _IOR('#', 0x0c, struct dv1394_status32)
-
-struct dv1394_init32 {
- u32 api_version;
- u32 channel;
- u32 n_frames;
- u32 format;
- u32 cip_n;
- u32 cip_d;
- u32 syt_offset;
-};
-
-struct dv1394_status32 {
- struct dv1394_init32 init;
- s32 active_frame;
- u32 first_clear_frame;
- u32 n_clear_frames;
- u32 dropped_frames;
-};
-
-/* RED-PEN: this should use compat_alloc_userspace instead */
-
-static int handle_dv1394_init(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct dv1394_init32 dv32;
- struct dv1394_init dv;
- mm_segment_t old_fs;
- int ret;
-
- if (file->f_op->unlocked_ioctl != dv1394_ioctl)
- return -EFAULT;
-
- if (copy_from_user(&dv32, (void __user *)arg, sizeof(dv32)))
- return -EFAULT;
-
- dv.api_version = dv32.api_version;
- dv.channel = dv32.channel;
- dv.n_frames = dv32.n_frames;
- dv.format = dv32.format;
- dv.cip_n = (unsigned long)dv32.cip_n;
- dv.cip_d = (unsigned long)dv32.cip_d;
- dv.syt_offset = dv32.syt_offset;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- ret = dv1394_ioctl(file, DV1394_IOC_INIT, (unsigned long)&dv);
- set_fs(old_fs);
-
- return ret;
-}
-
-static int handle_dv1394_get_status(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct dv1394_status32 dv32;
- struct dv1394_status dv;
- mm_segment_t old_fs;
- int ret;
-
- if (file->f_op->unlocked_ioctl != dv1394_ioctl)
- return -EFAULT;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- ret = dv1394_ioctl(file, DV1394_IOC_GET_STATUS, (unsigned long)&dv);
- set_fs(old_fs);
-
- if (!ret) {
- dv32.init.api_version = dv.init.api_version;
- dv32.init.channel = dv.init.channel;
- dv32.init.n_frames = dv.init.n_frames;
- dv32.init.format = dv.init.format;
- dv32.init.cip_n = (u32)dv.init.cip_n;
- dv32.init.cip_d = (u32)dv.init.cip_d;
- dv32.init.syt_offset = dv.init.syt_offset;
- dv32.active_frame = dv.active_frame;
- dv32.first_clear_frame = dv.first_clear_frame;
- dv32.n_clear_frames = dv.n_clear_frames;
- dv32.dropped_frames = dv.dropped_frames;
-
- if (copy_to_user((struct dv1394_status32 __user *)arg, &dv32, sizeof(dv32)))
- ret = -EFAULT;
- }
-
- return ret;
-}
-
-
-
-static long dv1394_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- switch (cmd) {
- case DV1394_IOC_SHUTDOWN:
- case DV1394_IOC_SUBMIT_FRAMES:
- case DV1394_IOC_WAIT_FRAMES:
- case DV1394_IOC_RECEIVE_FRAMES:
- case DV1394_IOC_START_RECEIVE:
- return dv1394_ioctl(file, cmd, arg);
-
- case DV1394_IOC32_INIT:
- return handle_dv1394_init(file, cmd, arg);
- case DV1394_IOC32_GET_STATUS:
- return handle_dv1394_get_status(file, cmd, arg);
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-#endif /* CONFIG_COMPAT */
-
-
-/*** KERNEL MODULE HANDLERS ************************************************/
-
-MODULE_AUTHOR("Dan Maas <dmaas@dcine.com>, Dan Dennedy <dan@dennedy.org>");
-MODULE_DESCRIPTION("driver for DV input/output on OHCI board");
-MODULE_SUPPORTED_DEVICE("dv1394");
-MODULE_LICENSE("GPL");
-
-static void __exit dv1394_exit_module(void)
-{
- hpsb_unregister_protocol(&dv1394_driver);
- hpsb_unregister_highlevel(&dv1394_highlevel);
- cdev_del(&dv1394_cdev);
-}
-
-static int __init dv1394_init_module(void)
-{
- int ret;
-
- cdev_init(&dv1394_cdev, &dv1394_fops);
- dv1394_cdev.owner = THIS_MODULE;
- ret = cdev_add(&dv1394_cdev, IEEE1394_DV1394_DEV, 16);
- if (ret) {
- printk(KERN_ERR "dv1394: unable to register character device\n");
- return ret;
- }
-
- hpsb_register_highlevel(&dv1394_highlevel);
-
- ret = hpsb_register_protocol(&dv1394_driver);
- if (ret) {
- printk(KERN_ERR "dv1394: failed to register protocol\n");
- hpsb_unregister_highlevel(&dv1394_highlevel);
- cdev_del(&dv1394_cdev);
- return ret;
- }
-
- return 0;
-}
-
-module_init(dv1394_init_module);
-module_exit(dv1394_exit_module);
diff --git a/drivers/ieee1394/dv1394.h b/drivers/ieee1394/dv1394.h
deleted file mode 100644
index 5807f5289810..000000000000
--- a/drivers/ieee1394/dv1394.h
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * dv1394.h - DV input/output over IEEE 1394 on OHCI chips
- * Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
- * receive by Dan Dennedy <dan@dennedy.org>
- *
- * based on:
- * video1394.h - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- * Peter Schlaile <udbz@rz.uni-karlsruhe.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This 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 _DV_1394_H
-#define _DV_1394_H
-
-/* This is the public user-space interface. Try not to break it. */
-
-#define DV1394_API_VERSION 0x20011127
-
-/* ********************
- ** **
- ** DV1394 API **
- ** **
- ********************
-
- There are two methods of operating the DV1394 DV output device.
-
- 1)
-
- The simplest is an interface based on write(): simply write
- full DV frames of data to the device, and they will be transmitted
- as quickly as possible. The FD may be set for non-blocking I/O,
- in which case you can use select() or poll() to wait for output
- buffer space.
-
- To set the DV output parameters (e.g. whether you want NTSC or PAL
- video), use the DV1394_INIT ioctl, passing in the parameters you
- want in a struct dv1394_init.
-
- Example 1:
- To play a raw .DV file: cat foo.DV > /dev/dv1394
- (cat will use write() internally)
-
- Example 2:
- static struct dv1394_init init = {
- 0x63, (broadcast channel)
- 4, (four-frame ringbuffer)
- DV1394_NTSC, (send NTSC video)
- 0, 0 (default empty packet rate)
- }
-
- ioctl(fd, DV1394_INIT, &init);
-
- while (1) {
- read( <a raw DV file>, buf, DV1394_NTSC_FRAME_SIZE );
- write( <the dv1394 FD>, buf, DV1394_NTSC_FRAME_SIZE );
- }
-
- 2)
-
- For more control over buffering, and to avoid unnecessary copies
- of the DV data, you can use the more sophisticated the mmap() interface.
- First, call the DV1394_INIT ioctl to specify your parameters,
- including the number of frames in the ringbuffer. Then, calling mmap()
- on the dv1394 device will give you direct access to the ringbuffer
- from which the DV card reads your frame data.
-
- The ringbuffer is simply one large, contiguous region of memory
- containing two or more frames of packed DV data. Each frame of DV data
- is 120000 bytes (NTSC) or 144000 bytes (PAL).
-
- Fill one or more frames in the ringbuffer, then use the DV1394_SUBMIT_FRAMES
- ioctl to begin I/O. You can use either the DV1394_WAIT_FRAMES ioctl
- or select()/poll() to wait until the frames are transmitted. Next, you'll
- need to call the DV1394_GET_STATUS ioctl to determine which ringbuffer
- frames are clear (ready to be filled with new DV data). Finally, use
- DV1394_SUBMIT_FRAMES again to send the new data to the DV output.
-
-
- Example: here is what a four-frame ringbuffer might look like
- during DV transmission:
-
-
- frame 0 frame 1 frame 2 frame 3
-
- *--------------------------------------*
- | CLEAR | DV data | DV data | CLEAR |
- *--------------------------------------*
- <ACTIVE>
-
- transmission goes in this direction --->>>
-
-
- The DV hardware is currently transmitting the data in frame 1.
- Once frame 1 is finished, it will automatically transmit frame 2.
- (if frame 2 finishes before frame 3 is submitted, the device
- will continue to transmit frame 2, and will increase the dropped_frames
- counter each time it repeats the transmission).
-
-
- If you called DV1394_GET_STATUS at this instant, you would
- receive the following values:
-
- n_frames = 4
- active_frame = 1
- first_clear_frame = 3
- n_clear_frames = 2
-
- At this point, you should write new DV data into frame 3 and optionally
- frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that
- it may transmit the new frames.
-
- ERROR HANDLING
-
- An error (buffer underflow/overflow or a break in the DV stream due
- to a 1394 bus reset) can be detected by checking the dropped_frames
- field of struct dv1394_status (obtained through the
- DV1394_GET_STATUS ioctl).
-
- The best way to recover from such an error is to re-initialize
- dv1394, either by using the DV1394_INIT ioctl call, or closing the
- file descriptor and opening it again. (note that you must unmap all
- ringbuffer mappings when closing the file descriptor, or else
- dv1394 will still be considered 'in use').
-
- MAIN LOOP
-
- For maximum efficiency and robustness against bus errors, you are
- advised to model the main loop of your application after the
- following pseudo-code example:
-
- (checks of system call return values omitted for brevity; always
- check return values in your code!)
-
- while ( frames left ) {
-
- struct pollfd *pfd = ...;
-
- pfd->fd = dv1394_fd;
- pfd->revents = 0;
- pfd->events = POLLOUT | POLLIN; (OUT for transmit, IN for receive)
-
- (add other sources of I/O here)
-
- poll(pfd, 1, -1); (or select(); add a timeout if you want)
-
- if (pfd->revents) {
- struct dv1394_status status;
-
- ioctl(dv1394_fd, DV1394_GET_STATUS, &status);
-
- if (status.dropped_frames > 0) {
- reset_dv1394();
- } else {
- for (int i = 0; i < status.n_clear_frames; i++) {
- copy_DV_frame();
- }
- }
- }
- }
-
- where copy_DV_frame() reads or writes on the dv1394 file descriptor
- (read/write mode) or copies data to/from the mmap ringbuffer and
- then calls ioctl(DV1394_SUBMIT_FRAMES) to notify dv1394 that new
- frames are availble (mmap mode).
-
- reset_dv1394() is called in the event of a buffer
- underflow/overflow or a halt in the DV stream (e.g. due to a 1394
- bus reset). To guarantee recovery from the error, this function
- should close the dv1394 file descriptor (and munmap() all
- ringbuffer mappings, if you are using them), then re-open the
- dv1394 device (and re-map the ringbuffer).
-
-*/
-
-
-/* maximum number of frames in the ringbuffer */
-#define DV1394_MAX_FRAMES 32
-
-/* number of *full* isochronous packets per DV frame */
-#define DV1394_NTSC_PACKETS_PER_FRAME 250
-#define DV1394_PAL_PACKETS_PER_FRAME 300
-
-/* size of one frame's worth of DV data, in bytes */
-#define DV1394_NTSC_FRAME_SIZE (480 * DV1394_NTSC_PACKETS_PER_FRAME)
-#define DV1394_PAL_FRAME_SIZE (480 * DV1394_PAL_PACKETS_PER_FRAME)
-
-
-/* ioctl() commands */
-#include "ieee1394-ioctl.h"
-
-
-enum pal_or_ntsc {
- DV1394_NTSC = 0,
- DV1394_PAL
-};
-
-
-
-
-/* this is the argument to DV1394_INIT */
-struct dv1394_init {
- /* DV1394_API_VERSION */
- unsigned int api_version;
-
- /* isochronous transmission channel to use */
- unsigned int channel;
-
- /* number of frames in the ringbuffer. Must be at least 2
- and at most DV1394_MAX_FRAMES. */
- unsigned int n_frames;
-
- /* send/receive PAL or NTSC video format */
- enum pal_or_ntsc format;
-
- /* the following are used only for transmission */
-
- /* set these to zero unless you want a
- non-default empty packet rate (see below) */
- unsigned long cip_n;
- unsigned long cip_d;
-
- /* set this to zero unless you want a
- non-default SYT cycle offset (default = 3 cycles) */
- unsigned int syt_offset;
-};
-
-/* NOTE: you may only allocate the DV frame ringbuffer once each time
- you open the dv1394 device. DV1394_INIT will fail if you call it a
- second time with different 'n_frames' or 'format' arguments (which
- would imply a different size for the ringbuffer). If you need a
- different buffer size, simply close and re-open the device, then
- initialize it with your new settings. */
-
-/* Q: What are cip_n and cip_d? */
-
-/*
- A: DV video streams do not utilize 100% of the potential bandwidth offered
- by IEEE 1394 (FireWire). To achieve the correct rate of data transmission,
- DV devices must periodically insert empty packets into the 1394 data stream.
- Typically there is one empty packet per 14-16 data-carrying packets.
-
- Some DV devices will accept a wide range of empty packet rates, while others
- require a precise rate. If the dv1394 driver produces empty packets at
- a rate that your device does not accept, you may see ugly patterns on the
- DV output, or even no output at all.
-
- The default empty packet insertion rate seems to work for many people; if
- your DV output is stable, you can simply ignore this discussion. However,
- we have exposed the empty packet rate as a parameter to support devices that
- do not work with the default rate.
-
- The decision to insert an empty packet is made with a numerator/denominator
- algorithm. Empty packets are produced at an average rate of CIP_N / CIP_D.
- You can alter the empty packet rate by passing non-zero values for cip_n
- and cip_d to the INIT ioctl.
-
- */
-
-
-
-struct dv1394_status {
- /* this embedded init struct returns the current dv1394
- parameters in use */
- struct dv1394_init init;
-
- /* the ringbuffer frame that is currently being
- displayed. (-1 if the device is not transmitting anything) */
- int active_frame;
-
- /* index of the first buffer (ahead of active_frame) that
- is ready to be filled with data */
- unsigned int first_clear_frame;
-
- /* how many buffers, including first_clear_buffer, are
- ready to be filled with data */
- unsigned int n_clear_frames;
-
- /* how many times the DV stream has underflowed, overflowed,
- or otherwise encountered an error, since the previous call
- to DV1394_GET_STATUS */
- unsigned int dropped_frames;
-
- /* N.B. The dropped_frames counter is only a lower bound on the actual
- number of dropped frames, with the special case that if dropped_frames
- is zero, then it is guaranteed that NO frames have been dropped
- since the last call to DV1394_GET_STATUS.
- */
-};
-
-
-#endif /* _DV_1394_H */
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
deleted file mode 100644
index bc289e367e30..000000000000
--- a/drivers/ieee1394/eth1394.c
+++ /dev/null
@@ -1,1736 +0,0 @@
-/*
- * eth1394.c -- IPv4 driver for Linux IEEE-1394 Subsystem
- *
- * Copyright (C) 2001-2003 Ben Collins <bcollins@debian.org>
- * 2000 Bonin Franck <boninf@free.fr>
- * 2003 Steve Kinneberg <kinnebergsteve@acmsystems.com>
- *
- * Mainly based on work by Emanuel Pirker and Andreas E. Bombe
- *
- * 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.
- */
-
-/*
- * This driver intends to support RFC 2734, which describes a method for
- * transporting IPv4 datagrams over IEEE-1394 serial busses.
- *
- * TODO:
- * RFC 2734 related:
- * - Add MCAP. Limited Multicast exists only to 224.0.0.1 and 224.0.0.2.
- *
- * Non-RFC 2734 related:
- * - Handle fragmented skb's coming from the networking layer.
- * - Move generic GASP reception to core 1394 code
- * - Convert kmalloc/kfree for link fragments to use kmem_cache_* instead
- * - Stability improvements
- * - Performance enhancements
- * - Consider garbage collecting old partial datagrams after X amount of time
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/workqueue.h>
-
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/if_arp.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/in.h>
-#include <linux/tcp.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-#include <linux/ethtool.h>
-#include <asm/uaccess.h>
-#include <asm/delay.h>
-#include <asm/unaligned.h>
-#include <net/arp.h>
-
-#include "config_roms.h"
-#include "csr1212.h"
-#include "eth1394.h"
-#include "highlevel.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-#include "iso.h"
-#include "nodemgr.h"
-
-#define ETH1394_PRINT_G(level, fmt, args...) \
- printk(level "%s: " fmt, driver_name, ## args)
-
-#define ETH1394_PRINT(level, dev_name, fmt, args...) \
- printk(level "%s: %s: " fmt, driver_name, dev_name, ## args)
-
-struct fragment_info {
- struct list_head list;
- int offset;
- int len;
-};
-
-struct partial_datagram {
- struct list_head list;
- u16 dgl;
- u16 dg_size;
- __be16 ether_type;
- struct sk_buff *skb;
- char *pbuf;
- struct list_head frag_info;
-};
-
-struct pdg_list {
- struct list_head list; /* partial datagram list per node */
- unsigned int sz; /* partial datagram list size per node */
- spinlock_t lock; /* partial datagram lock */
-};
-
-struct eth1394_host_info {
- struct hpsb_host *host;
- struct net_device *dev;
-};
-
-struct eth1394_node_ref {
- struct unit_directory *ud;
- struct list_head list;
-};
-
-struct eth1394_node_info {
- u16 maxpayload; /* max payload */
- u8 sspd; /* max speed */
- u64 fifo; /* FIFO address */
- struct pdg_list pdg; /* partial RX datagram lists */
- int dgl; /* outgoing datagram label */
-};
-
-static const char driver_name[] = "eth1394";
-
-static struct kmem_cache *packet_task_cache;
-
-static struct hpsb_highlevel eth1394_highlevel;
-
-/* Use common.lf to determine header len */
-static const int hdr_type_len[] = {
- sizeof(struct eth1394_uf_hdr),
- sizeof(struct eth1394_ff_hdr),
- sizeof(struct eth1394_sf_hdr),
- sizeof(struct eth1394_sf_hdr)
-};
-
-static const u16 eth1394_speedto_maxpayload[] = {
-/* S100, S200, S400, S800, S1600, S3200 */
- 512, 1024, 2048, 4096, 4096, 4096
-};
-
-MODULE_AUTHOR("Ben Collins (bcollins@debian.org)");
-MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)");
-MODULE_LICENSE("GPL");
-
-/*
- * The max_partial_datagrams parameter is the maximum number of fragmented
- * datagrams per node that eth1394 will keep in memory. Providing an upper
- * bound allows us to limit the amount of memory that partial datagrams
- * consume in the event that some partial datagrams are never completed.
- */
-static int max_partial_datagrams = 25;
-module_param(max_partial_datagrams, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(max_partial_datagrams,
- "Maximum number of partially received fragmented datagrams "
- "(default = 25).");
-
-
-static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, const void *daddr,
- const void *saddr, unsigned len);
-static int ether1394_rebuild_header(struct sk_buff *skb);
-static int ether1394_header_parse(const struct sk_buff *skb,
- unsigned char *haddr);
-static int ether1394_header_cache(const struct neighbour *neigh,
- struct hh_cache *hh);
-static void ether1394_header_cache_update(struct hh_cache *hh,
- const struct net_device *dev,
- const unsigned char *haddr);
-static netdev_tx_t ether1394_tx(struct sk_buff *skb,
- struct net_device *dev);
-static void ether1394_iso(struct hpsb_iso *iso);
-
-static const struct ethtool_ops ethtool_ops;
-
-static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
- quadlet_t *data, u64 addr, size_t len, u16 flags);
-static void ether1394_add_host(struct hpsb_host *host);
-static void ether1394_remove_host(struct hpsb_host *host);
-static void ether1394_host_reset(struct hpsb_host *host);
-
-/* Function for incoming 1394 packets */
-static const struct hpsb_address_ops addr_ops = {
- .write = ether1394_write,
-};
-
-/* Ieee1394 highlevel driver functions */
-static struct hpsb_highlevel eth1394_highlevel = {
- .name = driver_name,
- .add_host = ether1394_add_host,
- .remove_host = ether1394_remove_host,
- .host_reset = ether1394_host_reset,
-};
-
-static int ether1394_recv_init(struct eth1394_priv *priv)
-{
- unsigned int iso_buf_size;
-
- /* FIXME: rawiso limits us to PAGE_SIZE */
- iso_buf_size = min((unsigned int)PAGE_SIZE,
- 2 * (1U << (priv->host->csr.max_rec + 1)));
-
- priv->iso = hpsb_iso_recv_init(priv->host,
- ETHER1394_GASP_BUFFERS * iso_buf_size,
- ETHER1394_GASP_BUFFERS,
- priv->broadcast_channel,
- HPSB_ISO_DMA_PACKET_PER_BUFFER,
- 1, ether1394_iso);
- if (priv->iso == NULL) {
- ETH1394_PRINT_G(KERN_ERR, "Failed to allocate IR context\n");
- priv->bc_state = ETHER1394_BC_ERROR;
- return -EAGAIN;
- }
-
- if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0)
- priv->bc_state = ETHER1394_BC_STOPPED;
- else
- priv->bc_state = ETHER1394_BC_RUNNING;
- return 0;
-}
-
-/* This is called after an "ifup" */
-static int ether1394_open(struct net_device *dev)
-{
- struct eth1394_priv *priv = netdev_priv(dev);
- int ret;
-
- if (priv->bc_state == ETHER1394_BC_ERROR) {
- ret = ether1394_recv_init(priv);
- if (ret)
- return ret;
- }
- netif_start_queue(dev);
- return 0;
-}
-
-/* This is called after an "ifdown" */
-static int ether1394_stop(struct net_device *dev)
-{
- /* flush priv->wake */
- flush_scheduled_work();
-
- netif_stop_queue(dev);
- return 0;
-}
-
-/* FIXME: What to do if we timeout? I think a host reset is probably in order,
- * so that's what we do. Should we increment the stat counters too? */
-static void ether1394_tx_timeout(struct net_device *dev)
-{
- struct hpsb_host *host =
- ((struct eth1394_priv *)netdev_priv(dev))->host;
-
- ETH1394_PRINT(KERN_ERR, dev->name, "Timeout, resetting host\n");
- ether1394_host_reset(host);
-}
-
-static inline int ether1394_max_mtu(struct hpsb_host* host)
-{
- return (1 << (host->csr.max_rec + 1))
- - sizeof(union eth1394_hdr) - ETHER1394_GASP_OVERHEAD;
-}
-
-static int ether1394_change_mtu(struct net_device *dev, int new_mtu)
-{
- int max_mtu;
-
- if (new_mtu < 68)
- return -EINVAL;
-
- max_mtu = ether1394_max_mtu(
- ((struct eth1394_priv *)netdev_priv(dev))->host);
- if (new_mtu > max_mtu) {
- ETH1394_PRINT(KERN_INFO, dev->name,
- "Local node constrains MTU to %d\n", max_mtu);
- return -ERANGE;
- }
-
- dev->mtu = new_mtu;
- return 0;
-}
-
-static void purge_partial_datagram(struct list_head *old)
-{
- struct partial_datagram *pd;
- struct list_head *lh, *n;
- struct fragment_info *fi;
-
- pd = list_entry(old, struct partial_datagram, list);
-
- list_for_each_safe(lh, n, &pd->frag_info) {
- fi = list_entry(lh, struct fragment_info, list);
- list_del(lh);
- kfree(fi);
- }
- list_del(old);
- kfree_skb(pd->skb);
- kfree(pd);
-}
-
-/******************************************
- * 1394 bus activity functions
- ******************************************/
-
-static struct eth1394_node_ref *eth1394_find_node(struct list_head *inl,
- struct unit_directory *ud)
-{
- struct eth1394_node_ref *node;
-
- list_for_each_entry(node, inl, list)
- if (node->ud == ud)
- return node;
-
- return NULL;
-}
-
-static struct eth1394_node_ref *eth1394_find_node_guid(struct list_head *inl,
- u64 guid)
-{
- struct eth1394_node_ref *node;
-
- list_for_each_entry(node, inl, list)
- if (node->ud->ne->guid == guid)
- return node;
-
- return NULL;
-}
-
-static struct eth1394_node_ref *eth1394_find_node_nodeid(struct list_head *inl,
- nodeid_t nodeid)
-{
- struct eth1394_node_ref *node;
-
- list_for_each_entry(node, inl, list)
- if (node->ud->ne->nodeid == nodeid)
- return node;
-
- return NULL;
-}
-
-static int eth1394_new_node(struct eth1394_host_info *hi,
- struct unit_directory *ud)
-{
- struct eth1394_priv *priv;
- struct eth1394_node_ref *new_node;
- struct eth1394_node_info *node_info;
-
- new_node = kmalloc(sizeof(*new_node), GFP_KERNEL);
- if (!new_node)
- return -ENOMEM;
-
- node_info = kmalloc(sizeof(*node_info), GFP_KERNEL);
- if (!node_info) {
- kfree(new_node);
- return -ENOMEM;
- }
-
- spin_lock_init(&node_info->pdg.lock);
- INIT_LIST_HEAD(&node_info->pdg.list);
- node_info->pdg.sz = 0;
- node_info->fifo = CSR1212_INVALID_ADDR_SPACE;
-
- dev_set_drvdata(&ud->device, node_info);
- new_node->ud = ud;
-
- priv = netdev_priv(hi->dev);
- list_add_tail(&new_node->list, &priv->ip_node_list);
- return 0;
-}
-
-static int eth1394_probe(struct device *dev)
-{
- struct unit_directory *ud;
- struct eth1394_host_info *hi;
-
- ud = container_of(dev, struct unit_directory, device);
- hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
- if (!hi)
- return -ENOENT;
-
- return eth1394_new_node(hi, ud);
-}
-
-static int eth1394_remove(struct device *dev)
-{
- struct unit_directory *ud;
- struct eth1394_host_info *hi;
- struct eth1394_priv *priv;
- struct eth1394_node_ref *old_node;
- struct eth1394_node_info *node_info;
- struct list_head *lh, *n;
- unsigned long flags;
-
- ud = container_of(dev, struct unit_directory, device);
- hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
- if (!hi)
- return -ENOENT;
-
- priv = netdev_priv(hi->dev);
-
- old_node = eth1394_find_node(&priv->ip_node_list, ud);
- if (!old_node)
- return 0;
-
- list_del(&old_node->list);
- kfree(old_node);
-
- node_info = dev_get_drvdata(&ud->device);
-
- spin_lock_irqsave(&node_info->pdg.lock, flags);
- /* The partial datagram list should be empty, but we'll just
- * make sure anyway... */
- list_for_each_safe(lh, n, &node_info->pdg.list)
- purge_partial_datagram(lh);
- spin_unlock_irqrestore(&node_info->pdg.lock, flags);
-
- kfree(node_info);
- dev_set_drvdata(&ud->device, NULL);
- return 0;
-}
-
-static int eth1394_update(struct unit_directory *ud)
-{
- struct eth1394_host_info *hi;
- struct eth1394_priv *priv;
- struct eth1394_node_ref *node;
-
- hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
- if (!hi)
- return -ENOENT;
-
- priv = netdev_priv(hi->dev);
- node = eth1394_find_node(&priv->ip_node_list, ud);
- if (node)
- return 0;
-
- return eth1394_new_node(hi, ud);
-}
-
-static const struct ieee1394_device_id eth1394_id_table[] = {
- {
- .match_flags = (IEEE1394_MATCH_SPECIFIER_ID |
- IEEE1394_MATCH_VERSION),
- .specifier_id = ETHER1394_GASP_SPECIFIER_ID,
- .version = ETHER1394_GASP_VERSION,
- },
- {}
-};
-
-MODULE_DEVICE_TABLE(ieee1394, eth1394_id_table);
-
-static struct hpsb_protocol_driver eth1394_proto_driver = {
- .name = driver_name,
- .id_table = eth1394_id_table,
- .update = eth1394_update,
- .driver = {
- .probe = eth1394_probe,
- .remove = eth1394_remove,
- },
-};
-
-static void ether1394_reset_priv(struct net_device *dev, int set_mtu)
-{
- unsigned long flags;
- int i;
- struct eth1394_priv *priv = netdev_priv(dev);
- struct hpsb_host *host = priv->host;
- u64 guid = get_unaligned((u64 *)&(host->csr.rom->bus_info_data[3]));
- int max_speed = IEEE1394_SPEED_MAX;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- memset(priv->ud_list, 0, sizeof(priv->ud_list));
- priv->bc_maxpayload = 512;
-
- /* Determine speed limit */
- /* FIXME: This is broken for nodes with link speed < PHY speed,
- * and it is suboptimal for S200B...S800B hardware.
- * The result of nodemgr's speed probe should be used somehow. */
- for (i = 0; i < host->node_count; i++) {
- /* take care of S100B...S400B PHY ports */
- if (host->speed[i] == SELFID_SPEED_UNKNOWN) {
- max_speed = IEEE1394_SPEED_100;
- break;
- }
- if (max_speed > host->speed[i])
- max_speed = host->speed[i];
- }
- priv->bc_sspd = max_speed;
-
- if (set_mtu) {
- /* Use the RFC 2734 default 1500 octets or the maximum payload
- * as initial MTU */
- dev->mtu = min(1500, ether1394_max_mtu(host));
-
- /* Set our hardware address while we're at it */
- memcpy(dev->dev_addr, &guid, sizeof(u64));
- memset(dev->broadcast, 0xff, sizeof(u64));
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static const struct header_ops ether1394_header_ops = {
- .create = ether1394_header,
- .rebuild = ether1394_rebuild_header,
- .cache = ether1394_header_cache,
- .cache_update = ether1394_header_cache_update,
- .parse = ether1394_header_parse,
-};
-
-static const struct net_device_ops ether1394_netdev_ops = {
- .ndo_open = ether1394_open,
- .ndo_stop = ether1394_stop,
- .ndo_start_xmit = ether1394_tx,
- .ndo_tx_timeout = ether1394_tx_timeout,
- .ndo_change_mtu = ether1394_change_mtu,
-};
-
-static void ether1394_init_dev(struct net_device *dev)
-{
-
- dev->header_ops = &ether1394_header_ops;
- dev->netdev_ops = &ether1394_netdev_ops;
-
- SET_ETHTOOL_OPS(dev, &ethtool_ops);
-
- dev->watchdog_timeo = ETHER1394_TIMEOUT;
- dev->flags = IFF_BROADCAST | IFF_MULTICAST;
- dev->features = NETIF_F_HIGHDMA;
- dev->addr_len = ETH1394_ALEN;
- dev->hard_header_len = ETH1394_HLEN;
- dev->type = ARPHRD_IEEE1394;
-
- /* FIXME: This value was copied from ether_setup(). Is it too much? */
- dev->tx_queue_len = 1000;
-}
-
-/*
- * Wake the queue up after commonly encountered transmit failure conditions are
- * hopefully over. Currently only tlabel exhaustion is accounted for.
- */
-static void ether1394_wake_queue(struct work_struct *work)
-{
- struct eth1394_priv *priv;
- struct hpsb_packet *packet;
-
- priv = container_of(work, struct eth1394_priv, wake);
- packet = hpsb_alloc_packet(0);
-
- /* This is really bad, but unjam the queue anyway. */
- if (!packet)
- goto out;
-
- packet->host = priv->host;
- packet->node_id = priv->wake_node;
- /*
- * A transaction label is all we really want. If we get one, it almost
- * always means we can get a lot more because the ieee1394 core recycled
- * a whole batch of tlabels, at last.
- */
- if (hpsb_get_tlabel(packet) == 0)
- hpsb_free_tlabel(packet);
-
- hpsb_free_packet(packet);
-out:
- netif_wake_queue(priv->wake_dev);
-}
-
-/*
- * This function is called every time a card is found. It is generally called
- * when the module is installed. This is where we add all of our ethernet
- * devices. One for each host.
- */
-static void ether1394_add_host(struct hpsb_host *host)
-{
- struct eth1394_host_info *hi = NULL;
- struct net_device *dev = NULL;
- struct eth1394_priv *priv;
- u64 fifo_addr;
-
- if (hpsb_config_rom_ip1394_add(host) != 0) {
- ETH1394_PRINT_G(KERN_ERR, "Can't add IP-over-1394 ROM entry\n");
- return;
- }
-
- fifo_addr = hpsb_allocate_and_register_addrspace(
- &eth1394_highlevel, host, &addr_ops,
- ETHER1394_REGION_ADDR_LEN, ETHER1394_REGION_ADDR_LEN,
- CSR1212_INVALID_ADDR_SPACE, CSR1212_INVALID_ADDR_SPACE);
- if (fifo_addr == CSR1212_INVALID_ADDR_SPACE) {
- ETH1394_PRINT_G(KERN_ERR, "Cannot register CSR space\n");
- hpsb_config_rom_ip1394_remove(host);
- return;
- }
-
- dev = alloc_netdev(sizeof(*priv), "eth%d", ether1394_init_dev);
- if (dev == NULL) {
- ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
- goto out;
- }
-
- SET_NETDEV_DEV(dev, &host->device);
-
- priv = netdev_priv(dev);
- INIT_LIST_HEAD(&priv->ip_node_list);
- spin_lock_init(&priv->lock);
- priv->host = host;
- priv->local_fifo = fifo_addr;
- INIT_WORK(&priv->wake, ether1394_wake_queue);
- priv->wake_dev = dev;
-
- hi = hpsb_create_hostinfo(&eth1394_highlevel, host, sizeof(*hi));
- if (hi == NULL) {
- ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
- goto out;
- }
-
- ether1394_reset_priv(dev, 1);
-
- if (register_netdev(dev)) {
- ETH1394_PRINT_G(KERN_ERR, "Cannot register the driver\n");
- goto out;
- }
-
- ETH1394_PRINT(KERN_INFO, dev->name, "IPv4 over IEEE 1394 (fw-host%d)\n",
- host->id);
-
- hi->host = host;
- hi->dev = dev;
-
- /* Ignore validity in hopes that it will be set in the future. It'll
- * be checked when the eth device is opened. */
- priv->broadcast_channel = host->csr.broadcast_channel & 0x3f;
-
- ether1394_recv_init(priv);
- return;
-out:
- if (dev)
- free_netdev(dev);
- if (hi)
- hpsb_destroy_hostinfo(&eth1394_highlevel, host);
- hpsb_unregister_addrspace(&eth1394_highlevel, host, fifo_addr);
- hpsb_config_rom_ip1394_remove(host);
-}
-
-/* Remove a card from our list */
-static void ether1394_remove_host(struct hpsb_host *host)
-{
- struct eth1394_host_info *hi;
- struct eth1394_priv *priv;
-
- hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
- if (!hi)
- return;
- priv = netdev_priv(hi->dev);
- hpsb_unregister_addrspace(&eth1394_highlevel, host, priv->local_fifo);
- hpsb_config_rom_ip1394_remove(host);
- if (priv->iso)
- hpsb_iso_shutdown(priv->iso);
- unregister_netdev(hi->dev);
- free_netdev(hi->dev);
-}
-
-/* A bus reset happened */
-static void ether1394_host_reset(struct hpsb_host *host)
-{
- struct eth1394_host_info *hi;
- struct eth1394_priv *priv;
- struct net_device *dev;
- struct list_head *lh, *n;
- struct eth1394_node_ref *node;
- struct eth1394_node_info *node_info;
- unsigned long flags;
-
- hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
-
- /* This can happen for hosts that we don't use */
- if (!hi)
- return;
-
- dev = hi->dev;
- priv = netdev_priv(dev);
-
- /* Reset our private host data, but not our MTU */
- netif_stop_queue(dev);
- ether1394_reset_priv(dev, 0);
-
- list_for_each_entry(node, &priv->ip_node_list, list) {
- node_info = dev_get_drvdata(&node->ud->device);
-
- spin_lock_irqsave(&node_info->pdg.lock, flags);
-
- list_for_each_safe(lh, n, &node_info->pdg.list)
- purge_partial_datagram(lh);
-
- INIT_LIST_HEAD(&(node_info->pdg.list));
- node_info->pdg.sz = 0;
-
- spin_unlock_irqrestore(&node_info->pdg.lock, flags);
- }
-
- netif_wake_queue(dev);
-}
-
-/******************************************
- * HW Header net device functions
- ******************************************/
-/* These functions have been adapted from net/ethernet/eth.c */
-
-/* Create a fake MAC header for an arbitrary protocol layer.
- * saddr=NULL means use device source address
- * daddr=NULL means leave destination address (eg unresolved arp). */
-static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, const void *daddr,
- const void *saddr, unsigned len)
-{
- struct eth1394hdr *eth =
- (struct eth1394hdr *)skb_push(skb, ETH1394_HLEN);
-
- eth->h_proto = htons(type);
-
- if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
- memset(eth->h_dest, 0, dev->addr_len);
- return dev->hard_header_len;
- }
-
- if (daddr) {
- memcpy(eth->h_dest, daddr, dev->addr_len);
- return dev->hard_header_len;
- }
-
- return -dev->hard_header_len;
-}
-
-/* Rebuild the faked MAC header. This is called after an ARP
- * (or in future other address resolution) has completed on this
- * sk_buff. We now let ARP fill in the other fields.
- *
- * This routine CANNOT use cached dst->neigh!
- * Really, it is used only when dst->neigh is wrong.
- */
-static int ether1394_rebuild_header(struct sk_buff *skb)
-{
- struct eth1394hdr *eth = (struct eth1394hdr *)skb->data;
-
- if (eth->h_proto == htons(ETH_P_IP))
- return arp_find((unsigned char *)&eth->h_dest, skb);
-
- ETH1394_PRINT(KERN_DEBUG, skb->dev->name,
- "unable to resolve type %04x addresses\n",
- ntohs(eth->h_proto));
- return 0;
-}
-
-static int ether1394_header_parse(const struct sk_buff *skb,
- unsigned char *haddr)
-{
- memcpy(haddr, skb->dev->dev_addr, ETH1394_ALEN);
- return ETH1394_ALEN;
-}
-
-static int ether1394_header_cache(const struct neighbour *neigh,
- struct hh_cache *hh)
-{
- __be16 type = hh->hh_type;
- struct net_device *dev = neigh->dev;
- struct eth1394hdr *eth =
- (struct eth1394hdr *)((u8 *)hh->hh_data + 16 - ETH1394_HLEN);
-
- if (type == htons(ETH_P_802_3))
- return -1;
-
- eth->h_proto = type;
- memcpy(eth->h_dest, neigh->ha, dev->addr_len);
-
- hh->hh_len = ETH1394_HLEN;
- return 0;
-}
-
-/* Called by Address Resolution module to notify changes in address. */
-static void ether1394_header_cache_update(struct hh_cache *hh,
- const struct net_device *dev,
- const unsigned char * haddr)
-{
- memcpy((u8 *)hh->hh_data + 16 - ETH1394_HLEN, haddr, dev->addr_len);
-}
-
-/******************************************
- * Datagram reception code
- ******************************************/
-
-/* Copied from net/ethernet/eth.c */
-static __be16 ether1394_type_trans(struct sk_buff *skb, struct net_device *dev)
-{
- struct eth1394hdr *eth;
- unsigned char *rawp;
-
- skb_reset_mac_header(skb);
- skb_pull(skb, ETH1394_HLEN);
- eth = eth1394_hdr(skb);
-
- if (*eth->h_dest & 1) {
- if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len) == 0)
- skb->pkt_type = PACKET_BROADCAST;
-#if 0
- else
- skb->pkt_type = PACKET_MULTICAST;
-#endif
- } else {
- if (memcmp(eth->h_dest, dev->dev_addr, dev->addr_len))
- skb->pkt_type = PACKET_OTHERHOST;
- }
-
- if (ntohs(eth->h_proto) >= 1536)
- return eth->h_proto;
-
- rawp = skb->data;
-
- if (*(unsigned short *)rawp == 0xFFFF)
- return htons(ETH_P_802_3);
-
- return htons(ETH_P_802_2);
-}
-
-/* Parse an encapsulated IP1394 header into an ethernet frame packet.
- * We also perform ARP translation here, if need be. */
-static __be16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev,
- nodeid_t srcid, nodeid_t destid,
- __be16 ether_type)
-{
- struct eth1394_priv *priv = netdev_priv(dev);
- __be64 dest_hw;
- __be16 ret = 0;
-
- /* Setup our hw addresses. We use these to build the ethernet header. */
- if (destid == (LOCAL_BUS | ALL_NODES))
- dest_hw = ~cpu_to_be64(0); /* broadcast */
- else
- dest_hw = cpu_to_be64((u64)priv->host->csr.guid_hi << 32 |
- priv->host->csr.guid_lo);
-
- /* If this is an ARP packet, convert it. First, we want to make
- * use of some of the fields, since they tell us a little bit
- * about the sending machine. */
- if (ether_type == htons(ETH_P_ARP)) {
- struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
- struct arphdr *arp = (struct arphdr *)skb->data;
- unsigned char *arp_ptr = (unsigned char *)(arp + 1);
- u64 fifo_addr = (u64)ntohs(arp1394->fifo_hi) << 32 |
- ntohl(arp1394->fifo_lo);
- u8 max_rec = min(priv->host->csr.max_rec,
- (u8)(arp1394->max_rec));
- int sspd = arp1394->sspd;
- u16 maxpayload;
- struct eth1394_node_ref *node;
- struct eth1394_node_info *node_info;
- __be64 guid;
-
- /* Sanity check. MacOSX seems to be sending us 131 in this
- * field (atleast on my Panther G5). Not sure why. */
- if (sspd > 5 || sspd < 0)
- sspd = 0;
-
- maxpayload = min(eth1394_speedto_maxpayload[sspd],
- (u16)(1 << (max_rec + 1)));
-
- guid = get_unaligned(&arp1394->s_uniq_id);
- node = eth1394_find_node_guid(&priv->ip_node_list,
- be64_to_cpu(guid));
- if (!node)
- return cpu_to_be16(0);
-
- node_info = dev_get_drvdata(&node->ud->device);
-
- /* Update our speed/payload/fifo_offset table */
- node_info->maxpayload = maxpayload;
- node_info->sspd = sspd;
- node_info->fifo = fifo_addr;
-
- /* Now that we're done with the 1394 specific stuff, we'll
- * need to alter some of the data. Believe it or not, all
- * that needs to be done is sender_IP_address needs to be
- * moved, the destination hardware address get stuffed
- * in and the hardware address length set to 8.
- *
- * IMPORTANT: The code below overwrites 1394 specific data
- * needed above so keep the munging of the data for the
- * higher level IP stack last. */
-
- arp->ar_hln = 8;
- arp_ptr += arp->ar_hln; /* skip over sender unique id */
- *(u32 *)arp_ptr = arp1394->sip; /* move sender IP addr */
- arp_ptr += arp->ar_pln; /* skip over sender IP addr */
-
- if (arp->ar_op == htons(ARPOP_REQUEST))
- memset(arp_ptr, 0, sizeof(u64));
- else
- memcpy(arp_ptr, dev->dev_addr, sizeof(u64));
- }
-
- /* Now add the ethernet header. */
- if (dev_hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL,
- skb->len) >= 0)
- ret = ether1394_type_trans(skb, dev);
-
- return ret;
-}
-
-static int fragment_overlap(struct list_head *frag_list, int offset, int len)
-{
- struct fragment_info *fi;
- int end = offset + len;
-
- list_for_each_entry(fi, frag_list, list)
- if (offset < fi->offset + fi->len && end > fi->offset)
- return 1;
-
- return 0;
-}
-
-static struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl)
-{
- struct partial_datagram *pd;
-
- list_for_each_entry(pd, pdgl, list)
- if (pd->dgl == dgl)
- return &pd->list;
-
- return NULL;
-}
-
-/* Assumes that new fragment does not overlap any existing fragments */
-static int new_fragment(struct list_head *frag_info, int offset, int len)
-{
- struct list_head *lh;
- struct fragment_info *fi, *fi2, *new;
-
- list_for_each(lh, frag_info) {
- fi = list_entry(lh, struct fragment_info, list);
- if (fi->offset + fi->len == offset) {
- /* The new fragment can be tacked on to the end */
- fi->len += len;
- /* Did the new fragment plug a hole? */
- fi2 = list_entry(lh->next, struct fragment_info, list);
- if (fi->offset + fi->len == fi2->offset) {
- /* glue fragments together */
- fi->len += fi2->len;
- list_del(lh->next);
- kfree(fi2);
- }
- return 0;
- } else if (offset + len == fi->offset) {
- /* The new fragment can be tacked on to the beginning */
- fi->offset = offset;
- fi->len += len;
- /* Did the new fragment plug a hole? */
- fi2 = list_entry(lh->prev, struct fragment_info, list);
- if (fi2->offset + fi2->len == fi->offset) {
- /* glue fragments together */
- fi2->len += fi->len;
- list_del(lh);
- kfree(fi);
- }
- return 0;
- } else if (offset > fi->offset + fi->len) {
- break;
- } else if (offset + len < fi->offset) {
- lh = lh->prev;
- break;
- }
- }
-
- new = kmalloc(sizeof(*new), GFP_ATOMIC);
- if (!new)
- return -ENOMEM;
-
- new->offset = offset;
- new->len = len;
-
- list_add(&new->list, lh);
- return 0;
-}
-
-static int new_partial_datagram(struct net_device *dev, struct list_head *pdgl,
- int dgl, int dg_size, char *frag_buf,
- int frag_off, int frag_len)
-{
- struct partial_datagram *new;
-
- new = kmalloc(sizeof(*new), GFP_ATOMIC);
- if (!new)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&new->frag_info);
-
- if (new_fragment(&new->frag_info, frag_off, frag_len) < 0) {
- kfree(new);
- return -ENOMEM;
- }
-
- new->dgl = dgl;
- new->dg_size = dg_size;
-
- new->skb = dev_alloc_skb(dg_size + dev->hard_header_len + 15);
- if (!new->skb) {
- struct fragment_info *fi = list_entry(new->frag_info.next,
- struct fragment_info,
- list);
- kfree(fi);
- kfree(new);
- return -ENOMEM;
- }
-
- skb_reserve(new->skb, (dev->hard_header_len + 15) & ~15);
- new->pbuf = skb_put(new->skb, dg_size);
- memcpy(new->pbuf + frag_off, frag_buf, frag_len);
-
- list_add(&new->list, pdgl);
- return 0;
-}
-
-static int update_partial_datagram(struct list_head *pdgl, struct list_head *lh,
- char *frag_buf, int frag_off, int frag_len)
-{
- struct partial_datagram *pd =
- list_entry(lh, struct partial_datagram, list);
-
- if (new_fragment(&pd->frag_info, frag_off, frag_len) < 0)
- return -ENOMEM;
-
- memcpy(pd->pbuf + frag_off, frag_buf, frag_len);
-
- /* Move list entry to beginnig of list so that oldest partial
- * datagrams percolate to the end of the list */
- list_move(lh, pdgl);
- return 0;
-}
-
-static int is_datagram_complete(struct list_head *lh, int dg_size)
-{
- struct partial_datagram *pd;
- struct fragment_info *fi;
-
- pd = list_entry(lh, struct partial_datagram, list);
- fi = list_entry(pd->frag_info.next, struct fragment_info, list);
-
- return (fi->len == dg_size);
-}
-
-/* Packet reception. We convert the IP1394 encapsulation header to an
- * ethernet header, and fill it with some of our other fields. This is
- * an incoming packet from the 1394 bus. */
-static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
- char *buf, int len)
-{
- struct sk_buff *skb;
- unsigned long flags;
- struct eth1394_priv *priv = netdev_priv(dev);
- union eth1394_hdr *hdr = (union eth1394_hdr *)buf;
- __be16 ether_type = cpu_to_be16(0); /* initialized to clear warning */
- int hdr_len;
- struct unit_directory *ud = priv->ud_list[NODEID_TO_NODE(srcid)];
- struct eth1394_node_info *node_info;
-
- if (!ud) {
- struct eth1394_node_ref *node;
- node = eth1394_find_node_nodeid(&priv->ip_node_list, srcid);
- if (unlikely(!node)) {
- HPSB_PRINT(KERN_ERR, "ether1394 rx: sender nodeid "
- "lookup failure: " NODE_BUS_FMT,
- NODE_BUS_ARGS(priv->host, srcid));
- dev->stats.rx_dropped++;
- return -1;
- }
- ud = node->ud;
-
- priv->ud_list[NODEID_TO_NODE(srcid)] = ud;
- }
-
- node_info = dev_get_drvdata(&ud->device);
-
- /* First, did we receive a fragmented or unfragmented datagram? */
- hdr->words.word1 = ntohs(hdr->words.word1);
-
- hdr_len = hdr_type_len[hdr->common.lf];
-
- if (hdr->common.lf == ETH1394_HDR_LF_UF) {
- /* An unfragmented datagram has been received by the ieee1394
- * bus. Build an skbuff around it so we can pass it to the
- * high level network layer. */
-
- skb = dev_alloc_skb(len + dev->hard_header_len + 15);
- if (unlikely(!skb)) {
- ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
- dev->stats.rx_dropped++;
- return -1;
- }
- skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
- memcpy(skb_put(skb, len - hdr_len), buf + hdr_len,
- len - hdr_len);
- ether_type = hdr->uf.ether_type;
- } else {
- /* A datagram fragment has been received, now the fun begins. */
-
- struct list_head *pdgl, *lh;
- struct partial_datagram *pd;
- int fg_off;
- int fg_len = len - hdr_len;
- int dg_size;
- int dgl;
- int retval;
- struct pdg_list *pdg = &(node_info->pdg);
-
- hdr->words.word3 = ntohs(hdr->words.word3);
- /* The 4th header word is reserved so no need to do ntohs() */
-
- if (hdr->common.lf == ETH1394_HDR_LF_FF) {
- ether_type = hdr->ff.ether_type;
- dgl = hdr->ff.dgl;
- dg_size = hdr->ff.dg_size + 1;
- fg_off = 0;
- } else {
- hdr->words.word2 = ntohs(hdr->words.word2);
- dgl = hdr->sf.dgl;
- dg_size = hdr->sf.dg_size + 1;
- fg_off = hdr->sf.fg_off;
- }
- spin_lock_irqsave(&pdg->lock, flags);
-
- pdgl = &(pdg->list);
- lh = find_partial_datagram(pdgl, dgl);
-
- if (lh == NULL) {
- while (pdg->sz >= max_partial_datagrams) {
- /* remove the oldest */
- purge_partial_datagram(pdgl->prev);
- pdg->sz--;
- }
-
- retval = new_partial_datagram(dev, pdgl, dgl, dg_size,
- buf + hdr_len, fg_off,
- fg_len);
- if (retval < 0) {
- spin_unlock_irqrestore(&pdg->lock, flags);
- goto bad_proto;
- }
- pdg->sz++;
- lh = find_partial_datagram(pdgl, dgl);
- } else {
- pd = list_entry(lh, struct partial_datagram, list);
-
- if (fragment_overlap(&pd->frag_info, fg_off, fg_len)) {
- /* Overlapping fragments, obliterate old
- * datagram and start new one. */
- purge_partial_datagram(lh);
- retval = new_partial_datagram(dev, pdgl, dgl,
- dg_size,
- buf + hdr_len,
- fg_off, fg_len);
- if (retval < 0) {
- pdg->sz--;
- spin_unlock_irqrestore(&pdg->lock, flags);
- goto bad_proto;
- }
- } else {
- retval = update_partial_datagram(pdgl, lh,
- buf + hdr_len,
- fg_off, fg_len);
- if (retval < 0) {
- /* Couldn't save off fragment anyway
- * so might as well obliterate the
- * datagram now. */
- purge_partial_datagram(lh);
- pdg->sz--;
- spin_unlock_irqrestore(&pdg->lock, flags);
- goto bad_proto;
- }
- } /* fragment overlap */
- } /* new datagram or add to existing one */
-
- pd = list_entry(lh, struct partial_datagram, list);
-
- if (hdr->common.lf == ETH1394_HDR_LF_FF)
- pd->ether_type = ether_type;
-
- if (is_datagram_complete(lh, dg_size)) {
- ether_type = pd->ether_type;
- pdg->sz--;
- skb = skb_get(pd->skb);
- purge_partial_datagram(lh);
- spin_unlock_irqrestore(&pdg->lock, flags);
- } else {
- /* Datagram is not complete, we're done for the
- * moment. */
- spin_unlock_irqrestore(&pdg->lock, flags);
- return 0;
- }
- } /* unframgented datagram or fragmented one */
-
- /* Write metadata, and then pass to the receive level */
- skb->dev = dev;
- skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
-
- /* Parse the encapsulation header. This actually does the job of
- * converting to an ethernet frame header, aswell as arp
- * conversion if needed. ARP conversion is easier in this
- * direction, since we are using ethernet as our backend. */
- skb->protocol = ether1394_parse_encap(skb, dev, srcid, destid,
- ether_type);
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (!skb->protocol) {
- dev->stats.rx_errors++;
- dev->stats.rx_dropped++;
- dev_kfree_skb_any(skb);
- } else if (netif_rx(skb) == NET_RX_DROP) {
- dev->stats.rx_errors++;
- dev->stats.rx_dropped++;
- } else {
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
-bad_proto:
- if (netif_queue_stopped(dev))
- netif_wake_queue(dev);
-
- return 0;
-}
-
-static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
- quadlet_t *data, u64 addr, size_t len, u16 flags)
-{
- struct eth1394_host_info *hi;
-
- hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
- if (unlikely(!hi)) {
- ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
- host->id);
- return RCODE_ADDRESS_ERROR;
- }
-
- if (ether1394_data_handler(hi->dev, srcid, destid, (char*)data, len))
- return RCODE_ADDRESS_ERROR;
- else
- return RCODE_COMPLETE;
-}
-
-static void ether1394_iso(struct hpsb_iso *iso)
-{
- __be32 *data;
- char *buf;
- struct eth1394_host_info *hi;
- struct net_device *dev;
- unsigned int len;
- u32 specifier_id;
- u16 source_id;
- int i;
- int nready;
-
- hi = hpsb_get_hostinfo(&eth1394_highlevel, iso->host);
- if (unlikely(!hi)) {
- ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
- iso->host->id);
- return;
- }
-
- dev = hi->dev;
-
- nready = hpsb_iso_n_ready(iso);
- for (i = 0; i < nready; i++) {
- struct hpsb_iso_packet_info *info =
- &iso->infos[(iso->first_packet + i) % iso->buf_packets];
- data = (__be32 *)(iso->data_buf.kvirt + info->offset);
-
- /* skip over GASP header */
- buf = (char *)data + 8;
- len = info->len - 8;
-
- specifier_id = (be32_to_cpu(data[0]) & 0xffff) << 8 |
- (be32_to_cpu(data[1]) & 0xff000000) >> 24;
- source_id = be32_to_cpu(data[0]) >> 16;
-
- if (info->channel != (iso->host->csr.broadcast_channel & 0x3f)
- || specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
- /* This packet is not for us */
- continue;
- }
- ether1394_data_handler(dev, source_id, LOCAL_BUS | ALL_NODES,
- buf, len);
- }
-
- hpsb_iso_recv_release_packets(iso, i);
-
-}
-
-/******************************************
- * Datagram transmission code
- ******************************************/
-
-/* Convert a standard ARP packet to 1394 ARP. The first 8 bytes (the entire
- * arphdr) is the same format as the ip1394 header, so they overlap. The rest
- * needs to be munged a bit. The remainder of the arphdr is formatted based
- * on hwaddr len and ipaddr len. We know what they'll be, so it's easy to
- * judge.
- *
- * Now that the EUI is used for the hardware address all we need to do to make
- * this work for 1394 is to insert 2 quadlets that contain max_rec size,
- * speed, and unicast FIFO address information between the sender_unique_id
- * and the IP addresses.
- */
-static void ether1394_arp_to_1394arp(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct eth1394_priv *priv = netdev_priv(dev);
- struct arphdr *arp = (struct arphdr *)skb->data;
- unsigned char *arp_ptr = (unsigned char *)(arp + 1);
- struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
-
- arp1394->hw_addr_len = 16;
- arp1394->sip = *(u32*)(arp_ptr + ETH1394_ALEN);
- arp1394->max_rec = priv->host->csr.max_rec;
- arp1394->sspd = priv->host->csr.lnk_spd;
- arp1394->fifo_hi = htons(priv->local_fifo >> 32);
- arp1394->fifo_lo = htonl(priv->local_fifo & ~0x0);
-}
-
-/* We need to encapsulate the standard header with our own. We use the
- * ethernet header's proto for our own. */
-static unsigned int ether1394_encapsulate_prep(unsigned int max_payload,
- __be16 proto,
- union eth1394_hdr *hdr,
- u16 dg_size, u16 dgl)
-{
- unsigned int adj_max_payload =
- max_payload - hdr_type_len[ETH1394_HDR_LF_UF];
-
- /* Does it all fit in one packet? */
- if (dg_size <= adj_max_payload) {
- hdr->uf.lf = ETH1394_HDR_LF_UF;
- hdr->uf.ether_type = proto;
- } else {
- hdr->ff.lf = ETH1394_HDR_LF_FF;
- hdr->ff.ether_type = proto;
- hdr->ff.dg_size = dg_size - 1;
- hdr->ff.dgl = dgl;
- adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_FF];
- }
- return DIV_ROUND_UP(dg_size, adj_max_payload);
-}
-
-static unsigned int ether1394_encapsulate(struct sk_buff *skb,
- unsigned int max_payload,
- union eth1394_hdr *hdr)
-{
- union eth1394_hdr *bufhdr;
- int ftype = hdr->common.lf;
- int hdrsz = hdr_type_len[ftype];
- unsigned int adj_max_payload = max_payload - hdrsz;
-
- switch (ftype) {
- case ETH1394_HDR_LF_UF:
- bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz);
- bufhdr->words.word1 = htons(hdr->words.word1);
- bufhdr->words.word2 = hdr->words.word2;
- break;
-
- case ETH1394_HDR_LF_FF:
- bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz);
- bufhdr->words.word1 = htons(hdr->words.word1);
- bufhdr->words.word2 = hdr->words.word2;
- bufhdr->words.word3 = htons(hdr->words.word3);
- bufhdr->words.word4 = 0;
-
- /* Set frag type here for future interior fragments */
- hdr->common.lf = ETH1394_HDR_LF_IF;
- hdr->sf.fg_off = 0;
- break;
-
- default:
- hdr->sf.fg_off += adj_max_payload;
- bufhdr = (union eth1394_hdr *)skb_pull(skb, adj_max_payload);
- if (max_payload >= skb->len)
- hdr->common.lf = ETH1394_HDR_LF_LF;
- bufhdr->words.word1 = htons(hdr->words.word1);
- bufhdr->words.word2 = htons(hdr->words.word2);
- bufhdr->words.word3 = htons(hdr->words.word3);
- bufhdr->words.word4 = 0;
- }
- return min(max_payload, skb->len);
-}
-
-static struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host)
-{
- struct hpsb_packet *p;
-
- p = hpsb_alloc_packet(0);
- if (p) {
- p->host = host;
- p->generation = get_hpsb_generation(host);
- p->type = hpsb_async;
- }
- return p;
-}
-
-static int ether1394_prep_write_packet(struct hpsb_packet *p,
- struct hpsb_host *host, nodeid_t node,
- u64 addr, void *data, int tx_len)
-{
- p->node_id = node;
-
- if (hpsb_get_tlabel(p))
- return -EAGAIN;
-
- p->tcode = TCODE_WRITEB;
- p->header_size = 16;
- p->expect_response = 1;
- p->header[0] =
- p->node_id << 16 | p->tlabel << 10 | 1 << 8 | TCODE_WRITEB << 4;
- p->header[1] = host->node_id << 16 | addr >> 32;
- p->header[2] = addr & 0xffffffff;
- p->header[3] = tx_len << 16;
- p->data_size = (tx_len + 3) & ~3;
- p->data = data;
-
- return 0;
-}
-
-static void ether1394_prep_gasp_packet(struct hpsb_packet *p,
- struct eth1394_priv *priv,
- struct sk_buff *skb, int length)
-{
- p->header_size = 4;
- p->tcode = TCODE_STREAM_DATA;
-
- p->header[0] = length << 16 | 3 << 14 | priv->broadcast_channel << 8 |
- TCODE_STREAM_DATA << 4;
- p->data_size = length;
- p->data = (quadlet_t *)skb->data - 2;
- p->data[0] = cpu_to_be32(priv->host->node_id << 16 |
- ETHER1394_GASP_SPECIFIER_ID_HI);
- p->data[1] = cpu_to_be32(ETHER1394_GASP_SPECIFIER_ID_LO << 24 |
- ETHER1394_GASP_VERSION);
-
- p->speed_code = priv->bc_sspd;
-
- /* prevent hpsb_send_packet() from overriding our speed code */
- p->node_id = LOCAL_BUS | ALL_NODES;
-}
-
-static void ether1394_free_packet(struct hpsb_packet *packet)
-{
- if (packet->tcode != TCODE_STREAM_DATA)
- hpsb_free_tlabel(packet);
- hpsb_free_packet(packet);
-}
-
-static void ether1394_complete_cb(void *__ptask);
-
-static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len)
-{
- struct eth1394_priv *priv = ptask->priv;
- struct hpsb_packet *packet = NULL;
-
- packet = ether1394_alloc_common_packet(priv->host);
- if (!packet)
- return -ENOMEM;
-
- if (ptask->tx_type == ETH1394_GASP) {
- int length = tx_len + 2 * sizeof(quadlet_t);
-
- ether1394_prep_gasp_packet(packet, priv, ptask->skb, length);
- } else if (ether1394_prep_write_packet(packet, priv->host,
- ptask->dest_node,
- ptask->addr, ptask->skb->data,
- tx_len)) {
- hpsb_free_packet(packet);
- return -EAGAIN;
- }
-
- ptask->packet = packet;
- hpsb_set_packet_complete_task(ptask->packet, ether1394_complete_cb,
- ptask);
-
- if (hpsb_send_packet(packet) < 0) {
- ether1394_free_packet(packet);
- return -EIO;
- }
-
- return 0;
-}
-
-/* Task function to be run when a datagram transmission is completed */
-static void ether1394_dg_complete(struct packet_task *ptask, int fail)
-{
- struct sk_buff *skb = ptask->skb;
- struct net_device *dev = skb->dev;
- struct eth1394_priv *priv = netdev_priv(dev);
- unsigned long flags;
-
- /* Statistics */
- spin_lock_irqsave(&priv->lock, flags);
- if (fail) {
- dev->stats.tx_dropped++;
- dev->stats.tx_errors++;
- } else {
- dev->stats.tx_bytes += skb->len;
- dev->stats.tx_packets++;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
- dev_kfree_skb_any(skb);
- kmem_cache_free(packet_task_cache, ptask);
-}
-
-/* Callback for when a packet has been sent and the status of that packet is
- * known */
-static void ether1394_complete_cb(void *__ptask)
-{
- struct packet_task *ptask = (struct packet_task *)__ptask;
- struct hpsb_packet *packet = ptask->packet;
- int fail = 0;
-
- if (packet->tcode != TCODE_STREAM_DATA)
- fail = hpsb_packet_success(packet);
-
- ether1394_free_packet(packet);
-
- ptask->outstanding_pkts--;
- if (ptask->outstanding_pkts > 0 && !fail) {
- int tx_len, err;
-
- /* Add the encapsulation header to the fragment */
- tx_len = ether1394_encapsulate(ptask->skb, ptask->max_payload,
- &ptask->hdr);
- err = ether1394_send_packet(ptask, tx_len);
- if (err) {
- if (err == -EAGAIN)
- ETH1394_PRINT_G(KERN_ERR, "Out of tlabels\n");
-
- ether1394_dg_complete(ptask, 1);
- }
- } else {
- ether1394_dg_complete(ptask, fail);
- }
-}
-
-/* Transmit a packet (called by kernel) */
-static netdev_tx_t ether1394_tx(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct eth1394hdr hdr_buf;
- struct eth1394_priv *priv = netdev_priv(dev);
- __be16 proto;
- unsigned long flags;
- nodeid_t dest_node;
- eth1394_tx_type tx_type;
- unsigned int tx_len;
- unsigned int max_payload;
- u16 dg_size;
- u16 dgl;
- struct packet_task *ptask;
- struct eth1394_node_ref *node;
- struct eth1394_node_info *node_info = NULL;
-
- ptask = kmem_cache_alloc(packet_task_cache, GFP_ATOMIC);
- if (ptask == NULL)
- goto fail;
-
- /* XXX Ignore this for now. Noticed that when MacOSX is the IRM,
- * it does not set our validity bit. We need to compensate for
- * that somewhere else, but not in eth1394. */
-#if 0
- if ((priv->host->csr.broadcast_channel & 0xc0000000) != 0xc0000000)
- goto fail;
-#endif
-
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (!skb)
- goto fail;
-
- /* Get rid of the fake eth1394 header, but first make a copy.
- * We might need to rebuild the header on tx failure. */
- memcpy(&hdr_buf, skb->data, sizeof(hdr_buf));
- skb_pull(skb, ETH1394_HLEN);
-
- proto = hdr_buf.h_proto;
- dg_size = skb->len;
-
- /* Set the transmission type for the packet. ARP packets and IP
- * broadcast packets are sent via GASP. */
- if (memcmp(hdr_buf.h_dest, dev->broadcast, ETH1394_ALEN) == 0 ||
- proto == htons(ETH_P_ARP) ||
- (proto == htons(ETH_P_IP) &&
- IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) {
- tx_type = ETH1394_GASP;
- dest_node = LOCAL_BUS | ALL_NODES;
- max_payload = priv->bc_maxpayload - ETHER1394_GASP_OVERHEAD;
- BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD);
- dgl = priv->bc_dgl;
- if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
- priv->bc_dgl++;
- } else {
- __be64 guid = get_unaligned((__be64 *)hdr_buf.h_dest);
-
- node = eth1394_find_node_guid(&priv->ip_node_list,
- be64_to_cpu(guid));
- if (!node)
- goto fail;
-
- node_info = dev_get_drvdata(&node->ud->device);
- if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE)
- goto fail;
-
- dest_node = node->ud->ne->nodeid;
- max_payload = node_info->maxpayload;
- BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD);
-
- dgl = node_info->dgl;
- if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
- node_info->dgl++;
- tx_type = ETH1394_WRREQ;
- }
-
- /* If this is an ARP packet, convert it */
- if (proto == htons(ETH_P_ARP))
- ether1394_arp_to_1394arp(skb, dev);
-
- ptask->hdr.words.word1 = 0;
- ptask->hdr.words.word2 = 0;
- ptask->hdr.words.word3 = 0;
- ptask->hdr.words.word4 = 0;
- ptask->skb = skb;
- ptask->priv = priv;
- ptask->tx_type = tx_type;
-
- if (tx_type != ETH1394_GASP) {
- u64 addr;
-
- spin_lock_irqsave(&priv->lock, flags);
- addr = node_info->fifo;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- ptask->addr = addr;
- ptask->dest_node = dest_node;
- }
-
- ptask->tx_type = tx_type;
- ptask->max_payload = max_payload;
- ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload,
- proto, &ptask->hdr, dg_size, dgl);
-
- /* Add the encapsulation header to the fragment */
- tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr);
- dev->trans_start = jiffies;
- if (ether1394_send_packet(ptask, tx_len)) {
- if (dest_node == (LOCAL_BUS | ALL_NODES))
- goto fail;
-
- /* At this point we want to restore the packet. When we return
- * here with NETDEV_TX_BUSY we will get another entrance in this
- * routine with the same skb and we need it to look the same.
- * So we pull 4 more bytes, then build the header again. */
- skb_pull(skb, 4);
- ether1394_header(skb, dev, ntohs(hdr_buf.h_proto),
- hdr_buf.h_dest, NULL, 0);
-
- /* Most failures of ether1394_send_packet are recoverable. */
- netif_stop_queue(dev);
- priv->wake_node = dest_node;
- schedule_work(&priv->wake);
- kmem_cache_free(packet_task_cache, ptask);
- return NETDEV_TX_BUSY;
- }
-
- return NETDEV_TX_OK;
-fail:
- if (ptask)
- kmem_cache_free(packet_task_cache, ptask);
-
- if (skb != NULL)
- dev_kfree_skb(skb);
-
- spin_lock_irqsave(&priv->lock, flags);
- dev->stats.tx_dropped++;
- dev->stats.tx_errors++;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return NETDEV_TX_OK;
-}
-
-static void ether1394_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, driver_name);
- strcpy(info->bus_info, "ieee1394"); /* FIXME provide more detail? */
-}
-
-static const struct ethtool_ops ethtool_ops = {
- .get_drvinfo = ether1394_get_drvinfo
-};
-
-static int __init ether1394_init_module(void)
-{
- int err;
-
- packet_task_cache = kmem_cache_create("packet_task",
- sizeof(struct packet_task),
- 0, 0, NULL);
- if (!packet_task_cache)
- return -ENOMEM;
-
- hpsb_register_highlevel(&eth1394_highlevel);
- err = hpsb_register_protocol(&eth1394_proto_driver);
- if (err) {
- hpsb_unregister_highlevel(&eth1394_highlevel);
- kmem_cache_destroy(packet_task_cache);
- }
- return err;
-}
-
-static void __exit ether1394_exit_module(void)
-{
- hpsb_unregister_protocol(&eth1394_proto_driver);
- hpsb_unregister_highlevel(&eth1394_highlevel);
- kmem_cache_destroy(packet_task_cache);
-}
-
-module_init(ether1394_init_module);
-module_exit(ether1394_exit_module);
diff --git a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h
deleted file mode 100644
index d53bac47b86f..000000000000
--- a/drivers/ieee1394/eth1394.h
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * eth1394.h -- Ethernet driver for Linux IEEE-1394 Subsystem
- *
- * Copyright (C) 2000 Bonin Franck <boninf@free.fr>
- * (C) 2001 Ben Collins <bcollins@debian.org>
- *
- * Mainly based on work by Emanuel Pirker and Andreas E. Bombe
- *
- * 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 __ETH1394_H
-#define __ETH1394_H
-
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <asm/byteorder.h>
-
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-
-/* Register for incoming packets. This is 4096 bytes, which supports up to
- * S3200 (per Table 16-3 of IEEE 1394b-2002). */
-#define ETHER1394_REGION_ADDR_LEN 4096
-
-/* GASP identifier numbers for IPv4 over IEEE 1394 */
-#define ETHER1394_GASP_SPECIFIER_ID 0x00005E
-#define ETHER1394_GASP_SPECIFIER_ID_HI ((0x00005E >> 8) & 0xffff)
-#define ETHER1394_GASP_SPECIFIER_ID_LO (0x00005E & 0xff)
-#define ETHER1394_GASP_VERSION 1
-
-#define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t)) /* for GASP header */
-
-#define ETHER1394_GASP_BUFFERS 16
-
-#define NODE_SET (ALL_NODES + 1) /* Node set == 64 */
-
-enum eth1394_bc_states { ETHER1394_BC_ERROR,
- ETHER1394_BC_RUNNING,
- ETHER1394_BC_STOPPED };
-
-
-/* Private structure for our ethernet driver */
-struct eth1394_priv {
- struct hpsb_host *host; /* The card for this dev */
- u16 bc_maxpayload; /* Max broadcast payload */
- u8 bc_sspd; /* Max broadcast speed */
- u64 local_fifo; /* Local FIFO Address */
- spinlock_t lock; /* Private lock */
- int broadcast_channel; /* Async stream Broadcast Channel */
- enum eth1394_bc_states bc_state; /* broadcast channel state */
- struct hpsb_iso *iso; /* Async stream recv handle */
- int bc_dgl; /* Outgoing broadcast datagram label */
- struct list_head ip_node_list; /* List of IP capable nodes */
- struct unit_directory *ud_list[ALL_NODES]; /* Cached unit dir list */
-
- struct work_struct wake; /* Wake up after xmit failure */
- struct net_device *wake_dev; /* Stupid backlink for .wake */
- nodeid_t wake_node; /* Destination of failed xmit */
-};
-
-
-/* Define a fake hardware header format for the networking core. Note that
- * header size cannot exceed 16 bytes as that is the size of the header cache.
- * Also, we do not need the source address in the header so we omit it and
- * keep the header to under 16 bytes */
-#define ETH1394_ALEN (8)
-#define ETH1394_HLEN (10)
-
-struct eth1394hdr {
- unsigned char h_dest[ETH1394_ALEN]; /* destination eth1394 addr */
- __be16 h_proto; /* packet type ID field */
-} __attribute__((packed));
-
-static inline struct eth1394hdr *eth1394_hdr(const struct sk_buff *skb)
-{
- return (struct eth1394hdr *)skb_mac_header(skb);
-}
-
-typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type;
-
-/* IP1394 headers */
-
-/* Unfragmented */
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_uf_hdr {
- u16 lf:2;
- u16 res:14;
- __be16 ether_type; /* Ethernet packet type */
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_uf_hdr {
- u16 res:14;
- u16 lf:2;
- __be16 ether_type;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-/* First fragment */
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_ff_hdr {
- u16 lf:2;
- u16 res1:2;
- u16 dg_size:12; /* Datagram size */
- __be16 ether_type; /* Ethernet packet type */
- u16 dgl; /* Datagram label */
- u16 res2;
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_ff_hdr {
- u16 dg_size:12;
- u16 res1:2;
- u16 lf:2;
- __be16 ether_type;
- u16 dgl;
- u16 res2;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-/* XXX: Subsequent fragments, including last */
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_sf_hdr {
- u16 lf:2;
- u16 res1:2;
- u16 dg_size:12; /* Datagram size */
- u16 res2:4;
- u16 fg_off:12; /* Fragment offset */
- u16 dgl; /* Datagram label */
- u16 res3;
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_sf_hdr {
- u16 dg_size:12;
- u16 res1:2;
- u16 lf:2;
- u16 fg_off:12;
- u16 res2:4;
- u16 dgl;
- u16 res3;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_common_hdr {
- u16 lf:2;
- u16 pad1:14;
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_common_hdr {
- u16 pad1:14;
- u16 lf:2;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-struct eth1394_hdr_words {
- u16 word1;
- u16 word2;
- u16 word3;
- u16 word4;
-};
-
-union eth1394_hdr {
- struct eth1394_common_hdr common;
- struct eth1394_uf_hdr uf;
- struct eth1394_ff_hdr ff;
- struct eth1394_sf_hdr sf;
- struct eth1394_hdr_words words;
-};
-
-/* End of IP1394 headers */
-
-/* Fragment types */
-#define ETH1394_HDR_LF_UF 0 /* unfragmented */
-#define ETH1394_HDR_LF_FF 1 /* first fragment */
-#define ETH1394_HDR_LF_LF 2 /* last fragment */
-#define ETH1394_HDR_LF_IF 3 /* interior fragment */
-
-#define IP1394_HW_ADDR_LEN 16 /* As per RFC */
-
-/* Our arp packet (ARPHRD_IEEE1394) */
-struct eth1394_arp {
- u16 hw_type; /* 0x0018 */
- u16 proto_type; /* 0x0806 */
- u8 hw_addr_len; /* 16 */
- u8 ip_addr_len; /* 4 */
- u16 opcode; /* ARP Opcode */
- /* Above is exactly the same format as struct arphdr */
-
- __be64 s_uniq_id; /* Sender's 64bit EUI */
- u8 max_rec; /* Sender's max packet size */
- u8 sspd; /* Sender's max speed */
- __be16 fifo_hi; /* hi 16bits of sender's FIFO addr */
- __be32 fifo_lo; /* lo 32bits of sender's FIFO addr */
- u32 sip; /* Sender's IP Address */
- u32 tip; /* IP Address of requested hw addr */
-};
-
-/* Network timeout */
-#define ETHER1394_TIMEOUT 100000
-
-/* This is our task struct. It's used for the packet complete callback. */
-struct packet_task {
- struct sk_buff *skb;
- int outstanding_pkts;
- eth1394_tx_type tx_type;
- int max_payload;
- struct hpsb_packet *packet;
- struct eth1394_priv *priv;
- union eth1394_hdr hdr;
- u64 addr;
- u16 dest_node;
-};
-
-#endif /* __ETH1394_H */
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
deleted file mode 100644
index 4bc443546e04..000000000000
--- a/drivers/ieee1394/highlevel.c
+++ /dev/null
@@ -1,691 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Copyright (C) 1999 Andreas E. Bombe
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Christian Toegel <christian.toegel@gmx.at>
- * unregister address space
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- * unregister address space
- *
- */
-
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "nodemgr.h"
-
-
-struct hl_host_info {
- struct list_head list;
- struct hpsb_host *host;
- size_t size;
- unsigned long key;
- void *data;
-};
-
-
-static LIST_HEAD(hl_drivers);
-static DECLARE_RWSEM(hl_drivers_sem);
-
-static LIST_HEAD(hl_irqs);
-static DEFINE_RWLOCK(hl_irqs_lock);
-
-static DEFINE_RWLOCK(addr_space_lock);
-
-
-static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
- struct hpsb_host *host)
-{
- struct hl_host_info *hi = NULL;
-
- if (!hl || !host)
- return NULL;
-
- read_lock(&hl->host_info_lock);
- list_for_each_entry(hi, &hl->host_info_list, list) {
- if (hi->host == host) {
- read_unlock(&hl->host_info_lock);
- return hi;
- }
- }
- read_unlock(&hl->host_info_lock);
- return NULL;
-}
-
-/**
- * hpsb_get_hostinfo - retrieve a hostinfo pointer bound to this driver/host
- *
- * Returns a per @host and @hl driver data structure that was previously stored
- * by hpsb_create_hostinfo.
- */
-void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
-{
- struct hl_host_info *hi = hl_get_hostinfo(hl, host);
-
- return hi ? hi->data : NULL;
-}
-
-/**
- * hpsb_create_hostinfo - allocate a hostinfo pointer bound to this driver/host
- *
- * Allocate a hostinfo pointer backed by memory with @data_size and bind it to
- * to this @hl driver and @host. If @data_size is zero, then the return here is
- * only valid for error checking.
- */
-void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
- size_t data_size)
-{
- struct hl_host_info *hi;
- void *data;
- unsigned long flags;
-
- hi = hl_get_hostinfo(hl, host);
- if (hi) {
- HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already"
- " exists", hl->name);
- return NULL;
- }
-
- hi = kzalloc(sizeof(*hi) + data_size, GFP_ATOMIC);
- if (!hi)
- return NULL;
-
- if (data_size) {
- data = hi->data = hi + 1;
- hi->size = data_size;
- } else
- data = hi;
-
- hi->host = host;
-
- write_lock_irqsave(&hl->host_info_lock, flags);
- list_add_tail(&hi->list, &hl->host_info_list);
- write_unlock_irqrestore(&hl->host_info_lock, flags);
-
- return data;
-}
-
-/**
- * hpsb_set_hostinfo - set the hostinfo pointer to something useful
- *
- * Usually follows a call to hpsb_create_hostinfo, where the size is 0.
- */
-int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
- void *data)
-{
- struct hl_host_info *hi;
-
- hi = hl_get_hostinfo(hl, host);
- if (hi) {
- if (!hi->size && !hi->data) {
- hi->data = data;
- return 0;
- } else
- HPSB_ERR("%s called hpsb_set_hostinfo when hostinfo "
- "already has data", hl->name);
- } else
- HPSB_ERR("%s called hpsb_set_hostinfo when no hostinfo exists",
- hl->name);
- return -EINVAL;
-}
-
-/**
- * hpsb_destroy_hostinfo - free and remove a hostinfo pointer
- *
- * Free and remove the hostinfo pointer bound to this @hl driver and @host.
- */
-void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
-{
- struct hl_host_info *hi;
-
- hi = hl_get_hostinfo(hl, host);
- if (hi) {
- unsigned long flags;
- write_lock_irqsave(&hl->host_info_lock, flags);
- list_del(&hi->list);
- write_unlock_irqrestore(&hl->host_info_lock, flags);
- kfree(hi);
- }
- return;
-}
-
-/**
- * hpsb_set_hostinfo_key - set an alternate lookup key for an hostinfo
- *
- * Sets an alternate lookup key for the hostinfo bound to this @hl driver and
- * @host.
- */
-void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
- unsigned long key)
-{
- struct hl_host_info *hi;
-
- hi = hl_get_hostinfo(hl, host);
- if (hi)
- hi->key = key;
- return;
-}
-
-/**
- * hpsb_get_hostinfo_bykey - retrieve a hostinfo pointer by its alternate key
- */
-void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
-{
- struct hl_host_info *hi;
- void *data = NULL;
-
- if (!hl)
- return NULL;
-
- read_lock(&hl->host_info_lock);
- list_for_each_entry(hi, &hl->host_info_list, list) {
- if (hi->key == key) {
- data = hi->data;
- break;
- }
- }
- read_unlock(&hl->host_info_lock);
- return data;
-}
-
-static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data)
-{
- struct hpsb_highlevel *hl = __data;
-
- hl->add_host(host);
-
- if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
- HPSB_ERR("Failed to generate Configuration ROM image for host "
- "%s-%d", hl->name, host->id);
- return 0;
-}
-
-/**
- * hpsb_register_highlevel - register highlevel driver
- *
- * The name pointer in @hl has to stay valid at all times because the string is
- * not copied.
- */
-void hpsb_register_highlevel(struct hpsb_highlevel *hl)
-{
- unsigned long flags;
-
- hpsb_init_highlevel(hl);
- INIT_LIST_HEAD(&hl->addr_list);
-
- down_write(&hl_drivers_sem);
- list_add_tail(&hl->hl_list, &hl_drivers);
- up_write(&hl_drivers_sem);
-
- write_lock_irqsave(&hl_irqs_lock, flags);
- list_add_tail(&hl->irq_list, &hl_irqs);
- write_unlock_irqrestore(&hl_irqs_lock, flags);
-
- if (hl->add_host)
- nodemgr_for_each_host(hl, highlevel_for_each_host_reg);
- return;
-}
-
-static void __delete_addr(struct hpsb_address_serve *as)
-{
- list_del(&as->host_list);
- list_del(&as->hl_list);
- kfree(as);
-}
-
-static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host,
- int update_cr)
-{
- unsigned long flags;
- struct list_head *lh, *next;
- struct hpsb_address_serve *as;
-
- /* First, let the highlevel driver unreg */
- if (hl->remove_host)
- hl->remove_host(host);
-
- /* Remove any addresses that are matched for this highlevel driver
- * and this particular host. */
- write_lock_irqsave(&addr_space_lock, flags);
- list_for_each_safe (lh, next, &hl->addr_list) {
- as = list_entry(lh, struct hpsb_address_serve, hl_list);
- if (as->host == host)
- __delete_addr(as);
- }
- write_unlock_irqrestore(&addr_space_lock, flags);
-
- /* Now update the config-rom to reflect anything removed by the
- * highlevel driver. */
- if (update_cr && host->update_config_rom &&
- hpsb_update_config_rom_image(host) < 0)
- HPSB_ERR("Failed to generate Configuration ROM image for host "
- "%s-%d", hl->name, host->id);
-
- /* Finally remove all the host info associated between these two. */
- hpsb_destroy_hostinfo(hl, host);
-}
-
-static int highlevel_for_each_host_unreg(struct hpsb_host *host, void *__data)
-{
- struct hpsb_highlevel *hl = __data;
-
- __unregister_host(hl, host, 1);
- return 0;
-}
-
-/**
- * hpsb_unregister_highlevel - unregister highlevel driver
- */
-void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
-{
- unsigned long flags;
-
- write_lock_irqsave(&hl_irqs_lock, flags);
- list_del(&hl->irq_list);
- write_unlock_irqrestore(&hl_irqs_lock, flags);
-
- down_write(&hl_drivers_sem);
- list_del(&hl->hl_list);
- up_write(&hl_drivers_sem);
-
- nodemgr_for_each_host(hl, highlevel_for_each_host_unreg);
-}
-
-/**
- * hpsb_allocate_and_register_addrspace - alloc' and reg' a host address space
- *
- * @start and @end are 48 bit pointers and have to be quadlet aligned.
- * @end points to the first address behind the handled addresses. This
- * function can be called multiple times for a single hpsb_highlevel @hl to
- * implement sparse register sets. The requested region must not overlap any
- * previously allocated region, otherwise registering will fail.
- *
- * It returns true for successful allocation. Address spaces can be
- * unregistered with hpsb_unregister_addrspace. All remaining address spaces
- * are automatically deallocated together with the hpsb_highlevel @hl.
- */
-u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
- struct hpsb_host *host,
- const struct hpsb_address_ops *ops,
- u64 size, u64 alignment,
- u64 start, u64 end)
-{
- struct hpsb_address_serve *as, *a1, *a2;
- struct list_head *entry;
- u64 retval = CSR1212_INVALID_ADDR_SPACE;
- unsigned long flags;
- u64 align_mask = ~(alignment - 1);
-
- if ((alignment & 3) || (alignment > 0x800000000000ULL) ||
- (hweight64(alignment) != 1)) {
- HPSB_ERR("%s called with invalid alignment: 0x%048llx",
- __func__, (unsigned long long)alignment);
- return retval;
- }
-
- /* default range,
- * avoids controller's posted write area (see OHCI 1.1 clause 1.5) */
- if (start == CSR1212_INVALID_ADDR_SPACE &&
- end == CSR1212_INVALID_ADDR_SPACE) {
- start = host->middle_addr_space;
- end = CSR1212_ALL_SPACE_END;
- }
-
- if (((start|end) & ~align_mask) || (start >= end) ||
- (end > CSR1212_ALL_SPACE_END)) {
- HPSB_ERR("%s called with invalid addresses "
- "(start = %012Lx end = %012Lx)", __func__,
- (unsigned long long)start,(unsigned long long)end);
- return retval;
- }
-
- as = kmalloc(sizeof(*as), GFP_KERNEL);
- if (!as)
- return retval;
-
- INIT_LIST_HEAD(&as->host_list);
- INIT_LIST_HEAD(&as->hl_list);
- as->op = ops;
- as->host = host;
-
- write_lock_irqsave(&addr_space_lock, flags);
- list_for_each(entry, &host->addr_space) {
- u64 a1sa, a1ea;
- u64 a2sa, a2ea;
-
- a1 = list_entry(entry, struct hpsb_address_serve, host_list);
- a2 = list_entry(entry->next, struct hpsb_address_serve,
- host_list);
-
- a1sa = a1->start & align_mask;
- a1ea = (a1->end + alignment -1) & align_mask;
- a2sa = a2->start & align_mask;
- a2ea = (a2->end + alignment -1) & align_mask;
-
- if ((a2sa - a1ea >= size) && (a2sa - start >= size) &&
- (a2sa > start)) {
- as->start = max(start, a1ea);
- as->end = as->start + size;
- list_add(&as->host_list, entry);
- list_add_tail(&as->hl_list, &hl->addr_list);
- retval = as->start;
- break;
- }
- }
- write_unlock_irqrestore(&addr_space_lock, flags);
-
- if (retval == CSR1212_INVALID_ADDR_SPACE)
- kfree(as);
- return retval;
-}
-
-/**
- * hpsb_register_addrspace - register a host address space
- *
- * @start and @end are 48 bit pointers and have to be quadlet aligned.
- * @end points to the first address behind the handled addresses. This
- * function can be called multiple times for a single hpsb_highlevel @hl to
- * implement sparse register sets. The requested region must not overlap any
- * previously allocated region, otherwise registering will fail.
- *
- * It returns true for successful allocation. Address spaces can be
- * unregistered with hpsb_unregister_addrspace. All remaining address spaces
- * are automatically deallocated together with the hpsb_highlevel @hl.
- */
-int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
- const struct hpsb_address_ops *ops,
- u64 start, u64 end)
-{
- struct hpsb_address_serve *as;
- struct list_head *lh;
- int retval = 0;
- unsigned long flags;
-
- if (((start|end) & 3) || (start >= end) ||
- (end > CSR1212_ALL_SPACE_END)) {
- HPSB_ERR("%s called with invalid addresses", __func__);
- return 0;
- }
-
- as = kmalloc(sizeof(*as), GFP_KERNEL);
- if (!as)
- return 0;
-
- INIT_LIST_HEAD(&as->host_list);
- INIT_LIST_HEAD(&as->hl_list);
- as->op = ops;
- as->start = start;
- as->end = end;
- as->host = host;
-
- write_lock_irqsave(&addr_space_lock, flags);
- list_for_each(lh, &host->addr_space) {
- struct hpsb_address_serve *as_this =
- list_entry(lh, struct hpsb_address_serve, host_list);
- struct hpsb_address_serve *as_next =
- list_entry(lh->next, struct hpsb_address_serve,
- host_list);
-
- if (as_this->end > as->start)
- break;
-
- if (as_next->start >= as->end) {
- list_add(&as->host_list, lh);
- list_add_tail(&as->hl_list, &hl->addr_list);
- retval = 1;
- break;
- }
- }
- write_unlock_irqrestore(&addr_space_lock, flags);
-
- if (retval == 0)
- kfree(as);
- return retval;
-}
-
-int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
- u64 start)
-{
- int retval = 0;
- struct hpsb_address_serve *as;
- struct list_head *lh, *next;
- unsigned long flags;
-
- write_lock_irqsave(&addr_space_lock, flags);
- list_for_each_safe (lh, next, &hl->addr_list) {
- as = list_entry(lh, struct hpsb_address_serve, hl_list);
- if (as->start == start && as->host == host) {
- __delete_addr(as);
- retval = 1;
- break;
- }
- }
- write_unlock_irqrestore(&addr_space_lock, flags);
- return retval;
-}
-
-static const struct hpsb_address_ops dummy_ops;
-
-/* dummy address spaces as lower and upper bounds of the host's a.s. list */
-static void init_hpsb_highlevel(struct hpsb_host *host)
-{
- INIT_LIST_HEAD(&host->dummy_zero_addr.host_list);
- INIT_LIST_HEAD(&host->dummy_zero_addr.hl_list);
- INIT_LIST_HEAD(&host->dummy_max_addr.host_list);
- INIT_LIST_HEAD(&host->dummy_max_addr.hl_list);
-
- host->dummy_zero_addr.op = host->dummy_max_addr.op = &dummy_ops;
-
- host->dummy_zero_addr.start = host->dummy_zero_addr.end = 0;
- host->dummy_max_addr.start = host->dummy_max_addr.end = ((u64) 1) << 48;
-
- list_add_tail(&host->dummy_zero_addr.host_list, &host->addr_space);
- list_add_tail(&host->dummy_max_addr.host_list, &host->addr_space);
-}
-
-void highlevel_add_host(struct hpsb_host *host)
-{
- struct hpsb_highlevel *hl;
-
- init_hpsb_highlevel(host);
-
- down_read(&hl_drivers_sem);
- list_for_each_entry(hl, &hl_drivers, hl_list) {
- if (hl->add_host)
- hl->add_host(host);
- }
- up_read(&hl_drivers_sem);
- if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
- HPSB_ERR("Failed to generate Configuration ROM image for host "
- "%s-%d", hl->name, host->id);
-}
-
-void highlevel_remove_host(struct hpsb_host *host)
-{
- struct hpsb_highlevel *hl;
-
- down_read(&hl_drivers_sem);
- list_for_each_entry(hl, &hl_drivers, hl_list)
- __unregister_host(hl, host, 0);
- up_read(&hl_drivers_sem);
-}
-
-void highlevel_host_reset(struct hpsb_host *host)
-{
- unsigned long flags;
- struct hpsb_highlevel *hl;
-
- read_lock_irqsave(&hl_irqs_lock, flags);
- list_for_each_entry(hl, &hl_irqs, irq_list) {
- if (hl->host_reset)
- hl->host_reset(host);
- }
- read_unlock_irqrestore(&hl_irqs_lock, flags);
-}
-
-void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
- void *data, size_t length)
-{
- unsigned long flags;
- struct hpsb_highlevel *hl;
- int cts = ((quadlet_t *)data)[0] >> 4;
-
- read_lock_irqsave(&hl_irqs_lock, flags);
- list_for_each_entry(hl, &hl_irqs, irq_list) {
- if (hl->fcp_request)
- hl->fcp_request(host, nodeid, direction, cts, data,
- length);
- }
- read_unlock_irqrestore(&hl_irqs_lock, flags);
-}
-
-/*
- * highlevel_read, highlevel_write, highlevel_lock, highlevel_lock64:
- *
- * These functions are called to handle transactions. They are called when a
- * packet arrives. The flags argument contains the second word of the first
- * header quadlet of the incoming packet (containing transaction label, retry
- * code, transaction code and priority). These functions either return a
- * response code or a negative number. In the first case a response will be
- * generated. In the latter case, no response will be sent and the driver which
- * handled the request will send the response itself.
- */
-int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
- unsigned int length, u16 flags)
-{
- struct hpsb_address_serve *as;
- unsigned int partlength;
- int rcode = RCODE_ADDRESS_ERROR;
-
- read_lock(&addr_space_lock);
- list_for_each_entry(as, &host->addr_space, host_list) {
- if (as->start > addr)
- break;
-
- if (as->end > addr) {
- partlength = min(as->end - addr, (u64) length);
-
- if (as->op->read)
- rcode = as->op->read(host, nodeid, data,
- addr, partlength, flags);
- else
- rcode = RCODE_TYPE_ERROR;
-
- data += partlength;
- length -= partlength;
- addr += partlength;
-
- if ((rcode != RCODE_COMPLETE) || !length)
- break;
- }
- }
- read_unlock(&addr_space_lock);
-
- if (length && (rcode == RCODE_COMPLETE))
- rcode = RCODE_ADDRESS_ERROR;
- return rcode;
-}
-
-int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
- u64 addr, unsigned int length, u16 flags)
-{
- struct hpsb_address_serve *as;
- unsigned int partlength;
- int rcode = RCODE_ADDRESS_ERROR;
-
- read_lock(&addr_space_lock);
- list_for_each_entry(as, &host->addr_space, host_list) {
- if (as->start > addr)
- break;
-
- if (as->end > addr) {
- partlength = min(as->end - addr, (u64) length);
-
- if (as->op->write)
- rcode = as->op->write(host, nodeid, destid,
- data, addr, partlength,
- flags);
- else
- rcode = RCODE_TYPE_ERROR;
-
- data += partlength;
- length -= partlength;
- addr += partlength;
-
- if ((rcode != RCODE_COMPLETE) || !length)
- break;
- }
- }
- read_unlock(&addr_space_lock);
-
- if (length && (rcode == RCODE_COMPLETE))
- rcode = RCODE_ADDRESS_ERROR;
- return rcode;
-}
-
-int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
- u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
- u16 flags)
-{
- struct hpsb_address_serve *as;
- int rcode = RCODE_ADDRESS_ERROR;
-
- read_lock(&addr_space_lock);
- list_for_each_entry(as, &host->addr_space, host_list) {
- if (as->start > addr)
- break;
-
- if (as->end > addr) {
- if (as->op->lock)
- rcode = as->op->lock(host, nodeid, store, addr,
- data, arg, ext_tcode,
- flags);
- else
- rcode = RCODE_TYPE_ERROR;
- break;
- }
- }
- read_unlock(&addr_space_lock);
- return rcode;
-}
-
-int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
- u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
- u16 flags)
-{
- struct hpsb_address_serve *as;
- int rcode = RCODE_ADDRESS_ERROR;
-
- read_lock(&addr_space_lock);
-
- list_for_each_entry(as, &host->addr_space, host_list) {
- if (as->start > addr)
- break;
-
- if (as->end > addr) {
- if (as->op->lock64)
- rcode = as->op->lock64(host, nodeid, store,
- addr, data, arg,
- ext_tcode, flags);
- else
- rcode = RCODE_TYPE_ERROR;
- break;
- }
- }
- read_unlock(&addr_space_lock);
- return rcode;
-}
diff --git a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h
deleted file mode 100644
index 9dba89fc60ad..000000000000
--- a/drivers/ieee1394/highlevel.h
+++ /dev/null
@@ -1,141 +0,0 @@
-#ifndef IEEE1394_HIGHLEVEL_H
-#define IEEE1394_HIGHLEVEL_H
-
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-struct module;
-
-#include "ieee1394_types.h"
-
-struct hpsb_host;
-
-/* internal to ieee1394 core */
-struct hpsb_address_serve {
- struct list_head host_list; /* per host list */
- struct list_head hl_list; /* hpsb_highlevel list */
- const struct hpsb_address_ops *op;
- struct hpsb_host *host;
- u64 start; /* first address handled, quadlet aligned */
- u64 end; /* first address behind, quadlet aligned */
-};
-
-/* Only the following structures are of interest to actual highlevel drivers. */
-
-struct hpsb_highlevel {
- const char *name;
-
- /* Any of the following pointers can legally be NULL. */
-
- /* New host initialized. Will also be called during
- * hpsb_register_highlevel for all hosts already installed. */
- void (*add_host)(struct hpsb_host *host);
-
- /* Host about to be removed. Will also be called during
- * hpsb_unregister_highlevel once for each host. */
- void (*remove_host)(struct hpsb_host *host);
-
- /* Host experienced bus reset with possible configuration changes.
- * Note that this one may occur during interrupt/bottom half handling.
- * You can not expect to be able to do stock hpsb_reads. */
- void (*host_reset)(struct hpsb_host *host);
-
- /* A write request was received on either the FCP_COMMAND (direction =
- * 0) or the FCP_RESPONSE (direction = 1) register. The cts arg
- * contains the cts field (first byte of data). */
- void (*fcp_request)(struct hpsb_host *host, int nodeid, int direction,
- int cts, u8 *data, size_t length);
-
- /* These are initialized by the subsystem when the
- * hpsb_higlevel is registered. */
- struct list_head hl_list;
- struct list_head irq_list;
- struct list_head addr_list;
-
- struct list_head host_info_list;
- rwlock_t host_info_lock;
-};
-
-struct hpsb_address_ops {
- /*
- * Null function pointers will make the respective operation complete
- * with RCODE_TYPE_ERROR. Makes for easy to implement read-only
- * registers (just leave everything but read NULL).
- *
- * All functions shall return appropriate IEEE 1394 rcodes.
- */
-
- /* These functions have to implement block reads for themselves.
- *
- * These functions either return a response code or a negative number.
- * In the first case a response will be generated. In the latter case,
- * no response will be sent and the driver which handled the request
- * will send the response itself. */
- int (*read)(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
- u64 addr, size_t length, u16 flags);
- int (*write)(struct hpsb_host *host, int nodeid, int destid,
- quadlet_t *data, u64 addr, size_t length, u16 flags);
-
- /* Lock transactions: write results of ext_tcode operation into
- * *store. */
- int (*lock)(struct hpsb_host *host, int nodeid, quadlet_t *store,
- u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
- u16 flags);
- int (*lock64)(struct hpsb_host *host, int nodeid, octlet_t *store,
- u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
- u16 flags);
-};
-
-void highlevel_add_host(struct hpsb_host *host);
-void highlevel_remove_host(struct hpsb_host *host);
-void highlevel_host_reset(struct hpsb_host *host);
-int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
- unsigned int length, u16 flags);
-int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
- u64 addr, unsigned int length, u16 flags);
-int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
- u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
- u16 flags);
-int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
- u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
- u16 flags);
-void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
- void *data, size_t length);
-
-/**
- * hpsb_init_highlevel - initialize a struct hpsb_highlevel
- *
- * This is only necessary if hpsb_get_hostinfo_bykey can be called
- * before hpsb_register_highlevel.
- */
-static inline void hpsb_init_highlevel(struct hpsb_highlevel *hl)
-{
- rwlock_init(&hl->host_info_lock);
- INIT_LIST_HEAD(&hl->host_info_list);
-}
-void hpsb_register_highlevel(struct hpsb_highlevel *hl);
-void hpsb_unregister_highlevel(struct hpsb_highlevel *hl);
-
-u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
- struct hpsb_host *host,
- const struct hpsb_address_ops *ops,
- u64 size, u64 alignment,
- u64 start, u64 end);
-int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
- const struct hpsb_address_ops *ops,
- u64 start, u64 end);
-int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
- u64 start);
-
-void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
-void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
- size_t data_size);
-void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
-void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
- unsigned long key);
-void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key);
-int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
- void *data);
-
-#endif /* IEEE1394_HIGHLEVEL_H */
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
deleted file mode 100644
index e947d8ffac85..000000000000
--- a/drivers/ieee1394/hosts.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Low level (host adapter) management.
- *
- * Copyright (C) 1999 Andreas E. Bombe
- * Copyright (C) 1999 Emanuel Pirker
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/timer.h>
-#include <linux/jiffies.h>
-#include <linux/mutex.h>
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "nodemgr.h"
-#include "csr.h"
-#include "config_roms.h"
-
-
-static void delayed_reset_bus(struct work_struct *work)
-{
- struct hpsb_host *host =
- container_of(work, struct hpsb_host, delayed_reset.work);
- u8 generation = host->csr.generation + 1;
-
- /* The generation field rolls over to 2 rather than 0 per IEEE
- * 1394a-2000. */
- if (generation > 0xf || generation < 2)
- generation = 2;
-
- csr_set_bus_info_generation(host->csr.rom, generation);
- if (csr1212_generate_csr_image(host->csr.rom) != CSR1212_SUCCESS) {
- /* CSR image creation failed.
- * Reset generation field and do not issue a bus reset. */
- csr_set_bus_info_generation(host->csr.rom,
- host->csr.generation);
- return;
- }
-
- host->csr.generation = generation;
-
- host->update_config_rom = 0;
- if (host->driver->set_hw_config_rom)
- host->driver->set_hw_config_rom(host,
- host->csr.rom->bus_info_data);
-
- host->csr.gen_timestamp[host->csr.generation] = jiffies;
- hpsb_reset_bus(host, SHORT_RESET);
-}
-
-static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p)
-{
- return 0;
-}
-
-static int dummy_devctl(struct hpsb_host *h, enum devctl_cmd c, int arg)
-{
- return -1;
-}
-
-static int dummy_isoctl(struct hpsb_iso *iso, enum isoctl_cmd command,
- unsigned long arg)
-{
- return -1;
-}
-
-static struct hpsb_host_driver dummy_driver = {
- .transmit_packet = dummy_transmit_packet,
- .devctl = dummy_devctl,
- .isoctl = dummy_isoctl
-};
-
-static int alloc_hostnum_cb(struct hpsb_host *host, void *__data)
-{
- int *hostnum = __data;
-
- if (host->id == *hostnum)
- return 1;
-
- return 0;
-}
-
-static DEFINE_MUTEX(host_num_alloc);
-
-/**
- * hpsb_alloc_host - allocate a new host controller.
- * @drv: the driver that will manage the host controller
- * @extra: number of extra bytes to allocate for the driver
- *
- * Allocate a &hpsb_host and initialize the general subsystem specific
- * fields. If the driver needs to store per host data, as drivers
- * usually do, the amount of memory required can be specified by the
- * @extra parameter. Once allocated, the driver should initialize the
- * driver specific parts, enable the controller and make it available
- * to the general subsystem using hpsb_add_host().
- *
- * Return Value: a pointer to the &hpsb_host if successful, %NULL if
- * no memory was available.
- */
-struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
- struct device *dev)
-{
- struct hpsb_host *h;
- int i;
- int hostnum = 0;
-
- h = kzalloc(sizeof(*h) + extra, GFP_KERNEL);
- if (!h)
- return NULL;
-
- h->csr.rom = csr1212_create_csr(&csr_bus_ops, CSR_BUS_INFO_SIZE, h);
- if (!h->csr.rom)
- goto fail;
-
- h->hostdata = h + 1;
- h->driver = drv;
-
- INIT_LIST_HEAD(&h->pending_packets);
- INIT_LIST_HEAD(&h->addr_space);
-
- for (i = 2; i < 16; i++)
- h->csr.gen_timestamp[i] = jiffies - 60 * HZ;
-
- atomic_set(&h->generation, 0);
-
- INIT_DELAYED_WORK(&h->delayed_reset, delayed_reset_bus);
-
- init_timer(&h->timeout);
- h->timeout.data = (unsigned long) h;
- h->timeout.function = abort_timedouts;
- h->timeout_interval = HZ / 20; /* 50ms, half of minimum SPLIT_TIMEOUT */
-
- h->topology_map = h->csr.topology_map + 3;
- h->speed_map = (u8 *)(h->csr.speed_map + 2);
-
- mutex_lock(&host_num_alloc);
- while (nodemgr_for_each_host(&hostnum, alloc_hostnum_cb))
- hostnum++;
- mutex_unlock(&host_num_alloc);
- h->id = hostnum;
-
- memcpy(&h->device, &nodemgr_dev_template_host, sizeof(h->device));
- h->device.parent = dev;
- set_dev_node(&h->device, dev_to_node(dev));
- dev_set_name(&h->device, "fw-host%d", h->id);
-
- h->host_dev.parent = &h->device;
- h->host_dev.class = &hpsb_host_class;
- dev_set_name(&h->host_dev, "fw-host%d", h->id);
-
- if (device_register(&h->device))
- goto fail;
- if (device_register(&h->host_dev)) {
- device_unregister(&h->device);
- goto fail;
- }
- get_device(&h->device);
-
- return h;
-
-fail:
- kfree(h);
- return NULL;
-}
-
-int hpsb_add_host(struct hpsb_host *host)
-{
- if (hpsb_default_host_entry(host))
- return -ENOMEM;
-
- highlevel_add_host(host);
- return 0;
-}
-
-void hpsb_resume_host(struct hpsb_host *host)
-{
- if (host->driver->set_hw_config_rom)
- host->driver->set_hw_config_rom(host,
- host->csr.rom->bus_info_data);
- host->driver->devctl(host, RESET_BUS, SHORT_RESET);
-}
-
-void hpsb_remove_host(struct hpsb_host *host)
-{
- host->is_shutdown = 1;
-
- cancel_delayed_work(&host->delayed_reset);
- flush_scheduled_work();
-
- host->driver = &dummy_driver;
- highlevel_remove_host(host);
-
- device_unregister(&host->host_dev);
- device_unregister(&host->device);
-}
-
-/**
- * hpsb_update_config_rom_image - updates configuration ROM image of a host
- *
- * Updates the configuration ROM image of a host. rom_version must be the
- * current version, otherwise it will fail with return value -1. If this
- * host does not support config-rom-update, it will return -%EINVAL.
- * Return value 0 indicates success.
- */
-int hpsb_update_config_rom_image(struct hpsb_host *host)
-{
- unsigned long reset_delay;
- int next_gen = host->csr.generation + 1;
-
- if (!host->update_config_rom)
- return -EINVAL;
-
- if (next_gen > 0xf)
- next_gen = 2;
-
- /* Stop the delayed interrupt, we're about to change the config rom and
- * it would be a waste to do a bus reset twice. */
- cancel_delayed_work(&host->delayed_reset);
-
- /* IEEE 1394a-2000 prohibits using the same generation number
- * twice in a 60 second period. */
- if (time_before(jiffies, host->csr.gen_timestamp[next_gen] + 60 * HZ))
- /* Wait 60 seconds from the last time this generation number was
- * used. */
- reset_delay =
- (60 * HZ) + host->csr.gen_timestamp[next_gen] - jiffies;
- else
- /* Wait 1 second in case some other code wants to change the
- * Config ROM in the near future. */
- reset_delay = HZ;
-
- PREPARE_DELAYED_WORK(&host->delayed_reset, delayed_reset_bus);
- schedule_delayed_work(&host->delayed_reset, reset_delay);
-
- return 0;
-}
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
deleted file mode 100644
index 49c359022c54..000000000000
--- a/drivers/ieee1394/hosts.h
+++ /dev/null
@@ -1,201 +0,0 @@
-#ifndef _IEEE1394_HOSTS_H
-#define _IEEE1394_HOSTS_H
-
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/types.h>
-#include <linux/workqueue.h>
-#include <asm/atomic.h>
-
-struct pci_dev;
-struct module;
-
-#include "ieee1394_types.h"
-#include "csr.h"
-#include "highlevel.h"
-
-struct hpsb_packet;
-struct hpsb_iso;
-
-struct hpsb_host {
- struct list_head host_list;
-
- void *hostdata;
-
- atomic_t generation;
-
- struct list_head pending_packets;
- struct timer_list timeout;
- unsigned long timeout_interval;
-
- int node_count; /* number of identified nodes on this bus */
- int selfid_count; /* total number of SelfIDs received */
- int nodes_active; /* number of nodes with active link layer */
-
- nodeid_t node_id; /* node ID of this host */
- nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
- nodeid_t busmgr_id; /* ID of this bus' bus manager */
-
- /* this nodes state */
- unsigned in_bus_reset:1;
- unsigned is_shutdown:1;
- unsigned resume_packet_sent:1;
-
- /* this nodes' duties on the bus */
- unsigned is_root:1;
- unsigned is_cycmst:1;
- unsigned is_irm:1;
- unsigned is_busmgr:1;
-
- int reset_retries;
- quadlet_t *topology_map;
- u8 *speed_map;
-
- int id;
- struct hpsb_host_driver *driver;
- struct pci_dev *pdev;
- struct device device;
- struct device host_dev;
-
- struct delayed_work delayed_reset;
- unsigned config_roms:31;
- unsigned update_config_rom:1;
-
- struct list_head addr_space;
- u64 low_addr_space; /* upper bound of physical DMA area */
- u64 middle_addr_space; /* upper bound of posted write area */
-
- u8 speed[ALL_NODES]; /* speed between each node and local node */
-
- /* per node tlabel allocation */
- u8 next_tl[ALL_NODES];
- struct { DECLARE_BITMAP(map, 64); } tl_pool[ALL_NODES];
-
- struct csr_control csr;
-
- struct hpsb_address_serve dummy_zero_addr;
- struct hpsb_address_serve dummy_max_addr;
-};
-
-enum devctl_cmd {
- /* Host is requested to reset its bus and cancel all outstanding async
- * requests. If arg == 1, it shall also attempt to become root on the
- * bus. Return void. */
- RESET_BUS,
-
- /* Arg is void, return value is the hardware cycle counter value. */
- GET_CYCLE_COUNTER,
-
- /* Set the hardware cycle counter to the value in arg, return void.
- * FIXME - setting is probably not required. */
- SET_CYCLE_COUNTER,
-
- /* Configure hardware for new bus ID in arg, return void. */
- SET_BUS_ID,
-
- /* If arg true, start sending cycle start packets, stop if arg == 0.
- * Return void. */
- ACT_CYCLE_MASTER,
-
- /* Cancel all outstanding async requests without resetting the bus.
- * Return void. */
- CANCEL_REQUESTS,
-};
-
-enum isoctl_cmd {
- /* rawiso API - see iso.h for the meanings of these commands
- * (they correspond exactly to the hpsb_iso_* API functions)
- * INIT = allocate resources
- * START = begin transmission/reception
- * STOP = halt transmission/reception
- * QUEUE/RELEASE = produce/consume packets
- * SHUTDOWN = deallocate resources
- */
-
- XMIT_INIT,
- XMIT_START,
- XMIT_STOP,
- XMIT_QUEUE,
- XMIT_SHUTDOWN,
-
- RECV_INIT,
- RECV_LISTEN_CHANNEL, /* multi-channel only */
- RECV_UNLISTEN_CHANNEL, /* multi-channel only */
- RECV_SET_CHANNEL_MASK, /* multi-channel only; arg is a *u64 */
- RECV_START,
- RECV_STOP,
- RECV_RELEASE,
- RECV_SHUTDOWN,
- RECV_FLUSH
-};
-
-enum reset_types {
- /* 166 microsecond reset -- only type of reset available on
- non-1394a capable controllers */
- LONG_RESET,
-
- /* Short (arbitrated) reset -- only available on 1394a capable
- controllers */
- SHORT_RESET,
-
- /* Variants that set force_root before issueing the bus reset */
- LONG_RESET_FORCE_ROOT, SHORT_RESET_FORCE_ROOT,
-
- /* Variants that clear force_root before issueing the bus reset */
- LONG_RESET_NO_FORCE_ROOT, SHORT_RESET_NO_FORCE_ROOT
-};
-
-struct hpsb_host_driver {
- struct module *owner;
- const char *name;
-
- /* The hardware driver may optionally support a function that is used
- * to set the hardware ConfigROM if the hardware supports handling
- * reads to the ConfigROM on its own. */
- void (*set_hw_config_rom)(struct hpsb_host *host,
- __be32 *config_rom);
-
- /* This function shall implement packet transmission based on
- * packet->type. It shall CRC both parts of the packet (unless
- * packet->type == raw) and do byte-swapping as necessary or instruct
- * the hardware to do so. It can return immediately after the packet
- * was queued for sending. After sending, hpsb_sent_packet() has to be
- * called. Return 0 on success, negative errno on failure.
- * NOTE: The function must be callable in interrupt context.
- */
- int (*transmit_packet)(struct hpsb_host *host,
- struct hpsb_packet *packet);
-
- /* This function requests miscellanous services from the driver, see
- * above for command codes and expected actions. Return -1 for unknown
- * command, though that should never happen.
- */
- int (*devctl)(struct hpsb_host *host, enum devctl_cmd command, int arg);
-
- /* ISO transmission/reception functions. Return 0 on success, -1
- * (or -EXXX errno code) on failure. If the low-level driver does not
- * support the new ISO API, set isoctl to NULL.
- */
- int (*isoctl)(struct hpsb_iso *iso, enum isoctl_cmd command,
- unsigned long arg);
-
- /* This function is mainly to redirect local CSR reads/locks to the iso
- * management registers (bus manager id, bandwidth available, channels
- * available) to the hardware registers in OHCI. reg is 0,1,2,3 for bus
- * mgr, bwdth avail, ch avail hi, ch avail lo respectively (the same ids
- * as OHCI uses). data and compare are the new data and expected data
- * respectively, return value is the old value.
- */
- quadlet_t (*hw_csr_reg) (struct hpsb_host *host, int reg,
- quadlet_t data, quadlet_t compare);
-};
-
-struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
- struct device *dev);
-int hpsb_add_host(struct hpsb_host *host);
-void hpsb_resume_host(struct hpsb_host *host);
-void hpsb_remove_host(struct hpsb_host *host);
-int hpsb_update_config_rom_image(struct hpsb_host *host);
-
-#endif /* _IEEE1394_HOSTS_H */
diff --git a/drivers/ieee1394/ieee1394-ioctl.h b/drivers/ieee1394/ieee1394-ioctl.h
deleted file mode 100644
index 46878fef136c..000000000000
--- a/drivers/ieee1394/ieee1394-ioctl.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Base file for all ieee1394 ioctl's.
- * Linux-1394 has allocated base '#' with a range of 0x00-0x3f.
- */
-
-#ifndef __IEEE1394_IOCTL_H
-#define __IEEE1394_IOCTL_H
-
-#include <linux/ioctl.h>
-#include <linux/types.h>
-
-/* DV1394 Gets 10 */
-
-/* Get the driver ready to transmit video. pass a struct dv1394_init* as
- * the parameter (see below), or NULL to get default parameters */
-#define DV1394_IOC_INIT _IOW('#', 0x06, struct dv1394_init)
-
-/* Stop transmitting video and free the ringbuffer */
-#define DV1394_IOC_SHUTDOWN _IO ('#', 0x07)
-
-/* Submit N new frames to be transmitted, where the index of the first new
- * frame is first_clear_buffer, and the index of the last new frame is
- * (first_clear_buffer + N) % n_frames */
-#define DV1394_IOC_SUBMIT_FRAMES _IO ('#', 0x08)
-
-/* Block until N buffers are clear (pass N as the parameter) Because we
- * re-transmit the last frame on underrun, there will at most be n_frames
- * - 1 clear frames at any time */
-#define DV1394_IOC_WAIT_FRAMES _IO ('#', 0x09)
-
-/* Capture new frames that have been received, where the index of the
- * first new frame is first_clear_buffer, and the index of the last new
- * frame is (first_clear_buffer + N) % n_frames */
-#define DV1394_IOC_RECEIVE_FRAMES _IO ('#', 0x0a)
-
-/* Tell card to start receiving DMA */
-#define DV1394_IOC_START_RECEIVE _IO ('#', 0x0b)
-
-/* Pass a struct dv1394_status* as the parameter */
-#define DV1394_IOC_GET_STATUS _IOR('#', 0x0c, struct dv1394_status)
-
-
-/* Video1394 Gets 10 */
-
-#define VIDEO1394_IOC_LISTEN_CHANNEL \
- _IOWR('#', 0x10, struct video1394_mmap)
-#define VIDEO1394_IOC_UNLISTEN_CHANNEL \
- _IOW ('#', 0x11, int)
-#define VIDEO1394_IOC_LISTEN_QUEUE_BUFFER \
- _IOW ('#', 0x12, struct video1394_wait)
-#define VIDEO1394_IOC_LISTEN_WAIT_BUFFER \
- _IOWR('#', 0x13, struct video1394_wait)
-#define VIDEO1394_IOC_TALK_CHANNEL \
- _IOWR('#', 0x14, struct video1394_mmap)
-#define VIDEO1394_IOC_UNTALK_CHANNEL \
- _IOW ('#', 0x15, int)
-/*
- * This one is broken: it really wanted
- * "sizeof (struct video1394_wait) + sizeof (struct video1394_queue_variable)"
- * but got just a "size_t"
- */
-#define VIDEO1394_IOC_TALK_QUEUE_BUFFER \
- _IOW ('#', 0x16, size_t)
-#define VIDEO1394_IOC_TALK_WAIT_BUFFER \
- _IOW ('#', 0x17, struct video1394_wait)
-#define VIDEO1394_IOC_LISTEN_POLL_BUFFER \
- _IOWR('#', 0x18, struct video1394_wait)
-
-
-/* Raw1394's ISO interface */
-#define RAW1394_IOC_ISO_XMIT_INIT \
- _IOW ('#', 0x1a, struct raw1394_iso_status)
-#define RAW1394_IOC_ISO_RECV_INIT \
- _IOWR('#', 0x1b, struct raw1394_iso_status)
-#define RAW1394_IOC_ISO_RECV_START \
- _IOC (_IOC_WRITE, '#', 0x1c, sizeof(int) * 3)
-#define RAW1394_IOC_ISO_XMIT_START \
- _IOC (_IOC_WRITE, '#', 0x1d, sizeof(int) * 2)
-#define RAW1394_IOC_ISO_XMIT_RECV_STOP \
- _IO ('#', 0x1e)
-#define RAW1394_IOC_ISO_GET_STATUS \
- _IOR ('#', 0x1f, struct raw1394_iso_status)
-#define RAW1394_IOC_ISO_SHUTDOWN \
- _IO ('#', 0x20)
-#define RAW1394_IOC_ISO_QUEUE_ACTIVITY \
- _IO ('#', 0x21)
-#define RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL \
- _IOW ('#', 0x22, unsigned char)
-#define RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL \
- _IOW ('#', 0x23, unsigned char)
-#define RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK \
- _IOW ('#', 0x24, __u64)
-#define RAW1394_IOC_ISO_RECV_PACKETS \
- _IOW ('#', 0x25, struct raw1394_iso_packets)
-#define RAW1394_IOC_ISO_RECV_RELEASE_PACKETS \
- _IOW ('#', 0x26, unsigned int)
-#define RAW1394_IOC_ISO_XMIT_PACKETS \
- _IOW ('#', 0x27, struct raw1394_iso_packets)
-#define RAW1394_IOC_ISO_XMIT_SYNC \
- _IO ('#', 0x28)
-#define RAW1394_IOC_ISO_RECV_FLUSH \
- _IO ('#', 0x29)
-#define RAW1394_IOC_GET_CYCLE_TIMER \
- _IOR ('#', 0x30, struct raw1394_cycle_timer)
-
-#endif /* __IEEE1394_IOCTL_H */
diff --git a/drivers/ieee1394/ieee1394.h b/drivers/ieee1394/ieee1394.h
deleted file mode 100644
index af320e2c5079..000000000000
--- a/drivers/ieee1394/ieee1394.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Generic IEEE 1394 definitions
- */
-
-#ifndef _IEEE1394_IEEE1394_H
-#define _IEEE1394_IEEE1394_H
-
-#define TCODE_WRITEQ 0x0
-#define TCODE_WRITEB 0x1
-#define TCODE_WRITE_RESPONSE 0x2
-#define TCODE_READQ 0x4
-#define TCODE_READB 0x5
-#define TCODE_READQ_RESPONSE 0x6
-#define TCODE_READB_RESPONSE 0x7
-#define TCODE_CYCLE_START 0x8
-#define TCODE_LOCK_REQUEST 0x9
-#define TCODE_ISO_DATA 0xa
-#define TCODE_STREAM_DATA 0xa
-#define TCODE_LOCK_RESPONSE 0xb
-
-#define RCODE_COMPLETE 0x0
-#define RCODE_CONFLICT_ERROR 0x4
-#define RCODE_DATA_ERROR 0x5
-#define RCODE_TYPE_ERROR 0x6
-#define RCODE_ADDRESS_ERROR 0x7
-
-#define EXTCODE_MASK_SWAP 0x1
-#define EXTCODE_COMPARE_SWAP 0x2
-#define EXTCODE_FETCH_ADD 0x3
-#define EXTCODE_LITTLE_ADD 0x4
-#define EXTCODE_BOUNDED_ADD 0x5
-#define EXTCODE_WRAP_ADD 0x6
-
-#define ACK_COMPLETE 0x1
-#define ACK_PENDING 0x2
-#define ACK_BUSY_X 0x4
-#define ACK_BUSY_A 0x5
-#define ACK_BUSY_B 0x6
-#define ACK_TARDY 0xb
-#define ACK_CONFLICT_ERROR 0xc
-#define ACK_DATA_ERROR 0xd
-#define ACK_TYPE_ERROR 0xe
-#define ACK_ADDRESS_ERROR 0xf
-
-/* Non-standard "ACK codes" for internal use */
-#define ACKX_NONE (-1)
-#define ACKX_SEND_ERROR (-2)
-#define ACKX_ABORTED (-3)
-#define ACKX_TIMEOUT (-4)
-
-#define IEEE1394_SPEED_100 0x00
-#define IEEE1394_SPEED_200 0x01
-#define IEEE1394_SPEED_400 0x02
-#define IEEE1394_SPEED_800 0x03
-#define IEEE1394_SPEED_1600 0x04
-#define IEEE1394_SPEED_3200 0x05
-#define IEEE1394_SPEED_MAX IEEE1394_SPEED_3200
-
-/* Maps speed values above to a string representation */
-extern const char *hpsb_speedto_str[];
-
-/* 1394a cable PHY packets */
-#define SELFID_PWRCL_NO_POWER 0x0
-#define SELFID_PWRCL_PROVIDE_15W 0x1
-#define SELFID_PWRCL_PROVIDE_30W 0x2
-#define SELFID_PWRCL_PROVIDE_45W 0x3
-#define SELFID_PWRCL_USE_1W 0x4
-#define SELFID_PWRCL_USE_3W 0x5
-#define SELFID_PWRCL_USE_6W 0x6
-#define SELFID_PWRCL_USE_10W 0x7
-
-#define SELFID_PORT_CHILD 0x3
-#define SELFID_PORT_PARENT 0x2
-#define SELFID_PORT_NCONN 0x1
-#define SELFID_PORT_NONE 0x0
-
-#define SELFID_SPEED_UNKNOWN 0x3 /* 1394b PHY */
-
-#define PHYPACKET_LINKON 0x40000000
-#define PHYPACKET_PHYCONFIG_R 0x00800000
-#define PHYPACKET_PHYCONFIG_T 0x00400000
-#define EXTPHYPACKET_TYPE_PING 0x00000000
-#define EXTPHYPACKET_TYPE_REMOTEACCESS_BASE 0x00040000
-#define EXTPHYPACKET_TYPE_REMOTEACCESS_PAGED 0x00140000
-#define EXTPHYPACKET_TYPE_REMOTEREPLY_BASE 0x000C0000
-#define EXTPHYPACKET_TYPE_REMOTEREPLY_PAGED 0x001C0000
-#define EXTPHYPACKET_TYPE_REMOTECOMMAND 0x00200000
-#define EXTPHYPACKET_TYPE_REMOTECONFIRMATION 0x00280000
-#define EXTPHYPACKET_TYPE_RESUME 0x003C0000
-
-#define EXTPHYPACKET_TYPEMASK 0xC0FC0000
-
-#define PHYPACKET_PORT_SHIFT 24
-#define PHYPACKET_GAPCOUNT_SHIFT 16
-
-/* 1394a PHY register map bitmasks */
-#define PHY_00_PHYSICAL_ID 0xFC
-#define PHY_00_R 0x02 /* Root */
-#define PHY_00_PS 0x01 /* Power Status*/
-#define PHY_01_RHB 0x80 /* Root Hold-Off */
-#define PHY_01_IBR 0x80 /* Initiate Bus Reset */
-#define PHY_01_GAP_COUNT 0x3F
-#define PHY_02_EXTENDED 0xE0 /* 0x7 for 1394a-compliant PHY */
-#define PHY_02_TOTAL_PORTS 0x1F
-#define PHY_03_MAX_SPEED 0xE0
-#define PHY_03_DELAY 0x0F
-#define PHY_04_LCTRL 0x80 /* Link Active Report Control */
-#define PHY_04_CONTENDER 0x40
-#define PHY_04_JITTER 0x38
-#define PHY_04_PWR_CLASS 0x07 /* Power Class */
-#define PHY_05_WATCHDOG 0x80
-#define PHY_05_ISBR 0x40 /* Initiate Short Bus Reset */
-#define PHY_05_LOOP 0x20 /* Loop Detect */
-#define PHY_05_PWR_FAIL 0x10 /* Cable Power Failure Detect */
-#define PHY_05_TIMEOUT 0x08 /* Arbitration State Machine Timeout */
-#define PHY_05_PORT_EVENT 0x04 /* Port Event Detect */
-#define PHY_05_ENAB_ACCEL 0x02 /* Enable Arbitration Acceleration */
-#define PHY_05_ENAB_MULTI 0x01 /* Ena. Multispeed Packet Concatenation */
-
-#include <asm/byteorder.h>
-
-/* '1' '3' '9' '4' in ASCII */
-#define IEEE1394_BUSID_MAGIC cpu_to_be32(0x31333934)
-
-#ifdef __BIG_ENDIAN_BITFIELD
-
-struct selfid {
- u32 packet_identifier:2; /* always binary 10 */
- u32 phy_id:6;
- /* byte */
- u32 extended:1; /* if true is struct ext_selfid */
- u32 link_active:1;
- u32 gap_count:6;
- /* byte */
- u32 speed:2;
- u32 phy_delay:2;
- u32 contender:1;
- u32 power_class:3;
- /* byte */
- u32 port0:2;
- u32 port1:2;
- u32 port2:2;
- u32 initiated_reset:1;
- u32 more_packets:1;
-} __attribute__((packed));
-
-struct ext_selfid {
- u32 packet_identifier:2; /* always binary 10 */
- u32 phy_id:6;
- /* byte */
- u32 extended:1; /* if false is struct selfid */
- u32 seq_nr:3;
- u32 reserved:2;
- u32 porta:2;
- /* byte */
- u32 portb:2;
- u32 portc:2;
- u32 portd:2;
- u32 porte:2;
- /* byte */
- u32 portf:2;
- u32 portg:2;
- u32 porth:2;
- u32 reserved2:1;
- u32 more_packets:1;
-} __attribute__((packed));
-
-#elif defined __LITTLE_ENDIAN_BITFIELD /* __BIG_ENDIAN_BITFIELD */
-
-/*
- * Note: these mean to be bit fields of a big endian SelfID as seen on a little
- * endian machine. Without swapping.
- */
-
-struct selfid {
- u32 phy_id:6;
- u32 packet_identifier:2; /* always binary 10 */
- /* byte */
- u32 gap_count:6;
- u32 link_active:1;
- u32 extended:1; /* if true is struct ext_selfid */
- /* byte */
- u32 power_class:3;
- u32 contender:1;
- u32 phy_delay:2;
- u32 speed:2;
- /* byte */
- u32 more_packets:1;
- u32 initiated_reset:1;
- u32 port2:2;
- u32 port1:2;
- u32 port0:2;
-} __attribute__((packed));
-
-struct ext_selfid {
- u32 phy_id:6;
- u32 packet_identifier:2; /* always binary 10 */
- /* byte */
- u32 porta:2;
- u32 reserved:2;
- u32 seq_nr:3;
- u32 extended:1; /* if false is struct selfid */
- /* byte */
- u32 porte:2;
- u32 portd:2;
- u32 portc:2;
- u32 portb:2;
- /* byte */
- u32 more_packets:1;
- u32 reserved2:1;
- u32 porth:2;
- u32 portg:2;
- u32 portf:2;
-} __attribute__((packed));
-
-#else
-#error What? PDP endian?
-#endif /* __BIG_ENDIAN_BITFIELD */
-
-#endif /* _IEEE1394_IEEE1394_H */
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
deleted file mode 100644
index 872338003721..000000000000
--- a/drivers/ieee1394/ieee1394_core.c
+++ /dev/null
@@ -1,1380 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Core support: hpsb_packet management, packet handling and forwarding to
- * highlevel or lowlevel code
- *
- * Copyright (C) 1999, 2000 Andreas E. Bombe
- * 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- * loopback functionality in hpsb_send_packet
- * allow highlevel drivers to disable automatic response generation
- * and to generate responses themselves (deferred)
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/bitops.h>
-#include <linux/kdev_t.h>
-#include <linux/freezer.h>
-#include <linux/suspend.h>
-#include <linux/kthread.h>
-#include <linux/preempt.h>
-#include <linux/time.h>
-
-#include <asm/system.h>
-#include <asm/byteorder.h>
-
-#include "ieee1394_types.h"
-#include "ieee1394.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "ieee1394_transactions.h"
-#include "csr.h"
-#include "nodemgr.h"
-#include "dma.h"
-#include "iso.h"
-#include "config_roms.h"
-
-/*
- * Disable the nodemgr detection and config rom reading functionality.
- */
-static int disable_nodemgr;
-module_param(disable_nodemgr, int, 0444);
-MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
-
-/* Disable Isochronous Resource Manager functionality */
-int hpsb_disable_irm = 0;
-module_param_named(disable_irm, hpsb_disable_irm, bool, 0444);
-MODULE_PARM_DESC(disable_irm,
- "Disable Isochronous Resource Manager functionality.");
-
-/* We are GPL, so treat us special */
-MODULE_LICENSE("GPL");
-
-/* Some globals used */
-const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" };
-struct class *hpsb_protocol_class;
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-static void dump_packet(const char *text, quadlet_t *data, int size, int speed)
-{
- int i;
-
- size /= 4;
- size = (size > 4 ? 4 : size);
-
- printk(KERN_DEBUG "ieee1394: %s", text);
- if (speed > -1 && speed < 6)
- printk(" at %s", hpsb_speedto_str[speed]);
- printk(":");
- for (i = 0; i < size; i++)
- printk(" %08x", data[i]);
- printk("\n");
-}
-#else
-#define dump_packet(a,b,c,d) do {} while (0)
-#endif
-
-static void abort_requests(struct hpsb_host *host);
-static void queue_packet_complete(struct hpsb_packet *packet);
-
-
-/**
- * hpsb_set_packet_complete_task - set task that runs when a packet completes
- * @packet: the packet whose completion we want the task added to
- * @routine: function to call
- * @data: data (if any) to pass to the above function
- *
- * Set the task that runs when a packet completes. You cannot call this more
- * than once on a single packet before it is sent.
- *
- * Typically, the complete @routine is responsible to call hpsb_free_packet().
- */
-void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
- void (*routine)(void *), void *data)
-{
- WARN_ON(packet->complete_routine != NULL);
- packet->complete_routine = routine;
- packet->complete_data = data;
- return;
-}
-
-/**
- * hpsb_alloc_packet - allocate new packet structure
- * @data_size: size of the data block to be allocated, in bytes
- *
- * This function allocates, initializes and returns a new &struct hpsb_packet.
- * It can be used in interrupt context. A header block is always included and
- * initialized with zeros. Its size is big enough to contain all possible 1394
- * headers. The data block is only allocated if @data_size is not zero.
- *
- * For packets for which responses will be received the @data_size has to be big
- * enough to contain the response's data block since no further allocation
- * occurs at response matching time.
- *
- * The packet's generation value will be set to the current generation number
- * for ease of use. Remember to overwrite it with your own recorded generation
- * number if you can not be sure that your code will not race with a bus reset.
- *
- * Return value: A pointer to a &struct hpsb_packet or NULL on allocation
- * failure.
- */
-struct hpsb_packet *hpsb_alloc_packet(size_t data_size)
-{
- struct hpsb_packet *packet;
-
- data_size = ((data_size + 3) & ~3);
-
- packet = kzalloc(sizeof(*packet) + data_size, GFP_ATOMIC);
- if (!packet)
- return NULL;
-
- packet->state = hpsb_unused;
- packet->generation = -1;
- INIT_LIST_HEAD(&packet->driver_list);
- INIT_LIST_HEAD(&packet->queue);
- atomic_set(&packet->refcnt, 1);
-
- if (data_size) {
- packet->data = packet->embedded_data;
- packet->allocated_data_size = data_size;
- }
- return packet;
-}
-
-/**
- * hpsb_free_packet - free packet and data associated with it
- * @packet: packet to free (is NULL safe)
- *
- * Frees @packet->data only if it was allocated through hpsb_alloc_packet().
- */
-void hpsb_free_packet(struct hpsb_packet *packet)
-{
- if (packet && atomic_dec_and_test(&packet->refcnt)) {
- BUG_ON(!list_empty(&packet->driver_list) ||
- !list_empty(&packet->queue));
- kfree(packet);
- }
-}
-
-/**
- * hpsb_reset_bus - initiate bus reset on the given host
- * @host: host controller whose bus to reset
- * @type: one of enum reset_types
- *
- * Returns 1 if bus reset already in progress, 0 otherwise.
- */
-int hpsb_reset_bus(struct hpsb_host *host, int type)
-{
- if (!host->in_bus_reset) {
- host->driver->devctl(host, RESET_BUS, type);
- return 0;
- } else {
- return 1;
- }
-}
-
-/**
- * hpsb_read_cycle_timer - read cycle timer register and system time
- * @host: host whose isochronous cycle timer register is read
- * @cycle_timer: address of bitfield to return the register contents
- * @local_time: address to return the system time
- *
- * The format of * @cycle_timer, is described in OHCI 1.1 clause 5.13. This
- * format is also read from non-OHCI controllers. * @local_time contains the
- * system time in microseconds since the Epoch, read at the moment when the
- * cycle timer was read.
- *
- * Return value: 0 for success or error number otherwise.
- */
-int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
- u64 *local_time)
-{
- int ctr;
- struct timeval tv;
- unsigned long flags;
-
- if (!host || !cycle_timer || !local_time)
- return -EINVAL;
-
- preempt_disable();
- local_irq_save(flags);
-
- ctr = host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
- if (ctr)
- do_gettimeofday(&tv);
-
- local_irq_restore(flags);
- preempt_enable();
-
- if (!ctr)
- return -EIO;
- *cycle_timer = ctr;
- *local_time = tv.tv_sec * 1000000ULL + tv.tv_usec;
- return 0;
-}
-
-/**
- * hpsb_bus_reset - notify a bus reset to the core
- *
- * For host driver module usage. Safe to use in interrupt context, although
- * quite complex; so you may want to run it in the bottom rather than top half.
- *
- * Returns 1 if bus reset already in progress, 0 otherwise.
- */
-int hpsb_bus_reset(struct hpsb_host *host)
-{
- if (host->in_bus_reset) {
- HPSB_NOTICE("%s called while bus reset already in progress",
- __func__);
- return 1;
- }
-
- abort_requests(host);
- host->in_bus_reset = 1;
- host->irm_id = -1;
- host->is_irm = 0;
- host->busmgr_id = -1;
- host->is_busmgr = 0;
- host->is_cycmst = 0;
- host->node_count = 0;
- host->selfid_count = 0;
-
- return 0;
-}
-
-
-/*
- * Verify num_of_selfids SelfIDs and return number of nodes. Return zero in
- * case verification failed.
- */
-static int check_selfids(struct hpsb_host *host)
-{
- int nodeid = -1;
- int rest_of_selfids = host->selfid_count;
- struct selfid *sid = (struct selfid *)host->topology_map;
- struct ext_selfid *esid;
- int esid_seq = 23;
-
- host->nodes_active = 0;
-
- while (rest_of_selfids--) {
- if (!sid->extended) {
- nodeid++;
- esid_seq = 0;
-
- if (sid->phy_id != nodeid) {
- HPSB_INFO("SelfIDs failed monotony check with "
- "%d", sid->phy_id);
- return 0;
- }
-
- if (sid->link_active) {
- host->nodes_active++;
- if (sid->contender)
- host->irm_id = LOCAL_BUS | sid->phy_id;
- }
- } else {
- esid = (struct ext_selfid *)sid;
-
- if ((esid->phy_id != nodeid)
- || (esid->seq_nr != esid_seq)) {
- HPSB_INFO("SelfIDs failed monotony check with "
- "%d/%d", esid->phy_id, esid->seq_nr);
- return 0;
- }
- esid_seq++;
- }
- sid++;
- }
-
- esid = (struct ext_selfid *)(sid - 1);
- while (esid->extended) {
- if ((esid->porta == SELFID_PORT_PARENT) ||
- (esid->portb == SELFID_PORT_PARENT) ||
- (esid->portc == SELFID_PORT_PARENT) ||
- (esid->portd == SELFID_PORT_PARENT) ||
- (esid->porte == SELFID_PORT_PARENT) ||
- (esid->portf == SELFID_PORT_PARENT) ||
- (esid->portg == SELFID_PORT_PARENT) ||
- (esid->porth == SELFID_PORT_PARENT)) {
- HPSB_INFO("SelfIDs failed root check on "
- "extended SelfID");
- return 0;
- }
- esid--;
- }
-
- sid = (struct selfid *)esid;
- if ((sid->port0 == SELFID_PORT_PARENT) ||
- (sid->port1 == SELFID_PORT_PARENT) ||
- (sid->port2 == SELFID_PORT_PARENT)) {
- HPSB_INFO("SelfIDs failed root check");
- return 0;
- }
-
- host->node_count = nodeid + 1;
- return 1;
-}
-
-static void build_speed_map(struct hpsb_host *host, int nodecount)
-{
- u8 cldcnt[nodecount];
- u8 *map = host->speed_map;
- u8 *speedcap = host->speed;
- u8 local_link_speed = host->csr.lnk_spd;
- struct selfid *sid;
- struct ext_selfid *esid;
- int i, j, n;
-
- for (i = 0; i < (nodecount * 64); i += 64) {
- for (j = 0; j < nodecount; j++) {
- map[i+j] = IEEE1394_SPEED_MAX;
- }
- }
-
- for (i = 0; i < nodecount; i++) {
- cldcnt[i] = 0;
- }
-
- /* find direct children count and speed */
- for (sid = (struct selfid *)&host->topology_map[host->selfid_count-1],
- n = nodecount - 1;
- (void *)sid >= (void *)host->topology_map; sid--) {
- if (sid->extended) {
- esid = (struct ext_selfid *)sid;
-
- if (esid->porta == SELFID_PORT_CHILD) cldcnt[n]++;
- if (esid->portb == SELFID_PORT_CHILD) cldcnt[n]++;
- if (esid->portc == SELFID_PORT_CHILD) cldcnt[n]++;
- if (esid->portd == SELFID_PORT_CHILD) cldcnt[n]++;
- if (esid->porte == SELFID_PORT_CHILD) cldcnt[n]++;
- if (esid->portf == SELFID_PORT_CHILD) cldcnt[n]++;
- if (esid->portg == SELFID_PORT_CHILD) cldcnt[n]++;
- if (esid->porth == SELFID_PORT_CHILD) cldcnt[n]++;
- } else {
- if (sid->port0 == SELFID_PORT_CHILD) cldcnt[n]++;
- if (sid->port1 == SELFID_PORT_CHILD) cldcnt[n]++;
- if (sid->port2 == SELFID_PORT_CHILD) cldcnt[n]++;
-
- speedcap[n] = sid->speed;
- if (speedcap[n] > local_link_speed)
- speedcap[n] = local_link_speed;
- n--;
- }
- }
-
- /* set self mapping */
- for (i = 0; i < nodecount; i++) {
- map[64*i + i] = speedcap[i];
- }
-
- /* fix up direct children count to total children count;
- * also fix up speedcaps for sibling and parent communication */
- for (i = 1; i < nodecount; i++) {
- for (j = cldcnt[i], n = i - 1; j > 0; j--) {
- cldcnt[i] += cldcnt[n];
- speedcap[n] = min(speedcap[n], speedcap[i]);
- n -= cldcnt[n] + 1;
- }
- }
-
- for (n = 0; n < nodecount; n++) {
- for (i = n - cldcnt[n]; i <= n; i++) {
- for (j = 0; j < (n - cldcnt[n]); j++) {
- map[j*64 + i] = map[i*64 + j] =
- min(map[i*64 + j], speedcap[n]);
- }
- for (j = n + 1; j < nodecount; j++) {
- map[j*64 + i] = map[i*64 + j] =
- min(map[i*64 + j], speedcap[n]);
- }
- }
- }
-
- /* assume a maximum speed for 1394b PHYs, nodemgr will correct it */
- if (local_link_speed > SELFID_SPEED_UNKNOWN)
- for (i = 0; i < nodecount; i++)
- if (speedcap[i] == SELFID_SPEED_UNKNOWN)
- speedcap[i] = local_link_speed;
-}
-
-
-/**
- * hpsb_selfid_received - hand over received selfid packet to the core
- *
- * For host driver module usage. Safe to use in interrupt context.
- *
- * The host driver should have done a successful complement check (second
- * quadlet is complement of first) beforehand.
- */
-void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
-{
- if (host->in_bus_reset) {
- HPSB_VERBOSE("Including SelfID 0x%x", sid);
- host->topology_map[host->selfid_count++] = sid;
- } else {
- HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from bus %d",
- sid, NODEID_TO_BUS(host->node_id));
- }
-}
-
-/**
- * hpsb_selfid_complete - notify completion of SelfID stage to the core
- *
- * For host driver module usage. Safe to use in interrupt context, although
- * quite complex; so you may want to run it in the bottom rather than top half.
- *
- * Notify completion of SelfID stage to the core and report new physical ID
- * and whether host is root now.
- */
-void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
-{
- if (!host->in_bus_reset)
- HPSB_NOTICE("SelfID completion called outside of bus reset!");
-
- host->node_id = LOCAL_BUS | phyid;
- host->is_root = isroot;
-
- if (!check_selfids(host)) {
- if (host->reset_retries++ < 20) {
- /* selfid stage did not complete without error */
- HPSB_NOTICE("Error in SelfID stage, resetting");
- host->in_bus_reset = 0;
- /* this should work from ohci1394 now... */
- hpsb_reset_bus(host, LONG_RESET);
- return;
- } else {
- HPSB_NOTICE("Stopping out-of-control reset loop");
- HPSB_NOTICE("Warning - topology map and speed map will not be valid");
- host->reset_retries = 0;
- }
- } else {
- host->reset_retries = 0;
- build_speed_map(host, host->node_count);
- }
-
- HPSB_VERBOSE("selfid_complete called with successful SelfID stage "
- "... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id);
-
- /* irm_id is kept up to date by check_selfids() */
- if (host->irm_id == host->node_id) {
- host->is_irm = 1;
- } else {
- host->is_busmgr = 0;
- host->is_irm = 0;
- }
-
- if (isroot) {
- host->driver->devctl(host, ACT_CYCLE_MASTER, 1);
- host->is_cycmst = 1;
- }
- atomic_inc(&host->generation);
- host->in_bus_reset = 0;
- highlevel_host_reset(host);
-}
-
-static DEFINE_SPINLOCK(pending_packets_lock);
-
-/**
- * hpsb_packet_sent - notify core of sending a packet
- *
- * For host driver module usage. Safe to call from within a transmit packet
- * routine.
- *
- * Notify core of sending a packet. Ackcode is the ack code returned for async
- * transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE
- * for other cases (internal errors that don't justify a panic).
- */
-void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
- int ackcode)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&pending_packets_lock, flags);
-
- packet->ack_code = ackcode;
-
- if (packet->no_waiter || packet->state == hpsb_complete) {
- /* if packet->no_waiter, must not have a tlabel allocated */
- spin_unlock_irqrestore(&pending_packets_lock, flags);
- hpsb_free_packet(packet);
- return;
- }
-
- atomic_dec(&packet->refcnt); /* drop HC's reference */
- /* here the packet must be on the host->pending_packets queue */
-
- if (ackcode != ACK_PENDING || !packet->expect_response) {
- packet->state = hpsb_complete;
- list_del_init(&packet->queue);
- spin_unlock_irqrestore(&pending_packets_lock, flags);
- queue_packet_complete(packet);
- return;
- }
-
- packet->state = hpsb_pending;
- packet->sendtime = jiffies;
-
- spin_unlock_irqrestore(&pending_packets_lock, flags);
-
- mod_timer(&host->timeout, jiffies + host->timeout_interval);
-}
-
-/**
- * hpsb_send_phy_config - transmit a PHY configuration packet on the bus
- * @host: host that PHY config packet gets sent through
- * @rootid: root whose force_root bit should get set (-1 = don't set force_root)
- * @gapcnt: gap count value to set (-1 = don't set gap count)
- *
- * This function sends a PHY config packet on the bus through the specified
- * host.
- *
- * Return value: 0 for success or negative error number otherwise.
- */
-int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt)
-{
- struct hpsb_packet *packet;
- quadlet_t d = 0;
- int retval = 0;
-
- if (rootid >= ALL_NODES || rootid < -1 || gapcnt > 0x3f || gapcnt < -1 ||
- (rootid == -1 && gapcnt == -1)) {
- HPSB_DEBUG("Invalid Parameter: rootid = %d gapcnt = %d",
- rootid, gapcnt);
- return -EINVAL;
- }
-
- if (rootid != -1)
- d |= PHYPACKET_PHYCONFIG_R | rootid << PHYPACKET_PORT_SHIFT;
- if (gapcnt != -1)
- d |= PHYPACKET_PHYCONFIG_T | gapcnt << PHYPACKET_GAPCOUNT_SHIFT;
-
- packet = hpsb_make_phypacket(host, d);
- if (!packet)
- return -ENOMEM;
-
- packet->generation = get_hpsb_generation(host);
- retval = hpsb_send_packet_and_wait(packet);
- hpsb_free_packet(packet);
-
- return retval;
-}
-
-/**
- * hpsb_send_packet - transmit a packet on the bus
- * @packet: packet to send
- *
- * The packet is sent through the host specified in the packet->host field.
- * Before sending, the packet's transmit speed is automatically determined
- * using the local speed map when it is an async, non-broadcast packet.
- *
- * Possibilities for failure are that host is either not initialized, in bus
- * reset, the packet's generation number doesn't match the current generation
- * number or the host reports a transmit error.
- *
- * Return value: 0 on success, negative errno on failure.
- */
-int hpsb_send_packet(struct hpsb_packet *packet)
-{
- struct hpsb_host *host = packet->host;
-
- if (host->is_shutdown)
- return -EINVAL;
- if (host->in_bus_reset ||
- (packet->generation != get_hpsb_generation(host)))
- return -EAGAIN;
-
- packet->state = hpsb_queued;
-
- /* This just seems silly to me */
- WARN_ON(packet->no_waiter && packet->expect_response);
-
- if (!packet->no_waiter || packet->expect_response) {
- unsigned long flags;
-
- atomic_inc(&packet->refcnt);
- /* Set the initial "sendtime" to 10 seconds from now, to
- prevent premature expiry. If a packet takes more than
- 10 seconds to hit the wire, we have bigger problems :) */
- packet->sendtime = jiffies + 10 * HZ;
- spin_lock_irqsave(&pending_packets_lock, flags);
- list_add_tail(&packet->queue, &host->pending_packets);
- spin_unlock_irqrestore(&pending_packets_lock, flags);
- }
-
- if (packet->node_id == host->node_id) {
- /* it is a local request, so handle it locally */
-
- quadlet_t *data;
- size_t size = packet->data_size + packet->header_size;
-
- data = kmalloc(size, GFP_ATOMIC);
- if (!data) {
- HPSB_ERR("unable to allocate memory for concatenating header and data");
- return -ENOMEM;
- }
-
- memcpy(data, packet->header, packet->header_size);
-
- if (packet->data_size)
- memcpy(((u8*)data) + packet->header_size, packet->data, packet->data_size);
-
- dump_packet("send packet local", packet->header, packet->header_size, -1);
-
- hpsb_packet_sent(host, packet, packet->expect_response ? ACK_PENDING : ACK_COMPLETE);
- hpsb_packet_received(host, data, size, 0);
-
- kfree(data);
-
- return 0;
- }
-
- if (packet->type == hpsb_async &&
- NODEID_TO_NODE(packet->node_id) != ALL_NODES)
- packet->speed_code =
- host->speed[NODEID_TO_NODE(packet->node_id)];
-
- dump_packet("send packet", packet->header, packet->header_size, packet->speed_code);
-
- return host->driver->transmit_packet(host, packet);
-}
-
-/* We could just use complete() directly as the packet complete
- * callback, but this is more typesafe, in the sense that we get a
- * compiler error if the prototype for complete() changes. */
-
-static void complete_packet(void *data)
-{
- complete((struct completion *) data);
-}
-
-/**
- * hpsb_send_packet_and_wait - enqueue packet, block until transaction completes
- * @packet: packet to send
- *
- * Return value: 0 on success, negative errno on failure.
- */
-int hpsb_send_packet_and_wait(struct hpsb_packet *packet)
-{
- struct completion done;
- int retval;
-
- init_completion(&done);
- hpsb_set_packet_complete_task(packet, complete_packet, &done);
- retval = hpsb_send_packet(packet);
- if (retval == 0)
- wait_for_completion(&done);
-
- return retval;
-}
-
-static void send_packet_nocare(struct hpsb_packet *packet)
-{
- if (hpsb_send_packet(packet) < 0) {
- hpsb_free_packet(packet);
- }
-}
-
-static size_t packet_size_to_data_size(size_t packet_size, size_t header_size,
- size_t buffer_size, int tcode)
-{
- size_t ret = packet_size <= header_size ? 0 : packet_size - header_size;
-
- if (unlikely(ret > buffer_size))
- ret = buffer_size;
-
- if (unlikely(ret + header_size != packet_size))
- HPSB_ERR("unexpected packet size %zd (tcode %d), bug?",
- packet_size, tcode);
- return ret;
-}
-
-static void handle_packet_response(struct hpsb_host *host, int tcode,
- quadlet_t *data, size_t size)
-{
- struct hpsb_packet *packet;
- int tlabel = (data[0] >> 10) & 0x3f;
- size_t header_size;
- unsigned long flags;
-
- spin_lock_irqsave(&pending_packets_lock, flags);
-
- list_for_each_entry(packet, &host->pending_packets, queue)
- if (packet->tlabel == tlabel &&
- packet->node_id == (data[1] >> 16))
- goto found;
-
- spin_unlock_irqrestore(&pending_packets_lock, flags);
- HPSB_DEBUG("unsolicited response packet received - %s",
- "no tlabel match");
- dump_packet("contents", data, 16, -1);
- return;
-
-found:
- switch (packet->tcode) {
- case TCODE_WRITEQ:
- case TCODE_WRITEB:
- if (unlikely(tcode != TCODE_WRITE_RESPONSE))
- break;
- header_size = 12;
- size = 0;
- goto dequeue;
-
- case TCODE_READQ:
- if (unlikely(tcode != TCODE_READQ_RESPONSE))
- break;
- header_size = 16;
- size = 0;
- goto dequeue;
-
- case TCODE_READB:
- if (unlikely(tcode != TCODE_READB_RESPONSE))
- break;
- header_size = 16;
- size = packet_size_to_data_size(size, header_size,
- packet->allocated_data_size,
- tcode);
- goto dequeue;
-
- case TCODE_LOCK_REQUEST:
- if (unlikely(tcode != TCODE_LOCK_RESPONSE))
- break;
- header_size = 16;
- size = packet_size_to_data_size(min(size, (size_t)(16 + 8)),
- header_size,
- packet->allocated_data_size,
- tcode);
- goto dequeue;
- }
-
- spin_unlock_irqrestore(&pending_packets_lock, flags);
- HPSB_DEBUG("unsolicited response packet received - %s",
- "tcode mismatch");
- dump_packet("contents", data, 16, -1);
- return;
-
-dequeue:
- list_del_init(&packet->queue);
- spin_unlock_irqrestore(&pending_packets_lock, flags);
-
- if (packet->state == hpsb_queued) {
- packet->sendtime = jiffies;
- packet->ack_code = ACK_PENDING;
- }
- packet->state = hpsb_complete;
-
- memcpy(packet->header, data, header_size);
- if (size)
- memcpy(packet->data, data + 4, size);
-
- queue_packet_complete(packet);
-}
-
-
-static struct hpsb_packet *create_reply_packet(struct hpsb_host *host,
- quadlet_t *data, size_t dsize)
-{
- struct hpsb_packet *p;
-
- p = hpsb_alloc_packet(dsize);
- if (unlikely(p == NULL)) {
- /* FIXME - send data_error response */
- HPSB_ERR("out of memory, cannot send response packet");
- return NULL;
- }
-
- p->type = hpsb_async;
- p->state = hpsb_unused;
- p->host = host;
- p->node_id = data[1] >> 16;
- p->tlabel = (data[0] >> 10) & 0x3f;
- p->no_waiter = 1;
-
- p->generation = get_hpsb_generation(host);
-
- if (dsize % 4)
- p->data[dsize / 4] = 0;
-
- return p;
-}
-
-#define PREP_ASYNC_HEAD_RCODE(tc) \
- packet->tcode = tc; \
- packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
- | (1 << 8) | (tc << 4); \
- packet->header[1] = (packet->host->node_id << 16) | (rcode << 12); \
- packet->header[2] = 0
-
-static void fill_async_readquad_resp(struct hpsb_packet *packet, int rcode,
- quadlet_t data)
-{
- PREP_ASYNC_HEAD_RCODE(TCODE_READQ_RESPONSE);
- packet->header[3] = data;
- packet->header_size = 16;
- packet->data_size = 0;
-}
-
-static void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode,
- int length)
-{
- if (rcode != RCODE_COMPLETE)
- length = 0;
-
- PREP_ASYNC_HEAD_RCODE(TCODE_READB_RESPONSE);
- packet->header[3] = length << 16;
- packet->header_size = 16;
- packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
-}
-
-static void fill_async_write_resp(struct hpsb_packet *packet, int rcode)
-{
- PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE);
- packet->header_size = 12;
- packet->data_size = 0;
-}
-
-static void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extcode,
- int length)
-{
- if (rcode != RCODE_COMPLETE)
- length = 0;
-
- PREP_ASYNC_HEAD_RCODE(TCODE_LOCK_RESPONSE);
- packet->header[3] = (length << 16) | extcode;
- packet->header_size = 16;
- packet->data_size = length;
-}
-
-static void handle_incoming_packet(struct hpsb_host *host, int tcode,
- quadlet_t *data, size_t size,
- int write_acked)
-{
- struct hpsb_packet *packet;
- int length, rcode, extcode;
- quadlet_t buffer;
- nodeid_t source = data[1] >> 16;
- nodeid_t dest = data[0] >> 16;
- u16 flags = (u16) data[0];
- u64 addr;
-
- /* FIXME?
- * Out-of-bounds lengths are left for highlevel_read|write to cap. */
-
- switch (tcode) {
- case TCODE_WRITEQ:
- addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_write(host, source, dest, data + 3,
- addr, 4, flags);
- goto handle_write_request;
-
- case TCODE_WRITEB:
- addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_write(host, source, dest, data + 4,
- addr, data[3] >> 16, flags);
-handle_write_request:
- if (rcode < 0 || write_acked ||
- NODEID_TO_NODE(data[0] >> 16) == NODE_MASK)
- return;
- /* not a broadcast write, reply */
- packet = create_reply_packet(host, data, 0);
- if (packet) {
- fill_async_write_resp(packet, rcode);
- send_packet_nocare(packet);
- }
- return;
-
- case TCODE_READQ:
- addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_read(host, source, &buffer, addr, 4, flags);
- if (rcode < 0)
- return;
-
- packet = create_reply_packet(host, data, 0);
- if (packet) {
- fill_async_readquad_resp(packet, rcode, buffer);
- send_packet_nocare(packet);
- }
- return;
-
- case TCODE_READB:
- length = data[3] >> 16;
- packet = create_reply_packet(host, data, length);
- if (!packet)
- return;
-
- addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_read(host, source, packet->data, addr,
- length, flags);
- if (rcode < 0) {
- hpsb_free_packet(packet);
- return;
- }
- fill_async_readblock_resp(packet, rcode, length);
- send_packet_nocare(packet);
- return;
-
- case TCODE_LOCK_REQUEST:
- length = data[3] >> 16;
- extcode = data[3] & 0xffff;
- addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-
- packet = create_reply_packet(host, data, 8);
- if (!packet)
- return;
-
- if (extcode == 0 || extcode >= 7) {
- /* let switch default handle error */
- length = 0;
- }
-
- switch (length) {
- case 4:
- rcode = highlevel_lock(host, source, packet->data, addr,
- data[4], 0, extcode, flags);
- fill_async_lock_resp(packet, rcode, extcode, 4);
- break;
- case 8:
- if (extcode != EXTCODE_FETCH_ADD &&
- extcode != EXTCODE_LITTLE_ADD) {
- rcode = highlevel_lock(host, source,
- packet->data, addr,
- data[5], data[4],
- extcode, flags);
- fill_async_lock_resp(packet, rcode, extcode, 4);
- } else {
- rcode = highlevel_lock64(host, source,
- (octlet_t *)packet->data, addr,
- *(octlet_t *)(data + 4), 0ULL,
- extcode, flags);
- fill_async_lock_resp(packet, rcode, extcode, 8);
- }
- break;
- case 16:
- rcode = highlevel_lock64(host, source,
- (octlet_t *)packet->data, addr,
- *(octlet_t *)(data + 6),
- *(octlet_t *)(data + 4),
- extcode, flags);
- fill_async_lock_resp(packet, rcode, extcode, 8);
- break;
- default:
- rcode = RCODE_TYPE_ERROR;
- fill_async_lock_resp(packet, rcode, extcode, 0);
- }
-
- if (rcode < 0)
- hpsb_free_packet(packet);
- else
- send_packet_nocare(packet);
- return;
- }
-}
-
-/**
- * hpsb_packet_received - hand over received packet to the core
- *
- * For host driver module usage.
- *
- * The contents of data are expected to be the full packet but with the CRCs
- * left out (data block follows header immediately), with the header (i.e. the
- * first four quadlets) in machine byte order and the data block in big endian.
- * *@data can be safely overwritten after this call.
- *
- * If the packet is a write request, @write_acked is to be set to true if it was
- * ack_complete'd already, false otherwise. This argument is ignored for any
- * other packet type.
- */
-void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
- int write_acked)
-{
- int tcode;
-
- if (unlikely(host->in_bus_reset)) {
- HPSB_DEBUG("received packet during reset; ignoring");
- return;
- }
-
- dump_packet("received packet", data, size, -1);
-
- tcode = (data[0] >> 4) & 0xf;
-
- switch (tcode) {
- case TCODE_WRITE_RESPONSE:
- case TCODE_READQ_RESPONSE:
- case TCODE_READB_RESPONSE:
- case TCODE_LOCK_RESPONSE:
- handle_packet_response(host, tcode, data, size);
- break;
-
- case TCODE_WRITEQ:
- case TCODE_WRITEB:
- case TCODE_READQ:
- case TCODE_READB:
- case TCODE_LOCK_REQUEST:
- handle_incoming_packet(host, tcode, data, size, write_acked);
- break;
-
- case TCODE_CYCLE_START:
- /* simply ignore this packet if it is passed on */
- break;
-
- default:
- HPSB_DEBUG("received packet with bogus transaction code %d",
- tcode);
- break;
- }
-}
-
-static void abort_requests(struct hpsb_host *host)
-{
- struct hpsb_packet *packet, *p;
- struct list_head tmp;
- unsigned long flags;
-
- host->driver->devctl(host, CANCEL_REQUESTS, 0);
-
- INIT_LIST_HEAD(&tmp);
- spin_lock_irqsave(&pending_packets_lock, flags);
- list_splice_init(&host->pending_packets, &tmp);
- spin_unlock_irqrestore(&pending_packets_lock, flags);
-
- list_for_each_entry_safe(packet, p, &tmp, queue) {
- list_del_init(&packet->queue);
- packet->state = hpsb_complete;
- packet->ack_code = ACKX_ABORTED;
- queue_packet_complete(packet);
- }
-}
-
-void abort_timedouts(unsigned long __opaque)
-{
- struct hpsb_host *host = (struct hpsb_host *)__opaque;
- struct hpsb_packet *packet, *p;
- struct list_head tmp;
- unsigned long flags, expire, j;
-
- spin_lock_irqsave(&host->csr.lock, flags);
- expire = host->csr.expire;
- spin_unlock_irqrestore(&host->csr.lock, flags);
-
- j = jiffies;
- INIT_LIST_HEAD(&tmp);
- spin_lock_irqsave(&pending_packets_lock, flags);
-
- list_for_each_entry_safe(packet, p, &host->pending_packets, queue) {
- if (time_before(packet->sendtime + expire, j))
- list_move_tail(&packet->queue, &tmp);
- else
- /* Since packets are added to the tail, the oldest
- * ones are first, always. When we get to one that
- * isn't timed out, the rest aren't either. */
- break;
- }
- if (!list_empty(&host->pending_packets))
- mod_timer(&host->timeout, j + host->timeout_interval);
-
- spin_unlock_irqrestore(&pending_packets_lock, flags);
-
- list_for_each_entry_safe(packet, p, &tmp, queue) {
- list_del_init(&packet->queue);
- packet->state = hpsb_complete;
- packet->ack_code = ACKX_TIMEOUT;
- queue_packet_complete(packet);
- }
-}
-
-static struct task_struct *khpsbpkt_thread;
-static LIST_HEAD(hpsbpkt_queue);
-
-static void queue_packet_complete(struct hpsb_packet *packet)
-{
- unsigned long flags;
-
- if (packet->no_waiter) {
- hpsb_free_packet(packet);
- return;
- }
- if (packet->complete_routine != NULL) {
- spin_lock_irqsave(&pending_packets_lock, flags);
- list_add_tail(&packet->queue, &hpsbpkt_queue);
- spin_unlock_irqrestore(&pending_packets_lock, flags);
- wake_up_process(khpsbpkt_thread);
- }
- return;
-}
-
-/*
- * Kernel thread which handles packets that are completed. This way the
- * packet's "complete" function is asynchronously run in process context.
- * Only packets which have a "complete" function may be sent here.
- */
-static int hpsbpkt_thread(void *__hi)
-{
- struct hpsb_packet *packet, *p;
- struct list_head tmp;
- int may_schedule;
-
- while (!kthread_should_stop()) {
-
- INIT_LIST_HEAD(&tmp);
- spin_lock_irq(&pending_packets_lock);
- list_splice_init(&hpsbpkt_queue, &tmp);
- spin_unlock_irq(&pending_packets_lock);
-
- list_for_each_entry_safe(packet, p, &tmp, queue) {
- list_del_init(&packet->queue);
- packet->complete_routine(packet->complete_data);
- }
-
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irq(&pending_packets_lock);
- may_schedule = list_empty(&hpsbpkt_queue);
- spin_unlock_irq(&pending_packets_lock);
- if (may_schedule)
- schedule();
- __set_current_state(TASK_RUNNING);
- }
- return 0;
-}
-
-static int __init ieee1394_init(void)
-{
- int i, ret;
-
- /* non-fatal error */
- if (hpsb_init_config_roms()) {
- HPSB_ERR("Failed to initialize some config rom entries.\n");
- HPSB_ERR("Some features may not be available\n");
- }
-
- khpsbpkt_thread = kthread_run(hpsbpkt_thread, NULL, "khpsbpkt");
- if (IS_ERR(khpsbpkt_thread)) {
- HPSB_ERR("Failed to start hpsbpkt thread!\n");
- ret = PTR_ERR(khpsbpkt_thread);
- goto exit_cleanup_config_roms;
- }
-
- if (register_chrdev_region(IEEE1394_CORE_DEV, 256, "ieee1394")) {
- HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR);
- ret = -ENODEV;
- goto exit_release_kernel_thread;
- }
-
- ret = bus_register(&ieee1394_bus_type);
- if (ret < 0) {
- HPSB_INFO("bus register failed");
- goto release_chrdev;
- }
-
- for (i = 0; fw_bus_attrs[i]; i++) {
- ret = bus_create_file(&ieee1394_bus_type, fw_bus_attrs[i]);
- if (ret < 0) {
- while (i >= 0) {
- bus_remove_file(&ieee1394_bus_type,
- fw_bus_attrs[i--]);
- }
- bus_unregister(&ieee1394_bus_type);
- goto release_chrdev;
- }
- }
-
- ret = class_register(&hpsb_host_class);
- if (ret < 0)
- goto release_all_bus;
-
- hpsb_protocol_class = class_create(THIS_MODULE, "ieee1394_protocol");
- if (IS_ERR(hpsb_protocol_class)) {
- ret = PTR_ERR(hpsb_protocol_class);
- goto release_class_host;
- }
-
- ret = init_csr();
- if (ret) {
- HPSB_INFO("init csr failed");
- ret = -ENOMEM;
- goto release_class_protocol;
- }
-
- if (disable_nodemgr) {
- HPSB_INFO("nodemgr and IRM functionality disabled");
- /* We shouldn't contend for IRM with nodemgr disabled, since
- nodemgr implements functionality required of ieee1394a-2000
- IRMs */
- hpsb_disable_irm = 1;
-
- return 0;
- }
-
- if (hpsb_disable_irm) {
- HPSB_INFO("IRM functionality disabled");
- }
-
- ret = init_ieee1394_nodemgr();
- if (ret < 0) {
- HPSB_INFO("init nodemgr failed");
- goto cleanup_csr;
- }
-
- return 0;
-
-cleanup_csr:
- cleanup_csr();
-release_class_protocol:
- class_destroy(hpsb_protocol_class);
-release_class_host:
- class_unregister(&hpsb_host_class);
-release_all_bus:
- for (i = 0; fw_bus_attrs[i]; i++)
- bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
- bus_unregister(&ieee1394_bus_type);
-release_chrdev:
- unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
-exit_release_kernel_thread:
- kthread_stop(khpsbpkt_thread);
-exit_cleanup_config_roms:
- hpsb_cleanup_config_roms();
- return ret;
-}
-
-static void __exit ieee1394_cleanup(void)
-{
- int i;
-
- if (!disable_nodemgr)
- cleanup_ieee1394_nodemgr();
-
- cleanup_csr();
-
- class_destroy(hpsb_protocol_class);
- class_unregister(&hpsb_host_class);
- for (i = 0; fw_bus_attrs[i]; i++)
- bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
- bus_unregister(&ieee1394_bus_type);
-
- kthread_stop(khpsbpkt_thread);
-
- hpsb_cleanup_config_roms();
-
- unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
-}
-
-fs_initcall(ieee1394_init);
-module_exit(ieee1394_cleanup);
-
-/* Exported symbols */
-
-/** hosts.c **/
-EXPORT_SYMBOL(hpsb_alloc_host);
-EXPORT_SYMBOL(hpsb_add_host);
-EXPORT_SYMBOL(hpsb_resume_host);
-EXPORT_SYMBOL(hpsb_remove_host);
-EXPORT_SYMBOL(hpsb_update_config_rom_image);
-
-/** ieee1394_core.c **/
-EXPORT_SYMBOL(hpsb_speedto_str);
-EXPORT_SYMBOL(hpsb_protocol_class);
-EXPORT_SYMBOL(hpsb_set_packet_complete_task);
-EXPORT_SYMBOL(hpsb_alloc_packet);
-EXPORT_SYMBOL(hpsb_free_packet);
-EXPORT_SYMBOL(hpsb_send_packet);
-EXPORT_SYMBOL(hpsb_reset_bus);
-EXPORT_SYMBOL(hpsb_read_cycle_timer);
-EXPORT_SYMBOL(hpsb_bus_reset);
-EXPORT_SYMBOL(hpsb_selfid_received);
-EXPORT_SYMBOL(hpsb_selfid_complete);
-EXPORT_SYMBOL(hpsb_packet_sent);
-EXPORT_SYMBOL(hpsb_packet_received);
-EXPORT_SYMBOL_GPL(hpsb_disable_irm);
-
-/** ieee1394_transactions.c **/
-EXPORT_SYMBOL(hpsb_get_tlabel);
-EXPORT_SYMBOL(hpsb_free_tlabel);
-EXPORT_SYMBOL(hpsb_make_readpacket);
-EXPORT_SYMBOL(hpsb_make_writepacket);
-EXPORT_SYMBOL(hpsb_make_streampacket);
-EXPORT_SYMBOL(hpsb_make_lockpacket);
-EXPORT_SYMBOL(hpsb_make_lock64packet);
-EXPORT_SYMBOL(hpsb_make_phypacket);
-EXPORT_SYMBOL(hpsb_read);
-EXPORT_SYMBOL(hpsb_write);
-EXPORT_SYMBOL(hpsb_lock);
-EXPORT_SYMBOL(hpsb_packet_success);
-
-/** highlevel.c **/
-EXPORT_SYMBOL(hpsb_register_highlevel);
-EXPORT_SYMBOL(hpsb_unregister_highlevel);
-EXPORT_SYMBOL(hpsb_register_addrspace);
-EXPORT_SYMBOL(hpsb_unregister_addrspace);
-EXPORT_SYMBOL(hpsb_allocate_and_register_addrspace);
-EXPORT_SYMBOL(hpsb_get_hostinfo);
-EXPORT_SYMBOL(hpsb_create_hostinfo);
-EXPORT_SYMBOL(hpsb_destroy_hostinfo);
-EXPORT_SYMBOL(hpsb_set_hostinfo_key);
-EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
-EXPORT_SYMBOL(hpsb_set_hostinfo);
-
-/** nodemgr.c **/
-EXPORT_SYMBOL(hpsb_node_fill_packet);
-EXPORT_SYMBOL(hpsb_node_write);
-EXPORT_SYMBOL(__hpsb_register_protocol);
-EXPORT_SYMBOL(hpsb_unregister_protocol);
-
-/** csr.c **/
-EXPORT_SYMBOL(hpsb_update_config_rom);
-
-/** dma.c **/
-EXPORT_SYMBOL(dma_prog_region_init);
-EXPORT_SYMBOL(dma_prog_region_alloc);
-EXPORT_SYMBOL(dma_prog_region_free);
-EXPORT_SYMBOL(dma_region_init);
-EXPORT_SYMBOL(dma_region_alloc);
-EXPORT_SYMBOL(dma_region_free);
-EXPORT_SYMBOL(dma_region_sync_for_cpu);
-EXPORT_SYMBOL(dma_region_sync_for_device);
-EXPORT_SYMBOL(dma_region_mmap);
-EXPORT_SYMBOL(dma_region_offset_to_bus);
-
-/** iso.c **/
-EXPORT_SYMBOL(hpsb_iso_xmit_init);
-EXPORT_SYMBOL(hpsb_iso_recv_init);
-EXPORT_SYMBOL(hpsb_iso_xmit_start);
-EXPORT_SYMBOL(hpsb_iso_recv_start);
-EXPORT_SYMBOL(hpsb_iso_recv_listen_channel);
-EXPORT_SYMBOL(hpsb_iso_recv_unlisten_channel);
-EXPORT_SYMBOL(hpsb_iso_recv_set_channel_mask);
-EXPORT_SYMBOL(hpsb_iso_stop);
-EXPORT_SYMBOL(hpsb_iso_shutdown);
-EXPORT_SYMBOL(hpsb_iso_xmit_queue_packet);
-EXPORT_SYMBOL(hpsb_iso_xmit_sync);
-EXPORT_SYMBOL(hpsb_iso_recv_release_packets);
-EXPORT_SYMBOL(hpsb_iso_n_ready);
-EXPORT_SYMBOL(hpsb_iso_packet_sent);
-EXPORT_SYMBOL(hpsb_iso_packet_received);
-EXPORT_SYMBOL(hpsb_iso_wake);
-EXPORT_SYMBOL(hpsb_iso_recv_flush);
-
-/** csr1212.c **/
-EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
-EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
-EXPORT_SYMBOL(csr1212_get_keyval);
-EXPORT_SYMBOL(csr1212_new_directory);
-EXPORT_SYMBOL(csr1212_parse_keyval);
-EXPORT_SYMBOL(csr1212_read);
-EXPORT_SYMBOL(csr1212_release_keyval);
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
deleted file mode 100644
index 28b9f58bafd2..000000000000
--- a/drivers/ieee1394/ieee1394_core.h
+++ /dev/null
@@ -1,172 +0,0 @@
-#ifndef _IEEE1394_CORE_H
-#define _IEEE1394_CORE_H
-
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/list.h>
-#include <linux/types.h>
-#include <linux/cdev.h>
-#include <asm/atomic.h>
-
-#include "hosts.h"
-#include "ieee1394_types.h"
-
-struct hpsb_packet {
- /* This struct is basically read-only for hosts with the exception of
- * the data buffer contents and driver_list. */
-
- /* This can be used for host driver internal linking.
- *
- * NOTE: This must be left in init state when the driver is done
- * with it (e.g. by using list_del_init()), since the core does
- * some sanity checks to make sure the packet is not on a
- * driver_list when free'ing it. */
- struct list_head driver_list;
-
- nodeid_t node_id;
-
- /* hpsb_raw = send as-is, do not CRC (but still byte-swap it) */
- enum { hpsb_async, hpsb_raw } __attribute__((packed)) type;
-
- /* Okay, this is core internal and a no care for hosts.
- * queued = queued for sending
- * pending = sent, waiting for response
- * complete = processing completed, successful or not
- */
- enum {
- hpsb_unused, hpsb_queued, hpsb_pending, hpsb_complete
- } __attribute__((packed)) state;
-
- /* These are core-internal. */
- signed char tlabel;
- signed char ack_code;
- unsigned char tcode;
-
- unsigned expect_response:1;
- unsigned no_waiter:1;
-
- /* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */
- unsigned speed_code:2;
-
- struct hpsb_host *host;
- unsigned int generation;
-
- atomic_t refcnt;
- struct list_head queue;
-
- /* Function (and possible data to pass to it) to call when this
- * packet is completed. */
- void (*complete_routine)(void *);
- void *complete_data;
-
- /* Store jiffies for implementing bus timeouts. */
- unsigned long sendtime;
-
- /* Core-internal. */
- size_t allocated_data_size; /* as allocated */
-
- /* Sizes are in bytes. To be set by caller of hpsb_alloc_packet. */
- size_t data_size; /* as filled in */
- size_t header_size; /* as filled in, not counting the CRC */
-
- /* Buffers */
- quadlet_t *data; /* can be DMA-mapped */
- quadlet_t header[5];
- quadlet_t embedded_data[0]; /* keep as last member */
-};
-
-void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
- void (*routine)(void *), void *data);
-static inline struct hpsb_packet *driver_packet(struct list_head *l)
-{
- return list_entry(l, struct hpsb_packet, driver_list);
-}
-void abort_timedouts(unsigned long __opaque);
-struct hpsb_packet *hpsb_alloc_packet(size_t data_size);
-void hpsb_free_packet(struct hpsb_packet *packet);
-
-/**
- * get_hpsb_generation - generation counter for the complete 1394 subsystem
- *
- * Generation gets incremented on every change in the subsystem (notably on bus
- * resets). Use the functions, not the variable.
- */
-static inline unsigned int get_hpsb_generation(struct hpsb_host *host)
-{
- return atomic_read(&host->generation);
-}
-
-int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt);
-int hpsb_send_packet(struct hpsb_packet *packet);
-int hpsb_send_packet_and_wait(struct hpsb_packet *packet);
-int hpsb_reset_bus(struct hpsb_host *host, int type);
-int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
- u64 *local_time);
-
-int hpsb_bus_reset(struct hpsb_host *host);
-void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid);
-void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot);
-void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
- int ackcode);
-void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
- int write_acked);
-
-/*
- * CHARACTER DEVICE DISPATCHING
- *
- * All ieee1394 character device drivers share the same major number
- * (major 171). The 256 minor numbers are allocated to the various
- * task-specific interfaces (raw1394, video1394, dv1394, etc) in
- * blocks of 16.
- *
- * The core ieee1394.o module allocates the device number region
- * 171:0-255, the various drivers must then cdev_add() their cdev
- * objects to handle their respective sub-regions.
- *
- * Minor device number block allocations:
- *
- * Block 0 ( 0- 15) raw1394
- * Block 1 ( 16- 31) video1394
- * Block 2 ( 32- 47) dv1394
- *
- * Blocks 3-14 free for future allocation
- *
- * Block 15 (240-255) reserved for drivers under development, etc.
- */
-
-#define IEEE1394_MAJOR 171
-
-#define IEEE1394_MINOR_BLOCK_RAW1394 0
-#define IEEE1394_MINOR_BLOCK_VIDEO1394 1
-#define IEEE1394_MINOR_BLOCK_DV1394 2
-#define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
-
-#define IEEE1394_CORE_DEV MKDEV(IEEE1394_MAJOR, 0)
-#define IEEE1394_RAW1394_DEV MKDEV(IEEE1394_MAJOR, \
- IEEE1394_MINOR_BLOCK_RAW1394 * 16)
-#define IEEE1394_VIDEO1394_DEV MKDEV(IEEE1394_MAJOR, \
- IEEE1394_MINOR_BLOCK_VIDEO1394 * 16)
-#define IEEE1394_DV1394_DEV MKDEV(IEEE1394_MAJOR, \
- IEEE1394_MINOR_BLOCK_DV1394 * 16)
-#define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, \
- IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
-
-/**
- * ieee1394_file_to_instance - get the index within a minor number block
- */
-static inline unsigned char ieee1394_file_to_instance(struct file *file)
-{
- int idx = cdev_index(file->f_path.dentry->d_inode);
- if (idx < 0)
- idx = 0;
- return idx;
-}
-
-extern int hpsb_disable_irm;
-
-/* Our sysfs bus entry */
-extern struct bus_type ieee1394_bus_type;
-extern struct class hpsb_host_class;
-extern struct class *hpsb_protocol_class;
-
-#endif /* _IEEE1394_CORE_H */
diff --git a/drivers/ieee1394/ieee1394_hotplug.h b/drivers/ieee1394/ieee1394_hotplug.h
deleted file mode 100644
index dd5500ed8322..000000000000
--- a/drivers/ieee1394/ieee1394_hotplug.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _IEEE1394_HOTPLUG_H
-#define _IEEE1394_HOTPLUG_H
-
-/* Unit spec id and sw version entry for some protocols */
-#define AVC_UNIT_SPEC_ID_ENTRY 0x0000A02D
-#define AVC_SW_VERSION_ENTRY 0x00010001
-#define CAMERA_UNIT_SPEC_ID_ENTRY 0x0000A02D
-#define CAMERA_SW_VERSION_ENTRY 0x00000100
-
-/* /include/linux/mod_devicetable.h defines:
- * IEEE1394_MATCH_VENDOR_ID
- * IEEE1394_MATCH_MODEL_ID
- * IEEE1394_MATCH_SPECIFIER_ID
- * IEEE1394_MATCH_VERSION
- * struct ieee1394_device_id
- */
-#include <linux/mod_devicetable.h>
-
-#endif /* _IEEE1394_HOTPLUG_H */
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
deleted file mode 100644
index 675b3135d5f1..000000000000
--- a/drivers/ieee1394/ieee1394_transactions.c
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Transaction support.
- *
- * Copyright (C) 1999 Andreas E. Bombe
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/bitops.h>
-#include <linux/compiler.h>
-#include <linux/hardirq.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <linux/sched.h> /* because linux/wait.h is broken if CONFIG_SMP=n */
-#include <linux/wait.h>
-
-#include <asm/bug.h>
-#include <asm/errno.h>
-#include <asm/system.h>
-
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "ieee1394_transactions.h"
-
-#define PREP_ASYNC_HEAD_ADDRESS(tc) \
- packet->tcode = tc; \
- packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
- | (1 << 8) | (tc << 4); \
- packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \
- packet->header[2] = addr & 0xffffffff
-
-#ifndef HPSB_DEBUG_TLABELS
-static
-#endif
-DEFINE_SPINLOCK(hpsb_tlabel_lock);
-
-static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
-
-static void fill_async_readquad(struct hpsb_packet *packet, u64 addr)
-{
- PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ);
- packet->header_size = 12;
- packet->data_size = 0;
- packet->expect_response = 1;
-}
-
-static void fill_async_readblock(struct hpsb_packet *packet, u64 addr,
- int length)
-{
- PREP_ASYNC_HEAD_ADDRESS(TCODE_READB);
- packet->header[3] = length << 16;
- packet->header_size = 16;
- packet->data_size = 0;
- packet->expect_response = 1;
-}
-
-static void fill_async_writequad(struct hpsb_packet *packet, u64 addr,
- quadlet_t data)
-{
- PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEQ);
- packet->header[3] = data;
- packet->header_size = 16;
- packet->data_size = 0;
- packet->expect_response = 1;
-}
-
-static void fill_async_writeblock(struct hpsb_packet *packet, u64 addr,
- int length)
-{
- PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB);
- packet->header[3] = length << 16;
- packet->header_size = 16;
- packet->expect_response = 1;
- packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
-}
-
-static void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode,
- int length)
-{
- PREP_ASYNC_HEAD_ADDRESS(TCODE_LOCK_REQUEST);
- packet->header[3] = (length << 16) | extcode;
- packet->header_size = 16;
- packet->data_size = length;
- packet->expect_response = 1;
-}
-
-static void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data)
-{
- packet->header[0] = data;
- packet->header[1] = ~data;
- packet->header_size = 8;
- packet->data_size = 0;
- packet->expect_response = 0;
- packet->type = hpsb_raw; /* No CRC added */
- packet->speed_code = IEEE1394_SPEED_100; /* Force speed to be 100Mbps */
-}
-
-static void fill_async_stream_packet(struct hpsb_packet *packet, int length,
- int channel, int tag, int sync)
-{
- packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
- | (TCODE_STREAM_DATA << 4) | sync;
-
- packet->header_size = 4;
- packet->data_size = length;
- packet->type = hpsb_async;
- packet->tcode = TCODE_ISO_DATA;
-}
-
-/* same as hpsb_get_tlabel, except that it returns immediately */
-static int hpsb_get_tlabel_atomic(struct hpsb_packet *packet)
-{
- unsigned long flags, *tp;
- u8 *next;
- int tlabel, n = NODEID_TO_NODE(packet->node_id);
-
- /* Broadcast transactions are complete once the request has been sent.
- * Use the same transaction label for all broadcast transactions. */
- if (unlikely(n == ALL_NODES)) {
- packet->tlabel = 0;
- return 0;
- }
- tp = packet->host->tl_pool[n].map;
- next = &packet->host->next_tl[n];
-
- spin_lock_irqsave(&hpsb_tlabel_lock, flags);
- tlabel = find_next_zero_bit(tp, 64, *next);
- if (tlabel > 63)
- tlabel = find_first_zero_bit(tp, 64);
- if (tlabel > 63) {
- spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
- return -EAGAIN;
- }
- __set_bit(tlabel, tp);
- *next = (tlabel + 1) & 63;
- spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
- packet->tlabel = tlabel;
- return 0;
-}
-
-/**
- * hpsb_get_tlabel - allocate a transaction label
- * @packet: the packet whose tlabel and tl_pool we set
- *
- * Every asynchronous transaction on the 1394 bus needs a transaction
- * label to match the response to the request. This label has to be
- * different from any other transaction label in an outstanding request to
- * the same node to make matching possible without ambiguity.
- *
- * There are 64 different tlabels, so an allocated tlabel has to be freed
- * with hpsb_free_tlabel() after the transaction is complete (unless it's
- * reused again for the same target node).
- *
- * Return value: Zero on success, otherwise non-zero. A non-zero return
- * generally means there are no available tlabels. If this is called out
- * of interrupt or atomic context, then it will sleep until can return a
- * tlabel or a signal is received.
- */
-int hpsb_get_tlabel(struct hpsb_packet *packet)
-{
- if (irqs_disabled() || in_atomic())
- return hpsb_get_tlabel_atomic(packet);
-
- /* NB: The macro wait_event_interruptible() is called with a condition
- * argument with side effect. This is only possible because the side
- * effect does not occur until the condition became true, and
- * wait_event_interruptible() won't evaluate the condition again after
- * that. */
- return wait_event_interruptible(tlabel_wq,
- !hpsb_get_tlabel_atomic(packet));
-}
-
-/**
- * hpsb_free_tlabel - free an allocated transaction label
- * @packet: packet whose tlabel and tl_pool needs to be cleared
- *
- * Frees the transaction label allocated with hpsb_get_tlabel(). The
- * tlabel has to be freed after the transaction is complete (i.e. response
- * was received for a split transaction or packet was sent for a unified
- * transaction).
- *
- * A tlabel must not be freed twice.
- */
-void hpsb_free_tlabel(struct hpsb_packet *packet)
-{
- unsigned long flags, *tp;
- int tlabel, n = NODEID_TO_NODE(packet->node_id);
-
- if (unlikely(n == ALL_NODES))
- return;
- tp = packet->host->tl_pool[n].map;
- tlabel = packet->tlabel;
- BUG_ON(tlabel > 63 || tlabel < 0);
-
- spin_lock_irqsave(&hpsb_tlabel_lock, flags);
- BUG_ON(!__test_and_clear_bit(tlabel, tp));
- spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
- wake_up_interruptible(&tlabel_wq);
-}
-
-/**
- * hpsb_packet_success - Make sense of the ack and reply codes
- *
- * Make sense of the ack and reply codes and return more convenient error codes:
- * 0 = success. -%EBUSY = node is busy, try again. -%EAGAIN = error which can
- * probably resolved by retry. -%EREMOTEIO = node suffers from an internal
- * error. -%EACCES = this transaction is not allowed on requested address.
- * -%EINVAL = invalid address at node.
- */
-int hpsb_packet_success(struct hpsb_packet *packet)
-{
- switch (packet->ack_code) {
- case ACK_PENDING:
- switch ((packet->header[1] >> 12) & 0xf) {
- case RCODE_COMPLETE:
- return 0;
- case RCODE_CONFLICT_ERROR:
- return -EAGAIN;
- case RCODE_DATA_ERROR:
- return -EREMOTEIO;
- case RCODE_TYPE_ERROR:
- return -EACCES;
- case RCODE_ADDRESS_ERROR:
- return -EINVAL;
- default:
- HPSB_ERR("received reserved rcode %d from node %d",
- (packet->header[1] >> 12) & 0xf,
- packet->node_id);
- return -EAGAIN;
- }
-
- case ACK_BUSY_X:
- case ACK_BUSY_A:
- case ACK_BUSY_B:
- return -EBUSY;
-
- case ACK_TYPE_ERROR:
- return -EACCES;
-
- case ACK_COMPLETE:
- if (packet->tcode == TCODE_WRITEQ
- || packet->tcode == TCODE_WRITEB) {
- return 0;
- } else {
- HPSB_ERR("impossible ack_complete from node %d "
- "(tcode %d)", packet->node_id, packet->tcode);
- return -EAGAIN;
- }
-
- case ACK_DATA_ERROR:
- if (packet->tcode == TCODE_WRITEB
- || packet->tcode == TCODE_LOCK_REQUEST) {
- return -EAGAIN;
- } else {
- HPSB_ERR("impossible ack_data_error from node %d "
- "(tcode %d)", packet->node_id, packet->tcode);
- return -EAGAIN;
- }
-
- case ACK_ADDRESS_ERROR:
- return -EINVAL;
-
- case ACK_TARDY:
- case ACK_CONFLICT_ERROR:
- case ACKX_NONE:
- case ACKX_SEND_ERROR:
- case ACKX_ABORTED:
- case ACKX_TIMEOUT:
- /* error while sending */
- return -EAGAIN;
-
- default:
- HPSB_ERR("got invalid ack %d from node %d (tcode %d)",
- packet->ack_code, packet->node_id, packet->tcode);
- return -EAGAIN;
- }
-}
-
-struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
- u64 addr, size_t length)
-{
- struct hpsb_packet *packet;
-
- if (length == 0)
- return NULL;
-
- packet = hpsb_alloc_packet(length);
- if (!packet)
- return NULL;
-
- packet->host = host;
- packet->node_id = node;
-
- if (hpsb_get_tlabel(packet)) {
- hpsb_free_packet(packet);
- return NULL;
- }
-
- if (length == 4)
- fill_async_readquad(packet, addr);
- else
- fill_async_readblock(packet, addr, length);
-
- return packet;
-}
-
-struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host, nodeid_t node,
- u64 addr, quadlet_t * buffer,
- size_t length)
-{
- struct hpsb_packet *packet;
-
- if (length == 0)
- return NULL;
-
- packet = hpsb_alloc_packet(length);
- if (!packet)
- return NULL;
-
- if (length % 4) { /* zero padding bytes */
- packet->data[length >> 2] = 0;
- }
- packet->host = host;
- packet->node_id = node;
-
- if (hpsb_get_tlabel(packet)) {
- hpsb_free_packet(packet);
- return NULL;
- }
-
- if (length == 4) {
- fill_async_writequad(packet, addr, buffer ? *buffer : 0);
- } else {
- fill_async_writeblock(packet, addr, length);
- if (buffer)
- memcpy(packet->data, buffer, length);
- }
-
- return packet;
-}
-
-struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 * buffer,
- int length, int channel, int tag,
- int sync)
-{
- struct hpsb_packet *packet;
-
- if (length == 0)
- return NULL;
-
- packet = hpsb_alloc_packet(length);
- if (!packet)
- return NULL;
-
- if (length % 4) { /* zero padding bytes */
- packet->data[length >> 2] = 0;
- }
- packet->host = host;
-
- /* Because it is too difficult to determine all PHY speeds and link
- * speeds here, we use S100... */
- packet->speed_code = IEEE1394_SPEED_100;
-
- /* ...and prevent hpsb_send_packet() from overriding it. */
- packet->node_id = LOCAL_BUS | ALL_NODES;
-
- if (hpsb_get_tlabel(packet)) {
- hpsb_free_packet(packet);
- return NULL;
- }
-
- fill_async_stream_packet(packet, length, channel, tag, sync);
- if (buffer)
- memcpy(packet->data, buffer, length);
-
- return packet;
-}
-
-struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
- u64 addr, int extcode,
- quadlet_t * data, quadlet_t arg)
-{
- struct hpsb_packet *p;
- u32 length;
-
- p = hpsb_alloc_packet(8);
- if (!p)
- return NULL;
-
- p->host = host;
- p->node_id = node;
- if (hpsb_get_tlabel(p)) {
- hpsb_free_packet(p);
- return NULL;
- }
-
- switch (extcode) {
- case EXTCODE_FETCH_ADD:
- case EXTCODE_LITTLE_ADD:
- length = 4;
- if (data)
- p->data[0] = *data;
- break;
- default:
- length = 8;
- if (data) {
- p->data[0] = arg;
- p->data[1] = *data;
- }
- break;
- }
- fill_async_lock(p, addr, extcode, length);
-
- return p;
-}
-
-struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
- nodeid_t node, u64 addr, int extcode,
- octlet_t * data, octlet_t arg)
-{
- struct hpsb_packet *p;
- u32 length;
-
- p = hpsb_alloc_packet(16);
- if (!p)
- return NULL;
-
- p->host = host;
- p->node_id = node;
- if (hpsb_get_tlabel(p)) {
- hpsb_free_packet(p);
- return NULL;
- }
-
- switch (extcode) {
- case EXTCODE_FETCH_ADD:
- case EXTCODE_LITTLE_ADD:
- length = 8;
- if (data) {
- p->data[0] = *data >> 32;
- p->data[1] = *data & 0xffffffff;
- }
- break;
- default:
- length = 16;
- if (data) {
- p->data[0] = arg >> 32;
- p->data[1] = arg & 0xffffffff;
- p->data[2] = *data >> 32;
- p->data[3] = *data & 0xffffffff;
- }
- break;
- }
- fill_async_lock(p, addr, extcode, length);
-
- return p;
-}
-
-struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data)
-{
- struct hpsb_packet *p;
-
- p = hpsb_alloc_packet(0);
- if (!p)
- return NULL;
-
- p->host = host;
- fill_phy_packet(p, data);
-
- return p;
-}
-
-/*
- * FIXME - these functions should probably read from / write to user space to
- * avoid in kernel buffers for user space callers
- */
-
-/**
- * hpsb_read - generic read function
- *
- * Recognizes the local node ID and act accordingly. Automatically uses a
- * quadlet read request if @length == 4 and and a block read request otherwise.
- * It does not yet support lengths that are not a multiple of 4.
- *
- * You must explicitly specifiy the @generation for which the node ID is valid,
- * to avoid sending packets to the wrong nodes when we race with a bus reset.
- */
-int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
- u64 addr, quadlet_t * buffer, size_t length)
-{
- struct hpsb_packet *packet;
- int retval = 0;
-
- if (length == 0)
- return -EINVAL;
-
- packet = hpsb_make_readpacket(host, node, addr, length);
-
- if (!packet) {
- return -ENOMEM;
- }
-
- packet->generation = generation;
- retval = hpsb_send_packet_and_wait(packet);
- if (retval < 0)
- goto hpsb_read_fail;
-
- retval = hpsb_packet_success(packet);
-
- if (retval == 0) {
- if (length == 4) {
- *buffer = packet->header[3];
- } else {
- memcpy(buffer, packet->data, length);
- }
- }
-
- hpsb_read_fail:
- hpsb_free_tlabel(packet);
- hpsb_free_packet(packet);
-
- return retval;
-}
-
-/**
- * hpsb_write - generic write function
- *
- * Recognizes the local node ID and act accordingly. Automatically uses a
- * quadlet write request if @length == 4 and and a block write request
- * otherwise. It does not yet support lengths that are not a multiple of 4.
- *
- * You must explicitly specifiy the @generation for which the node ID is valid,
- * to avoid sending packets to the wrong nodes when we race with a bus reset.
- */
-int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
- u64 addr, quadlet_t * buffer, size_t length)
-{
- struct hpsb_packet *packet;
- int retval;
-
- if (length == 0)
- return -EINVAL;
-
- packet = hpsb_make_writepacket(host, node, addr, buffer, length);
-
- if (!packet)
- return -ENOMEM;
-
- packet->generation = generation;
- retval = hpsb_send_packet_and_wait(packet);
- if (retval < 0)
- goto hpsb_write_fail;
-
- retval = hpsb_packet_success(packet);
-
- hpsb_write_fail:
- hpsb_free_tlabel(packet);
- hpsb_free_packet(packet);
-
- return retval;
-}
-
-int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
- u64 addr, int extcode, quadlet_t *data, quadlet_t arg)
-{
- struct hpsb_packet *packet;
- int retval = 0;
-
- packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg);
- if (!packet)
- return -ENOMEM;
-
- packet->generation = generation;
- retval = hpsb_send_packet_and_wait(packet);
- if (retval < 0)
- goto hpsb_lock_fail;
-
- retval = hpsb_packet_success(packet);
-
- if (retval == 0)
- *data = packet->data[0];
-
-hpsb_lock_fail:
- hpsb_free_tlabel(packet);
- hpsb_free_packet(packet);
-
- return retval;
-}
diff --git a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h
deleted file mode 100644
index 20b693be14b2..000000000000
--- a/drivers/ieee1394/ieee1394_transactions.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef _IEEE1394_TRANSACTIONS_H
-#define _IEEE1394_TRANSACTIONS_H
-
-#include <linux/types.h>
-
-#include "ieee1394_types.h"
-
-struct hpsb_packet;
-struct hpsb_host;
-
-int hpsb_get_tlabel(struct hpsb_packet *packet);
-void hpsb_free_tlabel(struct hpsb_packet *packet);
-struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
- u64 addr, size_t length);
-struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
- u64 addr, int extcode, quadlet_t *data,
- quadlet_t arg);
-struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
- nodeid_t node, u64 addr, int extcode,
- octlet_t *data, octlet_t arg);
-struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data);
-struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host,
- nodeid_t node, u64 addr,
- quadlet_t *buffer, size_t length);
-struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer,
- int length, int channel, int tag,
- int sync);
-int hpsb_packet_success(struct hpsb_packet *packet);
-int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
- u64 addr, quadlet_t *buffer, size_t length);
-int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
- u64 addr, quadlet_t *buffer, size_t length);
-int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
- u64 addr, int extcode, quadlet_t *data, quadlet_t arg);
-
-#ifdef HPSB_DEBUG_TLABELS
-extern spinlock_t hpsb_tlabel_lock;
-#endif
-
-#endif /* _IEEE1394_TRANSACTIONS_H */
diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h
deleted file mode 100644
index 9803aaa15be0..000000000000
--- a/drivers/ieee1394/ieee1394_types.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef _IEEE1394_TYPES_H
-#define _IEEE1394_TYPES_H
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-typedef u32 quadlet_t;
-typedef u64 octlet_t;
-typedef u16 nodeid_t;
-
-typedef u8 byte_t;
-typedef u64 nodeaddr_t;
-typedef u16 arm_length_t;
-
-#define BUS_MASK 0xffc0
-#define BUS_SHIFT 6
-#define NODE_MASK 0x003f
-#define LOCAL_BUS 0xffc0
-#define ALL_NODES 0x003f
-
-#define NODEID_TO_BUS(nodeid) ((nodeid & BUS_MASK) >> BUS_SHIFT)
-#define NODEID_TO_NODE(nodeid) (nodeid & NODE_MASK)
-
-/* Can be used to consistently print a node/bus ID. */
-#define NODE_BUS_FMT "%d-%02d:%04d"
-#define NODE_BUS_ARGS(__host, __nodeid) \
- __host->id, NODEID_TO_NODE(__nodeid), NODEID_TO_BUS(__nodeid)
-
-#define HPSB_PRINT(level, fmt, args...) \
- printk(level "ieee1394: " fmt "\n" , ## args)
-
-#define HPSB_DEBUG(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
-#define HPSB_INFO(fmt, args...) HPSB_PRINT(KERN_INFO, fmt , ## args)
-#define HPSB_NOTICE(fmt, args...) HPSB_PRINT(KERN_NOTICE, fmt , ## args)
-#define HPSB_WARN(fmt, args...) HPSB_PRINT(KERN_WARNING, fmt , ## args)
-#define HPSB_ERR(fmt, args...) HPSB_PRINT(KERN_ERR, fmt , ## args)
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define HPSB_VERBOSE(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
-#define HPSB_DEBUG_TLABELS
-#else
-#define HPSB_VERBOSE(fmt, args...) do {} while (0)
-#endif
-
-#ifdef __BIG_ENDIAN
-
-static inline void *memcpy_le32(u32 *dest, const u32 *__src, size_t count)
-{
- void *tmp = dest;
- u32 *src = (u32 *)__src;
-
- count /= 4;
- while (count--)
- *dest++ = swab32p(src++);
- return tmp;
-}
-
-#else
-
-static __inline__ void *memcpy_le32(u32 *dest, const u32 *src, size_t count)
-{
- return memcpy(dest, src, count);
-}
-
-#endif /* __BIG_ENDIAN */
-
-#endif /* _IEEE1394_TYPES_H */
diff --git a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c
deleted file mode 100644
index 1cf6487b65ba..000000000000
--- a/drivers/ieee1394/iso.c
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * kernel ISO transmission/reception
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-
-#include "hosts.h"
-#include "iso.h"
-
-/**
- * hpsb_iso_stop - stop DMA
- */
-void hpsb_iso_stop(struct hpsb_iso *iso)
-{
- if (!(iso->flags & HPSB_ISO_DRIVER_STARTED))
- return;
-
- iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
- XMIT_STOP : RECV_STOP, 0);
- iso->flags &= ~HPSB_ISO_DRIVER_STARTED;
-}
-
-/**
- * hpsb_iso_shutdown - deallocate buffer and DMA context
- */
-void hpsb_iso_shutdown(struct hpsb_iso *iso)
-{
- if (iso->flags & HPSB_ISO_DRIVER_INIT) {
- hpsb_iso_stop(iso);
- iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
- XMIT_SHUTDOWN : RECV_SHUTDOWN, 0);
- iso->flags &= ~HPSB_ISO_DRIVER_INIT;
- }
-
- dma_region_free(&iso->data_buf);
- kfree(iso);
-}
-
-static struct hpsb_iso *hpsb_iso_common_init(struct hpsb_host *host,
- enum hpsb_iso_type type,
- unsigned int data_buf_size,
- unsigned int buf_packets,
- int channel, int dma_mode,
- int irq_interval,
- void (*callback) (struct hpsb_iso
- *))
-{
- struct hpsb_iso *iso;
- int dma_direction;
-
- /* make sure driver supports the ISO API */
- if (!host->driver->isoctl) {
- printk(KERN_INFO
- "ieee1394: host driver '%s' does not support the rawiso API\n",
- host->driver->name);
- return NULL;
- }
-
- /* sanitize parameters */
-
- if (buf_packets < 2)
- buf_packets = 2;
-
- if ((dma_mode < HPSB_ISO_DMA_DEFAULT)
- || (dma_mode > HPSB_ISO_DMA_PACKET_PER_BUFFER))
- dma_mode = HPSB_ISO_DMA_DEFAULT;
-
- if ((irq_interval < 0) || (irq_interval > buf_packets / 4))
- irq_interval = buf_packets / 4;
- if (irq_interval == 0) /* really interrupt for each packet */
- irq_interval = 1;
-
- if (channel < -1 || channel >= 64)
- return NULL;
-
- /* channel = -1 is OK for multi-channel recv but not for xmit */
- if (type == HPSB_ISO_XMIT && channel < 0)
- return NULL;
-
- /* allocate and write the struct hpsb_iso */
-
- iso =
- kmalloc(sizeof(*iso) +
- buf_packets * sizeof(struct hpsb_iso_packet_info),
- GFP_KERNEL);
- if (!iso)
- return NULL;
-
- iso->infos = (struct hpsb_iso_packet_info *)(iso + 1);
-
- iso->type = type;
- iso->host = host;
- iso->hostdata = NULL;
- iso->callback = callback;
- init_waitqueue_head(&iso->waitq);
- iso->channel = channel;
- iso->irq_interval = irq_interval;
- iso->dma_mode = dma_mode;
- dma_region_init(&iso->data_buf);
- iso->buf_size = PAGE_ALIGN(data_buf_size);
- iso->buf_packets = buf_packets;
- iso->pkt_dma = 0;
- iso->first_packet = 0;
- spin_lock_init(&iso->lock);
-
- if (iso->type == HPSB_ISO_XMIT) {
- iso->n_ready_packets = iso->buf_packets;
- dma_direction = PCI_DMA_TODEVICE;
- } else {
- iso->n_ready_packets = 0;
- dma_direction = PCI_DMA_FROMDEVICE;
- }
-
- atomic_set(&iso->overflows, 0);
- iso->bytes_discarded = 0;
- iso->flags = 0;
- iso->prebuffer = 0;
-
- /* allocate the packet buffer */
- if (dma_region_alloc
- (&iso->data_buf, iso->buf_size, host->pdev, dma_direction))
- goto err;
-
- return iso;
-
- err:
- hpsb_iso_shutdown(iso);
- return NULL;
-}
-
-/**
- * hpsb_iso_n_ready - returns number of packets ready to send or receive
- */
-int hpsb_iso_n_ready(struct hpsb_iso *iso)
-{
- unsigned long flags;
- int val;
-
- spin_lock_irqsave(&iso->lock, flags);
- val = iso->n_ready_packets;
- spin_unlock_irqrestore(&iso->lock, flags);
-
- return val;
-}
-
-/**
- * hpsb_iso_xmit_init - allocate the buffer and DMA context
- */
-struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
- unsigned int data_buf_size,
- unsigned int buf_packets,
- int channel,
- int speed,
- int irq_interval,
- void (*callback) (struct hpsb_iso *))
-{
- struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_XMIT,
- data_buf_size, buf_packets,
- channel,
- HPSB_ISO_DMA_DEFAULT,
- irq_interval, callback);
- if (!iso)
- return NULL;
-
- iso->speed = speed;
-
- /* tell the driver to start working */
- if (host->driver->isoctl(iso, XMIT_INIT, 0))
- goto err;
-
- iso->flags |= HPSB_ISO_DRIVER_INIT;
- return iso;
-
- err:
- hpsb_iso_shutdown(iso);
- return NULL;
-}
-
-/**
- * hpsb_iso_recv_init - allocate the buffer and DMA context
- *
- * Note, if channel = -1, multi-channel receive is enabled.
- */
-struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
- unsigned int data_buf_size,
- unsigned int buf_packets,
- int channel,
- int dma_mode,
- int irq_interval,
- void (*callback) (struct hpsb_iso *))
-{
- struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_RECV,
- data_buf_size, buf_packets,
- channel, dma_mode,
- irq_interval, callback);
- if (!iso)
- return NULL;
-
- /* tell the driver to start working */
- if (host->driver->isoctl(iso, RECV_INIT, 0))
- goto err;
-
- iso->flags |= HPSB_ISO_DRIVER_INIT;
- return iso;
-
- err:
- hpsb_iso_shutdown(iso);
- return NULL;
-}
-
-/**
- * hpsb_iso_recv_listen_channel
- *
- * multi-channel only
- */
-int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
-{
- if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
- return -EINVAL;
- return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel);
-}
-
-/**
- * hpsb_iso_recv_unlisten_channel
- *
- * multi-channel only
- */
-int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
-{
- if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
- return -EINVAL;
- return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel);
-}
-
-/**
- * hpsb_iso_recv_set_channel_mask
- *
- * multi-channel only
- */
-int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
-{
- if (iso->type != HPSB_ISO_RECV || iso->channel != -1)
- return -EINVAL;
- return iso->host->driver->isoctl(iso, RECV_SET_CHANNEL_MASK,
- (unsigned long)&mask);
-}
-
-/**
- * hpsb_iso_recv_flush - check for arrival of new packets
- *
- * check for arrival of new packets immediately (even if irq_interval
- * has not yet been reached)
- */
-int hpsb_iso_recv_flush(struct hpsb_iso *iso)
-{
- if (iso->type != HPSB_ISO_RECV)
- return -EINVAL;
- return iso->host->driver->isoctl(iso, RECV_FLUSH, 0);
-}
-
-static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle)
-{
- int retval = iso->host->driver->isoctl(iso, XMIT_START, cycle);
- if (retval)
- return retval;
-
- iso->flags |= HPSB_ISO_DRIVER_STARTED;
- return retval;
-}
-
-/**
- * hpsb_iso_xmit_start - start DMA
- */
-int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
-{
- if (iso->type != HPSB_ISO_XMIT)
- return -1;
-
- if (iso->flags & HPSB_ISO_DRIVER_STARTED)
- return 0;
-
- if (cycle < -1)
- cycle = -1;
- else if (cycle >= 8000)
- cycle %= 8000;
-
- iso->xmit_cycle = cycle;
-
- if (prebuffer < 0)
- prebuffer = iso->buf_packets - 1;
- else if (prebuffer == 0)
- prebuffer = 1;
-
- if (prebuffer >= iso->buf_packets)
- prebuffer = iso->buf_packets - 1;
-
- iso->prebuffer = prebuffer;
-
- /* remember the starting cycle; DMA will commence from xmit_queue_packets()
- once enough packets have been buffered */
- iso->start_cycle = cycle;
-
- return 0;
-}
-
-/**
- * hpsb_iso_recv_start - start DMA
- */
-int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
-{
- int retval = 0;
- int isoctl_args[3];
-
- if (iso->type != HPSB_ISO_RECV)
- return -1;
-
- if (iso->flags & HPSB_ISO_DRIVER_STARTED)
- return 0;
-
- if (cycle < -1)
- cycle = -1;
- else if (cycle >= 8000)
- cycle %= 8000;
-
- isoctl_args[0] = cycle;
-
- if (tag_mask < 0)
- /* match all tags */
- tag_mask = 0xF;
- isoctl_args[1] = tag_mask;
-
- isoctl_args[2] = sync;
-
- retval =
- iso->host->driver->isoctl(iso, RECV_START,
- (unsigned long)&isoctl_args[0]);
- if (retval)
- return retval;
-
- iso->flags |= HPSB_ISO_DRIVER_STARTED;
- return retval;
-}
-
-/* check to make sure the user has not supplied bogus values of offset/len
- * that would cause the kernel to access memory outside the buffer */
-static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
- unsigned int offset, unsigned short len,
- unsigned int *out_offset,
- unsigned short *out_len)
-{
- if (offset >= iso->buf_size)
- return -EFAULT;
-
- /* make sure the packet does not go beyond the end of the buffer */
- if (offset + len > iso->buf_size)
- return -EFAULT;
-
- /* check for wrap-around */
- if (offset + len < offset)
- return -EFAULT;
-
- /* now we can trust 'offset' and 'length' */
- *out_offset = offset;
- *out_len = len;
-
- return 0;
-}
-
-/**
- * hpsb_iso_xmit_queue_packet - queue a packet for transmission.
- *
- * @offset is relative to the beginning of the DMA buffer, where the packet's
- * data payload should already have been placed.
- */
-int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
- u8 tag, u8 sy)
-{
- struct hpsb_iso_packet_info *info;
- unsigned long flags;
- int rv;
-
- if (iso->type != HPSB_ISO_XMIT)
- return -EINVAL;
-
- /* is there space in the buffer? */
- if (iso->n_ready_packets <= 0) {
- return -EBUSY;
- }
-
- info = &iso->infos[iso->first_packet];
-
- /* check for bogus offset/length */
- if (hpsb_iso_check_offset_len
- (iso, offset, len, &info->offset, &info->len))
- return -EFAULT;
-
- info->tag = tag;
- info->sy = sy;
-
- spin_lock_irqsave(&iso->lock, flags);
-
- rv = iso->host->driver->isoctl(iso, XMIT_QUEUE, (unsigned long)info);
- if (rv)
- goto out;
-
- /* increment cursors */
- iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
- iso->xmit_cycle = (iso->xmit_cycle + 1) % 8000;
- iso->n_ready_packets--;
-
- if (iso->prebuffer != 0) {
- iso->prebuffer--;
- if (iso->prebuffer <= 0) {
- iso->prebuffer = 0;
- rv = do_iso_xmit_start(iso, iso->start_cycle);
- }
- }
-
- out:
- spin_unlock_irqrestore(&iso->lock, flags);
- return rv;
-}
-
-/**
- * hpsb_iso_xmit_sync - wait until all queued packets have been transmitted
- */
-int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
-{
- if (iso->type != HPSB_ISO_XMIT)
- return -EINVAL;
-
- return wait_event_interruptible(iso->waitq,
- hpsb_iso_n_ready(iso) ==
- iso->buf_packets);
-}
-
-/**
- * hpsb_iso_packet_sent
- *
- * Available to low-level drivers.
- *
- * Call after a packet has been transmitted to the bus (interrupt context is
- * OK). @cycle is the _exact_ cycle the packet was sent on. @error should be
- * non-zero if some sort of error occurred when sending the packet.
- */
-void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
-{
- unsigned long flags;
- spin_lock_irqsave(&iso->lock, flags);
-
- /* predict the cycle of the next packet to be queued */
-
- /* jump ahead by the number of packets that are already buffered */
- cycle += iso->buf_packets - iso->n_ready_packets;
- cycle %= 8000;
-
- iso->xmit_cycle = cycle;
- iso->n_ready_packets++;
- iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
-
- if (iso->n_ready_packets == iso->buf_packets || error != 0) {
- /* the buffer has run empty! */
- atomic_inc(&iso->overflows);
- }
-
- spin_unlock_irqrestore(&iso->lock, flags);
-}
-
-/**
- * hpsb_iso_packet_received
- *
- * Available to low-level drivers.
- *
- * Call after a packet has been received (interrupt context is OK).
- */
-void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
- u16 total_len, u16 cycle, u8 channel, u8 tag,
- u8 sy)
-{
- unsigned long flags;
- spin_lock_irqsave(&iso->lock, flags);
-
- if (iso->n_ready_packets == iso->buf_packets) {
- /* overflow! */
- atomic_inc(&iso->overflows);
- /* Record size of this discarded packet */
- iso->bytes_discarded += total_len;
- } else {
- struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma];
- info->offset = offset;
- info->len = len;
- info->total_len = total_len;
- info->cycle = cycle;
- info->channel = channel;
- info->tag = tag;
- info->sy = sy;
-
- iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
- iso->n_ready_packets++;
- }
-
- spin_unlock_irqrestore(&iso->lock, flags);
-}
-
-/**
- * hpsb_iso_recv_release_packets - release packets, reuse buffer
- *
- * @n_packets have been read out of the buffer, re-use the buffer space
- */
-int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
-{
- unsigned long flags;
- unsigned int i;
- int rv = 0;
-
- if (iso->type != HPSB_ISO_RECV)
- return -1;
-
- spin_lock_irqsave(&iso->lock, flags);
- for (i = 0; i < n_packets; i++) {
- rv = iso->host->driver->isoctl(iso, RECV_RELEASE,
- (unsigned long)&iso->infos[iso->
- first_packet]);
- if (rv)
- break;
-
- iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
- iso->n_ready_packets--;
-
- /* release memory from packets discarded when queue was full */
- if (iso->n_ready_packets == 0) { /* Release only after all prior packets handled */
- if (iso->bytes_discarded != 0) {
- struct hpsb_iso_packet_info inf;
- inf.total_len = iso->bytes_discarded;
- iso->host->driver->isoctl(iso, RECV_RELEASE,
- (unsigned long)&inf);
- iso->bytes_discarded = 0;
- }
- }
- }
- spin_unlock_irqrestore(&iso->lock, flags);
- return rv;
-}
-
-/**
- * hpsb_iso_wake
- *
- * Available to low-level drivers.
- *
- * Call to wake waiting processes after buffer space has opened up.
- */
-void hpsb_iso_wake(struct hpsb_iso *iso)
-{
- wake_up_interruptible(&iso->waitq);
-
- if (iso->callback)
- iso->callback(iso);
-}
diff --git a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h
deleted file mode 100644
index c2089c093aa7..000000000000
--- a/drivers/ieee1394/iso.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * kernel ISO transmission/reception
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#ifndef IEEE1394_ISO_H
-#define IEEE1394_ISO_H
-
-#include <linux/spinlock_types.h>
-#include <linux/wait.h>
-#include <asm/atomic.h>
-#include <asm/types.h>
-
-#include "dma.h"
-
-struct hpsb_host;
-
-/* high-level ISO interface */
-
-/*
- * This API sends and receives isochronous packets on a large,
- * virtually-contiguous kernel memory buffer. The buffer may be mapped
- * into a user-space process for zero-copy transmission and reception.
- *
- * There are no explicit boundaries between packets in the buffer. A
- * packet may be transmitted or received at any location. However,
- * low-level drivers may impose certain restrictions on alignment or
- * size of packets. (e.g. in OHCI no packet may cross a page boundary,
- * and packets should be quadlet-aligned)
- */
-
-/* Packet descriptor - the API maintains a ring buffer of these packet
- * descriptors in kernel memory (hpsb_iso.infos[]). */
-struct hpsb_iso_packet_info {
- /* offset of data payload relative to the first byte of the buffer */
- __u32 offset;
-
- /* length of the data payload, in bytes (not including the isochronous
- * header) */
- __u16 len;
-
- /* (recv only) the cycle number (mod 8000) on which the packet was
- * received */
- __u16 cycle;
-
- /* (recv only) channel on which the packet was received */
- __u8 channel;
-
- /* 2-bit 'tag' and 4-bit 'sy' fields of the isochronous header */
- __u8 tag;
- __u8 sy;
-
- /* length in bytes of the packet including header/trailer.
- * MUST be at structure end, since the first part of this structure is
- * also defined in raw1394.h (i.e. struct raw1394_iso_packet_info), is
- * copied to userspace and is accessed there through libraw1394. */
- __u16 total_len;
-};
-
-enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 };
-
-/* The mode of the dma when receiving iso data. Must be supported by chip */
-enum raw1394_iso_dma_recv_mode {
- HPSB_ISO_DMA_DEFAULT = -1,
- HPSB_ISO_DMA_OLD_ABI = 0,
- HPSB_ISO_DMA_BUFFERFILL = 1,
- HPSB_ISO_DMA_PACKET_PER_BUFFER = 2
-};
-
-struct hpsb_iso {
- enum hpsb_iso_type type;
-
- /* pointer to low-level driver and its private data */
- struct hpsb_host *host;
- void *hostdata;
-
- /* a function to be called (from interrupt context) after
- * outgoing packets have been sent, or incoming packets have
- * arrived */
- void (*callback)(struct hpsb_iso*);
-
- /* wait for buffer space */
- wait_queue_head_t waitq;
-
- int speed; /* IEEE1394_SPEED_100, 200, or 400 */
- int channel; /* -1 if multichannel */
- int dma_mode; /* dma receive mode */
-
-
- /* greatest # of packets between interrupts - controls
- * the maximum latency of the buffer */
- int irq_interval;
-
- /* the buffer for packet data payloads */
- struct dma_region data_buf;
-
- /* size of data_buf, in bytes (always a multiple of PAGE_SIZE) */
- unsigned int buf_size;
-
- /* # of packets in the ringbuffer */
- unsigned int buf_packets;
-
- /* protects packet cursors */
- spinlock_t lock;
-
- /* the index of the next packet that will be produced
- or consumed by the user */
- int first_packet;
-
- /* the index of the next packet that will be transmitted
- or received by the 1394 hardware */
- int pkt_dma;
-
- /* how many packets, starting at first_packet:
- * (transmit) are ready to be filled with data
- * (receive) contain received data */
- int n_ready_packets;
-
- /* how many times the buffer has overflowed or underflowed */
- atomic_t overflows;
- /* how many cycles were skipped for a given context */
- atomic_t skips;
-
- /* Current number of bytes lost in discarded packets */
- int bytes_discarded;
-
- /* private flags to track initialization progress */
-#define HPSB_ISO_DRIVER_INIT (1<<0)
-#define HPSB_ISO_DRIVER_STARTED (1<<1)
- unsigned int flags;
-
- /* # of packets left to prebuffer (xmit only) */
- int prebuffer;
-
- /* starting cycle for DMA (xmit only) */
- int start_cycle;
-
- /* cycle at which next packet will be transmitted,
- * -1 if not known */
- int xmit_cycle;
-
- /* ringbuffer of packet descriptors in regular kernel memory
- * XXX Keep this last, since we use over-allocated memory from
- * this entry to fill this field. */
- struct hpsb_iso_packet_info *infos;
-};
-
-/* functions available to high-level drivers (e.g. raw1394) */
-
-struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host,
- unsigned int data_buf_size,
- unsigned int buf_packets,
- int channel,
- int speed,
- int irq_interval,
- void (*callback)(struct hpsb_iso*));
-struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host,
- unsigned int data_buf_size,
- unsigned int buf_packets,
- int channel,
- int dma_mode,
- int irq_interval,
- void (*callback)(struct hpsb_iso*));
-int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel);
-int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel);
-int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask);
-int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle,
- int prebuffer);
-int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle,
- int tag_mask, int sync);
-void hpsb_iso_stop(struct hpsb_iso *iso);
-void hpsb_iso_shutdown(struct hpsb_iso *iso);
-int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
- u8 tag, u8 sy);
-int hpsb_iso_xmit_sync(struct hpsb_iso *iso);
-int hpsb_iso_recv_release_packets(struct hpsb_iso *recv,
- unsigned int n_packets);
-int hpsb_iso_recv_flush(struct hpsb_iso *iso);
-int hpsb_iso_n_ready(struct hpsb_iso *iso);
-
-/* the following are callbacks available to low-level drivers */
-
-void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error);
-void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
- u16 total_len, u16 cycle, u8 channel, u8 tag,
- u8 sy);
-void hpsb_iso_wake(struct hpsb_iso *iso);
-
-#endif /* IEEE1394_ISO_H */
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
deleted file mode 100644
index 18350213479e..000000000000
--- a/drivers/ieee1394/nodemgr.c
+++ /dev/null
@@ -1,1901 +0,0 @@
-/*
- * Node information (ConfigROM) collection and management.
- *
- * Copyright (C) 2000 Andreas E. Bombe
- * 2001-2003 Ben Collins <bcollins@debian.net>
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/bitmap.h>
-#include <linux/kernel.h>
-#include <linux/kmemcheck.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/kthread.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/mutex.h>
-#include <linux/freezer.h>
-#include <asm/atomic.h>
-
-#include "csr.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_types.h"
-#include "ieee1394_transactions.h"
-#include "nodemgr.h"
-
-static int ignore_drivers;
-module_param(ignore_drivers, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers.");
-
-struct nodemgr_csr_info {
- struct hpsb_host *host;
- nodeid_t nodeid;
- unsigned int generation;
-
- kmemcheck_bitfield_begin(flags);
- unsigned int speed_unverified:1;
- kmemcheck_bitfield_end(flags);
-};
-
-
-/*
- * Correct the speed map entry. This is necessary
- * - for nodes with link speed < phy speed,
- * - for 1394b nodes with negotiated phy port speed < IEEE1394_SPEED_MAX.
- * A possible speed is determined by trial and error, using quadlet reads.
- */
-static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
- quadlet_t *buffer)
-{
- quadlet_t q;
- u8 i, *speed, old_speed, good_speed;
- int error;
-
- speed = &(ci->host->speed[NODEID_TO_NODE(ci->nodeid)]);
- old_speed = *speed;
- good_speed = IEEE1394_SPEED_MAX + 1;
-
- /* Try every speed from S100 to old_speed.
- * If we did it the other way around, a too low speed could be caught
- * if the retry succeeded for some other reason, e.g. because the link
- * just finished its initialization. */
- for (i = IEEE1394_SPEED_100; i <= old_speed; i++) {
- *speed = i;
- error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
- &q, 4);
- if (error)
- break;
- *buffer = q;
- good_speed = i;
- }
- if (good_speed <= IEEE1394_SPEED_MAX) {
- HPSB_DEBUG("Speed probe of node " NODE_BUS_FMT " yields %s",
- NODE_BUS_ARGS(ci->host, ci->nodeid),
- hpsb_speedto_str[good_speed]);
- *speed = good_speed;
- ci->speed_unverified = 0;
- return 0;
- }
- *speed = old_speed;
- return error;
-}
-
-static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr,
- void *buffer, void *__ci)
-{
- struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci;
- int i, error;
-
- for (i = 1; ; i++) {
- error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
- buffer, 4);
- if (!error) {
- ci->speed_unverified = 0;
- break;
- }
- /* Give up after 3rd failure. */
- if (i == 3)
- break;
-
- /* The ieee1394_core guessed the node's speed capability from
- * the self ID. Check whether a lower speed works. */
- if (ci->speed_unverified) {
- error = nodemgr_check_speed(ci, addr, buffer);
- if (!error)
- break;
- }
- if (msleep_interruptible(334))
- return -EINTR;
- }
- return error;
-}
-
-static struct csr1212_bus_ops nodemgr_csr_ops = {
- .bus_read = nodemgr_bus_read,
-};
-
-
-/*
- * Basically what we do here is start off retrieving the bus_info block.
- * From there will fill in some info about the node, verify it is of IEEE
- * 1394 type, and that the crc checks out ok. After that we start off with
- * the root directory, and subdirectories. To do this, we retrieve the
- * quadlet header for a directory, find out the length, and retrieve the
- * complete directory entry (be it a leaf or a directory). We then process
- * it and add the info to our structure for that particular node.
- *
- * We verify CRC's along the way for each directory/block/leaf. The entire
- * node structure is generic, and simply stores the information in a way
- * that's easy to parse by the protocol interface.
- */
-
-/*
- * The nodemgr relies heavily on the Driver Model for device callbacks and
- * driver/device mappings. The old nodemgr used to handle all this itself,
- * but now we are much simpler because of the LDM.
- */
-
-struct host_info {
- struct hpsb_host *host;
- struct list_head list;
- struct task_struct *thread;
-};
-
-static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
-static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env);
-
-struct bus_type ieee1394_bus_type = {
- .name = "ieee1394",
- .match = nodemgr_bus_match,
-};
-
-static void host_cls_release(struct device *dev)
-{
- put_device(&container_of((dev), struct hpsb_host, host_dev)->device);
-}
-
-struct class hpsb_host_class = {
- .name = "ieee1394_host",
- .dev_release = host_cls_release,
-};
-
-static void ne_cls_release(struct device *dev)
-{
- put_device(&container_of((dev), struct node_entry, node_dev)->device);
-}
-
-static struct class nodemgr_ne_class = {
- .name = "ieee1394_node",
- .dev_release = ne_cls_release,
-};
-
-static void ud_cls_release(struct device *dev)
-{
- put_device(&container_of((dev), struct unit_directory, unit_dev)->device);
-}
-
-/* The name here is only so that unit directory hotplug works with old
- * style hotplug, which only ever did unit directories anyway.
- */
-static struct class nodemgr_ud_class = {
- .name = "ieee1394",
- .dev_release = ud_cls_release,
- .dev_uevent = nodemgr_uevent,
-};
-
-static struct hpsb_highlevel nodemgr_highlevel;
-
-
-static void nodemgr_release_ud(struct device *dev)
-{
- struct unit_directory *ud = container_of(dev, struct unit_directory, device);
-
- if (ud->vendor_name_kv)
- csr1212_release_keyval(ud->vendor_name_kv);
- if (ud->model_name_kv)
- csr1212_release_keyval(ud->model_name_kv);
-
- kfree(ud);
-}
-
-static void nodemgr_release_ne(struct device *dev)
-{
- struct node_entry *ne = container_of(dev, struct node_entry, device);
-
- if (ne->vendor_name_kv)
- csr1212_release_keyval(ne->vendor_name_kv);
-
- kfree(ne);
-}
-
-
-static void nodemgr_release_host(struct device *dev)
-{
- struct hpsb_host *host = container_of(dev, struct hpsb_host, device);
-
- csr1212_destroy_csr(host->csr.rom);
-
- kfree(host);
-}
-
-static int nodemgr_ud_platform_data;
-
-static struct device nodemgr_dev_template_ud = {
- .bus = &ieee1394_bus_type,
- .release = nodemgr_release_ud,
- .platform_data = &nodemgr_ud_platform_data,
-};
-
-static struct device nodemgr_dev_template_ne = {
- .bus = &ieee1394_bus_type,
- .release = nodemgr_release_ne,
-};
-
-/* This dummy driver prevents the host devices from being scanned. We have no
- * useful drivers for them yet, and there would be a deadlock possible if the
- * driver core scans the host device while the host's low-level driver (i.e.
- * the host's parent device) is being removed. */
-static struct device_driver nodemgr_mid_layer_driver = {
- .bus = &ieee1394_bus_type,
- .name = "nodemgr",
- .owner = THIS_MODULE,
-};
-
-struct device nodemgr_dev_template_host = {
- .bus = &ieee1394_bus_type,
- .release = nodemgr_release_host,
-};
-
-
-#define fw_attr(class, class_type, field, type, format_string) \
-static ssize_t fw_show_##class##_##field (struct device *dev, struct device_attribute *attr, char *buf)\
-{ \
- class_type *class; \
- class = container_of(dev, class_type, device); \
- return sprintf(buf, format_string, (type)class->field); \
-} \
-static struct device_attribute dev_attr_##class##_##field = { \
- .attr = {.name = __stringify(field), .mode = S_IRUGO }, \
- .show = fw_show_##class##_##field, \
-};
-
-#define fw_attr_td(class, class_type, td_kv) \
-static ssize_t fw_show_##class##_##td_kv (struct device *dev, struct device_attribute *attr, char *buf)\
-{ \
- int len; \
- class_type *class = container_of(dev, class_type, device); \
- len = (class->td_kv->value.leaf.len - 2) * sizeof(quadlet_t); \
- memcpy(buf, \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(class->td_kv), \
- len); \
- while (buf[len - 1] == '\0') \
- len--; \
- buf[len++] = '\n'; \
- buf[len] = '\0'; \
- return len; \
-} \
-static struct device_attribute dev_attr_##class##_##td_kv = { \
- .attr = {.name = __stringify(td_kv), .mode = S_IRUGO }, \
- .show = fw_show_##class##_##td_kv, \
-};
-
-
-#define fw_drv_attr(field, type, format_string) \
-static ssize_t fw_drv_show_##field (struct device_driver *drv, char *buf) \
-{ \
- struct hpsb_protocol_driver *driver; \
- driver = container_of(drv, struct hpsb_protocol_driver, driver); \
- return sprintf(buf, format_string, (type)driver->field);\
-} \
-static struct driver_attribute driver_attr_drv_##field = { \
- .attr = {.name = __stringify(field), .mode = S_IRUGO }, \
- .show = fw_drv_show_##field, \
-};
-
-
-static ssize_t fw_show_ne_bus_options(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct node_entry *ne = container_of(dev, struct node_entry, device);
-
- return sprintf(buf, "IRMC(%d) CMC(%d) ISC(%d) BMC(%d) PMC(%d) GEN(%d) "
- "LSPD(%d) MAX_REC(%d) MAX_ROM(%d) CYC_CLK_ACC(%d)\n",
- ne->busopt.irmc,
- ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc,
- ne->busopt.pmc, ne->busopt.generation, ne->busopt.lnkspd,
- ne->busopt.max_rec,
- ne->busopt.max_rom,
- ne->busopt.cyc_clk_acc);
-}
-static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);
-
-
-#ifdef HPSB_DEBUG_TLABELS
-static ssize_t fw_show_ne_tlabels_free(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct node_entry *ne = container_of(dev, struct node_entry, device);
- unsigned long flags;
- unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
- int tf;
-
- spin_lock_irqsave(&hpsb_tlabel_lock, flags);
- tf = 64 - bitmap_weight(tp, 64);
- spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
- return sprintf(buf, "%d\n", tf);
-}
-static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
-
-
-static ssize_t fw_show_ne_tlabels_mask(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct node_entry *ne = container_of(dev, struct node_entry, device);
- unsigned long flags;
- unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
- u64 tm;
-
- spin_lock_irqsave(&hpsb_tlabel_lock, flags);
-#if (BITS_PER_LONG <= 32)
- tm = ((u64)tp[0] << 32) + tp[1];
-#else
- tm = tp[0];
-#endif
- spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
- return sprintf(buf, "0x%016llx\n", (unsigned long long)tm);
-}
-static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL);
-#endif /* HPSB_DEBUG_TLABELS */
-
-
-static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
- struct unit_directory *ud = container_of(dev, struct unit_directory, device);
- int state = simple_strtoul(buf, NULL, 10);
-
- if (state == 1) {
- ud->ignore_driver = 1;
- device_release_driver(dev);
- } else if (state == 0)
- ud->ignore_driver = 0;
-
- return count;
-}
-static ssize_t fw_get_ignore_driver(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct unit_directory *ud = container_of(dev, struct unit_directory, device);
-
- return sprintf(buf, "%d\n", ud->ignore_driver);
-}
-static DEVICE_ATTR(ignore_driver, S_IWUSR | S_IRUGO, fw_get_ignore_driver, fw_set_ignore_driver);
-
-
-static ssize_t fw_set_rescan(struct bus_type *bus, const char *buf,
- size_t count)
-{
- int error = 0;
-
- if (simple_strtoul(buf, NULL, 10) == 1)
- error = bus_rescan_devices(&ieee1394_bus_type);
- return error ? error : count;
-}
-static ssize_t fw_get_rescan(struct bus_type *bus, char *buf)
-{
- return sprintf(buf, "You can force a rescan of the bus for "
- "drivers by writing a 1 to this file\n");
-}
-static BUS_ATTR(rescan, S_IWUSR | S_IRUGO, fw_get_rescan, fw_set_rescan);
-
-
-static ssize_t fw_set_ignore_drivers(struct bus_type *bus, const char *buf, size_t count)
-{
- int state = simple_strtoul(buf, NULL, 10);
-
- if (state == 1)
- ignore_drivers = 1;
- else if (state == 0)
- ignore_drivers = 0;
-
- return count;
-}
-static ssize_t fw_get_ignore_drivers(struct bus_type *bus, char *buf)
-{
- return sprintf(buf, "%d\n", ignore_drivers);
-}
-static BUS_ATTR(ignore_drivers, S_IWUSR | S_IRUGO, fw_get_ignore_drivers, fw_set_ignore_drivers);
-
-
-struct bus_attribute *const fw_bus_attrs[] = {
- &bus_attr_rescan,
- &bus_attr_ignore_drivers,
- NULL
-};
-
-
-fw_attr(ne, struct node_entry, capabilities, unsigned int, "0x%06x\n")
-fw_attr(ne, struct node_entry, nodeid, unsigned int, "0x%04x\n")
-
-fw_attr(ne, struct node_entry, vendor_id, unsigned int, "0x%06x\n")
-fw_attr_td(ne, struct node_entry, vendor_name_kv)
-
-fw_attr(ne, struct node_entry, guid, unsigned long long, "0x%016Lx\n")
-fw_attr(ne, struct node_entry, guid_vendor_id, unsigned int, "0x%06x\n")
-fw_attr(ne, struct node_entry, in_limbo, int, "%d\n");
-
-static struct device_attribute *const fw_ne_attrs[] = {
- &dev_attr_ne_guid,
- &dev_attr_ne_guid_vendor_id,
- &dev_attr_ne_capabilities,
- &dev_attr_ne_vendor_id,
- &dev_attr_ne_nodeid,
- &dev_attr_bus_options,
-#ifdef HPSB_DEBUG_TLABELS
- &dev_attr_tlabels_free,
- &dev_attr_tlabels_mask,
-#endif
-};
-
-
-
-fw_attr(ud, struct unit_directory, address, unsigned long long, "0x%016Lx\n")
-fw_attr(ud, struct unit_directory, length, int, "%d\n")
-/* These are all dependent on the value being provided */
-fw_attr(ud, struct unit_directory, vendor_id, unsigned int, "0x%06x\n")
-fw_attr(ud, struct unit_directory, model_id, unsigned int, "0x%06x\n")
-fw_attr(ud, struct unit_directory, specifier_id, unsigned int, "0x%06x\n")
-fw_attr(ud, struct unit_directory, version, unsigned int, "0x%06x\n")
-fw_attr_td(ud, struct unit_directory, vendor_name_kv)
-fw_attr_td(ud, struct unit_directory, model_name_kv)
-
-static struct device_attribute *const fw_ud_attrs[] = {
- &dev_attr_ud_address,
- &dev_attr_ud_length,
- &dev_attr_ignore_driver,
-};
-
-
-fw_attr(host, struct hpsb_host, node_count, int, "%d\n")
-fw_attr(host, struct hpsb_host, selfid_count, int, "%d\n")
-fw_attr(host, struct hpsb_host, nodes_active, int, "%d\n")
-fw_attr(host, struct hpsb_host, in_bus_reset, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_root, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_cycmst, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_irm, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_busmgr, int, "%d\n")
-
-static struct device_attribute *const fw_host_attrs[] = {
- &dev_attr_host_node_count,
- &dev_attr_host_selfid_count,
- &dev_attr_host_nodes_active,
- &dev_attr_host_in_bus_reset,
- &dev_attr_host_is_root,
- &dev_attr_host_is_cycmst,
- &dev_attr_host_is_irm,
- &dev_attr_host_is_busmgr,
-};
-
-
-static ssize_t fw_show_drv_device_ids(struct device_driver *drv, char *buf)
-{
- struct hpsb_protocol_driver *driver;
- const struct ieee1394_device_id *id;
- int length = 0;
- char *scratch = buf;
-
- driver = container_of(drv, struct hpsb_protocol_driver, driver);
- id = driver->id_table;
- if (!id)
- return 0;
-
- for (; id->match_flags != 0; id++) {
- int need_coma = 0;
-
- if (id->match_flags & IEEE1394_MATCH_VENDOR_ID) {
- length += sprintf(scratch, "vendor_id=0x%06x", id->vendor_id);
- scratch = buf + length;
- need_coma++;
- }
-
- if (id->match_flags & IEEE1394_MATCH_MODEL_ID) {
- length += sprintf(scratch, "%smodel_id=0x%06x",
- need_coma++ ? "," : "",
- id->model_id);
- scratch = buf + length;
- }
-
- if (id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) {
- length += sprintf(scratch, "%sspecifier_id=0x%06x",
- need_coma++ ? "," : "",
- id->specifier_id);
- scratch = buf + length;
- }
-
- if (id->match_flags & IEEE1394_MATCH_VERSION) {
- length += sprintf(scratch, "%sversion=0x%06x",
- need_coma++ ? "," : "",
- id->version);
- scratch = buf + length;
- }
-
- if (need_coma) {
- *scratch++ = '\n';
- length++;
- }
- }
-
- return length;
-}
-static DRIVER_ATTR(device_ids,S_IRUGO,fw_show_drv_device_ids,NULL);
-
-
-fw_drv_attr(name, const char *, "%s\n")
-
-static struct driver_attribute *const fw_drv_attrs[] = {
- &driver_attr_drv_name,
- &driver_attr_device_ids,
-};
-
-
-static void nodemgr_create_drv_files(struct hpsb_protocol_driver *driver)
-{
- struct device_driver *drv = &driver->driver;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(fw_drv_attrs); i++)
- if (driver_create_file(drv, fw_drv_attrs[i]))
- goto fail;
- return;
-fail:
- HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static void nodemgr_remove_drv_files(struct hpsb_protocol_driver *driver)
-{
- struct device_driver *drv = &driver->driver;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(fw_drv_attrs); i++)
- driver_remove_file(drv, fw_drv_attrs[i]);
-}
-
-
-static void nodemgr_create_ne_dev_files(struct node_entry *ne)
-{
- struct device *dev = &ne->device;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(fw_ne_attrs); i++)
- if (device_create_file(dev, fw_ne_attrs[i]))
- goto fail;
- return;
-fail:
- HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static void nodemgr_create_host_dev_files(struct hpsb_host *host)
-{
- struct device *dev = &host->device;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(fw_host_attrs); i++)
- if (device_create_file(dev, fw_host_attrs[i]))
- goto fail;
- return;
-fail:
- HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
- nodeid_t nodeid);
-
-static void nodemgr_update_host_dev_links(struct hpsb_host *host)
-{
- struct device *dev = &host->device;
- struct node_entry *ne;
-
- sysfs_remove_link(&dev->kobj, "irm_id");
- sysfs_remove_link(&dev->kobj, "busmgr_id");
- sysfs_remove_link(&dev->kobj, "host_id");
-
- if ((ne = find_entry_by_nodeid(host, host->irm_id)) &&
- sysfs_create_link(&dev->kobj, &ne->device.kobj, "irm_id"))
- goto fail;
- if ((ne = find_entry_by_nodeid(host, host->busmgr_id)) &&
- sysfs_create_link(&dev->kobj, &ne->device.kobj, "busmgr_id"))
- goto fail;
- if ((ne = find_entry_by_nodeid(host, host->node_id)) &&
- sysfs_create_link(&dev->kobj, &ne->device.kobj, "host_id"))
- goto fail;
- return;
-fail:
- HPSB_ERR("Failed to update sysfs attributes for host %d", host->id);
-}
-
-static void nodemgr_create_ud_dev_files(struct unit_directory *ud)
-{
- struct device *dev = &ud->device;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(fw_ud_attrs); i++)
- if (device_create_file(dev, fw_ud_attrs[i]))
- goto fail;
- if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)
- if (device_create_file(dev, &dev_attr_ud_specifier_id))
- goto fail;
- if (ud->flags & UNIT_DIRECTORY_VERSION)
- if (device_create_file(dev, &dev_attr_ud_version))
- goto fail;
- if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) {
- if (device_create_file(dev, &dev_attr_ud_vendor_id))
- goto fail;
- if (ud->vendor_name_kv &&
- device_create_file(dev, &dev_attr_ud_vendor_name_kv))
- goto fail;
- }
- if (ud->flags & UNIT_DIRECTORY_MODEL_ID) {
- if (device_create_file(dev, &dev_attr_ud_model_id))
- goto fail;
- if (ud->model_name_kv &&
- device_create_file(dev, &dev_attr_ud_model_name_kv))
- goto fail;
- }
- return;
-fail:
- HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
-{
- struct hpsb_protocol_driver *driver;
- struct unit_directory *ud;
- const struct ieee1394_device_id *id;
-
- /* We only match unit directories */
- if (dev->platform_data != &nodemgr_ud_platform_data)
- return 0;
-
- ud = container_of(dev, struct unit_directory, device);
- if (ud->ne->in_limbo || ud->ignore_driver)
- return 0;
-
- /* We only match drivers of type hpsb_protocol_driver */
- if (drv == &nodemgr_mid_layer_driver)
- return 0;
-
- driver = container_of(drv, struct hpsb_protocol_driver, driver);
- id = driver->id_table;
- if (!id)
- return 0;
-
- for (; id->match_flags != 0; id++) {
- if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) &&
- id->vendor_id != ud->vendor_id)
- continue;
-
- if ((id->match_flags & IEEE1394_MATCH_MODEL_ID) &&
- id->model_id != ud->model_id)
- continue;
-
- if ((id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) &&
- id->specifier_id != ud->specifier_id)
- continue;
-
- if ((id->match_flags & IEEE1394_MATCH_VERSION) &&
- id->version != ud->version)
- continue;
-
- return 1;
- }
-
- return 0;
-}
-
-
-static DEFINE_MUTEX(nodemgr_serialize_remove_uds);
-
-static int match_ne(struct device *dev, void *data)
-{
- struct unit_directory *ud;
- struct node_entry *ne = data;
-
- ud = container_of(dev, struct unit_directory, unit_dev);
- return ud->ne == ne;
-}
-
-static void nodemgr_remove_uds(struct node_entry *ne)
-{
- struct device *dev;
- struct unit_directory *ud;
-
- /* Use class_find device to iterate the devices. Since this code
- * may be called from other contexts besides the knodemgrds,
- * protect it by nodemgr_serialize_remove_uds.
- */
- mutex_lock(&nodemgr_serialize_remove_uds);
- for (;;) {
- dev = class_find_device(&nodemgr_ud_class, NULL, ne, match_ne);
- if (!dev)
- break;
- ud = container_of(dev, struct unit_directory, unit_dev);
- put_device(dev);
- device_unregister(&ud->unit_dev);
- device_unregister(&ud->device);
- }
- mutex_unlock(&nodemgr_serialize_remove_uds);
-}
-
-
-static void nodemgr_remove_ne(struct node_entry *ne)
-{
- struct device *dev;
-
- dev = get_device(&ne->device);
- if (!dev)
- return;
-
- HPSB_DEBUG("Node removed: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
- NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
- nodemgr_remove_uds(ne);
-
- device_unregister(&ne->node_dev);
- device_unregister(dev);
-
- put_device(dev);
-}
-
-static int remove_host_dev(struct device *dev, void *data)
-{
- if (dev->bus == &ieee1394_bus_type)
- nodemgr_remove_ne(container_of(dev, struct node_entry,
- device));
- return 0;
-}
-
-static void nodemgr_remove_host_dev(struct device *dev)
-{
- device_for_each_child(dev, NULL, remove_host_dev);
- sysfs_remove_link(&dev->kobj, "irm_id");
- sysfs_remove_link(&dev->kobj, "busmgr_id");
- sysfs_remove_link(&dev->kobj, "host_id");
-}
-
-
-static void nodemgr_update_bus_options(struct node_entry *ne)
-{
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
- static const u16 mr[] = { 4, 64, 1024, 0};
-#endif
- quadlet_t busoptions = be32_to_cpu(ne->csr->bus_info_data[2]);
-
- ne->busopt.irmc = (busoptions >> 31) & 1;
- ne->busopt.cmc = (busoptions >> 30) & 1;
- ne->busopt.isc = (busoptions >> 29) & 1;
- ne->busopt.bmc = (busoptions >> 28) & 1;
- ne->busopt.pmc = (busoptions >> 27) & 1;
- ne->busopt.cyc_clk_acc = (busoptions >> 16) & 0xff;
- ne->busopt.max_rec = 1 << (((busoptions >> 12) & 0xf) + 1);
- ne->busopt.max_rom = (busoptions >> 8) & 0x3;
- ne->busopt.generation = (busoptions >> 4) & 0xf;
- ne->busopt.lnkspd = busoptions & 0x7;
-
- HPSB_VERBOSE("NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d "
- "cyc_clk_acc=%d max_rec=%d max_rom=%d gen=%d lspd=%d",
- busoptions, ne->busopt.irmc, ne->busopt.cmc,
- ne->busopt.isc, ne->busopt.bmc, ne->busopt.pmc,
- ne->busopt.cyc_clk_acc, ne->busopt.max_rec,
- mr[ne->busopt.max_rom],
- ne->busopt.generation, ne->busopt.lnkspd);
-}
-
-
-static struct node_entry *nodemgr_create_node(octlet_t guid,
- struct csr1212_csr *csr, struct hpsb_host *host,
- nodeid_t nodeid, unsigned int generation)
-{
- struct node_entry *ne;
-
- ne = kzalloc(sizeof(*ne), GFP_KERNEL);
- if (!ne)
- goto fail_alloc;
-
- ne->host = host;
- ne->nodeid = nodeid;
- ne->generation = generation;
- ne->needs_probe = true;
-
- ne->guid = guid;
- ne->guid_vendor_id = (guid >> 40) & 0xffffff;
- ne->csr = csr;
-
- memcpy(&ne->device, &nodemgr_dev_template_ne,
- sizeof(ne->device));
- ne->device.parent = &host->device;
- dev_set_name(&ne->device, "%016Lx", (unsigned long long)(ne->guid));
-
- ne->node_dev.parent = &ne->device;
- ne->node_dev.class = &nodemgr_ne_class;
- dev_set_name(&ne->node_dev, "%016Lx", (unsigned long long)(ne->guid));
-
- if (device_register(&ne->device))
- goto fail_devreg;
- if (device_register(&ne->node_dev))
- goto fail_classdevreg;
- get_device(&ne->device);
-
- nodemgr_create_ne_dev_files(ne);
-
- nodemgr_update_bus_options(ne);
-
- HPSB_DEBUG("%s added: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
- (host->node_id == nodeid) ? "Host" : "Node",
- NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid);
-
- return ne;
-
-fail_classdevreg:
- device_unregister(&ne->device);
-fail_devreg:
- kfree(ne);
-fail_alloc:
- HPSB_ERR("Failed to create node ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
- NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid);
-
- return NULL;
-}
-
-static int match_ne_guid(struct device *dev, void *data)
-{
- struct node_entry *ne;
- u64 *guid = data;
-
- ne = container_of(dev, struct node_entry, node_dev);
- return ne->guid == *guid;
-}
-
-static struct node_entry *find_entry_by_guid(u64 guid)
-{
- struct device *dev;
- struct node_entry *ne;
-
- dev = class_find_device(&nodemgr_ne_class, NULL, &guid, match_ne_guid);
- if (!dev)
- return NULL;
- ne = container_of(dev, struct node_entry, node_dev);
- put_device(dev);
-
- return ne;
-}
-
-struct match_nodeid_parameter {
- struct hpsb_host *host;
- nodeid_t nodeid;
-};
-
-static int match_ne_nodeid(struct device *dev, void *data)
-{
- int found = 0;
- struct node_entry *ne;
- struct match_nodeid_parameter *p = data;
-
- if (!dev)
- goto ret;
- ne = container_of(dev, struct node_entry, node_dev);
- if (ne->host == p->host && ne->nodeid == p->nodeid)
- found = 1;
-ret:
- return found;
-}
-
-static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
- nodeid_t nodeid)
-{
- struct device *dev;
- struct node_entry *ne;
- struct match_nodeid_parameter p;
-
- p.host = host;
- p.nodeid = nodeid;
-
- dev = class_find_device(&nodemgr_ne_class, NULL, &p, match_ne_nodeid);
- if (!dev)
- return NULL;
- ne = container_of(dev, struct node_entry, node_dev);
- put_device(dev);
-
- return ne;
-}
-
-
-static void nodemgr_register_device(struct node_entry *ne,
- struct unit_directory *ud, struct device *parent)
-{
- memcpy(&ud->device, &nodemgr_dev_template_ud,
- sizeof(ud->device));
-
- ud->device.parent = parent;
-
- dev_set_name(&ud->device, "%s-%u", dev_name(&ne->device), ud->id);
-
- ud->unit_dev.parent = &ud->device;
- ud->unit_dev.class = &nodemgr_ud_class;
- dev_set_name(&ud->unit_dev, "%s-%u", dev_name(&ne->device), ud->id);
-
- if (device_register(&ud->device))
- goto fail_devreg;
- if (device_register(&ud->unit_dev))
- goto fail_classdevreg;
- get_device(&ud->device);
-
- nodemgr_create_ud_dev_files(ud);
-
- return;
-
-fail_classdevreg:
- device_unregister(&ud->device);
-fail_devreg:
- HPSB_ERR("Failed to create unit %s", dev_name(&ud->device));
-}
-
-
-/* This implementation currently only scans the config rom and its
- * immediate unit directories looking for software_id and
- * software_version entries, in order to get driver autoloading working. */
-static struct unit_directory *nodemgr_process_unit_directory
- (struct node_entry *ne, struct csr1212_keyval *ud_kv,
- unsigned int *id, struct unit_directory *parent)
-{
- struct unit_directory *ud;
- struct unit_directory *ud_child = NULL;
- struct csr1212_dentry *dentry;
- struct csr1212_keyval *kv;
- u8 last_key_id = 0;
-
- ud = kzalloc(sizeof(*ud), GFP_KERNEL);
- if (!ud)
- goto unit_directory_error;
-
- ud->ne = ne;
- ud->ignore_driver = ignore_drivers;
- ud->address = ud_kv->offset + CSR1212_REGISTER_SPACE_BASE;
- ud->directory_id = ud->address & 0xffffff;
- ud->ud_kv = ud_kv;
- ud->id = (*id)++;
-
- /* inherit vendor_id from root directory if none exists in unit dir */
- ud->vendor_id = ne->vendor_id;
-
- csr1212_for_each_dir_entry(ne->csr, kv, ud_kv, dentry) {
- switch (kv->key.id) {
- case CSR1212_KV_ID_VENDOR:
- if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
- ud->vendor_id = kv->value.immediate;
- ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
- }
- break;
-
- case CSR1212_KV_ID_MODEL:
- ud->model_id = kv->value.immediate;
- ud->flags |= UNIT_DIRECTORY_MODEL_ID;
- break;
-
- case CSR1212_KV_ID_SPECIFIER_ID:
- ud->specifier_id = kv->value.immediate;
- ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID;
- break;
-
- case CSR1212_KV_ID_VERSION:
- ud->version = kv->value.immediate;
- ud->flags |= UNIT_DIRECTORY_VERSION;
- break;
-
- case CSR1212_KV_ID_DESCRIPTOR:
- if (kv->key.type == CSR1212_KV_TYPE_LEAF &&
- CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 &&
- CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 &&
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {
- switch (last_key_id) {
- case CSR1212_KV_ID_VENDOR:
- csr1212_keep_keyval(kv);
- ud->vendor_name_kv = kv;
- break;
-
- case CSR1212_KV_ID_MODEL:
- csr1212_keep_keyval(kv);
- ud->model_name_kv = kv;
- break;
-
- }
- } /* else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) ... */
- break;
-
- case CSR1212_KV_ID_DEPENDENT_INFO:
- /* Logical Unit Number */
- if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
- if (ud->flags & UNIT_DIRECTORY_HAS_LUN) {
- ud_child = kmemdup(ud, sizeof(*ud_child), GFP_KERNEL);
- if (!ud_child)
- goto unit_directory_error;
- nodemgr_register_device(ne, ud_child, &ne->device);
- ud_child = NULL;
-
- ud->id = (*id)++;
- }
- ud->lun = kv->value.immediate;
- ud->flags |= UNIT_DIRECTORY_HAS_LUN;
-
- /* Logical Unit Directory */
- } else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) {
- /* This should really be done in SBP2 as this is
- * doing SBP2 specific parsing.
- */
-
- /* first register the parent unit */
- ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY;
- if (ud->device.bus != &ieee1394_bus_type)
- nodemgr_register_device(ne, ud, &ne->device);
-
- /* process the child unit */
- ud_child = nodemgr_process_unit_directory(ne, kv, id, ud);
-
- if (ud_child == NULL)
- break;
-
- /* inherit unspecified values, the driver core picks it up */
- if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) &&
- !(ud_child->flags & UNIT_DIRECTORY_MODEL_ID))
- {
- ud_child->flags |= UNIT_DIRECTORY_MODEL_ID;
- ud_child->model_id = ud->model_id;
- }
- if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) &&
- !(ud_child->flags & UNIT_DIRECTORY_SPECIFIER_ID))
- {
- ud_child->flags |= UNIT_DIRECTORY_SPECIFIER_ID;
- ud_child->specifier_id = ud->specifier_id;
- }
- if ((ud->flags & UNIT_DIRECTORY_VERSION) &&
- !(ud_child->flags & UNIT_DIRECTORY_VERSION))
- {
- ud_child->flags |= UNIT_DIRECTORY_VERSION;
- ud_child->version = ud->version;
- }
-
- /* register the child unit */
- ud_child->flags |= UNIT_DIRECTORY_LUN_DIRECTORY;
- nodemgr_register_device(ne, ud_child, &ud->device);
- }
-
- break;
-
- case CSR1212_KV_ID_DIRECTORY_ID:
- ud->directory_id = kv->value.immediate;
- break;
-
- default:
- break;
- }
- last_key_id = kv->key.id;
- }
-
- /* do not process child units here and only if not already registered */
- if (!parent && ud->device.bus != &ieee1394_bus_type)
- nodemgr_register_device(ne, ud, &ne->device);
-
- return ud;
-
-unit_directory_error:
- kfree(ud);
- return NULL;
-}
-
-
-static void nodemgr_process_root_directory(struct node_entry *ne)
-{
- unsigned int ud_id = 0;
- struct csr1212_dentry *dentry;
- struct csr1212_keyval *kv, *vendor_name_kv = NULL;
- u8 last_key_id = 0;
-
- ne->needs_probe = false;
-
- csr1212_for_each_dir_entry(ne->csr, kv, ne->csr->root_kv, dentry) {
- switch (kv->key.id) {
- case CSR1212_KV_ID_VENDOR:
- ne->vendor_id = kv->value.immediate;
- break;
-
- case CSR1212_KV_ID_NODE_CAPABILITIES:
- ne->capabilities = kv->value.immediate;
- break;
-
- case CSR1212_KV_ID_UNIT:
- nodemgr_process_unit_directory(ne, kv, &ud_id, NULL);
- break;
-
- case CSR1212_KV_ID_DESCRIPTOR:
- if (last_key_id == CSR1212_KV_ID_VENDOR) {
- if (kv->key.type == CSR1212_KV_TYPE_LEAF &&
- CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 &&
- CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 &&
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {
- csr1212_keep_keyval(kv);
- vendor_name_kv = kv;
- }
- }
- break;
- }
- last_key_id = kv->key.id;
- }
-
- if (ne->vendor_name_kv) {
- kv = ne->vendor_name_kv;
- ne->vendor_name_kv = vendor_name_kv;
- csr1212_release_keyval(kv);
- } else if (vendor_name_kv) {
- ne->vendor_name_kv = vendor_name_kv;
- if (device_create_file(&ne->device,
- &dev_attr_ne_vendor_name_kv) != 0)
- HPSB_ERR("Failed to add sysfs attribute");
- }
-}
-
-#ifdef CONFIG_HOTPLUG
-
-static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- struct unit_directory *ud;
- int retval = 0;
- /* ieee1394:venNmoNspNverN */
- char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
-
- if (!dev)
- return -ENODEV;
-
- ud = container_of(dev, struct unit_directory, unit_dev);
-
- if (ud->ne->in_limbo || ud->ignore_driver)
- return -ENODEV;
-
-#define PUT_ENVP(fmt,val) \
-do { \
- retval = add_uevent_var(env, fmt, val); \
- if (retval) \
- return retval; \
-} while (0)
-
- PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id);
- PUT_ENVP("MODEL_ID=%06x", ud->model_id);
- PUT_ENVP("GUID=%016Lx", (unsigned long long)ud->ne->guid);
- PUT_ENVP("SPECIFIER_ID=%06x", ud->specifier_id);
- PUT_ENVP("VERSION=%06x", ud->version);
- snprintf(buf, sizeof(buf), "ieee1394:ven%08Xmo%08Xsp%08Xver%08X",
- ud->vendor_id,
- ud->model_id,
- ud->specifier_id,
- ud->version);
- PUT_ENVP("MODALIAS=%s", buf);
-
-#undef PUT_ENVP
-
- return 0;
-}
-
-#else
-
-static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- return -ENODEV;
-}
-
-#endif /* CONFIG_HOTPLUG */
-
-
-int __hpsb_register_protocol(struct hpsb_protocol_driver *drv,
- struct module *owner)
-{
- int error;
-
- drv->driver.bus = &ieee1394_bus_type;
- drv->driver.owner = owner;
- drv->driver.name = drv->name;
-
- /* This will cause a probe for devices */
- error = driver_register(&drv->driver);
- if (!error)
- nodemgr_create_drv_files(drv);
- return error;
-}
-
-void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver)
-{
- nodemgr_remove_drv_files(driver);
- /* This will subsequently disconnect all devices that our driver
- * is attached to. */
- driver_unregister(&driver->driver);
-}
-
-
-/*
- * This function updates nodes that were present on the bus before the
- * reset and still are after the reset. The nodeid and the config rom
- * may have changed, and the drivers managing this device must be
- * informed that this device just went through a bus reset, to allow
- * the to take whatever actions required.
- */
-static void nodemgr_update_node(struct node_entry *ne, struct csr1212_csr *csr,
- nodeid_t nodeid, unsigned int generation)
-{
- if (ne->nodeid != nodeid) {
- HPSB_DEBUG("Node changed: " NODE_BUS_FMT " -> " NODE_BUS_FMT,
- NODE_BUS_ARGS(ne->host, ne->nodeid),
- NODE_BUS_ARGS(ne->host, nodeid));
- ne->nodeid = nodeid;
- }
-
- if (ne->busopt.generation != ((be32_to_cpu(csr->bus_info_data[2]) >> 4) & 0xf)) {
- kfree(ne->csr->private);
- csr1212_destroy_csr(ne->csr);
- ne->csr = csr;
-
- /* If the node's configrom generation has changed, we
- * unregister all the unit directories. */
- nodemgr_remove_uds(ne);
-
- nodemgr_update_bus_options(ne);
-
- /* Mark the node as new, so it gets re-probed */
- ne->needs_probe = true;
- } else {
- /* old cache is valid, so update its generation */
- struct nodemgr_csr_info *ci = ne->csr->private;
- ci->generation = generation;
- /* free the partially filled now unneeded new cache */
- kfree(csr->private);
- csr1212_destroy_csr(csr);
- }
-
- /* Finally, mark the node current */
- smp_wmb();
- ne->generation = generation;
-
- if (ne->in_limbo) {
- device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
- ne->in_limbo = false;
-
- HPSB_DEBUG("Node reactivated: "
- "ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
- NODE_BUS_ARGS(ne->host, ne->nodeid),
- (unsigned long long)ne->guid);
- }
-}
-
-static void nodemgr_node_scan_one(struct hpsb_host *host,
- nodeid_t nodeid, int generation)
-{
- struct node_entry *ne;
- octlet_t guid;
- struct csr1212_csr *csr;
- struct nodemgr_csr_info *ci;
- u8 *speed;
-
- ci = kmalloc(sizeof(*ci), GFP_KERNEL);
- kmemcheck_annotate_bitfield(ci, flags);
- if (!ci)
- return;
-
- ci->host = host;
- ci->nodeid = nodeid;
- ci->generation = generation;
-
- /* Prepare for speed probe which occurs when reading the ROM */
- speed = &(host->speed[NODEID_TO_NODE(nodeid)]);
- if (*speed > host->csr.lnk_spd)
- *speed = host->csr.lnk_spd;
- ci->speed_unverified = *speed > IEEE1394_SPEED_100;
-
- /* We need to detect when the ConfigROM's generation has changed,
- * so we only update the node's info when it needs to be. */
-
- csr = csr1212_create_csr(&nodemgr_csr_ops, 5 * sizeof(quadlet_t), ci);
- if (!csr || csr1212_parse_csr(csr) != CSR1212_SUCCESS) {
- HPSB_ERR("Error parsing configrom for node " NODE_BUS_FMT,
- NODE_BUS_ARGS(host, nodeid));
- if (csr)
- csr1212_destroy_csr(csr);
- kfree(ci);
- return;
- }
-
- if (csr->bus_info_data[1] != IEEE1394_BUSID_MAGIC) {
- /* This isn't a 1394 device, but we let it slide. There
- * was a report of a device with broken firmware which
- * reported '2394' instead of '1394', which is obviously a
- * mistake. One would hope that a non-1394 device never
- * gets connected to Firewire bus. If someone does, we
- * shouldn't be held responsible, so we'll allow it with a
- * warning. */
- HPSB_WARN("Node " NODE_BUS_FMT " has invalid busID magic [0x%08x]",
- NODE_BUS_ARGS(host, nodeid), csr->bus_info_data[1]);
- }
-
- guid = ((u64)be32_to_cpu(csr->bus_info_data[3]) << 32) | be32_to_cpu(csr->bus_info_data[4]);
- ne = find_entry_by_guid(guid);
-
- if (ne && ne->host != host && ne->in_limbo) {
- /* Must have moved this device from one host to another */
- nodemgr_remove_ne(ne);
- ne = NULL;
- }
-
- if (!ne)
- nodemgr_create_node(guid, csr, host, nodeid, generation);
- else
- nodemgr_update_node(ne, csr, nodeid, generation);
-}
-
-
-static void nodemgr_node_scan(struct hpsb_host *host, int generation)
-{
- int count;
- struct selfid *sid = (struct selfid *)host->topology_map;
- nodeid_t nodeid = LOCAL_BUS;
-
- /* Scan each node on the bus */
- for (count = host->selfid_count; count; count--, sid++) {
- if (sid->extended)
- continue;
-
- if (!sid->link_active) {
- nodeid++;
- continue;
- }
- nodemgr_node_scan_one(host, nodeid++, generation);
- }
-}
-
-static void nodemgr_pause_ne(struct node_entry *ne)
-{
- HPSB_DEBUG("Node paused: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
- NODE_BUS_ARGS(ne->host, ne->nodeid),
- (unsigned long long)ne->guid);
-
- ne->in_limbo = true;
- WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo));
-}
-
-static int update_pdrv(struct device *dev, void *data)
-{
- struct unit_directory *ud;
- struct device_driver *drv;
- struct hpsb_protocol_driver *pdrv;
- struct node_entry *ne = data;
- int error;
-
- ud = container_of(dev, struct unit_directory, unit_dev);
- if (ud->ne == ne) {
- drv = get_driver(ud->device.driver);
- if (drv) {
- error = 0;
- pdrv = container_of(drv, struct hpsb_protocol_driver,
- driver);
- if (pdrv->update) {
- device_lock(&ud->device);
- error = pdrv->update(ud);
- device_unlock(&ud->device);
- }
- if (error)
- device_release_driver(&ud->device);
- put_driver(drv);
- }
- }
-
- return 0;
-}
-
-static void nodemgr_update_pdrv(struct node_entry *ne)
-{
- class_for_each_device(&nodemgr_ud_class, NULL, ne, update_pdrv);
-}
-
-/* Write the BROADCAST_CHANNEL as per IEEE1394a 8.3.2.3.11 and 8.4.2.3. This
- * seems like an optional service but in the end it is practically mandatory
- * as a consequence of these clauses.
- *
- * Note that we cannot do a broadcast write to all nodes at once because some
- * pre-1394a devices would hang. */
-static void nodemgr_irm_write_bc(struct node_entry *ne, int generation)
-{
- const u64 bc_addr = (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL);
- quadlet_t bc_remote, bc_local;
- int error;
-
- if (!ne->host->is_irm || ne->generation != generation ||
- ne->nodeid == ne->host->node_id)
- return;
-
- bc_local = cpu_to_be32(ne->host->csr.broadcast_channel);
-
- /* Check if the register is implemented and 1394a compliant. */
- error = hpsb_read(ne->host, ne->nodeid, generation, bc_addr, &bc_remote,
- sizeof(bc_remote));
- if (!error && bc_remote & cpu_to_be32(0x80000000) &&
- bc_remote != bc_local)
- hpsb_node_write(ne, bc_addr, &bc_local, sizeof(bc_local));
-}
-
-
-static void nodemgr_probe_ne(struct hpsb_host *host, struct node_entry *ne,
- int generation)
-{
- struct device *dev;
-
- if (ne->host != host || ne->in_limbo)
- return;
-
- dev = get_device(&ne->device);
- if (!dev)
- return;
-
- nodemgr_irm_write_bc(ne, generation);
-
- /* If "needs_probe", then this is either a new or changed node we
- * rescan totally. If the generation matches for an existing node
- * (one that existed prior to the bus reset) we send update calls
- * down to the drivers. Otherwise, this is a dead node and we
- * suspend it. */
- if (ne->needs_probe)
- nodemgr_process_root_directory(ne);
- else if (ne->generation == generation)
- nodemgr_update_pdrv(ne);
- else
- nodemgr_pause_ne(ne);
-
- put_device(dev);
-}
-
-struct node_probe_parameter {
- struct hpsb_host *host;
- int generation;
- bool probe_now;
-};
-
-static int node_probe(struct device *dev, void *data)
-{
- struct node_probe_parameter *p = data;
- struct node_entry *ne;
-
- if (p->generation != get_hpsb_generation(p->host))
- return -EAGAIN;
-
- ne = container_of(dev, struct node_entry, node_dev);
- if (ne->needs_probe == p->probe_now)
- nodemgr_probe_ne(p->host, ne, p->generation);
- return 0;
-}
-
-static int nodemgr_node_probe(struct hpsb_host *host, int generation)
-{
- struct node_probe_parameter p;
-
- p.host = host;
- p.generation = generation;
- /*
- * Do some processing of the nodes we've probed. This pulls them
- * into the sysfs layer if needed, and can result in processing of
- * unit-directories, or just updating the node and it's
- * unit-directories.
- *
- * Run updates before probes. Usually, updates are time-critical
- * while probes are time-consuming.
- *
- * Meanwhile, another bus reset may have happened. In this case we
- * skip everything here and let the next bus scan handle it.
- * Otherwise we may prematurely remove nodes which are still there.
- */
- p.probe_now = false;
- if (class_for_each_device(&nodemgr_ne_class, NULL, &p, node_probe) != 0)
- return 0;
-
- p.probe_now = true;
- if (class_for_each_device(&nodemgr_ne_class, NULL, &p, node_probe) != 0)
- return 0;
- /*
- * Now let's tell the bus to rescan our devices. This may seem
- * like overhead, but the driver-model core will only scan a
- * device for a driver when either the device is added, or when a
- * new driver is added. A bus reset is a good reason to rescan
- * devices that were there before. For example, an sbp2 device
- * may become available for login, if the host that held it was
- * just removed.
- */
- if (bus_rescan_devices(&ieee1394_bus_type) != 0)
- HPSB_DEBUG("bus_rescan_devices had an error");
-
- return 1;
-}
-
-static int remove_nodes_in_limbo(struct device *dev, void *data)
-{
- struct node_entry *ne;
-
- if (dev->bus != &ieee1394_bus_type)
- return 0;
-
- ne = container_of(dev, struct node_entry, device);
- if (ne->in_limbo)
- nodemgr_remove_ne(ne);
-
- return 0;
-}
-
-static void nodemgr_remove_nodes_in_limbo(struct hpsb_host *host)
-{
- device_for_each_child(&host->device, NULL, remove_nodes_in_limbo);
-}
-
-static int nodemgr_send_resume_packet(struct hpsb_host *host)
-{
- struct hpsb_packet *packet;
- int error = -ENOMEM;
-
- packet = hpsb_make_phypacket(host,
- EXTPHYPACKET_TYPE_RESUME |
- NODEID_TO_NODE(host->node_id) << PHYPACKET_PORT_SHIFT);
- if (packet) {
- packet->no_waiter = 1;
- packet->generation = get_hpsb_generation(host);
- error = hpsb_send_packet(packet);
- }
- if (error)
- HPSB_WARN("fw-host%d: Failed to broadcast resume packet",
- host->id);
- return error;
-}
-
-/* Perform a few high-level IRM responsibilities. */
-static int nodemgr_do_irm_duties(struct hpsb_host *host, int cycles)
-{
- quadlet_t bc;
-
- /* if irm_id == -1 then there is no IRM on this bus */
- if (!host->is_irm || host->irm_id == (nodeid_t)-1)
- return 1;
-
- /* We are a 1394a-2000 compliant IRM. Set the validity bit. */
- host->csr.broadcast_channel |= 0x40000000;
-
- /* If there is no bus manager then we should set the root node's
- * force_root bit to promote bus stability per the 1394
- * spec. (8.4.2.6) */
- if (host->busmgr_id == 0xffff && host->node_count > 1)
- {
- u16 root_node = host->node_count - 1;
-
- /* get cycle master capability flag from root node */
- if (host->is_cycmst ||
- (!hpsb_read(host, LOCAL_BUS | root_node, get_hpsb_generation(host),
- (CSR_REGISTER_BASE + CSR_CONFIG_ROM + 2 * sizeof(quadlet_t)),
- &bc, sizeof(quadlet_t)) &&
- be32_to_cpu(bc) & 1 << CSR_CMC_SHIFT))
- hpsb_send_phy_config(host, root_node, -1);
- else {
- HPSB_DEBUG("The root node is not cycle master capable; "
- "selecting a new root node and resetting...");
-
- if (cycles >= 5) {
- /* Oh screw it! Just leave the bus as it is */
- HPSB_DEBUG("Stopping reset loop for IRM sanity");
- return 1;
- }
-
- hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1);
- hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
-
- return 0;
- }
- }
-
- /* Some devices suspend their ports while being connected to an inactive
- * host adapter, i.e. if connected before the low-level driver is
- * loaded. They become visible either when physically unplugged and
- * replugged, or when receiving a resume packet. Send one once. */
- if (!host->resume_packet_sent && !nodemgr_send_resume_packet(host))
- host->resume_packet_sent = 1;
-
- return 1;
-}
-
-/* We need to ensure that if we are not the IRM, that the IRM node is capable of
- * everything we can do, otherwise issue a bus reset and try to become the IRM
- * ourselves. */
-static int nodemgr_check_irm_capability(struct hpsb_host *host, int cycles)
-{
- quadlet_t bc;
- int status;
-
- if (hpsb_disable_irm || host->is_irm)
- return 1;
-
- status = hpsb_read(host, LOCAL_BUS | (host->irm_id),
- get_hpsb_generation(host),
- (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL),
- &bc, sizeof(quadlet_t));
-
- if (status < 0 || !(be32_to_cpu(bc) & 0x80000000)) {
- /* The current irm node does not have a valid BROADCAST_CHANNEL
- * register and we do, so reset the bus with force_root set */
- HPSB_DEBUG("Current remote IRM is not 1394a-2000 compliant, resetting...");
-
- if (cycles >= 5) {
- /* Oh screw it! Just leave the bus as it is */
- HPSB_DEBUG("Stopping reset loop for IRM sanity");
- return 1;
- }
-
- hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1);
- hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
-
- return 0;
- }
-
- return 1;
-}
-
-static int nodemgr_host_thread(void *data)
-{
- struct hpsb_host *host = data;
- unsigned int g, generation = 0;
- int i, reset_cycles = 0;
-
- set_freezable();
- /* Setup our device-model entries */
- nodemgr_create_host_dev_files(host);
-
- for (;;) {
- /* Sleep until next bus reset */
- set_current_state(TASK_INTERRUPTIBLE);
- if (get_hpsb_generation(host) == generation &&
- !kthread_should_stop())
- schedule();
- __set_current_state(TASK_RUNNING);
-
- /* Thread may have been woken up to freeze or to exit */
- if (try_to_freeze())
- continue;
- if (kthread_should_stop())
- goto exit;
-
- /* Pause for 1/4 second in 1/16 second intervals,
- * to make sure things settle down. */
- g = get_hpsb_generation(host);
- for (i = 0; i < 4 ; i++) {
- msleep_interruptible(63);
- try_to_freeze();
- if (kthread_should_stop())
- goto exit;
-
- /* Now get the generation in which the node ID's we collect
- * are valid. During the bus scan we will use this generation
- * for the read transactions, so that if another reset occurs
- * during the scan the transactions will fail instead of
- * returning bogus data. */
- generation = get_hpsb_generation(host);
-
- /* If we get a reset before we are done waiting, then
- * start the waiting over again */
- if (generation != g)
- g = generation, i = 0;
- }
-
- if (!nodemgr_check_irm_capability(host, reset_cycles) ||
- !nodemgr_do_irm_duties(host, reset_cycles)) {
- reset_cycles++;
- continue;
- }
- reset_cycles = 0;
-
- /* Scan our nodes to get the bus options and create node
- * entries. This does not do the sysfs stuff, since that
- * would trigger uevents and such, which is a bad idea at
- * this point. */
- nodemgr_node_scan(host, generation);
-
- /* This actually does the full probe, with sysfs
- * registration. */
- if (!nodemgr_node_probe(host, generation))
- continue;
-
- /* Update some of our sysfs symlinks */
- nodemgr_update_host_dev_links(host);
-
- /* Sleep 3 seconds */
- for (i = 3000/200; i; i--) {
- msleep_interruptible(200);
- try_to_freeze();
- if (kthread_should_stop())
- goto exit;
-
- if (generation != get_hpsb_generation(host))
- break;
- }
- /* Remove nodes which are gone, unless a bus reset happened */
- if (!i)
- nodemgr_remove_nodes_in_limbo(host);
- }
-exit:
- HPSB_VERBOSE("NodeMgr: Exiting thread");
- return 0;
-}
-
-struct per_host_parameter {
- void *data;
- int (*cb)(struct hpsb_host *, void *);
-};
-
-static int per_host(struct device *dev, void *data)
-{
- struct hpsb_host *host;
- struct per_host_parameter *p = data;
-
- host = container_of(dev, struct hpsb_host, host_dev);
- return p->cb(host, p->data);
-}
-
-/**
- * nodemgr_for_each_host - call a function for each IEEE 1394 host
- * @data: an address to supply to the callback
- * @cb: function to call for each host
- *
- * Iterate the hosts, calling a given function with supplied data for each host.
- * If the callback fails on a host, i.e. if it returns a non-zero value, the
- * iteration is stopped.
- *
- * Return value: 0 on success, non-zero on failure (same as returned by last run
- * of the callback).
- */
-int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *))
-{
- struct per_host_parameter p;
-
- p.cb = cb;
- p.data = data;
- return class_for_each_device(&hpsb_host_class, NULL, &p, per_host);
-}
-
-/* The following two convenience functions use a struct node_entry
- * for addressing a node on the bus. They are intended for use by any
- * process context, not just the nodemgr thread, so we need to be a
- * little careful when reading out the node ID and generation. The
- * thing that can go wrong is that we get the node ID, then a bus
- * reset occurs, and then we read the generation. The node ID is
- * possibly invalid, but the generation is current, and we end up
- * sending a packet to a the wrong node.
- *
- * The solution is to make sure we read the generation first, so that
- * if a reset occurs in the process, we end up with a stale generation
- * and the transactions will fail instead of silently using wrong node
- * ID's.
- */
-
-/**
- * hpsb_node_fill_packet - fill some destination information into a packet
- * @ne: destination node
- * @packet: packet to fill in
- *
- * This will fill in the given, pre-initialised hpsb_packet with the current
- * information from the node entry (host, node ID, bus generation number).
- */
-void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet)
-{
- packet->host = ne->host;
- packet->generation = ne->generation;
- smp_rmb();
- packet->node_id = ne->nodeid;
-}
-
-int hpsb_node_write(struct node_entry *ne, u64 addr,
- quadlet_t *buffer, size_t length)
-{
- unsigned int generation = ne->generation;
-
- smp_rmb();
- return hpsb_write(ne->host, ne->nodeid, generation,
- addr, buffer, length);
-}
-
-static void nodemgr_add_host(struct hpsb_host *host)
-{
- struct host_info *hi;
-
- hi = hpsb_create_hostinfo(&nodemgr_highlevel, host, sizeof(*hi));
- if (!hi) {
- HPSB_ERR("NodeMgr: out of memory in add host");
- return;
- }
- hi->host = host;
- hi->thread = kthread_run(nodemgr_host_thread, host, "knodemgrd_%d",
- host->id);
- if (IS_ERR(hi->thread)) {
- HPSB_ERR("NodeMgr: cannot start thread for host %d", host->id);
- hpsb_destroy_hostinfo(&nodemgr_highlevel, host);
- }
-}
-
-static void nodemgr_host_reset(struct hpsb_host *host)
-{
- struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);
-
- if (hi) {
- HPSB_VERBOSE("NodeMgr: Processing reset for host %d", host->id);
- wake_up_process(hi->thread);
- }
-}
-
-static void nodemgr_remove_host(struct hpsb_host *host)
-{
- struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);
-
- if (hi) {
- kthread_stop(hi->thread);
- nodemgr_remove_host_dev(&host->device);
- }
-}
-
-static struct hpsb_highlevel nodemgr_highlevel = {
- .name = "Node manager",
- .add_host = nodemgr_add_host,
- .host_reset = nodemgr_host_reset,
- .remove_host = nodemgr_remove_host,
-};
-
-int init_ieee1394_nodemgr(void)
-{
- int error;
-
- error = class_register(&nodemgr_ne_class);
- if (error)
- goto fail_ne;
- error = class_register(&nodemgr_ud_class);
- if (error)
- goto fail_ud;
- error = driver_register(&nodemgr_mid_layer_driver);
- if (error)
- goto fail_ml;
- /* This driver is not used if nodemgr is off (disable_nodemgr=1). */
- nodemgr_dev_template_host.driver = &nodemgr_mid_layer_driver;
-
- hpsb_register_highlevel(&nodemgr_highlevel);
- return 0;
-
-fail_ml:
- class_unregister(&nodemgr_ud_class);
-fail_ud:
- class_unregister(&nodemgr_ne_class);
-fail_ne:
- return error;
-}
-
-void cleanup_ieee1394_nodemgr(void)
-{
- hpsb_unregister_highlevel(&nodemgr_highlevel);
- driver_unregister(&nodemgr_mid_layer_driver);
- class_unregister(&nodemgr_ud_class);
- class_unregister(&nodemgr_ne_class);
-}
diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h
deleted file mode 100644
index 749b271d3107..000000000000
--- a/drivers/ieee1394/nodemgr.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2000 Andreas E. Bombe
- * 2001 Ben Collins <bcollins@debian.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.
- */
-
-#ifndef _IEEE1394_NODEMGR_H
-#define _IEEE1394_NODEMGR_H
-
-#include <linux/device.h>
-#include <asm/system.h>
-#include <asm/types.h>
-
-#include "ieee1394_core.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-
-struct csr1212_csr;
-struct csr1212_keyval;
-struct hpsb_host;
-struct ieee1394_device_id;
-
-/* This is the start of a Node entry structure. It should be a stable API
- * for which to gather info from the Node Manager about devices attached
- * to the bus. */
-struct bus_options {
- u8 irmc; /* Iso Resource Manager Capable */
- u8 cmc; /* Cycle Master Capable */
- u8 isc; /* Iso Capable */
- u8 bmc; /* Bus Master Capable */
- u8 pmc; /* Power Manager Capable (PNP spec) */
- u8 cyc_clk_acc; /* Cycle clock accuracy */
- u8 max_rom; /* Maximum block read supported in the CSR */
- u8 generation; /* Incremented when configrom changes */
- u8 lnkspd; /* Link speed */
- u16 max_rec; /* Maximum packet size node can receive */
-};
-
-#define UNIT_DIRECTORY_VENDOR_ID 0x01
-#define UNIT_DIRECTORY_MODEL_ID 0x02
-#define UNIT_DIRECTORY_SPECIFIER_ID 0x04
-#define UNIT_DIRECTORY_VERSION 0x08
-#define UNIT_DIRECTORY_HAS_LUN_DIRECTORY 0x10
-#define UNIT_DIRECTORY_LUN_DIRECTORY 0x20
-#define UNIT_DIRECTORY_HAS_LUN 0x40
-
-/*
- * A unit directory corresponds to a protocol supported by the
- * node. If a node supports eg. IP/1394 and AV/C, its config rom has a
- * unit directory for each of these protocols.
- */
-struct unit_directory {
- struct node_entry *ne; /* The node which this directory belongs to */
- octlet_t address; /* Address of the unit directory on the node */
- u8 flags; /* Indicates which entries were read */
-
- quadlet_t vendor_id;
- struct csr1212_keyval *vendor_name_kv;
-
- quadlet_t model_id;
- struct csr1212_keyval *model_name_kv;
- quadlet_t specifier_id;
- quadlet_t version;
- quadlet_t directory_id;
-
- unsigned int id;
-
- int ignore_driver;
-
- int length; /* Number of quadlets */
-
- struct device device;
- struct device unit_dev;
-
- struct csr1212_keyval *ud_kv;
- u32 lun; /* logical unit number immediate value */
-};
-
-struct node_entry {
- u64 guid; /* GUID of this node */
- u32 guid_vendor_id; /* Top 24bits of guid */
-
- struct hpsb_host *host; /* Host this node is attached to */
- nodeid_t nodeid; /* NodeID */
- struct bus_options busopt; /* Bus Options */
- bool needs_probe;
- unsigned int generation; /* Synced with hpsb generation */
-
- /* The following is read from the config rom */
- u32 vendor_id;
- struct csr1212_keyval *vendor_name_kv;
-
- u32 capabilities;
-
- struct device device;
- struct device node_dev;
-
- /* Means this node is not attached anymore */
- bool in_limbo;
-
- struct csr1212_csr *csr;
-};
-
-struct hpsb_protocol_driver {
- /* The name of the driver, e.g. SBP2 or IP1394 */
- const char *name;
-
- /*
- * The device id table describing the protocols and/or devices
- * supported by this driver. This is used by the nodemgr to
- * decide if a driver could support a given node, but the
- * probe function below can implement further protocol
- * dependent or vendor dependent checking.
- */
- const struct ieee1394_device_id *id_table;
-
- /*
- * The update function is called when the node has just
- * survived a bus reset, i.e. it is still present on the bus.
- * However, it may be necessary to reestablish the connection
- * or login into the node again, depending on the protocol. If the
- * probe fails (returns non-zero), we unbind the driver from this
- * device.
- */
- int (*update)(struct unit_directory *ud);
-
- /* Our LDM structure */
- struct device_driver driver;
-};
-
-int __hpsb_register_protocol(struct hpsb_protocol_driver *, struct module *);
-static inline int hpsb_register_protocol(struct hpsb_protocol_driver *driver)
-{
- return __hpsb_register_protocol(driver, THIS_MODULE);
-}
-
-void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver);
-
-static inline int hpsb_node_entry_valid(struct node_entry *ne)
-{
- return ne->generation == get_hpsb_generation(ne->host);
-}
-void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet);
-int hpsb_node_write(struct node_entry *ne, u64 addr,
- quadlet_t *buffer, size_t length);
-static inline int hpsb_node_read(struct node_entry *ne, u64 addr,
- quadlet_t *buffer, size_t length)
-{
- unsigned int g = ne->generation;
-
- smp_rmb();
- return hpsb_read(ne->host, ne->nodeid, g, addr, buffer, length);
-}
-static inline int hpsb_node_lock(struct node_entry *ne, u64 addr, int extcode,
- quadlet_t *buffer, quadlet_t arg)
-{
- unsigned int g = ne->generation;
-
- smp_rmb();
- return hpsb_lock(ne->host, ne->nodeid, g, addr, extcode, buffer, arg);
-}
-int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *));
-
-int init_ieee1394_nodemgr(void);
-void cleanup_ieee1394_nodemgr(void);
-
-/* The template for a host device */
-extern struct device nodemgr_dev_template_host;
-
-/* Bus attributes we export */
-extern struct bus_attribute *const fw_bus_attrs[];
-
-#endif /* _IEEE1394_NODEMGR_H */
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
deleted file mode 100644
index 50815022cff1..000000000000
--- a/drivers/ieee1394/ohci1394.c
+++ /dev/null
@@ -1,3590 +0,0 @@
-/*
- * ohci1394.c - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- * Gord Peters <GordPeters@smarttech.com>
- * 2001 Ben Collins <bcollins@debian.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.
- */
-
-/*
- * Things known to be working:
- * . Async Request Transmit
- * . Async Response Receive
- * . Async Request Receive
- * . Async Response Transmit
- * . Iso Receive
- * . DMA mmap for iso receive
- * . Config ROM generation
- *
- * Things implemented, but still in test phase:
- * . Iso Transmit
- * . Async Stream Packets Transmit (Receive done via Iso interface)
- *
- * Things not implemented:
- * . DMA error recovery
- *
- * Known bugs:
- * . devctl BUS_RESET arg confusion (reset type or root holdoff?)
- * added LONG_RESET_ROOT and SHORT_RESET_ROOT for root holdoff --kk
- */
-
-/*
- * Acknowledgments:
- *
- * Adam J Richter <adam@yggdrasil.com>
- * . Use of pci_class to find device
- *
- * Emilie Chung <emilie.chung@axis.com>
- * . Tip on Async Request Filter
- *
- * Pascal Drolet <pascal.drolet@informission.ca>
- * . Various tips for optimization and functionnalities
- *
- * Robert Ficklin <rficklin@westengineering.com>
- * . Loop in irq_handler
- *
- * James Goodwin <jamesg@Filanet.com>
- * . Various tips on initialization, self-id reception, etc.
- *
- * Albrecht Dress <ad@mpifr-bonn.mpg.de>
- * . Apple PowerBook detection
- *
- * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de>
- * . Reset the board properly before leaving + misc cleanups
- *
- * Leon van Stuivenberg <leonvs@iae.nl>
- * . Bug fixes
- *
- * Ben Collins <bcollins@debian.org>
- * . Working big-endian support
- * . Updated to 2.4.x module scheme (PCI aswell)
- * . Config ROM generation
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- * . Reworked code for initiating bus resets
- * (long, short, with or without hold-off)
- *
- * Nandu Santhi <contactnandu@users.sourceforge.net>
- * . Added support for nVidia nForce2 onboard Firewire chipset
- *
- */
-
-#include <linux/bitops.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/uaccess.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/irq.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-
-#ifdef CONFIG_PPC_PMAC
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#endif
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "dma.h"
-#include "iso.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "ohci1394.h"
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define OHCI1394_DEBUG
-#endif
-
-#ifdef DBGMSG
-#undef DBGMSG
-#endif
-
-#ifdef OHCI1394_DEBUG
-#define DBGMSG(fmt, args...) \
-printk(KERN_INFO "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args)
-#else
-#define DBGMSG(fmt, args...) do {} while (0)
-#endif
-
-/* print general (card independent) information */
-#define PRINT_G(level, fmt, args...) \
-printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)
-
-/* print card specific information */
-#define PRINT(level, fmt, args...) \
-printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args)
-
-/* Module Parameters */
-static int phys_dma = 1;
-module_param(phys_dma, int, 0444);
-MODULE_PARM_DESC(phys_dma, "Enable physical DMA (default = 1).");
-
-static void dma_trm_tasklet(unsigned long data);
-static void dma_trm_reset(struct dma_trm_ctx *d);
-
-static int alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
- enum context_type type, int ctx, int num_desc,
- int buf_size, int split_buf_size, int context_base);
-static void free_dma_rcv_ctx(struct dma_rcv_ctx *d);
-
-static int alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
- enum context_type type, int ctx, int num_desc,
- int context_base);
-
-static void ohci1394_pci_remove(struct pci_dev *pdev);
-
-#ifndef __LITTLE_ENDIAN
-static const size_t hdr_sizes[] = {
- 3, /* TCODE_WRITEQ */
- 4, /* TCODE_WRITEB */
- 3, /* TCODE_WRITE_RESPONSE */
- 0, /* reserved */
- 3, /* TCODE_READQ */
- 4, /* TCODE_READB */
- 3, /* TCODE_READQ_RESPONSE */
- 4, /* TCODE_READB_RESPONSE */
- 1, /* TCODE_CYCLE_START */
- 4, /* TCODE_LOCK_REQUEST */
- 2, /* TCODE_ISO_DATA */
- 4, /* TCODE_LOCK_RESPONSE */
- /* rest is reserved or link-internal */
-};
-
-static inline void header_le32_to_cpu(quadlet_t *data, unsigned char tcode)
-{
- size_t size;
-
- if (unlikely(tcode >= ARRAY_SIZE(hdr_sizes)))
- return;
-
- size = hdr_sizes[tcode];
- while (size--)
- data[size] = le32_to_cpu(data[size]);
-}
-#else
-#define header_le32_to_cpu(w,x) do {} while (0)
-#endif /* !LITTLE_ENDIAN */
-
-/***********************************
- * IEEE-1394 functionality section *
- ***********************************/
-
-static u8 get_phy_reg(struct ti_ohci *ohci, u8 addr)
-{
- int i;
- unsigned long flags;
- quadlet_t r;
-
- spin_lock_irqsave (&ohci->phy_reg_lock, flags);
-
- reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000);
-
- for (i = 0; i < OHCI_LOOP_COUNT; i++) {
- if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000)
- break;
-
- mdelay(1);
- }
-
- r = reg_read(ohci, OHCI1394_PhyControl);
-
- if (i >= OHCI_LOOP_COUNT)
- PRINT (KERN_ERR, "Get PHY Reg timeout [0x%08x/0x%08x/%d]",
- r, r & 0x80000000, i);
-
- spin_unlock_irqrestore (&ohci->phy_reg_lock, flags);
-
- return (r & 0x00ff0000) >> 16;
-}
-
-static void set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data)
-{
- int i;
- unsigned long flags;
- u32 r = 0;
-
- spin_lock_irqsave (&ohci->phy_reg_lock, flags);
-
- reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000);
-
- for (i = 0; i < OHCI_LOOP_COUNT; i++) {
- r = reg_read(ohci, OHCI1394_PhyControl);
- if (!(r & 0x00004000))
- break;
-
- mdelay(1);
- }
-
- if (i == OHCI_LOOP_COUNT)
- PRINT (KERN_ERR, "Set PHY Reg timeout [0x%08x/0x%08x/%d]",
- r, r & 0x00004000, i);
-
- spin_unlock_irqrestore (&ohci->phy_reg_lock, flags);
-
- return;
-}
-
-/* Or's our value into the current value */
-static void set_phy_reg_mask(struct ti_ohci *ohci, u8 addr, u8 data)
-{
- u8 old;
-
- old = get_phy_reg (ohci, addr);
- old |= data;
- set_phy_reg (ohci, addr, old);
-
- return;
-}
-
-static void handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
- int phyid, int isroot)
-{
- quadlet_t *q = ohci->selfid_buf_cpu;
- quadlet_t self_id_count=reg_read(ohci, OHCI1394_SelfIDCount);
- size_t size;
- quadlet_t q0, q1;
-
- /* Check status of self-id reception */
-
- if (ohci->selfid_swap)
- q0 = le32_to_cpu(q[0]);
- else
- q0 = q[0];
-
- if ((self_id_count & 0x80000000) ||
- ((self_id_count & 0x00FF0000) != (q0 & 0x00FF0000))) {
- PRINT(KERN_ERR,
- "Error in reception of SelfID packets [0x%08x/0x%08x] (count: %d)",
- self_id_count, q0, ohci->self_id_errors);
-
- /* Tip by James Goodwin <jamesg@Filanet.com>:
- * We had an error, generate another bus reset in response. */
- if (ohci->self_id_errors<OHCI1394_MAX_SELF_ID_ERRORS) {
- set_phy_reg_mask (ohci, 1, 0x40);
- ohci->self_id_errors++;
- } else {
- PRINT(KERN_ERR,
- "Too many errors on SelfID error reception, giving up!");
- }
- return;
- }
-
- /* SelfID Ok, reset error counter. */
- ohci->self_id_errors = 0;
-
- size = ((self_id_count & 0x00001FFC) >> 2) - 1;
- q++;
-
- while (size > 0) {
- if (ohci->selfid_swap) {
- q0 = le32_to_cpu(q[0]);
- q1 = le32_to_cpu(q[1]);
- } else {
- q0 = q[0];
- q1 = q[1];
- }
-
- if (q0 == ~q1) {
- DBGMSG ("SelfID packet 0x%x received", q0);
- hpsb_selfid_received(host, cpu_to_be32(q0));
- if (((q0 & 0x3f000000) >> 24) == phyid)
- DBGMSG ("SelfID for this node is 0x%08x", q0);
- } else {
- PRINT(KERN_ERR,
- "SelfID is inconsistent [0x%08x/0x%08x]", q0, q1);
- }
- q += 2;
- size -= 2;
- }
-
- DBGMSG("SelfID complete");
-
- return;
-}
-
-static void ohci_soft_reset(struct ti_ohci *ohci) {
- int i;
-
- reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
-
- for (i = 0; i < OHCI_LOOP_COUNT; i++) {
- if (!(reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_softReset))
- break;
- mdelay(1);
- }
- DBGMSG ("Soft reset finished");
-}
-
-
-/* Generate the dma receive prgs and start the context */
-static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d, int generate_irq)
-{
- struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
- int i;
-
- ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
- for (i=0; i<d->num_desc; i++) {
- u32 c;
-
- c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH;
- if (generate_irq)
- c |= DMA_CTL_IRQ;
-
- d->prg_cpu[i]->control = cpu_to_le32(c | d->buf_size);
-
- /* End of descriptor list? */
- if (i + 1 < d->num_desc) {
- d->prg_cpu[i]->branchAddress =
- cpu_to_le32((d->prg_bus[i+1] & 0xfffffff0) | 0x1);
- } else {
- d->prg_cpu[i]->branchAddress =
- cpu_to_le32((d->prg_bus[0] & 0xfffffff0));
- }
-
- d->prg_cpu[i]->address = cpu_to_le32(d->buf_bus[i]);
- d->prg_cpu[i]->status = cpu_to_le32(d->buf_size);
- }
-
- d->buf_ind = 0;
- d->buf_offset = 0;
-
- if (d->type == DMA_CTX_ISO) {
- /* Clear contextControl */
- reg_write(ohci, d->ctrlClear, 0xffffffff);
-
- /* Set bufferFill, isochHeader, multichannel for IR context */
- reg_write(ohci, d->ctrlSet, 0xd0000000);
-
- /* Set the context match register to match on all tags */
- reg_write(ohci, d->ctxtMatch, 0xf0000000);
-
- /* Clear the multi channel mask high and low registers */
- reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
-
- /* Set up isoRecvIntMask to generate interrupts */
- reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << d->ctx);
- }
-
- /* Tell the controller where the first AR program is */
- reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1);
-
- /* Run context */
- reg_write(ohci, d->ctrlSet, 0x00008000);
-
- DBGMSG("Receive DMA ctx=%d initialized", d->ctx);
-}
-
-/* Initialize the dma transmit context */
-static void initialize_dma_trm_ctx(struct dma_trm_ctx *d)
-{
- struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
-
- /* Stop the context */
- ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
- d->prg_ind = 0;
- d->sent_ind = 0;
- d->free_prgs = d->num_desc;
- d->branchAddrPtr = NULL;
- INIT_LIST_HEAD(&d->fifo_list);
- INIT_LIST_HEAD(&d->pending_list);
-
- if (d->type == DMA_CTX_ISO) {
- /* enable interrupts */
- reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << d->ctx);
- }
-
- DBGMSG("Transmit DMA ctx=%d initialized", d->ctx);
-}
-
-/* Count the number of available iso contexts */
-static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg)
-{
- u32 tmp;
-
- reg_write(ohci, reg, 0xffffffff);
- tmp = reg_read(ohci, reg);
-
- DBGMSG("Iso contexts reg: %08x implemented: %08x", reg, tmp);
-
- /* Count the number of contexts */
- return hweight32(tmp);
-}
-
-/* Global initialization */
-static void ohci_initialize(struct ti_ohci *ohci)
-{
- quadlet_t buf;
- int num_ports, i;
-
- spin_lock_init(&ohci->phy_reg_lock);
-
- /* Put some defaults to these undefined bus options */
- buf = reg_read(ohci, OHCI1394_BusOptions);
- buf |= 0x60000000; /* Enable CMC and ISC */
- if (hpsb_disable_irm)
- buf &= ~0x80000000;
- else
- buf |= 0x80000000; /* Enable IRMC */
- buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
- buf &= ~0x18000000; /* Disable PMC and BMC */
- reg_write(ohci, OHCI1394_BusOptions, buf);
-
- /* Set the bus number */
- reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
-
- /* Enable posted writes */
- reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_postedWriteEnable);
-
- /* Clear link control register */
- reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
-
- /* Enable cycle timer and cycle master and set the IRM
- * contender bit in our self ID packets if appropriate. */
- reg_write(ohci, OHCI1394_LinkControlSet,
- OHCI1394_LinkControl_CycleTimerEnable |
- OHCI1394_LinkControl_CycleMaster);
- i = get_phy_reg(ohci, 4) | PHY_04_LCTRL;
- if (hpsb_disable_irm)
- i &= ~PHY_04_CONTENDER;
- else
- i |= PHY_04_CONTENDER;
- set_phy_reg(ohci, 4, i);
-
- /* Set up self-id dma buffer */
- reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);
-
- /* enable self-id */
- reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID);
-
- /* Set the Config ROM mapping register */
- reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);
-
- /* Now get our max packet size */
- ohci->max_packet_size =
- 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
-
- /* Clear the interrupt mask */
- reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
-
- /* Clear the interrupt mask */
- reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
-
- /* Initialize AR dma */
- initialize_dma_rcv_ctx(&ohci->ar_req_context, 0);
- initialize_dma_rcv_ctx(&ohci->ar_resp_context, 0);
-
- /* Initialize AT dma */
- initialize_dma_trm_ctx(&ohci->at_req_context);
- initialize_dma_trm_ctx(&ohci->at_resp_context);
-
- /* Accept AR requests from all nodes */
- reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
-
- /* Set the address range of the physical response unit.
- * Most controllers do not implement it as a writable register though.
- * They will keep a hardwired offset of 0x00010000 and show 0x0 as
- * register content.
- * To actually enable physical responses is the job of our interrupt
- * handler which programs the physical request filter. */
- reg_write(ohci, OHCI1394_PhyUpperBound,
- OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED >> 16);
-
- DBGMSG("physUpperBoundOffset=%08x",
- reg_read(ohci, OHCI1394_PhyUpperBound));
-
- /* Specify AT retries */
- reg_write(ohci, OHCI1394_ATRetries,
- OHCI1394_MAX_AT_REQ_RETRIES |
- (OHCI1394_MAX_AT_RESP_RETRIES<<4) |
- (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
-
- /* We don't want hardware swapping */
- reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap);
-
- /* Enable interrupts */
- reg_write(ohci, OHCI1394_IntMaskSet,
- OHCI1394_unrecoverableError |
- OHCI1394_masterIntEnable |
- OHCI1394_busReset |
- OHCI1394_selfIDComplete |
- OHCI1394_RSPkt |
- OHCI1394_RQPkt |
- OHCI1394_respTxComplete |
- OHCI1394_reqTxComplete |
- OHCI1394_isochRx |
- OHCI1394_isochTx |
- OHCI1394_postedWriteErr |
- OHCI1394_cycleTooLong |
- OHCI1394_cycleInconsistent);
-
- /* Enable link */
- reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
-
- buf = reg_read(ohci, OHCI1394_Version);
- PRINT(KERN_INFO, "OHCI-1394 %d.%d (PCI): IRQ=[%d] "
- "MMIO=[%llx-%llx] Max Packet=[%d] IR/IT contexts=[%d/%d]",
- ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
- ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq,
- (unsigned long long)pci_resource_start(ohci->dev, 0),
- (unsigned long long)pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1,
- ohci->max_packet_size,
- ohci->nb_iso_rcv_ctx, ohci->nb_iso_xmit_ctx);
-
- /* Check all of our ports to make sure that if anything is
- * connected, we enable that port. */
- num_ports = get_phy_reg(ohci, 2) & 0xf;
- for (i = 0; i < num_ports; i++) {
- unsigned int status;
-
- set_phy_reg(ohci, 7, i);
- status = get_phy_reg(ohci, 8);
-
- if (status & 0x20)
- set_phy_reg(ohci, 8, status & ~1);
- }
-
- /* Serial EEPROM Sanity check. */
- if ((ohci->max_packet_size < 512) ||
- (ohci->max_packet_size > 4096)) {
- /* Serial EEPROM contents are suspect, set a sane max packet
- * size and print the raw contents for bug reports if verbose
- * debug is enabled. */
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
- int i;
-#endif
-
- PRINT(KERN_DEBUG, "Serial EEPROM has suspicious values, "
- "attempting to set max_packet_size to 512 bytes");
- reg_write(ohci, OHCI1394_BusOptions,
- (reg_read(ohci, OHCI1394_BusOptions) & 0xf007) | 0x8002);
- ohci->max_packet_size = 512;
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
- PRINT(KERN_DEBUG, " EEPROM Present: %d",
- (reg_read(ohci, OHCI1394_Version) >> 24) & 0x1);
- reg_write(ohci, OHCI1394_GUID_ROM, 0x80000000);
-
- for (i = 0;
- ((i < 1000) &&
- (reg_read(ohci, OHCI1394_GUID_ROM) & 0x80000000)); i++)
- udelay(10);
-
- for (i = 0; i < 0x20; i++) {
- reg_write(ohci, OHCI1394_GUID_ROM, 0x02000000);
- PRINT(KERN_DEBUG, " EEPROM %02x: %02x", i,
- (reg_read(ohci, OHCI1394_GUID_ROM) >> 16) & 0xff);
- }
-#endif
- }
-}
-
-/*
- * Insert a packet in the DMA fifo and generate the DMA prg
- * FIXME: rewrite the program in order to accept packets crossing
- * page boundaries.
- * check also that a single dma descriptor doesn't cross a
- * page boundary.
- */
-static void insert_packet(struct ti_ohci *ohci,
- struct dma_trm_ctx *d, struct hpsb_packet *packet)
-{
- u32 cycleTimer;
- int idx = d->prg_ind;
-
- DBGMSG("Inserting packet for node " NODE_BUS_FMT
- ", tlabel=%d, tcode=0x%x, speed=%d",
- NODE_BUS_ARGS(ohci->host, packet->node_id), packet->tlabel,
- packet->tcode, packet->speed_code);
-
- d->prg_cpu[idx]->begin.address = 0;
- d->prg_cpu[idx]->begin.branchAddress = 0;
-
- if (d->type == DMA_CTX_ASYNC_RESP) {
- /*
- * For response packets, we need to put a timeout value in
- * the 16 lower bits of the status... let's try 1 sec timeout
- */
- cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
- d->prg_cpu[idx]->begin.status = cpu_to_le32(
- (((((cycleTimer>>25)&0x7)+1)&0x7)<<13) |
- ((cycleTimer&0x01fff000)>>12));
-
- DBGMSG("cycleTimer: %08x timeStamp: %08x",
- cycleTimer, d->prg_cpu[idx]->begin.status);
- } else
- d->prg_cpu[idx]->begin.status = 0;
-
- if ( (packet->type == hpsb_async) || (packet->type == hpsb_raw) ) {
-
- if (packet->type == hpsb_raw) {
- d->prg_cpu[idx]->data[0] = cpu_to_le32(OHCI1394_TCODE_PHY<<4);
- d->prg_cpu[idx]->data[1] = cpu_to_le32(packet->header[0]);
- d->prg_cpu[idx]->data[2] = cpu_to_le32(packet->header[1]);
- } else {
- d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
- (packet->header[0] & 0xFFFF);
-
- if (packet->tcode == TCODE_ISO_DATA) {
- /* Sending an async stream packet */
- d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
- } else {
- /* Sending a normal async request or response */
- d->prg_cpu[idx]->data[1] =
- (packet->header[1] & 0xFFFF) |
- (packet->header[0] & 0xFFFF0000);
- d->prg_cpu[idx]->data[2] = packet->header[2];
- d->prg_cpu[idx]->data[3] = packet->header[3];
- }
- header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode);
- }
-
- if (packet->data_size) { /* block transmit */
- if (packet->tcode == TCODE_STREAM_DATA){
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_MORE |
- DMA_CTL_IMMEDIATE | 0x8);
- } else {
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_MORE |
- DMA_CTL_IMMEDIATE | 0x10);
- }
- d->prg_cpu[idx]->end.control =
- cpu_to_le32(DMA_CTL_OUTPUT_LAST |
- DMA_CTL_IRQ |
- DMA_CTL_BRANCH |
- packet->data_size);
- /*
- * Check that the packet data buffer
- * does not cross a page boundary.
- *
- * XXX Fix this some day. eth1394 seems to trigger
- * it, but ignoring it doesn't seem to cause a
- * problem.
- */
-#if 0
- if (cross_bound((unsigned long)packet->data,
- packet->data_size)>0) {
- /* FIXME: do something about it */
- PRINT(KERN_ERR,
- "%s: packet data addr: %p size %Zd bytes "
- "cross page boundary", __func__,
- packet->data, packet->data_size);
- }
-#endif
- d->prg_cpu[idx]->end.address = cpu_to_le32(
- pci_map_single(ohci->dev, packet->data,
- packet->data_size,
- PCI_DMA_TODEVICE));
-
- d->prg_cpu[idx]->end.branchAddress = 0;
- d->prg_cpu[idx]->end.status = 0;
- if (d->branchAddrPtr)
- *(d->branchAddrPtr) =
- cpu_to_le32(d->prg_bus[idx] | 0x3);
- d->branchAddrPtr =
- &(d->prg_cpu[idx]->end.branchAddress);
- } else { /* quadlet transmit */
- if (packet->type == hpsb_raw)
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_LAST |
- DMA_CTL_IMMEDIATE |
- DMA_CTL_IRQ |
- DMA_CTL_BRANCH |
- (packet->header_size + 4));
- else
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_LAST |
- DMA_CTL_IMMEDIATE |
- DMA_CTL_IRQ |
- DMA_CTL_BRANCH |
- packet->header_size);
-
- if (d->branchAddrPtr)
- *(d->branchAddrPtr) =
- cpu_to_le32(d->prg_bus[idx] | 0x2);
- d->branchAddrPtr =
- &(d->prg_cpu[idx]->begin.branchAddress);
- }
-
- } else { /* iso packet */
- d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
- (packet->header[0] & 0xFFFF);
- d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
- header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode);
-
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_MORE |
- DMA_CTL_IMMEDIATE | 0x8);
- d->prg_cpu[idx]->end.control =
- cpu_to_le32(DMA_CTL_OUTPUT_LAST |
- DMA_CTL_UPDATE |
- DMA_CTL_IRQ |
- DMA_CTL_BRANCH |
- packet->data_size);
- d->prg_cpu[idx]->end.address = cpu_to_le32(
- pci_map_single(ohci->dev, packet->data,
- packet->data_size, PCI_DMA_TODEVICE));
-
- d->prg_cpu[idx]->end.branchAddress = 0;
- d->prg_cpu[idx]->end.status = 0;
- DBGMSG("Iso xmit context info: header[%08x %08x]\n"
- " begin=%08x %08x %08x %08x\n"
- " %08x %08x %08x %08x\n"
- " end =%08x %08x %08x %08x",
- d->prg_cpu[idx]->data[0], d->prg_cpu[idx]->data[1],
- d->prg_cpu[idx]->begin.control,
- d->prg_cpu[idx]->begin.address,
- d->prg_cpu[idx]->begin.branchAddress,
- d->prg_cpu[idx]->begin.status,
- d->prg_cpu[idx]->data[0],
- d->prg_cpu[idx]->data[1],
- d->prg_cpu[idx]->data[2],
- d->prg_cpu[idx]->data[3],
- d->prg_cpu[idx]->end.control,
- d->prg_cpu[idx]->end.address,
- d->prg_cpu[idx]->end.branchAddress,
- d->prg_cpu[idx]->end.status);
- if (d->branchAddrPtr)
- *(d->branchAddrPtr) = cpu_to_le32(d->prg_bus[idx] | 0x3);
- d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress);
- }
- d->free_prgs--;
-
- /* queue the packet in the appropriate context queue */
- list_add_tail(&packet->driver_list, &d->fifo_list);
- d->prg_ind = (d->prg_ind + 1) % d->num_desc;
-}
-
-/*
- * This function fills the FIFO with the (eventual) pending packets
- * and runs or wakes up the DMA prg if necessary.
- *
- * The function MUST be called with the d->lock held.
- */
-static void dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d)
-{
- struct hpsb_packet *packet, *ptmp;
- int idx = d->prg_ind;
- int z = 0;
-
- /* insert the packets into the dma fifo */
- list_for_each_entry_safe(packet, ptmp, &d->pending_list, driver_list) {
- if (!d->free_prgs)
- break;
-
- /* For the first packet only */
- if (!z)
- z = (packet->data_size) ? 3 : 2;
-
- /* Insert the packet */
- list_del_init(&packet->driver_list);
- insert_packet(ohci, d, packet);
- }
-
- /* Nothing must have been done, either no free_prgs or no packets */
- if (z == 0)
- return;
-
- /* Is the context running ? (should be unless it is
- the first packet to be sent in this context) */
- if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) {
- u32 nodeId = reg_read(ohci, OHCI1394_NodeID);
-
- DBGMSG("Starting transmit DMA ctx=%d",d->ctx);
- reg_write(ohci, d->cmdPtr, d->prg_bus[idx] | z);
-
- /* Check that the node id is valid, and not 63 */
- if (!(nodeId & 0x80000000) || (nodeId & 0x3f) == 63)
- PRINT(KERN_ERR, "Running dma failed because Node ID is not valid");
- else
- reg_write(ohci, d->ctrlSet, 0x8000);
- } else {
- /* Wake up the dma context if necessary */
- if (!(reg_read(ohci, d->ctrlSet) & 0x400))
- DBGMSG("Waking transmit DMA ctx=%d",d->ctx);
-
- /* do this always, to avoid race condition */
- reg_write(ohci, d->ctrlSet, 0x1000);
- }
-
- return;
-}
-
-/* Transmission of an async or iso packet */
-static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
-{
- struct ti_ohci *ohci = host->hostdata;
- struct dma_trm_ctx *d;
- unsigned long flags;
-
- if (packet->data_size > ohci->max_packet_size) {
- PRINT(KERN_ERR,
- "Transmit packet size %Zd is too big",
- packet->data_size);
- return -EOVERFLOW;
- }
-
- if (packet->type == hpsb_raw)
- d = &ohci->at_req_context;
- else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA))
- d = &ohci->at_resp_context;
- else
- d = &ohci->at_req_context;
-
- spin_lock_irqsave(&d->lock,flags);
-
- list_add_tail(&packet->driver_list, &d->pending_list);
-
- dma_trm_flush(ohci, d);
-
- spin_unlock_irqrestore(&d->lock,flags);
-
- return 0;
-}
-
-static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
-{
- struct ti_ohci *ohci = host->hostdata;
- int retval = 0, phy_reg;
-
- switch (cmd) {
- case RESET_BUS:
- switch (arg) {
- case SHORT_RESET:
- phy_reg = get_phy_reg(ohci, 5);
- phy_reg |= 0x40;
- set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
- break;
- case LONG_RESET:
- phy_reg = get_phy_reg(ohci, 1);
- phy_reg |= 0x40;
- set_phy_reg(ohci, 1, phy_reg); /* set IBR */
- break;
- case SHORT_RESET_NO_FORCE_ROOT:
- phy_reg = get_phy_reg(ohci, 1);
- if (phy_reg & 0x80) {
- phy_reg &= ~0x80;
- set_phy_reg(ohci, 1, phy_reg); /* clear RHB */
- }
-
- phy_reg = get_phy_reg(ohci, 5);
- phy_reg |= 0x40;
- set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
- break;
- case LONG_RESET_NO_FORCE_ROOT:
- phy_reg = get_phy_reg(ohci, 1);
- phy_reg &= ~0x80;
- phy_reg |= 0x40;
- set_phy_reg(ohci, 1, phy_reg); /* clear RHB, set IBR */
- break;
- case SHORT_RESET_FORCE_ROOT:
- phy_reg = get_phy_reg(ohci, 1);
- if (!(phy_reg & 0x80)) {
- phy_reg |= 0x80;
- set_phy_reg(ohci, 1, phy_reg); /* set RHB */
- }
-
- phy_reg = get_phy_reg(ohci, 5);
- phy_reg |= 0x40;
- set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
- break;
- case LONG_RESET_FORCE_ROOT:
- phy_reg = get_phy_reg(ohci, 1);
- phy_reg |= 0xc0;
- set_phy_reg(ohci, 1, phy_reg); /* set RHB and IBR */
- break;
- default:
- retval = -1;
- }
- break;
-
- case GET_CYCLE_COUNTER:
- retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
- break;
-
- case SET_CYCLE_COUNTER:
- reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg);
- break;
-
- case SET_BUS_ID:
- PRINT(KERN_ERR, "devctl command SET_BUS_ID err");
- break;
-
- case ACT_CYCLE_MASTER:
- if (arg) {
- /* check if we are root and other nodes are present */
- u32 nodeId = reg_read(ohci, OHCI1394_NodeID);
- if ((nodeId & (1<<30)) && (nodeId & 0x3f)) {
- /*
- * enable cycleTimer, cycleMaster
- */
- DBGMSG("Cycle master enabled");
- reg_write(ohci, OHCI1394_LinkControlSet,
- OHCI1394_LinkControl_CycleTimerEnable |
- OHCI1394_LinkControl_CycleMaster);
- }
- } else {
- /* disable cycleTimer, cycleMaster, cycleSource */
- reg_write(ohci, OHCI1394_LinkControlClear,
- OHCI1394_LinkControl_CycleTimerEnable |
- OHCI1394_LinkControl_CycleMaster |
- OHCI1394_LinkControl_CycleSource);
- }
- break;
-
- case CANCEL_REQUESTS:
- DBGMSG("Cancel request received");
- dma_trm_reset(&ohci->at_req_context);
- dma_trm_reset(&ohci->at_resp_context);
- break;
-
- default:
- PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet",
- cmd);
- break;
- }
- return retval;
-}
-
-/***********************************
- * rawiso ISO reception *
- ***********************************/
-
-/*
- We use either buffer-fill or packet-per-buffer DMA mode. The DMA
- buffer is split into "blocks" (regions described by one DMA
- descriptor). Each block must be one page or less in size, and
- must not cross a page boundary.
-
- There is one little wrinkle with buffer-fill mode: a packet that
- starts in the final block may wrap around into the first block. But
- the user API expects all packets to be contiguous. Our solution is
- to keep the very last page of the DMA buffer in reserve - if a
- packet spans the gap, we copy its tail into this page.
-*/
-
-struct ohci_iso_recv {
- struct ti_ohci *ohci;
-
- struct ohci1394_iso_tasklet task;
- int task_active;
-
- enum { BUFFER_FILL_MODE = 0,
- PACKET_PER_BUFFER_MODE = 1 } dma_mode;
-
- /* memory and PCI mapping for the DMA descriptors */
- struct dma_prog_region prog;
- struct dma_cmd *block; /* = (struct dma_cmd*) prog.virt */
-
- /* how many DMA blocks fit in the buffer */
- unsigned int nblocks;
-
- /* stride of DMA blocks */
- unsigned int buf_stride;
-
- /* number of blocks to batch between interrupts */
- int block_irq_interval;
-
- /* block that DMA will finish next */
- int block_dma;
-
- /* (buffer-fill only) block that the reader will release next */
- int block_reader;
-
- /* (buffer-fill only) bytes of buffer the reader has released,
- less than one block */
- int released_bytes;
-
- /* (buffer-fill only) buffer offset at which the next packet will appear */
- int dma_offset;
-
- /* OHCI DMA context control registers */
- u32 ContextControlSet;
- u32 ContextControlClear;
- u32 CommandPtr;
- u32 ContextMatch;
-};
-
-static void ohci_iso_recv_task(unsigned long data);
-static void ohci_iso_recv_stop(struct hpsb_iso *iso);
-static void ohci_iso_recv_shutdown(struct hpsb_iso *iso);
-static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync);
-static void ohci_iso_recv_program(struct hpsb_iso *iso);
-
-static int ohci_iso_recv_init(struct hpsb_iso *iso)
-{
- struct ti_ohci *ohci = iso->host->hostdata;
- struct ohci_iso_recv *recv;
- int ctx;
- int ret = -ENOMEM;
-
- recv = kmalloc(sizeof(*recv), GFP_KERNEL);
- if (!recv)
- return -ENOMEM;
-
- iso->hostdata = recv;
- recv->ohci = ohci;
- recv->task_active = 0;
- dma_prog_region_init(&recv->prog);
- recv->block = NULL;
-
- /* use buffer-fill mode, unless irq_interval is 1
- (note: multichannel requires buffer-fill) */
-
- if (((iso->irq_interval == 1 && iso->dma_mode == HPSB_ISO_DMA_OLD_ABI) ||
- iso->dma_mode == HPSB_ISO_DMA_PACKET_PER_BUFFER) && iso->channel != -1) {
- recv->dma_mode = PACKET_PER_BUFFER_MODE;
- } else {
- recv->dma_mode = BUFFER_FILL_MODE;
- }
-
- /* set nblocks, buf_stride, block_irq_interval */
-
- if (recv->dma_mode == BUFFER_FILL_MODE) {
- recv->buf_stride = PAGE_SIZE;
-
- /* one block per page of data in the DMA buffer, minus the final guard page */
- recv->nblocks = iso->buf_size/PAGE_SIZE - 1;
- if (recv->nblocks < 3) {
- DBGMSG("ohci_iso_recv_init: DMA buffer too small");
- goto err;
- }
-
- /* iso->irq_interval is in packets - translate that to blocks */
- if (iso->irq_interval == 1)
- recv->block_irq_interval = 1;
- else
- recv->block_irq_interval = iso->irq_interval *
- ((recv->nblocks+1)/iso->buf_packets);
- if (recv->block_irq_interval*4 > recv->nblocks)
- recv->block_irq_interval = recv->nblocks/4;
- if (recv->block_irq_interval < 1)
- recv->block_irq_interval = 1;
-
- } else {
- int max_packet_size;
-
- recv->nblocks = iso->buf_packets;
- recv->block_irq_interval = iso->irq_interval;
- if (recv->block_irq_interval * 4 > iso->buf_packets)
- recv->block_irq_interval = iso->buf_packets / 4;
- if (recv->block_irq_interval < 1)
- recv->block_irq_interval = 1;
-
- /* choose a buffer stride */
- /* must be a power of 2, and <= PAGE_SIZE */
-
- max_packet_size = iso->buf_size / iso->buf_packets;
-
- for (recv->buf_stride = 8; recv->buf_stride < max_packet_size;
- recv->buf_stride *= 2);
-
- if (recv->buf_stride*iso->buf_packets > iso->buf_size ||
- recv->buf_stride > PAGE_SIZE) {
- /* this shouldn't happen, but anyway... */
- DBGMSG("ohci_iso_recv_init: problem choosing a buffer stride");
- goto err;
- }
- }
-
- recv->block_reader = 0;
- recv->released_bytes = 0;
- recv->block_dma = 0;
- recv->dma_offset = 0;
-
- /* size of DMA program = one descriptor per block */
- if (dma_prog_region_alloc(&recv->prog,
- sizeof(struct dma_cmd) * recv->nblocks,
- recv->ohci->dev))
- goto err;
-
- recv->block = (struct dma_cmd*) recv->prog.kvirt;
-
- ohci1394_init_iso_tasklet(&recv->task,
- iso->channel == -1 ? OHCI_ISO_MULTICHANNEL_RECEIVE :
- OHCI_ISO_RECEIVE,
- ohci_iso_recv_task, (unsigned long) iso);
-
- if (ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) {
- ret = -EBUSY;
- goto err;
- }
-
- recv->task_active = 1;
-
- /* recv context registers are spaced 32 bytes apart */
- ctx = recv->task.context;
- recv->ContextControlSet = OHCI1394_IsoRcvContextControlSet + 32 * ctx;
- recv->ContextControlClear = OHCI1394_IsoRcvContextControlClear + 32 * ctx;
- recv->CommandPtr = OHCI1394_IsoRcvCommandPtr + 32 * ctx;
- recv->ContextMatch = OHCI1394_IsoRcvContextMatch + 32 * ctx;
-
- if (iso->channel == -1) {
- /* clear multi-channel selection mask */
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, 0xFFFFFFFF);
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, 0xFFFFFFFF);
- }
-
- /* write the DMA program */
- ohci_iso_recv_program(iso);
-
- DBGMSG("ohci_iso_recv_init: %s mode, DMA buffer is %lu pages"
- " (%u bytes), using %u blocks, buf_stride %u, block_irq_interval %d",
- recv->dma_mode == BUFFER_FILL_MODE ?
- "buffer-fill" : "packet-per-buffer",
- iso->buf_size/PAGE_SIZE, iso->buf_size,
- recv->nblocks, recv->buf_stride, recv->block_irq_interval);
-
- return 0;
-
-err:
- ohci_iso_recv_shutdown(iso);
- return ret;
-}
-
-static void ohci_iso_recv_stop(struct hpsb_iso *iso)
-{
- struct ohci_iso_recv *recv = iso->hostdata;
-
- /* disable interrupts */
- reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << recv->task.context);
-
- /* halt DMA */
- ohci1394_stop_context(recv->ohci, recv->ContextControlClear, NULL);
-}
-
-static void ohci_iso_recv_shutdown(struct hpsb_iso *iso)
-{
- struct ohci_iso_recv *recv = iso->hostdata;
-
- if (recv->task_active) {
- ohci_iso_recv_stop(iso);
- ohci1394_unregister_iso_tasklet(recv->ohci, &recv->task);
- recv->task_active = 0;
- }
-
- dma_prog_region_free(&recv->prog);
- kfree(recv);
- iso->hostdata = NULL;
-}
-
-/* set up a "gapped" ring buffer DMA program */
-static void ohci_iso_recv_program(struct hpsb_iso *iso)
-{
- struct ohci_iso_recv *recv = iso->hostdata;
- int blk;
-
- /* address of 'branch' field in previous DMA descriptor */
- u32 *prev_branch = NULL;
-
- for (blk = 0; blk < recv->nblocks; blk++) {
- u32 control;
-
- /* the DMA descriptor */
- struct dma_cmd *cmd = &recv->block[blk];
-
- /* offset of the DMA descriptor relative to the DMA prog buffer */
- unsigned long prog_offset = blk * sizeof(struct dma_cmd);
-
- /* offset of this packet's data within the DMA buffer */
- unsigned long buf_offset = blk * recv->buf_stride;
-
- if (recv->dma_mode == BUFFER_FILL_MODE) {
- control = 2 << 28; /* INPUT_MORE */
- } else {
- control = 3 << 28; /* INPUT_LAST */
- }
-
- control |= 8 << 24; /* s = 1, update xferStatus and resCount */
-
- /* interrupt on last block, and at intervals */
- if (blk == recv->nblocks-1 || (blk % recv->block_irq_interval) == 0) {
- control |= 3 << 20; /* want interrupt */
- }
-
- control |= 3 << 18; /* enable branch to address */
- control |= recv->buf_stride;
-
- cmd->control = cpu_to_le32(control);
- cmd->address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, buf_offset));
- cmd->branchAddress = 0; /* filled in on next loop */
- cmd->status = cpu_to_le32(recv->buf_stride);
-
- /* link the previous descriptor to this one */
- if (prev_branch) {
- *prev_branch = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, prog_offset) | 1);
- }
-
- prev_branch = &cmd->branchAddress;
- }
-
- /* the final descriptor's branch address and Z should be left at 0 */
-}
-
-/* listen or unlisten to a specific channel (multi-channel mode only) */
-static void ohci_iso_recv_change_channel(struct hpsb_iso *iso, unsigned char channel, int listen)
-{
- struct ohci_iso_recv *recv = iso->hostdata;
- int reg, i;
-
- if (channel < 32) {
- reg = listen ? OHCI1394_IRMultiChanMaskLoSet : OHCI1394_IRMultiChanMaskLoClear;
- i = channel;
- } else {
- reg = listen ? OHCI1394_IRMultiChanMaskHiSet : OHCI1394_IRMultiChanMaskHiClear;
- i = channel - 32;
- }
-
- reg_write(recv->ohci, reg, (1 << i));
-
- /* issue a dummy read to force all PCI writes to be posted immediately */
- mb();
- reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
-}
-
-static void ohci_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
-{
- struct ohci_iso_recv *recv = iso->hostdata;
- int i;
-
- for (i = 0; i < 64; i++) {
- if (mask & (1ULL << i)) {
- if (i < 32)
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoSet, (1 << i));
- else
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiSet, (1 << (i-32)));
- } else {
- if (i < 32)
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, (1 << i));
- else
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, (1 << (i-32)));
- }
- }
-
- /* issue a dummy read to force all PCI writes to be posted immediately */
- mb();
- reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
-}
-
-static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
-{
- struct ohci_iso_recv *recv = iso->hostdata;
- struct ti_ohci *ohci = recv->ohci;
- u32 command, contextMatch;
-
- reg_write(recv->ohci, recv->ContextControlClear, 0xFFFFFFFF);
- wmb();
-
- /* always keep ISO headers */
- command = (1 << 30);
-
- if (recv->dma_mode == BUFFER_FILL_MODE)
- command |= (1 << 31);
-
- reg_write(recv->ohci, recv->ContextControlSet, command);
-
- /* match on specified tags */
- contextMatch = tag_mask << 28;
-
- if (iso->channel == -1) {
- /* enable multichannel reception */
- reg_write(recv->ohci, recv->ContextControlSet, (1 << 28));
- } else {
- /* listen on channel */
- contextMatch |= iso->channel;
- }
-
- if (cycle != -1) {
- u32 seconds;
-
- /* enable cycleMatch */
- reg_write(recv->ohci, recv->ContextControlSet, (1 << 29));
-
- /* set starting cycle */
- cycle &= 0x1FFF;
-
- /* 'cycle' is only mod 8000, but we also need two 'seconds' bits -
- just snarf them from the current time */
- seconds = reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer) >> 25;
-
- /* advance one second to give some extra time for DMA to start */
- seconds += 1;
-
- cycle |= (seconds & 3) << 13;
-
- contextMatch |= cycle << 12;
- }
-
- if (sync != -1) {
- /* set sync flag on first DMA descriptor */
- struct dma_cmd *cmd = &recv->block[recv->block_dma];
- cmd->control |= cpu_to_le32(DMA_CTL_WAIT);
-
- /* match sync field */
- contextMatch |= (sync&0xf)<<8;
- }
-
- reg_write(recv->ohci, recv->ContextMatch, contextMatch);
-
- /* address of first descriptor block */
- command = dma_prog_region_offset_to_bus(&recv->prog,
- recv->block_dma * sizeof(struct dma_cmd));
- command |= 1; /* Z=1 */
-
- reg_write(recv->ohci, recv->CommandPtr, command);
-
- /* enable interrupts */
- reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskSet, 1 << recv->task.context);
-
- wmb();
-
- /* run */
- reg_write(recv->ohci, recv->ContextControlSet, 0x8000);
-
- /* issue a dummy read of the cycle timer register to force
- all PCI writes to be posted immediately */
- mb();
- reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
-
- /* check RUN */
- if (!(reg_read(recv->ohci, recv->ContextControlSet) & 0x8000)) {
- PRINT(KERN_ERR,
- "Error starting IR DMA (ContextControl 0x%08x)\n",
- reg_read(recv->ohci, recv->ContextControlSet));
- return -1;
- }
-
- return 0;
-}
-
-static void ohci_iso_recv_release_block(struct ohci_iso_recv *recv, int block)
-{
- /* re-use the DMA descriptor for the block */
- /* by linking the previous descriptor to it */
-
- int next_i = block;
- int prev_i = (next_i == 0) ? (recv->nblocks - 1) : (next_i - 1);
-
- struct dma_cmd *next = &recv->block[next_i];
- struct dma_cmd *prev = &recv->block[prev_i];
-
- /* ignore out-of-range requests */
- if ((block < 0) || (block > recv->nblocks))
- return;
-
- /* 'next' becomes the new end of the DMA chain,
- so disable branch and enable interrupt */
- next->branchAddress = 0;
- next->control |= cpu_to_le32(3 << 20);
- next->status = cpu_to_le32(recv->buf_stride);
-
- /* link prev to next */
- prev->branchAddress = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog,
- sizeof(struct dma_cmd) * next_i)
- | 1); /* Z=1 */
-
- /* disable interrupt on previous DMA descriptor, except at intervals */
- if ((prev_i % recv->block_irq_interval) == 0) {
- prev->control |= cpu_to_le32(3 << 20); /* enable interrupt */
- } else {
- prev->control &= cpu_to_le32(~(3<<20)); /* disable interrupt */
- }
- wmb();
-
- /* wake up DMA in case it fell asleep */
- reg_write(recv->ohci, recv->ContextControlSet, (1 << 12));
-}
-
-static void ohci_iso_recv_bufferfill_release(struct ohci_iso_recv *recv,
- struct hpsb_iso_packet_info *info)
-{
- /* release the memory where the packet was */
- recv->released_bytes += info->total_len;
-
- /* have we released enough memory for one block? */
- while (recv->released_bytes > recv->buf_stride) {
- ohci_iso_recv_release_block(recv, recv->block_reader);
- recv->block_reader = (recv->block_reader + 1) % recv->nblocks;
- recv->released_bytes -= recv->buf_stride;
- }
-}
-
-static inline void ohci_iso_recv_release(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info)
-{
- struct ohci_iso_recv *recv = iso->hostdata;
- if (recv->dma_mode == BUFFER_FILL_MODE) {
- ohci_iso_recv_bufferfill_release(recv, info);
- } else {
- ohci_iso_recv_release_block(recv, info - iso->infos);
- }
-}
-
-/* parse all packets from blocks that have been fully received */
-static void ohci_iso_recv_bufferfill_parse(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
-{
- int wake = 0;
- int runaway = 0;
- struct ti_ohci *ohci = recv->ohci;
-
- while (1) {
- /* we expect the next parsable packet to begin at recv->dma_offset */
- /* note: packet layout is as shown in section 10.6.1.1 of the OHCI spec */
-
- unsigned int offset;
- unsigned short len, cycle, total_len;
- unsigned char channel, tag, sy;
-
- unsigned char *p = iso->data_buf.kvirt;
-
- unsigned int this_block = recv->dma_offset/recv->buf_stride;
-
- /* don't loop indefinitely */
- if (runaway++ > 100000) {
- atomic_inc(&iso->overflows);
- PRINT(KERN_ERR,
- "IR DMA error - Runaway during buffer parsing!\n");
- break;
- }
-
- /* stop parsing once we arrive at block_dma (i.e. don't get ahead of DMA) */
- if (this_block == recv->block_dma)
- break;
-
- wake = 1;
-
- /* parse data length, tag, channel, and sy */
-
- /* note: we keep our own local copies of 'len' and 'offset'
- so the user can't mess with them by poking in the mmap area */
-
- len = p[recv->dma_offset+2] | (p[recv->dma_offset+3] << 8);
-
- if (len > 4096) {
- PRINT(KERN_ERR,
- "IR DMA error - bogus 'len' value %u\n", len);
- }
-
- channel = p[recv->dma_offset+1] & 0x3F;
- tag = p[recv->dma_offset+1] >> 6;
- sy = p[recv->dma_offset+0] & 0xF;
-
- /* advance to data payload */
- recv->dma_offset += 4;
-
- /* check for wrap-around */
- if (recv->dma_offset >= recv->buf_stride*recv->nblocks) {
- recv->dma_offset -= recv->buf_stride*recv->nblocks;
- }
-
- /* dma_offset now points to the first byte of the data payload */
- offset = recv->dma_offset;
-
- /* advance to xferStatus/timeStamp */
- recv->dma_offset += len;
-
- total_len = len + 8; /* 8 bytes header+trailer in OHCI packet */
- /* payload is padded to 4 bytes */
- if (len % 4) {
- recv->dma_offset += 4 - (len%4);
- total_len += 4 - (len%4);
- }
-
- /* check for wrap-around */
- if (recv->dma_offset >= recv->buf_stride*recv->nblocks) {
- /* uh oh, the packet data wraps from the last
- to the first DMA block - make the packet
- contiguous by copying its "tail" into the
- guard page */
-
- int guard_off = recv->buf_stride*recv->nblocks;
- int tail_len = len - (guard_off - offset);
-
- if (tail_len > 0 && tail_len < recv->buf_stride) {
- memcpy(iso->data_buf.kvirt + guard_off,
- iso->data_buf.kvirt,
- tail_len);
- }
-
- recv->dma_offset -= recv->buf_stride*recv->nblocks;
- }
-
- /* parse timestamp */
- cycle = p[recv->dma_offset+0] | (p[recv->dma_offset+1]<<8);
- cycle &= 0x1FFF;
-
- /* advance to next packet */
- recv->dma_offset += 4;
-
- /* check for wrap-around */
- if (recv->dma_offset >= recv->buf_stride*recv->nblocks) {
- recv->dma_offset -= recv->buf_stride*recv->nblocks;
- }
-
- hpsb_iso_packet_received(iso, offset, len, total_len, cycle, channel, tag, sy);
- }
-
- if (wake)
- hpsb_iso_wake(iso);
-}
-
-static void ohci_iso_recv_bufferfill_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
-{
- int loop;
- struct ti_ohci *ohci = recv->ohci;
-
- /* loop over all blocks */
- for (loop = 0; loop < recv->nblocks; loop++) {
-
- /* check block_dma to see if it's done */
- struct dma_cmd *im = &recv->block[recv->block_dma];
-
- /* check the DMA descriptor for new writes to xferStatus */
- u16 xferstatus = le32_to_cpu(im->status) >> 16;
-
- /* rescount is the number of bytes *remaining to be written* in the block */
- u16 rescount = le32_to_cpu(im->status) & 0xFFFF;
-
- unsigned char event = xferstatus & 0x1F;
-
- if (!event) {
- /* nothing has happened to this block yet */
- break;
- }
-
- if (event != 0x11) {
- atomic_inc(&iso->overflows);
- PRINT(KERN_ERR,
- "IR DMA error - OHCI error code 0x%02x\n", event);
- }
-
- if (rescount != 0) {
- /* the card is still writing to this block;
- we can't touch it until it's done */
- break;
- }
-
- /* OK, the block is finished... */
-
- /* sync our view of the block */
- dma_region_sync_for_cpu(&iso->data_buf, recv->block_dma*recv->buf_stride, recv->buf_stride);
-
- /* reset the DMA descriptor */
- im->status = recv->buf_stride;
-
- /* advance block_dma */
- recv->block_dma = (recv->block_dma + 1) % recv->nblocks;
-
- if ((recv->block_dma+1) % recv->nblocks == recv->block_reader) {
- atomic_inc(&iso->overflows);
- DBGMSG("ISO reception overflow - "
- "ran out of DMA blocks");
- }
- }
-
- /* parse any packets that have arrived */
- ohci_iso_recv_bufferfill_parse(iso, recv);
-}
-
-static void ohci_iso_recv_packetperbuf_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
-{
- int count;
- int wake = 0;
- struct ti_ohci *ohci = recv->ohci;
-
- /* loop over the entire buffer */
- for (count = 0; count < recv->nblocks; count++) {
- u32 packet_len = 0;
-
- /* pointer to the DMA descriptor */
- struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + iso->pkt_dma;
-
- /* check the DMA descriptor for new writes to xferStatus */
- u16 xferstatus = le32_to_cpu(il->status) >> 16;
- u16 rescount = le32_to_cpu(il->status) & 0xFFFF;
-
- unsigned char event = xferstatus & 0x1F;
-
- if (!event) {
- /* this packet hasn't come in yet; we are done for now */
- goto out;
- }
-
- if (event == 0x11) {
- /* packet received successfully! */
-
- /* rescount is the number of bytes *remaining* in the packet buffer,
- after the packet was written */
- packet_len = recv->buf_stride - rescount;
-
- } else if (event == 0x02) {
- PRINT(KERN_ERR, "IR DMA error - packet too long for buffer\n");
- } else if (event) {
- PRINT(KERN_ERR, "IR DMA error - OHCI error code 0x%02x\n", event);
- }
-
- /* sync our view of the buffer */
- dma_region_sync_for_cpu(&iso->data_buf, iso->pkt_dma * recv->buf_stride, recv->buf_stride);
-
- /* record the per-packet info */
- {
- /* iso header is 8 bytes ahead of the data payload */
- unsigned char *hdr;
-
- unsigned int offset;
- unsigned short cycle;
- unsigned char channel, tag, sy;
-
- offset = iso->pkt_dma * recv->buf_stride;
- hdr = iso->data_buf.kvirt + offset;
-
- /* skip iso header */
- offset += 8;
- packet_len -= 8;
-
- cycle = (hdr[0] | (hdr[1] << 8)) & 0x1FFF;
- channel = hdr[5] & 0x3F;
- tag = hdr[5] >> 6;
- sy = hdr[4] & 0xF;
-
- hpsb_iso_packet_received(iso, offset, packet_len,
- recv->buf_stride, cycle, channel, tag, sy);
- }
-
- /* reset the DMA descriptor */
- il->status = recv->buf_stride;
-
- wake = 1;
- recv->block_dma = iso->pkt_dma;
- }
-
-out:
- if (wake)
- hpsb_iso_wake(iso);
-}
-
-static void ohci_iso_recv_task(unsigned long data)
-{
- struct hpsb_iso *iso = (struct hpsb_iso*) data;
- struct ohci_iso_recv *recv = iso->hostdata;
-
- if (recv->dma_mode == BUFFER_FILL_MODE)
- ohci_iso_recv_bufferfill_task(iso, recv);
- else
- ohci_iso_recv_packetperbuf_task(iso, recv);
-}
-
-/***********************************
- * rawiso ISO transmission *
- ***********************************/
-
-struct ohci_iso_xmit {
- struct ti_ohci *ohci;
- struct dma_prog_region prog;
- struct ohci1394_iso_tasklet task;
- int task_active;
- int last_cycle;
- atomic_t skips;
-
- u32 ContextControlSet;
- u32 ContextControlClear;
- u32 CommandPtr;
-};
-
-/* transmission DMA program:
- one OUTPUT_MORE_IMMEDIATE for the IT header
- one OUTPUT_LAST for the buffer data */
-
-struct iso_xmit_cmd {
- struct dma_cmd output_more_immediate;
- u8 iso_hdr[8];
- u32 unused[2];
- struct dma_cmd output_last;
-};
-
-static int ohci_iso_xmit_init(struct hpsb_iso *iso);
-static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle);
-static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso);
-static void ohci_iso_xmit_task(unsigned long data);
-
-static int ohci_iso_xmit_init(struct hpsb_iso *iso)
-{
- struct ohci_iso_xmit *xmit;
- unsigned int prog_size;
- int ctx;
- int ret = -ENOMEM;
-
- xmit = kmalloc(sizeof(*xmit), GFP_KERNEL);
- if (!xmit)
- return -ENOMEM;
-
- iso->hostdata = xmit;
- xmit->ohci = iso->host->hostdata;
- xmit->task_active = 0;
- xmit->last_cycle = -1;
- atomic_set(&iso->skips, 0);
-
- dma_prog_region_init(&xmit->prog);
-
- prog_size = sizeof(struct iso_xmit_cmd) * iso->buf_packets;
-
- if (dma_prog_region_alloc(&xmit->prog, prog_size, xmit->ohci->dev))
- goto err;
-
- ohci1394_init_iso_tasklet(&xmit->task, OHCI_ISO_TRANSMIT,
- ohci_iso_xmit_task, (unsigned long) iso);
-
- if (ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0) {
- ret = -EBUSY;
- goto err;
- }
-
- xmit->task_active = 1;
-
- /* xmit context registers are spaced 16 bytes apart */
- ctx = xmit->task.context;
- xmit->ContextControlSet = OHCI1394_IsoXmitContextControlSet + 16 * ctx;
- xmit->ContextControlClear = OHCI1394_IsoXmitContextControlClear + 16 * ctx;
- xmit->CommandPtr = OHCI1394_IsoXmitCommandPtr + 16 * ctx;
-
- return 0;
-
-err:
- ohci_iso_xmit_shutdown(iso);
- return ret;
-}
-
-static void ohci_iso_xmit_stop(struct hpsb_iso *iso)
-{
- struct ohci_iso_xmit *xmit = iso->hostdata;
- struct ti_ohci *ohci = xmit->ohci;
-
- /* disable interrupts */
- reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << xmit->task.context);
-
- /* halt DMA */
- if (ohci1394_stop_context(xmit->ohci, xmit->ContextControlClear, NULL)) {
- /* XXX the DMA context will lock up if you try to send too much data! */
- PRINT(KERN_ERR,
- "you probably exceeded the OHCI card's bandwidth limit - "
- "reload the module and reduce xmit bandwidth");
- }
-}
-
-static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso)
-{
- struct ohci_iso_xmit *xmit = iso->hostdata;
-
- if (xmit->task_active) {
- ohci_iso_xmit_stop(iso);
- ohci1394_unregister_iso_tasklet(xmit->ohci, &xmit->task);
- xmit->task_active = 0;
- }
-
- dma_prog_region_free(&xmit->prog);
- kfree(xmit);
- iso->hostdata = NULL;
-}
-
-static void ohci_iso_xmit_task(unsigned long data)
-{
- struct hpsb_iso *iso = (struct hpsb_iso*) data;
- struct ohci_iso_xmit *xmit = iso->hostdata;
- struct ti_ohci *ohci = xmit->ohci;
- int wake = 0;
- int count;
-
- /* check the whole buffer if necessary, starting at pkt_dma */
- for (count = 0; count < iso->buf_packets; count++) {
- int cycle;
-
- /* DMA descriptor */
- struct iso_xmit_cmd *cmd = dma_region_i(&xmit->prog, struct iso_xmit_cmd, iso->pkt_dma);
-
- /* check for new writes to xferStatus */
- u16 xferstatus = le32_to_cpu(cmd->output_last.status) >> 16;
- u8 event = xferstatus & 0x1F;
-
- if (!event) {
- /* packet hasn't been sent yet; we are done for now */
- break;
- }
-
- if (event != 0x11)
- PRINT(KERN_ERR,
- "IT DMA error - OHCI error code 0x%02x\n", event);
-
- /* at least one packet went out, so wake up the writer */
- wake = 1;
-
- /* parse cycle */
- cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF;
-
- if (xmit->last_cycle > -1) {
- int cycle_diff = cycle - xmit->last_cycle;
- int skip;
-
- /* unwrap */
- if (cycle_diff < 0) {
- cycle_diff += 8000;
- if (cycle_diff < 0)
- PRINT(KERN_ERR, "bogus cycle diff %d\n",
- cycle_diff);
- }
-
- skip = cycle_diff - 1;
- if (skip > 0) {
- DBGMSG("skipped %d cycles without packet loss", skip);
- atomic_add(skip, &iso->skips);
- }
- }
- xmit->last_cycle = cycle;
-
- /* tell the subsystem the packet has gone out */
- hpsb_iso_packet_sent(iso, cycle, event != 0x11);
-
- /* reset the DMA descriptor for next time */
- cmd->output_last.status = 0;
- }
-
- if (wake)
- hpsb_iso_wake(iso);
-}
-
-static int ohci_iso_xmit_queue(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info)
-{
- struct ohci_iso_xmit *xmit = iso->hostdata;
- struct ti_ohci *ohci = xmit->ohci;
-
- int next_i, prev_i;
- struct iso_xmit_cmd *next, *prev;
-
- unsigned int offset;
- unsigned short len;
- unsigned char tag, sy;
-
- /* check that the packet doesn't cross a page boundary
- (we could allow this if we added OUTPUT_MORE descriptor support) */
- if (cross_bound(info->offset, info->len)) {
- PRINT(KERN_ERR,
- "rawiso xmit: packet %u crosses a page boundary",
- iso->first_packet);
- return -EINVAL;
- }
-
- offset = info->offset;
- len = info->len;
- tag = info->tag;
- sy = info->sy;
-
- /* sync up the card's view of the buffer */
- dma_region_sync_for_device(&iso->data_buf, offset, len);
-
- /* append first_packet to the DMA chain */
- /* by linking the previous descriptor to it */
- /* (next will become the new end of the DMA chain) */
-
- next_i = iso->first_packet;
- prev_i = (next_i == 0) ? (iso->buf_packets - 1) : (next_i - 1);
-
- next = dma_region_i(&xmit->prog, struct iso_xmit_cmd, next_i);
- prev = dma_region_i(&xmit->prog, struct iso_xmit_cmd, prev_i);
-
- /* set up the OUTPUT_MORE_IMMEDIATE descriptor */
- memset(next, 0, sizeof(struct iso_xmit_cmd));
- next->output_more_immediate.control = cpu_to_le32(0x02000008);
-
- /* ISO packet header is embedded in the OUTPUT_MORE_IMMEDIATE */
-
- /* tcode = 0xA, and sy */
- next->iso_hdr[0] = 0xA0 | (sy & 0xF);
-
- /* tag and channel number */
- next->iso_hdr[1] = (tag << 6) | (iso->channel & 0x3F);
-
- /* transmission speed */
- next->iso_hdr[2] = iso->speed & 0x7;
-
- /* payload size */
- next->iso_hdr[6] = len & 0xFF;
- next->iso_hdr[7] = len >> 8;
-
- /* set up the OUTPUT_LAST */
- next->output_last.control = cpu_to_le32(1 << 28);
- next->output_last.control |= cpu_to_le32(1 << 27); /* update timeStamp */
- next->output_last.control |= cpu_to_le32(3 << 20); /* want interrupt */
- next->output_last.control |= cpu_to_le32(3 << 18); /* enable branch */
- next->output_last.control |= cpu_to_le32(len);
-
- /* payload bus address */
- next->output_last.address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, offset));
-
- /* leave branchAddress at zero for now */
-
- /* re-write the previous DMA descriptor to chain to this one */
-
- /* set prev branch address to point to next (Z=3) */
- prev->output_last.branchAddress = cpu_to_le32(
- dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3);
-
- /*
- * Link the skip address to this descriptor itself. This causes a
- * context to skip a cycle whenever lost cycles or FIFO overruns occur,
- * without dropping the data at that point the application should then
- * decide whether this is an error condition or not. Some protocols
- * can deal with this by dropping some rate-matching padding packets.
- */
- next->output_more_immediate.branchAddress =
- prev->output_last.branchAddress;
-
- /* disable interrupt, unless required by the IRQ interval */
- if (prev_i % iso->irq_interval) {
- prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */
- } else {
- prev->output_last.control |= cpu_to_le32(3 << 20); /* enable interrupt */
- }
-
- wmb();
-
- /* wake DMA in case it is sleeping */
- reg_write(xmit->ohci, xmit->ContextControlSet, 1 << 12);
-
- /* issue a dummy read of the cycle timer to force all PCI
- writes to be posted immediately */
- mb();
- reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer);
-
- return 0;
-}
-
-static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle)
-{
- struct ohci_iso_xmit *xmit = iso->hostdata;
- struct ti_ohci *ohci = xmit->ohci;
-
- /* clear out the control register */
- reg_write(xmit->ohci, xmit->ContextControlClear, 0xFFFFFFFF);
- wmb();
-
- /* address and length of first descriptor block (Z=3) */
- reg_write(xmit->ohci, xmit->CommandPtr,
- dma_prog_region_offset_to_bus(&xmit->prog, iso->pkt_dma * sizeof(struct iso_xmit_cmd)) | 3);
-
- /* cycle match */
- if (cycle != -1) {
- u32 start = cycle & 0x1FFF;
-
- /* 'cycle' is only mod 8000, but we also need two 'seconds' bits -
- just snarf them from the current time */
- u32 seconds = reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer) >> 25;
-
- /* advance one second to give some extra time for DMA to start */
- seconds += 1;
-
- start |= (seconds & 3) << 13;
-
- reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (start << 16));
- }
-
- /* enable interrupts */
- reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskSet, 1 << xmit->task.context);
-
- /* run */
- reg_write(xmit->ohci, xmit->ContextControlSet, 0x8000);
- mb();
-
- /* wait 100 usec to give the card time to go active */
- udelay(100);
-
- /* check the RUN bit */
- if (!(reg_read(xmit->ohci, xmit->ContextControlSet) & 0x8000)) {
- PRINT(KERN_ERR, "Error starting IT DMA (ContextControl 0x%08x)\n",
- reg_read(xmit->ohci, xmit->ContextControlSet));
- return -1;
- }
-
- return 0;
-}
-
-static int ohci_isoctl(struct hpsb_iso *iso, enum isoctl_cmd cmd, unsigned long arg)
-{
-
- switch(cmd) {
- case XMIT_INIT:
- return ohci_iso_xmit_init(iso);
- case XMIT_START:
- return ohci_iso_xmit_start(iso, arg);
- case XMIT_STOP:
- ohci_iso_xmit_stop(iso);
- return 0;
- case XMIT_QUEUE:
- return ohci_iso_xmit_queue(iso, (struct hpsb_iso_packet_info*) arg);
- case XMIT_SHUTDOWN:
- ohci_iso_xmit_shutdown(iso);
- return 0;
-
- case RECV_INIT:
- return ohci_iso_recv_init(iso);
- case RECV_START: {
- int *args = (int*) arg;
- return ohci_iso_recv_start(iso, args[0], args[1], args[2]);
- }
- case RECV_STOP:
- ohci_iso_recv_stop(iso);
- return 0;
- case RECV_RELEASE:
- ohci_iso_recv_release(iso, (struct hpsb_iso_packet_info*) arg);
- return 0;
- case RECV_FLUSH:
- ohci_iso_recv_task((unsigned long) iso);
- return 0;
- case RECV_SHUTDOWN:
- ohci_iso_recv_shutdown(iso);
- return 0;
- case RECV_LISTEN_CHANNEL:
- ohci_iso_recv_change_channel(iso, arg, 1);
- return 0;
- case RECV_UNLISTEN_CHANNEL:
- ohci_iso_recv_change_channel(iso, arg, 0);
- return 0;
- case RECV_SET_CHANNEL_MASK:
- ohci_iso_recv_set_channel_mask(iso, *((u64*) arg));
- return 0;
-
- default:
- PRINT_G(KERN_ERR, "ohci_isoctl cmd %d not implemented yet",
- cmd);
- break;
- }
- return -EINVAL;
-}
-
-/***************************************
- * IEEE-1394 functionality section END *
- ***************************************/
-
-
-/********************************************************
- * Global stuff (interrupt handler, init/shutdown code) *
- ********************************************************/
-
-static void dma_trm_reset(struct dma_trm_ctx *d)
-{
- unsigned long flags;
- LIST_HEAD(packet_list);
- struct ti_ohci *ohci = d->ohci;
- struct hpsb_packet *packet, *ptmp;
-
- ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
- /* Lock the context, reset it and release it. Move the packets
- * that were pending in the context to packet_list and free
- * them after releasing the lock. */
-
- spin_lock_irqsave(&d->lock, flags);
-
- list_splice_init(&d->fifo_list, &packet_list);
- list_splice_init(&d->pending_list, &packet_list);
-
- d->branchAddrPtr = NULL;
- d->sent_ind = d->prg_ind;
- d->free_prgs = d->num_desc;
-
- spin_unlock_irqrestore(&d->lock, flags);
-
- if (list_empty(&packet_list))
- return;
-
- PRINT(KERN_INFO, "AT dma reset ctx=%d, aborting transmission", d->ctx);
-
- /* Now process subsystem callbacks for the packets from this
- * context. */
- list_for_each_entry_safe(packet, ptmp, &packet_list, driver_list) {
- list_del_init(&packet->driver_list);
- hpsb_packet_sent(ohci->host, packet, ACKX_ABORTED);
- }
-}
-
-static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci,
- quadlet_t rx_event,
- quadlet_t tx_event)
-{
- struct ohci1394_iso_tasklet *t;
- unsigned long mask;
- unsigned long flags;
-
- spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
-
- list_for_each_entry(t, &ohci->iso_tasklet_list, link) {
- mask = 1 << t->context;
-
- if (t->type == OHCI_ISO_TRANSMIT) {
- if (tx_event & mask)
- tasklet_schedule(&t->tasklet);
- } else {
- /* OHCI_ISO_RECEIVE or OHCI_ISO_MULTICHANNEL_RECEIVE */
- if (rx_event & mask)
- tasklet_schedule(&t->tasklet);
- }
- }
-
- spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
-}
-
-static irqreturn_t ohci_irq_handler(int irq, void *dev_id)
-{
- quadlet_t event, node_id;
- struct ti_ohci *ohci = (struct ti_ohci *)dev_id;
- struct hpsb_host *host = ohci->host;
- int phyid = -1, isroot = 0;
- unsigned long flags;
-
- /* Read and clear the interrupt event register. Don't clear
- * the busReset event, though. This is done when we get the
- * selfIDComplete interrupt. */
- spin_lock_irqsave(&ohci->event_lock, flags);
- event = reg_read(ohci, OHCI1394_IntEventClear);
- reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset);
- spin_unlock_irqrestore(&ohci->event_lock, flags);
-
- if (!event)
- return IRQ_NONE;
-
- /* If event is ~(u32)0 cardbus card was ejected. In this case
- * we just return, and clean up in the ohci1394_pci_remove
- * function. */
- if (event == ~(u32) 0) {
- DBGMSG("Device removed.");
- return IRQ_NONE;
- }
-
- DBGMSG("IntEvent: %08x", event);
-
- if (event & OHCI1394_unrecoverableError) {
- int ctx;
- PRINT(KERN_ERR, "Unrecoverable error!");
-
- if (reg_read(ohci, OHCI1394_AsReqTrContextControlSet) & 0x800)
- PRINT(KERN_ERR, "Async Req Tx Context died: "
- "ctrl[%08x] cmdptr[%08x]",
- reg_read(ohci, OHCI1394_AsReqTrContextControlSet),
- reg_read(ohci, OHCI1394_AsReqTrCommandPtr));
-
- if (reg_read(ohci, OHCI1394_AsRspTrContextControlSet) & 0x800)
- PRINT(KERN_ERR, "Async Rsp Tx Context died: "
- "ctrl[%08x] cmdptr[%08x]",
- reg_read(ohci, OHCI1394_AsRspTrContextControlSet),
- reg_read(ohci, OHCI1394_AsRspTrCommandPtr));
-
- if (reg_read(ohci, OHCI1394_AsReqRcvContextControlSet) & 0x800)
- PRINT(KERN_ERR, "Async Req Rcv Context died: "
- "ctrl[%08x] cmdptr[%08x]",
- reg_read(ohci, OHCI1394_AsReqRcvContextControlSet),
- reg_read(ohci, OHCI1394_AsReqRcvCommandPtr));
-
- if (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x800)
- PRINT(KERN_ERR, "Async Rsp Rcv Context died: "
- "ctrl[%08x] cmdptr[%08x]",
- reg_read(ohci, OHCI1394_AsRspRcvContextControlSet),
- reg_read(ohci, OHCI1394_AsRspRcvCommandPtr));
-
- for (ctx = 0; ctx < ohci->nb_iso_xmit_ctx; ctx++) {
- if (reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)) & 0x800)
- PRINT(KERN_ERR, "Iso Xmit %d Context died: "
- "ctrl[%08x] cmdptr[%08x]", ctx,
- reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)),
- reg_read(ohci, OHCI1394_IsoXmitCommandPtr + (16 * ctx)));
- }
-
- for (ctx = 0; ctx < ohci->nb_iso_rcv_ctx; ctx++) {
- if (reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)) & 0x800)
- PRINT(KERN_ERR, "Iso Recv %d Context died: "
- "ctrl[%08x] cmdptr[%08x] match[%08x]", ctx,
- reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)),
- reg_read(ohci, OHCI1394_IsoRcvCommandPtr + (32 * ctx)),
- reg_read(ohci, OHCI1394_IsoRcvContextMatch + (32 * ctx)));
- }
-
- event &= ~OHCI1394_unrecoverableError;
- }
- if (event & OHCI1394_postedWriteErr) {
- PRINT(KERN_ERR, "physical posted write error");
- /* no recovery strategy yet, had to involve protocol drivers */
- event &= ~OHCI1394_postedWriteErr;
- }
- if (event & OHCI1394_cycleTooLong) {
- if(printk_ratelimit())
- PRINT(KERN_WARNING, "isochronous cycle too long");
- else
- DBGMSG("OHCI1394_cycleTooLong");
- reg_write(ohci, OHCI1394_LinkControlSet,
- OHCI1394_LinkControl_CycleMaster);
- event &= ~OHCI1394_cycleTooLong;
- }
- if (event & OHCI1394_cycleInconsistent) {
- /* We subscribe to the cycleInconsistent event only to
- * clear the corresponding event bit... otherwise,
- * isochronous cycleMatch DMA won't work. */
- DBGMSG("OHCI1394_cycleInconsistent");
- event &= ~OHCI1394_cycleInconsistent;
- }
- if (event & OHCI1394_busReset) {
- /* The busReset event bit can't be cleared during the
- * selfID phase, so we disable busReset interrupts, to
- * avoid burying the cpu in interrupt requests. */
- spin_lock_irqsave(&ohci->event_lock, flags);
- reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset);
-
- if (ohci->check_busreset) {
- int loop_count = 0;
-
- udelay(10);
-
- while (reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
- reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
-
- spin_unlock_irqrestore(&ohci->event_lock, flags);
- udelay(10);
- spin_lock_irqsave(&ohci->event_lock, flags);
-
- /* The loop counter check is to prevent the driver
- * from remaining in this state forever. For the
- * initial bus reset, the loop continues for ever
- * and the system hangs, until some device is plugged-in
- * or out manually into a port! The forced reset seems
- * to solve this problem. This mainly effects nForce2. */
- if (loop_count > 10000) {
- ohci_devctl(host, RESET_BUS, LONG_RESET);
- DBGMSG("Detected bus-reset loop. Forced a bus reset!");
- loop_count = 0;
- }
-
- loop_count++;
- }
- }
- spin_unlock_irqrestore(&ohci->event_lock, flags);
- if (!host->in_bus_reset) {
- DBGMSG("irq_handler: Bus reset requested");
-
- /* Subsystem call */
- hpsb_bus_reset(ohci->host);
- }
- event &= ~OHCI1394_busReset;
- }
- if (event & OHCI1394_reqTxComplete) {
- struct dma_trm_ctx *d = &ohci->at_req_context;
- DBGMSG("Got reqTxComplete interrupt "
- "status=0x%08X", reg_read(ohci, d->ctrlSet));
- if (reg_read(ohci, d->ctrlSet) & 0x800)
- ohci1394_stop_context(ohci, d->ctrlClear,
- "reqTxComplete");
- else
- dma_trm_tasklet((unsigned long)d);
- //tasklet_schedule(&d->task);
- event &= ~OHCI1394_reqTxComplete;
- }
- if (event & OHCI1394_respTxComplete) {
- struct dma_trm_ctx *d = &ohci->at_resp_context;
- DBGMSG("Got respTxComplete interrupt "
- "status=0x%08X", reg_read(ohci, d->ctrlSet));
- if (reg_read(ohci, d->ctrlSet) & 0x800)
- ohci1394_stop_context(ohci, d->ctrlClear,
- "respTxComplete");
- else
- tasklet_schedule(&d->task);
- event &= ~OHCI1394_respTxComplete;
- }
- if (event & OHCI1394_RQPkt) {
- struct dma_rcv_ctx *d = &ohci->ar_req_context;
- DBGMSG("Got RQPkt interrupt status=0x%08X",
- reg_read(ohci, d->ctrlSet));
- if (reg_read(ohci, d->ctrlSet) & 0x800)
- ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt");
- else
- tasklet_schedule(&d->task);
- event &= ~OHCI1394_RQPkt;
- }
- if (event & OHCI1394_RSPkt) {
- struct dma_rcv_ctx *d = &ohci->ar_resp_context;
- DBGMSG("Got RSPkt interrupt status=0x%08X",
- reg_read(ohci, d->ctrlSet));
- if (reg_read(ohci, d->ctrlSet) & 0x800)
- ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt");
- else
- tasklet_schedule(&d->task);
- event &= ~OHCI1394_RSPkt;
- }
- if (event & OHCI1394_isochRx) {
- quadlet_t rx_event;
-
- rx_event = reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
- reg_write(ohci, OHCI1394_IsoRecvIntEventClear, rx_event);
- ohci_schedule_iso_tasklets(ohci, rx_event, 0);
- event &= ~OHCI1394_isochRx;
- }
- if (event & OHCI1394_isochTx) {
- quadlet_t tx_event;
-
- tx_event = reg_read(ohci, OHCI1394_IsoXmitIntEventSet);
- reg_write(ohci, OHCI1394_IsoXmitIntEventClear, tx_event);
- ohci_schedule_iso_tasklets(ohci, 0, tx_event);
- event &= ~OHCI1394_isochTx;
- }
- if (event & OHCI1394_selfIDComplete) {
- if (host->in_bus_reset) {
- node_id = reg_read(ohci, OHCI1394_NodeID);
-
- if (!(node_id & 0x80000000)) {
- PRINT(KERN_ERR,
- "SelfID received, but NodeID invalid "
- "(probably new bus reset occurred): %08X",
- node_id);
- goto selfid_not_valid;
- }
-
- phyid = node_id & 0x0000003f;
- isroot = (node_id & 0x40000000) != 0;
-
- DBGMSG("SelfID interrupt received "
- "(phyid %d, %s)", phyid,
- (isroot ? "root" : "not root"));
-
- handle_selfid(ohci, host, phyid, isroot);
-
- /* Clear the bus reset event and re-enable the
- * busReset interrupt. */
- spin_lock_irqsave(&ohci->event_lock, flags);
- reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
- reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
- spin_unlock_irqrestore(&ohci->event_lock, flags);
-
- /* Turn on phys dma reception.
- *
- * TODO: Enable some sort of filtering management.
- */
- if (phys_dma) {
- reg_write(ohci, OHCI1394_PhyReqFilterHiSet,
- 0xffffffff);
- reg_write(ohci, OHCI1394_PhyReqFilterLoSet,
- 0xffffffff);
- }
-
- DBGMSG("PhyReqFilter=%08x%08x",
- reg_read(ohci, OHCI1394_PhyReqFilterHiSet),
- reg_read(ohci, OHCI1394_PhyReqFilterLoSet));
-
- hpsb_selfid_complete(host, phyid, isroot);
- } else
- PRINT(KERN_ERR,
- "SelfID received outside of bus reset sequence");
-
-selfid_not_valid:
- event &= ~OHCI1394_selfIDComplete;
- }
-
- /* Make sure we handle everything, just in case we accidentally
- * enabled an interrupt that we didn't write a handler for. */
- if (event)
- PRINT(KERN_ERR, "Unhandled interrupt(s) 0x%08x",
- event);
-
- return IRQ_HANDLED;
-}
-
-/* Put the buffer back into the dma context */
-static void insert_dma_buffer(struct dma_rcv_ctx *d, int idx)
-{
- struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
- DBGMSG("Inserting dma buf ctx=%d idx=%d", d->ctx, idx);
-
- d->prg_cpu[idx]->status = cpu_to_le32(d->buf_size);
- d->prg_cpu[idx]->branchAddress &= le32_to_cpu(0xfffffff0);
- idx = (idx + d->num_desc - 1 ) % d->num_desc;
- d->prg_cpu[idx]->branchAddress |= le32_to_cpu(0x00000001);
-
- /* To avoid a race, ensure 1394 interface hardware sees the inserted
- * context program descriptors before it sees the wakeup bit set. */
- wmb();
-
- /* wake up the dma context if necessary */
- if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
- PRINT(KERN_INFO,
- "Waking dma ctx=%d ... processing is probably too slow",
- d->ctx);
- }
-
- /* do this always, to avoid race condition */
- reg_write(ohci, d->ctrlSet, 0x1000);
-}
-
-#define cond_le32_to_cpu(data, noswap) \
- (noswap ? data : le32_to_cpu(data))
-
-static const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0,
- -1, 0, -1, 0, -1, -1, 16, -1};
-
-/*
- * Determine the length of a packet in the buffer
- * Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca>
- */
-static inline int packet_length(struct dma_rcv_ctx *d, int idx,
- quadlet_t *buf_ptr, int offset,
- unsigned char tcode, int noswap)
-{
- int length = -1;
-
- if (d->type == DMA_CTX_ASYNC_REQ || d->type == DMA_CTX_ASYNC_RESP) {
- length = TCODE_SIZE[tcode];
- if (length == 0) {
- if (offset + 12 >= d->buf_size) {
- length = (cond_le32_to_cpu(d->buf_cpu[(idx + 1) % d->num_desc]
- [3 - ((d->buf_size - offset) >> 2)], noswap) >> 16);
- } else {
- length = (cond_le32_to_cpu(buf_ptr[3], noswap) >> 16);
- }
- length += 20;
- }
- } else if (d->type == DMA_CTX_ISO) {
- /* Assumption: buffer fill mode with header/trailer */
- length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8;
- }
-
- if (length > 0 && length % 4)
- length += 4 - (length % 4);
-
- return length;
-}
-
-/* Tasklet that processes dma receive buffers */
-static void dma_rcv_tasklet (unsigned long data)
-{
- struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data;
- struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
- unsigned int split_left, idx, offset, rescount;
- unsigned char tcode;
- int length, bytes_left, ack;
- unsigned long flags;
- quadlet_t *buf_ptr;
- char *split_ptr;
- char msg[256];
-
- spin_lock_irqsave(&d->lock, flags);
-
- idx = d->buf_ind;
- offset = d->buf_offset;
- buf_ptr = d->buf_cpu[idx] + offset/4;
-
- rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
- bytes_left = d->buf_size - rescount - offset;
-
- while (bytes_left > 0) {
- tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf;
-
- /* packet_length() will return < 4 for an error */
- length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->no_swap_incoming);
-
- if (length < 4) { /* something is wrong */
- sprintf(msg,"Unexpected tcode 0x%x(0x%08x) in AR ctx=%d, length=%d",
- tcode, cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming),
- d->ctx, length);
- ohci1394_stop_context(ohci, d->ctrlClear, msg);
- spin_unlock_irqrestore(&d->lock, flags);
- return;
- }
-
- /* The first case is where we have a packet that crosses
- * over more than one descriptor. The next case is where
- * it's all in the first descriptor. */
- if ((offset + length) > d->buf_size) {
- DBGMSG("Split packet rcv'd");
- if (length > d->split_buf_size) {
- ohci1394_stop_context(ohci, d->ctrlClear,
- "Split packet size exceeded");
- d->buf_ind = idx;
- d->buf_offset = offset;
- spin_unlock_irqrestore(&d->lock, flags);
- return;
- }
-
- if (le32_to_cpu(d->prg_cpu[(idx+1)%d->num_desc]->status)
- == d->buf_size) {
- /* Other part of packet not written yet.
- * this should never happen I think
- * anyway we'll get it on the next call. */
- PRINT(KERN_INFO,
- "Got only half a packet!");
- d->buf_ind = idx;
- d->buf_offset = offset;
- spin_unlock_irqrestore(&d->lock, flags);
- return;
- }
-
- split_left = length;
- split_ptr = (char *)d->spb;
- memcpy(split_ptr,buf_ptr,d->buf_size-offset);
- split_left -= d->buf_size-offset;
- split_ptr += d->buf_size-offset;
- insert_dma_buffer(d, idx);
- idx = (idx+1) % d->num_desc;
- buf_ptr = d->buf_cpu[idx];
- offset=0;
-
- while (split_left >= d->buf_size) {
- memcpy(split_ptr,buf_ptr,d->buf_size);
- split_ptr += d->buf_size;
- split_left -= d->buf_size;
- insert_dma_buffer(d, idx);
- idx = (idx+1) % d->num_desc;
- buf_ptr = d->buf_cpu[idx];
- }
-
- if (split_left > 0) {
- memcpy(split_ptr, buf_ptr, split_left);
- offset = split_left;
- buf_ptr += offset/4;
- }
- } else {
- DBGMSG("Single packet rcv'd");
- memcpy(d->spb, buf_ptr, length);
- offset += length;
- buf_ptr += length/4;
- if (offset==d->buf_size) {
- insert_dma_buffer(d, idx);
- idx = (idx+1) % d->num_desc;
- buf_ptr = d->buf_cpu[idx];
- offset=0;
- }
- }
-
- /* We get one phy packet to the async descriptor for each
- * bus reset. We always ignore it. */
- if (tcode != OHCI1394_TCODE_PHY) {
- if (!ohci->no_swap_incoming)
- header_le32_to_cpu(d->spb, tcode);
- DBGMSG("Packet received from node"
- " %d ack=0x%02X spd=%d tcode=0x%X"
- " length=%d ctx=%d tlabel=%d",
- (d->spb[1]>>16)&0x3f,
- (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f,
- (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3,
- tcode, length, d->ctx,
- (d->spb[0]>>10)&0x3f);
-
- ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f)
- == 0x11) ? 1 : 0;
-
- hpsb_packet_received(ohci->host, d->spb,
- length-4, ack);
- }
-#ifdef OHCI1394_DEBUG
- else
- PRINT (KERN_DEBUG, "Got phy packet ctx=%d ... discarded",
- d->ctx);
-#endif
-
- rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
-
- bytes_left = d->buf_size - rescount - offset;
-
- }
-
- d->buf_ind = idx;
- d->buf_offset = offset;
-
- spin_unlock_irqrestore(&d->lock, flags);
-}
-
-/* Bottom half that processes sent packets */
-static void dma_trm_tasklet (unsigned long data)
-{
- struct dma_trm_ctx *d = (struct dma_trm_ctx*)data;
- struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
- struct hpsb_packet *packet, *ptmp;
- unsigned long flags;
- u32 status, ack;
- size_t datasize;
-
- spin_lock_irqsave(&d->lock, flags);
-
- list_for_each_entry_safe(packet, ptmp, &d->fifo_list, driver_list) {
- datasize = packet->data_size;
- if (datasize && packet->type != hpsb_raw)
- status = le32_to_cpu(
- d->prg_cpu[d->sent_ind]->end.status) >> 16;
- else
- status = le32_to_cpu(
- d->prg_cpu[d->sent_ind]->begin.status) >> 16;
-
- if (status == 0)
- /* this packet hasn't been sent yet*/
- break;
-
-#ifdef OHCI1394_DEBUG
- if (datasize)
- if (((le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf) == 0xa)
- DBGMSG("Stream packet sent to channel %d tcode=0x%X "
- "ack=0x%X spd=%d dataLength=%d ctx=%d",
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>8)&0x3f,
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf,
- status&0x1f, (status>>5)&0x3,
- le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16,
- d->ctx);
- else
- DBGMSG("Packet sent to node %d tcode=0x%X tLabel="
- "%d ack=0x%X spd=%d dataLength=%d ctx=%d",
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16)&0x3f,
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf,
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>10)&0x3f,
- status&0x1f, (status>>5)&0x3,
- le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3])>>16,
- d->ctx);
- else
- DBGMSG("Packet sent to node %d tcode=0x%X tLabel="
- "%d ack=0x%X spd=%d data=0x%08X ctx=%d",
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])
- >>16)&0x3f,
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
- >>4)&0xf,
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
- >>10)&0x3f,
- status&0x1f, (status>>5)&0x3,
- le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]),
- d->ctx);
-#endif
-
- if (status & 0x10) {
- ack = status & 0xf;
- } else {
- switch (status & 0x1f) {
- case EVT_NO_STATUS: /* that should never happen */
- case EVT_RESERVED_A: /* that should never happen */
- case EVT_LONG_PACKET: /* that should never happen */
- PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_MISSING_ACK:
- ack = ACKX_TIMEOUT;
- break;
- case EVT_UNDERRUN:
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_OVERRUN: /* that should never happen */
- PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_DESCRIPTOR_READ:
- case EVT_DATA_READ:
- case EVT_DATA_WRITE:
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_BUS_RESET: /* that should never happen */
- PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_TIMEOUT:
- ack = ACKX_TIMEOUT;
- break;
- case EVT_TCODE_ERR:
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_RESERVED_B: /* that should never happen */
- case EVT_RESERVED_C: /* that should never happen */
- PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_UNKNOWN:
- case EVT_FLUSHED:
- ack = ACKX_SEND_ERROR;
- break;
- default:
- PRINT(KERN_ERR, "Unhandled OHCI evt_* error 0x%x", status & 0x1f);
- ack = ACKX_SEND_ERROR;
- BUG();
- }
- }
-
- list_del_init(&packet->driver_list);
- hpsb_packet_sent(ohci->host, packet, ack);
-
- if (datasize)
- pci_unmap_single(ohci->dev,
- cpu_to_le32(d->prg_cpu[d->sent_ind]->end.address),
- datasize, PCI_DMA_TODEVICE);
-
- d->sent_ind = (d->sent_ind+1)%d->num_desc;
- d->free_prgs++;
- }
-
- dma_trm_flush(ohci, d);
-
- spin_unlock_irqrestore(&d->lock, flags);
-}
-
-static void free_dma_rcv_ctx(struct dma_rcv_ctx *d)
-{
- int i;
- struct ti_ohci *ohci = d->ohci;
-
- if (ohci == NULL)
- return;
-
- DBGMSG("Freeing dma_rcv_ctx %d", d->ctx);
-
- if (d->buf_cpu) {
- for (i=0; i<d->num_desc; i++)
- if (d->buf_cpu[i] && d->buf_bus[i])
- pci_free_consistent(
- ohci->dev, d->buf_size,
- d->buf_cpu[i], d->buf_bus[i]);
- kfree(d->buf_cpu);
- kfree(d->buf_bus);
- }
- if (d->prg_cpu) {
- for (i=0; i<d->num_desc; i++)
- if (d->prg_cpu[i] && d->prg_bus[i])
- pci_pool_free(d->prg_pool, d->prg_cpu[i],
- d->prg_bus[i]);
- pci_pool_destroy(d->prg_pool);
- kfree(d->prg_cpu);
- kfree(d->prg_bus);
- }
- kfree(d->spb);
-
- /* Mark this context as freed. */
- d->ohci = NULL;
-}
-
-static int
-alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
- enum context_type type, int ctx, int num_desc,
- int buf_size, int split_buf_size, int context_base)
-{
- int i, len;
- static int num_allocs;
- static char pool_name[20];
-
- d->ohci = ohci;
- d->type = type;
- d->ctx = ctx;
-
- d->num_desc = num_desc;
- d->buf_size = buf_size;
- d->split_buf_size = split_buf_size;
-
- d->ctrlSet = 0;
- d->ctrlClear = 0;
- d->cmdPtr = 0;
-
- d->buf_cpu = kzalloc(d->num_desc * sizeof(*d->buf_cpu), GFP_ATOMIC);
- d->buf_bus = kzalloc(d->num_desc * sizeof(*d->buf_bus), GFP_ATOMIC);
-
- if (d->buf_cpu == NULL || d->buf_bus == NULL) {
- PRINT(KERN_ERR, "Failed to allocate %s", "DMA buffer");
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
-
- d->prg_cpu = kzalloc(d->num_desc * sizeof(*d->prg_cpu), GFP_ATOMIC);
- d->prg_bus = kzalloc(d->num_desc * sizeof(*d->prg_bus), GFP_ATOMIC);
-
- if (d->prg_cpu == NULL || d->prg_bus == NULL) {
- PRINT(KERN_ERR, "Failed to allocate %s", "DMA prg");
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
-
- d->spb = kmalloc(d->split_buf_size, GFP_ATOMIC);
-
- if (d->spb == NULL) {
- PRINT(KERN_ERR, "Failed to allocate %s", "split buffer");
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
-
- len = sprintf(pool_name, "ohci1394_rcv_prg");
- sprintf(pool_name+len, "%d", num_allocs);
- d->prg_pool = pci_pool_create(pool_name, ohci->dev,
- sizeof(struct dma_cmd), 4, 0);
- if(d->prg_pool == NULL)
- {
- PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name);
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
- num_allocs++;
-
- for (i=0; i<d->num_desc; i++) {
- d->buf_cpu[i] = pci_alloc_consistent(ohci->dev,
- d->buf_size,
- d->buf_bus+i);
-
- if (d->buf_cpu[i] != NULL) {
- memset(d->buf_cpu[i], 0, d->buf_size);
- } else {
- PRINT(KERN_ERR,
- "Failed to allocate %s", "DMA buffer");
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
-
- d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i);
-
- if (d->prg_cpu[i] != NULL) {
- memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd));
- } else {
- PRINT(KERN_ERR,
- "Failed to allocate %s", "DMA prg");
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
- }
-
- spin_lock_init(&d->lock);
-
- d->ctrlSet = context_base + OHCI1394_ContextControlSet;
- d->ctrlClear = context_base + OHCI1394_ContextControlClear;
- d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
-
- tasklet_init(&d->task, dma_rcv_tasklet, (unsigned long) d);
- return 0;
-}
-
-static void free_dma_trm_ctx(struct dma_trm_ctx *d)
-{
- int i;
- struct ti_ohci *ohci = d->ohci;
-
- if (ohci == NULL)
- return;
-
- DBGMSG("Freeing dma_trm_ctx %d", d->ctx);
-
- if (d->prg_cpu) {
- for (i=0; i<d->num_desc; i++)
- if (d->prg_cpu[i] && d->prg_bus[i])
- pci_pool_free(d->prg_pool, d->prg_cpu[i],
- d->prg_bus[i]);
- pci_pool_destroy(d->prg_pool);
- kfree(d->prg_cpu);
- kfree(d->prg_bus);
- }
-
- /* Mark this context as freed. */
- d->ohci = NULL;
-}
-
-static int
-alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
- enum context_type type, int ctx, int num_desc,
- int context_base)
-{
- int i, len;
- static char pool_name[20];
- static int num_allocs=0;
-
- d->ohci = ohci;
- d->type = type;
- d->ctx = ctx;
- d->num_desc = num_desc;
- d->ctrlSet = 0;
- d->ctrlClear = 0;
- d->cmdPtr = 0;
-
- d->prg_cpu = kzalloc(d->num_desc * sizeof(*d->prg_cpu), GFP_KERNEL);
- d->prg_bus = kzalloc(d->num_desc * sizeof(*d->prg_bus), GFP_KERNEL);
-
- if (d->prg_cpu == NULL || d->prg_bus == NULL) {
- PRINT(KERN_ERR, "Failed to allocate %s", "AT DMA prg");
- free_dma_trm_ctx(d);
- return -ENOMEM;
- }
-
- len = sprintf(pool_name, "ohci1394_trm_prg");
- sprintf(pool_name+len, "%d", num_allocs);
- d->prg_pool = pci_pool_create(pool_name, ohci->dev,
- sizeof(struct at_dma_prg), 4, 0);
- if (d->prg_pool == NULL) {
- PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name);
- free_dma_trm_ctx(d);
- return -ENOMEM;
- }
- num_allocs++;
-
- for (i = 0; i < d->num_desc; i++) {
- d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i);
-
- if (d->prg_cpu[i] != NULL) {
- memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg));
- } else {
- PRINT(KERN_ERR,
- "Failed to allocate %s", "AT DMA prg");
- free_dma_trm_ctx(d);
- return -ENOMEM;
- }
- }
-
- spin_lock_init(&d->lock);
-
- /* initialize tasklet */
- d->ctrlSet = context_base + OHCI1394_ContextControlSet;
- d->ctrlClear = context_base + OHCI1394_ContextControlClear;
- d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
- tasklet_init(&d->task, dma_trm_tasklet, (unsigned long)d);
- return 0;
-}
-
-static void ohci_set_hw_config_rom(struct hpsb_host *host, __be32 *config_rom)
-{
- struct ti_ohci *ohci = host->hostdata;
-
- reg_write(ohci, OHCI1394_ConfigROMhdr, be32_to_cpu(config_rom[0]));
- reg_write(ohci, OHCI1394_BusOptions, be32_to_cpu(config_rom[2]));
-
- memcpy(ohci->csr_config_rom_cpu, config_rom, OHCI_CONFIG_ROM_LEN);
-}
-
-
-static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,
- quadlet_t data, quadlet_t compare)
-{
- struct ti_ohci *ohci = host->hostdata;
- int i;
-
- reg_write(ohci, OHCI1394_CSRData, data);
- reg_write(ohci, OHCI1394_CSRCompareData, compare);
- reg_write(ohci, OHCI1394_CSRControl, reg & 0x3);
-
- for (i = 0; i < OHCI_LOOP_COUNT; i++) {
- if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
- break;
-
- mdelay(1);
- }
-
- return reg_read(ohci, OHCI1394_CSRData);
-}
-
-static struct hpsb_host_driver ohci1394_driver = {
- .owner = THIS_MODULE,
- .name = OHCI1394_DRIVER_NAME,
- .set_hw_config_rom = ohci_set_hw_config_rom,
- .transmit_packet = ohci_transmit,
- .devctl = ohci_devctl,
- .isoctl = ohci_isoctl,
- .hw_csr_reg = ohci_hw_csr_reg,
-};
-
-/***********************************
- * PCI Driver Interface functions *
- ***********************************/
-
-#ifdef CONFIG_PPC_PMAC
-static void ohci1394_pmac_on(struct pci_dev *dev)
-{
- if (machine_is(powermac)) {
- struct device_node *ofn = pci_device_to_OF_node(dev);
-
- if (ofn) {
- pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 1);
- pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1);
- }
- }
-}
-
-static void ohci1394_pmac_off(struct pci_dev *dev)
-{
- if (machine_is(powermac)) {
- struct device_node *ofn = pci_device_to_OF_node(dev);
-
- if (ofn) {
- pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0);
- pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0);
- }
- }
-}
-#else
-#define ohci1394_pmac_on(dev)
-#define ohci1394_pmac_off(dev)
-#endif /* CONFIG_PPC_PMAC */
-
-static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- struct hpsb_host *host;
- struct ti_ohci *ohci; /* shortcut to currently handled device */
- resource_size_t ohci_base;
- int err = -ENOMEM;
-
- ohci1394_pmac_on(dev);
- if (pci_enable_device(dev)) {
- PRINT_G(KERN_ERR, "Failed to enable OHCI hardware");
- err = -ENXIO;
- goto err;
- }
- pci_set_master(dev);
-
- host = hpsb_alloc_host(&ohci1394_driver, sizeof(struct ti_ohci), &dev->dev);
- if (!host) {
- PRINT_G(KERN_ERR, "Failed to allocate %s", "host structure");
- goto err;
- }
- ohci = host->hostdata;
- ohci->dev = dev;
- ohci->host = host;
- ohci->init_state = OHCI_INIT_ALLOC_HOST;
- host->pdev = dev;
- pci_set_drvdata(dev, ohci);
-
- /* We don't want hardware swapping */
- pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
-
- /* Some oddball Apple controllers do not order the selfid
- * properly, so we make up for it here. */
-#ifndef __LITTLE_ENDIAN
- /* XXX: Need a better way to check this. I'm wondering if we can
- * read the values of the OHCI1394_PCI_HCI_Control and the
- * noByteSwapData registers to see if they were not cleared to
- * zero. Should this work? Obviously it's not defined what these
- * registers will read when they aren't supported. Bleh! */
- if (dev->vendor == PCI_VENDOR_ID_APPLE &&
- dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) {
- ohci->no_swap_incoming = 1;
- ohci->selfid_swap = 0;
- } else
- ohci->selfid_swap = 1;
-#endif
-
-
-#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2_FW
-#define PCI_DEVICE_ID_NVIDIA_NFORCE2_FW 0x006e
-#endif
-
- /* These chipsets require a bit of extra care when checking after
- * a busreset. */
- if ((dev->vendor == PCI_VENDOR_ID_APPLE &&
- dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) ||
- (dev->vendor == PCI_VENDOR_ID_NVIDIA &&
- dev->device == PCI_DEVICE_ID_NVIDIA_NFORCE2_FW))
- ohci->check_busreset = 1;
-
- /* We hardwire the MMIO length, since some CardBus adaptors
- * fail to report the right length. Anyway, the ohci spec
- * clearly says it's 2kb, so this shouldn't be a problem. */
- ohci_base = pci_resource_start(dev, 0);
- if (pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE)
- PRINT(KERN_WARNING, "PCI resource length of 0x%llx too small!",
- (unsigned long long)pci_resource_len(dev, 0));
-
- if (!request_mem_region(ohci_base, OHCI1394_REGISTER_SIZE,
- OHCI1394_DRIVER_NAME)) {
- PRINT_G(KERN_ERR, "MMIO resource (0x%llx - 0x%llx) unavailable",
- (unsigned long long)ohci_base,
- (unsigned long long)ohci_base + OHCI1394_REGISTER_SIZE);
- goto err;
- }
- ohci->init_state = OHCI_INIT_HAVE_MEM_REGION;
-
- ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE);
- if (ohci->registers == NULL) {
- PRINT_G(KERN_ERR, "Failed to remap registers");
- err = -ENXIO;
- goto err;
- }
- ohci->init_state = OHCI_INIT_HAVE_IOMAPPING;
- DBGMSG("Remapped memory spaces reg 0x%p", ohci->registers);
-
- /* csr_config rom allocation */
- ohci->csr_config_rom_cpu =
- pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,
- &ohci->csr_config_rom_bus);
- if (ohci->csr_config_rom_cpu == NULL) {
- PRINT_G(KERN_ERR, "Failed to allocate %s", "buffer config rom");
- goto err;
- }
- ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER;
-
- /* self-id dma buffer allocation */
- ohci->selfid_buf_cpu =
- pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE,
- &ohci->selfid_buf_bus);
- if (ohci->selfid_buf_cpu == NULL) {
- PRINT_G(KERN_ERR, "Failed to allocate %s", "self-ID buffer");
- goto err;
- }
- ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER;
-
- if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff)
- PRINT(KERN_INFO, "SelfID buffer %p is not aligned on "
- "8Kb boundary... may cause problems on some CXD3222 chip",
- ohci->selfid_buf_cpu);
-
- /* No self-id errors at startup */
- ohci->self_id_errors = 0;
-
- ohci->init_state = OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE;
- /* AR DMA request context allocation */
- if (alloc_dma_rcv_ctx(ohci, &ohci->ar_req_context,
- DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC,
- AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE,
- OHCI1394_AsReqRcvContextBase) < 0) {
- PRINT_G(KERN_ERR, "Failed to allocate %s", "AR Req context");
- goto err;
- }
- /* AR DMA response context allocation */
- if (alloc_dma_rcv_ctx(ohci, &ohci->ar_resp_context,
- DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC,
- AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE,
- OHCI1394_AsRspRcvContextBase) < 0) {
- PRINT_G(KERN_ERR, "Failed to allocate %s", "AR Resp context");
- goto err;
- }
- /* AT DMA request context */
- if (alloc_dma_trm_ctx(ohci, &ohci->at_req_context,
- DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC,
- OHCI1394_AsReqTrContextBase) < 0) {
- PRINT_G(KERN_ERR, "Failed to allocate %s", "AT Req context");
- goto err;
- }
- /* AT DMA response context */
- if (alloc_dma_trm_ctx(ohci, &ohci->at_resp_context,
- DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC,
- OHCI1394_AsRspTrContextBase) < 0) {
- PRINT_G(KERN_ERR, "Failed to allocate %s", "AT Resp context");
- goto err;
- }
- /* Start off with a soft reset, to clear everything to a sane
- * state. */
- ohci_soft_reset(ohci);
-
- /* Now enable LPS, which we need in order to start accessing
- * most of the registers. In fact, on some cards (ALI M5251),
- * accessing registers in the SClk domain without LPS enabled
- * will lock up the machine. */
- reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
-
- /* Disable and clear interrupts */
- reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
-
- /* Flush MMIO writes and wait to make sure we have full link enabled. */
- reg_read(ohci, OHCI1394_Version);
- msleep(50);
-
- /* Determine the number of available IR and IT contexts. */
- ohci->nb_iso_rcv_ctx =
- get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
- ohci->nb_iso_xmit_ctx =
- get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
-
- /* Set the usage bits for non-existent contexts so they can't
- * be allocated */
- ohci->ir_ctx_usage = ~0 << ohci->nb_iso_rcv_ctx;
- ohci->it_ctx_usage = ~0 << ohci->nb_iso_xmit_ctx;
-
- INIT_LIST_HEAD(&ohci->iso_tasklet_list);
- spin_lock_init(&ohci->iso_tasklet_list_lock);
- ohci->ISO_channel_usage = 0;
- spin_lock_init(&ohci->IR_channel_lock);
-
- spin_lock_init(&ohci->event_lock);
-
- /*
- * interrupts are disabled, all right, but... due to IRQF_SHARED we
- * might get called anyway. We'll see no event, of course, but
- * we need to get to that "no event", so enough should be initialized
- * by that point.
- */
- err = request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED,
- OHCI1394_DRIVER_NAME, ohci);
- if (err) {
- PRINT_G(KERN_ERR, "Failed to allocate interrupt %d", dev->irq);
- goto err;
- }
- ohci->init_state = OHCI_INIT_HAVE_IRQ;
- ohci_initialize(ohci);
-
- /* Set certain csr values */
- host->csr.guid_hi = reg_read(ohci, OHCI1394_GUIDHi);
- host->csr.guid_lo = reg_read(ohci, OHCI1394_GUIDLo);
- host->csr.cyc_clk_acc = 100; /* how do we determine clk accuracy? */
- host->csr.max_rec = (reg_read(ohci, OHCI1394_BusOptions) >> 12) & 0xf;
- host->csr.lnk_spd = reg_read(ohci, OHCI1394_BusOptions) & 0x7;
-
- if (phys_dma) {
- host->low_addr_space =
- (u64) reg_read(ohci, OHCI1394_PhyUpperBound) << 16;
- if (!host->low_addr_space)
- host->low_addr_space = OHCI1394_PHYS_UPPER_BOUND_FIXED;
- }
- host->middle_addr_space = OHCI1394_MIDDLE_ADDRESS_SPACE;
-
- /* Tell the highlevel this host is ready */
- if (hpsb_add_host(host)) {
- PRINT_G(KERN_ERR, "Failed to register host with highlevel");
- goto err;
- }
- ohci->init_state = OHCI_INIT_DONE;
-
- return 0;
-err:
- ohci1394_pci_remove(dev);
- return err;
-}
-
-static void ohci1394_pci_remove(struct pci_dev *dev)
-{
- struct ti_ohci *ohci;
- struct device *device;
-
- ohci = pci_get_drvdata(dev);
- if (!ohci)
- goto out;
-
- device = get_device(&ohci->host->device);
-
- switch (ohci->init_state) {
- case OHCI_INIT_DONE:
- hpsb_remove_host(ohci->host);
-
- /* Clear out BUS Options */
- reg_write(ohci, OHCI1394_ConfigROMhdr, 0);
- reg_write(ohci, OHCI1394_BusOptions,
- (reg_read(ohci, OHCI1394_BusOptions) & 0x0000f007) |
- 0x00ff0000);
- memset(ohci->csr_config_rom_cpu, 0, OHCI_CONFIG_ROM_LEN);
-
- case OHCI_INIT_HAVE_IRQ:
- /* Clear interrupt registers */
- reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
-
- /* Disable IRM Contender */
- set_phy_reg(ohci, 4, ~0xc0 & get_phy_reg(ohci, 4));
-
- /* Clear link control register */
- reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
-
- /* Let all other nodes know to ignore us */
- ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT);
-
- /* Soft reset before we start - this disables
- * interrupts and clears linkEnable and LPS. */
- ohci_soft_reset(ohci);
- free_irq(dev->irq, ohci);
-
- case OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE:
- /* The ohci_soft_reset() stops all DMA contexts, so we
- * dont need to do this. */
- free_dma_rcv_ctx(&ohci->ar_req_context);
- free_dma_rcv_ctx(&ohci->ar_resp_context);
- free_dma_trm_ctx(&ohci->at_req_context);
- free_dma_trm_ctx(&ohci->at_resp_context);
-
- case OHCI_INIT_HAVE_SELFID_BUFFER:
- pci_free_consistent(dev, OHCI1394_SI_DMA_BUF_SIZE,
- ohci->selfid_buf_cpu,
- ohci->selfid_buf_bus);
-
- case OHCI_INIT_HAVE_CONFIG_ROM_BUFFER:
- pci_free_consistent(dev, OHCI_CONFIG_ROM_LEN,
- ohci->csr_config_rom_cpu,
- ohci->csr_config_rom_bus);
-
- case OHCI_INIT_HAVE_IOMAPPING:
- iounmap(ohci->registers);
-
- case OHCI_INIT_HAVE_MEM_REGION:
- release_mem_region(pci_resource_start(dev, 0),
- OHCI1394_REGISTER_SIZE);
-
- case OHCI_INIT_ALLOC_HOST:
- pci_set_drvdata(dev, NULL);
- }
-
- if (device)
- put_device(device);
-out:
- ohci1394_pmac_off(dev);
-}
-
-#ifdef CONFIG_PM
-static int ohci1394_pci_suspend(struct pci_dev *dev, pm_message_t state)
-{
- int err;
- struct ti_ohci *ohci = pci_get_drvdata(dev);
-
- if (!ohci) {
- printk(KERN_ERR "%s: tried to suspend nonexisting host\n",
- OHCI1394_DRIVER_NAME);
- return -ENXIO;
- }
- DBGMSG("suspend called");
-
- /* Clear the async DMA contexts and stop using the controller */
- hpsb_bus_reset(ohci->host);
-
- /* See ohci1394_pci_remove() for comments on this sequence */
- reg_write(ohci, OHCI1394_ConfigROMhdr, 0);
- reg_write(ohci, OHCI1394_BusOptions,
- (reg_read(ohci, OHCI1394_BusOptions) & 0x0000f007) |
- 0x00ff0000);
- reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
- set_phy_reg(ohci, 4, ~0xc0 & get_phy_reg(ohci, 4));
- reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
- ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT);
- ohci_soft_reset(ohci);
-
- free_irq(dev->irq, ohci);
- err = pci_save_state(dev);
- if (err) {
- PRINT(KERN_ERR, "pci_save_state failed with %d", err);
- return err;
- }
- err = pci_set_power_state(dev, pci_choose_state(dev, state));
- if (err)
- DBGMSG("pci_set_power_state failed with %d", err);
- ohci1394_pmac_off(dev);
-
- return 0;
-}
-
-static int ohci1394_pci_resume(struct pci_dev *dev)
-{
- int err;
- struct ti_ohci *ohci = pci_get_drvdata(dev);
-
- if (!ohci) {
- printk(KERN_ERR "%s: tried to resume nonexisting host\n",
- OHCI1394_DRIVER_NAME);
- return -ENXIO;
- }
- DBGMSG("resume called");
-
- ohci1394_pmac_on(dev);
- pci_set_power_state(dev, PCI_D0);
- pci_restore_state(dev);
- err = pci_enable_device(dev);
- if (err) {
- PRINT(KERN_ERR, "pci_enable_device failed with %d", err);
- return err;
- }
-
- /* See ohci1394_pci_probe() for comments on this sequence */
- ohci_soft_reset(ohci);
- reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
- reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
- reg_read(ohci, OHCI1394_Version);
- msleep(50);
-
- err = request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED,
- OHCI1394_DRIVER_NAME, ohci);
- if (err) {
- PRINT_G(KERN_ERR, "Failed to allocate interrupt %d", dev->irq);
- return err;
- }
-
- ohci_initialize(ohci);
-
- hpsb_resume_host(ohci->host);
- return 0;
-}
-#endif /* CONFIG_PM */
-
-static struct pci_device_id ohci1394_pci_tbl[] = {
- {
- .class = PCI_CLASS_SERIAL_FIREWIRE_OHCI,
- .class_mask = PCI_ANY_ID,
- .vendor = PCI_ANY_ID,
- .device = PCI_ANY_ID,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);
-
-static struct pci_driver ohci1394_pci_driver = {
- .name = OHCI1394_DRIVER_NAME,
- .id_table = ohci1394_pci_tbl,
- .probe = ohci1394_pci_probe,
- .remove = ohci1394_pci_remove,
-#ifdef CONFIG_PM
- .resume = ohci1394_pci_resume,
- .suspend = ohci1394_pci_suspend,
-#endif
-};
-
-/***********************************
- * OHCI1394 Video Interface *
- ***********************************/
-
-/* essentially the only purpose of this code is to allow another
- module to hook into ohci's interrupt handler */
-
-/* returns zero if successful, one if DMA context is locked up */
-int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
-{
- int i=0;
-
- /* stop the channel program if it's still running */
- reg_write(ohci, reg, 0x8000);
-
- /* Wait until it effectively stops */
- while (reg_read(ohci, reg) & 0x400) {
- i++;
- if (i>5000) {
- PRINT(KERN_ERR,
- "Runaway loop while stopping context: %s...", msg ? msg : "");
- return 1;
- }
-
- mb();
- udelay(10);
- }
- if (msg) PRINT(KERN_ERR, "%s: dma prg stopped", msg);
- return 0;
-}
-
-void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, int type,
- void (*func)(unsigned long), unsigned long data)
-{
- tasklet_init(&tasklet->tasklet, func, data);
- tasklet->type = type;
- /* We init the tasklet->link field, so we can list_del() it
- * without worrying whether it was added to the list or not. */
- INIT_LIST_HEAD(&tasklet->link);
-}
-
-int ohci1394_register_iso_tasklet(struct ti_ohci *ohci,
- struct ohci1394_iso_tasklet *tasklet)
-{
- unsigned long flags, *usage;
- int n, i, r = -EBUSY;
-
- if (tasklet->type == OHCI_ISO_TRANSMIT) {
- n = ohci->nb_iso_xmit_ctx;
- usage = &ohci->it_ctx_usage;
- }
- else {
- n = ohci->nb_iso_rcv_ctx;
- usage = &ohci->ir_ctx_usage;
-
- /* only one receive context can be multichannel (OHCI sec 10.4.1) */
- if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) {
- if (test_and_set_bit(0, &ohci->ir_multichannel_used)) {
- return r;
- }
- }
- }
-
- spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
-
- for (i = 0; i < n; i++)
- if (!test_and_set_bit(i, usage)) {
- tasklet->context = i;
- list_add_tail(&tasklet->link, &ohci->iso_tasklet_list);
- r = 0;
- break;
- }
-
- spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
-
- return r;
-}
-
-void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
- struct ohci1394_iso_tasklet *tasklet)
-{
- unsigned long flags;
-
- tasklet_kill(&tasklet->tasklet);
-
- spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
-
- if (tasklet->type == OHCI_ISO_TRANSMIT)
- clear_bit(tasklet->context, &ohci->it_ctx_usage);
- else {
- clear_bit(tasklet->context, &ohci->ir_ctx_usage);
-
- if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) {
- clear_bit(0, &ohci->ir_multichannel_used);
- }
- }
-
- list_del(&tasklet->link);
-
- spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
-}
-
-EXPORT_SYMBOL(ohci1394_stop_context);
-EXPORT_SYMBOL(ohci1394_init_iso_tasklet);
-EXPORT_SYMBOL(ohci1394_register_iso_tasklet);
-EXPORT_SYMBOL(ohci1394_unregister_iso_tasklet);
-
-/***********************************
- * General module initialization *
- ***********************************/
-
-MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
-MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers");
-MODULE_LICENSE("GPL");
-
-static void __exit ohci1394_cleanup (void)
-{
- pci_unregister_driver(&ohci1394_pci_driver);
-}
-
-static int __init ohci1394_init(void)
-{
- return pci_register_driver(&ohci1394_pci_driver);
-}
-
-module_init(ohci1394_init);
-module_exit(ohci1394_cleanup);
diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h
deleted file mode 100644
index 7fb8ab9780ae..000000000000
--- a/drivers/ieee1394/ohci1394.h
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * ohci1394.h - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- * Gord Peters <GordPeters@smarttech.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 _OHCI1394_H
-#define _OHCI1394_H
-
-#include "ieee1394_types.h"
-#include <asm/io.h>
-
-#define OHCI1394_DRIVER_NAME "ohci1394"
-
-#define OHCI1394_MAX_AT_REQ_RETRIES 0xf
-#define OHCI1394_MAX_AT_RESP_RETRIES 0x2
-#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8
-#define OHCI1394_MAX_SELF_ID_ERRORS 16
-
-#define AR_REQ_NUM_DESC 4 /* number of AR req descriptors */
-#define AR_REQ_BUF_SIZE PAGE_SIZE /* size of AR req buffers */
-#define AR_REQ_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */
-
-#define AR_RESP_NUM_DESC 4 /* number of AR resp descriptors */
-#define AR_RESP_BUF_SIZE PAGE_SIZE /* size of AR resp buffers */
-#define AR_RESP_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */
-
-#define IR_NUM_DESC 16 /* number of IR descriptors */
-#define IR_BUF_SIZE PAGE_SIZE /* 4096 bytes/buffer */
-#define IR_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */
-
-#define IT_NUM_DESC 16 /* number of IT descriptors */
-
-#define AT_REQ_NUM_DESC 32 /* number of AT req descriptors */
-#define AT_RESP_NUM_DESC 32 /* number of AT resp descriptors */
-
-#define OHCI_LOOP_COUNT 100 /* Number of loops for reg read waits */
-
-#define OHCI_CONFIG_ROM_LEN 1024 /* Length of the mapped configrom space */
-
-#define OHCI1394_SI_DMA_BUF_SIZE 8192 /* length of the selfid buffer */
-
-/* PCI configuration space addresses */
-#define OHCI1394_PCI_HCI_Control 0x40
-
-struct dma_cmd {
- u32 control;
- u32 address;
- u32 branchAddress;
- u32 status;
-};
-
-/*
- * FIXME:
- * It is important that a single at_dma_prg does not cross a page boundary
- * The proper way to do it would be to do the check dynamically as the
- * programs are inserted into the AT fifo.
- */
-struct at_dma_prg {
- struct dma_cmd begin;
- quadlet_t data[4];
- struct dma_cmd end;
- quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */
-};
-
-/* identify whether a DMA context is asynchronous or isochronous */
-enum context_type { DMA_CTX_ASYNC_REQ, DMA_CTX_ASYNC_RESP, DMA_CTX_ISO };
-
-/* DMA receive context */
-struct dma_rcv_ctx {
- struct ti_ohci *ohci;
- enum context_type type;
- int ctx;
- unsigned int num_desc;
-
- unsigned int buf_size;
- unsigned int split_buf_size;
-
- /* dma block descriptors */
- struct dma_cmd **prg_cpu;
- dma_addr_t *prg_bus;
- struct pci_pool *prg_pool;
-
- /* dma buffers */
- quadlet_t **buf_cpu;
- dma_addr_t *buf_bus;
-
- unsigned int buf_ind;
- unsigned int buf_offset;
- quadlet_t *spb;
- spinlock_t lock;
- struct tasklet_struct task;
- int ctrlClear;
- int ctrlSet;
- int cmdPtr;
- int ctxtMatch;
-};
-
-/* DMA transmit context */
-struct dma_trm_ctx {
- struct ti_ohci *ohci;
- enum context_type type;
- int ctx;
- unsigned int num_desc;
-
- /* dma block descriptors */
- struct at_dma_prg **prg_cpu;
- dma_addr_t *prg_bus;
- struct pci_pool *prg_pool;
-
- unsigned int prg_ind;
- unsigned int sent_ind;
- int free_prgs;
- quadlet_t *branchAddrPtr;
-
- /* list of packets inserted in the AT FIFO */
- struct list_head fifo_list;
-
- /* list of pending packets to be inserted in the AT FIFO */
- struct list_head pending_list;
-
- spinlock_t lock;
- struct tasklet_struct task;
- int ctrlClear;
- int ctrlSet;
- int cmdPtr;
-};
-
-struct ohci1394_iso_tasklet {
- struct tasklet_struct tasklet;
- struct list_head link;
- int context;
- enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE,
- OHCI_ISO_MULTICHANNEL_RECEIVE } type;
-};
-
-struct ti_ohci {
- struct pci_dev *dev;
-
- enum {
- OHCI_INIT_ALLOC_HOST,
- OHCI_INIT_HAVE_MEM_REGION,
- OHCI_INIT_HAVE_IOMAPPING,
- OHCI_INIT_HAVE_CONFIG_ROM_BUFFER,
- OHCI_INIT_HAVE_SELFID_BUFFER,
- OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE,
- OHCI_INIT_HAVE_IRQ,
- OHCI_INIT_DONE,
- } init_state;
-
- /* remapped memory spaces */
- void __iomem *registers;
-
- /* dma buffer for self-id packets */
- quadlet_t *selfid_buf_cpu;
- dma_addr_t selfid_buf_bus;
-
- /* buffer for csr config rom */
- quadlet_t *csr_config_rom_cpu;
- dma_addr_t csr_config_rom_bus;
- int csr_config_rom_length;
-
- unsigned int max_packet_size;
-
- /* async receive */
- struct dma_rcv_ctx ar_resp_context;
- struct dma_rcv_ctx ar_req_context;
-
- /* async transmit */
- struct dma_trm_ctx at_resp_context;
- struct dma_trm_ctx at_req_context;
-
- /* iso receive */
- int nb_iso_rcv_ctx;
- unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */
- unsigned long ir_multichannel_used; /* ditto */
- spinlock_t IR_channel_lock;
-
- /* iso transmit */
- int nb_iso_xmit_ctx;
- unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */
-
- u64 ISO_channel_usage;
-
- /* IEEE-1394 part follows */
- struct hpsb_host *host;
-
- int phyid, isroot;
-
- spinlock_t phy_reg_lock;
- spinlock_t event_lock;
-
- int self_id_errors;
-
- /* Tasklets for iso receive and transmit, used by video1394
- * and dv1394 */
- struct list_head iso_tasklet_list;
- spinlock_t iso_tasklet_list_lock;
-
- /* Swap the selfid buffer? */
- unsigned int selfid_swap:1;
- /* Some Apple chipset seem to swap incoming headers for us */
- unsigned int no_swap_incoming:1;
-
- /* Force extra paranoia checking on bus-reset handling */
- unsigned int check_busreset:1;
-};
-
-static inline int cross_bound(unsigned long addr, unsigned int size)
-{
- if (size == 0)
- return 0;
-
- if (size > PAGE_SIZE)
- return 1;
-
- if (addr >> PAGE_SHIFT != (addr + size - 1) >> PAGE_SHIFT)
- return 1;
-
- return 0;
-}
-
-/*
- * Register read and write helper functions.
- */
-static inline void reg_write(const struct ti_ohci *ohci, int offset, u32 data)
-{
- writel(data, ohci->registers + offset);
-}
-
-static inline u32 reg_read(const struct ti_ohci *ohci, int offset)
-{
- return readl(ohci->registers + offset);
-}
-
-
-/* 2 KiloBytes of register space */
-#define OHCI1394_REGISTER_SIZE 0x800
-
-/* Offsets relative to context bases defined below */
-
-#define OHCI1394_ContextControlSet 0x000
-#define OHCI1394_ContextControlClear 0x004
-#define OHCI1394_ContextCommandPtr 0x00C
-
-/* register map */
-#define OHCI1394_Version 0x000
-#define OHCI1394_GUID_ROM 0x004
-#define OHCI1394_ATRetries 0x008
-#define OHCI1394_CSRData 0x00C
-#define OHCI1394_CSRCompareData 0x010
-#define OHCI1394_CSRControl 0x014
-#define OHCI1394_ConfigROMhdr 0x018
-#define OHCI1394_BusID 0x01C
-#define OHCI1394_BusOptions 0x020
-#define OHCI1394_GUIDHi 0x024
-#define OHCI1394_GUIDLo 0x028
-#define OHCI1394_ConfigROMmap 0x034
-#define OHCI1394_PostedWriteAddressLo 0x038
-#define OHCI1394_PostedWriteAddressHi 0x03C
-#define OHCI1394_VendorID 0x040
-#define OHCI1394_HCControlSet 0x050
-#define OHCI1394_HCControlClear 0x054
-#define OHCI1394_HCControl_noByteSwap 0x40000000
-#define OHCI1394_HCControl_programPhyEnable 0x00800000
-#define OHCI1394_HCControl_aPhyEnhanceEnable 0x00400000
-#define OHCI1394_HCControl_LPS 0x00080000
-#define OHCI1394_HCControl_postedWriteEnable 0x00040000
-#define OHCI1394_HCControl_linkEnable 0x00020000
-#define OHCI1394_HCControl_softReset 0x00010000
-#define OHCI1394_SelfIDBuffer 0x064
-#define OHCI1394_SelfIDCount 0x068
-#define OHCI1394_IRMultiChanMaskHiSet 0x070
-#define OHCI1394_IRMultiChanMaskHiClear 0x074
-#define OHCI1394_IRMultiChanMaskLoSet 0x078
-#define OHCI1394_IRMultiChanMaskLoClear 0x07C
-#define OHCI1394_IntEventSet 0x080
-#define OHCI1394_IntEventClear 0x084
-#define OHCI1394_IntMaskSet 0x088
-#define OHCI1394_IntMaskClear 0x08C
-#define OHCI1394_IsoXmitIntEventSet 0x090
-#define OHCI1394_IsoXmitIntEventClear 0x094
-#define OHCI1394_IsoXmitIntMaskSet 0x098
-#define OHCI1394_IsoXmitIntMaskClear 0x09C
-#define OHCI1394_IsoRecvIntEventSet 0x0A0
-#define OHCI1394_IsoRecvIntEventClear 0x0A4
-#define OHCI1394_IsoRecvIntMaskSet 0x0A8
-#define OHCI1394_IsoRecvIntMaskClear 0x0AC
-#define OHCI1394_InitialBandwidthAvailable 0x0B0
-#define OHCI1394_InitialChannelsAvailableHi 0x0B4
-#define OHCI1394_InitialChannelsAvailableLo 0x0B8
-#define OHCI1394_FairnessControl 0x0DC
-#define OHCI1394_LinkControlSet 0x0E0
-#define OHCI1394_LinkControlClear 0x0E4
-#define OHCI1394_LinkControl_RcvSelfID 0x00000200
-#define OHCI1394_LinkControl_RcvPhyPkt 0x00000400
-#define OHCI1394_LinkControl_CycleTimerEnable 0x00100000
-#define OHCI1394_LinkControl_CycleMaster 0x00200000
-#define OHCI1394_LinkControl_CycleSource 0x00400000
-#define OHCI1394_NodeID 0x0E8
-#define OHCI1394_PhyControl 0x0EC
-#define OHCI1394_IsochronousCycleTimer 0x0F0
-#define OHCI1394_AsReqFilterHiSet 0x100
-#define OHCI1394_AsReqFilterHiClear 0x104
-#define OHCI1394_AsReqFilterLoSet 0x108
-#define OHCI1394_AsReqFilterLoClear 0x10C
-#define OHCI1394_PhyReqFilterHiSet 0x110
-#define OHCI1394_PhyReqFilterHiClear 0x114
-#define OHCI1394_PhyReqFilterLoSet 0x118
-#define OHCI1394_PhyReqFilterLoClear 0x11C
-#define OHCI1394_PhyUpperBound 0x120
-
-#define OHCI1394_AsReqTrContextBase 0x180
-#define OHCI1394_AsReqTrContextControlSet 0x180
-#define OHCI1394_AsReqTrContextControlClear 0x184
-#define OHCI1394_AsReqTrCommandPtr 0x18C
-
-#define OHCI1394_AsRspTrContextBase 0x1A0
-#define OHCI1394_AsRspTrContextControlSet 0x1A0
-#define OHCI1394_AsRspTrContextControlClear 0x1A4
-#define OHCI1394_AsRspTrCommandPtr 0x1AC
-
-#define OHCI1394_AsReqRcvContextBase 0x1C0
-#define OHCI1394_AsReqRcvContextControlSet 0x1C0
-#define OHCI1394_AsReqRcvContextControlClear 0x1C4
-#define OHCI1394_AsReqRcvCommandPtr 0x1CC
-
-#define OHCI1394_AsRspRcvContextBase 0x1E0
-#define OHCI1394_AsRspRcvContextControlSet 0x1E0
-#define OHCI1394_AsRspRcvContextControlClear 0x1E4
-#define OHCI1394_AsRspRcvCommandPtr 0x1EC
-
-/* Isochronous transmit registers */
-/* Add (16 * n) for context n */
-#define OHCI1394_IsoXmitContextBase 0x200
-#define OHCI1394_IsoXmitContextControlSet 0x200
-#define OHCI1394_IsoXmitContextControlClear 0x204
-#define OHCI1394_IsoXmitCommandPtr 0x20C
-
-/* Isochronous receive registers */
-/* Add (32 * n) for context n */
-#define OHCI1394_IsoRcvContextBase 0x400
-#define OHCI1394_IsoRcvContextControlSet 0x400
-#define OHCI1394_IsoRcvContextControlClear 0x404
-#define OHCI1394_IsoRcvCommandPtr 0x40C
-#define OHCI1394_IsoRcvContextMatch 0x410
-
-/* Interrupts Mask/Events */
-
-#define OHCI1394_reqTxComplete 0x00000001
-#define OHCI1394_respTxComplete 0x00000002
-#define OHCI1394_ARRQ 0x00000004
-#define OHCI1394_ARRS 0x00000008
-#define OHCI1394_RQPkt 0x00000010
-#define OHCI1394_RSPkt 0x00000020
-#define OHCI1394_isochTx 0x00000040
-#define OHCI1394_isochRx 0x00000080
-#define OHCI1394_postedWriteErr 0x00000100
-#define OHCI1394_lockRespErr 0x00000200
-#define OHCI1394_selfIDComplete 0x00010000
-#define OHCI1394_busReset 0x00020000
-#define OHCI1394_phy 0x00080000
-#define OHCI1394_cycleSynch 0x00100000
-#define OHCI1394_cycle64Seconds 0x00200000
-#define OHCI1394_cycleLost 0x00400000
-#define OHCI1394_cycleInconsistent 0x00800000
-#define OHCI1394_unrecoverableError 0x01000000
-#define OHCI1394_cycleTooLong 0x02000000
-#define OHCI1394_phyRegRcvd 0x04000000
-#define OHCI1394_masterIntEnable 0x80000000
-
-/* DMA Control flags */
-#define DMA_CTL_OUTPUT_MORE 0x00000000
-#define DMA_CTL_OUTPUT_LAST 0x10000000
-#define DMA_CTL_INPUT_MORE 0x20000000
-#define DMA_CTL_INPUT_LAST 0x30000000
-#define DMA_CTL_UPDATE 0x08000000
-#define DMA_CTL_IMMEDIATE 0x02000000
-#define DMA_CTL_IRQ 0x00300000
-#define DMA_CTL_BRANCH 0x000c0000
-#define DMA_CTL_WAIT 0x00030000
-
-/* OHCI evt_* error types, table 3-2 of the OHCI 1.1 spec. */
-#define EVT_NO_STATUS 0x0 /* No event status */
-#define EVT_RESERVED_A 0x1 /* Reserved, not used !!! */
-#define EVT_LONG_PACKET 0x2 /* The revc data was longer than the buf */
-#define EVT_MISSING_ACK 0x3 /* A subaction gap was detected before an ack
- arrived, or recv'd ack had a parity error */
-#define EVT_UNDERRUN 0x4 /* Underrun on corresponding FIFO, packet
- truncated */
-#define EVT_OVERRUN 0x5 /* A recv FIFO overflowed on reception of ISO
- packet */
-#define EVT_DESCRIPTOR_READ 0x6 /* An unrecoverable error occurred while host was
- reading a descriptor block */
-#define EVT_DATA_READ 0x7 /* An error occurred while host controller was
- attempting to read from host memory in the data
- stage of descriptor processing */
-#define EVT_DATA_WRITE 0x8 /* An error occurred while host controller was
- attempting to write either during the data stage
- of descriptor processing, or when processing a single
- 16-bit host memory write */
-#define EVT_BUS_RESET 0x9 /* Identifies a PHY packet in the recv buffer as
- being a synthesized bus reset packet */
-#define EVT_TIMEOUT 0xa /* Indicates that the asynchronous transmit response
- packet expired and was not transmitted, or that an
- IT DMA context experienced a skip processing overflow */
-#define EVT_TCODE_ERR 0xb /* A bad tCode is associated with this packet.
- The packet was flushed */
-#define EVT_RESERVED_B 0xc /* Reserved, not used !!! */
-#define EVT_RESERVED_C 0xd /* Reserved, not used !!! */
-#define EVT_UNKNOWN 0xe /* An error condition has occurred that cannot be
- represented by any other event codes defined herein. */
-#define EVT_FLUSHED 0xf /* Send by the link side of output FIFO when asynchronous
- packets are being flushed due to a bus reset. */
-
-#define OHCI1394_TCODE_PHY 0xE
-
-/* Node offset map (phys DMA area, posted write area).
- * The value of OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED may be modified but must
- * be lower than OHCI1394_MIDDLE_ADDRESS_SPACE.
- * OHCI1394_PHYS_UPPER_BOUND_FIXED and OHCI1394_MIDDLE_ADDRESS_SPACE are
- * constants given by the OHCI spec.
- */
-#define OHCI1394_PHYS_UPPER_BOUND_FIXED 0x000100000000ULL /* 4 GB */
-#define OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED 0x010000000000ULL /* 1 TB */
-#define OHCI1394_MIDDLE_ADDRESS_SPACE 0xffff00000000ULL
-
-void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet,
- int type,
- void (*func)(unsigned long),
- unsigned long data);
-int ohci1394_register_iso_tasklet(struct ti_ohci *ohci,
- struct ohci1394_iso_tasklet *tasklet);
-void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
- struct ohci1394_iso_tasklet *tasklet);
-int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
-struct ti_ohci *ohci1394_get_struct(int card_num);
-
-#endif
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
deleted file mode 100644
index bf47fee79808..000000000000
--- a/drivers/ieee1394/pcilynx.c
+++ /dev/null
@@ -1,1554 +0,0 @@
-/*
- * pcilynx.c - Texas Instruments PCILynx driver
- * Copyright (C) 1999,2000 Andreas Bombe <andreas.bombe@munich.netsurf.de>,
- * Stephan Linz <linz@mazet.de>
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- *
- * 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.
- */
-
-/*
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- * reading bus info block (containing GUID) from serial
- * eeprom via i2c and storing it in config ROM
- * Reworked code for initiating bus resets
- * (long, short, with or without hold-off)
- * Enhancements in async and iso send code
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/kdev_t.h>
-#include <linux/dma-mapping.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "pcilynx.h"
-
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-/* print general (card independent) information */
-#define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
-/* print card specific information */
-#define PRINT(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define PRINT_GD(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
-#define PRINTD(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)
-#else
-#define PRINT_GD(level, fmt, args...) do {} while (0)
-#define PRINTD(level, card, fmt, args...) do {} while (0)
-#endif
-
-
-/* Module Parameters */
-static int skip_eeprom;
-module_param(skip_eeprom, int, 0444);
-MODULE_PARM_DESC(skip_eeprom, "Use generic bus info block instead of serial eeprom (default = 0).");
-
-
-static struct hpsb_host_driver lynx_driver;
-static unsigned int card_id;
-
-
-
-/*
- * I2C stuff
- */
-
-/* the i2c stuff was inspired by i2c-philips-par.c */
-
-static void bit_setscl(void *data, int state)
-{
- if (state) {
- ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000040;
- } else {
- ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000040;
- }
- reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state);
-}
-
-static void bit_setsda(void *data, int state)
-{
- if (state) {
- ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000010;
- } else {
- ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000010;
- }
- reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state);
-}
-
-static int bit_getscl(void *data)
-{
- return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000040;
-}
-
-static int bit_getsda(void *data)
-{
- return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000010;
-}
-
-static struct i2c_algo_bit_data bit_data = {
- .setsda = bit_setsda,
- .setscl = bit_setscl,
- .getsda = bit_getsda,
- .getscl = bit_getscl,
- .udelay = 5,
- .timeout = 100,
-};
-
-
-/*
- * PCL handling functions.
- */
-
-static pcl_t alloc_pcl(struct ti_lynx *lynx)
-{
- u8 m;
- int i, j;
-
- spin_lock(&lynx->lock);
- /* FIXME - use ffz() to make this readable */
- for (i = 0; i < (LOCALRAM_SIZE / 1024); i++) {
- m = lynx->pcl_bmap[i];
- for (j = 0; j < 8; j++) {
- if (m & 1<<j) {
- continue;
- }
- m |= 1<<j;
- lynx->pcl_bmap[i] = m;
- spin_unlock(&lynx->lock);
- return 8 * i + j;
- }
- }
- spin_unlock(&lynx->lock);
-
- return -1;
-}
-
-
-#if 0
-static void free_pcl(struct ti_lynx *lynx, pcl_t pclid)
-{
- int off, bit;
-
- off = pclid / 8;
- bit = pclid % 8;
-
- if (pclid < 0) {
- return;
- }
-
- spin_lock(&lynx->lock);
- if (lynx->pcl_bmap[off] & 1<<bit) {
- lynx->pcl_bmap[off] &= ~(1<<bit);
- } else {
- PRINT(KERN_ERR, lynx->id,
- "attempted to free unallocated PCL %d", pclid);
- }
- spin_unlock(&lynx->lock);
-}
-
-/* functions useful for debugging */
-static void pretty_print_pcl(const struct ti_pcl *pcl)
-{
- int i;
-
- printk("PCL next %08x, userdata %08x, status %08x, remtrans %08x, nextbuf %08x\n",
- pcl->next, pcl->user_data, pcl->pcl_status,
- pcl->remaining_transfer_count, pcl->next_data_buffer);
-
- printk("PCL");
- for (i=0; i<13; i++) {
- printk(" c%x:%08x d%x:%08x",
- i, pcl->buffer[i].control, i, pcl->buffer[i].pointer);
- if (!(i & 0x3) && (i != 12)) printk("\nPCL");
- }
- printk("\n");
-}
-
-static void print_pcl(const struct ti_lynx *lynx, pcl_t pclid)
-{
- struct ti_pcl pcl;
-
- get_pcl(lynx, pclid, &pcl);
- pretty_print_pcl(&pcl);
-}
-#endif
-
-
-
-/***********************************
- * IEEE-1394 functionality section *
- ***********************************/
-
-
-static int get_phy_reg(struct ti_lynx *lynx, int addr)
-{
- int retval;
- int i = 0;
-
- unsigned long flags;
-
- if (addr > 15) {
- PRINT(KERN_ERR, lynx->id,
- "%s: PHY register address %d out of range",
- __func__, addr);
- return -1;
- }
-
- spin_lock_irqsave(&lynx->phy_reg_lock, flags);
-
- reg_write(lynx, LINK_PHY, LINK_PHY_READ | LINK_PHY_ADDR(addr));
- do {
- retval = reg_read(lynx, LINK_PHY);
-
- if (i > 10000) {
- PRINT(KERN_ERR, lynx->id, "%s: runaway loop, aborting",
- __func__);
- retval = -1;
- break;
- }
- i++;
- } while ((retval & 0xf00) != LINK_PHY_RADDR(addr));
-
- reg_write(lynx, LINK_INT_STATUS, LINK_INT_PHY_REG_RCVD);
- spin_unlock_irqrestore(&lynx->phy_reg_lock, flags);
-
- if (retval != -1) {
- return retval & 0xff;
- } else {
- return -1;
- }
-}
-
-static int set_phy_reg(struct ti_lynx *lynx, int addr, int val)
-{
- unsigned long flags;
-
- if (addr > 15) {
- PRINT(KERN_ERR, lynx->id,
- "%s: PHY register address %d out of range", __func__, addr);
- return -1;
- }
-
- if (val > 0xff) {
- PRINT(KERN_ERR, lynx->id,
- "%s: PHY register value %d out of range", __func__, val);
- return -1;
- }
-
- spin_lock_irqsave(&lynx->phy_reg_lock, flags);
-
- reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | LINK_PHY_ADDR(addr)
- | LINK_PHY_WDATA(val));
-
- spin_unlock_irqrestore(&lynx->phy_reg_lock, flags);
-
- return 0;
-}
-
-static int sel_phy_reg_page(struct ti_lynx *lynx, int page)
-{
- int reg;
-
- if (page > 7) {
- PRINT(KERN_ERR, lynx->id,
- "%s: PHY page %d out of range", __func__, page);
- return -1;
- }
-
- reg = get_phy_reg(lynx, 7);
- if (reg != -1) {
- reg &= 0x1f;
- reg |= (page << 5);
- set_phy_reg(lynx, 7, reg);
- return 0;
- } else {
- return -1;
- }
-}
-
-#if 0 /* not needed at this time */
-static int sel_phy_reg_port(struct ti_lynx *lynx, int port)
-{
- int reg;
-
- if (port > 15) {
- PRINT(KERN_ERR, lynx->id,
- "%s: PHY port %d out of range", __func__, port);
- return -1;
- }
-
- reg = get_phy_reg(lynx, 7);
- if (reg != -1) {
- reg &= 0xf0;
- reg |= port;
- set_phy_reg(lynx, 7, reg);
- return 0;
- } else {
- return -1;
- }
-}
-#endif
-
-static u32 get_phy_vendorid(struct ti_lynx *lynx)
-{
- u32 pvid = 0;
- sel_phy_reg_page(lynx, 1);
- pvid |= (get_phy_reg(lynx, 10) << 16);
- pvid |= (get_phy_reg(lynx, 11) << 8);
- pvid |= get_phy_reg(lynx, 12);
- PRINT(KERN_INFO, lynx->id, "PHY vendor id 0x%06x", pvid);
- return pvid;
-}
-
-static u32 get_phy_productid(struct ti_lynx *lynx)
-{
- u32 id = 0;
- sel_phy_reg_page(lynx, 1);
- id |= (get_phy_reg(lynx, 13) << 16);
- id |= (get_phy_reg(lynx, 14) << 8);
- id |= get_phy_reg(lynx, 15);
- PRINT(KERN_INFO, lynx->id, "PHY product id 0x%06x", id);
- return id;
-}
-
-static quadlet_t generate_own_selfid(struct ti_lynx *lynx,
- struct hpsb_host *host)
-{
- quadlet_t lsid;
- char phyreg[7];
- int i;
-
- phyreg[0] = lynx->phy_reg0;
- for (i = 1; i < 7; i++) {
- phyreg[i] = get_phy_reg(lynx, i);
- }
-
- /* FIXME? We assume a TSB21LV03A phy here. This code doesn't support
- more than 3 ports on the PHY anyway. */
-
- lsid = 0x80400000 | ((phyreg[0] & 0xfc) << 22);
- lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */
- lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */
- if (!hpsb_disable_irm)
- lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dependent) */
- /* lsid |= 1 << 11; *//* set contender (hack) */
- lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */
-
- for (i = 0; i < (phyreg[2] & 0xf); i++) { /* ports */
- if (phyreg[3 + i] & 0x4) {
- lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3)
- << (6 - i*2);
- } else {
- lsid |= 1 << (6 - i*2);
- }
- }
-
- cpu_to_be32s(&lsid);
- PRINT(KERN_DEBUG, lynx->id, "generated own selfid 0x%x", lsid);
- return lsid;
-}
-
-static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host)
-{
- quadlet_t *q = lynx->rcv_page;
- int phyid, isroot, size;
- quadlet_t lsid = 0;
- int i;
-
- if (lynx->phy_reg0 == -1 || lynx->selfid_size == -1) return;
-
- size = lynx->selfid_size;
- phyid = lynx->phy_reg0;
-
- i = (size > 16 ? 16 : size) / 4 - 1;
- while (i >= 0) {
- cpu_to_be32s(&q[i]);
- i--;
- }
-
- if (!lynx->phyic.reg_1394a) {
- lsid = generate_own_selfid(lynx, host);
- }
-
- isroot = (phyid & 2) != 0;
- phyid >>= 2;
- PRINT(KERN_INFO, lynx->id, "SelfID process finished (phyid %d, %s)",
- phyid, (isroot ? "root" : "not root"));
- reg_write(lynx, LINK_ID, (0xffc0 | phyid) << 16);
-
- if (!lynx->phyic.reg_1394a && !size) {
- hpsb_selfid_received(host, lsid);
- }
-
- while (size > 0) {
- struct selfid *sid = (struct selfid *)q;
-
- if (!lynx->phyic.reg_1394a && !sid->extended
- && (sid->phy_id == (phyid + 1))) {
- hpsb_selfid_received(host, lsid);
- }
-
- if (q[0] == ~q[1]) {
- PRINT(KERN_DEBUG, lynx->id, "SelfID packet 0x%x rcvd",
- q[0]);
- hpsb_selfid_received(host, q[0]);
- } else {
- PRINT(KERN_INFO, lynx->id,
- "inconsistent selfid 0x%x/0x%x", q[0], q[1]);
- }
- q += 2;
- size -= 8;
- }
-
- if (!lynx->phyic.reg_1394a && isroot && phyid != 0) {
- hpsb_selfid_received(host, lsid);
- }
-
- hpsb_selfid_complete(host, phyid, isroot);
-
- if (host->in_bus_reset) return; /* in bus reset again */
-
- if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); //FIXME: I do not think, we need this here
- reg_set_bits(lynx, LINK_CONTROL,
- LINK_CONTROL_RCV_CMP_VALID | LINK_CONTROL_TX_ASYNC_EN
- | LINK_CONTROL_RX_ASYNC_EN | LINK_CONTROL_CYCTIMEREN);
-}
-
-
-
-/* This must be called with the respective queue_lock held. */
-static void send_next(struct ti_lynx *lynx, int what)
-{
- struct ti_pcl pcl;
- struct lynx_send_data *d;
- struct hpsb_packet *packet;
-
-#if 0 /* has been removed from ieee1394 core */
- d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async);
-#else
- d = &lynx->async;
-#endif
- if (!list_empty(&d->pcl_queue)) {
- PRINT(KERN_ERR, lynx->id, "trying to queue a new packet in nonempty fifo");
- BUG();
- }
-
- packet = driver_packet(d->queue.next);
- list_move_tail(&packet->driver_list, &d->pcl_queue);
-
- d->header_dma = pci_map_single(lynx->dev, packet->header,
- packet->header_size, PCI_DMA_TODEVICE);
- if (packet->data_size) {
- d->data_dma = pci_map_single(lynx->dev, packet->data,
- packet->data_size,
- PCI_DMA_TODEVICE);
- } else {
- d->data_dma = 0;
- }
-
- pcl.next = PCL_NEXT_INVALID;
- pcl.async_error_next = PCL_NEXT_INVALID;
- pcl.pcl_status = 0;
- pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size;
-#ifndef __BIG_ENDIAN
- pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
- pcl.buffer[0].pointer = d->header_dma;
- pcl.buffer[1].control = PCL_LAST_BUFF | packet->data_size;
- pcl.buffer[1].pointer = d->data_dma;
-
- switch (packet->type) {
- case hpsb_async:
- pcl.buffer[0].control |= PCL_CMD_XMT;
- break;
-#if 0 /* has been removed from ieee1394 core */
- case hpsb_iso:
- pcl.buffer[0].control |= PCL_CMD_XMT | PCL_ISOMODE;
- break;
-#endif
- case hpsb_raw:
- pcl.buffer[0].control |= PCL_CMD_UNFXMT;
- break;
- }
-
- put_pcl(lynx, d->pcl, &pcl);
- run_pcl(lynx, d->pcl_start, d->channel);
-}
-
-
-/* called from subsystem core */
-static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
-{
- struct ti_lynx *lynx = host->hostdata;
- struct lynx_send_data *d;
- unsigned long flags;
-
- if (packet->data_size >= 4096) {
- PRINT(KERN_ERR, lynx->id, "transmit packet data too big (%Zd)",
- packet->data_size);
- return -EOVERFLOW;
- }
-
- switch (packet->type) {
- case hpsb_async:
- case hpsb_raw:
- d = &lynx->async;
- break;
-#if 0 /* has been removed from ieee1394 core */
- case hpsb_iso:
- d = &lynx->iso_send;
- break;
-#endif
- default:
- PRINT(KERN_ERR, lynx->id, "invalid packet type %d",
- packet->type);
- return -EINVAL;
- }
-
- if (packet->tcode == TCODE_WRITEQ
- || packet->tcode == TCODE_READQ_RESPONSE) {
- cpu_to_be32s(&packet->header[3]);
- }
-
- spin_lock_irqsave(&d->queue_lock, flags);
-
- list_add_tail(&packet->driver_list, &d->queue);
- if (list_empty(&d->pcl_queue))
- send_next(lynx, packet->type);
-
- spin_unlock_irqrestore(&d->queue_lock, flags);
-
- return 0;
-}
-
-
-/* called from subsystem core */
-static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
-{
- struct ti_lynx *lynx = host->hostdata;
- int retval = 0;
- struct hpsb_packet *packet;
- LIST_HEAD(packet_list);
- unsigned long flags;
- int phy_reg;
-
- switch (cmd) {
- case RESET_BUS:
- if (reg_read(lynx, LINK_INT_STATUS) & LINK_INT_PHY_BUSRESET) {
- retval = 0;
- break;
- }
-
- switch (arg) {
- case SHORT_RESET:
- if (lynx->phyic.reg_1394a) {
- phy_reg = get_phy_reg(lynx, 5);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- phy_reg |= 0x40;
-
- PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset) on request");
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
- set_phy_reg(lynx, 5, phy_reg); /* set ISBR */
- break;
- } else {
- PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy");
- /* fall through to long bus reset */
- }
- case LONG_RESET:
- phy_reg = get_phy_reg(lynx, 1);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- phy_reg |= 0x40;
-
- PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset) on request");
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
- set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */
- break;
- case SHORT_RESET_NO_FORCE_ROOT:
- if (lynx->phyic.reg_1394a) {
- phy_reg = get_phy_reg(lynx, 1);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- if (phy_reg & 0x80) {
- phy_reg &= ~0x80;
- set_phy_reg(lynx, 1, phy_reg); /* clear RHB */
- }
-
- phy_reg = get_phy_reg(lynx, 5);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- phy_reg |= 0x40;
-
- PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset, no force_root) on request");
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
- set_phy_reg(lynx, 5, phy_reg); /* set ISBR */
- break;
- } else {
- PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy");
- /* fall through to long bus reset */
- }
- case LONG_RESET_NO_FORCE_ROOT:
- phy_reg = get_phy_reg(lynx, 1);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- phy_reg &= ~0x80;
- phy_reg |= 0x40;
-
- PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset, no force_root) on request");
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
- set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */
- break;
- case SHORT_RESET_FORCE_ROOT:
- if (lynx->phyic.reg_1394a) {
- phy_reg = get_phy_reg(lynx, 1);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- if (!(phy_reg & 0x80)) {
- phy_reg |= 0x80;
- set_phy_reg(lynx, 1, phy_reg); /* set RHB */
- }
-
- phy_reg = get_phy_reg(lynx, 5);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- phy_reg |= 0x40;
-
- PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset, force_root set) on request");
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
- set_phy_reg(lynx, 5, phy_reg); /* set ISBR */
- break;
- } else {
- PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy");
- /* fall through to long bus reset */
- }
- case LONG_RESET_FORCE_ROOT:
- phy_reg = get_phy_reg(lynx, 1);
- if (phy_reg == -1) {
- PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
- retval = -1;
- break;
- }
- phy_reg |= 0xc0;
-
- PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset, force_root set) on request");
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
- set_phy_reg(lynx, 1, phy_reg); /* set IBR and RHB */
- break;
- default:
- PRINT(KERN_ERR, lynx->id, "unknown argument for reset_bus command %d", arg);
- retval = -1;
- }
-
- break;
-
- case GET_CYCLE_COUNTER:
- retval = reg_read(lynx, CYCLE_TIMER);
- break;
-
- case SET_CYCLE_COUNTER:
- reg_write(lynx, CYCLE_TIMER, arg);
- break;
-
- case SET_BUS_ID:
- reg_write(lynx, LINK_ID,
- (arg << 22) | (reg_read(lynx, LINK_ID) & 0x003f0000));
- break;
-
- case ACT_CYCLE_MASTER:
- if (arg) {
- reg_set_bits(lynx, LINK_CONTROL,
- LINK_CONTROL_CYCMASTER);
- } else {
- reg_clear_bits(lynx, LINK_CONTROL,
- LINK_CONTROL_CYCMASTER);
- }
- break;
-
- case CANCEL_REQUESTS:
- spin_lock_irqsave(&lynx->async.queue_lock, flags);
-
- reg_write(lynx, DMA_CHAN_CTRL(CHANNEL_ASYNC_SEND), 0);
- list_splice_init(&lynx->async.queue, &packet_list);
-
- if (list_empty(&lynx->async.pcl_queue)) {
- spin_unlock_irqrestore(&lynx->async.queue_lock, flags);
- PRINTD(KERN_DEBUG, lynx->id, "no async packet in PCL to cancel");
- } else {
- struct ti_pcl pcl;
- u32 ack;
-
- PRINT(KERN_INFO, lynx->id, "cancelling async packet, that was already in PCL");
-
- get_pcl(lynx, lynx->async.pcl, &pcl);
-
- packet = driver_packet(lynx->async.pcl_queue.next);
- list_del_init(&packet->driver_list);
-
- pci_unmap_single(lynx->dev, lynx->async.header_dma,
- packet->header_size, PCI_DMA_TODEVICE);
- if (packet->data_size) {
- pci_unmap_single(lynx->dev, lynx->async.data_dma,
- packet->data_size, PCI_DMA_TODEVICE);
- }
-
- spin_unlock_irqrestore(&lynx->async.queue_lock, flags);
-
- if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
- if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
- ack = (pcl.pcl_status >> 15) & 0xf;
- PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
- ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
- } else {
- ack = (pcl.pcl_status >> 15) & 0xf;
- }
- } else {
- PRINT(KERN_INFO, lynx->id, "async packet was not completed");
- ack = ACKX_ABORTED;
- }
- hpsb_packet_sent(host, packet, ack);
- }
-
- while (!list_empty(&packet_list)) {
- packet = driver_packet(packet_list.next);
- list_del_init(&packet->driver_list);
- hpsb_packet_sent(host, packet, ACKX_ABORTED);
- }
-
- break;
-#if 0 /* has been removed from ieee1394 core */
- case ISO_LISTEN_CHANNEL:
- spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
-
- if (lynx->iso_rcv.chan_count++ == 0) {
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),
- DMA_WORD1_CMP_ENABLE_MASTER);
- }
-
- spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
- break;
-
- case ISO_UNLISTEN_CHANNEL:
- spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
-
- if (--lynx->iso_rcv.chan_count == 0) {
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),
- 0);
- }
-
- spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
- break;
-#endif
- default:
- PRINT(KERN_ERR, lynx->id, "unknown devctl command %d", cmd);
- retval = -1;
- }
-
- return retval;
-}
-
-
-/***************************************
- * IEEE-1394 functionality section END *
- ***************************************/
-
-
-/********************************************************
- * Global stuff (interrupt handler, init/shutdown code) *
- ********************************************************/
-
-
-static irqreturn_t lynx_irq_handler(int irq, void *dev_id)
-{
- struct ti_lynx *lynx = (struct ti_lynx *)dev_id;
- struct hpsb_host *host = lynx->host;
- u32 intmask;
- u32 linkint;
-
- linkint = reg_read(lynx, LINK_INT_STATUS);
- intmask = reg_read(lynx, PCI_INT_STATUS);
-
- if (!(intmask & PCI_INT_INT_PEND))
- return IRQ_NONE;
-
- PRINTD(KERN_DEBUG, lynx->id, "interrupt: 0x%08x / 0x%08x", intmask,
- linkint);
-
- reg_write(lynx, LINK_INT_STATUS, linkint);
- reg_write(lynx, PCI_INT_STATUS, intmask);
-
- if (intmask & PCI_INT_1394) {
- if (linkint & LINK_INT_PHY_TIMEOUT) {
- PRINT(KERN_INFO, lynx->id, "PHY timeout occurred");
- }
- if (linkint & LINK_INT_PHY_BUSRESET) {
- PRINT(KERN_INFO, lynx->id, "bus reset interrupt");
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
- if (!host->in_bus_reset)
- hpsb_bus_reset(host);
- }
- if (linkint & LINK_INT_PHY_REG_RCVD) {
- u32 reg;
-
- spin_lock(&lynx->phy_reg_lock);
- reg = reg_read(lynx, LINK_PHY);
- spin_unlock(&lynx->phy_reg_lock);
-
- if (!host->in_bus_reset) {
- PRINT(KERN_INFO, lynx->id,
- "phy reg received without reset");
- } else if (reg & 0xf00) {
- PRINT(KERN_INFO, lynx->id,
- "unsolicited phy reg %d received",
- (reg >> 8) & 0xf);
- } else {
- lynx->phy_reg0 = reg & 0xff;
- handle_selfid(lynx, host);
- }
- }
- if (linkint & LINK_INT_ISO_STUCK) {
- PRINT(KERN_INFO, lynx->id, "isochronous transmitter stuck");
- }
- if (linkint & LINK_INT_ASYNC_STUCK) {
- PRINT(KERN_INFO, lynx->id, "asynchronous transmitter stuck");
- }
- if (linkint & LINK_INT_SENT_REJECT) {
- PRINT(KERN_INFO, lynx->id, "sent reject");
- }
- if (linkint & LINK_INT_TX_INVALID_TC) {
- PRINT(KERN_INFO, lynx->id, "invalid transaction code");
- }
- if (linkint & LINK_INT_GRF_OVERFLOW) {
- /* flush FIFO if overflow happens during reset */
- if (host->in_bus_reset)
- reg_write(lynx, FIFO_CONTROL,
- FIFO_CONTROL_GRF_FLUSH);
- PRINT(KERN_INFO, lynx->id, "GRF overflow");
- }
- if (linkint & LINK_INT_ITF_UNDERFLOW) {
- PRINT(KERN_INFO, lynx->id, "ITF underflow");
- }
- if (linkint & LINK_INT_ATF_UNDERFLOW) {
- PRINT(KERN_INFO, lynx->id, "ATF underflow");
- }
- }
-
- if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_RCV)) {
- PRINTD(KERN_DEBUG, lynx->id, "iso receive");
-
- spin_lock(&lynx->iso_rcv.lock);
-
- lynx->iso_rcv.stat[lynx->iso_rcv.next] =
- reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ISO_RCV));
-
- lynx->iso_rcv.used++;
- lynx->iso_rcv.next = (lynx->iso_rcv.next + 1) % NUM_ISORCV_PCL;
-
- if ((lynx->iso_rcv.next == lynx->iso_rcv.last)
- || !lynx->iso_rcv.chan_count) {
- PRINTD(KERN_DEBUG, lynx->id, "stopped");
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
- }
-
- run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, lynx->iso_rcv.next,
- CHANNEL_ISO_RCV);
-
- spin_unlock(&lynx->iso_rcv.lock);
-
- tasklet_schedule(&lynx->iso_rcv.tq);
- }
-
- if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_SEND)) {
- PRINTD(KERN_DEBUG, lynx->id, "async sent");
- spin_lock(&lynx->async.queue_lock);
-
- if (list_empty(&lynx->async.pcl_queue)) {
- spin_unlock(&lynx->async.queue_lock);
- PRINT(KERN_WARNING, lynx->id, "async dma halted, but no queued packet (maybe it was cancelled)");
- } else {
- struct ti_pcl pcl;
- u32 ack;
- struct hpsb_packet *packet;
-
- get_pcl(lynx, lynx->async.pcl, &pcl);
-
- packet = driver_packet(lynx->async.pcl_queue.next);
- list_del_init(&packet->driver_list);
-
- pci_unmap_single(lynx->dev, lynx->async.header_dma,
- packet->header_size, PCI_DMA_TODEVICE);
- if (packet->data_size) {
- pci_unmap_single(lynx->dev, lynx->async.data_dma,
- packet->data_size, PCI_DMA_TODEVICE);
- }
-
- if (!list_empty(&lynx->async.queue)) {
- send_next(lynx, hpsb_async);
- }
-
- spin_unlock(&lynx->async.queue_lock);
-
- if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
- if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
- ack = (pcl.pcl_status >> 15) & 0xf;
- PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
- ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
- } else {
- ack = (pcl.pcl_status >> 15) & 0xf;
- }
- } else {
- PRINT(KERN_INFO, lynx->id, "async packet was not completed");
- ack = ACKX_SEND_ERROR;
- }
- hpsb_packet_sent(host, packet, ack);
- }
- }
-
- if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_SEND)) {
- PRINTD(KERN_DEBUG, lynx->id, "iso sent");
- spin_lock(&lynx->iso_send.queue_lock);
-
- if (list_empty(&lynx->iso_send.pcl_queue)) {
- spin_unlock(&lynx->iso_send.queue_lock);
- PRINT(KERN_ERR, lynx->id, "iso send dma halted, but no queued packet");
- } else {
- struct ti_pcl pcl;
- u32 ack;
- struct hpsb_packet *packet;
-
- get_pcl(lynx, lynx->iso_send.pcl, &pcl);
-
- packet = driver_packet(lynx->iso_send.pcl_queue.next);
- list_del_init(&packet->driver_list);
-
- pci_unmap_single(lynx->dev, lynx->iso_send.header_dma,
- packet->header_size, PCI_DMA_TODEVICE);
- if (packet->data_size) {
- pci_unmap_single(lynx->dev, lynx->iso_send.data_dma,
- packet->data_size, PCI_DMA_TODEVICE);
- }
-#if 0 /* has been removed from ieee1394 core */
- if (!list_empty(&lynx->iso_send.queue)) {
- send_next(lynx, hpsb_iso);
- }
-#endif
- spin_unlock(&lynx->iso_send.queue_lock);
-
- if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
- if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
- ack = (pcl.pcl_status >> 15) & 0xf;
- PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
- ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
- } else {
- ack = (pcl.pcl_status >> 15) & 0xf;
- }
- } else {
- PRINT(KERN_INFO, lynx->id, "iso send packet was not completed");
- ack = ACKX_SEND_ERROR;
- }
-
- hpsb_packet_sent(host, packet, ack); //FIXME: maybe we should just use ACK_COMPLETE and ACKX_SEND_ERROR
- }
- }
-
- if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_RCV)) {
- /* general receive DMA completed */
- int stat = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_RCV));
-
- PRINTD(KERN_DEBUG, lynx->id, "received packet size %d",
- stat & 0x1fff);
-
- if (stat & DMA_CHAN_STAT_SELFID) {
- lynx->selfid_size = stat & 0x1fff;
- handle_selfid(lynx, host);
- } else {
- quadlet_t *q_data = lynx->rcv_page;
- if ((*q_data >> 4 & 0xf) == TCODE_READQ_RESPONSE
- || (*q_data >> 4 & 0xf) == TCODE_WRITEQ) {
- cpu_to_be32s(q_data + 3);
- }
- hpsb_packet_received(host, q_data, stat & 0x1fff, 0);
- }
-
- run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
- }
-
- return IRQ_HANDLED;
-}
-
-
-static void iso_rcv_bh(struct ti_lynx *lynx)
-{
- unsigned int idx;
- quadlet_t *data;
- unsigned long flags;
-
- spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
-
- while (lynx->iso_rcv.used) {
- idx = lynx->iso_rcv.last;
- spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
-
- data = lynx->iso_rcv.page[idx / ISORCV_PER_PAGE]
- + (idx % ISORCV_PER_PAGE) * MAX_ISORCV_SIZE;
-
- if ((*data >> 16) + 4 != (lynx->iso_rcv.stat[idx] & 0x1fff)) {
- PRINT(KERN_ERR, lynx->id,
- "iso length mismatch 0x%08x/0x%08x", *data,
- lynx->iso_rcv.stat[idx]);
- }
-
- if (lynx->iso_rcv.stat[idx]
- & (DMA_CHAN_STAT_PCIERR | DMA_CHAN_STAT_PKTERR)) {
- PRINT(KERN_INFO, lynx->id,
- "iso receive error on %d to 0x%p", idx, data);
- } else {
- hpsb_packet_received(lynx->host, data,
- lynx->iso_rcv.stat[idx] & 0x1fff,
- 0);
- }
-
- spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
- lynx->iso_rcv.last = (idx + 1) % NUM_ISORCV_PCL;
- lynx->iso_rcv.used--;
- }
-
- if (lynx->iso_rcv.chan_count) {
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),
- DMA_WORD1_CMP_ENABLE_MASTER);
- }
- spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
-}
-
-
-static void remove_card(struct pci_dev *dev)
-{
- struct ti_lynx *lynx;
- struct device *lynx_dev;
- int i;
-
- lynx = pci_get_drvdata(dev);
- if (!lynx) return;
- pci_set_drvdata(dev, NULL);
-
- lynx_dev = get_device(&lynx->host->device);
-
- switch (lynx->state) {
- case is_host:
- reg_write(lynx, PCI_INT_ENABLE, 0);
- hpsb_remove_host(lynx->host);
- case have_intr:
- reg_write(lynx, PCI_INT_ENABLE, 0);
- free_irq(lynx->dev->irq, lynx);
-
- /* Disable IRM Contender and LCtrl */
- if (lynx->phyic.reg_1394a)
- set_phy_reg(lynx, 4, ~0xc0 & get_phy_reg(lynx, 4));
-
- /* Let all other nodes know to ignore us */
- lynx_devctl(lynx->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT);
-
- case have_iomappings:
- reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
- /* Fix buggy cards with autoboot pin not tied low: */
- reg_write(lynx, DMA0_CHAN_CTRL, 0);
- iounmap(lynx->registers);
- iounmap(lynx->local_rom);
- iounmap(lynx->local_ram);
- iounmap(lynx->aux_port);
- case have_1394_buffers:
- for (i = 0; i < ISORCV_PAGES; i++) {
- if (lynx->iso_rcv.page[i]) {
- pci_free_consistent(lynx->dev, PAGE_SIZE,
- lynx->iso_rcv.page[i],
- lynx->iso_rcv.page_dma[i]);
- }
- }
- pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,
- lynx->rcv_page_dma);
- case have_aux_buf:
- case have_pcl_mem:
- pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,
- lynx->pcl_mem_dma);
- case clear:
- /* do nothing - already freed */
- ;
- }
-
- tasklet_kill(&lynx->iso_rcv.tq);
-
- if (lynx_dev)
- put_device(lynx_dev);
-}
-
-
-static int __devinit add_card(struct pci_dev *dev,
- const struct pci_device_id *devid_is_unused)
-{
-#define FAIL(fmt, args...) do { \
- PRINT_G(KERN_ERR, fmt , ## args); \
- remove_card(dev); \
- return error; \
- } while (0)
-
- char irq_buf[16];
- struct hpsb_host *host;
- struct ti_lynx *lynx; /* shortcut to currently handled device */
- struct ti_pcl pcl;
- u32 *pcli;
- int i;
- int error;
-
- error = -ENXIO;
-
- if (pci_set_dma_mask(dev, DMA_BIT_MASK(32)))
- FAIL("DMA address limits not supported for PCILynx hardware");
- if (pci_enable_device(dev))
- FAIL("failed to enable PCILynx hardware");
- pci_set_master(dev);
-
- error = -ENOMEM;
-
- host = hpsb_alloc_host(&lynx_driver, sizeof(struct ti_lynx), &dev->dev);
- if (!host) FAIL("failed to allocate control structure memory");
-
- lynx = host->hostdata;
- lynx->id = card_id++;
- lynx->dev = dev;
- lynx->state = clear;
- lynx->host = host;
- host->pdev = dev;
- pci_set_drvdata(dev, lynx);
-
- spin_lock_init(&lynx->lock);
- spin_lock_init(&lynx->phy_reg_lock);
-
- lynx->pcl_mem = pci_alloc_consistent(dev, LOCALRAM_SIZE,
- &lynx->pcl_mem_dma);
-
- if (lynx->pcl_mem != NULL) {
- lynx->state = have_pcl_mem;
- PRINT(KERN_INFO, lynx->id,
- "allocated PCL memory %d Bytes @ 0x%p", LOCALRAM_SIZE,
- lynx->pcl_mem);
- } else {
- FAIL("failed to allocate PCL memory area");
- }
-
- lynx->rcv_page = pci_alloc_consistent(dev, PAGE_SIZE,
- &lynx->rcv_page_dma);
- if (lynx->rcv_page == NULL) {
- FAIL("failed to allocate receive buffer");
- }
- lynx->state = have_1394_buffers;
-
- for (i = 0; i < ISORCV_PAGES; i++) {
- lynx->iso_rcv.page[i] =
- pci_alloc_consistent(dev, PAGE_SIZE,
- &lynx->iso_rcv.page_dma[i]);
- if (lynx->iso_rcv.page[i] == NULL) {
- FAIL("failed to allocate iso receive buffers");
- }
- }
-
- lynx->registers = ioremap_nocache(pci_resource_start(dev,0),
- PCILYNX_MAX_REGISTER);
- lynx->local_ram = ioremap(pci_resource_start(dev,1), PCILYNX_MAX_MEMORY);
- lynx->aux_port = ioremap(pci_resource_start(dev,2), PCILYNX_MAX_MEMORY);
- lynx->local_rom = ioremap(pci_resource_start(dev,PCI_ROM_RESOURCE),
- PCILYNX_MAX_MEMORY);
- lynx->state = have_iomappings;
-
- if (lynx->registers == NULL) {
- FAIL("failed to remap registers - card not accessible");
- }
-
- reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
- /* Fix buggy cards with autoboot pin not tied low: */
- reg_write(lynx, DMA0_CHAN_CTRL, 0);
-
- sprintf (irq_buf, "%d", dev->irq);
-
- if (!request_irq(dev->irq, lynx_irq_handler, IRQF_SHARED,
- PCILYNX_DRIVER_NAME, lynx)) {
- PRINT(KERN_INFO, lynx->id, "allocated interrupt %s", irq_buf);
- lynx->state = have_intr;
- } else {
- FAIL("failed to allocate shared interrupt %s", irq_buf);
- }
-
- /* alloc_pcl return values are not checked, it is expected that the
- * provided PCL space is sufficient for the initial allocations */
- lynx->rcv_pcl = alloc_pcl(lynx);
- lynx->rcv_pcl_start = alloc_pcl(lynx);
- lynx->async.pcl = alloc_pcl(lynx);
- lynx->async.pcl_start = alloc_pcl(lynx);
- lynx->iso_send.pcl = alloc_pcl(lynx);
- lynx->iso_send.pcl_start = alloc_pcl(lynx);
-
- for (i = 0; i < NUM_ISORCV_PCL; i++) {
- lynx->iso_rcv.pcl[i] = alloc_pcl(lynx);
- }
- lynx->iso_rcv.pcl_start = alloc_pcl(lynx);
-
- /* all allocations successful - simple init stuff follows */
-
- reg_write(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL);
-
- tasklet_init(&lynx->iso_rcv.tq, (void (*)(unsigned long))iso_rcv_bh,
- (unsigned long)lynx);
-
- spin_lock_init(&lynx->iso_rcv.lock);
-
- spin_lock_init(&lynx->async.queue_lock);
- lynx->async.channel = CHANNEL_ASYNC_SEND;
- spin_lock_init(&lynx->iso_send.queue_lock);
- lynx->iso_send.channel = CHANNEL_ISO_SEND;
-
- PRINT(KERN_INFO, lynx->id, "remapped memory spaces reg 0x%p, rom 0x%p, "
- "ram 0x%p, aux 0x%p", lynx->registers, lynx->local_rom,
- lynx->local_ram, lynx->aux_port);
-
- /* now, looking for PHY register set */
- if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) {
- lynx->phyic.reg_1394a = 1;
- PRINT(KERN_INFO, lynx->id,
- "found 1394a conform PHY (using extended register set)");
- lynx->phyic.vendor = get_phy_vendorid(lynx);
- lynx->phyic.product = get_phy_productid(lynx);
- } else {
- lynx->phyic.reg_1394a = 0;
- PRINT(KERN_INFO, lynx->id, "found old 1394 PHY");
- }
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
-
- INIT_LIST_HEAD(&lynx->async.queue);
- INIT_LIST_HEAD(&lynx->async.pcl_queue);
- INIT_LIST_HEAD(&lynx->iso_send.queue);
- INIT_LIST_HEAD(&lynx->iso_send.pcl_queue);
-
- pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
- put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
-
- pcl.next = PCL_NEXT_INVALID;
- pcl.async_error_next = PCL_NEXT_INVALID;
-
- pcl.buffer[0].control = PCL_CMD_RCV | 16;
-#ifndef __BIG_ENDIAN
- pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
- pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
-
- pcl.buffer[0].pointer = lynx->rcv_page_dma;
- pcl.buffer[1].pointer = lynx->rcv_page_dma + 16;
- put_pcl(lynx, lynx->rcv_pcl, &pcl);
-
- pcl.next = pcl_bus(lynx, lynx->async.pcl);
- pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl);
- put_pcl(lynx, lynx->async.pcl_start, &pcl);
-
- pcl.next = pcl_bus(lynx, lynx->iso_send.pcl);
- pcl.async_error_next = PCL_NEXT_INVALID;
- put_pcl(lynx, lynx->iso_send.pcl_start, &pcl);
-
- pcl.next = PCL_NEXT_INVALID;
- pcl.async_error_next = PCL_NEXT_INVALID;
- pcl.buffer[0].control = PCL_CMD_RCV | 4;
-#ifndef __BIG_ENDIAN
- pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
- pcl.buffer[1].control = PCL_LAST_BUFF | 2044;
-
- for (i = 0; i < NUM_ISORCV_PCL; i++) {
- int page = i / ISORCV_PER_PAGE;
- int sec = i % ISORCV_PER_PAGE;
-
- pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page]
- + sec * MAX_ISORCV_SIZE;
- pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
- put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
- }
-
- pcli = (u32 *)&pcl;
- for (i = 0; i < NUM_ISORCV_PCL; i++) {
- pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]);
- }
- put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl);
-
- /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */
- reg_write(lynx, FIFO_SIZES, 0x003030a0);
- /* 20 byte threshold before triggering PCI transfer */
- reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24);
- /* threshold on both send FIFOs before transmitting:
- FIFO size - cache line size - 1 */
- i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff;
- i = 0x30 - i - 1;
- reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i);
-
- reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394);
-
- reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT
- | LINK_INT_PHY_REG_RCVD | LINK_INT_PHY_BUSRESET
- | LINK_INT_ISO_STUCK | LINK_INT_ASYNC_STUCK
- | LINK_INT_SENT_REJECT | LINK_INT_TX_INVALID_TC
- | LINK_INT_GRF_OVERFLOW | LINK_INT_ITF_UNDERFLOW
- | LINK_INT_ATF_UNDERFLOW);
-
- reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
- reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4);
- reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV),
- DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST
- | DMA_WORD1_CMP_MATCH_EXACT | DMA_WORD1_CMP_MATCH_BUS_BCAST
- | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER);
-
- run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
-
- reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0);
- reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4);
- reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0);
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
-
- run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV);
-
- reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID
- | LINK_CONTROL_TX_ISO_EN | LINK_CONTROL_RX_ISO_EN
- | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN
- | LINK_CONTROL_RESET_TX | LINK_CONTROL_RESET_RX);
-
- if (!lynx->phyic.reg_1394a) {
- if (!hpsb_disable_irm) {
- /* attempt to enable contender bit -FIXME- would this
- * work elsewhere? */
- reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
- reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1);
- }
- } else {
- /* set the contender (if appropriate) and LCtrl bit in the
- * extended PHY register set. (Should check that PHY_02_EXTENDED
- * is set in register 2?)
- */
- i = get_phy_reg(lynx, 4);
- i |= PHY_04_LCTRL;
- if (hpsb_disable_irm)
- i &= ~PHY_04_CONTENDER;
- else
- i |= PHY_04_CONTENDER;
- if (i != -1) set_phy_reg(lynx, 4, i);
- }
-
- if (!skip_eeprom)
- {
- /* needed for i2c communication with serial eeprom */
- struct i2c_adapter *i2c_ad;
- struct i2c_algo_bit_data i2c_adapter_data;
-
- error = -ENOMEM;
- i2c_ad = kzalloc(sizeof(*i2c_ad), GFP_KERNEL);
- if (!i2c_ad) FAIL("failed to allocate I2C adapter memory");
-
- strlcpy(i2c_ad->name, "PCILynx I2C", sizeof(i2c_ad->name));
- i2c_adapter_data = bit_data;
- i2c_ad->algo_data = &i2c_adapter_data;
- i2c_adapter_data.data = lynx;
- i2c_ad->dev.parent = &dev->dev;
-
- PRINTD(KERN_DEBUG, lynx->id,"original eeprom control: %d",
- reg_read(lynx, SERIAL_EEPROM_CONTROL));
-
- /* reset hardware to sane state */
- lynx->i2c_driven_state = 0x00000070;
- reg_write(lynx, SERIAL_EEPROM_CONTROL, lynx->i2c_driven_state);
-
- if (i2c_bit_add_bus(i2c_ad) < 0)
- {
- kfree(i2c_ad);
- error = -ENXIO;
- FAIL("unable to register i2c");
- }
- else
- {
- /* do i2c stuff */
- unsigned char i2c_cmd = 0x10;
- struct i2c_msg msg[2] = { { 0x50, 0, 1, &i2c_cmd },
- { 0x50, I2C_M_RD, 20, (unsigned char*) lynx->bus_info_block }
- };
-
- /* we use i2c_transfer because we have no i2c_client
- at hand */
- if (i2c_transfer(i2c_ad, msg, 2) < 0) {
- PRINT(KERN_ERR, lynx->id, "unable to read bus info block from i2c");
- } else {
- PRINT(KERN_INFO, lynx->id, "got bus info block from serial eeprom");
- /* FIXME: probably we should rewrite the max_rec, max_ROM(1394a),
- * generation(1394a) and link_spd(1394a) field and recalculate
- * the CRC */
-
- for (i = 0; i < 5 ; i++)
- PRINTD(KERN_DEBUG, lynx->id, "Businfo block quadlet %i: %08x",
- i, be32_to_cpu(lynx->bus_info_block[i]));
-
- /* info_length, crc_length and 1394 magic number to check, if it is really a bus info block */
- if (((be32_to_cpu(lynx->bus_info_block[0]) & 0xffff0000) == 0x04040000) &&
- (lynx->bus_info_block[1] == IEEE1394_BUSID_MAGIC))
- {
- PRINT(KERN_DEBUG, lynx->id, "read a valid bus info block from");
- } else {
- kfree(i2c_ad);
- error = -ENXIO;
- FAIL("read something from serial eeprom, but it does not seem to be a valid bus info block");
- }
-
- }
-
- i2c_del_adapter(i2c_ad);
- kfree(i2c_ad);
- }
- }
-
- host->csr.guid_hi = be32_to_cpu(lynx->bus_info_block[3]);
- host->csr.guid_lo = be32_to_cpu(lynx->bus_info_block[4]);
- host->csr.cyc_clk_acc = (be32_to_cpu(lynx->bus_info_block[2]) >> 16) & 0xff;
- host->csr.max_rec = (be32_to_cpu(lynx->bus_info_block[2]) >> 12) & 0xf;
- if (!lynx->phyic.reg_1394a)
- host->csr.lnk_spd = (get_phy_reg(lynx, 2) & 0xc0) >> 6;
- else
- host->csr.lnk_spd = be32_to_cpu(lynx->bus_info_block[2]) & 0x7;
-
- if (hpsb_add_host(host)) {
- error = -ENOMEM;
- FAIL("Failed to register host with highlevel");
- }
-
- lynx->state = is_host;
-
- return 0;
-#undef FAIL
-}
-
-
-static struct pci_device_id pci_table[] = {
- {
- .vendor = PCI_VENDOR_ID_TI,
- .device = PCI_DEVICE_ID_TI_PCILYNX,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { } /* Terminating entry */
-};
-
-static struct pci_driver lynx_pci_driver = {
- .name = PCILYNX_DRIVER_NAME,
- .id_table = pci_table,
- .probe = add_card,
- .remove = remove_card,
-};
-
-static struct hpsb_host_driver lynx_driver = {
- .owner = THIS_MODULE,
- .name = PCILYNX_DRIVER_NAME,
- .set_hw_config_rom = NULL,
- .transmit_packet = lynx_transmit,
- .devctl = lynx_devctl,
- .isoctl = NULL,
-};
-
-MODULE_AUTHOR("Andreas E. Bombe <andreas.bombe@munich.netsurf.de>");
-MODULE_DESCRIPTION("driver for Texas Instruments PCI Lynx IEEE-1394 controller");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("pcilynx");
-MODULE_DEVICE_TABLE(pci, pci_table);
-
-static int __init pcilynx_init(void)
-{
- int ret;
-
- ret = pci_register_driver(&lynx_pci_driver);
- if (ret < 0) {
- PRINT_G(KERN_ERR, "PCI module init failed");
- return ret;
- }
-
- return 0;
-}
-
-static void __exit pcilynx_cleanup(void)
-{
- pci_unregister_driver(&lynx_pci_driver);
-}
-
-
-module_init(pcilynx_init);
-module_exit(pcilynx_cleanup);
diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h
deleted file mode 100644
index 693a169acea3..000000000000
--- a/drivers/ieee1394/pcilynx.h
+++ /dev/null
@@ -1,468 +0,0 @@
-#ifndef __PCILYNX_H__
-#define __PCILYNX_H__
-
-
-#define PCILYNX_DRIVER_NAME "pcilynx"
-#define PCILYNX_MAJOR 177
-
-#define PCILYNX_MINOR_AUX_START 0
-#define PCILYNX_MINOR_ROM_START 16
-#define PCILYNX_MINOR_RAM_START 32
-
-#define PCILYNX_MAX_REGISTER 0xfff
-#define PCILYNX_MAX_MEMORY 0xffff
-
-#define PCI_DEVICE_ID_TI_PCILYNX 0x8000
-#define MAX_PCILYNX_CARDS 4
-#define LOCALRAM_SIZE 4096
-
-#define NUM_ISORCV_PCL 4
-#define MAX_ISORCV_SIZE 2048
-#define ISORCV_PER_PAGE (PAGE_SIZE / MAX_ISORCV_SIZE)
-#define ISORCV_PAGES (NUM_ISORCV_PCL / ISORCV_PER_PAGE)
-
-#define CHANNEL_LOCALBUS 0
-#define CHANNEL_ASYNC_RCV 1
-#define CHANNEL_ISO_RCV 2
-#define CHANNEL_ASYNC_SEND 3
-#define CHANNEL_ISO_SEND 4
-
-#define PCILYNX_CONFIG_ROM_LENGTH 1024
-
-typedef int pcl_t;
-
-struct ti_lynx {
- int id; /* sequential card number */
-
- spinlock_t lock;
-
- struct pci_dev *dev;
-
- struct {
- unsigned reg_1394a:1;
- u32 vendor;
- u32 product;
- } phyic;
-
- enum { clear, have_intr, have_aux_buf, have_pcl_mem,
- have_1394_buffers, have_iomappings, is_host } state;
-
- /* remapped memory spaces */
- void __iomem *registers;
- void __iomem *local_rom;
- void __iomem *local_ram;
- void __iomem *aux_port;
- __be32 bus_info_block[5];
-
- /*
- * use local RAM of LOCALRAM_SIZE bytes for PCLs, which allows for
- * LOCALRAM_SIZE * 8 PCLs (each sized 128 bytes);
- * the following is an allocation bitmap
- */
- u8 pcl_bmap[LOCALRAM_SIZE / 1024];
-
- /* point to PCLs memory area if needed */
- void *pcl_mem;
- dma_addr_t pcl_mem_dma;
-
- /* PCLs for local mem / aux transfers */
- pcl_t dmem_pcl;
-
- /* IEEE-1394 part follows */
- struct hpsb_host *host;
-
- int phyid, isroot;
- int selfid_size;
- int phy_reg0;
-
- spinlock_t phy_reg_lock;
-
- pcl_t rcv_pcl_start, rcv_pcl;
- void *rcv_page;
- dma_addr_t rcv_page_dma;
- int rcv_active;
-
- struct lynx_send_data {
- pcl_t pcl_start, pcl;
- struct list_head queue;
- struct list_head pcl_queue; /* this queue contains at most one packet */
- spinlock_t queue_lock;
- dma_addr_t header_dma, data_dma;
- int channel;
- } async, iso_send;
-
- struct {
- pcl_t pcl[NUM_ISORCV_PCL];
- u32 stat[NUM_ISORCV_PCL];
- void *page[ISORCV_PAGES];
- dma_addr_t page_dma[ISORCV_PAGES];
- pcl_t pcl_start;
- int chan_count;
- int next, last, used, running;
- struct tasklet_struct tq;
- spinlock_t lock;
- } iso_rcv;
-
- u32 i2c_driven_state; /* the state we currently drive the Serial EEPROM Control register */
-};
-
-/* the per-file data structure for mem space access */
-struct memdata {
- struct ti_lynx *lynx;
- int cid;
- atomic_t aux_intr_last_seen;
- /* enum values are the same as LBUS_ADDR_SEL_* values below */
- enum { rom = 0x10000, aux = 0x20000, ram = 0 } type;
-};
-
-
-
-/*
- * Register read and write helper functions.
- */
-static inline void reg_write(const struct ti_lynx *lynx, int offset, u32 data)
-{
- writel(data, lynx->registers + offset);
-}
-
-static inline u32 reg_read(const struct ti_lynx *lynx, int offset)
-{
- return readl(lynx->registers + offset);
-}
-
-static inline void reg_set_bits(const struct ti_lynx *lynx, int offset,
- u32 mask)
-{
- reg_write(lynx, offset, (reg_read(lynx, offset) | mask));
-}
-
-static inline void reg_clear_bits(const struct ti_lynx *lynx, int offset,
- u32 mask)
-{
- reg_write(lynx, offset, (reg_read(lynx, offset) & ~mask));
-}
-
-
-
-/* chip register definitions follow */
-
-#define PCI_LATENCY_CACHELINE 0x0c
-
-#define MISC_CONTROL 0x40
-#define MISC_CONTROL_SWRESET (1<<0)
-
-#define SERIAL_EEPROM_CONTROL 0x44
-
-#define PCI_INT_STATUS 0x48
-#define PCI_INT_ENABLE 0x4c
-/* status and enable have identical bit numbers */
-#define PCI_INT_INT_PEND (1<<31)
-#define PCI_INT_FORCED_INT (1<<30)
-#define PCI_INT_SLV_ADR_PERR (1<<28)
-#define PCI_INT_SLV_DAT_PERR (1<<27)
-#define PCI_INT_MST_DAT_PERR (1<<26)
-#define PCI_INT_MST_DEV_TIMEOUT (1<<25)
-#define PCI_INT_INTERNAL_SLV_TIMEOUT (1<<23)
-#define PCI_INT_AUX_TIMEOUT (1<<18)
-#define PCI_INT_AUX_INT (1<<17)
-#define PCI_INT_1394 (1<<16)
-#define PCI_INT_DMA4_PCL (1<<9)
-#define PCI_INT_DMA4_HLT (1<<8)
-#define PCI_INT_DMA3_PCL (1<<7)
-#define PCI_INT_DMA3_HLT (1<<6)
-#define PCI_INT_DMA2_PCL (1<<5)
-#define PCI_INT_DMA2_HLT (1<<4)
-#define PCI_INT_DMA1_PCL (1<<3)
-#define PCI_INT_DMA1_HLT (1<<2)
-#define PCI_INT_DMA0_PCL (1<<1)
-#define PCI_INT_DMA0_HLT (1<<0)
-/* all DMA interrupts combined: */
-#define PCI_INT_DMA_ALL 0x3ff
-
-#define PCI_INT_DMA_HLT(chan) (1 << (chan * 2))
-#define PCI_INT_DMA_PCL(chan) (1 << (chan * 2 + 1))
-
-#define LBUS_ADDR 0xb4
-#define LBUS_ADDR_SEL_RAM (0x0<<16)
-#define LBUS_ADDR_SEL_ROM (0x1<<16)
-#define LBUS_ADDR_SEL_AUX (0x2<<16)
-#define LBUS_ADDR_SEL_ZV (0x3<<16)
-
-#define GPIO_CTRL_A 0xb8
-#define GPIO_CTRL_B 0xbc
-#define GPIO_DATA_BASE 0xc0
-
-#define DMA_BREG(base, chan) (base + chan * 0x20)
-#define DMA_SREG(base, chan) (base + chan * 0x10)
-
-#define DMA0_PREV_PCL 0x100
-#define DMA1_PREV_PCL 0x120
-#define DMA2_PREV_PCL 0x140
-#define DMA3_PREV_PCL 0x160
-#define DMA4_PREV_PCL 0x180
-#define DMA_PREV_PCL(chan) (DMA_BREG(DMA0_PREV_PCL, chan))
-
-#define DMA0_CURRENT_PCL 0x104
-#define DMA1_CURRENT_PCL 0x124
-#define DMA2_CURRENT_PCL 0x144
-#define DMA3_CURRENT_PCL 0x164
-#define DMA4_CURRENT_PCL 0x184
-#define DMA_CURRENT_PCL(chan) (DMA_BREG(DMA0_CURRENT_PCL, chan))
-
-#define DMA0_CHAN_STAT 0x10c
-#define DMA1_CHAN_STAT 0x12c
-#define DMA2_CHAN_STAT 0x14c
-#define DMA3_CHAN_STAT 0x16c
-#define DMA4_CHAN_STAT 0x18c
-#define DMA_CHAN_STAT(chan) (DMA_BREG(DMA0_CHAN_STAT, chan))
-/* CHAN_STATUS registers share bits */
-#define DMA_CHAN_STAT_SELFID (1<<31)
-#define DMA_CHAN_STAT_ISOPKT (1<<30)
-#define DMA_CHAN_STAT_PCIERR (1<<29)
-#define DMA_CHAN_STAT_PKTERR (1<<28)
-#define DMA_CHAN_STAT_PKTCMPL (1<<27)
-#define DMA_CHAN_STAT_SPECIALACK (1<<14)
-
-
-#define DMA0_CHAN_CTRL 0x110
-#define DMA1_CHAN_CTRL 0x130
-#define DMA2_CHAN_CTRL 0x150
-#define DMA3_CHAN_CTRL 0x170
-#define DMA4_CHAN_CTRL 0x190
-#define DMA_CHAN_CTRL(chan) (DMA_BREG(DMA0_CHAN_CTRL, chan))
-/* CHAN_CTRL registers share bits */
-#define DMA_CHAN_CTRL_ENABLE (1<<31)
-#define DMA_CHAN_CTRL_BUSY (1<<30)
-#define DMA_CHAN_CTRL_LINK (1<<29)
-
-#define DMA0_READY 0x114
-#define DMA1_READY 0x134
-#define DMA2_READY 0x154
-#define DMA3_READY 0x174
-#define DMA4_READY 0x194
-#define DMA_READY(chan) (DMA_BREG(DMA0_READY, chan))
-
-#define DMA_GLOBAL_REGISTER 0x908
-
-#define FIFO_SIZES 0xa00
-
-#define FIFO_CONTROL 0xa10
-#define FIFO_CONTROL_GRF_FLUSH (1<<4)
-#define FIFO_CONTROL_ITF_FLUSH (1<<3)
-#define FIFO_CONTROL_ATF_FLUSH (1<<2)
-
-#define FIFO_XMIT_THRESHOLD 0xa14
-
-#define DMA0_WORD0_CMP_VALUE 0xb00
-#define DMA1_WORD0_CMP_VALUE 0xb10
-#define DMA2_WORD0_CMP_VALUE 0xb20
-#define DMA3_WORD0_CMP_VALUE 0xb30
-#define DMA4_WORD0_CMP_VALUE 0xb40
-#define DMA_WORD0_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD0_CMP_VALUE, chan))
-
-#define DMA0_WORD0_CMP_ENABLE 0xb04
-#define DMA1_WORD0_CMP_ENABLE 0xb14
-#define DMA2_WORD0_CMP_ENABLE 0xb24
-#define DMA3_WORD0_CMP_ENABLE 0xb34
-#define DMA4_WORD0_CMP_ENABLE 0xb44
-#define DMA_WORD0_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD0_CMP_ENABLE,chan))
-
-#define DMA0_WORD1_CMP_VALUE 0xb08
-#define DMA1_WORD1_CMP_VALUE 0xb18
-#define DMA2_WORD1_CMP_VALUE 0xb28
-#define DMA3_WORD1_CMP_VALUE 0xb38
-#define DMA4_WORD1_CMP_VALUE 0xb48
-#define DMA_WORD1_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD1_CMP_VALUE, chan))
-
-#define DMA0_WORD1_CMP_ENABLE 0xb0c
-#define DMA1_WORD1_CMP_ENABLE 0xb1c
-#define DMA2_WORD1_CMP_ENABLE 0xb2c
-#define DMA3_WORD1_CMP_ENABLE 0xb3c
-#define DMA4_WORD1_CMP_ENABLE 0xb4c
-#define DMA_WORD1_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD1_CMP_ENABLE,chan))
-/* word 1 compare enable flags */
-#define DMA_WORD1_CMP_MATCH_OTHERBUS (1<<15)
-#define DMA_WORD1_CMP_MATCH_BROADCAST (1<<14)
-#define DMA_WORD1_CMP_MATCH_BUS_BCAST (1<<13)
-#define DMA_WORD1_CMP_MATCH_LOCAL_NODE (1<<12)
-#define DMA_WORD1_CMP_MATCH_EXACT (1<<11)
-#define DMA_WORD1_CMP_ENABLE_SELF_ID (1<<10)
-#define DMA_WORD1_CMP_ENABLE_MASTER (1<<8)
-
-#define LINK_ID 0xf00
-#define LINK_ID_BUS(id) (id<<22)
-#define LINK_ID_NODE(id) (id<<16)
-
-#define LINK_CONTROL 0xf04
-#define LINK_CONTROL_BUSY (1<<29)
-#define LINK_CONTROL_TX_ISO_EN (1<<26)
-#define LINK_CONTROL_RX_ISO_EN (1<<25)
-#define LINK_CONTROL_TX_ASYNC_EN (1<<24)
-#define LINK_CONTROL_RX_ASYNC_EN (1<<23)
-#define LINK_CONTROL_RESET_TX (1<<21)
-#define LINK_CONTROL_RESET_RX (1<<20)
-#define LINK_CONTROL_CYCMASTER (1<<11)
-#define LINK_CONTROL_CYCSOURCE (1<<10)
-#define LINK_CONTROL_CYCTIMEREN (1<<9)
-#define LINK_CONTROL_RCV_CMP_VALID (1<<7)
-#define LINK_CONTROL_SNOOP_ENABLE (1<<6)
-
-#define CYCLE_TIMER 0xf08
-
-#define LINK_PHY 0xf0c
-#define LINK_PHY_READ (1<<31)
-#define LINK_PHY_WRITE (1<<30)
-#define LINK_PHY_ADDR(addr) (addr<<24)
-#define LINK_PHY_WDATA(data) (data<<16)
-#define LINK_PHY_RADDR(addr) (addr<<8)
-
-
-#define LINK_INT_STATUS 0xf14
-#define LINK_INT_ENABLE 0xf18
-/* status and enable have identical bit numbers */
-#define LINK_INT_LINK_INT (1<<31)
-#define LINK_INT_PHY_TIMEOUT (1<<30)
-#define LINK_INT_PHY_REG_RCVD (1<<29)
-#define LINK_INT_PHY_BUSRESET (1<<28)
-#define LINK_INT_TX_RDY (1<<26)
-#define LINK_INT_RX_DATA_RDY (1<<25)
-#define LINK_INT_ISO_STUCK (1<<20)
-#define LINK_INT_ASYNC_STUCK (1<<19)
-#define LINK_INT_SENT_REJECT (1<<17)
-#define LINK_INT_HDR_ERR (1<<16)
-#define LINK_INT_TX_INVALID_TC (1<<15)
-#define LINK_INT_CYC_SECOND (1<<11)
-#define LINK_INT_CYC_START (1<<10)
-#define LINK_INT_CYC_DONE (1<<9)
-#define LINK_INT_CYC_PENDING (1<<8)
-#define LINK_INT_CYC_LOST (1<<7)
-#define LINK_INT_CYC_ARB_FAILED (1<<6)
-#define LINK_INT_GRF_OVERFLOW (1<<5)
-#define LINK_INT_ITF_UNDERFLOW (1<<4)
-#define LINK_INT_ATF_UNDERFLOW (1<<3)
-#define LINK_INT_ISOARB_FAILED (1<<0)
-
-/* PHY specifics */
-#define PHY_VENDORID_TI 0x800028
-#define PHY_PRODUCTID_TSB41LV03 0x000000
-
-
-/* this is the physical layout of a PCL, its size is 128 bytes */
-struct ti_pcl {
- u32 next;
- u32 async_error_next;
- u32 user_data;
- u32 pcl_status;
- u32 remaining_transfer_count;
- u32 next_data_buffer;
- struct {
- u32 control;
- u32 pointer;
- } buffer[13] __attribute__ ((packed));
-} __attribute__ ((packed));
-
-#include <linux/stddef.h>
-#define pcloffs(MEMBER) (offsetof(struct ti_pcl, MEMBER))
-
-
-static inline void put_pcl(const struct ti_lynx *lynx, pcl_t pclid,
- const struct ti_pcl *pcl)
-{
- memcpy_le32((u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)),
- (u32 *)pcl, sizeof(struct ti_pcl));
-}
-
-static inline void get_pcl(const struct ti_lynx *lynx, pcl_t pclid,
- struct ti_pcl *pcl)
-{
- memcpy_le32((u32 *)pcl,
- (u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)),
- sizeof(struct ti_pcl));
-}
-
-static inline u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid)
-{
- return lynx->pcl_mem_dma + pclid * sizeof(struct ti_pcl);
-}
-
-
-#if defined (__BIG_ENDIAN)
-typedef struct ti_pcl pcltmp_t;
-
-static inline struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
- pcltmp_t *tmp)
-{
- get_pcl(lynx, pclid, tmp);
- return tmp;
-}
-
-static inline void commit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
- pcltmp_t *tmp)
-{
- put_pcl(lynx, pclid, tmp);
-}
-
-#else
-typedef int pcltmp_t; /* just a dummy */
-
-static inline struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
- pcltmp_t *tmp)
-{
- return lynx->pcl_mem + pclid * sizeof(struct ti_pcl);
-}
-
-static inline void commit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
- pcltmp_t *tmp)
-{
-}
-#endif
-
-
-static inline void run_sub_pcl(const struct ti_lynx *lynx, pcl_t pclid, int idx,
- int dmachan)
-{
- reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20,
- pcl_bus(lynx, pclid) + idx * 4);
- reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20,
- DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK);
-}
-
-static inline void run_pcl(const struct ti_lynx *lynx, pcl_t pclid, int dmachan)
-{
- run_sub_pcl(lynx, pclid, 0, dmachan);
-}
-
-#define PCL_NEXT_INVALID (1<<0)
-
-/* transfer commands */
-#define PCL_CMD_RCV (0x1<<24)
-#define PCL_CMD_RCV_AND_UPDATE (0xa<<24)
-#define PCL_CMD_XMT (0x2<<24)
-#define PCL_CMD_UNFXMT (0xc<<24)
-#define PCL_CMD_PCI_TO_LBUS (0x8<<24)
-#define PCL_CMD_LBUS_TO_PCI (0x9<<24)
-
-/* aux commands */
-#define PCL_CMD_NOP (0x0<<24)
-#define PCL_CMD_LOAD (0x3<<24)
-#define PCL_CMD_STOREQ (0x4<<24)
-#define PCL_CMD_STORED (0xb<<24)
-#define PCL_CMD_STORE0 (0x5<<24)
-#define PCL_CMD_STORE1 (0x6<<24)
-#define PCL_CMD_COMPARE (0xe<<24)
-#define PCL_CMD_SWAP_COMPARE (0xf<<24)
-#define PCL_CMD_ADD (0xd<<24)
-#define PCL_CMD_BRANCH (0x7<<24)
-
-/* BRANCH condition codes */
-#define PCL_COND_DMARDY_SET (0x1<<20)
-#define PCL_COND_DMARDY_CLEAR (0x2<<20)
-
-#define PCL_GEN_INTR (1<<19)
-#define PCL_LAST_BUFF (1<<18)
-#define PCL_LAST_CMD (PCL_LAST_BUFF)
-#define PCL_WAITSTAT (1<<17)
-#define PCL_BIGENDIAN (1<<16)
-#define PCL_ISOMODE (1<<12)
-
-#endif
diff --git a/drivers/ieee1394/raw1394-private.h b/drivers/ieee1394/raw1394-private.h
deleted file mode 100644
index 7a225a405987..000000000000
--- a/drivers/ieee1394/raw1394-private.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef IEEE1394_RAW1394_PRIVATE_H
-#define IEEE1394_RAW1394_PRIVATE_H
-
-/* header for definitions that are private to the raw1394 driver
- and not visible to user-space */
-
-#define RAW1394_DEVICE_MAJOR 171
-#define RAW1394_DEVICE_NAME "raw1394"
-
-#define RAW1394_MAX_USER_CSR_DIRS 16
-
-struct iso_block_store {
- atomic_t refcount;
- size_t data_size;
- quadlet_t data[0];
-};
-
-enum raw1394_iso_state { RAW1394_ISO_INACTIVE = 0,
- RAW1394_ISO_RECV = 1,
- RAW1394_ISO_XMIT = 2 };
-
-struct file_info {
- struct list_head list;
-
- struct mutex state_mutex;
- enum { opened, initialized, connected } state;
- unsigned int protocol_version;
-
- struct hpsb_host *host;
-
- struct list_head req_pending; /* protected by reqlists_lock */
- struct list_head req_complete; /* protected by reqlists_lock */
- spinlock_t reqlists_lock;
- wait_queue_head_t wait_complete;
-
- struct list_head addr_list; /* protected by host_info_lock */
-
- u8 __user *fcp_buffer;
-
- u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */
-
- /* new rawiso API */
- enum raw1394_iso_state iso_state;
- struct hpsb_iso *iso_handle;
-
- /* User space's CSR1212 dynamic ConfigROM directories */
- struct csr1212_keyval *csr1212_dirs[RAW1394_MAX_USER_CSR_DIRS];
-
- /* Legacy ConfigROM update flag */
- u8 cfgrom_upd;
-};
-
-struct arm_addr {
- struct list_head addr_list; /* file_info list */
- u64 start, end;
- u64 arm_tag;
- u8 access_rights;
- u8 notification_options;
- u8 client_transactions;
- u64 recvb;
- u16 rec_length;
- u8 *addr_space_buffer; /* accessed by read/write/lock requests */
-};
-
-struct pending_request {
- struct list_head list;
- struct file_info *file_info;
- struct hpsb_packet *packet;
- struct iso_block_store *ibs;
- quadlet_t *data;
- int free_data;
- struct raw1394_request req;
-};
-
-struct host_info {
- struct list_head list;
- struct hpsb_host *host;
- struct list_head file_info_list; /* protected by host_info_lock */
-};
-
-#endif /* IEEE1394_RAW1394_PRIVATE_H */
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
deleted file mode 100644
index f3401427404c..000000000000
--- a/drivers/ieee1394/raw1394.c
+++ /dev/null
@@ -1,3096 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Raw interface to the bus
- *
- * Copyright (C) 1999, 2000 Andreas E. Bombe
- * 2001, 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
- * 2002 Christian Toegel <christian.toegel@gmx.at>
- *
- * This code is licensed under the GPL. See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- * configuration ROM manipulation
- * address range mapping
- * adaptation for new (transparent) loopback mechanism
- * sending of arbitrary async packets
- * Christian Toegel <christian.toegel@gmx.at>
- * address range mapping
- * lock64 request
- * transmit physical packet
- * busreset notification control (switch on/off)
- * busreset with selection of type (short/long)
- * request_reply
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/vmalloc.h>
-#include <linux/cdev.h>
-#include <asm/uaccess.h>
-#include <asm/atomic.h>
-#include <linux/compat.h>
-
-#include "csr1212.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-#include "iso.h"
-#include "nodemgr.h"
-#include "raw1394.h"
-#include "raw1394-private.h"
-
-#define int2ptr(x) ((void __user *)(unsigned long)x)
-#define ptr2int(x) ((u64)(unsigned long)(void __user *)x)
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define RAW1394_DEBUG
-#endif
-
-#ifdef RAW1394_DEBUG
-#define DBGMSG(fmt, args...) \
-printk(KERN_INFO "raw1394:" fmt "\n" , ## args)
-#else
-#define DBGMSG(fmt, args...) do {} while (0)
-#endif
-
-static LIST_HEAD(host_info_list);
-static int host_count;
-static DEFINE_SPINLOCK(host_info_lock);
-static atomic_t internal_generation = ATOMIC_INIT(0);
-
-static atomic_t iso_buffer_size;
-static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */
-
-static struct hpsb_highlevel raw1394_highlevel;
-
-static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer,
- u64 addr, size_t length, u16 flags);
-static int arm_write(struct hpsb_host *host, int nodeid, int destid,
- quadlet_t * data, u64 addr, size_t length, u16 flags);
-static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store,
- u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
- u16 flags);
-static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store,
- u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
- u16 flags);
-static const struct hpsb_address_ops arm_ops = {
- .read = arm_read,
- .write = arm_write,
- .lock = arm_lock,
- .lock64 = arm_lock64,
-};
-
-static void queue_complete_cb(struct pending_request *req);
-
-static struct pending_request *__alloc_pending_request(gfp_t flags)
-{
- struct pending_request *req;
-
- req = kzalloc(sizeof(*req), flags);
- if (req)
- INIT_LIST_HEAD(&req->list);
-
- return req;
-}
-
-static inline struct pending_request *alloc_pending_request(void)
-{
- return __alloc_pending_request(GFP_KERNEL);
-}
-
-static void free_pending_request(struct pending_request *req)
-{
- if (req->ibs) {
- if (atomic_dec_and_test(&req->ibs->refcount)) {
- atomic_sub(req->ibs->data_size, &iso_buffer_size);
- kfree(req->ibs);
- }
- } else if (req->free_data) {
- kfree(req->data);
- }
- hpsb_free_packet(req->packet);
- kfree(req);
-}
-
-/* fi->reqlists_lock must be taken */
-static void __queue_complete_req(struct pending_request *req)
-{
- struct file_info *fi = req->file_info;
-
- list_move_tail(&req->list, &fi->req_complete);
- wake_up(&fi->wait_complete);
-}
-
-static void queue_complete_req(struct pending_request *req)
-{
- unsigned long flags;
- struct file_info *fi = req->file_info;
-
- spin_lock_irqsave(&fi->reqlists_lock, flags);
- __queue_complete_req(req);
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-}
-
-static void queue_complete_cb(struct pending_request *req)
-{
- struct hpsb_packet *packet = req->packet;
- int rcode = (packet->header[1] >> 12) & 0xf;
-
- switch (packet->ack_code) {
- case ACKX_NONE:
- case ACKX_SEND_ERROR:
- req->req.error = RAW1394_ERROR_SEND_ERROR;
- break;
- case ACKX_ABORTED:
- req->req.error = RAW1394_ERROR_ABORTED;
- break;
- case ACKX_TIMEOUT:
- req->req.error = RAW1394_ERROR_TIMEOUT;
- break;
- default:
- req->req.error = (packet->ack_code << 16) | rcode;
- break;
- }
-
- if (!((packet->ack_code == ACK_PENDING) && (rcode == RCODE_COMPLETE))) {
- req->req.length = 0;
- }
-
- if ((req->req.type == RAW1394_REQ_ASYNC_READ) ||
- (req->req.type == RAW1394_REQ_ASYNC_WRITE) ||
- (req->req.type == RAW1394_REQ_ASYNC_STREAM) ||
- (req->req.type == RAW1394_REQ_LOCK) ||
- (req->req.type == RAW1394_REQ_LOCK64))
- hpsb_free_tlabel(packet);
-
- queue_complete_req(req);
-}
-
-static void add_host(struct hpsb_host *host)
-{
- struct host_info *hi;
- unsigned long flags;
-
- hi = kmalloc(sizeof(*hi), GFP_KERNEL);
-
- if (hi) {
- INIT_LIST_HEAD(&hi->list);
- hi->host = host;
- INIT_LIST_HEAD(&hi->file_info_list);
-
- spin_lock_irqsave(&host_info_lock, flags);
- list_add_tail(&hi->list, &host_info_list);
- host_count++;
- spin_unlock_irqrestore(&host_info_lock, flags);
- }
-
- atomic_inc(&internal_generation);
-}
-
-static struct host_info *find_host_info(struct hpsb_host *host)
-{
- struct host_info *hi;
-
- list_for_each_entry(hi, &host_info_list, list)
- if (hi->host == host)
- return hi;
-
- return NULL;
-}
-
-static void remove_host(struct hpsb_host *host)
-{
- struct host_info *hi;
- unsigned long flags;
-
- spin_lock_irqsave(&host_info_lock, flags);
- hi = find_host_info(host);
-
- if (hi != NULL) {
- list_del(&hi->list);
- host_count--;
- /*
- FIXME: address ranges should be removed
- and fileinfo states should be initialized
- (including setting generation to
- internal-generation ...)
- */
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- if (hi == NULL) {
- printk(KERN_ERR "raw1394: attempt to remove unknown host "
- "0x%p\n", host);
- return;
- }
-
- kfree(hi);
-
- atomic_inc(&internal_generation);
-}
-
-static void host_reset(struct hpsb_host *host)
-{
- unsigned long flags;
- struct host_info *hi;
- struct file_info *fi;
- struct pending_request *req;
-
- spin_lock_irqsave(&host_info_lock, flags);
- hi = find_host_info(host);
-
- if (hi != NULL) {
- list_for_each_entry(fi, &hi->file_info_list, list) {
- if (fi->notification == RAW1394_NOTIFY_ON) {
- req = __alloc_pending_request(GFP_ATOMIC);
-
- if (req != NULL) {
- req->file_info = fi;
- req->req.type = RAW1394_REQ_BUS_RESET;
- req->req.generation =
- get_hpsb_generation(host);
- req->req.misc = (host->node_id << 16)
- | host->node_count;
- if (fi->protocol_version > 3) {
- req->req.misc |=
- (NODEID_TO_NODE
- (host->irm_id)
- << 8);
- }
-
- queue_complete_req(req);
- }
- }
- }
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
-}
-
-static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
- int cts, u8 * data, size_t length)
-{
- unsigned long flags;
- struct host_info *hi;
- struct file_info *fi;
- struct pending_request *req, *req_next;
- struct iso_block_store *ibs = NULL;
- LIST_HEAD(reqs);
-
- if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
- HPSB_INFO("dropped fcp request");
- return;
- }
-
- spin_lock_irqsave(&host_info_lock, flags);
- hi = find_host_info(host);
-
- if (hi != NULL) {
- list_for_each_entry(fi, &hi->file_info_list, list) {
- if (!fi->fcp_buffer)
- continue;
-
- req = __alloc_pending_request(GFP_ATOMIC);
- if (!req)
- break;
-
- if (!ibs) {
- ibs = kmalloc(sizeof(*ibs) + length,
- GFP_ATOMIC);
- if (!ibs) {
- kfree(req);
- break;
- }
-
- atomic_add(length, &iso_buffer_size);
- atomic_set(&ibs->refcount, 0);
- ibs->data_size = length;
- memcpy(ibs->data, data, length);
- }
-
- atomic_inc(&ibs->refcount);
-
- req->file_info = fi;
- req->ibs = ibs;
- req->data = ibs->data;
- req->req.type = RAW1394_REQ_FCP_REQUEST;
- req->req.generation = get_hpsb_generation(host);
- req->req.misc = nodeid | (direction << 16);
- req->req.recvb = ptr2int(fi->fcp_buffer);
- req->req.length = length;
-
- list_add_tail(&req->list, &reqs);
- }
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- list_for_each_entry_safe(req, req_next, &reqs, list)
- queue_complete_req(req);
-}
-
-#ifdef CONFIG_COMPAT
-struct compat_raw1394_req {
- __u32 type;
- __s32 error;
- __u32 misc;
-
- __u32 generation;
- __u32 length;
-
- __u64 address;
-
- __u64 tag;
-
- __u64 sendb;
- __u64 recvb;
-}
-#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
-__attribute__((packed))
-#endif
-;
-
-static const char __user *raw1394_compat_write(const char __user *buf)
-{
- struct compat_raw1394_req __user *cr = (typeof(cr)) buf;
- struct raw1394_request __user *r;
-
- r = compat_alloc_user_space(sizeof(struct raw1394_request));
-
-#define C(x) __copy_in_user(&r->x, &cr->x, sizeof(r->x))
-
- if (copy_in_user(r, cr, sizeof(struct compat_raw1394_req)) ||
- C(address) ||
- C(tag) ||
- C(sendb) ||
- C(recvb))
- return (__force const char __user *)ERR_PTR(-EFAULT);
-
- return (const char __user *)r;
-}
-#undef C
-
-#define P(x) __put_user(r->x, &cr->x)
-
-static int
-raw1394_compat_read(const char __user *buf, struct raw1394_request *r)
-{
- struct compat_raw1394_req __user *cr = (typeof(cr)) buf;
-
- if (!access_ok(VERIFY_WRITE, cr, sizeof(struct compat_raw1394_req)) ||
- P(type) ||
- P(error) ||
- P(misc) ||
- P(generation) ||
- P(length) ||
- P(address) ||
- P(tag) ||
- P(sendb) ||
- P(recvb))
- return -EFAULT;
-
- return sizeof(struct compat_raw1394_req);
-}
-#undef P
-
-#endif
-
-/* get next completed request (caller must hold fi->reqlists_lock) */
-static inline struct pending_request *__next_complete_req(struct file_info *fi)
-{
- struct list_head *lh;
- struct pending_request *req = NULL;
-
- if (!list_empty(&fi->req_complete)) {
- lh = fi->req_complete.next;
- list_del(lh);
- req = list_entry(lh, struct pending_request, list);
- }
- return req;
-}
-
-/* atomically get next completed request */
-static struct pending_request *next_complete_req(struct file_info *fi)
-{
- unsigned long flags;
- struct pending_request *req;
-
- spin_lock_irqsave(&fi->reqlists_lock, flags);
- req = __next_complete_req(fi);
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
- return req;
-}
-
-static ssize_t raw1394_read(struct file *file, char __user * buffer,
- size_t count, loff_t * offset_is_ignored)
-{
- struct file_info *fi = file->private_data;
- struct pending_request *req;
- ssize_t ret;
-
-#ifdef CONFIG_COMPAT
- if (count == sizeof(struct compat_raw1394_req)) {
- /* ok */
- } else
-#endif
- if (count != sizeof(struct raw1394_request)) {
- return -EINVAL;
- }
-
- if (!access_ok(VERIFY_WRITE, buffer, count)) {
- return -EFAULT;
- }
-
- if (file->f_flags & O_NONBLOCK) {
- if (!(req = next_complete_req(fi)))
- return -EAGAIN;
- } else {
- /*
- * NB: We call the macro wait_event_interruptible() with a
- * condition argument with side effect. This is only possible
- * because the side effect does not occur until the condition
- * became true, and wait_event_interruptible() won't evaluate
- * the condition again after that.
- */
- if (wait_event_interruptible(fi->wait_complete,
- (req = next_complete_req(fi))))
- return -ERESTARTSYS;
- }
-
- if (req->req.length) {
- if (copy_to_user(int2ptr(req->req.recvb), req->data,
- req->req.length)) {
- req->req.error = RAW1394_ERROR_MEMFAULT;
- }
- }
-
-#ifdef CONFIG_COMPAT
- if (count == sizeof(struct compat_raw1394_req) &&
- sizeof(struct compat_raw1394_req) !=
- sizeof(struct raw1394_request)) {
- ret = raw1394_compat_read(buffer, &req->req);
- } else
-#endif
- {
- if (copy_to_user(buffer, &req->req, sizeof(req->req))) {
- ret = -EFAULT;
- goto out;
- }
- ret = (ssize_t) sizeof(struct raw1394_request);
- }
- out:
- free_pending_request(req);
- return ret;
-}
-
-static int state_opened(struct file_info *fi, struct pending_request *req)
-{
- if (req->req.type == RAW1394_REQ_INITIALIZE) {
- switch (req->req.misc) {
- case RAW1394_KERNELAPI_VERSION:
- case 3:
- fi->state = initialized;
- fi->protocol_version = req->req.misc;
- req->req.error = RAW1394_ERROR_NONE;
- req->req.generation = atomic_read(&internal_generation);
- break;
-
- default:
- req->req.error = RAW1394_ERROR_COMPAT;
- req->req.misc = RAW1394_KERNELAPI_VERSION;
- }
- } else {
- req->req.error = RAW1394_ERROR_STATE_ORDER;
- }
-
- req->req.length = 0;
- queue_complete_req(req);
- return 0;
-}
-
-static int state_initialized(struct file_info *fi, struct pending_request *req)
-{
- unsigned long flags;
- struct host_info *hi;
- struct raw1394_khost_list *khl;
-
- if (req->req.generation != atomic_read(&internal_generation)) {
- req->req.error = RAW1394_ERROR_GENERATION;
- req->req.generation = atomic_read(&internal_generation);
- req->req.length = 0;
- queue_complete_req(req);
- return 0;
- }
-
- switch (req->req.type) {
- case RAW1394_REQ_LIST_CARDS:
- spin_lock_irqsave(&host_info_lock, flags);
- khl = kmalloc(sizeof(*khl) * host_count, GFP_ATOMIC);
-
- if (khl) {
- req->req.misc = host_count;
- req->data = (quadlet_t *) khl;
-
- list_for_each_entry(hi, &host_info_list, list) {
- khl->nodes = hi->host->node_count;
- strcpy(khl->name, hi->host->driver->name);
- khl++;
- }
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- if (khl) {
- req->req.error = RAW1394_ERROR_NONE;
- req->req.length = min(req->req.length,
- (u32) (sizeof
- (struct raw1394_khost_list)
- * req->req.misc));
- req->free_data = 1;
- } else {
- return -ENOMEM;
- }
- break;
-
- case RAW1394_REQ_SET_CARD:
- spin_lock_irqsave(&host_info_lock, flags);
- if (req->req.misc >= host_count) {
- req->req.error = RAW1394_ERROR_INVALID_ARG;
- goto out_set_card;
- }
- list_for_each_entry(hi, &host_info_list, list)
- if (!req->req.misc--)
- break;
- get_device(&hi->host->device); /* FIXME handle failure case */
- list_add_tail(&fi->list, &hi->file_info_list);
-
- /* prevent unloading of the host's low-level driver */
- if (!try_module_get(hi->host->driver->owner)) {
- req->req.error = RAW1394_ERROR_ABORTED;
- goto out_set_card;
- }
- WARN_ON(fi->host);
- fi->host = hi->host;
- fi->state = connected;
-
- req->req.error = RAW1394_ERROR_NONE;
- req->req.generation = get_hpsb_generation(fi->host);
- req->req.misc = (fi->host->node_id << 16)
- | fi->host->node_count;
- if (fi->protocol_version > 3)
- req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8;
-out_set_card:
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- req->req.length = 0;
- break;
-
- default:
- req->req.error = RAW1394_ERROR_STATE_ORDER;
- req->req.length = 0;
- break;
- }
-
- queue_complete_req(req);
- return 0;
-}
-
-static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
-{
- if (req->req.misc) {
- if (fi->fcp_buffer) {
- req->req.error = RAW1394_ERROR_ALREADY;
- } else {
- fi->fcp_buffer = int2ptr(req->req.recvb);
- }
- } else {
- if (!fi->fcp_buffer) {
- req->req.error = RAW1394_ERROR_ALREADY;
- } else {
- fi->fcp_buffer = NULL;
- }
- }
-
- req->req.length = 0;
- queue_complete_req(req);
-}
-
-static int handle_async_request(struct file_info *fi,
- struct pending_request *req, int node)
-{
- unsigned long flags;
- struct hpsb_packet *packet = NULL;
- u64 addr = req->req.address & 0xffffffffffffULL;
-
- switch (req->req.type) {
- case RAW1394_REQ_ASYNC_READ:
- DBGMSG("read_request called");
- packet =
- hpsb_make_readpacket(fi->host, node, addr, req->req.length);
-
- if (!packet)
- return -ENOMEM;
-
- if (req->req.length == 4)
- req->data = &packet->header[3];
- else
- req->data = packet->data;
-
- break;
-
- case RAW1394_REQ_ASYNC_WRITE:
- DBGMSG("write_request called");
-
- packet = hpsb_make_writepacket(fi->host, node, addr, NULL,
- req->req.length);
- if (!packet)
- return -ENOMEM;
-
- if (req->req.length == 4) {
- if (copy_from_user
- (&packet->header[3], int2ptr(req->req.sendb),
- req->req.length))
- req->req.error = RAW1394_ERROR_MEMFAULT;
- } else {
- if (copy_from_user
- (packet->data, int2ptr(req->req.sendb),
- req->req.length))
- req->req.error = RAW1394_ERROR_MEMFAULT;
- }
-
- req->req.length = 0;
- break;
-
- case RAW1394_REQ_ASYNC_STREAM:
- DBGMSG("stream_request called");
-
- packet =
- hpsb_make_streampacket(fi->host, NULL, req->req.length,
- node & 0x3f /*channel */ ,
- (req->req.misc >> 16) & 0x3,
- req->req.misc & 0xf);
- if (!packet)
- return -ENOMEM;
-
- if (copy_from_user(packet->data, int2ptr(req->req.sendb),
- req->req.length))
- req->req.error = RAW1394_ERROR_MEMFAULT;
-
- req->req.length = 0;
- break;
-
- case RAW1394_REQ_LOCK:
- DBGMSG("lock_request called");
- if ((req->req.misc == EXTCODE_FETCH_ADD)
- || (req->req.misc == EXTCODE_LITTLE_ADD)) {
- if (req->req.length != 4) {
- req->req.error = RAW1394_ERROR_INVALID_ARG;
- break;
- }
- } else {
- if (req->req.length != 8) {
- req->req.error = RAW1394_ERROR_INVALID_ARG;
- break;
- }
- }
-
- packet = hpsb_make_lockpacket(fi->host, node, addr,
- req->req.misc, NULL, 0);
- if (!packet)
- return -ENOMEM;
-
- if (copy_from_user(packet->data, int2ptr(req->req.sendb),
- req->req.length)) {
- req->req.error = RAW1394_ERROR_MEMFAULT;
- break;
- }
-
- req->data = packet->data;
- req->req.length = 4;
- break;
-
- case RAW1394_REQ_LOCK64:
- DBGMSG("lock64_request called");
- if ((req->req.misc == EXTCODE_FETCH_ADD)
- || (req->req.misc == EXTCODE_LITTLE_ADD)) {
- if (req->req.length != 8) {
- req->req.error = RAW1394_ERROR_INVALID_ARG;
- break;
- }
- } else {
- if (req->req.length != 16) {
- req->req.error = RAW1394_ERROR_INVALID_ARG;
- break;
- }
- }
- packet = hpsb_make_lock64packet(fi->host, node, addr,
- req->req.misc, NULL, 0);
- if (!packet)
- return -ENOMEM;
-
- if (copy_from_user(packet->data, int2ptr(req->req.sendb),
- req->req.length)) {
- req->req.error = RAW1394_ERROR_MEMFAULT;
- break;
- }
-
- req->data = packet->data;
- req->req.length = 8;
- break;
-
- default:
- req->req.error = RAW1394_ERROR_STATE_ORDER;
- }
-
- req->packet = packet;
-
- if (req->req.error) {
- req->req.length = 0;
- queue_complete_req(req);
- return 0;
- }
-
- hpsb_set_packet_complete_task(packet,
- (void (*)(void *))queue_complete_cb, req);
-
- spin_lock_irqsave(&fi->reqlists_lock, flags);
- list_add_tail(&req->list, &fi->req_pending);
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
- packet->generation = req->req.generation;
-
- if (hpsb_send_packet(packet) < 0) {
- req->req.error = RAW1394_ERROR_SEND_ERROR;
- req->req.length = 0;
- hpsb_free_tlabel(packet);
- queue_complete_req(req);
- }
- return 0;
-}
-
-static int handle_async_send(struct file_info *fi, struct pending_request *req)
-{
- unsigned long flags;
- struct hpsb_packet *packet;
- int header_length = req->req.misc & 0xffff;
- int expect_response = req->req.misc >> 16;
- size_t data_size;
-
- if (header_length > req->req.length || header_length < 12 ||
- header_length > FIELD_SIZEOF(struct hpsb_packet, header)) {
- req->req.error = RAW1394_ERROR_INVALID_ARG;
- req->req.length = 0;
- queue_complete_req(req);
- return 0;
- }
-
- data_size = req->req.length - header_length;
- packet = hpsb_alloc_packet(data_size);
- req->packet = packet;
- if (!packet)
- return -ENOMEM;
-
- if (copy_from_user(packet->header, int2ptr(req->req.sendb),
- header_length)) {
- req->req.error = RAW1394_ERROR_MEMFAULT;
- req->req.length = 0;
- queue_complete_req(req);
- return 0;
- }
-
- if (copy_from_user
- (packet->data, int2ptr(req->req.sendb) + header_length,
- data_size)) {
- req->req.error = RAW1394_ERROR_MEMFAULT;
- req->req.length = 0;
- queue_complete_req(req);
- return 0;
- }
-
- packet->type = hpsb_async;
- packet->node_id = packet->header[0] >> 16;
- packet->tcode = (packet->header[0] >> 4) & 0xf;
- packet->tlabel = (packet->header[0] >> 10) & 0x3f;
- packet->host = fi->host;
- packet->expect_response = expect_response;
- packet->header_size = header_length;
- packet->data_size = data_size;
-
- req->req.length = 0;
- hpsb_set_packet_complete_task(packet,
- (void (*)(void *))queue_complete_cb, req);
-
- spin_lock_irqsave(&fi->reqlists_lock, flags);
- list_add_tail(&req->list, &fi->req_pending);
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
- /* Update the generation of the packet just before sending. */
- packet->generation = req->req.generation;
-
- if (hpsb_send_packet(packet) < 0) {
- req->req.error = RAW1394_ERROR_SEND_ERROR;
- queue_complete_req(req);
- }
-
- return 0;
-}
-
-static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer,
- u64 addr, size_t length, u16 flags)
-{
- unsigned long irqflags;
- struct pending_request *req;
- struct host_info *hi;
- struct file_info *fi = NULL;
- struct list_head *entry;
- struct arm_addr *arm_addr = NULL;
- struct arm_request *arm_req = NULL;
- struct arm_response *arm_resp = NULL;
- int found = 0, size = 0, rcode = -1;
- struct arm_request_response *arm_req_resp = NULL;
-
- DBGMSG("arm_read called by node: %X "
- "addr: %4.4x %8.8x length: %Zu", nodeid,
- (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
- length);
- spin_lock_irqsave(&host_info_lock, irqflags);
- hi = find_host_info(host); /* search address-entry */
- if (hi != NULL) {
- list_for_each_entry(fi, &hi->file_info_list, list) {
- entry = fi->addr_list.next;
- while (entry != &(fi->addr_list)) {
- arm_addr =
- list_entry(entry, struct arm_addr,
- addr_list);
- if (((arm_addr->start) <= (addr))
- && ((arm_addr->end) >= (addr + length))) {
- found = 1;
- break;
- }
- entry = entry->next;
- }
- if (found) {
- break;
- }
- }
- }
- rcode = -1;
- if (!found) {
- printk(KERN_ERR "raw1394: arm_read FAILED addr_entry not found"
- " -> rcode_address_error\n");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_ADDRESS_ERROR);
- } else {
- DBGMSG("arm_read addr_entry FOUND");
- }
- if (arm_addr->rec_length < length) {
- DBGMSG("arm_read blocklength too big -> rcode_data_error");
- rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */
- }
- if (rcode == -1) {
- if (arm_addr->access_rights & ARM_READ) {
- if (!(arm_addr->client_transactions & ARM_READ)) {
- memcpy(buffer,
- (arm_addr->addr_space_buffer) + (addr -
- (arm_addr->
- start)),
- length);
- DBGMSG("arm_read -> (rcode_complete)");
- rcode = RCODE_COMPLETE;
- }
- } else {
- rcode = RCODE_TYPE_ERROR; /* function not allowed */
- DBGMSG("arm_read -> rcode_type_error (access denied)");
- }
- }
- if (arm_addr->notification_options & ARM_READ) {
- DBGMSG("arm_read -> entering notification-section");
- req = __alloc_pending_request(GFP_ATOMIC);
- if (!req) {
- DBGMSG("arm_read -> rcode_conflict_error");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request may be retried */
- }
- if (rcode == RCODE_COMPLETE) {
- size =
- sizeof(struct arm_request) +
- sizeof(struct arm_response) +
- length * sizeof(byte_t) +
- sizeof(struct arm_request_response);
- } else {
- size =
- sizeof(struct arm_request) +
- sizeof(struct arm_response) +
- sizeof(struct arm_request_response);
- }
- req->data = kmalloc(size, GFP_ATOMIC);
- if (!(req->data)) {
- free_pending_request(req);
- DBGMSG("arm_read -> rcode_conflict_error");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request may be retried */
- }
- req->free_data = 1;
- req->file_info = fi;
- req->req.type = RAW1394_REQ_ARM;
- req->req.generation = get_hpsb_generation(host);
- req->req.misc =
- (((length << 16) & (0xFFFF0000)) | (ARM_READ & 0xFF));
- req->req.tag = arm_addr->arm_tag;
- req->req.recvb = arm_addr->recvb;
- req->req.length = size;
- arm_req_resp = (struct arm_request_response *)(req->data);
- arm_req = (struct arm_request *)((byte_t *) (req->data) +
- (sizeof
- (struct
- arm_request_response)));
- arm_resp =
- (struct arm_response *)((byte_t *) (arm_req) +
- (sizeof(struct arm_request)));
- arm_req->buffer = NULL;
- arm_resp->buffer = NULL;
- if (rcode == RCODE_COMPLETE) {
- byte_t *buf =
- (byte_t *) arm_resp + sizeof(struct arm_response);
- memcpy(buf,
- (arm_addr->addr_space_buffer) + (addr -
- (arm_addr->
- start)),
- length);
- arm_resp->buffer =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request) +
- sizeof(struct arm_response));
- }
- arm_resp->buffer_length =
- (rcode == RCODE_COMPLETE) ? length : 0;
- arm_resp->response_code = rcode;
- arm_req->buffer_length = 0;
- arm_req->generation = req->req.generation;
- arm_req->extended_transaction_code = 0;
- arm_req->destination_offset = addr;
- arm_req->source_nodeid = nodeid;
- arm_req->destination_nodeid = host->node_id;
- arm_req->tlabel = (flags >> 10) & 0x3f;
- arm_req->tcode = (flags >> 4) & 0x0f;
- arm_req_resp->request = int2ptr((arm_addr->recvb) +
- sizeof(struct
- arm_request_response));
- arm_req_resp->response =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request));
- queue_complete_req(req);
- }
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (rcode);
-}
-
-static int arm_write(struct hpsb_host *host, int nodeid, int destid,
- quadlet_t * data, u64 addr, size_t length, u16 flags)
-{
- unsigned long irqflags;
- struct pending_request *req;
- struct host_info *hi;
- struct file_info *fi = NULL;
- struct list_head *entry;
- struct arm_addr *arm_addr = NULL;
- struct arm_request *arm_req = NULL;
- struct arm_response *arm_resp = NULL;
- int found = 0, size = 0, rcode = -1;
- struct arm_request_response *arm_req_resp = NULL;
-
- DBGMSG("arm_write called by node: %X "
- "addr: %4.4x %8.8x length: %Zu", nodeid,
- (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
- length);
- spin_lock_irqsave(&host_info_lock, irqflags);
- hi = find_host_info(host); /* search address-entry */
- if (hi != NULL) {
- list_for_each_entry(fi, &hi->file_info_list, list) {
- entry = fi->addr_list.next;
- while (entry != &(fi->addr_list)) {
- arm_addr =
- list_entry(entry, struct arm_addr,
- addr_list);
- if (((arm_addr->start) <= (addr))
- && ((arm_addr->end) >= (addr + length))) {
- found = 1;
- break;
- }
- entry = entry->next;
- }
- if (found) {
- break;
- }
- }
- }
- rcode = -1;
- if (!found) {
- printk(KERN_ERR "raw1394: arm_write FAILED addr_entry not found"
- " -> rcode_address_error\n");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_ADDRESS_ERROR);
- } else {
- DBGMSG("arm_write addr_entry FOUND");
- }
- if (arm_addr->rec_length < length) {
- DBGMSG("arm_write blocklength too big -> rcode_data_error");
- rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */
- }
- if (rcode == -1) {
- if (arm_addr->access_rights & ARM_WRITE) {
- if (!(arm_addr->client_transactions & ARM_WRITE)) {
- memcpy((arm_addr->addr_space_buffer) +
- (addr - (arm_addr->start)), data,
- length);
- DBGMSG("arm_write -> (rcode_complete)");
- rcode = RCODE_COMPLETE;
- }
- } else {
- rcode = RCODE_TYPE_ERROR; /* function not allowed */
- DBGMSG("arm_write -> rcode_type_error (access denied)");
- }
- }
- if (arm_addr->notification_options & ARM_WRITE) {
- DBGMSG("arm_write -> entering notification-section");
- req = __alloc_pending_request(GFP_ATOMIC);
- if (!req) {
- DBGMSG("arm_write -> rcode_conflict_error");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request my be retried */
- }
- size =
- sizeof(struct arm_request) + sizeof(struct arm_response) +
- (length) * sizeof(byte_t) +
- sizeof(struct arm_request_response);
- req->data = kmalloc(size, GFP_ATOMIC);
- if (!(req->data)) {
- free_pending_request(req);
- DBGMSG("arm_write -> rcode_conflict_error");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request may be retried */
- }
- req->free_data = 1;
- req->file_info = fi;
- req->req.type = RAW1394_REQ_ARM;
- req->req.generation = get_hpsb_generation(host);
- req->req.misc =
- (((length << 16) & (0xFFFF0000)) | (ARM_WRITE & 0xFF));
- req->req.tag = arm_addr->arm_tag;
- req->req.recvb = arm_addr->recvb;
- req->req.length = size;
- arm_req_resp = (struct arm_request_response *)(req->data);
- arm_req = (struct arm_request *)((byte_t *) (req->data) +
- (sizeof
- (struct
- arm_request_response)));
- arm_resp =
- (struct arm_response *)((byte_t *) (arm_req) +
- (sizeof(struct arm_request)));
- arm_resp->buffer = NULL;
- memcpy((byte_t *) arm_resp + sizeof(struct arm_response),
- data, length);
- arm_req->buffer = int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request) +
- sizeof(struct arm_response));
- arm_req->buffer_length = length;
- arm_req->generation = req->req.generation;
- arm_req->extended_transaction_code = 0;
- arm_req->destination_offset = addr;
- arm_req->source_nodeid = nodeid;
- arm_req->destination_nodeid = destid;
- arm_req->tlabel = (flags >> 10) & 0x3f;
- arm_req->tcode = (flags >> 4) & 0x0f;
- arm_resp->buffer_length = 0;
- arm_resp->response_code = rcode;
- arm_req_resp->request = int2ptr((arm_addr->recvb) +
- sizeof(struct
- arm_request_response));
- arm_req_resp->response =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request));
- queue_complete_req(req);
- }
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (rcode);
-}
-
-static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store,
- u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
- u16 flags)
-{
- unsigned long irqflags;
- struct pending_request *req;
- struct host_info *hi;
- struct file_info *fi = NULL;
- struct list_head *entry;
- struct arm_addr *arm_addr = NULL;
- struct arm_request *arm_req = NULL;
- struct arm_response *arm_resp = NULL;
- int found = 0, size = 0, rcode = -1;
- quadlet_t old, new;
- struct arm_request_response *arm_req_resp = NULL;
-
- if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
- ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
- DBGMSG("arm_lock called by node: %X "
- "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X",
- nodeid, (u16) ((addr >> 32) & 0xFFFF),
- (u32) (addr & 0xFFFFFFFF), ext_tcode & 0xFF,
- be32_to_cpu(data));
- } else {
- DBGMSG("arm_lock called by node: %X "
- "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X arg: %8.8X",
- nodeid, (u16) ((addr >> 32) & 0xFFFF),
- (u32) (addr & 0xFFFFFFFF), ext_tcode & 0xFF,
- be32_to_cpu(data), be32_to_cpu(arg));
- }
- spin_lock_irqsave(&host_info_lock, irqflags);
- hi = find_host_info(host); /* search address-entry */
- if (hi != NULL) {
- list_for_each_entry(fi, &hi->file_info_list, list) {
- entry = fi->addr_list.next;
- while (entry != &(fi->addr_list)) {
- arm_addr =
- list_entry(entry, struct arm_addr,
- addr_list);
- if (((arm_addr->start) <= (addr))
- && ((arm_addr->end) >=
- (addr + sizeof(*store)))) {
- found = 1;
- break;
- }
- entry = entry->next;
- }
- if (found) {
- break;
- }
- }
- }
- rcode = -1;
- if (!found) {
- printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found"
- " -> rcode_address_error\n");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_ADDRESS_ERROR);
- } else {
- DBGMSG("arm_lock addr_entry FOUND");
- }
- if (rcode == -1) {
- if (arm_addr->access_rights & ARM_LOCK) {
- if (!(arm_addr->client_transactions & ARM_LOCK)) {
- memcpy(&old,
- (arm_addr->addr_space_buffer) + (addr -
- (arm_addr->
- start)),
- sizeof(old));
- switch (ext_tcode) {
- case (EXTCODE_MASK_SWAP):
- new = data | (old & ~arg);
- break;
- case (EXTCODE_COMPARE_SWAP):
- if (old == arg) {
- new = data;
- } else {
- new = old;
- }
- break;
- case (EXTCODE_FETCH_ADD):
- new =
- cpu_to_be32(be32_to_cpu(data) +
- be32_to_cpu(old));
- break;
- case (EXTCODE_LITTLE_ADD):
- new =
- cpu_to_le32(le32_to_cpu(data) +
- le32_to_cpu(old));
- break;
- case (EXTCODE_BOUNDED_ADD):
- if (old != arg) {
- new =
- cpu_to_be32(be32_to_cpu
- (data) +
- be32_to_cpu
- (old));
- } else {
- new = old;
- }
- break;
- case (EXTCODE_WRAP_ADD):
- if (old != arg) {
- new =
- cpu_to_be32(be32_to_cpu
- (data) +
- be32_to_cpu
- (old));
- } else {
- new = data;
- }
- break;
- default:
- rcode = RCODE_TYPE_ERROR; /* function not allowed */
- printk(KERN_ERR
- "raw1394: arm_lock FAILED "
- "ext_tcode not allowed -> rcode_type_error\n");
- break;
- } /*switch */
- if (rcode == -1) {
- DBGMSG("arm_lock -> (rcode_complete)");
- rcode = RCODE_COMPLETE;
- memcpy(store, &old, sizeof(*store));
- memcpy((arm_addr->addr_space_buffer) +
- (addr - (arm_addr->start)),
- &new, sizeof(*store));
- }
- }
- } else {
- rcode = RCODE_TYPE_ERROR; /* function not allowed */
- DBGMSG("arm_lock -> rcode_type_error (access denied)");
- }
- }
- if (arm_addr->notification_options & ARM_LOCK) {
- byte_t *buf1, *buf2;
- DBGMSG("arm_lock -> entering notification-section");
- req = __alloc_pending_request(GFP_ATOMIC);
- if (!req) {
- DBGMSG("arm_lock -> rcode_conflict_error");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request may be retried */
- }
- size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response); /* maximum */
- req->data = kmalloc(size, GFP_ATOMIC);
- if (!(req->data)) {
- free_pending_request(req);
- DBGMSG("arm_lock -> rcode_conflict_error");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request may be retried */
- }
- req->free_data = 1;
- arm_req_resp = (struct arm_request_response *)(req->data);
- arm_req = (struct arm_request *)((byte_t *) (req->data) +
- (sizeof
- (struct
- arm_request_response)));
- arm_resp =
- (struct arm_response *)((byte_t *) (arm_req) +
- (sizeof(struct arm_request)));
- buf1 = (byte_t *) arm_resp + sizeof(struct arm_response);
- buf2 = buf1 + 2 * sizeof(*store);
- if ((ext_tcode == EXTCODE_FETCH_ADD) ||
- (ext_tcode == EXTCODE_LITTLE_ADD)) {
- arm_req->buffer_length = sizeof(*store);
- memcpy(buf1, &data, sizeof(*store));
-
- } else {
- arm_req->buffer_length = 2 * sizeof(*store);
- memcpy(buf1, &arg, sizeof(*store));
- memcpy(buf1 + sizeof(*store), &data, sizeof(*store));
- }
- if (rcode == RCODE_COMPLETE) {
- arm_resp->buffer_length = sizeof(*store);
- memcpy(buf2, &old, sizeof(*store));
- } else {
- arm_resp->buffer_length = 0;
- }
- req->file_info = fi;
- req->req.type = RAW1394_REQ_ARM;
- req->req.generation = get_hpsb_generation(host);
- req->req.misc = ((((sizeof(*store)) << 16) & (0xFFFF0000)) |
- (ARM_LOCK & 0xFF));
- req->req.tag = arm_addr->arm_tag;
- req->req.recvb = arm_addr->recvb;
- req->req.length = size;
- arm_req->generation = req->req.generation;
- arm_req->extended_transaction_code = ext_tcode;
- arm_req->destination_offset = addr;
- arm_req->source_nodeid = nodeid;
- arm_req->destination_nodeid = host->node_id;
- arm_req->tlabel = (flags >> 10) & 0x3f;
- arm_req->tcode = (flags >> 4) & 0x0f;
- arm_resp->response_code = rcode;
- arm_req_resp->request = int2ptr((arm_addr->recvb) +
- sizeof(struct
- arm_request_response));
- arm_req_resp->response =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request));
- arm_req->buffer =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request) +
- sizeof(struct arm_response));
- arm_resp->buffer =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request) +
- sizeof(struct arm_response) + 2 * sizeof(*store));
- queue_complete_req(req);
- }
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (rcode);
-}
-
-static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store,
- u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
- u16 flags)
-{
- unsigned long irqflags;
- struct pending_request *req;
- struct host_info *hi;
- struct file_info *fi = NULL;
- struct list_head *entry;
- struct arm_addr *arm_addr = NULL;
- struct arm_request *arm_req = NULL;
- struct arm_response *arm_resp = NULL;
- int found = 0, size = 0, rcode = -1;
- octlet_t old, new;
- struct arm_request_response *arm_req_resp = NULL;
-
- if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
- ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
- DBGMSG("arm_lock64 called by node: %X "
- "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ",
- nodeid, (u16) ((addr >> 32) & 0xFFFF),
- (u32) (addr & 0xFFFFFFFF),
- ext_tcode & 0xFF,
- (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF),
- (u32) (be64_to_cpu(data) & 0xFFFFFFFF));
- } else {
- DBGMSG("arm_lock64 called by node: %X "
- "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X arg: "
- "%8.8X %8.8X ",
- nodeid, (u16) ((addr >> 32) & 0xFFFF),
- (u32) (addr & 0xFFFFFFFF),
- ext_tcode & 0xFF,
- (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF),
- (u32) (be64_to_cpu(data) & 0xFFFFFFFF),
- (u32) ((be64_to_cpu(arg) >> 32) & 0xFFFFFFFF),
- (u32) (be64_to_cpu(arg) & 0xFFFFFFFF));
- }
- spin_lock_irqsave(&host_info_lock, irqflags);
- hi = find_host_info(host); /* search addressentry in file_info's for host */
- if (hi != NULL) {
- list_for_each_entry(fi, &hi->file_info_list, list) {
- entry = fi->addr_list.next;
- while (entry != &(fi->addr_list)) {
- arm_addr =
- list_entry(entry, struct arm_addr,
- addr_list);
- if (((arm_addr->start) <= (addr))
- && ((arm_addr->end) >=
- (addr + sizeof(*store)))) {
- found = 1;
- break;
- }
- entry = entry->next;
- }
- if (found) {
- break;
- }
- }
- }
- rcode = -1;
- if (!found) {
- printk(KERN_ERR
- "raw1394: arm_lock64 FAILED addr_entry not found"
- " -> rcode_address_error\n");
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (RCODE_ADDRESS_ERROR);
- } else {
- DBGMSG("arm_lock64 addr_entry FOUND");
- }
- if (rcode == -1) {
- if (arm_addr->access_rights & ARM_LOCK) {
- if (!(arm_addr->client_transactions & ARM_LOCK)) {
- memcpy(&old,
- (arm_addr->addr_space_buffer) + (addr -
- (arm_addr->
- start)),
- sizeof(old));
- switch (ext_tcode) {
- case (EXTCODE_MASK_SWAP):
- new = data | (old & ~arg);
- break;
- case (EXTCODE_COMPARE_SWAP):
- if (old == arg) {
- new = data;
- } else {
- new = old;
- }
- break;
- case (EXTCODE_FETCH_ADD):
- new =
- cpu_to_be64(be64_to_cpu(data) +
- be64_to_cpu(old));
- break;
- case (EXTCODE_LITTLE_ADD):
- new =
- cpu_to_le64(le64_to_cpu(data) +
- le64_to_cpu(old));
- break;
- case (EXTCODE_BOUNDED_ADD):
- if (old != arg) {
- new =
- cpu_to_be64(be64_to_cpu
- (data) +
- be64_to_cpu
- (old));
- } else {
- new = old;
- }
- break;
- case (EXTCODE_WRAP_ADD):
- if (old != arg) {
- new =
- cpu_to_be64(be64_to_cpu
- (data) +
- be64_to_cpu
- (old));
- } else {
- new = data;
- }
- break;
- default:
- printk(KERN_ERR
- "raw1394: arm_lock64 FAILED "
- "ext_tcode not allowed -> rcode_type_error\n");
- rcode = RCODE_TYPE_ERROR; /* function not allowed */
- break;
- } /*switch */
- if (rcode == -1) {
- DBGMSG
- ("arm_lock64 -> (rcode_complete)");
- rcode = RCODE_COMPLETE;
- memcpy(store, &old, sizeof(*store));
- memcpy((arm_addr->addr_space_buffer) +
- (addr - (arm_addr->start)),
- &new, sizeof(*store));
- }
- }
- } else {
- rcode = RCODE_TYPE_ERROR; /* function not allowed */
- DBGMSG
- ("arm_lock64 -> rcode_type_error (access denied)");
- }
- }
- if (arm_addr->notification_options & ARM_LOCK) {
- byte_t *buf1, *buf2;
- DBGMSG("arm_lock64 -> entering notification-section");
- req = __alloc_pending_request(GFP_ATOMIC);
- if (!req) {
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- DBGMSG("arm_lock64 -> rcode_conflict_error");
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request may be retried */
- }
- size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response); /* maximum */
- req->data = kmalloc(size, GFP_ATOMIC);
- if (!(req->data)) {
- free_pending_request(req);
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- DBGMSG("arm_lock64 -> rcode_conflict_error");
- return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected.
- The request may be retried */
- }
- req->free_data = 1;
- arm_req_resp = (struct arm_request_response *)(req->data);
- arm_req = (struct arm_request *)((byte_t *) (req->data) +
- (sizeof
- (struct
- arm_request_response)));
- arm_resp =
- (struct arm_response *)((byte_t *) (arm_req) +
- (sizeof(struct arm_request)));
- buf1 = (byte_t *) arm_resp + sizeof(struct arm_response);
- buf2 = buf1 + 2 * sizeof(*store);
- if ((ext_tcode == EXTCODE_FETCH_ADD) ||
- (ext_tcode == EXTCODE_LITTLE_ADD)) {
- arm_req->buffer_length = sizeof(*store);
- memcpy(buf1, &data, sizeof(*store));
-
- } else {
- arm_req->buffer_length = 2 * sizeof(*store);
- memcpy(buf1, &arg, sizeof(*store));
- memcpy(buf1 + sizeof(*store), &data, sizeof(*store));
- }
- if (rcode == RCODE_COMPLETE) {
- arm_resp->buffer_length = sizeof(*store);
- memcpy(buf2, &old, sizeof(*store));
- } else {
- arm_resp->buffer_length = 0;
- }
- req->file_info = fi;
- req->req.type = RAW1394_REQ_ARM;
- req->req.generation = get_hpsb_generation(host);
- req->req.misc = ((((sizeof(*store)) << 16) & (0xFFFF0000)) |
- (ARM_LOCK & 0xFF));
- req->req.tag = arm_addr->arm_tag;
- req->req.recvb = arm_addr->recvb;
- req->req.length = size;
- arm_req->generation = req->req.generation;
- arm_req->extended_transaction_code = ext_tcode;
- arm_req->destination_offset = addr;
- arm_req->source_nodeid = nodeid;
- arm_req->destination_nodeid = host->node_id;
- arm_req->tlabel = (flags >> 10) & 0x3f;
- arm_req->tcode = (flags >> 4) & 0x0f;
- arm_resp->response_code = rcode;
- arm_req_resp->request = int2ptr((arm_addr->recvb) +
- sizeof(struct
- arm_request_response));
- arm_req_resp->response =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request));
- arm_req->buffer =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request) +
- sizeof(struct arm_response));
- arm_resp->buffer =
- int2ptr((arm_addr->recvb) +
- sizeof(struct arm_request_response) +
- sizeof(struct arm_request) +
- sizeof(struct arm_response) + 2 * sizeof(*store));
- queue_complete_req(req);
- }
- spin_unlock_irqrestore(&host_info_lock, irqflags);
- return (rcode);
-}
-
-static int arm_register(struct file_info *fi, struct pending_request *req)
-{
- int retval;
- struct arm_addr *addr;
- struct host_info *hi;
- struct file_info *fi_hlp = NULL;
- struct list_head *entry;
- struct arm_addr *arm_addr = NULL;
- int same_host, another_host;
- unsigned long flags;
-
- DBGMSG("arm_register called "
- "addr(Offset): %8.8x %8.8x length: %u "
- "rights: %2.2X notify: %2.2X "
- "max_blk_len: %4.4X",
- (u32) ((req->req.address >> 32) & 0xFFFF),
- (u32) (req->req.address & 0xFFFFFFFF),
- req->req.length, ((req->req.misc >> 8) & 0xFF),
- (req->req.misc & 0xFF), ((req->req.misc >> 16) & 0xFFFF));
- /* check addressrange */
- if ((((req->req.address) & ~(0xFFFFFFFFFFFFULL)) != 0) ||
- (((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFFULL)) !=
- 0)) {
- req->req.length = 0;
- return (-EINVAL);
- }
- /* addr-list-entry for fileinfo */
- addr = kmalloc(sizeof(*addr), GFP_KERNEL);
- if (!addr) {
- req->req.length = 0;
- return (-ENOMEM);
- }
- /* allocation of addr_space_buffer */
- addr->addr_space_buffer = vmalloc(req->req.length);
- if (!(addr->addr_space_buffer)) {
- kfree(addr);
- req->req.length = 0;
- return (-ENOMEM);
- }
- /* initialization of addr_space_buffer */
- if ((req->req.sendb) == (unsigned long)NULL) {
- /* init: set 0 */
- memset(addr->addr_space_buffer, 0, req->req.length);
- } else {
- /* init: user -> kernel */
- if (copy_from_user
- (addr->addr_space_buffer, int2ptr(req->req.sendb),
- req->req.length)) {
- vfree(addr->addr_space_buffer);
- kfree(addr);
- return (-EFAULT);
- }
- }
- INIT_LIST_HEAD(&addr->addr_list);
- addr->arm_tag = req->req.tag;
- addr->start = req->req.address;
- addr->end = req->req.address + req->req.length;
- addr->access_rights = (u8) (req->req.misc & 0x0F);
- addr->notification_options = (u8) ((req->req.misc >> 4) & 0x0F);
- addr->client_transactions = (u8) ((req->req.misc >> 8) & 0x0F);
- addr->access_rights |= addr->client_transactions;
- addr->notification_options |= addr->client_transactions;
- addr->recvb = req->req.recvb;
- addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF);
-
- spin_lock_irqsave(&host_info_lock, flags);
- hi = find_host_info(fi->host);
- same_host = 0;
- another_host = 0;
- /* same host with address-entry containing same addressrange ? */
- list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
- entry = fi_hlp->addr_list.next;
- while (entry != &(fi_hlp->addr_list)) {
- arm_addr =
- list_entry(entry, struct arm_addr, addr_list);
- if ((arm_addr->start == addr->start)
- && (arm_addr->end == addr->end)) {
- DBGMSG("same host ownes same "
- "addressrange -> EALREADY");
- same_host = 1;
- break;
- }
- entry = entry->next;
- }
- if (same_host) {
- break;
- }
- }
- if (same_host) {
- /* addressrange occupied by same host */
- spin_unlock_irqrestore(&host_info_lock, flags);
- vfree(addr->addr_space_buffer);
- kfree(addr);
- return (-EALREADY);
- }
- /* another host with valid address-entry containing same addressrange */
- list_for_each_entry(hi, &host_info_list, list) {
- if (hi->host != fi->host) {
- list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
- entry = fi_hlp->addr_list.next;
- while (entry != &(fi_hlp->addr_list)) {
- arm_addr =
- list_entry(entry, struct arm_addr,
- addr_list);
- if ((arm_addr->start == addr->start)
- && (arm_addr->end == addr->end)) {
- DBGMSG
- ("another host ownes same "
- "addressrange");
- another_host = 1;
- break;
- }
- entry = entry->next;
- }
- if (another_host) {
- break;
- }
- }
- }
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- if (another_host) {
- DBGMSG("another hosts entry is valid -> SUCCESS");
- if (copy_to_user(int2ptr(req->req.recvb),
- &addr->start, sizeof(u64))) {
- printk(KERN_ERR "raw1394: arm_register failed "
- " address-range-entry is invalid -> EFAULT !!!\n");
- vfree(addr->addr_space_buffer);
- kfree(addr);
- return (-EFAULT);
- }
- free_pending_request(req); /* immediate success or fail */
- /* INSERT ENTRY */
- spin_lock_irqsave(&host_info_lock, flags);
- list_add_tail(&addr->addr_list, &fi->addr_list);
- spin_unlock_irqrestore(&host_info_lock, flags);
- return 0;
- }
- retval =
- hpsb_register_addrspace(&raw1394_highlevel, fi->host, &arm_ops,
- req->req.address,
- req->req.address + req->req.length);
- if (retval) {
- /* INSERT ENTRY */
- spin_lock_irqsave(&host_info_lock, flags);
- list_add_tail(&addr->addr_list, &fi->addr_list);
- spin_unlock_irqrestore(&host_info_lock, flags);
- } else {
- DBGMSG("arm_register failed errno: %d \n", retval);
- vfree(addr->addr_space_buffer);
- kfree(addr);
- return (-EALREADY);
- }
- free_pending_request(req); /* immediate success or fail */
- return 0;
-}
-
-static int arm_unregister(struct file_info *fi, struct pending_request *req)
-{
- int found = 0;
- int retval = 0;
- struct list_head *entry;
- struct arm_addr *addr = NULL;
- struct host_info *hi;
- struct file_info *fi_hlp = NULL;
- struct arm_addr *arm_addr = NULL;
- int another_host;
- unsigned long flags;
-
- DBGMSG("arm_Unregister called addr(Offset): "
- "%8.8x %8.8x",
- (u32) ((req->req.address >> 32) & 0xFFFF),
- (u32) (req->req.address & 0xFFFFFFFF));
- spin_lock_irqsave(&host_info_lock, flags);
- /* get addr */
- entry = fi->addr_list.next;
- while (entry != &(fi->addr_list)) {
- addr = list_entry(entry, struct arm_addr, addr_list);
- if (addr->start == req->req.address) {
- found = 1;
- break;
- }
- entry = entry->next;
- }
- if (!found) {
- DBGMSG("arm_Unregister addr not found");
- spin_unlock_irqrestore(&host_info_lock, flags);
- return (-EINVAL);
- }
- DBGMSG("arm_Unregister addr found");
- another_host = 0;
- /* another host with valid address-entry containing
- same addressrange */
- list_for_each_entry(hi, &host_info_list, list) {
- if (hi->host != fi->host) {
- list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
- entry = fi_hlp->addr_list.next;
- while (entry != &(fi_hlp->addr_list)) {
- arm_addr = list_entry(entry,
- struct arm_addr,
- addr_list);
- if (arm_addr->start == addr->start) {
- DBGMSG("another host ownes "
- "same addressrange");
- another_host = 1;
- break;
- }
- entry = entry->next;
- }
- if (another_host) {
- break;
- }
- }
- }
- }
- if (another_host) {
- DBGMSG("delete entry from list -> success");
- list_del(&addr->addr_list);
- spin_unlock_irqrestore(&host_info_lock, flags);
- vfree(addr->addr_space_buffer);
- kfree(addr);
- free_pending_request(req); /* immediate success or fail */
- return 0;
- }
- retval =
- hpsb_unregister_addrspace(&raw1394_highlevel, fi->host,
- addr->start);
- if (!retval) {
- printk(KERN_ERR "raw1394: arm_Unregister failed -> EINVAL\n");
- spin_unlock_irqrestore(&host_info_lock, flags);
- return (-EINVAL);
- }
- DBGMSG("delete entry from list -> success");
- list_del(&addr->addr_list);
- spin_unlock_irqrestore(&host_info_lock, flags);
- vfree(addr->addr_space_buffer);
- kfree(addr);
- free_pending_request(req); /* immediate success or fail */
- return 0;
-}
-
-/* Copy data from ARM buffer(s) to user buffer. */
-static int arm_get_buf(struct file_info *fi, struct pending_request *req)
-{
- struct arm_addr *arm_addr = NULL;
- unsigned long flags;
- unsigned long offset;
-
- struct list_head *entry;
-
- DBGMSG("arm_get_buf "
- "addr(Offset): %04X %08X length: %u",
- (u32) ((req->req.address >> 32) & 0xFFFF),
- (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length);
-
- spin_lock_irqsave(&host_info_lock, flags);
- entry = fi->addr_list.next;
- while (entry != &(fi->addr_list)) {
- arm_addr = list_entry(entry, struct arm_addr, addr_list);
- if ((arm_addr->start <= req->req.address) &&
- (arm_addr->end > req->req.address)) {
- if (req->req.address + req->req.length <= arm_addr->end) {
- offset = req->req.address - arm_addr->start;
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- DBGMSG
- ("arm_get_buf copy_to_user( %08X, %p, %u )",
- (u32) req->req.recvb,
- arm_addr->addr_space_buffer + offset,
- (u32) req->req.length);
- if (copy_to_user
- (int2ptr(req->req.recvb),
- arm_addr->addr_space_buffer + offset,
- req->req.length))
- return (-EFAULT);
-
- /* We have to free the request, because we
- * queue no response, and therefore nobody
- * will free it. */
- free_pending_request(req);
- return 0;
- } else {
- DBGMSG("arm_get_buf request exceeded mapping");
- spin_unlock_irqrestore(&host_info_lock, flags);
- return (-EINVAL);
- }
- }
- entry = entry->next;
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
- return (-EINVAL);
-}
-
-/* Copy data from user buffer to ARM buffer(s). */
-static int arm_set_buf(struct file_info *fi, struct pending_request *req)
-{
- struct arm_addr *arm_addr = NULL;
- unsigned long flags;
- unsigned long offset;
-
- struct list_head *entry;
-
- DBGMSG("arm_set_buf "
- "addr(Offset): %04X %08X length: %u",
- (u32) ((req->req.address >> 32) & 0xFFFF),
- (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length);
-
- spin_lock_irqsave(&host_info_lock, flags);
- entry = fi->addr_list.next;
- while (entry != &(fi->addr_list)) {
- arm_addr = list_entry(entry, struct arm_addr, addr_list);
- if ((arm_addr->start <= req->req.address) &&
- (arm_addr->end > req->req.address)) {
- if (req->req.address + req->req.length <= arm_addr->end) {
- offset = req->req.address - arm_addr->start;
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- DBGMSG
- ("arm_set_buf copy_from_user( %p, %08X, %u )",
- arm_addr->addr_space_buffer + offset,
- (u32) req->req.sendb,
- (u32) req->req.length);
- if (copy_from_user
- (arm_addr->addr_space_buffer + offset,
- int2ptr(req->req.sendb),
- req->req.length))
- return (-EFAULT);
-
- /* We have to free the request, because we
- * queue no response, and therefore nobody
- * will free it. */
- free_pending_request(req);
- return 0;
- } else {
- DBGMSG("arm_set_buf request exceeded mapping");
- spin_unlock_irqrestore(&host_info_lock, flags);
- return (-EINVAL);
- }
- }
- entry = entry->next;
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
- return (-EINVAL);
-}
-
-static int reset_notification(struct file_info *fi, struct pending_request *req)
-{
- DBGMSG("reset_notification called - switch %s ",
- (req->req.misc == RAW1394_NOTIFY_OFF) ? "OFF" : "ON");
- if ((req->req.misc == RAW1394_NOTIFY_OFF) ||
- (req->req.misc == RAW1394_NOTIFY_ON)) {
- fi->notification = (u8) req->req.misc;
- free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
- return 0;
- }
- /* error EINVAL (22) invalid argument */
- return (-EINVAL);
-}
-
-static int write_phypacket(struct file_info *fi, struct pending_request *req)
-{
- struct hpsb_packet *packet = NULL;
- int retval = 0;
- quadlet_t data;
- unsigned long flags;
-
- data = be32_to_cpu((u32) req->req.sendb);
- DBGMSG("write_phypacket called - quadlet 0x%8.8x ", data);
- packet = hpsb_make_phypacket(fi->host, data);
- if (!packet)
- return -ENOMEM;
- req->req.length = 0;
- req->packet = packet;
- hpsb_set_packet_complete_task(packet,
- (void (*)(void *))queue_complete_cb, req);
- spin_lock_irqsave(&fi->reqlists_lock, flags);
- list_add_tail(&req->list, &fi->req_pending);
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
- packet->generation = req->req.generation;
- retval = hpsb_send_packet(packet);
- DBGMSG("write_phypacket send_packet called => retval: %d ", retval);
- if (retval < 0) {
- req->req.error = RAW1394_ERROR_SEND_ERROR;
- req->req.length = 0;
- queue_complete_req(req);
- }
- return 0;
-}
-
-static int get_config_rom(struct file_info *fi, struct pending_request *req)
-{
- int ret = 0;
- quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL);
- int status;
-
- if (!data)
- return -ENOMEM;
-
- status =
- csr1212_read(fi->host->csr.rom, CSR1212_CONFIG_ROM_SPACE_OFFSET,
- data, req->req.length);
- if (copy_to_user(int2ptr(req->req.recvb), data, req->req.length))
- ret = -EFAULT;
- if (copy_to_user
- (int2ptr(req->req.tag), &fi->host->csr.rom->cache_head->len,
- sizeof(fi->host->csr.rom->cache_head->len)))
- ret = -EFAULT;
- if (copy_to_user(int2ptr(req->req.address), &fi->host->csr.generation,
- sizeof(fi->host->csr.generation)))
- ret = -EFAULT;
- if (copy_to_user(int2ptr(req->req.sendb), &status, sizeof(status)))
- ret = -EFAULT;
- kfree(data);
- if (ret >= 0) {
- free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
- }
- return ret;
-}
-
-static int update_config_rom(struct file_info *fi, struct pending_request *req)
-{
- int ret = 0;
- quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
- if (copy_from_user(data, int2ptr(req->req.sendb), req->req.length)) {
- ret = -EFAULT;
- } else {
- int status = hpsb_update_config_rom(fi->host,
- data, req->req.length,
- (unsigned char)req->req.
- misc);
- if (copy_to_user
- (int2ptr(req->req.recvb), &status, sizeof(status)))
- ret = -ENOMEM;
- }
- kfree(data);
- if (ret >= 0) {
- free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
- fi->cfgrom_upd = 1;
- }
- return ret;
-}
-
-static int modify_config_rom(struct file_info *fi, struct pending_request *req)
-{
- struct csr1212_keyval *kv;
- struct csr1212_csr_rom_cache *cache;
- struct csr1212_dentry *dentry;
- u32 dr;
- int ret = 0;
-
- if (req->req.misc == ~0) {
- if (req->req.length == 0)
- return -EINVAL;
-
- /* Find an unused slot */
- for (dr = 0;
- dr < RAW1394_MAX_USER_CSR_DIRS && fi->csr1212_dirs[dr];
- dr++) ;
-
- if (dr == RAW1394_MAX_USER_CSR_DIRS)
- return -ENOMEM;
-
- fi->csr1212_dirs[dr] =
- csr1212_new_directory(CSR1212_KV_ID_VENDOR);
- if (!fi->csr1212_dirs[dr])
- return -ENOMEM;
- } else {
- dr = req->req.misc;
- if (!fi->csr1212_dirs[dr])
- return -EINVAL;
-
- /* Delete old stuff */
- for (dentry =
- fi->csr1212_dirs[dr]->value.directory.dentries_head;
- dentry; dentry = dentry->next) {
- csr1212_detach_keyval_from_directory(fi->host->csr.rom->
- root_kv,
- dentry->kv);
- }
-
- if (req->req.length == 0) {
- csr1212_release_keyval(fi->csr1212_dirs[dr]);
- fi->csr1212_dirs[dr] = NULL;
-
- hpsb_update_config_rom_image(fi->host);
- free_pending_request(req);
- return 0;
- }
- }
-
- cache = csr1212_rom_cache_malloc(0, req->req.length);
- if (!cache) {
- csr1212_release_keyval(fi->csr1212_dirs[dr]);
- fi->csr1212_dirs[dr] = NULL;
- return -ENOMEM;
- }
-
- cache->filled_head = kmalloc(sizeof(*cache->filled_head), GFP_KERNEL);
- if (!cache->filled_head) {
- csr1212_release_keyval(fi->csr1212_dirs[dr]);
- fi->csr1212_dirs[dr] = NULL;
- CSR1212_FREE(cache);
- return -ENOMEM;
- }
- cache->filled_tail = cache->filled_head;
-
- if (copy_from_user(cache->data, int2ptr(req->req.sendb),
- req->req.length)) {
- csr1212_release_keyval(fi->csr1212_dirs[dr]);
- fi->csr1212_dirs[dr] = NULL;
- ret = -EFAULT;
- } else {
- cache->len = req->req.length;
- cache->filled_head->offset_start = 0;
- cache->filled_head->offset_end = cache->size - 1;
-
- cache->layout_head = cache->layout_tail = fi->csr1212_dirs[dr];
-
- ret = CSR1212_SUCCESS;
- /* parse all the items */
- for (kv = cache->layout_head; ret == CSR1212_SUCCESS && kv;
- kv = kv->next) {
- ret = csr1212_parse_keyval(kv, cache);
- }
-
- /* attach top level items to the root directory */
- for (dentry =
- fi->csr1212_dirs[dr]->value.directory.dentries_head;
- ret == CSR1212_SUCCESS && dentry; dentry = dentry->next) {
- ret =
- csr1212_attach_keyval_to_directory(fi->host->csr.
- rom->root_kv,
- dentry->kv);
- }
-
- if (ret == CSR1212_SUCCESS) {
- ret = hpsb_update_config_rom_image(fi->host);
-
- if (ret >= 0 && copy_to_user(int2ptr(req->req.recvb),
- &dr, sizeof(dr))) {
- ret = -ENOMEM;
- }
- }
- }
- kfree(cache->filled_head);
- CSR1212_FREE(cache);
-
- if (ret >= 0) {
- /* we have to free the request, because we queue no response,
- * and therefore nobody will free it */
- free_pending_request(req);
- return 0;
- } else {
- for (dentry =
- fi->csr1212_dirs[dr]->value.directory.dentries_head;
- dentry; dentry = dentry->next) {
- csr1212_detach_keyval_from_directory(fi->host->csr.rom->
- root_kv,
- dentry->kv);
- }
- csr1212_release_keyval(fi->csr1212_dirs[dr]);
- fi->csr1212_dirs[dr] = NULL;
- return ret;
- }
-}
-
-static int state_connected(struct file_info *fi, struct pending_request *req)
-{
- int node = req->req.address >> 48;
-
- req->req.error = RAW1394_ERROR_NONE;
-
- switch (req->req.type) {
-
- case RAW1394_REQ_ECHO:
- queue_complete_req(req);
- return 0;
-
- case RAW1394_REQ_ARM_REGISTER:
- return arm_register(fi, req);
-
- case RAW1394_REQ_ARM_UNREGISTER:
- return arm_unregister(fi, req);
-
- case RAW1394_REQ_ARM_SET_BUF:
- return arm_set_buf(fi, req);
-
- case RAW1394_REQ_ARM_GET_BUF:
- return arm_get_buf(fi, req);
-
- case RAW1394_REQ_RESET_NOTIFY:
- return reset_notification(fi, req);
-
- case RAW1394_REQ_ISO_SEND:
- case RAW1394_REQ_ISO_LISTEN:
- printk(KERN_DEBUG "raw1394: old iso ABI has been removed\n");
- req->req.error = RAW1394_ERROR_COMPAT;
- req->req.misc = RAW1394_KERNELAPI_VERSION;
- queue_complete_req(req);
- return 0;
-
- case RAW1394_REQ_FCP_LISTEN:
- handle_fcp_listen(fi, req);
- return 0;
-
- case RAW1394_REQ_RESET_BUS:
- if (req->req.misc == RAW1394_LONG_RESET) {
- DBGMSG("busreset called (type: LONG)");
- hpsb_reset_bus(fi->host, LONG_RESET);
- free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
- return 0;
- }
- if (req->req.misc == RAW1394_SHORT_RESET) {
- DBGMSG("busreset called (type: SHORT)");
- hpsb_reset_bus(fi->host, SHORT_RESET);
- free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
- return 0;
- }
- /* error EINVAL (22) invalid argument */
- return (-EINVAL);
- case RAW1394_REQ_GET_ROM:
- return get_config_rom(fi, req);
-
- case RAW1394_REQ_UPDATE_ROM:
- return update_config_rom(fi, req);
-
- case RAW1394_REQ_MODIFY_ROM:
- return modify_config_rom(fi, req);
- }
-
- if (req->req.generation != get_hpsb_generation(fi->host)) {
- req->req.error = RAW1394_ERROR_GENERATION;
- req->req.generation = get_hpsb_generation(fi->host);
- req->req.length = 0;
- queue_complete_req(req);
- return 0;
- }
-
- switch (req->req.type) {
- case RAW1394_REQ_PHYPACKET:
- return write_phypacket(fi, req);
- case RAW1394_REQ_ASYNC_SEND:
- return handle_async_send(fi, req);
- }
-
- if (req->req.length == 0) {
- req->req.error = RAW1394_ERROR_INVALID_ARG;
- queue_complete_req(req);
- return 0;
- }
-
- return handle_async_request(fi, req, node);
-}
-
-static ssize_t raw1394_write(struct file *file, const char __user * buffer,
- size_t count, loff_t * offset_is_ignored)
-{
- struct file_info *fi = file->private_data;
- struct pending_request *req;
- ssize_t retval = -EBADFD;
-
-#ifdef CONFIG_COMPAT
- if (count == sizeof(struct compat_raw1394_req) &&
- sizeof(struct compat_raw1394_req) !=
- sizeof(struct raw1394_request)) {
- buffer = raw1394_compat_write(buffer);
- if (IS_ERR((__force void *)buffer))
- return PTR_ERR((__force void *)buffer);
- } else
-#endif
- if (count != sizeof(struct raw1394_request)) {
- return -EINVAL;
- }
-
- req = alloc_pending_request();
- if (req == NULL) {
- return -ENOMEM;
- }
- req->file_info = fi;
-
- if (copy_from_user(&req->req, buffer, sizeof(struct raw1394_request))) {
- free_pending_request(req);
- return -EFAULT;
- }
-
- if (!mutex_trylock(&fi->state_mutex)) {
- free_pending_request(req);
- return -EAGAIN;
- }
-
- switch (fi->state) {
- case opened:
- retval = state_opened(fi, req);
- break;
-
- case initialized:
- retval = state_initialized(fi, req);
- break;
-
- case connected:
- retval = state_connected(fi, req);
- break;
- }
-
- mutex_unlock(&fi->state_mutex);
-
- if (retval < 0) {
- free_pending_request(req);
- } else {
- BUG_ON(retval);
- retval = count;
- }
-
- return retval;
-}
-
-/* rawiso operations */
-
-/* check if any RAW1394_REQ_RAWISO_ACTIVITY event is already in the
- * completion queue (reqlists_lock must be taken) */
-static inline int __rawiso_event_in_queue(struct file_info *fi)
-{
- struct pending_request *req;
-
- list_for_each_entry(req, &fi->req_complete, list)
- if (req->req.type == RAW1394_REQ_RAWISO_ACTIVITY)
- return 1;
-
- return 0;
-}
-
-/* put a RAWISO_ACTIVITY event in the queue, if one isn't there already */
-static void queue_rawiso_event(struct file_info *fi)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&fi->reqlists_lock, flags);
-
- /* only one ISO activity event may be in the queue */
- if (!__rawiso_event_in_queue(fi)) {
- struct pending_request *req =
- __alloc_pending_request(GFP_ATOMIC);
-
- if (req) {
- req->file_info = fi;
- req->req.type = RAW1394_REQ_RAWISO_ACTIVITY;
- req->req.generation = get_hpsb_generation(fi->host);
- __queue_complete_req(req);
- } else {
- /* on allocation failure, signal an overflow */
- if (fi->iso_handle) {
- atomic_inc(&fi->iso_handle->overflows);
- }
- }
- }
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-}
-
-static void rawiso_activity_cb(struct hpsb_iso *iso)
-{
- unsigned long flags;
- struct host_info *hi;
- struct file_info *fi;
-
- spin_lock_irqsave(&host_info_lock, flags);
- hi = find_host_info(iso->host);
-
- if (hi != NULL) {
- list_for_each_entry(fi, &hi->file_info_list, list) {
- if (fi->iso_handle == iso)
- queue_rawiso_event(fi);
- }
- }
-
- spin_unlock_irqrestore(&host_info_lock, flags);
-}
-
-/* helper function - gather all the kernel iso status bits for returning to user-space */
-static void raw1394_iso_fill_status(struct hpsb_iso *iso,
- struct raw1394_iso_status *stat)
-{
- int overflows = atomic_read(&iso->overflows);
- int skips = atomic_read(&iso->skips);
-
- stat->config.data_buf_size = iso->buf_size;
- stat->config.buf_packets = iso->buf_packets;
- stat->config.channel = iso->channel;
- stat->config.speed = iso->speed;
- stat->config.irq_interval = iso->irq_interval;
- stat->n_packets = hpsb_iso_n_ready(iso);
- stat->overflows = ((skips & 0xFFFF) << 16) | ((overflows & 0xFFFF));
- stat->xmit_cycle = iso->xmit_cycle;
-}
-
-static int raw1394_iso_xmit_init(struct file_info *fi, void __user * uaddr)
-{
- struct raw1394_iso_status stat;
-
- if (!fi->host)
- return -EINVAL;
-
- if (copy_from_user(&stat, uaddr, sizeof(stat)))
- return -EFAULT;
-
- fi->iso_handle = hpsb_iso_xmit_init(fi->host,
- stat.config.data_buf_size,
- stat.config.buf_packets,
- stat.config.channel,
- stat.config.speed,
- stat.config.irq_interval,
- rawiso_activity_cb);
- if (!fi->iso_handle)
- return -ENOMEM;
-
- fi->iso_state = RAW1394_ISO_XMIT;
-
- raw1394_iso_fill_status(fi->iso_handle, &stat);
- if (copy_to_user(uaddr, &stat, sizeof(stat)))
- return -EFAULT;
-
- /* queue an event to get things started */
- rawiso_activity_cb(fi->iso_handle);
-
- return 0;
-}
-
-static int raw1394_iso_recv_init(struct file_info *fi, void __user * uaddr)
-{
- struct raw1394_iso_status stat;
-
- if (!fi->host)
- return -EINVAL;
-
- if (copy_from_user(&stat, uaddr, sizeof(stat)))
- return -EFAULT;
-
- fi->iso_handle = hpsb_iso_recv_init(fi->host,
- stat.config.data_buf_size,
- stat.config.buf_packets,
- stat.config.channel,
- stat.config.dma_mode,
- stat.config.irq_interval,
- rawiso_activity_cb);
- if (!fi->iso_handle)
- return -ENOMEM;
-
- fi->iso_state = RAW1394_ISO_RECV;
-
- raw1394_iso_fill_status(fi->iso_handle, &stat);
- if (copy_to_user(uaddr, &stat, sizeof(stat)))
- return -EFAULT;
- return 0;
-}
-
-static int raw1394_iso_get_status(struct file_info *fi, void __user * uaddr)
-{
- struct raw1394_iso_status stat;
- struct hpsb_iso *iso = fi->iso_handle;
-
- raw1394_iso_fill_status(fi->iso_handle, &stat);
- if (copy_to_user(uaddr, &stat, sizeof(stat)))
- return -EFAULT;
-
- /* reset overflow counter */
- atomic_set(&iso->overflows, 0);
- /* reset skip counter */
- atomic_set(&iso->skips, 0);
-
- return 0;
-}
-
-/* copy N packet_infos out of the ringbuffer into user-supplied array */
-static int raw1394_iso_recv_packets(struct file_info *fi, void __user * uaddr)
-{
- struct raw1394_iso_packets upackets;
- unsigned int packet = fi->iso_handle->first_packet;
- int i;
-
- if (copy_from_user(&upackets, uaddr, sizeof(upackets)))
- return -EFAULT;
-
- if (upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle))
- return -EINVAL;
-
- /* ensure user-supplied buffer is accessible and big enough */
- if (!access_ok(VERIFY_WRITE, upackets.infos,
- upackets.n_packets *
- sizeof(struct raw1394_iso_packet_info)))
- return -EFAULT;
-
- /* copy the packet_infos out */
- for (i = 0; i < upackets.n_packets; i++) {
- if (__copy_to_user(&upackets.infos[i],
- &fi->iso_handle->infos[packet],
- sizeof(struct raw1394_iso_packet_info)))
- return -EFAULT;
-
- packet = (packet + 1) % fi->iso_handle->buf_packets;
- }
-
- return 0;
-}
-
-/* copy N packet_infos from user to ringbuffer, and queue them for transmission */
-static int raw1394_iso_send_packets(struct file_info *fi, void __user * uaddr)
-{
- struct raw1394_iso_packets upackets;
- int i, rv;
-
- if (copy_from_user(&upackets, uaddr, sizeof(upackets)))
- return -EFAULT;
-
- if (upackets.n_packets >= fi->iso_handle->buf_packets)
- return -EINVAL;
-
- if (upackets.n_packets >= hpsb_iso_n_ready(fi->iso_handle))
- return -EAGAIN;
-
- /* ensure user-supplied buffer is accessible and big enough */
- if (!access_ok(VERIFY_READ, upackets.infos,
- upackets.n_packets *
- sizeof(struct raw1394_iso_packet_info)))
- return -EFAULT;
-
- /* copy the infos structs in and queue the packets */
- for (i = 0; i < upackets.n_packets; i++) {
- struct raw1394_iso_packet_info info;
-
- if (__copy_from_user(&info, &upackets.infos[i],
- sizeof(struct raw1394_iso_packet_info)))
- return -EFAULT;
-
- rv = hpsb_iso_xmit_queue_packet(fi->iso_handle, info.offset,
- info.len, info.tag, info.sy);
- if (rv)
- return rv;
- }
-
- return 0;
-}
-
-static void raw1394_iso_shutdown(struct file_info *fi)
-{
- if (fi->iso_handle)
- hpsb_iso_shutdown(fi->iso_handle);
-
- fi->iso_handle = NULL;
- fi->iso_state = RAW1394_ISO_INACTIVE;
-}
-
-static int raw1394_read_cycle_timer(struct file_info *fi, void __user * uaddr)
-{
- struct raw1394_cycle_timer ct;
- int err;
-
- err = hpsb_read_cycle_timer(fi->host, &ct.cycle_timer, &ct.local_time);
- if (!err)
- if (copy_to_user(uaddr, &ct, sizeof(ct)))
- err = -EFAULT;
- return err;
-}
-
-/* mmap the rawiso xmit/recv buffer */
-static int raw1394_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct file_info *fi = file->private_data;
- int ret;
-
- if (!mutex_trylock(&fi->state_mutex))
- return -EAGAIN;
-
- if (fi->iso_state == RAW1394_ISO_INACTIVE)
- ret = -EINVAL;
- else
- ret = dma_region_mmap(&fi->iso_handle->data_buf, file, vma);
-
- mutex_unlock(&fi->state_mutex);
-
- return ret;
-}
-
-static long raw1394_ioctl_inactive(struct file_info *fi, unsigned int cmd,
- void __user *argp)
-{
- switch (cmd) {
- case RAW1394_IOC_ISO_XMIT_INIT:
- return raw1394_iso_xmit_init(fi, argp);
- case RAW1394_IOC_ISO_RECV_INIT:
- return raw1394_iso_recv_init(fi, argp);
- default:
- return -EINVAL;
- }
-}
-
-static long raw1394_ioctl_recv(struct file_info *fi, unsigned int cmd,
- unsigned long arg)
-{
- void __user *argp = (void __user *)arg;
-
- switch (cmd) {
- case RAW1394_IOC_ISO_RECV_START:{
- int args[3];
-
- if (copy_from_user(&args[0], argp, sizeof(args)))
- return -EFAULT;
- return hpsb_iso_recv_start(fi->iso_handle,
- args[0], args[1], args[2]);
- }
- case RAW1394_IOC_ISO_XMIT_RECV_STOP:
- hpsb_iso_stop(fi->iso_handle);
- return 0;
- case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL:
- return hpsb_iso_recv_listen_channel(fi->iso_handle, arg);
- case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL:
- return hpsb_iso_recv_unlisten_channel(fi->iso_handle, arg);
- case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK:{
- u64 mask;
-
- if (copy_from_user(&mask, argp, sizeof(mask)))
- return -EFAULT;
- return hpsb_iso_recv_set_channel_mask(fi->iso_handle,
- mask);
- }
- case RAW1394_IOC_ISO_GET_STATUS:
- return raw1394_iso_get_status(fi, argp);
- case RAW1394_IOC_ISO_RECV_PACKETS:
- return raw1394_iso_recv_packets(fi, argp);
- case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS:
- return hpsb_iso_recv_release_packets(fi->iso_handle, arg);
- case RAW1394_IOC_ISO_RECV_FLUSH:
- return hpsb_iso_recv_flush(fi->iso_handle);
- case RAW1394_IOC_ISO_SHUTDOWN:
- raw1394_iso_shutdown(fi);
- return 0;
- case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
- queue_rawiso_event(fi);
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-static long raw1394_ioctl_xmit(struct file_info *fi, unsigned int cmd,
- void __user *argp)
-{
- switch (cmd) {
- case RAW1394_IOC_ISO_XMIT_START:{
- int args[2];
-
- if (copy_from_user(&args[0], argp, sizeof(args)))
- return -EFAULT;
- return hpsb_iso_xmit_start(fi->iso_handle,
- args[0], args[1]);
- }
- case RAW1394_IOC_ISO_XMIT_SYNC:
- return hpsb_iso_xmit_sync(fi->iso_handle);
- case RAW1394_IOC_ISO_XMIT_RECV_STOP:
- hpsb_iso_stop(fi->iso_handle);
- return 0;
- case RAW1394_IOC_ISO_GET_STATUS:
- return raw1394_iso_get_status(fi, argp);
- case RAW1394_IOC_ISO_XMIT_PACKETS:
- return raw1394_iso_send_packets(fi, argp);
- case RAW1394_IOC_ISO_SHUTDOWN:
- raw1394_iso_shutdown(fi);
- return 0;
- case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
- queue_rawiso_event(fi);
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-/* ioctl is only used for rawiso operations */
-static long raw1394_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct file_info *fi = file->private_data;
- void __user *argp = (void __user *)arg;
- long ret;
-
- /* state-independent commands */
- switch(cmd) {
- case RAW1394_IOC_GET_CYCLE_TIMER:
- return raw1394_read_cycle_timer(fi, argp);
- default:
- break;
- }
-
- if (!mutex_trylock(&fi->state_mutex))
- return -EAGAIN;
-
- switch (fi->iso_state) {
- case RAW1394_ISO_INACTIVE:
- ret = raw1394_ioctl_inactive(fi, cmd, argp);
- break;
- case RAW1394_ISO_RECV:
- ret = raw1394_ioctl_recv(fi, cmd, arg);
- break;
- case RAW1394_ISO_XMIT:
- ret = raw1394_ioctl_xmit(fi, cmd, argp);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- mutex_unlock(&fi->state_mutex);
-
- return ret;
-}
-
-#ifdef CONFIG_COMPAT
-struct raw1394_iso_packets32 {
- __u32 n_packets;
- compat_uptr_t infos;
-} __attribute__((packed));
-
-struct raw1394_cycle_timer32 {
- __u32 cycle_timer;
- __u64 local_time;
-}
-#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
-__attribute__((packed))
-#endif
-;
-
-#define RAW1394_IOC_ISO_RECV_PACKETS32 \
- _IOW ('#', 0x25, struct raw1394_iso_packets32)
-#define RAW1394_IOC_ISO_XMIT_PACKETS32 \
- _IOW ('#', 0x27, struct raw1394_iso_packets32)
-#define RAW1394_IOC_GET_CYCLE_TIMER32 \
- _IOR ('#', 0x30, struct raw1394_cycle_timer32)
-
-static long raw1394_iso_xmit_recv_packets32(struct file *file, unsigned int cmd,
- struct raw1394_iso_packets32 __user *arg)
-{
- compat_uptr_t infos32;
- void __user *infos;
- long err = -EFAULT;
- struct raw1394_iso_packets __user *dst = compat_alloc_user_space(sizeof(struct raw1394_iso_packets));
-
- if (!copy_in_user(&dst->n_packets, &arg->n_packets, sizeof arg->n_packets) &&
- !copy_from_user(&infos32, &arg->infos, sizeof infos32)) {
- infos = compat_ptr(infos32);
- if (!copy_to_user(&dst->infos, &infos, sizeof infos))
- err = raw1394_ioctl(file, cmd, (unsigned long)dst);
- }
- return err;
-}
-
-static long raw1394_read_cycle_timer32(struct file_info *fi, void __user * uaddr)
-{
- struct raw1394_cycle_timer32 ct;
- int err;
-
- err = hpsb_read_cycle_timer(fi->host, &ct.cycle_timer, &ct.local_time);
- if (!err)
- if (copy_to_user(uaddr, &ct, sizeof(ct)))
- err = -EFAULT;
- return err;
-}
-
-static long raw1394_compat_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct file_info *fi = file->private_data;
- void __user *argp = (void __user *)arg;
- long err;
-
- switch (cmd) {
- /* These requests have same format as long as 'int' has same size. */
- case RAW1394_IOC_ISO_RECV_INIT:
- case RAW1394_IOC_ISO_RECV_START:
- case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL:
- case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL:
- case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK:
- case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS:
- case RAW1394_IOC_ISO_RECV_FLUSH:
- case RAW1394_IOC_ISO_XMIT_RECV_STOP:
- case RAW1394_IOC_ISO_XMIT_INIT:
- case RAW1394_IOC_ISO_XMIT_START:
- case RAW1394_IOC_ISO_XMIT_SYNC:
- case RAW1394_IOC_ISO_GET_STATUS:
- case RAW1394_IOC_ISO_SHUTDOWN:
- case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
- err = raw1394_ioctl(file, cmd, arg);
- break;
- /* These request have different format. */
- case RAW1394_IOC_ISO_RECV_PACKETS32:
- err = raw1394_iso_xmit_recv_packets32(file, RAW1394_IOC_ISO_RECV_PACKETS, argp);
- break;
- case RAW1394_IOC_ISO_XMIT_PACKETS32:
- err = raw1394_iso_xmit_recv_packets32(file, RAW1394_IOC_ISO_XMIT_PACKETS, argp);
- break;
- case RAW1394_IOC_GET_CYCLE_TIMER32:
- err = raw1394_read_cycle_timer32(fi, argp);
- break;
- default:
- err = -EINVAL;
- break;
- }
-
- return err;
-}
-#endif
-
-static unsigned int raw1394_poll(struct file *file, poll_table * pt)
-{
- struct file_info *fi = file->private_data;
- unsigned int mask = POLLOUT | POLLWRNORM;
- unsigned long flags;
-
- poll_wait(file, &fi->wait_complete, pt);
-
- spin_lock_irqsave(&fi->reqlists_lock, flags);
- if (!list_empty(&fi->req_complete)) {
- mask |= POLLIN | POLLRDNORM;
- }
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
- return mask;
-}
-
-static int raw1394_open(struct inode *inode, struct file *file)
-{
- struct file_info *fi;
-
- fi = kzalloc(sizeof(*fi), GFP_KERNEL);
- if (!fi)
- return -ENOMEM;
-
- fi->notification = (u8) RAW1394_NOTIFY_ON; /* busreset notification */
-
- INIT_LIST_HEAD(&fi->list);
- mutex_init(&fi->state_mutex);
- fi->state = opened;
- INIT_LIST_HEAD(&fi->req_pending);
- INIT_LIST_HEAD(&fi->req_complete);
- spin_lock_init(&fi->reqlists_lock);
- init_waitqueue_head(&fi->wait_complete);
- INIT_LIST_HEAD(&fi->addr_list);
-
- file->private_data = fi;
-
- return nonseekable_open(inode, file);
-}
-
-static int raw1394_release(struct inode *inode, struct file *file)
-{
- struct file_info *fi = file->private_data;
- struct list_head *lh;
- struct pending_request *req;
- int i, fail;
- int retval = 0;
- struct list_head *entry;
- struct arm_addr *addr = NULL;
- struct host_info *hi;
- struct file_info *fi_hlp = NULL;
- struct arm_addr *arm_addr = NULL;
- int another_host;
- int csr_mod = 0;
- unsigned long flags;
-
- if (fi->iso_state != RAW1394_ISO_INACTIVE)
- raw1394_iso_shutdown(fi);
-
- spin_lock_irqsave(&host_info_lock, flags);
-
- fail = 0;
- /* set address-entries invalid */
-
- while (!list_empty(&fi->addr_list)) {
- another_host = 0;
- lh = fi->addr_list.next;
- addr = list_entry(lh, struct arm_addr, addr_list);
- /* another host with valid address-entry containing
- same addressrange? */
- list_for_each_entry(hi, &host_info_list, list) {
- if (hi->host != fi->host) {
- list_for_each_entry(fi_hlp, &hi->file_info_list,
- list) {
- entry = fi_hlp->addr_list.next;
- while (entry != &(fi_hlp->addr_list)) {
- arm_addr = list_entry(entry, struct
- arm_addr,
- addr_list);
- if (arm_addr->start ==
- addr->start) {
- DBGMSG
- ("raw1394_release: "
- "another host ownes "
- "same addressrange");
- another_host = 1;
- break;
- }
- entry = entry->next;
- }
- if (another_host) {
- break;
- }
- }
- }
- }
- if (!another_host) {
- DBGMSG("raw1394_release: call hpsb_arm_unregister");
- retval =
- hpsb_unregister_addrspace(&raw1394_highlevel,
- fi->host, addr->start);
- if (!retval) {
- ++fail;
- printk(KERN_ERR
- "raw1394_release arm_Unregister failed\n");
- }
- }
- DBGMSG("raw1394_release: delete addr_entry from list");
- list_del(&addr->addr_list);
- vfree(addr->addr_space_buffer);
- kfree(addr);
- } /* while */
- spin_unlock_irqrestore(&host_info_lock, flags);
- if (fail > 0) {
- printk(KERN_ERR "raw1394: during addr_list-release "
- "error(s) occurred \n");
- }
-
- for (;;) {
- /* This locked section guarantees that neither
- * complete nor pending requests exist once i!=0 */
- spin_lock_irqsave(&fi->reqlists_lock, flags);
- while ((req = __next_complete_req(fi)))
- free_pending_request(req);
-
- i = list_empty(&fi->req_pending);
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
- if (i)
- break;
- /*
- * Sleep until more requests can be freed.
- *
- * NB: We call the macro wait_event() with a condition argument
- * with side effect. This is only possible because the side
- * effect does not occur until the condition became true, and
- * wait_event() won't evaluate the condition again after that.
- */
- wait_event(fi->wait_complete, (req = next_complete_req(fi)));
- free_pending_request(req);
- }
-
- /* Remove any sub-trees left by user space programs */
- for (i = 0; i < RAW1394_MAX_USER_CSR_DIRS; i++) {
- struct csr1212_dentry *dentry;
- if (!fi->csr1212_dirs[i])
- continue;
- for (dentry =
- fi->csr1212_dirs[i]->value.directory.dentries_head; dentry;
- dentry = dentry->next) {
- csr1212_detach_keyval_from_directory(fi->host->csr.rom->
- root_kv,
- dentry->kv);
- }
- csr1212_release_keyval(fi->csr1212_dirs[i]);
- fi->csr1212_dirs[i] = NULL;
- csr_mod = 1;
- }
-
- if ((csr_mod || fi->cfgrom_upd)
- && hpsb_update_config_rom_image(fi->host) < 0)
- HPSB_ERR
- ("Failed to generate Configuration ROM image for host %d",
- fi->host->id);
-
- if (fi->state == connected) {
- spin_lock_irqsave(&host_info_lock, flags);
- list_del(&fi->list);
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- put_device(&fi->host->device);
- }
-
- spin_lock_irqsave(&host_info_lock, flags);
- if (fi->host)
- module_put(fi->host->driver->owner);
- spin_unlock_irqrestore(&host_info_lock, flags);
-
- kfree(fi);
-
- return 0;
-}
-
-/*** HOTPLUG STUFF **********************************************************/
-/*
- * Export information about protocols/devices supported by this driver.
- */
-#ifdef MODULE
-static const struct ieee1394_device_id raw1394_id_table[] = {
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = AVC_SW_VERSION_ENTRY & 0xffffff},
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = CAMERA_SW_VERSION_ENTRY & 0xffffff},
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = (CAMERA_SW_VERSION_ENTRY + 1) & 0xffffff},
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff},
- {}
-};
-
-MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table);
-#endif /* MODULE */
-
-static struct hpsb_protocol_driver raw1394_driver = {
- .name = "raw1394",
-};
-
-/******************************************************************************/
-
-static struct hpsb_highlevel raw1394_highlevel = {
- .name = RAW1394_DEVICE_NAME,
- .add_host = add_host,
- .remove_host = remove_host,
- .host_reset = host_reset,
- .fcp_request = fcp_request,
-};
-
-static struct cdev raw1394_cdev;
-static const struct file_operations raw1394_fops = {
- .owner = THIS_MODULE,
- .read = raw1394_read,
- .write = raw1394_write,
- .mmap = raw1394_mmap,
- .unlocked_ioctl = raw1394_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = raw1394_compat_ioctl,
-#endif
- .poll = raw1394_poll,
- .open = raw1394_open,
- .release = raw1394_release,
- .llseek = no_llseek,
-};
-
-static int __init init_raw1394(void)
-{
- int ret = 0;
-
- hpsb_register_highlevel(&raw1394_highlevel);
-
- if (IS_ERR
- (device_create(hpsb_protocol_class, NULL,
- MKDEV(IEEE1394_MAJOR,
- IEEE1394_MINOR_BLOCK_RAW1394 * 16),
- NULL, RAW1394_DEVICE_NAME))) {
- ret = -EFAULT;
- goto out_unreg;
- }
-
- cdev_init(&raw1394_cdev, &raw1394_fops);
- raw1394_cdev.owner = THIS_MODULE;
- ret = cdev_add(&raw1394_cdev, IEEE1394_RAW1394_DEV, 1);
- if (ret) {
- HPSB_ERR("raw1394 failed to register minor device block");
- goto out_dev;
- }
-
- HPSB_INFO("raw1394: /dev/%s device initialized", RAW1394_DEVICE_NAME);
-
- ret = hpsb_register_protocol(&raw1394_driver);
- if (ret) {
- HPSB_ERR("raw1394: failed to register protocol");
- cdev_del(&raw1394_cdev);
- goto out_dev;
- }
-
- goto out;
-
- out_dev:
- device_destroy(hpsb_protocol_class,
- MKDEV(IEEE1394_MAJOR,
- IEEE1394_MINOR_BLOCK_RAW1394 * 16));
- out_unreg:
- hpsb_unregister_highlevel(&raw1394_highlevel);
- out:
- return ret;
-}
-
-static void __exit cleanup_raw1394(void)
-{
- device_destroy(hpsb_protocol_class,
- MKDEV(IEEE1394_MAJOR,
- IEEE1394_MINOR_BLOCK_RAW1394 * 16));
- cdev_del(&raw1394_cdev);
- hpsb_unregister_highlevel(&raw1394_highlevel);
- hpsb_unregister_protocol(&raw1394_driver);
-}
-
-module_init(init_raw1394);
-module_exit(cleanup_raw1394);
-MODULE_LICENSE("GPL");
diff --git a/drivers/ieee1394/raw1394.h b/drivers/ieee1394/raw1394.h
deleted file mode 100644
index 963ac20373d2..000000000000
--- a/drivers/ieee1394/raw1394.h
+++ /dev/null
@@ -1,191 +0,0 @@
-#ifndef IEEE1394_RAW1394_H
-#define IEEE1394_RAW1394_H
-
-/* header for the raw1394 API that is exported to user-space */
-
-#define RAW1394_KERNELAPI_VERSION 4
-
-/* state: opened */
-#define RAW1394_REQ_INITIALIZE 1
-
-/* state: initialized */
-#define RAW1394_REQ_LIST_CARDS 2
-#define RAW1394_REQ_SET_CARD 3
-
-/* state: connected */
-#define RAW1394_REQ_ASYNC_READ 100
-#define RAW1394_REQ_ASYNC_WRITE 101
-#define RAW1394_REQ_LOCK 102
-#define RAW1394_REQ_LOCK64 103
-#define RAW1394_REQ_ISO_SEND 104 /* removed ABI, now a no-op */
-#define RAW1394_REQ_ASYNC_SEND 105
-#define RAW1394_REQ_ASYNC_STREAM 106
-
-#define RAW1394_REQ_ISO_LISTEN 200 /* removed ABI, now a no-op */
-#define RAW1394_REQ_FCP_LISTEN 201
-#define RAW1394_REQ_RESET_BUS 202
-#define RAW1394_REQ_GET_ROM 203
-#define RAW1394_REQ_UPDATE_ROM 204
-#define RAW1394_REQ_ECHO 205
-#define RAW1394_REQ_MODIFY_ROM 206
-
-#define RAW1394_REQ_ARM_REGISTER 300
-#define RAW1394_REQ_ARM_UNREGISTER 301
-#define RAW1394_REQ_ARM_SET_BUF 302
-#define RAW1394_REQ_ARM_GET_BUF 303
-
-#define RAW1394_REQ_RESET_NOTIFY 400
-
-#define RAW1394_REQ_PHYPACKET 500
-
-/* kernel to user */
-#define RAW1394_REQ_BUS_RESET 10000
-#define RAW1394_REQ_ISO_RECEIVE 10001
-#define RAW1394_REQ_FCP_REQUEST 10002
-#define RAW1394_REQ_ARM 10003
-#define RAW1394_REQ_RAWISO_ACTIVITY 10004
-
-/* error codes */
-#define RAW1394_ERROR_NONE 0
-#define RAW1394_ERROR_COMPAT (-1001)
-#define RAW1394_ERROR_STATE_ORDER (-1002)
-#define RAW1394_ERROR_GENERATION (-1003)
-#define RAW1394_ERROR_INVALID_ARG (-1004)
-#define RAW1394_ERROR_MEMFAULT (-1005)
-#define RAW1394_ERROR_ALREADY (-1006)
-
-#define RAW1394_ERROR_EXCESSIVE (-1020)
-#define RAW1394_ERROR_UNTIDY_LEN (-1021)
-
-#define RAW1394_ERROR_SEND_ERROR (-1100)
-#define RAW1394_ERROR_ABORTED (-1101)
-#define RAW1394_ERROR_TIMEOUT (-1102)
-
-/* arm_codes */
-#define ARM_READ 1
-#define ARM_WRITE 2
-#define ARM_LOCK 4
-
-#define RAW1394_LONG_RESET 0
-#define RAW1394_SHORT_RESET 1
-
-/* busresetnotify ... */
-#define RAW1394_NOTIFY_OFF 0
-#define RAW1394_NOTIFY_ON 1
-
-#include <asm/types.h>
-
-struct raw1394_request {
- __u32 type;
- __s32 error;
- __u32 misc;
-
- __u32 generation;
- __u32 length;
-
- __u64 address;
-
- __u64 tag;
-
- __u64 sendb;
- __u64 recvb;
-};
-
-struct raw1394_khost_list {
- __u32 nodes;
- __u8 name[32];
-};
-
-typedef struct arm_request {
- __u16 destination_nodeid;
- __u16 source_nodeid;
- __u64 destination_offset;
- __u8 tlabel;
- __u8 tcode;
- __u8 extended_transaction_code;
- __u32 generation;
- __u16 buffer_length;
- __u8 __user *buffer;
-} *arm_request_t;
-
-typedef struct arm_response {
- __s32 response_code;
- __u16 buffer_length;
- __u8 __user *buffer;
-} *arm_response_t;
-
-typedef struct arm_request_response {
- struct arm_request __user *request;
- struct arm_response __user *response;
-} *arm_request_response_t;
-
-/* rawiso API */
-#include "ieee1394-ioctl.h"
-
-/* per-packet metadata embedded in the ringbuffer */
-/* must be identical to hpsb_iso_packet_info in iso.h! */
-struct raw1394_iso_packet_info {
- __u32 offset;
- __u16 len;
- __u16 cycle; /* recv only */
- __u8 channel; /* recv only */
- __u8 tag;
- __u8 sy;
-};
-
-/* argument for RAW1394_ISO_RECV/XMIT_PACKETS ioctls */
-struct raw1394_iso_packets {
- __u32 n_packets;
- struct raw1394_iso_packet_info __user *infos;
-};
-
-struct raw1394_iso_config {
- /* size of packet data buffer, in bytes (will be rounded up to PAGE_SIZE) */
- __u32 data_buf_size;
-
- /* # of packets to buffer */
- __u32 buf_packets;
-
- /* iso channel (set to -1 for multi-channel recv) */
- __s32 channel;
-
- /* xmit only - iso transmission speed */
- __u8 speed;
-
- /* The mode of the dma when receiving iso data. Must be supported by chip */
- __u8 dma_mode;
-
- /* max. latency of buffer, in packets (-1 if you don't care) */
- __s32 irq_interval;
-};
-
-/* argument to RAW1394_ISO_XMIT/RECV_INIT and RAW1394_ISO_GET_STATUS */
-struct raw1394_iso_status {
- /* current settings */
- struct raw1394_iso_config config;
-
- /* number of packets waiting to be filled with data (ISO transmission)
- or containing data received (ISO reception) */
- __u32 n_packets;
-
- /* approximate number of packets dropped due to overflow or
- underflow of the packet buffer (a value of zero guarantees
- that no packets have been dropped) */
- __u32 overflows;
-
- /* cycle number at which next packet will be transmitted;
- -1 if not known */
- __s16 xmit_cycle;
-};
-
-/* argument to RAW1394_IOC_GET_CYCLE_TIMER ioctl */
-struct raw1394_cycle_timer {
- /* contents of Isochronous Cycle Timer register,
- as in OHCI 1.1 clause 5.13 (also with non-OHCI hosts) */
- __u32 cycle_timer;
-
- /* local time in microseconds since Epoch,
- simultaneously read with cycle timer */
- __u64 local_time;
-};
-#endif /* IEEE1394_RAW1394_H */
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
deleted file mode 100644
index d6e251a300ce..000000000000
--- a/drivers/ieee1394/sbp2.c
+++ /dev/null
@@ -1,2138 +0,0 @@
-/*
- * sbp2.c - SBP-2 protocol driver for IEEE-1394
- *
- * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com)
- * jamesg@filanet.com (JSG)
- *
- * Copyright (C) 2003 Ben Collins <bcollins@debian.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.
- */
-
-/*
- * Brief Description:
- *
- * This driver implements the Serial Bus Protocol 2 (SBP-2) over IEEE-1394
- * under Linux. The SBP-2 driver is implemented as an IEEE-1394 high-level
- * driver. It also registers as a SCSI lower-level driver in order to accept
- * SCSI commands for transport using SBP-2.
- *
- * You may access any attached SBP-2 (usually storage devices) as regular
- * SCSI devices. E.g. mount /dev/sda1, fdisk, mkfs, etc..
- *
- * See http://www.t10.org/drafts.htm#sbp2 for the final draft of the SBP-2
- * specification and for where to purchase the official standard.
- *
- * TODO:
- * - look into possible improvements of the SCSI error handlers
- * - handle Unit_Characteristics.mgt_ORB_timeout and .ORB_size
- * - handle Logical_Unit_Number.ordered
- * - handle src == 1 in status blocks
- * - reimplement the DMA mapping in absence of physical DMA so that
- * bus_to_virt is no longer required
- * - debug the handling of absent physical DMA
- * - replace CONFIG_IEEE1394_SBP2_PHYS_DMA by automatic detection
- * (this is easy but depends on the previous two TODO items)
- * - make the parameter serialize_io configurable per device
- * - move all requests to fetch agent registers into non-atomic context,
- * replace all usages of sbp2util_node_write_no_wait by true transactions
- * Grep for inline FIXME comments below.
- */
-
-#include <linux/blkdev.h>
-#include <linux/compiler.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/stringify.h>
-#include <linux/types.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <linux/scatterlist.h>
-
-#include <asm/byteorder.h>
-#include <asm/errno.h>
-#include <asm/param.h>
-#include <asm/system.h>
-#include <asm/types.h>
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
-#include <asm/io.h> /* for bus_to_virt */
-#endif
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-
-#include "csr1212.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-#include "nodemgr.h"
-#include "sbp2.h"
-
-/*
- * Module load parameter definitions
- */
-
-/*
- * Change max_speed on module load if you have a bad IEEE-1394
- * controller that has trouble running 2KB packets at 400mb.
- *
- * NOTE: On certain OHCI parts I have seen short packets on async transmit
- * (probably due to PCI latency/throughput issues with the part). You can
- * bump down the speed if you are running into problems.
- */
-static int sbp2_max_speed = IEEE1394_SPEED_MAX;
-module_param_named(max_speed, sbp2_max_speed, int, 0644);
-MODULE_PARM_DESC(max_speed, "Limit data transfer speed (5 <= 3200, "
- "4 <= 1600, 3 <= 800, 2 <= 400, 1 <= 200, 0 = 100 Mb/s)");
-
-/*
- * Set serialize_io to 0 or N to use dynamically appended lists of command ORBs.
- * This is and always has been buggy in multiple subtle ways. See above TODOs.
- */
-static int sbp2_serialize_io = 1;
-module_param_named(serialize_io, sbp2_serialize_io, bool, 0444);
-MODULE_PARM_DESC(serialize_io, "Serialize requests coming from SCSI drivers "
- "(default = Y, faster but buggy = N)");
-
-/*
- * Adjust max_sectors if you'd like to influence how many sectors each SCSI
- * command can transfer at most. Please note that some older SBP-2 bridge
- * chips are broken for transfers greater or equal to 128KB, therefore
- * max_sectors used to be a safe 255 sectors for many years. We now have a
- * default of 0 here which means that we let the SCSI stack choose a limit.
- *
- * The SBP2_WORKAROUND_128K_MAX_TRANS flag, if set either in the workarounds
- * module parameter or in the sbp2_workarounds_table[], will override the
- * value of max_sectors. We should use sbp2_workarounds_table[] to cover any
- * bridge chip which becomes known to need the 255 sectors limit.
- */
-static int sbp2_max_sectors;
-module_param_named(max_sectors, sbp2_max_sectors, int, 0444);
-MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported "
- "(default = 0 = use SCSI stack's default)");
-
-/*
- * Exclusive login to sbp2 device? In most cases, the sbp2 driver should
- * do an exclusive login, as it's generally unsafe to have two hosts
- * talking to a single sbp2 device at the same time (filesystem coherency,
- * etc.). If you're running an sbp2 device that supports multiple logins,
- * and you're either running read-only filesystems or some sort of special
- * filesystem supporting multiple hosts, e.g. OpenGFS, Oracle Cluster
- * File System, or Lustre, then set exclusive_login to zero.
- *
- * So far only bridges from Oxford Semiconductor are known to support
- * concurrent logins. Depending on firmware, four or two concurrent logins
- * are possible on OXFW911 and newer Oxsemi bridges.
- */
-static int sbp2_exclusive_login = 1;
-module_param_named(exclusive_login, sbp2_exclusive_login, bool, 0644);
-MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
- "(default = Y, use N for concurrent initiators)");
-
-/*
- * If any of the following workarounds is required for your device to work,
- * please submit the kernel messages logged by sbp2 to the linux1394-devel
- * mailing list.
- *
- * - 128kB max transfer
- * Limit transfer size. Necessary for some old bridges.
- *
- * - 36 byte inquiry
- * When scsi_mod probes the device, let the inquiry command look like that
- * from MS Windows.
- *
- * - skip mode page 8
- * Suppress sending of mode_sense for mode page 8 if the device pretends to
- * support the SCSI Primary Block commands instead of Reduced Block Commands.
- *
- * - fix capacity
- * Tell sd_mod to correct the last sector number reported by read_capacity.
- * Avoids access beyond actual disk limits on devices with an off-by-one bug.
- * Don't use this with devices which don't have this bug.
- *
- * - delay inquiry
- * Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
- *
- * - power condition
- * Set the power condition field in the START STOP UNIT commands sent by
- * sd_mod on suspend, resume, and shutdown (if manage_start_stop is on).
- * Some disks need this to spin down or to resume properly.
- *
- * - override internal blacklist
- * Instead of adding to the built-in blacklist, use only the workarounds
- * specified in the module load parameter.
- * Useful if a blacklist entry interfered with a non-broken device.
- */
-static int sbp2_default_workarounds;
-module_param_named(workarounds, sbp2_default_workarounds, int, 0644);
-MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
- ", 128kB max transfer = " __stringify(SBP2_WORKAROUND_128K_MAX_TRANS)
- ", 36 byte inquiry = " __stringify(SBP2_WORKAROUND_INQUIRY_36)
- ", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
- ", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
- ", delay inquiry = " __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
- ", set power condition in start stop unit = "
- __stringify(SBP2_WORKAROUND_POWER_CONDITION)
- ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
- ", or a combination)");
-
-/*
- * This influences the format of the sysfs attribute
- * /sys/bus/scsi/devices/.../ieee1394_id.
- *
- * The default format is like in older kernels: %016Lx:%d:%d
- * It contains the target's EUI-64, a number given to the logical unit by
- * the ieee1394 driver's nodemgr (starting at 0), and the LUN.
- *
- * The long format is: %016Lx:%06x:%04x
- * It contains the target's EUI-64, the unit directory's directory_ID as per
- * IEEE 1212 clause 7.7.19, and the LUN. This format comes closest to the
- * format of SBP(-3) target port and logical unit identifier as per SAM (SCSI
- * Architecture Model) rev.2 to 4 annex A. Therefore and because it is
- * independent of the implementation of the ieee1394 nodemgr, the longer format
- * is recommended for future use.
- */
-static int sbp2_long_sysfs_ieee1394_id;
-module_param_named(long_ieee1394_id, sbp2_long_sysfs_ieee1394_id, bool, 0644);
-MODULE_PARM_DESC(long_ieee1394_id, "8+3+2 bytes format of ieee1394_id in sysfs "
- "(default = backwards-compatible = N, SAM-conforming = Y)");
-
-
-#define SBP2_INFO(fmt, args...) HPSB_INFO("sbp2: "fmt, ## args)
-#define SBP2_ERR(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args)
-
-/*
- * Globals
- */
-static void sbp2scsi_complete_all_commands(struct sbp2_lu *, u32);
-static void sbp2scsi_complete_command(struct sbp2_lu *, u32, struct scsi_cmnd *,
- void (*)(struct scsi_cmnd *));
-static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *);
-static int sbp2_start_device(struct sbp2_lu *);
-static void sbp2_remove_device(struct sbp2_lu *);
-static int sbp2_login_device(struct sbp2_lu *);
-static int sbp2_reconnect_device(struct sbp2_lu *);
-static int sbp2_logout_device(struct sbp2_lu *);
-static void sbp2_host_reset(struct hpsb_host *);
-static int sbp2_handle_status_write(struct hpsb_host *, int, int, quadlet_t *,
- u64, size_t, u16);
-static int sbp2_agent_reset(struct sbp2_lu *, int);
-static void sbp2_parse_unit_directory(struct sbp2_lu *,
- struct unit_directory *);
-static int sbp2_set_busy_timeout(struct sbp2_lu *);
-static int sbp2_max_speed_and_size(struct sbp2_lu *);
-
-
-static const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xa, 0xa, 0xa };
-
-static DEFINE_RWLOCK(sbp2_hi_logical_units_lock);
-
-static struct hpsb_highlevel sbp2_highlevel = {
- .name = SBP2_DEVICE_NAME,
- .host_reset = sbp2_host_reset,
-};
-
-static const struct hpsb_address_ops sbp2_ops = {
- .write = sbp2_handle_status_write
-};
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
-static int sbp2_handle_physdma_write(struct hpsb_host *, int, int, quadlet_t *,
- u64, size_t, u16);
-static int sbp2_handle_physdma_read(struct hpsb_host *, int, quadlet_t *, u64,
- size_t, u16);
-
-static const struct hpsb_address_ops sbp2_physdma_ops = {
- .read = sbp2_handle_physdma_read,
- .write = sbp2_handle_physdma_write,
-};
-#endif
-
-
-/*
- * Interface to driver core and IEEE 1394 core
- */
-static const struct ieee1394_device_id sbp2_id_table[] = {
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = SBP2_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = SBP2_SW_VERSION_ENTRY & 0xffffff},
- {}
-};
-MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table);
-
-static int sbp2_probe(struct device *);
-static int sbp2_remove(struct device *);
-static int sbp2_update(struct unit_directory *);
-
-static struct hpsb_protocol_driver sbp2_driver = {
- .name = SBP2_DEVICE_NAME,
- .id_table = sbp2_id_table,
- .update = sbp2_update,
- .driver = {
- .probe = sbp2_probe,
- .remove = sbp2_remove,
- },
-};
-
-
-/*
- * Interface to SCSI core
- */
-static int sbp2scsi_queuecommand(struct scsi_cmnd *,
- void (*)(struct scsi_cmnd *));
-static int sbp2scsi_abort(struct scsi_cmnd *);
-static int sbp2scsi_reset(struct scsi_cmnd *);
-static int sbp2scsi_slave_alloc(struct scsi_device *);
-static int sbp2scsi_slave_configure(struct scsi_device *);
-static void sbp2scsi_slave_destroy(struct scsi_device *);
-static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *,
- struct device_attribute *, char *);
-
-static DEVICE_ATTR(ieee1394_id, S_IRUGO, sbp2_sysfs_ieee1394_id_show, NULL);
-
-static struct device_attribute *sbp2_sysfs_sdev_attrs[] = {
- &dev_attr_ieee1394_id,
- NULL
-};
-
-static struct scsi_host_template sbp2_shost_template = {
- .module = THIS_MODULE,
- .name = "SBP-2 IEEE-1394",
- .proc_name = SBP2_DEVICE_NAME,
- .queuecommand = sbp2scsi_queuecommand,
- .eh_abort_handler = sbp2scsi_abort,
- .eh_device_reset_handler = sbp2scsi_reset,
- .slave_alloc = sbp2scsi_slave_alloc,
- .slave_configure = sbp2scsi_slave_configure,
- .slave_destroy = sbp2scsi_slave_destroy,
- .this_id = -1,
- .sg_tablesize = SG_ALL,
- .use_clustering = ENABLE_CLUSTERING,
- .cmd_per_lun = SBP2_MAX_CMDS,
- .can_queue = SBP2_MAX_CMDS,
- .sdev_attrs = sbp2_sysfs_sdev_attrs,
-};
-
-#define SBP2_ROM_VALUE_WILDCARD ~0 /* match all */
-#define SBP2_ROM_VALUE_MISSING 0xff000000 /* not present in the unit dir. */
-
-/*
- * List of devices with known bugs.
- *
- * The firmware_revision field, masked with 0xffff00, is the best indicator
- * for the type of bridge chip of a device. It yields a few false positives
- * but this did not break correctly behaving devices so far.
- */
-static const struct {
- u32 firmware_revision;
- u32 model;
- unsigned workarounds;
-} sbp2_workarounds_table[] = {
- /* DViCO Momobay CX-1 with TSB42AA9 bridge */ {
- .firmware_revision = 0x002800,
- .model = 0x001010,
- .workarounds = SBP2_WORKAROUND_INQUIRY_36 |
- SBP2_WORKAROUND_MODE_SENSE_8 |
- SBP2_WORKAROUND_POWER_CONDITION,
- },
- /* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
- .firmware_revision = 0x002800,
- .model = 0x000000,
- .workarounds = SBP2_WORKAROUND_POWER_CONDITION,
- },
- /* Initio bridges, actually only needed for some older ones */ {
- .firmware_revision = 0x000200,
- .model = SBP2_ROM_VALUE_WILDCARD,
- .workarounds = SBP2_WORKAROUND_INQUIRY_36,
- },
- /* PL-3507 bridge with Prolific firmware */ {
- .firmware_revision = 0x012800,
- .model = SBP2_ROM_VALUE_WILDCARD,
- .workarounds = SBP2_WORKAROUND_POWER_CONDITION,
- },
- /* Symbios bridge */ {
- .firmware_revision = 0xa0b800,
- .model = SBP2_ROM_VALUE_WILDCARD,
- .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS,
- },
- /* Datafab MD2-FW2 with Symbios/LSILogic SYM13FW500 bridge */ {
- .firmware_revision = 0x002600,
- .model = SBP2_ROM_VALUE_WILDCARD,
- .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS,
- },
- /*
- * iPod 2nd generation: needs 128k max transfer size workaround
- * iPod 3rd generation: needs fix capacity workaround
- */
- {
- .firmware_revision = 0x0a2700,
- .model = 0x000000,
- .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS |
- SBP2_WORKAROUND_FIX_CAPACITY,
- },
- /* iPod 4th generation */ {
- .firmware_revision = 0x0a2700,
- .model = 0x000021,
- .workarounds = SBP2_WORKAROUND_FIX_CAPACITY,
- },
- /* iPod mini */ {
- .firmware_revision = 0x0a2700,
- .model = 0x000022,
- .workarounds = SBP2_WORKAROUND_FIX_CAPACITY,
- },
- /* iPod mini */ {
- .firmware_revision = 0x0a2700,
- .model = 0x000023,
- .workarounds = SBP2_WORKAROUND_FIX_CAPACITY,
- },
- /* iPod Photo */ {
- .firmware_revision = 0x0a2700,
- .model = 0x00007e,
- .workarounds = SBP2_WORKAROUND_FIX_CAPACITY,
- }
-};
-
-/**************************************
- * General utility functions
- **************************************/
-
-#ifndef __BIG_ENDIAN
-/*
- * Converts a buffer from be32 to cpu byte ordering. Length is in bytes.
- */
-static inline void sbp2util_be32_to_cpu_buffer(void *buffer, int length)
-{
- u32 *temp = buffer;
-
- for (length = (length >> 2); length--; )
- temp[length] = be32_to_cpu(temp[length]);
-}
-
-/*
- * Converts a buffer from cpu to be32 byte ordering. Length is in bytes.
- */
-static inline void sbp2util_cpu_to_be32_buffer(void *buffer, int length)
-{
- u32 *temp = buffer;
-
- for (length = (length >> 2); length--; )
- temp[length] = cpu_to_be32(temp[length]);
-}
-#else /* BIG_ENDIAN */
-/* Why waste the cpu cycles? */
-#define sbp2util_be32_to_cpu_buffer(x,y) do {} while (0)
-#define sbp2util_cpu_to_be32_buffer(x,y) do {} while (0)
-#endif
-
-static DECLARE_WAIT_QUEUE_HEAD(sbp2_access_wq);
-
-/*
- * Waits for completion of an SBP-2 access request.
- * Returns nonzero if timed out or prematurely interrupted.
- */
-static int sbp2util_access_timeout(struct sbp2_lu *lu, int timeout)
-{
- long leftover;
-
- leftover = wait_event_interruptible_timeout(
- sbp2_access_wq, lu->access_complete, timeout);
- lu->access_complete = 0;
- return leftover <= 0;
-}
-
-static void sbp2_free_packet(void *packet)
-{
- hpsb_free_tlabel(packet);
- hpsb_free_packet(packet);
-}
-
-/*
- * This is much like hpsb_node_write(), except it ignores the response
- * subaction and returns immediately. Can be used from atomic context.
- */
-static int sbp2util_node_write_no_wait(struct node_entry *ne, u64 addr,
- quadlet_t *buf, size_t len)
-{
- struct hpsb_packet *packet;
-
- packet = hpsb_make_writepacket(ne->host, ne->nodeid, addr, buf, len);
- if (!packet)
- return -ENOMEM;
-
- hpsb_set_packet_complete_task(packet, sbp2_free_packet, packet);
- hpsb_node_fill_packet(ne, packet);
- if (hpsb_send_packet(packet) < 0) {
- sbp2_free_packet(packet);
- return -EIO;
- }
- return 0;
-}
-
-static void sbp2util_notify_fetch_agent(struct sbp2_lu *lu, u64 offset,
- quadlet_t *data, size_t len)
-{
- /* There is a small window after a bus reset within which the node
- * entry's generation is current but the reconnect wasn't completed. */
- if (unlikely(atomic_read(&lu->state) == SBP2LU_STATE_IN_RESET))
- return;
-
- if (hpsb_node_write(lu->ne, lu->command_block_agent_addr + offset,
- data, len))
- SBP2_ERR("sbp2util_notify_fetch_agent failed.");
-
- /* Now accept new SCSI commands, unless a bus reset happended during
- * hpsb_node_write. */
- if (likely(atomic_read(&lu->state) != SBP2LU_STATE_IN_RESET))
- scsi_unblock_requests(lu->shost);
-}
-
-static void sbp2util_write_orb_pointer(struct work_struct *work)
-{
- struct sbp2_lu *lu = container_of(work, struct sbp2_lu, protocol_work);
- quadlet_t data[2];
-
- data[0] = ORB_SET_NODE_ID(lu->hi->host->node_id);
- data[1] = lu->last_orb_dma;
- sbp2util_cpu_to_be32_buffer(data, 8);
- sbp2util_notify_fetch_agent(lu, SBP2_ORB_POINTER_OFFSET, data, 8);
-}
-
-static void sbp2util_write_doorbell(struct work_struct *work)
-{
- struct sbp2_lu *lu = container_of(work, struct sbp2_lu, protocol_work);
-
- sbp2util_notify_fetch_agent(lu, SBP2_DOORBELL_OFFSET, NULL, 4);
-}
-
-static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu)
-{
- struct sbp2_command_info *cmd;
- struct device *dmadev = lu->hi->host->device.parent;
- int i, orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS;
-
- for (i = 0; i < orbs; i++) {
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd)
- goto failed_alloc;
-
- cmd->command_orb_dma =
- dma_map_single(dmadev, &cmd->command_orb,
- sizeof(struct sbp2_command_orb),
- DMA_TO_DEVICE);
- if (dma_mapping_error(dmadev, cmd->command_orb_dma))
- goto failed_orb;
-
- cmd->sge_dma =
- dma_map_single(dmadev, &cmd->scatter_gather_element,
- sizeof(cmd->scatter_gather_element),
- DMA_TO_DEVICE);
- if (dma_mapping_error(dmadev, cmd->sge_dma))
- goto failed_sge;
-
- INIT_LIST_HEAD(&cmd->list);
- list_add_tail(&cmd->list, &lu->cmd_orb_completed);
- }
- return 0;
-
-failed_sge:
- dma_unmap_single(dmadev, cmd->command_orb_dma,
- sizeof(struct sbp2_command_orb), DMA_TO_DEVICE);
-failed_orb:
- kfree(cmd);
-failed_alloc:
- return -ENOMEM;
-}
-
-static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu,
- struct hpsb_host *host)
-{
- struct list_head *lh, *next;
- struct sbp2_command_info *cmd;
- unsigned long flags;
-
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- if (!list_empty(&lu->cmd_orb_completed))
- list_for_each_safe(lh, next, &lu->cmd_orb_completed) {
- cmd = list_entry(lh, struct sbp2_command_info, list);
- dma_unmap_single(host->device.parent,
- cmd->command_orb_dma,
- sizeof(struct sbp2_command_orb),
- DMA_TO_DEVICE);
- dma_unmap_single(host->device.parent, cmd->sge_dma,
- sizeof(cmd->scatter_gather_element),
- DMA_TO_DEVICE);
- kfree(cmd);
- }
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
- return;
-}
-
-/*
- * Finds the sbp2_command for a given outstanding command ORB.
- * Only looks at the in-use list.
- */
-static struct sbp2_command_info *sbp2util_find_command_for_orb(
- struct sbp2_lu *lu, dma_addr_t orb)
-{
- struct sbp2_command_info *cmd;
- unsigned long flags;
-
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- if (!list_empty(&lu->cmd_orb_inuse))
- list_for_each_entry(cmd, &lu->cmd_orb_inuse, list)
- if (cmd->command_orb_dma == orb) {
- spin_unlock_irqrestore(
- &lu->cmd_orb_lock, flags);
- return cmd;
- }
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
- return NULL;
-}
-
-/*
- * Finds the sbp2_command for a given outstanding SCpnt.
- * Only looks at the in-use list.
- * Must be called with lu->cmd_orb_lock held.
- */
-static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(
- struct sbp2_lu *lu, void *SCpnt)
-{
- struct sbp2_command_info *cmd;
-
- if (!list_empty(&lu->cmd_orb_inuse))
- list_for_each_entry(cmd, &lu->cmd_orb_inuse, list)
- if (cmd->Current_SCpnt == SCpnt)
- return cmd;
- return NULL;
-}
-
-static struct sbp2_command_info *sbp2util_allocate_command_orb(
- struct sbp2_lu *lu,
- struct scsi_cmnd *Current_SCpnt,
- void (*Current_done)(struct scsi_cmnd *))
-{
- struct list_head *lh;
- struct sbp2_command_info *cmd = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- if (!list_empty(&lu->cmd_orb_completed)) {
- lh = lu->cmd_orb_completed.next;
- list_del(lh);
- cmd = list_entry(lh, struct sbp2_command_info, list);
- cmd->Current_done = Current_done;
- cmd->Current_SCpnt = Current_SCpnt;
- list_add_tail(&cmd->list, &lu->cmd_orb_inuse);
- } else
- SBP2_ERR("%s: no orbs available", __func__);
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
- return cmd;
-}
-
-/*
- * Unmaps the DMAs of a command and moves the command to the completed ORB list.
- * Must be called with lu->cmd_orb_lock held.
- */
-static void sbp2util_mark_command_completed(struct sbp2_lu *lu,
- struct sbp2_command_info *cmd)
-{
- if (scsi_sg_count(cmd->Current_SCpnt))
- dma_unmap_sg(lu->ud->ne->host->device.parent,
- scsi_sglist(cmd->Current_SCpnt),
- scsi_sg_count(cmd->Current_SCpnt),
- cmd->Current_SCpnt->sc_data_direction);
- list_move_tail(&cmd->list, &lu->cmd_orb_completed);
-}
-
-/*
- * Is lu valid? Is the 1394 node still present?
- */
-static inline int sbp2util_node_is_available(struct sbp2_lu *lu)
-{
- return lu && lu->ne && !lu->ne->in_limbo;
-}
-
-/*********************************************
- * IEEE-1394 core driver stack related section
- *********************************************/
-
-static int sbp2_probe(struct device *dev)
-{
- struct unit_directory *ud;
- struct sbp2_lu *lu;
-
- ud = container_of(dev, struct unit_directory, device);
-
- /* Don't probe UD's that have the LUN flag. We'll probe the LUN(s)
- * instead. */
- if (ud->flags & UNIT_DIRECTORY_HAS_LUN_DIRECTORY)
- return -ENODEV;
-
- lu = sbp2_alloc_device(ud);
- if (!lu)
- return -ENOMEM;
-
- sbp2_parse_unit_directory(lu, ud);
- return sbp2_start_device(lu);
-}
-
-static int sbp2_remove(struct device *dev)
-{
- struct unit_directory *ud;
- struct sbp2_lu *lu;
- struct scsi_device *sdev;
-
- ud = container_of(dev, struct unit_directory, device);
- lu = dev_get_drvdata(&ud->device);
- if (!lu)
- return 0;
-
- if (lu->shost) {
- /* Get rid of enqueued commands if there is no chance to
- * send them. */
- if (!sbp2util_node_is_available(lu))
- sbp2scsi_complete_all_commands(lu, DID_NO_CONNECT);
- /* scsi_remove_device() may trigger shutdown functions of SCSI
- * highlevel drivers which would deadlock if blocked. */
- atomic_set(&lu->state, SBP2LU_STATE_IN_SHUTDOWN);
- scsi_unblock_requests(lu->shost);
- }
- sdev = lu->sdev;
- if (sdev) {
- lu->sdev = NULL;
- scsi_remove_device(sdev);
- }
-
- sbp2_logout_device(lu);
- sbp2_remove_device(lu);
-
- return 0;
-}
-
-static int sbp2_update(struct unit_directory *ud)
-{
- struct sbp2_lu *lu = dev_get_drvdata(&ud->device);
-
- if (sbp2_reconnect_device(lu) != 0) {
- /*
- * Reconnect failed. If another bus reset happened,
- * let nodemgr proceed and call sbp2_update again later
- * (or sbp2_remove if this node went away).
- */
- if (!hpsb_node_entry_valid(lu->ne))
- return 0;
- /*
- * Or the target rejected the reconnect because we weren't
- * fast enough. Try a regular login, but first log out
- * just in case of any weirdness.
- */
- sbp2_logout_device(lu);
-
- if (sbp2_login_device(lu) != 0) {
- if (!hpsb_node_entry_valid(lu->ne))
- return 0;
-
- /* Maybe another initiator won the login. */
- SBP2_ERR("Failed to reconnect to sbp2 device!");
- return -EBUSY;
- }
- }
-
- sbp2_set_busy_timeout(lu);
- sbp2_agent_reset(lu, 1);
- sbp2_max_speed_and_size(lu);
-
- /* Complete any pending commands with busy (so they get retried)
- * and remove them from our queue. */
- sbp2scsi_complete_all_commands(lu, DID_BUS_BUSY);
-
- /* Accept new commands unless there was another bus reset in the
- * meantime. */
- if (hpsb_node_entry_valid(lu->ne)) {
- atomic_set(&lu->state, SBP2LU_STATE_RUNNING);
- scsi_unblock_requests(lu->shost);
- }
- return 0;
-}
-
-static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud)
-{
- struct sbp2_fwhost_info *hi;
- struct Scsi_Host *shost = NULL;
- struct sbp2_lu *lu = NULL;
- unsigned long flags;
-
- lu = kzalloc(sizeof(*lu), GFP_KERNEL);
- if (!lu) {
- SBP2_ERR("failed to create lu");
- goto failed_alloc;
- }
-
- lu->ne = ud->ne;
- lu->ud = ud;
- lu->speed_code = IEEE1394_SPEED_100;
- lu->max_payload_size = sbp2_speedto_max_payload[IEEE1394_SPEED_100];
- lu->status_fifo_addr = CSR1212_INVALID_ADDR_SPACE;
- INIT_LIST_HEAD(&lu->cmd_orb_inuse);
- INIT_LIST_HEAD(&lu->cmd_orb_completed);
- INIT_LIST_HEAD(&lu->lu_list);
- spin_lock_init(&lu->cmd_orb_lock);
- atomic_set(&lu->state, SBP2LU_STATE_RUNNING);
- INIT_WORK(&lu->protocol_work, NULL);
-
- dev_set_drvdata(&ud->device, lu);
-
- hi = hpsb_get_hostinfo(&sbp2_highlevel, ud->ne->host);
- if (!hi) {
- hi = hpsb_create_hostinfo(&sbp2_highlevel, ud->ne->host,
- sizeof(*hi));
- if (!hi) {
- SBP2_ERR("failed to allocate hostinfo");
- goto failed_alloc;
- }
- hi->host = ud->ne->host;
- INIT_LIST_HEAD(&hi->logical_units);
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
- /* Handle data movement if physical dma is not
- * enabled or not supported on host controller */
- if (!hpsb_register_addrspace(&sbp2_highlevel, ud->ne->host,
- &sbp2_physdma_ops,
- 0x0ULL, 0xfffffffcULL)) {
- SBP2_ERR("failed to register lower 4GB address range");
- goto failed_alloc;
- }
-#endif
- }
-
- if (dma_get_max_seg_size(hi->host->device.parent) > SBP2_MAX_SEG_SIZE)
- BUG_ON(dma_set_max_seg_size(hi->host->device.parent,
- SBP2_MAX_SEG_SIZE));
-
- /* Prevent unloading of the 1394 host */
- if (!try_module_get(hi->host->driver->owner)) {
- SBP2_ERR("failed to get a reference on 1394 host driver");
- goto failed_alloc;
- }
-
- lu->hi = hi;
-
- write_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
- list_add_tail(&lu->lu_list, &hi->logical_units);
- write_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-
- /* Register the status FIFO address range. We could use the same FIFO
- * for targets at different nodes. However we need different FIFOs per
- * target in order to support multi-unit devices.
- * The FIFO is located out of the local host controller's physical range
- * but, if possible, within the posted write area. Status writes will
- * then be performed as unified transactions. This slightly reduces
- * bandwidth usage, and some Prolific based devices seem to require it.
- */
- lu->status_fifo_addr = hpsb_allocate_and_register_addrspace(
- &sbp2_highlevel, ud->ne->host, &sbp2_ops,
- sizeof(struct sbp2_status_block), sizeof(quadlet_t),
- ud->ne->host->low_addr_space, CSR1212_ALL_SPACE_END);
- if (lu->status_fifo_addr == CSR1212_INVALID_ADDR_SPACE) {
- SBP2_ERR("failed to allocate status FIFO address range");
- goto failed_alloc;
- }
-
- shost = scsi_host_alloc(&sbp2_shost_template, sizeof(unsigned long));
- if (!shost) {
- SBP2_ERR("failed to register scsi host");
- goto failed_alloc;
- }
-
- shost->hostdata[0] = (unsigned long)lu;
- shost->max_cmd_len = SBP2_MAX_CDB_SIZE;
-
- if (!scsi_add_host(shost, &ud->device)) {
- lu->shost = shost;
- return lu;
- }
-
- SBP2_ERR("failed to add scsi host");
- scsi_host_put(shost);
-
-failed_alloc:
- sbp2_remove_device(lu);
- return NULL;
-}
-
-static void sbp2_host_reset(struct hpsb_host *host)
-{
- struct sbp2_fwhost_info *hi;
- struct sbp2_lu *lu;
- unsigned long flags;
-
- hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
- if (!hi)
- return;
-
- read_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
-
- list_for_each_entry(lu, &hi->logical_units, lu_list)
- if (atomic_cmpxchg(&lu->state,
- SBP2LU_STATE_RUNNING, SBP2LU_STATE_IN_RESET)
- == SBP2LU_STATE_RUNNING)
- scsi_block_requests(lu->shost);
-
- read_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-}
-
-static int sbp2_start_device(struct sbp2_lu *lu)
-{
- struct sbp2_fwhost_info *hi = lu->hi;
- int error;
-
- lu->login_response = dma_alloc_coherent(hi->host->device.parent,
- sizeof(struct sbp2_login_response),
- &lu->login_response_dma, GFP_KERNEL);
- if (!lu->login_response)
- goto alloc_fail;
-
- lu->query_logins_orb = dma_alloc_coherent(hi->host->device.parent,
- sizeof(struct sbp2_query_logins_orb),
- &lu->query_logins_orb_dma, GFP_KERNEL);
- if (!lu->query_logins_orb)
- goto alloc_fail;
-
- lu->query_logins_response = dma_alloc_coherent(hi->host->device.parent,
- sizeof(struct sbp2_query_logins_response),
- &lu->query_logins_response_dma, GFP_KERNEL);
- if (!lu->query_logins_response)
- goto alloc_fail;
-
- lu->reconnect_orb = dma_alloc_coherent(hi->host->device.parent,
- sizeof(struct sbp2_reconnect_orb),
- &lu->reconnect_orb_dma, GFP_KERNEL);
- if (!lu->reconnect_orb)
- goto alloc_fail;
-
- lu->logout_orb = dma_alloc_coherent(hi->host->device.parent,
- sizeof(struct sbp2_logout_orb),
- &lu->logout_orb_dma, GFP_KERNEL);
- if (!lu->logout_orb)
- goto alloc_fail;
-
- lu->login_orb = dma_alloc_coherent(hi->host->device.parent,
- sizeof(struct sbp2_login_orb),
- &lu->login_orb_dma, GFP_KERNEL);
- if (!lu->login_orb)
- goto alloc_fail;
-
- if (sbp2util_create_command_orb_pool(lu))
- goto alloc_fail;
-
- /* Wait a second before trying to log in. Previously logged in
- * initiators need a chance to reconnect. */
- if (msleep_interruptible(1000)) {
- sbp2_remove_device(lu);
- return -EINTR;
- }
-
- if (sbp2_login_device(lu)) {
- sbp2_remove_device(lu);
- return -EBUSY;
- }
-
- sbp2_set_busy_timeout(lu);
- sbp2_agent_reset(lu, 1);
- sbp2_max_speed_and_size(lu);
-
- if (lu->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
- ssleep(SBP2_INQUIRY_DELAY);
-
- error = scsi_add_device(lu->shost, 0, lu->ud->id, 0);
- if (error) {
- SBP2_ERR("scsi_add_device failed");
- sbp2_logout_device(lu);
- sbp2_remove_device(lu);
- return error;
- }
-
- return 0;
-
-alloc_fail:
- SBP2_ERR("Could not allocate memory for lu");
- sbp2_remove_device(lu);
- return -ENOMEM;
-}
-
-static void sbp2_remove_device(struct sbp2_lu *lu)
-{
- struct sbp2_fwhost_info *hi;
- unsigned long flags;
-
- if (!lu)
- return;
- hi = lu->hi;
- if (!hi)
- goto no_hi;
-
- if (lu->shost) {
- scsi_remove_host(lu->shost);
- scsi_host_put(lu->shost);
- }
- flush_scheduled_work();
- sbp2util_remove_command_orb_pool(lu, hi->host);
-
- write_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
- list_del(&lu->lu_list);
- write_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-
- if (lu->login_response)
- dma_free_coherent(hi->host->device.parent,
- sizeof(struct sbp2_login_response),
- lu->login_response,
- lu->login_response_dma);
- if (lu->login_orb)
- dma_free_coherent(hi->host->device.parent,
- sizeof(struct sbp2_login_orb),
- lu->login_orb,
- lu->login_orb_dma);
- if (lu->reconnect_orb)
- dma_free_coherent(hi->host->device.parent,
- sizeof(struct sbp2_reconnect_orb),
- lu->reconnect_orb,
- lu->reconnect_orb_dma);
- if (lu->logout_orb)
- dma_free_coherent(hi->host->device.parent,
- sizeof(struct sbp2_logout_orb),
- lu->logout_orb,
- lu->logout_orb_dma);
- if (lu->query_logins_orb)
- dma_free_coherent(hi->host->device.parent,
- sizeof(struct sbp2_query_logins_orb),
- lu->query_logins_orb,
- lu->query_logins_orb_dma);
- if (lu->query_logins_response)
- dma_free_coherent(hi->host->device.parent,
- sizeof(struct sbp2_query_logins_response),
- lu->query_logins_response,
- lu->query_logins_response_dma);
-
- if (lu->status_fifo_addr != CSR1212_INVALID_ADDR_SPACE)
- hpsb_unregister_addrspace(&sbp2_highlevel, hi->host,
- lu->status_fifo_addr);
-
- dev_set_drvdata(&lu->ud->device, NULL);
-
- module_put(hi->host->driver->owner);
-no_hi:
- kfree(lu);
-}
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
-/*
- * Deal with write requests on adapters which do not support physical DMA or
- * have it switched off.
- */
-static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid,
- int destid, quadlet_t *data, u64 addr,
- size_t length, u16 flags)
-{
- memcpy(bus_to_virt((u32) addr), data, length);
- return RCODE_COMPLETE;
-}
-
-/*
- * Deal with read requests on adapters which do not support physical DMA or
- * have it switched off.
- */
-static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid,
- quadlet_t *data, u64 addr, size_t length,
- u16 flags)
-{
- memcpy(data, bus_to_virt((u32) addr), length);
- return RCODE_COMPLETE;
-}
-#endif
-
-/**************************************
- * SBP-2 protocol related section
- **************************************/
-
-static int sbp2_query_logins(struct sbp2_lu *lu)
-{
- struct sbp2_fwhost_info *hi = lu->hi;
- quadlet_t data[2];
- int max_logins;
- int active_logins;
-
- lu->query_logins_orb->reserved1 = 0x0;
- lu->query_logins_orb->reserved2 = 0x0;
-
- lu->query_logins_orb->query_response_lo = lu->query_logins_response_dma;
- lu->query_logins_orb->query_response_hi =
- ORB_SET_NODE_ID(hi->host->node_id);
- lu->query_logins_orb->lun_misc =
- ORB_SET_FUNCTION(SBP2_QUERY_LOGINS_REQUEST);
- lu->query_logins_orb->lun_misc |= ORB_SET_NOTIFY(1);
- lu->query_logins_orb->lun_misc |= ORB_SET_LUN(lu->lun);
-
- lu->query_logins_orb->reserved_resp_length =
- ORB_SET_QUERY_LOGINS_RESP_LENGTH(
- sizeof(struct sbp2_query_logins_response));
-
- lu->query_logins_orb->status_fifo_hi =
- ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
- lu->query_logins_orb->status_fifo_lo =
- ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
- sbp2util_cpu_to_be32_buffer(lu->query_logins_orb,
- sizeof(struct sbp2_query_logins_orb));
-
- memset(lu->query_logins_response, 0,
- sizeof(struct sbp2_query_logins_response));
-
- data[0] = ORB_SET_NODE_ID(hi->host->node_id);
- data[1] = lu->query_logins_orb_dma;
- sbp2util_cpu_to_be32_buffer(data, 8);
-
- hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
-
- if (sbp2util_access_timeout(lu, 2*HZ)) {
- SBP2_INFO("Error querying logins to SBP-2 device - timed out");
- return -EIO;
- }
-
- if (lu->status_block.ORB_offset_lo != lu->query_logins_orb_dma) {
- SBP2_INFO("Error querying logins to SBP-2 device - timed out");
- return -EIO;
- }
-
- if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) {
- SBP2_INFO("Error querying logins to SBP-2 device - failed");
- return -EIO;
- }
-
- sbp2util_cpu_to_be32_buffer(lu->query_logins_response,
- sizeof(struct sbp2_query_logins_response));
-
- max_logins = RESPONSE_GET_MAX_LOGINS(
- lu->query_logins_response->length_max_logins);
- SBP2_INFO("Maximum concurrent logins supported: %d", max_logins);
-
- active_logins = RESPONSE_GET_ACTIVE_LOGINS(
- lu->query_logins_response->length_max_logins);
- SBP2_INFO("Number of active logins: %d", active_logins);
-
- if (active_logins >= max_logins) {
- return -EIO;
- }
-
- return 0;
-}
-
-static int sbp2_login_device(struct sbp2_lu *lu)
-{
- struct sbp2_fwhost_info *hi = lu->hi;
- quadlet_t data[2];
-
- if (!lu->login_orb)
- return -EIO;
-
- if (!sbp2_exclusive_login && sbp2_query_logins(lu)) {
- SBP2_INFO("Device does not support any more concurrent logins");
- return -EIO;
- }
-
- /* assume no password */
- lu->login_orb->password_hi = 0;
- lu->login_orb->password_lo = 0;
-
- lu->login_orb->login_response_lo = lu->login_response_dma;
- lu->login_orb->login_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
- lu->login_orb->lun_misc = ORB_SET_FUNCTION(SBP2_LOGIN_REQUEST);
-
- /* one second reconnect time */
- lu->login_orb->lun_misc |= ORB_SET_RECONNECT(0);
- lu->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(sbp2_exclusive_login);
- lu->login_orb->lun_misc |= ORB_SET_NOTIFY(1);
- lu->login_orb->lun_misc |= ORB_SET_LUN(lu->lun);
-
- lu->login_orb->passwd_resp_lengths =
- ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response));
-
- lu->login_orb->status_fifo_hi =
- ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
- lu->login_orb->status_fifo_lo =
- ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
- sbp2util_cpu_to_be32_buffer(lu->login_orb,
- sizeof(struct sbp2_login_orb));
-
- memset(lu->login_response, 0, sizeof(struct sbp2_login_response));
-
- data[0] = ORB_SET_NODE_ID(hi->host->node_id);
- data[1] = lu->login_orb_dma;
- sbp2util_cpu_to_be32_buffer(data, 8);
-
- hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
-
- /* wait up to 20 seconds for login status */
- if (sbp2util_access_timeout(lu, 20*HZ)) {
- SBP2_ERR("Error logging into SBP-2 device - timed out");
- return -EIO;
- }
-
- /* make sure that the returned status matches the login ORB */
- if (lu->status_block.ORB_offset_lo != lu->login_orb_dma) {
- SBP2_ERR("Error logging into SBP-2 device - timed out");
- return -EIO;
- }
-
- if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) {
- SBP2_ERR("Error logging into SBP-2 device - failed");
- return -EIO;
- }
-
- sbp2util_cpu_to_be32_buffer(lu->login_response,
- sizeof(struct sbp2_login_response));
- lu->command_block_agent_addr =
- ((u64)lu->login_response->command_block_agent_hi) << 32;
- lu->command_block_agent_addr |=
- ((u64)lu->login_response->command_block_agent_lo);
- lu->command_block_agent_addr &= 0x0000ffffffffffffULL;
-
- SBP2_INFO("Logged into SBP-2 device");
- return 0;
-}
-
-static int sbp2_logout_device(struct sbp2_lu *lu)
-{
- struct sbp2_fwhost_info *hi = lu->hi;
- quadlet_t data[2];
- int error;
-
- lu->logout_orb->reserved1 = 0x0;
- lu->logout_orb->reserved2 = 0x0;
- lu->logout_orb->reserved3 = 0x0;
- lu->logout_orb->reserved4 = 0x0;
-
- lu->logout_orb->login_ID_misc = ORB_SET_FUNCTION(SBP2_LOGOUT_REQUEST);
- lu->logout_orb->login_ID_misc |=
- ORB_SET_LOGIN_ID(lu->login_response->length_login_ID);
- lu->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
-
- lu->logout_orb->reserved5 = 0x0;
- lu->logout_orb->status_fifo_hi =
- ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
- lu->logout_orb->status_fifo_lo =
- ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
- sbp2util_cpu_to_be32_buffer(lu->logout_orb,
- sizeof(struct sbp2_logout_orb));
-
- data[0] = ORB_SET_NODE_ID(hi->host->node_id);
- data[1] = lu->logout_orb_dma;
- sbp2util_cpu_to_be32_buffer(data, 8);
-
- error = hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
- if (error)
- return error;
-
- /* wait up to 1 second for the device to complete logout */
- if (sbp2util_access_timeout(lu, HZ))
- return -EIO;
-
- SBP2_INFO("Logged out of SBP-2 device");
- return 0;
-}
-
-static int sbp2_reconnect_device(struct sbp2_lu *lu)
-{
- struct sbp2_fwhost_info *hi = lu->hi;
- quadlet_t data[2];
- int error;
-
- lu->reconnect_orb->reserved1 = 0x0;
- lu->reconnect_orb->reserved2 = 0x0;
- lu->reconnect_orb->reserved3 = 0x0;
- lu->reconnect_orb->reserved4 = 0x0;
-
- lu->reconnect_orb->login_ID_misc =
- ORB_SET_FUNCTION(SBP2_RECONNECT_REQUEST);
- lu->reconnect_orb->login_ID_misc |=
- ORB_SET_LOGIN_ID(lu->login_response->length_login_ID);
- lu->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
-
- lu->reconnect_orb->reserved5 = 0x0;
- lu->reconnect_orb->status_fifo_hi =
- ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
- lu->reconnect_orb->status_fifo_lo =
- ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
- sbp2util_cpu_to_be32_buffer(lu->reconnect_orb,
- sizeof(struct sbp2_reconnect_orb));
-
- data[0] = ORB_SET_NODE_ID(hi->host->node_id);
- data[1] = lu->reconnect_orb_dma;
- sbp2util_cpu_to_be32_buffer(data, 8);
-
- error = hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
- if (error)
- return error;
-
- /* wait up to 1 second for reconnect status */
- if (sbp2util_access_timeout(lu, HZ)) {
- SBP2_ERR("Error reconnecting to SBP-2 device - timed out");
- return -EIO;
- }
-
- /* make sure that the returned status matches the reconnect ORB */
- if (lu->status_block.ORB_offset_lo != lu->reconnect_orb_dma) {
- SBP2_ERR("Error reconnecting to SBP-2 device - timed out");
- return -EIO;
- }
-
- if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) {
- SBP2_ERR("Error reconnecting to SBP-2 device - failed");
- return -EIO;
- }
-
- SBP2_INFO("Reconnected to SBP-2 device");
- return 0;
-}
-
-/*
- * Set the target node's Single Phase Retry limit. Affects the target's retry
- * behaviour if our node is too busy to accept requests.
- */
-static int sbp2_set_busy_timeout(struct sbp2_lu *lu)
-{
- quadlet_t data;
-
- data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE);
- if (hpsb_node_write(lu->ne, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4))
- SBP2_ERR("%s error", __func__);
- return 0;
-}
-
-static void sbp2_parse_unit_directory(struct sbp2_lu *lu,
- struct unit_directory *ud)
-{
- struct csr1212_keyval *kv;
- struct csr1212_dentry *dentry;
- u64 management_agent_addr;
- u32 firmware_revision, model;
- unsigned workarounds;
- int i;
-
- management_agent_addr = 0;
- firmware_revision = SBP2_ROM_VALUE_MISSING;
- model = ud->flags & UNIT_DIRECTORY_MODEL_ID ?
- ud->model_id : SBP2_ROM_VALUE_MISSING;
-
- csr1212_for_each_dir_entry(ud->ne->csr, kv, ud->ud_kv, dentry) {
- switch (kv->key.id) {
- case CSR1212_KV_ID_DEPENDENT_INFO:
- if (kv->key.type == CSR1212_KV_TYPE_CSR_OFFSET)
- management_agent_addr =
- CSR1212_REGISTER_SPACE_BASE +
- (kv->value.csr_offset << 2);
-
- else if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE)
- lu->lun = ORB_SET_LUN(kv->value.immediate);
- break;
-
-
- case SBP2_FIRMWARE_REVISION_KEY:
- firmware_revision = kv->value.immediate;
- break;
-
- default:
- /* FIXME: Check for SBP2_UNIT_CHARACTERISTICS_KEY
- * mgt_ORB_timeout and ORB_size, SBP-2 clause 7.4.8. */
-
- /* FIXME: Check for SBP2_DEVICE_TYPE_AND_LUN_KEY.
- * Its "ordered" bit has consequences for command ORB
- * list handling. See SBP-2 clauses 4.6, 7.4.11, 10.2 */
- break;
- }
- }
-
- workarounds = sbp2_default_workarounds;
-
- if (!(workarounds & SBP2_WORKAROUND_OVERRIDE))
- for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
- if (sbp2_workarounds_table[i].firmware_revision !=
- SBP2_ROM_VALUE_WILDCARD &&
- sbp2_workarounds_table[i].firmware_revision !=
- (firmware_revision & 0xffff00))
- continue;
- if (sbp2_workarounds_table[i].model !=
- SBP2_ROM_VALUE_WILDCARD &&
- sbp2_workarounds_table[i].model != model)
- continue;
- workarounds |= sbp2_workarounds_table[i].workarounds;
- break;
- }
-
- if (workarounds)
- SBP2_INFO("Workarounds for node " NODE_BUS_FMT ": 0x%x "
- "(firmware_revision 0x%06x, vendor_id 0x%06x,"
- " model_id 0x%06x)",
- NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid),
- workarounds, firmware_revision, ud->vendor_id,
- model);
-
- /* We would need one SCSI host template for each target to adjust
- * max_sectors on the fly, therefore warn only. */
- if (workarounds & SBP2_WORKAROUND_128K_MAX_TRANS &&
- (sbp2_max_sectors * 512) > (128 * 1024))
- SBP2_INFO("Node " NODE_BUS_FMT ": Bridge only supports 128KB "
- "max transfer size. WARNING: Current max_sectors "
- "setting is larger than 128KB (%d sectors)",
- NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid),
- sbp2_max_sectors);
-
- /* If this is a logical unit directory entry, process the parent
- * to get the values. */
- if (ud->flags & UNIT_DIRECTORY_LUN_DIRECTORY) {
- struct unit_directory *parent_ud = container_of(
- ud->device.parent, struct unit_directory, device);
- sbp2_parse_unit_directory(lu, parent_ud);
- } else {
- lu->management_agent_addr = management_agent_addr;
- lu->workarounds = workarounds;
- if (ud->flags & UNIT_DIRECTORY_HAS_LUN)
- lu->lun = ORB_SET_LUN(ud->lun);
- }
-}
-
-#define SBP2_PAYLOAD_TO_BYTES(p) (1 << ((p) + 2))
-
-/*
- * This function is called in order to determine the max speed and packet
- * size we can use in our ORBs. Note, that we (the driver and host) only
- * initiate the transaction. The SBP-2 device actually transfers the data
- * (by reading from the DMA area we tell it). This means that the SBP-2
- * device decides the actual maximum data it can transfer. We just tell it
- * the speed that it needs to use, and the max_rec the host supports, and
- * it takes care of the rest.
- */
-static int sbp2_max_speed_and_size(struct sbp2_lu *lu)
-{
- struct sbp2_fwhost_info *hi = lu->hi;
- u8 payload;
-
- lu->speed_code = hi->host->speed[NODEID_TO_NODE(lu->ne->nodeid)];
-
- if (lu->speed_code > sbp2_max_speed) {
- lu->speed_code = sbp2_max_speed;
- SBP2_INFO("Reducing speed to %s",
- hpsb_speedto_str[sbp2_max_speed]);
- }
-
- /* Payload size is the lesser of what our speed supports and what
- * our host supports. */
- payload = min(sbp2_speedto_max_payload[lu->speed_code],
- (u8) (hi->host->csr.max_rec - 1));
-
- /* If physical DMA is off, work around limitation in ohci1394:
- * packet size must not exceed PAGE_SIZE */
- if (lu->ne->host->low_addr_space < (1ULL << 32))
- while (SBP2_PAYLOAD_TO_BYTES(payload) + 24 > PAGE_SIZE &&
- payload)
- payload--;
-
- SBP2_INFO("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]",
- NODE_BUS_ARGS(hi->host, lu->ne->nodeid),
- hpsb_speedto_str[lu->speed_code],
- SBP2_PAYLOAD_TO_BYTES(payload));
-
- lu->max_payload_size = payload;
- return 0;
-}
-
-static int sbp2_agent_reset(struct sbp2_lu *lu, int wait)
-{
- quadlet_t data;
- u64 addr;
- int retval;
- unsigned long flags;
-
- /* flush lu->protocol_work */
- if (wait)
- flush_scheduled_work();
-
- data = ntohl(SBP2_AGENT_RESET_DATA);
- addr = lu->command_block_agent_addr + SBP2_AGENT_RESET_OFFSET;
-
- if (wait)
- retval = hpsb_node_write(lu->ne, addr, &data, 4);
- else
- retval = sbp2util_node_write_no_wait(lu->ne, addr, &data, 4);
-
- if (retval < 0) {
- SBP2_ERR("hpsb_node_write failed.\n");
- return -EIO;
- }
-
- /* make sure that the ORB_POINTER is written on next command */
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- lu->last_orb = NULL;
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
- return 0;
-}
-
-static int sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
- struct sbp2_fwhost_info *hi,
- struct sbp2_command_info *cmd,
- unsigned int sg_count,
- struct scatterlist *sg,
- u32 orb_direction,
- enum dma_data_direction dma_dir)
-{
- struct device *dmadev = hi->host->device.parent;
- struct sbp2_unrestricted_page_table *pt;
- int i, n;
-
- n = dma_map_sg(dmadev, sg, sg_count, dma_dir);
- if (n == 0)
- return -ENOMEM;
-
- orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
- orb->misc |= ORB_SET_DIRECTION(orb_direction);
-
- /* special case if only one element (and less than 64KB in size) */
- if (n == 1) {
- orb->misc |= ORB_SET_DATA_SIZE(sg_dma_len(sg));
- orb->data_descriptor_lo = sg_dma_address(sg);
- } else {
- pt = &cmd->scatter_gather_element[0];
-
- dma_sync_single_for_cpu(dmadev, cmd->sge_dma,
- sizeof(cmd->scatter_gather_element),
- DMA_TO_DEVICE);
-
- for_each_sg(sg, sg, n, i) {
- pt[i].high = cpu_to_be32(sg_dma_len(sg) << 16);
- pt[i].low = cpu_to_be32(sg_dma_address(sg));
- }
-
- orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1) |
- ORB_SET_DATA_SIZE(n);
- orb->data_descriptor_lo = cmd->sge_dma;
-
- dma_sync_single_for_device(dmadev, cmd->sge_dma,
- sizeof(cmd->scatter_gather_element),
- DMA_TO_DEVICE);
- }
- return 0;
-}
-
-static int sbp2_create_command_orb(struct sbp2_lu *lu,
- struct sbp2_command_info *cmd,
- struct scsi_cmnd *SCpnt)
-{
- struct device *dmadev = lu->hi->host->device.parent;
- struct sbp2_command_orb *orb = &cmd->command_orb;
- unsigned int scsi_request_bufflen = scsi_bufflen(SCpnt);
- enum dma_data_direction dma_dir = SCpnt->sc_data_direction;
- u32 orb_direction;
- int ret;
-
- dma_sync_single_for_cpu(dmadev, cmd->command_orb_dma,
- sizeof(struct sbp2_command_orb), DMA_TO_DEVICE);
- /*
- * Set-up our command ORB.
- *
- * NOTE: We're doing unrestricted page tables (s/g), as this is
- * best performance (at least with the devices I have). This means
- * that data_size becomes the number of s/g elements, and
- * page_size should be zero (for unrestricted).
- */
- orb->next_ORB_hi = ORB_SET_NULL_PTR(1);
- orb->next_ORB_lo = 0x0;
- orb->misc = ORB_SET_MAX_PAYLOAD(lu->max_payload_size);
- orb->misc |= ORB_SET_SPEED(lu->speed_code);
- orb->misc |= ORB_SET_NOTIFY(1);
-
- if (dma_dir == DMA_NONE)
- orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER;
- else if (dma_dir == DMA_TO_DEVICE && scsi_request_bufflen)
- orb_direction = ORB_DIRECTION_WRITE_TO_MEDIA;
- else if (dma_dir == DMA_FROM_DEVICE && scsi_request_bufflen)
- orb_direction = ORB_DIRECTION_READ_FROM_MEDIA;
- else {
- SBP2_INFO("Falling back to DMA_NONE");
- orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER;
- }
-
- /* set up our page table stuff */
- if (orb_direction == ORB_DIRECTION_NO_DATA_TRANSFER) {
- orb->data_descriptor_hi = 0x0;
- orb->data_descriptor_lo = 0x0;
- orb->misc |= ORB_SET_DIRECTION(1);
- ret = 0;
- } else {
- ret = sbp2_prep_command_orb_sg(orb, lu->hi, cmd,
- scsi_sg_count(SCpnt),
- scsi_sglist(SCpnt),
- orb_direction, dma_dir);
- }
- sbp2util_cpu_to_be32_buffer(orb, sizeof(*orb));
-
- memset(orb->cdb, 0, sizeof(orb->cdb));
- memcpy(orb->cdb, SCpnt->cmnd, SCpnt->cmd_len);
-
- dma_sync_single_for_device(dmadev, cmd->command_orb_dma,
- sizeof(struct sbp2_command_orb), DMA_TO_DEVICE);
- return ret;
-}
-
-static void sbp2_link_orb_command(struct sbp2_lu *lu,
- struct sbp2_command_info *cmd)
-{
- struct sbp2_fwhost_info *hi = lu->hi;
- struct sbp2_command_orb *last_orb;
- dma_addr_t last_orb_dma;
- u64 addr = lu->command_block_agent_addr;
- quadlet_t data[2];
- size_t length;
- unsigned long flags;
-
- /* check to see if there are any previous orbs to use */
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- last_orb = lu->last_orb;
- last_orb_dma = lu->last_orb_dma;
- if (!last_orb) {
- /*
- * last_orb == NULL means: We know that the target's fetch agent
- * is not active right now.
- */
- addr += SBP2_ORB_POINTER_OFFSET;
- data[0] = ORB_SET_NODE_ID(hi->host->node_id);
- data[1] = cmd->command_orb_dma;
- sbp2util_cpu_to_be32_buffer(data, 8);
- length = 8;
- } else {
- /*
- * last_orb != NULL means: We know that the target's fetch agent
- * is (very probably) not dead or in reset state right now.
- * We have an ORB already sent that we can append a new one to.
- * The target's fetch agent may or may not have read this
- * previous ORB yet.
- */
- dma_sync_single_for_cpu(hi->host->device.parent, last_orb_dma,
- sizeof(struct sbp2_command_orb),
- DMA_TO_DEVICE);
- last_orb->next_ORB_lo = cpu_to_be32(cmd->command_orb_dma);
- wmb();
- /* Tells hardware that this pointer is valid */
- last_orb->next_ORB_hi = 0;
- dma_sync_single_for_device(hi->host->device.parent,
- last_orb_dma,
- sizeof(struct sbp2_command_orb),
- DMA_TO_DEVICE);
- addr += SBP2_DOORBELL_OFFSET;
- data[0] = 0;
- length = 4;
- }
- lu->last_orb = &cmd->command_orb;
- lu->last_orb_dma = cmd->command_orb_dma;
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
- if (sbp2util_node_write_no_wait(lu->ne, addr, data, length)) {
- /*
- * sbp2util_node_write_no_wait failed. We certainly ran out
- * of transaction labels, perhaps just because there were no
- * context switches which gave khpsbpkt a chance to collect
- * free tlabels. Try again in non-atomic context. If necessary,
- * the workqueue job will sleep to guaranteedly get a tlabel.
- * We do not accept new commands until the job is over.
- */
- scsi_block_requests(lu->shost);
- PREPARE_WORK(&lu->protocol_work,
- last_orb ? sbp2util_write_doorbell:
- sbp2util_write_orb_pointer);
- schedule_work(&lu->protocol_work);
- }
-}
-
-static int sbp2_send_command(struct sbp2_lu *lu, struct scsi_cmnd *SCpnt,
- void (*done)(struct scsi_cmnd *))
-{
- struct sbp2_command_info *cmd;
-
- cmd = sbp2util_allocate_command_orb(lu, SCpnt, done);
- if (!cmd)
- return -EIO;
-
- if (sbp2_create_command_orb(lu, cmd, SCpnt))
- return -ENOMEM;
-
- sbp2_link_orb_command(lu, cmd);
- return 0;
-}
-
-/*
- * Translates SBP-2 status into SCSI sense data for check conditions
- */
-static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status,
- unchar *sense_data)
-{
- /* OK, it's pretty ugly... ;-) */
- sense_data[0] = 0x70;
- sense_data[1] = 0x0;
- sense_data[2] = sbp2_status[9];
- sense_data[3] = sbp2_status[12];
- sense_data[4] = sbp2_status[13];
- sense_data[5] = sbp2_status[14];
- sense_data[6] = sbp2_status[15];
- sense_data[7] = 10;
- sense_data[8] = sbp2_status[16];
- sense_data[9] = sbp2_status[17];
- sense_data[10] = sbp2_status[18];
- sense_data[11] = sbp2_status[19];
- sense_data[12] = sbp2_status[10];
- sense_data[13] = sbp2_status[11];
- sense_data[14] = sbp2_status[20];
- sense_data[15] = sbp2_status[21];
-
- return sbp2_status[8] & 0x3f;
-}
-
-static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
- int destid, quadlet_t *data, u64 addr,
- size_t length, u16 fl)
-{
- struct sbp2_fwhost_info *hi;
- struct sbp2_lu *lu = NULL, *lu_tmp;
- struct scsi_cmnd *SCpnt = NULL;
- struct sbp2_status_block *sb;
- u32 scsi_status = SBP2_SCSI_STATUS_GOOD;
- struct sbp2_command_info *cmd;
- unsigned long flags;
-
- if (unlikely(length < 8 || length > sizeof(struct sbp2_status_block))) {
- SBP2_ERR("Wrong size of status block");
- return RCODE_ADDRESS_ERROR;
- }
- if (unlikely(!host)) {
- SBP2_ERR("host is NULL - this is bad!");
- return RCODE_ADDRESS_ERROR;
- }
- hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
- if (unlikely(!hi)) {
- SBP2_ERR("host info is NULL - this is bad!");
- return RCODE_ADDRESS_ERROR;
- }
-
- /* Find the unit which wrote the status. */
- read_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
- list_for_each_entry(lu_tmp, &hi->logical_units, lu_list) {
- if (lu_tmp->ne->nodeid == nodeid &&
- lu_tmp->status_fifo_addr == addr) {
- lu = lu_tmp;
- break;
- }
- }
- read_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-
- if (unlikely(!lu)) {
- SBP2_ERR("lu is NULL - device is gone?");
- return RCODE_ADDRESS_ERROR;
- }
-
- /* Put response into lu status fifo buffer. The first two bytes
- * come in big endian bit order. Often the target writes only a
- * truncated status block, minimally the first two quadlets. The rest
- * is implied to be zeros. */
- sb = &lu->status_block;
- memset(sb->command_set_dependent, 0, sizeof(sb->command_set_dependent));
- memcpy(sb, data, length);
- sbp2util_be32_to_cpu_buffer(sb, 8);
-
- /* Ignore unsolicited status. Handle command ORB status. */
- if (unlikely(STATUS_GET_SRC(sb->ORB_offset_hi_misc) == 2))
- cmd = NULL;
- else
- cmd = sbp2util_find_command_for_orb(lu, sb->ORB_offset_lo);
- if (cmd) {
- /* Grab SCSI command pointers and check status. */
- /*
- * FIXME: If the src field in the status is 1, the ORB DMA must
- * not be reused until status for a subsequent ORB is received.
- */
- SCpnt = cmd->Current_SCpnt;
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- sbp2util_mark_command_completed(lu, cmd);
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
- if (SCpnt) {
- u32 h = sb->ORB_offset_hi_misc;
- u32 r = STATUS_GET_RESP(h);
-
- if (r != RESP_STATUS_REQUEST_COMPLETE) {
- SBP2_INFO("resp 0x%x, sbp_status 0x%x",
- r, STATUS_GET_SBP_STATUS(h));
- scsi_status =
- r == RESP_STATUS_TRANSPORT_FAILURE ?
- SBP2_SCSI_STATUS_BUSY :
- SBP2_SCSI_STATUS_COMMAND_TERMINATED;
- }
-
- if (STATUS_GET_LEN(h) > 1)
- scsi_status = sbp2_status_to_sense_data(
- (unchar *)sb, SCpnt->sense_buffer);
-
- if (STATUS_TEST_DEAD(h))
- sbp2_agent_reset(lu, 0);
- }
-
- /* Check here to see if there are no commands in-use. If there
- * are none, we know that the fetch agent left the active state
- * _and_ that we did not reactivate it yet. Therefore clear
- * last_orb so that next time we write directly to the
- * ORB_POINTER register. That way the fetch agent does not need
- * to refetch the next_ORB. */
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- if (list_empty(&lu->cmd_orb_inuse))
- lu->last_orb = NULL;
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
- } else {
- /* It's probably status after a management request. */
- if ((sb->ORB_offset_lo == lu->reconnect_orb_dma) ||
- (sb->ORB_offset_lo == lu->login_orb_dma) ||
- (sb->ORB_offset_lo == lu->query_logins_orb_dma) ||
- (sb->ORB_offset_lo == lu->logout_orb_dma)) {
- lu->access_complete = 1;
- wake_up_interruptible(&sbp2_access_wq);
- }
- }
-
- if (SCpnt)
- sbp2scsi_complete_command(lu, scsi_status, SCpnt,
- cmd->Current_done);
- return RCODE_COMPLETE;
-}
-
-/**************************************
- * SCSI interface related section
- **************************************/
-
-static int sbp2scsi_queuecommand(struct scsi_cmnd *SCpnt,
- void (*done)(struct scsi_cmnd *))
-{
- struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0];
- struct sbp2_fwhost_info *hi;
- int result = DID_NO_CONNECT << 16;
-
- if (unlikely(!sbp2util_node_is_available(lu)))
- goto done;
-
- hi = lu->hi;
-
- if (unlikely(!hi)) {
- SBP2_ERR("sbp2_fwhost_info is NULL - this is bad!");
- goto done;
- }
-
- /* Multiple units are currently represented to the SCSI core as separate
- * targets, not as one target with multiple LUs. Therefore return
- * selection time-out to any IO directed at non-zero LUNs. */
- if (unlikely(SCpnt->device->lun))
- goto done;
-
- if (unlikely(!hpsb_node_entry_valid(lu->ne))) {
- SBP2_ERR("Bus reset in progress - rejecting command");
- result = DID_BUS_BUSY << 16;
- goto done;
- }
-
- /* Bidirectional commands are not yet implemented,
- * and unknown transfer direction not handled. */
- if (unlikely(SCpnt->sc_data_direction == DMA_BIDIRECTIONAL)) {
- SBP2_ERR("Cannot handle DMA_BIDIRECTIONAL - rejecting command");
- result = DID_ERROR << 16;
- goto done;
- }
-
- if (sbp2_send_command(lu, SCpnt, done)) {
- SBP2_ERR("Error sending SCSI command");
- sbp2scsi_complete_command(lu,
- SBP2_SCSI_STATUS_SELECTION_TIMEOUT,
- SCpnt, done);
- }
- return 0;
-
-done:
- SCpnt->result = result;
- done(SCpnt);
- return 0;
-}
-
-static void sbp2scsi_complete_all_commands(struct sbp2_lu *lu, u32 status)
-{
- struct list_head *lh;
- struct sbp2_command_info *cmd;
- unsigned long flags;
-
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- while (!list_empty(&lu->cmd_orb_inuse)) {
- lh = lu->cmd_orb_inuse.next;
- cmd = list_entry(lh, struct sbp2_command_info, list);
- sbp2util_mark_command_completed(lu, cmd);
- if (cmd->Current_SCpnt) {
- cmd->Current_SCpnt->result = status << 16;
- cmd->Current_done(cmd->Current_SCpnt);
- }
- }
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
- return;
-}
-
-/*
- * Complete a regular SCSI command. Can be called in atomic context.
- */
-static void sbp2scsi_complete_command(struct sbp2_lu *lu, u32 scsi_status,
- struct scsi_cmnd *SCpnt,
- void (*done)(struct scsi_cmnd *))
-{
- if (!SCpnt) {
- SBP2_ERR("SCpnt is NULL");
- return;
- }
-
- switch (scsi_status) {
- case SBP2_SCSI_STATUS_GOOD:
- SCpnt->result = DID_OK << 16;
- break;
-
- case SBP2_SCSI_STATUS_BUSY:
- SBP2_ERR("SBP2_SCSI_STATUS_BUSY");
- SCpnt->result = DID_BUS_BUSY << 16;
- break;
-
- case SBP2_SCSI_STATUS_CHECK_CONDITION:
- SCpnt->result = CHECK_CONDITION << 1 | DID_OK << 16;
- break;
-
- case SBP2_SCSI_STATUS_SELECTION_TIMEOUT:
- SBP2_ERR("SBP2_SCSI_STATUS_SELECTION_TIMEOUT");
- SCpnt->result = DID_NO_CONNECT << 16;
- scsi_print_command(SCpnt);
- break;
-
- case SBP2_SCSI_STATUS_CONDITION_MET:
- case SBP2_SCSI_STATUS_RESERVATION_CONFLICT:
- case SBP2_SCSI_STATUS_COMMAND_TERMINATED:
- SBP2_ERR("Bad SCSI status = %x", scsi_status);
- SCpnt->result = DID_ERROR << 16;
- scsi_print_command(SCpnt);
- break;
-
- default:
- SBP2_ERR("Unsupported SCSI status = %x", scsi_status);
- SCpnt->result = DID_ERROR << 16;
- }
-
- /* If a bus reset is in progress and there was an error, complete
- * the command as busy so that it will get retried. */
- if (!hpsb_node_entry_valid(lu->ne)
- && (scsi_status != SBP2_SCSI_STATUS_GOOD)) {
- SBP2_ERR("Completing command with busy (bus reset)");
- SCpnt->result = DID_BUS_BUSY << 16;
- }
-
- /* Tell the SCSI stack that we're done with this command. */
- done(SCpnt);
-}
-
-static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
-{
- struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
-
- if (sdev->lun != 0 || sdev->id != lu->ud->id || sdev->channel != 0)
- return -ENODEV;
-
- lu->sdev = sdev;
- sdev->allow_restart = 1;
-
- /* SBP-2 requires quadlet alignment of the data buffers. */
- blk_queue_update_dma_alignment(sdev->request_queue, 4 - 1);
-
- if (lu->workarounds & SBP2_WORKAROUND_INQUIRY_36)
- sdev->inquiry_len = 36;
- return 0;
-}
-
-static int sbp2scsi_slave_configure(struct scsi_device *sdev)
-{
- struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
-
- sdev->use_10_for_rw = 1;
-
- if (sbp2_exclusive_login)
- sdev->manage_start_stop = 1;
- if (sdev->type == TYPE_ROM)
- sdev->use_10_for_ms = 1;
- if (sdev->type == TYPE_DISK &&
- lu->workarounds & SBP2_WORKAROUND_MODE_SENSE_8)
- sdev->skip_ms_page_8 = 1;
- if (lu->workarounds & SBP2_WORKAROUND_FIX_CAPACITY)
- sdev->fix_capacity = 1;
- if (lu->workarounds & SBP2_WORKAROUND_POWER_CONDITION)
- sdev->start_stop_pwr_cond = 1;
- if (lu->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
- blk_queue_max_hw_sectors(sdev->request_queue, 128 * 1024 / 512);
-
- blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE);
- return 0;
-}
-
-static void sbp2scsi_slave_destroy(struct scsi_device *sdev)
-{
- ((struct sbp2_lu *)sdev->host->hostdata[0])->sdev = NULL;
- return;
-}
-
-/*
- * Called by scsi stack when something has really gone wrong.
- * Usually called when a command has timed-out for some reason.
- */
-static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
-{
- struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0];
- struct sbp2_command_info *cmd;
- unsigned long flags;
-
- SBP2_INFO("aborting sbp2 command");
- scsi_print_command(SCpnt);
-
- if (sbp2util_node_is_available(lu)) {
- sbp2_agent_reset(lu, 1);
-
- /* Return a matching command structure to the free pool. */
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
- cmd = sbp2util_find_command_for_SCpnt(lu, SCpnt);
- if (cmd) {
- sbp2util_mark_command_completed(lu, cmd);
- if (cmd->Current_SCpnt) {
- cmd->Current_SCpnt->result = DID_ABORT << 16;
- cmd->Current_done(cmd->Current_SCpnt);
- }
- }
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
- sbp2scsi_complete_all_commands(lu, DID_BUS_BUSY);
- }
-
- return SUCCESS;
-}
-
-/*
- * Called by scsi stack when something has really gone wrong.
- */
-static int sbp2scsi_reset(struct scsi_cmnd *SCpnt)
-{
- struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0];
-
- SBP2_INFO("reset requested");
-
- if (sbp2util_node_is_available(lu)) {
- SBP2_INFO("generating sbp2 fetch agent reset");
- sbp2_agent_reset(lu, 1);
- }
-
- return SUCCESS;
-}
-
-static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct scsi_device *sdev;
- struct sbp2_lu *lu;
-
- if (!(sdev = to_scsi_device(dev)))
- return 0;
-
- if (!(lu = (struct sbp2_lu *)sdev->host->hostdata[0]))
- return 0;
-
- if (sbp2_long_sysfs_ieee1394_id)
- return sprintf(buf, "%016Lx:%06x:%04x\n",
- (unsigned long long)lu->ne->guid,
- lu->ud->directory_id, ORB_SET_LUN(lu->lun));
- else
- return sprintf(buf, "%016Lx:%d:%d\n",
- (unsigned long long)lu->ne->guid,
- lu->ud->id, ORB_SET_LUN(lu->lun));
-}
-
-MODULE_AUTHOR("Ben Collins <bcollins@debian.org>");
-MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
-MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
-MODULE_LICENSE("GPL");
-
-static int sbp2_module_init(void)
-{
- int ret;
-
- if (sbp2_serialize_io) {
- sbp2_shost_template.can_queue = 1;
- sbp2_shost_template.cmd_per_lun = 1;
- }
-
- sbp2_shost_template.max_sectors = sbp2_max_sectors;
-
- hpsb_register_highlevel(&sbp2_highlevel);
- ret = hpsb_register_protocol(&sbp2_driver);
- if (ret) {
- SBP2_ERR("Failed to register protocol");
- hpsb_unregister_highlevel(&sbp2_highlevel);
- return ret;
- }
- return 0;
-}
-
-static void __exit sbp2_module_exit(void)
-{
- hpsb_unregister_protocol(&sbp2_driver);
- hpsb_unregister_highlevel(&sbp2_highlevel);
-}
-
-module_init(sbp2_module_init);
-module_exit(sbp2_module_exit);
diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
deleted file mode 100644
index 64a3a66a8a39..000000000000
--- a/drivers/ieee1394/sbp2.h
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * sbp2.h - Defines and prototypes for sbp2.c
- *
- * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com)
- * jamesg@filanet.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 SBP2_H
-#define SBP2_H
-
-#define SBP2_DEVICE_NAME "sbp2"
-
-/*
- * There is no transport protocol limit to the CDB length, but we implement
- * a fixed length only. 16 bytes is enough for disks larger than 2 TB.
- */
-#define SBP2_MAX_CDB_SIZE 16
-
-/*
- * SBP-2 specific definitions
- */
-
-#define ORB_DIRECTION_WRITE_TO_MEDIA 0x0
-#define ORB_DIRECTION_READ_FROM_MEDIA 0x1
-#define ORB_DIRECTION_NO_DATA_TRANSFER 0x2
-
-#define ORB_SET_NULL_PTR(v) (((v) & 0x1) << 31)
-#define ORB_SET_NOTIFY(v) (((v) & 0x1) << 31)
-#define ORB_SET_RQ_FMT(v) (((v) & 0x3) << 29)
-#define ORB_SET_NODE_ID(v) (((v) & 0xffff) << 16)
-#define ORB_SET_STATUS_FIFO_HI(v, id) ((v) >> 32 | ORB_SET_NODE_ID(id))
-#define ORB_SET_STATUS_FIFO_LO(v) ((v) & 0xffffffff)
-#define ORB_SET_DATA_SIZE(v) ((v) & 0xffff)
-#define ORB_SET_PAGE_SIZE(v) (((v) & 0x7) << 16)
-#define ORB_SET_PAGE_TABLE_PRESENT(v) (((v) & 0x1) << 19)
-#define ORB_SET_MAX_PAYLOAD(v) (((v) & 0xf) << 20)
-#define ORB_SET_SPEED(v) (((v) & 0x7) << 24)
-#define ORB_SET_DIRECTION(v) (((v) & 0x1) << 27)
-
-struct sbp2_command_orb {
- u32 next_ORB_hi;
- u32 next_ORB_lo;
- u32 data_descriptor_hi;
- u32 data_descriptor_lo;
- u32 misc;
- u8 cdb[SBP2_MAX_CDB_SIZE];
-} __attribute__((packed));
-
-#define SBP2_LOGIN_REQUEST 0x0
-#define SBP2_QUERY_LOGINS_REQUEST 0x1
-#define SBP2_RECONNECT_REQUEST 0x3
-#define SBP2_SET_PASSWORD_REQUEST 0x4
-#define SBP2_LOGOUT_REQUEST 0x7
-#define SBP2_ABORT_TASK_REQUEST 0xb
-#define SBP2_ABORT_TASK_SET 0xc
-#define SBP2_LOGICAL_UNIT_RESET 0xe
-#define SBP2_TARGET_RESET_REQUEST 0xf
-
-#define ORB_SET_LUN(v) ((v) & 0xffff)
-#define ORB_SET_FUNCTION(v) (((v) & 0xf) << 16)
-#define ORB_SET_RECONNECT(v) (((v) & 0xf) << 20)
-#define ORB_SET_EXCLUSIVE(v) ((v) ? 1 << 28 : 0)
-#define ORB_SET_LOGIN_RESP_LENGTH(v) ((v) & 0xffff)
-#define ORB_SET_PASSWD_LENGTH(v) (((v) & 0xffff) << 16)
-
-struct sbp2_login_orb {
- u32 password_hi;
- u32 password_lo;
- u32 login_response_hi;
- u32 login_response_lo;
- u32 lun_misc;
- u32 passwd_resp_lengths;
- u32 status_fifo_hi;
- u32 status_fifo_lo;
-} __attribute__((packed));
-
-#define RESPONSE_GET_LOGIN_ID(v) ((v) & 0xffff)
-#define RESPONSE_GET_LENGTH(v) (((v) >> 16) & 0xffff)
-#define RESPONSE_GET_RECONNECT_HOLD(v) ((v) & 0xffff)
-
-struct sbp2_login_response {
- u32 length_login_ID;
- u32 command_block_agent_hi;
- u32 command_block_agent_lo;
- u32 reconnect_hold;
-} __attribute__((packed));
-
-#define ORB_SET_LOGIN_ID(v) ((v) & 0xffff)
-#define ORB_SET_QUERY_LOGINS_RESP_LENGTH(v) ((v) & 0xffff)
-
-struct sbp2_query_logins_orb {
- u32 reserved1;
- u32 reserved2;
- u32 query_response_hi;
- u32 query_response_lo;
- u32 lun_misc;
- u32 reserved_resp_length;
- u32 status_fifo_hi;
- u32 status_fifo_lo;
-} __attribute__((packed));
-
-#define RESPONSE_GET_MAX_LOGINS(v) ((v) & 0xffff)
-#define RESPONSE_GET_ACTIVE_LOGINS(v) ((RESPONSE_GET_LENGTH((v)) - 4) / 12)
-
-struct sbp2_query_logins_response {
- u32 length_max_logins;
- u32 misc_IDs;
- u32 initiator_misc_hi;
- u32 initiator_misc_lo;
-} __attribute__((packed));
-
-struct sbp2_reconnect_orb {
- u32 reserved1;
- u32 reserved2;
- u32 reserved3;
- u32 reserved4;
- u32 login_ID_misc;
- u32 reserved5;
- u32 status_fifo_hi;
- u32 status_fifo_lo;
-} __attribute__((packed));
-
-struct sbp2_logout_orb {
- u32 reserved1;
- u32 reserved2;
- u32 reserved3;
- u32 reserved4;
- u32 login_ID_misc;
- u32 reserved5;
- u32 status_fifo_hi;
- u32 status_fifo_lo;
-} __attribute__((packed));
-
-struct sbp2_unrestricted_page_table {
- __be32 high;
- __be32 low;
-};
-
-#define RESP_STATUS_REQUEST_COMPLETE 0x0
-#define RESP_STATUS_TRANSPORT_FAILURE 0x1
-#define RESP_STATUS_ILLEGAL_REQUEST 0x2
-#define RESP_STATUS_VENDOR_DEPENDENT 0x3
-
-#define SBP2_STATUS_NO_ADDITIONAL_INFO 0x0
-#define SBP2_STATUS_REQ_TYPE_NOT_SUPPORTED 0x1
-#define SBP2_STATUS_SPEED_NOT_SUPPORTED 0x2
-#define SBP2_STATUS_PAGE_SIZE_NOT_SUPPORTED 0x3
-#define SBP2_STATUS_ACCESS_DENIED 0x4
-#define SBP2_STATUS_LU_NOT_SUPPORTED 0x5
-#define SBP2_STATUS_MAX_PAYLOAD_TOO_SMALL 0x6
-#define SBP2_STATUS_RESOURCES_UNAVAILABLE 0x8
-#define SBP2_STATUS_FUNCTION_REJECTED 0x9
-#define SBP2_STATUS_LOGIN_ID_NOT_RECOGNIZED 0xa
-#define SBP2_STATUS_DUMMY_ORB_COMPLETED 0xb
-#define SBP2_STATUS_REQUEST_ABORTED 0xc
-#define SBP2_STATUS_UNSPECIFIED_ERROR 0xff
-
-#define SFMT_CURRENT_ERROR 0x0
-#define SFMT_DEFERRED_ERROR 0x1
-#define SFMT_VENDOR_DEPENDENT_STATUS 0x3
-
-#define STATUS_GET_SRC(v) (((v) >> 30) & 0x3)
-#define STATUS_GET_RESP(v) (((v) >> 28) & 0x3)
-#define STATUS_GET_LEN(v) (((v) >> 24) & 0x7)
-#define STATUS_GET_SBP_STATUS(v) (((v) >> 16) & 0xff)
-#define STATUS_GET_ORB_OFFSET_HI(v) ((v) & 0x0000ffff)
-#define STATUS_TEST_DEAD(v) ((v) & 0x08000000)
-/* test 'resp' | 'dead' | 'sbp2_status' */
-#define STATUS_TEST_RDS(v) ((v) & 0x38ff0000)
-
-struct sbp2_status_block {
- u32 ORB_offset_hi_misc;
- u32 ORB_offset_lo;
- u8 command_set_dependent[24];
-} __attribute__((packed));
-
-
-/*
- * SBP2 related configuration ROM definitions
- */
-
-#define SBP2_UNIT_DIRECTORY_OFFSET_KEY 0xd1
-#define SBP2_CSR_OFFSET_KEY 0x54
-#define SBP2_UNIT_SPEC_ID_KEY 0x12
-#define SBP2_UNIT_SW_VERSION_KEY 0x13
-#define SBP2_COMMAND_SET_SPEC_ID_KEY 0x38
-#define SBP2_COMMAND_SET_KEY 0x39
-#define SBP2_UNIT_CHARACTERISTICS_KEY 0x3a
-#define SBP2_DEVICE_TYPE_AND_LUN_KEY 0x14
-#define SBP2_FIRMWARE_REVISION_KEY 0x3c
-
-#define SBP2_AGENT_STATE_OFFSET 0x00ULL
-#define SBP2_AGENT_RESET_OFFSET 0x04ULL
-#define SBP2_ORB_POINTER_OFFSET 0x08ULL
-#define SBP2_DOORBELL_OFFSET 0x10ULL
-#define SBP2_UNSOLICITED_STATUS_ENABLE_OFFSET 0x14ULL
-#define SBP2_UNSOLICITED_STATUS_VALUE 0xf
-
-#define SBP2_BUSY_TIMEOUT_ADDRESS 0xfffff0000210ULL
-/* biggest possible value for Single Phase Retry count is 0xf */
-#define SBP2_BUSY_TIMEOUT_VALUE 0xf
-
-#define SBP2_AGENT_RESET_DATA 0xf
-
-#define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e
-#define SBP2_SW_VERSION_ENTRY 0x00010483
-
-/*
- * The default maximum s/g segment size of a FireWire controller is
- * usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to
- * be quadlet-aligned, we set the length limit to 0xffff & ~3.
- */
-#define SBP2_MAX_SEG_SIZE 0xfffc
-
-/*
- * There is no real limitation of the queue depth (i.e. length of the linked
- * list of command ORBs) at the target. The chosen depth is merely an
- * implementation detail of the sbp2 driver.
- */
-#define SBP2_MAX_CMDS 8
-
-#define SBP2_SCSI_STATUS_GOOD 0x0
-#define SBP2_SCSI_STATUS_CHECK_CONDITION 0x2
-#define SBP2_SCSI_STATUS_CONDITION_MET 0x4
-#define SBP2_SCSI_STATUS_BUSY 0x8
-#define SBP2_SCSI_STATUS_RESERVATION_CONFLICT 0x18
-#define SBP2_SCSI_STATUS_COMMAND_TERMINATED 0x22
-#define SBP2_SCSI_STATUS_SELECTION_TIMEOUT 0xff
-
-
-/*
- * Representations of commands and devices
- */
-
-/* Per SCSI command */
-struct sbp2_command_info {
- struct list_head list;
- struct sbp2_command_orb command_orb;
- dma_addr_t command_orb_dma;
- struct scsi_cmnd *Current_SCpnt;
- void (*Current_done)(struct scsi_cmnd *);
-
- /* Also need s/g structure for each sbp2 command */
- struct sbp2_unrestricted_page_table
- scatter_gather_element[SG_ALL] __attribute__((aligned(8)));
- dma_addr_t sge_dma;
-};
-
-/* Per FireWire host */
-struct sbp2_fwhost_info {
- struct hpsb_host *host;
- struct list_head logical_units;
-};
-
-/* Per logical unit */
-struct sbp2_lu {
- /* Operation request blocks */
- struct sbp2_command_orb *last_orb;
- dma_addr_t last_orb_dma;
- struct sbp2_login_orb *login_orb;
- dma_addr_t login_orb_dma;
- struct sbp2_login_response *login_response;
- dma_addr_t login_response_dma;
- struct sbp2_query_logins_orb *query_logins_orb;
- dma_addr_t query_logins_orb_dma;
- struct sbp2_query_logins_response *query_logins_response;
- dma_addr_t query_logins_response_dma;
- struct sbp2_reconnect_orb *reconnect_orb;
- dma_addr_t reconnect_orb_dma;
- struct sbp2_logout_orb *logout_orb;
- dma_addr_t logout_orb_dma;
- struct sbp2_status_block status_block;
-
- /* How to talk to the unit */
- u64 management_agent_addr;
- u64 command_block_agent_addr;
- u32 speed_code;
- u32 max_payload_size;
- u16 lun;
-
- /* Address for the unit to write status blocks to */
- u64 status_fifo_addr;
-
- /* Waitqueue flag for logins, reconnects, logouts, query logins */
- unsigned int access_complete:1;
-
- /* Pool of command ORBs for this logical unit */
- spinlock_t cmd_orb_lock;
- struct list_head cmd_orb_inuse;
- struct list_head cmd_orb_completed;
-
- /* Backlink to FireWire host; list of units attached to the host */
- struct sbp2_fwhost_info *hi;
- struct list_head lu_list;
-
- /* IEEE 1394 core's device representations */
- struct node_entry *ne;
- struct unit_directory *ud;
-
- /* SCSI core's device representations */
- struct scsi_device *sdev;
- struct Scsi_Host *shost;
-
- /* Device specific workarounds/brokeness */
- unsigned workarounds;
-
- /* Connection state */
- atomic_t state;
-
- /* For deferred requests to the fetch agent */
- struct work_struct protocol_work;
-};
-
-/* For use in sbp2_lu.state */
-enum sbp2lu_state_types {
- SBP2LU_STATE_RUNNING, /* all normal */
- SBP2LU_STATE_IN_RESET, /* between bus reset and reconnect */
- SBP2LU_STATE_IN_SHUTDOWN /* when sbp2_remove was called */
-};
-
-/* For use in sbp2_lu.workarounds and in the corresponding
- * module load parameter */
-#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
-#define SBP2_WORKAROUND_INQUIRY_36 0x2
-#define SBP2_WORKAROUND_MODE_SENSE_8 0x4
-#define SBP2_WORKAROUND_FIX_CAPACITY 0x8
-#define SBP2_WORKAROUND_DELAY_INQUIRY 0x10
-#define SBP2_INQUIRY_DELAY 12
-#define SBP2_WORKAROUND_POWER_CONDITION 0x20
-#define SBP2_WORKAROUND_OVERRIDE 0x100
-
-#endif /* SBP2_H */
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
deleted file mode 100644
index 5c74f796d7f1..000000000000
--- a/drivers/ieee1394/video1394.c
+++ /dev/null
@@ -1,1528 +0,0 @@
-/*
- * video1394.c - video driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- * Peter Schlaile <udbz@rz.uni-karlsruhe.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This 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.
- *
- * NOTES:
- *
- * ioctl return codes:
- * EFAULT is only for invalid address for the argp
- * EINVAL for out of range values
- * EBUSY when trying to use an already used resource
- * ESRCH when trying to free/stop a not used resource
- * EAGAIN for resource allocation failure that could perhaps succeed later
- * ENOTTY for unsupported ioctl request
- *
- */
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/timex.h>
-#include <linux/mm.h>
-#include <linux/compat.h>
-#include <linux/cdev.h>
-
-#include "dma.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_types.h"
-#include "nodemgr.h"
-#include "ohci1394.h"
-#include "video1394.h"
-
-#define ISO_CHANNELS 64
-
-struct it_dma_prg {
- struct dma_cmd begin;
- quadlet_t data[4];
- struct dma_cmd end;
- quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */
-};
-
-struct dma_iso_ctx {
- struct ti_ohci *ohci;
- int type; /* OHCI_ISO_TRANSMIT or OHCI_ISO_RECEIVE */
- struct ohci1394_iso_tasklet iso_tasklet;
- int channel;
- int ctx;
- int last_buffer;
- int * next_buffer; /* For ISO Transmit of video packets
- to write the correct SYT field
- into the next block */
- unsigned int num_desc;
- unsigned int buf_size;
- unsigned int frame_size;
- unsigned int packet_size;
- unsigned int left_size;
- unsigned int nb_cmd;
-
- struct dma_region dma;
-
- struct dma_prog_region *prg_reg;
-
- struct dma_cmd **ir_prg;
- struct it_dma_prg **it_prg;
-
- unsigned int *buffer_status;
- unsigned int *buffer_prg_assignment;
- struct timeval *buffer_time; /* time when the buffer was received */
- unsigned int *last_used_cmd; /* For ISO Transmit with
- variable sized packets only ! */
- int ctrlClear;
- int ctrlSet;
- int cmdPtr;
- int ctxMatch;
- wait_queue_head_t waitq;
- spinlock_t lock;
- unsigned int syt_offset;
- int flags;
-
- struct list_head link;
-};
-
-
-struct file_ctx {
- struct ti_ohci *ohci;
- struct list_head context_list;
- struct dma_iso_ctx *current_ctx;
-};
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define VIDEO1394_DEBUG
-#endif
-
-#ifdef DBGMSG
-#undef DBGMSG
-#endif
-
-#ifdef VIDEO1394_DEBUG
-#define DBGMSG(card, fmt, args...) \
-printk(KERN_INFO "video1394_%d: " fmt "\n" , card , ## args)
-#else
-#define DBGMSG(card, fmt, args...) do {} while (0)
-#endif
-
-/* print general (card independent) information */
-#define PRINT_G(level, fmt, args...) \
-printk(level "video1394: " fmt "\n" , ## args)
-
-/* print card specific information */
-#define PRINT(level, card, fmt, args...) \
-printk(level "video1394_%d: " fmt "\n" , card , ## args)
-
-static void wakeup_dma_ir_ctx(unsigned long l);
-static void wakeup_dma_it_ctx(unsigned long l);
-
-static struct hpsb_highlevel video1394_highlevel;
-
-static int free_dma_iso_ctx(struct dma_iso_ctx *d)
-{
- int i;
-
- DBGMSG(d->ohci->host->id, "Freeing dma_iso_ctx %d", d->ctx);
-
- ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
- if (d->iso_tasklet.link.next != NULL)
- ohci1394_unregister_iso_tasklet(d->ohci, &d->iso_tasklet);
-
- dma_region_free(&d->dma);
-
- if (d->prg_reg) {
- for (i = 0; i < d->num_desc; i++)
- dma_prog_region_free(&d->prg_reg[i]);
- kfree(d->prg_reg);
- }
-
- kfree(d->ir_prg);
- kfree(d->it_prg);
- kfree(d->buffer_status);
- kfree(d->buffer_prg_assignment);
- kfree(d->buffer_time);
- kfree(d->last_used_cmd);
- kfree(d->next_buffer);
- list_del(&d->link);
- kfree(d);
-
- return 0;
-}
-
-static struct dma_iso_ctx *
-alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc,
- int buf_size, int channel, unsigned int packet_size)
-{
- struct dma_iso_ctx *d;
- int i;
-
- d = kzalloc(sizeof(*d), GFP_KERNEL);
- if (!d) {
- PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma_iso_ctx");
- return NULL;
- }
-
- d->ohci = ohci;
- d->type = type;
- d->channel = channel;
- d->num_desc = num_desc;
- d->frame_size = buf_size;
- d->buf_size = PAGE_ALIGN(buf_size);
- d->last_buffer = -1;
- INIT_LIST_HEAD(&d->link);
- init_waitqueue_head(&d->waitq);
-
- /* Init the regions for easy cleanup */
- dma_region_init(&d->dma);
-
- if (dma_region_alloc(&d->dma, (d->num_desc - 1) * d->buf_size, ohci->dev,
- PCI_DMA_BIDIRECTIONAL)) {
- PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma buffer");
- free_dma_iso_ctx(d);
- return NULL;
- }
-
- if (type == OHCI_ISO_RECEIVE)
- ohci1394_init_iso_tasklet(&d->iso_tasklet, type,
- wakeup_dma_ir_ctx,
- (unsigned long) d);
- else
- ohci1394_init_iso_tasklet(&d->iso_tasklet, type,
- wakeup_dma_it_ctx,
- (unsigned long) d);
-
- if (ohci1394_register_iso_tasklet(ohci, &d->iso_tasklet) < 0) {
- PRINT(KERN_ERR, ohci->host->id, "no free iso %s contexts",
- type == OHCI_ISO_RECEIVE ? "receive" : "transmit");
- free_dma_iso_ctx(d);
- return NULL;
- }
- d->ctx = d->iso_tasklet.context;
-
- d->prg_reg = kmalloc(d->num_desc * sizeof(*d->prg_reg), GFP_KERNEL);
- if (!d->prg_reg) {
- PRINT(KERN_ERR, ohci->host->id, "Failed to allocate ir prg regs");
- free_dma_iso_ctx(d);
- return NULL;
- }
- /* Makes for easier cleanup */
- for (i = 0; i < d->num_desc; i++)
- dma_prog_region_init(&d->prg_reg[i]);
-
- if (type == OHCI_ISO_RECEIVE) {
- d->ctrlSet = OHCI1394_IsoRcvContextControlSet+32*d->ctx;
- d->ctrlClear = OHCI1394_IsoRcvContextControlClear+32*d->ctx;
- d->cmdPtr = OHCI1394_IsoRcvCommandPtr+32*d->ctx;
- d->ctxMatch = OHCI1394_IsoRcvContextMatch+32*d->ctx;
-
- d->ir_prg = kzalloc(d->num_desc * sizeof(*d->ir_prg),
- GFP_KERNEL);
-
- if (!d->ir_prg) {
- PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma ir prg");
- free_dma_iso_ctx(d);
- return NULL;
- }
-
- d->nb_cmd = d->buf_size / PAGE_SIZE + 1;
- d->left_size = (d->frame_size % PAGE_SIZE) ?
- d->frame_size % PAGE_SIZE : PAGE_SIZE;
-
- for (i = 0;i < d->num_desc; i++) {
- if (dma_prog_region_alloc(&d->prg_reg[i], d->nb_cmd *
- sizeof(struct dma_cmd), ohci->dev)) {
- PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma ir prg");
- free_dma_iso_ctx(d);
- return NULL;
- }
- d->ir_prg[i] = (struct dma_cmd *)d->prg_reg[i].kvirt;
- }
-
- } else { /* OHCI_ISO_TRANSMIT */
- d->ctrlSet = OHCI1394_IsoXmitContextControlSet+16*d->ctx;
- d->ctrlClear = OHCI1394_IsoXmitContextControlClear+16*d->ctx;
- d->cmdPtr = OHCI1394_IsoXmitCommandPtr+16*d->ctx;
-
- d->it_prg = kzalloc(d->num_desc * sizeof(*d->it_prg),
- GFP_KERNEL);
-
- if (!d->it_prg) {
- PRINT(KERN_ERR, ohci->host->id,
- "Failed to allocate dma it prg");
- free_dma_iso_ctx(d);
- return NULL;
- }
-
- d->packet_size = packet_size;
-
- if (PAGE_SIZE % packet_size || packet_size>4096) {
- PRINT(KERN_ERR, ohci->host->id,
- "Packet size %d (page_size: %ld) "
- "not yet supported\n",
- packet_size, PAGE_SIZE);
- free_dma_iso_ctx(d);
- return NULL;
- }
-
- d->nb_cmd = d->frame_size / d->packet_size;
- if (d->frame_size % d->packet_size) {
- d->nb_cmd++;
- d->left_size = d->frame_size % d->packet_size;
- } else
- d->left_size = d->packet_size;
-
- for (i = 0; i < d->num_desc; i++) {
- if (dma_prog_region_alloc(&d->prg_reg[i], d->nb_cmd *
- sizeof(struct it_dma_prg), ohci->dev)) {
- PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma it prg");
- free_dma_iso_ctx(d);
- return NULL;
- }
- d->it_prg[i] = (struct it_dma_prg *)d->prg_reg[i].kvirt;
- }
- }
-
- d->buffer_status =
- kzalloc(d->num_desc * sizeof(*d->buffer_status), GFP_KERNEL);
- d->buffer_prg_assignment =
- kzalloc(d->num_desc * sizeof(*d->buffer_prg_assignment), GFP_KERNEL);
- d->buffer_time =
- kzalloc(d->num_desc * sizeof(*d->buffer_time), GFP_KERNEL);
- d->last_used_cmd =
- kzalloc(d->num_desc * sizeof(*d->last_used_cmd), GFP_KERNEL);
- d->next_buffer =
- kzalloc(d->num_desc * sizeof(*d->next_buffer), GFP_KERNEL);
-
- if (!d->buffer_status || !d->buffer_prg_assignment || !d->buffer_time ||
- !d->last_used_cmd || !d->next_buffer) {
- PRINT(KERN_ERR, ohci->host->id,
- "Failed to allocate dma_iso_ctx member");
- free_dma_iso_ctx(d);
- return NULL;
- }
-
- spin_lock_init(&d->lock);
-
- DBGMSG(ohci->host->id, "Iso %s DMA: %d buffers "
- "of size %d allocated for a frame size %d, each with %d prgs",
- (type == OHCI_ISO_RECEIVE) ? "receive" : "transmit",
- d->num_desc - 1, d->buf_size, d->frame_size, d->nb_cmd);
-
- return d;
-}
-
-static void reset_ir_status(struct dma_iso_ctx *d, int n)
-{
- int i;
- d->ir_prg[n][0].status = cpu_to_le32(4);
- d->ir_prg[n][1].status = cpu_to_le32(PAGE_SIZE-4);
- for (i = 2; i < d->nb_cmd - 1; i++)
- d->ir_prg[n][i].status = cpu_to_le32(PAGE_SIZE);
- d->ir_prg[n][i].status = cpu_to_le32(d->left_size);
-}
-
-static void reprogram_dma_ir_prg(struct dma_iso_ctx *d, int n, int buffer, int flags)
-{
- struct dma_cmd *ir_prg = d->ir_prg[n];
- unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size;
- int i;
-
- d->buffer_prg_assignment[n] = buffer;
-
- ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf -
- (unsigned long)d->dma.kvirt));
- ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
- (buf + 4) - (unsigned long)d->dma.kvirt));
-
- for (i=2;i<d->nb_cmd-1;i++) {
- ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
- (buf+(i-1)*PAGE_SIZE) -
- (unsigned long)d->dma.kvirt));
- }
-
- ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
- DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size);
- ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
- (buf+(i-1)*PAGE_SIZE) - (unsigned long)d->dma.kvirt));
-}
-
-static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags)
-{
- struct dma_cmd *ir_prg = d->ir_prg[n];
- struct dma_prog_region *ir_reg = &d->prg_reg[n];
- unsigned long buf = (unsigned long)d->dma.kvirt;
- int i;
-
- /* the first descriptor will read only 4 bytes */
- ir_prg[0].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
- DMA_CTL_BRANCH | 4);
-
- /* set the sync flag */
- if (flags & VIDEO1394_SYNC_FRAMES)
- ir_prg[0].control |= cpu_to_le32(DMA_CTL_WAIT);
-
- ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf -
- (unsigned long)d->dma.kvirt));
- ir_prg[0].branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
- 1 * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
-
- /* If there is *not* only one DMA page per frame (hence, d->nb_cmd==2) */
- if (d->nb_cmd > 2) {
- /* The second descriptor will read PAGE_SIZE-4 bytes */
- ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
- DMA_CTL_BRANCH | (PAGE_SIZE-4));
- ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf + 4) -
- (unsigned long)d->dma.kvirt));
- ir_prg[1].branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
- 2 * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
-
- for (i = 2; i < d->nb_cmd - 1; i++) {
- ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
- DMA_CTL_BRANCH | PAGE_SIZE);
- ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
- (buf+(i-1)*PAGE_SIZE) -
- (unsigned long)d->dma.kvirt));
-
- ir_prg[i].branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
- (i + 1) * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
- }
-
- /* The last descriptor will generate an interrupt */
- ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
- DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size);
- ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
- (buf+(i-1)*PAGE_SIZE) -
- (unsigned long)d->dma.kvirt));
- } else {
- /* Only one DMA page is used. Read d->left_size immediately and */
- /* generate an interrupt as this is also the last page. */
- ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
- DMA_CTL_IRQ | DMA_CTL_BRANCH | (d->left_size-4));
- ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
- (buf + 4) - (unsigned long)d->dma.kvirt));
- }
-}
-
-static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags)
-{
- struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;
- int i;
-
- d->flags = flags;
-
- ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
- for (i=0;i<d->num_desc;i++) {
- initialize_dma_ir_prg(d, i, flags);
- reset_ir_status(d, i);
- }
-
- /* reset the ctrl register */
- reg_write(ohci, d->ctrlClear, 0xf0000000);
-
- /* Set bufferFill */
- reg_write(ohci, d->ctrlSet, 0x80000000);
-
- /* Set isoch header */
- if (flags & VIDEO1394_INCLUDE_ISO_HEADERS)
- reg_write(ohci, d->ctrlSet, 0x40000000);
-
- /* Set the context match register to match on all tags,
- sync for sync tag, and listen to d->channel */
- reg_write(ohci, d->ctxMatch, 0xf0000000|((tag&0xf)<<8)|d->channel);
-
- /* Set up isoRecvIntMask to generate interrupts */
- reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1<<d->ctx);
-}
-
-/* find which context is listening to this channel */
-static struct dma_iso_ctx *
-find_ctx(struct list_head *list, int type, int channel)
-{
- struct dma_iso_ctx *ctx;
-
- list_for_each_entry(ctx, list, link) {
- if (ctx->type == type && ctx->channel == channel)
- return ctx;
- }
-
- return NULL;
-}
-
-static void wakeup_dma_ir_ctx(unsigned long l)
-{
- struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;
- int i;
-
- spin_lock(&d->lock);
-
- for (i = 0; i < d->num_desc; i++) {
- if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) {
- reset_ir_status(d, i);
- d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
- do_gettimeofday(&d->buffer_time[d->buffer_prg_assignment[i]]);
- dma_region_sync_for_cpu(&d->dma,
- d->buffer_prg_assignment[i] * d->buf_size,
- d->buf_size);
- }
- }
-
- spin_unlock(&d->lock);
-
- if (waitqueue_active(&d->waitq))
- wake_up_interruptible(&d->waitq);
-}
-
-static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d,
- int n)
-{
- unsigned char* buf = d->dma.kvirt + n * d->buf_size;
- u32 cycleTimer;
- u32 timeStamp;
-
- if (n == -1) {
- return;
- }
-
- cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-
- timeStamp = ((cycleTimer & 0x0fff) + d->syt_offset); /* 11059 = 450 us */
- timeStamp = (timeStamp % 3072 + ((timeStamp / 3072) << 12)
- + (cycleTimer & 0xf000)) & 0xffff;
-
- buf[6] = timeStamp >> 8;
- buf[7] = timeStamp & 0xff;
-
- /* if first packet is empty packet, then put timestamp into the next full one too */
- if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) {
- buf += d->packet_size;
- buf[6] = timeStamp >> 8;
- buf[7] = timeStamp & 0xff;
- }
-
- /* do the next buffer frame too in case of irq latency */
- n = d->next_buffer[n];
- if (n == -1) {
- return;
- }
- buf = d->dma.kvirt + n * d->buf_size;
-
- timeStamp += (d->last_used_cmd[n] << 12) & 0xffff;
-
- buf[6] = timeStamp >> 8;
- buf[7] = timeStamp & 0xff;
-
- /* if first packet is empty packet, then put timestamp into the next full one too */
- if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) {
- buf += d->packet_size;
- buf[6] = timeStamp >> 8;
- buf[7] = timeStamp & 0xff;
- }
-
-#if 0
- printk("curr: %d, next: %d, cycleTimer: %08x timeStamp: %08x\n",
- curr, n, cycleTimer, timeStamp);
-#endif
-}
-
-static void wakeup_dma_it_ctx(unsigned long l)
-{
- struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;
- struct ti_ohci *ohci = d->ohci;
- int i;
-
- spin_lock(&d->lock);
-
- for (i = 0; i < d->num_desc; i++) {
- if (d->it_prg[i][d->last_used_cmd[i]].end.status &
- cpu_to_le32(0xFFFF0000)) {
- int next = d->next_buffer[i];
- put_timestamp(ohci, d, next);
- d->it_prg[i][d->last_used_cmd[i]].end.status = 0;
- d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
- }
- }
-
- spin_unlock(&d->lock);
-
- if (waitqueue_active(&d->waitq))
- wake_up_interruptible(&d->waitq);
-}
-
-static void reprogram_dma_it_prg(struct dma_iso_ctx *d, int n, int buffer)
-{
- struct it_dma_prg *it_prg = d->it_prg[n];
- unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size;
- int i;
-
- d->buffer_prg_assignment[n] = buffer;
- for (i=0;i<d->nb_cmd;i++) {
- it_prg[i].end.address =
- cpu_to_le32(dma_region_offset_to_bus(&d->dma,
- (buf+i*d->packet_size) - (unsigned long)d->dma.kvirt));
- }
-}
-
-static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag)
-{
- struct it_dma_prg *it_prg = d->it_prg[n];
- struct dma_prog_region *it_reg = &d->prg_reg[n];
- unsigned long buf = (unsigned long)d->dma.kvirt;
- int i;
- d->last_used_cmd[n] = d->nb_cmd - 1;
- for (i=0;i<d->nb_cmd;i++) {
-
- it_prg[i].begin.control = cpu_to_le32(DMA_CTL_OUTPUT_MORE |
- DMA_CTL_IMMEDIATE | 8) ;
- it_prg[i].begin.address = 0;
-
- it_prg[i].begin.status = 0;
-
- it_prg[i].data[0] = cpu_to_le32(
- (IEEE1394_SPEED_100 << 16)
- | (/* tag */ 1 << 14)
- | (d->channel << 8)
- | (TCODE_ISO_DATA << 4));
- if (i==0) it_prg[i].data[0] |= cpu_to_le32(sync_tag);
- it_prg[i].data[1] = cpu_to_le32(d->packet_size << 16);
- it_prg[i].data[2] = 0;
- it_prg[i].data[3] = 0;
-
- it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST |
- DMA_CTL_BRANCH);
- it_prg[i].end.address =
- cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf+i*d->packet_size) -
- (unsigned long)d->dma.kvirt));
-
- if (i<d->nb_cmd-1) {
- it_prg[i].end.control |= cpu_to_le32(d->packet_size);
- it_prg[i].begin.branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
- sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
- it_prg[i].end.branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
- sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
- } else {
- /* the last prg generates an interrupt */
- it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE |
- DMA_CTL_IRQ | d->left_size);
- /* the last prg doesn't branch */
- it_prg[i].begin.branchAddress = 0;
- it_prg[i].end.branchAddress = 0;
- }
- it_prg[i].end.status = 0;
- }
-}
-
-static void initialize_dma_it_prg_var_packet_queue(
- struct dma_iso_ctx *d, int n, unsigned int * packet_sizes,
- struct ti_ohci *ohci)
-{
- struct it_dma_prg *it_prg = d->it_prg[n];
- struct dma_prog_region *it_reg = &d->prg_reg[n];
- int i;
-
-#if 0
- if (n != -1) {
- put_timestamp(ohci, d, n);
- }
-#endif
- d->last_used_cmd[n] = d->nb_cmd - 1;
-
- for (i = 0; i < d->nb_cmd; i++) {
- unsigned int size;
- if (packet_sizes[i] > d->packet_size) {
- size = d->packet_size;
- } else {
- size = packet_sizes[i];
- }
- it_prg[i].data[1] = cpu_to_le32(size << 16);
- it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH);
-
- if (i < d->nb_cmd-1 && packet_sizes[i+1] != 0) {
- it_prg[i].end.control |= cpu_to_le32(size);
- it_prg[i].begin.branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
- sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
- it_prg[i].end.branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
- sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
- } else {
- /* the last prg generates an interrupt */
- it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE |
- DMA_CTL_IRQ | size);
- /* the last prg doesn't branch */
- it_prg[i].begin.branchAddress = 0;
- it_prg[i].end.branchAddress = 0;
- d->last_used_cmd[n] = i;
- break;
- }
- }
-}
-
-static void initialize_dma_it_ctx(struct dma_iso_ctx *d, int sync_tag,
- unsigned int syt_offset, int flags)
-{
- struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;
- int i;
-
- d->flags = flags;
- d->syt_offset = (syt_offset == 0 ? 11000 : syt_offset);
-
- ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
- for (i=0;i<d->num_desc;i++)
- initialize_dma_it_prg(d, i, sync_tag);
-
- /* Set up isoRecvIntMask to generate interrupts */
- reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx);
-}
-
-static inline unsigned video1394_buffer_state(struct dma_iso_ctx *d,
- unsigned int buffer)
-{
- unsigned long flags;
- unsigned int ret;
- spin_lock_irqsave(&d->lock, flags);
- ret = d->buffer_status[buffer];
- spin_unlock_irqrestore(&d->lock, flags);
- return ret;
-}
-
-static long video1394_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct file_ctx *ctx = file->private_data;
- struct ti_ohci *ohci = ctx->ohci;
- unsigned long flags;
- void __user *argp = (void __user *)arg;
-
- switch(cmd)
- {
- case VIDEO1394_IOC_LISTEN_CHANNEL:
- case VIDEO1394_IOC_TALK_CHANNEL:
- {
- struct video1394_mmap v;
- u64 mask;
- struct dma_iso_ctx *d;
- int i;
-
- if (copy_from_user(&v, argp, sizeof(v)))
- return -EFAULT;
-
- /* if channel < 0, find lowest available one */
- if (v.channel < 0) {
- mask = (u64)0x1;
- for (i=0; ; i++) {
- if (i == ISO_CHANNELS) {
- PRINT(KERN_ERR, ohci->host->id,
- "No free channel found");
- return -EAGAIN;
- }
- if (!(ohci->ISO_channel_usage & mask)) {
- v.channel = i;
- PRINT(KERN_INFO, ohci->host->id, "Found free channel %d", i);
- break;
- }
- mask = mask << 1;
- }
- } else if (v.channel >= ISO_CHANNELS) {
- PRINT(KERN_ERR, ohci->host->id,
- "Iso channel %d out of bounds", v.channel);
- return -EINVAL;
- } else {
- mask = (u64)0x1<<v.channel;
- }
- DBGMSG(ohci->host->id, "mask: %08X%08X usage: %08X%08X\n",
- (u32)(mask>>32),(u32)(mask&0xffffffff),
- (u32)(ohci->ISO_channel_usage>>32),
- (u32)(ohci->ISO_channel_usage&0xffffffff));
- if (ohci->ISO_channel_usage & mask) {
- PRINT(KERN_ERR, ohci->host->id,
- "Channel %d is already taken", v.channel);
- return -EBUSY;
- }
-
- if (v.buf_size == 0 || v.buf_size > VIDEO1394_MAX_SIZE) {
- PRINT(KERN_ERR, ohci->host->id,
- "Invalid %d length buffer requested",v.buf_size);
- return -EINVAL;
- }
-
- if (v.nb_buffers == 0 || v.nb_buffers > VIDEO1394_MAX_SIZE) {
- PRINT(KERN_ERR, ohci->host->id,
- "Invalid %d buffers requested",v.nb_buffers);
- return -EINVAL;
- }
-
- if (v.nb_buffers * v.buf_size > VIDEO1394_MAX_SIZE) {
- PRINT(KERN_ERR, ohci->host->id,
- "%d buffers of size %d bytes is too big",
- v.nb_buffers, v.buf_size);
- return -EINVAL;
- }
-
- if (cmd == VIDEO1394_IOC_LISTEN_CHANNEL) {
- d = alloc_dma_iso_ctx(ohci, OHCI_ISO_RECEIVE,
- v.nb_buffers + 1, v.buf_size,
- v.channel, 0);
-
- if (d == NULL) {
- PRINT(KERN_ERR, ohci->host->id,
- "Couldn't allocate ir context");
- return -EAGAIN;
- }
- initialize_dma_ir_ctx(d, v.sync_tag, v.flags);
-
- ctx->current_ctx = d;
-
- v.buf_size = d->buf_size;
- list_add_tail(&d->link, &ctx->context_list);
-
- DBGMSG(ohci->host->id,
- "iso context %d listen on channel %d",
- d->ctx, v.channel);
- }
- else {
- d = alloc_dma_iso_ctx(ohci, OHCI_ISO_TRANSMIT,
- v.nb_buffers + 1, v.buf_size,
- v.channel, v.packet_size);
-
- if (d == NULL) {
- PRINT(KERN_ERR, ohci->host->id,
- "Couldn't allocate it context");
- return -EAGAIN;
- }
- initialize_dma_it_ctx(d, v.sync_tag,
- v.syt_offset, v.flags);
-
- ctx->current_ctx = d;
-
- v.buf_size = d->buf_size;
-
- list_add_tail(&d->link, &ctx->context_list);
-
- DBGMSG(ohci->host->id,
- "Iso context %d talk on channel %d", d->ctx,
- v.channel);
- }
-
- if (copy_to_user(argp, &v, sizeof(v))) {
- /* FIXME : free allocated dma resources */
- return -EFAULT;
- }
-
- ohci->ISO_channel_usage |= mask;
-
- return 0;
- }
- case VIDEO1394_IOC_UNLISTEN_CHANNEL:
- case VIDEO1394_IOC_UNTALK_CHANNEL:
- {
- int channel;
- u64 mask;
- struct dma_iso_ctx *d;
-
- if (copy_from_user(&channel, argp, sizeof(int)))
- return -EFAULT;
-
- if (channel < 0 || channel >= ISO_CHANNELS) {
- PRINT(KERN_ERR, ohci->host->id,
- "Iso channel %d out of bound", channel);
- return -EINVAL;
- }
- mask = (u64)0x1<<channel;
- if (!(ohci->ISO_channel_usage & mask)) {
- PRINT(KERN_ERR, ohci->host->id,
- "Channel %d is not being used", channel);
- return -ESRCH;
- }
-
- /* Mark this channel as unused */
- ohci->ISO_channel_usage &= ~mask;
-
- if (cmd == VIDEO1394_IOC_UNLISTEN_CHANNEL)
- d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, channel);
- else
- d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, channel);
-
- if (d == NULL) return -ESRCH;
- DBGMSG(ohci->host->id, "Iso context %d "
- "stop talking on channel %d", d->ctx, channel);
- free_dma_iso_ctx(d);
-
- return 0;
- }
- case VIDEO1394_IOC_LISTEN_QUEUE_BUFFER:
- {
- struct video1394_wait v;
- struct dma_iso_ctx *d;
- int next_prg;
-
- if (unlikely(copy_from_user(&v, argp, sizeof(v))))
- return -EFAULT;
-
- d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
- if (unlikely(d == NULL))
- return -EFAULT;
-
- if (unlikely(v.buffer >= d->num_desc - 1)) {
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d out of range",v.buffer);
- return -EINVAL;
- }
-
- spin_lock_irqsave(&d->lock,flags);
-
- if (unlikely(d->buffer_status[v.buffer]==VIDEO1394_BUFFER_QUEUED)) {
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d is already used",v.buffer);
- spin_unlock_irqrestore(&d->lock,flags);
- return -EBUSY;
- }
-
- d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
-
- next_prg = (d->last_buffer + 1) % d->num_desc;
- if (d->last_buffer>=0)
- d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0)
- & 0xfffffff0) | 0x1);
-
- d->last_buffer = next_prg;
- reprogram_dma_ir_prg(d, d->last_buffer, v.buffer, d->flags);
-
- d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 0;
-
- spin_unlock_irqrestore(&d->lock,flags);
-
- if (!(reg_read(ohci, d->ctrlSet) & 0x8000))
- {
- DBGMSG(ohci->host->id, "Starting iso DMA ctx=%d",d->ctx);
-
- /* Tell the controller where the first program is */
- reg_write(ohci, d->cmdPtr,
- dma_prog_region_offset_to_bus(&d->prg_reg[d->last_buffer], 0) | 0x1);
-
- /* Run IR context */
- reg_write(ohci, d->ctrlSet, 0x8000);
- }
- else {
- /* Wake up dma context if necessary */
- if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
- DBGMSG(ohci->host->id,
- "Waking up iso dma ctx=%d", d->ctx);
- reg_write(ohci, d->ctrlSet, 0x1000);
- }
- }
- return 0;
-
- }
- case VIDEO1394_IOC_LISTEN_WAIT_BUFFER:
- case VIDEO1394_IOC_LISTEN_POLL_BUFFER:
- {
- struct video1394_wait v;
- struct dma_iso_ctx *d;
- int i = 0;
-
- if (unlikely(copy_from_user(&v, argp, sizeof(v))))
- return -EFAULT;
-
- d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
- if (unlikely(d == NULL))
- return -EFAULT;
-
- if (unlikely(v.buffer > d->num_desc - 1)) {
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d out of range",v.buffer);
- return -EINVAL;
- }
-
- /*
- * I change the way it works so that it returns
- * the last received frame.
- */
- spin_lock_irqsave(&d->lock, flags);
- switch(d->buffer_status[v.buffer]) {
- case VIDEO1394_BUFFER_READY:
- d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
- break;
- case VIDEO1394_BUFFER_QUEUED:
- if (cmd == VIDEO1394_IOC_LISTEN_POLL_BUFFER) {
- /* for polling, return error code EINTR */
- spin_unlock_irqrestore(&d->lock, flags);
- return -EINTR;
- }
-
- spin_unlock_irqrestore(&d->lock, flags);
- wait_event_interruptible(d->waitq,
- video1394_buffer_state(d, v.buffer) ==
- VIDEO1394_BUFFER_READY);
- if (signal_pending(current))
- return -EINTR;
- spin_lock_irqsave(&d->lock, flags);
- d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
- break;
- default:
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d is not queued",v.buffer);
- spin_unlock_irqrestore(&d->lock, flags);
- return -ESRCH;
- }
-
- /* set time of buffer */
- v.filltime = d->buffer_time[v.buffer];
-
- /*
- * Look ahead to see how many more buffers have been received
- */
- i=0;
- while (d->buffer_status[(v.buffer+1)%(d->num_desc - 1)]==
- VIDEO1394_BUFFER_READY) {
- v.buffer=(v.buffer+1)%(d->num_desc - 1);
- i++;
- }
- spin_unlock_irqrestore(&d->lock, flags);
-
- v.buffer=i;
- if (unlikely(copy_to_user(argp, &v, sizeof(v))))
- return -EFAULT;
-
- return 0;
- }
- case VIDEO1394_IOC_TALK_QUEUE_BUFFER:
- {
- struct video1394_wait v;
- unsigned int *psizes = NULL;
- struct dma_iso_ctx *d;
- int next_prg;
-
- if (copy_from_user(&v, argp, sizeof(v)))
- return -EFAULT;
-
- d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
- if (d == NULL) return -EFAULT;
-
- if (v.buffer >= d->num_desc - 1) {
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d out of range",v.buffer);
- return -EINVAL;
- }
-
- if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) {
- int buf_size = d->nb_cmd * sizeof(*psizes);
- struct video1394_queue_variable __user *p = argp;
- unsigned int __user *qv;
-
- if (get_user(qv, &p->packet_sizes))
- return -EFAULT;
-
- psizes = memdup_user(qv, buf_size);
- if (IS_ERR(psizes))
- return PTR_ERR(psizes);
- }
-
- spin_lock_irqsave(&d->lock,flags);
-
- /* last_buffer is last_prg */
- next_prg = (d->last_buffer + 1) % d->num_desc;
- if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) {
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d is already used",v.buffer);
- spin_unlock_irqrestore(&d->lock,flags);
- kfree(psizes);
- return -EBUSY;
- }
-
- if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) {
- initialize_dma_it_prg_var_packet_queue(
- d, next_prg, psizes, ohci);
- }
-
- d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
-
- if (d->last_buffer >= 0) {
- d->it_prg[d->last_buffer]
- [ d->last_used_cmd[d->last_buffer] ].end.branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg],
- 0) & 0xfffffff0) | 0x3);
-
- d->it_prg[d->last_buffer]
- [ d->last_used_cmd[d->last_buffer] ].begin.branchAddress =
- cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg],
- 0) & 0xfffffff0) | 0x3);
- d->next_buffer[d->last_buffer] = (v.buffer + 1) % (d->num_desc - 1);
- }
- d->last_buffer = next_prg;
- reprogram_dma_it_prg(d, d->last_buffer, v.buffer);
- d->next_buffer[d->last_buffer] = -1;
-
- d->it_prg[d->last_buffer][d->last_used_cmd[d->last_buffer]].end.branchAddress = 0;
-
- spin_unlock_irqrestore(&d->lock,flags);
-
- if (!(reg_read(ohci, d->ctrlSet) & 0x8000))
- {
- DBGMSG(ohci->host->id, "Starting iso transmit DMA ctx=%d",
- d->ctx);
- put_timestamp(ohci, d, d->last_buffer);
- dma_region_sync_for_device(&d->dma,
- v.buffer * d->buf_size, d->buf_size);
-
- /* Tell the controller where the first program is */
- reg_write(ohci, d->cmdPtr,
- dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0) | 0x3);
-
- /* Run IT context */
- reg_write(ohci, d->ctrlSet, 0x8000);
- }
- else {
- /* Wake up dma context if necessary */
- if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
- DBGMSG(ohci->host->id,
- "Waking up iso transmit dma ctx=%d",
- d->ctx);
- put_timestamp(ohci, d, d->last_buffer);
- dma_region_sync_for_device(&d->dma,
- v.buffer * d->buf_size, d->buf_size);
-
- reg_write(ohci, d->ctrlSet, 0x1000);
- }
- }
-
- kfree(psizes);
- return 0;
-
- }
- case VIDEO1394_IOC_TALK_WAIT_BUFFER:
- {
- struct video1394_wait v;
- struct dma_iso_ctx *d;
-
- if (copy_from_user(&v, argp, sizeof(v)))
- return -EFAULT;
-
- d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
- if (d == NULL) return -EFAULT;
-
- if (v.buffer >= d->num_desc - 1) {
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d out of range",v.buffer);
- return -EINVAL;
- }
-
- switch(d->buffer_status[v.buffer]) {
- case VIDEO1394_BUFFER_READY:
- d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
- return 0;
- case VIDEO1394_BUFFER_QUEUED:
- wait_event_interruptible(d->waitq,
- (d->buffer_status[v.buffer] == VIDEO1394_BUFFER_READY));
- if (signal_pending(current))
- return -EINTR;
- d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
- return 0;
- default:
- PRINT(KERN_ERR, ohci->host->id,
- "Buffer %d is not queued",v.buffer);
- return -ESRCH;
- }
- }
- default:
- return -ENOTTY;
- }
-}
-
-/*
- * This maps the vmalloced and reserved buffer to user space.
- *
- * FIXME:
- * - PAGE_READONLY should suffice!?
- * - remap_pfn_range is kind of inefficient for page by page remapping.
- * But e.g. pte_alloc() does not work in modules ... :-(
- */
-
-static int video1394_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct file_ctx *ctx = file->private_data;
-
- if (ctx->current_ctx == NULL) {
- PRINT(KERN_ERR, ctx->ohci->host->id,
- "Current iso context not set");
- return -EINVAL;
- }
-
- return dma_region_mmap(&ctx->current_ctx->dma, file, vma);
-}
-
-static unsigned int video1394_poll(struct file *file, poll_table *pt)
-{
- struct file_ctx *ctx;
- unsigned int mask = 0;
- unsigned long flags;
- struct dma_iso_ctx *d;
- int i;
-
- ctx = file->private_data;
- d = ctx->current_ctx;
- if (d == NULL) {
- PRINT(KERN_ERR, ctx->ohci->host->id,
- "Current iso context not set");
- return POLLERR;
- }
-
- poll_wait(file, &d->waitq, pt);
-
- spin_lock_irqsave(&d->lock, flags);
- for (i = 0; i < d->num_desc; i++) {
- if (d->buffer_status[i] == VIDEO1394_BUFFER_READY) {
- mask |= POLLIN | POLLRDNORM;
- break;
- }
- }
- spin_unlock_irqrestore(&d->lock, flags);
-
- return mask;
-}
-
-static int video1394_open(struct inode *inode, struct file *file)
-{
- int i = ieee1394_file_to_instance(file);
- struct ti_ohci *ohci;
- struct file_ctx *ctx;
-
- ohci = hpsb_get_hostinfo_bykey(&video1394_highlevel, i);
- if (ohci == NULL)
- return -EIO;
-
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
- if (!ctx) {
- PRINT(KERN_ERR, ohci->host->id, "Cannot malloc file_ctx");
- return -ENOMEM;
- }
-
- ctx->ohci = ohci;
- INIT_LIST_HEAD(&ctx->context_list);
- ctx->current_ctx = NULL;
- file->private_data = ctx;
-
- return nonseekable_open(inode, file);
-}
-
-static int video1394_release(struct inode *inode, struct file *file)
-{
- struct file_ctx *ctx = file->private_data;
- struct ti_ohci *ohci = ctx->ohci;
- struct list_head *lh, *next;
- u64 mask;
-
- list_for_each_safe(lh, next, &ctx->context_list) {
- struct dma_iso_ctx *d;
- d = list_entry(lh, struct dma_iso_ctx, link);
- mask = (u64) 1 << d->channel;
-
- if (!(ohci->ISO_channel_usage & mask))
- PRINT(KERN_ERR, ohci->host->id, "On release: Channel %d "
- "is not being used", d->channel);
- else
- ohci->ISO_channel_usage &= ~mask;
- DBGMSG(ohci->host->id, "On release: Iso %s context "
- "%d stop listening on channel %d",
- d->type == OHCI_ISO_RECEIVE ? "receive" : "transmit",
- d->ctx, d->channel);
- free_dma_iso_ctx(d);
- }
-
- kfree(ctx);
- file->private_data = NULL;
-
- return 0;
-}
-
-#ifdef CONFIG_COMPAT
-static long video1394_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg);
-#endif
-
-static struct cdev video1394_cdev;
-static const struct file_operations video1394_fops=
-{
- .owner = THIS_MODULE,
- .unlocked_ioctl = video1394_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = video1394_compat_ioctl,
-#endif
- .poll = video1394_poll,
- .mmap = video1394_mmap,
- .open = video1394_open,
- .release = video1394_release,
- .llseek = no_llseek,
-};
-
-/*** HOTPLUG STUFF **********************************************************/
-/*
- * Export information about protocols/devices supported by this driver.
- */
-#ifdef MODULE
-static const struct ieee1394_device_id video1394_id_table[] = {
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = CAMERA_SW_VERSION_ENTRY & 0xffffff
- },
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = (CAMERA_SW_VERSION_ENTRY + 1) & 0xffffff
- },
- {
- .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
- .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
- .version = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff
- },
- { }
-};
-
-MODULE_DEVICE_TABLE(ieee1394, video1394_id_table);
-#endif /* MODULE */
-
-static struct hpsb_protocol_driver video1394_driver = {
- .name = VIDEO1394_DRIVER_NAME,
-};
-
-
-static void video1394_add_host (struct hpsb_host *host)
-{
- struct ti_ohci *ohci;
- int minor;
-
- /* We only work with the OHCI-1394 driver */
- if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
- return;
-
- ohci = (struct ti_ohci *)host->hostdata;
-
- if (!hpsb_create_hostinfo(&video1394_highlevel, host, 0)) {
- PRINT(KERN_ERR, ohci->host->id, "Cannot allocate hostinfo");
- return;
- }
-
- hpsb_set_hostinfo(&video1394_highlevel, host, ohci);
- hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->host->id);
-
- minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id;
- device_create(hpsb_protocol_class, NULL, MKDEV(IEEE1394_MAJOR, minor),
- NULL, "%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
-}
-
-
-static void video1394_remove_host (struct hpsb_host *host)
-{
- struct ti_ohci *ohci = hpsb_get_hostinfo(&video1394_highlevel, host);
-
- if (ohci)
- device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
- IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id));
- return;
-}
-
-
-static struct hpsb_highlevel video1394_highlevel = {
- .name = VIDEO1394_DRIVER_NAME,
- .add_host = video1394_add_host,
- .remove_host = video1394_remove_host,
-};
-
-MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
-MODULE_DESCRIPTION("driver for digital video on OHCI board");
-MODULE_SUPPORTED_DEVICE(VIDEO1394_DRIVER_NAME);
-MODULE_LICENSE("GPL");
-
-#ifdef CONFIG_COMPAT
-
-#define VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER \
- _IOW ('#', 0x12, struct video1394_wait32)
-#define VIDEO1394_IOC32_LISTEN_WAIT_BUFFER \
- _IOWR('#', 0x13, struct video1394_wait32)
-#define VIDEO1394_IOC32_TALK_WAIT_BUFFER \
- _IOW ('#', 0x17, struct video1394_wait32)
-#define VIDEO1394_IOC32_LISTEN_POLL_BUFFER \
- _IOWR('#', 0x18, struct video1394_wait32)
-
-struct video1394_wait32 {
- u32 channel;
- u32 buffer;
- struct compat_timeval filltime;
-};
-
-static int video1394_wr_wait32(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct video1394_wait32 __user *argp = (void __user *)arg;
- struct video1394_wait32 wait32;
- struct video1394_wait wait;
- mm_segment_t old_fs;
- int ret;
-
- if (copy_from_user(&wait32, argp, sizeof(wait32)))
- return -EFAULT;
-
- wait.channel = wait32.channel;
- wait.buffer = wait32.buffer;
- wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
- wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- if (cmd == VIDEO1394_IOC32_LISTEN_WAIT_BUFFER)
- ret = video1394_ioctl(file,
- VIDEO1394_IOC_LISTEN_WAIT_BUFFER,
- (unsigned long) &wait);
- else
- ret = video1394_ioctl(file,
- VIDEO1394_IOC_LISTEN_POLL_BUFFER,
- (unsigned long) &wait);
- set_fs(old_fs);
-
- if (!ret) {
- wait32.channel = wait.channel;
- wait32.buffer = wait.buffer;
- wait32.filltime.tv_sec = (int)wait.filltime.tv_sec;
- wait32.filltime.tv_usec = (int)wait.filltime.tv_usec;
-
- if (copy_to_user(argp, &wait32, sizeof(wait32)))
- ret = -EFAULT;
- }
-
- return ret;
-}
-
-static int video1394_w_wait32(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct video1394_wait32 wait32;
- struct video1394_wait wait;
- mm_segment_t old_fs;
- int ret;
-
- if (copy_from_user(&wait32, (void __user *)arg, sizeof(wait32)))
- return -EFAULT;
-
- wait.channel = wait32.channel;
- wait.buffer = wait32.buffer;
- wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
- wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- if (cmd == VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER)
- ret = video1394_ioctl(file,
- VIDEO1394_IOC_LISTEN_QUEUE_BUFFER,
- (unsigned long) &wait);
- else
- ret = video1394_ioctl(file,
- VIDEO1394_IOC_TALK_WAIT_BUFFER,
- (unsigned long) &wait);
- set_fs(old_fs);
-
- return ret;
-}
-
-static int video1394_queue_buf32(struct file *file, unsigned int cmd, unsigned long arg)
-{
- return -EFAULT; /* ??? was there before. */
-
- return video1394_ioctl(file,
- VIDEO1394_IOC_TALK_QUEUE_BUFFER, arg);
-}
-
-static long video1394_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
-{
- switch (cmd) {
- case VIDEO1394_IOC_LISTEN_CHANNEL:
- case VIDEO1394_IOC_UNLISTEN_CHANNEL:
- case VIDEO1394_IOC_TALK_CHANNEL:
- case VIDEO1394_IOC_UNTALK_CHANNEL:
- return video1394_ioctl(f, cmd, arg);
-
- case VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER:
- return video1394_w_wait32(f, cmd, arg);
- case VIDEO1394_IOC32_LISTEN_WAIT_BUFFER:
- return video1394_wr_wait32(f, cmd, arg);
- case VIDEO1394_IOC_TALK_QUEUE_BUFFER:
- return video1394_queue_buf32(f, cmd, arg);
- case VIDEO1394_IOC32_TALK_WAIT_BUFFER:
- return video1394_w_wait32(f, cmd, arg);
- case VIDEO1394_IOC32_LISTEN_POLL_BUFFER:
- return video1394_wr_wait32(f, cmd, arg);
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-#endif /* CONFIG_COMPAT */
-
-static void __exit video1394_exit_module (void)
-{
- hpsb_unregister_protocol(&video1394_driver);
- hpsb_unregister_highlevel(&video1394_highlevel);
- cdev_del(&video1394_cdev);
- PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
-}
-
-static int __init video1394_init_module (void)
-{
- int ret;
-
- hpsb_init_highlevel(&video1394_highlevel);
-
- cdev_init(&video1394_cdev, &video1394_fops);
- video1394_cdev.owner = THIS_MODULE;
- ret = cdev_add(&video1394_cdev, IEEE1394_VIDEO1394_DEV, 16);
- if (ret) {
- PRINT_G(KERN_ERR, "video1394: unable to get minor device block");
- return ret;
- }
-
- hpsb_register_highlevel(&video1394_highlevel);
-
- ret = hpsb_register_protocol(&video1394_driver);
- if (ret) {
- PRINT_G(KERN_ERR, "video1394: failed to register protocol");
- hpsb_unregister_highlevel(&video1394_highlevel);
- cdev_del(&video1394_cdev);
- return ret;
- }
-
- PRINT_G(KERN_INFO, "Installed " VIDEO1394_DRIVER_NAME " module");
- return 0;
-}
-
-
-module_init(video1394_init_module);
-module_exit(video1394_exit_module);
diff --git a/drivers/ieee1394/video1394.h b/drivers/ieee1394/video1394.h
deleted file mode 100644
index 9a89d9cc3c85..000000000000
--- a/drivers/ieee1394/video1394.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * video1394.h - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- * Peter Schlaile <udbz@rz.uni-karlsruhe.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This 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 _VIDEO_1394_H
-#define _VIDEO_1394_H
-
-#include "ieee1394-ioctl.h"
-
-#define VIDEO1394_DRIVER_NAME "video1394"
-
-#define VIDEO1394_MAX_SIZE 0x4000000
-
-enum {
- VIDEO1394_BUFFER_FREE = 0,
- VIDEO1394_BUFFER_QUEUED,
- VIDEO1394_BUFFER_READY
-};
-
-#define VIDEO1394_SYNC_FRAMES 0x00000001
-#define VIDEO1394_INCLUDE_ISO_HEADERS 0x00000002
-#define VIDEO1394_VARIABLE_PACKET_SIZE 0x00000004
-
-struct video1394_mmap {
- int channel; /* -1 to find an open channel in LISTEN/TALK */
- unsigned int sync_tag;
- unsigned int nb_buffers;
- unsigned int buf_size;
- unsigned int packet_size; /* For VARIABLE_PACKET_SIZE:
- Maximum packet size */
- unsigned int fps;
- unsigned int syt_offset;
- unsigned int flags;
-};
-
-/* For TALK_QUEUE_BUFFER with VIDEO1394_VARIABLE_PACKET_SIZE use */
-struct video1394_queue_variable {
- unsigned int channel;
- unsigned int buffer;
- unsigned int __user * packet_sizes; /* Buffer of size:
- buf_size / packet_size */
-};
-
-struct video1394_wait {
- unsigned int channel;
- unsigned int buffer;
- struct timeval filltime; /* time of buffer full */
-};
-
-
-#endif
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index 89d70de5e235..6e35eccc9caa 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -16,7 +16,7 @@ config INFINIBAND_USER_MAD
Userspace InfiniBand Management Datagram (MAD) support. This
is the kernel side of the userspace MAD support, which allows
userspace processes to send and receive MADs. You will also
- need libibumad from <http://www.openib.org>.
+ need libibumad from <http://www.openfabrics.org/downloads/management/>.
config INFINIBAND_USER_ACCESS
tristate "InfiniBand userspace access (verbs and CM)"
@@ -28,7 +28,7 @@ config INFINIBAND_USER_ACCESS
to set up connections and directly access InfiniBand
hardware for fast-path operations. You will also need
libibverbs, libibcm and a hardware driver library from
- <http://www.openib.org>.
+ <http://www.openfabrics.org/git/>.
config INFINIBAND_USER_MEM
bool
diff --git a/drivers/infiniband/core/agent.c b/drivers/infiniband/core/agent.c
index ae7c2880e624..91916a8d5de4 100644
--- a/drivers/infiniband/core/agent.c
+++ b/drivers/infiniband/core/agent.c
@@ -59,8 +59,8 @@ __ib_get_agent_port(struct ib_device *device, int port_num)
struct ib_agent_port_private *entry;
list_for_each_entry(entry, &ib_agent_port_list, port_list) {
- if (entry->agent[0]->device == device &&
- entry->agent[0]->port_num == port_num)
+ if (entry->agent[1]->device == device &&
+ entry->agent[1]->port_num == port_num)
return entry;
}
return NULL;
@@ -155,14 +155,16 @@ int ib_agent_port_open(struct ib_device *device, int port_num)
goto error1;
}
- /* Obtain send only MAD agent for SMI QP */
- port_priv->agent[0] = ib_register_mad_agent(device, port_num,
- IB_QPT_SMI, NULL, 0,
- &agent_send_handler,
- NULL, NULL);
- if (IS_ERR(port_priv->agent[0])) {
- ret = PTR_ERR(port_priv->agent[0]);
- goto error2;
+ if (rdma_port_get_link_layer(device, port_num) == IB_LINK_LAYER_INFINIBAND) {
+ /* Obtain send only MAD agent for SMI QP */
+ port_priv->agent[0] = ib_register_mad_agent(device, port_num,
+ IB_QPT_SMI, NULL, 0,
+ &agent_send_handler,
+ NULL, NULL);
+ if (IS_ERR(port_priv->agent[0])) {
+ ret = PTR_ERR(port_priv->agent[0]);
+ goto error2;
+ }
}
/* Obtain send only MAD agent for GSI QP */
@@ -182,7 +184,8 @@ int ib_agent_port_open(struct ib_device *device, int port_num)
return 0;
error3:
- ib_unregister_mad_agent(port_priv->agent[0]);
+ if (port_priv->agent[0])
+ ib_unregister_mad_agent(port_priv->agent[0]);
error2:
kfree(port_priv);
error1:
@@ -205,7 +208,9 @@ int ib_agent_port_close(struct ib_device *device, int port_num)
spin_unlock_irqrestore(&ib_agent_port_list_lock, flags);
ib_unregister_mad_agent(port_priv->agent[1]);
- ib_unregister_mad_agent(port_priv->agent[0]);
+ if (port_priv->agent[0])
+ ib_unregister_mad_agent(port_priv->agent[0]);
+
kfree(port_priv);
return 0;
}
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index b930b8110a63..6884da24fde1 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -59,6 +59,7 @@ MODULE_LICENSE("Dual BSD/GPL");
#define CMA_CM_RESPONSE_TIMEOUT 20
#define CMA_MAX_CM_RETRIES 15
#define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24)
+#define CMA_IBOE_PACKET_LIFETIME 18
static void cma_add_one(struct ib_device *device);
static void cma_remove_one(struct ib_device *device);
@@ -157,6 +158,7 @@ struct cma_multicast {
struct list_head list;
void *context;
struct sockaddr_storage addr;
+ struct kref mcref;
};
struct cma_work {
@@ -173,6 +175,12 @@ struct cma_ndev_work {
struct rdma_cm_event event;
};
+struct iboe_mcast_work {
+ struct work_struct work;
+ struct rdma_id_private *id;
+ struct cma_multicast *mc;
+};
+
union cma_ip_addr {
struct in6_addr ip6;
struct {
@@ -281,6 +289,8 @@ static void cma_attach_to_dev(struct rdma_id_private *id_priv,
atomic_inc(&cma_dev->refcount);
id_priv->cma_dev = cma_dev;
id_priv->id.device = cma_dev->device;
+ id_priv->id.route.addr.dev_addr.transport =
+ rdma_node_get_transport(cma_dev->device->node_type);
list_add_tail(&id_priv->list, &cma_dev->id_list);
}
@@ -290,6 +300,14 @@ static inline void cma_deref_dev(struct cma_device *cma_dev)
complete(&cma_dev->comp);
}
+static inline void release_mc(struct kref *kref)
+{
+ struct cma_multicast *mc = container_of(kref, struct cma_multicast, mcref);
+
+ kfree(mc->multicast.ib);
+ kfree(mc);
+}
+
static void cma_detach_from_dev(struct rdma_id_private *id_priv)
{
list_del(&id_priv->list);
@@ -323,22 +341,63 @@ static int cma_set_qkey(struct rdma_id_private *id_priv)
return ret;
}
+static int find_gid_port(struct ib_device *device, union ib_gid *gid, u8 port_num)
+{
+ int i;
+ int err;
+ struct ib_port_attr props;
+ union ib_gid tmp;
+
+ err = ib_query_port(device, port_num, &props);
+ if (err)
+ return 1;
+
+ for (i = 0; i < props.gid_tbl_len; ++i) {
+ err = ib_query_gid(device, port_num, i, &tmp);
+ if (err)
+ return 1;
+ if (!memcmp(&tmp, gid, sizeof tmp))
+ return 0;
+ }
+
+ return -EAGAIN;
+}
+
static int cma_acquire_dev(struct rdma_id_private *id_priv)
{
struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
struct cma_device *cma_dev;
- union ib_gid gid;
+ union ib_gid gid, iboe_gid;
int ret = -ENODEV;
+ u8 port;
+ enum rdma_link_layer dev_ll = dev_addr->dev_type == ARPHRD_INFINIBAND ?
+ IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET;
- rdma_addr_get_sgid(dev_addr, &gid);
+ iboe_addr_get_sgid(dev_addr, &iboe_gid);
+ memcpy(&gid, dev_addr->src_dev_addr +
+ rdma_addr_gid_offset(dev_addr), sizeof gid);
list_for_each_entry(cma_dev, &dev_list, list) {
- ret = ib_find_cached_gid(cma_dev->device, &gid,
- &id_priv->id.port_num, NULL);
- if (!ret) {
- cma_attach_to_dev(id_priv, cma_dev);
- break;
+ for (port = 1; port <= cma_dev->device->phys_port_cnt; ++port) {
+ if (rdma_port_get_link_layer(cma_dev->device, port) == dev_ll) {
+ if (rdma_node_get_transport(cma_dev->device->node_type) == RDMA_TRANSPORT_IB &&
+ rdma_port_get_link_layer(cma_dev->device, port) == IB_LINK_LAYER_ETHERNET)
+ ret = find_gid_port(cma_dev->device, &iboe_gid, port);
+ else
+ ret = find_gid_port(cma_dev->device, &gid, port);
+
+ if (!ret) {
+ id_priv->id.port_num = port;
+ goto out;
+ } else if (ret == 1)
+ break;
+ }
}
}
+
+out:
+ if (!ret)
+ cma_attach_to_dev(id_priv, cma_dev);
+
return ret;
}
@@ -556,10 +615,16 @@ static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv,
{
struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
int ret;
+ u16 pkey;
+
+ if (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num) ==
+ IB_LINK_LAYER_INFINIBAND)
+ pkey = ib_addr_get_pkey(dev_addr);
+ else
+ pkey = 0xffff;
ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num,
- ib_addr_get_pkey(dev_addr),
- &qp_attr->pkey_index);
+ pkey, &qp_attr->pkey_index);
if (ret)
return ret;
@@ -737,8 +802,8 @@ static inline int cma_user_data_offset(enum rdma_port_space ps)
static void cma_cancel_route(struct rdma_id_private *id_priv)
{
- switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
- case RDMA_TRANSPORT_IB:
+ switch (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num)) {
+ case IB_LINK_LAYER_INFINIBAND:
if (id_priv->query)
ib_sa_cancel_query(id_priv->query_id, id_priv->query);
break;
@@ -816,8 +881,17 @@ static void cma_leave_mc_groups(struct rdma_id_private *id_priv)
mc = container_of(id_priv->mc_list.next,
struct cma_multicast, list);
list_del(&mc->list);
- ib_sa_free_multicast(mc->multicast.ib);
- kfree(mc);
+ switch (rdma_port_get_link_layer(id_priv->cma_dev->device, id_priv->id.port_num)) {
+ case IB_LINK_LAYER_INFINIBAND:
+ ib_sa_free_multicast(mc->multicast.ib);
+ kfree(mc);
+ break;
+ case IB_LINK_LAYER_ETHERNET:
+ kref_put(&mc->mcref, release_mc);
+ break;
+ default:
+ break;
+ }
}
}
@@ -833,7 +907,7 @@ void rdma_destroy_id(struct rdma_cm_id *id)
mutex_lock(&lock);
if (id_priv->cma_dev) {
mutex_unlock(&lock);
- switch (rdma_node_get_transport(id->device->node_type)) {
+ switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
case RDMA_TRANSPORT_IB:
if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
ib_destroy_cm_id(id_priv->cm_id.ib);
@@ -1708,6 +1782,81 @@ static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms)
return 0;
}
+static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
+{
+ struct rdma_route *route = &id_priv->id.route;
+ struct rdma_addr *addr = &route->addr;
+ struct cma_work *work;
+ int ret;
+ struct sockaddr_in *src_addr = (struct sockaddr_in *)&route->addr.src_addr;
+ struct sockaddr_in *dst_addr = (struct sockaddr_in *)&route->addr.dst_addr;
+ struct net_device *ndev = NULL;
+ u16 vid;
+
+ if (src_addr->sin_family != dst_addr->sin_family)
+ return -EINVAL;
+
+ work = kzalloc(sizeof *work, GFP_KERNEL);
+ if (!work)
+ return -ENOMEM;
+
+ work->id = id_priv;
+ INIT_WORK(&work->work, cma_work_handler);
+
+ route->path_rec = kzalloc(sizeof *route->path_rec, GFP_KERNEL);
+ if (!route->path_rec) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ route->num_paths = 1;
+
+ if (addr->dev_addr.bound_dev_if)
+ ndev = dev_get_by_index(&init_net, addr->dev_addr.bound_dev_if);
+ if (!ndev) {
+ ret = -ENODEV;
+ goto err2;
+ }
+
+ vid = rdma_vlan_dev_vlan_id(ndev);
+
+ iboe_mac_vlan_to_ll(&route->path_rec->sgid, addr->dev_addr.src_dev_addr, vid);
+ iboe_mac_vlan_to_ll(&route->path_rec->dgid, addr->dev_addr.dst_dev_addr, vid);
+
+ route->path_rec->hop_limit = 1;
+ route->path_rec->reversible = 1;
+ route->path_rec->pkey = cpu_to_be16(0xffff);
+ route->path_rec->mtu_selector = IB_SA_EQ;
+ route->path_rec->sl = id_priv->tos >> 5;
+
+ route->path_rec->mtu = iboe_get_mtu(ndev->mtu);
+ route->path_rec->rate_selector = IB_SA_EQ;
+ route->path_rec->rate = iboe_get_rate(ndev);
+ dev_put(ndev);
+ route->path_rec->packet_life_time_selector = IB_SA_EQ;
+ route->path_rec->packet_life_time = CMA_IBOE_PACKET_LIFETIME;
+ if (!route->path_rec->mtu) {
+ ret = -EINVAL;
+ goto err2;
+ }
+
+ work->old_state = CMA_ROUTE_QUERY;
+ work->new_state = CMA_ROUTE_RESOLVED;
+ work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
+ work->event.status = 0;
+
+ queue_work(cma_wq, &work->work);
+
+ return 0;
+
+err2:
+ kfree(route->path_rec);
+ route->path_rec = NULL;
+err1:
+ kfree(work);
+ return ret;
+}
+
int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
{
struct rdma_id_private *id_priv;
@@ -1720,7 +1869,16 @@ int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
atomic_inc(&id_priv->refcount);
switch (rdma_node_get_transport(id->device->node_type)) {
case RDMA_TRANSPORT_IB:
- ret = cma_resolve_ib_route(id_priv, timeout_ms);
+ switch (rdma_port_get_link_layer(id->device, id->port_num)) {
+ case IB_LINK_LAYER_INFINIBAND:
+ ret = cma_resolve_ib_route(id_priv, timeout_ms);
+ break;
+ case IB_LINK_LAYER_ETHERNET:
+ ret = cma_resolve_iboe_route(id_priv);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
break;
case RDMA_TRANSPORT_IWARP:
ret = cma_resolve_iw_route(id_priv, timeout_ms);
@@ -1773,7 +1931,7 @@ port_found:
goto out;
id_priv->id.route.addr.dev_addr.dev_type =
- (rdma_node_get_transport(cma_dev->device->node_type) == RDMA_TRANSPORT_IB) ?
+ (rdma_port_get_link_layer(cma_dev->device, p) == IB_LINK_LAYER_INFINIBAND) ?
ARPHRD_INFINIBAND : ARPHRD_ETHER;
rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid);
@@ -2758,6 +2916,102 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
return 0;
}
+static void iboe_mcast_work_handler(struct work_struct *work)
+{
+ struct iboe_mcast_work *mw = container_of(work, struct iboe_mcast_work, work);
+ struct cma_multicast *mc = mw->mc;
+ struct ib_sa_multicast *m = mc->multicast.ib;
+
+ mc->multicast.ib->context = mc;
+ cma_ib_mc_handler(0, m);
+ kref_put(&mc->mcref, release_mc);
+ kfree(mw);
+}
+
+static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
+
+ if (cma_any_addr(addr)) {
+ memset(mgid, 0, sizeof *mgid);
+ } else if (addr->sa_family == AF_INET6) {
+ memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
+ } else {
+ mgid->raw[0] = 0xff;
+ mgid->raw[1] = 0x0e;
+ mgid->raw[2] = 0;
+ mgid->raw[3] = 0;
+ mgid->raw[4] = 0;
+ mgid->raw[5] = 0;
+ mgid->raw[6] = 0;
+ mgid->raw[7] = 0;
+ mgid->raw[8] = 0;
+ mgid->raw[9] = 0;
+ mgid->raw[10] = 0xff;
+ mgid->raw[11] = 0xff;
+ *(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr;
+ }
+}
+
+static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
+ struct cma_multicast *mc)
+{
+ struct iboe_mcast_work *work;
+ struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
+ int err;
+ struct sockaddr *addr = (struct sockaddr *)&mc->addr;
+ struct net_device *ndev = NULL;
+
+ if (cma_zero_addr((struct sockaddr *)&mc->addr))
+ return -EINVAL;
+
+ work = kzalloc(sizeof *work, GFP_KERNEL);
+ if (!work)
+ return -ENOMEM;
+
+ mc->multicast.ib = kzalloc(sizeof(struct ib_sa_multicast), GFP_KERNEL);
+ if (!mc->multicast.ib) {
+ err = -ENOMEM;
+ goto out1;
+ }
+
+ cma_iboe_set_mgid(addr, &mc->multicast.ib->rec.mgid);
+
+ mc->multicast.ib->rec.pkey = cpu_to_be16(0xffff);
+ if (id_priv->id.ps == RDMA_PS_UDP)
+ mc->multicast.ib->rec.qkey = cpu_to_be32(RDMA_UDP_QKEY);
+
+ if (dev_addr->bound_dev_if)
+ ndev = dev_get_by_index(&init_net, dev_addr->bound_dev_if);
+ if (!ndev) {
+ err = -ENODEV;
+ goto out2;
+ }
+ mc->multicast.ib->rec.rate = iboe_get_rate(ndev);
+ mc->multicast.ib->rec.hop_limit = 1;
+ mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->mtu);
+ dev_put(ndev);
+ if (!mc->multicast.ib->rec.mtu) {
+ err = -EINVAL;
+ goto out2;
+ }
+ iboe_addr_get_sgid(dev_addr, &mc->multicast.ib->rec.port_gid);
+ work->id = id_priv;
+ work->mc = mc;
+ INIT_WORK(&work->work, iboe_mcast_work_handler);
+ kref_get(&mc->mcref);
+ queue_work(cma_wq, &work->work);
+
+ return 0;
+
+out2:
+ kfree(mc->multicast.ib);
+out1:
+ kfree(work);
+ return err;
+}
+
int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
void *context)
{
@@ -2784,7 +3038,17 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
switch (rdma_node_get_transport(id->device->node_type)) {
case RDMA_TRANSPORT_IB:
- ret = cma_join_ib_multicast(id_priv, mc);
+ switch (rdma_port_get_link_layer(id->device, id->port_num)) {
+ case IB_LINK_LAYER_INFINIBAND:
+ ret = cma_join_ib_multicast(id_priv, mc);
+ break;
+ case IB_LINK_LAYER_ETHERNET:
+ kref_init(&mc->mcref);
+ ret = cma_iboe_join_multicast(id_priv, mc);
+ break;
+ default:
+ ret = -EINVAL;
+ }
break;
default:
ret = -ENOSYS;
@@ -2817,8 +3081,19 @@ void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)
ib_detach_mcast(id->qp,
&mc->multicast.ib->rec.mgid,
mc->multicast.ib->rec.mlid);
- ib_sa_free_multicast(mc->multicast.ib);
- kfree(mc);
+ if (rdma_node_get_transport(id_priv->cma_dev->device->node_type) == RDMA_TRANSPORT_IB) {
+ switch (rdma_port_get_link_layer(id->device, id->port_num)) {
+ case IB_LINK_LAYER_INFINIBAND:
+ ib_sa_free_multicast(mc->multicast.ib);
+ kfree(mc);
+ break;
+ case IB_LINK_LAYER_ETHERNET:
+ kref_put(&mc->mcref, release_mc);
+ break;
+ default:
+ break;
+ }
+ }
return;
}
}
diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c
index bfead5bc25f6..2a1e9ae134b4 100644
--- a/drivers/infiniband/core/iwcm.c
+++ b/drivers/infiniband/core/iwcm.c
@@ -506,6 +506,8 @@ int iw_cm_accept(struct iw_cm_id *cm_id,
qp = cm_id->device->iwcm->get_qp(cm_id->device, iw_param->qpn);
if (!qp) {
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+ wake_up_all(&cm_id_priv->connect_wait);
return -EINVAL;
}
cm_id->device->iwcm->add_ref(qp);
@@ -565,6 +567,8 @@ int iw_cm_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
qp = cm_id->device->iwcm->get_qp(cm_id->device, iw_param->qpn);
if (!qp) {
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+ wake_up_all(&cm_id_priv->connect_wait);
return -EINVAL;
}
cm_id->device->iwcm->add_ref(qp);
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index ef1304f151dc..822cfdcd9f78 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -2598,6 +2598,9 @@ static void cleanup_recv_queue(struct ib_mad_qp_info *qp_info)
struct ib_mad_private *recv;
struct ib_mad_list_head *mad_list;
+ if (!qp_info->qp)
+ return;
+
while (!list_empty(&qp_info->recv_queue.list)) {
mad_list = list_entry(qp_info->recv_queue.list.next,
@@ -2639,6 +2642,9 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
for (i = 0; i < IB_MAD_QPS_CORE; i++) {
qp = port_priv->qp_info[i].qp;
+ if (!qp)
+ continue;
+
/*
* PKey index for QP1 is irrelevant but
* one is needed for the Reset to Init transition
@@ -2680,6 +2686,9 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
}
for (i = 0; i < IB_MAD_QPS_CORE; i++) {
+ if (!port_priv->qp_info[i].qp)
+ continue;
+
ret = ib_mad_post_receive_mads(&port_priv->qp_info[i], NULL);
if (ret) {
printk(KERN_ERR PFX "Couldn't post receive WRs\n");
@@ -2758,6 +2767,9 @@ error:
static void destroy_mad_qp(struct ib_mad_qp_info *qp_info)
{
+ if (!qp_info->qp)
+ return;
+
ib_destroy_qp(qp_info->qp);
kfree(qp_info->snoop_table);
}
@@ -2773,6 +2785,7 @@ static int ib_mad_port_open(struct ib_device *device,
struct ib_mad_port_private *port_priv;
unsigned long flags;
char name[sizeof "ib_mad123"];
+ int has_smi;
/* Create new device info */
port_priv = kzalloc(sizeof *port_priv, GFP_KERNEL);
@@ -2788,7 +2801,11 @@ static int ib_mad_port_open(struct ib_device *device,
init_mad_qp(port_priv, &port_priv->qp_info[0]);
init_mad_qp(port_priv, &port_priv->qp_info[1]);
- cq_size = (mad_sendq_size + mad_recvq_size) * 2;
+ cq_size = mad_sendq_size + mad_recvq_size;
+ has_smi = rdma_port_get_link_layer(device, port_num) == IB_LINK_LAYER_INFINIBAND;
+ if (has_smi)
+ cq_size *= 2;
+
port_priv->cq = ib_create_cq(port_priv->device,
ib_mad_thread_completion_handler,
NULL, port_priv, cq_size, 0);
@@ -2812,9 +2829,11 @@ static int ib_mad_port_open(struct ib_device *device,
goto error5;
}
- ret = create_mad_qp(&port_priv->qp_info[0], IB_QPT_SMI);
- if (ret)
- goto error6;
+ if (has_smi) {
+ ret = create_mad_qp(&port_priv->qp_info[0], IB_QPT_SMI);
+ if (ret)
+ goto error6;
+ }
ret = create_mad_qp(&port_priv->qp_info[1], IB_QPT_GSI);
if (ret)
goto error7;
diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c
index a519801dcfb7..68b4162fd9d2 100644
--- a/drivers/infiniband/core/multicast.c
+++ b/drivers/infiniband/core/multicast.c
@@ -774,6 +774,10 @@ static void mcast_event_handler(struct ib_event_handler *handler,
int index;
dev = container_of(handler, struct mcast_device, event_handler);
+ if (rdma_port_get_link_layer(dev->device, event->element.port_num) !=
+ IB_LINK_LAYER_INFINIBAND)
+ return;
+
index = event->element.port_num - dev->start_port;
switch (event->event) {
@@ -796,6 +800,7 @@ static void mcast_add_one(struct ib_device *device)
struct mcast_device *dev;
struct mcast_port *port;
int i;
+ int count = 0;
if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
return;
@@ -813,6 +818,9 @@ static void mcast_add_one(struct ib_device *device)
}
for (i = 0; i <= dev->end_port - dev->start_port; i++) {
+ if (rdma_port_get_link_layer(device, dev->start_port + i) !=
+ IB_LINK_LAYER_INFINIBAND)
+ continue;
port = &dev->port[i];
port->dev = dev;
port->port_num = dev->start_port + i;
@@ -820,6 +828,12 @@ static void mcast_add_one(struct ib_device *device)
port->table = RB_ROOT;
init_completion(&port->comp);
atomic_set(&port->refcount, 1);
+ ++count;
+ }
+
+ if (!count) {
+ kfree(dev);
+ return;
}
dev->device = device;
@@ -843,9 +857,12 @@ static void mcast_remove_one(struct ib_device *device)
flush_workqueue(mcast_wq);
for (i = 0; i <= dev->end_port - dev->start_port; i++) {
- port = &dev->port[i];
- deref_port(port);
- wait_for_completion(&port->comp);
+ if (rdma_port_get_link_layer(device, dev->start_port + i) ==
+ IB_LINK_LAYER_INFINIBAND) {
+ port = &dev->port[i];
+ deref_port(port);
+ wait_for_completion(&port->comp);
+ }
}
kfree(dev);
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 7e1ffd8ccd5c..91a660310b7c 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -416,6 +416,9 @@ static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event
struct ib_sa_port *port =
&sa_dev->port[event->element.port_num - sa_dev->start_port];
+ if (rdma_port_get_link_layer(handler->device, port->port_num) != IB_LINK_LAYER_INFINIBAND)
+ return;
+
spin_lock_irqsave(&port->ah_lock, flags);
if (port->sm_ah)
kref_put(&port->sm_ah->ref, free_sm_ah);
@@ -493,6 +496,7 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
{
int ret;
u16 gid_index;
+ int force_grh;
memset(ah_attr, 0, sizeof *ah_attr);
ah_attr->dlid = be16_to_cpu(rec->dlid);
@@ -502,7 +506,9 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
ah_attr->port_num = port_num;
ah_attr->static_rate = rec->rate;
- if (rec->hop_limit > 1) {
+ force_grh = rdma_port_get_link_layer(device, port_num) == IB_LINK_LAYER_ETHERNET;
+
+ if (rec->hop_limit > 1 || force_grh) {
ah_attr->ah_flags = IB_AH_GRH;
ah_attr->grh.dgid = rec->dgid;
@@ -1007,7 +1013,7 @@ static void ib_sa_add_one(struct ib_device *device)
e = device->phys_port_cnt;
}
- sa_dev = kmalloc(sizeof *sa_dev +
+ sa_dev = kzalloc(sizeof *sa_dev +
(e - s + 1) * sizeof (struct ib_sa_port),
GFP_KERNEL);
if (!sa_dev)
@@ -1017,9 +1023,12 @@ static void ib_sa_add_one(struct ib_device *device)
sa_dev->end_port = e;
for (i = 0; i <= e - s; ++i) {
+ spin_lock_init(&sa_dev->port[i].ah_lock);
+ if (rdma_port_get_link_layer(device, i + 1) != IB_LINK_LAYER_INFINIBAND)
+ continue;
+
sa_dev->port[i].sm_ah = NULL;
sa_dev->port[i].port_num = i + s;
- spin_lock_init(&sa_dev->port[i].ah_lock);
sa_dev->port[i].agent =
ib_register_mad_agent(device, i + s, IB_QPT_GSI,
@@ -1045,13 +1054,15 @@ static void ib_sa_add_one(struct ib_device *device)
goto err;
for (i = 0; i <= e - s; ++i)
- update_sm_ah(&sa_dev->port[i].update_task);
+ if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND)
+ update_sm_ah(&sa_dev->port[i].update_task);
return;
err:
while (--i >= 0)
- ib_unregister_mad_agent(sa_dev->port[i].agent);
+ if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND)
+ ib_unregister_mad_agent(sa_dev->port[i].agent);
kfree(sa_dev);
@@ -1071,9 +1082,12 @@ static void ib_sa_remove_one(struct ib_device *device)
flush_scheduled_work();
for (i = 0; i <= sa_dev->end_port - sa_dev->start_port; ++i) {
- ib_unregister_mad_agent(sa_dev->port[i].agent);
- if (sa_dev->port[i].sm_ah)
- kref_put(&sa_dev->port[i].sm_ah->ref, free_sm_ah);
+ if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND) {
+ ib_unregister_mad_agent(sa_dev->port[i].agent);
+ if (sa_dev->port[i].sm_ah)
+ kref_put(&sa_dev->port[i].sm_ah->ref, free_sm_ah);
+ }
+
}
kfree(sa_dev);
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 3627300e2a10..9ab5df72df7b 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -222,6 +222,19 @@ static ssize_t phys_state_show(struct ib_port *p, struct port_attribute *unused,
}
}
+static ssize_t link_layer_show(struct ib_port *p, struct port_attribute *unused,
+ char *buf)
+{
+ switch (rdma_port_get_link_layer(p->ibdev, p->port_num)) {
+ case IB_LINK_LAYER_INFINIBAND:
+ return sprintf(buf, "%s\n", "InfiniBand");
+ case IB_LINK_LAYER_ETHERNET:
+ return sprintf(buf, "%s\n", "Ethernet");
+ default:
+ return sprintf(buf, "%s\n", "Unknown");
+ }
+}
+
static PORT_ATTR_RO(state);
static PORT_ATTR_RO(lid);
static PORT_ATTR_RO(lid_mask_count);
@@ -230,6 +243,7 @@ static PORT_ATTR_RO(sm_sl);
static PORT_ATTR_RO(cap_mask);
static PORT_ATTR_RO(rate);
static PORT_ATTR_RO(phys_state);
+static PORT_ATTR_RO(link_layer);
static struct attribute *port_default_attrs[] = {
&port_attr_state.attr,
@@ -240,6 +254,7 @@ static struct attribute *port_default_attrs[] = {
&port_attr_cap_mask.attr,
&port_attr_rate.attr,
&port_attr_phys_state.attr,
+ &port_attr_link_layer.attr,
NULL
};
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index ac7edc24165c..ca12acf38379 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -40,6 +40,7 @@
#include <linux/in6.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
+#include <linux/sysctl.h>
#include <rdma/rdma_user_cm.h>
#include <rdma/ib_marshall.h>
@@ -50,8 +51,24 @@ MODULE_AUTHOR("Sean Hefty");
MODULE_DESCRIPTION("RDMA Userspace Connection Manager Access");
MODULE_LICENSE("Dual BSD/GPL");
-enum {
- UCMA_MAX_BACKLOG = 128
+static unsigned int max_backlog = 1024;
+
+static struct ctl_table_header *ucma_ctl_table_hdr;
+static ctl_table ucma_ctl_table[] = {
+ {
+ .procname = "max_backlog",
+ .data = &max_backlog,
+ .maxlen = sizeof max_backlog,
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ { }
+};
+
+static struct ctl_path ucma_ctl_path[] = {
+ { .procname = "net" },
+ { .procname = "rdma_ucm" },
+ { }
};
struct ucma_file {
@@ -583,6 +600,42 @@ static void ucma_copy_ib_route(struct rdma_ucm_query_route_resp *resp,
}
}
+static void ucma_copy_iboe_route(struct rdma_ucm_query_route_resp *resp,
+ struct rdma_route *route)
+{
+ struct rdma_dev_addr *dev_addr;
+ struct net_device *dev;
+ u16 vid = 0;
+
+ resp->num_paths = route->num_paths;
+ switch (route->num_paths) {
+ case 0:
+ dev_addr = &route->addr.dev_addr;
+ dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if);
+ if (dev) {
+ vid = rdma_vlan_dev_vlan_id(dev);
+ dev_put(dev);
+ }
+
+ iboe_mac_vlan_to_ll((union ib_gid *) &resp->ib_route[0].dgid,
+ dev_addr->dst_dev_addr, vid);
+ iboe_addr_get_sgid(dev_addr,
+ (union ib_gid *) &resp->ib_route[0].sgid);
+ resp->ib_route[0].pkey = cpu_to_be16(0xffff);
+ break;
+ case 2:
+ ib_copy_path_rec_to_user(&resp->ib_route[1],
+ &route->path_rec[1]);
+ /* fall through */
+ case 1:
+ ib_copy_path_rec_to_user(&resp->ib_route[0],
+ &route->path_rec[0]);
+ break;
+ default:
+ break;
+ }
+}
+
static ssize_t ucma_query_route(struct ucma_file *file,
const char __user *inbuf,
int in_len, int out_len)
@@ -617,12 +670,17 @@ static ssize_t ucma_query_route(struct ucma_file *file,
resp.node_guid = (__force __u64) ctx->cm_id->device->node_guid;
resp.port_num = ctx->cm_id->port_num;
- switch (rdma_node_get_transport(ctx->cm_id->device->node_type)) {
- case RDMA_TRANSPORT_IB:
- ucma_copy_ib_route(&resp, &ctx->cm_id->route);
- break;
- default:
- break;
+ if (rdma_node_get_transport(ctx->cm_id->device->node_type) == RDMA_TRANSPORT_IB) {
+ switch (rdma_port_get_link_layer(ctx->cm_id->device, ctx->cm_id->port_num)) {
+ case IB_LINK_LAYER_INFINIBAND:
+ ucma_copy_ib_route(&resp, &ctx->cm_id->route);
+ break;
+ case IB_LINK_LAYER_ETHERNET:
+ ucma_copy_iboe_route(&resp, &ctx->cm_id->route);
+ break;
+ default:
+ break;
+ }
}
out:
@@ -686,8 +744,8 @@ static ssize_t ucma_listen(struct ucma_file *file, const char __user *inbuf,
if (IS_ERR(ctx))
return PTR_ERR(ctx);
- ctx->backlog = cmd.backlog > 0 && cmd.backlog < UCMA_MAX_BACKLOG ?
- cmd.backlog : UCMA_MAX_BACKLOG;
+ ctx->backlog = cmd.backlog > 0 && cmd.backlog < max_backlog ?
+ cmd.backlog : max_backlog;
ret = rdma_listen(ctx->cm_id, ctx->backlog);
ucma_put_ctx(ctx);
return ret;
@@ -1279,16 +1337,26 @@ static int __init ucma_init(void)
ret = device_create_file(ucma_misc.this_device, &dev_attr_abi_version);
if (ret) {
printk(KERN_ERR "rdma_ucm: couldn't create abi_version attr\n");
- goto err;
+ goto err1;
+ }
+
+ ucma_ctl_table_hdr = register_sysctl_paths(ucma_ctl_path, ucma_ctl_table);
+ if (!ucma_ctl_table_hdr) {
+ printk(KERN_ERR "rdma_ucm: couldn't register sysctl paths\n");
+ ret = -ENOMEM;
+ goto err2;
}
return 0;
-err:
+err2:
+ device_remove_file(ucma_misc.this_device, &dev_attr_abi_version);
+err1:
misc_deregister(&ucma_misc);
return ret;
}
static void __exit ucma_cleanup(void)
{
+ unregister_sysctl_table(ucma_ctl_table_hdr);
device_remove_file(ucma_misc.this_device, &dev_attr_abi_version);
misc_deregister(&ucma_misc);
idr_destroy(&ctx_idr);
diff --git a/drivers/infiniband/core/ud_header.c b/drivers/infiniband/core/ud_header.c
index 650b501eb142..bb7e19280821 100644
--- a/drivers/infiniband/core/ud_header.c
+++ b/drivers/infiniband/core/ud_header.c
@@ -33,6 +33,7 @@
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/if_ether.h>
#include <rdma/ib_pack.h>
@@ -80,6 +81,40 @@ static const struct ib_field lrh_table[] = {
.size_bits = 16 }
};
+static const struct ib_field eth_table[] = {
+ { STRUCT_FIELD(eth, dmac_h),
+ .offset_words = 0,
+ .offset_bits = 0,
+ .size_bits = 32 },
+ { STRUCT_FIELD(eth, dmac_l),
+ .offset_words = 1,
+ .offset_bits = 0,
+ .size_bits = 16 },
+ { STRUCT_FIELD(eth, smac_h),
+ .offset_words = 1,
+ .offset_bits = 16,
+ .size_bits = 16 },
+ { STRUCT_FIELD(eth, smac_l),
+ .offset_words = 2,
+ .offset_bits = 0,
+ .size_bits = 32 },
+ { STRUCT_FIELD(eth, type),
+ .offset_words = 3,
+ .offset_bits = 0,
+ .size_bits = 16 }
+};
+
+static const struct ib_field vlan_table[] = {
+ { STRUCT_FIELD(vlan, tag),
+ .offset_words = 0,
+ .offset_bits = 0,
+ .size_bits = 16 },
+ { STRUCT_FIELD(vlan, type),
+ .offset_words = 0,
+ .offset_bits = 16,
+ .size_bits = 16 }
+};
+
static const struct ib_field grh_table[] = {
{ STRUCT_FIELD(grh, ip_version),
.offset_words = 0,
@@ -180,38 +215,43 @@ static const struct ib_field deth_table[] = {
/**
* ib_ud_header_init - Initialize UD header structure
* @payload_bytes:Length of packet payload
+ * @lrh_present: specify if LRH is present
+ * @eth_present: specify if Eth header is present
+ * @vlan_present: packet is tagged vlan
* @grh_present:GRH flag (if non-zero, GRH will be included)
- * @immediate_present: specify if immediate data should be used
+ * @immediate_present: specify if immediate data is present
* @header:Structure to initialize
- *
- * ib_ud_header_init() initializes the lrh.link_version, lrh.link_next_header,
- * lrh.packet_length, grh.ip_version, grh.payload_length,
- * grh.next_header, bth.opcode, bth.pad_count and
- * bth.transport_header_version fields of a &struct ib_ud_header given
- * the payload length and whether a GRH will be included.
*/
void ib_ud_header_init(int payload_bytes,
+ int lrh_present,
+ int eth_present,
+ int vlan_present,
int grh_present,
int immediate_present,
struct ib_ud_header *header)
{
- u16 packet_length;
-
memset(header, 0, sizeof *header);
- header->lrh.link_version = 0;
- header->lrh.link_next_header =
- grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
- packet_length = (IB_LRH_BYTES +
- IB_BTH_BYTES +
- IB_DETH_BYTES +
- payload_bytes +
- 4 + /* ICRC */
- 3) / 4; /* round up */
-
- header->grh_present = grh_present;
+ if (lrh_present) {
+ u16 packet_length;
+
+ header->lrh.link_version = 0;
+ header->lrh.link_next_header =
+ grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
+ packet_length = (IB_LRH_BYTES +
+ IB_BTH_BYTES +
+ IB_DETH_BYTES +
+ (grh_present ? IB_GRH_BYTES : 0) +
+ payload_bytes +
+ 4 + /* ICRC */
+ 3) / 4; /* round up */
+ header->lrh.packet_length = cpu_to_be16(packet_length);
+ }
+
+ if (vlan_present)
+ header->eth.type = cpu_to_be16(ETH_P_8021Q);
+
if (grh_present) {
- packet_length += IB_GRH_BYTES / 4;
header->grh.ip_version = 6;
header->grh.payload_length =
cpu_to_be16((IB_BTH_BYTES +
@@ -222,19 +262,52 @@ void ib_ud_header_init(int payload_bytes,
header->grh.next_header = 0x1b;
}
- header->lrh.packet_length = cpu_to_be16(packet_length);
-
- header->immediate_present = immediate_present;
if (immediate_present)
header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
else
header->bth.opcode = IB_OPCODE_UD_SEND_ONLY;
header->bth.pad_count = (4 - payload_bytes) & 3;
header->bth.transport_header_version = 0;
+
+ header->lrh_present = lrh_present;
+ header->eth_present = eth_present;
+ header->vlan_present = vlan_present;
+ header->grh_present = grh_present;
+ header->immediate_present = immediate_present;
}
EXPORT_SYMBOL(ib_ud_header_init);
/**
+ * ib_lrh_header_pack - Pack LRH header struct into wire format
+ * @lrh:unpacked LRH header struct
+ * @buf:Buffer to pack into
+ *
+ * ib_lrh_header_pack() packs the LRH header structure @lrh into
+ * wire format in the buffer @buf.
+ */
+int ib_lrh_header_pack(struct ib_unpacked_lrh *lrh, void *buf)
+{
+ ib_pack(lrh_table, ARRAY_SIZE(lrh_table), lrh, buf);
+ return 0;
+}
+EXPORT_SYMBOL(ib_lrh_header_pack);
+
+/**
+ * ib_lrh_header_unpack - Unpack LRH structure from wire format
+ * @lrh:unpacked LRH header struct
+ * @buf:Buffer to pack into
+ *
+ * ib_lrh_header_unpack() unpacks the LRH header structure from
+ * wire format (in buf) into @lrh.
+ */
+int ib_lrh_header_unpack(void *buf, struct ib_unpacked_lrh *lrh)
+{
+ ib_unpack(lrh_table, ARRAY_SIZE(lrh_table), buf, lrh);
+ return 0;
+}
+EXPORT_SYMBOL(ib_lrh_header_unpack);
+
+/**
* ib_ud_header_pack - Pack UD header struct into wire format
* @header:UD header struct
* @buf:Buffer to pack into
@@ -247,10 +320,21 @@ int ib_ud_header_pack(struct ib_ud_header *header,
{
int len = 0;
- ib_pack(lrh_table, ARRAY_SIZE(lrh_table),
- &header->lrh, buf);
- len += IB_LRH_BYTES;
-
+ if (header->lrh_present) {
+ ib_pack(lrh_table, ARRAY_SIZE(lrh_table),
+ &header->lrh, buf + len);
+ len += IB_LRH_BYTES;
+ }
+ if (header->eth_present) {
+ ib_pack(eth_table, ARRAY_SIZE(eth_table),
+ &header->eth, buf + len);
+ len += IB_ETH_BYTES;
+ }
+ if (header->vlan_present) {
+ ib_pack(vlan_table, ARRAY_SIZE(vlan_table),
+ &header->vlan, buf + len);
+ len += IB_VLAN_BYTES;
+ }
if (header->grh_present) {
ib_pack(grh_table, ARRAY_SIZE(grh_table),
&header->grh, buf + len);
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index 5fa856909511..cd1996d0ad08 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -1022,7 +1022,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
port->ib_dev = device;
port->port_num = port_num;
- init_MUTEX(&port->sm_sem);
+ sema_init(&port->sm_sem, 1);
mutex_init(&port->file_mutex);
INIT_LIST_HEAD(&port->file_list);
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 6fcfbeb24a23..b342248aec05 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -460,6 +460,8 @@ ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file,
resp.active_width = attr.active_width;
resp.active_speed = attr.active_speed;
resp.phys_state = attr.phys_state;
+ resp.link_layer = rdma_port_get_link_layer(file->device->ib_dev,
+ cmd.port_num);
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp))
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index e0fa22238715..af7a8b08b2e9 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -94,6 +94,22 @@ rdma_node_get_transport(enum rdma_node_type node_type)
}
EXPORT_SYMBOL(rdma_node_get_transport);
+enum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device, u8 port_num)
+{
+ if (device->get_link_layer)
+ return device->get_link_layer(device, port_num);
+
+ switch (rdma_node_get_transport(device->node_type)) {
+ case RDMA_TRANSPORT_IB:
+ return IB_LINK_LAYER_INFINIBAND;
+ case RDMA_TRANSPORT_IWARP:
+ return IB_LINK_LAYER_ETHERNET;
+ default:
+ return IB_LINK_LAYER_UNSPECIFIED;
+ }
+}
+EXPORT_SYMBOL(rdma_port_get_link_layer);
+
/* Protection domains */
struct ib_pd *ib_alloc_pd(struct ib_device *device)
diff --git a/drivers/infiniband/hw/amso1100/Kbuild b/drivers/infiniband/hw/amso1100/Kbuild
index 06964c4af849..950dfabcd89d 100644
--- a/drivers/infiniband/hw/amso1100/Kbuild
+++ b/drivers/infiniband/hw/amso1100/Kbuild
@@ -1,6 +1,4 @@
-ifdef CONFIG_INFINIBAND_AMSO1100_DEBUG
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_INFINIBAND_AMSO1100_DEBUG) := -DDEBUG
obj-$(CONFIG_INFINIBAND_AMSO1100) += iw_c2.o
diff --git a/drivers/infiniband/hw/amso1100/c2_intr.c b/drivers/infiniband/hw/amso1100/c2_intr.c
index 3b5095470cb3..0ebe4e806b86 100644
--- a/drivers/infiniband/hw/amso1100/c2_intr.c
+++ b/drivers/infiniband/hw/amso1100/c2_intr.c
@@ -62,8 +62,8 @@ void c2_rnic_interrupt(struct c2_dev *c2dev)
static void handle_mq(struct c2_dev *c2dev, u32 mq_index)
{
if (c2dev->qptr_array[mq_index] == NULL) {
- pr_debug(KERN_INFO "handle_mq: stray activity for mq_index=%d\n",
- mq_index);
+ pr_debug("handle_mq: stray activity for mq_index=%d\n",
+ mq_index);
return;
}
diff --git a/drivers/infiniband/hw/cxgb3/Kconfig b/drivers/infiniband/hw/cxgb3/Kconfig
index 2acec3fadf69..2b6352b85485 100644
--- a/drivers/infiniband/hw/cxgb3/Kconfig
+++ b/drivers/infiniband/hw/cxgb3/Kconfig
@@ -10,7 +10,7 @@ config INFINIBAND_CXGB3
our website at <http://www.chelsio.com>.
For customer support, please visit our customer support page at
- <http://www.chelsio.com/support.htm>.
+ <http://www.chelsio.com/support.html>.
Please send feedback to <linux-bugs@chelsio.com>.
diff --git a/drivers/infiniband/hw/cxgb3/Makefile b/drivers/infiniband/hw/cxgb3/Makefile
index 7e7b5a66f042..621619c794e5 100644
--- a/drivers/infiniband/hw/cxgb3/Makefile
+++ b/drivers/infiniband/hw/cxgb3/Makefile
@@ -1,10 +1,8 @@
-EXTRA_CFLAGS += -Idrivers/net/cxgb3
+ccflags-y := -Idrivers/net/cxgb3
obj-$(CONFIG_INFINIBAND_CXGB3) += iw_cxgb3.o
iw_cxgb3-y := iwch_cm.o iwch_ev.o iwch_cq.o iwch_qp.o iwch_mem.o \
iwch_provider.o iwch.o cxio_hal.o cxio_resource.o
-ifdef CONFIG_INFINIBAND_CXGB3_DEBUG
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_INFINIBAND_CXGB3_DEBUG) += -DDEBUG
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index 005b7b52bc1e..09dda0b8740e 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -160,6 +160,7 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq, int kernel)
struct rdma_cq_setup setup;
int size = (1UL << (cq->size_log2)) * sizeof(struct t3_cqe);
+ size += 1; /* one extra page for storing cq-in-err state */
cq->cqid = cxio_hal_get_cqid(rdev_p->rscp);
if (!cq->cqid)
return -ENOMEM;
diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h
index e5ddb63e7d23..4bb997aa39d0 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_wr.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h
@@ -728,6 +728,22 @@ struct t3_cq {
#define CQ_VLD_ENTRY(ptr,size_log2,cqe) (Q_GENBIT(ptr,size_log2) == \
CQE_GENBIT(*cqe))
+struct t3_cq_status_page {
+ u32 cq_err;
+};
+
+static inline int cxio_cq_in_error(struct t3_cq *cq)
+{
+ return ((struct t3_cq_status_page *)
+ &cq->queue[1 << cq->size_log2])->cq_err;
+}
+
+static inline void cxio_set_cq_in_error(struct t3_cq *cq)
+{
+ ((struct t3_cq_status_page *)
+ &cq->queue[1 << cq->size_log2])->cq_err = 1;
+}
+
static inline void cxio_set_wq_in_error(struct t3_wq *wq)
{
wq->queue->wq_in_err.err |= 1;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 13c88871dc3b..d02dcc6e5963 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -1093,8 +1093,8 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
PDBG("%s ep %p credits %u\n", __func__, ep, credits);
if (credits == 0) {
- PDBG(KERN_ERR "%s 0 credit ack ep %p state %u\n",
- __func__, ep, state_read(&ep->com));
+ PDBG("%s 0 credit ack ep %p state %u\n",
+ __func__, ep, state_read(&ep->com));
return CPL_RET_BUF_DONE;
}
diff --git a/drivers/infiniband/hw/cxgb3/iwch_ev.c b/drivers/infiniband/hw/cxgb3/iwch_ev.c
index 6afc89e7572c..71e0d845da3d 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_ev.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_ev.c
@@ -76,6 +76,14 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp,
atomic_inc(&qhp->refcnt);
spin_unlock(&rnicp->lock);
+ if (qhp->attr.state == IWCH_QP_STATE_RTS) {
+ attrs.next_state = IWCH_QP_STATE_TERMINATE;
+ iwch_modify_qp(qhp->rhp, qhp, IWCH_QP_ATTR_NEXT_STATE,
+ &attrs, 1);
+ if (send_term)
+ iwch_post_terminate(qhp, rsp_msg);
+ }
+
event.event = ib_event;
event.device = chp->ibcq.device;
if (ib_event == IB_EVENT_CQ_ERR)
@@ -86,13 +94,7 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp,
if (qhp->ibqp.event_handler)
(*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context);
- if (qhp->attr.state == IWCH_QP_STATE_RTS) {
- attrs.next_state = IWCH_QP_STATE_TERMINATE;
- iwch_modify_qp(qhp->rhp, qhp, IWCH_QP_ATTR_NEXT_STATE,
- &attrs, 1);
- if (send_term)
- iwch_post_terminate(qhp, rsp_msg);
- }
+ (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
if (atomic_dec_and_test(&qhp->refcnt))
wake_up(&qhp->wait);
@@ -179,7 +181,6 @@ void iwch_ev_dispatch(struct cxio_rdev *rdev_p, struct sk_buff *skb)
case TPT_ERR_BOUND:
case TPT_ERR_INVALIDATE_SHARED_MR:
case TPT_ERR_INVALIDATE_MR_WITH_MW_BOUND:
- (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_QP_ACCESS_ERR, 1);
break;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index fca0b4b747e4..2e2741307af4 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -154,6 +154,8 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve
struct iwch_create_cq_resp uresp;
struct iwch_create_cq_req ureq;
struct iwch_ucontext *ucontext = NULL;
+ static int warned;
+ size_t resplen;
PDBG("%s ib_dev %p entries %d\n", __func__, ibdev, entries);
rhp = to_iwch_dev(ibdev);
@@ -217,15 +219,26 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve
uresp.key = ucontext->key;
ucontext->key += PAGE_SIZE;
spin_unlock(&ucontext->mmap_lock);
- if (ib_copy_to_udata(udata, &uresp, sizeof (uresp))) {
+ mm->key = uresp.key;
+ mm->addr = virt_to_phys(chp->cq.queue);
+ if (udata->outlen < sizeof uresp) {
+ if (!warned++)
+ printk(KERN_WARNING MOD "Warning - "
+ "downlevel libcxgb3 (non-fatal).\n");
+ mm->len = PAGE_ALIGN((1UL << uresp.size_log2) *
+ sizeof(struct t3_cqe));
+ resplen = sizeof(struct iwch_create_cq_resp_v0);
+ } else {
+ mm->len = PAGE_ALIGN(((1UL << uresp.size_log2) + 1) *
+ sizeof(struct t3_cqe));
+ uresp.memsize = mm->len;
+ resplen = sizeof uresp;
+ }
+ if (ib_copy_to_udata(udata, &uresp, resplen)) {
kfree(mm);
iwch_destroy_cq(&chp->ibcq);
return ERR_PTR(-EFAULT);
}
- mm->key = uresp.key;
- mm->addr = virt_to_phys(chp->cq.queue);
- mm->len = PAGE_ALIGN((1UL << uresp.size_log2) *
- sizeof (struct t3_cqe));
insert_mmap(ucontext, mm);
}
PDBG("created cqid 0x%0x chp %p size 0x%0x, dma_addr 0x%0llx\n",
@@ -1414,6 +1427,7 @@ int iwch_register_device(struct iwch_dev *dev)
dev->ibdev.post_send = iwch_post_send;
dev->ibdev.post_recv = iwch_post_receive;
dev->ibdev.get_protocol_stats = iwch_get_mib;
+ dev->ibdev.uverbs_abi_ver = IWCH_UVERBS_ABI_VERSION;
dev->ibdev.iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL);
if (!dev->ibdev.iwcm)
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index c64d27bf2c15..0993137181d7 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -802,14 +802,12 @@ int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg)
/*
* Assumes qhp lock is held.
*/
-static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
+static void __flush_qp(struct iwch_qp *qhp, struct iwch_cq *rchp,
+ struct iwch_cq *schp, unsigned long *flag)
{
- struct iwch_cq *rchp, *schp;
int count;
int flushed;
- rchp = get_chp(qhp->rhp, qhp->attr.rcq);
- schp = get_chp(qhp->rhp, qhp->attr.scq);
PDBG("%s qhp %p rchp %p schp %p\n", __func__, qhp, rchp, schp);
/* take a ref on the qhp since we must release the lock */
@@ -847,10 +845,23 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
static void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
{
- if (qhp->ibqp.uobject)
+ struct iwch_cq *rchp, *schp;
+
+ rchp = get_chp(qhp->rhp, qhp->attr.rcq);
+ schp = get_chp(qhp->rhp, qhp->attr.scq);
+
+ if (qhp->ibqp.uobject) {
cxio_set_wq_in_error(&qhp->wq);
- else
- __flush_qp(qhp, flag);
+ cxio_set_cq_in_error(&rchp->cq);
+ (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
+ if (schp != rchp) {
+ cxio_set_cq_in_error(&schp->cq);
+ (*schp->ibcq.comp_handler)(&schp->ibcq,
+ schp->ibcq.cq_context);
+ }
+ return;
+ }
+ __flush_qp(qhp, rchp, schp, flag);
}
diff --git a/drivers/infiniband/hw/cxgb3/iwch_user.h b/drivers/infiniband/hw/cxgb3/iwch_user.h
index cb7086f558c1..a277c31fcaf7 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_user.h
+++ b/drivers/infiniband/hw/cxgb3/iwch_user.h
@@ -45,10 +45,18 @@ struct iwch_create_cq_req {
__u64 user_rptr_addr;
};
+struct iwch_create_cq_resp_v0 {
+ __u64 key;
+ __u32 cqid;
+ __u32 size_log2;
+};
+
struct iwch_create_cq_resp {
__u64 key;
__u32 cqid;
__u32 size_log2;
+ __u32 memsize;
+ __u32 reserved;
};
struct iwch_create_qp_resp {
diff --git a/drivers/infiniband/hw/cxgb4/Kconfig b/drivers/infiniband/hw/cxgb4/Kconfig
index ccb85eaaad75..6b7e6c543534 100644
--- a/drivers/infiniband/hw/cxgb4/Kconfig
+++ b/drivers/infiniband/hw/cxgb4/Kconfig
@@ -10,7 +10,7 @@ config INFINIBAND_CXGB4
our website at <http://www.chelsio.com>.
For customer support, please visit our customer support page at
- <http://www.chelsio.com/support.htm>.
+ <http://www.chelsio.com/support.html>.
Please send feedback to <linux-bugs@chelsio.com>.
diff --git a/drivers/infiniband/hw/cxgb4/Makefile b/drivers/infiniband/hw/cxgb4/Makefile
index e31a499f0172..cd20b1342aec 100644
--- a/drivers/infiniband/hw/cxgb4/Makefile
+++ b/drivers/infiniband/hw/cxgb4/Makefile
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS += -Idrivers/net/cxgb4
+ccflags-y := -Idrivers/net/cxgb4
obj-$(CONFIG_INFINIBAND_CXGB4) += iw_cxgb4.o
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 32d352a88d50..0dc62b1438be 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -117,9 +117,9 @@ static int rcv_win = 256 * 1024;
module_param(rcv_win, int, 0644);
MODULE_PARM_DESC(rcv_win, "TCP receive window in bytes (default=256KB)");
-static int snd_win = 32 * 1024;
+static int snd_win = 128 * 1024;
module_param(snd_win, int, 0644);
-MODULE_PARM_DESC(snd_win, "TCP send window in bytes (default=32KB)");
+MODULE_PARM_DESC(snd_win, "TCP send window in bytes (default=128KB)");
static struct workqueue_struct *workq;
@@ -172,7 +172,7 @@ static int c4iw_l2t_send(struct c4iw_rdev *rdev, struct sk_buff *skb,
error = cxgb4_l2t_send(rdev->lldi.ports[0], skb, l2e);
if (error < 0)
kfree_skb(skb);
- return error;
+ return error < 0 ? error : 0;
}
int c4iw_ofld_send(struct c4iw_rdev *rdev, struct sk_buff *skb)
@@ -187,7 +187,7 @@ int c4iw_ofld_send(struct c4iw_rdev *rdev, struct sk_buff *skb)
error = cxgb4_ofld_send(rdev->lldi.ports[0], skb);
if (error < 0)
kfree_skb(skb);
- return error;
+ return error < 0 ? error : 0;
}
static void release_tid(struct c4iw_rdev *rdev, u32 hwtid, struct sk_buff *skb)
@@ -219,12 +219,11 @@ static void set_emss(struct c4iw_ep *ep, u16 opt)
static enum c4iw_ep_state state_read(struct c4iw_ep_common *epc)
{
- unsigned long flags;
enum c4iw_ep_state state;
- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->mutex);
state = epc->state;
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->mutex);
return state;
}
@@ -235,12 +234,10 @@ static void __state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state new)
static void state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state new)
{
- unsigned long flags;
-
- spin_lock_irqsave(&epc->lock, flags);
+ mutex_lock(&epc->mutex);
PDBG("%s - %s -> %s\n", __func__, states[epc->state], states[new]);
__state_set(epc, new);
- spin_unlock_irqrestore(&epc->lock, flags);
+ mutex_unlock(&epc->mutex);
return;
}
@@ -251,8 +248,8 @@ static void *alloc_ep(int size, gfp_t gfp)
epc = kzalloc(size, gfp);
if (epc) {
kref_init(&epc->kref);
- spin_lock_init(&epc->lock);
- init_waitqueue_head(&epc->waitq);
+ mutex_init(&epc->mutex);
+ c4iw_init_wr_wait(&epc->wr_wait);
}
PDBG("%s alloc ep %p\n", __func__, epc);
return epc;
@@ -1131,7 +1128,6 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
{
struct c4iw_ep *ep;
struct cpl_abort_rpl_rss *rpl = cplhdr(skb);
- unsigned long flags;
int release = 0;
unsigned int tid = GET_TID(rpl);
struct tid_info *t = dev->rdev.lldi.tids;
@@ -1139,7 +1135,7 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
ep = lookup_tid(t, tid);
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
BUG_ON(!ep);
- spin_lock_irqsave(&ep->com.lock, flags);
+ mutex_lock(&ep->com.mutex);
switch (ep->com.state) {
case ABORTING:
__state_set(&ep->com, DEAD);
@@ -1150,7 +1146,7 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
__func__, ep, ep->com.state);
break;
}
- spin_unlock_irqrestore(&ep->com.lock, flags);
+ mutex_unlock(&ep->com.mutex);
if (release)
release_ep_resources(ep);
@@ -1213,9 +1209,9 @@ static int pass_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
}
PDBG("%s ep %p status %d error %d\n", __func__, ep,
rpl->status, status2errno(rpl->status));
- ep->com.rpl_err = status2errno(rpl->status);
- ep->com.rpl_done = 1;
- wake_up(&ep->com.waitq);
+ ep->com.wr_wait.ret = status2errno(rpl->status);
+ ep->com.wr_wait.done = 1;
+ wake_up(&ep->com.wr_wait.wait);
return 0;
}
@@ -1249,9 +1245,9 @@ static int close_listsrv_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
struct c4iw_listen_ep *ep = lookup_stid(t, stid);
PDBG("%s ep %p\n", __func__, ep);
- ep->com.rpl_err = status2errno(rpl->status);
- ep->com.rpl_done = 1;
- wake_up(&ep->com.waitq);
+ ep->com.wr_wait.ret = status2errno(rpl->status);
+ ep->com.wr_wait.done = 1;
+ wake_up(&ep->com.wr_wait.wait);
return 0;
}
@@ -1478,7 +1474,6 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
struct cpl_peer_close *hdr = cplhdr(skb);
struct c4iw_ep *ep;
struct c4iw_qp_attributes attrs;
- unsigned long flags;
int disconnect = 1;
int release = 0;
int closing = 0;
@@ -1489,7 +1484,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
dst_confirm(ep->dst);
- spin_lock_irqsave(&ep->com.lock, flags);
+ mutex_lock(&ep->com.mutex);
switch (ep->com.state) {
case MPA_REQ_WAIT:
__state_set(&ep->com, CLOSING);
@@ -1507,17 +1502,17 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
* in rdma connection migration (see c4iw_accept_cr()).
*/
__state_set(&ep->com, CLOSING);
- ep->com.rpl_done = 1;
- ep->com.rpl_err = -ECONNRESET;
+ ep->com.wr_wait.done = 1;
+ ep->com.wr_wait.ret = -ECONNRESET;
PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
- wake_up(&ep->com.waitq);
+ wake_up(&ep->com.wr_wait.wait);
break;
case MPA_REP_SENT:
__state_set(&ep->com, CLOSING);
- ep->com.rpl_done = 1;
- ep->com.rpl_err = -ECONNRESET;
+ ep->com.wr_wait.done = 1;
+ ep->com.wr_wait.ret = -ECONNRESET;
PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
- wake_up(&ep->com.waitq);
+ wake_up(&ep->com.wr_wait.wait);
break;
case FPDU_MODE:
start_ep_timer(ep);
@@ -1550,7 +1545,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
default:
BUG_ON(1);
}
- spin_unlock_irqrestore(&ep->com.lock, flags);
+ mutex_unlock(&ep->com.mutex);
if (closing) {
attrs.next_state = C4IW_QP_STATE_CLOSING;
c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
@@ -1581,7 +1576,6 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
struct c4iw_qp_attributes attrs;
int ret;
int release = 0;
- unsigned long flags;
struct tid_info *t = dev->rdev.lldi.tids;
unsigned int tid = GET_TID(req);
@@ -1591,9 +1585,17 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
ep->hwtid);
return 0;
}
- spin_lock_irqsave(&ep->com.lock, flags);
PDBG("%s ep %p tid %u state %u\n", __func__, ep, ep->hwtid,
ep->com.state);
+
+ /*
+ * Wake up any threads in rdma_init() or rdma_fini().
+ */
+ ep->com.wr_wait.done = 1;
+ ep->com.wr_wait.ret = -ECONNRESET;
+ wake_up(&ep->com.wr_wait.wait);
+
+ mutex_lock(&ep->com.mutex);
switch (ep->com.state) {
case CONNECTING:
break;
@@ -1605,23 +1607,8 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
connect_reply_upcall(ep, -ECONNRESET);
break;
case MPA_REP_SENT:
- ep->com.rpl_done = 1;
- ep->com.rpl_err = -ECONNRESET;
- PDBG("waking up ep %p\n", ep);
- wake_up(&ep->com.waitq);
break;
case MPA_REQ_RCVD:
-
- /*
- * We're gonna mark this puppy DEAD, but keep
- * the reference on it until the ULP accepts or
- * rejects the CR. Also wake up anyone waiting
- * in rdma connection migration (see c4iw_accept_cr()).
- */
- ep->com.rpl_done = 1;
- ep->com.rpl_err = -ECONNRESET;
- PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
- wake_up(&ep->com.waitq);
break;
case MORIBUND:
case CLOSING:
@@ -1644,7 +1631,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
break;
case DEAD:
PDBG("%s PEER_ABORT IN DEAD STATE!!!!\n", __func__);
- spin_unlock_irqrestore(&ep->com.lock, flags);
+ mutex_unlock(&ep->com.mutex);
return 0;
default:
BUG_ON(1);
@@ -1655,7 +1642,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
__state_set(&ep->com, DEAD);
release = 1;
}
- spin_unlock_irqrestore(&ep->com.lock, flags);
+ mutex_unlock(&ep->com.mutex);
rpl_skb = get_skb(skb, sizeof(*rpl), GFP_KERNEL);
if (!rpl_skb) {
@@ -1681,7 +1668,6 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
struct c4iw_ep *ep;
struct c4iw_qp_attributes attrs;
struct cpl_close_con_rpl *rpl = cplhdr(skb);
- unsigned long flags;
int release = 0;
struct tid_info *t = dev->rdev.lldi.tids;
unsigned int tid = GET_TID(rpl);
@@ -1692,7 +1678,7 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
BUG_ON(!ep);
/* The cm_id may be null if we failed to connect */
- spin_lock_irqsave(&ep->com.lock, flags);
+ mutex_lock(&ep->com.mutex);
switch (ep->com.state) {
case CLOSING:
__state_set(&ep->com, MORIBUND);
@@ -1717,7 +1703,7 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
BUG_ON(1);
break;
}
- spin_unlock_irqrestore(&ep->com.lock, flags);
+ mutex_unlock(&ep->com.mutex);
if (release)
release_ep_resources(ep);
return 0;
@@ -1725,23 +1711,24 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
static int terminate(struct c4iw_dev *dev, struct sk_buff *skb)
{
- struct c4iw_ep *ep;
- struct cpl_rdma_terminate *term = cplhdr(skb);
+ struct cpl_rdma_terminate *rpl = cplhdr(skb);
struct tid_info *t = dev->rdev.lldi.tids;
- unsigned int tid = GET_TID(term);
+ unsigned int tid = GET_TID(rpl);
+ struct c4iw_ep *ep;
+ struct c4iw_qp_attributes attrs;
ep = lookup_tid(t, tid);
+ BUG_ON(!ep);
- if (state_read(&ep->com) != FPDU_MODE)
- return 0;
+ if (ep->com.qp) {
+ printk(KERN_WARNING MOD "TERM received tid %u qpid %u\n", tid,
+ ep->com.qp->wq.sq.qid);
+ attrs.next_state = C4IW_QP_STATE_TERMINATE;
+ c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
+ C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
+ } else
+ printk(KERN_WARNING MOD "TERM received tid %u no qp\n", tid);
- PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
- skb_pull(skb, sizeof *term);
- PDBG("%s saving %d bytes of term msg\n", __func__, skb->len);
- skb_copy_from_linear_data(skb, ep->com.qp->attr.terminate_buffer,
- skb->len);
- ep->com.qp->attr.terminate_msg_len = skb->len;
- ep->com.qp->attr.is_terminate_local = 0;
return 0;
}
@@ -1762,8 +1749,8 @@ static int fw4_ack(struct c4iw_dev *dev, struct sk_buff *skb)
ep = lookup_tid(t, tid);
PDBG("%s ep %p tid %u credits %u\n", __func__, ep, ep->hwtid, credits);
if (credits == 0) {
- PDBG(KERN_ERR "%s 0 credit ack ep %p tid %u state %u\n",
- __func__, ep, ep->hwtid, state_read(&ep->com));
+ PDBG("%s 0 credit ack ep %p tid %u state %u\n",
+ __func__, ep, ep->hwtid, state_read(&ep->com));
return 0;
}
@@ -2042,6 +2029,7 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
}
state_set(&ep->com, LISTEN);
+ c4iw_init_wr_wait(&ep->com.wr_wait);
err = cxgb4_create_server(ep->com.dev->rdev.lldi.ports[0], ep->stid,
ep->com.local_addr.sin_addr.s_addr,
ep->com.local_addr.sin_port,
@@ -2050,15 +2038,8 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
goto fail3;
/* wait for pass_open_rpl */
- wait_event_timeout(ep->com.waitq, ep->com.rpl_done, C4IW_WR_TO);
- if (ep->com.rpl_done)
- err = ep->com.rpl_err;
- else {
- printk(KERN_ERR MOD "Device %s not responding!\n",
- pci_name(ep->com.dev->rdev.lldi.pdev));
- ep->com.dev->rdev.flags = T4_FATAL_ERROR;
- err = -EIO;
- }
+ err = c4iw_wait_for_reply(&ep->com.dev->rdev, &ep->com.wr_wait, 0, 0,
+ __func__);
if (!err) {
cm_id->provider_data = ep;
goto out;
@@ -2082,20 +2063,12 @@ int c4iw_destroy_listen(struct iw_cm_id *cm_id)
might_sleep();
state_set(&ep->com, DEAD);
- ep->com.rpl_done = 0;
- ep->com.rpl_err = 0;
+ c4iw_init_wr_wait(&ep->com.wr_wait);
err = listen_stop(ep);
if (err)
goto done;
- wait_event_timeout(ep->com.waitq, ep->com.rpl_done, C4IW_WR_TO);
- if (ep->com.rpl_done)
- err = ep->com.rpl_err;
- else {
- printk(KERN_ERR MOD "Device %s not responding!\n",
- pci_name(ep->com.dev->rdev.lldi.pdev));
- ep->com.dev->rdev.flags = T4_FATAL_ERROR;
- err = -EIO;
- }
+ err = c4iw_wait_for_reply(&ep->com.dev->rdev, &ep->com.wr_wait, 0, 0,
+ __func__);
cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid, PF_INET);
done:
cm_id->rem_ref(cm_id);
@@ -2106,12 +2079,11 @@ done:
int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
{
int ret = 0;
- unsigned long flags;
int close = 0;
int fatal = 0;
struct c4iw_rdev *rdev;
- spin_lock_irqsave(&ep->com.lock, flags);
+ mutex_lock(&ep->com.mutex);
PDBG("%s ep %p state %s, abrupt %d\n", __func__, ep,
states[ep->com.state], abrupt);
@@ -2158,7 +2130,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
break;
}
- spin_unlock_irqrestore(&ep->com.lock, flags);
+ mutex_unlock(&ep->com.mutex);
if (close) {
if (abrupt)
ret = abort_connection(ep, NULL, gfp);
@@ -2172,6 +2144,13 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
return ret;
}
+static int async_event(struct c4iw_dev *dev, struct sk_buff *skb)
+{
+ struct cpl_fw6_msg *rpl = cplhdr(skb);
+ c4iw_ev_dispatch(dev, (struct t4_cqe *)&rpl->data[0]);
+ return 0;
+}
+
/*
* These are the real handlers that are called from a
* work queue.
@@ -2190,7 +2169,8 @@ static c4iw_handler_func work_handlers[NUM_CPL_CMDS] = {
[CPL_ABORT_REQ_RSS] = peer_abort,
[CPL_CLOSE_CON_RPL] = close_con_rpl,
[CPL_RDMA_TERMINATE] = terminate,
- [CPL_FW4_ACK] = fw4_ack
+ [CPL_FW4_ACK] = fw4_ack,
+ [CPL_FW6_MSG] = async_event
};
static void process_timeout(struct c4iw_ep *ep)
@@ -2198,7 +2178,7 @@ static void process_timeout(struct c4iw_ep *ep)
struct c4iw_qp_attributes attrs;
int abort = 1;
- spin_lock_irq(&ep->com.lock);
+ mutex_lock(&ep->com.mutex);
PDBG("%s ep %p tid %u state %d\n", __func__, ep, ep->hwtid,
ep->com.state);
switch (ep->com.state) {
@@ -2225,7 +2205,7 @@ static void process_timeout(struct c4iw_ep *ep)
WARN_ON(1);
abort = 0;
}
- spin_unlock_irq(&ep->com.lock);
+ mutex_unlock(&ep->com.mutex);
if (abort)
abort_connection(ep, NULL, GFP_KERNEL);
c4iw_put_ep(&ep->com);
@@ -2309,6 +2289,7 @@ static int set_tcb_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
printk(KERN_ERR MOD "Unexpected SET_TCB_RPL status %u "
"for tid %u\n", rpl->status, GET_TID(rpl));
}
+ kfree_skb(skb);
return 0;
}
@@ -2323,20 +2304,25 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
switch (rpl->type) {
case 1:
ret = (int)((be64_to_cpu(rpl->data[0]) >> 8) & 0xff);
- wr_waitp = (__force struct c4iw_wr_wait *)rpl->data[1];
+ wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1];
PDBG("%s wr_waitp %p ret %u\n", __func__, wr_waitp, ret);
if (wr_waitp) {
- wr_waitp->ret = ret;
+ if (ret)
+ wr_waitp->ret = -ret;
+ else
+ wr_waitp->ret = 0;
wr_waitp->done = 1;
wake_up(&wr_waitp->wait);
}
+ kfree_skb(skb);
break;
case 2:
- c4iw_ev_dispatch(dev, (struct t4_cqe *)&rpl->data[0]);
+ sched(dev, skb);
break;
default:
printk(KERN_ERR MOD "%s unexpected fw6 msg type %u\n", __func__,
rpl->type);
+ kfree_skb(skb);
break;
}
return 0;
diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c
index b3daf39eed4a..8d8f8add6fcd 100644
--- a/drivers/infiniband/hw/cxgb4/cq.c
+++ b/drivers/infiniband/hw/cxgb4/cq.c
@@ -55,7 +55,7 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
V_FW_RI_RES_WR_NRES(1) |
FW_WR_COMPL(1));
res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
- res_wr->cookie = (u64)&wr_wait;
+ res_wr->cookie = (unsigned long) &wr_wait;
res = res_wr->res;
res->u.cq.restype = FW_RI_RES_TYPE_CQ;
res->u.cq.op = FW_RI_RES_OP_RESET;
@@ -64,14 +64,7 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
c4iw_init_wr_wait(&wr_wait);
ret = c4iw_ofld_send(rdev, skb);
if (!ret) {
- wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
- if (!wr_wait.done) {
- printk(KERN_ERR MOD "Device %s not responding!\n",
- pci_name(rdev->lldi.pdev));
- rdev->flags = T4_FATAL_ERROR;
- ret = -EIO;
- } else
- ret = wr_wait.ret;
+ ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
}
kfree(cq->sw_queue);
@@ -132,7 +125,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
V_FW_RI_RES_WR_NRES(1) |
FW_WR_COMPL(1));
res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
- res_wr->cookie = (u64)&wr_wait;
+ res_wr->cookie = (unsigned long) &wr_wait;
res = res_wr->res;
res->u.cq.restype = FW_RI_RES_TYPE_CQ;
res->u.cq.op = FW_RI_RES_OP_WRITE;
@@ -157,14 +150,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
if (ret)
goto err4;
PDBG("%s wait_event wr_wait %p\n", __func__, &wr_wait);
- wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
- if (!wr_wait.done) {
- printk(KERN_ERR MOD "Device %s not responding!\n",
- pci_name(rdev->lldi.pdev));
- rdev->flags = T4_FATAL_ERROR;
- ret = -EIO;
- } else
- ret = wr_wait.ret;
+ ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
if (ret)
goto err4;
@@ -476,6 +462,11 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
goto proc_cqe;
}
+ if (CQE_OPCODE(hw_cqe) == FW_RI_TERMINATE) {
+ ret = -EAGAIN;
+ goto skip_cqe;
+ }
+
/*
* RECV completion.
*/
@@ -696,6 +687,7 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
case T4_ERR_MSN_RANGE:
case T4_ERR_IRD_OVERFLOW:
case T4_ERR_OPCODE:
+ case T4_ERR_INTERNAL_ERR:
wc->status = IB_WC_FATAL_ERR;
break;
case T4_ERR_SWFLUSH:
diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c
index 9bbf491d5d9e..54fbc1118abe 100644
--- a/drivers/infiniband/hw/cxgb4/device.c
+++ b/drivers/infiniband/hw/cxgb4/device.c
@@ -49,29 +49,33 @@ static DEFINE_MUTEX(dev_mutex);
static struct dentry *c4iw_debugfs_root;
-struct debugfs_qp_data {
+struct c4iw_debugfs_data {
struct c4iw_dev *devp;
char *buf;
int bufsize;
int pos;
};
-static int count_qps(int id, void *p, void *data)
+static int count_idrs(int id, void *p, void *data)
{
- struct c4iw_qp *qp = p;
int *countp = data;
- if (id != qp->wq.sq.qid)
- return 0;
-
*countp = *countp + 1;
return 0;
}
-static int dump_qps(int id, void *p, void *data)
+static ssize_t debugfs_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct c4iw_debugfs_data *d = file->private_data;
+
+ return simple_read_from_buffer(buf, count, ppos, d->buf, d->pos);
+}
+
+static int dump_qp(int id, void *p, void *data)
{
struct c4iw_qp *qp = p;
- struct debugfs_qp_data *qpd = data;
+ struct c4iw_debugfs_data *qpd = data;
int space;
int cc;
@@ -101,7 +105,7 @@ static int dump_qps(int id, void *p, void *data)
static int qp_release(struct inode *inode, struct file *file)
{
- struct debugfs_qp_data *qpd = file->private_data;
+ struct c4iw_debugfs_data *qpd = file->private_data;
if (!qpd) {
printk(KERN_INFO "%s null qpd?\n", __func__);
return 0;
@@ -113,7 +117,7 @@ static int qp_release(struct inode *inode, struct file *file)
static int qp_open(struct inode *inode, struct file *file)
{
- struct debugfs_qp_data *qpd;
+ struct c4iw_debugfs_data *qpd;
int ret = 0;
int count = 1;
@@ -126,7 +130,7 @@ static int qp_open(struct inode *inode, struct file *file)
qpd->pos = 0;
spin_lock_irq(&qpd->devp->lock);
- idr_for_each(&qpd->devp->qpidr, count_qps, &count);
+ idr_for_each(&qpd->devp->qpidr, count_idrs, &count);
spin_unlock_irq(&qpd->devp->lock);
qpd->bufsize = count * 128;
@@ -137,7 +141,7 @@ static int qp_open(struct inode *inode, struct file *file)
}
spin_lock_irq(&qpd->devp->lock);
- idr_for_each(&qpd->devp->qpidr, dump_qps, qpd);
+ idr_for_each(&qpd->devp->qpidr, dump_qp, qpd);
spin_unlock_irq(&qpd->devp->lock);
qpd->buf[qpd->pos++] = 0;
@@ -149,43 +153,86 @@ out:
return ret;
}
-static ssize_t qp_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
+static const struct file_operations qp_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = qp_open,
+ .release = qp_release,
+ .read = debugfs_read,
+ .llseek = default_llseek,
+};
+
+static int dump_stag(int id, void *p, void *data)
{
- struct debugfs_qp_data *qpd = file->private_data;
- loff_t pos = *ppos;
- loff_t avail = qpd->pos;
+ struct c4iw_debugfs_data *stagd = data;
+ int space;
+ int cc;
- if (pos < 0)
- return -EINVAL;
- if (pos >= avail)
+ space = stagd->bufsize - stagd->pos - 1;
+ if (space == 0)
+ return 1;
+
+ cc = snprintf(stagd->buf + stagd->pos, space, "0x%x\n", id<<8);
+ if (cc < space)
+ stagd->pos += cc;
+ return 0;
+}
+
+static int stag_release(struct inode *inode, struct file *file)
+{
+ struct c4iw_debugfs_data *stagd = file->private_data;
+ if (!stagd) {
+ printk(KERN_INFO "%s null stagd?\n", __func__);
return 0;
- if (count > avail - pos)
- count = avail - pos;
+ }
+ kfree(stagd->buf);
+ kfree(stagd);
+ return 0;
+}
- while (count) {
- size_t len = 0;
+static int stag_open(struct inode *inode, struct file *file)
+{
+ struct c4iw_debugfs_data *stagd;
+ int ret = 0;
+ int count = 1;
- len = min((int)count, (int)qpd->pos - (int)pos);
- if (copy_to_user(buf, qpd->buf + pos, len))
- return -EFAULT;
- if (len == 0)
- return -EINVAL;
+ stagd = kmalloc(sizeof *stagd, GFP_KERNEL);
+ if (!stagd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ stagd->devp = inode->i_private;
+ stagd->pos = 0;
+
+ spin_lock_irq(&stagd->devp->lock);
+ idr_for_each(&stagd->devp->mmidr, count_idrs, &count);
+ spin_unlock_irq(&stagd->devp->lock);
- buf += len;
- pos += len;
- count -= len;
+ stagd->bufsize = count * sizeof("0x12345678\n");
+ stagd->buf = kmalloc(stagd->bufsize, GFP_KERNEL);
+ if (!stagd->buf) {
+ ret = -ENOMEM;
+ goto err1;
}
- count = pos - *ppos;
- *ppos = pos;
- return count;
+
+ spin_lock_irq(&stagd->devp->lock);
+ idr_for_each(&stagd->devp->mmidr, dump_stag, stagd);
+ spin_unlock_irq(&stagd->devp->lock);
+
+ stagd->buf[stagd->pos++] = 0;
+ file->private_data = stagd;
+ goto out;
+err1:
+ kfree(stagd);
+out:
+ return ret;
}
-static const struct file_operations qp_debugfs_fops = {
+static const struct file_operations stag_debugfs_fops = {
.owner = THIS_MODULE,
- .open = qp_open,
- .release = qp_release,
- .read = qp_read,
+ .open = stag_open,
+ .release = stag_release,
+ .read = debugfs_read,
+ .llseek = default_llseek,
};
static int setup_debugfs(struct c4iw_dev *devp)
@@ -199,6 +246,11 @@ static int setup_debugfs(struct c4iw_dev *devp)
(void *)devp, &qp_debugfs_fops);
if (de && de->d_inode)
de->d_inode->i_size = 4096;
+
+ de = debugfs_create_file("stags", S_IWUSR, devp->debugfs_root,
+ (void *)devp, &stag_debugfs_fops);
+ if (de && de->d_inode)
+ de->d_inode->i_size = 4096;
return 0;
}
@@ -290,7 +342,14 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev)
printk(KERN_ERR MOD "error %d initializing rqt pool\n", err);
goto err3;
}
+ err = c4iw_ocqp_pool_create(rdev);
+ if (err) {
+ printk(KERN_ERR MOD "error %d initializing ocqp pool\n", err);
+ goto err4;
+ }
return 0;
+err4:
+ c4iw_rqtpool_destroy(rdev);
err3:
c4iw_pblpool_destroy(rdev);
err2:
@@ -317,6 +376,7 @@ static void c4iw_remove(struct c4iw_dev *dev)
idr_destroy(&dev->cqidr);
idr_destroy(&dev->qpidr);
idr_destroy(&dev->mmidr);
+ iounmap(dev->rdev.oc_mw_kva);
ib_dealloc_device(&dev->ibdev);
}
@@ -332,6 +392,17 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
}
devp->rdev.lldi = *infop;
+ devp->rdev.oc_mw_pa = pci_resource_start(devp->rdev.lldi.pdev, 2) +
+ (pci_resource_len(devp->rdev.lldi.pdev, 2) -
+ roundup_pow_of_two(devp->rdev.lldi.vr->ocq.size));
+ devp->rdev.oc_mw_kva = ioremap_wc(devp->rdev.oc_mw_pa,
+ devp->rdev.lldi.vr->ocq.size);
+
+ printk(KERN_INFO MOD "ocq memory: "
+ "hw_start 0x%x size %u mw_pa 0x%lx mw_kva %p\n",
+ devp->rdev.lldi.vr->ocq.start, devp->rdev.lldi.vr->ocq.size,
+ devp->rdev.oc_mw_pa, devp->rdev.oc_mw_kva);
+
mutex_lock(&dev_mutex);
ret = c4iw_rdev_open(&devp->rdev);
@@ -383,46 +454,6 @@ out:
return dev;
}
-static struct sk_buff *t4_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 (gl->tot_len <= 512) {
- skb = alloc_skb(gl->tot_len, GFP_ATOMIC);
- if (unlikely(!skb))
- goto out;
- __skb_put(skb, gl->tot_len);
- skb_copy_to_linear_data(skb, gl->va, gl->tot_len);
- } else {
- skb = alloc_skb(skb_len, GFP_ATOMIC);
- if (unlikely(!skb))
- goto out;
- __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;
-
- 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:
- return skb;
-}
-
static int c4iw_uld_rx_handler(void *handle, const __be64 *rsp,
const struct pkt_gl *gl)
{
@@ -447,7 +478,7 @@ static int c4iw_uld_rx_handler(void *handle, const __be64 *rsp,
c4iw_ev_handler(dev, qid);
return 0;
} else {
- skb = t4_pktgl_to_skb(gl, 128, 128);
+ skb = cxgb4_pktgl_to_skb(gl, 128, 128);
if (unlikely(!skb))
goto nomem;
}
diff --git a/drivers/infiniband/hw/cxgb4/ev.c b/drivers/infiniband/hw/cxgb4/ev.c
index 491e76a0327f..c13041a0aeba 100644
--- a/drivers/infiniband/hw/cxgb4/ev.c
+++ b/drivers/infiniband/hw/cxgb4/ev.c
@@ -60,7 +60,7 @@ static void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp,
if (qhp->attr.state == C4IW_QP_STATE_RTS) {
attrs.next_state = C4IW_QP_STATE_TERMINATE;
c4iw_modify_qp(qhp->rhp, qhp, C4IW_QP_ATTR_NEXT_STATE,
- &attrs, 1);
+ &attrs, 0);
}
event.event = ib_event;
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index ed459b8f800f..16032cdb4337 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -46,6 +46,7 @@
#include <linux/timer.h>
#include <linux/io.h>
#include <linux/kfifo.h>
+#include <linux/mutex.h>
#include <asm/byteorder.h>
@@ -79,21 +80,6 @@ static inline void *cplhdr(struct sk_buff *skb)
return skb->data;
}
-#define C4IW_WR_TO (10*HZ)
-
-struct c4iw_wr_wait {
- wait_queue_head_t wait;
- int done;
- int ret;
-};
-
-static inline void c4iw_init_wr_wait(struct c4iw_wr_wait *wr_waitp)
-{
- wr_waitp->ret = 0;
- wr_waitp->done = 0;
- init_waitqueue_head(&wr_waitp->wait);
-}
-
struct c4iw_resource {
struct kfifo tpt_fifo;
spinlock_t tpt_fifo_lock;
@@ -127,8 +113,11 @@ struct c4iw_rdev {
struct c4iw_dev_ucontext uctx;
struct gen_pool *pbl_pool;
struct gen_pool *rqt_pool;
+ struct gen_pool *ocqp_pool;
u32 flags;
struct cxgb4_lld_info lldi;
+ unsigned long oc_mw_pa;
+ void __iomem *oc_mw_kva;
};
static inline int c4iw_fatal_error(struct c4iw_rdev *rdev)
@@ -141,6 +130,44 @@ static inline int c4iw_num_stags(struct c4iw_rdev *rdev)
return min((int)T4_MAX_NUM_STAG, (int)(rdev->lldi.vr->stag.size >> 5));
}
+#define C4IW_WR_TO (10*HZ)
+
+struct c4iw_wr_wait {
+ wait_queue_head_t wait;
+ int done;
+ int ret;
+};
+
+static inline void c4iw_init_wr_wait(struct c4iw_wr_wait *wr_waitp)
+{
+ wr_waitp->ret = 0;
+ wr_waitp->done = 0;
+ init_waitqueue_head(&wr_waitp->wait);
+}
+
+static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
+ struct c4iw_wr_wait *wr_waitp,
+ u32 hwtid, u32 qpid,
+ const char *func)
+{
+ unsigned to = C4IW_WR_TO;
+ do {
+
+ wait_event_timeout(wr_waitp->wait, wr_waitp->done, to);
+ if (!wr_waitp->done) {
+ printk(KERN_ERR MOD "%s - Device %s not responding - "
+ "tid %u qpid %u\n", func,
+ pci_name(rdev->lldi.pdev), hwtid, qpid);
+ to = to << 2;
+ }
+ } while (!wr_waitp->done);
+ if (wr_waitp->ret)
+ printk(KERN_WARNING MOD "%s: FW reply %d tid %u qpid %u\n",
+ pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid);
+ return wr_waitp->ret;
+}
+
+
struct c4iw_dev {
struct ib_device ibdev;
struct c4iw_rdev rdev;
@@ -327,6 +354,7 @@ struct c4iw_qp {
struct c4iw_qp_attributes attr;
struct t4_wq wq;
spinlock_t lock;
+ struct mutex mutex;
atomic_t refcnt;
wait_queue_head_t wait;
struct timer_list timer;
@@ -579,12 +607,10 @@ struct c4iw_ep_common {
struct c4iw_dev *dev;
enum c4iw_ep_state state;
struct kref kref;
- spinlock_t lock;
+ struct mutex mutex;
struct sockaddr_in local_addr;
struct sockaddr_in remote_addr;
- wait_queue_head_t waitq;
- int rpl_done;
- int rpl_err;
+ struct c4iw_wr_wait wr_wait;
unsigned long flags;
};
@@ -654,8 +680,10 @@ int c4iw_init_resource(struct c4iw_rdev *rdev, u32 nr_tpt, u32 nr_pdid);
int c4iw_init_ctrl_qp(struct c4iw_rdev *rdev);
int c4iw_pblpool_create(struct c4iw_rdev *rdev);
int c4iw_rqtpool_create(struct c4iw_rdev *rdev);
+int c4iw_ocqp_pool_create(struct c4iw_rdev *rdev);
void c4iw_pblpool_destroy(struct c4iw_rdev *rdev);
void c4iw_rqtpool_destroy(struct c4iw_rdev *rdev);
+void c4iw_ocqp_pool_destroy(struct c4iw_rdev *rdev);
void c4iw_destroy_resource(struct c4iw_resource *rscp);
int c4iw_destroy_ctrl_qp(struct c4iw_rdev *rdev);
int c4iw_register_device(struct c4iw_dev *dev);
@@ -721,6 +749,8 @@ u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size);
void c4iw_rqtpool_free(struct c4iw_rdev *rdev, u32 addr, int size);
u32 c4iw_pblpool_alloc(struct c4iw_rdev *rdev, int size);
void c4iw_pblpool_free(struct c4iw_rdev *rdev, u32 addr, int size);
+u32 c4iw_ocqp_pool_alloc(struct c4iw_rdev *rdev, int size);
+void c4iw_ocqp_pool_free(struct c4iw_rdev *rdev, u32 addr, int size);
int c4iw_ofld_send(struct c4iw_rdev *rdev, struct sk_buff *skb);
void c4iw_flush_hw_cq(struct t4_cq *cq);
void c4iw_count_rcqes(struct t4_cq *cq, struct t4_wq *wq, int *count);
diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c
index 269373a62f22..273ffe49525a 100644
--- a/drivers/infiniband/hw/cxgb4/mem.c
+++ b/drivers/infiniband/hw/cxgb4/mem.c
@@ -71,7 +71,7 @@ static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
if (i == (num_wqe-1)) {
req->wr.wr_hi = cpu_to_be32(FW_WR_OP(FW_ULPTX_WR) |
FW_WR_COMPL(1));
- req->wr.wr_lo = (__force __be64)&wr_wait;
+ req->wr.wr_lo = (__force __be64)(unsigned long) &wr_wait;
} else
req->wr.wr_hi = cpu_to_be32(FW_WR_OP(FW_ULPTX_WR));
req->wr.wr_mid = cpu_to_be32(
@@ -103,14 +103,7 @@ static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
len -= C4IW_MAX_INLINE_SIZE;
}
- wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
- if (!wr_wait.done) {
- printk(KERN_ERR MOD "Device %s not responding!\n",
- pci_name(rdev->lldi.pdev));
- rdev->flags = T4_FATAL_ERROR;
- ret = -EIO;
- } else
- ret = wr_wait.ret;
+ ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
return ret;
}
diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c
index 8f645c83a125..f66dd8bf5128 100644
--- a/drivers/infiniband/hw/cxgb4/provider.c
+++ b/drivers/infiniband/hw/cxgb4/provider.c
@@ -54,9 +54,9 @@
#include "iw_cxgb4.h"
-static int fastreg_support;
+static int fastreg_support = 1;
module_param(fastreg_support, int, 0644);
-MODULE_PARM_DESC(fastreg_support, "Advertise fastreg support (default=0)");
+MODULE_PARM_DESC(fastreg_support, "Advertise fastreg support (default=1)");
static int c4iw_modify_port(struct ib_device *ibdev,
u8 port, int port_modify_mask,
@@ -149,19 +149,28 @@ static int c4iw_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
addr = mm->addr;
kfree(mm);
- if ((addr >= pci_resource_start(rdev->lldi.pdev, 2)) &&
- (addr < (pci_resource_start(rdev->lldi.pdev, 2) +
- pci_resource_len(rdev->lldi.pdev, 2)))) {
+ if ((addr >= pci_resource_start(rdev->lldi.pdev, 0)) &&
+ (addr < (pci_resource_start(rdev->lldi.pdev, 0) +
+ pci_resource_len(rdev->lldi.pdev, 0)))) {
/*
- * Map T4 DB register.
+ * MA_SYNC register...
*/
- if (vma->vm_flags & VM_READ)
- return -EPERM;
-
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
- vma->vm_flags &= ~VM_MAYREAD;
+ ret = io_remap_pfn_range(vma, vma->vm_start,
+ addr >> PAGE_SHIFT,
+ len, vma->vm_page_prot);
+ } else if ((addr >= pci_resource_start(rdev->lldi.pdev, 2)) &&
+ (addr < (pci_resource_start(rdev->lldi.pdev, 2) +
+ pci_resource_len(rdev->lldi.pdev, 2)))) {
+
+ /*
+ * Map user DB or OCQP memory...
+ */
+ if (addr >= rdev->oc_mw_pa)
+ vma->vm_page_prot = t4_pgprot_wc(vma->vm_page_prot);
+ else
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
ret = io_remap_pfn_range(vma, vma->vm_start,
addr >> PAGE_SHIFT,
len, vma->vm_page_prot);
@@ -382,7 +391,17 @@ static ssize_t show_board(struct device *dev, struct device_attribute *attr,
static int c4iw_get_mib(struct ib_device *ibdev,
union rdma_protocol_stats *stats)
{
- return -ENOSYS;
+ struct tp_tcp_stats v4, v6;
+ struct c4iw_dev *c4iw_dev = to_c4iw_dev(ibdev);
+
+ cxgb4_get_tcp_stats(c4iw_dev->rdev.lldi.pdev, &v4, &v6);
+ memset(stats, 0, sizeof *stats);
+ stats->iw.tcpInSegs = v4.tcpInSegs + v6.tcpInSegs;
+ stats->iw.tcpOutSegs = v4.tcpOutSegs + v6.tcpOutSegs;
+ stats->iw.tcpRetransSegs = v4.tcpRetransSegs + v6.tcpRetransSegs;
+ stats->iw.tcpOutRsts = v4.tcpOutRsts + v6.tcpOutSegs;
+
+ return 0;
}
static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
@@ -472,6 +491,7 @@ int c4iw_register_device(struct c4iw_dev *dev)
dev->ibdev.post_send = c4iw_post_send;
dev->ibdev.post_recv = c4iw_post_receive;
dev->ibdev.get_protocol_stats = c4iw_get_mib;
+ dev->ibdev.uverbs_abi_ver = C4IW_UVERBS_ABI_VERSION;
dev->ibdev.iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL);
if (!dev->ibdev.iwcm)
diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
index 93f6e5bf0ec5..057cb2505ea1 100644
--- a/drivers/infiniband/hw/cxgb4/qp.c
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -31,6 +31,63 @@
*/
#include "iw_cxgb4.h"
+static int ocqp_support;
+module_param(ocqp_support, int, 0644);
+MODULE_PARM_DESC(ocqp_support, "Support on-chip SQs (default=0)");
+
+static void set_state(struct c4iw_qp *qhp, enum c4iw_qp_state state)
+{
+ unsigned long flag;
+ spin_lock_irqsave(&qhp->lock, flag);
+ qhp->attr.state = state;
+ spin_unlock_irqrestore(&qhp->lock, flag);
+}
+
+static void dealloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
+{
+ c4iw_ocqp_pool_free(rdev, sq->dma_addr, sq->memsize);
+}
+
+static void dealloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
+{
+ dma_free_coherent(&(rdev->lldi.pdev->dev), sq->memsize, sq->queue,
+ pci_unmap_addr(sq, mapping));
+}
+
+static void dealloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
+{
+ if (t4_sq_onchip(sq))
+ dealloc_oc_sq(rdev, sq);
+ else
+ dealloc_host_sq(rdev, sq);
+}
+
+static int alloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
+{
+ if (!ocqp_support || !t4_ocqp_supported())
+ return -ENOSYS;
+ sq->dma_addr = c4iw_ocqp_pool_alloc(rdev, sq->memsize);
+ if (!sq->dma_addr)
+ return -ENOMEM;
+ sq->phys_addr = rdev->oc_mw_pa + sq->dma_addr -
+ rdev->lldi.vr->ocq.start;
+ sq->queue = (__force union t4_wr *)(rdev->oc_mw_kva + sq->dma_addr -
+ rdev->lldi.vr->ocq.start);
+ sq->flags |= T4_SQ_ONCHIP;
+ return 0;
+}
+
+static int alloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
+{
+ sq->queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev), sq->memsize,
+ &(sq->dma_addr), GFP_KERNEL);
+ if (!sq->queue)
+ return -ENOMEM;
+ sq->phys_addr = virt_to_phys(sq->queue);
+ pci_unmap_addr_set(sq, mapping, sq->dma_addr);
+ return 0;
+}
+
static int destroy_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
struct c4iw_dev_ucontext *uctx)
{
@@ -41,9 +98,7 @@ static int destroy_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
dma_free_coherent(&(rdev->lldi.pdev->dev),
wq->rq.memsize, wq->rq.queue,
dma_unmap_addr(&wq->rq, mapping));
- dma_free_coherent(&(rdev->lldi.pdev->dev),
- wq->sq.memsize, wq->sq.queue,
- dma_unmap_addr(&wq->sq, mapping));
+ dealloc_sq(rdev, &wq->sq);
c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
kfree(wq->rq.sw_rq);
kfree(wq->sq.sw_sq);
@@ -93,11 +148,12 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
if (!wq->rq.rqt_hwaddr)
goto err4;
- wq->sq.queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev),
- wq->sq.memsize, &(wq->sq.dma_addr),
- GFP_KERNEL);
- if (!wq->sq.queue)
- goto err5;
+ if (user) {
+ if (alloc_oc_sq(rdev, &wq->sq) && alloc_host_sq(rdev, &wq->sq))
+ goto err5;
+ } else
+ if (alloc_host_sq(rdev, &wq->sq))
+ goto err5;
memset(wq->sq.queue, 0, wq->sq.memsize);
dma_unmap_addr_set(&wq->sq, mapping, wq->sq.dma_addr);
@@ -144,7 +200,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
V_FW_RI_RES_WR_NRES(2) |
FW_WR_COMPL(1));
res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
- res_wr->cookie = (u64)&wr_wait;
+ res_wr->cookie = (unsigned long) &wr_wait;
res = res_wr->res;
res->u.sqrq.restype = FW_RI_RES_TYPE_SQ;
res->u.sqrq.op = FW_RI_RES_OP_WRITE;
@@ -158,6 +214,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
V_FW_RI_RES_WR_HOSTFCMODE(0) | /* no host cidx updates */
V_FW_RI_RES_WR_CPRIO(0) | /* don't keep in chip cache */
V_FW_RI_RES_WR_PCIECHN(0) | /* set by uP at ri_init time */
+ t4_sq_onchip(&wq->sq) ? F_FW_RI_RES_WR_ONCHIP : 0 |
V_FW_RI_RES_WR_IQID(scq->cqid));
res->u.sqrq.dcaen_to_eqsize = cpu_to_be32(
V_FW_RI_RES_WR_DCAEN(0) |
@@ -198,14 +255,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
ret = c4iw_ofld_send(rdev, skb);
if (ret)
goto err7;
- wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
- if (!wr_wait.done) {
- printk(KERN_ERR MOD "Device %s not responding!\n",
- pci_name(rdev->lldi.pdev));
- rdev->flags = T4_FATAL_ERROR;
- ret = -EIO;
- } else
- ret = wr_wait.ret;
+ ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, wq->sq.qid, __func__);
if (ret)
goto err7;
@@ -219,9 +269,7 @@ err7:
wq->rq.memsize, wq->rq.queue,
dma_unmap_addr(&wq->rq, mapping));
err6:
- dma_free_coherent(&(rdev->lldi.pdev->dev),
- wq->sq.memsize, wq->sq.queue,
- dma_unmap_addr(&wq->sq, mapping));
+ dealloc_sq(rdev, &wq->sq);
err5:
c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
err4:
@@ -263,6 +311,9 @@ static int build_immd(struct t4_sq *sq, struct fw_ri_immd *immdp,
rem -= len;
}
}
+ len = roundup(plen + sizeof *immdp, 16) - (plen + sizeof *immdp);
+ if (len)
+ memset(dstp, 0, len);
immdp->op = FW_RI_DATA_IMMD;
immdp->r1 = 0;
immdp->r2 = 0;
@@ -292,6 +343,7 @@ static int build_isgl(__be64 *queue_start, __be64 *queue_end,
if (++flitp == queue_end)
flitp = queue_start;
}
+ *flitp = (__force __be64)0;
isglp->op = FW_RI_DATA_ISGL;
isglp->r1 = 0;
isglp->nsge = cpu_to_be16(num_sge);
@@ -453,13 +505,15 @@ static int build_rdma_recv(struct c4iw_qp *qhp, union t4_recv_wr *wqe,
return 0;
}
-static int build_fastreg(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
+static int build_fastreg(struct t4_sq *sq, union t4_wr *wqe,
+ struct ib_send_wr *wr, u8 *len16)
{
struct fw_ri_immd *imdp;
__be64 *p;
int i;
int pbllen = roundup(wr->wr.fast_reg.page_list_len * sizeof(u64), 32);
+ int rem;
if (wr->wr.fast_reg.page_list_len > T4_MAX_FR_DEPTH)
return -EINVAL;
@@ -474,32 +528,28 @@ static int build_fastreg(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
wqe->fr.va_hi = cpu_to_be32(wr->wr.fast_reg.iova_start >> 32);
wqe->fr.va_lo_fbo = cpu_to_be32(wr->wr.fast_reg.iova_start &
0xffffffff);
- if (pbllen > T4_MAX_FR_IMMD) {
- struct c4iw_fr_page_list *c4pl =
- to_c4iw_fr_page_list(wr->wr.fast_reg.page_list);
- struct fw_ri_dsgl *sglp;
-
- sglp = (struct fw_ri_dsgl *)(&wqe->fr + 1);
- sglp->op = FW_RI_DATA_DSGL;
- sglp->r1 = 0;
- sglp->nsge = cpu_to_be16(1);
- sglp->addr0 = cpu_to_be64(c4pl->dma_addr);
- sglp->len0 = cpu_to_be32(pbllen);
-
- *len16 = DIV_ROUND_UP(sizeof wqe->fr + sizeof *sglp, 16);
- } else {
- imdp = (struct fw_ri_immd *)(&wqe->fr + 1);
- imdp->op = FW_RI_DATA_IMMD;
- imdp->r1 = 0;
- imdp->r2 = 0;
- imdp->immdlen = cpu_to_be32(pbllen);
- p = (__be64 *)(imdp + 1);
- for (i = 0; i < wr->wr.fast_reg.page_list_len; i++, p++)
- *p = cpu_to_be64(
- (u64)wr->wr.fast_reg.page_list->page_list[i]);
- *len16 = DIV_ROUND_UP(sizeof wqe->fr + sizeof *imdp + pbllen,
- 16);
+ WARN_ON(pbllen > T4_MAX_FR_IMMD);
+ imdp = (struct fw_ri_immd *)(&wqe->fr + 1);
+ imdp->op = FW_RI_DATA_IMMD;
+ imdp->r1 = 0;
+ imdp->r2 = 0;
+ imdp->immdlen = cpu_to_be32(pbllen);
+ p = (__be64 *)(imdp + 1);
+ rem = pbllen;
+ for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) {
+ *p = cpu_to_be64((u64)wr->wr.fast_reg.page_list->page_list[i]);
+ rem -= sizeof *p;
+ if (++p == (__be64 *)&sq->queue[sq->size])
+ p = (__be64 *)sq->queue;
}
+ BUG_ON(rem < 0);
+ while (rem) {
+ *p = 0;
+ rem -= sizeof *p;
+ if (++p == (__be64 *)&sq->queue[sq->size])
+ p = (__be64 *)sq->queue;
+ }
+ *len16 = DIV_ROUND_UP(sizeof wqe->fr + sizeof *imdp + pbllen, 16);
return 0;
}
@@ -587,7 +637,7 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
fw_opcode = FW_RI_RDMA_READ_WR;
swsqe->opcode = FW_RI_READ_REQ;
if (wr->opcode == IB_WR_RDMA_READ_WITH_INV)
- fw_flags |= FW_RI_RDMA_READ_INVALIDATE;
+ fw_flags = FW_RI_RDMA_READ_INVALIDATE;
else
fw_flags = 0;
err = build_rdma_read(wqe, wr, &len16);
@@ -600,7 +650,7 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
case IB_WR_FAST_REG_MR:
fw_opcode = FW_RI_FR_NSMR_WR;
swsqe->opcode = FW_RI_FAST_REGISTER;
- err = build_fastreg(wqe, wr, &len16);
+ err = build_fastreg(&qhp->wq.sq, wqe, wr, &len16);
break;
case IB_WR_LOCAL_INV:
if (wr->send_flags & IB_SEND_FENCE)
@@ -905,46 +955,38 @@ static void post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe,
* Assumes qhp lock is held.
*/
static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
- struct c4iw_cq *schp, unsigned long *flag)
+ struct c4iw_cq *schp)
{
int count;
int flushed;
+ unsigned long flag;
PDBG("%s qhp %p rchp %p schp %p\n", __func__, qhp, rchp, schp);
- /* take a ref on the qhp since we must release the lock */
- atomic_inc(&qhp->refcnt);
- spin_unlock_irqrestore(&qhp->lock, *flag);
/* locking hierarchy: cq lock first, then qp lock. */
- spin_lock_irqsave(&rchp->lock, *flag);
+ spin_lock_irqsave(&rchp->lock, flag);
spin_lock(&qhp->lock);
c4iw_flush_hw_cq(&rchp->cq);
c4iw_count_rcqes(&rchp->cq, &qhp->wq, &count);
flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count);
spin_unlock(&qhp->lock);
- spin_unlock_irqrestore(&rchp->lock, *flag);
+ spin_unlock_irqrestore(&rchp->lock, flag);
if (flushed)
(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
/* locking hierarchy: cq lock first, then qp lock. */
- spin_lock_irqsave(&schp->lock, *flag);
+ spin_lock_irqsave(&schp->lock, flag);
spin_lock(&qhp->lock);
c4iw_flush_hw_cq(&schp->cq);
c4iw_count_scqes(&schp->cq, &qhp->wq, &count);
flushed = c4iw_flush_sq(&qhp->wq, &schp->cq, count);
spin_unlock(&qhp->lock);
- spin_unlock_irqrestore(&schp->lock, *flag);
+ spin_unlock_irqrestore(&schp->lock, flag);
if (flushed)
(*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
-
- /* deref */
- if (atomic_dec_and_test(&qhp->refcnt))
- wake_up(&qhp->wait);
-
- spin_lock_irqsave(&qhp->lock, *flag);
}
-static void flush_qp(struct c4iw_qp *qhp, unsigned long *flag)
+static void flush_qp(struct c4iw_qp *qhp)
{
struct c4iw_cq *rchp, *schp;
@@ -958,7 +1000,7 @@ static void flush_qp(struct c4iw_qp *qhp, unsigned long *flag)
t4_set_cq_in_error(&schp->cq);
return;
}
- __flush_qp(qhp, rchp, schp, flag);
+ __flush_qp(qhp, rchp, schp);
}
static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
@@ -966,7 +1008,6 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
{
struct fw_ri_wr *wqe;
int ret;
- struct c4iw_wr_wait wr_wait;
struct sk_buff *skb;
PDBG("%s qhp %p qid 0x%x tid %u\n", __func__, qhp, qhp->wq.sq.qid,
@@ -985,28 +1026,16 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
wqe->flowid_len16 = cpu_to_be32(
FW_WR_FLOWID(ep->hwtid) |
FW_WR_LEN16(DIV_ROUND_UP(sizeof *wqe, 16)));
- wqe->cookie = (u64)&wr_wait;
+ wqe->cookie = (unsigned long) &ep->com.wr_wait;
wqe->u.fini.type = FW_RI_TYPE_FINI;
- c4iw_init_wr_wait(&wr_wait);
+ c4iw_init_wr_wait(&ep->com.wr_wait);
ret = c4iw_ofld_send(&rhp->rdev, skb);
if (ret)
goto out;
- wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
- if (!wr_wait.done) {
- printk(KERN_ERR MOD "Device %s not responding!\n",
- pci_name(rhp->rdev.lldi.pdev));
- rhp->rdev.flags = T4_FATAL_ERROR;
- ret = -EIO;
- } else {
- ret = wr_wait.ret;
- if (ret)
- printk(KERN_WARNING MOD
- "%s: Abnormal close qpid %d ret %u\n",
- pci_name(rhp->rdev.lldi.pdev), qhp->wq.sq.qid,
- ret);
- }
+ ret = c4iw_wait_for_reply(&rhp->rdev, &ep->com.wr_wait, qhp->ep->hwtid,
+ qhp->wq.sq.qid, __func__);
out:
PDBG("%s ret %d\n", __func__, ret);
return ret;
@@ -1040,7 +1069,6 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
{
struct fw_ri_wr *wqe;
int ret;
- struct c4iw_wr_wait wr_wait;
struct sk_buff *skb;
PDBG("%s qhp %p qid 0x%x tid %u\n", __func__, qhp, qhp->wq.sq.qid,
@@ -1060,7 +1088,7 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
FW_WR_FLOWID(qhp->ep->hwtid) |
FW_WR_LEN16(DIV_ROUND_UP(sizeof *wqe, 16)));
- wqe->cookie = (u64)&wr_wait;
+ wqe->cookie = (unsigned long) &qhp->ep->com.wr_wait;
wqe->u.init.type = FW_RI_TYPE_INIT;
wqe->u.init.mpareqbit_p2ptype =
@@ -1097,19 +1125,13 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
if (qhp->attr.mpa_attr.initiator)
build_rtr_msg(qhp->attr.mpa_attr.p2p_type, &wqe->u.init);
- c4iw_init_wr_wait(&wr_wait);
+ c4iw_init_wr_wait(&qhp->ep->com.wr_wait);
ret = c4iw_ofld_send(&rhp->rdev, skb);
if (ret)
goto out;
- wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
- if (!wr_wait.done) {
- printk(KERN_ERR MOD "Device %s not responding!\n",
- pci_name(rhp->rdev.lldi.pdev));
- rhp->rdev.flags = T4_FATAL_ERROR;
- ret = -EIO;
- } else
- ret = wr_wait.ret;
+ ret = c4iw_wait_for_reply(&rhp->rdev, &qhp->ep->com.wr_wait,
+ qhp->ep->hwtid, qhp->wq.sq.qid, __func__);
out:
PDBG("%s ret %d\n", __func__, ret);
return ret;
@@ -1122,7 +1144,6 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
{
int ret = 0;
struct c4iw_qp_attributes newattr = qhp->attr;
- unsigned long flag;
int disconnect = 0;
int terminate = 0;
int abort = 0;
@@ -1133,7 +1154,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
qhp, qhp->wq.sq.qid, qhp->wq.rq.qid, qhp->ep, qhp->attr.state,
(mask & C4IW_QP_ATTR_NEXT_STATE) ? attrs->next_state : -1);
- spin_lock_irqsave(&qhp->lock, flag);
+ mutex_lock(&qhp->mutex);
/* Process attr changes if in IDLE */
if (mask & C4IW_QP_ATTR_VALID_MODIFY) {
@@ -1184,7 +1205,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
qhp->attr.mpa_attr = attrs->mpa_attr;
qhp->attr.llp_stream_handle = attrs->llp_stream_handle;
qhp->ep = qhp->attr.llp_stream_handle;
- qhp->attr.state = C4IW_QP_STATE_RTS;
+ set_state(qhp, C4IW_QP_STATE_RTS);
/*
* Ref the endpoint here and deref when we
@@ -1193,15 +1214,13 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
* transition.
*/
c4iw_get_ep(&qhp->ep->com);
- spin_unlock_irqrestore(&qhp->lock, flag);
ret = rdma_init(rhp, qhp);
- spin_lock_irqsave(&qhp->lock, flag);
if (ret)
goto err;
break;
case C4IW_QP_STATE_ERROR:
- qhp->attr.state = C4IW_QP_STATE_ERROR;
- flush_qp(qhp, &flag);
+ set_state(qhp, C4IW_QP_STATE_ERROR);
+ flush_qp(qhp);
break;
default:
ret = -EINVAL;
@@ -1212,38 +1231,38 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
switch (attrs->next_state) {
case C4IW_QP_STATE_CLOSING:
BUG_ON(atomic_read(&qhp->ep->com.kref.refcount) < 2);
- qhp->attr.state = C4IW_QP_STATE_CLOSING;
+ set_state(qhp, C4IW_QP_STATE_CLOSING);
ep = qhp->ep;
if (!internal) {
abort = 0;
disconnect = 1;
- c4iw_get_ep(&ep->com);
+ c4iw_get_ep(&qhp->ep->com);
}
- spin_unlock_irqrestore(&qhp->lock, flag);
ret = rdma_fini(rhp, qhp, ep);
- spin_lock_irqsave(&qhp->lock, flag);
if (ret) {
- c4iw_get_ep(&ep->com);
+ if (internal)
+ c4iw_get_ep(&qhp->ep->com);
disconnect = abort = 1;
goto err;
}
break;
case C4IW_QP_STATE_TERMINATE:
- qhp->attr.state = C4IW_QP_STATE_TERMINATE;
+ set_state(qhp, C4IW_QP_STATE_TERMINATE);
if (qhp->ibqp.uobject)
t4_set_wq_in_error(&qhp->wq);
ep = qhp->ep;
- c4iw_get_ep(&ep->com);
- terminate = 1;
+ if (!internal)
+ terminate = 1;
disconnect = 1;
+ c4iw_get_ep(&qhp->ep->com);
break;
case C4IW_QP_STATE_ERROR:
- qhp->attr.state = C4IW_QP_STATE_ERROR;
+ set_state(qhp, C4IW_QP_STATE_ERROR);
if (!internal) {
abort = 1;
disconnect = 1;
ep = qhp->ep;
- c4iw_get_ep(&ep->com);
+ c4iw_get_ep(&qhp->ep->com);
}
goto err;
break;
@@ -1259,8 +1278,8 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
}
switch (attrs->next_state) {
case C4IW_QP_STATE_IDLE:
- flush_qp(qhp, &flag);
- qhp->attr.state = C4IW_QP_STATE_IDLE;
+ flush_qp(qhp);
+ set_state(qhp, C4IW_QP_STATE_IDLE);
qhp->attr.llp_stream_handle = NULL;
c4iw_put_ep(&qhp->ep->com);
qhp->ep = NULL;
@@ -1282,7 +1301,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
ret = -EINVAL;
goto out;
}
- qhp->attr.state = C4IW_QP_STATE_IDLE;
+ set_state(qhp, C4IW_QP_STATE_IDLE);
break;
case C4IW_QP_STATE_TERMINATE:
if (!internal) {
@@ -1305,15 +1324,16 @@ err:
/* disassociate the LLP connection */
qhp->attr.llp_stream_handle = NULL;
- ep = qhp->ep;
+ if (!ep)
+ ep = qhp->ep;
qhp->ep = NULL;
- qhp->attr.state = C4IW_QP_STATE_ERROR;
+ set_state(qhp, C4IW_QP_STATE_ERROR);
free = 1;
wake_up(&qhp->wait);
BUG_ON(!ep);
- flush_qp(qhp, &flag);
+ flush_qp(qhp);
out:
- spin_unlock_irqrestore(&qhp->lock, flag);
+ mutex_unlock(&qhp->mutex);
if (terminate)
post_terminate(qhp, NULL, internal ? GFP_ATOMIC : GFP_KERNEL);
@@ -1335,7 +1355,6 @@ out:
*/
if (free)
c4iw_put_ep(&ep->com);
-
PDBG("%s exit state %d\n", __func__, qhp->attr.state);
return ret;
}
@@ -1380,7 +1399,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
int sqsize, rqsize;
struct c4iw_ucontext *ucontext;
int ret;
- struct c4iw_mm_entry *mm1, *mm2, *mm3, *mm4;
+ struct c4iw_mm_entry *mm1, *mm2, *mm3, *mm4, *mm5 = NULL;
PDBG("%s ib_pd %p\n", __func__, pd);
@@ -1450,6 +1469,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
qhp->attr.max_ord = 1;
qhp->attr.max_ird = 1;
spin_lock_init(&qhp->lock);
+ mutex_init(&qhp->mutex);
init_waitqueue_head(&qhp->wait);
atomic_set(&qhp->refcnt, 1);
@@ -1478,7 +1498,15 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
ret = -ENOMEM;
goto err6;
}
-
+ if (t4_sq_onchip(&qhp->wq.sq)) {
+ mm5 = kmalloc(sizeof *mm5, GFP_KERNEL);
+ if (!mm5) {
+ ret = -ENOMEM;
+ goto err7;
+ }
+ uresp.flags = C4IW_QPF_ONCHIP;
+ } else
+ uresp.flags = 0;
uresp.qid_mask = rhp->rdev.qpmask;
uresp.sqid = qhp->wq.sq.qid;
uresp.sq_size = qhp->wq.sq.size;
@@ -1487,6 +1515,10 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
uresp.rq_size = qhp->wq.rq.size;
uresp.rq_memsize = qhp->wq.rq.memsize;
spin_lock(&ucontext->mmap_lock);
+ if (mm5) {
+ uresp.ma_sync_key = ucontext->key;
+ ucontext->key += PAGE_SIZE;
+ }
uresp.sq_key = ucontext->key;
ucontext->key += PAGE_SIZE;
uresp.rq_key = ucontext->key;
@@ -1498,9 +1530,9 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
spin_unlock(&ucontext->mmap_lock);
ret = ib_copy_to_udata(udata, &uresp, sizeof uresp);
if (ret)
- goto err7;
+ goto err8;
mm1->key = uresp.sq_key;
- mm1->addr = virt_to_phys(qhp->wq.sq.queue);
+ mm1->addr = qhp->wq.sq.phys_addr;
mm1->len = PAGE_ALIGN(qhp->wq.sq.memsize);
insert_mmap(ucontext, mm1);
mm2->key = uresp.rq_key;
@@ -1515,6 +1547,13 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
mm4->addr = qhp->wq.rq.udb;
mm4->len = PAGE_SIZE;
insert_mmap(ucontext, mm4);
+ if (mm5) {
+ mm5->key = uresp.ma_sync_key;
+ mm5->addr = (pci_resource_start(rhp->rdev.lldi.pdev, 0)
+ + A_PCIE_MA_SYNC) & PAGE_MASK;
+ mm5->len = PAGE_SIZE;
+ insert_mmap(ucontext, mm5);
+ }
}
qhp->ibqp.qp_num = qhp->wq.sq.qid;
init_timer(&(qhp->timer));
@@ -1522,6 +1561,8 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
__func__, qhp, qhp->attr.sq_num_entries, qhp->attr.rq_num_entries,
qhp->wq.sq.qid);
return &qhp->ibqp;
+err8:
+ kfree(mm5);
err7:
kfree(mm4);
err6:
diff --git a/drivers/infiniband/hw/cxgb4/resource.c b/drivers/infiniband/hw/cxgb4/resource.c
index 83b23dfa250d..4fb50d58b493 100644
--- a/drivers/infiniband/hw/cxgb4/resource.c
+++ b/drivers/infiniband/hw/cxgb4/resource.c
@@ -311,6 +311,9 @@ u32 c4iw_pblpool_alloc(struct c4iw_rdev *rdev, int size)
{
unsigned long addr = gen_pool_alloc(rdev->pbl_pool, size);
PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size);
+ if (!addr && printk_ratelimit())
+ printk(KERN_WARNING MOD "%s: Out of PBL memory\n",
+ pci_name(rdev->lldi.pdev));
return (u32)addr;
}
@@ -370,6 +373,9 @@ u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size)
{
unsigned long addr = gen_pool_alloc(rdev->rqt_pool, size << 6);
PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size << 6);
+ if (!addr && printk_ratelimit())
+ printk(KERN_WARNING MOD "%s: Out of RQT memory\n",
+ pci_name(rdev->lldi.pdev));
return (u32)addr;
}
@@ -416,3 +422,59 @@ void c4iw_rqtpool_destroy(struct c4iw_rdev *rdev)
{
gen_pool_destroy(rdev->rqt_pool);
}
+
+/*
+ * On-Chip QP Memory.
+ */
+#define MIN_OCQP_SHIFT 12 /* 4KB == min ocqp size */
+
+u32 c4iw_ocqp_pool_alloc(struct c4iw_rdev *rdev, int size)
+{
+ unsigned long addr = gen_pool_alloc(rdev->ocqp_pool, size);
+ PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size);
+ return (u32)addr;
+}
+
+void c4iw_ocqp_pool_free(struct c4iw_rdev *rdev, u32 addr, int size)
+{
+ PDBG("%s addr 0x%x size %d\n", __func__, addr, size);
+ gen_pool_free(rdev->ocqp_pool, (unsigned long)addr, size);
+}
+
+int c4iw_ocqp_pool_create(struct c4iw_rdev *rdev)
+{
+ unsigned start, chunk, top;
+
+ rdev->ocqp_pool = gen_pool_create(MIN_OCQP_SHIFT, -1);
+ if (!rdev->ocqp_pool)
+ return -ENOMEM;
+
+ start = rdev->lldi.vr->ocq.start;
+ chunk = rdev->lldi.vr->ocq.size;
+ top = start + chunk;
+
+ while (start < top) {
+ chunk = min(top - start + 1, chunk);
+ if (gen_pool_add(rdev->ocqp_pool, start, chunk, -1)) {
+ PDBG("%s failed to add OCQP chunk (%x/%x)\n",
+ __func__, start, chunk);
+ if (chunk <= 1024 << MIN_OCQP_SHIFT) {
+ printk(KERN_WARNING MOD
+ "Failed to add all OCQP chunks (%x/%x)\n",
+ start, top - start);
+ return 0;
+ }
+ chunk >>= 1;
+ } else {
+ PDBG("%s added OCQP chunk (%x/%x)\n",
+ __func__, start, chunk);
+ start += chunk;
+ }
+ }
+ return 0;
+}
+
+void c4iw_ocqp_pool_destroy(struct c4iw_rdev *rdev)
+{
+ gen_pool_destroy(rdev->ocqp_pool);
+}
diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h
index 24f369046ef3..70004425d695 100644
--- a/drivers/infiniband/hw/cxgb4/t4.h
+++ b/drivers/infiniband/hw/cxgb4/t4.h
@@ -52,6 +52,7 @@
#define T4_STAG_UNSET 0xffffffff
#define T4_FW_MAJ 0
#define T4_EQ_STATUS_ENTRIES (L1_CACHE_BYTES > 64 ? 2 : 1)
+#define A_PCIE_MA_SYNC 0x30b4
struct t4_status_page {
__be32 rsvd1; /* flit 0 - hw owns */
@@ -65,7 +66,7 @@ struct t4_status_page {
#define T4_EQ_ENTRY_SIZE 64
-#define T4_SQ_NUM_SLOTS 4
+#define T4_SQ_NUM_SLOTS 5
#define T4_SQ_NUM_BYTES (T4_EQ_ENTRY_SIZE * T4_SQ_NUM_SLOTS)
#define T4_MAX_SEND_SGE ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_send_wr) - \
sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge))
@@ -78,7 +79,7 @@ struct t4_status_page {
sizeof(struct fw_ri_rdma_write_wr) - \
sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge))
#define T4_MAX_FR_IMMD ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_fr_nsmr_wr) - \
- sizeof(struct fw_ri_immd)))
+ sizeof(struct fw_ri_immd)) & ~31UL)
#define T4_MAX_FR_DEPTH (T4_MAX_FR_IMMD / sizeof(u64))
#define T4_RQ_NUM_SLOTS 2
@@ -266,10 +267,36 @@ struct t4_swsqe {
u16 idx;
};
+static inline pgprot_t t4_pgprot_wc(pgprot_t prot)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ return pgprot_writecombine(prot);
+#elif defined(CONFIG_PPC64)
+ return __pgprot((pgprot_val(prot) | _PAGE_NO_CACHE) &
+ ~(pgprot_t)_PAGE_GUARDED);
+#else
+ return pgprot_noncached(prot);
+#endif
+}
+
+static inline int t4_ocqp_supported(void)
+{
+#if defined(__i386__) || defined(__x86_64__) || defined(CONFIG_PPC64)
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+enum {
+ T4_SQ_ONCHIP = (1<<0),
+};
+
struct t4_sq {
union t4_wr *queue;
dma_addr_t dma_addr;
DEFINE_DMA_UNMAP_ADDR(mapping);
+ unsigned long phys_addr;
struct t4_swsqe *sw_sq;
struct t4_swsqe *oldest_read;
u64 udb;
@@ -280,6 +307,7 @@ struct t4_sq {
u16 cidx;
u16 pidx;
u16 wq_pidx;
+ u16 flags;
};
struct t4_swrqe {
@@ -350,6 +378,11 @@ static inline void t4_rq_consume(struct t4_wq *wq)
wq->rq.cidx = 0;
}
+static inline int t4_sq_onchip(struct t4_sq *sq)
+{
+ return sq->flags & T4_SQ_ONCHIP;
+}
+
static inline int t4_sq_empty(struct t4_wq *wq)
{
return wq->sq.in_use == 0;
@@ -396,30 +429,27 @@ static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc)
static inline int t4_wq_in_error(struct t4_wq *wq)
{
- return wq->sq.queue[wq->sq.size].status.qp_err;
+ return wq->rq.queue[wq->rq.size].status.qp_err;
}
static inline void t4_set_wq_in_error(struct t4_wq *wq)
{
- wq->sq.queue[wq->sq.size].status.qp_err = 1;
wq->rq.queue[wq->rq.size].status.qp_err = 1;
}
static inline void t4_disable_wq_db(struct t4_wq *wq)
{
- wq->sq.queue[wq->sq.size].status.db_off = 1;
wq->rq.queue[wq->rq.size].status.db_off = 1;
}
static inline void t4_enable_wq_db(struct t4_wq *wq)
{
- wq->sq.queue[wq->sq.size].status.db_off = 0;
wq->rq.queue[wq->rq.size].status.db_off = 0;
}
static inline int t4_wq_db_enabled(struct t4_wq *wq)
{
- return !wq->sq.queue[wq->sq.size].status.db_off;
+ return !wq->rq.queue[wq->rq.size].status.db_off;
}
struct t4_cq {
diff --git a/drivers/infiniband/hw/cxgb4/user.h b/drivers/infiniband/hw/cxgb4/user.h
index ed6414abde02..e6669d54770e 100644
--- a/drivers/infiniband/hw/cxgb4/user.h
+++ b/drivers/infiniband/hw/cxgb4/user.h
@@ -50,7 +50,13 @@ struct c4iw_create_cq_resp {
__u32 qid_mask;
};
+
+enum {
+ C4IW_QPF_ONCHIP = (1<<0)
+};
+
struct c4iw_create_qp_resp {
+ __u64 ma_sync_key;
__u64 sq_key;
__u64 rq_key;
__u64 sq_db_gts_key;
@@ -62,5 +68,6 @@ struct c4iw_create_qp_resp {
__u32 sq_size;
__u32 rq_size;
__u32 qid_mask;
+ __u32 flags;
};
#endif
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c
index 53f4cd4fc19a..43cae84005f0 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.c
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c
@@ -171,7 +171,7 @@ struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
}
ret = ehca_reg_maxmr(shca, e_maxmr,
- (void *)ehca_map_vaddr((void *)KERNELBASE),
+ (void *)ehca_map_vaddr((void *)(KERNELBASE + PHYSICAL_START)),
mr_access_flags, e_pd,
&e_maxmr->ib.ib_mr.lkey,
&e_maxmr->ib.ib_mr.rkey);
@@ -1636,7 +1636,7 @@ int ehca_reg_internal_maxmr(
/* register internal max-MR on HCA */
size_maxmr = ehca_mr_len;
- iova_start = (u64 *)ehca_map_vaddr((void *)KERNELBASE);
+ iova_start = (u64 *)ehca_map_vaddr((void *)(KERNELBASE + PHYSICAL_START));
ib_pbuf.addr = 0;
ib_pbuf.size = size_maxmr;
num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size_maxmr,
@@ -2209,7 +2209,7 @@ int ehca_mr_is_maxmr(u64 size,
{
/* a MR is treated as max-MR only if it fits following: */
if ((size == ehca_mr_len) &&
- (iova_start == (void *)ehca_map_vaddr((void *)KERNELBASE))) {
+ (iova_start == (void *)ehca_map_vaddr((void *)(KERNELBASE + PHYSICAL_START)))) {
ehca_gen_dbg("this is a max-MR");
return 1;
} else
diff --git a/drivers/infiniband/hw/ipath/Makefile b/drivers/infiniband/hw/ipath/Makefile
index fa3df82681df..4496f2820c92 100644
--- a/drivers/infiniband/hw/ipath/Makefile
+++ b/drivers/infiniband/hw/ipath/Makefile
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS += -DIPATH_IDSTR='"QLogic kernel.org driver"' \
+ccflags-y := -DIPATH_IDSTR='"QLogic kernel.org driver"' \
-DIPATH_KERN_TYPE=0
obj-$(CONFIG_INFINIBAND_IPATH) += ib_ipath.o
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index d13e72685dcf..12d5bf76302c 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -57,6 +57,7 @@ static int ipathfs_mknod(struct inode *dir, struct dentry *dentry,
goto bail;
}
+ inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_private = data;
diff --git a/drivers/infiniband/hw/mlx4/Kconfig b/drivers/infiniband/hw/mlx4/Kconfig
index 4175a4bd0c78..bd995b2b50d8 100644
--- a/drivers/infiniband/hw/mlx4/Kconfig
+++ b/drivers/infiniband/hw/mlx4/Kconfig
@@ -1,5 +1,6 @@
config MLX4_INFINIBAND
tristate "Mellanox ConnectX HCA support"
+ depends on NETDEVICES && NETDEV_10000 && PCI
select MLX4_CORE
---help---
This driver provides low-level InfiniBand support for
diff --git a/drivers/infiniband/hw/mlx4/ah.c b/drivers/infiniband/hw/mlx4/ah.c
index 11a236f8d884..4b8f9c49397e 100644
--- a/drivers/infiniband/hw/mlx4/ah.c
+++ b/drivers/infiniband/hw/mlx4/ah.c
@@ -30,66 +30,163 @@
* SOFTWARE.
*/
+#include <rdma/ib_addr.h>
+#include <rdma/ib_cache.h>
+
#include <linux/slab.h>
+#include <linux/inet.h>
+#include <linux/string.h>
#include "mlx4_ib.h"
-struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+int mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr,
+ u8 *mac, int *is_mcast, u8 port)
{
- struct mlx4_dev *dev = to_mdev(pd->device)->dev;
- struct mlx4_ib_ah *ah;
+ struct in6_addr in6;
- ah = kmalloc(sizeof *ah, GFP_ATOMIC);
- if (!ah)
- return ERR_PTR(-ENOMEM);
+ *is_mcast = 0;
- memset(&ah->av, 0, sizeof ah->av);
+ memcpy(&in6, ah_attr->grh.dgid.raw, sizeof in6);
+ if (rdma_link_local_addr(&in6))
+ rdma_get_ll_mac(&in6, mac);
+ else if (rdma_is_multicast_addr(&in6)) {
+ rdma_get_mcast_mac(&in6, mac);
+ *is_mcast = 1;
+ } else
+ return -EINVAL;
- ah->av.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
- ah->av.g_slid = ah_attr->src_path_bits;
- ah->av.dlid = cpu_to_be16(ah_attr->dlid);
- if (ah_attr->static_rate) {
- ah->av.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET;
- while (ah->av.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
- !(1 << ah->av.stat_rate & dev->caps.stat_rate_support))
- --ah->av.stat_rate;
- }
- ah->av.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
+ return 0;
+}
+
+static struct ib_ah *create_ib_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr,
+ struct mlx4_ib_ah *ah)
+{
+ struct mlx4_dev *dev = to_mdev(pd->device)->dev;
+
+ ah->av.ib.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
+ ah->av.ib.g_slid = ah_attr->src_path_bits;
if (ah_attr->ah_flags & IB_AH_GRH) {
- ah->av.g_slid |= 0x80;
- ah->av.gid_index = ah_attr->grh.sgid_index;
- ah->av.hop_limit = ah_attr->grh.hop_limit;
- ah->av.sl_tclass_flowlabel |=
+ ah->av.ib.g_slid |= 0x80;
+ ah->av.ib.gid_index = ah_attr->grh.sgid_index;
+ ah->av.ib.hop_limit = ah_attr->grh.hop_limit;
+ ah->av.ib.sl_tclass_flowlabel |=
cpu_to_be32((ah_attr->grh.traffic_class << 20) |
ah_attr->grh.flow_label);
- memcpy(ah->av.dgid, ah_attr->grh.dgid.raw, 16);
+ memcpy(ah->av.ib.dgid, ah_attr->grh.dgid.raw, 16);
+ }
+
+ ah->av.ib.dlid = cpu_to_be16(ah_attr->dlid);
+ if (ah_attr->static_rate) {
+ ah->av.ib.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET;
+ while (ah->av.ib.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
+ !(1 << ah->av.ib.stat_rate & dev->caps.stat_rate_support))
+ --ah->av.ib.stat_rate;
}
+ ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
return &ah->ibah;
}
+static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr,
+ struct mlx4_ib_ah *ah)
+{
+ struct mlx4_ib_dev *ibdev = to_mdev(pd->device);
+ struct mlx4_dev *dev = ibdev->dev;
+ union ib_gid sgid;
+ u8 mac[6];
+ int err;
+ int is_mcast;
+ u16 vlan_tag;
+
+ err = mlx4_ib_resolve_grh(ibdev, ah_attr, mac, &is_mcast, ah_attr->port_num);
+ if (err)
+ return ERR_PTR(err);
+
+ memcpy(ah->av.eth.mac, mac, 6);
+ err = ib_get_cached_gid(pd->device, ah_attr->port_num, ah_attr->grh.sgid_index, &sgid);
+ if (err)
+ return ERR_PTR(err);
+ vlan_tag = rdma_get_vlan_id(&sgid);
+ if (vlan_tag < 0x1000)
+ vlan_tag |= (ah_attr->sl & 7) << 13;
+ ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
+ ah->av.eth.gid_index = ah_attr->grh.sgid_index;
+ ah->av.eth.vlan = cpu_to_be16(vlan_tag);
+ if (ah_attr->static_rate) {
+ ah->av.eth.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET;
+ while (ah->av.eth.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
+ !(1 << ah->av.eth.stat_rate & dev->caps.stat_rate_support))
+ --ah->av.eth.stat_rate;
+ }
+
+ /*
+ * HW requires multicast LID so we just choose one.
+ */
+ if (is_mcast)
+ ah->av.ib.dlid = cpu_to_be16(0xc000);
+
+ memcpy(ah->av.eth.dgid, ah_attr->grh.dgid.raw, 16);
+ ah->av.eth.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
+
+ return &ah->ibah;
+}
+
+struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+{
+ struct mlx4_ib_ah *ah;
+ struct ib_ah *ret;
+
+ ah = kzalloc(sizeof *ah, GFP_ATOMIC);
+ if (!ah)
+ return ERR_PTR(-ENOMEM);
+
+ if (rdma_port_get_link_layer(pd->device, ah_attr->port_num) == IB_LINK_LAYER_ETHERNET) {
+ if (!(ah_attr->ah_flags & IB_AH_GRH)) {
+ ret = ERR_PTR(-EINVAL);
+ } else {
+ /*
+ * TBD: need to handle the case when we get
+ * called in an atomic context and there we
+ * might sleep. We don't expect this
+ * currently since we're working with link
+ * local addresses which we can translate
+ * without going to sleep.
+ */
+ ret = create_iboe_ah(pd, ah_attr, ah);
+ }
+
+ if (IS_ERR(ret))
+ kfree(ah);
+
+ return ret;
+ } else
+ return create_ib_ah(pd, ah_attr, ah); /* never fails */
+}
+
int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr)
{
struct mlx4_ib_ah *ah = to_mah(ibah);
+ enum rdma_link_layer ll;
memset(ah_attr, 0, sizeof *ah_attr);
- ah_attr->dlid = be16_to_cpu(ah->av.dlid);
- ah_attr->sl = be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28;
- ah_attr->port_num = be32_to_cpu(ah->av.port_pd) >> 24;
- if (ah->av.stat_rate)
- ah_attr->static_rate = ah->av.stat_rate - MLX4_STAT_RATE_OFFSET;
- ah_attr->src_path_bits = ah->av.g_slid & 0x7F;
+ ah_attr->sl = be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28;
+ ah_attr->port_num = be32_to_cpu(ah->av.ib.port_pd) >> 24;
+ ll = rdma_port_get_link_layer(ibah->device, ah_attr->port_num);
+ ah_attr->dlid = ll == IB_LINK_LAYER_INFINIBAND ? be16_to_cpu(ah->av.ib.dlid) : 0;
+ if (ah->av.ib.stat_rate)
+ ah_attr->static_rate = ah->av.ib.stat_rate - MLX4_STAT_RATE_OFFSET;
+ ah_attr->src_path_bits = ah->av.ib.g_slid & 0x7F;
if (mlx4_ib_ah_grh_present(ah)) {
ah_attr->ah_flags = IB_AH_GRH;
ah_attr->grh.traffic_class =
- be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 20;
+ be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20;
ah_attr->grh.flow_label =
- be32_to_cpu(ah->av.sl_tclass_flowlabel) & 0xfffff;
- ah_attr->grh.hop_limit = ah->av.hop_limit;
- ah_attr->grh.sgid_index = ah->av.gid_index;
- memcpy(ah_attr->grh.dgid.raw, ah->av.dgid, 16);
+ be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) & 0xfffff;
+ ah_attr->grh.hop_limit = ah->av.ib.hop_limit;
+ ah_attr->grh.sgid_index = ah->av.ib.gid_index;
+ memcpy(ah_attr->grh.dgid.raw, ah->av.ib.dgid, 16);
}
return 0;
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index f38d5b118927..c9a8dd63b9e2 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -311,19 +311,25 @@ int mlx4_ib_mad_init(struct mlx4_ib_dev *dev)
struct ib_mad_agent *agent;
int p, q;
int ret;
+ enum rdma_link_layer ll;
- for (p = 0; p < dev->num_ports; ++p)
+ for (p = 0; p < dev->num_ports; ++p) {
+ ll = rdma_port_get_link_layer(&dev->ib_dev, p + 1);
for (q = 0; q <= 1; ++q) {
- agent = ib_register_mad_agent(&dev->ib_dev, p + 1,
- q ? IB_QPT_GSI : IB_QPT_SMI,
- NULL, 0, send_handler,
- NULL, NULL);
- if (IS_ERR(agent)) {
- ret = PTR_ERR(agent);
- goto err;
- }
- dev->send_agent[p][q] = agent;
+ if (ll == IB_LINK_LAYER_INFINIBAND) {
+ agent = ib_register_mad_agent(&dev->ib_dev, p + 1,
+ q ? IB_QPT_GSI : IB_QPT_SMI,
+ NULL, 0, send_handler,
+ NULL, NULL);
+ if (IS_ERR(agent)) {
+ ret = PTR_ERR(agent);
+ goto err;
+ }
+ dev->send_agent[p][q] = agent;
+ } else
+ dev->send_agent[p][q] = NULL;
}
+ }
return 0;
@@ -344,8 +350,10 @@ void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev)
for (p = 0; p < dev->num_ports; ++p) {
for (q = 0; q <= 1; ++q) {
agent = dev->send_agent[p][q];
- dev->send_agent[p][q] = NULL;
- ib_unregister_mad_agent(agent);
+ if (agent) {
+ dev->send_agent[p][q] = NULL;
+ ib_unregister_mad_agent(agent);
+ }
}
if (dev->sm_ah[p])
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 4e94e360e43b..bf3e20cd0298 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -35,9 +35,14 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_vlan.h>
#include <rdma/ib_smi.h>
#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
#include <linux/mlx4/driver.h>
#include <linux/mlx4/cmd.h>
@@ -58,6 +63,15 @@ static const char mlx4_ib_version[] =
DRV_NAME ": Mellanox ConnectX InfiniBand driver v"
DRV_VERSION " (" DRV_RELDATE ")\n";
+struct update_gid_work {
+ struct work_struct work;
+ union ib_gid gids[128];
+ struct mlx4_ib_dev *dev;
+ int port;
+};
+
+static struct workqueue_struct *wq;
+
static void init_query_mad(struct ib_smp *mad)
{
mad->base_version = 1;
@@ -66,6 +80,8 @@ static void init_query_mad(struct ib_smp *mad)
mad->method = IB_MGMT_METHOD_GET;
}
+static union ib_gid zgid;
+
static int mlx4_ib_query_device(struct ib_device *ibdev,
struct ib_device_attr *props)
{
@@ -135,7 +151,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev,
props->max_srq = dev->dev->caps.num_srqs - dev->dev->caps.reserved_srqs;
props->max_srq_wr = dev->dev->caps.max_srq_wqes - 1;
props->max_srq_sge = dev->dev->caps.max_srq_sge;
- props->max_fast_reg_page_list_len = PAGE_SIZE / sizeof (u64);
+ props->max_fast_reg_page_list_len = MLX4_MAX_FAST_REG_PAGES;
props->local_ca_ack_delay = dev->dev->caps.local_ca_ack_delay;
props->atomic_cap = dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_ATOMIC ?
IB_ATOMIC_HCA : IB_ATOMIC_NONE;
@@ -154,28 +170,19 @@ out:
return err;
}
-static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port,
- struct ib_port_attr *props)
+static enum rdma_link_layer
+mlx4_ib_port_link_layer(struct ib_device *device, u8 port_num)
{
- struct ib_smp *in_mad = NULL;
- struct ib_smp *out_mad = NULL;
- int err = -ENOMEM;
-
- in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL);
- out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
- if (!in_mad || !out_mad)
- goto out;
-
- memset(props, 0, sizeof *props);
-
- init_query_mad(in_mad);
- in_mad->attr_id = IB_SMP_ATTR_PORT_INFO;
- in_mad->attr_mod = cpu_to_be32(port);
+ struct mlx4_dev *dev = to_mdev(device)->dev;
- err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
- if (err)
- goto out;
+ return dev->caps.port_mask & (1 << (port_num - 1)) ?
+ IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET;
+}
+static int ib_link_query_port(struct ib_device *ibdev, u8 port,
+ struct ib_port_attr *props,
+ struct ib_smp *out_mad)
+{
props->lid = be16_to_cpup((__be16 *) (out_mad->data + 16));
props->lmc = out_mad->data[34] & 0x7;
props->sm_lid = be16_to_cpup((__be16 *) (out_mad->data + 18));
@@ -196,6 +203,80 @@ static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port,
props->max_vl_num = out_mad->data[37] >> 4;
props->init_type_reply = out_mad->data[41] >> 4;
+ return 0;
+}
+
+static u8 state_to_phys_state(enum ib_port_state state)
+{
+ return state == IB_PORT_ACTIVE ? 5 : 3;
+}
+
+static int eth_link_query_port(struct ib_device *ibdev, u8 port,
+ struct ib_port_attr *props,
+ struct ib_smp *out_mad)
+{
+ struct mlx4_ib_iboe *iboe = &to_mdev(ibdev)->iboe;
+ struct net_device *ndev;
+ enum ib_mtu tmp;
+
+ props->active_width = IB_WIDTH_4X;
+ props->active_speed = 4;
+ props->port_cap_flags = IB_PORT_CM_SUP;
+ props->gid_tbl_len = to_mdev(ibdev)->dev->caps.gid_table_len[port];
+ props->max_msg_sz = to_mdev(ibdev)->dev->caps.max_msg_sz;
+ props->pkey_tbl_len = 1;
+ props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46));
+ props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48));
+ props->max_mtu = IB_MTU_2048;
+ props->subnet_timeout = 0;
+ props->max_vl_num = out_mad->data[37] >> 4;
+ props->init_type_reply = 0;
+ props->state = IB_PORT_DOWN;
+ props->phys_state = state_to_phys_state(props->state);
+ props->active_mtu = IB_MTU_256;
+ spin_lock(&iboe->lock);
+ ndev = iboe->netdevs[port - 1];
+ if (!ndev)
+ goto out;
+
+ tmp = iboe_get_mtu(ndev->mtu);
+ props->active_mtu = tmp ? min(props->max_mtu, tmp) : IB_MTU_256;
+
+ props->state = netif_running(ndev) && netif_oper_up(ndev) ?
+ IB_PORT_ACTIVE : IB_PORT_DOWN;
+ props->phys_state = state_to_phys_state(props->state);
+
+out:
+ spin_unlock(&iboe->lock);
+ return 0;
+}
+
+static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port,
+ struct ib_port_attr *props)
+{
+ struct ib_smp *in_mad = NULL;
+ struct ib_smp *out_mad = NULL;
+ int err = -ENOMEM;
+
+ in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL);
+ out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
+ if (!in_mad || !out_mad)
+ goto out;
+
+ memset(props, 0, sizeof *props);
+
+ init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_PORT_INFO;
+ in_mad->attr_mod = cpu_to_be32(port);
+
+ err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
+ if (err)
+ goto out;
+
+ err = mlx4_ib_port_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND ?
+ ib_link_query_port(ibdev, port, props, out_mad) :
+ eth_link_query_port(ibdev, port, props, out_mad);
+
out:
kfree(in_mad);
kfree(out_mad);
@@ -203,8 +284,8 @@ out:
return err;
}
-static int mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
- union ib_gid *gid)
+static int __mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
+ union ib_gid *gid)
{
struct ib_smp *in_mad = NULL;
struct ib_smp *out_mad = NULL;
@@ -241,6 +322,25 @@ out:
return err;
}
+static int iboe_query_gid(struct ib_device *ibdev, u8 port, int index,
+ union ib_gid *gid)
+{
+ struct mlx4_ib_dev *dev = to_mdev(ibdev);
+
+ *gid = dev->iboe.gid_table[port - 1][index];
+
+ return 0;
+}
+
+static int mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
+ union ib_gid *gid)
+{
+ if (rdma_port_get_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND)
+ return __mlx4_ib_query_gid(ibdev, port, index, gid);
+ else
+ return iboe_query_gid(ibdev, port, index, gid);
+}
+
static int mlx4_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index,
u16 *pkey)
{
@@ -272,14 +372,32 @@ out:
static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
struct ib_device_modify *props)
{
+ struct mlx4_cmd_mailbox *mailbox;
+
if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
return -EOPNOTSUPP;
- if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
- spin_lock(&to_mdev(ibdev)->sm_lock);
- memcpy(ibdev->node_desc, props->node_desc, 64);
- spin_unlock(&to_mdev(ibdev)->sm_lock);
- }
+ if (!(mask & IB_DEVICE_MODIFY_NODE_DESC))
+ return 0;
+
+ spin_lock(&to_mdev(ibdev)->sm_lock);
+ memcpy(ibdev->node_desc, props->node_desc, 64);
+ spin_unlock(&to_mdev(ibdev)->sm_lock);
+
+ /*
+ * If possible, pass node desc to FW, so it can generate
+ * a 144 trap. If cmd fails, just ignore.
+ */
+ mailbox = mlx4_alloc_cmd_mailbox(to_mdev(ibdev)->dev);
+ if (IS_ERR(mailbox))
+ return 0;
+
+ memset(mailbox->buf, 0, 256);
+ memcpy(mailbox->buf, props->node_desc, 64);
+ mlx4_cmd(to_mdev(ibdev)->dev, mailbox->dma, 1, 0,
+ MLX4_CMD_SET_NODE, MLX4_CMD_TIME_CLASS_A);
+
+ mlx4_free_cmd_mailbox(to_mdev(ibdev)->dev, mailbox);
return 0;
}
@@ -289,6 +407,7 @@ static int mlx4_SET_PORT(struct mlx4_ib_dev *dev, u8 port, int reset_qkey_viols,
{
struct mlx4_cmd_mailbox *mailbox;
int err;
+ u8 is_eth = dev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH;
mailbox = mlx4_alloc_cmd_mailbox(dev->dev);
if (IS_ERR(mailbox))
@@ -304,7 +423,7 @@ static int mlx4_SET_PORT(struct mlx4_ib_dev *dev, u8 port, int reset_qkey_viols,
((__be32 *) mailbox->buf)[1] = cpu_to_be32(cap_mask);
}
- err = mlx4_cmd(dev->dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT,
+ err = mlx4_cmd(dev->dev, mailbox->dma, port, is_eth, MLX4_CMD_SET_PORT,
MLX4_CMD_TIME_CLASS_B);
mlx4_free_cmd_mailbox(dev->dev, mailbox);
@@ -447,18 +566,132 @@ static int mlx4_ib_dealloc_pd(struct ib_pd *pd)
return 0;
}
+static int add_gid_entry(struct ib_qp *ibqp, union ib_gid *gid)
+{
+ struct mlx4_ib_qp *mqp = to_mqp(ibqp);
+ struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
+ struct mlx4_ib_gid_entry *ge;
+
+ ge = kzalloc(sizeof *ge, GFP_KERNEL);
+ if (!ge)
+ return -ENOMEM;
+
+ ge->gid = *gid;
+ if (mlx4_ib_add_mc(mdev, mqp, gid)) {
+ ge->port = mqp->port;
+ ge->added = 1;
+ }
+
+ mutex_lock(&mqp->mutex);
+ list_add_tail(&ge->list, &mqp->gid_list);
+ mutex_unlock(&mqp->mutex);
+
+ return 0;
+}
+
+int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
+ union ib_gid *gid)
+{
+ u8 mac[6];
+ struct net_device *ndev;
+ int ret = 0;
+
+ if (!mqp->port)
+ return 0;
+
+ spin_lock(&mdev->iboe.lock);
+ ndev = mdev->iboe.netdevs[mqp->port - 1];
+ if (ndev)
+ dev_hold(ndev);
+ spin_unlock(&mdev->iboe.lock);
+
+ if (ndev) {
+ rdma_get_mcast_mac((struct in6_addr *)gid, mac);
+ rtnl_lock();
+ dev_mc_add(mdev->iboe.netdevs[mqp->port - 1], mac);
+ ret = 1;
+ rtnl_unlock();
+ dev_put(ndev);
+ }
+
+ return ret;
+}
+
static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
{
- return mlx4_multicast_attach(to_mdev(ibqp->device)->dev,
- &to_mqp(ibqp)->mqp, gid->raw,
- !!(to_mqp(ibqp)->flags &
- MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK));
+ int err;
+ struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
+ struct mlx4_ib_qp *mqp = to_mqp(ibqp);
+
+ err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, !!(mqp->flags &
+ MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK));
+ if (err)
+ return err;
+
+ err = add_gid_entry(ibqp, gid);
+ if (err)
+ goto err_add;
+
+ return 0;
+
+err_add:
+ mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw);
+ return err;
+}
+
+static struct mlx4_ib_gid_entry *find_gid_entry(struct mlx4_ib_qp *qp, u8 *raw)
+{
+ struct mlx4_ib_gid_entry *ge;
+ struct mlx4_ib_gid_entry *tmp;
+ struct mlx4_ib_gid_entry *ret = NULL;
+
+ list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) {
+ if (!memcmp(raw, ge->gid.raw, 16)) {
+ ret = ge;
+ break;
+ }
+ }
+
+ return ret;
}
static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
{
- return mlx4_multicast_detach(to_mdev(ibqp->device)->dev,
- &to_mqp(ibqp)->mqp, gid->raw);
+ int err;
+ struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
+ struct mlx4_ib_qp *mqp = to_mqp(ibqp);
+ u8 mac[6];
+ struct net_device *ndev;
+ struct mlx4_ib_gid_entry *ge;
+
+ err = mlx4_multicast_detach(mdev->dev,
+ &mqp->mqp, gid->raw);
+ if (err)
+ return err;
+
+ mutex_lock(&mqp->mutex);
+ ge = find_gid_entry(mqp, gid->raw);
+ if (ge) {
+ spin_lock(&mdev->iboe.lock);
+ ndev = ge->added ? mdev->iboe.netdevs[ge->port - 1] : NULL;
+ if (ndev)
+ dev_hold(ndev);
+ spin_unlock(&mdev->iboe.lock);
+ rdma_get_mcast_mac((struct in6_addr *)gid, mac);
+ if (ndev) {
+ rtnl_lock();
+ dev_mc_del(mdev->iboe.netdevs[ge->port - 1], mac);
+ rtnl_unlock();
+ dev_put(ndev);
+ }
+ list_del(&ge->list);
+ kfree(ge);
+ } else
+ printk(KERN_WARNING "could not find mgid entry\n");
+
+ mutex_unlock(&mqp->mutex);
+
+ return 0;
}
static int init_node_data(struct mlx4_ib_dev *dev)
@@ -543,15 +776,215 @@ static struct device_attribute *mlx4_class_attributes[] = {
&dev_attr_board_id
};
+static void mlx4_addrconf_ifid_eui48(u8 *eui, u16 vlan_id, struct net_device *dev)
+{
+ memcpy(eui, dev->dev_addr, 3);
+ memcpy(eui + 5, dev->dev_addr + 3, 3);
+ if (vlan_id < 0x1000) {
+ eui[3] = vlan_id >> 8;
+ eui[4] = vlan_id & 0xff;
+ } else {
+ eui[3] = 0xff;
+ eui[4] = 0xfe;
+ }
+ eui[0] ^= 2;
+}
+
+static void update_gids_task(struct work_struct *work)
+{
+ struct update_gid_work *gw = container_of(work, struct update_gid_work, work);
+ struct mlx4_cmd_mailbox *mailbox;
+ union ib_gid *gids;
+ int err;
+ struct mlx4_dev *dev = gw->dev->dev;
+ struct ib_event event;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox)) {
+ printk(KERN_WARNING "update gid table failed %ld\n", PTR_ERR(mailbox));
+ return;
+ }
+
+ gids = mailbox->buf;
+ memcpy(gids, gw->gids, sizeof gw->gids);
+
+ err = mlx4_cmd(dev, mailbox->dma, MLX4_SET_PORT_GID_TABLE << 8 | gw->port,
+ 1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B);
+ if (err)
+ printk(KERN_WARNING "set port command failed\n");
+ else {
+ memcpy(gw->dev->iboe.gid_table[gw->port - 1], gw->gids, sizeof gw->gids);
+ event.device = &gw->dev->ib_dev;
+ event.element.port_num = gw->port;
+ event.event = IB_EVENT_LID_CHANGE;
+ ib_dispatch_event(&event);
+ }
+
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ kfree(gw);
+}
+
+static int update_ipv6_gids(struct mlx4_ib_dev *dev, int port, int clear)
+{
+ struct net_device *ndev = dev->iboe.netdevs[port - 1];
+ struct update_gid_work *work;
+ struct net_device *tmp;
+ int i;
+ u8 *hits;
+ int ret;
+ union ib_gid gid;
+ int free;
+ int found;
+ int need_update = 0;
+ u16 vid;
+
+ work = kzalloc(sizeof *work, GFP_ATOMIC);
+ if (!work)
+ return -ENOMEM;
+
+ hits = kzalloc(128, GFP_ATOMIC);
+ if (!hits) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ read_lock(&dev_base_lock);
+ for_each_netdev(&init_net, tmp) {
+ if (ndev && (tmp == ndev || rdma_vlan_dev_real_dev(tmp) == ndev)) {
+ gid.global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
+ vid = rdma_vlan_dev_vlan_id(tmp);
+ mlx4_addrconf_ifid_eui48(&gid.raw[8], vid, ndev);
+ found = 0;
+ free = -1;
+ for (i = 0; i < 128; ++i) {
+ if (free < 0 &&
+ !memcmp(&dev->iboe.gid_table[port - 1][i], &zgid, sizeof zgid))
+ free = i;
+ if (!memcmp(&dev->iboe.gid_table[port - 1][i], &gid, sizeof gid)) {
+ hits[i] = 1;
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ if (tmp == ndev &&
+ (memcmp(&dev->iboe.gid_table[port - 1][0],
+ &gid, sizeof gid) ||
+ !memcmp(&dev->iboe.gid_table[port - 1][0],
+ &zgid, sizeof gid))) {
+ dev->iboe.gid_table[port - 1][0] = gid;
+ ++need_update;
+ hits[0] = 1;
+ } else if (free >= 0) {
+ dev->iboe.gid_table[port - 1][free] = gid;
+ hits[free] = 1;
+ ++need_update;
+ }
+ }
+ }
+ }
+ read_unlock(&dev_base_lock);
+
+ for (i = 0; i < 128; ++i)
+ if (!hits[i]) {
+ if (memcmp(&dev->iboe.gid_table[port - 1][i], &zgid, sizeof zgid))
+ ++need_update;
+ dev->iboe.gid_table[port - 1][i] = zgid;
+ }
+
+ if (need_update) {
+ memcpy(work->gids, dev->iboe.gid_table[port - 1], sizeof work->gids);
+ INIT_WORK(&work->work, update_gids_task);
+ work->port = port;
+ work->dev = dev;
+ queue_work(wq, &work->work);
+ } else
+ kfree(work);
+
+ kfree(hits);
+ return 0;
+
+out:
+ kfree(work);
+ return ret;
+}
+
+static void handle_en_event(struct mlx4_ib_dev *dev, int port, unsigned long event)
+{
+ switch (event) {
+ case NETDEV_UP:
+ case NETDEV_CHANGEADDR:
+ update_ipv6_gids(dev, port, 0);
+ break;
+
+ case NETDEV_DOWN:
+ update_ipv6_gids(dev, port, 1);
+ dev->iboe.netdevs[port - 1] = NULL;
+ }
+}
+
+static void netdev_added(struct mlx4_ib_dev *dev, int port)
+{
+ update_ipv6_gids(dev, port, 0);
+}
+
+static void netdev_removed(struct mlx4_ib_dev *dev, int port)
+{
+ update_ipv6_gids(dev, port, 1);
+}
+
+static int mlx4_ib_netdev_event(struct notifier_block *this, unsigned long event,
+ void *ptr)
+{
+ struct net_device *dev = ptr;
+ struct mlx4_ib_dev *ibdev;
+ struct net_device *oldnd;
+ struct mlx4_ib_iboe *iboe;
+ int port;
+
+ if (!net_eq(dev_net(dev), &init_net))
+ return NOTIFY_DONE;
+
+ ibdev = container_of(this, struct mlx4_ib_dev, iboe.nb);
+ iboe = &ibdev->iboe;
+
+ spin_lock(&iboe->lock);
+ mlx4_foreach_ib_transport_port(port, ibdev->dev) {
+ oldnd = iboe->netdevs[port - 1];
+ iboe->netdevs[port - 1] =
+ mlx4_get_protocol_dev(ibdev->dev, MLX4_PROTOCOL_EN, port);
+ if (oldnd != iboe->netdevs[port - 1]) {
+ if (iboe->netdevs[port - 1])
+ netdev_added(ibdev, port);
+ else
+ netdev_removed(ibdev, port);
+ }
+ }
+
+ if (dev == iboe->netdevs[0] ||
+ (iboe->netdevs[0] && rdma_vlan_dev_real_dev(dev) == iboe->netdevs[0]))
+ handle_en_event(ibdev, 1, event);
+ else if (dev == iboe->netdevs[1]
+ || (iboe->netdevs[1] && rdma_vlan_dev_real_dev(dev) == iboe->netdevs[1]))
+ handle_en_event(ibdev, 2, event);
+
+ spin_unlock(&iboe->lock);
+
+ return NOTIFY_DONE;
+}
+
static void *mlx4_ib_add(struct mlx4_dev *dev)
{
struct mlx4_ib_dev *ibdev;
int num_ports = 0;
int i;
+ int err;
+ struct mlx4_ib_iboe *iboe;
printk_once(KERN_INFO "%s", mlx4_ib_version);
- mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
+ mlx4_foreach_ib_transport_port(i, dev)
num_ports++;
/* No point in registering a device with no ports... */
@@ -564,6 +997,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
return NULL;
}
+ iboe = &ibdev->iboe;
+
if (mlx4_pd_alloc(dev, &ibdev->priv_pdn))
goto err_dealloc;
@@ -612,6 +1047,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
ibdev->ib_dev.query_device = mlx4_ib_query_device;
ibdev->ib_dev.query_port = mlx4_ib_query_port;
+ ibdev->ib_dev.get_link_layer = mlx4_ib_port_link_layer;
ibdev->ib_dev.query_gid = mlx4_ib_query_gid;
ibdev->ib_dev.query_pkey = mlx4_ib_query_pkey;
ibdev->ib_dev.modify_device = mlx4_ib_modify_device;
@@ -656,6 +1092,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
ibdev->ib_dev.unmap_fmr = mlx4_ib_unmap_fmr;
ibdev->ib_dev.dealloc_fmr = mlx4_ib_fmr_dealloc;
+ spin_lock_init(&iboe->lock);
+
if (init_node_data(ibdev))
goto err_map;
@@ -668,16 +1106,28 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
if (mlx4_ib_mad_init(ibdev))
goto err_reg;
+ if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE && !iboe->nb.notifier_call) {
+ iboe->nb.notifier_call = mlx4_ib_netdev_event;
+ err = register_netdevice_notifier(&iboe->nb);
+ if (err)
+ goto err_reg;
+ }
+
for (i = 0; i < ARRAY_SIZE(mlx4_class_attributes); ++i) {
if (device_create_file(&ibdev->ib_dev.dev,
mlx4_class_attributes[i]))
- goto err_reg;
+ goto err_notif;
}
ibdev->ib_active = true;
return ibdev;
+err_notif:
+ if (unregister_netdevice_notifier(&ibdev->iboe.nb))
+ printk(KERN_WARNING "failure unregistering notifier\n");
+ flush_workqueue(wq);
+
err_reg:
ib_unregister_device(&ibdev->ib_dev);
@@ -703,11 +1153,16 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
mlx4_ib_mad_cleanup(ibdev);
ib_unregister_device(&ibdev->ib_dev);
+ if (ibdev->iboe.nb.notifier_call) {
+ if (unregister_netdevice_notifier(&ibdev->iboe.nb))
+ printk(KERN_WARNING "failure unregistering notifier\n");
+ ibdev->iboe.nb.notifier_call = NULL;
+ }
+ iounmap(ibdev->uar_map);
- for (p = 1; p <= ibdev->num_ports; ++p)
+ mlx4_foreach_port(p, dev, MLX4_PORT_TYPE_IB)
mlx4_CLOSE_PORT(dev, p);
- iounmap(ibdev->uar_map);
mlx4_uar_free(dev, &ibdev->priv_uar);
mlx4_pd_free(dev, ibdev->priv_pdn);
ib_dealloc_device(&ibdev->ib_dev);
@@ -747,19 +1202,33 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
}
static struct mlx4_interface mlx4_ib_interface = {
- .add = mlx4_ib_add,
- .remove = mlx4_ib_remove,
- .event = mlx4_ib_event
+ .add = mlx4_ib_add,
+ .remove = mlx4_ib_remove,
+ .event = mlx4_ib_event,
+ .protocol = MLX4_PROTOCOL_IB
};
static int __init mlx4_ib_init(void)
{
- return mlx4_register_interface(&mlx4_ib_interface);
+ int err;
+
+ wq = create_singlethread_workqueue("mlx4_ib");
+ if (!wq)
+ return -ENOMEM;
+
+ err = mlx4_register_interface(&mlx4_ib_interface);
+ if (err) {
+ destroy_workqueue(wq);
+ return err;
+ }
+
+ return 0;
}
static void __exit mlx4_ib_cleanup(void)
{
mlx4_unregister_interface(&mlx4_ib_interface);
+ destroy_workqueue(wq);
}
module_init(mlx4_ib_init);
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index 3486d7675e56..2a322f21049f 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -112,6 +112,13 @@ enum mlx4_ib_qp_flags {
MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK = 1 << 1,
};
+struct mlx4_ib_gid_entry {
+ struct list_head list;
+ union ib_gid gid;
+ int added;
+ u8 port;
+};
+
struct mlx4_ib_qp {
struct ib_qp ibqp;
struct mlx4_qp mqp;
@@ -138,6 +145,8 @@ struct mlx4_ib_qp {
u8 resp_depth;
u8 sq_no_prefetch;
u8 state;
+ int mlx_type;
+ struct list_head gid_list;
};
struct mlx4_ib_srq {
@@ -157,7 +166,14 @@ struct mlx4_ib_srq {
struct mlx4_ib_ah {
struct ib_ah ibah;
- struct mlx4_av av;
+ union mlx4_ext_av av;
+};
+
+struct mlx4_ib_iboe {
+ spinlock_t lock;
+ struct net_device *netdevs[MLX4_MAX_PORTS];
+ struct notifier_block nb;
+ union ib_gid gid_table[MLX4_MAX_PORTS][128];
};
struct mlx4_ib_dev {
@@ -176,6 +192,7 @@ struct mlx4_ib_dev {
struct mutex cap_mask_mutex;
bool ib_active;
+ struct mlx4_ib_iboe iboe;
};
static inline struct mlx4_ib_dev *to_mdev(struct ib_device *ibdev)
@@ -314,9 +331,20 @@ int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, int npages,
int mlx4_ib_unmap_fmr(struct list_head *fmr_list);
int mlx4_ib_fmr_dealloc(struct ib_fmr *fmr);
+int mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr,
+ u8 *mac, int *is_mcast, u8 port);
+
static inline int mlx4_ib_ah_grh_present(struct mlx4_ib_ah *ah)
{
- return !!(ah->av.g_slid & 0x80);
+ u8 port = be32_to_cpu(ah->av.ib.port_pd) >> 24 & 3;
+
+ if (rdma_port_get_link_layer(ah->ibah.device, port) == IB_LINK_LAYER_ETHERNET)
+ return 1;
+
+ return !!(ah->av.ib.g_slid & 0x80);
}
+int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
+ union ib_gid *gid);
+
#endif /* MLX4_IB_H */
diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c
index 1d27b9a8e2d6..dca55b19a6f1 100644
--- a/drivers/infiniband/hw/mlx4/mr.c
+++ b/drivers/infiniband/hw/mlx4/mr.c
@@ -226,7 +226,7 @@ struct ib_fast_reg_page_list *mlx4_ib_alloc_fast_reg_page_list(struct ib_device
struct mlx4_ib_fast_reg_page_list *mfrpl;
int size = page_list_len * sizeof (u64);
- if (size > PAGE_SIZE)
+ if (page_list_len > MLX4_MAX_FAST_REG_PAGES)
return ERR_PTR(-EINVAL);
mfrpl = kmalloc(sizeof *mfrpl, GFP_KERNEL);
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 6a60827b2301..9a7794ac34c1 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -33,9 +33,11 @@
#include <linux/log2.h>
#include <linux/slab.h>
+#include <linux/netdevice.h>
#include <rdma/ib_cache.h>
#include <rdma/ib_pack.h>
+#include <rdma/ib_addr.h>
#include <linux/mlx4/qp.h>
@@ -48,17 +50,26 @@ enum {
enum {
MLX4_IB_DEFAULT_SCHED_QUEUE = 0x83,
- MLX4_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f
+ MLX4_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f,
+ MLX4_IB_LINK_TYPE_IB = 0,
+ MLX4_IB_LINK_TYPE_ETH = 1
};
enum {
/*
- * Largest possible UD header: send with GRH and immediate data.
+ * Largest possible UD header: send with GRH and immediate
+ * data plus 18 bytes for an Ethernet header with VLAN/802.1Q
+ * tag. (LRH would only use 8 bytes, so Ethernet is the
+ * biggest case)
*/
- MLX4_IB_UD_HEADER_SIZE = 72,
+ MLX4_IB_UD_HEADER_SIZE = 82,
MLX4_IB_LSO_HEADER_SPARE = 128,
};
+enum {
+ MLX4_IB_IBOE_ETHERTYPE = 0x8915
+};
+
struct mlx4_ib_sqp {
struct mlx4_ib_qp qp;
int pkey_index;
@@ -462,6 +473,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
mutex_init(&qp->mutex);
spin_lock_init(&qp->sq.lock);
spin_lock_init(&qp->rq.lock);
+ INIT_LIST_HEAD(&qp->gid_list);
qp->state = IB_QPS_RESET;
if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
@@ -649,6 +661,16 @@ static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *re
}
}
+static void del_gid_entries(struct mlx4_ib_qp *qp)
+{
+ struct mlx4_ib_gid_entry *ge, *tmp;
+
+ list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) {
+ list_del(&ge->list);
+ kfree(ge);
+ }
+}
+
static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
int is_user)
{
@@ -695,6 +717,8 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
if (!qp->ibqp.srq)
mlx4_db_free(dev->dev, &qp->db);
}
+
+ del_gid_entries(qp);
}
struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
@@ -852,6 +876,14 @@ static void mlx4_set_sched(struct mlx4_qp_path *path, u8 port)
static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah,
struct mlx4_qp_path *path, u8 port)
{
+ int err;
+ int is_eth = rdma_port_get_link_layer(&dev->ib_dev, port) ==
+ IB_LINK_LAYER_ETHERNET;
+ u8 mac[6];
+ int is_mcast;
+ u16 vlan_tag;
+ int vidx;
+
path->grh_mylmc = ah->src_path_bits & 0x7f;
path->rlid = cpu_to_be16(ah->dlid);
if (ah->static_rate) {
@@ -879,12 +911,49 @@ static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah,
memcpy(path->rgid, ah->grh.dgid.raw, 16);
}
- path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
- ((port - 1) << 6) | ((ah->sl & 0xf) << 2);
+ if (is_eth) {
+ path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
+ ((port - 1) << 6) | ((ah->sl & 7) << 3) | ((ah->sl & 8) >> 1);
+
+ if (!(ah->ah_flags & IB_AH_GRH))
+ return -1;
+
+ err = mlx4_ib_resolve_grh(dev, ah, mac, &is_mcast, port);
+ if (err)
+ return err;
+
+ memcpy(path->dmac, mac, 6);
+ path->ackto = MLX4_IB_LINK_TYPE_ETH;
+ /* use index 0 into MAC table for IBoE */
+ path->grh_mylmc &= 0x80;
+
+ vlan_tag = rdma_get_vlan_id(&dev->iboe.gid_table[port - 1][ah->grh.sgid_index]);
+ if (vlan_tag < 0x1000) {
+ if (mlx4_find_cached_vlan(dev->dev, port, vlan_tag, &vidx))
+ return -ENOENT;
+
+ path->vlan_index = vidx;
+ path->fl = 1 << 6;
+ }
+ } else
+ path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
+ ((port - 1) << 6) | ((ah->sl & 0xf) << 2);
return 0;
}
+static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
+{
+ struct mlx4_ib_gid_entry *ge, *tmp;
+
+ list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) {
+ if (!ge->added && mlx4_ib_add_mc(dev, qp, &ge->gid)) {
+ ge->added = 1;
+ ge->port = qp->port;
+ }
+ }
+}
+
static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
const struct ib_qp_attr *attr, int attr_mask,
enum ib_qp_state cur_state, enum ib_qp_state new_state)
@@ -980,7 +1049,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
}
if (attr_mask & IB_QP_TIMEOUT) {
- context->pri_path.ackto = attr->timeout << 3;
+ context->pri_path.ackto |= attr->timeout << 3;
optpar |= MLX4_QP_OPTPAR_ACK_TIMEOUT;
}
@@ -1118,8 +1187,10 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
qp->atomic_rd_en = attr->qp_access_flags;
if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
qp->resp_depth = attr->max_dest_rd_atomic;
- if (attr_mask & IB_QP_PORT)
+ if (attr_mask & IB_QP_PORT) {
qp->port = attr->port_num;
+ update_mcg_macs(dev, qp);
+ }
if (attr_mask & IB_QP_ALT_PATH)
qp->alt_port = attr->alt_port_num;
@@ -1221,40 +1292,59 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
struct mlx4_wqe_mlx_seg *mlx = wqe;
struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx;
struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah);
+ union ib_gid sgid;
u16 pkey;
int send_size;
int header_size;
int spc;
int i;
+ int is_eth;
+ int is_vlan = 0;
+ int is_grh;
+ u16 vlan;
send_size = 0;
for (i = 0; i < wr->num_sge; ++i)
send_size += wr->sg_list[i].length;
- ib_ud_header_init(send_size, mlx4_ib_ah_grh_present(ah), 0, &sqp->ud_header);
+ is_eth = rdma_port_get_link_layer(sqp->qp.ibqp.device, sqp->qp.port) == IB_LINK_LAYER_ETHERNET;
+ is_grh = mlx4_ib_ah_grh_present(ah);
+ if (is_eth) {
+ ib_get_cached_gid(ib_dev, be32_to_cpu(ah->av.ib.port_pd) >> 24,
+ ah->av.ib.gid_index, &sgid);
+ vlan = rdma_get_vlan_id(&sgid);
+ is_vlan = vlan < 0x1000;
+ }
+ ib_ud_header_init(send_size, !is_eth, is_eth, is_vlan, is_grh, 0, &sqp->ud_header);
+
+ if (!is_eth) {
+ sqp->ud_header.lrh.service_level =
+ be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28;
+ sqp->ud_header.lrh.destination_lid = ah->av.ib.dlid;
+ sqp->ud_header.lrh.source_lid = cpu_to_be16(ah->av.ib.g_slid & 0x7f);
+ }
- sqp->ud_header.lrh.service_level =
- be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28;
- sqp->ud_header.lrh.destination_lid = ah->av.dlid;
- sqp->ud_header.lrh.source_lid = cpu_to_be16(ah->av.g_slid & 0x7f);
- if (mlx4_ib_ah_grh_present(ah)) {
+ if (is_grh) {
sqp->ud_header.grh.traffic_class =
- (be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 20) & 0xff;
+ (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20) & 0xff;
sqp->ud_header.grh.flow_label =
- ah->av.sl_tclass_flowlabel & cpu_to_be32(0xfffff);
- sqp->ud_header.grh.hop_limit = ah->av.hop_limit;
- ib_get_cached_gid(ib_dev, be32_to_cpu(ah->av.port_pd) >> 24,
- ah->av.gid_index, &sqp->ud_header.grh.source_gid);
+ ah->av.ib.sl_tclass_flowlabel & cpu_to_be32(0xfffff);
+ sqp->ud_header.grh.hop_limit = ah->av.ib.hop_limit;
+ ib_get_cached_gid(ib_dev, be32_to_cpu(ah->av.ib.port_pd) >> 24,
+ ah->av.ib.gid_index, &sqp->ud_header.grh.source_gid);
memcpy(sqp->ud_header.grh.destination_gid.raw,
- ah->av.dgid, 16);
+ ah->av.ib.dgid, 16);
}
mlx->flags &= cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE);
- mlx->flags |= cpu_to_be32((!sqp->qp.ibqp.qp_num ? MLX4_WQE_MLX_VL15 : 0) |
- (sqp->ud_header.lrh.destination_lid ==
- IB_LID_PERMISSIVE ? MLX4_WQE_MLX_SLR : 0) |
- (sqp->ud_header.lrh.service_level << 8));
- mlx->rlid = sqp->ud_header.lrh.destination_lid;
+
+ if (!is_eth) {
+ mlx->flags |= cpu_to_be32((!sqp->qp.ibqp.qp_num ? MLX4_WQE_MLX_VL15 : 0) |
+ (sqp->ud_header.lrh.destination_lid ==
+ IB_LID_PERMISSIVE ? MLX4_WQE_MLX_SLR : 0) |
+ (sqp->ud_header.lrh.service_level << 8));
+ mlx->rlid = sqp->ud_header.lrh.destination_lid;
+ }
switch (wr->opcode) {
case IB_WR_SEND:
@@ -1270,9 +1360,29 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
return -EINVAL;
}
- sqp->ud_header.lrh.virtual_lane = !sqp->qp.ibqp.qp_num ? 15 : 0;
- if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE)
- sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE;
+ if (is_eth) {
+ u8 *smac;
+
+ memcpy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac, 6);
+ /* FIXME: cache smac value? */
+ smac = to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1]->dev_addr;
+ memcpy(sqp->ud_header.eth.smac_h, smac, 6);
+ if (!memcmp(sqp->ud_header.eth.smac_h, sqp->ud_header.eth.dmac_h, 6))
+ mlx->flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK);
+ if (!is_vlan) {
+ sqp->ud_header.eth.type = cpu_to_be16(MLX4_IB_IBOE_ETHERTYPE);
+ } else {
+ u16 pcp;
+
+ sqp->ud_header.vlan.type = cpu_to_be16(MLX4_IB_IBOE_ETHERTYPE);
+ pcp = (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 27 & 3) << 13;
+ sqp->ud_header.vlan.tag = cpu_to_be16(vlan | pcp);
+ }
+ } else {
+ sqp->ud_header.lrh.virtual_lane = !sqp->qp.ibqp.qp_num ? 15 : 0;
+ if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE)
+ sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE;
+ }
sqp->ud_header.bth.solicited_event = !!(wr->send_flags & IB_SEND_SOLICITED);
if (!sqp->qp.ibqp.qp_num)
ib_get_cached_pkey(ib_dev, sqp->qp.port, sqp->pkey_index, &pkey);
@@ -1429,11 +1539,14 @@ static void set_masked_atomic_seg(struct mlx4_wqe_masked_atomic_seg *aseg,
}
static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg,
- struct ib_send_wr *wr)
+ struct ib_send_wr *wr, __be16 *vlan)
{
memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
dseg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
dseg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+ dseg->vlan = to_mah(wr->wr.ud.ah)->av.eth.vlan;
+ memcpy(dseg->mac, to_mah(wr->wr.ud.ah)->av.eth.mac, 6);
+ *vlan = dseg->vlan;
}
static void set_mlx_icrc_seg(void *dseg)
@@ -1536,6 +1649,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
__be32 uninitialized_var(lso_hdr_sz);
__be32 blh;
int i;
+ __be16 vlan = cpu_to_be16(0xffff);
spin_lock_irqsave(&qp->sq.lock, flags);
@@ -1639,7 +1753,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
break;
case IB_QPT_UD:
- set_datagram_seg(wqe, wr);
+ set_datagram_seg(wqe, wr, &vlan);
wqe += sizeof (struct mlx4_wqe_datagram_seg);
size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
@@ -1717,6 +1831,11 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
ctrl->owner_opcode = mlx4_ib_opcode[wr->opcode] |
(ind & qp->sq.wqe_cnt ? cpu_to_be32(1 << 31) : 0) | blh;
+ if (be16_to_cpu(vlan) < 0x1000) {
+ ctrl->ins_vlan = 1 << 6;
+ ctrl->vlan_tag = vlan;
+ }
+
stamp = ind + qp->sq_spare_wqes;
ind += DIV_ROUND_UP(size * 16, 1U << qp->sq.wqe_shift);
@@ -1866,17 +1985,27 @@ static int to_ib_qp_access_flags(int mlx4_flags)
return ib_flags;
}
-static void to_ib_ah_attr(struct mlx4_dev *dev, struct ib_ah_attr *ib_ah_attr,
+static void to_ib_ah_attr(struct mlx4_ib_dev *ibdev, struct ib_ah_attr *ib_ah_attr,
struct mlx4_qp_path *path)
{
+ struct mlx4_dev *dev = ibdev->dev;
+ int is_eth;
+
memset(ib_ah_attr, 0, sizeof *ib_ah_attr);
ib_ah_attr->port_num = path->sched_queue & 0x40 ? 2 : 1;
if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports)
return;
+ is_eth = rdma_port_get_link_layer(&ibdev->ib_dev, ib_ah_attr->port_num) ==
+ IB_LINK_LAYER_ETHERNET;
+ if (is_eth)
+ ib_ah_attr->sl = ((path->sched_queue >> 3) & 0x7) |
+ ((path->sched_queue & 4) << 1);
+ else
+ ib_ah_attr->sl = (path->sched_queue >> 2) & 0xf;
+
ib_ah_attr->dlid = be16_to_cpu(path->rlid);
- ib_ah_attr->sl = (path->sched_queue >> 2) & 0xf;
ib_ah_attr->src_path_bits = path->grh_mylmc & 0x7f;
ib_ah_attr->static_rate = path->static_rate ? path->static_rate - 5 : 0;
ib_ah_attr->ah_flags = (path->grh_mylmc & (1 << 7)) ? IB_AH_GRH : 0;
@@ -1929,8 +2058,8 @@ int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr
to_ib_qp_access_flags(be32_to_cpu(context.params2));
if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC) {
- to_ib_ah_attr(dev->dev, &qp_attr->ah_attr, &context.pri_path);
- to_ib_ah_attr(dev->dev, &qp_attr->alt_ah_attr, &context.alt_path);
+ to_ib_ah_attr(dev, &qp_attr->ah_attr, &context.pri_path);
+ to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context.alt_path);
qp_attr->alt_pkey_index = context.alt_path.pkey_index & 0x7f;
qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num;
}
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index d2d172e6289c..a34c9d38e822 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -1493,7 +1493,7 @@ static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp,
int err;
u16 pkey;
- ib_ud_header_init(256, /* assume a MAD */
+ ib_ud_header_init(256, /* assume a MAD */ 1, 0, 0,
mthca_ah_grh_present(to_mah(wr->wr.ud.ah)), 0,
&sqp->ud_header);
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 61e0efd4ccfb..25ad0f9944c0 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -1424,7 +1424,6 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
{
int reset = 0; /* whether to send reset in case of err.. */
- int passive_state;
atomic_inc(&cm_resets_recvd);
nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u."
" refcnt=%d\n", cm_node, cm_node->state,
@@ -1439,7 +1438,7 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
active_open_err(cm_node, skb, reset);
break;
case NES_CM_STATE_MPAREQ_RCVD:
- passive_state = atomic_add_return(1, &cm_node->passive_state);
+ atomic_inc(&cm_node->passive_state);
dev_kfree_skb_any(skb);
break;
case NES_CM_STATE_ESTABLISHED:
@@ -2701,7 +2700,7 @@ static int nes_disconnect(struct nes_qp *nesqp, int abrupt)
nesibdev = nesvnic->nesibdev;
nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
- atomic_read(&nesvnic->netdev->refcnt));
+ netdev_refcnt_read(nesvnic->netdev));
if (nesqp->active_conn) {
@@ -2791,7 +2790,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
atomic_inc(&cm_accepts);
nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
- atomic_read(&nesvnic->netdev->refcnt));
+ netdev_refcnt_read(nesvnic->netdev));
/* allocate the ietf frame and space for private data */
nesqp->ietf_frame = pci_alloc_consistent(nesdev->pcidev,
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 10560c796fd6..3892e2c0e95a 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -271,6 +271,7 @@ static int nes_netdev_stop(struct net_device *netdev)
if (netif_msg_ifdown(nesvnic))
printk(KERN_INFO PFX "%s: disabling interface\n", netdev->name);
+ netif_carrier_off(netdev);
/* Disable network packets */
napi_disable(&nesvnic->napi);
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index 9046e6675686..99933e4e48ff 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -476,9 +476,9 @@ static struct ib_fast_reg_page_list *nes_alloc_fast_reg_page_list(
}
nes_debug(NES_DBG_MR, "nes_alloc_fast_reg_pbl: nes_frpl = %p, "
"ibfrpl = %p, ibfrpl.page_list = %p, pbl.kva = %p, "
- "pbl.paddr= %p\n", pnesfrpl, &pnesfrpl->ibfrpl,
+ "pbl.paddr = %llx\n", pnesfrpl, &pnesfrpl->ibfrpl,
pnesfrpl->ibfrpl.page_list, pnesfrpl->nes_wqe_pbl.kva,
- (void *)pnesfrpl->nes_wqe_pbl.paddr);
+ (unsigned long long) pnesfrpl->nes_wqe_pbl.paddr);
return pifrpl;
}
@@ -584,7 +584,9 @@ static int nes_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr
props->lmc = 0;
props->sm_lid = 0;
props->sm_sl = 0;
- if (nesvnic->linkup)
+ if (netif_queue_stopped(netdev))
+ props->state = IB_PORT_DOWN;
+ else if (nesvnic->linkup)
props->state = IB_PORT_ACTIVE;
else
props->state = IB_PORT_DOWN;
@@ -785,7 +787,7 @@ static struct ib_pd *nes_alloc_pd(struct ib_device *ibdev,
nes_debug(NES_DBG_PD, "nesvnic=%p, netdev=%p %s, ibdev=%p, context=%p, netdev refcnt=%u\n",
nesvnic, nesdev->netdev[0], nesdev->netdev[0]->name, ibdev, context,
- atomic_read(&nesvnic->netdev->refcnt));
+ netdev_refcnt_read(nesvnic->netdev));
err = nes_alloc_resource(nesadapter, nesadapter->allocated_pds,
nesadapter->max_pd, &pd_num, &nesadapter->next_pd);
@@ -1416,7 +1418,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
/* update the QP table */
nesdev->nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = nesqp;
nes_debug(NES_DBG_QP, "netdev refcnt=%u\n",
- atomic_read(&nesvnic->netdev->refcnt));
+ netdev_refcnt_read(nesvnic->netdev));
return &nesqp->ibqp;
}
@@ -3483,13 +3485,13 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
for (i = 0; i < ib_wr->wr.fast_reg.page_list_len; i++)
dst_page_list[i] = cpu_to_le64(src_page_list[i]);
- nes_debug(NES_DBG_IW_TX, "SQ_FMR: iova_start: %p, "
- "length: %d, rkey: %0x, pgl_paddr: %p, "
+ nes_debug(NES_DBG_IW_TX, "SQ_FMR: iova_start: %llx, "
+ "length: %d, rkey: %0x, pgl_paddr: %llx, "
"page_list_len: %u, wqe_misc: %x\n",
- (void *)ib_wr->wr.fast_reg.iova_start,
+ (unsigned long long) ib_wr->wr.fast_reg.iova_start,
ib_wr->wr.fast_reg.length,
ib_wr->wr.fast_reg.rkey,
- (void *)pnesfrpl->nes_wqe_pbl.paddr,
+ (unsigned long long) pnesfrpl->nes_wqe_pbl.paddr,
ib_wr->wr.fast_reg.page_list_len,
wqe_misc);
break;
diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h
index 61de0654820e..64c9e7d02d4a 100644
--- a/drivers/infiniband/hw/qib/qib.h
+++ b/drivers/infiniband/hw/qib/qib.h
@@ -1406,7 +1406,7 @@ extern struct mutex qib_mutex;
*/
#define qib_early_err(dev, fmt, ...) \
do { \
- dev_info(dev, KERN_ERR QIB_DRV_NAME ": " fmt, ##__VA_ARGS__); \
+ dev_err(dev, fmt, ##__VA_ARGS__); \
} while (0)
#define qib_dev_err(dd, fmt, ...) \
diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c
index aa2be214270f..79d9971aff1f 100644
--- a/drivers/infiniband/hw/qib/qib_file_ops.c
+++ b/drivers/infiniband/hw/qib/qib_file_ops.c
@@ -1723,7 +1723,7 @@ static int qib_close(struct inode *in, struct file *fp)
mutex_lock(&qib_mutex);
- fd = (struct qib_filedata *) fp->private_data;
+ fd = fp->private_data;
fp->private_data = NULL;
rcd = fd->rcd;
if (!rcd) {
@@ -1809,7 +1809,7 @@ static int qib_ctxt_info(struct file *fp, struct qib_ctxt_info __user *uinfo)
struct qib_ctxtdata *rcd = ctxt_fp(fp);
struct qib_filedata *fd;
- fd = (struct qib_filedata *) fp->private_data;
+ fd = fp->private_data;
info.num_active = qib_count_active_units();
info.unit = rcd->dd->unit;
diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c
index a0e6613e8be6..7e433d75c775 100644
--- a/drivers/infiniband/hw/qib/qib_fs.c
+++ b/drivers/infiniband/hw/qib/qib_fs.c
@@ -58,6 +58,7 @@ static int qibfs_mknod(struct inode *dir, struct dentry *dentry,
goto bail;
}
+ inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_uid = 0;
inode->i_gid = 0;
diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c
index f1d16d3a01f6..f3b503936043 100644
--- a/drivers/infiniband/hw/qib/qib_init.c
+++ b/drivers/infiniband/hw/qib/qib_init.c
@@ -1243,6 +1243,7 @@ static int __devinit qib_init_one(struct pci_dev *pdev,
qib_early_err(&pdev->dev, "QLogic PCIE device 0x%x cannot "
"work if CONFIG_PCI_MSI is not enabled\n",
ent->device);
+ dd = ERR_PTR(-ENODEV);
#endif
break;
diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c
index 7fa6e5592630..48b6674cbc49 100644
--- a/drivers/infiniband/hw/qib/qib_pcie.c
+++ b/drivers/infiniband/hw/qib/qib_pcie.c
@@ -103,16 +103,20 @@ int qib_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent)
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
} else
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
- if (ret)
+ if (ret) {
qib_early_err(&pdev->dev,
"Unable to set DMA consistent mask: %d\n", ret);
+ goto bail;
+ }
pci_set_master(pdev);
ret = pci_enable_pcie_error_reporting(pdev);
- if (ret)
+ if (ret) {
qib_early_err(&pdev->dev,
"Unable to enable pcie error reporting: %d\n",
ret);
+ ret = 0;
+ }
goto done;
bail:
diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c
index a0931119bd78..955fb7157793 100644
--- a/drivers/infiniband/hw/qib/qib_rc.c
+++ b/drivers/infiniband/hw/qib/qib_rc.c
@@ -2068,7 +2068,10 @@ send_last:
goto nack_op_err;
if (!ret)
goto rnr_nak;
- goto send_last_imm;
+ wc.ex.imm_data = ohdr->u.rc.imm_data;
+ hdrsize += 4;
+ wc.wc_flags = IB_WC_WITH_IMM;
+ goto send_last;
case OP(RDMA_READ_REQUEST): {
struct qib_ack_entry *e;
diff --git a/drivers/infiniband/hw/qib/qib_uc.c b/drivers/infiniband/hw/qib/qib_uc.c
index b9c8b6346c1b..32ccf3c824ca 100644
--- a/drivers/infiniband/hw/qib/qib_uc.c
+++ b/drivers/infiniband/hw/qib/qib_uc.c
@@ -457,8 +457,10 @@ rdma_first:
}
if (opcode == OP(RDMA_WRITE_ONLY))
goto rdma_last;
- else if (opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE))
+ else if (opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE)) {
+ wc.ex.imm_data = ohdr->u.rc.imm_data;
goto rdma_last_imm;
+ }
/* FALLTHROUGH */
case OP(RDMA_WRITE_MIDDLE):
/* Check for invalid length PMTU or posted rwqe len. */
@@ -471,8 +473,8 @@ rdma_first:
break;
case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE):
-rdma_last_imm:
wc.ex.imm_data = ohdr->u.imm_data;
+rdma_last_imm:
hdrsize += 4;
wc.wc_flags = IB_WC_WITH_IMM;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index ec6b4fbe25e4..dfa71903d6e4 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -223,6 +223,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
unsigned int wr_id = wc->wr_id & ~IPOIB_OP_RECV;
struct sk_buff *skb;
u64 mapping[IPOIB_UD_RX_SG];
+ union ib_gid *dgid;
ipoib_dbg_data(priv, "recv completion: id %d, status: %d\n",
wr_id, wc->status);
@@ -271,6 +272,16 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
ipoib_ud_dma_unmap_rx(priv, mapping);
ipoib_ud_skb_put_frags(priv, skb, wc->byte_len);
+ /* First byte of dgid signals multicast when 0xff */
+ dgid = &((struct ib_grh *)skb->data)->dgid;
+
+ if (!(wc->wc_flags & IB_WC_GRH) || dgid->raw[0] != 0xff)
+ skb->pkt_type = PACKET_HOST;
+ else if (memcmp(dgid, dev->broadcast + 4, sizeof(union ib_gid)) == 0)
+ skb->pkt_type = PACKET_BROADCAST;
+ else
+ skb->pkt_type = PACKET_MULTICAST;
+
skb_pull(skb, IB_GRH_BYTES);
skb->protocol = ((struct ipoib_header *) skb->data)->proto;
@@ -281,9 +292,6 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
dev->stats.rx_bytes += skb->len;
skb->dev = dev;
- /* XXX get correct PACKET_ type here */
- skb->pkt_type = PACKET_HOST;
-
if (test_bit(IPOIB_FLAG_CSUM, &priv->flags) && likely(wc->csum_ok))
skb->ip_summed = CHECKSUM_UNNECESSARY;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index b4b22576f12a..9ff7bc73ed95 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1240,6 +1240,7 @@ static struct net_device *ipoib_add_port(const char *format,
goto alloc_mem_failed;
SET_NETDEV_DEV(priv->dev, hca->dma_device);
+ priv->dev->dev_id = port - 1;
if (!ib_query_port(hca, port, &attr))
priv->max_ib_mtu = ib_mtu_enum_to_int(attr.max_mtu);
@@ -1362,6 +1363,8 @@ static void ipoib_add_one(struct ib_device *device)
}
for (p = s; p <= e; ++p) {
+ if (rdma_port_get_link_layer(device, p) != IB_LINK_LAYER_INFINIBAND)
+ continue;
dev = ipoib_add_port("ib%d", device, p);
if (!IS_ERR(dev)) {
priv = netdev_priv(dev);
@@ -1409,8 +1412,7 @@ static int __init ipoib_init_module(void)
ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size);
ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE);
- ipoib_sendq_size = max(ipoib_sendq_size, max(2 * MAX_SEND_CQE,
- IPOIB_MIN_QUEUE_SIZE));
+ ipoib_sendq_size = max3(ipoib_sendq_size, 2 * MAX_SEND_CQE, IPOIB_MIN_QUEUE_SIZE);
#ifdef CONFIG_INFINIBAND_IPOIB_CM
ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP);
#endif
diff --git a/drivers/infiniband/ulp/iser/Kconfig b/drivers/infiniband/ulp/iser/Kconfig
index b411c51842da..d00af71a2cfc 100644
--- a/drivers/infiniband/ulp/iser/Kconfig
+++ b/drivers/infiniband/ulp/iser/Kconfig
@@ -9,4 +9,4 @@ config INFINIBAND_ISER
The iSER protocol is defined by IETF.
See <http://www.ietf.org/rfc/rfc5046.txt>
- and <http://www.infinibandta.org/members/spec/Annex_iSER.PDF>
+ and <http://members.infinibandta.org/kwspub/spec/Annex_iSER.PDF>
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 7f8f16bad753..cfc1d65c4577 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -291,7 +291,7 @@ static void srp_free_target_ib(struct srp_target_port *target)
for (i = 0; i < SRP_RQ_SIZE; ++i)
srp_free_iu(target->srp_host, target->rx_ring[i]);
- for (i = 0; i < SRP_SQ_SIZE + 1; ++i)
+ for (i = 0; i < SRP_SQ_SIZE; ++i)
srp_free_iu(target->srp_host, target->tx_ring[i]);
}
@@ -811,6 +811,75 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
return len;
}
+/*
+ * Must be called with target->scsi_host->host_lock held to protect
+ * req_lim and tx_head. Lock cannot be dropped between call here and
+ * call to __srp_post_send().
+ *
+ * Note:
+ * An upper limit for the number of allocated information units for each
+ * request type is:
+ * - SRP_IU_CMD: SRP_CMD_SQ_SIZE, since the SCSI mid-layer never queues
+ * more than Scsi_Host.can_queue requests.
+ * - SRP_IU_TSK_MGMT: SRP_TSK_MGMT_SQ_SIZE.
+ * - SRP_IU_RSP: 1, since a conforming SRP target never sends more than
+ * one unanswered SRP request to an initiator.
+ */
+static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
+ enum srp_iu_type iu_type)
+{
+ s32 rsv = (iu_type == SRP_IU_TSK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE;
+ struct srp_iu *iu;
+
+ srp_send_completion(target->send_cq, target);
+
+ if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
+ return NULL;
+
+ /* Initiator responses to target requests do not consume credits */
+ if (target->req_lim <= rsv && iu_type != SRP_IU_RSP) {
+ ++target->zero_req_lim;
+ return NULL;
+ }
+
+ iu = target->tx_ring[target->tx_head & SRP_SQ_MASK];
+ iu->type = iu_type;
+ return iu;
+}
+
+/*
+ * Must be called with target->scsi_host->host_lock held to protect
+ * req_lim and tx_head.
+ */
+static int __srp_post_send(struct srp_target_port *target,
+ struct srp_iu *iu, int len)
+{
+ struct ib_sge list;
+ struct ib_send_wr wr, *bad_wr;
+ int ret = 0;
+
+ list.addr = iu->dma;
+ list.length = len;
+ list.lkey = target->srp_host->srp_dev->mr->lkey;
+
+ wr.next = NULL;
+ wr.wr_id = target->tx_head & SRP_SQ_MASK;
+ wr.sg_list = &list;
+ wr.num_sge = 1;
+ wr.opcode = IB_WR_SEND;
+ wr.send_flags = IB_SEND_SIGNALED;
+
+ ret = ib_post_send(target->qp, &wr, &bad_wr);
+
+ if (!ret) {
+ ++target->tx_head;
+ if (iu->type != SRP_IU_RSP)
+ --target->req_lim;
+ }
+
+ return ret;
+}
+
static int srp_post_recv(struct srp_target_port *target)
{
unsigned long flags;
@@ -822,7 +891,7 @@ static int srp_post_recv(struct srp_target_port *target)
spin_lock_irqsave(target->scsi_host->host_lock, flags);
- next = target->rx_head & (SRP_RQ_SIZE - 1);
+ next = target->rx_head & SRP_RQ_MASK;
wr.wr_id = next;
iu = target->rx_ring[next];
@@ -896,6 +965,71 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
}
+static int srp_response_common(struct srp_target_port *target, s32 req_delta,
+ void *rsp, int len)
+{
+ struct ib_device *dev;
+ unsigned long flags;
+ struct srp_iu *iu;
+ int err = 1;
+
+ dev = target->srp_host->srp_dev->dev;
+
+ spin_lock_irqsave(target->scsi_host->host_lock, flags);
+ target->req_lim += req_delta;
+
+ iu = __srp_get_tx_iu(target, SRP_IU_RSP);
+ if (!iu) {
+ shost_printk(KERN_ERR, target->scsi_host, PFX
+ "no IU available to send response\n");
+ goto out;
+ }
+
+ ib_dma_sync_single_for_cpu(dev, iu->dma, len, DMA_TO_DEVICE);
+ memcpy(iu->buf, rsp, len);
+ ib_dma_sync_single_for_device(dev, iu->dma, len, DMA_TO_DEVICE);
+
+ err = __srp_post_send(target, iu, len);
+ if (err)
+ shost_printk(KERN_ERR, target->scsi_host, PFX
+ "unable to post response: %d\n", err);
+
+out:
+ spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
+ return err;
+}
+
+static void srp_process_cred_req(struct srp_target_port *target,
+ struct srp_cred_req *req)
+{
+ struct srp_cred_rsp rsp = {
+ .opcode = SRP_CRED_RSP,
+ .tag = req->tag,
+ };
+ s32 delta = be32_to_cpu(req->req_lim_delta);
+
+ if (srp_response_common(target, delta, &rsp, sizeof rsp))
+ shost_printk(KERN_ERR, target->scsi_host, PFX
+ "problems processing SRP_CRED_REQ\n");
+}
+
+static void srp_process_aer_req(struct srp_target_port *target,
+ struct srp_aer_req *req)
+{
+ struct srp_aer_rsp rsp = {
+ .opcode = SRP_AER_RSP,
+ .tag = req->tag,
+ };
+ s32 delta = be32_to_cpu(req->req_lim_delta);
+
+ shost_printk(KERN_ERR, target->scsi_host, PFX
+ "ignoring AER for LUN %llu\n", be64_to_cpu(req->lun));
+
+ if (srp_response_common(target, delta, &rsp, sizeof rsp))
+ shost_printk(KERN_ERR, target->scsi_host, PFX
+ "problems processing SRP_AER_REQ\n");
+}
+
static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
{
struct ib_device *dev;
@@ -923,6 +1057,14 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
srp_process_rsp(target, iu->buf);
break;
+ case SRP_CRED_REQ:
+ srp_process_cred_req(target, iu->buf);
+ break;
+
+ case SRP_AER_REQ:
+ srp_process_aer_req(target, iu->buf);
+ break;
+
case SRP_T_LOGOUT:
/* XXX Handle target logout */
shost_printk(KERN_WARNING, target->scsi_host,
@@ -981,61 +1123,6 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
}
}
-/*
- * Must be called with target->scsi_host->host_lock held to protect
- * req_lim and tx_head. Lock cannot be dropped between call here and
- * call to __srp_post_send().
- */
-static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
- enum srp_request_type req_type)
-{
- s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2;
-
- srp_send_completion(target->send_cq, target);
-
- if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
- return NULL;
-
- if (target->req_lim < min) {
- ++target->zero_req_lim;
- return NULL;
- }
-
- return target->tx_ring[target->tx_head & SRP_SQ_SIZE];
-}
-
-/*
- * Must be called with target->scsi_host->host_lock held to protect
- * req_lim and tx_head.
- */
-static int __srp_post_send(struct srp_target_port *target,
- struct srp_iu *iu, int len)
-{
- struct ib_sge list;
- struct ib_send_wr wr, *bad_wr;
- int ret = 0;
-
- list.addr = iu->dma;
- list.length = len;
- list.lkey = target->srp_host->srp_dev->mr->lkey;
-
- wr.next = NULL;
- wr.wr_id = target->tx_head & SRP_SQ_SIZE;
- wr.sg_list = &list;
- wr.num_sge = 1;
- wr.opcode = IB_WR_SEND;
- wr.send_flags = IB_SEND_SIGNALED;
-
- ret = ib_post_send(target->qp, &wr, &bad_wr);
-
- if (!ret) {
- ++target->tx_head;
- --target->req_lim;
- }
-
- return ret;
-}
-
static int srp_queuecommand(struct scsi_cmnd *scmnd,
void (*done)(struct scsi_cmnd *))
{
@@ -1056,7 +1143,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
return 0;
}
- iu = __srp_get_tx_iu(target, SRP_REQ_NORMAL);
+ iu = __srp_get_tx_iu(target, SRP_IU_CMD);
if (!iu)
goto err;
@@ -1064,7 +1151,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
ib_dma_sync_single_for_cpu(dev, iu->dma, srp_max_iu_len,
DMA_TO_DEVICE);
- req = list_entry(target->free_reqs.next, struct srp_request, list);
+ req = list_first_entry(&target->free_reqs, struct srp_request, list);
scmnd->scsi_done = done;
scmnd->result = 0;
@@ -1121,7 +1208,7 @@ static int srp_alloc_iu_bufs(struct srp_target_port *target)
goto err;
}
- for (i = 0; i < SRP_SQ_SIZE + 1; ++i) {
+ for (i = 0; i < SRP_SQ_SIZE; ++i) {
target->tx_ring[i] = srp_alloc_iu(target->srp_host,
srp_max_iu_len,
GFP_KERNEL, DMA_TO_DEVICE);
@@ -1137,7 +1224,7 @@ err:
target->rx_ring[i] = NULL;
}
- for (i = 0; i < SRP_SQ_SIZE + 1; ++i) {
+ for (i = 0; i < SRP_SQ_SIZE; ++i) {
srp_free_iu(target->srp_host, target->tx_ring[i]);
target->tx_ring[i] = NULL;
}
@@ -1252,8 +1339,13 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
target->max_ti_iu_len = be32_to_cpu(rsp->max_ti_iu_len);
target->req_lim = be32_to_cpu(rsp->req_lim_delta);
- target->scsi_host->can_queue = min(target->req_lim,
- target->scsi_host->can_queue);
+ /*
+ * Reserve credits for task management so we don't
+ * bounce requests back to the SCSI mid-layer.
+ */
+ target->scsi_host->can_queue
+ = min(target->req_lim - SRP_TSK_MGMT_SQ_SIZE,
+ target->scsi_host->can_queue);
} else {
shost_printk(KERN_WARNING, target->scsi_host,
PFX "Unhandled RSP opcode %#x\n", opcode);
@@ -1350,6 +1442,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
static int srp_send_tsk_mgmt(struct srp_target_port *target,
struct srp_request *req, u8 func)
{
+ struct ib_device *dev = target->srp_host->srp_dev->dev;
struct srp_iu *iu;
struct srp_tsk_mgmt *tsk_mgmt;
@@ -1363,10 +1456,12 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
init_completion(&req->done);
- iu = __srp_get_tx_iu(target, SRP_REQ_TASK_MGMT);
+ iu = __srp_get_tx_iu(target, SRP_IU_TSK_MGMT);
if (!iu)
goto out;
+ ib_dma_sync_single_for_cpu(dev, iu->dma, sizeof *tsk_mgmt,
+ DMA_TO_DEVICE);
tsk_mgmt = iu->buf;
memset(tsk_mgmt, 0, sizeof *tsk_mgmt);
@@ -1376,6 +1471,8 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
tsk_mgmt->tsk_mgmt_func = func;
tsk_mgmt->task_tag = req->index;
+ ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt,
+ DMA_TO_DEVICE);
if (__srp_post_send(target, iu, sizeof *tsk_mgmt))
goto out;
@@ -1626,9 +1723,9 @@ static struct scsi_host_template srp_template = {
.eh_abort_handler = srp_abort,
.eh_device_reset_handler = srp_reset_device,
.eh_host_reset_handler = srp_reset_host,
- .can_queue = SRP_SQ_SIZE,
+ .can_queue = SRP_CMD_SQ_SIZE,
.this_id = -1,
- .cmd_per_lun = SRP_SQ_SIZE,
+ .cmd_per_lun = SRP_CMD_SQ_SIZE,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = srp_host_attrs
};
@@ -1813,7 +1910,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
printk(KERN_WARNING PFX "bad max cmd_per_lun parameter '%s'\n", p);
goto out;
}
- target->scsi_host->cmd_per_lun = min(token, SRP_SQ_SIZE);
+ target->scsi_host->cmd_per_lun = min(token, SRP_CMD_SQ_SIZE);
break;
case SRP_OPT_IO_CLASS:
@@ -1891,7 +1988,7 @@ static ssize_t srp_create_target(struct device *dev,
INIT_LIST_HEAD(&target->free_reqs);
INIT_LIST_HEAD(&target->req_queue);
- for (i = 0; i < SRP_SQ_SIZE; ++i) {
+ for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) {
target->req_ring[i].index = i;
list_add_tail(&target->req_ring[i].list, &target->free_reqs);
}
@@ -2159,6 +2256,9 @@ static int __init srp_init_module(void)
{
int ret;
+ BUILD_BUG_ON_NOT_POWER_OF_2(SRP_SQ_SIZE);
+ BUILD_BUG_ON_NOT_POWER_OF_2(SRP_RQ_SIZE);
+
if (srp_sg_tablesize > 255) {
printk(KERN_WARNING PFX "Clamping srp_sg_tablesize to 255\n");
srp_sg_tablesize = 255;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 5a80eac6fdaa..ed0dce9e479f 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -59,7 +59,14 @@ enum {
SRP_RQ_SHIFT = 6,
SRP_RQ_SIZE = 1 << SRP_RQ_SHIFT,
- SRP_SQ_SIZE = SRP_RQ_SIZE - 1,
+ SRP_RQ_MASK = SRP_RQ_SIZE - 1,
+
+ SRP_SQ_SIZE = SRP_RQ_SIZE,
+ SRP_SQ_MASK = SRP_SQ_SIZE - 1,
+ SRP_RSP_SQ_SIZE = 1,
+ SRP_REQ_SQ_SIZE = SRP_SQ_SIZE - SRP_RSP_SQ_SIZE,
+ SRP_TSK_MGMT_SQ_SIZE = 1,
+ SRP_CMD_SQ_SIZE = SRP_REQ_SQ_SIZE - SRP_TSK_MGMT_SQ_SIZE,
SRP_TAG_TSK_MGMT = 1 << (SRP_RQ_SHIFT + 1),
@@ -75,9 +82,10 @@ enum srp_target_state {
SRP_TARGET_REMOVED
};
-enum srp_request_type {
- SRP_REQ_NORMAL,
- SRP_REQ_TASK_MGMT,
+enum srp_iu_type {
+ SRP_IU_CMD,
+ SRP_IU_TSK_MGMT,
+ SRP_IU_RSP,
};
struct srp_device {
@@ -144,11 +152,11 @@ struct srp_target_port {
unsigned tx_head;
unsigned tx_tail;
- struct srp_iu *tx_ring[SRP_SQ_SIZE + 1];
+ struct srp_iu *tx_ring[SRP_SQ_SIZE];
struct list_head free_reqs;
struct list_head req_queue;
- struct srp_request req_ring[SRP_SQ_SIZE];
+ struct srp_request req_ring[SRP_CMD_SQ_SIZE];
struct work_struct work;
@@ -164,6 +172,7 @@ struct srp_iu {
void *buf;
size_t size;
enum dma_data_direction direction;
+ enum srp_iu_type type;
};
#endif /* IB_SRP_H */
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 535fea4fe67f..e3f7fc6f9565 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -534,6 +534,80 @@ static int handle_eviocgbit(struct input_dev *dev,
}
#undef OLD_KEY_MAX
+static int evdev_handle_get_keycode(struct input_dev *dev,
+ void __user *p, size_t size)
+{
+ struct input_keymap_entry ke;
+ int error;
+
+ memset(&ke, 0, sizeof(ke));
+
+ if (size == sizeof(unsigned int[2])) {
+ /* legacy case */
+ int __user *ip = (int __user *)p;
+
+ if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
+ return -EFAULT;
+
+ ke.len = sizeof(unsigned int);
+ ke.flags = 0;
+
+ error = input_get_keycode(dev, &ke);
+ if (error)
+ return error;
+
+ if (put_user(ke.keycode, ip + 1))
+ return -EFAULT;
+
+ } else {
+ size = min(size, sizeof(ke));
+
+ if (copy_from_user(&ke, p, size))
+ return -EFAULT;
+
+ error = input_get_keycode(dev, &ke);
+ if (error)
+ return error;
+
+ if (copy_to_user(p, &ke, size))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static int evdev_handle_set_keycode(struct input_dev *dev,
+ void __user *p, size_t size)
+{
+ struct input_keymap_entry ke;
+
+ memset(&ke, 0, sizeof(ke));
+
+ if (size == sizeof(unsigned int[2])) {
+ /* legacy case */
+ int __user *ip = (int __user *)p;
+
+ if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
+ return -EFAULT;
+
+ if (get_user(ke.keycode, ip + 1))
+ return -EFAULT;
+
+ ke.len = sizeof(unsigned int);
+ ke.flags = 0;
+
+ } else {
+ size = min(size, sizeof(ke));
+
+ if (copy_from_user(&ke, p, size))
+ return -EFAULT;
+
+ if (ke.len > sizeof(ke.scancode))
+ return -EINVAL;
+ }
+
+ return input_set_keycode(dev, &ke);
+}
+
static long evdev_do_ioctl(struct file *file, unsigned int cmd,
void __user *p, int compat_mode)
{
@@ -580,25 +654,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return 0;
- case EVIOCGKEYCODE:
- if (get_user(t, ip))
- return -EFAULT;
-
- error = input_get_keycode(dev, t, &v);
- if (error)
- return error;
-
- if (put_user(v, ip + 1))
- return -EFAULT;
-
- return 0;
-
- case EVIOCSKEYCODE:
- if (get_user(t, ip) || get_user(v, ip + 1))
- return -EFAULT;
-
- return input_set_keycode(dev, t, v);
-
case EVIOCRMFF:
return input_ff_erase(dev, (int)(unsigned long) p, file);
@@ -620,7 +675,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
/* Now check variable-length commands */
#define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
-
switch (EVIOC_MASK_SIZE(cmd)) {
case EVIOCGKEY(0):
@@ -654,6 +708,12 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return -EFAULT;
return error;
+
+ case EVIOC_MASK_SIZE(EVIOCGKEYCODE):
+ return evdev_handle_get_keycode(dev, p, size);
+
+ case EVIOC_MASK_SIZE(EVIOCSKEYCODE):
+ return evdev_handle_set_keycode(dev, p, size);
}
/* Multi-number variable-length handlers */
diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
index 7392992da424..422aa0a6b77f 100644
--- a/drivers/input/gameport/emu10k1-gp.c
+++ b/drivers/input/gameport/emu10k1-gp.c
@@ -59,44 +59,52 @@ MODULE_DEVICE_TABLE(pci, emu_tbl);
static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- int ioport, iolen;
struct emu *emu;
struct gameport *port;
-
- if (pci_enable_device(pdev))
- return -EBUSY;
-
- ioport = pci_resource_start(pdev, 0);
- iolen = pci_resource_len(pdev, 0);
-
- if (!request_region(ioport, iolen, "emu10k1-gp"))
- return -EBUSY;
+ int error;
emu = kzalloc(sizeof(struct emu), GFP_KERNEL);
port = gameport_allocate_port();
if (!emu || !port) {
printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n");
- release_region(ioport, iolen);
- kfree(emu);
- gameport_free_port(port);
- return -ENOMEM;
+ error = -ENOMEM;
+ goto err_out_free;
}
- emu->io = ioport;
- emu->size = iolen;
+ error = pci_enable_device(pdev);
+ if (error)
+ goto err_out_free;
+
+ emu->io = pci_resource_start(pdev, 0);
+ emu->size = pci_resource_len(pdev, 0);
+
emu->dev = pdev;
emu->gameport = port;
gameport_set_name(port, "EMU10K1");
gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
port->dev.parent = &pdev->dev;
- port->io = ioport;
+ port->io = emu->io;
+
+ if (!request_region(emu->io, emu->size, "emu10k1-gp")) {
+ printk(KERN_ERR "emu10k1-gp: unable to grab region 0x%x-0x%x\n",
+ emu->io, emu->io + emu->size - 1);
+ error = -EBUSY;
+ goto err_out_disable_dev;
+ }
pci_set_drvdata(pdev, emu);
gameport_register_port(port);
return 0;
+
+ err_out_disable_dev:
+ pci_disable_device(pdev);
+ err_out_free:
+ gameport_free_port(port);
+ kfree(emu);
+ return error;
}
static void __devexit emu_remove(struct pci_dev *pdev)
@@ -106,6 +114,8 @@ static void __devexit emu_remove(struct pci_dev *pdev)
gameport_unregister_port(emu->gameport);
release_region(emu->io, emu->size);
kfree(emu);
+
+ pci_disable_device(pdev);
}
static struct pci_driver emu_driver = {
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
index 14d3f3e208a2..a3b70ff21018 100644
--- a/drivers/input/gameport/fm801-gp.c
+++ b/drivers/input/gameport/fm801-gp.c
@@ -133,11 +133,11 @@ static void __devexit fm801_gp_remove(struct pci_dev *pci)
{
struct fm801_gp *gp = pci_get_drvdata(pci);
- if (gp) {
- gameport_unregister_port(gp->gameport);
- release_resource(gp->res_port);
- kfree(gp);
- }
+ gameport_unregister_port(gp->gameport);
+ release_resource(gp->res_port);
+ kfree(gp);
+
+ pci_disable_device(pci);
}
static const struct pci_device_id fm801_gp_id_table[] = {
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 7919c2537225..d092ef9291da 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -171,7 +171,7 @@ static int input_handle_abs_event(struct input_dev *dev,
if (code == ABS_MT_SLOT) {
/*
* "Stage" the event; we'll flush it later, when we
- * get actiual touch data.
+ * get actual touch data.
*/
if (*pval >= 0 && *pval < dev->mtsize)
dev->slot = *pval;
@@ -188,7 +188,7 @@ static int input_handle_abs_event(struct input_dev *dev,
pold = &mtslot->abs[code - ABS_MT_FIRST];
} else {
/*
- * Bypass filtering for multitouch events when
+ * Bypass filtering for multi-touch events when
* not employing slots.
*/
pold = NULL;
@@ -634,78 +634,141 @@ static void input_disconnect_device(struct input_dev *dev)
spin_unlock_irq(&dev->event_lock);
}
-static int input_fetch_keycode(struct input_dev *dev, int scancode)
+/**
+ * input_scancode_to_scalar() - converts scancode in &struct input_keymap_entry
+ * @ke: keymap entry containing scancode to be converted.
+ * @scancode: pointer to the location where converted scancode should
+ * be stored.
+ *
+ * This function is used to convert scancode stored in &struct keymap_entry
+ * into scalar form understood by legacy keymap handling methods. These
+ * methods expect scancodes to be represented as 'unsigned int'.
+ */
+int input_scancode_to_scalar(const struct input_keymap_entry *ke,
+ unsigned int *scancode)
+{
+ switch (ke->len) {
+ case 1:
+ *scancode = *((u8 *)ke->scancode);
+ break;
+
+ case 2:
+ *scancode = *((u16 *)ke->scancode);
+ break;
+
+ case 4:
+ *scancode = *((u32 *)ke->scancode);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(input_scancode_to_scalar);
+
+/*
+ * Those routines handle the default case where no [gs]etkeycode() is
+ * defined. In this case, an array indexed by the scancode is used.
+ */
+
+static unsigned int input_fetch_keycode(struct input_dev *dev,
+ unsigned int index)
{
switch (dev->keycodesize) {
- case 1:
- return ((u8 *)dev->keycode)[scancode];
+ case 1:
+ return ((u8 *)dev->keycode)[index];
- case 2:
- return ((u16 *)dev->keycode)[scancode];
+ case 2:
+ return ((u16 *)dev->keycode)[index];
- default:
- return ((u32 *)dev->keycode)[scancode];
+ default:
+ return ((u32 *)dev->keycode)[index];
}
}
static int input_default_getkeycode(struct input_dev *dev,
- unsigned int scancode,
- unsigned int *keycode)
+ struct input_keymap_entry *ke)
{
+ unsigned int index;
+ int error;
+
if (!dev->keycodesize)
return -EINVAL;
- if (scancode >= dev->keycodemax)
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX)
+ index = ke->index;
+ else {
+ error = input_scancode_to_scalar(ke, &index);
+ if (error)
+ return error;
+ }
+
+ if (index >= dev->keycodemax)
return -EINVAL;
- *keycode = input_fetch_keycode(dev, scancode);
+ ke->keycode = input_fetch_keycode(dev, index);
+ ke->index = index;
+ ke->len = sizeof(index);
+ memcpy(ke->scancode, &index, sizeof(index));
return 0;
}
static int input_default_setkeycode(struct input_dev *dev,
- unsigned int scancode,
- unsigned int keycode)
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode)
{
- int old_keycode;
+ unsigned int index;
+ int error;
int i;
- if (scancode >= dev->keycodemax)
+ if (!dev->keycodesize)
return -EINVAL;
- if (!dev->keycodesize)
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ index = ke->index;
+ } else {
+ error = input_scancode_to_scalar(ke, &index);
+ if (error)
+ return error;
+ }
+
+ if (index >= dev->keycodemax)
return -EINVAL;
- if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8)))
+ if (dev->keycodesize < sizeof(dev->keycode) &&
+ (ke->keycode >> (dev->keycodesize * 8)))
return -EINVAL;
switch (dev->keycodesize) {
case 1: {
u8 *k = (u8 *)dev->keycode;
- old_keycode = k[scancode];
- k[scancode] = keycode;
+ *old_keycode = k[index];
+ k[index] = ke->keycode;
break;
}
case 2: {
u16 *k = (u16 *)dev->keycode;
- old_keycode = k[scancode];
- k[scancode] = keycode;
+ *old_keycode = k[index];
+ k[index] = ke->keycode;
break;
}
default: {
u32 *k = (u32 *)dev->keycode;
- old_keycode = k[scancode];
- k[scancode] = keycode;
+ *old_keycode = k[index];
+ k[index] = ke->keycode;
break;
}
}
- __clear_bit(old_keycode, dev->keybit);
- __set_bit(keycode, dev->keybit);
+ __clear_bit(*old_keycode, dev->keybit);
+ __set_bit(ke->keycode, dev->keybit);
for (i = 0; i < dev->keycodemax; i++) {
- if (input_fetch_keycode(dev, i) == old_keycode) {
- __set_bit(old_keycode, dev->keybit);
+ if (input_fetch_keycode(dev, i) == *old_keycode) {
+ __set_bit(*old_keycode, dev->keybit);
break; /* Setting the bit twice is useless, so break */
}
}
@@ -716,53 +779,86 @@ static int input_default_setkeycode(struct input_dev *dev,
/**
* input_get_keycode - retrieve keycode currently mapped to a given scancode
* @dev: input device which keymap is being queried
- * @scancode: scancode (or its equivalent for device in question) for which
- * keycode is needed
- * @keycode: result
+ * @ke: keymap entry
*
* This function should be called by anyone interested in retrieving current
- * keymap. Presently keyboard and evdev handlers use it.
+ * keymap. Presently evdev handlers use it.
*/
-int input_get_keycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
+int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke)
{
unsigned long flags;
int retval;
spin_lock_irqsave(&dev->event_lock, flags);
- retval = dev->getkeycode(dev, scancode, keycode);
- spin_unlock_irqrestore(&dev->event_lock, flags);
+ if (dev->getkeycode) {
+ /*
+ * Support for legacy drivers, that don't implement the new
+ * ioctls
+ */
+ u32 scancode = ke->index;
+
+ memcpy(ke->scancode, &scancode, sizeof(scancode));
+ ke->len = sizeof(scancode);
+ retval = dev->getkeycode(dev, scancode, &ke->keycode);
+ } else {
+ retval = dev->getkeycode_new(dev, ke);
+ }
+
+ spin_unlock_irqrestore(&dev->event_lock, flags);
return retval;
}
EXPORT_SYMBOL(input_get_keycode);
/**
- * input_get_keycode - assign new keycode to a given scancode
+ * input_set_keycode - attribute a keycode to a given scancode
* @dev: input device which keymap is being updated
- * @scancode: scancode (or its equivalent for device in question)
- * @keycode: new keycode to be assigned to the scancode
+ * @ke: new keymap entry
*
* This function should be called by anyone needing to update current
* keymap. Presently keyboard and evdev handlers use it.
*/
int input_set_keycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
+ const struct input_keymap_entry *ke)
{
unsigned long flags;
unsigned int old_keycode;
int retval;
- if (keycode > KEY_MAX)
+ if (ke->keycode > KEY_MAX)
return -EINVAL;
spin_lock_irqsave(&dev->event_lock, flags);
- retval = dev->getkeycode(dev, scancode, &old_keycode);
- if (retval)
- goto out;
+ if (dev->setkeycode) {
+ /*
+ * Support for legacy drivers, that don't implement the new
+ * ioctls
+ */
+ unsigned int scancode;
+
+ retval = input_scancode_to_scalar(ke, &scancode);
+ if (retval)
+ goto out;
+
+ /*
+ * We need to know the old scancode, in order to generate a
+ * keyup effect, if the set operation happens successfully
+ */
+ if (!dev->getkeycode) {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ retval = dev->getkeycode(dev, scancode, &old_keycode);
+ if (retval)
+ goto out;
+
+ retval = dev->setkeycode(dev, scancode, ke->keycode);
+ } else {
+ retval = dev->setkeycode_new(dev, ke, &old_keycode);
+ }
- retval = dev->setkeycode(dev, scancode, keycode);
if (retval)
goto out;
@@ -1601,7 +1697,7 @@ EXPORT_SYMBOL(input_free_device);
*
* This function allocates all necessary memory for MT slot handling in the
* input device, and adds ABS_MT_SLOT to the device capabilities. All slots
- * are initially marked as unused iby setting ABS_MT_TRACKING_ID to -1.
+ * are initially marked as unused by setting ABS_MT_TRACKING_ID to -1.
*/
int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots)
{
@@ -1759,11 +1855,11 @@ int input_register_device(struct input_dev *dev)
dev->rep[REP_PERIOD] = 33;
}
- if (!dev->getkeycode)
- dev->getkeycode = input_default_getkeycode;
+ if (!dev->getkeycode && !dev->getkeycode_new)
+ dev->getkeycode_new = input_default_getkeycode;
- if (!dev->setkeycode)
- dev->setkeycode = input_default_setkeycode;
+ if (!dev->setkeycode && !dev->setkeycode_new)
+ dev->setkeycode_new = input_default_setkeycode;
dev_set_name(&dev->dev, "input%ld",
(unsigned long) atomic_inc_return(&input_no) - 1);
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index 0ffaf2c77a19..e68e49786483 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -521,9 +521,8 @@ static void gc_multi_process_packet(struct gc *gc)
* PSX support
*
* See documentation at:
- * http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt
+ * http://www.geocities.co.jp/Playtown/2004/psx/ps_eng.txt
* http://www.gamesx.com/controldata/psxcont/psxcont.htm
- * ftp://milano.usal.es/pablo/
*
*/
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index aa037fec2f86..b8c51b9781db 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -327,6 +327,16 @@ config KEYBOARD_NEWTON
To compile this driver as a module, choose M here: the
module will be called newtonkbd.
+config KEYBOARD_NOMADIK
+ tristate "ST-Ericsson Nomadik SKE keyboard"
+ depends on PLAT_NOMADIK
+ help
+ Say Y here if you want to use a keypad provided on the SKE controller
+ used on the Ux500 and Nomadik platforms
+
+ To compile this driver as a module, choose M here: the
+ module will be called nmk-ske-keypad.
+
config KEYBOARD_OPENCORES
tristate "OpenCores Keyboard Controller"
help
@@ -424,6 +434,24 @@ config KEYBOARD_OMAP
To compile this driver as a module, choose M here: the
module will be called omap-keypad.
+config KEYBOARD_OMAP4
+ tristate "TI OMAP4 keypad support"
+ depends on ARCH_OMAP4
+ help
+ Say Y here if you want to use the OMAP4 keypad.
+
+ To compile this driver as a module, choose M here: the
+ module will be called omap4-keypad.
+
+config KEYBOARD_TNETV107X
+ tristate "TI TNETV107X keypad support"
+ depends on ARCH_DAVINCI_TNETV107X
+ help
+ Say Y here if you want to use the TNETV107X keypad.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tnetv107x-keypad.
+
config KEYBOARD_TWL4030
tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
depends on TWL4030_CORE
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 504b591be0cd..a34452e8ebe2 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -28,7 +28,9 @@ obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o
obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o
obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
+obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
+obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o
obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
@@ -38,6 +40,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
+obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index d6918cb966c0..b92d1cd5cba1 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -660,7 +660,7 @@ static const struct dev_pm_ops adp5588_dev_pm_ops = {
#endif
static const struct i2c_device_id adp5588_id[] = {
- { KBUILD_MODNAME, 0 },
+ { "adp5588-keys", 0 },
{ "adp5587-keys", 0 },
{ }
};
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
index 19fa94af207a..fed31e0947a1 100644
--- a/drivers/input/keyboard/hil_kbd.c
+++ b/drivers/input/keyboard/hil_kbd.c
@@ -570,6 +570,8 @@ static struct serio_device_id hil_dev_ids[] = {
{ 0 }
};
+MODULE_DEVICE_TABLE(serio, hil_dev_ids);
+
static struct serio_driver hil_serio_drv = {
.driver = {
.name = "hil_dev",
diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c
new file mode 100644
index 000000000000..6e0f23091360
--- /dev/null
+++ b/drivers/input/keyboard/nomadik-ske-keypad.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *
+ * License terms:GNU General Public License (GPL) version 2
+ *
+ * Keypad controller driver for the SKE (Scroll Key Encoder) module used in
+ * the Nomadik 8815 and Ux500 platforms.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#include <plat/ske.h>
+
+/* SKE_CR bits */
+#define SKE_KPMLT (0x1 << 6)
+#define SKE_KPCN (0x7 << 3)
+#define SKE_KPASEN (0x1 << 2)
+#define SKE_KPASON (0x1 << 7)
+
+/* SKE_IMSC bits */
+#define SKE_KPIMA (0x1 << 2)
+
+/* SKE_ICR bits */
+#define SKE_KPICS (0x1 << 3)
+#define SKE_KPICA (0x1 << 2)
+
+/* SKE_RIS bits */
+#define SKE_KPRISA (0x1 << 2)
+
+#define SKE_KEYPAD_ROW_SHIFT 3
+#define SKE_KPD_KEYMAP_SIZE (8 * 8)
+
+/* keypad auto scan registers */
+#define SKE_ASR0 0x20
+#define SKE_ASR1 0x24
+#define SKE_ASR2 0x28
+#define SKE_ASR3 0x2C
+
+#define SKE_NUM_ASRX_REGISTERS (4)
+
+/**
+ * struct ske_keypad - data structure used by keypad driver
+ * @irq: irq no
+ * @reg_base: ske regsiters base address
+ * @input: pointer to input device object
+ * @board: keypad platform device
+ * @keymap: matrix scan code table for keycodes
+ * @clk: clock structure pointer
+ */
+struct ske_keypad {
+ int irq;
+ void __iomem *reg_base;
+ struct input_dev *input;
+ const struct ske_keypad_platform_data *board;
+ unsigned short keymap[SKE_KPD_KEYMAP_SIZE];
+ struct clk *clk;
+ spinlock_t ske_keypad_lock;
+};
+
+static void ske_keypad_set_bits(struct ske_keypad *keypad, u16 addr,
+ u8 mask, u8 data)
+{
+ u32 ret;
+
+ spin_lock(&keypad->ske_keypad_lock);
+
+ ret = readl(keypad->reg_base + addr);
+ ret &= ~mask;
+ ret |= data;
+ writel(ret, keypad->reg_base + addr);
+
+ spin_unlock(&keypad->ske_keypad_lock);
+}
+
+/*
+ * ske_keypad_chip_init: init keypad controller configuration
+ *
+ * Enable Multi key press detection, auto scan mode
+ */
+static int __devinit ske_keypad_chip_init(struct ske_keypad *keypad)
+{
+ u32 value;
+ int timeout = 50;
+
+ /* check SKE_RIS to be 0 */
+ while ((readl(keypad->reg_base + SKE_RIS) != 0x00000000) && timeout--)
+ cpu_relax();
+
+ if (!timeout)
+ return -EINVAL;
+
+ /*
+ * set debounce value
+ * keypad dbounce is configured in DBCR[15:8]
+ * dbounce value in steps of 32/32.768 ms
+ */
+ spin_lock(&keypad->ske_keypad_lock);
+ value = readl(keypad->reg_base + SKE_DBCR);
+ value = value & 0xff;
+ value |= ((keypad->board->debounce_ms * 32000)/32768) << 8;
+ writel(value, keypad->reg_base + SKE_DBCR);
+ spin_unlock(&keypad->ske_keypad_lock);
+
+ /* enable multi key detection */
+ ske_keypad_set_bits(keypad, SKE_CR, 0x0, SKE_KPMLT);
+
+ /*
+ * set up the number of columns
+ * KPCN[5:3] defines no. of keypad columns to be auto scanned
+ */
+ value = (keypad->board->kcol - 1) << 3;
+ ske_keypad_set_bits(keypad, SKE_CR, SKE_KPCN, value);
+
+ /* clear keypad interrupt for auto(and pending SW) scans */
+ ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA | SKE_KPICS);
+
+ /* un-mask keypad interrupts */
+ ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
+
+ /* enable automatic scan */
+ ske_keypad_set_bits(keypad, SKE_CR, 0x0, SKE_KPASEN);
+
+ return 0;
+}
+
+static void ske_keypad_read_data(struct ske_keypad *keypad)
+{
+ struct input_dev *input = keypad->input;
+ u16 status;
+ int col = 0, row = 0, code;
+ int ske_asr, ske_ris, key_pressed, i;
+
+ /*
+ * Read the auto scan registers
+ *
+ * Each SKE_ASRx (x=0 to x=3) contains two row values.
+ * lower byte contains row value for column 2*x,
+ * upper byte contains row value for column 2*x + 1
+ */
+ for (i = 0; i < SKE_NUM_ASRX_REGISTERS; i++) {
+ ske_asr = readl(keypad->reg_base + SKE_ASR0 + (4 * i));
+ if (!ske_asr)
+ continue;
+
+ /* now that ASRx is zero, find out the column x and row y*/
+ if (ske_asr & 0xff) {
+ col = i * 2;
+ status = ske_asr & 0xff;
+ } else {
+ col = (i * 2) + 1;
+ status = (ske_asr & 0xff00) >> 8;
+ }
+
+ /* find out the row */
+ row = __ffs(status);
+
+ code = MATRIX_SCAN_CODE(row, col, SKE_KEYPAD_ROW_SHIFT);
+ ske_ris = readl(keypad->reg_base + SKE_RIS);
+ key_pressed = ske_ris & SKE_KPRISA;
+
+ input_event(input, EV_MSC, MSC_SCAN, code);
+ input_report_key(input, keypad->keymap[code], key_pressed);
+ input_sync(input);
+ }
+}
+
+static irqreturn_t ske_keypad_irq(int irq, void *dev_id)
+{
+ struct ske_keypad *keypad = dev_id;
+ int retries = 20;
+
+ /* disable auto scan interrupt; mask the interrupt generated */
+ ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0);
+ ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA);
+
+ while ((readl(keypad->reg_base + SKE_CR) & SKE_KPASON) && --retries)
+ msleep(5);
+
+ if (retries) {
+ /* SKEx registers are stable and can be read */
+ ske_keypad_read_data(keypad);
+ }
+
+ /* enable auto scan interrupts */
+ ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit ske_keypad_probe(struct platform_device *pdev)
+{
+ const struct ske_keypad_platform_data *plat = pdev->dev.platform_data;
+ struct ske_keypad *keypad;
+ struct input_dev *input;
+ struct resource *res;
+ int irq;
+ int error;
+
+ if (!plat) {
+ dev_err(&pdev->dev, "invalid keypad platform data\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get keypad irq\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "missing platform resources\n");
+ return -EINVAL;
+ }
+
+ keypad = kzalloc(sizeof(struct ske_keypad), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!keypad || !input) {
+ dev_err(&pdev->dev, "failed to allocate keypad memory\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ keypad->irq = irq;
+ keypad->board = plat;
+ keypad->input = input;
+ spin_lock_init(&keypad->ske_keypad_lock);
+
+ if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "failed to request I/O memory\n");
+ error = -EBUSY;
+ goto err_free_mem;
+ }
+
+ keypad->reg_base = ioremap(res->start, resource_size(res));
+ if (!keypad->reg_base) {
+ dev_err(&pdev->dev, "failed to remap I/O memory\n");
+ error = -ENXIO;
+ goto err_free_mem_region;
+ }
+
+ keypad->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(keypad->clk)) {
+ dev_err(&pdev->dev, "failed to get clk\n");
+ error = PTR_ERR(keypad->clk);
+ goto err_iounmap;
+ }
+
+ input->id.bustype = BUS_HOST;
+ input->name = "ux500-ske-keypad";
+ input->dev.parent = &pdev->dev;
+
+ input->keycode = keypad->keymap;
+ input->keycodesize = sizeof(keypad->keymap[0]);
+ input->keycodemax = ARRAY_SIZE(keypad->keymap);
+
+ input_set_capability(input, EV_MSC, MSC_SCAN);
+
+ __set_bit(EV_KEY, input->evbit);
+ if (!plat->no_autorepeat)
+ __set_bit(EV_REP, input->evbit);
+
+ matrix_keypad_build_keymap(plat->keymap_data, SKE_KEYPAD_ROW_SHIFT,
+ input->keycode, input->keybit);
+
+ clk_enable(keypad->clk);
+
+ /* go through board initialization helpers */
+ if (keypad->board->init)
+ keypad->board->init();
+
+ error = ske_keypad_chip_init(keypad);
+ if (error) {
+ dev_err(&pdev->dev, "unable to init keypad hardware\n");
+ goto err_clk_disable;
+ }
+
+ error = request_threaded_irq(keypad->irq, NULL, ske_keypad_irq,
+ IRQF_ONESHOT, "ske-keypad", keypad);
+ if (error) {
+ dev_err(&pdev->dev, "allocate irq %d failed\n", keypad->irq);
+ goto err_clk_disable;
+ }
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&pdev->dev,
+ "unable to register input device: %d\n", error);
+ goto err_free_irq;
+ }
+
+ if (plat->wakeup_enable)
+ device_init_wakeup(&pdev->dev, true);
+
+ platform_set_drvdata(pdev, keypad);
+
+ return 0;
+
+err_free_irq:
+ free_irq(keypad->irq, keypad);
+err_clk_disable:
+ clk_disable(keypad->clk);
+ clk_put(keypad->clk);
+err_iounmap:
+ iounmap(keypad->reg_base);
+err_free_mem_region:
+ release_mem_region(res->start, resource_size(res));
+err_free_mem:
+ input_free_device(input);
+ kfree(keypad);
+ return error;
+}
+
+static int __devexit ske_keypad_remove(struct platform_device *pdev)
+{
+ struct ske_keypad *keypad = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ free_irq(keypad->irq, keypad);
+
+ input_unregister_device(keypad->input);
+
+ clk_disable(keypad->clk);
+ clk_put(keypad->clk);
+
+ if (keypad->board->exit)
+ keypad->board->exit();
+
+ iounmap(keypad->reg_base);
+ release_mem_region(res->start, resource_size(res));
+ kfree(keypad);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ske_keypad_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ske_keypad *keypad = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(irq);
+ else
+ ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0);
+
+ return 0;
+}
+
+static int ske_keypad_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ske_keypad *keypad = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(irq);
+ else
+ ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ske_keypad_dev_pm_ops = {
+ .suspend = ske_keypad_suspend,
+ .resume = ske_keypad_resume,
+};
+#endif
+
+struct platform_driver ske_keypad_driver = {
+ .driver = {
+ .name = "nmk-ske-keypad",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &ske_keypad_dev_pm_ops,
+#endif
+ },
+ .probe = ske_keypad_probe,
+ .remove = __devexit_p(ske_keypad_remove),
+};
+
+static int __init ske_keypad_init(void)
+{
+ return platform_driver_probe(&ske_keypad_driver, ske_keypad_probe);
+}
+module_init(ske_keypad_init);
+
+static void __exit ske_keypad_exit(void)
+{
+ platform_driver_unregister(&ske_keypad_driver);
+}
+module_exit(ske_keypad_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Naveen Kumar <naveen.gaddipati@stericsson.com> / Sundar Iyer <sundar.iyer@stericsson.com>");
+MODULE_DESCRIPTION("Nomadik Scroll-Key-Encoder Keypad Driver");
+MODULE_ALIAS("platform:nomadik-ske-keypad");
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
new file mode 100644
index 000000000000..45bd0977d006
--- /dev/null
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -0,0 +1,318 @@
+/*
+ * OMAP4 Keypad Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * Author: Abraham Arce <x0066660@ti.com>
+ * Initial Code: Syed Rafiuddin <rafiuddin.syed@ti.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/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+#include <plat/omap4-keypad.h>
+
+/* OMAP4 registers */
+#define OMAP4_KBD_REVISION 0x00
+#define OMAP4_KBD_SYSCONFIG 0x10
+#define OMAP4_KBD_SYSSTATUS 0x14
+#define OMAP4_KBD_IRQSTATUS 0x18
+#define OMAP4_KBD_IRQENABLE 0x1C
+#define OMAP4_KBD_WAKEUPENABLE 0x20
+#define OMAP4_KBD_PENDING 0x24
+#define OMAP4_KBD_CTRL 0x28
+#define OMAP4_KBD_DEBOUNCINGTIME 0x2C
+#define OMAP4_KBD_LONGKEYTIME 0x30
+#define OMAP4_KBD_TIMEOUT 0x34
+#define OMAP4_KBD_STATEMACHINE 0x38
+#define OMAP4_KBD_ROWINPUTS 0x3C
+#define OMAP4_KBD_COLUMNOUTPUTS 0x40
+#define OMAP4_KBD_FULLCODE31_0 0x44
+#define OMAP4_KBD_FULLCODE63_32 0x48
+
+/* OMAP4 bit definitions */
+#define OMAP4_DEF_IRQENABLE_EVENTEN (1 << 0)
+#define OMAP4_DEF_IRQENABLE_LONGKEY (1 << 1)
+#define OMAP4_DEF_IRQENABLE_TIMEOUTEN (1 << 2)
+#define OMAP4_DEF_WUP_EVENT_ENA (1 << 0)
+#define OMAP4_DEF_WUP_LONG_KEY_ENA (1 << 1)
+#define OMAP4_DEF_CTRL_NOSOFTMODE (1 << 1)
+#define OMAP4_DEF_CTRLPTVVALUE (1 << 2)
+#define OMAP4_DEF_CTRLPTV (1 << 1)
+
+/* OMAP4 values */
+#define OMAP4_VAL_IRQDISABLE 0x00
+#define OMAP4_VAL_DEBOUNCINGTIME 0x07
+#define OMAP4_VAL_FUNCTIONALCFG 0x1E
+
+#define OMAP4_MASK_IRQSTATUSDISABLE 0xFFFF
+
+struct omap4_keypad {
+ struct input_dev *input;
+
+ void __iomem *base;
+ int irq;
+
+ unsigned int rows;
+ unsigned int cols;
+ unsigned int row_shift;
+ unsigned char key_state[8];
+ unsigned short keymap[];
+};
+
+static void __devinit omap4_keypad_config(struct omap4_keypad *keypad_data)
+{
+ __raw_writel(OMAP4_VAL_FUNCTIONALCFG,
+ keypad_data->base + OMAP4_KBD_CTRL);
+ __raw_writel(OMAP4_VAL_DEBOUNCINGTIME,
+ keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME);
+ __raw_writel(OMAP4_VAL_IRQDISABLE,
+ keypad_data->base + OMAP4_KBD_IRQSTATUS);
+ __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
+ keypad_data->base + OMAP4_KBD_IRQENABLE);
+ __raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA,
+ keypad_data->base + OMAP4_KBD_WAKEUPENABLE);
+}
+
+/* Interrupt handler */
+static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
+{
+ struct omap4_keypad *keypad_data = dev_id;
+ struct input_dev *input_dev = keypad_data->input;
+ unsigned char key_state[ARRAY_SIZE(keypad_data->key_state)];
+ unsigned int col, row, code, changed;
+ u32 *new_state = (u32 *) key_state;
+
+ /* Disable interrupts */
+ __raw_writel(OMAP4_VAL_IRQDISABLE,
+ keypad_data->base + OMAP4_KBD_IRQENABLE);
+
+ *new_state = __raw_readl(keypad_data->base + OMAP4_KBD_FULLCODE31_0);
+ *(new_state + 1) = __raw_readl(keypad_data->base
+ + OMAP4_KBD_FULLCODE63_32);
+
+ for (row = 0; row < keypad_data->rows; row++) {
+ changed = key_state[row] ^ keypad_data->key_state[row];
+ if (!changed)
+ continue;
+
+ for (col = 0; col < keypad_data->cols; col++) {
+ if (changed & (1 << col)) {
+ code = MATRIX_SCAN_CODE(row, col,
+ keypad_data->row_shift);
+ input_event(input_dev, EV_MSC, MSC_SCAN, code);
+ input_report_key(input_dev,
+ keypad_data->keymap[code],
+ key_state[row] & (1 << col));
+ }
+ }
+ }
+
+ input_sync(input_dev);
+
+ memcpy(keypad_data->key_state, key_state,
+ sizeof(keypad_data->key_state));
+
+ /* clear pending interrupts */
+ __raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS),
+ keypad_data->base + OMAP4_KBD_IRQSTATUS);
+
+ /* enable interrupts */
+ __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
+ keypad_data->base + OMAP4_KBD_IRQENABLE);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit omap4_keypad_probe(struct platform_device *pdev)
+{
+ const struct omap4_keypad_platform_data *pdata;
+ struct omap4_keypad *keypad_data;
+ struct input_dev *input_dev;
+ struct resource *res;
+ resource_size_t size;
+ unsigned int row_shift, max_keys;
+ int irq;
+ int error;
+
+ /* platform data */
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data defined\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no base address specified\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "no keyboard irq assigned\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->keymap_data) {
+ dev_err(&pdev->dev, "no keymap data defined\n");
+ return -EINVAL;
+ }
+
+ row_shift = get_count_order(pdata->cols);
+ max_keys = pdata->rows << row_shift;
+
+ keypad_data = kzalloc(sizeof(struct omap4_keypad) +
+ max_keys * sizeof(keypad_data->keymap[0]),
+ GFP_KERNEL);
+ if (!keypad_data) {
+ dev_err(&pdev->dev, "keypad_data memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ size = resource_size(res);
+
+ res = request_mem_region(res->start, size, pdev->name);
+ if (!res) {
+ dev_err(&pdev->dev, "can't request mem region\n");
+ error = -EBUSY;
+ goto err_free_keypad;
+ }
+
+ keypad_data->base = ioremap(res->start, resource_size(res));
+ if (!keypad_data->base) {
+ dev_err(&pdev->dev, "can't ioremap mem resource\n");
+ error = -ENOMEM;
+ goto err_release_mem;
+ }
+
+ keypad_data->irq = irq;
+ keypad_data->row_shift = row_shift;
+ keypad_data->rows = pdata->rows;
+ keypad_data->cols = pdata->cols;
+
+ /* input device allocation */
+ keypad_data->input = input_dev = input_allocate_device();
+ if (!input_dev) {
+ error = -ENOMEM;
+ goto err_unmap;
+ }
+
+ input_dev->name = pdev->name;
+ input_dev->dev.parent = &pdev->dev;
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->id.vendor = 0x0001;
+ input_dev->id.product = 0x0001;
+ input_dev->id.version = 0x0001;
+
+ input_dev->keycode = keypad_data->keymap;
+ input_dev->keycodesize = sizeof(keypad_data->keymap[0]);
+ input_dev->keycodemax = max_keys;
+
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(EV_REP, input_dev->evbit);
+
+ input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+ input_set_drvdata(input_dev, keypad_data);
+
+ matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
+ input_dev->keycode, input_dev->keybit);
+
+ omap4_keypad_config(keypad_data);
+
+ error = request_irq(keypad_data->irq, omap4_keypad_interrupt,
+ IRQF_TRIGGER_RISING,
+ "omap4-keypad", keypad_data);
+ if (error) {
+ dev_err(&pdev->dev, "failed to register interrupt\n");
+ goto err_free_input;
+ }
+
+ error = input_register_device(keypad_data->input);
+ if (error < 0) {
+ dev_err(&pdev->dev, "failed to register input device\n");
+ goto err_free_irq;
+ }
+
+
+ platform_set_drvdata(pdev, keypad_data);
+ return 0;
+
+err_free_irq:
+ free_irq(keypad_data->irq, keypad_data);
+err_free_input:
+ input_free_device(input_dev);
+err_unmap:
+ iounmap(keypad_data->base);
+err_release_mem:
+ release_mem_region(res->start, size);
+err_free_keypad:
+ kfree(keypad_data);
+ return error;
+}
+
+static int __devexit omap4_keypad_remove(struct platform_device *pdev)
+{
+ struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ free_irq(keypad_data->irq, keypad_data);
+ input_unregister_device(keypad_data->input);
+
+ iounmap(keypad_data->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(keypad_data);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver omap4_keypad_driver = {
+ .probe = omap4_keypad_probe,
+ .remove = __devexit_p(omap4_keypad_remove),
+ .driver = {
+ .name = "omap4-keypad",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap4_keypad_init(void)
+{
+ return platform_driver_register(&omap4_keypad_driver);
+}
+module_init(omap4_keypad_init);
+
+static void __exit omap4_keypad_exit(void)
+{
+ platform_driver_unregister(&omap4_keypad_driver);
+}
+module_exit(omap4_keypad_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("OMAP4 Keypad Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap4-keypad");
diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c
new file mode 100644
index 000000000000..b4a81ebfab92
--- /dev/null
+++ b/drivers/input/keyboard/tnetv107x-keypad.c
@@ -0,0 +1,340 @@
+/*
+ * Texas Instruments TNETV107X Keypad Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; 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/errno.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/input/matrix_keypad.h>
+
+#define BITS(x) (BIT(x) - 1)
+
+#define KEYPAD_ROWS 9
+#define KEYPAD_COLS 9
+
+#define DEBOUNCE_MIN 0x400ul
+#define DEBOUNCE_MAX 0x3ffffffful
+
+struct keypad_regs {
+ u32 rev;
+ u32 mode;
+ u32 mask;
+ u32 pol;
+ u32 dclock;
+ u32 rclock;
+ u32 stable_cnt;
+ u32 in_en;
+ u32 out;
+ u32 out_en;
+ u32 in;
+ u32 lock;
+ u32 pres[3];
+};
+
+#define keypad_read(kp, reg) __raw_readl(&(kp)->regs->reg)
+#define keypad_write(kp, reg, val) __raw_writel(val, &(kp)->regs->reg)
+
+struct keypad_data {
+ struct input_dev *input_dev;
+ struct resource *res;
+ struct keypad_regs __iomem *regs;
+ struct clk *clk;
+ struct device *dev;
+ spinlock_t lock;
+ u32 irq_press;
+ u32 irq_release;
+ int rows, cols, row_shift;
+ int debounce_ms, active_low;
+ u32 prev_keys[3];
+ unsigned short keycodes[];
+};
+
+static irqreturn_t keypad_irq(int irq, void *data)
+{
+ struct keypad_data *kp = data;
+ int i, bit, val, row, col, code;
+ unsigned long flags;
+ u32 curr_keys[3];
+ u32 change;
+
+ spin_lock_irqsave(&kp->lock, flags);
+
+ memset(curr_keys, 0, sizeof(curr_keys));
+ if (irq == kp->irq_press)
+ for (i = 0; i < 3; i++)
+ curr_keys[i] = keypad_read(kp, pres[i]);
+
+ for (i = 0; i < 3; i++) {
+ change = curr_keys[i] ^ kp->prev_keys[i];
+
+ while (change) {
+ bit = fls(change) - 1;
+ change ^= BIT(bit);
+ val = curr_keys[i] & BIT(bit);
+ bit += i * 32;
+ row = bit / KEYPAD_COLS;
+ col = bit % KEYPAD_COLS;
+
+ code = MATRIX_SCAN_CODE(row, col, kp->row_shift);
+ input_event(kp->input_dev, EV_MSC, MSC_SCAN, code);
+ input_report_key(kp->input_dev, kp->keycodes[code],
+ val);
+ }
+ }
+ input_sync(kp->input_dev);
+ memcpy(kp->prev_keys, curr_keys, sizeof(curr_keys));
+
+ if (irq == kp->irq_press)
+ keypad_write(kp, lock, 0); /* Allow hardware updates */
+
+ spin_unlock_irqrestore(&kp->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int keypad_start(struct input_dev *dev)
+{
+ struct keypad_data *kp = input_get_drvdata(dev);
+ unsigned long mask, debounce, clk_rate_khz;
+ unsigned long flags;
+
+ clk_enable(kp->clk);
+ clk_rate_khz = clk_get_rate(kp->clk) / 1000;
+
+ spin_lock_irqsave(&kp->lock, flags);
+
+ /* Initialize device registers */
+ keypad_write(kp, mode, 0);
+
+ mask = BITS(kp->rows) << KEYPAD_COLS;
+ mask |= BITS(kp->cols);
+ keypad_write(kp, mask, ~mask);
+
+ keypad_write(kp, pol, kp->active_low ? 0 : 0x3ffff);
+ keypad_write(kp, stable_cnt, 3);
+
+ debounce = kp->debounce_ms * clk_rate_khz;
+ debounce = clamp(debounce, DEBOUNCE_MIN, DEBOUNCE_MAX);
+ keypad_write(kp, dclock, debounce);
+ keypad_write(kp, rclock, 4 * debounce);
+
+ keypad_write(kp, in_en, 1);
+
+ spin_unlock_irqrestore(&kp->lock, flags);
+
+ return 0;
+}
+
+static void keypad_stop(struct input_dev *dev)
+{
+ struct keypad_data *kp = input_get_drvdata(dev);
+
+ synchronize_irq(kp->irq_press);
+ synchronize_irq(kp->irq_release);
+ clk_disable(kp->clk);
+}
+
+static int __devinit keypad_probe(struct platform_device *pdev)
+{
+ const struct matrix_keypad_platform_data *pdata;
+ const struct matrix_keymap_data *keymap_data;
+ struct device *dev = &pdev->dev;
+ struct keypad_data *kp;
+ int error = 0, sz, row_shift;
+ u32 rev = 0;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(dev, "cannot find device data\n");
+ return -EINVAL;
+ }
+
+ keymap_data = pdata->keymap_data;
+ if (!keymap_data) {
+ dev_err(dev, "cannot find keymap data\n");
+ return -EINVAL;
+ }
+
+ row_shift = get_count_order(pdata->num_col_gpios);
+ sz = offsetof(struct keypad_data, keycodes);
+ sz += (pdata->num_row_gpios << row_shift) * sizeof(kp->keycodes[0]);
+ kp = kzalloc(sz, GFP_KERNEL);
+ if (!kp) {
+ dev_err(dev, "cannot allocate device info\n");
+ return -ENOMEM;
+ }
+
+ kp->dev = dev;
+ kp->rows = pdata->num_row_gpios;
+ kp->cols = pdata->num_col_gpios;
+ kp->row_shift = row_shift;
+ platform_set_drvdata(pdev, kp);
+ spin_lock_init(&kp->lock);
+
+ kp->irq_press = platform_get_irq_byname(pdev, "press");
+ kp->irq_release = platform_get_irq_byname(pdev, "release");
+ if (kp->irq_press < 0 || kp->irq_release < 0) {
+ dev_err(dev, "cannot determine device interrupts\n");
+ error = -ENODEV;
+ goto error_res;
+ }
+
+ kp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!kp->res) {
+ dev_err(dev, "cannot determine register area\n");
+ error = -ENODEV;
+ goto error_res;
+ }
+
+ if (!request_mem_region(kp->res->start, resource_size(kp->res),
+ pdev->name)) {
+ dev_err(dev, "cannot claim register memory\n");
+ kp->res = NULL;
+ error = -EINVAL;
+ goto error_res;
+ }
+
+ kp->regs = ioremap(kp->res->start, resource_size(kp->res));
+ if (!kp->regs) {
+ dev_err(dev, "cannot map register memory\n");
+ error = -ENOMEM;
+ goto error_map;
+ }
+
+ kp->clk = clk_get(dev, NULL);
+ if (!kp->clk) {
+ dev_err(dev, "cannot claim device clock\n");
+ error = -EINVAL;
+ goto error_clk;
+ }
+
+ error = request_threaded_irq(kp->irq_press, NULL, keypad_irq, 0,
+ dev_name(dev), kp);
+ if (error < 0) {
+ dev_err(kp->dev, "Could not allocate keypad press key irq\n");
+ goto error_irq_press;
+ }
+
+ error = request_threaded_irq(kp->irq_release, NULL, keypad_irq, 0,
+ dev_name(dev), kp);
+ if (error < 0) {
+ dev_err(kp->dev, "Could not allocate keypad release key irq\n");
+ goto error_irq_release;
+ }
+
+ kp->input_dev = input_allocate_device();
+ if (!kp->input_dev) {
+ dev_err(dev, "cannot allocate input device\n");
+ error = -ENOMEM;
+ goto error_input;
+ }
+ input_set_drvdata(kp->input_dev, kp);
+
+ kp->input_dev->name = pdev->name;
+ kp->input_dev->dev.parent = &pdev->dev;
+ kp->input_dev->open = keypad_start;
+ kp->input_dev->close = keypad_stop;
+ kp->input_dev->evbit[0] = BIT_MASK(EV_KEY);
+ if (!pdata->no_autorepeat)
+ kp->input_dev->evbit[0] |= BIT_MASK(EV_REP);
+
+ clk_enable(kp->clk);
+ rev = keypad_read(kp, rev);
+ kp->input_dev->id.bustype = BUS_HOST;
+ kp->input_dev->id.product = ((rev >> 8) & 0x07);
+ kp->input_dev->id.version = ((rev >> 16) & 0xfff);
+ clk_disable(kp->clk);
+
+ kp->input_dev->keycode = kp->keycodes;
+ kp->input_dev->keycodesize = sizeof(kp->keycodes[0]);
+ kp->input_dev->keycodemax = kp->rows << kp->row_shift;
+
+ matrix_keypad_build_keymap(keymap_data, kp->row_shift, kp->keycodes,
+ kp->input_dev->keybit);
+
+ input_set_capability(kp->input_dev, EV_MSC, MSC_SCAN);
+
+ error = input_register_device(kp->input_dev);
+ if (error < 0) {
+ dev_err(dev, "Could not register input device\n");
+ goto error_reg;
+ }
+
+ return 0;
+
+
+error_reg:
+ input_free_device(kp->input_dev);
+error_input:
+ free_irq(kp->irq_release, kp);
+error_irq_release:
+ free_irq(kp->irq_press, kp);
+error_irq_press:
+ clk_put(kp->clk);
+error_clk:
+ iounmap(kp->regs);
+error_map:
+ release_mem_region(kp->res->start, resource_size(kp->res));
+error_res:
+ platform_set_drvdata(pdev, NULL);
+ kfree(kp);
+ return error;
+}
+
+static int __devexit keypad_remove(struct platform_device *pdev)
+{
+ struct keypad_data *kp = platform_get_drvdata(pdev);
+
+ free_irq(kp->irq_press, kp);
+ free_irq(kp->irq_release, kp);
+ input_unregister_device(kp->input_dev);
+ clk_put(kp->clk);
+ iounmap(kp->regs);
+ release_mem_region(kp->res->start, resource_size(kp->res));
+ platform_set_drvdata(pdev, NULL);
+ kfree(kp);
+
+ return 0;
+}
+
+static struct platform_driver keypad_driver = {
+ .probe = keypad_probe,
+ .remove = __devexit_p(keypad_remove),
+ .driver.name = "tnetv107x-keypad",
+ .driver.owner = THIS_MODULE,
+};
+
+static int __init keypad_init(void)
+{
+ return platform_driver_register(&keypad_driver);
+}
+
+static void __exit keypad_exit(void)
+{
+ platform_driver_unregister(&keypad_driver);
+}
+
+module_init(keypad_init);
+module_exit(keypad_exit);
+
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_DESCRIPTION("TNETV107X Keypad Driver");
+MODULE_ALIAS("platform: tnetv107x-keypad");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c
index fb16b5e5ea13..09bef79d9da1 100644
--- a/drivers/input/keyboard/twl4030_keypad.c
+++ b/drivers/input/keyboard/twl4030_keypad.c
@@ -406,23 +406,22 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev)
if (error) {
dev_info(kp->dbg_dev, "request_irq failed for irq no=%d\n",
kp->irq);
- goto err3;
+ goto err2;
}
/* Enable KP and TO interrupts now. */
reg = (u8) ~(KEYP_IMR1_KP | KEYP_IMR1_TO);
if (twl4030_kpwrite_u8(kp, reg, KEYP_IMR1)) {
error = -EIO;
- goto err4;
+ goto err3;
}
platform_set_drvdata(pdev, kp);
return 0;
-err4:
+err3:
/* mask all events - we don't care about the result */
(void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1);
-err3:
free_irq(kp->irq, NULL);
err2:
input_unregister_device(input);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index b49e23379723..b99b8cbde02f 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -22,6 +22,16 @@ config INPUT_88PM860X_ONKEY
To compile this driver as a module, choose M here: the module
will be called 88pm860x_onkey.
+config INPUT_AB8500_PONKEY
+ tristate "AB8500 Pon (PowerOn) Key"
+ depends on AB8500_CORE
+ help
+ Say Y here to use the PowerOn Key for ST-Ericsson's AB8500
+ Mix-Sig PMIC.
+
+ To compile this driver as a module, choose M here: the module
+ will be called ab8500-ponkey.
+
config INPUT_AD714X
tristate "Analog Devices AD714x Capacitance Touch Sensor"
help
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 19ccca78fa76..1fe1f6c8b737 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -5,6 +5,7 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o
+obj-$(CONFIG_INPUT_AB8500_PONKEY) += ab8500-ponkey.o
obj-$(CONFIG_INPUT_AD714X) += ad714x.o
obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o
obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o
diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c
new file mode 100644
index 000000000000..3d3288a78fdc
--- /dev/null
+++ b/drivers/input/misc/ab8500-ponkey.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *
+ * AB8500 Power-On Key handler
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/slab.h>
+
+/**
+ * struct ab8500_ponkey - ab8500 ponkey information
+ * @input_dev: pointer to input device
+ * @ab8500: ab8500 parent
+ * @irq_dbf: irq number for falling transition
+ * @irq_dbr: irq number for rising transition
+ */
+struct ab8500_ponkey {
+ struct input_dev *idev;
+ struct ab8500 *ab8500;
+ int irq_dbf;
+ int irq_dbr;
+};
+
+/* AB8500 gives us an interrupt when ONKEY is held */
+static irqreturn_t ab8500_ponkey_handler(int irq, void *data)
+{
+ struct ab8500_ponkey *ponkey = data;
+
+ if (irq == ponkey->irq_dbf)
+ input_report_key(ponkey->idev, KEY_POWER, true);
+ else if (irq == ponkey->irq_dbr)
+ input_report_key(ponkey->idev, KEY_POWER, false);
+
+ input_sync(ponkey->idev);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit ab8500_ponkey_probe(struct platform_device *pdev)
+{
+ struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
+ struct ab8500_ponkey *ponkey;
+ struct input_dev *input;
+ int irq_dbf, irq_dbr;
+ int error;
+
+ irq_dbf = platform_get_irq_byname(pdev, "ONKEY_DBF");
+ if (irq_dbf < 0) {
+ dev_err(&pdev->dev, "No IRQ for ONKEY_DBF, error=%d\n", irq_dbf);
+ return irq_dbf;
+ }
+
+ irq_dbr = platform_get_irq_byname(pdev, "ONKEY_DBR");
+ if (irq_dbr < 0) {
+ dev_err(&pdev->dev, "No IRQ for ONKEY_DBR, error=%d\n", irq_dbr);
+ return irq_dbr;
+ }
+
+ ponkey = kzalloc(sizeof(struct ab8500_ponkey), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!ponkey || !input) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ ponkey->idev = input;
+ ponkey->ab8500 = ab8500;
+ ponkey->irq_dbf = irq_dbf;
+ ponkey->irq_dbr = irq_dbr;
+
+ input->name = "AB8500 POn(PowerOn) Key";
+ input->dev.parent = &pdev->dev;
+
+ input_set_capability(input, EV_KEY, KEY_POWER);
+
+ error = request_any_context_irq(ponkey->irq_dbf, ab8500_ponkey_handler,
+ 0, "ab8500-ponkey-dbf", ponkey);
+ if (error < 0) {
+ dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n",
+ ponkey->irq_dbf, error);
+ goto err_free_mem;
+ }
+
+ error = request_any_context_irq(ponkey->irq_dbr, ab8500_ponkey_handler,
+ 0, "ab8500-ponkey-dbr", ponkey);
+ if (error < 0) {
+ dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n",
+ ponkey->irq_dbr, error);
+ goto err_free_dbf_irq;
+ }
+
+ error = input_register_device(ponkey->idev);
+ if (error) {
+ dev_err(ab8500->dev, "Can't register input device: %d\n", error);
+ goto err_free_dbr_irq;
+ }
+
+ platform_set_drvdata(pdev, ponkey);
+ return 0;
+
+err_free_dbr_irq:
+ free_irq(ponkey->irq_dbr, ponkey);
+err_free_dbf_irq:
+ free_irq(ponkey->irq_dbf, ponkey);
+err_free_mem:
+ input_free_device(input);
+ kfree(ponkey);
+
+ return error;
+}
+
+static int __devexit ab8500_ponkey_remove(struct platform_device *pdev)
+{
+ struct ab8500_ponkey *ponkey = platform_get_drvdata(pdev);
+
+ free_irq(ponkey->irq_dbf, ponkey);
+ free_irq(ponkey->irq_dbr, ponkey);
+ input_unregister_device(ponkey->idev);
+ kfree(ponkey);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver ab8500_ponkey_driver = {
+ .driver = {
+ .name = "ab8500-poweron-key",
+ .owner = THIS_MODULE,
+ },
+ .probe = ab8500_ponkey_probe,
+ .remove = __devexit_p(ab8500_ponkey_remove),
+};
+
+static int __init ab8500_ponkey_init(void)
+{
+ return platform_driver_register(&ab8500_ponkey_driver);
+}
+module_init(ab8500_ponkey_init);
+
+static void __exit ab8500_ponkey_exit(void)
+{
+ platform_driver_unregister(&ab8500_ponkey_driver);
+}
+module_exit(ab8500_ponkey_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>");
+MODULE_DESCRIPTION("ST-Ericsson AB8500 Power-ON(Pon) Key driver");
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index 23257652b8e8..0b0e9be63542 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -483,51 +483,88 @@ static void ati_remote2_complete_key(struct urb *urb)
}
static int ati_remote2_getkeycode(struct input_dev *idev,
- unsigned int scancode, unsigned int *keycode)
+ struct input_keymap_entry *ke)
{
struct ati_remote2 *ar2 = input_get_drvdata(idev);
unsigned int mode;
- int index;
+ int offset;
+ unsigned int index;
+ unsigned int scancode;
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ index = ke->index;
+ if (index >= ATI_REMOTE2_MODES *
+ ARRAY_SIZE(ati_remote2_key_table))
+ return -EINVAL;
+
+ mode = ke->index / ARRAY_SIZE(ati_remote2_key_table);
+ offset = ke->index % ARRAY_SIZE(ati_remote2_key_table);
+ scancode = (mode << 8) + ati_remote2_key_table[offset].hw_code;
+ } else {
+ if (input_scancode_to_scalar(ke, &scancode))
+ return -EINVAL;
+
+ mode = scancode >> 8;
+ if (mode > ATI_REMOTE2_PC)
+ return -EINVAL;
+
+ offset = ati_remote2_lookup(scancode & 0xff);
+ if (offset < 0)
+ return -EINVAL;
+
+ index = mode * ARRAY_SIZE(ati_remote2_key_table) + offset;
+ }
- mode = scancode >> 8;
- if (mode > ATI_REMOTE2_PC || !((1 << mode) & ar2->mode_mask))
- return -EINVAL;
+ ke->keycode = ar2->keycode[mode][offset];
+ ke->len = sizeof(scancode);
+ memcpy(&ke->scancode, &scancode, sizeof(scancode));
+ ke->index = index;
- index = ati_remote2_lookup(scancode & 0xFF);
- if (index < 0)
- return -EINVAL;
-
- *keycode = ar2->keycode[mode][index];
return 0;
}
static int ati_remote2_setkeycode(struct input_dev *idev,
- unsigned int scancode, unsigned int keycode)
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode)
{
struct ati_remote2 *ar2 = input_get_drvdata(idev);
- unsigned int mode, old_keycode;
- int index;
-
- mode = scancode >> 8;
- if (mode > ATI_REMOTE2_PC || !((1 << mode) & ar2->mode_mask))
- return -EINVAL;
-
- index = ati_remote2_lookup(scancode & 0xFF);
- if (index < 0)
- return -EINVAL;
+ unsigned int mode;
+ int offset;
+ unsigned int index;
+ unsigned int scancode;
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ if (ke->index >= ATI_REMOTE2_MODES *
+ ARRAY_SIZE(ati_remote2_key_table))
+ return -EINVAL;
+
+ mode = ke->index / ARRAY_SIZE(ati_remote2_key_table);
+ offset = ke->index % ARRAY_SIZE(ati_remote2_key_table);
+ } else {
+ if (input_scancode_to_scalar(ke, &scancode))
+ return -EINVAL;
+
+ mode = scancode >> 8;
+ if (mode > ATI_REMOTE2_PC)
+ return -EINVAL;
+
+ offset = ati_remote2_lookup(scancode & 0xff);
+ if (offset < 0)
+ return -EINVAL;
+ }
- old_keycode = ar2->keycode[mode][index];
- ar2->keycode[mode][index] = keycode;
- __set_bit(keycode, idev->keybit);
+ *old_keycode = ar2->keycode[mode][offset];
+ ar2->keycode[mode][offset] = ke->keycode;
+ __set_bit(ke->keycode, idev->keybit);
for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
- if (ar2->keycode[mode][index] == old_keycode)
+ if (ar2->keycode[mode][index] == *old_keycode)
return 0;
}
}
- __clear_bit(old_keycode, idev->keybit);
+ __clear_bit(*old_keycode, idev->keybit);
return 0;
}
@@ -575,8 +612,8 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2)
idev->open = ati_remote2_open;
idev->close = ati_remote2_close;
- idev->getkeycode = ati_remote2_getkeycode;
- idev->setkeycode = ati_remote2_setkeycode;
+ idev->getkeycode_new = ati_remote2_getkeycode;
+ idev->setkeycode_new = ati_remote2_setkeycode;
idev->name = ar2->name;
idev->phys = ar2->phys;
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
index 2b0eba6619bd..b09c7d127219 100644
--- a/drivers/input/misc/cm109.c
+++ b/drivers/input/misc/cm109.c
@@ -259,7 +259,7 @@ static unsigned short keymap_usbph01(int scancode)
/*
* Keymap for ATCom AU-100
- * http://www.atcom.cn/En_products_AU100.html
+ * http://www.atcom.cn/products.html
* http://www.packetizer.com/products/au100/
* http://www.voip-info.org/wiki/view/AU-100
*
diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c
index bf170f6b4422..f45947190e4f 100644
--- a/drivers/input/misc/powermate.c
+++ b/drivers/input/misc/powermate.c
@@ -280,7 +280,7 @@ static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_dev
pm->configcr = kmalloc(sizeof(*(pm->configcr)), GFP_KERNEL);
if (!pm->configcr)
- return -1;
+ return -ENOMEM;
return 0;
}
diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
index 4f9b2afc24e8..014dd4ad0d4f 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -271,7 +271,7 @@ static struct platform_driver twl4030_vibra_driver = {
.probe = twl4030_vibra_probe,
.remove = __devexit_p(twl4030_vibra_remove),
.driver = {
- .name = "twl4030_codec_vibra",
+ .name = "twl4030-vibra",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &twl4030_vibra_pm_ops,
@@ -291,7 +291,7 @@ static void __exit twl4030_vibra_exit(void)
}
module_exit(twl4030_vibra_exit);
-MODULE_ALIAS("platform:twl4030_codec_vibra");
+MODULE_ALIAS("platform:twl4030-vibra");
MODULE_DESCRIPTION("TWL4030 Vibra driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index c714ca2407f8..bf5fd7f6a313 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -30,6 +30,7 @@ config MOUSE_PS2
<http://w1.894.telia.com/~u89404340/touchpad/index.html>
and a new version of GPM at:
<http://www.geocities.com/dt_or/gpm/gpm.html>
+ <http://xorg.freedesktop.org/archive/individual/driver/>
to take advantage of the advanced features of the touchpad.
If unsure, say Y.
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 48311204ba51..04d9bf320a4f 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -699,7 +699,7 @@ int elantech_init(struct psmouse *psmouse)
psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
if (!etd)
- return -1;
+ return -ENOMEM;
etd->parity[0] = 1;
for (i = 1; i < 256; i++)
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 73a7af2542a8..cd9d0c97e429 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -1584,10 +1584,10 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
if (!new_dev)
return -ENOMEM;
- while (serio->child) {
+ while (!list_empty(&serio->children)) {
if (++retry > 3) {
printk(KERN_WARNING
- "psmouse: failed to destroy child port, "
+ "psmouse: failed to destroy children ports, "
"protocol change aborted.\n");
input_free_device(new_dev);
return -EIO;
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 96b70a43515f..2e300a460556 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -294,7 +294,29 @@ static int synaptics_pt_write(struct serio *serio, unsigned char c)
return 0;
}
-static inline int synaptics_is_pt_packet(unsigned char *buf)
+static int synaptics_pt_start(struct serio *serio)
+{
+ struct psmouse *parent = serio_get_drvdata(serio->parent);
+ struct synaptics_data *priv = parent->private;
+
+ serio_pause_rx(parent->ps2dev.serio);
+ priv->pt_port = serio;
+ serio_continue_rx(parent->ps2dev.serio);
+
+ return 0;
+}
+
+static void synaptics_pt_stop(struct serio *serio)
+{
+ struct psmouse *parent = serio_get_drvdata(serio->parent);
+ struct synaptics_data *priv = parent->private;
+
+ serio_pause_rx(parent->ps2dev.serio);
+ priv->pt_port = NULL;
+ serio_continue_rx(parent->ps2dev.serio);
+}
+
+static int synaptics_is_pt_packet(unsigned char *buf)
{
return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
}
@@ -315,9 +337,8 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet
static void synaptics_pt_activate(struct psmouse *psmouse)
{
- struct serio *ptport = psmouse->ps2dev.serio->child;
- struct psmouse *child = serio_get_drvdata(ptport);
struct synaptics_data *priv = psmouse->private;
+ struct psmouse *child = serio_get_drvdata(priv->pt_port);
/* adjust the touchpad to child's choice of protocol */
if (child) {
@@ -345,6 +366,8 @@ static void synaptics_pt_create(struct psmouse *psmouse)
strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
serio->write = synaptics_pt_write;
+ serio->start = synaptics_pt_start;
+ serio->stop = synaptics_pt_stop;
serio->parent = psmouse->ps2dev.serio;
psmouse->pt_activate = synaptics_pt_activate;
@@ -578,9 +601,10 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
if (unlikely(priv->pkt_type == SYN_NEWABS))
priv->pkt_type = synaptics_detect_pkt_type(psmouse);
- if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) {
- if (psmouse->ps2dev.serio->child)
- synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet);
+ if (SYN_CAP_PASS_THROUGH(priv->capabilities) &&
+ synaptics_is_pt_packet(psmouse->packet)) {
+ if (priv->pt_port)
+ synaptics_pass_pt_packet(priv->pt_port, psmouse->packet);
} else
synaptics_process_packet(psmouse);
@@ -731,7 +755,7 @@ int synaptics_init(struct psmouse *psmouse)
psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL);
if (!priv)
- return -1;
+ return -ENOMEM;
psmouse_reset(psmouse);
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index b6aa7d20d8a3..613a3652f98f 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -110,6 +110,8 @@ struct synaptics_data {
unsigned char pkt_type; /* packet type - old, new, etc */
unsigned char mode; /* current mode byte */
int scroll;
+
+ struct serio *pt_port; /* Pass-through serio port */
};
void synaptics_module_init(void);
diff --git a/drivers/input/mouse/touchkit_ps2.c b/drivers/input/mouse/touchkit_ps2.c
index 88121c59c3cc..1fd8f5e192f9 100644
--- a/drivers/input/mouse/touchkit_ps2.c
+++ b/drivers/input/mouse/touchkit_ps2.c
@@ -21,8 +21,8 @@
*
* Based upon touchkitusb.c
*
- * Vendor documentation is available in support section of:
- * http://www.egalax.com.tw/
+ * Vendor documentation is available at:
+ * http://home.eeti.com.tw/web20/drivers/Software%20Programming%20Guide_v2.0.pdf
*/
#include <linux/kernel.h>
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index 0643e49ca603..54b2fa892e19 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -303,7 +303,7 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL);
if (!psmouse->private)
- return -1;
+ return -ENOMEM;
psmouse->vendor = "IBM";
psmouse->name = "TrackPoint";
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 31ec7265aac6..2a00ddf4f23a 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -867,7 +867,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
spin_lock_init(&mousedev->client_lock);
mutex_init(&mousedev->mutex);
lockdep_set_subclass(&mousedev->mutex,
- minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0);
+ minor == MOUSEDEV_MIX ? SINGLE_DEPTH_NESTING : 0);
init_waitqueue_head(&mousedev->wait);
if (minor == MOUSEDEV_MIX)
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index 3bfe8fafc6ad..6256233d2bfb 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -226,4 +226,13 @@ config SERIO_AMS_DELTA
To compile this driver as a module, choose M here;
the module will be called ams_delta_serio.
+config SERIO_PS2MULT
+ tristate "TQC PS/2 multiplexer"
+ help
+ Say Y here if you have the PS/2 line multiplexer like the one
+ present on TQC boads.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ps2mult.
+
endif
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 84c80bf7185e..dbbe37616c92 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o
obj-$(CONFIG_HP_SDC) += hp_sdc.o
obj-$(CONFIG_HIL_MLC) += hp_sdc_mlc.o hil_mlc.o
obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
+obj-$(CONFIG_SERIO_PS2MULT) += ps2mult.o
obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
obj-$(CONFIG_SERIO_LIBPS2) += libps2.o
obj-$(CONFIG_SERIO_RAW) += serio_raw.o
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index f58513160480..18db5a8c7478 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -1063,7 +1063,7 @@ static long i8042_panic_blink(int state)
#ifdef CONFIG_X86
static void i8042_dritek_enable(void)
{
- char param = 0x90;
+ unsigned char param = 0x90;
int error;
error = i8042_command(&param, 0x1059);
diff --git a/drivers/input/serio/ps2mult.c b/drivers/input/serio/ps2mult.c
new file mode 100644
index 000000000000..6bce22e4e495
--- /dev/null
+++ b/drivers/input/serio/ps2mult.c
@@ -0,0 +1,318 @@
+/*
+ * TQC PS/2 Multiplexer driver
+ *
+ * Copyright (C) 2010 Dmitry Eremin-Solenikov
+ *
+ * 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/slab.h>
+#include <linux/module.h>
+#include <linux/serio.h>
+
+MODULE_AUTHOR("Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>");
+MODULE_DESCRIPTION("TQC PS/2 Multiplexer driver");
+MODULE_LICENSE("GPL");
+
+#define PS2MULT_KB_SELECTOR 0xA0
+#define PS2MULT_MS_SELECTOR 0xA1
+#define PS2MULT_ESCAPE 0x7D
+#define PS2MULT_BSYNC 0x7E
+#define PS2MULT_SESSION_START 0x55
+#define PS2MULT_SESSION_END 0x56
+
+struct ps2mult_port {
+ struct serio *serio;
+ unsigned char sel;
+ bool registered;
+};
+
+#define PS2MULT_NUM_PORTS 2
+#define PS2MULT_KBD_PORT 0
+#define PS2MULT_MOUSE_PORT 1
+
+struct ps2mult {
+ struct serio *mx_serio;
+ struct ps2mult_port ports[PS2MULT_NUM_PORTS];
+
+ spinlock_t lock;
+ struct ps2mult_port *in_port;
+ struct ps2mult_port *out_port;
+ bool escape;
+};
+
+/* First MUST come PS2MULT_NUM_PORTS selectors */
+static const unsigned char ps2mult_controls[] = {
+ PS2MULT_KB_SELECTOR, PS2MULT_MS_SELECTOR,
+ PS2MULT_ESCAPE, PS2MULT_BSYNC,
+ PS2MULT_SESSION_START, PS2MULT_SESSION_END,
+};
+
+static const struct serio_device_id ps2mult_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_PS2MULT,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, ps2mult_serio_ids);
+
+static void ps2mult_select_port(struct ps2mult *psm, struct ps2mult_port *port)
+{
+ struct serio *mx_serio = psm->mx_serio;
+
+ serio_write(mx_serio, port->sel);
+ psm->out_port = port;
+ dev_dbg(&mx_serio->dev, "switched to sel %02x\n", port->sel);
+}
+
+static int ps2mult_serio_write(struct serio *serio, unsigned char data)
+{
+ struct serio *mx_port = serio->parent;
+ struct ps2mult *psm = serio_get_drvdata(mx_port);
+ struct ps2mult_port *port = serio->port_data;
+ bool need_escape;
+ unsigned long flags;
+
+ spin_lock_irqsave(&psm->lock, flags);
+
+ if (psm->out_port != port)
+ ps2mult_select_port(psm, port);
+
+ need_escape = memchr(ps2mult_controls, data, sizeof(ps2mult_controls));
+
+ dev_dbg(&serio->dev,
+ "write: %s%02x\n", need_escape ? "ESC " : "", data);
+
+ if (need_escape)
+ serio_write(mx_port, PS2MULT_ESCAPE);
+
+ serio_write(mx_port, data);
+
+ spin_unlock_irqrestore(&psm->lock, flags);
+
+ return 0;
+}
+
+static int ps2mult_serio_start(struct serio *serio)
+{
+ struct ps2mult *psm = serio_get_drvdata(serio->parent);
+ struct ps2mult_port *port = serio->port_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&psm->lock, flags);
+ port->registered = true;
+ spin_unlock_irqrestore(&psm->lock, flags);
+
+ return 0;
+}
+
+static void ps2mult_serio_stop(struct serio *serio)
+{
+ struct ps2mult *psm = serio_get_drvdata(serio->parent);
+ struct ps2mult_port *port = serio->port_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&psm->lock, flags);
+ port->registered = false;
+ spin_unlock_irqrestore(&psm->lock, flags);
+}
+
+static int ps2mult_create_port(struct ps2mult *psm, int i)
+{
+ struct serio *mx_serio = psm->mx_serio;
+ struct serio *serio;
+
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!serio)
+ return -ENOMEM;
+
+ strlcpy(serio->name, "TQC PS/2 Multiplexer", sizeof(serio->name));
+ snprintf(serio->phys, sizeof(serio->phys),
+ "%s/port%d", mx_serio->phys, i);
+ serio->id.type = SERIO_8042;
+ serio->write = ps2mult_serio_write;
+ serio->start = ps2mult_serio_start;
+ serio->stop = ps2mult_serio_stop;
+ serio->parent = psm->mx_serio;
+ serio->port_data = &psm->ports[i];
+
+ psm->ports[i].serio = serio;
+
+ return 0;
+}
+
+static void ps2mult_reset(struct ps2mult *psm)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&psm->lock, flags);
+
+ serio_write(psm->mx_serio, PS2MULT_SESSION_END);
+ serio_write(psm->mx_serio, PS2MULT_SESSION_START);
+
+ ps2mult_select_port(psm, &psm->ports[PS2MULT_KBD_PORT]);
+
+ spin_unlock_irqrestore(&psm->lock, flags);
+}
+
+static int ps2mult_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct ps2mult *psm;
+ int i;
+ int error;
+
+ if (!serio->write)
+ return -EINVAL;
+
+ psm = kzalloc(sizeof(*psm), GFP_KERNEL);
+ if (!psm)
+ return -ENOMEM;
+
+ spin_lock_init(&psm->lock);
+ psm->mx_serio = serio;
+
+ for (i = 0; i < PS2MULT_NUM_PORTS; i++) {
+ psm->ports[i].sel = ps2mult_controls[i];
+ error = ps2mult_create_port(psm, i);
+ if (error)
+ goto err_out;
+ }
+
+ psm->in_port = psm->out_port = &psm->ports[PS2MULT_KBD_PORT];
+
+ serio_set_drvdata(serio, psm);
+ error = serio_open(serio, drv);
+ if (error)
+ goto err_out;
+
+ ps2mult_reset(psm);
+
+ for (i = 0; i < PS2MULT_NUM_PORTS; i++) {
+ struct serio *s = psm->ports[i].serio;
+
+ dev_info(&serio->dev, "%s port at %s\n", s->name, serio->phys);
+ serio_register_port(s);
+ }
+
+ return 0;
+
+err_out:
+ while (--i >= 0)
+ kfree(psm->ports[i].serio);
+ kfree(serio);
+ return error;
+}
+
+static void ps2mult_disconnect(struct serio *serio)
+{
+ struct ps2mult *psm = serio_get_drvdata(serio);
+
+ /* Note that serio core already take care of children ports */
+ serio_write(serio, PS2MULT_SESSION_END);
+ serio_close(serio);
+ kfree(psm);
+
+ serio_set_drvdata(serio, NULL);
+}
+
+static int ps2mult_reconnect(struct serio *serio)
+{
+ struct ps2mult *psm = serio_get_drvdata(serio);
+
+ ps2mult_reset(psm);
+
+ return 0;
+}
+
+static irqreturn_t ps2mult_interrupt(struct serio *serio,
+ unsigned char data, unsigned int dfl)
+{
+ struct ps2mult *psm = serio_get_drvdata(serio);
+ struct ps2mult_port *in_port;
+ unsigned long flags;
+
+ dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, dfl);
+
+ spin_lock_irqsave(&psm->lock, flags);
+
+ if (psm->escape) {
+ psm->escape = false;
+ in_port = psm->in_port;
+ if (in_port->registered)
+ serio_interrupt(in_port->serio, data, dfl);
+ goto out;
+ }
+
+ switch (data) {
+ case PS2MULT_ESCAPE:
+ dev_dbg(&serio->dev, "ESCAPE\n");
+ psm->escape = true;
+ break;
+
+ case PS2MULT_BSYNC:
+ dev_dbg(&serio->dev, "BSYNC\n");
+ psm->in_port = psm->out_port;
+ break;
+
+ case PS2MULT_SESSION_START:
+ dev_dbg(&serio->dev, "SS\n");
+ break;
+
+ case PS2MULT_SESSION_END:
+ dev_dbg(&serio->dev, "SE\n");
+ break;
+
+ case PS2MULT_KB_SELECTOR:
+ dev_dbg(&serio->dev, "KB\n");
+ psm->in_port = &psm->ports[PS2MULT_KBD_PORT];
+ break;
+
+ case PS2MULT_MS_SELECTOR:
+ dev_dbg(&serio->dev, "MS\n");
+ psm->in_port = &psm->ports[PS2MULT_MOUSE_PORT];
+ break;
+
+ default:
+ in_port = psm->in_port;
+ if (in_port->registered)
+ serio_interrupt(in_port->serio, data, dfl);
+ break;
+ }
+
+ out:
+ spin_unlock_irqrestore(&psm->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static struct serio_driver ps2mult_drv = {
+ .driver = {
+ .name = "ps2mult",
+ },
+ .description = "TQC PS/2 Multiplexer driver",
+ .id_table = ps2mult_serio_ids,
+ .interrupt = ps2mult_interrupt,
+ .connect = ps2mult_connect,
+ .disconnect = ps2mult_disconnect,
+ .reconnect = ps2mult_reconnect,
+};
+
+static int __init ps2mult_init(void)
+{
+ return serio_register_driver(&ps2mult_drv);
+}
+
+static void __exit ps2mult_exit(void)
+{
+ serio_unregister_driver(&ps2mult_drv);
+}
+
+module_init(ps2mult_init);
+module_exit(ps2mult_exit);
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index c3b626e9eae7..405bf214527c 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -37,7 +37,6 @@
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
-#include <linux/freezer.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Serio abstraction core");
@@ -56,7 +55,7 @@ static struct bus_type serio_bus;
static void serio_add_port(struct serio *serio);
static int serio_reconnect_port(struct serio *serio);
static void serio_disconnect_port(struct serio *serio);
-static void serio_reconnect_chain(struct serio *serio);
+static void serio_reconnect_subtree(struct serio *serio);
static void serio_attach_driver(struct serio_driver *drv);
static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
@@ -152,7 +151,7 @@ static void serio_find_driver(struct serio *serio)
enum serio_event_type {
SERIO_RESCAN_PORT,
SERIO_RECONNECT_PORT,
- SERIO_RECONNECT_CHAIN,
+ SERIO_RECONNECT_SUBTREE,
SERIO_REGISTER_PORT,
SERIO_ATTACH_DRIVER,
};
@@ -292,8 +291,8 @@ static void serio_handle_event(void)
serio_find_driver(event->object);
break;
- case SERIO_RECONNECT_CHAIN:
- serio_reconnect_chain(event->object);
+ case SERIO_RECONNECT_SUBTREE:
+ serio_reconnect_subtree(event->object);
break;
case SERIO_ATTACH_DRIVER:
@@ -330,12 +329,10 @@ static void serio_remove_pending_events(void *object)
}
/*
- * Destroy child serio port (if any) that has not been fully registered yet.
+ * Locate child serio port (if any) that has not been fully registered yet.
*
- * Note that we rely on the fact that port can have only one child and therefore
- * only one child registration request can be pending. Additionally, children
- * are registered by driver's connect() handler so there can't be a grandchild
- * pending registration together with a child.
+ * Children are registered by driver's connect() handler so there can't be a
+ * grandchild pending registration together with a child.
*/
static struct serio *serio_get_pending_child(struct serio *parent)
{
@@ -449,7 +446,7 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
if (!strncmp(buf, "none", count)) {
serio_disconnect_port(serio);
} else if (!strncmp(buf, "reconnect", count)) {
- serio_reconnect_chain(serio);
+ serio_reconnect_subtree(serio);
} else if (!strncmp(buf, "rescan", count)) {
serio_disconnect_port(serio);
serio_find_driver(serio);
@@ -516,6 +513,8 @@ static void serio_init_port(struct serio *serio)
__module_get(THIS_MODULE);
INIT_LIST_HEAD(&serio->node);
+ INIT_LIST_HEAD(&serio->child_node);
+ INIT_LIST_HEAD(&serio->children);
spin_lock_init(&serio->lock);
mutex_init(&serio->drv_mutex);
device_initialize(&serio->dev);
@@ -538,12 +537,13 @@ static void serio_init_port(struct serio *serio)
*/
static void serio_add_port(struct serio *serio)
{
+ struct serio *parent = serio->parent;
int error;
- if (serio->parent) {
- serio_pause_rx(serio->parent);
- serio->parent->child = serio;
- serio_continue_rx(serio->parent);
+ if (parent) {
+ serio_pause_rx(parent);
+ list_add_tail(&serio->child_node, &parent->children);
+ serio_continue_rx(parent);
}
list_add_tail(&serio->node, &serio_list);
@@ -559,15 +559,14 @@ static void serio_add_port(struct serio *serio)
}
/*
- * serio_destroy_port() completes deregistration process and removes
+ * serio_destroy_port() completes unregistration process and removes
* port from the system
*/
static void serio_destroy_port(struct serio *serio)
{
struct serio *child;
- child = serio_get_pending_child(serio);
- if (child) {
+ while ((child = serio_get_pending_child(serio)) != NULL) {
serio_remove_pending_events(child);
put_device(&child->dev);
}
@@ -577,7 +576,7 @@ static void serio_destroy_port(struct serio *serio)
if (serio->parent) {
serio_pause_rx(serio->parent);
- serio->parent->child = NULL;
+ list_del_init(&serio->child_node);
serio_continue_rx(serio->parent);
serio->parent = NULL;
}
@@ -609,46 +608,82 @@ static int serio_reconnect_port(struct serio *serio)
}
/*
- * Reconnect serio port and all its children (re-initialize attached devices)
+ * Reconnect serio port and all its children (re-initialize attached
+ * devices).
*/
-static void serio_reconnect_chain(struct serio *serio)
+static void serio_reconnect_subtree(struct serio *root)
{
+ struct serio *s = root;
+ int error;
+
do {
- if (serio_reconnect_port(serio)) {
- /* Ok, old children are now gone, we are done */
- break;
+ error = serio_reconnect_port(s);
+ if (!error) {
+ /*
+ * Reconnect was successful, move on to do the
+ * first child.
+ */
+ if (!list_empty(&s->children)) {
+ s = list_first_entry(&s->children,
+ struct serio, child_node);
+ continue;
+ }
}
- serio = serio->child;
- } while (serio);
+
+ /*
+ * Either it was a leaf node or reconnect failed and it
+ * became a leaf node. Continue reconnecting starting with
+ * the next sibling of the parent node.
+ */
+ while (s != root) {
+ struct serio *parent = s->parent;
+
+ if (!list_is_last(&s->child_node, &parent->children)) {
+ s = list_entry(s->child_node.next,
+ struct serio, child_node);
+ break;
+ }
+
+ s = parent;
+ }
+ } while (s != root);
}
/*
* serio_disconnect_port() unbinds a port from its driver. As a side effect
- * all child ports are unbound and destroyed.
+ * all children ports are unbound and destroyed.
*/
static void serio_disconnect_port(struct serio *serio)
{
- struct serio *s, *parent;
+ struct serio *s = serio;
+
+ /*
+ * Children ports should be disconnected and destroyed
+ * first; we travel the tree in depth-first order.
+ */
+ while (!list_empty(&serio->children)) {
+
+ /* Locate a leaf */
+ while (!list_empty(&s->children))
+ s = list_first_entry(&s->children,
+ struct serio, child_node);
- if (serio->child) {
/*
- * Children ports should be disconnected and destroyed
- * first, staring with the leaf one, since we don't want
- * to do recursion
+ * Prune this leaf node unless it is the one we
+ * started with.
*/
- for (s = serio; s->child; s = s->child)
- /* empty */;
-
- do {
- parent = s->parent;
+ if (s != serio) {
+ struct serio *parent = s->parent;
device_release_driver(&s->dev);
serio_destroy_port(s);
- } while ((s = parent) != serio);
+
+ s = parent;
+ }
}
/*
- * Ok, no children left, now disconnect this port
+ * OK, no children left, now disconnect this port.
*/
device_release_driver(&serio->dev);
}
@@ -661,7 +696,7 @@ EXPORT_SYMBOL(serio_rescan);
void serio_reconnect(struct serio *serio)
{
- serio_queue_event(serio, NULL, SERIO_RECONNECT_CHAIN);
+ serio_queue_event(serio, NULL, SERIO_RECONNECT_SUBTREE);
}
EXPORT_SYMBOL(serio_reconnect);
@@ -689,14 +724,16 @@ void serio_unregister_port(struct serio *serio)
EXPORT_SYMBOL(serio_unregister_port);
/*
- * Safely unregisters child port if one is present.
+ * Safely unregisters children ports if they are present.
*/
void serio_unregister_child_port(struct serio *serio)
{
+ struct serio *s, *next;
+
mutex_lock(&serio_mutex);
- if (serio->child) {
- serio_disconnect_port(serio->child);
- serio_destroy_port(serio->child);
+ list_for_each_entry_safe(s, next, &serio->children, child_node) {
+ serio_disconnect_port(s);
+ serio_destroy_port(s);
}
mutex_unlock(&serio_mutex);
}
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
index 014248344763..a29a7812bd46 100644
--- a/drivers/input/sparse-keymap.c
+++ b/drivers/input/sparse-keymap.c
@@ -22,6 +22,37 @@ MODULE_DESCRIPTION("Generic support for sparse keymaps");
MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.1");
+static unsigned int sparse_keymap_get_key_index(struct input_dev *dev,
+ const struct key_entry *k)
+{
+ struct key_entry *key;
+ unsigned int idx = 0;
+
+ for (key = dev->keycode; key->type != KE_END; key++) {
+ if (key->type == KE_KEY) {
+ if (key == k)
+ break;
+ idx++;
+ }
+ }
+
+ return idx;
+}
+
+static struct key_entry *sparse_keymap_entry_by_index(struct input_dev *dev,
+ unsigned int index)
+{
+ struct key_entry *key;
+ unsigned int key_cnt = 0;
+
+ for (key = dev->keycode; key->type != KE_END; key++)
+ if (key->type == KE_KEY)
+ if (key_cnt++ == index)
+ return key;
+
+ return NULL;
+}
+
/**
* sparse_keymap_entry_from_scancode - perform sparse keymap lookup
* @dev: Input device using sparse keymap
@@ -64,16 +95,36 @@ struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
}
EXPORT_SYMBOL(sparse_keymap_entry_from_keycode);
+static struct key_entry *sparse_keymap_locate(struct input_dev *dev,
+ const struct input_keymap_entry *ke)
+{
+ struct key_entry *key;
+ unsigned int scancode;
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX)
+ key = sparse_keymap_entry_by_index(dev, ke->index);
+ else if (input_scancode_to_scalar(ke, &scancode) == 0)
+ key = sparse_keymap_entry_from_scancode(dev, scancode);
+ else
+ key = NULL;
+
+ return key;
+}
+
static int sparse_keymap_getkeycode(struct input_dev *dev,
- unsigned int scancode,
- unsigned int *keycode)
+ struct input_keymap_entry *ke)
{
const struct key_entry *key;
if (dev->keycode) {
- key = sparse_keymap_entry_from_scancode(dev, scancode);
+ key = sparse_keymap_locate(dev, ke);
if (key && key->type == KE_KEY) {
- *keycode = key->keycode;
+ ke->keycode = key->keycode;
+ if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
+ ke->index =
+ sparse_keymap_get_key_index(dev, key);
+ ke->len = sizeof(key->code);
+ memcpy(ke->scancode, &key->code, sizeof(key->code));
return 0;
}
}
@@ -82,20 +133,19 @@ static int sparse_keymap_getkeycode(struct input_dev *dev,
}
static int sparse_keymap_setkeycode(struct input_dev *dev,
- unsigned int scancode,
- unsigned int keycode)
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode)
{
struct key_entry *key;
- int old_keycode;
if (dev->keycode) {
- key = sparse_keymap_entry_from_scancode(dev, scancode);
+ key = sparse_keymap_locate(dev, ke);
if (key && key->type == KE_KEY) {
- old_keycode = key->keycode;
- key->keycode = keycode;
- set_bit(keycode, dev->keybit);
- if (!sparse_keymap_entry_from_keycode(dev, old_keycode))
- clear_bit(old_keycode, dev->keybit);
+ *old_keycode = key->keycode;
+ key->keycode = ke->keycode;
+ set_bit(ke->keycode, dev->keybit);
+ if (!sparse_keymap_entry_from_keycode(dev, *old_keycode))
+ clear_bit(*old_keycode, dev->keybit);
return 0;
}
}
@@ -159,15 +209,14 @@ int sparse_keymap_setup(struct input_dev *dev,
dev->keycode = map;
dev->keycodemax = map_size;
- dev->getkeycode = sparse_keymap_getkeycode;
- dev->setkeycode = sparse_keymap_setkeycode;
+ dev->getkeycode_new = sparse_keymap_getkeycode;
+ dev->setkeycode_new = sparse_keymap_setkeycode;
return 0;
err_out:
kfree(map);
return error;
-
}
EXPORT_SYMBOL(sparse_keymap_setup);
diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig
index effb49ea24aa..58a87755b936 100644
--- a/drivers/input/tablet/Kconfig
+++ b/drivers/input/tablet/Kconfig
@@ -49,6 +49,17 @@ config TABLET_USB_GTCO
To compile this driver as a module, choose M here: the
module will be called gtco.
+config TABLET_USB_HANWANG
+ tristate "Hanwang Art Master III tablet support (USB)"
+ depends on USB_ARCH_HAS_HCD
+ select USB
+ help
+ Say Y here if you want to use the USB version of the Hanwang Art
+ Master III tablet.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hanwang.
+
config TABLET_USB_KBTAB
tristate "KB Gear JamStudio tablet support (USB)"
depends on USB_ARCH_HAS_HCD
diff --git a/drivers/input/tablet/Makefile b/drivers/input/tablet/Makefile
index ce8b9a9cfa40..3f6c25220638 100644
--- a/drivers/input/tablet/Makefile
+++ b/drivers/input/tablet/Makefile
@@ -8,5 +8,6 @@ wacom-objs := wacom_wac.o wacom_sys.o
obj-$(CONFIG_TABLET_USB_ACECAD) += acecad.o
obj-$(CONFIG_TABLET_USB_AIPTEK) += aiptek.o
obj-$(CONFIG_TABLET_USB_GTCO) += gtco.o
+obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o
obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o
obj-$(CONFIG_TABLET_USB_WACOM) += wacom.o
diff --git a/drivers/input/tablet/hanwang.c b/drivers/input/tablet/hanwang.c
new file mode 100644
index 000000000000..6504b627b234
--- /dev/null
+++ b/drivers/input/tablet/hanwang.c
@@ -0,0 +1,446 @@
+/*
+ * USB Hanwang tablet support
+ *
+ * Copyright (c) 2010 Xing Wei <weixing@hanwang.com.cn>
+ *
+ */
+
+/*
+ * 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/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+
+#define DRIVER_AUTHOR "Xing Wei <weixing@hanwang.com.cn>"
+#define DRIVER_DESC "USB Hanwang tablet driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_HANWANG 0x0b57
+#define HANWANG_TABLET_INT_CLASS 0x0003
+#define HANWANG_TABLET_INT_SUB_CLASS 0x0001
+#define HANWANG_TABLET_INT_PROTOCOL 0x0002
+
+#define ART_MASTER_PKGLEN_MAX 10
+
+/* device IDs */
+#define STYLUS_DEVICE_ID 0x02
+#define TOUCH_DEVICE_ID 0x03
+#define CURSOR_DEVICE_ID 0x06
+#define ERASER_DEVICE_ID 0x0A
+#define PAD_DEVICE_ID 0x0F
+
+/* match vendor and interface info */
+#define HANWANG_TABLET_DEVICE(vend, cl, sc, pr) \
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR \
+ | USB_DEVICE_ID_MATCH_INT_INFO, \
+ .idVendor = (vend), \
+ .bInterfaceClass = (cl), \
+ .bInterfaceSubClass = (sc), \
+ .bInterfaceProtocol = (pr)
+
+enum hanwang_tablet_type {
+ HANWANG_ART_MASTER_III,
+ HANWANG_ART_MASTER_HD,
+};
+
+struct hanwang {
+ unsigned char *data;
+ dma_addr_t data_dma;
+ struct input_dev *dev;
+ struct usb_device *usbdev;
+ struct urb *irq;
+ const struct hanwang_features *features;
+ unsigned int current_tool;
+ unsigned int current_id;
+ char name[64];
+ char phys[32];
+};
+
+struct hanwang_features {
+ unsigned short pid;
+ char *name;
+ enum hanwang_tablet_type type;
+ int pkg_len;
+ int max_x;
+ int max_y;
+ int max_tilt_x;
+ int max_tilt_y;
+ int max_pressure;
+};
+
+static const struct hanwang_features features_array[] = {
+ { 0x8528, "Hanwang Art Master III 0906", HANWANG_ART_MASTER_III,
+ ART_MASTER_PKGLEN_MAX, 0x5757, 0x3692, 0x3f, 0x7f, 2048 },
+ { 0x8529, "Hanwang Art Master III 0604", HANWANG_ART_MASTER_III,
+ ART_MASTER_PKGLEN_MAX, 0x3d84, 0x2672, 0x3f, 0x7f, 2048 },
+ { 0x852a, "Hanwang Art Master III 1308", HANWANG_ART_MASTER_III,
+ ART_MASTER_PKGLEN_MAX, 0x7f00, 0x4f60, 0x3f, 0x7f, 2048 },
+ { 0x8401, "Hanwang Art Master HD 5012", HANWANG_ART_MASTER_HD,
+ ART_MASTER_PKGLEN_MAX, 0x678e, 0x4150, 0x3f, 0x7f, 1024 },
+};
+
+static const int hw_eventtypes[] = {
+ EV_KEY, EV_ABS, EV_MSC,
+};
+
+static const int hw_absevents[] = {
+ ABS_X, ABS_Y, ABS_TILT_X, ABS_TILT_Y, ABS_WHEEL,
+ ABS_RX, ABS_RY, ABS_PRESSURE, ABS_MISC,
+};
+
+static const int hw_btnevents[] = {
+ BTN_STYLUS, BTN_STYLUS2, BTN_TOOL_PEN, BTN_TOOL_RUBBER,
+ BTN_TOOL_MOUSE, BTN_TOOL_FINGER,
+ BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8,
+};
+
+static const int hw_mscevents[] = {
+ MSC_SERIAL,
+};
+
+static void hanwang_parse_packet(struct hanwang *hanwang)
+{
+ unsigned char *data = hanwang->data;
+ struct input_dev *input_dev = hanwang->dev;
+ struct usb_device *dev = hanwang->usbdev;
+ enum hanwang_tablet_type type = hanwang->features->type;
+ int i;
+ u16 x, y, p;
+
+ switch (data[0]) {
+ case 0x02: /* data packet */
+ switch (data[1]) {
+ case 0x80: /* tool prox out */
+ hanwang->current_id = 0;
+ input_report_key(input_dev, hanwang->current_tool, 0);
+ break;
+
+ case 0xc2: /* first time tool prox in */
+ switch (data[3] & 0xf0) {
+ case 0x20: /* art_master III */
+ case 0x30: /* art_master_HD */
+ hanwang->current_id = STYLUS_DEVICE_ID;
+ hanwang->current_tool = BTN_TOOL_PEN;
+ input_report_key(input_dev, BTN_TOOL_PEN, 1);
+ break;
+ case 0xa0: /* art_master III */
+ case 0xb0: /* art_master_HD */
+ hanwang->current_id = ERASER_DEVICE_ID;
+ hanwang->current_tool = BTN_TOOL_RUBBER;
+ input_report_key(input_dev, BTN_TOOL_RUBBER, 1);
+ break;
+ default:
+ hanwang->current_id = 0;
+ dev_dbg(&dev->dev,
+ "unknown tablet tool %02x ", data[0]);
+ break;
+ }
+ break;
+
+ default: /* tool data packet */
+ x = (data[2] << 8) | data[3];
+ y = (data[4] << 8) | data[5];
+
+ switch (type) {
+ case HANWANG_ART_MASTER_III:
+ p = (data[6] << 3) |
+ ((data[7] & 0xc0) >> 5) |
+ (data[1] & 0x01);
+ break;
+
+ case HANWANG_ART_MASTER_HD:
+ p = (data[7] >> 6) | (data[6] << 2);
+ break;
+
+ default:
+ p = 0;
+ break;
+ }
+
+ input_report_abs(input_dev, ABS_X,
+ le16_to_cpup((__le16 *)&x));
+ input_report_abs(input_dev, ABS_Y,
+ le16_to_cpup((__le16 *)&y));
+ input_report_abs(input_dev, ABS_PRESSURE,
+ le16_to_cpup((__le16 *)&p));
+ input_report_abs(input_dev, ABS_TILT_X, data[7] & 0x3f);
+ input_report_abs(input_dev, ABS_TILT_Y, data[8] & 0x7f);
+ input_report_key(input_dev, BTN_STYLUS, data[1] & 0x02);
+ input_report_key(input_dev, BTN_STYLUS2, data[1] & 0x04);
+ break;
+ }
+ input_report_abs(input_dev, ABS_MISC, hanwang->current_id);
+ input_event(input_dev, EV_MSC, MSC_SERIAL,
+ hanwang->features->pid);
+ break;
+
+ case 0x0c:
+ /* roll wheel */
+ hanwang->current_id = PAD_DEVICE_ID;
+
+ switch (type) {
+ case HANWANG_ART_MASTER_III:
+ input_report_key(input_dev, BTN_TOOL_FINGER, data[1] ||
+ data[2] || data[3]);
+ input_report_abs(input_dev, ABS_WHEEL, data[1]);
+ input_report_key(input_dev, BTN_0, data[2]);
+ for (i = 0; i < 8; i++)
+ input_report_key(input_dev,
+ BTN_1 + i, data[3] & (1 << i));
+ break;
+
+ case HANWANG_ART_MASTER_HD:
+ input_report_key(input_dev, BTN_TOOL_FINGER, data[1] ||
+ data[2] || data[3] || data[4] ||
+ data[5] || data[6]);
+ input_report_abs(input_dev, ABS_RX,
+ ((data[1] & 0x1f) << 8) | data[2]);
+ input_report_abs(input_dev, ABS_RY,
+ ((data[3] & 0x1f) << 8) | data[4]);
+ input_report_key(input_dev, BTN_0, data[5] & 0x01);
+ for (i = 0; i < 4; i++) {
+ input_report_key(input_dev,
+ BTN_1 + i, data[5] & (1 << i));
+ input_report_key(input_dev,
+ BTN_5 + i, data[6] & (1 << i));
+ }
+ break;
+ }
+
+ input_report_abs(input_dev, ABS_MISC, hanwang->current_id);
+ input_event(input_dev, EV_MSC, MSC_SERIAL, 0xffffffff);
+ break;
+
+ default:
+ dev_dbg(&dev->dev, "error packet %02x ", data[0]);
+ break;
+ }
+
+ input_sync(input_dev);
+}
+
+static void hanwang_irq(struct urb *urb)
+{
+ struct hanwang *hanwang = urb->context;
+ struct usb_device *dev = hanwang->usbdev;
+ int retval;
+
+ switch (urb->status) {
+ case 0:
+ /* success */;
+ hanwang_parse_packet(hanwang);
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dev_err(&dev->dev, "%s - urb shutting down with status: %d",
+ __func__, urb->status);
+ return;
+ default:
+ dev_err(&dev->dev, "%s - nonzero urb status received: %d",
+ __func__, urb->status);
+ break;
+ }
+
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
+ dev_err(&dev->dev, "%s - usb_submit_urb failed with result %d",
+ __func__, retval);
+}
+
+static int hanwang_open(struct input_dev *dev)
+{
+ struct hanwang *hanwang = input_get_drvdata(dev);
+
+ hanwang->irq->dev = hanwang->usbdev;
+ if (usb_submit_urb(hanwang->irq, GFP_KERNEL))
+ return -EIO;
+
+ return 0;
+}
+
+static void hanwang_close(struct input_dev *dev)
+{
+ struct hanwang *hanwang = input_get_drvdata(dev);
+
+ usb_kill_urb(hanwang->irq);
+}
+
+static bool get_features(struct usb_device *dev, struct hanwang *hanwang)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(features_array); i++) {
+ if (le16_to_cpu(dev->descriptor.idProduct) ==
+ features_array[i].pid) {
+ hanwang->features = &features_array[i];
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+static int hanwang_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct usb_endpoint_descriptor *endpoint;
+ struct hanwang *hanwang;
+ struct input_dev *input_dev;
+ int error;
+ int i;
+
+ hanwang = kzalloc(sizeof(struct hanwang), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!hanwang || !input_dev) {
+ error = -ENOMEM;
+ goto fail1;
+ }
+
+ if (!get_features(dev, hanwang)) {
+ error = -ENXIO;
+ goto fail1;
+ }
+
+ hanwang->data = usb_alloc_coherent(dev, hanwang->features->pkg_len,
+ GFP_KERNEL, &hanwang->data_dma);
+ if (!hanwang->data) {
+ error = -ENOMEM;
+ goto fail1;
+ }
+
+ hanwang->irq = usb_alloc_urb(0, GFP_KERNEL);
+ if (!hanwang->irq) {
+ error = -ENOMEM;
+ goto fail2;
+ }
+
+ hanwang->usbdev = dev;
+ hanwang->dev = input_dev;
+
+ usb_make_path(dev, hanwang->phys, sizeof(hanwang->phys));
+ strlcat(hanwang->phys, "/input0", sizeof(hanwang->phys));
+
+ strlcpy(hanwang->name, hanwang->features->name, sizeof(hanwang->name));
+ input_dev->name = hanwang->name;
+ input_dev->phys = hanwang->phys;
+ usb_to_input_id(dev, &input_dev->id);
+ input_dev->dev.parent = &intf->dev;
+
+ input_set_drvdata(input_dev, hanwang);
+
+ input_dev->open = hanwang_open;
+ input_dev->close = hanwang_close;
+
+ for (i = 0; i < ARRAY_SIZE(hw_eventtypes); ++i)
+ __set_bit(hw_eventtypes[i], input_dev->evbit);
+
+ for (i = 0; i < ARRAY_SIZE(hw_absevents); ++i)
+ __set_bit(hw_absevents[i], input_dev->absbit);
+
+ for (i = 0; i < ARRAY_SIZE(hw_btnevents); ++i)
+ __set_bit(hw_btnevents[i], input_dev->keybit);
+
+ for (i = 0; i < ARRAY_SIZE(hw_mscevents); ++i)
+ __set_bit(hw_mscevents[i], input_dev->mscbit);
+
+ input_set_abs_params(input_dev, ABS_X,
+ 0, hanwang->features->max_x, 4, 0);
+ input_set_abs_params(input_dev, ABS_Y,
+ 0, hanwang->features->max_y, 4, 0);
+ input_set_abs_params(input_dev, ABS_TILT_X,
+ 0, hanwang->features->max_tilt_x, 0, 0);
+ input_set_abs_params(input_dev, ABS_TILT_Y,
+ 0, hanwang->features->max_tilt_y, 0, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE,
+ 0, hanwang->features->max_pressure, 0, 0);
+
+ endpoint = &intf->cur_altsetting->endpoint[0].desc;
+ usb_fill_int_urb(hanwang->irq, dev,
+ usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ hanwang->data, hanwang->features->pkg_len,
+ hanwang_irq, hanwang, endpoint->bInterval);
+ hanwang->irq->transfer_dma = hanwang->data_dma;
+ hanwang->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ error = input_register_device(hanwang->dev);
+ if (error)
+ goto fail3;
+
+ usb_set_intfdata(intf, hanwang);
+
+ return 0;
+
+ fail3: usb_free_urb(hanwang->irq);
+ fail2: usb_free_coherent(dev, hanwang->features->pkg_len,
+ hanwang->data, hanwang->data_dma);
+ fail1: input_free_device(input_dev);
+ kfree(hanwang);
+ return error;
+
+}
+
+static void hanwang_disconnect(struct usb_interface *intf)
+{
+ struct hanwang *hanwang = usb_get_intfdata(intf);
+
+ input_unregister_device(hanwang->dev);
+ usb_free_urb(hanwang->irq);
+ usb_free_coherent(interface_to_usbdev(intf),
+ hanwang->features->pkg_len, hanwang->data,
+ hanwang->data_dma);
+ kfree(hanwang);
+ usb_set_intfdata(intf, NULL);
+}
+
+static const struct usb_device_id hanwang_ids[] = {
+ { HANWANG_TABLET_DEVICE(USB_VENDOR_ID_HANWANG, HANWANG_TABLET_INT_CLASS,
+ HANWANG_TABLET_INT_SUB_CLASS, HANWANG_TABLET_INT_PROTOCOL) },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, hanwang_ids);
+
+static struct usb_driver hanwang_driver = {
+ .name = "hanwang",
+ .probe = hanwang_probe,
+ .disconnect = hanwang_disconnect,
+ .id_table = hanwang_ids,
+};
+
+static int __init hanwang_init(void)
+{
+ return usb_register(&hanwang_driver);
+}
+
+static void __exit hanwang_exit(void)
+{
+ usb_deregister(&hanwang_driver);
+}
+
+module_init(hanwang_init);
+module_exit(hanwang_exit);
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
index 284dfaab6b8c..de5adb109030 100644
--- a/drivers/input/tablet/wacom.h
+++ b/drivers/input/tablet/wacom.h
@@ -118,6 +118,7 @@ struct wacom {
extern const struct usb_device_id wacom_ids[];
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
+void wacom_setup_device_quirks(struct wacom_features *features);
void wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac);
#endif
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index b35876ee6908..fc381498b798 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -120,14 +120,16 @@ static int wacom_open(struct input_dev *dev)
out:
mutex_unlock(&wacom->lock);
- if (retval)
- usb_autopm_put_interface(wacom->intf);
+ usb_autopm_put_interface(wacom->intf);
return retval;
}
static void wacom_close(struct input_dev *dev)
{
struct wacom *wacom = input_get_drvdata(dev);
+ int autopm_error;
+
+ autopm_error = usb_autopm_get_interface(wacom->intf);
mutex_lock(&wacom->lock);
usb_kill_urb(wacom->irq);
@@ -135,7 +137,8 @@ static void wacom_close(struct input_dev *dev)
wacom->intf->needs_remote_wakeup = 0;
mutex_unlock(&wacom->lock);
- usb_autopm_put_interface(wacom->intf);
+ if (!autopm_error)
+ usb_autopm_put_interface(wacom->intf);
}
static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc,
@@ -196,17 +199,30 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
features->pktlen = WACOM_PKGLEN_TPC2FG;
features->device_type = BTN_TOOL_TRIPLETAP;
}
- features->x_max =
- get_unaligned_le16(&report[i + 3]);
- features->x_phy =
- get_unaligned_le16(&report[i + 6]);
- features->unit = report[i + 9];
- features->unitExpo = report[i + 11];
- i += 12;
+ if (features->type == BAMBOO_PT) {
+ /* need to reset back */
+ features->pktlen = WACOM_PKGLEN_BBTOUCH;
+ features->device_type = BTN_TOOL_TRIPLETAP;
+ features->x_phy =
+ get_unaligned_le16(&report[i + 5]);
+ features->x_max =
+ get_unaligned_le16(&report[i + 8]);
+ i += 15;
+ } else {
+ features->x_max =
+ get_unaligned_le16(&report[i + 3]);
+ features->x_phy =
+ get_unaligned_le16(&report[i + 6]);
+ features->unit = report[i + 9];
+ features->unitExpo = report[i + 11];
+ i += 12;
+ }
} else if (pen) {
/* penabled only accepts exact bytes of data */
if (features->type == TABLETPC2FG)
features->pktlen = WACOM_PKGLEN_GRAPHIRE;
+ if (features->type == BAMBOO_PT)
+ features->pktlen = WACOM_PKGLEN_BBFUN;
features->device_type = BTN_TOOL_PEN;
features->x_max =
get_unaligned_le16(&report[i + 3]);
@@ -235,6 +251,15 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
features->y_phy =
get_unaligned_le16(&report[i + 6]);
i += 7;
+ } else if (features->type == BAMBOO_PT) {
+ /* need to reset back */
+ features->pktlen = WACOM_PKGLEN_BBTOUCH;
+ features->device_type = BTN_TOOL_TRIPLETAP;
+ features->y_phy =
+ get_unaligned_le16(&report[i + 3]);
+ features->y_max =
+ get_unaligned_le16(&report[i + 6]);
+ i += 12;
} else {
features->y_max =
features->x_max;
@@ -246,6 +271,8 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
/* penabled only accepts exact bytes of data */
if (features->type == TABLETPC2FG)
features->pktlen = WACOM_PKGLEN_GRAPHIRE;
+ if (features->type == BAMBOO_PT)
+ features->pktlen = WACOM_PKGLEN_BBFUN;
features->device_type = BTN_TOOL_PEN;
features->y_max =
get_unaligned_le16(&report[i + 3]);
@@ -296,8 +323,9 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
if (!rep_data)
return error;
- /* ask to report tablet data if it is 2FGT or not a Tablet PC */
- if (features->device_type == BTN_TOOL_TRIPLETAP) {
+ /* ask to report tablet data if it is 2FGT Tablet PC or
+ * not a Tablet PC */
+ if (features->type == TABLETPC2FG) {
do {
rep_data[0] = 3;
rep_data[1] = 4;
@@ -309,7 +337,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
WAC_HID_FEATURE_REPORT, report_id,
rep_data, 3);
} while ((error < 0 || rep_data[1] != 4) && limit++ < 5);
- } else if (features->type != TABLETPC && features->type != TABLETPC2FG) {
+ } else if (features->type != TABLETPC) {
do {
rep_data[0] = 2;
rep_data[1] = 2;
@@ -334,11 +362,16 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
struct usb_host_interface *interface = intf->cur_altsetting;
struct hid_descriptor *hid_desc;
- /* default device to penabled */
+ /* default features */
features->device_type = BTN_TOOL_PEN;
-
- /* only Tablet PCs need to retrieve the info */
- if ((features->type != TABLETPC) && (features->type != TABLETPC2FG))
+ features->x_fuzz = 4;
+ features->y_fuzz = 4;
+ features->pressure_fuzz = 0;
+ features->distance_fuzz = 0;
+
+ /* only Tablet PCs and Bamboo P&T need to retrieve the info */
+ if ((features->type != TABLETPC) && (features->type != TABLETPC2FG) &&
+ (features->type != BAMBOO_PT))
goto out;
if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) {
@@ -353,12 +386,6 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
if (error)
goto out;
- /* touch device found but size is not defined. use default */
- if (features->device_type == BTN_TOOL_DOUBLETAP && !features->x_max) {
- features->x_max = 1023;
- features->y_max = 1023;
- }
-
out:
return error;
}
@@ -494,9 +521,11 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
if (error)
goto fail2;
+ wacom_setup_device_quirks(features);
+
strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
- if (features->type == TABLETPC || features->type == TABLETPC2FG) {
+ if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
/* Append the device type to the name */
strlcat(wacom_wac->name,
features->device_type == BTN_TOOL_PEN ?
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 47fd7a041c52..b3252ef1e279 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -857,6 +857,134 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
return retval;
}
+static int wacom_bpt_touch(struct wacom_wac *wacom)
+{
+ struct wacom_features *features = &wacom->features;
+ struct input_dev *input = wacom->input;
+ unsigned char *data = wacom->data;
+ int sp = 0, sx = 0, sy = 0, count = 0;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ int p = data[9 * i + 2];
+ input_mt_slot(input, i);
+ /*
+ * 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.
+ */
+ if (p && !wacom->shared->stylus_in_proximity) {
+ int x = get_unaligned_be16(&data[9 * i + 3]) & 0x7ff;
+ int y = get_unaligned_be16(&data[9 * i + 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);
+ if (wacom->id[i] < 0)
+ wacom->id[i] = wacom->trk_id++ & MAX_TRACKING_ID;
+ if (!count++)
+ sp = p, sx = x, sy = y;
+ } else {
+ wacom->id[i] = -1;
+ }
+ input_report_abs(input, ABS_MT_TRACKING_ID, wacom->id[i]);
+ }
+
+ input_report_key(input, BTN_TOUCH, count > 0);
+ input_report_key(input, BTN_TOOL_FINGER, count == 1);
+ input_report_key(input, BTN_TOOL_DOUBLETAP, count == 2);
+
+ input_report_abs(input, ABS_PRESSURE, sp);
+ input_report_abs(input, ABS_X, sx);
+ input_report_abs(input, ABS_Y, sy);
+
+ input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
+ input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0);
+ input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0);
+ input_report_key(input, BTN_RIGHT, (data[1] & 0x01) != 0);
+
+ input_sync(input);
+
+ return 0;
+}
+
+static int wacom_bpt_pen(struct wacom_wac *wacom)
+{
+ struct input_dev *input = wacom->input;
+ unsigned char *data = wacom->data;
+ int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0;
+
+ /*
+ * Similar to Graphire protocol, data[1] & 0x20 is proximity and
+ * data[1] & 0x18 is tool ID. 0x30 is safety check to ignore
+ * 2 unused tool ID's.
+ */
+ prox = (data[1] & 0x30) == 0x30;
+
+ /*
+ * All reports shared between PEN and RUBBER tool must be
+ * forced to a known starting value (zero) when transitioning to
+ * out-of-prox.
+ *
+ * If not reset then, to userspace, it will look like lost events
+ * if new tool comes in-prox with same values as previous tool sent.
+ *
+ * Hardware does report zero in most out-of-prox cases but not all.
+ */
+ if (prox) {
+ if (!wacom->shared->stylus_in_proximity) {
+ if (data[1] & 0x08) {
+ wacom->tool[0] = BTN_TOOL_RUBBER;
+ wacom->id[0] = ERASER_DEVICE_ID;
+ } else {
+ wacom->tool[0] = BTN_TOOL_PEN;
+ wacom->id[0] = STYLUS_DEVICE_ID;
+ }
+ wacom->shared->stylus_in_proximity = true;
+ }
+ x = le16_to_cpup((__le16 *)&data[2]);
+ y = le16_to_cpup((__le16 *)&data[4]);
+ p = le16_to_cpup((__le16 *)&data[6]);
+ d = data[8];
+ pen = data[1] & 0x01;
+ btn1 = data[1] & 0x02;
+ btn2 = data[1] & 0x04;
+ }
+
+ input_report_key(input, BTN_TOUCH, pen);
+ input_report_key(input, BTN_STYLUS, btn1);
+ input_report_key(input, BTN_STYLUS2, btn2);
+
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+ input_report_abs(input, ABS_PRESSURE, p);
+ input_report_abs(input, ABS_DISTANCE, d);
+
+ if (!prox) {
+ wacom->id[0] = 0;
+ wacom->shared->stylus_in_proximity = false;
+ }
+
+ input_report_key(input, wacom->tool[0], prox); /* PEN or RUBBER */
+ input_report_abs(input, ABS_MISC, wacom->id[0]); /* TOOL ID */
+
+ return 1;
+}
+
+static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
+{
+ if (len == WACOM_PKGLEN_BBTOUCH)
+ return wacom_bpt_touch(wacom);
+ else if (len == WACOM_PKGLEN_BBFUN)
+ return wacom_bpt_pen(wacom);
+
+ return 0;
+}
+
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
{
bool sync;
@@ -902,6 +1030,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
sync = wacom_tpc_irq(wacom_wac, len);
break;
+ case BAMBOO_PT:
+ sync = wacom_bpt_irq(wacom_wac, len);
+ break;
+
default:
sync = false;
break;
@@ -911,26 +1043,17 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
input_sync(wacom_wac->input);
}
-static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
+static void wacom_setup_cintiq(struct wacom_wac *wacom_wac)
{
struct input_dev *input_dev = wacom_wac->input;
input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
- input_set_capability(input_dev, EV_REL, REL_WHEEL);
-
- __set_bit(BTN_LEFT, input_dev->keybit);
- __set_bit(BTN_RIGHT, input_dev->keybit);
- __set_bit(BTN_MIDDLE, input_dev->keybit);
- __set_bit(BTN_SIDE, input_dev->keybit);
- __set_bit(BTN_EXTRA, input_dev->keybit);
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
- __set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
__set_bit(BTN_TOOL_BRUSH, input_dev->keybit);
__set_bit(BTN_TOOL_PENCIL, input_dev->keybit);
__set_bit(BTN_TOOL_AIRBRUSH, input_dev->keybit);
- __set_bit(BTN_TOOL_LENS, input_dev->keybit);
__set_bit(BTN_STYLUS, input_dev->keybit);
__set_bit(BTN_STYLUS2, input_dev->keybit);
@@ -939,10 +1062,55 @@ static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
+}
+
+static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
+{
+ struct input_dev *input_dev = wacom_wac->input;
+
+ input_set_capability(input_dev, EV_REL, REL_WHEEL);
+
+ wacom_setup_cintiq(wacom_wac);
+
+ __set_bit(BTN_LEFT, input_dev->keybit);
+ __set_bit(BTN_RIGHT, input_dev->keybit);
+ __set_bit(BTN_MIDDLE, input_dev->keybit);
+ __set_bit(BTN_SIDE, input_dev->keybit);
+ __set_bit(BTN_EXTRA, input_dev->keybit);
+ __set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
+ __set_bit(BTN_TOOL_LENS, input_dev->keybit);
+
input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
}
+void wacom_setup_device_quirks(struct wacom_features *features)
+{
+
+ /* touch device found but size is not defined. use default */
+ if (features->device_type == BTN_TOOL_DOUBLETAP && !features->x_max) {
+ features->x_max = 1023;
+ features->y_max = 1023;
+ }
+
+ /* these device have multiple inputs */
+ if (features->type == TABLETPC || features->type == TABLETPC2FG ||
+ features->type == BAMBOO_PT)
+ features->quirks |= WACOM_QUIRK_MULTI_INPUT;
+
+ /* quirks for bamboo touch */
+ if (features->type == BAMBOO_PT &&
+ features->device_type == BTN_TOOL_TRIPLETAP) {
+ features->x_max <<= 5;
+ features->y_max <<= 5;
+ features->x_fuzz <<= 5;
+ features->y_fuzz <<= 5;
+ features->pressure_max = 256;
+ features->pressure_fuzz = 16;
+ features->quirks |= WACOM_QUIRK_BBTOUCH_LOWRES;
+ }
+}
+
void wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac)
{
@@ -953,9 +1121,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOUCH, input_dev->keybit);
- input_set_abs_params(input_dev, ABS_X, 0, features->x_max, 4, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, features->y_max, 4, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max, 0, 0);
+ input_set_abs_params(input_dev, ABS_X, 0, features->x_max,
+ 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);
__set_bit(ABS_MISC, input_dev->absbit);
@@ -1005,9 +1176,19 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_9, input_dev->keybit);
/* fall through */
+ case CINTIQ:
+ for (i = 0; i < 8; i++)
+ __set_bit(BTN_0 + i, input_dev->keybit);
+ __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+
+ 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);
+ wacom_setup_cintiq(wacom_wac);
+ break;
+
case INTUOS3:
case INTUOS3L:
- case CINTIQ:
__set_bit(BTN_4, input_dev->keybit);
__set_bit(BTN_5, input_dev->keybit);
__set_bit(BTN_6, input_dev->keybit);
@@ -1078,6 +1259,38 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
case PENPARTNER:
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
break;
+
+ case BAMBOO_PT:
+ __clear_bit(ABS_MISC, input_dev->absbit);
+
+ if (features->device_type == BTN_TOOL_TRIPLETAP) {
+ __set_bit(BTN_LEFT, input_dev->keybit);
+ __set_bit(BTN_FORWARD, input_dev->keybit);
+ __set_bit(BTN_BACK, input_dev->keybit);
+ __set_bit(BTN_RIGHT, input_dev->keybit);
+
+ __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+ __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+
+ input_mt_create_slots(input_dev, 2);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ 0, features->x_max,
+ features->x_fuzz, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ 0, features->y_max,
+ features->y_fuzz, 0);
+ input_set_abs_params(input_dev, ABS_MT_PRESSURE,
+ 0, features->pressure_max,
+ features->pressure_fuzz, 0);
+ input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0,
+ MAX_TRACKING_ID, 0, 0);
+ } else if (features->device_type == BTN_TOOL_PEN) {
+ __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
+ __set_bit(BTN_TOOL_PEN, input_dev->keybit);
+ __set_bit(BTN_STYLUS, input_dev->keybit);
+ __set_bit(BTN_STYLUS2, input_dev->keybit);
+ }
+ break;
}
}
@@ -1215,6 +1428,14 @@ static const struct wacom_features wacom_features_0xE3 =
{ "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG };
static const struct wacom_features wacom_features_0x47 =
{ "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS };
+static struct wacom_features wacom_features_0xD0 =
+ { "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD1 =
+ { "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD2 =
+ { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD3 =
+ { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT };
#define USB_DEVICE_WACOM(prod) \
USB_DEVICE(USB_VENDOR_ID_WACOM, prod), \
@@ -1279,6 +1500,10 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0xC6) },
{ USB_DEVICE_WACOM(0xC7) },
{ USB_DEVICE_WACOM(0xCE) },
+ { USB_DEVICE_WACOM(0xD0) },
+ { USB_DEVICE_WACOM(0xD1) },
+ { USB_DEVICE_WACOM(0xD2) },
+ { USB_DEVICE_WACOM(0xD3) },
{ USB_DEVICE_WACOM(0xF0) },
{ USB_DEVICE_WACOM(0xCC) },
{ USB_DEVICE_WACOM(0x90) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 99e1a54cd305..00ca01541d89 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -21,6 +21,7 @@
#define WACOM_PKGLEN_INTUOS 10
#define WACOM_PKGLEN_TPC1FG 5
#define WACOM_PKGLEN_TPC2FG 14
+#define WACOM_PKGLEN_BBTOUCH 20
/* device IDs */
#define STYLUS_DEVICE_ID 0x02
@@ -37,6 +38,13 @@
#define WACOM_REPORT_TPC1FG 6
#define WACOM_REPORT_TPC2FG 13
+/* device quirks */
+#define WACOM_QUIRK_MULTI_INPUT 0x0001
+#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0002
+
+/* largest reported tracking id */
+#define MAX_TRACKING_ID 0xfff
+
enum {
PENPARTNER = 0,
GRAPHIRE,
@@ -44,6 +52,7 @@ enum {
PTU,
PL,
DTU,
+ BAMBOO_PT,
INTUOS,
INTUOS3S,
INTUOS3,
@@ -73,6 +82,11 @@ struct wacom_features {
int y_phy;
unsigned char unit;
unsigned char unitExpo;
+ int x_fuzz;
+ int y_fuzz;
+ int pressure_fuzz;
+ int distance_fuzz;
+ unsigned quirks;
};
struct wacom_shared {
@@ -86,6 +100,7 @@ struct wacom_wac {
int id[3];
__u32 serial[2];
int last_finger;
+ int trk_id;
struct wacom_features features;
struct wacom_shared *shared;
struct input_dev *input;
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 0069d9703fda..06ea8da95c62 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -98,6 +98,18 @@ config TOUCHSCREEN_BITSY
To compile this driver as a module, choose M here: the
module will be called h3600_ts_input.
+config TOUCHSCREEN_BU21013
+ tristate "BU21013 based touch panel controllers"
+ depends on I2C
+ help
+ Say Y here if you have a bu21013 touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bu21013_ts.
+
config TOUCHSCREEN_CY8CTMG110
tristate "cy8ctmg110 touchscreen"
depends on I2C
@@ -214,6 +226,16 @@ config TOUCHSCREEN_WACOM_W8001
To compile this driver as a module, choose M here: the
module will be called wacom_w8001.
+config TOUCHSCREEN_LPC32XX
+ tristate "LPC32XX touchscreen controller"
+ depends on ARCH_LPC32XX
+ help
+ Say Y here if you have a LPC32XX device and want
+ to support the built-in touchscreen.
+
+ To compile this driver as a module, choose M here: the
+ module will be called lpc32xx_ts.
+
config TOUCHSCREEN_MCS5000
tristate "MELFAS MCS-5000 touchscreen"
depends on I2C
@@ -250,6 +272,18 @@ config TOUCHSCREEN_INEXIO
To compile this driver as a module, choose M here: the
module will be called inexio.
+config TOUCHSCREEN_INTEL_MID
+ tristate "Intel MID platform resistive touchscreen"
+ depends on INTEL_SCU_IPC
+ help
+ Say Y here if you have a Intel MID based touchscreen in
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called intel_mid_touch.
+
config TOUCHSCREEN_MK712
tristate "ICS MicroClock MK712 touchscreen"
help
@@ -328,6 +362,15 @@ config TOUCHSCREEN_MIGOR
To compile this driver as a module, choose M here: the
module will be called migor_ts.
+config TOUCHSCREEN_TNETV107X
+ tristate "TI TNETV107X touchscreen support"
+ depends on ARCH_DAVINCI_TNETV107X
+ help
+ Say Y here if you want to use the TNETV107X touchscreen.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tnetv107x-ts.
+
config TOUCHSCREEN_TOUCHRIGHT
tristate "Touchright serial touchscreen"
select SERIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 28217e1dcafd..7cc1b4f4b677 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
@@ -23,6 +24,8 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
+obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
+obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o
obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
@@ -37,6 +40,7 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_QT602240) += qt602240_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
+obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c
index 5f0221cffef9..a1952fcc083e 100644
--- a/drivers/input/touchscreen/ad7877.c
+++ b/drivers/input/touchscreen/ad7877.c
@@ -191,13 +191,12 @@ struct ad7877 {
struct spi_message msg;
struct mutex mutex;
- unsigned disabled:1; /* P: mutex */
- unsigned gpio3:1; /* P: mutex */
- unsigned gpio4:1; /* P: mutex */
+ bool disabled; /* P: mutex */
+ bool gpio3; /* P: mutex */
+ bool gpio4; /* P: mutex */
spinlock_t lock;
struct timer_list timer; /* P: lock */
- unsigned pending:1; /* P: lock */
/*
* DMA (thus cache coherency maintenance) requires the
@@ -206,8 +205,8 @@ struct ad7877 {
u16 conversion_data[AD7877_NR_SENSE] ____cacheline_aligned;
};
-static int gpio3;
-module_param(gpio3, int, 0);
+static bool gpio3;
+module_param(gpio3, bool, 0);
MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3");
/*
@@ -230,6 +229,7 @@ static int ad7877_read(struct spi_device *spi, u16 reg)
AD7877_READADD(reg));
req->xfer[0].tx_buf = &req->command;
req->xfer[0].len = 2;
+ req->xfer[0].cs_change = 1;
req->xfer[1].rx_buf = &req->sample;
req->xfer[1].len = 2;
@@ -295,20 +295,25 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command)
req->xfer[0].tx_buf = &req->reset;
req->xfer[0].len = 2;
+ req->xfer[0].cs_change = 1;
req->xfer[1].tx_buf = &req->ref_on;
req->xfer[1].len = 2;
req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+ req->xfer[1].cs_change = 1;
req->xfer[2].tx_buf = &req->command;
req->xfer[2].len = 2;
req->xfer[2].delay_usecs = ts->vref_delay_usecs;
+ req->xfer[2].cs_change = 1;
req->xfer[3].rx_buf = &req->sample;
req->xfer[3].len = 2;
+ req->xfer[3].cs_change = 1;
req->xfer[4].tx_buf = &ts->cmd_crtl2; /*REF OFF*/
req->xfer[4].len = 2;
+ req->xfer[4].cs_change = 1;
req->xfer[5].tx_buf = &ts->cmd_crtl1; /*DEFAULT*/
req->xfer[5].len = 2;
@@ -327,7 +332,7 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command)
return status ? : sample;
}
-static void ad7877_rx(struct ad7877 *ts)
+static int ad7877_process_data(struct ad7877 *ts)
{
struct input_dev *input_dev = ts->input;
unsigned Rt;
@@ -354,11 +359,25 @@ static void ad7877_rx(struct ad7877 *ts)
Rt /= z1;
Rt = (Rt + 2047) >> 12;
+ /*
+ * Sample found inconsistent, pressure is beyond
+ * the maximum. Don't report it to user space.
+ */
+ if (Rt > ts->pressure_max)
+ return -EINVAL;
+
+ if (!timer_pending(&ts->timer))
+ input_report_key(input_dev, BTN_TOUCH, 1);
+
input_report_abs(input_dev, ABS_X, x);
input_report_abs(input_dev, ABS_Y, y);
input_report_abs(input_dev, ABS_PRESSURE, Rt);
input_sync(input_dev);
+
+ return 0;
}
+
+ return -EINVAL;
}
static inline void ad7877_ts_event_release(struct ad7877 *ts)
@@ -366,72 +385,56 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts)
struct input_dev *input_dev = ts->input;
input_report_abs(input_dev, ABS_PRESSURE, 0);
+ input_report_key(input_dev, BTN_TOUCH, 0);
input_sync(input_dev);
}
static void ad7877_timer(unsigned long handle)
{
struct ad7877 *ts = (void *)handle;
+ unsigned long flags;
+ spin_lock_irqsave(&ts->lock, flags);
ad7877_ts_event_release(ts);
+ spin_unlock_irqrestore(&ts->lock, flags);
}
static irqreturn_t ad7877_irq(int irq, void *handle)
{
struct ad7877 *ts = handle;
unsigned long flags;
- int status;
+ int error;
- /*
- * The repeated conversion sequencer controlled by TMR kicked off
- * too fast. We ignore the last and process the sample sequence
- * currently in the queue. It can't be older than 9.4ms, and we
- * need to avoid that ts->msg doesn't get issued twice while in work.
- */
+ error = spi_sync(ts->spi, &ts->msg);
+ if (error) {
+ dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
+ goto out;
+ }
spin_lock_irqsave(&ts->lock, flags);
- if (!ts->pending) {
- ts->pending = 1;
-
- status = spi_async(ts->spi, &ts->msg);
- if (status)
- dev_err(&ts->spi->dev, "spi_sync --> %d\n", status);
- }
+ error = ad7877_process_data(ts);
+ if (!error)
+ mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
spin_unlock_irqrestore(&ts->lock, flags);
+out:
return IRQ_HANDLED;
}
-static void ad7877_callback(void *_ts)
-{
- struct ad7877 *ts = _ts;
-
- spin_lock_irq(&ts->lock);
-
- ad7877_rx(ts);
- ts->pending = 0;
- mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
-
- spin_unlock_irq(&ts->lock);
-}
-
static void ad7877_disable(struct ad7877 *ts)
{
mutex_lock(&ts->mutex);
if (!ts->disabled) {
- ts->disabled = 1;
+ ts->disabled = true;
disable_irq(ts->spi->irq);
- /* Wait for spi_async callback */
- while (ts->pending)
- msleep(1);
-
if (del_timer_sync(&ts->timer))
ad7877_ts_event_release(ts);
}
- /* we know the chip's in lowpower mode since we always
+ /*
+ * We know the chip's in lowpower mode since we always
* leave it that way after every request
*/
@@ -443,7 +446,7 @@ static void ad7877_enable(struct ad7877 *ts)
mutex_lock(&ts->mutex);
if (ts->disabled) {
- ts->disabled = 0;
+ ts->disabled = false;
enable_irq(ts->spi->irq);
}
@@ -453,7 +456,7 @@ static void ad7877_enable(struct ad7877 *ts)
#define SHOW(name) static ssize_t \
name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
- struct ad7877 *ts = dev_get_drvdata(dev); \
+ struct ad7877 *ts = dev_get_drvdata(dev); \
ssize_t v = ad7877_read_adc(ts->spi, \
AD7877_READ_CHAN(name)); \
if (v < 0) \
@@ -473,7 +476,7 @@ SHOW(temp2)
static ssize_t ad7877_disable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct ad7877 *ts = dev_get_drvdata(dev);
+ struct ad7877 *ts = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ts->disabled);
}
@@ -503,7 +506,7 @@ static DEVICE_ATTR(disable, 0664, ad7877_disable_show, ad7877_disable_store);
static ssize_t ad7877_dac_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct ad7877 *ts = dev_get_drvdata(dev);
+ struct ad7877 *ts = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ts->dac);
}
@@ -533,7 +536,7 @@ static DEVICE_ATTR(dac, 0664, ad7877_dac_show, ad7877_dac_store);
static ssize_t ad7877_gpio3_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct ad7877 *ts = dev_get_drvdata(dev);
+ struct ad7877 *ts = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ts->gpio3);
}
@@ -564,7 +567,7 @@ static DEVICE_ATTR(gpio3, 0664, ad7877_gpio3_show, ad7877_gpio3_store);
static ssize_t ad7877_gpio4_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct ad7877 *ts = dev_get_drvdata(dev);
+ struct ad7877 *ts = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ts->gpio4);
}
@@ -597,16 +600,35 @@ static struct attribute *ad7877_attributes[] = {
&dev_attr_temp2.attr,
&dev_attr_aux1.attr,
&dev_attr_aux2.attr,
+ &dev_attr_aux3.attr,
&dev_attr_bat1.attr,
&dev_attr_bat2.attr,
&dev_attr_disable.attr,
&dev_attr_dac.attr,
+ &dev_attr_gpio3.attr,
&dev_attr_gpio4.attr,
NULL
};
+static mode_t ad7877_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ mode_t mode = attr->mode;
+
+ if (attr == &dev_attr_aux3.attr) {
+ if (gpio3)
+ mode = 0;
+ } else if (attr == &dev_attr_gpio3.attr) {
+ if (!gpio3)
+ mode = 0;
+ }
+
+ return mode;
+}
+
static const struct attribute_group ad7877_attr_group = {
- .attrs = ad7877_attributes,
+ .is_visible = ad7877_attr_is_visible,
+ .attrs = ad7877_attributes,
};
static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts)
@@ -635,22 +657,25 @@ static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts)
spi_message_init(m);
- m->complete = ad7877_callback;
m->context = ts;
ts->xfer[0].tx_buf = &ts->cmd_crtl1;
ts->xfer[0].len = 2;
+ ts->xfer[0].cs_change = 1;
spi_message_add_tail(&ts->xfer[0], m);
ts->xfer[1].tx_buf = &ts->cmd_dummy; /* Send ZERO */
ts->xfer[1].len = 2;
+ ts->xfer[1].cs_change = 1;
spi_message_add_tail(&ts->xfer[1], m);
- for (i = 0; i < 11; i++) {
+ for (i = 0; i < AD7877_NR_SENSE; i++) {
ts->xfer[i + 2].rx_buf = &ts->conversion_data[AD7877_SEQ_YPOS + i];
ts->xfer[i + 2].len = 2;
+ if (i < (AD7877_NR_SENSE - 1))
+ ts->xfer[i + 2].cs_change = 1;
spi_message_add_tail(&ts->xfer[i + 2], m);
}
}
@@ -718,6 +743,8 @@ static int __devinit ad7877_probe(struct spi_device *spi)
input_dev->phys = ts->phys;
input_dev->dev.parent = &spi->dev;
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(ABS_X, input_dev->absbit);
__set_bit(ABS_Y, input_dev->absbit);
@@ -752,8 +779,9 @@ static int __devinit ad7877_probe(struct spi_device *spi)
/* Request AD7877 /DAV GPIO interrupt */
- err = request_irq(spi->irq, ad7877_irq, IRQF_TRIGGER_FALLING,
- spi->dev.driver->name, ts);
+ err = request_threaded_irq(spi->irq, NULL, ad7877_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ spi->dev.driver->name, ts);
if (err) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
goto err_free_mem;
@@ -763,20 +791,12 @@ static int __devinit ad7877_probe(struct spi_device *spi)
if (err)
goto err_free_irq;
- err = device_create_file(&spi->dev,
- gpio3 ? &dev_attr_gpio3 : &dev_attr_aux3);
- if (err)
- goto err_remove_attr_group;
-
err = input_register_device(input_dev);
if (err)
- goto err_remove_attr;
+ goto err_remove_attr_group;
return 0;
-err_remove_attr:
- device_remove_file(&spi->dev,
- gpio3 ? &dev_attr_gpio3 : &dev_attr_aux3);
err_remove_attr_group:
sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group);
err_free_irq:
@@ -790,11 +810,9 @@ err_free_mem:
static int __devexit ad7877_remove(struct spi_device *spi)
{
- struct ad7877 *ts = dev_get_drvdata(&spi->dev);
+ struct ad7877 *ts = dev_get_drvdata(&spi->dev);
sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group);
- device_remove_file(&spi->dev,
- gpio3 ? &dev_attr_gpio3 : &dev_attr_aux3);
ad7877_disable(ts);
free_irq(ts->spi->irq, ts);
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 16031933a8f6..14ea54b78e46 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -17,9 +17,11 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/types.h>
#include <linux/hwmon.h>
#include <linux/init.h>
#include <linux/err.h>
+#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/interrupt.h>
@@ -52,22 +54,23 @@
* files.
*/
-#define TS_POLL_DELAY (1 * 1000000) /* ns delay before the first sample */
-#define TS_POLL_PERIOD (5 * 1000000) /* ns delay between samples */
+#define TS_POLL_DELAY 1 /* ms delay before the first sample */
+#define TS_POLL_PERIOD 5 /* ms delay between samples */
/* this driver doesn't aim at the peak continuous sample rate */
#define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
struct ts_event {
- /* For portability, we can't read 12 bit values using SPI (which
- * would make the controller deliver them as native byteorder u16
+ /*
+ * For portability, we can't read 12 bit values using SPI (which
+ * would make the controller deliver them as native byte order u16
* with msbs zeroed). Instead, we read them as two 8-bit values,
* *** WHICH NEED BYTESWAPPING *** and range adjustment.
*/
u16 x;
u16 y;
u16 z1, z2;
- int ignore;
+ bool ignore;
u8 x_buf[3];
u8 y_buf[3];
};
@@ -110,8 +113,11 @@ struct ads7846 {
struct spi_transfer xfer[18];
struct spi_message msg[5];
- struct spi_message *last_msg;
- int msg_idx;
+ int msg_count;
+ wait_queue_head_t wait;
+
+ bool pendown;
+
int read_cnt;
int read_rep;
int last_read;
@@ -122,14 +128,10 @@ struct ads7846 {
u16 penirq_recheck_delay_usecs;
- spinlock_t lock;
- struct hrtimer timer;
- unsigned pendown:1; /* P: lock */
- unsigned pending:1; /* P: lock */
-// FIXME remove "irq_disabled"
- unsigned irq_disabled:1; /* P: lock */
- unsigned disabled:1;
- unsigned is_suspended:1;
+ struct mutex lock;
+ bool stopped; /* P: lock */
+ bool disabled; /* P: lock */
+ bool suspended; /* P: lock */
int (*filter)(void *data, int data_idx, int *val);
void *filter_data;
@@ -165,7 +167,7 @@ struct ads7846 {
#define ADS_12_BIT (0 << 3)
#define ADS_SER (1 << 2) /* non-differential */
#define ADS_DFR (0 << 2) /* differential */
-#define ADS_PD10_PDOWN (0 << 0) /* lowpower mode + penirq */
+#define ADS_PD10_PDOWN (0 << 0) /* low power mode + penirq */
#define ADS_PD10_ADC_ON (1 << 0) /* ADC on */
#define ADS_PD10_REF_ON (2 << 0) /* vREF on + penirq */
#define ADS_PD10_ALL_ON (3 << 0) /* ADC + vREF on */
@@ -193,6 +195,78 @@ struct ads7846 {
#define REF_ON (READ_12BIT_DFR(x, 1, 1))
#define REF_OFF (READ_12BIT_DFR(y, 0, 0))
+/* Must be called with ts->lock held */
+static void ads7846_stop(struct ads7846 *ts)
+{
+ if (!ts->disabled && !ts->suspended) {
+ /* Signal IRQ thread to stop polling and disable the handler. */
+ ts->stopped = true;
+ mb();
+ wake_up(&ts->wait);
+ disable_irq(ts->spi->irq);
+ }
+}
+
+/* Must be called with ts->lock held */
+static void ads7846_restart(struct ads7846 *ts)
+{
+ if (!ts->disabled && !ts->suspended) {
+ /* Tell IRQ thread that it may poll the device. */
+ ts->stopped = false;
+ mb();
+ enable_irq(ts->spi->irq);
+ }
+}
+
+/* Must be called with ts->lock held */
+static void __ads7846_disable(struct ads7846 *ts)
+{
+ ads7846_stop(ts);
+ regulator_disable(ts->reg);
+
+ /*
+ * We know the chip's in low power mode since we always
+ * leave it that way after every request
+ */
+}
+
+/* Must be called with ts->lock held */
+static void __ads7846_enable(struct ads7846 *ts)
+{
+ regulator_enable(ts->reg);
+ ads7846_restart(ts);
+}
+
+static void ads7846_disable(struct ads7846 *ts)
+{
+ mutex_lock(&ts->lock);
+
+ if (!ts->disabled) {
+
+ if (!ts->suspended)
+ __ads7846_disable(ts);
+
+ ts->disabled = true;
+ }
+
+ mutex_unlock(&ts->lock);
+}
+
+static void ads7846_enable(struct ads7846 *ts)
+{
+ mutex_lock(&ts->lock);
+
+ if (ts->disabled) {
+
+ ts->disabled = false;
+
+ if (!ts->suspended)
+ __ads7846_enable(ts);
+ }
+
+ mutex_unlock(&ts->lock);
+}
+
/*--------------------------------------------------------------------------*/
/*
@@ -219,23 +293,15 @@ struct ads7845_ser_req {
struct spi_transfer xfer[2];
};
-static void ads7846_enable(struct ads7846 *ts);
-static void ads7846_disable(struct ads7846 *ts);
-
-static int device_suspended(struct device *dev)
-{
- struct ads7846 *ts = dev_get_drvdata(dev);
- return ts->is_suspended || ts->disabled;
-}
-
static int ads7846_read12_ser(struct device *dev, unsigned command)
{
- struct spi_device *spi = to_spi_device(dev);
- struct ads7846 *ts = dev_get_drvdata(dev);
- struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
- int status;
- int use_internal;
+ struct spi_device *spi = to_spi_device(dev);
+ struct ads7846 *ts = dev_get_drvdata(dev);
+ struct ser_req *req;
+ int status;
+ int use_internal;
+ req = kzalloc(sizeof *req, GFP_KERNEL);
if (!req)
return -ENOMEM;
@@ -282,11 +348,11 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
CS_CHANGE(req->xfer[5]);
spi_message_add_tail(&req->xfer[5], &req->msg);
- ts->irq_disabled = 1;
- disable_irq(spi->irq);
+ mutex_lock(&ts->lock);
+ ads7846_stop(ts);
status = spi_sync(spi, &req->msg);
- ts->irq_disabled = 0;
- enable_irq(spi->irq);
+ ads7846_restart(ts);
+ mutex_unlock(&ts->lock);
if (status == 0) {
/* on-wire is a must-ignore bit, a BE12 value, then padding */
@@ -301,11 +367,12 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
static int ads7845_read12_ser(struct device *dev, unsigned command)
{
- struct spi_device *spi = to_spi_device(dev);
- struct ads7846 *ts = dev_get_drvdata(dev);
- struct ads7845_ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
- int status;
+ struct spi_device *spi = to_spi_device(dev);
+ struct ads7846 *ts = dev_get_drvdata(dev);
+ struct ads7845_ser_req *req;
+ int status;
+ req = kzalloc(sizeof *req, GFP_KERNEL);
if (!req)
return -ENOMEM;
@@ -317,11 +384,11 @@ static int ads7845_read12_ser(struct device *dev, unsigned command)
req->xfer[0].len = 3;
spi_message_add_tail(&req->xfer[0], &req->msg);
- ts->irq_disabled = 1;
- disable_irq(spi->irq);
+ mutex_lock(&ts->lock);
+ ads7846_stop(ts);
status = spi_sync(spi, &req->msg);
- ts->irq_disabled = 0;
- enable_irq(spi->irq);
+ ads7846_restart(ts);
+ mutex_unlock(&ts->lock);
if (status == 0) {
/* BE12 value, then padding */
@@ -374,6 +441,7 @@ static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v)
/* external resistors may scale vAUX into 0..vREF */
retval *= ts->vref_mv;
retval = retval >> 12;
+
return retval;
}
@@ -384,13 +452,13 @@ static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v)
/* ads7846 has a resistor ladder to scale this signal down */
if (ts->model == 7846)
retval *= 4;
+
return retval;
}
SHOW(in0_input, vaux, vaux_adjust)
SHOW(in1_input, vbatt, vbatt_adjust)
-
static struct attribute *ads7846_attributes[] = {
&dev_attr_temp0.attr,
&dev_attr_temp1.attr,
@@ -498,17 +566,12 @@ static inline void ads784x_hwmon_unregister(struct spi_device *spi,
}
#endif
-static int is_pen_down(struct device *dev)
-{
- struct ads7846 *ts = dev_get_drvdata(dev);
-
- return ts->pendown;
-}
-
static ssize_t ads7846_pen_down_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "%u\n", is_pen_down(dev));
+ struct ads7846 *ts = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", ts->pendown);
}
static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL);
@@ -516,7 +579,7 @@ static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL);
static ssize_t ads7846_disable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct ads7846 *ts = dev_get_drvdata(dev);
+ struct ads7846 *ts = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ts->disabled);
}
@@ -531,15 +594,11 @@ static ssize_t ads7846_disable_store(struct device *dev,
if (strict_strtoul(buf, 10, &i))
return -EINVAL;
- spin_lock_irq(&ts->lock);
-
if (i)
ads7846_disable(ts);
else
ads7846_enable(ts);
- spin_unlock_irq(&ts->lock);
-
return count;
}
@@ -569,23 +628,141 @@ static void null_wait_for_sync(void)
{
}
-/*
- * PENIRQ only kicks the timer. The timer only reissues the SPI transfer,
- * to retrieve touchscreen status.
- *
- * The SPI transfer completion callback does the real work. It reports
- * touchscreen events and reactivates the timer (or IRQ) as appropriate.
- */
+static int ads7846_debounce_filter(void *ads, int data_idx, int *val)
+{
+ struct ads7846 *ts = ads;
+
+ if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
+ /* Start over collecting consistent readings. */
+ ts->read_rep = 0;
+ /*
+ * Repeat it, if this was the first read or the read
+ * wasn't consistent enough.
+ */
+ if (ts->read_cnt < ts->debounce_max) {
+ ts->last_read = *val;
+ ts->read_cnt++;
+ return ADS7846_FILTER_REPEAT;
+ } else {
+ /*
+ * Maximum number of debouncing reached and still
+ * not enough number of consistent readings. Abort
+ * the whole sample, repeat it in the next sampling
+ * period.
+ */
+ ts->read_cnt = 0;
+ return ADS7846_FILTER_IGNORE;
+ }
+ } else {
+ if (++ts->read_rep > ts->debounce_rep) {
+ /*
+ * Got a good reading for this coordinate,
+ * go for the next one.
+ */
+ ts->read_cnt = 0;
+ ts->read_rep = 0;
+ return ADS7846_FILTER_OK;
+ } else {
+ /* Read more values that are consistent. */
+ ts->read_cnt++;
+ return ADS7846_FILTER_REPEAT;
+ }
+ }
+}
+
+static int ads7846_no_filter(void *ads, int data_idx, int *val)
+{
+ return ADS7846_FILTER_OK;
+}
+
+static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m)
+{
+ struct spi_transfer *t =
+ list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+
+ if (ts->model == 7845) {
+ return be16_to_cpup((__be16 *)&(((char*)t->rx_buf)[1])) >> 3;
+ } else {
+ /*
+ * adjust: on-wire is a must-ignore bit, a BE12 value, then
+ * padding; built from two 8 bit values written msb-first.
+ */
+ return be16_to_cpup((__be16 *)t->rx_buf) >> 3;
+ }
+}
+
+static void ads7846_update_value(struct spi_message *m, int val)
+{
+ struct spi_transfer *t =
+ list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+
+ *(u16 *)t->rx_buf = val;
+}
+
+static void ads7846_read_state(struct ads7846 *ts)
+{
+ struct ads7846_packet *packet = ts->packet;
+ struct spi_message *m;
+ int msg_idx = 0;
+ int val;
+ int action;
+ int error;
+
+ while (msg_idx < ts->msg_count) {
+
+ ts->wait_for_sync();
+
+ m = &ts->msg[msg_idx];
+ error = spi_sync(ts->spi, m);
+ if (error) {
+ dev_err(&ts->spi->dev, "spi_async --> %d\n", error);
+ packet->tc.ignore = true;
+ return;
+ }
+
+ /*
+ * Last message is power down request, no need to convert
+ * or filter the value.
+ */
+ if (msg_idx < ts->msg_count - 1) {
-static void ads7846_rx(void *ads)
+ val = ads7846_get_value(ts, m);
+
+ action = ts->filter(ts->filter_data, msg_idx, &val);
+ switch (action) {
+ case ADS7846_FILTER_REPEAT:
+ continue;
+
+ case ADS7846_FILTER_IGNORE:
+ packet->tc.ignore = true;
+ msg_idx = ts->msg_count - 1;
+ continue;
+
+ case ADS7846_FILTER_OK:
+ ads7846_update_value(m, val);
+ packet->tc.ignore = false;
+ msg_idx++;
+ break;
+
+ default:
+ BUG();
+ }
+ } else {
+ msg_idx++;
+ }
+ }
+}
+
+static void ads7846_report_state(struct ads7846 *ts)
{
- struct ads7846 *ts = ads;
- struct ads7846_packet *packet = ts->packet;
- unsigned Rt;
- u16 x, y, z1, z2;
+ struct ads7846_packet *packet = ts->packet;
+ unsigned int Rt;
+ u16 x, y, z1, z2;
- /* ads7846_rx_val() did in-place conversion (including byteswap) from
- * on-the-wire format as part of debouncing to get stable readings.
+ /*
+ * ads7846_get_value() does in-place conversion (including byte swap)
+ * from on-the-wire format as part of debouncing to get stable
+ * readings.
*/
if (ts->model == 7845) {
x = *(u16 *)packet->tc.x_buf;
@@ -623,19 +800,19 @@ static void ads7846_rx(void *ads)
Rt = 0;
}
- /* Sample found inconsistent by debouncing or pressure is beyond
+ /*
+ * Sample found inconsistent by debouncing or pressure is beyond
* the maximum. Don't report it to user space, repeat at least
* once more the measurement
*/
if (packet->tc.ignore || Rt > ts->pressure_max) {
dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n",
packet->tc.ignore, Rt);
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
- HRTIMER_MODE_REL);
return;
}
- /* Maybe check the pendown state before reporting. This discards
+ /*
+ * Maybe check the pendown state before reporting. This discards
* false readings when the pen is lifted.
*/
if (ts->penirq_recheck_delay_usecs) {
@@ -644,8 +821,9 @@ static void ads7846_rx(void *ads)
Rt = 0;
}
- /* NOTE: We can't rely on the pressure to determine the pen down
- * state, even this controller has a pressure sensor. The pressure
+ /*
+ * NOTE: We can't rely on the pressure to determine the pen down
+ * state, even this controller has a pressure sensor. The pressure
* value can fluctuate for quite a while after lifting the pen and
* in some cases may not even settle at the expected value.
*
@@ -655,15 +833,15 @@ static void ads7846_rx(void *ads)
if (Rt) {
struct input_dev *input = ts->input;
+ if (ts->swap_xy)
+ swap(x, y);
+
if (!ts->pendown) {
input_report_key(input, BTN_TOUCH, 1);
- ts->pendown = 1;
+ ts->pendown = true;
dev_vdbg(&ts->spi->dev, "DOWN\n");
}
- if (ts->swap_xy)
- swap(x, y);
-
input_report_abs(input, ABS_X, x);
input_report_abs(input, ABS_Y, y);
input_report_abs(input, ABS_PRESSURE, ts->pressure_max - Rt);
@@ -671,246 +849,94 @@ static void ads7846_rx(void *ads)
input_sync(input);
dev_vdbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
}
-
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
- HRTIMER_MODE_REL);
-}
-
-static int ads7846_debounce(void *ads, int data_idx, int *val)
-{
- struct ads7846 *ts = ads;
-
- if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
- /* Start over collecting consistent readings. */
- ts->read_rep = 0;
- /* Repeat it, if this was the first read or the read
- * wasn't consistent enough. */
- if (ts->read_cnt < ts->debounce_max) {
- ts->last_read = *val;
- ts->read_cnt++;
- return ADS7846_FILTER_REPEAT;
- } else {
- /* Maximum number of debouncing reached and still
- * not enough number of consistent readings. Abort
- * the whole sample, repeat it in the next sampling
- * period.
- */
- ts->read_cnt = 0;
- return ADS7846_FILTER_IGNORE;
- }
- } else {
- if (++ts->read_rep > ts->debounce_rep) {
- /* Got a good reading for this coordinate,
- * go for the next one. */
- ts->read_cnt = 0;
- ts->read_rep = 0;
- return ADS7846_FILTER_OK;
- } else {
- /* Read more values that are consistent. */
- ts->read_cnt++;
- return ADS7846_FILTER_REPEAT;
- }
- }
}
-static int ads7846_no_filter(void *ads, int data_idx, int *val)
+static irqreturn_t ads7846_hard_irq(int irq, void *handle)
{
- return ADS7846_FILTER_OK;
-}
-
-static void ads7846_rx_val(void *ads)
-{
- struct ads7846 *ts = ads;
- struct ads7846_packet *packet = ts->packet;
- struct spi_message *m;
- struct spi_transfer *t;
- int val;
- int action;
- int status;
-
- m = &ts->msg[ts->msg_idx];
- t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
-
- if (ts->model == 7845) {
- val = be16_to_cpup((__be16 *)&(((char*)t->rx_buf)[1])) >> 3;
- } else {
- /* adjust: on-wire is a must-ignore bit, a BE12 value, then
- * padding; built from two 8 bit values written msb-first.
- */
- val = be16_to_cpup((__be16 *)t->rx_buf) >> 3;
- }
+ struct ads7846 *ts = handle;
- action = ts->filter(ts->filter_data, ts->msg_idx, &val);
- switch (action) {
- case ADS7846_FILTER_REPEAT:
- break;
- case ADS7846_FILTER_IGNORE:
- packet->tc.ignore = 1;
- /* Last message will contain ads7846_rx() as the
- * completion function.
- */
- m = ts->last_msg;
- break;
- case ADS7846_FILTER_OK:
- *(u16 *)t->rx_buf = val;
- packet->tc.ignore = 0;
- m = &ts->msg[++ts->msg_idx];
- break;
- default:
- BUG();
- }
- ts->wait_for_sync();
- status = spi_async(ts->spi, m);
- if (status)
- dev_err(&ts->spi->dev, "spi_async --> %d\n",
- status);
+ return get_pendown_state(ts) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
}
-static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
-{
- struct ads7846 *ts = container_of(handle, struct ads7846, timer);
- int status = 0;
-
- spin_lock(&ts->lock);
-
- if (unlikely(!get_pendown_state(ts) ||
- device_suspended(&ts->spi->dev))) {
- if (ts->pendown) {
- struct input_dev *input = ts->input;
-
- input_report_key(input, BTN_TOUCH, 0);
- input_report_abs(input, ABS_PRESSURE, 0);
- input_sync(input);
-
- ts->pendown = 0;
- dev_vdbg(&ts->spi->dev, "UP\n");
- }
-
- /* measurement cycle ended */
- if (!device_suspended(&ts->spi->dev)) {
- ts->irq_disabled = 0;
- enable_irq(ts->spi->irq);
- }
- ts->pending = 0;
- } else {
- /* pen is still down, continue with the measurement */
- ts->msg_idx = 0;
- ts->wait_for_sync();
- status = spi_async(ts->spi, &ts->msg[0]);
- if (status)
- dev_err(&ts->spi->dev, "spi_async --> %d\n", status);
- }
-
- spin_unlock(&ts->lock);
- return HRTIMER_NORESTART;
-}
static irqreturn_t ads7846_irq(int irq, void *handle)
{
struct ads7846 *ts = handle;
- unsigned long flags;
-
- spin_lock_irqsave(&ts->lock, flags);
- if (likely(get_pendown_state(ts))) {
- if (!ts->irq_disabled) {
- /* The ARM do_simple_IRQ() dispatcher doesn't act
- * like the other dispatchers: it will report IRQs
- * even after they've been disabled. We work around
- * that here. (The "generic irq" framework may help...)
- */
- ts->irq_disabled = 1;
- disable_irq_nosync(ts->spi->irq);
- ts->pending = 1;
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
- HRTIMER_MODE_REL);
- }
- }
- spin_unlock_irqrestore(&ts->lock, flags);
- return IRQ_HANDLED;
-}
+ /* Start with a small delay before checking pendown state */
+ msleep(TS_POLL_DELAY);
-/*--------------------------------------------------------------------------*/
+ while (!ts->stopped && get_pendown_state(ts)) {
-/* Must be called with ts->lock held */
-static void ads7846_disable(struct ads7846 *ts)
-{
- if (ts->disabled)
- return;
+ /* pen is down, continue with the measurement */
+ ads7846_read_state(ts);
- ts->disabled = 1;
+ if (!ts->stopped)
+ ads7846_report_state(ts);
- /* are we waiting for IRQ, or polling? */
- if (!ts->pending) {
- ts->irq_disabled = 1;
- disable_irq(ts->spi->irq);
- } else {
- /* the timer will run at least once more, and
- * leave everything in a clean state, IRQ disabled
- */
- while (ts->pending) {
- spin_unlock_irq(&ts->lock);
- msleep(1);
- spin_lock_irq(&ts->lock);
- }
+ wait_event_timeout(ts->wait, ts->stopped,
+ msecs_to_jiffies(TS_POLL_PERIOD));
}
- regulator_disable(ts->reg);
-
- /* we know the chip's in lowpower mode since we always
- * leave it that way after every request
- */
-}
+ if (ts->pendown) {
+ struct input_dev *input = ts->input;
-/* Must be called with ts->lock held */
-static void ads7846_enable(struct ads7846 *ts)
-{
- if (!ts->disabled)
- return;
+ input_report_key(input, BTN_TOUCH, 0);
+ input_report_abs(input, ABS_PRESSURE, 0);
+ input_sync(input);
- regulator_enable(ts->reg);
+ ts->pendown = false;
+ dev_vdbg(&ts->spi->dev, "UP\n");
+ }
- ts->disabled = 0;
- ts->irq_disabled = 0;
- enable_irq(ts->spi->irq);
+ return IRQ_HANDLED;
}
static int ads7846_suspend(struct spi_device *spi, pm_message_t message)
{
struct ads7846 *ts = dev_get_drvdata(&spi->dev);
- spin_lock_irq(&ts->lock);
+ mutex_lock(&ts->lock);
- ts->is_suspended = 1;
- ads7846_disable(ts);
+ if (!ts->suspended) {
- spin_unlock_irq(&ts->lock);
+ if (!ts->disabled)
+ __ads7846_disable(ts);
- if (device_may_wakeup(&ts->spi->dev))
- enable_irq_wake(ts->spi->irq);
+ if (device_may_wakeup(&ts->spi->dev))
+ enable_irq_wake(ts->spi->irq);
- return 0;
+ ts->suspended = true;
+ }
+
+ mutex_unlock(&ts->lock);
+ return 0;
}
static int ads7846_resume(struct spi_device *spi)
{
struct ads7846 *ts = dev_get_drvdata(&spi->dev);
- if (device_may_wakeup(&ts->spi->dev))
- disable_irq_wake(ts->spi->irq);
+ mutex_lock(&ts->lock);
+
+ if (ts->suspended) {
- spin_lock_irq(&ts->lock);
+ ts->suspended = false;
- ts->is_suspended = 0;
- ads7846_enable(ts);
+ if (device_may_wakeup(&ts->spi->dev))
+ disable_irq_wake(ts->spi->irq);
- spin_unlock_irq(&ts->lock);
+ if (!ts->disabled)
+ __ads7846_enable(ts);
+ }
+
+ mutex_unlock(&ts->lock);
return 0;
}
-static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
+static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads7846 *ts)
{
struct ads7846_platform_data *pdata = spi->dev.platform_data;
int err;
@@ -932,146 +958,40 @@ static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
err = gpio_request(pdata->gpio_pendown, "ads7846_pendown");
if (err) {
dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
- pdata->gpio_pendown);
+ pdata->gpio_pendown);
return err;
}
ts->gpio_pendown = pdata->gpio_pendown;
+
return 0;
}
-static int __devinit ads7846_probe(struct spi_device *spi)
+/*
+ * Set up the transfers to read touchscreen state; this assumes we
+ * use formula #2 for pressure, not #3.
+ */
+static void __devinit ads7846_setup_spi_msg(struct ads7846 *ts,
+ const struct ads7846_platform_data *pdata)
{
- struct ads7846 *ts;
- struct ads7846_packet *packet;
- struct input_dev *input_dev;
- const struct ads7846_platform_data *pdata = spi->dev.platform_data;
- struct spi_message *m;
- struct spi_transfer *x;
- unsigned long irq_flags;
- int vref;
- int err;
-
- if (!spi->irq) {
- dev_dbg(&spi->dev, "no IRQ?\n");
- return -ENODEV;
- }
-
- if (!pdata) {
- dev_dbg(&spi->dev, "no platform data?\n");
- return -ENODEV;
- }
-
- /* don't exceed max specified sample rate */
- if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
- dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
- (spi->max_speed_hz/SAMPLE_BITS)/1000);
- return -EINVAL;
- }
-
- /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except
- * that even if the hardware can do that, the SPI controller driver
- * may not. So we stick to very-portable 8 bit words, both RX and TX.
- */
- spi->bits_per_word = 8;
- spi->mode = SPI_MODE_0;
- err = spi_setup(spi);
- if (err < 0)
- return err;
-
- ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
- packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ts || !packet || !input_dev) {
- err = -ENOMEM;
- goto err_free_mem;
- }
-
- dev_set_drvdata(&spi->dev, ts);
-
- ts->packet = packet;
- ts->spi = spi;
- ts->input = input_dev;
- ts->vref_mv = pdata->vref_mv;
- ts->swap_xy = pdata->swap_xy;
-
- hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- ts->timer.function = ads7846_timer;
-
- spin_lock_init(&ts->lock);
-
- ts->model = pdata->model ? : 7846;
- ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
- ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
- ts->pressure_max = pdata->pressure_max ? : ~0;
-
- if (pdata->filter != NULL) {
- if (pdata->filter_init != NULL) {
- err = pdata->filter_init(pdata, &ts->filter_data);
- if (err < 0)
- goto err_free_mem;
- }
- ts->filter = pdata->filter;
- ts->filter_cleanup = pdata->filter_cleanup;
- } else if (pdata->debounce_max) {
- ts->debounce_max = pdata->debounce_max;
- if (ts->debounce_max < 2)
- ts->debounce_max = 2;
- ts->debounce_tol = pdata->debounce_tol;
- ts->debounce_rep = pdata->debounce_rep;
- ts->filter = ads7846_debounce;
- ts->filter_data = ts;
- } else
- ts->filter = ads7846_no_filter;
-
- err = setup_pendown(spi, ts);
- if (err)
- goto err_cleanup_filter;
-
- if (pdata->penirq_recheck_delay_usecs)
- ts->penirq_recheck_delay_usecs =
- pdata->penirq_recheck_delay_usecs;
-
- ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
-
- snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
- snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
-
- input_dev->name = ts->name;
- input_dev->phys = ts->phys;
- input_dev->dev.parent = &spi->dev;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
- input_set_abs_params(input_dev, ABS_X,
- pdata->x_min ? : 0,
- pdata->x_max ? : MAX_12BIT,
- 0, 0);
- input_set_abs_params(input_dev, ABS_Y,
- pdata->y_min ? : 0,
- pdata->y_max ? : MAX_12BIT,
- 0, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE,
- pdata->pressure_min, pdata->pressure_max, 0, 0);
-
- vref = pdata->keep_vref_on;
+ struct spi_message *m = &ts->msg[0];
+ struct spi_transfer *x = ts->xfer;
+ struct ads7846_packet *packet = ts->packet;
+ int vref = pdata->keep_vref_on;
if (ts->model == 7873) {
- /* The AD7873 is almost identical to the ADS7846
+ /*
+ * The AD7873 is almost identical to the ADS7846
* keep VREF off during differential/ratiometric
- * conversion modes
+ * conversion modes.
*/
ts->model = 7846;
vref = 0;
}
- /* set up the transfers to read touchscreen state; this assumes we
- * use formula #2 for pressure, not #3.
- */
- m = &ts->msg[0];
- x = ts->xfer;
-
+ ts->msg_count = 1;
spi_message_init(m);
+ m->context = ts;
if (ts->model == 7845) {
packet->read_y_cmd[0] = READ_Y(vref);
@@ -1094,7 +1014,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_add_tail(x, m);
}
- /* the first sample after switching drivers can be low quality;
+ /*
+ * The first sample after switching drivers can be low quality;
* optionally discard it, using a second one after the signals
* have had enough time to stabilize.
*/
@@ -1112,11 +1033,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_add_tail(x, m);
}
- m->complete = ads7846_rx_val;
- m->context = ts;
-
+ ts->msg_count++;
m++;
spi_message_init(m);
+ m->context = ts;
if (ts->model == 7845) {
x++;
@@ -1156,13 +1076,12 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_add_tail(x, m);
}
- m->complete = ads7846_rx_val;
- m->context = ts;
-
/* turn y+ off, x- on; we'll use formula #2 */
if (ts->model == 7846) {
+ ts->msg_count++;
m++;
spi_message_init(m);
+ m->context = ts;
x++;
packet->read_z1 = READ_Z1(vref);
@@ -1190,11 +1109,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_add_tail(x, m);
}
- m->complete = ads7846_rx_val;
- m->context = ts;
-
+ ts->msg_count++;
m++;
spi_message_init(m);
+ m->context = ts;
x++;
packet->read_z2 = READ_Z2(vref);
@@ -1221,14 +1139,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
}
-
- m->complete = ads7846_rx_val;
- m->context = ts;
}
/* power down */
+ ts->msg_count++;
m++;
spi_message_init(m);
+ m->context = ts;
if (ts->model == 7845) {
x++;
@@ -1251,11 +1168,119 @@ static int __devinit ads7846_probe(struct spi_device *spi)
CS_CHANGE(*x);
spi_message_add_tail(x, m);
+}
- m->complete = ads7846_rx;
- m->context = ts;
+static int __devinit ads7846_probe(struct spi_device *spi)
+{
+ struct ads7846 *ts;
+ struct ads7846_packet *packet;
+ struct input_dev *input_dev;
+ struct ads7846_platform_data *pdata = spi->dev.platform_data;
+ unsigned long irq_flags;
+ int err;
+
+ if (!spi->irq) {
+ dev_dbg(&spi->dev, "no IRQ?\n");
+ return -ENODEV;
+ }
+
+ if (!pdata) {
+ dev_dbg(&spi->dev, "no platform data?\n");
+ return -ENODEV;
+ }
+
+ /* don't exceed max specified sample rate */
+ if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
+ dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
+ (spi->max_speed_hz/SAMPLE_BITS)/1000);
+ return -EINVAL;
+ }
+
+ /* We'd set TX word size 8 bits and RX word size to 13 bits ... except
+ * that even if the hardware can do that, the SPI controller driver
+ * may not. So we stick to very-portable 8 bit words, both RX and TX.
+ */
+ spi->bits_per_word = 8;
+ spi->mode = SPI_MODE_0;
+ err = spi_setup(spi);
+ if (err < 0)
+ return err;
- ts->last_msg = m;
+ ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
+ packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!ts || !packet || !input_dev) {
+ err = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ dev_set_drvdata(&spi->dev, ts);
+
+ ts->packet = packet;
+ ts->spi = spi;
+ ts->input = input_dev;
+ ts->vref_mv = pdata->vref_mv;
+ ts->swap_xy = pdata->swap_xy;
+
+ mutex_init(&ts->lock);
+ init_waitqueue_head(&ts->wait);
+
+ ts->model = pdata->model ? : 7846;
+ ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
+ ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
+ ts->pressure_max = pdata->pressure_max ? : ~0;
+
+ if (pdata->filter != NULL) {
+ if (pdata->filter_init != NULL) {
+ err = pdata->filter_init(pdata, &ts->filter_data);
+ if (err < 0)
+ goto err_free_mem;
+ }
+ ts->filter = pdata->filter;
+ ts->filter_cleanup = pdata->filter_cleanup;
+ } else if (pdata->debounce_max) {
+ ts->debounce_max = pdata->debounce_max;
+ if (ts->debounce_max < 2)
+ ts->debounce_max = 2;
+ ts->debounce_tol = pdata->debounce_tol;
+ ts->debounce_rep = pdata->debounce_rep;
+ ts->filter = ads7846_debounce_filter;
+ ts->filter_data = ts;
+ } else {
+ ts->filter = ads7846_no_filter;
+ }
+
+ err = ads7846_setup_pendown(spi, ts);
+ if (err)
+ goto err_cleanup_filter;
+
+ if (pdata->penirq_recheck_delay_usecs)
+ ts->penirq_recheck_delay_usecs =
+ pdata->penirq_recheck_delay_usecs;
+
+ ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
+
+ snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
+ snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
+
+ input_dev->name = ts->name;
+ input_dev->phys = ts->phys;
+ input_dev->dev.parent = &spi->dev;
+
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ input_set_abs_params(input_dev, ABS_X,
+ pdata->x_min ? : 0,
+ pdata->x_max ? : MAX_12BIT,
+ 0, 0);
+ input_set_abs_params(input_dev, ABS_Y,
+ pdata->y_min ? : 0,
+ pdata->y_max ? : MAX_12BIT,
+ 0, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE,
+ pdata->pressure_min, pdata->pressure_max, 0, 0);
+
+ ads7846_setup_spi_msg(ts, pdata);
ts->reg = regulator_get(&spi->dev, "vcc");
if (IS_ERR(ts->reg)) {
@@ -1271,16 +1296,17 @@ static int __devinit ads7846_probe(struct spi_device *spi)
}
irq_flags = pdata->irq_flags ? : IRQF_TRIGGER_FALLING;
+ irq_flags |= IRQF_ONESHOT;
- err = request_irq(spi->irq, ads7846_irq, irq_flags,
- spi->dev.driver->name, ts);
-
+ err = request_threaded_irq(spi->irq, ads7846_hard_irq, ads7846_irq,
+ irq_flags, spi->dev.driver->name, ts);
if (err && !pdata->irq_flags) {
dev_info(&spi->dev,
"trying pin change workaround on irq %d\n", spi->irq);
- err = request_irq(spi->irq, ads7846_irq,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- spi->dev.driver->name, ts);
+ irq_flags |= IRQF_TRIGGER_RISING;
+ err = request_threaded_irq(spi->irq,
+ ads7846_hard_irq, ads7846_irq,
+ irq_flags, spi->dev.driver->name, ts);
}
if (err) {
@@ -1294,7 +1320,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
- /* take a first sample, leaving nPENIRQ active and vREF off; avoid
+ /*
+ * Take a first sample, leaving nPENIRQ active and vREF off; avoid
* the touchscreen, in case it's not connected.
*/
if (ts->model == 7845)
@@ -1340,20 +1367,18 @@ static int __devinit ads7846_probe(struct spi_device *spi)
static int __devexit ads7846_remove(struct spi_device *spi)
{
- struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+ struct ads7846 *ts = dev_get_drvdata(&spi->dev);
device_init_wakeup(&spi->dev, false);
- ads784x_hwmon_unregister(spi, ts);
- input_unregister_device(ts->input);
-
- ads7846_suspend(spi, PMSG_SUSPEND);
-
sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
+ ads7846_disable(ts);
free_irq(ts->spi->irq, ts);
- /* suspend left the IRQ disabled */
- enable_irq(ts->spi->irq);
+
+ input_unregister_device(ts->input);
+
+ ads784x_hwmon_unregister(spi, ts);
regulator_disable(ts->reg);
regulator_put(ts->reg);
@@ -1368,6 +1393,7 @@ static int __devexit ads7846_remove(struct spi_device *spi)
kfree(ts);
dev_dbg(&spi->dev, "unregistered touchscreen\n");
+
return 0;
}
diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c
new file mode 100644
index 000000000000..ccde58602563
--- /dev/null
+++ b/drivers/input/touchscreen/bu21013_ts.c
@@ -0,0 +1,648 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * License terms:GNU General Public License (GPL) version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/input.h>
+#include <linux/input/bu21013.h>
+#include <linux/slab.h>
+
+#define PEN_DOWN_INTR 0
+#define MAX_FINGERS 2
+#define RESET_DELAY 30
+#define PENUP_TIMEOUT (10)
+#define DELTA_MIN 16
+#define MASK_BITS 0x03
+#define SHIFT_8 8
+#define SHIFT_2 2
+#define LENGTH_OF_BUFFER 11
+#define I2C_RETRY_COUNT 5
+
+#define BU21013_SENSORS_BTN_0_7_REG 0x70
+#define BU21013_SENSORS_BTN_8_15_REG 0x71
+#define BU21013_SENSORS_BTN_16_23_REG 0x72
+#define BU21013_X1_POS_MSB_REG 0x73
+#define BU21013_X1_POS_LSB_REG 0x74
+#define BU21013_Y1_POS_MSB_REG 0x75
+#define BU21013_Y1_POS_LSB_REG 0x76
+#define BU21013_X2_POS_MSB_REG 0x77
+#define BU21013_X2_POS_LSB_REG 0x78
+#define BU21013_Y2_POS_MSB_REG 0x79
+#define BU21013_Y2_POS_LSB_REG 0x7A
+#define BU21013_INT_CLR_REG 0xE8
+#define BU21013_INT_MODE_REG 0xE9
+#define BU21013_GAIN_REG 0xEA
+#define BU21013_OFFSET_MODE_REG 0xEB
+#define BU21013_XY_EDGE_REG 0xEC
+#define BU21013_RESET_REG 0xED
+#define BU21013_CALIB_REG 0xEE
+#define BU21013_DONE_REG 0xEF
+#define BU21013_SENSOR_0_7_REG 0xF0
+#define BU21013_SENSOR_8_15_REG 0xF1
+#define BU21013_SENSOR_16_23_REG 0xF2
+#define BU21013_POS_MODE1_REG 0xF3
+#define BU21013_POS_MODE2_REG 0xF4
+#define BU21013_CLK_MODE_REG 0xF5
+#define BU21013_IDLE_REG 0xFA
+#define BU21013_FILTER_REG 0xFB
+#define BU21013_TH_ON_REG 0xFC
+#define BU21013_TH_OFF_REG 0xFD
+
+
+#define BU21013_RESET_ENABLE 0x01
+
+#define BU21013_SENSORS_EN_0_7 0x3F
+#define BU21013_SENSORS_EN_8_15 0xFC
+#define BU21013_SENSORS_EN_16_23 0x1F
+
+#define BU21013_POS_MODE1_0 0x02
+#define BU21013_POS_MODE1_1 0x04
+#define BU21013_POS_MODE1_2 0x08
+
+#define BU21013_POS_MODE2_ZERO 0x01
+#define BU21013_POS_MODE2_AVG1 0x02
+#define BU21013_POS_MODE2_AVG2 0x04
+#define BU21013_POS_MODE2_EN_XY 0x08
+#define BU21013_POS_MODE2_EN_RAW 0x10
+#define BU21013_POS_MODE2_MULTI 0x80
+
+#define BU21013_CLK_MODE_DIV 0x01
+#define BU21013_CLK_MODE_EXT 0x02
+#define BU21013_CLK_MODE_CALIB 0x80
+
+#define BU21013_IDLET_0 0x01
+#define BU21013_IDLET_1 0x02
+#define BU21013_IDLET_2 0x04
+#define BU21013_IDLET_3 0x08
+#define BU21013_IDLE_INTERMIT_EN 0x10
+
+#define BU21013_DELTA_0_6 0x7F
+#define BU21013_FILTER_EN 0x80
+
+#define BU21013_INT_MODE_LEVEL 0x00
+#define BU21013_INT_MODE_EDGE 0x01
+
+#define BU21013_GAIN_0 0x01
+#define BU21013_GAIN_1 0x02
+#define BU21013_GAIN_2 0x04
+
+#define BU21013_OFFSET_MODE_DEFAULT 0x00
+#define BU21013_OFFSET_MODE_MOVE 0x01
+#define BU21013_OFFSET_MODE_DISABLE 0x02
+
+#define BU21013_TH_ON_0 0x01
+#define BU21013_TH_ON_1 0x02
+#define BU21013_TH_ON_2 0x04
+#define BU21013_TH_ON_3 0x08
+#define BU21013_TH_ON_4 0x10
+#define BU21013_TH_ON_5 0x20
+#define BU21013_TH_ON_6 0x40
+#define BU21013_TH_ON_7 0x80
+#define BU21013_TH_ON_MAX 0xFF
+
+#define BU21013_TH_OFF_0 0x01
+#define BU21013_TH_OFF_1 0x02
+#define BU21013_TH_OFF_2 0x04
+#define BU21013_TH_OFF_3 0x08
+#define BU21013_TH_OFF_4 0x10
+#define BU21013_TH_OFF_5 0x20
+#define BU21013_TH_OFF_6 0x40
+#define BU21013_TH_OFF_7 0x80
+#define BU21013_TH_OFF_MAX 0xFF
+
+#define BU21013_X_EDGE_0 0x01
+#define BU21013_X_EDGE_1 0x02
+#define BU21013_X_EDGE_2 0x04
+#define BU21013_X_EDGE_3 0x08
+#define BU21013_Y_EDGE_0 0x10
+#define BU21013_Y_EDGE_1 0x20
+#define BU21013_Y_EDGE_2 0x40
+#define BU21013_Y_EDGE_3 0x80
+
+#define BU21013_DONE 0x01
+#define BU21013_NUMBER_OF_X_SENSORS (6)
+#define BU21013_NUMBER_OF_Y_SENSORS (11)
+
+#define DRIVER_TP "bu21013_tp"
+
+/**
+ * struct bu21013_ts_data - touch panel data structure
+ * @client: pointer to the i2c client
+ * @wait: variable to wait_queue_head_t structure
+ * @touch_stopped: touch stop flag
+ * @chip: pointer to the touch panel controller
+ * @in_dev: pointer to the input device structure
+ * @intr_pin: interrupt pin value
+ *
+ * Touch panel device data structure
+ */
+struct bu21013_ts_data {
+ struct i2c_client *client;
+ wait_queue_head_t wait;
+ bool touch_stopped;
+ const struct bu21013_platform_device *chip;
+ struct input_dev *in_dev;
+ unsigned int intr_pin;
+};
+
+/**
+ * bu21013_read_block_data(): read the touch co-ordinates
+ * @data: bu21013_ts_data structure pointer
+ * @buf: byte pointer
+ *
+ * Read the touch co-ordinates using i2c read block into buffer
+ * and returns integer.
+ */
+static int bu21013_read_block_data(struct bu21013_ts_data *data, u8 *buf)
+{
+ int ret, i;
+
+ for (i = 0; i < I2C_RETRY_COUNT; i++) {
+ ret = i2c_smbus_read_i2c_block_data
+ (data->client, BU21013_SENSORS_BTN_0_7_REG,
+ LENGTH_OF_BUFFER, buf);
+ if (ret == LENGTH_OF_BUFFER)
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/**
+ * bu21013_do_touch_report(): Get the touch co-ordinates
+ * @data: bu21013_ts_data structure pointer
+ *
+ * Get the touch co-ordinates from touch sensor registers and writes
+ * into device structure and returns integer.
+ */
+static int bu21013_do_touch_report(struct bu21013_ts_data *data)
+{
+ u8 buf[LENGTH_OF_BUFFER];
+ unsigned int pos_x[2], pos_y[2];
+ bool has_x_sensors, has_y_sensors;
+ int finger_down_count = 0;
+ int i;
+
+ if (data == NULL)
+ return -EINVAL;
+
+ if (bu21013_read_block_data(data, buf) < 0)
+ return -EINVAL;
+
+ has_x_sensors = hweight32(buf[0] & BU21013_SENSORS_EN_0_7);
+ has_y_sensors = hweight32(((buf[1] & BU21013_SENSORS_EN_8_15) |
+ ((buf[2] & BU21013_SENSORS_EN_16_23) << SHIFT_8)) >> SHIFT_2);
+ if (!has_x_sensors || !has_y_sensors)
+ return 0;
+
+ for (i = 0; i < MAX_FINGERS; i++) {
+ const u8 *p = &buf[4 * i + 3];
+ unsigned int x = p[0] << SHIFT_2 | (p[1] & MASK_BITS);
+ unsigned int y = p[2] << SHIFT_2 | (p[3] & MASK_BITS);
+ if (x == 0 || y == 0)
+ continue;
+ pos_x[finger_down_count] = x;
+ pos_y[finger_down_count] = y;
+ finger_down_count++;
+ }
+
+ if (finger_down_count) {
+ if (finger_down_count == 2 &&
+ (abs(pos_x[0] - pos_x[1]) < DELTA_MIN ||
+ abs(pos_y[0] - pos_y[1]) < DELTA_MIN)) {
+ return 0;
+ }
+
+ for (i = 0; i < finger_down_count; i++) {
+ if (data->chip->x_flip)
+ pos_x[i] = data->chip->touch_x_max - pos_x[i];
+ if (data->chip->y_flip)
+ pos_y[i] = data->chip->touch_y_max - pos_y[i];
+
+ input_report_abs(data->in_dev,
+ ABS_MT_POSITION_X, pos_x[i]);
+ input_report_abs(data->in_dev,
+ ABS_MT_POSITION_Y, pos_y[i]);
+ input_mt_sync(data->in_dev);
+ }
+ } else
+ input_mt_sync(data->in_dev);
+
+ input_sync(data->in_dev);
+
+ return 0;
+}
+/**
+ * bu21013_gpio_irq() - gpio thread function for touch interrupt
+ * @irq: irq value
+ * @device_data: void pointer
+ *
+ * This gpio thread function for touch interrupt
+ * and returns irqreturn_t.
+ */
+static irqreturn_t bu21013_gpio_irq(int irq, void *device_data)
+{
+ struct bu21013_ts_data *data = device_data;
+ struct i2c_client *i2c = data->client;
+ int retval;
+
+ do {
+ retval = bu21013_do_touch_report(data);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "bu21013_do_touch_report failed\n");
+ return IRQ_NONE;
+ }
+
+ data->intr_pin = data->chip->irq_read_val();
+ if (data->intr_pin == PEN_DOWN_INTR)
+ wait_event_timeout(data->wait, data->touch_stopped,
+ msecs_to_jiffies(2));
+ } while (!data->intr_pin && !data->touch_stopped);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * bu21013_init_chip() - power on sequence for the bu21013 controller
+ * @data: device structure pointer
+ *
+ * This function is used to power on
+ * the bu21013 controller and returns integer.
+ */
+static int bu21013_init_chip(struct bu21013_ts_data *data)
+{
+ int retval;
+ struct i2c_client *i2c = data->client;
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_RESET_REG,
+ BU21013_RESET_ENABLE);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_RESET reg write failed\n");
+ return retval;
+ }
+ msleep(RESET_DELAY);
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_0_7_REG,
+ BU21013_SENSORS_EN_0_7);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_SENSOR_0_7 reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_8_15_REG,
+ BU21013_SENSORS_EN_8_15);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_SENSOR_8_15 reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_16_23_REG,
+ BU21013_SENSORS_EN_16_23);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_SENSOR_16_23 reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE1_REG,
+ (BU21013_POS_MODE1_0 | BU21013_POS_MODE1_1));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_POS_MODE1 reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE2_REG,
+ (BU21013_POS_MODE2_ZERO | BU21013_POS_MODE2_AVG1 |
+ BU21013_POS_MODE2_AVG2 | BU21013_POS_MODE2_EN_RAW |
+ BU21013_POS_MODE2_MULTI));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_POS_MODE2 reg write failed\n");
+ return retval;
+ }
+
+ if (data->chip->ext_clk)
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,
+ (BU21013_CLK_MODE_EXT | BU21013_CLK_MODE_CALIB));
+ else
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,
+ (BU21013_CLK_MODE_DIV | BU21013_CLK_MODE_CALIB));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_CLK_MODE reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_IDLE_REG,
+ (BU21013_IDLET_0 | BU21013_IDLE_INTERMIT_EN));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_IDLE reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_INT_MODE_REG,
+ BU21013_INT_MODE_LEVEL);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_INT_MODE reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_FILTER_REG,
+ (BU21013_DELTA_0_6 |
+ BU21013_FILTER_EN));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_FILTER reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_ON_REG,
+ BU21013_TH_ON_5);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_TH_ON reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF_REG,
+ BU21013_TH_OFF_4 || BU21013_TH_OFF_3);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_TH_OFF reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_GAIN_REG,
+ (BU21013_GAIN_0 | BU21013_GAIN_1));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_GAIN reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_OFFSET_MODE_REG,
+ BU21013_OFFSET_MODE_DEFAULT);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_OFFSET_MODE reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_XY_EDGE_REG,
+ (BU21013_X_EDGE_0 | BU21013_X_EDGE_2 |
+ BU21013_Y_EDGE_1 | BU21013_Y_EDGE_3));
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_XY_EDGE reg write failed\n");
+ return retval;
+ }
+
+ retval = i2c_smbus_write_byte_data(i2c, BU21013_DONE_REG,
+ BU21013_DONE);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "BU21013_REG_DONE reg write failed\n");
+ return retval;
+ }
+
+ return 0;
+}
+
+/**
+ * bu21013_free_irq() - frees IRQ registered for touchscreen
+ * @bu21013_data: device structure pointer
+ *
+ * This function signals interrupt thread to stop processing and
+ * frees interrupt.
+ */
+static void bu21013_free_irq(struct bu21013_ts_data *bu21013_data)
+{
+ bu21013_data->touch_stopped = true;
+ wake_up(&bu21013_data->wait);
+ free_irq(bu21013_data->chip->irq, bu21013_data);
+}
+
+/**
+ * bu21013_probe() - initializes the i2c-client touchscreen driver
+ * @client: i2c client structure pointer
+ * @id: i2c device id pointer
+ *
+ * This function used to initializes the i2c-client touchscreen
+ * driver and returns integer.
+ */
+static int __devinit bu21013_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct bu21013_ts_data *bu21013_data;
+ struct input_dev *in_dev;
+ const struct bu21013_platform_device *pdata =
+ client->dev.platform_data;
+ int error;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev, "i2c smbus byte data not supported\n");
+ return -EIO;
+ }
+
+ if (!pdata) {
+ dev_err(&client->dev, "platform data not defined\n");
+ return -EINVAL;
+ }
+
+ bu21013_data = kzalloc(sizeof(struct bu21013_ts_data), GFP_KERNEL);
+ in_dev = input_allocate_device();
+ if (!bu21013_data || !in_dev) {
+ dev_err(&client->dev, "device memory alloc failed\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ bu21013_data->in_dev = in_dev;
+ bu21013_data->chip = pdata;
+ bu21013_data->client = client;
+ bu21013_data->touch_stopped = false;
+ init_waitqueue_head(&bu21013_data->wait);
+
+ /* configure the gpio pins */
+ if (pdata->cs_en) {
+ error = pdata->cs_en(pdata->cs_pin);
+ if (error < 0) {
+ dev_err(&client->dev, "chip init failed\n");
+ goto err_free_mem;
+ }
+ }
+
+ /* configure the touch panel controller */
+ error = bu21013_init_chip(bu21013_data);
+ if (error) {
+ dev_err(&client->dev, "error in bu21013 config\n");
+ goto err_cs_disable;
+ }
+
+ /* register the device to input subsystem */
+ in_dev->name = DRIVER_TP;
+ in_dev->id.bustype = BUS_I2C;
+ in_dev->dev.parent = &client->dev;
+
+ __set_bit(EV_SYN, in_dev->evbit);
+ __set_bit(EV_KEY, in_dev->evbit);
+ __set_bit(EV_ABS, in_dev->evbit);
+
+ input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0,
+ pdata->x_max_res, 0, 0);
+ input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0,
+ pdata->y_max_res, 0, 0);
+ input_set_drvdata(in_dev, bu21013_data);
+
+ error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq,
+ IRQF_TRIGGER_FALLING | IRQF_SHARED,
+ DRIVER_TP, bu21013_data);
+ if (error) {
+ dev_err(&client->dev, "request irq %d failed\n", pdata->irq);
+ goto err_cs_disable;
+ }
+
+ error = input_register_device(in_dev);
+ if (error) {
+ dev_err(&client->dev, "failed to register input device\n");
+ goto err_free_irq;
+ }
+
+ device_init_wakeup(&client->dev, pdata->wakeup);
+ i2c_set_clientdata(client, bu21013_data);
+
+ return 0;
+
+err_free_irq:
+ bu21013_free_irq(bu21013_data);
+err_cs_disable:
+ pdata->cs_dis(pdata->cs_pin);
+err_free_mem:
+ input_free_device(bu21013_data->in_dev);
+ kfree(bu21013_data);
+
+ return error;
+}
+/**
+ * bu21013_remove() - removes the i2c-client touchscreen driver
+ * @client: i2c client structure pointer
+ *
+ * This function uses to remove the i2c-client
+ * touchscreen driver and returns integer.
+ */
+static int __devexit bu21013_remove(struct i2c_client *client)
+{
+ struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client);
+
+ bu21013_free_irq(bu21013_data);
+
+ bu21013_data->chip->cs_dis(bu21013_data->chip->cs_pin);
+
+ input_unregister_device(bu21013_data->in_dev);
+ kfree(bu21013_data);
+
+ device_init_wakeup(&client->dev, false);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/**
+ * bu21013_suspend() - suspend the touch screen controller
+ * @dev: pointer to device structure
+ *
+ * This function is used to suspend the
+ * touch panel controller and returns integer
+ */
+static int bu21013_suspend(struct device *dev)
+{
+ struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);
+ struct i2c_client *client = bu21013_data->client;
+
+ bu21013_data->touch_stopped = true;
+ if (device_may_wakeup(&client->dev))
+ enable_irq_wake(bu21013_data->chip->irq);
+ else
+ disable_irq(bu21013_data->chip->irq);
+
+ return 0;
+}
+
+/**
+ * bu21013_resume() - resume the touch screen controller
+ * @dev: pointer to device structure
+ *
+ * This function is used to resume the touch panel
+ * controller and returns integer.
+ */
+static int bu21013_resume(struct device *dev)
+{
+ struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);
+ struct i2c_client *client = bu21013_data->client;
+ int retval;
+
+ retval = bu21013_init_chip(bu21013_data);
+ if (retval < 0) {
+ dev_err(&client->dev, "bu21013 controller config failed\n");
+ return retval;
+ }
+
+ bu21013_data->touch_stopped = false;
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq_wake(bu21013_data->chip->irq);
+ else
+ enable_irq(bu21013_data->chip->irq);
+
+ return 0;
+}
+
+static const struct dev_pm_ops bu21013_dev_pm_ops = {
+ .suspend = bu21013_suspend,
+ .resume = bu21013_resume,
+};
+#endif
+
+static const struct i2c_device_id bu21013_id[] = {
+ { DRIVER_TP, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, bu21013_id);
+
+static struct i2c_driver bu21013_driver = {
+ .driver = {
+ .name = DRIVER_TP,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &bu21013_dev_pm_ops,
+#endif
+ },
+ .probe = bu21013_probe,
+ .remove = __devexit_p(bu21013_remove),
+ .id_table = bu21013_id,
+};
+
+/**
+ * bu21013_init() - initializes the bu21013 touchscreen driver
+ *
+ * This function used to initializes the bu21013
+ * touchscreen driver and returns integer.
+ */
+static int __init bu21013_init(void)
+{
+ return i2c_add_driver(&bu21013_driver);
+}
+
+/**
+ * bu21013_exit() - de-initializes the bu21013 touchscreen driver
+ *
+ * This function uses to de-initializes the bu21013
+ * touchscreen driver and returns none.
+ */
+static void __exit bu21013_exit(void)
+{
+ i2c_del_driver(&bu21013_driver);
+}
+
+module_init(bu21013_init);
+module_exit(bu21013_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Naveen Kumar G <naveen.gaddipati@stericsson.com>");
+MODULE_DESCRIPTION("bu21013 touch screen controller driver");
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c
index 5ec0946938fe..d0c3a7229adf 100644
--- a/drivers/input/touchscreen/cy8ctmg110_ts.c
+++ b/drivers/input/touchscreen/cy8ctmg110_ts.c
@@ -206,9 +206,9 @@ static int __devinit cy8ctmg110_probe(struct i2c_client *client,
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X,
- CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 0, 0);
+ CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 4, 0);
input_set_abs_params(input_dev, ABS_Y,
- CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 0, 0);
+ CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 4, 0);
if (ts->reset_pin) {
err = gpio_request(ts->reset_pin, NULL);
diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c
index a89700e7ace4..498bd62af09a 100644
--- a/drivers/input/touchscreen/hp680_ts_input.c
+++ b/drivers/input/touchscreen/hp680_ts_input.c
@@ -107,8 +107,7 @@ static int __init hp680_ts_init(void)
return 0;
fail2: free_irq(HP680_TS_IRQ, NULL);
- cancel_delayed_work(&work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&work);
fail1: input_free_device(hp680_ts_dev);
return err;
}
@@ -116,8 +115,7 @@ static int __init hp680_ts_init(void)
static void __exit hp680_ts_exit(void)
{
free_irq(HP680_TS_IRQ, NULL);
- cancel_delayed_work(&work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&work);
input_unregister_device(hp680_ts_dev);
}
diff --git a/drivers/input/touchscreen/intel-mid-touch.c b/drivers/input/touchscreen/intel-mid-touch.c
new file mode 100644
index 000000000000..c0307b22d86f
--- /dev/null
+++ b/drivers/input/touchscreen/intel-mid-touch.c
@@ -0,0 +1,687 @@
+/*
+ * Intel MID Resistive Touch Screen Driver
+ *
+ * Copyright (C) 2008 Intel Corp
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.
+ *
+ * Questions/Comments/Bug fixes to Sreedhara (sreedhara.ds@intel.com)
+ * Ramesh Agarwal (ramesh.agarwal@intel.com)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * TODO:
+ * review conversion of r/m/w sequences
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/param.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <asm/intel_scu_ipc.h>
+
+/* PMIC Interrupt registers */
+#define PMIC_REG_ID1 0x00 /* PMIC ID1 register */
+
+/* PMIC Interrupt registers */
+#define PMIC_REG_INT 0x04 /* PMIC interrupt register */
+#define PMIC_REG_MINT 0x05 /* PMIC interrupt mask register */
+
+/* ADC Interrupt registers */
+#define PMIC_REG_ADCINT 0x5F /* ADC interrupt register */
+#define PMIC_REG_MADCINT 0x60 /* ADC interrupt mask register */
+
+/* ADC Control registers */
+#define PMIC_REG_ADCCNTL1 0x61 /* ADC control register */
+
+/* ADC Channel Selection registers */
+#define PMICADDR0 0xA4
+#define END_OF_CHANNEL 0x1F
+
+/* ADC Result register */
+#define PMIC_REG_ADCSNS0H 0x64
+
+/* ADC channels for touch screen */
+#define MRST_TS_CHAN10 0xA /* Touch screen X+ connection */
+#define MRST_TS_CHAN11 0xB /* Touch screen X- connection */
+#define MRST_TS_CHAN12 0xC /* Touch screen Y+ connection */
+#define MRST_TS_CHAN13 0xD /* Touch screen Y- connection */
+
+/* Touch screen channel BIAS constants */
+#define MRST_XBIAS 0x20
+#define MRST_YBIAS 0x40
+#define MRST_ZBIAS 0x80
+
+/* Touch screen coordinates */
+#define MRST_X_MIN 10
+#define MRST_X_MAX 1024
+#define MRST_X_FUZZ 5
+#define MRST_Y_MIN 10
+#define MRST_Y_MAX 1024
+#define MRST_Y_FUZZ 5
+#define MRST_PRESSURE_MIN 0
+#define MRST_PRESSURE_NOMINAL 50
+#define MRST_PRESSURE_MAX 100
+
+#define WAIT_ADC_COMPLETION 10 /* msec */
+
+/* PMIC ADC round robin delays */
+#define ADC_LOOP_DELAY0 0x0 /* Continuous loop */
+#define ADC_LOOP_DELAY1 0x1 /* 4.5 ms approximate */
+
+/* PMIC Vendor Identifiers */
+#define PMIC_VENDOR_FS 0 /* PMIC vendor FreeScale */
+#define PMIC_VENDOR_MAXIM 1 /* PMIC vendor MAXIM */
+#define PMIC_VENDOR_NEC 2 /* PMIC vendor NEC */
+#define MRSTOUCH_MAX_CHANNELS 32 /* Maximum ADC channels */
+
+/* Touch screen device structure */
+struct mrstouch_dev {
+ struct device *dev; /* device associated with touch screen */
+ struct input_dev *input;
+ char phys[32];
+ u16 asr; /* Address selection register */
+ int irq;
+ unsigned int vendor; /* PMIC vendor */
+ unsigned int rev; /* PMIC revision */
+
+ int (*read_prepare)(struct mrstouch_dev *tsdev);
+ int (*read)(struct mrstouch_dev *tsdev, u16 *x, u16 *y, u16 *z);
+ int (*read_finish)(struct mrstouch_dev *tsdev);
+};
+
+
+/*************************** NEC and Maxim Interface ************************/
+
+static int mrstouch_nec_adc_read_prepare(struct mrstouch_dev *tsdev)
+{
+ return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0, 0x20);
+}
+
+/*
+ * Enables PENDET interrupt.
+ */
+static int mrstouch_nec_adc_read_finish(struct mrstouch_dev *tsdev)
+{
+ int err;
+
+ err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x20, 0x20);
+ if (!err)
+ err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, 0, 0x05);
+
+ return err;
+}
+
+/*
+ * Reads PMIC ADC touch screen result
+ * Reads ADC storage registers for higher 7 and lower 3 bits and
+ * converts the two readings into a single value and turns off gain bit
+ */
+static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm)
+{
+ int err;
+ u16 result;
+ u32 res;
+
+ result = PMIC_REG_ADCSNS0H + offset;
+
+ if (chan == MRST_TS_CHAN12)
+ result += 4;
+
+ err = intel_scu_ipc_ioread32(result, &res);
+ if (err)
+ return err;
+
+ /* Mash the bits up */
+
+ *vp = (res & 0xFF) << 3; /* Highest 7 bits */
+ *vp |= (res >> 8) & 0x07; /* Lower 3 bits */
+ *vp &= 0x3FF;
+
+ res >>= 16;
+
+ *vm = (res & 0xFF) << 3; /* Highest 7 bits */
+ *vm |= (res >> 8) & 0x07; /* Lower 3 bits */
+ *vm &= 0x3FF;
+
+ return 0;
+}
+
+/*
+ * Enables X, Y and Z bias values
+ * Enables YPYM for X channels and XPXM for Y channels
+ */
+static int mrstouch_ts_bias_set(uint offset, uint bias)
+{
+ int count;
+ u16 chan, start;
+ u16 reg[4];
+ u8 data[4];
+
+ chan = PMICADDR0 + offset;
+ start = MRST_TS_CHAN10;
+
+ for (count = 0; count <= 3; count++) {
+ reg[count] = chan++;
+ data[count] = bias | (start + count);
+ }
+
+ return intel_scu_ipc_writev(reg, data, 4);
+}
+
+/* To read touch screen channel values */
+static int mrstouch_nec_adc_read(struct mrstouch_dev *tsdev,
+ u16 *x, u16 *y, u16 *z)
+{
+ int err;
+ u16 xm, ym, zm;
+
+ /* configure Y bias for X channels */
+ err = mrstouch_ts_bias_set(tsdev->asr, MRST_YBIAS);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* read x+ and x- channels */
+ err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, x, &xm);
+ if (err)
+ goto ipc_error;
+
+ /* configure x bias for y channels */
+ err = mrstouch_ts_bias_set(tsdev->asr, MRST_XBIAS);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* read y+ and y- channels */
+ err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN12, y, &ym);
+ if (err)
+ goto ipc_error;
+
+ /* configure z bias for x and y channels */
+ err = mrstouch_ts_bias_set(tsdev->asr, MRST_ZBIAS);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* read z+ and z- channels */
+ err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, z, &zm);
+ if (err)
+ goto ipc_error;
+
+ return 0;
+
+ipc_error:
+ dev_err(tsdev->dev, "ipc error during adc read\n");
+ return err;
+}
+
+
+/*************************** Freescale Interface ************************/
+
+static int mrstouch_fs_adc_read_prepare(struct mrstouch_dev *tsdev)
+{
+ int err, count;
+ u16 chan;
+ u16 reg[5];
+ u8 data[5];
+
+ /* Stop the ADC */
+ err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x00, 0x02);
+ if (err)
+ goto ipc_error;
+
+ chan = PMICADDR0 + tsdev->asr;
+
+ /* Set X BIAS */
+ for (count = 0; count <= 3; count++) {
+ reg[count] = chan++;
+ data[count] = 0x2A;
+ }
+ reg[count] = chan++; /* Dummy */
+ data[count] = 0;
+
+ err = intel_scu_ipc_writev(reg, data, 5);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* Set Y BIAS */
+ for (count = 0; count <= 3; count++) {
+ reg[count] = chan++;
+ data[count] = 0x4A;
+ }
+ reg[count] = chan++; /* Dummy */
+ data[count] = 0;
+
+ err = intel_scu_ipc_writev(reg, data, 5);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* Set Z BIAS */
+ err = intel_scu_ipc_iowrite32(chan + 2, 0x8A8A8A8A);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ return 0;
+
+ipc_error:
+ dev_err(tsdev->dev, "ipc error during %s\n", __func__);
+ return err;
+}
+
+static int mrstouch_fs_adc_read(struct mrstouch_dev *tsdev,
+ u16 *x, u16 *y, u16 *z)
+{
+ int err;
+ u16 result;
+ u16 reg[4];
+ u8 data[4];
+
+ result = PMIC_REG_ADCSNS0H + tsdev->asr;
+
+ reg[0] = result + 4;
+ reg[1] = result + 5;
+ reg[2] = result + 16;
+ reg[3] = result + 17;
+
+ err = intel_scu_ipc_readv(reg, data, 4);
+ if (err)
+ goto ipc_error;
+
+ *x = data[0] << 3; /* Higher 7 bits */
+ *x |= data[1] & 0x7; /* Lower 3 bits */
+ *x &= 0x3FF;
+
+ *y = data[2] << 3; /* Higher 7 bits */
+ *y |= data[3] & 0x7; /* Lower 3 bits */
+ *y &= 0x3FF;
+
+ /* Read Z value */
+ reg[0] = result + 28;
+ reg[1] = result + 29;
+
+ err = intel_scu_ipc_readv(reg, data, 4);
+ if (err)
+ goto ipc_error;
+
+ *z = data[0] << 3; /* Higher 7 bits */
+ *z |= data[1] & 0x7; /* Lower 3 bits */
+ *z &= 0x3FF;
+
+ return 0;
+
+ipc_error:
+ dev_err(tsdev->dev, "ipc error during %s\n", __func__);
+ return err;
+}
+
+static int mrstouch_fs_adc_read_finish(struct mrstouch_dev *tsdev)
+{
+ int err, count;
+ u16 chan;
+ u16 reg[5];
+ u8 data[5];
+
+ /* Clear all TS channels */
+ chan = PMICADDR0 + tsdev->asr;
+ for (count = 0; count <= 4; count++) {
+ reg[count] = chan++;
+ data[count] = 0;
+ }
+ err = intel_scu_ipc_writev(reg, data, 5);
+ if (err)
+ goto ipc_error;
+
+ for (count = 0; count <= 4; count++) {
+ reg[count] = chan++;
+ data[count] = 0;
+ }
+ err = intel_scu_ipc_writev(reg, data, 5);
+ if (err)
+ goto ipc_error;
+
+ err = intel_scu_ipc_iowrite32(chan + 2, 0x00000000);
+ if (err)
+ goto ipc_error;
+
+ /* Start ADC */
+ err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x02, 0x02);
+ if (err)
+ goto ipc_error;
+
+ return 0;
+
+ipc_error:
+ dev_err(tsdev->dev, "ipc error during %s\n", __func__);
+ return err;
+}
+
+static void mrstouch_report_event(struct input_dev *input,
+ unsigned int x, unsigned int y, unsigned int z)
+{
+ if (z > MRST_PRESSURE_NOMINAL) {
+ /* Pen touched, report button touch and coordinates */
+ input_report_key(input, BTN_TOUCH, 1);
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+ } else {
+ input_report_key(input, BTN_TOUCH, 0);
+ }
+
+ input_report_abs(input, ABS_PRESSURE, z);
+ input_sync(input);
+}
+
+/* PENDET interrupt handler */
+static irqreturn_t mrstouch_pendet_irq(int irq, void *dev_id)
+{
+ struct mrstouch_dev *tsdev = dev_id;
+ u16 x, y, z;
+
+ /*
+ * Should we lower thread priority? Probably not, since we are
+ * not spinning but sleeping...
+ */
+
+ if (tsdev->read_prepare(tsdev))
+ goto out;
+
+ do {
+ if (tsdev->read(tsdev, &x, &y, &z))
+ break;
+
+ mrstouch_report_event(tsdev->input, x, y, z);
+ } while (z > MRST_PRESSURE_NOMINAL);
+
+ tsdev->read_finish(tsdev);
+
+out:
+ return IRQ_HANDLED;
+}
+
+/* Utility to read PMIC ID */
+static int __devinit mrstouch_read_pmic_id(uint *vendor, uint *rev)
+{
+ int err;
+ u8 r;
+
+ err = intel_scu_ipc_ioread8(PMIC_REG_ID1, &r);
+ if (err)
+ return err;
+
+ *vendor = r & 0x7;
+ *rev = (r >> 3) & 0x7;
+
+ return 0;
+}
+
+/*
+ * Parse ADC channels to find end of the channel configured by other ADC user
+ * NEC and MAXIM requires 4 channels and FreeScale needs 18 channels
+ */
+static int __devinit mrstouch_chan_parse(struct mrstouch_dev *tsdev)
+{
+ int err, i, found;
+ u8 r8;
+
+ found = -1;
+
+ for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) {
+ if (found >= 0)
+ break;
+
+ err = intel_scu_ipc_ioread8(PMICADDR0 + i, &r8);
+ if (err)
+ return err;
+
+ if (r8 == END_OF_CHANNEL) {
+ found = i;
+ break;
+ }
+ }
+ if (found < 0)
+ return 0;
+
+ if (tsdev->vendor == PMIC_VENDOR_FS) {
+ if (found && found > (MRSTOUCH_MAX_CHANNELS - 18))
+ return -ENOSPC;
+ } else {
+ if (found && found > (MRSTOUCH_MAX_CHANNELS - 4))
+ return -ENOSPC;
+ }
+ return found;
+}
+
+
+/*
+ * Writes touch screen channels to ADC address selection registers
+ */
+static int __devinit mrstouch_ts_chan_set(uint offset)
+{
+ u16 chan;
+
+ int ret, count;
+
+ chan = PMICADDR0 + offset;
+ for (count = 0; count <= 3; count++) {
+ ret = intel_scu_ipc_iowrite8(chan++, MRST_TS_CHAN10 + count);
+ if (ret)
+ return ret;
+ }
+ return intel_scu_ipc_iowrite8(chan++, END_OF_CHANNEL);
+}
+
+/* Initialize ADC */
+static int __devinit mrstouch_adc_init(struct mrstouch_dev *tsdev)
+{
+ int err, start;
+ u8 ra, rm;
+
+ err = mrstouch_read_pmic_id(&tsdev->vendor, &tsdev->rev);
+ if (err) {
+ dev_err(tsdev->dev, "Unable to read PMIC id\n");
+ return err;
+ }
+
+ switch (tsdev->vendor) {
+ case PMIC_VENDOR_NEC:
+ case PMIC_VENDOR_MAXIM:
+ tsdev->read_prepare = mrstouch_nec_adc_read_prepare;
+ tsdev->read = mrstouch_nec_adc_read;
+ tsdev->read_finish = mrstouch_nec_adc_read_finish;
+ break;
+
+ case PMIC_VENDOR_FS:
+ tsdev->read_prepare = mrstouch_fs_adc_read_prepare;
+ tsdev->read = mrstouch_fs_adc_read;
+ tsdev->read_finish = mrstouch_fs_adc_read_finish;
+ break;
+
+ default:
+ dev_err(tsdev->dev,
+ "Unsupported touchscreen: %d\n", tsdev->vendor);
+ return -ENXIO;
+ }
+
+ start = mrstouch_chan_parse(tsdev);
+ if (start < 0) {
+ dev_err(tsdev->dev, "Unable to parse channels\n");
+ return start;
+ }
+
+ tsdev->asr = start;
+
+ /*
+ * ADC power on, start, enable PENDET and set loop delay
+ * ADC loop delay is set to 4.5 ms approximately
+ * Loop delay more than this results in jitter in adc readings
+ * Setting loop delay to 0 (continous loop) in MAXIM stops PENDET
+ * interrupt generation sometimes.
+ */
+
+ if (tsdev->vendor == PMIC_VENDOR_FS) {
+ ra = 0xE0 | ADC_LOOP_DELAY0;
+ rm = 0x5;
+ } else {
+ /* NEC and MAXIm not consistent with loop delay 0 */
+ ra = 0xE0 | ADC_LOOP_DELAY1;
+ rm = 0x0;
+
+ /* configure touch screen channels */
+ err = mrstouch_ts_chan_set(tsdev->asr);
+ if (err)
+ return err;
+ }
+
+ err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, ra, 0xE7);
+ if (err)
+ return err;
+
+ err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, rm, 0x03);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+
+/* Probe function for touch screen driver */
+static int __devinit mrstouch_probe(struct platform_device *pdev)
+{
+ struct mrstouch_dev *tsdev;
+ struct input_dev *input;
+ int err;
+ int irq;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no interrupt assigned\n");
+ return -EINVAL;
+ }
+
+ tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!tsdev || !input) {
+ dev_err(&pdev->dev, "unable to allocate memory\n");
+ err = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ tsdev->dev = &pdev->dev;
+ tsdev->input = input;
+ tsdev->irq = irq;
+
+ snprintf(tsdev->phys, sizeof(tsdev->phys),
+ "%s/input0", dev_name(tsdev->dev));
+
+ err = mrstouch_adc_init(tsdev);
+ if (err) {
+ dev_err(&pdev->dev, "ADC initialization failed\n");
+ goto err_free_mem;
+ }
+
+ input->name = "mrst_touchscreen";
+ input->phys = tsdev->phys;
+ input->dev.parent = tsdev->dev;
+
+ input->id.vendor = tsdev->vendor;
+ input->id.version = tsdev->rev;
+
+ input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ input_set_abs_params(tsdev->input, ABS_X,
+ MRST_X_MIN, MRST_X_MAX, MRST_X_FUZZ, 0);
+ input_set_abs_params(tsdev->input, ABS_Y,
+ MRST_Y_MIN, MRST_Y_MAX, MRST_Y_FUZZ, 0);
+ input_set_abs_params(tsdev->input, ABS_PRESSURE,
+ MRST_PRESSURE_MIN, MRST_PRESSURE_MAX, 0, 0);
+
+ err = request_threaded_irq(tsdev->irq, NULL, mrstouch_pendet_irq,
+ 0, "mrstouch", tsdev);
+ if (err) {
+ dev_err(tsdev->dev, "unable to allocate irq\n");
+ goto err_free_mem;
+ }
+
+ err = input_register_device(tsdev->input);
+ if (err) {
+ dev_err(tsdev->dev, "unable to register input device\n");
+ goto err_free_irq;
+ }
+
+ platform_set_drvdata(pdev, tsdev);
+ return 0;
+
+err_free_irq:
+ free_irq(tsdev->irq, tsdev);
+err_free_mem:
+ input_free_device(input);
+ kfree(tsdev);
+ return err;
+}
+
+static int __devexit mrstouch_remove(struct platform_device *pdev)
+{
+ struct mrstouch_dev *tsdev = platform_get_drvdata(pdev);
+
+ free_irq(tsdev->irq, tsdev);
+ input_unregister_device(tsdev->input);
+ kfree(tsdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver mrstouch_driver = {
+ .driver = {
+ .name = "pmic_touch",
+ .owner = THIS_MODULE,
+ },
+ .probe = mrstouch_probe,
+ .remove = __devexit_p(mrstouch_remove),
+};
+
+static int __init mrstouch_init(void)
+{
+ return platform_driver_register(&mrstouch_driver);
+}
+module_init(mrstouch_init);
+
+static void __exit mrstouch_exit(void)
+{
+ platform_driver_unregister(&mrstouch_driver);
+}
+module_exit(mrstouch_exit);
+
+MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com");
+MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c
new file mode 100644
index 000000000000..dcf803f5a1f7
--- /dev/null
+++ b/drivers/input/touchscreen/lpc32xx_ts.c
@@ -0,0 +1,411 @@
+/*
+ * LPC32xx built-in touchscreen driver
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+/*
+ * Touchscreen controller register offsets
+ */
+#define LPC32XX_TSC_STAT 0x00
+#define LPC32XX_TSC_SEL 0x04
+#define LPC32XX_TSC_CON 0x08
+#define LPC32XX_TSC_FIFO 0x0C
+#define LPC32XX_TSC_DTR 0x10
+#define LPC32XX_TSC_RTR 0x14
+#define LPC32XX_TSC_UTR 0x18
+#define LPC32XX_TSC_TTR 0x1C
+#define LPC32XX_TSC_DXP 0x20
+#define LPC32XX_TSC_MIN_X 0x24
+#define LPC32XX_TSC_MAX_X 0x28
+#define LPC32XX_TSC_MIN_Y 0x2C
+#define LPC32XX_TSC_MAX_Y 0x30
+#define LPC32XX_TSC_AUX_UTR 0x34
+#define LPC32XX_TSC_AUX_MIN 0x38
+#define LPC32XX_TSC_AUX_MAX 0x3C
+
+#define LPC32XX_TSC_STAT_FIFO_OVRRN (1 << 8)
+#define LPC32XX_TSC_STAT_FIFO_EMPTY (1 << 7)
+
+#define LPC32XX_TSC_SEL_DEFVAL 0x0284
+
+#define LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4 (0x1 << 11)
+#define LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(s) ((10 - (s)) << 7)
+#define LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(s) ((10 - (s)) << 4)
+#define LPC32XX_TSC_ADCCON_POWER_UP (1 << 2)
+#define LPC32XX_TSC_ADCCON_AUTO_EN (1 << 0)
+
+#define LPC32XX_TSC_FIFO_TS_P_LEVEL (1 << 31)
+#define LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(x) (((x) & 0x03FF0000) >> 16)
+#define LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(y) ((y) & 0x000003FF)
+
+#define LPC32XX_TSC_ADCDAT_VALUE_MASK 0x000003FF
+
+#define LPC32XX_TSC_MIN_XY_VAL 0x0
+#define LPC32XX_TSC_MAX_XY_VAL 0x3FF
+
+#define MOD_NAME "ts-lpc32xx"
+
+#define tsc_readl(dev, reg) \
+ __raw_readl((dev)->tsc_base + (reg))
+#define tsc_writel(dev, reg, val) \
+ __raw_writel((val), (dev)->tsc_base + (reg))
+
+struct lpc32xx_tsc {
+ struct input_dev *dev;
+ void __iomem *tsc_base;
+ int irq;
+ struct clk *clk;
+};
+
+static void lpc32xx_fifo_clear(struct lpc32xx_tsc *tsc)
+{
+ while (!(tsc_readl(tsc, LPC32XX_TSC_STAT) &
+ LPC32XX_TSC_STAT_FIFO_EMPTY))
+ tsc_readl(tsc, LPC32XX_TSC_FIFO);
+}
+
+static irqreturn_t lpc32xx_ts_interrupt(int irq, void *dev_id)
+{
+ u32 tmp, rv[4], xs[4], ys[4];
+ int idx;
+ struct lpc32xx_tsc *tsc = dev_id;
+ struct input_dev *input = tsc->dev;
+
+ tmp = tsc_readl(tsc, LPC32XX_TSC_STAT);
+
+ if (tmp & LPC32XX_TSC_STAT_FIFO_OVRRN) {
+ /* FIFO overflow - throw away samples */
+ lpc32xx_fifo_clear(tsc);
+ return IRQ_HANDLED;
+ }
+
+ /*
+ * Gather and normalize 4 samples. Pen-up events may have less
+ * than 4 samples, but its ok to pop 4 and let the last sample
+ * pen status check drop the samples.
+ */
+ idx = 0;
+ while (idx < 4 &&
+ !(tsc_readl(tsc, LPC32XX_TSC_STAT) &
+ LPC32XX_TSC_STAT_FIFO_EMPTY)) {
+ tmp = tsc_readl(tsc, LPC32XX_TSC_FIFO);
+ xs[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
+ LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(tmp);
+ ys[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
+ LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(tmp);
+ rv[idx] = tmp;
+ idx++;
+ }
+
+ /* Data is only valid if pen is still down in last sample */
+ if (!(rv[3] & LPC32XX_TSC_FIFO_TS_P_LEVEL) && idx == 4) {
+ /* Use average of 2nd and 3rd sample for position */
+ input_report_abs(input, ABS_X, (xs[1] + xs[2]) / 2);
+ input_report_abs(input, ABS_Y, (ys[1] + ys[2]) / 2);
+ input_report_key(input, BTN_TOUCH, 1);
+ } else {
+ input_report_key(input, BTN_TOUCH, 0);
+ }
+
+ input_sync(input);
+
+ return IRQ_HANDLED;
+}
+
+static void lpc32xx_stop_tsc(struct lpc32xx_tsc *tsc)
+{
+ /* Disable auto mode */
+ tsc_writel(tsc, LPC32XX_TSC_CON,
+ tsc_readl(tsc, LPC32XX_TSC_CON) &
+ ~LPC32XX_TSC_ADCCON_AUTO_EN);
+
+ clk_disable(tsc->clk);
+}
+
+static void lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc)
+{
+ u32 tmp;
+
+ clk_enable(tsc->clk);
+
+ tmp = tsc_readl(tsc, LPC32XX_TSC_CON) & ~LPC32XX_TSC_ADCCON_POWER_UP;
+
+ /* Set the TSC FIFO depth to 4 samples @ 10-bits per sample (max) */
+ tmp = LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4 |
+ LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(10) |
+ LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(10);
+ tsc_writel(tsc, LPC32XX_TSC_CON, tmp);
+
+ /* These values are all preset */
+ tsc_writel(tsc, LPC32XX_TSC_SEL, LPC32XX_TSC_SEL_DEFVAL);
+ tsc_writel(tsc, LPC32XX_TSC_MIN_X, LPC32XX_TSC_MIN_XY_VAL);
+ tsc_writel(tsc, LPC32XX_TSC_MAX_X, LPC32XX_TSC_MAX_XY_VAL);
+ tsc_writel(tsc, LPC32XX_TSC_MIN_Y, LPC32XX_TSC_MIN_XY_VAL);
+ tsc_writel(tsc, LPC32XX_TSC_MAX_Y, LPC32XX_TSC_MAX_XY_VAL);
+
+ /* Aux support is not used */
+ tsc_writel(tsc, LPC32XX_TSC_AUX_UTR, 0);
+ tsc_writel(tsc, LPC32XX_TSC_AUX_MIN, 0);
+ tsc_writel(tsc, LPC32XX_TSC_AUX_MAX, 0);
+
+ /*
+ * Set sample rate to about 240Hz per X/Y pair. A single measurement
+ * consists of 4 pairs which gives about a 60Hz sample rate based on
+ * a stable 32768Hz clock source. Values are in clocks.
+ * Rate is (32768 / (RTR + XCONV + RTR + YCONV + DXP + TTR + UTR) / 4
+ */
+ tsc_writel(tsc, LPC32XX_TSC_RTR, 0x2);
+ tsc_writel(tsc, LPC32XX_TSC_DTR, 0x2);
+ tsc_writel(tsc, LPC32XX_TSC_TTR, 0x10);
+ tsc_writel(tsc, LPC32XX_TSC_DXP, 0x4);
+ tsc_writel(tsc, LPC32XX_TSC_UTR, 88);
+
+ lpc32xx_fifo_clear(tsc);
+
+ /* Enable automatic ts event capture */
+ tsc_writel(tsc, LPC32XX_TSC_CON, tmp | LPC32XX_TSC_ADCCON_AUTO_EN);
+}
+
+static int lpc32xx_ts_open(struct input_dev *dev)
+{
+ struct lpc32xx_tsc *tsc = input_get_drvdata(dev);
+
+ lpc32xx_setup_tsc(tsc);
+
+ return 0;
+}
+
+static void lpc32xx_ts_close(struct input_dev *dev)
+{
+ struct lpc32xx_tsc *tsc = input_get_drvdata(dev);
+
+ lpc32xx_stop_tsc(tsc);
+}
+
+static int __devinit lpc32xx_ts_probe(struct platform_device *pdev)
+{
+ struct lpc32xx_tsc *tsc;
+ struct input_dev *input;
+ struct resource *res;
+ resource_size_t size;
+ int irq;
+ int error;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Can't get memory resource\n");
+ return -ENOENT;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Can't get interrupt resource\n");
+ return irq;
+ }
+
+ tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!tsc || !input) {
+ dev_err(&pdev->dev, "failed allocating memory\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ tsc->dev = input;
+ tsc->irq = irq;
+
+ size = resource_size(res);
+
+ if (!request_mem_region(res->start, size, pdev->name)) {
+ dev_err(&pdev->dev, "TSC registers are not free\n");
+ error = -EBUSY;
+ goto err_free_mem;
+ }
+
+ tsc->tsc_base = ioremap(res->start, size);
+ if (!tsc->tsc_base) {
+ dev_err(&pdev->dev, "Can't map memory\n");
+ error = -ENOMEM;
+ goto err_release_mem;
+ }
+
+ tsc->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(tsc->clk)) {
+ dev_err(&pdev->dev, "failed getting clock\n");
+ error = PTR_ERR(tsc->clk);
+ goto err_unmap;
+ }
+
+ input->name = MOD_NAME;
+ input->phys = "lpc32xx/input0";
+ input->id.bustype = BUS_HOST;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x0002;
+ input->id.version = 0x0100;
+ input->dev.parent = &pdev->dev;
+ input->open = lpc32xx_ts_open;
+ input->close = lpc32xx_ts_close;
+
+ input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ input_set_abs_params(input, ABS_X, LPC32XX_TSC_MIN_XY_VAL,
+ LPC32XX_TSC_MAX_XY_VAL, 0, 0);
+ input_set_abs_params(input, ABS_Y, LPC32XX_TSC_MIN_XY_VAL,
+ LPC32XX_TSC_MAX_XY_VAL, 0, 0);
+
+ input_set_drvdata(input, tsc);
+
+ error = request_irq(tsc->irq, lpc32xx_ts_interrupt,
+ IRQF_DISABLED, pdev->name, tsc);
+ if (error) {
+ dev_err(&pdev->dev, "failed requesting interrupt\n");
+ goto err_put_clock;
+ }
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&pdev->dev, "failed registering input device\n");
+ goto err_free_irq;
+ }
+
+ platform_set_drvdata(pdev, tsc);
+ device_init_wakeup(&pdev->dev, 1);
+
+ return 0;
+
+err_free_irq:
+ free_irq(tsc->irq, tsc);
+err_put_clock:
+ clk_put(tsc->clk);
+err_unmap:
+ iounmap(tsc->tsc_base);
+err_release_mem:
+ release_mem_region(res->start, size);
+err_free_mem:
+ input_free_device(input);
+ kfree(tsc);
+
+ return error;
+}
+
+static int __devexit lpc32xx_ts_remove(struct platform_device *pdev)
+{
+ struct lpc32xx_tsc *tsc = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ device_init_wakeup(&pdev->dev, 0);
+ free_irq(tsc->irq, tsc);
+
+ input_unregister_device(tsc->dev);
+
+ clk_put(tsc->clk);
+
+ iounmap(tsc->tsc_base);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(tsc);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int lpc32xx_ts_suspend(struct device *dev)
+{
+ struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);
+ struct input_dev *input = tsc->dev;
+
+ /*
+ * Suspend and resume can be called when the device hasn't been
+ * enabled. If there are no users that have the device open, then
+ * avoid calling the TSC stop and start functions as the TSC
+ * isn't yet clocked.
+ */
+ mutex_lock(&input->mutex);
+
+ if (input->users) {
+ if (device_may_wakeup(dev))
+ enable_irq_wake(tsc->irq);
+ else
+ lpc32xx_stop_tsc(tsc);
+ }
+
+ mutex_unlock(&input->mutex);
+
+ return 0;
+}
+
+static int lpc32xx_ts_resume(struct device *dev)
+{
+ struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);
+ struct input_dev *input = tsc->dev;
+
+ mutex_lock(&input->mutex);
+
+ if (input->users) {
+ if (device_may_wakeup(dev))
+ disable_irq_wake(tsc->irq);
+ else
+ lpc32xx_setup_tsc(tsc);
+ }
+
+ mutex_unlock(&input->mutex);
+
+ return 0;
+}
+
+static const struct dev_pm_ops lpc32xx_ts_pm_ops = {
+ .suspend = lpc32xx_ts_suspend,
+ .resume = lpc32xx_ts_resume,
+};
+#define LPC32XX_TS_PM_OPS (&lpc32xx_ts_pm_ops)
+#else
+#define LPC32XX_TS_PM_OPS NULL
+#endif
+
+static struct platform_driver lpc32xx_ts_driver = {
+ .probe = lpc32xx_ts_probe,
+ .remove = __devexit_p(lpc32xx_ts_remove),
+ .driver = {
+ .name = MOD_NAME,
+ .owner = THIS_MODULE,
+ .pm = LPC32XX_TS_PM_OPS,
+ },
+};
+
+static int __init lpc32xx_ts_init(void)
+{
+ return platform_driver_register(&lpc32xx_ts_driver);
+}
+module_init(lpc32xx_ts_init);
+
+static void __exit lpc32xx_ts_exit(void)
+{
+ platform_driver_unregister(&lpc32xx_ts_driver);
+}
+module_exit(lpc32xx_ts_exit);
+
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com");
+MODULE_DESCRIPTION("LPC32XX TSC Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lpc32xx_ts");
diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c
index efd3aebaba5f..36e57deacd03 100644
--- a/drivers/input/touchscreen/mk712.c
+++ b/drivers/input/touchscreen/mk712.c
@@ -17,7 +17,7 @@
* found in Gateway AOL Connected Touchpad computers.
*
* Documentation for ICS MK712 can be found at:
- * http://www.icst.com/pdf/mk712.pdf
+ * http://www.idt.com/products/getDoc.cfm?docID=18713923
*/
/*
diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c
index 6085d12fd561..8feb7f3c8be1 100644
--- a/drivers/input/touchscreen/s3c2410_ts.c
+++ b/drivers/input/touchscreen/s3c2410_ts.c
@@ -350,7 +350,7 @@ static int __devinit s3c2410ts_probe(struct platform_device *pdev)
err_tcirq:
free_irq(ts.irq_tc, ts.input);
err_inputdev:
- input_unregister_device(ts.input);
+ input_free_device(ts.input);
err_iomap:
iounmap(ts.io);
err_clk:
diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c
index 656148ec0027..ae88e13c99ff 100644
--- a/drivers/input/touchscreen/stmpe-ts.c
+++ b/drivers/input/touchscreen/stmpe-ts.c
@@ -268,7 +268,7 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev)
struct stmpe_touch *ts;
struct input_dev *idev;
struct stmpe_ts_platform_data *ts_pdata = NULL;
- int ret = 0;
+ int ret;
int ts_irq;
ts_irq = platform_get_irq_byname(pdev, "FIFO_TH");
@@ -276,12 +276,16 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev)
return ts_irq;
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
- if (!ts)
+ if (!ts) {
+ ret = -ENOMEM;
goto err_out;
+ }
idev = input_allocate_device();
- if (!idev)
+ if (!idev) {
+ ret = -ENOMEM;
goto err_free_ts;
+ }
platform_set_drvdata(pdev, ts);
ts->stmpe = stmpe;
@@ -361,7 +365,6 @@ static int __devexit stmpe_ts_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
input_unregister_device(ts->idev);
- input_free_device(ts->idev);
kfree(ts);
diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c
new file mode 100644
index 000000000000..cf1dba2e267c
--- /dev/null
+++ b/drivers/input/touchscreen/tnetv107x-ts.c
@@ -0,0 +1,396 @@
+/*
+ * Texas Instruments TNETV107X Touchscreen Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; 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/errno.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <mach/tnetv107x.h>
+
+#define TSC_PENUP_POLL (HZ / 5)
+#define IDLE_TIMEOUT 100 /* msec */
+
+/*
+ * The first and last samples of a touch interval are usually garbage and need
+ * to be filtered out with these devices. The following definitions control
+ * the number of samples skipped.
+ */
+#define TSC_HEAD_SKIP 1
+#define TSC_TAIL_SKIP 1
+#define TSC_SKIP (TSC_HEAD_SKIP + TSC_TAIL_SKIP + 1)
+#define TSC_SAMPLES (TSC_SKIP + 1)
+
+/* Register Offsets */
+struct tsc_regs {
+ u32 rev;
+ u32 tscm;
+ u32 bwcm;
+ u32 swc;
+ u32 adcchnl;
+ u32 adcdata;
+ u32 chval[4];
+};
+
+/* TSC Mode Configuration Register (tscm) bits */
+#define WMODE BIT(0)
+#define TSKIND BIT(1)
+#define ZMEASURE_EN BIT(2)
+#define IDLE BIT(3)
+#define TSC_EN BIT(4)
+#define STOP BIT(5)
+#define ONE_SHOT BIT(6)
+#define SINGLE BIT(7)
+#define AVG BIT(8)
+#define AVGNUM(x) (((x) & 0x03) << 9)
+#define PVSTC(x) (((x) & 0x07) << 11)
+#define PON BIT(14)
+#define PONBG BIT(15)
+#define AFERST BIT(16)
+
+/* ADC DATA Capture Register bits */
+#define DATA_VALID BIT(16)
+
+/* Register Access Macros */
+#define tsc_read(ts, reg) __raw_readl(&(ts)->regs->reg)
+#define tsc_write(ts, reg, val) __raw_writel(val, &(ts)->regs->reg);
+#define tsc_set_bits(ts, reg, val) \
+ tsc_write(ts, reg, tsc_read(ts, reg) | (val))
+#define tsc_clr_bits(ts, reg, val) \
+ tsc_write(ts, reg, tsc_read(ts, reg) & ~(val))
+
+struct sample {
+ int x, y, p;
+};
+
+struct tsc_data {
+ struct input_dev *input_dev;
+ struct resource *res;
+ struct tsc_regs __iomem *regs;
+ struct timer_list timer;
+ spinlock_t lock;
+ struct clk *clk;
+ struct device *dev;
+ int sample_count;
+ struct sample samples[TSC_SAMPLES];
+ int tsc_irq;
+};
+
+static int tsc_read_sample(struct tsc_data *ts, struct sample* sample)
+{
+ int x, y, z1, z2, t, p = 0;
+ u32 val;
+
+ val = tsc_read(ts, chval[0]);
+ if (val & DATA_VALID)
+ x = val & 0xffff;
+ else
+ return -EINVAL;
+
+ y = tsc_read(ts, chval[1]) & 0xffff;
+ z1 = tsc_read(ts, chval[2]) & 0xffff;
+ z2 = tsc_read(ts, chval[3]) & 0xffff;
+
+ if (z1) {
+ t = ((600 * x) * (z2 - z1));
+ p = t / (u32) (z1 << 12);
+ if (p < 0)
+ p = 0;
+ }
+
+ sample->x = x;
+ sample->y = y;
+ sample->p = p;
+
+ return 0;
+}
+
+static void tsc_poll(unsigned long data)
+{
+ struct tsc_data *ts = (struct tsc_data *)data;
+ unsigned long flags;
+ int i, val, x, y, p;
+
+ spin_lock_irqsave(&ts->lock, flags);
+
+ if (ts->sample_count >= TSC_SKIP) {
+ input_report_abs(ts->input_dev, ABS_PRESSURE, 0);
+ input_report_key(ts->input_dev, BTN_TOUCH, 0);
+ input_sync(ts->input_dev);
+ } else if (ts->sample_count > 0) {
+ /*
+ * A touch event lasted less than our skip count. Salvage and
+ * report anyway.
+ */
+ for (i = 0, val = 0; i < ts->sample_count; i++)
+ val += ts->samples[i].x;
+ x = val / ts->sample_count;
+
+ for (i = 0, val = 0; i < ts->sample_count; i++)
+ val += ts->samples[i].y;
+ y = val / ts->sample_count;
+
+ for (i = 0, val = 0; i < ts->sample_count; i++)
+ val += ts->samples[i].p;
+ p = val / ts->sample_count;
+
+ input_report_abs(ts->input_dev, ABS_X, x);
+ input_report_abs(ts->input_dev, ABS_Y, y);
+ input_report_abs(ts->input_dev, ABS_PRESSURE, p);
+ input_report_key(ts->input_dev, BTN_TOUCH, 1);
+ input_sync(ts->input_dev);
+ }
+
+ ts->sample_count = 0;
+
+ spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+static irqreturn_t tsc_irq(int irq, void *dev_id)
+{
+ struct tsc_data *ts = (struct tsc_data *)dev_id;
+ struct sample *sample;
+ int index;
+
+ spin_lock(&ts->lock);
+
+ index = ts->sample_count % TSC_SAMPLES;
+ sample = &ts->samples[index];
+ if (tsc_read_sample(ts, sample) < 0)
+ goto out;
+
+ if (++ts->sample_count >= TSC_SKIP) {
+ index = (ts->sample_count - TSC_TAIL_SKIP - 1) % TSC_SAMPLES;
+ sample = &ts->samples[index];
+
+ input_report_abs(ts->input_dev, ABS_X, sample->x);
+ input_report_abs(ts->input_dev, ABS_Y, sample->y);
+ input_report_abs(ts->input_dev, ABS_PRESSURE, sample->p);
+ if (ts->sample_count == TSC_SKIP)
+ input_report_key(ts->input_dev, BTN_TOUCH, 1);
+ input_sync(ts->input_dev);
+ }
+ mod_timer(&ts->timer, jiffies + TSC_PENUP_POLL);
+out:
+ spin_unlock(&ts->lock);
+ return IRQ_HANDLED;
+}
+
+static int tsc_start(struct input_dev *dev)
+{
+ struct tsc_data *ts = input_get_drvdata(dev);
+ unsigned long timeout = jiffies + msecs_to_jiffies(IDLE_TIMEOUT);
+ u32 val;
+
+ clk_enable(ts->clk);
+
+ /* Go to idle mode, before any initialization */
+ while (time_after(timeout, jiffies)) {
+ if (tsc_read(ts, tscm) & IDLE)
+ break;
+ }
+
+ if (time_before(timeout, jiffies)) {
+ dev_warn(ts->dev, "timeout waiting for idle\n");
+ clk_disable(ts->clk);
+ return -EIO;
+ }
+
+ /* Configure TSC Control register*/
+ val = (PONBG | PON | PVSTC(4) | ONE_SHOT | ZMEASURE_EN);
+ tsc_write(ts, tscm, val);
+
+ /* Bring TSC out of reset: Clear AFE reset bit */
+ val &= ~(AFERST);
+ tsc_write(ts, tscm, val);
+
+ /* Configure all pins for hardware control*/
+ tsc_write(ts, bwcm, 0);
+
+ /* Finally enable the TSC */
+ tsc_set_bits(ts, tscm, TSC_EN);
+
+ return 0;
+}
+
+static void tsc_stop(struct input_dev *dev)
+{
+ struct tsc_data *ts = input_get_drvdata(dev);
+
+ tsc_clr_bits(ts, tscm, TSC_EN);
+ synchronize_irq(ts->tsc_irq);
+ del_timer_sync(&ts->timer);
+ clk_disable(ts->clk);
+}
+
+static int __devinit tsc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct tsc_data *ts;
+ int error = 0;
+ u32 rev = 0;
+
+ ts = kzalloc(sizeof(struct tsc_data), GFP_KERNEL);
+ if (!ts) {
+ dev_err(dev, "cannot allocate device info\n");
+ return -ENOMEM;
+ }
+
+ ts->dev = dev;
+ spin_lock_init(&ts->lock);
+ setup_timer(&ts->timer, tsc_poll, (unsigned long)ts);
+ platform_set_drvdata(pdev, ts);
+
+ ts->tsc_irq = platform_get_irq(pdev, 0);
+ if (ts->tsc_irq < 0) {
+ dev_err(dev, "cannot determine device interrupt\n");
+ error = -ENODEV;
+ goto error_res;
+ }
+
+ ts->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!ts->res) {
+ dev_err(dev, "cannot determine register area\n");
+ error = -ENODEV;
+ goto error_res;
+ }
+
+ if (!request_mem_region(ts->res->start, resource_size(ts->res),
+ pdev->name)) {
+ dev_err(dev, "cannot claim register memory\n");
+ ts->res = NULL;
+ error = -EINVAL;
+ goto error_res;
+ }
+
+ ts->regs = ioremap(ts->res->start, resource_size(ts->res));
+ if (!ts->regs) {
+ dev_err(dev, "cannot map register memory\n");
+ error = -ENOMEM;
+ goto error_map;
+ }
+
+ ts->clk = clk_get(dev, NULL);
+ if (!ts->clk) {
+ dev_err(dev, "cannot claim device clock\n");
+ error = -EINVAL;
+ goto error_clk;
+ }
+
+ error = request_threaded_irq(ts->tsc_irq, NULL, tsc_irq, 0,
+ dev_name(dev), ts);
+ if (error < 0) {
+ dev_err(ts->dev, "Could not allocate ts irq\n");
+ goto error_irq;
+ }
+
+ ts->input_dev = input_allocate_device();
+ if (!ts->input_dev) {
+ dev_err(dev, "cannot allocate input device\n");
+ error = -ENOMEM;
+ goto error_input;
+ }
+ input_set_drvdata(ts->input_dev, ts);
+
+ ts->input_dev->name = pdev->name;
+ ts->input_dev->id.bustype = BUS_HOST;
+ ts->input_dev->dev.parent = &pdev->dev;
+ ts->input_dev->open = tsc_start;
+ ts->input_dev->close = tsc_stop;
+
+ clk_enable(ts->clk);
+ rev = tsc_read(ts, rev);
+ ts->input_dev->id.product = ((rev >> 8) & 0x07);
+ ts->input_dev->id.version = ((rev >> 16) & 0xfff);
+ clk_disable(ts->clk);
+
+ __set_bit(EV_KEY, ts->input_dev->evbit);
+ __set_bit(EV_ABS, ts->input_dev->evbit);
+ __set_bit(BTN_TOUCH, ts->input_dev->keybit);
+
+ input_set_abs_params(ts->input_dev, ABS_X, 0, 0xffff, 5, 0);
+ input_set_abs_params(ts->input_dev, ABS_Y, 0, 0xffff, 5, 0);
+ input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 4095, 128, 0);
+
+ error = input_register_device(ts->input_dev);
+ if (error < 0) {
+ dev_err(dev, "failed input device registration\n");
+ goto error_reg;
+ }
+
+ return 0;
+
+error_reg:
+ input_free_device(ts->input_dev);
+error_input:
+ free_irq(ts->tsc_irq, ts);
+error_irq:
+ clk_put(ts->clk);
+error_clk:
+ iounmap(ts->regs);
+error_map:
+ release_mem_region(ts->res->start, resource_size(ts->res));
+error_res:
+ platform_set_drvdata(pdev, NULL);
+ kfree(ts);
+
+ return error;
+}
+
+static int __devexit tsc_remove(struct platform_device *pdev)
+{
+ struct tsc_data *ts = platform_get_drvdata(pdev);
+
+ input_unregister_device(ts->input_dev);
+ free_irq(ts->tsc_irq, ts);
+ clk_put(ts->clk);
+ iounmap(ts->regs);
+ release_mem_region(ts->res->start, resource_size(ts->res));
+ platform_set_drvdata(pdev, NULL);
+ kfree(ts);
+
+ return 0;
+}
+
+static struct platform_driver tsc_driver = {
+ .probe = tsc_probe,
+ .remove = __devexit_p(tsc_remove),
+ .driver.name = "tnetv107x-ts",
+ .driver.owner = THIS_MODULE,
+};
+
+static int __init tsc_init(void)
+{
+ return platform_driver_register(&tsc_driver);
+}
+
+static void __exit tsc_exit(void)
+{
+ platform_driver_unregister(&tsc_driver);
+}
+
+module_init(tsc_init);
+module_exit(tsc_exit);
+
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_DESCRIPTION("TNETV107X Touchscreen Driver");
+MODULE_ALIAS("platform: tnetv107x-ts");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c
index a644d18c04dc..c8c136cf7bbc 100644
--- a/drivers/input/touchscreen/tps6507x-ts.c
+++ b/drivers/input/touchscreen/tps6507x-ts.c
@@ -335,6 +335,7 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
dev_err(tsc->dev, "schedule failed");
goto err2;
}
+ platform_set_drvdata(pdev, tps6507x_dev);
return 0;
@@ -358,7 +359,7 @@ static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
cancel_delayed_work_sync(&tsc->work);
destroy_workqueue(tsc->wq);
- input_free_device(input_dev);
+ input_unregister_device(input_dev);
tps6507x_dev->ts = NULL;
kfree(tsc);
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index be23780e8a3e..80467f262331 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -265,7 +265,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tsc2007 *ts;
- struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data;
+ struct tsc2007_platform_data *pdata = client->dev.platform_data;
struct input_dev *input_dev;
int err;
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index 56dc35c94bb1..9ae4c7b16ba7 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -2,6 +2,7 @@
* Wacom W8001 penabled serial touchscreen driver
*
* Copyright (c) 2008 Jaya Kumar
+ * Copyright (c) 2010 Red Hat, Inc.
*
* 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
@@ -30,11 +31,24 @@ MODULE_LICENSE("GPL");
#define W8001_LEAD_BYTE 0x80
#define W8001_TAB_MASK 0x40
#define W8001_TAB_BYTE 0x40
+/* set in first byte of touch data packets */
+#define W8001_TOUCH_MASK (0x10 | W8001_LEAD_MASK)
+#define W8001_TOUCH_BYTE (0x10 | W8001_LEAD_BYTE)
#define W8001_QUERY_PACKET 0x20
#define W8001_CMD_START '1'
#define W8001_CMD_QUERY '*'
+#define W8001_CMD_TOUCHQUERY '%'
+
+/* length of data packets in bytes, depends on device. */
+#define W8001_PKTLEN_TOUCH93 5
+#define W8001_PKTLEN_TOUCH9A 7
+#define W8001_PKTLEN_TPCPEN 9
+#define W8001_PKTLEN_TPCCTL 11 /* control packet */
+#define W8001_PKTLEN_TOUCH2FG 13
+
+#define MAX_TRACKING_ID 0xFF /* arbitrarily chosen */
struct w8001_coord {
u8 rdy;
@@ -48,6 +62,15 @@ struct w8001_coord {
u8 tilt_y;
};
+/* touch query reply packet */
+struct w8001_touch_query {
+ u8 panel_res;
+ u8 capacity_res;
+ u8 sensor_id;
+ u16 x;
+ u16 y;
+};
+
/*
* Per-touchscreen data.
*/
@@ -62,6 +85,9 @@ struct w8001 {
unsigned char response[W8001_MAX_LENGTH];
unsigned char data[W8001_MAX_LENGTH];
char phys[32];
+ int type;
+ unsigned int pktlen;
+ int trkid[2];
};
static void parse_data(u8 *data, struct w8001_coord *coord)
@@ -88,11 +114,98 @@ static void parse_data(u8 *data, struct w8001_coord *coord)
coord->tilt_y = data[8] & 0x7F;
}
+static void parse_touch(struct w8001 *w8001)
+{
+ static int trkid;
+ struct input_dev *dev = w8001->dev;
+ unsigned char *data = w8001->data;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ input_mt_slot(dev, i);
+
+ if (data[0] & (1 << i)) {
+ int x = (data[6 * i + 1] << 7) | (data[6 * i + 2]);
+ int y = (data[6 * i + 3] << 7) | (data[6 * i + 4]);
+ /* data[5,6] and [11,12] is finger capacity */
+
+ input_report_abs(dev, ABS_MT_POSITION_X, x);
+ input_report_abs(dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(dev, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
+ if (w8001->trkid[i] < 0)
+ w8001->trkid[i] = trkid++ & MAX_TRACKING_ID;
+ } else {
+ w8001->trkid[i] = -1;
+ }
+ input_report_abs(dev, ABS_MT_TRACKING_ID, w8001->trkid[i]);
+ }
+
+ input_sync(dev);
+}
+
+static void parse_touchquery(u8 *data, struct w8001_touch_query *query)
+{
+ memset(query, 0, sizeof(*query));
+
+ query->panel_res = data[1];
+ query->sensor_id = data[2] & 0x7;
+ query->capacity_res = data[7];
+
+ query->x = data[3] << 9;
+ query->x |= data[4] << 2;
+ query->x |= (data[2] >> 5) & 0x3;
+
+ query->y = data[5] << 9;
+ query->y |= data[6] << 2;
+ query->y |= (data[2] >> 3) & 0x3;
+}
+
+static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
+{
+ struct input_dev *dev = w8001->dev;
+
+ /*
+ * We have 1 bit for proximity (rdy) and 3 bits for tip, side,
+ * side2/eraser. If rdy && f2 are set, this can be either pen + side2,
+ * or eraser. assume
+ * - if dev is already in proximity and f2 is toggled → pen + side2
+ * - if dev comes into proximity with f2 set → eraser
+ * If f2 disappears after assuming eraser, fake proximity out for
+ * eraser and in for pen.
+ */
+
+ if (!w8001->type) {
+ w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+ } else if (w8001->type == BTN_TOOL_RUBBER) {
+ if (!coord->f2) {
+ input_report_abs(dev, ABS_PRESSURE, 0);
+ input_report_key(dev, BTN_TOUCH, 0);
+ input_report_key(dev, BTN_STYLUS, 0);
+ input_report_key(dev, BTN_STYLUS2, 0);
+ input_report_key(dev, BTN_TOOL_RUBBER, 0);
+ input_sync(dev);
+ w8001->type = BTN_TOOL_PEN;
+ }
+ } else {
+ input_report_key(dev, BTN_STYLUS2, coord->f2);
+ }
+
+ input_report_abs(dev, ABS_X, coord->x);
+ input_report_abs(dev, ABS_Y, coord->y);
+ input_report_abs(dev, ABS_PRESSURE, coord->pen_pressure);
+ input_report_key(dev, BTN_TOUCH, coord->tsw);
+ input_report_key(dev, BTN_STYLUS, coord->f1);
+ input_report_key(dev, w8001->type, coord->rdy);
+ input_sync(dev);
+
+ if (!coord->rdy)
+ w8001->type = 0;
+}
+
static irqreturn_t w8001_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct w8001 *w8001 = serio_get_drvdata(serio);
- struct input_dev *dev = w8001->dev;
struct w8001_coord coord;
unsigned char tmp;
@@ -105,26 +218,45 @@ static irqreturn_t w8001_interrupt(struct serio *serio,
}
break;
- case 8:
+ case W8001_PKTLEN_TOUCH93 - 1:
+ case W8001_PKTLEN_TOUCH9A - 1:
+ /* ignore one-finger touch packet. */
+ if (w8001->pktlen == w8001->idx)
+ w8001->idx = 0;
+ break;
+
+ /* Pen coordinates packet */
+ case W8001_PKTLEN_TPCPEN - 1:
tmp = w8001->data[0] & W8001_TAB_MASK;
if (unlikely(tmp == W8001_TAB_BYTE))
break;
+ tmp = (w8001->data[0] & W8001_TOUCH_BYTE);
+ if (tmp == W8001_TOUCH_BYTE)
+ break;
+
w8001->idx = 0;
parse_data(w8001->data, &coord);
- input_report_abs(dev, ABS_X, coord.x);
- input_report_abs(dev, ABS_Y, coord.y);
- input_report_abs(dev, ABS_PRESSURE, coord.pen_pressure);
- input_report_key(dev, BTN_TOUCH, coord.tsw);
- input_sync(dev);
+ report_pen_events(w8001, &coord);
break;
- case 10:
+ /* control packet */
+ case W8001_PKTLEN_TPCCTL - 1:
+ tmp = (w8001->data[0] & W8001_TOUCH_MASK);
+ if (tmp == W8001_TOUCH_BYTE)
+ break;
+
w8001->idx = 0;
memcpy(w8001->response, w8001->data, W8001_MAX_LENGTH);
w8001->response_type = W8001_QUERY_PACKET;
complete(&w8001->cmd_done);
break;
+
+ /* 2 finger touch packet */
+ case W8001_PKTLEN_TOUCH2FG - 1:
+ w8001->idx = 0;
+ parse_touch(w8001);
+ break;
}
return IRQ_HANDLED;
@@ -167,6 +299,38 @@ static int w8001_setup(struct w8001 *w8001)
input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
+ error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true);
+ if (!error) {
+ struct w8001_touch_query touch;
+
+ parse_touchquery(w8001->response, &touch);
+
+ switch (touch.sensor_id) {
+ case 0:
+ case 2:
+ w8001->pktlen = W8001_PKTLEN_TOUCH93;
+ break;
+ case 1:
+ case 3:
+ case 4:
+ w8001->pktlen = W8001_PKTLEN_TOUCH9A;
+ break;
+ case 5:
+ w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
+
+ input_mt_create_slots(dev, 2);
+ input_set_abs_params(dev, ABS_MT_TRACKING_ID,
+ 0, MAX_TRACKING_ID, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_X,
+ 0, touch.x, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y,
+ 0, touch.y, 0, 0);
+ input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
+ 0, 0, 0, 0);
+ break;
+ }
+ }
+
return w8001_command(w8001, W8001_CMD_START, false);
}
@@ -208,6 +372,7 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
w8001->serio = serio;
w8001->id = serio->id.id;
w8001->dev = input_dev;
+ w8001->trkid[0] = w8001->trkid[1] = -1;
init_completion(&w8001->cmd_done);
snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
@@ -221,6 +386,10 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ input_dev->keybit[BIT_WORD(BTN_TOOL_PEN)] |= BIT_MASK(BTN_TOOL_PEN);
+ input_dev->keybit[BIT_WORD(BTN_TOOL_RUBBER)] |= BIT_MASK(BTN_TOOL_RUBBER);
+ input_dev->keybit[BIT_WORD(BTN_STYLUS)] |= BIT_MASK(BTN_STYLUS);
+ input_dev->keybit[BIT_WORD(BTN_STYLUS2)] |= BIT_MASK(BTN_STYLUS2);
serio_set_drvdata(serio, w8001);
err = serio_open(serio, drv);
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index cbfef1ea7e30..6b75c9f660ae 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -125,6 +125,8 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
{
int power_adc = 0, auxval;
u16 power = 0;
+ int rc = 0;
+ int timeout = 0;
/* get codec */
mutex_lock(&wm->codec_mutex);
@@ -143,7 +145,9 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
/* Turn polling mode on to read AUX ADC */
wm->pen_probably_down = 1;
- wm->codec->poll_sample(wm, adcsel, &auxval);
+
+ while (rc != RC_VALID && timeout++ < 5)
+ rc = wm->codec->poll_sample(wm, adcsel, &auxval);
if (power_adc)
wm97xx_reg_write(wm, AC97_EXTENDED_MID, power | 0x8000);
@@ -152,8 +156,15 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
wm->pen_probably_down = 0;
+ if (timeout >= 5) {
+ dev_err(wm->dev,
+ "timeout reading auxadc %d, disabling digitiser\n",
+ adcsel);
+ wm->codec->dig_enable(wm, false);
+ }
+
mutex_unlock(&wm->codec_mutex);
- return auxval & 0xfff;
+ return (rc == RC_VALID ? auxval & 0xfff : -EBUSY);
}
EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc);
@@ -684,8 +695,7 @@ static int wm97xx_probe(struct device *dev)
touch_reg_err:
platform_device_put(wm->touch_dev);
touch_err:
- platform_device_unregister(wm->battery_dev);
- wm->battery_dev = NULL;
+ platform_device_del(wm->battery_dev);
batt_reg_err:
platform_device_put(wm->battery_dev);
batt_err:
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index 2978bdaa6b88..e54e79d4e2c1 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -1515,8 +1515,13 @@ static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
while (*s) {
int digit1 = 0;
int digit2 = 0;
- if (!isdigit(*s)) return -3;
- while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; }
+ char *endp;
+
+ digit1 = simple_strtoul(s, &endp, 10);
+ if (s == endp)
+ return -3;
+ s = endp;
+
if (digit1 <= 0 || digit1 > 30) return -4;
if (*s == 0 || *s == ',' || *s == ' ') {
bmask |= (1 << digit1);
@@ -1526,8 +1531,12 @@ static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
}
if (*s != '-') return -5;
s++;
- if (!isdigit(*s)) return -3;
- while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; }
+
+ digit2 = simple_strtoul(s, &endp, 10);
+ if (s == endp)
+ return -3;
+ s = endp;
+
if (digit2 <= 0 || digit2 > 30) return -4;
if (*s == 0 || *s == ',' || *s == ' ') {
if (digit1 > digit2)
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
index b054494df846..3acf94cc5acd 100644
--- a/drivers/isdn/capi/kcapi.c
+++ b/drivers/isdn/capi/kcapi.c
@@ -98,6 +98,16 @@ static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr)
return capi_controller[contr - 1];
}
+static inline struct capi20_appl *__get_capi_appl_by_nr(u16 applid)
+{
+ lockdep_assert_held(&capi_controller_lock);
+
+ if (applid - 1 >= CAPI_MAXAPPL)
+ return NULL;
+
+ return capi_applications[applid - 1];
+}
+
static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid)
{
if (applid - 1 >= CAPI_MAXAPPL)
@@ -185,10 +195,9 @@ static void notify_up(u32 contr)
ctr->state = CAPI_CTR_RUNNING;
for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
- ap = get_capi_appl_by_nr(applid);
- if (!ap)
- continue;
- register_appl(ctr, applid, &ap->rparam);
+ ap = __get_capi_appl_by_nr(applid);
+ if (ap)
+ register_appl(ctr, applid, &ap->rparam);
}
wake_up_interruptible_all(&ctr->state_wait_queue);
@@ -215,7 +224,7 @@ static void ctr_down(struct capi_ctr *ctr, int new_state)
memset(ctr->serial, 0, sizeof(ctr->serial));
for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
- ap = get_capi_appl_by_nr(applid);
+ ap = __get_capi_appl_by_nr(applid);
if (ap)
capi_ctr_put(ctr);
}
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c
index 70cf6bac7a5a..48e6d220f62c 100644
--- a/drivers/isdn/divert/isdn_divert.c
+++ b/drivers/isdn/divert/isdn_divert.c
@@ -77,7 +77,7 @@ static void deflect_timer_expire(ulong arg)
case DEFLECT_ALERT:
cs->ics.command = ISDN_CMD_REDIR; /* protocol */
- strcpy(cs->ics.parm.setup.phone,cs->deflect_dest);
+ strlcpy(cs->ics.parm.setup.phone, cs->deflect_dest, sizeof(cs->ics.parm.setup.phone));
strcpy(cs->ics.parm.setup.eazmsn,"Testtext delayed");
divert_if.ll_cmd(&cs->ics);
spin_lock_irqsave(&divert_lock, flags);
@@ -251,7 +251,7 @@ int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
case 2: /* redir */
del_timer(&cs->timer);
- strcpy(cs->ics.parm.setup.phone, to_nr);
+ strlcpy(cs->ics.parm.setup.phone, to_nr, sizeof(cs->ics.parm.setup.phone));
strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual");
ic.command = ISDN_CMD_REDIR;
if ((i = divert_if.ll_cmd(&ic)))
@@ -480,7 +480,7 @@ static int isdn_divert_icall(isdn_ctrl *ic)
if (!cs->timer.expires)
{ strcpy(ic->parm.setup.eazmsn,"Testtext direct");
ic->parm.setup.screen = dv->rule.screen;
- strcpy(ic->parm.setup.phone,dv->rule.to_nr);
+ strlcpy(ic->parm.setup.phone, dv->rule.to_nr, sizeof(ic->parm.setup.phone));
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
retval = 5;
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 707d9c94cf9e..178942a2ee61 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -109,6 +109,9 @@ struct bas_cardstate {
struct urb *urb_int_in; /* URB for interrupt pipe */
unsigned char *int_in_buf;
+ struct work_struct int_in_wq; /* for usb_clear_halt() */
+ struct timer_list timer_int_in; /* int read retry delay */
+ int retry_int_in;
spinlock_t lock; /* locks all following */
int basstate; /* bitmap (BS_*) */
@@ -169,7 +172,7 @@ static char *get_usb_rcmsg(int rc)
case -EAGAIN:
return "start frame too early or too much scheduled";
case -EFBIG:
- return "too many isochronous frames requested";
+ return "too many isoc frames requested";
case -EPIPE:
return "endpoint stalled";
case -EMSGSIZE:
@@ -200,13 +203,13 @@ static char *get_usb_statmsg(int status)
case -ENOENT:
return "unlinked (sync)";
case -EINPROGRESS:
- return "pending";
+ return "URB still pending";
case -EPROTO:
- return "bit stuffing error, timeout, or unknown USB error";
+ return "bitstuff error, timeout, or unknown USB error";
case -EILSEQ:
return "CRC mismatch, timeout, or unknown USB error";
case -ETIME:
- return "timed out";
+ return "USB response timeout";
case -EPIPE:
return "endpoint stalled";
case -ECOMM:
@@ -214,15 +217,15 @@ static char *get_usb_statmsg(int status)
case -ENOSR:
return "OUT buffer underrun";
case -EOVERFLOW:
- return "too much data";
+ return "endpoint babble";
case -EREMOTEIO:
- return "short packet detected";
+ return "short packet";
case -ENODEV:
return "device removed";
case -EXDEV:
- return "partial isochronous transfer";
+ return "partial isoc transfer";
case -EINVAL:
- return "invalid argument";
+ return "ISO madness";
case -ECONNRESET:
return "unlinked (async)";
case -ESHUTDOWN:
@@ -350,7 +353,7 @@ static inline void error_hangup(struct bc_state *bcs)
* reset Gigaset device because of an unrecoverable error
* This function may be called from any context, and takes care of
* scheduling the necessary actions for execution outside of interrupt context.
- * cs->lock must not be held.
+ * cs->hw.bas->lock must not be held.
* argument:
* controller state structure
*/
@@ -358,7 +361,9 @@ static inline void error_reset(struct cardstate *cs)
{
/* reset interrupt pipe to recover (ignore errors) */
update_basstate(cs->hw.bas, BS_RESETTING, 0);
- req_submit(cs->bcs, HD_RESET_INTERRUPT_PIPE, 0, BAS_TIMEOUT);
+ if (req_submit(cs->bcs, HD_RESET_INTERRUPT_PIPE, 0, BAS_TIMEOUT))
+ /* submission failed, escalate to USB port reset */
+ usb_queue_reset_device(cs->hw.bas->interface);
}
/* check_pending
@@ -438,23 +443,27 @@ static void cmd_in_timeout(unsigned long data)
return;
}
- if (ucs->retry_cmd_in++ < BAS_RETRY) {
- dev_notice(cs->dev, "control read: timeout, retry %d\n",
- ucs->retry_cmd_in);
- rc = atread_submit(cs, BAS_TIMEOUT);
- if (rc >= 0 || rc == -ENODEV)
- /* resubmitted or disconnected */
- /* - bypass regular exit block */
- return;
- } else {
+ if (ucs->retry_cmd_in++ >= BAS_RETRY) {
dev_err(cs->dev,
"control read: timeout, giving up after %d tries\n",
ucs->retry_cmd_in);
+ kfree(ucs->rcvbuf);
+ ucs->rcvbuf = NULL;
+ ucs->rcvbuf_size = 0;
+ error_reset(cs);
+ return;
+ }
+
+ gig_dbg(DEBUG_USBREQ, "%s: timeout, retry %d",
+ __func__, ucs->retry_cmd_in);
+ rc = atread_submit(cs, BAS_TIMEOUT);
+ if (rc < 0) {
+ kfree(ucs->rcvbuf);
+ ucs->rcvbuf = NULL;
+ ucs->rcvbuf_size = 0;
+ if (rc != -ENODEV)
+ error_reset(cs);
}
- kfree(ucs->rcvbuf);
- ucs->rcvbuf = NULL;
- ucs->rcvbuf_size = 0;
- error_reset(cs);
}
/* read_ctrl_callback
@@ -470,18 +479,11 @@ static void read_ctrl_callback(struct urb *urb)
struct cardstate *cs = inbuf->cs;
struct bas_cardstate *ucs = cs->hw.bas;
int status = urb->status;
- int have_data = 0;
unsigned numbytes;
int rc;
update_basstate(ucs, 0, BS_ATRDPEND);
wake_up(&ucs->waitqueue);
-
- if (!ucs->rcvbuf_size) {
- dev_warn(cs->dev, "%s: no receive in progress\n", __func__);
- return;
- }
-
del_timer(&ucs->timer_cmd_in);
switch (status) {
@@ -495,19 +497,10 @@ static void read_ctrl_callback(struct urb *urb)
numbytes = ucs->rcvbuf_size;
}
- /* copy received bytes to inbuf */
- have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes);
-
- if (unlikely(numbytes < ucs->rcvbuf_size)) {
- /* incomplete - resubmit for remaining bytes */
- ucs->rcvbuf_size -= numbytes;
- ucs->retry_cmd_in = 0;
- rc = atread_submit(cs, BAS_TIMEOUT);
- if (rc >= 0 || rc == -ENODEV)
- /* resubmitted or disconnected */
- /* - bypass regular exit block */
- return;
- error_reset(cs);
+ /* copy received bytes to inbuf, notify event layer */
+ if (gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes)) {
+ gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
+ gigaset_schedule_event(cs);
}
break;
@@ -516,37 +509,32 @@ static void read_ctrl_callback(struct urb *urb)
case -EINPROGRESS: /* pending */
case -ENODEV: /* device removed */
case -ESHUTDOWN: /* device shut down */
- /* no action necessary */
+ /* no further action necessary */
gig_dbg(DEBUG_USBREQ, "%s: %s",
__func__, get_usb_statmsg(status));
break;
- default: /* severe trouble */
- dev_warn(cs->dev, "control read: %s\n",
- get_usb_statmsg(status));
+ default: /* other errors: retry */
if (ucs->retry_cmd_in++ < BAS_RETRY) {
- dev_notice(cs->dev, "control read: retry %d\n",
- ucs->retry_cmd_in);
+ gig_dbg(DEBUG_USBREQ, "%s: %s, retry %d", __func__,
+ get_usb_statmsg(status), ucs->retry_cmd_in);
rc = atread_submit(cs, BAS_TIMEOUT);
- if (rc >= 0 || rc == -ENODEV)
- /* resubmitted or disconnected */
- /* - bypass regular exit block */
+ if (rc >= 0)
+ /* successfully resubmitted, skip freeing */
return;
- } else {
- dev_err(cs->dev,
- "control read: giving up after %d tries\n",
- ucs->retry_cmd_in);
+ if (rc == -ENODEV)
+ /* disconnect, no further action necessary */
+ break;
}
+ dev_err(cs->dev, "control read: %s, giving up after %d tries\n",
+ get_usb_statmsg(status), ucs->retry_cmd_in);
error_reset(cs);
}
+ /* read finished, free buffer */
kfree(ucs->rcvbuf);
ucs->rcvbuf = NULL;
ucs->rcvbuf_size = 0;
- if (have_data) {
- gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
- gigaset_schedule_event(cs);
- }
}
/* atread_submit
@@ -605,14 +593,67 @@ static int atread_submit(struct cardstate *cs, int timeout)
if (timeout > 0) {
gig_dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout);
- ucs->timer_cmd_in.expires = jiffies + timeout * HZ / 10;
- ucs->timer_cmd_in.data = (unsigned long) cs;
- ucs->timer_cmd_in.function = cmd_in_timeout;
- add_timer(&ucs->timer_cmd_in);
+ mod_timer(&ucs->timer_cmd_in, jiffies + timeout * HZ / 10);
}
return 0;
}
+/* int_in_work
+ * workqueue routine to clear halt on interrupt in endpoint
+ */
+
+static void int_in_work(struct work_struct *work)
+{
+ struct bas_cardstate *ucs =
+ container_of(work, struct bas_cardstate, int_in_wq);
+ struct urb *urb = ucs->urb_int_in;
+ struct cardstate *cs = urb->context;
+ int rc;
+
+ /* clear halt condition */
+ rc = usb_clear_halt(ucs->udev, urb->pipe);
+ gig_dbg(DEBUG_USBREQ, "clear_halt: %s", get_usb_rcmsg(rc));
+ if (rc == 0)
+ /* success, resubmit interrupt read URB */
+ rc = usb_submit_urb(urb, GFP_ATOMIC);
+ if (rc != 0 && rc != -ENODEV) {
+ dev_err(cs->dev, "clear halt failed: %s\n", get_usb_rcmsg(rc));
+ rc = usb_lock_device_for_reset(ucs->udev, ucs->interface);
+ if (rc == 0) {
+ rc = usb_reset_device(ucs->udev);
+ usb_unlock_device(ucs->udev);
+ }
+ }
+ ucs->retry_int_in = 0;
+}
+
+/* int_in_resubmit
+ * timer routine for interrupt read delayed resubmit
+ * argument:
+ * controller state structure
+ */
+static void int_in_resubmit(unsigned long data)
+{
+ struct cardstate *cs = (struct cardstate *) data;
+ struct bas_cardstate *ucs = cs->hw.bas;
+ int rc;
+
+ if (ucs->retry_int_in++ >= BAS_RETRY) {
+ dev_err(cs->dev, "interrupt read: giving up after %d tries\n",
+ ucs->retry_int_in);
+ usb_queue_reset_device(ucs->interface);
+ return;
+ }
+
+ gig_dbg(DEBUG_USBREQ, "%s: retry %d", __func__, ucs->retry_int_in);
+ rc = usb_submit_urb(ucs->urb_int_in, GFP_ATOMIC);
+ if (rc != 0 && rc != -ENODEV) {
+ dev_err(cs->dev, "could not resubmit interrupt URB: %s\n",
+ get_usb_rcmsg(rc));
+ usb_queue_reset_device(ucs->interface);
+ }
+}
+
/* read_int_callback
* USB completion handler for interrupt pipe input
* called by the USB subsystem in interrupt context
@@ -633,19 +674,29 @@ static void read_int_callback(struct urb *urb)
switch (status) {
case 0: /* success */
+ ucs->retry_int_in = 0;
break;
+ case -EPIPE: /* endpoint stalled */
+ schedule_work(&ucs->int_in_wq);
+ /* fall through */
case -ENOENT: /* cancelled */
case -ECONNRESET: /* cancelled (async) */
case -EINPROGRESS: /* pending */
- /* ignore silently */
+ case -ENODEV: /* device removed */
+ case -ESHUTDOWN: /* device shut down */
+ /* no further action necessary */
gig_dbg(DEBUG_USBREQ, "%s: %s",
__func__, get_usb_statmsg(status));
return;
- case -ENODEV: /* device removed */
- case -ESHUTDOWN: /* device shut down */
- gig_dbg(DEBUG_USBREQ, "%s: device disconnected", __func__);
+ case -EPROTO: /* protocol error or unplug */
+ case -EILSEQ:
+ case -ETIME:
+ /* resubmit after delay */
+ gig_dbg(DEBUG_USBREQ, "%s: %s",
+ __func__, get_usb_statmsg(status));
+ mod_timer(&ucs->timer_int_in, jiffies + HZ / 10);
return;
- default: /* severe trouble */
+ default: /* other errors: just resubmit */
dev_warn(cs->dev, "interrupt read: %s\n",
get_usb_statmsg(status));
goto resubmit;
@@ -723,6 +774,13 @@ static void read_int_callback(struct urb *urb)
break;
}
spin_lock_irqsave(&cs->lock, flags);
+ if (ucs->basstate & BS_ATRDPEND) {
+ spin_unlock_irqrestore(&cs->lock, flags);
+ dev_warn(cs->dev,
+ "HD_RECEIVEATDATA_ACK(%d) during HD_READ_ATMESSAGE(%d) ignored\n",
+ l, ucs->rcvbuf_size);
+ break;
+ }
if (ucs->rcvbuf_size) {
/* throw away previous buffer - we have no queue */
dev_err(cs->dev,
@@ -735,7 +793,6 @@ static void read_int_callback(struct urb *urb)
if (ucs->rcvbuf == NULL) {
spin_unlock_irqrestore(&cs->lock, flags);
dev_err(cs->dev, "out of memory receiving AT data\n");
- error_reset(cs);
break;
}
ucs->rcvbuf_size = l;
@@ -745,13 +802,10 @@ static void read_int_callback(struct urb *urb)
kfree(ucs->rcvbuf);
ucs->rcvbuf = NULL;
ucs->rcvbuf_size = 0;
- if (rc != -ENODEV) {
- spin_unlock_irqrestore(&cs->lock, flags);
- error_reset(cs);
- break;
- }
}
spin_unlock_irqrestore(&cs->lock, flags);
+ if (rc < 0 && rc != -ENODEV)
+ error_reset(cs);
break;
case HD_RESET_INTERRUPT_PIPE_ACK:
@@ -818,6 +872,7 @@ static void read_iso_callback(struct urb *urb)
tasklet_hi_schedule(&ubc->rcvd_tasklet);
} else {
/* tasklet still busy, drop data and resubmit URB */
+ gig_dbg(DEBUG_ISO, "%s: overrun", __func__);
ubc->loststatus = status;
for (i = 0; i < BAS_NUMFRAMES; i++) {
ubc->isoinlost += urb->iso_frame_desc[i].actual_length;
@@ -833,13 +888,11 @@ static void read_iso_callback(struct urb *urb)
urb->dev = bcs->cs->hw.bas->udev;
urb->transfer_flags = URB_ISO_ASAP;
urb->number_of_packets = BAS_NUMFRAMES;
- gig_dbg(DEBUG_ISO, "%s: isoc read overrun/resubmit",
- __func__);
rc = usb_submit_urb(urb, GFP_ATOMIC);
if (unlikely(rc != 0 && rc != -ENODEV)) {
dev_err(bcs->cs->dev,
- "could not resubmit isochronous read "
- "URB: %s\n", get_usb_rcmsg(rc));
+ "could not resubmit isoc read URB: %s\n",
+ get_usb_rcmsg(rc));
dump_urb(DEBUG_ISO, "isoc read", urb);
error_hangup(bcs);
}
@@ -1081,7 +1134,7 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
gig_dbg(DEBUG_ISO, "%s: disconnected", __func__);
else
dev_err(ucx->bcs->cs->dev,
- "could not submit isochronous write URB: %s\n",
+ "could not submit isoc write URB: %s\n",
get_usb_rcmsg(rc));
return rc;
}
@@ -1126,7 +1179,7 @@ static void write_iso_tasklet(unsigned long data)
ubc->isooutovfl = NULL;
spin_unlock_irqrestore(&ubc->isooutlock, flags);
if (ovfl) {
- dev_err(cs->dev, "isochronous write buffer underrun\n");
+ dev_err(cs->dev, "isoc write underrun\n");
error_hangup(bcs);
break;
}
@@ -1151,7 +1204,7 @@ static void write_iso_tasklet(unsigned long data)
if (next) {
/* couldn't put it back */
dev_err(cs->dev,
- "losing isochronous write URB\n");
+ "losing isoc write URB\n");
error_hangup(bcs);
}
}
@@ -1178,10 +1231,10 @@ static void write_iso_tasklet(unsigned long data)
if (ifd->status ||
ifd->actual_length != ifd->length) {
dev_warn(cs->dev,
- "isochronous write: frame %d: %s, "
- "only %d of %d bytes sent\n",
- i, get_usb_statmsg(ifd->status),
- ifd->actual_length, ifd->length);
+ "isoc write: frame %d[%d/%d]: %s\n",
+ i, ifd->actual_length,
+ ifd->length,
+ get_usb_statmsg(ifd->status));
offset = (ifd->offset +
ifd->actual_length)
% BAS_OUTBUFSIZE;
@@ -1190,11 +1243,11 @@ static void write_iso_tasklet(unsigned long data)
}
break;
case -EPIPE: /* stall - probably underrun */
- dev_err(cs->dev, "isochronous write stalled\n");
+ dev_err(cs->dev, "isoc write: stalled\n");
error_hangup(bcs);
break;
- default: /* severe trouble */
- dev_warn(cs->dev, "isochronous write: %s\n",
+ default: /* other errors */
+ dev_warn(cs->dev, "isoc write: %s\n",
get_usb_statmsg(status));
}
@@ -1250,6 +1303,7 @@ static void read_iso_tasklet(unsigned long data)
struct cardstate *cs = bcs->cs;
struct urb *urb;
int status;
+ struct usb_iso_packet_descriptor *ifd;
char *rcvbuf;
unsigned long flags;
int totleft, numbytes, offset, frame, rc;
@@ -1267,8 +1321,7 @@ static void read_iso_tasklet(unsigned long data)
ubc->isoindone = NULL;
if (unlikely(ubc->loststatus != -EINPROGRESS)) {
dev_warn(cs->dev,
- "isochronous read overrun, "
- "dropped URB with status: %s, %d bytes lost\n",
+ "isoc read overrun, URB dropped (status: %s, %d bytes)\n",
get_usb_statmsg(ubc->loststatus),
ubc->isoinlost);
ubc->loststatus = -EINPROGRESS;
@@ -1298,11 +1351,11 @@ static void read_iso_tasklet(unsigned long data)
__func__, get_usb_statmsg(status));
continue; /* -> skip */
case -EPIPE:
- dev_err(cs->dev, "isochronous read stalled\n");
+ dev_err(cs->dev, "isoc read: stalled\n");
error_hangup(bcs);
continue; /* -> skip */
- default: /* severe trouble */
- dev_warn(cs->dev, "isochronous read: %s\n",
+ default: /* other error */
+ dev_warn(cs->dev, "isoc read: %s\n",
get_usb_statmsg(status));
goto error;
}
@@ -1310,40 +1363,52 @@ static void read_iso_tasklet(unsigned long data)
rcvbuf = urb->transfer_buffer;
totleft = urb->actual_length;
for (frame = 0; totleft > 0 && frame < BAS_NUMFRAMES; frame++) {
- numbytes = urb->iso_frame_desc[frame].actual_length;
- if (unlikely(urb->iso_frame_desc[frame].status))
+ ifd = &urb->iso_frame_desc[frame];
+ numbytes = ifd->actual_length;
+ switch (ifd->status) {
+ case 0: /* success */
+ break;
+ case -EPROTO: /* protocol error or unplug */
+ case -EILSEQ:
+ case -ETIME:
+ /* probably just disconnected, ignore */
+ gig_dbg(DEBUG_ISO,
+ "isoc read: frame %d[%d]: %s\n",
+ frame, numbytes,
+ get_usb_statmsg(ifd->status));
+ break;
+ default: /* other error */
+ /* report, assume transferred bytes are ok */
dev_warn(cs->dev,
- "isochronous read: frame %d[%d]: %s\n",
+ "isoc read: frame %d[%d]: %s\n",
frame, numbytes,
- get_usb_statmsg(
- urb->iso_frame_desc[frame].status));
+ get_usb_statmsg(ifd->status));
+ }
if (unlikely(numbytes > BAS_MAXFRAME))
dev_warn(cs->dev,
- "isochronous read: frame %d: "
- "numbytes (%d) > BAS_MAXFRAME\n",
- frame, numbytes);
+ "isoc read: frame %d[%d]: %s\n",
+ frame, numbytes,
+ "exceeds max frame size");
if (unlikely(numbytes > totleft)) {
dev_warn(cs->dev,
- "isochronous read: frame %d: "
- "numbytes (%d) > totleft (%d)\n",
- frame, numbytes, totleft);
+ "isoc read: frame %d[%d]: %s\n",
+ frame, numbytes,
+ "exceeds total transfer length");
numbytes = totleft;
}
- offset = urb->iso_frame_desc[frame].offset;
+ offset = ifd->offset;
if (unlikely(offset + numbytes > BAS_INBUFSIZE)) {
dev_warn(cs->dev,
- "isochronous read: frame %d: "
- "offset (%d) + numbytes (%d) "
- "> BAS_INBUFSIZE\n",
- frame, offset, numbytes);
+ "isoc read: frame %d[%d]: %s\n",
+ frame, numbytes,
+ "exceeds end of buffer");
numbytes = BAS_INBUFSIZE - offset;
}
gigaset_isoc_receive(rcvbuf + offset, numbytes, bcs);
totleft -= numbytes;
}
if (unlikely(totleft > 0))
- dev_warn(cs->dev,
- "isochronous read: %d data bytes missing\n",
+ dev_warn(cs->dev, "isoc read: %d data bytes missing\n",
totleft);
error:
@@ -1359,9 +1424,9 @@ error:
rc = usb_submit_urb(urb, GFP_ATOMIC);
if (unlikely(rc != 0 && rc != -ENODEV)) {
dev_err(cs->dev,
- "could not resubmit isochronous read URB: %s\n",
+ "could not resubmit isoc read URB: %s\n",
get_usb_rcmsg(rc));
- dump_urb(DEBUG_ISO, "resubmit iso read", urb);
+ dump_urb(DEBUG_ISO, "resubmit isoc read", urb);
error_hangup(bcs);
}
}
@@ -1373,12 +1438,12 @@ error:
/* req_timeout
* timeout routine for control output request
* argument:
- * B channel control structure
+ * controller state structure
*/
static void req_timeout(unsigned long data)
{
- struct bc_state *bcs = (struct bc_state *) data;
- struct bas_cardstate *ucs = bcs->cs->hw.bas;
+ struct cardstate *cs = (struct cardstate *) data;
+ struct bas_cardstate *ucs = cs->hw.bas;
int pending;
unsigned long flags;
@@ -1395,38 +1460,44 @@ static void req_timeout(unsigned long data)
break;
case HD_OPEN_ATCHANNEL:
- dev_err(bcs->cs->dev, "timeout opening AT channel\n");
- error_reset(bcs->cs);
+ dev_err(cs->dev, "timeout opening AT channel\n");
+ error_reset(cs);
break;
- case HD_OPEN_B2CHANNEL:
case HD_OPEN_B1CHANNEL:
- dev_err(bcs->cs->dev, "timeout opening channel %d\n",
- bcs->channel + 1);
- error_hangup(bcs);
+ dev_err(cs->dev, "timeout opening channel 1\n");
+ error_hangup(&cs->bcs[0]);
+ break;
+
+ case HD_OPEN_B2CHANNEL:
+ dev_err(cs->dev, "timeout opening channel 2\n");
+ error_hangup(&cs->bcs[1]);
break;
case HD_CLOSE_ATCHANNEL:
- dev_err(bcs->cs->dev, "timeout closing AT channel\n");
- error_reset(bcs->cs);
+ dev_err(cs->dev, "timeout closing AT channel\n");
+ error_reset(cs);
break;
- case HD_CLOSE_B2CHANNEL:
case HD_CLOSE_B1CHANNEL:
- dev_err(bcs->cs->dev, "timeout closing channel %d\n",
- bcs->channel + 1);
- error_reset(bcs->cs);
+ dev_err(cs->dev, "timeout closing channel 1\n");
+ error_reset(cs);
+ break;
+
+ case HD_CLOSE_B2CHANNEL:
+ dev_err(cs->dev, "timeout closing channel 2\n");
+ error_reset(cs);
break;
case HD_RESET_INTERRUPT_PIPE:
/* error recovery escalation */
- dev_err(bcs->cs->dev,
+ dev_err(cs->dev,
"reset interrupt pipe timeout, attempting USB reset\n");
- usb_queue_reset_device(bcs->cs->hw.bas->interface);
+ usb_queue_reset_device(ucs->interface);
break;
default:
- dev_warn(bcs->cs->dev, "request 0x%02x timed out, clearing\n",
+ dev_warn(cs->dev, "request 0x%02x timed out, clearing\n",
pending);
}
@@ -1557,10 +1628,7 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout)
if (timeout > 0) {
gig_dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout);
- ucs->timer_ctrl.expires = jiffies + timeout * HZ / 10;
- ucs->timer_ctrl.data = (unsigned long) bcs;
- ucs->timer_ctrl.function = req_timeout;
- add_timer(&ucs->timer_ctrl);
+ mod_timer(&ucs->timer_ctrl, jiffies + timeout * HZ / 10);
}
spin_unlock_irqrestore(&ucs->lock, flags);
@@ -1590,21 +1658,20 @@ static int gigaset_init_bchannel(struct bc_state *bcs)
if (cs->hw.bas->basstate & BS_SUSPEND) {
dev_notice(cs->dev,
- "not starting isochronous I/O, "
- "suspend in progress\n");
+ "not starting isoc I/O, suspend in progress\n");
spin_unlock_irqrestore(&cs->lock, flags);
return -EHOSTUNREACH;
}
ret = starturbs(bcs);
if (ret < 0) {
+ spin_unlock_irqrestore(&cs->lock, flags);
dev_err(cs->dev,
- "could not start isochronous I/O for channel B%d: %s\n",
+ "could not start isoc I/O for channel B%d: %s\n",
bcs->channel + 1,
ret == -EFAULT ? "null URB" : get_usb_rcmsg(ret));
if (ret != -ENODEV)
error_hangup(bcs);
- spin_unlock_irqrestore(&cs->lock, flags);
return ret;
}
@@ -1614,11 +1681,11 @@ static int gigaset_init_bchannel(struct bc_state *bcs)
dev_err(cs->dev, "could not open channel B%d\n",
bcs->channel + 1);
stopurbs(bcs->hw.bas);
- if (ret != -ENODEV)
- error_hangup(bcs);
}
spin_unlock_irqrestore(&cs->lock, flags);
+ if (ret < 0 && ret != -ENODEV)
+ error_hangup(bcs);
return ret;
}
@@ -1826,10 +1893,7 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len)
if (!(update_basstate(ucs, BS_ATTIMER, BS_ATREADY) & BS_ATTIMER)) {
gig_dbg(DEBUG_OUTPUT, "setting ATREADY timeout of %d/10 secs",
ATRDY_TIMEOUT);
- ucs->timer_atrdy.expires = jiffies + ATRDY_TIMEOUT * HZ / 10;
- ucs->timer_atrdy.data = (unsigned long) cs;
- ucs->timer_atrdy.function = atrdy_timeout;
- add_timer(&ucs->timer_atrdy);
+ mod_timer(&ucs->timer_atrdy, jiffies + ATRDY_TIMEOUT * HZ / 10);
}
return 0;
}
@@ -1914,6 +1978,28 @@ static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb)
* The next command will reopen the AT channel automatically.
*/
if (cb->len == 3 && !memcmp(cb->buf, "+++", 3)) {
+ /* If an HD_RECEIVEATDATA_ACK message remains unhandled
+ * because of an error, the base never sends another one.
+ * The response channel is thus effectively blocked.
+ * Closing and reopening the AT channel does *not* clear
+ * this condition.
+ * As a stopgap measure, submit a zero-length AT read
+ * before closing the AT channel. This has the undocumented
+ * effect of triggering a new HD_RECEIVEATDATA_ACK message
+ * from the base if necessary.
+ * The subsequent AT channel close then discards any pending
+ * messages.
+ */
+ spin_lock_irqsave(&cs->lock, flags);
+ if (!(cs->hw.bas->basstate & BS_ATRDPEND)) {
+ kfree(cs->hw.bas->rcvbuf);
+ cs->hw.bas->rcvbuf = NULL;
+ cs->hw.bas->rcvbuf_size = 0;
+ cs->hw.bas->retry_cmd_in = 0;
+ atread_submit(cs, 0);
+ }
+ spin_unlock_irqrestore(&cs->lock, flags);
+
rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT);
if (cb->wake_tasklet)
tasklet_schedule(cb->wake_tasklet);
@@ -2010,7 +2096,7 @@ static int gigaset_freebcshw(struct bc_state *bcs)
/* kill URBs and tasklets before freeing - better safe than sorry */
ubc->running = 0;
- gig_dbg(DEBUG_INIT, "%s: killing iso URBs", __func__);
+ gig_dbg(DEBUG_INIT, "%s: killing isoc URBs", __func__);
for (i = 0; i < BAS_OUTURBS; ++i) {
usb_kill_urb(ubc->isoouturbs[i].urb);
usb_free_urb(ubc->isoouturbs[i].urb);
@@ -2131,10 +2217,12 @@ static int gigaset_initcshw(struct cardstate *cs)
ucs->pending = 0;
ucs->basstate = 0;
- init_timer(&ucs->timer_ctrl);
- init_timer(&ucs->timer_atrdy);
- init_timer(&ucs->timer_cmd_in);
+ setup_timer(&ucs->timer_ctrl, req_timeout, (unsigned long) cs);
+ setup_timer(&ucs->timer_atrdy, atrdy_timeout, (unsigned long) cs);
+ setup_timer(&ucs->timer_cmd_in, cmd_in_timeout, (unsigned long) cs);
+ setup_timer(&ucs->timer_int_in, int_in_resubmit, (unsigned long) cs);
init_waitqueue_head(&ucs->waitqueue);
+ INIT_WORK(&ucs->int_in_wq, int_in_work);
return 1;
}
@@ -2282,6 +2370,7 @@ static int gigaset_probe(struct usb_interface *interface,
get_usb_rcmsg(rc));
goto error;
}
+ ucs->retry_int_in = 0;
/* tell the device that the driver is ready */
rc = req_submit(cs->bcs, HD_DEVICE_INIT_ACK, 0, 0);
@@ -2334,10 +2423,12 @@ static void gigaset_disconnect(struct usb_interface *interface)
/* stop driver (common part) */
gigaset_stop(cs);
- /* stop timers and URBs, free ressources */
+ /* stop delayed work and URBs, free ressources */
del_timer_sync(&ucs->timer_ctrl);
del_timer_sync(&ucs->timer_atrdy);
del_timer_sync(&ucs->timer_cmd_in);
+ del_timer_sync(&ucs->timer_int_in);
+ cancel_work_sync(&ucs->int_in_wq);
freeurbs(cs);
usb_set_intfdata(interface, NULL);
kfree(ucs->rcvbuf);
@@ -2400,10 +2491,14 @@ static int gigaset_suspend(struct usb_interface *intf, pm_message_t message)
/* in case of timeout, proceed anyway */
}
- /* kill all URBs and timers that might still be pending */
+ /* kill all URBs and delayed work that might still be pending */
usb_kill_urb(ucs->urb_ctrl);
usb_kill_urb(ucs->urb_int_in);
del_timer_sync(&ucs->timer_ctrl);
+ del_timer_sync(&ucs->timer_atrdy);
+ del_timer_sync(&ucs->timer_cmd_in);
+ del_timer_sync(&ucs->timer_int_in);
+ cancel_work_sync(&ucs->int_in_wq);
gig_dbg(DEBUG_SUSPEND, "suspend complete");
return 0;
@@ -2425,6 +2520,7 @@ static int gigaset_resume(struct usb_interface *intf)
get_usb_rcmsg(rc));
return rc;
}
+ ucs->retry_int_in = 0;
/* clear suspend flag to reallow activity */
update_basstate(ucs, 0, BS_SUSPEND);
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index 3ca561eccd9f..db621db67f61 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -1026,32 +1026,6 @@ struct cardstate *gigaset_get_cs_by_id(int id)
return ret;
}
-void gigaset_debugdrivers(void)
-{
- unsigned long flags;
- static struct cardstate *cs;
- struct gigaset_driver *drv;
- unsigned i;
-
- spin_lock_irqsave(&driver_lock, flags);
- list_for_each_entry(drv, &drivers, list) {
- gig_dbg(DEBUG_DRIVER, "driver %p", drv);
- spin_lock(&drv->lock);
- for (i = 0; i < drv->minors; ++i) {
- gig_dbg(DEBUG_DRIVER, " index %u", i);
- cs = drv->cs + i;
- gig_dbg(DEBUG_DRIVER, " cardstate %p", cs);
- gig_dbg(DEBUG_DRIVER, " flags 0x%02x", cs->flags);
- gig_dbg(DEBUG_DRIVER, " minor_index %u",
- cs->minor_index);
- gig_dbg(DEBUG_DRIVER, " driver %p", cs->driver);
- gig_dbg(DEBUG_DRIVER, " i4l id %d", cs->myid);
- }
- spin_unlock(&drv->lock);
- }
- spin_unlock_irqrestore(&driver_lock, flags);
-}
-
static struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
{
unsigned long flags;
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index a69512fb1195..6dd360734cfd 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -70,7 +70,6 @@ enum debuglevel {
DEBUG_STREAM_DUMP = 0x00080, /* application data stream content */
DEBUG_LLDATA = 0x00100, /* sent/received LL data */
DEBUG_EVENT = 0x00200, /* event processing */
- DEBUG_DRIVER = 0x00400, /* driver structure */
DEBUG_HDLC = 0x00800, /* M10x HDLC processing */
DEBUG_CHANNEL = 0x01000, /* channel allocation/deallocation */
DEBUG_TRANSCMD = 0x02000, /* AT-COMMANDS+RESPONSES */
@@ -727,7 +726,7 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
/* Deallocate driver structure. */
void gigaset_freedriver(struct gigaset_driver *drv);
-void gigaset_debugdrivers(void);
+
struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty);
struct cardstate *gigaset_get_cs_by_id(int id);
void gigaset_blockdriver(struct gigaset_driver *drv);
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c
index 34bca37d65b9..9bec8b969964 100644
--- a/drivers/isdn/gigaset/i4l.c
+++ b/drivers/isdn/gigaset/i4l.c
@@ -201,8 +201,6 @@ static int command_from_LL(isdn_ctrl *cntrl)
int i;
size_t l;
- gigaset_debugdrivers();
-
gig_dbg(DEBUG_CMD, "driver: %d, command: %d, arg: 0x%lx",
cntrl->driver, cntrl->command, cntrl->arg);
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c
index 2dfd346fc889..f39ccdf87a17 100644
--- a/drivers/isdn/gigaset/isocdata.c
+++ b/drivers/isdn/gigaset/isocdata.c
@@ -842,13 +842,14 @@ static inline void trans_receive(unsigned char *src, unsigned count,
if (unlikely(bcs->ignore)) {
bcs->ignore--;
- hdlc_flush(bcs);
return;
}
skb = bcs->rx_skb;
- if (skb == NULL)
+ if (skb == NULL) {
skb = gigaset_new_rx_skb(bcs);
- bcs->hw.bas->goodbytes += skb->len;
+ if (skb == NULL)
+ return;
+ }
dobytes = bcs->rx_bufsize - skb->len;
while (count > 0) {
dst = skb_put(skb, count < dobytes ? count : dobytes);
@@ -860,6 +861,7 @@ static inline void trans_receive(unsigned char *src, unsigned count,
if (dobytes == 0) {
dump_bytes(DEBUG_STREAM_DUMP,
"rcv data", skb->data, skb->len);
+ bcs->hw.bas->goodbytes += skb->len;
gigaset_skb_rcvd(bcs, skb);
skb = gigaset_new_rx_skb(bcs);
if (skb == NULL)
diff --git a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c
index 33ce89eed65b..362640120886 100644
--- a/drivers/isdn/hardware/eicon/debug.c
+++ b/drivers/isdn/hardware/eicon/debug.c
@@ -862,7 +862,7 @@ void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) {
diva_os_spin_lock_magic_t old_irql, old_irql1;
dword sec, usec, logical, serial, org_mask;
int id, best_id = 0, free_id = -1;
- char tmp[256];
+ char tmp[128];
diva_dbg_entry_head_t* pmsg = NULL;
int len;
word size;
diff --git a/drivers/isdn/hardware/eicon/debuglib.h b/drivers/isdn/hardware/eicon/debuglib.h
index 8ea587783e14..02eed6b4354c 100644
--- a/drivers/isdn/hardware/eicon/debuglib.h
+++ b/drivers/isdn/hardware/eicon/debuglib.h
@@ -249,7 +249,7 @@ typedef struct _DbgHandle_
} regTime ; /* timestamp for registration */
void *pIrp ; /* ptr to pending i/o request */
unsigned long dbgMask ; /* current debug mask */
- char drvName[16] ; /* ASCII name of registered driver */
+ char drvName[128] ; /* ASCII name of registered driver */
char drvTag[64] ; /* revision string */
DbgEnd dbg_end ; /* function for debug closing */
DbgLog dbg_prt ; /* function for debug appending */
diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c
index af25e1f3efd4..e90db8870b6c 100644
--- a/drivers/isdn/hardware/mISDN/mISDNinfineon.c
+++ b/drivers/isdn/hardware/mISDN/mISDNinfineon.c
@@ -563,7 +563,7 @@ reset_inf(struct inf_hw *hw)
mdelay(10);
hw->ipac.isac.adf2 = 0x87;
hw->ipac.hscx[0].slot = 0x1f;
- hw->ipac.hscx[0].slot = 0x23;
+ hw->ipac.hscx[1].slot = 0x23;
break;
case INF_GAZEL_R753:
val = inl((u32)hw->cfg.start + GAZEL_CNTRL);
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index be5faf4aa868..5aa138eb0b3c 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -234,13 +234,14 @@ read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max)
count++;
if (count > trans_max)
count = trans_max; /* limit length */
- if ((skb = dev_alloc_skb(count))) {
- dst = skb_put(skb, count);
- while (count--)
+ skb = dev_alloc_skb(count);
+ if (skb) {
+ dst = skb_put(skb, count);
+ while (count--)
*dst++ = Read_hfc(cs, HFCSX_FIF_DRD);
- return(skb);
- }
- else return(NULL); /* no memory */
+ return skb;
+ } else
+ return NULL; /* no memory */
}
do {
diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c
index b0554f80bfb3..ee4dae1382e0 100644
--- a/drivers/isdn/hisax/l3_1tr6.c
+++ b/drivers/isdn/hisax/l3_1tr6.c
@@ -164,11 +164,9 @@ l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg)
char tmp[80];
struct sk_buff *skb = arg;
- p = skb->data;
-
/* Channel Identification */
- p = skb->data;
- if ((p = findie(p, skb->len, WE0_chanID, 0))) {
+ p = findie(skb->data, skb->len, WE0_chanID, 0);
+ if (p) {
if (p[1] != 1) {
l3_1tr6_error(pc, "setup wrong chanID len", skb);
return;
diff --git a/drivers/isdn/i4l/isdn_audio.c b/drivers/isdn/i4l/isdn_audio.c
index 861bdf3421f2..d5013935ac62 100644
--- a/drivers/isdn/i4l/isdn_audio.c
+++ b/drivers/isdn/i4l/isdn_audio.c
@@ -439,7 +439,7 @@ isdn_audio_xlaw2adpcm(adpcm_state * s, int fmt, unsigned char *in,
/*
* Goertzel algorithm.
- * See http://ptolemy.eecs.berkeley.edu/~pino/Ptolemy/papers/96/dtmf_ict/
+ * See http://ptolemy.eecs.berkeley.edu/papers/96/dtmf_ict/
* for more info.
* Result is stored into an sk_buff and queued up for later
* evaluation.
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 51dc60da333b..c463162843ba 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -14,7 +14,7 @@
#include <linux/isdn.h>
#include <linux/slab.h>
#include <linux/delay.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include "isdn_common.h"
#include "isdn_tty.h"
#ifdef CONFIG_ISDN_AUDIO
@@ -28,6 +28,7 @@
/* Prototypes */
+static DEFINE_MUTEX(modem_info_mutex);
static int isdn_tty_edit_at(const char *, int, modem_info *);
static void isdn_tty_check_esc(const u_char *, u_char, int, int *, u_long *);
static void isdn_tty_modem_reset_regs(modem_info *, int);
@@ -1354,14 +1355,14 @@ isdn_tty_tiocmget(struct tty_struct *tty, struct file *file)
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
- lock_kernel();
+ mutex_lock(&modem_info_mutex);
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
#endif
control = info->mcr;
status = info->msr;
- unlock_kernel();
+ mutex_unlock(&modem_info_mutex);
return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
| ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
@@ -1385,7 +1386,7 @@ isdn_tty_tiocmset(struct tty_struct *tty, struct file *file,
printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear);
#endif
- lock_kernel();
+ mutex_lock(&modem_info_mutex);
if (set & TIOCM_RTS)
info->mcr |= UART_MCR_RTS;
if (set & TIOCM_DTR) {
@@ -1407,7 +1408,7 @@ isdn_tty_tiocmset(struct tty_struct *tty, struct file *file,
isdn_tty_modem_hup(info, 1);
}
}
- unlock_kernel();
+ mutex_unlock(&modem_info_mutex);
return 0;
}
@@ -3515,7 +3516,7 @@ isdn_tty_parse_at(modem_info * info)
{
atemu *m = &info->emu;
char *p;
- char ds[40];
+ char ds[ISDN_MSNLEN];
#ifdef ISDN_DEBUG_AT
printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd);
@@ -3594,7 +3595,7 @@ isdn_tty_parse_at(modem_info * info)
break;
case '3':
p++;
- sprintf(ds, "\r\n%d", info->emu.charge);
+ snprintf(ds, sizeof(ds), "\r\n%d", info->emu.charge);
isdn_tty_at_cout(ds, info);
break;
default:;
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c
index 713ef2b805a2..76d9e673b4e1 100644
--- a/drivers/isdn/mISDN/dsp_cmx.c
+++ b/drivers/isdn/mISDN/dsp_cmx.c
@@ -1237,6 +1237,7 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb)
if (dsp->cmx_delay)
dsp->rx_W = (dsp->rx_R + dsp->cmx_delay)
& CMX_BUFF_MASK;
+ else
dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1))
& CMX_BUFF_MASK;
} else {
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c
index 22f38e48ac4e..5b59796ed250 100644
--- a/drivers/isdn/mISDN/l1oip_core.c
+++ b/drivers/isdn/mISDN/l1oip_core.c
@@ -972,7 +972,7 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq)
if (debug & DEBUG_L1OIP_SOCKET)
printk(KERN_DEBUG "%s: got new ip address from user "
"space.\n", __func__);
- l1oip_socket_open(hc);
+ l1oip_socket_open(hc);
break;
case MISDN_CTRL_UNSETPEER:
if (debug & DEBUG_L1OIP_SOCKET)
diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c
index b159bd59e64e..a5b632e67552 100644
--- a/drivers/isdn/mISDN/stack.c
+++ b/drivers/isdn/mISDN/stack.c
@@ -18,7 +18,6 @@
#include <linux/slab.h>
#include <linux/mISDNif.h>
#include <linux/kthread.h>
-#include <linux/smp_lock.h>
#include "core.h"
static u_int *debug;
@@ -205,13 +204,7 @@ mISDNStackd(void *data)
struct mISDNstack *st = data;
int err = 0;
-#ifdef CONFIG_SMP
- lock_kernel();
-#endif
sigfillset(&current->blocked);
-#ifdef CONFIG_SMP
- unlock_kernel();
-#endif
if (*debug & DEBUG_MSG_THREAD)
printk(KERN_DEBUG "mISDNStackd %s started\n",
dev_name(&st->dev->dev));
diff --git a/drivers/isdn/pcbit/edss1.c b/drivers/isdn/pcbit/edss1.c
index d5920ae22d73..80c9c16fd5ef 100644
--- a/drivers/isdn/pcbit/edss1.c
+++ b/drivers/isdn/pcbit/edss1.c
@@ -33,7 +33,7 @@
#include "callbacks.h"
-char * isdn_state_table[] = {
+const char * const isdn_state_table[] = {
"Closed",
"Call initiated",
"Overlap sending",
diff --git a/drivers/isdn/pcbit/edss1.h b/drivers/isdn/pcbit/edss1.h
index 0b64f97015d8..39f8346e28c5 100644
--- a/drivers/isdn/pcbit/edss1.h
+++ b/drivers/isdn/pcbit/edss1.h
@@ -90,7 +90,7 @@ struct fsm_timer_entry {
unsigned long timeout; /* in seconds */
};
-extern char * isdn_state_table[];
+extern const char * const isdn_state_table[];
void pcbit_fsm_event(struct pcbit_dev *, struct pcbit_chan *,
unsigned short event, struct callb_data *);
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index d0d221332db0..9e3e2c566598 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -3,9 +3,9 @@
*
* Copyright (C) 2003, 2004 Colin Leroy, Rasmus Rohde, Benjamin Herrenschmidt
*
- * Documentation from
- * http://www.analog.com/UploadedFiles/Data_Sheets/115254175ADT7467_pra.pdf
- * http://www.analog.com/UploadedFiles/Data_Sheets/3686221171167ADT7460_b.pdf
+ * Documentation from 115254175ADT7467_pra.pdf and 3686221171167ADT7460_b.pdf
+ * http://www.onsemi.com/PowerSolutions/product.do?id=ADT7467
+ * http://www.onsemi.com/PowerSolutions/product.do?id=ADT7460
*
*/
diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c
index 947d4afa25ca..30e6195e19d4 100644
--- a/drivers/macintosh/windfarm_pm121.c
+++ b/drivers/macintosh/windfarm_pm121.c
@@ -482,7 +482,7 @@ static s32 pm121_correct(s32 new_setpoint,
new_min += correction->offset;
new_min = (new_min >> 16) + min;
- return max(new_setpoint, max(new_min, 0));
+ return max3(new_setpoint, new_min, 0);
}
static s32 pm121_connect(unsigned int control_id, s32 setpoint)
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
index 0b61792a2780..2129cdb115dc 100644
--- a/drivers/md/dm-snap-persistent.c
+++ b/drivers/md/dm-snap-persistent.c
@@ -254,7 +254,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw,
* Issue the synchronous I/O from a different thread
* to avoid generic_make_request recursion.
*/
- INIT_WORK_ON_STACK(&req.work, do_metadata);
+ INIT_WORK_ONSTACK(&req.work, do_metadata);
queue_work(ps->metadata_wq, &req.work);
flush_workqueue(ps->metadata_wq);
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
index 7961d59f5cac..c06b4d50a3dc 100644
--- a/drivers/media/IR/ir-keytable.c
+++ b/drivers/media/IR/ir-keytable.c
@@ -25,14 +25,56 @@
#define IR_KEYPRESS_TIMEOUT 250
/**
+ * ir_create_table() - initializes a scancode table
+ * @rc_tab: the ir_scancode_table to initialize
+ * @name: name to assign to the table
+ * @ir_type: ir type to assign to the new table
+ * @size: initial size of the table
+ * @return: zero on success or a negative error code
+ *
+ * This routine will initialize the ir_scancode_table and will allocate
+ * memory to hold at least the specified number elements.
+ */
+static int ir_create_table(struct ir_scancode_table *rc_tab,
+ const char *name, u64 ir_type, size_t size)
+{
+ rc_tab->name = name;
+ rc_tab->ir_type = ir_type;
+ rc_tab->alloc = roundup_pow_of_two(size * sizeof(struct ir_scancode));
+ rc_tab->size = rc_tab->alloc / sizeof(struct ir_scancode);
+ rc_tab->scan = kmalloc(rc_tab->alloc, GFP_KERNEL);
+ if (!rc_tab->scan)
+ return -ENOMEM;
+
+ IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
+ rc_tab->size, rc_tab->alloc);
+ return 0;
+}
+
+/**
+ * ir_free_table() - frees memory allocated by a scancode table
+ * @rc_tab: the table whose mappings need to be freed
+ *
+ * This routine will free memory alloctaed for key mappings used by given
+ * scancode table.
+ */
+static void ir_free_table(struct ir_scancode_table *rc_tab)
+{
+ rc_tab->size = 0;
+ kfree(rc_tab->scan);
+ rc_tab->scan = NULL;
+}
+
+/**
* ir_resize_table() - resizes a scancode table if necessary
* @rc_tab: the ir_scancode_table to resize
+ * @gfp_flags: gfp flags to use when allocating memory
* @return: zero on success or a negative error code
*
* This routine will shrink the ir_scancode_table if it has lots of
* unused entries and grow it if it is full.
*/
-static int ir_resize_table(struct ir_scancode_table *rc_tab)
+static int ir_resize_table(struct ir_scancode_table *rc_tab, gfp_t gfp_flags)
{
unsigned int oldalloc = rc_tab->alloc;
unsigned int newalloc = oldalloc;
@@ -57,7 +99,7 @@ static int ir_resize_table(struct ir_scancode_table *rc_tab)
if (newalloc == oldalloc)
return 0;
- newscan = kmalloc(newalloc, GFP_ATOMIC);
+ newscan = kmalloc(newalloc, gfp_flags);
if (!newscan) {
IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
return -ENOMEM;
@@ -72,26 +114,78 @@ static int ir_resize_table(struct ir_scancode_table *rc_tab)
}
/**
- * ir_do_setkeycode() - internal function to set a keycode in the
- * scancode->keycode table
+ * ir_update_mapping() - set a keycode in the scancode->keycode table
* @dev: the struct input_dev device descriptor
- * @rc_tab: the struct ir_scancode_table to set the keycode in
- * @scancode: the scancode for the ir command
- * @keycode: the keycode for the ir command
- * @resize: whether the keytable may be shrunk
- * @return: -EINVAL if the keycode could not be inserted, otherwise zero.
+ * @rc_tab: scancode table to be adjusted
+ * @index: index of the mapping that needs to be updated
+ * @keycode: the desired keycode
+ * @return: previous keycode assigned to the mapping
+ *
+ * This routine is used to update scancode->keycopde mapping at given
+ * position.
+ */
+static unsigned int ir_update_mapping(struct input_dev *dev,
+ struct ir_scancode_table *rc_tab,
+ unsigned int index,
+ unsigned int new_keycode)
+{
+ int old_keycode = rc_tab->scan[index].keycode;
+ int i;
+
+ /* Did the user wish to remove the mapping? */
+ if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
+ IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
+ index, rc_tab->scan[index].scancode);
+ rc_tab->len--;
+ memmove(&rc_tab->scan[index], &rc_tab->scan[index+ 1],
+ (rc_tab->len - index) * sizeof(struct ir_scancode));
+ } else {
+ IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n",
+ index,
+ old_keycode == KEY_RESERVED ? "New" : "Replacing",
+ rc_tab->scan[index].scancode, new_keycode);
+ rc_tab->scan[index].keycode = new_keycode;
+ __set_bit(new_keycode, dev->keybit);
+ }
+
+ if (old_keycode != KEY_RESERVED) {
+ /* A previous mapping was updated... */
+ __clear_bit(old_keycode, dev->keybit);
+ /* ... but another scancode might use the same keycode */
+ for (i = 0; i < rc_tab->len; i++) {
+ if (rc_tab->scan[i].keycode == old_keycode) {
+ __set_bit(old_keycode, dev->keybit);
+ break;
+ }
+ }
+
+ /* Possibly shrink the keytable, failure is not a problem */
+ ir_resize_table(rc_tab, GFP_ATOMIC);
+ }
+
+ return old_keycode;
+}
+
+/**
+ * ir_locate_scancode() - set a keycode in the scancode->keycode table
+ * @ir_dev: the struct ir_input_dev device descriptor
+ * @rc_tab: scancode table to be searched
+ * @scancode: the desired scancode
+ * @resize: controls whether we allowed to resize the table to
+ * accomodate not yet present scancodes
+ * @return: index of the mapping containing scancode in question
+ * or -1U in case of failure.
*
- * This routine is used internally to manipulate the scancode->keycode table.
- * The caller has to hold @rc_tab->lock.
+ * This routine is used to locate given scancode in ir_scancode_table.
+ * If scancode is not yet present the routine will allocate a new slot
+ * for it.
*/
-static int ir_do_setkeycode(struct input_dev *dev,
- struct ir_scancode_table *rc_tab,
- unsigned scancode, unsigned keycode,
- bool resize)
+static unsigned int ir_establish_scancode(struct ir_input_dev *ir_dev,
+ struct ir_scancode_table *rc_tab,
+ unsigned int scancode,
+ bool resize)
{
unsigned int i;
- int old_keycode = KEY_RESERVED;
- struct ir_input_dev *ir_dev = input_get_drvdata(dev);
/*
* Unfortunately, some hardware-based IR decoders don't provide
@@ -100,65 +194,34 @@ static int ir_do_setkeycode(struct input_dev *dev,
* the provided IR with another one, it is needed to allow loading
* IR tables from other remotes. So,
*/
- if (ir_dev->props && ir_dev->props->scanmask) {
+ if (ir_dev->props && ir_dev->props->scanmask)
scancode &= ir_dev->props->scanmask;
- }
/* First check if we already have a mapping for this ir command */
for (i = 0; i < rc_tab->len; i++) {
+ if (rc_tab->scan[i].scancode == scancode)
+ return i;
+
/* Keytable is sorted from lowest to highest scancode */
- if (rc_tab->scan[i].scancode > scancode)
+ if (rc_tab->scan[i].scancode >= scancode)
break;
- else if (rc_tab->scan[i].scancode < scancode)
- continue;
-
- old_keycode = rc_tab->scan[i].keycode;
- rc_tab->scan[i].keycode = keycode;
-
- /* Did the user wish to remove the mapping? */
- if (keycode == KEY_RESERVED || keycode == KEY_UNKNOWN) {
- IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
- i, scancode);
- rc_tab->len--;
- memmove(&rc_tab->scan[i], &rc_tab->scan[i + 1],
- (rc_tab->len - i) * sizeof(struct ir_scancode));
- }
-
- /* Possibly shrink the keytable, failure is not a problem */
- ir_resize_table(rc_tab);
- break;
}
- if (old_keycode == KEY_RESERVED && keycode != KEY_RESERVED) {
- /* No previous mapping found, we might need to grow the table */
- if (resize && ir_resize_table(rc_tab))
- return -ENOMEM;
-
- IR_dprintk(1, "#%d: New scan 0x%04x with key 0x%04x\n",
- i, scancode, keycode);
+ /* No previous mapping found, we might need to grow the table */
+ if (rc_tab->size == rc_tab->len) {
+ if (!resize || ir_resize_table(rc_tab, GFP_ATOMIC))
+ return -1U;
+ }
- /* i is the proper index to insert our new keycode */
+ /* i is the proper index to insert our new keycode */
+ if (i < rc_tab->len)
memmove(&rc_tab->scan[i + 1], &rc_tab->scan[i],
(rc_tab->len - i) * sizeof(struct ir_scancode));
- rc_tab->scan[i].scancode = scancode;
- rc_tab->scan[i].keycode = keycode;
- rc_tab->len++;
- set_bit(keycode, dev->keybit);
- } else {
- IR_dprintk(1, "#%d: Replacing scan 0x%04x with key 0x%04x\n",
- i, scancode, keycode);
- /* A previous mapping was updated... */
- clear_bit(old_keycode, dev->keybit);
- /* ...but another scancode might use the same keycode */
- for (i = 0; i < rc_tab->len; i++) {
- if (rc_tab->scan[i].keycode == old_keycode) {
- set_bit(old_keycode, dev->keybit);
- break;
- }
- }
- }
+ rc_tab->scan[i].scancode = scancode;
+ rc_tab->scan[i].keycode = KEY_RESERVED;
+ rc_tab->len++;
- return 0;
+ return i;
}
/**
@@ -171,17 +234,41 @@ static int ir_do_setkeycode(struct input_dev *dev,
* This routine is used to handle evdev EVIOCSKEY ioctl.
*/
static int ir_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode)
{
- int rc;
- unsigned long flags;
struct ir_input_dev *ir_dev = input_get_drvdata(dev);
struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
+ unsigned int index;
+ unsigned int scancode;
+ int retval;
+ unsigned long flags;
spin_lock_irqsave(&rc_tab->lock, flags);
- rc = ir_do_setkeycode(dev, rc_tab, scancode, keycode, true);
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ index = ke->index;
+ if (index >= rc_tab->len) {
+ retval = -EINVAL;
+ goto out;
+ }
+ } else {
+ retval = input_scancode_to_scalar(ke, &scancode);
+ if (retval)
+ goto out;
+
+ index = ir_establish_scancode(ir_dev, rc_tab, scancode, true);
+ if (index >= rc_tab->len) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ }
+
+ *old_keycode = ir_update_mapping(dev, rc_tab, index, ke->keycode);
+
+out:
spin_unlock_irqrestore(&rc_tab->lock, flags);
- return rc;
+ return retval;
}
/**
@@ -189,32 +276,73 @@ static int ir_setkeycode(struct input_dev *dev,
* @dev: the struct input_dev device descriptor
* @to: the struct ir_scancode_table to copy entries to
* @from: the struct ir_scancode_table to copy entries from
- * @return: -EINVAL if all keycodes could not be inserted, otherwise zero.
+ * @return: -ENOMEM if all keycodes could not be inserted, otherwise zero.
*
* This routine is used to handle table initialization.
*/
-static int ir_setkeytable(struct input_dev *dev,
- struct ir_scancode_table *to,
+static int ir_setkeytable(struct ir_input_dev *ir_dev,
const struct ir_scancode_table *from)
{
- struct ir_input_dev *ir_dev = input_get_drvdata(dev);
struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
- unsigned long flags;
- unsigned int i;
- int rc = 0;
+ unsigned int i, index;
+ int rc;
+
+ rc = ir_create_table(&ir_dev->rc_tab,
+ from->name, from->ir_type, from->size);
+ if (rc)
+ return rc;
+
+ IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
+ rc_tab->size, rc_tab->alloc);
- spin_lock_irqsave(&rc_tab->lock, flags);
for (i = 0; i < from->size; i++) {
- rc = ir_do_setkeycode(dev, to, from->scan[i].scancode,
- from->scan[i].keycode, false);
- if (rc)
+ index = ir_establish_scancode(ir_dev, rc_tab,
+ from->scan[i].scancode, false);
+ if (index >= rc_tab->len) {
+ rc = -ENOMEM;
break;
+ }
+
+ ir_update_mapping(ir_dev->input_dev, rc_tab, index,
+ from->scan[i].keycode);
}
- spin_unlock_irqrestore(&rc_tab->lock, flags);
+
+ if (rc)
+ ir_free_table(rc_tab);
+
return rc;
}
/**
+ * ir_lookup_by_scancode() - locate mapping by scancode
+ * @rc_tab: the &struct ir_scancode_table to search
+ * @scancode: scancode to look for in the table
+ * @return: index in the table, -1U if not found
+ *
+ * This routine performs binary search in RC keykeymap table for
+ * given scancode.
+ */
+static unsigned int ir_lookup_by_scancode(const struct ir_scancode_table *rc_tab,
+ unsigned int scancode)
+{
+ unsigned int start = 0;
+ unsigned int end = rc_tab->len - 1;
+ unsigned int mid;
+
+ while (start <= end) {
+ mid = (start + end) / 2;
+ if (rc_tab->scan[mid].scancode < scancode)
+ start = mid + 1;
+ else if (rc_tab->scan[mid].scancode > scancode)
+ end = mid - 1;
+ else
+ return mid;
+ }
+
+ return -1U;
+}
+
+/**
* ir_getkeycode() - get a keycode from the scancode->keycode table
* @dev: the struct input_dev device descriptor
* @scancode: the desired scancode
@@ -224,36 +352,46 @@ static int ir_setkeytable(struct input_dev *dev,
* This routine is used to handle evdev EVIOCGKEY ioctl.
*/
static int ir_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
+ struct input_keymap_entry *ke)
{
- int start, end, mid;
- unsigned long flags;
- int key = KEY_RESERVED;
struct ir_input_dev *ir_dev = input_get_drvdata(dev);
struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
+ struct ir_scancode *entry;
+ unsigned long flags;
+ unsigned int index;
+ unsigned int scancode;
+ int retval;
spin_lock_irqsave(&rc_tab->lock, flags);
- start = 0;
- end = rc_tab->len - 1;
- while (start <= end) {
- mid = (start + end) / 2;
- if (rc_tab->scan[mid].scancode < scancode)
- start = mid + 1;
- else if (rc_tab->scan[mid].scancode > scancode)
- end = mid - 1;
- else {
- key = rc_tab->scan[mid].keycode;
- break;
- }
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ index = ke->index;
+ } else {
+ retval = input_scancode_to_scalar(ke, &scancode);
+ if (retval)
+ goto out;
+
+ index = ir_lookup_by_scancode(rc_tab, scancode);
+ }
+
+ if (index >= rc_tab->len) {
+ if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
+ IR_dprintk(1, "unknown key for scancode 0x%04x\n",
+ scancode);
+ retval = -EINVAL;
+ goto out;
}
- spin_unlock_irqrestore(&rc_tab->lock, flags);
- if (key == KEY_RESERVED)
- IR_dprintk(1, "unknown key for scancode 0x%04x\n",
- scancode);
+ entry = &rc_tab->scan[index];
- *keycode = key;
- return 0;
+ ke->index = index;
+ ke->keycode = entry->keycode;
+ ke->len = sizeof(entry->scancode);
+ memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
+
+out:
+ spin_unlock_irqrestore(&rc_tab->lock, flags);
+ return retval;
}
/**
@@ -268,12 +406,24 @@ static int ir_getkeycode(struct input_dev *dev,
*/
u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode)
{
- int keycode;
+ struct ir_input_dev *ir_dev = input_get_drvdata(dev);
+ struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
+ unsigned int keycode;
+ unsigned int index;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc_tab->lock, flags);
+
+ index = ir_lookup_by_scancode(rc_tab, scancode);
+ keycode = index < rc_tab->len ?
+ rc_tab->scan[index].keycode : KEY_RESERVED;
+
+ spin_unlock_irqrestore(&rc_tab->lock, flags);
- ir_getkeycode(dev, scancode, &keycode);
if (keycode != KEY_RESERVED)
IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
dev->name, scancode, keycode);
+
return keycode;
}
EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
@@ -453,8 +603,8 @@ int __ir_input_register(struct input_dev *input_dev,
goto out_dev;
}
- input_dev->getkeycode = ir_getkeycode;
- input_dev->setkeycode = ir_setkeycode;
+ input_dev->getkeycode_new = ir_getkeycode;
+ input_dev->setkeycode_new = ir_setkeycode;
input_set_drvdata(input_dev, ir_dev);
ir_dev->input_dev = input_dev;
@@ -462,12 +612,6 @@ int __ir_input_register(struct input_dev *input_dev,
spin_lock_init(&ir_dev->keylock);
setup_timer(&ir_dev->timer_keyup, ir_timer_keyup, (unsigned long)ir_dev);
- ir_dev->rc_tab.name = rc_tab->name;
- ir_dev->rc_tab.ir_type = rc_tab->ir_type;
- ir_dev->rc_tab.alloc = roundup_pow_of_two(rc_tab->size *
- sizeof(struct ir_scancode));
- ir_dev->rc_tab.scan = kmalloc(ir_dev->rc_tab.alloc, GFP_KERNEL);
- ir_dev->rc_tab.size = ir_dev->rc_tab.alloc / sizeof(struct ir_scancode);
if (props) {
ir_dev->props = props;
if (props->open)
@@ -476,23 +620,14 @@ int __ir_input_register(struct input_dev *input_dev,
input_dev->close = ir_close;
}
- if (!ir_dev->rc_tab.scan) {
- rc = -ENOMEM;
- goto out_name;
- }
-
- IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
- ir_dev->rc_tab.size, ir_dev->rc_tab.alloc);
-
set_bit(EV_KEY, input_dev->evbit);
set_bit(EV_REP, input_dev->evbit);
set_bit(EV_MSC, input_dev->evbit);
set_bit(MSC_SCAN, input_dev->mscbit);
- if (ir_setkeytable(input_dev, &ir_dev->rc_tab, rc_tab)) {
- rc = -ENOMEM;
- goto out_table;
- }
+ rc = ir_setkeytable(ir_dev, rc_tab);
+ if (rc)
+ goto out_name;
rc = ir_register_class(input_dev);
if (rc < 0)
@@ -522,7 +657,7 @@ int __ir_input_register(struct input_dev *input_dev,
out_event:
ir_unregister_class(input_dev);
out_table:
- kfree(ir_dev->rc_tab.scan);
+ ir_free_table(&ir_dev->rc_tab);
out_name:
kfree(ir_dev->driver_name);
out_dev:
@@ -540,7 +675,6 @@ EXPORT_SYMBOL_GPL(__ir_input_register);
void ir_input_unregister(struct input_dev *input_dev)
{
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct ir_scancode_table *rc_tab;
if (!ir_dev)
return;
@@ -552,10 +686,7 @@ void ir_input_unregister(struct input_dev *input_dev)
if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW)
ir_raw_event_unregister(input_dev);
- rc_tab = &ir_dev->rc_tab;
- rc_tab->size = 0;
- kfree(rc_tab->scan);
- rc_tab->scan = NULL;
+ ir_free_table(&ir_dev->rc_tab);
ir_unregister_class(input_dev);
diff --git a/drivers/media/IR/keymaps/rc-manli.c b/drivers/media/IR/keymaps/rc-manli.c
index 1e9fbfa90a1e..0f590b3d01c0 100644
--- a/drivers/media/IR/keymaps/rc-manli.c
+++ b/drivers/media/IR/keymaps/rc-manli.c
@@ -13,7 +13,6 @@
#include <media/rc-map.h>
/* Michael Tokarev <mjt@tls.msk.ru>
- http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
keytable is used by MANLI MTV00[0x0c] and BeholdTV 40[13] at
least, and probably other cards too.
The "ascii-art picture" below (in comments, first row
diff --git a/drivers/media/IR/lirc_dev.c b/drivers/media/IR/lirc_dev.c
index 0acf6396e068..202581808bdc 100644
--- a/drivers/media/IR/lirc_dev.c
+++ b/drivers/media/IR/lirc_dev.c
@@ -27,7 +27,6 @@
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/completion.h>
-#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/unistd.h>
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 893fbc57c72f..a12b88f53ed9 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -26,7 +26,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
@@ -2291,12 +2291,7 @@ static int frontend_init(struct av7110 *av7110)
/* Budgetpatch note:
* Original hardware design by Roberto Deza:
* There is a DVB_Wiki at
- * http://212.227.36.83/linuxtv/wiki/index.php/Main_Page
- * where is described this 'DVB TT Budget Patch', on Card Modding:
- * http://212.227.36.83/linuxtv/wiki/index.php/DVB_TT_Budget_Patch
- * On the short description there is also a link to a external file,
- * with more details:
- * http://perso.wanadoo.es/jesussolano/Ttf_tsc1.zip
+ * http://www.linuxtv.org/
*
* New software triggering design by Emard that works on
* original Roberto Deza's hardware:
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 6ef3996565ad..244d5d51f5f9 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -25,7 +25,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
#include <linux/types.h>
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index 43f61f2eca98..122c72806916 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -25,7 +25,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
#include <linux/kernel.h>
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index e162691b515d..f1cbfe526989 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -22,7 +22,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
/* for debugging ARM communication: */
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index 8986d967d2f4..ac20c5bbfa43 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -22,7 +22,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
#include <linux/kernel.h>
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 983672aa2450..97afc01f60d0 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -30,7 +30,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
#include "budget.h"
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 13ac9e3ab121..a9c2c326df4b 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -26,7 +26,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
#include <linux/module.h>
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index ba18e56d5f11..054661315311 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -31,7 +31,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index 9c92f9ddd223..579835590690 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -27,7 +27,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
#include "av7110.h"
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 874a10a9d493..d238fb9371a7 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -31,7 +31,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
#include "budget.h"
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 4349213b403b..255d40df4b46 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -13,7 +13,7 @@
* anybody does please mail me.
*
* For the pdf file see:
- * http://www.semiconductors.philips.com/pip/TEA5757H/V1
+ * http://www.nxp.com/acrobat_download2/expired_datasheets/TEA5757_5759_3.pdf
*
*
* CHANGES:
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index 03439282dfce..b1f630527dc1 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -1,9 +1,6 @@
/* Typhoon Radio Card driver for radio support
* (c) 1999 Dr. Henrik Seidel <Henrik.Seidel@gmx.de>
*
- * Card manufacturer:
- * http://194.18.155.92/idc/prod2.idc?nr=50753&lang=e
- *
* Notes on the hardware
*
* This card has two output sockets, one for speakers and one for line.
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index f6e4d0475351..d000522cb0f4 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -978,7 +978,7 @@ config USB_STKWEBCAM
Supported devices are typically found in some Asus laptops,
with USB id 174f:a311 and 05e1:0501. Other Syntek cameras
may be supported by the stk11xx driver, from which this is
- derived, see http://stk11xx.sourceforge.net
+ derived, see <http://sourceforge.net/projects/syntekdriver/>
To compile this driver as a module, choose M here: the
module will be called stkwebcam.
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index be35e6965829..9536f1a40dd2 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -4,7 +4,7 @@
* sensor.
*
* The data sheet for this device can be found at:
- * http://www.marvell.com/products/pcconn/88ALP01.jsp
+ * http://www.marvell.com/products/pc_connectivity/88alp01/
*
* Copyright 2006 One Laptop Per Child Association, Inc.
* Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index 6b805afe5d20..fe1090940b01 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -39,7 +39,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = {
.tv = { 0x61, 0x60, I2C_CLIENT_END },
};
-/* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii
+/* Please add new PCI IDs to: http://pci-ids.ucw.cz/
This keeps the PCI ID database up to date. Note that the entries
must be added under vendor 0x4444 (Conexant) as subsystem IDs.
New vendor IDs should still be added to the vendor ID list. */
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
index abd64e89f60f..53a67824071b 100644
--- a/drivers/media/video/cx23885/cx23885-417.c
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -7,7 +7,7 @@
* (c) 2008 Steven Toth <stoth@linuxtv.org>
* - CX23885/7/8 support
*
- * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
+ * Includes parts from the ivtv driver <http://sourceforge.net/projects/ivtv/>
*
* 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/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index e46e1ceef72c..660b2a927feb 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -9,7 +9,7 @@
* (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
* - video_ioctl2 conversion
*
- * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
+ * Includes parts from the ivtv driver <http://sourceforge.net/projects/ivtv/>
*
* 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/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index ca1fd3227a93..87afbbee2063 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -65,7 +65,7 @@ static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = {
/********************** card configuration *******************************/
-/* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii
+/* Please add new PCI IDs to: http://pci-ids.ucw.cz/
This keeps the PCI ID database up to date. Note that the entries
must be added under vendor 0x4444 (Conexant) as subsystem IDs.
New vendor IDs should still be added to the vendor ID list. */
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index ef0c8178f255..b1dbcf1d2bcb 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -3,7 +3,7 @@
Copyright (C) 1998-2006 Michael Hunold <michael@mihu.de>
- Visit http://www.mihu.de/linux/saa7146/mxb/
+ Visit http://www.themm.net/~mihu/linux/saa7146/mxb.html
for further details about this card.
This program is free software; you can redistribute it and/or modify
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
index 2782f94cf6f8..2e86fdc86989 100644
--- a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
+++ b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
@@ -4,7 +4,6 @@
* *
* Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio *
* <medaglia@undl.org.br> *
- * http://cadu.homelinux.com:8080/ *
* *
* Support for SN9C103, DAC Magnitude, exposure and green gain controls *
* added by Luca Risolia <luca.risolia@studio.unibo.it> *
diff --git a/drivers/media/video/zoran/videocodec.h b/drivers/media/video/zoran/videocodec.h
index 5c27b251354e..b654bfff8740 100644
--- a/drivers/media/video/zoran/videocodec.h
+++ b/drivers/media/video/zoran/videocodec.h
@@ -56,7 +56,7 @@
the slave is bound to it). Otherwise it doesn't need this functions and
therfor they may not be initialized.
- The other fuctions are just for convenience, as they are for sure used by
+ The other functions are just for convenience, as they are for sure used by
most/all of the codecs. The last ones may be ommited, too.
See the structure declaration below for more information and which data has
diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c
index 6f89d0a096ea..3c471a4e3e4a 100644
--- a/drivers/media/video/zoran/zoran_driver.c
+++ b/drivers/media/video/zoran/zoran_driver.c
@@ -1177,7 +1177,7 @@ static int setup_window(struct zoran_fh *fh, int x, int y, int width, int height
if (height > BUZ_MAX_HEIGHT)
height = BUZ_MAX_HEIGHT;
- /* Check for vaild parameters */
+ /* Check for invalid parameters */
if (width < BUZ_MIN_WIDTH || height < BUZ_MIN_HEIGHT ||
width > BUZ_MAX_WIDTH || height > BUZ_MAX_HEIGHT) {
dprintk(1,
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index defa786dee34..b8c4b80e4c43 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -338,6 +338,21 @@ static struct resource ab8500_rtc_resources[] = {
},
};
+static struct resource ab8500_poweronkey_db_resources[] = {
+ {
+ .name = "ONKEY_DBF",
+ .start = AB8500_INT_PON_KEY1DB_F,
+ .end = AB8500_INT_PON_KEY1DB_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "ONKEY_DBR",
+ .start = AB8500_INT_PON_KEY1DB_R,
+ .end = AB8500_INT_PON_KEY1DB_R,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static struct mfd_cell ab8500_devs[] = {
{
.name = "ab8500-gpadc",
@@ -354,6 +369,11 @@ static struct mfd_cell ab8500_devs[] = {
{ .name = "ab8500-usb", },
{ .name = "ab8500-pwm", },
{ .name = "ab8500-regulator", },
+ {
+ .name = "ab8500-poweron-key",
+ .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
+ .resources = ab8500_poweronkey_db_resources,
+ },
};
int __devinit ab8500_init(struct ab8500 *ab8500)
diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c
index cd164595f08a..49b4d069cbf9 100644
--- a/drivers/mfd/sh_mobile_sdhi.c
+++ b/drivers/mfd/sh_mobile_sdhi.c
@@ -65,7 +65,7 @@ static void sh_mobile_sdhi_set_pwr(struct platform_device *tmio, int state)
p->set_pwr(pdev, state);
}
-static int __init sh_mobile_sdhi_probe(struct platform_device *pdev)
+static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
{
struct sh_mobile_sdhi *priv;
struct tmio_mmc_data *mmc_data;
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 720e099e506d..5d0fb60a4c14 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -698,17 +698,17 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
if (twl_has_codec() && pdata->codec && twl_class_is_4030()) {
sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
- child = add_child(sub_chip_id, "twl4030_codec",
+ child = add_child(sub_chip_id, "twl4030-audio",
pdata->codec, sizeof(*pdata->codec),
false, 0, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
- /* Phoenix*/
+ /* Phoenix codec driver is probed directly atm */
if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
- child = add_child(sub_chip_id, "twl6040_codec",
+ child = add_child(sub_chip_id, "twl6040-codec",
pdata->codec, sizeof(*pdata->codec),
false, 0, 0);
if (IS_ERR(child))
diff --git a/drivers/mfd/twl4030-codec.c b/drivers/mfd/twl4030-codec.c
index add6f67d8032..9a4b196d6deb 100644
--- a/drivers/mfd/twl4030-codec.c
+++ b/drivers/mfd/twl4030-codec.c
@@ -207,14 +207,14 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
if (pdata->audio) {
cell = &codec->cells[childs];
- cell->name = "twl4030_codec_audio";
+ cell->name = "twl4030-codec";
cell->platform_data = pdata->audio;
cell->data_size = sizeof(*pdata->audio);
childs++;
}
if (pdata->vibra) {
cell = &codec->cells[childs];
- cell->name = "twl4030_codec_vibra";
+ cell->name = "twl4030-vibra";
cell->platform_data = pdata->vibra;
cell->data_size = sizeof(*pdata->vibra);
childs++;
@@ -249,14 +249,14 @@ static int __devexit twl4030_codec_remove(struct platform_device *pdev)
return 0;
}
-MODULE_ALIAS("platform:twl4030_codec");
+MODULE_ALIAS("platform:twl4030-audio");
static struct platform_driver twl4030_codec_driver = {
.probe = twl4030_codec_probe,
.remove = __devexit_p(twl4030_codec_remove),
.driver = {
.owner = THIS_MODULE,
- .name = "twl4030_codec",
+ .name = "twl4030-audio",
},
};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index db2fbe2d4146..5a74db75f66f 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -4,7 +4,6 @@
menuconfig MISC_DEVICES
bool "Misc devices"
- default y
---help---
Say Y here to get to see options for device drivers from various
different categories. This option alone does not add any kernel code.
@@ -24,7 +23,8 @@ config AD525X_DPOT
AD5260, AD5262, AD5263, AD5290, AD5291, AD5292, AD5293,
AD7376, AD8400, AD8402, AD8403, ADN2850, AD5241, AD5242,
AD5243, AD5245, AD5246, AD5247, AD5248, AD5280, AD5282,
- ADN2860, AD5273, AD5171, AD5170, AD5172, AD5173
+ ADN2860, AD5273, AD5171, AD5170, AD5172, AD5173, AD5270,
+ AD5271, AD5272, AD5274
digital potentiometer chips.
See Documentation/misc-devices/ad525x_dpot.txt for the
@@ -112,8 +112,8 @@ config IBM_ASM
WARNING: This software may not be supported or function
correctly on your IBM server. Please consult the IBM ServerProven
- website <http://www.pc.ibm.com/ww/eserver/xseries/serverproven> for
- information on the specific driver level and support statement
+ website <http://www-03.ibm.com/systems/info/x86servers/serverproven/compat/us/>
+ for information on the specific driver level and support statement
for your IBM server.
config PHANTOM
@@ -284,6 +284,16 @@ config SGI_GRU_DEBUG
This option enables addition debugging code for the SGI GRU driver. If
you are unsure, say N.
+config APDS9802ALS
+ tristate "Medfield Avago APDS9802 ALS Sensor module"
+ depends on I2C
+ help
+ If you say yes here you get support for the ALS APDS9802 ambient
+ light sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called apds9802als.
+
config ISL29003
tristate "Intersil ISL29003 ambient light sensor"
depends on I2C && SYSFS
@@ -294,6 +304,16 @@ config ISL29003
This driver can also be built as a module. If so, the module
will be called isl29003.
+config ISL29020
+ tristate "Intersil ISL29020 ambient light sensor"
+ depends on I2C
+ help
+ If you say yes here you get support for the Intersil ISL29020
+ ambient light sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called isl29020.
+
config SENSORS_TSL2550
tristate "Taos TSL2550 ambient light sensor"
depends on I2C && SYSFS
@@ -314,6 +334,27 @@ config SENSORS_BH1780
This driver can also be built as a module. If so, the module
will be called bh1780gli.
+config SENSORS_BH1770
+ tristate "BH1770GLC / SFH7770 combined ALS - Proximity sensor"
+ depends on I2C
+ ---help---
+ Say Y here if you want to build a driver for BH1770GLC (ROHM) or
+ SFH7770 (Osram) combined ambient light and proximity sensor chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bh1770glc. If unsure, say N here.
+
+config SENSORS_APDS990X
+ tristate "APDS990X combined als and proximity sensors"
+ depends on I2C
+ default n
+ ---help---
+ Say Y here if you want to build a driver for Avago APDS990x
+ combined ambient light and proximity sensor chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called apds990x. If unsure, say N here.
+
config HMC6352
tristate "Honeywell HMC6352 compass"
depends on I2C
@@ -385,7 +426,7 @@ config BMP085
depends on I2C && SYSFS
help
If you say yes here you get support for the Bosch Sensortec
- BMP086 digital pressure sensor.
+ BMP085 digital pressure sensor.
To compile this driver as a module, choose M here: the
module will be called bmp085.
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 9f2986b4da2f..4be5c6fc5ef4 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -16,6 +16,8 @@ obj-$(CONFIG_TIFM_CORE) += tifm_core.o
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
obj-$(CONFIG_PHANTOM) += phantom.o
obj-$(CONFIG_SENSORS_BH1780) += bh1780gli.o
+obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o
+obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
@@ -23,7 +25,9 @@ obj-$(CONFIG_SGI_XP) += sgi-xp/
obj-$(CONFIG_SGI_GRU) += sgi-gru/
obj-$(CONFIG_CS5535_MFGPT) += cs5535-mfgpt.o
obj-$(CONFIG_HP_ILO) += hpilo.o
+obj-$(CONFIG_APDS9802ALS) += apds9802als.o
obj-$(CONFIG_ISL29003) += isl29003.o
+obj-$(CONFIG_ISL29020) += isl29020.o
obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o
obj-$(CONFIG_DS1682) += ds1682.o
diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c
index 374352af7979..4ff73c215746 100644
--- a/drivers/misc/ad525x_dpot-i2c.c
+++ b/drivers/misc/ad525x_dpot-i2c.c
@@ -102,6 +102,8 @@ static const struct i2c_device_id ad_dpot_id[] = {
{"ad5170", AD5170_ID},
{"ad5172", AD5172_ID},
{"ad5173", AD5173_ID},
+ {"ad5272", AD5272_ID},
+ {"ad5274", AD5274_ID},
{}
};
MODULE_DEVICE_TABLE(i2c, ad_dpot_id);
diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c
index b8c6df9c8437..7f9a55afe05d 100644
--- a/drivers/misc/ad525x_dpot-spi.c
+++ b/drivers/misc/ad525x_dpot-spi.c
@@ -38,6 +38,8 @@ static const struct ad_dpot_id ad_dpot_spi_devlist[] = {
{.name = "ad8402", .devid = AD8402_ID},
{.name = "ad8403", .devid = AD8403_ID},
{.name = "adn2850", .devid = ADN2850_ID},
+ {.name = "ad5270", .devid = AD5270_ID},
+ {.name = "ad5271", .devid = AD5271_ID},
{}
};
@@ -53,13 +55,13 @@ static int write8(void *client, u8 val)
static int write16(void *client, u8 reg, u8 val)
{
u8 data[2] = {reg, val};
- return spi_write(client, data, 1);
+ return spi_write(client, data, 2);
}
static int write24(void *client, u8 reg, u16 val)
{
u8 data[3] = {reg, val >> 8, val};
- return spi_write(client, data, 1);
+ return spi_write(client, data, 3);
}
static int read8(void *client)
diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c
index 5e6fa8449e8b..7cb911028d09 100644
--- a/drivers/misc/ad525x_dpot.c
+++ b/drivers/misc/ad525x_dpot.c
@@ -29,9 +29,9 @@
* AD5262 2 256 20, 50, 200
* AD5263 4 256 20, 50, 200
* AD5290 1 256 10, 50, 100
- * AD5291 1 256 20
- * AD5292 1 1024 20
- * AD5293 1 1024 20
+ * AD5291 1 256 20, 50, 100 (20-TP)
+ * AD5292 1 1024 20, 50, 100 (20-TP)
+ * AD5293 1 1024 20, 50, 100
* AD7376 1 128 10, 50, 100, 1M
* AD8400 1 256 1, 10, 50, 100
* AD8402 2 256 1, 10, 50, 100
@@ -52,6 +52,10 @@
* AD5170 1 256 2.5, 10, 50, 100 (OTP)
* AD5172 2 256 2.5, 10, 50, 100 (OTP)
* AD5173 2 256 2.5, 10, 50, 100 (OTP)
+ * AD5270 1 1024 20, 50, 100 (50-TP)
+ * AD5271 1 256 20, 50, 100 (50-TP)
+ * AD5272 1 1024 20, 50, 100 (50-TP)
+ * AD5274 1 256 20, 50, 100 (50-TP)
*
* See Documentation/misc-devices/ad525x_dpot.txt for more info.
*
@@ -126,18 +130,38 @@ static inline int dpot_write_r8d16(struct dpot_data *dpot, u8 reg, u16 val)
static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg)
{
unsigned ctrl = 0;
+ int value;
if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
if (dpot->feat & F_RDACS_WONLY)
return dpot->rdac_cache[reg & DPOT_RDAC_MASK];
-
if (dpot->uid == DPOT_UID(AD5291_ID) ||
dpot->uid == DPOT_UID(AD5292_ID) ||
- dpot->uid == DPOT_UID(AD5293_ID))
- return dpot_read_r8d8(dpot,
+ dpot->uid == DPOT_UID(AD5293_ID)) {
+
+ value = dpot_read_r8d8(dpot,
DPOT_AD5291_READ_RDAC << 2);
+ if (dpot->uid == DPOT_UID(AD5291_ID))
+ value = value >> 2;
+
+ return value;
+ } else if (dpot->uid == DPOT_UID(AD5270_ID) ||
+ dpot->uid == DPOT_UID(AD5271_ID)) {
+
+ value = dpot_read_r8d8(dpot,
+ DPOT_AD5270_1_2_4_READ_RDAC << 2);
+
+ if (value < 0)
+ return value;
+
+ if (dpot->uid == DPOT_UID(AD5271_ID))
+ value = value >> 2;
+
+ return value;
+ }
+
ctrl = DPOT_SPI_READ_RDAC;
} else if (reg & DPOT_ADDR_EEPROM) {
ctrl = DPOT_SPI_READ_EEPROM;
@@ -153,6 +177,7 @@ static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg)
static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
{
+ int value;
unsigned ctrl = 0;
switch (dpot->uid) {
case DPOT_UID(AD5246_ID):
@@ -166,7 +191,7 @@ static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
case DPOT_UID(AD5280_ID):
case DPOT_UID(AD5282_ID):
ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
- 0 : DPOT_AD5291_RDAC_AB;
+ 0 : DPOT_AD5282_RDAC_AB;
return dpot_read_r8d8(dpot, ctrl);
case DPOT_UID(AD5170_ID):
case DPOT_UID(AD5171_ID):
@@ -175,8 +200,27 @@ static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
case DPOT_UID(AD5172_ID):
case DPOT_UID(AD5173_ID):
ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
- 0 : DPOT_AD5272_3_A0;
+ 0 : DPOT_AD5172_3_A0;
return dpot_read_r8d8(dpot, ctrl);
+ case DPOT_UID(AD5272_ID):
+ case DPOT_UID(AD5274_ID):
+ dpot_write_r8d8(dpot,
+ (DPOT_AD5270_1_2_4_READ_RDAC << 2), 0);
+
+ value = dpot_read_r8d16(dpot,
+ DPOT_AD5270_1_2_4_RDAC << 2);
+
+ if (value < 0)
+ return value;
+ /*
+ * AD5272/AD5274 returns high byte first, however
+ * underling smbus expects low byte first.
+ */
+ value = swab16(value);
+
+ if (dpot->uid == DPOT_UID(AD5271_ID))
+ value = value >> 2;
+ return value;
default:
if ((reg & DPOT_REG_TOL) || (dpot->max_pos > 256))
return dpot_read_r8d16(dpot, (reg & 0xF8) |
@@ -198,7 +242,7 @@ static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value)
{
unsigned val = 0;
- if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
+ if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD | DPOT_ADDR_OTP))) {
if (dpot->feat & F_RDACS_WONLY)
dpot->rdac_cache[reg & DPOT_RDAC_MASK] = value;
@@ -219,11 +263,30 @@ static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value)
} else {
if (dpot->uid == DPOT_UID(AD5291_ID) ||
dpot->uid == DPOT_UID(AD5292_ID) ||
- dpot->uid == DPOT_UID(AD5293_ID))
+ dpot->uid == DPOT_UID(AD5293_ID)) {
+
+ dpot_write_r8d8(dpot, DPOT_AD5291_CTRLREG << 2,
+ DPOT_AD5291_UNLOCK_CMD);
+
+ if (dpot->uid == DPOT_UID(AD5291_ID))
+ value = value << 2;
+
return dpot_write_r8d8(dpot,
(DPOT_AD5291_RDAC << 2) |
(value >> 8), value & 0xFF);
+ } else if (dpot->uid == DPOT_UID(AD5270_ID) ||
+ dpot->uid == DPOT_UID(AD5271_ID)) {
+ dpot_write_r8d8(dpot,
+ DPOT_AD5270_1_2_4_CTRLREG << 2,
+ DPOT_AD5270_1_2_4_UNLOCK_CMD);
+
+ if (dpot->uid == DPOT_UID(AD5271_ID))
+ value = value << 2;
+ return dpot_write_r8d8(dpot,
+ (DPOT_AD5270_1_2_4_RDAC << 2) |
+ (value >> 8), value & 0xFF);
+ }
val = DPOT_SPI_RDAC | (reg & DPOT_RDAC_MASK);
}
} else if (reg & DPOT_ADDR_EEPROM) {
@@ -243,6 +306,16 @@ static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value)
val = DPOT_SPI_INC_ALL;
break;
}
+ } else if (reg & DPOT_ADDR_OTP) {
+ if (dpot->uid == DPOT_UID(AD5291_ID) ||
+ dpot->uid == DPOT_UID(AD5292_ID)) {
+ return dpot_write_r8d8(dpot,
+ DPOT_AD5291_STORE_XTPM << 2, 0);
+ } else if (dpot->uid == DPOT_UID(AD5270_ID) ||
+ dpot->uid == DPOT_UID(AD5271_ID)) {
+ return dpot_write_r8d8(dpot,
+ DPOT_AD5270_1_2_4_STORE_XTPM << 2, 0);
+ }
} else
BUG();
@@ -273,7 +346,7 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
case DPOT_UID(AD5280_ID):
case DPOT_UID(AD5282_ID):
ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
- 0 : DPOT_AD5291_RDAC_AB;
+ 0 : DPOT_AD5282_RDAC_AB;
return dpot_write_r8d8(dpot, ctrl, value);
break;
case DPOT_UID(AD5171_ID):
@@ -289,12 +362,12 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
case DPOT_UID(AD5172_ID):
case DPOT_UID(AD5173_ID):
ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
- 0 : DPOT_AD5272_3_A0;
+ 0 : DPOT_AD5172_3_A0;
if (reg & DPOT_ADDR_OTP) {
tmp = dpot_read_r8d16(dpot, ctrl);
if (tmp >> 14) /* Ready to Program? */
return -EFAULT;
- ctrl |= DPOT_AD5270_2_3_FUSE;
+ ctrl |= DPOT_AD5170_2_3_FUSE;
}
return dpot_write_r8d8(dpot, ctrl, value);
break;
@@ -303,10 +376,25 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
tmp = dpot_read_r8d16(dpot, tmp);
if (tmp >> 14) /* Ready to Program? */
return -EFAULT;
- ctrl = DPOT_AD5270_2_3_FUSE;
+ ctrl = DPOT_AD5170_2_3_FUSE;
}
return dpot_write_r8d8(dpot, ctrl, value);
break;
+ case DPOT_UID(AD5272_ID):
+ case DPOT_UID(AD5274_ID):
+ dpot_write_r8d8(dpot, DPOT_AD5270_1_2_4_CTRLREG << 2,
+ DPOT_AD5270_1_2_4_UNLOCK_CMD);
+
+ if (reg & DPOT_ADDR_OTP)
+ return dpot_write_r8d8(dpot,
+ DPOT_AD5270_1_2_4_STORE_XTPM << 2, 0);
+
+ if (dpot->uid == DPOT_UID(AD5274_ID))
+ value = value << 2;
+
+ return dpot_write_r8d8(dpot, (DPOT_AD5270_1_2_4_RDAC << 2) |
+ (value >> 8), value & 0xFF);
+ break;
default:
if (reg & DPOT_ADDR_CMD)
return dpot_write_d8(dpot, reg);
@@ -320,7 +408,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
}
}
-
static s32 dpot_write(struct dpot_data *dpot, u8 reg, u16 value)
{
if (dpot->feat & F_SPI)
diff --git a/drivers/misc/ad525x_dpot.h b/drivers/misc/ad525x_dpot.h
index 78b89fd2e2fd..a662f5987b68 100644
--- a/drivers/misc/ad525x_dpot.h
+++ b/drivers/misc/ad525x_dpot.h
@@ -47,9 +47,9 @@ enum dpot_devid {
AD5258_ID = DPOT_CONF(F_RDACS_RW_TOL, BRDAC0, 6, 0), /* I2C */
AD5259_ID = DPOT_CONF(F_RDACS_RW_TOL, BRDAC0, 8, 1),
AD5251_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
- BRDAC0 | BRDAC3, 6, 2),
+ BRDAC1 | BRDAC3, 6, 2),
AD5252_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
- BRDAC0 | BRDAC3, 8, 3),
+ BRDAC1 | BRDAC3, 8, 3),
AD5253_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 6, 4),
AD5254_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
@@ -93,8 +93,10 @@ enum dpot_devid {
BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 8, 23),
AD5290_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
BRDAC0, 8, 24),
- AD5291_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 8, 25),
- AD5292_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 26),
+ AD5291_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT | F_CMD_OTP,
+ BRDAC0, 8, 25),
+ AD5292_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT | F_CMD_OTP,
+ BRDAC0, 10, 26),
AD5293_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 27),
AD7376_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
BRDAC0, 7, 28),
@@ -122,6 +124,12 @@ enum dpot_devid {
AD5170_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 8, 45),
AD5172_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0 | BRDAC1, 8, 46),
AD5173_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0 | BRDAC1, 8, 47),
+ AD5270_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP | F_SPI_16BIT,
+ BRDAC0, 10, 48),
+ AD5271_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP | F_SPI_16BIT,
+ BRDAC0, 8, 49),
+ AD5272_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 10, 50),
+ AD5274_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 8, 51),
};
#define DPOT_RDAC0 0
@@ -165,15 +173,24 @@ enum dpot_devid {
/* AD5291/2/3 use special commands */
#define DPOT_AD5291_RDAC 0x01
#define DPOT_AD5291_READ_RDAC 0x02
+#define DPOT_AD5291_STORE_XTPM 0x03
+#define DPOT_AD5291_CTRLREG 0x06
+#define DPOT_AD5291_UNLOCK_CMD 0x03
-/* AD524x use special commands */
-#define DPOT_AD5291_RDAC_AB 0x80
+/* AD5270/1/2/4 use special commands */
+#define DPOT_AD5270_1_2_4_RDAC 0x01
+#define DPOT_AD5270_1_2_4_READ_RDAC 0x02
+#define DPOT_AD5270_1_2_4_STORE_XTPM 0x03
+#define DPOT_AD5270_1_2_4_CTRLREG 0x07
+#define DPOT_AD5270_1_2_4_UNLOCK_CMD 0x03
+
+#define DPOT_AD5282_RDAC_AB 0x80
#define DPOT_AD5273_FUSE 0x80
-#define DPOT_AD5270_2_3_FUSE 0x20
-#define DPOT_AD5270_2_3_OW 0x08
-#define DPOT_AD5272_3_A0 0x08
-#define DPOT_AD5270_2FUSE 0x80
+#define DPOT_AD5170_2_3_FUSE 0x20
+#define DPOT_AD5170_2_3_OW 0x08
+#define DPOT_AD5172_3_A0 0x08
+#define DPOT_AD5170_2FUSE 0x80
struct dpot_data;
diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c
new file mode 100644
index 000000000000..f9b91ba8900c
--- /dev/null
+++ b/drivers/misc/apds9802als.c
@@ -0,0 +1,347 @@
+/*
+ * apds9802als.c - apds9802 ALS Driver
+ *
+ * Copyright (C) 2009 Intel Corp
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/pm_runtime.h>
+
+#define ALS_MIN_RANGE_VAL 1
+#define ALS_MAX_RANGE_VAL 2
+#define POWER_STA_ENABLE 1
+#define POWER_STA_DISABLE 0
+
+#define DRIVER_NAME "apds9802als"
+
+struct als_data {
+ struct mutex mutex;
+};
+
+static ssize_t als_sensing_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int val;
+
+ val = i2c_smbus_read_byte_data(client, 0x81);
+ if (val < 0)
+ return val;
+ if (val & 1)
+ return sprintf(buf, "4095\n");
+ else
+ return sprintf(buf, "65535\n");
+}
+
+static int als_wait_for_data_ready(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret;
+ int retry = 10;
+
+ do {
+ msleep(30);
+ ret = i2c_smbus_read_byte_data(client, 0x86);
+ } while (!(ret & 0x80) && retry--);
+
+ if (!retry) {
+ dev_warn(dev, "timeout waiting for data ready\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static ssize_t als_lux0_input_data_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct als_data *data = i2c_get_clientdata(client);
+ int ret_val;
+ int temp;
+
+ /* Protect against parallel reads */
+ pm_runtime_get_sync(dev);
+ mutex_lock(&data->mutex);
+
+ /* clear EOC interrupt status */
+ i2c_smbus_write_byte(client, 0x40);
+ /* start measurement */
+ temp = i2c_smbus_read_byte_data(client, 0x81);
+ i2c_smbus_write_byte_data(client, 0x81, temp | 0x08);
+
+ ret_val = als_wait_for_data_ready(dev);
+ if (ret_val < 0)
+ goto failed;
+
+ temp = i2c_smbus_read_byte_data(client, 0x8C); /* LSB data */
+ if (temp < 0) {
+ ret_val = temp;
+ goto failed;
+ }
+ ret_val = i2c_smbus_read_byte_data(client, 0x8D); /* MSB data */
+ if (ret_val < 0)
+ goto failed;
+
+ mutex_unlock(&data->mutex);
+ pm_runtime_put_sync(dev);
+
+ temp = (ret_val << 8) | temp;
+ return sprintf(buf, "%d\n", temp);
+failed:
+ mutex_unlock(&data->mutex);
+ pm_runtime_put_sync(dev);
+ return ret_val;
+}
+
+static ssize_t als_sensing_range_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct als_data *data = i2c_get_clientdata(client);
+ unsigned int ret_val;
+ unsigned long val;
+
+ if (strict_strtoul(buf, 10, &val))
+ return -EINVAL;
+
+ if (val < 4096)
+ val = 1;
+ else if (val < 65536)
+ val = 2;
+ else
+ return -ERANGE;
+
+ pm_runtime_get_sync(dev);
+
+ /* Make sure nobody else reads/modifies/writes 0x81 while we
+ are active */
+ mutex_lock(&data->mutex);
+
+ ret_val = i2c_smbus_read_byte_data(client, 0x81);
+ if (ret_val < 0)
+ goto fail;
+
+ /* Reset the bits before setting them */
+ ret_val = ret_val & 0xFA;
+
+ if (val == 1) /* Setting detection range up to 4k LUX */
+ ret_val = (ret_val | 0x01);
+ else /* Setting detection range up to 64k LUX*/
+ ret_val = (ret_val | 0x00);
+
+ ret_val = i2c_smbus_write_byte_data(client, 0x81, ret_val);
+
+ if (ret_val >= 0) {
+ /* All OK */
+ mutex_unlock(&data->mutex);
+ pm_runtime_put_sync(dev);
+ return count;
+ }
+fail:
+ mutex_unlock(&data->mutex);
+ pm_runtime_put_sync(dev);
+ return ret_val;
+}
+
+static int als_set_power_state(struct i2c_client *client, bool on_off)
+{
+ int ret_val;
+ struct als_data *data = i2c_get_clientdata(client);
+
+ mutex_lock(&data->mutex);
+ ret_val = i2c_smbus_read_byte_data(client, 0x80);
+ if (ret_val < 0)
+ goto fail;
+ if (on_off)
+ ret_val = ret_val | 0x01;
+ else
+ ret_val = ret_val & 0xFE;
+ ret_val = i2c_smbus_write_byte_data(client, 0x80, ret_val);
+fail:
+ mutex_unlock(&data->mutex);
+ return ret_val;
+}
+
+static DEVICE_ATTR(lux0_sensor_range, S_IRUGO | S_IWUSR,
+ als_sensing_range_show, als_sensing_range_store);
+static DEVICE_ATTR(lux0_input, S_IRUGO, als_lux0_input_data_show, NULL);
+
+static struct attribute *mid_att_als[] = {
+ &dev_attr_lux0_sensor_range.attr,
+ &dev_attr_lux0_input.attr,
+ NULL
+};
+
+static struct attribute_group m_als_gr = {
+ .name = "apds9802als",
+ .attrs = mid_att_als
+};
+
+static int als_set_default_config(struct i2c_client *client)
+{
+ int ret_val;
+ /* Write the command and then switch on */
+ ret_val = i2c_smbus_write_byte_data(client, 0x80, 0x01);
+ if (ret_val < 0) {
+ dev_err(&client->dev, "failed default switch on write\n");
+ return ret_val;
+ }
+ /* detection range: 1~64K Lux, maunal measurement */
+ ret_val = i2c_smbus_write_byte_data(client, 0x81, 0x08);
+ if (ret_val < 0)
+ dev_err(&client->dev, "failed default LUX on write\n");
+
+ /* We always get 0 for the 1st measurement after system power on,
+ * so make sure it is finished before user asks for data.
+ */
+ als_wait_for_data_ready(&client->dev);
+
+ return ret_val;
+}
+
+static int apds9802als_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int res;
+ struct als_data *data;
+
+ data = kzalloc(sizeof(struct als_data), GFP_KERNEL);
+ if (data == NULL) {
+ dev_err(&client->dev, "Memory allocation failed\n");
+ return -ENOMEM;
+ }
+ i2c_set_clientdata(client, data);
+ res = sysfs_create_group(&client->dev.kobj, &m_als_gr);
+ if (res) {
+ dev_err(&client->dev, "device create file failed\n");
+ goto als_error1;
+ }
+ dev_info(&client->dev, "ALS chip found\n");
+ als_set_default_config(client);
+ mutex_init(&data->mutex);
+
+ pm_runtime_enable(&client->dev);
+ pm_runtime_get(&client->dev);
+ pm_runtime_put(&client->dev);
+
+ return res;
+als_error1:
+ i2c_set_clientdata(client, NULL);
+ kfree(data);
+ return res;
+}
+
+static int apds9802als_remove(struct i2c_client *client)
+{
+ struct als_data *data = i2c_get_clientdata(client);
+
+ als_set_power_state(client, false);
+ sysfs_remove_group(&client->dev.kobj, &m_als_gr);
+ kfree(data);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int apds9802als_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ als_set_power_state(client, false);
+ return 0;
+}
+
+static int apds9802als_resume(struct i2c_client *client)
+{
+ als_set_default_config(client);
+
+ pm_runtime_get(&client->dev);
+ pm_runtime_put(&client->dev);
+ return 0;
+}
+
+static int apds9802als_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ als_set_power_state(client, false);
+ return 0;
+}
+
+static int apds9802als_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ als_set_power_state(client, true);
+ return 0;
+}
+
+static const struct dev_pm_ops apds9802als_pm_ops = {
+ .runtime_suspend = apds9802als_runtime_suspend,
+ .runtime_resume = apds9802als_runtime_resume,
+};
+
+#define APDS9802ALS_PM_OPS (&apds9802als_pm_ops)
+
+#else /* CONFIG_PM */
+#define apds9802als_suspend NULL
+#define apds9802als_resume NULL
+#define APDS9802ALS_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static struct i2c_device_id apds9802als_id[] = {
+ { DRIVER_NAME, 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, apds9802als_id);
+
+static struct i2c_driver apds9802als_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .pm = APDS9802ALS_PM_OPS,
+ },
+ .probe = apds9802als_probe,
+ .remove = apds9802als_remove,
+ .suspend = apds9802als_suspend,
+ .resume = apds9802als_resume,
+ .id_table = apds9802als_id,
+};
+
+static int __init sensor_apds9802als_init(void)
+{
+ return i2c_add_driver(&apds9802als_driver);
+}
+
+static void __exit sensor_apds9802als_exit(void)
+{
+ i2c_del_driver(&apds9802als_driver);
+}
+module_init(sensor_apds9802als_init);
+module_exit(sensor_apds9802als_exit);
+
+MODULE_AUTHOR("Anantha Narayanan <Anantha.Narayanan@intel.com");
+MODULE_DESCRIPTION("Avago apds9802als ALS Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c
new file mode 100644
index 000000000000..200311fea369
--- /dev/null
+++ b/drivers/misc/apds990x.c
@@ -0,0 +1,1295 @@
+/*
+ * This file is part of the APDS990x sensor driver.
+ * Chip is combined proximity and ambient light sensor.
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/i2c/apds990x.h>
+
+/* Register map */
+#define APDS990X_ENABLE 0x00 /* Enable of states and interrupts */
+#define APDS990X_ATIME 0x01 /* ALS ADC time */
+#define APDS990X_PTIME 0x02 /* Proximity ADC time */
+#define APDS990X_WTIME 0x03 /* Wait time */
+#define APDS990X_AILTL 0x04 /* ALS interrupt low threshold low byte */
+#define APDS990X_AILTH 0x05 /* ALS interrupt low threshold hi byte */
+#define APDS990X_AIHTL 0x06 /* ALS interrupt hi threshold low byte */
+#define APDS990X_AIHTH 0x07 /* ALS interrupt hi threshold hi byte */
+#define APDS990X_PILTL 0x08 /* Proximity interrupt low threshold low byte */
+#define APDS990X_PILTH 0x09 /* Proximity interrupt low threshold hi byte */
+#define APDS990X_PIHTL 0x0a /* Proximity interrupt hi threshold low byte */
+#define APDS990X_PIHTH 0x0b /* Proximity interrupt hi threshold hi byte */
+#define APDS990X_PERS 0x0c /* Interrupt persistence filters */
+#define APDS990X_CONFIG 0x0d /* Configuration */
+#define APDS990X_PPCOUNT 0x0e /* Proximity pulse count */
+#define APDS990X_CONTROL 0x0f /* Gain control register */
+#define APDS990X_REV 0x11 /* Revision Number */
+#define APDS990X_ID 0x12 /* Device ID */
+#define APDS990X_STATUS 0x13 /* Device status */
+#define APDS990X_CDATAL 0x14 /* Clear ADC low data register */
+#define APDS990X_CDATAH 0x15 /* Clear ADC high data register */
+#define APDS990X_IRDATAL 0x16 /* IR ADC low data register */
+#define APDS990X_IRDATAH 0x17 /* IR ADC high data register */
+#define APDS990X_PDATAL 0x18 /* Proximity ADC low data register */
+#define APDS990X_PDATAH 0x19 /* Proximity ADC high data register */
+
+/* Control */
+#define APDS990X_MAX_AGAIN 3
+
+/* Enable register */
+#define APDS990X_EN_PIEN (0x1 << 5)
+#define APDS990X_EN_AIEN (0x1 << 4)
+#define APDS990X_EN_WEN (0x1 << 3)
+#define APDS990X_EN_PEN (0x1 << 2)
+#define APDS990X_EN_AEN (0x1 << 1)
+#define APDS990X_EN_PON (0x1 << 0)
+#define APDS990X_EN_DISABLE_ALL 0
+
+/* Status register */
+#define APDS990X_ST_PINT (0x1 << 5)
+#define APDS990X_ST_AINT (0x1 << 4)
+
+/* I2C access types */
+#define APDS990x_CMD_TYPE_MASK (0x03 << 5)
+#define APDS990x_CMD_TYPE_RB (0x00 << 5) /* Repeated byte */
+#define APDS990x_CMD_TYPE_INC (0x01 << 5) /* Auto increment */
+#define APDS990x_CMD_TYPE_SPE (0x03 << 5) /* Special function */
+
+#define APDS990x_ADDR_SHIFT 0
+#define APDS990x_CMD 0x80
+
+/* Interrupt ack commands */
+#define APDS990X_INT_ACK_ALS 0x6
+#define APDS990X_INT_ACK_PS 0x5
+#define APDS990X_INT_ACK_BOTH 0x7
+
+/* ptime */
+#define APDS990X_PTIME_DEFAULT 0xff /* Recommended conversion time 2.7ms*/
+
+/* wtime */
+#define APDS990X_WTIME_DEFAULT 0xee /* ~50ms wait time */
+
+#define APDS990X_TIME_TO_ADC 1024 /* One timetick as ADC count value */
+
+/* Persistence */
+#define APDS990X_APERS_SHIFT 0
+#define APDS990X_PPERS_SHIFT 4
+
+/* Supported ID:s */
+#define APDS990X_ID_0 0x0
+#define APDS990X_ID_4 0x4
+#define APDS990X_ID_29 0x29
+
+/* pgain and pdiode settings */
+#define APDS_PGAIN_1X 0x0
+#define APDS_PDIODE_IR 0x2
+
+#define APDS990X_LUX_OUTPUT_SCALE 10
+
+/* Reverse chip factors for threshold calculation */
+struct reverse_factors {
+ u32 afactor;
+ int cf1;
+ int irf1;
+ int cf2;
+ int irf2;
+};
+
+struct apds990x_chip {
+ struct apds990x_platform_data *pdata;
+ struct i2c_client *client;
+ struct mutex mutex; /* avoid parallel access */
+ struct regulator_bulk_data regs[2];
+ wait_queue_head_t wait;
+
+ int prox_en;
+ bool prox_continuous_mode;
+ bool lux_wait_fresh_res;
+
+ /* Chip parameters */
+ struct apds990x_chip_factors cf;
+ struct reverse_factors rcf;
+ u16 atime; /* als integration time */
+ u16 arate; /* als reporting rate */
+ u16 a_max_result; /* Max possible ADC value with current atime */
+ u8 again_meas; /* Gain used in last measurement */
+ u8 again_next; /* Next calculated gain */
+ u8 pgain;
+ u8 pdiode;
+ u8 pdrive;
+ u8 lux_persistence;
+ u8 prox_persistence;
+
+ u32 lux_raw;
+ u32 lux;
+ u16 lux_clear;
+ u16 lux_ir;
+ u16 lux_calib;
+ u32 lux_thres_hi;
+ u32 lux_thres_lo;
+
+ u32 prox_thres;
+ u16 prox_data;
+ u16 prox_calib;
+
+ char chipname[10];
+ u8 revision;
+};
+
+#define APDS_CALIB_SCALER 8192
+#define APDS_LUX_NEUTRAL_CALIB_VALUE (1 * APDS_CALIB_SCALER)
+#define APDS_PROX_NEUTRAL_CALIB_VALUE (1 * APDS_CALIB_SCALER)
+
+#define APDS_PROX_DEF_THRES 600
+#define APDS_PROX_HYSTERESIS 50
+#define APDS_LUX_DEF_THRES_HI 101
+#define APDS_LUX_DEF_THRES_LO 100
+#define APDS_DEFAULT_PROX_PERS 1
+
+#define APDS_TIMEOUT 2000
+#define APDS_STARTUP_DELAY 25000 /* us */
+#define APDS_RANGE 65535
+#define APDS_PROX_RANGE 1023
+#define APDS_LUX_GAIN_LO_LIMIT 100
+#define APDS_LUX_GAIN_LO_LIMIT_STRICT 25
+
+#define TIMESTEP 87 /* 2.7ms is about 87 / 32 */
+#define TIME_STEP_SCALER 32
+
+#define APDS_LUX_AVERAGING_TIME 50 /* tolerates 50/60Hz ripple */
+#define APDS_LUX_DEFAULT_RATE 200
+
+static const u8 again[] = {1, 8, 16, 120}; /* ALS gain steps */
+static const u8 ir_currents[] = {100, 50, 25, 12}; /* IRled currents in mA */
+
+/* Following two tables must match i.e 10Hz rate means 1 as persistence value */
+static const u16 arates_hz[] = {10, 5, 2, 1};
+static const u8 apersis[] = {1, 2, 4, 5};
+
+/* Regulators */
+static const char reg_vcc[] = "Vdd";
+static const char reg_vled[] = "Vled";
+
+static int apds990x_read_byte(struct apds990x_chip *chip, u8 reg, u8 *data)
+{
+ struct i2c_client *client = chip->client;
+ s32 ret;
+
+ reg &= ~APDS990x_CMD_TYPE_MASK;
+ reg |= APDS990x_CMD | APDS990x_CMD_TYPE_RB;
+
+ ret = i2c_smbus_read_byte_data(client, reg);
+ *data = ret;
+ return (int)ret;
+}
+
+static int apds990x_read_word(struct apds990x_chip *chip, u8 reg, u16 *data)
+{
+ struct i2c_client *client = chip->client;
+ s32 ret;
+
+ reg &= ~APDS990x_CMD_TYPE_MASK;
+ reg |= APDS990x_CMD | APDS990x_CMD_TYPE_INC;
+
+ ret = i2c_smbus_read_word_data(client, reg);
+ *data = ret;
+ return (int)ret;
+}
+
+static int apds990x_write_byte(struct apds990x_chip *chip, u8 reg, u8 data)
+{
+ struct i2c_client *client = chip->client;
+ s32 ret;
+
+ reg &= ~APDS990x_CMD_TYPE_MASK;
+ reg |= APDS990x_CMD | APDS990x_CMD_TYPE_RB;
+
+ ret = i2c_smbus_write_byte_data(client, reg, data);
+ return (int)ret;
+}
+
+static int apds990x_write_word(struct apds990x_chip *chip, u8 reg, u16 data)
+{
+ struct i2c_client *client = chip->client;
+ s32 ret;
+
+ reg &= ~APDS990x_CMD_TYPE_MASK;
+ reg |= APDS990x_CMD | APDS990x_CMD_TYPE_INC;
+
+ ret = i2c_smbus_write_word_data(client, reg, data);
+ return (int)ret;
+}
+
+static int apds990x_mode_on(struct apds990x_chip *chip)
+{
+ /* ALS is mandatory, proximity optional */
+ u8 reg = APDS990X_EN_AIEN | APDS990X_EN_PON | APDS990X_EN_AEN |
+ APDS990X_EN_WEN;
+
+ if (chip->prox_en)
+ reg |= APDS990X_EN_PIEN | APDS990X_EN_PEN;
+
+ return apds990x_write_byte(chip, APDS990X_ENABLE, reg);
+}
+
+static u16 apds990x_lux_to_threshold(struct apds990x_chip *chip, u32 lux)
+{
+ u32 thres;
+ u32 cpl;
+ u32 ir;
+
+ if (lux == 0)
+ return 0;
+ else if (lux == APDS_RANGE)
+ return APDS_RANGE;
+
+ /*
+ * Reported LUX value is a combination of the IR and CLEAR channel
+ * values. However, interrupt threshold is only for clear channel.
+ * This function approximates needed HW threshold value for a given
+ * LUX value in the current lightning type.
+ * IR level compared to visible light varies heavily depending on the
+ * source of the light
+ *
+ * Calculate threshold value for the next measurement period.
+ * Math: threshold = lux * cpl where
+ * cpl = atime * again / (glass_attenuation * device_factor)
+ * (count-per-lux)
+ *
+ * First remove calibration. Division by four is to avoid overflow
+ */
+ lux = lux * (APDS_CALIB_SCALER / 4) / (chip->lux_calib / 4);
+
+ /* Multiplication by 64 is to increase accuracy */
+ cpl = ((u32)chip->atime * (u32)again[chip->again_next] *
+ APDS_PARAM_SCALE * 64) / (chip->cf.ga * chip->cf.df);
+
+ thres = lux * cpl / 64;
+ /*
+ * Convert IR light from the latest result to match with
+ * new gain step. This helps to adapt with the current
+ * source of light.
+ */
+ ir = (u32)chip->lux_ir * (u32)again[chip->again_next] /
+ (u32)again[chip->again_meas];
+
+ /*
+ * Compensate count with IR light impact
+ * IAC1 > IAC2 (see apds990x_get_lux for formulas)
+ */
+ if (chip->lux_clear * APDS_PARAM_SCALE >=
+ chip->rcf.afactor * chip->lux_ir)
+ thres = (chip->rcf.cf1 * thres + chip->rcf.irf1 * ir) /
+ APDS_PARAM_SCALE;
+ else
+ thres = (chip->rcf.cf2 * thres + chip->rcf.irf2 * ir) /
+ APDS_PARAM_SCALE;
+
+ if (thres >= chip->a_max_result)
+ thres = chip->a_max_result - 1;
+ return thres;
+}
+
+static inline int apds990x_set_atime(struct apds990x_chip *chip, u32 time_ms)
+{
+ u8 reg_value;
+
+ chip->atime = time_ms;
+ /* Formula is specified in the data sheet */
+ reg_value = 256 - ((time_ms * TIME_STEP_SCALER) / TIMESTEP);
+ /* Calculate max ADC value for given integration time */
+ chip->a_max_result = (u16)(256 - reg_value) * APDS990X_TIME_TO_ADC;
+ return apds990x_write_byte(chip, APDS990X_ATIME, reg_value);
+}
+
+/* Called always with mutex locked */
+static int apds990x_refresh_pthres(struct apds990x_chip *chip, int data)
+{
+ int ret, lo, hi;
+
+ /* If the chip is not in use, don't try to access it */
+ if (pm_runtime_suspended(&chip->client->dev))
+ return 0;
+
+ if (data < chip->prox_thres) {
+ lo = 0;
+ hi = chip->prox_thres;
+ } else {
+ lo = chip->prox_thres - APDS_PROX_HYSTERESIS;
+ if (chip->prox_continuous_mode)
+ hi = chip->prox_thres;
+ else
+ hi = APDS_RANGE;
+ }
+
+ ret = apds990x_write_word(chip, APDS990X_PILTL, lo);
+ ret |= apds990x_write_word(chip, APDS990X_PIHTL, hi);
+ return ret;
+}
+
+/* Called always with mutex locked */
+static int apds990x_refresh_athres(struct apds990x_chip *chip)
+{
+ int ret;
+ /* If the chip is not in use, don't try to access it */
+ if (pm_runtime_suspended(&chip->client->dev))
+ return 0;
+
+ ret = apds990x_write_word(chip, APDS990X_AILTL,
+ apds990x_lux_to_threshold(chip, chip->lux_thres_lo));
+ ret |= apds990x_write_word(chip, APDS990X_AIHTL,
+ apds990x_lux_to_threshold(chip, chip->lux_thres_hi));
+
+ return ret;
+}
+
+/* Called always with mutex locked */
+static void apds990x_force_a_refresh(struct apds990x_chip *chip)
+{
+ /* This will force ALS interrupt after the next measurement. */
+ apds990x_write_word(chip, APDS990X_AILTL, APDS_LUX_DEF_THRES_LO);
+ apds990x_write_word(chip, APDS990X_AIHTL, APDS_LUX_DEF_THRES_HI);
+}
+
+/* Called always with mutex locked */
+static void apds990x_force_p_refresh(struct apds990x_chip *chip)
+{
+ /* This will force proximity interrupt after the next measurement. */
+ apds990x_write_word(chip, APDS990X_PILTL, APDS_PROX_DEF_THRES - 1);
+ apds990x_write_word(chip, APDS990X_PIHTL, APDS_PROX_DEF_THRES);
+}
+
+/* Called always with mutex locked */
+static int apds990x_calc_again(struct apds990x_chip *chip)
+{
+ int curr_again = chip->again_meas;
+ int next_again = chip->again_meas;
+ int ret = 0;
+
+ /* Calculate suitable als gain */
+ if (chip->lux_clear == chip->a_max_result)
+ next_again -= 2; /* ALS saturated. Decrease gain by 2 steps */
+ else if (chip->lux_clear > chip->a_max_result / 2)
+ next_again--;
+ else if (chip->lux_clear < APDS_LUX_GAIN_LO_LIMIT_STRICT)
+ next_again += 2; /* Too dark. Increase gain by 2 steps */
+ else if (chip->lux_clear < APDS_LUX_GAIN_LO_LIMIT)
+ next_again++;
+
+ /* Limit gain to available range */
+ if (next_again < 0)
+ next_again = 0;
+ else if (next_again > APDS990X_MAX_AGAIN)
+ next_again = APDS990X_MAX_AGAIN;
+
+ /* Let's check can we trust the measured result */
+ if (chip->lux_clear == chip->a_max_result)
+ /* Result can be totally garbage due to saturation */
+ ret = -ERANGE;
+ else if (next_again != curr_again &&
+ chip->lux_clear < APDS_LUX_GAIN_LO_LIMIT_STRICT)
+ /*
+ * Gain is changed and measurement result is very small.
+ * Result can be totally garbage due to underflow
+ */
+ ret = -ERANGE;
+
+ chip->again_next = next_again;
+ apds990x_write_byte(chip, APDS990X_CONTROL,
+ (chip->pdrive << 6) |
+ (chip->pdiode << 4) |
+ (chip->pgain << 2) |
+ (chip->again_next << 0));
+
+ /*
+ * Error means bad result -> re-measurement is needed. The forced
+ * refresh uses fastest possible persistence setting to get result
+ * as soon as possible.
+ */
+ if (ret < 0)
+ apds990x_force_a_refresh(chip);
+ else
+ apds990x_refresh_athres(chip);
+
+ return ret;
+}
+
+/* Called always with mutex locked */
+static int apds990x_get_lux(struct apds990x_chip *chip, int clear, int ir)
+{
+ int iac, iac1, iac2; /* IR adjusted counts */
+ u32 lpc; /* Lux per count */
+
+ /* Formulas:
+ * iac1 = CF1 * CLEAR_CH - IRF1 * IR_CH
+ * iac2 = CF2 * CLEAR_CH - IRF2 * IR_CH
+ */
+ iac1 = (chip->cf.cf1 * clear - chip->cf.irf1 * ir) / APDS_PARAM_SCALE;
+ iac2 = (chip->cf.cf2 * clear - chip->cf.irf2 * ir) / APDS_PARAM_SCALE;
+
+ iac = max(iac1, iac2);
+ iac = max(iac, 0);
+
+ lpc = APDS990X_LUX_OUTPUT_SCALE * (chip->cf.df * chip->cf.ga) /
+ (u32)(again[chip->again_meas] * (u32)chip->atime);
+
+ return (iac * lpc) / APDS_PARAM_SCALE;
+}
+
+static int apds990x_ack_int(struct apds990x_chip *chip, u8 mode)
+{
+ struct i2c_client *client = chip->client;
+ s32 ret;
+ u8 reg = APDS990x_CMD | APDS990x_CMD_TYPE_SPE;
+
+ switch (mode & (APDS990X_ST_AINT | APDS990X_ST_PINT)) {
+ case APDS990X_ST_AINT:
+ reg |= APDS990X_INT_ACK_ALS;
+ break;
+ case APDS990X_ST_PINT:
+ reg |= APDS990X_INT_ACK_PS;
+ break;
+ default:
+ reg |= APDS990X_INT_ACK_BOTH;
+ break;
+ }
+
+ ret = i2c_smbus_read_byte_data(client, reg);
+ return (int)ret;
+}
+
+static irqreturn_t apds990x_irq(int irq, void *data)
+{
+ struct apds990x_chip *chip = data;
+ u8 status;
+
+ apds990x_read_byte(chip, APDS990X_STATUS, &status);
+ apds990x_ack_int(chip, status);
+
+ mutex_lock(&chip->mutex);
+ if (!pm_runtime_suspended(&chip->client->dev)) {
+ if (status & APDS990X_ST_AINT) {
+ apds990x_read_word(chip, APDS990X_CDATAL,
+ &chip->lux_clear);
+ apds990x_read_word(chip, APDS990X_IRDATAL,
+ &chip->lux_ir);
+ /* Store used gain for calculations */
+ chip->again_meas = chip->again_next;
+
+ chip->lux_raw = apds990x_get_lux(chip,
+ chip->lux_clear,
+ chip->lux_ir);
+
+ if (apds990x_calc_again(chip) == 0) {
+ /* Result is valid */
+ chip->lux = chip->lux_raw;
+ chip->lux_wait_fresh_res = false;
+ wake_up(&chip->wait);
+ sysfs_notify(&chip->client->dev.kobj,
+ NULL, "lux0_input");
+ }
+ }
+
+ if ((status & APDS990X_ST_PINT) && chip->prox_en) {
+ u16 clr_ch;
+
+ apds990x_read_word(chip, APDS990X_CDATAL, &clr_ch);
+ /*
+ * If ALS channel is saturated at min gain,
+ * proximity gives false posivite values.
+ * Just ignore them.
+ */
+ if (chip->again_meas == 0 &&
+ clr_ch == chip->a_max_result)
+ chip->prox_data = 0;
+ else
+ apds990x_read_word(chip,
+ APDS990X_PDATAL,
+ &chip->prox_data);
+
+ apds990x_refresh_pthres(chip, chip->prox_data);
+ if (chip->prox_data < chip->prox_thres)
+ chip->prox_data = 0;
+ else if (!chip->prox_continuous_mode)
+ chip->prox_data = APDS_PROX_RANGE;
+ sysfs_notify(&chip->client->dev.kobj,
+ NULL, "prox0_raw");
+ }
+ }
+ mutex_unlock(&chip->mutex);
+ return IRQ_HANDLED;
+}
+
+static int apds990x_configure(struct apds990x_chip *chip)
+{
+ /* It is recommended to use disabled mode during these operations */
+ apds990x_write_byte(chip, APDS990X_ENABLE, APDS990X_EN_DISABLE_ALL);
+
+ /* conversion and wait times for different state machince states */
+ apds990x_write_byte(chip, APDS990X_PTIME, APDS990X_PTIME_DEFAULT);
+ apds990x_write_byte(chip, APDS990X_WTIME, APDS990X_WTIME_DEFAULT);
+ apds990x_set_atime(chip, APDS_LUX_AVERAGING_TIME);
+
+ apds990x_write_byte(chip, APDS990X_CONFIG, 0);
+
+ /* Persistence levels */
+ apds990x_write_byte(chip, APDS990X_PERS,
+ (chip->lux_persistence << APDS990X_APERS_SHIFT) |
+ (chip->prox_persistence << APDS990X_PPERS_SHIFT));
+
+ apds990x_write_byte(chip, APDS990X_PPCOUNT, chip->pdata->ppcount);
+
+ /* Start with relatively small gain */
+ chip->again_meas = 1;
+ chip->again_next = 1;
+ apds990x_write_byte(chip, APDS990X_CONTROL,
+ (chip->pdrive << 6) |
+ (chip->pdiode << 4) |
+ (chip->pgain << 2) |
+ (chip->again_next << 0));
+ return 0;
+}
+
+static int apds990x_detect(struct apds990x_chip *chip)
+{
+ struct i2c_client *client = chip->client;
+ int ret;
+ u8 id;
+
+ ret = apds990x_read_byte(chip, APDS990X_ID, &id);
+ if (ret < 0) {
+ dev_err(&client->dev, "ID read failed\n");
+ return ret;
+ }
+
+ ret = apds990x_read_byte(chip, APDS990X_REV, &chip->revision);
+ if (ret < 0) {
+ dev_err(&client->dev, "REV read failed\n");
+ return ret;
+ }
+
+ switch (id) {
+ case APDS990X_ID_0:
+ case APDS990X_ID_4:
+ case APDS990X_ID_29:
+ snprintf(chip->chipname, sizeof(chip->chipname), "APDS-990x");
+ break;
+ default:
+ ret = -ENODEV;
+ break;
+ }
+ return ret;
+}
+
+static int apds990x_chip_on(struct apds990x_chip *chip)
+{
+ int err = regulator_bulk_enable(ARRAY_SIZE(chip->regs),
+ chip->regs);
+ if (err < 0)
+ return err;
+
+ usleep_range(APDS_STARTUP_DELAY, 2 * APDS_STARTUP_DELAY);
+
+ /* Refresh all configs in case of regulators were off */
+ chip->prox_data = 0;
+ apds990x_configure(chip);
+ apds990x_mode_on(chip);
+ return 0;
+}
+
+static int apds990x_chip_off(struct apds990x_chip *chip)
+{
+ apds990x_write_byte(chip, APDS990X_ENABLE, APDS990X_EN_DISABLE_ALL);
+ regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
+ return 0;
+}
+
+static ssize_t apds990x_lux_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ ssize_t ret;
+ u32 result;
+ long timeout;
+
+ if (pm_runtime_suspended(dev))
+ return -EIO;
+
+ timeout = wait_event_interruptible_timeout(chip->wait,
+ !chip->lux_wait_fresh_res,
+ msecs_to_jiffies(APDS_TIMEOUT));
+ if (!timeout)
+ return -EIO;
+
+ mutex_lock(&chip->mutex);
+ result = (chip->lux * chip->lux_calib) / APDS_CALIB_SCALER;
+ if (result > (APDS_RANGE * APDS990X_LUX_OUTPUT_SCALE))
+ result = APDS_RANGE * APDS990X_LUX_OUTPUT_SCALE;
+
+ ret = sprintf(buf, "%d.%d\n",
+ result / APDS990X_LUX_OUTPUT_SCALE,
+ result % APDS990X_LUX_OUTPUT_SCALE);
+ mutex_unlock(&chip->mutex);
+ return ret;
+}
+
+static DEVICE_ATTR(lux0_input, S_IRUGO, apds990x_lux_show, NULL);
+
+static ssize_t apds990x_lux_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", APDS_RANGE);
+}
+
+static DEVICE_ATTR(lux0_sensor_range, S_IRUGO, apds990x_lux_range_show, NULL);
+
+static ssize_t apds990x_lux_calib_format_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", APDS_CALIB_SCALER);
+}
+
+static DEVICE_ATTR(lux0_calibscale_default, S_IRUGO,
+ apds990x_lux_calib_format_show, NULL);
+
+static ssize_t apds990x_lux_calib_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", chip->lux_calib);
+}
+
+static ssize_t apds990x_lux_calib_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ unsigned long value;
+
+ if (strict_strtoul(buf, 0, &value))
+ return -EINVAL;
+
+ if (chip->lux_calib > APDS_RANGE)
+ return -EINVAL;
+
+ chip->lux_calib = value;
+
+ return len;
+}
+
+static DEVICE_ATTR(lux0_calibscale, S_IRUGO | S_IWUSR, apds990x_lux_calib_show,
+ apds990x_lux_calib_store);
+
+static ssize_t apds990x_rate_avail(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i;
+ int pos = 0;
+ for (i = 0; i < ARRAY_SIZE(arates_hz); i++)
+ pos += sprintf(buf + pos, "%d ", arates_hz[i]);
+ sprintf(buf + pos - 1, "\n");
+ return pos;
+}
+
+static ssize_t apds990x_rate_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", chip->arate);
+}
+
+static int apds990x_set_arate(struct apds990x_chip *chip, int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(arates_hz); i++)
+ if (rate >= arates_hz[i])
+ break;
+
+ if (i == ARRAY_SIZE(arates_hz))
+ return -EINVAL;
+
+ /* Pick up corresponding persistence value */
+ chip->lux_persistence = apersis[i];
+ chip->arate = arates_hz[i];
+
+ /* If the chip is not in use, don't try to access it */
+ if (pm_runtime_suspended(&chip->client->dev))
+ return 0;
+
+ /* Persistence levels */
+ return apds990x_write_byte(chip, APDS990X_PERS,
+ (chip->lux_persistence << APDS990X_APERS_SHIFT) |
+ (chip->prox_persistence << APDS990X_PPERS_SHIFT));
+}
+
+static ssize_t apds990x_rate_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ unsigned long value;
+ int ret;
+
+ if (strict_strtoul(buf, 0, &value))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ ret = apds990x_set_arate(chip, value);
+ mutex_unlock(&chip->mutex);
+
+ if (ret < 0)
+ return ret;
+ return len;
+}
+
+static DEVICE_ATTR(lux0_rate_avail, S_IRUGO, apds990x_rate_avail, NULL);
+
+static DEVICE_ATTR(lux0_rate, S_IRUGO | S_IWUSR, apds990x_rate_show,
+ apds990x_rate_store);
+
+static ssize_t apds990x_prox_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ if (pm_runtime_suspended(dev) || !chip->prox_en)
+ return -EIO;
+
+ mutex_lock(&chip->mutex);
+ ret = sprintf(buf, "%d\n", chip->prox_data);
+ mutex_unlock(&chip->mutex);
+ return ret;
+}
+
+static DEVICE_ATTR(prox0_raw, S_IRUGO, apds990x_prox_show, NULL);
+
+static ssize_t apds990x_prox_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", APDS_PROX_RANGE);
+}
+
+static DEVICE_ATTR(prox0_sensor_range, S_IRUGO, apds990x_prox_range_show, NULL);
+
+static ssize_t apds990x_prox_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", chip->prox_en);
+}
+
+static ssize_t apds990x_prox_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ unsigned long value;
+
+ if (strict_strtoul(buf, 0, &value))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+
+ if (!chip->prox_en)
+ chip->prox_data = 0;
+
+ if (value)
+ chip->prox_en++;
+ else if (chip->prox_en > 0)
+ chip->prox_en--;
+
+ if (!pm_runtime_suspended(dev))
+ apds990x_mode_on(chip);
+ mutex_unlock(&chip->mutex);
+ return len;
+}
+
+static DEVICE_ATTR(prox0_raw_en, S_IRUGO | S_IWUSR, apds990x_prox_enable_show,
+ apds990x_prox_enable_store);
+
+static const char reporting_modes[][9] = {"trigger", "periodic"};
+
+static ssize_t apds990x_prox_reporting_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n",
+ reporting_modes[!!chip->prox_continuous_mode]);
+}
+
+static ssize_t apds990x_prox_reporting_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+
+ if (sysfs_streq(buf, reporting_modes[0]))
+ chip->prox_continuous_mode = 0;
+ else if (sysfs_streq(buf, reporting_modes[1]))
+ chip->prox_continuous_mode = 1;
+ else
+ return -EINVAL;
+ return len;
+}
+
+static DEVICE_ATTR(prox0_reporting_mode, S_IRUGO | S_IWUSR,
+ apds990x_prox_reporting_mode_show,
+ apds990x_prox_reporting_mode_store);
+
+static ssize_t apds990x_prox_reporting_avail_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s %s\n", reporting_modes[0], reporting_modes[1]);
+}
+
+static DEVICE_ATTR(prox0_reporting_mode_avail, S_IRUGO | S_IWUSR,
+ apds990x_prox_reporting_avail_show, NULL);
+
+
+static ssize_t apds990x_lux_thresh_above_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", chip->lux_thres_hi);
+}
+
+static ssize_t apds990x_lux_thresh_below_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", chip->lux_thres_lo);
+}
+
+static ssize_t apds990x_set_lux_thresh(struct apds990x_chip *chip, u32 *target,
+ const char *buf)
+{
+ int ret = 0;
+ unsigned long thresh;
+
+ if (strict_strtoul(buf, 0, &thresh))
+ return -EINVAL;
+
+ if (thresh > APDS_RANGE)
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ *target = thresh;
+ /*
+ * Don't update values in HW if we are still waiting for
+ * first interrupt to come after device handle open call.
+ */
+ if (!chip->lux_wait_fresh_res)
+ apds990x_refresh_athres(chip);
+ mutex_unlock(&chip->mutex);
+ return ret;
+
+}
+
+static ssize_t apds990x_lux_thresh_above_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ int ret = apds990x_set_lux_thresh(chip, &chip->lux_thres_hi, buf);
+ if (ret < 0)
+ return ret;
+ return len;
+}
+
+static ssize_t apds990x_lux_thresh_below_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ int ret = apds990x_set_lux_thresh(chip, &chip->lux_thres_lo, buf);
+ if (ret < 0)
+ return ret;
+ return len;
+}
+
+static DEVICE_ATTR(lux0_thresh_above_value, S_IRUGO | S_IWUSR,
+ apds990x_lux_thresh_above_show,
+ apds990x_lux_thresh_above_store);
+
+static DEVICE_ATTR(lux0_thresh_below_value, S_IRUGO | S_IWUSR,
+ apds990x_lux_thresh_below_show,
+ apds990x_lux_thresh_below_store);
+
+static ssize_t apds990x_prox_threshold_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", chip->prox_thres);
+}
+
+static ssize_t apds990x_prox_threshold_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ unsigned long value;
+
+ if (strict_strtoul(buf, 0, &value))
+ return -EINVAL;
+
+ if ((value > APDS_RANGE) || (value == 0) ||
+ (value < APDS_PROX_HYSTERESIS))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ chip->prox_thres = value;
+
+ apds990x_force_p_refresh(chip);
+ mutex_unlock(&chip->mutex);
+ return len;
+}
+
+static DEVICE_ATTR(prox0_thresh_above_value, S_IRUGO | S_IWUSR,
+ apds990x_prox_threshold_show,
+ apds990x_prox_threshold_store);
+
+static ssize_t apds990x_power_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", !pm_runtime_suspended(dev));
+ return 0;
+}
+
+static ssize_t apds990x_power_state_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ unsigned long value;
+
+ if (strict_strtoul(buf, 0, &value))
+ return -EINVAL;
+ if (value) {
+ pm_runtime_get_sync(dev);
+ mutex_lock(&chip->mutex);
+ chip->lux_wait_fresh_res = true;
+ apds990x_force_a_refresh(chip);
+ apds990x_force_p_refresh(chip);
+ mutex_unlock(&chip->mutex);
+ } else {
+ if (!pm_runtime_suspended(dev))
+ pm_runtime_put(dev);
+ }
+ return len;
+}
+
+static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
+ apds990x_power_state_show,
+ apds990x_power_state_store);
+
+static ssize_t apds990x_chip_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct apds990x_chip *chip = dev_get_drvdata(dev);
+ return sprintf(buf, "%s %d\n", chip->chipname, chip->revision);
+}
+
+static DEVICE_ATTR(chip_id, S_IRUGO, apds990x_chip_id_show, NULL);
+
+static struct attribute *sysfs_attrs_ctrl[] = {
+ &dev_attr_lux0_calibscale.attr,
+ &dev_attr_lux0_calibscale_default.attr,
+ &dev_attr_lux0_input.attr,
+ &dev_attr_lux0_sensor_range.attr,
+ &dev_attr_lux0_rate.attr,
+ &dev_attr_lux0_rate_avail.attr,
+ &dev_attr_lux0_thresh_above_value.attr,
+ &dev_attr_lux0_thresh_below_value.attr,
+ &dev_attr_prox0_raw_en.attr,
+ &dev_attr_prox0_raw.attr,
+ &dev_attr_prox0_sensor_range.attr,
+ &dev_attr_prox0_thresh_above_value.attr,
+ &dev_attr_prox0_reporting_mode.attr,
+ &dev_attr_prox0_reporting_mode_avail.attr,
+ &dev_attr_chip_id.attr,
+ &dev_attr_power_state.attr,
+ NULL
+};
+
+static struct attribute_group apds990x_attribute_group[] = {
+ {.attrs = sysfs_attrs_ctrl },
+};
+
+static int __devinit apds990x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct apds990x_chip *chip;
+ int err;
+
+ chip = kzalloc(sizeof *chip, GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, chip);
+ chip->client = client;
+
+ init_waitqueue_head(&chip->wait);
+ mutex_init(&chip->mutex);
+ chip->pdata = client->dev.platform_data;
+
+ if (chip->pdata == NULL) {
+ dev_err(&client->dev, "platform data is mandatory\n");
+ err = -EINVAL;
+ goto fail1;
+ }
+
+ if (chip->pdata->cf.ga == 0) {
+ /* set uncovered sensor default parameters */
+ chip->cf.ga = 1966; /* 0.48 * APDS_PARAM_SCALE */
+ chip->cf.cf1 = 4096; /* 1.00 * APDS_PARAM_SCALE */
+ chip->cf.irf1 = 9134; /* 2.23 * APDS_PARAM_SCALE */
+ chip->cf.cf2 = 2867; /* 0.70 * APDS_PARAM_SCALE */
+ chip->cf.irf2 = 5816; /* 1.42 * APDS_PARAM_SCALE */
+ chip->cf.df = 52;
+ } else {
+ chip->cf = chip->pdata->cf;
+ }
+
+ /* precalculate inverse chip factors for threshold control */
+ chip->rcf.afactor =
+ (chip->cf.irf1 - chip->cf.irf2) * APDS_PARAM_SCALE /
+ (chip->cf.cf1 - chip->cf.cf2);
+ chip->rcf.cf1 = APDS_PARAM_SCALE * APDS_PARAM_SCALE /
+ chip->cf.cf1;
+ chip->rcf.irf1 = chip->cf.irf1 * APDS_PARAM_SCALE /
+ chip->cf.cf1;
+ chip->rcf.cf2 = APDS_PARAM_SCALE * APDS_PARAM_SCALE /
+ chip->cf.cf2;
+ chip->rcf.irf2 = chip->cf.irf2 * APDS_PARAM_SCALE /
+ chip->cf.cf2;
+
+ /* Set something to start with */
+ chip->lux_thres_hi = APDS_LUX_DEF_THRES_HI;
+ chip->lux_thres_lo = APDS_LUX_DEF_THRES_LO;
+ chip->lux_calib = APDS_LUX_NEUTRAL_CALIB_VALUE;
+
+ chip->prox_thres = APDS_PROX_DEF_THRES;
+ chip->pdrive = chip->pdata->pdrive;
+ chip->pdiode = APDS_PDIODE_IR;
+ chip->pgain = APDS_PGAIN_1X;
+ chip->prox_calib = APDS_PROX_NEUTRAL_CALIB_VALUE;
+ chip->prox_persistence = APDS_DEFAULT_PROX_PERS;
+ chip->prox_continuous_mode = false;
+
+ chip->regs[0].supply = reg_vcc;
+ chip->regs[1].supply = reg_vled;
+
+ err = regulator_bulk_get(&client->dev,
+ ARRAY_SIZE(chip->regs), chip->regs);
+ if (err < 0) {
+ dev_err(&client->dev, "Cannot get regulators\n");
+ goto fail1;
+ }
+
+ err = regulator_bulk_enable(ARRAY_SIZE(chip->regs), chip->regs);
+ if (err < 0) {
+ dev_err(&client->dev, "Cannot enable regulators\n");
+ goto fail2;
+ }
+
+ usleep_range(APDS_STARTUP_DELAY, 2 * APDS_STARTUP_DELAY);
+
+ err = apds990x_detect(chip);
+ if (err < 0) {
+ dev_err(&client->dev, "APDS990X not found\n");
+ goto fail3;
+ }
+
+ pm_runtime_set_active(&client->dev);
+
+ apds990x_configure(chip);
+ apds990x_set_arate(chip, APDS_LUX_DEFAULT_RATE);
+ apds990x_mode_on(chip);
+
+ pm_runtime_enable(&client->dev);
+
+ if (chip->pdata->setup_resources) {
+ err = chip->pdata->setup_resources();
+ if (err) {
+ err = -EINVAL;
+ goto fail3;
+ }
+ }
+
+ err = sysfs_create_group(&chip->client->dev.kobj,
+ apds990x_attribute_group);
+ if (err < 0) {
+ dev_err(&chip->client->dev, "Sysfs registration failed\n");
+ goto fail4;
+ }
+
+ err = request_threaded_irq(client->irq, NULL,
+ apds990x_irq,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW |
+ IRQF_ONESHOT,
+ "apds990x", chip);
+ if (err) {
+ dev_err(&client->dev, "could not get IRQ %d\n",
+ client->irq);
+ goto fail5;
+ }
+ return err;
+fail5:
+ sysfs_remove_group(&chip->client->dev.kobj,
+ &apds990x_attribute_group[0]);
+fail4:
+ if (chip->pdata && chip->pdata->release_resources)
+ chip->pdata->release_resources();
+fail3:
+ regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
+fail2:
+ regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs);
+fail1:
+ kfree(chip);
+ return err;
+}
+
+static int __devexit apds990x_remove(struct i2c_client *client)
+{
+ struct apds990x_chip *chip = i2c_get_clientdata(client);
+
+ free_irq(client->irq, chip);
+ sysfs_remove_group(&chip->client->dev.kobj,
+ apds990x_attribute_group);
+
+ if (chip->pdata && chip->pdata->release_resources)
+ chip->pdata->release_resources();
+
+ if (!pm_runtime_suspended(&client->dev))
+ apds990x_chip_off(chip);
+
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
+ regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs);
+
+ kfree(chip);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int apds990x_suspend(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct apds990x_chip *chip = i2c_get_clientdata(client);
+
+ apds990x_chip_off(chip);
+ return 0;
+}
+
+static int apds990x_resume(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct apds990x_chip *chip = i2c_get_clientdata(client);
+
+ /*
+ * If we were enabled at suspend time, it is expected
+ * everything works nice and smoothly. Chip_on is enough
+ */
+ apds990x_chip_on(chip);
+
+ return 0;
+}
+#else
+#define apds990x_suspend NULL
+#define apds990x_resume NULL
+#define apds990x_shutdown NULL
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int apds990x_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct apds990x_chip *chip = i2c_get_clientdata(client);
+
+ apds990x_chip_off(chip);
+ return 0;
+}
+
+static int apds990x_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct apds990x_chip *chip = i2c_get_clientdata(client);
+
+ apds990x_chip_on(chip);
+ return 0;
+}
+
+#endif
+
+static const struct i2c_device_id apds990x_id[] = {
+ {"apds990x", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, apds990x_id);
+
+static const struct dev_pm_ops apds990x_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(apds990x_suspend, apds990x_resume)
+ SET_RUNTIME_PM_OPS(apds990x_runtime_suspend,
+ apds990x_runtime_resume,
+ NULL)
+};
+
+static struct i2c_driver apds990x_driver = {
+ .driver = {
+ .name = "apds990x",
+ .owner = THIS_MODULE,
+ .pm = &apds990x_pm_ops,
+ },
+ .probe = apds990x_probe,
+ .remove = __devexit_p(apds990x_remove),
+ .id_table = apds990x_id,
+};
+
+static int __init apds990x_init(void)
+{
+ return i2c_add_driver(&apds990x_driver);
+}
+
+static void __exit apds990x_exit(void)
+{
+ i2c_del_driver(&apds990x_driver);
+}
+
+MODULE_DESCRIPTION("APDS990X combined ALS and proximity sensor");
+MODULE_AUTHOR("Samu Onkalo, Nokia Corporation");
+MODULE_LICENSE("GPL v2");
+
+module_init(apds990x_init);
+module_exit(apds990x_exit);
diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c
new file mode 100644
index 000000000000..cee632e645e1
--- /dev/null
+++ b/drivers/misc/bh1770glc.c
@@ -0,0 +1,1413 @@
+/*
+ * This file is part of the ROHM BH1770GLC / OSRAM SFH7770 sensor driver.
+ * Chip is combined proximity and ambient light sensor.
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/i2c/bh1770glc.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+
+#define BH1770_ALS_CONTROL 0x80 /* ALS operation mode control */
+#define BH1770_PS_CONTROL 0x81 /* PS operation mode control */
+#define BH1770_I_LED 0x82 /* active LED and LED1, LED2 current */
+#define BH1770_I_LED3 0x83 /* LED3 current setting */
+#define BH1770_ALS_PS_MEAS 0x84 /* Forced mode trigger */
+#define BH1770_PS_MEAS_RATE 0x85 /* PS meas. rate at stand alone mode */
+#define BH1770_ALS_MEAS_RATE 0x86 /* ALS meas. rate at stand alone mode */
+#define BH1770_PART_ID 0x8a /* Part number and revision ID */
+#define BH1770_MANUFACT_ID 0x8b /* Manufacturerer ID */
+#define BH1770_ALS_DATA_0 0x8c /* ALS DATA low byte */
+#define BH1770_ALS_DATA_1 0x8d /* ALS DATA high byte */
+#define BH1770_ALS_PS_STATUS 0x8e /* Measurement data and int status */
+#define BH1770_PS_DATA_LED1 0x8f /* PS data from LED1 */
+#define BH1770_PS_DATA_LED2 0x90 /* PS data from LED2 */
+#define BH1770_PS_DATA_LED3 0x91 /* PS data from LED3 */
+#define BH1770_INTERRUPT 0x92 /* Interrupt setting */
+#define BH1770_PS_TH_LED1 0x93 /* PS interrupt threshold for LED1 */
+#define BH1770_PS_TH_LED2 0x94 /* PS interrupt threshold for LED2 */
+#define BH1770_PS_TH_LED3 0x95 /* PS interrupt threshold for LED3 */
+#define BH1770_ALS_TH_UP_0 0x96 /* ALS upper threshold low byte */
+#define BH1770_ALS_TH_UP_1 0x97 /* ALS upper threshold high byte */
+#define BH1770_ALS_TH_LOW_0 0x98 /* ALS lower threshold low byte */
+#define BH1770_ALS_TH_LOW_1 0x99 /* ALS lower threshold high byte */
+
+/* MANUFACT_ID */
+#define BH1770_MANUFACT_ROHM 0x01
+#define BH1770_MANUFACT_OSRAM 0x03
+
+/* PART_ID */
+#define BH1770_PART 0x90
+#define BH1770_PART_MASK 0xf0
+#define BH1770_REV_MASK 0x0f
+#define BH1770_REV_SHIFT 0
+#define BH1770_REV_0 0x00
+#define BH1770_REV_1 0x01
+
+/* Operating modes for both */
+#define BH1770_STANDBY 0x00
+#define BH1770_FORCED 0x02
+#define BH1770_STANDALONE 0x03
+#define BH1770_SWRESET (0x01 << 2)
+
+#define BH1770_PS_TRIG_MEAS (1 << 0)
+#define BH1770_ALS_TRIG_MEAS (1 << 1)
+
+/* Interrupt control */
+#define BH1770_INT_OUTPUT_MODE (1 << 3) /* 0 = latched */
+#define BH1770_INT_POLARITY (1 << 2) /* 1 = active high */
+#define BH1770_INT_ALS_ENA (1 << 1)
+#define BH1770_INT_PS_ENA (1 << 0)
+
+/* Interrupt status */
+#define BH1770_INT_LED1_DATA (1 << 0)
+#define BH1770_INT_LED1_INT (1 << 1)
+#define BH1770_INT_LED2_DATA (1 << 2)
+#define BH1770_INT_LED2_INT (1 << 3)
+#define BH1770_INT_LED3_DATA (1 << 4)
+#define BH1770_INT_LED3_INT (1 << 5)
+#define BH1770_INT_LEDS_INT ((1 << 1) | (1 << 3) | (1 << 5))
+#define BH1770_INT_ALS_DATA (1 << 6)
+#define BH1770_INT_ALS_INT (1 << 7)
+
+/* Led channels */
+#define BH1770_LED1 0x00
+
+#define BH1770_DISABLE 0
+#define BH1770_ENABLE 1
+#define BH1770_PROX_CHANNELS 1
+
+#define BH1770_LUX_DEFAULT_RATE 1 /* Index to lux rate table */
+#define BH1770_PROX_DEFAULT_RATE 1 /* Direct HW value =~ 50Hz */
+#define BH1770_PROX_DEF_RATE_THRESH 6 /* Direct HW value =~ 5 Hz */
+#define BH1770_STARTUP_DELAY 50
+#define BH1770_RESET_TIME 10
+#define BH1770_TIMEOUT 2100 /* Timeout in 2.1 seconds */
+
+#define BH1770_LUX_RANGE 65535
+#define BH1770_PROX_RANGE 255
+#define BH1770_COEF_SCALER 1024
+#define BH1770_CALIB_SCALER 8192
+#define BH1770_LUX_NEUTRAL_CALIB_VALUE (1 * BH1770_CALIB_SCALER)
+#define BH1770_LUX_DEF_THRES 1000
+#define BH1770_PROX_DEF_THRES 70
+#define BH1770_PROX_DEF_ABS_THRES 100
+#define BH1770_DEFAULT_PERSISTENCE 10
+#define BH1770_PROX_MAX_PERSISTENCE 50
+#define BH1770_LUX_GA_SCALE 16384
+#define BH1770_LUX_CF_SCALE 2048 /* CF ChipFactor */
+#define BH1770_NEUTRAL_CF BH1770_LUX_CF_SCALE
+#define BH1770_LUX_CORR_SCALE 4096
+
+#define PROX_ABOVE_THRESHOLD 1
+#define PROX_BELOW_THRESHOLD 0
+
+#define PROX_IGNORE_LUX_LIMIT 500
+
+struct bh1770_chip {
+ struct bh1770_platform_data *pdata;
+ char chipname[10];
+ u8 revision;
+ struct i2c_client *client;
+ struct regulator_bulk_data regs[2];
+ struct mutex mutex; /* avoid parallel access */
+ wait_queue_head_t wait;
+
+ bool int_mode_prox;
+ bool int_mode_lux;
+ struct delayed_work prox_work;
+ u32 lux_cf; /* Chip specific factor */
+ u32 lux_ga;
+ u32 lux_calib;
+ int lux_rate_index;
+ u32 lux_corr;
+ u16 lux_data_raw;
+ u16 lux_threshold_hi;
+ u16 lux_threshold_lo;
+ u16 lux_thres_hi_onchip;
+ u16 lux_thres_lo_onchip;
+ bool lux_wait_result;
+
+ int prox_enable_count;
+ u16 prox_coef;
+ u16 prox_const;
+ int prox_rate;
+ int prox_rate_threshold;
+ u8 prox_persistence;
+ u8 prox_persistence_counter;
+ u8 prox_data;
+ u8 prox_threshold;
+ u8 prox_threshold_hw;
+ bool prox_force_update;
+ u8 prox_abs_thres;
+ u8 prox_led;
+};
+
+static const char reg_vcc[] = "Vcc";
+static const char reg_vleds[] = "Vleds";
+
+/*
+ * Supported stand alone rates in ms from chip data sheet
+ * {10, 20, 30, 40, 70, 100, 200, 500, 1000, 2000};
+ */
+static const s16 prox_rates_hz[] = {100, 50, 33, 25, 14, 10, 5, 2};
+static const s16 prox_rates_ms[] = {10, 20, 30, 40, 70, 100, 200, 500};
+
+/* Supported IR-led currents in mA */
+static const u8 prox_curr_ma[] = {5, 10, 20, 50, 100, 150, 200};
+
+/*
+ * Supported stand alone rates in ms from chip data sheet
+ * {100, 200, 500, 1000, 2000};
+ */
+static const s16 lux_rates_hz[] = {10, 5, 2, 1, 0};
+
+/*
+ * interrupt control functions are called while keeping chip->mutex
+ * excluding module probe / remove
+ */
+static inline int bh1770_lux_interrupt_control(struct bh1770_chip *chip,
+ int lux)
+{
+ chip->int_mode_lux = lux;
+ /* Set interrupt modes, interrupt active low, latched */
+ return i2c_smbus_write_byte_data(chip->client,
+ BH1770_INTERRUPT,
+ (lux << 1) | chip->int_mode_prox);
+}
+
+static inline int bh1770_prox_interrupt_control(struct bh1770_chip *chip,
+ int ps)
+{
+ chip->int_mode_prox = ps;
+ return i2c_smbus_write_byte_data(chip->client,
+ BH1770_INTERRUPT,
+ (chip->int_mode_lux << 1) | (ps << 0));
+}
+
+/* chip->mutex is always kept here */
+static int bh1770_lux_rate(struct bh1770_chip *chip, int rate_index)
+{
+ /* sysfs may call this when the chip is powered off */
+ if (pm_runtime_suspended(&chip->client->dev))
+ return 0;
+
+ /* Proper proximity response needs fastest lux rate (100ms) */
+ if (chip->prox_enable_count)
+ rate_index = 0;
+
+ return i2c_smbus_write_byte_data(chip->client,
+ BH1770_ALS_MEAS_RATE,
+ rate_index);
+}
+
+static int bh1770_prox_rate(struct bh1770_chip *chip, int mode)
+{
+ int rate;
+
+ rate = (mode == PROX_ABOVE_THRESHOLD) ?
+ chip->prox_rate_threshold : chip->prox_rate;
+
+ return i2c_smbus_write_byte_data(chip->client,
+ BH1770_PS_MEAS_RATE,
+ rate);
+}
+
+/* InfraredLED is controlled by the chip during proximity scanning */
+static inline int bh1770_led_cfg(struct bh1770_chip *chip)
+{
+ /* LED cfg, current for leds 1 and 2 */
+ return i2c_smbus_write_byte_data(chip->client,
+ BH1770_I_LED,
+ (BH1770_LED1 << 6) |
+ (BH1770_LED_5mA << 3) |
+ chip->prox_led);
+}
+
+/*
+ * Following two functions converts raw ps values from HW to normalized
+ * values. Purpose is to compensate differences between different sensor
+ * versions and variants so that result means about the same between
+ * versions.
+ */
+static inline u8 bh1770_psraw_to_adjusted(struct bh1770_chip *chip, u8 psraw)
+{
+ u16 adjusted;
+ adjusted = (u16)(((u32)(psraw + chip->prox_const) * chip->prox_coef) /
+ BH1770_COEF_SCALER);
+ if (adjusted > BH1770_PROX_RANGE)
+ adjusted = BH1770_PROX_RANGE;
+ return adjusted;
+}
+
+static inline u8 bh1770_psadjusted_to_raw(struct bh1770_chip *chip, u8 ps)
+{
+ u16 raw;
+
+ raw = (((u32)ps * BH1770_COEF_SCALER) / chip->prox_coef);
+ if (raw > chip->prox_const)
+ raw = raw - chip->prox_const;
+ else
+ raw = 0;
+ return raw;
+}
+
+/*
+ * Following two functions converts raw lux values from HW to normalized
+ * values. Purpose is to compensate differences between different sensor
+ * versions and variants so that result means about the same between
+ * versions. Chip->mutex is kept when this is called.
+ */
+static int bh1770_prox_set_threshold(struct bh1770_chip *chip)
+{
+ u8 tmp = 0;
+
+ /* sysfs may call this when the chip is powered off */
+ if (pm_runtime_suspended(&chip->client->dev))
+ return 0;
+
+ tmp = bh1770_psadjusted_to_raw(chip, chip->prox_threshold);
+ chip->prox_threshold_hw = tmp;
+
+ return i2c_smbus_write_byte_data(chip->client, BH1770_PS_TH_LED1,
+ tmp);
+}
+
+static inline u16 bh1770_lux_raw_to_adjusted(struct bh1770_chip *chip, u16 raw)
+{
+ u32 lux;
+ lux = ((u32)raw * chip->lux_corr) / BH1770_LUX_CORR_SCALE;
+ return min(lux, (u32)BH1770_LUX_RANGE);
+}
+
+static inline u16 bh1770_lux_adjusted_to_raw(struct bh1770_chip *chip,
+ u16 adjusted)
+{
+ return (u32)adjusted * BH1770_LUX_CORR_SCALE / chip->lux_corr;
+}
+
+/* chip->mutex is kept when this is called */
+static int bh1770_lux_update_thresholds(struct bh1770_chip *chip,
+ u16 threshold_hi, u16 threshold_lo)
+{
+ u8 data[4];
+ int ret;
+
+ /* sysfs may call this when the chip is powered off */
+ if (pm_runtime_suspended(&chip->client->dev))
+ return 0;
+
+ /*
+ * Compensate threshold values with the correction factors if not
+ * set to minimum or maximum.
+ * Min & max values disables interrupts.
+ */
+ if (threshold_hi != BH1770_LUX_RANGE && threshold_hi != 0)
+ threshold_hi = bh1770_lux_adjusted_to_raw(chip, threshold_hi);
+
+ if (threshold_lo != BH1770_LUX_RANGE && threshold_lo != 0)
+ threshold_lo = bh1770_lux_adjusted_to_raw(chip, threshold_lo);
+
+ if (chip->lux_thres_hi_onchip == threshold_hi &&
+ chip->lux_thres_lo_onchip == threshold_lo)
+ return 0;
+
+ chip->lux_thres_hi_onchip = threshold_hi;
+ chip->lux_thres_lo_onchip = threshold_lo;
+
+ data[0] = threshold_hi;
+ data[1] = threshold_hi >> 8;
+ data[2] = threshold_lo;
+ data[3] = threshold_lo >> 8;
+
+ ret = i2c_smbus_write_i2c_block_data(chip->client,
+ BH1770_ALS_TH_UP_0,
+ ARRAY_SIZE(data),
+ data);
+ return ret;
+}
+
+static int bh1770_lux_get_result(struct bh1770_chip *chip)
+{
+ u16 data;
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(chip->client, BH1770_ALS_DATA_0);
+ if (ret < 0)
+ return ret;
+
+ data = ret & 0xff;
+ ret = i2c_smbus_read_byte_data(chip->client, BH1770_ALS_DATA_1);
+ if (ret < 0)
+ return ret;
+
+ chip->lux_data_raw = data | ((ret & 0xff) << 8);
+
+ return 0;
+}
+
+/* Calculate correction value which contains chip and device specific parts */
+static u32 bh1770_get_corr_value(struct bh1770_chip *chip)
+{
+ u32 tmp;
+ /* Impact of glass attenuation correction */
+ tmp = (BH1770_LUX_CORR_SCALE * chip->lux_ga) / BH1770_LUX_GA_SCALE;
+ /* Impact of chip factor correction */
+ tmp = (tmp * chip->lux_cf) / BH1770_LUX_CF_SCALE;
+ /* Impact of Device specific calibration correction */
+ tmp = (tmp * chip->lux_calib) / BH1770_CALIB_SCALER;
+ return tmp;
+}
+
+static int bh1770_lux_read_result(struct bh1770_chip *chip)
+{
+ bh1770_lux_get_result(chip);
+ return bh1770_lux_raw_to_adjusted(chip, chip->lux_data_raw);
+}
+
+/*
+ * Chip on / off functions are called while keeping mutex except probe
+ * or remove phase
+ */
+static int bh1770_chip_on(struct bh1770_chip *chip)
+{
+ int ret = regulator_bulk_enable(ARRAY_SIZE(chip->regs),
+ chip->regs);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(BH1770_STARTUP_DELAY, BH1770_STARTUP_DELAY * 2);
+
+ /* Reset the chip */
+ i2c_smbus_write_byte_data(chip->client, BH1770_ALS_CONTROL,
+ BH1770_SWRESET);
+ usleep_range(BH1770_RESET_TIME, BH1770_RESET_TIME * 2);
+
+ /*
+ * ALS is started always since proximity needs als results
+ * for realibility estimation.
+ * Let's assume dark until the first ALS measurement is ready.
+ */
+ chip->lux_data_raw = 0;
+ chip->prox_data = 0;
+ ret = i2c_smbus_write_byte_data(chip->client,
+ BH1770_ALS_CONTROL, BH1770_STANDALONE);
+
+ /* Assume reset defaults */
+ chip->lux_thres_hi_onchip = BH1770_LUX_RANGE;
+ chip->lux_thres_lo_onchip = 0;
+
+ return ret;
+}
+
+static void bh1770_chip_off(struct bh1770_chip *chip)
+{
+ i2c_smbus_write_byte_data(chip->client,
+ BH1770_INTERRUPT, BH1770_DISABLE);
+ i2c_smbus_write_byte_data(chip->client,
+ BH1770_ALS_CONTROL, BH1770_STANDBY);
+ i2c_smbus_write_byte_data(chip->client,
+ BH1770_PS_CONTROL, BH1770_STANDBY);
+ regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
+}
+
+/* chip->mutex is kept when this is called */
+static int bh1770_prox_mode_control(struct bh1770_chip *chip)
+{
+ if (chip->prox_enable_count) {
+ chip->prox_force_update = true; /* Force immediate update */
+
+ bh1770_lux_rate(chip, chip->lux_rate_index);
+ bh1770_prox_set_threshold(chip);
+ bh1770_led_cfg(chip);
+ bh1770_prox_rate(chip, PROX_BELOW_THRESHOLD);
+ bh1770_prox_interrupt_control(chip, BH1770_ENABLE);
+ i2c_smbus_write_byte_data(chip->client,
+ BH1770_PS_CONTROL, BH1770_STANDALONE);
+ } else {
+ chip->prox_data = 0;
+ bh1770_lux_rate(chip, chip->lux_rate_index);
+ bh1770_prox_interrupt_control(chip, BH1770_DISABLE);
+ i2c_smbus_write_byte_data(chip->client,
+ BH1770_PS_CONTROL, BH1770_STANDBY);
+ }
+ return 0;
+}
+
+/* chip->mutex is kept when this is called */
+static int bh1770_prox_read_result(struct bh1770_chip *chip)
+{
+ int ret;
+ bool above;
+ u8 mode;
+
+ ret = i2c_smbus_read_byte_data(chip->client, BH1770_PS_DATA_LED1);
+ if (ret < 0)
+ goto out;
+
+ if (ret > chip->prox_threshold_hw)
+ above = true;
+ else
+ above = false;
+
+ /*
+ * when ALS levels goes above limit, proximity result may be
+ * false proximity. Thus ignore the result. With real proximity
+ * there is a shadow causing low als levels.
+ */
+ if (chip->lux_data_raw > PROX_IGNORE_LUX_LIMIT)
+ ret = 0;
+
+ chip->prox_data = bh1770_psraw_to_adjusted(chip, ret);
+
+ /* Strong proximity level or force mode requires immediate response */
+ if (chip->prox_data >= chip->prox_abs_thres ||
+ chip->prox_force_update)
+ chip->prox_persistence_counter = chip->prox_persistence;
+
+ chip->prox_force_update = false;
+
+ /* Persistence filttering to reduce false proximity events */
+ if (likely(above)) {
+ if (chip->prox_persistence_counter < chip->prox_persistence) {
+ chip->prox_persistence_counter++;
+ ret = -ENODATA;
+ } else {
+ mode = PROX_ABOVE_THRESHOLD;
+ ret = 0;
+ }
+ } else {
+ chip->prox_persistence_counter = 0;
+ mode = PROX_BELOW_THRESHOLD;
+ chip->prox_data = 0;
+ ret = 0;
+ }
+
+ /* Set proximity detection rate based on above or below value */
+ if (ret == 0) {
+ bh1770_prox_rate(chip, mode);
+ sysfs_notify(&chip->client->dev.kobj, NULL, "prox0_raw");
+ }
+out:
+ return ret;
+}
+
+static int bh1770_detect(struct bh1770_chip *chip)
+{
+ struct i2c_client *client = chip->client;
+ s32 ret;
+ u8 manu, part;
+
+ ret = i2c_smbus_read_byte_data(client, BH1770_MANUFACT_ID);
+ if (ret < 0)
+ goto error;
+ manu = (u8)ret;
+
+ ret = i2c_smbus_read_byte_data(client, BH1770_PART_ID);
+ if (ret < 0)
+ goto error;
+ part = (u8)ret;
+
+ chip->revision = (part & BH1770_REV_MASK) >> BH1770_REV_SHIFT;
+ chip->prox_coef = BH1770_COEF_SCALER;
+ chip->prox_const = 0;
+ chip->lux_cf = BH1770_NEUTRAL_CF;
+
+ if ((manu == BH1770_MANUFACT_ROHM) &&
+ ((part & BH1770_PART_MASK) == BH1770_PART)) {
+ snprintf(chip->chipname, sizeof(chip->chipname), "BH1770GLC");
+ return 0;
+ }
+
+ if ((manu == BH1770_MANUFACT_OSRAM) &&
+ ((part & BH1770_PART_MASK) == BH1770_PART)) {
+ snprintf(chip->chipname, sizeof(chip->chipname), "SFH7770");
+ /* Values selected by comparing different versions */
+ chip->prox_coef = 819; /* 0.8 * BH1770_COEF_SCALER */
+ chip->prox_const = 40;
+ return 0;
+ }
+
+ ret = -ENODEV;
+error:
+ dev_dbg(&client->dev, "BH1770 or SFH7770 not found\n");
+
+ return ret;
+}
+
+/*
+ * This work is re-scheduled at every proximity interrupt.
+ * If this work is running, it means that there hasn't been any
+ * proximity interrupt in time. Situation is handled as no-proximity.
+ * It would be nice to have low-threshold interrupt or interrupt
+ * when measurement and hi-threshold are both 0. But neither of those exists.
+ * This is a workaroud for missing HW feature.
+ */
+
+static void bh1770_prox_work(struct work_struct *work)
+{
+ struct bh1770_chip *chip =
+ container_of(work, struct bh1770_chip, prox_work.work);
+
+ mutex_lock(&chip->mutex);
+ bh1770_prox_read_result(chip);
+ mutex_unlock(&chip->mutex);
+}
+
+/* This is threaded irq handler */
+static irqreturn_t bh1770_irq(int irq, void *data)
+{
+ struct bh1770_chip *chip = data;
+ int status;
+ int rate = 0;
+
+ mutex_lock(&chip->mutex);
+ status = i2c_smbus_read_byte_data(chip->client, BH1770_ALS_PS_STATUS);
+
+ /* Acknowledge interrupt by reading this register */
+ i2c_smbus_read_byte_data(chip->client, BH1770_INTERRUPT);
+
+ /*
+ * Check if there is fresh data available for als.
+ * If this is the very first data, update thresholds after that.
+ */
+ if (status & BH1770_INT_ALS_DATA) {
+ bh1770_lux_get_result(chip);
+ if (unlikely(chip->lux_wait_result)) {
+ chip->lux_wait_result = false;
+ wake_up(&chip->wait);
+ bh1770_lux_update_thresholds(chip,
+ chip->lux_threshold_hi,
+ chip->lux_threshold_lo);
+ }
+ }
+
+ /* Disable interrupt logic to guarantee acknowledgement */
+ i2c_smbus_write_byte_data(chip->client, BH1770_INTERRUPT,
+ (0 << 1) | (0 << 0));
+
+ if ((status & BH1770_INT_ALS_INT))
+ sysfs_notify(&chip->client->dev.kobj, NULL, "lux0_input");
+
+ if (chip->int_mode_prox && (status & BH1770_INT_LEDS_INT)) {
+ rate = prox_rates_ms[chip->prox_rate_threshold];
+ bh1770_prox_read_result(chip);
+ }
+
+ /* Re-enable interrupt logic */
+ i2c_smbus_write_byte_data(chip->client, BH1770_INTERRUPT,
+ (chip->int_mode_lux << 1) |
+ (chip->int_mode_prox << 0));
+ mutex_unlock(&chip->mutex);
+
+ /*
+ * Can't cancel work while keeping mutex since the work uses the
+ * same mutex.
+ */
+ if (rate) {
+ /*
+ * Simulate missing no-proximity interrupt 50ms after the
+ * next expected interrupt time.
+ */
+ cancel_delayed_work_sync(&chip->prox_work);
+ schedule_delayed_work(&chip->prox_work,
+ msecs_to_jiffies(rate + 50));
+ }
+ return IRQ_HANDLED;
+}
+
+static ssize_t bh1770_power_state_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ unsigned long value;
+ size_t ret;
+
+ if (strict_strtoul(buf, 0, &value))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ if (value) {
+ pm_runtime_get_sync(dev);
+
+ ret = bh1770_lux_rate(chip, chip->lux_rate_index);
+ ret |= bh1770_lux_interrupt_control(chip, BH1770_ENABLE);
+
+ if (ret < 0) {
+ pm_runtime_put(dev);
+ goto leave;
+ }
+
+ /* This causes interrupt after the next measurement cycle */
+ bh1770_lux_update_thresholds(chip, BH1770_LUX_DEF_THRES,
+ BH1770_LUX_DEF_THRES);
+ /* Inform that we are waiting for a result from ALS */
+ chip->lux_wait_result = true;
+ bh1770_prox_mode_control(chip);
+ } else if (!pm_runtime_suspended(dev)) {
+ pm_runtime_put(dev);
+ }
+ ret = count;
+leave:
+ mutex_unlock(&chip->mutex);
+ return ret;
+}
+
+static ssize_t bh1770_power_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", !pm_runtime_suspended(dev));
+}
+
+static ssize_t bh1770_lux_result_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ ssize_t ret;
+ long timeout;
+
+ if (pm_runtime_suspended(dev))
+ return -EIO; /* Chip is not enabled at all */
+
+ timeout = wait_event_interruptible_timeout(chip->wait,
+ !chip->lux_wait_result,
+ msecs_to_jiffies(BH1770_TIMEOUT));
+ if (!timeout)
+ return -EIO;
+
+ mutex_lock(&chip->mutex);
+ ret = sprintf(buf, "%d\n", bh1770_lux_read_result(chip));
+ mutex_unlock(&chip->mutex);
+
+ return ret;
+}
+
+static ssize_t bh1770_lux_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", BH1770_LUX_RANGE);
+}
+
+static ssize_t bh1770_prox_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ unsigned long value;
+
+ if (strict_strtoul(buf, 0, &value))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ /* Assume no proximity. Sensor will tell real state soon */
+ if (!chip->prox_enable_count)
+ chip->prox_data = 0;
+
+ if (value)
+ chip->prox_enable_count++;
+ else if (chip->prox_enable_count > 0)
+ chip->prox_enable_count--;
+ else
+ goto leave;
+
+ /* Run control only when chip is powered on */
+ if (!pm_runtime_suspended(dev))
+ bh1770_prox_mode_control(chip);
+leave:
+ mutex_unlock(&chip->mutex);
+ return count;
+}
+
+static ssize_t bh1770_prox_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ ssize_t len;
+
+ mutex_lock(&chip->mutex);
+ len = sprintf(buf, "%d\n", chip->prox_enable_count);
+ mutex_unlock(&chip->mutex);
+ return len;
+}
+
+static ssize_t bh1770_prox_result_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ ssize_t ret;
+
+ mutex_lock(&chip->mutex);
+ if (chip->prox_enable_count && !pm_runtime_suspended(dev))
+ ret = sprintf(buf, "%d\n", chip->prox_data);
+ else
+ ret = -EIO;
+ mutex_unlock(&chip->mutex);
+ return ret;
+}
+
+static ssize_t bh1770_prox_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", BH1770_PROX_RANGE);
+}
+
+static ssize_t bh1770_get_prox_rate_avail(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i;
+ int pos = 0;
+ for (i = 0; i < ARRAY_SIZE(prox_rates_hz); i++)
+ pos += sprintf(buf + pos, "%d ", prox_rates_hz[i]);
+ sprintf(buf + pos - 1, "\n");
+ return pos;
+}
+
+static ssize_t bh1770_get_prox_rate_above(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", prox_rates_hz[chip->prox_rate_threshold]);
+}
+
+static ssize_t bh1770_get_prox_rate_below(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", prox_rates_hz[chip->prox_rate]);
+}
+
+static int bh1770_prox_rate_validate(int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(prox_rates_hz) - 1; i++)
+ if (rate >= prox_rates_hz[i])
+ break;
+ return i;
+}
+
+static ssize_t bh1770_set_prox_rate_above(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ unsigned long value;
+
+ if (strict_strtoul(buf, 0, &value))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ chip->prox_rate_threshold = bh1770_prox_rate_validate(value);
+ mutex_unlock(&chip->mutex);
+ return count;
+}
+
+static ssize_t bh1770_set_prox_rate_below(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ unsigned long value;
+
+ if (strict_strtoul(buf, 0, &value))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ chip->prox_rate = bh1770_prox_rate_validate(value);
+ mutex_unlock(&chip->mutex);
+ return count;
+}
+
+static ssize_t bh1770_get_prox_thres(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", chip->prox_threshold);
+}
+
+static ssize_t bh1770_set_prox_thres(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ unsigned long value;
+ int ret;
+
+ if (strict_strtoul(buf, 0, &value))
+ return -EINVAL;
+ if (value > BH1770_PROX_RANGE)
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ chip->prox_threshold = value;
+ ret = bh1770_prox_set_threshold(chip);
+ mutex_unlock(&chip->mutex);
+ if (ret < 0)
+ return ret;
+ return count;
+}
+
+static ssize_t bh1770_prox_persistence_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", chip->prox_persistence);
+}
+
+static ssize_t bh1770_prox_persistence_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ unsigned long value;
+
+ if (strict_strtoul(buf, 0, &value))
+ return -EINVAL;
+
+ if (value > BH1770_PROX_MAX_PERSISTENCE)
+ return -EINVAL;
+
+ chip->prox_persistence = value;
+
+ return len;
+}
+
+static ssize_t bh1770_prox_abs_thres_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ return sprintf(buf, "%u\n", chip->prox_abs_thres);
+}
+
+static ssize_t bh1770_prox_abs_thres_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ unsigned long value;
+
+ if (strict_strtoul(buf, 0, &value))
+ return -EINVAL;
+
+ if (value > BH1770_PROX_RANGE)
+ return -EINVAL;
+
+ chip->prox_abs_thres = value;
+
+ return len;
+}
+
+static ssize_t bh1770_chip_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ return sprintf(buf, "%s rev %d\n", chip->chipname, chip->revision);
+}
+
+static ssize_t bh1770_lux_calib_default_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", BH1770_CALIB_SCALER);
+}
+
+static ssize_t bh1770_lux_calib_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ ssize_t len;
+
+ mutex_lock(&chip->mutex);
+ len = sprintf(buf, "%u\n", chip->lux_calib);
+ mutex_unlock(&chip->mutex);
+ return len;
+}
+
+static ssize_t bh1770_lux_calib_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ unsigned long value;
+ u32 old_calib;
+ u32 new_corr;
+
+ if (strict_strtoul(buf, 0, &value))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ old_calib = chip->lux_calib;
+ chip->lux_calib = value;
+ new_corr = bh1770_get_corr_value(chip);
+ if (new_corr == 0) {
+ chip->lux_calib = old_calib;
+ mutex_unlock(&chip->mutex);
+ return -EINVAL;
+ }
+ chip->lux_corr = new_corr;
+ /* Refresh thresholds on HW after changing correction value */
+ bh1770_lux_update_thresholds(chip, chip->lux_threshold_hi,
+ chip->lux_threshold_lo);
+
+ mutex_unlock(&chip->mutex);
+
+ return len;
+}
+
+static ssize_t bh1770_get_lux_rate_avail(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i;
+ int pos = 0;
+ for (i = 0; i < ARRAY_SIZE(lux_rates_hz); i++)
+ pos += sprintf(buf + pos, "%d ", lux_rates_hz[i]);
+ sprintf(buf + pos - 1, "\n");
+ return pos;
+}
+
+static ssize_t bh1770_get_lux_rate(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", lux_rates_hz[chip->lux_rate_index]);
+}
+
+static ssize_t bh1770_set_lux_rate(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ unsigned long rate_hz;
+ int ret, i;
+
+ if (strict_strtoul(buf, 0, &rate_hz))
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(lux_rates_hz) - 1; i++)
+ if (rate_hz >= lux_rates_hz[i])
+ break;
+
+ mutex_lock(&chip->mutex);
+ chip->lux_rate_index = i;
+ ret = bh1770_lux_rate(chip, i);
+ mutex_unlock(&chip->mutex);
+
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t bh1770_get_lux_thresh_above(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", chip->lux_threshold_hi);
+}
+
+static ssize_t bh1770_get_lux_thresh_below(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", chip->lux_threshold_lo);
+}
+
+static ssize_t bh1770_set_lux_thresh(struct bh1770_chip *chip, u16 *target,
+ const char *buf)
+{
+ int ret = 0;
+ unsigned long thresh;
+
+ if (strict_strtoul(buf, 0, &thresh))
+ return -EINVAL;
+
+ if (thresh > BH1770_LUX_RANGE)
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ *target = thresh;
+ /*
+ * Don't update values in HW if we are still waiting for
+ * first interrupt to come after device handle open call.
+ */
+ if (!chip->lux_wait_result)
+ ret = bh1770_lux_update_thresholds(chip,
+ chip->lux_threshold_hi,
+ chip->lux_threshold_lo);
+ mutex_unlock(&chip->mutex);
+ return ret;
+
+}
+
+static ssize_t bh1770_set_lux_thresh_above(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ int ret = bh1770_set_lux_thresh(chip, &chip->lux_threshold_hi, buf);
+ if (ret < 0)
+ return ret;
+ return len;
+}
+
+static ssize_t bh1770_set_lux_thresh_below(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct bh1770_chip *chip = dev_get_drvdata(dev);
+ int ret = bh1770_set_lux_thresh(chip, &chip->lux_threshold_lo, buf);
+ if (ret < 0)
+ return ret;
+ return len;
+}
+
+static DEVICE_ATTR(prox0_raw_en, S_IRUGO | S_IWUSR, bh1770_prox_enable_show,
+ bh1770_prox_enable_store);
+static DEVICE_ATTR(prox0_thresh_above1_value, S_IRUGO | S_IWUSR,
+ bh1770_prox_abs_thres_show,
+ bh1770_prox_abs_thres_store);
+static DEVICE_ATTR(prox0_thresh_above0_value, S_IRUGO | S_IWUSR,
+ bh1770_get_prox_thres,
+ bh1770_set_prox_thres);
+static DEVICE_ATTR(prox0_raw, S_IRUGO, bh1770_prox_result_show, NULL);
+static DEVICE_ATTR(prox0_sensor_range, S_IRUGO, bh1770_prox_range_show, NULL);
+static DEVICE_ATTR(prox0_thresh_above_count, S_IRUGO | S_IWUSR,
+ bh1770_prox_persistence_show,
+ bh1770_prox_persistence_store);
+static DEVICE_ATTR(prox0_rate_above, S_IRUGO | S_IWUSR,
+ bh1770_get_prox_rate_above,
+ bh1770_set_prox_rate_above);
+static DEVICE_ATTR(prox0_rate_below, S_IRUGO | S_IWUSR,
+ bh1770_get_prox_rate_below,
+ bh1770_set_prox_rate_below);
+static DEVICE_ATTR(prox0_rate_avail, S_IRUGO, bh1770_get_prox_rate_avail, NULL);
+
+static DEVICE_ATTR(lux0_calibscale, S_IRUGO | S_IWUSR, bh1770_lux_calib_show,
+ bh1770_lux_calib_store);
+static DEVICE_ATTR(lux0_calibscale_default, S_IRUGO,
+ bh1770_lux_calib_default_show,
+ NULL);
+static DEVICE_ATTR(lux0_input, S_IRUGO, bh1770_lux_result_show, NULL);
+static DEVICE_ATTR(lux0_sensor_range, S_IRUGO, bh1770_lux_range_show, NULL);
+static DEVICE_ATTR(lux0_rate, S_IRUGO | S_IWUSR, bh1770_get_lux_rate,
+ bh1770_set_lux_rate);
+static DEVICE_ATTR(lux0_rate_avail, S_IRUGO, bh1770_get_lux_rate_avail, NULL);
+static DEVICE_ATTR(lux0_thresh_above_value, S_IRUGO | S_IWUSR,
+ bh1770_get_lux_thresh_above,
+ bh1770_set_lux_thresh_above);
+static DEVICE_ATTR(lux0_thresh_below_value, S_IRUGO | S_IWUSR,
+ bh1770_get_lux_thresh_below,
+ bh1770_set_lux_thresh_below);
+static DEVICE_ATTR(chip_id, S_IRUGO, bh1770_chip_id_show, NULL);
+static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, bh1770_power_state_show,
+ bh1770_power_state_store);
+
+
+static struct attribute *sysfs_attrs[] = {
+ &dev_attr_lux0_calibscale.attr,
+ &dev_attr_lux0_calibscale_default.attr,
+ &dev_attr_lux0_input.attr,
+ &dev_attr_lux0_sensor_range.attr,
+ &dev_attr_lux0_rate.attr,
+ &dev_attr_lux0_rate_avail.attr,
+ &dev_attr_lux0_thresh_above_value.attr,
+ &dev_attr_lux0_thresh_below_value.attr,
+ &dev_attr_prox0_raw.attr,
+ &dev_attr_prox0_sensor_range.attr,
+ &dev_attr_prox0_raw_en.attr,
+ &dev_attr_prox0_thresh_above_count.attr,
+ &dev_attr_prox0_rate_above.attr,
+ &dev_attr_prox0_rate_below.attr,
+ &dev_attr_prox0_rate_avail.attr,
+ &dev_attr_prox0_thresh_above0_value.attr,
+ &dev_attr_prox0_thresh_above1_value.attr,
+ &dev_attr_chip_id.attr,
+ &dev_attr_power_state.attr,
+ NULL
+};
+
+static struct attribute_group bh1770_attribute_group = {
+ .attrs = sysfs_attrs
+};
+
+static int __devinit bh1770_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct bh1770_chip *chip;
+ int err;
+
+ chip = kzalloc(sizeof *chip, GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, chip);
+ chip->client = client;
+
+ mutex_init(&chip->mutex);
+ init_waitqueue_head(&chip->wait);
+ INIT_DELAYED_WORK(&chip->prox_work, bh1770_prox_work);
+
+ if (client->dev.platform_data == NULL) {
+ dev_err(&client->dev, "platform data is mandatory\n");
+ err = -EINVAL;
+ goto fail1;
+ }
+
+ chip->pdata = client->dev.platform_data;
+ chip->lux_calib = BH1770_LUX_NEUTRAL_CALIB_VALUE;
+ chip->lux_rate_index = BH1770_LUX_DEFAULT_RATE;
+ chip->lux_threshold_lo = BH1770_LUX_DEF_THRES;
+ chip->lux_threshold_hi = BH1770_LUX_DEF_THRES;
+
+ if (chip->pdata->glass_attenuation == 0)
+ chip->lux_ga = BH1770_NEUTRAL_GA;
+ else
+ chip->lux_ga = chip->pdata->glass_attenuation;
+
+ chip->prox_threshold = BH1770_PROX_DEF_THRES;
+ chip->prox_led = chip->pdata->led_def_curr;
+ chip->prox_abs_thres = BH1770_PROX_DEF_ABS_THRES;
+ chip->prox_persistence = BH1770_DEFAULT_PERSISTENCE;
+ chip->prox_rate_threshold = BH1770_PROX_DEF_RATE_THRESH;
+ chip->prox_rate = BH1770_PROX_DEFAULT_RATE;
+ chip->prox_data = 0;
+
+ chip->regs[0].supply = reg_vcc;
+ chip->regs[1].supply = reg_vleds;
+
+ err = regulator_bulk_get(&client->dev,
+ ARRAY_SIZE(chip->regs), chip->regs);
+ if (err < 0) {
+ dev_err(&client->dev, "Cannot get regulators\n");
+ goto fail1;
+ }
+
+ err = regulator_bulk_enable(ARRAY_SIZE(chip->regs),
+ chip->regs);
+ if (err < 0) {
+ dev_err(&client->dev, "Cannot enable regulators\n");
+ goto fail2;
+ }
+
+ usleep_range(BH1770_STARTUP_DELAY, BH1770_STARTUP_DELAY * 2);
+ err = bh1770_detect(chip);
+ if (err < 0)
+ goto fail3;
+
+ /* Start chip */
+ bh1770_chip_on(chip);
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_enable(&client->dev);
+
+ chip->lux_corr = bh1770_get_corr_value(chip);
+ if (chip->lux_corr == 0) {
+ dev_err(&client->dev, "Improper correction values\n");
+ err = -EINVAL;
+ goto fail3;
+ }
+
+ if (chip->pdata->setup_resources) {
+ err = chip->pdata->setup_resources();
+ if (err) {
+ err = -EINVAL;
+ goto fail3;
+ }
+ }
+
+ err = sysfs_create_group(&chip->client->dev.kobj,
+ &bh1770_attribute_group);
+ if (err < 0) {
+ dev_err(&chip->client->dev, "Sysfs registration failed\n");
+ goto fail4;
+ }
+
+ /*
+ * Chip needs level triggered interrupt to work. However,
+ * level triggering doesn't work always correctly with power
+ * management. Select both
+ */
+ err = request_threaded_irq(client->irq, NULL,
+ bh1770_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
+ IRQF_TRIGGER_LOW,
+ "bh1770", chip);
+ if (err) {
+ dev_err(&client->dev, "could not get IRQ %d\n",
+ client->irq);
+ goto fail5;
+ }
+ regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
+ return err;
+fail5:
+ sysfs_remove_group(&chip->client->dev.kobj,
+ &bh1770_attribute_group);
+fail4:
+ if (chip->pdata->release_resources)
+ chip->pdata->release_resources();
+fail3:
+ regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
+fail2:
+ regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs);
+fail1:
+ kfree(chip);
+ return err;
+}
+
+static int __devexit bh1770_remove(struct i2c_client *client)
+{
+ struct bh1770_chip *chip = i2c_get_clientdata(client);
+
+ free_irq(client->irq, chip);
+
+ sysfs_remove_group(&chip->client->dev.kobj,
+ &bh1770_attribute_group);
+
+ if (chip->pdata->release_resources)
+ chip->pdata->release_resources();
+
+ cancel_delayed_work_sync(&chip->prox_work);
+
+ if (!pm_runtime_suspended(&client->dev))
+ bh1770_chip_off(chip);
+
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
+ regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs);
+ kfree(chip);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int bh1770_suspend(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct bh1770_chip *chip = i2c_get_clientdata(client);
+
+ bh1770_chip_off(chip);
+
+ return 0;
+}
+
+static int bh1770_resume(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct bh1770_chip *chip = i2c_get_clientdata(client);
+ int ret = 0;
+
+ bh1770_chip_on(chip);
+
+ if (!pm_runtime_suspended(dev)) {
+ /*
+ * If we were enabled at suspend time, it is expected
+ * everything works nice and smoothly
+ */
+ ret = bh1770_lux_rate(chip, chip->lux_rate_index);
+ ret |= bh1770_lux_interrupt_control(chip, BH1770_ENABLE);
+
+ /* This causes interrupt after the next measurement cycle */
+ bh1770_lux_update_thresholds(chip, BH1770_LUX_DEF_THRES,
+ BH1770_LUX_DEF_THRES);
+ /* Inform that we are waiting for a result from ALS */
+ chip->lux_wait_result = true;
+ bh1770_prox_mode_control(chip);
+ }
+ return ret;
+}
+
+#else
+#define bh1770_suspend NULL
+#define bh1770_shutdown NULL
+#define bh1770_resume NULL
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int bh1770_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct bh1770_chip *chip = i2c_get_clientdata(client);
+
+ bh1770_chip_off(chip);
+
+ return 0;
+}
+
+static int bh1770_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct bh1770_chip *chip = i2c_get_clientdata(client);
+
+ bh1770_chip_on(chip);
+
+ return 0;
+}
+#endif
+
+static const struct i2c_device_id bh1770_id[] = {
+ {"bh1770glc", 0 },
+ {"sfh7770", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, bh1770_id);
+
+static const struct dev_pm_ops bh1770_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(bh1770_suspend, bh1770_resume)
+ SET_RUNTIME_PM_OPS(bh1770_runtime_suspend, bh1770_runtime_resume, NULL)
+};
+
+static struct i2c_driver bh1770_driver = {
+ .driver = {
+ .name = "bh1770glc",
+ .owner = THIS_MODULE,
+ .pm = &bh1770_pm_ops,
+ },
+ .probe = bh1770_probe,
+ .remove = __devexit_p(bh1770_remove),
+ .id_table = bh1770_id,
+};
+
+static int __init bh1770_init(void)
+{
+ return i2c_add_driver(&bh1770_driver);
+}
+
+static void __exit bh1770_exit(void)
+{
+ i2c_del_driver(&bh1770_driver);
+}
+
+MODULE_DESCRIPTION("BH1770GLC / SFH7770 combined ALS and proximity sensor");
+MODULE_AUTHOR("Samu Onkalo, Nokia Corporation");
+MODULE_LICENSE("GPL v2");
+
+module_init(bh1770_init);
+module_exit(bh1770_exit);
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index af2497ae5fe3..0a53500636c9 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -146,6 +146,7 @@ static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode)
struct inode *ret = new_inode(sb);
if (ret) {
+ ret->i_ino = get_next_ino();
ret->i_mode = mode;
ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
}
diff --git a/drivers/misc/isl29020.c b/drivers/misc/isl29020.c
new file mode 100644
index 000000000000..34fe835921c4
--- /dev/null
+++ b/drivers/misc/isl29020.c
@@ -0,0 +1,248 @@
+/*
+ * isl29020.c - Intersil ALS Driver
+ *
+ * Copyright (C) 2008 Intel Corp
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Data sheet at: http://www.intersil.com/data/fn/fn6505.pdf
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/pm_runtime.h>
+
+static DEFINE_MUTEX(mutex);
+
+static ssize_t als_sensing_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int val;
+
+ val = i2c_smbus_read_byte_data(client, 0x00);
+
+ if (val < 0)
+ return val;
+ return sprintf(buf, "%d000\n", 1 << (2 * (val & 3)));
+
+}
+
+static ssize_t als_lux_input_data_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret_val, val;
+ unsigned long int lux;
+ int temp;
+
+ pm_runtime_get_sync(dev);
+ msleep(100);
+
+ mutex_lock(&mutex);
+ temp = i2c_smbus_read_byte_data(client, 0x02); /* MSB data */
+ if (temp < 0) {
+ pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+ return temp;
+ }
+
+ ret_val = i2c_smbus_read_byte_data(client, 0x01); /* LSB data */
+ mutex_unlock(&mutex);
+
+ if (ret_val < 0) {
+ pm_runtime_put_sync(dev);
+ return ret_val;
+ }
+
+ ret_val |= temp << 8;
+ val = i2c_smbus_read_byte_data(client, 0x00);
+ pm_runtime_put_sync(dev);
+ if (val < 0)
+ return val;
+ lux = ((((1 << (2 * (val & 3))))*1000) * ret_val) / 65536;
+ return sprintf(buf, "%ld\n", lux);
+}
+
+static ssize_t als_sensing_range_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned int ret_val;
+ unsigned long val;
+
+ if (strict_strtoul(buf, 10, &val))
+ return -EINVAL;
+ if (val < 1 || val > 64000)
+ return -EINVAL;
+
+ /* Pick the smallest sensor range that will meet our requirements */
+ if (val <= 1000)
+ val = 1;
+ else if (val <= 4000)
+ val = 2;
+ else if (val <= 16000)
+ val = 3;
+ else
+ val = 4;
+
+ ret_val = i2c_smbus_read_byte_data(client, 0x00);
+
+ ret_val &= 0xFC; /*reset the bit before setting them */
+ ret_val |= val - 1;
+ ret_val = i2c_smbus_write_byte_data(client, 0x00, ret_val);
+
+ if (ret_val < 0)
+ return ret_val;
+ return count;
+}
+
+static void als_set_power_state(struct i2c_client *client, int enable)
+{
+ int ret_val;
+
+ ret_val = i2c_smbus_read_byte_data(client, 0x00);
+ if (ret_val < 0)
+ return;
+
+ if (enable)
+ ret_val |= 0x80;
+ else
+ ret_val &= 0x7F;
+
+ i2c_smbus_write_byte_data(client, 0x00, ret_val);
+}
+
+static DEVICE_ATTR(lux0_sensor_range, S_IRUGO | S_IWUSR,
+ als_sensing_range_show, als_sensing_range_store);
+static DEVICE_ATTR(lux0_input, S_IRUGO, als_lux_input_data_show, NULL);
+
+static struct attribute *mid_att_als[] = {
+ &dev_attr_lux0_sensor_range.attr,
+ &dev_attr_lux0_input.attr,
+ NULL
+};
+
+static struct attribute_group m_als_gr = {
+ .name = "isl29020",
+ .attrs = mid_att_als
+};
+
+static int als_set_default_config(struct i2c_client *client)
+{
+ int retval;
+
+ retval = i2c_smbus_write_byte_data(client, 0x00, 0xc0);
+ if (retval < 0) {
+ dev_err(&client->dev, "default write failed.");
+ return retval;
+ }
+ return 0;;
+}
+
+static int isl29020_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int res;
+
+ res = als_set_default_config(client);
+ if (res < 0)
+ return res;
+
+ res = sysfs_create_group(&client->dev.kobj, &m_als_gr);
+ if (res) {
+ dev_err(&client->dev, "isl29020: device create file failed\n");
+ return res;
+ }
+ dev_info(&client->dev, "%s isl29020: ALS chip found\n", client->name);
+ als_set_power_state(client, 0);
+ pm_runtime_enable(&client->dev);
+ return res;
+}
+
+static int isl29020_remove(struct i2c_client *client)
+{
+ struct als_data *data = i2c_get_clientdata(client);
+ sysfs_remove_group(&client->dev.kobj, &m_als_gr);
+ kfree(data);
+ return 0;
+}
+
+static struct i2c_device_id isl29020_id[] = {
+ { "isl29020", 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, isl29020_id);
+
+#ifdef CONFIG_PM
+
+static int isl29020_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ als_set_power_state(client, 0);
+ return 0;
+}
+
+static int isl29020_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ als_set_power_state(client, 1);
+ return 0;
+}
+
+static const struct dev_pm_ops isl29020_pm_ops = {
+ .runtime_suspend = isl29020_runtime_suspend,
+ .runtime_resume = isl29020_runtime_resume,
+};
+
+#define ISL29020_PM_OPS (&isl29020_pm_ops)
+#else /* CONFIG_PM */
+#define ISL29020_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static struct i2c_driver isl29020_driver = {
+ .driver = {
+ .name = "isl29020",
+ .pm = ISL29020_PM_OPS,
+ },
+ .probe = isl29020_probe,
+ .remove = isl29020_remove,
+ .id_table = isl29020_id,
+};
+
+static int __init sensor_isl29020_init(void)
+{
+ return i2c_add_driver(&isl29020_driver);
+}
+
+static void __exit sensor_isl29020_exit(void)
+{
+ i2c_del_driver(&isl29020_driver);
+}
+
+module_init(sensor_isl29020_init);
+module_exit(sensor_isl29020_exit);
+
+MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com");
+MODULE_DESCRIPTION("Intersil isl29020 ALS Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index 343b5d8ea697..81d7fa4ec0db 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -52,32 +52,32 @@
#define REC_NUM_DEFAULT 10
enum cname {
- INVALID,
- INT_HARDWARE_ENTRY,
- INT_HW_IRQ_EN,
- INT_TASKLET_ENTRY,
- FS_DEVRW,
- MEM_SWAPOUT,
- TIMERADD,
- SCSI_DISPATCH_CMD,
- IDE_CORE_CP,
- DIRECT,
+ CN_INVALID,
+ CN_INT_HARDWARE_ENTRY,
+ CN_INT_HW_IRQ_EN,
+ CN_INT_TASKLET_ENTRY,
+ CN_FS_DEVRW,
+ CN_MEM_SWAPOUT,
+ CN_TIMERADD,
+ CN_SCSI_DISPATCH_CMD,
+ CN_IDE_CORE_CP,
+ CN_DIRECT,
};
enum ctype {
- NONE,
- PANIC,
- BUG,
- EXCEPTION,
- LOOP,
- OVERFLOW,
- CORRUPT_STACK,
- UNALIGNED_LOAD_STORE_WRITE,
- OVERWRITE_ALLOCATION,
- WRITE_AFTER_FREE,
- SOFTLOCKUP,
- HARDLOCKUP,
- HUNG_TASK,
+ CT_NONE,
+ CT_PANIC,
+ CT_BUG,
+ CT_EXCEPTION,
+ CT_LOOP,
+ CT_OVERFLOW,
+ CT_CORRUPT_STACK,
+ CT_UNALIGNED_LOAD_STORE_WRITE,
+ CT_OVERWRITE_ALLOCATION,
+ CT_WRITE_AFTER_FREE,
+ CT_SOFTLOCKUP,
+ CT_HARDLOCKUP,
+ CT_HUNG_TASK,
};
static char* cp_name[] = {
@@ -117,8 +117,8 @@ static char* cpoint_type;
static int cpoint_count = DEFAULT_COUNT;
static int recur_count = REC_NUM_DEFAULT;
-static enum cname cpoint = INVALID;
-static enum ctype cptype = NONE;
+static enum cname cpoint = CN_INVALID;
+static enum ctype cptype = CT_NONE;
static int count = DEFAULT_COUNT;
module_param(recur_count, int, 0644);
@@ -207,12 +207,12 @@ static enum ctype parse_cp_type(const char *what, size_t count)
return i + 1;
}
- return NONE;
+ return CT_NONE;
}
static const char *cp_type_to_str(enum ctype type)
{
- if (type == NONE || type < 0 || type > ARRAY_SIZE(cp_type))
+ if (type == CT_NONE || type < 0 || type > ARRAY_SIZE(cp_type))
return "None";
return cp_type[type - 1];
@@ -220,7 +220,7 @@ static const char *cp_type_to_str(enum ctype type)
static const char *cp_name_to_str(enum cname name)
{
- if (name == INVALID || name < 0 || name > ARRAY_SIZE(cp_name))
+ if (name == CN_INVALID || name < 0 || name > ARRAY_SIZE(cp_name))
return "INVALID";
return cp_name[name - 1];
@@ -245,7 +245,7 @@ static int lkdtm_parse_commandline(void)
return -EINVAL;
cptype = parse_cp_type(cpoint_type, strlen(cpoint_type));
- if (cptype == NONE)
+ if (cptype == CT_NONE)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(cp_name); i++) {
@@ -274,30 +274,30 @@ static int recursive_loop(int a)
static void lkdtm_do_action(enum ctype which)
{
switch (which) {
- case PANIC:
+ case CT_PANIC:
panic("dumptest");
break;
- case BUG:
+ case CT_BUG:
BUG();
break;
- case EXCEPTION:
+ case CT_EXCEPTION:
*((int *) 0) = 0;
break;
- case LOOP:
+ case CT_LOOP:
for (;;)
;
break;
- case OVERFLOW:
+ case CT_OVERFLOW:
(void) recursive_loop(0);
break;
- case CORRUPT_STACK: {
+ case CT_CORRUPT_STACK: {
volatile u32 data[8];
volatile u32 *p = data;
p[12] = 0x12345678;
break;
}
- case UNALIGNED_LOAD_STORE_WRITE: {
+ case CT_UNALIGNED_LOAD_STORE_WRITE: {
static u8 data[5] __attribute__((aligned(4))) = {1, 2,
3, 4, 5};
u32 *p;
@@ -309,7 +309,7 @@ static void lkdtm_do_action(enum ctype which)
*p = val;
break;
}
- case OVERWRITE_ALLOCATION: {
+ case CT_OVERWRITE_ALLOCATION: {
size_t len = 1020;
u32 *data = kmalloc(len, GFP_KERNEL);
@@ -317,7 +317,7 @@ static void lkdtm_do_action(enum ctype which)
kfree(data);
break;
}
- case WRITE_AFTER_FREE: {
+ case CT_WRITE_AFTER_FREE: {
size_t len = 1024;
u32 *data = kmalloc(len, GFP_KERNEL);
@@ -326,21 +326,21 @@ static void lkdtm_do_action(enum ctype which)
memset(data, 0x78, len);
break;
}
- case SOFTLOCKUP:
+ case CT_SOFTLOCKUP:
preempt_disable();
for (;;)
cpu_relax();
break;
- case HARDLOCKUP:
+ case CT_HARDLOCKUP:
local_irq_disable();
for (;;)
cpu_relax();
break;
- case HUNG_TASK:
+ case CT_HUNG_TASK:
set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
break;
- case NONE:
+ case CT_NONE:
default:
break;
}
@@ -363,43 +363,43 @@ static int lkdtm_register_cpoint(enum cname which)
{
int ret;
- cpoint = INVALID;
+ cpoint = CN_INVALID;
if (lkdtm.entry != NULL)
unregister_jprobe(&lkdtm);
switch (which) {
- case DIRECT:
+ case CN_DIRECT:
lkdtm_do_action(cptype);
return 0;
- case INT_HARDWARE_ENTRY:
+ case CN_INT_HARDWARE_ENTRY:
lkdtm.kp.symbol_name = "do_IRQ";
lkdtm.entry = (kprobe_opcode_t*) jp_do_irq;
break;
- case INT_HW_IRQ_EN:
+ case CN_INT_HW_IRQ_EN:
lkdtm.kp.symbol_name = "handle_IRQ_event";
lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event;
break;
- case INT_TASKLET_ENTRY:
+ case CN_INT_TASKLET_ENTRY:
lkdtm.kp.symbol_name = "tasklet_action";
lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action;
break;
- case FS_DEVRW:
+ case CN_FS_DEVRW:
lkdtm.kp.symbol_name = "ll_rw_block";
lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block;
break;
- case MEM_SWAPOUT:
+ case CN_MEM_SWAPOUT:
lkdtm.kp.symbol_name = "shrink_inactive_list";
lkdtm.entry = (kprobe_opcode_t*) jp_shrink_inactive_list;
break;
- case TIMERADD:
+ case CN_TIMERADD:
lkdtm.kp.symbol_name = "hrtimer_start";
lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start;
break;
- case SCSI_DISPATCH_CMD:
+ case CN_SCSI_DISPATCH_CMD:
lkdtm.kp.symbol_name = "scsi_dispatch_cmd";
lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd;
break;
- case IDE_CORE_CP:
+ case CN_IDE_CORE_CP:
#ifdef CONFIG_IDE
lkdtm.kp.symbol_name = "generic_ide_ioctl";
lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl;
@@ -416,7 +416,7 @@ static int lkdtm_register_cpoint(enum cname which)
cpoint = which;
if ((ret = register_jprobe(&lkdtm)) < 0) {
printk(KERN_INFO "lkdtm: Couldn't register jprobe\n");
- cpoint = INVALID;
+ cpoint = CN_INVALID;
}
return ret;
@@ -445,7 +445,7 @@ static ssize_t do_register_entry(enum cname which, struct file *f,
cptype = parse_cp_type(buf, count);
free_page((unsigned long) buf);
- if (cptype == NONE)
+ if (cptype == CT_NONE)
return -EINVAL;
err = lkdtm_register_cpoint(which);
@@ -487,49 +487,49 @@ static int lkdtm_debugfs_open(struct inode *inode, struct file *file)
static ssize_t int_hardware_entry(struct file *f, const char __user *buf,
size_t count, loff_t *off)
{
- return do_register_entry(INT_HARDWARE_ENTRY, f, buf, count, off);
+ return do_register_entry(CN_INT_HARDWARE_ENTRY, f, buf, count, off);
}
static ssize_t int_hw_irq_en(struct file *f, const char __user *buf,
size_t count, loff_t *off)
{
- return do_register_entry(INT_HW_IRQ_EN, f, buf, count, off);
+ return do_register_entry(CN_INT_HW_IRQ_EN, f, buf, count, off);
}
static ssize_t int_tasklet_entry(struct file *f, const char __user *buf,
size_t count, loff_t *off)
{
- return do_register_entry(INT_TASKLET_ENTRY, f, buf, count, off);
+ return do_register_entry(CN_INT_TASKLET_ENTRY, f, buf, count, off);
}
static ssize_t fs_devrw_entry(struct file *f, const char __user *buf,
size_t count, loff_t *off)
{
- return do_register_entry(FS_DEVRW, f, buf, count, off);
+ return do_register_entry(CN_FS_DEVRW, f, buf, count, off);
}
static ssize_t mem_swapout_entry(struct file *f, const char __user *buf,
size_t count, loff_t *off)
{
- return do_register_entry(MEM_SWAPOUT, f, buf, count, off);
+ return do_register_entry(CN_MEM_SWAPOUT, f, buf, count, off);
}
static ssize_t timeradd_entry(struct file *f, const char __user *buf,
size_t count, loff_t *off)
{
- return do_register_entry(TIMERADD, f, buf, count, off);
+ return do_register_entry(CN_TIMERADD, f, buf, count, off);
}
static ssize_t scsi_dispatch_cmd_entry(struct file *f,
const char __user *buf, size_t count, loff_t *off)
{
- return do_register_entry(SCSI_DISPATCH_CMD, f, buf, count, off);
+ return do_register_entry(CN_SCSI_DISPATCH_CMD, f, buf, count, off);
}
static ssize_t ide_core_cp_entry(struct file *f, const char __user *buf,
size_t count, loff_t *off)
{
- return do_register_entry(IDE_CORE_CP, f, buf, count, off);
+ return do_register_entry(CN_IDE_CORE_CP, f, buf, count, off);
}
/* Special entry to just crash directly. Available without KPROBEs */
@@ -557,7 +557,7 @@ static ssize_t direct_entry(struct file *f, const char __user *user_buf,
type = parse_cp_type(buf, count);
free_page((unsigned long) buf);
- if (type == NONE)
+ if (type == CT_NONE)
return -EINVAL;
printk(KERN_INFO "lkdtm: Performing direct entry %s\n",
@@ -649,7 +649,7 @@ static int __init lkdtm_module_init(void)
goto out_err;
}
- if (cpoint != INVALID && cptype != NONE) {
+ if (cpoint != CN_INVALID && cptype != CT_NONE) {
ret = lkdtm_register_cpoint(cpoint);
if (ret < 0) {
printk(KERN_INFO "lkdtm: Invalid crash point %d\n",
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c
index 4197a3cb26ba..b05db55c8c8e 100644
--- a/drivers/misc/phantom.c
+++ b/drivers/misc/phantom.c
@@ -343,8 +343,10 @@ static int __devinit phantom_probe(struct pci_dev *pdev,
int retval;
retval = pci_enable_device(pdev);
- if (retval)
+ if (retval) {
+ dev_err(&pdev->dev, "pci_enable_device failed!\n");
goto err;
+ }
minor = phantom_get_free();
if (minor == PHANTOM_MAX_MINORS) {
@@ -356,8 +358,10 @@ static int __devinit phantom_probe(struct pci_dev *pdev,
phantom_devices[minor] = 1;
retval = pci_request_regions(pdev, "phantom");
- if (retval)
+ if (retval) {
+ dev_err(&pdev->dev, "pci_request_regions failed!\n");
goto err_null;
+ }
retval = -ENOMEM;
pht = kzalloc(sizeof(*pht), GFP_KERNEL);
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c
index 1f59ee2226ca..17bbacb1b4b1 100644
--- a/drivers/misc/sgi-xp/xpc_uv.c
+++ b/drivers/misc/sgi-xp/xpc_uv.c
@@ -417,6 +417,7 @@ xpc_process_activate_IRQ_rcvd_uv(void)
static void
xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
struct xpc_activate_mq_msghdr_uv *msg_hdr,
+ int part_setup,
int *wakeup_hb_checker)
{
unsigned long irq_flags;
@@ -481,6 +482,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV: {
struct xpc_activate_mq_msg_chctl_closerequest_uv *msg;
+ if (!part_setup)
+ break;
+
msg = container_of(msg_hdr, struct
xpc_activate_mq_msg_chctl_closerequest_uv,
hdr);
@@ -497,6 +501,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV: {
struct xpc_activate_mq_msg_chctl_closereply_uv *msg;
+ if (!part_setup)
+ break;
+
msg = container_of(msg_hdr, struct
xpc_activate_mq_msg_chctl_closereply_uv,
hdr);
@@ -511,6 +518,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV: {
struct xpc_activate_mq_msg_chctl_openrequest_uv *msg;
+ if (!part_setup)
+ break;
+
msg = container_of(msg_hdr, struct
xpc_activate_mq_msg_chctl_openrequest_uv,
hdr);
@@ -528,6 +538,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV: {
struct xpc_activate_mq_msg_chctl_openreply_uv *msg;
+ if (!part_setup)
+ break;
+
msg = container_of(msg_hdr, struct
xpc_activate_mq_msg_chctl_openreply_uv, hdr);
args = &part->remote_openclose_args[msg->ch_number];
@@ -545,6 +558,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENCOMPLETE_UV: {
struct xpc_activate_mq_msg_chctl_opencomplete_uv *msg;
+ if (!part_setup)
+ break;
+
msg = container_of(msg_hdr, struct
xpc_activate_mq_msg_chctl_opencomplete_uv, hdr);
spin_lock_irqsave(&part->chctl_lock, irq_flags);
@@ -621,6 +637,7 @@ xpc_handle_activate_IRQ_uv(int irq, void *dev_id)
part_referenced = xpc_part_ref(part);
xpc_handle_activate_mq_msg_uv(part, msg_hdr,
+ part_referenced,
&wakeup_hb_checker);
if (part_referenced)
xpc_part_deref(part);
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 40b0fb9a47fb..d618e8673996 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -259,7 +259,7 @@ endchoice
config MMC_ATMELMCI_DMA
bool "Atmel MCI DMA support (EXPERIMENTAL)"
- depends on MMC_ATMELMCI && AVR32 && DMA_ENGINE && EXPERIMENTAL
+ depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE && EXPERIMENTAL
help
Say Y here to have the Atmel MCI driver use a DMA engine to
do data transfers and thus increase the throughput and
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 8c863ccb1bfe..e865032a52eb 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -369,6 +369,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
{
struct regulator *reg;
int ret = 0;
+ int ocr_value = 0;
switch (host->id) {
case OMAP_MMC1_DEVID:
@@ -401,6 +402,17 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
}
} else {
host->vcc = reg;
+ ocr_value = mmc_regulator_get_ocrmask(reg);
+ if (!mmc_slot(host).ocr_mask) {
+ mmc_slot(host).ocr_mask = ocr_value;
+ } else {
+ if (!(mmc_slot(host).ocr_mask & ocr_value)) {
+ pr_err("MMC%d ocrmask %x is not supported\n",
+ host->id, mmc_slot(host).ocr_mask);
+ mmc_slot(host).ocr_mask = 0;
+ return -EINVAL;
+ }
+ }
mmc_slot(host).ocr_mask = mmc_regulator_get_ocrmask(reg);
/* Allow an aux regulator */
@@ -987,6 +999,17 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) | bit);
+ /*
+ * OMAP4 ES2 and greater has an updated reset logic.
+ * Monitor a 0->1 transition first
+ */
+ if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) {
+ while ((!(OMAP_HSMMC_READ(host, SYSCTL) & bit))
+ && (i++ < limit))
+ cpu_relax();
+ }
+ i = 0;
+
while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) &&
(i++ < limit))
cpu_relax();
@@ -2008,6 +2031,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
if (res == NULL || irq < 0)
return -ENXIO;
+ res->start += pdata->reg_offset;
+ res->end += pdata->reg_offset;
res = request_mem_region(res->start, res->end - res->start + 1,
pdev->name);
if (res == NULL)
@@ -2120,23 +2145,9 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
- switch (mmc_slot(host).wires) {
- case 8:
- mmc->caps |= MMC_CAP_8_BIT_DATA;
- /* Fall through */
- case 4:
+ mmc->caps |= mmc_slot(host).caps;
+ if (mmc->caps & MMC_CAP_8_BIT_DATA)
mmc->caps |= MMC_CAP_4_BIT_DATA;
- break;
- case 1:
- /* Nothing to crib here */
- case 0:
- /* Assuming nothing was given by board, Core use's 1-Bit */
- break;
- default:
- /* Completely unexpected.. Core goes with 1-Bit Width */
- dev_crit(mmc_dev(host->mmc), "Invalid width %d\n used!"
- "using 1 instead\n", mmc_slot(host).wires);
- }
if (mmc_slot(host).nonremovable)
mmc->caps |= MMC_CAP_NONREMOVABLE;
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 3e6c47bdce53..ba29d2f0ffd7 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -418,8 +418,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
/*
* Valid primary extension versions are: 1.0, 1.1, 1.2, 1.3, 1.4
- * see: http://www.amd.com/us-en/assets/content_type/DownloadableAssets/cfi_r20.pdf, page 19
- * http://www.amd.com/us-en/assets/content_type/DownloadableAssets/cfi_100_20011201.pdf
+ * see: http://cs.ozerki.net/zap/pub/axim-x5/docs/cfi_r20.pdf, page 19
+ * http://www.spansion.com/Support/AppNotes/cfi_100_20011201.pdf
* http://www.spansion.com/Support/Datasheets/s29ws-p_00_a12_e.pdf
*/
if (extp->MajorVersion != '1' ||
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c
index f4359fe7150f..caf604167f03 100644
--- a/drivers/mtd/devices/lart.c
+++ b/drivers/mtd/devices/lart.c
@@ -17,7 +17,7 @@
* - January 2000
*
* [2] MTD internal API documentation
- * - http://www.linux-mtd.infradead.org/tech/
+ * - http://www.linux-mtd.infradead.org/
*
* Limitations:
*
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 6f512b5c117b..ea22520c0406 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -924,6 +924,13 @@ static int __devinit m25p_probe(struct spi_device *spi)
nr_parts = data->nr_parts;
}
+#ifdef CONFIG_OF
+ if (nr_parts <= 0 && spi->dev.of_node) {
+ nr_parts = of_mtd_parse_partitions(&spi->dev,
+ spi->dev.of_node, &parts);
+ }
+#endif
+
if (nr_parts > 0) {
for (i = 0; i < nr_parts; i++) {
DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index 4d6a64c387ec..037b399df3f1 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -51,7 +51,7 @@
Use of the FTL format for non-PCMCIA applications may be an
infringement of these patents. For additional information,
- contact M-Systems (http://www.m-sys.com) directly.
+ contact M-Systems directly. M-Systems since acquired by Sandisk.
======================================================================*/
#include <linux/mtd/blktrans.h>
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 701d942c6795..962212628f6e 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -172,7 +172,7 @@ config MTD_OCTAGON
This provides a 'mapping' driver which supports the way in which
the flash chips are connected in the Octagon-5066 Single Board
Computer. More information on the board is available at
- <http://www.octagonsystems.com/CPUpages/5066.html>.
+ <http://www.octagonsystems.com/products/5066.aspx>.
config MTD_VMAX
tristate "JEDEC Flash device mapped on Tempustech VMAX SBC301"
@@ -284,7 +284,7 @@ config MTD_TQM8XXL
chips, currently uses AMD one. This 'mapping' driver supports
that arrangement, allowing the CFI probe and command set driver
code to communicate with the chips on the TQM8xxL board. More at
- <http://www.denx.de/embedded-ppc-en.html>.
+ <http://www.denx.de/wiki/PPCEmbedded/>.
config MTD_RPXLITE
tristate "CFI Flash device mapped on RPX Lite or CLLF"
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index fe63f6bd663c..ec3edf6e68b4 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -294,7 +294,7 @@ static int __devinit of_flash_probe(struct platform_device *dev,
info->list[i].map.name = dev_name(&dev->dev);
info->list[i].map.phys = res.start;
info->list[i].map.size = res_size;
- info->list[i].map.bankwidth = *width;
+ info->list[i].map.bankwidth = be32_to_cpup(width);
err = -ENOMEM;
info->list[i].map.virt = ioremap(info->list[i].map.phys,
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index db1dfc5a1b11..e06c8983978e 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -2,7 +2,7 @@
* Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01
*
* The data sheet for this device can be found at:
- * http://www.marvell.com/products/pcconn/88ALP01.jsp
+ * http://wiki.laptop.org/go/Datasheets
*
* Copyright © 2006 Red Hat, Inc.
* Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index 2ac7367afe77..8beb0d0233b5 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -35,6 +35,7 @@
#include <linux/slab.h>
#include <mach/nand.h>
+#include <mach/aemif.h>
#include <asm/mach-types.h>
@@ -74,6 +75,8 @@ struct davinci_nand_info {
uint32_t mask_cle;
uint32_t core_chipsel;
+
+ struct davinci_aemif_timing *timing;
};
static DEFINE_SPINLOCK(davinci_nand_lock);
@@ -478,36 +481,6 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd)
return davinci_nand_readl(info, NANDFSR_OFFSET) & BIT(0);
}
-static void __init nand_dm6446evm_flash_init(struct davinci_nand_info *info)
-{
- uint32_t regval, a1cr;
-
- /*
- * NAND FLASH timings @ PLL1 == 459 MHz
- * - AEMIF.CLK freq = PLL1/6 = 459/6 = 76.5 MHz
- * - AEMIF.CLK period = 1/76.5 MHz = 13.1 ns
- */
- regval = 0
- | (0 << 31) /* selectStrobe */
- | (0 << 30) /* extWait (never with NAND) */
- | (1 << 26) /* writeSetup 10 ns */
- | (3 << 20) /* writeStrobe 40 ns */
- | (1 << 17) /* writeHold 10 ns */
- | (0 << 13) /* readSetup 10 ns */
- | (3 << 7) /* readStrobe 60 ns */
- | (0 << 4) /* readHold 10 ns */
- | (3 << 2) /* turnAround ?? ns */
- | (0 << 0) /* asyncSize 8-bit bus */
- ;
- a1cr = davinci_nand_readl(info, A1CR_OFFSET);
- if (a1cr != regval) {
- dev_dbg(info->dev, "Warning: NAND config: Set A1CR " \
- "reg to 0x%08x, was 0x%08x, should be done by " \
- "bootloader.\n", regval, a1cr);
- davinci_nand_writel(info, A1CR_OFFSET, regval);
- }
-}
-
/*----------------------------------------------------------------------*/
/* An ECC layout for using 4-bit ECC with small-page flash, storing
@@ -611,6 +584,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
info->chip.options = pdata->options;
info->chip.bbt_td = pdata->bbt_td;
info->chip.bbt_md = pdata->bbt_md;
+ info->timing = pdata->timing;
info->ioaddr = (uint32_t __force) vaddr;
@@ -688,15 +662,25 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
goto err_clk_enable;
}
- /* EMIF timings should normally be set by the boot loader,
- * especially after boot-from-NAND. The *only* reason to
- * have this special casing for the DM6446 EVM is to work
- * with boot-from-NOR ... with CS0 manually re-jumpered
- * (after startup) so it addresses the NAND flash, not NOR.
- * Even for dev boards, that's unusually rude...
+ /*
+ * Setup Async configuration register in case we did not boot from
+ * NAND and so bootloader did not bother to set it up.
*/
- if (machine_is_davinci_evm())
- nand_dm6446evm_flash_init(info);
+ val = davinci_nand_readl(info, A1CR_OFFSET + info->core_chipsel * 4);
+
+ /* Extended Wait is not valid and Select Strobe mode is not used */
+ val &= ~(ACR_ASIZE_MASK | ACR_EW_MASK | ACR_SS_MASK);
+ if (info->chip.options & NAND_BUSWIDTH_16)
+ val |= 0x1;
+
+ davinci_nand_writel(info, A1CR_OFFSET + info->core_chipsel * 4, val);
+
+ ret = davinci_aemif_setup_timing(info->timing, info->base,
+ info->core_chipsel);
+ if (ret < 0) {
+ dev_dbg(&pdev->dev, "NAND timing values setup fail\n");
+ goto err_timing;
+ }
spin_lock_irq(&davinci_nand_lock);
@@ -809,6 +793,7 @@ syndrome_done:
return 0;
err_scan:
+err_timing:
clk_disable(info->clk);
err_clk_enable:
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
index 8bf7dc6d1ce6..7bd171eefd21 100644
--- a/drivers/mtd/ofpart.c
+++ b/drivers/mtd/ofpart.c
@@ -53,8 +53,8 @@ int __devinit of_mtd_parse_partitions(struct device *dev,
continue;
}
- (*pparts)[i].offset = reg[0];
- (*pparts)[i].size = reg[1];
+ (*pparts)[i].offset = be32_to_cpu(reg[0]);
+ (*pparts)[i].size = be32_to_cpu(reg[1]);
partname = of_get_property(pp, "label", &len);
if (!partname)
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index baac246561b9..4777a1cbcd8d 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -337,10 +337,10 @@ el2_probe1(struct net_device *dev, int ioaddr)
/* Finish setting the board's parameters. */
ei_status.stop_page = EL2_MB1_STOP_PG;
ei_status.word16 = wordlength;
- ei_status.reset_8390 = &el2_reset_8390;
- ei_status.get_8390_hdr = &el2_get_8390_hdr;
- ei_status.block_input = &el2_block_input;
- ei_status.block_output = &el2_block_output;
+ ei_status.reset_8390 = el2_reset_8390;
+ ei_status.get_8390_hdr = el2_get_8390_hdr;
+ ei_status.block_input = el2_block_input;
+ ei_status.block_output = el2_block_output;
if (dev->irq == 2)
dev->irq = 9;
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 3bba835f1a21..cdf7226a7c43 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -662,7 +662,9 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr,
pr_warning(" *** Warning: this IRQ is unlikely to work! ***\n");
{
- char *ram_split[] = { "5:3", "3:1", "1:1", "3:5" };
+ static const char * const ram_split[] = {
+ "5:3", "3:1", "1:1", "3:5"
+ };
__u32 config;
EL3WINDOW(3);
vp->available_media = inw(ioaddr + Wn3_Options);
@@ -734,7 +736,7 @@ static int corkscrew_open(struct net_device *dev)
init_timer(&vp->timer);
vp->timer.expires = jiffies + media_tbl[dev->if_port].wait;
vp->timer.data = (unsigned long) dev;
- vp->timer.function = &corkscrew_timer; /* timer handler */
+ vp->timer.function = corkscrew_timer; /* timer handler */
add_timer(&vp->timer);
} else
dev->if_port = vp->default_media;
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index a7b0e5e43a52..de579d043169 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -287,7 +287,7 @@ static int elmc_open(struct net_device *dev)
elmc_id_attn586(); /* disable interrupts */
- ret = request_irq(dev->irq, elmc_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+ ret = request_irq(dev->irq, elmc_interrupt, IRQF_SHARED,
dev->name, dev);
if (ret) {
pr_err("%s: couldn't get irq %d\n", dev->name, dev->irq);
@@ -463,7 +463,7 @@ static int __init do_elmc_probe(struct net_device *dev)
/* we didn't find any 3c523 in the slots we checked for */
if (slot == MCA_NOTFOUND)
- return ((base_addr || irq) ? -ENXIO : -ENODEV);
+ return (base_addr || irq) ? -ENXIO : -ENODEV;
mca_set_adapter_name(slot, "3Com 3c523 Etherlink/MC");
mca_set_adapter_procfn(slot, (MCA_ProcFn) elmc_getinfo, dev);
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index eca55c52bdfd..013b7c396663 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -443,7 +443,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
* Grab the IRQ
*/
- err = request_irq(dev->irq, mc32_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, DRV_NAME, dev);
+ err = request_irq(dev->irq, mc32_interrupt, IRQF_SHARED, DRV_NAME, dev);
if (err) {
release_region(dev->base_addr, MC32_IO_EXTENT);
pr_err("%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq);
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 179871d9e71f..e1da258bbfb7 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -1742,7 +1742,7 @@ vortex_open(struct net_device *dev)
/* Use the now-standard shared IRQ implementation. */
if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ?
- &boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev))) {
+ boomerang_interrupt : vortex_interrupt, IRQF_SHARED, dev->name, dev))) {
pr_err("%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
goto err;
}
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 4a4f6b81e32d..ac422cd332ea 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -561,7 +561,7 @@ rx_status_loop:
if (cp_rx_csum_ok(status))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
skb_put(skb, len);
@@ -754,7 +754,7 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
}
#if CP_VLAN_TAG_USED
- if (cp->vlgrp && vlan_tx_tag_present(skb))
+ if (vlan_tx_tag_present(skb))
vlan_tag = TxVlanTag | swab16(vlan_tx_tag_get(skb));
#endif
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 77efe462b921..9334539ebf75 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -180,6 +180,13 @@ config NET_SB1000
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"
#
@@ -215,13 +222,6 @@ menuconfig NET_ETHERNET
if NET_ETHERNET
-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 lack MII.
-
config MACB
tristate "Atmel MACB support"
depends on HAVE_NET_MACB
@@ -883,14 +883,6 @@ config BFIN_RX_DESC_NUM
help
Set the number of buffer packets used in driver.
-config BFIN_MAC_RMII
- bool "RMII PHY Interface"
- depends on BFIN_MAC
- default y if BFIN527_EZKIT
- default n if BFIN537_STAMP
- help
- Use Reduced PHY MII Interface
-
config BFIN_MAC_USE_HWSTAMP
bool "Use IEEE 1588 hwstamp"
depends on BFIN_MAC && BF518
@@ -924,7 +916,7 @@ config SMC91X
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.linuxdoc.org/docs.html#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).
@@ -954,6 +946,8 @@ config NET_NETX
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 .
@@ -961,6 +955,25 @@ config TI_DAVINCI_EMAC
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
@@ -1028,13 +1041,13 @@ config SMC911X
tristate "SMSC LAN911[5678] support"
select CRC32
select MII
- depends on ARM || SUPERH
+ 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.linuxdoc.org/docs.html#howto>.
+ <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
@@ -1042,7 +1055,7 @@ config SMC911X
config SMSC911X
tristate "SMSC LAN911x/LAN921x families embedded ethernet support"
- depends on ARM || SUPERH || BLACKFIN || MIPS
+ depends on ARM || SUPERH || BLACKFIN || MIPS || MN10300
select CRC32
select MII
select PHYLIB
@@ -1054,6 +1067,14 @@ config SMSC911X
<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
@@ -1516,7 +1537,7 @@ config E100
For the latest Intel PRO/100 network driver for Linux, see:
- <http://appsr.intel.com/scripts-df/support_intel.asp>
+ <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>.
@@ -1542,9 +1563,8 @@ config FEALNX
select CRC32
select MII
help
- Say Y here to support the Mysom MTD-800 family of PCI-based Ethernet
- cards. Specifications and data at
- <http://www.myson.com.hk/mtd/datasheet/>.
+ 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"
@@ -1718,7 +1738,7 @@ config SMSC9420
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.linuxdoc.org/docs.html#howto>.
+ <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
@@ -2518,6 +2538,18 @@ config S6GMAC
source "drivers/net/stmmac/Kconfig"
+config PCH_GBE
+ tristate "PCH Gigabit Ethernet"
+ depends on PCI
+ ---help---
+ This is a gigabit ethernet driver for Topcliff PCH.
+ Topcliff PCH is the platform controller hub that is used in Intel's
+ general embedded platform.
+ Topcliff 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.
+
endif # NETDEV_1000
#
@@ -2553,7 +2585,7 @@ config CHELSIO_T1
our website at <http://www.chelsio.com>.
For customer support, please visit our customer support page at
- <http://www.chelsio.com/support.htm>.
+ <http://www.chelsio.com/support.html>.
Please send feedback to <linux-bugs@chelsio.com>.
@@ -2585,7 +2617,7 @@ config CHELSIO_T3
our website at <http://www.chelsio.com>.
For customer support, please visit our customer support page at
- <http://www.chelsio.com/support.htm>.
+ <http://www.chelsio.com/support.html>.
Please send feedback to <linux-bugs@chelsio.com>.
@@ -2610,7 +2642,7 @@ config CHELSIO_T4
our website at <http://www.chelsio.com>.
For customer support, please visit our customer support page at
- <http://www.chelsio.com/support.htm>.
+ <http://www.chelsio.com/support.html>.
Please send feedback to <linux-bugs@chelsio.com>.
@@ -2633,7 +2665,7 @@ config CHELSIO_T4VF
our website at <http://www.chelsio.com>.
For customer support, please visit our customer support page at
- <http://www.chelsio.com/support.htm>.
+ <http://www.chelsio.com/support.html>.
Please send feedback to <linux-bugs@chelsio.com>.
@@ -2872,6 +2904,20 @@ config QLGE
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"
@@ -3205,6 +3251,17 @@ config 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
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 3e8f150c4b14..652fc6b98039 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -7,6 +7,8 @@ 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/
@@ -34,6 +36,7 @@ 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 \
@@ -162,6 +165,7 @@ 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
@@ -296,3 +300,4 @@ obj-$(CONFIG_WIMAX) += wimax/
obj-$(CONFIG_CAIF) += caif/
obj-$(CONFIG_OCTEON_MGMT_ETHERNET) += octeon/
+obj-$(CONFIG_PCH_GBE) += pch_gbe/
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index b9a591604e5b..41d9911202d0 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -2033,7 +2033,7 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
skb->csum = htons(csum);
skb->ip_summed = CHECKSUM_COMPLETE;
} else {
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
}
/* send it up */
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index 585c25f4b60c..2ca880b4c0db 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -396,7 +396,7 @@ static int amd8111e_set_coalesce(struct net_device * dev, enum coal_mode cmod)
event_count = coal_conf->rx_event_count;
if( timeout > MAX_TIMEOUT ||
event_count > MAX_EVENT_COUNT )
- return -EINVAL;
+ return -EINVAL;
timeout = timeout * DELAY_TIMER_CONV;
writel(VAL0|STINTEN, mmio+INTEN0);
@@ -409,7 +409,7 @@ static int amd8111e_set_coalesce(struct net_device * dev, enum coal_mode cmod)
event_count = coal_conf->tx_event_count;
if( timeout > MAX_TIMEOUT ||
event_count > MAX_EVENT_COUNT )
- return -EINVAL;
+ return -EINVAL;
timeout = timeout * DELAY_TIMER_CONV;
@@ -903,18 +903,18 @@ static int amd8111e_read_mib(void __iomem *mmio, u8 MIB_COUNTER)
}
/*
-This function reads the mib registers and returns the hardware statistics. It updates previous internal driver statistics with new values.
-*/
-static struct net_device_stats *amd8111e_get_stats(struct net_device * dev)
+ * This function reads the mib registers and returns the hardware statistics.
+ * It updates previous internal driver statistics with new values.
+ */
+static struct net_device_stats *amd8111e_get_stats(struct net_device *dev)
{
struct amd8111e_priv *lp = netdev_priv(dev);
void __iomem *mmio = lp->mmio;
unsigned long flags;
- /* struct net_device_stats *prev_stats = &lp->prev_stats; */
- struct net_device_stats* new_stats = &lp->stats;
+ struct net_device_stats *new_stats = &dev->stats;
- if(!lp->opened)
- return &lp->stats;
+ if (!lp->opened)
+ return new_stats;
spin_lock_irqsave (&lp->lock, flags);
/* stats.rx_packets */
@@ -1315,7 +1315,7 @@ static netdev_tx_t amd8111e_start_xmit(struct sk_buff *skb,
lp->tx_ring[tx_index].tx_flags = 0;
#if AMD8111E_VLAN_TAG_USED
- if((lp->vlgrp != NULL) && vlan_tx_tag_present(skb)){
+ if (vlan_tx_tag_present(skb)) {
lp->tx_ring[tx_index].tag_ctrl_cmd |=
cpu_to_le16(TCC_VLAN_INSERT);
lp->tx_ring[tx_index].tag_ctrl_info =
diff --git a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h
index ac36eb6981e3..b5926af03a7e 100644
--- a/drivers/net/amd8111e.h
+++ b/drivers/net/amd8111e.h
@@ -787,7 +787,6 @@ struct amd8111e_priv{
struct vlan_group *vlgrp;
#endif
char opened;
- struct net_device_stats stats;
unsigned int drv_rx_errors;
struct amd8111e_coalesce_conf coal_conf;
diff --git a/drivers/net/appletalk/Kconfig b/drivers/net/appletalk/Kconfig
index 20f97e7017ce..0b376a990972 100644
--- a/drivers/net/appletalk/Kconfig
+++ b/drivers/net/appletalk/Kconfig
@@ -19,7 +19,7 @@ config ATALK
General information about how to connect Linux, Windows machines and
Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>. The
- NET-3-HOWTO, available from
+ NET3-4-HOWTO, available from
<http://www.tldp.org/docs.html#howto>, contains valuable
information as well.
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index 0362c8d31a08..10d0dba572c2 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -244,7 +244,7 @@ static int ipddp_delete(struct ipddp_route *rt)
}
spin_unlock_bh(&ipddp_route_lock);
- return (-ENOENT);
+ return -ENOENT;
}
/*
@@ -259,10 +259,10 @@ static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt)
if(f->ip == rt->ip &&
f->at.s_net == rt->at.s_net &&
f->at.s_node == rt->at.s_node)
- return (f);
+ return f;
}
- return (NULL);
+ return NULL;
}
static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -279,7 +279,7 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
switch(cmd)
{
case SIOCADDIPDDPRT:
- return (ipddp_create(&rcp));
+ return ipddp_create(&rcp);
case SIOCFINDIPDDPRT:
spin_lock_bh(&ipddp_route_lock);
@@ -297,7 +297,7 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -ENOENT;
case SIOCDELIPDDPRT:
- return (ipddp_delete(&rcp));
+ return ipddp_delete(&rcp);
default:
return -EINVAL;
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index adc07551739e..e69eead12ec7 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -727,7 +727,7 @@ static int sendup_buffer (struct net_device *dev)
if (ltc->command != LT_RCVLAP) {
printk("unknown command 0x%02x from ltpc card\n",ltc->command);
- return(-1);
+ return -1;
}
dnode = ltc->dnode;
snode = ltc->snode;
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 8c496fb1ac9e..62f21106efec 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -300,8 +300,6 @@ am79c961_open(struct net_device *dev)
struct dev_priv *priv = netdev_priv(dev);
int ret;
- memset (&priv->stats, 0, sizeof (priv->stats));
-
ret = request_irq(dev->irq, am79c961_interrupt, 0, dev->name, dev);
if (ret)
return ret;
@@ -347,8 +345,7 @@ am79c961_close(struct net_device *dev)
*/
static struct net_device_stats *am79c961_getstats (struct net_device *dev)
{
- struct dev_priv *priv = netdev_priv(dev);
- return &priv->stats;
+ return &dev->stats;
}
static void am79c961_mc_hash(char *addr, unsigned short *hash)
@@ -510,14 +507,14 @@ am79c961_rx(struct net_device *dev, struct dev_priv *priv)
if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP)) {
am_writeword (dev, hdraddr + 2, RMD_OWN);
- priv->stats.rx_errors ++;
+ dev->stats.rx_errors++;
if (status & RMD_ERR) {
if (status & RMD_FRAM)
- priv->stats.rx_frame_errors ++;
+ dev->stats.rx_frame_errors++;
if (status & RMD_CRC)
- priv->stats.rx_crc_errors ++;
+ dev->stats.rx_crc_errors++;
} else if (status & RMD_STP)
- priv->stats.rx_length_errors ++;
+ dev->stats.rx_length_errors++;
continue;
}
@@ -531,12 +528,12 @@ am79c961_rx(struct net_device *dev, struct dev_priv *priv)
am_writeword(dev, hdraddr + 2, RMD_OWN);
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
- priv->stats.rx_bytes += len;
- priv->stats.rx_packets ++;
+ dev->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
} else {
am_writeword (dev, hdraddr + 2, RMD_OWN);
printk (KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name);
- priv->stats.rx_dropped ++;
+ dev->stats.rx_dropped++;
break;
}
} while (1);
@@ -565,7 +562,7 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
if (status & TMD_ERR) {
u_int status2;
- priv->stats.tx_errors ++;
+ dev->stats.tx_errors++;
status2 = am_readword (dev, hdraddr + 6);
@@ -575,18 +572,18 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
am_writeword (dev, hdraddr + 6, 0);
if (status2 & TST_RTRY)
- priv->stats.collisions += 16;
+ dev->stats.collisions += 16;
if (status2 & TST_LCOL)
- priv->stats.tx_window_errors ++;
+ dev->stats.tx_window_errors++;
if (status2 & TST_LCAR)
- priv->stats.tx_carrier_errors ++;
+ dev->stats.tx_carrier_errors++;
if (status2 & TST_UFLO)
- priv->stats.tx_fifo_errors ++;
+ dev->stats.tx_fifo_errors++;
continue;
}
- priv->stats.tx_packets ++;
+ dev->stats.tx_packets++;
len = am_readword (dev, hdraddr + 4);
- priv->stats.tx_bytes += -len;
+ dev->stats.tx_bytes += -len;
} while (priv->txtail != priv->txhead);
netif_wake_queue(dev);
@@ -616,7 +613,7 @@ am79c961_interrupt(int irq, void *dev_id)
}
if (status & CSR0_MISS) {
handled = 1;
- priv->stats.rx_dropped ++;
+ dev->stats.rx_dropped++;
}
if (status & CSR0_CERR) {
handled = 1;
diff --git a/drivers/net/arm/am79c961a.h b/drivers/net/arm/am79c961a.h
index 483009fe6ec2..fd634d32756b 100644
--- a/drivers/net/arm/am79c961a.h
+++ b/drivers/net/arm/am79c961a.h
@@ -130,7 +130,6 @@
#define ISALED0_LNKST 0x8000
struct dev_priv {
- struct net_device_stats stats;
unsigned long rxbuffer[RX_BUFFERS];
unsigned long txbuffer[TX_BUFFERS];
unsigned char txhead;
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index 4a5ec9470aa1..5a77001b6d10 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -175,8 +175,6 @@ struct ep93xx_priv
struct net_device *dev;
struct napi_struct napi;
- struct net_device_stats stats;
-
struct mii_if_info mii;
u8 mdc_divisor;
};
@@ -230,12 +228,6 @@ static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int d
pr_info("mdio write timed out\n");
}
-static struct net_device_stats *ep93xx_get_stats(struct net_device *dev)
-{
- struct ep93xx_priv *ep = netdev_priv(dev);
- return &(ep->stats);
-}
-
static int ep93xx_rx(struct net_device *dev, int processed, int budget)
{
struct ep93xx_priv *ep = netdev_priv(dev);
@@ -267,15 +259,15 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget)
pr_crit("entry mismatch %.8x %.8x\n", rstat0, rstat1);
if (!(rstat0 & RSTAT0_RWE)) {
- ep->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rstat0 & RSTAT0_OE)
- ep->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if (rstat0 & RSTAT0_FE)
- ep->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rstat0 & (RSTAT0_RUNT | RSTAT0_EDATA))
- ep->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (rstat0 & RSTAT0_CRCE)
- ep->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
goto err;
}
@@ -300,10 +292,10 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget)
netif_receive_skb(skb);
- ep->stats.rx_packets++;
- ep->stats.rx_bytes += length;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += length;
} else {
- ep->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
err:
@@ -359,7 +351,7 @@ static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev)
int entry;
if (unlikely(skb->len > MAX_PKT_SIZE)) {
- ep->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -415,17 +407,17 @@ static void ep93xx_tx_complete(struct net_device *dev)
if (tstat0 & TSTAT0_TXWE) {
int length = ep->descs->tdesc[entry].tdesc1 & 0xfff;
- ep->stats.tx_packets++;
- ep->stats.tx_bytes += length;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += length;
} else {
- ep->stats.tx_errors++;
+ dev->stats.tx_errors++;
}
if (tstat0 & TSTAT0_OW)
- ep->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (tstat0 & TSTAT0_TXU)
- ep->stats.tx_fifo_errors++;
- ep->stats.collisions += (tstat0 >> 16) & 0x1f;
+ dev->stats.tx_fifo_errors++;
+ dev->stats.collisions += (tstat0 >> 16) & 0x1f;
ep->tx_clean_pointer = (entry + 1) & (TX_QUEUE_ENTRIES - 1);
if (ep->tx_pending == TX_QUEUE_ENTRIES)
@@ -758,7 +750,6 @@ static const struct net_device_ops ep93xx_netdev_ops = {
.ndo_open = ep93xx_open,
.ndo_stop = ep93xx_close,
.ndo_start_xmit = ep93xx_xmit,
- .ndo_get_stats = ep93xx_get_stats,
.ndo_do_ioctl = ep93xx_ioctl,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index b17ab5153f51..b00781c02d5d 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -68,7 +68,6 @@ static int ether1_open(struct net_device *dev);
static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t ether1_interrupt(int irq, void *dev_id);
static int ether1_close(struct net_device *dev);
-static struct net_device_stats *ether1_getstats(struct net_device *dev);
static void ether1_setmulticastlist(struct net_device *dev);
static void ether1_timeout(struct net_device *dev);
@@ -649,8 +648,6 @@ ether1_open (struct net_device *dev)
if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev))
return -EAGAIN;
- memset (&priv(dev)->stats, 0, sizeof (struct net_device_stats));
-
if (ether1_init_for_open (dev)) {
free_irq (dev->irq, dev);
return -EAGAIN;
@@ -673,7 +670,7 @@ ether1_timeout(struct net_device *dev)
if (ether1_init_for_open (dev))
printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
- priv(dev)->stats.tx_errors++;
+ dev->stats.tx_errors++;
netif_wake_queue(dev);
}
@@ -802,21 +799,21 @@ again:
while (nop.nop_status & STAT_COMPLETE) {
if (nop.nop_status & STAT_OK) {
- priv(dev)->stats.tx_packets ++;
- priv(dev)->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
+ dev->stats.tx_packets++;
+ dev->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
} else {
- priv(dev)->stats.tx_errors ++;
+ dev->stats.tx_errors++;
if (nop.nop_status & STAT_COLLAFTERTX)
- priv(dev)->stats.collisions ++;
+ dev->stats.collisions++;
if (nop.nop_status & STAT_NOCARRIER)
- priv(dev)->stats.tx_carrier_errors ++;
+ dev->stats.tx_carrier_errors++;
if (nop.nop_status & STAT_TXLOSTCTS)
printk (KERN_WARNING "%s: cts lost\n", dev->name);
if (nop.nop_status & STAT_TXSLOWDMA)
- priv(dev)->stats.tx_fifo_errors ++;
+ dev->stats.tx_fifo_errors++;
if (nop.nop_status & STAT_COLLEXCESSIVE)
- priv(dev)->stats.collisions += 16;
+ dev->stats.collisions += 16;
}
if (nop.nop_link == caddr) {
@@ -879,13 +876,13 @@ ether1_recv_done (struct net_device *dev)
skb->protocol = eth_type_trans (skb, dev);
netif_rx (skb);
- priv(dev)->stats.rx_packets ++;
+ dev->stats.rx_packets++;
} else
- priv(dev)->stats.rx_dropped ++;
+ dev->stats.rx_dropped++;
} else {
printk(KERN_WARNING "%s: %s\n", dev->name,
(rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");
- priv(dev)->stats.rx_dropped ++;
+ dev->stats.rx_dropped++;
}
nexttail = ether1_readw(dev, priv(dev)->rx_tail, rfd_t, rfd_link, NORMALIRQS);
@@ -939,7 +936,7 @@ ether1_interrupt (int irq, void *dev_id)
printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name);
ether1_writew(dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
writeb(CTRL_CA, REG_CONTROL);
- priv(dev)->stats.rx_dropped ++; /* we suspended due to lack of buffer space */
+ dev->stats.rx_dropped++; /* we suspended due to lack of buffer space */
} else
printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,
ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));
@@ -962,12 +959,6 @@ ether1_close (struct net_device *dev)
return 0;
}
-static struct net_device_stats *
-ether1_getstats (struct net_device *dev)
-{
- return &priv(dev)->stats;
-}
-
/*
* Set or clear the multicast filter for this adaptor.
* num_addrs == -1 Promiscuous mode, receive all packets.
@@ -994,7 +985,6 @@ static const struct net_device_ops ether1_netdev_ops = {
.ndo_open = ether1_open,
.ndo_stop = ether1_close,
.ndo_start_xmit = ether1_sendpacket,
- .ndo_get_stats = ether1_getstats,
.ndo_set_multicast_list = ether1_setmulticastlist,
.ndo_tx_timeout = ether1_timeout,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/arm/ether1.h b/drivers/net/arm/ether1.h
index c8a4b2389d85..3a5830ab3dc7 100644
--- a/drivers/net/arm/ether1.h
+++ b/drivers/net/arm/ether1.h
@@ -38,7 +38,6 @@
struct ether1_priv {
void __iomem *base;
- struct net_device_stats stats;
unsigned int tx_link;
unsigned int tx_head;
volatile unsigned int tx_tail;
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index 1361b7367c28..44a8746f4014 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -81,7 +81,6 @@ static int ether3_open (struct net_device *dev);
static int ether3_sendpacket (struct sk_buff *skb, struct net_device *dev);
static irqreturn_t ether3_interrupt (int irq, void *dev_id);
static int ether3_close (struct net_device *dev);
-static struct net_device_stats *ether3_getstats (struct net_device *dev);
static void ether3_setmulticastlist (struct net_device *dev);
static void ether3_timeout(struct net_device *dev);
@@ -323,8 +322,6 @@ ether3_init_for_open(struct net_device *dev)
{
int i;
- memset(&priv(dev)->stats, 0, sizeof(struct net_device_stats));
-
/* Reset the chip */
ether3_outw(CFG2_RESET, REG_CONFIG2);
udelay(4);
@@ -442,15 +439,6 @@ ether3_close(struct net_device *dev)
}
/*
- * Get the current statistics. This may be called with the card open or
- * closed.
- */
-static struct net_device_stats *ether3_getstats(struct net_device *dev)
-{
- return &priv(dev)->stats;
-}
-
-/*
* Set or clear promiscuous/multicast mode filter for this adaptor.
*
* We don't attempt any packet filtering. The card may have a SEEQ 8004
@@ -490,7 +478,7 @@ static void ether3_timeout(struct net_device *dev)
local_irq_restore(flags);
priv(dev)->regs.config2 |= CFG2_CTRLO;
- priv(dev)->stats.tx_errors += 1;
+ dev->stats.tx_errors += 1;
ether3_outw(priv(dev)->regs.config2, REG_CONFIG2);
priv(dev)->tx_head = priv(dev)->tx_tail = 0;
@@ -509,7 +497,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
if (priv(dev)->broken) {
dev_kfree_skb(skb);
- priv(dev)->stats.tx_dropped ++;
+ dev->stats.tx_dropped++;
netif_start_queue(dev);
return NETDEV_TX_OK;
}
@@ -673,7 +661,7 @@ if (next_ptr < RX_START || next_ptr >= RX_END) {
} else
goto dropping;
} else {
- struct net_device_stats *stats = &priv(dev)->stats;
+ struct net_device_stats *stats = &dev->stats;
ether3_outw(next_ptr >> 8, REG_RECVEND);
if (status & RXSTAT_OVERSIZE) stats->rx_over_errors ++;
if (status & RXSTAT_CRCERROR) stats->rx_crc_errors ++;
@@ -685,14 +673,14 @@ if (next_ptr < RX_START || next_ptr >= RX_END) {
while (-- maxcnt);
done:
- priv(dev)->stats.rx_packets += received;
+ dev->stats.rx_packets += received;
priv(dev)->rx_head = next_ptr;
/*
* If rx went off line, then that means that the buffer may be full. We
* have dropped at least one packet.
*/
if (!(ether3_inw(REG_STATUS) & STAT_RXON)) {
- priv(dev)->stats.rx_dropped ++;
+ dev->stats.rx_dropped++;
ether3_outw(next_ptr, REG_RECVPTR);
ether3_outw(priv(dev)->regs.command | CMD_RXON, REG_COMMAND);
}
@@ -710,7 +698,7 @@ dropping:{
last_warned = jiffies;
printk("%s: memory squeeze, dropping packet.\n", dev->name);
}
- priv(dev)->stats.rx_dropped ++;
+ dev->stats.rx_dropped++;
goto done;
}
}
@@ -743,13 +731,13 @@ static void ether3_tx(struct net_device *dev)
* Update errors
*/
if (!(status & (TXSTAT_BABBLED | TXSTAT_16COLLISIONS)))
- priv(dev)->stats.tx_packets++;
+ dev->stats.tx_packets++;
else {
- priv(dev)->stats.tx_errors ++;
+ dev->stats.tx_errors++;
if (status & TXSTAT_16COLLISIONS)
- priv(dev)->stats.collisions += 16;
+ dev->stats.collisions += 16;
if (status & TXSTAT_BABBLED)
- priv(dev)->stats.tx_fifo_errors ++;
+ dev->stats.tx_fifo_errors++;
}
tx_tail = (tx_tail + 1) & 15;
@@ -773,7 +761,6 @@ static const struct net_device_ops ether3_netdev_ops = {
.ndo_open = ether3_open,
.ndo_stop = ether3_close,
.ndo_start_xmit = ether3_sendpacket,
- .ndo_get_stats = ether3_getstats,
.ndo_set_multicast_list = ether3_setmulticastlist,
.ndo_tx_timeout = ether3_timeout,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/arm/ether3.h b/drivers/net/arm/ether3.h
index 1921a3a07da7..2db63b08bdf3 100644
--- a/drivers/net/arm/ether3.h
+++ b/drivers/net/arm/ether3.h
@@ -164,7 +164,6 @@ struct dev_priv {
unsigned char tx_head; /* buffer nr to insert next packet */
unsigned char tx_tail; /* buffer nr of transmitting packet */
unsigned int rx_head; /* address to fetch next packet from */
- struct net_device_stats stats;
struct timer_list timer;
int broken; /* 0 = ok, 1 = something went wrong */
};
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index b57d7dee389a..3134e5326231 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -362,7 +362,7 @@ static void *slow_memcpy( void *dst, const void *src, size_t len )
*cto++ = *cfrom++;
MFPDELAY();
}
- return( dst );
+ return dst;
}
@@ -449,7 +449,7 @@ static noinline int __init addr_accessible(volatile void *regp, int wordflag,
vbr[2] = save_berr;
local_irq_restore(flags);
- return( ret );
+ return ret;
}
static const struct net_device_ops lance_netdev_ops = {
@@ -526,7 +526,7 @@ static unsigned long __init lance_probe1( struct net_device *dev,
goto probe_ok;
probe_fail:
- return( 0 );
+ return 0;
probe_ok:
lp = netdev_priv(dev);
@@ -556,7 +556,7 @@ static unsigned long __init lance_probe1( struct net_device *dev,
if (request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO,
"PAM/Riebl-ST Ethernet", dev)) {
printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 );
- return( 0 );
+ return 0;
}
dev->irq = (unsigned short)IRQ_AUTO_5;
}
@@ -568,12 +568,12 @@ static unsigned long __init lance_probe1( struct net_device *dev,
unsigned long irq = atari_register_vme_int();
if (!irq) {
printk( "Lance: request for VME interrupt failed\n" );
- return( 0 );
+ return 0;
}
if (request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO,
"Riebl-VME Ethernet", dev)) {
printk( "Lance: request for irq %ld failed\n", irq );
- return( 0 );
+ return 0;
}
dev->irq = irq;
}
@@ -637,7 +637,7 @@ static unsigned long __init lance_probe1( struct net_device *dev,
/* XXX MSch */
dev->watchdog_timeo = TX_TIMEOUT;
- return( 1 );
+ return 1;
}
@@ -666,7 +666,7 @@ static int lance_open( struct net_device *dev )
DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n",
dev->name, i, DREG ));
DREG = CSR0_STOP;
- return( -EIO );
+ return -EIO;
}
DREG = CSR0_IDON;
DREG = CSR0_STRT;
@@ -676,7 +676,7 @@ static int lance_open( struct net_device *dev )
DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
- return( 0 );
+ return 0;
}
@@ -1126,13 +1126,13 @@ static int lance_set_mac_address( struct net_device *dev, void *addr )
int i;
if (lp->cardtype != OLD_RIEBL && lp->cardtype != NEW_RIEBL)
- return( -EOPNOTSUPP );
+ return -EOPNOTSUPP;
if (netif_running(dev)) {
/* Only possible while card isn't started */
DPRINTK( 1, ( "%s: hwaddr can be set only while card isn't open.\n",
dev->name ));
- return( -EIO );
+ return -EIO;
}
memcpy( dev->dev_addr, saddr->sa_data, dev->addr_len );
@@ -1142,7 +1142,7 @@ static int lance_set_mac_address( struct net_device *dev, void *addr )
/* set also the magic for future sessions */
*RIEBL_MAGIC_ADDR = RIEBL_MAGIC;
- return( 0 );
+ return 0;
}
diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h
index 52abbbdf8a08..9ab58097fa2e 100644
--- a/drivers/net/atl1c/atl1c.h
+++ b/drivers/net/atl1c/atl1c.h
@@ -559,7 +559,6 @@ struct atl1c_adapter {
struct napi_struct napi;
struct atl1c_hw hw;
struct atl1c_hw_stats hw_stats;
- struct net_device_stats net_stats;
struct mii_if_info mii; /* MII interface info */
u16 rx_buffer_len;
@@ -632,8 +631,6 @@ struct atl1c_adapter {
extern char atl1c_driver_name[];
extern char atl1c_driver_version[];
-extern int atl1c_up(struct atl1c_adapter *adapter);
-extern void atl1c_down(struct atl1c_adapter *adapter);
extern void atl1c_reinit_locked(struct atl1c_adapter *adapter);
extern s32 atl1c_reset_hw(struct atl1c_hw *hw);
extern void atl1c_set_ethtool_ops(struct net_device *netdev);
diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c
index d8501f060957..919080b2c3a5 100644
--- a/drivers/net/atl1c/atl1c_hw.c
+++ b/drivers/net/atl1c/atl1c_hw.c
@@ -480,7 +480,7 @@ int atl1c_phy_reset(struct atl1c_hw *hw)
atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x929D);
}
if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b2
- || hw->nic_type == athr_l2c || hw->nic_type == athr_l2c) {
+ || hw->nic_type == athr_l2c) {
atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD);
}
diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
index c7b8ef507ebd..09b099bfab2b 100644
--- a/drivers/net/atl1c/atl1c_main.c
+++ b/drivers/net/atl1c/atl1c_main.c
@@ -66,6 +66,8 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup);
static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter);
static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que,
int *work_done, int work_to_do);
+static int atl1c_up(struct atl1c_adapter *adapter);
+static void atl1c_down(struct atl1c_adapter *adapter);
static const u16 atl1c_pay_load_size[] = {
128, 256, 512, 1024, 2048, 4096,
@@ -1562,7 +1564,7 @@ static struct net_device_stats *atl1c_get_stats(struct net_device *netdev)
{
struct atl1c_adapter *adapter = netdev_priv(netdev);
struct atl1c_hw_stats *hw_stats = &adapter->hw_stats;
- struct net_device_stats *net_stats = &adapter->net_stats;
+ struct net_device_stats *net_stats = &netdev->stats;
atl1c_update_hw_stats(adapter);
net_stats->rx_packets = hw_stats->rx_ok;
@@ -1590,7 +1592,7 @@ static struct net_device_stats *atl1c_get_stats(struct net_device *netdev)
net_stats->tx_aborted_errors = hw_stats->tx_abort_col;
net_stats->tx_window_errors = hw_stats->tx_late_col;
- return &adapter->net_stats;
+ return net_stats;
}
static inline void atl1c_clear_phy_int(struct atl1c_adapter *adapter)
@@ -1700,7 +1702,7 @@ static irqreturn_t atl1c_intr(int irq, void *data)
/* link event */
if (status & (ISR_GPHY | ISR_MANUAL)) {
- adapter->net_stats.tx_carrier_errors++;
+ netdev->stats.tx_carrier_errors++;
atl1c_link_chg_event(adapter);
break;
}
@@ -1719,7 +1721,7 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter,
* cannot figure out if the packet is fragmented or not,
* so we tell the KERNEL CHECKSUM_NONE
*/
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
}
static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid)
@@ -2243,7 +2245,7 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
return NETDEV_TX_OK;
}
- if (unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) {
+ if (unlikely(vlan_tx_tag_present(skb))) {
u16 vlan = vlan_tx_tag_get(skb);
__le16 tag;
@@ -2309,7 +2311,7 @@ static int atl1c_request_irq(struct atl1c_adapter *adapter)
return err;
}
-int atl1c_up(struct atl1c_adapter *adapter)
+static int atl1c_up(struct atl1c_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
int num;
@@ -2351,7 +2353,7 @@ err_alloc_rx:
return err;
}
-void atl1c_down(struct atl1c_adapter *adapter)
+static void atl1c_down(struct atl1c_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c
index 1acea5774e89..ef6349bf3b33 100644
--- a/drivers/net/atl1e/atl1e_main.c
+++ b/drivers/net/atl1e/atl1e_main.c
@@ -1331,7 +1331,7 @@ static inline void atl1e_rx_checksum(struct atl1e_adapter *adapter,
u16 pkt_flags;
u16 err_flags;
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
pkt_flags = prrs->pkt_flag;
err_flags = prrs->err_flag;
if (((pkt_flags & RRS_IS_IPV4) || (pkt_flags & RRS_IS_IPV6)) &&
@@ -1814,7 +1814,7 @@ static netdev_tx_t atl1e_xmit_frame(struct sk_buff *skb,
tpd = atl1e_get_tpd(adapter);
- if (unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) {
+ if (unlikely(vlan_tx_tag_present(skb))) {
u16 vlan_tag = vlan_tx_tag_get(skb);
u16 atl1e_vlan_tag;
@@ -2316,7 +2316,7 @@ static int __devinit atl1e_probe(struct pci_dev *pdev,
netif_napi_add(netdev, &adapter->napi, atl1e_clean, 64);
init_timer(&adapter->phy_config_timer);
- adapter->phy_config_timer.function = &atl1e_phy_config;
+ adapter->phy_config_timer.function = atl1e_phy_config;
adapter->phy_config_timer.data = (unsigned long) adapter;
/* get user settings */
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index c73be2848319..43579b3b24ac 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -91,6 +91,8 @@ MODULE_VERSION(ATLX_DRIVER_VERSION);
/* Temporary hack for merging atl1 and atl2 */
#include "atlx.c"
+static const struct ethtool_ops atl1_ethtool_ops;
+
/*
* This is the only thing that needs to be changed to adjust the
* maximum number of ports that the driver can manage.
@@ -353,7 +355,7 @@ static bool atl1_read_eeprom(struct atl1_hw *hw, u32 offset, u32 *p_value)
* hw - Struct containing variables accessed by shared code
* reg_addr - address of the PHY register to read
*/
-s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data)
+static s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data)
{
u32 val;
int i;
@@ -553,7 +555,7 @@ static s32 atl1_read_mac_addr(struct atl1_hw *hw)
* 1. calcu 32bit CRC for multicast address
* 2. reverse crc with MSB to LSB
*/
-u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr)
+static u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr)
{
u32 crc32, value = 0;
int i;
@@ -570,7 +572,7 @@ u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr)
* hw - Struct containing variables accessed by shared code
* hash_value - Multicast address hash value
*/
-void atl1_hash_set(struct atl1_hw *hw, u32 hash_value)
+static void atl1_hash_set(struct atl1_hw *hw, u32 hash_value)
{
u32 hash_bit, hash_reg;
u32 mta;
@@ -914,7 +916,7 @@ static s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex
return 0;
}
-void atl1_set_mac_addr(struct atl1_hw *hw)
+static void atl1_set_mac_addr(struct atl1_hw *hw)
{
u32 value;
/*
@@ -1811,7 +1813,7 @@ static void atl1_rx_checksum(struct atl1_adapter *adapter,
* the higher layers and let it be sorted out there.
*/
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) {
if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC |
@@ -2100,9 +2102,9 @@ static u16 atl1_tpd_avail(struct atl1_tpd_ring *tpd_ring)
{
u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean);
u16 next_to_use = atomic_read(&tpd_ring->next_to_use);
- return ((next_to_clean > next_to_use) ?
+ return (next_to_clean > next_to_use) ?
next_to_clean - next_to_use - 1 :
- tpd_ring->count + next_to_clean - next_to_use - 1);
+ tpd_ring->count + next_to_clean - next_to_use - 1;
}
static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
@@ -2408,7 +2410,7 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb,
(u16) atomic_read(&tpd_ring->next_to_use));
memset(ptpd, 0, sizeof(struct tx_packet_desc));
- if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+ if (vlan_tx_tag_present(skb)) {
vlan_tag = vlan_tx_tag_get(skb);
vlan_tag = (vlan_tag << 4) | (vlan_tag >> 13) |
((vlan_tag >> 9) & 0x8);
@@ -3043,7 +3045,7 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
netif_carrier_off(netdev);
netif_stop_queue(netdev);
- setup_timer(&adapter->phy_config_timer, &atl1_phy_config,
+ setup_timer(&adapter->phy_config_timer, atl1_phy_config,
(unsigned long)adapter);
adapter->phy_timer_pending = false;
@@ -3658,7 +3660,7 @@ static int atl1_nway_reset(struct net_device *netdev)
return 0;
}
-const struct ethtool_ops atl1_ethtool_ops = {
+static const struct ethtool_ops atl1_ethtool_ops = {
.get_settings = atl1_get_settings,
.set_settings = atl1_set_settings,
.get_drvinfo = atl1_get_drvinfo,
diff --git a/drivers/net/atlx/atl1.h b/drivers/net/atlx/atl1.h
index 9c0ddb273ac8..68de8cbfb3ec 100644
--- a/drivers/net/atlx/atl1.h
+++ b/drivers/net/atlx/atl1.h
@@ -56,16 +56,13 @@ struct atl1_adapter;
struct atl1_hw;
/* function prototypes needed by multiple files */
-u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr);
-void atl1_hash_set(struct atl1_hw *hw, u32 hash_value);
-s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data);
-void atl1_set_mac_addr(struct atl1_hw *hw);
+static u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr);
+static void atl1_hash_set(struct atl1_hw *hw, u32 hash_value);
+static void atl1_set_mac_addr(struct atl1_hw *hw);
static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
int cmd);
static u32 atl1_check_link(struct atl1_adapter *adapter);
-extern const struct ethtool_ops atl1_ethtool_ops;
-
/* hardware definitions specific to L1 */
/* Block IDLE Status Register */
diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c
index 8da87383fb39..35b14bec1207 100644
--- a/drivers/net/atlx/atl2.c
+++ b/drivers/net/atlx/atl2.c
@@ -51,10 +51,10 @@
#define ATL2_DRV_VERSION "2.2.3"
-static char atl2_driver_name[] = "atl2";
+static const char atl2_driver_name[] = "atl2";
static const char atl2_driver_string[] = "Atheros(R) L2 Ethernet Driver";
-static char atl2_copyright[] = "Copyright (c) 2007 Atheros Corporation.";
-static char atl2_driver_version[] = ATL2_DRV_VERSION;
+static const char atl2_copyright[] = "Copyright (c) 2007 Atheros Corporation.";
+static const char atl2_driver_version[] = ATL2_DRV_VERSION;
MODULE_AUTHOR("Atheros Corporation <xiong.huang@atheros.com>, Chris Snook <csnook@redhat.com>");
MODULE_DESCRIPTION("Atheros Fast Ethernet Network Driver");
@@ -870,7 +870,7 @@ static netdev_tx_t atl2_xmit_frame(struct sk_buff *skb,
offset = ((u32)(skb->len-copy_len + 3) & ~3);
}
#ifdef NETIF_F_HW_VLAN_TX
- if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+ if (vlan_tx_tag_present(skb)) {
u16 vlan_tag = vlan_tx_tag_get(skb);
vlan_tag = (vlan_tag << 4) |
(vlan_tag >> 13) |
@@ -1444,11 +1444,11 @@ static int __devinit atl2_probe(struct pci_dev *pdev,
atl2_check_options(adapter);
init_timer(&adapter->watchdog_timer);
- adapter->watchdog_timer.function = &atl2_watchdog;
+ adapter->watchdog_timer.function = atl2_watchdog;
adapter->watchdog_timer.data = (unsigned long) adapter;
init_timer(&adapter->phy_config_timer);
- adapter->phy_config_timer.function = &atl2_phy_config;
+ adapter->phy_config_timer.function = atl2_phy_config;
adapter->phy_config_timer.data = (unsigned long) adapter;
INIT_WORK(&adapter->reset_task, atl2_reset_task);
diff --git a/drivers/net/atlx/atlx.c b/drivers/net/atlx/atlx.c
index f979ea2d6d3c..afb7f7dd1bb1 100644
--- a/drivers/net/atlx/atlx.c
+++ b/drivers/net/atlx/atlx.c
@@ -41,6 +41,10 @@
#include "atlx.h"
+static s32 atlx_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data);
+static u32 atlx_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr);
+static void atlx_set_mac_addr(struct atl1_hw *hw);
+
static struct atlx_spi_flash_dev flash_table[] = {
/* MFR_NAME WRSR READ PRGM WREN WRDI RDSR RDID SEC_ERS CHIP_ERS */
{"Atmel", 0x00, 0x03, 0x02, 0x06, 0x04, 0x05, 0x15, 0x52, 0x62},
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index bd2f9d331dac..f3459798b0e9 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -68,7 +68,7 @@ static int xcvr[NUM_UNITS]; /* The data transfer mode. */
In 1997 Realtek made available the documentation for the second generation
RTL8012 chip, which has lead to several driver improvements.
- http://www.realtek.com.tw/cn/cn.html
+ http://www.realtek.com.tw/
Theory of Operation
@@ -445,7 +445,7 @@ static int net_open(struct net_device *dev)
init_timer(&lp->timer);
lp->timer.expires = jiffies + TIMED_CHECKER;
lp->timer.data = (unsigned long)dev;
- lp->timer.function = &atp_timed_checker; /* timer handler */
+ lp->timer.function = atp_timed_checker; /* timer handler */
add_timer(&lp->timer);
netif_start_queue(dev);
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 15ae6df2ff00..43489f89c142 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -13,7 +13,7 @@
* converted to use linux-2.6.x's PHY framework
*
* Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
+ * ppopov@mvista.com or source@mvista.com
*
* ########################################################################
*
@@ -34,6 +34,8 @@
*
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/capability.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
@@ -56,11 +58,11 @@
#include <linux/crc32.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
+#include <linux/cpu.h>
+#include <linux/io.h>
-#include <asm/cpu.h>
#include <asm/mipsregs.h>
#include <asm/irq.h>
-#include <asm/io.h>
#include <asm/processor.h>
#include <au1000.h>
@@ -152,11 +154,11 @@ static void au1000_enable_mac(struct net_device *dev, int force_reset)
spin_lock_irqsave(&aup->lock, flags);
- if(force_reset || (!aup->mac_enabled)) {
- *aup->enable = MAC_EN_CLOCK_ENABLE;
+ if (force_reset || (!aup->mac_enabled)) {
+ writel(MAC_EN_CLOCK_ENABLE, &aup->enable);
au_sync_delay(2);
- *aup->enable = (MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2
- | MAC_EN_CLOCK_ENABLE);
+ writel((MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2
+ | MAC_EN_CLOCK_ENABLE), &aup->enable);
au_sync_delay(2);
aup->mac_enabled = 1;
@@ -171,12 +173,12 @@ static void au1000_enable_mac(struct net_device *dev, int force_reset)
static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg)
{
struct au1000_private *aup = netdev_priv(dev);
- volatile u32 *const mii_control_reg = &aup->mac->mii_control;
- volatile u32 *const mii_data_reg = &aup->mac->mii_data;
+ u32 *const mii_control_reg = &aup->mac->mii_control;
+ u32 *const mii_data_reg = &aup->mac->mii_data;
u32 timedout = 20;
u32 mii_control;
- while (*mii_control_reg & MAC_MII_BUSY) {
+ while (readl(mii_control_reg) & MAC_MII_BUSY) {
mdelay(1);
if (--timedout == 0) {
netdev_err(dev, "read_MII busy timeout!!\n");
@@ -187,29 +189,29 @@ static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg)
mii_control = MAC_SET_MII_SELECT_REG(reg) |
MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_READ;
- *mii_control_reg = mii_control;
+ writel(mii_control, mii_control_reg);
timedout = 20;
- while (*mii_control_reg & MAC_MII_BUSY) {
+ while (readl(mii_control_reg) & MAC_MII_BUSY) {
mdelay(1);
if (--timedout == 0) {
netdev_err(dev, "mdio_read busy timeout!!\n");
return -1;
}
}
- return (int)*mii_data_reg;
+ return readl(mii_data_reg);
}
static void au1000_mdio_write(struct net_device *dev, int phy_addr,
int reg, u16 value)
{
struct au1000_private *aup = netdev_priv(dev);
- volatile u32 *const mii_control_reg = &aup->mac->mii_control;
- volatile u32 *const mii_data_reg = &aup->mac->mii_data;
+ u32 *const mii_control_reg = &aup->mac->mii_control;
+ u32 *const mii_data_reg = &aup->mac->mii_data;
u32 timedout = 20;
u32 mii_control;
- while (*mii_control_reg & MAC_MII_BUSY) {
+ while (readl(mii_control_reg) & MAC_MII_BUSY) {
mdelay(1);
if (--timedout == 0) {
netdev_err(dev, "mdio_write busy timeout!!\n");
@@ -220,18 +222,22 @@ static void au1000_mdio_write(struct net_device *dev, int phy_addr,
mii_control = MAC_SET_MII_SELECT_REG(reg) |
MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_WRITE;
- *mii_data_reg = value;
- *mii_control_reg = mii_control;
+ writel(value, mii_data_reg);
+ writel(mii_control, mii_control_reg);
}
static int au1000_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
{
/* WARNING: bus->phy_map[phy_addr].attached_dev == dev does
- * _NOT_ hold (e.g. when PHY is accessed through other MAC's MII bus) */
+ * _NOT_ hold (e.g. when PHY is accessed through other MAC's MII bus)
+ */
struct net_device *const dev = bus->priv;
- au1000_enable_mac(dev, 0); /* make sure the MAC associated with this
- * mii_bus is enabled */
+ /* make sure the MAC associated with this
+ * mii_bus is enabled
+ */
+ au1000_enable_mac(dev, 0);
+
return au1000_mdio_read(dev, phy_addr, regnum);
}
@@ -240,8 +246,11 @@ static int au1000_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
{
struct net_device *const dev = bus->priv;
- au1000_enable_mac(dev, 0); /* make sure the MAC associated with this
- * mii_bus is enabled */
+ /* make sure the MAC associated with this
+ * mii_bus is enabled
+ */
+ au1000_enable_mac(dev, 0);
+
au1000_mdio_write(dev, phy_addr, regnum, value);
return 0;
}
@@ -250,28 +259,37 @@ static int au1000_mdiobus_reset(struct mii_bus *bus)
{
struct net_device *const dev = bus->priv;
- au1000_enable_mac(dev, 0); /* make sure the MAC associated with this
- * mii_bus is enabled */
+ /* make sure the MAC associated with this
+ * mii_bus is enabled
+ */
+ au1000_enable_mac(dev, 0);
+
return 0;
}
static void au1000_hard_stop(struct net_device *dev)
{
struct au1000_private *aup = netdev_priv(dev);
+ u32 reg;
netif_dbg(aup, drv, dev, "hard stop\n");
- aup->mac->control &= ~(MAC_RX_ENABLE | MAC_TX_ENABLE);
+ reg = readl(&aup->mac->control);
+ reg &= ~(MAC_RX_ENABLE | MAC_TX_ENABLE);
+ writel(reg, &aup->mac->control);
au_sync_delay(10);
}
static void au1000_enable_rx_tx(struct net_device *dev)
{
struct au1000_private *aup = netdev_priv(dev);
+ u32 reg;
netif_dbg(aup, hw, dev, "enable_rx_tx\n");
- aup->mac->control |= (MAC_RX_ENABLE | MAC_TX_ENABLE);
+ reg = readl(&aup->mac->control);
+ reg |= (MAC_RX_ENABLE | MAC_TX_ENABLE);
+ writel(reg, &aup->mac->control);
au_sync_delay(10);
}
@@ -281,6 +299,7 @@ au1000_adjust_link(struct net_device *dev)
struct au1000_private *aup = netdev_priv(dev);
struct phy_device *phydev = aup->phy_dev;
unsigned long flags;
+ u32 reg;
int status_change = 0;
@@ -312,14 +331,15 @@ au1000_adjust_link(struct net_device *dev)
/* switching duplex mode requires to disable rx and tx! */
au1000_hard_stop(dev);
- if (DUPLEX_FULL == phydev->duplex)
- aup->mac->control = ((aup->mac->control
- | MAC_FULL_DUPLEX)
- & ~MAC_DISABLE_RX_OWN);
- else
- aup->mac->control = ((aup->mac->control
- & ~MAC_FULL_DUPLEX)
- | MAC_DISABLE_RX_OWN);
+ reg = readl(&aup->mac->control);
+ if (DUPLEX_FULL == phydev->duplex) {
+ reg |= MAC_FULL_DUPLEX;
+ reg &= ~MAC_DISABLE_RX_OWN;
+ } else {
+ reg &= ~MAC_FULL_DUPLEX;
+ reg |= MAC_DISABLE_RX_OWN;
+ }
+ writel(reg, &aup->mac->control);
au_sync_delay(1);
au1000_enable_rx_tx(dev);
@@ -353,10 +373,11 @@ au1000_adjust_link(struct net_device *dev)
}
}
-static int au1000_mii_probe (struct net_device *dev)
+static int au1000_mii_probe(struct net_device *dev)
{
struct au1000_private *const aup = netdev_priv(dev);
struct phy_device *phydev = NULL;
+ int phy_addr;
if (aup->phy_static_config) {
BUG_ON(aup->mac_id < 0 || aup->mac_id > 1);
@@ -366,42 +387,46 @@ static int au1000_mii_probe (struct net_device *dev)
else
netdev_info(dev, "using PHY-less setup\n");
return 0;
- } else {
- int phy_addr;
-
- /* find the first (lowest address) PHY on the current MAC's MII bus */
- for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++)
- if (aup->mii_bus->phy_map[phy_addr]) {
- phydev = aup->mii_bus->phy_map[phy_addr];
- if (!aup->phy_search_highest_addr)
- break; /* break out with first one found */
- }
-
- if (aup->phy1_search_mac0) {
- /* try harder to find a PHY */
- if (!phydev && (aup->mac_id == 1)) {
- /* no PHY found, maybe we have a dual PHY? */
- dev_info(&dev->dev, ": no PHY found on MAC1, "
- "let's see if it's attached to MAC0...\n");
-
- /* find the first (lowest address) non-attached PHY on
- * the MAC0 MII bus */
- for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
- struct phy_device *const tmp_phydev =
- aup->mii_bus->phy_map[phy_addr];
-
- if (aup->mac_id == 1)
- break;
-
- if (!tmp_phydev)
- continue; /* no PHY here... */
+ }
- if (tmp_phydev->attached_dev)
- continue; /* already claimed by MAC0 */
+ /* find the first (lowest address) PHY
+ * on the current MAC's MII bus
+ */
+ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++)
+ if (aup->mii_bus->phy_map[phy_addr]) {
+ phydev = aup->mii_bus->phy_map[phy_addr];
+ if (!aup->phy_search_highest_addr)
+ /* break out with first one found */
+ break;
+ }
- phydev = tmp_phydev;
- break; /* found it */
- }
+ if (aup->phy1_search_mac0) {
+ /* try harder to find a PHY */
+ if (!phydev && (aup->mac_id == 1)) {
+ /* no PHY found, maybe we have a dual PHY? */
+ dev_info(&dev->dev, ": no PHY found on MAC1, "
+ "let's see if it's attached to MAC0...\n");
+
+ /* find the first (lowest address) non-attached
+ * PHY on the MAC0 MII bus
+ */
+ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+ struct phy_device *const tmp_phydev =
+ aup->mii_bus->phy_map[phy_addr];
+
+ if (aup->mac_id == 1)
+ break;
+
+ /* no PHY here... */
+ if (!tmp_phydev)
+ continue;
+
+ /* already claimed by MAC0 */
+ if (tmp_phydev->attached_dev)
+ continue;
+
+ phydev = tmp_phydev;
+ break; /* found it */
}
}
}
@@ -452,20 +477,20 @@ static int au1000_mii_probe (struct net_device *dev)
* has the virtual and dma address of a buffer suitable for
* both, receive and transmit operations.
*/
-static db_dest_t *au1000_GetFreeDB(struct au1000_private *aup)
+static struct db_dest *au1000_GetFreeDB(struct au1000_private *aup)
{
- db_dest_t *pDB;
+ struct db_dest *pDB;
pDB = aup->pDBfree;
- if (pDB) {
+ if (pDB)
aup->pDBfree = pDB->pnext;
- }
+
return pDB;
}
-void au1000_ReleaseDB(struct au1000_private *aup, db_dest_t *pDB)
+void au1000_ReleaseDB(struct au1000_private *aup, struct db_dest *pDB)
{
- db_dest_t *pDBfree = aup->pDBfree;
+ struct db_dest *pDBfree = aup->pDBfree;
if (pDBfree)
pDBfree->pnext = pDB;
aup->pDBfree = pDB;
@@ -478,9 +503,9 @@ static void au1000_reset_mac_unlocked(struct net_device *dev)
au1000_hard_stop(dev);
- *aup->enable = MAC_EN_CLOCK_ENABLE;
+ writel(MAC_EN_CLOCK_ENABLE, &aup->enable);
au_sync_delay(2);
- *aup->enable = 0;
+ writel(0, &aup->enable);
au_sync_delay(2);
aup->tx_full = 0;
@@ -507,7 +532,7 @@ static void au1000_reset_mac(struct net_device *dev)
spin_lock_irqsave(&aup->lock, flags);
- au1000_reset_mac_unlocked (dev);
+ au1000_reset_mac_unlocked(dev);
spin_unlock_irqrestore(&aup->lock, flags);
}
@@ -524,11 +549,13 @@ au1000_setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base)
for (i = 0; i < NUM_RX_DMA; i++) {
aup->rx_dma_ring[i] =
- (volatile rx_dma_t *) (rx_base + sizeof(rx_dma_t)*i);
+ (struct rx_dma *)
+ (rx_base + sizeof(struct rx_dma)*i);
}
for (i = 0; i < NUM_TX_DMA; i++) {
aup->tx_dma_ring[i] =
- (volatile tx_dma_t *) (tx_base + sizeof(tx_dma_t)*i);
+ (struct tx_dma *)
+ (tx_base + sizeof(struct tx_dma)*i);
}
}
@@ -616,18 +643,21 @@ static int au1000_init(struct net_device *dev)
spin_lock_irqsave(&aup->lock, flags);
- aup->mac->control = 0;
+ writel(0, &aup->mac->control);
aup->tx_head = (aup->tx_dma_ring[0]->buff_stat & 0xC) >> 2;
aup->tx_tail = aup->tx_head;
aup->rx_head = (aup->rx_dma_ring[0]->buff_stat & 0xC) >> 2;
- aup->mac->mac_addr_high = dev->dev_addr[5]<<8 | dev->dev_addr[4];
- aup->mac->mac_addr_low = dev->dev_addr[3]<<24 | dev->dev_addr[2]<<16 |
- dev->dev_addr[1]<<8 | dev->dev_addr[0];
+ writel(dev->dev_addr[5]<<8 | dev->dev_addr[4],
+ &aup->mac->mac_addr_high);
+ writel(dev->dev_addr[3]<<24 | dev->dev_addr[2]<<16 |
+ dev->dev_addr[1]<<8 | dev->dev_addr[0],
+ &aup->mac->mac_addr_low);
- for (i = 0; i < NUM_RX_DMA; i++) {
+
+ for (i = 0; i < NUM_RX_DMA; i++)
aup->rx_dma_ring[i]->buff_stat |= RX_DMA_ENABLE;
- }
+
au_sync();
control = MAC_RX_ENABLE | MAC_TX_ENABLE;
@@ -643,8 +673,8 @@ static int au1000_init(struct net_device *dev)
control |= MAC_FULL_DUPLEX;
}
- aup->mac->control = control;
- aup->mac->vlan1_tag = 0x8100; /* activate vlan support */
+ writel(control, &aup->mac->control);
+ writel(0x8100, &aup->mac->vlan1_tag); /* activate vlan support */
au_sync();
spin_unlock_irqrestore(&aup->lock, flags);
@@ -681,9 +711,9 @@ static int au1000_rx(struct net_device *dev)
{
struct au1000_private *aup = netdev_priv(dev);
struct sk_buff *skb;
- volatile rx_dma_t *prxd;
+ struct rx_dma *prxd;
u32 buff_stat, status;
- db_dest_t *pDB;
+ struct db_dest *pDB;
u32 frmlen;
netif_dbg(aup, rx_status, dev, "au1000_rx head %d\n", aup->rx_head);
@@ -713,24 +743,26 @@ static int au1000_rx(struct net_device *dev)
netif_rx(skb); /* pass the packet to upper layers */
} else {
if (au1000_debug > 4) {
+ pr_err("rx_error(s):");
if (status & RX_MISSED_FRAME)
- printk("rx miss\n");
+ pr_cont(" miss");
if (status & RX_WDOG_TIMER)
- printk("rx wdog\n");
+ pr_cont(" wdog");
if (status & RX_RUNT)
- printk("rx runt\n");
+ pr_cont(" runt");
if (status & RX_OVERLEN)
- printk("rx overlen\n");
+ pr_cont(" overlen");
if (status & RX_COLL)
- printk("rx coll\n");
+ pr_cont(" coll");
if (status & RX_MII_ERROR)
- printk("rx mii error\n");
+ pr_cont(" mii error");
if (status & RX_CRC_ERROR)
- printk("rx crc error\n");
+ pr_cont(" crc error");
if (status & RX_LEN_ERROR)
- printk("rx len error\n");
+ pr_cont(" len error");
if (status & RX_U_CNTRL_FRAME)
- printk("rx u control frame\n");
+ pr_cont(" u control frame");
+ pr_cont("\n");
}
}
prxd->buff_stat = (u32)(pDB->dma_addr | RX_DMA_ENABLE);
@@ -753,7 +785,8 @@ static void au1000_update_tx_stats(struct net_device *dev, u32 status)
if (!aup->phy_dev || (DUPLEX_FULL == aup->phy_dev->duplex)) {
if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) {
/* any other tx errors are only valid
- * in half duplex mode */
+ * in half duplex mode
+ */
ps->tx_errors++;
ps->tx_aborted_errors++;
}
@@ -774,7 +807,7 @@ static void au1000_update_tx_stats(struct net_device *dev, u32 status)
static void au1000_tx_ack(struct net_device *dev)
{
struct au1000_private *aup = netdev_priv(dev);
- volatile tx_dma_t *ptxd;
+ struct tx_dma *ptxd;
ptxd = aup->tx_dma_ring[aup->tx_tail];
@@ -854,7 +887,7 @@ static int au1000_close(struct net_device *dev)
spin_lock_irqsave(&aup->lock, flags);
- au1000_reset_mac_unlocked (dev);
+ au1000_reset_mac_unlocked(dev);
/* stop the device */
netif_stop_queue(dev);
@@ -873,9 +906,9 @@ static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev)
{
struct au1000_private *aup = netdev_priv(dev);
struct net_device_stats *ps = &dev->stats;
- volatile tx_dma_t *ptxd;
+ struct tx_dma *ptxd;
u32 buff_stat;
- db_dest_t *pDB;
+ struct db_dest *pDB;
int i;
netif_dbg(aup, tx_queued, dev, "tx: aup %x len=%d, data=%p, head %d\n",
@@ -902,9 +935,9 @@ static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev)
pDB = aup->tx_db_inuse[aup->tx_head];
skb_copy_from_linear_data(skb, (void *)pDB->vaddr, skb->len);
if (skb->len < ETH_ZLEN) {
- for (i = skb->len; i < ETH_ZLEN; i++) {
+ for (i = skb->len; i < ETH_ZLEN; i++)
((char *)pDB->vaddr)[i] = 0;
- }
+
ptxd->len = ETH_ZLEN;
} else
ptxd->len = skb->len;
@@ -935,15 +968,16 @@ static void au1000_tx_timeout(struct net_device *dev)
static void au1000_multicast_list(struct net_device *dev)
{
struct au1000_private *aup = netdev_priv(dev);
+ u32 reg;
- netif_dbg(aup, drv, dev, "au1000_multicast_list: flags=%x\n", dev->flags);
-
+ netif_dbg(aup, drv, dev, "%s: flags=%x\n", __func__, dev->flags);
+ reg = readl(&aup->mac->control);
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- aup->mac->control |= MAC_PROMISCUOUS;
+ reg |= MAC_PROMISCUOUS;
} else if ((dev->flags & IFF_ALLMULTI) ||
netdev_mc_count(dev) > MULTICAST_FILTER_LIMIT) {
- aup->mac->control |= MAC_PASS_ALL_MULTI;
- aup->mac->control &= ~MAC_PROMISCUOUS;
+ reg |= MAC_PASS_ALL_MULTI;
+ reg &= ~MAC_PROMISCUOUS;
netdev_info(dev, "Pass all multicast\n");
} else {
struct netdev_hw_addr *ha;
@@ -953,11 +987,12 @@ static void au1000_multicast_list(struct net_device *dev)
netdev_for_each_mc_addr(ha, dev)
set_bit(ether_crc(ETH_ALEN, ha->addr)>>26,
(long *)mc_filter);
- aup->mac->multi_hash_high = mc_filter[1];
- aup->mac->multi_hash_low = mc_filter[0];
- aup->mac->control &= ~MAC_PROMISCUOUS;
- aup->mac->control |= MAC_HASH_MODE;
+ writel(mc_filter[1], &aup->mac->multi_hash_high);
+ writel(mc_filter[0], &aup->mac->multi_hash_low);
+ reg &= ~MAC_PROMISCUOUS;
+ reg |= MAC_HASH_MODE;
}
+ writel(reg, &aup->mac->control);
}
static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -991,7 +1026,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
struct au1000_private *aup = NULL;
struct au1000_eth_platform_data *pd;
struct net_device *dev = NULL;
- db_dest_t *pDB, *pDBfree;
+ struct db_dest *pDB, *pDBfree;
int irq, i, err = 0;
struct resource *base, *macen;
@@ -1016,13 +1051,15 @@ static int __devinit au1000_probe(struct platform_device *pdev)
goto out;
}
- if (!request_mem_region(base->start, resource_size(base), pdev->name)) {
+ if (!request_mem_region(base->start, resource_size(base),
+ pdev->name)) {
dev_err(&pdev->dev, "failed to request memory region for base registers\n");
err = -ENXIO;
goto out;
}
- if (!request_mem_region(macen->start, resource_size(macen), pdev->name)) {
+ if (!request_mem_region(macen->start, resource_size(macen),
+ pdev->name)) {
dev_err(&pdev->dev, "failed to request memory region for MAC enable register\n");
err = -ENXIO;
goto err_request;
@@ -1040,10 +1077,12 @@ static int __devinit au1000_probe(struct platform_device *pdev)
aup = netdev_priv(dev);
spin_lock_init(&aup->lock);
- aup->msg_enable = (au1000_debug < 4 ? AU1000_DEF_MSG_ENABLE : au1000_debug);
+ aup->msg_enable = (au1000_debug < 4 ?
+ AU1000_DEF_MSG_ENABLE : au1000_debug);
- /* Allocate the data buffers */
- /* Snooping works fine with eth on all au1xxx */
+ /* Allocate the data buffers
+ * Snooping works fine with eth on all au1xxx
+ */
aup->vaddr = (u32)dma_alloc_noncoherent(NULL, MAX_BUF_SIZE *
(NUM_TX_BUFFS + NUM_RX_BUFFS),
&aup->dma_addr, 0);
@@ -1054,15 +1093,17 @@ static int __devinit au1000_probe(struct platform_device *pdev)
}
/* aup->mac is the base address of the MAC's registers */
- aup->mac = (volatile mac_reg_t *)ioremap_nocache(base->start, resource_size(base));
+ aup->mac = (struct mac_reg *)
+ ioremap_nocache(base->start, resource_size(base));
if (!aup->mac) {
dev_err(&pdev->dev, "failed to ioremap MAC registers\n");
err = -ENXIO;
goto err_remap1;
}
- /* Setup some variables for quick register address access */
- aup->enable = (volatile u32 *)ioremap_nocache(macen->start, resource_size(macen));
+ /* Setup some variables for quick register address access */
+ aup->enable = (u32 *)ioremap_nocache(macen->start,
+ resource_size(macen));
if (!aup->enable) {
dev_err(&pdev->dev, "failed to ioremap MAC enable register\n");
err = -ENXIO;
@@ -1078,12 +1119,13 @@ static int __devinit au1000_probe(struct platform_device *pdev)
/* set a random MAC now in case platform_data doesn't provide one */
random_ether_addr(dev->dev_addr);
- *aup->enable = 0;
+ writel(0, &aup->enable);
aup->mac_enabled = 0;
pd = pdev->dev.platform_data;
if (!pd) {
- dev_info(&pdev->dev, "no platform_data passed, PHY search on MAC0\n");
+ dev_info(&pdev->dev, "no platform_data passed,"
+ " PHY search on MAC0\n");
aup->phy1_search_mac0 = 1;
} else {
if (is_valid_ether_addr(pd->mac))
@@ -1098,8 +1140,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
}
if (aup->phy_busid && aup->phy_busid > 0) {
- dev_err(&pdev->dev, "MAC0-associated PHY attached 2nd MACs MII"
- "bus not supported yet\n");
+ dev_err(&pdev->dev, "MAC0-associated PHY attached 2nd MACs MII bus not supported yet\n");
err = -ENODEV;
goto err_mdiobus_alloc;
}
@@ -1151,17 +1192,17 @@ static int __devinit au1000_probe(struct platform_device *pdev)
for (i = 0; i < NUM_RX_DMA; i++) {
pDB = au1000_GetFreeDB(aup);
- if (!pDB) {
+ if (!pDB)
goto err_out;
- }
+
aup->rx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
aup->rx_db_inuse[i] = pDB;
}
for (i = 0; i < NUM_TX_DMA; i++) {
pDB = au1000_GetFreeDB(aup);
- if (!pDB) {
+ if (!pDB)
goto err_out;
- }
+
aup->tx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
aup->tx_dma_ring[i]->len = 0;
aup->tx_db_inuse[i] = pDB;
@@ -1188,7 +1229,8 @@ static int __devinit au1000_probe(struct platform_device *pdev)
netdev_info(dev, "Au1xx0 Ethernet found at 0x%lx, irq %d\n",
(unsigned long)base->start, irq);
if (version_printed++ == 0)
- printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
+ pr_info("%s version %s %s\n",
+ DRV_NAME, DRV_VERSION, DRV_AUTHOR);
return 0;
@@ -1197,7 +1239,8 @@ err_out:
mdiobus_unregister(aup->mii_bus);
/* here we should have a valid dev plus aup-> register addresses
- * so we can reset the mac properly.*/
+ * so we can reset the mac properly.
+ */
au1000_reset_mac(dev);
for (i = 0; i < NUM_RX_DMA; i++) {
diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h
index d06ec008fbf1..6229c774552c 100644
--- a/drivers/net/au1000_eth.h
+++ b/drivers/net/au1000_eth.h
@@ -44,34 +44,34 @@
* Data Buffer Descriptor. Data buffers must be aligned on 32 byte
* boundary for both, receive and transmit.
*/
-typedef struct db_dest {
+struct db_dest {
struct db_dest *pnext;
- volatile u32 *vaddr;
+ u32 *vaddr;
dma_addr_t dma_addr;
-} db_dest_t;
+};
/*
* The transmit and receive descriptors are memory
* mapped registers.
*/
-typedef struct tx_dma {
+struct tx_dma {
u32 status;
u32 buff_stat;
u32 len;
u32 pad;
-} tx_dma_t;
+};
-typedef struct rx_dma {
+struct rx_dma {
u32 status;
u32 buff_stat;
u32 pad[2];
-} rx_dma_t;
+};
/*
* MAC control registers, memory mapped.
*/
-typedef struct mac_reg {
+struct mac_reg {
u32 control;
u32 mac_addr_high;
u32 mac_addr_low;
@@ -82,16 +82,16 @@ typedef struct mac_reg {
u32 flow_control;
u32 vlan1_tag;
u32 vlan2_tag;
-} mac_reg_t;
+};
struct au1000_private {
- db_dest_t *pDBfree;
- db_dest_t db[NUM_RX_BUFFS+NUM_TX_BUFFS];
- volatile rx_dma_t *rx_dma_ring[NUM_RX_DMA];
- volatile tx_dma_t *tx_dma_ring[NUM_TX_DMA];
- db_dest_t *rx_db_inuse[NUM_RX_DMA];
- db_dest_t *tx_db_inuse[NUM_TX_DMA];
+ struct db_dest *pDBfree;
+ struct db_dest db[NUM_RX_BUFFS+NUM_TX_BUFFS];
+ struct rx_dma *rx_dma_ring[NUM_RX_DMA];
+ struct tx_dma *tx_dma_ring[NUM_TX_DMA];
+ struct db_dest *rx_db_inuse[NUM_RX_DMA];
+ struct db_dest *tx_db_inuse[NUM_TX_DMA];
u32 rx_head;
u32 tx_head;
u32 tx_tail;
@@ -99,7 +99,9 @@ struct au1000_private {
int mac_id;
- int mac_enabled; /* whether MAC is currently enabled and running (req. for mdio) */
+ int mac_enabled; /* whether MAC is currently enabled and running
+ * (req. for mdio)
+ */
int old_link; /* used by au1000_adjust_link */
int old_speed;
@@ -117,9 +119,11 @@ struct au1000_private {
int phy_busid;
int phy_irq;
- /* These variables are just for quick access to certain regs addresses. */
- volatile mac_reg_t *mac; /* mac registers */
- volatile u32 *enable; /* address of MAC Enable Register */
+ /* These variables are just for quick access
+ * to certain regs addresses.
+ */
+ struct mac_reg *mac; /* mac registers */
+ u32 *enable; /* address of MAC Enable Register */
u32 vaddr; /* virtual address of rx/tx buffers */
dma_addr_t dma_addr; /* dma address of rx/tx buffers */
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index 20e946b1e744..b6da4cf3694b 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -864,6 +864,7 @@ static int ax_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
dev_err(&pdev->dev, "no IRQ specified\n");
+ ret = -ENXIO;
goto exit_mem;
}
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index efeffdf9e5fa..c6e86315b3f8 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -818,7 +818,7 @@ static int b44_rx(struct b44 *bp, int budget)
copy_skb->data, len);
skb = copy_skb;
}
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
skb->protocol = eth_type_trans(skb, bp->dev);
netif_receive_skb(skb);
received++;
@@ -2296,18 +2296,27 @@ static int b44_resume(struct ssb_device *sdev)
if (!netif_running(dev))
return 0;
+ spin_lock_irq(&bp->lock);
+ b44_init_rings(bp);
+ b44_init_hw(bp, B44_FULL_RESET);
+ spin_unlock_irq(&bp->lock);
+
+ /*
+ * As a shared interrupt, the handler can be called immediately. To be
+ * able to check the interrupt status the hardware must already be
+ * powered back on (b44_init_hw).
+ */
rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
if (rc) {
netdev_err(dev, "request_irq failed\n");
+ spin_lock_irq(&bp->lock);
+ b44_halt(bp);
+ b44_free_rings(bp);
+ spin_unlock_irq(&bp->lock);
return rc;
}
- spin_lock_irq(&bp->lock);
-
- b44_init_rings(bp);
- b44_init_hw(bp, B44_FULL_RESET);
netif_device_attach(bp->dev);
- spin_unlock_irq(&bp->lock);
b44_enable_ints(bp);
netif_wake_queue(dev);
diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c
index 0d2c5da08937..ecfef240a303 100644
--- a/drivers/net/bcm63xx_enet.c
+++ b/drivers/net/bcm63xx_enet.c
@@ -293,22 +293,22 @@ static int bcm_enet_receive_queue(struct net_device *dev, int budget)
/* if the packet does not have start of packet _and_
* end of packet flag set, then just recycle it */
if ((len_stat & DMADESC_ESOP_MASK) != DMADESC_ESOP_MASK) {
- priv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
continue;
}
/* recycle packet if it's marked as bad */
if (unlikely(len_stat & DMADESC_ERR_MASK)) {
- priv->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (len_stat & DMADESC_OVSIZE_MASK)
- priv->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (len_stat & DMADESC_CRC_MASK)
- priv->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (len_stat & DMADESC_UNDER_MASK)
- priv->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (len_stat & DMADESC_OV_MASK)
- priv->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
continue;
}
@@ -324,7 +324,7 @@ static int bcm_enet_receive_queue(struct net_device *dev, int budget)
nskb = netdev_alloc_skb_ip_align(dev, len);
if (!nskb) {
/* forget packet, just rearm desc */
- priv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
continue;
}
@@ -342,8 +342,8 @@ static int bcm_enet_receive_queue(struct net_device *dev, int budget)
skb_put(skb, len);
skb->protocol = eth_type_trans(skb, dev);
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
netif_receive_skb(skb);
} while (--budget > 0);
@@ -403,7 +403,7 @@ static int bcm_enet_tx_reclaim(struct net_device *dev, int force)
spin_unlock(&priv->tx_lock);
if (desc->len_stat & DMADESC_UNDER_MASK)
- priv->stats.tx_errors++;
+ dev->stats.tx_errors++;
dev_kfree_skb(skb);
released++;
@@ -563,8 +563,8 @@ static int bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!priv->tx_desc_count)
netif_stop_queue(dev);
- priv->stats.tx_bytes += skb->len;
- priv->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
ret = NETDEV_TX_OK;
out_unlock:
@@ -798,7 +798,7 @@ static int bcm_enet_open(struct net_device *dev)
snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
priv->mac_id ? "1" : "0", priv->phy_id);
- phydev = phy_connect(dev, phy_id, &bcm_enet_adjust_phy_link, 0,
+ phydev = phy_connect(dev, phy_id, bcm_enet_adjust_phy_link, 0,
PHY_INTERFACE_MODE_MII);
if (IS_ERR(phydev)) {
@@ -1141,17 +1141,6 @@ static int bcm_enet_stop(struct net_device *dev)
}
/*
- * core request to return device rx/tx stats
- */
-static struct net_device_stats *bcm_enet_get_stats(struct net_device *dev)
-{
- struct bcm_enet_priv *priv;
-
- priv = netdev_priv(dev);
- return &priv->stats;
-}
-
-/*
* ethtool callbacks
*/
struct bcm_enet_stats {
@@ -1163,16 +1152,18 @@ struct bcm_enet_stats {
#define GEN_STAT(m) sizeof(((struct bcm_enet_priv *)0)->m), \
offsetof(struct bcm_enet_priv, m)
+#define DEV_STAT(m) sizeof(((struct net_device_stats *)0)->m), \
+ offsetof(struct net_device_stats, m)
static const struct bcm_enet_stats bcm_enet_gstrings_stats[] = {
- { "rx_packets", GEN_STAT(stats.rx_packets), -1 },
- { "tx_packets", GEN_STAT(stats.tx_packets), -1 },
- { "rx_bytes", GEN_STAT(stats.rx_bytes), -1 },
- { "tx_bytes", GEN_STAT(stats.tx_bytes), -1 },
- { "rx_errors", GEN_STAT(stats.rx_errors), -1 },
- { "tx_errors", GEN_STAT(stats.tx_errors), -1 },
- { "rx_dropped", GEN_STAT(stats.rx_dropped), -1 },
- { "tx_dropped", GEN_STAT(stats.tx_dropped), -1 },
+ { "rx_packets", DEV_STAT(rx_packets), -1 },
+ { "tx_packets", DEV_STAT(tx_packets), -1 },
+ { "rx_bytes", DEV_STAT(rx_bytes), -1 },
+ { "tx_bytes", DEV_STAT(tx_bytes), -1 },
+ { "rx_errors", DEV_STAT(rx_errors), -1 },
+ { "tx_errors", DEV_STAT(tx_errors), -1 },
+ { "rx_dropped", DEV_STAT(rx_dropped), -1 },
+ { "tx_dropped", DEV_STAT(tx_dropped), -1 },
{ "rx_good_octets", GEN_STAT(mib.rx_gd_octets), ETH_MIB_RX_GD_OCTETS},
{ "rx_good_pkts", GEN_STAT(mib.rx_gd_pkts), ETH_MIB_RX_GD_PKTS },
@@ -1328,7 +1319,11 @@ static void bcm_enet_get_ethtool_stats(struct net_device *netdev,
char *p;
s = &bcm_enet_gstrings_stats[i];
- p = (char *)priv + s->stat_offset;
+ if (s->mib_reg == -1)
+ p = (char *)&netdev->stats;
+ else
+ p = (char *)priv;
+ p += s->stat_offset;
data[i] = (s->sizeof_stat == sizeof(u64)) ?
*(u64 *)p : *(u32 *)p;
}
@@ -1605,7 +1600,6 @@ static const struct net_device_ops bcm_enet_ops = {
.ndo_open = bcm_enet_open,
.ndo_stop = bcm_enet_stop,
.ndo_start_xmit = bcm_enet_start_xmit,
- .ndo_get_stats = bcm_enet_get_stats,
.ndo_set_mac_address = bcm_enet_set_mac_address,
.ndo_set_multicast_list = bcm_enet_set_multicast_list,
.ndo_do_ioctl = bcm_enet_ioctl,
diff --git a/drivers/net/bcm63xx_enet.h b/drivers/net/bcm63xx_enet.h
index bd3684d42d74..0e3048b788c2 100644
--- a/drivers/net/bcm63xx_enet.h
+++ b/drivers/net/bcm63xx_enet.h
@@ -274,7 +274,6 @@ struct bcm_enet_priv {
int pause_tx;
/* stats */
- struct net_device_stats stats;
struct bcm_enet_mib_counters mib;
/* after mib interrupt, mib registers update is done in this
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
index 53306bf3f401..4594a28b1f66 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -78,6 +78,8 @@ static inline char *nic_name(struct pci_dev *pdev)
#define MCC_Q_LEN 128 /* total size not to exceed 8 pages */
#define MCC_CQ_LEN 256
+#define MAX_RSS_QS 4 /* BE limit is 4 queues/port */
+#define BE_MAX_MSIX_VECTORS (MAX_RSS_QS + 1 + 1)/* RSS qs + 1 def Rx + Tx */
#define BE_NAPI_WEIGHT 64
#define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */
#define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST)
@@ -157,10 +159,9 @@ struct be_mcc_obj {
bool rearm_cq;
};
-struct be_drvr_stats {
+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_fwd_reqs; /* number of send reqs through forwarding i/f */
u32 be_tx_wrbs; /* number of tx WRBs used */
u32 be_tx_events; /* number of tx completion events */
u32 be_tx_compl; /* number of tx completion entries processed */
@@ -169,35 +170,6 @@ struct be_drvr_stats {
u64 be_tx_bytes_prev;
u64 be_tx_pkts;
u32 be_tx_rate;
-
- u32 cache_barrier[16];
-
- u32 be_ethrx_post_fail;/* number of ethrx buffer alloc failures */
- u32 be_rx_polls; /* number of times NAPI called poll function */
- u32 be_rx_events; /* number of ucast rx completion events */
- u32 be_rx_compl; /* number of rx completion entries processed */
- ulong be_rx_jiffies;
- u64 be_rx_bytes;
- u64 be_rx_bytes_prev;
- u64 be_rx_pkts;
- u32 be_rx_rate;
- u32 be_rx_mcast_pkt;
- /* number of non ether type II frames dropped where
- * frame len > length field of Mac Hdr */
- u32 be_802_3_dropped_frames;
- /* number of non ether type II frames malformed where
- * in frame len < length field of Mac Hdr */
- u32 be_802_3_malformed_frames;
- u32 be_rxcp_err; /* Num rx completion entries w/ err set. */
- ulong rx_fps_jiffies; /* jiffies at last FPS calc */
- u32 be_rx_frags;
- u32 be_prev_rx_frags;
- u32 be_rx_fps; /* Rx frags per second */
-};
-
-struct be_stats_obj {
- struct be_drvr_stats drvr_stats;
- struct be_dma_mem cmd;
};
struct be_tx_obj {
@@ -215,10 +187,34 @@ struct be_rx_page_info {
bool last_page_user;
};
+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_jiffies;
+ u64 rx_bytes;
+ u64 rx_bytes_prev;
+ u64 rx_pkts;
+ u32 rx_rate;
+ 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 */
+};
+
struct be_rx_obj {
+ struct be_adapter *adapter;
struct be_queue_info q;
struct be_queue_info cq;
struct be_rx_page_info page_info_tbl[RX_Q_LEN];
+ struct be_eq_obj rx_eq;
+ struct be_rx_stats stats;
+ u8 rss_id;
+ bool rx_post_starved; /* Zero rx frags have been posted to BE */
+ u32 cache_line_barrier[16];
};
struct be_vf_cfg {
@@ -229,7 +225,6 @@ struct be_vf_cfg {
u32 vf_tx_rate;
};
-#define BE_NUM_MSIX_VECTORS 2 /* 1 each for Tx and Rx */
#define BE_INVALID_PMAC_ID 0xffffffff
struct be_adapter {
struct pci_dev *pdev;
@@ -249,29 +244,31 @@ struct be_adapter {
spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */
spinlock_t mcc_cq_lock;
- struct msix_entry msix_entries[BE_NUM_MSIX_VECTORS];
+ struct msix_entry msix_entries[BE_MAX_MSIX_VECTORS];
bool msix_enabled;
bool isr_registered;
/* TX Rings */
struct be_eq_obj tx_eq;
struct be_tx_obj tx_obj;
+ struct be_tx_stats tx_stats;
u32 cache_line_break[8];
/* Rx rings */
- struct be_eq_obj rx_eq;
- struct be_rx_obj rx_obj;
+ struct be_rx_obj rx_obj[MAX_RSS_QS + 1]; /* one default non-rss Q */
+ u32 num_rx_qs;
u32 big_page_size; /* Compounded page size shared by rx wrbs */
- bool rx_post_starved; /* Zero rx frags have been posted to BE */
struct vlan_group *vlan_grp;
u16 vlans_added;
u16 max_vlans; /* Number of vlans supported */
- u8 vlan_tag[VLAN_GROUP_ARRAY_LEN];
+ 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_stats_obj stats;
+ struct be_dma_mem stats_cmd;
/* Work queue used to perform periodic tasks like getting statistics */
struct delayed_work work;
@@ -287,6 +284,7 @@ struct be_adapter {
bool promiscuous;
bool wol;
u32 function_mode;
+ u32 function_caps;
u32 rx_fc; /* Rx flow control */
u32 tx_fc; /* Tx flow control */
bool ue_detected;
@@ -313,10 +311,20 @@ struct be_adapter {
extern const struct ethtool_ops be_ethtool_ops;
-#define drvr_stats(adapter) (&adapter->stats.drvr_stats)
+#define tx_stats(adapter) (&adapter->tx_stats)
+#define rx_stats(rxo) (&rxo->stats)
#define BE_SET_NETDEV_OPS(netdev, ops) (netdev->netdev_ops = ops)
+#define for_all_rx_queues(adapter, rxo, i) \
+ for (i = 0, rxo = &adapter->rx_obj[i]; i < adapter->num_rx_qs; \
+ i++, rxo++)
+
+/* Just skip the first default non-rss queue */
+#define for_all_rss_queues(adapter, rxo, i) \
+ for (i = 0, rxo = &adapter->rx_obj[i+1]; i < (adapter->num_rx_qs - 1);\
+ i++, rxo++)
+
#define PAGE_SHIFT_4K 12
#define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K)
@@ -414,6 +422,20 @@ static inline void be_check_sriov_fn_type(struct be_adapter *adapter)
adapter->is_virtfn = (data != 0xAA);
}
+static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
+{
+ u32 addr;
+
+ addr = jhash(adapter->netdev->dev_addr, ETH_ALEN, 0);
+
+ mac[5] = (u8)(addr & 0xFF);
+ mac[4] = (u8)((addr >> 8) & 0xFF);
+ mac[3] = (u8)((addr >> 16) & 0xFF);
+ mac[2] = 0xC9;
+ mac[1] = 0x00;
+ mac[0] = 0x00;
+}
+
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);
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
index 34abcc9403d6..36eca1ce75d4 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -71,7 +71,7 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
if (compl_status == MCC_STATUS_SUCCESS) {
if (compl->tag0 == OPCODE_ETH_GET_STATISTICS) {
struct be_cmd_resp_get_stats *resp =
- adapter->stats.cmd.va;
+ adapter->stats_cmd.va;
be_dws_le_to_cpu(&resp->hw_stats,
sizeof(resp->hw_stats));
netdev_stats_update(adapter);
@@ -96,11 +96,62 @@ static void be_async_link_state_process(struct be_adapter *adapter,
evt->port_link_status == ASYNC_EVENT_LINK_UP);
}
+/* Grp5 CoS Priority evt */
+static void be_async_grp5_cos_priority_process(struct be_adapter *adapter,
+ struct be_async_event_grp5_cos_priority *evt)
+{
+ if (evt->valid) {
+ adapter->vlan_prio_bmap = evt->available_priority_bmap;
+ adapter->recommended_prio =
+ evt->reco_default_priority << VLAN_PRIO_SHIFT;
+ }
+}
+
+/* Grp5 QOS Speed evt */
+static void be_async_grp5_qos_speed_process(struct be_adapter *adapter,
+ struct be_async_event_grp5_qos_link_speed *evt)
+{
+ if (evt->physical_port == adapter->port_num) {
+ /* qos_link_speed is in units of 10 Mbps */
+ adapter->link_speed = evt->qos_link_speed * 10;
+ }
+}
+
+static void be_async_grp5_evt_process(struct be_adapter *adapter,
+ u32 trailer, struct be_mcc_compl *evt)
+{
+ u8 event_type = 0;
+
+ event_type = (trailer >> ASYNC_TRAILER_EVENT_TYPE_SHIFT) &
+ ASYNC_TRAILER_EVENT_TYPE_MASK;
+
+ switch (event_type) {
+ case ASYNC_EVENT_COS_PRIORITY:
+ be_async_grp5_cos_priority_process(adapter,
+ (struct be_async_event_grp5_cos_priority *)evt);
+ break;
+ case ASYNC_EVENT_QOS_SPEED:
+ be_async_grp5_qos_speed_process(adapter,
+ (struct be_async_event_grp5_qos_link_speed *)evt);
+ break;
+ default:
+ dev_warn(&adapter->pdev->dev, "Unknown grp5 event!\n");
+ break;
+ }
+}
+
static inline bool is_link_state_evt(u32 trailer)
{
+ return ((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
+ ASYNC_TRAILER_EVENT_CODE_MASK) ==
+ ASYNC_EVENT_CODE_LINK_STATE;
+}
+
+static inline bool is_grp5_evt(u32 trailer)
+{
return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
ASYNC_TRAILER_EVENT_CODE_MASK) ==
- ASYNC_EVENT_CODE_LINK_STATE);
+ ASYNC_EVENT_CODE_GRP_5);
}
static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter)
@@ -143,6 +194,9 @@ int be_process_mcc(struct be_adapter *adapter, int *status)
if (is_link_state_evt(compl->flags))
be_async_link_state_process(adapter,
(struct be_async_event_link_state *) compl);
+ else if (is_grp5_evt(compl->flags))
+ be_async_grp5_evt_process(adapter,
+ compl->flags, compl);
} else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
*status = be_mcc_compl_process(adapter, compl);
atomic_dec(&mcc_obj->q.used);
@@ -677,10 +731,10 @@ int be_cmd_mccq_create(struct be_adapter *adapter,
ctxt = &req->context;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
- OPCODE_COMMON_MCC_CREATE);
+ OPCODE_COMMON_MCC_CREATE_EXT);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
- OPCODE_COMMON_MCC_CREATE, sizeof(*req));
+ OPCODE_COMMON_MCC_CREATE_EXT, sizeof(*req));
req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
@@ -688,7 +742,8 @@ int be_cmd_mccq_create(struct be_adapter *adapter,
AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt,
be_encoded_q_len(mccq->len));
AMAP_SET_BITS(struct amap_mcc_context, cq_id, ctxt, cq->id);
-
+ /* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */
+ req->async_event_bitmap[0] |= 0x00000022;
be_dws_cpu_to_le(ctxt, sizeof(req->context));
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
@@ -754,7 +809,7 @@ int be_cmd_txq_create(struct be_adapter *adapter,
/* Uses mbox */
int be_cmd_rxq_create(struct be_adapter *adapter,
struct be_queue_info *rxq, u16 cq_id, u16 frag_size,
- u16 max_frame_size, u32 if_id, u32 rss)
+ u16 max_frame_size, u32 if_id, u32 rss, u8 *rss_id)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_eth_rx_create *req;
@@ -785,6 +840,7 @@ int be_cmd_rxq_create(struct be_adapter *adapter,
struct be_cmd_resp_eth_rx_create *resp = embedded_payload(wrb);
rxq->id = le16_to_cpu(resp->id);
rxq->created = true;
+ *rss_id = resp->rss_id;
}
spin_unlock(&adapter->mbox_lock);
@@ -1259,7 +1315,8 @@ err:
}
/* Uses mbox */
-int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *mode)
+int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num,
+ u32 *mode, u32 *caps)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_query_fw_cfg *req;
@@ -1281,6 +1338,7 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *mode)
struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb);
*port_num = le32_to_cpu(resp->phys_port);
*mode = le32_to_cpu(resp->function_mode);
+ *caps = le32_to_cpu(resp->function_caps);
}
spin_unlock(&adapter->mbox_lock);
@@ -1311,6 +1369,37 @@ int be_cmd_reset_function(struct be_adapter *adapter)
return status;
}
+int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_rss_config *req;
+ u32 myhash[10];
+ int status;
+
+ spin_lock(&adapter->mbox_lock);
+
+ wrb = wrb_from_mbox(adapter);
+ req = embedded_payload(wrb);
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
+ OPCODE_ETH_RSS_CONFIG);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
+ OPCODE_ETH_RSS_CONFIG, sizeof(*req));
+
+ req->if_id = cpu_to_le32(adapter->if_handle);
+ req->enable_rss = cpu_to_le16(RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_IPV4);
+ req->cpu_table_size_log2 = cpu_to_le16(fls(table_size) - 1);
+ memcpy(req->cpu_table, rsstable, table_size);
+ memcpy(req->hash, myhash, sizeof(myhash));
+ be_dws_cpu_to_le(req->hash, sizeof(req->hash));
+
+ status = be_mbox_notify_wait(adapter);
+
+ spin_unlock(&adapter->mbox_lock);
+ return status;
+}
+
/* Uses sync mcc */
int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num,
u8 bcn, u8 sts, u8 state)
@@ -1382,42 +1471,6 @@ err:
return status;
}
-/* Uses sync mcc */
-int be_cmd_read_port_type(struct be_adapter *adapter, u32 port,
- u8 *connector)
-{
- struct be_mcc_wrb *wrb;
- struct be_cmd_req_port_type *req;
- int status;
-
- 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(struct be_cmd_resp_port_type), true, 0,
- OPCODE_COMMON_READ_TRANSRECV_DATA);
-
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
- OPCODE_COMMON_READ_TRANSRECV_DATA, sizeof(*req));
-
- req->port = cpu_to_le32(port);
- req->page_num = cpu_to_le32(TR_PAGE_A0);
- status = be_mcc_notify_wait(adapter);
- if (!status) {
- struct be_cmd_resp_port_type *resp = embedded_payload(wrb);
- *connector = resp->data.connector;
- }
-
-err:
- spin_unlock_bh(&adapter->mcc_lock);
- return status;
-}
-
int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
u32 flash_type, u32 flash_opcode, u32 buf_size)
{
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h
index ad1e6fac60c5..8469ff061f30 100644
--- a/drivers/net/benet/be_cmds.h
+++ b/drivers/net/benet/be_cmds.h
@@ -82,7 +82,12 @@ struct be_mcc_compl {
*/
#define ASYNC_TRAILER_EVENT_CODE_SHIFT 8 /* bits 8 - 15 */
#define ASYNC_TRAILER_EVENT_CODE_MASK 0xFF
+#define ASYNC_TRAILER_EVENT_TYPE_SHIFT 16
+#define ASYNC_TRAILER_EVENT_TYPE_MASK 0xFF
#define ASYNC_EVENT_CODE_LINK_STATE 0x1
+#define ASYNC_EVENT_CODE_GRP_5 0x5
+#define ASYNC_EVENT_QOS_SPEED 0x1
+#define ASYNC_EVENT_COS_PRIORITY 0x2
struct be_async_event_trailer {
u32 code;
};
@@ -105,6 +110,30 @@ struct be_async_event_link_state {
struct be_async_event_trailer trailer;
} __packed;
+/* When the event code of an async trailer is GRP-5 and event_type is QOS_SPEED
+ * the mcc_compl must be interpreted as follows
+ */
+struct be_async_event_grp5_qos_link_speed {
+ u8 physical_port;
+ u8 rsvd[5];
+ u16 qos_link_speed;
+ u32 event_tag;
+ struct be_async_event_trailer trailer;
+} __packed;
+
+/* When the event code of an async trailer is GRP5 and event type is
+ * CoS-Priority, the mcc_compl must be interpreted as follows
+ */
+struct be_async_event_grp5_cos_priority {
+ u8 physical_port;
+ u8 available_priority_bmap;
+ u8 reco_default_priority;
+ u8 valid;
+ u8 rsvd0;
+ u8 event_tag;
+ struct be_async_event_trailer trailer;
+} __packed;
+
struct be_mcc_mailbox {
struct be_mcc_wrb wrb;
struct be_mcc_compl compl;
@@ -123,8 +152,9 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_WRITE_FLASHROM 7
#define OPCODE_COMMON_CQ_CREATE 12
#define OPCODE_COMMON_EQ_CREATE 13
-#define OPCODE_COMMON_MCC_CREATE 21
+#define OPCODE_COMMON_MCC_CREATE 21
#define OPCODE_COMMON_SET_QOS 28
+#define OPCODE_COMMON_MCC_CREATE_EXT 90
#define OPCODE_COMMON_SEEPROM_READ 30
#define OPCODE_COMMON_NTWK_RX_FILTER 34
#define OPCODE_COMMON_GET_FW_VERSION 35
@@ -147,6 +177,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_READ_TRANSRECV_DATA 73
#define OPCODE_COMMON_GET_PHY_DETAILS 102
+#define OPCODE_ETH_RSS_CONFIG 1
#define OPCODE_ETH_ACPI_CONFIG 2
#define OPCODE_ETH_PROMISCUOUS 3
#define OPCODE_ETH_GET_STATISTICS 4
@@ -337,6 +368,7 @@ struct be_cmd_req_mcc_create {
struct be_cmd_req_hdr hdr;
u16 num_pages;
u16 rsvd0;
+ u32 async_event_bitmap[1];
u8 context[sizeof(struct amap_mcc_context) / 8];
struct phys_addr pages[8];
} __packed;
@@ -409,7 +441,7 @@ struct be_cmd_req_eth_rx_create {
struct be_cmd_resp_eth_rx_create {
struct be_cmd_resp_hdr hdr;
u16 id;
- u8 cpu_id;
+ u8 rss_id;
u8 rsvd0;
} __packed;
@@ -739,9 +771,10 @@ struct be_cmd_resp_modify_eq_delay {
} __packed;
/******************** Get FW Config *******************/
+#define BE_FUNCTION_CAPS_RSS 0x2
struct be_cmd_req_query_fw_cfg {
struct be_cmd_req_hdr hdr;
- u32 rsvd[30];
+ u32 rsvd[31];
};
struct be_cmd_resp_query_fw_cfg {
@@ -751,6 +784,26 @@ struct be_cmd_resp_query_fw_cfg {
u32 phys_port;
u32 function_mode;
u32 rsvd[26];
+ u32 function_caps;
+};
+
+/******************** RSS Config *******************/
+/* RSS types */
+#define RSS_ENABLE_NONE 0x0
+#define RSS_ENABLE_IPV4 0x1
+#define RSS_ENABLE_TCP_IPV4 0x2
+#define RSS_ENABLE_IPV6 0x4
+#define RSS_ENABLE_TCP_IPV6 0x8
+
+struct be_cmd_req_rss_config {
+ struct be_cmd_req_hdr hdr;
+ u32 if_id;
+ u16 enable_rss;
+ u16 cpu_table_size_log2;
+ u32 hash[10];
+ u8 cpu_table[128];
+ u8 flush;
+ u8 rsvd0[3];
};
/******************** Port Beacon ***************************/
@@ -937,7 +990,7 @@ extern int be_cmd_txq_create(struct be_adapter *adapter,
extern int be_cmd_rxq_create(struct be_adapter *adapter,
struct be_queue_info *rxq, u16 cq_id,
u16 frag_size, u16 max_frame_size, u32 if_id,
- u32 rss);
+ u32 rss, u8 *rss_id);
extern int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
int type);
extern int be_cmd_link_status_query(struct be_adapter *adapter,
@@ -960,15 +1013,15 @@ extern int be_cmd_set_flow_control(struct be_adapter *adapter,
extern int be_cmd_get_flow_control(struct be_adapter *adapter,
u32 *tx_fc, u32 *rx_fc);
extern int be_cmd_query_fw_cfg(struct be_adapter *adapter,
- u32 *port_num, u32 *cap);
+ u32 *port_num, u32 *function_mode, u32 *function_caps);
extern int be_cmd_reset_function(struct be_adapter *adapter);
+extern int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable,
+ u16 table_size);
extern int be_process_mcc(struct be_adapter *adapter, int *status);
extern int be_cmd_set_beacon_state(struct be_adapter *adapter,
u8 port_num, u8 beacon, u8 status, u8 state);
extern int be_cmd_get_beacon_state(struct be_adapter *adapter,
u8 port_num, u32 *state);
-extern int be_cmd_read_port_type(struct be_adapter *adapter, u32 port,
- u8 *connector);
extern int be_cmd_write_flashrom(struct be_adapter *adapter,
struct be_dma_mem *cmd, u32 flash_oper,
u32 flash_opcode, u32 buf_size);
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index 13f0abbc5205..0f46366ecc48 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -26,14 +26,16 @@ struct be_ethtool_stat {
int offset;
};
-enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT, ERXSTAT};
+enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT_TX, DRVSTAT_RX, ERXSTAT};
#define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \
offsetof(_struct, field)
#define NETSTAT_INFO(field) #field, NETSTAT,\
FIELDINFO(struct net_device_stats,\
field)
-#define DRVSTAT_INFO(field) #field, DRVSTAT,\
- FIELDINFO(struct be_drvr_stats, field)
+#define 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 MISCSTAT_INFO(field) #field, MISCSTAT,\
FIELDINFO(struct be_rxf_stats, field)
#define PORTSTAT_INFO(field) #field, PORTSTAT,\
@@ -51,21 +53,12 @@ static const struct be_ethtool_stat et_stats[] = {
{NETSTAT_INFO(tx_errors)},
{NETSTAT_INFO(rx_dropped)},
{NETSTAT_INFO(tx_dropped)},
- {DRVSTAT_INFO(be_tx_reqs)},
- {DRVSTAT_INFO(be_tx_stops)},
- {DRVSTAT_INFO(be_fwd_reqs)},
- {DRVSTAT_INFO(be_tx_wrbs)},
- {DRVSTAT_INFO(be_rx_polls)},
- {DRVSTAT_INFO(be_tx_events)},
- {DRVSTAT_INFO(be_rx_events)},
- {DRVSTAT_INFO(be_tx_compl)},
- {DRVSTAT_INFO(be_rx_compl)},
- {DRVSTAT_INFO(be_rx_mcast_pkt)},
- {DRVSTAT_INFO(be_ethrx_post_fail)},
- {DRVSTAT_INFO(be_802_3_dropped_frames)},
- {DRVSTAT_INFO(be_802_3_malformed_frames)},
- {DRVSTAT_INFO(be_tx_rate)},
- {DRVSTAT_INFO(be_rx_rate)},
+ {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_events)},
+ {DRVSTAT_TX_INFO(be_tx_compl)},
{PORTSTAT_INFO(rx_unicast_frames)},
{PORTSTAT_INFO(rx_multicast_frames)},
{PORTSTAT_INFO(rx_broadcast_frames)},
@@ -91,6 +84,9 @@ static const struct be_ethtool_stat et_stats[] = {
{PORTSTAT_INFO(rx_non_rss_packets)},
{PORTSTAT_INFO(rx_ipv4_packets)},
{PORTSTAT_INFO(rx_ipv6_packets)},
+ {PORTSTAT_INFO(rx_switched_unicast_packets)},
+ {PORTSTAT_INFO(rx_switched_multicast_packets)},
+ {PORTSTAT_INFO(rx_switched_broadcast_packets)},
{PORTSTAT_INFO(tx_unicastframes)},
{PORTSTAT_INFO(tx_multicastframes)},
{PORTSTAT_INFO(tx_broadcastframes)},
@@ -103,11 +99,24 @@ static const struct be_ethtool_stat et_stats[] = {
{MISCSTAT_INFO(rx_drops_too_many_frags)},
{MISCSTAT_INFO(rx_drops_invalid_ring)},
{MISCSTAT_INFO(forwarded_packets)},
- {MISCSTAT_INFO(rx_drops_mtu)},
- {ERXSTAT_INFO(rx_drops_no_fragments)},
+ {MISCSTAT_INFO(rx_drops_mtu)}
};
#define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats)
+/* Stats related to multi RX queues */
+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_polls)},
+ {DRVSTAT_RX_INFO(rx_events)},
+ {DRVSTAT_RX_INFO(rx_compl)},
+ {DRVSTAT_RX_INFO(rx_mcast_pkts)},
+ {DRVSTAT_RX_INFO(rx_post_fail)},
+ {ERXSTAT_INFO(rx_drops_no_fragments)}
+};
+#define ETHTOOL_RXSTATS_NUM (ARRAY_SIZE(et_rx_stats))
+
static const char et_self_tests[][ETH_GSTRING_LEN] = {
"MAC Loopback test",
"PHY Loopback test",
@@ -140,7 +149,7 @@ static int
be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
{
struct be_adapter *adapter = netdev_priv(netdev);
- struct be_eq_obj *rx_eq = &adapter->rx_eq;
+ struct be_eq_obj *rx_eq = &adapter->rx_obj[0].rx_eq;
struct be_eq_obj *tx_eq = &adapter->tx_eq;
coalesce->rx_coalesce_usecs = rx_eq->cur_eqd;
@@ -164,25 +173,49 @@ static int
be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
{
struct be_adapter *adapter = netdev_priv(netdev);
- struct be_eq_obj *rx_eq = &adapter->rx_eq;
+ struct be_rx_obj *rxo;
+ struct be_eq_obj *rx_eq;
struct be_eq_obj *tx_eq = &adapter->tx_eq;
u32 tx_max, tx_min, tx_cur;
u32 rx_max, rx_min, rx_cur;
- int status = 0;
+ int status = 0, i;
if (coalesce->use_adaptive_tx_coalesce == 1)
return -EINVAL;
- /* if AIC is being turned on now, start with an EQD of 0 */
- if (rx_eq->enable_aic == 0 &&
- coalesce->use_adaptive_rx_coalesce == 1) {
- rx_eq->cur_eqd = 0;
+ for_all_rx_queues(adapter, rxo, i) {
+ rx_eq = &rxo->rx_eq;
+
+ if (!rx_eq->enable_aic && coalesce->use_adaptive_rx_coalesce)
+ rx_eq->cur_eqd = 0;
+ rx_eq->enable_aic = coalesce->use_adaptive_rx_coalesce;
+
+ rx_max = coalesce->rx_coalesce_usecs_high;
+ rx_min = coalesce->rx_coalesce_usecs_low;
+ rx_cur = coalesce->rx_coalesce_usecs;
+
+ if (rx_eq->enable_aic) {
+ if (rx_max > BE_MAX_EQD)
+ rx_max = BE_MAX_EQD;
+ if (rx_min > rx_max)
+ rx_min = rx_max;
+ rx_eq->max_eqd = rx_max;
+ rx_eq->min_eqd = rx_min;
+ if (rx_eq->cur_eqd > rx_max)
+ rx_eq->cur_eqd = rx_max;
+ if (rx_eq->cur_eqd < rx_min)
+ rx_eq->cur_eqd = rx_min;
+ } else {
+ if (rx_cur > BE_MAX_EQD)
+ rx_cur = BE_MAX_EQD;
+ if (rx_eq->cur_eqd != rx_cur) {
+ status = be_cmd_modify_eqd(adapter, rx_eq->q.id,
+ rx_cur);
+ if (!status)
+ rx_eq->cur_eqd = rx_cur;
+ }
+ }
}
- rx_eq->enable_aic = coalesce->use_adaptive_rx_coalesce;
-
- rx_max = coalesce->rx_coalesce_usecs_high;
- rx_min = coalesce->rx_coalesce_usecs_low;
- rx_cur = coalesce->rx_coalesce_usecs;
tx_max = coalesce->tx_coalesce_usecs_high;
tx_min = coalesce->tx_coalesce_usecs_low;
@@ -196,27 +229,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
tx_eq->cur_eqd = tx_cur;
}
- if (rx_eq->enable_aic) {
- if (rx_max > BE_MAX_EQD)
- rx_max = BE_MAX_EQD;
- if (rx_min > rx_max)
- rx_min = rx_max;
- rx_eq->max_eqd = rx_max;
- rx_eq->min_eqd = rx_min;
- if (rx_eq->cur_eqd > rx_max)
- rx_eq->cur_eqd = rx_max;
- if (rx_eq->cur_eqd < rx_min)
- rx_eq->cur_eqd = rx_min;
- } else {
- if (rx_cur > BE_MAX_EQD)
- rx_cur = BE_MAX_EQD;
- if (rx_eq->cur_eqd != rx_cur) {
- status = be_cmd_modify_eqd(adapter, rx_eq->q.id,
- rx_cur);
- if (!status)
- rx_eq->cur_eqd = rx_cur;
- }
- }
return 0;
}
@@ -244,32 +256,25 @@ be_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, uint64_t *data)
{
struct be_adapter *adapter = netdev_priv(netdev);
- struct be_drvr_stats *drvr_stats = &adapter->stats.drvr_stats;
- struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats.cmd.va);
- struct be_rxf_stats *rxf_stats = &hw_stats->rxf;
- struct be_port_rxf_stats *port_stats =
- &rxf_stats->port[adapter->port_num];
- struct net_device_stats *net_stats = &netdev->stats;
+ struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats_cmd.va);
struct be_erx_stats *erx_stats = &hw_stats->erx;
+ struct be_rx_obj *rxo;
void *p = NULL;
- int i;
+ int i, j;
for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
switch (et_stats[i].type) {
case NETSTAT:
- p = net_stats;
+ p = &netdev->stats;
break;
- case DRVSTAT:
- p = drvr_stats;
+ case DRVSTAT_TX:
+ p = &adapter->tx_stats;
break;
case PORTSTAT:
- p = port_stats;
+ p = &hw_stats->rxf.port[adapter->port_num];
break;
case MISCSTAT:
- p = rxf_stats;
- break;
- case ERXSTAT: /* Currently only one ERX stat is provided */
- p = (u32 *)erx_stats + adapter->rx_obj.q.id;
+ p = &hw_stats->rxf;
break;
}
@@ -277,19 +282,44 @@ be_get_ethtool_stats(struct net_device *netdev,
data[i] = (et_stats[i].size == sizeof(u64)) ?
*(u64 *)p: *(u32 *)p;
}
+
+ 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 *)erx_stats + rxo->q.id;
+ break;
+ }
+ data[ETHTOOL_STATS_NUM + j * ETHTOOL_RXSTATS_NUM + i] =
+ (et_rx_stats[i].size == sizeof(u64)) ?
+ *(u64 *)p: *(u32 *)p;
+ }
+ }
}
static void
be_get_stat_strings(struct net_device *netdev, uint32_t stringset,
uint8_t *data)
{
- int i;
+ struct be_adapter *adapter = netdev_priv(netdev);
+ int i, j;
+
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
memcpy(data, et_stats[i].desc, ETH_GSTRING_LEN);
data += ETH_GSTRING_LEN;
}
+ for (i = 0; i < adapter->num_rx_qs; i++) {
+ for (j = 0; j < ETHTOOL_RXSTATS_NUM; j++) {
+ sprintf(data, "rxq%d: %s", i,
+ et_rx_stats[j].desc);
+ data += ETH_GSTRING_LEN;
+ }
+ }
break;
case ETH_SS_TEST:
for (i = 0; i < ETHTOOL_TESTS_NUM; i++) {
@@ -302,11 +332,14 @@ be_get_stat_strings(struct net_device *netdev, uint32_t stringset,
static int be_get_sset_count(struct net_device *netdev, int stringset)
{
+ struct be_adapter *adapter = netdev_priv(netdev);
+
switch (stringset) {
case ETH_SS_TEST:
return ETHTOOL_TESTS_NUM;
case ETH_SS_STATS:
- return ETHTOOL_STATS_NUM;
+ return ETHTOOL_STATS_NUM +
+ adapter->num_rx_qs * ETHTOOL_RXSTATS_NUM;
default:
return -EINVAL;
}
@@ -421,10 +454,10 @@ be_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
{
struct be_adapter *adapter = netdev_priv(netdev);
- ring->rx_max_pending = adapter->rx_obj.q.len;
+ ring->rx_max_pending = adapter->rx_obj[0].q.len;
ring->tx_max_pending = adapter->tx_obj.q.len;
- ring->rx_pending = atomic_read(&adapter->rx_obj.q.used);
+ ring->rx_pending = atomic_read(&adapter->rx_obj[0].q.used);
ring->tx_pending = atomic_read(&adapter->tx_obj.q.used);
}
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 6eda7a022256..c36cd2ffbadc 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -32,6 +32,10 @@ module_param(num_vfs, uint, S_IRUGO);
MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data.");
MODULE_PARM_DESC(num_vfs, "Number of PCI VFs to initialize");
+static bool multi_rxq = true;
+module_param(multi_rxq, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(multi_rxq, "Multi Rx Queue support. Enabled by default");
+
static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {
{ PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) },
{ PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) },
@@ -111,6 +115,11 @@ static char *ue_status_hi_desc[] = {
"Unknown"
};
+static inline bool be_multi_rxq(struct be_adapter *adapter)
+{
+ return (adapter->num_rx_qs > 1);
+}
+
static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)
{
struct be_dma_mem *mem = &q->dma_mem;
@@ -236,18 +245,27 @@ netdev_addr:
void netdev_stats_update(struct be_adapter *adapter)
{
- struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats.cmd.va);
+ struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats_cmd.va);
struct be_rxf_stats *rxf_stats = &hw_stats->rxf;
struct be_port_rxf_stats *port_stats =
&rxf_stats->port[adapter->port_num];
struct net_device_stats *dev_stats = &adapter->netdev->stats;
struct be_erx_stats *erx_stats = &hw_stats->erx;
+ struct be_rx_obj *rxo;
+ int i;
+
+ memset(dev_stats, 0, sizeof(*dev_stats));
+ for_all_rx_queues(adapter, rxo, i) {
+ dev_stats->rx_packets += rx_stats(rxo)->rx_pkts;
+ dev_stats->rx_bytes += rx_stats(rxo)->rx_bytes;
+ dev_stats->multicast += rx_stats(rxo)->rx_mcast_pkts;
+ /* no space in linux buffers: best possible approximation */
+ dev_stats->rx_dropped +=
+ erx_stats->rx_drops_no_fragments[rxo->q.id];
+ }
- dev_stats->rx_packets = drvr_stats(adapter)->be_rx_pkts;
- dev_stats->tx_packets = drvr_stats(adapter)->be_tx_pkts;
- dev_stats->rx_bytes = drvr_stats(adapter)->be_rx_bytes;
- dev_stats->tx_bytes = drvr_stats(adapter)->be_tx_bytes;
- dev_stats->multicast = drvr_stats(adapter)->be_rx_mcast_pkt;
+ dev_stats->tx_packets = tx_stats(adapter)->be_tx_pkts;
+ dev_stats->tx_bytes = tx_stats(adapter)->be_tx_bytes;
/* bad pkts received */
dev_stats->rx_errors = port_stats->rx_crc_errors +
@@ -264,18 +282,11 @@ void netdev_stats_update(struct be_adapter *adapter)
port_stats->rx_ip_checksum_errs +
port_stats->rx_udp_checksum_errs;
- /* no space in linux buffers: best possible approximation */
- dev_stats->rx_dropped =
- erx_stats->rx_drops_no_fragments[adapter->rx_obj.q.id];
-
/* detailed rx errors */
dev_stats->rx_length_errors = port_stats->rx_in_range_errors +
port_stats->rx_out_range_errors +
port_stats->rx_frame_too_long;
- /* receive ring buffer overflow */
- dev_stats->rx_over_errors = 0;
-
dev_stats->rx_crc_errors = port_stats->rx_crc_errors;
/* frame alignment errors */
@@ -286,23 +297,6 @@ void netdev_stats_update(struct be_adapter *adapter)
dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow +
port_stats->rx_input_fifo_overflow +
rxf_stats->rx_drops_no_pbuf;
- /* receiver missed packetd */
- dev_stats->rx_missed_errors = 0;
-
- /* packet transmit problems */
- dev_stats->tx_errors = 0;
-
- /* no space available in linux */
- dev_stats->tx_dropped = 0;
-
- dev_stats->collisions = 0;
-
- /* detailed tx_errors */
- dev_stats->tx_aborted_errors = 0;
- dev_stats->tx_carrier_errors = 0;
- dev_stats->tx_fifo_errors = 0;
- dev_stats->tx_heartbeat_errors = 0;
- dev_stats->tx_window_errors = 0;
}
void be_link_status_update(struct be_adapter *adapter, bool link_up)
@@ -326,10 +320,10 @@ void be_link_status_update(struct be_adapter *adapter, bool 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)
+static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo)
{
- struct be_eq_obj *rx_eq = &adapter->rx_eq;
- struct be_drvr_stats *stats = &adapter->stats.drvr_stats;
+ struct be_eq_obj *rx_eq = &rxo->rx_eq;
+ struct be_rx_stats *stats = &rxo->stats;
ulong now = jiffies;
u32 eqd;
@@ -346,12 +340,12 @@ static void be_rx_eqd_update(struct be_adapter *adapter)
if ((now - stats->rx_fps_jiffies) < HZ)
return;
- stats->be_rx_fps = (stats->be_rx_frags - stats->be_prev_rx_frags) /
+ stats->rx_fps = (stats->rx_frags - stats->prev_rx_frags) /
((now - stats->rx_fps_jiffies) / HZ);
stats->rx_fps_jiffies = now;
- stats->be_prev_rx_frags = stats->be_rx_frags;
- eqd = stats->be_rx_fps / 110000;
+ 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;
@@ -365,11 +359,6 @@ static void be_rx_eqd_update(struct be_adapter *adapter)
rx_eq->cur_eqd = eqd;
}
-static struct net_device_stats *be_get_stats(struct net_device *dev)
-{
- return &dev->stats;
-}
-
static u32 be_calc_rate(u64 bytes, unsigned long ticks)
{
u64 rate = bytes;
@@ -383,7 +372,7 @@ static u32 be_calc_rate(u64 bytes, unsigned long ticks)
static void be_tx_rate_update(struct be_adapter *adapter)
{
- struct be_drvr_stats *stats = drvr_stats(adapter);
+ struct be_tx_stats *stats = tx_stats(adapter);
ulong now = jiffies;
/* Wrapped around? */
@@ -405,7 +394,7 @@ static void be_tx_rate_update(struct be_adapter *adapter)
static void be_tx_stats_update(struct be_adapter *adapter,
u32 wrb_cnt, u32 copied, u32 gso_segs, bool stopped)
{
- struct be_drvr_stats *stats = drvr_stats(adapter);
+ struct be_tx_stats *stats = tx_stats(adapter);
stats->be_tx_reqs++;
stats->be_tx_wrbs += wrb_cnt;
stats->be_tx_bytes += copied;
@@ -440,9 +429,12 @@ static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len)
wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK;
}
-static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb,
- bool vlan, u32 wrb_cnt, u32 len)
+static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
+ struct sk_buff *skb, u32 wrb_cnt, u32 len)
{
+ u8 vlan_prio = 0;
+ u16 vlan_tag = 0;
+
memset(hdr, 0, sizeof(*hdr));
AMAP_SET_BITS(struct amap_eth_hdr_wrb, crc, hdr, 1);
@@ -460,10 +452,15 @@ static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb,
AMAP_SET_BITS(struct amap_eth_hdr_wrb, udpcs, hdr, 1);
}
- if (vlan && vlan_tx_tag_present(skb)) {
+ if (adapter->vlan_grp && vlan_tx_tag_present(skb)) {
AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1);
- AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag,
- hdr, vlan_tx_tag_get(skb));
+ vlan_tag = vlan_tx_tag_get(skb);
+ vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
+ /* If vlan priority provided by OS is NOT in available bmap */
+ if (!(adapter->vlan_prio_bmap & (1 << vlan_prio)))
+ vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) |
+ adapter->recommended_prio;
+ AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag);
}
AMAP_SET_BITS(struct amap_eth_hdr_wrb, event, hdr, 1);
@@ -543,8 +540,7 @@ static int make_tx_wrbs(struct be_adapter *adapter,
queue_head_inc(txq);
}
- wrb_fill_hdr(hdr, first_skb, adapter->vlan_grp ? true : false,
- wrb_cnt, copied);
+ wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied);
be_dws_cpu_to_le(hdr, sizeof(*hdr));
return copied;
@@ -637,7 +633,7 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)
if (adapter->vlans_added <= adapter->max_vlans) {
/* Construct VLAN Table to give to HW */
- for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ for (i = 0; i < VLAN_N_VID; i++) {
if (adapter->vlan_tag[i]) {
vtag[ntags] = cpu_to_le16(i);
ntags++;
@@ -656,14 +652,8 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)
static void be_vlan_register(struct net_device *netdev, struct vlan_group *grp)
{
struct be_adapter *adapter = netdev_priv(netdev);
- struct be_eq_obj *rx_eq = &adapter->rx_eq;
- struct be_eq_obj *tx_eq = &adapter->tx_eq;
- be_eq_notify(adapter, rx_eq->q.id, false, false, 0);
- be_eq_notify(adapter, tx_eq->q.id, false, false, 0);
adapter->vlan_grp = grp;
- be_eq_notify(adapter, rx_eq->q.id, true, false, 0);
- be_eq_notify(adapter, tx_eq->q.id, true, false, 0);
}
static void be_vlan_add_vid(struct net_device *netdev, u16 vid)
@@ -825,65 +815,61 @@ static int be_set_vf_tx_rate(struct net_device *netdev,
return status;
}
-static void be_rx_rate_update(struct be_adapter *adapter)
+static void be_rx_rate_update(struct be_rx_obj *rxo)
{
- struct be_drvr_stats *stats = drvr_stats(adapter);
+ struct be_rx_stats *stats = &rxo->stats;
ulong now = jiffies;
/* Wrapped around */
- if (time_before(now, stats->be_rx_jiffies)) {
- stats->be_rx_jiffies = now;
+ if (time_before(now, stats->rx_jiffies)) {
+ stats->rx_jiffies = now;
return;
}
/* Update the rate once in two seconds */
- if ((now - stats->be_rx_jiffies) < 2 * HZ)
+ if ((now - stats->rx_jiffies) < 2 * HZ)
return;
- stats->be_rx_rate = be_calc_rate(stats->be_rx_bytes
- - stats->be_rx_bytes_prev,
- now - stats->be_rx_jiffies);
- stats->be_rx_jiffies = now;
- stats->be_rx_bytes_prev = stats->be_rx_bytes;
+ stats->rx_rate = be_calc_rate(stats->rx_bytes - stats->rx_bytes_prev,
+ now - stats->rx_jiffies);
+ stats->rx_jiffies = now;
+ stats->rx_bytes_prev = stats->rx_bytes;
}
-static void be_rx_stats_update(struct be_adapter *adapter,
+static void be_rx_stats_update(struct be_rx_obj *rxo,
u32 pktsize, u16 numfrags, u8 pkt_type)
{
- struct be_drvr_stats *stats = drvr_stats(adapter);
-
- stats->be_rx_compl++;
- stats->be_rx_frags += numfrags;
- stats->be_rx_bytes += pktsize;
- stats->be_rx_pkts++;
+ struct be_rx_stats *stats = &rxo->stats;
+ stats->rx_compl++;
+ stats->rx_frags += numfrags;
+ stats->rx_bytes += pktsize;
+ stats->rx_pkts++;
if (pkt_type == BE_MULTICAST_PACKET)
- stats->be_rx_mcast_pkt++;
+ stats->rx_mcast_pkts++;
}
-static inline bool do_pkt_csum(struct be_eth_rx_compl *rxcp, bool cso)
+static inline bool csum_passed(struct be_eth_rx_compl *rxcp)
{
- u8 l4_cksm, ip_version, ipcksm, tcpf = 0, udpf = 0, ipv6_chk;
+ u8 l4_cksm, ipv6, ipcksm;
l4_cksm = AMAP_GET_BITS(struct amap_eth_rx_compl, l4_cksm, rxcp);
ipcksm = AMAP_GET_BITS(struct amap_eth_rx_compl, ipcksm, rxcp);
- ip_version = AMAP_GET_BITS(struct amap_eth_rx_compl, ip_version, rxcp);
- if (ip_version) {
- tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp);
- udpf = AMAP_GET_BITS(struct amap_eth_rx_compl, udpf, rxcp);
- }
- ipv6_chk = (ip_version && (tcpf || udpf));
+ ipv6 = AMAP_GET_BITS(struct amap_eth_rx_compl, ip_version, rxcp);
- return ((l4_cksm && ipv6_chk && ipcksm) && cso) ? false : true;
+ /* Ignore ipcksm for ipv6 pkts */
+ return l4_cksm && (ipcksm || ipv6);
}
static struct be_rx_page_info *
-get_rx_page_info(struct be_adapter *adapter, u16 frag_idx)
+get_rx_page_info(struct be_adapter *adapter,
+ struct be_rx_obj *rxo,
+ u16 frag_idx)
{
struct be_rx_page_info *rx_page_info;
- struct be_queue_info *rxq = &adapter->rx_obj.q;
+ struct be_queue_info *rxq = &rxo->q;
- rx_page_info = &adapter->rx_obj.page_info_tbl[frag_idx];
+ rx_page_info = &rxo->page_info_tbl[frag_idx];
BUG_ON(!rx_page_info->page);
if (rx_page_info->last_page_user) {
@@ -898,9 +884,10 @@ get_rx_page_info(struct be_adapter *adapter, u16 frag_idx)
/* Throwaway the data in the Rx completion */
static void be_rx_compl_discard(struct be_adapter *adapter,
- struct be_eth_rx_compl *rxcp)
+ struct be_rx_obj *rxo,
+ struct be_eth_rx_compl *rxcp)
{
- struct be_queue_info *rxq = &adapter->rx_obj.q;
+ struct be_queue_info *rxq = &rxo->q;
struct be_rx_page_info *page_info;
u16 rxq_idx, i, num_rcvd;
@@ -908,7 +895,7 @@ static void be_rx_compl_discard(struct be_adapter *adapter,
num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
for (i = 0; i < num_rcvd; i++) {
- page_info = get_rx_page_info(adapter, rxq_idx);
+ page_info = get_rx_page_info(adapter, rxo, rxq_idx);
put_page(page_info->page);
memset(page_info, 0, sizeof(*page_info));
index_inc(&rxq_idx, rxq->len);
@@ -919,11 +906,11 @@ static void be_rx_compl_discard(struct be_adapter *adapter,
* skb_fill_rx_data forms a complete skb for an ether frame
* indicated by rxcp.
*/
-static void skb_fill_rx_data(struct be_adapter *adapter,
+static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo,
struct sk_buff *skb, struct be_eth_rx_compl *rxcp,
u16 num_rcvd)
{
- struct be_queue_info *rxq = &adapter->rx_obj.q;
+ struct be_queue_info *rxq = &rxo->q;
struct be_rx_page_info *page_info;
u16 rxq_idx, i, j;
u32 pktsize, hdr_len, curr_frag_len, size;
@@ -934,7 +921,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
pktsize = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl, cast_enc, rxcp);
- page_info = get_rx_page_info(adapter, rxq_idx);
+ page_info = get_rx_page_info(adapter, rxo, rxq_idx);
start = page_address(page_info->page) + page_info->page_offset;
prefetch(start);
@@ -972,7 +959,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
for (i = 1, j = 0; i < num_rcvd; i++) {
size -= curr_frag_len;
index_inc(&rxq_idx, rxq->len);
- page_info = get_rx_page_info(adapter, rxq_idx);
+ page_info = get_rx_page_info(adapter, rxo, rxq_idx);
curr_frag_len = min(size, rx_frag_size);
@@ -998,11 +985,12 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
BUG_ON(j > MAX_SKB_FRAGS);
done:
- be_rx_stats_update(adapter, pktsize, num_rcvd, pkt_type);
+ be_rx_stats_update(rxo, pktsize, num_rcvd, pkt_type);
}
/* Process the RX completion indicated by rxcp when GRO is disabled */
static void be_rx_compl_process(struct be_adapter *adapter,
+ struct be_rx_obj *rxo,
struct be_eth_rx_compl *rxcp)
{
struct sk_buff *skb;
@@ -1019,16 +1007,16 @@ static void be_rx_compl_process(struct be_adapter *adapter,
if (unlikely(!skb)) {
if (net_ratelimit())
dev_warn(&adapter->pdev->dev, "skb alloc failed\n");
- be_rx_compl_discard(adapter, rxcp);
+ be_rx_compl_discard(adapter, rxo, rxcp);
return;
}
- skb_fill_rx_data(adapter, skb, rxcp, num_rcvd);
+ skb_fill_rx_data(adapter, rxo, skb, rxcp, num_rcvd);
- if (do_pkt_csum(rxcp, adapter->rx_csum))
- skb->ip_summed = CHECKSUM_NONE;
- else
+ if (likely(adapter->rx_csum && csum_passed(rxcp)))
skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb_checksum_none_assert(skb);
skb->truesize = skb->len + sizeof(struct sk_buff);
skb->protocol = eth_type_trans(skb, adapter->netdev);
@@ -1056,12 +1044,13 @@ static void be_rx_compl_process(struct be_adapter *adapter,
/* Process the RX completion indicated by rxcp when GRO is enabled */
static void be_rx_compl_process_gro(struct be_adapter *adapter,
- struct be_eth_rx_compl *rxcp)
+ struct be_rx_obj *rxo,
+ struct be_eth_rx_compl *rxcp)
{
struct be_rx_page_info *page_info;
struct sk_buff *skb = NULL;
- struct be_queue_info *rxq = &adapter->rx_obj.q;
- struct be_eq_obj *eq_obj = &adapter->rx_eq;
+ struct be_queue_info *rxq = &rxo->q;
+ struct be_eq_obj *eq_obj = &rxo->rx_eq;
u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len;
u16 i, rxq_idx = 0, vid, j;
u8 vtm;
@@ -1085,13 +1074,13 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
skb = napi_get_frags(&eq_obj->napi);
if (!skb) {
- be_rx_compl_discard(adapter, rxcp);
+ be_rx_compl_discard(adapter, rxo, rxcp);
return;
}
remaining = pkt_size;
for (i = 0, j = -1; i < num_rcvd; i++) {
- page_info = get_rx_page_info(adapter, rxq_idx);
+ page_info = get_rx_page_info(adapter, rxo, rxq_idx);
curr_frag_len = min(remaining, rx_frag_size);
@@ -1132,12 +1121,12 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid);
}
- be_rx_stats_update(adapter, pkt_size, num_rcvd, pkt_type);
+ be_rx_stats_update(rxo, pkt_size, num_rcvd, pkt_type);
}
-static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter)
+static struct be_eth_rx_compl *be_rx_compl_get(struct be_rx_obj *rxo)
{
- struct be_eth_rx_compl *rxcp = queue_tail_node(&adapter->rx_obj.cq);
+ struct be_eth_rx_compl *rxcp = queue_tail_node(&rxo->cq);
if (rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] == 0)
return NULL;
@@ -1145,7 +1134,7 @@ static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter)
rmb();
be_dws_le_to_cpu(rxcp, sizeof(*rxcp));
- queue_tail_inc(&adapter->rx_obj.cq);
+ queue_tail_inc(&rxo->cq);
return rxcp;
}
@@ -1171,22 +1160,23 @@ static inline struct page *be_alloc_pages(u32 size)
* Allocate a page, split it to fragments of size rx_frag_size and post as
* receive buffers to BE
*/
-static void be_post_rx_frags(struct be_adapter *adapter)
+static void be_post_rx_frags(struct be_rx_obj *rxo)
{
- struct be_rx_page_info *page_info_tbl = adapter->rx_obj.page_info_tbl;
+ struct be_adapter *adapter = rxo->adapter;
+ struct be_rx_page_info *page_info_tbl = rxo->page_info_tbl;
struct be_rx_page_info *page_info = NULL, *prev_page_info = NULL;
- struct be_queue_info *rxq = &adapter->rx_obj.q;
+ struct be_queue_info *rxq = &rxo->q;
struct page *pagep = NULL;
struct be_eth_rx_d *rxd;
u64 page_dmaaddr = 0, frag_dmaaddr;
u32 posted, page_offset = 0;
- page_info = &page_info_tbl[rxq->head];
+ page_info = &rxo->page_info_tbl[rxq->head];
for (posted = 0; posted < MAX_RX_POST && !page_info->page; posted++) {
if (!pagep) {
pagep = be_alloc_pages(adapter->big_page_size);
if (unlikely(!pagep)) {
- drvr_stats(adapter)->be_ethrx_post_fail++;
+ rxo->stats.rx_post_fail++;
break;
}
page_dmaaddr = pci_map_page(adapter->pdev, pagep, 0,
@@ -1225,7 +1215,7 @@ static void be_post_rx_frags(struct be_adapter *adapter)
be_rxq_notify(adapter, rxq->id, posted);
} else if (atomic_read(&rxq->used) == 0) {
/* Let be_worker replenish when memory is available */
- adapter->rx_post_starved = true;
+ rxo->rx_post_starved = true;
}
}
@@ -1328,17 +1318,17 @@ static void be_eq_clean(struct be_adapter *adapter,
be_eq_notify(adapter, eq_obj->q.id, false, true, num);
}
-static void be_rx_q_clean(struct be_adapter *adapter)
+static void be_rx_q_clean(struct be_adapter *adapter, struct be_rx_obj *rxo)
{
struct be_rx_page_info *page_info;
- struct be_queue_info *rxq = &adapter->rx_obj.q;
- struct be_queue_info *rx_cq = &adapter->rx_obj.cq;
+ struct be_queue_info *rxq = &rxo->q;
+ struct be_queue_info *rx_cq = &rxo->cq;
struct be_eth_rx_compl *rxcp;
u16 tail;
/* First cleanup pending rx completions */
- while ((rxcp = be_rx_compl_get(adapter)) != NULL) {
- be_rx_compl_discard(adapter, rxcp);
+ while ((rxcp = be_rx_compl_get(rxo)) != NULL) {
+ be_rx_compl_discard(adapter, rxo, rxcp);
be_rx_compl_reset(rxcp);
be_cq_notify(adapter, rx_cq->id, true, 1);
}
@@ -1346,7 +1336,7 @@ static void be_rx_q_clean(struct be_adapter *adapter)
/* Then free posted rx buffer that were not used */
tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len;
for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) {
- page_info = get_rx_page_info(adapter, tail);
+ page_info = get_rx_page_info(adapter, rxo, tail);
put_page(page_info->page);
memset(page_info, 0, sizeof(*page_info));
}
@@ -1524,92 +1514,101 @@ tx_eq_free:
static void be_rx_queues_destroy(struct be_adapter *adapter)
{
struct be_queue_info *q;
-
- q = &adapter->rx_obj.q;
- if (q->created) {
- be_cmd_q_destroy(adapter, q, QTYPE_RXQ);
-
- /* After the rxq is invalidated, wait for a grace time
- * of 1ms for all dma to end and the flush compl to arrive
- */
- mdelay(1);
- be_rx_q_clean(adapter);
+ struct be_rx_obj *rxo;
+ int i;
+
+ for_all_rx_queues(adapter, rxo, i) {
+ q = &rxo->q;
+ if (q->created) {
+ be_cmd_q_destroy(adapter, q, QTYPE_RXQ);
+ /* After the rxq is invalidated, wait for a grace time
+ * of 1ms for all dma to end and the flush compl to
+ * arrive
+ */
+ mdelay(1);
+ be_rx_q_clean(adapter, rxo);
+ }
+ be_queue_free(adapter, q);
+
+ q = &rxo->cq;
+ if (q->created)
+ be_cmd_q_destroy(adapter, q, QTYPE_CQ);
+ be_queue_free(adapter, q);
+
+ /* Clear any residual events */
+ q = &rxo->rx_eq.q;
+ if (q->created) {
+ be_eq_clean(adapter, &rxo->rx_eq);
+ be_cmd_q_destroy(adapter, q, QTYPE_EQ);
+ }
+ be_queue_free(adapter, q);
}
- be_queue_free(adapter, q);
-
- q = &adapter->rx_obj.cq;
- if (q->created)
- be_cmd_q_destroy(adapter, q, QTYPE_CQ);
- be_queue_free(adapter, q);
-
- /* Clear any residual events */
- be_eq_clean(adapter, &adapter->rx_eq);
-
- q = &adapter->rx_eq.q;
- if (q->created)
- be_cmd_q_destroy(adapter, q, QTYPE_EQ);
- be_queue_free(adapter, q);
}
static int be_rx_queues_create(struct be_adapter *adapter)
{
struct be_queue_info *eq, *q, *cq;
- int rc;
+ struct be_rx_obj *rxo;
+ int rc, i;
adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
- adapter->rx_eq.max_eqd = BE_MAX_EQD;
- adapter->rx_eq.min_eqd = 0;
- adapter->rx_eq.cur_eqd = 0;
- adapter->rx_eq.enable_aic = true;
-
- /* Alloc Rx Event queue */
- eq = &adapter->rx_eq.q;
- rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN,
- sizeof(struct be_eq_entry));
- if (rc)
- return rc;
-
- /* Ask BE to create Rx Event queue */
- rc = be_cmd_eq_create(adapter, eq, adapter->rx_eq.cur_eqd);
- if (rc)
- goto rx_eq_free;
-
- /* Alloc RX eth compl queue */
- cq = &adapter->rx_obj.cq;
- rc = be_queue_alloc(adapter, cq, RX_CQ_LEN,
- sizeof(struct be_eth_rx_compl));
- if (rc)
- goto rx_eq_destroy;
-
- /* Ask BE to create Rx eth compl queue */
- rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3);
- if (rc)
- goto rx_cq_free;
-
- /* Alloc RX eth queue */
- q = &adapter->rx_obj.q;
- rc = be_queue_alloc(adapter, q, RX_Q_LEN, sizeof(struct be_eth_rx_d));
- if (rc)
- goto rx_cq_destroy;
-
- /* Ask BE to create Rx eth queue */
- rc = be_cmd_rxq_create(adapter, q, cq->id, rx_frag_size,
- BE_MAX_JUMBO_FRAME_SIZE, adapter->if_handle, false);
- if (rc)
- goto rx_q_free;
+ for_all_rx_queues(adapter, rxo, i) {
+ rxo->adapter = adapter;
+ rxo->rx_eq.max_eqd = BE_MAX_EQD;
+ rxo->rx_eq.enable_aic = true;
+
+ /* EQ */
+ eq = &rxo->rx_eq.q;
+ rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN,
+ sizeof(struct be_eq_entry));
+ if (rc)
+ goto err;
+
+ rc = be_cmd_eq_create(adapter, eq, rxo->rx_eq.cur_eqd);
+ if (rc)
+ goto err;
+
+ /* CQ */
+ cq = &rxo->cq;
+ rc = be_queue_alloc(adapter, cq, RX_CQ_LEN,
+ sizeof(struct be_eth_rx_compl));
+ if (rc)
+ goto err;
+
+ rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3);
+ if (rc)
+ goto err;
+
+ /* Rx Q */
+ q = &rxo->q;
+ rc = be_queue_alloc(adapter, q, RX_Q_LEN,
+ sizeof(struct be_eth_rx_d));
+ if (rc)
+ goto err;
+
+ rc = be_cmd_rxq_create(adapter, q, cq->id, rx_frag_size,
+ BE_MAX_JUMBO_FRAME_SIZE, adapter->if_handle,
+ (i > 0) ? 1 : 0/* rss enable */, &rxo->rss_id);
+ if (rc)
+ goto err;
+ }
+
+ if (be_multi_rxq(adapter)) {
+ u8 rsstable[MAX_RSS_QS];
+
+ for_all_rss_queues(adapter, rxo, i)
+ rsstable[i] = rxo->rss_id;
+
+ rc = be_cmd_rss_config(adapter, rsstable,
+ adapter->num_rx_qs - 1);
+ if (rc)
+ goto err;
+ }
return 0;
-rx_q_free:
- be_queue_free(adapter, q);
-rx_cq_destroy:
- be_cmd_q_destroy(adapter, cq, QTYPE_CQ);
-rx_cq_free:
- be_queue_free(adapter, cq);
-rx_eq_destroy:
- be_cmd_q_destroy(adapter, eq, QTYPE_EQ);
-rx_eq_free:
- be_queue_free(adapter, eq);
- return rc;
+err:
+ be_rx_queues_destroy(adapter);
+ return -1;
}
/* There are 8 evt ids per func. Retruns the evt id's bit number */
@@ -1621,24 +1620,31 @@ static inline int be_evt_bit_get(struct be_adapter *adapter, u32 eq_id)
static irqreturn_t be_intx(int irq, void *dev)
{
struct be_adapter *adapter = dev;
- int isr;
+ struct be_rx_obj *rxo;
+ int isr, i;
isr = ioread32(adapter->csr + CEV_ISR0_OFFSET +
(adapter->tx_eq.q.id/ 8) * CEV_ISR_SIZE);
if (!isr)
return IRQ_NONE;
- event_handle(adapter, &adapter->tx_eq);
- event_handle(adapter, &adapter->rx_eq);
+ if ((1 << be_evt_bit_get(adapter, adapter->tx_eq.q.id) & isr))
+ event_handle(adapter, &adapter->tx_eq);
+
+ for_all_rx_queues(adapter, rxo, i) {
+ if ((1 << be_evt_bit_get(adapter, rxo->rx_eq.q.id) & isr))
+ event_handle(adapter, &rxo->rx_eq);
+ }
return IRQ_HANDLED;
}
static irqreturn_t be_msix_rx(int irq, void *dev)
{
- struct be_adapter *adapter = dev;
+ struct be_rx_obj *rxo = dev;
+ struct be_adapter *adapter = rxo->adapter;
- event_handle(adapter, &adapter->rx_eq);
+ event_handle(adapter, &rxo->rx_eq);
return IRQ_HANDLED;
}
@@ -1652,44 +1658,44 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev)
return IRQ_HANDLED;
}
-static inline bool do_gro(struct be_adapter *adapter,
+static inline bool do_gro(struct be_adapter *adapter, struct be_rx_obj *rxo,
struct be_eth_rx_compl *rxcp)
{
int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp);
int tcp_frame = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp);
if (err)
- drvr_stats(adapter)->be_rxcp_err++;
+ rxo->stats.rxcp_err++;
return (tcp_frame && !err) ? true : false;
}
-int be_poll_rx(struct napi_struct *napi, int budget)
+static int be_poll_rx(struct napi_struct *napi, int budget)
{
struct be_eq_obj *rx_eq = container_of(napi, struct be_eq_obj, napi);
- struct be_adapter *adapter =
- container_of(rx_eq, struct be_adapter, rx_eq);
- struct be_queue_info *rx_cq = &adapter->rx_obj.cq;
+ struct be_rx_obj *rxo = container_of(rx_eq, struct be_rx_obj, rx_eq);
+ struct be_adapter *adapter = rxo->adapter;
+ struct be_queue_info *rx_cq = &rxo->cq;
struct be_eth_rx_compl *rxcp;
u32 work_done;
- adapter->stats.drvr_stats.be_rx_polls++;
+ rxo->stats.rx_polls++;
for (work_done = 0; work_done < budget; work_done++) {
- rxcp = be_rx_compl_get(adapter);
+ rxcp = be_rx_compl_get(rxo);
if (!rxcp)
break;
- if (do_gro(adapter, rxcp))
- be_rx_compl_process_gro(adapter, rxcp);
+ if (do_gro(adapter, rxo, rxcp))
+ be_rx_compl_process_gro(adapter, rxo, rxcp);
else
- be_rx_compl_process(adapter, rxcp);
+ be_rx_compl_process(adapter, rxo, rxcp);
be_rx_compl_reset(rxcp);
}
/* Refill the queue */
- if (atomic_read(&adapter->rx_obj.q.used) < RX_FRAGS_REFILL_WM)
- be_post_rx_frags(adapter);
+ if (atomic_read(&rxo->q.used) < RX_FRAGS_REFILL_WM)
+ be_post_rx_frags(rxo);
/* All consumed */
if (work_done < budget) {
@@ -1743,8 +1749,8 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
netif_wake_queue(adapter->netdev);
}
- drvr_stats(adapter)->be_tx_events++;
- drvr_stats(adapter)->be_tx_compl += tx_compl;
+ tx_stats(adapter)->be_tx_events++;
+ tx_stats(adapter)->be_tx_compl += tx_compl;
}
return 1;
@@ -1793,23 +1799,42 @@ 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;
+ int i;
- if (!adapter->stats_ioctl_sent)
- be_cmd_get_stats(adapter, &adapter->stats.cmd);
+ /* when interrupts are not yet enabled, just reap any pending
+ * mcc completions */
+ if (!netif_running(adapter->netdev)) {
+ int mcc_compl, status = 0;
- /* Set EQ delay */
- be_rx_eqd_update(adapter);
+ mcc_compl = be_process_mcc(adapter, &status);
+
+ if (mcc_compl) {
+ struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
+ be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl);
+ }
+ goto reschedule;
+ }
+
+ if (!adapter->stats_ioctl_sent)
+ be_cmd_get_stats(adapter, &adapter->stats_cmd);
be_tx_rate_update(adapter);
- be_rx_rate_update(adapter);
- if (adapter->rx_post_starved) {
- adapter->rx_post_starved = false;
- be_post_rx_frags(adapter);
+ for_all_rx_queues(adapter, rxo, i) {
+ be_rx_rate_update(rxo);
+ be_rx_eqd_update(adapter, rxo);
+
+ if (rxo->rx_post_starved) {
+ rxo->rx_post_starved = false;
+ be_post_rx_frags(rxo);
+ }
}
+
if (!adapter->ue_detected)
be_detect_dump_ue(adapter);
+reschedule:
schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
}
@@ -1821,17 +1846,45 @@ static void be_msix_disable(struct be_adapter *adapter)
}
}
+static int be_num_rxqs_get(struct be_adapter *adapter)
+{
+ if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&
+ !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) {
+ return 1 + MAX_RSS_QS; /* one default non-RSS queue */
+ } else {
+ dev_warn(&adapter->pdev->dev,
+ "No support for multiple RX queues\n");
+ return 1;
+ }
+}
+
static void be_msix_enable(struct be_adapter *adapter)
{
+#define BE_MIN_MSIX_VECTORS (1 + 1) /* Rx + Tx */
int i, status;
- for (i = 0; i < BE_NUM_MSIX_VECTORS; i++)
+ adapter->num_rx_qs = be_num_rxqs_get(adapter);
+
+ for (i = 0; i < (adapter->num_rx_qs + 1); i++)
adapter->msix_entries[i].entry = i;
status = pci_enable_msix(adapter->pdev, adapter->msix_entries,
- BE_NUM_MSIX_VECTORS);
- if (status == 0)
- adapter->msix_enabled = true;
+ adapter->num_rx_qs + 1);
+ if (status == 0) {
+ goto done;
+ } else if (status >= BE_MIN_MSIX_VECTORS) {
+ if (pci_enable_msix(adapter->pdev, adapter->msix_entries,
+ status) == 0) {
+ adapter->num_rx_qs = status - 1;
+ dev_warn(&adapter->pdev->dev,
+ "Could alloc only %d MSIx vectors. "
+ "Using %d RX Qs\n", status, adapter->num_rx_qs);
+ goto done;
+ }
+ }
+ return;
+done:
+ adapter->msix_enabled = true;
}
static void be_sriov_enable(struct be_adapter *adapter)
@@ -1865,38 +1918,50 @@ static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id)
static int be_request_irq(struct be_adapter *adapter,
struct be_eq_obj *eq_obj,
- void *handler, char *desc)
+ void *handler, char *desc, void *context)
{
struct net_device *netdev = adapter->netdev;
int vec;
sprintf(eq_obj->desc, "%s-%s", netdev->name, desc);
vec = be_msix_vec_get(adapter, eq_obj->q.id);
- return request_irq(vec, handler, 0, eq_obj->desc, adapter);
+ return request_irq(vec, handler, 0, eq_obj->desc, context);
}
-static void be_free_irq(struct be_adapter *adapter, struct be_eq_obj *eq_obj)
+static void be_free_irq(struct be_adapter *adapter, struct be_eq_obj *eq_obj,
+ void *context)
{
int vec = be_msix_vec_get(adapter, eq_obj->q.id);
- free_irq(vec, adapter);
+ free_irq(vec, context);
}
static int be_msix_register(struct be_adapter *adapter)
{
- int status;
+ struct be_rx_obj *rxo;
+ int status, i;
+ char qname[10];
- status = be_request_irq(adapter, &adapter->tx_eq, be_msix_tx_mcc, "tx");
+ status = be_request_irq(adapter, &adapter->tx_eq, be_msix_tx_mcc, "tx",
+ adapter);
if (status)
goto err;
- status = be_request_irq(adapter, &adapter->rx_eq, be_msix_rx, "rx");
- if (status)
- goto free_tx_irq;
+ for_all_rx_queues(adapter, rxo, i) {
+ sprintf(qname, "rxq%d", i);
+ status = be_request_irq(adapter, &rxo->rx_eq, be_msix_rx,
+ qname, rxo);
+ if (status)
+ goto err_msix;
+ }
return 0;
-free_tx_irq:
- be_free_irq(adapter, &adapter->tx_eq);
+err_msix:
+ be_free_irq(adapter, &adapter->tx_eq, adapter);
+
+ for (i--, rxo = &adapter->rx_obj[i]; i >= 0; i--, rxo--)
+ be_free_irq(adapter, &rxo->rx_eq, rxo);
+
err:
dev_warn(&adapter->pdev->dev,
"MSIX Request IRQ failed - err %d\n", status);
@@ -1936,6 +2001,8 @@ done:
static void be_irq_unregister(struct be_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
+ struct be_rx_obj *rxo;
+ int i;
if (!adapter->isr_registered)
return;
@@ -1947,8 +2014,11 @@ static void be_irq_unregister(struct be_adapter *adapter)
}
/* MSIx */
- be_free_irq(adapter, &adapter->tx_eq);
- be_free_irq(adapter, &adapter->rx_eq);
+ be_free_irq(adapter, &adapter->tx_eq, adapter);
+
+ for_all_rx_queues(adapter, rxo, i)
+ be_free_irq(adapter, &rxo->rx_eq, rxo);
+
done:
adapter->isr_registered = false;
}
@@ -1956,11 +2026,9 @@ done:
static int be_close(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
- struct be_eq_obj *rx_eq = &adapter->rx_eq;
+ struct be_rx_obj *rxo;
struct be_eq_obj *tx_eq = &adapter->tx_eq;
- int vec;
-
- cancel_delayed_work_sync(&adapter->work);
+ int vec, i;
be_async_mcc_disable(adapter);
@@ -1973,14 +2041,19 @@ static int be_close(struct net_device *netdev)
if (adapter->msix_enabled) {
vec = be_msix_vec_get(adapter, tx_eq->q.id);
synchronize_irq(vec);
- vec = be_msix_vec_get(adapter, rx_eq->q.id);
- synchronize_irq(vec);
+
+ for_all_rx_queues(adapter, rxo, i) {
+ vec = be_msix_vec_get(adapter, rxo->rx_eq.q.id);
+ synchronize_irq(vec);
+ }
} else {
synchronize_irq(netdev->irq);
}
be_irq_unregister(adapter);
- napi_disable(&rx_eq->napi);
+ for_all_rx_queues(adapter, rxo, i)
+ napi_disable(&rxo->rx_eq.napi);
+
napi_disable(&tx_eq->napi);
/* Wait for all pending tx completions to arrive so that
@@ -1994,17 +2067,17 @@ static int be_close(struct net_device *netdev)
static int be_open(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
- struct be_eq_obj *rx_eq = &adapter->rx_eq;
struct be_eq_obj *tx_eq = &adapter->tx_eq;
+ struct be_rx_obj *rxo;
bool link_up;
- int status;
+ int status, i;
u8 mac_speed;
u16 link_speed;
- /* First time posting */
- be_post_rx_frags(adapter);
-
- napi_enable(&rx_eq->napi);
+ for_all_rx_queues(adapter, rxo, i) {
+ be_post_rx_frags(rxo);
+ napi_enable(&rxo->rx_eq.napi);
+ }
napi_enable(&tx_eq->napi);
be_irq_register(adapter);
@@ -2012,17 +2085,15 @@ static int be_open(struct net_device *netdev)
be_intr_set(adapter, true);
/* The evt queues are created in unarmed state; arm them */
- be_eq_notify(adapter, rx_eq->q.id, true, false, 0);
+ for_all_rx_queues(adapter, rxo, i) {
+ be_eq_notify(adapter, rxo->rx_eq.q.id, true, false, 0);
+ be_cq_notify(adapter, rxo->cq.id, true, 0);
+ }
be_eq_notify(adapter, tx_eq->q.id, true, false, 0);
- /* Rx compl queue may be in unarmed state; rearm it */
- be_cq_notify(adapter, adapter->rx_obj.cq.id, true, 0);
-
/* Now that interrupts are on we can process async mcc */
be_async_mcc_enable(adapter);
- schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
-
status = be_cmd_link_status_query(adapter, &link_up, &mac_speed,
&link_speed);
if (status)
@@ -2084,6 +2155,47 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable)
return status;
}
+/*
+ * Generate a seed MAC address from the PF MAC Address using jhash.
+ * MAC Address for VFs are assigned incrementally starting from the seed.
+ * These addresses are programmed in the ASIC by the PF and the VF driver
+ * queries for the MAC address during its probe.
+ */
+static inline int be_vf_eth_addr_config(struct be_adapter *adapter)
+{
+ u32 vf = 0;
+ int status = 0;
+ u8 mac[ETH_ALEN];
+
+ be_vf_eth_addr_generate(adapter, mac);
+
+ for (vf = 0; vf < num_vfs; vf++) {
+ status = be_cmd_pmac_add(adapter, mac,
+ adapter->vf_cfg[vf].vf_if_handle,
+ &adapter->vf_cfg[vf].vf_pmac_id);
+ if (status)
+ dev_err(&adapter->pdev->dev,
+ "Mac address add failed for VF %d\n", vf);
+ else
+ memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN);
+
+ mac[5] += 1;
+ }
+ return status;
+}
+
+static inline void be_vf_eth_addr_rem(struct be_adapter *adapter)
+{
+ u32 vf;
+
+ for (vf = 0; vf < num_vfs; vf++) {
+ if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID)
+ be_cmd_pmac_del(adapter,
+ adapter->vf_cfg[vf].vf_if_handle,
+ adapter->vf_cfg[vf].vf_pmac_id);
+ }
+}
+
static int be_setup(struct be_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
@@ -2098,6 +2210,11 @@ static int be_setup(struct be_adapter *adapter)
BE_IF_FLAGS_PROMISCUOUS |
BE_IF_FLAGS_PASS_L3L4_ERRORS;
en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS;
+
+ if (be_multi_rxq(adapter)) {
+ cap_flags |= BE_IF_FLAGS_RSS;
+ en_flags |= BE_IF_FLAGS_RSS;
+ }
}
status = be_cmd_if_create(adapter, cap_flags, en_flags,
@@ -2143,10 +2260,20 @@ static int be_setup(struct be_adapter *adapter)
if (status != 0)
goto rx_qs_destroy;
+ if (be_physfn(adapter)) {
+ status = be_vf_eth_addr_config(adapter);
+ if (status)
+ goto mcc_q_destroy;
+ }
+
adapter->link_speed = -1;
return 0;
+mcc_q_destroy:
+ if (be_physfn(adapter))
+ be_vf_eth_addr_rem(adapter);
+ be_mcc_queues_destroy(adapter);
rx_qs_destroy:
be_rx_queues_destroy(adapter);
tx_qs_destroy:
@@ -2163,6 +2290,9 @@ do_none:
static int be_clear(struct be_adapter *adapter)
{
+ if (be_physfn(adapter))
+ be_vf_eth_addr_rem(adapter);
+
be_mcc_queues_destroy(adapter);
be_rx_queues_destroy(adapter);
be_tx_queues_destroy(adapter);
@@ -2176,9 +2306,6 @@ static int be_clear(struct be_adapter *adapter)
#define FW_FILE_HDR_SIGN "ServerEngines Corp. "
-char flash_cookie[2][16] = {"*** SE FLAS",
- "H DIRECTORY *** "};
-
static bool be_flash_redboot(struct be_adapter *adapter,
const u8 *p, u32 img_start, int image_size,
int hdr_size)
@@ -2390,7 +2517,6 @@ static struct net_device_ops be_netdev_ops = {
.ndo_open = be_open,
.ndo_stop = be_close,
.ndo_start_xmit = be_xmit,
- .ndo_get_stats = be_get_stats,
.ndo_set_rx_mode = be_set_multicast_list,
.ndo_set_mac_address = be_mac_addr_set,
.ndo_change_mtu = be_change_mtu,
@@ -2407,6 +2533,8 @@ static struct net_device_ops be_netdev_ops = {
static void be_netdev_init(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
+ struct be_rx_obj *rxo;
+ int i;
netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO |
NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_CSUM |
@@ -2428,12 +2556,13 @@ static void be_netdev_init(struct net_device *netdev)
SET_ETHTOOL_OPS(netdev, &be_ethtool_ops);
- netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx,
- BE_NAPI_WEIGHT);
+ for_all_rx_queues(adapter, rxo, i)
+ netif_napi_add(netdev, &rxo->rx_eq.napi, be_poll_rx,
+ BE_NAPI_WEIGHT);
+
netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc,
BE_NAPI_WEIGHT);
- netif_carrier_off(netdev);
netif_stop_queue(netdev);
}
@@ -2563,8 +2692,7 @@ done:
static void be_stats_cleanup(struct be_adapter *adapter)
{
- struct be_stats_obj *stats = &adapter->stats;
- struct be_dma_mem *cmd = &stats->cmd;
+ struct be_dma_mem *cmd = &adapter->stats_cmd;
if (cmd->va)
pci_free_consistent(adapter->pdev, cmd->size,
@@ -2573,8 +2701,7 @@ static void be_stats_cleanup(struct be_adapter *adapter)
static int be_stats_init(struct be_adapter *adapter)
{
- struct be_stats_obj *stats = &adapter->stats;
- struct be_dma_mem *cmd = &stats->cmd;
+ struct be_dma_mem *cmd = &adapter->stats_cmd;
cmd->size = sizeof(struct be_cmd_req_get_stats);
cmd->va = pci_alloc_consistent(adapter->pdev, cmd->size, &cmd->dma);
@@ -2591,6 +2718,8 @@ static void __devexit be_remove(struct pci_dev *pdev)
if (!adapter)
return;
+ cancel_delayed_work_sync(&adapter->work);
+
unregister_netdev(adapter->netdev);
be_clear(adapter);
@@ -2619,8 +2748,8 @@ static int be_get_config(struct be_adapter *adapter)
if (status)
return status;
- status = be_cmd_query_fw_cfg(adapter,
- &adapter->port_num, &adapter->function_mode);
+ status = be_cmd_query_fw_cfg(adapter, &adapter->port_num,
+ &adapter->function_mode, &adapter->function_caps);
if (status)
return status;
@@ -2655,7 +2784,6 @@ static int __devinit be_probe(struct pci_dev *pdev,
struct be_adapter *adapter;
struct net_device *netdev;
-
status = pci_enable_device(pdev);
if (status)
goto do_none;
@@ -2688,11 +2816,8 @@ static int __devinit be_probe(struct pci_dev *pdev,
adapter->pdev = pdev;
pci_set_drvdata(pdev, adapter);
adapter->netdev = netdev;
- be_netdev_init(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
- be_msix_enable(adapter);
-
status = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
if (!status) {
netdev->features |= NETIF_F_HIGHDMA;
@@ -2736,27 +2861,33 @@ static int __devinit be_probe(struct pci_dev *pdev,
if (status)
goto stats_clean;
+ be_msix_enable(adapter);
+
INIT_DELAYED_WORK(&adapter->work, be_worker);
status = be_setup(adapter);
if (status)
- goto stats_clean;
+ goto msix_disable;
+ be_netdev_init(netdev);
status = register_netdev(netdev);
if (status != 0)
goto unsetup;
+ netif_carrier_off(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;
unsetup:
be_clear(adapter);
+msix_disable:
+ be_msix_disable(adapter);
stats_clean:
be_stats_cleanup(adapter);
ctrl_clean:
be_ctrl_cleanup(adapter);
free_netdev:
- be_msix_disable(adapter);
be_sriov_disable(adapter);
free_netdev(adapter->netdev);
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 03d063554b7f..ce1e5e9d06f6 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -1,7 +1,7 @@
/*
* Blackfin On-Chip MAC Driver
*
- * Copyright 2004-2007 Analog Devices Inc.
+ * Copyright 2004-2010 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
@@ -23,7 +23,6 @@
#include <linux/device.h>
#include <linux/spinlock.h>
#include <linux/mii.h>
-#include <linux/phy.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
@@ -76,12 +75,6 @@ static struct net_dma_desc_tx *current_tx_ptr;
static struct net_dma_desc_tx *tx_desc;
static struct net_dma_desc_rx *rx_desc;
-#if defined(CONFIG_BFIN_MAC_RMII)
-static u16 pin_req[] = P_RMII0;
-#else
-static u16 pin_req[] = P_MII0;
-#endif
-
static void desc_list_free(void)
{
struct net_dma_desc_rx *r;
@@ -347,23 +340,23 @@ static void bfin_mac_adjust_link(struct net_device *dev)
}
if (phydev->speed != lp->old_speed) {
-#if defined(CONFIG_BFIN_MAC_RMII)
- u32 opmode = bfin_read_EMAC_OPMODE();
- switch (phydev->speed) {
- case 10:
- opmode |= RMII_10;
- break;
- case 100:
- opmode &= ~(RMII_10);
- break;
- default:
- printk(KERN_WARNING
- "%s: Ack! Speed (%d) is not 10/100!\n",
- DRV_NAME, phydev->speed);
- break;
+ if (phydev->interface == PHY_INTERFACE_MODE_RMII) {
+ u32 opmode = bfin_read_EMAC_OPMODE();
+ switch (phydev->speed) {
+ case 10:
+ opmode |= RMII_10;
+ break;
+ case 100:
+ opmode &= ~RMII_10;
+ break;
+ default:
+ printk(KERN_WARNING
+ "%s: Ack! Speed (%d) is not 10/100!\n",
+ DRV_NAME, phydev->speed);
+ break;
+ }
+ bfin_write_EMAC_OPMODE(opmode);
}
- bfin_write_EMAC_OPMODE(opmode);
-#endif
new_state = 1;
lp->old_speed = phydev->speed;
@@ -392,7 +385,7 @@ static void bfin_mac_adjust_link(struct net_device *dev)
/* MDC = 2.5 MHz */
#define MDC_CLK 2500000
-static int mii_probe(struct net_device *dev)
+static int mii_probe(struct net_device *dev, int phy_mode)
{
struct bfin_mac_local *lp = netdev_priv(dev);
struct phy_device *phydev = NULL;
@@ -411,8 +404,8 @@ static int mii_probe(struct net_device *dev)
sysctl = (sysctl & ~MDCDIV) | SET_MDCDIV(mdc_div);
bfin_write_EMAC_SYSCTL(sysctl);
- /* search for connect PHY device */
- for (i = 0; i < PHY_MAX_ADDR; i++) {
+ /* search for connected PHY device */
+ for (i = 0; i < PHY_MAX_ADDR; ++i) {
struct phy_device *const tmp_phydev = lp->mii_bus->phy_map[i];
if (!tmp_phydev)
@@ -429,13 +422,14 @@ static int mii_probe(struct net_device *dev)
return -ENODEV;
}
-#if defined(CONFIG_BFIN_MAC_RMII)
- phydev = phy_connect(dev, dev_name(&phydev->dev), &bfin_mac_adjust_link,
- 0, PHY_INTERFACE_MODE_RMII);
-#else
+ if (phy_mode != PHY_INTERFACE_MODE_RMII &&
+ phy_mode != PHY_INTERFACE_MODE_MII) {
+ printk(KERN_INFO "%s: Invalid phy interface mode\n", dev->name);
+ return -EINVAL;
+ }
+
phydev = phy_connect(dev, dev_name(&phydev->dev), &bfin_mac_adjust_link,
- 0, PHY_INTERFACE_MODE_MII);
-#endif
+ 0, phy_mode);
if (IS_ERR(phydev)) {
printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
@@ -570,6 +564,8 @@ static const struct ethtool_ops bfin_mac_ethtool_ops = {
/**************************************************************************/
void setup_system_regs(struct net_device *dev)
{
+ struct bfin_mac_local *lp = netdev_priv(dev);
+ int i;
unsigned short sysctl;
/*
@@ -577,6 +573,15 @@ void setup_system_regs(struct net_device *dev)
* Configure checksum support and rcve frame word alignment
*/
sysctl = bfin_read_EMAC_SYSCTL();
+ /*
+ * check if interrupt is requested for any PHY,
+ * enable PHY interrupt only if needed
+ */
+ for (i = 0; i < PHY_MAX_ADDR; ++i)
+ if (lp->mii_bus->irq[i] != PHY_POLL)
+ break;
+ if (i < PHY_MAX_ADDR)
+ sysctl |= PHYIE;
sysctl |= RXDWA;
#if defined(BFIN_MAC_CSUM_OFFLOAD)
sysctl |= RXCKS;
@@ -804,15 +809,14 @@ static void bfin_dump_hwtamp(char *s, ktime_t *hw, ktime_t *ts, struct timecompa
static void bfin_tx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
{
struct bfin_mac_local *lp = netdev_priv(netdev);
- union skb_shared_tx *shtx = skb_tx(skb);
- if (shtx->hardware) {
+ if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
int timeout_cnt = MAX_TIMEOUT_CNT;
/* When doing time stamping, keep the connection to the socket
* a while longer
*/
- shtx->in_progress = 1;
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
/*
* The timestamping is done at the EMAC module's MII/RMII interface
@@ -992,7 +996,6 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
struct bfin_mac_local *lp = netdev_priv(dev);
u16 *data;
u32 data_align = (unsigned long)(skb->data) & 0x3;
- union skb_shared_tx *shtx = skb_tx(skb);
current_tx_ptr->skb = skb;
@@ -1006,7 +1009,7 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
* of this field are the length of the packet payload in bytes and the higher
* 4 bits are the timestamping enable field.
*/
- if (shtx->hardware)
+ if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
*data |= 0x1000;
current_tx_ptr->desc_a.start_addr = (u32)data;
@@ -1016,7 +1019,7 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
} else {
*((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len);
/* enable timestamping for the sent packet */
- if (shtx->hardware)
+ if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
*((u16 *)(current_tx_ptr->packet)) |= 0x1000;
memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data,
skb->len);
@@ -1205,7 +1208,7 @@ static void bfin_mac_disable(void)
/*
* Enable Interrupts, Receive, and Transmit
*/
-static int bfin_mac_enable(void)
+static int bfin_mac_enable(struct phy_device *phydev)
{
int ret;
u32 opmode;
@@ -1235,12 +1238,13 @@ static int bfin_mac_enable(void)
opmode |= DRO | DC | PSF;
opmode |= RE;
-#if defined(CONFIG_BFIN_MAC_RMII)
- opmode |= RMII; /* For Now only 100MBit are supported */
+ if (phydev->interface == PHY_INTERFACE_MODE_RMII) {
+ opmode |= RMII; /* For Now only 100MBit are supported */
#if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) && CONFIG_BF_REV_0_2
- opmode |= TE;
-#endif
+ opmode |= TE;
#endif
+ }
+
/* Turn on the EMAC rx */
bfin_write_EMAC_OPMODE(opmode);
@@ -1272,7 +1276,7 @@ static void bfin_mac_timeout(struct net_device *dev)
if (netif_queue_stopped(lp->ndev))
netif_wake_queue(lp->ndev);
- bfin_mac_enable();
+ bfin_mac_enable(lp->phydev);
/* We can accept TX packets again */
dev->trans_start = jiffies; /* prevent tx timeout */
@@ -1344,11 +1348,19 @@ static void bfin_mac_set_multicast_list(struct net_device *dev)
static int bfin_mac_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
+ struct bfin_mac_local *lp = netdev_priv(netdev);
+
+ if (!netif_running(netdev))
+ return -EINVAL;
+
switch (cmd) {
case SIOCSHWTSTAMP:
return bfin_mac_hwtstamp_ioctl(netdev, ifr, cmd);
default:
- return -EOPNOTSUPP;
+ if (lp->phydev)
+ return phy_mii_ioctl(lp->phydev, ifr, cmd);
+ else
+ return -EOPNOTSUPP;
}
}
@@ -1396,7 +1408,7 @@ static int bfin_mac_open(struct net_device *dev)
setup_mac_addr(dev->dev_addr);
bfin_mac_disable();
- ret = bfin_mac_enable();
+ ret = bfin_mac_enable(lp->phydev);
if (ret)
return ret;
pr_debug("hardware init finished\n");
@@ -1452,6 +1464,7 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
struct net_device *ndev;
struct bfin_mac_local *lp;
struct platform_device *pd;
+ struct bfin_mii_bus_platform_data *mii_bus_data;
int rc;
ndev = alloc_etherdev(sizeof(struct bfin_mac_local));
@@ -1503,11 +1516,12 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
if (!lp->mii_bus) {
dev_err(&pdev->dev, "Cannot get mii_bus!\n");
rc = -ENODEV;
- goto out_err_mii_bus_probe;
+ goto out_err_probe_mac;
}
lp->mii_bus->priv = ndev;
+ mii_bus_data = pd->dev.platform_data;
- rc = mii_probe(ndev);
+ rc = mii_probe(ndev, mii_bus_data->phy_mode);
if (rc) {
dev_err(&pdev->dev, "MII Probe failed!\n");
goto out_err_mii_probe;
@@ -1554,8 +1568,6 @@ out_err_request_irq:
out_err_mii_probe:
mdiobus_unregister(lp->mii_bus);
mdiobus_free(lp->mii_bus);
-out_err_mii_bus_probe:
- peripheral_free_list(pin_req);
out_err_probe_mac:
platform_set_drvdata(pdev, NULL);
free_netdev(ndev);
@@ -1578,8 +1590,6 @@ static int __devexit bfin_mac_remove(struct platform_device *pdev)
free_netdev(ndev);
- peripheral_free_list(pin_req);
-
return 0;
}
@@ -1625,12 +1635,21 @@ static int bfin_mac_resume(struct platform_device *pdev)
static int __devinit bfin_mii_bus_probe(struct platform_device *pdev)
{
struct mii_bus *miibus;
+ struct bfin_mii_bus_platform_data *mii_bus_pd;
+ const unsigned short *pin_req;
int rc, i;
+ mii_bus_pd = dev_get_platdata(&pdev->dev);
+ if (!mii_bus_pd) {
+ dev_err(&pdev->dev, "No peripherals in platform data!\n");
+ return -EINVAL;
+ }
+
/*
* We are setting up a network card,
* so set the GPIO pins to Ethernet mode
*/
+ pin_req = mii_bus_pd->mac_peripherals;
rc = peripheral_request_list(pin_req, DRV_NAME);
if (rc) {
dev_err(&pdev->dev, "Requesting peripherals failed!\n");
@@ -1647,13 +1666,30 @@ static int __devinit bfin_mii_bus_probe(struct platform_device *pdev)
miibus->parent = &pdev->dev;
miibus->name = "bfin_mii_bus";
+ miibus->phy_mask = mii_bus_pd->phy_mask;
+
snprintf(miibus->id, MII_BUS_ID_SIZE, "0");
miibus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
- if (miibus->irq == NULL)
- goto out_err_alloc;
- for (i = 0; i < PHY_MAX_ADDR; ++i)
+ if (!miibus->irq)
+ goto out_err_irq_alloc;
+
+ for (i = rc; i < PHY_MAX_ADDR; ++i)
miibus->irq[i] = PHY_POLL;
+ rc = clamp(mii_bus_pd->phydev_number, 0, PHY_MAX_ADDR);
+ if (rc != mii_bus_pd->phydev_number)
+ dev_err(&pdev->dev, "Invalid number (%i) of phydevs\n",
+ mii_bus_pd->phydev_number);
+ for (i = 0; i < rc; ++i) {
+ unsigned short phyaddr = mii_bus_pd->phydev_data[i].addr;
+ if (phyaddr < PHY_MAX_ADDR)
+ miibus->irq[phyaddr] = mii_bus_pd->phydev_data[i].irq;
+ else
+ dev_err(&pdev->dev,
+ "Invalid PHY address %i for phydev %i\n",
+ phyaddr, i);
+ }
+
rc = mdiobus_register(miibus);
if (rc) {
dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
@@ -1665,6 +1701,7 @@ static int __devinit bfin_mii_bus_probe(struct platform_device *pdev)
out_err_mdiobus_register:
kfree(miibus->irq);
+out_err_irq_alloc:
mdiobus_free(miibus);
out_err_alloc:
peripheral_free_list(pin_req);
@@ -1675,11 +1712,15 @@ out_err_alloc:
static int __devexit bfin_mii_bus_remove(struct platform_device *pdev)
{
struct mii_bus *miibus = platform_get_drvdata(pdev);
+ struct bfin_mii_bus_platform_data *mii_bus_pd =
+ dev_get_platdata(&pdev->dev);
+
platform_set_drvdata(pdev, NULL);
mdiobus_unregister(miibus);
kfree(miibus->irq);
mdiobus_free(miibus);
- peripheral_free_list(pin_req);
+ peripheral_free_list(mii_bus_pd->mac_peripherals);
+
return 0;
}
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
index 04e4050df18b..aed68bed2365 100644
--- a/drivers/net/bfin_mac.h
+++ b/drivers/net/bfin_mac.h
@@ -14,6 +14,8 @@
#include <linux/clocksource.h>
#include <linux/timecompare.h>
#include <linux/timer.h>
+#include <linux/etherdevice.h>
+#include <linux/bfin_mac.h>
#define BFIN_MAC_CSUM_OFFLOAD
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 959add2410bf..a1b8c8b8010b 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -1233,15 +1233,8 @@ static void bmac_reset_and_enable(struct net_device *dev)
}
spin_unlock_irqrestore(&bp->lock, flags);
}
-static void bmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
- struct bmac_data *bp = netdev_priv(dev);
- strcpy(info->driver, "bmac");
- strcpy(info->bus_info, dev_name(&bp->mdev->ofdev.dev));
-}
static const struct ethtool_ops bmac_ethtool_ops = {
- .get_drvinfo = bmac_get_drvinfo,
.get_link = ethtool_op_get_link,
};
@@ -1588,7 +1581,7 @@ bmac_proc_info(char *buffer, char **start, off_t offset, int length)
int i;
if (bmac_devs == NULL)
- return (-ENOSYS);
+ return -ENOSYS;
len += sprintf(buffer, "BMAC counters & registers\n");
diff --git a/drivers/net/bna/Makefile b/drivers/net/bna/Makefile
new file mode 100644
index 000000000000..a5d604de7fea
--- /dev/null
+++ b/drivers/net/bna/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+# All rights reserved.
+#
+
+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
+
+EXTRA_CFLAGS := -Idrivers/net/bna
diff --git a/drivers/net/bna/bfa_cee.c b/drivers/net/bna/bfa_cee.c
new file mode 100644
index 000000000000..f7b789a3b217
--- /dev/null
+++ b/drivers/net/bna/bfa_cee.c
@@ -0,0 +1,291 @@
+/*
+ * 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_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);
+
+static void
+bfa_cee_format_cee_cfg(void *buffer)
+{
+ struct bfa_cee_attr *cee_cfg = buffer;
+ bfa_cee_format_lldp_cfg(&cee_cfg->lldp_remote);
+}
+
+static void
+bfa_cee_stats_swap(struct bfa_cee_stats *stats)
+{
+ u32 *buffer = (u32 *)stats;
+ int i;
+
+ for (i = 0; i < (sizeof(struct bfa_cee_stats) / sizeof(u32));
+ i++) {
+ buffer[i] = ntohl(buffer[i]);
+ }
+}
+
+static void
+bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg *lldp_cfg)
+{
+ lldp_cfg->time_to_live =
+ ntohs(lldp_cfg->time_to_live);
+ lldp_cfg->enabled_system_cap =
+ ntohs(lldp_cfg->enabled_system_cap);
+}
+
+/**
+ * bfa_cee_attr_meminfo()
+ *
+ * @brief Returns the size of the DMA memory needed by CEE attributes
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+static u32
+bfa_cee_attr_meminfo(void)
+{
+ return roundup(sizeof(struct bfa_cee_attr), BFA_DMA_ALIGN_SZ);
+}
+/**
+ * bfa_cee_stats_meminfo()
+ *
+ * @brief Returns the size of the DMA memory needed by CEE stats
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+static u32
+bfa_cee_stats_meminfo(void)
+{
+ return roundup(sizeof(struct bfa_cee_stats), BFA_DMA_ALIGN_SZ);
+}
+
+/**
+ * bfa_cee_get_attr_isr()
+ *
+ * @brief CEE ISR for get-attributes responses from f/w
+ *
+ * @param[in] cee - Pointer to the CEE module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_cee_get_attr_isr(struct bfa_cee *cee, enum bfa_status status)
+{
+ cee->get_attr_status = status;
+ if (status == BFA_STATUS_OK) {
+ memcpy(cee->attr, cee->attr_dma.kva,
+ sizeof(struct bfa_cee_attr));
+ bfa_cee_format_cee_cfg(cee->attr);
+ }
+ cee->get_attr_pending = false;
+ if (cee->cbfn.get_attr_cbfn)
+ cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg, status);
+}
+
+/**
+ * bfa_cee_get_attr_isr()
+ *
+ * @brief CEE ISR for get-stats responses from f/w
+ *
+ * @param[in] cee - Pointer to the CEE module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_cee_get_stats_isr(struct bfa_cee *cee, enum bfa_status status)
+{
+ cee->get_stats_status = status;
+ if (status == BFA_STATUS_OK) {
+ memcpy(cee->stats, cee->stats_dma.kva,
+ sizeof(struct bfa_cee_stats));
+ bfa_cee_stats_swap(cee->stats);
+ }
+ cee->get_stats_pending = false;
+ if (cee->cbfn.get_stats_cbfn)
+ cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg, status);
+}
+
+/**
+ * bfa_cee_get_attr_isr()
+ *
+ * @brief CEE ISR for reset-stats responses from f/w
+ *
+ * @param[in] cee - Pointer to the CEE module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_cee_reset_stats_isr(struct bfa_cee *cee, enum bfa_status status)
+{
+ cee->reset_stats_status = status;
+ cee->reset_stats_pending = false;
+ if (cee->cbfn.reset_stats_cbfn)
+ cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg, status);
+}
+/**
+ * bfa_nw_cee_meminfo()
+ *
+ * @brief Returns the size of the DMA memory needed by CEE module
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+u32
+bfa_nw_cee_meminfo(void)
+{
+ return bfa_cee_attr_meminfo() + bfa_cee_stats_meminfo();
+}
+
+/**
+ * bfa_nw_cee_mem_claim()
+ *
+ * @brief Initialized CEE DMA Memory
+ *
+ * @param[in] cee CEE module pointer
+ * dma_kva Kernel Virtual Address of CEE DMA Memory
+ * dma_pa Physical Address of CEE DMA Memory
+ *
+ * @return void
+ */
+void
+bfa_nw_cee_mem_claim(struct bfa_cee *cee, u8 *dma_kva, u64 dma_pa)
+{
+ cee->attr_dma.kva = dma_kva;
+ cee->attr_dma.pa = dma_pa;
+ cee->stats_dma.kva = dma_kva + bfa_cee_attr_meminfo();
+ cee->stats_dma.pa = dma_pa + bfa_cee_attr_meminfo();
+ cee->attr = (struct bfa_cee_attr *) dma_kva;
+ cee->stats = (struct bfa_cee_stats *)
+ (dma_kva + bfa_cee_attr_meminfo());
+}
+
+/**
+ * bfa_cee_isrs()
+ *
+ * @brief Handles Mail-box interrupts for CEE module.
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return void
+ */
+
+static void
+bfa_cee_isr(void *cbarg, struct bfi_mbmsg *m)
+{
+ union bfi_cee_i2h_msg_u *msg;
+ struct bfi_cee_get_rsp *get_rsp;
+ struct bfa_cee *cee = (struct bfa_cee *) cbarg;
+ msg = (union bfi_cee_i2h_msg_u *) m;
+ get_rsp = (struct bfi_cee_get_rsp *) m;
+ switch (msg->mh.msg_id) {
+ case BFI_CEE_I2H_GET_CFG_RSP:
+ bfa_cee_get_attr_isr(cee, get_rsp->cmd_status);
+ break;
+ case BFI_CEE_I2H_GET_STATS_RSP:
+ bfa_cee_get_stats_isr(cee, get_rsp->cmd_status);
+ break;
+ case BFI_CEE_I2H_RESET_STATS_RSP:
+ bfa_cee_reset_stats_isr(cee, get_rsp->cmd_status);
+ break;
+ default:
+ BUG_ON(1);
+ }
+}
+
+/**
+ * bfa_cee_hbfail()
+ *
+ * @brief CEE module heart-beat failure handler.
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return void
+ */
+
+static void
+bfa_cee_hbfail(void *arg)
+{
+ struct bfa_cee *cee;
+ cee = (struct bfa_cee *) arg;
+
+ if (cee->get_attr_pending == true) {
+ cee->get_attr_status = BFA_STATUS_FAILED;
+ cee->get_attr_pending = false;
+ if (cee->cbfn.get_attr_cbfn) {
+ cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg,
+ BFA_STATUS_FAILED);
+ }
+ }
+ if (cee->get_stats_pending == true) {
+ cee->get_stats_status = BFA_STATUS_FAILED;
+ cee->get_stats_pending = false;
+ if (cee->cbfn.get_stats_cbfn) {
+ cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg,
+ BFA_STATUS_FAILED);
+ }
+ }
+ if (cee->reset_stats_pending == true) {
+ cee->reset_stats_status = BFA_STATUS_FAILED;
+ cee->reset_stats_pending = false;
+ if (cee->cbfn.reset_stats_cbfn) {
+ cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg,
+ BFA_STATUS_FAILED);
+ }
+ }
+}
+
+/**
+ * bfa_nw_cee_attach()
+ *
+ * @brief CEE module-attach API
+ *
+ * @param[in] cee - Pointer to the CEE module data structure
+ * ioc - Pointer to the ioc module data structure
+ * dev - Pointer to the device driver module data structure
+ * The device driver specific mbox ISR functions have
+ * this pointer as one of the parameters.
+ *
+ * @return void
+ */
+void
+bfa_nw_cee_attach(struct bfa_cee *cee, struct bfa_ioc *ioc,
+ void *dev)
+{
+ BUG_ON(!(cee != NULL));
+ cee->dev = dev;
+ cee->ioc = ioc;
+
+ bfa_nw_ioc_mbox_regisr(cee->ioc, BFI_MC_CEE, bfa_cee_isr, cee);
+ bfa_ioc_hbfail_init(&cee->hbfail, bfa_cee_hbfail, cee);
+ bfa_nw_ioc_hbfail_register(cee->ioc, &cee->hbfail);
+}
diff --git a/drivers/net/bna/bfa_cee.h b/drivers/net/bna/bfa_cee.h
new file mode 100644
index 000000000000..20543d15b64f
--- /dev/null
+++ b/drivers/net/bna/bfa_cee.h
@@ -0,0 +1,64 @@
+/*
+ * 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 __BFA_CEE_H__
+#define __BFA_CEE_H__
+
+#include "bfa_defs_cna.h"
+#include "bfa_ioc.h"
+
+typedef void (*bfa_cee_get_attr_cbfn_t) (void *dev, enum bfa_status status);
+typedef void (*bfa_cee_get_stats_cbfn_t) (void *dev, enum bfa_status status);
+typedef void (*bfa_cee_reset_stats_cbfn_t) (void *dev, enum bfa_status status);
+typedef void (*bfa_cee_hbfail_cbfn_t) (void *dev, enum bfa_status status);
+
+struct bfa_cee_cbfn {
+ bfa_cee_get_attr_cbfn_t get_attr_cbfn;
+ void *get_attr_cbarg;
+ bfa_cee_get_stats_cbfn_t get_stats_cbfn;
+ void *get_stats_cbarg;
+ bfa_cee_reset_stats_cbfn_t reset_stats_cbfn;
+ void *reset_stats_cbarg;
+};
+
+struct bfa_cee {
+ void *dev;
+ bool get_attr_pending;
+ bool get_stats_pending;
+ bool reset_stats_pending;
+ enum bfa_status get_attr_status;
+ enum bfa_status get_stats_status;
+ enum bfa_status reset_stats_status;
+ struct bfa_cee_cbfn cbfn;
+ struct bfa_ioc_hbfail_notify hbfail;
+ struct bfa_cee_attr *attr;
+ struct bfa_cee_stats *stats;
+ struct bfa_dma attr_dma;
+ struct bfa_dma stats_dma;
+ struct bfa_ioc *ioc;
+ struct bfa_mbox_cmd get_cfg_mb;
+ struct bfa_mbox_cmd get_stats_mb;
+ struct bfa_mbox_cmd reset_stats_mb;
+};
+
+u32 bfa_nw_cee_meminfo(void);
+void bfa_nw_cee_mem_claim(struct bfa_cee *cee, u8 *dma_kva,
+ u64 dma_pa);
+void bfa_nw_cee_attach(struct bfa_cee *cee, struct bfa_ioc *ioc, void *dev);
+
+#endif /* __BFA_CEE_H__ */
diff --git a/drivers/net/bna/bfa_defs.h b/drivers/net/bna/bfa_defs.h
new file mode 100644
index 000000000000..29c1b8de2c2d
--- /dev/null
+++ b/drivers/net/bna/bfa_defs.h
@@ -0,0 +1,243 @@
+/*
+ * 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 __BFA_DEFS_H__
+#define __BFA_DEFS_H__
+
+#include "cna.h"
+#include "bfa_defs_status.h"
+#include "bfa_defs_mfg_comm.h"
+
+#define BFA_STRING_32 32
+#define BFA_VERSION_LEN 64
+
+/**
+ * ---------------------- adapter definitions ------------
+ */
+
+/**
+ * BFA adapter level attributes.
+ */
+enum {
+ BFA_ADAPTER_SERIAL_NUM_LEN = STRSZ(BFA_MFG_SERIALNUM_SIZE),
+ /*
+ *!< adapter serial num length
+ */
+ BFA_ADAPTER_MODEL_NAME_LEN = 16, /*!< model name length */
+ BFA_ADAPTER_MODEL_DESCR_LEN = 128, /*!< model description length */
+ BFA_ADAPTER_MFG_NAME_LEN = 8, /*!< manufacturer name length */
+ BFA_ADAPTER_SYM_NAME_LEN = 64, /*!< adapter symbolic name length */
+ BFA_ADAPTER_OS_TYPE_LEN = 64, /*!< adapter os type length */
+};
+
+struct bfa_adapter_attr {
+ char manufacturer[BFA_ADAPTER_MFG_NAME_LEN];
+ char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
+ u32 card_type;
+ char model[BFA_ADAPTER_MODEL_NAME_LEN];
+ char model_descr[BFA_ADAPTER_MODEL_DESCR_LEN];
+ u64 pwwn;
+ char node_symname[FC_SYMNAME_MAX];
+ char hw_ver[BFA_VERSION_LEN];
+ char fw_ver[BFA_VERSION_LEN];
+ char optrom_ver[BFA_VERSION_LEN];
+ char os_type[BFA_ADAPTER_OS_TYPE_LEN];
+ struct bfa_mfg_vpd vpd;
+ struct mac mac;
+
+ u8 nports;
+ u8 max_speed;
+ u8 prototype;
+ char asic_rev;
+
+ u8 pcie_gen;
+ u8 pcie_lanes_orig;
+ u8 pcie_lanes;
+ u8 cna_capable;
+
+ u8 is_mezz;
+ u8 trunk_capable;
+};
+
+/**
+ * ---------------------- IOC definitions ------------
+ */
+
+enum {
+ BFA_IOC_DRIVER_LEN = 16,
+ BFA_IOC_CHIP_REV_LEN = 8,
+};
+
+/**
+ * Driver and firmware versions.
+ */
+struct bfa_ioc_driver_attr {
+ char driver[BFA_IOC_DRIVER_LEN]; /*!< driver name */
+ char driver_ver[BFA_VERSION_LEN]; /*!< driver version */
+ char fw_ver[BFA_VERSION_LEN]; /*!< firmware version */
+ char bios_ver[BFA_VERSION_LEN]; /*!< bios version */
+ char efi_ver[BFA_VERSION_LEN]; /*!< EFI version */
+ char ob_ver[BFA_VERSION_LEN]; /*!< openboot version */
+};
+
+/**
+ * IOC PCI device attributes
+ */
+struct bfa_ioc_pci_attr {
+ u16 vendor_id; /*!< PCI vendor ID */
+ u16 device_id; /*!< PCI device ID */
+ u16 ssid; /*!< subsystem ID */
+ u16 ssvid; /*!< subsystem vendor ID */
+ u32 pcifn; /*!< PCI device function */
+ u32 rsvd; /* padding */
+ char chip_rev[BFA_IOC_CHIP_REV_LEN]; /*!< chip revision */
+};
+
+/**
+ * IOC states
+ */
+enum bfa_ioc_state {
+ BFA_IOC_RESET = 1, /*!< IOC is in reset state */
+ BFA_IOC_SEMWAIT = 2, /*!< Waiting for IOC h/w semaphore */
+ BFA_IOC_HWINIT = 3, /*!< IOC h/w is being initialized */
+ BFA_IOC_GETATTR = 4, /*!< IOC is being configured */
+ BFA_IOC_OPERATIONAL = 5, /*!< IOC is operational */
+ BFA_IOC_INITFAIL = 6, /*!< IOC hardware failure */
+ BFA_IOC_HBFAIL = 7, /*!< IOC heart-beat failure */
+ BFA_IOC_DISABLING = 8, /*!< IOC is being disabled */
+ BFA_IOC_DISABLED = 9, /*!< IOC is disabled */
+ BFA_IOC_FWMISMATCH = 10, /*!< IOC f/w different from drivers */
+};
+
+/**
+ * IOC firmware stats
+ */
+struct bfa_fw_ioc_stats {
+ u32 enable_reqs;
+ u32 disable_reqs;
+ u32 get_attr_reqs;
+ u32 dbg_sync;
+ u32 dbg_dump;
+ u32 unknown_reqs;
+};
+
+/**
+ * IOC driver stats
+ */
+struct bfa_ioc_drv_stats {
+ u32 ioc_isrs;
+ u32 ioc_enables;
+ u32 ioc_disables;
+ u32 ioc_hbfails;
+ u32 ioc_boots;
+ u32 stats_tmos;
+ u32 hb_count;
+ u32 disable_reqs;
+ u32 enable_reqs;
+ u32 disable_replies;
+ u32 enable_replies;
+};
+
+/**
+ * IOC statistics
+ */
+struct bfa_ioc_stats {
+ struct bfa_ioc_drv_stats drv_stats; /*!< driver IOC stats */
+ struct bfa_fw_ioc_stats fw_stats; /*!< firmware IOC stats */
+};
+
+enum bfa_ioc_type {
+ BFA_IOC_TYPE_FC = 1,
+ BFA_IOC_TYPE_FCoE = 2,
+ BFA_IOC_TYPE_LL = 3,
+};
+
+/**
+ * IOC attributes returned in queries
+ */
+struct bfa_ioc_attr {
+ enum bfa_ioc_type ioc_type;
+ enum bfa_ioc_state state; /*!< IOC state */
+ 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 */
+};
+
+/**
+ * ---------------------- mfg definitions ------------
+ */
+
+/**
+ * Checksum size
+ */
+#define BFA_MFG_CHKSUM_SIZE 16
+
+#define BFA_MFG_PARTNUM_SIZE 14
+#define BFA_MFG_SUPPLIER_ID_SIZE 10
+#define BFA_MFG_SUPPLIER_PARTNUM_SIZE 20
+#define BFA_MFG_SUPPLIER_SERIALNUM_SIZE 20
+#define BFA_MFG_SUPPLIER_REVISION_SIZE 4
+
+#pragma pack(1)
+
+/**
+ * @brief BFA adapter manufacturing block definition.
+ *
+ * All numerical fields are in big-endian format.
+ */
+struct bfa_mfg_block {
+ u8 version; /*!< manufacturing block version */
+ u8 mfg_sig[3]; /*!< characters 'M', 'F', 'G' */
+ u16 mfgsize; /*!< mfg block size */
+ u16 u16_chksum; /*!< old u16 checksum */
+ char brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)];
+ char brcd_partnum[STRSZ(BFA_MFG_PARTNUM_SIZE)];
+ u8 mfg_day; /*!< manufacturing day */
+ u8 mfg_month; /*!< manufacturing month */
+ u16 mfg_year; /*!< manufacturing year */
+ u64 mfg_wwn; /*!< wwn base for this adapter */
+ u8 num_wwn; /*!< number of wwns assigned */
+ u8 mfg_speeds; /*!< speeds allowed for this adapter */
+ u8 rsv[2];
+ char supplier_id[STRSZ(BFA_MFG_SUPPLIER_ID_SIZE)];
+ char supplier_partnum[STRSZ(BFA_MFG_SUPPLIER_PARTNUM_SIZE)];
+ char
+ supplier_serialnum[STRSZ(BFA_MFG_SUPPLIER_SERIALNUM_SIZE)];
+ char
+ supplier_revision[STRSZ(BFA_MFG_SUPPLIER_REVISION_SIZE)];
+ mac_t mfg_mac; /*!< mac address */
+ u8 num_mac; /*!< number of mac addresses */
+ u8 rsv2;
+ u32 mfg_type; /*!< card type */
+ u8 rsv3[108];
+ u8 md5_chksum[BFA_MFG_CHKSUM_SIZE]; /*!< md5 checksum */
+};
+
+#pragma pack()
+
+/**
+ * ---------------------- pci definitions ------------
+ */
+
+#define bfa_asic_id_ct(devid) \
+ ((devid) == PCI_DEVICE_ID_BROCADE_CT || \
+ (devid) == PCI_DEVICE_ID_BROCADE_CT_FC)
+
+#endif /* __BFA_DEFS_H__ */
diff --git a/drivers/net/bna/bfa_defs_cna.h b/drivers/net/bna/bfa_defs_cna.h
new file mode 100644
index 000000000000..7e0a9187bdd5
--- /dev/null
+++ b/drivers/net/bna/bfa_defs_cna.h
@@ -0,0 +1,223 @@
+/*
+ * 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 __BFA_DEFS_CNA_H__
+#define __BFA_DEFS_CNA_H__
+
+#include "bfa_defs.h"
+
+/**
+ * @brief
+ * FC physical port statistics.
+ */
+struct bfa_port_fc_stats {
+ u64 secs_reset; /*!< Seconds since stats is reset */
+ u64 tx_frames; /*!< Tx frames */
+ u64 tx_words; /*!< Tx words */
+ u64 tx_lip; /*!< Tx LIP */
+ u64 tx_nos; /*!< Tx NOS */
+ u64 tx_ols; /*!< Tx OLS */
+ u64 tx_lr; /*!< Tx LR */
+ u64 tx_lrr; /*!< Tx LRR */
+ u64 rx_frames; /*!< Rx frames */
+ u64 rx_words; /*!< Rx words */
+ u64 lip_count; /*!< Rx LIP */
+ u64 nos_count; /*!< Rx NOS */
+ u64 ols_count; /*!< Rx OLS */
+ u64 lr_count; /*!< Rx LR */
+ u64 lrr_count; /*!< Rx LRR */
+ u64 invalid_crcs; /*!< Rx CRC err frames */
+ u64 invalid_crc_gd_eof; /*!< Rx CRC err good EOF frames */
+ u64 undersized_frm; /*!< Rx undersized frames */
+ u64 oversized_frm; /*!< Rx oversized frames */
+ u64 bad_eof_frm; /*!< Rx frames with bad EOF */
+ u64 error_frames; /*!< Errored frames */
+ u64 dropped_frames; /*!< Dropped frames */
+ u64 link_failures; /*!< Link Failure (LF) count */
+ u64 loss_of_syncs; /*!< Loss of sync count */
+ u64 loss_of_signals; /*!< Loss of signal count */
+ u64 primseq_errs; /*!< Primitive sequence protocol err. */
+ u64 bad_os_count; /*!< Invalid ordered sets */
+ u64 err_enc_out; /*!< Encoding err nonframe_8b10b */
+ u64 err_enc; /*!< Encoding err frame_8b10b */
+};
+
+/**
+ * @brief
+ * Eth Physical Port statistics.
+ */
+struct bfa_port_eth_stats {
+ u64 secs_reset; /*!< Seconds since stats is reset */
+ u64 frame_64; /*!< Frames 64 bytes */
+ u64 frame_65_127; /*!< Frames 65-127 bytes */
+ u64 frame_128_255; /*!< Frames 128-255 bytes */
+ u64 frame_256_511; /*!< Frames 256-511 bytes */
+ u64 frame_512_1023; /*!< Frames 512-1023 bytes */
+ u64 frame_1024_1518; /*!< Frames 1024-1518 bytes */
+ u64 frame_1519_1522; /*!< Frames 1519-1522 bytes */
+ u64 tx_bytes; /*!< Tx bytes */
+ u64 tx_packets; /*!< Tx packets */
+ u64 tx_mcast_packets; /*!< Tx multicast packets */
+ u64 tx_bcast_packets; /*!< Tx broadcast packets */
+ u64 tx_control_frame; /*!< Tx control frame */
+ u64 tx_drop; /*!< Tx drops */
+ u64 tx_jabber; /*!< Tx jabber */
+ u64 tx_fcs_error; /*!< Tx FCS errors */
+ u64 tx_fragments; /*!< Tx fragments */
+ u64 rx_bytes; /*!< Rx bytes */
+ u64 rx_packets; /*!< Rx packets */
+ u64 rx_mcast_packets; /*!< Rx multicast packets */
+ u64 rx_bcast_packets; /*!< Rx broadcast packets */
+ u64 rx_control_frames; /*!< Rx control frames */
+ u64 rx_unknown_opcode; /*!< Rx unknown opcode */
+ u64 rx_drop; /*!< Rx drops */
+ u64 rx_jabber; /*!< Rx jabber */
+ u64 rx_fcs_error; /*!< Rx FCS errors */
+ u64 rx_alignment_error; /*!< Rx alignment errors */
+ u64 rx_frame_length_error; /*!< Rx frame len errors */
+ u64 rx_code_error; /*!< Rx code errors */
+ u64 rx_fragments; /*!< Rx fragments */
+ u64 rx_pause; /*!< Rx pause */
+ u64 rx_zero_pause; /*!< Rx zero pause */
+ u64 tx_pause; /*!< Tx pause */
+ u64 tx_zero_pause; /*!< Tx zero pause */
+ u64 rx_fcoe_pause; /*!< Rx FCoE pause */
+ 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 */
+};
+
+/**
+ * @brief
+ * Port statistics.
+ */
+union bfa_port_stats_u {
+ struct bfa_port_fc_stats fc;
+ struct bfa_port_eth_stats eth;
+};
+
+#pragma pack(1)
+
+#define BFA_CEE_LLDP_MAX_STRING_LEN (128)
+#define BFA_CEE_DCBX_MAX_PRIORITY (8)
+#define BFA_CEE_DCBX_MAX_PGID (8)
+
+#define BFA_CEE_LLDP_SYS_CAP_OTHER 0x0001
+#define BFA_CEE_LLDP_SYS_CAP_REPEATER 0x0002
+#define BFA_CEE_LLDP_SYS_CAP_MAC_BRIDGE 0x0004
+#define BFA_CEE_LLDP_SYS_CAP_WLAN_AP 0x0008
+#define BFA_CEE_LLDP_SYS_CAP_ROUTER 0x0010
+#define BFA_CEE_LLDP_SYS_CAP_TELEPHONE 0x0020
+#define BFA_CEE_LLDP_SYS_CAP_DOCSIS_CD 0x0040
+#define BFA_CEE_LLDP_SYS_CAP_STATION 0x0080
+#define BFA_CEE_LLDP_SYS_CAP_CVLAN 0x0100
+#define BFA_CEE_LLDP_SYS_CAP_SVLAN 0x0200
+#define BFA_CEE_LLDP_SYS_CAP_TPMR 0x0400
+
+/* LLDP string type */
+struct bfa_cee_lldp_str {
+ u8 sub_type;
+ u8 len;
+ u8 rsvd[2];
+ u8 value[BFA_CEE_LLDP_MAX_STRING_LEN];
+};
+
+/* LLDP paramters */
+struct bfa_cee_lldp_cfg {
+ struct bfa_cee_lldp_str chassis_id;
+ struct bfa_cee_lldp_str port_id;
+ struct bfa_cee_lldp_str port_desc;
+ struct bfa_cee_lldp_str sys_name;
+ struct bfa_cee_lldp_str sys_desc;
+ struct bfa_cee_lldp_str mgmt_addr;
+ u16 time_to_live;
+ u16 enabled_system_cap;
+};
+
+enum bfa_cee_dcbx_version {
+ DCBX_PROTOCOL_PRECEE = 1,
+ DCBX_PROTOCOL_CEE = 2,
+};
+
+enum bfa_cee_lls {
+ /* LLS is down because the TLV not sent by the peer */
+ CEE_LLS_DOWN_NO_TLV = 0,
+ /* LLS is down as advertised by the peer */
+ CEE_LLS_DOWN = 1,
+ CEE_LLS_UP = 2,
+};
+
+/* CEE/DCBX parameters */
+struct bfa_cee_dcbx_cfg {
+ u8 pgid[BFA_CEE_DCBX_MAX_PRIORITY];
+ u8 pg_percentage[BFA_CEE_DCBX_MAX_PGID];
+ u8 pfc_primap; /* bitmap of priorties with PFC enabled */
+ u8 fcoe_primap; /* bitmap of priorities used for FcoE traffic */
+ u8 iscsi_primap; /* bitmap of priorities used for iSCSI traffic */
+ u8 dcbx_version; /* operating version:CEE or preCEE */
+ u8 lls_fcoe; /* FCoE Logical Link Status */
+ u8 lls_lan; /* LAN Logical Link Status */
+ u8 rsvd[2];
+};
+
+/* CEE status */
+/* Making this to tri-state for the benefit of port list command */
+enum bfa_cee_status {
+ CEE_UP = 0,
+ CEE_PHY_UP = 1,
+ CEE_LOOPBACK = 2,
+ CEE_PHY_DOWN = 3,
+};
+
+/* CEE Query */
+struct bfa_cee_attr {
+ u8 cee_status;
+ u8 error_reason;
+ struct bfa_cee_lldp_cfg lldp_remote;
+ struct bfa_cee_dcbx_cfg dcbx_remote;
+ mac_t src_mac;
+ u8 link_speed;
+ u8 nw_priority;
+ u8 filler[2];
+};
+
+/* LLDP/DCBX/CEE Statistics */
+struct bfa_cee_stats {
+ u32 lldp_tx_frames; /*!< LLDP Tx Frames */
+ u32 lldp_rx_frames; /*!< LLDP Rx Frames */
+ u32 lldp_rx_frames_invalid; /*!< LLDP Rx Frames invalid */
+ u32 lldp_rx_frames_new; /*!< LLDP Rx Frames new */
+ u32 lldp_tlvs_unrecognized; /*!< LLDP Rx unrecognized TLVs */
+ u32 lldp_rx_shutdown_tlvs; /*!< LLDP Rx shutdown TLVs */
+ u32 lldp_info_aged_out; /*!< LLDP remote info aged out */
+ u32 dcbx_phylink_ups; /*!< DCBX phy link ups */
+ u32 dcbx_phylink_downs; /*!< DCBX phy link downs */
+ u32 dcbx_rx_tlvs; /*!< DCBX Rx TLVs */
+ u32 dcbx_rx_tlvs_invalid; /*!< DCBX Rx TLVs invalid */
+ u32 dcbx_control_tlv_error; /*!< DCBX control TLV errors */
+ u32 dcbx_feature_tlv_error; /*!< DCBX feature TLV errors */
+ u32 dcbx_cee_cfg_new; /*!< DCBX new CEE cfg rcvd */
+ u32 cee_status_down; /*!< CEE status down */
+ u32 cee_status_up; /*!< CEE status up */
+ u32 cee_hw_cfg_changed; /*!< CEE hw cfg changed */
+ u32 cee_rx_invalid_cfg; /*!< CEE invalid cfg */
+};
+
+#pragma pack()
+
+#endif /* __BFA_DEFS_CNA_H__ */
diff --git a/drivers/net/bna/bfa_defs_mfg_comm.h b/drivers/net/bna/bfa_defs_mfg_comm.h
new file mode 100644
index 000000000000..987978fcb3fe
--- /dev/null
+++ b/drivers/net/bna/bfa_defs_mfg_comm.h
@@ -0,0 +1,244 @@
+/*
+ * 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 __BFA_DEFS_MFG_COMM_H__
+#define __BFA_DEFS_MFG_COMM_H__
+
+#include "cna.h"
+
+/**
+ * Manufacturing block version
+ */
+#define BFA_MFG_VERSION 2
+#define BFA_MFG_VERSION_UNINIT 0xFF
+
+/**
+ * Manufacturing block encrypted version
+ */
+#define BFA_MFG_ENC_VER 2
+
+/**
+ * Manufacturing block version 1 length
+ */
+#define BFA_MFG_VER1_LEN 128
+
+/**
+ * Manufacturing block header length
+ */
+#define BFA_MFG_HDR_LEN 4
+
+#define BFA_MFG_SERIALNUM_SIZE 11
+#define STRSZ(_n) (((_n) + 4) & ~3)
+
+/**
+ * Manufacturing card type
+ */
+enum {
+ BFA_MFG_TYPE_CB_MAX = 825, /*!< Crossbow card type max */
+ BFA_MFG_TYPE_FC8P2 = 825, /*!< 8G 2port FC card */
+ BFA_MFG_TYPE_FC8P1 = 815, /*!< 8G 1port FC card */
+ BFA_MFG_TYPE_FC4P2 = 425, /*!< 4G 2port FC card */
+ BFA_MFG_TYPE_FC4P1 = 415, /*!< 4G 1port FC card */
+ BFA_MFG_TYPE_CNA10P2 = 1020, /*!< 10G 2port CNA card */
+ BFA_MFG_TYPE_CNA10P1 = 1010, /*!< 10G 1port CNA card */
+ BFA_MFG_TYPE_JAYHAWK = 804, /*!< Jayhawk mezz card */
+ BFA_MFG_TYPE_WANCHESE = 1007, /*!< Wanchese mezz card */
+ 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_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) (( \
+ (type) == BFA_MFG_TYPE_JAYHAWK || \
+ (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)))
+
+/**
+ * Check if the card having old wwn/mac handling
+ */
+#define bfa_mfg_is_old_wwn_mac_model(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 || \
+ (type) == BFA_MFG_TYPE_JAYHAWK || \
+ (type) == BFA_MFG_TYPE_WANCHESE))
+
+#define bfa_mfg_increment_wwn_mac(m, i) \
+do { \
+ u32 t = ((m)[0] << 16) | ((m)[1] << 8) | (m)[2]; \
+ t += (i); \
+ (m)[0] = (t >> 16) & 0xFF; \
+ (m)[1] = (t >> 8) & 0xFF; \
+ (m)[2] = t & 0xFF; \
+} while (0)
+
+#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)
+
+enum {
+ CB_GPIO_TTV = (1), /*!< TTV debug capable cards */
+ CB_GPIO_FC8P2 = (2), /*!< 8G 2port FC card */
+ CB_GPIO_FC8P1 = (3), /*!< 8G 1port FC card */
+ CB_GPIO_FC4P2 = (4), /*!< 4G 2port FC card */
+ CB_GPIO_FC4P1 = (5), /*!< 4G 1port FC card */
+ CB_GPIO_DFLY = (6), /*!< 8G 2port FC mezzanine card */
+ CB_GPIO_PROTO = (1 << 7) /*!< 8G 2port FC prototypes */
+};
+
+#define bfa_mfg_adapter_prop_init_gpio(gpio, card_type, prop) \
+do { \
+ if ((gpio) & CB_GPIO_PROTO) { \
+ (prop) |= BFI_ADAPTER_PROTO; \
+ (gpio) &= ~CB_GPIO_PROTO; \
+ } \
+ switch ((gpio)) { \
+ case CB_GPIO_TTV: \
+ (prop) |= BFI_ADAPTER_TTV; \
+ case CB_GPIO_DFLY: \
+ case CB_GPIO_FC8P2: \
+ (prop) |= BFI_ADAPTER_SETP(NPORTS, 2); \
+ (prop) |= BFI_ADAPTER_SETP(SPEED, 8); \
+ (card_type) = BFA_MFG_TYPE_FC8P2; \
+ break; \
+ case CB_GPIO_FC8P1: \
+ (prop) |= BFI_ADAPTER_SETP(NPORTS, 1); \
+ (prop) |= BFI_ADAPTER_SETP(SPEED, 8); \
+ (card_type) = BFA_MFG_TYPE_FC8P1; \
+ break; \
+ case CB_GPIO_FC4P2: \
+ (prop) |= BFI_ADAPTER_SETP(NPORTS, 2); \
+ (prop) |= BFI_ADAPTER_SETP(SPEED, 4); \
+ (card_type) = BFA_MFG_TYPE_FC4P2; \
+ break; \
+ case CB_GPIO_FC4P1: \
+ (prop) |= BFI_ADAPTER_SETP(NPORTS, 1); \
+ (prop) |= BFI_ADAPTER_SETP(SPEED, 4); \
+ (card_type) = BFA_MFG_TYPE_FC4P1; \
+ break; \
+ default: \
+ (prop) |= BFI_ADAPTER_UNSUPP; \
+ (card_type) = BFA_MFG_TYPE_INVALID; \
+ } \
+} while (0)
+
+/**
+ * VPD data length
+ */
+#define BFA_MFG_VPD_LEN 512
+#define BFA_MFG_VPD_LEN_INVALID 0
+
+#define BFA_MFG_VPD_PCI_HDR_OFF 137
+#define BFA_MFG_VPD_PCI_VER_MASK 0x07 /*!< version mask 3 bits */
+#define BFA_MFG_VPD_PCI_VDR_MASK 0xf8 /*!< vendor mask 5 bits */
+
+/**
+ * VPD vendor tag
+ */
+enum {
+ BFA_MFG_VPD_UNKNOWN = 0, /*!< vendor unknown */
+ BFA_MFG_VPD_IBM = 1, /*!< vendor IBM */
+ BFA_MFG_VPD_HP = 2, /*!< vendor HP */
+ BFA_MFG_VPD_DELL = 3, /*!< vendor DELL */
+ BFA_MFG_VPD_PCI_IBM = 0x08, /*!< PCI VPD IBM */
+ BFA_MFG_VPD_PCI_HP = 0x10, /*!< PCI VPD HP */
+ BFA_MFG_VPD_PCI_DELL = 0x20, /*!< PCI VPD DELL */
+ BFA_MFG_VPD_PCI_BRCD = 0xf8, /*!< PCI VPD Brocade */
+};
+
+/**
+ * @brief BFA adapter flash vpd data definition.
+ *
+ * All numerical fields are in big-endian format.
+ */
+struct bfa_mfg_vpd {
+ u8 version; /*!< vpd data version */
+ u8 vpd_sig[3]; /*!< characters 'V', 'P', 'D' */
+ u8 chksum; /*!< u8 checksum */
+ u8 vendor; /*!< vendor */
+ u8 len; /*!< vpd data length excluding header */
+ u8 rsv;
+ u8 data[BFA_MFG_VPD_LEN]; /*!< vpd data */
+};
+
+#pragma pack()
+
+#endif /* __BFA_DEFS_MFG_H__ */
diff --git a/drivers/net/bna/bfa_defs_status.h b/drivers/net/bna/bfa_defs_status.h
new file mode 100644
index 000000000000..af951126375c
--- /dev/null
+++ b/drivers/net/bna/bfa_defs_status.h
@@ -0,0 +1,216 @@
+/*
+ * 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 __BFA_DEFS_STATUS_H__
+#define __BFA_DEFS_STATUS_H__
+
+/**
+ * API status return values
+ *
+ * NOTE: The error msgs are auto generated from the comments. Only singe line
+ * comments are supported
+ */
+enum bfa_status {
+ BFA_STATUS_OK = 0,
+ BFA_STATUS_FAILED = 1,
+ BFA_STATUS_EINVAL = 2,
+ BFA_STATUS_ENOMEM = 3,
+ BFA_STATUS_ENOSYS = 4,
+ BFA_STATUS_ETIMER = 5,
+ BFA_STATUS_EPROTOCOL = 6,
+ BFA_STATUS_ENOFCPORTS = 7,
+ BFA_STATUS_NOFLASH = 8,
+ BFA_STATUS_BADFLASH = 9,
+ BFA_STATUS_SFP_UNSUPP = 10,
+ BFA_STATUS_UNKNOWN_VFID = 11,
+ BFA_STATUS_DATACORRUPTED = 12,
+ BFA_STATUS_DEVBUSY = 13,
+ BFA_STATUS_ABORTED = 14,
+ BFA_STATUS_NODEV = 15,
+ BFA_STATUS_HDMA_FAILED = 16,
+ BFA_STATUS_FLASH_BAD_LEN = 17,
+ BFA_STATUS_UNKNOWN_LWWN = 18,
+ BFA_STATUS_UNKNOWN_RWWN = 19,
+ BFA_STATUS_FCPT_LS_RJT = 20,
+ BFA_STATUS_VPORT_EXISTS = 21,
+ BFA_STATUS_VPORT_MAX = 22,
+ BFA_STATUS_UNSUPP_SPEED = 23,
+ BFA_STATUS_INVLD_DFSZ = 24,
+ BFA_STATUS_CNFG_FAILED = 25,
+ BFA_STATUS_CMD_NOTSUPP = 26,
+ BFA_STATUS_NO_ADAPTER = 27,
+ BFA_STATUS_LINKDOWN = 28,
+ BFA_STATUS_FABRIC_RJT = 29,
+ BFA_STATUS_UNKNOWN_VWWN = 30,
+ BFA_STATUS_NSLOGIN_FAILED = 31,
+ BFA_STATUS_NO_RPORTS = 32,
+ BFA_STATUS_NSQUERY_FAILED = 33,
+ BFA_STATUS_PORT_OFFLINE = 34,
+ BFA_STATUS_RPORT_OFFLINE = 35,
+ BFA_STATUS_TGTOPEN_FAILED = 36,
+ BFA_STATUS_BAD_LUNS = 37,
+ BFA_STATUS_IO_FAILURE = 38,
+ BFA_STATUS_NO_FABRIC = 39,
+ BFA_STATUS_EBADF = 40,
+ BFA_STATUS_EINTR = 41,
+ BFA_STATUS_EIO = 42,
+ BFA_STATUS_ENOTTY = 43,
+ BFA_STATUS_ENXIO = 44,
+ BFA_STATUS_EFOPEN = 45,
+ BFA_STATUS_VPORT_WWN_BP = 46,
+ BFA_STATUS_PORT_NOT_DISABLED = 47,
+ BFA_STATUS_BADFRMHDR = 48,
+ BFA_STATUS_BADFRMSZ = 49,
+ BFA_STATUS_MISSINGFRM = 50,
+ BFA_STATUS_LINKTIMEOUT = 51,
+ BFA_STATUS_NO_FCPIM_NEXUS = 52,
+ BFA_STATUS_CHECKSUM_FAIL = 53,
+ BFA_STATUS_GZME_FAILED = 54,
+ BFA_STATUS_SCSISTART_REQD = 55,
+ BFA_STATUS_IOC_FAILURE = 56,
+ BFA_STATUS_INVALID_WWN = 57,
+ BFA_STATUS_MISMATCH = 58,
+ BFA_STATUS_IOC_ENABLED = 59,
+ BFA_STATUS_ADAPTER_ENABLED = 60,
+ BFA_STATUS_IOC_NON_OP = 61,
+ BFA_STATUS_ADDR_MAP_FAILURE = 62,
+ BFA_STATUS_SAME_NAME = 63,
+ BFA_STATUS_PENDING = 64,
+ BFA_STATUS_8G_SPD = 65,
+ BFA_STATUS_4G_SPD = 66,
+ BFA_STATUS_AD_IS_ENABLE = 67,
+ BFA_STATUS_EINVAL_TOV = 68,
+ BFA_STATUS_EINVAL_QDEPTH = 69,
+ BFA_STATUS_VERSION_FAIL = 70,
+ BFA_STATUS_DIAG_BUSY = 71,
+ BFA_STATUS_BEACON_ON = 72,
+ BFA_STATUS_BEACON_OFF = 73,
+ BFA_STATUS_LBEACON_ON = 74,
+ BFA_STATUS_LBEACON_OFF = 75,
+ BFA_STATUS_PORT_NOT_INITED = 76,
+ BFA_STATUS_RPSC_ENABLED = 77,
+ BFA_STATUS_ENOFSAVE = 78,
+ BFA_STATUS_BAD_FILE = 79,
+ BFA_STATUS_RLIM_EN = 80,
+ BFA_STATUS_RLIM_DIS = 81,
+ BFA_STATUS_IOC_DISABLED = 82,
+ BFA_STATUS_ADAPTER_DISABLED = 83,
+ BFA_STATUS_BIOS_DISABLED = 84,
+ BFA_STATUS_AUTH_ENABLED = 85,
+ BFA_STATUS_AUTH_DISABLED = 86,
+ BFA_STATUS_ERROR_TRL_ENABLED = 87,
+ BFA_STATUS_ERROR_QOS_ENABLED = 88,
+ BFA_STATUS_NO_SFP_DEV = 89,
+ BFA_STATUS_MEMTEST_FAILED = 90,
+ BFA_STATUS_INVALID_DEVID = 91,
+ BFA_STATUS_QOS_ENABLED = 92,
+ BFA_STATUS_QOS_DISABLED = 93,
+ BFA_STATUS_INCORRECT_DRV_CONFIG = 94,
+ BFA_STATUS_REG_FAIL = 95,
+ BFA_STATUS_IM_INV_CODE = 96,
+ BFA_STATUS_IM_INV_VLAN = 97,
+ BFA_STATUS_IM_INV_ADAPT_NAME = 98,
+ BFA_STATUS_IM_LOW_RESOURCES = 99,
+ BFA_STATUS_IM_VLANID_IS_PVID = 100,
+ BFA_STATUS_IM_VLANID_EXISTS = 101,
+ BFA_STATUS_IM_FW_UPDATE_FAIL = 102,
+ BFA_STATUS_PORTLOG_ENABLED = 103,
+ BFA_STATUS_PORTLOG_DISABLED = 104,
+ BFA_STATUS_FILE_NOT_FOUND = 105,
+ BFA_STATUS_QOS_FC_ONLY = 106,
+ BFA_STATUS_RLIM_FC_ONLY = 107,
+ BFA_STATUS_CT_SPD = 108,
+ BFA_STATUS_LEDTEST_OP = 109,
+ BFA_STATUS_CEE_NOT_DN = 110,
+ BFA_STATUS_10G_SPD = 111,
+ BFA_STATUS_IM_INV_TEAM_NAME = 112,
+ BFA_STATUS_IM_DUP_TEAM_NAME = 113,
+ BFA_STATUS_IM_ADAPT_ALREADY_IN_TEAM = 114,
+ BFA_STATUS_IM_ADAPT_HAS_VLANS = 115,
+ BFA_STATUS_IM_PVID_MISMATCH = 116,
+ BFA_STATUS_IM_LINK_SPEED_MISMATCH = 117,
+ BFA_STATUS_IM_MTU_MISMATCH = 118,
+ BFA_STATUS_IM_RSS_MISMATCH = 119,
+ BFA_STATUS_IM_HDS_MISMATCH = 120,
+ BFA_STATUS_IM_OFFLOAD_MISMATCH = 121,
+ BFA_STATUS_IM_PORT_PARAMS = 122,
+ BFA_STATUS_IM_PORT_NOT_IN_TEAM = 123,
+ BFA_STATUS_IM_CANNOT_REM_PRI = 124,
+ BFA_STATUS_IM_MAX_PORTS_REACHED = 125,
+ BFA_STATUS_IM_LAST_PORT_DELETE = 126,
+ BFA_STATUS_IM_NO_DRIVER = 127,
+ BFA_STATUS_IM_MAX_VLANS_REACHED = 128,
+ BFA_STATUS_TOMCAT_SPD_NOT_ALLOWED = 129,
+ BFA_STATUS_NO_MINPORT_DRIVER = 130,
+ BFA_STATUS_CARD_TYPE_MISMATCH = 131,
+ BFA_STATUS_BAD_ASICBLK = 132,
+ BFA_STATUS_NO_DRIVER = 133,
+ BFA_STATUS_INVALID_MAC = 134,
+ BFA_STATUS_IM_NO_VLAN = 135,
+ BFA_STATUS_IM_ETH_LB_FAILED = 136,
+ BFA_STATUS_IM_PVID_REMOVE = 137,
+ BFA_STATUS_IM_PVID_EDIT = 138,
+ BFA_STATUS_CNA_NO_BOOT = 139,
+ BFA_STATUS_IM_PVID_NON_ZERO = 140,
+ BFA_STATUS_IM_INETCFG_LOCK_FAILED = 141,
+ BFA_STATUS_IM_GET_INETCFG_FAILED = 142,
+ BFA_STATUS_IM_NOT_BOUND = 143,
+ BFA_STATUS_INSUFFICIENT_PERMS = 144,
+ BFA_STATUS_IM_INV_VLAN_NAME = 145,
+ BFA_STATUS_CMD_NOTSUPP_CNA = 146,
+ BFA_STATUS_IM_PASSTHRU_EDIT = 147,
+ BFA_STATUS_IM_BIND_FAILED = 148,
+ BFA_STATUS_IM_UNBIND_FAILED = 149,
+ BFA_STATUS_IM_PORT_IN_TEAM = 150,
+ BFA_STATUS_IM_VLAN_NOT_FOUND = 151,
+ BFA_STATUS_IM_TEAM_NOT_FOUND = 152,
+ BFA_STATUS_IM_TEAM_CFG_NOT_ALLOWED = 153,
+ BFA_STATUS_PBC = 154,
+ BFA_STATUS_DEVID_MISSING = 155,
+ BFA_STATUS_BAD_FWCFG = 156,
+ BFA_STATUS_CREATE_FILE = 157,
+ BFA_STATUS_INVALID_VENDOR = 158,
+ BFA_STATUS_SFP_NOT_READY = 159,
+ BFA_STATUS_FLASH_UNINIT = 160,
+ BFA_STATUS_FLASH_EMPTY = 161,
+ BFA_STATUS_FLASH_CKFAIL = 162,
+ BFA_STATUS_TRUNK_UNSUPP = 163,
+ BFA_STATUS_TRUNK_ENABLED = 164,
+ BFA_STATUS_TRUNK_DISABLED = 165,
+ BFA_STATUS_TRUNK_ERROR_TRL_ENABLED = 166,
+ BFA_STATUS_BOOT_CODE_UPDATED = 167,
+ BFA_STATUS_BOOT_VERSION = 168,
+ BFA_STATUS_CARDTYPE_MISSING = 169,
+ BFA_STATUS_INVALID_CARDTYPE = 170,
+ BFA_STATUS_NO_TOPOLOGY_FOR_CNA = 171,
+ BFA_STATUS_IM_VLAN_OVER_TEAM_DELETE_FAILED = 172,
+ BFA_STATUS_ETHBOOT_ENABLED = 173,
+ BFA_STATUS_ETHBOOT_DISABLED = 174,
+ BFA_STATUS_IOPROFILE_OFF = 175,
+ BFA_STATUS_NO_PORT_INSTANCE = 176,
+ BFA_STATUS_BOOT_CODE_TIMEDOUT = 177,
+ BFA_STATUS_NO_VPORT_LOCK = 178,
+ BFA_STATUS_VPORT_NO_CNFG = 179,
+ BFA_STATUS_MAX_VAL
+};
+
+enum bfa_eproto_status {
+ BFA_EPROTO_BAD_ACCEPT = 0,
+ BFA_EPROTO_UNKNOWN_RSP = 1
+};
+
+#endif /* __BFA_DEFS_STATUS_H__ */
diff --git a/drivers/net/bna/bfa_ioc.c b/drivers/net/bna/bfa_ioc.c
new file mode 100644
index 000000000000..e94e5aa97515
--- /dev/null
+++ b/drivers/net/bna/bfa_ioc.c
@@ -0,0 +1,1732 @@
+/*
+ * 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"
+
+/**
+ * IOC local definitions
+ */
+
+#define bfa_ioc_timer_start(__ioc) \
+ mod_timer(&(__ioc)->ioc_timer, jiffies + \
+ msecs_to_jiffies(BFA_IOC_TOV))
+#define bfa_ioc_timer_stop(__ioc) del_timer(&(__ioc)->ioc_timer)
+
+#define bfa_ioc_recovery_timer_start(__ioc) \
+ mod_timer(&(__ioc)->ioc_timer, jiffies + \
+ msecs_to_jiffies(BFA_IOC_TOV_RECOVER))
+
+#define bfa_sem_timer_start(__ioc) \
+ mod_timer(&(__ioc)->sem_timer, jiffies + \
+ msecs_to_jiffies(BFA_IOC_HWSEM_TOV))
+#define bfa_sem_timer_stop(__ioc) del_timer(&(__ioc)->sem_timer)
+
+#define bfa_hb_timer_start(__ioc) \
+ mod_timer(&(__ioc)->hb_timer, jiffies + \
+ msecs_to_jiffies(BFA_IOC_HB_TOV))
+#define bfa_hb_timer_stop(__ioc) del_timer(&(__ioc)->hb_timer)
+
+/**
+ * Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details.
+ */
+
+#define bfa_ioc_firmware_lock(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_firmware_lock(__ioc))
+#define bfa_ioc_firmware_unlock(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_firmware_unlock(__ioc))
+#define bfa_ioc_reg_init(__ioc) ((__ioc)->ioc_hwif->ioc_reg_init(__ioc))
+#define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc))
+#define bfa_ioc_notify_hbfail(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_notify_hbfail(__ioc))
+
+#define bfa_ioc_is_optrom(__ioc) \
+ (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(__ioc)) < BFA_IOC_FWIMG_MINSZ)
+
+#define bfa_ioc_mbox_cmd_pending(__ioc) \
+ (!list_empty(&((__ioc)->mbox_mod.cmd_q)) || \
+ readl((__ioc)->ioc_regs.hfn_mbox_cmd))
+
+static bool bfa_nw_auto_recover = true;
+
+/*
+ * forward declarations
+ */
+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_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);
+static void bfa_ioc_hb_monitor(struct bfa_ioc *ioc);
+static void bfa_ioc_hb_stop(struct bfa_ioc *ioc);
+static void bfa_ioc_reset(struct bfa_ioc *ioc, bool force);
+static void bfa_ioc_mbox_poll(struct bfa_ioc *ioc);
+static void bfa_ioc_mbox_hbfail(struct bfa_ioc *ioc);
+static void bfa_ioc_recover(struct bfa_ioc *ioc);
+static void bfa_ioc_check_attr_wwns(struct bfa_ioc *ioc);
+static void bfa_ioc_disable_comp(struct bfa_ioc *ioc);
+static void bfa_ioc_lpu_stop(struct bfa_ioc *ioc);
+static void bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type,
+ u32 boot_param);
+static u32 bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr);
+static u32 bfa_ioc_smem_pgoff(struct bfa_ioc *ioc, u32 fmaddr);
+static void bfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc,
+ char *serial_num);
+static void bfa_ioc_get_adapter_fw_ver(struct bfa_ioc *ioc,
+ char *fw_ver);
+static void bfa_ioc_get_pci_chip_rev(struct bfa_ioc *ioc,
+ char *chip_rev);
+static void bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc *ioc,
+ char *optrom_ver);
+static void bfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc,
+ char *manufacturer);
+static void bfa_ioc_get_adapter_model(struct bfa_ioc *ioc, char *model);
+static u64 bfa_ioc_get_pwwn(struct bfa_ioc *ioc);
+static mac_t bfa_ioc_get_mfg_mac(struct bfa_ioc *ioc);
+
+/**
+ * IOC state machine events
+ */
+enum ioc_event {
+ IOC_E_ENABLE = 1, /*!< IOC enable request */
+ IOC_E_DISABLE = 2, /*!< IOC disable request */
+ IOC_E_TIMEOUT = 3, /*!< f/w response timeout */
+ IOC_E_FWREADY = 4, /*!< f/w initialization done */
+ IOC_E_FWRSP_GETATTR = 5, /*!< IOC get attribute response */
+ IOC_E_FWRSP_ENABLE = 6, /*!< enable f/w response */
+ IOC_E_FWRSP_DISABLE = 7, /*!< disable f/w response */
+ IOC_E_HBFAIL = 8, /*!< heartbeat failure */
+ IOC_E_HWERROR = 9, /*!< hardware error interrupt */
+ IOC_E_SEMLOCKED = 10, /*!< h/w semaphore is locked */
+ IOC_E_DETACH = 11, /*!< driver detach cleanup */
+};
+
+bfa_fsm_state_decl(bfa_ioc, reset, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, fwcheck, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, mismatch, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, semwait, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, hwinit, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, getattr, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, op, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, initfail, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, hbfail, 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);
+
+static struct bfa_sm_table ioc_sm_table[] = {
+ {BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET},
+ {BFA_SM(bfa_ioc_sm_fwcheck), BFA_IOC_FWMISMATCH},
+ {BFA_SM(bfa_ioc_sm_mismatch), BFA_IOC_FWMISMATCH},
+ {BFA_SM(bfa_ioc_sm_semwait), BFA_IOC_SEMWAIT},
+ {BFA_SM(bfa_ioc_sm_hwinit), BFA_IOC_HWINIT},
+ {BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_HWINIT},
+ {BFA_SM(bfa_ioc_sm_getattr), BFA_IOC_GETATTR},
+ {BFA_SM(bfa_ioc_sm_op), BFA_IOC_OPERATIONAL},
+ {BFA_SM(bfa_ioc_sm_initfail), BFA_IOC_INITFAIL},
+ {BFA_SM(bfa_ioc_sm_hbfail), BFA_IOC_HBFAIL},
+ {BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING},
+ {BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},
+};
+
+/**
+ * Reset entry actions -- initialize state machine
+ */
+static void
+bfa_ioc_sm_reset_entry(struct bfa_ioc *ioc)
+{
+ ioc->retry_count = 0;
+ ioc->auto_recover = bfa_nw_auto_recover;
+}
+
+/**
+ * Beginning state. IOC is in reset state.
+ */
+static void
+bfa_ioc_sm_reset(struct bfa_ioc *ioc, enum ioc_event event)
+{
+ switch (event) {
+ case IOC_E_ENABLE:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_disable_comp(ioc);
+ break;
+
+ case IOC_E_DETACH:
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * Semaphore should be acquired for version check.
+ */
+static void
+bfa_ioc_sm_fwcheck_entry(struct bfa_ioc *ioc)
+{
+ bfa_ioc_hw_sem_get(ioc);
+}
+
+/**
+ * Awaiting h/w semaphore to continue with version check.
+ */
+static void
+bfa_ioc_sm_fwcheck(struct bfa_ioc *ioc, enum ioc_event event)
+{
+ switch (event) {
+ case IOC_E_SEMLOCKED:
+ if (bfa_ioc_firmware_lock(ioc)) {
+ ioc->retry_count = 0;
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+ } else {
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_mismatch);
+ }
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_disable_comp(ioc);
+ /* fall through */
+
+ case IOC_E_DETACH:
+ bfa_ioc_hw_sem_get_cancel(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ break;
+
+ case IOC_E_FWREADY:
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * Notify enable completion callback and generate mismatch AEN.
+ */
+static void
+bfa_ioc_sm_mismatch_entry(struct bfa_ioc *ioc)
+{
+ /**
+ * Provide enable completion callback and AEN notification only once.
+ */
+ if (ioc->retry_count == 0)
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ ioc->retry_count++;
+ bfa_ioc_timer_start(ioc);
+}
+
+/**
+ * Awaiting firmware version match.
+ */
+static void
+bfa_ioc_sm_mismatch(struct bfa_ioc *ioc, enum ioc_event event)
+{
+ switch (event) {
+ case IOC_E_TIMEOUT:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_disable_comp(ioc);
+ /* fall through */
+
+ case IOC_E_DETACH:
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ break;
+
+ case IOC_E_FWREADY:
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * Request for semaphore.
+ */
+static void
+bfa_ioc_sm_semwait_entry(struct bfa_ioc *ioc)
+{
+ bfa_ioc_hw_sem_get(ioc);
+}
+
+/**
+ * Awaiting semaphore for h/w initialzation.
+ */
+static void
+bfa_ioc_sm_semwait(struct bfa_ioc *ioc, enum ioc_event event)
+{
+ switch (event) {
+ case IOC_E_SEMLOCKED:
+ ioc->retry_count = 0;
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_hw_sem_get_cancel(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+static void
+bfa_ioc_sm_hwinit_entry(struct bfa_ioc *ioc)
+{
+ bfa_ioc_timer_start(ioc);
+ bfa_ioc_reset(ioc, false);
+}
+
+/**
+ * @brief
+ * Hardware is being initialized. Interrupts are enabled.
+ * Holding hardware semaphore lock.
+ */
+static void
+bfa_ioc_sm_hwinit(struct bfa_ioc *ioc, enum ioc_event event)
+{
+ switch (event) {
+ case IOC_E_FWREADY:
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);
+ break;
+
+ case IOC_E_HWERROR:
+ bfa_ioc_timer_stop(ioc);
+ /* fall through */
+
+ case IOC_E_TIMEOUT:
+ ioc->retry_count++;
+ if (ioc->retry_count < BFA_IOC_HWINIT_MAX) {
+ bfa_ioc_timer_start(ioc);
+ bfa_ioc_reset(ioc, true);
+ break;
+ }
+
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+static void
+bfa_ioc_sm_enabling_entry(struct bfa_ioc *ioc)
+{
+ bfa_ioc_timer_start(ioc);
+ bfa_ioc_send_enable(ioc);
+}
+
+/**
+ * Host IOC function is being enabled, awaiting response from firmware.
+ * Semaphore is acquired.
+ */
+static void
+bfa_ioc_sm_enabling(struct bfa_ioc *ioc, enum ioc_event event)
+{
+ switch (event) {
+ case IOC_E_FWRSP_ENABLE:
+ bfa_ioc_timer_stop(ioc);
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
+ break;
+
+ case IOC_E_HWERROR:
+ bfa_ioc_timer_stop(ioc);
+ /* fall through */
+
+ case IOC_E_TIMEOUT:
+ ioc->retry_count++;
+ if (ioc->retry_count < BFA_IOC_HWINIT_MAX) {
+ writel(BFI_IOC_UNINIT,
+ ioc->ioc_regs.ioc_fwstate);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+ break;
+ }
+
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_timer_stop(ioc);
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ case IOC_E_FWREADY:
+ bfa_ioc_send_enable(ioc);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+static void
+bfa_ioc_sm_getattr_entry(struct bfa_ioc *ioc)
+{
+ bfa_ioc_timer_start(ioc);
+ bfa_ioc_send_getattr(ioc);
+}
+
+/**
+ * @brief
+ * IOC configuration in progress. Timer is active.
+ */
+static void
+bfa_ioc_sm_getattr(struct bfa_ioc *ioc, enum ioc_event event)
+{
+ switch (event) {
+ case IOC_E_FWRSP_GETATTR:
+ bfa_ioc_timer_stop(ioc);
+ bfa_ioc_check_attr_wwns(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
+ break;
+
+ case IOC_E_HWERROR:
+ bfa_ioc_timer_stop(ioc);
+ /* fall through */
+
+ case IOC_E_TIMEOUT:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+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);
+}
+
+static void
+bfa_ioc_sm_op(struct bfa_ioc *ioc, enum ioc_event event)
+{
+ switch (event) {
+ case IOC_E_ENABLE:
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_hb_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
+ break;
+
+ case IOC_E_HWERROR:
+ case IOC_E_FWREADY:
+ /**
+ * Hard error or IOC recovery by other function.
+ * Treat it same as heartbeat failure.
+ */
+ bfa_ioc_hb_stop(ioc);
+ /* !!! fall through !!! */
+
+ case IOC_E_HBFAIL:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_hbfail);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+static void
+bfa_ioc_sm_disabling_entry(struct bfa_ioc *ioc)
+{
+ bfa_ioc_timer_start(ioc);
+ bfa_ioc_send_disable(ioc);
+}
+
+/**
+ * IOC is being disabled
+ */
+static void
+bfa_ioc_sm_disabling(struct bfa_ioc *ioc, enum ioc_event event)
+{
+ switch (event) {
+ case IOC_E_FWRSP_DISABLE:
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ case IOC_E_HWERROR:
+ bfa_ioc_timer_stop(ioc);
+ /*
+ * !!! fall through !!!
+ */
+
+ case IOC_E_TIMEOUT:
+ writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * IOC disable completion entry.
+ */
+static void
+bfa_ioc_sm_disabled_entry(struct bfa_ioc *ioc)
+{
+ bfa_ioc_disable_comp(ioc);
+}
+
+static void
+bfa_ioc_sm_disabled(struct bfa_ioc *ioc, enum ioc_event event)
+{
+ switch (event) {
+ case IOC_E_ENABLE:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+ break;
+
+ case IOC_E_DISABLE:
+ ioc->cbfn->disable_cbfn(ioc->bfa);
+ break;
+
+ case IOC_E_FWREADY:
+ break;
+
+ case IOC_E_DETACH:
+ bfa_ioc_firmware_unlock(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+static void
+bfa_ioc_sm_initfail_entry(struct bfa_ioc *ioc)
+{
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_ioc_timer_start(ioc);
+}
+
+/**
+ * @brief
+ * Hardware initialization failed.
+ */
+static void
+bfa_ioc_sm_initfail(struct bfa_ioc *ioc, enum ioc_event event)
+{
+ switch (event) {
+ case IOC_E_DISABLE:
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ case IOC_E_DETACH:
+ bfa_ioc_timer_stop(ioc);
+ bfa_ioc_firmware_unlock(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ break;
+
+ case IOC_E_TIMEOUT:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+static void
+bfa_ioc_sm_hbfail_entry(struct bfa_ioc *ioc)
+{
+ struct list_head *qe;
+ struct bfa_ioc_hbfail_notify *notify;
+
+ /**
+ * Mark IOC as failed in hardware and stop firmware.
+ */
+ bfa_ioc_lpu_stop(ioc);
+ writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
+
+ /**
+ * Notify other functions on HB failure.
+ */
+ bfa_ioc_notify_hbfail(ioc);
+
+ /**
+ * Notify driver and common modules registered for notification.
+ */
+ ioc->cbfn->hbfail_cbfn(ioc->bfa);
+ list_for_each(qe, &ioc->hb_notify_q) {
+ notify = (struct bfa_ioc_hbfail_notify *) qe;
+ notify->cbfn(notify->cbarg);
+ }
+
+ /**
+ * Flush any queued up mailbox requests.
+ */
+ bfa_ioc_mbox_hbfail(ioc);
+
+ /**
+ * Trigger auto-recovery after a delay.
+ */
+ if (ioc->auto_recover)
+ mod_timer(&ioc->ioc_timer, jiffies +
+ msecs_to_jiffies(BFA_IOC_TOV_RECOVER));
+}
+
+/**
+ * @brief
+ * IOC heartbeat failure.
+ */
+static void
+bfa_ioc_sm_hbfail(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:
+ if (ioc->auto_recover)
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ case IOC_E_TIMEOUT:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+ break;
+
+ case IOC_E_FWREADY:
+ /**
+ * Recovery is already initiated by other function.
+ */
+ break;
+
+ case IOC_E_HWERROR:
+ /*
+ * HB failure notification, ignore.
+ */
+ break;
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * BFA IOC private functions
+ */
+
+static void
+bfa_ioc_disable_comp(struct bfa_ioc *ioc)
+{
+ struct list_head *qe;
+ struct bfa_ioc_hbfail_notify *notify;
+
+ ioc->cbfn->disable_cbfn(ioc->bfa);
+
+ /**
+ * Notify common modules registered for notification.
+ */
+ list_for_each(qe, &ioc->hb_notify_q) {
+ notify = (struct bfa_ioc_hbfail_notify *) qe;
+ notify->cbfn(notify->cbarg);
+ }
+}
+
+void
+bfa_nw_ioc_sem_timeout(void *ioc_arg)
+{
+ struct bfa_ioc *ioc = (struct bfa_ioc *) ioc_arg;
+
+ bfa_ioc_hw_sem_get(ioc);
+}
+
+bool
+bfa_nw_ioc_sem_get(void __iomem *sem_reg)
+{
+ u32 r32;
+ int cnt = 0;
+#define BFA_SEM_SPINCNT 3000
+
+ r32 = readl(sem_reg);
+
+ while (r32 && (cnt < BFA_SEM_SPINCNT)) {
+ cnt++;
+ udelay(2);
+ r32 = readl(sem_reg);
+ }
+
+ if (r32 == 0)
+ return true;
+
+ BUG_ON(!(cnt < BFA_SEM_SPINCNT));
+ return false;
+}
+
+void
+bfa_nw_ioc_sem_release(void __iomem *sem_reg)
+{
+ writel(1, sem_reg);
+}
+
+static void
+bfa_ioc_hw_sem_get(struct bfa_ioc *ioc)
+{
+ u32 r32;
+
+ /**
+ * First read to the semaphore register will return 0, subsequent reads
+ * will return 1. Semaphore is released by writing 1 to the register
+ */
+ r32 = readl(ioc->ioc_regs.ioc_sem_reg);
+ if (r32 == 0) {
+ bfa_fsm_send_event(ioc, IOC_E_SEMLOCKED);
+ return;
+ }
+
+ mod_timer(&ioc->sem_timer, jiffies +
+ msecs_to_jiffies(BFA_IOC_HWSEM_TOV));
+}
+
+void
+bfa_nw_ioc_hw_sem_release(struct bfa_ioc *ioc)
+{
+ writel(1, ioc->ioc_regs.ioc_sem_reg);
+}
+
+static void
+bfa_ioc_hw_sem_get_cancel(struct bfa_ioc *ioc)
+{
+ del_timer(&ioc->sem_timer);
+}
+
+/**
+ * @brief
+ * Initialize LPU local memory (aka secondary memory / SRAM)
+ */
+static void
+bfa_ioc_lmem_init(struct bfa_ioc *ioc)
+{
+ u32 pss_ctl;
+ int i;
+#define PSS_LMEM_INIT_TIME 10000
+
+ pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
+ pss_ctl &= ~__PSS_LMEM_RESET;
+ pss_ctl |= __PSS_LMEM_INIT_EN;
+
+ /*
+ * i2c workaround 12.5khz clock
+ */
+ pss_ctl |= __PSS_I2C_CLK_DIV(3UL);
+ writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
+
+ /**
+ * wait for memory initialization to be complete
+ */
+ i = 0;
+ do {
+ pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
+ i++;
+ } while (!(pss_ctl & __PSS_LMEM_INIT_DONE) && (i < PSS_LMEM_INIT_TIME));
+
+ /**
+ * If memory initialization is not successful, IOC timeout will catch
+ * such failures.
+ */
+ BUG_ON(!(pss_ctl & __PSS_LMEM_INIT_DONE));
+
+ pss_ctl &= ~(__PSS_LMEM_INIT_DONE | __PSS_LMEM_INIT_EN);
+ writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
+}
+
+static void
+bfa_ioc_lpu_start(struct bfa_ioc *ioc)
+{
+ u32 pss_ctl;
+
+ /**
+ * Take processor out of reset.
+ */
+ pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
+ pss_ctl &= ~__PSS_LPU0_RESET;
+
+ writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
+}
+
+static void
+bfa_ioc_lpu_stop(struct bfa_ioc *ioc)
+{
+ u32 pss_ctl;
+
+ /**
+ * Put processors in reset.
+ */
+ pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
+ pss_ctl |= (__PSS_LPU0_RESET | __PSS_LPU1_RESET);
+
+ writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
+}
+
+/**
+ * Get driver and firmware versions.
+ */
+void
+bfa_nw_ioc_fwver_get(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
+{
+ u32 pgnum, pgoff;
+ u32 loff = 0;
+ int i;
+ u32 *fwsig = (u32 *) fwhdr;
+
+ pgnum = bfa_ioc_smem_pgnum(ioc, loff);
+ pgoff = bfa_ioc_smem_pgoff(ioc, loff);
+ writel(pgnum, ioc->ioc_regs.host_page_num_fn);
+
+ for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr) / sizeof(u32));
+ i++) {
+ fwsig[i] =
+ swab32(readl((loff) + (ioc->ioc_regs.smem_page_start)));
+ loff += sizeof(u32);
+ }
+}
+
+/**
+ * Returns TRUE if same.
+ */
+bool
+bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
+{
+ struct bfi_ioc_image_hdr *drv_fwhdr;
+ int i;
+
+ drv_fwhdr = (struct bfi_ioc_image_hdr *)
+ bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0);
+
+ for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) {
+ if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i])
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Return true if current running version is valid. Firmware signature and
+ * execution context (driver/bios) must match.
+ */
+static bool
+bfa_ioc_fwver_valid(struct bfa_ioc *ioc)
+{
+ struct bfi_ioc_image_hdr fwhdr, *drv_fwhdr;
+
+ /**
+ * If bios/efi boot (flash based) -- return true
+ */
+ if (bfa_ioc_is_optrom(ioc))
+ return true;
+
+ 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);
+
+ if (fwhdr.signature != drv_fwhdr->signature)
+ return false;
+
+ if (fwhdr.exec != drv_fwhdr->exec)
+ return false;
+
+ return bfa_nw_ioc_fwver_cmp(ioc, &fwhdr);
+}
+
+/**
+ * Conditionally flush any pending message from firmware at start.
+ */
+static void
+bfa_ioc_msgflush(struct bfa_ioc *ioc)
+{
+ u32 r32;
+
+ r32 = readl(ioc->ioc_regs.lpu_mbox_cmd);
+ if (r32)
+ writel(1, ioc->ioc_regs.lpu_mbox_cmd);
+}
+
+/**
+ * @img ioc_init_logic.jpg
+ */
+static void
+bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
+{
+ enum bfi_ioc_state ioc_fwstate;
+ bool fwvalid;
+
+ ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
+
+ if (force)
+ ioc_fwstate = BFI_IOC_UNINIT;
+
+ /**
+ * check if firmware is valid
+ */
+ fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ?
+ false : bfa_ioc_fwver_valid(ioc);
+
+ if (!fwvalid) {
+ bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id);
+ return;
+ }
+
+ /**
+ * If hardware initialization is in progress (initialized by other IOC),
+ * just wait for an initialization completion interrupt.
+ */
+ if (ioc_fwstate == BFI_IOC_INITING) {
+ ioc->cbfn->reset_cbfn(ioc->bfa);
+ return;
+ }
+
+ /**
+ * If IOC function is disabled and firmware version is same,
+ * just re-enable IOC.
+ *
+ * If option rom, IOC must not be in operational state. With
+ * convergence, IOC will be in operational state when 2nd driver
+ * is loaded.
+ */
+ if (ioc_fwstate == BFI_IOC_DISABLED ||
+ (!bfa_ioc_is_optrom(ioc) && ioc_fwstate == BFI_IOC_OP)) {
+ /**
+ * When using MSI-X any pending firmware ready event should
+ * be flushed. Otherwise MSI-X interrupts are not delivered.
+ */
+ bfa_ioc_msgflush(ioc);
+ ioc->cbfn->reset_cbfn(ioc->bfa);
+ bfa_fsm_send_event(ioc, IOC_E_FWREADY);
+ return;
+ }
+
+ /**
+ * Initialize the h/w for any other states.
+ */
+ bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id);
+}
+
+void
+bfa_nw_ioc_timeout(void *ioc_arg)
+{
+ struct bfa_ioc *ioc = (struct bfa_ioc *) ioc_arg;
+
+ bfa_fsm_send_event(ioc, IOC_E_TIMEOUT);
+}
+
+static void
+bfa_ioc_mbox_send(struct bfa_ioc *ioc, void *ioc_msg, int len)
+{
+ u32 *msgp = (u32 *) ioc_msg;
+ u32 i;
+
+ BUG_ON(!(len <= BFI_IOC_MSGLEN_MAX));
+
+ /*
+ * first write msg to mailbox registers
+ */
+ for (i = 0; i < len / sizeof(u32); i++)
+ writel(cpu_to_le32(msgp[i]),
+ ioc->ioc_regs.hfn_mbox + i * sizeof(u32));
+
+ for (; i < BFI_IOC_MSGLEN_MAX / sizeof(u32); i++)
+ writel(0, ioc->ioc_regs.hfn_mbox + i * sizeof(u32));
+
+ /*
+ * write 1 to mailbox CMD to trigger LPU event
+ */
+ writel(1, ioc->ioc_regs.hfn_mbox_cmd);
+ (void) readl(ioc->ioc_regs.hfn_mbox_cmd);
+}
+
+static void
+bfa_ioc_send_enable(struct bfa_ioc *ioc)
+{
+ struct bfi_ioc_ctrl_req enable_req;
+ struct timeval tv;
+
+ 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;
+ do_gettimeofday(&tv);
+ enable_req.tv_sec = ntohl(tv.tv_sec);
+ bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req));
+}
+
+static void
+bfa_ioc_send_disable(struct bfa_ioc *ioc)
+{
+ struct bfi_ioc_ctrl_req disable_req;
+
+ bfi_h2i_set(disable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_DISABLE_REQ,
+ bfa_ioc_portid(ioc));
+ bfa_ioc_mbox_send(ioc, &disable_req, sizeof(struct bfi_ioc_ctrl_req));
+}
+
+static void
+bfa_ioc_send_getattr(struct bfa_ioc *ioc)
+{
+ struct bfi_ioc_getattr_req attr_req;
+
+ bfi_h2i_set(attr_req.mh, BFI_MC_IOC, BFI_IOC_H2I_GETATTR_REQ,
+ bfa_ioc_portid(ioc));
+ bfa_dma_be_addr_set(attr_req.attr_addr, ioc->attr_dma.pa);
+ bfa_ioc_mbox_send(ioc, &attr_req, sizeof(attr_req));
+}
+
+void
+bfa_nw_ioc_hb_check(void *cbarg)
+{
+ struct bfa_ioc *ioc = cbarg;
+ u32 hb_count;
+
+ hb_count = readl(ioc->ioc_regs.heartbeat);
+ if (ioc->hb_count == hb_count) {
+ pr_crit("Firmware heartbeat failure at %d", hb_count);
+ bfa_ioc_recover(ioc);
+ return;
+ } else {
+ ioc->hb_count = hb_count;
+ }
+
+ bfa_ioc_mbox_poll(ioc);
+ mod_timer(&ioc->hb_timer, jiffies +
+ msecs_to_jiffies(BFA_IOC_HB_TOV));
+}
+
+static void
+bfa_ioc_hb_monitor(struct bfa_ioc *ioc)
+{
+ ioc->hb_count = readl(ioc->ioc_regs.heartbeat);
+ mod_timer(&ioc->hb_timer, jiffies +
+ msecs_to_jiffies(BFA_IOC_HB_TOV));
+}
+
+static void
+bfa_ioc_hb_stop(struct bfa_ioc *ioc)
+{
+ del_timer(&ioc->hb_timer);
+}
+
+/**
+ * @brief
+ * Initiate a full firmware download.
+ */
+static void
+bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
+ u32 boot_param)
+{
+ u32 *fwimg;
+ u32 pgnum, pgoff;
+ u32 loff = 0;
+ u32 chunkno = 0;
+ u32 i;
+
+ /**
+ * Initialize LMEM first before code download
+ */
+ bfa_ioc_lmem_init(ioc);
+
+ /**
+ * Flash based firmware boot
+ */
+ if (bfa_ioc_is_optrom(ioc))
+ boot_type = BFI_BOOT_TYPE_FLASH;
+ fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno);
+
+ pgnum = bfa_ioc_smem_pgnum(ioc, loff);
+ pgoff = bfa_ioc_smem_pgoff(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++) {
+ 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),
+ BFA_IOC_FLASH_CHUNK_ADDR(chunkno));
+ }
+
+ /**
+ * write smem
+ */
+ writel((swab32(fwimg[BFA_IOC_FLASH_OFFSET_IN_CHUNK(i)])),
+ ((ioc->ioc_regs.smem_page_start) + (loff)));
+
+ loff += sizeof(u32);
+
+ /**
+ * handle page offset wrap around
+ */
+ loff = PSS_SMEM_PGOFF(loff);
+ if (loff == 0) {
+ pgnum++;
+ writel(pgnum,
+ ioc->ioc_regs.host_page_num_fn);
+ }
+ }
+
+ writel(bfa_ioc_smem_pgnum(ioc, 0),
+ ioc->ioc_regs.host_page_num_fn);
+
+ /*
+ * Set boot type and boot param at the end.
+ */
+ writel((swab32(swab32(boot_type))), ((ioc->ioc_regs.smem_page_start)
+ + (BFI_BOOT_TYPE_OFF)));
+ writel((swab32(swab32(boot_param))), ((ioc->ioc_regs.smem_page_start)
+ + (BFI_BOOT_PARAM_OFF)));
+}
+
+static void
+bfa_ioc_reset(struct bfa_ioc *ioc, bool force)
+{
+ bfa_ioc_hwinit(ioc, force);
+}
+
+/**
+ * @brief
+ * Update BFA configuration from firmware configuration.
+ */
+static void
+bfa_ioc_getattr_reply(struct bfa_ioc *ioc)
+{
+ struct bfi_ioc_attr *attr = ioc->attr;
+
+ attr->adapter_prop = ntohl(attr->adapter_prop);
+ attr->card_type = ntohl(attr->card_type);
+ attr->maxfrsize = ntohs(attr->maxfrsize);
+
+ bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR);
+}
+
+/**
+ * Attach time initialization of mbox logic.
+ */
+static void
+bfa_ioc_mbox_attach(struct bfa_ioc *ioc)
+{
+ struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+ int mc;
+
+ INIT_LIST_HEAD(&mod->cmd_q);
+ for (mc = 0; mc < BFI_MC_MAX; mc++) {
+ mod->mbhdlr[mc].cbfn = NULL;
+ mod->mbhdlr[mc].cbarg = ioc->bfa;
+ }
+}
+
+/**
+ * Mbox poll timer -- restarts any pending mailbox requests.
+ */
+static void
+bfa_ioc_mbox_poll(struct bfa_ioc *ioc)
+{
+ struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+ struct bfa_mbox_cmd *cmd;
+ u32 stat;
+
+ /**
+ * If no command pending, do nothing
+ */
+ if (list_empty(&mod->cmd_q))
+ return;
+
+ /**
+ * If previous command is not yet fetched by firmware, do nothing
+ */
+ stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
+ if (stat)
+ return;
+
+ /**
+ * Enqueue command to firmware.
+ */
+ bfa_q_deq(&mod->cmd_q, &cmd);
+ bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
+}
+
+/**
+ * Cleanup any pending requests.
+ */
+static void
+bfa_ioc_mbox_hbfail(struct bfa_ioc *ioc)
+{
+ struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+ struct bfa_mbox_cmd *cmd;
+
+ while (!list_empty(&mod->cmd_q))
+ bfa_q_deq(&mod->cmd_q, &cmd);
+}
+
+/**
+ * IOC public
+ */
+static enum bfa_status
+bfa_ioc_pll_init(struct bfa_ioc *ioc)
+{
+ /*
+ * Hold semaphore so that nobody can access the chip during init.
+ */
+ bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg);
+
+ bfa_ioc_pll_init_asic(ioc);
+
+ ioc->pllinit = true;
+ /*
+ * release semaphore.
+ */
+ bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Interface used by diag module to do firmware boot with memory test
+ * as the entry vector.
+ */
+static void
+bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param)
+{
+ void __iomem *rb;
+
+ bfa_ioc_stats(ioc, ioc_boots);
+
+ if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK)
+ return;
+
+ /**
+ * Initialize IOC state of all functions on a chip reset.
+ */
+ rb = ioc->pcidev.pci_bar_kva;
+ if (boot_param == BFI_BOOT_TYPE_MEMTEST) {
+ writel(BFI_IOC_MEMTEST, (rb + BFA_IOC0_STATE_REG));
+ writel(BFI_IOC_MEMTEST, (rb + BFA_IOC1_STATE_REG));
+ } else {
+ writel(BFI_IOC_INITING, (rb + BFA_IOC0_STATE_REG));
+ writel(BFI_IOC_INITING, (rb + BFA_IOC1_STATE_REG));
+ }
+
+ bfa_ioc_msgflush(ioc);
+ bfa_ioc_download_fw(ioc, boot_type, boot_param);
+
+ /**
+ * Enable interrupts just before starting LPU
+ */
+ ioc->cbfn->reset_cbfn(ioc->bfa);
+ bfa_ioc_lpu_start(ioc);
+}
+
+/**
+ * Enable/disable IOC failure auto recovery.
+ */
+void
+bfa_nw_ioc_auto_recover(bool auto_recover)
+{
+ bfa_nw_auto_recover = auto_recover;
+}
+
+static void
+bfa_ioc_msgget(struct bfa_ioc *ioc, void *mbmsg)
+{
+ u32 *msgp = mbmsg;
+ u32 r32;
+ int i;
+
+ /**
+ * read the MBOX msg
+ */
+ for (i = 0; i < (sizeof(union bfi_ioc_i2h_msg_u) / sizeof(u32));
+ i++) {
+ r32 = readl(ioc->ioc_regs.lpu_mbox +
+ i * sizeof(u32));
+ msgp[i] = htonl(r32);
+ }
+
+ /**
+ * turn off mailbox interrupt by clearing mailbox status
+ */
+ writel(1, ioc->ioc_regs.lpu_mbox_cmd);
+ readl(ioc->ioc_regs.lpu_mbox_cmd);
+}
+
+static void
+bfa_ioc_isr(struct bfa_ioc *ioc, struct bfi_mbmsg *m)
+{
+ union bfi_ioc_i2h_msg_u *msg;
+
+ msg = (union bfi_ioc_i2h_msg_u *) m;
+
+ bfa_ioc_stats(ioc, ioc_isrs);
+
+ switch (msg->mh.msg_id) {
+ case BFI_IOC_I2H_HBEAT:
+ break;
+
+ case BFI_IOC_I2H_READY_EVENT:
+ bfa_fsm_send_event(ioc, IOC_E_FWREADY);
+ break;
+
+ case BFI_IOC_I2H_ENABLE_REPLY:
+ bfa_fsm_send_event(ioc, IOC_E_FWRSP_ENABLE);
+ break;
+
+ case BFI_IOC_I2H_DISABLE_REPLY:
+ bfa_fsm_send_event(ioc, IOC_E_FWRSP_DISABLE);
+ break;
+
+ case BFI_IOC_I2H_GETATTR_REPLY:
+ bfa_ioc_getattr_reply(ioc);
+ break;
+
+ default:
+ BUG_ON(1);
+ }
+}
+
+/**
+ * IOC attach time initialization and setup.
+ *
+ * @param[in] ioc memory for IOC
+ * @param[in] bfa driver instance structure
+ */
+void
+bfa_nw_ioc_attach(struct bfa_ioc *ioc, void *bfa, struct bfa_ioc_cbfn *cbfn)
+{
+ ioc->bfa = bfa;
+ ioc->cbfn = cbfn;
+ ioc->fcmode = false;
+ ioc->pllinit = false;
+ ioc->dbg_fwsave_once = true;
+
+ bfa_ioc_mbox_attach(ioc);
+ INIT_LIST_HEAD(&ioc->hb_notify_q);
+
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+}
+
+/**
+ * Driver detach time IOC cleanup.
+ */
+void
+bfa_nw_ioc_detach(struct bfa_ioc *ioc)
+{
+ bfa_fsm_send_event(ioc, IOC_E_DETACH);
+}
+
+/**
+ * Setup IOC PCI properties.
+ *
+ * @param[in] pcidev PCI device information for this IOC
+ */
+void
+bfa_nw_ioc_pci_init(struct bfa_ioc *ioc, struct bfa_pcidev *pcidev,
+ enum bfi_mclass mc)
+{
+ ioc->ioc_mc = mc;
+ 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);
+
+ bfa_ioc_map_port(ioc);
+ bfa_ioc_reg_init(ioc);
+}
+
+/**
+ * Initialize IOC dma memory
+ *
+ * @param[in] dm_kva kernel virtual address of IOC dma memory
+ * @param[in] dm_pa physical address of IOC dma memory
+ */
+void
+bfa_nw_ioc_mem_claim(struct bfa_ioc *ioc, u8 *dm_kva, u64 dm_pa)
+{
+ /**
+ * dma memory for firmware attribute
+ */
+ ioc->attr_dma.kva = dm_kva;
+ ioc->attr_dma.pa = dm_pa;
+ ioc->attr = (struct bfi_ioc_attr *) dm_kva;
+}
+
+/**
+ * Return size of dma memory required.
+ */
+u32
+bfa_nw_ioc_meminfo(void)
+{
+ return roundup(sizeof(struct bfi_ioc_attr), BFA_DMA_ALIGN_SZ);
+}
+
+void
+bfa_nw_ioc_enable(struct bfa_ioc *ioc)
+{
+ bfa_ioc_stats(ioc, ioc_enables);
+ ioc->dbg_fwsave_once = true;
+
+ bfa_fsm_send_event(ioc, IOC_E_ENABLE);
+}
+
+void
+bfa_nw_ioc_disable(struct bfa_ioc *ioc)
+{
+ bfa_ioc_stats(ioc, ioc_disables);
+ bfa_fsm_send_event(ioc, IOC_E_DISABLE);
+}
+
+static u32
+bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr)
+{
+ return PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, fmaddr);
+}
+
+static u32
+bfa_ioc_smem_pgoff(struct bfa_ioc *ioc, u32 fmaddr)
+{
+ return PSS_SMEM_PGOFF(fmaddr);
+}
+
+/**
+ * Register mailbox message handler function, to be called by common modules
+ */
+void
+bfa_nw_ioc_mbox_regisr(struct bfa_ioc *ioc, enum bfi_mclass mc,
+ bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg)
+{
+ struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+
+ mod->mbhdlr[mc].cbfn = cbfn;
+ mod->mbhdlr[mc].cbarg = cbarg;
+}
+
+/**
+ * Queue a mailbox command request to firmware. Waits if mailbox is busy.
+ * Responsibility of caller to serialize
+ *
+ * @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)
+{
+ struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+ u32 stat;
+
+ /**
+ * If a previous command is pending, queue new command
+ */
+ if (!list_empty(&mod->cmd_q)) {
+ list_add_tail(&cmd->qe, &mod->cmd_q);
+ return;
+ }
+
+ /**
+ * If mailbox is busy, queue command for poll timer
+ */
+ stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
+ if (stat) {
+ list_add_tail(&cmd->qe, &mod->cmd_q);
+ return;
+ }
+
+ /**
+ * mailbox is free -- queue command to firmware
+ */
+ bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
+}
+
+/**
+ * Handle mailbox interrupts
+ */
+void
+bfa_nw_ioc_mbox_isr(struct bfa_ioc *ioc)
+{
+ struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+ struct bfi_mbmsg m;
+ int mc;
+
+ 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;
+ }
+
+ if ((mc >= BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL))
+ return;
+
+ mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m);
+}
+
+void
+bfa_nw_ioc_error_isr(struct bfa_ioc *ioc)
+{
+ bfa_fsm_send_event(ioc, IOC_E_HWERROR);
+}
+
+/**
+ * Add to IOC heartbeat failure notification queue. To be used by common
+ * modules such as cee, port, diag.
+ */
+void
+bfa_nw_ioc_hbfail_register(struct bfa_ioc *ioc,
+ struct bfa_ioc_hbfail_notify *notify)
+{
+ list_add_tail(&notify->qe, &ioc->hb_notify_q);
+}
+
+#define BFA_MFG_NAME "Brocade"
+static void
+bfa_ioc_get_adapter_attr(struct bfa_ioc *ioc,
+ struct bfa_adapter_attr *ad_attr)
+{
+ struct bfi_ioc_attr *ioc_attr;
+
+ ioc_attr = ioc->attr;
+
+ bfa_ioc_get_adapter_serial_num(ioc, ad_attr->serial_num);
+ bfa_ioc_get_adapter_fw_ver(ioc, ad_attr->fw_ver);
+ bfa_ioc_get_adapter_optrom_ver(ioc, ad_attr->optrom_ver);
+ bfa_ioc_get_adapter_manufacturer(ioc, ad_attr->manufacturer);
+ memcpy(&ad_attr->vpd, &ioc_attr->vpd,
+ sizeof(struct bfa_mfg_vpd));
+
+ ad_attr->nports = bfa_ioc_get_nports(ioc);
+ ad_attr->max_speed = bfa_ioc_speed_sup(ioc);
+
+ bfa_ioc_get_adapter_model(ioc, ad_attr->model);
+ /* For now, model descr uses same model string */
+ bfa_ioc_get_adapter_model(ioc, ad_attr->model_descr);
+
+ ad_attr->card_type = ioc_attr->card_type;
+ ad_attr->is_mezz = bfa_mfg_is_mezz(ioc_attr->card_type);
+
+ if (BFI_ADAPTER_IS_SPECIAL(ioc_attr->adapter_prop))
+ ad_attr->prototype = 1;
+ else
+ ad_attr->prototype = 0;
+
+ ad_attr->pwwn = bfa_ioc_get_pwwn(ioc);
+ ad_attr->mac = bfa_nw_ioc_get_mac(ioc);
+
+ ad_attr->pcie_gen = ioc_attr->pcie_gen;
+ ad_attr->pcie_lanes = ioc_attr->pcie_lanes;
+ ad_attr->pcie_lanes_orig = ioc_attr->pcie_lanes_orig;
+ 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));
+ return BFA_IOC_TYPE_LL;
+ }
+}
+
+static void
+bfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc, char *serial_num)
+{
+ memset(serial_num, 0, BFA_ADAPTER_SERIAL_NUM_LEN);
+ memcpy(serial_num,
+ (void *)ioc->attr->brcd_serialnum,
+ BFA_ADAPTER_SERIAL_NUM_LEN);
+}
+
+static void
+bfa_ioc_get_adapter_fw_ver(struct bfa_ioc *ioc, char *fw_ver)
+{
+ memset(fw_ver, 0, BFA_VERSION_LEN);
+ memcpy(fw_ver, ioc->attr->fw_version, BFA_VERSION_LEN);
+}
+
+static void
+bfa_ioc_get_pci_chip_rev(struct bfa_ioc *ioc, char *chip_rev)
+{
+ BUG_ON(!(chip_rev));
+
+ memset(chip_rev, 0, BFA_IOC_CHIP_REV_LEN);
+
+ chip_rev[0] = 'R';
+ chip_rev[1] = 'e';
+ chip_rev[2] = 'v';
+ chip_rev[3] = '-';
+ chip_rev[4] = ioc->attr->asic_rev;
+ chip_rev[5] = '\0';
+}
+
+static void
+bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc *ioc, char *optrom_ver)
+{
+ memset(optrom_ver, 0, BFA_VERSION_LEN);
+ memcpy(optrom_ver, ioc->attr->optrom_version,
+ BFA_VERSION_LEN);
+}
+
+static void
+bfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc, char *manufacturer)
+{
+ memset(manufacturer, 0, BFA_ADAPTER_MFG_NAME_LEN);
+ memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
+}
+
+static void
+bfa_ioc_get_adapter_model(struct bfa_ioc *ioc, char *model)
+{
+ struct bfi_ioc_attr *ioc_attr;
+
+ BUG_ON(!(model));
+ memset(model, 0, BFA_ADAPTER_MODEL_NAME_LEN);
+
+ ioc_attr = ioc->attr;
+
+ /**
+ * model name
+ */
+ snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u",
+ BFA_MFG_NAME, ioc_attr->card_type);
+}
+
+static enum bfa_ioc_state
+bfa_ioc_get_state(struct bfa_ioc *ioc)
+{
+ return bfa_sm_to_state(ioc_sm_table, ioc->fsm);
+}
+
+void
+bfa_nw_ioc_get_attr(struct bfa_ioc *ioc, struct bfa_ioc_attr *ioc_attr)
+{
+ memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr));
+
+ ioc_attr->state = bfa_ioc_get_state(ioc);
+ ioc_attr->port_id = ioc->port_id;
+
+ ioc_attr->ioc_type = bfa_ioc_get_type(ioc);
+
+ bfa_ioc_get_adapter_attr(ioc, &ioc_attr->adapter_attr);
+
+ ioc_attr->pci_attr.device_id = ioc->pcidev.device_id;
+ ioc_attr->pci_attr.pcifn = ioc->pcidev.pci_func;
+ bfa_ioc_get_pci_chip_rev(ioc, ioc_attr->pci_attr.chip_rev);
+}
+
+/**
+ * WWN public
+ */
+static u64
+bfa_ioc_get_pwwn(struct bfa_ioc *ioc)
+{
+ return ioc->attr->pwwn;
+}
+
+mac_t
+bfa_nw_ioc_get_mac(struct bfa_ioc *ioc)
+{
+ /*
+ * Currently mfg mac is used as FCoE enode mac (not configured by PBC)
+ */
+ if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_FCoE)
+ return bfa_ioc_get_mfg_mac(ioc);
+ else
+ return ioc->attr->mac;
+}
+
+static mac_t
+bfa_ioc_get_mfg_mac(struct bfa_ioc *ioc)
+{
+ mac_t m;
+
+ m = ioc->attr->mfg_mac;
+ if (bfa_mfg_is_old_wwn_mac_model(ioc->attr->card_type))
+ m.mac[MAC_ADDRLEN - 1] += bfa_ioc_pcifn(ioc);
+ else
+ bfa_mfg_increment_wwn_mac(&(m.mac[MAC_ADDRLEN-3]),
+ bfa_ioc_pcifn(ioc));
+
+ return m;
+}
+
+/**
+ * Firmware failure detected. Start recovery actions.
+ */
+static void
+bfa_ioc_recover(struct bfa_ioc *ioc)
+{
+ bfa_ioc_stats(ioc, ioc_hbfails);
+ bfa_fsm_send_event(ioc, IOC_E_HBFAIL);
+}
+
+static void
+bfa_ioc_check_attr_wwns(struct bfa_ioc *ioc)
+{
+ if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_LL)
+ return;
+
+}
diff --git a/drivers/net/bna/bfa_ioc.h b/drivers/net/bna/bfa_ioc.h
new file mode 100644
index 000000000000..a73d84ec808c
--- /dev/null
+++ b/drivers/net/bna/bfa_ioc.h
@@ -0,0 +1,300 @@
+/*
+ * 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 __BFA_IOC_H__
+#define __BFA_IOC_H__
+
+#include "bfa_sm.h"
+#include "bfi.h"
+#include "cna.h"
+
+#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 2
+#define BFA_IOC_TOV_RECOVER BFA_IOC_HB_TOV
+
+/**
+ * Generic Scatter Gather Element used by driver
+ */
+struct bfa_sge {
+ u32 sg_len;
+ void *sg_addr;
+};
+
+/**
+ * PCI device information required by IOC
+ */
+struct bfa_pcidev {
+ int pci_slot;
+ u8 pci_func;
+ u16 device_id;
+ void __iomem *pci_bar_kva;
+};
+
+/**
+ * Structure used to remember the DMA-able memory block's KVA and Physical
+ * Address
+ */
+struct bfa_dma {
+ void *kva; /* ! Kernel virtual address */
+ u64 pa; /* ! Physical address */
+};
+
+#define BFA_DMA_ALIGN_SZ 256
+
+/**
+ * smem size for Crossbow and Catapult
+ */
+#define BFI_SMEM_CB_SIZE 0x200000U /* ! 2MB for crossbow */
+#define BFI_SMEM_CT_SIZE 0x280000U /* ! 2.5MB for catapult */
+
+/**
+ * @brief BFA dma address assignment macro
+ */
+#define bfa_dma_addr_set(dma_addr, pa) \
+ __bfa_dma_addr_set(&dma_addr, (u64)pa)
+
+static inline void
+__bfa_dma_addr_set(union bfi_addr_u *dma_addr, u64 pa)
+{
+ dma_addr->a32.addr_lo = (u32) pa;
+ dma_addr->a32.addr_hi = (u32) (upper_32_bits(pa));
+}
+
+/**
+ * @brief BFA dma address assignment macro. (big endian format)
+ */
+#define bfa_dma_be_addr_set(dma_addr, pa) \
+ __bfa_dma_be_addr_set(&dma_addr, (u64)pa)
+static inline void
+__bfa_dma_be_addr_set(union bfi_addr_u *dma_addr, u64 pa)
+{
+ dma_addr->a32.addr_lo = (u32) htonl(pa);
+ dma_addr->a32.addr_hi = (u32) htonl(upper_32_bits(pa));
+}
+
+struct bfa_ioc_regs {
+ void __iomem *hfn_mbox_cmd;
+ void __iomem *hfn_mbox;
+ void __iomem *lpu_mbox_cmd;
+ void __iomem *lpu_mbox;
+ void __iomem *pss_ctl_reg;
+ void __iomem *pss_err_status_reg;
+ void __iomem *app_pll_fast_ctl_reg;
+ void __iomem *app_pll_slow_ctl_reg;
+ void __iomem *ioc_sem_reg;
+ void __iomem *ioc_usage_sem_reg;
+ void __iomem *ioc_init_sem_reg;
+ void __iomem *ioc_usage_reg;
+ void __iomem *host_page_num_fn;
+ void __iomem *heartbeat;
+ void __iomem *ioc_fwstate;
+ void __iomem *ll_halt;
+ void __iomem *err_set;
+ void __iomem *shirq_isr_next;
+ void __iomem *shirq_msk_next;
+ void __iomem *smem_page_start;
+ u32 smem_pg0;
+};
+
+/**
+ * IOC Mailbox structures
+ */
+struct bfa_mbox_cmd {
+ struct list_head qe;
+ u32 msg[BFI_IOC_MSGSZ];
+};
+
+/**
+ * IOC mailbox module
+ */
+typedef void (*bfa_ioc_mbox_mcfunc_t)(void *cbarg, struct bfi_mbmsg *m);
+struct bfa_ioc_mbox_mod {
+ struct list_head cmd_q; /*!< pending mbox queue */
+ int nmclass; /*!< number of handlers */
+ struct {
+ bfa_ioc_mbox_mcfunc_t cbfn; /*!< message handlers */
+ void *cbarg;
+ } mbhdlr[BFI_MC_MAX];
+};
+
+/**
+ * IOC callback function interfaces
+ */
+typedef void (*bfa_ioc_enable_cbfn_t)(void *bfa, enum bfa_status status);
+typedef void (*bfa_ioc_disable_cbfn_t)(void *bfa);
+typedef void (*bfa_ioc_hbfail_cbfn_t)(void *bfa);
+typedef void (*bfa_ioc_reset_cbfn_t)(void *bfa);
+struct bfa_ioc_cbfn {
+ bfa_ioc_enable_cbfn_t enable_cbfn;
+ bfa_ioc_disable_cbfn_t disable_cbfn;
+ bfa_ioc_hbfail_cbfn_t hbfail_cbfn;
+ bfa_ioc_reset_cbfn_t reset_cbfn;
+};
+
+/**
+ * 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
+ */
+#define bfa_ioc_hbfail_init(__notify, __cbfn, __cbarg) do { \
+ (__notify)->cbfn = (__cbfn); \
+ (__notify)->cbarg = (__cbarg); \
+} while (0)
+
+struct bfa_ioc {
+ bfa_fsm_t fsm;
+ struct bfa *bfa;
+ struct bfa_pcidev pcidev;
+ struct bfa_timer_mod *timer_mod;
+ struct timer_list ioc_timer;
+ struct timer_list sem_timer;
+ struct timer_list hb_timer;
+ u32 hb_count;
+ u32 retry_count;
+ struct list_head hb_notify_q;
+ void *dbg_fwsave;
+ int dbg_fwsave_len;
+ bool dbg_fwsave_once;
+ enum bfi_mclass ioc_mc;
+ struct bfa_ioc_regs ioc_regs;
+ struct bfa_ioc_drv_stats stats;
+ bool auto_recover;
+ bool fcmode;
+ bool ctdev;
+ bool cna;
+ bool pllinit;
+ bool stats_busy; /*!< outstanding stats */
+ u8 port_id;
+
+ struct bfa_dma attr_dma;
+ struct bfi_ioc_attr *attr;
+ struct bfa_ioc_cbfn *cbfn;
+ struct bfa_ioc_mbox_mod mbox_mod;
+ struct bfa_ioc_hwif *ioc_hwif;
+};
+
+struct bfa_ioc_hwif {
+ enum bfa_status (*ioc_pll_init) (void __iomem *rb, bool fcmode);
+ bool (*ioc_firmware_lock) (struct bfa_ioc *ioc);
+ void (*ioc_firmware_unlock) (struct bfa_ioc *ioc);
+ void (*ioc_reg_init) (struct bfa_ioc *ioc);
+ void (*ioc_map_port) (struct bfa_ioc *ioc);
+ void (*ioc_isr_mode_set) (struct bfa_ioc *ioc,
+ bool msix);
+ void (*ioc_notify_hbfail) (struct bfa_ioc *ioc);
+ void (*ioc_ownership_reset) (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_fetch_stats(__ioc, __stats) \
+ (((__stats)->drv_stats) = (__ioc)->stats)
+#define bfa_ioc_clr_stats(__ioc) \
+ memset(&(__ioc)->stats, 0, sizeof((__ioc)->stats))
+#define bfa_ioc_maxfrsize(__ioc) ((__ioc)->attr->maxfrsize)
+#define bfa_ioc_rx_bbcredit(__ioc) ((__ioc)->attr->rx_bbcredit)
+#define bfa_ioc_speed_sup(__ioc) \
+ BFI_ADAPTER_GETP(SPEED, (__ioc)->attr->adapter_prop)
+#define bfa_ioc_get_nports(__ioc) \
+ BFI_ADAPTER_GETP(NPORTS, (__ioc)->attr->adapter_prop)
+
+#define bfa_ioc_stats(_ioc, _stats) ((_ioc)->stats._stats++)
+#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)
+#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)
+
+/**
+ * IOC mailbox interface
+ */
+void bfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd);
+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);
+
+/**
+ * IOC interfaces
+ */
+
+#define bfa_ioc_pll_init_asic(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_pll_init((__ioc)->pcidev.pci_bar_kva, \
+ (__ioc)->fcmode))
+
+#define bfa_ioc_isr_mode_set(__ioc, __msix) \
+ ((__ioc)->ioc_hwif->ioc_isr_mode_set(__ioc, __msix))
+#define bfa_ioc_ownership_reset(__ioc) \
+ ((__ioc)->ioc_hwif->ioc_ownership_reset(__ioc))
+
+void bfa_nw_ioc_set_ct_hwif(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);
+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);
+void bfa_nw_ioc_disable(struct bfa_ioc *ioc);
+
+void bfa_nw_ioc_error_isr(struct bfa_ioc *ioc);
+
+void bfa_nw_ioc_get_attr(struct bfa_ioc *ioc, struct bfa_ioc_attr *ioc_attr);
+void bfa_nw_ioc_hbfail_register(struct bfa_ioc *ioc,
+ struct bfa_ioc_hbfail_notify *notify);
+bool bfa_nw_ioc_sem_get(void __iomem *sem_reg);
+void bfa_nw_ioc_sem_release(void __iomem *sem_reg);
+void bfa_nw_ioc_hw_sem_release(struct bfa_ioc *ioc);
+void bfa_nw_ioc_fwver_get(struct bfa_ioc *ioc,
+ struct bfi_ioc_image_hdr *fwhdr);
+bool bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc,
+ struct bfi_ioc_image_hdr *fwhdr);
+mac_t bfa_nw_ioc_get_mac(struct bfa_ioc *ioc);
+
+/*
+ * Timeout APIs
+ */
+void bfa_nw_ioc_timeout(void *ioc);
+void bfa_nw_ioc_hb_check(void *ioc);
+void bfa_nw_ioc_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);
+
+#endif /* __BFA_IOC_H__ */
diff --git a/drivers/net/bna/bfa_ioc_ct.c b/drivers/net/bna/bfa_ioc_ct.c
new file mode 100644
index 000000000000..121cfd6d48b1
--- /dev/null
+++ b/drivers/net/bna/bfa_ioc_ct.c
@@ -0,0 +1,392 @@
+/*
+ * 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"
+
+/*
+ * 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_hbfail(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_ownership_reset(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_hbfail = bfa_ioc_ct_notify_hbfail;
+ nw_hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset;
+
+ 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);
+ 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_hbfail(struct bfa_ioc *ioc)
+{
+ if (ioc->cna) {
+ writel(__FW_INIT_HALT_P, ioc->ioc_regs.ll_halt);
+ /* Wait for halt to take effect */
+ readl(ioc->ioc_regs.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.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;
+ } else {
+ ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
+ ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_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;
+ }
+
+ /*
+ * 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);
+
+ /**
+ * 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);
+}
+
+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/bfa_sm.h b/drivers/net/bna/bfa_sm.h
new file mode 100644
index 000000000000..46462c49b6f9
--- /dev/null
+++ b/drivers/net/bna/bfa_sm.h
@@ -0,0 +1,88 @@
+/*
+ * 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 bfasm.h State machine defines
+ */
+
+#ifndef __BFA_SM_H__
+#define __BFA_SM_H__
+
+#include "cna.h"
+
+typedef void (*bfa_sm_t)(void *sm, int event);
+
+/**
+ * oc - object class eg. bfa_ioc
+ * st - state, eg. reset
+ * otype - object type, eg. struct bfa_ioc
+ * etype - object type, eg. enum ioc_event
+ */
+#define bfa_sm_state_decl(oc, st, otype, etype) \
+ static void oc ## _sm_ ## st(otype * fsm, etype event)
+
+#define bfa_sm_set_state(_sm, _state) ((_sm)->sm = (bfa_sm_t)(_state))
+#define bfa_sm_send_event(_sm, _event) ((_sm)->sm((_sm), (_event)))
+#define bfa_sm_get_state(_sm) ((_sm)->sm)
+#define bfa_sm_cmp_state(_sm, _state) ((_sm)->sm == (bfa_sm_t)(_state))
+
+/**
+ * For converting from state machine function to state encoding.
+ */
+struct bfa_sm_table {
+ bfa_sm_t sm; /*!< state machine function */
+ int state; /*!< state machine encoding */
+ char *name; /*!< state name for display */
+};
+#define BFA_SM(_sm) ((bfa_sm_t)(_sm))
+
+/**
+ * State machine with entry actions.
+ */
+typedef void (*bfa_fsm_t)(void *fsm, int event);
+
+/**
+ * oc - object class eg. bfa_ioc
+ * st - state, eg. reset
+ * otype - object type, eg. struct bfa_ioc
+ * etype - object type, eg. enum ioc_event
+ */
+#define bfa_fsm_state_decl(oc, st, otype, etype) \
+ static void oc ## _sm_ ## st(otype * fsm, etype event); \
+ static void oc ## _sm_ ## st ## _entry(otype * fsm)
+
+#define bfa_fsm_set_state(_fsm, _state) do { \
+ (_fsm)->fsm = (bfa_fsm_t)(_state); \
+ _state ## _entry(_fsm); \
+} while (0)
+
+#define bfa_fsm_send_event(_fsm, _event) ((_fsm)->fsm((_fsm), (_event)))
+#define bfa_fsm_get_state(_fsm) ((_fsm)->fsm)
+#define bfa_fsm_cmp_state(_fsm, _state) \
+ ((_fsm)->fsm == (bfa_fsm_t)(_state))
+
+static inline int
+bfa_sm_to_state(const struct bfa_sm_table *smt, bfa_sm_t sm)
+{
+ int i = 0;
+
+ while (smt[i].sm && smt[i].sm != sm)
+ i++;
+ return smt[i].state;
+}
+#endif
diff --git a/drivers/net/bna/bfa_wc.h b/drivers/net/bna/bfa_wc.h
new file mode 100644
index 000000000000..d0e4caee67b0
--- /dev/null
+++ b/drivers/net/bna/bfa_wc.h
@@ -0,0 +1,69 @@
+/*
+ * 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 bfa_wc.h Generic wait counter.
+ */
+
+#ifndef __BFA_WC_H__
+#define __BFA_WC_H__
+
+typedef void (*bfa_wc_resume_t) (void *cbarg);
+
+struct bfa_wc {
+ bfa_wc_resume_t wc_resume;
+ void *wc_cbarg;
+ int wc_count;
+};
+
+static inline void
+bfa_wc_up(struct bfa_wc *wc)
+{
+ wc->wc_count++;
+}
+
+static inline void
+bfa_wc_down(struct bfa_wc *wc)
+{
+ wc->wc_count--;
+ if (wc->wc_count == 0)
+ wc->wc_resume(wc->wc_cbarg);
+}
+
+/**
+ * Initialize a waiting counter.
+ */
+static inline void
+bfa_wc_init(struct bfa_wc *wc, bfa_wc_resume_t wc_resume, void *wc_cbarg)
+{
+ wc->wc_resume = wc_resume;
+ wc->wc_cbarg = wc_cbarg;
+ wc->wc_count = 0;
+ bfa_wc_up(wc);
+}
+
+/**
+ * Wait for counter to reach zero
+ */
+static inline void
+bfa_wc_wait(struct bfa_wc *wc)
+{
+ bfa_wc_down(wc);
+}
+
+#endif
diff --git a/drivers/net/bna/bfi.h b/drivers/net/bna/bfi.h
new file mode 100644
index 000000000000..a97396811050
--- /dev/null
+++ b/drivers/net/bna/bfi.h
@@ -0,0 +1,392 @@
+/*
+ * 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_H__
+#define __BFI_H__
+
+#include "bfa_defs.h"
+
+#pragma pack(1)
+
+/**
+ * BFI FW image type
+ */
+#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
+ */
+struct bfi_mhdr {
+ u8 msg_class; /*!< @ref enum bfi_mclass */
+ u8 msg_id; /*!< msg opcode with in the class */
+ union {
+ struct {
+ u8 rsvd;
+ u8 lpu_id; /*!< msg destination */
+ } h2i;
+ u16 i2htok; /*!< token in msgs to host */
+ } mtag;
+};
+
+#define bfi_h2i_set(_mh, _mc, _op, _lpuid) do { \
+ (_mh).msg_class = (_mc); \
+ (_mh).msg_id = (_op); \
+ (_mh).mtag.h2i.lpu_id = (_lpuid); \
+} while (0)
+
+#define bfi_i2h_set(_mh, _mc, _op, _i2htok) do { \
+ (_mh).msg_class = (_mc); \
+ (_mh).msg_id = (_op); \
+ (_mh).mtag.i2htok = (_i2htok); \
+} while (0)
+
+/*
+ * Message opcodes: 0-127 to firmware, 128-255 to host
+ */
+#define BFI_I2H_OPCODE_BASE 128
+#define BFA_I2HM(_x) ((_x) + BFI_I2H_OPCODE_BASE)
+
+/**
+ ****************************************************************************
+ *
+ * Scatter Gather Element and Page definition
+ *
+ ****************************************************************************
+ */
+
+#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
+ */
+union bfi_addr_u {
+ struct {
+ u32 addr_lo;
+ u32 addr_hi;
+ } 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
+ */
+#define BFI_LMSG_SZ 128
+#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
+ */
+#define BFI_MBMSG_SZ 7
+struct bfi_mbmsg {
+ struct bfi_mhdr mh;
+ u32 pl[BFI_MBMSG_SZ];
+};
+
+/**
+ * Message Classes
+ */
+enum bfi_mclass {
+ BFI_MC_IOC = 1, /*!< IO Controller (IOC) */
+ BFI_MC_DIAG = 2, /*!< Diagnostic Msgs */
+ BFI_MC_FLASH = 3, /*!< Flash message class */
+ BFI_MC_CEE = 4, /*!< CEE */
+ BFI_MC_FCPORT = 5, /*!< FC port */
+ BFI_MC_IOCFC = 6, /*!< FC - IO Controller (IOC) */
+ BFI_MC_LL = 7, /*!< Link Layer */
+ BFI_MC_UF = 8, /*!< Unsolicited frame receive */
+ BFI_MC_FCXP = 9, /*!< FC Transport */
+ BFI_MC_LPS = 10, /*!< lport fc login services */
+ BFI_MC_RPORT = 11, /*!< Remote port */
+ BFI_MC_ITNIM = 12, /*!< I-T nexus (Initiator mode) */
+ BFI_MC_IOIM_READ = 13, /*!< read IO (Initiator mode) */
+ BFI_MC_IOIM_WRITE = 14, /*!< write IO (Initiator mode) */
+ BFI_MC_IOIM_IO = 15, /*!< IO (Initiator mode) */
+ BFI_MC_IOIM = 16, /*!< IO (Initiator mode) */
+ BFI_MC_IOIM_IOCOM = 17, /*!< good IO completion */
+ BFI_MC_TSKIM = 18, /*!< Initiator Task management */
+ BFI_MC_SBOOT = 19, /*!< SAN boot services */
+ BFI_MC_IPFC = 20, /*!< IP over FC Msgs */
+ BFI_MC_PORT = 21, /*!< Physical port */
+ BFI_MC_SFP = 22, /*!< SFP module */
+ BFI_MC_MSGQ = 23, /*!< MSGQ */
+ BFI_MC_ENET = 24, /*!< ENET commands/responses */
+ BFI_MC_MAX = 32
+};
+
+#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_PARAM_OFF 12
+
+#define BFI_BOOT_TYPE_NORMAL 0 /* param is device id */
+#define BFI_BOOT_TYPE_FLASH 1
+#define BFI_BOOT_TYPE_MEMTEST 2
+
+#define BFI_BOOT_MEMTEST_RES_ADDR 0x900
+#define BFI_BOOT_MEMTEST_RES_SIG 0xA0A1A2A3
+
+/**
+ *----------------------------------------------------------------------
+ * IOC
+ *----------------------------------------------------------------------
+ */
+
+enum bfi_ioc_h2i_msgs {
+ BFI_IOC_H2I_ENABLE_REQ = 1,
+ BFI_IOC_H2I_DISABLE_REQ = 2,
+ BFI_IOC_H2I_GETATTR_REQ = 3,
+ BFI_IOC_H2I_DBG_SYNC = 4,
+ BFI_IOC_H2I_DBG_DUMP = 5,
+};
+
+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_H2I_GETATTR_REQ message
+ */
+struct bfi_ioc_getattr_req {
+ struct bfi_mhdr mh;
+ union bfi_addr_u attr_addr;
+};
+
+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;
+ u64 pwwn;
+ u64 nwwn;
+ mac_t mac; /*!< PBC or Mfg mac */
+ u16 rsvd_b;
+ mac_t fcoe_mac;
+ u16 rsvd_c;
+ char brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)];
+ u8 pcie_gen;
+ u8 pcie_lanes_orig;
+ u8 pcie_lanes;
+ u8 rx_bbcredit; /*!< receive buffer credits */
+ u32 adapter_prop; /*!< adapter properties */
+ u16 maxfrsize; /*!< max receive frame size */
+ char asic_rev;
+ u8 rsvd_d;
+ char fw_version[BFA_VERSION_LEN];
+ char optrom_version[BFA_VERSION_LEN];
+ struct bfa_mfg_vpd vpd;
+ u32 card_type; /*!< card type */
+};
+
+/**
+ * BFI_IOC_I2H_GETATTR_REPLY message
+ */
+struct bfi_ioc_getattr_reply {
+ struct bfi_mhdr mh; /*!< Common msg header */
+ u8 status; /*!< cfg reply status */
+ u8 rsvd[3];
+};
+
+/**
+ * Firmware memory page offsets
+ */
+#define BFI_IOC_SMEM_PG0_CB (0x40)
+#define BFI_IOC_SMEM_PG0_CT (0x180)
+
+/**
+ * Firmware statistic offset
+ */
+#define BFI_IOC_FWSTATS_OFF (0x6B40)
+#define BFI_IOC_FWSTATS_SZ (4096)
+
+/**
+ * Firmware trace offset
+ */
+#define BFI_IOC_TRC_OFF (0x4b00)
+#define BFI_IOC_TRC_ENTS 256
+
+#define BFI_IOC_FW_SIGNATURE (0xbfadbfad)
+#define BFI_IOC_MD5SUM_SZ 4
+struct bfi_ioc_image_hdr {
+ u32 signature; /*!< constant signature */
+ u32 rsvd_a;
+ u32 exec; /*!< exec vector */
+ u32 param; /*!< parameters */
+ u32 rsvd_b[4];
+ u32 md5sum[BFI_IOC_MD5SUM_SZ];
+};
+
+/**
+ * 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];
+};
+
+struct bfi_ioc_hbeat {
+ struct bfi_mhdr mh; /*!< common msg header */
+ u32 hb_count; /*!< current heart beat count */
+};
+
+/**
+ * IOC hardware/firmware state
+ */
+enum bfi_ioc_state {
+ BFI_IOC_UNINIT = 0, /*!< not initialized */
+ BFI_IOC_INITING = 1, /*!< h/w is being initialized */
+ BFI_IOC_HWINIT = 2, /*!< h/w is initialized */
+ BFI_IOC_CFG = 3, /*!< IOC configuration in progress */
+ BFI_IOC_OP = 4, /*!< IOC is operational */
+ BFI_IOC_DISABLING = 5, /*!< IOC is being disabled */
+ BFI_IOC_DISABLED = 6, /*!< IOC is disabled */
+ BFI_IOC_CFG_DISABLED = 7, /*!< IOC is being disabled;transient */
+ BFI_IOC_FAIL = 8, /*!< IOC heart-beat failure */
+ BFI_IOC_MEMTEST = 9, /*!< IOC is doing memtest */
+};
+
+#define BFI_IOC_ENDIAN_SIG 0x12345678
+
+enum {
+ BFI_ADAPTER_TYPE_FC = 0x01, /*!< FC adapters */
+ BFI_ADAPTER_TYPE_MK = 0x0f0000, /*!< adapter type mask */
+ BFI_ADAPTER_TYPE_SH = 16, /*!< adapter type shift */
+ BFI_ADAPTER_NPORTS_MK = 0xff00, /*!< number of ports mask */
+ BFI_ADAPTER_NPORTS_SH = 8, /*!< number of ports shift */
+ BFI_ADAPTER_SPEED_MK = 0xff, /*!< adapter speed mask */
+ BFI_ADAPTER_SPEED_SH = 0, /*!< adapter speed shift */
+ BFI_ADAPTER_PROTO = 0x100000, /*!< prototype adapaters */
+ BFI_ADAPTER_TTV = 0x200000, /*!< TTV debug capable */
+ BFI_ADAPTER_UNSUPP = 0x400000, /*!< unknown adapter type */
+};
+
+#define BFI_ADAPTER_GETP(__prop, __adap_prop) \
+ (((__adap_prop) & BFI_ADAPTER_ ## __prop ## _MK) >> \
+ BFI_ADAPTER_ ## __prop ## _SH)
+#define BFI_ADAPTER_SETP(__prop, __val) \
+ ((__val) << BFI_ADAPTER_ ## __prop ## _SH)
+#define BFI_ADAPTER_IS_PROTO(__adap_type) \
+ ((__adap_type) & BFI_ADAPTER_PROTO)
+#define BFI_ADAPTER_IS_TTV(__adap_type) \
+ ((__adap_type) & BFI_ADAPTER_TTV)
+#define BFI_ADAPTER_IS_UNSUPP(__adap_type) \
+ ((__adap_type) & BFI_ADAPTER_UNSUPP)
+#define BFI_ADAPTER_IS_SPECIAL(__adap_type) \
+ ((__adap_type) & (BFI_ADAPTER_TTV | BFI_ADAPTER_PROTO | \
+ BFI_ADAPTER_UNSUPP))
+
+/**
+ * BFI_IOC_H2I_ENABLE_REQ & BFI_IOC_H2I_DISABLE_REQ messages
+ */
+struct bfi_ioc_ctrl_req {
+ struct bfi_mhdr mh;
+ u8 ioc_class;
+ u8 rsvd[3];
+ u32 tv_sec;
+};
+
+/**
+ * BFI_IOC_I2H_ENABLE_REPLY & BFI_IOC_I2H_DISABLE_REPLY messages
+ */
+struct bfi_ioc_ctrl_reply {
+ struct bfi_mhdr mh; /*!< Common msg header */
+ u8 status; /*!< enable/disable status */
+ u8 rsvd[3];
+};
+
+#define BFI_IOC_MSGSZ 8
+/**
+ * H2I Messages
+ */
+union bfi_ioc_h2i_msg_u {
+ struct bfi_mhdr mh;
+ struct bfi_ioc_ctrl_req enable_req;
+ struct bfi_ioc_ctrl_req disable_req;
+ struct bfi_ioc_getattr_req getattr_req;
+ u32 mboxmsg[BFI_IOC_MSGSZ];
+};
+
+/**
+ * I2H Messages
+ */
+union bfi_ioc_i2h_msg_u {
+ struct bfi_mhdr mh;
+ struct bfi_ioc_rdy_event rdy_event;
+ u32 mboxmsg[BFI_IOC_MSGSZ];
+};
+
+#pragma pack()
+
+#endif /* __BFI_H__ */
diff --git a/drivers/net/bna/bfi_cna.h b/drivers/net/bna/bfi_cna.h
new file mode 100644
index 000000000000..4eecabea397b
--- /dev/null
+++ b/drivers/net/bna/bfi_cna.h
@@ -0,0 +1,199 @@
+/*
+ * 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_CNA_H__
+#define __BFI_CNA_H__
+
+#include "bfi.h"
+#include "bfa_defs_cna.h"
+
+#pragma pack(1)
+
+enum bfi_port_h2i {
+ BFI_PORT_H2I_ENABLE_REQ = (1),
+ BFI_PORT_H2I_DISABLE_REQ = (2),
+ BFI_PORT_H2I_GET_STATS_REQ = (3),
+ BFI_PORT_H2I_CLEAR_STATS_REQ = (4),
+};
+
+enum bfi_port_i2h {
+ BFI_PORT_I2H_ENABLE_RSP = BFA_I2HM(1),
+ BFI_PORT_I2H_DISABLE_RSP = BFA_I2HM(2),
+ BFI_PORT_I2H_GET_STATS_RSP = BFA_I2HM(3),
+ BFI_PORT_I2H_CLEAR_STATS_RSP = BFA_I2HM(4),
+};
+
+/**
+ * Generic REQ type
+ */
+struct bfi_port_generic_req {
+ struct bfi_mhdr mh; /*!< msg header */
+ u32 msgtag; /*!< msgtag for reply */
+ u32 rsvd;
+};
+
+/**
+ * Generic RSP type
+ */
+struct bfi_port_generic_rsp {
+ struct bfi_mhdr mh; /*!< common msg header */
+ u8 status; /*!< port enable status */
+ u8 rsvd[3];
+ u32 msgtag; /*!< msgtag for reply */
+};
+
+/**
+ * @todo
+ * BFI_PORT_H2I_ENABLE_REQ
+ */
+
+/**
+ * @todo
+ * BFI_PORT_I2H_ENABLE_RSP
+ */
+
+/**
+ * BFI_PORT_H2I_DISABLE_REQ
+ */
+
+/**
+ * BFI_PORT_I2H_DISABLE_RSP
+ */
+
+/**
+ * BFI_PORT_H2I_GET_STATS_REQ
+ */
+struct bfi_port_get_stats_req {
+ struct bfi_mhdr mh; /*!< common msg header */
+ union bfi_addr_u dma_addr;
+};
+
+/**
+ * BFI_PORT_I2H_GET_STATS_RSP
+ */
+
+/**
+ * BFI_PORT_H2I_CLEAR_STATS_REQ
+ */
+
+/**
+ * BFI_PORT_I2H_CLEAR_STATS_RSP
+ */
+
+union bfi_port_h2i_msg_u {
+ struct bfi_mhdr mh;
+ struct bfi_port_generic_req enable_req;
+ struct bfi_port_generic_req disable_req;
+ struct bfi_port_get_stats_req getstats_req;
+ struct bfi_port_generic_req clearstats_req;
+};
+
+union bfi_port_i2h_msg_u {
+ struct bfi_mhdr mh;
+ struct bfi_port_generic_rsp enable_rsp;
+ struct bfi_port_generic_rsp disable_rsp;
+ struct bfi_port_generic_rsp getstats_rsp;
+ struct bfi_port_generic_rsp clearstats_rsp;
+};
+
+/* @brief Mailbox commands from host to (DCBX/LLDP) firmware */
+enum bfi_cee_h2i_msgs {
+ BFI_CEE_H2I_GET_CFG_REQ = 1,
+ BFI_CEE_H2I_RESET_STATS = 2,
+ BFI_CEE_H2I_GET_STATS_REQ = 3,
+};
+
+/* @brief Mailbox reply and AEN messages from DCBX/LLDP firmware to host */
+enum bfi_cee_i2h_msgs {
+ BFI_CEE_I2H_GET_CFG_RSP = BFA_I2HM(1),
+ BFI_CEE_I2H_RESET_STATS_RSP = BFA_I2HM(2),
+ BFI_CEE_I2H_GET_STATS_RSP = BFA_I2HM(3),
+};
+
+/* Data structures */
+
+/*
+ * @brief H2I command structure for resetting the stats.
+ * BFI_CEE_H2I_RESET_STATS
+ */
+struct bfi_lldp_reset_stats {
+ struct bfi_mhdr mh;
+};
+
+/*
+ * @brief H2I command structure for resetting the stats.
+ * BFI_CEE_H2I_RESET_STATS
+ */
+struct bfi_cee_reset_stats {
+ struct bfi_mhdr mh;
+};
+
+/*
+ * @brief get configuration command from host
+ * BFI_CEE_H2I_GET_CFG_REQ
+ */
+struct bfi_cee_get_req {
+ struct bfi_mhdr mh;
+ union bfi_addr_u dma_addr;
+};
+
+/*
+ * @brief reply message from firmware
+ * BFI_CEE_I2H_GET_CFG_RSP
+ */
+struct bfi_cee_get_rsp {
+ struct bfi_mhdr mh;
+ u8 cmd_status;
+ u8 rsvd[3];
+};
+
+/*
+ * @brief get configuration command from host
+ * BFI_CEE_H2I_GET_STATS_REQ
+ */
+struct bfi_cee_stats_req {
+ struct bfi_mhdr mh;
+ union bfi_addr_u dma_addr;
+};
+
+/*
+ * @brief reply message from firmware
+ * BFI_CEE_I2H_GET_STATS_RSP
+ */
+struct bfi_cee_stats_rsp {
+ struct bfi_mhdr mh;
+ u8 cmd_status;
+ u8 rsvd[3];
+};
+
+/* @brief mailbox command structures from host to firmware */
+union bfi_cee_h2i_msg_u {
+ struct bfi_mhdr mh;
+ struct bfi_cee_get_req get_req;
+ struct bfi_cee_stats_req stats_req;
+};
+
+/* @brief mailbox message structures from firmware to host */
+union bfi_cee_i2h_msg_u {
+ struct bfi_mhdr mh;
+ struct bfi_cee_get_rsp get_rsp;
+ struct bfi_cee_stats_rsp stats_rsp;
+};
+
+#pragma pack()
+
+#endif /* __BFI_CNA_H__ */
diff --git a/drivers/net/bna/bfi_ctreg.h b/drivers/net/bna/bfi_ctreg.h
new file mode 100644
index 000000000000..404ea351d4a1
--- /dev/null
+++ b/drivers/net/bna/bfi_ctreg.h
@@ -0,0 +1,637 @@
+/*
+ * 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 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
new file mode 100644
index 000000000000..bee4d054066a
--- /dev/null
+++ b/drivers/net/bna/bfi_ll.h
@@ -0,0 +1,438 @@
+/*
+ * 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.h b/drivers/net/bna/bna.h
new file mode 100644
index 000000000000..df6676bbc84e
--- /dev/null
+++ b/drivers/net/bna/bna.h
@@ -0,0 +1,550 @@
+/*
+ * 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.
+ */
+#ifndef __BNA_H__
+#define __BNA_H__
+
+#include "bfa_wc.h"
+#include "bfa_ioc.h"
+#include "cna.h"
+#include "bfi_ll.h"
+#include "bna_types.h"
+
+extern const u32 bna_napi_dim_vector[][BNA_BIAS_T_MAX];
+
+/**
+ *
+ * Macros and constants
+ *
+ */
+
+#define BNA_IOC_TIMER_FREQ 200
+
+/* Log string size */
+#define BNA_MESSAGE_SIZE 256
+
+#define bna_device_timer(_dev) bfa_timer_beat(&((_dev)->timer_mod))
+
+/* 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_MAC_IS_EQUAL(_mac1, _mac2) \
+ (!memcmp((_mac1), (_mac2), sizeof(mac_t)))
+
+#define BNA_POWER_OF_2(x) (((x) & ((x) - 1)) == 0)
+
+#define BNA_TO_POWER_OF_2(x) \
+do { \
+ int _shift = 0; \
+ while ((x) && (x) != 1) { \
+ (x) >>= 1; \
+ _shift++; \
+ } \
+ (x) <<= _shift; \
+} while (0)
+
+#define BNA_TO_POWER_OF_2_HIGH(x) \
+do { \
+ int n = 1; \
+ while (n < (x)) \
+ n <<= 1; \
+ (x) = n; \
+} while (0)
+
+/*
+ * input : _addr-> os dma addr in host endian format,
+ * output : _bna_dma_addr-> pointer to hw dma addr
+ */
+#define BNA_SET_DMA_ADDR(_addr, _bna_dma_addr) \
+do { \
+ u64 tmp_addr = \
+ cpu_to_be64((u64)(_addr)); \
+ (_bna_dma_addr)->msb = ((struct bna_dma_addr *)&tmp_addr)->msb; \
+ (_bna_dma_addr)->lsb = ((struct bna_dma_addr *)&tmp_addr)->lsb; \
+} while (0)
+
+/*
+ * input : _bna_dma_addr-> pointer to hw dma addr
+ * output : _addr-> os dma addr in host endian format
+ */
+#define BNA_GET_DMA_ADDR(_bna_dma_addr, _addr) \
+do { \
+ (_addr) = ((((u64)ntohl((_bna_dma_addr)->msb))) << 32) \
+ | ((ntohl((_bna_dma_addr)->lsb) & 0xffffffff)); \
+} while (0)
+
+#define containing_rec(addr, type, field) \
+ ((type *)((unsigned char *)(addr) - \
+ (unsigned char *)(&((type *)0)->field)))
+
+#define BNA_TXQ_WI_NEEDED(_vectors) (((_vectors) + 3) >> 2)
+
+/* TxQ element is 64 bytes */
+#define BNA_TXQ_PAGE_INDEX_MAX (PAGE_SIZE >> 6)
+#define BNA_TXQ_PAGE_INDEX_MAX_SHIFT (PAGE_SHIFT - 6)
+
+#define BNA_TXQ_QPGE_PTR_GET(_qe_idx, _qpt_ptr, _qe_ptr, _qe_ptr_range) \
+{ \
+ unsigned int page_index; /* index within a page */ \
+ void *page_addr; \
+ page_index = (_qe_idx) & (BNA_TXQ_PAGE_INDEX_MAX - 1); \
+ (_qe_ptr_range) = (BNA_TXQ_PAGE_INDEX_MAX - page_index); \
+ page_addr = (_qpt_ptr)[((_qe_idx) >> BNA_TXQ_PAGE_INDEX_MAX_SHIFT)];\
+ (_qe_ptr) = &((struct bna_txq_entry *)(page_addr))[page_index]; \
+}
+
+/* RxQ element is 8 bytes */
+#define BNA_RXQ_PAGE_INDEX_MAX (PAGE_SIZE >> 3)
+#define BNA_RXQ_PAGE_INDEX_MAX_SHIFT (PAGE_SHIFT - 3)
+
+#define BNA_RXQ_QPGE_PTR_GET(_qe_idx, _qpt_ptr, _qe_ptr, _qe_ptr_range) \
+{ \
+ unsigned int page_index; /* index within a page */ \
+ void *page_addr; \
+ page_index = (_qe_idx) & (BNA_RXQ_PAGE_INDEX_MAX - 1); \
+ (_qe_ptr_range) = (BNA_RXQ_PAGE_INDEX_MAX - page_index); \
+ page_addr = (_qpt_ptr)[((_qe_idx) >> \
+ BNA_RXQ_PAGE_INDEX_MAX_SHIFT)]; \
+ (_qe_ptr) = &((struct bna_rxq_entry *)(page_addr))[page_index]; \
+}
+
+/* CQ element is 16 bytes */
+#define BNA_CQ_PAGE_INDEX_MAX (PAGE_SIZE >> 4)
+#define BNA_CQ_PAGE_INDEX_MAX_SHIFT (PAGE_SHIFT - 4)
+
+#define BNA_CQ_QPGE_PTR_GET(_qe_idx, _qpt_ptr, _qe_ptr, _qe_ptr_range) \
+{ \
+ unsigned int page_index; /* index within a page */ \
+ void *page_addr; \
+ \
+ page_index = (_qe_idx) & (BNA_CQ_PAGE_INDEX_MAX - 1); \
+ (_qe_ptr_range) = (BNA_CQ_PAGE_INDEX_MAX - page_index); \
+ page_addr = (_qpt_ptr)[((_qe_idx) >> \
+ BNA_CQ_PAGE_INDEX_MAX_SHIFT)]; \
+ (_qe_ptr) = &((struct bna_cq_entry *)(page_addr))[page_index];\
+}
+
+#define BNA_QE_INDX_2_PTR(_cast, _qe_idx, _q_base) \
+ (&((_cast *)(_q_base))[(_qe_idx)])
+
+#define BNA_QE_INDX_RANGE(_qe_idx, _q_depth) ((_q_depth) - (_qe_idx))
+
+#define BNA_QE_INDX_ADD(_qe_idx, _qe_num, _q_depth) \
+ ((_qe_idx) = ((_qe_idx) + (_qe_num)) & ((_q_depth) - 1))
+
+#define BNA_Q_INDEX_CHANGE(_old_idx, _updated_idx, _q_depth) \
+ (((_updated_idx) - (_old_idx)) & ((_q_depth) - 1))
+
+#define BNA_QE_FREE_CNT(_q_ptr, _q_depth) \
+ (((_q_ptr)->consumer_index - (_q_ptr)->producer_index - 1) & \
+ ((_q_depth) - 1))
+
+#define BNA_QE_IN_USE_CNT(_q_ptr, _q_depth) \
+ ((((_q_ptr)->producer_index - (_q_ptr)->consumer_index)) & \
+ (_q_depth - 1))
+
+#define BNA_Q_GET_CI(_q_ptr) ((_q_ptr)->q.consumer_index)
+
+#define BNA_Q_GET_PI(_q_ptr) ((_q_ptr)->q.producer_index)
+
+#define BNA_Q_PI_ADD(_q_ptr, _num) \
+ (_q_ptr)->q.producer_index = \
+ (((_q_ptr)->q.producer_index + (_num)) & \
+ ((_q_ptr)->q.q_depth - 1))
+
+#define BNA_Q_CI_ADD(_q_ptr, _num) \
+ (_q_ptr)->q.consumer_index = \
+ (((_q_ptr)->q.consumer_index + (_num)) \
+ & ((_q_ptr)->q.q_depth - 1))
+
+#define BNA_Q_FREE_COUNT(_q_ptr) \
+ (BNA_QE_FREE_CNT(&((_q_ptr)->q), (_q_ptr)->q.q_depth))
+
+#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) \
+do { \
+ if ((_len) > BNA_LARGE_PKT_SIZE) { \
+ (_pkt)->large_pkt_cnt++; \
+ } else { \
+ (_pkt)->small_pkt_cnt++; \
+ } \
+} while (0)
+
+#define call_rxf_stop_cbfn(rxf, status) \
+ if ((rxf)->stop_cbfn) { \
+ (*(rxf)->stop_cbfn)((rxf)->stop_cbarg, (status)); \
+ (rxf)->stop_cbfn = NULL; \
+ (rxf)->stop_cbarg = NULL; \
+ }
+
+#define call_rxf_start_cbfn(rxf, status) \
+ if ((rxf)->start_cbfn) { \
+ (*(rxf)->start_cbfn)((rxf)->start_cbarg, (status)); \
+ (rxf)->start_cbfn = NULL; \
+ (rxf)->start_cbarg = NULL; \
+ }
+
+#define call_rxf_cam_fltr_cbfn(rxf, status) \
+ if ((rxf)->cam_fltr_cbfn) { \
+ (*(rxf)->cam_fltr_cbfn)((rxf)->cam_fltr_cbarg, rxf->rx, \
+ (status)); \
+ (rxf)->cam_fltr_cbfn = NULL; \
+ (rxf)->cam_fltr_cbarg = NULL; \
+ }
+
+#define call_rxf_pause_cbfn(rxf, status) \
+ if ((rxf)->oper_state_cbfn) { \
+ (*(rxf)->oper_state_cbfn)((rxf)->oper_state_cbarg, rxf->rx,\
+ (status)); \
+ (rxf)->rxf_flags &= ~BNA_RXF_FL_OPERSTATE_CHANGED; \
+ (rxf)->oper_state_cbfn = NULL; \
+ (rxf)->oper_state_cbarg = NULL; \
+ }
+
+#define call_rxf_resume_cbfn(rxf, status) call_rxf_pause_cbfn(rxf, status)
+
+#define is_xxx_enable(mode, bitmask, xxx) ((bitmask & xxx) && (mode & xxx))
+
+#define is_xxx_disable(mode, bitmask, xxx) ((bitmask & xxx) && !(mode & xxx))
+
+#define xxx_enable(mode, bitmask, xxx) \
+do { \
+ bitmask |= xxx; \
+ mode |= xxx; \
+} while (0)
+
+#define xxx_disable(mode, bitmask, xxx) \
+do { \
+ bitmask |= xxx; \
+ mode &= ~xxx; \
+} while (0)
+
+#define xxx_inactive(mode, bitmask, xxx) \
+do { \
+ bitmask &= ~xxx; \
+ mode &= ~xxx; \
+} while (0)
+
+#define is_promisc_enable(mode, bitmask) \
+ is_xxx_enable(mode, bitmask, BNA_RXMODE_PROMISC)
+
+#define is_promisc_disable(mode, bitmask) \
+ is_xxx_disable(mode, bitmask, BNA_RXMODE_PROMISC)
+
+#define promisc_enable(mode, bitmask) \
+ xxx_enable(mode, bitmask, BNA_RXMODE_PROMISC)
+
+#define promisc_disable(mode, bitmask) \
+ xxx_disable(mode, bitmask, BNA_RXMODE_PROMISC)
+
+#define promisc_inactive(mode, bitmask) \
+ xxx_inactive(mode, bitmask, BNA_RXMODE_PROMISC)
+
+#define is_default_enable(mode, bitmask) \
+ is_xxx_enable(mode, bitmask, BNA_RXMODE_DEFAULT)
+
+#define is_default_disable(mode, bitmask) \
+ is_xxx_disable(mode, bitmask, BNA_RXMODE_DEFAULT)
+
+#define default_enable(mode, bitmask) \
+ xxx_enable(mode, bitmask, BNA_RXMODE_DEFAULT)
+
+#define default_disable(mode, bitmask) \
+ xxx_disable(mode, bitmask, BNA_RXMODE_DEFAULT)
+
+#define default_inactive(mode, bitmask) \
+ xxx_inactive(mode, bitmask, BNA_RXMODE_DEFAULT)
+
+#define is_allmulti_enable(mode, bitmask) \
+ is_xxx_enable(mode, bitmask, BNA_RXMODE_ALLMULTI)
+
+#define is_allmulti_disable(mode, bitmask) \
+ is_xxx_disable(mode, bitmask, BNA_RXMODE_ALLMULTI)
+
+#define allmulti_enable(mode, bitmask) \
+ xxx_enable(mode, bitmask, BNA_RXMODE_ALLMULTI)
+
+#define allmulti_disable(mode, bitmask) \
+ xxx_disable(mode, bitmask, BNA_RXMODE_ALLMULTI)
+
+#define allmulti_inactive(mode, bitmask) \
+ xxx_inactive(mode, bitmask, BNA_RXMODE_ALLMULTI)
+
+#define GET_RXQS(rxp, q0, q1) do { \
+ switch ((rxp)->type) { \
+ case BNA_RXP_SINGLE: \
+ (q0) = rxp->rxq.single.only; \
+ (q1) = NULL; \
+ break; \
+ case BNA_RXP_SLR: \
+ (q0) = rxp->rxq.slr.large; \
+ (q1) = rxp->rxq.slr.small; \
+ break; \
+ case BNA_RXP_HDS: \
+ (q0) = rxp->rxq.hds.data; \
+ (q1) = rxp->rxq.hds.hdr; \
+ break; \
+ } \
+} while (0)
+
+/**
+ *
+ * Function prototypes
+ *
+ */
+
+/**
+ * BNA
+ */
+
+/* APIs for BNAD */
+void bna_res_req(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_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);
+
+/* APIs for RxF */
+struct bna_mac *bna_ucam_mod_mac_get(struct bna_ucam_mod *ucam_mod);
+void bna_ucam_mod_mac_put(struct bna_ucam_mod *ucam_mod,
+ struct bna_mac *mac);
+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);
+
+/**
+ * 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_admin_up(struct bna_llport *llport);
+void bna_llport_admin_down(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);
+
+/**
+ * IB
+ */
+
+/* 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);
+
+/**
+ * TX MODULE AND TX
+ */
+
+/* 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 */
+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,
+ 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 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);
+
+/* 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 */
+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);
+
+/* APIs for BNAD */
+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,
+ 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 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));
+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));
+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));
+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 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));
+
+/**
+ * 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/bna/bna_ctrl.c b/drivers/net/bna/bna_ctrl.c
new file mode 100644
index 000000000000..07b26598546e
--- /dev/null
+++ b/drivers/net/bna/bna_ctrl.c
@@ -0,0 +1,3261 @@
+/*
+ * 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_sm.h"
+#include "bfa_wc.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);
+}
+
+/**
+ * MBOX
+ */
+static int
+bna_is_aen(u8 msg_id)
+{
+ return msg_id == BFI_LL_I2H_LINK_DOWN_AEN ||
+ msg_id == BFI_LL_I2H_LINK_UP_AEN;
+}
+
+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;
+ 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 bfi_mhdr *cmd_h;
+ 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--;
+
+ cmd_h = (struct bfi_mhdr *)(&mb_qe->cmd.msg[0]);
+ 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_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 = 6,
+ LLPORT_E_FWRESP_DOWN = 7
+};
+
+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:
+ case LLPORT_E_FWRESP_DOWN:
+ /**
+ * These events are received due to flushing of mbox when
+ * device fails
+ */
+ /* No-op */
+ break;
+
+ default:
+ bfa_sm_fault(llport->bna, 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(llport->bna, event);
+ }
+}
+
+static void
+bna_llport_sm_up_resp_wait_entry(struct bna_llport *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:
+ bfa_fsm_set_state(llport, bna_llport_sm_up);
+ 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(llport->bna, 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:
+ /* up_resp_wait->down_resp_wait transition on LLPORT_E_DOWN */
+ bna_fw_llport_down(llport);
+ break;
+
+ case LLPORT_E_FWRESP_DOWN:
+ bfa_fsm_set_state(llport, bna_llport_sm_down);
+ break;
+
+ default:
+ bfa_sm_fault(llport->bna, 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(llport->bna, 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:
+ /* up_resp_wait->last_resp_wait transition on LLPORT_T_STOP */
+ bna_fw_llport_down(llport);
+ break;
+
+ case LLPORT_E_FWRESP_DOWN:
+ bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+ break;
+
+ default:
+ bfa_sm_fault(llport->bna, 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);
+ bfa_fsm_send_event(llport, LLPORT_E_FWRESP_UP);
+}
+
+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_ENABLED;
+ llport->type = BNA_PORT_T_REGULAR;
+ llport->bna = bna;
+
+ llport->link_status = BNA_LINK_DOWN;
+
+ llport->admin_up_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_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)
+{
+ 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_admin_up(struct bna_llport *llport)
+{
+ llport->admin_up_count++;
+
+ if (llport->admin_up_count == 1) {
+ llport->flags |= BNA_LLPORT_F_RX_ENABLED;
+ if (llport->flags & BNA_LLPORT_F_ENABLED)
+ bfa_fsm_send_event(llport, LLPORT_E_UP);
+ }
+}
+
+void
+bna_llport_admin_down(struct bna_llport *llport)
+{
+ llport->admin_up_count--;
+
+ if (llport->admin_up_count == 0) {
+ llport->flags &= ~BNA_LLPORT_F_RX_ENABLED;
+ if (llport->flags & BNA_LLPORT_F_ENABLED)
+ 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(port->bna, 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(port->bna, 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(port->bna, 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(port->bna, 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(port->bna, 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(port->bna, 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(port->bna, 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(port->bna, 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(port->bna, 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(device->bna, 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(device->bna, 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(device->bna, 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(device->bna, 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(device->bna, 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(device->bna, 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);
+}
+
+static void
+__rxf_default_function_config(struct bna_rxf *rxf, enum bna_status status)
+{
+ struct bna_rx_fndb_ram *rx_fndb_ram;
+ u32 ctrl_flags;
+ int i;
+
+ rx_fndb_ram = (struct bna_rx_fndb_ram *)
+ BNA_GET_MEM_BASE_ADDR(rxf->rx->bna->pcidev.pci_bar_kva,
+ RX_FNDB_RAM_BASE_OFFSET);
+
+ for (i = 0; i < BFI_MAX_RXF; i++) {
+ if (status == BNA_STATUS_T_ENABLED) {
+ if (i == rxf->rxf_id)
+ continue;
+
+ ctrl_flags =
+ readl(&rx_fndb_ram[i].control_flags);
+ ctrl_flags |= BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE;
+ writel(ctrl_flags,
+ &rx_fndb_ram[i].control_flags);
+ } else {
+ ctrl_flags =
+ readl(&rx_fndb_ram[i].control_flags);
+ ctrl_flags &= ~BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE;
+ writel(ctrl_flags,
+ &rx_fndb_ram[i].control_flags);
+ }
+ }
+}
+
+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_default(struct bna_rxf *rxf)
+{
+ struct bna *bna = rxf->rx->bna;
+
+ /* Enable/disable default mode */
+ if (is_default_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ /* move default configuration from pending -> active */
+ default_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ rxf->rxmode_active |= BNA_RXMODE_DEFAULT;
+
+ /* Disable VLAN filter to allow all VLANs */
+ __rxf_vlan_filter_set(rxf, BNA_STATUS_T_DISABLED);
+ /* Redirect all other RxF vlan filtering to this one */
+ __rxf_default_function_config(rxf, BNA_STATUS_T_ENABLED);
+ rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_SET_REQ,
+ BNA_STATUS_T_ENABLED);
+ return 1;
+ } else if (is_default_disable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ /* move default configuration from pending -> active */
+ default_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
+ bna->rxf_default_id = BFI_MAX_RXF;
+
+ /* Revert VLAN filter */
+ __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+ /* Stop RxF vlan filter table redirection */
+ __rxf_default_function_config(rxf, BNA_STATUS_T_DISABLED);
+ rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_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_default(struct bna_rxf *rxf)
+{
+ struct bna *bna = rxf->rx->bna;
+
+ /* 8. Execute pending default mode disable command */
+ if (is_default_disable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ /* move default configuration from pending -> active */
+ default_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
+ bna->rxf_default_id = BFI_MAX_RXF;
+
+ /* Revert VLAN filter */
+ __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+ /* Stop RxF vlan filter table redirection */
+ __rxf_default_function_config(rxf, BNA_STATUS_T_DISABLED);
+ rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_SET_REQ,
+ BNA_STATUS_T_DISABLED);
+ return 1;
+ }
+
+ /* 9. Clear active default mode; move it to pending enable */
+ if (rxf->rxmode_active & BNA_RXMODE_DEFAULT) {
+ /* move default configuration from active -> pending */
+ default_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
+
+ /* Revert VLAN filter */
+ __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+ /* Stop RxF vlan filter table redirection */
+ __rxf_default_function_config(rxf, BNA_STATUS_T_DISABLED);
+ rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_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_default(struct bna_rxf *rxf)
+{
+ struct bna *bna = rxf->rx->bna;
+
+ /* 8. Clear pending default mode disable */
+ if (is_default_disable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ default_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
+ bna->rxf_default_id = BFI_MAX_RXF;
+ }
+
+ /* 9. Move default mode config from active -> pending */
+ if (rxf->rxmode_active & BNA_RXMODE_DEFAULT) {
+ default_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
+ }
+}
+
+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_default_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_default_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask) ||
+ (rxf->rxmode_active & BNA_RXMODE_DEFAULT)) {
+ /* Schedule enable */
+ } else {
+ /* Default mode should not be active in the system */
+ default_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ bna->rxf_default_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_default_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_default_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ /* Promisc mode should not be active */
+ /* system default state should be pending */
+ default_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ /* Remove the default state from the system */
+ bna->rxf_default_id = BFI_MAX_RXF;
+
+ /* Schedule disable */
+ } else if (rxf->rxmode_active & BNA_RXMODE_DEFAULT) {
+ /* Default mode should be active in the system */
+ default_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;
+
+ /* Error checks */
+
+ 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 default mode is already enabled in the system */
+ if (rx->bna->rxf_default_id != BFI_MAX_RXF)
+ 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->rxf_default_id != BFI_MAX_RXF) &&
+ (rx->bna->rxf_default_id != rxf->rxf_id)) {
+ goto err_return;
+ }
+
+ /* If promiscuous mode is already enabled in the system */
+ if (rx->bna->rxf_promisc_id != BFI_MAX_RXF)
+ goto err_return;
+ }
+
+ /* Process the commands */
+
+ if (is_promisc_enable(new_mode, bitmask)) {
+ 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_default_enable(new_mode, bitmask)) {
+ if (rxf_default_enable(rxf))
+ need_hw_config = 1;
+ } else if (is_default_disable(new_mode, bitmask)) {
+ if (rxf_default_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;
+ }
+ }
+}
+
+static void
+bna_rit_mod_uninit(struct bna_rit_mod *rit_mod)
+{
+ struct bna_rit_segment *rit_segment;
+ struct list_head *qe;
+ int i;
+ int j;
+
+ for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
+ j = 0;
+ list_for_each(qe, &rit_mod->rit_seg_pool[i]) {
+ rit_segment = (struct bna_rit_segment *)qe;
+ j++;
+ }
+ }
+}
+
+/*
+ * 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_default_id = BFI_MAX_RXF;
+ 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_rit_mod_uninit(&bna->rit_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
new file mode 100644
index 000000000000..806b224a4c63
--- /dev/null
+++ b/drivers/net/bna/bna_hw.h
@@ -0,0 +1,1490 @@
+/*
+ * 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 alligned 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
new file mode 100644
index 000000000000..ad93fdb0f427
--- /dev/null
+++ b/drivers/net/bna/bna_txrx.c
@@ -0,0 +1,4172 @@
+/*
+ * 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_sm.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(rxf->rx->bna, 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(rxf->rx->bna, 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(rxf->rx->bna, 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(rxf->rx->bna, 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(rxf->rx->bna, 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(rxf->rx->bna, 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(rxf->rx->bna, 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(rxf->rx->bna, 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(rxf->rx->bna, 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->rxmode_active & BNA_RXMODE_DEFAULT))
+ __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_default(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_default(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_default(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)));
+
+ bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+}
+
+static void
+bna_rxf_uninit(struct bna_rxf *rxf)
+{
+ 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);
+ }
+
+ 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(rx->bna, 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(rx->bna, 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_admin_up(&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_admin_down(&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_admin_down(&rx->bna->port.llport);
+ bfa_fsm_set_state(rx, bna_rx_sm_rxf_stop_wait);
+ break;
+ default:
+ bfa_sm_fault(rx->bna, 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(rx->bna, 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(rx->bna, 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 *bna;
+ struct bna_rxp *rxp;
+ struct bna_rxq *q0 = NULL;
+ struct bna_rxq *q1 = NULL;
+ int offset;
+
+ bna = rx->bna;
+
+ 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, ret;
+ 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;
+
+ ret = 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(tx->bna, 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(tx->bna, 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(tx->bna, 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(tx->bna, 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(tx->bna, 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 & 0x3));
+ 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/bna/bna_types.h b/drivers/net/bna/bna_types.h
new file mode 100644
index 000000000000..6877310f6ef4
--- /dev/null
+++ b/drivers/net/bna/bna_types.h
@@ -0,0 +1,1128 @@
+/*
+ * 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 __BNA_TYPES_H__
+#define __BNA_TYPES_H__
+
+#include "cna.h"
+#include "bna_hw.h"
+#include "bfa_cee.h"
+
+/**
+ *
+ * Forward declarations
+ *
+ */
+
+struct bna_txq;
+struct bna_tx;
+struct bna_rxq;
+struct bna_cq;
+struct bna_rx;
+struct bna_rxf;
+struct bna_port;
+struct bna;
+struct bnad;
+
+/**
+ *
+ * Enums, primitive data types
+ *
+ */
+
+enum bna_status {
+ BNA_STATUS_T_DISABLED = 0,
+ BNA_STATUS_T_ENABLED = 1
+};
+
+enum bna_cleanup_type {
+ BNA_HARD_CLEANUP = 0,
+ BNA_SOFT_CLEANUP = 1
+};
+
+enum bna_cb_status {
+ BNA_CB_SUCCESS = 0,
+ BNA_CB_FAIL = 1,
+ BNA_CB_INTERRUPT = 2,
+ BNA_CB_BUSY = 3,
+ BNA_CB_INVALID_MAC = 4,
+ BNA_CB_MCAST_LIST_FULL = 5,
+ BNA_CB_UCAST_CAM_FULL = 6,
+ BNA_CB_WAITING = 7,
+ BNA_CB_NOT_EXEC = 8
+};
+
+enum bna_res_type {
+ BNA_RES_T_MEM = 1,
+ BNA_RES_T_INTR = 2
+};
+
+enum bna_mem_type {
+ BNA_MEM_T_KVA = 1,
+ BNA_MEM_T_DMA = 2
+};
+
+enum bna_intr_type {
+ BNA_INTR_T_INTX = 1,
+ BNA_INTR_T_MSIX = 2
+};
+
+enum bna_res_req_type {
+ BNA_RES_MEM_T_COM = 0,
+ 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_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_T_MAX,
+};
+
+enum bna_rx_mem_type {
+ BNA_RX_RES_MEM_T_CCB = 0, /* CQ context */
+ BNA_RX_RES_MEM_T_RCB = 1, /* CQ context */
+ BNA_RX_RES_MEM_T_UNMAPQ = 2, /* UnmapQ for RxQs */
+ BNA_RX_RES_MEM_T_CQPT = 3, /* CQ QPT */
+ BNA_RX_RES_MEM_T_CSWQPT = 4, /* S/W QPT */
+ BNA_RX_RES_MEM_T_CQPT_PAGE = 5, /* CQPT page */
+ BNA_RX_RES_MEM_T_HQPT = 6, /* RX QPT */
+ BNA_RX_RES_MEM_T_DQPT = 7, /* RX QPT */
+ BNA_RX_RES_MEM_T_HSWQPT = 8, /* RX s/w QPT */
+ 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
+};
+
+enum bna_tx_type {
+ BNA_TX_T_REGULAR = 0,
+ BNA_TX_T_LOOPBACK = 1,
+};
+
+enum bna_tx_flags {
+ BNA_TX_F_PORT_STARTED = 1,
+ BNA_TX_F_ENABLED = 2,
+ BNA_TX_F_PRIO_LOCK = 4,
+};
+
+enum bna_tx_mod_flags {
+ BNA_TX_MOD_F_PORT_STARTED = 1,
+ BNA_TX_MOD_F_PORT_LOOPBACK = 2,
+};
+
+enum bna_rx_type {
+ BNA_RX_T_REGULAR = 0,
+ BNA_RX_T_LOOPBACK = 1,
+};
+
+enum bna_rxp_type {
+ BNA_RXP_SINGLE = 1,
+ BNA_RXP_SLR = 2,
+ BNA_RXP_HDS = 3
+};
+
+enum bna_rxmode {
+ BNA_RXMODE_PROMISC = 1,
+ 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,
+};
+
+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 */
+};
+
+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 */
+};
+
+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,
+};
+
+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,
+};
+
+enum bna_port_type {
+ BNA_PORT_T_REGULAR = 0,
+ BNA_PORT_T_LOOPBACK_INTERNAL = 1,
+ BNA_PORT_T_LOOPBACK_EXTERNAL = 2,
+};
+
+enum bna_link_status {
+ BNA_LINK_DOWN = 0,
+ BNA_LINK_UP = 1,
+ BNA_CEE_UP = 2
+};
+
+enum bna_llport_flags {
+ BNA_LLPORT_F_ENABLED = 1,
+ BNA_LLPORT_F_RX_ENABLED = 2
+};
+
+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_pkt_rates {
+ BNA_PKT_RATE_10K = 10000,
+ BNA_PKT_RATE_20K = 20000,
+ BNA_PKT_RATE_30K = 30000,
+ BNA_PKT_RATE_40K = 40000,
+ BNA_PKT_RATE_50K = 50000,
+ BNA_PKT_RATE_60K = 60000,
+ BNA_PKT_RATE_70K = 70000,
+ BNA_PKT_RATE_80K = 80000,
+};
+
+enum bna_dim_load_types {
+ BNA_LOAD_T_HIGH_4 = 0, /* 80K <= r */
+ BNA_LOAD_T_HIGH_3 = 1, /* 60K <= r < 80K */
+ BNA_LOAD_T_HIGH_2 = 2, /* 50K <= r < 60K */
+ BNA_LOAD_T_HIGH_1 = 3, /* 40K <= r < 50K */
+ BNA_LOAD_T_LOW_1 = 4, /* 30K <= r < 40K */
+ BNA_LOAD_T_LOW_2 = 5, /* 20K <= r < 30K */
+ BNA_LOAD_T_LOW_3 = 6, /* 10K <= r < 20K */
+ BNA_LOAD_T_LOW_4 = 7, /* r < 10K */
+ BNA_LOAD_T_MAX = 8
+};
+
+enum bna_dim_bias_types {
+ BNA_BIAS_T_SMALL = 0, /* small pkts > (large pkts * 2) */
+ BNA_BIAS_T_LARGE = 1, /* Not BNA_BIAS_T_SMALL */
+ BNA_BIAS_T_MAX = 2
+};
+
+struct bna_mac {
+ /* This should be the first one */
+ struct list_head qe;
+ u8 addr[ETH_ALEN];
+};
+
+struct bna_mem_descr {
+ u32 len;
+ void *kva;
+ struct bna_dma_addr dma;
+};
+
+struct bna_mem_info {
+ enum bna_mem_type mem_type;
+ u32 len;
+ u32 num;
+ u32 align_sz; /* 0/1 = no alignment */
+ struct bna_mem_descr *mdl;
+ void *cookie; /* For bnad to unmap dma later */
+};
+
+struct bna_intr_descr {
+ int vector;
+};
+
+struct bna_intr_info {
+ enum bna_intr_type intr_type;
+ int num;
+ struct bna_intr_descr *idl;
+};
+
+union bna_res_u {
+ struct bna_mem_info mem_info;
+ struct bna_intr_info intr_info;
+};
+
+struct bna_res_info {
+ enum bna_res_type res_type;
+ union bna_res_u res_u;
+};
+
+/* HW QPT */
+struct bna_qpt {
+ struct bna_dma_addr hw_qpt_ptr;
+ void *kv_qpt_ptr;
+ u32 page_count;
+ u32 page_size;
+};
+
+/**
+ *
+ * Device
+ *
+ */
+
+struct bna_device {
+ bfa_fsm_t fsm;
+ struct bfa_ioc ioc;
+
+ enum bna_intr_type intr_type;
+ int vector;
+
+ 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);
+ struct bnad *stop_cbarg;
+
+ struct bna *bna;
+};
+
+/**
+ *
+ * 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
+ *
+ */
+
+/* Pause configuration */
+struct bna_pause_config {
+ enum bna_status tx_pause;
+ enum bna_status rx_pause;
+};
+
+struct bna_llport {
+ bfa_fsm_t fsm;
+ enum bna_llport_flags flags;
+
+ enum bna_port_type type;
+
+ enum bna_link_status link_status;
+
+ int admin_up_count;
+
+ void (*stop_cbfn)(struct bna_port *, enum bna_cb_status);
+
+ struct bna_mbox_qe mbox_qe;
+
+ struct bna *bna;
+};
+
+struct bna_port {
+ bfa_fsm_t fsm;
+ enum bna_port_flags flags;
+
+ enum bna_port_type type;
+
+ struct bna_llport llport;
+
+ struct bna_pause_config pause_config;
+ u8 priority;
+ int mtu;
+
+ /* Callback for bna_port_disable(), port_stop() */
+ void (*stop_cbfn)(void *, enum bna_cb_status);
+ void *stop_cbarg;
+
+ /* Callback for bna_port_pause_config() */
+ void (*pause_cbfn)(struct bnad *, enum bna_cb_status);
+
+ /* Callback for bna_port_mtu_set() */
+ void (*mtu_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 bna *bna;
+};
+
+/**
+ *
+ * Interrupt Block
+ *
+ */
+
+/* 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];
+
+ struct list_head intr_free_q;
+ struct list_head intr_active_q;
+
+ struct bna *bna;
+};
+
+/**
+ *
+ * Tx object
+ *
+ */
+
+/* Tx datapath control structure */
+#define BNA_Q_NAME_SIZE 16
+struct bna_tcb {
+ /* Fast path */
+ void **sw_qpt;
+ void *unmap_q;
+ u32 producer_index;
+ u32 consumer_index;
+ volatile u32 *hw_consumer_index;
+ u32 q_depth;
+ void *__iomem q_dbell;
+ struct bna_ib_dbell *i_dbell;
+ int page_idx;
+ int page_count;
+ /* Control path */
+ struct bna_txq *txq;
+ struct bnad *bnad;
+ enum bna_intr_type intr_type;
+ int intr_vector;
+ u8 priority; /* Current priority */
+ unsigned long flags; /* Used by bnad as required */
+ int id;
+ char name[BNA_Q_NAME_SIZE];
+};
+
+/* TxQ QPT and configuration */
+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_tx *tx;
+
+ 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;
+
+ bfa_fsm_t fsm;
+ enum bna_tx_flags flags;
+
+ enum bna_tx_type type;
+
+ struct list_head txq_q;
+ struct bna_txf txf;
+
+ /* 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 *);
+
+ /* callback for bna_tx_disable(), bna_tx_stop() */
+ void (*stop_cbfn)(void *arg, struct bna_tx *tx,
+ enum bna_cb_status status);
+ 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;
+
+ struct bna_mbox_qe mbox_qe;
+
+ struct bna *bna;
+ void *priv; /* bnad's cookie */
+};
+
+struct bna_tx_config {
+ int num_txq;
+ int txq_depth;
+ enum bna_tx_type tx_type;
+};
+
+struct bna_tx_event_cbfn {
+ /* Optional */
+ 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 *);
+};
+
+/* Tx module - keeps track of free, active tx objects */
+struct bna_tx_mod {
+ struct bna_tx *tx; /* BFI_MAX_TXQ entries */
+ struct bna_txq *txq; /* BFI_MAX_TXQ entries */
+
+ struct list_head tx_free_q;
+ struct list_head tx_active_q;
+
+ struct list_head txq_free_q;
+
+ /* callback for bna_tx_mod_stop() */
+ void (*stop_cbfn)(struct bna_port *port,
+ enum bna_cb_status status);
+
+ struct bfa_wc tx_stop_wc;
+
+ enum bna_tx_mod_flags flags;
+
+ int priority;
+ int cee_link;
+
+ u32 txf_bmap[2];
+
+ 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
+ *
+ */
+
+/* Rx datapath control structure */
+struct bna_rcb {
+ /* Fast path */
+ void **sw_qpt;
+ void *unmap_q;
+ u32 producer_index;
+ u32 consumer_index;
+ u32 q_depth;
+ void *__iomem q_dbell;
+ int page_idx;
+ int page_count;
+ /* Control path */
+ struct bna_rxq *rxq;
+ struct bna_cq *cq;
+ struct bnad *bnad;
+ unsigned long flags;
+ int id;
+};
+
+/* RxQ structure - QPT, configuration */
+struct bna_rxq {
+ struct list_head qe;
+ int rxq_id;
+
+ int buffer_size;
+ int q_depth;
+
+ struct bna_qpt qpt;
+ struct bna_rcb *rcb;
+
+ struct bna_rxp *rxp;
+ struct bna_rx *rx;
+
+ u64 rx_packets;
+ u64 rx_bytes;
+ u64 rx_packets_with_error;
+ u64 rxbuf_alloc_failed;
+};
+
+/* RxQ pair */
+union bna_rxq_u {
+ struct {
+ struct bna_rxq *hdr;
+ struct bna_rxq *data;
+ } hds;
+ struct {
+ struct bna_rxq *small;
+ struct bna_rxq *large;
+ } slr;
+ struct {
+ struct bna_rxq *only;
+ struct bna_rxq *reserved;
+ } single;
+};
+
+/* Packet rate for Dynamic Interrupt Moderation */
+struct bna_pkt_rate {
+ u32 small_pkt_cnt;
+ u32 large_pkt_cnt;
+};
+
+/* Completion control structure */
+struct bna_ccb {
+ /* Fast path */
+ void **sw_qpt;
+ u32 producer_index;
+ volatile u32 *hw_producer_index;
+ u32 q_depth;
+ struct bna_ib_dbell *i_dbell;
+ struct bna_rcb *rcb[2];
+ void *ctrl; /* For bnad */
+ struct bna_pkt_rate pkt_rate;
+ int page_idx;
+ int page_count;
+
+ /* Control path */
+ struct bna_cq *cq;
+ struct bnad *bnad;
+ enum bna_intr_type intr_type;
+ int intr_vector;
+ u8 rx_coalescing_timeo; /* For NAPI */
+ int id;
+ char name[BNA_Q_NAME_SIZE];
+};
+
+/* 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_rx *rx;
+};
+
+struct bna_rss_config {
+ enum rss_hash_type hash_type;
+ u8 hash_mask;
+ u32 toeplitz_hash_key[BFI_RSS_HASH_KEY_LEN];
+};
+
+struct bna_hds_config {
+ enum hds_header_type hdr_type;
+ int header_size;
+};
+
+/* This structure is used during RX 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;
+ /*
+ * Small/Large (or Header/Data) buffer size to be configured
+ * for SLR and HDS queue type. Large buffer size comes from
+ * port->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;
+};
+
+/* Rx Path structure - one per MSIX vector/CPU */
+struct bna_rxp {
+ /* This should be the first one */
+ struct list_head qe;
+
+ enum bna_rxp_type type;
+ union bna_rxq_u rxq;
+ struct bna_cq cq;
+
+ struct bna_rx *rx;
+
+ /* 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];
+};
+
+/* 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;
+
+ /* callback for bna_rxf_start() */
+ void (*start_cbfn) (struct bna_rx *rx, enum bna_cb_status status);
+ struct bna_rx *start_cbarg;
+
+ /* callback for bna_rxf_stop() */
+ void (*stop_cbfn) (struct bna_rx *rx, enum bna_cb_status status);
+ 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);
+ struct bnad *oper_state_cbarg;
+
+ /**
+ * callback for:
+ * bna_rxf_ucast_set()
+ * bna_rxf_{ucast/mcast}_add(),
+ * 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);
+ 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;
+ int ucast_pending_set;
+ /* ucast addresses applied to the h/w */
+ struct list_head ucast_active_q;
+ struct bna_mac *ucast_active_mac;
+
+ /* 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;
+
+ /* Rx modes yet to be applied to h/w */
+ enum bna_rxmode rxmode_pending;
+ enum bna_rxmode rxmode_pending_bitmask;
+ /* Rx modes applied to h/w */
+ enum bna_rxmode rxmode_active;
+
+ enum bna_status vlan_filter_status;
+ u32 vlan_filter_table[(BFI_MAX_VLAN + 1) / 32];
+};
+
+/* Rx object */
+struct bna_rx {
+ /* This should be the first one */
+ struct list_head qe;
+
+ bfa_fsm_t fsm;
+
+ enum bna_rx_type type;
+
+ /* list-head for RX path objects */
+ struct list_head rxp_q;
+
+ struct bna_rxf rxf;
+
+ enum bna_rx_flags rx_flags;
+
+ struct bna_mbox_qe mbox_qe;
+
+ struct bfa_wc rxq_stop_wc;
+
+ /* 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 *);
+
+ /* callback for bna_rx_disable(), bna_rx_stop() */
+ void (*stop_cbfn)(void *arg, struct bna_rx *rx,
+ enum bna_cb_status status);
+ void *stop_cbarg;
+
+ struct bna *bna;
+ void *priv; /* bnad's cookie */
+};
+
+struct bna_rx_event_cbfn {
+ /* Optional */
+ 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 *);
+ /* Mandatory */
+ void (*rx_cleanup_cbfn)(struct bnad *, struct bna_ccb *);
+ void (*rx_post_cbfn)(struct bnad *, struct bna_rcb *);
+};
+
+/* Rx module - keeps track of free, active rx objects */
+struct bna_rx_mod {
+ struct bna *bna; /* back pointer to parent */
+ struct bna_rx *rx; /* BFI_MAX_RXQ entries */
+ struct bna_rxp *rxp; /* BFI_MAX_RXQ entries */
+ struct bna_rxq *rxq; /* BFI_MAX_RXQ entries */
+
+ struct list_head rx_free_q;
+ struct list_head rx_active_q;
+ int rx_free_count;
+
+ struct list_head rxp_free_q;
+ int rxp_free_count;
+
+ struct list_head rxq_free_q;
+ int rxq_free_count;
+
+ enum bna_rx_mod_flags flags;
+
+ /* callback for bna_rx_mod_stop() */
+ void (*stop_cbfn)(struct bna_port *port,
+ enum bna_cb_status status);
+
+ struct bfa_wc rx_stop_wc;
+ u32 dim_vector[BNA_LOAD_T_MAX][BNA_BIAS_T_MAX];
+ u32 rxf_bmap[2];
+};
+
+/**
+ *
+ * CAM
+ *
+ */
+
+struct bna_ucam_mod {
+ struct bna_mac *ucmac; /* BFI_MAX_UCMAC entries */
+ struct list_head free_q;
+
+ struct bna *bna;
+};
+
+struct bna_mcam_mod {
+ struct bna_mac *mcmac; /* BFI_MAX_MCMAC entries */
+ struct list_head free_q;
+
+ struct bna *bna;
+};
+
+/**
+ *
+ * Statistics
+ *
+ */
+
+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 {
+ u32 txf_bmap[2];
+ u32 rxf_bmap[2];
+ struct bfi_ll_stats *hw_stats;
+ struct bna_sw_stats *sw_stats;
+};
+
+/**
+ *
+ * BNA
+ *
+ */
+
+struct bna {
+ struct bfa_pcidev pcidev;
+
+ int port_num;
+
+ struct bna_chip_regs regs;
+
+ struct bna_dma_addr hw_stats_dma;
+ struct bna_stats stats;
+
+ struct bna_device device;
+ struct bfa_cee cee;
+
+ struct bna_mbox_mod mbox_mod;
+
+ struct bna_port port;
+
+ 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;
+
+ int rxf_default_id;
+ int rxf_promisc_id;
+
+ struct bna_mbox_qe mbox_qe;
+
+ struct bnad *bnad;
+};
+
+#endif /* __BNA_TYPES_H__ */
diff --git a/drivers/net/bna/bnad.c b/drivers/net/bna/bnad.c
new file mode 100644
index 000000000000..7e839b9cec22
--- /dev/null
+++ b/drivers/net/bna/bnad.c
@@ -0,0 +1,3264 @@
+/*
+ * 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 <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/in.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+
+#include "bnad.h"
+#include "bna.h"
+#include "cna.h"
+
+static DEFINE_MUTEX(bnad_fwimg_mutex);
+
+/*
+ * Module params
+ */
+static uint bnad_msix_disable;
+module_param(bnad_msix_disable, uint, 0444);
+MODULE_PARM_DESC(bnad_msix_disable, "Disable MSIX mode");
+
+static uint bnad_ioc_auto_recover = 1;
+module_param(bnad_ioc_auto_recover, uint, 0444);
+MODULE_PARM_DESC(bnad_ioc_auto_recover, "Enable / Disable auto recovery");
+
+/*
+ * Global variables
+ */
+u32 bnad_rxqs_per_cq = 2;
+
+static const u8 bnad_bcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+/*
+ * Local MACROS
+ */
+#define BNAD_TX_UNMAPQ_DEPTH (bnad->txq_depth * 2)
+
+#define BNAD_RX_UNMAPQ_DEPTH (bnad->rxq_depth)
+
+#define BNAD_GET_MBOX_IRQ(_bnad) \
+ (((_bnad)->cfg_flags & BNAD_CF_MSIX) ? \
+ ((_bnad)->msix_table[(_bnad)->msix_num - 1].vector) : \
+ ((_bnad)->pcidev->irq))
+
+#define BNAD_FILL_UNMAPQ_MEM_REQ(_res_info, _num, _depth) \
+do { \
+ (_res_info)->res_type = BNA_RES_T_MEM; \
+ (_res_info)->res_u.mem_info.mem_type = BNA_MEM_T_KVA; \
+ (_res_info)->res_u.mem_info.num = (_num); \
+ (_res_info)->res_u.mem_info.len = \
+ sizeof(struct bnad_unmap_q) + \
+ (sizeof(struct bnad_skb_unmap) * ((_depth) - 1)); \
+} while (0)
+
+/*
+ * Reinitialize completions in CQ, once Rx is taken down
+ */
+static void
+bnad_cq_cmpl_init(struct bnad *bnad, struct bna_ccb *ccb)
+{
+ struct bna_cq_entry *cmpl, *next_cmpl;
+ unsigned int wi_range, wis = 0, ccb_prod = 0;
+ int i;
+
+ BNA_CQ_QPGE_PTR_GET(ccb_prod, ccb->sw_qpt, cmpl,
+ wi_range);
+
+ for (i = 0; i < ccb->q_depth; i++) {
+ wis++;
+ if (likely(--wi_range))
+ next_cmpl = cmpl + 1;
+ else {
+ BNA_QE_INDX_ADD(ccb_prod, wis, ccb->q_depth);
+ wis = 0;
+ BNA_CQ_QPGE_PTR_GET(ccb_prod, ccb->sw_qpt,
+ next_cmpl, wi_range);
+ }
+ cmpl->valid = 0;
+ cmpl = next_cmpl;
+ }
+}
+
+/*
+ * Frees all pending Tx Bufs
+ * At this point no activity is expected on the Q,
+ * so DMA unmap & freeing is fine.
+ */
+static void
+bnad_free_all_txbufs(struct bnad *bnad,
+ struct bna_tcb *tcb)
+{
+ u16 unmap_cons;
+ struct bnad_unmap_q *unmap_q = tcb->unmap_q;
+ struct bnad_skb_unmap *unmap_array;
+ struct sk_buff *skb = NULL;
+ int i;
+
+ 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++;
+ continue;
+ }
+ unmap_array[unmap_cons].skb = NULL;
+
+ pci_unmap_single(bnad->pcidev,
+ pci_unmap_addr(&unmap_array[unmap_cons],
+ dma_addr), skb_headlen(skb),
+ PCI_DMA_TODEVICE);
+
+ pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, 0);
+ unmap_cons++;
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ pci_unmap_page(bnad->pcidev,
+ pci_unmap_addr(&unmap_array[unmap_cons],
+ dma_addr),
+ skb_shinfo(skb)->frags[i].size,
+ PCI_DMA_TODEVICE);
+ pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr,
+ 0);
+ unmap_cons++;
+ }
+ dev_kfree_skb_any(skb);
+ }
+}
+
+/* Data Path Handlers */
+
+/*
+ * bnad_free_txbufs : Frees the Tx bufs on Tx completion
+ * Can be called in a) Interrupt context
+ * b) Sending context
+ * c) Tasklet context
+ */
+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;
+ 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
+ * when bnad_free_txbufs() runs out of a tasklet scheduled
+ * before bnad_cb_tx_cleanup() cleared BNAD_RF_TX_STARTED bit
+ * but this routine runs actually after the cleanup has been
+ * executed.
+ */
+ if (!test_bit(BNAD_RF_TX_STARTED, &bnad->run_flags))
+ return 0;
+
+ updated_hw_cons = *(tcb->hw_consumer_index);
+
+ wis = BNA_Q_INDEX_CHANGE(tcb->consumer_index,
+ updated_hw_cons, tcb->q_depth);
+
+ BUG_ON(!(wis <= BNA_QE_IN_USE_CNT(tcb, tcb->q_depth)));
+
+ unmap_array = unmap_q->unmap_array;
+ unmap_cons = unmap_q->consumer_index;
+
+ prefetch(&unmap_array[unmap_cons + 1]);
+ 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);
+
+ pci_unmap_single(bnad->pcidev,
+ pci_unmap_addr(&unmap_array[unmap_cons],
+ dma_addr), skb_headlen(skb),
+ PCI_DMA_TODEVICE);
+ pci_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]);
+
+ pci_unmap_page(bnad->pcidev,
+ pci_unmap_addr(&unmap_array[unmap_cons],
+ dma_addr),
+ skb_shinfo(skb)->frags[i].size,
+ PCI_DMA_TODEVICE);
+ pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr,
+ 0);
+ BNA_QE_INDX_ADD(unmap_cons, 1, unmap_q->q_depth);
+ }
+ dev_kfree_skb_any(skb);
+ }
+
+ /* Update consumer pointers. */
+ tcb->consumer_index = updated_hw_cons;
+ unmap_q->consumer_index = unmap_cons;
+
+ tcb->txq->tx_packets += sent_packets;
+ tcb->txq->tx_bytes += sent_bytes;
+
+ return sent_packets;
+}
+
+/* Tx Free Tasklet function */
+/* Frees for all the tcb's in all the Tx's */
+/*
+ * Scheduled from sending context, so that
+ * the fat Tx lock is not held for too long
+ * in the sending context.
+ */
+static void
+bnad_tx_free_tasklet(unsigned long bnad_ptr)
+{
+ struct bnad *bnad = (struct bnad *)bnad_ptr;
+ struct bna_tcb *tcb;
+ u32 acked;
+ int i, j;
+
+ for (i = 0; i < bnad->num_tx; i++) {
+ for (j = 0; j < bnad->num_txq_per_tx; j++) {
+ tcb = bnad->tx_info[i].tcb[j];
+ if (!tcb)
+ continue;
+ if (((u16) (*tcb->hw_consumer_index) !=
+ tcb->consumer_index) &&
+ (!test_and_set_bit(BNAD_TXQ_FREE_SENT,
+ &tcb->flags))) {
+ acked = bnad_free_txbufs(bnad, tcb);
+ bna_ib_ack(tcb->i_dbell, acked);
+ smp_mb__before_clear_bit();
+ clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
+ }
+ }
+ }
+}
+
+static u32
+bnad_tx(struct bnad *bnad, struct bna_tcb *tcb)
+{
+ struct net_device *netdev = bnad->netdev;
+ u32 sent;
+
+ if (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
+ return 0;
+
+ sent = bnad_free_txbufs(bnad, tcb);
+ if (sent) {
+ if (netif_queue_stopped(netdev) &&
+ netif_carrier_ok(netdev) &&
+ BNA_QE_FREE_CNT(tcb, tcb->q_depth) >=
+ BNAD_NETIF_WAKE_THRESHOLD) {
+ netif_wake_queue(netdev);
+ BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
+ }
+ bna_ib_ack(tcb->i_dbell, sent);
+ } else
+ bna_ib_ack(tcb->i_dbell, 0);
+
+ smp_mb__before_clear_bit();
+ clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
+
+ return sent;
+}
+
+/* MSIX Tx Completion Handler */
+static irqreturn_t
+bnad_msix_tx(int irq, void *data)
+{
+ struct bna_tcb *tcb = (struct bna_tcb *)data;
+ struct bnad *bnad = tcb->bnad;
+
+ bnad_tx(bnad, tcb);
+
+ return IRQ_HANDLED;
+}
+
+static void
+bnad_reset_rcb(struct bnad *bnad, struct bna_rcb *rcb)
+{
+ struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+
+ rcb->producer_index = 0;
+ rcb->consumer_index = 0;
+
+ unmap_q->producer_index = 0;
+ unmap_q->consumer_index = 0;
+}
+
+static void
+bnad_free_rxbufs(struct bnad *bnad, struct bna_rcb *rcb)
+{
+ struct bnad_unmap_q *unmap_q;
+ struct sk_buff *skb;
+
+ unmap_q = rcb->unmap_q;
+ while (BNA_QE_IN_USE_CNT(unmap_q, unmap_q->q_depth)) {
+ skb = unmap_q->unmap_array[unmap_q->consumer_index].skb;
+ BUG_ON(!(skb));
+ unmap_q->unmap_array[unmap_q->consumer_index].skb = NULL;
+ pci_unmap_single(bnad->pcidev, pci_unmap_addr(&unmap_q->
+ unmap_array[unmap_q->consumer_index],
+ dma_addr), rcb->rxq->buffer_size +
+ NET_IP_ALIGN, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(skb);
+ BNA_QE_INDX_ADD(unmap_q->consumer_index, 1, unmap_q->q_depth);
+ BNA_QE_INDX_ADD(rcb->consumer_index, 1, rcb->q_depth);
+ }
+
+ bnad_reset_rcb(bnad, rcb);
+}
+
+static void
+bnad_alloc_n_post_rxbufs(struct bnad *bnad, struct bna_rcb *rcb)
+{
+ u16 to_alloc, alloced, unmap_prod, wi_range;
+ struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+ struct bnad_skb_unmap *unmap_array;
+ struct bna_rxq_entry *rxent;
+ struct sk_buff *skb;
+ dma_addr_t dma_addr;
+
+ alloced = 0;
+ to_alloc =
+ BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth);
+
+ unmap_array = unmap_q->unmap_array;
+ unmap_prod = unmap_q->producer_index;
+
+ BNA_RXQ_QPGE_PTR_GET(unmap_prod, rcb->sw_qpt, rxent, wi_range);
+
+ while (to_alloc--) {
+ if (!wi_range) {
+ BNA_RXQ_QPGE_PTR_GET(unmap_prod, rcb->sw_qpt, rxent,
+ wi_range);
+ }
+ skb = alloc_skb(rcb->rxq->buffer_size + NET_IP_ALIGN,
+ GFP_ATOMIC);
+ if (unlikely(!skb)) {
+ BNAD_UPDATE_CTR(bnad, rxbuf_alloc_failed);
+ goto finishing;
+ }
+ skb->dev = bnad->netdev;
+ skb_reserve(skb, NET_IP_ALIGN);
+ unmap_array[unmap_prod].skb = skb;
+ dma_addr = pci_map_single(bnad->pcidev, skb->data,
+ rcb->rxq->buffer_size, PCI_DMA_FROMDEVICE);
+ pci_unmap_addr_set(&unmap_array[unmap_prod], dma_addr,
+ dma_addr);
+ BNA_SET_DMA_ADDR(dma_addr, &rxent->host_addr);
+ BNA_QE_INDX_ADD(unmap_prod, 1, unmap_q->q_depth);
+
+ rxent++;
+ wi_range--;
+ alloced++;
+ }
+
+finishing:
+ if (likely(alloced)) {
+ unmap_q->producer_index = unmap_prod;
+ rcb->producer_index = unmap_prod;
+ smp_mb();
+ bna_rxq_prod_indx_doorbell(rcb);
+ }
+}
+
+/*
+ * Locking is required in the enable path
+ * because it is called from a napi poll
+ * context, where the bna_lock is not held
+ * unlike the IRQ context.
+ */
+static void
+bnad_enable_txrx_irqs(struct bnad *bnad)
+{
+ struct bna_tcb *tcb;
+ struct bna_ccb *ccb;
+ int i, j;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ for (i = 0; i < bnad->num_tx; i++) {
+ for (j = 0; j < bnad->num_txq_per_tx; j++) {
+ tcb = bnad->tx_info[i].tcb[j];
+ bna_ib_coalescing_timer_set(tcb->i_dbell,
+ tcb->txq->ib->ib_config.coalescing_timeo);
+ bna_ib_ack(tcb->i_dbell, 0);
+ }
+ }
+
+ for (i = 0; i < bnad->num_rx; i++) {
+ for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+ ccb = bnad->rx_info[i].rx_ctrl[j].ccb;
+ bnad_enable_rx_irq_unsafe(ccb);
+ }
+ }
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+static inline void
+bnad_refill_rxq(struct bnad *bnad, struct bna_rcb *rcb)
+{
+ struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+
+ 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 u32
+bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget)
+{
+ struct bna_cq_entry *cmpl, *next_cmpl;
+ struct bna_rcb *rcb = NULL;
+ unsigned int wi_range, packets = 0, wis = 0;
+ struct bnad_unmap_q *unmap_q;
+ struct sk_buff *skb;
+ u32 flags;
+ u32 qid0 = ccb->rcb[0]->rxq->rxq_id;
+ struct bna_pkt_rate *pkt_rt = &ccb->pkt_rate;
+
+ prefetch(bnad->netdev);
+ BNA_CQ_QPGE_PTR_GET(ccb->producer_index, ccb->sw_qpt, cmpl,
+ wi_range);
+ BUG_ON(!(wi_range <= ccb->q_depth));
+ while (cmpl->valid && packets < budget) {
+ packets++;
+ BNA_UPDATE_PKT_CNT(pkt_rt, ntohs(cmpl->length));
+
+ if (qid0 == cmpl->rxq_id)
+ rcb = ccb->rcb[0];
+ else
+ rcb = ccb->rcb[1];
+
+ unmap_q = rcb->unmap_q;
+
+ skb = unmap_q->unmap_array[unmap_q->consumer_index].skb;
+ BUG_ON(!(skb));
+ unmap_q->unmap_array[unmap_q->consumer_index].skb = NULL;
+ pci_unmap_single(bnad->pcidev,
+ pci_unmap_addr(&unmap_q->
+ unmap_array[unmap_q->
+ consumer_index],
+ dma_addr),
+ rcb->rxq->buffer_size,
+ PCI_DMA_FROMDEVICE);
+ BNA_QE_INDX_ADD(unmap_q->consumer_index, 1, unmap_q->q_depth);
+
+ /* Should be more efficient ? Performance ? */
+ BNA_QE_INDX_ADD(rcb->consumer_index, 1, rcb->q_depth);
+
+ wis++;
+ if (likely(--wi_range))
+ next_cmpl = cmpl + 1;
+ else {
+ BNA_QE_INDX_ADD(ccb->producer_index, wis, ccb->q_depth);
+ wis = 0;
+ BNA_CQ_QPGE_PTR_GET(ccb->producer_index, ccb->sw_qpt,
+ next_cmpl, wi_range);
+ BUG_ON(!(wi_range <= ccb->q_depth));
+ }
+ prefetch(next_cmpl);
+
+ flags = ntohl(cmpl->flags);
+ if (unlikely
+ (flags &
+ (BNA_CQ_EF_MAC_ERROR | BNA_CQ_EF_FCS_ERROR |
+ BNA_CQ_EF_TOO_LONG))) {
+ dev_kfree_skb_any(skb);
+ rcb->rxq->rx_packets_with_error++;
+ goto next;
+ }
+
+ skb_put(skb, ntohs(cmpl->length));
+ if (likely
+ (bnad->rx_csum &&
+ (((flags & BNA_CQ_EF_IPV4) &&
+ (flags & BNA_CQ_EF_L3_CKSUM_OK)) ||
+ (flags & BNA_CQ_EF_IPV6)) &&
+ (flags & (BNA_CQ_EF_TCP | BNA_CQ_EF_UDP)) &&
+ (flags & BNA_CQ_EF_L4_CKSUM_OK)))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb_checksum_none_assert(skb);
+
+ rcb->rxq->rx_packets++;
+ rcb->rxq->rx_bytes += skb->len;
+ skb->protocol = eth_type_trans(skb, bnad->netdev);
+
+ if (bnad->vlan_grp && (flags & BNA_CQ_EF_VLAN)) {
+ struct bnad_rx_ctrl *rx_ctrl =
+ (struct bnad_rx_ctrl *)ccb->ctrl;
+ if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+ vlan_gro_receive(&rx_ctrl->napi, bnad->vlan_grp,
+ ntohs(cmpl->vlan_tag), skb);
+ else
+ vlan_hwaccel_receive_skb(skb,
+ bnad->vlan_grp,
+ ntohs(cmpl->vlan_tag));
+
+ } else { /* Not VLAN tagged/stripped */
+ struct bnad_rx_ctrl *rx_ctrl =
+ (struct bnad_rx_ctrl *)ccb->ctrl;
+ if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+ napi_gro_receive(&rx_ctrl->napi, skb);
+ else
+ netif_receive_skb(skb);
+ }
+
+next:
+ cmpl->valid = 0;
+ cmpl = next_cmpl;
+ }
+
+ BNA_QE_INDX_ADD(ccb->producer_index, wis, ccb->q_depth);
+
+ if (likely(ccb)) {
+ 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
+ bna_ib_ack(ccb->i_dbell, 0);
+
+ return packets;
+}
+
+static void
+bnad_disable_rx_irq(struct bnad *bnad, struct bna_ccb *ccb)
+{
+ bna_ib_coalescing_timer_set(ccb->i_dbell, 0);
+ bna_ib_ack(ccb->i_dbell, 0);
+}
+
+static void
+bnad_enable_rx_irq(struct bnad *bnad, struct bna_ccb *ccb)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags); /* Because of polling context */
+ bnad_enable_rx_irq_unsafe(ccb);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+static void
+bnad_netif_rx_schedule_poll(struct bnad *bnad, struct bna_ccb *ccb)
+{
+ struct bnad_rx_ctrl *rx_ctrl = (struct bnad_rx_ctrl *)(ccb->ctrl);
+ if (likely(napi_schedule_prep((&rx_ctrl->napi)))) {
+ bnad_disable_rx_irq(bnad, ccb);
+ __napi_schedule((&rx_ctrl->napi));
+ }
+ BNAD_UPDATE_CTR(bnad, netif_rx_schedule);
+}
+
+/* MSIX Rx Path Handler */
+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);
+
+ return IRQ_HANDLED;
+}
+
+/* Interrupt handlers */
+
+/* Mbox Interrupt Handlers */
+static irqreturn_t
+bnad_msix_mbox_handler(int irq, void *data)
+{
+ u32 intr_status;
+ unsigned long flags;
+ struct net_device *netdev = data;
+ struct bnad *bnad;
+
+ bnad = netdev_priv(netdev);
+
+ /* BNA_ISR_GET(bnad); Inc Ref count */
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+
+ bna_intr_status_get(&bnad->bna, intr_status);
+
+ if (BNA_IS_MBOX_ERR_INTR(intr_status))
+ bna_mbox_handler(&bnad->bna, intr_status);
+
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ /* BNAD_ISR_PUT(bnad); Dec Ref count */
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+bnad_isr(int irq, void *data)
+{
+ int i, j;
+ u32 intr_status;
+ unsigned long flags;
+ struct net_device *netdev = data;
+ struct bnad *bnad = netdev_priv(netdev);
+ struct bnad_rx_info *rx_info;
+ struct bnad_rx_ctrl *rx_ctrl;
+
+ if (unlikely(test_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags)))
+ return IRQ_NONE;
+
+ bna_intr_status_get(&bnad->bna, intr_status);
+
+ if (unlikely(!intr_status))
+ return IRQ_NONE;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+
+ if (BNA_IS_MBOX_ERR_INTR(intr_status)) {
+ bna_mbox_handler(&bnad->bna, intr_status);
+ if (!BNA_IS_INTX_DATA_INTR(intr_status)) {
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ goto done;
+ }
+ }
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ /* Process data interrupts */
+ 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_netif_rx_schedule_poll(bnad,
+ rx_ctrl->ccb);
+ }
+ }
+done:
+ return IRQ_HANDLED;
+}
+
+/*
+ * Called in interrupt / callback context
+ * with bna_lock held, so cfg_flags access is OK
+ */
+static void
+bnad_enable_mbox_irq(struct bnad *bnad)
+{
+ int irq = BNAD_GET_MBOX_IRQ(bnad);
+
+ if (test_and_clear_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags))
+ if (bnad->cfg_flags & BNAD_CF_MSIX)
+ enable_irq(irq);
+
+ BNAD_UPDATE_CTR(bnad, mbox_intr_enabled);
+}
+
+/*
+ * Called with bnad->bna_lock held b'cos of
+ * bnad->cfg_flags access.
+ */
+static void
+bnad_disable_mbox_irq(struct bnad *bnad)
+{
+ int irq = BNAD_GET_MBOX_IRQ(bnad);
+
+
+ if (!test_and_set_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags))
+ if (bnad->cfg_flags & BNAD_CF_MSIX)
+ disable_irq_nosync(irq);
+
+ BNAD_UPDATE_CTR(bnad, mbox_intr_disabled);
+}
+
+/* Control Path Handlers */
+
+/* Callbacks */
+void
+bnad_cb_device_enable_mbox_intr(struct bnad *bnad)
+{
+ bnad_enable_mbox_irq(bnad);
+}
+
+void
+bnad_cb_device_disable_mbox_intr(struct bnad *bnad)
+{
+ bnad_disable_mbox_irq(bnad);
+}
+
+void
+bnad_cb_device_enabled(struct bnad *bnad, enum bna_cb_status status)
+{
+ 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)
+{
+ 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)
+{
+ struct bnad *bnad = (struct bnad *)arg;
+
+ complete(&bnad->bnad_completions.port_comp);
+
+ netif_carrier_off(bnad->netdev);
+}
+
+void
+bnad_cb_port_link_status(struct bnad *bnad,
+ enum bna_link_status link_status)
+{
+ bool link_up = 0;
+
+ link_up = (link_status == BNA_LINK_UP) || (link_status == BNA_CEE_UP);
+
+ if (link_status == BNA_CEE_UP) {
+ set_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags);
+ BNAD_UPDATE_CTR(bnad, cee_up);
+ } else
+ clear_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags);
+
+ if (link_up) {
+ if (!netif_carrier_ok(bnad->netdev)) {
+ pr_warn("bna: %s link up\n",
+ bnad->netdev->name);
+ netif_carrier_on(bnad->netdev);
+ BNAD_UPDATE_CTR(bnad, link_toggle);
+ if (test_bit(BNAD_RF_TX_STARTED, &bnad->run_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);
+ }
+ }
+ } else {
+ if (netif_carrier_ok(bnad->netdev)) {
+ pr_warn("bna: %s link down\n",
+ bnad->netdev->name);
+ netif_carrier_off(bnad->netdev);
+ BNAD_UPDATE_CTR(bnad, link_toggle);
+ }
+ }
+}
+
+static void
+bnad_cb_tx_disabled(void *arg, struct bna_tx *tx,
+ enum bna_cb_status status)
+{
+ struct bnad *bnad = (struct bnad *)arg;
+
+ complete(&bnad->bnad_completions.tx_comp);
+}
+
+static void
+bnad_cb_tcb_setup(struct bnad *bnad, struct bna_tcb *tcb)
+{
+ struct bnad_tx_info *tx_info =
+ (struct bnad_tx_info *)tcb->txq->tx->priv;
+ struct bnad_unmap_q *unmap_q = tcb->unmap_q;
+
+ tx_info->tcb[tcb->id] = tcb;
+ unmap_q->producer_index = 0;
+ unmap_q->consumer_index = 0;
+ unmap_q->q_depth = BNAD_TX_UNMAPQ_DEPTH;
+}
+
+static void
+bnad_cb_tcb_destroy(struct bnad *bnad, struct bna_tcb *tcb)
+{
+ struct bnad_tx_info *tx_info =
+ (struct bnad_tx_info *)tcb->txq->tx->priv;
+
+ tx_info->tcb[tcb->id] = NULL;
+}
+
+static void
+bnad_cb_rcb_setup(struct bnad *bnad, struct bna_rcb *rcb)
+{
+ struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+
+ unmap_q->producer_index = 0;
+ unmap_q->consumer_index = 0;
+ unmap_q->q_depth = BNAD_RX_UNMAPQ_DEPTH;
+}
+
+static void
+bnad_cb_ccb_setup(struct bnad *bnad, struct bna_ccb *ccb)
+{
+ struct bnad_rx_info *rx_info =
+ (struct bnad_rx_info *)ccb->cq->rx->priv;
+
+ rx_info->rx_ctrl[ccb->id].ccb = ccb;
+ ccb->ctrl = &rx_info->rx_ctrl[ccb->id];
+}
+
+static void
+bnad_cb_ccb_destroy(struct bnad *bnad, struct bna_ccb *ccb)
+{
+ struct bnad_rx_info *rx_info =
+ (struct bnad_rx_info *)ccb->cq->rx->priv;
+
+ rx_info->rx_ctrl[ccb->id].ccb = NULL;
+}
+
+static void
+bnad_cb_tx_stall(struct bnad *bnad, struct bna_tcb *tcb)
+{
+ struct bnad_tx_info *tx_info =
+ (struct bnad_tx_info *)tcb->txq->tx->priv;
+
+ if (tx_info != &bnad->tx_info[0])
+ return;
+
+ clear_bit(BNAD_RF_TX_STARTED, &bnad->run_flags);
+ netif_stop_queue(bnad->netdev);
+ pr_info("bna: %s TX_STOPPED\n", bnad->netdev->name);
+}
+
+static void
+bnad_cb_tx_resume(struct bnad *bnad, struct bna_tcb *tcb)
+{
+ if (test_and_set_bit(BNAD_RF_TX_STARTED, &bnad->run_flags))
+ return;
+
+ 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);
+ }
+}
+
+static void
+bnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tcb *tcb)
+{
+ struct bnad_unmap_q *unmap_q;
+
+ if (!tcb || (!tcb->unmap_q))
+ return;
+
+ unmap_q = tcb->unmap_q;
+ if (!unmap_q->unmap_array)
+ return;
+
+ if (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
+ return;
+
+ bnad_free_all_txbufs(bnad, tcb);
+
+ unmap_q->producer_index = 0;
+ unmap_q->consumer_index = 0;
+
+ smp_mb__before_clear_bit();
+ clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
+}
+
+static void
+bnad_cb_rx_cleanup(struct bnad *bnad,
+ struct bna_ccb *ccb)
+{
+ bnad_cq_cmpl_init(bnad, ccb);
+
+ bnad_free_rxbufs(bnad, ccb->rcb[0]);
+ clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags);
+
+ if (ccb->rcb[1]) {
+ bnad_free_rxbufs(bnad, ccb->rcb[1]);
+ clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[1]->flags);
+ }
+}
+
+static void
+bnad_cb_rx_post(struct bnad *bnad, struct bna_rcb *rcb)
+{
+ struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+
+ set_bit(BNAD_RXQ_STARTED, &rcb->flags);
+
+ /* 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)
+{
+ struct bnad *bnad = (struct bnad *)arg;
+
+ complete(&bnad->bnad_completions.rx_comp);
+}
+
+static void
+bnad_cb_rx_mcast_add(struct bnad *bnad, struct bna_rx *rx,
+ enum bna_cb_status status)
+{
+ bnad->bnad_completions.mcast_comp_status = status;
+ complete(&bnad->bnad_completions.mcast_comp);
+}
+
+void
+bnad_cb_stats_get(struct bnad *bnad, enum bna_cb_status status,
+ struct bna_stats *stats)
+{
+ if (status == BNA_CB_SUCCESS)
+ BNAD_UPDATE_CTR(bnad, hw_stats_updates);
+
+ if (!netif_running(bnad->netdev) ||
+ !test_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags))
+ return;
+
+ mod_timer(&bnad->stats_timer,
+ jiffies + msecs_to_jiffies(BNAD_STATS_TIMER_FREQ));
+}
+
+/* Resource allocation, free functions */
+
+static void
+bnad_mem_free(struct bnad *bnad,
+ struct bna_mem_info *mem_info)
+{
+ int i;
+ dma_addr_t dma_pa;
+
+ if (mem_info->mdl == NULL)
+ return;
+
+ for (i = 0; i < mem_info->num; i++) {
+ if (mem_info->mdl[i].kva != NULL) {
+ if (mem_info->mem_type == BNA_MEM_T_DMA) {
+ BNA_GET_DMA_ADDR(&(mem_info->mdl[i].dma),
+ dma_pa);
+ pci_free_consistent(bnad->pcidev,
+ mem_info->mdl[i].len,
+ mem_info->mdl[i].kva, dma_pa);
+ } else
+ kfree(mem_info->mdl[i].kva);
+ }
+ }
+ kfree(mem_info->mdl);
+ mem_info->mdl = NULL;
+}
+
+static int
+bnad_mem_alloc(struct bnad *bnad,
+ struct bna_mem_info *mem_info)
+{
+ int i;
+ dma_addr_t dma_pa;
+
+ if ((mem_info->num == 0) || (mem_info->len == 0)) {
+ mem_info->mdl = NULL;
+ return 0;
+ }
+
+ mem_info->mdl = kcalloc(mem_info->num, sizeof(struct bna_mem_descr),
+ GFP_KERNEL);
+ if (mem_info->mdl == NULL)
+ return -ENOMEM;
+
+ if (mem_info->mem_type == BNA_MEM_T_DMA) {
+ for (i = 0; i < mem_info->num; i++) {
+ mem_info->mdl[i].len = mem_info->len;
+ mem_info->mdl[i].kva =
+ pci_alloc_consistent(bnad->pcidev,
+ mem_info->len, &dma_pa);
+
+ if (mem_info->mdl[i].kva == NULL)
+ goto err_return;
+
+ BNA_SET_DMA_ADDR(dma_pa,
+ &(mem_info->mdl[i].dma));
+ }
+ } else {
+ for (i = 0; i < mem_info->num; i++) {
+ mem_info->mdl[i].len = mem_info->len;
+ mem_info->mdl[i].kva = kzalloc(mem_info->len,
+ GFP_KERNEL);
+ if (mem_info->mdl[i].kva == NULL)
+ goto err_return;
+ }
+ }
+
+ return 0;
+
+err_return:
+ bnad_mem_free(bnad, mem_info);
+ return -ENOMEM;
+}
+
+/* Free IRQ for Mailbox */
+static void
+bnad_mbox_irq_free(struct bnad *bnad,
+ struct bna_intr_info *intr_info)
+{
+ 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->netdev);
+
+ kfree(intr_info->idl);
+}
+
+/*
+ * Allocates IRQ for Mailbox, but keep it disabled
+ * This will be enabled once we get the mbox enable callback
+ * from bna
+ */
+static int
+bnad_mbox_irq_alloc(struct bnad *bnad,
+ struct bna_intr_info *intr_info)
+{
+ int err;
+ unsigned long 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->msix_num - 1].vector;
+ flags = 0;
+ intr_info->intr_type = BNA_INTR_T_MSIX;
+ intr_info->idl[0].vector = bnad->msix_num - 1;
+ } else {
+ irq_handler = (irq_handler_t)bnad_isr;
+ irq = bnad->pcidev->irq;
+ flags = IRQF_SHARED;
+ intr_info->intr_type = BNA_INTR_T_INTX;
+ /* intr_info->idl.vector = 0 ? */
+ }
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ sprintf(bnad->mbox_irq_name, "%s", BNAD_NAME);
+
+ /*
+ * Set the Mbox IRQ disable flag, so that the IRQ handler
+ * called from request_irq() for SHARED IRQs do not execute
+ */
+ set_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags);
+
+ err = request_irq(irq, irq_handler, flags,
+ bnad->mbox_irq_name, bnad->netdev);
+
+ if (err) {
+ kfree(intr_info->idl);
+ intr_info->idl = NULL;
+ return err;
+ }
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+
+ if (bnad->cfg_flags & BNAD_CF_MSIX)
+ disable_irq_nosync(irq);
+
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ return 0;
+}
+
+static void
+bnad_txrx_irq_free(struct bnad *bnad, struct bna_intr_info *intr_info)
+{
+ kfree(intr_info->idl);
+ intr_info->idl = NULL;
+}
+
+/* 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)
+{
+ int i, vector_start = 0;
+ u32 cfg_flags;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ cfg_flags = bnad->cfg_flags;
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ if (cfg_flags & BNAD_CF_MSIX) {
+ intr_info->intr_type = BNA_INTR_T_MSIX;
+ intr_info->idl = kcalloc(intr_info->num,
+ sizeof(struct bna_intr_descr),
+ GFP_KERNEL);
+ if (!intr_info->idl)
+ return -ENOMEM;
+
+ switch (src) {
+ case BNAD_INTR_TX:
+ vector_start = txrx_id;
+ break;
+
+ case BNAD_INTR_RX:
+ vector_start = bnad->num_tx * bnad->num_txq_per_tx +
+ txrx_id;
+ break;
+
+ default:
+ BUG();
+ }
+
+ for (i = 0; i < intr_info->num; i++)
+ intr_info->idl[i].vector = vector_start + i;
+ } else {
+ intr_info->intr_type = BNA_INTR_T_INTX;
+ intr_info->num = 1;
+ intr_info->idl = kcalloc(intr_info->num,
+ sizeof(struct bna_intr_descr),
+ GFP_KERNEL);
+ if (!intr_info->idl)
+ return -ENOMEM;
+
+ switch (src) {
+ case BNAD_INTR_TX:
+ intr_info->idl[0].vector = 0x1; /* Bit mask : Tx IB */
+ break;
+
+ case BNAD_INTR_RX:
+ intr_info->idl[0].vector = 0x2; /* Bit mask : Rx IB */
+ break;
+ }
+ }
+ return 0;
+}
+
+/**
+ * NOTE: Should be called for MSIX only
+ * Unregisters Tx MSIX vector(s) from the kernel
+ */
+static void
+bnad_tx_msix_unregister(struct bnad *bnad, struct bnad_tx_info *tx_info,
+ int num_txqs)
+{
+ int i;
+ int vector_num;
+
+ for (i = 0; i < num_txqs; i++) {
+ if (tx_info->tcb[i] == NULL)
+ continue;
+
+ vector_num = tx_info->tcb[i]->intr_vector;
+ free_irq(bnad->msix_table[vector_num].vector, tx_info->tcb[i]);
+ }
+}
+
+/**
+ * NOTE: Should be called for MSIX only
+ * Registers Tx MSIX vector(s) and ISR(s), cookie with the kernel
+ */
+static int
+bnad_tx_msix_register(struct bnad *bnad, struct bnad_tx_info *tx_info,
+ uint tx_id, int num_txqs)
+{
+ int i;
+ int err;
+ int vector_num;
+
+ for (i = 0; i < num_txqs; i++) {
+ vector_num = tx_info->tcb[i]->intr_vector;
+ sprintf(tx_info->tcb[i]->name, "%s TXQ %d", bnad->netdev->name,
+ tx_id + tx_info->tcb[i]->id);
+ err = request_irq(bnad->msix_table[vector_num].vector,
+ (irq_handler_t)bnad_msix_tx, 0,
+ tx_info->tcb[i]->name,
+ tx_info->tcb[i]);
+ if (err)
+ goto err_return;
+ }
+
+ return 0;
+
+err_return:
+ if (i > 0)
+ bnad_tx_msix_unregister(bnad, tx_info, (i - 1));
+ return -1;
+}
+
+/**
+ * NOTE: Should be called for MSIX only
+ * Unregisters Rx MSIX vector(s) from the kernel
+ */
+static void
+bnad_rx_msix_unregister(struct bnad *bnad, struct bnad_rx_info *rx_info,
+ int num_rxps)
+{
+ int i;
+ int vector_num;
+
+ for (i = 0; i < num_rxps; i++) {
+ if (rx_info->rx_ctrl[i].ccb == NULL)
+ continue;
+
+ vector_num = rx_info->rx_ctrl[i].ccb->intr_vector;
+ free_irq(bnad->msix_table[vector_num].vector,
+ rx_info->rx_ctrl[i].ccb);
+ }
+}
+
+/**
+ * NOTE: Should be called for MSIX only
+ * Registers Tx MSIX vector(s) and ISR(s), cookie with the kernel
+ */
+static int
+bnad_rx_msix_register(struct bnad *bnad, struct bnad_rx_info *rx_info,
+ uint rx_id, int num_rxps)
+{
+ int i;
+ int err;
+ int vector_num;
+
+ for (i = 0; i < num_rxps; i++) {
+ vector_num = rx_info->rx_ctrl[i].ccb->intr_vector;
+ sprintf(rx_info->rx_ctrl[i].ccb->name, "%s CQ %d",
+ bnad->netdev->name,
+ rx_id + rx_info->rx_ctrl[i].ccb->id);
+ err = request_irq(bnad->msix_table[vector_num].vector,
+ (irq_handler_t)bnad_msix_rx, 0,
+ rx_info->rx_ctrl[i].ccb->name,
+ rx_info->rx_ctrl[i].ccb);
+ if (err)
+ goto err_return;
+ }
+
+ return 0;
+
+err_return:
+ if (i > 0)
+ bnad_rx_msix_unregister(bnad, rx_info, (i - 1));
+ return -1;
+}
+
+/* Free Tx object Resources */
+static void
+bnad_tx_res_free(struct bnad *bnad, struct bna_res_info *res_info)
+{
+ int i;
+
+ for (i = 0; i < BNA_TX_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 if (res_info[i].res_type == BNA_RES_T_INTR)
+ bnad_txrx_irq_free(bnad, &res_info[i].res_u.intr_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)
+{
+ int i, err = 0;
+
+ for (i = 0; i < BNA_TX_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 if (res_info[i].res_type == BNA_RES_T_INTR)
+ err = bnad_txrx_irq_alloc(bnad, BNAD_INTR_TX, tx_id,
+ &res_info[i].res_u.intr_info);
+ if (err)
+ goto err_return;
+ }
+ return 0;
+
+err_return:
+ bnad_tx_res_free(bnad, res_info);
+ return err;
+}
+
+/* Free Rx object Resources */
+static void
+bnad_rx_res_free(struct bnad *bnad, struct bna_res_info *res_info)
+{
+ int i;
+
+ for (i = 0; i < BNA_RX_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 if (res_info[i].res_type == BNA_RES_T_INTR)
+ bnad_txrx_irq_free(bnad, &res_info[i].res_u.intr_info);
+ }
+}
+
+/* Allocates memory and interrupt resources for Rx object */
+static int
+bnad_rx_res_alloc(struct bnad *bnad, struct bna_res_info *res_info,
+ uint rx_id)
+{
+ int i, err = 0;
+
+ /* All memory needs to be allocated before setup_ccbs */
+ for (i = 0; i < BNA_RX_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 if (res_info[i].res_type == BNA_RES_T_INTR)
+ err = bnad_txrx_irq_alloc(bnad, BNAD_INTR_RX, rx_id,
+ &res_info[i].res_u.intr_info);
+ if (err)
+ goto err_return;
+ }
+ return 0;
+
+err_return:
+ bnad_rx_res_free(bnad, res_info);
+ return err;
+}
+
+/* Timer callbacks */
+/* a) IOC timer */
+static void
+bnad_ioc_timeout(unsigned long data)
+{
+ struct bnad *bnad = (struct bnad *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bfa_nw_ioc_timeout((void *) &bnad->bna.device.ioc);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+static void
+bnad_ioc_hb_check(unsigned long data)
+{
+ struct bnad *bnad = (struct bnad *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bfa_nw_ioc_hb_check((void *) &bnad->bna.device.ioc);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+static void
+bnad_ioc_sem_timeout(unsigned long data)
+{
+ struct bnad *bnad = (struct bnad *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bfa_nw_ioc_sem_timeout((void *) &bnad->bna.device.ioc);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+/*
+ * All timer routines use bnad->bna_lock to protect against
+ * the following race, which may occur in case of no locking:
+ * Time CPU m CPU n
+ * 0 1 = test_bit
+ * 1 clear_bit
+ * 2 del_timer_sync
+ * 3 mod_timer
+ */
+
+/* b) Dynamic Interrupt Moderation Timer */
+static void
+bnad_dim_timeout(unsigned long data)
+{
+ struct bnad *bnad = (struct bnad *)data;
+ struct bnad_rx_info *rx_info;
+ struct bnad_rx_ctrl *rx_ctrl;
+ int i, j;
+ unsigned long flags;
+
+ if (!netif_carrier_ok(bnad->netdev))
+ return;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ 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)
+ continue;
+ bna_rx_dim_update(rx_ctrl->ccb);
+ }
+ }
+
+ /* Check for BNAD_CF_DIM_ENABLED, does not eleminate a race */
+ if (test_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags))
+ mod_timer(&bnad->dim_timer,
+ jiffies + msecs_to_jiffies(BNAD_DIM_TIMER_FREQ));
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+/* c) Statistics Timer */
+static void
+bnad_stats_timeout(unsigned long data)
+{
+ struct bnad *bnad = (struct bnad *)data;
+ unsigned long flags;
+
+ if (!netif_running(bnad->netdev) ||
+ !test_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags))
+ return;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bna_stats_get(&bnad->bna);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+/*
+ * Set up timer for DIM
+ * Called with bnad->bna_lock held
+ */
+void
+bnad_dim_timer_start(struct bnad *bnad)
+{
+ if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED &&
+ !test_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags)) {
+ setup_timer(&bnad->dim_timer, bnad_dim_timeout,
+ (unsigned long)bnad);
+ set_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags);
+ mod_timer(&bnad->dim_timer,
+ jiffies + msecs_to_jiffies(BNAD_DIM_TIMER_FREQ));
+ }
+}
+
+/*
+ * Set up timer for statistics
+ * Called with mutex_lock(&bnad->conf_mutex) held
+ */
+static void
+bnad_stats_timer_start(struct bnad *bnad)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ if (!test_and_set_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags)) {
+ setup_timer(&bnad->stats_timer, bnad_stats_timeout,
+ (unsigned long)bnad);
+ mod_timer(&bnad->stats_timer,
+ jiffies + msecs_to_jiffies(BNAD_STATS_TIMER_FREQ));
+ }
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+/*
+ * Stops the stats timer
+ * Called with mutex_lock(&bnad->conf_mutex) held
+ */
+static void
+bnad_stats_timer_stop(struct bnad *bnad)
+{
+ int to_del = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ if (test_and_clear_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags))
+ to_del = 1;
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ if (to_del)
+ del_timer_sync(&bnad->stats_timer);
+}
+
+/* Utilities */
+
+static void
+bnad_netdev_mc_list_get(struct net_device *netdev, u8 *mc_list)
+{
+ int i = 1; /* Index 0 has broadcast address */
+ struct netdev_hw_addr *mc_addr;
+
+ netdev_for_each_mc_addr(mc_addr, netdev) {
+ memcpy(&mc_list[i * ETH_ALEN], &mc_addr->addr[0],
+ ETH_ALEN);
+ i++;
+ }
+}
+
+static int
+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;
+ int rcvd = 0;
+
+ ccb = rx_ctrl->ccb;
+
+ bnad = ccb->bnad;
+
+ if (!netif_carrier_ok(bnad->netdev))
+ goto poll_exit;
+
+ rcvd = bnad_poll_cq(bnad, ccb, budget);
+ if (rcvd == budget)
+ return rcvd;
+
+poll_exit:
+ napi_complete((napi));
+
+ BNAD_UPDATE_CTR(bnad, netif_rx_complete);
+
+ bnad_enable_rx_irq(bnad, ccb);
+ return rcvd;
+}
+
+static int
+bnad_napi_poll_txrx(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;
+ int rcvd = 0;
+ int i, j;
+
+ ccb = rx_ctrl->ccb;
+
+ bnad = ccb->bnad;
+
+ if (!netif_carrier_ok(bnad->netdev))
+ goto poll_exit;
+
+ /* Handle Tx Completions, if any */
+ 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]);
+ }
+
+ /* Handle Rx Completions */
+ rcvd = bnad_poll_cq(bnad, ccb, budget);
+ if (rcvd == budget)
+ return rcvd;
+poll_exit:
+ napi_complete((napi));
+
+ BNAD_UPDATE_CTR(bnad, netif_rx_complete);
+
+ bnad_enable_txrx_irqs(bnad);
+ return rcvd;
+}
+
+static void
+bnad_napi_enable(struct bnad *bnad, u32 rx_id)
+{
+ int (*napi_poll) (struct napi_struct *, int);
+ struct bnad_rx_ctrl *rx_ctrl;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ if (bnad->cfg_flags & BNAD_CF_MSIX)
+ napi_poll = bnad_napi_poll_rx;
+ else
+ napi_poll = bnad_napi_poll_txrx;
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ /* 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,
+ napi_poll, 64);
+ napi_enable(&rx_ctrl->napi);
+ }
+}
+
+static void
+bnad_napi_disable(struct bnad *bnad, u32 rx_id)
+{
+ int i;
+
+ /* First disable and then clean up */
+ for (i = 0; i < bnad->num_rxp_per_rx; i++) {
+ napi_disable(&bnad->rx_info[rx_id].rx_ctrl[i].napi);
+ netif_napi_del(&bnad->rx_info[rx_id].rx_ctrl[i].napi);
+ }
+}
+
+/* Should be held with conf_lock held */
+void
+bnad_cleanup_tx(struct bnad *bnad, uint 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];
+ unsigned long flags;
+
+ if (!tx_info->tx)
+ return;
+
+ init_completion(&bnad->bnad_completions.tx_comp);
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bna_tx_disable(tx_info->tx, BNA_HARD_CLEANUP, bnad_cb_tx_disabled);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ wait_for_completion(&bnad->bnad_completions.tx_comp);
+
+ if (tx_info->tcb[0]->intr_type == BNA_INTR_T_MSIX)
+ bnad_tx_msix_unregister(bnad, tx_info,
+ bnad->num_txq_per_tx);
+
+ 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);
+
+ bnad_tx_res_free(bnad, res_info);
+}
+
+/* Should be held with conf_lock held */
+int
+bnad_setup_tx(struct bnad *bnad, uint tx_id)
+{
+ int err;
+ 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];
+ 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;
+ struct bna_tx *tx;
+ unsigned long flags;
+
+ /* 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;
+
+ /* Get BNA's resource requirement for one tx object */
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bna_tx_res_req(bnad->num_txq_per_tx,
+ bnad->txq_depth, res_info);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ /* Fill Unmap Q memory requirements */
+ BNAD_FILL_UNMAPQ_MEM_REQ(
+ &res_info[BNA_TX_RES_MEM_T_UNMAPQ],
+ bnad->num_txq_per_tx,
+ BNAD_TX_UNMAPQ_DEPTH);
+
+ /* Allocate resources */
+ err = bnad_tx_res_alloc(bnad, res_info, tx_id);
+ if (err)
+ return err;
+
+ /* Ask BNA to create one Tx object, supplying required resources */
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ tx = bna_tx_create(&bnad->bna, bnad, tx_config, &tx_cbfn, res_info,
+ tx_info);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ if (!tx)
+ goto err_return;
+ tx_info->tx = tx;
+
+ /* Register ISR for the Tx object */
+ if (intr_info->intr_type == BNA_INTR_T_MSIX) {
+ err = bnad_tx_msix_register(bnad, tx_info,
+ tx_id, bnad->num_txq_per_tx);
+ if (err)
+ goto err_return;
+ }
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bna_tx_enable(tx);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ return 0;
+
+err_return:
+ bnad_tx_res_free(bnad, res_info);
+ return err;
+}
+
+/* Setup the rx config for bna_rx_create */
+/* bnad decides the configuration */
+static void
+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;
+
+ 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);
+ rx_config->rss_config.hash_mask =
+ bnad->num_rxp_per_rx - 1;
+ get_random_bytes(rx_config->rss_config.toeplitz_hash_key,
+ sizeof(rx_config->rss_config.toeplitz_hash_key));
+ } else {
+ rx_config->rss_status = BNA_STATUS_T_DISABLED;
+ memset(&rx_config->rss_config, 0,
+ sizeof(rx_config->rss_config));
+ }
+ rx_config->rxp_type = BNA_RXP_SLR;
+ rx_config->q_depth = bnad->rxq_depth;
+
+ rx_config->small_buff_size = BFI_SMALL_RXBUF_SIZE;
+
+ rx_config->vlan_strip_status = BNA_STATUS_T_ENABLED;
+}
+
+/* Called with mutex_lock(&bnad->conf_mutex) held */
+void
+bnad_cleanup_rx(struct bnad *bnad, uint 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;
+
+ 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)
+ clear_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ if (dim_timer_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);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ wait_for_completion(&bnad->bnad_completions.rx_comp);
+
+ if (rx_info->rx_ctrl[0].ccb->intr_type == BNA_INTR_T_MSIX)
+ bnad_rx_msix_unregister(bnad, rx_info, rx_config->num_paths);
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bna_rx_destroy(rx_info->rx);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ rx_info->rx = NULL;
+
+ 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)
+{
+ int err;
+ struct bnad_rx_info *rx_info = &bnad->rx_info[rx_id];
+ struct bna_res_info *res_info = &bnad->rx_res_info[rx_id].res_info[0];
+ 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;
+ struct bna_rx *rx;
+ unsigned long flags;
+
+ /* 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 = NULL;
+ 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);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ /* Fill Unmap Q memory requirements */
+ BNAD_FILL_UNMAPQ_MEM_REQ(
+ &res_info[BNA_RX_RES_MEM_T_UNMAPQ],
+ rx_config->num_paths +
+ ((rx_config->rxp_type == BNA_RXP_SINGLE) ? 0 :
+ rx_config->num_paths), BNAD_RX_UNMAPQ_DEPTH);
+
+ /* Allocate resource */
+ err = bnad_rx_res_alloc(bnad, res_info, rx_id);
+ if (err)
+ return err;
+
+ /* 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)
+ goto err_return;
+ rx_info->rx = rx;
+
+ /* Register ISR for the Rx object */
+ if (intr_info->intr_type == BNA_INTR_T_MSIX) {
+ err = bnad_rx_msix_register(bnad, rx_info, rx_id,
+ rx_config->num_paths);
+ if (err)
+ 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 */
+ if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED)
+ bna_rx_dim_reconfig(&bnad->bna, bna_napi_dim_vector);
+
+ /* Enable VLAN filtering only on the default Rx */
+ bna_rx_vlanfilter_enable(rx);
+
+ /* Start the DIM timer */
+ bnad_dim_timer_start(bnad);
+ }
+
+ bna_rx_enable(rx);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ return 0;
+
+err_return:
+ bnad_cleanup_rx(bnad, rx_id);
+ return err;
+}
+
+/* Called with conf_lock & bnad->bna_lock held */
+void
+bnad_tx_coalescing_timeo_set(struct bnad *bnad)
+{
+ struct bnad_tx_info *tx_info;
+
+ tx_info = &bnad->tx_info[0];
+ if (!tx_info->tx)
+ return;
+
+ bna_tx_coalescing_timeo_set(tx_info->tx, bnad->tx_coalescing_timeo);
+}
+
+/* Called with conf_lock & bnad->bna_lock held */
+void
+bnad_rx_coalescing_timeo_set(struct bnad *bnad)
+{
+ struct bnad_rx_info *rx_info;
+ int i;
+
+ for (i = 0; i < bnad->num_rx; i++) {
+ rx_info = &bnad->rx_info[i];
+ if (!rx_info->rx)
+ continue;
+ bna_rx_coalescing_timeo_set(rx_info->rx,
+ bnad->rx_coalescing_timeo);
+ }
+}
+
+/*
+ * Called with bnad->bna_lock held
+ */
+static int
+bnad_mac_addr_set_locked(struct bnad *bnad, u8 *mac_addr)
+{
+ int ret;
+
+ if (!is_valid_ether_addr(mac_addr))
+ return -EADDRNOTAVAIL;
+
+ /* If datapath is down, pretend everything went through */
+ if (!bnad->rx_info[0].rx)
+ return 0;
+
+ ret = bna_rx_ucast_set(bnad->rx_info[0].rx, mac_addr, NULL);
+ if (ret != BNA_CB_SUCCESS)
+ return -EADDRNOTAVAIL;
+
+ return 0;
+}
+
+/* Should be called with conf_lock held */
+static int
+bnad_enable_default_bcast(struct bnad *bnad)
+{
+ struct bnad_rx_info *rx_info = &bnad->rx_info[0];
+ int ret;
+ unsigned long flags;
+
+ init_completion(&bnad->bnad_completions.mcast_comp);
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ ret = bna_rx_mcast_add(rx_info->rx, (u8 *)bnad_bcast_addr,
+ bnad_cb_rx_mcast_add);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ if (ret == BNA_CB_SUCCESS)
+ wait_for_completion(&bnad->bnad_completions.mcast_comp);
+ else
+ return -ENODEV;
+
+ if (bnad->bnad_completions.mcast_comp_status != BNA_CB_SUCCESS)
+ return -ENODEV;
+
+ return 0;
+}
+
+/* Statistics utilities */
+void
+bnad_netdev_qstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats)
+{
+ int i, j;
+
+ for (i = 0; i < bnad->num_rx; i++) {
+ for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+ if (bnad->rx_info[i].rx_ctrl[j].ccb) {
+ stats->rx_packets += bnad->rx_info[i].
+ rx_ctrl[j].ccb->rcb[0]->rxq->rx_packets;
+ stats->rx_bytes += bnad->rx_info[i].
+ rx_ctrl[j].ccb->rcb[0]->rxq->rx_bytes;
+ if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
+ bnad->rx_info[i].rx_ctrl[j].ccb->
+ rcb[1]->rxq) {
+ stats->rx_packets +=
+ bnad->rx_info[i].rx_ctrl[j].
+ ccb->rcb[1]->rxq->rx_packets;
+ stats->rx_bytes +=
+ bnad->rx_info[i].rx_ctrl[j].
+ ccb->rcb[1]->rxq->rx_bytes;
+ }
+ }
+ }
+ }
+ for (i = 0; i < bnad->num_tx; i++) {
+ for (j = 0; j < bnad->num_txq_per_tx; j++) {
+ if (bnad->tx_info[i].tcb[j]) {
+ stats->tx_packets +=
+ bnad->tx_info[i].tcb[j]->txq->tx_packets;
+ stats->tx_bytes +=
+ bnad->tx_info[i].tcb[j]->txq->tx_bytes;
+ }
+ }
+ }
+}
+
+/*
+ * Must be called with the bna_lock held.
+ */
+void
+bnad_netdev_hwstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats)
+{
+ struct bfi_ll_stats_mac *mac_stats;
+ u64 bmap;
+ int i;
+
+ 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 +
+ mac_stats->rx_undersize;
+ stats->tx_errors = mac_stats->tx_fcs_error +
+ mac_stats->tx_undersize;
+ stats->rx_dropped = mac_stats->rx_drop;
+ stats->tx_dropped = mac_stats->tx_drop;
+ stats->multicast = mac_stats->rx_multicast;
+ stats->collisions = mac_stats->tx_total_collision;
+
+ stats->rx_length_errors = mac_stats->rx_frame_length_error;
+
+ /* receive ring buffer overflow ?? */
+
+ 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++) {
+ if (bmap & 1) {
+ stats->rx_fifo_errors +=
+ bnad->stats.bna_stats->
+ hw_stats->rxf_stats[i].frame_drops;
+ break;
+ }
+ bmap >>= 1;
+ }
+}
+
+static void
+bnad_mbox_irq_sync(struct bnad *bnad)
+{
+ u32 irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ if (bnad->cfg_flags & BNAD_CF_MSIX)
+ irq = bnad->msix_table[bnad->msix_num - 1].vector;
+ else
+ irq = bnad->pcidev->irq;
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ synchronize_irq(irq);
+}
+
+/* Utility used by bnad_start_xmit, for doing TSO */
+static int
+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) {
+ BNAD_UPDATE_CTR(bnad, tso_err);
+ return err;
+ }
+ }
+
+ /*
+ * For TSO, the TCP checksum field is seeded with pseudo-header sum
+ * excluding the length field.
+ */
+ if (skb->protocol == htons(ETH_P_IP)) {
+ struct iphdr *iph = ip_hdr(skb);
+
+ /* Do we really need these? */
+ iph->tot_len = 0;
+ iph->check = 0;
+
+ tcp_hdr(skb)->check =
+ ~csum_tcpudp_magic(iph->saddr, iph->daddr, 0,
+ IPPROTO_TCP, 0);
+ BNAD_UPDATE_CTR(bnad, tso4);
+ } 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,
+ IPPROTO_TCP, 0);
+ BNAD_UPDATE_CTR(bnad, tso6);
+ }
+
+ return 0;
+}
+
+/*
+ * Initialize Q numbers depending on Rx Paths
+ * Called with bnad->bna_lock held, because of cfg_flags
+ * access.
+ */
+static void
+bnad_q_num_init(struct bnad *bnad)
+{
+ int rxps;
+
+ rxps = min((uint)num_online_cpus(),
+ (uint)(BNAD_MAX_RXS * BNAD_MAX_RXPS_PER_RX));
+
+ if (!(bnad->cfg_flags & BNAD_CF_MSIX))
+ rxps = 1; /* INTx */
+
+ bnad->num_rx = 1;
+ bnad->num_tx = 1;
+ bnad->num_rxp_per_rx = rxps;
+ bnad->num_txq_per_tx = BNAD_TXQ_NUM;
+}
+
+/*
+ * Adjusts the Q numbers, given a number of msix vectors
+ * Give preference to RSS as opposed to Tx priority Queues,
+ * in such a case, just use 1 Tx Q
+ * 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->num_txq_per_tx = 1;
+ if ((msix_vectors >= (bnad->num_tx * bnad->num_txq_per_tx) +
+ bnad_rxqs_per_cq + BNAD_MAILBOX_MSIX_VECTORS) &&
+ (bnad->cfg_flags & BNAD_CF_MSIX)) {
+ bnad->num_rxp_per_rx = msix_vectors -
+ (bnad->num_tx * bnad->num_txq_per_tx) -
+ BNAD_MAILBOX_MSIX_VECTORS;
+ } else
+ bnad->num_rxp_per_rx = 1;
+}
+
+static void
+bnad_set_netdev_perm_addr(struct bnad *bnad)
+{
+ struct net_device *netdev = bnad->netdev;
+
+ memcpy(netdev->perm_addr, &bnad->perm_addr, netdev->addr_len);
+ if (is_zero_ether_addr(netdev->dev_addr))
+ memcpy(netdev->dev_addr, &bnad->perm_addr, netdev->addr_len);
+}
+
+/* Enable / disable device */
+static void
+bnad_device_disable(struct bnad *bnad)
+{
+ unsigned long flags;
+
+ init_completion(&bnad->bnad_completions.ioc_comp);
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bna_device_disable(&bnad->bna.device, BNA_HARD_CLEANUP);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ wait_for_completion(&bnad->bnad_completions.ioc_comp);
+}
+
+static int
+bnad_device_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);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ wait_for_completion(&bnad->bnad_completions.ioc_comp);
+
+ if (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)
+{
+ 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);
+ }
+}
+
+/* Allocates memory and interrupt resources for BNA */
+static int
+bnad_res_alloc(struct bnad *bnad)
+{
+ 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);
+ if (err)
+ goto err_return;
+ }
+ return 0;
+
+err_return:
+ bnad_res_free(bnad);
+ return err;
+}
+
+/* Interrupt enable / disable */
+static void
+bnad_enable_msix(struct bnad *bnad)
+{
+ int i, ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ if (!(bnad->cfg_flags & BNAD_CF_MSIX)) {
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ if (bnad->msix_table)
+ return;
+
+ bnad->msix_table =
+ kcalloc(bnad->msix_num, sizeof(struct msix_entry), GFP_KERNEL);
+
+ if (!bnad->msix_table)
+ goto intx_mode;
+
+ for (i = 0; i < bnad->msix_num; i++)
+ bnad->msix_table[i].entry = i;
+
+ ret = pci_enable_msix(bnad->pcidev, bnad->msix_table, bnad->msix_num);
+ if (ret > 0) {
+ /* Not enough MSI-X vectors. */
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ /* ret = #of vectors that we got */
+ bnad_q_num_adjust(bnad, ret);
+ 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_MAILBOX_MSIX_VECTORS;
+
+ /* Try once more with adjusted numbers */
+ /* If this fails, fall back to INTx */
+ ret = pci_enable_msix(bnad->pcidev, bnad->msix_table,
+ bnad->msix_num);
+ if (ret)
+ goto intx_mode;
+
+ } else if (ret < 0)
+ goto intx_mode;
+ return;
+
+intx_mode:
+
+ kfree(bnad->msix_table);
+ bnad->msix_table = NULL;
+ bnad->msix_num = 0;
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bnad->cfg_flags &= ~BNAD_CF_MSIX;
+ bnad_q_num_init(bnad);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+static void
+bnad_disable_msix(struct bnad *bnad)
+{
+ u32 cfg_flags;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ cfg_flags = bnad->cfg_flags;
+ if (bnad->cfg_flags & BNAD_CF_MSIX)
+ bnad->cfg_flags &= ~BNAD_CF_MSIX;
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ if (cfg_flags & BNAD_CF_MSIX) {
+ pci_disable_msix(bnad->pcidev);
+ kfree(bnad->msix_table);
+ bnad->msix_table = NULL;
+ }
+}
+
+/* Netdev entry points */
+static int
+bnad_open(struct net_device *netdev)
+{
+ int err;
+ struct bnad *bnad = netdev_priv(netdev);
+ struct bna_pause_config pause_config;
+ int mtu;
+ unsigned long flags;
+
+ mutex_lock(&bnad->conf_mutex);
+
+ /* Tx */
+ err = bnad_setup_tx(bnad, 0);
+ if (err)
+ goto err_return;
+
+ /* Rx */
+ err = bnad_setup_rx(bnad, 0);
+ if (err)
+ goto cleanup_tx;
+
+ /* Port */
+ pause_config.tx_pause = 0;
+ pause_config.rx_pause = 0;
+
+ mtu = ETH_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);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ /* Enable broadcast */
+ bnad_enable_default_bcast(bnad);
+
+ /* Set the UCAST address */
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bnad_mac_addr_set_locked(bnad, netdev->dev_addr);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ /* Start the stats timer */
+ bnad_stats_timer_start(bnad);
+
+ mutex_unlock(&bnad->conf_mutex);
+
+ return 0;
+
+cleanup_tx:
+ bnad_cleanup_tx(bnad, 0);
+
+err_return:
+ mutex_unlock(&bnad->conf_mutex);
+ return err;
+}
+
+static int
+bnad_stop(struct net_device *netdev)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ unsigned long flags;
+
+ mutex_lock(&bnad->conf_mutex);
+
+ /* Stop the stats timer */
+ bnad_stats_timer_stop(bnad);
+
+ init_completion(&bnad->bnad_completions.port_comp);
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bna_port_disable(&bnad->bna.port, BNA_HARD_CLEANUP,
+ bnad_cb_port_disabled);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ wait_for_completion(&bnad->bnad_completions.port_comp);
+
+ bnad_cleanup_tx(bnad, 0);
+ bnad_cleanup_rx(bnad, 0);
+
+ /* Synchronize mailbox IRQ */
+ bnad_mbox_irq_sync(bnad);
+
+ mutex_unlock(&bnad->conf_mutex);
+
+ return 0;
+}
+
+/* TX */
+/*
+ * bnad_start_xmit : Netdev entry point for Transmit
+ * Called under lock held by net_device
+ */
+static netdev_tx_t
+bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+
+ 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;
+
+ struct bnad_tx_info *tx_info;
+ struct bna_tcb *tcb;
+ struct bnad_unmap_q *unmap_q;
+ dma_addr_t dma_addr;
+ struct bna_txq_entry *txqent;
+ bna_txq_wi_ctrl_flag_t flags;
+
+ if (unlikely
+ (skb->len <= ETH_HLEN || skb->len > BFI_TX_MAX_DATA_PER_PKT)) {
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ /*
+ * Takes care of the Tx that is scheduled between clearing the flag
+ * and the netif_stop_queue() call.
+ */
+ if (unlikely(!test_bit(BNAD_RF_TX_STARTED, &bnad->run_flags))) {
+ dev_kfree_skb(skb);
+ 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;
+
+ vectors = 1 + skb_shinfo(skb)->nr_frags;
+ if (vectors > BFI_TX_MAX_VECTORS_PER_PKT) {
+ dev_kfree_skb(skb);
+ 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 ((u16) (*tcb->hw_consumer_index) !=
+ tcb->consumer_index &&
+ !test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags)) {
+ acked = bnad_free_txbufs(bnad, tcb);
+ bna_ib_ack(tcb->i_dbell, acked);
+ smp_mb__before_clear_bit();
+ clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
+ } else {
+ netif_stop_queue(netdev);
+ BNAD_UPDATE_CTR(bnad, netif_queue_stop);
+ }
+
+ smp_mb();
+ /*
+ * Check again to deal with race condition between
+ * netif_stop_queue here, and netif_wake_queue in
+ * interrupt handler which is not inside netif tx lock.
+ */
+ if (likely
+ (wis > BNA_QE_FREE_CNT(tcb, tcb->q_depth) ||
+ vectors > BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth))) {
+ BNAD_UPDATE_CTR(bnad, netif_queue_stop);
+ return NETDEV_TX_BUSY;
+ } else {
+ netif_wake_queue(netdev);
+ BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
+ }
+ }
+
+ 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);
+ flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN);
+ }
+ if (test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags)) {
+ vlan_tag =
+ (tcb->priority & 0x7) << 13 | (vlan_tag & 0x1fff);
+ flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN);
+ }
+
+ txqent->hdr.wi.vlan_tag = htons(vlan_tag);
+
+ if (skb_is_gso(skb)) {
+ err = bnad_tso_prepare(bnad, skb);
+ if (err) {
+ dev_kfree_skb(skb);
+ 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;
+
+ 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 (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);
+
+ 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);
+
+ 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) {
+ dev_kfree_skb(skb);
+ BNAD_UPDATE_CTR(bnad, csum_help_err);
+ return NETDEV_TX_OK;
+ }
+ }
+ } else {
+ txqent->hdr.wi.lso_mss = 0;
+ txqent->hdr.wi.l4_hdr_size_n_offset = 0;
+ }
+
+ txqent->hdr.wi.flags = htons(flags);
+
+ 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));
+ dma_addr = pci_map_single(bnad->pcidev, skb->data, skb_headlen(skb),
+ PCI_DMA_TODEVICE);
+ pci_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);
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
+ u32 size = frag->size;
+
+ if (++vect_id == BFI_TX_MAX_VECTORS_PER_WI) {
+ vect_id = 0;
+ if (--wi_range)
+ txqent++;
+ else {
+ BNA_QE_INDX_ADD(txq_prod, wis_used,
+ tcb->q_depth);
+ 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);
+ }
+
+ BUG_ON(!(size <= BFI_TX_MAX_DATA_PER_VECTOR));
+ txqent->vector[vect_id].length = htons(size);
+ dma_addr =
+ pci_map_page(bnad->pcidev, frag->page,
+ frag->page_offset, size,
+ PCI_DMA_TODEVICE);
+ pci_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);
+ }
+
+ unmap_q->producer_index = unmap_prod;
+ BNA_QE_INDX_ADD(txq_prod, wis_used, tcb->q_depth);
+ tcb->producer_index = txq_prod;
+
+ smp_mb();
+ bna_txq_prod_indx_doorbell(tcb);
+
+ if ((u16) (*tcb->hw_consumer_index) != tcb->consumer_index)
+ tasklet_schedule(&bnad->tx_free_tasklet);
+
+ return NETDEV_TX_OK;
+}
+
+/*
+ * Used spin_lock to synchronize reading of stats structures, which
+ * is written by BNA under the same lock.
+ */
+static struct rtnl_link_stats64 *
+bnad_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+
+ bnad_netdev_qstats_fill(bnad, stats);
+ bnad_netdev_hwstats_fill(bnad, stats);
+
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ return stats;
+}
+
+static void
+bnad_set_rx_mode(struct net_device *netdev)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ u32 new_mask, valid_mask;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+
+ new_mask = valid_mask = 0;
+
+ if (netdev->flags & IFF_PROMISC) {
+ if (!(bnad->cfg_flags & BNAD_CF_PROMISC)) {
+ new_mask = BNAD_RXMODE_PROMISC_DEFAULT;
+ valid_mask = BNAD_RXMODE_PROMISC_DEFAULT;
+ bnad->cfg_flags |= BNAD_CF_PROMISC;
+ }
+ } else {
+ if (bnad->cfg_flags & BNAD_CF_PROMISC) {
+ new_mask = ~BNAD_RXMODE_PROMISC_DEFAULT;
+ valid_mask = BNAD_RXMODE_PROMISC_DEFAULT;
+ bnad->cfg_flags &= ~BNAD_CF_PROMISC;
+ }
+ }
+
+ if (netdev->flags & IFF_ALLMULTI) {
+ if (!(bnad->cfg_flags & BNAD_CF_ALLMULTI)) {
+ new_mask |= BNA_RXMODE_ALLMULTI;
+ valid_mask |= BNA_RXMODE_ALLMULTI;
+ bnad->cfg_flags |= BNAD_CF_ALLMULTI;
+ }
+ } else {
+ if (bnad->cfg_flags & BNAD_CF_ALLMULTI) {
+ new_mask &= ~BNA_RXMODE_ALLMULTI;
+ valid_mask |= BNA_RXMODE_ALLMULTI;
+ bnad->cfg_flags &= ~BNAD_CF_ALLMULTI;
+ }
+ }
+
+ bna_rx_mode_set(bnad->rx_info[0].rx, new_mask, valid_mask, NULL);
+
+ if (!netdev_mc_empty(netdev)) {
+ u8 *mcaddr_list;
+ int mc_count = netdev_mc_count(netdev);
+
+ /* Index 0 holds the broadcast address */
+ mcaddr_list =
+ kzalloc((mc_count + 1) * ETH_ALEN,
+ GFP_ATOMIC);
+ if (!mcaddr_list)
+ goto unlock;
+
+ memcpy(&mcaddr_list[0], &bnad_bcast_addr[0], ETH_ALEN);
+
+ /* Copy rest of the MC addresses */
+ bnad_netdev_mc_list_get(netdev, mcaddr_list);
+
+ bna_rx_mcast_listset(bnad->rx_info[0].rx, mc_count + 1,
+ mcaddr_list, NULL);
+
+ /* Should we enable BNAD_CF_ALLMULTI for err != 0 ? */
+ kfree(mcaddr_list);
+ }
+unlock:
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+/*
+ * bna_lock is used to sync writes to netdev->addr
+ * conf_lock cannot be used since this call may be made
+ * in a non-blocking context.
+ */
+static int
+bnad_set_mac_address(struct net_device *netdev, void *mac_addr)
+{
+ int err;
+ struct bnad *bnad = netdev_priv(netdev);
+ struct sockaddr *sa = (struct sockaddr *)mac_addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+
+ err = bnad_mac_addr_set_locked(bnad, sa->sa_data);
+
+ if (!err)
+ memcpy(netdev->dev_addr, sa->sa_data, netdev->addr_len);
+
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ return err;
+}
+
+static int
+bnad_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ int mtu, err = 0;
+ unsigned long flags;
+
+ struct bnad *bnad = netdev_priv(netdev);
+
+ if (new_mtu + ETH_HLEN < ETH_ZLEN || new_mtu > BNAD_JUMBO_MTU)
+ return -EINVAL;
+
+ mutex_lock(&bnad->conf_mutex);
+
+ 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);
+
+ mutex_unlock(&bnad->conf_mutex);
+ return err;
+}
+
+static void
+bnad_vlan_rx_register(struct net_device *netdev,
+ struct vlan_group *vlan_grp)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+
+ mutex_lock(&bnad->conf_mutex);
+ bnad->vlan_grp = vlan_grp;
+ mutex_unlock(&bnad->conf_mutex);
+}
+
+static void
+bnad_vlan_rx_add_vid(struct net_device *netdev,
+ unsigned short vid)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ unsigned long flags;
+
+ if (!bnad->rx_info[0].rx)
+ return;
+
+ mutex_lock(&bnad->conf_mutex);
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bna_rx_vlan_add(bnad->rx_info[0].rx, vid);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ mutex_unlock(&bnad->conf_mutex);
+}
+
+static void
+bnad_vlan_rx_kill_vid(struct net_device *netdev,
+ unsigned short vid)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ unsigned long flags;
+
+ if (!bnad->rx_info[0].rx)
+ return;
+
+ mutex_lock(&bnad->conf_mutex);
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bna_rx_vlan_del(bnad->rx_info[0].rx, vid);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ mutex_unlock(&bnad->conf_mutex);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void
+bnad_netpoll(struct net_device *netdev)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ struct bnad_rx_info *rx_info;
+ struct bnad_rx_ctrl *rx_ctrl;
+ u32 curr_mask;
+ int i, j;
+
+ if (!(bnad->cfg_flags & BNAD_CF_MSIX)) {
+ bna_intx_disable(&bnad->bna, curr_mask);
+ bnad_isr(bnad->pcidev->irq, netdev);
+ bna_intx_enable(&bnad->bna, curr_mask);
+ } else {
+ 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);
+ bnad_netif_rx_schedule_poll(bnad,
+ rx_ctrl->ccb);
+ }
+ }
+ }
+ }
+}
+#endif
+
+static const struct net_device_ops bnad_netdev_ops = {
+ .ndo_open = bnad_open,
+ .ndo_stop = bnad_stop,
+ .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,
+ .ndo_vlan_rx_register = bnad_vlan_rx_register,
+ .ndo_vlan_rx_add_vid = bnad_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = bnad_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = bnad_netpoll
+#endif
+};
+
+static void
+bnad_netdev_init(struct bnad *bnad, bool using_dac)
+{
+ struct net_device *netdev = bnad->netdev;
+
+ netdev->features |= NETIF_F_IPV6_CSUM;
+ netdev->features |= NETIF_F_TSO;
+ netdev->features |= NETIF_F_TSO6;
+
+ netdev->features |= NETIF_F_GRO;
+ pr_warn("bna: GRO enabled, using kernel stack GRO\n");
+
+ netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+
+ if (using_dac)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ netdev->features |=
+ NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_FILTER;
+
+ netdev->vlan_features = netdev->features;
+ netdev->mem_start = bnad->mmio_start;
+ netdev->mem_end = bnad->mmio_start + bnad->mmio_len - 1;
+
+ netdev->netdev_ops = &bnad_netdev_ops;
+ bnad_set_ethtool_ops(netdev);
+}
+
+/*
+ * 1. Initialize the bnad structure
+ * 2. Setup netdev pointer in pci_dev
+ * 3. Initialze Tx free tasklet
+ * 4. Initialize no. of TxQ & CQs & MSIX vectors
+ */
+static int
+bnad_init(struct bnad *bnad,
+ struct pci_dev *pdev, struct net_device *netdev)
+{
+ unsigned long flags;
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+ pci_set_drvdata(pdev, netdev);
+
+ bnad->netdev = netdev;
+ bnad->pcidev = pdev;
+ bnad->mmio_start = pci_resource_start(pdev, 0);
+ bnad->mmio_len = pci_resource_len(pdev, 0);
+ bnad->bar0 = ioremap_nocache(bnad->mmio_start, bnad->mmio_len);
+ if (!bnad->bar0) {
+ dev_err(&pdev->dev, "ioremap for bar0 failed\n");
+ pci_set_drvdata(pdev, NULL);
+ return -ENOMEM;
+ }
+ pr_info("bar0 mapped to %p, len %llu\n", bnad->bar0,
+ (unsigned long long) bnad->mmio_len);
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ if (!bnad_msix_disable)
+ bnad->cfg_flags = BNAD_CF_MSIX;
+
+ bnad->cfg_flags |= BNAD_CF_DIM_ENABLED;
+
+ bnad_q_num_init(bnad);
+ 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_MAILBOX_MSIX_VECTORS;
+
+ bnad->txq_depth = BNAD_TXQ_DEPTH;
+ bnad->rxq_depth = BNAD_RXQ_DEPTH;
+ bnad->rx_csum = true;
+
+ bnad->tx_coalescing_timeo = BFI_TX_COALESCING_TIMEO;
+ bnad->rx_coalescing_timeo = BFI_RX_COALESCING_TIMEO;
+
+ tasklet_init(&bnad->tx_free_tasklet, bnad_tx_free_tasklet,
+ (unsigned long)bnad);
+
+ return 0;
+}
+
+/*
+ * Must be called after bnad_pci_uninit()
+ * so that iounmap() and pci_set_drvdata(NULL)
+ * happens only after PCI uninitialization.
+ */
+static void
+bnad_uninit(struct bnad *bnad)
+{
+ if (bnad->bar0)
+ iounmap(bnad->bar0);
+ pci_set_drvdata(bnad->pcidev, NULL);
+}
+
+/*
+ * Initialize locks
+ a) Per device mutes used for serializing configuration
+ changes from OS interface
+ b) spin lock used to protect bna state machine
+ */
+static void
+bnad_lock_init(struct bnad *bnad)
+{
+ spin_lock_init(&bnad->bna_lock);
+ mutex_init(&bnad->conf_mutex);
+}
+
+static void
+bnad_lock_uninit(struct bnad *bnad)
+{
+ mutex_destroy(&bnad->conf_mutex);
+}
+
+/* PCI Initialization */
+static int
+bnad_pci_init(struct bnad *bnad,
+ struct pci_dev *pdev, bool *using_dac)
+{
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+ err = pci_request_regions(pdev, BNAD_NAME);
+ if (err)
+ goto disable_device;
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
+ !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ *using_dac = 1;
+ } else {
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err) {
+ err = pci_set_consistent_dma_mask(pdev,
+ DMA_BIT_MASK(32));
+ if (err)
+ goto release_regions;
+ }
+ *using_dac = 0;
+ }
+ pci_set_master(pdev);
+ return 0;
+
+release_regions:
+ pci_release_regions(pdev);
+disable_device:
+ pci_disable_device(pdev);
+
+ return err;
+}
+
+static void
+bnad_pci_uninit(struct pci_dev *pdev)
+{
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+static int __devinit
+bnad_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pcidev_id)
+{
+ bool using_dac;
+ int err;
+ struct bnad *bnad;
+ struct bna *bna;
+ struct net_device *netdev;
+ struct bfa_pcidev pcidev_info;
+ unsigned long flags;
+
+ pr_info("bnad_pci_probe : (0x%p, 0x%p) PCI Func : (%d)\n",
+ pdev, pcidev_id, PCI_FUNC(pdev->devfn));
+
+ mutex_lock(&bnad_fwimg_mutex);
+ if (!cna_get_firmware_buf(pdev)) {
+ mutex_unlock(&bnad_fwimg_mutex);
+ pr_warn("Failed to load Firmware Image!\n");
+ return -ENODEV;
+ }
+ mutex_unlock(&bnad_fwimg_mutex);
+
+ /*
+ * Allocates sizeof(struct net_device + struct bnad)
+ * bnad = netdev->priv
+ */
+ netdev = alloc_etherdev(sizeof(struct bnad));
+ if (!netdev) {
+ dev_err(&pdev->dev, "alloc_etherdev failed\n");
+ err = -ENOMEM;
+ return err;
+ }
+ bnad = netdev_priv(netdev);
+
+ /*
+ * PCI initialization
+ * Output : using_dac = 1 for 64 bit DMA
+ * = 0 for 32 bit DMA
+ */
+ err = bnad_pci_init(bnad, pdev, &using_dac);
+ if (err)
+ goto free_netdev;
+
+ bnad_lock_init(bnad);
+ /*
+ * Initialize bnad structure
+ * Setup relation between pci_dev & netdev
+ * Init Tx free tasklet
+ */
+ err = bnad_init(bnad, pdev, netdev);
+ if (err)
+ goto pci_uninit;
+ /* Initialize netdev structure, set up ethtool ops */
+ bnad_netdev_init(bnad, using_dac);
+
+ bnad_enable_msix(bnad);
+
+ /* Get resource requirement form bna */
+ bna_res_req(&bnad->res_info[0]);
+
+ /* Allocate resources from bna */
+ err = bnad_res_alloc(bnad);
+ if (err)
+ goto free_netdev;
+
+ bna = &bnad->bna;
+
+ /* Setup pcidev_info for bna_init() */
+ pcidev_info.pci_slot = PCI_SLOT(bnad->pcidev->devfn);
+ pcidev_info.pci_func = PCI_FUNC(bnad->pcidev->devfn);
+ 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;
+
+ /* Set up timers */
+ setup_timer(&bnad->bna.device.ioc.ioc_timer, bnad_ioc_timeout,
+ ((unsigned long)bnad));
+ setup_timer(&bnad->bna.device.ioc.hb_timer, bnad_ioc_hb_check,
+ ((unsigned long)bnad));
+ setup_timer(&bnad->bna.device.ioc.sem_timer, bnad_ioc_sem_timeout,
+ ((unsigned long)bnad));
+
+ /* Now start the timer before calling IOC */
+ mod_timer(&bnad->bna.device.ioc.ioc_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
+ */
+ err = bnad_device_enable(bnad);
+
+ /* Get the burnt-in mac */
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bna_port_mac_get(&bna->port, &bnad->perm_addr);
+ bnad_set_netdev_perm_addr(bnad);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ mutex_unlock(&bnad->conf_mutex);
+
+ /*
+ * Make sure the link appears down to the stack
+ */
+ netif_carrier_off(netdev);
+
+ /* Finally, reguister with net_device layer */
+ err = register_netdev(netdev);
+ if (err) {
+ pr_err("BNA : Registering with netdev failed\n");
+ goto disable_device;
+ }
+
+ return 0;
+
+disable_device:
+ 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);
+ 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_disable_msix(bnad);
+pci_uninit:
+ bnad_pci_uninit(pdev);
+ bnad_lock_uninit(bnad);
+ bnad_uninit(bnad);
+free_netdev:
+ free_netdev(netdev);
+ return err;
+}
+
+static void __devexit
+bnad_pci_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct bnad *bnad;
+ struct bna *bna;
+ unsigned long flags;
+
+ if (!netdev)
+ return;
+
+ pr_info("%s bnad_pci_remove\n", netdev->name);
+ bnad = netdev_priv(netdev);
+ bna = &bnad->bna;
+
+ 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);
+ 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_disable_msix(bnad);
+ bnad_pci_uninit(pdev);
+ bnad_lock_uninit(bnad);
+ bnad_uninit(bnad);
+ free_netdev(netdev);
+}
+
+static const struct pci_device_id bnad_pci_id_table[] = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_BROCADE,
+ PCI_DEVICE_ID_BROCADE_CT),
+ .class = PCI_CLASS_NETWORK_ETHERNET << 8,
+ .class_mask = 0xffff00
+ }, {0, }
+};
+
+MODULE_DEVICE_TABLE(pci, bnad_pci_id_table);
+
+static struct pci_driver bnad_pci_driver = {
+ .name = BNAD_NAME,
+ .id_table = bnad_pci_id_table,
+ .probe = bnad_pci_probe,
+ .remove = __devexit_p(bnad_pci_remove),
+};
+
+static int __init
+bnad_module_init(void)
+{
+ int err;
+
+ pr_info("Brocade 10G Ethernet driver\n");
+
+ bfa_nw_ioc_auto_recover(bnad_ioc_auto_recover);
+
+ err = pci_register_driver(&bnad_pci_driver);
+ if (err < 0) {
+ pr_err("bna : PCI registration failed in module init "
+ "(%d)\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static void __exit
+bnad_module_exit(void)
+{
+ pci_unregister_driver(&bnad_pci_driver);
+
+ if (bfi_fw)
+ release_firmware(bfi_fw);
+}
+
+module_init(bnad_module_init);
+module_exit(bnad_module_exit);
+
+MODULE_AUTHOR("Brocade");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Brocade 10G PCIe Ethernet driver");
+MODULE_VERSION(BNAD_VERSION);
+MODULE_FIRMWARE(CNA_FW_FILE_CT);
diff --git a/drivers/net/bna/bnad.h b/drivers/net/bna/bnad.h
new file mode 100644
index 000000000000..ebc3a9078642
--- /dev/null
+++ b/drivers/net/bna/bnad.h
@@ -0,0 +1,332 @@
+/*
+ * 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 __BNAD_H__
+#define __BNAD_H__
+
+#include <linux/rtnetlink.h>
+#include <linux/workqueue.h>
+#include <linux/ipv6.h>
+#include <linux/etherdevice.h>
+#include <linux/mutex.h>
+#include <linux/firmware.h>
+
+/* Fix for IA64 */
+#include <asm/checksum.h>
+#include <net/ip6_checksum.h>
+
+#include <net/ip.h>
+#include <net/tcp.h>
+
+#include "bna.h"
+
+#define BNAD_TXQ_DEPTH 2048
+#define BNAD_RXQ_DEPTH 2048
+
+#define BNAD_MAX_TXS 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
+
+/*
+ * Control structure pointed to ccb->ctrl, which
+ * determines the NAPI / LRO behavior CCB
+ * There is 1:1 corres. between ccb & ctrl
+ */
+struct bnad_rx_ctrl {
+ struct bna_ccb *ccb;
+ struct napi_struct napi;
+};
+
+#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.0"
+
+#define BNAD_MAILBOX_MSIX_VECTORS 1
+
+#define BNAD_STATS_TIMER_FREQ 1000 /* in msecs */
+#define BNAD_DIM_TIMER_FREQ 1000 /* in msecs */
+
+#define BNAD_MAX_Q_DEPTH 0x10000
+#define BNAD_MIN_Q_DEPTH 0x200
+
+#define BNAD_JUMBO_MTU 9000
+
+#define BNAD_NETIF_WAKE_THRESHOLD 8
+
+#define BNAD_RXQ_REFILL_THRESHOLD_SHIFT 3
+
+/* Bit positions for tcb->flags */
+#define BNAD_TXQ_FREE_SENT 0
+
+/* Bit positions for rcb->flags */
+#define BNAD_RXQ_REFILL 0
+#define BNAD_RXQ_STARTED 1
+
+/*
+ * DATA STRUCTURES
+ */
+
+/* enums */
+enum bnad_intr_source {
+ BNAD_INTR_TX = 1,
+ BNAD_INTR_RX = 2
+};
+
+enum bnad_link_state {
+ BNAD_LS_DOWN = 0,
+ BNAD_LS_UP = 1
+};
+
+struct bnad_completion {
+ struct completion ioc_comp;
+ struct completion ucast_comp;
+ struct completion mcast_comp;
+ struct completion tx_comp;
+ struct completion rx_comp;
+ struct completion stats_comp;
+ struct completion port_comp;
+
+ u8 ioc_comp_status;
+ u8 ucast_comp_status;
+ u8 mcast_comp_status;
+ u8 tx_comp_status;
+ u8 rx_comp_status;
+ u8 stats_comp_status;
+ u8 port_comp_status;
+};
+
+/* Tx Rx Control Stats */
+struct bnad_drv_stats {
+ u64 netif_queue_stop;
+ u64 netif_queue_wakeup;
+ u64 tso4;
+ u64 tso6;
+ u64 tso_err;
+ u64 tcpcsum_offload;
+ u64 udpcsum_offload;
+ u64 csum_help;
+ u64 csum_help_err;
+
+ u64 hw_stats_updates;
+ u64 netif_rx_schedule;
+ u64 netif_rx_complete;
+ u64 netif_rx_dropped;
+
+ u64 link_toggle;
+ u64 cee_up;
+
+ u64 rxp_info_alloc_failed;
+ u64 mbox_intr_disabled;
+ u64 mbox_intr_enabled;
+ u64 tx_unmap_q_alloc_failed;
+ u64 rx_unmap_q_alloc_failed;
+
+ u64 rxbuf_alloc_failed;
+};
+
+/* Complete driver stats */
+struct bnad_stats {
+ struct bnad_drv_stats drv_stats;
+ struct bna_stats *bna_stats;
+};
+
+/* Tx / Rx Resources */
+struct bnad_tx_res_info {
+ struct bna_res_info res_info[BNA_TX_RES_T_MAX];
+};
+
+struct bnad_rx_res_info {
+ struct bna_res_info res_info[BNA_RX_RES_T_MAX];
+};
+
+struct bnad_tx_info {
+ struct bna_tx *tx; /* 1:1 between tx_info & tx */
+ struct bna_tcb *tcb[BNAD_MAX_TXQ_PER_TX];
+} ____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];
+} ____cacheline_aligned;
+
+/* Unmap queues for Tx / Rx cleanup */
+struct bnad_skb_unmap {
+ struct sk_buff *skb;
+ DECLARE_PCI_UNMAP_ADDR(dma_addr)
+};
+
+struct bnad_unmap_q {
+ u32 producer_index;
+ u32 consumer_index;
+ u32 q_depth;
+ /* This should be the last one */
+ struct bnad_skb_unmap unmap_array[1];
+};
+
+/* Bit mask values for bnad->cfg_flags */
+#define BNAD_CF_DIM_ENABLED 0x01 /* DIM */
+#define BNAD_CF_PROMISC 0x02
+#define BNAD_CF_ALLMULTI 0x04
+#define BNAD_CF_MSIX 0x08 /* If in MSIx mode */
+
+/* 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_HW_ERROR 2
+#define BNAD_RF_MBOX_IRQ_DISABLED 3
+#define BNAD_RF_TX_STARTED 4
+#define BNAD_RF_RX_STARTED 5
+#define BNAD_RF_DIM_TIMER_RUNNING 6
+#define BNAD_RF_STATS_TIMER_RUNNING 7
+
+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 vlan_group *vlan_grp;
+ /*
+ * These q numbers are global only because
+ * they are used to calculate MSIx vectors.
+ * Actually the exact # of queues are per Tx/Rx
+ * object.
+ */
+ u32 num_tx;
+ u32 num_rx;
+ u32 num_txq_per_tx;
+ u32 num_rxp_per_rx;
+
+ u32 txq_depth;
+ u32 rxq_depth;
+
+ 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];
+
+ u32 rx_csum;
+
+ void __iomem *bar0; /* BAR0 address */
+
+ struct bna bna;
+
+ u32 cfg_flags;
+ unsigned long run_flags;
+
+ struct pci_dev *pcidev;
+ u64 mmio_start;
+ u64 mmio_len;
+
+ u32 msix_num;
+ struct msix_entry *msix_table;
+
+ struct mutex conf_mutex;
+ spinlock_t bna_lock ____cacheline_aligned;
+
+ /* Timers */
+ struct timer_list ioc_timer;
+ struct timer_list dim_timer;
+ struct timer_list stats_timer;
+
+ /* 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 bnad_completion bnad_completions;
+
+ /* Burnt in MAC address */
+ mac_t perm_addr;
+
+ struct tasklet_struct tx_free_tasklet;
+
+ /* Statistics */
+ struct bnad_stats stats;
+
+ struct bnad_diag *diag;
+
+ char adapter_name[BNAD_NAME_LEN];
+ char port_name[BNAD_NAME_LEN];
+ char mbox_irq_name[BNAD_NAME_LEN];
+};
+
+/*
+ * EXTERN VARIABLES
+ */
+extern struct firmware *bfi_fw;
+extern u32 bnad_rxqs_per_cq;
+
+/*
+ * EXTERN PROTOTYPES
+ */
+extern u32 *cna_get_firmware_buf(struct pci_dev *pdev);
+/* Netdev entry point prototypes */
+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);
+
+/* Timer start/stop protos */
+extern void bnad_dim_timer_start(struct bnad *bnad);
+
+/* Statistics */
+extern void bnad_netdev_qstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats);
+extern void bnad_netdev_hwstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats);
+
+/**
+ * MACROS
+ */
+/* To set & get the stats counters */
+#define BNAD_UPDATE_CTR(_bnad, _ctr) \
+ (((_bnad)->stats.drv_stats._ctr)++)
+
+#define BNAD_GET_CTR(_bnad, _ctr) ((_bnad)->stats.drv_stats._ctr)
+
+#define bnad_enable_rx_irq_unsafe(_ccb) \
+{ \
+ 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/bna/bnad_ethtool.c
new file mode 100644
index 000000000000..11fa2ea842c1
--- /dev/null
+++ b/drivers/net/bna/bnad_ethtool.c
@@ -0,0 +1,1277 @@
+/*
+ * 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 "cna.h"
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/rtnetlink.h>
+
+#include "bna.h"
+
+#include "bnad.h"
+
+#define BNAD_NUM_TXF_COUNTERS 12
+#define BNAD_NUM_RXF_COUNTERS 10
+#define BNAD_NUM_CQ_COUNTERS 3
+#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))
+
+static char *bnad_net_stats_strings[BNAD_ETHTOOL_STATS_NUM] = {
+ "rx_packets",
+ "tx_packets",
+ "rx_bytes",
+ "tx_bytes",
+ "rx_errors",
+ "tx_errors",
+ "rx_dropped",
+ "tx_dropped",
+ "multicast",
+ "collisions",
+
+ "rx_length_errors",
+ "rx_over_errors",
+ "rx_crc_errors",
+ "rx_frame_errors",
+ "rx_fifo_errors",
+ "rx_missed_errors",
+
+ "tx_aborted_errors",
+ "tx_carrier_errors",
+ "tx_fifo_errors",
+ "tx_heartbeat_errors",
+ "tx_window_errors",
+
+ "rx_compressed",
+ "tx_compressed",
+
+ "netif_queue_stop",
+ "netif_queue_wakeup",
+ "tso4",
+ "tso6",
+ "tso_err",
+ "tcpcsum_offload",
+ "udpcsum_offload",
+ "csum_help",
+ "csum_help_err",
+ "hw_stats_updates",
+ "netif_rx_schedule",
+ "netif_rx_complete",
+ "netif_rx_dropped",
+
+ "link_toggle",
+ "cee_up",
+
+ "rxp_info_alloc_failed",
+ "mbox_intr_disabled",
+ "mbox_intr_enabled",
+ "tx_unmap_q_alloc_failed",
+ "rx_unmap_q_alloc_failed",
+ "rxbuf_alloc_failed",
+
+ "mac_frame_64",
+ "mac_frame_65_127",
+ "mac_frame_128_255",
+ "mac_frame_256_511",
+ "mac_frame_512_1023",
+ "mac_frame_1024_1518",
+ "mac_frame_1518_1522",
+ "mac_rx_bytes",
+ "mac_rx_packets",
+ "mac_rx_fcs_error",
+ "mac_rx_multicast",
+ "mac_rx_broadcast",
+ "mac_rx_control_frames",
+ "mac_rx_pause",
+ "mac_rx_unknown_opcode",
+ "mac_rx_alignment_error",
+ "mac_rx_frame_length_error",
+ "mac_rx_code_error",
+ "mac_rx_carrier_sense_error",
+ "mac_rx_undersize",
+ "mac_rx_oversize",
+ "mac_rx_fragments",
+ "mac_rx_jabber",
+ "mac_rx_drop",
+
+ "mac_tx_bytes",
+ "mac_tx_packets",
+ "mac_tx_multicast",
+ "mac_tx_broadcast",
+ "mac_tx_pause",
+ "mac_tx_deferral",
+ "mac_tx_excessive_deferral",
+ "mac_tx_single_collision",
+ "mac_tx_muliple_collision",
+ "mac_tx_late_collision",
+ "mac_tx_excessive_collision",
+ "mac_tx_total_collision",
+ "mac_tx_pause_honored",
+ "mac_tx_drop",
+ "mac_tx_jabber",
+ "mac_tx_fcs_error",
+ "mac_tx_control_frame",
+ "mac_tx_oversize",
+ "mac_tx_undersize",
+ "mac_tx_fragments",
+
+ "bpc_tx_pause_0",
+ "bpc_tx_pause_1",
+ "bpc_tx_pause_2",
+ "bpc_tx_pause_3",
+ "bpc_tx_pause_4",
+ "bpc_tx_pause_5",
+ "bpc_tx_pause_6",
+ "bpc_tx_pause_7",
+ "bpc_tx_zero_pause_0",
+ "bpc_tx_zero_pause_1",
+ "bpc_tx_zero_pause_2",
+ "bpc_tx_zero_pause_3",
+ "bpc_tx_zero_pause_4",
+ "bpc_tx_zero_pause_5",
+ "bpc_tx_zero_pause_6",
+ "bpc_tx_zero_pause_7",
+ "bpc_tx_first_pause_0",
+ "bpc_tx_first_pause_1",
+ "bpc_tx_first_pause_2",
+ "bpc_tx_first_pause_3",
+ "bpc_tx_first_pause_4",
+ "bpc_tx_first_pause_5",
+ "bpc_tx_first_pause_6",
+ "bpc_tx_first_pause_7",
+
+ "bpc_rx_pause_0",
+ "bpc_rx_pause_1",
+ "bpc_rx_pause_2",
+ "bpc_rx_pause_3",
+ "bpc_rx_pause_4",
+ "bpc_rx_pause_5",
+ "bpc_rx_pause_6",
+ "bpc_rx_pause_7",
+ "bpc_rx_zero_pause_0",
+ "bpc_rx_zero_pause_1",
+ "bpc_rx_zero_pause_2",
+ "bpc_rx_zero_pause_3",
+ "bpc_rx_zero_pause_4",
+ "bpc_rx_zero_pause_5",
+ "bpc_rx_zero_pause_6",
+ "bpc_rx_zero_pause_7",
+ "bpc_rx_first_pause_0",
+ "bpc_rx_first_pause_1",
+ "bpc_rx_first_pause_2",
+ "bpc_rx_first_pause_3",
+ "bpc_rx_first_pause_4",
+ "bpc_rx_first_pause_5",
+ "bpc_rx_first_pause_6",
+ "bpc_rx_first_pause_7",
+
+ "rad_rx_frames",
+ "rad_rx_octets",
+ "rad_rx_vlan_frames",
+ "rad_rx_ucast",
+ "rad_rx_ucast_octets",
+ "rad_rx_ucast_vlan",
+ "rad_rx_mcast",
+ "rad_rx_mcast_octets",
+ "rad_rx_mcast_vlan",
+ "rad_rx_bcast",
+ "rad_rx_bcast_octets",
+ "rad_rx_bcast_vlan",
+ "rad_rx_drops",
+
+ "fc_rx_ucast_octets",
+ "fc_rx_ucast",
+ "fc_rx_ucast_vlan",
+ "fc_rx_mcast_octets",
+ "fc_rx_mcast",
+ "fc_rx_mcast_vlan",
+ "fc_rx_bcast_octets",
+ "fc_rx_bcast",
+ "fc_rx_bcast_vlan",
+
+ "fc_tx_ucast_octets",
+ "fc_tx_ucast",
+ "fc_tx_ucast_vlan",
+ "fc_tx_mcast_octets",
+ "fc_tx_mcast",
+ "fc_tx_mcast_vlan",
+ "fc_tx_bcast_octets",
+ "fc_tx_bcast",
+ "fc_tx_bcast_vlan",
+ "fc_tx_parity_errors",
+ "fc_tx_timeout",
+ "fc_tx_fid_parity_errors",
+};
+
+static int
+bnad_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+ cmd->supported = SUPPORTED_10000baseT_Full;
+ cmd->advertising = ADVERTISED_10000baseT_Full;
+ cmd->autoneg = AUTONEG_DISABLE;
+ cmd->supported |= SUPPORTED_FIBRE;
+ cmd->advertising |= ADVERTISED_FIBRE;
+ cmd->port = PORT_FIBRE;
+ cmd->phy_address = 0;
+
+ if (netif_carrier_ok(netdev)) {
+ cmd->speed = SPEED_10000;
+ cmd->duplex = DUPLEX_FULL;
+ } else {
+ cmd->speed = -1;
+ cmd->duplex = -1;
+ }
+ cmd->transceiver = XCVR_EXTERNAL;
+ cmd->maxtxpkt = 0;
+ cmd->maxrxpkt = 0;
+
+ return 0;
+}
+
+static int
+bnad_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+ /* 10G full duplex setting supported only */
+ if (cmd->autoneg == AUTONEG_ENABLE)
+ return -EOPNOTSUPP; else {
+ if ((cmd->speed == SPEED_10000) && (cmd->duplex == DUPLEX_FULL))
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static void
+bnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ struct bfa_ioc_attr *ioc_attr;
+ unsigned long flags;
+
+ strcpy(drvinfo->driver, BNAD_NAME);
+ strcpy(drvinfo->version, BNAD_VERSION);
+
+ ioc_attr = kzalloc(sizeof(*ioc_attr), GFP_KERNEL);
+ if (ioc_attr) {
+ memset(ioc_attr, 0, sizeof(*ioc_attr));
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bfa_nw_ioc_get_attr(&bnad->bna.device.ioc, ioc_attr);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ strncpy(drvinfo->fw_version, ioc_attr->adapter_attr.fw_ver,
+ sizeof(drvinfo->fw_version) - 1);
+ kfree(ioc_attr);
+ }
+
+ 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_REG);
+ BNAD_GET_REG(HOST_SEM1_REG);
+ BNAD_GET_REG(HOST_SEM2_REG);
+ BNAD_GET_REG(HOST_SEM3_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)
+{
+ wolinfo->supported = 0;
+ wolinfo->wolopts = 0;
+}
+
+static int
+bnad_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ unsigned long flags;
+
+ /* Lock rqd. to access bnad->bna_lock */
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ coalesce->use_adaptive_rx_coalesce =
+ (bnad->cfg_flags & BNAD_CF_DIM_ENABLED) ? true : false;
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ coalesce->rx_coalesce_usecs = bnad->rx_coalescing_timeo *
+ BFI_COALESCING_TIMER_UNIT;
+ coalesce->tx_coalesce_usecs = bnad->tx_coalescing_timeo *
+ BFI_COALESCING_TIMER_UNIT;
+ coalesce->tx_max_coalesced_frames = BFI_TX_INTERPKT_COUNT;
+
+ return 0;
+}
+
+static int
+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;
+
+ if (coalesce->rx_coalesce_usecs == 0 ||
+ coalesce->rx_coalesce_usecs >
+ BFI_MAX_COALESCING_TIMEO * BFI_COALESCING_TIMER_UNIT)
+ return -EINVAL;
+
+ if (coalesce->tx_coalesce_usecs == 0 ||
+ coalesce->tx_coalesce_usecs >
+ BFI_MAX_COALESCING_TIMEO * BFI_COALESCING_TIMER_UNIT)
+ return -EINVAL;
+
+ mutex_lock(&bnad->conf_mutex);
+ /*
+ * Do not need to store rx_coalesce_usecs here
+ * Every time DIM is disabled, we can get it from the
+ * stack.
+ */
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ if (coalesce->use_adaptive_rx_coalesce) {
+ if (!(bnad->cfg_flags & BNAD_CF_DIM_ENABLED)) {
+ bnad->cfg_flags |= BNAD_CF_DIM_ENABLED;
+ bnad_dim_timer_start(bnad);
+ }
+ } 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) {
+ 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);
+ }
+ bnad_rx_coalescing_timeo_set(bnad);
+ }
+ }
+ if (bnad->tx_coalescing_timeo != coalesce->tx_coalesce_usecs /
+ BFI_COALESCING_TIMER_UNIT) {
+ bnad->tx_coalescing_timeo = coalesce->tx_coalesce_usecs /
+ BFI_COALESCING_TIMER_UNIT;
+ bnad_tx_coalescing_timeo_set(bnad);
+ }
+
+ if (bnad->rx_coalescing_timeo != coalesce->rx_coalesce_usecs /
+ BFI_COALESCING_TIMER_UNIT) {
+ bnad->rx_coalescing_timeo = coalesce->rx_coalesce_usecs /
+ BFI_COALESCING_TIMER_UNIT;
+
+ if (!(bnad->cfg_flags & BNAD_CF_DIM_ENABLED))
+ bnad_rx_coalescing_timeo_set(bnad);
+
+ }
+
+ /* Add Tx Inter-pkt DMA count? */
+
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ mutex_unlock(&bnad->conf_mutex);
+ return 0;
+}
+
+static void
+bnad_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ringparam)
+{
+ 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_pending = bnad->rxq_depth;
+ ringparam->rx_mini_max_pending = 0;
+ ringparam->rx_jumbo_max_pending = 0;
+ ringparam->tx_pending = bnad->txq_depth;
+}
+
+static int
+bnad_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ringparam)
+{
+ int i, current_err, err = 0;
+ struct bnad *bnad = netdev_priv(netdev);
+
+ mutex_lock(&bnad->conf_mutex);
+ if (ringparam->rx_pending == bnad->rxq_depth &&
+ ringparam->tx_pending == bnad->txq_depth) {
+ mutex_unlock(&bnad->conf_mutex);
+ return 0;
+ }
+
+ if (ringparam->rx_pending < BNAD_MIN_Q_DEPTH ||
+ ringparam->rx_pending > BNAD_MAX_Q_DEPTH / bnad_rxqs_per_cq ||
+ !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 ||
+ !BNA_POWER_OF_2(ringparam->tx_pending)) {
+ mutex_unlock(&bnad->conf_mutex);
+ return -EINVAL;
+ }
+
+ if (ringparam->rx_pending != bnad->rxq_depth) {
+ bnad->rxq_depth = ringparam->rx_pending;
+ for (i = 0; i < bnad->num_rx; i++) {
+ if (!bnad->rx_info[i].rx)
+ continue;
+ bnad_cleanup_rx(bnad, i);
+ current_err = bnad_setup_rx(bnad, i);
+ if (current_err && !err)
+ err = current_err;
+ }
+ }
+ if (ringparam->tx_pending != bnad->txq_depth) {
+ bnad->txq_depth = ringparam->tx_pending;
+ for (i = 0; i < bnad->num_tx; i++) {
+ if (!bnad->tx_info[i].tx)
+ continue;
+ bnad_cleanup_tx(bnad, i);
+ current_err = bnad_setup_tx(bnad, i);
+ if (current_err && !err)
+ err = current_err;
+ }
+ }
+
+ mutex_unlock(&bnad->conf_mutex);
+ return err;
+}
+
+static void
+bnad_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pauseparam)
+{
+ 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;
+}
+
+static int
+bnad_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pauseparam)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ struct bna_pause_config pause_config;
+ unsigned long flags;
+
+ if (pauseparam->autoneg == AUTONEG_ENABLE)
+ 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) {
+ 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);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ }
+ mutex_unlock(&bnad->conf_mutex);
+ return 0;
+}
+
+static u32
+bnad_get_rx_csum(struct net_device *netdev)
+{
+ u32 rx_csum;
+ struct bnad *bnad = netdev_priv(netdev);
+
+ rx_csum = bnad->rx_csum;
+ return rx_csum;
+}
+
+static int
+bnad_set_rx_csum(struct net_device *netdev, u32 rx_csum)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+
+ mutex_lock(&bnad->conf_mutex);
+ bnad->rx_csum = rx_csum;
+ mutex_unlock(&bnad->conf_mutex);
+ return 0;
+}
+
+static int
+bnad_set_tx_csum(struct net_device *netdev, u32 tx_csum)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+
+ mutex_lock(&bnad->conf_mutex);
+ if (tx_csum) {
+ netdev->features |= NETIF_F_IP_CSUM;
+ netdev->features |= NETIF_F_IPV6_CSUM;
+ } else {
+ netdev->features &= ~NETIF_F_IP_CSUM;
+ netdev->features &= ~NETIF_F_IPV6_CSUM;
+ }
+ mutex_unlock(&bnad->conf_mutex);
+ return 0;
+}
+
+static int
+bnad_set_tso(struct net_device *netdev, u32 tso)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+
+ mutex_lock(&bnad->conf_mutex);
+ if (tso) {
+ netdev->features |= NETIF_F_TSO;
+ netdev->features |= NETIF_F_TSO6;
+ } else {
+ netdev->features &= ~NETIF_F_TSO;
+ netdev->features &= ~NETIF_F_TSO6;
+ }
+ mutex_unlock(&bnad->conf_mutex);
+ return 0;
+}
+
+static void
+bnad_get_strings(struct net_device *netdev, u32 stringset, u8 * string)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ int i, j, q_num;
+ u64 bmap;
+
+ mutex_lock(&bnad->conf_mutex);
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < BNAD_ETHTOOL_STATS_NUM; i++) {
+ BUG_ON(!(strlen(bnad_net_stats_strings[i]) <
+ ETH_GSTRING_LEN));
+ memcpy(string, bnad_net_stats_strings[i],
+ 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++) {
+ if (bmap & 1) {
+ sprintf(string, "txf%d_ucast_octets", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txf%d_ucast", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txf%d_ucast_vlan", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txf%d_mcast_octets", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txf%d_mcast", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txf%d_mcast_vlan", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txf%d_bcast_octets", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txf%d_bcast", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txf%d_bcast_vlan", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txf%d_errors", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txf%d_filter_vlan", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txf%d_filter_mac_sa", i);
+ string += ETH_GSTRING_LEN;
+ }
+ 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++) {
+ if (bmap & 1) {
+ sprintf(string, "rxf%d_ucast_octets", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_ucast", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_ucast_vlan", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_mcast_octets", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_mcast", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_mcast_vlan", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_bcast_octets", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_bcast", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_bcast_vlan", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_frame_drops", i);
+ string += ETH_GSTRING_LEN;
+ }
+ bmap >>= 1;
+ }
+
+ q_num = 0;
+ for (i = 0; i < bnad->num_rx; i++) {
+ if (!bnad->rx_info[i].rx)
+ continue;
+ for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+ sprintf(string, "cq%d_producer_index", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "cq%d_consumer_index", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "cq%d_hw_producer_index",
+ q_num);
+ string += ETH_GSTRING_LEN;
+ q_num++;
+ }
+ }
+
+ q_num = 0;
+ for (i = 0; i < bnad->num_rx; i++) {
+ if (!bnad->rx_info[i].rx)
+ continue;
+ for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+ sprintf(string, "rxq%d_packets", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxq%d_bytes", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxq%d_packets_with_error",
+ q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxq%d_allocbuf_failed", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxq%d_producer_index", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxq%d_consumer_index", q_num);
+ string += ETH_GSTRING_LEN;
+ q_num++;
+ if (bnad->rx_info[i].rx_ctrl[j].ccb &&
+ bnad->rx_info[i].rx_ctrl[j].ccb->
+ rcb[1] &&
+ bnad->rx_info[i].rx_ctrl[j].ccb->
+ rcb[1]->rxq) {
+ sprintf(string, "rxq%d_packets", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxq%d_bytes", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string,
+ "rxq%d_packets_with_error", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxq%d_allocbuf_failed",
+ q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxq%d_producer_index",
+ q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxq%d_consumer_index",
+ q_num);
+ string += ETH_GSTRING_LEN;
+ q_num++;
+ }
+ }
+ }
+
+ q_num = 0;
+ for (i = 0; i < bnad->num_tx; i++) {
+ if (!bnad->tx_info[i].tx)
+ continue;
+ for (j = 0; j < bnad->num_txq_per_tx; j++) {
+ sprintf(string, "txq%d_packets", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txq%d_bytes", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txq%d_producer_index", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txq%d_consumer_index", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txq%d_hw_consumer_index",
+ q_num);
+ string += ETH_GSTRING_LEN;
+ q_num++;
+ }
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ mutex_unlock(&bnad->conf_mutex);
+}
+
+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;
+
+ 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++) {
+ 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++) {
+ if (bmap & 1)
+ rxf_active_num++;
+ bmap >>= 1;
+ }
+ count = BNAD_ETHTOOL_STATS_NUM +
+ txf_active_num * BNAD_NUM_TXF_COUNTERS +
+ rxf_active_num * BNAD_NUM_RXF_COUNTERS;
+
+ for (i = 0; i < bnad->num_rx; i++) {
+ if (!bnad->rx_info[i].rx)
+ continue;
+ count += bnad->num_rxp_per_rx * BNAD_NUM_CQ_COUNTERS;
+ count += bnad->num_rxp_per_rx * BNAD_NUM_RXQ_COUNTERS;
+ for (j = 0; j < bnad->num_rxp_per_rx; j++)
+ if (bnad->rx_info[i].rx_ctrl[j].ccb &&
+ bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
+ bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1]->rxq)
+ count += BNAD_NUM_RXQ_COUNTERS;
+ }
+
+ for (i = 0; i < bnad->num_tx; i++) {
+ if (!bnad->tx_info[i].tx)
+ continue;
+ count += bnad->num_txq_per_tx * BNAD_NUM_TXQ_COUNTERS;
+ }
+ return count;
+}
+
+static int
+bnad_per_q_stats_fill(struct bnad *bnad, u64 *buf, int bi)
+{
+ int i, j;
+ struct bna_rcb *rcb = NULL;
+ struct bna_tcb *tcb = NULL;
+
+ for (i = 0; i < bnad->num_rx; i++) {
+ if (!bnad->rx_info[i].rx)
+ continue;
+ for (j = 0; j < bnad->num_rxp_per_rx; j++)
+ if (bnad->rx_info[i].rx_ctrl[j].ccb &&
+ bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0] &&
+ bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0]->rxq) {
+ buf[bi++] = bnad->rx_info[i].rx_ctrl[j].
+ ccb->producer_index;
+ buf[bi++] = 0; /* ccb->consumer_index */
+ buf[bi++] = *(bnad->rx_info[i].rx_ctrl[j].
+ ccb->hw_producer_index);
+ }
+ }
+ for (i = 0; i < bnad->num_rx; i++) {
+ if (!bnad->rx_info[i].rx)
+ continue;
+ for (j = 0; j < bnad->num_rxp_per_rx; j++)
+ if (bnad->rx_info[i].rx_ctrl[j].ccb) {
+ if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0] &&
+ bnad->rx_info[i].rx_ctrl[j].ccb->
+ rcb[0]->rxq) {
+ rcb = bnad->rx_info[i].rx_ctrl[j].
+ ccb->rcb[0];
+ buf[bi++] = rcb->rxq->rx_packets;
+ buf[bi++] = rcb->rxq->rx_bytes;
+ buf[bi++] = rcb->rxq->
+ rx_packets_with_error;
+ buf[bi++] = rcb->rxq->
+ rxbuf_alloc_failed;
+ buf[bi++] = rcb->producer_index;
+ buf[bi++] = rcb->consumer_index;
+ }
+ if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
+ bnad->rx_info[i].rx_ctrl[j].ccb->
+ rcb[1]->rxq) {
+ rcb = bnad->rx_info[i].rx_ctrl[j].
+ ccb->rcb[1];
+ buf[bi++] = rcb->rxq->rx_packets;
+ buf[bi++] = rcb->rxq->rx_bytes;
+ buf[bi++] = rcb->rxq->
+ rx_packets_with_error;
+ buf[bi++] = rcb->rxq->
+ rxbuf_alloc_failed;
+ buf[bi++] = rcb->producer_index;
+ buf[bi++] = rcb->consumer_index;
+ }
+ }
+ }
+
+ for (i = 0; i < bnad->num_tx; i++) {
+ if (!bnad->tx_info[i].tx)
+ continue;
+ for (j = 0; j < bnad->num_txq_per_tx; j++)
+ if (bnad->tx_info[i].tcb[j] &&
+ bnad->tx_info[i].tcb[j]->txq) {
+ tcb = bnad->tx_info[i].tcb[j];
+ buf[bi++] = tcb->txq->tx_packets;
+ buf[bi++] = tcb->txq->tx_bytes;
+ buf[bi++] = tcb->producer_index;
+ buf[bi++] = tcb->consumer_index;
+ buf[bi++] = *(tcb->hw_consumer_index);
+ }
+ }
+
+ return bi;
+}
+
+static void
+bnad_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats,
+ u64 *buf)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ int i, j, bi;
+ unsigned long flags;
+ struct rtnl_link_stats64 *net_stats64;
+ u64 *stats64;
+ u64 bmap;
+
+ mutex_lock(&bnad->conf_mutex);
+ if (bnad_get_stats_count_locked(netdev) != stats->n_stats) {
+ mutex_unlock(&bnad->conf_mutex);
+ return;
+ }
+
+ /*
+ * Used bna_lock to sync reads from bna_stats, which is written
+ * under the same lock
+ */
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bi = 0;
+ memset(buf, 0, stats->n_stats * sizeof(u64));
+
+ net_stats64 = (struct rtnl_link_stats64 *)buf;
+ bnad_netdev_qstats_fill(bnad, net_stats64);
+ bnad_netdev_hwstats_fill(bnad, net_stats64);
+
+ bi = sizeof(*net_stats64) / sizeof(u64);
+
+ /* Fill driver stats into ethtool buffers */
+ stats64 = (u64 *)&bnad->stats.drv_stats;
+ for (i = 0; i < sizeof(struct bnad_drv_stats) / sizeof(u64); i++)
+ buf[bi++] = stats64[i];
+
+ /* Fill hardware stats excluding the rxf/txf into ethtool bufs */
+ stats64 = (u64 *) bnad->stats.bna_stats->hw_stats;
+ for (i = 0;
+ i < offsetof(struct bfi_ll_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++) {
+ if (bmap & 1) {
+ stats64 = (u64 *)&bnad->stats.bna_stats->
+ hw_stats->txf_stats[i];
+ for (j = 0; j < sizeof(struct bfi_ll_stats_txf) /
+ sizeof(u64); j++)
+ buf[bi++] = stats64[j];
+ }
+ bmap >>= 1;
+ }
+
+ /* 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++) {
+ if (bmap & 1) {
+ stats64 = (u64 *)&bnad->stats.bna_stats->
+ hw_stats->rxf_stats[i];
+ for (j = 0; j < sizeof(struct bfi_ll_stats_rxf) /
+ sizeof(u64); j++)
+ buf[bi++] = stats64[j];
+ }
+ bmap >>= 1;
+ }
+
+ /* Fill per Q stats into ethtool buffers */
+ bi = bnad_per_q_stats_fill(bnad, buf, bi);
+
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ mutex_unlock(&bnad->conf_mutex);
+}
+
+static int
+bnad_get_sset_count(struct net_device *netdev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return bnad_get_stats_count_locked(netdev);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+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,
+ .set_coalesce = bnad_set_coalesce,
+ .get_ringparam = bnad_get_ringparam,
+ .set_ringparam = bnad_set_ringparam,
+ .get_pauseparam = bnad_get_pauseparam,
+ .set_pauseparam = bnad_set_pauseparam,
+ .get_rx_csum = bnad_get_rx_csum,
+ .set_rx_csum = bnad_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = bnad_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = bnad_set_tso,
+ .get_strings = bnad_get_strings,
+ .get_ethtool_stats = bnad_get_ethtool_stats,
+ .get_sset_count = bnad_get_sset_count
+};
+
+void
+bnad_set_ethtool_ops(struct net_device *netdev)
+{
+ SET_ETHTOOL_OPS(netdev, &bnad_ethtool_ops);
+}
diff --git a/drivers/net/bna/cna.h b/drivers/net/bna/cna.h
new file mode 100644
index 000000000000..bbd39dc65972
--- /dev/null
+++ b/drivers/net/bna/cna.h
@@ -0,0 +1,81 @@
+/*
+ * 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) 2006-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __CNA_H__
+#define __CNA_H__
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/timer.h>
+#include <linux/interrupt.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(__mod, __event) do { \
+ pr_err("SM Assertion failure: %s: %d: event = %d", __FILE__, __LINE__, \
+ __event); \
+} while (0)
+
+extern char bfa_version[];
+
+#define CNA_FW_FILE_CT "ctfw_cna.bin"
+#define FC_SYMNAME_MAX 256 /*!< max name server symbolic name size */
+
+#pragma pack(1)
+
+#define MAC_ADDRLEN (6)
+typedef struct mac { u8 mac[MAC_ADDRLEN]; } mac_t;
+
+#pragma pack()
+
+#define bfa_q_first(_q) ((void *)(((struct list_head *) (_q))->next))
+#define bfa_q_next(_qe) (((struct list_head *) (_qe))->next)
+#define bfa_q_prev(_qe) (((struct list_head *) (_qe))->prev)
+
+/*
+ * bfa_q_qe_init - to initialize a queue element
+ */
+#define bfa_q_qe_init(_qe) { \
+ bfa_q_next(_qe) = (struct list_head *) NULL; \
+ bfa_q_prev(_qe) = (struct list_head *) NULL; \
+}
+
+/*
+ * bfa_q_deq - dequeue an element from head of the queue
+ */
+#define bfa_q_deq(_q, _qe) { \
+ if (!list_empty(_q)) { \
+ (*((struct list_head **) (_qe))) = bfa_q_next(_q); \
+ bfa_q_prev(bfa_q_next(*((struct list_head **) _qe))) = \
+ (struct list_head *) (_q); \
+ bfa_q_next(_q) = bfa_q_next(*((struct list_head **) _qe)); \
+ bfa_q_qe_init(*((struct list_head **) _qe)); \
+ } else { \
+ *((struct list_head **) (_qe)) = (struct list_head *) NULL; \
+ } \
+}
+
+#endif /* __CNA_H__ */
diff --git a/drivers/net/bna/cna_fwimg.c b/drivers/net/bna/cna_fwimg.c
new file mode 100644
index 000000000000..e8f4ecd9ebb5
--- /dev/null
+++ b/drivers/net/bna/cna_fwimg.c
@@ -0,0 +1,64 @@
+/*
+ * 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 <linux/firmware.h>
+#include "cna.h"
+
+const struct firmware *bfi_fw;
+static u32 *bfi_image_ct_cna;
+static u32 bfi_image_ct_cna_size;
+
+static u32 *
+cna_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
+ u32 *bfi_image_size, char *fw_name)
+{
+ const struct firmware *fw;
+
+ if (request_firmware(&fw, fw_name, &pdev->dev)) {
+ pr_alert("Can't locate firmware %s\n", fw_name);
+ goto error;
+ }
+
+ *bfi_image = (u32 *)fw->data;
+ *bfi_image_size = fw->size/sizeof(u32);
+ bfi_fw = fw;
+
+ return *bfi_image;
+error:
+ return NULL;
+}
+
+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;
+}
+
+u32 *
+bfa_cb_image_get_chunk(int type, u32 off)
+{
+ return (u32 *)(bfi_image_ct_cna + off);
+}
+
+u32
+bfa_cb_image_get_size(int type)
+{
+ return bfi_image_ct_cna_size;
+}
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index e6a803f1c507..062600be073b 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -37,9 +37,6 @@
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/if_vlan.h>
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-#define BCM_VLAN 1
-#endif
#include <net/ip.h>
#include <net/tcp.h>
#include <net/checksum.h>
@@ -49,6 +46,7 @@
#include <linux/cache.h>
#include <linux/firmware.h>
#include <linux/log2.h>
+#include <linux/aer.h>
#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
#define BCM_CNIC 1
@@ -58,13 +56,13 @@
#include "bnx2_fw.h"
#define DRV_MODULE_NAME "bnx2"
-#define DRV_MODULE_VERSION "2.0.17"
-#define DRV_MODULE_RELDATE "July 18, 2010"
-#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-5.0.0.j6.fw"
-#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-5.0.0.j3.fw"
-#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-5.0.0.j15.fw"
-#define FW_RV2P_FILE_09_Ax "bnx2/bnx2-rv2p-09ax-5.0.0.j10.fw"
-#define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-5.0.0.j10.fw"
+#define DRV_MODULE_VERSION "2.0.18"
+#define DRV_MODULE_RELDATE "Oct 7, 2010"
+#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-6.0.15.fw"
+#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-6.0.15.fw"
+#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-6.0.17.fw"
+#define FW_RV2P_FILE_09_Ax "bnx2/bnx2-rv2p-09ax-6.0.17.fw"
+#define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-6.0.17.fw"
#define RUN_AT(x) (jiffies + (x))
@@ -265,7 +263,7 @@ static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)
if (diff == TX_DESC_CNT)
diff = MAX_TX_DESC_CNT;
}
- return (bp->tx_ring_size - diff);
+ return bp->tx_ring_size - diff;
}
static u32
@@ -298,7 +296,7 @@ bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
static u32
bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
{
- return (bnx2_reg_rd_ind(bp, bp->shmem_base + offset));
+ return bnx2_reg_rd_ind(bp, bp->shmem_base + offset);
}
static void
@@ -976,9 +974,9 @@ bnx2_report_fw_link(struct bnx2 *bp)
static char *
bnx2_xceiver_str(struct bnx2 *bp)
{
- return ((bp->phy_port == PORT_FIBRE) ? "SerDes" :
+ return (bp->phy_port == PORT_FIBRE) ? "SerDes" :
((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" :
- "Copper"));
+ "Copper");
}
static void
@@ -1268,30 +1266,9 @@ bnx2_init_rx_context(struct bnx2 *bp, u32 cid)
val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
val |= 0x02 << 8;
- if (CHIP_NUM(bp) == CHIP_NUM_5709) {
- u32 lo_water, hi_water;
-
- if (bp->flow_ctrl & FLOW_CTRL_TX)
- lo_water = BNX2_L2CTX_LO_WATER_MARK_DEFAULT;
- else
- lo_water = BNX2_L2CTX_LO_WATER_MARK_DIS;
- if (lo_water >= bp->rx_ring_size)
- lo_water = 0;
-
- hi_water = min_t(int, bp->rx_ring_size / 4, lo_water + 16);
-
- if (hi_water <= lo_water)
- lo_water = 0;
-
- hi_water /= BNX2_L2CTX_HI_WATER_MARK_SCALE;
- lo_water /= BNX2_L2CTX_LO_WATER_MARK_SCALE;
+ if (bp->flow_ctrl & FLOW_CTRL_TX)
+ val |= BNX2_L2CTX_FLOW_CTRL_ENABLE;
- if (hi_water > 0xf)
- hi_water = 0xf;
- else if (hi_water == 0)
- lo_water = 0;
- val |= lo_water | (hi_water << BNX2_L2CTX_HI_WATER_MARK_SHIFT);
- }
bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
}
@@ -1372,8 +1349,7 @@ bnx2_set_mac_link(struct bnx2 *bp)
/* Acknowledge the interrupt. */
REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
- if (CHIP_NUM(bp) == CHIP_NUM_5709)
- bnx2_init_all_rx_contexts(bp);
+ bnx2_init_all_rx_contexts(bp);
}
static void
@@ -1757,7 +1733,7 @@ __acquires(&bp->phy_lock)
u32 new_adv = 0;
if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
- return (bnx2_setup_remote_phy(bp, port));
+ return bnx2_setup_remote_phy(bp, port);
if (!(bp->autoneg & AUTONEG_SPEED)) {
u32 new_bmcr;
@@ -2170,10 +2146,10 @@ __acquires(&bp->phy_lock)
return 0;
if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
- return (bnx2_setup_serdes_phy(bp, port));
+ return bnx2_setup_serdes_phy(bp, port);
}
else {
- return (bnx2_setup_copper_phy(bp));
+ return bnx2_setup_copper_phy(bp);
}
}
@@ -3108,8 +3084,6 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
struct sw_bd *rx_buf, *next_rx_buf;
struct sk_buff *skb;
dma_addr_t dma_addr;
- u16 vtag = 0;
- int hw_vlan __maybe_unused = 0;
sw_ring_cons = RX_RING_IDX(sw_cons);
sw_ring_prod = RX_RING_IDX(sw_prod);
@@ -3189,23 +3163,8 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
goto next_rx;
if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
- !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) {
- vtag = rx_hdr->l2_fhdr_vlan_tag;
-#ifdef BCM_VLAN
- if (bp->vlgrp)
- hw_vlan = 1;
- else
-#endif
- {
- struct vlan_ethhdr *ve = (struct vlan_ethhdr *)
- __skb_push(skb, 4);
-
- memmove(ve, skb->data + 4, ETH_ALEN * 2);
- ve->h_vlan_proto = htons(ETH_P_8021Q);
- ve->h_vlan_TCI = htons(vtag);
- len += 4;
- }
- }
+ !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG))
+ __vlan_hwaccel_put_tag(skb, rx_hdr->l2_fhdr_vlan_tag);
skb->protocol = eth_type_trans(skb, bp->dev);
@@ -3217,7 +3176,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
}
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
if (bp->rx_csum &&
(status & (L2_FHDR_STATUS_TCP_SEGMENT |
L2_FHDR_STATUS_UDP_DATAGRAM))) {
@@ -3232,14 +3191,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
skb->rxhash = rx_hdr->l2_fhdr_hash;
skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]);
-
-#ifdef BCM_VLAN
- if (hw_vlan)
- vlan_gro_receive(&bnapi->napi, bp->vlgrp, vtag, skb);
- else
-#endif
- napi_gro_receive(&bnapi->napi, skb);
-
+ napi_gro_receive(&bnapi->napi, skb);
rx_pkt++;
next_rx:
@@ -3554,13 +3506,9 @@ bnx2_set_rx_mode(struct net_device *dev)
rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
-#ifdef BCM_VLAN
- if (!bp->vlgrp && (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
+ if (!(dev->features & NETIF_F_HW_VLAN_RX) &&
+ (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
-#else
- if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)
- rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
-#endif
if (dev->flags & IFF_PROMISC) {
/* Promiscuous mode. */
rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
@@ -4973,6 +4921,11 @@ bnx2_init_chip(struct bnx2 *bp)
REG_WR(bp, BNX2_HC_CONFIG, val);
+ if (bp->rx_ticks < 25)
+ bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 1);
+ else
+ bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 0);
+
for (i = 1; i < bp->irq_nvecs; i++) {
u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
BNX2_HC_SB_CONFIG_1;
@@ -5241,18 +5194,20 @@ bnx2_init_all_rings(struct bnx2 *bp)
bnx2_init_rx_ring(bp, i);
if (bp->num_rx_rings > 1) {
- u32 tbl_32;
- u8 *tbl = (u8 *) &tbl_32;
-
- bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ,
- BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES);
+ u32 tbl_32 = 0;
for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
- tbl[i % 4] = i % (bp->num_rx_rings - 1);
- if ((i % 4) == 3)
- bnx2_reg_wr_ind(bp,
- BNX2_RXP_SCRATCH_RSS_TBL + i,
- cpu_to_be32(tbl_32));
+ int shift = (i % 8) << 2;
+
+ tbl_32 |= (i % (bp->num_rx_rings - 1)) << shift;
+ if ((i % 8) == 7) {
+ REG_WR(bp, BNX2_RLUP_RSS_DATA, tbl_32);
+ REG_WR(bp, BNX2_RLUP_RSS_COMMAND, (i >> 3) |
+ BNX2_RLUP_RSS_COMMAND_RSS_WRITE_MASK |
+ BNX2_RLUP_RSS_COMMAND_WRITE |
+ BNX2_RLUP_RSS_COMMAND_HASH_MASK);
+ tbl_32 = 0;
+ }
}
val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
@@ -6201,7 +6156,7 @@ bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
}
}
-static void
+static int
bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
{
int cpus = num_online_cpus();
@@ -6230,9 +6185,10 @@ bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
}
bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs);
- bp->dev->real_num_tx_queues = bp->num_tx_rings;
+ netif_set_real_num_tx_queues(bp->dev, bp->num_tx_rings);
bp->num_rx_rings = bp->irq_nvecs;
+ return netif_set_real_num_rx_queues(bp->dev, bp->num_rx_rings);
}
/* Called with rtnl_lock */
@@ -6247,7 +6203,9 @@ bnx2_open(struct net_device *dev)
bnx2_set_power_state(bp, PCI_D0);
bnx2_disable_int(bp);
- bnx2_setup_int_mode(bp, disable_msi);
+ rc = bnx2_setup_int_mode(bp, disable_msi);
+ if (rc)
+ goto open_err;
bnx2_init_napi(bp);
bnx2_napi_enable(bp);
rc = bnx2_alloc_mem(bp);
@@ -6376,29 +6334,6 @@ bnx2_tx_timeout(struct net_device *dev)
schedule_work(&bp->reset_task);
}
-#ifdef BCM_VLAN
-/* Called with rtnl_lock */
-static void
-bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
-{
- struct bnx2 *bp = netdev_priv(dev);
-
- if (netif_running(dev))
- bnx2_netif_stop(bp, false);
-
- bp->vlgrp = vlgrp;
-
- if (!netif_running(dev))
- return;
-
- bnx2_set_rx_mode(dev);
- if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)
- bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
-
- bnx2_netif_start(bp, false);
-}
-#endif
-
/* Called with netif_tx_lock.
* bnx2_tx_int() runs without netif_tx_lock unless it needs to call
* netif_wake_queue().
@@ -6439,12 +6374,11 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
}
-#ifdef BCM_VLAN
- if (bp->vlgrp && vlan_tx_tag_present(skb)) {
+ if (vlan_tx_tag_present(skb)) {
vlan_tag_flags |=
(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
}
-#endif
+
if ((mss = skb_shinfo(skb)->gso_size)) {
u32 tcp_opt_len;
struct iphdr *iph;
@@ -7581,15 +7515,36 @@ bnx2_set_tx_csum(struct net_device *dev, u32 data)
struct bnx2 *bp = netdev_priv(dev);
if (CHIP_NUM(bp) == CHIP_NUM_5709)
- return (ethtool_op_set_tx_ipv6_csum(dev, data));
+ return ethtool_op_set_tx_ipv6_csum(dev, data);
else
- return (ethtool_op_set_tx_csum(dev, data));
+ return ethtool_op_set_tx_csum(dev, data);
}
static int
bnx2_set_flags(struct net_device *dev, u32 data)
{
- return ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH);
+ struct bnx2 *bp = netdev_priv(dev);
+ int rc;
+
+ if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN) &&
+ !(data & ETH_FLAG_RXVLAN))
+ return -EINVAL;
+
+ rc = ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH | ETH_FLAG_RXVLAN |
+ ETH_FLAG_TXVLAN);
+ if (rc)
+ return rc;
+
+ if ((!!(data & ETH_FLAG_RXVLAN) !=
+ !!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) &&
+ netif_running(dev)) {
+ bnx2_netif_stop(bp, false);
+ bnx2_set_rx_mode(dev);
+ bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
+ bnx2_netif_start(bp, false);
+ }
+
+ return 0;
}
static const struct ethtool_ops bnx2_ethtool_ops = {
@@ -7704,7 +7659,7 @@ bnx2_change_mtu(struct net_device *dev, int new_mtu)
return -EINVAL;
dev->mtu = new_mtu;
- return (bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size));
+ return bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -7890,6 +7845,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
int rc, i, j;
u32 reg;
u64 dma_mask, persist_dma_mask;
+ int err;
SET_NETDEV_DEV(dev, &pdev->dev);
bp = netdev_priv(dev);
@@ -7926,7 +7882,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
}
pci_set_master(pdev);
- pci_save_state(pdev);
bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
if (bp->pm_cap == 0) {
@@ -7981,6 +7936,15 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->flags |= BNX2_FLAG_PCIE;
if (CHIP_REV(bp) == CHIP_REV_Ax)
bp->flags |= BNX2_FLAG_JUMBO_BROKEN;
+
+ /* AER (Advanced Error Reporting) hooks */
+ err = pci_enable_pcie_error_reporting(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "pci_enable_pcie_error_reporting "
+ "failed 0x%x\n", err);
+ /* non-fatal, continue */
+ }
+
} else {
bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
if (bp->pcix_cap == 0) {
@@ -8237,9 +8201,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->timer.data = (unsigned long) bp;
bp->timer.function = bnx2_timer;
+ pci_save_state(pdev);
+
return 0;
err_out_unmap:
+ if (bp->flags & BNX2_FLAG_PCIE)
+ pci_disable_pcie_error_reporting(pdev);
+
if (bp->regview) {
iounmap(bp->regview);
bp->regview = NULL;
@@ -8315,9 +8284,6 @@ static const struct net_device_ops bnx2_netdev_ops = {
.ndo_set_mac_address = bnx2_change_mac_addr,
.ndo_change_mtu = bnx2_change_mtu,
.ndo_tx_timeout = bnx2_tx_timeout,
-#ifdef BCM_VLAN
- .ndo_vlan_rx_register = bnx2_vlan_rx_register,
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = poll_bnx2,
#endif
@@ -8325,9 +8291,7 @@ static const struct net_device_ops bnx2_netdev_ops = {
static void inline vlan_features_add(struct net_device *dev, unsigned long flags)
{
-#ifdef BCM_VLAN
dev->vlan_features |= flags;
-#endif
}
static int __devinit
@@ -8376,9 +8340,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->features |= NETIF_F_IPV6_CSUM;
vlan_features_add(dev, NETIF_F_IPV6_CSUM);
}
-#ifdef BCM_VLAN
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-#endif
dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN);
if (CHIP_NUM(bp) == CHIP_NUM_5709) {
@@ -8435,7 +8397,11 @@ bnx2_remove_one(struct pci_dev *pdev)
kfree(bp->temp_stats_blk);
+ if (bp->flags & BNX2_FLAG_PCIE)
+ pci_disable_pcie_error_reporting(pdev);
+
free_netdev(dev);
+
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
@@ -8527,25 +8493,38 @@ static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct bnx2 *bp = netdev_priv(dev);
+ pci_ers_result_t result;
+ int err;
rtnl_lock();
if (pci_enable_device(pdev)) {
dev_err(&pdev->dev,
"Cannot re-enable PCI device after reset\n");
- rtnl_unlock();
- return PCI_ERS_RESULT_DISCONNECT;
+ result = PCI_ERS_RESULT_DISCONNECT;
+ } else {
+ pci_set_master(pdev);
+ pci_restore_state(pdev);
+ pci_save_state(pdev);
+
+ if (netif_running(dev)) {
+ bnx2_set_power_state(bp, PCI_D0);
+ bnx2_init_nic(bp, 1);
+ }
+ result = PCI_ERS_RESULT_RECOVERED;
}
- pci_set_master(pdev);
- pci_restore_state(pdev);
- pci_save_state(pdev);
+ rtnl_unlock();
- if (netif_running(dev)) {
- bnx2_set_power_state(bp, PCI_D0);
- bnx2_init_nic(bp, 1);
+ if (!(bp->flags & BNX2_FLAG_PCIE))
+ return result;
+
+ err = pci_cleanup_aer_uncorrect_error_status(pdev);
+ if (err) {
+ dev_err(&pdev->dev,
+ "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
+ err); /* non-fatal, continue */
}
- rtnl_unlock();
- return PCI_ERS_RESULT_RECOVERED;
+ return result;
}
/**
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 2104c1005d02..bf4c3421067d 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -352,12 +352,7 @@ struct l2_fhdr {
#define BNX2_L2CTX_BD_PRE_READ 0x00000000
#define BNX2_L2CTX_CTX_SIZE 0x00000000
#define BNX2_L2CTX_CTX_TYPE 0x00000000
-#define BNX2_L2CTX_LO_WATER_MARK_DEFAULT 4
-#define BNX2_L2CTX_LO_WATER_MARK_SCALE 4
-#define BNX2_L2CTX_LO_WATER_MARK_DIS 0
-#define BNX2_L2CTX_HI_WATER_MARK_SHIFT 4
-#define BNX2_L2CTX_HI_WATER_MARK_SCALE 16
-#define BNX2_L2CTX_WATER_MARKS_MSK 0x000000ff
+#define BNX2_L2CTX_FLOW_CTRL_ENABLE 0x000000ff
#define BNX2_L2CTX_CTX_TYPE_SIZE_L2 ((0x20/20)<<16)
#define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE (0xf<<28)
#define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_UNDEFINED (0<<28)
@@ -4185,6 +4180,15 @@ struct l2_fhdr {
#define BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_IP_ONLY_XI (2L<<2)
#define BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_RES_XI (3L<<2)
+#define BNX2_RLUP_RSS_COMMAND 0x00002048
+#define BNX2_RLUP_RSS_COMMAND_RSS_IND_TABLE_ADDR (0xfUL<<0)
+#define BNX2_RLUP_RSS_COMMAND_RSS_WRITE_MASK (0xffUL<<4)
+#define BNX2_RLUP_RSS_COMMAND_WRITE (1UL<<12)
+#define BNX2_RLUP_RSS_COMMAND_READ (1UL<<13)
+#define BNX2_RLUP_RSS_COMMAND_HASH_MASK (0x7UL<<14)
+
+#define BNX2_RLUP_RSS_DATA 0x0000204c
+
/*
* rbuf_reg definition
@@ -6077,6 +6081,7 @@ struct l2_fhdr {
#define BNX2_COM_SCRATCH 0x00120000
+#define BNX2_FW_RX_LOW_LATENCY 0x00120058
#define BNX2_FW_RX_DROP_COUNT 0x00120084
@@ -6497,8 +6502,8 @@ struct l2_fhdr {
#define TX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct tx_bd))
#define MAX_TX_DESC_CNT (TX_DESC_CNT - 1)
-#define MAX_RX_RINGS 4
-#define MAX_RX_PG_RINGS 16
+#define MAX_RX_RINGS 8
+#define MAX_RX_PG_RINGS 32
#define RX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct rx_bd))
#define MAX_RX_DESC_CNT (RX_DESC_CNT - 1)
#define MAX_TOTAL_RX_DESC_CNT (MAX_RX_DESC_CNT * MAX_RX_RINGS)
@@ -6737,10 +6742,6 @@ struct bnx2 {
struct bnx2_napi bnx2_napi[BNX2_MAX_MSIX_VEC];
-#ifdef BCM_VLAN
- struct vlan_group *vlgrp;
-#endif
-
u32 rx_buf_use_size; /* useable size */
u32 rx_buf_size; /* with alignment */
u32 rx_copy_thresh;
diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h
index 0c2d96ed561c..9eea225decaf 100644
--- a/drivers/net/bnx2x/bnx2x.h
+++ b/drivers/net/bnx2x/bnx2x.h
@@ -20,26 +20,20 @@
* (you will need to reboot afterwards) */
/* #define BNX2X_STOP_ON_ERROR */
-#define DRV_MODULE_VERSION "1.52.53-4"
-#define DRV_MODULE_RELDATE "2010/16/08"
+#define DRV_MODULE_VERSION "1.60.00-3"
+#define DRV_MODULE_RELDATE "2010/10/19"
#define BNX2X_BC_VER 0x040200
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-#define BCM_VLAN 1
-#endif
-
#define BNX2X_MULTI_QUEUE
#define BNX2X_NEW_NAPI
-
#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
#define BCM_CNIC 1
#include "../cnic_if.h"
#endif
-
#ifdef BCM_CNIC
#define BNX2X_MIN_MSIX_VEC_CNT 3
#define BNX2X_MSIX_VEC_FP_START 2
@@ -129,16 +123,18 @@ void bnx2x_panic_dump(struct bnx2x *bp);
} while (0)
#endif
+#define bnx2x_mc_addr(ha) ((ha)->addr)
#define U64_LO(x) (u32)(((u64)(x)) & 0xffffffff)
#define U64_HI(x) (u32)(((u64)(x)) >> 32)
#define HILO_U64(hi, lo) ((((u64)(hi)) << 32) + (lo))
-#define REG_ADDR(bp, offset) (bp->regview + offset)
+#define REG_ADDR(bp, offset) ((bp->regview) + (offset))
#define REG_RD(bp, offset) readl(REG_ADDR(bp, offset))
#define REG_RD8(bp, offset) readb(REG_ADDR(bp, offset))
+#define REG_RD16(bp, offset) readw(REG_ADDR(bp, offset))
#define REG_WR(bp, offset, val) writel((u32)val, REG_ADDR(bp, offset))
#define REG_WR8(bp, offset, val) writeb((u8)val, REG_ADDR(bp, offset))
@@ -160,6 +156,9 @@ void bnx2x_panic_dump(struct bnx2x *bp);
offset, len32); \
} while (0)
+#define REG_WR_DMAE_LEN(bp, offset, valp, len32) \
+ REG_WR_DMAE(bp, offset, valp, len32)
+
#define VIRT_WR_DMAE_LEN(bp, data, addr, len32, le32_swap) \
do { \
memcpy(GUNZIP_BUF(bp), data, (len32) * 4); \
@@ -175,16 +174,59 @@ void bnx2x_panic_dump(struct bnx2x *bp);
offsetof(struct shmem2_region, field))
#define SHMEM2_RD(bp, field) REG_RD(bp, SHMEM2_ADDR(bp, field))
#define SHMEM2_WR(bp, field, val) REG_WR(bp, SHMEM2_ADDR(bp, field), val)
+#define MF_CFG_ADDR(bp, field) (bp->common.mf_cfg_base + \
+ offsetof(struct mf_cfg, field))
+#define MF2_CFG_ADDR(bp, field) (bp->common.mf2_cfg_base + \
+ offsetof(struct mf2_cfg, field))
-#define MF_CFG_RD(bp, field) SHMEM_RD(bp, mf_cfg.field)
-#define MF_CFG_WR(bp, field, val) SHMEM_WR(bp, mf_cfg.field, val)
+#define MF_CFG_RD(bp, field) REG_RD(bp, MF_CFG_ADDR(bp, field))
+#define MF_CFG_WR(bp, field, val) REG_WR(bp,\
+ MF_CFG_ADDR(bp, field), (val))
+#define MF2_CFG_RD(bp, field) REG_RD(bp, MF2_CFG_ADDR(bp, field))
+
+#define SHMEM2_HAS(bp, field) ((bp)->common.shmem2_base && \
+ (SHMEM2_RD((bp), size) > \
+ offsetof(struct shmem2_region, field)))
#define EMAC_RD(bp, reg) REG_RD(bp, emac_base + reg)
#define EMAC_WR(bp, reg, val) REG_WR(bp, emac_base + reg, val)
+/* SP SB indices */
+
+/* General SP events - stats query, cfc delete, etc */
+#define HC_SP_INDEX_ETH_DEF_CONS 3
+
+/* EQ completions */
+#define HC_SP_INDEX_EQ_CONS 7
+
+/* iSCSI L2 */
+#define HC_SP_INDEX_ETH_ISCSI_CQ_CONS 5
+#define HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS 1
+
+/**
+ * CIDs and CLIDs:
+ * CLIDs below is a CLID for func 0, then the CLID for other
+ * functions will be calculated by the formula:
+ *
+ * FUNC_N_CLID_X = N * NUM_SPECIAL_CLIENTS + FUNC_0_CLID_X
+ *
+ */
+/* iSCSI L2 */
+#define BNX2X_ISCSI_ETH_CL_ID 17
+#define BNX2X_ISCSI_ETH_CID 17
+
+/** Additional rings budgeting */
+#ifdef BCM_CNIC
+#define CNIC_CONTEXT_USE 1
+#else
+#define CNIC_CONTEXT_USE 0
+#endif /* BCM_CNIC */
+
#define AEU_IN_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR \
AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR
+#define SM_RX_ID 0
+#define SM_TX_ID 1
/* fast path */
@@ -254,11 +296,24 @@ union db_prod {
#define RX_SGE_MASK_LEN_MASK (RX_SGE_MASK_LEN - 1)
#define NEXT_SGE_MASK_ELEM(el) (((el) + 1) & RX_SGE_MASK_LEN_MASK)
+union host_hc_status_block {
+ /* pointer to fp status block e1x */
+ struct host_hc_status_block_e1x *e1x_sb;
+ /* pointer to fp status block e2 */
+ struct host_hc_status_block_e2 *e2_sb;
+};
struct bnx2x_fastpath {
+#define BNX2X_NAPI_WEIGHT 128
struct napi_struct napi;
- struct host_status_block *status_blk;
+ union host_hc_status_block status_blk;
+ /* chip independed shortcuts into sb structure */
+ __le16 *sb_index_values;
+ __le16 *sb_running_index;
+ /* chip independed shortcut into rx_prods_offset memory */
+ u32 ustorm_rx_prods_offset;
+
dma_addr_t status_blk_mapping;
struct sw_tx_bd *tx_buf_ring;
@@ -288,10 +343,15 @@ struct bnx2x_fastpath {
#define BNX2X_FP_STATE_OPEN 0xa0000
#define BNX2X_FP_STATE_HALTING 0xb0000
#define BNX2X_FP_STATE_HALTED 0xc0000
+#define BNX2X_FP_STATE_TERMINATING 0xd0000
+#define BNX2X_FP_STATE_TERMINATED 0xe0000
- u8 index; /* number in fp array */
- u8 cl_id; /* eth client id */
- u8 sb_id; /* status block number in HW */
+ u8 index; /* number in fp array */
+ u8 cl_id; /* eth client id */
+ u8 cl_qzone_id;
+ u8 fw_sb_id; /* status block number in FW */
+ u8 igu_sb_id; /* status block number in HW */
+ u32 cid;
union db_prod tx_db;
@@ -301,8 +361,7 @@ struct bnx2x_fastpath {
u16 tx_bd_cons;
__le16 *tx_cons_sb;
- __le16 fp_c_idx;
- __le16 fp_u_idx;
+ __le16 fp_hc_idx;
u16 rx_bd_prod;
u16 rx_bd_cons;
@@ -312,8 +371,6 @@ struct bnx2x_fastpath {
/* The last maximal completed SGE */
u16 last_max_sge;
__le16 *rx_cons_sb;
- __le16 *rx_bd_cons_sb;
-
unsigned long tx_pkt,
rx_pkt,
@@ -356,6 +413,8 @@ struct bnx2x_fastpath {
#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 INIT_JUMBO_TX_RING_SIZE MAX_TX_AVAIL
+#define INIT_TX_RING_SIZE MAX_TX_AVAIL
#define NEXT_TX_IDX(x) ((((x) & MAX_TX_DESC_CNT) == \
(MAX_TX_DESC_CNT - 1)) ? (x) + 2 : (x) + 1)
#define TX_BD(x) ((x) & MAX_TX_BD)
@@ -369,6 +428,9 @@ struct bnx2x_fastpath {
#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
+#define INIT_JUMBO_RX_RING_SIZE MAX_RX_AVAIL
+#define INIT_RX_RING_SIZE MAX_RX_AVAIL
#define NEXT_RX_IDX(x) ((((x) & RX_DESC_MASK) == \
(MAX_RX_DESC_CNT - 1)) ? (x) + 3 : (x) + 1)
#define RX_BD(x) ((x) & MAX_RX_BD)
@@ -419,11 +481,12 @@ struct bnx2x_fastpath {
le32_to_cpu((bd)->addr_lo))
#define BD_UNMAP_LEN(bd) (le16_to_cpu((bd)->nbytes))
-
+#define BNX2X_DB_MIN_SHIFT 3 /* 8 bytes */
+#define BNX2X_DB_SHIFT 7 /* 128 bytes*/
#define DPM_TRIGER_TYPE 0x40
#define DOORBELL(bp, cid, val) \
do { \
- writel((u32)(val), bp->doorbells + (BCM_PAGE_SIZE * (cid)) + \
+ writel((u32)(val), bp->doorbells + (bp->db_size * (cid)) + \
DPM_TRIGER_TYPE); \
} while (0)
@@ -481,31 +544,15 @@ struct bnx2x_fastpath {
#define BNX2X_RX_SUM_FIX(cqe) \
BNX2X_PRS_FLAG_OVERETH_IPV4(cqe->fast_path_cqe.pars_flags.flags)
-
-#define FP_USB_FUNC_OFF (2 + 2*HC_USTORM_SB_NUM_INDICES)
-#define FP_CSB_FUNC_OFF (2 + 2*HC_CSTORM_SB_NUM_INDICES)
-
-#define U_SB_ETH_RX_CQ_INDEX HC_INDEX_U_ETH_RX_CQ_CONS
-#define U_SB_ETH_RX_BD_INDEX HC_INDEX_U_ETH_RX_BD_CONS
-#define C_SB_ETH_TX_CQ_INDEX HC_INDEX_C_ETH_TX_CQ_CONS
+#define U_SB_ETH_RX_CQ_INDEX 1
+#define U_SB_ETH_RX_BD_INDEX 2
+#define C_SB_ETH_TX_CQ_INDEX 5
#define BNX2X_RX_SB_INDEX \
- (&fp->status_blk->u_status_block.index_values[U_SB_ETH_RX_CQ_INDEX])
-
-#define BNX2X_RX_SB_BD_INDEX \
- (&fp->status_blk->u_status_block.index_values[U_SB_ETH_RX_BD_INDEX])
-
-#define BNX2X_RX_SB_INDEX_NUM \
- (((U_SB_ETH_RX_CQ_INDEX << \
- USTORM_ETH_ST_CONTEXT_CONFIG_CQE_SB_INDEX_NUMBER_SHIFT) & \
- USTORM_ETH_ST_CONTEXT_CONFIG_CQE_SB_INDEX_NUMBER) | \
- ((U_SB_ETH_RX_BD_INDEX << \
- USTORM_ETH_ST_CONTEXT_CONFIG_BD_SB_INDEX_NUMBER_SHIFT) & \
- USTORM_ETH_ST_CONTEXT_CONFIG_BD_SB_INDEX_NUMBER))
+ (&fp->sb_index_values[U_SB_ETH_RX_CQ_INDEX])
#define BNX2X_TX_SB_INDEX \
- (&fp->status_blk->c_status_block.index_values[C_SB_ETH_TX_CQ_INDEX])
-
+ (&fp->sb_index_values[C_SB_ETH_TX_CQ_INDEX])
/* end of fast path */
@@ -521,12 +568,19 @@ struct bnx2x_common {
#define CHIP_NUM_57710 0x164e
#define CHIP_NUM_57711 0x164f
#define CHIP_NUM_57711E 0x1650
+#define CHIP_NUM_57712 0x1662
+#define CHIP_NUM_57712E 0x1663
#define CHIP_IS_E1(bp) (CHIP_NUM(bp) == CHIP_NUM_57710)
#define CHIP_IS_57711(bp) (CHIP_NUM(bp) == CHIP_NUM_57711)
#define CHIP_IS_57711E(bp) (CHIP_NUM(bp) == CHIP_NUM_57711E)
+#define CHIP_IS_57712(bp) (CHIP_NUM(bp) == CHIP_NUM_57712)
+#define CHIP_IS_57712E(bp) (CHIP_NUM(bp) == CHIP_NUM_57712E)
#define CHIP_IS_E1H(bp) (CHIP_IS_57711(bp) || \
CHIP_IS_57711E(bp))
-#define IS_E1H_OFFSET CHIP_IS_E1H(bp)
+#define CHIP_IS_E2(bp) (CHIP_IS_57712(bp) || \
+ CHIP_IS_57712E(bp))
+#define CHIP_IS_E1x(bp) (CHIP_IS_E1((bp)) || CHIP_IS_E1H((bp)))
+#define IS_E1H_OFFSET (CHIP_IS_E1H(bp) || CHIP_IS_E2(bp))
#define CHIP_REV(bp) (bp->common.chip_id & 0x0000f000)
#define CHIP_REV_Ax 0x00000000
@@ -552,12 +606,34 @@ struct bnx2x_common {
u32 shmem_base;
u32 shmem2_base;
+ u32 mf_cfg_base;
+ u32 mf2_cfg_base;
u32 hw_config;
u32 bc_ver;
+
+ u8 int_block;
+#define INT_BLOCK_HC 0
+#define INT_BLOCK_IGU 1
+#define INT_BLOCK_MODE_NORMAL 0
+#define INT_BLOCK_MODE_BW_COMP 2
+#define CHIP_INT_MODE_IS_NBC(bp) \
+ (CHIP_IS_E2(bp) && \
+ !((bp)->common.int_block & INT_BLOCK_MODE_BW_COMP))
+#define CHIP_INT_MODE_IS_BC(bp) (!CHIP_INT_MODE_IS_NBC(bp))
+
+ u8 chip_port_mode;
+#define CHIP_4_PORT_MODE 0x0
+#define CHIP_2_PORT_MODE 0x1
+#define CHIP_PORT_MODE_NONE 0x2
+#define CHIP_MODE(bp) (bp->common.chip_port_mode)
+#define CHIP_MODE_IS_4_PORT(bp) (CHIP_MODE(bp) == CHIP_4_PORT_MODE)
};
+/* IGU MSIX STATISTICS on 57712: 64 for VFs; 4 for PFs; 4 for Attentions */
+#define BNX2X_IGU_STAS_MSG_VF_CNT 64
+#define BNX2X_IGU_STAS_MSG_PF_CNT 4
/* end of common */
@@ -566,13 +642,13 @@ struct bnx2x_common {
struct bnx2x_port {
u32 pmf;
- u32 link_config;
+ u32 link_config[LINK_CONFIG_SIZE];
- u32 supported;
+ u32 supported[LINK_CONFIG_SIZE];
/* link settings - missing defines */
#define SUPPORTED_2500baseX_Full (1 << 15)
- u32 advertising;
+ u32 advertising[LINK_CONFIG_SIZE];
/* link settings - missing defines */
#define ADVERTISED_2500baseX_Full (1 << 15)
@@ -589,27 +665,98 @@ struct bnx2x_port {
/* end of port */
+/* e1h Classification CAM line allocations */
+enum {
+ CAM_ETH_LINE = 0,
+ CAM_ISCSI_ETH_LINE,
+ CAM_MAX_PF_LINE = CAM_ISCSI_ETH_LINE
+};
+#define BNX2X_VF_ID_INVALID 0xFF
-#ifdef BCM_CNIC
-#define MAX_CONTEXT 15
-#else
-#define MAX_CONTEXT 16
-#endif
+/*
+ * The total number of L2 queues, MSIX vectors and HW contexts (CIDs) is
+ * control by the number of fast-path status blocks supported by the
+ * device (HW/FW). Each fast-path status block (FP-SB) aka non-default
+ * status block represents an independent interrupts context that can
+ * serve a regular L2 networking queue. However special L2 queues such
+ * as the FCoE queue do not require a FP-SB and other components like
+ * the CNIC may consume FP-SB reducing the number of possible L2 queues
+ *
+ * If the maximum number of FP-SB available is X then:
+ * a. If CNIC is supported it consumes 1 FP-SB thus the max number of
+ * regular L2 queues is Y=X-1
+ * b. in MF mode the actual number of L2 queues is Y= (X-1/MF_factor)
+ * c. If the FCoE L2 queue is supported the actual number of L2 queues
+ * is Y+1
+ * d. The number of irqs (MSIX vectors) is either Y+1 (one extra for
+ * slow-path interrupts) or Y+2 if CNIC is supported (one additional
+ * FP interrupt context for the CNIC).
+ * e. The number of HW context (CID count) is always X or X+1 if FCoE
+ * L2 queue is supported. the cid for the FCoE L2 queue is always X.
+ */
+
+#define FP_SB_MAX_E1x 16 /* fast-path interrupt contexts E1x */
+#define FP_SB_MAX_E2 16 /* fast-path interrupt contexts E2 */
+
+/*
+ * cid_cnt paramter below refers to the value returned by
+ * 'bnx2x_get_l2_cid_count()' routine
+ */
+
+/*
+ * The number of FP context allocated by the driver == max number of regular
+ * L2 queues + 1 for the FCoE L2 queue
+ */
+#define L2_FP_COUNT(cid_cnt) ((cid_cnt) - CNIC_CONTEXT_USE)
union cdu_context {
struct eth_context eth;
char pad[1024];
};
+/* CDU host DB constants */
+#define CDU_ILT_PAGE_SZ_HW 3
+#define CDU_ILT_PAGE_SZ (4096 << CDU_ILT_PAGE_SZ_HW) /* 32K */
+#define ILT_PAGE_CIDS (CDU_ILT_PAGE_SZ / sizeof(union cdu_context))
+
+#ifdef BCM_CNIC
+#define CNIC_ISCSI_CID_MAX 256
+#define CNIC_CID_MAX (CNIC_ISCSI_CID_MAX)
+#define CNIC_ILT_LINES DIV_ROUND_UP(CNIC_CID_MAX, ILT_PAGE_CIDS)
+#endif
+
+#define QM_ILT_PAGE_SZ_HW 3
+#define QM_ILT_PAGE_SZ (4096 << QM_ILT_PAGE_SZ_HW) /* 32K */
+#define QM_CID_ROUND 1024
+
+#ifdef BCM_CNIC
+/* TM (timers) host DB constants */
+#define TM_ILT_PAGE_SZ_HW 2
+#define TM_ILT_PAGE_SZ (4096 << TM_ILT_PAGE_SZ_HW) /* 16K */
+/* #define TM_CONN_NUM (CNIC_STARTING_CID+CNIC_ISCSI_CXT_MAX) */
+#define TM_CONN_NUM 1024
+#define TM_ILT_SZ (8 * TM_CONN_NUM)
+#define TM_ILT_LINES DIV_ROUND_UP(TM_ILT_SZ, TM_ILT_PAGE_SZ)
+
+/* SRC (Searcher) host DB constants */
+#define SRC_ILT_PAGE_SZ_HW 3
+#define SRC_ILT_PAGE_SZ (4096 << SRC_ILT_PAGE_SZ_HW) /* 32K */
+#define SRC_HASH_BITS 10
+#define SRC_CONN_NUM (1 << SRC_HASH_BITS) /* 1024 */
+#define SRC_ILT_SZ (sizeof(struct src_ent) * SRC_CONN_NUM)
+#define SRC_T2_SZ SRC_ILT_SZ
+#define SRC_ILT_LINES DIV_ROUND_UP(SRC_ILT_SZ, SRC_ILT_PAGE_SZ)
+#endif
+
#define MAX_DMAE_C 8
/* DMA memory not used in fastpath */
struct bnx2x_slowpath {
- union cdu_context context[MAX_CONTEXT];
struct eth_stats_query fw_stats;
struct mac_configuration_cmd mac_config;
struct mac_configuration_cmd mcast_config;
+ struct client_init_ramrod_data client_init_data;
/* used by dmae command executer */
struct dmae_command dmae[MAX_DMAE_C];
@@ -634,52 +781,83 @@ struct bnx2x_slowpath {
#define MAX_DYNAMIC_ATTN_GRPS 8
struct attn_route {
- u32 sig[4];
+ u32 sig[5];
+};
+
+struct iro {
+ u32 base;
+ u16 m1;
+ u16 m2;
+ u16 m3;
+ u16 size;
+};
+
+struct hw_context {
+ union cdu_context *vcxt;
+ dma_addr_t cxt_mapping;
+ size_t size;
};
+/* forward */
+struct bnx2x_ilt;
+
typedef enum {
BNX2X_RECOVERY_DONE,
BNX2X_RECOVERY_INIT,
BNX2X_RECOVERY_WAIT,
} bnx2x_recovery_state_t;
+/**
+ * Event queue (EQ or event ring) MC hsi
+ * NUM_EQ_PAGES and EQ_DESC_CNT_PAGE must be power of 2
+ */
+#define NUM_EQ_PAGES 1
+#define EQ_DESC_CNT_PAGE (BCM_PAGE_SIZE / sizeof(union event_ring_elem))
+#define EQ_DESC_MAX_PAGE (EQ_DESC_CNT_PAGE - 1)
+#define NUM_EQ_DESC (EQ_DESC_CNT_PAGE * NUM_EQ_PAGES)
+#define EQ_DESC_MASK (NUM_EQ_DESC - 1)
+#define MAX_EQ_AVAIL (EQ_DESC_MAX_PAGE * NUM_EQ_PAGES - 2)
+
+/* depends on EQ_DESC_CNT_PAGE being a power of 2 */
+#define NEXT_EQ_IDX(x) ((((x) & EQ_DESC_MAX_PAGE) == \
+ (EQ_DESC_MAX_PAGE - 1)) ? (x) + 2 : (x) + 1)
+
+/* depends on the above and on NUM_EQ_PAGES being a power of 2 */
+#define EQ_DESC(x) ((x) & EQ_DESC_MASK)
+
+#define BNX2X_EQ_INDEX \
+ (&bp->def_status_blk->sp_sb.\
+ index_values[HC_SP_INDEX_EQ_CONS])
+
struct bnx2x {
/* Fields used in the tx and intr/napi performance paths
* are grouped together in the beginning of the structure
*/
- struct bnx2x_fastpath fp[MAX_CONTEXT];
+ struct bnx2x_fastpath *fp;
void __iomem *regview;
void __iomem *doorbells;
-#ifdef BCM_CNIC
-#define BNX2X_DB_SIZE (18*BCM_PAGE_SIZE)
-#else
-#define BNX2X_DB_SIZE (16*BCM_PAGE_SIZE)
-#endif
+ u16 db_size;
struct net_device *dev;
struct pci_dev *pdev;
+ struct iro *iro_arr;
+#define IRO (bp->iro_arr)
+
atomic_t intr_sem;
bnx2x_recovery_state_t recovery_state;
int is_leader;
-#ifdef BCM_CNIC
- struct msix_entry msix_table[MAX_CONTEXT+2];
-#else
- struct msix_entry msix_table[MAX_CONTEXT+1];
-#endif
+ struct msix_entry *msix_table;
#define INT_MODE_INTx 1
#define INT_MODE_MSI 2
int tx_ring_size;
-#ifdef BCM_VLAN
- struct vlan_group *vlgrp;
-#endif
-
u32 rx_csum;
u32 rx_buf_size;
-#define ETH_OVREHEAD (ETH_HLEN + 8) /* 8 for CRC + VLAN */
+/* L2 header size + 2*VLANs (8 bytes) + LLC SNAP (8 bytes) */
+#define ETH_OVREHEAD (ETH_HLEN + 8 + 8)
#define ETH_MIN_PACKET_SIZE 60
#define ETH_MAX_PACKET_SIZE 1500
#define ETH_MAX_JUMBO_PACKET_SIZE 9600
@@ -688,13 +866,12 @@ struct bnx2x {
#define BNX2X_RX_ALIGN_SHIFT ((L1_CACHE_SHIFT < 8) ? \
L1_CACHE_SHIFT : 8)
#define BNX2X_RX_ALIGN (1 << BNX2X_RX_ALIGN_SHIFT)
+#define BNX2X_PXP_DRAM_ALIGN (BNX2X_RX_ALIGN_SHIFT - 5)
- struct host_def_status_block *def_status_blk;
-#define DEF_SB_ID 16
- __le16 def_c_idx;
- __le16 def_u_idx;
- __le16 def_x_idx;
- __le16 def_t_idx;
+ struct host_sp_status_block *def_status_blk;
+#define DEF_SB_IGU_ID 16
+#define DEF_SB_ID HC_SP_SB_ID
+ __le16 def_idx;
__le16 def_att_idx;
u32 attn_state;
struct attn_route attn_group[MAX_DYNAMIC_ATTN_GRPS];
@@ -706,10 +883,17 @@ struct bnx2x {
struct eth_spe *spq_prod_bd;
struct eth_spe *spq_last_bd;
__le16 *dsb_sp_prod;
- u16 spq_left; /* serialize spq */
+ atomic_t spq_left; /* serialize spq */
/* used to synchronize spq accesses */
spinlock_t spq_lock;
+ /* event queue */
+ union event_ring_elem *eq_ring;
+ dma_addr_t eq_mapping;
+ u16 eq_prod;
+ u16 eq_cons;
+ __le16 *eq_cons_sb;
+
/* Flags for marking that there is a STAT_QUERY or
SET_MAC ramrod pending */
int stats_pending;
@@ -728,18 +912,27 @@ struct bnx2x {
#define USING_DAC_FLAG 0x10
#define USING_MSIX_FLAG 0x20
#define USING_MSI_FLAG 0x40
+
#define TPA_ENABLE_FLAG 0x80
#define NO_MCP_FLAG 0x100
+#define DISABLE_MSI_FLAG 0x200
#define BP_NOMCP(bp) (bp->flags & NO_MCP_FLAG)
-#define HW_VLAN_TX_FLAG 0x400
-#define HW_VLAN_RX_FLAG 0x800
#define MF_FUNC_DIS 0x1000
- int func;
-#define BP_PORT(bp) (bp->func % PORT_MAX)
-#define BP_FUNC(bp) (bp->func)
-#define BP_E1HVN(bp) (bp->func >> 1)
+ int pf_num; /* absolute PF number */
+ int pfid; /* per-path PF number */
+ int base_fw_ndsb;
+#define BP_PATH(bp) (!CHIP_IS_E2(bp) ? \
+ 0 : (bp->pf_num & 1))
+#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) (CHIP_MODE_IS_4_PORT(bp) ? \
+ 0 : BP_E1HVN(bp))
#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) ? 2 : 1))
#ifdef BCM_CNIC
#define BCM_CNIC_CID_START 16
@@ -769,10 +962,11 @@ struct bnx2x {
struct cmng_struct_per_port cmng;
u32 vn_weight_sum;
- u32 mf_config;
- u16 e1hov;
- u8 e1hmf;
-#define IS_E1HMF(bp) (bp->e1hmf != 0)
+ u32 mf_config[E1HVN_MAX];
+ u32 mf2_config[E2_FUNC_MAX];
+ u16 mf_ov;
+ u8 mf_mode;
+#define IS_MF(bp) (bp->mf_mode != 0)
u8 wol;
@@ -800,6 +994,7 @@ struct bnx2x {
#define BNX2X_STATE_CLOSING_WAIT4_HALT 0x4000
#define BNX2X_STATE_CLOSING_WAIT4_DELETE 0x5000
#define BNX2X_STATE_CLOSING_WAIT4_UNLOAD 0x6000
+#define BNX2X_STATE_FUNC_STARTED 0x7000
#define BNX2X_STATE_DIAG 0xe000
#define BNX2X_STATE_ERROR 0xf000
@@ -808,6 +1003,15 @@ struct bnx2x {
int disable_tpa;
int int_mode;
+ struct tstorm_eth_mac_filter_config mac_filters;
+#define BNX2X_ACCEPT_NONE 0x0000
+#define BNX2X_ACCEPT_UNICAST 0x0001
+#define BNX2X_ACCEPT_MULTICAST 0x0002
+#define BNX2X_ACCEPT_ALL_UNICAST 0x0004
+#define BNX2X_ACCEPT_ALL_MULTICAST 0x0008
+#define BNX2X_ACCEPT_BROADCAST 0x0010
+#define BNX2X_PROMISCUOUS_MODE 0x10000
+
u32 rx_mode;
#define BNX2X_RX_MODE_NONE 0
#define BNX2X_RX_MODE_NORMAL 1
@@ -816,34 +1020,41 @@ struct bnx2x {
#define BNX2X_MAX_MULTICAST 64
#define BNX2X_MAX_EMUL_MULTI 16
- u32 rx_mode_cl_mask;
-
+ u8 igu_dsb_id;
+ u8 igu_base_sb;
+ u8 igu_sb_cnt;
dma_addr_t def_status_blk_mapping;
struct bnx2x_slowpath *slowpath;
dma_addr_t slowpath_mapping;
+ struct hw_context context;
+
+ struct bnx2x_ilt *ilt;
+#define BP_ILT(bp) ((bp)->ilt)
+#define ILT_MAX_LINES 128
+
+ int l2_cid_count;
+#define L2_ILT_LINES(bp) (DIV_ROUND_UP((bp)->l2_cid_count, \
+ ILT_PAGE_CIDS))
+#define BNX2X_DB_SIZE(bp) ((bp)->l2_cid_count * (1 << BNX2X_DB_SHIFT))
+
+ int qm_cid_count;
int dropless_fc;
#ifdef BCM_CNIC
u32 cnic_flags;
#define BNX2X_CNIC_FLAG_MAC_SET 1
-
- void *t1;
- dma_addr_t t1_mapping;
void *t2;
dma_addr_t t2_mapping;
- void *timers;
- dma_addr_t timers_mapping;
- void *qm;
- dma_addr_t qm_mapping;
struct cnic_ops *cnic_ops;
void *cnic_data;
u32 cnic_tag;
struct cnic_eth_dev cnic_eth_dev;
- struct host_status_block *cnic_sb;
+ union host_hc_status_block cnic_sb;
dma_addr_t cnic_sb_mapping;
-#define CNIC_SB_ID(bp) BP_L_ID(bp)
+#define CNIC_SB_ID(bp) ((bp)->base_fw_ndsb + BP_L_ID(bp))
+#define CNIC_IGU_SB_ID(bp) ((bp)->igu_base_sb)
struct eth_spe *cnic_kwq;
struct eth_spe *cnic_kwq_prod;
struct eth_spe *cnic_kwq_cons;
@@ -913,32 +1124,191 @@ struct bnx2x {
const struct firmware *firmware;
};
+/**
+ * Init queue/func interface
+ */
+/* queue init flags */
+#define QUEUE_FLG_TPA 0x0001
+#define QUEUE_FLG_CACHE_ALIGN 0x0002
+#define QUEUE_FLG_STATS 0x0004
+#define QUEUE_FLG_OV 0x0008
+#define QUEUE_FLG_VLAN 0x0010
+#define QUEUE_FLG_COS 0x0020
+#define QUEUE_FLG_HC 0x0040
+#define QUEUE_FLG_DHC 0x0080
+#define QUEUE_FLG_OOO 0x0100
+
+#define QUEUE_DROP_IP_CS_ERR TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR
+#define QUEUE_DROP_TCP_CS_ERR TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR
+#define QUEUE_DROP_TTL0 TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0
+#define QUEUE_DROP_UDP_CS_ERR TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR
+
+
+
+/* rss capabilities */
+#define RSS_IPV4_CAP 0x0001
+#define RSS_IPV4_TCP_CAP 0x0002
+#define RSS_IPV6_CAP 0x0004
+#define RSS_IPV6_TCP_CAP 0x0008
-#define BNX2X_MAX_QUEUES(bp) (IS_E1HMF(bp) ? (MAX_CONTEXT/E1HVN_MAX) \
- : MAX_CONTEXT)
#define BNX2X_NUM_QUEUES(bp) (bp->num_queues)
#define is_multi(bp) (BNX2X_NUM_QUEUES(bp) > 1)
+#define BNX2X_MAX_QUEUES(bp) (bp->igu_sb_cnt - CNIC_CONTEXT_USE)
+#define is_eth_multi(bp) (BNX2X_NUM_ETH_QUEUES(bp) > 1)
+
+#define RSS_IPV4_CAP_MASK \
+ TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY
+
+#define RSS_IPV4_TCP_CAP_MASK \
+ TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY
+
+#define RSS_IPV6_CAP_MASK \
+ TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY
+
+#define RSS_IPV6_TCP_CAP_MASK \
+ TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY
+
+/* func init flags */
+#define FUNC_FLG_STATS 0x0001
+#define FUNC_FLG_TPA 0x0002
+#define FUNC_FLG_SPQ 0x0004
+#define FUNC_FLG_LEADING 0x0008 /* PF only */
+
+struct rxq_pause_params {
+ u16 bd_th_lo;
+ u16 bd_th_hi;
+ u16 rcq_th_lo;
+ u16 rcq_th_hi;
+ u16 sge_th_lo; /* valid iff QUEUE_FLG_TPA */
+ u16 sge_th_hi; /* valid iff QUEUE_FLG_TPA */
+ u16 pri_map;
+};
+
+struct bnx2x_rxq_init_params {
+ /* cxt*/
+ struct eth_context *cxt;
+
+ /* dma */
+ dma_addr_t dscr_map;
+ dma_addr_t sge_map;
+ dma_addr_t rcq_map;
+ dma_addr_t rcq_np_map;
+
+ u16 flags;
+ u16 drop_flags;
+ u16 mtu;
+ u16 buf_sz;
+ u16 fw_sb_id;
+ u16 cl_id;
+ u16 spcl_id;
+ u16 cl_qzone_id;
+
+ /* valid iff QUEUE_FLG_STATS */
+ u16 stat_id;
+
+ /* valid iff QUEUE_FLG_TPA */
+ u16 tpa_agg_sz;
+ u16 sge_buf_sz;
+ u16 max_sges_pkt;
+
+ /* valid iff QUEUE_FLG_CACHE_ALIGN */
+ u8 cache_line_log;
+
+ u8 sb_cq_index;
+ u32 cid;
+
+ /* desired interrupts per sec. valid iff QUEUE_FLG_HC */
+ u32 hc_rate;
+};
+
+struct bnx2x_txq_init_params {
+ /* cxt*/
+ struct eth_context *cxt;
+
+ /* dma */
+ dma_addr_t dscr_map;
+
+ u16 flags;
+ u16 fw_sb_id;
+ u8 sb_cq_index;
+ u8 cos; /* valid iff QUEUE_FLG_COS */
+ u16 stat_id; /* valid iff QUEUE_FLG_STATS */
+ u16 traffic_type;
+ u32 cid;
+ u16 hc_rate; /* desired interrupts per sec.*/
+ /* valid iff QUEUE_FLG_HC */
+
+};
+
+struct bnx2x_client_ramrod_params {
+ int *pstate;
+ int state;
+ u16 index;
+ u16 cl_id;
+ u32 cid;
+ u8 poll;
+#define CLIENT_IS_LEADING_RSS 0x02
+ u8 flags;
+};
+
+struct bnx2x_client_init_params {
+ struct rxq_pause_params pause;
+ struct bnx2x_rxq_init_params rxq_params;
+ struct bnx2x_txq_init_params txq_params;
+ struct bnx2x_client_ramrod_params ramrod_params;
+};
+
+struct bnx2x_rss_params {
+ int mode;
+ u16 cap;
+ u16 result_mask;
+};
+
+struct bnx2x_func_init_params {
+
+ /* rss */
+ struct bnx2x_rss_params *rss; /* valid iff FUNC_FLG_RSS */
+
+ /* dma */
+ dma_addr_t fw_stat_map; /* valid iff FUNC_FLG_STATS */
+ dma_addr_t spq_map; /* valid iff FUNC_FLG_SPQ */
+
+ u16 func_flgs;
+ u16 func_id; /* abs fid */
+ u16 pf_id;
+ u16 spq_prod; /* valid iff FUNC_FLG_SPQ */
+};
+
#define for_each_queue(bp, var) \
for (var = 0; var < BNX2X_NUM_QUEUES(bp); var++)
#define for_each_nondefault_queue(bp, var) \
for (var = 1; var < BNX2X_NUM_QUEUES(bp); var++)
+#define WAIT_RAMROD_POLL 0x01
+#define WAIT_RAMROD_COMMON 0x02
+
+/* dmae */
void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32);
void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
u32 len32);
+void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, int idx);
+u32 bnx2x_dmae_opcode_add_comp(u32 opcode, u8 comp_type);
+u32 bnx2x_dmae_opcode_clr_src_reset(u32 opcode);
+u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
+ bool with_comp, u8 comp_type);
+
int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port);
int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
-u32 bnx2x_fw_command(struct bnx2x *bp, u32 command);
-void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val);
-void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
- u32 addr, u32 len);
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command, u32 param);
+
void bnx2x_calc_fc_adv(struct bnx2x *bp);
int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
u32 data_hi, u32 data_lo, int common);
void bnx2x_update_coalesce(struct bnx2x *bp);
+int bnx2x_get_link_cfg_idx(struct bnx2x *bp);
static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
int wait)
@@ -957,6 +1327,40 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
return val;
}
+#define BNX2X_ILT_ZALLOC(x, y, size) \
+ do { \
+ x = pci_alloc_consistent(bp->pdev, size, y); \
+ if (x) \
+ memset(x, 0, size); \
+ } while (0)
+
+#define BNX2X_ILT_FREE(x, y, size) \
+ do { \
+ if (x) { \
+ pci_free_consistent(bp->pdev, size, x, y); \
+ x = NULL; \
+ y = 0; \
+ } \
+ } while (0)
+
+#define ILOG2(x) (ilog2((x)))
+
+#define ILT_NUM_PAGE_ENTRIES (3072)
+/* In 57710/11 we use whole table since we have 8 func
+ * In 57712 we have only 4 func, but use same size per func, then only half of
+ * the table in use
+ */
+#define ILT_PER_FUNC (ILT_NUM_PAGE_ENTRIES/8)
+
+#define FUNC_ILT_BASE(func) (func * ILT_PER_FUNC)
+/*
+ * the phys address is shifted right 12 bits and has an added
+ * 1=valid bit added to the 53rd bit
+ * then since this is a wide register(TM)
+ * we split it into two 32 bit writes
+ */
+#define ONCHIP_ADDR1(x) ((u32)(((u64)x >> 12) & 0xFFFFFFFF))
+#define ONCHIP_ADDR2(x) ((u32)((1 << 20) | ((u64)x >> 44)))
/* load/unload mode */
#define LOAD_NORMAL 0
@@ -964,18 +1368,44 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
#define LOAD_DIAG 2
#define UNLOAD_NORMAL 0
#define UNLOAD_CLOSE 1
-#define UNLOAD_RECOVERY 2
+#define UNLOAD_RECOVERY 2
/* DMAE command defines */
-#define DMAE_CMD_SRC_PCI 0
-#define DMAE_CMD_SRC_GRC DMAE_COMMAND_SRC
+#define DMAE_TIMEOUT -1
+#define DMAE_PCI_ERROR -2 /* E2 and onward */
+#define DMAE_NOT_RDY -3
+#define DMAE_PCI_ERR_FLAG 0x80000000
+
+#define DMAE_SRC_PCI 0
+#define DMAE_SRC_GRC 1
+
+#define DMAE_DST_NONE 0
+#define DMAE_DST_PCI 1
+#define DMAE_DST_GRC 2
+
+#define DMAE_COMP_PCI 0
+#define DMAE_COMP_GRC 1
+
+/* E2 and onward - PCI error handling in the completion */
+
+#define DMAE_COMP_REGULAR 0
+#define DMAE_COM_SET_ERR 1
-#define DMAE_CMD_DST_PCI (1 << DMAE_COMMAND_DST_SHIFT)
-#define DMAE_CMD_DST_GRC (2 << DMAE_COMMAND_DST_SHIFT)
+#define DMAE_CMD_SRC_PCI (DMAE_SRC_PCI << \
+ DMAE_COMMAND_SRC_SHIFT)
+#define DMAE_CMD_SRC_GRC (DMAE_SRC_GRC << \
+ DMAE_COMMAND_SRC_SHIFT)
-#define DMAE_CMD_C_DST_PCI 0
-#define DMAE_CMD_C_DST_GRC (1 << DMAE_COMMAND_C_DST_SHIFT)
+#define DMAE_CMD_DST_PCI (DMAE_DST_PCI << \
+ DMAE_COMMAND_DST_SHIFT)
+#define DMAE_CMD_DST_GRC (DMAE_DST_GRC << \
+ DMAE_COMMAND_DST_SHIFT)
+
+#define DMAE_CMD_C_DST_PCI (DMAE_COMP_PCI << \
+ DMAE_COMMAND_C_DST_SHIFT)
+#define DMAE_CMD_C_DST_GRC (DMAE_COMP_GRC << \
+ DMAE_COMMAND_C_DST_SHIFT)
#define DMAE_CMD_C_ENABLE DMAE_COMMAND_C_TYPE_ENABLE
@@ -991,10 +1421,20 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
#define DMAE_CMD_DST_RESET DMAE_COMMAND_DST_RESET
#define DMAE_CMD_E1HVN_SHIFT DMAE_COMMAND_E1HVN_SHIFT
+#define DMAE_SRC_PF 0
+#define DMAE_SRC_VF 1
+
+#define DMAE_DST_PF 0
+#define DMAE_DST_VF 1
+
+#define DMAE_C_SRC 0
+#define DMAE_C_DST 1
+
#define DMAE_LEN32_RD_MAX 0x80
#define DMAE_LEN32_WR_MAX(bp) (CHIP_IS_E1(bp) ? 0x400 : 0x2000)
-#define DMAE_COMP_VAL 0xe0d0d0ae
+#define DMAE_COMP_VAL 0x60d0d0ae /* E2 and on - upper bit
+ indicates eror */
#define MAX_DMAE_C_PER_PORT 8
#define INIT_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \
@@ -1002,7 +1442,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
#define PMF_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \
E1HVN_MAX)
-
/* PCIE link and speed */
#define PCICFG_LINK_WIDTH 0x1f00000
#define PCICFG_LINK_WIDTH_SHIFT 20
@@ -1031,7 +1470,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
#define MAX_SP_DESC_CNT (SP_DESC_CNT - 1)
-#define BNX2X_BTR 1
+#define BNX2X_BTR 4
#define MAX_SPQ_PENDING 8
@@ -1148,20 +1587,26 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_MODE_SHIFT))
#define MULTI_MASK 0x7f
+#define BNX2X_SP_DSB_INDEX \
+ (&bp->def_status_blk->sp_sb.\
+ index_values[HC_SP_INDEX_ETH_DEF_CONS])
-#define DEF_USB_FUNC_OFF (2 + 2*HC_USTORM_DEF_SB_NUM_INDICES)
-#define DEF_CSB_FUNC_OFF (2 + 2*HC_CSTORM_DEF_SB_NUM_INDICES)
-#define DEF_XSB_FUNC_OFF (2 + 2*HC_XSTORM_DEF_SB_NUM_INDICES)
-#define DEF_TSB_FUNC_OFF (2 + 2*HC_TSTORM_DEF_SB_NUM_INDICES)
-
-#define C_DEF_SB_SP_INDEX HC_INDEX_DEF_C_ETH_SLOW_PATH
+#define SET_FLAG(value, mask, flag) \
+ do {\
+ (value) &= ~(mask);\
+ (value) |= ((flag) << (mask##_SHIFT));\
+ } while (0)
-#define BNX2X_SP_DSB_INDEX \
-(&bp->def_status_blk->c_def_status_block.index_values[C_DEF_SB_SP_INDEX])
+#define GET_FLAG(value, mask) \
+ (((value) &= (mask)) >> (mask##_SHIFT))
+#define GET_FIELD(value, fname) \
+ (((value) & (fname##_MASK)) >> (fname##_SHIFT))
#define CAM_IS_INVALID(x) \
-(x.target_table_entry.flags == TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE)
+ (GET_FLAG(x.flags, \
+ MAC_CONFIGURATION_ENTRY_ACTION_TYPE) == \
+ (T_ETH_MAC_COMMAND_INVALIDATE))
#define CAM_INVALIDATE(x) \
(x.target_table_entry.flags = TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE)
@@ -1177,21 +1622,29 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
#define PXP2_REG_PXP2_INT_STS PXP2_REG_PXP2_INT_STS_0
#endif
+#ifndef ETH_MAX_RX_CLIENTS_E2
+#define ETH_MAX_RX_CLIENTS_E2 ETH_MAX_RX_CLIENTS_E1H
+#endif
+
#define BNX2X_VPD_LEN 128
#define VENDOR_ID_LEN 4
+/* Congestion management fairness mode */
+#define CMNG_FNS_NONE 0
+#define CMNG_FNS_MINMAX 1
+
+#define HC_SEG_ACCESS_DEF 0 /*Driver decision 0-3*/
+#define HC_SEG_ACCESS_ATTN 4
+#define HC_SEG_ACCESS_NORM 0 /*Driver decision 0-1*/
+
#ifdef BNX2X_MAIN
#define BNX2X_EXTERN
#else
#define BNX2X_EXTERN extern
#endif
-BNX2X_EXTERN int load_count[3]; /* 0-common, 1-port0, 2-port1 */
-
-/* MISC_REG_RESET_REG - this is here for the hsi to work don't touch */
+BNX2X_EXTERN int load_count[2][3]; /* per path: 0-common, 1-port0, 2-port1 */
extern void bnx2x_set_ethtool_ops(struct net_device *netdev);
-void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, int idx);
-
#endif /* bnx2x.h */
diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c
index 02bf710629a3..459614d2d7bc 100644
--- a/drivers/net/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/bnx2x/bnx2x_cmn.c
@@ -15,18 +15,17 @@
*
*/
-
#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
#include <linux/ip.h>
-#include <linux/ipv6.h>
+#include <net/ipv6.h>
#include <net/ip6_checksum.h>
+#include <linux/firmware.h>
#include "bnx2x_cmn.h"
-#ifdef BCM_VLAN
-#include <linux/if_vlan.h>
-#endif
+#include "bnx2x_init.h"
-static int bnx2x_poll(struct napi_struct *napi, int budget);
+static int bnx2x_setup_irqs(struct bnx2x *bp);
/* free skb in the packet ring at pos idx
* return idx of last bd freed
@@ -51,7 +50,7 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp,
DP(BNX2X_MSG_OFF, "free bd_idx %d\n", bd_idx);
tx_start_bd = &fp->tx_desc_ring[bd_idx].start_bd;
dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd),
- BD_UNMAP_LEN(tx_start_bd), PCI_DMA_TODEVICE);
+ BD_UNMAP_LEN(tx_start_bd), DMA_TO_DEVICE);
nbd = le16_to_cpu(tx_start_bd->nbd) - 1;
#ifdef BNX2X_STOP_ON_ERROR
@@ -115,16 +114,10 @@ int bnx2x_tx_int(struct bnx2x_fastpath *fp)
pkt_cons = TX_BD(sw_cons);
- /* prefetch(bp->tx_buf_ring[pkt_cons].skb); */
-
- DP(NETIF_MSG_TX_DONE, "hw_cons %u sw_cons %u pkt_cons %u\n",
- hw_cons, sw_cons, pkt_cons);
+ DP(NETIF_MSG_TX_DONE, "queue[%d]: hw_cons %u sw_cons %u "
+ " pkt_cons %u\n",
+ fp->index, hw_cons, sw_cons, pkt_cons);
-/* if (NEXT_TX_IDX(sw_cons) != hw_cons) {
- rmb();
- prefetch(fp->tx_buf_ring[NEXT_TX_IDX(sw_cons)].skb);
- }
-*/
bd_cons = bnx2x_free_tx_pkt(bp, fp, pkt_cons);
sw_cons++;
}
@@ -140,7 +133,6 @@ int bnx2x_tx_int(struct bnx2x_fastpath *fp)
*/
smp_mb();
- /* TBD need a thresh? */
if (unlikely(netif_tx_queue_stopped(txq))) {
/* Taking tx_lock() is needed to prevent reenabling the queue
* while it's empty. This could have happen if rx_action() gets
@@ -189,14 +181,16 @@ static void bnx2x_update_sge_prod(struct bnx2x_fastpath *fp,
/* First mark all used pages */
for (i = 0; i < sge_len; i++)
- SGE_MASK_CLEAR_BIT(fp, RX_SGE(le16_to_cpu(fp_cqe->sgl[i])));
+ SGE_MASK_CLEAR_BIT(fp,
+ RX_SGE(le16_to_cpu(fp_cqe->sgl_or_raw_data.sgl[i])));
DP(NETIF_MSG_RX_STATUS, "fp_cqe->sgl[%d] = %d\n",
- sge_len - 1, le16_to_cpu(fp_cqe->sgl[sge_len - 1]));
+ sge_len - 1, le16_to_cpu(fp_cqe->sgl_or_raw_data.sgl[sge_len - 1]));
/* Here we assume that the last SGE index is the biggest */
prefetch((void *)(fp->sge_mask));
- bnx2x_update_last_max_sge(fp, le16_to_cpu(fp_cqe->sgl[sge_len - 1]));
+ bnx2x_update_last_max_sge(fp,
+ le16_to_cpu(fp_cqe->sgl_or_raw_data.sgl[sge_len - 1]));
last_max = RX_SGE(fp->last_max_sge);
last_elem = last_max >> RX_SGE_MASK_ELEM_SHIFT;
@@ -297,7 +291,8 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
/* Run through the SGL and compose the fragmented skb */
for (i = 0, j = 0; i < pages; i += PAGES_PER_SGE, j++) {
- u16 sge_idx = RX_SGE(le16_to_cpu(fp_cqe->sgl[j]));
+ u16 sge_idx =
+ RX_SGE(le16_to_cpu(fp_cqe->sgl_or_raw_data.sgl[j]));
/* FW gives the indices of the SGE as if the ring is an array
(meaning that "next" element will consume 2 indices) */
@@ -349,16 +344,9 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
if (likely(new_skb)) {
/* fix ip xsum and give it to the stack */
/* (no need to map the new skb) */
-#ifdef BCM_VLAN
- int is_vlan_cqe =
- (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
- PARSING_FLAGS_VLAN);
- int is_not_hwaccel_vlan_cqe =
- (is_vlan_cqe && (!(bp->flags & HW_VLAN_RX_FLAG)));
-#endif
prefetch(skb);
- prefetch(((char *)(skb)) + 128);
+ prefetch(((char *)(skb)) + L1_CACHE_BYTES);
#ifdef BNX2X_STOP_ON_ERROR
if (pad + len > bp->rx_buf_size) {
@@ -380,27 +368,18 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
struct iphdr *iph;
iph = (struct iphdr *)skb->data;
-#ifdef BCM_VLAN
- /* If there is no Rx VLAN offloading -
- take VLAN tag into an account */
- if (unlikely(is_not_hwaccel_vlan_cqe))
- iph = (struct iphdr *)((u8 *)iph + VLAN_HLEN);
-#endif
iph->check = 0;
iph->check = ip_fast_csum((u8 *)iph, iph->ihl);
}
if (!bnx2x_fill_frag_skb(bp, fp, skb,
&cqe->fast_path_cqe, cqe_idx)) {
-#ifdef BCM_VLAN
- if ((bp->vlgrp != NULL) && is_vlan_cqe &&
- (!is_not_hwaccel_vlan_cqe))
- vlan_gro_receive(&fp->napi, bp->vlgrp,
+ if ((le16_to_cpu(cqe->fast_path_cqe.
+ pars_flags.flags) & PARSING_FLAGS_VLAN))
+ __vlan_hwaccel_put_tag(skb,
le16_to_cpu(cqe->fast_path_cqe.
- vlan_tag), skb);
- else
-#endif
- napi_gro_receive(&fp->napi, skb);
+ vlan_tag));
+ napi_gro_receive(&fp->napi, skb);
} else {
DP(NETIF_MSG_RX_STATUS, "Failed to allocate new pages"
" - dropping packet!\n");
@@ -509,8 +488,11 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
len = le16_to_cpu(cqe->fast_path_cqe.pkt_len);
pad = cqe->fast_path_cqe.placement_offset;
- /* If CQE is marked both TPA_START and TPA_END
- it is a non-TPA CQE */
+ /* - If CQE is marked both TPA_START and TPA_END it is
+ * a non-TPA CQE.
+ * - FP CQE will always have either TPA_START or/and
+ * TPA_STOP flags set.
+ */
if ((!fp->disable_tpa) &&
(TPA_TYPE(cqe_fp_flags) !=
(TPA_TYPE_START | TPA_TYPE_END))) {
@@ -528,9 +510,7 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
bnx2x_set_skb_rxhash(bp, cqe, skb);
goto next_rx;
- }
-
- if (TPA_TYPE(cqe_fp_flags) == TPA_TYPE_END) {
+ } else { /* TPA_STOP */
DP(NETIF_MSG_RX_STATUS,
"calling tpa_stop on queue %d\n",
queue);
@@ -560,7 +540,7 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
dma_unmap_addr(rx_buf, mapping),
pad + RX_COPY_THRESH,
DMA_FROM_DEVICE);
- prefetch(((char *)(skb)) + 128);
+ prefetch(((char *)(skb)) + L1_CACHE_BYTES);
/* is this an error packet? */
if (unlikely(cqe_fp_flags & ETH_RX_ERROR_FALGS)) {
@@ -594,7 +574,7 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
skb_reserve(new_skb, pad);
skb_put(new_skb, len);
- bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod);
+ bnx2x_reuse_rx_skb(fp, bd_cons, bd_prod);
skb = new_skb;
@@ -613,7 +593,7 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
"of alloc failure\n");
fp->eth_q_stats.rx_skb_alloc_failed++;
reuse_rx:
- bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod);
+ bnx2x_reuse_rx_skb(fp, bd_cons, bd_prod);
goto next_rx;
}
@@ -622,7 +602,8 @@ reuse_rx:
/* Set Toeplitz hash for a none-LRO skb */
bnx2x_set_skb_rxhash(bp, cqe, skb);
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
+
if (bp->rx_csum) {
if (likely(BNX2X_RX_CSUM_OK(cqe)))
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -633,15 +614,11 @@ reuse_rx:
skb_record_rx_queue(skb, fp->index);
-#ifdef BCM_VLAN
- if ((bp->vlgrp != NULL) && (bp->flags & HW_VLAN_RX_FLAG) &&
- (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
- PARSING_FLAGS_VLAN))
- vlan_gro_receive(&fp->napi, bp->vlgrp,
- le16_to_cpu(cqe->fast_path_cqe.vlan_tag), skb);
- else
-#endif
- napi_gro_receive(&fp->napi, skb);
+ if (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
+ PARSING_FLAGS_VLAN)
+ __vlan_hwaccel_put_tag(skb,
+ le16_to_cpu(cqe->fast_path_cqe.vlan_tag));
+ napi_gro_receive(&fp->napi, skb);
next_rx:
@@ -685,9 +662,10 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)
return IRQ_HANDLED;
}
- DP(BNX2X_MSG_FP, "got an MSI-X interrupt on IDX:SB [%d:%d]\n",
- fp->index, fp->sb_id);
- bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0);
+ DP(BNX2X_MSG_FP, "got an MSI-X interrupt on IDX:SB "
+ "[fp %d fw_sd %d igusb %d]\n",
+ fp->index, fp->fw_sb_id, fp->igu_sb_id);
+ bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0);
#ifdef BNX2X_STOP_ON_ERROR
if (unlikely(bp->panic))
@@ -697,14 +675,12 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)
/* Handle Rx and Tx according to MSI-X vector */
prefetch(fp->rx_cons_sb);
prefetch(fp->tx_cons_sb);
- prefetch(&fp->status_blk->u_status_block.status_block_index);
- prefetch(&fp->status_blk->c_status_block.status_block_index);
+ prefetch(&fp->sb_running_index[SM_RX_ID]);
napi_schedule(&bnx2x_fp(bp, fp->index, napi));
return IRQ_HANDLED;
}
-
/* HW Lock for shared dual port PHYs */
void bnx2x_acquire_phy_lock(struct bnx2x *bp)
{
@@ -738,12 +714,13 @@ void bnx2x_link_report(struct bnx2x *bp)
netdev_info(bp->dev, "NIC Link is Up, ");
line_speed = bp->link_vars.line_speed;
- if (IS_E1HMF(bp)) {
+ if (IS_MF(bp)) {
u16 vn_max_rate;
vn_max_rate =
- ((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >>
- FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
+ ((bp->mf_config[BP_VN(bp)] &
+ FUNC_MF_CFG_MAX_BW_MASK) >>
+ FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
if (vn_max_rate < line_speed)
line_speed = vn_max_rate;
}
@@ -773,23 +750,73 @@ void bnx2x_link_report(struct bnx2x *bp)
}
}
+/* Returns the number of actually allocated BDs */
+static inline int bnx2x_alloc_rx_bds(struct bnx2x_fastpath *fp,
+ int rx_ring_size)
+{
+ struct bnx2x *bp = fp->bp;
+ u16 ring_prod, cqe_ring_prod;
+ int i;
+
+ fp->rx_comp_cons = 0;
+ cqe_ring_prod = ring_prod = 0;
+ for (i = 0; i < rx_ring_size; i++) {
+ if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) {
+ BNX2X_ERR("was only able to allocate "
+ "%d rx skbs on queue[%d]\n", i, fp->index);
+ fp->eth_q_stats.rx_skb_alloc_failed++;
+ break;
+ }
+ ring_prod = NEXT_RX_IDX(ring_prod);
+ cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod);
+ WARN_ON(ring_prod <= i);
+ }
+
+ fp->rx_bd_prod = ring_prod;
+ /* Limit the CQE producer by the CQE ring size */
+ fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT,
+ cqe_ring_prod);
+ fp->rx_pkt = fp->rx_calls = 0;
+
+ return i;
+}
+
+static inline void bnx2x_alloc_rx_bd_ring(struct bnx2x_fastpath *fp)
+{
+ struct bnx2x *bp = fp->bp;
+ int rx_ring_size = bp->rx_ring_size ? bp->rx_ring_size :
+ MAX_RX_AVAIL/bp->num_queues;
+
+ rx_ring_size = max_t(int, MIN_RX_AVAIL, rx_ring_size);
+
+ bnx2x_alloc_rx_bds(fp, rx_ring_size);
+
+ /* Warning!
+ * this will generate an interrupt (to the TSTORM)
+ * must only be done after chip is initialized
+ */
+ bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod,
+ fp->rx_sge_prod);
+}
+
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;
- u16 ring_prod, cqe_ring_prod;
+ u16 ring_prod;
int i, j;
- bp->rx_buf_size = bp->dev->mtu + ETH_OVREHEAD + BNX2X_RX_ALIGN;
+ bp->rx_buf_size = bp->dev->mtu + ETH_OVREHEAD + BNX2X_RX_ALIGN +
+ IP_HEADER_ALIGNMENT_PADDING;
+
DP(NETIF_MSG_IFUP,
"mtu %d rx_buf_size %d\n", bp->dev->mtu, bp->rx_buf_size);
- if (bp->flags & TPA_ENABLE_FLAG) {
-
- for_each_queue(bp, j) {
- struct bnx2x_fastpath *fp = &bp->fp[j];
+ for_each_queue(bp, j) {
+ struct bnx2x_fastpath *fp = &bp->fp[j];
+ if (!fp->disable_tpa) {
for (i = 0; i < max_agg_queues; i++) {
fp->tpa_pool[i].skb =
netdev_alloc_skb(bp->dev, bp->rx_buf_size);
@@ -807,6 +834,35 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
mapping, 0);
fp->tpa_state[i] = BNX2X_TPA_STOP;
}
+
+ /* "next page" elements initialization */
+ bnx2x_set_next_page_sgl(fp);
+
+ /* set SGEs bit mask */
+ bnx2x_init_sge_ring_bit_mask(fp);
+
+ /* Allocate SGEs and initialize the ring elements */
+ for (i = 0, ring_prod = 0;
+ i < MAX_RX_SGE_CNT*NUM_RX_SGE_PAGES; i++) {
+
+ if (bnx2x_alloc_rx_sge(bp, fp, ring_prod) < 0) {
+ BNX2X_ERR("was only able to allocate "
+ "%d rx sges\n", i);
+ BNX2X_ERR("disabling TPA for"
+ " queue[%d]\n", j);
+ /* Cleanup already allocated elements */
+ bnx2x_free_rx_sge_range(bp,
+ fp, ring_prod);
+ bnx2x_free_tpa_pool(bp,
+ fp, max_agg_queues);
+ fp->disable_tpa = 1;
+ ring_prod = 0;
+ break;
+ }
+ ring_prod = NEXT_SGE_IDX(ring_prod);
+ }
+
+ fp->rx_sge_prod = ring_prod;
}
}
@@ -814,109 +870,29 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
struct bnx2x_fastpath *fp = &bp->fp[j];
fp->rx_bd_cons = 0;
- fp->rx_cons_sb = BNX2X_RX_SB_INDEX;
- fp->rx_bd_cons_sb = BNX2X_RX_SB_BD_INDEX;
-
- /* "next page" elements initialization */
- /* SGE ring */
- for (i = 1; i <= NUM_RX_SGE_PAGES; i++) {
- struct eth_rx_sge *sge;
-
- sge = &fp->rx_sge_ring[RX_SGE_CNT * i - 2];
- sge->addr_hi =
- cpu_to_le32(U64_HI(fp->rx_sge_mapping +
- BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES)));
- sge->addr_lo =
- cpu_to_le32(U64_LO(fp->rx_sge_mapping +
- BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES)));
- }
-
- bnx2x_init_sge_ring_bit_mask(fp);
- /* RX BD ring */
- for (i = 1; i <= NUM_RX_RINGS; i++) {
- struct eth_rx_bd *rx_bd;
-
- rx_bd = &fp->rx_desc_ring[RX_DESC_CNT * i - 2];
- rx_bd->addr_hi =
- cpu_to_le32(U64_HI(fp->rx_desc_mapping +
- BCM_PAGE_SIZE*(i % NUM_RX_RINGS)));
- rx_bd->addr_lo =
- cpu_to_le32(U64_LO(fp->rx_desc_mapping +
- BCM_PAGE_SIZE*(i % NUM_RX_RINGS)));
- }
+ bnx2x_set_next_page_rx_bd(fp);
/* CQ ring */
- for (i = 1; i <= NUM_RCQ_RINGS; i++) {
- struct eth_rx_cqe_next_page *nextpg;
-
- nextpg = (struct eth_rx_cqe_next_page *)
- &fp->rx_comp_ring[RCQ_DESC_CNT * i - 1];
- nextpg->addr_hi =
- cpu_to_le32(U64_HI(fp->rx_comp_mapping +
- BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
- nextpg->addr_lo =
- cpu_to_le32(U64_LO(fp->rx_comp_mapping +
- BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
- }
-
- /* Allocate SGEs and initialize the ring elements */
- for (i = 0, ring_prod = 0;
- i < MAX_RX_SGE_CNT*NUM_RX_SGE_PAGES; i++) {
-
- if (bnx2x_alloc_rx_sge(bp, fp, ring_prod) < 0) {
- BNX2X_ERR("was only able to allocate "
- "%d rx sges\n", i);
- BNX2X_ERR("disabling TPA for queue[%d]\n", j);
- /* Cleanup already allocated elements */
- bnx2x_free_rx_sge_range(bp, fp, ring_prod);
- bnx2x_free_tpa_pool(bp, fp, max_agg_queues);
- fp->disable_tpa = 1;
- ring_prod = 0;
- break;
- }
- ring_prod = NEXT_SGE_IDX(ring_prod);
- }
- fp->rx_sge_prod = ring_prod;
+ bnx2x_set_next_page_rx_cq(fp);
/* Allocate BDs and initialize BD ring */
- fp->rx_comp_cons = 0;
- cqe_ring_prod = ring_prod = 0;
- for (i = 0; i < bp->rx_ring_size; i++) {
- if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) {
- BNX2X_ERR("was only able to allocate "
- "%d rx skbs on queue[%d]\n", i, j);
- fp->eth_q_stats.rx_skb_alloc_failed++;
- break;
- }
- ring_prod = NEXT_RX_IDX(ring_prod);
- cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod);
- WARN_ON(ring_prod <= i);
- }
+ bnx2x_alloc_rx_bd_ring(fp);
- fp->rx_bd_prod = ring_prod;
- /* must not have more available CQEs than BDs */
- fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT,
- cqe_ring_prod);
- fp->rx_pkt = fp->rx_calls = 0;
-
- /* Warning!
- * this will generate an interrupt (to the TSTORM)
- * must only be done after chip is initialized
- */
- bnx2x_update_rx_prod(bp, fp, ring_prod, fp->rx_comp_prod,
- fp->rx_sge_prod);
if (j != 0)
continue;
- REG_WR(bp, BAR_USTRORM_INTMEM +
- USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func),
- U64_LO(fp->rx_comp_mapping));
- REG_WR(bp, BAR_USTRORM_INTMEM +
- USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func) + 4,
- U64_HI(fp->rx_comp_mapping));
+ if (!CHIP_IS_E2(bp)) {
+ REG_WR(bp, BAR_USTRORM_INTMEM +
+ USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func),
+ U64_LO(fp->rx_comp_mapping));
+ REG_WR(bp, BAR_USTRORM_INTMEM +
+ USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func) + 4,
+ U64_HI(fp->rx_comp_mapping));
+ }
}
}
+
static void bnx2x_free_tx_skbs(struct bnx2x *bp)
{
int i;
@@ -989,55 +965,49 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp)
}
}
-void bnx2x_free_irq(struct bnx2x *bp, bool disable_only)
+void bnx2x_free_irq(struct bnx2x *bp)
{
- if (bp->flags & USING_MSIX_FLAG) {
- if (!disable_only)
- bnx2x_free_msix_irqs(bp);
- pci_disable_msix(bp->pdev);
- bp->flags &= ~USING_MSIX_FLAG;
-
- } else if (bp->flags & USING_MSI_FLAG) {
- if (!disable_only)
- free_irq(bp->pdev->irq, bp->dev);
- pci_disable_msi(bp->pdev);
- bp->flags &= ~USING_MSI_FLAG;
-
- } else if (!disable_only)
+ if (bp->flags & USING_MSIX_FLAG)
+ bnx2x_free_msix_irqs(bp);
+ else if (bp->flags & USING_MSI_FLAG)
+ free_irq(bp->pdev->irq, bp->dev);
+ else
free_irq(bp->pdev->irq, bp->dev);
}
-static int bnx2x_enable_msix(struct bnx2x *bp)
+int bnx2x_enable_msix(struct bnx2x *bp)
{
- int i, rc, offset = 1;
- int igu_vec = 0;
+ int msix_vec = 0, i, rc, req_cnt;
- bp->msix_table[0].entry = igu_vec;
- DP(NETIF_MSG_IFUP, "msix_table[0].entry = %d (slowpath)\n", igu_vec);
+ bp->msix_table[msix_vec].entry = msix_vec;
+ DP(NETIF_MSG_IFUP, "msix_table[0].entry = %d (slowpath)\n",
+ bp->msix_table[0].entry);
+ msix_vec++;
#ifdef BCM_CNIC
- igu_vec = BP_L_ID(bp) + offset;
- bp->msix_table[1].entry = igu_vec;
- DP(NETIF_MSG_IFUP, "msix_table[1].entry = %d (CNIC)\n", igu_vec);
- offset++;
+ bp->msix_table[msix_vec].entry = msix_vec;
+ DP(NETIF_MSG_IFUP, "msix_table[%d].entry = %d (CNIC)\n",
+ bp->msix_table[msix_vec].entry, bp->msix_table[msix_vec].entry);
+ msix_vec++;
#endif
for_each_queue(bp, i) {
- igu_vec = BP_L_ID(bp) + offset + i;
- bp->msix_table[i + offset].entry = igu_vec;
+ bp->msix_table[msix_vec].entry = msix_vec;
DP(NETIF_MSG_IFUP, "msix_table[%d].entry = %d "
- "(fastpath #%u)\n", i + offset, igu_vec, i);
+ "(fastpath #%u)\n", msix_vec, msix_vec, i);
+ msix_vec++;
}
- rc = pci_enable_msix(bp->pdev, &bp->msix_table[0],
- BNX2X_NUM_QUEUES(bp) + offset);
+ req_cnt = BNX2X_NUM_QUEUES(bp) + CNIC_CONTEXT_USE + 1;
+
+ rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], req_cnt);
/*
* reconfigure number of tx/rx queues according to available
* MSI-X vectors
*/
if (rc >= BNX2X_MIN_MSIX_VEC_CNT) {
- /* vectors available for FP */
- int fp_vec = rc - BNX2X_MSIX_VEC_FP_START;
+ /* how less vectors we will have? */
+ int diff = req_cnt - rc;
DP(NETIF_MSG_IFUP,
"Trying to use less MSI-X vectors: %d\n", rc);
@@ -1049,12 +1019,17 @@ static int bnx2x_enable_msix(struct bnx2x *bp)
"MSI-X is not attainable rc %d\n", rc);
return rc;
}
-
- bp->num_queues = min(bp->num_queues, fp_vec);
+ /*
+ * decrease number of queues by number of unallocated entries
+ */
+ bp->num_queues -= diff;
DP(NETIF_MSG_IFUP, "New queue configuration set: %d\n",
bp->num_queues);
} else if (rc) {
+ /* fall to INTx if not enough memory */
+ if (rc == -ENOMEM)
+ bp->flags |= DISABLE_MSI_FLAG;
DP(NETIF_MSG_IFUP, "MSI-X is not attainable rc %d\n", rc);
return rc;
}
@@ -1083,7 +1058,7 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
snprintf(fp->name, sizeof(fp->name), "%s-fp-%d",
bp->dev->name, i);
- rc = request_irq(bp->msix_table[i + offset].vector,
+ rc = request_irq(bp->msix_table[offset].vector,
bnx2x_msix_fp_int, 0, fp->name, fp);
if (rc) {
BNX2X_ERR("request fp #%d irq failed rc %d\n", i, rc);
@@ -1091,10 +1066,12 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
return -EBUSY;
}
+ offset++;
fp->state = BNX2X_FP_STATE_IRQ;
}
i = BNX2X_NUM_QUEUES(bp);
+ offset = 1 + CNIC_CONTEXT_USE;
netdev_info(bp->dev, "using MSI-X IRQs: sp %d fp[%d] %d"
" ... fp[%d] %d\n",
bp->msix_table[0].vector,
@@ -1104,7 +1081,7 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
return 0;
}
-static int bnx2x_enable_msi(struct bnx2x *bp)
+int bnx2x_enable_msi(struct bnx2x *bp)
{
int rc;
@@ -1175,35 +1152,29 @@ void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
bnx2x_napi_disable(bp);
netif_tx_disable(bp->dev);
}
-static int bnx2x_set_num_queues(struct bnx2x *bp)
-{
- int rc = 0;
- switch (bp->int_mode) {
- case INT_MODE_INTx:
- case INT_MODE_MSI:
+void bnx2x_set_num_queues(struct bnx2x *bp)
+{
+ switch (bp->multi_mode) {
+ case ETH_RSS_MODE_DISABLED:
bp->num_queues = 1;
- DP(NETIF_MSG_IFUP, "set number of queues to 1\n");
break;
- default:
- /* Set number of queues according to bp->multi_mode value */
- bnx2x_set_num_queues_msix(bp);
-
- DP(NETIF_MSG_IFUP, "set number of queues to %d\n",
- bp->num_queues);
+ case ETH_RSS_MODE_REGULAR:
+ bp->num_queues = bnx2x_calc_num_queues(bp);
+ break;
- /* if we can't use MSI-X we only need one fp,
- * so try to enable MSI-X with the requested number of fp's
- * and fallback to MSI or legacy INTx with one fp
- */
- rc = bnx2x_enable_msix(bp);
- if (rc)
- /* failed to enable MSI-X */
- bp->num_queues = 1;
+ default:
+ bp->num_queues = 1;
break;
}
- bp->dev->real_num_tx_queues = bp->num_queues;
- return rc;
+}
+
+static void bnx2x_release_firmware(struct bnx2x *bp)
+{
+ kfree(bp->init_ops_offsets);
+ kfree(bp->init_ops);
+ kfree(bp->init_data);
+ release_firmware(bp->firmware);
}
/* must be called with rtnl_lock */
@@ -1212,6 +1183,13 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
u32 load_code;
int i, rc;
+ /* Set init arrays */
+ rc = bnx2x_init_firmware(bp);
+ if (rc) {
+ BNX2X_ERR("Error loading firmware\n");
+ return rc;
+ }
+
#ifdef BNX2X_STOP_ON_ERROR
if (unlikely(bp->panic))
return -EPERM;
@@ -1219,83 +1197,64 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
- rc = bnx2x_set_num_queues(bp);
+ /* must be called before memory allocation and HW init */
+ bnx2x_ilt_set_info(bp);
- if (bnx2x_alloc_mem(bp)) {
- bnx2x_free_irq(bp, true);
+ if (bnx2x_alloc_mem(bp))
return -ENOMEM;
+
+ netif_set_real_num_tx_queues(bp->dev, bp->num_queues);
+ rc = netif_set_real_num_rx_queues(bp->dev, bp->num_queues);
+ if (rc) {
+ BNX2X_ERR("Unable to update real_num_rx_queues\n");
+ goto load_error0;
}
for_each_queue(bp, i)
bnx2x_fp(bp, i, disable_tpa) =
((bp->flags & TPA_ENABLE_FLAG) == 0);
- for_each_queue(bp, i)
- netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
- bnx2x_poll, 128);
-
bnx2x_napi_enable(bp);
- if (bp->flags & USING_MSIX_FLAG) {
- rc = bnx2x_req_msix_irqs(bp);
- if (rc) {
- bnx2x_free_irq(bp, true);
- goto load_error1;
- }
- } else {
- /* Fall to INTx if failed to enable MSI-X due to lack of
- memory (in bnx2x_set_num_queues()) */
- if ((rc != -ENOMEM) && (bp->int_mode != INT_MODE_INTx))
- bnx2x_enable_msi(bp);
- bnx2x_ack_int(bp);
- rc = bnx2x_req_irq(bp);
- if (rc) {
- BNX2X_ERR("IRQ request failed rc %d, aborting\n", rc);
- bnx2x_free_irq(bp, true);
- goto load_error1;
- }
- if (bp->flags & USING_MSI_FLAG) {
- bp->dev->irq = bp->pdev->irq;
- netdev_info(bp->dev, "using MSI IRQ %d\n",
- bp->pdev->irq);
- }
- }
-
/* Send LOAD_REQUEST command to MCP
Returns the type of LOAD command:
if it is the first port to be initialized
common blocks should be initialized, otherwise - not
*/
if (!BP_NOMCP(bp)) {
- load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ);
+ load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ, 0);
if (!load_code) {
BNX2X_ERR("MCP response failure, aborting\n");
rc = -EBUSY;
- goto load_error2;
+ goto load_error1;
}
if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) {
rc = -EBUSY; /* other port in diagnostic mode */
- goto load_error2;
+ goto load_error1;
}
} else {
+ int path = BP_PATH(bp);
int port = BP_PORT(bp);
- DP(NETIF_MSG_IFUP, "NO MCP - load counts %d, %d, %d\n",
- load_count[0], load_count[1], load_count[2]);
- load_count[0]++;
- load_count[1 + port]++;
- DP(NETIF_MSG_IFUP, "NO MCP - new load counts %d, %d, %d\n",
- load_count[0], load_count[1], load_count[2]);
- if (load_count[0] == 1)
+ DP(NETIF_MSG_IFUP, "NO MCP - load counts[%d] %d, %d, %d\n",
+ path, load_count[path][0], load_count[path][1],
+ load_count[path][2]);
+ load_count[path][0]++;
+ load_count[path][1 + port]++;
+ DP(NETIF_MSG_IFUP, "NO MCP - new load counts[%d] %d, %d, %d\n",
+ path, load_count[path][0], load_count[path][1],
+ load_count[path][2]);
+ if (load_count[path][0] == 1)
load_code = FW_MSG_CODE_DRV_LOAD_COMMON;
- else if (load_count[1 + port] == 1)
+ else if (load_count[path][1 + port] == 1)
load_code = FW_MSG_CODE_DRV_LOAD_PORT;
else
load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION;
}
if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
+ (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP) ||
(load_code == FW_MSG_CODE_DRV_LOAD_PORT))
bp->port.pmf = 1;
else
@@ -1306,16 +1265,22 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
rc = bnx2x_init_hw(bp, load_code);
if (rc) {
BNX2X_ERR("HW init failed, aborting\n");
- bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
- bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP);
- bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+ bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
+ goto load_error2;
+ }
+
+ /* Connect to IRQs */
+ rc = bnx2x_setup_irqs(bp);
+ if (rc) {
+ bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
goto load_error2;
}
/* Setup NIC internals and enable interrupts */
bnx2x_nic_init(bp, load_code);
- if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) &&
+ if (((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
+ (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP)) &&
(bp->common.shmem2_base))
SHMEM2_WR(bp, dcc_support,
(SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
@@ -1323,7 +1288,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
/* Send LOAD_DONE command to MCP */
if (!BP_NOMCP(bp)) {
- load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
+ load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
if (!load_code) {
BNX2X_ERR("MCP response failure, aborting\n");
rc = -EBUSY;
@@ -1333,7 +1298,18 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
- rc = bnx2x_setup_leading(bp);
+ rc = bnx2x_func_start(bp);
+ if (rc) {
+ BNX2X_ERR("Function start failed!\n");
+#ifndef BNX2X_STOP_ON_ERROR
+ goto load_error3;
+#else
+ bp->panic = 1;
+ return -EBUSY;
+#endif
+ }
+
+ rc = bnx2x_setup_client(bp, &bp->fp[0], 1 /* Leading */);
if (rc) {
BNX2X_ERR("Setup leading failed!\n");
#ifndef BNX2X_STOP_ON_ERROR
@@ -1344,62 +1320,47 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
#endif
}
- if (CHIP_IS_E1H(bp))
- if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) {
- DP(NETIF_MSG_IFUP, "mf_cfg function disabled\n");
- bp->flags |= MF_FUNC_DIS;
- }
+ if (!CHIP_IS_E1(bp) &&
+ (bp->mf_config[BP_VN(bp)] & FUNC_MF_CFG_FUNC_DISABLED)) {
+ DP(NETIF_MSG_IFUP, "mf_cfg function disabled\n");
+ bp->flags |= MF_FUNC_DIS;
+ }
- if (bp->state == BNX2X_STATE_OPEN) {
-#ifdef BCM_CNIC
- /* Enable Timer scan */
- REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + BP_PORT(bp)*4, 1);
-#endif
- for_each_nondefault_queue(bp, i) {
- rc = bnx2x_setup_multi(bp, i);
- if (rc)
#ifdef BCM_CNIC
- goto load_error4;
-#else
- goto load_error3;
+ /* Enable Timer scan */
+ REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + BP_PORT(bp)*4, 1);
#endif
- }
- if (CHIP_IS_E1(bp))
- bnx2x_set_eth_mac_addr_e1(bp, 1);
- else
- bnx2x_set_eth_mac_addr_e1h(bp, 1);
+ for_each_nondefault_queue(bp, i) {
+ rc = bnx2x_setup_client(bp, &bp->fp[i], 0);
+ if (rc)
#ifdef BCM_CNIC
- /* Set iSCSI L2 MAC */
- mutex_lock(&bp->cnic_mutex);
- if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD) {
- bnx2x_set_iscsi_eth_mac_addr(bp, 1);
- bp->cnic_flags |= BNX2X_CNIC_FLAG_MAC_SET;
- bnx2x_init_sb(bp, bp->cnic_sb, bp->cnic_sb_mapping,
- CNIC_SB_ID(bp));
- }
- mutex_unlock(&bp->cnic_mutex);
+ goto load_error4;
+#else
+ goto load_error3;
#endif
}
+ /* Now when Clients are configured we are ready to work */
+ bp->state = BNX2X_STATE_OPEN;
+
+ bnx2x_set_eth_mac(bp, 1);
+
if (bp->port.pmf)
bnx2x_initial_phy_init(bp, load_mode);
/* Start fast path */
switch (load_mode) {
case LOAD_NORMAL:
- if (bp->state == BNX2X_STATE_OPEN) {
- /* Tx queue should be only reenabled */
- netif_tx_wake_all_queues(bp->dev);
- }
+ /* Tx queue should be only reenabled */
+ netif_tx_wake_all_queues(bp->dev);
/* Initialize the receive filter. */
bnx2x_set_rx_mode(bp->dev);
break;
case LOAD_OPEN:
netif_tx_start_all_queues(bp->dev);
- if (bp->state != BNX2X_STATE_OPEN)
- netif_tx_disable(bp->dev);
+ smp_mb__after_clear_bit();
/* Initialize the receive filter. */
bnx2x_set_rx_mode(bp->dev);
break;
@@ -1427,6 +1388,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
#endif
bnx2x_inc_load_cnt(bp);
+ bnx2x_release_firmware(bp);
+
return 0;
#ifdef BCM_CNIC
@@ -1436,24 +1399,28 @@ load_error4:
#endif
load_error3:
bnx2x_int_disable_sync(bp, 1);
- if (!BP_NOMCP(bp)) {
- bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP);
- bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
- }
- bp->port.pmf = 0;
+
/* Free SKBs, SGEs, TPA pool and driver internals */
bnx2x_free_skbs(bp);
for_each_queue(bp, i)
bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
-load_error2:
+
/* Release IRQs */
- bnx2x_free_irq(bp, false);
+ bnx2x_free_irq(bp);
+load_error2:
+ if (!BP_NOMCP(bp)) {
+ bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP, 0);
+ bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
+ }
+
+ bp->port.pmf = 0;
load_error1:
bnx2x_napi_disable(bp);
- for_each_queue(bp, i)
- netif_napi_del(&bnx2x_fp(bp, i, napi));
+load_error0:
bnx2x_free_mem(bp);
+ bnx2x_release_firmware(bp);
+
return rc;
}
@@ -1481,21 +1448,26 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
bp->rx_mode = BNX2X_RX_MODE_NONE;
bnx2x_set_storm_rx_mode(bp);
- /* Disable HW interrupts, NAPI and Tx */
- bnx2x_netif_stop(bp, 1);
- netif_carrier_off(bp->dev);
+ /* Stop Tx */
+ bnx2x_tx_disable(bp);
del_timer_sync(&bp->timer);
- SHMEM_WR(bp, func_mb[BP_FUNC(bp)].drv_pulse_mb,
+
+ SHMEM_WR(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb,
(DRV_PULSE_ALWAYS_ALIVE | bp->fw_drv_pulse_wr_seq));
- bnx2x_stats_handle(bp, STATS_EVENT_STOP);
- /* Release IRQs */
- bnx2x_free_irq(bp, false);
+ bnx2x_stats_handle(bp, STATS_EVENT_STOP);
/* Cleanup the chip if needed */
if (unload_mode != UNLOAD_RECOVERY)
bnx2x_chip_cleanup(bp, unload_mode);
+ else {
+ /* Disable HW interrupts, NAPI and Tx */
+ bnx2x_netif_stop(bp, 1);
+
+ /* Release IRQs */
+ bnx2x_free_irq(bp);
+ }
bp->port.pmf = 0;
@@ -1503,8 +1475,7 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
bnx2x_free_skbs(bp);
for_each_queue(bp, i)
bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
- for_each_queue(bp, i)
- netif_napi_del(&bnx2x_fp(bp, i, napi));
+
bnx2x_free_mem(bp);
bp->state = BNX2X_STATE_CLOSED;
@@ -1522,10 +1493,17 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
return 0;
}
+
int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state)
{
u16 pmcsr;
+ /* If there is no power capability, silently succeed */
+ if (!bp->pm_cap) {
+ DP(NETIF_MSG_HW, "No power capability. Breaking.\n");
+ return 0;
+ }
+
pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
switch (state) {
@@ -1568,13 +1546,10 @@ int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state)
return 0;
}
-
-
/*
* net_device service functions
*/
-
-static int bnx2x_poll(struct napi_struct *napi, int budget)
+int bnx2x_poll(struct napi_struct *napi, int budget)
{
int work_done = 0;
struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath,
@@ -1603,27 +1578,28 @@ static int bnx2x_poll(struct napi_struct *napi, int budget)
/* Fall out from the NAPI loop if needed */
if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
bnx2x_update_fpsb_idx(fp);
- /* bnx2x_has_rx_work() reads the status block, thus we need
- * to ensure that status block indices have been actually read
- * (bnx2x_update_fpsb_idx) prior to this check
- * (bnx2x_has_rx_work) so that we won't write the "newer"
- * value of the status block to IGU (if there was a DMA right
- * after bnx2x_has_rx_work and if there is no rmb, the memory
- * reading (bnx2x_update_fpsb_idx) may be postponed to right
- * before bnx2x_ack_sb). In this case there will never be
- * another interrupt until there is another update of the
- * status block, while there is still unhandled work.
- */
+ /* bnx2x_has_rx_work() reads the status block,
+ * thus we need to ensure that status block indices
+ * have been actually read (bnx2x_update_fpsb_idx)
+ * prior to this check (bnx2x_has_rx_work) so that
+ * we won't write the "newer" value of the status block
+ * to IGU (if there was a DMA right after
+ * bnx2x_has_rx_work and if there is no rmb, the memory
+ * reading (bnx2x_update_fpsb_idx) may be postponed
+ * to right before bnx2x_ack_sb). In this case there
+ * will never be another interrupt until there is
+ * another update of the status block, while there
+ * is still unhandled work.
+ */
rmb();
if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
napi_complete(napi);
/* Re-enable interrupts */
- bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID,
- le16_to_cpu(fp->fp_c_idx),
- IGU_INT_NOP, 1);
- bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID,
- le16_to_cpu(fp->fp_u_idx),
+ DP(NETIF_MSG_HW,
+ "Update index to %d\n", fp->fp_hc_idx);
+ bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID,
+ le16_to_cpu(fp->fp_hc_idx),
IGU_INT_ENABLE, 1);
break;
}
@@ -1633,7 +1609,6 @@ static int bnx2x_poll(struct napi_struct *napi, int budget)
return work_done;
}
-
/* we split the first BD into headers and data BDs
* to ease the pain of our fellow microcode engineers
* we use one mapping for both BDs
@@ -1807,6 +1782,122 @@ exit_lbl:
}
#endif
+static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb,
+ struct eth_tx_parse_bd_e2 *pbd,
+ u32 xmit_type)
+{
+ pbd->parsing_data |= cpu_to_le16(skb_shinfo(skb)->gso_size) <<
+ ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT;
+ if ((xmit_type & XMIT_GSO_V6) &&
+ (ipv6_hdr(skb)->nexthdr == NEXTHDR_IPV6))
+ pbd->parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
+}
+
+/**
+ * Update PBD in GSO case.
+ *
+ * @param skb
+ * @param tx_start_bd
+ * @param pbd
+ * @param xmit_type
+ */
+static inline void bnx2x_set_pbd_gso(struct sk_buff *skb,
+ struct eth_tx_parse_bd_e1x *pbd,
+ u32 xmit_type)
+{
+ pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
+ pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq);
+ pbd->tcp_flags = pbd_tcp_flags(skb);
+
+ if (xmit_type & XMIT_GSO_V4) {
+ pbd->ip_id = swab16(ip_hdr(skb)->id);
+ pbd->tcp_pseudo_csum =
+ swab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+ ip_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0));
+
+ } else
+ pbd->tcp_pseudo_csum =
+ swab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0));
+
+ pbd->global_data |= ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN;
+}
+
+/**
+ *
+ * @param skb
+ * @param tx_start_bd
+ * @param pbd_e2
+ * @param xmit_type
+ *
+ * @return header len
+ */
+static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
+ struct eth_tx_parse_bd_e2 *pbd,
+ u32 xmit_type)
+{
+ pbd->parsing_data |= cpu_to_le16(tcp_hdrlen(skb)/4) <<
+ ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT;
+
+ pbd->parsing_data |= cpu_to_le16(((unsigned char *)tcp_hdr(skb) -
+ skb->data) / 2) <<
+ ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT;
+
+ return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data;
+}
+
+/**
+ *
+ * @param skb
+ * @param tx_start_bd
+ * @param pbd
+ * @param xmit_type
+ *
+ * @return Header length
+ */
+static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb,
+ struct eth_tx_parse_bd_e1x *pbd,
+ u32 xmit_type)
+{
+ u8 hlen = (skb_network_header(skb) - skb->data) / 2;
+
+ /* for now NS flag is not used in Linux */
+ pbd->global_data =
+ (hlen | ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
+ ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT));
+
+ pbd->ip_hlen_w = (skb_transport_header(skb) -
+ skb_network_header(skb)) / 2;
+
+ hlen += pbd->ip_hlen_w + tcp_hdrlen(skb) / 2;
+
+ pbd->total_hlen_w = cpu_to_le16(hlen);
+ hlen = hlen*2;
+
+ if (xmit_type & XMIT_CSUM_TCP) {
+ pbd->tcp_pseudo_csum = swab16(tcp_hdr(skb)->check);
+
+ } else {
+ s8 fix = SKB_CS_OFF(skb); /* signed! */
+
+ DP(NETIF_MSG_TX_QUEUED,
+ "hlen %d fix %d csum before fix %x\n",
+ le16_to_cpu(pbd->total_hlen_w), fix, SKB_CS(skb));
+
+ /* HW bug: fixup the CSUM */
+ pbd->tcp_pseudo_csum =
+ bnx2x_csum_fix(skb_transport_header(skb),
+ SKB_CS(skb), fix);
+
+ DP(NETIF_MSG_TX_QUEUED, "csum after fix %x\n",
+ pbd->tcp_pseudo_csum);
+ }
+
+ return hlen;
+}
+
/* called with netif_tx_lock
* bnx2x_tx_int() runs without netif_tx_lock unless it needs to call
* netif_wake_queue()
@@ -1819,7 +1910,8 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct sw_tx_bd *tx_buf;
struct eth_tx_start_bd *tx_start_bd;
struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL;
- struct eth_tx_parse_bd *pbd = NULL;
+ struct eth_tx_parse_bd_e1x *pbd_e1x = NULL;
+ struct eth_tx_parse_bd_e2 *pbd_e2 = NULL;
u16 pkt_prod, bd_prod;
int nbd, fp_index;
dma_addr_t mapping;
@@ -1847,9 +1939,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY;
}
- DP(NETIF_MSG_TX_QUEUED, "SKB: summed %x protocol %x protocol(%x,%x)"
- " gso type %x xmit_type %x\n",
- skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr,
+ DP(NETIF_MSG_TX_QUEUED, "queue[%d]: SKB: summed %x protocol %x "
+ "protocol(%x,%x) gso type %x xmit_type %x\n",
+ fp_index, skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr,
ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type);
eth = (struct ethhdr *)skb->data;
@@ -1895,10 +1987,11 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
tx_start_bd = &fp->tx_desc_ring[bd_prod].start_bd;
tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
- tx_start_bd->general_data = (mac_type <<
- ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT);
+ SET_FLAG(tx_start_bd->general_data, ETH_TX_START_BD_ETH_ADDR_TYPE,
+ mac_type);
+
/* header nbd */
- tx_start_bd->general_data |= (1 << ETH_TX_START_BD_HDR_NBDS_SHIFT);
+ SET_FLAG(tx_start_bd->general_data, ETH_TX_START_BD_HDR_NBDS, 1);
/* remember the first BD of the packet */
tx_buf->first_bd = fp->tx_bd_prod;
@@ -1909,37 +2002,18 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
"sending pkt %u @%p next_idx %u bd %u @%p\n",
pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_start_bd);
-#ifdef BCM_VLAN
- if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb) &&
- (bp->flags & HW_VLAN_TX_FLAG)) {
- tx_start_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb));
- tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG;
+ if (vlan_tx_tag_present(skb)) {
+ tx_start_bd->vlan_or_ethertype =
+ cpu_to_le16(vlan_tx_tag_get(skb));
+ tx_start_bd->bd_flags.as_bitfield |=
+ (X_ETH_OUTBAND_VLAN << ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT);
} else
-#endif
- tx_start_bd->vlan = cpu_to_le16(pkt_prod);
+ tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
/* turn on parsing and get a BD */
bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
- pbd = &fp->tx_desc_ring[bd_prod].parse_bd;
-
- memset(pbd, 0, sizeof(struct eth_tx_parse_bd));
if (xmit_type & XMIT_CSUM) {
- hlen = (skb_network_header(skb) - skb->data) / 2;
-
- /* for now NS flag is not used in Linux */
- pbd->global_data =
- (hlen | ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
- ETH_TX_PARSE_BD_LLC_SNAP_EN_SHIFT));
-
- pbd->ip_hlen = (skb_transport_header(skb) -
- skb_network_header(skb)) / 2;
-
- hlen += pbd->ip_hlen + tcp_hdrlen(skb) / 2;
-
- pbd->total_hlen = cpu_to_le16(hlen);
- hlen = hlen*2;
-
tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_L4_CSUM;
if (xmit_type & XMIT_CSUM_V4)
@@ -1949,31 +2023,32 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
tx_start_bd->bd_flags.as_bitfield |=
ETH_TX_BD_FLAGS_IPV6;
- if (xmit_type & XMIT_CSUM_TCP) {
- pbd->tcp_pseudo_csum = swab16(tcp_hdr(skb)->check);
-
- } else {
- s8 fix = SKB_CS_OFF(skb); /* signed! */
-
- pbd->global_data |= ETH_TX_PARSE_BD_UDP_CS_FLG;
-
- DP(NETIF_MSG_TX_QUEUED,
- "hlen %d fix %d csum before fix %x\n",
- le16_to_cpu(pbd->total_hlen), fix, SKB_CS(skb));
+ if (!(xmit_type & XMIT_CSUM_TCP))
+ tx_start_bd->bd_flags.as_bitfield |=
+ ETH_TX_BD_FLAGS_IS_UDP;
+ }
- /* HW bug: fixup the CSUM */
- pbd->tcp_pseudo_csum =
- bnx2x_csum_fix(skb_transport_header(skb),
- SKB_CS(skb), fix);
+ if (CHIP_IS_E2(bp)) {
+ pbd_e2 = &fp->tx_desc_ring[bd_prod].parse_bd_e2;
+ memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2));
+ /* Set PBD in checksum offload case */
+ if (xmit_type & XMIT_CSUM)
+ hlen = bnx2x_set_pbd_csum_e2(bp,
+ skb, pbd_e2, xmit_type);
+ } else {
+ pbd_e1x = &fp->tx_desc_ring[bd_prod].parse_bd_e1x;
+ memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x));
+ /* Set PBD in checksum offload case */
+ if (xmit_type & XMIT_CSUM)
+ hlen = bnx2x_set_pbd_csum(bp, skb, pbd_e1x, xmit_type);
- DP(NETIF_MSG_TX_QUEUED, "csum after fix %x\n",
- pbd->tcp_pseudo_csum);
- }
}
+ /* Map skb linear data for DMA */
mapping = dma_map_single(&bp->pdev->dev, skb->data,
skb_headlen(skb), DMA_TO_DEVICE);
+ /* Setup the data pointer of the first BD of the packet */
tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
nbd = skb_shinfo(skb)->nr_frags + 2; /* start_bd + pbd + frags */
@@ -1985,7 +2060,8 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
" nbytes %d flags %x vlan %x\n",
tx_start_bd, tx_start_bd->addr_hi, tx_start_bd->addr_lo,
le16_to_cpu(tx_start_bd->nbd), le16_to_cpu(tx_start_bd->nbytes),
- tx_start_bd->bd_flags.as_bitfield, le16_to_cpu(tx_start_bd->vlan));
+ tx_start_bd->bd_flags.as_bitfield,
+ le16_to_cpu(tx_start_bd->vlan_or_ethertype));
if (xmit_type & XMIT_GSO) {
@@ -1999,28 +2075,14 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(skb_headlen(skb) > hlen))
bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd,
hlen, bd_prod, ++nbd);
-
- pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
- pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq);
- pbd->tcp_flags = pbd_tcp_flags(skb);
-
- if (xmit_type & XMIT_GSO_V4) {
- pbd->ip_id = swab16(ip_hdr(skb)->id);
- pbd->tcp_pseudo_csum =
- swab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
- ip_hdr(skb)->daddr,
- 0, IPPROTO_TCP, 0));
-
- } else
- pbd->tcp_pseudo_csum =
- swab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
- &ipv6_hdr(skb)->daddr,
- 0, IPPROTO_TCP, 0));
-
- pbd->global_data |= ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN;
+ if (CHIP_IS_E2(bp))
+ bnx2x_set_pbd_gso_e2(skb, pbd_e2, xmit_type);
+ else
+ bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type);
}
tx_data_bd = (struct eth_tx_bd *)tx_start_bd;
+ /* Handle fragmented skb */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -2057,14 +2119,21 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (total_pkt_bd != NULL)
total_pkt_bd->total_pkt_bytes = pkt_size;
- if (pbd)
+ if (pbd_e1x)
DP(NETIF_MSG_TX_QUEUED,
- "PBD @%p ip_data %x ip_hlen %u ip_id %u lso_mss %u"
+ "PBD (E1X) @%p ip_data %x ip_hlen %u ip_id %u lso_mss %u"
" tcp_flags %x xsum %x seq %u hlen %u\n",
- pbd, pbd->global_data, pbd->ip_hlen, pbd->ip_id,
- pbd->lso_mss, pbd->tcp_flags, pbd->tcp_pseudo_csum,
- pbd->tcp_send_seq, le16_to_cpu(pbd->total_hlen));
-
+ pbd_e1x, pbd_e1x->global_data, pbd_e1x->ip_hlen_w,
+ pbd_e1x->ip_id, pbd_e1x->lso_mss, pbd_e1x->tcp_flags,
+ pbd_e1x->tcp_pseudo_csum, pbd_e1x->tcp_send_seq,
+ le16_to_cpu(pbd_e1x->total_hlen_w));
+ if (pbd_e2)
+ DP(NETIF_MSG_TX_QUEUED,
+ "PBD (E2) @%p dst %x %x %x src %x %x %x parsing_data %x\n",
+ pbd_e2, pbd_e2->dst_mac_addr_hi, pbd_e2->dst_mac_addr_mid,
+ pbd_e2->dst_mac_addr_lo, pbd_e2->src_mac_addr_hi,
+ pbd_e2->src_mac_addr_mid, pbd_e2->src_mac_addr_lo,
+ pbd_e2->parsing_data);
DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %d bd %u\n", nbd, bd_prod);
/*
@@ -2078,7 +2147,8 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
fp->tx_db.data.prod += nbd;
barrier();
- DOORBELL(bp, fp->index, fp->tx_db.raw);
+
+ DOORBELL(bp, fp->cid, fp->tx_db.raw);
mmiowb();
@@ -2100,6 +2170,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
+
/* called with rtnl_lock */
int bnx2x_change_mac_addr(struct net_device *dev, void *p)
{
@@ -2110,16 +2181,76 @@ int bnx2x_change_mac_addr(struct net_device *dev, void *p)
return -EINVAL;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
- if (netif_running(dev)) {
- if (CHIP_IS_E1(bp))
- bnx2x_set_eth_mac_addr_e1(bp, 1);
- else
- bnx2x_set_eth_mac_addr_e1h(bp, 1);
+ if (netif_running(dev))
+ bnx2x_set_eth_mac(bp, 1);
+
+ return 0;
+}
+
+
+static int bnx2x_setup_irqs(struct bnx2x *bp)
+{
+ int rc = 0;
+ if (bp->flags & USING_MSIX_FLAG) {
+ rc = bnx2x_req_msix_irqs(bp);
+ if (rc)
+ return rc;
+ } else {
+ bnx2x_ack_int(bp);
+ rc = bnx2x_req_irq(bp);
+ if (rc) {
+ BNX2X_ERR("IRQ request failed rc %d, aborting\n", rc);
+ return rc;
+ }
+ if (bp->flags & USING_MSI_FLAG) {
+ bp->dev->irq = bp->pdev->irq;
+ netdev_info(bp->dev, "using MSI IRQ %d\n",
+ bp->pdev->irq);
+ }
}
return 0;
}
+void bnx2x_free_mem_bp(struct bnx2x *bp)
+{
+ kfree(bp->fp);
+ kfree(bp->msix_table);
+ kfree(bp->ilt);
+}
+
+int __devinit bnx2x_alloc_mem_bp(struct bnx2x *bp)
+{
+ struct bnx2x_fastpath *fp;
+ struct msix_entry *tbl;
+ struct bnx2x_ilt *ilt;
+
+ /* fp array */
+ fp = kzalloc(L2_FP_COUNT(bp->l2_cid_count)*sizeof(*fp), GFP_KERNEL);
+ if (!fp)
+ goto alloc_err;
+ bp->fp = fp;
+
+ /* msix table */
+ tbl = kzalloc((bp->l2_cid_count + 1) * sizeof(*tbl),
+ GFP_KERNEL);
+ if (!tbl)
+ goto alloc_err;
+ bp->msix_table = tbl;
+
+ /* ilt */
+ ilt = kzalloc(sizeof(*ilt), GFP_KERNEL);
+ if (!ilt)
+ goto alloc_err;
+ bp->ilt = ilt;
+
+ return 0;
+alloc_err:
+ bnx2x_free_mem_bp(bp);
+ return -ENOMEM;
+
+}
+
/* called with rtnl_lock */
int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
{
@@ -2161,29 +2292,6 @@ void bnx2x_tx_timeout(struct net_device *dev)
schedule_delayed_work(&bp->reset_task, 0);
}
-#ifdef BCM_VLAN
-/* called with rtnl_lock */
-void bnx2x_vlan_rx_register(struct net_device *dev,
- struct vlan_group *vlgrp)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- bp->vlgrp = vlgrp;
-
- /* Set flags according to the required capabilities */
- bp->flags &= ~(HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG);
-
- if (dev->features & NETIF_F_HW_VLAN_TX)
- bp->flags |= HW_VLAN_TX_FLAG;
-
- if (dev->features & NETIF_F_HW_VLAN_RX)
- bp->flags |= HW_VLAN_RX_FLAG;
-
- if (netif_running(dev))
- bnx2x_set_client_config(bp);
-}
-
-#endif
int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *dev = pci_get_drvdata(pdev);
@@ -2244,6 +2352,8 @@ int bnx2x_resume(struct pci_dev *pdev)
bnx2x_set_power_state(bp, PCI_D0);
netif_device_attach(dev);
+ /* Since the chip was reset, clear the FW sequence number */
+ bp->fw_seq = 0;
rc = bnx2x_nic_load(bp, LOAD_OPEN);
rtnl_unlock();
diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h
index d1979b1a7ed2..6b28739c5302 100644
--- a/drivers/net/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/bnx2x/bnx2x_cmn.h
@@ -23,6 +23,7 @@
#include "bnx2x.h"
+extern int num_queues;
/*********************** Interfaces ****************************
* Functions that need to be implemented by each driver version
@@ -49,10 +50,11 @@ void bnx2x_link_set(struct bnx2x *bp);
* Query link status
*
* @param bp
+ * @param is_serdes
*
* @return 0 - link is UP
*/
-u8 bnx2x_link_test(struct bnx2x *bp);
+u8 bnx2x_link_test(struct bnx2x *bp, u8 is_serdes);
/**
* Handles link status change
@@ -62,6 +64,15 @@ u8 bnx2x_link_test(struct bnx2x *bp);
void bnx2x__link_status_update(struct bnx2x *bp);
/**
+ * Report link status to upper layer
+ *
+ * @param bp
+ *
+ * @return int
+ */
+void bnx2x_link_report(struct bnx2x *bp);
+
+/**
* MSI-X slowpath interrupt handler
*
* @param irq
@@ -115,6 +126,15 @@ void bnx2x_int_enable(struct bnx2x *bp);
void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw);
/**
+ * Loads device firmware
+ *
+ * @param bp
+ *
+ * @return int
+ */
+int bnx2x_init_firmware(struct bnx2x *bp);
+
+/**
* Init HW blocks according to current initialization stage:
* COMMON, PORT or FUNCTION.
*
@@ -153,32 +173,24 @@ int bnx2x_alloc_mem(struct bnx2x *bp);
void bnx2x_free_mem(struct bnx2x *bp);
/**
- * Bring up a leading (the first) eth Client.
- *
- * @param bp
- *
- * @return int
- */
-int bnx2x_setup_leading(struct bnx2x *bp);
-
-/**
- * Setup non-leading eth Client.
+ * Setup eth Client.
*
* @param bp
* @param fp
+ * @param is_leading
*
* @return int
*/
-int bnx2x_setup_multi(struct bnx2x *bp, int index);
+int bnx2x_setup_client(struct bnx2x *bp, struct bnx2x_fastpath *fp,
+ int is_leading);
/**
- * Set number of quueus according to mode and number of available
- * msi-x vectors
+ * Set number of queues according to mode
*
* @param bp
*
*/
-void bnx2x_set_num_queues_msix(struct bnx2x *bp);
+void bnx2x_set_num_queues(struct bnx2x *bp);
/**
* Cleanup chip internals:
@@ -213,101 +225,187 @@ int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource);
/**
* Configure eth MAC address in the HW according to the value in
- * netdev->dev_addr for 57711
+ * netdev->dev_addr.
*
* @param bp driver handle
* @param set
*/
-void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set);
+void bnx2x_set_eth_mac(struct bnx2x *bp, int set);
/**
- * Configure eth MAC address in the HW according to the value in
- * netdev->dev_addr for 57710
+ * Set MAC filtering configurations.
+ *
+ * @remarks called with netif_tx_lock from dev_mcast.c
+ *
+ * @param dev net_device
+ */
+void bnx2x_set_rx_mode(struct net_device *dev);
+
+/**
+ * Configure MAC filtering rules in a FW.
*
* @param bp driver handle
- * @param set
*/
-void bnx2x_set_eth_mac_addr_e1(struct bnx2x *bp, int set);
+void bnx2x_set_storm_rx_mode(struct bnx2x *bp);
+
+/* Parity errors related */
+void bnx2x_inc_load_cnt(struct bnx2x *bp);
+u32 bnx2x_dec_load_cnt(struct bnx2x *bp);
+bool bnx2x_chk_parity_attn(struct bnx2x *bp);
+bool bnx2x_reset_is_done(struct bnx2x *bp);
+void bnx2x_disable_close_the_gate(struct bnx2x *bp);
-#ifdef BCM_CNIC
/**
- * Set iSCSI MAC(s) at the next enties in the CAM after the ETH
- * MAC(s). The function will wait until the ramrod completion
- * returns.
+ * Perform statistics handling according to event
*
* @param bp driver handle
- * @param set set or clear the CAM entry
+ * @param event bnx2x_stats_event
+ */
+void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event);
+
+/**
+ * Handle ramrods completion
*
- * @return 0 if cussess, -ENODEV if ramrod doesn't return.
+ * @param fp fastpath handle for the event
+ * @param rr_cqe eth_rx_cqe
*/
-int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set);
-#endif
+void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe);
/**
- * Initialize status block in FW and HW
+ * Init/halt function before/after sending
+ * CLIENT_SETUP/CFC_DEL for the first/last client.
*
- * @param bp driver handle
- * @param sb host_status_block
- * @param dma_addr_t mapping
- * @param int sb_id
+ * @param bp
+ *
+ * @return int
*/
-void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb,
- dma_addr_t mapping, int sb_id);
+int bnx2x_func_start(struct bnx2x *bp);
/**
- * Reconfigure FW/HW according to dev->flags rx mode
+ * Prepare ILT configurations according to current driver
+ * parameters.
*
- * @param dev net_device
+ * @param bp
+ */
+void bnx2x_ilt_set_info(struct bnx2x *bp);
+
+/**
+ * Set power state to the requested value. Currently only D0 and
+ * D3hot are supported.
*
+ * @param bp
+ * @param state D0 or D3hot
+ *
+ * @return int
*/
-void bnx2x_set_rx_mode(struct net_device *dev);
+int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state);
+
+/* dev_close main block */
+int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode);
+
+/* dev_open main block */
+int bnx2x_nic_load(struct bnx2x *bp, int load_mode);
+
+/* hard_xmit callback */
+netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev);
+
+int bnx2x_change_mac_addr(struct net_device *dev, void *p);
+
+/* NAPI poll Rx part */
+int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget);
+
+/* NAPI poll Tx part */
+int bnx2x_tx_int(struct bnx2x_fastpath *fp);
+
+/* suspend/resume callbacks */
+int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state);
+int bnx2x_resume(struct pci_dev *pdev);
+
+/* Release IRQ vectors */
+void bnx2x_free_irq(struct bnx2x *bp);
+
+void bnx2x_init_rx_rings(struct bnx2x *bp);
+void bnx2x_free_skbs(struct bnx2x *bp);
+void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw);
+void bnx2x_netif_start(struct bnx2x *bp);
/**
- * Configure MAC filtering rules in a FW.
+ * Fill msix_table, request vectors, update num_queues according
+ * to number of available vectors
*
- * @param bp driver handle
+ * @param bp
+ *
+ * @return int
*/
-void bnx2x_set_storm_rx_mode(struct bnx2x *bp);
+int bnx2x_enable_msix(struct bnx2x *bp);
-/* Parity errors related */
-void bnx2x_inc_load_cnt(struct bnx2x *bp);
-u32 bnx2x_dec_load_cnt(struct bnx2x *bp);
-bool bnx2x_chk_parity_attn(struct bnx2x *bp);
-bool bnx2x_reset_is_done(struct bnx2x *bp);
-void bnx2x_disable_close_the_gate(struct bnx2x *bp);
+/**
+ * Request msi mode from OS, updated internals accordingly
+ *
+ * @param bp
+ *
+ * @return int
+ */
+int bnx2x_enable_msi(struct bnx2x *bp);
/**
- * Perform statistics handling according to event
+ * NAPI callback
*
- * @param bp driver handle
- * @param even tbnx2x_stats_event
+ * @param napi
+ * @param budget
+ *
+ * @return int
*/
-void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event);
+int bnx2x_poll(struct napi_struct *napi, int budget);
/**
- * Configures FW with client paramteres (like HW VLAN removal)
- * for each active client.
+ * Allocate/release memories outsize main driver structure
*
* @param bp
+ *
+ * @return int
*/
-void bnx2x_set_client_config(struct bnx2x *bp);
+int __devinit bnx2x_alloc_mem_bp(struct bnx2x *bp);
+void bnx2x_free_mem_bp(struct bnx2x *bp);
/**
- * Handle sp events
+ * Change mtu netdev callback
*
- * @param fp fastpath handle for the event
- * @param rr_cqe eth_rx_cqe
+ * @param dev
+ * @param new_mtu
+ *
+ * @return int
*/
-void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe);
+int bnx2x_change_mtu(struct net_device *dev, int new_mtu);
+/**
+ * tx timeout netdev callback
+ *
+ * @param dev
+ * @param new_mtu
+ *
+ * @return int
+ */
+void bnx2x_tx_timeout(struct net_device *dev);
+
+#ifdef BCM_VLAN
+/**
+ * vlan rx register netdev callback
+ *
+ * @param dev
+ * @param new_mtu
+ *
+ * @return int
+ */
+void bnx2x_vlan_rx_register(struct net_device *dev,
+ struct vlan_group *vlgrp);
+
+#endif
static inline void bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
{
- struct host_status_block *fpsb = fp->status_blk;
-
barrier(); /* status block is written to by the chip */
- fp->fp_c_idx = fpsb->c_status_block.status_block_index;
- fp->fp_u_idx = fpsb->u_status_block.status_block_index;
+ fp->fp_hc_idx = fp->sb_running_index[SM_RX_ID];
}
static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
@@ -334,8 +432,8 @@ static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
wmb();
for (i = 0; i < sizeof(struct ustorm_eth_rx_producers)/4; i++)
- REG_WR(bp, BAR_USTRORM_INTMEM +
- USTORM_RX_PRODS_OFFSET(BP_PORT(bp), fp->cl_id) + i*4,
+ REG_WR(bp,
+ BAR_USTRORM_INTMEM + fp->ustorm_rx_prods_offset + i*4,
((u32 *)&rx_prods)[i]);
mmiowb(); /* keep prod updates ordered */
@@ -345,10 +443,77 @@ static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
fp->index, bd_prod, rx_comp_prod, rx_sge_prod);
}
+static inline void bnx2x_igu_ack_sb_gen(struct bnx2x *bp, u8 igu_sb_id,
+ u8 segment, u16 index, u8 op,
+ u8 update, u32 igu_addr)
+{
+ struct igu_regular cmd_data = {0};
+
+ cmd_data.sb_id_and_flags =
+ ((index << IGU_REGULAR_SB_INDEX_SHIFT) |
+ (segment << IGU_REGULAR_SEGMENT_ACCESS_SHIFT) |
+ (update << IGU_REGULAR_BUPDATE_SHIFT) |
+ (op << IGU_REGULAR_ENABLE_INT_SHIFT));
+
+ DP(NETIF_MSG_HW, "write 0x%08x to IGU addr 0x%x\n",
+ cmd_data.sb_id_and_flags, igu_addr);
+ REG_WR(bp, igu_addr, cmd_data.sb_id_and_flags);
+
+ /* Make sure that ACK is written */
+ mmiowb();
+ barrier();
+}
+
+static inline void bnx2x_igu_clear_sb_gen(struct bnx2x *bp,
+ u8 idu_sb_id, bool is_Pf)
+{
+ u32 data, ctl, cnt = 100;
+ u32 igu_addr_data = IGU_REG_COMMAND_REG_32LSB_DATA;
+ u32 igu_addr_ctl = IGU_REG_COMMAND_REG_CTRL;
+ u32 igu_addr_ack = IGU_REG_CSTORM_TYPE_0_SB_CLEANUP + (idu_sb_id/32)*4;
+ u32 sb_bit = 1 << (idu_sb_id%32);
+ u32 func_encode = BP_FUNC(bp) |
+ ((is_Pf == true ? 1 : 0) << IGU_FID_ENCODE_IS_PF_SHIFT);
+ u32 addr_encode = IGU_CMD_E2_PROD_UPD_BASE + idu_sb_id;
+
+ /* Not supported in BC mode */
+ if (CHIP_INT_MODE_IS_BC(bp))
+ return;
+
+ data = (IGU_USE_REGISTER_cstorm_type_0_sb_cleanup
+ << IGU_REGULAR_CLEANUP_TYPE_SHIFT) |
+ IGU_REGULAR_CLEANUP_SET |
+ IGU_REGULAR_BCLEANUP;
+
+ ctl = addr_encode << IGU_CTRL_REG_ADDRESS_SHIFT |
+ func_encode << IGU_CTRL_REG_FID_SHIFT |
+ IGU_CTRL_CMD_TYPE_WR << IGU_CTRL_REG_TYPE_SHIFT;
+ DP(NETIF_MSG_HW, "write 0x%08x to IGU(via GRC) addr 0x%x\n",
+ data, igu_addr_data);
+ REG_WR(bp, igu_addr_data, data);
+ mmiowb();
+ barrier();
+ DP(NETIF_MSG_HW, "write 0x%08x to IGU(via GRC) addr 0x%x\n",
+ ctl, igu_addr_ctl);
+ REG_WR(bp, igu_addr_ctl, ctl);
+ mmiowb();
+ barrier();
+
+ /* wait for clean up to finish */
+ while (!(REG_RD(bp, igu_addr_ack) & sb_bit) && --cnt)
+ msleep(20);
-static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id,
- u8 storm, u16 index, u8 op, u8 update)
+
+ if (!(REG_RD(bp, igu_addr_ack) & sb_bit)) {
+ DP(NETIF_MSG_HW, "Unable to finish IGU cleanup: "
+ "idu_sb_id %d offset %d bit %d (cnt %d)\n",
+ idu_sb_id, idu_sb_id/32, idu_sb_id%32, cnt);
+ }
+}
+
+static inline void bnx2x_hc_ack_sb(struct bnx2x *bp, u8 sb_id,
+ u8 storm, u16 index, u8 op, u8 update)
{
u32 hc_addr = (HC_REG_COMMAND_REG + BP_PORT(bp)*32 +
COMMAND_REG_INT_ACK);
@@ -369,7 +534,37 @@ static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id,
mmiowb();
barrier();
}
-static inline u16 bnx2x_ack_int(struct bnx2x *bp)
+
+static inline void bnx2x_igu_ack_sb(struct bnx2x *bp, u8 igu_sb_id, u8 segment,
+ u16 index, u8 op, u8 update)
+{
+ u32 igu_addr = BAR_IGU_INTMEM + (IGU_CMD_INT_ACK_BASE + igu_sb_id)*8;
+
+ bnx2x_igu_ack_sb_gen(bp, igu_sb_id, segment, index, op, update,
+ igu_addr);
+}
+
+static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 igu_sb_id, u8 storm,
+ u16 index, u8 op, u8 update)
+{
+ if (bp->common.int_block == INT_BLOCK_HC)
+ bnx2x_hc_ack_sb(bp, igu_sb_id, storm, index, op, update);
+ else {
+ u8 segment;
+
+ if (CHIP_INT_MODE_IS_BC(bp))
+ segment = storm;
+ else if (igu_sb_id != bp->igu_dsb_id)
+ segment = IGU_SEG_ACCESS_DEF;
+ else if (storm == ATTENTION_ID)
+ segment = IGU_SEG_ACCESS_ATTN;
+ else
+ segment = IGU_SEG_ACCESS_DEF;
+ bnx2x_igu_ack_sb(bp, igu_sb_id, segment, index, op, update);
+ }
+}
+
+static inline u16 bnx2x_hc_ack_int(struct bnx2x *bp)
{
u32 hc_addr = (HC_REG_COMMAND_REG + BP_PORT(bp)*32 +
COMMAND_REG_SIMD_MASK);
@@ -378,18 +573,36 @@ static inline u16 bnx2x_ack_int(struct bnx2x *bp)
DP(BNX2X_MSG_OFF, "read 0x%08x from HC addr 0x%x\n",
result, hc_addr);
+ barrier();
+ return result;
+}
+
+static inline u16 bnx2x_igu_ack_int(struct bnx2x *bp)
+{
+ u32 igu_addr = (BAR_IGU_INTMEM + IGU_REG_SISR_MDPC_WMASK_LSB_UPPER*8);
+ u32 result = REG_RD(bp, igu_addr);
+
+ DP(NETIF_MSG_HW, "read 0x%08x from IGU addr 0x%x\n",
+ result, igu_addr);
+
+ barrier();
return result;
}
-/*
- * fast path service functions
- */
+static inline u16 bnx2x_ack_int(struct bnx2x *bp)
+{
+ barrier();
+ if (bp->common.int_block == INT_BLOCK_HC)
+ return bnx2x_hc_ack_int(bp);
+ else
+ return bnx2x_igu_ack_int(bp);
+}
static inline int bnx2x_has_tx_work_unload(struct bnx2x_fastpath *fp)
{
/* Tell compiler that consumer and producer can change */
barrier();
- return (fp->tx_pkt_prod != fp->tx_pkt_cons);
+ return fp->tx_pkt_prod != fp->tx_pkt_cons;
}
static inline u16 bnx2x_tx_avail(struct bnx2x_fastpath *fp)
@@ -424,6 +637,29 @@ static inline int bnx2x_has_tx_work(struct bnx2x_fastpath *fp)
return hw_cons != fp->tx_pkt_cons;
}
+static inline int bnx2x_has_rx_work(struct bnx2x_fastpath *fp)
+{
+ u16 rx_cons_sb;
+
+ /* Tell compiler that status block fields can change */
+ barrier();
+ rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb);
+ if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT)
+ rx_cons_sb++;
+ return (fp->rx_comp_cons != rx_cons_sb);
+}
+
+/**
+ * disables tx from stack point of view
+ *
+ * @param bp
+ */
+static inline void bnx2x_tx_disable(struct bnx2x *bp)
+{
+ netif_tx_disable(bp->dev);
+ netif_carrier_off(bp->dev);
+}
+
static inline void bnx2x_free_rx_sge(struct bnx2x *bp,
struct bnx2x_fastpath *fp, u16 index)
{
@@ -436,7 +672,7 @@ static inline void bnx2x_free_rx_sge(struct bnx2x *bp,
return;
dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(sw_buf, mapping),
- SGE_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE);
+ SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
__free_pages(page, PAGES_PER_SGE_SHIFT);
sw_buf->page = NULL;
@@ -444,13 +680,67 @@ static inline void bnx2x_free_rx_sge(struct bnx2x *bp,
sge->addr_lo = 0;
}
-static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp,
- struct bnx2x_fastpath *fp, int last)
+static inline void bnx2x_add_all_napi(struct bnx2x *bp)
{
int i;
- for (i = 0; i < last; i++)
- bnx2x_free_rx_sge(bp, fp, i);
+ /* Add NAPI objects */
+ for_each_queue(bp, i)
+ netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
+ bnx2x_poll, BNX2X_NAPI_WEIGHT);
+}
+
+static inline void bnx2x_del_all_napi(struct bnx2x *bp)
+{
+ int i;
+
+ for_each_queue(bp, i)
+ netif_napi_del(&bnx2x_fp(bp, i, napi));
+}
+
+static inline void bnx2x_disable_msi(struct bnx2x *bp)
+{
+ if (bp->flags & USING_MSIX_FLAG) {
+ pci_disable_msix(bp->pdev);
+ bp->flags &= ~USING_MSIX_FLAG;
+ } else if (bp->flags & USING_MSI_FLAG) {
+ pci_disable_msi(bp->pdev);
+ bp->flags &= ~USING_MSI_FLAG;
+ }
+}
+
+static inline int bnx2x_calc_num_queues(struct bnx2x *bp)
+{
+ return num_queues ?
+ min_t(int, num_queues, BNX2X_MAX_QUEUES(bp)) :
+ min_t(int, num_online_cpus(), BNX2X_MAX_QUEUES(bp));
+}
+
+static inline void bnx2x_clear_sge_mask_next_elems(struct bnx2x_fastpath *fp)
+{
+ int i, j;
+
+ for (i = 1; i <= NUM_RX_SGE_PAGES; i++) {
+ int idx = RX_SGE_CNT * i - 1;
+
+ for (j = 0; j < 2; j++) {
+ SGE_MASK_CLEAR_BIT(fp, idx);
+ idx--;
+ }
+ }
+}
+
+static inline void bnx2x_init_sge_ring_bit_mask(struct bnx2x_fastpath *fp)
+{
+ /* Set the mask to all 1-s: it's faster to compare to 0 than to 0xf-s */
+ memset(fp->sge_mask, 0xff,
+ (NUM_RX_SGE >> RX_SGE_MASK_ELEM_SHIFT)*sizeof(u64));
+
+ /* Clear the two last indices in the page to 1:
+ these are the indices that correspond to the "next" element,
+ hence will never be indicated and should be removed from
+ the calculations. */
+ bnx2x_clear_sge_mask_next_elems(fp);
}
static inline int bnx2x_alloc_rx_sge(struct bnx2x *bp,
@@ -479,6 +769,7 @@ static inline int bnx2x_alloc_rx_sge(struct bnx2x *bp,
return 0;
}
+
static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
struct bnx2x_fastpath *fp, u16 index)
{
@@ -513,7 +804,7 @@ static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
* so there is no need to check for dma_mapping_error().
*/
static inline void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp,
- struct sk_buff *skb, u16 cons, u16 prod)
+ u16 cons, u16 prod)
{
struct bnx2x *bp = fp->bp;
struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons];
@@ -531,32 +822,15 @@ static inline void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp,
*prod_bd = *cons_bd;
}
-static inline void bnx2x_clear_sge_mask_next_elems(struct bnx2x_fastpath *fp)
+static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp, int last)
{
- int i, j;
-
- for (i = 1; i <= NUM_RX_SGE_PAGES; i++) {
- int idx = RX_SGE_CNT * i - 1;
+ int i;
- for (j = 0; j < 2; j++) {
- SGE_MASK_CLEAR_BIT(fp, idx);
- idx--;
- }
- }
+ for (i = 0; i < last; i++)
+ bnx2x_free_rx_sge(bp, fp, i);
}
-static inline void bnx2x_init_sge_ring_bit_mask(struct bnx2x_fastpath *fp)
-{
- /* Set the mask to all 1-s: it's faster to compare to 0 than to 0xf-s */
- memset(fp->sge_mask, 0xff,
- (NUM_RX_SGE >> RX_SGE_MASK_ELEM_SHIFT)*sizeof(u64));
-
- /* Clear the two last indices in the page to 1:
- these are the indices that correspond to the "next" element,
- hence will never be indicated and should be removed from
- the calculations. */
- bnx2x_clear_sge_mask_next_elems(fp);
-}
static inline void bnx2x_free_tpa_pool(struct bnx2x *bp,
struct bnx2x_fastpath *fp, int last)
{
@@ -582,7 +856,7 @@ static inline void bnx2x_free_tpa_pool(struct bnx2x *bp,
}
-static inline void bnx2x_init_tx_ring(struct bnx2x *bp)
+static inline void bnx2x_init_tx_rings(struct bnx2x *bp)
{
int i, j;
@@ -601,7 +875,7 @@ static inline void bnx2x_init_tx_ring(struct bnx2x *bp)
BCM_PAGE_SIZE*(i % NUM_TX_RINGS)));
}
- fp->tx_db.data.header.header = DOORBELL_HDR_DB_TYPE;
+ SET_FLAG(fp->tx_db.data.header.header, DOORBELL_HDR_DB_TYPE, 1);
fp->tx_db.data.zero_fill1 = 0;
fp->tx_db.data.prod = 0;
@@ -609,44 +883,98 @@ static inline void bnx2x_init_tx_ring(struct bnx2x *bp)
fp->tx_pkt_cons = 0;
fp->tx_bd_prod = 0;
fp->tx_bd_cons = 0;
- fp->tx_cons_sb = BNX2X_TX_SB_INDEX;
fp->tx_pkt = 0;
}
}
-static inline int bnx2x_has_rx_work(struct bnx2x_fastpath *fp)
+
+static inline void bnx2x_set_next_page_rx_bd(struct bnx2x_fastpath *fp)
{
- u16 rx_cons_sb;
+ int i;
- /* Tell compiler that status block fields can change */
- barrier();
- rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb);
- if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT)
- rx_cons_sb++;
- return (fp->rx_comp_cons != rx_cons_sb);
+ for (i = 1; i <= NUM_RX_RINGS; i++) {
+ struct eth_rx_bd *rx_bd;
+
+ rx_bd = &fp->rx_desc_ring[RX_DESC_CNT * i - 2];
+ rx_bd->addr_hi =
+ cpu_to_le32(U64_HI(fp->rx_desc_mapping +
+ BCM_PAGE_SIZE*(i % NUM_RX_RINGS)));
+ rx_bd->addr_lo =
+ cpu_to_le32(U64_LO(fp->rx_desc_mapping +
+ BCM_PAGE_SIZE*(i % NUM_RX_RINGS)));
+ }
+}
+
+static inline void bnx2x_set_next_page_sgl(struct bnx2x_fastpath *fp)
+{
+ int i;
+
+ for (i = 1; i <= NUM_RX_SGE_PAGES; i++) {
+ struct eth_rx_sge *sge;
+
+ sge = &fp->rx_sge_ring[RX_SGE_CNT * i - 2];
+ sge->addr_hi =
+ cpu_to_le32(U64_HI(fp->rx_sge_mapping +
+ BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES)));
+
+ sge->addr_lo =
+ cpu_to_le32(U64_LO(fp->rx_sge_mapping +
+ BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES)));
+ }
+}
+
+static inline void bnx2x_set_next_page_rx_cq(struct bnx2x_fastpath *fp)
+{
+ int i;
+ for (i = 1; i <= NUM_RCQ_RINGS; i++) {
+ struct eth_rx_cqe_next_page *nextpg;
+
+ nextpg = (struct eth_rx_cqe_next_page *)
+ &fp->rx_comp_ring[RCQ_DESC_CNT * i - 1];
+ nextpg->addr_hi =
+ cpu_to_le32(U64_HI(fp->rx_comp_mapping +
+ BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
+ nextpg->addr_lo =
+ cpu_to_le32(U64_LO(fp->rx_comp_mapping +
+ BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
+ }
+}
+
+
+
+static inline void __storm_memset_struct(struct bnx2x *bp,
+ u32 addr, size_t size, u32 *data)
+{
+ int i;
+ for (i = 0; i < size/4; i++)
+ REG_WR(bp, addr + (i * 4), data[i]);
+}
+
+static inline void storm_memset_mac_filters(struct bnx2x *bp,
+ struct tstorm_eth_mac_filter_config *mac_filters,
+ u16 abs_fid)
+{
+ size_t size = sizeof(struct tstorm_eth_mac_filter_config);
+
+ u32 addr = BAR_TSTRORM_INTMEM +
+ TSTORM_MAC_FILTER_CONFIG_OFFSET(abs_fid);
+
+ __storm_memset_struct(bp, addr, size, (u32 *)mac_filters);
+}
+
+static inline void storm_memset_cmng(struct bnx2x *bp,
+ struct cmng_struct_per_port *cmng,
+ u8 port)
+{
+ size_t size = sizeof(struct cmng_struct_per_port);
+
+ u32 addr = BAR_XSTRORM_INTMEM +
+ XSTORM_CMNG_PER_PORT_VARS_OFFSET(port);
+
+ __storm_memset_struct(bp, addr, size, (u32 *)cmng);
}
/* HW Lock for shared dual port PHYs */
void bnx2x_acquire_phy_lock(struct bnx2x *bp);
void bnx2x_release_phy_lock(struct bnx2x *bp);
-void bnx2x_link_report(struct bnx2x *bp);
-int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget);
-int bnx2x_tx_int(struct bnx2x_fastpath *fp);
-void bnx2x_init_rx_rings(struct bnx2x *bp);
-netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev);
-
-int bnx2x_change_mac_addr(struct net_device *dev, void *p);
-void bnx2x_tx_timeout(struct net_device *dev);
-void bnx2x_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp);
-void bnx2x_netif_start(struct bnx2x *bp);
-void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw);
-void bnx2x_free_irq(struct bnx2x *bp, bool disable_only);
-int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state);
-int bnx2x_resume(struct pci_dev *pdev);
-void bnx2x_free_skbs(struct bnx2x *bp);
-int bnx2x_change_mtu(struct net_device *dev, int new_mtu);
-int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode);
-int bnx2x_nic_load(struct bnx2x *bp, int load_mode);
-int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state);
-
#endif /* BNX2X_CMN_H */
diff --git a/drivers/net/bnx2x/bnx2x_dump.h b/drivers/net/bnx2x/bnx2x_dump.h
index 3bb9a91bb3f7..dc18c25ca9e5 100644
--- a/drivers/net/bnx2x/bnx2x_dump.h
+++ b/drivers/net/bnx2x/bnx2x_dump.h
@@ -31,14 +31,24 @@ struct dump_sign {
#define RI_E1 0x1
#define RI_E1H 0x2
+#define RI_E2 0x4
#define RI_ONLINE 0x100
-
+#define RI_PATH0_DUMP 0x200
+#define RI_PATH1_DUMP 0x400
#define RI_E1_OFFLINE (RI_E1)
#define RI_E1_ONLINE (RI_E1 | RI_ONLINE)
#define RI_E1H_OFFLINE (RI_E1H)
#define RI_E1H_ONLINE (RI_E1H | RI_ONLINE)
-#define RI_ALL_OFFLINE (RI_E1 | RI_E1H)
-#define RI_ALL_ONLINE (RI_E1 | RI_E1H | RI_ONLINE)
+#define RI_E2_OFFLINE (RI_E2)
+#define RI_E2_ONLINE (RI_E2 | RI_ONLINE)
+#define RI_E1E1H_OFFLINE (RI_E1 | RI_E1H)
+#define RI_E1E1H_ONLINE (RI_E1 | RI_E1H | RI_ONLINE)
+#define RI_E1HE2_OFFLINE (RI_E2 | RI_E1H)
+#define RI_E1HE2_ONLINE (RI_E2 | RI_E1H | RI_ONLINE)
+#define RI_E1E2_OFFLINE (RI_E2 | RI_E1)
+#define RI_E1E2_ONLINE (RI_E2 | RI_E1 | RI_ONLINE)
+#define RI_ALL_OFFLINE (RI_E1 | RI_E1H | RI_E2)
+#define RI_ALL_ONLINE (RI_E1 | RI_E1H | RI_E2 | RI_ONLINE)
#define MAX_TIMER_PENDING 200
#define TIMER_SCAN_DONT_CARE 0xFF
@@ -513,6 +523,12 @@ static const struct wreg_addr wreg_addrs_e1h[WREGS_COUNT_E1H] = {
{ 0x1b0c00, 256, 2, read_reg_e1h_0, RI_E1H_OFFLINE }
};
+#define WREGS_COUNT_E2 1
+static const u32 read_reg_e2_0[] = { 0x1b1040, 0x1b1000 };
+
+static const struct wreg_addr wreg_addrs_e2[WREGS_COUNT_E2] = {
+ { 0x1b0c00, 128, 2, read_reg_e2_0, RI_E2_OFFLINE }
+};
static const struct dump_sign dump_sign_all = { 0x49aa93ee, 0x40835, 0x22 };
@@ -531,4 +547,17 @@ static const u32 timer_scan_regs_e1h[TIMER_REGS_COUNT_E1H] =
{ 0x1640d0, 0x1640d4 };
+#define PAGE_MODE_VALUES_E2 2
+
+#define PAGE_READ_REGS_E2 1
+
+#define PAGE_WRITE_REGS_E2 1
+
+static const u32 page_vals_e2[PAGE_MODE_VALUES_E2] = { 0, 128 };
+
+static const u32 page_write_regs_e2[PAGE_WRITE_REGS_E2] = { 328476 };
+
+static const struct reg_addr page_read_regs_e2[PAGE_READ_REGS_E2] = {
+ { 0x58000, 4608, RI_E2_ONLINE } };
+
#endif /* BNX2X_DUMP_H */
diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c
index 8b75b05e34c5..d02ffbdc9f0e 100644
--- a/drivers/net/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/bnx2x/bnx2x_ethtool.c
@@ -25,70 +25,46 @@
#include "bnx2x_cmn.h"
#include "bnx2x_dump.h"
-
static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct bnx2x *bp = netdev_priv(dev);
-
- cmd->supported = bp->port.supported;
- cmd->advertising = bp->port.advertising;
+ int cfg_idx = bnx2x_get_link_cfg_idx(bp);
+ /* Dual Media boards present all available port types */
+ cmd->supported = bp->port.supported[cfg_idx] |
+ (bp->port.supported[cfg_idx ^ 1] &
+ (SUPPORTED_TP | SUPPORTED_FIBRE));
+ cmd->advertising = bp->port.advertising[cfg_idx];
if ((bp->state == BNX2X_STATE_OPEN) &&
!(bp->flags & MF_FUNC_DIS) &&
(bp->link_vars.link_up)) {
cmd->speed = bp->link_vars.line_speed;
cmd->duplex = bp->link_vars.duplex;
- if (IS_E1HMF(bp)) {
- u16 vn_max_rate;
-
- vn_max_rate =
- ((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >>
- FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
- if (vn_max_rate < cmd->speed)
- cmd->speed = vn_max_rate;
- }
} else {
- cmd->speed = -1;
- cmd->duplex = -1;
- }
-
- if (bp->link_params.switch_cfg == SWITCH_CFG_10G) {
- u32 ext_phy_type =
- XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
-
- switch (ext_phy_type) {
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
- cmd->port = PORT_FIBRE;
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
- cmd->port = PORT_TP;
- break;
+ cmd->speed = bp->link_params.req_line_speed[cfg_idx];
+ cmd->duplex = bp->link_params.req_duplex[cfg_idx];
+ }
+ if (IS_MF(bp)) {
+ u16 vn_max_rate = ((bp->mf_config[BP_VN(bp)] &
+ FUNC_MF_CFG_MAX_BW_MASK) >> FUNC_MF_CFG_MAX_BW_SHIFT) *
+ 100;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
- BNX2X_ERR("XGXS PHY Failure detected 0x%x\n",
- bp->link_params.ext_phy_config);
- break;
+ if (vn_max_rate < cmd->speed)
+ cmd->speed = vn_max_rate;
+ }
- default:
- DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
- bp->link_params.ext_phy_config);
- break;
- }
- } else
+ if (bp->port.supported[cfg_idx] & SUPPORTED_TP)
cmd->port = PORT_TP;
+ else if (bp->port.supported[cfg_idx] & SUPPORTED_FIBRE)
+ cmd->port = PORT_FIBRE;
+ else
+ BNX2X_ERR("XGXS PHY Failure detected\n");
cmd->phy_address = bp->mdio.prtad;
cmd->transceiver = XCVR_INTERNAL;
- if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
+ if (bp->link_params.req_line_speed[cfg_idx] == SPEED_AUTO_NEG)
cmd->autoneg = AUTONEG_ENABLE;
else
cmd->autoneg = AUTONEG_DISABLE;
@@ -110,9 +86,9 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct bnx2x *bp = netdev_priv(dev);
- u32 advertising;
+ u32 advertising, cfg_idx, old_multi_phy_config, new_multi_phy_config;
- if (IS_E1HMF(bp))
+ if (IS_MF(bp))
return 0;
DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n"
@@ -123,26 +99,81 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
+ cfg_idx = bnx2x_get_link_cfg_idx(bp);
+ old_multi_phy_config = bp->link_params.multi_phy_config;
+ switch (cmd->port) {
+ case PORT_TP:
+ if (bp->port.supported[cfg_idx] & SUPPORTED_TP)
+ break; /* no port change */
+
+ if (!(bp->port.supported[0] & SUPPORTED_TP ||
+ bp->port.supported[1] & SUPPORTED_TP)) {
+ DP(NETIF_MSG_LINK, "Unsupported port type\n");
+ return -EINVAL;
+ }
+ bp->link_params.multi_phy_config &=
+ ~PORT_HW_CFG_PHY_SELECTION_MASK;
+ if (bp->link_params.multi_phy_config &
+ PORT_HW_CFG_PHY_SWAPPED_ENABLED)
+ bp->link_params.multi_phy_config |=
+ PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
+ else
+ bp->link_params.multi_phy_config |=
+ PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
+ break;
+ case PORT_FIBRE:
+ if (bp->port.supported[cfg_idx] & SUPPORTED_FIBRE)
+ break; /* no port change */
+
+ if (!(bp->port.supported[0] & SUPPORTED_FIBRE ||
+ bp->port.supported[1] & SUPPORTED_FIBRE)) {
+ DP(NETIF_MSG_LINK, "Unsupported port type\n");
+ return -EINVAL;
+ }
+ bp->link_params.multi_phy_config &=
+ ~PORT_HW_CFG_PHY_SELECTION_MASK;
+ if (bp->link_params.multi_phy_config &
+ PORT_HW_CFG_PHY_SWAPPED_ENABLED)
+ bp->link_params.multi_phy_config |=
+ PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
+ else
+ bp->link_params.multi_phy_config |=
+ PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
+ break;
+ default:
+ DP(NETIF_MSG_LINK, "Unsupported port type\n");
+ return -EINVAL;
+ }
+ /* Save new config in case command complete successuly */
+ new_multi_phy_config = bp->link_params.multi_phy_config;
+ /* Get the new cfg_idx */
+ cfg_idx = bnx2x_get_link_cfg_idx(bp);
+ /* Restore old config in case command failed */
+ bp->link_params.multi_phy_config = old_multi_phy_config;
+ DP(NETIF_MSG_LINK, "cfg_idx = %x\n", cfg_idx);
+
if (cmd->autoneg == AUTONEG_ENABLE) {
- if (!(bp->port.supported & SUPPORTED_Autoneg)) {
+ if (!(bp->port.supported[cfg_idx] & SUPPORTED_Autoneg)) {
DP(NETIF_MSG_LINK, "Autoneg not supported\n");
return -EINVAL;
}
/* advertise the requested speed and duplex if supported */
- cmd->advertising &= bp->port.supported;
+ cmd->advertising &= bp->port.supported[cfg_idx];
- bp->link_params.req_line_speed = SPEED_AUTO_NEG;
- bp->link_params.req_duplex = DUPLEX_FULL;
- bp->port.advertising |= (ADVERTISED_Autoneg |
+ 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 |
cmd->advertising);
} else { /* forced speed */
/* advertise the requested speed and duplex if supported */
- switch (cmd->speed) {
+ u32 speed = cmd->speed;
+ speed |= (cmd->speed_hi << 16);
+ switch (speed) {
case SPEED_10:
if (cmd->duplex == DUPLEX_FULL) {
- if (!(bp->port.supported &
+ if (!(bp->port.supported[cfg_idx] &
SUPPORTED_10baseT_Full)) {
DP(NETIF_MSG_LINK,
"10M full not supported\n");
@@ -152,7 +183,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
advertising = (ADVERTISED_10baseT_Full |
ADVERTISED_TP);
} else {
- if (!(bp->port.supported &
+ if (!(bp->port.supported[cfg_idx] &
SUPPORTED_10baseT_Half)) {
DP(NETIF_MSG_LINK,
"10M half not supported\n");
@@ -166,7 +197,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
case SPEED_100:
if (cmd->duplex == DUPLEX_FULL) {
- if (!(bp->port.supported &
+ if (!(bp->port.supported[cfg_idx] &
SUPPORTED_100baseT_Full)) {
DP(NETIF_MSG_LINK,
"100M full not supported\n");
@@ -176,7 +207,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
advertising = (ADVERTISED_100baseT_Full |
ADVERTISED_TP);
} else {
- if (!(bp->port.supported &
+ if (!(bp->port.supported[cfg_idx] &
SUPPORTED_100baseT_Half)) {
DP(NETIF_MSG_LINK,
"100M half not supported\n");
@@ -194,7 +225,8 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
return -EINVAL;
}
- if (!(bp->port.supported & SUPPORTED_1000baseT_Full)) {
+ if (!(bp->port.supported[cfg_idx] &
+ SUPPORTED_1000baseT_Full)) {
DP(NETIF_MSG_LINK, "1G full not supported\n");
return -EINVAL;
}
@@ -210,7 +242,8 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
return -EINVAL;
}
- if (!(bp->port.supported & SUPPORTED_2500baseX_Full)) {
+ if (!(bp->port.supported[cfg_idx]
+ & SUPPORTED_2500baseX_Full)) {
DP(NETIF_MSG_LINK,
"2.5G full not supported\n");
return -EINVAL;
@@ -226,7 +259,8 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
return -EINVAL;
}
- if (!(bp->port.supported & SUPPORTED_10000baseT_Full)) {
+ if (!(bp->port.supported[cfg_idx]
+ & SUPPORTED_10000baseT_Full)) {
DP(NETIF_MSG_LINK, "10G full not supported\n");
return -EINVAL;
}
@@ -236,20 +270,23 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
break;
default:
- DP(NETIF_MSG_LINK, "Unsupported speed\n");
+ DP(NETIF_MSG_LINK, "Unsupported speed %d\n", speed);
return -EINVAL;
}
- bp->link_params.req_line_speed = cmd->speed;
- bp->link_params.req_duplex = cmd->duplex;
- bp->port.advertising = advertising;
+ bp->link_params.req_line_speed[cfg_idx] = speed;
+ bp->link_params.req_duplex[cfg_idx] = cmd->duplex;
+ bp->port.advertising[cfg_idx] = advertising;
}
DP(NETIF_MSG_LINK, "req_line_speed %d\n"
DP_LEVEL " req_duplex %d advertising 0x%x\n",
- bp->link_params.req_line_speed, bp->link_params.req_duplex,
- bp->port.advertising);
+ bp->link_params.req_line_speed[cfg_idx],
+ bp->link_params.req_duplex[cfg_idx],
+ bp->port.advertising[cfg_idx]);
+ /* Set new config */
+ bp->link_params.multi_phy_config = new_multi_phy_config;
if (netif_running(dev)) {
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
bnx2x_link_set(bp);
@@ -260,6 +297,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
#define IS_E1_ONLINE(info) (((info) & RI_E1_ONLINE) == RI_E1_ONLINE)
#define IS_E1H_ONLINE(info) (((info) & RI_E1H_ONLINE) == RI_E1H_ONLINE)
+#define IS_E2_ONLINE(info) (((info) & RI_E2_ONLINE) == RI_E2_ONLINE)
static int bnx2x_get_regs_len(struct net_device *dev)
{
@@ -277,7 +315,7 @@ static int bnx2x_get_regs_len(struct net_device *dev)
regdump_len += wreg_addrs_e1[i].size *
(1 + wreg_addrs_e1[i].read_regs_count);
- } else { /* E1H */
+ } else if (CHIP_IS_E1H(bp)) {
for (i = 0; i < REGS_COUNT; i++)
if (IS_E1H_ONLINE(reg_addrs[i].info))
regdump_len += reg_addrs[i].size;
@@ -286,6 +324,15 @@ static int bnx2x_get_regs_len(struct net_device *dev)
if (IS_E1H_ONLINE(wreg_addrs_e1h[i].info))
regdump_len += wreg_addrs_e1h[i].size *
(1 + wreg_addrs_e1h[i].read_regs_count);
+ } else if (CHIP_IS_E2(bp)) {
+ for (i = 0; i < REGS_COUNT; i++)
+ if (IS_E2_ONLINE(reg_addrs[i].info))
+ regdump_len += reg_addrs[i].size;
+
+ for (i = 0; i < WREGS_COUNT_E2; i++)
+ if (IS_E2_ONLINE(wreg_addrs_e2[i].info))
+ regdump_len += wreg_addrs_e2[i].size *
+ (1 + wreg_addrs_e2[i].read_regs_count);
}
regdump_len *= 4;
regdump_len += sizeof(struct dump_hdr);
@@ -293,6 +340,23 @@ static int bnx2x_get_regs_len(struct net_device *dev)
return regdump_len;
}
+static inline void bnx2x_read_pages_regs_e2(struct bnx2x *bp, u32 *p)
+{
+ u32 i, j, k, n;
+
+ for (i = 0; i < PAGE_MODE_VALUES_E2; i++) {
+ for (j = 0; j < PAGE_WRITE_REGS_E2; j++) {
+ REG_WR(bp, page_write_regs_e2[j], page_vals_e2[i]);
+ for (k = 0; k < PAGE_READ_REGS_E2; k++)
+ if (IS_E2_ONLINE(page_read_regs_e2[k].info))
+ for (n = 0; n <
+ page_read_regs_e2[k].size; n++)
+ *p++ = REG_RD(bp,
+ page_read_regs_e2[k].addr + n*4);
+ }
+ }
+}
+
static void bnx2x_get_regs(struct net_device *dev,
struct ethtool_regs *regs, void *_p)
{
@@ -312,7 +376,14 @@ static void bnx2x_get_regs(struct net_device *dev,
dump_hdr.tstorm_waitp = REG_RD(bp, TSTORM_WAITP_ADDR);
dump_hdr.ustorm_waitp = REG_RD(bp, USTORM_WAITP_ADDR);
dump_hdr.cstorm_waitp = REG_RD(bp, CSTORM_WAITP_ADDR);
- dump_hdr.info = CHIP_IS_E1(bp) ? RI_E1_ONLINE : RI_E1H_ONLINE;
+
+ if (CHIP_IS_E1(bp))
+ dump_hdr.info = RI_E1_ONLINE;
+ else if (CHIP_IS_E1H(bp))
+ dump_hdr.info = RI_E1H_ONLINE;
+ else if (CHIP_IS_E2(bp))
+ dump_hdr.info = RI_E2_ONLINE |
+ (BP_PATH(bp) ? RI_PATH1_DUMP : RI_PATH0_DUMP);
memcpy(p, &dump_hdr, sizeof(struct dump_hdr));
p += dump_hdr.hdr_size + 1;
@@ -324,16 +395,25 @@ static void bnx2x_get_regs(struct net_device *dev,
*p++ = REG_RD(bp,
reg_addrs[i].addr + j*4);
- } else { /* E1H */
+ } else if (CHIP_IS_E1H(bp)) {
for (i = 0; i < REGS_COUNT; i++)
if (IS_E1H_ONLINE(reg_addrs[i].info))
for (j = 0; j < reg_addrs[i].size; j++)
*p++ = REG_RD(bp,
reg_addrs[i].addr + j*4);
+
+ } else if (CHIP_IS_E2(bp)) {
+ for (i = 0; i < REGS_COUNT; i++)
+ if (IS_E2_ONLINE(reg_addrs[i].info))
+ for (j = 0; j < reg_addrs[i].size; j++)
+ *p++ = REG_RD(bp,
+ reg_addrs[i].addr + j*4);
+
+ bnx2x_read_pages_regs_e2(bp, p);
}
}
-#define PHY_FW_VER_LEN 10
+#define PHY_FW_VER_LEN 20
static void bnx2x_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
@@ -436,7 +516,7 @@ static u32 bnx2x_get_link(struct net_device *dev)
{
struct bnx2x *bp = netdev_priv(dev);
- if (bp->flags & MF_FUNC_DIS)
+ if (bp->flags & MF_FUNC_DIS || (bp->state != BNX2X_STATE_OPEN))
return 0;
return bp->link_vars.link_up;
@@ -811,7 +891,7 @@ static int bnx2x_set_eeprom(struct net_device *dev,
struct bnx2x *bp = netdev_priv(dev);
int port = BP_PORT(bp);
int rc = 0;
-
+ u32 ext_phy_config;
if (!netif_running(dev))
return -EAGAIN;
@@ -827,6 +907,10 @@ static int bnx2x_set_eeprom(struct net_device *dev,
!bp->port.pmf)
return -EINVAL;
+ ext_phy_config =
+ SHMEM_RD(bp,
+ dev_info.port_hw_config[port].external_phy_config);
+
if (eeprom->magic == 0x50485950) {
/* 'PHYP' (0x50485950): prepare phy for FW upgrade */
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
@@ -834,7 +918,7 @@ static int bnx2x_set_eeprom(struct net_device *dev,
bnx2x_acquire_phy_lock(bp);
rc |= bnx2x_link_reset(&bp->link_params,
&bp->link_vars, 0);
- if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+ if (XGXS_EXT_PHY_TYPE(ext_phy_config) ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101)
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
MISC_REGISTERS_GPIO_HIGH, port);
@@ -855,10 +939,8 @@ static int bnx2x_set_eeprom(struct net_device *dev,
}
} else if (eeprom->magic == 0x53985943) {
/* 'PHYC' (0x53985943): PHY FW upgrade completed */
- if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+ if (XGXS_EXT_PHY_TYPE(ext_phy_config) ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) {
- u8 ext_phy_addr =
- XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config);
/* DSP Remove Download Mode */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
@@ -866,7 +948,8 @@ static int bnx2x_set_eeprom(struct net_device *dev,
bnx2x_acquire_phy_lock(bp);
- bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
+ bnx2x_sfx7101_sp_sw_reset(bp,
+ &bp->link_params.phy[EXT_PHY1]);
/* wait 0.5 sec to allow it to run */
msleep(500);
@@ -879,6 +962,7 @@ static int bnx2x_set_eeprom(struct net_device *dev,
return rc;
}
+
static int bnx2x_get_coalesce(struct net_device *dev,
struct ethtool_coalesce *coal)
{
@@ -920,7 +1004,14 @@ static void bnx2x_get_ringparam(struct net_device *dev,
ering->rx_mini_max_pending = 0;
ering->rx_jumbo_max_pending = 0;
- ering->rx_pending = bp->rx_ring_size;
+ 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;
@@ -940,6 +1031,7 @@ static int bnx2x_set_ringparam(struct net_device *dev,
}
if ((ering->rx_pending > MAX_RX_AVAIL) ||
+ (ering->rx_pending < MIN_RX_AVAIL) ||
(ering->tx_pending > MAX_TX_AVAIL) ||
(ering->tx_pending <= MAX_SKB_FRAGS + 4))
return -EINVAL;
@@ -959,10 +1051,9 @@ static void bnx2x_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *epause)
{
struct bnx2x *bp = netdev_priv(dev);
-
- epause->autoneg = (bp->link_params.req_flow_ctrl ==
- BNX2X_FLOW_CTRL_AUTO) &&
- (bp->link_params.req_line_speed == SPEED_AUTO_NEG);
+ int cfg_idx = bnx2x_get_link_cfg_idx(bp);
+ epause->autoneg = (bp->link_params.req_flow_ctrl[cfg_idx] ==
+ BNX2X_FLOW_CTRL_AUTO);
epause->rx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) ==
BNX2X_FLOW_CTRL_RX);
@@ -978,37 +1069,39 @@ static int bnx2x_set_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *epause)
{
struct bnx2x *bp = netdev_priv(dev);
-
- if (IS_E1HMF(bp))
+ u32 cfg_idx = bnx2x_get_link_cfg_idx(bp);
+ if (IS_MF(bp))
return 0;
DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n"
DP_LEVEL " 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 = BNX2X_FLOW_CTRL_AUTO;
+ bp->link_params.req_flow_ctrl[cfg_idx] = BNX2X_FLOW_CTRL_AUTO;
if (epause->rx_pause)
- bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_RX;
+ bp->link_params.req_flow_ctrl[cfg_idx] |= BNX2X_FLOW_CTRL_RX;
if (epause->tx_pause)
- bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_TX;
+ bp->link_params.req_flow_ctrl[cfg_idx] |= BNX2X_FLOW_CTRL_TX;
- if (bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
- bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+ if (bp->link_params.req_flow_ctrl[cfg_idx] == BNX2X_FLOW_CTRL_AUTO)
+ bp->link_params.req_flow_ctrl[cfg_idx] = BNX2X_FLOW_CTRL_NONE;
if (epause->autoneg) {
- if (!(bp->port.supported & SUPPORTED_Autoneg)) {
+ if (!(bp->port.supported[cfg_idx] & SUPPORTED_Autoneg)) {
DP(NETIF_MSG_LINK, "autoneg not supported\n");
return -EINVAL;
}
- if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
- bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
+ if (bp->link_params.req_line_speed[cfg_idx] == SPEED_AUTO_NEG) {
+ bp->link_params.req_flow_ctrl[cfg_idx] =
+ BNX2X_FLOW_CTRL_AUTO;
+ }
}
DP(NETIF_MSG_LINK,
- "req_flow_ctrl 0x%x\n", bp->link_params.req_flow_ctrl);
+ "req_flow_ctrl 0x%x\n", bp->link_params.req_flow_ctrl[cfg_idx]);
if (netif_running(dev)) {
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
@@ -1024,35 +1117,34 @@ static int bnx2x_set_flags(struct net_device *dev, u32 data)
int changed = 0;
int rc = 0;
- if (data & ~(ETH_FLAG_LRO | ETH_FLAG_RXHASH))
- return -EINVAL;
-
if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
printk(KERN_ERR "Handling parity error recovery. Try again later\n");
return -EAGAIN;
}
+ if (!(data & ETH_FLAG_RXVLAN))
+ return -EINVAL;
+
+ if ((data & ETH_FLAG_LRO) && bp->rx_csum && bp->disable_tpa)
+ return -EINVAL;
+
+ rc = ethtool_op_set_flags(dev, data, ETH_FLAG_LRO | ETH_FLAG_RXVLAN |
+ ETH_FLAG_TXVLAN | ETH_FLAG_RXHASH);
+ if (rc)
+ return rc;
+
/* TPA requires Rx CSUM offloading */
if ((data & ETH_FLAG_LRO) && bp->rx_csum) {
- if (!bp->disable_tpa) {
- if (!(dev->features & NETIF_F_LRO)) {
- dev->features |= NETIF_F_LRO;
- bp->flags |= TPA_ENABLE_FLAG;
- changed = 1;
- }
- } else
- rc = -EINVAL;
- } else if (dev->features & NETIF_F_LRO) {
+ if (!(bp->flags & TPA_ENABLE_FLAG)) {
+ bp->flags |= TPA_ENABLE_FLAG;
+ changed = 1;
+ }
+ } else if (bp->flags & TPA_ENABLE_FLAG) {
dev->features &= ~NETIF_F_LRO;
bp->flags &= ~TPA_ENABLE_FLAG;
changed = 1;
}
- if (data & ETH_FLAG_RXHASH)
- dev->features |= NETIF_F_RXHASH;
- else
- dev->features &= ~NETIF_F_RXHASH;
-
if (changed && netif_running(dev)) {
bnx2x_nic_unload(bp, UNLOAD_NORMAL);
rc = bnx2x_nic_load(bp, LOAD_NORMAL);
@@ -1185,6 +1277,9 @@ static int bnx2x_test_registers(struct bnx2x *bp)
for (i = 0; reg_tbl[i].offset0 != 0xffffffff; i++) {
u32 offset, mask, save_val, val;
+ if (CHIP_IS_E2(bp) &&
+ reg_tbl[i].offset0 == HC_REG_AGG_INT_0)
+ continue;
offset = reg_tbl[i].offset0 + port*reg_tbl[i].offset1;
mask = reg_tbl[i].mask;
@@ -1192,6 +1287,7 @@ static int bnx2x_test_registers(struct bnx2x *bp)
save_val = REG_RD(bp, offset);
REG_WR(bp, offset, (wr_val & mask));
+
val = REG_RD(bp, offset);
/* Restore the original register's value */
@@ -1236,20 +1332,33 @@ static int bnx2x_test_memory(struct bnx2x *bp)
u32 offset;
u32 e1_mask;
u32 e1h_mask;
+ u32 e2_mask;
} prty_tbl[] = {
- { "CCM_PRTY_STS", CCM_REG_CCM_PRTY_STS, 0x3ffc0, 0 },
- { "CFC_PRTY_STS", CFC_REG_CFC_PRTY_STS, 0x2, 0x2 },
- { "DMAE_PRTY_STS", DMAE_REG_DMAE_PRTY_STS, 0, 0 },
- { "TCM_PRTY_STS", TCM_REG_TCM_PRTY_STS, 0x3ffc0, 0 },
- { "UCM_PRTY_STS", UCM_REG_UCM_PRTY_STS, 0x3ffc0, 0 },
- { "XCM_PRTY_STS", XCM_REG_XCM_PRTY_STS, 0x3ffc1, 0 },
-
- { NULL, 0xffffffff, 0, 0 }
+ { "CCM_PRTY_STS", CCM_REG_CCM_PRTY_STS, 0x3ffc0, 0, 0 },
+ { "CFC_PRTY_STS", CFC_REG_CFC_PRTY_STS, 0x2, 0x2, 0 },
+ { "DMAE_PRTY_STS", DMAE_REG_DMAE_PRTY_STS, 0, 0, 0 },
+ { "TCM_PRTY_STS", TCM_REG_TCM_PRTY_STS, 0x3ffc0, 0, 0 },
+ { "UCM_PRTY_STS", UCM_REG_UCM_PRTY_STS, 0x3ffc0, 0, 0 },
+ { "XCM_PRTY_STS", XCM_REG_XCM_PRTY_STS, 0x3ffc1, 0, 0 },
+
+ { NULL, 0xffffffff, 0, 0, 0 }
};
if (!netif_running(bp->dev))
return rc;
+ /* pre-Check the parity status */
+ for (i = 0; prty_tbl[i].offset != 0xffffffff; i++) {
+ val = REG_RD(bp, prty_tbl[i].offset);
+ if ((CHIP_IS_E1(bp) && (val & ~(prty_tbl[i].e1_mask))) ||
+ (CHIP_IS_E1H(bp) && (val & ~(prty_tbl[i].e1h_mask))) ||
+ (CHIP_IS_E2(bp) && (val & ~(prty_tbl[i].e2_mask)))) {
+ DP(NETIF_MSG_HW,
+ "%s is 0x%x\n", prty_tbl[i].name, val);
+ goto test_mem_exit;
+ }
+ }
+
/* Go through all the memories */
for (i = 0; mem_tbl[i].offset != 0xffffffff; i++)
for (j = 0; j < mem_tbl[i].size; j++)
@@ -1259,7 +1368,8 @@ static int bnx2x_test_memory(struct bnx2x *bp)
for (i = 0; prty_tbl[i].offset != 0xffffffff; i++) {
val = REG_RD(bp, prty_tbl[i].offset);
if ((CHIP_IS_E1(bp) && (val & ~(prty_tbl[i].e1_mask))) ||
- (CHIP_IS_E1H(bp) && (val & ~(prty_tbl[i].e1h_mask)))) {
+ (CHIP_IS_E1H(bp) && (val & ~(prty_tbl[i].e1h_mask))) ||
+ (CHIP_IS_E2(bp) && (val & ~(prty_tbl[i].e2_mask)))) {
DP(NETIF_MSG_HW,
"%s is 0x%x\n", prty_tbl[i].name, val);
goto test_mem_exit;
@@ -1272,12 +1382,12 @@ test_mem_exit:
return rc;
}
-static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up)
+static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up, u8 is_serdes)
{
- int cnt = 1000;
+ int cnt = 1400;
if (link_up)
- while (bnx2x_link_test(bp) && cnt--)
+ while (bnx2x_link_test(bp, is_serdes) && cnt--)
msleep(10);
}
@@ -1293,7 +1403,8 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
u16 pkt_prod, bd_prod;
struct sw_tx_bd *tx_buf;
struct eth_tx_start_bd *tx_start_bd;
- struct eth_tx_parse_bd *pbd = NULL;
+ struct eth_tx_parse_bd_e1x *pbd_e1x = NULL;
+ struct eth_tx_parse_bd_e2 *pbd_e2 = NULL;
dma_addr_t mapping;
union eth_rx_cqe *cqe;
u8 cqe_fp_flags;
@@ -1304,7 +1415,7 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
/* check the loopback mode */
switch (loopback_mode) {
case BNX2X_PHY_LOOPBACK:
- if (bp->link_params.loopback_mode != LOOPBACK_XGXS_10)
+ if (bp->link_params.loopback_mode != LOOPBACK_XGXS)
return -EINVAL;
break;
case BNX2X_MAC_LOOPBACK:
@@ -1349,16 +1460,23 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
tx_start_bd->nbd = cpu_to_le16(2); /* start + pbd */
tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb));
- tx_start_bd->vlan = cpu_to_le16(pkt_prod);
+ tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
- tx_start_bd->general_data = ((UNICAST_ADDRESS <<
- ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT) | 1);
+ SET_FLAG(tx_start_bd->general_data,
+ ETH_TX_START_BD_ETH_ADDR_TYPE,
+ UNICAST_ADDRESS);
+ SET_FLAG(tx_start_bd->general_data,
+ ETH_TX_START_BD_HDR_NBDS,
+ 1);
/* turn on parsing and get a BD */
bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
- pbd = &fp_tx->tx_desc_ring[bd_prod].parse_bd;
- memset(pbd, 0, sizeof(struct eth_tx_parse_bd));
+ pbd_e1x = &fp_tx->tx_desc_ring[bd_prod].parse_bd_e1x;
+ pbd_e2 = &fp_tx->tx_desc_ring[bd_prod].parse_bd_e2;
+
+ memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2));
+ memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x));
wmb();
@@ -1377,6 +1495,13 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
if (tx_idx != tx_start_idx + num_pkts)
goto test_loopback_exit;
+ /* Unlike HC IGU won't generate an interrupt for status block
+ * updates that have been performed while interrupts were
+ * disabled.
+ */
+ if (bp->common.int_block == INT_BLOCK_IGU)
+ bnx2x_tx_int(fp_tx);
+
rx_idx = le16_to_cpu(*fp_rx->rx_cons_sb);
if (rx_idx != rx_start_idx + num_pkts)
goto test_loopback_exit;
@@ -1519,8 +1644,7 @@ static int bnx2x_test_intr(struct bnx2x *bp)
config->hdr.length = 0;
if (CHIP_IS_E1(bp))
- /* use last unicast entries */
- config->hdr.offset = (BP_PORT(bp) ? 63 : 31);
+ config->hdr.offset = (BP_PORT(bp) ? 32 : 0);
else
config->hdr.offset = BP_FUNC(bp);
config->hdr.client_id = bp->fp->cl_id;
@@ -1528,9 +1652,9 @@ static int bnx2x_test_intr(struct bnx2x *bp)
bp->set_mac_pending++;
smp_wmb();
- rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
+ rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_MAC, 0,
U64_HI(bnx2x_sp_mapping(bp, mac_config)),
- U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
+ U64_LO(bnx2x_sp_mapping(bp, mac_config)), 1);
if (rc == 0) {
for (i = 0; i < 10; i++) {
if (!bp->set_mac_pending)
@@ -1549,7 +1673,7 @@ static void bnx2x_self_test(struct net_device *dev,
struct ethtool_test *etest, u64 *buf)
{
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");
etest->flags |= ETH_TEST_FL_FAILED;
@@ -1562,8 +1686,9 @@ static void bnx2x_self_test(struct net_device *dev,
return;
/* offline tests are not supported in MF mode */
- if (IS_E1HMF(bp))
+ if (IS_MF(bp))
etest->flags &= ~ETH_TEST_FL_OFFLINE;
+ is_serdes = (bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) > 0;
if (etest->flags & ETH_TEST_FL_OFFLINE) {
int port = BP_PORT(bp);
@@ -1575,11 +1700,12 @@ static void bnx2x_self_test(struct net_device *dev,
/* disable input for TX port IF */
REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0);
- link_up = (bnx2x_link_test(bp) == 0);
+ link_up = bp->link_vars.link_up;
+
bnx2x_nic_unload(bp, UNLOAD_NORMAL);
bnx2x_nic_load(bp, LOAD_DIAG);
/* wait until link state is restored */
- bnx2x_wait_for_link(bp, link_up);
+ bnx2x_wait_for_link(bp, link_up, is_serdes);
if (bnx2x_test_registers(bp) != 0) {
buf[0] = 1;
@@ -1589,6 +1715,7 @@ static void bnx2x_self_test(struct net_device *dev,
buf[1] = 1;
etest->flags |= ETH_TEST_FL_FAILED;
}
+
buf[2] = bnx2x_test_loopback(bp, link_up);
if (buf[2] != 0)
etest->flags |= ETH_TEST_FL_FAILED;
@@ -1600,7 +1727,7 @@ static void bnx2x_self_test(struct net_device *dev,
bnx2x_nic_load(bp, LOAD_NORMAL);
/* wait until link state is restored */
- bnx2x_wait_for_link(bp, link_up);
+ bnx2x_wait_for_link(bp, link_up, is_serdes);
}
if (bnx2x_test_nvram(bp) != 0) {
buf[3] = 1;
@@ -1611,7 +1738,7 @@ static void bnx2x_self_test(struct net_device *dev,
etest->flags |= ETH_TEST_FL_FAILED;
}
if (bp->port.pmf)
- if (bnx2x_link_test(bp) != 0) {
+ if (bnx2x_link_test(bp, is_serdes) != 0) {
buf[5] = 1;
etest->flags |= ETH_TEST_FL_FAILED;
}
@@ -1752,8 +1879,8 @@ static const struct {
#define IS_PORT_STAT(i) \
((bnx2x_stats_arr[i].flags & STATS_FLAGS_BOTH) == STATS_FLAGS_PORT)
#define IS_FUNC_STAT(i) (bnx2x_stats_arr[i].flags & STATS_FLAGS_FUNC)
-#define IS_E1HMF_MODE_STAT(bp) \
- (IS_E1HMF(bp) && !(bp->msg_enable & BNX2X_MSG_STATS))
+#define IS_MF_MODE_STAT(bp) \
+ (IS_MF(bp) && !(bp->msg_enable & BNX2X_MSG_STATS))
static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
{
@@ -1764,10 +1891,10 @@ static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
case ETH_SS_STATS:
if (is_multi(bp)) {
num_stats = BNX2X_NUM_Q_STATS * bp->num_queues;
- if (!IS_E1HMF_MODE_STAT(bp))
+ if (!IS_MF_MODE_STAT(bp))
num_stats += BNX2X_NUM_STATS;
} else {
- if (IS_E1HMF_MODE_STAT(bp)) {
+ if (IS_MF_MODE_STAT(bp)) {
num_stats = 0;
for (i = 0; i < BNX2X_NUM_STATS; i++)
if (IS_FUNC_STAT(i))
@@ -1800,14 +1927,14 @@ static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
bnx2x_q_stats_arr[j].string, i);
k += BNX2X_NUM_Q_STATS;
}
- if (IS_E1HMF_MODE_STAT(bp))
+ if (IS_MF_MODE_STAT(bp))
break;
for (j = 0; j < BNX2X_NUM_STATS; j++)
strcpy(buf + (k + j)*ETH_GSTRING_LEN,
bnx2x_stats_arr[j].string);
} else {
for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
- if (IS_E1HMF_MODE_STAT(bp) && IS_PORT_STAT(i))
+ if (IS_MF_MODE_STAT(bp) && IS_PORT_STAT(i))
continue;
strcpy(buf + j*ETH_GSTRING_LEN,
bnx2x_stats_arr[i].string);
@@ -1851,7 +1978,7 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev,
}
k += BNX2X_NUM_Q_STATS;
}
- if (IS_E1HMF_MODE_STAT(bp))
+ if (IS_MF_MODE_STAT(bp))
return;
hw_stats = (u32 *)&bp->eth_stats;
for (j = 0; j < BNX2X_NUM_STATS; j++) {
@@ -1872,7 +1999,7 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev,
} else {
hw_stats = (u32 *)&bp->eth_stats;
for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
- if (IS_E1HMF_MODE_STAT(bp) && IS_PORT_STAT(i))
+ if (IS_MF_MODE_STAT(bp) && IS_PORT_STAT(i))
continue;
if (bnx2x_stats_arr[i].size == 0) {
/* skip this counter */
@@ -1910,10 +2037,11 @@ static int bnx2x_phys_id(struct net_device *dev, u32 data)
for (i = 0; i < (data * 2); i++) {
if ((i % 2) == 0)
- bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
- SPEED_1000);
+ bnx2x_set_led(&bp->link_params, &bp->link_vars,
+ LED_MODE_OPER, SPEED_1000);
else
- bnx2x_set_led(&bp->link_params, LED_MODE_OFF, 0);
+ bnx2x_set_led(&bp->link_params, &bp->link_vars,
+ LED_MODE_OFF, 0);
msleep_interruptible(500);
if (signal_pending(current))
@@ -1921,7 +2049,7 @@ static int bnx2x_phys_id(struct net_device *dev, u32 data)
}
if (bp->link_vars.link_up)
- bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
+ bnx2x_set_led(&bp->link_params, &bp->link_vars, LED_MODE_OPER,
bp->link_vars.line_speed);
return 0;
diff --git a/drivers/net/bnx2x/bnx2x_fw_defs.h b/drivers/net/bnx2x/bnx2x_fw_defs.h
index 08d71bf438d6..f4e5b1ce8149 100644
--- a/drivers/net/bnx2x/bnx2x_fw_defs.h
+++ b/drivers/net/bnx2x/bnx2x_fw_defs.h
@@ -7,369 +7,272 @@
* the Free Software Foundation.
*/
-
-#define CSTORM_ASSERT_LIST_INDEX_OFFSET \
- (IS_E1H_OFFSET ? 0x7000 : 0x1000)
-#define CSTORM_ASSERT_LIST_OFFSET(idx) \
- (IS_E1H_OFFSET ? (0x7020 + (idx * 0x10)) : (0x1020 + (idx * 0x10)))
-#define CSTORM_DEF_SB_HC_DISABLE_C_OFFSET(function, index) \
- (IS_E1H_OFFSET ? (0x8622 + ((function>>1) * 0x40) + \
- ((function&1) * 0x100) + (index * 0x4)) : (0x3562 + (function * \
- 0x40) + (index * 0x4)))
-#define CSTORM_DEF_SB_HC_DISABLE_U_OFFSET(function, index) \
- (IS_E1H_OFFSET ? (0x8822 + ((function>>1) * 0x80) + \
- ((function&1) * 0x200) + (index * 0x4)) : (0x35e2 + (function * \
- 0x80) + (index * 0x4)))
-#define CSTORM_DEF_SB_HOST_SB_ADDR_C_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8600 + ((function>>1) * 0x40) + \
- ((function&1) * 0x100)) : (0x3540 + (function * 0x40)))
-#define CSTORM_DEF_SB_HOST_SB_ADDR_U_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8800 + ((function>>1) * 0x80) + \
- ((function&1) * 0x200)) : (0x35c0 + (function * 0x80)))
-#define CSTORM_DEF_SB_HOST_STATUS_BLOCK_C_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8608 + ((function>>1) * 0x40) + \
- ((function&1) * 0x100)) : (0x3548 + (function * 0x40)))
-#define CSTORM_DEF_SB_HOST_STATUS_BLOCK_U_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8808 + ((function>>1) * 0x80) + \
- ((function&1) * 0x200)) : (0x35c8 + (function * 0x80)))
-#define CSTORM_FUNCTION_MODE_OFFSET \
- (IS_E1H_OFFSET ? 0x11e8 : 0xffffffff)
-#define CSTORM_HC_BTR_C_OFFSET(port) \
- (IS_E1H_OFFSET ? (0x8c04 + (port * 0xf0)) : (0x36c4 + (port * 0xc0)))
-#define CSTORM_HC_BTR_U_OFFSET(port) \
- (IS_E1H_OFFSET ? (0x8de4 + (port * 0xf0)) : (0x3844 + (port * 0xc0)))
-#define CSTORM_ISCSI_CQ_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x6680 + (function * 0x8)) : (0x25a0 + \
- (function * 0x8)))
-#define CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x66c0 + (function * 0x8)) : (0x25b0 + \
- (function * 0x8)))
-#define CSTORM_ISCSI_EQ_CONS_OFFSET(function, eqIdx) \
- (IS_E1H_OFFSET ? (0x6040 + (function * 0xc0) + (eqIdx * 0x18)) : \
- (0x2410 + (function * 0xc0) + (eqIdx * 0x18)))
-#define CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(function, eqIdx) \
- (IS_E1H_OFFSET ? (0x6044 + (function * 0xc0) + (eqIdx * 0x18)) : \
- (0x2414 + (function * 0xc0) + (eqIdx * 0x18)))
-#define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(function, eqIdx) \
- (IS_E1H_OFFSET ? (0x604c + (function * 0xc0) + (eqIdx * 0x18)) : \
- (0x241c + (function * 0xc0) + (eqIdx * 0x18)))
-#define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(function, eqIdx) \
- (IS_E1H_OFFSET ? (0x6057 + (function * 0xc0) + (eqIdx * 0x18)) : \
- (0x2427 + (function * 0xc0) + (eqIdx * 0x18)))
-#define CSTORM_ISCSI_EQ_PROD_OFFSET(function, eqIdx) \
- (IS_E1H_OFFSET ? (0x6042 + (function * 0xc0) + (eqIdx * 0x18)) : \
- (0x2412 + (function * 0xc0) + (eqIdx * 0x18)))
-#define CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(function, eqIdx) \
- (IS_E1H_OFFSET ? (0x6056 + (function * 0xc0) + (eqIdx * 0x18)) : \
- (0x2426 + (function * 0xc0) + (eqIdx * 0x18)))
-#define CSTORM_ISCSI_EQ_SB_NUM_OFFSET(function, eqIdx) \
- (IS_E1H_OFFSET ? (0x6054 + (function * 0xc0) + (eqIdx * 0x18)) : \
- (0x2424 + (function * 0xc0) + (eqIdx * 0x18)))
-#define CSTORM_ISCSI_HQ_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x6640 + (function * 0x8)) : (0x2590 + \
- (function * 0x8)))
-#define CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x6004 + (function * 0x8)) : (0x2404 + \
- (function * 0x8)))
-#define CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x6002 + (function * 0x8)) : (0x2402 + \
- (function * 0x8)))
-#define CSTORM_ISCSI_PAGE_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x6000 + (function * 0x8)) : (0x2400 + \
- (function * 0x8)))
-#define CSTORM_SB_HC_DISABLE_C_OFFSET(port, cpu_id, index) \
- (IS_E1H_OFFSET ? (0x811a + (port * 0x280) + (cpu_id * 0x28) + \
- (index * 0x4)) : (0x305a + (port * 0x280) + (cpu_id * 0x28) + \
- (index * 0x4)))
-#define CSTORM_SB_HC_DISABLE_U_OFFSET(port, cpu_id, index) \
- (IS_E1H_OFFSET ? (0xb01a + (port * 0x800) + (cpu_id * 0x80) + \
- (index * 0x4)) : (0x401a + (port * 0x800) + (cpu_id * 0x80) + \
- (index * 0x4)))
-#define CSTORM_SB_HC_TIMEOUT_C_OFFSET(port, cpu_id, index) \
- (IS_E1H_OFFSET ? (0x8118 + (port * 0x280) + (cpu_id * 0x28) + \
- (index * 0x4)) : (0x3058 + (port * 0x280) + (cpu_id * 0x28) + \
- (index * 0x4)))
-#define CSTORM_SB_HC_TIMEOUT_U_OFFSET(port, cpu_id, index) \
- (IS_E1H_OFFSET ? (0xb018 + (port * 0x800) + (cpu_id * 0x80) + \
- (index * 0x4)) : (0x4018 + (port * 0x800) + (cpu_id * 0x80) + \
- (index * 0x4)))
-#define CSTORM_SB_HOST_SB_ADDR_C_OFFSET(port, cpu_id) \
- (IS_E1H_OFFSET ? (0x8100 + (port * 0x280) + (cpu_id * 0x28)) : \
- (0x3040 + (port * 0x280) + (cpu_id * 0x28)))
-#define CSTORM_SB_HOST_SB_ADDR_U_OFFSET(port, cpu_id) \
- (IS_E1H_OFFSET ? (0xb000 + (port * 0x800) + (cpu_id * 0x80)) : \
- (0x4000 + (port * 0x800) + (cpu_id * 0x80)))
-#define CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, cpu_id) \
- (IS_E1H_OFFSET ? (0x8108 + (port * 0x280) + (cpu_id * 0x28)) : \
- (0x3048 + (port * 0x280) + (cpu_id * 0x28)))
-#define CSTORM_SB_HOST_STATUS_BLOCK_U_OFFSET(port, cpu_id) \
- (IS_E1H_OFFSET ? (0xb008 + (port * 0x800) + (cpu_id * 0x80)) : \
- (0x4008 + (port * 0x800) + (cpu_id * 0x80)))
-#define CSTORM_SB_STATUS_BLOCK_C_SIZE 0x10
-#define CSTORM_SB_STATUS_BLOCK_U_SIZE 0x60
-#define CSTORM_STATS_FLAGS_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x1108 + (function * 0x8)) : (0x5108 + \
- (function * 0x8)))
-#define TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x3200 + (function * 0x20)) : 0xffffffff)
-#define TSTORM_ASSERT_LIST_INDEX_OFFSET \
- (IS_E1H_OFFSET ? 0xa000 : 0x1000)
-#define TSTORM_ASSERT_LIST_OFFSET(idx) \
- (IS_E1H_OFFSET ? (0xa020 + (idx * 0x10)) : (0x1020 + (idx * 0x10)))
-#define TSTORM_CLIENT_CONFIG_OFFSET(port, client_id) \
- (IS_E1H_OFFSET ? (0x33a0 + (port * 0x1a0) + (client_id * 0x10)) \
- : (0x9c0 + (port * 0x120) + (client_id * 0x10)))
-#define TSTORM_COMMON_SAFC_WORKAROUND_ENABLE_OFFSET \
- (IS_E1H_OFFSET ? 0x1ed8 : 0xffffffff)
+#ifndef BNX2X_FW_DEFS_H
+#define BNX2X_FW_DEFS_H
+
+#define CSTORM_ASSERT_LIST_INDEX_OFFSET (IRO[142].base)
+#define CSTORM_ASSERT_LIST_OFFSET(assertListEntry) \
+ (IRO[141].base + ((assertListEntry) * IRO[141].m1))
+#define CSTORM_ETH_STATS_QUERY_ADDR_OFFSET(pfId) \
+ (IRO[144].base + ((pfId) * IRO[144].m1))
+#define CSTORM_EVENT_RING_DATA_OFFSET(pfId) \
+ (IRO[149].base + (((pfId)>>1) * IRO[149].m1) + (((pfId)&1) * \
+ IRO[149].m2))
+#define CSTORM_EVENT_RING_PROD_OFFSET(pfId) \
+ (IRO[150].base + (((pfId)>>1) * IRO[150].m1) + (((pfId)&1) * \
+ IRO[150].m2))
+#define CSTORM_FINAL_CLEANUP_COMPLETE_OFFSET(funcId) \
+ (IRO[156].base + ((funcId) * IRO[156].m1))
+#define CSTORM_FUNC_EN_OFFSET(funcId) \
+ (IRO[146].base + ((funcId) * IRO[146].m1))
+#define CSTORM_FUNCTION_MODE_OFFSET (IRO[153].base)
+#define CSTORM_IGU_MODE_OFFSET (IRO[154].base)
+#define CSTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \
+ (IRO[311].base + ((pfId) * IRO[311].m1))
+#define CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
+ (IRO[312].base + ((pfId) * IRO[312].m1))
+ #define CSTORM_ISCSI_EQ_CONS_OFFSET(pfId, iscsiEqId) \
+ (IRO[304].base + ((pfId) * IRO[304].m1) + ((iscsiEqId) * \
+ IRO[304].m2))
+ #define CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(pfId, iscsiEqId) \
+ (IRO[306].base + ((pfId) * IRO[306].m1) + ((iscsiEqId) * \
+ IRO[306].m2))
+ #define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(pfId, iscsiEqId) \
+ (IRO[305].base + ((pfId) * IRO[305].m1) + ((iscsiEqId) * \
+ IRO[305].m2))
+ #define \
+ CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(pfId, iscsiEqId) \
+ (IRO[307].base + ((pfId) * IRO[307].m1) + ((iscsiEqId) * \
+ IRO[307].m2))
+ #define CSTORM_ISCSI_EQ_PROD_OFFSET(pfId, iscsiEqId) \
+ (IRO[303].base + ((pfId) * IRO[303].m1) + ((iscsiEqId) * \
+ IRO[303].m2))
+ #define CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(pfId, iscsiEqId) \
+ (IRO[309].base + ((pfId) * IRO[309].m1) + ((iscsiEqId) * \
+ IRO[309].m2))
+ #define CSTORM_ISCSI_EQ_SB_NUM_OFFSET(pfId, iscsiEqId) \
+ (IRO[308].base + ((pfId) * IRO[308].m1) + ((iscsiEqId) * \
+ IRO[308].m2))
+#define CSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \
+ (IRO[310].base + ((pfId) * IRO[310].m1))
+#define CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
+ (IRO[302].base + ((pfId) * IRO[302].m1))
+#define CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
+ (IRO[301].base + ((pfId) * IRO[301].m1))
+#define CSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
+ (IRO[300].base + ((pfId) * IRO[300].m1))
+#define CSTORM_PATH_ID_OFFSET (IRO[159].base)
+#define CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(pfId) \
+ (IRO[137].base + ((pfId) * IRO[137].m1))
+#define CSTORM_SP_STATUS_BLOCK_OFFSET(pfId) \
+ (IRO[136].base + ((pfId) * IRO[136].m1))
+#define CSTORM_SP_STATUS_BLOCK_SIZE (IRO[136].size)
+#define CSTORM_SP_SYNC_BLOCK_OFFSET(pfId) \
+ (IRO[138].base + ((pfId) * IRO[138].m1))
+#define CSTORM_SP_SYNC_BLOCK_SIZE (IRO[138].size)
+#define CSTORM_STATS_FLAGS_OFFSET(pfId) \
+ (IRO[143].base + ((pfId) * IRO[143].m1))
+#define CSTORM_STATUS_BLOCK_DATA_OFFSET(sbId) \
+ (IRO[129].base + ((sbId) * IRO[129].m1))
+#define CSTORM_STATUS_BLOCK_OFFSET(sbId) \
+ (IRO[128].base + ((sbId) * IRO[128].m1))
+#define CSTORM_STATUS_BLOCK_SIZE (IRO[128].size)
+#define CSTORM_SYNC_BLOCK_OFFSET(sbId) \
+ (IRO[132].base + ((sbId) * IRO[132].m1))
+#define CSTORM_SYNC_BLOCK_SIZE (IRO[132].size)
+#define CSTORM_VF_PF_CHANNEL_STATE_OFFSET(vfId) \
+ (IRO[151].base + ((vfId) * IRO[151].m1))
+#define CSTORM_VF_PF_CHANNEL_VALID_OFFSET(vfId) \
+ (IRO[152].base + ((vfId) * IRO[152].m1))
+#define CSTORM_VF_TO_PF_OFFSET(funcId) \
+ (IRO[147].base + ((funcId) * IRO[147].m1))
+#define TSTORM_ACCEPT_CLASSIFY_FAILED_OFFSET (IRO[199].base)
+#define TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(pfId) \
+ (IRO[198].base + ((pfId) * IRO[198].m1))
+#define TSTORM_ASSERT_LIST_INDEX_OFFSET (IRO[99].base)
+#define TSTORM_ASSERT_LIST_OFFSET(assertListEntry) \
+ (IRO[98].base + ((assertListEntry) * IRO[98].m1))
+ #define TSTORM_CLIENT_CONFIG_OFFSET(portId, clientId) \
+ (IRO[197].base + ((portId) * IRO[197].m1) + ((clientId) * \
+ IRO[197].m2))
+#define TSTORM_COMMON_SAFC_WORKAROUND_ENABLE_OFFSET (IRO[104].base)
#define TSTORM_COMMON_SAFC_WORKAROUND_TIMEOUT_10USEC_OFFSET \
- (IS_E1H_OFFSET ? 0x1eda : 0xffffffff)
-#define TSTORM_DEF_SB_HC_DISABLE_OFFSET(function, index) \
- (IS_E1H_OFFSET ? (0xb01a + ((function>>1) * 0x28) + \
- ((function&1) * 0xa0) + (index * 0x4)) : (0x141a + (function * \
- 0x28) + (index * 0x4)))
-#define TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(function) \
- (IS_E1H_OFFSET ? (0xb000 + ((function>>1) * 0x28) + \
- ((function&1) * 0xa0)) : (0x1400 + (function * 0x28)))
-#define TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(function) \
- (IS_E1H_OFFSET ? (0xb008 + ((function>>1) * 0x28) + \
- ((function&1) * 0xa0)) : (0x1408 + (function * 0x28)))
-#define TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x2940 + (function * 0x8)) : (0x4928 + \
- (function * 0x8)))
-#define TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x3000 + (function * 0x40)) : (0x1500 + \
- (function * 0x40)))
-#define TSTORM_FUNCTION_MODE_OFFSET \
- (IS_E1H_OFFSET ? 0x1ed0 : 0xffffffff)
-#define TSTORM_HC_BTR_OFFSET(port) \
- (IS_E1H_OFFSET ? (0xb144 + (port * 0x30)) : (0x1454 + (port * 0x18)))
-#define TSTORM_INDIRECTION_TABLE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x12c8 + (function * 0x80)) : (0x22c8 + \
- (function * 0x80)))
-#define TSTORM_INDIRECTION_TABLE_SIZE 0x80
-#define TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(function, pblEntry) \
- (IS_E1H_OFFSET ? (0x60c0 + (function * 0x40) + (pblEntry * 0x8)) \
- : (0x4c30 + (function * 0x40) + (pblEntry * 0x8)))
-#define TSTORM_ISCSI_ERROR_BITMAP_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x6340 + (function * 0x8)) : (0x4cd0 + \
- (function * 0x8)))
-#define TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x6004 + (function * 0x8)) : (0x4c04 + \
- (function * 0x8)))
-#define TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x6002 + (function * 0x8)) : (0x4c02 + \
- (function * 0x8)))
-#define TSTORM_ISCSI_PAGE_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x6000 + (function * 0x8)) : (0x4c00 + \
- (function * 0x8)))
-#define TSTORM_ISCSI_RQ_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x6080 + (function * 0x8)) : (0x4c20 + \
- (function * 0x8)))
-#define TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x6040 + (function * 0x8)) : (0x4c10 + \
- (function * 0x8)))
-#define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x6042 + (function * 0x8)) : (0x4c12 + \
- (function * 0x8)))
-#define TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x6044 + (function * 0x8)) : (0x4c14 + \
- (function * 0x8)))
-#define TSTORM_MAC_FILTER_CONFIG_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x3008 + (function * 0x40)) : (0x1508 + \
- (function * 0x40)))
-#define TSTORM_PER_COUNTER_ID_STATS_OFFSET(port, stats_counter_id) \
- (IS_E1H_OFFSET ? (0x2010 + (port * 0x490) + (stats_counter_id * \
- 0x40)) : (0x4010 + (port * 0x490) + (stats_counter_id * 0x40)))
-#define TSTORM_STATS_FLAGS_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x29c0 + (function * 0x8)) : (0x4948 + \
- (function * 0x8)))
-#define TSTORM_TCP_MAX_CWND_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x4004 + (function * 0x8)) : (0x1fb4 + \
- (function * 0x8)))
-#define USTORM_AGG_DATA_OFFSET (IS_E1H_OFFSET ? 0xa000 : 0x3000)
-#define USTORM_AGG_DATA_SIZE (IS_E1H_OFFSET ? 0x2000 : 0x1000)
-#define USTORM_ASSERT_LIST_INDEX_OFFSET \
- (IS_E1H_OFFSET ? 0x8000 : 0x1000)
-#define USTORM_ASSERT_LIST_OFFSET(idx) \
- (IS_E1H_OFFSET ? (0x8020 + (idx * 0x10)) : (0x1020 + (idx * 0x10)))
-#define USTORM_CQE_PAGE_BASE_OFFSET(port, clientId) \
- (IS_E1H_OFFSET ? (0x1010 + (port * 0x680) + (clientId * 0x40)) : \
- (0x4010 + (port * 0x360) + (clientId * 0x30)))
-#define USTORM_CQE_PAGE_NEXT_OFFSET(port, clientId) \
- (IS_E1H_OFFSET ? (0x1028 + (port * 0x680) + (clientId * 0x40)) : \
- (0x4028 + (port * 0x360) + (clientId * 0x30)))
-#define USTORM_ETH_PAUSE_ENABLED_OFFSET(port) \
- (IS_E1H_OFFSET ? (0x2ad4 + (port * 0x8)) : 0xffffffff)
-#define USTORM_ETH_RING_PAUSE_DATA_OFFSET(port, clientId) \
- (IS_E1H_OFFSET ? (0x1030 + (port * 0x680) + (clientId * 0x40)) : \
- 0xffffffff)
-#define USTORM_ETH_STATS_QUERY_ADDR_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x2a50 + (function * 0x8)) : (0x1dd0 + \
- (function * 0x8)))
-#define USTORM_FUNCTION_MODE_OFFSET \
- (IS_E1H_OFFSET ? 0x2448 : 0xffffffff)
-#define USTORM_ISCSI_CQ_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x7044 + (function * 0x8)) : (0x2414 + \
- (function * 0x8)))
-#define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x7046 + (function * 0x8)) : (0x2416 + \
- (function * 0x8)))
-#define USTORM_ISCSI_ERROR_BITMAP_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x7688 + (function * 0x8)) : (0x29c8 + \
- (function * 0x8)))
-#define USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x7648 + (function * 0x8)) : (0x29b8 + \
- (function * 0x8)))
-#define USTORM_ISCSI_NUM_OF_TASKS_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x7004 + (function * 0x8)) : (0x2404 + \
- (function * 0x8)))
-#define USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x7002 + (function * 0x8)) : (0x2402 + \
- (function * 0x8)))
-#define USTORM_ISCSI_PAGE_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x7000 + (function * 0x8)) : (0x2400 + \
- (function * 0x8)))
-#define USTORM_ISCSI_R2TQ_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x7040 + (function * 0x8)) : (0x2410 + \
- (function * 0x8)))
-#define USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x7080 + (function * 0x8)) : (0x2420 + \
- (function * 0x8)))
-#define USTORM_ISCSI_RQ_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x7084 + (function * 0x8)) : (0x2424 + \
- (function * 0x8)))
-#define USTORM_MAX_AGG_SIZE_OFFSET(port, clientId) \
- (IS_E1H_OFFSET ? (0x1018 + (port * 0x680) + (clientId * 0x40)) : \
- (0x4018 + (port * 0x360) + (clientId * 0x30)))
-#define USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x2408 + (function * 0x8)) : (0x1da8 + \
- (function * 0x8)))
-#define USTORM_PER_COUNTER_ID_STATS_OFFSET(port, stats_counter_id) \
- (IS_E1H_OFFSET ? (0x2450 + (port * 0x2d0) + (stats_counter_id * \
- 0x28)) : (0x1500 + (port * 0x2d0) + (stats_counter_id * 0x28)))
-#define USTORM_RX_PRODS_OFFSET(port, client_id) \
- (IS_E1H_OFFSET ? (0x1000 + (port * 0x680) + (client_id * 0x40)) \
- : (0x4000 + (port * 0x360) + (client_id * 0x30)))
-#define USTORM_STATS_FLAGS_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x29f0 + (function * 0x8)) : (0x1db8 + \
- (function * 0x8)))
-#define USTORM_TPA_BTR_OFFSET (IS_E1H_OFFSET ? 0x3da5 : 0x5095)
-#define USTORM_TPA_BTR_SIZE 0x1
-#define XSTORM_ASSERT_LIST_INDEX_OFFSET \
- (IS_E1H_OFFSET ? 0x9000 : 0x1000)
-#define XSTORM_ASSERT_LIST_OFFSET(idx) \
- (IS_E1H_OFFSET ? (0x9020 + (idx * 0x10)) : (0x1020 + (idx * 0x10)))
-#define XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) \
- (IS_E1H_OFFSET ? (0x24a8 + (port * 0x50)) : (0x3a80 + (port * 0x50)))
-#define XSTORM_DEF_SB_HC_DISABLE_OFFSET(function, index) \
- (IS_E1H_OFFSET ? (0xa01a + ((function>>1) * 0x28) + \
- ((function&1) * 0xa0) + (index * 0x4)) : (0x141a + (function * \
- 0x28) + (index * 0x4)))
-#define XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(function) \
- (IS_E1H_OFFSET ? (0xa000 + ((function>>1) * 0x28) + \
- ((function&1) * 0xa0)) : (0x1400 + (function * 0x28)))
-#define XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(function) \
- (IS_E1H_OFFSET ? (0xa008 + ((function>>1) * 0x28) + \
- ((function&1) * 0xa0)) : (0x1408 + (function * 0x28)))
-#define XSTORM_E1HOV_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x2c10 + (function * 0x8)) : 0xffffffff)
-#define XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x2418 + (function * 0x8)) : (0x3a50 + \
- (function * 0x8)))
-#define XSTORM_FAIRNESS_PER_VN_VARS_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x2588 + (function * 0x90)) : (0x3b60 + \
- (function * 0x90)))
-#define XSTORM_FUNCTION_MODE_OFFSET \
- (IS_E1H_OFFSET ? 0x2c50 : 0xffffffff)
-#define XSTORM_HC_BTR_OFFSET(port) \
- (IS_E1H_OFFSET ? (0xa144 + (port * 0x30)) : (0x1454 + (port * 0x18)))
-#define XSTORM_ISCSI_HQ_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x80c0 + (function * 0x8)) : (0x1c30 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8080 + (function * 0x8)) : (0x1c20 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8081 + (function * 0x8)) : (0x1c21 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8082 + (function * 0x8)) : (0x1c22 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8083 + (function * 0x8)) : (0x1c23 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8084 + (function * 0x8)) : (0x1c24 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8085 + (function * 0x8)) : (0x1c25 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8086 + (function * 0x8)) : (0x1c26 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8004 + (function * 0x8)) : (0x1c04 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8002 + (function * 0x8)) : (0x1c02 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_PAGE_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8000 + (function * 0x8)) : (0x1c00 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_R2TQ_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x80c4 + (function * 0x8)) : (0x1c34 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_SQ_SIZE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x80c2 + (function * 0x8)) : (0x1c32 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8043 + (function * 0x8)) : (0x1c13 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8042 + (function * 0x8)) : (0x1c12 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8041 + (function * 0x8)) : (0x1c11 + \
- (function * 0x8)))
-#define XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x8040 + (function * 0x8)) : (0x1c10 + \
- (function * 0x8)))
-#define XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, stats_counter_id) \
- (IS_E1H_OFFSET ? (0xc000 + (port * 0x360) + (stats_counter_id * \
- 0x30)) : (0x3378 + (port * 0x360) + (stats_counter_id * 0x30)))
-#define XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x2548 + (function * 0x90)) : (0x3b20 + \
- (function * 0x90)))
-#define XSTORM_SPQ_PAGE_BASE_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x2000 + (function * 0x10)) : (0x3328 + \
- (function * 0x10)))
-#define XSTORM_SPQ_PROD_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x2008 + (function * 0x10)) : (0x3330 + \
- (function * 0x10)))
-#define XSTORM_STATS_FLAGS_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x23d8 + (function * 0x8)) : (0x3a40 + \
- (function * 0x8)))
-#define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_ENABLED_OFFSET(port) \
- (IS_E1H_OFFSET ? (0x4000 + (port * 0x8)) : (0x1960 + (port * 0x8)))
-#define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_MAX_COUNT_OFFSET(port) \
- (IS_E1H_OFFSET ? (0x4001 + (port * 0x8)) : (0x1961 + (port * 0x8)))
-#define XSTORM_TCP_TX_SWS_TIMER_VAL_OFFSET(function) \
- (IS_E1H_OFFSET ? (0x4060 + ((function>>1) * 0x8) + ((function&1) \
- * 0x4)) : (0x1978 + (function * 0x4)))
+ (IRO[105].base)
+#define TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(pfId) \
+ (IRO[96].base + ((pfId) * IRO[96].m1))
+#define TSTORM_FUNC_EN_OFFSET(funcId) \
+ (IRO[101].base + ((funcId) * IRO[101].m1))
+#define TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(pfId) \
+ (IRO[195].base + ((pfId) * IRO[195].m1))
+#define TSTORM_FUNCTION_MODE_OFFSET (IRO[103].base)
+#define TSTORM_INDIRECTION_TABLE_OFFSET(pfId) \
+ (IRO[91].base + ((pfId) * IRO[91].m1))
+#define TSTORM_INDIRECTION_TABLE_SIZE (IRO[91].size)
+ #define \
+ TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(pfId, iscsiConBufPblEntry) \
+ (IRO[260].base + ((pfId) * IRO[260].m1) + ((iscsiConBufPblEntry) \
+ * IRO[260].m2))
+#define TSTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \
+ (IRO[264].base + ((pfId) * IRO[264].m1))
+#define TSTORM_ISCSI_L2_ISCSI_OOO_CID_TABLE_OFFSET(pfId) \
+ (IRO[265].base + ((pfId) * IRO[265].m1))
+#define TSTORM_ISCSI_L2_ISCSI_OOO_CLIENT_ID_TABLE_OFFSET(pfId) \
+ (IRO[266].base + ((pfId) * IRO[266].m1))
+#define TSTORM_ISCSI_L2_ISCSI_OOO_PROD_OFFSET(pfId) \
+ (IRO[267].base + ((pfId) * IRO[267].m1))
+#define TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
+ (IRO[263].base + ((pfId) * IRO[263].m1))
+#define TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
+ (IRO[262].base + ((pfId) * IRO[262].m1))
+#define TSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
+ (IRO[261].base + ((pfId) * IRO[261].m1))
+#define TSTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
+ (IRO[259].base + ((pfId) * IRO[259].m1))
+#define TSTORM_ISCSI_TCP_LOCAL_ADV_WND_OFFSET(pfId) \
+ (IRO[269].base + ((pfId) * IRO[269].m1))
+#define TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \
+ (IRO[256].base + ((pfId) * IRO[256].m1))
+#define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfId) \
+ (IRO[257].base + ((pfId) * IRO[257].m1))
+#define TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfId) \
+ (IRO[258].base + ((pfId) * IRO[258].m1))
+#define TSTORM_MAC_FILTER_CONFIG_OFFSET(pfId) \
+ (IRO[196].base + ((pfId) * IRO[196].m1))
+ #define TSTORM_PER_COUNTER_ID_STATS_OFFSET(portId, tStatCntId) \
+ (IRO[100].base + ((portId) * IRO[100].m1) + ((tStatCntId) * \
+ IRO[100].m2))
+#define TSTORM_STATS_FLAGS_OFFSET(pfId) \
+ (IRO[95].base + ((pfId) * IRO[95].m1))
+#define TSTORM_TCP_MAX_CWND_OFFSET(pfId) \
+ (IRO[211].base + ((pfId) * IRO[211].m1))
+#define TSTORM_VF_TO_PF_OFFSET(funcId) \
+ (IRO[102].base + ((funcId) * IRO[102].m1))
+#define USTORM_AGG_DATA_OFFSET (IRO[201].base)
+#define USTORM_AGG_DATA_SIZE (IRO[201].size)
+#define USTORM_ASSERT_LIST_INDEX_OFFSET (IRO[170].base)
+#define USTORM_ASSERT_LIST_OFFSET(assertListEntry) \
+ (IRO[169].base + ((assertListEntry) * IRO[169].m1))
+#define USTORM_ETH_PAUSE_ENABLED_OFFSET(portId) \
+ (IRO[178].base + ((portId) * IRO[178].m1))
+#define USTORM_ETH_STATS_QUERY_ADDR_OFFSET(pfId) \
+ (IRO[172].base + ((pfId) * IRO[172].m1))
+#define USTORM_FCOE_EQ_PROD_OFFSET(pfId) \
+ (IRO[313].base + ((pfId) * IRO[313].m1))
+#define USTORM_FUNC_EN_OFFSET(funcId) \
+ (IRO[174].base + ((funcId) * IRO[174].m1))
+#define USTORM_FUNCTION_MODE_OFFSET (IRO[177].base)
+#define USTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \
+ (IRO[277].base + ((pfId) * IRO[277].m1))
+#define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
+ (IRO[278].base + ((pfId) * IRO[278].m1))
+#define USTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \
+ (IRO[282].base + ((pfId) * IRO[282].m1))
+#define USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfId) \
+ (IRO[279].base + ((pfId) * IRO[279].m1))
+#define USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
+ (IRO[275].base + ((pfId) * IRO[275].m1))
+#define USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
+ (IRO[274].base + ((pfId) * IRO[274].m1))
+#define USTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
+ (IRO[273].base + ((pfId) * IRO[273].m1))
+#define USTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \
+ (IRO[276].base + ((pfId) * IRO[276].m1))
+#define USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfId) \
+ (IRO[280].base + ((pfId) * IRO[280].m1))
+#define USTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
+ (IRO[281].base + ((pfId) * IRO[281].m1))
+#define USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(pfId) \
+ (IRO[176].base + ((pfId) * IRO[176].m1))
+ #define USTORM_PER_COUNTER_ID_STATS_OFFSET(portId, uStatCntId) \
+ (IRO[173].base + ((portId) * IRO[173].m1) + ((uStatCntId) * \
+ IRO[173].m2))
+ #define USTORM_RX_PRODS_E1X_OFFSET(portId, clientId) \
+ (IRO[204].base + ((portId) * IRO[204].m1) + ((clientId) * \
+ IRO[204].m2))
+#define USTORM_RX_PRODS_E2_OFFSET(qzoneId) \
+ (IRO[205].base + ((qzoneId) * IRO[205].m1))
+#define USTORM_STATS_FLAGS_OFFSET(pfId) \
+ (IRO[171].base + ((pfId) * IRO[171].m1))
+#define USTORM_TPA_BTR_OFFSET (IRO[202].base)
+#define USTORM_TPA_BTR_SIZE (IRO[202].size)
+#define USTORM_VF_TO_PF_OFFSET(funcId) \
+ (IRO[175].base + ((funcId) * IRO[175].m1))
+#define XSTORM_AGG_INT_FINAL_CLEANUP_COMP_TYPE (IRO[59].base)
+#define XSTORM_AGG_INT_FINAL_CLEANUP_INDEX (IRO[58].base)
+#define XSTORM_ASSERT_LIST_INDEX_OFFSET (IRO[54].base)
+#define XSTORM_ASSERT_LIST_OFFSET(assertListEntry) \
+ (IRO[53].base + ((assertListEntry) * IRO[53].m1))
+#define XSTORM_CMNG_PER_PORT_VARS_OFFSET(portId) \
+ (IRO[47].base + ((portId) * IRO[47].m1))
+#define XSTORM_E1HOV_OFFSET(pfId) \
+ (IRO[55].base + ((pfId) * IRO[55].m1))
+#define XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(pfId) \
+ (IRO[45].base + ((pfId) * IRO[45].m1))
+#define XSTORM_FAIRNESS_PER_VN_VARS_OFFSET(pfId) \
+ (IRO[49].base + ((pfId) * IRO[49].m1))
+#define XSTORM_FUNC_EN_OFFSET(funcId) \
+ (IRO[51].base + ((funcId) * IRO[51].m1))
+#define XSTORM_FUNCTION_MODE_OFFSET (IRO[56].base)
+#define XSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \
+ (IRO[290].base + ((pfId) * IRO[290].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(pfId) \
+ (IRO[293].base + ((pfId) * IRO[293].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfId) \
+ (IRO[294].base + ((pfId) * IRO[294].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfId) \
+ (IRO[295].base + ((pfId) * IRO[295].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfId) \
+ (IRO[296].base + ((pfId) * IRO[296].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfId) \
+ (IRO[297].base + ((pfId) * IRO[297].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfId) \
+ (IRO[298].base + ((pfId) * IRO[298].m1))
+#define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfId) \
+ (IRO[299].base + ((pfId) * IRO[299].m1))
+#define XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
+ (IRO[289].base + ((pfId) * IRO[289].m1))
+#define XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
+ (IRO[288].base + ((pfId) * IRO[288].m1))
+#define XSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
+ (IRO[287].base + ((pfId) * IRO[287].m1))
+#define XSTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \
+ (IRO[292].base + ((pfId) * IRO[292].m1))
+#define XSTORM_ISCSI_SQ_SIZE_OFFSET(pfId) \
+ (IRO[291].base + ((pfId) * IRO[291].m1))
+#define XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(pfId) \
+ (IRO[286].base + ((pfId) * IRO[286].m1))
+#define XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \
+ (IRO[285].base + ((pfId) * IRO[285].m1))
+#define XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(pfId) \
+ (IRO[284].base + ((pfId) * IRO[284].m1))
+#define XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(pfId) \
+ (IRO[283].base + ((pfId) * IRO[283].m1))
+#define XSTORM_PATH_ID_OFFSET (IRO[65].base)
+ #define XSTORM_PER_COUNTER_ID_STATS_OFFSET(portId, xStatCntId) \
+ (IRO[50].base + ((portId) * IRO[50].m1) + ((xStatCntId) * \
+ IRO[50].m2))
+#define XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(pfId) \
+ (IRO[48].base + ((pfId) * IRO[48].m1))
+#define XSTORM_SPQ_DATA_OFFSET(funcId) \
+ (IRO[32].base + ((funcId) * IRO[32].m1))
+#define XSTORM_SPQ_DATA_SIZE (IRO[32].size)
+#define XSTORM_SPQ_PAGE_BASE_OFFSET(funcId) \
+ (IRO[30].base + ((funcId) * IRO[30].m1))
+#define XSTORM_SPQ_PROD_OFFSET(funcId) \
+ (IRO[31].base + ((funcId) * IRO[31].m1))
+#define XSTORM_STATS_FLAGS_OFFSET(pfId) \
+ (IRO[43].base + ((pfId) * IRO[43].m1))
+#define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_ENABLED_OFFSET(portId) \
+ (IRO[206].base + ((portId) * IRO[206].m1))
+#define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_MAX_COUNT_OFFSET(portId) \
+ (IRO[207].base + ((portId) * IRO[207].m1))
+#define XSTORM_TCP_TX_SWS_TIMER_VAL_OFFSET(pfId) \
+ (IRO[209].base + (((pfId)>>1) * IRO[209].m1) + (((pfId)&1) * \
+ IRO[209].m2))
+#define XSTORM_VF_TO_PF_OFFSET(funcId) \
+ (IRO[52].base + ((funcId) * IRO[52].m1))
#define COMMON_ASM_INVALID_ASSERT_OPCODE 0x0
-/**
-* This file defines HSI constants for the ETH flow
-*/
-#ifdef _EVEREST_MICROCODE
-#include "microcode_constants.h"
-#include "eth_rx_bd.h"
-#include "eth_tx_bd.h"
-#include "eth_rx_cqe.h"
-#include "eth_rx_sge.h"
-#include "eth_rx_cqe_next_page.h"
-#endif
-
/* RSS hash types */
#define DEFAULT_HASH_TYPE 0
#define IPV4_HASH_TYPE 1
@@ -389,11 +292,17 @@
#define U_ETH_NUM_OF_SGES_TO_FETCH 8
#define U_ETH_MAX_SGES_FOR_PACKET 3
+/*Tx params*/
+#define X_ETH_NO_VLAN 0
+#define X_ETH_OUTBAND_VLAN 1
+#define X_ETH_INBAND_VLAN 2
/* Rx ring params */
#define U_ETH_LOCAL_BD_RING_SIZE 8
#define U_ETH_LOCAL_SGE_RING_SIZE 10
#define U_ETH_SGL_SIZE 8
-
+ /* The fw will padd the buffer with this value, so the IP header \
+ will be align to 4 Byte */
+#define IP_HEADER_ALIGNMENT_PADDING 2
#define U_ETH_SGES_PER_PAGE_INVERSE_MASK \
(0xFFFF - ((PAGE_SIZE/((STRUCT_SIZE(eth_rx_sge))/8))-1))
@@ -409,16 +318,15 @@
#define U_ETH_UNDEFINED_Q 0xFF
/* values of command IDs in the ramrod message */
-#define RAMROD_CMD_ID_ETH_PORT_SETUP 80
-#define RAMROD_CMD_ID_ETH_CLIENT_SETUP 85
-#define RAMROD_CMD_ID_ETH_STAT_QUERY 90
-#define RAMROD_CMD_ID_ETH_UPDATE 100
-#define RAMROD_CMD_ID_ETH_HALT 105
-#define RAMROD_CMD_ID_ETH_SET_MAC 110
-#define RAMROD_CMD_ID_ETH_CFC_DEL 115
-#define RAMROD_CMD_ID_ETH_PORT_DEL 120
-#define RAMROD_CMD_ID_ETH_FORWARD_SETUP 125
-
+#define RAMROD_CMD_ID_ETH_UNUSED 0
+#define RAMROD_CMD_ID_ETH_CLIENT_SETUP 1
+#define RAMROD_CMD_ID_ETH_UPDATE 2
+#define RAMROD_CMD_ID_ETH_HALT 3
+#define RAMROD_CMD_ID_ETH_FORWARD_SETUP 4
+#define RAMROD_CMD_ID_ETH_ACTIVATE 5
+#define RAMROD_CMD_ID_ETH_DEACTIVATE 6
+#define RAMROD_CMD_ID_ETH_EMPTY 7
+#define RAMROD_CMD_ID_ETH_TERMINATE 8
/* command values for set mac command */
#define T_ETH_MAC_COMMAND_SET 0
@@ -431,7 +339,9 @@
/* Maximal L2 clients supported */
#define ETH_MAX_RX_CLIENTS_E1 18
-#define ETH_MAX_RX_CLIENTS_E1H 26
+#define ETH_MAX_RX_CLIENTS_E1H 28
+
+#define MAX_STAT_COUNTER_ID ETH_MAX_RX_CLIENTS_E1H
/* Maximal aggregation queues supported */
#define ETH_MAX_AGGREGATION_QUEUES_E1 32
@@ -443,6 +353,20 @@
#define ETH_RSS_MODE_VLAN_PRI 2
#define ETH_RSS_MODE_E1HOV_PRI 3
#define ETH_RSS_MODE_IP_DSCP 4
+#define ETH_RSS_MODE_E2_INTEG 5
+
+
+/* ETH vlan filtering modes */
+#define ETH_VLAN_FILTER_ANY_VLAN 0 /* Don't filter by vlan */
+#define ETH_VLAN_FILTER_SPECIFIC_VLAN \
+ 1 /* Only the vlan_id is allowed */
+#define ETH_VLAN_FILTER_CLASSIFY \
+ 2 /* vlan will be added to CAM for classification */
+
+/* Fast path CQE selection */
+#define ETH_FP_CQE_REGULAR 0
+#define ETH_FP_CQE_SGL 1
+#define ETH_FP_CQE_RAW 2
/**
@@ -458,6 +382,7 @@
#define RESERVED_CONNECTION_TYPE_0 5
#define RESERVED_CONNECTION_TYPE_1 6
#define RESERVED_CONNECTION_TYPE_2 7
+#define NONE_CONNECTION_TYPE 8
#define PROTOCOL_STATE_BIT_OFFSET 6
@@ -466,6 +391,16 @@
#define TOE_STATE (TOE_CONNECTION_TYPE << PROTOCOL_STATE_BIT_OFFSET)
#define RDMA_STATE (RDMA_CONNECTION_TYPE << PROTOCOL_STATE_BIT_OFFSET)
+/* values of command IDs in the ramrod message */
+#define RAMROD_CMD_ID_COMMON_FUNCTION_START 1
+#define RAMROD_CMD_ID_COMMON_FUNCTION_STOP 2
+#define RAMROD_CMD_ID_COMMON_CFC_DEL 3
+#define RAMROD_CMD_ID_COMMON_CFC_DEL_WB 4
+#define RAMROD_CMD_ID_COMMON_SET_MAC 5
+#define RAMROD_CMD_ID_COMMON_STAT_QUERY 6
+#define RAMROD_CMD_ID_COMMON_STOP_TRAFFIC 7
+#define RAMROD_CMD_ID_COMMON_START_TRAFFIC 8
+
/* microcode fixed page page size 4K (chains and ring segments) */
#define MC_PAGE_SIZE 4096
@@ -473,46 +408,26 @@
/* Host coalescing constants */
#define HC_IGU_BC_MODE 0
#define HC_IGU_NBC_MODE 1
+/* Host coalescing constants. E1 includes E1H as well */
+
+/* Number of indices per slow-path SB */
+#define HC_SP_SB_MAX_INDICES 16
+
+/* Number of indices per SB */
+#define HC_SB_MAX_INDICES_E1X 8
+#define HC_SB_MAX_INDICES_E2 8
+
+#define HC_SB_MAX_SB_E1X 32
+#define HC_SB_MAX_SB_E2 136
+
+#define HC_SP_SB_ID 0xde
#define HC_REGULAR_SEGMENT 0
#define HC_DEFAULT_SEGMENT 1
+#define HC_SB_MAX_SM 2
-/* index numbers */
-#define HC_USTORM_DEF_SB_NUM_INDICES 8
-#define HC_CSTORM_DEF_SB_NUM_INDICES 8
-#define HC_XSTORM_DEF_SB_NUM_INDICES 4
-#define HC_TSTORM_DEF_SB_NUM_INDICES 4
-#define HC_USTORM_SB_NUM_INDICES 4
-#define HC_CSTORM_SB_NUM_INDICES 4
-
-/* index values - which counter to update */
-
-#define HC_INDEX_U_TOE_RX_CQ_CONS 0
-#define HC_INDEX_U_ETH_RX_CQ_CONS 1
-#define HC_INDEX_U_ETH_RX_BD_CONS 2
-#define HC_INDEX_U_FCOE_EQ_CONS 3
-
-#define HC_INDEX_C_TOE_TX_CQ_CONS 0
-#define HC_INDEX_C_ETH_TX_CQ_CONS 1
-#define HC_INDEX_C_ISCSI_EQ_CONS 2
-
-#define HC_INDEX_DEF_X_SPQ_CONS 0
-
-#define HC_INDEX_DEF_C_RDMA_EQ_CONS 0
-#define HC_INDEX_DEF_C_RDMA_NAL_PROD 1
-#define HC_INDEX_DEF_C_ETH_FW_TX_CQ_CONS 2
-#define HC_INDEX_DEF_C_ETH_SLOW_PATH 3
-#define HC_INDEX_DEF_C_ETH_RDMA_CQ_CONS 4
-#define HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS 5
-#define HC_INDEX_DEF_C_ETH_FCOE_CQ_CONS 6
-
-#define HC_INDEX_DEF_U_ETH_RDMA_RX_CQ_CONS 0
-#define HC_INDEX_DEF_U_ETH_ISCSI_RX_CQ_CONS 1
-#define HC_INDEX_DEF_U_ETH_RDMA_RX_BD_CONS 2
-#define HC_INDEX_DEF_U_ETH_ISCSI_RX_BD_CONS 3
-#define HC_INDEX_DEF_U_ETH_FCOE_RX_CQ_CONS 4
-#define HC_INDEX_DEF_U_ETH_FCOE_RX_BD_CONS 5
-
+#define HC_SB_MAX_DYNAMIC_INDICES 4
+#define HC_FUNCTION_DISABLED 0xff
/* used by the driver to get the SB offset */
#define USTORM_ID 0
#define CSTORM_ID 1
@@ -529,45 +444,17 @@
/**** DEFINES FOR TIMERS/CLOCKS RESOLUTIONS ****/
-#define EMULATION_FREQUENCY_FACTOR 1600
-#define FPGA_FREQUENCY_FACTOR 100
#define TIMERS_TICK_SIZE_CHIP (1e-3)
-#define TIMERS_TICK_SIZE_EMUL \
- ((TIMERS_TICK_SIZE_CHIP)/((EMULATION_FREQUENCY_FACTOR)))
-#define TIMERS_TICK_SIZE_FPGA \
- ((TIMERS_TICK_SIZE_CHIP)/((FPGA_FREQUENCY_FACTOR)))
#define TSEMI_CLK1_RESUL_CHIP (1e-3)
-#define TSEMI_CLK1_RESUL_EMUL \
- ((TSEMI_CLK1_RESUL_CHIP)/(EMULATION_FREQUENCY_FACTOR))
-#define TSEMI_CLK1_RESUL_FPGA \
- ((TSEMI_CLK1_RESUL_CHIP)/(FPGA_FREQUENCY_FACTOR))
-
-#define USEMI_CLK1_RESUL_CHIP (TIMERS_TICK_SIZE_CHIP)
-#define USEMI_CLK1_RESUL_EMUL (TIMERS_TICK_SIZE_EMUL)
-#define USEMI_CLK1_RESUL_FPGA (TIMERS_TICK_SIZE_FPGA)
#define XSEMI_CLK1_RESUL_CHIP (1e-3)
-#define XSEMI_CLK1_RESUL_EMUL \
- ((XSEMI_CLK1_RESUL_CHIP)/(EMULATION_FREQUENCY_FACTOR))
-#define XSEMI_CLK1_RESUL_FPGA \
- ((XSEMI_CLK1_RESUL_CHIP)/(FPGA_FREQUENCY_FACTOR))
-
-#define XSEMI_CLK2_RESUL_CHIP (1e-6)
-#define XSEMI_CLK2_RESUL_EMUL \
- ((XSEMI_CLK2_RESUL_CHIP)/(EMULATION_FREQUENCY_FACTOR))
-#define XSEMI_CLK2_RESUL_FPGA \
- ((XSEMI_CLK2_RESUL_CHIP)/(FPGA_FREQUENCY_FACTOR))
#define SDM_TIMER_TICK_RESUL_CHIP (4*(1e-6))
-#define SDM_TIMER_TICK_RESUL_EMUL \
- ((SDM_TIMER_TICK_RESUL_CHIP)/(EMULATION_FREQUENCY_FACTOR))
-#define SDM_TIMER_TICK_RESUL_FPGA \
- ((SDM_TIMER_TICK_RESUL_CHIP)/(FPGA_FREQUENCY_FACTOR))
-
/**** END DEFINES FOR TIMERS/CLOCKS RESOLUTIONS ****/
+
#define XSTORM_IP_ID_ROLL_HALF 0x8000
#define XSTORM_IP_ID_ROLL_ALL 0
@@ -576,10 +463,36 @@
#define NUM_OF_PROTOCOLS 4
#define NUM_OF_SAFC_BITS 16
#define MAX_COS_NUMBER 4
-#define MAX_T_STAT_COUNTER_ID 18
-#define MAX_X_STAT_COUNTER_ID 18
-#define MAX_U_STAT_COUNTER_ID 18
+#define FAIRNESS_COS_WRR_MODE 0
+#define FAIRNESS_COS_ETS_MODE 1
+
+
+/* Priority Flow Control (PFC) */
+#define MAX_PFC_PRIORITIES 8
+#define MAX_PFC_TRAFFIC_TYPES 8
+
+/* Available Traffic Types for Link Layer Flow Control */
+#define LLFC_TRAFFIC_TYPE_NW 0
+#define LLFC_TRAFFIC_TYPE_FCOE 1
+#define LLFC_TRAFFIC_TYPE_ISCSI 2
+ /***************** START OF E2 INTEGRATION \
+ CODE***************************************/
+#define LLFC_TRAFFIC_TYPE_NW_COS1_E2INTEG 3
+ /***************** END OF E2 INTEGRATION \
+ CODE***************************************/
+#define LLFC_TRAFFIC_TYPE_MAX 4
+
+ /* used by array traffic_type_to_priority[] to mark traffic type \
+ that is not mapped to priority*/
+#define LLFC_TRAFFIC_TYPE_TO_PRIORITY_UNMAPPED 0xFF
+
+#define LLFC_MODE_NONE 0
+#define LLFC_MODE_PFC 1
+#define LLFC_MODE_SAFC 2
+
+#define DCB_DISABLED 0
+#define DCB_ENABLED 1
#define UNKNOWN_ADDRESS 0
#define UNICAST_ADDRESS 1
@@ -587,8 +500,32 @@
#define BROADCAST_ADDRESS 3
#define SINGLE_FUNCTION 0
-#define MULTI_FUNCTION 1
+#define MULTI_FUNCTION_SD 1
+#define MULTI_FUNCTION_SI 2
#define IP_V4 0
#define IP_V6 1
+
+#define C_ERES_PER_PAGE \
+ (PAGE_SIZE / BITS_TO_BYTES(STRUCT_SIZE(event_ring_elem)))
+#define C_ERE_PER_PAGE_MASK (C_ERES_PER_PAGE - 1)
+
+#define EVENT_RING_OPCODE_VF_PF_CHANNEL 0
+#define EVENT_RING_OPCODE_FUNCTION_START 1
+#define EVENT_RING_OPCODE_FUNCTION_STOP 2
+#define EVENT_RING_OPCODE_CFC_DEL 3
+#define EVENT_RING_OPCODE_CFC_DEL_WB 4
+#define EVENT_RING_OPCODE_SET_MAC 5
+#define EVENT_RING_OPCODE_STAT_QUERY 6
+#define EVENT_RING_OPCODE_STOP_TRAFFIC 7
+#define EVENT_RING_OPCODE_START_TRAFFIC 8
+#define EVENT_RING_OPCODE_FORWARD_SETUP 9
+
+#define VF_PF_CHANNEL_STATE_READY 0
+#define VF_PF_CHANNEL_STATE_WAITING_FOR_ACK 1
+
+#define VF_PF_CHANNEL_STATE_MAX_NUMBER 2
+
+
+#endif /* BNX2X_FW_DEFS_H */
diff --git a/drivers/net/bnx2x/bnx2x_fw_file_hdr.h b/drivers/net/bnx2x/bnx2x_fw_file_hdr.h
index 3f5ee5d7cc2a..f807262911e5 100644
--- a/drivers/net/bnx2x/bnx2x_fw_file_hdr.h
+++ b/drivers/net/bnx2x/bnx2x_fw_file_hdr.h
@@ -31,6 +31,7 @@ struct bnx2x_fw_file_hdr {
struct bnx2x_fw_file_section csem_pram_data;
struct bnx2x_fw_file_section xsem_int_table_data;
struct bnx2x_fw_file_section xsem_pram_data;
+ struct bnx2x_fw_file_section iro_arr;
struct bnx2x_fw_file_section fw_version;
};
diff --git a/drivers/net/bnx2x/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h
index fd1f29e0317d..18c8e23a0e82 100644
--- a/drivers/net/bnx2x/bnx2x_hsi.h
+++ b/drivers/net/bnx2x/bnx2x_hsi.h
@@ -6,6 +6,10 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*/
+#ifndef BNX2X_HSI_H
+#define BNX2X_HSI_H
+
+#include "bnx2x_fw_defs.h"
struct license_key {
u32 reserved[6];
@@ -78,6 +82,8 @@ struct shared_hw_cfg { /* NVRAM Offset */
#define SHARED_HW_CFG_LED_PHY11 0x000b0000
#define SHARED_HW_CFG_LED_MAC4 0x000c0000
#define SHARED_HW_CFG_LED_PHY8 0x000d0000
+#define SHARED_HW_CFG_LED_EXTPHY1 0x000e0000
+
#define SHARED_HW_CFG_AN_ENABLE_MASK 0x3f000000
#define SHARED_HW_CFG_AN_ENABLE_SHIFT 24
@@ -120,6 +126,23 @@ struct shared_hw_cfg { /* NVRAM Offset */
#define SHARED_HW_CFG_FAN_FAILURE_DISABLED 0x00080000
#define SHARED_HW_CFG_FAN_FAILURE_ENABLED 0x00100000
+ /* Set the MDC/MDIO access for the first external phy */
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK 0x1C000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT 26
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE 0x00000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0 0x04000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1 0x08000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH 0x0c000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED 0x10000000
+
+ /* Set the MDC/MDIO access for the second external phy */
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK 0xE0000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT 29
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS2_PHY_TYPE 0x00000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS2_EMAC0 0x20000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS2_EMAC1 0x40000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS2_BOTH 0x60000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS2_SWAPPED 0x80000000
u32 power_dissipated; /* 0x11c */
#define SHARED_HW_CFG_POWER_DIS_CMN_MASK 0xff000000
#define SHARED_HW_CFG_POWER_DIS_CMN_SHIFT 24
@@ -221,11 +244,93 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */
u16 xgxs_config_tx[4]; /* 0x1A0 */
- u32 Reserved1[64]; /* 0x1A8 */
+ u32 Reserved1[57]; /* 0x1A8 */
+ u32 speed_capability_mask2; /* 0x28C */
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_MASK 0x0000FFFF
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_SHIFT 0
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_10M_FULL 0x00000001
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3__ 0x00000002
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3___ 0x00000004
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_100M_FULL 0x00000008
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_1G 0x00000010
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_2_DOT_5G 0x00000020
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_10G 0x00000040
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_12G 0x00000080
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_12_DOT_5G 0x00000100
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_13G 0x00000200
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_15G 0x00000400
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_16G 0x00000800
+
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_MASK 0xFFFF0000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_SHIFT 16
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_10M_FULL 0x00010000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0__ 0x00020000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0___ 0x00040000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_100M_FULL 0x00080000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_1G 0x00100000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_2_DOT_5G 0x00200000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_10G 0x00400000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_12G 0x00800000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_12_DOT_5G 0x01000000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_13G 0x02000000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_15G 0x04000000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_16G 0x08000000
+
+ /* In the case where two media types (e.g. copper and fiber) are
+ present and electrically active at the same time, PHY Selection
+ will determine which of the two PHYs will be designated as the
+ Active PHY and used for a connection to the network. */
+ u32 multi_phy_config; /* 0x290 */
+#define PORT_HW_CFG_PHY_SELECTION_MASK 0x00000007
+#define PORT_HW_CFG_PHY_SELECTION_SHIFT 0
+#define PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT 0x00000000
+#define PORT_HW_CFG_PHY_SELECTION_FIRST_PHY 0x00000001
+#define PORT_HW_CFG_PHY_SELECTION_SECOND_PHY 0x00000002
+#define PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY 0x00000003
+#define PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY 0x00000004
+
+ /* When enabled, all second phy nvram parameters will be swapped
+ with the first phy parameters */
+#define PORT_HW_CFG_PHY_SWAPPED_MASK 0x00000008
+#define PORT_HW_CFG_PHY_SWAPPED_SHIFT 3
+#define PORT_HW_CFG_PHY_SWAPPED_DISABLED 0x00000000
+#define PORT_HW_CFG_PHY_SWAPPED_ENABLED 0x00000008
+
+
+ /* Address of the second external phy */
+ u32 external_phy_config2; /* 0x294 */
+#define PORT_HW_CFG_XGXS_EXT_PHY2_ADDR_MASK 0x000000FF
+#define PORT_HW_CFG_XGXS_EXT_PHY2_ADDR_SHIFT 0
+
+ /* The second XGXS external PHY type */
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_MASK 0x0000FF00
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_SHIFT 8
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_DIRECT 0x00000000
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8071 0x00000100
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8072 0x00000200
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8073 0x00000300
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8705 0x00000400
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8706 0x00000500
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8726 0x00000600
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8481 0x00000700
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_SFX7101 0x00000800
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8727 0x00000900
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8727_NOC 0x00000a00
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84823 0x00000b00
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM54640 0x00000c00
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84833 0x00000d00
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_FAILURE 0x0000fd00
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_NOT_CONN 0x0000ff00
+
+ /* 4 times 16 bits for all 4 lanes. For some external PHYs (such as
+ 8706, 8726 and 8727) not all 4 values are needed. */
+ u16 xgxs_config2_rx[4]; /* 0x296 */
+ u16 xgxs_config2_tx[4]; /* 0x2A0 */
u32 lane_config;
#define PORT_HW_CFG_LANE_SWAP_CFG_MASK 0x0000ffff
#define PORT_HW_CFG_LANE_SWAP_CFG_SHIFT 0
+
#define PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK 0x000000ff
#define PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT 0
#define PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK 0x0000ff00
@@ -515,10 +620,17 @@ struct port_feat_cfg { /* port 0: 0x454 port 1: 0x4c8 */
#define PORT_FEATURE_FLOW_CONTROL_NONE 0x00000400
/* The default for MCP link configuration,
- uses the same defines as link_config */
+ uses the same defines as link_config */
u32 mfw_wol_link_cfg;
+ /* The default for the driver of the second external phy,
+ uses the same defines as link_config */
+ u32 link_config2; /* 0x47C */
- u32 reserved[19];
+ /* The default for MCP of the second external phy,
+ uses the same defines as link_config */
+ u32 mfw_wol_link_cfg2; /* 0x480 */
+
+ u32 Reserved2[17]; /* 0x484 */
};
@@ -551,6 +663,7 @@ struct shm_dev_info { /* size */
#define FUNC_7 7
#define E1_FUNC_MAX 2
#define E1H_FUNC_MAX 8
+#define E2_FUNC_MAX 4 /* per path */
#define VN_0 0
#define VN_1 1
@@ -686,8 +799,14 @@ struct drv_func_mb {
* The optic module verification commands require bootcode
* v5.0.6 or later
*/
-#define DRV_MSG_CODE_VRFY_OPT_MDL 0xa0000000
-#define REQ_BC_VER_4_VRFY_OPT_MDL 0x00050006
+#define DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL 0xa0000000
+#define REQ_BC_VER_4_VRFY_FIRST_PHY_OPT_MDL 0x00050006
+ /*
+ * The specific optic module verification command requires bootcode
+ * v5.2.12 or later
+ */
+#define DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL 0xa1000000
+#define REQ_BC_VER_4_VRFY_SPECIFIC_PHY_OPT_MDL 0x00050234
#define BIOS_MSG_CODE_LIC_CHALLENGE 0xff010000
#define BIOS_MSG_CODE_LIC_RESPONSE 0xff020000
@@ -703,6 +822,9 @@ struct drv_func_mb {
#define FW_MSG_CODE_DRV_LOAD_COMMON 0x10100000
#define FW_MSG_CODE_DRV_LOAD_PORT 0x10110000
#define FW_MSG_CODE_DRV_LOAD_FUNCTION 0x10120000
+ /* Load common chip is supported from bc 6.0.0 */
+#define REQ_BC_VER_4_DRV_LOAD_COMMON_CHIP 0x00060000
+#define FW_MSG_CODE_DRV_LOAD_COMMON_CHIP 0x10130000
#define FW_MSG_CODE_DRV_LOAD_REFUSED 0x10200000
#define FW_MSG_CODE_DRV_LOAD_DONE 0x11100000
#define FW_MSG_CODE_DRV_UNLOAD_COMMON 0x20100000
@@ -903,11 +1025,22 @@ struct shmem_region { /* SharedMem Offset (size) */
struct mgmtfw_state mgmtfw_state; /* 0x4ac (0x1b8) */
struct drv_port_mb port_mb[PORT_MAX]; /* 0x664 (16*2=0x20) */
- struct drv_func_mb func_mb[E1H_FUNC_MAX];
+ struct drv_func_mb func_mb[]; /* 0x684
+ (44*2/4/8=0x58/0xb0/0x160) */
+
+}; /* 57710 = 0x6dc | 57711 = 0x7E4 | 57712 = 0x734 */
- struct mf_cfg mf_cfg;
+struct fw_flr_ack {
+ u32 pf_ack;
+ u32 vf_ack[1];
+ u32 iov_dis_ack;
+};
-}; /* 0x6dc */
+struct fw_flr_mb {
+ u32 aggint;
+ u32 opgen_addr;
+ struct fw_flr_ack ack;
+};
struct shmem2_region {
@@ -922,7 +1055,25 @@ struct shmem2_region {
#define SHMEM_DCC_SUPPORT_SET_PROTOCOL_TLV 0x00000040
#define SHMEM_DCC_SUPPORT_SET_PRIORITY_TLV 0x00000080
#define SHMEM_DCC_SUPPORT_DEFAULT SHMEM_DCC_SUPPORT_NONE
-
+ u32 ext_phy_fw_version2[PORT_MAX];
+ /*
+ * For backwards compatibility, if the mf_cfg_addr does not exist
+ * (the size filed is smaller than 0xc) the mf_cfg resides at the
+ * end of struct shmem_region
+ */
+ u32 mf_cfg_addr;
+#define SHMEM_MF_CFG_ADDR_NONE 0x00000000
+
+ struct fw_flr_mb flr_mb;
+ u32 reserved[3];
+ /*
+ * The other shmemX_base_addr holds the other path's shmem address
+ * required for example in case of common phy init, or for path1 to know
+ * the address of mcp debug trace which is located in offset from shmem
+ * of path0
+ */
+ u32 other_shmem_base_addr;
+ u32 other_shmem2_base_addr;
};
@@ -978,7 +1129,7 @@ struct emac_stats {
};
-struct bmac_stats {
+struct bmac1_stats {
u32 tx_stat_gtpkt_lo;
u32 tx_stat_gtpkt_hi;
u32 tx_stat_gtxpf_lo;
@@ -1082,10 +1233,126 @@ struct bmac_stats {
u32 rx_stat_gripj_hi;
};
+struct bmac2_stats {
+ u32 tx_stat_gtpk_lo; /* gtpok */
+ u32 tx_stat_gtpk_hi; /* gtpok */
+ u32 tx_stat_gtxpf_lo; /* gtpf */
+ u32 tx_stat_gtxpf_hi; /* gtpf */
+ u32 tx_stat_gtpp_lo; /* NEW BMAC2 */
+ u32 tx_stat_gtpp_hi; /* NEW BMAC2 */
+ u32 tx_stat_gtfcs_lo;
+ u32 tx_stat_gtfcs_hi;
+ u32 tx_stat_gtuca_lo; /* NEW BMAC2 */
+ u32 tx_stat_gtuca_hi; /* NEW BMAC2 */
+ u32 tx_stat_gtmca_lo;
+ u32 tx_stat_gtmca_hi;
+ u32 tx_stat_gtbca_lo;
+ u32 tx_stat_gtbca_hi;
+ u32 tx_stat_gtovr_lo;
+ u32 tx_stat_gtovr_hi;
+ u32 tx_stat_gtfrg_lo;
+ u32 tx_stat_gtfrg_hi;
+ u32 tx_stat_gtpkt1_lo; /* gtpkt */
+ u32 tx_stat_gtpkt1_hi; /* gtpkt */
+ u32 tx_stat_gt64_lo;
+ u32 tx_stat_gt64_hi;
+ u32 tx_stat_gt127_lo;
+ u32 tx_stat_gt127_hi;
+ u32 tx_stat_gt255_lo;
+ u32 tx_stat_gt255_hi;
+ u32 tx_stat_gt511_lo;
+ u32 tx_stat_gt511_hi;
+ u32 tx_stat_gt1023_lo;
+ u32 tx_stat_gt1023_hi;
+ u32 tx_stat_gt1518_lo;
+ u32 tx_stat_gt1518_hi;
+ u32 tx_stat_gt2047_lo;
+ u32 tx_stat_gt2047_hi;
+ u32 tx_stat_gt4095_lo;
+ u32 tx_stat_gt4095_hi;
+ u32 tx_stat_gt9216_lo;
+ u32 tx_stat_gt9216_hi;
+ u32 tx_stat_gt16383_lo;
+ u32 tx_stat_gt16383_hi;
+ u32 tx_stat_gtmax_lo;
+ u32 tx_stat_gtmax_hi;
+ u32 tx_stat_gtufl_lo;
+ u32 tx_stat_gtufl_hi;
+ u32 tx_stat_gterr_lo;
+ u32 tx_stat_gterr_hi;
+ u32 tx_stat_gtbyt_lo;
+ u32 tx_stat_gtbyt_hi;
+
+ u32 rx_stat_gr64_lo;
+ u32 rx_stat_gr64_hi;
+ u32 rx_stat_gr127_lo;
+ u32 rx_stat_gr127_hi;
+ u32 rx_stat_gr255_lo;
+ u32 rx_stat_gr255_hi;
+ u32 rx_stat_gr511_lo;
+ u32 rx_stat_gr511_hi;
+ u32 rx_stat_gr1023_lo;
+ u32 rx_stat_gr1023_hi;
+ u32 rx_stat_gr1518_lo;
+ u32 rx_stat_gr1518_hi;
+ u32 rx_stat_gr2047_lo;
+ u32 rx_stat_gr2047_hi;
+ u32 rx_stat_gr4095_lo;
+ u32 rx_stat_gr4095_hi;
+ u32 rx_stat_gr9216_lo;
+ u32 rx_stat_gr9216_hi;
+ u32 rx_stat_gr16383_lo;
+ u32 rx_stat_gr16383_hi;
+ u32 rx_stat_grmax_lo;
+ u32 rx_stat_grmax_hi;
+ u32 rx_stat_grpkt_lo;
+ u32 rx_stat_grpkt_hi;
+ u32 rx_stat_grfcs_lo;
+ u32 rx_stat_grfcs_hi;
+ u32 rx_stat_gruca_lo;
+ u32 rx_stat_gruca_hi;
+ u32 rx_stat_grmca_lo;
+ u32 rx_stat_grmca_hi;
+ u32 rx_stat_grbca_lo;
+ u32 rx_stat_grbca_hi;
+ u32 rx_stat_grxpf_lo; /* grpf */
+ u32 rx_stat_grxpf_hi; /* grpf */
+ u32 rx_stat_grpp_lo;
+ u32 rx_stat_grpp_hi;
+ u32 rx_stat_grxuo_lo; /* gruo */
+ u32 rx_stat_grxuo_hi; /* gruo */
+ u32 rx_stat_grjbr_lo;
+ u32 rx_stat_grjbr_hi;
+ u32 rx_stat_grovr_lo;
+ u32 rx_stat_grovr_hi;
+ u32 rx_stat_grxcf_lo; /* grcf */
+ u32 rx_stat_grxcf_hi; /* grcf */
+ u32 rx_stat_grflr_lo;
+ u32 rx_stat_grflr_hi;
+ u32 rx_stat_grpok_lo;
+ u32 rx_stat_grpok_hi;
+ u32 rx_stat_grmeg_lo;
+ u32 rx_stat_grmeg_hi;
+ u32 rx_stat_grmeb_lo;
+ u32 rx_stat_grmeb_hi;
+ u32 rx_stat_grbyt_lo;
+ u32 rx_stat_grbyt_hi;
+ u32 rx_stat_grund_lo;
+ u32 rx_stat_grund_hi;
+ u32 rx_stat_grfrg_lo;
+ u32 rx_stat_grfrg_hi;
+ u32 rx_stat_grerb_lo; /* grerrbyt */
+ u32 rx_stat_grerb_hi; /* grerrbyt */
+ u32 rx_stat_grfre_lo; /* grfrerr */
+ u32 rx_stat_grfre_hi; /* grfrerr */
+ u32 rx_stat_gripj_lo;
+ u32 rx_stat_gripj_hi;
+};
union mac_stats {
- struct emac_stats emac_stats;
- struct bmac_stats bmac_stats;
+ struct emac_stats emac_stats;
+ struct bmac1_stats bmac1_stats;
+ struct bmac2_stats bmac2_stats;
};
@@ -1259,17 +1526,17 @@ struct host_func_stats {
};
-#define BCM_5710_FW_MAJOR_VERSION 5
-#define BCM_5710_FW_MINOR_VERSION 2
-#define BCM_5710_FW_REVISION_VERSION 13
-#define BCM_5710_FW_ENGINEERING_VERSION 0
+#define BCM_5710_FW_MAJOR_VERSION 6
+#define BCM_5710_FW_MINOR_VERSION 0
+#define BCM_5710_FW_REVISION_VERSION 34
+#define BCM_5710_FW_ENGINEERING_VERSION 0
#define BCM_5710_FW_COMPILE_FLAGS 1
/*
* attention bits
*/
-struct atten_def_status_block {
+struct atten_sp_status_block {
__le32 attn_bits;
__le32 attn_bits_ack;
u8 status_block_id;
@@ -1327,7 +1594,60 @@ struct doorbell_set_prod {
/*
- * IGU driver acknowledgement register
+ * 3 lines. status block
+ */
+struct hc_status_block_e1x {
+ __le16 index_values[HC_SB_MAX_INDICES_E1X];
+ __le16 running_index[HC_SB_MAX_SM];
+ u32 rsrv;
+};
+
+/*
+ * host status block
+ */
+struct host_hc_status_block_e1x {
+ struct hc_status_block_e1x sb;
+};
+
+
+/*
+ * 3 lines. status block
+ */
+struct hc_status_block_e2 {
+ __le16 index_values[HC_SB_MAX_INDICES_E2];
+ __le16 running_index[HC_SB_MAX_SM];
+ u32 reserved;
+};
+
+/*
+ * host status block
+ */
+struct host_hc_status_block_e2 {
+ struct hc_status_block_e2 sb;
+};
+
+
+/*
+ * 5 lines. slow-path status block
+ */
+struct hc_sp_status_block {
+ __le16 index_values[HC_SP_SB_MAX_INDICES];
+ __le16 running_index;
+ __le16 rsrv;
+ u32 rsrv1;
+};
+
+/*
+ * host status block
+ */
+struct host_sp_status_block {
+ struct atten_sp_status_block atten_status_block;
+ struct hc_sp_status_block sp_sb;
+};
+
+
+/*
+ * IGU driver acknowledgment register
*/
struct igu_ack_register {
#if defined(__BIG_ENDIAN)
@@ -1417,6 +1737,24 @@ union igu_consprod_reg {
/*
+ * Control register for the IGU command register
+ */
+struct igu_ctrl_reg {
+ u32 ctrl_data;
+#define IGU_CTRL_REG_ADDRESS (0xFFF<<0)
+#define IGU_CTRL_REG_ADDRESS_SHIFT 0
+#define IGU_CTRL_REG_FID (0x7F<<12)
+#define IGU_CTRL_REG_FID_SHIFT 12
+#define IGU_CTRL_REG_RESERVED (0x1<<19)
+#define IGU_CTRL_REG_RESERVED_SHIFT 19
+#define IGU_CTRL_REG_TYPE (0x1<<20)
+#define IGU_CTRL_REG_TYPE_SHIFT 20
+#define IGU_CTRL_REG_UNUSED (0x7FF<<21)
+#define IGU_CTRL_REG_UNUSED_SHIFT 21
+};
+
+
+/*
* Parser parsing flags field
*/
struct parsing_flags {
@@ -1485,8 +1823,14 @@ struct dmae_command {
#define DMAE_COMMAND_DST_RESET_SHIFT 14
#define DMAE_COMMAND_E1HVN (0x3<<15)
#define DMAE_COMMAND_E1HVN_SHIFT 15
-#define DMAE_COMMAND_RESERVED0 (0x7FFF<<17)
-#define DMAE_COMMAND_RESERVED0_SHIFT 17
+#define DMAE_COMMAND_DST_VN (0x3<<17)
+#define DMAE_COMMAND_DST_VN_SHIFT 17
+#define DMAE_COMMAND_C_FUNC (0x1<<19)
+#define DMAE_COMMAND_C_FUNC_SHIFT 19
+#define DMAE_COMMAND_ERR_POLICY (0x3<<20)
+#define DMAE_COMMAND_ERR_POLICY_SHIFT 20
+#define DMAE_COMMAND_RESERVED0 (0x3FF<<22)
+#define DMAE_COMMAND_RESERVED0_SHIFT 22
u32 src_addr_lo;
u32 src_addr_hi;
u32 dst_addr_lo;
@@ -1511,11 +1855,11 @@ struct dmae_command {
u16 crc16_c;
#endif
#if defined(__BIG_ENDIAN)
- u16 reserved2;
+ u16 reserved3;
u16 crc_t10;
#elif defined(__LITTLE_ENDIAN)
u16 crc_t10;
- u16 reserved2;
+ u16 reserved3;
#endif
#if defined(__BIG_ENDIAN)
u16 xsum8;
@@ -1536,96 +1880,20 @@ struct double_regpair {
/*
- * The eth storm context of Ustorm (configuration part)
+ * SDM operation gen command (generate aggregative interrupt)
*/
-struct ustorm_eth_st_context_config {
-#if defined(__BIG_ENDIAN)
- u8 flags;
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT (0x1<<0)
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT_SHIFT 0
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_DYNAMIC_HC (0x1<<1)
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_DYNAMIC_HC_SHIFT 1
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA (0x1<<2)
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA_SHIFT 2
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS (0x1<<3)
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS_SHIFT 3
-#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0 (0xF<<4)
-#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0_SHIFT 4
- u8 status_block_id;
- u8 clientId;
- u8 sb_index_numbers;
-#define USTORM_ETH_ST_CONTEXT_CONFIG_CQE_SB_INDEX_NUMBER (0xF<<0)
-#define USTORM_ETH_ST_CONTEXT_CONFIG_CQE_SB_INDEX_NUMBER_SHIFT 0
-#define USTORM_ETH_ST_CONTEXT_CONFIG_BD_SB_INDEX_NUMBER (0xF<<4)
-#define USTORM_ETH_ST_CONTEXT_CONFIG_BD_SB_INDEX_NUMBER_SHIFT 4
-#elif defined(__LITTLE_ENDIAN)
- u8 sb_index_numbers;
-#define USTORM_ETH_ST_CONTEXT_CONFIG_CQE_SB_INDEX_NUMBER (0xF<<0)
-#define USTORM_ETH_ST_CONTEXT_CONFIG_CQE_SB_INDEX_NUMBER_SHIFT 0
-#define USTORM_ETH_ST_CONTEXT_CONFIG_BD_SB_INDEX_NUMBER (0xF<<4)
-#define USTORM_ETH_ST_CONTEXT_CONFIG_BD_SB_INDEX_NUMBER_SHIFT 4
- u8 clientId;
- u8 status_block_id;
- u8 flags;
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT (0x1<<0)
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT_SHIFT 0
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_DYNAMIC_HC (0x1<<1)
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_DYNAMIC_HC_SHIFT 1
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA (0x1<<2)
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA_SHIFT 2
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS (0x1<<3)
-#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS_SHIFT 3
-#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0 (0xF<<4)
-#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0_SHIFT 4
-#endif
-#if defined(__BIG_ENDIAN)
- u16 bd_buff_size;
- u8 statistics_counter_id;
- u8 mc_alignment_log_size;
-#elif defined(__LITTLE_ENDIAN)
- u8 mc_alignment_log_size;
- u8 statistics_counter_id;
- u16 bd_buff_size;
-#endif
-#if defined(__BIG_ENDIAN)
- u8 __local_sge_prod;
- u8 __local_bd_prod;
- u16 sge_buff_size;
-#elif defined(__LITTLE_ENDIAN)
- u16 sge_buff_size;
- u8 __local_bd_prod;
- u8 __local_sge_prod;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 __sdm_bd_expected_counter;
- u8 cstorm_agg_int;
- u8 __expected_bds_on_ram;
-#elif defined(__LITTLE_ENDIAN)
- u8 __expected_bds_on_ram;
- u8 cstorm_agg_int;
- u16 __sdm_bd_expected_counter;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 __ring_data_ram_addr;
- u16 __hc_cstorm_ram_addr;
-#elif defined(__LITTLE_ENDIAN)
- u16 __hc_cstorm_ram_addr;
- u16 __ring_data_ram_addr;
-#endif
-#if defined(__BIG_ENDIAN)
- u8 reserved1;
- u8 max_sges_for_packet;
- u16 __bd_ring_ram_addr;
-#elif defined(__LITTLE_ENDIAN)
- u16 __bd_ring_ram_addr;
- u8 max_sges_for_packet;
- u8 reserved1;
-#endif
- u32 bd_page_base_lo;
- u32 bd_page_base_hi;
- u32 sge_page_base_lo;
- u32 sge_page_base_hi;
- struct regpair reserved2;
+struct sdm_op_gen {
+ __le32 command;
+#define SDM_OP_GEN_COMP_PARAM (0x1F<<0)
+#define SDM_OP_GEN_COMP_PARAM_SHIFT 0
+#define SDM_OP_GEN_COMP_TYPE (0x7<<5)
+#define SDM_OP_GEN_COMP_TYPE_SHIFT 5
+#define SDM_OP_GEN_AGG_VECT_IDX (0xFF<<8)
+#define SDM_OP_GEN_AGG_VECT_IDX_SHIFT 8
+#define SDM_OP_GEN_AGG_VECT_IDX_VALID (0x1<<16)
+#define SDM_OP_GEN_AGG_VECT_IDX_VALID_SHIFT 16
+#define SDM_OP_GEN_RESERVED (0x7FFF<<17)
+#define SDM_OP_GEN_RESERVED_SHIFT 17
};
/*
@@ -1644,20 +1912,13 @@ struct eth_rx_sge {
__le32 addr_hi;
};
-/*
- * Local BDs and SGEs rings (in ETH)
- */
-struct eth_local_rx_rings {
- struct eth_rx_bd __local_bd_ring[8];
- struct eth_rx_sge __local_sge_ring[10];
-};
+
/*
* The eth storm context of Ustorm
*/
struct ustorm_eth_st_context {
- struct ustorm_eth_st_context_config common;
- struct eth_local_rx_rings __rings;
+ u32 reserved0[48];
};
/*
@@ -1668,337 +1929,53 @@ struct tstorm_eth_st_context {
};
/*
- * The eth aggregative context section of Xstorm
- */
-struct xstorm_eth_extra_ag_context_section {
-#if defined(__BIG_ENDIAN)
- u8 __tcp_agg_vars1;
- u8 __reserved50;
- u16 __mss;
-#elif defined(__LITTLE_ENDIAN)
- u16 __mss;
- u8 __reserved50;
- u8 __tcp_agg_vars1;
-#endif
- u32 __snd_nxt;
- u32 __tx_wnd;
- u32 __snd_una;
- u32 __reserved53;
-#if defined(__BIG_ENDIAN)
- u8 __agg_val8_th;
- u8 __agg_val8;
- u16 __tcp_agg_vars2;
-#elif defined(__LITTLE_ENDIAN)
- u16 __tcp_agg_vars2;
- u8 __agg_val8;
- u8 __agg_val8_th;
-#endif
- u32 __reserved58;
- u32 __reserved59;
- u32 __reserved60;
- u32 __reserved61;
-#if defined(__BIG_ENDIAN)
- u16 __agg_val7_th;
- u16 __agg_val7;
-#elif defined(__LITTLE_ENDIAN)
- u16 __agg_val7;
- u16 __agg_val7_th;
-#endif
-#if defined(__BIG_ENDIAN)
- u8 __tcp_agg_vars5;
- u8 __tcp_agg_vars4;
- u8 __tcp_agg_vars3;
- u8 __reserved62;
-#elif defined(__LITTLE_ENDIAN)
- u8 __reserved62;
- u8 __tcp_agg_vars3;
- u8 __tcp_agg_vars4;
- u8 __tcp_agg_vars5;
-#endif
- u32 __tcp_agg_vars6;
-#if defined(__BIG_ENDIAN)
- u16 __agg_misc6;
- u16 __tcp_agg_vars7;
-#elif defined(__LITTLE_ENDIAN)
- u16 __tcp_agg_vars7;
- u16 __agg_misc6;
-#endif
- u32 __agg_val10;
- u32 __agg_val10_th;
-#if defined(__BIG_ENDIAN)
- u16 __reserved3;
- u8 __reserved2;
- u8 __da_only_cnt;
-#elif defined(__LITTLE_ENDIAN)
- u8 __da_only_cnt;
- u8 __reserved2;
- u16 __reserved3;
-#endif
-};
-
-/*
* The eth aggregative context of Xstorm
*/
struct xstorm_eth_ag_context {
-#if defined(__BIG_ENDIAN)
- u16 agg_val1;
- u8 __agg_vars1;
- u8 __state;
-#elif defined(__LITTLE_ENDIAN)
- u8 __state;
- u8 __agg_vars1;
- u16 agg_val1;
-#endif
+ u32 reserved0;
#if defined(__BIG_ENDIAN)
u8 cdu_reserved;
- u8 __agg_vars4;
- u8 __agg_vars3;
- u8 __agg_vars2;
+ u8 reserved2;
+ u16 reserved1;
#elif defined(__LITTLE_ENDIAN)
- u8 __agg_vars2;
- u8 __agg_vars3;
- u8 __agg_vars4;
+ u16 reserved1;
+ u8 reserved2;
u8 cdu_reserved;
#endif
- u32 __bd_prod;
-#if defined(__BIG_ENDIAN)
- u16 __agg_vars5;
- u16 __agg_val4_th;
-#elif defined(__LITTLE_ENDIAN)
- u16 __agg_val4_th;
- u16 __agg_vars5;
-#endif
- struct xstorm_eth_extra_ag_context_section __extra_section;
-#if defined(__BIG_ENDIAN)
- u16 __agg_vars7;
- u8 __agg_val3_th;
- u8 __agg_vars6;
-#elif defined(__LITTLE_ENDIAN)
- u8 __agg_vars6;
- u8 __agg_val3_th;
- u16 __agg_vars7;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 __agg_val11_th;
- u16 __agg_val11;
-#elif defined(__LITTLE_ENDIAN)
- u16 __agg_val11;
- u16 __agg_val11_th;
-#endif
-#if defined(__BIG_ENDIAN)
- u8 __reserved1;
- u8 __agg_val6_th;
- u16 __agg_val9;
-#elif defined(__LITTLE_ENDIAN)
- u16 __agg_val9;
- u8 __agg_val6_th;
- u8 __reserved1;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 __agg_val2_th;
- u16 __agg_val2;
-#elif defined(__LITTLE_ENDIAN)
- u16 __agg_val2;
- u16 __agg_val2_th;
-#endif
- u32 __agg_vars8;
-#if defined(__BIG_ENDIAN)
- u16 __agg_misc0;
- u16 __agg_val4;
-#elif defined(__LITTLE_ENDIAN)
- u16 __agg_val4;
- u16 __agg_misc0;
-#endif
-#if defined(__BIG_ENDIAN)
- u8 __agg_val3;
- u8 __agg_val6;
- u8 __agg_val5_th;
- u8 __agg_val5;
-#elif defined(__LITTLE_ENDIAN)
- u8 __agg_val5;
- u8 __agg_val5_th;
- u8 __agg_val6;
- u8 __agg_val3;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 __agg_misc1;
- u16 __bd_ind_max_val;
-#elif defined(__LITTLE_ENDIAN)
- u16 __bd_ind_max_val;
- u16 __agg_misc1;
-#endif
- u32 __reserved57;
- u32 __agg_misc4;
- u32 __agg_misc5;
-};
-
-/*
- * The eth extra aggregative context section of Tstorm
- */
-struct tstorm_eth_extra_ag_context_section {
- u32 __agg_val1;
-#if defined(__BIG_ENDIAN)
- u8 __tcp_agg_vars2;
- u8 __agg_val3;
- u16 __agg_val2;
-#elif defined(__LITTLE_ENDIAN)
- u16 __agg_val2;
- u8 __agg_val3;
- u8 __tcp_agg_vars2;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 __agg_val5;
- u8 __agg_val6;
- u8 __tcp_agg_vars3;
-#elif defined(__LITTLE_ENDIAN)
- u8 __tcp_agg_vars3;
- u8 __agg_val6;
- u16 __agg_val5;
-#endif
- u32 __reserved63;
- u32 __reserved64;
- u32 __reserved65;
- u32 __reserved66;
- u32 __reserved67;
- u32 __tcp_agg_vars1;
- u32 __reserved61;
- u32 __reserved62;
- u32 __reserved2;
+ u32 reserved3[30];
};
/*
* The eth aggregative context of Tstorm
*/
struct tstorm_eth_ag_context {
-#if defined(__BIG_ENDIAN)
- u16 __reserved54;
- u8 __agg_vars1;
- u8 __state;
-#elif defined(__LITTLE_ENDIAN)
- u8 __state;
- u8 __agg_vars1;
- u16 __reserved54;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 __agg_val4;
- u16 __agg_vars2;
-#elif defined(__LITTLE_ENDIAN)
- u16 __agg_vars2;
- u16 __agg_val4;
-#endif
- struct tstorm_eth_extra_ag_context_section __extra_section;
+ u32 __reserved0[14];
};
+
/*
* The eth aggregative context of Cstorm
*/
struct cstorm_eth_ag_context {
- u32 __agg_vars1;
-#if defined(__BIG_ENDIAN)
- u8 __aux1_th;
- u8 __aux1_val;
- u16 __agg_vars2;
-#elif defined(__LITTLE_ENDIAN)
- u16 __agg_vars2;
- u8 __aux1_val;
- u8 __aux1_th;
-#endif
- u32 __num_of_treated_packet;
- u32 __last_packet_treated;
-#if defined(__BIG_ENDIAN)
- u16 __reserved58;
- u16 __reserved57;
-#elif defined(__LITTLE_ENDIAN)
- u16 __reserved57;
- u16 __reserved58;
-#endif
-#if defined(__BIG_ENDIAN)
- u8 __reserved62;
- u8 __reserved61;
- u8 __reserved60;
- u8 __reserved59;
-#elif defined(__LITTLE_ENDIAN)
- u8 __reserved59;
- u8 __reserved60;
- u8 __reserved61;
- u8 __reserved62;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 __reserved64;
- u16 __reserved63;
-#elif defined(__LITTLE_ENDIAN)
- u16 __reserved63;
- u16 __reserved64;
-#endif
- u32 __reserved65;
-#if defined(__BIG_ENDIAN)
- u16 __agg_vars3;
- u16 __rq_inv_cnt;
-#elif defined(__LITTLE_ENDIAN)
- u16 __rq_inv_cnt;
- u16 __agg_vars3;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 __packet_index_th;
- u16 __packet_index;
-#elif defined(__LITTLE_ENDIAN)
- u16 __packet_index;
- u16 __packet_index_th;
-#endif
+ u32 __reserved0[10];
};
+
/*
* The eth aggregative context of Ustorm
*/
struct ustorm_eth_ag_context {
-#if defined(__BIG_ENDIAN)
- u8 __aux_counter_flags;
- u8 __agg_vars2;
- u8 __agg_vars1;
- u8 __state;
-#elif defined(__LITTLE_ENDIAN)
- u8 __state;
- u8 __agg_vars1;
- u8 __agg_vars2;
- u8 __aux_counter_flags;
-#endif
+ u32 __reserved0;
#if defined(__BIG_ENDIAN)
u8 cdu_usage;
- u8 __agg_misc2;
- u16 __agg_misc1;
+ u8 __reserved2;
+ u16 __reserved1;
#elif defined(__LITTLE_ENDIAN)
- u16 __agg_misc1;
- u8 __agg_misc2;
+ u16 __reserved1;
+ u8 __reserved2;
u8 cdu_usage;
#endif
- u32 __agg_misc4;
-#if defined(__BIG_ENDIAN)
- u8 __agg_val3_th;
- u8 __agg_val3;
- u16 __agg_misc3;
-#elif defined(__LITTLE_ENDIAN)
- u16 __agg_misc3;
- u8 __agg_val3;
- u8 __agg_val3_th;
-#endif
- u32 __agg_val1;
- u32 __agg_misc4_th;
-#if defined(__BIG_ENDIAN)
- u16 __agg_val2_th;
- u16 __agg_val2;
-#elif defined(__LITTLE_ENDIAN)
- u16 __agg_val2;
- u16 __agg_val2_th;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 __reserved2;
- u8 __decision_rules;
- u8 __decision_rule_enable_bits;
-#elif defined(__LITTLE_ENDIAN)
- u8 __decision_rule_enable_bits;
- u8 __decision_rules;
- u16 __reserved2;
-#endif
+ u32 __reserved3[6];
};
/*
@@ -2022,18 +1999,16 @@ struct timers_block_context {
*/
struct eth_tx_bd_flags {
u8 as_bitfield;
-#define ETH_TX_BD_FLAGS_VLAN_TAG (0x1<<0)
-#define ETH_TX_BD_FLAGS_VLAN_TAG_SHIFT 0
-#define ETH_TX_BD_FLAGS_IP_CSUM (0x1<<1)
-#define ETH_TX_BD_FLAGS_IP_CSUM_SHIFT 1
-#define ETH_TX_BD_FLAGS_L4_CSUM (0x1<<2)
-#define ETH_TX_BD_FLAGS_L4_CSUM_SHIFT 2
-#define ETH_TX_BD_FLAGS_END_BD (0x1<<3)
-#define ETH_TX_BD_FLAGS_END_BD_SHIFT 3
+#define ETH_TX_BD_FLAGS_IP_CSUM (0x1<<0)
+#define ETH_TX_BD_FLAGS_IP_CSUM_SHIFT 0
+#define ETH_TX_BD_FLAGS_L4_CSUM (0x1<<1)
+#define ETH_TX_BD_FLAGS_L4_CSUM_SHIFT 1
+#define ETH_TX_BD_FLAGS_VLAN_MODE (0x3<<2)
+#define ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT 2
#define ETH_TX_BD_FLAGS_START_BD (0x1<<4)
#define ETH_TX_BD_FLAGS_START_BD_SHIFT 4
-#define ETH_TX_BD_FLAGS_HDR_POOL (0x1<<5)
-#define ETH_TX_BD_FLAGS_HDR_POOL_SHIFT 5
+#define ETH_TX_BD_FLAGS_IS_UDP (0x1<<5)
+#define ETH_TX_BD_FLAGS_IS_UDP_SHIFT 5
#define ETH_TX_BD_FLAGS_SW_LSO (0x1<<6)
#define ETH_TX_BD_FLAGS_SW_LSO_SHIFT 6
#define ETH_TX_BD_FLAGS_IPV6 (0x1<<7)
@@ -2048,7 +2023,7 @@ struct eth_tx_start_bd {
__le32 addr_hi;
__le16 nbd;
__le16 nbytes;
- __le16 vlan;
+ __le16 vlan_or_ethertype;
struct eth_tx_bd_flags bd_flags;
u8 general_data;
#define ETH_TX_START_BD_HDR_NBDS (0x3F<<0)
@@ -2061,48 +2036,48 @@ struct eth_tx_start_bd {
* Tx regular BD structure
*/
struct eth_tx_bd {
- u32 addr_lo;
- u32 addr_hi;
- u16 total_pkt_bytes;
- u16 nbytes;
+ __le32 addr_lo;
+ __le32 addr_hi;
+ __le16 total_pkt_bytes;
+ __le16 nbytes;
u8 reserved[4];
};
/*
- * Tx parsing BD structure for ETH,Relevant in START
+ * Tx parsing BD structure for ETH E1/E1h
*/
-struct eth_tx_parse_bd {
+struct eth_tx_parse_bd_e1x {
u8 global_data;
-#define ETH_TX_PARSE_BD_IP_HDR_START_OFFSET (0xF<<0)
-#define ETH_TX_PARSE_BD_IP_HDR_START_OFFSET_SHIFT 0
-#define ETH_TX_PARSE_BD_UDP_CS_FLG (0x1<<4)
-#define ETH_TX_PARSE_BD_UDP_CS_FLG_SHIFT 4
-#define ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN (0x1<<5)
-#define ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN_SHIFT 5
-#define ETH_TX_PARSE_BD_LLC_SNAP_EN (0x1<<6)
-#define ETH_TX_PARSE_BD_LLC_SNAP_EN_SHIFT 6
-#define ETH_TX_PARSE_BD_NS_FLG (0x1<<7)
-#define ETH_TX_PARSE_BD_NS_FLG_SHIFT 7
+#define ETH_TX_PARSE_BD_E1X_IP_HDR_START_OFFSET_W (0xF<<0)
+#define ETH_TX_PARSE_BD_E1X_IP_HDR_START_OFFSET_W_SHIFT 0
+#define ETH_TX_PARSE_BD_E1X_RESERVED0 (0x1<<4)
+#define ETH_TX_PARSE_BD_E1X_RESERVED0_SHIFT 4
+#define ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN (0x1<<5)
+#define ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN_SHIFT 5
+#define ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN (0x1<<6)
+#define ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT 6
+#define ETH_TX_PARSE_BD_E1X_NS_FLG (0x1<<7)
+#define ETH_TX_PARSE_BD_E1X_NS_FLG_SHIFT 7
u8 tcp_flags;
-#define ETH_TX_PARSE_BD_FIN_FLG (0x1<<0)
-#define ETH_TX_PARSE_BD_FIN_FLG_SHIFT 0
-#define ETH_TX_PARSE_BD_SYN_FLG (0x1<<1)
-#define ETH_TX_PARSE_BD_SYN_FLG_SHIFT 1
-#define ETH_TX_PARSE_BD_RST_FLG (0x1<<2)
-#define ETH_TX_PARSE_BD_RST_FLG_SHIFT 2
-#define ETH_TX_PARSE_BD_PSH_FLG (0x1<<3)
-#define ETH_TX_PARSE_BD_PSH_FLG_SHIFT 3
-#define ETH_TX_PARSE_BD_ACK_FLG (0x1<<4)
-#define ETH_TX_PARSE_BD_ACK_FLG_SHIFT 4
-#define ETH_TX_PARSE_BD_URG_FLG (0x1<<5)
-#define ETH_TX_PARSE_BD_URG_FLG_SHIFT 5
-#define ETH_TX_PARSE_BD_ECE_FLG (0x1<<6)
-#define ETH_TX_PARSE_BD_ECE_FLG_SHIFT 6
-#define ETH_TX_PARSE_BD_CWR_FLG (0x1<<7)
-#define ETH_TX_PARSE_BD_CWR_FLG_SHIFT 7
- u8 ip_hlen;
+#define ETH_TX_PARSE_BD_E1X_FIN_FLG (0x1<<0)
+#define ETH_TX_PARSE_BD_E1X_FIN_FLG_SHIFT 0
+#define ETH_TX_PARSE_BD_E1X_SYN_FLG (0x1<<1)
+#define ETH_TX_PARSE_BD_E1X_SYN_FLG_SHIFT 1
+#define ETH_TX_PARSE_BD_E1X_RST_FLG (0x1<<2)
+#define ETH_TX_PARSE_BD_E1X_RST_FLG_SHIFT 2
+#define ETH_TX_PARSE_BD_E1X_PSH_FLG (0x1<<3)
+#define ETH_TX_PARSE_BD_E1X_PSH_FLG_SHIFT 3
+#define ETH_TX_PARSE_BD_E1X_ACK_FLG (0x1<<4)
+#define ETH_TX_PARSE_BD_E1X_ACK_FLG_SHIFT 4
+#define ETH_TX_PARSE_BD_E1X_URG_FLG (0x1<<5)
+#define ETH_TX_PARSE_BD_E1X_URG_FLG_SHIFT 5
+#define ETH_TX_PARSE_BD_E1X_ECE_FLG (0x1<<6)
+#define ETH_TX_PARSE_BD_E1X_ECE_FLG_SHIFT 6
+#define ETH_TX_PARSE_BD_E1X_CWR_FLG (0x1<<7)
+#define ETH_TX_PARSE_BD_E1X_CWR_FLG_SHIFT 7
+ u8 ip_hlen_w;
s8 reserved;
- __le16 total_hlen;
+ __le16 total_hlen_w;
__le16 tcp_pseudo_csum;
__le16 lso_mss;
__le16 ip_id;
@@ -2110,6 +2085,27 @@ struct eth_tx_parse_bd {
};
/*
+ * Tx parsing BD structure for ETH E2
+ */
+struct eth_tx_parse_bd_e2 {
+ __le16 dst_mac_addr_lo;
+ __le16 dst_mac_addr_mid;
+ __le16 dst_mac_addr_hi;
+ __le16 src_mac_addr_lo;
+ __le16 src_mac_addr_mid;
+ __le16 src_mac_addr_hi;
+ __le32 parsing_data;
+#define ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W (0x1FFF<<0)
+#define ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT 0
+#define ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW (0xF<<13)
+#define ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT 13
+#define ETH_TX_PARSE_BD_E2_LSO_MSS (0x3FFF<<17)
+#define ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT 17
+#define ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR (0x1<<31)
+#define ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR_SHIFT 31
+};
+
+/*
* The last BD in the BD memory will hold a pointer to the next BD memory
*/
struct eth_tx_next_bd {
@@ -2124,79 +2120,24 @@ struct eth_tx_next_bd {
union eth_tx_bd_types {
struct eth_tx_start_bd start_bd;
struct eth_tx_bd reg_bd;
- struct eth_tx_parse_bd parse_bd;
+ struct eth_tx_parse_bd_e1x parse_bd_e1x;
+ struct eth_tx_parse_bd_e2 parse_bd_e2;
struct eth_tx_next_bd next_bd;
};
+
/*
* The eth storm context of Xstorm
*/
struct xstorm_eth_st_context {
- u32 tx_bd_page_base_lo;
- u32 tx_bd_page_base_hi;
-#if defined(__BIG_ENDIAN)
- u16 tx_bd_cons;
- u8 statistics_data;
-#define XSTORM_ETH_ST_CONTEXT_STATISTICS_COUNTER_ID (0x7F<<0)
-#define XSTORM_ETH_ST_CONTEXT_STATISTICS_COUNTER_ID_SHIFT 0
-#define XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE (0x1<<7)
-#define XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE_SHIFT 7
- u8 __local_tx_bd_prod;
-#elif defined(__LITTLE_ENDIAN)
- u8 __local_tx_bd_prod;
- u8 statistics_data;
-#define XSTORM_ETH_ST_CONTEXT_STATISTICS_COUNTER_ID (0x7F<<0)
-#define XSTORM_ETH_ST_CONTEXT_STATISTICS_COUNTER_ID_SHIFT 0
-#define XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE (0x1<<7)
-#define XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE_SHIFT 7
- u16 tx_bd_cons;
-#endif
- u32 __reserved1;
- u32 __reserved2;
-#if defined(__BIG_ENDIAN)
- u8 __ram_cache_index;
- u8 __double_buffer_client;
- u16 __pkt_cons;
-#elif defined(__LITTLE_ENDIAN)
- u16 __pkt_cons;
- u8 __double_buffer_client;
- u8 __ram_cache_index;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 __statistics_address;
- u16 __gso_next;
-#elif defined(__LITTLE_ENDIAN)
- u16 __gso_next;
- u16 __statistics_address;
-#endif
-#if defined(__BIG_ENDIAN)
- u8 __local_tx_bd_cons;
- u8 safc_group_num;
- u8 safc_group_en;
- u8 __is_eth_conn;
-#elif defined(__LITTLE_ENDIAN)
- u8 __is_eth_conn;
- u8 safc_group_en;
- u8 safc_group_num;
- u8 __local_tx_bd_cons;
-#endif
- union eth_tx_bd_types __bds[13];
+ u32 reserved0[60];
};
/*
* The eth storm context of Cstorm
*/
struct cstorm_eth_st_context {
-#if defined(__BIG_ENDIAN)
- u16 __reserved0;
- u8 sb_index_number;
- u8 status_block_id;
-#elif defined(__LITTLE_ENDIAN)
- u8 status_block_id;
- u8 sb_index_number;
- u16 __reserved0;
-#endif
- u32 __reserved1[3];
+ u32 __reserved0[4];
};
/*
@@ -2244,103 +2185,114 @@ struct eth_tx_doorbell {
/*
- * cstorm default status block, generated by ustorm
- */
-struct cstorm_def_status_block_u {
- __le16 index_values[HC_USTORM_DEF_SB_NUM_INDICES];
- __le16 status_block_index;
- u8 func;
- u8 status_block_id;
- __le32 __flags;
-};
-
-/*
- * cstorm default status block, generated by cstorm
- */
-struct cstorm_def_status_block_c {
- __le16 index_values[HC_CSTORM_DEF_SB_NUM_INDICES];
- __le16 status_block_index;
- u8 func;
- u8 status_block_id;
- __le32 __flags;
-};
-
-/*
- * xstorm status block
+ * client init fc data
*/
-struct xstorm_def_status_block {
- __le16 index_values[HC_XSTORM_DEF_SB_NUM_INDICES];
- __le16 status_block_index;
- u8 func;
- u8 status_block_id;
- __le32 __flags;
+struct client_init_fc_data {
+ __le16 cqe_pause_thr_low;
+ __le16 cqe_pause_thr_high;
+ __le16 bd_pause_thr_low;
+ __le16 bd_pause_thr_high;
+ __le16 sge_pause_thr_low;
+ __le16 sge_pause_thr_high;
+ __le16 rx_cos_mask;
+ u8 safc_group_num;
+ u8 safc_group_en_flg;
+ u8 traffic_type;
+ u8 reserved0;
+ __le16 reserved1;
+ __le32 reserved2;
};
-/*
- * tstorm status block
- */
-struct tstorm_def_status_block {
- __le16 index_values[HC_TSTORM_DEF_SB_NUM_INDICES];
- __le16 status_block_index;
- u8 func;
- u8 status_block_id;
- __le32 __flags;
-};
/*
- * host status block
+ * client init ramrod data
*/
-struct host_def_status_block {
- struct atten_def_status_block atten_status_block;
- struct cstorm_def_status_block_u u_def_status_block;
- struct cstorm_def_status_block_c c_def_status_block;
- struct xstorm_def_status_block x_def_status_block;
- struct tstorm_def_status_block t_def_status_block;
+struct client_init_general_data {
+ u8 client_id;
+ u8 statistics_counter_id;
+ u8 statistics_en_flg;
+ u8 is_fcoe_flg;
+ u8 activate_flg;
+ u8 sp_client_id;
+ __le16 reserved0;
+ __le32 reserved1[2];
};
/*
- * cstorm status block, generated by ustorm
+ * client init rx data
*/
-struct cstorm_status_block_u {
- __le16 index_values[HC_USTORM_SB_NUM_INDICES];
- __le16 status_block_index;
- u8 func;
+struct client_init_rx_data {
+ u8 tpa_en_flg;
+ u8 vmqueue_mode_en_flg;
+ u8 extra_data_over_sgl_en_flg;
+ u8 cache_line_alignment_log_size;
+ u8 enable_dynamic_hc;
+ u8 max_sges_for_packet;
+ u8 client_qzone_id;
+ u8 drop_ip_cs_err_flg;
+ u8 drop_tcp_cs_err_flg;
+ u8 drop_ttl0_flg;
+ u8 drop_udp_cs_err_flg;
+ u8 inner_vlan_removal_enable_flg;
+ u8 outer_vlan_removal_enable_flg;
u8 status_block_id;
- __le32 __flags;
+ u8 rx_sb_index_number;
+ u8 reserved0[3];
+ __le16 bd_buff_size;
+ __le16 sge_buff_size;
+ __le16 mtu;
+ struct regpair bd_page_base;
+ struct regpair sge_page_base;
+ struct regpair cqe_page_base;
+ u8 is_leading_rss;
+ u8 is_approx_mcast;
+ __le16 max_agg_size;
+ __le32 reserved2[3];
+};
+
+/*
+ * client init tx data
+ */
+struct client_init_tx_data {
+ u8 enforce_security_flg;
+ u8 tx_status_block_id;
+ u8 tx_sb_index_number;
+ u8 reserved0;
+ __le16 mtu;
+ __le16 reserved1;
+ struct regpair tx_bd_page_base;
+ __le32 reserved2[2];
};
/*
- * cstorm status block, generated by cstorm
+ * client init ramrod data
*/
-struct cstorm_status_block_c {
- __le16 index_values[HC_CSTORM_SB_NUM_INDICES];
- __le16 status_block_index;
- u8 func;
- u8 status_block_id;
- __le32 __flags;
+struct client_init_ramrod_data {
+ struct client_init_general_data general;
+ struct client_init_rx_data rx;
+ struct client_init_tx_data tx;
+ struct client_init_fc_data fc;
};
+
/*
- * host status block
+ * The data contain client ID need to the ramrod
*/
-struct host_status_block {
- struct cstorm_status_block_u u_status_block;
- struct cstorm_status_block_c c_status_block;
+struct eth_common_ramrod_data {
+ u32 client_id;
+ u32 reserved1;
};
/*
- * The data for RSS setup ramrod
+ * union for sgl and raw data.
*/
-struct eth_client_setup_ramrod_data {
- u32 client_id;
- u8 is_rdma;
- u8 is_fcoe;
- u16 reserved1;
+union eth_sgl_or_raw_data {
+ __le16 sgl[8];
+ u32 raw_data[4];
};
-
/*
* regular eth FP CQE parameters struct
*/
@@ -2358,8 +2310,8 @@ struct eth_fast_path_rx_cqe {
#define ETH_FAST_PATH_RX_CQE_START_FLG_SHIFT 4
#define ETH_FAST_PATH_RX_CQE_END_FLG (0x1<<5)
#define ETH_FAST_PATH_RX_CQE_END_FLG_SHIFT 5
-#define ETH_FAST_PATH_RX_CQE_RESERVED0 (0x3<<6)
-#define ETH_FAST_PATH_RX_CQE_RESERVED0_SHIFT 6
+#define ETH_FAST_PATH_RX_CQE_SGL_RAW_SEL (0x3<<6)
+#define ETH_FAST_PATH_RX_CQE_SGL_RAW_SEL_SHIFT 6
u8 status_flags;
#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE (0x7<<0)
#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE_SHIFT 0
@@ -2380,7 +2332,7 @@ struct eth_fast_path_rx_cqe {
__le16 pkt_len;
__le16 len_on_bd;
struct parsing_flags pars_flags;
- __le16 sgl[8];
+ union eth_sgl_or_raw_data sgl_or_raw_data;
};
@@ -2392,11 +2344,10 @@ struct eth_halt_ramrod_data {
u32 reserved0;
};
-
/*
* The data for statistics query ramrod
*/
-struct eth_query_ramrod_data {
+struct common_query_ramrod_data {
#if defined(__BIG_ENDIAN)
u8 reserved0;
u8 collect_port;
@@ -2479,9 +2430,9 @@ struct spe_hdr {
__le16 type;
#define SPE_HDR_CONN_TYPE (0xFF<<0)
#define SPE_HDR_CONN_TYPE_SHIFT 0
-#define SPE_HDR_COMMON_RAMROD (0xFF<<8)
-#define SPE_HDR_COMMON_RAMROD_SHIFT 8
- __le16 reserved;
+#define SPE_HDR_FUNCTION_ID (0xFF<<8)
+#define SPE_HDR_FUNCTION_ID_SHIFT 8
+ __le16 reserved1;
};
/*
@@ -2489,12 +2440,10 @@ struct spe_hdr {
*/
union eth_specific_data {
u8 protocol_data[8];
- struct regpair mac_config_addr;
- struct eth_client_setup_ramrod_data client_setup_ramrod_data;
+ struct regpair client_init_ramrod_init_data;
struct eth_halt_ramrod_data halt_ramrod_data;
- struct regpair leading_cqe_addr;
struct regpair update_data_addr;
- struct eth_query_ramrod_data query_ramrod_data;
+ struct eth_common_ramrod_data common_ramrod_data;
};
/*
@@ -2519,7 +2468,7 @@ struct eth_tx_bds_array {
*/
struct tstorm_eth_function_common_config {
#if defined(__BIG_ENDIAN)
- u8 leading_client_id;
+ u8 reserved1;
u8 rss_result_mask;
u16 config_flags;
#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY (0x1<<0)
@@ -2532,16 +2481,12 @@ struct tstorm_eth_function_common_config {
#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY_SHIFT 3
#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_MODE (0x7<<4)
#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_MODE_SHIFT 4
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_DEFAULT_ENABLE (0x1<<7)
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_DEFAULT_ENABLE_SHIFT 7
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_IN_CAM (0x1<<8)
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_IN_CAM_SHIFT 8
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM (0x1<<9)
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM_SHIFT 9
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA (0x1<<10)
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA_SHIFT 10
-#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x1F<<11)
-#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 11
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA (0x1<<7)
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA_SHIFT 7
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_FILTERING_ENABLE (0x1<<8)
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_FILTERING_ENABLE_SHIFT 8
+#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x7F<<9)
+#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 9
#elif defined(__LITTLE_ENDIAN)
u16 config_flags;
#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY (0x1<<0)
@@ -2554,18 +2499,14 @@ struct tstorm_eth_function_common_config {
#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY_SHIFT 3
#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_MODE (0x7<<4)
#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_MODE_SHIFT 4
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_DEFAULT_ENABLE (0x1<<7)
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_DEFAULT_ENABLE_SHIFT 7
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_IN_CAM (0x1<<8)
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_IN_CAM_SHIFT 8
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM (0x1<<9)
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM_SHIFT 9
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA (0x1<<10)
-#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA_SHIFT 10
-#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x1F<<11)
-#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 11
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA (0x1<<7)
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA_SHIFT 7
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_FILTERING_ENABLE (0x1<<8)
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_FILTERING_ENABLE_SHIFT 8
+#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x7F<<9)
+#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 9
u8 rss_result_mask;
- u8 leading_client_id;
+ u8 reserved1;
#endif
u16 vlan_id[2];
};
@@ -2613,90 +2554,42 @@ struct mac_configuration_hdr {
u8 length;
u8 offset;
u16 client_id;
- u32 reserved1;
-};
-
-/*
- * MAC address in list for ramrod
- */
-struct tstorm_cam_entry {
- __le16 lsb_mac_addr;
- __le16 middle_mac_addr;
- __le16 msb_mac_addr;
- __le16 flags;
-#define TSTORM_CAM_ENTRY_PORT_ID (0x1<<0)
-#define TSTORM_CAM_ENTRY_PORT_ID_SHIFT 0
-#define TSTORM_CAM_ENTRY_RSRVVAL0 (0x7<<1)
-#define TSTORM_CAM_ENTRY_RSRVVAL0_SHIFT 1
-#define TSTORM_CAM_ENTRY_RESERVED0 (0xFFF<<4)
-#define TSTORM_CAM_ENTRY_RESERVED0_SHIFT 4
-};
-
-/*
- * MAC filtering: CAM target table entry
- */
-struct tstorm_cam_target_table_entry {
- u8 flags;
-#define TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST (0x1<<0)
-#define TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST_SHIFT 0
-#define TSTORM_CAM_TARGET_TABLE_ENTRY_OVERRIDE_VLAN_REMOVAL (0x1<<1)
-#define TSTORM_CAM_TARGET_TABLE_ENTRY_OVERRIDE_VLAN_REMOVAL_SHIFT 1
-#define TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE (0x1<<2)
-#define TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE_SHIFT 2
-#define TSTORM_CAM_TARGET_TABLE_ENTRY_RDMA_MAC (0x1<<3)
-#define TSTORM_CAM_TARGET_TABLE_ENTRY_RDMA_MAC_SHIFT 3
-#define TSTORM_CAM_TARGET_TABLE_ENTRY_RESERVED0 (0xF<<4)
-#define TSTORM_CAM_TARGET_TABLE_ENTRY_RESERVED0_SHIFT 4
- u8 reserved1;
- u16 vlan_id;
- u32 clients_bit_vector;
+ u16 echo;
+ u16 reserved1;
};
/*
* MAC address in list for ramrod
*/
struct mac_configuration_entry {
- struct tstorm_cam_entry cam_entry;
- struct tstorm_cam_target_table_entry target_table_entry;
-};
-
-/*
- * MAC filtering configuration command
- */
-struct mac_configuration_cmd {
- struct mac_configuration_hdr hdr;
- struct mac_configuration_entry config_table[64];
-};
-
-
-/*
- * MAC address in list for ramrod
- */
-struct mac_configuration_entry_e1h {
__le16 lsb_mac_addr;
__le16 middle_mac_addr;
__le16 msb_mac_addr;
__le16 vlan_id;
- __le16 e1hov_id;
- u8 reserved0;
+ u8 pf_id;
u8 flags;
-#define MAC_CONFIGURATION_ENTRY_E1H_PORT (0x1<<0)
-#define MAC_CONFIGURATION_ENTRY_E1H_PORT_SHIFT 0
-#define MAC_CONFIGURATION_ENTRY_E1H_ACTION_TYPE (0x1<<1)
-#define MAC_CONFIGURATION_ENTRY_E1H_ACTION_TYPE_SHIFT 1
-#define MAC_CONFIGURATION_ENTRY_E1H_RDMA_MAC (0x1<<2)
-#define MAC_CONFIGURATION_ENTRY_E1H_RDMA_MAC_SHIFT 2
-#define MAC_CONFIGURATION_ENTRY_E1H_RESERVED1 (0x1F<<3)
-#define MAC_CONFIGURATION_ENTRY_E1H_RESERVED1_SHIFT 3
+#define MAC_CONFIGURATION_ENTRY_ACTION_TYPE (0x1<<0)
+#define MAC_CONFIGURATION_ENTRY_ACTION_TYPE_SHIFT 0
+#define MAC_CONFIGURATION_ENTRY_RDMA_MAC (0x1<<1)
+#define MAC_CONFIGURATION_ENTRY_RDMA_MAC_SHIFT 1
+#define MAC_CONFIGURATION_ENTRY_VLAN_FILTERING_MODE (0x3<<2)
+#define MAC_CONFIGURATION_ENTRY_VLAN_FILTERING_MODE_SHIFT 2
+#define MAC_CONFIGURATION_ENTRY_OVERRIDE_VLAN_REMOVAL (0x1<<4)
+#define MAC_CONFIGURATION_ENTRY_OVERRIDE_VLAN_REMOVAL_SHIFT 4
+#define MAC_CONFIGURATION_ENTRY_BROADCAST (0x1<<5)
+#define MAC_CONFIGURATION_ENTRY_BROADCAST_SHIFT 5
+#define MAC_CONFIGURATION_ENTRY_RESERVED1 (0x3<<6)
+#define MAC_CONFIGURATION_ENTRY_RESERVED1_SHIFT 6
+ u16 reserved0;
u32 clients_bit_vector;
};
/*
* MAC filtering configuration command
*/
-struct mac_configuration_cmd_e1h {
+struct mac_configuration_cmd {
struct mac_configuration_hdr hdr;
- struct mac_configuration_entry_e1h config_table[32];
+ struct mac_configuration_entry config_table[64];
};
@@ -2709,65 +2602,6 @@ struct tstorm_eth_approximate_match_multicast_filtering {
/*
- * Configuration parameters per client in Tstorm
- */
-struct tstorm_eth_client_config {
-#if defined(__BIG_ENDIAN)
- u8 reserved0;
- u8 statistics_counter_id;
- u16 mtu;
-#elif defined(__LITTLE_ENDIAN)
- u16 mtu;
- u8 statistics_counter_id;
- u8 reserved0;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 drop_flags;
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR (0x1<<0)
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR_SHIFT 0
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR (0x1<<1)
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR_SHIFT 1
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0 (0x1<<2)
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0_SHIFT 2
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR (0x1<<3)
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR_SHIFT 3
-#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED2 (0xFFF<<4)
-#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED2_SHIFT 4
- u16 config_flags;
-#define TSTORM_ETH_CLIENT_CONFIG_VLAN_REM_ENABLE (0x1<<0)
-#define TSTORM_ETH_CLIENT_CONFIG_VLAN_REM_ENABLE_SHIFT 0
-#define TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE (0x1<<1)
-#define TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE_SHIFT 1
-#define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE (0x1<<2)
-#define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE_SHIFT 2
-#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0x1FFF<<3)
-#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 3
-#elif defined(__LITTLE_ENDIAN)
- u16 config_flags;
-#define TSTORM_ETH_CLIENT_CONFIG_VLAN_REM_ENABLE (0x1<<0)
-#define TSTORM_ETH_CLIENT_CONFIG_VLAN_REM_ENABLE_SHIFT 0
-#define TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE (0x1<<1)
-#define TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE_SHIFT 1
-#define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE (0x1<<2)
-#define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE_SHIFT 2
-#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0x1FFF<<3)
-#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 3
- u16 drop_flags;
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR (0x1<<0)
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR_SHIFT 0
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR (0x1<<1)
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR_SHIFT 1
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0 (0x1<<2)
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0_SHIFT 2
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR (0x1<<3)
-#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR_SHIFT 3
-#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED2 (0xFFF<<4)
-#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED2_SHIFT 4
-#endif
-};
-
-
-/*
* MAC filtering configuration parameters per port in Tstorm
*/
struct tstorm_eth_mac_filter_config {
@@ -2777,8 +2611,8 @@ struct tstorm_eth_mac_filter_config {
u32 mcast_accept_all;
u32 bcast_drop_all;
u32 bcast_accept_all;
- u32 strict_vlan;
u32 vlan_filter[2];
+ u32 unmatched_unicast;
u32 reserved;
};
@@ -2801,41 +2635,6 @@ struct tstorm_eth_tpa_exist {
/*
- * rx rings pause data for E1h only
- */
-struct ustorm_eth_rx_pause_data_e1h {
-#if defined(__BIG_ENDIAN)
- u16 bd_thr_low;
- u16 cqe_thr_low;
-#elif defined(__LITTLE_ENDIAN)
- u16 cqe_thr_low;
- u16 bd_thr_low;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 cos;
- u16 sge_thr_low;
-#elif defined(__LITTLE_ENDIAN)
- u16 sge_thr_low;
- u16 cos;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 bd_thr_high;
- u16 cqe_thr_high;
-#elif defined(__LITTLE_ENDIAN)
- u16 cqe_thr_high;
- u16 bd_thr_high;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 reserved0;
- u16 sge_thr_high;
-#elif defined(__LITTLE_ENDIAN)
- u16 sge_thr_high;
- u16 reserved0;
-#endif
-};
-
-
-/*
* Three RX producers for ETH
*/
struct ustorm_eth_rx_producers {
@@ -2857,6 +2656,18 @@ struct ustorm_eth_rx_producers {
/*
+ * cfc delete event data
+ */
+struct cfc_del_event_data {
+ u32 cid;
+ u8 error;
+ u8 reserved0;
+ u16 reserved1;
+ u32 reserved2;
+};
+
+
+/*
* per-port SAFC demo variables
*/
struct cmng_flags_per_port {
@@ -2872,8 +2683,10 @@ struct cmng_flags_per_port {
#define CMNG_FLAGS_PER_PORT_RATE_SHAPING_PROTOCOL_SHIFT 3
#define CMNG_FLAGS_PER_PORT_FAIRNESS_COS (0x1<<4)
#define CMNG_FLAGS_PER_PORT_FAIRNESS_COS_SHIFT 4
-#define __CMNG_FLAGS_PER_PORT_RESERVED0 (0x7FFFFFF<<5)
-#define __CMNG_FLAGS_PER_PORT_RESERVED0_SHIFT 5
+#define CMNG_FLAGS_PER_PORT_FAIRNESS_COS_MODE (0x1<<5)
+#define CMNG_FLAGS_PER_PORT_FAIRNESS_COS_MODE_SHIFT 5
+#define __CMNG_FLAGS_PER_PORT_RESERVED0 (0x3FFFFFF<<6)
+#define __CMNG_FLAGS_PER_PORT_RESERVED0_SHIFT 6
};
@@ -2907,30 +2720,92 @@ struct safc_struct_per_port {
u8 __reserved0;
u16 __reserved1;
#endif
+ u8 cos_to_traffic_types[MAX_COS_NUMBER];
+ u32 __reserved2;
u16 cos_to_pause_mask[NUM_OF_SAFC_BITS];
};
/*
+ * per-port PFC variables
+ */
+struct pfc_struct_per_port {
+ u8 priority_to_traffic_types[MAX_PFC_PRIORITIES];
+#if defined(__BIG_ENDIAN)
+ u16 pfc_pause_quanta_in_nanosec;
+ u8 __reserved0;
+ u8 priority_non_pausable_mask;
+#elif defined(__LITTLE_ENDIAN)
+ u8 priority_non_pausable_mask;
+ u8 __reserved0;
+ u16 pfc_pause_quanta_in_nanosec;
+#endif
+};
+
+/*
+ * Priority and cos
+ */
+struct priority_cos {
+#if defined(__BIG_ENDIAN)
+ u16 reserved1;
+ u8 cos;
+ u8 priority;
+#elif defined(__LITTLE_ENDIAN)
+ u8 priority;
+ u8 cos;
+ u16 reserved1;
+#endif
+ u32 reserved2;
+};
+
+/*
* Per-port congestion management variables
*/
struct cmng_struct_per_port {
struct rate_shaping_vars_per_port rs_vars;
struct fairness_vars_per_port fair_vars;
struct safc_struct_per_port safc_vars;
+ struct pfc_struct_per_port pfc_vars;
+#if defined(__BIG_ENDIAN)
+ u16 __reserved1;
+ u8 dcb_enabled;
+ u8 llfc_mode;
+#elif defined(__LITTLE_ENDIAN)
+ u8 llfc_mode;
+ u8 dcb_enabled;
+ u16 __reserved1;
+#endif
+ struct priority_cos
+ traffic_type_to_priority_cos[MAX_PFC_TRAFFIC_TYPES];
struct cmng_flags_per_port flags;
};
+
+/*
+ * Dynamic HC counters set by the driver
+ */
+struct hc_dynamic_drv_counter {
+ u32 val[HC_SB_MAX_DYNAMIC_INDICES];
+};
+
+/*
+ * zone A per-queue data
+ */
+struct cstorm_queue_zone_data {
+ struct hc_dynamic_drv_counter hc_dyn_drv_cnt;
+ struct regpair reserved[2];
+};
+
/*
* Dynamic host coalescing init parameters
*/
struct dynamic_hc_config {
u32 threshold[3];
- u8 shift_per_protocol[HC_USTORM_SB_NUM_INDICES];
- u8 hc_timeout0[HC_USTORM_SB_NUM_INDICES];
- u8 hc_timeout1[HC_USTORM_SB_NUM_INDICES];
- u8 hc_timeout2[HC_USTORM_SB_NUM_INDICES];
- u8 hc_timeout3[HC_USTORM_SB_NUM_INDICES];
+ u8 shift_per_protocol[HC_SB_MAX_DYNAMIC_INDICES];
+ u8 hc_timeout0[HC_SB_MAX_DYNAMIC_INDICES];
+ u8 hc_timeout1[HC_SB_MAX_DYNAMIC_INDICES];
+ u8 hc_timeout2[HC_SB_MAX_DYNAMIC_INDICES];
+ u8 hc_timeout3[HC_SB_MAX_DYNAMIC_INDICES];
};
@@ -2954,7 +2829,7 @@ struct xstorm_per_client_stats {
* Common statistics collected by the Xstorm (per port)
*/
struct xstorm_common_stats {
- struct xstorm_per_client_stats client_statistics[MAX_X_STAT_COUNTER_ID];
+ struct xstorm_per_client_stats client_statistics[MAX_STAT_COUNTER_ID];
};
/*
@@ -2991,7 +2866,7 @@ struct tstorm_per_client_stats {
*/
struct tstorm_common_stats {
struct tstorm_per_port_stats port_statistics;
- struct tstorm_per_client_stats client_statistics[MAX_T_STAT_COUNTER_ID];
+ struct tstorm_per_client_stats client_statistics[MAX_STAT_COUNTER_ID];
};
/*
@@ -3012,7 +2887,7 @@ struct ustorm_per_client_stats {
* Protocol-common statistics collected by the Ustorm
*/
struct ustorm_common_stats {
- struct ustorm_per_client_stats client_statistics[MAX_U_STAT_COUNTER_ID];
+ struct ustorm_per_client_stats client_statistics[MAX_STAT_COUNTER_ID];
};
/*
@@ -3026,6 +2901,70 @@ struct eth_stats_query {
/*
+ * set mac event data
+ */
+struct set_mac_event_data {
+ u16 echo;
+ u16 reserved0;
+ u32 reserved1;
+ u32 reserved2;
+};
+
+/*
+ * union for all event ring message types
+ */
+union event_data {
+ struct set_mac_event_data set_mac_event;
+ struct cfc_del_event_data cfc_del_event;
+};
+
+
+/*
+ * per PF event ring data
+ */
+struct event_ring_data {
+ struct regpair base_addr;
+#if defined(__BIG_ENDIAN)
+ u8 index_id;
+ u8 sb_id;
+ u16 producer;
+#elif defined(__LITTLE_ENDIAN)
+ u16 producer;
+ u8 sb_id;
+ u8 index_id;
+#endif
+ u32 reserved0;
+};
+
+
+/*
+ * event ring message element (each element is 128 bits)
+ */
+struct event_ring_msg {
+ u8 opcode;
+ u8 reserved0;
+ u16 reserved1;
+ union event_data data;
+};
+
+/*
+ * event ring next page element (128 bits)
+ */
+struct event_ring_next {
+ struct regpair addr;
+ u32 reserved[2];
+};
+
+/*
+ * union for event ring element types (each element is 128 bits)
+ */
+union event_ring_elem {
+ struct event_ring_msg message;
+ struct event_ring_next next_page;
+};
+
+
+/*
* per-vnic fairness variables
*/
struct fairness_vars_per_vn {
@@ -3064,6 +3003,137 @@ struct fw_version {
/*
+ * Dynamic Host-Coalescing - Driver(host) counters
+ */
+struct hc_dynamic_sb_drv_counters {
+ u32 dynamic_hc_drv_counter[HC_SB_MAX_DYNAMIC_INDICES];
+};
+
+
+/*
+ * 2 bytes. configuration/state parameters for a single protocol index
+ */
+struct hc_index_data {
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define HC_INDEX_DATA_SM_ID (0x1<<0)
+#define HC_INDEX_DATA_SM_ID_SHIFT 0
+#define HC_INDEX_DATA_HC_ENABLED (0x1<<1)
+#define HC_INDEX_DATA_HC_ENABLED_SHIFT 1
+#define HC_INDEX_DATA_DYNAMIC_HC_ENABLED (0x1<<2)
+#define HC_INDEX_DATA_DYNAMIC_HC_ENABLED_SHIFT 2
+#define HC_INDEX_DATA_RESERVE (0x1F<<3)
+#define HC_INDEX_DATA_RESERVE_SHIFT 3
+ u8 timeout;
+#elif defined(__LITTLE_ENDIAN)
+ u8 timeout;
+ u8 flags;
+#define HC_INDEX_DATA_SM_ID (0x1<<0)
+#define HC_INDEX_DATA_SM_ID_SHIFT 0
+#define HC_INDEX_DATA_HC_ENABLED (0x1<<1)
+#define HC_INDEX_DATA_HC_ENABLED_SHIFT 1
+#define HC_INDEX_DATA_DYNAMIC_HC_ENABLED (0x1<<2)
+#define HC_INDEX_DATA_DYNAMIC_HC_ENABLED_SHIFT 2
+#define HC_INDEX_DATA_RESERVE (0x1F<<3)
+#define HC_INDEX_DATA_RESERVE_SHIFT 3
+#endif
+};
+
+
+/*
+ * HC state-machine
+ */
+struct hc_status_block_sm {
+#if defined(__BIG_ENDIAN)
+ u8 igu_seg_id;
+ u8 igu_sb_id;
+ u8 timer_value;
+ u8 __flags;
+#elif defined(__LITTLE_ENDIAN)
+ u8 __flags;
+ u8 timer_value;
+ u8 igu_sb_id;
+ u8 igu_seg_id;
+#endif
+ u32 time_to_expire;
+};
+
+/*
+ * hold PCI identification variables- used in various places in firmware
+ */
+struct pci_entity {
+#if defined(__BIG_ENDIAN)
+ u8 vf_valid;
+ u8 vf_id;
+ u8 vnic_id;
+ u8 pf_id;
+#elif defined(__LITTLE_ENDIAN)
+ u8 pf_id;
+ u8 vnic_id;
+ u8 vf_id;
+ u8 vf_valid;
+#endif
+};
+
+/*
+ * The fast-path status block meta-data, common to all chips
+ */
+struct hc_sb_data {
+ struct regpair host_sb_addr;
+ struct hc_status_block_sm state_machine[HC_SB_MAX_SM];
+ struct pci_entity p_func;
+#if defined(__BIG_ENDIAN)
+ u8 rsrv0;
+ u8 dhc_qzone_id;
+ u8 __dynamic_hc_level;
+ u8 same_igu_sb_1b;
+#elif defined(__LITTLE_ENDIAN)
+ u8 same_igu_sb_1b;
+ u8 __dynamic_hc_level;
+ u8 dhc_qzone_id;
+ u8 rsrv0;
+#endif
+ struct regpair rsrv1[2];
+};
+
+
+/*
+ * The fast-path status block meta-data
+ */
+struct hc_sp_status_block_data {
+ struct regpair host_sb_addr;
+#if defined(__BIG_ENDIAN)
+ u16 rsrv;
+ u8 igu_seg_id;
+ u8 igu_sb_id;
+#elif defined(__LITTLE_ENDIAN)
+ u8 igu_sb_id;
+ u8 igu_seg_id;
+ u16 rsrv;
+#endif
+ struct pci_entity p_func;
+};
+
+
+/*
+ * The fast-path status block meta-data
+ */
+struct hc_status_block_data_e1x {
+ struct hc_index_data index_data[HC_SB_MAX_INDICES_E1X];
+ struct hc_sb_data common;
+};
+
+
+/*
+ * The fast-path status block meta-data
+ */
+struct hc_status_block_data_e2 {
+ struct hc_index_data index_data[HC_SB_MAX_INDICES_E2];
+ struct hc_sb_data common;
+};
+
+
+/*
* FW version stored in first line of pram
*/
struct pram_fw_version {
@@ -3086,11 +3156,21 @@ struct pram_fw_version {
/*
+ * Ethernet slow path element
+ */
+union protocol_common_specific_data {
+ u8 protocol_data[8];
+ struct regpair phy_address;
+ struct regpair mac_config_addr;
+ struct common_query_ramrod_data query_ramrod_data;
+};
+
+/*
* The send queue element
*/
struct protocol_common_spe {
struct spe_hdr hdr;
- struct regpair phy_address;
+ union protocol_common_specific_data data;
};
@@ -3123,7 +3203,7 @@ struct rate_shaping_vars_per_vn {
*/
struct slow_path_element {
struct spe_hdr hdr;
- u8 protocol_data[8];
+ struct regpair protocol_data;
};
@@ -3136,3 +3216,97 @@ struct stats_indication_flags {
};
+/*
+ * per-port PFC variables
+ */
+struct storm_pfc_struct_per_port {
+#if defined(__BIG_ENDIAN)
+ u16 mid_mac_addr;
+ u16 msb_mac_addr;
+#elif defined(__LITTLE_ENDIAN)
+ u16 msb_mac_addr;
+ u16 mid_mac_addr;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 pfc_pause_quanta_in_nanosec;
+ u16 lsb_mac_addr;
+#elif defined(__LITTLE_ENDIAN)
+ u16 lsb_mac_addr;
+ u16 pfc_pause_quanta_in_nanosec;
+#endif
+};
+
+/*
+ * Per-port congestion management variables
+ */
+struct storm_cmng_struct_per_port {
+ struct storm_pfc_struct_per_port pfc_vars;
+};
+
+
+/*
+ * zone A per-queue data
+ */
+struct tstorm_queue_zone_data {
+ struct regpair reserved[4];
+};
+
+
+/*
+ * zone B per-VF data
+ */
+struct tstorm_vf_zone_data {
+ struct regpair reserved;
+};
+
+
+/*
+ * zone A per-queue data
+ */
+struct ustorm_queue_zone_data {
+ struct ustorm_eth_rx_producers eth_rx_producers;
+ struct regpair reserved[3];
+};
+
+
+/*
+ * zone B per-VF data
+ */
+struct ustorm_vf_zone_data {
+ struct regpair reserved;
+};
+
+
+/*
+ * data per VF-PF channel
+ */
+struct vf_pf_channel_data {
+#if defined(__BIG_ENDIAN)
+ u16 reserved0;
+ u8 valid;
+ u8 state;
+#elif defined(__LITTLE_ENDIAN)
+ u8 state;
+ u8 valid;
+ u16 reserved0;
+#endif
+ u32 reserved1;
+};
+
+
+/*
+ * zone A per-queue data
+ */
+struct xstorm_queue_zone_data {
+ struct regpair reserved[4];
+};
+
+
+/*
+ * zone B per-VF data
+ */
+struct xstorm_vf_zone_data {
+ struct regpair reserved;
+};
+
+#endif /* BNX2X_HSI_H */
diff --git a/drivers/net/bnx2x/bnx2x_init.h b/drivers/net/bnx2x/bnx2x_init.h
index 65b26cbfe3e7..a9d54874a559 100644
--- a/drivers/net/bnx2x/bnx2x_init.h
+++ b/drivers/net/bnx2x/bnx2x_init.h
@@ -97,6 +97,9 @@
#define MISC_AEU_BLOCK 35
#define PGLUE_B_BLOCK 36
#define IGU_BLOCK 37
+#define ATC_BLOCK 38
+#define QM_4PORT_BLOCK 39
+#define XSEM_4PORT_BLOCK 40
/* Returns the index of start or end of a specific block stage in ops array*/
@@ -148,5 +151,46 @@ union init_op {
struct raw_op raw;
};
+#define INITOP_SET 0 /* set the HW directly */
+#define INITOP_CLEAR 1 /* clear the HW directly */
+#define INITOP_INIT 2 /* set the init-value array */
+
+/****************************************************************************
+* ILT management
+****************************************************************************/
+struct ilt_line {
+ dma_addr_t page_mapping;
+ void *page;
+ u32 size;
+};
+
+struct ilt_client_info {
+ u32 page_size;
+ u16 start;
+ u16 end;
+ u16 client_num;
+ u16 flags;
+#define ILT_CLIENT_SKIP_INIT 0x1
+#define ILT_CLIENT_SKIP_MEM 0x2
+};
+
+struct bnx2x_ilt {
+ u32 start_line;
+ struct ilt_line *lines;
+ struct ilt_client_info clients[4];
+#define ILT_CLIENT_CDU 0
+#define ILT_CLIENT_QM 1
+#define ILT_CLIENT_SRC 2
+#define ILT_CLIENT_TM 3
+};
+
+/****************************************************************************
+* SRC configuration
+****************************************************************************/
+struct src_ent {
+ u8 opaque[56];
+ u64 next;
+};
+
#endif /* BNX2X_INIT_H */
diff --git a/drivers/net/bnx2x/bnx2x_init_ops.h b/drivers/net/bnx2x/bnx2x_init_ops.h
index 2b1363a6fe78..a306b0e46b61 100644
--- a/drivers/net/bnx2x/bnx2x_init_ops.h
+++ b/drivers/net/bnx2x/bnx2x_init_ops.h
@@ -16,7 +16,9 @@
#define BNX2X_INIT_OPS_H
static int bnx2x_gunzip(struct bnx2x *bp, const u8 *zbuf, int len);
-
+static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val);
+static void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
+ u32 addr, u32 len);
static void bnx2x_init_str_wr(struct bnx2x *bp, u32 addr, const u32 *data,
u32 len)
@@ -151,6 +153,15 @@ static void bnx2x_init_wr_wb(struct bnx2x *bp, u32 addr, const u32 *data,
bnx2x_init_ind_wr(bp, addr, data, len);
}
+static void bnx2x_wr_64(struct bnx2x *bp, u32 reg, u32 val_lo, u32 val_hi)
+{
+ u32 wb_write[2];
+
+ wb_write[0] = val_lo;
+ wb_write[1] = val_hi;
+ REG_WR_DMAE_LEN(bp, reg, wb_write, 2);
+}
+
static void bnx2x_init_wr_zp(struct bnx2x *bp, u32 addr, u32 len, u32 blob_off)
{
const u8 *data = NULL;
@@ -477,18 +488,30 @@ static void bnx2x_init_pxp_arb(struct bnx2x *bp, int r_order, int w_order)
REG_WR(bp, PXP2_REG_RQ_RD_MBS0, r_order);
REG_WR(bp, PXP2_REG_RQ_RD_MBS1, r_order);
- if (r_order == MAX_RD_ORD)
+ if ((CHIP_IS_E1(bp) || CHIP_IS_E1H(bp)) && (r_order == MAX_RD_ORD))
REG_WR(bp, PXP2_REG_RQ_PDR_LIMIT, 0xe00);
- REG_WR(bp, PXP2_REG_WR_USDMDP_TH, (0x18 << w_order));
+ if (CHIP_IS_E2(bp))
+ REG_WR(bp, PXP2_REG_WR_USDMDP_TH, (0x8 << w_order));
+ else
+ REG_WR(bp, PXP2_REG_WR_USDMDP_TH, (0x18 << w_order));
- if (CHIP_IS_E1H(bp)) {
+ if (CHIP_IS_E1H(bp) || CHIP_IS_E2(bp)) {
/* MPS w_order optimal TH presently TH
* 128 0 0 2
* 256 1 1 3
* >=512 2 2 3
*/
- val = ((w_order == 0) ? 2 : 3);
+ /* DMAE is special */
+ if (CHIP_IS_E2(bp)) {
+ /* E2 can use optimal TH */
+ val = w_order;
+ REG_WR(bp, PXP2_REG_WR_DMAE_MPS, val);
+ } else {
+ val = ((w_order == 0) ? 2 : 3);
+ REG_WR(bp, PXP2_REG_WR_DMAE_MPS, 2);
+ }
+
REG_WR(bp, PXP2_REG_WR_HC_MPS, val);
REG_WR(bp, PXP2_REG_WR_USDM_MPS, val);
REG_WR(bp, PXP2_REG_WR_CSDM_MPS, val);
@@ -498,9 +521,346 @@ static void bnx2x_init_pxp_arb(struct bnx2x *bp, int r_order, int w_order)
REG_WR(bp, PXP2_REG_WR_TM_MPS, val);
REG_WR(bp, PXP2_REG_WR_SRC_MPS, val);
REG_WR(bp, PXP2_REG_WR_DBG_MPS, val);
- REG_WR(bp, PXP2_REG_WR_DMAE_MPS, 2); /* DMAE is special */
REG_WR(bp, PXP2_REG_WR_CDU_MPS, val);
}
+
+ /* Validate number of tags suppoted by device */
+#define PCIE_REG_PCIER_TL_HDR_FC_ST 0x2980
+ val = REG_RD(bp, PCIE_REG_PCIER_TL_HDR_FC_ST);
+ val &= 0xFF;
+ if (val <= 0x20)
+ REG_WR(bp, PXP2_REG_PGL_TAGS_LIMIT, 0x20);
+}
+
+/****************************************************************************
+* ILT management
+****************************************************************************/
+/*
+ * This codes hides the low level HW interaction for ILT management and
+ * configuration. The API consists of a shadow ILT table which is set by the
+ * driver and a set of routines to use it to configure the HW.
+ *
+ */
+
+/* ILT HW init operations */
+
+/* ILT memory management operations */
+#define ILT_MEMOP_ALLOC 0
+#define ILT_MEMOP_FREE 1
+
+/* the phys address is shifted right 12 bits and has an added
+ * 1=valid bit added to the 53rd bit
+ * then since this is a wide register(TM)
+ * we split it into two 32 bit writes
+ */
+#define ILT_ADDR1(x) ((u32)(((u64)x >> 12) & 0xFFFFFFFF))
+#define ILT_ADDR2(x) ((u32)((1 << 20) | ((u64)x >> 44)))
+#define ILT_RANGE(f, l) (((l) << 10) | f)
+
+static int bnx2x_ilt_line_mem_op(struct bnx2x *bp, struct ilt_line *line,
+ u32 size, u8 memop)
+{
+ if (memop == ILT_MEMOP_FREE) {
+ BNX2X_ILT_FREE(line->page, line->page_mapping, line->size);
+ return 0;
+ }
+ BNX2X_ILT_ZALLOC(line->page, &line->page_mapping, size);
+ if (!line->page)
+ return -1;
+ line->size = size;
+ return 0;
+}
+
+
+static int bnx2x_ilt_client_mem_op(struct bnx2x *bp, int cli_num, u8 memop)
+{
+ int i, rc;
+ struct bnx2x_ilt *ilt = BP_ILT(bp);
+ struct ilt_client_info *ilt_cli = &ilt->clients[cli_num];
+
+ if (!ilt || !ilt->lines)
+ return -1;
+
+ if (ilt_cli->flags & (ILT_CLIENT_SKIP_INIT | ILT_CLIENT_SKIP_MEM))
+ return 0;
+
+ for (rc = 0, i = ilt_cli->start; i <= ilt_cli->end && !rc; i++) {
+ rc = bnx2x_ilt_line_mem_op(bp, &ilt->lines[i],
+ ilt_cli->page_size, memop);
+ }
+ return rc;
+}
+
+static int bnx2x_ilt_mem_op(struct bnx2x *bp, u8 memop)
+{
+ int rc = bnx2x_ilt_client_mem_op(bp, ILT_CLIENT_CDU, memop);
+ if (!rc)
+ rc = bnx2x_ilt_client_mem_op(bp, ILT_CLIENT_QM, memop);
+ if (!rc)
+ rc = bnx2x_ilt_client_mem_op(bp, ILT_CLIENT_SRC, memop);
+ if (!rc)
+ rc = bnx2x_ilt_client_mem_op(bp, ILT_CLIENT_TM, memop);
+
+ return rc;
+}
+
+static void bnx2x_ilt_line_wr(struct bnx2x *bp, int abs_idx,
+ dma_addr_t page_mapping)
+{
+ u32 reg;
+
+ if (CHIP_IS_E1(bp))
+ reg = PXP2_REG_RQ_ONCHIP_AT + abs_idx*8;
+ else
+ reg = PXP2_REG_RQ_ONCHIP_AT_B0 + abs_idx*8;
+
+ bnx2x_wr_64(bp, reg, ILT_ADDR1(page_mapping), ILT_ADDR2(page_mapping));
+}
+
+static void bnx2x_ilt_line_init_op(struct bnx2x *bp, struct bnx2x_ilt *ilt,
+ int idx, u8 initop)
+{
+ dma_addr_t null_mapping;
+ int abs_idx = ilt->start_line + idx;
+
+
+ switch (initop) {
+ case INITOP_INIT:
+ /* set in the init-value array */
+ case INITOP_SET:
+ bnx2x_ilt_line_wr(bp, abs_idx, ilt->lines[idx].page_mapping);
+ break;
+ case INITOP_CLEAR:
+ null_mapping = 0;
+ bnx2x_ilt_line_wr(bp, abs_idx, null_mapping);
+ break;
+ }
+}
+
+static void bnx2x_ilt_boundry_init_op(struct bnx2x *bp,
+ struct ilt_client_info *ilt_cli,
+ u32 ilt_start, u8 initop)
+{
+ u32 start_reg = 0;
+ u32 end_reg = 0;
+
+ /* The boundary is either SET or INIT,
+ CLEAR => SET and for now SET ~~ INIT */
+
+ /* find the appropriate regs */
+ if (CHIP_IS_E1(bp)) {
+ switch (ilt_cli->client_num) {
+ case ILT_CLIENT_CDU:
+ start_reg = PXP2_REG_PSWRQ_CDU0_L2P;
+ break;
+ case ILT_CLIENT_QM:
+ start_reg = PXP2_REG_PSWRQ_QM0_L2P;
+ break;
+ case ILT_CLIENT_SRC:
+ start_reg = PXP2_REG_PSWRQ_SRC0_L2P;
+ break;
+ case ILT_CLIENT_TM:
+ start_reg = PXP2_REG_PSWRQ_TM0_L2P;
+ break;
+ }
+ REG_WR(bp, start_reg + BP_FUNC(bp)*4,
+ ILT_RANGE((ilt_start + ilt_cli->start),
+ (ilt_start + ilt_cli->end)));
+ } else {
+ switch (ilt_cli->client_num) {
+ case ILT_CLIENT_CDU:
+ start_reg = PXP2_REG_RQ_CDU_FIRST_ILT;
+ end_reg = PXP2_REG_RQ_CDU_LAST_ILT;
+ break;
+ case ILT_CLIENT_QM:
+ start_reg = PXP2_REG_RQ_QM_FIRST_ILT;
+ end_reg = PXP2_REG_RQ_QM_LAST_ILT;
+ break;
+ case ILT_CLIENT_SRC:
+ start_reg = PXP2_REG_RQ_SRC_FIRST_ILT;
+ end_reg = PXP2_REG_RQ_SRC_LAST_ILT;
+ break;
+ case ILT_CLIENT_TM:
+ start_reg = PXP2_REG_RQ_TM_FIRST_ILT;
+ end_reg = PXP2_REG_RQ_TM_LAST_ILT;
+ break;
+ }
+ REG_WR(bp, start_reg, (ilt_start + ilt_cli->start));
+ REG_WR(bp, end_reg, (ilt_start + ilt_cli->end));
+ }
+}
+
+static void bnx2x_ilt_client_init_op_ilt(struct bnx2x *bp,
+ struct bnx2x_ilt *ilt,
+ struct ilt_client_info *ilt_cli,
+ u8 initop)
+{
+ int i;
+
+ if (ilt_cli->flags & ILT_CLIENT_SKIP_INIT)
+ return;
+
+ for (i = ilt_cli->start; i <= ilt_cli->end; i++)
+ bnx2x_ilt_line_init_op(bp, ilt, i, initop);
+
+ /* init/clear the ILT boundries */
+ bnx2x_ilt_boundry_init_op(bp, ilt_cli, ilt->start_line, initop);
+}
+
+static void bnx2x_ilt_client_init_op(struct bnx2x *bp,
+ struct ilt_client_info *ilt_cli, u8 initop)
+{
+ struct bnx2x_ilt *ilt = BP_ILT(bp);
+
+ bnx2x_ilt_client_init_op_ilt(bp, ilt, ilt_cli, initop);
+}
+
+static void bnx2x_ilt_client_id_init_op(struct bnx2x *bp,
+ int cli_num, u8 initop)
+{
+ struct bnx2x_ilt *ilt = BP_ILT(bp);
+ struct ilt_client_info *ilt_cli = &ilt->clients[cli_num];
+
+ bnx2x_ilt_client_init_op(bp, ilt_cli, initop);
+}
+
+static void bnx2x_ilt_init_op(struct bnx2x *bp, u8 initop)
+{
+ bnx2x_ilt_client_id_init_op(bp, ILT_CLIENT_CDU, initop);
+ bnx2x_ilt_client_id_init_op(bp, ILT_CLIENT_QM, initop);
+ bnx2x_ilt_client_id_init_op(bp, ILT_CLIENT_SRC, initop);
+ bnx2x_ilt_client_id_init_op(bp, ILT_CLIENT_TM, initop);
+}
+
+static void bnx2x_ilt_init_client_psz(struct bnx2x *bp, int cli_num,
+ u32 psz_reg, u8 initop)
+{
+ struct bnx2x_ilt *ilt = BP_ILT(bp);
+ struct ilt_client_info *ilt_cli = &ilt->clients[cli_num];
+
+ if (ilt_cli->flags & ILT_CLIENT_SKIP_INIT)
+ return;
+
+ switch (initop) {
+ case INITOP_INIT:
+ /* set in the init-value array */
+ case INITOP_SET:
+ REG_WR(bp, psz_reg, ILOG2(ilt_cli->page_size >> 12));
+ break;
+ case INITOP_CLEAR:
+ break;
+ }
+}
+
+/*
+ * called during init common stage, ilt clients should be initialized
+ * prioir to calling this function
+ */
+static void bnx2x_ilt_init_page_size(struct bnx2x *bp, u8 initop)
+{
+ bnx2x_ilt_init_client_psz(bp, ILT_CLIENT_CDU,
+ PXP2_REG_RQ_CDU_P_SIZE, initop);
+ bnx2x_ilt_init_client_psz(bp, ILT_CLIENT_QM,
+ PXP2_REG_RQ_QM_P_SIZE, initop);
+ bnx2x_ilt_init_client_psz(bp, ILT_CLIENT_SRC,
+ PXP2_REG_RQ_SRC_P_SIZE, initop);
+ bnx2x_ilt_init_client_psz(bp, ILT_CLIENT_TM,
+ PXP2_REG_RQ_TM_P_SIZE, initop);
+}
+
+/****************************************************************************
+* QM initializations
+****************************************************************************/
+#define QM_QUEUES_PER_FUNC 16 /* E1 has 32, but only 16 are used */
+#define QM_INIT_MIN_CID_COUNT 31
+#define QM_INIT(cid_cnt) (cid_cnt > QM_INIT_MIN_CID_COUNT)
+
+/* called during init port stage */
+static void bnx2x_qm_init_cid_count(struct bnx2x *bp, int qm_cid_count,
+ u8 initop)
+{
+ int port = BP_PORT(bp);
+
+ if (QM_INIT(qm_cid_count)) {
+ switch (initop) {
+ case INITOP_INIT:
+ /* set in the init-value array */
+ case INITOP_SET:
+ REG_WR(bp, QM_REG_CONNNUM_0 + port*4,
+ qm_cid_count/16 - 1);
+ break;
+ case INITOP_CLEAR:
+ break;
+ }
+ }
+}
+
+static void bnx2x_qm_set_ptr_table(struct bnx2x *bp, int qm_cid_count)
+{
+ int i;
+ u32 wb_data[2];
+
+ wb_data[0] = wb_data[1] = 0;
+
+ for (i = 0; i < 4 * QM_QUEUES_PER_FUNC; i++) {
+ REG_WR(bp, QM_REG_BASEADDR + i*4,
+ qm_cid_count * 4 * (i % QM_QUEUES_PER_FUNC));
+ bnx2x_init_ind_wr(bp, QM_REG_PTRTBL + i*8,
+ wb_data, 2);
+
+ if (CHIP_IS_E1H(bp)) {
+ REG_WR(bp, QM_REG_BASEADDR_EXT_A + i*4,
+ qm_cid_count * 4 * (i % QM_QUEUES_PER_FUNC));
+ bnx2x_init_ind_wr(bp, QM_REG_PTRTBL_EXT_A + i*8,
+ wb_data, 2);
+ }
+ }
+}
+
+/* called during init common stage */
+static void bnx2x_qm_init_ptr_table(struct bnx2x *bp, int qm_cid_count,
+ u8 initop)
+{
+ if (!QM_INIT(qm_cid_count))
+ return;
+
+ switch (initop) {
+ case INITOP_INIT:
+ /* set in the init-value array */
+ case INITOP_SET:
+ bnx2x_qm_set_ptr_table(bp, qm_cid_count);
+ break;
+ case INITOP_CLEAR:
+ break;
+ }
+}
+
+/****************************************************************************
+* SRC initializations
+****************************************************************************/
+
+/* called during init func stage */
+static void bnx2x_src_init_t2(struct bnx2x *bp, struct src_ent *t2,
+ dma_addr_t t2_mapping, int src_cid_count)
+{
+ int i;
+ int port = BP_PORT(bp);
+
+ /* Initialize T2 */
+ for (i = 0; i < src_cid_count-1; i++)
+ t2[i].next = (u64)(t2_mapping + (i+1)*sizeof(struct src_ent));
+
+ /* tell the searcher where the T2 table is */
+ REG_WR(bp, SRC_REG_COUNTFREE0 + port*4, src_cid_count);
+
+ bnx2x_wr_64(bp, SRC_REG_FIRSTFREE0 + port*16,
+ U64_LO(t2_mapping), U64_HI(t2_mapping));
+
+ bnx2x_wr_64(bp, SRC_REG_LASTFREE0 + port*16,
+ U64_LO((u64)t2_mapping +
+ (src_cid_count-1) * sizeof(struct src_ent)),
+ U64_HI((u64)t2_mapping +
+ (src_cid_count-1) * sizeof(struct src_ent)));
}
#endif /* BNX2X_INIT_OPS_H */
diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c
index 0383e3066313..2326774df843 100644
--- a/drivers/net/bnx2x/bnx2x_link.c
+++ b/drivers/net/bnx2x/bnx2x_link.c
@@ -28,7 +28,7 @@
/********************************************************/
#define ETH_HLEN 14
-#define ETH_OVREHEAD (ETH_HLEN + 8)/* 8 for CRC + VLAN*/
+#define ETH_OVREHEAD (ETH_HLEN + 8 + 8)/* 16 for CRC + VLAN + LLC */
#define ETH_MIN_PACKET_SIZE 60
#define ETH_MAX_PACKET_SIZE 1500
#define ETH_MAX_JUMBO_PACKET_SIZE 9600
@@ -168,49 +168,24 @@
/**********************************************************/
/* INTERFACE */
/**********************************************************/
-#define CL45_WR_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
- bnx2x_cl45_write(_bp, _port, 0, _phy_addr, \
- DEFAULT_PHY_DEV_ADDR, \
+
+#define CL45_WR_OVER_CL22(_bp, _phy, _bank, _addr, _val) \
+ bnx2x_cl45_write(_bp, _phy, \
+ (_phy)->def_md_devad, \
(_bank + (_addr & 0xf)), \
_val)
-#define CL45_RD_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
- bnx2x_cl45_read(_bp, _port, 0, _phy_addr, \
- DEFAULT_PHY_DEV_ADDR, \
+#define CL45_RD_OVER_CL22(_bp, _phy, _bank, _addr, _val) \
+ bnx2x_cl45_read(_bp, _phy, \
+ (_phy)->def_md_devad, \
(_bank + (_addr & 0xf)), \
_val)
-static void bnx2x_set_serdes_access(struct link_params *params)
-{
- struct bnx2x *bp = params->bp;
- u32 emac_base = (params->port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+static u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
+ u8 devad, u16 reg, u16 *ret_val);
- /* Set Clause 22 */
- REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 1);
- REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
- udelay(500);
- REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
- udelay(500);
- /* Set Clause 45 */
- REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 0);
-}
-static void bnx2x_set_phy_mdio(struct link_params *params, u8 phy_flags)
-{
- struct bnx2x *bp = params->bp;
-
- if (phy_flags & PHY_XGXS_FLAG) {
- REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
- params->port*0x18, 0);
- REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18,
- DEFAULT_PHY_DEV_ADDR);
- } else {
- bnx2x_set_serdes_access(params);
-
- REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD +
- params->port*0x10,
- DEFAULT_PHY_DEV_ADDR);
- }
-}
+static u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
+ u8 devad, u16 reg, u16 val);
static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
{
@@ -408,9 +383,60 @@ static u8 bnx2x_emac_enable(struct link_params *params,
return 0;
}
+static void bnx2x_update_bmac2(struct link_params *params,
+ struct link_vars *vars,
+ u8 is_lb)
+{
+ /*
+ * Set rx control: Strip CRC and enable BigMAC to relay
+ * control packets to the system as well
+ */
+ u32 wb_data[2];
+ struct bnx2x *bp = params->bp;
+ u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
+ NIG_REG_INGRESS_BMAC0_MEM;
+ u32 val = 0x14;
+
+ if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
+ /* Enable BigMAC to react on received Pause packets */
+ val |= (1<<5);
+ wb_data[0] = val;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_CONTROL,
+ wb_data, 2);
+ udelay(30);
+ /* Tx control */
+ val = 0xc0;
+ if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
+ val |= 0x800000;
+ wb_data[0] = val;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_CONTROL,
+ wb_data, 2);
+
+ val = 0x8000;
+ wb_data[0] = val;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_PAUSE_CONTROL,
+ wb_data, 2);
-static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
+ /* mac control */
+ val = 0x3; /* Enable RX and TX */
+ if (is_lb) {
+ val |= 0x4; /* Local loopback */
+ DP(NETIF_MSG_LINK, "enable bmac loopback\n");
+ }
+
+ wb_data[0] = val;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL,
+ wb_data, 2);
+}
+
+
+static u8 bnx2x_bmac1_enable(struct link_params *params,
+ struct link_vars *vars,
u8 is_lb)
{
struct bnx2x *bp = params->bp;
@@ -420,17 +446,7 @@ static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
u32 wb_data[2];
u32 val;
- DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
- /* reset and unreset the BigMac */
- REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
- (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
- msleep(1);
-
- REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
- (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
-
- /* enable access for bmac registers */
- REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
+ DP(NETIF_MSG_LINK, "Enabling BigMAC1\n");
/* XGXS control */
wb_data[0] = 0x3c;
@@ -510,180 +526,121 @@ static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
wb_data, 2);
}
- REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
- REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
- REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
- val = 0;
- if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
- val = 1;
- REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
- REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
- REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
- REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
- REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
- REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
- vars->mac_type = MAC_TYPE_BMAC;
return 0;
}
-static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
-{
- struct bnx2x *bp = params->bp;
- u32 val;
-
- if (phy_flags & PHY_XGXS_FLAG) {
- DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
- val = XGXS_RESET_BITS;
-
- } else { /* SerDes */
- DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
- val = SERDES_RESET_BITS;
- }
-
- val = val << (params->port*16);
-
- /* reset and unreset the SerDes/XGXS */
- REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
- val);
- udelay(500);
- REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
- val);
- bnx2x_set_phy_mdio(params, phy_flags);
-}
-
-void bnx2x_link_status_update(struct link_params *params,
- struct link_vars *vars)
+static u8 bnx2x_bmac2_enable(struct link_params *params,
+ struct link_vars *vars,
+ u8 is_lb)
{
struct bnx2x *bp = params->bp;
- u8 link_10g;
u8 port = params->port;
+ u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
+ NIG_REG_INGRESS_BMAC0_MEM;
+ u32 wb_data[2];
- if (params->switch_cfg == SWITCH_CFG_1G)
- vars->phy_flags = PHY_SERDES_FLAG;
- else
- vars->phy_flags = PHY_XGXS_FLAG;
- vars->link_status = REG_RD(bp, params->shmem_base +
- offsetof(struct shmem_region,
- port_mb[port].link_status));
-
- vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
-
- if (vars->link_up) {
- DP(NETIF_MSG_LINK, "phy link up\n");
-
- vars->phy_link_up = 1;
- vars->duplex = DUPLEX_FULL;
- switch (vars->link_status &
- LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
- case LINK_10THD:
- vars->duplex = DUPLEX_HALF;
- /* fall thru */
- case LINK_10TFD:
- vars->line_speed = SPEED_10;
- break;
-
- case LINK_100TXHD:
- vars->duplex = DUPLEX_HALF;
- /* fall thru */
- case LINK_100T4:
- case LINK_100TXFD:
- vars->line_speed = SPEED_100;
- break;
-
- case LINK_1000THD:
- vars->duplex = DUPLEX_HALF;
- /* fall thru */
- case LINK_1000TFD:
- vars->line_speed = SPEED_1000;
- break;
-
- case LINK_2500THD:
- vars->duplex = DUPLEX_HALF;
- /* fall thru */
- case LINK_2500TFD:
- vars->line_speed = SPEED_2500;
- break;
-
- case LINK_10GTFD:
- vars->line_speed = SPEED_10000;
- break;
-
- case LINK_12GTFD:
- vars->line_speed = SPEED_12000;
- break;
+ DP(NETIF_MSG_LINK, "Enabling BigMAC2\n");
- case LINK_12_5GTFD:
- vars->line_speed = SPEED_12500;
- break;
+ wb_data[0] = 0;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL,
+ wb_data, 2);
+ udelay(30);
- case LINK_13GTFD:
- vars->line_speed = SPEED_13000;
- break;
+ /* XGXS control: Reset phy HW, MDIO registers, PHY PLL and BMAC */
+ wb_data[0] = 0x3c;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr +
+ BIGMAC2_REGISTER_BMAC_XGXS_CONTROL,
+ wb_data, 2);
- case LINK_15GTFD:
- vars->line_speed = SPEED_15000;
- break;
+ udelay(30);
- case LINK_16GTFD:
- vars->line_speed = SPEED_16000;
- break;
+ /* tx MAC SA */
+ wb_data[0] = ((params->mac_addr[2] << 24) |
+ (params->mac_addr[3] << 16) |
+ (params->mac_addr[4] << 8) |
+ params->mac_addr[5]);
+ wb_data[1] = ((params->mac_addr[0] << 8) |
+ params->mac_addr[1]);
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_SOURCE_ADDR,
+ wb_data, 2);
- default:
- break;
- }
+ udelay(30);
- if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
- vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
- else
- vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_TX;
+ /* Configure SAFC */
+ wb_data[0] = 0x1000200;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LLFC_MSG_FLDS,
+ wb_data, 2);
+ udelay(30);
- if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
- vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
- else
- vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_RX;
+ /* set rx mtu */
+ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_MAX_SIZE,
+ wb_data, 2);
+ udelay(30);
- if (vars->phy_flags & PHY_XGXS_FLAG) {
- if (vars->line_speed &&
- ((vars->line_speed == SPEED_10) ||
- (vars->line_speed == SPEED_100))) {
- vars->phy_flags |= PHY_SGMII_FLAG;
- } else {
- vars->phy_flags &= ~PHY_SGMII_FLAG;
- }
- }
+ /* set tx mtu */
+ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_MAX_SIZE,
+ wb_data, 2);
+ udelay(30);
+ /* set cnt max size */
+ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD - 2;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE,
+ wb_data, 2);
+ udelay(30);
+ bnx2x_update_bmac2(params, vars, is_lb);
- /* anything 10 and over uses the bmac */
- link_10g = ((vars->line_speed == SPEED_10000) ||
- (vars->line_speed == SPEED_12000) ||
- (vars->line_speed == SPEED_12500) ||
- (vars->line_speed == SPEED_13000) ||
- (vars->line_speed == SPEED_15000) ||
- (vars->line_speed == SPEED_16000));
- if (link_10g)
- vars->mac_type = MAC_TYPE_BMAC;
- else
- vars->mac_type = MAC_TYPE_EMAC;
+ return 0;
+}
- } else { /* link down */
- DP(NETIF_MSG_LINK, "phy link down\n");
+static u8 bnx2x_bmac_enable(struct link_params *params,
+ struct link_vars *vars,
+ u8 is_lb)
+{
+ u8 rc, port = params->port;
+ struct bnx2x *bp = params->bp;
+ u32 val;
+ /* reset and unreset the BigMac */
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+ (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
+ udelay(10);
- vars->phy_link_up = 0;
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
+ (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
- vars->line_speed = 0;
- vars->duplex = DUPLEX_FULL;
- vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+ /* enable access for bmac registers */
+ REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
- /* indicate no mac active */
- vars->mac_type = MAC_TYPE_NONE;
- }
+ /* Enable BMAC according to BMAC type*/
+ if (CHIP_IS_E2(bp))
+ rc = bnx2x_bmac2_enable(params, vars, is_lb);
+ else
+ rc = bnx2x_bmac1_enable(params, vars, is_lb);
+ REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
+ REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
+ REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
+ val = 0;
+ if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
+ val = 1;
+ REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
+ REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
+ REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
+ REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
+ REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
+ REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
- DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
- vars->link_status, vars->phy_link_up);
- DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
- vars->line_speed, vars->duplex, vars->flow_ctrl);
+ vars->mac_type = MAC_TYPE_BMAC;
+ return rc;
}
+
static void bnx2x_update_mng(struct link_params *params, u32 link_status)
{
struct bnx2x *bp = params->bp;
@@ -706,13 +663,25 @@ static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
(MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
nig_bmac_enable) {
- /* Clear Rx Enable bit in BMAC_CONTROL register */
- REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
- wb_data, 2);
- wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
- REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
- wb_data, 2);
-
+ if (CHIP_IS_E2(bp)) {
+ /* Clear Rx Enable bit in BMAC_CONTROL register */
+ REG_RD_DMAE(bp, bmac_addr +
+ BIGMAC2_REGISTER_BMAC_CONTROL,
+ wb_data, 2);
+ wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
+ REG_WR_DMAE(bp, bmac_addr +
+ BIGMAC2_REGISTER_BMAC_CONTROL,
+ wb_data, 2);
+ } else {
+ /* Clear Rx Enable bit in BMAC_CONTROL register */
+ REG_RD_DMAE(bp, bmac_addr +
+ BIGMAC_REGISTER_BMAC_CONTROL,
+ wb_data, 2);
+ wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
+ REG_WR_DMAE(bp, bmac_addr +
+ BIGMAC_REGISTER_BMAC_CONTROL,
+ wb_data, 2);
+ }
msleep(1);
}
}
@@ -800,62 +769,69 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
return 0;
}
-static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
+static u32 bnx2x_get_emac_base(struct bnx2x *bp,
+ u32 mdc_mdio_access, u8 port)
{
- u32 emac_base;
-
- switch (ext_phy_type) {
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
- /* All MDC/MDIO is directed through single EMAC */
+ u32 emac_base = 0;
+ switch (mdc_mdio_access) {
+ case SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE:
+ break;
+ case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0:
+ if (REG_RD(bp, NIG_REG_PORT_SWAP))
+ emac_base = GRCBASE_EMAC1;
+ else
+ emac_base = GRCBASE_EMAC0;
+ break;
+ case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1:
if (REG_RD(bp, NIG_REG_PORT_SWAP))
emac_base = GRCBASE_EMAC0;
else
emac_base = GRCBASE_EMAC1;
break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
+ case SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH:
+ emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+ break;
+ case SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED:
emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
break;
default:
- emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
break;
}
return emac_base;
}
-u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
- u8 phy_addr, u8 devad, u16 reg, u16 val)
+u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
+ u8 devad, u16 reg, u16 val)
{
u32 tmp, saved_mode;
u8 i, rc = 0;
- u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
/* set clause 45 mode, slow down the MDIO clock to 2.5MHz
* (a value of 49==0x31) and make sure that the AUTO poll is off
*/
- saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+ saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
EMAC_MDIO_MODE_CLOCK_CNT);
tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
(49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
- REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
- REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+ REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
+ REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
udelay(40);
/* address */
- tmp = ((phy_addr << 21) | (devad << 16) | reg |
+ tmp = ((phy->addr << 21) | (devad << 16) | reg |
EMAC_MDIO_COMM_COMMAND_ADDRESS |
EMAC_MDIO_COMM_START_BUSY);
- REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
+ REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
for (i = 0; i < 50; i++) {
udelay(10);
- tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
+ tmp = REG_RD(bp, phy->mdio_ctrl +
+ EMAC_REG_EMAC_MDIO_COMM);
if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
udelay(5);
break;
@@ -866,15 +842,15 @@ u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
rc = -EFAULT;
} else {
/* data */
- tmp = ((phy_addr << 21) | (devad << 16) | val |
+ tmp = ((phy->addr << 21) | (devad << 16) | val |
EMAC_MDIO_COMM_COMMAND_WRITE_45 |
EMAC_MDIO_COMM_START_BUSY);
- REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
+ REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
for (i = 0; i < 50; i++) {
udelay(10);
- tmp = REG_RD(bp, mdio_ctrl +
+ tmp = REG_RD(bp, phy->mdio_ctrl +
EMAC_REG_EMAC_MDIO_COMM);
if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
udelay(5);
@@ -888,42 +864,41 @@ u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
}
/* Restore the saved mode */
- REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
+ REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
return rc;
}
-u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
- u8 phy_addr, u8 devad, u16 reg, u16 *ret_val)
+u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
+ u8 devad, u16 reg, u16 *ret_val)
{
u32 val, saved_mode;
u16 i;
u8 rc = 0;
- u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
/* set clause 45 mode, slow down the MDIO clock to 2.5MHz
* (a value of 49==0x31) and make sure that the AUTO poll is off
*/
- saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
- val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
+ saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+ val = saved_mode & ~((EMAC_MDIO_MODE_AUTO_POLL |
EMAC_MDIO_MODE_CLOCK_CNT));
val |= (EMAC_MDIO_MODE_CLAUSE_45 |
(49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
- REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
- REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+ REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
+ REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
udelay(40);
/* address */
- val = ((phy_addr << 21) | (devad << 16) | reg |
+ val = ((phy->addr << 21) | (devad << 16) | reg |
EMAC_MDIO_COMM_COMMAND_ADDRESS |
EMAC_MDIO_COMM_START_BUSY);
- REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
+ REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
for (i = 0; i < 50; i++) {
udelay(10);
- val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
+ val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
udelay(5);
break;
@@ -937,15 +912,15 @@ u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
} else {
/* data */
- val = ((phy_addr << 21) | (devad << 16) |
+ val = ((phy->addr << 21) | (devad << 16) |
EMAC_MDIO_COMM_COMMAND_READ_45 |
EMAC_MDIO_COMM_START_BUSY);
- REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
+ REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
for (i = 0; i < 50; i++) {
udelay(10);
- val = REG_RD(bp, mdio_ctrl +
+ val = REG_RD(bp, phy->mdio_ctrl +
EMAC_REG_EMAC_MDIO_COMM);
if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
*ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
@@ -961,32 +936,262 @@ u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
}
/* Restore the saved mode */
- REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
+ REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
return rc;
}
-static void bnx2x_set_aer_mmd(struct link_params *params,
- struct link_vars *vars)
+u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr,
+ u8 devad, u16 reg, u16 *ret_val)
{
- struct bnx2x *bp = params->bp;
- u32 ser_lane;
- u16 offset;
+ u8 phy_index;
+ /**
+ * Probe for the phy according to the given phy_addr, and execute
+ * the read request on it
+ */
+ for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
+ if (params->phy[phy_index].addr == phy_addr) {
+ return bnx2x_cl45_read(params->bp,
+ &params->phy[phy_index], devad,
+ reg, ret_val);
+ }
+ }
+ return -EINVAL;
+}
+u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr,
+ u8 devad, u16 reg, u16 val)
+{
+ u8 phy_index;
+ /**
+ * Probe for the phy according to the given phy_addr, and execute
+ * the write request on it
+ */
+ for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
+ if (params->phy[phy_index].addr == phy_addr) {
+ return bnx2x_cl45_write(params->bp,
+ &params->phy[phy_index], devad,
+ reg, val);
+ }
+ }
+ return -EINVAL;
+}
+
+static void bnx2x_set_aer_mmd_xgxs(struct link_params *params,
+ struct bnx2x_phy *phy)
+{
+ u32 ser_lane;
+ u16 offset, aer_val;
+ struct bnx2x *bp = params->bp;
ser_lane = ((params->lane_config &
PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
- offset = (vars->phy_flags & PHY_XGXS_FLAG) ?
- (params->phy_addr + ser_lane) : 0;
+ offset = phy->addr + ser_lane;
+ if (CHIP_IS_E2(bp))
+ aer_val = 0x2800 + offset - 1;
+ else
+ aer_val = 0x3800 + offset;
+ CL45_WR_OVER_CL22(bp, phy,
+ MDIO_REG_BANK_AER_BLOCK,
+ MDIO_AER_BLOCK_AER_REG, aer_val);
+}
+static void bnx2x_set_aer_mmd_serdes(struct bnx2x *bp,
+ struct bnx2x_phy *phy)
+{
+ CL45_WR_OVER_CL22(bp, phy,
+ MDIO_REG_BANK_AER_BLOCK,
+ MDIO_AER_BLOCK_AER_REG, 0x3800);
+}
+
+/******************************************************************/
+/* Internal phy section */
+/******************************************************************/
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
- MDIO_REG_BANK_AER_BLOCK,
- MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
+static void bnx2x_set_serdes_access(struct bnx2x *bp, u8 port)
+{
+ u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+
+ /* Set Clause 22 */
+ REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 1);
+ REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
+ udelay(500);
+ REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
+ udelay(500);
+ /* Set Clause 45 */
+ REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 0);
}
-static void bnx2x_set_master_ln(struct link_params *params)
+static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port)
+{
+ u32 val;
+
+ DP(NETIF_MSG_LINK, "bnx2x_serdes_deassert\n");
+
+ val = SERDES_RESET_BITS << (port*16);
+
+ /* reset and unreset the SerDes/XGXS */
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
+ udelay(500);
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
+
+ bnx2x_set_serdes_access(bp, port);
+
+ REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD +
+ port*0x10,
+ DEFAULT_PHY_DEV_ADDR);
+}
+
+static void bnx2x_xgxs_deassert(struct link_params *params)
+{
+ struct bnx2x *bp = params->bp;
+ u8 port;
+ u32 val;
+ DP(NETIF_MSG_LINK, "bnx2x_xgxs_deassert\n");
+ port = params->port;
+
+ val = XGXS_RESET_BITS << (port*16);
+
+ /* reset and unreset the SerDes/XGXS */
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
+ udelay(500);
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
+
+ REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
+ port*0x18, 0);
+ REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
+ params->phy[INT_PHY].def_md_devad);
+}
+
+
+void bnx2x_link_status_update(struct link_params *params,
+ struct link_vars *vars)
+{
+ struct bnx2x *bp = params->bp;
+ u8 link_10g;
+ u8 port = params->port;
+
+ vars->link_status = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region,
+ port_mb[port].link_status));
+
+ vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
+
+ if (vars->link_up) {
+ DP(NETIF_MSG_LINK, "phy link up\n");
+
+ vars->phy_link_up = 1;
+ vars->duplex = DUPLEX_FULL;
+ switch (vars->link_status &
+ LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
+ case LINK_10THD:
+ vars->duplex = DUPLEX_HALF;
+ /* fall thru */
+ case LINK_10TFD:
+ vars->line_speed = SPEED_10;
+ break;
+
+ case LINK_100TXHD:
+ vars->duplex = DUPLEX_HALF;
+ /* fall thru */
+ case LINK_100T4:
+ case LINK_100TXFD:
+ vars->line_speed = SPEED_100;
+ break;
+
+ case LINK_1000THD:
+ vars->duplex = DUPLEX_HALF;
+ /* fall thru */
+ case LINK_1000TFD:
+ vars->line_speed = SPEED_1000;
+ break;
+
+ case LINK_2500THD:
+ vars->duplex = DUPLEX_HALF;
+ /* fall thru */
+ case LINK_2500TFD:
+ vars->line_speed = SPEED_2500;
+ break;
+
+ case LINK_10GTFD:
+ vars->line_speed = SPEED_10000;
+ break;
+
+ case LINK_12GTFD:
+ vars->line_speed = SPEED_12000;
+ break;
+
+ case LINK_12_5GTFD:
+ vars->line_speed = SPEED_12500;
+ break;
+
+ case LINK_13GTFD:
+ vars->line_speed = SPEED_13000;
+ break;
+
+ case LINK_15GTFD:
+ vars->line_speed = SPEED_15000;
+ break;
+
+ case LINK_16GTFD:
+ vars->line_speed = SPEED_16000;
+ break;
+
+ default:
+ break;
+ }
+ vars->flow_ctrl = 0;
+ if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
+ vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
+
+ if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
+ vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
+
+ if (!vars->flow_ctrl)
+ vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+
+ if (vars->line_speed &&
+ ((vars->line_speed == SPEED_10) ||
+ (vars->line_speed == SPEED_100))) {
+ vars->phy_flags |= PHY_SGMII_FLAG;
+ } else {
+ vars->phy_flags &= ~PHY_SGMII_FLAG;
+ }
+
+ /* anything 10 and over uses the bmac */
+ link_10g = ((vars->line_speed == SPEED_10000) ||
+ (vars->line_speed == SPEED_12000) ||
+ (vars->line_speed == SPEED_12500) ||
+ (vars->line_speed == SPEED_13000) ||
+ (vars->line_speed == SPEED_15000) ||
+ (vars->line_speed == SPEED_16000));
+ if (link_10g)
+ vars->mac_type = MAC_TYPE_BMAC;
+ else
+ vars->mac_type = MAC_TYPE_EMAC;
+
+ } else { /* link down */
+ DP(NETIF_MSG_LINK, "phy link down\n");
+
+ vars->phy_link_up = 0;
+
+ vars->line_speed = 0;
+ vars->duplex = DUPLEX_FULL;
+ vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+
+ /* indicate no mac active */
+ vars->mac_type = MAC_TYPE_NONE;
+ }
+
+ DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
+ vars->link_status, vars->phy_link_up);
+ DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
+ vars->line_speed, vars->duplex, vars->flow_ctrl);
+}
+
+
+static void bnx2x_set_master_ln(struct link_params *params,
+ struct bnx2x_phy *phy)
{
struct bnx2x *bp = params->bp;
u16 new_master_ln, ser_lane;
@@ -995,47 +1200,44 @@ static void bnx2x_set_master_ln(struct link_params *params)
PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
/* set the master_ln for AN */
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_XGXS_BLOCK2,
MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
&new_master_ln);
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_XGXS_BLOCK2 ,
MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
(new_master_ln | ser_lane));
}
-static u8 bnx2x_reset_unicore(struct link_params *params)
+static u8 bnx2x_reset_unicore(struct link_params *params,
+ struct bnx2x_phy *phy,
+ u8 set_serdes)
{
struct bnx2x *bp = params->bp;
u16 mii_control;
u16 i;
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
/* reset the unicore */
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_MII_CONTROL,
(mii_control |
MDIO_COMBO_IEEO_MII_CONTROL_RESET));
- if (params->switch_cfg == SWITCH_CFG_1G)
- bnx2x_set_serdes_access(params);
+ if (set_serdes)
+ bnx2x_set_serdes_access(bp, params->port);
/* wait for the reset to self clear */
for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
udelay(5);
/* the reset erased the previous bank value */
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_MII_CONTROL,
&mii_control);
@@ -1051,7 +1253,8 @@ static u8 bnx2x_reset_unicore(struct link_params *params)
}
-static void bnx2x_set_swap_lanes(struct link_params *params)
+static void bnx2x_set_swap_lanes(struct link_params *params,
+ struct bnx2x_phy *phy)
{
struct bnx2x *bp = params->bp;
/* Each two bits represents a lane number:
@@ -1069,71 +1272,62 @@ static void bnx2x_set_swap_lanes(struct link_params *params)
PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
if (rx_lane_swap != 0x1b) {
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_XGXS_BLOCK2,
MDIO_XGXS_BLOCK2_RX_LN_SWAP,
(rx_lane_swap |
MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
} else {
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_XGXS_BLOCK2,
MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
}
if (tx_lane_swap != 0x1b) {
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_XGXS_BLOCK2,
MDIO_XGXS_BLOCK2_TX_LN_SWAP,
(tx_lane_swap |
MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
} else {
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_XGXS_BLOCK2,
MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
}
}
-static void bnx2x_set_parallel_detection(struct link_params *params,
- u8 phy_flags)
+static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy,
+ struct link_params *params)
{
struct bnx2x *bp = params->bp;
u16 control2;
-
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_SERDES_DIGITAL,
MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
&control2);
- if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
+ if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
else
control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
- DP(NETIF_MSG_LINK, "params->speed_cap_mask = 0x%x, control2 = 0x%x\n",
- params->speed_cap_mask, control2);
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n",
+ phy->speed_cap_mask, control2);
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_SERDES_DIGITAL,
MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
control2);
- if ((phy_flags & PHY_XGXS_FLAG) &&
- (params->speed_cap_mask &
+ if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
+ (phy->speed_cap_mask &
PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
DP(NETIF_MSG_LINK, "XGXS\n");
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_10G_PARALLEL_DETECT,
MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_10G_PARALLEL_DETECT,
MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
&control2);
@@ -1142,15 +1336,13 @@ static void bnx2x_set_parallel_detection(struct link_params *params,
control2 |=
MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_10G_PARALLEL_DETECT,
MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
control2);
/* Disable parallel detection of HiG */
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_XGXS_BLOCK2,
MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
@@ -1158,7 +1350,8 @@ static void bnx2x_set_parallel_detection(struct link_params *params,
}
}
-static void bnx2x_set_autoneg(struct link_params *params,
+static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
+ struct link_params *params,
struct link_vars *vars,
u8 enable_cl73)
{
@@ -1166,9 +1359,7 @@ static void bnx2x_set_autoneg(struct link_params *params,
u16 reg_val;
/* CL37 Autoneg */
-
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
@@ -1179,15 +1370,13 @@ static void bnx2x_set_autoneg(struct link_params *params,
reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
/* Enable/Disable Autodetection */
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_SERDES_DIGITAL,
MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
@@ -1198,14 +1387,12 @@ static void bnx2x_set_autoneg(struct link_params *params,
else
reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_SERDES_DIGITAL,
MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
/* Enable TetonII and BAM autoneg */
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_BAM_NEXT_PAGE,
MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
&reg_val);
@@ -1218,23 +1405,20 @@ static void bnx2x_set_autoneg(struct link_params *params,
reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
}
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_BAM_NEXT_PAGE,
MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
reg_val);
if (enable_cl73) {
/* Enable Cl73 FSM status bits */
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_CL73_USERB0,
MDIO_CL73_USERB0_CL73_UCTRL,
0xe);
/* Enable BAM Station Manager*/
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_CL73_USERB0,
MDIO_CL73_USERB0_CL73_BAM_CTRL1,
MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
@@ -1242,20 +1426,18 @@ static void bnx2x_set_autoneg(struct link_params *params,
MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
/* Advertise CL73 link speeds */
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_CL73_IEEEB1,
MDIO_CL73_IEEEB1_AN_ADV2,
&reg_val);
- if (params->speed_cap_mask &
+ if (phy->speed_cap_mask &
PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
- if (params->speed_cap_mask &
+ if (phy->speed_cap_mask &
PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_CL73_IEEEB1,
MDIO_CL73_IEEEB1_AN_ADV2,
reg_val);
@@ -1266,38 +1448,35 @@ static void bnx2x_set_autoneg(struct link_params *params,
} else /* CL73 Autoneg Disabled */
reg_val = 0;
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_CL73_IEEEB0,
MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
}
/* program SerDes, forced speed */
-static void bnx2x_program_serdes(struct link_params *params,
+static void bnx2x_program_serdes(struct bnx2x_phy *phy,
+ struct link_params *params,
struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
u16 reg_val;
/* program duplex, disable autoneg and sgmii*/
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
- if (params->req_duplex == DUPLEX_FULL)
+ if (phy->req_duplex == DUPLEX_FULL)
reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
/* program speed
- needed only if the speed is greater than 1G (2.5G or 10G) */
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_SERDES_DIGITAL,
MDIO_SERDES_DIGITAL_MISC1, &reg_val);
/* clearing the speed value before setting the right speed */
@@ -1320,14 +1499,14 @@ static void bnx2x_program_serdes(struct link_params *params,
MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
}
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_SERDES_DIGITAL,
MDIO_SERDES_DIGITAL_MISC1, reg_val);
}
-static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
+static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x_phy *phy,
+ struct link_params *params)
{
struct bnx2x *bp = params->bp;
u16 val = 0;
@@ -1335,29 +1514,28 @@ static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
/* configure the 48 bits for BAM AN */
/* set extended capabilities */
- if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
+ if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
val |= MDIO_OVER_1G_UP1_2_5G;
- if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
+ if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
val |= MDIO_OVER_1G_UP1_10G;
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_OVER_1G,
MDIO_OVER_1G_UP1, val);
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_OVER_1G,
MDIO_OVER_1G_UP3, 0x400);
}
-static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u16 *ieee_fc)
+static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
+ struct link_params *params, u16 *ieee_fc)
{
struct bnx2x *bp = params->bp;
*ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
/* resolve pause mode and advertisement
* Please refer to Table 28B-3 of the 802.3ab-1999 spec */
- switch (params->req_flow_ctrl) {
+ switch (phy->req_flow_ctrl) {
case BNX2X_FLOW_CTRL_AUTO:
if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
*ieee_fc |=
@@ -1385,30 +1563,30 @@ static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u16 *ieee_fc)
DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
}
-static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
+static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x_phy *phy,
+ struct link_params *params,
u16 ieee_fc)
{
struct bnx2x *bp = params->bp;
u16 val;
/* for AN, we are always publishing full duplex */
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_CL73_IEEEB1,
MDIO_CL73_IEEEB1_AN_ADV1, &val);
val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_CL73_IEEEB1,
MDIO_CL73_IEEEB1_AN_ADV1, val);
}
-static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73)
+static void bnx2x_restart_autoneg(struct bnx2x_phy *phy,
+ struct link_params *params,
+ u8 enable_cl73)
{
struct bnx2x *bp = params->bp;
u16 mii_control;
@@ -1417,14 +1595,12 @@ static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73)
/* Enable and restart BAM/CL37 aneg */
if (enable_cl73) {
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_CL73_IEEEB0,
MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
&mii_control);
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_CL73_IEEEB0,
MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
(mii_control |
@@ -1432,16 +1608,14 @@ static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73)
MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
} else {
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_MII_CONTROL,
&mii_control);
DP(NETIF_MSG_LINK,
"bnx2x_restart_autoneg mii_control before = 0x%x\n",
mii_control);
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_MII_CONTROL,
(mii_control |
@@ -1450,7 +1624,8 @@ static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73)
}
}
-static void bnx2x_initialize_sgmii_process(struct link_params *params,
+static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
+ struct link_params *params,
struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
@@ -1458,8 +1633,7 @@ static void bnx2x_initialize_sgmii_process(struct link_params *params,
/* in SGMII mode, the unicore is always slave */
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_SERDES_DIGITAL,
MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
&control1);
@@ -1468,8 +1642,7 @@ static void bnx2x_initialize_sgmii_process(struct link_params *params,
control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_SERDES_DIGITAL,
MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
control1);
@@ -1479,8 +1652,7 @@ static void bnx2x_initialize_sgmii_process(struct link_params *params,
/* set speed, disable autoneg */
u16 mii_control;
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_MII_CONTROL,
&mii_control);
@@ -1508,18 +1680,17 @@ static void bnx2x_initialize_sgmii_process(struct link_params *params,
}
/* setting the full duplex */
- if (params->req_duplex == DUPLEX_FULL)
+ if (phy->req_duplex == DUPLEX_FULL)
mii_control |=
MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_MII_CONTROL,
mii_control);
} else { /* AN mode */
/* enable and restart AN */
- bnx2x_restart_autoneg(params, 0);
+ bnx2x_restart_autoneg(phy, params, 0);
}
}
@@ -1549,91 +1720,24 @@ static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
default:
break;
}
+ if (pause_result & (1<<0))
+ vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
+ if (pause_result & (1<<1))
+ vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
}
-static u8 bnx2x_ext_phy_resolve_fc(struct link_params *params,
- struct link_vars *vars)
-{
- struct bnx2x *bp = params->bp;
- u8 ext_phy_addr;
- u16 ld_pause; /* local */
- u16 lp_pause; /* link partner */
- u16 an_complete; /* AN complete */
- u16 pause_result;
- u8 ret = 0;
- u32 ext_phy_type;
- u8 port = params->port;
- ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
- ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
- /* read twice */
-
- bnx2x_cl45_read(bp, port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_STATUS, &an_complete);
- bnx2x_cl45_read(bp, port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_STATUS, &an_complete);
-
- if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) {
- ret = 1;
- bnx2x_cl45_read(bp, port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_ADV_PAUSE, &ld_pause);
- bnx2x_cl45_read(bp, port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
- pause_result = (ld_pause &
- MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
- pause_result |= (lp_pause &
- MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
- DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
- pause_result);
- bnx2x_pause_resolve(vars, pause_result);
- if (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE &&
- ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
- bnx2x_cl45_read(bp, port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CL37_FC_LD, &ld_pause);
-
- bnx2x_cl45_read(bp, port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CL37_FC_LP, &lp_pause);
- pause_result = (ld_pause &
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
- pause_result |= (lp_pause &
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
-
- bnx2x_pause_resolve(vars, pause_result);
- DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
- pause_result);
- }
- }
- return ret;
-}
-
-static u8 bnx2x_direct_parallel_detect_used(struct link_params *params)
+static u8 bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
+ struct link_params *params)
{
struct bnx2x *bp = params->bp;
u16 pd_10g, status2_1000x;
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ if (phy->req_line_speed != SPEED_AUTO_NEG)
+ return 0;
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_SERDES_DIGITAL,
MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
&status2_1000x);
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_SERDES_DIGITAL,
MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
&status2_1000x);
@@ -1643,8 +1747,7 @@ static u8 bnx2x_direct_parallel_detect_used(struct link_params *params)
return 1;
}
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_10G_PARALLEL_DETECT,
MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
&pd_10g);
@@ -1657,9 +1760,10 @@ static u8 bnx2x_direct_parallel_detect_used(struct link_params *params)
return 0;
}
-static void bnx2x_flow_ctrl_resolve(struct link_params *params,
- struct link_vars *vars,
- u32 gp_status)
+static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars,
+ u32 gp_status)
{
struct bnx2x *bp = params->bp;
u16 ld_pause; /* local driver */
@@ -1669,12 +1773,13 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params,
vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
/* resolve from gp_status in case of AN complete and not sgmii */
- if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
- (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
- (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
- (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
- if (bnx2x_direct_parallel_detect_used(params)) {
+ if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
+ vars->flow_ctrl = phy->req_flow_ctrl;
+ else if (phy->req_line_speed != SPEED_AUTO_NEG)
+ vars->flow_ctrl = params->req_fc_auto_adv;
+ else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
+ (!(vars->phy_flags & PHY_SGMII_FLAG))) {
+ if (bnx2x_direct_parallel_detect_used(phy, params)) {
vars->flow_ctrl = params->req_fc_auto_adv;
return;
}
@@ -1684,13 +1789,11 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params,
(MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_CL73_IEEEB1,
MDIO_CL73_IEEEB1_AN_ADV1,
&ld_pause);
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_CL73_IEEEB1,
MDIO_CL73_IEEEB1_AN_LP_ADV1,
&lp_pause);
@@ -1703,14 +1806,11 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params,
DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
pause_result);
} else {
-
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
&ld_pause);
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
&lp_pause);
@@ -1722,26 +1822,18 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params,
pause_result);
}
bnx2x_pause_resolve(vars, pause_result);
- } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
- (bnx2x_ext_phy_resolve_fc(params, vars))) {
- return;
- } else {
- if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
- vars->flow_ctrl = params->req_fc_auto_adv;
- else
- vars->flow_ctrl = params->req_flow_ctrl;
}
DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
}
-static void bnx2x_check_fallback_to_cl37(struct link_params *params)
+static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
+ struct link_params *params)
{
struct bnx2x *bp = params->bp;
u16 rx_status, ustat_val, cl37_fsm_recieved;
DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
/* Step 1: Make sure signal is detected */
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_RX0,
MDIO_RX0_RX_STATUS,
&rx_status);
@@ -1749,16 +1841,14 @@ static void bnx2x_check_fallback_to_cl37(struct link_params *params)
(MDIO_RX0_RX_STATUS_SIGDET)) {
DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
"rx_status(0x80b0) = 0x%x\n", rx_status);
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_CL73_IEEEB0,
MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
return;
}
/* Step 2: Check CL73 state machine */
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_CL73_USERB0,
MDIO_CL73_USERB0_CL73_USTAT1,
&ustat_val);
@@ -1773,8 +1863,7 @@ static void bnx2x_check_fallback_to_cl37(struct link_params *params)
}
/* Step 3: Check CL37 Message Pages received to indicate LP
supports only CL37 */
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_REMOTE_PHY,
MDIO_REMOTE_PHY_MISC_RX_STATUS,
&cl37_fsm_recieved);
@@ -1792,25 +1881,45 @@ static void bnx2x_check_fallback_to_cl37(struct link_params *params)
connected to a device which does not support cl73, but does support
cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */
/* Disable CL73 */
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
MDIO_REG_BANK_CL73_IEEEB0,
MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
0);
/* Restart CL37 autoneg */
- bnx2x_restart_autoneg(params, 0);
+ bnx2x_restart_autoneg(phy, params, 0);
DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
}
-static u8 bnx2x_link_settings_status(struct link_params *params,
- struct link_vars *vars,
- u32 gp_status,
- u8 ext_phy_link_up)
+
+static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars,
+ u32 gp_status)
+{
+ if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE)
+ vars->link_status |=
+ LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
+
+ if (bnx2x_direct_parallel_detect_used(phy, params))
+ vars->link_status |=
+ LINK_STATUS_PARALLEL_DETECTION_USED;
+}
+
+static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
- u16 new_line_speed;
+ u16 new_line_speed , gp_status;
u8 rc = 0;
- vars->link_status = 0;
+ /* Read gp_status */
+ CL45_RD_OVER_CL22(bp, phy,
+ MDIO_REG_BANK_GP_STATUS,
+ MDIO_GP_STATUS_TOP_AN_STATUS1,
+ &gp_status);
+
+ if (phy->req_line_speed == SPEED_AUTO_NEG)
+ vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
gp_status);
@@ -1823,7 +1932,12 @@ static u8 bnx2x_link_settings_status(struct link_params *params,
else
vars->duplex = DUPLEX_HALF;
- bnx2x_flow_ctrl_resolve(params, vars, gp_status);
+ if (SINGLE_MEDIA_DIRECT(params)) {
+ bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
+ if (phy->req_line_speed == SPEED_AUTO_NEG)
+ bnx2x_xgxs_an_resolve(phy, params, vars,
+ gp_status);
+ }
switch (gp_status & GP_STATUS_SPEED_MASK) {
case GP_STATUS_10M:
@@ -1905,56 +2019,7 @@ static u8 bnx2x_link_settings_status(struct link_params *params,
return -EINVAL;
}
- /* Upon link speed change set the NIG into drain mode.
- Comes to deals with possible FIFO glitch due to clk change
- when speed is decreased without link down indicator */
- if (new_line_speed != vars->line_speed) {
- if (XGXS_EXT_PHY_TYPE(params->ext_phy_config) !=
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT &&
- ext_phy_link_up) {
- DP(NETIF_MSG_LINK, "Internal link speed %d is"
- " different than the external"
- " link speed %d\n", new_line_speed,
- vars->line_speed);
- vars->phy_link_up = 0;
- return 0;
- }
- REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
- + params->port*4, 0);
- msleep(1);
- }
vars->line_speed = new_line_speed;
- vars->link_status |= LINK_STATUS_SERDES_LINK;
-
- if ((params->req_line_speed == SPEED_AUTO_NEG) &&
- ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
- (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
- (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) ||
- (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726))) {
- vars->autoneg = AUTO_NEG_ENABLED;
-
- if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
- vars->autoneg |= AUTO_NEG_COMPLETE;
- vars->link_status |=
- LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
- }
-
- vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED;
- vars->link_status |=
- LINK_STATUS_PARALLEL_DETECTION_USED;
-
- }
- if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
- vars->link_status |=
- LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
-
- if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
- vars->link_status |=
- LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
} else { /* link_down */
DP(NETIF_MSG_LINK, "phy link down\n");
@@ -1963,38 +2028,32 @@ static u8 bnx2x_link_settings_status(struct link_params *params,
vars->duplex = DUPLEX_FULL;
vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
- vars->autoneg = AUTO_NEG_DISABLED;
vars->mac_type = MAC_TYPE_NONE;
- if ((params->req_line_speed == SPEED_AUTO_NEG) &&
- ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT))) {
+ if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
+ SINGLE_MEDIA_DIRECT(params)) {
/* Check signal is detected */
- bnx2x_check_fallback_to_cl37(params);
+ bnx2x_check_fallback_to_cl37(phy, params);
}
}
DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n",
gp_status, vars->phy_link_up, vars->line_speed);
- DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x"
- " autoneg 0x%x\n",
- vars->duplex,
- vars->flow_ctrl, vars->autoneg);
- DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
-
+ DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
+ vars->duplex, vars->flow_ctrl, vars->link_status);
return rc;
}
static void bnx2x_set_gmii_tx_driver(struct link_params *params)
{
struct bnx2x *bp = params->bp;
+ struct bnx2x_phy *phy = &params->phy[INT_PHY];
u16 lp_up2;
u16 tx_driver;
u16 bank;
/* read precomp */
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_OVER_1G,
MDIO_OVER_1G_LP_UP2, &lp_up2);
@@ -2008,8 +2067,7 @@ static void bnx2x_set_gmii_tx_driver(struct link_params *params)
for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_RD_OVER_CL22(bp, phy,
bank,
MDIO_TX0_TX_DRIVER, &tx_driver);
@@ -2018,8 +2076,7 @@ static void bnx2x_set_gmii_tx_driver(struct link_params *params)
(tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
tx_driver |= lp_up2;
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
+ CL45_WR_OVER_CL22(bp, phy,
bank,
MDIO_TX0_TX_DRIVER, tx_driver);
}
@@ -2027,7 +2084,7 @@ static void bnx2x_set_gmii_tx_driver(struct link_params *params)
}
static u8 bnx2x_emac_program(struct link_params *params,
- u32 line_speed, u32 duplex)
+ struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
u8 port = params->port;
@@ -2039,7 +2096,7 @@ static u8 bnx2x_emac_program(struct link_params *params,
(EMAC_MODE_25G_MODE |
EMAC_MODE_PORT_MII_10M |
EMAC_MODE_HALF_DUPLEX));
- switch (line_speed) {
+ switch (vars->line_speed) {
case SPEED_10:
mode |= EMAC_MODE_PORT_MII_10M;
break;
@@ -2058,371 +2115,1257 @@ static u8 bnx2x_emac_program(struct link_params *params,
default:
/* 10G not valid for EMAC */
- DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed);
+ DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
+ vars->line_speed);
return -EINVAL;
}
- if (duplex == DUPLEX_HALF)
+ if (vars->duplex == DUPLEX_HALF)
mode |= EMAC_MODE_HALF_DUPLEX;
bnx2x_bits_en(bp,
GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
mode);
- bnx2x_set_led(params, LED_MODE_OPER, line_speed);
+ bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
return 0;
}
-/*****************************************************************************/
-/* External Phy section */
-/*****************************************************************************/
-void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
+static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
+ struct link_params *params)
{
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
- MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
- msleep(1);
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
- MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
+
+ u16 bank, i = 0;
+ struct bnx2x *bp = params->bp;
+
+ for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
+ bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
+ CL45_WR_OVER_CL22(bp, phy,
+ bank,
+ MDIO_RX0_RX_EQ_BOOST,
+ phy->rx_preemphasis[i]);
+ }
+
+ for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
+ bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
+ CL45_WR_OVER_CL22(bp, phy,
+ bank,
+ MDIO_TX0_TX_DRIVER,
+ phy->tx_preemphasis[i]);
+ }
}
-static void bnx2x_ext_phy_reset(struct link_params *params,
- struct link_vars *vars)
+static void bnx2x_init_internal_phy(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
- u32 ext_phy_type;
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
+ u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
+ (params->loopback_mode == LOOPBACK_XGXS));
+ if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
+ if (SINGLE_MEDIA_DIRECT(params) &&
+ (params->feature_config_flags &
+ FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
+ bnx2x_set_preemphasis(phy, params);
- DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port);
- ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
- /* The PHY reset is controled by GPIO 1
- * Give it 1ms of reset pulse
- */
- if (vars->phy_flags & PHY_XGXS_FLAG) {
+ /* forced speed requested? */
+ if (vars->line_speed != SPEED_AUTO_NEG ||
+ (SINGLE_MEDIA_DIRECT(params) &&
+ params->loopback_mode == LOOPBACK_EXT)) {
+ DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
- switch (ext_phy_type) {
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
- DP(NETIF_MSG_LINK, "XGXS Direct\n");
- break;
+ /* disable autoneg */
+ bnx2x_set_autoneg(phy, params, vars, 0);
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
- DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
+ /* program speed and duplex */
+ bnx2x_program_serdes(phy, params, vars);
- /* Restore normal power mode*/
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
- MISC_REGISTERS_GPIO_OUTPUT_HIGH,
- params->port);
+ } else { /* AN_mode */
+ DP(NETIF_MSG_LINK, "not SGMII, AN\n");
- /* HW reset */
- bnx2x_ext_phy_hw_reset(bp, params->port);
+ /* AN enabled */
+ bnx2x_set_brcm_cl37_advertisment(phy, params);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CTRL, 0xa040);
- break;
+ /* program duplex & pause advertisement (for aneg) */
+ bnx2x_set_ieee_aneg_advertisment(phy, params,
+ vars->ieee_fc);
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
- break;
+ /* enable autoneg */
+ bnx2x_set_autoneg(phy, params, vars, enable_cl73);
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+ /* enable and restart AN */
+ bnx2x_restart_autoneg(phy, params, enable_cl73);
+ }
- /* Restore normal power mode*/
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
- MISC_REGISTERS_GPIO_OUTPUT_HIGH,
- params->port);
+ } else { /* SGMII mode */
+ DP(NETIF_MSG_LINK, "SGMII\n");
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
- MISC_REGISTERS_GPIO_OUTPUT_HIGH,
- params->port);
+ bnx2x_initialize_sgmii_process(phy, params, vars);
+ }
+}
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CTRL,
- 1<<15);
- break;
+static u8 bnx2x_init_serdes(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
+{
+ u8 rc;
+ vars->phy_flags |= PHY_SGMII_FLAG;
+ bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
+ bnx2x_set_aer_mmd_serdes(params->bp, phy);
+ rc = bnx2x_reset_unicore(params, phy, 1);
+ /* reset the SerDes and wait for reset bit return low */
+ if (rc != 0)
+ return rc;
+ bnx2x_set_aer_mmd_serdes(params->bp, phy);
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
- DP(NETIF_MSG_LINK, "XGXS 8072\n");
+ return rc;
+}
- /* Unset Low Power Mode and SW reset */
- /* Restore normal power mode*/
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
- MISC_REGISTERS_GPIO_OUTPUT_HIGH,
- params->port);
+static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
+{
+ u8 rc;
+ vars->phy_flags = PHY_XGXS_FLAG;
+ if ((phy->req_line_speed &&
+ ((phy->req_line_speed == SPEED_100) ||
+ (phy->req_line_speed == SPEED_10))) ||
+ (!phy->req_line_speed &&
+ (phy->speed_cap_mask >=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
+ (phy->speed_cap_mask <
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
+ ))
+ vars->phy_flags |= PHY_SGMII_FLAG;
+ else
+ vars->phy_flags &= ~PHY_SGMII_FLAG;
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CTRL,
- 1<<15);
- break;
+ bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
+ bnx2x_set_aer_mmd_xgxs(params, phy);
+ bnx2x_set_master_ln(params, phy);
+
+ rc = bnx2x_reset_unicore(params, phy, 0);
+ /* reset the SerDes and wait for reset bit return low */
+ if (rc != 0)
+ return rc;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
- DP(NETIF_MSG_LINK, "XGXS 8073\n");
+ bnx2x_set_aer_mmd_xgxs(params, phy);
- /* Restore normal power mode*/
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
- MISC_REGISTERS_GPIO_OUTPUT_HIGH,
- params->port);
+ /* setting the masterLn_def again after the reset */
+ bnx2x_set_master_ln(params, phy);
+ bnx2x_set_swap_lanes(params, phy);
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
- MISC_REGISTERS_GPIO_OUTPUT_HIGH,
- params->port);
+ return rc;
+}
+
+static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
+ struct bnx2x_phy *phy)
+{
+ u16 cnt, ctrl;
+ /* Wait for soft reset to get cleared upto 1 sec */
+ for (cnt = 0; cnt < 1000; cnt++) {
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, &ctrl);
+ if (!(ctrl & (1<<15)))
break;
+ msleep(1);
+ }
+ DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt);
+ return cnt;
+}
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
- DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
+static void bnx2x_link_int_enable(struct link_params *params)
+{
+ u8 port = params->port;
+ u32 mask;
+ struct bnx2x *bp = params->bp;
- /* Restore normal power mode*/
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
- MISC_REGISTERS_GPIO_OUTPUT_HIGH,
- params->port);
+ /* setting the status to report on link up
+ for either XGXS or SerDes */
- /* HW reset */
- bnx2x_ext_phy_hw_reset(bp, params->port);
- break;
+ if (params->switch_cfg == SWITCH_CFG_10G) {
+ mask = (NIG_MASK_XGXS0_LINK10G |
+ NIG_MASK_XGXS0_LINK_STATUS);
+ DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
+ if (!(SINGLE_MEDIA_DIRECT(params)) &&
+ params->phy[INT_PHY].type !=
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
+ mask |= NIG_MASK_MI_INT;
+ DP(NETIF_MSG_LINK, "enabled external phy int\n");
+ }
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
- /* Restore normal power mode*/
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
- MISC_REGISTERS_GPIO_OUTPUT_HIGH,
- params->port);
+ } else { /* SerDes */
+ mask = NIG_MASK_SERDES0_LINK_STATUS;
+ DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
+ if (!(SINGLE_MEDIA_DIRECT(params)) &&
+ params->phy[INT_PHY].type !=
+ PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
+ mask |= NIG_MASK_MI_INT;
+ DP(NETIF_MSG_LINK, "enabled external phy int\n");
+ }
+ }
+ bnx2x_bits_en(bp,
+ NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+ mask);
+
+ DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
+ (params->switch_cfg == SWITCH_CFG_10G),
+ REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
+ DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
+ REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
+ REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
+ REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
+ DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
+ REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
+ REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
+}
- /* HW reset */
- bnx2x_ext_phy_hw_reset(bp, params->port);
+static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port,
+ u8 exp_mi_int)
+{
+ u32 latch_status = 0;
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CTRL,
- 1<<15);
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
- DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n");
- break;
+ /**
+ * Disable the MI INT ( external phy int ) by writing 1 to the
+ * status register. Link down indication is high-active-signal,
+ * so in this case we need to write the status to clear the XOR
+ */
+ /* Read Latched signals */
+ latch_status = REG_RD(bp,
+ NIG_REG_LATCH_STATUS_0 + port*8);
+ DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status);
+ /* Handle only those with latched-signal=up.*/
+ if (exp_mi_int)
+ bnx2x_bits_en(bp,
+ NIG_REG_STATUS_INTERRUPT_PORT0
+ + port*4,
+ NIG_STATUS_EMAC0_MI_INT);
+ else
+ bnx2x_bits_dis(bp,
+ NIG_REG_STATUS_INTERRUPT_PORT0
+ + port*4,
+ NIG_STATUS_EMAC0_MI_INT);
- default:
- DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
- params->ext_phy_config);
- break;
+ if (latch_status & 1) {
+
+ /* For all latched-signal=up : Re-Arm Latch signals */
+ REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
+ (latch_status & 0xfffe) | (latch_status & 1));
+ }
+ /* For all latched-signal=up,Write original_signal to status */
+}
+
+static void bnx2x_link_int_ack(struct link_params *params,
+ struct link_vars *vars, u8 is_10g)
+{
+ struct bnx2x *bp = params->bp;
+ u8 port = params->port;
+
+ /* first reset all status
+ * we assume only one line will be change at a time */
+ bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
+ (NIG_STATUS_XGXS0_LINK10G |
+ NIG_STATUS_XGXS0_LINK_STATUS |
+ NIG_STATUS_SERDES0_LINK_STATUS));
+ if (vars->phy_link_up) {
+ if (is_10g) {
+ /* Disable the 10G link interrupt
+ * by writing 1 to the status register
+ */
+ DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
+ bnx2x_bits_en(bp,
+ NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
+ NIG_STATUS_XGXS0_LINK10G);
+
+ } else if (params->switch_cfg == SWITCH_CFG_10G) {
+ /* Disable the link interrupt
+ * by writing 1 to the relevant lane
+ * in the status register
+ */
+ u32 ser_lane = ((params->lane_config &
+ PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
+ PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
+
+ DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
+ vars->line_speed);
+ bnx2x_bits_en(bp,
+ NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
+ ((1 << ser_lane) <<
+ NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
+
+ } else { /* SerDes */
+ DP(NETIF_MSG_LINK, "SerDes phy link up\n");
+ /* Disable the link interrupt
+ * by writing 1 to the status register
+ */
+ bnx2x_bits_en(bp,
+ NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
+ NIG_STATUS_SERDES0_LINK_STATUS);
}
- } else { /* SerDes */
- ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
- switch (ext_phy_type) {
- case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
- DP(NETIF_MSG_LINK, "SerDes Direct\n");
- break;
+ }
+}
+
+static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len)
+{
+ u8 *str_ptr = str;
+ u32 mask = 0xf0000000;
+ u8 shift = 8*4;
+ u8 digit;
+ u8 remove_leading_zeros = 1;
+ if (*len < 10) {
+ /* Need more than 10chars for this format */
+ *str_ptr = '\0';
+ (*len)--;
+ return -EINVAL;
+ }
+ while (shift > 0) {
+
+ shift -= 4;
+ digit = ((num & mask) >> shift);
+ if (digit == 0 && remove_leading_zeros) {
+ mask = mask >> 4;
+ continue;
+ } else if (digit < 0xa)
+ *str_ptr = digit + '0';
+ else
+ *str_ptr = digit - 0xa + 'a';
+ remove_leading_zeros = 0;
+ str_ptr++;
+ (*len)--;
+ mask = mask >> 4;
+ if (shift == 4*4) {
+ *str_ptr = '.';
+ str_ptr++;
+ (*len)--;
+ remove_leading_zeros = 1;
+ }
+ }
+ return 0;
+}
+
+
+static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
+{
+ str[0] = '\0';
+ (*len)--;
+ return 0;
+}
+
+u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
+ u8 *version, u16 len)
+{
+ struct bnx2x *bp;
+ u32 spirom_ver = 0;
+ u8 status = 0;
+ u8 *ver_p = version;
+ u16 remain_len = len;
+ if (version == NULL || params == NULL)
+ return -EINVAL;
+ bp = params->bp;
+
+ /* Extract first external phy*/
+ version[0] = '\0';
+ spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
+
+ if (params->phy[EXT_PHY1].format_fw_ver) {
+ status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
+ ver_p,
+ &remain_len);
+ ver_p += (len - remain_len);
+ }
+ if ((params->num_phys == MAX_PHYS) &&
+ (params->phy[EXT_PHY2].ver_addr != 0)) {
+ spirom_ver = REG_RD(bp,
+ params->phy[EXT_PHY2].ver_addr);
+ if (params->phy[EXT_PHY2].format_fw_ver) {
+ *ver_p = '/';
+ ver_p++;
+ remain_len--;
+ status |= params->phy[EXT_PHY2].format_fw_ver(
+ spirom_ver,
+ ver_p,
+ &remain_len);
+ ver_p = version + (len - remain_len);
+ }
+ }
+ *ver_p = '\0';
+ return status;
+}
+
+static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
+ struct link_params *params)
+{
+ u8 port = params->port;
+ struct bnx2x *bp = params->bp;
+
+ if (phy->req_line_speed != SPEED_1000) {
+ u32 md_devad;
- case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
- DP(NETIF_MSG_LINK, "SerDes 5482\n");
- bnx2x_ext_phy_hw_reset(bp, params->port);
+ DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
+
+ /* change the uni_phy_addr in the nig */
+ md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
+ port*0x18));
+
+ REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
+
+ bnx2x_cl45_write(bp, phy,
+ 5,
+ (MDIO_REG_BANK_AER_BLOCK +
+ (MDIO_AER_BLOCK_AER_REG & 0xf)),
+ 0x2800);
+
+ bnx2x_cl45_write(bp, phy,
+ 5,
+ (MDIO_REG_BANK_CL73_IEEEB0 +
+ (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
+ 0x6041);
+ msleep(200);
+ /* set aer mmd back */
+ bnx2x_set_aer_mmd_xgxs(params, phy);
+
+ /* and md_devad */
+ REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
+ md_devad);
+
+ } else {
+ u16 mii_ctrl;
+ DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
+ bnx2x_cl45_read(bp, phy, 5,
+ (MDIO_REG_BANK_COMBO_IEEE0 +
+ (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
+ &mii_ctrl);
+ bnx2x_cl45_write(bp, phy, 5,
+ (MDIO_REG_BANK_COMBO_IEEE0 +
+ (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
+ mii_ctrl |
+ MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
+ }
+}
+
+u8 bnx2x_set_led(struct link_params *params,
+ struct link_vars *vars, u8 mode, u32 speed)
+{
+ u8 port = params->port;
+ u16 hw_led_mode = params->hw_led_mode;
+ u8 rc = 0, phy_idx;
+ u32 tmp;
+ u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+ struct bnx2x *bp = params->bp;
+ DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
+ DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
+ speed, hw_led_mode);
+ /* In case */
+ for (phy_idx = EXT_PHY1; phy_idx < MAX_PHYS; phy_idx++) {
+ if (params->phy[phy_idx].set_link_led) {
+ params->phy[phy_idx].set_link_led(
+ &params->phy[phy_idx], params, mode);
+ }
+ }
+
+ switch (mode) {
+ case LED_MODE_FRONT_PANEL_OFF:
+ case LED_MODE_OFF:
+ REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
+ REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
+ SHARED_HW_CFG_LED_MAC1);
+
+ tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
+ EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
+ break;
+
+ case LED_MODE_OPER:
+ /**
+ * For all other phys, OPER mode is same as ON, so in case
+ * link is down, do nothing
+ **/
+ if (!vars->link_up)
break;
+ case LED_MODE_ON:
+ if (SINGLE_MEDIA_DIRECT(params)) {
+ /**
+ * This is a work-around for HW issue found when link
+ * is up in CL73
+ */
+ REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
+ REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
+ } else {
+ REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
+ hw_led_mode);
+ }
- default:
- DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
- params->ext_phy_config);
+ REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
+ port*4, 0);
+ /* Set blinking rate to ~15.9Hz */
+ REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
+ LED_BLINK_RATE_VAL);
+ REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
+ port*4, 1);
+ tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
+ EMAC_WR(bp, EMAC_REG_EMAC_LED,
+ (tmp & (~EMAC_LED_OVERRIDE)));
+
+ if (CHIP_IS_E1(bp) &&
+ ((speed == SPEED_2500) ||
+ (speed == SPEED_1000) ||
+ (speed == SPEED_100) ||
+ (speed == SPEED_10))) {
+ /* On Everest 1 Ax chip versions for speeds less than
+ 10G LED scheme is different */
+ REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
+ + port*4, 1);
+ REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
+ port*4, 0);
+ REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
+ port*4, 1);
+ }
+ break;
+
+ default:
+ rc = -EINVAL;
+ DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
+ mode);
+ break;
+ }
+ return rc;
+
+}
+
+/**
+ * This function comes to reflect the actual link state read DIRECTLY from the
+ * HW
+ */
+u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars,
+ u8 is_serdes)
+{
+ struct bnx2x *bp = params->bp;
+ u16 gp_status = 0, phy_index = 0;
+ u8 ext_phy_link_up = 0, serdes_phy_type;
+ struct link_vars temp_vars;
+
+ CL45_RD_OVER_CL22(bp, &params->phy[INT_PHY],
+ MDIO_REG_BANK_GP_STATUS,
+ MDIO_GP_STATUS_TOP_AN_STATUS1,
+ &gp_status);
+ /* link is up only if both local phy and external phy are up */
+ if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS))
+ return -ESRCH;
+
+ switch (params->num_phys) {
+ case 1:
+ /* No external PHY */
+ return 0;
+ case 2:
+ ext_phy_link_up = params->phy[EXT_PHY1].read_status(
+ &params->phy[EXT_PHY1],
+ params, &temp_vars);
+ break;
+ case 3: /* Dual Media */
+ for (phy_index = EXT_PHY1; phy_index < params->num_phys;
+ phy_index++) {
+ serdes_phy_type = ((params->phy[phy_index].media_type ==
+ ETH_PHY_SFP_FIBER) ||
+ (params->phy[phy_index].media_type ==
+ ETH_PHY_XFP_FIBER));
+
+ if (is_serdes != serdes_phy_type)
+ continue;
+ if (params->phy[phy_index].read_status) {
+ ext_phy_link_up |=
+ params->phy[phy_index].read_status(
+ &params->phy[phy_index],
+ params, &temp_vars);
+ }
+ }
+ break;
+ }
+ if (ext_phy_link_up)
+ return 0;
+ return -ESRCH;
+}
+
+static u8 bnx2x_link_initialize(struct link_params *params,
+ struct link_vars *vars)
+{
+ u8 rc = 0;
+ u8 phy_index, non_ext_phy;
+ struct bnx2x *bp = params->bp;
+ /**
+ * In case of external phy existence, the line speed would be the
+ * line speed linked up by the external phy. In case it is direct
+ * only, then the line_speed during initialization will be
+ * equal to the req_line_speed
+ */
+ vars->line_speed = params->phy[INT_PHY].req_line_speed;
+
+ /**
+ * Initialize the internal phy in case this is a direct board
+ * (no external phys), or this board has external phy which requires
+ * to first.
+ */
+
+ if (params->phy[INT_PHY].config_init)
+ params->phy[INT_PHY].config_init(
+ &params->phy[INT_PHY],
+ params, vars);
+
+ /* init ext phy and enable link state int */
+ non_ext_phy = (SINGLE_MEDIA_DIRECT(params) ||
+ (params->loopback_mode == LOOPBACK_XGXS));
+
+ if (non_ext_phy ||
+ (params->phy[EXT_PHY1].flags & FLAGS_INIT_XGXS_FIRST) ||
+ (params->loopback_mode == LOOPBACK_EXT_PHY)) {
+ struct bnx2x_phy *phy = &params->phy[INT_PHY];
+ if (vars->line_speed == SPEED_AUTO_NEG)
+ bnx2x_set_parallel_detection(phy, params);
+ bnx2x_init_internal_phy(phy, params, vars);
+ }
+
+ /* Init external phy*/
+ if (!non_ext_phy)
+ for (phy_index = EXT_PHY1; phy_index < params->num_phys;
+ phy_index++) {
+ /**
+ * No need to initialize second phy in case of first
+ * phy only selection. In case of second phy, we do
+ * need to initialize the first phy, since they are
+ * connected.
+ **/
+ 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");
+ continue;
+ }
+ params->phy[phy_index].config_init(
+ &params->phy[phy_index],
+ params, vars);
+ }
+
+ /* Reset the interrupt indication after phy was initialized */
+ bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
+ params->port*4,
+ (NIG_STATUS_XGXS0_LINK10G |
+ NIG_STATUS_XGXS0_LINK_STATUS |
+ NIG_STATUS_SERDES0_LINK_STATUS |
+ NIG_MASK_MI_INT));
+ return rc;
+}
+
+static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
+ struct link_params *params)
+{
+ /* reset the SerDes/XGXS */
+ REG_WR(params->bp, GRCBASE_MISC +
+ MISC_REGISTERS_RESET_REG_3_CLEAR,
+ (0x1ff << (params->port*16)));
+}
+
+static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
+ struct link_params *params)
+{
+ struct bnx2x *bp = params->bp;
+ u8 gpio_port;
+ /* HW reset */
+ if (CHIP_IS_E2(bp))
+ gpio_port = BP_PATH(bp);
+ else
+ gpio_port = params->port;
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW,
+ gpio_port);
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW,
+ gpio_port);
+ DP(NETIF_MSG_LINK, "reset external PHY\n");
+}
+
+static u8 bnx2x_update_link_down(struct link_params *params,
+ struct link_vars *vars)
+{
+ struct bnx2x *bp = params->bp;
+ u8 port = params->port;
+
+ DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
+ bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
+
+ /* indicate no mac active */
+ vars->mac_type = MAC_TYPE_NONE;
+
+ /* update shared memory */
+ vars->link_status = 0;
+ vars->line_speed = 0;
+ bnx2x_update_mng(params, vars->link_status);
+
+ /* activate nig drain */
+ REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
+
+ /* disable emac */
+ REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
+
+ msleep(10);
+
+ /* reset BigMac */
+ bnx2x_bmac_rx_disable(bp, params->port);
+ REG_WR(bp, GRCBASE_MISC +
+ MISC_REGISTERS_RESET_REG_2_CLEAR,
+ (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
+ return 0;
+}
+
+static u8 bnx2x_update_link_up(struct link_params *params,
+ struct link_vars *vars,
+ u8 link_10g)
+{
+ struct bnx2x *bp = params->bp;
+ u8 port = params->port;
+ u8 rc = 0;
+
+ vars->link_status |= LINK_STATUS_LINK_UP;
+
+ if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
+ vars->link_status |=
+ LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
+
+ if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
+ vars->link_status |=
+ LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
+
+ if (link_10g) {
+ bnx2x_bmac_enable(params, vars, 0);
+ bnx2x_set_led(params, vars,
+ LED_MODE_OPER, SPEED_10000);
+ } else {
+ rc = bnx2x_emac_program(params, vars);
+
+ bnx2x_emac_enable(params, vars, 0);
+
+ /* AN complete? */
+ if ((vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
+ && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
+ SINGLE_MEDIA_DIRECT(params))
+ bnx2x_set_gmii_tx_driver(params);
+ }
+
+ /* PBF - link up */
+ if (!(CHIP_IS_E2(bp)))
+ rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
+ vars->line_speed);
+
+ /* disable drain */
+ REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
+
+ /* update shared memory */
+ bnx2x_update_mng(params, vars->link_status);
+ msleep(20);
+ return rc;
+}
+/**
+ * The bnx2x_link_update function should be called upon link
+ * interrupt.
+ * Link is considered up as follows:
+ * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
+ * to be up
+ * - SINGLE_MEDIA - The link between the 577xx and the external
+ * phy (XGXS) need to up as well as the external link of the
+ * phy (PHY_EXT1)
+ * - DUAL_MEDIA - The link between the 577xx and the first
+ * external phy needs to be up, and at least one of the 2
+ * external phy link must be up.
+ */
+u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
+{
+ struct bnx2x *bp = params->bp;
+ struct link_vars phy_vars[MAX_PHYS];
+ u8 port = params->port;
+ u8 link_10g, phy_index;
+ u8 ext_phy_link_up = 0, cur_link_up, rc = 0;
+ u8 is_mi_int = 0;
+ u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
+ u8 active_external_phy = INT_PHY;
+ vars->link_status = 0;
+ for (phy_index = INT_PHY; phy_index < params->num_phys;
+ phy_index++) {
+ phy_vars[phy_index].flow_ctrl = 0;
+ phy_vars[phy_index].link_status = 0;
+ phy_vars[phy_index].line_speed = 0;
+ phy_vars[phy_index].duplex = DUPLEX_FULL;
+ phy_vars[phy_index].phy_link_up = 0;
+ phy_vars[phy_index].link_up = 0;
+ }
+
+ DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
+ port, (vars->phy_flags & PHY_XGXS_FLAG),
+ REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
+
+ is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
+ port*0x18) > 0);
+ DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
+ REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
+ is_mi_int,
+ REG_RD(bp,
+ NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
+
+ DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
+ REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
+ REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
+
+ /* disable emac */
+ REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
+
+ /**
+ * Step 1:
+ * Check external link change only for external phys, and apply
+ * priority selection between them in case the link on both phys
+ * is up. Note that the instead of the common vars, a temporary
+ * vars argument is used since each phy may have different link/
+ * speed/duplex result
+ */
+ for (phy_index = EXT_PHY1; phy_index < params->num_phys;
+ phy_index++) {
+ struct bnx2x_phy *phy = &params->phy[phy_index];
+ if (!phy->read_status)
+ continue;
+ /* Read link status and params of this ext phy */
+ cur_link_up = phy->read_status(phy, params,
+ &phy_vars[phy_index]);
+ if (cur_link_up) {
+ DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
+ phy_index);
+ } else {
+ DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
+ phy_index);
+ continue;
+ }
+
+ if (!ext_phy_link_up) {
+ ext_phy_link_up = 1;
+ active_external_phy = phy_index;
+ } else {
+ switch (bnx2x_phy_selection(params)) {
+ case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
+ case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
+ /**
+ * In this option, the first PHY makes sure to pass the
+ * traffic through itself only.
+ * Its not clear how to reset the link on the second phy
+ **/
+ active_external_phy = EXT_PHY1;
+ break;
+ case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
+ /**
+ * In this option, the first PHY makes sure to pass the
+ * traffic through the second PHY.
+ **/
+ active_external_phy = EXT_PHY2;
+ break;
+ default:
+ /**
+ * Link indication on both PHYs with the following cases
+ * is invalid:
+ * - FIRST_PHY means that second phy wasn't initialized,
+ * hence its link is expected to be down
+ * - SECOND_PHY means that first phy should not be able
+ * to link up by itself (using configuration)
+ * - DEFAULT should be overriden during initialiazation
+ **/
+ DP(NETIF_MSG_LINK, "Invalid link indication"
+ "mpc=0x%x. DISABLING LINK !!!\n",
+ params->multi_phy_config);
+ ext_phy_link_up = 0;
+ break;
+ }
+ }
+ }
+ prev_line_speed = vars->line_speed;
+ /**
+ * Step 2:
+ * Read the status of the internal phy. In case of
+ * DIRECT_SINGLE_MEDIA board, this link is the external link,
+ * otherwise this is the link between the 577xx and the first
+ * external phy
+ */
+ if (params->phy[INT_PHY].read_status)
+ params->phy[INT_PHY].read_status(
+ &params->phy[INT_PHY],
+ params, vars);
+ /**
+ * The INT_PHY flow control reside in the vars. This include the
+ * case where the speed or flow control are not set to AUTO.
+ * Otherwise, the active external phy flow control result is set
+ * to the vars. The ext_phy_line_speed is needed to check if the
+ * speed is different between the internal phy and external phy.
+ * This case may be result of intermediate link speed change.
+ */
+ if (active_external_phy > INT_PHY) {
+ vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
+ /**
+ * Link speed is taken from the XGXS. AN and FC result from
+ * the external phy.
+ */
+ vars->link_status |= phy_vars[active_external_phy].link_status;
+
+ /**
+ * if active_external_phy is first PHY and link is up - disable
+ * disable TX on second external PHY
+ */
+ if (active_external_phy == EXT_PHY1) {
+ if (params->phy[EXT_PHY2].phy_specific_func) {
+ DP(NETIF_MSG_LINK, "Disabling TX on"
+ " EXT_PHY2\n");
+ params->phy[EXT_PHY2].phy_specific_func(
+ &params->phy[EXT_PHY2],
+ params, DISABLE_TX);
+ }
+ }
+
+ ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
+ vars->duplex = phy_vars[active_external_phy].duplex;
+ if (params->phy[active_external_phy].supported &
+ SUPPORTED_FIBRE)
+ vars->link_status |= LINK_STATUS_SERDES_LINK;
+ DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
+ active_external_phy);
+ }
+
+ for (phy_index = EXT_PHY1; phy_index < params->num_phys;
+ phy_index++) {
+ if (params->phy[phy_index].flags &
+ FLAGS_REARM_LATCH_SIGNAL) {
+ bnx2x_rearm_latch_signal(bp, port,
+ phy_index ==
+ active_external_phy);
break;
}
}
+ DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
+ " ext_phy_line_speed = %d\n", vars->flow_ctrl,
+ vars->link_status, ext_phy_line_speed);
+ /**
+ * Upon link speed change set the NIG into drain mode. Comes to
+ * deals with possible FIFO glitch due to clk change when speed
+ * is decreased without link down indicator
+ */
+
+ if (vars->phy_link_up) {
+ if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
+ (ext_phy_line_speed != vars->line_speed)) {
+ DP(NETIF_MSG_LINK, "Internal link speed %d is"
+ " different than the external"
+ " link speed %d\n", vars->line_speed,
+ ext_phy_line_speed);
+ vars->phy_link_up = 0;
+ } else if (prev_line_speed != vars->line_speed) {
+ REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
+ + params->port*4, 0);
+ msleep(1);
+ }
+ }
+
+ /* anything 10 and over uses the bmac */
+ link_10g = ((vars->line_speed == SPEED_10000) ||
+ (vars->line_speed == SPEED_12000) ||
+ (vars->line_speed == SPEED_12500) ||
+ (vars->line_speed == SPEED_13000) ||
+ (vars->line_speed == SPEED_15000) ||
+ (vars->line_speed == SPEED_16000));
+
+ bnx2x_link_int_ack(params, vars, link_10g);
+
+ /**
+ * In case external phy link is up, and internal link is down
+ * (not initialized yet probably after link initialization, it
+ * needs to be initialized.
+ * Note that after link down-up as result of cable plug, the xgxs
+ * link would probably become up again without the need
+ * initialize it
+ */
+ if (!(SINGLE_MEDIA_DIRECT(params))) {
+ DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
+ " init_preceding = %d\n", ext_phy_link_up,
+ vars->phy_link_up,
+ params->phy[EXT_PHY1].flags &
+ FLAGS_INIT_XGXS_FIRST);
+ if (!(params->phy[EXT_PHY1].flags &
+ FLAGS_INIT_XGXS_FIRST)
+ && ext_phy_link_up && !vars->phy_link_up) {
+ vars->line_speed = ext_phy_line_speed;
+ if (vars->line_speed < SPEED_1000)
+ vars->phy_flags |= PHY_SGMII_FLAG;
+ else
+ vars->phy_flags &= ~PHY_SGMII_FLAG;
+ bnx2x_init_internal_phy(&params->phy[INT_PHY],
+ params,
+ vars);
+ }
+ }
+ /**
+ * Link is up only if both local phy and external phy (in case of
+ * non-direct board) are up
+ */
+ vars->link_up = (vars->phy_link_up &&
+ (ext_phy_link_up ||
+ SINGLE_MEDIA_DIRECT(params)));
+
+ if (vars->link_up)
+ rc = bnx2x_update_link_up(params, vars, link_10g);
+ else
+ rc = bnx2x_update_link_down(params, vars);
+
+ return rc;
+}
+
+
+/*****************************************************************************/
+/* External Phy section */
+/*****************************************************************************/
+void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
+{
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
+ msleep(1);
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+ MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
}
static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
- u32 shmem_base, u32 spirom_ver)
+ u32 spirom_ver, u32 ver_addr)
{
DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
(u16)(spirom_ver>>16), (u16)spirom_ver, port);
- REG_WR(bp, shmem_base +
- offsetof(struct shmem_region,
- port_mb[port].ext_phy_fw_version),
- spirom_ver);
+
+ if (ver_addr)
+ REG_WR(bp, ver_addr, spirom_ver);
}
-static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port,
- u32 ext_phy_type, u8 ext_phy_addr,
- u32 shmem_base)
+static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp,
+ struct bnx2x_phy *phy,
+ u8 port)
{
u16 fw_ver1, fw_ver2;
- bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
+ bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER1, &fw_ver1);
- bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
+ bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER2, &fw_ver2);
- bnx2x_save_spirom_version(bp, port, shmem_base,
- (u32)(fw_ver1<<16 | fw_ver2));
+ bnx2x_save_spirom_version(bp, port, (u32)(fw_ver1<<16 | fw_ver2),
+ phy->ver_addr);
}
-
-static void bnx2x_save_8481_spirom_version(struct bnx2x *bp, u8 port,
- u8 ext_phy_addr, u32 shmem_base)
+static void bnx2x_ext_phy_set_pause(struct link_params *params,
+ struct bnx2x_phy *phy,
+ struct link_vars *vars)
{
- u16 val, fw_ver1, fw_ver2, cnt;
- /* For the 32 bits registers in 8481, access via MDIO2ARM interface.*/
- /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
- ext_phy_addr, MDIO_PMA_DEVAD,
- 0xA819, 0x0014);
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- 0xA81A,
- 0xc200);
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- 0xA81B,
- 0x0000);
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- 0xA81C,
- 0x0300);
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- 0xA817,
- 0x0009);
+ u16 val;
+ struct bnx2x *bp = params->bp;
+ /* read modify write pause advertizing */
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
- for (cnt = 0; cnt < 100; cnt++) {
- bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- 0xA818,
- &val);
- if (val & 1)
- break;
- udelay(5);
+ val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
+
+ /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
+ bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
+ if ((vars->ieee_fc &
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
+ val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
}
- if (cnt == 100) {
- DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(1)\n");
- bnx2x_save_spirom_version(bp, port,
- shmem_base, 0);
- return;
+ if ((vars->ieee_fc &
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
+ val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
}
+ DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
+}
+static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
+{
+ struct bnx2x *bp = params->bp;
+ u16 ld_pause; /* local */
+ u16 lp_pause; /* link partner */
+ u16 pause_result;
+ u8 ret = 0;
+ /* read twice */
- /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
- ext_phy_addr, MDIO_PMA_DEVAD,
- 0xA819, 0x0000);
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
- ext_phy_addr, MDIO_PMA_DEVAD,
- 0xA81A, 0xc200);
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
- ext_phy_addr, MDIO_PMA_DEVAD,
- 0xA817, 0x000A);
- for (cnt = 0; cnt < 100; cnt++) {
- bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- 0xA818,
- &val);
- if (val & 1)
- break;
- udelay(5);
+ vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+
+ if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
+ vars->flow_ctrl = phy->req_flow_ctrl;
+ else if (phy->req_line_speed != SPEED_AUTO_NEG)
+ vars->flow_ctrl = params->req_fc_auto_adv;
+ else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
+ ret = 1;
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_ADV_PAUSE, &ld_pause);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
+ pause_result = (ld_pause &
+ MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
+ pause_result |= (lp_pause &
+ MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
+ DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
+ pause_result);
+ bnx2x_pause_resolve(vars, pause_result);
}
- if (cnt == 100) {
- DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(2)\n");
- bnx2x_save_spirom_version(bp, port,
- shmem_base, 0);
+ return ret;
+}
+
+static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
+ struct bnx2x_phy *phy,
+ struct link_vars *vars)
+{
+ u16 val;
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_STATUS, &val);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_STATUS, &val);
+ if (val & (1<<5))
+ vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
+ if ((val & (1<<0)) == 0)
+ vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED;
+}
+
+/******************************************************************/
+/* common BCM8073/BCM8727 PHY SECTION */
+/******************************************************************/
+static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
+{
+ struct bnx2x *bp = params->bp;
+ if (phy->req_line_speed == SPEED_10 ||
+ phy->req_line_speed == SPEED_100) {
+ vars->flow_ctrl = phy->req_flow_ctrl;
return;
}
- /* lower 16 bits of the register SPI_FW_STATUS */
- bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- 0xA81B,
- &fw_ver1);
- /* upper 16 bits of register SPI_FW_STATUS */
- bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- 0xA81C,
- &fw_ver2);
+ if (bnx2x_ext_phy_resolve_fc(phy, params, vars) &&
+ (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) {
+ u16 pause_result;
+ u16 ld_pause; /* local */
+ u16 lp_pause; /* link partner */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_CL37_FC_LD, &ld_pause);
+
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_CL37_FC_LP, &lp_pause);
+ pause_result = (ld_pause &
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
+ pause_result |= (lp_pause &
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
- bnx2x_save_spirom_version(bp, port,
- shmem_base, (fw_ver2<<16) | fw_ver1);
+ bnx2x_pause_resolve(vars, pause_result);
+ DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
+ pause_result);
+ }
}
-static void bnx2x_bcm8072_external_rom_boot(struct link_params *params)
+static void bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
+ struct bnx2x_phy *phy,
+ u8 port)
{
- struct bnx2x *bp = params->bp;
- u8 port = params->port;
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
- u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+ /* Boot port from external ROM */
+ /* EDC grst */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_GEN_CTRL,
+ 0x0001);
- /* Need to wait 200ms after reset */
- msleep(200);
- /* Boot port from external ROM
- * Set ser_boot_ctl bit in the MISC_CTRL1 register
- */
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_MISC_CTRL1, 0x0001);
+ /* ucode reboot and rst */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_GEN_CTRL,
+ 0x008c);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_MISC_CTRL1, 0x0001);
/* Reset internal microprocessor */
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_GEN_CTRL,
- MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
- /* set micro reset = 0 */
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_GEN_CTRL,
- MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
- /* Reset internal microprocessor */
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_GEN_CTRL,
- MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
- /* wait for 100ms for code download via SPI port */
- msleep(100);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_GEN_CTRL,
+ MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
+
+ /* Release srst bit */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_GEN_CTRL,
+ MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
+
+ /* wait for 120ms for code download via SPI port */
+ msleep(120);
/* Clear ser_boot_ctl bit */
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_MISC_CTRL1, 0x0000);
- /* Wait 100ms */
- msleep(100);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_MISC_CTRL1, 0x0000);
+ bnx2x_save_bcm_spirom_ver(bp, phy, port);
+}
+
+static void bnx2x_8073_set_xaui_low_power_mode(struct bnx2x *bp,
+ struct bnx2x_phy *phy)
+{
+ u16 val;
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV, &val);
+
+ if (val == 0) {
+ /* Mustn't set low power mode in 8073 A0 */
+ return;
+ }
+
+ /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
+ val &= ~(1<<13);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
+
+ /* PLL controls */
+ bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805E, 0x1077);
+ bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805D, 0x0000);
+ bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805C, 0x030B);
+ bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805B, 0x1240);
+ bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805A, 0x2490);
+
+ /* Tx Controls */
+ bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A7, 0x0C74);
+ bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A6, 0x9041);
+ bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A5, 0x4640);
+
+ /* Rx Controls */
+ bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FE, 0x01C4);
+ bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FD, 0x9249);
+ bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FC, 0x2015);
- bnx2x_save_bcm_spirom_ver(bp, port,
- ext_phy_type,
- ext_phy_addr,
- params->shmem_base);
+ /* Enable PLL sequencer (use read-modify-write to set bit 13) */
+ bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
+ val |= (1<<13);
+ bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
}
-static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
+/******************************************************************/
+/* BCM8073 PHY SECTION */
+/******************************************************************/
+static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
{
/* This is only required for 8073A1, version 102 only */
-
- struct bnx2x *bp = params->bp;
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
u16 val;
/* Read 8073 HW revision*/
- bnx2x_cl45_read(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8073_CHIP_REV, &val);
@@ -2431,9 +3374,7 @@ static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
return 0;
}
- bnx2x_cl45_read(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER2, &val);
@@ -2444,15 +3385,11 @@ static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
return 1;
}
-static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
+static u8 bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
{
- struct bnx2x *bp = params->bp;
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
u16 val, cnt, cnt1 ;
- bnx2x_cl45_read(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8073_CHIP_REV, &val);
@@ -2466,9 +3403,7 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
poll Dev1, Reg $C820: */
for (cnt = 0; cnt < 1000; cnt++) {
- bnx2x_cl45_read(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
&val);
@@ -2485,9 +3420,7 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
XAUI workaround has completed),
then continue on with system initialization.*/
for (cnt1 = 0; cnt1 < 1000; cnt1++) {
- bnx2x_cl45_read(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8073_XAUI_WA, &val);
if (val & (1<<15)) {
@@ -2505,143 +3438,391 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
return -EINVAL;
}
-static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
- u8 ext_phy_addr,
- u32 ext_phy_type,
- u32 shmem_base)
+static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy)
{
- /* Boot port from external ROM */
- /* EDC grst */
- bnx2x_cl45_write(bp, port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_GEN_CTRL,
- 0x0001);
+ /* Force KR or KX */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
+}
- /* ucode reboot and rst */
- bnx2x_cl45_write(bp, port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_GEN_CTRL,
- 0x008c);
+static void bnx2x_8073_set_pause_cl37(struct link_params *params,
+ struct bnx2x_phy *phy,
+ struct link_vars *vars)
+{
+ u16 cl37_val;
+ struct bnx2x *bp = params->bp;
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val);
- bnx2x_cl45_write(bp, port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_MISC_CTRL1, 0x0001);
+ cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+ /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
+ bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
+ if ((vars->ieee_fc &
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
+ cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
+ }
+ if ((vars->ieee_fc &
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
+ cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+ }
+ if ((vars->ieee_fc &
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
+ cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+ }
+ DP(NETIF_MSG_LINK,
+ "Ext phy AN advertize cl37 0x%x\n", cl37_val);
- /* Reset internal microprocessor */
- bnx2x_cl45_write(bp, port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_GEN_CTRL,
- MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val);
+ msleep(500);
+}
- /* Release srst bit */
- bnx2x_cl45_write(bp, port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_GEN_CTRL,
- MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
+static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
+{
+ struct bnx2x *bp = params->bp;
+ u16 val = 0, tmp1;
+ u8 gpio_port;
+ DP(NETIF_MSG_LINK, "Init 8073\n");
- /* wait for 100ms for code download via SPI port */
- msleep(100);
+ if (CHIP_IS_E2(bp))
+ gpio_port = BP_PATH(bp);
+ else
+ gpio_port = params->port;
+ /* Restore normal power mode*/
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+ MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
- /* Clear ser_boot_ctl bit */
- bnx2x_cl45_write(bp, port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_MISC_CTRL1, 0x0000);
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+ MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
- bnx2x_save_bcm_spirom_ver(bp, port,
- ext_phy_type,
- ext_phy_addr,
- shmem_base);
-}
+ /* enable LASI */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<2));
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x0004);
-static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
- u8 ext_phy_addr,
- u32 shmem_base)
-{
- bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- shmem_base);
-}
+ bnx2x_8073_set_pause_cl37(params, phy, vars);
-static void bnx2x_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
- u8 ext_phy_addr,
- u32 shmem_base)
-{
- bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- shmem_base);
+ bnx2x_8073_set_xaui_low_power_mode(bp, phy);
-}
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
-static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
-{
- struct bnx2x *bp = params->bp;
- u8 port = params->port;
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
- u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
- /* Need to wait 100ms after reset */
- msleep(100);
+ DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
- /* Micro controller re-boot */
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_GEN_CTRL,
- 0x018B);
+ /* Enable CL37 BAM */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_8073_BAM, &val);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_8073_BAM, val | 1);
- /* Set soft reset */
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_GEN_CTRL,
- MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
+ if (params->loopback_mode == LOOPBACK_EXT) {
+ bnx2x_807x_force_10G(bp, phy);
+ DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
+ return 0;
+ } else {
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
+ }
+ if (phy->req_line_speed != SPEED_AUTO_NEG) {
+ if (phy->req_line_speed == SPEED_10000) {
+ val = (1<<7);
+ } else if (phy->req_line_speed == SPEED_2500) {
+ val = (1<<5);
+ /* Note that 2.5G works only
+ when used with 1G advertisment */
+ } else
+ val = (1<<5);
+ } else {
+ val = 0;
+ if (phy->speed_cap_mask &
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
+ val |= (1<<7);
+
+ /* Note that 2.5G works only when
+ used with 1G advertisment */
+ if (phy->speed_cap_mask &
+ (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
+ val |= (1<<5);
+ DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
+ }
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_MISC_CTRL1, 0x0001);
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
+
+ if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
+ (phy->req_line_speed == SPEED_AUTO_NEG)) ||
+ (phy->req_line_speed == SPEED_2500)) {
+ u16 phy_ver;
+ /* Allow 2.5G for A1 and above */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
+ &phy_ver);
+ DP(NETIF_MSG_LINK, "Add 2.5G\n");
+ if (phy_ver > 0)
+ tmp1 |= 1;
+ else
+ tmp1 &= 0xfffe;
+ } else {
+ DP(NETIF_MSG_LINK, "Disable 2.5G\n");
+ tmp1 &= 0xfffe;
+ }
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_GEN_CTRL,
- MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
+ /* Add support for CL37 (passive mode) II */
- /* wait for 150ms for microcode load */
- msleep(150);
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
+ (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
+ 0x20 : 0x40)));
- /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_MISC_CTRL1, 0x0000);
+ /* Add support for CL37 (passive mode) III */
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
- msleep(200);
- bnx2x_save_bcm_spirom_ver(bp, port,
- ext_phy_type,
- ext_phy_addr,
- params->shmem_base);
+ /* The SNR will improve about 2db by changing
+ BW and FEE main tap. Rest commands are executed
+ after link is up*/
+ if (bnx2x_8073_is_snr_needed(bp, phy))
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
+ 0xFB0C);
+
+ /* Enable FEC (Forware Error Correction) Request in the AN */
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
+ tmp1 |= (1<<15);
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
+
+ bnx2x_ext_phy_set_pause(params, phy, vars);
+
+ /* Restart autoneg */
+ msleep(500);
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
+ DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
+ ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
+ return 0;
+}
+
+static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
+{
+ struct bnx2x *bp = params->bp;
+ u8 link_up = 0;
+ u16 val1, val2;
+ u16 link_status = 0;
+ u16 an1000_status = 0;
+
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
+
+ DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
+
+ /* clear the interrupt LASI status register */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
+ DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
+ /* Clear MSG-OUT */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
+
+ /* Check the LASI */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
+
+ DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
+
+ /* Check the link status */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
+ DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
+
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
+ link_up = ((val1 & 4) == 4);
+ DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
+
+ if (link_up &&
+ ((phy->req_line_speed != SPEED_10000))) {
+ if (bnx2x_8073_xaui_wa(bp, phy) != 0)
+ return 0;
+ }
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
+
+ /* Check the link status on 1.1.2 */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
+ DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
+ "an_link_status=0x%x\n", val2, val1, an1000_status);
+
+ link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
+ if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
+ /* The SNR will improve about 2dbby
+ changing the BW and FEE main tap.*/
+ /* The 1st write to change FFE main
+ tap is set before restart AN */
+ /* Change PLL Bandwidth in EDC
+ register */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
+ 0x26BC);
+
+ /* Change CDR Bandwidth in EDC register */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
+ 0x0333);
+ }
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
+ &link_status);
+
+ /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
+ if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
+ link_up = 1;
+ vars->line_speed = SPEED_10000;
+ DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
+ params->port);
+ } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
+ link_up = 1;
+ vars->line_speed = SPEED_2500;
+ DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
+ params->port);
+ } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
+ link_up = 1;
+ vars->line_speed = SPEED_1000;
+ DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
+ params->port);
+ } else {
+ link_up = 0;
+ DP(NETIF_MSG_LINK, "port %x: External link is down\n",
+ params->port);
+ }
+
+ if (link_up) {
+ bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
+ bnx2x_8073_resolve_fc(phy, params, vars);
+ }
+ return link_up;
}
-static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port,
- u32 ext_phy_type, u8 ext_phy_addr,
- u8 tx_en)
+static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
+ struct link_params *params)
+{
+ struct bnx2x *bp = params->bp;
+ u8 gpio_port;
+ if (CHIP_IS_E2(bp))
+ gpio_port = BP_PATH(bp);
+ else
+ gpio_port = params->port;
+ DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
+ gpio_port);
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW,
+ gpio_port);
+}
+
+/******************************************************************/
+/* BCM8705 PHY SECTION */
+/******************************************************************/
+static u8 bnx2x_8705_config_init(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
+{
+ struct bnx2x *bp = params->bp;
+ DP(NETIF_MSG_LINK, "init 8705\n");
+ /* Restore normal power mode*/
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+ MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
+ /* HW reset */
+ bnx2x_ext_phy_hw_reset(bp, params->port);
+ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
+ bnx2x_wait_reset_complete(bp, phy);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1);
+ /* BCM8705 doesn't have microcode, hence the 0 */
+ bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0);
+ return 0;
+}
+
+static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
+{
+ u8 link_up = 0;
+ u16 val1, rx_sd;
+ struct bnx2x *bp = params->bp;
+ DP(NETIF_MSG_LINK, "read status 8705\n");
+ bnx2x_cl45_read(bp, phy,
+ MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
+ DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
+
+ bnx2x_cl45_read(bp, phy,
+ MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
+ DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
+
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
+
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, 0xc809, &val1);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, 0xc809, &val1);
+
+ DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
+ link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
+ if (link_up) {
+ vars->line_speed = SPEED_10000;
+ bnx2x_ext_phy_resolve_fc(phy, params, vars);
+ }
+ return link_up;
+}
+
+/******************************************************************/
+/* SFP+ module Section */
+/******************************************************************/
+static void bnx2x_sfp_set_transmitter(struct bnx2x *bp,
+ struct bnx2x_phy *phy,
+ u8 port,
+ u8 tx_en)
{
u16 val;
DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
tx_en, port);
/* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
- bnx2x_cl45_read(bp, port,
- ext_phy_type,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER,
&val);
@@ -2651,58 +3832,42 @@ static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port,
else
val |= (1<<15);
- bnx2x_cl45_write(bp, port,
- ext_phy_type,
- ext_phy_addr,
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER,
val);
}
-static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params,
+static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
+ struct link_params *params,
u16 addr, u8 byte_cnt, u8 *o_buf)
{
struct bnx2x *bp = params->bp;
u16 val = 0;
u16 i;
- u8 port = params->port;
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
- u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
if (byte_cnt > 16) {
DP(NETIF_MSG_LINK, "Reading from eeprom is"
" is limited to 0xf\n");
return -EINVAL;
}
/* Set the read command byte count */
- bnx2x_cl45_write(bp, port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
(byte_cnt | 0xa000));
/* Set the read command address */
- bnx2x_cl45_write(bp, port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
addr);
/* Activate read command */
- bnx2x_cl45_write(bp, port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
0x2c0f);
/* Wait up to 500us for command complete status */
for (i = 0; i < 100; i++) {
- bnx2x_cl45_read(bp, port,
- ext_phy_type,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
@@ -2721,18 +3886,14 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params,
/* Read the buffer */
for (i = 0; i < byte_cnt; i++) {
- bnx2x_cl45_read(bp, port,
- ext_phy_type,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
}
for (i = 0; i < 100; i++) {
- bnx2x_cl45_read(bp, port,
- ext_phy_type,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
@@ -2743,14 +3904,12 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params,
return -EINVAL;
}
-static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
+static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
+ struct link_params *params,
u16 addr, u8 byte_cnt, u8 *o_buf)
{
struct bnx2x *bp = params->bp;
u16 val, i;
- u8 port = params->port;
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
- u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
if (byte_cnt > 16) {
DP(NETIF_MSG_LINK, "Reading from eeprom is"
@@ -2759,40 +3918,30 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
}
/* Need to read from 1.8000 to clear it */
- bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
&val);
/* Set the read command byte count */
- bnx2x_cl45_write(bp, port,
- ext_phy_type,
- ext_phy_addr,
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
((byte_cnt < 2) ? 2 : byte_cnt));
/* Set the read command address */
- bnx2x_cl45_write(bp, port,
- ext_phy_type,
- ext_phy_addr,
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
addr);
/* Set the destination address */
- bnx2x_cl45_write(bp, port,
- ext_phy_type,
- ext_phy_addr,
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
0x8004,
MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
/* Activate read command */
- bnx2x_cl45_write(bp, port,
- ext_phy_type,
- ext_phy_addr,
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
0x8002);
@@ -2802,9 +3951,7 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
/* Wait up to 500us for command complete status */
for (i = 0; i < 100; i++) {
- bnx2x_cl45_read(bp, port,
- ext_phy_type,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
@@ -2823,18 +3970,14 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
/* Read the buffer */
for (i = 0; i < byte_cnt; i++) {
- bnx2x_cl45_read(bp, port,
- ext_phy_type,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
}
for (i = 0; i < 100; i++) {
- bnx2x_cl45_read(bp, port,
- ext_phy_type,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
@@ -2846,21 +3989,21 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
return -EINVAL;
}
-u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
- u8 byte_cnt, u8 *o_buf)
+static u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
+ struct link_params *params, u16 addr,
+ u8 byte_cnt, u8 *o_buf)
{
- u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
- if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
- return bnx2x_8726_read_sfp_module_eeprom(params, addr,
+ if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
+ return bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
byte_cnt, o_buf);
- else if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
- return bnx2x_8727_read_sfp_module_eeprom(params, addr,
+ else if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
+ return bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
byte_cnt, o_buf);
return -EINVAL;
}
-static u8 bnx2x_get_edc_mode(struct link_params *params,
+static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
+ struct link_params *params,
u16 *edc_mode)
{
struct bnx2x *bp = params->bp;
@@ -2868,10 +4011,11 @@ static u8 bnx2x_get_edc_mode(struct link_params *params,
*edc_mode = EDC_MODE_LIMITING;
/* First check for copper cable */
- if (bnx2x_read_sfp_module_eeprom(params,
- SFP_EEPROM_CON_TYPE_ADDR,
- 1,
- &val) != 0) {
+ if (bnx2x_read_sfp_module_eeprom(phy,
+ params,
+ SFP_EEPROM_CON_TYPE_ADDR,
+ 1,
+ &val) != 0) {
DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
return -EINVAL;
}
@@ -2883,7 +4027,8 @@ static u8 bnx2x_get_edc_mode(struct link_params *params,
/* Check if its active cable( includes SFP+ module)
of passive cable*/
- if (bnx2x_read_sfp_module_eeprom(params,
+ if (bnx2x_read_sfp_module_eeprom(phy,
+ params,
SFP_EEPROM_FC_TX_TECH_ADDR,
1,
&copper_module_type) !=
@@ -2923,10 +4068,11 @@ static u8 bnx2x_get_edc_mode(struct link_params *params,
if (check_limiting_mode) {
u8 options[SFP_EEPROM_OPTIONS_SIZE];
- if (bnx2x_read_sfp_module_eeprom(params,
- SFP_EEPROM_OPTIONS_ADDR,
- SFP_EEPROM_OPTIONS_SIZE,
- options) != 0) {
+ if (bnx2x_read_sfp_module_eeprom(phy,
+ params,
+ SFP_EEPROM_OPTIONS_ADDR,
+ SFP_EEPROM_OPTIONS_SIZE,
+ options) != 0) {
DP(NETIF_MSG_LINK, "Failed to read Option"
" field from module EEPROM\n");
return -EINVAL;
@@ -2939,17 +4085,17 @@ static u8 bnx2x_get_edc_mode(struct link_params *params,
DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
return 0;
}
-
/* This function read the relevant field from the module ( SFP+ ),
and verify it is compliant with this board */
-static u8 bnx2x_verify_sfp_module(struct link_params *params)
+static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
+ struct link_params *params)
{
struct bnx2x *bp = params->bp;
- u32 val;
- u32 fw_resp;
+ u32 val, cmd;
+ u32 fw_resp, fw_cmd_param;
char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
-
+ phy->flags &= ~FLAGS_SFP_NOT_APPROVED;
val = REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region, dev_info.
port_feature_config[params->port].config));
@@ -2959,29 +4105,44 @@ static u8 bnx2x_verify_sfp_module(struct link_params *params)
return 0;
}
- /* Ask the FW to validate the module */
- if (!(params->feature_config_flags &
- FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) {
+ if (params->feature_config_flags &
+ FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY) {
+ /* Use specific phy request */
+ cmd = DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL;
+ } else if (params->feature_config_flags &
+ 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");
+ 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");
+ "verification\n");
return -EINVAL;
}
- fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL);
+ fw_cmd_param = FW_PARAM_SET(phy->addr, phy->type, phy->mdio_ctrl);
+ fw_resp = bnx2x_fw_command(bp, cmd, fw_cmd_param);
if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
DP(NETIF_MSG_LINK, "Approved module\n");
return 0;
}
/* format the warning message */
- if (bnx2x_read_sfp_module_eeprom(params,
+ if (bnx2x_read_sfp_module_eeprom(phy,
+ params,
SFP_EEPROM_VENDOR_NAME_ADDR,
SFP_EEPROM_VENDOR_NAME_SIZE,
(u8 *)vendor_name))
vendor_name[0] = '\0';
else
vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
- if (bnx2x_read_sfp_module_eeprom(params,
+ if (bnx2x_read_sfp_module_eeprom(phy,
+ params,
SFP_EEPROM_PART_NO_ADDR,
SFP_EEPROM_PART_NO_SIZE,
(u8 *)vendor_pn))
@@ -2989,22 +4150,78 @@ static u8 bnx2x_verify_sfp_module(struct link_params *params)
else
vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
- netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected, Port %d from %s part number %s\n",
+ netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected,"
+ " Port %d from %s part number %s\n",
params->port, vendor_name, vendor_pn);
+ phy->flags |= FLAGS_SFP_NOT_APPROVED;
return -EINVAL;
}
-static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
- u16 edc_mode)
+static u8 bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
+ struct link_params *params)
+
{
+ u8 val;
struct bnx2x *bp = params->bp;
- u8 port = params->port;
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
+ u16 timeout;
+ /* Initialization time after hot-plug may take up to 300ms for some
+ phys type ( e.g. JDSU ) */
+ 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);
+ return 0;
+ }
+ msleep(5);
+ }
+ return -EINVAL;
+}
+
+static void bnx2x_8727_power_module(struct bnx2x *bp,
+ struct bnx2x_phy *phy,
+ u8 is_power_up) {
+ /* Make sure GPIOs are not using for LED mode */
+ u16 val;
+ /*
+ * In the GPIO register, bit 4 is use to detemine if the GPIOs are
+ * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
+ * output
+ * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
+ * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
+ * where the 1st bit is the over-current(only input), and 2nd bit is
+ * for power( only output )
+ */
+
+ /*
+ * In case of NOC feature is disabled and power is up, set GPIO control
+ * as input to enable listening of over-current indication
+ */
+ if (phy->flags & FLAGS_NOC)
+ return;
+ if (!(phy->flags &
+ FLAGS_NOC) && is_power_up)
+ val = (1<<4);
+ else
+ /*
+ * Set GPIO control to OUTPUT, and set the power bit
+ * to according to the is_power_up
+ */
+ val = ((!(is_power_up)) << 1);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_GPIO_CTRL,
+ val);
+}
+
+static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
+ struct bnx2x_phy *phy,
+ u16 edc_mode)
+{
u16 cur_limiting_mode;
- bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER2,
&cur_limiting_mode);
@@ -3014,12 +4231,10 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
if (edc_mode == EDC_MODE_LIMITING) {
DP(NETIF_MSG_LINK,
"Setting LIMITING MODE\n");
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_ROM_VER2,
- EDC_MODE_LIMITING);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_ROM_VER2,
+ EDC_MODE_LIMITING);
} else { /* LRM mode ( default )*/
DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
@@ -3030,27 +4245,19 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
if (cur_limiting_mode != EDC_MODE_LIMITING)
return 0;
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
- ext_phy_addr,
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_LRM_MODE,
0);
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
- ext_phy_addr,
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER2,
0x128);
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
- ext_phy_addr,
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_MISC_CTRL0,
0x4008);
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
- ext_phy_addr,
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_LRM_MODE,
0xaaaa);
@@ -3058,46 +4265,33 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
return 0;
}
-static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params,
+static u8 bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
+ struct bnx2x_phy *phy,
u16 edc_mode)
{
- struct bnx2x *bp = params->bp;
- u8 port = params->port;
u16 phy_identifier;
u16 rom_ver2_val;
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-
- bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER,
&phy_identifier);
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr,
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER,
(phy_identifier & ~(1<<9)));
- bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER2,
&rom_ver2_val);
/* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr,
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER2,
(rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr,
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER,
(phy_identifier | (1<<9)));
@@ -3105,72 +4299,34 @@ static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params,
return 0;
}
-
-static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
+static void bnx2x_8727_specific_func(struct bnx2x_phy *phy,
+ struct link_params *params,
+ u32 action)
{
- u8 val;
struct bnx2x *bp = params->bp;
- u16 timeout;
- /* Initialization time after hot-plug may take up to 300ms for some
- phys type ( e.g. JDSU ) */
- for (timeout = 0; timeout < 60; timeout++) {
- if (bnx2x_read_sfp_module_eeprom(params, 1, 1, &val)
- == 0) {
- DP(NETIF_MSG_LINK, "SFP+ module initialization "
- "took %d ms\n", timeout * 5);
- return 0;
- }
- msleep(5);
- }
- return -EINVAL;
-}
-
-static void bnx2x_8727_power_module(struct bnx2x *bp,
- struct link_params *params,
- u8 ext_phy_addr, u8 is_power_up) {
- /* Make sure GPIOs are not using for LED mode */
- u16 val;
- u8 port = params->port;
- /*
- * In the GPIO register, bit 4 is use to detemine if the GPIOs are
- * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
- * output
- * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
- * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
- * where the 1st bit is the over-current(only input), and 2nd bit is
- * for power( only output )
- */
- /*
- * In case of NOC feature is disabled and power is up, set GPIO control
- * as input to enable listening of over-current indication
- */
-
- if (!(params->feature_config_flags &
- FEATURE_CONFIG_BCM8727_NOC) && is_power_up)
- val = (1<<4);
- else
- /*
- * Set GPIO control to OUTPUT, and set the power bit
- * to according to the is_power_up
- */
- val = ((!(is_power_up)) << 1);
-
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8727_GPIO_CTRL,
- val);
+ switch (action) {
+ case DISABLE_TX:
+ bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
+ break;
+ case ENABLE_TX:
+ if (!(phy->flags & FLAGS_SFP_NOT_APPROVED))
+ bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
+ break;
+ default:
+ DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n",
+ action);
+ return;
+ }
}
-static u8 bnx2x_sfp_module_detection(struct link_params *params)
+static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
+ struct link_params *params)
{
struct bnx2x *bp = params->bp;
u16 edc_mode;
u8 rc = 0;
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
- u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+
u32 val = REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region, dev_info.
port_feature_config[params->port].config));
@@ -3178,10 +4334,10 @@ static u8 bnx2x_sfp_module_detection(struct link_params *params)
DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
params->port);
- if (bnx2x_get_edc_mode(params, &edc_mode) != 0) {
+ if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
return -EINVAL;
- } else if (bnx2x_verify_sfp_module(params) !=
+ } else if (bnx2x_verify_sfp_module(phy, params) !=
0) {
/* check SFP+ module compatibility */
DP(NETIF_MSG_LINK, "Module verification failed!!\n");
@@ -3190,13 +4346,12 @@ static u8 bnx2x_sfp_module_detection(struct link_params *params)
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
MISC_REGISTERS_GPIO_HIGH,
params->port);
- if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
+ if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
/* Shutdown SFP+ module */
DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
- bnx2x_8727_power_module(bp, params,
- ext_phy_addr, 0);
+ bnx2x_8727_power_module(bp, phy, 0);
return rc;
}
} else {
@@ -3208,15 +4363,15 @@ static u8 bnx2x_sfp_module_detection(struct link_params *params)
}
/* power up the SFP module */
- if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
- bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
+ if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
+ bnx2x_8727_power_module(bp, phy, 1);
/* Check and set limiting mode / LRM mode on 8726.
On 8727 it is done automatically */
- if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
- bnx2x_bcm8726_set_limiting_mode(params, edc_mode);
+ if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
+ bnx2x_8726_set_limiting_mode(bp, phy, edc_mode);
else
- bnx2x_bcm8727_set_limiting_mode(params, edc_mode);
+ bnx2x_8727_set_limiting_mode(bp, phy, edc_mode);
/*
* Enable transmit for this module if the module is approved, or
* if unapproved modules should also enable the Tx laser
@@ -3224,11 +4379,9 @@ static u8 bnx2x_sfp_module_detection(struct link_params *params)
if (rc == 0 ||
(val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
- bnx2x_sfp_set_transmitter(bp, params->port,
- ext_phy_type, ext_phy_addr, 1);
+ bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
else
- bnx2x_sfp_set_transmitter(bp, params->port,
- ext_phy_type, ext_phy_addr, 0);
+ bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
return rc;
}
@@ -3236,6 +4389,7 @@ static u8 bnx2x_sfp_module_detection(struct link_params *params)
void bnx2x_handle_module_detect_int(struct link_params *params)
{
struct bnx2x *bp = params->bp;
+ struct bnx2x_phy *phy = &params->phy[EXT_PHY1];
u32 gpio_val;
u8 port = params->port;
@@ -3245,1349 +4399,587 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
params->port);
/* Get current gpio val refelecting module plugged in / out*/
- gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
+ gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
/* Call the handling function in case module is detected */
if (gpio_val == 0) {
bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
- MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
- port);
+ MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
+ port);
- if (bnx2x_wait_for_sfp_module_initialized(params) ==
- 0)
- bnx2x_sfp_module_detection(params);
+ if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
+ bnx2x_sfp_module_detection(phy, params);
else
DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
} else {
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-
- u32 ext_phy_type =
- XGXS_EXT_PHY_TYPE(params->ext_phy_config);
u32 val = REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region, dev_info.
port_feature_config[params->port].
config));
bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
- MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
- port);
+ MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
+ port);
/* Module was plugged out. */
/* Disable transmit for this module */
if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
- bnx2x_sfp_set_transmitter(bp, params->port,
- ext_phy_type, ext_phy_addr, 0);
+ bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
}
}
-static void bnx2x_bcm807x_force_10G(struct link_params *params)
+/******************************************************************/
+/* common BCM8706/BCM8726 PHY SECTION */
+/******************************************************************/
+static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
{
+ u8 link_up = 0;
+ u16 val1, val2, rx_sd, pcs_status;
struct bnx2x *bp = params->bp;
- u8 port = params->port;
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
- u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
- /* Force KR or KX */
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CTRL,
- 0x2040);
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_10G_CTRL2,
- 0x000b);
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_BCM_CTRL,
- 0x0000);
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CTRL,
- 0x0000);
-}
-
-static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params)
-{
- struct bnx2x *bp = params->bp;
- u8 port = params->port;
- u16 val;
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
- u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
- bnx2x_cl45_read(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8073_CHIP_REV, &val);
-
- if (val == 0) {
- /* Mustn't set low power mode in 8073 A0 */
- return;
+ DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
+ /* Clear RX Alarm*/
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
+ /* clear LASI indication*/
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
+ DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
+
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
+
+ DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
+ " link_status 0x%x\n", rx_sd, pcs_status, val2);
+ /* link is up if both bit 0 of pmd_rx_sd and
+ * bit 0 of pcs_status are set, or if the autoneg bit
+ * 1 is set
+ */
+ link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
+ if (link_up) {
+ if (val2 & (1<<1))
+ vars->line_speed = SPEED_1000;
+ else
+ vars->line_speed = SPEED_10000;
+ bnx2x_ext_phy_resolve_fc(phy, params, vars);
}
-
- /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
- bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_XS_DEVAD,
- MDIO_XS_PLL_SEQUENCER, &val);
- val &= ~(1<<13);
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
-
- /* PLL controls */
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_XS_DEVAD, 0x805E, 0x1077);
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_XS_DEVAD, 0x805D, 0x0000);
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_XS_DEVAD, 0x805C, 0x030B);
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_XS_DEVAD, 0x805B, 0x1240);
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_XS_DEVAD, 0x805A, 0x2490);
-
- /* Tx Controls */
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_XS_DEVAD, 0x80A7, 0x0C74);
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_XS_DEVAD, 0x80A6, 0x9041);
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_XS_DEVAD, 0x80A5, 0x4640);
-
- /* Rx Controls */
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_XS_DEVAD, 0x80FE, 0x01C4);
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_XS_DEVAD, 0x80FD, 0x9249);
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_XS_DEVAD, 0x80FC, 0x2015);
-
- /* Enable PLL sequencer (use read-modify-write to set bit 13) */
- bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_XS_DEVAD,
- MDIO_XS_PLL_SEQUENCER, &val);
- val |= (1<<13);
- bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
- MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
+ return link_up;
}
-static void bnx2x_8073_set_pause_cl37(struct link_params *params,
- struct link_vars *vars)
+/******************************************************************/
+/* BCM8706 PHY SECTION */
+/******************************************************************/
+static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
{
+ u16 cnt, val;
struct bnx2x *bp = params->bp;
- u16 cl37_val;
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
- u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CL37_FC_LD, &cl37_val);
-
- cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
- /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+ MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
+ /* HW reset */
+ bnx2x_ext_phy_hw_reset(bp, params->port);
+ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
+ bnx2x_wait_reset_complete(bp, phy);
- if ((vars->ieee_fc &
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
- cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
+ /* Wait until fw is loaded */
+ for (cnt = 0; cnt < 100; cnt++) {
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
+ if (val)
+ break;
+ msleep(10);
}
- if ((vars->ieee_fc &
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
- cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+ DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
+ if ((params->feature_config_flags &
+ FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
+ u8 i;
+ u16 reg;
+ for (i = 0; i < 4; i++) {
+ reg = MDIO_XS_8706_REG_BANK_RX0 +
+ i*(MDIO_XS_8706_REG_BANK_RX1 -
+ MDIO_XS_8706_REG_BANK_RX0);
+ bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val);
+ /* Clear first 3 bits of the control */
+ val &= ~0x7;
+ /* Set control bits according to configuration */
+ val |= (phy->rx_preemphasis[i] & 0x7);
+ DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706"
+ " reg 0x%x <-- val 0x%x\n", reg, val);
+ bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
+ }
}
- if ((vars->ieee_fc &
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
- cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+ /* Force speed */
+ if (phy->req_line_speed == SPEED_10000) {
+ DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
+ } else {
+ /* Force 1Gbps using autoneg with 1G advertisment */
+
+ /* Allow CL37 through CL73 */
+ DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
+
+ /* Enable Full-Duplex advertisment on CL37 */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020);
+ /* Enable CL37 AN */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
+ /* 1G support */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5));
+
+ /* Enable clause 73 AN */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
+ 0x0400);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
+ 0x0004);
}
- DP(NETIF_MSG_LINK,
- "Ext phy AN advertize cl37 0x%x\n", cl37_val);
+ bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
+ return 0;
+}
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CL37_FC_LD, cl37_val);
- msleep(500);
+static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
+{
+ return bnx2x_8706_8726_read_status(phy, params, vars);
}
-static void bnx2x_ext_phy_set_pause(struct link_params *params,
- struct link_vars *vars)
+/******************************************************************/
+/* BCM8726 PHY SECTION */
+/******************************************************************/
+static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
+ struct link_params *params)
{
struct bnx2x *bp = params->bp;
- u16 val;
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
- u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
- /* read modify write pause advertizing */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_ADV_PAUSE, &val);
-
- val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
-
- /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
-
- if ((vars->ieee_fc &
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
- val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
- }
- if ((vars->ieee_fc &
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
- val |=
- MDIO_AN_REG_ADV_PAUSE_PAUSE;
- }
- DP(NETIF_MSG_LINK,
- "Ext phy AN advertize 0x%x\n", val);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_ADV_PAUSE, val);
+ DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
+ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
}
-static void bnx2x_set_preemphasis(struct link_params *params)
+
+static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
+ struct link_params *params)
{
- u16 bank, i = 0;
struct bnx2x *bp = params->bp;
+ /* Need to wait 100ms after reset */
+ msleep(100);
- for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
- bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
- bank,
- MDIO_RX0_RX_EQ_BOOST,
- params->xgxs_config_rx[i]);
- }
-
- for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
- bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
- CL45_WR_OVER_CL22(bp, params->port,
- params->phy_addr,
- bank,
- MDIO_TX0_TX_DRIVER,
- params->xgxs_config_tx[i]);
- }
-}
+ /* Micro controller re-boot */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B);
+ /* Set soft reset */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_GEN_CTRL,
+ MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
-static void bnx2x_8481_set_led4(struct link_params *params,
- u32 ext_phy_type, u8 ext_phy_addr)
-{
- struct bnx2x *bp = params->bp;
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_MISC_CTRL1, 0x0001);
- /* PHYC_CTL_LED_CTL */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8481_LINK_SIGNAL, 0xa482);
+ MDIO_PMA_REG_GEN_CTRL,
+ MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
- /* Unmask LED4 for 10G link */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
+ /* wait for 150ms for microcode load */
+ msleep(150);
+
+ /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8481_SIGNAL_MASK, (1<<6));
- /* 'Interrupt Mask' */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- 0xFFFB, 0xFFFD);
-}
-static void bnx2x_8481_set_legacy_led_mode(struct link_params *params,
- u32 ext_phy_type, u8 ext_phy_addr)
-{
- struct bnx2x *bp = params->bp;
+ MDIO_PMA_REG_MISC_CTRL1, 0x0000);
- /* LED1 (10G Link): Disable LED1 when 10/100/1000 link */
- /* LED2 (1G/100/10 Link): Enable LED2 when 10/100/1000 link) */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_8481_LEGACY_SHADOW,
- (1<<15) | (0xd << 10) | (0xc<<4) | 0xe);
+ msleep(200);
+ bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
}
-static void bnx2x_8481_set_10G_led_mode(struct link_params *params,
- u32 ext_phy_type, u8 ext_phy_addr)
+static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
u16 val1;
-
- /* LED1 (10G Link) */
- /* Enable continuse based on source 7(10G-link) */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8481_LINK_SIGNAL,
- &val1);
- /* Set bit 2 to 0, and bits [1:0] to 10 */
- val1 &= ~((1<<0) | (1<<2) | (1<<7)); /* Clear bits 0,2,7*/
- val1 |= ((1<<1) | (1<<6)); /* Set bit 1, 6 */
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8481_LINK_SIGNAL,
- val1);
-
- /* Unmask LED1 for 10G link */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8481_LED1_MASK,
- &val1);
- /* Set bit 2 to 0, and bits [1:0] to 10 */
- val1 |= (1<<7);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8481_LED1_MASK,
- val1);
-
- /* LED2 (1G/100/10G Link) */
- /* Mask LED2 for 10G link */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8481_LED2_MASK,
- 0);
-
- /* Unmask LED3 for 10G link */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8481_LED3_MASK,
- 0x6);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8481_LED3_BLINK,
- 0);
+ u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
+ if (link_up) {
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
+ &val1);
+ if (val1 & (1<<15)) {
+ DP(NETIF_MSG_LINK, "Tx is disabled\n");
+ link_up = 0;
+ vars->line_speed = 0;
+ }
+ }
+ return link_up;
}
-static void bnx2x_init_internal_phy(struct link_params *params,
- struct link_vars *vars,
- u8 enable_cl73)
+static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
+ u32 val;
+ u32 swap_val, swap_override, aeu_gpio_mask, offset;
+ DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
+ /* Restore normal power mode*/
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+ MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
- if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
- if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
- (params->feature_config_flags &
- FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
- bnx2x_set_preemphasis(params);
-
- /* forced speed requested? */
- if (vars->line_speed != SPEED_AUTO_NEG ||
- ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
- params->loopback_mode == LOOPBACK_EXT)) {
- DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
-
- /* disable autoneg */
- bnx2x_set_autoneg(params, vars, 0);
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+ MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
+
+ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
+ bnx2x_wait_reset_complete(bp, phy);
+
+ bnx2x_8726_external_rom_boot(phy, params);
+
+ /* Need to call module detected on initialization since
+ the module detection triggered by actual module
+ insertion might occur before driver is loaded, and when
+ driver is loaded, it reset all registers, including the
+ transmitter */
+ bnx2x_sfp_module_detection(phy, params);
+
+ if (phy->req_line_speed == SPEED_1000) {
+ DP(NETIF_MSG_LINK, "Setting 1G force\n");
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x5);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
+ 0x400);
+ } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
+ (phy->speed_cap_mask &
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
+ ((phy->speed_cap_mask &
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
+ DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
+ /* Set Flow control */
+ bnx2x_ext_phy_set_pause(params, phy, vars);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
+ /* Enable RX-ALARM control to receive
+ interrupt for 1G speed change */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
+ 0x400);
+
+ } else { /* Default 10G. Set only LASI control */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
+ }
- /* program speed and duplex */
- bnx2x_program_serdes(params, vars);
+ /* 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",
+ phy->tx_preemphasis[0],
+ phy->tx_preemphasis[1]);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8726_TX_CTRL1,
+ phy->tx_preemphasis[0]);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8726_TX_CTRL2,
+ phy->tx_preemphasis[1]);
+ }
- } else { /* AN_mode */
- DP(NETIF_MSG_LINK, "not SGMII, AN\n");
+ /* Set GPIO3 to trigger SFP+ module insertion/removal */
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
+ MISC_REGISTERS_GPIO_INPUT_HI_Z, params->port);
- /* AN enabled */
- bnx2x_set_brcm_cl37_advertisment(params);
+ /* The GPIO should be swapped if the swap register is set and active */
+ swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+ swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
- /* program duplex & pause advertisement (for aneg) */
- bnx2x_set_ieee_aneg_advertisment(params,
- vars->ieee_fc);
+ /* Select function upon port-swap configuration */
+ if (params->port == 0) {
+ offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
+ aeu_gpio_mask = (swap_val && swap_override) ?
+ AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 :
+ AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0;
+ } else {
+ offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
+ aeu_gpio_mask = (swap_val && swap_override) ?
+ AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 :
+ AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1;
+ }
+ val = REG_RD(bp, offset);
+ /* add GPIO3 to group */
+ val |= aeu_gpio_mask;
+ REG_WR(bp, offset, val);
+ return 0;
- /* enable autoneg */
- bnx2x_set_autoneg(params, vars, enable_cl73);
+}
- /* enable and restart AN */
- bnx2x_restart_autoneg(params, enable_cl73);
- }
+static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
+ struct link_params *params)
+{
+ struct bnx2x *bp = params->bp;
+ DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
+ /* Set serial boot control for external load */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_GEN_CTRL, 0x0001);
+}
- } else { /* SGMII mode */
- DP(NETIF_MSG_LINK, "SGMII\n");
+/******************************************************************/
+/* BCM8727 PHY SECTION */
+/******************************************************************/
- bnx2x_initialize_sgmii_process(params, vars);
+static void bnx2x_8727_set_link_led(struct bnx2x_phy *phy,
+ struct link_params *params, u8 mode)
+{
+ struct bnx2x *bp = params->bp;
+ u16 led_mode_bitmask = 0;
+ u16 gpio_pins_bitmask = 0;
+ u16 val;
+ /* Only NOC flavor requires to set the LED specifically */
+ if (!(phy->flags & FLAGS_NOC))
+ return;
+ switch (mode) {
+ case LED_MODE_FRONT_PANEL_OFF:
+ case LED_MODE_OFF:
+ led_mode_bitmask = 0;
+ gpio_pins_bitmask = 0x03;
+ break;
+ case LED_MODE_ON:
+ led_mode_bitmask = 0;
+ gpio_pins_bitmask = 0x02;
+ break;
+ case LED_MODE_OPER:
+ led_mode_bitmask = 0x60;
+ gpio_pins_bitmask = 0x11;
+ break;
}
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+ &val);
+ val &= 0xff8f;
+ val |= led_mode_bitmask;
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+ val);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_GPIO_CTRL,
+ &val);
+ val &= 0xffe0;
+ val |= gpio_pins_bitmask;
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_GPIO_CTRL,
+ val);
+}
+static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
+ struct link_params *params) {
+ u32 swap_val, swap_override;
+ u8 port;
+ /**
+ * The PHY reset is controlled by GPIO 1. Fake the port number
+ * to cancel the swap done in set_gpio()
+ */
+ struct bnx2x *bp = params->bp;
+ swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+ swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
+ port = (swap_val && swap_override) ^ 1;
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
}
-static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
+static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
{
+ u16 tmp1, val, mod_abs;
+ u16 rx_alarm_ctrl_val;
+ u16 lasi_ctrl_val;
struct bnx2x *bp = params->bp;
- u32 ext_phy_type;
- u8 ext_phy_addr;
- u16 cnt;
- u16 ctrl = 0;
- u16 val = 0;
- u8 rc = 0;
-
- if (vars->phy_flags & PHY_XGXS_FLAG) {
- ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-
- ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
- /* Make sure that the soft reset is off (expect for the 8072:
- * due to the lock, it will be done inside the specific
- * handling)
+ /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
+
+ bnx2x_wait_reset_complete(bp, phy);
+ rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
+ lasi_ctrl_val = 0x0004;
+
+ DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
+ /* enable LASI */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
+ rx_alarm_ctrl_val);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
+
+ /* Initially configure MOD_ABS to interrupt when
+ module is presence( bit 8) */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
+ /* Set EDC off by setting OPTXLOS signal input to low
+ (bit 9).
+ When the EDC is off it locks onto a reference clock and
+ avoids becoming 'lost'.*/
+ mod_abs &= ~(1<<8);
+ if (!(phy->flags & FLAGS_NOC))
+ mod_abs &= ~(1<<9);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+
+ /* Make MOD_ABS give interrupt on change */
+ bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+ &val);
+ val |= (1<<12);
+ if (phy->flags & FLAGS_NOC)
+ val |= (3<<5);
+
+ /**
+ * Set 8727 GPIOs to input to allow reading from the 8727 GPIO0
+ * status which reflect SFP+ module over-current
+ */
+ if (!(phy->flags & FLAGS_NOC))
+ val &= 0xff8f; /* Reset bits 4-6 */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
+
+ bnx2x_8727_power_module(bp, phy, 1);
+
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
+
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
+
+ /* Set option 1G speed */
+ if (phy->req_line_speed == SPEED_1000) {
+ DP(NETIF_MSG_LINK, "Setting 1G force\n");
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
+ DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
+ /**
+ * Power down the XAUI until link is up in case of dual-media
+ * and 1G
*/
- if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
- (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
- (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
- (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
- (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
- /* Wait for soft reset to get cleared upto 1 sec */
- for (cnt = 0; cnt < 1000; cnt++) {
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CTRL, &ctrl);
- if (!(ctrl & (1<<15)))
- break;
- msleep(1);
- }
- DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
- ctrl, cnt);
- }
-
- switch (ext_phy_type) {
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
- break;
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
- DP(NETIF_MSG_LINK, "XGXS 8705\n");
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_MISC_CTRL,
- 0x8288);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_PHY_IDENTIFIER,
- 0x7fbf);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CMU_PLL_BYPASS,
- 0x0100);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_WIS_DEVAD,
- MDIO_WIS_REG_LASI_CNTL, 0x1);
-
- /* BCM8705 doesn't have microcode, hence the 0 */
- bnx2x_save_spirom_version(bp, params->port,
- params->shmem_base, 0);
- break;
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
- /* Wait until fw is loaded */
- for (cnt = 0; cnt < 100; cnt++) {
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_PMA_DEVAD,
- MDIO_PMA_REG_ROM_VER1, &val);
- if (val)
- break;
- msleep(10);
- }
- DP(NETIF_MSG_LINK, "XGXS 8706 is initialized "
- "after %d ms\n", cnt);
- if ((params->feature_config_flags &
- FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
- u8 i;
- u16 reg;
- for (i = 0; i < 4; i++) {
- reg = MDIO_XS_8706_REG_BANK_RX0 +
- i*(MDIO_XS_8706_REG_BANK_RX1 -
- MDIO_XS_8706_REG_BANK_RX0);
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_XS_DEVAD,
- reg, &val);
- /* Clear first 3 bits of the control */
- val &= ~0x7;
- /* Set control bits according to
- configuation */
- val |= (params->xgxs_config_rx[i] &
- 0x7);
- DP(NETIF_MSG_LINK, "Setting RX"
- "Equalizer to BCM8706 reg 0x%x"
- " <-- val 0x%x\n", reg, val);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_XS_DEVAD,
- reg, val);
- }
- }
- /* Force speed */
- if (params->req_line_speed == SPEED_10000) {
- DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_DIGITAL_CTRL,
- 0x400);
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_PMA_DEVAD,
- MDIO_PMA_REG_LASI_CTRL, 1);
- } else {
- /* Force 1Gbps using autoneg with 1G
- advertisment */
-
- /* Allow CL37 through CL73 */
- DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CL37_CL73,
- 0x040c);
-
- /* Enable Full-Duplex advertisment on CL37 */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CL37_FC_LP,
- 0x0020);
- /* Enable CL37 AN */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CL37_AN,
- 0x1000);
- /* 1G support */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_ADV, (1<<5));
-
- /* Enable clause 73 AN */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CTRL,
- 0x1200);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_RX_ALARM_CTRL,
- 0x0400);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_LASI_CTRL, 0x0004);
-
- }
- bnx2x_save_bcm_spirom_ver(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- params->shmem_base);
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
- DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
- bnx2x_bcm8726_external_rom_boot(params);
-
- /* Need to call module detected on initialization since
- the module detection triggered by actual module
- insertion might occur before driver is loaded, and when
- driver is loaded, it reset all registers, including the
- transmitter */
- bnx2x_sfp_module_detection(params);
-
- /* Set Flow control */
- bnx2x_ext_phy_set_pause(params, vars);
- if (params->req_line_speed == SPEED_1000) {
- DP(NETIF_MSG_LINK, "Setting 1G force\n");
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CTRL, 0x40);
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_PMA_DEVAD,
- MDIO_PMA_REG_10G_CTRL2, 0xD);
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_PMA_DEVAD,
- MDIO_PMA_REG_LASI_CTRL, 0x5);
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_PMA_DEVAD,
- MDIO_PMA_REG_RX_ALARM_CTRL,
- 0x400);
- } else if ((params->req_line_speed ==
- SPEED_AUTO_NEG) &&
- ((params->speed_cap_mask &
- PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
- DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_AN_DEVAD,
- MDIO_AN_REG_ADV, 0x20);
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_AN_DEVAD,
- MDIO_AN_REG_CL37_CL73, 0x040c);
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_AN_DEVAD,
- MDIO_AN_REG_CL37_FC_LD, 0x0020);
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_AN_DEVAD,
- MDIO_AN_REG_CL37_AN, 0x1000);
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_AN_DEVAD,
- MDIO_AN_REG_CTRL, 0x1200);
-
- /* Enable RX-ALARM control to receive
- interrupt for 1G speed change */
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_PMA_DEVAD,
- MDIO_PMA_REG_LASI_CTRL, 0x4);
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_PMA_DEVAD,
- MDIO_PMA_REG_RX_ALARM_CTRL,
- 0x400);
-
- } else { /* Default 10G. Set only LASI control */
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_PMA_DEVAD,
- MDIO_PMA_REG_LASI_CTRL, 1);
- }
-
- /* Set TX PreEmphasis if needed */
- if ((params->feature_config_flags &
- FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
- DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
- "TX_CTRL2 0x%x\n",
- params->xgxs_config_tx[0],
- params->xgxs_config_tx[1]);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TX_CTRL1,
- params->xgxs_config_tx[0]);
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TX_CTRL2,
- params->xgxs_config_tx[1]);
- }
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
- {
- u16 tmp1;
- u16 rx_alarm_ctrl_val;
- u16 lasi_ctrl_val;
- if (ext_phy_type ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
- rx_alarm_ctrl_val = 0x400;
- lasi_ctrl_val = 0x0004;
- } else {
- rx_alarm_ctrl_val = (1<<2);
- lasi_ctrl_val = 0x0004;
- }
-
- /* enable LASI */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_RX_ALARM_CTRL,
- rx_alarm_ctrl_val);
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_LASI_CTRL,
- lasi_ctrl_val);
-
- bnx2x_8073_set_pause_cl37(params, vars);
-
- if (ext_phy_type ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072)
- bnx2x_bcm8072_external_rom_boot(params);
- else
- /* In case of 8073 with long xaui lines,
- don't set the 8073 xaui low power*/
- bnx2x_bcm8073_set_xaui_low_power_mode(params);
-
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_M8051_MSGOUT_REG,
- &tmp1);
-
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_RX_ALARM, &tmp1);
-
- DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):"
- "0x%x\n", tmp1);
-
- /* If this is forced speed, set to KR or KX
- * (all other are not supported)
- */
- if (params->loopback_mode == LOOPBACK_EXT) {
- bnx2x_bcm807x_force_10G(params);
- DP(NETIF_MSG_LINK,
- "Forced speed 10G on 807X\n");
- break;
- } else {
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type, ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_BCM_CTRL,
- 0x0002);
- }
- if (params->req_line_speed != SPEED_AUTO_NEG) {
- if (params->req_line_speed == SPEED_10000) {
- val = (1<<7);
- } else if (params->req_line_speed ==
- SPEED_2500) {
- val = (1<<5);
- /* Note that 2.5G works only
- when used with 1G advertisment */
- } else
- val = (1<<5);
- } else {
-
- val = 0;
- if (params->speed_cap_mask &
- PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
- val |= (1<<7);
-
- /* Note that 2.5G works only when
- used with 1G advertisment */
- if (params->speed_cap_mask &
- (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
- PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
- val |= (1<<5);
- DP(NETIF_MSG_LINK,
- "807x autoneg val = 0x%x\n", val);
- }
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_ADV, val);
- if (ext_phy_type ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_8073_2_5G, &tmp1);
-
- if (((params->speed_cap_mask &
- PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
- (params->req_line_speed ==
- SPEED_AUTO_NEG)) ||
- (params->req_line_speed ==
- SPEED_2500)) {
- u16 phy_ver;
- /* Allow 2.5G for A1 and above */
- bnx2x_cl45_read(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- ext_phy_addr,
+ if (DUAL_MEDIA(params)) {
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_GP, &val);
+ val |= (3<<10);
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8073_CHIP_REV, &phy_ver);
- DP(NETIF_MSG_LINK, "Add 2.5G\n");
- if (phy_ver > 0)
- tmp1 |= 1;
- else
- tmp1 &= 0xfffe;
- } else {
- DP(NETIF_MSG_LINK, "Disable 2.5G\n");
- tmp1 &= 0xfffe;
- }
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_8073_2_5G, tmp1);
- }
-
- /* Add support for CL37 (passive mode) II */
-
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CL37_FC_LD,
- &tmp1);
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CL37_FC_LD, (tmp1 |
- ((params->req_duplex == DUPLEX_FULL) ?
- 0x20 : 0x40)));
-
- /* Add support for CL37 (passive mode) III */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CL37_AN, 0x1000);
-
- if (ext_phy_type ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
- /* The SNR will improve about 2db by changing
- BW and FEE main tap. Rest commands are executed
- after link is up*/
- /*Change FFE main cursor to 5 in EDC register*/
- if (bnx2x_8073_is_snr_needed(params))
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_EDC_FFE_MAIN,
- 0xFB0C);
-
- /* Enable FEC (Forware Error Correction)
- Request in the AN */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_ADV2, &tmp1);
-
- tmp1 |= (1<<15);
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_ADV2, tmp1);
-
- }
-
- bnx2x_ext_phy_set_pause(params, vars);
-
- /* Restart autoneg */
- msleep(500);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CTRL, 0x1200);
- DP(NETIF_MSG_LINK, "807x Autoneg Restart: "
- "Advertise 1G=%x, 10G=%x\n",
- ((val & (1<<5)) > 0),
- ((val & (1<<7)) > 0));
- break;
+ MDIO_PMA_REG_8727_PCS_GP, val);
}
+ } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
+ ((phy->speed_cap_mask &
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
+ ((phy->speed_cap_mask &
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
+
+ DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
+ } else {
+ /**
+ * Since the 8727 has only single reset pin, need to set the 10G
+ * registers although it is default
+ */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
+ 0x0020);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
+ 0x0008);
+ }
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
- {
- u16 tmp1;
- u16 rx_alarm_ctrl_val;
- u16 lasi_ctrl_val;
-
- /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
-
- u16 mod_abs;
- rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
- lasi_ctrl_val = 0x0004;
-
- DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
- /* enable LASI */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_RX_ALARM_CTRL,
- rx_alarm_ctrl_val);
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_LASI_CTRL,
- lasi_ctrl_val);
-
- /* Initially configure MOD_ABS to interrupt when
- module is presence( bit 8) */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
- /* Set EDC off by setting OPTXLOS signal input to low
- (bit 9).
- When the EDC is off it locks onto a reference clock and
- avoids becoming 'lost'.*/
- mod_abs &= ~((1<<8) | (1<<9));
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
-
- /* Make MOD_ABS give interrupt on change */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8727_PCS_OPT_CTRL,
- &val);
- val |= (1<<12);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8727_PCS_OPT_CTRL,
- val);
-
- /* Set 8727 GPIOs to input to allow reading from the
- 8727 GPIO0 status which reflect SFP+ module
- over-current */
-
- bnx2x_cl45_read(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8727_PCS_OPT_CTRL,
- &val);
- val &= 0xff8f; /* Reset bits 4-6 */
- bnx2x_cl45_write(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8727_PCS_OPT_CTRL,
- val);
-
- bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
- bnx2x_bcm8073_set_xaui_low_power_mode(params);
-
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_M8051_MSGOUT_REG,
- &tmp1);
-
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_RX_ALARM, &tmp1);
-
- /* Set option 1G speed */
- if (params->req_line_speed == SPEED_1000) {
-
- DP(NETIF_MSG_LINK, "Setting 1G force\n");
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CTRL, 0x40);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_10G_CTRL2, 0xD);
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_10G_CTRL2, &tmp1);
- DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
-
- } else if ((params->req_line_speed ==
- SPEED_AUTO_NEG) &&
- ((params->speed_cap_mask &
- PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
-
- DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_AN_DEVAD,
- MDIO_PMA_REG_8727_MISC_CTRL, 0);
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_AN_DEVAD,
- MDIO_AN_REG_CL37_AN, 0x1300);
- } else {
- /* Since the 8727 has only single reset pin,
- need to set the 10G registers although it is
- default */
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_AN_DEVAD,
- MDIO_AN_REG_CTRL, 0x0020);
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_AN_DEVAD,
- 0x7, 0x0100);
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CTRL, 0x2040);
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_PMA_DEVAD,
- MDIO_PMA_REG_10G_CTRL2, 0x0008);
- }
-
- /* Set 2-wire transfer rate of SFP+ module EEPROM
- * to 100Khz since some DACs(direct attached cables) do
- * not work at 400Khz.
- */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
- 0xa001);
-
- /* Set TX PreEmphasis if needed */
- if ((params->feature_config_flags &
- FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
- DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
- "TX_CTRL2 0x%x\n",
- params->xgxs_config_tx[0],
- params->xgxs_config_tx[1]);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8727_TX_CTRL1,
- params->xgxs_config_tx[0]);
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8727_TX_CTRL2,
- params->xgxs_config_tx[1]);
- }
-
- break;
- }
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
- {
- u16 fw_ver1, fw_ver2;
- DP(NETIF_MSG_LINK,
- "Setting the SFX7101 LASI indication\n");
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_LASI_CTRL, 0x1);
- DP(NETIF_MSG_LINK,
- "Setting the SFX7101 LED to blink on traffic\n");
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
-
- bnx2x_ext_phy_set_pause(params, vars);
- /* Restart autoneg */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CTRL, &val);
- val |= 0x200;
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CTRL, val);
-
- /* Save spirom version */
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_PMA_DEVAD,
- MDIO_PMA_REG_7101_VER1, &fw_ver1);
-
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr, MDIO_PMA_DEVAD,
- MDIO_PMA_REG_7101_VER2, &fw_ver2);
-
- bnx2x_save_spirom_version(params->bp, params->port,
- params->shmem_base,
- (u32)(fw_ver1<<16 | fw_ver2));
- break;
- }
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
- /* This phy uses the NIG latch mechanism since link
- indication arrives through its LED4 and not via
- its LASI signal, so we get steady signal
- instead of clear on read */
- bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
- 1 << NIG_LATCH_BC_ENABLE_MI_INT);
-
- bnx2x_cl45_write(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CTRL, 0x0000);
-
- bnx2x_8481_set_led4(params, ext_phy_type, ext_phy_addr);
- if (params->req_line_speed == SPEED_AUTO_NEG) {
-
- u16 autoneg_val, an_1000_val, an_10_100_val;
- /* set 1000 speed advertisement */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_8481_1000T_CTRL,
- &an_1000_val);
-
- if (params->speed_cap_mask &
- PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) {
- an_1000_val |= (1<<8);
- if (params->req_duplex == DUPLEX_FULL)
- an_1000_val |= (1<<9);
- DP(NETIF_MSG_LINK, "Advertising 1G\n");
- } else
- an_1000_val &= ~((1<<8) | (1<<9));
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_8481_1000T_CTRL,
- an_1000_val);
-
- /* set 100 speed advertisement */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_8481_LEGACY_AN_ADV,
- &an_10_100_val);
-
- if (params->speed_cap_mask &
- (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
- PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)) {
- an_10_100_val |= (1<<7);
- if (params->req_duplex == DUPLEX_FULL)
- an_10_100_val |= (1<<8);
- DP(NETIF_MSG_LINK,
- "Advertising 100M\n");
- } else
- an_10_100_val &= ~((1<<7) | (1<<8));
-
- /* set 10 speed advertisement */
- if (params->speed_cap_mask &
- (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
- PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) {
- an_10_100_val |= (1<<5);
- if (params->req_duplex == DUPLEX_FULL)
- an_10_100_val |= (1<<6);
- DP(NETIF_MSG_LINK, "Advertising 10M\n");
- }
- else
- an_10_100_val &= ~((1<<5) | (1<<6));
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_8481_LEGACY_AN_ADV,
- an_10_100_val);
-
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_8481_LEGACY_MII_CTRL,
- &autoneg_val);
-
- /* Disable forced speed */
- autoneg_val &= ~(1<<6|1<<13);
-
- /* Enable autoneg and restart autoneg
- for legacy speeds */
- autoneg_val |= (1<<9|1<<12);
-
- if (params->req_duplex == DUPLEX_FULL)
- autoneg_val |= (1<<8);
- else
- autoneg_val &= ~(1<<8);
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_8481_LEGACY_MII_CTRL,
- autoneg_val);
-
- if (params->speed_cap_mask &
- PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) {
- DP(NETIF_MSG_LINK, "Advertising 10G\n");
- /* Restart autoneg for 10G*/
-
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CTRL, 0x3200);
- }
- } else {
- /* Force speed */
- u16 autoneg_ctrl, pma_ctrl;
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_8481_LEGACY_MII_CTRL,
- &autoneg_ctrl);
-
- /* Disable autoneg */
- autoneg_ctrl &= ~(1<<12);
-
- /* Set 1000 force */
- switch (params->req_line_speed) {
- case SPEED_10000:
- DP(NETIF_MSG_LINK,
- "Unable to set 10G force !\n");
- break;
- case SPEED_1000:
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CTRL,
- &pma_ctrl);
- autoneg_ctrl &= ~(1<<13);
- autoneg_ctrl |= (1<<6);
- pma_ctrl &= ~(1<<13);
- pma_ctrl |= (1<<6);
- DP(NETIF_MSG_LINK,
- "Setting 1000M force\n");
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CTRL,
- pma_ctrl);
- break;
- case SPEED_100:
- autoneg_ctrl |= (1<<13);
- autoneg_ctrl &= ~(1<<6);
- DP(NETIF_MSG_LINK,
- "Setting 100M force\n");
- break;
- case SPEED_10:
- autoneg_ctrl &= ~(1<<13);
- autoneg_ctrl &= ~(1<<6);
- DP(NETIF_MSG_LINK,
- "Setting 10M force\n");
- break;
- }
-
- /* Duplex mode */
- if (params->req_duplex == DUPLEX_FULL) {
- autoneg_ctrl |= (1<<8);
- DP(NETIF_MSG_LINK,
- "Setting full duplex\n");
- } else
- autoneg_ctrl &= ~(1<<8);
-
- /* Update autoneg ctrl and pma ctrl */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_8481_LEGACY_MII_CTRL,
- autoneg_ctrl);
- }
-
- /* Save spirom version */
- bnx2x_save_8481_spirom_version(bp, params->port,
- ext_phy_addr,
- params->shmem_base);
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
- DP(NETIF_MSG_LINK,
- "XGXS PHY Failure detected 0x%x\n",
- params->ext_phy_config);
- rc = -EINVAL;
- break;
- default:
- DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
- params->ext_phy_config);
- rc = -EINVAL;
- break;
- }
-
- } else { /* SerDes */
-
- ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
- switch (ext_phy_type) {
- case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
- DP(NETIF_MSG_LINK, "SerDes Direct\n");
- break;
-
- case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
- DP(NETIF_MSG_LINK, "SerDes 5482\n");
- break;
-
- default:
- DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
- params->ext_phy_config);
- break;
- }
+ /* Set 2-wire transfer rate of SFP+ module EEPROM
+ * to 100Khz since some DACs(direct attached cables) do
+ * not work at 400Khz.
+ */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
+ 0xa001);
+
+ /* 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",
+ phy->tx_preemphasis[0],
+ phy->tx_preemphasis[1]);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
+ phy->tx_preemphasis[0]);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
+ phy->tx_preemphasis[1]);
}
- return rc;
+
+ return 0;
}
-static void bnx2x_8727_handle_mod_abs(struct link_params *params)
+static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
+ struct link_params *params)
{
struct bnx2x *bp = params->bp;
u16 mod_abs, rx_alarm_status;
- u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
u32 val = REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region, dev_info.
port_feature_config[params->port].
config));
- bnx2x_cl45_read(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
if (mod_abs & (1<<8)) {
@@ -4602,18 +4994,16 @@ static void bnx2x_8727_handle_mod_abs(struct link_params *params)
(bit 9).
When the EDC is off it locks onto a reference clock and
avoids becoming 'lost'.*/
- mod_abs &= ~((1<<8)|(1<<9));
- bnx2x_cl45_write(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr,
+ mod_abs &= ~(1<<8);
+ if (!(phy->flags & FLAGS_NOC))
+ mod_abs &= ~(1<<9);
+ bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
/* Clear RX alarm since it stays up as long as
the mod_abs wasn't changed */
- bnx2x_cl45_read(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr,
+ bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
@@ -4630,33 +5020,28 @@ static void bnx2x_8727_handle_mod_abs(struct link_params *params)
2. Restore the default polarity of the OPRXLOS signal and
this signal will then correctly indicate the presence or
absence of the Rx signal. (bit 9) */
- mod_abs |= ((1<<8)|(1<<9));
- bnx2x_cl45_write(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+ mod_abs |= (1<<8);
+ if (!(phy->flags & FLAGS_NOC))
+ mod_abs |= (1<<9);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
/* Clear RX alarm since it stays up as long as
the mod_abs wasn't changed. This is need to be done
before calling the module detection, otherwise it will clear
the link update alarm */
- bnx2x_cl45_read(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
- bnx2x_sfp_set_transmitter(bp, params->port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr, 0);
+ bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
- if (bnx2x_wait_for_sfp_module_initialized(params)
- == 0)
- bnx2x_sfp_module_detection(params);
+ if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
+ bnx2x_sfp_module_detection(phy, params);
else
DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
}
@@ -4667,1298 +5052,1707 @@ static void bnx2x_8727_handle_mod_abs(struct link_params *params)
module plugged in/out */
}
+static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
-static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
- struct link_vars *vars,
- u8 is_mi_int)
{
struct bnx2x *bp = params->bp;
- u32 ext_phy_type;
- u8 ext_phy_addr;
- u16 val1 = 0, val2;
- u16 rx_sd, pcs_status;
- u8 ext_phy_link_up = 0;
- u8 port = params->port;
-
- if (vars->phy_flags & PHY_XGXS_FLAG) {
- ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
- ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
- switch (ext_phy_type) {
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
- DP(NETIF_MSG_LINK, "XGXS Direct\n");
- ext_phy_link_up = 1;
- break;
+ u8 link_up = 0;
+ u16 link_status = 0;
+ u16 rx_alarm_status, lasi_ctrl, val1;
+
+ /* If PHY is not initialized, do not check link status */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
+ &lasi_ctrl);
+ if (!lasi_ctrl)
+ return 0;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
- DP(NETIF_MSG_LINK, "XGXS 8705\n");
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_WIS_DEVAD,
- MDIO_WIS_REG_LASI_STATUS, &val1);
- DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
-
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_WIS_DEVAD,
- MDIO_WIS_REG_LASI_STATUS, &val1);
- DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
-
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_RX_SD, &rx_sd);
-
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- 1,
- 0xc809, &val1);
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- 1,
- 0xc809, &val1);
-
- DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
- ext_phy_link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) &&
- ((val1 & (1<<8)) == 0));
- if (ext_phy_link_up)
- vars->line_speed = SPEED_10000;
- break;
+ /* Check the LASI */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
+ &rx_alarm_status);
+ vars->line_speed = 0;
+ DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
- DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
- /* Clear RX Alarm*/
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
- &val2);
- /* clear LASI indication*/
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
- &val1);
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
- &val2);
- DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x-->"
- "0x%x\n", val1, val2);
-
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
- &rx_sd);
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
- &pcs_status);
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
- &val2);
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
- &val2);
-
- DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x"
- " pcs_status 0x%x 1Gbps link_status 0x%x\n",
- rx_sd, pcs_status, val2);
- /* link is up if both bit 0 of pmd_rx_sd and
- * bit 0 of pcs_status are set, or if the autoneg bit
- 1 is set
- */
- ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
- (val2 & (1<<1)));
- if (ext_phy_link_up) {
- if (ext_phy_type ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
- /* If transmitter is disabled,
- ignore false link up indication */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_PHY_IDENTIFIER,
- &val1);
- if (val1 & (1<<15)) {
- DP(NETIF_MSG_LINK, "Tx is "
- "disabled\n");
- ext_phy_link_up = 0;
- break;
- }
- }
- if (val2 & (1<<1))
- vars->line_speed = SPEED_1000;
- else
- vars->line_speed = SPEED_10000;
- }
- break;
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
- {
- u16 link_status = 0;
- u16 rx_alarm_status;
- /* Check the LASI */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
-
- DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
- rx_alarm_status);
-
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_LASI_STATUS, &val1);
+ DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
- DP(NETIF_MSG_LINK,
- "8727 LASI status 0x%x\n",
- val1);
+ /* Clear MSG-OUT */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
- /* Clear MSG-OUT */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_M8051_MSGOUT_REG,
- &val1);
+ /**
+ * If a module is present and there is need to check
+ * for over current
+ */
+ if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
+ /* Check over-current using 8727 GPIO0 input*/
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
+ &val1);
+
+ if ((val1 & (1<<8)) == 0) {
+ DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
+ " on port %d\n", params->port);
+ netdev_err(bp->dev, "Error: Power fault on Port %d has"
+ " been detected and the power to "
+ "that SFP+ module has been removed"
+ " to prevent failure of the card."
+ " Please remove the SFP+ module and"
+ " restart the system to clear this"
+ " error.\n",
+ params->port);
/*
- * If a module is present and there is need to check
- * for over current
+ * Disable all RX_ALARMs except for
+ * mod_abs
*/
- if (!(params->feature_config_flags &
- FEATURE_CONFIG_BCM8727_NOC) &&
- !(rx_alarm_status & (1<<5))) {
- /* Check over-current using 8727 GPIO0 input*/
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8727_GPIO_CTRL,
- &val1);
-
- if ((val1 & (1<<8)) == 0) {
- DP(NETIF_MSG_LINK, "8727 Power fault"
- " has been detected on "
- "port %d\n",
- params->port);
- netdev_err(bp->dev, "Error: Power fault on Port %d has been detected and the power to that SFP+ module has been removed to prevent failure of the card. Please remove the SFP+ module and restart the system to clear this error.\n",
- params->port);
- /*
- * Disable all RX_ALARMs except for
- * mod_abs
- */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_RX_ALARM_CTRL,
- (1<<5));
-
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_PHY_IDENTIFIER,
- &val1);
- /* Wait for module_absent_event */
- val1 |= (1<<8);
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_PHY_IDENTIFIER,
- val1);
- /* Clear RX alarm */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_RX_ALARM,
- &rx_alarm_status);
- break;
- }
- } /* Over current check */
-
- /* When module absent bit is set, check module */
- if (rx_alarm_status & (1<<5)) {
- bnx2x_8727_handle_mod_abs(params);
- /* Enable all mod_abs and link detection bits */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_RX_ALARM_CTRL,
- ((1<<5) | (1<<2)));
- }
-
- /* If transmitter is disabled,
- ignore false link up indication */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_PHY_IDENTIFIER,
- &val1);
- if (val1 & (1<<15)) {
- DP(NETIF_MSG_LINK, "Tx is disabled\n");
- ext_phy_link_up = 0;
- break;
- }
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5));
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
- &link_status);
-
- /* Bits 0..2 --> speed detected,
- bits 13..15--> link is down */
- if ((link_status & (1<<2)) &&
- (!(link_status & (1<<15)))) {
- ext_phy_link_up = 1;
- vars->line_speed = SPEED_10000;
- } else if ((link_status & (1<<0)) &&
- (!(link_status & (1<<13)))) {
- ext_phy_link_up = 1;
- vars->line_speed = SPEED_1000;
- DP(NETIF_MSG_LINK,
- "port %x: External link"
- " up in 1G\n", params->port);
- } else {
- ext_phy_link_up = 0;
- DP(NETIF_MSG_LINK,
- "port %x: External link"
- " is down\n", params->port);
- }
- break;
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
+ /* Wait for module_absent_event */
+ val1 |= (1<<8);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, val1);
+ /* Clear RX alarm */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+ return 0;
}
+ } /* Over current check */
+
+ /* When module absent bit is set, check module */
+ if (rx_alarm_status & (1<<5)) {
+ bnx2x_8727_handle_mod_abs(phy, params);
+ /* Enable all mod_abs and link detection bits */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
+ ((1<<5) | (1<<2)));
+ }
+ DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n");
+ bnx2x_8727_specific_func(phy, params, ENABLE_TX);
+ /* If transmitter is disabled, ignore false link up indication */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
+ if (val1 & (1<<15)) {
+ DP(NETIF_MSG_LINK, "Tx is disabled\n");
+ return 0;
+ }
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
- {
- u16 link_status = 0;
- u16 an1000_status = 0;
-
- if (ext_phy_type ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PCS_DEVAD,
- MDIO_PCS_REG_LASI_STATUS, &val1);
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PCS_DEVAD,
- MDIO_PCS_REG_LASI_STATUS, &val2);
- DP(NETIF_MSG_LINK,
- "870x LASI status 0x%x->0x%x\n",
- val1, val2);
- } else {
- /* In 8073, port1 is directed through emac0 and
- * port0 is directed through emac1
- */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_LASI_STATUS, &val1);
-
- DP(NETIF_MSG_LINK,
- "8703 LASI status 0x%x\n",
- val1);
- }
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
- /* clear the interrupt LASI status register */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PCS_DEVAD,
- MDIO_PCS_REG_STATUS, &val2);
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PCS_DEVAD,
- MDIO_PCS_REG_STATUS, &val1);
- DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n",
- val2, val1);
- /* Clear MSG-OUT */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_M8051_MSGOUT_REG,
- &val1);
-
- /* Check the LASI */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_RX_ALARM, &val2);
-
- DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
-
- /* Check the link status */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PCS_DEVAD,
- MDIO_PCS_REG_STATUS, &val2);
- DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
-
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_STATUS, &val2);
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_STATUS, &val1);
- ext_phy_link_up = ((val1 & 4) == 4);
- DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
- if (ext_phy_type ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
-
- if (ext_phy_link_up &&
- ((params->req_line_speed !=
- SPEED_10000))) {
- if (bnx2x_bcm8073_xaui_wa(params)
- != 0) {
- ext_phy_link_up = 0;
- break;
- }
- }
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_LINK_STATUS,
- &an1000_status);
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_LINK_STATUS,
- &an1000_status);
-
- /* Check the link status on 1.1.2 */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_STATUS, &val2);
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_STATUS, &val1);
- DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
- "an_link_status=0x%x\n",
- val2, val1, an1000_status);
-
- ext_phy_link_up = (((val1 & 4) == 4) ||
- (an1000_status & (1<<1)));
- if (ext_phy_link_up &&
- bnx2x_8073_is_snr_needed(params)) {
- /* The SNR will improve about 2dbby
- changing the BW and FEE main tap.*/
-
- /* The 1st write to change FFE main
- tap is set before restart AN */
- /* Change PLL Bandwidth in EDC
- register */
- bnx2x_cl45_write(bp, port, ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_PLL_BANDWIDTH,
- 0x26BC);
-
- /* Change CDR Bandwidth in EDC
- register */
- bnx2x_cl45_write(bp, port, ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CDR_BANDWIDTH,
- 0x0333);
- }
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
- &link_status);
-
- /* Bits 0..2 --> speed detected,
- bits 13..15--> link is down */
- if ((link_status & (1<<2)) &&
- (!(link_status & (1<<15)))) {
- ext_phy_link_up = 1;
- vars->line_speed = SPEED_10000;
- DP(NETIF_MSG_LINK,
- "port %x: External link"
- " up in 10G\n", params->port);
- } else if ((link_status & (1<<1)) &&
- (!(link_status & (1<<14)))) {
- ext_phy_link_up = 1;
- vars->line_speed = SPEED_2500;
- DP(NETIF_MSG_LINK,
- "port %x: External link"
- " up in 2.5G\n", params->port);
- } else if ((link_status & (1<<0)) &&
- (!(link_status & (1<<13)))) {
- ext_phy_link_up = 1;
- vars->line_speed = SPEED_1000;
- DP(NETIF_MSG_LINK,
- "port %x: External link"
- " up in 1G\n", params->port);
- } else {
- ext_phy_link_up = 0;
- DP(NETIF_MSG_LINK,
- "port %x: External link"
- " is down\n", params->port);
- }
- } else {
- /* See if 1G link is up for the 8072 */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_LINK_STATUS,
- &an1000_status);
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_LINK_STATUS,
- &an1000_status);
- if (an1000_status & (1<<1)) {
- ext_phy_link_up = 1;
- vars->line_speed = SPEED_1000;
- DP(NETIF_MSG_LINK,
- "port %x: External link"
- " up in 1G\n", params->port);
- } else if (ext_phy_link_up) {
- ext_phy_link_up = 1;
- vars->line_speed = SPEED_10000;
- DP(NETIF_MSG_LINK,
- "port %x: External link"
- " up in 10G\n", params->port);
- }
- }
+ /* Bits 0..2 --> speed detected,
+ bits 13..15--> link is down */
+ if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
+ link_up = 1;
+ vars->line_speed = SPEED_10000;
+ } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
+ link_up = 1;
+ vars->line_speed = SPEED_1000;
+ DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
+ params->port);
+ } else {
+ link_up = 0;
+ DP(NETIF_MSG_LINK, "port %x: External link is down\n",
+ params->port);
+ }
+ if (link_up)
+ bnx2x_ext_phy_resolve_fc(phy, params, vars);
+
+ if ((DUAL_MEDIA(params)) &&
+ (phy->req_line_speed == SPEED_1000)) {
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_GP, &val1);
+ /**
+ * In case of dual-media board and 1G, power up the XAUI side,
+ * otherwise power it down. For 10G it is done automatically
+ */
+ if (link_up)
+ val1 &= ~(3<<10);
+ else
+ val1 |= (3<<10);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_GP, val1);
+ }
+ return link_up;
+}
+static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
+ struct link_params *params)
+{
+ struct bnx2x *bp = params->bp;
+ /* Disable Transmitter */
+ bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
+ /* Clear LASI */
+ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0);
- break;
- }
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_LASI_STATUS, &val2);
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_LASI_STATUS, &val1);
- DP(NETIF_MSG_LINK,
- "10G-base-T LASI status 0x%x->0x%x\n",
- val2, val1);
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_STATUS, &val2);
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_STATUS, &val1);
- DP(NETIF_MSG_LINK,
- "10G-base-T PMA status 0x%x->0x%x\n",
- val2, val1);
- ext_phy_link_up = ((val1 & 4) == 4);
- /* if link is up
- * print the AN outcome of the SFX7101 PHY
- */
- if (ext_phy_link_up) {
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_MASTER_STATUS,
- &val2);
- vars->line_speed = SPEED_10000;
- DP(NETIF_MSG_LINK,
- "SFX7101 AN status 0x%x->Master=%x\n",
- val2,
- (val2 & (1<<14)));
- }
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
- /* Check 10G-BaseT link status */
- /* Check PMD signal ok */
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- 0xFFFA,
- &val1);
- bnx2x_cl45_read(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8481_PMD_SIGNAL,
- &val2);
- DP(NETIF_MSG_LINK, "PMD_SIGNAL 1.a811 = 0x%x\n", val2);
-
- /* Check link 10G */
- if (val2 & (1<<11)) {
- vars->line_speed = SPEED_10000;
- ext_phy_link_up = 1;
- bnx2x_8481_set_10G_led_mode(params,
- ext_phy_type,
- ext_phy_addr);
- } else { /* Check Legacy speed link */
- u16 legacy_status, legacy_speed;
-
- /* Enable expansion register 0x42
- (Operation mode status) */
- bnx2x_cl45_write(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_8481_EXPANSION_REG_ACCESS,
- 0xf42);
-
- /* Get legacy speed operation status */
- bnx2x_cl45_read(bp, params->port,
- ext_phy_type,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
- &legacy_status);
-
- DP(NETIF_MSG_LINK, "Legacy speed status"
- " = 0x%x\n", legacy_status);
- ext_phy_link_up = ((legacy_status & (1<<11))
- == (1<<11));
- if (ext_phy_link_up) {
- legacy_speed = (legacy_status & (3<<9));
- if (legacy_speed == (0<<9))
- vars->line_speed = SPEED_10;
- else if (legacy_speed == (1<<9))
- vars->line_speed =
- SPEED_100;
- else if (legacy_speed == (2<<9))
- vars->line_speed =
- SPEED_1000;
- else /* Should not happen */
- vars->line_speed = 0;
-
- if (legacy_status & (1<<8))
- vars->duplex = DUPLEX_FULL;
- 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));
- bnx2x_8481_set_legacy_led_mode(params,
- ext_phy_type,
- ext_phy_addr);
- }
- }
- break;
- default:
- DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
- params->ext_phy_config);
- ext_phy_link_up = 0;
- break;
- }
- /* Set SGMII mode for external phy */
- if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
- if (vars->line_speed < SPEED_1000)
- vars->phy_flags |= PHY_SGMII_FLAG;
- else
- vars->phy_flags &= ~PHY_SGMII_FLAG;
- }
+}
- } else { /* SerDes */
- ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
- switch (ext_phy_type) {
- case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
- DP(NETIF_MSG_LINK, "SerDes Direct\n");
- ext_phy_link_up = 1;
- break;
+/******************************************************************/
+/* BCM8481/BCM84823/BCM84833 PHY SECTION */
+/******************************************************************/
+static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
+ struct link_params *params)
+{
+ u16 val, fw_ver1, fw_ver2, cnt;
+ struct bnx2x *bp = params->bp;
- case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
- DP(NETIF_MSG_LINK, "SerDes 5482\n");
- ext_phy_link_up = 1;
+ /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
+ /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
+ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
+ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
+ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
+ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
+ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
+
+ for (cnt = 0; cnt < 100; cnt++) {
+ bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
+ if (val & 1)
break;
+ udelay(5);
+ }
+ if (cnt == 100) {
+ DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n");
+ bnx2x_save_spirom_version(bp, params->port, 0,
+ phy->ver_addr);
+ return;
+ }
- default:
- DP(NETIF_MSG_LINK,
- "BAD SerDes ext_phy_config 0x%x\n",
- params->ext_phy_config);
- ext_phy_link_up = 0;
+
+ /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
+ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
+ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
+ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
+ for (cnt = 0; cnt < 100; cnt++) {
+ bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
+ if (val & 1)
break;
- }
+ udelay(5);
+ }
+ if (cnt == 100) {
+ DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
+ bnx2x_save_spirom_version(bp, params->port, 0,
+ phy->ver_addr);
+ return;
}
- return ext_phy_link_up;
+ /* lower 16 bits of the register SPI_FW_STATUS */
+ bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
+ /* upper 16 bits of register SPI_FW_STATUS */
+ bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
+
+ bnx2x_save_spirom_version(bp, params->port, (fw_ver2<<16) | fw_ver1,
+ phy->ver_addr);
}
-static void bnx2x_link_int_enable(struct link_params *params)
+static void bnx2x_848xx_set_led(struct bnx2x *bp,
+ struct bnx2x_phy *phy)
{
- u8 port = params->port;
- u32 ext_phy_type;
- u32 mask;
- struct bnx2x *bp = params->bp;
+ u16 val;
- /* setting the status to report on link up
- for either XGXS or SerDes */
+ /* PHYC_CTL_LED_CTL */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
+ val &= 0xFE00;
+ val |= 0x0092;
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LINK_SIGNAL, val);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED1_MASK,
+ 0x80);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED2_MASK,
+ 0x18);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED3_MASK,
+ 0x0040);
- if (params->switch_cfg == SWITCH_CFG_10G) {
- mask = (NIG_MASK_XGXS0_LINK10G |
- NIG_MASK_XGXS0_LINK_STATUS);
- DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
- ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
- if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
- (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
- (ext_phy_type !=
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
- mask |= NIG_MASK_MI_INT;
- DP(NETIF_MSG_LINK, "enabled external phy int\n");
- }
+ /* 'Interrupt Mask' */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD,
+ 0xFFFB, 0xFFFD);
+}
- } else { /* SerDes */
- mask = NIG_MASK_SERDES0_LINK_STATUS;
- DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
- ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
- if ((ext_phy_type !=
- PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
- (ext_phy_type !=
- PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
- mask |= NIG_MASK_MI_INT;
- DP(NETIF_MSG_LINK, "enabled external phy int\n");
- }
+static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
+{
+ struct bnx2x *bp = params->bp;
+ u16 autoneg_val, an_1000_val, an_10_100_val;
+ bnx2x_wait_reset_complete(bp, phy);
+ bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
+ 1 << NIG_LATCH_BC_ENABLE_MI_INT);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
+
+ bnx2x_848xx_set_led(bp, phy);
+
+ /* set 1000 speed advertisement */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
+ &an_1000_val);
+
+ bnx2x_ext_phy_set_pause(params, phy, vars);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_LEGACY_AN_ADV,
+ &an_10_100_val);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
+ &autoneg_val);
+ /* Disable forced speed */
+ autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
+ an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
+
+ if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
+ (phy->speed_cap_mask &
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
+ (phy->req_line_speed == SPEED_1000)) {
+ an_1000_val |= (1<<8);
+ autoneg_val |= (1<<9 | 1<<12);
+ if (phy->req_duplex == DUPLEX_FULL)
+ an_1000_val |= (1<<9);
+ DP(NETIF_MSG_LINK, "Advertising 1G\n");
+ } else
+ an_1000_val &= ~((1<<8) | (1<<9));
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
+ an_1000_val);
+
+ /* set 10 speed advertisement */
+ if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
+ (phy->speed_cap_mask &
+ (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
+ an_10_100_val |= (1<<7);
+ /* Enable autoneg and restart autoneg for legacy speeds */
+ autoneg_val |= (1<<9 | 1<<12);
+
+ if (phy->req_duplex == DUPLEX_FULL)
+ an_10_100_val |= (1<<8);
+ DP(NETIF_MSG_LINK, "Advertising 100M\n");
+ }
+ /* set 10 speed advertisement */
+ if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
+ (phy->speed_cap_mask &
+ (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
+ an_10_100_val |= (1<<5);
+ autoneg_val |= (1<<9 | 1<<12);
+ if (phy->req_duplex == DUPLEX_FULL)
+ an_10_100_val |= (1<<6);
+ DP(NETIF_MSG_LINK, "Advertising 10M\n");
}
- bnx2x_bits_en(bp,
- NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
- mask);
- DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
- (params->switch_cfg == SWITCH_CFG_10G),
- REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
- DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
- REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
- REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
- REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
- DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
- REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
- REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
-}
+ /* Only 10/100 are allowed to work in FORCE mode */
+ if (phy->req_line_speed == SPEED_100) {
+ autoneg_val |= (1<<13);
+ /* Enabled AUTO-MDIX when autoneg is disabled */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
+ (1<<15 | 1<<9 | 7<<0));
+ DP(NETIF_MSG_LINK, "Setting 100M force\n");
+ }
+ if (phy->req_line_speed == SPEED_10) {
+ /* Enabled AUTO-MDIX when autoneg is disabled */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
+ (1<<15 | 1<<9 | 7<<0));
+ DP(NETIF_MSG_LINK, "Setting 10M force\n");
+ }
-static void bnx2x_8481_rearm_latch_signal(struct bnx2x *bp, u8 port,
- u8 is_mi_int)
-{
- u32 latch_status = 0, is_mi_int_status;
- /* Disable the MI INT ( external phy int )
- * by writing 1 to the status register. Link down indication
- * is high-active-signal, so in this case we need to write the
- * status to clear the XOR
- */
- /* Read Latched signals */
- latch_status = REG_RD(bp,
- NIG_REG_LATCH_STATUS_0 + port*8);
- is_mi_int_status = REG_RD(bp,
- NIG_REG_STATUS_INTERRUPT_PORT0 + port*4);
- DP(NETIF_MSG_LINK, "original_signal = 0x%x, nig_status = 0x%x,"
- "latch_status = 0x%x\n",
- is_mi_int, is_mi_int_status, latch_status);
- /* Handle only those with latched-signal=up.*/
- if (latch_status & 1) {
- /* For all latched-signal=up,Write original_signal to status */
- if (is_mi_int)
- bnx2x_bits_en(bp,
- NIG_REG_STATUS_INTERRUPT_PORT0
- + port*4,
- NIG_STATUS_EMAC0_MI_INT);
- else
- bnx2x_bits_dis(bp,
- NIG_REG_STATUS_INTERRUPT_PORT0
- + port*4,
- NIG_STATUS_EMAC0_MI_INT);
- /* For all latched-signal=up : Re-Arm Latch signals */
- REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
- (latch_status & 0xfffe) | (latch_status & 1));
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
+ an_10_100_val);
+
+ if (phy->req_duplex == DUPLEX_FULL)
+ autoneg_val |= (1<<8);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
+
+ if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
+ (phy->speed_cap_mask &
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
+ (phy->req_line_speed == SPEED_10000)) {
+ DP(NETIF_MSG_LINK, "Advertising 10G\n");
+ /* Restart autoneg for 10G*/
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
+ 0x3200);
+ } else if (phy->req_line_speed != SPEED_10 &&
+ phy->req_line_speed != SPEED_100) {
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
+ 1);
}
+ /* Save spirom version */
+ bnx2x_save_848xx_spirom_version(phy, params);
+
+ return 0;
}
-/*
- * link management
- */
-static void bnx2x_link_int_ack(struct link_params *params,
- struct link_vars *vars, u8 is_10g,
- u8 is_mi_int)
+
+static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
- u8 port = params->port;
+ /* Restore normal power mode*/
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+ MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
- /* first reset all status
- * we assume only one line will be change at a time */
- bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
- (NIG_STATUS_XGXS0_LINK10G |
- NIG_STATUS_XGXS0_LINK_STATUS |
- NIG_STATUS_SERDES0_LINK_STATUS));
- if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config)
- == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) ||
- (XGXS_EXT_PHY_TYPE(params->ext_phy_config)
- == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823)) {
- bnx2x_8481_rearm_latch_signal(bp, port, is_mi_int);
- }
- if (vars->phy_link_up) {
- if (is_10g) {
- /* Disable the 10G link interrupt
- * by writing 1 to the status register
- */
- DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
- bnx2x_bits_en(bp,
- NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
- NIG_STATUS_XGXS0_LINK10G);
+ /* HW reset */
+ bnx2x_ext_phy_hw_reset(bp, params->port);
- } else if (params->switch_cfg == SWITCH_CFG_10G) {
- /* Disable the link interrupt
- * by writing 1 to the relevant lane
- * in the status register
- */
- u32 ser_lane = ((params->lane_config &
- PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
- PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
+ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
+ return bnx2x_848xx_cmn_config_init(phy, params, vars);
+}
- DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
- vars->line_speed);
- bnx2x_bits_en(bp,
- NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
- ((1 << ser_lane) <<
- NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
+static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
+{
+ struct bnx2x *bp = params->bp;
+ u8 port = params->port, initialize = 1;
+ u16 val;
+ u16 temp;
+ u32 actual_phy_selection;
+ u8 rc = 0;
- } else { /* SerDes */
- DP(NETIF_MSG_LINK, "SerDes phy link up\n");
- /* Disable the link interrupt
- * by writing 1 to the status register
- */
- bnx2x_bits_en(bp,
- NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
- NIG_STATUS_SERDES0_LINK_STATUS);
- }
+ /* This is just for MDIO_CTL_REG_84823_MEDIA register. */
- } else { /* link_down */
+ msleep(1);
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
+ MISC_REGISTERS_GPIO_OUTPUT_HIGH,
+ port);
+ msleep(200); /* 100 is not enough */
+
+ /* BCM84823 requires that XGXS links up first @ 10G for normal
+ behavior */
+ temp = vars->line_speed;
+ vars->line_speed = SPEED_10000;
+ bnx2x_set_autoneg(&params->phy[INT_PHY], params, vars, 0);
+ bnx2x_program_serdes(&params->phy[INT_PHY], params, vars);
+ vars->line_speed = temp;
+
+ /* Set dual-media configuration according to configuration */
+
+ bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
+ MDIO_CTL_REG_84823_MEDIA, &val);
+ val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK |
+ MDIO_CTL_REG_84823_MEDIA_LINE_MASK |
+ MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN |
+ MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK |
+ MDIO_CTL_REG_84823_MEDIA_FIBER_1G);
+ val |= MDIO_CTL_REG_84823_CTRL_MAC_XFI |
+ MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L;
+
+ actual_phy_selection = bnx2x_phy_selection(params);
+
+ switch (actual_phy_selection) {
+ case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
+ /* Do nothing. Essentialy this is like the priority copper */
+ break;
+ case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
+ val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER;
+ break;
+ case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
+ val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER;
+ break;
+ case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
+ /* Do nothing here. The first PHY won't be initialized at all */
+ break;
+ case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
+ val |= MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN;
+ initialize = 0;
+ break;
}
+ if (params->phy[EXT_PHY2].req_line_speed == SPEED_1000)
+ val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G;
+
+ bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
+ MDIO_CTL_REG_84823_MEDIA, val);
+ DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n",
+ params->multi_phy_config, val);
+
+ if (initialize)
+ rc = bnx2x_848xx_cmn_config_init(phy, params, vars);
+ else
+ bnx2x_save_848xx_spirom_version(phy, params);
+ return rc;
}
-static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
+static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
{
- u8 *str_ptr = str;
- u32 mask = 0xf0000000;
- u8 shift = 8*4;
- u8 digit;
- if (len < 10) {
- /* Need more than 10chars for this format */
- *str_ptr = '\0';
- return -EINVAL;
- }
- while (shift > 0) {
+ struct bnx2x *bp = params->bp;
+ u16 val, val1, val2;
+ u8 link_up = 0;
+
+ /* Check 10G-BaseT link status */
+ /* Check PMD signal ok */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD, 0xFFFA, &val1);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
+ &val2);
+ DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
+
+ /* Check link 10G */
+ if (val2 & (1<<11)) {
+ vars->line_speed = SPEED_10000;
+ link_up = 1;
+ bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
+ } else { /* Check Legacy speed link */
+ u16 legacy_status, legacy_speed;
+
+ /* Enable expansion register 0x42 (Operation mode status) */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
+
+ /* Get legacy speed operation status */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
+ &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));
+ if (legacy_speed == (0<<9))
+ vars->line_speed = SPEED_10;
+ else if (legacy_speed == (1<<9))
+ vars->line_speed = SPEED_100;
+ else if (legacy_speed == (2<<9))
+ vars->line_speed = SPEED_1000;
+ else /* Should not happen */
+ vars->line_speed = 0;
- shift -= 4;
- digit = ((num & mask) >> shift);
- if (digit < 0xa)
- *str_ptr = digit + '0';
- else
- *str_ptr = digit - 0xa + 'a';
- str_ptr++;
- mask = mask >> 4;
- if (shift == 4*4) {
- *str_ptr = ':';
- str_ptr++;
+ if (legacy_status & (1<<8))
+ vars->duplex = DUPLEX_FULL;
+ 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));
+ /* Check legacy speed AN resolution */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_LEGACY_MII_STATUS,
+ &val);
+ if (val & (1<<5))
+ vars->link_status |=
+ LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
+ &val);
+ if ((val & (1<<0)) == 0)
+ vars->link_status |=
+ LINK_STATUS_PARALLEL_DETECTION_USED;
}
}
- *str_ptr = '\0';
- return 0;
+ if (link_up) {
+ DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
+ vars->line_speed);
+ bnx2x_ext_phy_resolve_fc(phy, params, vars);
+ }
+
+ return link_up;
}
-u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
- u8 *version, u16 len)
+static u8 bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
{
- struct bnx2x *bp;
- u32 ext_phy_type = 0;
- u32 spirom_ver = 0;
- u8 status;
+ u8 status = 0;
+ u32 spirom_ver;
+ spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
+ status = bnx2x_format_ver(spirom_ver, str, len);
+ return status;
+}
- if (version == NULL || params == NULL)
- return -EINVAL;
- bp = params->bp;
+static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
+ struct link_params *params)
+{
+ bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
+ bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
+}
- spirom_ver = REG_RD(bp, params->shmem_base +
- offsetof(struct shmem_region,
- port_mb[params->port].ext_phy_fw_version));
+static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
+ struct link_params *params)
+{
+ bnx2x_cl45_write(params->bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
+ bnx2x_cl45_write(params->bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
+}
- status = 0;
- /* reset the returned value to zero */
- ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
- switch (ext_phy_type) {
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
+ struct link_params *params)
+{
+ struct bnx2x *bp = params->bp;
+ u8 port = params->port;
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW,
+ port);
+}
- if (len < 5)
- return -EINVAL;
+static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
+ struct link_params *params, u8 mode)
+{
+ struct bnx2x *bp = params->bp;
+ u16 val;
- version[0] = (spirom_ver & 0xFF);
- version[1] = (spirom_ver & 0xFF00) >> 8;
- version[2] = (spirom_ver & 0xFF0000) >> 16;
- version[3] = (spirom_ver & 0xFF000000) >> 24;
- version[4] = '\0';
+ switch (mode) {
+ case LED_MODE_OFF:
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
- status = bnx2x_format_ver(spirom_ver, version, len);
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
- spirom_ver = ((spirom_ver & 0xF80) >> 7) << 16 |
- (spirom_ver & 0x7F);
- status = bnx2x_format_ver(spirom_ver, version, len);
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
- version[0] = '\0';
- break;
+ DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", params->port);
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
- DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
- " type is FAILURE!\n");
- status = -EINVAL;
+ if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
+ SHARED_HW_CFG_LED_EXTPHY1) {
+
+ /* Set LED masks */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED1_MASK,
+ 0x0);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED2_MASK,
+ 0x0);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED3_MASK,
+ 0x0);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED5_MASK,
+ 0x0);
+
+ } else {
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED1_MASK,
+ 0x0);
+ }
break;
+ case LED_MODE_FRONT_PANEL_OFF:
- default:
+ DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n",
+ params->port);
+
+ if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
+ SHARED_HW_CFG_LED_EXTPHY1) {
+
+ /* Set LED masks */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED1_MASK,
+ 0x0);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED2_MASK,
+ 0x0);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED3_MASK,
+ 0x0);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED5_MASK,
+ 0x20);
+
+ } else {
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED1_MASK,
+ 0x0);
+ }
break;
- }
- return status;
-}
+ case LED_MODE_ON:
-static void bnx2x_set_xgxs_loopback(struct link_params *params,
- struct link_vars *vars,
- u8 is_10g)
-{
- u8 port = params->port;
- struct bnx2x *bp = params->bp;
+ DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", params->port);
- if (is_10g) {
- u32 md_devad;
+ if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
+ SHARED_HW_CFG_LED_EXTPHY1) {
+ /* Set control reg */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LINK_SIGNAL,
+ &val);
+ val &= 0x8000;
+ val |= 0x2492;
- DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LINK_SIGNAL,
+ val);
- /* change the uni_phy_addr in the nig */
- md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
- port*0x18));
+ /* Set LED masks */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED1_MASK,
+ 0x0);
- REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED2_MASK,
+ 0x20);
- bnx2x_cl45_write(bp, port, 0,
- params->phy_addr,
- 5,
- (MDIO_REG_BANK_AER_BLOCK +
- (MDIO_AER_BLOCK_AER_REG & 0xf)),
- 0x2800);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED3_MASK,
+ 0x20);
- bnx2x_cl45_write(bp, port, 0,
- params->phy_addr,
- 5,
- (MDIO_REG_BANK_CL73_IEEEB0 +
- (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
- 0x6041);
- msleep(200);
- /* set aer mmd back */
- bnx2x_set_aer_mmd(params, vars);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED5_MASK,
+ 0x0);
+ } else {
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED1_MASK,
+ 0x20);
+ }
+ break;
- /* and md_devad */
- REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
- md_devad);
+ case LED_MODE_OPER:
- } else {
- u16 mii_control;
+ DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", params->port);
- DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
+ if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
+ SHARED_HW_CFG_LED_EXTPHY1) {
- CL45_RD_OVER_CL22(bp, port,
- params->phy_addr,
- MDIO_REG_BANK_COMBO_IEEE0,
- MDIO_COMBO_IEEE0_MII_CONTROL,
- &mii_control);
+ /* Set control reg */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LINK_SIGNAL,
+ &val);
+
+ if (!((val &
+ MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK)
+ >> MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT)){
+ DP(NETIF_MSG_LINK, "Seting LINK_SIGNAL\n");
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LINK_SIGNAL,
+ 0xa492);
+ }
- CL45_WR_OVER_CL22(bp, port,
- params->phy_addr,
- MDIO_REG_BANK_COMBO_IEEE0,
- MDIO_COMBO_IEEE0_MII_CONTROL,
- (mii_control |
- MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
+ /* Set LED masks */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED1_MASK,
+ 0x10);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED2_MASK,
+ 0x80);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED3_MASK,
+ 0x98);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED5_MASK,
+ 0x40);
+
+ } else {
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED1_MASK,
+ 0x80);
+ }
+ break;
}
}
+/******************************************************************/
+/* SFX7101 PHY SECTION */
+/******************************************************************/
+static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
+ struct link_params *params)
+{
+ struct bnx2x *bp = params->bp;
+ /* SFX7101_XGXS_TEST1 */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
+}
-
-static void bnx2x_ext_phy_loopback(struct link_params *params)
+static u8 bnx2x_7101_config_init(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
{
+ u16 fw_ver1, fw_ver2, val;
struct bnx2x *bp = params->bp;
- u8 ext_phy_addr;
- u32 ext_phy_type;
+ DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
- if (params->switch_cfg == SWITCH_CFG_10G) {
- ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
- ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
- /* CL37 Autoneg Enabled */
- switch (ext_phy_type) {
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
- DP(NETIF_MSG_LINK,
- "ext_phy_loopback: We should not get here\n");
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
- DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
- DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
- DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CTRL,
- 0x0001);
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
- /* SFX7101_XGXS_TEST1 */
- bnx2x_cl45_write(bp, params->port, ext_phy_type,
- ext_phy_addr,
- MDIO_XS_DEVAD,
- MDIO_XS_SFX7101_XGXS_TEST1,
- 0x100);
- DP(NETIF_MSG_LINK,
- "ext_phy_loopback: set ext phy loopback\n");
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
+ /* Restore normal power mode*/
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+ MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
+ /* HW reset */
+ bnx2x_ext_phy_hw_reset(bp, params->port);
+ bnx2x_wait_reset_complete(bp, phy);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1);
+ DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
+
+ bnx2x_ext_phy_set_pause(params, phy, vars);
+ /* Restart autoneg */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
+ val |= 0x200;
+ bnx2x_cl45_write(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
+
+ /* Save spirom version */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
+
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
+ bnx2x_save_spirom_version(bp, params->port,
+ (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
+ return 0;
+}
- break;
- } /* switch external PHY type */
- } else {
- /* serdes */
- ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
- ext_phy_addr = (params->ext_phy_config &
- PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK)
- >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT;
+static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
+{
+ struct bnx2x *bp = params->bp;
+ u8 link_up;
+ u16 val1, val2;
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
+ DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
+ val2, val1);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
+ DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
+ val2, val1);
+ link_up = ((val1 & 4) == 4);
+ /* if link is up
+ * print the AN outcome of the SFX7101 PHY
+ */
+ if (link_up) {
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
+ &val2);
+ vars->line_speed = SPEED_10000;
+ DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
+ val2, (val2 & (1<<14)));
+ bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
+ bnx2x_ext_phy_resolve_fc(phy, params, vars);
}
+ return link_up;
}
-/*
- *------------------------------------------------------------------------
- * bnx2x_override_led_value -
- *
- * Override the led value of the requsted led
- *
- *------------------------------------------------------------------------
- */
-u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
- u32 led_idx, u32 value)
+static u8 bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
{
- u32 reg_val;
+ if (*len < 5)
+ return -EINVAL;
+ str[0] = (spirom_ver & 0xFF);
+ str[1] = (spirom_ver & 0xFF00) >> 8;
+ str[2] = (spirom_ver & 0xFF0000) >> 16;
+ str[3] = (spirom_ver & 0xFF000000) >> 24;
+ str[4] = '\0';
+ *len -= 5;
+ return 0;
+}
- /* If port 0 then use EMAC0, else use EMAC1*/
- u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
+{
+ u16 val, cnt;
- DP(NETIF_MSG_LINK,
- "bnx2x_override_led_value() port %x led_idx %d value %d\n",
- port, led_idx, value);
-
- switch (led_idx) {
- case 0: /* 10MB led */
- /* Read the current value of the LED register in
- the EMAC block */
- reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
- /* Set the OVERRIDE bit to 1 */
- reg_val |= EMAC_LED_OVERRIDE;
- /* If value is 1, set the 10M_OVERRIDE bit,
- otherwise reset it.*/
- reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
- (reg_val & ~EMAC_LED_10MB_OVERRIDE);
- REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
- break;
- case 1: /*100MB led */
- /*Read the current value of the LED register in
- the EMAC block */
- reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
- /* Set the OVERRIDE bit to 1 */
- reg_val |= EMAC_LED_OVERRIDE;
- /* If value is 1, set the 100M_OVERRIDE bit,
- otherwise reset it.*/
- reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
- (reg_val & ~EMAC_LED_100MB_OVERRIDE);
- REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
- break;
- case 2: /* 1000MB led */
- /* Read the current value of the LED register in the
- EMAC block */
- reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
- /* Set the OVERRIDE bit to 1 */
- reg_val |= EMAC_LED_OVERRIDE;
- /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
- reset it. */
- reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
- (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
- REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
- break;
- case 3: /* 2500MB led */
- /* Read the current value of the LED register in the
- EMAC block*/
- reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
- /* Set the OVERRIDE bit to 1 */
- reg_val |= EMAC_LED_OVERRIDE;
- /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
- reset it.*/
- reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
- (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
- REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
- break;
- case 4: /*10G led */
- if (port == 0) {
- REG_WR(bp, NIG_REG_LED_10G_P0,
- value);
- } else {
- REG_WR(bp, NIG_REG_LED_10G_P1,
- value);
- }
- break;
- case 5: /* TRAFFIC led */
- /* Find if the traffic control is via BMAC or EMAC */
- if (port == 0)
- reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
- else
- reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
-
- /* Override the traffic led in the EMAC:*/
- if (reg_val == 1) {
- /* Read the current value of the LED register in
- the EMAC block */
- reg_val = REG_RD(bp, emac_base +
- EMAC_REG_EMAC_LED);
- /* Set the TRAFFIC_OVERRIDE bit to 1 */
- reg_val |= EMAC_LED_OVERRIDE;
- /* If value is 1, set the TRAFFIC bit, otherwise
- reset it.*/
- reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
- (reg_val & ~EMAC_LED_TRAFFIC);
- REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
- } else { /* Override the traffic led in the BMAC: */
- REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
- + port*4, 1);
- REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
- value);
- }
- break;
- default:
- DP(NETIF_MSG_LINK,
- "bnx2x_override_led_value() unknown led index %d "
- "(should be 0-5)\n", led_idx);
- return -EINVAL;
- }
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_7101_RESET, &val);
- return 0;
+ for (cnt = 0; cnt < 10; cnt++) {
+ msleep(50);
+ /* Writes a self-clearing reset */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_7101_RESET,
+ (val | (1<<15)));
+ /* Wait for clear */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_7101_RESET, &val);
+
+ if ((val & (1<<15)) == 0)
+ break;
+ }
}
+static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
+ struct link_params *params) {
+ /* Low power mode is controlled by GPIO 2 */
+ bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
+ /* The PHY reset is controlled by GPIO 1 */
+ bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
+}
-u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed)
+static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy,
+ struct link_params *params, u8 mode)
{
- u8 port = params->port;
- u16 hw_led_mode = params->hw_led_mode;
- u8 rc = 0;
- u32 tmp;
- u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
- u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+ u16 val = 0;
struct bnx2x *bp = params->bp;
- DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
- DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
- speed, hw_led_mode);
switch (mode) {
+ case LED_MODE_FRONT_PANEL_OFF:
case LED_MODE_OFF:
- REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
- REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
- SHARED_HW_CFG_LED_MAC1);
-
- tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
- EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
+ val = 2;
+ break;
+ case LED_MODE_ON:
+ val = 1;
break;
-
case LED_MODE_OPER:
- if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
- REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
- REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
+ val = 0;
+ break;
+ }
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_7107_LINK_LED_CNTL,
+ val);
+}
+
+/******************************************************************/
+/* STATIC PHY DECLARATION */
+/******************************************************************/
+
+static struct bnx2x_phy phy_null = {
+ .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
+ .addr = 0,
+ .flags = FLAGS_INIT_XGXS_FIRST,
+ .def_md_devad = 0,
+ .reserved = 0,
+ .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .mdio_ctrl = 0,
+ .supported = 0,
+ .media_type = ETH_PHY_NOT_PRESENT,
+ .ver_addr = 0,
+ .req_flow_ctrl = 0,
+ .req_line_speed = 0,
+ .speed_cap_mask = 0,
+ .req_duplex = 0,
+ .rsrv = 0,
+ .config_init = (config_init_t)NULL,
+ .read_status = (read_status_t)NULL,
+ .link_reset = (link_reset_t)NULL,
+ .config_loopback = (config_loopback_t)NULL,
+ .format_fw_ver = (format_fw_ver_t)NULL,
+ .hw_reset = (hw_reset_t)NULL,
+ .set_link_led = (set_link_led_t)NULL,
+ .phy_specific_func = (phy_specific_func_t)NULL
+};
+
+static struct bnx2x_phy phy_serdes = {
+ .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
+ .addr = 0xff,
+ .flags = 0,
+ .def_md_devad = 0,
+ .reserved = 0,
+ .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .mdio_ctrl = 0,
+ .supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_2500baseX_Full |
+ SUPPORTED_TP |
+ SUPPORTED_Autoneg |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause),
+ .media_type = ETH_PHY_UNSPECIFIED,
+ .ver_addr = 0,
+ .req_flow_ctrl = 0,
+ .req_line_speed = 0,
+ .speed_cap_mask = 0,
+ .req_duplex = 0,
+ .rsrv = 0,
+ .config_init = (config_init_t)bnx2x_init_serdes,
+ .read_status = (read_status_t)bnx2x_link_settings_status,
+ .link_reset = (link_reset_t)bnx2x_int_link_reset,
+ .config_loopback = (config_loopback_t)NULL,
+ .format_fw_ver = (format_fw_ver_t)NULL,
+ .hw_reset = (hw_reset_t)NULL,
+ .set_link_led = (set_link_led_t)NULL,
+ .phy_specific_func = (phy_specific_func_t)NULL
+};
+
+static struct bnx2x_phy phy_xgxs = {
+ .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
+ .addr = 0xff,
+ .flags = 0,
+ .def_md_devad = 0,
+ .reserved = 0,
+ .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .mdio_ctrl = 0,
+ .supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_2500baseX_Full |
+ SUPPORTED_10000baseT_Full |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Autoneg |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause),
+ .media_type = ETH_PHY_UNSPECIFIED,
+ .ver_addr = 0,
+ .req_flow_ctrl = 0,
+ .req_line_speed = 0,
+ .speed_cap_mask = 0,
+ .req_duplex = 0,
+ .rsrv = 0,
+ .config_init = (config_init_t)bnx2x_init_xgxs,
+ .read_status = (read_status_t)bnx2x_link_settings_status,
+ .link_reset = (link_reset_t)bnx2x_int_link_reset,
+ .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
+ .format_fw_ver = (format_fw_ver_t)NULL,
+ .hw_reset = (hw_reset_t)NULL,
+ .set_link_led = (set_link_led_t)NULL,
+ .phy_specific_func = (phy_specific_func_t)NULL
+};
+
+static struct bnx2x_phy phy_7101 = {
+ .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
+ .addr = 0xff,
+ .flags = FLAGS_FAN_FAILURE_DET_REQ,
+ .def_md_devad = 0,
+ .reserved = 0,
+ .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .mdio_ctrl = 0,
+ .supported = (SUPPORTED_10000baseT_Full |
+ SUPPORTED_TP |
+ SUPPORTED_Autoneg |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause),
+ .media_type = ETH_PHY_BASE_T,
+ .ver_addr = 0,
+ .req_flow_ctrl = 0,
+ .req_line_speed = 0,
+ .speed_cap_mask = 0,
+ .req_duplex = 0,
+ .rsrv = 0,
+ .config_init = (config_init_t)bnx2x_7101_config_init,
+ .read_status = (read_status_t)bnx2x_7101_read_status,
+ .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
+ .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
+ .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
+ .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
+ .set_link_led = (set_link_led_t)bnx2x_7101_set_link_led,
+ .phy_specific_func = (phy_specific_func_t)NULL
+};
+static struct bnx2x_phy phy_8073 = {
+ .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ .addr = 0xff,
+ .flags = FLAGS_HW_LOCK_REQUIRED,
+ .def_md_devad = 0,
+ .reserved = 0,
+ .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .mdio_ctrl = 0,
+ .supported = (SUPPORTED_10000baseT_Full |
+ SUPPORTED_2500baseX_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Autoneg |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause),
+ .media_type = ETH_PHY_UNSPECIFIED,
+ .ver_addr = 0,
+ .req_flow_ctrl = 0,
+ .req_line_speed = 0,
+ .speed_cap_mask = 0,
+ .req_duplex = 0,
+ .rsrv = 0,
+ .config_init = (config_init_t)bnx2x_8073_config_init,
+ .read_status = (read_status_t)bnx2x_8073_read_status,
+ .link_reset = (link_reset_t)bnx2x_8073_link_reset,
+ .config_loopback = (config_loopback_t)NULL,
+ .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
+ .hw_reset = (hw_reset_t)NULL,
+ .set_link_led = (set_link_led_t)NULL,
+ .phy_specific_func = (phy_specific_func_t)NULL
+};
+static struct bnx2x_phy phy_8705 = {
+ .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
+ .addr = 0xff,
+ .flags = FLAGS_INIT_XGXS_FIRST,
+ .def_md_devad = 0,
+ .reserved = 0,
+ .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .mdio_ctrl = 0,
+ .supported = (SUPPORTED_10000baseT_Full |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause),
+ .media_type = ETH_PHY_XFP_FIBER,
+ .ver_addr = 0,
+ .req_flow_ctrl = 0,
+ .req_line_speed = 0,
+ .speed_cap_mask = 0,
+ .req_duplex = 0,
+ .rsrv = 0,
+ .config_init = (config_init_t)bnx2x_8705_config_init,
+ .read_status = (read_status_t)bnx2x_8705_read_status,
+ .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
+ .config_loopback = (config_loopback_t)NULL,
+ .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver,
+ .hw_reset = (hw_reset_t)NULL,
+ .set_link_led = (set_link_led_t)NULL,
+ .phy_specific_func = (phy_specific_func_t)NULL
+};
+static struct bnx2x_phy phy_8706 = {
+ .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
+ .addr = 0xff,
+ .flags = FLAGS_INIT_XGXS_FIRST,
+ .def_md_devad = 0,
+ .reserved = 0,
+ .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .mdio_ctrl = 0,
+ .supported = (SUPPORTED_10000baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause),
+ .media_type = ETH_PHY_SFP_FIBER,
+ .ver_addr = 0,
+ .req_flow_ctrl = 0,
+ .req_line_speed = 0,
+ .speed_cap_mask = 0,
+ .req_duplex = 0,
+ .rsrv = 0,
+ .config_init = (config_init_t)bnx2x_8706_config_init,
+ .read_status = (read_status_t)bnx2x_8706_read_status,
+ .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
+ .config_loopback = (config_loopback_t)NULL,
+ .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
+ .hw_reset = (hw_reset_t)NULL,
+ .set_link_led = (set_link_led_t)NULL,
+ .phy_specific_func = (phy_specific_func_t)NULL
+};
+
+static struct bnx2x_phy phy_8726 = {
+ .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
+ .addr = 0xff,
+ .flags = (FLAGS_HW_LOCK_REQUIRED |
+ FLAGS_INIT_XGXS_FIRST),
+ .def_md_devad = 0,
+ .reserved = 0,
+ .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .mdio_ctrl = 0,
+ .supported = (SUPPORTED_10000baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause),
+ .media_type = ETH_PHY_SFP_FIBER,
+ .ver_addr = 0,
+ .req_flow_ctrl = 0,
+ .req_line_speed = 0,
+ .speed_cap_mask = 0,
+ .req_duplex = 0,
+ .rsrv = 0,
+ .config_init = (config_init_t)bnx2x_8726_config_init,
+ .read_status = (read_status_t)bnx2x_8726_read_status,
+ .link_reset = (link_reset_t)bnx2x_8726_link_reset,
+ .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
+ .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
+ .hw_reset = (hw_reset_t)NULL,
+ .set_link_led = (set_link_led_t)NULL,
+ .phy_specific_func = (phy_specific_func_t)NULL
+};
+
+static struct bnx2x_phy phy_8727 = {
+ .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ .addr = 0xff,
+ .flags = FLAGS_FAN_FAILURE_DET_REQ,
+ .def_md_devad = 0,
+ .reserved = 0,
+ .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .mdio_ctrl = 0,
+ .supported = (SUPPORTED_10000baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause),
+ .media_type = ETH_PHY_SFP_FIBER,
+ .ver_addr = 0,
+ .req_flow_ctrl = 0,
+ .req_line_speed = 0,
+ .speed_cap_mask = 0,
+ .req_duplex = 0,
+ .rsrv = 0,
+ .config_init = (config_init_t)bnx2x_8727_config_init,
+ .read_status = (read_status_t)bnx2x_8727_read_status,
+ .link_reset = (link_reset_t)bnx2x_8727_link_reset,
+ .config_loopback = (config_loopback_t)NULL,
+ .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
+ .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
+ .set_link_led = (set_link_led_t)bnx2x_8727_set_link_led,
+ .phy_specific_func = (phy_specific_func_t)bnx2x_8727_specific_func
+};
+static struct bnx2x_phy phy_8481 = {
+ .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
+ .addr = 0xff,
+ .flags = FLAGS_FAN_FAILURE_DET_REQ |
+ FLAGS_REARM_LATCH_SIGNAL,
+ .def_md_devad = 0,
+ .reserved = 0,
+ .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .mdio_ctrl = 0,
+ .supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_10000baseT_Full |
+ SUPPORTED_TP |
+ SUPPORTED_Autoneg |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause),
+ .media_type = ETH_PHY_BASE_T,
+ .ver_addr = 0,
+ .req_flow_ctrl = 0,
+ .req_line_speed = 0,
+ .speed_cap_mask = 0,
+ .req_duplex = 0,
+ .rsrv = 0,
+ .config_init = (config_init_t)bnx2x_8481_config_init,
+ .read_status = (read_status_t)bnx2x_848xx_read_status,
+ .link_reset = (link_reset_t)bnx2x_8481_link_reset,
+ .config_loopback = (config_loopback_t)NULL,
+ .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
+ .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
+ .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
+ .phy_specific_func = (phy_specific_func_t)NULL
+};
+
+static struct bnx2x_phy phy_84823 = {
+ .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
+ .addr = 0xff,
+ .flags = FLAGS_FAN_FAILURE_DET_REQ |
+ FLAGS_REARM_LATCH_SIGNAL,
+ .def_md_devad = 0,
+ .reserved = 0,
+ .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+ .mdio_ctrl = 0,
+ .supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_10000baseT_Full |
+ SUPPORTED_TP |
+ SUPPORTED_Autoneg |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause),
+ .media_type = ETH_PHY_BASE_T,
+ .ver_addr = 0,
+ .req_flow_ctrl = 0,
+ .req_line_speed = 0,
+ .speed_cap_mask = 0,
+ .req_duplex = 0,
+ .rsrv = 0,
+ .config_init = (config_init_t)bnx2x_848x3_config_init,
+ .read_status = (read_status_t)bnx2x_848xx_read_status,
+ .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
+ .config_loopback = (config_loopback_t)NULL,
+ .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
+ .hw_reset = (hw_reset_t)NULL,
+ .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
+ .phy_specific_func = (phy_specific_func_t)NULL
+};
+
+/*****************************************************************/
+/* */
+/* Populate the phy according. Main function: bnx2x_populate_phy */
+/* */
+/*****************************************************************/
+
+static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
+ struct bnx2x_phy *phy, u8 port,
+ u8 phy_index)
+{
+ /* Get the 4 lanes xgxs config rx and tx */
+ u32 rx = 0, tx = 0, i;
+ for (i = 0; i < 2; i++) {
+ /**
+ * INT_PHY and EXT_PHY1 share the same value location in the
+ * shmem. When num_phys is greater than 1, than this value
+ * applies only to EXT_PHY1
+ */
+ if (phy_index == INT_PHY || phy_index == EXT_PHY1) {
+ rx = REG_RD(bp, shmem_base +
+ offsetof(struct shmem_region,
+ dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
+
+ tx = REG_RD(bp, shmem_base +
+ offsetof(struct shmem_region,
+ dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
} else {
- REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
- hw_led_mode);
+ rx = REG_RD(bp, shmem_base +
+ offsetof(struct shmem_region,
+ dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
+
+ tx = REG_RD(bp, shmem_base +
+ offsetof(struct shmem_region,
+ dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
}
- REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
- port*4, 0);
- /* Set blinking rate to ~15.9Hz */
- REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
- LED_BLINK_RATE_VAL);
- REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
- port*4, 1);
- tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
- EMAC_WR(bp, EMAC_REG_EMAC_LED,
- (tmp & (~EMAC_LED_OVERRIDE)));
+ phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
+ phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
- if (CHIP_IS_E1(bp) &&
- ((speed == SPEED_2500) ||
- (speed == SPEED_1000) ||
- (speed == SPEED_100) ||
- (speed == SPEED_10))) {
- /* On Everest 1 Ax chip versions for speeds less than
- 10G LED scheme is different */
- REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
- + port*4, 1);
- REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
- port*4, 0);
- REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
- port*4, 1);
- }
- break;
+ phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
+ phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
+ }
+}
- default:
- rc = -EINVAL;
- DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
- mode);
+static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
+ u8 phy_index, u8 port)
+{
+ u32 ext_phy_config = 0;
+ switch (phy_index) {
+ case EXT_PHY1:
+ ext_phy_config = REG_RD(bp, shmem_base +
+ offsetof(struct shmem_region,
+ dev_info.port_hw_config[port].external_phy_config));
break;
+ case EXT_PHY2:
+ ext_phy_config = REG_RD(bp, shmem_base +
+ offsetof(struct shmem_region,
+ dev_info.port_hw_config[port].external_phy_config2));
+ break;
+ default:
+ DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
+ return -EINVAL;
}
- return rc;
+ return ext_phy_config;
}
-
-u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
+static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
+ struct bnx2x_phy *phy)
{
- struct bnx2x *bp = params->bp;
- u16 gp_status = 0;
+ u32 phy_addr;
+ u32 chip_id;
+ u32 switch_cfg = (REG_RD(bp, shmem_base +
+ offsetof(struct shmem_region,
+ dev_info.port_feature_config[port].link_config)) &
+ PORT_FEATURE_CONNECTED_SWITCH_MASK);
+ chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
+ switch (switch_cfg) {
+ case SWITCH_CFG_1G:
+ phy_addr = REG_RD(bp,
+ NIG_REG_SERDES0_CTRL_PHY_ADDR +
+ port * 0x10);
+ *phy = phy_serdes;
+ break;
+ case SWITCH_CFG_10G:
+ phy_addr = REG_RD(bp,
+ NIG_REG_XGXS0_CTRL_PHY_ADDR +
+ port * 0x18);
+ *phy = phy_xgxs;
+ break;
+ default:
+ DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
+ return -EINVAL;
+ }
+ phy->addr = (u8)phy_addr;
+ phy->mdio_ctrl = bnx2x_get_emac_base(bp,
+ SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH,
+ port);
+ if (CHIP_IS_E2(bp))
+ phy->def_md_devad = E2_DEFAULT_PHY_DEV_ADDR;
+ else
+ phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
- CL45_RD_OVER_CL22(bp, params->port,
- params->phy_addr,
- MDIO_REG_BANK_GP_STATUS,
- MDIO_GP_STATUS_TOP_AN_STATUS1,
- &gp_status);
- /* link is up only if both local phy and external phy are up */
- if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
- bnx2x_ext_phy_is_link_up(params, vars, 1))
- return 0;
+ DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
+ port, phy->addr, phy->mdio_ctrl);
- return -ESRCH;
+ bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
+ return 0;
}
-static u8 bnx2x_link_initialize(struct link_params *params,
- struct link_vars *vars)
+static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
+ u8 phy_index,
+ u32 shmem_base,
+ u32 shmem2_base,
+ u8 port,
+ struct bnx2x_phy *phy)
{
- struct bnx2x *bp = params->bp;
- u8 port = params->port;
- u8 rc = 0;
- u8 non_ext_phy;
- u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+ u32 ext_phy_config, phy_type, config2;
+ u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH;
+ ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
+ phy_index, port);
+ phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
+ /* Select the phy type */
+ switch (phy_type) {
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
+ mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED;
+ *phy = phy_8073;
+ break;
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
+ *phy = phy_8705;
+ break;
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
+ *phy = phy_8706;
+ break;
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+ mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
+ *phy = phy_8726;
+ break;
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
+ /* BCM8727_NOC => BCM8727 no over current */
+ mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
+ *phy = phy_8727;
+ phy->flags |= FLAGS_NOC;
+ break;
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
+ *phy = phy_8727;
+ break;
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
+ *phy = phy_8481;
+ break;
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
+ *phy = phy_84823;
+ break;
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+ *phy = phy_7101;
+ break;
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
+ *phy = phy_null;
+ return -EINVAL;
+ default:
+ *phy = phy_null;
+ return 0;
+ }
- /* Activate the external PHY */
- bnx2x_ext_phy_reset(params, vars);
+ phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
+ bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
- bnx2x_set_aer_mmd(params, vars);
+ /**
+ * The shmem address of the phy version is located on different
+ * structures. In case this structure is too old, do not set
+ * the address
+ */
+ config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region,
+ dev_info.shared_hw_config.config2));
+ if (phy_index == EXT_PHY1) {
+ phy->ver_addr = shmem_base + offsetof(struct shmem_region,
+ port_mb[port].ext_phy_fw_version);
+
+ /* Check specific mdc mdio settings */
+ if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK)
+ mdc_mdio_access = config2 &
+ SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK;
+ } else {
+ u32 size = REG_RD(bp, shmem2_base);
- if (vars->phy_flags & PHY_XGXS_FLAG)
- bnx2x_set_master_ln(params);
+ if (size >
+ offsetof(struct shmem2_region, ext_phy_fw_version2)) {
+ phy->ver_addr = shmem2_base +
+ offsetof(struct shmem2_region,
+ ext_phy_fw_version2[port]);
+ }
+ /* Check specific mdc mdio settings */
+ if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK)
+ mdc_mdio_access = (config2 &
+ SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) >>
+ (SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT -
+ SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT);
+ }
+ phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port);
- rc = bnx2x_reset_unicore(params);
- /* reset the SerDes and wait for reset bit return low */
- if (rc != 0)
- return rc;
+ /**
+ * In case mdc/mdio_access of the external phy is different than the
+ * mdc/mdio access of the XGXS, a HW lock must be taken in each access
+ * to prevent one port interfere with another port's CL45 operations.
+ */
+ if (mdc_mdio_access != SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH)
+ phy->flags |= FLAGS_HW_LOCK_REQUIRED;
+ DP(NETIF_MSG_LINK, "phy_type 0x%x port %d found in index %d\n",
+ phy_type, port, phy_index);
+ DP(NETIF_MSG_LINK, " addr=0x%x, mdio_ctl=0x%x\n",
+ phy->addr, phy->mdio_ctrl);
+ return 0;
+}
- bnx2x_set_aer_mmd(params, vars);
+static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
+ u32 shmem2_base, u8 port, struct bnx2x_phy *phy)
+{
+ u8 status = 0;
+ phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
+ if (phy_index == INT_PHY)
+ return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
+ status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, shmem2_base,
+ port, phy);
+ return status;
+}
- /* setting the masterLn_def again after the reset */
- if (vars->phy_flags & PHY_XGXS_FLAG) {
- bnx2x_set_master_ln(params);
- bnx2x_set_swap_lanes(params);
+static void bnx2x_phy_def_cfg(struct link_params *params,
+ struct bnx2x_phy *phy,
+ u8 phy_index)
+{
+ struct bnx2x *bp = params->bp;
+ u32 link_config;
+ /* Populate the default phy configuration for MF mode */
+ if (phy_index == EXT_PHY2) {
+ link_config = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].link_config2));
+ phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_hw_config[params->port].speed_capability_mask2));
+ } else {
+ link_config = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].link_config));
+ phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, 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);
+
+ phy->req_duplex = DUPLEX_FULL;
+ switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
+ case PORT_FEATURE_LINK_SPEED_10M_HALF:
+ phy->req_duplex = DUPLEX_HALF;
+ case PORT_FEATURE_LINK_SPEED_10M_FULL:
+ phy->req_line_speed = SPEED_10;
+ break;
+ case PORT_FEATURE_LINK_SPEED_100M_HALF:
+ phy->req_duplex = DUPLEX_HALF;
+ case PORT_FEATURE_LINK_SPEED_100M_FULL:
+ phy->req_line_speed = SPEED_100;
+ break;
+ case PORT_FEATURE_LINK_SPEED_1G:
+ phy->req_line_speed = SPEED_1000;
+ break;
+ case PORT_FEATURE_LINK_SPEED_2_5G:
+ phy->req_line_speed = SPEED_2500;
+ break;
+ case PORT_FEATURE_LINK_SPEED_10G_CX4:
+ phy->req_line_speed = SPEED_10000;
+ break;
+ default:
+ phy->req_line_speed = SPEED_AUTO_NEG;
+ break;
}
- if (vars->phy_flags & PHY_XGXS_FLAG) {
- if ((params->req_line_speed &&
- ((params->req_line_speed == SPEED_100) ||
- (params->req_line_speed == SPEED_10))) ||
- (!params->req_line_speed &&
- (params->speed_cap_mask >=
- PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
- (params->speed_cap_mask <
- PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
- )) {
- vars->phy_flags |= PHY_SGMII_FLAG;
- } else {
- vars->phy_flags &= ~PHY_SGMII_FLAG;
- }
+ switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
+ case PORT_FEATURE_FLOW_CONTROL_AUTO:
+ phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
+ break;
+ case PORT_FEATURE_FLOW_CONTROL_TX:
+ phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
+ break;
+ case PORT_FEATURE_FLOW_CONTROL_RX:
+ phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
+ break;
+ case PORT_FEATURE_FLOW_CONTROL_BOTH:
+ phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
+ break;
+ default:
+ phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+ break;
}
- /* In case of external phy existance, the line speed would be the
- line speed linked up by the external phy. In case it is direct only,
- then the line_speed during initialization will be equal to the
- req_line_speed*/
- vars->line_speed = params->req_line_speed;
+}
- bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
+u32 bnx2x_phy_selection(struct link_params *params)
+{
+ u32 phy_config_swapped, prio_cfg;
+ u32 return_cfg = PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT;
+
+ phy_config_swapped = params->multi_phy_config &
+ PORT_HW_CFG_PHY_SWAPPED_ENABLED;
+
+ prio_cfg = params->multi_phy_config &
+ PORT_HW_CFG_PHY_SELECTION_MASK;
+
+ if (phy_config_swapped) {
+ switch (prio_cfg) {
+ case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
+ return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY;
+ break;
+ case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
+ return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY;
+ break;
+ case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
+ return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
+ break;
+ case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
+ return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
+ break;
+ }
+ } else
+ return_cfg = prio_cfg;
- /* init ext phy and enable link state int */
- non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
- (params->loopback_mode == LOOPBACK_XGXS_10));
+ return return_cfg;
+}
- if (non_ext_phy ||
- (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
- (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) ||
- (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
- (params->loopback_mode == LOOPBACK_EXT_PHY)) {
- if (params->req_line_speed == SPEED_AUTO_NEG)
- bnx2x_set_parallel_detection(params, vars->phy_flags);
- bnx2x_init_internal_phy(params, vars, non_ext_phy);
+
+u8 bnx2x_phy_probe(struct link_params *params)
+{
+ u8 phy_index, actual_phy_idx, link_cfg_idx;
+ u32 phy_config_swapped;
+ struct bnx2x *bp = params->bp;
+ struct bnx2x_phy *phy;
+ params->num_phys = 0;
+ DP(NETIF_MSG_LINK, "Begin phy probe\n");
+ phy_config_swapped = params->multi_phy_config &
+ PORT_HW_CFG_PHY_SWAPPED_ENABLED;
+
+ for (phy_index = INT_PHY; phy_index < MAX_PHYS;
+ phy_index++) {
+ link_cfg_idx = LINK_CONFIG_IDX(phy_index);
+ actual_phy_idx = phy_index;
+ if (phy_config_swapped) {
+ if (phy_index == EXT_PHY1)
+ actual_phy_idx = EXT_PHY2;
+ else if (phy_index == EXT_PHY2)
+ actual_phy_idx = EXT_PHY1;
+ }
+ DP(NETIF_MSG_LINK, "phy_config_swapped %x, phy_index %x,"
+ " actual_phy_idx %x\n", phy_config_swapped,
+ phy_index, actual_phy_idx);
+ phy = &params->phy[actual_phy_idx];
+ if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
+ params->shmem2_base, params->port,
+ phy) != 0) {
+ params->num_phys = 0;
+ DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
+ phy_index);
+ for (phy_index = INT_PHY;
+ phy_index < MAX_PHYS;
+ phy_index++)
+ *phy = phy_null;
+ return -EINVAL;
+ }
+ if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
+ break;
+
+ bnx2x_phy_def_cfg(params, phy, phy_index);
+ params->num_phys++;
}
- if (!non_ext_phy)
- rc |= bnx2x_ext_phy_init(params, vars);
+ DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
+ return 0;
+}
- bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
- (NIG_STATUS_XGXS0_LINK10G |
- NIG_STATUS_XGXS0_LINK_STATUS |
- NIG_STATUS_SERDES0_LINK_STATUS));
+static void set_phy_vars(struct link_params *params)
+{
+ struct bnx2x *bp = params->bp;
+ u8 actual_phy_idx, phy_index, link_cfg_idx;
+ u8 phy_config_swapped = params->multi_phy_config &
+ PORT_HW_CFG_PHY_SWAPPED_ENABLED;
+ for (phy_index = INT_PHY; phy_index < params->num_phys;
+ phy_index++) {
+ link_cfg_idx = LINK_CONFIG_IDX(phy_index);
+ actual_phy_idx = phy_index;
+ if (phy_config_swapped) {
+ if (phy_index == EXT_PHY1)
+ actual_phy_idx = EXT_PHY2;
+ else if (phy_index == EXT_PHY2)
+ actual_phy_idx = EXT_PHY1;
+ }
+ params->phy[actual_phy_idx].req_flow_ctrl =
+ params->req_flow_ctrl[link_cfg_idx];
- return rc;
+ params->phy[actual_phy_idx].req_line_speed =
+ params->req_line_speed[link_cfg_idx];
-}
+ params->phy[actual_phy_idx].speed_cap_mask =
+ params->speed_cap_mask[link_cfg_idx];
+
+ params->phy[actual_phy_idx].req_duplex =
+ params->req_duplex[link_cfg_idx];
+ DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
+ " speed_cap_mask %x\n",
+ params->phy[actual_phy_idx].req_flow_ctrl,
+ params->phy[actual_phy_idx].req_line_speed,
+ params->phy[actual_phy_idx].speed_cap_mask);
+ }
+}
u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
- u32 val;
-
DP(NETIF_MSG_LINK, "Phy Initialization started\n");
- DP(NETIF_MSG_LINK, "req_speed %d, req_flowctrl %d\n",
- params->req_line_speed, params->req_flow_ctrl);
+ DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n",
+ params->req_line_speed[0], params->req_flow_ctrl[0]);
+ DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n",
+ params->req_line_speed[1], params->req_flow_ctrl[1]);
vars->link_status = 0;
vars->phy_link_up = 0;
vars->link_up = 0;
@@ -5966,11 +6760,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
vars->duplex = DUPLEX_FULL;
vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
vars->mac_type = MAC_TYPE_NONE;
-
- if (params->switch_cfg == SWITCH_CFG_1G)
- vars->phy_flags = PHY_SERDES_FLAG;
- else
- vars->phy_flags = PHY_XGXS_FLAG;
+ vars->phy_flags = 0;
/* disable attentions */
bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
@@ -5981,6 +6771,13 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
bnx2x_emac_init(params, vars);
+ if (params->num_phys == 0) {
+ DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
+ return -EINVAL;
+ }
+ set_phy_vars(params);
+
+ DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
if (CHIP_REV_IS_FPGA(bp)) {
vars->link_up = 1;
@@ -5999,7 +6796,9 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
}
bnx2x_emac_enable(params, vars, 0);
- bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
+ if (!(CHIP_IS_E2(bp)))
+ bnx2x_pbf_update(params, vars->flow_ctrl,
+ vars->line_speed);
/* disable drain */
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
@@ -6040,7 +6839,8 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
vars->phy_flags = PHY_XGXS_FLAG;
- bnx2x_phy_deassert(params, vars->phy_flags);
+ bnx2x_xgxs_deassert(params);
+
/* set bmac loopback */
bnx2x_bmac_enable(params, vars, 1);
@@ -6057,80 +6857,66 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
vars->phy_flags = PHY_XGXS_FLAG;
- bnx2x_phy_deassert(params, vars->phy_flags);
+ bnx2x_xgxs_deassert(params);
/* set bmac loopback */
bnx2x_emac_enable(params, vars, 1);
- bnx2x_emac_program(params, vars->line_speed,
- vars->duplex);
+ bnx2x_emac_program(params, vars);
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
params->port*4, 0);
- } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
+ } else if ((params->loopback_mode == LOOPBACK_XGXS) ||
(params->loopback_mode == LOOPBACK_EXT_PHY)) {
vars->link_up = 1;
- vars->line_speed = SPEED_10000;
- vars->duplex = DUPLEX_FULL;
vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+ vars->duplex = DUPLEX_FULL;
+ if (params->req_line_speed[0] == SPEED_1000) {
+ vars->line_speed = SPEED_1000;
+ vars->mac_type = MAC_TYPE_EMAC;
+ } else {
+ vars->line_speed = SPEED_10000;
+ vars->mac_type = MAC_TYPE_BMAC;
+ }
- vars->phy_flags = PHY_XGXS_FLAG;
-
- val = REG_RD(bp,
- NIG_REG_XGXS0_CTRL_PHY_ADDR+
- params->port*0x18);
- params->phy_addr = (u8)val;
-
- bnx2x_phy_deassert(params, vars->phy_flags);
+ bnx2x_xgxs_deassert(params);
bnx2x_link_initialize(params, vars);
- vars->mac_type = MAC_TYPE_BMAC;
-
+ if (params->req_line_speed[0] == SPEED_1000) {
+ bnx2x_emac_program(params, vars);
+ bnx2x_emac_enable(params, vars, 0);
+ } else
bnx2x_bmac_enable(params, vars, 0);
- if (params->loopback_mode == LOOPBACK_XGXS_10) {
+ if (params->loopback_mode == LOOPBACK_XGXS) {
/* set 10G XGXS loopback */
- bnx2x_set_xgxs_loopback(params, vars, 1);
+ params->phy[INT_PHY].config_loopback(
+ &params->phy[INT_PHY],
+ params);
+
} else {
/* set external phy loopback */
- bnx2x_ext_phy_loopback(params);
+ u8 phy_index;
+ for (phy_index = EXT_PHY1;
+ phy_index < params->num_phys; phy_index++) {
+ if (params->phy[phy_index].config_loopback)
+ params->phy[phy_index].config_loopback(
+ &params->phy[phy_index],
+ params);
+ }
}
+
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
params->port*4, 0);
- bnx2x_set_led(params, LED_MODE_OPER, vars->line_speed);
+ bnx2x_set_led(params, vars,
+ LED_MODE_OPER, vars->line_speed);
} else
/* No loopback */
{
- bnx2x_phy_deassert(params, vars->phy_flags);
- switch (params->switch_cfg) {
- case SWITCH_CFG_1G:
- vars->phy_flags |= PHY_SERDES_FLAG;
- if ((params->ext_phy_config &
- PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
- PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
- vars->phy_flags |= PHY_SGMII_FLAG;
- }
-
- val = REG_RD(bp,
- NIG_REG_SERDES0_CTRL_PHY_ADDR+
- params->port*0x10);
-
- params->phy_addr = (u8)val;
-
- break;
- case SWITCH_CFG_10G:
- vars->phy_flags |= PHY_XGXS_FLAG;
- val = REG_RD(bp,
- NIG_REG_XGXS0_CTRL_PHY_ADDR+
- params->port*0x18);
- params->phy_addr = (u8)val;
-
- break;
- default:
- DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
- return -EINVAL;
- }
- DP(NETIF_MSG_LINK, "Phy address = 0x%x\n", params->phy_addr);
+ if (params->switch_cfg == SWITCH_CFG_10G)
+ bnx2x_xgxs_deassert(params);
+ else
+ bnx2x_serdes_deassert(bp, params->port);
bnx2x_link_initialize(params, vars);
msleep(30);
@@ -6138,29 +6924,11 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
}
return 0;
}
-
-static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
-{
- DP(NETIF_MSG_LINK, "bnx2x_8726_reset_phy port %d\n", port);
-
- /* Set serial boot control for external load */
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_GEN_CTRL, 0x0001);
-}
-
u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
u8 reset_ext_phy)
{
struct bnx2x *bp = params->bp;
- u32 ext_phy_config = params->ext_phy_config;
- u8 port = params->port;
- u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
- u32 val = REG_RD(bp, params->shmem_base +
- offsetof(struct shmem_region, dev_info.
- port_feature_config[params->port].
- config));
+ u8 phy_index, port = params->port;
DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
/* disable attentions */
vars->link_status = 0;
@@ -6189,73 +6957,21 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
* Hold it as vars low
*/
/* clear link led */
- bnx2x_set_led(params, LED_MODE_OFF, 0);
- if (reset_ext_phy) {
- switch (ext_phy_type) {
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
- break;
+ bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
- {
-
- /* Disable Transmitter */
- u8 ext_phy_addr =
- XGXS_EXT_PHY_ADDR(params->ext_phy_config);
- if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
- PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
- bnx2x_sfp_set_transmitter(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr, 0);
- break;
- }
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
- DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
- "low power mode\n",
- port);
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
- MISC_REGISTERS_GPIO_OUTPUT_LOW,
- port);
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
- {
- u8 ext_phy_addr =
- XGXS_EXT_PHY_ADDR(params->ext_phy_config);
- /* Set soft reset */
- bnx2x_8726_reset_phy(bp, params->port, ext_phy_addr);
- break;
- }
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
- {
- u8 ext_phy_addr =
- XGXS_EXT_PHY_ADDR(params->ext_phy_config);
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
- ext_phy_addr,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_CTRL, 0x0000);
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
- ext_phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_CTRL, 1);
- break;
- }
- default:
- /* HW reset */
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
- MISC_REGISTERS_GPIO_OUTPUT_LOW,
- port);
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
- MISC_REGISTERS_GPIO_OUTPUT_LOW,
- port);
- DP(NETIF_MSG_LINK, "reset external PHY\n");
+ if (reset_ext_phy) {
+ for (phy_index = EXT_PHY1; phy_index < params->num_phys;
+ phy_index++) {
+ if (params->phy[phy_index].link_reset)
+ params->phy[phy_index].link_reset(
+ &params->phy[phy_index],
+ params);
}
}
- /* reset the SerDes/XGXS */
- REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
- (0x1ff << (port*16)));
+ if (params->phy[INT_PHY].link_reset)
+ params->phy[INT_PHY].link_reset(
+ &params->phy[INT_PHY], params);
/* reset BigMac */
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
(MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
@@ -6269,183 +6985,41 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
return 0;
}
-static u8 bnx2x_update_link_down(struct link_params *params,
- struct link_vars *vars)
-{
- struct bnx2x *bp = params->bp;
- u8 port = params->port;
-
- DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
- bnx2x_set_led(params, LED_MODE_OFF, 0);
-
- /* indicate no mac active */
- vars->mac_type = MAC_TYPE_NONE;
-
- /* update shared memory */
- vars->link_status = 0;
- vars->line_speed = 0;
- bnx2x_update_mng(params, vars->link_status);
-
- /* activate nig drain */
- REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
-
- /* disable emac */
- REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
-
- msleep(10);
-
- /* reset BigMac */
- bnx2x_bmac_rx_disable(bp, params->port);
- REG_WR(bp, GRCBASE_MISC +
- MISC_REGISTERS_RESET_REG_2_CLEAR,
- (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
- return 0;
-}
-
-static u8 bnx2x_update_link_up(struct link_params *params,
- struct link_vars *vars,
- u8 link_10g, u32 gp_status)
+/****************************************************************************/
+/* Common function */
+/****************************************************************************/
+static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
+ u32 shmem_base_path[],
+ u32 shmem2_base_path[], u8 phy_index,
+ u32 chip_id)
{
- struct bnx2x *bp = params->bp;
- u8 port = params->port;
- u8 rc = 0;
-
- vars->link_status |= LINK_STATUS_LINK_UP;
- if (link_10g) {
- bnx2x_bmac_enable(params, vars, 0);
- bnx2x_set_led(params, LED_MODE_OPER, SPEED_10000);
- } else {
- rc = bnx2x_emac_program(params, vars->line_speed,
- vars->duplex);
-
- bnx2x_emac_enable(params, vars, 0);
-
- /* AN complete? */
- if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
- if (!(vars->phy_flags &
- PHY_SGMII_FLAG))
- bnx2x_set_gmii_tx_driver(params);
- }
- }
-
- /* PBF - link up */
- rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
- vars->line_speed);
-
- /* disable drain */
- REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
-
- /* update shared memory */
- bnx2x_update_mng(params, vars->link_status);
- msleep(20);
- return rc;
-}
-/* This function should called upon link interrupt */
-/* In case vars->link_up, driver needs to
- 1. Update the pbf
- 2. Disable drain
- 3. Update the shared memory
- 4. Indicate link up
- 5. Set LEDs
- Otherwise,
- 1. Update shared memory
- 2. Reset BigMac
- 3. Report link down
- 4. Unset LEDs
-*/
-u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
-{
- struct bnx2x *bp = params->bp;
- u8 port = params->port;
- u16 gp_status;
- u8 link_10g;
- u8 ext_phy_link_up, rc = 0;
- u32 ext_phy_type;
- u8 is_mi_int = 0;
-
- DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
- port, (vars->phy_flags & PHY_XGXS_FLAG),
- REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
-
- is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
- port*0x18) > 0);
- DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
- REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
- is_mi_int,
- REG_RD(bp,
- NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
-
- DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
- REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
- REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
-
- /* disable emac */
- REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
-
- ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
- /* Check external link change only for non-direct */
- ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars, is_mi_int);
-
- /* Read gp_status */
- CL45_RD_OVER_CL22(bp, port, params->phy_addr,
- MDIO_REG_BANK_GP_STATUS,
- MDIO_GP_STATUS_TOP_AN_STATUS1,
- &gp_status);
-
- rc = bnx2x_link_settings_status(params, vars, gp_status,
- ext_phy_link_up);
- if (rc != 0)
- return rc;
-
- /* anything 10 and over uses the bmac */
- link_10g = ((vars->line_speed == SPEED_10000) ||
- (vars->line_speed == SPEED_12000) ||
- (vars->line_speed == SPEED_12500) ||
- (vars->line_speed == SPEED_13000) ||
- (vars->line_speed == SPEED_15000) ||
- (vars->line_speed == SPEED_16000));
-
- bnx2x_link_int_ack(params, vars, link_10g, is_mi_int);
-
- /* In case external phy link is up, and internal link is down
- ( not initialized yet probably after link initialization, it needs
- to be initialized.
- Note that after link down-up as result of cable plug,
- the xgxs link would probably become up again without the need to
- initialize it*/
-
- if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
- (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
- (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) &&
- (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) &&
- (ext_phy_link_up && !vars->phy_link_up))
- bnx2x_init_internal_phy(params, vars, 0);
-
- /* link is up only if both local phy and external phy are up */
- vars->link_up = (ext_phy_link_up && vars->phy_link_up);
-
- if (vars->link_up)
- rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
- else
- rc = bnx2x_update_link_down(params, vars);
-
- return rc;
-}
-
-static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
-{
- u8 ext_phy_addr[PORT_MAX];
+ struct bnx2x_phy phy[PORT_MAX];
+ struct bnx2x_phy *phy_blk[PORT_MAX];
u16 val;
s8 port;
+ s8 port_of_path = 0;
/* PART1 - Reset both phys */
for (port = PORT_MAX - 1; port >= PORT_0; port--) {
- /* Extract the ext phy address for the port */
- u32 ext_phy_config = REG_RD(bp, shmem_base +
- offsetof(struct shmem_region,
- dev_info.port_hw_config[port].external_phy_config));
+ u32 shmem_base, shmem2_base;
+ /* In E2, same phy is using for port0 of the two paths */
+ if (CHIP_IS_E2(bp)) {
+ shmem_base = shmem_base_path[port];
+ shmem2_base = shmem2_base_path[port];
+ port_of_path = 0;
+ } else {
+ shmem_base = shmem_base_path[0];
+ shmem2_base = shmem2_base_path[0];
+ port_of_path = port;
+ }
+ /* Extract the ext phy address for the port */
+ if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
+ port_of_path, &phy[port]) !=
+ 0) {
+ DP(NETIF_MSG_LINK, "populate_phy failed\n");
+ return -EINVAL;
+ }
/* disable attentions */
bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
(NIG_MASK_XGXS0_LINK_STATUS |
@@ -6453,17 +7027,13 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
NIG_MASK_SERDES0_LINK_STATUS |
NIG_MASK_MI_INT));
- ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config);
-
/* Need to take the phy out of low power mode in order
to write to access its registers */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
/* Reset the phy */
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- ext_phy_addr[port],
+ bnx2x_cl45_write(bp, &phy[port],
MDIO_PMA_DEVAD,
MDIO_PMA_REG_CTRL,
1<<15);
@@ -6472,15 +7042,28 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
/* Add delay of 150ms after reset */
msleep(150);
+ if (phy[PORT_0].addr & 0x1) {
+ phy_blk[PORT_0] = &(phy[PORT_1]);
+ phy_blk[PORT_1] = &(phy[PORT_0]);
+ } else {
+ phy_blk[PORT_0] = &(phy[PORT_0]);
+ phy_blk[PORT_1] = &(phy[PORT_1]);
+ }
+
/* PART2 - Download firmware to both phys */
for (port = PORT_MAX - 1; port >= PORT_0; port--) {
u16 fw_ver1;
+ if (CHIP_IS_E2(bp))
+ port_of_path = 0;
+ else
+ port_of_path = port;
- bnx2x_bcm8073_external_rom_boot(bp, port,
- ext_phy_addr[port], shmem_base);
+ DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
+ phy_blk[port]->addr);
+ bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
+ port_of_path);
- bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- ext_phy_addr[port],
+ bnx2x_cl45_read(bp, phy_blk[port],
MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER1, &fw_ver1);
if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
@@ -6492,16 +7075,12 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
}
/* Only set bit 10 = 1 (Tx power down) */
- bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- ext_phy_addr[port],
+ bnx2x_cl45_read(bp, phy_blk[port],
MDIO_PMA_DEVAD,
MDIO_PMA_REG_TX_POWER_DOWN, &val);
/* Phase1 of TX_POWER_DOWN reset */
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- ext_phy_addr[port],
+ bnx2x_cl45_write(bp, phy_blk[port],
MDIO_PMA_DEVAD,
MDIO_PMA_REG_TX_POWER_DOWN,
(val | 1<<10));
@@ -6515,28 +7094,20 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
for (port = PORT_MAX - 1; port >= PORT_0; port--) {
/* Phase2 of POWER_DOWN_RESET */
/* Release bit 10 (Release Tx power down) */
- bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- ext_phy_addr[port],
+ bnx2x_cl45_read(bp, phy_blk[port],
MDIO_PMA_DEVAD,
MDIO_PMA_REG_TX_POWER_DOWN, &val);
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- ext_phy_addr[port],
+ bnx2x_cl45_write(bp, phy_blk[port],
MDIO_PMA_DEVAD,
MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
msleep(15);
/* Read modify write the SPI-ROM version select register */
- bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- ext_phy_addr[port],
+ bnx2x_cl45_read(bp, phy_blk[port],
MDIO_PMA_DEVAD,
MDIO_PMA_REG_EDC_FFE_MAIN, &val);
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
- ext_phy_addr[port],
+ bnx2x_cl45_write(bp, phy_blk[port],
MDIO_PMA_DEVAD,
MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
@@ -6545,46 +7116,111 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
}
return 0;
-
}
+static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp,
+ u32 shmem_base_path[],
+ u32 shmem2_base_path[], u8 phy_index,
+ u32 chip_id)
+{
+ u32 val;
+ s8 port;
+ struct bnx2x_phy phy;
+ /* Use port1 because of the static port-swap */
+ /* Enable the module detection interrupt */
+ val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
+ val |= ((1<<MISC_REGISTERS_GPIO_3)|
+ (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
+ REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
-static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
+ bnx2x_ext_phy_hw_reset(bp, 1);
+ msleep(5);
+ for (port = 0; port < PORT_MAX; port++) {
+ u32 shmem_base, shmem2_base;
+
+ /* In E2, same phy is using for port0 of the two paths */
+ if (CHIP_IS_E2(bp)) {
+ shmem_base = shmem_base_path[port];
+ shmem2_base = shmem2_base_path[port];
+ } else {
+ shmem_base = shmem_base_path[0];
+ shmem2_base = shmem2_base_path[0];
+ }
+ /* Extract the ext phy address for the port */
+ if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
+ port, &phy) !=
+ 0) {
+ DP(NETIF_MSG_LINK, "populate phy failed\n");
+ return -EINVAL;
+ }
+
+ /* Reset phy*/
+ bnx2x_cl45_write(bp, &phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
+
+
+ /* Set fault module detected LED on */
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
+ MISC_REGISTERS_GPIO_HIGH,
+ port);
+ }
+
+ return 0;
+}
+static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp,
+ u32 shmem_base_path[],
+ u32 shmem2_base_path[], u8 phy_index,
+ u32 chip_id)
{
- u8 ext_phy_addr[PORT_MAX];
- s8 port, first_port, i;
+ s8 port;
u32 swap_val, swap_override;
- DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
+ struct bnx2x_phy phy[PORT_MAX];
+ struct bnx2x_phy *phy_blk[PORT_MAX];
+ s8 port_of_path;
swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
- bnx2x_ext_phy_hw_reset(bp, 1 ^ (swap_val && swap_override));
- msleep(5);
+ port = 1;
- if (swap_val && swap_override)
- first_port = PORT_0;
- else
- first_port = PORT_1;
+ bnx2x_ext_phy_hw_reset(bp, port ^ (swap_val && swap_override));
+
+ /* Calculate the port based on port swap */
+ port ^= (swap_val && swap_override);
+
+ msleep(5);
/* PART1 - Reset both phys */
- for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
- /* Extract the ext phy address for the port */
- u32 ext_phy_config = REG_RD(bp, shmem_base +
- offsetof(struct shmem_region,
- dev_info.port_hw_config[port].external_phy_config));
+ for (port = PORT_MAX - 1; port >= PORT_0; port--) {
+ u32 shmem_base, shmem2_base;
+
+ /* In E2, same phy is using for port0 of the two paths */
+ if (CHIP_IS_E2(bp)) {
+ shmem_base = shmem_base_path[port];
+ shmem2_base = shmem2_base_path[port];
+ port_of_path = 0;
+ } else {
+ shmem_base = shmem_base_path[0];
+ shmem2_base = shmem2_base_path[0];
+ port_of_path = port;
+ }
+ /* Extract the ext phy address for the port */
+ if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
+ port_of_path, &phy[port]) !=
+ 0) {
+ DP(NETIF_MSG_LINK, "populate phy failed\n");
+ return -EINVAL;
+ }
/* disable attentions */
- bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
- (NIG_MASK_XGXS0_LINK_STATUS |
- NIG_MASK_XGXS0_LINK10G |
- NIG_MASK_SERDES0_LINK_STATUS |
- NIG_MASK_MI_INT));
+ bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
+ port_of_path*4,
+ (NIG_MASK_XGXS0_LINK_STATUS |
+ NIG_MASK_XGXS0_LINK10G |
+ NIG_MASK_SERDES0_LINK_STATUS |
+ NIG_MASK_MI_INT));
- ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config);
/* Reset the phy */
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr[port],
+ bnx2x_cl45_write(bp, &phy[port],
MDIO_PMA_DEVAD,
MDIO_PMA_REG_CTRL,
1<<15);
@@ -6592,16 +7228,25 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
/* Add delay of 150ms after reset */
msleep(150);
-
+ if (phy[PORT_0].addr & 0x1) {
+ phy_blk[PORT_0] = &(phy[PORT_1]);
+ phy_blk[PORT_1] = &(phy[PORT_0]);
+ } else {
+ phy_blk[PORT_0] = &(phy[PORT_0]);
+ phy_blk[PORT_1] = &(phy[PORT_1]);
+ }
/* PART2 - Download firmware to both phys */
- for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
+ for (port = PORT_MAX - 1; port >= PORT_0; port--) {
u16 fw_ver1;
-
- bnx2x_bcm8727_external_rom_boot(bp, port,
- ext_phy_addr[port], shmem_base);
-
- bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
- ext_phy_addr[port],
+ if (CHIP_IS_E2(bp))
+ port_of_path = 0;
+ else
+ port_of_path = port;
+ DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
+ phy_blk[port]->addr);
+ bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
+ port_of_path);
+ bnx2x_cl45_read(bp, phy_blk[port],
MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER1, &fw_ver1);
if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
@@ -6616,82 +7261,35 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
return 0;
}
-
-static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
-{
- u8 ext_phy_addr;
- u32 val;
- s8 port;
-
- /* Use port1 because of the static port-swap */
- /* Enable the module detection interrupt */
- val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
- val |= ((1<<MISC_REGISTERS_GPIO_3)|
- (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
- REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
-
- bnx2x_ext_phy_hw_reset(bp, 1);
- msleep(5);
- for (port = 0; port < PORT_MAX; port++) {
- /* Extract the ext phy address for the port */
- u32 ext_phy_config = REG_RD(bp, shmem_base +
- offsetof(struct shmem_region,
- dev_info.port_hw_config[port].external_phy_config));
-
- ext_phy_addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
- DP(NETIF_MSG_LINK, "8726_common_init : ext_phy_addr = 0x%x\n",
- ext_phy_addr);
-
- bnx2x_8726_reset_phy(bp, port, ext_phy_addr);
-
- /* Set fault module detected LED on */
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
- MISC_REGISTERS_GPIO_HIGH,
- port);
- }
-
- return 0;
-}
-
-
-static u8 bnx2x_84823_common_init_phy(struct bnx2x *bp, u32 shmem_base)
-{
- /* HW reset */
- bnx2x_ext_phy_hw_reset(bp, 1);
- return 0;
-}
-u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
+static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
+ u32 shmem2_base_path[], u8 phy_index,
+ u32 ext_phy_type, u32 chip_id)
{
u8 rc = 0;
- u32 ext_phy_type;
-
- DP(NETIF_MSG_LINK, "Begin common phy init\n");
-
- /* Read the ext_phy_type for arbitrary port(0) */
- ext_phy_type = XGXS_EXT_PHY_TYPE(
- REG_RD(bp, shmem_base +
- offsetof(struct shmem_region,
- dev_info.port_hw_config[0].external_phy_config)));
switch (ext_phy_type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
- {
- rc = bnx2x_8073_common_init_phy(bp, shmem_base);
+ rc = bnx2x_8073_common_init_phy(bp, shmem_base_path,
+ shmem2_base_path,
+ phy_index, chip_id);
break;
- }
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
- rc = bnx2x_8727_common_init_phy(bp, shmem_base);
+ rc = bnx2x_8727_common_init_phy(bp, shmem_base_path,
+ shmem2_base_path,
+ phy_index, chip_id);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
/* GPIO1 affects both ports, so there's need to pull
it for single port alone */
- rc = bnx2x_8726_common_init_phy(bp, shmem_base);
+ rc = bnx2x_8726_common_init_phy(bp, shmem_base_path,
+ shmem2_base_path,
+ phy_index, chip_id);
break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
- rc = bnx2x_84823_common_init_phy(bp, shmem_base);
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
+ rc = -EINVAL;
break;
default:
DP(NETIF_MSG_LINK,
@@ -6703,33 +7301,81 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
return rc;
}
-void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
+u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
+ u32 shmem2_base_path[], u32 chip_id)
{
- u16 val, cnt;
+ u8 rc = 0;
+ u8 phy_index;
+ u32 ext_phy_type, ext_phy_config;
+ DP(NETIF_MSG_LINK, "Begin common phy init\n");
- bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
- phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_7101_RESET, &val);
+ if (CHIP_REV_IS_EMUL(bp))
+ return 0;
- for (cnt = 0; cnt < 10; cnt++) {
- msleep(50);
- /* Writes a self-clearing reset */
- bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
- phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_7101_RESET,
- (val | (1<<15)));
- /* Wait for clear */
- bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
- phy_addr,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_7101_RESET, &val);
+ /* Read the ext_phy_type for arbitrary port(0) */
+ for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
+ phy_index++) {
+ ext_phy_config = bnx2x_get_ext_phy_config(bp,
+ shmem_base_path[0],
+ phy_index, 0);
+ ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
+ rc |= bnx2x_ext_phy_common_init(bp, shmem_base_path,
+ shmem2_base_path,
+ phy_index, ext_phy_type,
+ chip_id);
+ }
+ return rc;
+}
- if ((val & (1<<15)) == 0)
- break;
+u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base)
+{
+ u8 phy_index;
+ struct bnx2x_phy phy;
+ for (phy_index = INT_PHY; phy_index < MAX_PHYS;
+ phy_index++) {
+ if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
+ 0, &phy) != 0) {
+ DP(NETIF_MSG_LINK, "populate phy failed\n");
+ return 0;
+ }
+
+ if (phy.flags & FLAGS_HW_LOCK_REQUIRED)
+ return 1;
+ }
+ return 0;
+}
+
+u8 bnx2x_fan_failure_det_req(struct bnx2x *bp,
+ u32 shmem_base,
+ u32 shmem2_base,
+ u8 port)
+{
+ u8 phy_index, fan_failure_det_req = 0;
+ struct bnx2x_phy phy;
+ for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
+ phy_index++) {
+ if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
+ port, &phy)
+ != 0) {
+ DP(NETIF_MSG_LINK, "populate phy failed\n");
+ return 0;
+ }
+ fan_failure_det_req |= (phy.flags &
+ FLAGS_FAN_FAILURE_DET_REQ);
+ }
+ return fan_failure_det_req;
+}
+
+void bnx2x_hw_reset_phy(struct link_params *params)
+{
+ u8 phy_index;
+ for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
+ phy_index++) {
+ if (params->phy[phy_index].hw_reset) {
+ params->phy[phy_index].hw_reset(
+ &params->phy[phy_index],
+ params);
+ params->phy[phy_index] = phy_null;
+ }
}
}
diff --git a/drivers/net/bnx2x/bnx2x_link.h b/drivers/net/bnx2x/bnx2x_link.h
index 40c2981de8ed..171abf8097ee 100644
--- a/drivers/net/bnx2x/bnx2x_link.h
+++ b/drivers/net/bnx2x/bnx2x_link.h
@@ -1,4 +1,4 @@
-/* Copyright 2008-2009 Broadcom Corporation
+/* Copyright 2008-2010 Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -22,7 +22,8 @@
/***********************************************************/
/* Defines */
/***********************************************************/
-#define DEFAULT_PHY_DEV_ADDR 3
+#define DEFAULT_PHY_DEV_ADDR 3
+#define E2_DEFAULT_PHY_DEV_ADDR 5
@@ -46,9 +47,137 @@
#define SFP_EEPROM_PART_NO_ADDR 0x28
#define SFP_EEPROM_PART_NO_SIZE 16
#define PWR_FLT_ERR_MSG_LEN 250
+
+#define XGXS_EXT_PHY_TYPE(ext_phy_config) \
+ ((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK)
+#define XGXS_EXT_PHY_ADDR(ext_phy_config) \
+ (((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> \
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT)
+#define SERDES_EXT_PHY_TYPE(ext_phy_config) \
+ ((ext_phy_config) & PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK)
+
+/* Single Media Direct board is the plain 577xx board with CX4/RJ45 jacks */
+#define SINGLE_MEDIA_DIRECT(params) (params->num_phys == 1)
+/* Single Media board contains single external phy */
+#define SINGLE_MEDIA(params) (params->num_phys == 2)
+/* Dual Media board contains two external phy with different media */
+#define DUAL_MEDIA(params) (params->num_phys == 3)
+#define FW_PARAM_MDIO_CTRL_OFFSET 16
+#define FW_PARAM_SET(phy_addr, phy_type, mdio_access) \
+ (phy_addr | phy_type | mdio_access << FW_PARAM_MDIO_CTRL_OFFSET)
/***********************************************************/
/* Structs */
/***********************************************************/
+#define INT_PHY 0
+#define EXT_PHY1 1
+#define EXT_PHY2 2
+#define MAX_PHYS 3
+
+/* Same configuration is shared between the XGXS and the first external phy */
+#define LINK_CONFIG_SIZE (MAX_PHYS - 1)
+#define LINK_CONFIG_IDX(_phy_idx) ((_phy_idx == INT_PHY) ? \
+ 0 : (_phy_idx - 1))
+/***********************************************************/
+/* bnx2x_phy struct */
+/* Defines the required arguments and function per phy */
+/***********************************************************/
+struct link_vars;
+struct link_params;
+struct bnx2x_phy;
+
+typedef u8 (*config_init_t)(struct bnx2x_phy *phy, struct link_params *params,
+ struct link_vars *vars);
+typedef u8 (*read_status_t)(struct bnx2x_phy *phy, struct link_params *params,
+ struct link_vars *vars);
+typedef void (*link_reset_t)(struct bnx2x_phy *phy,
+ struct link_params *params);
+typedef void (*config_loopback_t)(struct bnx2x_phy *phy,
+ struct link_params *params);
+typedef u8 (*format_fw_ver_t)(u32 raw, u8 *str, u16 *len);
+typedef void (*hw_reset_t)(struct bnx2x_phy *phy, struct link_params *params);
+typedef void (*set_link_led_t)(struct bnx2x_phy *phy,
+ struct link_params *params, u8 mode);
+typedef void (*phy_specific_func_t)(struct bnx2x_phy *phy,
+ struct link_params *params, u32 action);
+
+struct bnx2x_phy {
+ u32 type;
+
+ /* Loaded during init */
+ u8 addr;
+
+ u8 flags;
+ /* Require HW lock */
+#define FLAGS_HW_LOCK_REQUIRED (1<<0)
+ /* No Over-Current detection */
+#define FLAGS_NOC (1<<1)
+ /* Fan failure detection required */
+#define FLAGS_FAN_FAILURE_DET_REQ (1<<2)
+ /* Initialize first the XGXS and only then the phy itself */
+#define FLAGS_INIT_XGXS_FIRST (1<<3)
+#define FLAGS_REARM_LATCH_SIGNAL (1<<6)
+#define FLAGS_SFP_NOT_APPROVED (1<<7)
+
+ u8 def_md_devad;
+ u8 reserved;
+ /* preemphasis values for the rx side */
+ u16 rx_preemphasis[4];
+
+ /* preemphasis values for the tx side */
+ u16 tx_preemphasis[4];
+
+ /* EMAC address for access MDIO */
+ u32 mdio_ctrl;
+
+ u32 supported;
+
+ u32 media_type;
+#define ETH_PHY_UNSPECIFIED 0x0
+#define ETH_PHY_SFP_FIBER 0x1
+#define ETH_PHY_XFP_FIBER 0x2
+#define ETH_PHY_DA_TWINAX 0x3
+#define ETH_PHY_BASE_T 0x4
+#define ETH_PHY_NOT_PRESENT 0xff
+
+ /* The address in which version is located*/
+ u32 ver_addr;
+
+ u16 req_flow_ctrl;
+
+ u16 req_line_speed;
+
+ u32 speed_cap_mask;
+
+ u16 req_duplex;
+ u16 rsrv;
+ /* Called per phy/port init, and it configures LASI, speed, autoneg,
+ duplex, flow control negotiation, etc. */
+ config_init_t config_init;
+
+ /* Called due to interrupt. It determines the link, speed */
+ read_status_t read_status;
+
+ /* Called when driver is unloading. Should reset the phy */
+ link_reset_t link_reset;
+
+ /* Set the loopback configuration for the phy */
+ config_loopback_t config_loopback;
+
+ /* Format the given raw number into str up to len */
+ format_fw_ver_t format_fw_ver;
+
+ /* Reset the phy (both ports) */
+ hw_reset_t hw_reset;
+
+ /* Set link led mode (on/off/oper)*/
+ set_link_led_t set_link_led;
+
+ /* PHY Specific tasks */
+ phy_specific_func_t phy_specific_func;
+#define DISABLE_TX 1
+#define ENABLE_TX 2
+};
+
/* Inputs parameters to the CLC */
struct link_params {
@@ -59,56 +188,50 @@ struct link_params {
#define LOOPBACK_NONE 0
#define LOOPBACK_EMAC 1
#define LOOPBACK_BMAC 2
-#define LOOPBACK_XGXS_10 3
+#define LOOPBACK_XGXS 3
#define LOOPBACK_EXT_PHY 4
#define LOOPBACK_EXT 5
- u16 req_duplex;
- u16 req_flow_ctrl;
- u16 req_fc_auto_adv; /* Should be set to TX / BOTH when
- req_flow_ctrl is set to AUTO */
- u16 req_line_speed; /* Also determine AutoNeg */
-
/* Device parameters */
u8 mac_addr[6];
+ u16 req_duplex[LINK_CONFIG_SIZE];
+ u16 req_flow_ctrl[LINK_CONFIG_SIZE];
+
+ u16 req_line_speed[LINK_CONFIG_SIZE]; /* Also determine AutoNeg */
+
/* shmem parameters */
u32 shmem_base;
- u32 speed_cap_mask;
+ u32 shmem2_base;
+ u32 speed_cap_mask[LINK_CONFIG_SIZE];
u32 switch_cfg;
#define SWITCH_CFG_1G PORT_FEATURE_CON_SWITCH_1G_SWITCH
#define SWITCH_CFG_10G PORT_FEATURE_CON_SWITCH_10G_SWITCH
#define SWITCH_CFG_AUTO_DETECT PORT_FEATURE_CON_SWITCH_AUTO_DETECT
- u16 hw_led_mode; /* part of the hw_config read from the shmem */
-
- /* phy_addr populated by the phy_init function */
- u8 phy_addr;
- /*u8 reserved1;*/
-
u32 lane_config;
- u32 ext_phy_config;
-#define XGXS_EXT_PHY_TYPE(ext_phy_config) \
- ((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK)
-#define XGXS_EXT_PHY_ADDR(ext_phy_config) \
- (((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> \
- PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT)
-#define SERDES_EXT_PHY_TYPE(ext_phy_config) \
- ((ext_phy_config) & PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK)
/* Phy register parameter */
u32 chip_id;
- u16 xgxs_config_rx[4]; /* preemphasis values for the rx side */
- u16 xgxs_config_tx[4]; /* preemphasis values for the tx side */
-
u32 feature_config_flags;
#define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0)
#define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY (1<<2)
-#define FEATURE_CONFIG_BCM8727_NOC (1<<3)
+#define FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY (1<<3)
+ /* Will be populated during common init */
+ struct bnx2x_phy phy[MAX_PHYS];
+
+ /* Will be populated during common init */
+ u8 num_phys;
+
+ u8 rsrv;
+ u16 hw_led_mode; /* part of the hw_config read from the shmem */
+ u32 multi_phy_config;
/* Device pointer passed to all callback functions */
struct bnx2x *bp;
+ u16 req_fc_auto_adv; /* Should be set to TX / BOTH when
+ req_flow_ctrl is set to AUTO */
};
/* Output parameters */
@@ -129,12 +252,6 @@ struct link_vars {
u16 flow_ctrl;
u16 ieee_fc;
- u32 autoneg;
-#define AUTO_NEG_DISABLED 0x0
-#define AUTO_NEG_ENABLED 0x1
-#define AUTO_NEG_COMPLETE 0x2
-#define AUTO_NEG_PARALLEL_DETECTION_USED 0x3
-
/* The same definitions as the shmem parameter */
u32 link_status;
};
@@ -142,8 +259,6 @@ struct link_vars {
/***********************************************************/
/* Functions */
/***********************************************************/
-
-/* Initialize the phy */
u8 bnx2x_phy_init(struct link_params *input, struct link_vars *output);
/* Reset the link. Should be called when driver or interface goes down
@@ -155,17 +270,15 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
/* bnx2x_link_update should be called upon link interrupt */
u8 bnx2x_link_update(struct link_params *input, struct link_vars *output);
-/* use the following cl45 functions to read/write from external_phy
+/* use the following phy functions to read/write from external_phy
In order to use it to read/write internal phy registers, use
DEFAULT_PHY_DEV_ADDR as devad, and (_bank + (_addr & 0xf)) as
- Use ext_phy_type of 0 in case of cl22 over cl45
the register */
-u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
- u8 phy_addr, u8 devad, u16 reg, u16 *ret_val);
-
-u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
- u8 phy_addr, u8 devad, u16 reg, u16 val);
+u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr,
+ u8 devad, u16 reg, u16 *ret_val);
+u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr,
+ u8 devad, u16 reg, u16 val);
/* Reads the link_status from the shmem,
and update the link vars accordingly */
void bnx2x_link_status_update(struct link_params *input,
@@ -178,11 +291,12 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
Basically, the CLC takes care of the led for the link, but in case one needs
to set/unset the led unnaturally, set the "mode" to LED_MODE_OPER to
blink the led, and LED_MODE_OFF to set the led off.*/
-u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed);
-#define LED_MODE_OFF 0
-#define LED_MODE_OPER 2
-
-u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port, u32 led_idx, u32 value);
+u8 bnx2x_set_led(struct link_params *params, struct link_vars *vars,
+ u8 mode, u32 speed);
+#define LED_MODE_OFF 0
+#define LED_MODE_ON 1
+#define LED_MODE_OPER 2
+#define LED_MODE_FRONT_PANEL_OFF 3
/* bnx2x_handle_module_detect_int should be called upon module detection
interrupt */
@@ -190,17 +304,32 @@ void bnx2x_handle_module_detect_int(struct link_params *params);
/* Get the actual link status. In case it returns 0, link is up,
otherwise link is down*/
-u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars);
+u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars,
+ u8 is_serdes);
/* One-time initialization for external phy after power up */
-u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base);
+u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
+ u32 shmem2_base_path[], u32 chip_id);
/* Reset the external PHY using GPIO */
void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port);
-void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr);
+/* Reset the external of SFX7101 */
+void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy);
+
+void bnx2x_hw_reset_phy(struct link_params *params);
+
+/* Checks if HW lock is required for this phy/board type */
+u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base,
+ u32 shmem2_base);
+
+/* Check swap bit and adjust PHY order */
+u32 bnx2x_phy_selection(struct link_params *params);
-u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
- u8 byte_cnt, u8 *o_buf);
+/* Probe the phys on board, and populate them in "params" */
+u8 bnx2x_phy_probe(struct link_params *params);
+/* Checks if fan failure detection is required on one of the phys on board */
+u8 bnx2x_fan_failure_det_req(struct bnx2x *bp, u32 shmem_base,
+ u32 shmem2_base, u8 port);
#endif /* BNX2X_LINK_H */
diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c
index f8c3f08e4ce7..e9ad16f00b56 100644
--- a/drivers/net/bnx2x/bnx2x_main.c
+++ b/drivers/net/bnx2x/bnx2x_main.c
@@ -23,7 +23,6 @@
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
-#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
@@ -57,7 +56,6 @@
#include "bnx2x_init_ops.h"
#include "bnx2x_cmn.h"
-
#include <linux/firmware.h>
#include "bnx2x_fw_file_hdr.h"
/* FW files */
@@ -66,8 +64,9 @@
__stringify(BCM_5710_FW_MINOR_VERSION) "." \
__stringify(BCM_5710_FW_REVISION_VERSION) "." \
__stringify(BCM_5710_FW_ENGINEERING_VERSION)
-#define FW_FILE_NAME_E1 "bnx2x-e1-" FW_FILE_VERSION ".fw"
-#define FW_FILE_NAME_E1H "bnx2x-e1h-" FW_FILE_VERSION ".fw"
+#define FW_FILE_NAME_E1 "bnx2x/bnx2x-e1-" FW_FILE_VERSION ".fw"
+#define FW_FILE_NAME_E1H "bnx2x/bnx2x-e1h-" FW_FILE_VERSION ".fw"
+#define FW_FILE_NAME_E2 "bnx2x/bnx2x-e2-" FW_FILE_VERSION ".fw"
/* Time in jiffies before concluding the transmitter is hung */
#define TX_TIMEOUT (5*HZ)
@@ -77,18 +76,20 @@ static char version[] __devinitdata =
DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
MODULE_AUTHOR("Eliezer Tamir");
-MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710/57711/57711E Driver");
+MODULE_DESCRIPTION("Broadcom NetXtreme II "
+ "BCM57710/57711/57711E/57712/57712E Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
MODULE_FIRMWARE(FW_FILE_NAME_E1);
MODULE_FIRMWARE(FW_FILE_NAME_E1H);
+MODULE_FIRMWARE(FW_FILE_NAME_E2);
static int multi_mode = 1;
module_param(multi_mode, int, 0);
MODULE_PARM_DESC(multi_mode, " Multi queue mode "
"(0 Disable; 1 Enable (default))");
-static int num_queues;
+int num_queues;
module_param(num_queues, int, 0);
MODULE_PARM_DESC(num_queues, " Number of queues for multi_mode=1"
" (default is as a number of CPUs)");
@@ -124,6 +125,8 @@ enum bnx2x_board_type {
BCM57710 = 0,
BCM57711 = 1,
BCM57711E = 2,
+ BCM57712 = 3,
+ BCM57712E = 4
};
/* indexed by board_type, above */
@@ -132,14 +135,24 @@ static struct {
} board_info[] __devinitdata = {
{ "Broadcom NetXtreme II BCM57710 XGb" },
{ "Broadcom NetXtreme II BCM57711 XGb" },
- { "Broadcom NetXtreme II BCM57711E XGb" }
+ { "Broadcom NetXtreme II BCM57711E XGb" },
+ { "Broadcom NetXtreme II BCM57712 XGb" },
+ { "Broadcom NetXtreme II BCM57712E XGb" }
};
+#ifndef PCI_DEVICE_ID_NX2_57712
+#define PCI_DEVICE_ID_NX2_57712 0x1662
+#endif
+#ifndef PCI_DEVICE_ID_NX2_57712E
+#define PCI_DEVICE_ID_NX2_57712E 0x1663
+#endif
static DEFINE_PCI_DEVICE_TABLE(bnx2x_pci_tbl) = {
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711E), BCM57711E },
+ { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712), BCM57712 },
+ { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712E), BCM57712E },
{ 0 }
};
@@ -149,10 +162,248 @@ MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl);
* General service functions
****************************************************************************/
+static inline void __storm_memset_dma_mapping(struct bnx2x *bp,
+ u32 addr, dma_addr_t mapping)
+{
+ REG_WR(bp, addr, U64_LO(mapping));
+ REG_WR(bp, addr + 4, U64_HI(mapping));
+}
+
+static inline void __storm_memset_fill(struct bnx2x *bp,
+ u32 addr, size_t size, u32 val)
+{
+ int i;
+ for (i = 0; i < size/4; i++)
+ REG_WR(bp, addr + (i * 4), val);
+}
+
+static inline void storm_memset_ustats_zero(struct bnx2x *bp,
+ u8 port, u16 stat_id)
+{
+ size_t size = sizeof(struct ustorm_per_client_stats);
+
+ u32 addr = BAR_USTRORM_INTMEM +
+ USTORM_PER_COUNTER_ID_STATS_OFFSET(port, stat_id);
+
+ __storm_memset_fill(bp, addr, size, 0);
+}
+
+static inline void storm_memset_tstats_zero(struct bnx2x *bp,
+ u8 port, u16 stat_id)
+{
+ size_t size = sizeof(struct tstorm_per_client_stats);
+
+ u32 addr = BAR_TSTRORM_INTMEM +
+ TSTORM_PER_COUNTER_ID_STATS_OFFSET(port, stat_id);
+
+ __storm_memset_fill(bp, addr, size, 0);
+}
+
+static inline void storm_memset_xstats_zero(struct bnx2x *bp,
+ u8 port, u16 stat_id)
+{
+ size_t size = sizeof(struct xstorm_per_client_stats);
+
+ u32 addr = BAR_XSTRORM_INTMEM +
+ XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, stat_id);
+
+ __storm_memset_fill(bp, addr, size, 0);
+}
+
+
+static inline void storm_memset_spq_addr(struct bnx2x *bp,
+ dma_addr_t mapping, u16 abs_fid)
+{
+ u32 addr = XSEM_REG_FAST_MEMORY +
+ XSTORM_SPQ_PAGE_BASE_OFFSET(abs_fid);
+
+ __storm_memset_dma_mapping(bp, addr, mapping);
+}
+
+static inline void storm_memset_ov(struct bnx2x *bp, u16 ov, u16 abs_fid)
+{
+ REG_WR16(bp, BAR_XSTRORM_INTMEM + XSTORM_E1HOV_OFFSET(abs_fid), ov);
+}
+
+static inline void storm_memset_func_cfg(struct bnx2x *bp,
+ struct tstorm_eth_function_common_config *tcfg,
+ u16 abs_fid)
+{
+ size_t size = sizeof(struct tstorm_eth_function_common_config);
+
+ u32 addr = BAR_TSTRORM_INTMEM +
+ TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(abs_fid);
+
+ __storm_memset_struct(bp, addr, size, (u32 *)tcfg);
+}
+
+static inline void storm_memset_xstats_flags(struct bnx2x *bp,
+ struct stats_indication_flags *flags,
+ u16 abs_fid)
+{
+ size_t size = sizeof(struct stats_indication_flags);
+
+ u32 addr = BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(abs_fid);
+
+ __storm_memset_struct(bp, addr, size, (u32 *)flags);
+}
+
+static inline void storm_memset_tstats_flags(struct bnx2x *bp,
+ struct stats_indication_flags *flags,
+ u16 abs_fid)
+{
+ size_t size = sizeof(struct stats_indication_flags);
+
+ u32 addr = BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(abs_fid);
+
+ __storm_memset_struct(bp, addr, size, (u32 *)flags);
+}
+
+static inline void storm_memset_ustats_flags(struct bnx2x *bp,
+ struct stats_indication_flags *flags,
+ u16 abs_fid)
+{
+ size_t size = sizeof(struct stats_indication_flags);
+
+ u32 addr = BAR_USTRORM_INTMEM + USTORM_STATS_FLAGS_OFFSET(abs_fid);
+
+ __storm_memset_struct(bp, addr, size, (u32 *)flags);
+}
+
+static inline void storm_memset_cstats_flags(struct bnx2x *bp,
+ struct stats_indication_flags *flags,
+ u16 abs_fid)
+{
+ size_t size = sizeof(struct stats_indication_flags);
+
+ u32 addr = BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(abs_fid);
+
+ __storm_memset_struct(bp, addr, size, (u32 *)flags);
+}
+
+static inline void storm_memset_xstats_addr(struct bnx2x *bp,
+ dma_addr_t mapping, u16 abs_fid)
+{
+ u32 addr = BAR_XSTRORM_INTMEM +
+ XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(abs_fid);
+
+ __storm_memset_dma_mapping(bp, addr, mapping);
+}
+
+static inline void storm_memset_tstats_addr(struct bnx2x *bp,
+ dma_addr_t mapping, u16 abs_fid)
+{
+ u32 addr = BAR_TSTRORM_INTMEM +
+ TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(abs_fid);
+
+ __storm_memset_dma_mapping(bp, addr, mapping);
+}
+
+static inline void storm_memset_ustats_addr(struct bnx2x *bp,
+ dma_addr_t mapping, u16 abs_fid)
+{
+ u32 addr = BAR_USTRORM_INTMEM +
+ USTORM_ETH_STATS_QUERY_ADDR_OFFSET(abs_fid);
+
+ __storm_memset_dma_mapping(bp, addr, mapping);
+}
+
+static inline void storm_memset_cstats_addr(struct bnx2x *bp,
+ dma_addr_t mapping, u16 abs_fid)
+{
+ u32 addr = BAR_CSTRORM_INTMEM +
+ CSTORM_ETH_STATS_QUERY_ADDR_OFFSET(abs_fid);
+
+ __storm_memset_dma_mapping(bp, addr, mapping);
+}
+
+static inline void storm_memset_vf_to_pf(struct bnx2x *bp, u16 abs_fid,
+ u16 pf_id)
+{
+ REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_VF_TO_PF_OFFSET(abs_fid),
+ pf_id);
+ REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_VF_TO_PF_OFFSET(abs_fid),
+ pf_id);
+ REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_VF_TO_PF_OFFSET(abs_fid),
+ pf_id);
+ REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_VF_TO_PF_OFFSET(abs_fid),
+ pf_id);
+}
+
+static inline void storm_memset_func_en(struct bnx2x *bp, u16 abs_fid,
+ u8 enable)
+{
+ REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_FUNC_EN_OFFSET(abs_fid),
+ enable);
+ REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_FUNC_EN_OFFSET(abs_fid),
+ enable);
+ REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_FUNC_EN_OFFSET(abs_fid),
+ enable);
+ REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNC_EN_OFFSET(abs_fid),
+ enable);
+}
+
+static inline void storm_memset_eq_data(struct bnx2x *bp,
+ struct event_ring_data *eq_data,
+ u16 pfid)
+{
+ size_t size = sizeof(struct event_ring_data);
+
+ u32 addr = BAR_CSTRORM_INTMEM + CSTORM_EVENT_RING_DATA_OFFSET(pfid);
+
+ __storm_memset_struct(bp, addr, size, (u32 *)eq_data);
+}
+
+static inline void storm_memset_eq_prod(struct bnx2x *bp, u16 eq_prod,
+ u16 pfid)
+{
+ u32 addr = BAR_CSTRORM_INTMEM + CSTORM_EVENT_RING_PROD_OFFSET(pfid);
+ REG_WR16(bp, addr, eq_prod);
+}
+
+static inline void storm_memset_hc_timeout(struct bnx2x *bp, u8 port,
+ u16 fw_sb_id, u8 sb_index,
+ u8 ticks)
+{
+
+ int index_offset = CHIP_IS_E2(bp) ?
+ offsetof(struct hc_status_block_data_e2, index_data) :
+ offsetof(struct hc_status_block_data_e1x, index_data);
+ u32 addr = BAR_CSTRORM_INTMEM +
+ CSTORM_STATUS_BLOCK_DATA_OFFSET(fw_sb_id) +
+ index_offset +
+ sizeof(struct hc_index_data)*sb_index +
+ offsetof(struct hc_index_data, timeout);
+ REG_WR8(bp, addr, ticks);
+ DP(NETIF_MSG_HW, "port %x fw_sb_id %d sb_index %d ticks %d\n",
+ port, fw_sb_id, sb_index, ticks);
+}
+static inline void storm_memset_hc_disable(struct bnx2x *bp, u8 port,
+ u16 fw_sb_id, u8 sb_index,
+ u8 disable)
+{
+ u32 enable_flag = disable ? 0 : (1 << HC_INDEX_DATA_HC_ENABLED_SHIFT);
+ int index_offset = CHIP_IS_E2(bp) ?
+ offsetof(struct hc_status_block_data_e2, index_data) :
+ offsetof(struct hc_status_block_data_e1x, index_data);
+ u32 addr = BAR_CSTRORM_INTMEM +
+ CSTORM_STATUS_BLOCK_DATA_OFFSET(fw_sb_id) +
+ index_offset +
+ sizeof(struct hc_index_data)*sb_index +
+ offsetof(struct hc_index_data, flags);
+ u16 flags = REG_RD16(bp, addr);
+ /* clear and set */
+ flags &= ~HC_INDEX_DATA_HC_ENABLED;
+ flags |= enable_flag;
+ REG_WR16(bp, addr, flags);
+ DP(NETIF_MSG_HW, "port %x fw_sb_id %d sb_index %d disable %d\n",
+ port, fw_sb_id, sb_index, disable);
+}
+
/* used only at init
* locking is done by mcp
*/
-void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val)
+static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val)
{
pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
pci_write_config_dword(bp->pdev, PCICFG_GRC_DATA, val);
@@ -172,6 +423,76 @@ static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr)
return val;
}
+#define DMAE_DP_SRC_GRC "grc src_addr [%08x]"
+#define DMAE_DP_SRC_PCI "pci src_addr [%x:%08x]"
+#define DMAE_DP_DST_GRC "grc dst_addr [%08x]"
+#define DMAE_DP_DST_PCI "pci dst_addr [%x:%08x]"
+#define DMAE_DP_DST_NONE "dst_addr [none]"
+
+static void bnx2x_dp_dmae(struct bnx2x *bp, struct dmae_command *dmae,
+ int msglvl)
+{
+ u32 src_type = dmae->opcode & DMAE_COMMAND_SRC;
+
+ switch (dmae->opcode & DMAE_COMMAND_DST) {
+ case DMAE_CMD_DST_PCI:
+ if (src_type == DMAE_CMD_SRC_PCI)
+ DP(msglvl, "DMAE: opcode 0x%08x\n"
+ "src [%x:%08x], len [%d*4], dst [%x:%08x]\n"
+ "comp_addr [%x:%08x], comp_val 0x%08x\n",
+ dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+ dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo,
+ dmae->comp_addr_hi, dmae->comp_addr_lo,
+ dmae->comp_val);
+ else
+ DP(msglvl, "DMAE: opcode 0x%08x\n"
+ "src [%08x], len [%d*4], dst [%x:%08x]\n"
+ "comp_addr [%x:%08x], comp_val 0x%08x\n",
+ dmae->opcode, dmae->src_addr_lo >> 2,
+ dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo,
+ dmae->comp_addr_hi, dmae->comp_addr_lo,
+ dmae->comp_val);
+ break;
+ case DMAE_CMD_DST_GRC:
+ if (src_type == DMAE_CMD_SRC_PCI)
+ DP(msglvl, "DMAE: opcode 0x%08x\n"
+ "src [%x:%08x], len [%d*4], dst_addr [%08x]\n"
+ "comp_addr [%x:%08x], comp_val 0x%08x\n",
+ dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+ dmae->len, dmae->dst_addr_lo >> 2,
+ dmae->comp_addr_hi, dmae->comp_addr_lo,
+ dmae->comp_val);
+ else
+ DP(msglvl, "DMAE: opcode 0x%08x\n"
+ "src [%08x], len [%d*4], dst [%08x]\n"
+ "comp_addr [%x:%08x], comp_val 0x%08x\n",
+ dmae->opcode, dmae->src_addr_lo >> 2,
+ dmae->len, dmae->dst_addr_lo >> 2,
+ dmae->comp_addr_hi, dmae->comp_addr_lo,
+ dmae->comp_val);
+ break;
+ 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",
+ 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",
+ dmae->opcode, dmae->src_addr_lo >> 2,
+ dmae->len, dmae->comp_addr_hi, dmae->comp_addr_lo,
+ dmae->comp_val);
+ break;
+ }
+
+}
+
const u32 dmae_reg_go_c[] = {
DMAE_REG_GO_C0, DMAE_REG_GO_C1, DMAE_REG_GO_C2, DMAE_REG_GO_C3,
DMAE_REG_GO_C4, DMAE_REG_GO_C5, DMAE_REG_GO_C6, DMAE_REG_GO_C7,
@@ -195,85 +516,139 @@ void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, int idx)
REG_WR(bp, dmae_reg_go_c[idx], 1);
}
-void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
- u32 len32)
+u32 bnx2x_dmae_opcode_add_comp(u32 opcode, u8 comp_type)
{
- struct dmae_command dmae;
- u32 *wb_comp = bnx2x_sp(bp, wb_comp);
- int cnt = 200;
+ return opcode | ((comp_type << DMAE_COMMAND_C_DST_SHIFT) |
+ DMAE_CMD_C_ENABLE);
+}
- if (!bp->dmae_ready) {
- u32 *data = bnx2x_sp(bp, wb_data[0]);
+u32 bnx2x_dmae_opcode_clr_src_reset(u32 opcode)
+{
+ return opcode & ~DMAE_CMD_SRC_RESET;
+}
- DP(BNX2X_MSG_OFF, "DMAE is not ready (dst_addr %08x len32 %d)"
- " using indirect\n", dst_addr, len32);
- bnx2x_init_ind_wr(bp, dst_addr, data, len32);
- return;
- }
+u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
+ bool with_comp, u8 comp_type)
+{
+ u32 opcode = 0;
+
+ opcode |= ((src_type << DMAE_COMMAND_SRC_SHIFT) |
+ (dst_type << DMAE_COMMAND_DST_SHIFT));
+
+ opcode |= (DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET);
- memset(&dmae, 0, sizeof(struct dmae_command));
+ 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 |= (DMAE_COM_SET_ERR << DMAE_COMMAND_ERR_POLICY_SHIFT);
- dmae.opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
- DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
+ opcode |= DMAE_CMD_ENDIANITY_B_DW_SWAP;
#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
+ opcode |= DMAE_CMD_ENDIANITY_DW_SWAP;
#endif
- (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
- dmae.src_addr_lo = U64_LO(dma_addr);
- dmae.src_addr_hi = U64_HI(dma_addr);
- dmae.dst_addr_lo = dst_addr >> 2;
- dmae.dst_addr_hi = 0;
- dmae.len = len32;
- dmae.comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
- dmae.comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
- dmae.comp_val = DMAE_COMP_VAL;
-
- DP(BNX2X_MSG_OFF, "DMAE: opcode 0x%08x\n"
- DP_LEVEL "src_addr [%x:%08x] len [%d *4] "
- "dst_addr [%x:%08x (%08x)]\n"
- DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n",
- dmae.opcode, dmae.src_addr_hi, dmae.src_addr_lo,
- dmae.len, dmae.dst_addr_hi, dmae.dst_addr_lo, dst_addr,
- dmae.comp_addr_hi, dmae.comp_addr_lo, dmae.comp_val);
- DP(BNX2X_MSG_OFF, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n",
+ if (with_comp)
+ opcode = bnx2x_dmae_opcode_add_comp(opcode, comp_type);
+ return opcode;
+}
+
+static void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
+ struct dmae_command *dmae,
+ u8 src_type, u8 dst_type)
+{
+ memset(dmae, 0, sizeof(struct dmae_command));
+
+ /* set the opcode */
+ dmae->opcode = bnx2x_dmae_opcode(bp, src_type, dst_type,
+ true, DMAE_COMP_PCI);
+
+ /* fill in the completion parameters */
+ dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
+ dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
+ dmae->comp_val = DMAE_COMP_VAL;
+}
+
+/* issue a dmae command over the init-channel and wailt for completion */
+static int bnx2x_issue_dmae_with_comp(struct bnx2x *bp,
+ struct dmae_command *dmae)
+{
+ u32 *wb_comp = bnx2x_sp(bp, wb_comp);
+ int cnt = CHIP_REV_IS_SLOW(bp) ? (400000) : 40;
+ int rc = 0;
+
+ DP(BNX2X_MSG_OFF, "data before [0x%08x 0x%08x 0x%08x 0x%08x]\n",
bp->slowpath->wb_data[0], bp->slowpath->wb_data[1],
bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]);
+ /* lock the dmae channel */
mutex_lock(&bp->dmae_mutex);
+ /* reset completion */
*wb_comp = 0;
- bnx2x_post_dmae(bp, &dmae, INIT_DMAE_C(bp));
+ /* post the command on the channel used for initializations */
+ bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp));
+ /* wait for completion */
udelay(5);
-
- while (*wb_comp != DMAE_COMP_VAL) {
+ while ((*wb_comp & ~DMAE_PCI_ERR_FLAG) != DMAE_COMP_VAL) {
DP(BNX2X_MSG_OFF, "wb_comp 0x%08x\n", *wb_comp);
if (!cnt) {
BNX2X_ERR("DMAE timeout!\n");
- break;
+ rc = DMAE_TIMEOUT;
+ goto unlock;
}
cnt--;
- /* adjust delay for emulation/FPGA */
- if (CHIP_REV_IS_SLOW(bp))
- msleep(100);
- else
- udelay(5);
+ udelay(50);
+ }
+ if (*wb_comp & DMAE_PCI_ERR_FLAG) {
+ BNX2X_ERR("DMAE PCI error!\n");
+ rc = DMAE_PCI_ERROR;
}
+ DP(BNX2X_MSG_OFF, "data after [0x%08x 0x%08x 0x%08x 0x%08x]\n",
+ bp->slowpath->wb_data[0], bp->slowpath->wb_data[1],
+ bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]);
+
+unlock:
mutex_unlock(&bp->dmae_mutex);
+ return rc;
+}
+
+void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
+ u32 len32)
+{
+ struct dmae_command dmae;
+
+ if (!bp->dmae_ready) {
+ u32 *data = bnx2x_sp(bp, wb_data[0]);
+
+ DP(BNX2X_MSG_OFF, "DMAE is not ready (dst_addr %08x len32 %d)"
+ " using indirect\n", dst_addr, len32);
+ bnx2x_init_ind_wr(bp, dst_addr, data, len32);
+ return;
+ }
+
+ /* set opcode and fixed command fields */
+ bnx2x_prep_dmae_with_comp(bp, &dmae, DMAE_SRC_PCI, DMAE_DST_GRC);
+
+ /* fill in addresses and len */
+ dmae.src_addr_lo = U64_LO(dma_addr);
+ dmae.src_addr_hi = U64_HI(dma_addr);
+ dmae.dst_addr_lo = dst_addr >> 2;
+ dmae.dst_addr_hi = 0;
+ dmae.len = len32;
+
+ bnx2x_dp_dmae(bp, &dmae, BNX2X_MSG_OFF);
+
+ /* issue the command and wait for completion */
+ bnx2x_issue_dmae_with_comp(bp, &dmae);
}
void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
{
struct dmae_command dmae;
- u32 *wb_comp = bnx2x_sp(bp, wb_comp);
- int cnt = 200;
if (!bp->dmae_ready) {
u32 *data = bnx2x_sp(bp, wb_data[0]);
@@ -286,66 +661,24 @@ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
return;
}
- memset(&dmae, 0, sizeof(struct dmae_command));
+ /* set opcode and fixed command fields */
+ bnx2x_prep_dmae_with_comp(bp, &dmae, DMAE_SRC_GRC, DMAE_DST_PCI);
- dmae.opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
- DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+ /* fill in addresses and len */
dmae.src_addr_lo = src_addr >> 2;
dmae.src_addr_hi = 0;
dmae.dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data));
dmae.dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data));
dmae.len = len32;
- dmae.comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
- dmae.comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
- dmae.comp_val = DMAE_COMP_VAL;
-
- DP(BNX2X_MSG_OFF, "DMAE: opcode 0x%08x\n"
- DP_LEVEL "src_addr [%x:%08x] len [%d *4] "
- "dst_addr [%x:%08x (%08x)]\n"
- DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n",
- dmae.opcode, dmae.src_addr_hi, dmae.src_addr_lo,
- dmae.len, dmae.dst_addr_hi, dmae.dst_addr_lo, src_addr,
- dmae.comp_addr_hi, dmae.comp_addr_lo, dmae.comp_val);
-
- mutex_lock(&bp->dmae_mutex);
- memset(bnx2x_sp(bp, wb_data[0]), 0, sizeof(u32) * 4);
- *wb_comp = 0;
-
- bnx2x_post_dmae(bp, &dmae, INIT_DMAE_C(bp));
-
- udelay(5);
-
- while (*wb_comp != DMAE_COMP_VAL) {
-
- if (!cnt) {
- BNX2X_ERR("DMAE timeout!\n");
- break;
- }
- cnt--;
- /* adjust delay for emulation/FPGA */
- if (CHIP_REV_IS_SLOW(bp))
- msleep(100);
- else
- udelay(5);
- }
- DP(BNX2X_MSG_OFF, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n",
- bp->slowpath->wb_data[0], bp->slowpath->wb_data[1],
- bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]);
+ bnx2x_dp_dmae(bp, &dmae, BNX2X_MSG_OFF);
- mutex_unlock(&bp->dmae_mutex);
+ /* issue the command and wait for completion */
+ bnx2x_issue_dmae_with_comp(bp, &dmae);
}
-void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
- u32 addr, u32 len)
+static void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
+ u32 addr, u32 len)
{
int dmae_wr_max = DMAE_LEN32_WR_MAX(bp);
int offset = 0;
@@ -508,19 +841,24 @@ static void bnx2x_fw_dump(struct bnx2x *bp)
u32 mark, offset;
__be32 data[9];
int word;
-
+ u32 trace_shmem_base;
if (BP_NOMCP(bp)) {
BNX2X_ERR("NO MCP - can not dump\n");
return;
}
- addr = bp->common.shmem_base - 0x0800 + 4;
+ if (BP_PATH(bp) == 0)
+ trace_shmem_base = bp->common.shmem_base;
+ else
+ trace_shmem_base = SHMEM2_RD(bp, other_shmem_base_addr);
+ addr = trace_shmem_base - 0x0800 + 4;
mark = REG_RD(bp, addr);
- mark = MCP_REG_MCPR_SCRATCH + ((mark + 0x3) & ~0x3) - 0x08000000;
+ mark = (CHIP_IS_E1x(bp) ? MCP_REG_MCPR_SCRATCH : MCP_A_REG_MCPR_SCRATCH)
+ + ((mark + 0x3) & ~0x3) - 0x08000000;
pr_err("begin fw dump (mark 0x%x)\n", mark);
pr_err("");
- for (offset = mark; offset <= bp->common.shmem_base; offset += 0x8*4) {
+ for (offset = mark; offset <= trace_shmem_base; offset += 0x8*4) {
for (word = 0; word < 8; word++)
data[word] = htonl(REG_RD(bp, offset + 4*word));
data[8] = 0x0;
@@ -538,7 +876,12 @@ static void bnx2x_fw_dump(struct bnx2x *bp)
void bnx2x_panic_dump(struct bnx2x *bp)
{
int i;
- u16 j, start, end;
+ u16 j;
+ struct hc_sp_status_block_data sp_sb_data;
+ int func = BP_FUNC(bp);
+#ifdef BNX2X_STOP_ON_ERROR
+ u16 start = 0, end = 0;
+#endif
bp->stats_state = STATS_STATE_DISABLED;
DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n");
@@ -547,44 +890,143 @@ void bnx2x_panic_dump(struct bnx2x *bp)
/* Indices */
/* Common */
- BNX2X_ERR("def_c_idx(0x%x) def_u_idx(0x%x) def_x_idx(0x%x)"
- " def_t_idx(0x%x) def_att_idx(0x%x) attn_state(0x%x)"
+ BNX2X_ERR("def_idx(0x%x) def_att_idx(0x%x) attn_state(0x%x)"
" spq_prod_idx(0x%x)\n",
- bp->def_c_idx, bp->def_u_idx, bp->def_x_idx, bp->def_t_idx,
- bp->def_att_idx, bp->attn_state, bp->spq_prod_idx);
+ bp->def_idx, bp->def_att_idx,
+ bp->attn_state, bp->spq_prod_idx);
+ BNX2X_ERR("DSB: attn bits(0x%x) ack(0x%x) id(0x%x) idx(0x%x)\n",
+ bp->def_status_blk->atten_status_block.attn_bits,
+ bp->def_status_blk->atten_status_block.attn_bits_ack,
+ bp->def_status_blk->atten_status_block.status_block_id,
+ bp->def_status_blk->atten_status_block.attn_bits_index);
+ 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) ? ") " : " ");
+
+ 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)\n",
+ sp_sb_data.igu_sb_id,
+ sp_sb_data.igu_seg_id,
+ sp_sb_data.p_func.pf_id,
+ sp_sb_data.p_func.vnic_id,
+ sp_sb_data.p_func.vf_id,
+ sp_sb_data.p_func.vf_valid);
+
- /* Rx */
for_each_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
-
+ int loop;
+ struct hc_status_block_data_e2 sb_data_e2;
+ struct hc_status_block_data_e1x sb_data_e1x;
+ struct hc_status_block_sm *hc_sm_p =
+ CHIP_IS_E2(bp) ?
+ sb_data_e2.common.state_machine :
+ sb_data_e1x.common.state_machine;
+ struct hc_index_data *hc_index_p =
+ CHIP_IS_E2(bp) ?
+ sb_data_e2.index_data :
+ sb_data_e1x.index_data;
+ int data_size;
+ u32 *sb_data_p;
+
+ /* Rx */
BNX2X_ERR("fp%d: rx_bd_prod(0x%x) rx_bd_cons(0x%x)"
- " *rx_bd_cons_sb(0x%x) rx_comp_prod(0x%x)"
+ " rx_comp_prod(0x%x)"
" rx_comp_cons(0x%x) *rx_cons_sb(0x%x)\n",
i, fp->rx_bd_prod, fp->rx_bd_cons,
- le16_to_cpu(*fp->rx_bd_cons_sb), fp->rx_comp_prod,
+ fp->rx_comp_prod,
fp->rx_comp_cons, le16_to_cpu(*fp->rx_cons_sb));
BNX2X_ERR(" rx_sge_prod(0x%x) last_max_sge(0x%x)"
- " fp_u_idx(0x%x) *sb_u_idx(0x%x)\n",
+ " fp_hc_idx(0x%x)\n",
fp->rx_sge_prod, fp->last_max_sge,
- le16_to_cpu(fp->fp_u_idx),
- fp->status_blk->u_status_block.status_block_index);
- }
-
- /* Tx */
- for_each_queue(bp, i) {
- struct bnx2x_fastpath *fp = &bp->fp[i];
+ le16_to_cpu(fp->fp_hc_idx));
+ /* Tx */
BNX2X_ERR("fp%d: tx_pkt_prod(0x%x) tx_pkt_cons(0x%x)"
" tx_bd_prod(0x%x) tx_bd_cons(0x%x)"
" *tx_cons_sb(0x%x)\n",
i, fp->tx_pkt_prod, fp->tx_pkt_cons, fp->tx_bd_prod,
fp->tx_bd_cons, le16_to_cpu(*fp->tx_cons_sb));
- BNX2X_ERR(" fp_c_idx(0x%x) *sb_c_idx(0x%x)"
- " tx_db_prod(0x%x)\n", le16_to_cpu(fp->fp_c_idx),
- fp->status_blk->c_status_block.status_block_index,
- fp->tx_db.data.prod);
+
+ loop = CHIP_IS_E2(bp) ?
+ HC_SB_MAX_INDICES_E2 : HC_SB_MAX_INDICES_E1X;
+
+ /* host sb data */
+
+ BNX2X_ERR(" run indexes (");
+ for (j = 0; j < HC_SB_MAX_SM; j++)
+ pr_cont("0x%x%s",
+ fp->sb_running_index[j],
+ (j == HC_SB_MAX_SM - 1) ? ")" : " ");
+
+ BNX2X_ERR(" indexes (");
+ for (j = 0; j < loop; j++)
+ pr_cont("0x%x%s",
+ fp->sb_index_values[j],
+ (j == loop - 1) ? ")" : " ");
+ /* fw sb data */
+ data_size = CHIP_IS_E2(bp) ?
+ sizeof(struct hc_status_block_data_e2) :
+ sizeof(struct hc_status_block_data_e1x);
+ data_size /= sizeof(u32);
+ sb_data_p = CHIP_IS_E2(bp) ?
+ (u32 *)&sb_data_e2 :
+ (u32 *)&sb_data_e1x;
+ /* copy sb data in here */
+ for (j = 0; j < data_size; j++)
+ *(sb_data_p + j) = REG_RD(bp, BAR_CSTRORM_INTMEM +
+ CSTORM_STATUS_BLOCK_DATA_OFFSET(fp->fw_sb_id) +
+ j * sizeof(u32));
+
+ if (CHIP_IS_E2(bp)) {
+ pr_cont("pf_id(0x%x) vf_id (0x%x) vf_valid(0x%x) "
+ "vnic_id(0x%x) same_igu_sb_1b(0x%x)\n",
+ sb_data_e2.common.p_func.pf_id,
+ sb_data_e2.common.p_func.vf_id,
+ sb_data_e2.common.p_func.vf_valid,
+ sb_data_e2.common.p_func.vnic_id,
+ sb_data_e2.common.same_igu_sb_1b);
+ } else {
+ pr_cont("pf_id(0x%x) vf_id (0x%x) vf_valid(0x%x) "
+ "vnic_id(0x%x) same_igu_sb_1b(0x%x)\n",
+ sb_data_e1x.common.p_func.pf_id,
+ sb_data_e1x.common.p_func.vf_id,
+ sb_data_e1x.common.p_func.vf_valid,
+ sb_data_e1x.common.p_func.vnic_id,
+ sb_data_e1x.common.same_igu_sb_1b);
+ }
+
+ /* SB_SMs data */
+ for (j = 0; j < HC_SB_MAX_SM; j++) {
+ pr_cont("SM[%d] __flags (0x%x) "
+ "igu_sb_id (0x%x) igu_seg_id(0x%x) "
+ "time_to_expire (0x%x) "
+ "timer_value(0x%x)\n", j,
+ hc_sm_p[j].__flags,
+ hc_sm_p[j].igu_sb_id,
+ hc_sm_p[j].igu_seg_id,
+ hc_sm_p[j].time_to_expire,
+ hc_sm_p[j].timer_value);
+ }
+
+ /* Indecies data */
+ for (j = 0; j < loop; j++) {
+ pr_cont("INDEX[%d] flags (0x%x) "
+ "timeout (0x%x)\n", j,
+ hc_index_p[j].flags,
+ hc_index_p[j].timeout);
+ }
}
+#ifdef BNX2X_STOP_ON_ERROR
/* Rings */
/* Rx */
for_each_queue(bp, i) {
@@ -642,13 +1084,13 @@ void bnx2x_panic_dump(struct bnx2x *bp)
i, j, tx_bd[0], tx_bd[1], tx_bd[2], tx_bd[3]);
}
}
-
+#endif
bnx2x_fw_dump(bp);
bnx2x_mc_assert(bp);
BNX2X_ERR("end crash dump -----------------\n");
}
-void bnx2x_int_enable(struct bnx2x *bp)
+static void bnx2x_hc_int_enable(struct bnx2x *bp)
{
int port = BP_PORT(bp);
u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
@@ -672,14 +1114,19 @@ void bnx2x_int_enable(struct bnx2x *bp)
HC_CONFIG_0_REG_INT_LINE_EN_0 |
HC_CONFIG_0_REG_ATTN_BIT_EN_0);
- DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)\n",
- val, port, addr);
+ if (!CHIP_IS_E1(bp)) {
+ DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)\n",
+ val, port, addr);
- REG_WR(bp, addr, val);
+ REG_WR(bp, addr, val);
- val &= ~HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0;
+ val &= ~HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0;
+ }
}
+ if (CHIP_IS_E1(bp))
+ REG_WR(bp, HC_REG_INT_MASK + port*4, 0x1FFFF);
+
DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x) mode %s\n",
val, port, addr, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
@@ -690,9 +1137,9 @@ void bnx2x_int_enable(struct bnx2x *bp)
mmiowb();
barrier();
- if (CHIP_IS_E1H(bp)) {
+ if (!CHIP_IS_E1(bp)) {
/* init leading/trailing edge */
- if (IS_E1HMF(bp)) {
+ if (IS_MF(bp)) {
val = (0xee0f | (1 << (BP_E1HVN(bp) + 4)));
if (bp->port.pmf)
/* enable nig and gpio3 attention */
@@ -708,16 +1155,91 @@ void bnx2x_int_enable(struct bnx2x *bp)
mmiowb();
}
-static void bnx2x_int_disable(struct bnx2x *bp)
+static void bnx2x_igu_int_enable(struct bnx2x *bp)
+{
+ u32 val;
+ int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
+ int msi = (bp->flags & USING_MSI_FLAG) ? 1 : 0;
+
+ val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
+
+ if (msix) {
+ val &= ~(IGU_PF_CONF_INT_LINE_EN |
+ IGU_PF_CONF_SINGLE_ISR_EN);
+ val |= (IGU_PF_CONF_FUNC_EN |
+ IGU_PF_CONF_MSI_MSIX_EN |
+ IGU_PF_CONF_ATTN_BIT_EN);
+ } else if (msi) {
+ val &= ~IGU_PF_CONF_INT_LINE_EN;
+ val |= (IGU_PF_CONF_FUNC_EN |
+ IGU_PF_CONF_MSI_MSIX_EN |
+ IGU_PF_CONF_ATTN_BIT_EN |
+ IGU_PF_CONF_SINGLE_ISR_EN);
+ } else {
+ val &= ~IGU_PF_CONF_MSI_MSIX_EN;
+ val |= (IGU_PF_CONF_FUNC_EN |
+ IGU_PF_CONF_INT_LINE_EN |
+ IGU_PF_CONF_ATTN_BIT_EN |
+ IGU_PF_CONF_SINGLE_ISR_EN);
+ }
+
+ DP(NETIF_MSG_INTR, "write 0x%x to IGU mode %s\n",
+ val, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
+
+ REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
+
+ barrier();
+
+ /* init leading/trailing edge */
+ if (IS_MF(bp)) {
+ val = (0xee0f | (1 << (BP_E1HVN(bp) + 4)));
+ if (bp->port.pmf)
+ /* enable nig and gpio3 attention */
+ val |= 0x1100;
+ } else
+ val = 0xffff;
+
+ REG_WR(bp, IGU_REG_TRAILING_EDGE_LATCH, val);
+ REG_WR(bp, IGU_REG_LEADING_EDGE_LATCH, val);
+
+ /* Make sure that interrupts are indeed enabled from here on */
+ mmiowb();
+}
+
+void bnx2x_int_enable(struct bnx2x *bp)
+{
+ if (bp->common.int_block == INT_BLOCK_HC)
+ bnx2x_hc_int_enable(bp);
+ else
+ bnx2x_igu_int_enable(bp);
+}
+
+static void bnx2x_hc_int_disable(struct bnx2x *bp)
{
int port = BP_PORT(bp);
u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
u32 val = REG_RD(bp, addr);
- val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
- HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
- HC_CONFIG_0_REG_INT_LINE_EN_0 |
- HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+ /*
+ * in E1 we must use only PCI configuration space to disable
+ * MSI/MSIX capablility
+ * It's forbitten to disable IGU_PF_CONF_MSI_MSIX_EN in HC block
+ */
+ if (CHIP_IS_E1(bp)) {
+ /* Since IGU_PF_CONF_MSI_MSIX_EN still always on
+ * Use mask register to prevent from HC sending interrupts
+ * after we exit the function
+ */
+ REG_WR(bp, HC_REG_INT_MASK + port*4, 0);
+
+ val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+ HC_CONFIG_0_REG_INT_LINE_EN_0 |
+ HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+ } else
+ val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+ HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
+ HC_CONFIG_0_REG_INT_LINE_EN_0 |
+ HC_CONFIG_0_REG_ATTN_BIT_EN_0);
DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)\n",
val, port, addr);
@@ -730,6 +1252,32 @@ static void bnx2x_int_disable(struct bnx2x *bp)
BNX2X_ERR("BUG! proper val not read from IGU!\n");
}
+static void bnx2x_igu_int_disable(struct bnx2x *bp)
+{
+ u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
+
+ val &= ~(IGU_PF_CONF_MSI_MSIX_EN |
+ IGU_PF_CONF_INT_LINE_EN |
+ IGU_PF_CONF_ATTN_BIT_EN);
+
+ DP(NETIF_MSG_INTR, "write %x to IGU\n", val);
+
+ /* flush all outstanding writes */
+ mmiowb();
+
+ REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
+ if (REG_RD(bp, IGU_REG_PF_CONFIGURATION) != val)
+ BNX2X_ERR("BUG! proper val not read from IGU!\n");
+}
+
+static void bnx2x_int_disable(struct bnx2x *bp)
+{
+ if (bp->common.int_block == INT_BLOCK_HC)
+ bnx2x_hc_int_disable(bp);
+ else
+ bnx2x_igu_int_disable(bp);
+}
+
void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
{
int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
@@ -781,7 +1329,7 @@ static bool bnx2x_trylock_hw_lock(struct bnx2x *bp, u32 resource)
DP(NETIF_MSG_HW,
"resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
resource, HW_LOCK_MAX_RESOURCE_VALUE);
- return -EINVAL;
+ return false;
}
if (func <= 5)
@@ -800,7 +1348,6 @@ static bool bnx2x_trylock_hw_lock(struct bnx2x *bp, u32 resource)
return false;
}
-
#ifdef BCM_CNIC
static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid);
#endif
@@ -817,76 +1364,35 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp,
fp->index, cid, command, bp->state,
rr_cqe->ramrod_cqe.ramrod_type);
- bp->spq_left++;
-
- if (fp->index) {
- switch (command | fp->state) {
- case (RAMROD_CMD_ID_ETH_CLIENT_SETUP |
- BNX2X_FP_STATE_OPENING):
- DP(NETIF_MSG_IFUP, "got MULTI[%d] setup ramrod\n",
- cid);
- fp->state = BNX2X_FP_STATE_OPEN;
- break;
-
- case (RAMROD_CMD_ID_ETH_HALT | BNX2X_FP_STATE_HALTING):
- DP(NETIF_MSG_IFDOWN, "got MULTI[%d] halt ramrod\n",
- cid);
- fp->state = BNX2X_FP_STATE_HALTED;
- break;
-
- default:
- BNX2X_ERR("unexpected MC reply (%d) "
- "fp[%d] state is %x\n",
- command, fp->index, fp->state);
- break;
- }
- mb(); /* force bnx2x_wait_ramrod() to see the change */
- return;
- }
-
- switch (command | bp->state) {
- case (RAMROD_CMD_ID_ETH_PORT_SETUP | BNX2X_STATE_OPENING_WAIT4_PORT):
- DP(NETIF_MSG_IFUP, "got setup ramrod\n");
- bp->state = BNX2X_STATE_OPEN;
+ switch (command | fp->state) {
+ case (RAMROD_CMD_ID_ETH_CLIENT_SETUP | BNX2X_FP_STATE_OPENING):
+ DP(NETIF_MSG_IFUP, "got MULTI[%d] setup ramrod\n", cid);
+ fp->state = BNX2X_FP_STATE_OPEN;
break;
- case (RAMROD_CMD_ID_ETH_HALT | BNX2X_STATE_CLOSING_WAIT4_HALT):
- DP(NETIF_MSG_IFDOWN, "got halt ramrod\n");
- bp->state = BNX2X_STATE_CLOSING_WAIT4_DELETE;
+ case (RAMROD_CMD_ID_ETH_HALT | BNX2X_FP_STATE_HALTING):
+ DP(NETIF_MSG_IFDOWN, "got MULTI[%d] halt ramrod\n", cid);
fp->state = BNX2X_FP_STATE_HALTED;
break;
- case (RAMROD_CMD_ID_ETH_CFC_DEL | BNX2X_STATE_CLOSING_WAIT4_HALT):
- DP(NETIF_MSG_IFDOWN, "got delete ramrod for MULTI[%d]\n", cid);
- bnx2x_fp(bp, cid, state) = BNX2X_FP_STATE_CLOSED;
- break;
-
-#ifdef BCM_CNIC
- case (RAMROD_CMD_ID_ETH_CFC_DEL | BNX2X_STATE_OPEN):
- DP(NETIF_MSG_IFDOWN, "got delete ramrod for CID %d\n", cid);
- bnx2x_cnic_cfc_comp(bp, cid);
- break;
-#endif
-
- case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_OPEN):
- case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_DIAG):
- DP(NETIF_MSG_IFUP, "got set mac ramrod\n");
- bp->set_mac_pending--;
- smp_wmb();
- break;
-
- case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_CLOSING_WAIT4_HALT):
- DP(NETIF_MSG_IFDOWN, "got (un)set mac ramrod\n");
- bp->set_mac_pending--;
- smp_wmb();
+ case (RAMROD_CMD_ID_ETH_TERMINATE | BNX2X_FP_STATE_TERMINATING):
+ DP(NETIF_MSG_IFDOWN, "got MULTI[%d] teminate ramrod\n", cid);
+ fp->state = BNX2X_FP_STATE_TERMINATED;
break;
default:
- BNX2X_ERR("unexpected MC reply (%d) bp->state is %x\n",
- command, bp->state);
+ BNX2X_ERR("unexpected MC reply (%d) "
+ "fp[%d] state is %x\n",
+ command, fp->index, fp->state);
break;
}
- mb(); /* force bnx2x_wait_ramrod() to see the change */
+
+ smp_mb__before_atomic_inc();
+ atomic_inc(&bp->spq_left);
+ /* push the change in fp->state and towards the memory */
+ smp_wmb();
+
+ return;
}
irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
@@ -914,25 +1420,22 @@ irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
return IRQ_HANDLED;
#endif
- for (i = 0; i < BNX2X_NUM_QUEUES(bp); i++) {
+ for_each_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
- mask = 0x2 << fp->sb_id;
+ mask = 0x2 << (fp->index + CNIC_CONTEXT_USE);
if (status & mask) {
/* Handle Rx and Tx according to SB id */
prefetch(fp->rx_cons_sb);
- prefetch(&fp->status_blk->u_status_block.
- status_block_index);
prefetch(fp->tx_cons_sb);
- prefetch(&fp->status_blk->c_status_block.
- status_block_index);
+ prefetch(&fp->sb_running_index[SM_RX_ID]);
napi_schedule(&bnx2x_fp(bp, fp->index, napi));
status &= ~mask;
}
}
#ifdef BCM_CNIC
- mask = 0x2 << CNIC_SB_ID(bp);
+ mask = 0x2;
if (status & (mask | 0x1)) {
struct cnic_ops *c_ops = NULL;
@@ -1227,49 +1730,91 @@ static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode)
return 0;
}
+int bnx2x_get_link_cfg_idx(struct bnx2x *bp)
+{
+ u32 sel_phy_idx = 0;
+ if (bp->link_vars.link_up) {
+ sel_phy_idx = EXT_PHY1;
+ /* In case link is SERDES, check if the EXT_PHY2 is the one */
+ if ((bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) &&
+ (bp->link_params.phy[EXT_PHY2].supported & SUPPORTED_FIBRE))
+ sel_phy_idx = EXT_PHY2;
+ } else {
+
+ switch (bnx2x_phy_selection(&bp->link_params)) {
+ case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
+ case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
+ case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
+ sel_phy_idx = EXT_PHY1;
+ break;
+ case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
+ case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
+ sel_phy_idx = EXT_PHY2;
+ break;
+ }
+ }
+ /*
+ * The selected actived PHY is always after swapping (in case PHY
+ * swapping is enabled). So when swapping is enabled, we need to reverse
+ * the configuration
+ */
+
+ if (bp->link_params.multi_phy_config &
+ PORT_HW_CFG_PHY_SWAPPED_ENABLED) {
+ if (sel_phy_idx == EXT_PHY1)
+ sel_phy_idx = EXT_PHY2;
+ else if (sel_phy_idx == EXT_PHY2)
+ sel_phy_idx = EXT_PHY1;
+ }
+ return LINK_CONFIG_IDX(sel_phy_idx);
+}
+
void bnx2x_calc_fc_adv(struct bnx2x *bp)
{
+ u8 cfg_idx = bnx2x_get_link_cfg_idx(bp);
switch (bp->link_vars.ieee_fc &
MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK) {
case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE:
- bp->port.advertising &= ~(ADVERTISED_Asym_Pause |
- ADVERTISED_Pause);
+ bp->port.advertising[cfg_idx] &= ~(ADVERTISED_Asym_Pause |
+ ADVERTISED_Pause);
break;
case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH:
- bp->port.advertising |= (ADVERTISED_Asym_Pause |
- ADVERTISED_Pause);
+ bp->port.advertising[cfg_idx] |= (ADVERTISED_Asym_Pause |
+ ADVERTISED_Pause);
break;
case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC:
- bp->port.advertising |= ADVERTISED_Asym_Pause;
+ bp->port.advertising[cfg_idx] |= ADVERTISED_Asym_Pause;
break;
default:
- bp->port.advertising &= ~(ADVERTISED_Asym_Pause |
- ADVERTISED_Pause);
+ bp->port.advertising[cfg_idx] &= ~(ADVERTISED_Asym_Pause |
+ ADVERTISED_Pause);
break;
}
}
-
u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
{
if (!BP_NOMCP(bp)) {
u8 rc;
-
+ int cfx_idx = bnx2x_get_link_cfg_idx(bp);
+ u16 req_line_speed = bp->link_params.req_line_speed[cfx_idx];
/* Initialize link parameters structure variables */
/* It is recommended to turn off RX FC for jumbo frames
for better performance */
- if (bp->dev->mtu > 5000)
+ if ((CHIP_IS_E1x(bp)) && (bp->dev->mtu > 5000))
bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_TX;
else
bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH;
bnx2x_acquire_phy_lock(bp);
- if (load_mode == LOAD_DIAG)
- bp->link_params.loopback_mode = LOOPBACK_XGXS_10;
+ if (load_mode == LOAD_DIAG) {
+ bp->link_params.loopback_mode = LOOPBACK_XGXS;
+ bp->link_params.req_line_speed[cfx_idx] = SPEED_10000;
+ }
rc = bnx2x_phy_init(&bp->link_params, &bp->link_vars);
@@ -1281,7 +1826,7 @@ u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
bnx2x_link_report(bp);
}
-
+ bp->link_params.req_line_speed[cfx_idx] = req_line_speed;
return rc;
}
BNX2X_ERR("Bootcode is missing - can not initialize link\n");
@@ -1292,6 +1837,7 @@ void bnx2x_link_set(struct bnx2x *bp)
{
if (!BP_NOMCP(bp)) {
bnx2x_acquire_phy_lock(bp);
+ bnx2x_link_reset(&bp->link_params, &bp->link_vars, 1);
bnx2x_phy_init(&bp->link_params, &bp->link_vars);
bnx2x_release_phy_lock(bp);
@@ -1310,13 +1856,14 @@ static void bnx2x__link_reset(struct bnx2x *bp)
BNX2X_ERR("Bootcode is missing - can not reset link\n");
}
-u8 bnx2x_link_test(struct bnx2x *bp)
+u8 bnx2x_link_test(struct bnx2x *bp, u8 is_serdes)
{
u8 rc = 0;
if (!BP_NOMCP(bp)) {
bnx2x_acquire_phy_lock(bp);
- rc = bnx2x_test_link(&bp->link_params, &bp->link_vars);
+ rc = bnx2x_test_link(&bp->link_params, &bp->link_vars,
+ is_serdes);
bnx2x_release_phy_lock(bp);
} else
BNX2X_ERR("Bootcode is missing - can not test link\n");
@@ -1371,13 +1918,11 @@ static void bnx2x_init_port_minmax(struct bnx2x *bp)
static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
{
int all_zero = 1;
- int port = BP_PORT(bp);
int vn;
bp->vn_weight_sum = 0;
for (vn = VN_0; vn < E1HVN_MAX; vn++) {
- int func = 2*vn + port;
- u32 vn_cfg = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
+ 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;
@@ -1405,11 +1950,12 @@ static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
}
-static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func)
+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 = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
+ u32 vn_cfg = bp->mf_config[vn];
+ int func = 2*vn + BP_PORT(bp);
u16 vn_min_rate, vn_max_rate;
int i;
@@ -1422,11 +1968,12 @@ static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func)
vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
/* If min rate is zero - set it to 1 */
- if (!vn_min_rate)
+ if (bp->vn_weight_sum && (vn_min_rate == 0))
vn_min_rate = DEF_MIN_RATE;
vn_max_rate = ((vn_cfg & FUNC_MF_CFG_MAX_BW_MASK) >>
FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
}
+
DP(NETIF_MSG_IFUP,
"func %d: vn_min_rate %d vn_max_rate %d vn_weight_sum %d\n",
func, vn_min_rate, vn_max_rate, bp->vn_weight_sum);
@@ -1467,6 +2014,83 @@ static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func)
((u32 *)(&m_fair_vn))[i]);
}
+static int bnx2x_get_cmng_fns_mode(struct bnx2x *bp)
+{
+ if (CHIP_REV_IS_SLOW(bp))
+ return CMNG_FNS_NONE;
+ if (IS_MF(bp))
+ return CMNG_FNS_MINMAX;
+
+ return CMNG_FNS_NONE;
+}
+
+static void bnx2x_read_mf_cfg(struct bnx2x *bp)
+{
+ int vn;
+
+ if (BP_NOMCP(bp))
+ return; /* what should be the default bvalue in this case */
+
+ for (vn = VN_0; vn < E1HVN_MAX; vn++) {
+ int /*abs*/func = 2*vn + BP_PORT(bp);
+ bp->mf_config[vn] =
+ MF_CFG_RD(bp, func_mf_config[func].config);
+ }
+}
+
+static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type)
+{
+
+ if (cmng_type == CMNG_FNS_MINMAX) {
+ int vn;
+
+ /* clear cmng_enables */
+ bp->cmng.flags.cmng_enables = 0;
+
+ /* read mf conf from shmem */
+ if (read_cfg)
+ bnx2x_read_mf_cfg(bp);
+
+ /* Init rate shaping and fairness contexts */
+ bnx2x_init_port_minmax(bp);
+
+ /* vn_weight_sum and enable fairness if not 0 */
+ bnx2x_calc_vn_weight_sum(bp);
+
+ /* calculate and set min-max rate for each vn */
+ for (vn = VN_0; vn < E1HVN_MAX; vn++)
+ bnx2x_init_vn_minmax(bp, vn);
+
+ /* always enable rate shaping and fairness */
+ bp->cmng.flags.cmng_enables |=
+ CMNG_FLAGS_PER_PORT_RATE_SHAPING_VN;
+ if (!bp->vn_weight_sum)
+ DP(NETIF_MSG_IFUP, "All MIN values are zeroes"
+ " fairness will be disabled\n");
+ return;
+ }
+
+ /* rate shaping and fairness are disabled */
+ DP(NETIF_MSG_IFUP,
+ "rate shaping and fairness are disabled\n");
+}
+
+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))
+ continue;
+
+ func = ((vn << 1) | port);
+ REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
+ (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
+ }
+}
/* This function is called upon link interrupt */
static void bnx2x_link_attn(struct bnx2x *bp)
@@ -1480,7 +2104,7 @@ static void bnx2x_link_attn(struct bnx2x *bp)
if (bp->link_vars.link_up) {
/* dropless flow control */
- if (CHIP_IS_E1H(bp) && bp->dropless_fc) {
+ if (!CHIP_IS_E1(bp) && bp->dropless_fc) {
int port = BP_PORT(bp);
u32 pause_enabled = 0;
@@ -1508,37 +2132,19 @@ static void bnx2x_link_attn(struct bnx2x *bp)
if (prev_link_status != bp->link_vars.link_status)
bnx2x_link_report(bp);
- if (IS_E1HMF(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))
- continue;
+ if (IS_MF(bp))
+ bnx2x_link_sync_notify(bp);
- func = ((vn << 1) | port);
- REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
- (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
- }
+ if (bp->link_vars.link_up && bp->link_vars.line_speed) {
+ int cmng_fns = bnx2x_get_cmng_fns_mode(bp);
- if (bp->link_vars.link_up) {
- int i;
-
- /* Init rate shaping and fairness contexts */
- bnx2x_init_port_minmax(bp);
-
- for (vn = VN_0; vn < E1HVN_MAX; vn++)
- bnx2x_init_vn_minmax(bp, 2*vn + port);
-
- /* Store it to internal memory */
- for (i = 0;
- i < sizeof(struct cmng_struct_per_port) / 4; i++)
- REG_WR(bp, BAR_XSTRORM_INTMEM +
- XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i*4,
- ((u32 *)(&bp->cmng))[i]);
- }
+ if (cmng_fns != CMNG_FNS_NONE) {
+ bnx2x_cmng_fns_init(bp, false, cmng_fns);
+ storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp));
+ } else
+ /* rate shaping and fairness are disabled */
+ DP(NETIF_MSG_IFUP,
+ "single function mode without fairness\n");
}
}
@@ -1554,7 +2160,9 @@ void bnx2x__link_status_update(struct bnx2x *bp)
else
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
- bnx2x_calc_vn_weight_sum(bp);
+ /* the link status update could be the result of a DCC event
+ hence re-read the shmem mf configuration */
+ bnx2x_read_mf_cfg(bp);
/* indicate link status */
bnx2x_link_report(bp);
@@ -1570,8 +2178,13 @@ static void bnx2x_pmf_update(struct bnx2x *bp)
/* enable nig attention */
val = (0xff0f | (1 << (BP_E1HVN(bp) + 4)));
- REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
- REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
+ 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);
+ } else if (CHIP_IS_E2(bp)) {
+ REG_WR(bp, IGU_REG_TRAILING_EDGE_LATCH, val);
+ REG_WR(bp, IGU_REG_LEADING_EDGE_LATCH, val);
+ }
bnx2x_stats_handle(bp, STATS_EVENT_PMF);
}
@@ -1585,23 +2198,25 @@ static void bnx2x_pmf_update(struct bnx2x *bp)
*/
/* send the MCP a request, block until there is a reply */
-u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command, u32 param)
{
- int func = BP_FUNC(bp);
+ int mb_idx = BP_FW_MB_IDX(bp);
u32 seq = ++bp->fw_seq;
u32 rc = 0;
u32 cnt = 1;
u8 delay = CHIP_REV_IS_SLOW(bp) ? 100 : 10;
mutex_lock(&bp->fw_mb_mutex);
- SHMEM_WR(bp, func_mb[func].drv_mb_header, (command | seq));
+ SHMEM_WR(bp, func_mb[mb_idx].drv_mb_param, param);
+ SHMEM_WR(bp, func_mb[mb_idx].drv_mb_header, (command | seq));
+
DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", (command | seq));
do {
/* let the FW do it's magic ... */
msleep(delay);
- rc = SHMEM_RD(bp, func_mb[func].fw_mb_header);
+ rc = SHMEM_RD(bp, func_mb[mb_idx].fw_mb_header);
/* Give the FW up to 5 second (500*10ms) */
} while ((seq != (rc & FW_MSG_SEQ_NUMBER_MASK)) && (cnt++ < 500));
@@ -1623,6 +2238,315 @@ u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
return rc;
}
+/* must be called under rtnl_lock */
+static void bnx2x_rxq_set_mac_filters(struct bnx2x *bp, u16 cl_id, u32 filters)
+{
+ u32 mask = (1 << cl_id);
+
+ /* initial seeting is BNX2X_ACCEPT_NONE */
+ u8 drop_all_ucast = 1, drop_all_bcast = 1, drop_all_mcast = 1;
+ u8 accp_all_ucast = 0, accp_all_bcast = 0, accp_all_mcast = 0;
+ u8 unmatched_unicast = 0;
+
+ if (filters & BNX2X_PROMISCUOUS_MODE) {
+ /* promiscious - accept all, drop none */
+ drop_all_ucast = drop_all_bcast = drop_all_mcast = 0;
+ accp_all_ucast = accp_all_bcast = accp_all_mcast = 1;
+ }
+ if (filters & BNX2X_ACCEPT_UNICAST) {
+ /* accept matched ucast */
+ drop_all_ucast = 0;
+ }
+ if (filters & BNX2X_ACCEPT_MULTICAST) {
+ /* accept matched mcast */
+ drop_all_mcast = 0;
+ }
+ if (filters & BNX2X_ACCEPT_ALL_UNICAST) {
+ /* accept all mcast */
+ drop_all_ucast = 0;
+ accp_all_ucast = 1;
+ }
+ if (filters & BNX2X_ACCEPT_ALL_MULTICAST) {
+ /* accept all mcast */
+ drop_all_mcast = 0;
+ accp_all_mcast = 1;
+ }
+ if (filters & BNX2X_ACCEPT_BROADCAST) {
+ /* accept (all) bcast */
+ drop_all_bcast = 0;
+ accp_all_bcast = 1;
+ }
+
+ bp->mac_filters.ucast_drop_all = drop_all_ucast ?
+ bp->mac_filters.ucast_drop_all | mask :
+ bp->mac_filters.ucast_drop_all & ~mask;
+
+ bp->mac_filters.mcast_drop_all = drop_all_mcast ?
+ bp->mac_filters.mcast_drop_all | mask :
+ bp->mac_filters.mcast_drop_all & ~mask;
+
+ bp->mac_filters.bcast_drop_all = drop_all_bcast ?
+ bp->mac_filters.bcast_drop_all | mask :
+ bp->mac_filters.bcast_drop_all & ~mask;
+
+ bp->mac_filters.ucast_accept_all = accp_all_ucast ?
+ bp->mac_filters.ucast_accept_all | mask :
+ bp->mac_filters.ucast_accept_all & ~mask;
+
+ bp->mac_filters.mcast_accept_all = accp_all_mcast ?
+ bp->mac_filters.mcast_accept_all | mask :
+ bp->mac_filters.mcast_accept_all & ~mask;
+
+ bp->mac_filters.bcast_accept_all = accp_all_bcast ?
+ bp->mac_filters.bcast_accept_all | mask :
+ bp->mac_filters.bcast_accept_all & ~mask;
+
+ bp->mac_filters.unmatched_unicast = unmatched_unicast ?
+ bp->mac_filters.unmatched_unicast | mask :
+ bp->mac_filters.unmatched_unicast & ~mask;
+}
+
+static void bnx2x_func_init(struct bnx2x *bp, struct bnx2x_func_init_params *p)
+{
+ struct tstorm_eth_function_common_config tcfg = {0};
+ u16 rss_flgs;
+
+ /* tpa */
+ if (p->func_flgs & FUNC_FLG_TPA)
+ tcfg.config_flags |=
+ TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA;
+
+ /* set rss flags */
+ rss_flgs = (p->rss->mode <<
+ TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_MODE_SHIFT);
+
+ if (p->rss->cap & RSS_IPV4_CAP)
+ rss_flgs |= RSS_IPV4_CAP_MASK;
+ if (p->rss->cap & RSS_IPV4_TCP_CAP)
+ rss_flgs |= RSS_IPV4_TCP_CAP_MASK;
+ if (p->rss->cap & RSS_IPV6_CAP)
+ rss_flgs |= RSS_IPV6_CAP_MASK;
+ if (p->rss->cap & RSS_IPV6_TCP_CAP)
+ rss_flgs |= RSS_IPV6_TCP_CAP_MASK;
+
+ tcfg.config_flags |= rss_flgs;
+ tcfg.rss_result_mask = p->rss->result_mask;
+
+ storm_memset_func_cfg(bp, &tcfg, p->func_id);
+
+ /* Enable the function in the FW */
+ storm_memset_vf_to_pf(bp, p->func_id, p->pf_id);
+ storm_memset_func_en(bp, p->func_id, 1);
+
+ /* statistics */
+ if (p->func_flgs & FUNC_FLG_STATS) {
+ struct stats_indication_flags stats_flags = {0};
+ stats_flags.collect_eth = 1;
+
+ storm_memset_xstats_flags(bp, &stats_flags, p->func_id);
+ storm_memset_xstats_addr(bp, p->fw_stat_map, p->func_id);
+
+ storm_memset_tstats_flags(bp, &stats_flags, p->func_id);
+ storm_memset_tstats_addr(bp, p->fw_stat_map, p->func_id);
+
+ storm_memset_ustats_flags(bp, &stats_flags, p->func_id);
+ storm_memset_ustats_addr(bp, p->fw_stat_map, p->func_id);
+
+ storm_memset_cstats_flags(bp, &stats_flags, p->func_id);
+ storm_memset_cstats_addr(bp, p->fw_stat_map, p->func_id);
+ }
+
+ /* spq */
+ if (p->func_flgs & FUNC_FLG_SPQ) {
+ storm_memset_spq_addr(bp, p->spq_map, p->func_id);
+ REG_WR(bp, XSEM_REG_FAST_MEMORY +
+ XSTORM_SPQ_PROD_OFFSET(p->func_id), p->spq_prod);
+ }
+}
+
+static inline u16 bnx2x_get_cl_flags(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp)
+{
+ u16 flags = 0;
+
+ /* calculate queue flags */
+ flags |= QUEUE_FLG_CACHE_ALIGN;
+ flags |= QUEUE_FLG_HC;
+ flags |= IS_MF(bp) ? QUEUE_FLG_OV : 0;
+
+ flags |= QUEUE_FLG_VLAN;
+ DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
+
+ if (!fp->disable_tpa)
+ flags |= QUEUE_FLG_TPA;
+
+ flags |= QUEUE_FLG_STATS;
+
+ return flags;
+}
+
+static void bnx2x_pf_rx_cl_prep(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp, struct rxq_pause_params *pause,
+ struct bnx2x_rxq_init_params *rxq_init)
+{
+ u16 max_sge = 0;
+ u16 sge_sz = 0;
+ u16 tpa_agg_size = 0;
+
+ /* calculate queue flags */
+ u16 flags = bnx2x_get_cl_flags(bp, fp);
+
+ if (!fp->disable_tpa) {
+ pause->sge_th_hi = 250;
+ pause->sge_th_lo = 150;
+ tpa_agg_size = min_t(u32,
+ (min_t(u32, 8, MAX_SKB_FRAGS) *
+ SGE_PAGE_SIZE * PAGES_PER_SGE), 0xffff);
+ max_sge = SGE_PAGE_ALIGN(bp->dev->mtu) >>
+ SGE_PAGE_SHIFT;
+ max_sge = ((max_sge + PAGES_PER_SGE - 1) &
+ (~(PAGES_PER_SGE-1))) >> PAGES_PER_SGE_SHIFT;
+ sge_sz = (u16)min_t(u32, SGE_PAGE_SIZE * PAGES_PER_SGE,
+ 0xffff);
+ }
+
+ /* 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->sge_th_hi = 0;
+ pause->sge_th_lo = 0;
+ pause->pri_map = 1;
+ }
+
+ /* rxq setup */
+ rxq_init->flags = flags;
+ rxq_init->cxt = &bp->context.vcxt[fp->cid].eth;
+ rxq_init->dscr_map = fp->rx_desc_mapping;
+ rxq_init->sge_map = fp->rx_sge_mapping;
+ rxq_init->rcq_map = fp->rx_comp_mapping;
+ rxq_init->rcq_np_map = fp->rx_comp_mapping + BCM_PAGE_SIZE;
+ rxq_init->mtu = bp->dev->mtu;
+ rxq_init->buf_sz = bp->rx_buf_size;
+ rxq_init->cl_qzone_id = fp->cl_qzone_id;
+ rxq_init->cl_id = fp->cl_id;
+ rxq_init->spcl_id = fp->cl_id;
+ rxq_init->stat_id = fp->cl_id;
+ rxq_init->tpa_agg_sz = tpa_agg_size;
+ rxq_init->sge_buf_sz = sge_sz;
+ rxq_init->max_sges_pkt = max_sge;
+ rxq_init->cache_line_log = BNX2X_RX_ALIGN_SHIFT;
+ rxq_init->fw_sb_id = fp->fw_sb_id;
+
+ rxq_init->sb_cq_index = U_SB_ETH_RX_CQ_INDEX;
+
+ rxq_init->cid = HW_CID(bp, fp->cid);
+
+ rxq_init->hc_rate = bp->rx_ticks ? (1000000 / bp->rx_ticks) : 0;
+}
+
+static void bnx2x_pf_tx_cl_prep(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp, struct bnx2x_txq_init_params *txq_init)
+{
+ u16 flags = bnx2x_get_cl_flags(bp, fp);
+
+ txq_init->flags = flags;
+ txq_init->cxt = &bp->context.vcxt[fp->cid].eth;
+ txq_init->dscr_map = fp->tx_desc_mapping;
+ txq_init->stat_id = fp->cl_id;
+ txq_init->cid = HW_CID(bp, fp->cid);
+ txq_init->sb_cq_index = C_SB_ETH_TX_CQ_INDEX;
+ txq_init->traffic_type = LLFC_TRAFFIC_TYPE_NW;
+ txq_init->fw_sb_id = fp->fw_sb_id;
+ txq_init->hc_rate = bp->tx_ticks ? (1000000 / bp->tx_ticks) : 0;
+}
+
+static void bnx2x_pf_init(struct bnx2x *bp)
+{
+ struct bnx2x_func_init_params func_init = {0};
+ struct bnx2x_rss_params rss = {0};
+ struct event_ring_data eq_data = { {0} };
+ u16 flags;
+
+ /* pf specific setups */
+ if (!CHIP_IS_E1(bp))
+ storm_memset_ov(bp, bp->mf_ov, BP_FUNC(bp));
+
+ if (CHIP_IS_E2(bp)) {
+ /* reset IGU PF statistics: MSIX + ATTN */
+ /* PF */
+ REG_WR(bp, IGU_REG_STATISTIC_NUM_MESSAGE_SENT +
+ BNX2X_IGU_STAS_MSG_VF_CNT*4 +
+ (CHIP_MODE_IS_4_PORT(bp) ?
+ BP_FUNC(bp) : BP_VN(bp))*4, 0);
+ /* ATTN */
+ REG_WR(bp, IGU_REG_STATISTIC_NUM_MESSAGE_SENT +
+ BNX2X_IGU_STAS_MSG_VF_CNT*4 +
+ BNX2X_IGU_STAS_MSG_PF_CNT*4 +
+ (CHIP_MODE_IS_4_PORT(bp) ?
+ BP_FUNC(bp) : BP_VN(bp))*4, 0);
+ }
+
+ /* function setup flags */
+ flags = (FUNC_FLG_STATS | FUNC_FLG_LEADING | FUNC_FLG_SPQ);
+
+ if (CHIP_IS_E1x(bp))
+ flags |= (bp->flags & TPA_ENABLE_FLAG) ? FUNC_FLG_TPA : 0;
+ else
+ flags |= FUNC_FLG_TPA;
+
+ /* function setup */
+
+ /**
+ * Although RSS is meaningless when there is a single HW queue we
+ * still need it enabled in order to have HW Rx hash generated.
+ */
+ rss.cap = (RSS_IPV4_CAP | RSS_IPV4_TCP_CAP |
+ RSS_IPV6_CAP | RSS_IPV6_TCP_CAP);
+ rss.mode = bp->multi_mode;
+ rss.result_mask = MULTI_MASK;
+ func_init.rss = &rss;
+
+ func_init.func_flgs = flags;
+ func_init.pf_id = BP_FUNC(bp);
+ func_init.func_id = BP_FUNC(bp);
+ func_init.fw_stat_map = bnx2x_sp_mapping(bp, fw_stats);
+ func_init.spq_map = bp->spq_mapping;
+ func_init.spq_prod = bp->spq_prod_idx;
+
+ bnx2x_func_init(bp, &func_init);
+
+ memset(&(bp->cmng), 0, sizeof(struct cmng_struct_per_port));
+
+ /*
+ Congestion management values depend on the link rate
+ There is no active link so initial link rate is set to 10 Gbps.
+ When the link comes up The congestion management values are
+ re-calculated according to the actual link rate.
+ */
+ bp->link_vars.line_speed = SPEED_10000;
+ bnx2x_cmng_fns_init(bp, true, bnx2x_get_cmng_fns_mode(bp));
+
+ /* Only the PMF sets the HW */
+ if (bp->port.pmf)
+ storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp));
+
+ /* no rx until link is up */
+ bp->rx_mode = BNX2X_RX_MODE_NONE;
+ bnx2x_set_storm_rx_mode(bp);
+
+ /* init Event Queue */
+ eq_data.base_addr.hi = U64_HI(bp->eq_mapping);
+ eq_data.base_addr.lo = U64_LO(bp->eq_mapping);
+ eq_data.producer = bp->eq_prod;
+ eq_data.index_id = HC_SP_INDEX_EQ_CONS;
+ eq_data.sb_id = DEF_SB_ID;
+ storm_memset_eq_data(bp, &eq_data, BP_FUNC(bp));
+}
+
+
static void bnx2x_e1h_disable(struct bnx2x *bp)
{
int port = BP_PORT(bp);
@@ -1649,40 +2573,6 @@ static void bnx2x_e1h_enable(struct bnx2x *bp)
*/
}
-static void bnx2x_update_min_max(struct bnx2x *bp)
-{
- int port = BP_PORT(bp);
- int vn, i;
-
- /* Init rate shaping and fairness contexts */
- bnx2x_init_port_minmax(bp);
-
- bnx2x_calc_vn_weight_sum(bp);
-
- for (vn = VN_0; vn < E1HVN_MAX; vn++)
- bnx2x_init_vn_minmax(bp, 2*vn + port);
-
- if (bp->port.pmf) {
- int func;
-
- /* Set the attention towards other drivers on the same port */
- for (vn = VN_0; vn < E1HVN_MAX; vn++) {
- if (vn == BP_E1HVN(bp))
- continue;
-
- func = ((vn << 1) | port);
- REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
- (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
- }
-
- /* Store it to internal memory */
- for (i = 0; i < sizeof(struct cmng_struct_per_port) / 4; i++)
- REG_WR(bp, BAR_XSTRORM_INTMEM +
- XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i*4,
- ((u32 *)(&bp->cmng))[i]);
- }
-}
-
static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
{
DP(BNX2X_MSG_MCP, "dcc_event 0x%x\n", dcc_event);
@@ -1694,7 +2584,7 @@ static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
* where the bp->flags can change so it is done without any
* locks
*/
- if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) {
+ if (bp->mf_config[BP_VN(bp)] & FUNC_MF_CFG_FUNC_DISABLED) {
DP(NETIF_MSG_IFDOWN, "mf_cfg function disabled\n");
bp->flags |= MF_FUNC_DIS;
@@ -1709,15 +2599,17 @@ static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
}
if (dcc_event & DRV_STATUS_DCC_BANDWIDTH_ALLOCATION) {
- bnx2x_update_min_max(bp);
+ bnx2x_cmng_fns_init(bp, true, CMNG_FNS_MINMAX);
+ bnx2x_link_sync_notify(bp);
+ storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp));
dcc_event &= ~DRV_STATUS_DCC_BANDWIDTH_ALLOCATION;
}
/* Report results to MCP */
if (dcc_event)
- bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_FAILURE);
+ bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_FAILURE, 0);
else
- bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_OK);
+ bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_OK, 0);
}
/* must be called under the spq lock */
@@ -1744,16 +2636,17 @@ static inline void bnx2x_sp_prod_update(struct bnx2x *bp)
/* Make sure that BD data is updated before writing the producer */
wmb();
- REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func),
- bp->spq_prod_idx);
+ REG_WR16(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func),
+ bp->spq_prod_idx);
mmiowb();
}
/* the slow path queue is odd since completions arrive on the fastpath ring */
int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
- u32 data_hi, u32 data_lo, int common)
+ u32 data_hi, u32 data_lo, int common)
{
struct eth_spe *spe;
+ u16 type;
#ifdef BNX2X_STOP_ON_ERROR
if (unlikely(bp->panic))
@@ -1762,7 +2655,7 @@ int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
spin_lock_bh(&bp->spq_lock);
- if (!bp->spq_left) {
+ if (!atomic_read(&bp->spq_left)) {
BNX2X_ERR("BUG! SPQ ring full!\n");
spin_unlock_bh(&bp->spq_lock);
bnx2x_panic();
@@ -1775,22 +2668,42 @@ int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
spe->hdr.conn_and_cmd_data =
cpu_to_le32((command << SPE_HDR_CMD_ID_SHIFT) |
HW_CID(bp, cid));
- spe->hdr.type = cpu_to_le16(ETH_CONNECTION_TYPE);
+
if (common)
- spe->hdr.type |=
- cpu_to_le16((1 << SPE_HDR_COMMON_RAMROD_SHIFT));
+ /* Common ramrods:
+ * FUNC_START, FUNC_STOP, CFC_DEL, STATS, SET_MAC
+ * TRAFFIC_STOP, TRAFFIC_START
+ */
+ type = (NONE_CONNECTION_TYPE << SPE_HDR_CONN_TYPE_SHIFT)
+ & SPE_HDR_CONN_TYPE;
+ else
+ /* ETH ramrods: SETUP, HALT */
+ type = (ETH_CONNECTION_TYPE << SPE_HDR_CONN_TYPE_SHIFT)
+ & SPE_HDR_CONN_TYPE;
+
+ type |= ((BP_FUNC(bp) << SPE_HDR_FUNCTION_ID_SHIFT) &
+ SPE_HDR_FUNCTION_ID);
+
+ spe->hdr.type = cpu_to_le16(type);
- spe->data.mac_config_addr.hi = cpu_to_le32(data_hi);
- spe->data.mac_config_addr.lo = cpu_to_le32(data_lo);
+ spe->data.update_data_addr.hi = cpu_to_le32(data_hi);
+ spe->data.update_data_addr.lo = cpu_to_le32(data_lo);
- bp->spq_left--;
+ /* stats ramrod has it's own slot on the spq */
+ if (command != RAMROD_CMD_ID_COMMON_STAT_QUERY)
+ /* It's ok if the actual decrement is issued towards the memory
+ * somewhere between the spin_lock and spin_unlock. Thus no
+ * more explict memory barrier is needed.
+ */
+ atomic_dec(&bp->spq_left);
DP(BNX2X_MSG_SP/*NETIF_MSG_TIMER*/,
- "SPQE[%x] (%x:%x) command %d hw_cid %x data (%x:%x) left %x\n",
+ "SPQE[%x] (%x:%x) command %d hw_cid %x data (%x:%x) "
+ "type(0x%x) left %x\n",
bp->spq_prod_idx, (u32)U64_HI(bp->spq_mapping),
(u32)(U64_LO(bp->spq_mapping) +
(void *)bp->spq_prod_bd - (void *)bp->spq), command,
- HW_CID(bp, cid), data_hi, data_lo, bp->spq_left);
+ HW_CID(bp, cid), data_hi, data_lo, type, atomic_read(&bp->spq_left));
bnx2x_sp_prod_update(bp);
spin_unlock_bh(&bp->spq_lock);
@@ -1827,32 +2740,27 @@ static void bnx2x_release_alr(struct bnx2x *bp)
REG_WR(bp, GRCBASE_MCP + 0x9c, 0);
}
+#define BNX2X_DEF_SB_ATT_IDX 0x0001
+#define BNX2X_DEF_SB_IDX 0x0002
+
static inline u16 bnx2x_update_dsb_idx(struct bnx2x *bp)
{
- struct host_def_status_block *def_sb = bp->def_status_blk;
+ struct host_sp_status_block *def_sb = bp->def_status_blk;
u16 rc = 0;
barrier(); /* status block is written to by the chip */
if (bp->def_att_idx != def_sb->atten_status_block.attn_bits_index) {
bp->def_att_idx = def_sb->atten_status_block.attn_bits_index;
- rc |= 1;
- }
- if (bp->def_c_idx != def_sb->c_def_status_block.status_block_index) {
- bp->def_c_idx = def_sb->c_def_status_block.status_block_index;
- rc |= 2;
+ rc |= BNX2X_DEF_SB_ATT_IDX;
}
- if (bp->def_u_idx != def_sb->u_def_status_block.status_block_index) {
- bp->def_u_idx = def_sb->u_def_status_block.status_block_index;
- rc |= 4;
- }
- if (bp->def_x_idx != def_sb->x_def_status_block.status_block_index) {
- bp->def_x_idx = def_sb->x_def_status_block.status_block_index;
- rc |= 8;
- }
- if (bp->def_t_idx != def_sb->t_def_status_block.status_block_index) {
- bp->def_t_idx = def_sb->t_def_status_block.status_block_index;
- rc |= 16;
+
+ if (bp->def_idx != def_sb->sp_sb.running_index) {
+ bp->def_idx = def_sb->sp_sb.running_index;
+ rc |= BNX2X_DEF_SB_IDX;
}
+
+ /* Do not reorder: indecies reading should complete before handling */
+ barrier();
return rc;
}
@@ -1863,14 +2771,13 @@ static inline u16 bnx2x_update_dsb_idx(struct bnx2x *bp)
static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
{
int port = BP_PORT(bp);
- u32 hc_addr = (HC_REG_COMMAND_REG + port*32 +
- COMMAND_REG_ATTN_BITS_SET);
u32 aeu_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
MISC_REG_AEU_MASK_ATTN_FUNC_0;
u32 nig_int_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 :
NIG_REG_MASK_INTERRUPT_PORT0;
u32 aeu_mask;
u32 nig_mask = 0;
+ u32 reg_addr;
if (bp->attn_state & asserted)
BNX2X_ERR("IGU ERROR\n");
@@ -1945,9 +2852,15 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
} /* if hardwired */
- DP(NETIF_MSG_HW, "about to mask 0x%08x at HC addr 0x%x\n",
- asserted, hc_addr);
- REG_WR(bp, hc_addr, asserted);
+ if (bp->common.int_block == INT_BLOCK_HC)
+ reg_addr = (HC_REG_COMMAND_REG + port*32 +
+ COMMAND_REG_ATTN_BITS_SET);
+ else
+ reg_addr = (BAR_IGU_INTMEM + IGU_CMD_ATTN_BIT_SET_UPPER*8);
+
+ DP(NETIF_MSG_HW, "about to mask 0x%08x at %s addr 0x%x\n", asserted,
+ (bp->common.int_block == INT_BLOCK_HC) ? "HC" : "IGU", reg_addr);
+ REG_WR(bp, reg_addr, asserted);
/* now set back the mask */
if (asserted & ATTN_NIG_FOR_FUNC) {
@@ -1959,12 +2872,16 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
static inline void bnx2x_fan_failure(struct bnx2x *bp)
{
int port = BP_PORT(bp);
-
+ u32 ext_phy_config;
/* mark the failure */
- bp->link_params.ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
- bp->link_params.ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
+ ext_phy_config =
+ SHMEM_RD(bp,
+ dev_info.port_hw_config[port].external_phy_config);
+
+ ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+ ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
SHMEM_WR(bp, dev_info.port_hw_config[port].external_phy_config,
- bp->link_params.ext_phy_config);
+ ext_phy_config);
/* log the failure */
netdev_err(bp->dev, "Fan Failure on Network Controller has caused"
@@ -1976,7 +2893,7 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
{
int port = BP_PORT(bp);
int reg_offset;
- u32 val, swap_val, swap_override;
+ u32 val;
reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
@@ -1990,30 +2907,7 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
BNX2X_ERR("SPIO5 hw attention\n");
/* Fan failure attention */
- switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
- /* Low power mode is controlled by GPIO 2 */
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
- MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
- /* The PHY reset is controlled by GPIO 1 */
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
- MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
- break;
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
- /* The PHY reset is controlled by GPIO 1 */
- /* fake the port number to cancel the swap done in
- set_gpio() */
- swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
- swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
- port = (swap_val && swap_override) ^ 1;
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
- MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
- break;
-
- default:
- break;
- }
+ bnx2x_hw_reset_phy(&bp->link_params);
bnx2x_fan_failure(bp);
}
@@ -2087,6 +2981,10 @@ static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn)
/* RQ_USDMDP_FIFO_OVERFLOW */
if (val & 0x18000)
BNX2X_ERR("FATAL error from PXP\n");
+ if (CHIP_IS_E2(bp)) {
+ val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_1);
+ BNX2X_ERR("PXP hw attention-1 0x%x\n", val);
+ }
}
if (attn & HW_INTERRUT_ASSERT_SET_2) {
@@ -2117,9 +3015,10 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
int func = BP_FUNC(bp);
REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0);
- bp->mf_config = SHMEM_RD(bp,
- mf_cfg.func_mf_config[func].config);
- val = SHMEM_RD(bp, func_mb[func].drv_status);
+ bp->mf_config[BP_VN(bp)] = MF_CFG_RD(bp,
+ func_mf_config[BP_ABS_FUNC(bp)].config);
+ val = SHMEM_RD(bp,
+ func_mb[BP_FW_MB_IDX(bp)].drv_status);
if (val & DRV_STATUS_DCC_EVENT_MASK)
bnx2x_dcc_event(bp,
(val & DRV_STATUS_DCC_EVENT_MASK));
@@ -2149,13 +3048,13 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
if (attn & EVEREST_LATCHED_ATTN_IN_USE_MASK) {
BNX2X_ERR("LATCHED attention 0x%08x (masked)\n", attn);
if (attn & BNX2X_GRC_TIMEOUT) {
- val = CHIP_IS_E1H(bp) ?
- REG_RD(bp, MISC_REG_GRC_TIMEOUT_ATTN) : 0;
+ val = CHIP_IS_E1(bp) ? 0 :
+ REG_RD(bp, MISC_REG_GRC_TIMEOUT_ATTN);
BNX2X_ERR("GRC time-out 0x%08x\n", val);
}
if (attn & BNX2X_GRC_RSV) {
- val = CHIP_IS_E1H(bp) ?
- REG_RD(bp, MISC_REG_GRC_RSV_ATTN) : 0;
+ val = CHIP_IS_E1(bp) ? 0 :
+ REG_RD(bp, MISC_REG_GRC_RSV_ATTN);
BNX2X_ERR("GRC reserved 0x%08x\n", val);
}
REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0x7ff);
@@ -2168,6 +3067,7 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
#define RESET_DONE_FLAG_MASK (~LOAD_COUNTER_MASK)
#define RESET_DONE_FLAG_SHIFT LOAD_COUNTER_BITS
#define CHIP_PARITY_SUPPORTED(bp) (CHIP_IS_E1(bp) || CHIP_IS_E1H(bp))
+
/*
* should be run under rtnl lock
*/
@@ -2460,6 +3360,74 @@ bool bnx2x_chk_parity_attn(struct bnx2x *bp)
attn.sig[3]);
}
+
+static inline void bnx2x_attn_int_deasserted4(struct bnx2x *bp, u32 attn)
+{
+ u32 val;
+ if (attn & AEU_INPUTS_ATTN_BITS_PGLUE_HW_INTERRUPT) {
+
+ val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS_CLR);
+ BNX2X_ERR("PGLUE hw attention 0x%x\n", val);
+ if (val & PGLUE_B_PGLUE_B_INT_STS_REG_ADDRESS_ERROR)
+ BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
+ "ADDRESS_ERROR\n");
+ if (val & PGLUE_B_PGLUE_B_INT_STS_REG_INCORRECT_RCV_BEHAVIOR)
+ BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
+ "INCORRECT_RCV_BEHAVIOR\n");
+ if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN)
+ BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
+ "WAS_ERROR_ATTN\n");
+ if (val & PGLUE_B_PGLUE_B_INT_STS_REG_VF_LENGTH_VIOLATION_ATTN)
+ BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
+ "VF_LENGTH_VIOLATION_ATTN\n");
+ if (val &
+ PGLUE_B_PGLUE_B_INT_STS_REG_VF_GRC_SPACE_VIOLATION_ATTN)
+ BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
+ "VF_GRC_SPACE_VIOLATION_ATTN\n");
+ if (val &
+ PGLUE_B_PGLUE_B_INT_STS_REG_VF_MSIX_BAR_VIOLATION_ATTN)
+ BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
+ "VF_MSIX_BAR_VIOLATION_ATTN\n");
+ if (val & PGLUE_B_PGLUE_B_INT_STS_REG_TCPL_ERROR_ATTN)
+ BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
+ "TCPL_ERROR_ATTN\n");
+ if (val & PGLUE_B_PGLUE_B_INT_STS_REG_TCPL_IN_TWO_RCBS_ATTN)
+ BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
+ "TCPL_IN_TWO_RCBS_ATTN\n");
+ if (val & PGLUE_B_PGLUE_B_INT_STS_REG_CSSNOOP_FIFO_OVERFLOW)
+ BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
+ "CSSNOOP_FIFO_OVERFLOW\n");
+ }
+ if (attn & AEU_INPUTS_ATTN_BITS_ATC_HW_INTERRUPT) {
+ val = REG_RD(bp, ATC_REG_ATC_INT_STS_CLR);
+ BNX2X_ERR("ATC hw attention 0x%x\n", val);
+ if (val & ATC_ATC_INT_STS_REG_ADDRESS_ERROR)
+ BNX2X_ERR("ATC_ATC_INT_STS_REG_ADDRESS_ERROR\n");
+ if (val & ATC_ATC_INT_STS_REG_ATC_TCPL_TO_NOT_PEND)
+ BNX2X_ERR("ATC_ATC_INT_STS_REG"
+ "_ATC_TCPL_TO_NOT_PEND\n");
+ if (val & ATC_ATC_INT_STS_REG_ATC_GPA_MULTIPLE_HITS)
+ BNX2X_ERR("ATC_ATC_INT_STS_REG_"
+ "ATC_GPA_MULTIPLE_HITS\n");
+ if (val & ATC_ATC_INT_STS_REG_ATC_RCPL_TO_EMPTY_CNT)
+ BNX2X_ERR("ATC_ATC_INT_STS_REG_"
+ "ATC_RCPL_TO_EMPTY_CNT\n");
+ if (val & ATC_ATC_INT_STS_REG_ATC_TCPL_ERROR)
+ BNX2X_ERR("ATC_ATC_INT_STS_REG_ATC_TCPL_ERROR\n");
+ if (val & ATC_ATC_INT_STS_REG_ATC_IREQ_LESS_THAN_STU)
+ BNX2X_ERR("ATC_ATC_INT_STS_REG_"
+ "ATC_IREQ_LESS_THAN_STU\n");
+ }
+
+ if (attn & (AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR |
+ AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR)) {
+ BNX2X_ERR("FATAL parity attention set4 0x%x\n",
+ (u32)(attn & (AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR |
+ AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR)));
+ }
+
+}
+
static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
{
struct attn_route attn, *group_mask;
@@ -2490,17 +3458,28 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
attn.sig[1] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + port*4);
attn.sig[2] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 + port*4);
attn.sig[3] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 + port*4);
- DP(NETIF_MSG_HW, "attn: %08x %08x %08x %08x\n",
- attn.sig[0], attn.sig[1], attn.sig[2], attn.sig[3]);
+ if (CHIP_IS_E2(bp))
+ attn.sig[4] =
+ REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_5_FUNC_0 + port*4);
+ else
+ attn.sig[4] = 0;
+
+ DP(NETIF_MSG_HW, "attn: %08x %08x %08x %08x %08x\n",
+ attn.sig[0], attn.sig[1], attn.sig[2], attn.sig[3], attn.sig[4]);
for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
if (deasserted & (1 << index)) {
group_mask = &bp->attn_group[index];
- DP(NETIF_MSG_HW, "group[%d]: %08x %08x %08x %08x\n",
- index, group_mask->sig[0], group_mask->sig[1],
- group_mask->sig[2], group_mask->sig[3]);
+ DP(NETIF_MSG_HW, "group[%d]: %08x %08x "
+ "%08x %08x %08x\n",
+ index,
+ group_mask->sig[0], group_mask->sig[1],
+ group_mask->sig[2], group_mask->sig[3],
+ group_mask->sig[4]);
+ bnx2x_attn_int_deasserted4(bp,
+ attn.sig[4] & group_mask->sig[4]);
bnx2x_attn_int_deasserted3(bp,
attn.sig[3] & group_mask->sig[3]);
bnx2x_attn_int_deasserted1(bp,
@@ -2514,11 +3493,15 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
bnx2x_release_alr(bp);
- reg_addr = (HC_REG_COMMAND_REG + port*32 + COMMAND_REG_ATTN_BITS_CLR);
+ if (bp->common.int_block == INT_BLOCK_HC)
+ reg_addr = (HC_REG_COMMAND_REG + port*32 +
+ COMMAND_REG_ATTN_BITS_CLR);
+ else
+ reg_addr = (BAR_IGU_INTMEM + IGU_CMD_ATTN_BIT_CLR_UPPER*8);
val = ~deasserted;
- DP(NETIF_MSG_HW, "about to mask 0x%08x at HC addr 0x%x\n",
- val, reg_addr);
+ DP(NETIF_MSG_HW, "about to mask 0x%08x at %s addr 0x%x\n", val,
+ (bp->common.int_block == INT_BLOCK_HC) ? "HC" : "IGU", reg_addr);
REG_WR(bp, reg_addr, val);
if (~bp->attn_state & deasserted)
@@ -2571,6 +3554,141 @@ static void bnx2x_attn_int(struct bnx2x *bp)
bnx2x_attn_int_deasserted(bp, deasserted);
}
+static inline void bnx2x_update_eq_prod(struct bnx2x *bp, u16 prod)
+{
+ /* No memory barriers */
+ storm_memset_eq_prod(bp, prod, BP_FUNC(bp));
+ mmiowb(); /* keep prod updates ordered */
+}
+
+#ifdef BCM_CNIC
+static int bnx2x_cnic_handle_cfc_del(struct bnx2x *bp, u32 cid,
+ union event_ring_elem *elem)
+{
+ if (!bp->cnic_eth_dev.starting_cid ||
+ cid < bp->cnic_eth_dev.starting_cid)
+ return 1;
+
+ DP(BNX2X_MSG_SP, "got delete ramrod for CNIC CID %d\n", cid);
+
+ if (unlikely(elem->message.data.cfc_del_event.error)) {
+ BNX2X_ERR("got delete ramrod for CNIC CID %d with error!\n",
+ cid);
+ bnx2x_panic_dump(bp);
+ }
+ bnx2x_cnic_cfc_comp(bp, cid);
+ return 0;
+}
+#endif
+
+static void bnx2x_eq_int(struct bnx2x *bp)
+{
+ u16 hw_cons, sw_cons, sw_prod;
+ union event_ring_elem *elem;
+ u32 cid;
+ u8 opcode;
+ int spqe_cnt = 0;
+
+ hw_cons = le16_to_cpu(*bp->eq_cons_sb);
+
+ /* The hw_cos range is 1-255, 257 - the sw_cons range is 0-254, 256.
+ * when we get the the next-page we nned to adjust so the loop
+ * condition below will be met. The next element is the size of a
+ * regular element and hence incrementing by 1
+ */
+ if ((hw_cons & EQ_DESC_MAX_PAGE) == EQ_DESC_MAX_PAGE)
+ hw_cons++;
+
+ /* This function may never run in parralel with itself for a
+ * specific bp, thus there is no need in "paired" read memory
+ * barrier here.
+ */
+ sw_cons = bp->eq_cons;
+ sw_prod = bp->eq_prod;
+
+ DP(BNX2X_MSG_SP, "EQ: hw_cons %u sw_cons %u bp->spq_left %u\n",
+ hw_cons, sw_cons, atomic_read(&bp->spq_left));
+
+ for (; sw_cons != hw_cons;
+ sw_prod = NEXT_EQ_IDX(sw_prod), sw_cons = NEXT_EQ_IDX(sw_cons)) {
+
+
+ elem = &bp->eq_ring[EQ_DESC(sw_cons)];
+
+ cid = SW_CID(elem->message.data.cfc_del_event.cid);
+ opcode = elem->message.opcode;
+
+
+ /* handle eq element */
+ switch (opcode) {
+ case EVENT_RING_OPCODE_STAT_QUERY:
+ DP(NETIF_MSG_TIMER, "got statistics comp event\n");
+ /* nothing to do with stats comp */
+ continue;
+
+ case EVENT_RING_OPCODE_CFC_DEL:
+ /* handle according to cid range */
+ /*
+ * we may want to verify here that the bp state is
+ * HALTING
+ */
+ DP(NETIF_MSG_IFDOWN,
+ "got delete ramrod for MULTI[%d]\n", cid);
+#ifdef BCM_CNIC
+ if (!bnx2x_cnic_handle_cfc_del(bp, cid, elem))
+ goto next_spqe;
+#endif
+ bnx2x_fp(bp, cid, state) =
+ BNX2X_FP_STATE_CLOSED;
+
+ goto next_spqe;
+ }
+
+ switch (opcode | bp->state) {
+ case (EVENT_RING_OPCODE_FUNCTION_START |
+ BNX2X_STATE_OPENING_WAIT4_PORT):
+ DP(NETIF_MSG_IFUP, "got setup ramrod\n");
+ bp->state = BNX2X_STATE_FUNC_STARTED;
+ break;
+
+ case (EVENT_RING_OPCODE_FUNCTION_STOP |
+ BNX2X_STATE_CLOSING_WAIT4_HALT):
+ DP(NETIF_MSG_IFDOWN, "got halt ramrod\n");
+ bp->state = BNX2X_STATE_CLOSING_WAIT4_UNLOAD;
+ break;
+
+ case (EVENT_RING_OPCODE_SET_MAC | BNX2X_STATE_OPEN):
+ case (EVENT_RING_OPCODE_SET_MAC | BNX2X_STATE_DIAG):
+ DP(NETIF_MSG_IFUP, "got set mac ramrod\n");
+ bp->set_mac_pending = 0;
+ break;
+
+ case (EVENT_RING_OPCODE_SET_MAC |
+ BNX2X_STATE_CLOSING_WAIT4_HALT):
+ DP(NETIF_MSG_IFDOWN, "got (un)set mac ramrod\n");
+ bp->set_mac_pending = 0;
+ break;
+ default:
+ /* unknown event log error and continue */
+ BNX2X_ERR("Unknown EQ event %d\n",
+ elem->message.opcode);
+ }
+next_spqe:
+ spqe_cnt++;
+ } /* for */
+
+ smp_mb__before_atomic_inc();
+ atomic_add(spqe_cnt, &bp->spq_left);
+
+ bp->eq_cons = sw_cons;
+ bp->eq_prod = sw_prod;
+ /* Make sure that above mem writes were issued towards the memory */
+ smp_wmb();
+
+ /* update producer */
+ bnx2x_update_eq_prod(bp, bp->eq_prod);
+}
+
static void bnx2x_sp_task(struct work_struct *work)
{
struct bnx2x *bp = container_of(work, struct bnx2x, sp_task.work);
@@ -2589,31 +3707,29 @@ static void bnx2x_sp_task(struct work_struct *work)
DP(NETIF_MSG_INTR, "got a slowpath interrupt (status 0x%x)\n", status);
/* HW attentions */
- if (status & 0x1) {
+ if (status & BNX2X_DEF_SB_ATT_IDX) {
bnx2x_attn_int(bp);
- status &= ~0x1;
+ status &= ~BNX2X_DEF_SB_ATT_IDX;
}
- /* CStorm events: STAT_QUERY */
- if (status & 0x2) {
- DP(BNX2X_MSG_SP, "CStorm events: STAT_QUERY\n");
- status &= ~0x2;
+ /* SP events: STAT_QUERY and others */
+ if (status & BNX2X_DEF_SB_IDX) {
+
+ /* Handle EQ completions */
+ bnx2x_eq_int(bp);
+
+ bnx2x_ack_sb(bp, bp->igu_dsb_id, USTORM_ID,
+ le16_to_cpu(bp->def_idx), IGU_INT_NOP, 1);
+
+ status &= ~BNX2X_DEF_SB_IDX;
}
if (unlikely(status))
DP(NETIF_MSG_INTR, "got an unknown interrupt! (status 0x%x)\n",
status);
- bnx2x_ack_sb(bp, DEF_SB_ID, ATTENTION_ID, le16_to_cpu(bp->def_att_idx),
- IGU_INT_NOP, 1);
- bnx2x_ack_sb(bp, DEF_SB_ID, USTORM_ID, le16_to_cpu(bp->def_u_idx),
- IGU_INT_NOP, 1);
- bnx2x_ack_sb(bp, DEF_SB_ID, CSTORM_ID, le16_to_cpu(bp->def_c_idx),
- IGU_INT_NOP, 1);
- bnx2x_ack_sb(bp, DEF_SB_ID, XSTORM_ID, le16_to_cpu(bp->def_x_idx),
- IGU_INT_NOP, 1);
- bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, le16_to_cpu(bp->def_t_idx),
- IGU_INT_ENABLE, 1);
+ bnx2x_ack_sb(bp, bp->igu_dsb_id, ATTENTION_ID,
+ le16_to_cpu(bp->def_att_idx), IGU_INT_ENABLE, 1);
}
irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
@@ -2627,7 +3743,8 @@ irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
return IRQ_HANDLED;
}
- bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, 0, IGU_INT_DISABLE, 0);
+ bnx2x_ack_sb(bp, bp->igu_dsb_id, USTORM_ID, 0,
+ IGU_INT_DISABLE, 0);
#ifdef BNX2X_STOP_ON_ERROR
if (unlikely(bp->panic))
@@ -2671,7 +3788,7 @@ static void bnx2x_timer(unsigned long data)
}
if (!BP_NOMCP(bp)) {
- int func = BP_FUNC(bp);
+ int mb_idx = BP_FW_MB_IDX(bp);
u32 drv_pulse;
u32 mcp_pulse;
@@ -2679,9 +3796,9 @@ static void bnx2x_timer(unsigned long data)
bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK;
/* TBD - add SYSTEM_TIME */
drv_pulse = bp->fw_drv_pulse_wr_seq;
- SHMEM_WR(bp, func_mb[func].drv_pulse_mb, drv_pulse);
+ SHMEM_WR(bp, func_mb[mb_idx].drv_pulse_mb, drv_pulse);
- mcp_pulse = (SHMEM_RD(bp, func_mb[func].mcp_pulse_mb) &
+ mcp_pulse = (SHMEM_RD(bp, func_mb[mb_idx].mcp_pulse_mb) &
MCP_PULSE_SEQ_MASK);
/* The delta between driver pulse and mcp response
* should be 1 (before mcp response) or 0 (after mcp response)
@@ -2709,324 +3826,310 @@ timer_restart:
* nic init service functions
*/
-static void bnx2x_zero_sb(struct bnx2x *bp, int sb_id)
+static inline void bnx2x_fill(struct bnx2x *bp, u32 addr, int fill, u32 len)
{
- int port = BP_PORT(bp);
+ u32 i;
+ if (!(len%4) && !(addr%4))
+ for (i = 0; i < len; i += 4)
+ REG_WR(bp, addr + i, fill);
+ else
+ for (i = 0; i < len; i++)
+ REG_WR8(bp, addr + i, fill);
- /* "CSTORM" */
- bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
- CSTORM_SB_HOST_STATUS_BLOCK_U_OFFSET(port, sb_id), 0,
- CSTORM_SB_STATUS_BLOCK_U_SIZE / 4);
- bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
- CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id), 0,
- CSTORM_SB_STATUS_BLOCK_C_SIZE / 4);
}
-void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb,
- dma_addr_t mapping, int sb_id)
+/* helper: writes FP SP data to FW - data_size in dwords */
+static inline void bnx2x_wr_fp_sb_data(struct bnx2x *bp,
+ int fw_sb_id,
+ u32 *sb_data_p,
+ u32 data_size)
{
- int port = BP_PORT(bp);
- int func = BP_FUNC(bp);
int index;
- u64 section;
+ for (index = 0; index < data_size; index++)
+ REG_WR(bp, BAR_CSTRORM_INTMEM +
+ CSTORM_STATUS_BLOCK_DATA_OFFSET(fw_sb_id) +
+ sizeof(u32)*index,
+ *(sb_data_p + index));
+}
+
+static inline void bnx2x_zero_fp_sb(struct bnx2x *bp, int fw_sb_id)
+{
+ u32 *sb_data_p;
+ u32 data_size = 0;
+ struct hc_status_block_data_e2 sb_data_e2;
+ struct hc_status_block_data_e1x sb_data_e1x;
+
+ /* disable the function first */
+ if (CHIP_IS_E2(bp)) {
+ memset(&sb_data_e2, 0, sizeof(struct hc_status_block_data_e2));
+ sb_data_e2.common.p_func.pf_id = HC_FUNCTION_DISABLED;
+ sb_data_e2.common.p_func.vf_id = HC_FUNCTION_DISABLED;
+ sb_data_e2.common.p_func.vf_valid = false;
+ sb_data_p = (u32 *)&sb_data_e2;
+ data_size = sizeof(struct hc_status_block_data_e2)/sizeof(u32);
+ } else {
+ memset(&sb_data_e1x, 0,
+ sizeof(struct hc_status_block_data_e1x));
+ sb_data_e1x.common.p_func.pf_id = HC_FUNCTION_DISABLED;
+ sb_data_e1x.common.p_func.vf_id = HC_FUNCTION_DISABLED;
+ sb_data_e1x.common.p_func.vf_valid = false;
+ sb_data_p = (u32 *)&sb_data_e1x;
+ data_size = sizeof(struct hc_status_block_data_e1x)/sizeof(u32);
+ }
+ bnx2x_wr_fp_sb_data(bp, fw_sb_id, sb_data_p, data_size);
- /* USTORM */
- section = ((u64)mapping) + offsetof(struct host_status_block,
- u_status_block);
- sb->u_status_block.status_block_id = sb_id;
-
- REG_WR(bp, BAR_CSTRORM_INTMEM +
- CSTORM_SB_HOST_SB_ADDR_U_OFFSET(port, sb_id), U64_LO(section));
- REG_WR(bp, BAR_CSTRORM_INTMEM +
- ((CSTORM_SB_HOST_SB_ADDR_U_OFFSET(port, sb_id)) + 4),
- U64_HI(section));
- REG_WR8(bp, BAR_CSTRORM_INTMEM + FP_USB_FUNC_OFF +
- CSTORM_SB_HOST_STATUS_BLOCK_U_OFFSET(port, sb_id), func);
-
- for (index = 0; index < HC_USTORM_SB_NUM_INDICES; index++)
- REG_WR16(bp, BAR_CSTRORM_INTMEM +
- CSTORM_SB_HC_DISABLE_U_OFFSET(port, sb_id, index), 1);
+ bnx2x_fill(bp, BAR_CSTRORM_INTMEM +
+ CSTORM_STATUS_BLOCK_OFFSET(fw_sb_id), 0,
+ CSTORM_STATUS_BLOCK_SIZE);
+ bnx2x_fill(bp, BAR_CSTRORM_INTMEM +
+ CSTORM_SYNC_BLOCK_OFFSET(fw_sb_id), 0,
+ CSTORM_SYNC_BLOCK_SIZE);
+}
- /* CSTORM */
- section = ((u64)mapping) + offsetof(struct host_status_block,
- c_status_block);
- sb->c_status_block.status_block_id = sb_id;
+/* helper: writes SP SB data to FW */
+static inline void bnx2x_wr_sp_sb_data(struct bnx2x *bp,
+ struct hc_sp_status_block_data *sp_sb_data)
+{
+ int func = BP_FUNC(bp);
+ int i;
+ for (i = 0; i < sizeof(struct hc_sp_status_block_data)/sizeof(u32); i++)
+ REG_WR(bp, BAR_CSTRORM_INTMEM +
+ CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func) +
+ i*sizeof(u32),
+ *((u32 *)sp_sb_data + i));
+}
- REG_WR(bp, BAR_CSTRORM_INTMEM +
- CSTORM_SB_HOST_SB_ADDR_C_OFFSET(port, sb_id), U64_LO(section));
- REG_WR(bp, BAR_CSTRORM_INTMEM +
- ((CSTORM_SB_HOST_SB_ADDR_C_OFFSET(port, sb_id)) + 4),
- U64_HI(section));
- REG_WR8(bp, BAR_CSTRORM_INTMEM + FP_CSB_FUNC_OFF +
- CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id), func);
+static inline void bnx2x_zero_sp_sb(struct bnx2x *bp)
+{
+ int func = BP_FUNC(bp);
+ struct hc_sp_status_block_data sp_sb_data;
+ memset(&sp_sb_data, 0, sizeof(struct hc_sp_status_block_data));
+
+ sp_sb_data.p_func.pf_id = HC_FUNCTION_DISABLED;
+ sp_sb_data.p_func.vf_id = HC_FUNCTION_DISABLED;
+ sp_sb_data.p_func.vf_valid = false;
- for (index = 0; index < HC_CSTORM_SB_NUM_INDICES; index++)
- REG_WR16(bp, BAR_CSTRORM_INTMEM +
- CSTORM_SB_HC_DISABLE_C_OFFSET(port, sb_id, index), 1);
+ bnx2x_wr_sp_sb_data(bp, &sp_sb_data);
+
+ bnx2x_fill(bp, BAR_CSTRORM_INTMEM +
+ CSTORM_SP_STATUS_BLOCK_OFFSET(func), 0,
+ CSTORM_SP_STATUS_BLOCK_SIZE);
+ bnx2x_fill(bp, BAR_CSTRORM_INTMEM +
+ CSTORM_SP_SYNC_BLOCK_OFFSET(func), 0,
+ CSTORM_SP_SYNC_BLOCK_SIZE);
- bnx2x_ack_sb(bp, sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
}
-static void bnx2x_zero_def_sb(struct bnx2x *bp)
+
+static inline
+void bnx2x_setup_ndsb_state_machine(struct hc_status_block_sm *hc_sm,
+ int igu_sb_id, int igu_seg_id)
{
- int func = BP_FUNC(bp);
+ hc_sm->igu_sb_id = igu_sb_id;
+ hc_sm->igu_seg_id = igu_seg_id;
+ hc_sm->timer_value = 0xFF;
+ hc_sm->time_to_expire = 0xFFFFFFFF;
+}
+
+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)
+{
+ int igu_seg_id;
+
+ struct hc_status_block_data_e2 sb_data_e2;
+ struct hc_status_block_data_e1x sb_data_e1x;
+ struct hc_status_block_sm *hc_sm_p;
+ struct hc_index_data *hc_index_p;
+ int data_size;
+ u32 *sb_data_p;
+
+ if (CHIP_INT_MODE_IS_BC(bp))
+ igu_seg_id = HC_SEG_ACCESS_NORM;
+ else
+ igu_seg_id = IGU_SEG_ACCESS_NORM;
+
+ bnx2x_zero_fp_sb(bp, fw_sb_id);
+
+ if (CHIP_IS_E2(bp)) {
+ memset(&sb_data_e2, 0, sizeof(struct hc_status_block_data_e2));
+ sb_data_e2.common.p_func.pf_id = BP_FUNC(bp);
+ sb_data_e2.common.p_func.vf_id = vfid;
+ sb_data_e2.common.p_func.vf_valid = vf_valid;
+ sb_data_e2.common.p_func.vnic_id = BP_VN(bp);
+ sb_data_e2.common.same_igu_sb_1b = true;
+ sb_data_e2.common.host_sb_addr.hi = U64_HI(mapping);
+ sb_data_e2.common.host_sb_addr.lo = U64_LO(mapping);
+ hc_sm_p = sb_data_e2.common.state_machine;
+ hc_index_p = sb_data_e2.index_data;
+ sb_data_p = (u32 *)&sb_data_e2;
+ data_size = sizeof(struct hc_status_block_data_e2)/sizeof(u32);
+ } else {
+ memset(&sb_data_e1x, 0,
+ sizeof(struct hc_status_block_data_e1x));
+ sb_data_e1x.common.p_func.pf_id = BP_FUNC(bp);
+ sb_data_e1x.common.p_func.vf_id = 0xff;
+ sb_data_e1x.common.p_func.vf_valid = false;
+ sb_data_e1x.common.p_func.vnic_id = BP_VN(bp);
+ sb_data_e1x.common.same_igu_sb_1b = true;
+ sb_data_e1x.common.host_sb_addr.hi = U64_HI(mapping);
+ sb_data_e1x.common.host_sb_addr.lo = U64_LO(mapping);
+ hc_sm_p = sb_data_e1x.common.state_machine;
+ hc_index_p = sb_data_e1x.index_data;
+ sb_data_p = (u32 *)&sb_data_e1x;
+ data_size = sizeof(struct hc_status_block_data_e1x)/sizeof(u32);
+ }
+
+ bnx2x_setup_ndsb_state_machine(&hc_sm_p[SM_RX_ID],
+ igu_sb_id, igu_seg_id);
+ bnx2x_setup_ndsb_state_machine(&hc_sm_p[SM_TX_ID],
+ igu_sb_id, igu_seg_id);
+
+ DP(NETIF_MSG_HW, "Init FW SB %d\n", fw_sb_id);
+
+ /* write indecies to HW */
+ bnx2x_wr_fp_sb_data(bp, fw_sb_id, sb_data_p, data_size);
+}
+
+static void bnx2x_update_coalesce_sb_index(struct bnx2x *bp, u16 fw_sb_id,
+ u8 sb_index, u8 disable, u16 usec)
+{
+ int port = BP_PORT(bp);
+ u8 ticks = usec / BNX2X_BTR;
+
+ storm_memset_hc_timeout(bp, port, fw_sb_id, sb_index, ticks);
+
+ disable = disable ? 1 : (usec ? 0 : 1);
+ storm_memset_hc_disable(bp, port, fw_sb_id, sb_index, disable);
+}
- bnx2x_init_fill(bp, TSEM_REG_FAST_MEMORY +
- TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0,
- sizeof(struct tstorm_def_status_block)/4);
- bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
- CSTORM_DEF_SB_HOST_STATUS_BLOCK_U_OFFSET(func), 0,
- sizeof(struct cstorm_def_status_block_u)/4);
- bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
- CSTORM_DEF_SB_HOST_STATUS_BLOCK_C_OFFSET(func), 0,
- sizeof(struct cstorm_def_status_block_c)/4);
- bnx2x_init_fill(bp, XSEM_REG_FAST_MEMORY +
- XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0,
- sizeof(struct xstorm_def_status_block)/4);
+static void bnx2x_update_coalesce_sb(struct bnx2x *bp, u16 fw_sb_id,
+ u16 tx_usec, u16 rx_usec)
+{
+ bnx2x_update_coalesce_sb_index(bp, fw_sb_id, U_SB_ETH_RX_CQ_INDEX,
+ false, rx_usec);
+ bnx2x_update_coalesce_sb_index(bp, fw_sb_id, C_SB_ETH_TX_CQ_INDEX,
+ false, tx_usec);
}
-static void bnx2x_init_def_sb(struct bnx2x *bp,
- struct host_def_status_block *def_sb,
- dma_addr_t mapping, int sb_id)
+static void bnx2x_init_def_sb(struct bnx2x *bp)
{
+ struct host_sp_status_block *def_sb = bp->def_status_blk;
+ dma_addr_t mapping = bp->def_status_blk_mapping;
+ int igu_sp_sb_index;
+ int igu_seg_id;
int port = BP_PORT(bp);
int func = BP_FUNC(bp);
- int index, val, reg_offset;
+ int reg_offset;
u64 section;
+ int index;
+ struct hc_sp_status_block_data sp_sb_data;
+ memset(&sp_sb_data, 0, sizeof(struct hc_sp_status_block_data));
+
+ if (CHIP_INT_MODE_IS_BC(bp)) {
+ igu_sp_sb_index = DEF_SB_IGU_ID;
+ igu_seg_id = HC_SEG_ACCESS_DEF;
+ } else {
+ igu_sp_sb_index = bp->igu_dsb_id;
+ igu_seg_id = IGU_SEG_ACCESS_DEF;
+ }
/* ATTN */
- section = ((u64)mapping) + offsetof(struct host_def_status_block,
+ section = ((u64)mapping) + offsetof(struct host_sp_status_block,
atten_status_block);
- def_sb->atten_status_block.status_block_id = sb_id;
+ def_sb->atten_status_block.status_block_id = igu_sp_sb_index;
bp->attn_state = 0;
reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
-
for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
- bp->attn_group[index].sig[0] = REG_RD(bp,
- reg_offset + 0x10*index);
- bp->attn_group[index].sig[1] = REG_RD(bp,
- reg_offset + 0x4 + 0x10*index);
- bp->attn_group[index].sig[2] = REG_RD(bp,
- reg_offset + 0x8 + 0x10*index);
- bp->attn_group[index].sig[3] = REG_RD(bp,
- reg_offset + 0xc + 0x10*index);
+ int sindex;
+ /* take care of sig[0]..sig[4] */
+ for (sindex = 0; sindex < 4; sindex++)
+ bp->attn_group[index].sig[sindex] =
+ REG_RD(bp, reg_offset + sindex*0x4 + 0x10*index);
+
+ if (CHIP_IS_E2(bp))
+ /*
+ * enable5 is separate from the rest of the registers,
+ * and therefore the address skip is 4
+ * and not 16 between the different groups
+ */
+ bp->attn_group[index].sig[4] = REG_RD(bp,
+ reg_offset + 0x10 + 0x4*index);
+ else
+ bp->attn_group[index].sig[4] = 0;
}
- reg_offset = (port ? HC_REG_ATTN_MSG1_ADDR_L :
- HC_REG_ATTN_MSG0_ADDR_L);
+ if (bp->common.int_block == INT_BLOCK_HC) {
+ reg_offset = (port ? HC_REG_ATTN_MSG1_ADDR_L :
+ HC_REG_ATTN_MSG0_ADDR_L);
- REG_WR(bp, reg_offset, U64_LO(section));
- REG_WR(bp, reg_offset + 4, U64_HI(section));
-
- reg_offset = (port ? HC_REG_ATTN_NUM_P1 : HC_REG_ATTN_NUM_P0);
-
- val = REG_RD(bp, reg_offset);
- val |= sb_id;
- REG_WR(bp, reg_offset, val);
+ REG_WR(bp, reg_offset, U64_LO(section));
+ REG_WR(bp, reg_offset + 4, U64_HI(section));
+ } else if (CHIP_IS_E2(bp)) {
+ REG_WR(bp, IGU_REG_ATTN_MSG_ADDR_L, U64_LO(section));
+ REG_WR(bp, IGU_REG_ATTN_MSG_ADDR_H, U64_HI(section));
+ }
- /* USTORM */
- section = ((u64)mapping) + offsetof(struct host_def_status_block,
- u_def_status_block);
- def_sb->u_def_status_block.status_block_id = sb_id;
-
- REG_WR(bp, BAR_CSTRORM_INTMEM +
- CSTORM_DEF_SB_HOST_SB_ADDR_U_OFFSET(func), U64_LO(section));
- REG_WR(bp, BAR_CSTRORM_INTMEM +
- ((CSTORM_DEF_SB_HOST_SB_ADDR_U_OFFSET(func)) + 4),
- U64_HI(section));
- REG_WR8(bp, BAR_CSTRORM_INTMEM + DEF_USB_FUNC_OFF +
- CSTORM_DEF_SB_HOST_STATUS_BLOCK_U_OFFSET(func), func);
-
- for (index = 0; index < HC_USTORM_DEF_SB_NUM_INDICES; index++)
- REG_WR16(bp, BAR_CSTRORM_INTMEM +
- CSTORM_DEF_SB_HC_DISABLE_U_OFFSET(func, index), 1);
+ section = ((u64)mapping) + offsetof(struct host_sp_status_block,
+ sp_sb);
- /* CSTORM */
- section = ((u64)mapping) + offsetof(struct host_def_status_block,
- c_def_status_block);
- def_sb->c_def_status_block.status_block_id = sb_id;
-
- REG_WR(bp, BAR_CSTRORM_INTMEM +
- CSTORM_DEF_SB_HOST_SB_ADDR_C_OFFSET(func), U64_LO(section));
- REG_WR(bp, BAR_CSTRORM_INTMEM +
- ((CSTORM_DEF_SB_HOST_SB_ADDR_C_OFFSET(func)) + 4),
- U64_HI(section));
- REG_WR8(bp, BAR_CSTRORM_INTMEM + DEF_CSB_FUNC_OFF +
- CSTORM_DEF_SB_HOST_STATUS_BLOCK_C_OFFSET(func), func);
-
- for (index = 0; index < HC_CSTORM_DEF_SB_NUM_INDICES; index++)
- REG_WR16(bp, BAR_CSTRORM_INTMEM +
- CSTORM_DEF_SB_HC_DISABLE_C_OFFSET(func, index), 1);
+ bnx2x_zero_sp_sb(bp);
- /* TSTORM */
- section = ((u64)mapping) + offsetof(struct host_def_status_block,
- t_def_status_block);
- def_sb->t_def_status_block.status_block_id = sb_id;
-
- REG_WR(bp, BAR_TSTRORM_INTMEM +
- TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section));
- REG_WR(bp, BAR_TSTRORM_INTMEM +
- ((TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4),
- U64_HI(section));
- REG_WR8(bp, BAR_TSTRORM_INTMEM + DEF_TSB_FUNC_OFF +
- TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func);
-
- for (index = 0; index < HC_TSTORM_DEF_SB_NUM_INDICES; index++)
- REG_WR16(bp, BAR_TSTRORM_INTMEM +
- TSTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1);
+ sp_sb_data.host_sb_addr.lo = U64_LO(section);
+ sp_sb_data.host_sb_addr.hi = U64_HI(section);
+ sp_sb_data.igu_sb_id = igu_sp_sb_index;
+ sp_sb_data.igu_seg_id = igu_seg_id;
+ sp_sb_data.p_func.pf_id = func;
+ sp_sb_data.p_func.vnic_id = BP_VN(bp);
+ sp_sb_data.p_func.vf_id = 0xff;
- /* XSTORM */
- section = ((u64)mapping) + offsetof(struct host_def_status_block,
- x_def_status_block);
- def_sb->x_def_status_block.status_block_id = sb_id;
-
- REG_WR(bp, BAR_XSTRORM_INTMEM +
- XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section));
- REG_WR(bp, BAR_XSTRORM_INTMEM +
- ((XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4),
- U64_HI(section));
- REG_WR8(bp, BAR_XSTRORM_INTMEM + DEF_XSB_FUNC_OFF +
- XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func);
-
- for (index = 0; index < HC_XSTORM_DEF_SB_NUM_INDICES; index++)
- REG_WR16(bp, BAR_XSTRORM_INTMEM +
- XSTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1);
+ bnx2x_wr_sp_sb_data(bp, &sp_sb_data);
bp->stats_pending = 0;
bp->set_mac_pending = 0;
- bnx2x_ack_sb(bp, sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
+ bnx2x_ack_sb(bp, bp->igu_dsb_id, USTORM_ID, 0, IGU_INT_ENABLE, 0);
}
void bnx2x_update_coalesce(struct bnx2x *bp)
{
- int port = BP_PORT(bp);
int i;
- for_each_queue(bp, i) {
- int sb_id = bp->fp[i].sb_id;
-
- /* HC_INDEX_U_ETH_RX_CQ_CONS */
- REG_WR8(bp, BAR_CSTRORM_INTMEM +
- CSTORM_SB_HC_TIMEOUT_U_OFFSET(port, sb_id,
- U_SB_ETH_RX_CQ_INDEX),
- bp->rx_ticks/(4 * BNX2X_BTR));
- REG_WR16(bp, BAR_CSTRORM_INTMEM +
- CSTORM_SB_HC_DISABLE_U_OFFSET(port, sb_id,
- U_SB_ETH_RX_CQ_INDEX),
- (bp->rx_ticks/(4 * BNX2X_BTR)) ? 0 : 1);
-
- /* HC_INDEX_C_ETH_TX_CQ_CONS */
- REG_WR8(bp, BAR_CSTRORM_INTMEM +
- CSTORM_SB_HC_TIMEOUT_C_OFFSET(port, sb_id,
- C_SB_ETH_TX_CQ_INDEX),
- bp->tx_ticks/(4 * BNX2X_BTR));
- REG_WR16(bp, BAR_CSTRORM_INTMEM +
- CSTORM_SB_HC_DISABLE_C_OFFSET(port, sb_id,
- C_SB_ETH_TX_CQ_INDEX),
- (bp->tx_ticks/(4 * BNX2X_BTR)) ? 0 : 1);
- }
+ for_each_queue(bp, i)
+ bnx2x_update_coalesce_sb(bp, bp->fp[i].fw_sb_id,
+ bp->rx_ticks, bp->tx_ticks);
}
static void bnx2x_init_sp_ring(struct bnx2x *bp)
{
- int func = BP_FUNC(bp);
-
spin_lock_init(&bp->spq_lock);
+ atomic_set(&bp->spq_left, MAX_SPQ_PENDING);
- bp->spq_left = MAX_SPQ_PENDING;
bp->spq_prod_idx = 0;
bp->dsb_sp_prod = BNX2X_SP_DSB_INDEX;
bp->spq_prod_bd = bp->spq;
bp->spq_last_bd = bp->spq_prod_bd + MAX_SP_DESC_CNT;
-
- REG_WR(bp, XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PAGE_BASE_OFFSET(func),
- U64_LO(bp->spq_mapping));
- REG_WR(bp,
- XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PAGE_BASE_OFFSET(func) + 4,
- U64_HI(bp->spq_mapping));
-
- REG_WR(bp, XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PROD_OFFSET(func),
- bp->spq_prod_idx);
}
-static void bnx2x_init_context(struct bnx2x *bp)
+static void bnx2x_init_eq_ring(struct bnx2x *bp)
{
int i;
+ for (i = 1; i <= NUM_EQ_PAGES; i++) {
+ union event_ring_elem *elem =
+ &bp->eq_ring[EQ_DESC_CNT_PAGE * i - 1];
- /* Rx */
- for_each_queue(bp, i) {
- struct eth_context *context = bnx2x_sp(bp, context[i].eth);
- struct bnx2x_fastpath *fp = &bp->fp[i];
- u8 cl_id = fp->cl_id;
-
- context->ustorm_st_context.common.sb_index_numbers =
- BNX2X_RX_SB_INDEX_NUM;
- context->ustorm_st_context.common.clientId = cl_id;
- context->ustorm_st_context.common.status_block_id = fp->sb_id;
- context->ustorm_st_context.common.flags =
- (USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT |
- USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS);
- context->ustorm_st_context.common.statistics_counter_id =
- cl_id;
- context->ustorm_st_context.common.mc_alignment_log_size =
- BNX2X_RX_ALIGN_SHIFT;
- context->ustorm_st_context.common.bd_buff_size =
- bp->rx_buf_size;
- context->ustorm_st_context.common.bd_page_base_hi =
- U64_HI(fp->rx_desc_mapping);
- context->ustorm_st_context.common.bd_page_base_lo =
- U64_LO(fp->rx_desc_mapping);
- if (!fp->disable_tpa) {
- context->ustorm_st_context.common.flags |=
- USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA;
- context->ustorm_st_context.common.sge_buff_size =
- (u16)min_t(u32, SGE_PAGE_SIZE*PAGES_PER_SGE,
- 0xffff);
- context->ustorm_st_context.common.sge_page_base_hi =
- U64_HI(fp->rx_sge_mapping);
- context->ustorm_st_context.common.sge_page_base_lo =
- U64_LO(fp->rx_sge_mapping);
-
- context->ustorm_st_context.common.max_sges_for_packet =
- SGE_PAGE_ALIGN(bp->dev->mtu) >> SGE_PAGE_SHIFT;
- context->ustorm_st_context.common.max_sges_for_packet =
- ((context->ustorm_st_context.common.
- max_sges_for_packet + PAGES_PER_SGE - 1) &
- (~(PAGES_PER_SGE - 1))) >> PAGES_PER_SGE_SHIFT;
- }
-
- context->ustorm_ag_context.cdu_usage =
- CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i),
- CDU_REGION_NUMBER_UCM_AG,
- ETH_CONNECTION_TYPE);
-
- context->xstorm_ag_context.cdu_reserved =
- CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i),
- CDU_REGION_NUMBER_XCM_AG,
- ETH_CONNECTION_TYPE);
- }
-
- /* Tx */
- for_each_queue(bp, i) {
- struct bnx2x_fastpath *fp = &bp->fp[i];
- struct eth_context *context =
- bnx2x_sp(bp, context[i].eth);
-
- context->cstorm_st_context.sb_index_number =
- C_SB_ETH_TX_CQ_INDEX;
- context->cstorm_st_context.status_block_id = fp->sb_id;
-
- context->xstorm_st_context.tx_bd_page_base_hi =
- U64_HI(fp->tx_desc_mapping);
- context->xstorm_st_context.tx_bd_page_base_lo =
- U64_LO(fp->tx_desc_mapping);
- context->xstorm_st_context.statistics_data = (fp->cl_id |
- XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE);
+ elem->next_page.addr.hi =
+ cpu_to_le32(U64_HI(bp->eq_mapping +
+ BCM_PAGE_SIZE * (i % NUM_EQ_PAGES)));
+ elem->next_page.addr.lo =
+ cpu_to_le32(U64_LO(bp->eq_mapping +
+ BCM_PAGE_SIZE*(i % NUM_EQ_PAGES)));
}
+ bp->eq_cons = 0;
+ bp->eq_prod = NUM_EQ_DESC;
+ bp->eq_cons_sb = BNX2X_EQ_INDEX;
}
static void bnx2x_init_ind_table(struct bnx2x *bp)
@@ -3045,47 +4148,11 @@ static void bnx2x_init_ind_table(struct bnx2x *bp)
bp->fp->cl_id + (i % bp->num_queues));
}
-void bnx2x_set_client_config(struct bnx2x *bp)
-{
- struct tstorm_eth_client_config tstorm_client = {0};
- int port = BP_PORT(bp);
- int i;
-
- tstorm_client.mtu = bp->dev->mtu;
- tstorm_client.config_flags =
- (TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE |
- TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE);
-#ifdef BCM_VLAN
- if (bp->rx_mode && bp->vlgrp && (bp->flags & HW_VLAN_RX_FLAG)) {
- tstorm_client.config_flags |=
- TSTORM_ETH_CLIENT_CONFIG_VLAN_REM_ENABLE;
- DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
- }
-#endif
-
- for_each_queue(bp, i) {
- tstorm_client.statistics_counter_id = bp->fp[i].cl_id;
-
- REG_WR(bp, BAR_TSTRORM_INTMEM +
- TSTORM_CLIENT_CONFIG_OFFSET(port, bp->fp[i].cl_id),
- ((u32 *)&tstorm_client)[0]);
- REG_WR(bp, BAR_TSTRORM_INTMEM +
- TSTORM_CLIENT_CONFIG_OFFSET(port, bp->fp[i].cl_id) + 4,
- ((u32 *)&tstorm_client)[1]);
- }
-
- DP(BNX2X_MSG_OFF, "tstorm_client: 0x%08x 0x%08x\n",
- ((u32 *)&tstorm_client)[0], ((u32 *)&tstorm_client)[1]);
-}
-
void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
{
- struct tstorm_eth_mac_filter_config tstorm_mac_filter = {0};
int mode = bp->rx_mode;
- int mask = bp->rx_mode_cl_mask;
- int func = BP_FUNC(bp);
- int port = BP_PORT(bp);
- int i;
+ u16 cl_id;
+
/* All but management unicast packets should pass to the host as well */
u32 llh_mask =
NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_BRCST |
@@ -3093,28 +4160,32 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN |
NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN;
- DP(NETIF_MSG_IFUP, "rx mode %d mask 0x%x\n", mode, mask);
-
switch (mode) {
case BNX2X_RX_MODE_NONE: /* no Rx */
- tstorm_mac_filter.ucast_drop_all = mask;
- tstorm_mac_filter.mcast_drop_all = mask;
- tstorm_mac_filter.bcast_drop_all = mask;
+ cl_id = BP_L_ID(bp);
+ bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_NONE);
break;
case BNX2X_RX_MODE_NORMAL:
- tstorm_mac_filter.bcast_accept_all = mask;
+ cl_id = BP_L_ID(bp);
+ bnx2x_rxq_set_mac_filters(bp, cl_id,
+ BNX2X_ACCEPT_UNICAST |
+ BNX2X_ACCEPT_BROADCAST |
+ BNX2X_ACCEPT_MULTICAST);
break;
case BNX2X_RX_MODE_ALLMULTI:
- tstorm_mac_filter.mcast_accept_all = mask;
- tstorm_mac_filter.bcast_accept_all = mask;
+ cl_id = BP_L_ID(bp);
+ bnx2x_rxq_set_mac_filters(bp, cl_id,
+ BNX2X_ACCEPT_UNICAST |
+ BNX2X_ACCEPT_BROADCAST |
+ BNX2X_ACCEPT_ALL_MULTICAST);
break;
case BNX2X_RX_MODE_PROMISC:
- tstorm_mac_filter.ucast_accept_all = mask;
- tstorm_mac_filter.mcast_accept_all = mask;
- tstorm_mac_filter.bcast_accept_all = mask;
+ cl_id = BP_L_ID(bp);
+ bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_PROMISCUOUS_MODE);
+
/* pass management unicast packets as well */
llh_mask |= NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST;
break;
@@ -3125,262 +4196,64 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
}
REG_WR(bp,
- (port ? NIG_REG_LLH1_BRB1_DRV_MASK : NIG_REG_LLH0_BRB1_DRV_MASK),
+ BP_PORT(bp) ? NIG_REG_LLH1_BRB1_DRV_MASK :
+ NIG_REG_LLH0_BRB1_DRV_MASK,
llh_mask);
- for (i = 0; i < sizeof(struct tstorm_eth_mac_filter_config)/4; i++) {
- REG_WR(bp, BAR_TSTRORM_INTMEM +
- TSTORM_MAC_FILTER_CONFIG_OFFSET(func) + i * 4,
- ((u32 *)&tstorm_mac_filter)[i]);
+ DP(NETIF_MSG_IFUP, "rx mode %d\n"
+ "drop_ucast 0x%x\ndrop_mcast 0x%x\ndrop_bcast 0x%x\n"
+ "accp_ucast 0x%x\naccp_mcast 0x%x\naccp_bcast 0x%x\n", mode,
+ bp->mac_filters.ucast_drop_all,
+ bp->mac_filters.mcast_drop_all,
+ bp->mac_filters.bcast_drop_all,
+ bp->mac_filters.ucast_accept_all,
+ bp->mac_filters.mcast_accept_all,
+ bp->mac_filters.bcast_accept_all
+ );
-/* DP(NETIF_MSG_IFUP, "tstorm_mac_filter[%d]: 0x%08x\n", i,
- ((u32 *)&tstorm_mac_filter)[i]); */
- }
-
- if (mode != BNX2X_RX_MODE_NONE)
- bnx2x_set_client_config(bp);
+ storm_memset_mac_filters(bp, &bp->mac_filters, BP_FUNC(bp));
}
static void bnx2x_init_internal_common(struct bnx2x *bp)
{
int i;
- /* Zero this manually as its initialization is
- currently missing in the initTool */
- for (i = 0; i < (USTORM_AGG_DATA_SIZE >> 2); i++)
- REG_WR(bp, BAR_USTRORM_INTMEM +
- USTORM_AGG_DATA_OFFSET + i * 4, 0);
-}
-
-static void bnx2x_init_internal_port(struct bnx2x *bp)
-{
- int port = BP_PORT(bp);
-
- REG_WR(bp,
- BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_U_OFFSET(port), BNX2X_BTR);
- REG_WR(bp,
- BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_C_OFFSET(port), BNX2X_BTR);
- REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_HC_BTR_OFFSET(port), BNX2X_BTR);
- REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_HC_BTR_OFFSET(port), BNX2X_BTR);
-}
-
-static void bnx2x_init_internal_func(struct bnx2x *bp)
-{
- struct tstorm_eth_function_common_config tstorm_config = {0};
- struct stats_indication_flags stats_flags = {0};
- int port = BP_PORT(bp);
- int func = BP_FUNC(bp);
- int i, j;
- u32 offset;
- u16 max_agg_size;
-
- tstorm_config.config_flags = RSS_FLAGS(bp);
-
- if (is_multi(bp))
- tstorm_config.rss_result_mask = MULTI_MASK;
-
- /* Enable TPA if needed */
- if (bp->flags & TPA_ENABLE_FLAG)
- tstorm_config.config_flags |=
- TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA;
-
- if (IS_E1HMF(bp))
- tstorm_config.config_flags |=
- TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM;
-
- tstorm_config.leading_client_id = BP_L_ID(bp);
-
- REG_WR(bp, BAR_TSTRORM_INTMEM +
- TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(func),
- (*(u32 *)&tstorm_config));
-
- bp->rx_mode = BNX2X_RX_MODE_NONE; /* no rx until link is up */
- bp->rx_mode_cl_mask = (1 << BP_L_ID(bp));
- bnx2x_set_storm_rx_mode(bp);
+ if (!CHIP_IS_E1(bp)) {
- for_each_queue(bp, i) {
- u8 cl_id = bp->fp[i].cl_id;
-
- /* reset xstorm per client statistics */
- offset = BAR_XSTRORM_INTMEM +
- XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cl_id);
- for (j = 0;
- j < sizeof(struct xstorm_per_client_stats) / 4; j++)
- REG_WR(bp, offset + j*4, 0);
-
- /* reset tstorm per client statistics */
- offset = BAR_TSTRORM_INTMEM +
- TSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cl_id);
- for (j = 0;
- j < sizeof(struct tstorm_per_client_stats) / 4; j++)
- REG_WR(bp, offset + j*4, 0);
-
- /* reset ustorm per client statistics */
- offset = BAR_USTRORM_INTMEM +
- USTORM_PER_COUNTER_ID_STATS_OFFSET(port, cl_id);
- for (j = 0;
- j < sizeof(struct ustorm_per_client_stats) / 4; j++)
- REG_WR(bp, offset + j*4, 0);
- }
-
- /* Init statistics related context */
- stats_flags.collect_eth = 1;
-
- REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(func),
- ((u32 *)&stats_flags)[0]);
- REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(func) + 4,
- ((u32 *)&stats_flags)[1]);
-
- REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(func),
- ((u32 *)&stats_flags)[0]);
- REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(func) + 4,
- ((u32 *)&stats_flags)[1]);
-
- REG_WR(bp, BAR_USTRORM_INTMEM + USTORM_STATS_FLAGS_OFFSET(func),
- ((u32 *)&stats_flags)[0]);
- REG_WR(bp, BAR_USTRORM_INTMEM + USTORM_STATS_FLAGS_OFFSET(func) + 4,
- ((u32 *)&stats_flags)[1]);
-
- REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(func),
- ((u32 *)&stats_flags)[0]);
- REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(func) + 4,
- ((u32 *)&stats_flags)[1]);
-
- REG_WR(bp, BAR_XSTRORM_INTMEM +
- XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func),
- U64_LO(bnx2x_sp_mapping(bp, fw_stats)));
- REG_WR(bp, BAR_XSTRORM_INTMEM +
- XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func) + 4,
- U64_HI(bnx2x_sp_mapping(bp, fw_stats)));
-
- REG_WR(bp, BAR_TSTRORM_INTMEM +
- TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func),
- U64_LO(bnx2x_sp_mapping(bp, fw_stats)));
- REG_WR(bp, BAR_TSTRORM_INTMEM +
- TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func) + 4,
- U64_HI(bnx2x_sp_mapping(bp, fw_stats)));
-
- REG_WR(bp, BAR_USTRORM_INTMEM +
- USTORM_ETH_STATS_QUERY_ADDR_OFFSET(func),
- U64_LO(bnx2x_sp_mapping(bp, fw_stats)));
- REG_WR(bp, BAR_USTRORM_INTMEM +
- USTORM_ETH_STATS_QUERY_ADDR_OFFSET(func) + 4,
- U64_HI(bnx2x_sp_mapping(bp, fw_stats)));
-
- if (CHIP_IS_E1H(bp)) {
+ /* xstorm needs to know whether to add ovlan to packets or not,
+ * in switch-independent we'll write 0 to here... */
REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_FUNCTION_MODE_OFFSET,
- IS_E1HMF(bp));
+ bp->mf_mode);
REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_FUNCTION_MODE_OFFSET,
- IS_E1HMF(bp));
+ bp->mf_mode);
REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_FUNCTION_MODE_OFFSET,
- IS_E1HMF(bp));
+ bp->mf_mode);
REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNCTION_MODE_OFFSET,
- IS_E1HMF(bp));
-
- REG_WR16(bp, BAR_XSTRORM_INTMEM + XSTORM_E1HOV_OFFSET(func),
- bp->e1hov);
+ bp->mf_mode);
}
- /* Init CQ ring mapping and aggregation size, the FW limit is 8 frags */
- max_agg_size = min_t(u32, (min_t(u32, 8, MAX_SKB_FRAGS) *
- SGE_PAGE_SIZE * PAGES_PER_SGE), 0xffff);
- for_each_queue(bp, i) {
- struct bnx2x_fastpath *fp = &bp->fp[i];
-
- REG_WR(bp, BAR_USTRORM_INTMEM +
- USTORM_CQE_PAGE_BASE_OFFSET(port, fp->cl_id),
- U64_LO(fp->rx_comp_mapping));
- REG_WR(bp, BAR_USTRORM_INTMEM +
- USTORM_CQE_PAGE_BASE_OFFSET(port, fp->cl_id) + 4,
- U64_HI(fp->rx_comp_mapping));
-
- /* Next page */
- REG_WR(bp, BAR_USTRORM_INTMEM +
- USTORM_CQE_PAGE_NEXT_OFFSET(port, fp->cl_id),
- U64_LO(fp->rx_comp_mapping + BCM_PAGE_SIZE));
+ /* Zero this manually as its initialization is
+ currently missing in the initTool */
+ for (i = 0; i < (USTORM_AGG_DATA_SIZE >> 2); i++)
REG_WR(bp, BAR_USTRORM_INTMEM +
- USTORM_CQE_PAGE_NEXT_OFFSET(port, fp->cl_id) + 4,
- U64_HI(fp->rx_comp_mapping + BCM_PAGE_SIZE));
-
- REG_WR16(bp, BAR_USTRORM_INTMEM +
- USTORM_MAX_AGG_SIZE_OFFSET(port, fp->cl_id),
- max_agg_size);
- }
-
- /* dropless flow control */
- if (CHIP_IS_E1H(bp)) {
- struct ustorm_eth_rx_pause_data_e1h rx_pause = {0};
-
- rx_pause.bd_thr_low = 250;
- rx_pause.cqe_thr_low = 250;
- rx_pause.cos = 1;
- rx_pause.sge_thr_low = 0;
- rx_pause.bd_thr_high = 350;
- rx_pause.cqe_thr_high = 350;
- rx_pause.sge_thr_high = 0;
-
- for_each_queue(bp, i) {
- struct bnx2x_fastpath *fp = &bp->fp[i];
-
- if (!fp->disable_tpa) {
- rx_pause.sge_thr_low = 150;
- rx_pause.sge_thr_high = 250;
- }
-
-
- offset = BAR_USTRORM_INTMEM +
- USTORM_ETH_RING_PAUSE_DATA_OFFSET(port,
- fp->cl_id);
- for (j = 0;
- j < sizeof(struct ustorm_eth_rx_pause_data_e1h)/4;
- j++)
- REG_WR(bp, offset + j*4,
- ((u32 *)&rx_pause)[j]);
- }
- }
-
- memset(&(bp->cmng), 0, sizeof(struct cmng_struct_per_port));
-
- /* Init rate shaping and fairness contexts */
- if (IS_E1HMF(bp)) {
- int vn;
-
- /* During init there is no active link
- Until link is up, set link rate to 10Gbps */
- bp->link_vars.line_speed = SPEED_10000;
- bnx2x_init_port_minmax(bp);
-
- if (!BP_NOMCP(bp))
- bp->mf_config =
- SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
- bnx2x_calc_vn_weight_sum(bp);
-
- for (vn = VN_0; vn < E1HVN_MAX; vn++)
- bnx2x_init_vn_minmax(bp, 2*vn + port);
-
- /* Enable rate shaping and fairness */
- bp->cmng.flags.cmng_enables |=
- CMNG_FLAGS_PER_PORT_RATE_SHAPING_VN;
-
- } else {
- /* rate shaping and fairness are disabled */
- DP(NETIF_MSG_IFUP,
- "single function mode minmax will be disabled\n");
+ USTORM_AGG_DATA_OFFSET + i * 4, 0);
+ if (CHIP_IS_E2(bp)) {
+ REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_IGU_MODE_OFFSET,
+ CHIP_INT_MODE_IS_BC(bp) ?
+ HC_IGU_BC_MODE : HC_IGU_NBC_MODE);
}
+}
-
- /* Store cmng structures to internal memory */
- if (bp->port.pmf)
- for (i = 0; i < sizeof(struct cmng_struct_per_port) / 4; i++)
- REG_WR(bp, BAR_XSTRORM_INTMEM +
- XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i * 4,
- ((u32 *)(&bp->cmng))[i]);
+static void bnx2x_init_internal_port(struct bnx2x *bp)
+{
+ /* port */
}
static void bnx2x_init_internal(struct bnx2x *bp, u32 load_code)
{
switch (load_code) {
case FW_MSG_CODE_DRV_LOAD_COMMON:
+ case FW_MSG_CODE_DRV_LOAD_COMMON_CHIP:
bnx2x_init_internal_common(bp);
/* no break */
@@ -3389,7 +4262,8 @@ static void bnx2x_init_internal(struct bnx2x *bp, u32 load_code)
/* no break */
case FW_MSG_CODE_DRV_LOAD_FUNCTION:
- bnx2x_init_internal_func(bp);
+ /* internal memory per function is
+ initialized inside bnx2x_pf_init */
break;
default:
@@ -3398,43 +4272,63 @@ static void bnx2x_init_internal(struct bnx2x *bp, u32 load_code)
}
}
+static void bnx2x_init_fp_sb(struct bnx2x *bp, int fp_idx)
+{
+ struct bnx2x_fastpath *fp = &bp->fp[fp_idx];
+
+ fp->state = BNX2X_FP_STATE_CLOSED;
+
+ fp->index = fp->cid = fp_idx;
+ fp->cl_id = BP_L_ID(bp) + fp_idx;
+ fp->fw_sb_id = bp->base_fw_ndsb + fp->cl_id + CNIC_CONTEXT_USE;
+ fp->igu_sb_id = bp->igu_base_sb + fp_idx + CNIC_CONTEXT_USE;
+ /* qZone id equals to FW (per path) client id */
+ fp->cl_qzone_id = fp->cl_id +
+ BP_PORT(bp)*(CHIP_IS_E2(bp) ? ETH_MAX_RX_CLIENTS_E2 :
+ ETH_MAX_RX_CLIENTS_E1H);
+ /* init shortcut */
+ fp->ustorm_rx_prods_offset = CHIP_IS_E2(bp) ?
+ USTORM_RX_PRODS_E2_OFFSET(fp->cl_qzone_id) :
+ USTORM_RX_PRODS_E1X_OFFSET(BP_PORT(bp), fp->cl_id);
+ /* Setup SB indicies */
+ fp->rx_cons_sb = BNX2X_RX_SB_INDEX;
+ fp->tx_cons_sb = BNX2X_TX_SB_INDEX;
+
+ DP(NETIF_MSG_IFUP, "queue[%d]: bnx2x_init_sb(%p,%p) "
+ "cl_id %d fw_sb %d igu_sb %d\n",
+ fp_idx, bp, fp->status_blk.e1x_sb, fp->cl_id, fp->fw_sb_id,
+ fp->igu_sb_id);
+ bnx2x_init_sb(bp, fp->status_blk_mapping, BNX2X_VF_ID_INVALID, false,
+ fp->fw_sb_id, fp->igu_sb_id);
+
+ bnx2x_update_fpsb_idx(fp);
+}
+
void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
{
int i;
- for_each_queue(bp, i) {
- struct bnx2x_fastpath *fp = &bp->fp[i];
-
- fp->bp = bp;
- fp->state = BNX2X_FP_STATE_CLOSED;
- fp->index = i;
- fp->cl_id = BP_L_ID(bp) + i;
+ for_each_queue(bp, i)
+ bnx2x_init_fp_sb(bp, i);
#ifdef BCM_CNIC
- fp->sb_id = fp->cl_id + 1;
-#else
- fp->sb_id = fp->cl_id;
+
+ bnx2x_init_sb(bp, bp->cnic_sb_mapping,
+ BNX2X_VF_ID_INVALID, false,
+ CNIC_SB_ID(bp), CNIC_IGU_SB_ID(bp));
+
#endif
- DP(NETIF_MSG_IFUP,
- "queue[%d]: bnx2x_init_sb(%p,%p) cl_id %d sb %d\n",
- i, bp, fp->status_blk, fp->cl_id, fp->sb_id);
- bnx2x_init_sb(bp, fp->status_blk, fp->status_blk_mapping,
- fp->sb_id);
- bnx2x_update_fpsb_idx(fp);
- }
/* ensure status block indices were read */
rmb();
-
- bnx2x_init_def_sb(bp, bp->def_status_blk, bp->def_status_blk_mapping,
- DEF_SB_ID);
+ bnx2x_init_def_sb(bp);
bnx2x_update_dsb_idx(bp);
- bnx2x_update_coalesce(bp);
bnx2x_init_rx_rings(bp);
- bnx2x_init_tx_ring(bp);
+ bnx2x_init_tx_rings(bp);
bnx2x_init_sp_ring(bp);
- bnx2x_init_context(bp);
+ bnx2x_init_eq_ring(bp);
bnx2x_init_internal(bp, load_code);
+ bnx2x_pf_init(bp);
bnx2x_init_ind_table(bp);
bnx2x_stats_init(bp);
@@ -3495,7 +4389,6 @@ gunzip_nomem1:
static void bnx2x_gunzip_end(struct bnx2x *bp)
{
kfree(bp->strm->workspace);
-
kfree(bp->strm);
bp->strm = NULL;
@@ -3593,8 +4486,6 @@ static int bnx2x_int_mem_test(struct bnx2x *bp)
else
factor = 1;
- DP(NETIF_MSG_HW, "start part1\n");
-
/* Disable inputs of parser neighbor blocks */
REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x0);
REG_WR(bp, TCM_REG_PRS_IFEN, 0x0);
@@ -3731,9 +4622,19 @@ static int bnx2x_int_mem_test(struct bnx2x *bp)
static void enable_blocks_attention(struct bnx2x *bp)
{
REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0);
- REG_WR(bp, PXP_REG_PXP_INT_MASK_1, 0);
+ if (CHIP_IS_E2(bp))
+ REG_WR(bp, PXP_REG_PXP_INT_MASK_1, 0x40);
+ else
+ REG_WR(bp, PXP_REG_PXP_INT_MASK_1, 0);
REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0);
REG_WR(bp, CFC_REG_CFC_INT_MASK, 0);
+ /*
+ * mask read length error interrupts in brb for parser
+ * (parsing unit and 'checksum and crc' unit)
+ * these errors are legal (PU reads fixed length and CAC can cause
+ * read length error on truncated packets)
+ */
+ REG_WR(bp, BRB1_REG_BRB1_INT_MASK, 0xFC00);
REG_WR(bp, QM_REG_QM_INT_MASK, 0);
REG_WR(bp, TM_REG_TM_INT_MASK, 0);
REG_WR(bp, XSDM_REG_XSDM_INT_MASK_0, 0);
@@ -3752,8 +4653,16 @@ static void enable_blocks_attention(struct bnx2x *bp)
REG_WR(bp, CCM_REG_CCM_INT_MASK, 0);
/* REG_WR(bp, CSEM_REG_CSEM_INT_MASK_0, 0); */
/* REG_WR(bp, CSEM_REG_CSEM_INT_MASK_1, 0); */
+
if (CHIP_REV_IS_FPGA(bp))
REG_WR(bp, PXP2_REG_PXP2_INT_MASK_0, 0x580000);
+ else if (CHIP_IS_E2(bp))
+ REG_WR(bp, PXP2_REG_PXP2_INT_MASK_0,
+ (PXP2_PXP2_INT_MASK_0_REG_PGL_CPL_OF
+ | PXP2_PXP2_INT_MASK_0_REG_PGL_CPL_AFT
+ | PXP2_PXP2_INT_MASK_0_REG_PGL_PCIE_ATTN
+ | PXP2_PXP2_INT_MASK_0_REG_PGL_READ_BLOCKED
+ | PXP2_PXP2_INT_MASK_0_REG_PGL_WRITE_BLOCKED));
else
REG_WR(bp, PXP2_REG_PXP2_INT_MASK_0, 0x480000);
REG_WR(bp, TSDM_REG_TSDM_INT_MASK_0, 0);
@@ -3771,42 +4680,41 @@ static const struct {
u32 addr;
u32 mask;
} bnx2x_parity_mask[] = {
- {PXP_REG_PXP_PRTY_MASK, 0xffffffff},
- {PXP2_REG_PXP2_PRTY_MASK_0, 0xffffffff},
- {PXP2_REG_PXP2_PRTY_MASK_1, 0xffffffff},
- {HC_REG_HC_PRTY_MASK, 0xffffffff},
- {MISC_REG_MISC_PRTY_MASK, 0xffffffff},
- {QM_REG_QM_PRTY_MASK, 0x0},
- {DORQ_REG_DORQ_PRTY_MASK, 0x0},
+ {PXP_REG_PXP_PRTY_MASK, 0x3ffffff},
+ {PXP2_REG_PXP2_PRTY_MASK_0, 0xffffffff},
+ {PXP2_REG_PXP2_PRTY_MASK_1, 0x7f},
+ {HC_REG_HC_PRTY_MASK, 0x7},
+ {MISC_REG_MISC_PRTY_MASK, 0x1},
+ {QM_REG_QM_PRTY_MASK, 0x0},
+ {DORQ_REG_DORQ_PRTY_MASK, 0x0},
{GRCBASE_UPB + PB_REG_PB_PRTY_MASK, 0x0},
{GRCBASE_XPB + PB_REG_PB_PRTY_MASK, 0x0},
- {SRC_REG_SRC_PRTY_MASK, 0x4}, /* bit 2 */
- {CDU_REG_CDU_PRTY_MASK, 0x0},
- {CFC_REG_CFC_PRTY_MASK, 0x0},
- {DBG_REG_DBG_PRTY_MASK, 0x0},
- {DMAE_REG_DMAE_PRTY_MASK, 0x0},
- {BRB1_REG_BRB1_PRTY_MASK, 0x0},
- {PRS_REG_PRS_PRTY_MASK, (1<<6)},/* bit 6 */
- {TSDM_REG_TSDM_PRTY_MASK, 0x18},/* bit 3,4 */
- {CSDM_REG_CSDM_PRTY_MASK, 0x8}, /* bit 3 */
- {USDM_REG_USDM_PRTY_MASK, 0x38},/* bit 3,4,5 */
- {XSDM_REG_XSDM_PRTY_MASK, 0x8}, /* bit 3 */
- {TSEM_REG_TSEM_PRTY_MASK_0, 0x0},
- {TSEM_REG_TSEM_PRTY_MASK_1, 0x0},
- {USEM_REG_USEM_PRTY_MASK_0, 0x0},
- {USEM_REG_USEM_PRTY_MASK_1, 0x0},
- {CSEM_REG_CSEM_PRTY_MASK_0, 0x0},
- {CSEM_REG_CSEM_PRTY_MASK_1, 0x0},
- {XSEM_REG_XSEM_PRTY_MASK_0, 0x0},
- {XSEM_REG_XSEM_PRTY_MASK_1, 0x0}
+ {SRC_REG_SRC_PRTY_MASK, 0x4}, /* bit 2 */
+ {CDU_REG_CDU_PRTY_MASK, 0x0},
+ {CFC_REG_CFC_PRTY_MASK, 0x0},
+ {DBG_REG_DBG_PRTY_MASK, 0x0},
+ {DMAE_REG_DMAE_PRTY_MASK, 0x0},
+ {BRB1_REG_BRB1_PRTY_MASK, 0x0},
+ {PRS_REG_PRS_PRTY_MASK, (1<<6)},/* bit 6 */
+ {TSDM_REG_TSDM_PRTY_MASK, 0x18}, /* bit 3,4 */
+ {CSDM_REG_CSDM_PRTY_MASK, 0x8}, /* bit 3 */
+ {USDM_REG_USDM_PRTY_MASK, 0x38}, /* bit 3,4,5 */
+ {XSDM_REG_XSDM_PRTY_MASK, 0x8}, /* bit 3 */
+ {TSEM_REG_TSEM_PRTY_MASK_0, 0x0},
+ {TSEM_REG_TSEM_PRTY_MASK_1, 0x0},
+ {USEM_REG_USEM_PRTY_MASK_0, 0x0},
+ {USEM_REG_USEM_PRTY_MASK_1, 0x0},
+ {CSEM_REG_CSEM_PRTY_MASK_0, 0x0},
+ {CSEM_REG_CSEM_PRTY_MASK_1, 0x0},
+ {XSEM_REG_XSEM_PRTY_MASK_0, 0x0},
+ {XSEM_REG_XSEM_PRTY_MASK_1, 0x0}
};
static void enable_blocks_parity(struct bnx2x *bp)
{
- int i, mask_arr_len =
- sizeof(bnx2x_parity_mask)/(sizeof(bnx2x_parity_mask[0]));
+ int i;
- for (i = 0; i < mask_arr_len; i++)
+ for (i = 0; i < ARRAY_SIZE(bnx2x_parity_mask); i++)
REG_WR(bp, bnx2x_parity_mask[i].addr,
bnx2x_parity_mask[i].mask);
}
@@ -3862,17 +4770,12 @@ static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
*/
else if (val == SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE)
for (port = PORT_0; port < PORT_MAX; port++) {
- u32 phy_type =
- SHMEM_RD(bp, dev_info.port_hw_config[port].
- external_phy_config) &
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
is_required |=
- ((phy_type ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) ||
- (phy_type ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
- (phy_type ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481));
+ bnx2x_fan_failure_det_req(
+ bp,
+ bp->common.shmem_base,
+ bp->common.shmem2_base,
+ port);
}
DP(NETIF_MSG_HW, "fan detection setting: %d\n", is_required);
@@ -3896,26 +4799,97 @@ static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
}
-static int bnx2x_init_common(struct bnx2x *bp)
+static void bnx2x_pretend_func(struct bnx2x *bp, u8 pretend_func_num)
+{
+ u32 offset = 0;
+
+ if (CHIP_IS_E1(bp))
+ return;
+ if (CHIP_IS_E1H(bp) && (pretend_func_num >= E1H_FUNC_MAX))
+ return;
+
+ switch (BP_ABS_FUNC(bp)) {
+ case 0:
+ offset = PXP2_REG_PGL_PRETEND_FUNC_F0;
+ break;
+ case 1:
+ offset = PXP2_REG_PGL_PRETEND_FUNC_F1;
+ break;
+ case 2:
+ offset = PXP2_REG_PGL_PRETEND_FUNC_F2;
+ break;
+ case 3:
+ offset = PXP2_REG_PGL_PRETEND_FUNC_F3;
+ break;
+ case 4:
+ offset = PXP2_REG_PGL_PRETEND_FUNC_F4;
+ break;
+ case 5:
+ offset = PXP2_REG_PGL_PRETEND_FUNC_F5;
+ break;
+ case 6:
+ offset = PXP2_REG_PGL_PRETEND_FUNC_F6;
+ break;
+ case 7:
+ offset = PXP2_REG_PGL_PRETEND_FUNC_F7;
+ break;
+ default:
+ return;
+ }
+
+ REG_WR(bp, offset, pretend_func_num);
+ REG_RD(bp, offset);
+ DP(NETIF_MSG_HW, "Pretending to func %d\n", pretend_func_num);
+}
+
+static void bnx2x_pf_disable(struct bnx2x *bp)
+{
+ u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
+ val &= ~IGU_PF_CONF_FUNC_EN;
+
+ REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
+ REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, 0);
+ REG_WR(bp, CFC_REG_WEAK_ENABLE_PF, 0);
+}
+
+static int bnx2x_init_hw_common(struct bnx2x *bp, u32 load_code)
{
u32 val, i;
-#ifdef BCM_CNIC
- u32 wb_write[2];
-#endif
- DP(BNX2X_MSG_MCP, "starting common init func %d\n", BP_FUNC(bp));
+ DP(BNX2X_MSG_MCP, "starting common init func %d\n", BP_ABS_FUNC(bp));
bnx2x_reset_common(bp);
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0xffffffff);
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, 0xfffc);
bnx2x_init_block(bp, MISC_BLOCK, COMMON_STAGE);
- if (CHIP_IS_E1H(bp))
- REG_WR(bp, MISC_REG_E1HMF_MODE, IS_E1HMF(bp));
+ if (!CHIP_IS_E1(bp))
+ REG_WR(bp, MISC_REG_E1HMF_MODE, IS_MF(bp));
+
+ if (CHIP_IS_E2(bp)) {
+ u8 fid;
+
+ /**
+ * 4-port mode or 2-port mode we need to turn of master-enable
+ * for everyone, after that, turn it back on for self.
+ * so, we disregard multi-function or not, and always disable
+ * for all functions on the given path, this means 0,2,4,6 for
+ * path 0 and 1,3,5,7 for path 1
+ */
+ for (fid = BP_PATH(bp); fid < E2_FUNC_MAX*2; fid += 2) {
+ if (fid == BP_ABS_FUNC(bp)) {
+ REG_WR(bp,
+ PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER,
+ 1);
+ continue;
+ }
- REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x100);
- msleep(30);
- REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x0);
+ bnx2x_pretend_func(bp, fid);
+ /* clear pf enable */
+ bnx2x_pf_disable(bp);
+ bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+ }
+ }
bnx2x_init_block(bp, PXP_BLOCK, COMMON_STAGE);
if (CHIP_IS_E1(bp)) {
@@ -3943,12 +4917,7 @@ static int bnx2x_init_common(struct bnx2x *bp)
REG_WR(bp, PXP2_REG_RD_CDURD_SWAP_MODE, 1);
#endif
- REG_WR(bp, PXP2_REG_RQ_CDU_P_SIZE, 2);
-#ifdef BCM_CNIC
- REG_WR(bp, PXP2_REG_RQ_TM_P_SIZE, 5);
- REG_WR(bp, PXP2_REG_RQ_QM_P_SIZE, 5);
- REG_WR(bp, PXP2_REG_RQ_SRC_P_SIZE, 5);
-#endif
+ bnx2x_ilt_init_page_size(bp, INITOP_SET);
if (CHIP_REV_IS_FPGA(bp) && CHIP_IS_E1H(bp))
REG_WR(bp, PXP2_REG_PGL_TAGS_LIMIT, 0x1);
@@ -3967,9 +4936,65 @@ static int bnx2x_init_common(struct bnx2x *bp)
return -EBUSY;
}
+ /* Timers bug workaround E2 only. We need to set the entire ILT to
+ * have entries with value "0" and valid bit on.
+ * This needs to be done by the first PF that is loaded in a path
+ * (i.e. common phase)
+ */
+ if (CHIP_IS_E2(bp)) {
+ struct ilt_client_info ilt_cli;
+ struct bnx2x_ilt ilt;
+ memset(&ilt_cli, 0, sizeof(struct ilt_client_info));
+ memset(&ilt, 0, sizeof(struct bnx2x_ilt));
+
+ /* initalize dummy TM client */
+ ilt_cli.start = 0;
+ ilt_cli.end = ILT_NUM_PAGE_ENTRIES - 1;
+ ilt_cli.client_num = ILT_CLIENT_TM;
+
+ /* Step 1: set zeroes to all ilt page entries with valid bit on
+ * Step 2: set the timers first/last ilt entry to point
+ * to the entire range to prevent ILT range error for 3rd/4th
+ * vnic (this code assumes existance of the vnic)
+ *
+ * both steps performed by call to bnx2x_ilt_client_init_op()
+ * with dummy TM client
+ *
+ * we must use pretend since PXP2_REG_RQ_##blk##_FIRST_ILT
+ * and his brother are split registers
+ */
+ bnx2x_pretend_func(bp, (BP_PATH(bp) + 6));
+ bnx2x_ilt_client_init_op_ilt(bp, &ilt, &ilt_cli, INITOP_CLEAR);
+ bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+
+ REG_WR(bp, PXP2_REG_RQ_DRAM_ALIGN, BNX2X_PXP_DRAM_ALIGN);
+ REG_WR(bp, PXP2_REG_RQ_DRAM_ALIGN_RD, BNX2X_PXP_DRAM_ALIGN);
+ REG_WR(bp, PXP2_REG_RQ_DRAM_ALIGN_SEL, 1);
+ }
+
+
REG_WR(bp, PXP2_REG_RQ_DISABLE_INPUTS, 0);
REG_WR(bp, PXP2_REG_RD_DISABLE_INPUTS, 0);
+ if (CHIP_IS_E2(bp)) {
+ int factor = CHIP_REV_IS_EMUL(bp) ? 1000 :
+ (CHIP_REV_IS_FPGA(bp) ? 400 : 0);
+ bnx2x_init_block(bp, PGLUE_B_BLOCK, COMMON_STAGE);
+
+ bnx2x_init_block(bp, ATC_BLOCK, COMMON_STAGE);
+
+ /* let the HW do it's magic ... */
+ do {
+ msleep(200);
+ val = REG_RD(bp, ATC_REG_ATC_INIT_DONE);
+ } while (factor-- && (val != 1));
+
+ if (val != 1) {
+ BNX2X_ERR("ATC_INIT failed\n");
+ return -EBUSY;
+ }
+ }
+
bnx2x_init_block(bp, DMAE_BLOCK, COMMON_STAGE);
/* clean the DMAE memory */
@@ -3988,20 +5013,12 @@ static int bnx2x_init_common(struct bnx2x *bp)
bnx2x_init_block(bp, QM_BLOCK, COMMON_STAGE);
-#ifdef BCM_CNIC
- wb_write[0] = 0;
- wb_write[1] = 0;
- for (i = 0; i < 64; i++) {
- REG_WR(bp, QM_REG_BASEADDR + i*4, 1024 * 4 * (i%16));
- bnx2x_init_ind_wr(bp, QM_REG_PTRTBL + i*8, wb_write, 2);
+ if (CHIP_MODE_IS_4_PORT(bp))
+ bnx2x_init_block(bp, QM_4PORT_BLOCK, COMMON_STAGE);
+
+ /* QM queues pointers table */
+ bnx2x_qm_init_ptr_table(bp, bp->qm_cid_count, INITOP_SET);
- if (CHIP_IS_E1H(bp)) {
- REG_WR(bp, QM_REG_BASEADDR_EXT_A + i*4, 1024*4*(i%16));
- bnx2x_init_ind_wr(bp, QM_REG_PTRTBL_EXT_A + i*8,
- wb_write, 2);
- }
- }
-#endif
/* soft reset pulse */
REG_WR(bp, QM_REG_SOFT_RESET, 1);
REG_WR(bp, QM_REG_SOFT_RESET, 0);
@@ -4011,21 +5028,35 @@ static int bnx2x_init_common(struct bnx2x *bp)
#endif
bnx2x_init_block(bp, DQ_BLOCK, COMMON_STAGE);
- REG_WR(bp, DORQ_REG_DPM_CID_OFST, BCM_PAGE_SHIFT);
+ REG_WR(bp, DORQ_REG_DPM_CID_OFST, BNX2X_DB_SHIFT);
+
if (!CHIP_REV_IS_SLOW(bp)) {
/* enable hw interrupt from doorbell Q */
REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0);
}
bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE);
+ if (CHIP_MODE_IS_4_PORT(bp)) {
+ REG_WR(bp, BRB1_REG_FULL_LB_XOFF_THRESHOLD, 248);
+ REG_WR(bp, BRB1_REG_FULL_LB_XON_THRESHOLD, 328);
+ }
+
bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE);
REG_WR(bp, PRS_REG_A_PRSU_20, 0xf);
#ifndef BCM_CNIC
/* set NIC mode */
REG_WR(bp, PRS_REG_NIC_MODE, 1);
#endif
- if (CHIP_IS_E1H(bp))
- REG_WR(bp, PRS_REG_E1HOV_MODE, IS_E1HMF(bp));
+ if (!CHIP_IS_E1(bp))
+ REG_WR(bp, PRS_REG_E1HOV_MODE, IS_MF(bp));
+
+ if (CHIP_IS_E2(bp)) {
+ /* Bit-map indicating which L2 hdrs may appear after the
+ basic Ethernet header */
+ int has_ovlan = IS_MF(bp);
+ REG_WR(bp, PRS_REG_HDRS_AFTER_BASIC, (has_ovlan ? 7 : 6));
+ REG_WR(bp, PRS_REG_MUST_HAVE_HDRS, (has_ovlan ? 1 : 0));
+ }
bnx2x_init_block(bp, TSDM_BLOCK, COMMON_STAGE);
bnx2x_init_block(bp, CSDM_BLOCK, COMMON_STAGE);
@@ -4042,6 +5073,9 @@ static int bnx2x_init_common(struct bnx2x *bp)
bnx2x_init_block(bp, CSEM_BLOCK, COMMON_STAGE);
bnx2x_init_block(bp, XSEM_BLOCK, COMMON_STAGE);
+ if (CHIP_MODE_IS_4_PORT(bp))
+ bnx2x_init_block(bp, XSEM_4PORT_BLOCK, COMMON_STAGE);
+
/* sync semi rtc */
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
0x80000000);
@@ -4052,9 +5086,16 @@ static int bnx2x_init_common(struct bnx2x *bp)
bnx2x_init_block(bp, XPB_BLOCK, COMMON_STAGE);
bnx2x_init_block(bp, PBF_BLOCK, COMMON_STAGE);
+ if (CHIP_IS_E2(bp)) {
+ int has_ovlan = IS_MF(bp);
+ REG_WR(bp, PBF_REG_HDRS_AFTER_BASIC, (has_ovlan ? 7 : 6));
+ REG_WR(bp, PBF_REG_MUST_HAVE_HDRS, (has_ovlan ? 1 : 0));
+ }
+
REG_WR(bp, SRC_REG_SOFT_RST, 1);
for (i = SRC_REG_KEYRSS0_0; i <= SRC_REG_KEYRSS1_9; i += 4)
REG_WR(bp, i, random32());
+
bnx2x_init_block(bp, SRCH_BLOCK, COMMON_STAGE);
#ifdef BCM_CNIC
REG_WR(bp, SRC_REG_KEYSEARCH_0, 0x63285672);
@@ -4089,6 +5130,11 @@ static int bnx2x_init_common(struct bnx2x *bp)
REG_WR(bp, CFC_REG_DEBUG0, 0x20020000);
bnx2x_init_block(bp, HC_BLOCK, COMMON_STAGE);
+
+ if (CHIP_IS_E2(bp) && BP_NOMCP(bp))
+ REG_WR(bp, IGU_REG_RESET_MEMORIES, 0x36);
+
+ bnx2x_init_block(bp, IGU_BLOCK, COMMON_STAGE);
bnx2x_init_block(bp, MISC_AEU_BLOCK, COMMON_STAGE);
bnx2x_init_block(bp, PXPCS_BLOCK, COMMON_STAGE);
@@ -4096,15 +5142,34 @@ static int bnx2x_init_common(struct bnx2x *bp)
REG_WR(bp, 0x2814, 0xffffffff);
REG_WR(bp, 0x3820, 0xffffffff);
+ if (CHIP_IS_E2(bp)) {
+ REG_WR(bp, PCICFG_OFFSET + PXPCS_TL_CONTROL_5,
+ (PXPCS_TL_CONTROL_5_ERR_UNSPPORT1 |
+ PXPCS_TL_CONTROL_5_ERR_UNSPPORT));
+ REG_WR(bp, PCICFG_OFFSET + PXPCS_TL_FUNC345_STAT,
+ (PXPCS_TL_FUNC345_STAT_ERR_UNSPPORT4 |
+ PXPCS_TL_FUNC345_STAT_ERR_UNSPPORT3 |
+ PXPCS_TL_FUNC345_STAT_ERR_UNSPPORT2));
+ REG_WR(bp, PCICFG_OFFSET + PXPCS_TL_FUNC678_STAT,
+ (PXPCS_TL_FUNC678_STAT_ERR_UNSPPORT7 |
+ PXPCS_TL_FUNC678_STAT_ERR_UNSPPORT6 |
+ PXPCS_TL_FUNC678_STAT_ERR_UNSPPORT5));
+ }
+
bnx2x_init_block(bp, EMAC0_BLOCK, COMMON_STAGE);
bnx2x_init_block(bp, EMAC1_BLOCK, COMMON_STAGE);
bnx2x_init_block(bp, DBU_BLOCK, COMMON_STAGE);
bnx2x_init_block(bp, DBG_BLOCK, COMMON_STAGE);
bnx2x_init_block(bp, NIG_BLOCK, COMMON_STAGE);
- if (CHIP_IS_E1H(bp)) {
- REG_WR(bp, NIG_REG_LLH_MF_MODE, IS_E1HMF(bp));
- REG_WR(bp, NIG_REG_LLH_E1HOV_MODE, IS_E1HMF(bp));
+ if (!CHIP_IS_E1(bp)) {
+ REG_WR(bp, NIG_REG_LLH_MF_MODE, IS_MF(bp));
+ REG_WR(bp, NIG_REG_LLH_E1HOV_MODE, IS_MF(bp));
+ }
+ if (CHIP_IS_E2(bp)) {
+ /* Bit-map indicating which L2 hdrs may appear after the
+ basic Ethernet header */
+ REG_WR(bp, NIG_REG_P0_HDRS_AFTER_BASIC, (IS_MF(bp) ? 7 : 6));
}
if (CHIP_REV_IS_SLOW(bp))
@@ -4128,28 +5193,22 @@ static int bnx2x_init_common(struct bnx2x *bp)
}
REG_WR(bp, CFC_REG_DEBUG0, 0);
- /* read NIG statistic
- to see if this is our first up since powerup */
- bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2);
- val = *bnx2x_sp(bp, wb_data[0]);
+ if (CHIP_IS_E1(bp)) {
+ /* read NIG statistic
+ to see if this is our first up since powerup */
+ bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2);
+ val = *bnx2x_sp(bp, wb_data[0]);
- /* do internal memory self test */
- if ((CHIP_IS_E1(bp)) && (val == 0) && bnx2x_int_mem_test(bp)) {
- BNX2X_ERR("internal mem self test failed\n");
- return -EBUSY;
+ /* do internal memory self test */
+ if ((val == 0) && bnx2x_int_mem_test(bp)) {
+ BNX2X_ERR("internal mem self test failed\n");
+ return -EBUSY;
+ }
}
- switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
- bp->port.need_hw_lock = 1;
- break;
-
- default:
- break;
- }
+ bp->port.need_hw_lock = bnx2x_hw_lock_required(bp,
+ bp->common.shmem_base,
+ bp->common.shmem2_base);
bnx2x_setup_fan_failure_detection(bp);
@@ -4161,16 +5220,30 @@ static int bnx2x_init_common(struct bnx2x *bp)
enable_blocks_parity(bp);
if (!BP_NOMCP(bp)) {
- bnx2x_acquire_phy_lock(bp);
- bnx2x_common_init_phy(bp, bp->common.shmem_base);
- bnx2x_release_phy_lock(bp);
+ /* In E2 2-PORT mode, same ext phy is used for the two paths */
+ if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP) ||
+ CHIP_IS_E1x(bp)) {
+ u32 shmem_base[2], shmem2_base[2];
+ shmem_base[0] = bp->common.shmem_base;
+ shmem2_base[0] = bp->common.shmem2_base;
+ if (CHIP_IS_E2(bp)) {
+ shmem_base[1] =
+ SHMEM2_RD(bp, other_shmem_base_addr);
+ shmem2_base[1] =
+ SHMEM2_RD(bp, other_shmem2_base_addr);
+ }
+ bnx2x_acquire_phy_lock(bp);
+ bnx2x_common_init_phy(bp, shmem_base, shmem2_base,
+ bp->common.chip_id);
+ bnx2x_release_phy_lock(bp);
+ }
} else
BNX2X_ERR("Bootcode is missing - can not initialize link\n");
return 0;
}
-static int bnx2x_init_port(struct bnx2x *bp)
+static int bnx2x_init_hw_port(struct bnx2x *bp)
{
int port = BP_PORT(bp);
int init_stage = port ? PORT1_STAGE : PORT0_STAGE;
@@ -4184,14 +5257,23 @@ static int bnx2x_init_port(struct bnx2x *bp)
bnx2x_init_block(bp, PXP_BLOCK, init_stage);
bnx2x_init_block(bp, PXP2_BLOCK, init_stage);
+ /* Timers bug workaround: disables the pf_master bit in pglue at
+ * common phase, we need to enable it here before any dmae access are
+ * attempted. Therefore we manually added the enable-master to the
+ * port phase (it also happens in the function phase)
+ */
+ if (CHIP_IS_E2(bp))
+ REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, 1);
+
bnx2x_init_block(bp, TCM_BLOCK, init_stage);
bnx2x_init_block(bp, UCM_BLOCK, init_stage);
bnx2x_init_block(bp, CCM_BLOCK, init_stage);
bnx2x_init_block(bp, XCM_BLOCK, init_stage);
-#ifdef BCM_CNIC
- REG_WR(bp, QM_REG_CONNNUM_0 + port*4, 1024/16 - 1);
+ /* QM cid (connection) count */
+ bnx2x_qm_init_cid_count(bp, bp->qm_cid_count, INITOP_SET);
+#ifdef BCM_CNIC
bnx2x_init_block(bp, TIMERS_BLOCK, init_stage);
REG_WR(bp, TM_REG_LIN0_SCAN_TIME + port*4, 20);
REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + port*4, 31);
@@ -4199,29 +5281,41 @@ static int bnx2x_init_port(struct bnx2x *bp)
bnx2x_init_block(bp, DQ_BLOCK, init_stage);
- bnx2x_init_block(bp, BRB1_BLOCK, init_stage);
- if (CHIP_REV_IS_SLOW(bp) && !CHIP_IS_E1H(bp)) {
- /* no pause for emulation and FPGA */
- low = 0;
- high = 513;
- } else {
- if (IS_E1HMF(bp))
- low = ((bp->flags & ONE_PORT_FLAG) ? 160 : 246);
- else if (bp->dev->mtu > 4096) {
- if (bp->flags & ONE_PORT_FLAG)
- low = 160;
- else {
- val = bp->dev->mtu;
- /* (24*1024 + val*4)/256 */
- low = 96 + (val/64) + ((val % 64) ? 1 : 0);
- }
- } else
- low = ((bp->flags & ONE_PORT_FLAG) ? 80 : 160);
- high = low + 56; /* 14*1024/256 */
+ if (CHIP_MODE_IS_4_PORT(bp))
+ bnx2x_init_block(bp, QM_4PORT_BLOCK, init_stage);
+
+ if (CHIP_IS_E1(bp) || CHIP_IS_E1H(bp)) {
+ bnx2x_init_block(bp, BRB1_BLOCK, init_stage);
+ if (CHIP_REV_IS_SLOW(bp) && CHIP_IS_E1(bp)) {
+ /* no pause for emulation and FPGA */
+ low = 0;
+ high = 513;
+ } else {
+ if (IS_MF(bp))
+ low = ((bp->flags & ONE_PORT_FLAG) ? 160 : 246);
+ else if (bp->dev->mtu > 4096) {
+ if (bp->flags & ONE_PORT_FLAG)
+ low = 160;
+ else {
+ val = bp->dev->mtu;
+ /* (24*1024 + val*4)/256 */
+ low = 96 + (val/64) +
+ ((val % 64) ? 1 : 0);
+ }
+ } else
+ low = ((bp->flags & ONE_PORT_FLAG) ? 80 : 160);
+ high = low + 56; /* 14*1024/256 */
+ }
+ REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_0 + port*4, low);
+ REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_0 + port*4, high);
}
- REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_0 + port*4, low);
- REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_0 + port*4, high);
+ if (CHIP_MODE_IS_4_PORT(bp)) {
+ REG_WR(bp, BRB1_REG_PAUSE_0_XOFF_THRESHOLD_0 + port*8, 248);
+ REG_WR(bp, BRB1_REG_PAUSE_0_XON_THRESHOLD_0 + port*8, 328);
+ REG_WR(bp, (BP_PORT(bp) ? BRB1_REG_MAC_GUARANTIED_1 :
+ BRB1_REG_MAC_GUARANTIED_0), 40);
+ }
bnx2x_init_block(bp, PRS_BLOCK, init_stage);
@@ -4234,24 +5328,28 @@ static int bnx2x_init_port(struct bnx2x *bp)
bnx2x_init_block(bp, USEM_BLOCK, init_stage);
bnx2x_init_block(bp, CSEM_BLOCK, init_stage);
bnx2x_init_block(bp, XSEM_BLOCK, init_stage);
+ if (CHIP_MODE_IS_4_PORT(bp))
+ bnx2x_init_block(bp, XSEM_4PORT_BLOCK, init_stage);
bnx2x_init_block(bp, UPB_BLOCK, init_stage);
bnx2x_init_block(bp, XPB_BLOCK, init_stage);
bnx2x_init_block(bp, PBF_BLOCK, init_stage);
- /* configure PBF to work without PAUSE mtu 9000 */
- REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
+ if (!CHIP_IS_E2(bp)) {
+ /* configure PBF to work without PAUSE mtu 9000 */
+ REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
- /* update threshold */
- REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, (9040/16));
- /* update init credit */
- REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, (9040/16) + 553 - 22);
+ /* update threshold */
+ REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, (9040/16));
+ /* update init credit */
+ REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, (9040/16) + 553 - 22);
- /* probe changes */
- REG_WR(bp, PBF_REG_INIT_P0 + port*4, 1);
- msleep(5);
- REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0);
+ /* probe changes */
+ REG_WR(bp, PBF_REG_INIT_P0 + port*4, 1);
+ udelay(50);
+ REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0);
+ }
#ifdef BCM_CNIC
bnx2x_init_block(bp, SRCH_BLOCK, init_stage);
@@ -4265,13 +5363,15 @@ static int bnx2x_init_port(struct bnx2x *bp)
}
bnx2x_init_block(bp, HC_BLOCK, init_stage);
+ bnx2x_init_block(bp, IGU_BLOCK, init_stage);
+
bnx2x_init_block(bp, MISC_AEU_BLOCK, init_stage);
/* init aeu_mask_attn_func_0/1:
* - SF mode: bits 3-7 are masked. only bits 0-2 are in use
* - MF mode: bit 3 is masked. bits 0-2 are in use as in SF
* bits 4-7 are used for "per vn group attention" */
REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4,
- (IS_E1HMF(bp) ? 0xF7 : 0x7));
+ (IS_MF(bp) ? 0xF7 : 0x7));
bnx2x_init_block(bp, PXPCS_BLOCK, init_stage);
bnx2x_init_block(bp, EMAC0_BLOCK, init_stage);
@@ -4283,11 +5383,25 @@ static int bnx2x_init_port(struct bnx2x *bp)
REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1);
- if (CHIP_IS_E1H(bp)) {
- /* 0x2 disable e1hov, 0x1 enable */
+ if (!CHIP_IS_E1(bp)) {
+ /* 0x2 disable mf_ov, 0x1 enable */
REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK_MF + port*4,
- (IS_E1HMF(bp) ? 0x1 : 0x2));
+ (IS_MF(bp) ? 0x1 : 0x2));
+ if (CHIP_IS_E2(bp)) {
+ val = 0;
+ switch (bp->mf_mode) {
+ case MULTI_FUNCTION_SD:
+ val = 1;
+ break;
+ case MULTI_FUNCTION_SI:
+ val = 2;
+ break;
+ }
+
+ REG_WR(bp, (BP_PORT(bp) ? NIG_REG_LLH1_CLS_TYPE :
+ NIG_REG_LLH0_CLS_TYPE), val);
+ }
{
REG_WR(bp, NIG_REG_LLFC_ENABLE_0 + port*4, 0);
REG_WR(bp, NIG_REG_LLFC_OUT_EN_0 + port*4, 0);
@@ -4297,199 +5411,339 @@ static int bnx2x_init_port(struct bnx2x *bp)
bnx2x_init_block(bp, MCP_BLOCK, init_stage);
bnx2x_init_block(bp, DMAE_BLOCK, init_stage);
-
- switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
- {
- u32 swap_val, swap_override, aeu_gpio_mask, offset;
-
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
- MISC_REGISTERS_GPIO_INPUT_HI_Z, port);
-
- /* The GPIO should be swapped if the swap register is
- set and active */
- swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
- swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
-
- /* Select function upon port-swap configuration */
- if (port == 0) {
- offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
- aeu_gpio_mask = (swap_val && swap_override) ?
- AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 :
- AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0;
- } else {
- offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
- aeu_gpio_mask = (swap_val && swap_override) ?
- AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 :
- AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1;
- }
- val = REG_RD(bp, offset);
- /* add GPIO3 to group */
- val |= aeu_gpio_mask;
- REG_WR(bp, offset, val);
- }
- bp->port.need_hw_lock = 1;
- break;
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
- bp->port.need_hw_lock = 1;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
- /* add SPIO 5 to group 0 */
- {
+ bp->port.need_hw_lock = bnx2x_hw_lock_required(bp,
+ bp->common.shmem_base,
+ bp->common.shmem2_base);
+ if (bnx2x_fan_failure_det_req(bp, bp->common.shmem_base,
+ bp->common.shmem2_base, port)) {
u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
val = REG_RD(bp, reg_addr);
val |= AEU_INPUTS_ATTN_BITS_SPIO5;
REG_WR(bp, reg_addr, val);
- }
- break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
- bp->port.need_hw_lock = 1;
- break;
- default:
- break;
}
-
bnx2x__link_reset(bp);
return 0;
}
-#define ILT_PER_FUNC (768/2)
-#define FUNC_ILT_BASE(func) (func * ILT_PER_FUNC)
-/* the phys address is shifted right 12 bits and has an added
- 1=valid bit added to the 53rd bit
- then since this is a wide register(TM)
- we split it into two 32 bit writes
- */
-#define ONCHIP_ADDR1(x) ((u32)(((u64)x >> 12) & 0xFFFFFFFF))
-#define ONCHIP_ADDR2(x) ((u32)((1 << 20) | ((u64)x >> 44)))
-#define PXP_ONE_ILT(x) (((x) << 10) | x)
-#define PXP_ILT_RANGE(f, l) (((l) << 10) | f)
-
-#ifdef BCM_CNIC
-#define CNIC_ILT_LINES 127
-#define CNIC_CTX_PER_ILT 16
-#else
-#define CNIC_ILT_LINES 0
-#endif
-
static void bnx2x_ilt_wr(struct bnx2x *bp, u32 index, dma_addr_t addr)
{
int reg;
- if (CHIP_IS_E1H(bp))
- reg = PXP2_REG_RQ_ONCHIP_AT_B0 + index*8;
- else /* E1 */
+ if (CHIP_IS_E1(bp))
reg = PXP2_REG_RQ_ONCHIP_AT + index*8;
+ else
+ reg = PXP2_REG_RQ_ONCHIP_AT_B0 + index*8;
bnx2x_wb_wr(bp, reg, ONCHIP_ADDR1(addr), ONCHIP_ADDR2(addr));
}
-static int bnx2x_init_func(struct bnx2x *bp)
+static inline void bnx2x_igu_clear_sb(struct bnx2x *bp, u8 idu_sb_id)
+{
+ bnx2x_igu_clear_sb_gen(bp, idu_sb_id, true /*PF*/);
+}
+
+static inline void bnx2x_clear_func_ilt(struct bnx2x *bp, u32 func)
+{
+ u32 i, base = FUNC_ILT_BASE(func);
+ for (i = base; i < base + ILT_PER_FUNC; i++)
+ bnx2x_ilt_wr(bp, i, 0);
+}
+
+static int bnx2x_init_hw_func(struct bnx2x *bp)
{
int port = BP_PORT(bp);
int func = BP_FUNC(bp);
+ struct bnx2x_ilt *ilt = BP_ILT(bp);
+ u16 cdu_ilt_start;
u32 addr, val;
- int i;
+ u32 main_mem_base, main_mem_size, main_mem_prty_clr;
+ int i, main_mem_width;
DP(BNX2X_MSG_MCP, "starting func init func %d\n", func);
/* set MSI reconfigure capability */
- addr = (port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0);
- val = REG_RD(bp, addr);
- val |= HC_CONFIG_0_REG_MSI_ATTN_EN_0;
- REG_WR(bp, addr, val);
+ if (bp->common.int_block == INT_BLOCK_HC) {
+ addr = (port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0);
+ val = REG_RD(bp, addr);
+ val |= HC_CONFIG_0_REG_MSI_ATTN_EN_0;
+ REG_WR(bp, addr, val);
+ }
- i = FUNC_ILT_BASE(func);
+ ilt = BP_ILT(bp);
+ cdu_ilt_start = ilt->clients[ILT_CLIENT_CDU].start;
- bnx2x_ilt_wr(bp, i, bnx2x_sp_mapping(bp, context));
- if (CHIP_IS_E1H(bp)) {
- REG_WR(bp, PXP2_REG_RQ_CDU_FIRST_ILT, i);
- REG_WR(bp, PXP2_REG_RQ_CDU_LAST_ILT, i + CNIC_ILT_LINES);
- } else /* E1 */
- REG_WR(bp, PXP2_REG_PSWRQ_CDU0_L2P + func*4,
- PXP_ILT_RANGE(i, i + CNIC_ILT_LINES));
+ for (i = 0; i < L2_ILT_LINES(bp); i++) {
+ ilt->lines[cdu_ilt_start + i].page =
+ bp->context.vcxt + (ILT_PAGE_CIDS * i);
+ ilt->lines[cdu_ilt_start + i].page_mapping =
+ bp->context.cxt_mapping + (CDU_ILT_PAGE_SZ * i);
+ /* cdu ilt pages are allocated manually so there's no need to
+ set the size */
+ }
+ bnx2x_ilt_init_op(bp, INITOP_SET);
#ifdef BCM_CNIC
- i += 1 + CNIC_ILT_LINES;
- bnx2x_ilt_wr(bp, i, bp->timers_mapping);
- if (CHIP_IS_E1(bp))
- REG_WR(bp, PXP2_REG_PSWRQ_TM0_L2P + func*4, PXP_ONE_ILT(i));
- else {
- REG_WR(bp, PXP2_REG_RQ_TM_FIRST_ILT, i);
- REG_WR(bp, PXP2_REG_RQ_TM_LAST_ILT, i);
- }
+ bnx2x_src_init_t2(bp, bp->t2, bp->t2_mapping, SRC_CONN_NUM);
- i++;
- bnx2x_ilt_wr(bp, i, bp->qm_mapping);
- if (CHIP_IS_E1(bp))
- REG_WR(bp, PXP2_REG_PSWRQ_QM0_L2P + func*4, PXP_ONE_ILT(i));
- else {
- REG_WR(bp, PXP2_REG_RQ_QM_FIRST_ILT, i);
- REG_WR(bp, PXP2_REG_RQ_QM_LAST_ILT, i);
+ /* T1 hash bits value determines the T1 number of entries */
+ REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + port*4, SRC_HASH_BITS);
+#endif
+
+#ifndef BCM_CNIC
+ /* set NIC mode */
+ REG_WR(bp, PRS_REG_NIC_MODE, 1);
+#endif /* BCM_CNIC */
+
+ if (CHIP_IS_E2(bp)) {
+ u32 pf_conf = IGU_PF_CONF_FUNC_EN;
+
+ /* Turn on a single ISR mode in IGU if driver is going to use
+ * INT#x or MSI
+ */
+ if (!(bp->flags & USING_MSIX_FLAG))
+ pf_conf |= IGU_PF_CONF_SINGLE_ISR_EN;
+ /*
+ * Timers workaround bug: function init part.
+ * Need to wait 20msec after initializing ILT,
+ * needed to make sure there are no requests in
+ * one of the PXP internal queues with "old" ILT addresses
+ */
+ msleep(20);
+ /*
+ * Master enable - Due to WB DMAE writes performed before this
+ * register is re-initialized as part of the regular function
+ * init
+ */
+ REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, 1);
+ /* Enable the function in IGU */
+ REG_WR(bp, IGU_REG_PF_CONFIGURATION, pf_conf);
}
- i++;
- bnx2x_ilt_wr(bp, i, bp->t1_mapping);
- if (CHIP_IS_E1(bp))
- REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i));
- else {
- REG_WR(bp, PXP2_REG_RQ_SRC_FIRST_ILT, i);
- REG_WR(bp, PXP2_REG_RQ_SRC_LAST_ILT, i);
+ bp->dmae_ready = 1;
+
+ bnx2x_init_block(bp, PGLUE_B_BLOCK, FUNC0_STAGE + func);
+
+ if (CHIP_IS_E2(bp))
+ REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, func);
+
+ bnx2x_init_block(bp, MISC_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, TCM_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, UCM_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, CCM_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, XCM_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, TSEM_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, USEM_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, CSEM_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, XSEM_BLOCK, FUNC0_STAGE + func);
+
+ if (CHIP_IS_E2(bp)) {
+ REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_PATH_ID_OFFSET,
+ BP_PATH(bp));
+ REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_PATH_ID_OFFSET,
+ BP_PATH(bp));
}
- /* tell the searcher where the T2 table is */
- REG_WR(bp, SRC_REG_COUNTFREE0 + port*4, 16*1024/64);
+ if (CHIP_MODE_IS_4_PORT(bp))
+ bnx2x_init_block(bp, XSEM_4PORT_BLOCK, FUNC0_STAGE + func);
- bnx2x_wb_wr(bp, SRC_REG_FIRSTFREE0 + port*16,
- U64_LO(bp->t2_mapping), U64_HI(bp->t2_mapping));
+ if (CHIP_IS_E2(bp))
+ REG_WR(bp, QM_REG_PF_EN, 1);
- bnx2x_wb_wr(bp, SRC_REG_LASTFREE0 + port*16,
- U64_LO((u64)bp->t2_mapping + 16*1024 - 64),
- U64_HI((u64)bp->t2_mapping + 16*1024 - 64));
+ bnx2x_init_block(bp, QM_BLOCK, FUNC0_STAGE + func);
- REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + port*4, 10);
-#endif
+ if (CHIP_MODE_IS_4_PORT(bp))
+ bnx2x_init_block(bp, QM_4PORT_BLOCK, FUNC0_STAGE + func);
+
+ bnx2x_init_block(bp, TIMERS_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, DQ_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, BRB1_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, PRS_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, TSDM_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, CSDM_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, USDM_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, XSDM_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, UPB_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, XPB_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, PBF_BLOCK, FUNC0_STAGE + func);
+ if (CHIP_IS_E2(bp))
+ REG_WR(bp, PBF_REG_DISABLE_PF, 0);
- if (CHIP_IS_E1H(bp)) {
- bnx2x_init_block(bp, MISC_BLOCK, FUNC0_STAGE + func);
- bnx2x_init_block(bp, TCM_BLOCK, FUNC0_STAGE + func);
- bnx2x_init_block(bp, UCM_BLOCK, FUNC0_STAGE + func);
- bnx2x_init_block(bp, CCM_BLOCK, FUNC0_STAGE + func);
- bnx2x_init_block(bp, XCM_BLOCK, FUNC0_STAGE + func);
- bnx2x_init_block(bp, TSEM_BLOCK, FUNC0_STAGE + func);
- bnx2x_init_block(bp, USEM_BLOCK, FUNC0_STAGE + func);
- bnx2x_init_block(bp, CSEM_BLOCK, FUNC0_STAGE + func);
- bnx2x_init_block(bp, XSEM_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, CDU_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, CFC_BLOCK, FUNC0_STAGE + func);
+
+ if (CHIP_IS_E2(bp))
+ REG_WR(bp, CFC_REG_WEAK_ENABLE_PF, 1);
+
+ if (IS_MF(bp)) {
REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1);
- REG_WR(bp, NIG_REG_LLH0_FUNC_VLAN_ID + port*8, bp->e1hov);
+ REG_WR(bp, NIG_REG_LLH0_FUNC_VLAN_ID + port*8, bp->mf_ov);
}
+ bnx2x_init_block(bp, MISC_AEU_BLOCK, FUNC0_STAGE + func);
+
/* HC init per function */
- if (CHIP_IS_E1H(bp)) {
+ if (bp->common.int_block == INT_BLOCK_HC) {
+ if (CHIP_IS_E1H(bp)) {
+ REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0);
+
+ REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0);
+ REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0);
+ }
+ bnx2x_init_block(bp, HC_BLOCK, FUNC0_STAGE + func);
+
+ } else {
+ int num_segs, sb_idx, prod_offset;
+
REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0);
- REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0);
- REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0);
+ if (CHIP_IS_E2(bp)) {
+ REG_WR(bp, IGU_REG_LEADING_EDGE_LATCH, 0);
+ REG_WR(bp, IGU_REG_TRAILING_EDGE_LATCH, 0);
+ }
+
+ bnx2x_init_block(bp, IGU_BLOCK, FUNC0_STAGE + func);
+
+ if (CHIP_IS_E2(bp)) {
+ int dsb_idx = 0;
+ /**
+ * Producer memory:
+ * E2 mode: address 0-135 match to the mapping memory;
+ * 136 - PF0 default prod; 137 - PF1 default prod;
+ * 138 - PF2 default prod; 139 - PF3 default prod;
+ * 140 - PF0 attn prod; 141 - PF1 attn prod;
+ * 142 - PF2 attn prod; 143 - PF3 attn prod;
+ * 144-147 reserved.
+ *
+ * E1.5 mode - In backward compatible mode;
+ * for non default SB; each even line in the memory
+ * holds the U producer and each odd line hold
+ * the C producer. The first 128 producers are for
+ * NDSB (PF0 - 0-31; PF1 - 32-63 and so on). The last 20
+ * producers are for the DSB for each PF.
+ * Each PF has five segments: (the order inside each
+ * segment is PF0; PF1; PF2; PF3) - 128-131 U prods;
+ * 132-135 C prods; 136-139 X prods; 140-143 T prods;
+ * 144-147 attn prods;
+ */
+ /* non-default-status-blocks */
+ num_segs = CHIP_INT_MODE_IS_BC(bp) ?
+ IGU_BC_NDSB_NUM_SEGS : IGU_NORM_NDSB_NUM_SEGS;
+ for (sb_idx = 0; sb_idx < bp->igu_sb_cnt; sb_idx++) {
+ prod_offset = (bp->igu_base_sb + sb_idx) *
+ num_segs;
+
+ for (i = 0; i < num_segs; i++) {
+ addr = IGU_REG_PROD_CONS_MEMORY +
+ (prod_offset + i) * 4;
+ REG_WR(bp, addr, 0);
+ }
+ /* send consumer update with value 0 */
+ bnx2x_ack_sb(bp, bp->igu_base_sb + sb_idx,
+ USTORM_ID, 0, IGU_INT_NOP, 1);
+ bnx2x_igu_clear_sb(bp,
+ bp->igu_base_sb + sb_idx);
+ }
+
+ /* default-status-blocks */
+ num_segs = CHIP_INT_MODE_IS_BC(bp) ?
+ IGU_BC_DSB_NUM_SEGS : IGU_NORM_DSB_NUM_SEGS;
+
+ if (CHIP_MODE_IS_4_PORT(bp))
+ dsb_idx = BP_FUNC(bp);
+ else
+ dsb_idx = BP_E1HVN(bp);
+
+ prod_offset = (CHIP_INT_MODE_IS_BC(bp) ?
+ IGU_BC_BASE_DSB_PROD + dsb_idx :
+ IGU_NORM_BASE_DSB_PROD + dsb_idx);
+
+ for (i = 0; i < (num_segs * E1HVN_MAX);
+ i += E1HVN_MAX) {
+ addr = IGU_REG_PROD_CONS_MEMORY +
+ (prod_offset + i)*4;
+ REG_WR(bp, addr, 0);
+ }
+ /* send consumer update with 0 */
+ if (CHIP_INT_MODE_IS_BC(bp)) {
+ bnx2x_ack_sb(bp, bp->igu_dsb_id,
+ USTORM_ID, 0, IGU_INT_NOP, 1);
+ bnx2x_ack_sb(bp, bp->igu_dsb_id,
+ CSTORM_ID, 0, IGU_INT_NOP, 1);
+ bnx2x_ack_sb(bp, bp->igu_dsb_id,
+ XSTORM_ID, 0, IGU_INT_NOP, 1);
+ bnx2x_ack_sb(bp, bp->igu_dsb_id,
+ TSTORM_ID, 0, IGU_INT_NOP, 1);
+ bnx2x_ack_sb(bp, bp->igu_dsb_id,
+ ATTENTION_ID, 0, IGU_INT_NOP, 1);
+ } else {
+ bnx2x_ack_sb(bp, bp->igu_dsb_id,
+ USTORM_ID, 0, IGU_INT_NOP, 1);
+ bnx2x_ack_sb(bp, bp->igu_dsb_id,
+ ATTENTION_ID, 0, IGU_INT_NOP, 1);
+ }
+ bnx2x_igu_clear_sb(bp, bp->igu_dsb_id);
+
+ /* !!! these should become driver const once
+ rf-tool supports split-68 const */
+ REG_WR(bp, IGU_REG_SB_INT_BEFORE_MASK_LSB, 0);
+ REG_WR(bp, IGU_REG_SB_INT_BEFORE_MASK_MSB, 0);
+ REG_WR(bp, IGU_REG_SB_MASK_LSB, 0);
+ REG_WR(bp, IGU_REG_SB_MASK_MSB, 0);
+ REG_WR(bp, IGU_REG_PBA_STATUS_LSB, 0);
+ REG_WR(bp, IGU_REG_PBA_STATUS_MSB, 0);
+ }
}
- bnx2x_init_block(bp, HC_BLOCK, FUNC0_STAGE + func);
/* Reset PCIE errors for debug */
REG_WR(bp, 0x2114, 0xffffffff);
REG_WR(bp, 0x2120, 0xffffffff);
+ bnx2x_init_block(bp, EMAC0_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, EMAC1_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, DBU_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, DBG_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, MCP_BLOCK, FUNC0_STAGE + func);
+ bnx2x_init_block(bp, DMAE_BLOCK, FUNC0_STAGE + func);
+
+ if (CHIP_IS_E1x(bp)) {
+ main_mem_size = HC_REG_MAIN_MEMORY_SIZE / 2; /*dwords*/
+ main_mem_base = HC_REG_MAIN_MEMORY +
+ BP_PORT(bp) * (main_mem_size * 4);
+ main_mem_prty_clr = HC_REG_HC_PRTY_STS_CLR;
+ main_mem_width = 8;
+
+ val = REG_RD(bp, main_mem_prty_clr);
+ if (val)
+ DP(BNX2X_MSG_MCP, "Hmmm... Parity errors in HC "
+ "block during "
+ "function init (0x%x)!\n", val);
+
+ /* Clear "false" parity errors in MSI-X table */
+ for (i = main_mem_base;
+ i < main_mem_base + main_mem_size * 4;
+ i += main_mem_width) {
+ bnx2x_read_dmae(bp, i, main_mem_width / 4);
+ bnx2x_write_dmae(bp, bnx2x_sp_mapping(bp, wb_data),
+ i, main_mem_width / 4);
+ }
+ /* Clear HC parity attention */
+ REG_RD(bp, main_mem_prty_clr);
+ }
+
+ bnx2x_phy_probe(&bp->link_params);
+
return 0;
}
int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
{
- int i, rc = 0;
+ int rc = 0;
DP(BNX2X_MSG_MCP, "function %d load_code %x\n",
- BP_FUNC(bp), load_code);
+ BP_ABS_FUNC(bp), load_code);
bp->dmae_ready = 0;
mutex_init(&bp->dmae_mutex);
@@ -4499,21 +5753,20 @@ int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
switch (load_code) {
case FW_MSG_CODE_DRV_LOAD_COMMON:
- rc = bnx2x_init_common(bp);
+ case FW_MSG_CODE_DRV_LOAD_COMMON_CHIP:
+ rc = bnx2x_init_hw_common(bp, load_code);
if (rc)
goto init_hw_err;
/* no break */
case FW_MSG_CODE_DRV_LOAD_PORT:
- bp->dmae_ready = 1;
- rc = bnx2x_init_port(bp);
+ rc = bnx2x_init_hw_port(bp);
if (rc)
goto init_hw_err;
/* no break */
case FW_MSG_CODE_DRV_LOAD_FUNCTION:
- bp->dmae_ready = 1;
- rc = bnx2x_init_func(bp);
+ rc = bnx2x_init_hw_func(bp);
if (rc)
goto init_hw_err;
break;
@@ -4524,22 +5777,14 @@ int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
}
if (!BP_NOMCP(bp)) {
- int func = BP_FUNC(bp);
+ int mb_idx = BP_FW_MB_IDX(bp);
bp->fw_drv_pulse_wr_seq =
- (SHMEM_RD(bp, func_mb[func].drv_pulse_mb) &
+ (SHMEM_RD(bp, func_mb[mb_idx].drv_pulse_mb) &
DRV_PULSE_SEQ_MASK);
DP(BNX2X_MSG_MCP, "drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
}
- /* this needs to be done before gunzip end */
- bnx2x_zero_def_sb(bp);
- for_each_queue(bp, i)
- bnx2x_zero_sb(bp, BP_L_ID(bp) + i);
-#ifdef BCM_CNIC
- bnx2x_zero_sb(bp, BP_L_ID(bp) + i);
-#endif
-
init_hw_err:
bnx2x_gunzip_end(bp);
@@ -4552,7 +5797,7 @@ void bnx2x_free_mem(struct bnx2x *bp)
#define BNX2X_PCI_FREE(x, y, size) \
do { \
if (x) { \
- dma_free_coherent(&bp->pdev->dev, size, x, y); \
+ dma_free_coherent(&bp->pdev->dev, size, (void *)x, y); \
x = NULL; \
y = 0; \
} \
@@ -4561,7 +5806,7 @@ void bnx2x_free_mem(struct bnx2x *bp)
#define BNX2X_FREE(x) \
do { \
if (x) { \
- vfree(x); \
+ kfree((void *)x); \
x = NULL; \
} \
} while (0)
@@ -4571,11 +5816,15 @@ void bnx2x_free_mem(struct bnx2x *bp)
/* fastpath */
/* Common */
for_each_queue(bp, i) {
-
/* status blocks */
- BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk),
- bnx2x_fp(bp, i, status_blk_mapping),
- sizeof(struct host_status_block));
+ if (CHIP_IS_E2(bp))
+ BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk.e2_sb),
+ bnx2x_fp(bp, i, status_blk_mapping),
+ sizeof(struct host_hc_status_block_e2));
+ else
+ BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk.e1x_sb),
+ bnx2x_fp(bp, i, status_blk_mapping),
+ sizeof(struct host_hc_status_block_e1x));
}
/* Rx */
for_each_queue(bp, i) {
@@ -4609,28 +5858,56 @@ void bnx2x_free_mem(struct bnx2x *bp)
/* end of fastpath */
BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping,
- sizeof(struct host_def_status_block));
+ sizeof(struct host_sp_status_block));
BNX2X_PCI_FREE(bp->slowpath, bp->slowpath_mapping,
sizeof(struct bnx2x_slowpath));
+ BNX2X_PCI_FREE(bp->context.vcxt, bp->context.cxt_mapping,
+ bp->context.size);
+
+ bnx2x_ilt_mem_op(bp, ILT_MEMOP_FREE);
+
+ BNX2X_FREE(bp->ilt->lines);
+
#ifdef BCM_CNIC
- BNX2X_PCI_FREE(bp->t1, bp->t1_mapping, 64*1024);
- BNX2X_PCI_FREE(bp->t2, bp->t2_mapping, 16*1024);
- BNX2X_PCI_FREE(bp->timers, bp->timers_mapping, 8*1024);
- BNX2X_PCI_FREE(bp->qm, bp->qm_mapping, 128*1024);
- BNX2X_PCI_FREE(bp->cnic_sb, bp->cnic_sb_mapping,
- sizeof(struct host_status_block));
+ if (CHIP_IS_E2(bp))
+ BNX2X_PCI_FREE(bp->cnic_sb.e2_sb, bp->cnic_sb_mapping,
+ sizeof(struct host_hc_status_block_e2));
+ else
+ BNX2X_PCI_FREE(bp->cnic_sb.e1x_sb, bp->cnic_sb_mapping,
+ sizeof(struct host_hc_status_block_e1x));
+
+ BNX2X_PCI_FREE(bp->t2, bp->t2_mapping, SRC_T2_SZ);
#endif
+
BNX2X_PCI_FREE(bp->spq, bp->spq_mapping, BCM_PAGE_SIZE);
+ BNX2X_PCI_FREE(bp->eq_ring, bp->eq_mapping,
+ BCM_PAGE_SIZE * NUM_EQ_PAGES);
+
#undef BNX2X_PCI_FREE
#undef BNX2X_KFREE
}
-int bnx2x_alloc_mem(struct bnx2x *bp)
+static inline void set_sb_shortcuts(struct bnx2x *bp, int index)
{
+ union host_hc_status_block status_blk = bnx2x_fp(bp, index, status_blk);
+ if (CHIP_IS_E2(bp)) {
+ bnx2x_fp(bp, index, sb_index_values) =
+ (__le16 *)status_blk.e2_sb->sb.index_values;
+ bnx2x_fp(bp, index, sb_running_index) =
+ (__le16 *)status_blk.e2_sb->sb.running_index;
+ } else {
+ bnx2x_fp(bp, index, sb_index_values) =
+ (__le16 *)status_blk.e1x_sb->sb.index_values;
+ bnx2x_fp(bp, index, sb_running_index) =
+ (__le16 *)status_blk.e1x_sb->sb.running_index;
+ }
+}
+int bnx2x_alloc_mem(struct bnx2x *bp)
+{
#define BNX2X_PCI_ALLOC(x, y, size) \
do { \
x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
@@ -4641,10 +5918,9 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
#define BNX2X_ALLOC(x, size) \
do { \
- x = vmalloc(size); \
+ x = kzalloc(size, GFP_KERNEL); \
if (x == NULL) \
goto alloc_mem_err; \
- memset(x, 0, size); \
} while (0)
int i;
@@ -4652,12 +5928,19 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
/* fastpath */
/* Common */
for_each_queue(bp, i) {
+ union host_hc_status_block *sb = &bnx2x_fp(bp, i, status_blk);
bnx2x_fp(bp, i, bp) = bp;
-
/* status blocks */
- BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, status_blk),
+ if (CHIP_IS_E2(bp))
+ BNX2X_PCI_ALLOC(sb->e2_sb,
&bnx2x_fp(bp, i, status_blk_mapping),
- sizeof(struct host_status_block));
+ sizeof(struct host_hc_status_block_e2));
+ else
+ BNX2X_PCI_ALLOC(sb->e1x_sb,
+ &bnx2x_fp(bp, i, status_blk_mapping),
+ sizeof(struct host_hc_status_block_e1x));
+
+ set_sb_shortcuts(bp, i);
}
/* Rx */
for_each_queue(bp, i) {
@@ -4693,37 +5976,41 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
}
/* end of fastpath */
+#ifdef BCM_CNIC
+ if (CHIP_IS_E2(bp))
+ BNX2X_PCI_ALLOC(bp->cnic_sb.e2_sb, &bp->cnic_sb_mapping,
+ sizeof(struct host_hc_status_block_e2));
+ else
+ BNX2X_PCI_ALLOC(bp->cnic_sb.e1x_sb, &bp->cnic_sb_mapping,
+ sizeof(struct host_hc_status_block_e1x));
+
+ /* allocate searcher T2 table */
+ BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, SRC_T2_SZ);
+#endif
+
+
BNX2X_PCI_ALLOC(bp->def_status_blk, &bp->def_status_blk_mapping,
- sizeof(struct host_def_status_block));
+ sizeof(struct host_sp_status_block));
BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping,
sizeof(struct bnx2x_slowpath));
-#ifdef BCM_CNIC
- BNX2X_PCI_ALLOC(bp->t1, &bp->t1_mapping, 64*1024);
-
- /* allocate searcher T2 table
- we allocate 1/4 of alloc num for T2
- (which is not entered into the ILT) */
- BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, 16*1024);
-
- /* Initialize T2 (for 1024 connections) */
- for (i = 0; i < 16*1024; i += 64)
- *(u64 *)((char *)bp->t2 + i + 56) = bp->t2_mapping + i + 64;
+ bp->context.size = sizeof(union cdu_context) * bp->l2_cid_count;
- /* Timer block array (8*MAX_CONN) phys uncached for now 1024 conns */
- BNX2X_PCI_ALLOC(bp->timers, &bp->timers_mapping, 8*1024);
+ BNX2X_PCI_ALLOC(bp->context.vcxt, &bp->context.cxt_mapping,
+ bp->context.size);
- /* QM queues (128*MAX_CONN) */
- BNX2X_PCI_ALLOC(bp->qm, &bp->qm_mapping, 128*1024);
+ BNX2X_ALLOC(bp->ilt->lines, sizeof(struct ilt_line) * ILT_MAX_LINES);
- BNX2X_PCI_ALLOC(bp->cnic_sb, &bp->cnic_sb_mapping,
- sizeof(struct host_status_block));
-#endif
+ if (bnx2x_ilt_mem_op(bp, ILT_MEMOP_ALLOC))
+ goto alloc_mem_err;
/* Slow path ring */
BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE);
+ /* EQ */
+ BNX2X_PCI_ALLOC(bp->eq_ring, &bp->eq_mapping,
+ BCM_PAGE_SIZE * NUM_EQ_PAGES);
return 0;
alloc_mem_err:
@@ -4734,97 +6021,50 @@ alloc_mem_err:
#undef BNX2X_ALLOC
}
-
/*
* Init service functions
*/
+static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx,
+ int *state_p, int flags);
-/**
- * Sets a MAC in a CAM for a few L2 Clients for E1 chip
- *
- * @param bp driver descriptor
- * @param set set or clear an entry (1 or 0)
- * @param mac pointer to a buffer containing a MAC
- * @param cl_bit_vec bit vector of clients to register a MAC for
- * @param cam_offset offset in a CAM to use
- * @param with_bcast set broadcast MAC as well
- */
-static void bnx2x_set_mac_addr_e1_gen(struct bnx2x *bp, int set, u8 *mac,
- u32 cl_bit_vec, u8 cam_offset,
- u8 with_bcast)
+int bnx2x_func_start(struct bnx2x *bp)
{
- struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config);
- int port = BP_PORT(bp);
-
- /* CAM allocation
- * unicasts 0-31:port0 32-63:port1
- * multicast 64-127:port0 128-191:port1
- */
- config->hdr.length = 1 + (with_bcast ? 1 : 0);
- config->hdr.offset = cam_offset;
- config->hdr.client_id = 0xff;
- config->hdr.reserved1 = 0;
+ bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_START, 0, 0, 0, 1);
- /* primary MAC */
- config->config_table[0].cam_entry.msb_mac_addr =
- swab16(*(u16 *)&mac[0]);
- config->config_table[0].cam_entry.middle_mac_addr =
- swab16(*(u16 *)&mac[2]);
- config->config_table[0].cam_entry.lsb_mac_addr =
- swab16(*(u16 *)&mac[4]);
- config->config_table[0].cam_entry.flags = cpu_to_le16(port);
- if (set)
- config->config_table[0].target_table_entry.flags = 0;
- else
- CAM_INVALIDATE(config->config_table[0]);
- config->config_table[0].target_table_entry.clients_bit_vector =
- cpu_to_le32(cl_bit_vec);
- config->config_table[0].target_table_entry.vlan_id = 0;
+ /* Wait for completion */
+ return bnx2x_wait_ramrod(bp, BNX2X_STATE_FUNC_STARTED, 0, &(bp->state),
+ WAIT_RAMROD_COMMON);
+}
- DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x)\n",
- (set ? "setting" : "clearing"),
- config->config_table[0].cam_entry.msb_mac_addr,
- config->config_table[0].cam_entry.middle_mac_addr,
- config->config_table[0].cam_entry.lsb_mac_addr);
-
- /* broadcast */
- if (with_bcast) {
- config->config_table[1].cam_entry.msb_mac_addr =
- cpu_to_le16(0xffff);
- config->config_table[1].cam_entry.middle_mac_addr =
- cpu_to_le16(0xffff);
- config->config_table[1].cam_entry.lsb_mac_addr =
- cpu_to_le16(0xffff);
- config->config_table[1].cam_entry.flags = cpu_to_le16(port);
- if (set)
- config->config_table[1].target_table_entry.flags =
- TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST;
- else
- CAM_INVALIDATE(config->config_table[1]);
- config->config_table[1].target_table_entry.clients_bit_vector =
- cpu_to_le32(cl_bit_vec);
- config->config_table[1].target_table_entry.vlan_id = 0;
- }
+static int bnx2x_func_stop(struct bnx2x *bp)
+{
+ bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_STOP, 0, 0, 0, 1);
- bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
- U64_HI(bnx2x_sp_mapping(bp, mac_config)),
- U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
+ /* Wait for completion */
+ return bnx2x_wait_ramrod(bp, BNX2X_STATE_CLOSING_WAIT4_UNLOAD,
+ 0, &(bp->state), WAIT_RAMROD_COMMON);
}
/**
- * Sets a MAC in a CAM for a few L2 Clients for E1H chip
+ * Sets a MAC in a CAM for a few L2 Clients for E1x chips
*
* @param bp driver descriptor
* @param set set or clear an entry (1 or 0)
* @param mac pointer to a buffer containing a MAC
* @param cl_bit_vec bit vector of clients to register a MAC for
* @param cam_offset offset in a CAM to use
+ * @param is_bcast is the set MAC a broadcast address (for E1 only)
*/
-static void bnx2x_set_mac_addr_e1h_gen(struct bnx2x *bp, int set, u8 *mac,
- u32 cl_bit_vec, u8 cam_offset)
+static void bnx2x_set_mac_addr_gen(struct bnx2x *bp, int set, u8 *mac,
+ u32 cl_bit_vec, u8 cam_offset,
+ u8 is_bcast)
{
- struct mac_configuration_cmd_e1h *config =
- (struct mac_configuration_cmd_e1h *)bnx2x_sp(bp, mac_config);
+ struct mac_configuration_cmd *config =
+ (struct mac_configuration_cmd *)bnx2x_sp(bp, mac_config);
+ int ramrod_flags = WAIT_RAMROD_COMMON;
+
+ bp->set_mac_pending = 1;
+ smp_wmb();
config->hdr.length = 1;
config->hdr.offset = cam_offset;
@@ -4841,29 +6081,41 @@ static void bnx2x_set_mac_addr_e1h_gen(struct bnx2x *bp, int set, u8 *mac,
config->config_table[0].clients_bit_vector =
cpu_to_le32(cl_bit_vec);
config->config_table[0].vlan_id = 0;
- config->config_table[0].e1hov_id = cpu_to_le16(bp->e1hov);
+ config->config_table[0].pf_id = BP_FUNC(bp);
if (set)
- config->config_table[0].flags = BP_PORT(bp);
+ SET_FLAG(config->config_table[0].flags,
+ MAC_CONFIGURATION_ENTRY_ACTION_TYPE,
+ T_ETH_MAC_COMMAND_SET);
else
- config->config_table[0].flags =
- MAC_CONFIGURATION_ENTRY_E1H_ACTION_TYPE;
+ SET_FLAG(config->config_table[0].flags,
+ MAC_CONFIGURATION_ENTRY_ACTION_TYPE,
+ T_ETH_MAC_COMMAND_INVALIDATE);
- DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x) E1HOV %d CLID mask %d\n",
+ if (is_bcast)
+ SET_FLAG(config->config_table[0].flags,
+ MAC_CONFIGURATION_ENTRY_BROADCAST, 1);
+
+ DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x) PF_ID %d CLID mask %d\n",
(set ? "setting" : "clearing"),
config->config_table[0].msb_mac_addr,
config->config_table[0].middle_mac_addr,
- config->config_table[0].lsb_mac_addr, bp->e1hov, cl_bit_vec);
+ config->config_table[0].lsb_mac_addr, BP_FUNC(bp), cl_bit_vec);
- bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
+ bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_MAC, 0,
U64_HI(bnx2x_sp_mapping(bp, mac_config)),
- U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
+ U64_LO(bnx2x_sp_mapping(bp, mac_config)), 1);
+
+ /* Wait for a completion */
+ bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, ramrod_flags);
}
static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx,
- int *state_p, int poll)
+ int *state_p, int flags)
{
/* can take a while if any port is running */
int cnt = 5000;
+ u8 poll = flags & WAIT_RAMROD_POLL;
+ u8 common = flags & WAIT_RAMROD_COMMON;
DP(NETIF_MSG_IFUP, "%s for state to become %x on IDX [%d]\n",
poll ? "polling" : "waiting", state, idx);
@@ -4871,13 +6123,17 @@ static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx,
might_sleep();
while (cnt--) {
if (poll) {
- bnx2x_rx_int(bp->fp, 10);
- /* if index is different from 0
- * the reply for some commands will
- * be on the non default queue
- */
- if (idx)
- bnx2x_rx_int(&bp->fp[idx], 10);
+ if (common)
+ bnx2x_eq_int(bp);
+ else {
+ bnx2x_rx_int(bp->fp, 10);
+ /* if index is different from 0
+ * the reply for some commands will
+ * be on the non default queue
+ */
+ if (idx)
+ bnx2x_rx_int(&bp->fp[idx], 10);
+ }
}
mb(); /* state is changed by bnx2x_sp_event() */
@@ -4904,29 +6160,112 @@ static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx,
return -EBUSY;
}
-void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set)
+static u8 bnx2x_e1h_cam_offset(struct bnx2x *bp, u8 rel_offset)
{
- bp->set_mac_pending++;
- smp_wmb();
+ if (CHIP_IS_E1H(bp))
+ return E1H_FUNC_MAX * rel_offset + BP_FUNC(bp);
+ else if (CHIP_MODE_IS_4_PORT(bp))
+ return BP_FUNC(bp) * 32 + rel_offset;
+ else
+ return BP_VN(bp) * 32 + rel_offset;
+}
- bnx2x_set_mac_addr_e1h_gen(bp, set, bp->dev->dev_addr,
- (1 << bp->fp->cl_id), BP_FUNC(bp));
+void bnx2x_set_eth_mac(struct bnx2x *bp, int set)
+{
+ u8 cam_offset = (CHIP_IS_E1(bp) ? (BP_PORT(bp) ? 32 : 0) :
+ bnx2x_e1h_cam_offset(bp, CAM_ETH_LINE));
- /* Wait for a completion */
- bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
+ /* networking MAC */
+ bnx2x_set_mac_addr_gen(bp, set, bp->dev->dev_addr,
+ (1 << bp->fp->cl_id), cam_offset , 0);
+
+ if (CHIP_IS_E1(bp)) {
+ /* broadcast MAC */
+ u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ bnx2x_set_mac_addr_gen(bp, set, bcast, 0, cam_offset + 1, 1);
+ }
}
+static void bnx2x_set_e1_mc_list(struct bnx2x *bp, u8 offset)
+{
+ int i = 0, old;
+ struct net_device *dev = bp->dev;
+ struct netdev_hw_addr *ha;
+ struct mac_configuration_cmd *config_cmd = bnx2x_sp(bp, mcast_config);
+ dma_addr_t config_cmd_map = bnx2x_sp_mapping(bp, mcast_config);
+
+ netdev_for_each_mc_addr(ha, dev) {
+ /* copy mac */
+ config_cmd->config_table[i].msb_mac_addr =
+ swab16(*(u16 *)&bnx2x_mc_addr(ha)[0]);
+ config_cmd->config_table[i].middle_mac_addr =
+ swab16(*(u16 *)&bnx2x_mc_addr(ha)[2]);
+ config_cmd->config_table[i].lsb_mac_addr =
+ swab16(*(u16 *)&bnx2x_mc_addr(ha)[4]);
-void bnx2x_set_eth_mac_addr_e1(struct bnx2x *bp, int set)
+ config_cmd->config_table[i].vlan_id = 0;
+ config_cmd->config_table[i].pf_id = BP_FUNC(bp);
+ config_cmd->config_table[i].clients_bit_vector =
+ cpu_to_le32(1 << BP_L_ID(bp));
+
+ SET_FLAG(config_cmd->config_table[i].flags,
+ MAC_CONFIGURATION_ENTRY_ACTION_TYPE,
+ T_ETH_MAC_COMMAND_SET);
+
+ DP(NETIF_MSG_IFUP,
+ "setting MCAST[%d] (%04x:%04x:%04x)\n", i,
+ config_cmd->config_table[i].msb_mac_addr,
+ config_cmd->config_table[i].middle_mac_addr,
+ config_cmd->config_table[i].lsb_mac_addr);
+ i++;
+ }
+ old = config_cmd->hdr.length;
+ if (old > i) {
+ for (; i < old; i++) {
+ if (CAM_IS_INVALID(config_cmd->
+ config_table[i])) {
+ /* already invalidated */
+ break;
+ }
+ /* invalidate */
+ SET_FLAG(config_cmd->config_table[i].flags,
+ MAC_CONFIGURATION_ENTRY_ACTION_TYPE,
+ T_ETH_MAC_COMMAND_INVALIDATE);
+ }
+ }
+
+ config_cmd->hdr.length = i;
+ config_cmd->hdr.offset = offset;
+ config_cmd->hdr.client_id = 0xff;
+ config_cmd->hdr.reserved1 = 0;
+
+ bp->set_mac_pending = 1;
+ smp_wmb();
+
+ bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_MAC, 0,
+ U64_HI(config_cmd_map), U64_LO(config_cmd_map), 1);
+}
+static void bnx2x_invlidate_e1_mc_list(struct bnx2x *bp)
{
- bp->set_mac_pending++;
+ int i;
+ struct mac_configuration_cmd *config_cmd = bnx2x_sp(bp, mcast_config);
+ dma_addr_t config_cmd_map = bnx2x_sp_mapping(bp, mcast_config);
+ int ramrod_flags = WAIT_RAMROD_COMMON;
+
+ bp->set_mac_pending = 1;
smp_wmb();
- bnx2x_set_mac_addr_e1_gen(bp, set, bp->dev->dev_addr,
- (1 << bp->fp->cl_id), (BP_PORT(bp) ? 32 : 0),
- 1);
+ for (i = 0; i < config_cmd->hdr.length; i++)
+ SET_FLAG(config_cmd->config_table[i].flags,
+ MAC_CONFIGURATION_ENTRY_ACTION_TYPE,
+ T_ETH_MAC_COMMAND_INVALIDATE);
+
+ bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_MAC, 0,
+ U64_HI(config_cmd_map), U64_LO(config_cmd_map), 1);
/* Wait for a completion */
- bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
+ bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending,
+ ramrod_flags);
+
}
#ifdef BCM_CNIC
@@ -4940,176 +6279,466 @@ void bnx2x_set_eth_mac_addr_e1(struct bnx2x *bp, int set)
*
* @return 0 if cussess, -ENODEV if ramrod doesn't return.
*/
-int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set)
+static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set)
{
- u32 cl_bit_vec = (1 << BCM_ISCSI_ETH_CL_ID);
-
- bp->set_mac_pending++;
- smp_wmb();
+ u8 cam_offset = (CHIP_IS_E1(bp) ? ((BP_PORT(bp) ? 32 : 0) + 2) :
+ bnx2x_e1h_cam_offset(bp, CAM_ISCSI_ETH_LINE));
+ u32 iscsi_l2_cl_id = BNX2X_ISCSI_ETH_CL_ID;
+ u32 cl_bit_vec = (1 << iscsi_l2_cl_id);
/* Send a SET_MAC ramrod */
- if (CHIP_IS_E1(bp))
- bnx2x_set_mac_addr_e1_gen(bp, set, bp->iscsi_mac,
- cl_bit_vec, (BP_PORT(bp) ? 32 : 0) + 2,
- 1);
- else
- /* CAM allocation for E1H
- * unicasts: by func number
- * multicast: 20+FUNC*20, 20 each
- */
- bnx2x_set_mac_addr_e1h_gen(bp, set, bp->iscsi_mac,
- cl_bit_vec, E1H_FUNC_MAX + BP_FUNC(bp));
-
- /* Wait for a completion when setting */
- bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
-
+ bnx2x_set_mac_addr_gen(bp, set, bp->iscsi_mac, cl_bit_vec,
+ cam_offset, 0);
return 0;
}
#endif
-int bnx2x_setup_leading(struct bnx2x *bp)
-{
- int rc;
+static void bnx2x_fill_cl_init_data(struct bnx2x *bp,
+ struct bnx2x_client_init_params *params,
+ u8 activate,
+ struct client_init_ramrod_data *data)
+{
+ /* Clear the buffer */
+ memset(data, 0, sizeof(*data));
+
+ /* general */
+ data->general.client_id = params->rxq_params.cl_id;
+ data->general.statistics_counter_id = params->rxq_params.stat_id;
+ data->general.statistics_en_flg =
+ (params->rxq_params.flags & QUEUE_FLG_STATS) ? 1 : 0;
+ data->general.activate_flg = activate;
+ data->general.sp_client_id = params->rxq_params.spcl_id;
+
+ /* Rx data */
+ data->rx.tpa_en_flg =
+ (params->rxq_params.flags & QUEUE_FLG_TPA) ? 1 : 0;
+ data->rx.vmqueue_mode_en_flg = 0;
+ data->rx.cache_line_alignment_log_size =
+ params->rxq_params.cache_line_log;
+ data->rx.enable_dynamic_hc =
+ (params->rxq_params.flags & QUEUE_FLG_DHC) ? 1 : 0;
+ data->rx.max_sges_for_packet = params->rxq_params.max_sges_pkt;
+ data->rx.client_qzone_id = params->rxq_params.cl_qzone_id;
+ data->rx.max_agg_size = params->rxq_params.tpa_agg_sz;
+
+ /* We don't set drop flags */
+ data->rx.drop_ip_cs_err_flg = 0;
+ data->rx.drop_tcp_cs_err_flg = 0;
+ data->rx.drop_ttl0_flg = 0;
+ data->rx.drop_udp_cs_err_flg = 0;
+
+ data->rx.inner_vlan_removal_enable_flg =
+ (params->rxq_params.flags & QUEUE_FLG_VLAN) ? 1 : 0;
+ data->rx.outer_vlan_removal_enable_flg =
+ (params->rxq_params.flags & QUEUE_FLG_OV) ? 1 : 0;
+ data->rx.status_block_id = params->rxq_params.fw_sb_id;
+ data->rx.rx_sb_index_number = params->rxq_params.sb_cq_index;
+ data->rx.bd_buff_size = cpu_to_le16(params->rxq_params.buf_sz);
+ data->rx.sge_buff_size = cpu_to_le16(params->rxq_params.sge_buf_sz);
+ data->rx.mtu = cpu_to_le16(params->rxq_params.mtu);
+ data->rx.bd_page_base.lo =
+ cpu_to_le32(U64_LO(params->rxq_params.dscr_map));
+ data->rx.bd_page_base.hi =
+ cpu_to_le32(U64_HI(params->rxq_params.dscr_map));
+ data->rx.sge_page_base.lo =
+ cpu_to_le32(U64_LO(params->rxq_params.sge_map));
+ data->rx.sge_page_base.hi =
+ cpu_to_le32(U64_HI(params->rxq_params.sge_map));
+ data->rx.cqe_page_base.lo =
+ cpu_to_le32(U64_LO(params->rxq_params.rcq_map));
+ data->rx.cqe_page_base.hi =
+ cpu_to_le32(U64_HI(params->rxq_params.rcq_map));
+ data->rx.is_leading_rss =
+ (params->ramrod_params.flags & CLIENT_IS_LEADING_RSS) ? 1 : 0;
+ data->rx.is_approx_mcast = data->rx.is_leading_rss;
+
+ /* Tx data */
+ data->tx.enforce_security_flg = 0; /* VF specific */
+ data->tx.tx_status_block_id = params->txq_params.fw_sb_id;
+ data->tx.tx_sb_index_number = params->txq_params.sb_cq_index;
+ data->tx.mtu = 0; /* VF specific */
+ data->tx.tx_bd_page_base.lo =
+ cpu_to_le32(U64_LO(params->txq_params.dscr_map));
+ data->tx.tx_bd_page_base.hi =
+ cpu_to_le32(U64_HI(params->txq_params.dscr_map));
+
+ /* flow control data */
+ data->fc.cqe_pause_thr_low = cpu_to_le16(params->pause.rcq_th_lo);
+ data->fc.cqe_pause_thr_high = cpu_to_le16(params->pause.rcq_th_hi);
+ data->fc.bd_pause_thr_low = cpu_to_le16(params->pause.bd_th_lo);
+ data->fc.bd_pause_thr_high = cpu_to_le16(params->pause.bd_th_hi);
+ data->fc.sge_pause_thr_low = cpu_to_le16(params->pause.sge_th_lo);
+ data->fc.sge_pause_thr_high = cpu_to_le16(params->pause.sge_th_hi);
+ data->fc.rx_cos_mask = cpu_to_le16(params->pause.pri_map);
+
+ data->fc.safc_group_num = params->txq_params.cos;
+ data->fc.safc_group_en_flg =
+ (params->txq_params.flags & QUEUE_FLG_COS) ? 1 : 0;
+ data->fc.traffic_type = LLFC_TRAFFIC_TYPE_NW;
+}
+
+static inline void bnx2x_set_ctx_validation(struct eth_context *cxt, u32 cid)
+{
+ /* ustorm cxt validation */
+ cxt->ustorm_ag_context.cdu_usage =
+ CDU_RSRVD_VALUE_TYPE_A(cid, CDU_REGION_NUMBER_UCM_AG,
+ ETH_CONNECTION_TYPE);
+ /* xcontext validation */
+ cxt->xstorm_ag_context.cdu_reserved =
+ CDU_RSRVD_VALUE_TYPE_A(cid, CDU_REGION_NUMBER_XCM_AG,
+ ETH_CONNECTION_TYPE);
+}
+
+static int bnx2x_setup_fw_client(struct bnx2x *bp,
+ struct bnx2x_client_init_params *params,
+ u8 activate,
+ struct client_init_ramrod_data *data,
+ dma_addr_t data_mapping)
+{
+ u16 hc_usec;
+ int ramrod = RAMROD_CMD_ID_ETH_CLIENT_SETUP;
+ int ramrod_flags = 0, rc;
+
+ /* HC and context validation values */
+ hc_usec = params->txq_params.hc_rate ?
+ 1000000 / params->txq_params.hc_rate : 0;
+ bnx2x_update_coalesce_sb_index(bp,
+ params->txq_params.fw_sb_id,
+ params->txq_params.sb_cq_index,
+ !(params->txq_params.flags & QUEUE_FLG_HC),
+ hc_usec);
+
+ *(params->ramrod_params.pstate) = BNX2X_FP_STATE_OPENING;
+
+ hc_usec = params->rxq_params.hc_rate ?
+ 1000000 / params->rxq_params.hc_rate : 0;
+ bnx2x_update_coalesce_sb_index(bp,
+ params->rxq_params.fw_sb_id,
+ params->rxq_params.sb_cq_index,
+ !(params->rxq_params.flags & QUEUE_FLG_HC),
+ hc_usec);
+
+ bnx2x_set_ctx_validation(params->rxq_params.cxt,
+ params->rxq_params.cid);
+
+ /* zero stats */
+ if (params->txq_params.flags & QUEUE_FLG_STATS)
+ storm_memset_xstats_zero(bp, BP_PORT(bp),
+ params->txq_params.stat_id);
+
+ if (params->rxq_params.flags & QUEUE_FLG_STATS) {
+ storm_memset_ustats_zero(bp, BP_PORT(bp),
+ params->rxq_params.stat_id);
+ storm_memset_tstats_zero(bp, BP_PORT(bp),
+ params->rxq_params.stat_id);
+ }
+
+ /* Fill the ramrod data */
+ bnx2x_fill_cl_init_data(bp, params, activate, data);
+
+ /* SETUP ramrod.
+ *
+ * bnx2x_sp_post() takes a spin_lock thus no other explict memory
+ * barrier except from mmiowb() is needed to impose a
+ * proper ordering of memory operations.
+ */
+ mmiowb();
- /* reset IGU state */
- bnx2x_ack_sb(bp, bp->fp[0].sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
- /* SETUP ramrod */
- bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_SETUP, 0, 0, 0, 0);
+ bnx2x_sp_post(bp, ramrod, params->ramrod_params.cid,
+ U64_HI(data_mapping), U64_LO(data_mapping), 0);
/* Wait for completion */
- rc = bnx2x_wait_ramrod(bp, BNX2X_STATE_OPEN, 0, &(bp->state), 0);
-
+ rc = bnx2x_wait_ramrod(bp, params->ramrod_params.state,
+ params->ramrod_params.index,
+ params->ramrod_params.pstate,
+ ramrod_flags);
return rc;
}
-int bnx2x_setup_multi(struct bnx2x *bp, int index)
+/**
+ * Configure interrupt mode according to current configuration.
+ * In case of MSI-X it will also try to enable MSI-X.
+ *
+ * @param bp
+ *
+ * @return int
+ */
+static int __devinit bnx2x_set_int_mode(struct bnx2x *bp)
{
- struct bnx2x_fastpath *fp = &bp->fp[index];
+ int rc = 0;
+
+ switch (bp->int_mode) {
+ case INT_MODE_MSI:
+ bnx2x_enable_msi(bp);
+ /* falling through... */
+ case INT_MODE_INTx:
+ bp->num_queues = 1;
+ DP(NETIF_MSG_IFUP, "set number of queues to 1\n");
+ break;
+ default:
+ /* Set number of queues according to bp->multi_mode value */
+ bnx2x_set_num_queues(bp);
+
+ DP(NETIF_MSG_IFUP, "set number of queues to %d\n",
+ bp->num_queues);
- /* reset IGU state */
- bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
+ /* if we can't use MSI-X we only need one fp,
+ * so try to enable MSI-X with the requested number of fp's
+ * and fallback to MSI or legacy INTx with one fp
+ */
+ rc = bnx2x_enable_msix(bp);
+ if (rc) {
+ /* failed to enable MSI-X */
+ if (bp->multi_mode)
+ DP(NETIF_MSG_IFUP,
+ "Multi requested but failed to "
+ "enable MSI-X (%d), "
+ "set number of queues to %d\n",
+ bp->num_queues,
+ 1);
+ bp->num_queues = 1;
+
+ if (!(bp->flags & DISABLE_MSI_FLAG))
+ bnx2x_enable_msi(bp);
+ }
- /* SETUP ramrod */
- fp->state = BNX2X_FP_STATE_OPENING;
- bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_SETUP, index, 0,
- fp->cl_id, 0);
+ break;
+ }
- /* Wait for completion */
- return bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_OPEN, index,
- &(fp->state), 0);
+ return rc;
}
-
-void bnx2x_set_num_queues_msix(struct bnx2x *bp)
+/* must be called prioir to any HW initializations */
+static inline u16 bnx2x_cid_ilt_lines(struct bnx2x *bp)
{
+ return L2_ILT_LINES(bp);
+}
- switch (bp->multi_mode) {
- case ETH_RSS_MODE_DISABLED:
- bp->num_queues = 1;
- break;
+void bnx2x_ilt_set_info(struct bnx2x *bp)
+{
+ struct ilt_client_info *ilt_client;
+ struct bnx2x_ilt *ilt = BP_ILT(bp);
+ u16 line = 0;
- case ETH_RSS_MODE_REGULAR:
- if (num_queues)
- bp->num_queues = min_t(u32, num_queues,
- BNX2X_MAX_QUEUES(bp));
- else
- bp->num_queues = min_t(u32, num_online_cpus(),
- BNX2X_MAX_QUEUES(bp));
- break;
+ ilt->start_line = FUNC_ILT_BASE(BP_FUNC(bp));
+ DP(BNX2X_MSG_SP, "ilt starts at line %d\n", ilt->start_line);
+ /* CDU */
+ ilt_client = &ilt->clients[ILT_CLIENT_CDU];
+ ilt_client->client_num = ILT_CLIENT_CDU;
+ ilt_client->page_size = CDU_ILT_PAGE_SZ;
+ ilt_client->flags = ILT_CLIENT_SKIP_MEM;
+ ilt_client->start = line;
+ line += L2_ILT_LINES(bp);
+#ifdef BCM_CNIC
+ line += CNIC_ILT_LINES;
+#endif
+ ilt_client->end = line - 1;
+
+ DP(BNX2X_MSG_SP, "ilt client[CDU]: start %d, end %d, psz 0x%x, "
+ "flags 0x%x, hw psz %d\n",
+ ilt_client->start,
+ ilt_client->end,
+ ilt_client->page_size,
+ ilt_client->flags,
+ ilog2(ilt_client->page_size >> 12));
+
+ /* QM */
+ if (QM_INIT(bp->qm_cid_count)) {
+ ilt_client = &ilt->clients[ILT_CLIENT_QM];
+ ilt_client->client_num = ILT_CLIENT_QM;
+ ilt_client->page_size = QM_ILT_PAGE_SZ;
+ ilt_client->flags = 0;
+ ilt_client->start = line;
+
+ /* 4 bytes for each cid */
+ line += DIV_ROUND_UP(bp->qm_cid_count * QM_QUEUES_PER_FUNC * 4,
+ QM_ILT_PAGE_SZ);
+
+ ilt_client->end = line - 1;
+
+ DP(BNX2X_MSG_SP, "ilt client[QM]: start %d, end %d, psz 0x%x, "
+ "flags 0x%x, hw psz %d\n",
+ ilt_client->start,
+ ilt_client->end,
+ ilt_client->page_size,
+ ilt_client->flags,
+ ilog2(ilt_client->page_size >> 12));
+
+ }
+ /* SRC */
+ ilt_client = &ilt->clients[ILT_CLIENT_SRC];
+#ifdef BCM_CNIC
+ ilt_client->client_num = ILT_CLIENT_SRC;
+ ilt_client->page_size = SRC_ILT_PAGE_SZ;
+ ilt_client->flags = 0;
+ ilt_client->start = line;
+ line += SRC_ILT_LINES;
+ ilt_client->end = line - 1;
+
+ DP(BNX2X_MSG_SP, "ilt client[SRC]: start %d, end %d, psz 0x%x, "
+ "flags 0x%x, hw psz %d\n",
+ ilt_client->start,
+ ilt_client->end,
+ ilt_client->page_size,
+ ilt_client->flags,
+ ilog2(ilt_client->page_size >> 12));
- default:
- bp->num_queues = 1;
- break;
- }
-}
+#else
+ ilt_client->flags = (ILT_CLIENT_SKIP_INIT | ILT_CLIENT_SKIP_MEM);
+#endif
+ /* TM */
+ ilt_client = &ilt->clients[ILT_CLIENT_TM];
+#ifdef BCM_CNIC
+ ilt_client->client_num = ILT_CLIENT_TM;
+ ilt_client->page_size = TM_ILT_PAGE_SZ;
+ ilt_client->flags = 0;
+ ilt_client->start = line;
+ line += TM_ILT_LINES;
+ ilt_client->end = line - 1;
+
+ DP(BNX2X_MSG_SP, "ilt client[TM]: start %d, end %d, psz 0x%x, "
+ "flags 0x%x, hw psz %d\n",
+ ilt_client->start,
+ ilt_client->end,
+ ilt_client->page_size,
+ ilt_client->flags,
+ ilog2(ilt_client->page_size >> 12));
+#else
+ ilt_client->flags = (ILT_CLIENT_SKIP_INIT | ILT_CLIENT_SKIP_MEM);
+#endif
+}
-static int bnx2x_stop_multi(struct bnx2x *bp, int index)
+int bnx2x_setup_client(struct bnx2x *bp, struct bnx2x_fastpath *fp,
+ int is_leading)
{
- struct bnx2x_fastpath *fp = &bp->fp[index];
+ struct bnx2x_client_init_params params = { {0} };
int rc;
- /* halt the connection */
- fp->state = BNX2X_FP_STATE_HALTING;
- bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, index, 0, fp->cl_id, 0);
+ bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 0,
+ IGU_INT_ENABLE, 0);
- /* Wait for completion */
- rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, index,
- &(fp->state), 1);
- if (rc) /* timeout */
- return rc;
+ params.ramrod_params.pstate = &fp->state;
+ params.ramrod_params.state = BNX2X_FP_STATE_OPEN;
+ params.ramrod_params.index = fp->index;
+ params.ramrod_params.cid = fp->cid;
- /* delete cfc entry */
- bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CFC_DEL, index, 0, 0, 1);
+ if (is_leading)
+ params.ramrod_params.flags |= CLIENT_IS_LEADING_RSS;
- /* Wait for completion */
- rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_CLOSED, index,
- &(fp->state), 1);
+ bnx2x_pf_rx_cl_prep(bp, fp, &params.pause, &params.rxq_params);
+
+ bnx2x_pf_tx_cl_prep(bp, fp, &params.txq_params);
+
+ rc = bnx2x_setup_fw_client(bp, &params, 1,
+ bnx2x_sp(bp, client_init_data),
+ bnx2x_sp_mapping(bp, client_init_data));
return rc;
}
-static int bnx2x_stop_leading(struct bnx2x *bp)
+static int bnx2x_stop_fw_client(struct bnx2x *bp,
+ struct bnx2x_client_ramrod_params *p)
{
- __le16 dsb_sp_prod_idx;
- /* if the other port is handling traffic,
- this can take a lot of time */
- int cnt = 500;
int rc;
- might_sleep();
+ int poll_flag = p->poll ? WAIT_RAMROD_POLL : 0;
- /* Send HALT ramrod */
- bp->fp[0].state = BNX2X_FP_STATE_HALTING;
- bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, 0, 0, bp->fp->cl_id, 0);
+ /* halt the connection */
+ *p->pstate = BNX2X_FP_STATE_HALTING;
+ bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, p->cid, 0,
+ p->cl_id, 0);
/* Wait for completion */
- rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, 0,
- &(bp->fp[0].state), 1);
+ rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, p->index,
+ p->pstate, poll_flag);
if (rc) /* timeout */
return rc;
- dsb_sp_prod_idx = *bp->dsb_sp_prod;
+ *p->pstate = BNX2X_FP_STATE_TERMINATING;
+ bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_TERMINATE, p->cid, 0,
+ p->cl_id, 0);
+ /* Wait for completion */
+ rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_TERMINATED, p->index,
+ p->pstate, poll_flag);
+ if (rc) /* timeout */
+ return rc;
- /* Send PORT_DELETE ramrod */
- bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_DEL, 0, 0, 0, 1);
- /* Wait for completion to arrive on default status block
- we are going to reset the chip anyway
- so there is not much to do if this times out
- */
- while (dsb_sp_prod_idx == *bp->dsb_sp_prod) {
- if (!cnt) {
- DP(NETIF_MSG_IFDOWN, "timeout waiting for port del "
- "dsb_sp_prod 0x%x != dsb_sp_prod_idx 0x%x\n",
- *bp->dsb_sp_prod, dsb_sp_prod_idx);
-#ifdef BNX2X_STOP_ON_ERROR
- bnx2x_panic();
-#endif
- rc = -EBUSY;
- break;
- }
- cnt--;
- msleep(1);
- rmb(); /* Refresh the dsb_sp_prod */
- }
- bp->state = BNX2X_STATE_CLOSING_WAIT4_UNLOAD;
- bp->fp[0].state = BNX2X_FP_STATE_CLOSED;
+ /* delete cfc entry */
+ bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_CFC_DEL, p->cid, 0, 0, 1);
+ /* Wait for completion */
+ rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_CLOSED, p->index,
+ p->pstate, WAIT_RAMROD_COMMON);
return rc;
}
+static int bnx2x_stop_client(struct bnx2x *bp, int index)
+{
+ struct bnx2x_client_ramrod_params client_stop = {0};
+ struct bnx2x_fastpath *fp = &bp->fp[index];
+
+ client_stop.index = index;
+ client_stop.cid = fp->cid;
+ client_stop.cl_id = fp->cl_id;
+ client_stop.pstate = &(fp->state);
+ client_stop.poll = 0;
+
+ return bnx2x_stop_fw_client(bp, &client_stop);
+}
+
+
static void bnx2x_reset_func(struct bnx2x *bp)
{
int port = BP_PORT(bp);
int func = BP_FUNC(bp);
- int base, i;
+ int i;
+ int pfunc_offset_fp = offsetof(struct hc_sb_data, p_func) +
+ (CHIP_IS_E2(bp) ?
+ offsetof(struct hc_status_block_data_e2, common) :
+ offsetof(struct hc_status_block_data_e1x, common));
+ int pfunc_offset_sp = offsetof(struct hc_sp_status_block_data, p_func);
+ int pfid_offset = offsetof(struct pci_entity, pf_id);
+
+ /* Disable the function in the FW */
+ REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_FUNC_EN_OFFSET(func), 0);
+ REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_FUNC_EN_OFFSET(func), 0);
+ REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_FUNC_EN_OFFSET(func), 0);
+ REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNC_EN_OFFSET(func), 0);
+
+ /* FP SBs */
+ for_each_queue(bp, i) {
+ struct bnx2x_fastpath *fp = &bp->fp[i];
+ REG_WR8(bp,
+ BAR_CSTRORM_INTMEM +
+ CSTORM_STATUS_BLOCK_DATA_OFFSET(fp->fw_sb_id)
+ + pfunc_offset_fp + pfid_offset,
+ HC_FUNCTION_DISABLED);
+ }
+
+ /* SP SB */
+ REG_WR8(bp,
+ BAR_CSTRORM_INTMEM +
+ CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func) +
+ pfunc_offset_sp + pfid_offset,
+ HC_FUNCTION_DISABLED);
+
+
+ for (i = 0; i < XSTORM_SPQ_DATA_SIZE / 4; i++)
+ REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_DATA_OFFSET(func),
+ 0);
/* Configure IGU */
- REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0);
- REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0);
+ if (bp->common.int_block == INT_BLOCK_HC) {
+ REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0);
+ REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0);
+ } else {
+ REG_WR(bp, IGU_REG_LEADING_EDGE_LATCH, 0);
+ REG_WR(bp, IGU_REG_TRAILING_EDGE_LATCH, 0);
+ }
#ifdef BCM_CNIC
/* Disable Timer scan */
@@ -5125,9 +6754,27 @@ static void bnx2x_reset_func(struct bnx2x *bp)
}
#endif
/* Clear ILT */
- base = FUNC_ILT_BASE(func);
- for (i = base; i < base + ILT_PER_FUNC; i++)
- bnx2x_ilt_wr(bp, i, 0);
+ bnx2x_clear_func_ilt(bp, func);
+
+ /* Timers workaround bug for E2: if this is vnic-3,
+ * we need to set the entire ilt range for this timers.
+ */
+ if (CHIP_IS_E2(bp) && BP_VN(bp) == 3) {
+ struct ilt_client_info ilt_cli;
+ /* use dummy TM client */
+ memset(&ilt_cli, 0, sizeof(struct ilt_client_info));
+ ilt_cli.start = 0;
+ ilt_cli.end = ILT_NUM_PAGE_ENTRIES - 1;
+ ilt_cli.client_num = ILT_CLIENT_TM;
+
+ bnx2x_ilt_boundry_init_op(bp, &ilt_cli, 0, INITOP_CLEAR);
+ }
+
+ /* this assumes that reset_port() called before reset_func()*/
+ if (CHIP_IS_E2(bp))
+ bnx2x_pf_disable(bp);
+
+ bp->dmae_ready = 0;
}
static void bnx2x_reset_port(struct bnx2x *bp)
@@ -5159,7 +6806,7 @@ static void bnx2x_reset_port(struct bnx2x *bp)
static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code)
{
DP(BNX2X_MSG_MCP, "function %d reset_code %x\n",
- BP_FUNC(bp), reset_code);
+ BP_ABS_FUNC(bp), reset_code);
switch (reset_code) {
case FW_MSG_CODE_DRV_UNLOAD_COMMON:
@@ -5196,7 +6843,6 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
cnt = 1000;
while (bnx2x_has_tx_work_unload(fp)) {
- bnx2x_tx_int(fp);
if (!cnt) {
BNX2X_ERR("timeout waiting for queue[%d]\n",
i);
@@ -5215,39 +6861,21 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
msleep(1);
if (CHIP_IS_E1(bp)) {
- struct mac_configuration_cmd *config =
- bnx2x_sp(bp, mcast_config);
-
- bnx2x_set_eth_mac_addr_e1(bp, 0);
-
- for (i = 0; i < config->hdr.length; i++)
- CAM_INVALIDATE(config->config_table[i]);
-
- config->hdr.length = i;
- if (CHIP_REV_IS_SLOW(bp))
- config->hdr.offset = BNX2X_MAX_EMUL_MULTI*(1 + port);
- else
- config->hdr.offset = BNX2X_MAX_MULTICAST*(1 + port);
- config->hdr.client_id = bp->fp->cl_id;
- config->hdr.reserved1 = 0;
-
- bp->set_mac_pending++;
- smp_wmb();
-
- bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
- U64_HI(bnx2x_sp_mapping(bp, mcast_config)),
- U64_LO(bnx2x_sp_mapping(bp, mcast_config)), 0);
+ /* invalidate mc list,
+ * wait and poll (interrupts are off)
+ */
+ bnx2x_invlidate_e1_mc_list(bp);
+ bnx2x_set_eth_mac(bp, 0);
- } else { /* E1H */
+ } else {
REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0);
- bnx2x_set_eth_mac_addr_e1h(bp, 0);
+ bnx2x_set_eth_mac(bp, 0);
for (i = 0; i < MC_HASH_SIZE; i++)
REG_WR(bp, MC_HASH_OFFSET(bp, i), 0);
-
- REG_WR(bp, MISC_REG_E1HMF_MODE, 0);
}
+
#ifdef BCM_CNIC
/* Clear iSCSI L2 MAC */
mutex_lock(&bp->cnic_mutex);
@@ -5286,33 +6914,44 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
/* Close multi and leading connections
Completions for ramrods are collected in a synchronous way */
- for_each_nondefault_queue(bp, i)
- if (bnx2x_stop_multi(bp, i))
+ for_each_queue(bp, i)
+
+ if (bnx2x_stop_client(bp, i))
+#ifdef BNX2X_STOP_ON_ERROR
+ return;
+#else
goto unload_error;
+#endif
- rc = bnx2x_stop_leading(bp);
+ rc = bnx2x_func_stop(bp);
if (rc) {
- BNX2X_ERR("Stop leading failed!\n");
+ BNX2X_ERR("Function stop failed!\n");
#ifdef BNX2X_STOP_ON_ERROR
- return -EBUSY;
+ return;
#else
goto unload_error;
#endif
}
-
+#ifndef BNX2X_STOP_ON_ERROR
unload_error:
+#endif
if (!BP_NOMCP(bp))
- reset_code = bnx2x_fw_command(bp, reset_code);
+ reset_code = bnx2x_fw_command(bp, reset_code, 0);
else {
- DP(NETIF_MSG_IFDOWN, "NO MCP - load counts %d, %d, %d\n",
- load_count[0], load_count[1], load_count[2]);
- load_count[0]--;
- load_count[1 + port]--;
- DP(NETIF_MSG_IFDOWN, "NO MCP - new load counts %d, %d, %d\n",
- load_count[0], load_count[1], load_count[2]);
- if (load_count[0] == 0)
+ DP(NETIF_MSG_IFDOWN, "NO MCP - load counts[%d] "
+ "%d, %d, %d\n", BP_PATH(bp),
+ load_count[BP_PATH(bp)][0],
+ load_count[BP_PATH(bp)][1],
+ load_count[BP_PATH(bp)][2]);
+ load_count[BP_PATH(bp)][0]--;
+ load_count[BP_PATH(bp)][1 + port]--;
+ DP(NETIF_MSG_IFDOWN, "NO MCP - new load counts[%d] "
+ "%d, %d, %d\n", BP_PATH(bp),
+ load_count[BP_PATH(bp)][0], load_count[BP_PATH(bp)][1],
+ load_count[BP_PATH(bp)][2]);
+ if (load_count[BP_PATH(bp)][0] == 0)
reset_code = FW_MSG_CODE_DRV_UNLOAD_COMMON;
- else if (load_count[1 + port] == 0)
+ else if (load_count[BP_PATH(bp)][1 + port] == 0)
reset_code = FW_MSG_CODE_DRV_UNLOAD_PORT;
else
reset_code = FW_MSG_CODE_DRV_UNLOAD_FUNCTION;
@@ -5322,12 +6961,18 @@ unload_error:
(reset_code == FW_MSG_CODE_DRV_UNLOAD_PORT))
bnx2x__link_reset(bp);
+ /* Disable HW interrupts, NAPI */
+ bnx2x_netif_stop(bp, 1);
+
+ /* Release IRQs */
+ bnx2x_free_irq(bp);
+
/* Reset the chip */
bnx2x_reset_chip(bp, reset_code);
/* Report UNLOAD_DONE to MCP */
if (!BP_NOMCP(bp))
- bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+ bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
}
@@ -5353,7 +6998,6 @@ void bnx2x_disable_close_the_gate(struct bnx2x *bp)
}
}
-
/* Close gates #2, #3 and #4: */
static void bnx2x_set_234_gates(struct bnx2x *bp, bool close)
{
@@ -5399,15 +7043,13 @@ static void bnx2x_clp_reset_prep(struct bnx2x *bp, u32 *magic_val)
static void bnx2x_clp_reset_done(struct bnx2x *bp, u32 magic_val)
{
/* Restore the `magic' bit value... */
- /* u32 val = SHMEM_RD(bp, mf_cfg.shared_mf_config.clp_mb);
- SHMEM_WR(bp, mf_cfg.shared_mf_config.clp_mb,
- (val & (~SHARED_MF_CLP_MAGIC)) | magic_val); */
u32 val = MF_CFG_RD(bp, shared_mf_config.clp_mb);
MF_CFG_WR(bp, shared_mf_config.clp_mb,
(val & (~SHARED_MF_CLP_MAGIC)) | magic_val);
}
-/* Prepares for MCP reset: takes care of CLP configurations.
+/**
+ * Prepares for MCP reset: takes care of CLP configurations.
*
* @param bp
* @param magic_val Old value of 'magic' bit.
@@ -5805,39 +7447,23 @@ reset_task_exit:
* Init service functions
*/
-static inline u32 bnx2x_get_pretend_reg(struct bnx2x *bp, int func)
-{
- switch (func) {
- case 0: return PXP2_REG_PGL_PRETEND_FUNC_F0;
- case 1: return PXP2_REG_PGL_PRETEND_FUNC_F1;
- case 2: return PXP2_REG_PGL_PRETEND_FUNC_F2;
- case 3: return PXP2_REG_PGL_PRETEND_FUNC_F3;
- case 4: return PXP2_REG_PGL_PRETEND_FUNC_F4;
- case 5: return PXP2_REG_PGL_PRETEND_FUNC_F5;
- case 6: return PXP2_REG_PGL_PRETEND_FUNC_F6;
- case 7: return PXP2_REG_PGL_PRETEND_FUNC_F7;
- default:
- BNX2X_ERR("Unsupported function index: %d\n", func);
- return (u32)(-1);
- }
+static u32 bnx2x_get_pretend_reg(struct bnx2x *bp)
+{
+ u32 base = PXP2_REG_PGL_PRETEND_FUNC_F0;
+ u32 stride = PXP2_REG_PGL_PRETEND_FUNC_F1 - base;
+ return base + (BP_ABS_FUNC(bp)) * stride;
}
-static void bnx2x_undi_int_disable_e1h(struct bnx2x *bp, int orig_func)
+static void bnx2x_undi_int_disable_e1h(struct bnx2x *bp)
{
- u32 reg = bnx2x_get_pretend_reg(bp, orig_func), new_val;
+ u32 reg = bnx2x_get_pretend_reg(bp);
/* Flush all outstanding writes */
mmiowb();
/* Pretend to be function 0 */
REG_WR(bp, reg, 0);
- /* Flush the GRC transaction (in the chip) */
- new_val = REG_RD(bp, reg);
- if (new_val != 0) {
- BNX2X_ERR("Hmmm... Pretend register wasn't updated: (0,%d)!\n",
- new_val);
- BUG();
- }
+ REG_RD(bp, reg); /* Flush the GRC transaction (in the chip) */
/* From now we are in the "like-E1" mode */
bnx2x_int_disable(bp);
@@ -5845,22 +7471,17 @@ static void bnx2x_undi_int_disable_e1h(struct bnx2x *bp, int orig_func)
/* Flush all outstanding writes */
mmiowb();
- /* Restore the original funtion settings */
- REG_WR(bp, reg, orig_func);
- new_val = REG_RD(bp, reg);
- if (new_val != orig_func) {
- BNX2X_ERR("Hmmm... Pretend register wasn't updated: (%d,%d)!\n",
- orig_func, new_val);
- BUG();
- }
+ /* Restore the original function */
+ REG_WR(bp, reg, BP_ABS_FUNC(bp));
+ REG_RD(bp, reg);
}
-static inline void bnx2x_undi_int_disable(struct bnx2x *bp, int func)
+static inline void bnx2x_undi_int_disable(struct bnx2x *bp)
{
- if (CHIP_IS_E1H(bp))
- bnx2x_undi_int_disable_e1h(bp, func);
- else
+ if (CHIP_IS_E1(bp))
bnx2x_int_disable(bp);
+ else
+ bnx2x_undi_int_disable_e1h(bp);
}
static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
@@ -5877,8 +7498,8 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
val = REG_RD(bp, DORQ_REG_NORM_CID_OFST);
if (val == 0x7) {
u32 reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
- /* save our func */
- int func = BP_FUNC(bp);
+ /* save our pf_num */
+ int orig_pf_num = bp->pf_num;
u32 swap_en;
u32 swap_val;
@@ -5888,32 +7509,33 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
BNX2X_DEV_INFO("UNDI is active! reset device\n");
/* try unload UNDI on port 0 */
- bp->func = 0;
+ bp->pf_num = 0;
bp->fw_seq =
- (SHMEM_RD(bp, func_mb[bp->func].drv_mb_header) &
+ (SHMEM_RD(bp, func_mb[bp->pf_num].drv_mb_header) &
DRV_MSG_SEQ_NUMBER_MASK);
- reset_code = bnx2x_fw_command(bp, reset_code);
+ reset_code = bnx2x_fw_command(bp, reset_code, 0);
/* if UNDI is loaded on the other port */
if (reset_code != FW_MSG_CODE_DRV_UNLOAD_COMMON) {
/* send "DONE" for previous unload */
- bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+ bnx2x_fw_command(bp,
+ DRV_MSG_CODE_UNLOAD_DONE, 0);
/* unload UNDI on port 1 */
- bp->func = 1;
+ bp->pf_num = 1;
bp->fw_seq =
- (SHMEM_RD(bp, func_mb[bp->func].drv_mb_header) &
+ (SHMEM_RD(bp, func_mb[bp->pf_num].drv_mb_header) &
DRV_MSG_SEQ_NUMBER_MASK);
reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
- bnx2x_fw_command(bp, reset_code);
+ 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, func);
+ bnx2x_undi_int_disable(bp);
/* close input traffic and wait for it */
/* Do not rcv packets to BRB */
@@ -5949,14 +7571,13 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
REG_WR(bp, NIG_REG_STRAP_OVERRIDE, swap_en);
/* send unload done to the MCP */
- bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+ bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
/* restore our func and fw_seq */
- bp->func = func;
+ bp->pf_num = orig_pf_num;
bp->fw_seq =
- (SHMEM_RD(bp, func_mb[bp->func].drv_mb_header) &
+ (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);
}
@@ -5978,6 +7599,40 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
val = REG_RD(bp, MISC_REG_BOND_ID);
id |= (val & 0xf);
bp->common.chip_id = id;
+
+ /* Set doorbell size */
+ bp->db_size = (1 << BNX2X_DB_SHIFT);
+
+ if (CHIP_IS_E2(bp)) {
+ val = REG_RD(bp, MISC_REG_PORT4MODE_EN_OVWR);
+ if ((val & 1) == 0)
+ val = REG_RD(bp, MISC_REG_PORT4MODE_EN);
+ else
+ val = (val >> 1) & 1;
+ BNX2X_DEV_INFO("chip is in %s\n", val ? "4_PORT_MODE" :
+ "2_PORT_MODE");
+ bp->common.chip_port_mode = val ? CHIP_4_PORT_MODE :
+ CHIP_2_PORT_MODE;
+
+ if (CHIP_MODE_IS_4_PORT(bp))
+ bp->pfid = (bp->pf_num >> 1); /* 0..3 */
+ else
+ bp->pfid = (bp->pf_num & 0x6); /* 0, 2, 4, 6 */
+ } else {
+ bp->common.chip_port_mode = CHIP_PORT_MODE_NONE; /* N/A */
+ bp->pfid = bp->pf_num; /* 0..7 */
+ }
+
+ /*
+ * set base FW non-default (fast path) status block id, this value is
+ * used to initialize the fw_sb_id saved on the fp/queue structure to
+ * determine the id used by the FW.
+ */
+ if (CHIP_IS_E1x(bp))
+ bp->base_fw_ndsb = BP_PORT(bp) * FP_SB_MAX_E1x;
+ else /* E2 */
+ bp->base_fw_ndsb = BP_PORT(bp) * FP_SB_MAX_E2;
+
bp->link_params.chip_id = bp->common.chip_id;
BNX2X_DEV_INFO("chip ID is 0x%x\n", id);
@@ -5995,14 +7650,15 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
bp->common.flash_size, bp->common.flash_size);
bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
- bp->common.shmem2_base = REG_RD(bp, MISC_REG_GENERIC_CR_0);
+ bp->common.shmem2_base = REG_RD(bp, (BP_PATH(bp) ?
+ MISC_REG_GENERIC_CR_1 :
+ MISC_REG_GENERIC_CR_0));
bp->link_params.shmem_base = bp->common.shmem_base;
+ bp->link_params.shmem2_base = bp->common.shmem2_base;
BNX2X_DEV_INFO("shmem offset 0x%x shmem2 offset 0x%x\n",
bp->common.shmem_base, bp->common.shmem2_base);
- if (!bp->common.shmem_base ||
- (bp->common.shmem_base < 0xA0000) ||
- (bp->common.shmem_base >= 0xC0000)) {
+ if (!bp->common.shmem_base) {
BNX2X_DEV_INFO("MCP not active\n");
bp->flags |= NO_MCP_FLAG;
return;
@@ -6011,7 +7667,7 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]);
if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
!= (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
- BNX2X_ERROR("BAD MCP validity signature\n");
+ BNX2X_ERR("BAD MCP validity signature\n");
bp->common.hw_config = SHMEM_RD(bp, dev_info.shared_hw_config.config);
BNX2X_DEV_INFO("hw_config 0x%08x\n", bp->common.hw_config);
@@ -6035,12 +7691,16 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
if (val < BNX2X_BC_VER) {
/* for now only warn
* later we might need to enforce this */
- BNX2X_ERROR("This driver needs bc_ver %X but found %X, "
- "please upgrade BC\n", BNX2X_BC_VER, val);
+ BNX2X_ERR("This driver needs bc_ver %X but found %X, "
+ "please upgrade BC\n", BNX2X_BC_VER, val);
}
bp->link_params.feature_config_flags |=
- (val >= REQ_BC_VER_4_VRFY_OPT_MDL) ?
- FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY : 0;
+ (val >= REQ_BC_VER_4_VRFY_FIRST_PHY_OPT_MDL) ?
+ FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY : 0;
+
+ bp->link_params.feature_config_flags |=
+ (val >= REQ_BC_VER_4_VRFY_SPECIFIC_PHY_OPT_MDL) ?
+ FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY : 0;
if (BP_E1HVN(bp) == 0) {
pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc);
@@ -6061,404 +7721,348 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
val, val2, val3, val4);
}
+#define IGU_FID(val) GET_FIELD((val), IGU_REG_MAPPING_MEMORY_FID)
+#define IGU_VEC(val) GET_FIELD((val), IGU_REG_MAPPING_MEMORY_VECTOR)
+
+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;
+
+ bp->igu_base_sb = 0xff;
+ bp->igu_sb_cnt = 0;
+ if (CHIP_INT_MODE_IS_BC(bp)) {
+ bp->igu_sb_cnt = min_t(u8, FP_SB_MAX_E1x,
+ bp->l2_cid_count);
+
+ bp->igu_base_sb = (CHIP_MODE_IS_4_PORT(bp) ? pfid : vn) *
+ FP_SB_MAX_E1x;
+
+ bp->igu_dsb_id = E1HVN_MAX * FP_SB_MAX_E1x +
+ (CHIP_MODE_IS_4_PORT(bp) ? pfid : vn);
+
+ return;
+ }
+
+ /* IGU in normal mode - read CAM */
+ for (igu_sb_id = 0; igu_sb_id < IGU_REG_MAPPING_MEMORY_SIZE;
+ igu_sb_id++) {
+ val = REG_RD(bp, IGU_REG_MAPPING_MEMORY + igu_sb_id * 4);
+ if (!(val & IGU_REG_MAPPING_MEMORY_VALID))
+ continue;
+ fid = IGU_FID(val);
+ if ((fid & IGU_FID_ENCODE_IS_PF)) {
+ if ((fid & IGU_FID_PF_NUM_MASK) != pfid)
+ continue;
+ if (IGU_VEC(val) == 0)
+ /* default status block */
+ bp->igu_dsb_id = igu_sb_id;
+ else {
+ if (bp->igu_base_sb == 0xff)
+ bp->igu_base_sb = igu_sb_id;
+ bp->igu_sb_cnt++;
+ }
+ }
+ }
+ bp->igu_sb_cnt = min_t(u8, bp->igu_sb_cnt, bp->l2_cid_count);
+ if (bp->igu_sb_cnt == 0)
+ BNX2X_ERR("CAM configuration error\n");
+}
+
static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
u32 switch_cfg)
{
- int port = BP_PORT(bp);
- u32 ext_phy_type;
-
- switch (switch_cfg) {
- case SWITCH_CFG_1G:
- BNX2X_DEV_INFO("switch_cfg 0x%x (1G)\n", switch_cfg);
-
- ext_phy_type =
- SERDES_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
- switch (ext_phy_type) {
- case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
- BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n",
- ext_phy_type);
-
- bp->port.supported |= (SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full |
- SUPPORTED_100baseT_Half |
- SUPPORTED_100baseT_Full |
- SUPPORTED_1000baseT_Full |
- SUPPORTED_2500baseX_Full |
- SUPPORTED_TP |
- SUPPORTED_FIBRE |
- SUPPORTED_Autoneg |
- SUPPORTED_Pause |
- SUPPORTED_Asym_Pause);
- break;
+ int cfg_size = 0, idx, port = BP_PORT(bp);
- case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
- BNX2X_DEV_INFO("ext_phy_type 0x%x (5482)\n",
- ext_phy_type);
-
- bp->port.supported |= (SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full |
- SUPPORTED_100baseT_Half |
- SUPPORTED_100baseT_Full |
- SUPPORTED_1000baseT_Full |
- SUPPORTED_TP |
- SUPPORTED_FIBRE |
- SUPPORTED_Autoneg |
- SUPPORTED_Pause |
- SUPPORTED_Asym_Pause);
- break;
+ /* Aggregation of supported attributes of all external phys */
+ bp->port.supported[0] = 0;
+ bp->port.supported[1] = 0;
+ switch (bp->link_params.num_phys) {
+ case 1:
+ bp->port.supported[0] = bp->link_params.phy[INT_PHY].supported;
+ cfg_size = 1;
+ break;
+ case 2:
+ bp->port.supported[0] = bp->link_params.phy[EXT_PHY1].supported;
+ cfg_size = 1;
+ break;
+ case 3:
+ if (bp->link_params.multi_phy_config &
+ PORT_HW_CFG_PHY_SWAPPED_ENABLED) {
+ bp->port.supported[1] =
+ bp->link_params.phy[EXT_PHY1].supported;
+ bp->port.supported[0] =
+ bp->link_params.phy[EXT_PHY2].supported;
+ } else {
+ bp->port.supported[0] =
+ bp->link_params.phy[EXT_PHY1].supported;
+ bp->port.supported[1] =
+ bp->link_params.phy[EXT_PHY2].supported;
+ }
+ cfg_size = 2;
+ break;
+ }
- default:
- BNX2X_ERR("NVRAM config error. "
- "BAD SerDes ext_phy_config 0x%x\n",
- bp->link_params.ext_phy_config);
+ if (!(bp->port.supported[0] || bp->port.supported[1])) {
+ BNX2X_ERR("NVRAM config error. BAD phy config."
+ "PHY1 config 0x%x, PHY2 config 0x%x\n",
+ SHMEM_RD(bp,
+ dev_info.port_hw_config[port].external_phy_config),
+ SHMEM_RD(bp,
+ dev_info.port_hw_config[port].external_phy_config2));
return;
- }
+ }
+ switch (switch_cfg) {
+ case SWITCH_CFG_1G:
bp->port.phy_addr = REG_RD(bp, NIG_REG_SERDES0_CTRL_PHY_ADDR +
port*0x10);
BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr);
break;
case SWITCH_CFG_10G:
- BNX2X_DEV_INFO("switch_cfg 0x%x (10G)\n", switch_cfg);
-
- ext_phy_type =
- XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
- switch (ext_phy_type) {
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
- BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n",
- ext_phy_type);
-
- bp->port.supported |= (SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full |
- SUPPORTED_100baseT_Half |
- SUPPORTED_100baseT_Full |
- SUPPORTED_1000baseT_Full |
- SUPPORTED_2500baseX_Full |
- SUPPORTED_10000baseT_Full |
- SUPPORTED_TP |
- SUPPORTED_FIBRE |
- SUPPORTED_Autoneg |
- SUPPORTED_Pause |
- SUPPORTED_Asym_Pause);
- break;
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
- BNX2X_DEV_INFO("ext_phy_type 0x%x (8072)\n",
- ext_phy_type);
-
- bp->port.supported |= (SUPPORTED_10000baseT_Full |
- SUPPORTED_1000baseT_Full |
- SUPPORTED_FIBRE |
- SUPPORTED_Autoneg |
- SUPPORTED_Pause |
- SUPPORTED_Asym_Pause);
- break;
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
- BNX2X_DEV_INFO("ext_phy_type 0x%x (8073)\n",
- ext_phy_type);
-
- bp->port.supported |= (SUPPORTED_10000baseT_Full |
- SUPPORTED_2500baseX_Full |
- SUPPORTED_1000baseT_Full |
- SUPPORTED_FIBRE |
- SUPPORTED_Autoneg |
- SUPPORTED_Pause |
- SUPPORTED_Asym_Pause);
- break;
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
- BNX2X_DEV_INFO("ext_phy_type 0x%x (8705)\n",
- ext_phy_type);
-
- bp->port.supported |= (SUPPORTED_10000baseT_Full |
- SUPPORTED_FIBRE |
- SUPPORTED_Pause |
- SUPPORTED_Asym_Pause);
- break;
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
- BNX2X_DEV_INFO("ext_phy_type 0x%x (8706)\n",
- ext_phy_type);
-
- bp->port.supported |= (SUPPORTED_10000baseT_Full |
- SUPPORTED_1000baseT_Full |
- SUPPORTED_FIBRE |
- SUPPORTED_Pause |
- SUPPORTED_Asym_Pause);
- break;
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
- BNX2X_DEV_INFO("ext_phy_type 0x%x (8726)\n",
- ext_phy_type);
-
- bp->port.supported |= (SUPPORTED_10000baseT_Full |
- SUPPORTED_1000baseT_Full |
- SUPPORTED_Autoneg |
- SUPPORTED_FIBRE |
- SUPPORTED_Pause |
- SUPPORTED_Asym_Pause);
- break;
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
- BNX2X_DEV_INFO("ext_phy_type 0x%x (8727)\n",
- ext_phy_type);
-
- bp->port.supported |= (SUPPORTED_10000baseT_Full |
- SUPPORTED_1000baseT_Full |
- SUPPORTED_Autoneg |
- SUPPORTED_FIBRE |
- SUPPORTED_Pause |
- SUPPORTED_Asym_Pause);
- break;
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
- BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n",
- ext_phy_type);
-
- bp->port.supported |= (SUPPORTED_10000baseT_Full |
- SUPPORTED_TP |
- SUPPORTED_Autoneg |
- SUPPORTED_Pause |
- SUPPORTED_Asym_Pause);
- break;
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
- BNX2X_DEV_INFO("ext_phy_type 0x%x (BCM8481)\n",
- ext_phy_type);
-
- bp->port.supported |= (SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full |
- SUPPORTED_100baseT_Half |
- SUPPORTED_100baseT_Full |
- SUPPORTED_1000baseT_Full |
- SUPPORTED_10000baseT_Full |
- SUPPORTED_TP |
- SUPPORTED_Autoneg |
- SUPPORTED_Pause |
- SUPPORTED_Asym_Pause);
- break;
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
- BNX2X_ERR("XGXS PHY Failure detected 0x%x\n",
- bp->link_params.ext_phy_config);
- break;
-
- default:
- BNX2X_ERR("NVRAM config error. "
- "BAD XGXS ext_phy_config 0x%x\n",
- bp->link_params.ext_phy_config);
- return;
- }
-
bp->port.phy_addr = REG_RD(bp, NIG_REG_XGXS0_CTRL_PHY_ADDR +
port*0x18);
BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr);
-
break;
default:
BNX2X_ERR("BAD switch_cfg link_config 0x%x\n",
- bp->port.link_config);
+ bp->port.link_config[0]);
return;
}
- bp->link_params.phy_addr = bp->port.phy_addr;
-
- /* mask what we support according to speed_cap_mask */
- if (!(bp->link_params.speed_cap_mask &
+ /* mask what we support according to speed_cap_mask per configuration */
+ for (idx = 0; idx < cfg_size; idx++) {
+ if (!(bp->link_params.speed_cap_mask[idx] &
PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF))
- bp->port.supported &= ~SUPPORTED_10baseT_Half;
+ bp->port.supported[idx] &= ~SUPPORTED_10baseT_Half;
- if (!(bp->link_params.speed_cap_mask &
+ if (!(bp->link_params.speed_cap_mask[idx] &
PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL))
- bp->port.supported &= ~SUPPORTED_10baseT_Full;
+ bp->port.supported[idx] &= ~SUPPORTED_10baseT_Full;
- if (!(bp->link_params.speed_cap_mask &
+ if (!(bp->link_params.speed_cap_mask[idx] &
PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF))
- bp->port.supported &= ~SUPPORTED_100baseT_Half;
+ bp->port.supported[idx] &= ~SUPPORTED_100baseT_Half;
- if (!(bp->link_params.speed_cap_mask &
+ if (!(bp->link_params.speed_cap_mask[idx] &
PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL))
- bp->port.supported &= ~SUPPORTED_100baseT_Full;
+ bp->port.supported[idx] &= ~SUPPORTED_100baseT_Full;
- if (!(bp->link_params.speed_cap_mask &
+ if (!(bp->link_params.speed_cap_mask[idx] &
PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))
- bp->port.supported &= ~(SUPPORTED_1000baseT_Half |
- SUPPORTED_1000baseT_Full);
+ bp->port.supported[idx] &= ~(SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full);
- if (!(bp->link_params.speed_cap_mask &
+ if (!(bp->link_params.speed_cap_mask[idx] &
PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
- bp->port.supported &= ~SUPPORTED_2500baseX_Full;
+ bp->port.supported[idx] &= ~SUPPORTED_2500baseX_Full;
- if (!(bp->link_params.speed_cap_mask &
+ if (!(bp->link_params.speed_cap_mask[idx] &
PORT_HW_CFG_SPEED_CAPABILITY_D0_10G))
- bp->port.supported &= ~SUPPORTED_10000baseT_Full;
+ bp->port.supported[idx] &= ~SUPPORTED_10000baseT_Full;
+
+ }
- BNX2X_DEV_INFO("supported 0x%x\n", bp->port.supported);
+ BNX2X_DEV_INFO("supported 0x%x 0x%x\n", bp->port.supported[0],
+ bp->port.supported[1]);
}
static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
{
- bp->link_params.req_duplex = DUPLEX_FULL;
+ u32 link_config, idx, cfg_size = 0;
+ bp->port.advertising[0] = 0;
+ bp->port.advertising[1] = 0;
+ switch (bp->link_params.num_phys) {
+ case 1:
+ case 2:
+ cfg_size = 1;
+ break;
+ case 3:
+ cfg_size = 2;
+ break;
+ }
+ for (idx = 0; idx < cfg_size; idx++) {
+ bp->link_params.req_duplex[idx] = DUPLEX_FULL;
+ link_config = bp->port.link_config[idx];
+ switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
+ case PORT_FEATURE_LINK_SPEED_AUTO:
+ if (bp->port.supported[idx] & SUPPORTED_Autoneg) {
+ bp->link_params.req_line_speed[idx] =
+ SPEED_AUTO_NEG;
+ bp->port.advertising[idx] |=
+ bp->port.supported[idx];
+ } else {
+ /* force 10G, no AN */
+ bp->link_params.req_line_speed[idx] =
+ SPEED_10000;
+ bp->port.advertising[idx] |=
+ (ADVERTISED_10000baseT_Full |
+ ADVERTISED_FIBRE);
+ continue;
+ }
+ break;
- switch (bp->port.link_config & PORT_FEATURE_LINK_SPEED_MASK) {
- case PORT_FEATURE_LINK_SPEED_AUTO:
- if (bp->port.supported & SUPPORTED_Autoneg) {
- bp->link_params.req_line_speed = SPEED_AUTO_NEG;
- bp->port.advertising = bp->port.supported;
- } else {
- u32 ext_phy_type =
- XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+ case PORT_FEATURE_LINK_SPEED_10M_FULL:
+ if (bp->port.supported[idx] & SUPPORTED_10baseT_Full) {
+ bp->link_params.req_line_speed[idx] =
+ SPEED_10;
+ bp->port.advertising[idx] |=
+ (ADVERTISED_10baseT_Full |
+ ADVERTISED_TP);
+ } else {
+ BNX2X_ERROR("NVRAM config error. "
+ "Invalid link_config 0x%x"
+ " speed_cap_mask 0x%x\n",
+ link_config,
+ bp->link_params.speed_cap_mask[idx]);
+ return;
+ }
+ break;
- if ((ext_phy_type ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
- (ext_phy_type ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706)) {
- /* force 10G, no AN */
- bp->link_params.req_line_speed = SPEED_10000;
- bp->port.advertising =
- (ADVERTISED_10000baseT_Full |
- ADVERTISED_FIBRE);
- break;
+ case PORT_FEATURE_LINK_SPEED_10M_HALF:
+ if (bp->port.supported[idx] & SUPPORTED_10baseT_Half) {
+ bp->link_params.req_line_speed[idx] =
+ SPEED_10;
+ bp->link_params.req_duplex[idx] =
+ DUPLEX_HALF;
+ bp->port.advertising[idx] |=
+ (ADVERTISED_10baseT_Half |
+ ADVERTISED_TP);
+ } else {
+ BNX2X_ERROR("NVRAM config error. "
+ "Invalid link_config 0x%x"
+ " speed_cap_mask 0x%x\n",
+ link_config,
+ bp->link_params.speed_cap_mask[idx]);
+ return;
}
- BNX2X_ERR("NVRAM config error. "
- "Invalid link_config 0x%x"
- " Autoneg not supported\n",
- bp->port.link_config);
- return;
- }
- break;
+ break;
- case PORT_FEATURE_LINK_SPEED_10M_FULL:
- if (bp->port.supported & SUPPORTED_10baseT_Full) {
- bp->link_params.req_line_speed = SPEED_10;
- bp->port.advertising = (ADVERTISED_10baseT_Full |
- ADVERTISED_TP);
- } else {
- BNX2X_ERROR("NVRAM config error. "
- "Invalid link_config 0x%x"
- " speed_cap_mask 0x%x\n",
- bp->port.link_config,
- bp->link_params.speed_cap_mask);
- return;
- }
- break;
+ case PORT_FEATURE_LINK_SPEED_100M_FULL:
+ if (bp->port.supported[idx] &
+ SUPPORTED_100baseT_Full) {
+ bp->link_params.req_line_speed[idx] =
+ SPEED_100;
+ bp->port.advertising[idx] |=
+ (ADVERTISED_100baseT_Full |
+ ADVERTISED_TP);
+ } else {
+ BNX2X_ERROR("NVRAM config error. "
+ "Invalid link_config 0x%x"
+ " speed_cap_mask 0x%x\n",
+ link_config,
+ bp->link_params.speed_cap_mask[idx]);
+ return;
+ }
+ break;
- case PORT_FEATURE_LINK_SPEED_10M_HALF:
- if (bp->port.supported & SUPPORTED_10baseT_Half) {
- bp->link_params.req_line_speed = SPEED_10;
- bp->link_params.req_duplex = DUPLEX_HALF;
- bp->port.advertising = (ADVERTISED_10baseT_Half |
- ADVERTISED_TP);
- } else {
- BNX2X_ERROR("NVRAM config error. "
+ case PORT_FEATURE_LINK_SPEED_100M_HALF:
+ if (bp->port.supported[idx] &
+ SUPPORTED_100baseT_Half) {
+ bp->link_params.req_line_speed[idx] =
+ SPEED_100;
+ bp->link_params.req_duplex[idx] =
+ DUPLEX_HALF;
+ bp->port.advertising[idx] |=
+ (ADVERTISED_100baseT_Half |
+ ADVERTISED_TP);
+ } else {
+ BNX2X_ERROR("NVRAM config error. "
"Invalid link_config 0x%x"
" speed_cap_mask 0x%x\n",
- bp->port.link_config,
- bp->link_params.speed_cap_mask);
- return;
- }
- break;
+ link_config,
+ bp->link_params.speed_cap_mask[idx]);
+ return;
+ }
+ break;
- case PORT_FEATURE_LINK_SPEED_100M_FULL:
- if (bp->port.supported & SUPPORTED_100baseT_Full) {
- bp->link_params.req_line_speed = SPEED_100;
- bp->port.advertising = (ADVERTISED_100baseT_Full |
- ADVERTISED_TP);
- } else {
- BNX2X_ERROR("NVRAM config error. "
+ case PORT_FEATURE_LINK_SPEED_1G:
+ if (bp->port.supported[idx] &
+ SUPPORTED_1000baseT_Full) {
+ bp->link_params.req_line_speed[idx] =
+ SPEED_1000;
+ bp->port.advertising[idx] |=
+ (ADVERTISED_1000baseT_Full |
+ ADVERTISED_TP);
+ } else {
+ BNX2X_ERROR("NVRAM config error. "
"Invalid link_config 0x%x"
" speed_cap_mask 0x%x\n",
- bp->port.link_config,
- bp->link_params.speed_cap_mask);
- return;
- }
- break;
+ link_config,
+ bp->link_params.speed_cap_mask[idx]);
+ return;
+ }
+ break;
- case PORT_FEATURE_LINK_SPEED_100M_HALF:
- if (bp->port.supported & SUPPORTED_100baseT_Half) {
- bp->link_params.req_line_speed = SPEED_100;
- bp->link_params.req_duplex = DUPLEX_HALF;
- bp->port.advertising = (ADVERTISED_100baseT_Half |
+ case PORT_FEATURE_LINK_SPEED_2_5G:
+ if (bp->port.supported[idx] &
+ SUPPORTED_2500baseX_Full) {
+ bp->link_params.req_line_speed[idx] =
+ SPEED_2500;
+ bp->port.advertising[idx] |=
+ (ADVERTISED_2500baseX_Full |
ADVERTISED_TP);
- } else {
- BNX2X_ERROR("NVRAM config error. "
+ } else {
+ BNX2X_ERROR("NVRAM config error. "
"Invalid link_config 0x%x"
" speed_cap_mask 0x%x\n",
- bp->port.link_config,
- bp->link_params.speed_cap_mask);
- return;
- }
- break;
+ link_config,
+ bp->link_params.speed_cap_mask[idx]);
+ return;
+ }
+ break;
- case PORT_FEATURE_LINK_SPEED_1G:
- if (bp->port.supported & SUPPORTED_1000baseT_Full) {
- bp->link_params.req_line_speed = SPEED_1000;
- bp->port.advertising = (ADVERTISED_1000baseT_Full |
- ADVERTISED_TP);
- } else {
- BNX2X_ERROR("NVRAM config error. "
+ case PORT_FEATURE_LINK_SPEED_10G_CX4:
+ case PORT_FEATURE_LINK_SPEED_10G_KX4:
+ case PORT_FEATURE_LINK_SPEED_10G_KR:
+ if (bp->port.supported[idx] &
+ SUPPORTED_10000baseT_Full) {
+ bp->link_params.req_line_speed[idx] =
+ SPEED_10000;
+ bp->port.advertising[idx] |=
+ (ADVERTISED_10000baseT_Full |
+ ADVERTISED_FIBRE);
+ } else {
+ BNX2X_ERROR("NVRAM config error. "
"Invalid link_config 0x%x"
" speed_cap_mask 0x%x\n",
- bp->port.link_config,
- bp->link_params.speed_cap_mask);
- return;
- }
- break;
+ link_config,
+ bp->link_params.speed_cap_mask[idx]);
+ return;
+ }
+ break;
- case PORT_FEATURE_LINK_SPEED_2_5G:
- if (bp->port.supported & SUPPORTED_2500baseX_Full) {
- bp->link_params.req_line_speed = SPEED_2500;
- bp->port.advertising = (ADVERTISED_2500baseX_Full |
- ADVERTISED_TP);
- } else {
+ default:
BNX2X_ERROR("NVRAM config error. "
- "Invalid link_config 0x%x"
- " speed_cap_mask 0x%x\n",
- bp->port.link_config,
- bp->link_params.speed_cap_mask);
- return;
+ "BAD link speed link_config 0x%x\n",
+ link_config);
+ bp->link_params.req_line_speed[idx] =
+ SPEED_AUTO_NEG;
+ bp->port.advertising[idx] =
+ bp->port.supported[idx];
+ break;
}
- break;
- case PORT_FEATURE_LINK_SPEED_10G_CX4:
- case PORT_FEATURE_LINK_SPEED_10G_KX4:
- case PORT_FEATURE_LINK_SPEED_10G_KR:
- if (bp->port.supported & SUPPORTED_10000baseT_Full) {
- bp->link_params.req_line_speed = SPEED_10000;
- bp->port.advertising = (ADVERTISED_10000baseT_Full |
- ADVERTISED_FIBRE);
- } else {
- BNX2X_ERROR("NVRAM config error. "
- "Invalid link_config 0x%x"
- " speed_cap_mask 0x%x\n",
- bp->port.link_config,
- bp->link_params.speed_cap_mask);
- return;
+ bp->link_params.req_flow_ctrl[idx] = (link_config &
+ PORT_FEATURE_FLOW_CONTROL_MASK);
+ if ((bp->link_params.req_flow_ctrl[idx] ==
+ BNX2X_FLOW_CTRL_AUTO) &&
+ !(bp->port.supported[idx] & SUPPORTED_Autoneg)) {
+ bp->link_params.req_flow_ctrl[idx] =
+ BNX2X_FLOW_CTRL_NONE;
}
- break;
- default:
- BNX2X_ERROR("NVRAM config error. "
- "BAD link speed link_config 0x%x\n",
- bp->port.link_config);
- bp->link_params.req_line_speed = SPEED_AUTO_NEG;
- bp->port.advertising = bp->port.supported;
- break;
+ BNX2X_DEV_INFO("req_line_speed %d req_duplex %d req_flow_ctrl"
+ " 0x%x advertising 0x%x\n",
+ bp->link_params.req_line_speed[idx],
+ bp->link_params.req_duplex[idx],
+ bp->link_params.req_flow_ctrl[idx],
+ bp->port.advertising[idx]);
}
-
- bp->link_params.req_flow_ctrl = (bp->port.link_config &
- PORT_FEATURE_FLOW_CONTROL_MASK);
- if ((bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
- !(bp->port.supported & SUPPORTED_Autoneg))
- bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
-
- BNX2X_DEV_INFO("req_line_speed %d req_duplex %d req_flow_ctrl 0x%x"
- " advertising 0x%x\n",
- bp->link_params.req_line_speed,
- bp->link_params.req_duplex,
- bp->link_params.req_flow_ctrl, bp->port.advertising);
}
static void __devinit bnx2x_set_mac_buf(u8 *mac_buf, u32 mac_lo, u16 mac_hi)
@@ -6474,48 +8078,28 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
int port = BP_PORT(bp);
u32 val, val2;
u32 config;
- u16 i;
- u32 ext_phy_type;
+ u32 ext_phy_type, ext_phy_config;;
bp->link_params.bp = bp;
bp->link_params.port = port;
bp->link_params.lane_config =
SHMEM_RD(bp, dev_info.port_hw_config[port].lane_config);
- bp->link_params.ext_phy_config =
- SHMEM_RD(bp,
- dev_info.port_hw_config[port].external_phy_config);
- /* BCM8727_NOC => BCM8727 no over current */
- if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC) {
- bp->link_params.ext_phy_config &=
- ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
- bp->link_params.ext_phy_config |=
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727;
- bp->link_params.feature_config_flags |=
- FEATURE_CONFIG_BCM8727_NOC;
- }
- bp->link_params.speed_cap_mask =
+ bp->link_params.speed_cap_mask[0] =
SHMEM_RD(bp,
dev_info.port_hw_config[port].speed_capability_mask);
-
- bp->port.link_config =
+ bp->link_params.speed_cap_mask[1] =
+ SHMEM_RD(bp,
+ dev_info.port_hw_config[port].speed_capability_mask2);
+ bp->port.link_config[0] =
SHMEM_RD(bp, dev_info.port_feature_config[port].link_config);
- /* Get the 4 lanes xgxs config rx and tx */
- for (i = 0; i < 2; i++) {
- val = SHMEM_RD(bp,
- dev_info.port_hw_config[port].xgxs_config_rx[i<<1]);
- bp->link_params.xgxs_config_rx[i << 1] = ((val>>16) & 0xffff);
- bp->link_params.xgxs_config_rx[(i << 1) + 1] = (val & 0xffff);
-
- val = SHMEM_RD(bp,
- dev_info.port_hw_config[port].xgxs_config_tx[i<<1]);
- bp->link_params.xgxs_config_tx[i << 1] = ((val>>16) & 0xffff);
- bp->link_params.xgxs_config_tx[(i << 1) + 1] = (val & 0xffff);
- }
+ bp->port.link_config[1] =
+ SHMEM_RD(bp, dev_info.port_feature_config[port].link_config2);
+ bp->link_params.multi_phy_config =
+ SHMEM_RD(bp, dev_info.port_hw_config[port].multi_phy_config);
/* If the device is capable of WoL, set the default state according
* to the HW
*/
@@ -6523,14 +8107,15 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
bp->wol = (!(bp->flags & NO_WOL_FLAG) &&
(config & PORT_FEATURE_WOL_ENABLED));
- BNX2X_DEV_INFO("lane_config 0x%08x ext_phy_config 0x%08x"
- " speed_cap_mask 0x%08x link_config 0x%08x\n",
+ BNX2X_DEV_INFO("lane_config 0x%08x "
+ "speed_cap_mask0 0x%08x link_config0 0x%08x\n",
bp->link_params.lane_config,
- bp->link_params.ext_phy_config,
- bp->link_params.speed_cap_mask, bp->port.link_config);
+ bp->link_params.speed_cap_mask[0],
+ bp->port.link_config[0]);
- bp->link_params.switch_cfg |= (bp->port.link_config &
- PORT_FEATURE_CONNECTED_SWITCH_MASK);
+ bp->link_params.switch_cfg = (bp->port.link_config[0] &
+ PORT_FEATURE_CONNECTED_SWITCH_MASK);
+ bnx2x_phy_probe(&bp->link_params);
bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg);
bnx2x_link_settings_requested(bp);
@@ -6539,14 +8124,17 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
* If connected directly, work with the internal PHY, otherwise, work
* with the external PHY
*/
- ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+ ext_phy_config =
+ SHMEM_RD(bp,
+ dev_info.port_hw_config[port].external_phy_config);
+ ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
- bp->mdio.prtad = bp->link_params.phy_addr;
+ bp->mdio.prtad = bp->port.phy_addr;
else if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
(ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN))
bp->mdio.prtad =
- XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config);
+ XGXS_EXT_PHY_ADDR(ext_phy_config);
val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper);
val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower);
@@ -6563,41 +8151,74 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
{
- int func = BP_FUNC(bp);
+ int func = BP_ABS_FUNC(bp);
+ int vn;
u32 val, val2;
int rc = 0;
bnx2x_get_common_hwinfo(bp);
- bp->e1hov = 0;
- bp->e1hmf = 0;
- if (CHIP_IS_E1H(bp) && !BP_NOMCP(bp)) {
- bp->mf_config =
- SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
+ if (CHIP_IS_E1x(bp)) {
+ bp->common.int_block = INT_BLOCK_HC;
+
+ bp->igu_dsb_id = DEF_SB_IGU_ID;
+ bp->igu_base_sb = 0;
+ bp->igu_sb_cnt = min_t(u8, FP_SB_MAX_E1x, bp->l2_cid_count);
+ } else {
+ bp->common.int_block = INT_BLOCK_IGU;
+ val = REG_RD(bp, IGU_REG_BLOCK_CONFIGURATION);
+ if (val & IGU_BLOCK_CONFIGURATION_REG_BACKWARD_COMP_EN) {
+ DP(NETIF_MSG_PROBE, "IGU Backward Compatible Mode\n");
+ bp->common.int_block |= INT_BLOCK_MODE_BW_COMP;
+ } else
+ DP(NETIF_MSG_PROBE, "IGU Normal Mode\n");
+
+ bnx2x_get_igu_cam_info(bp);
+
+ }
+ DP(NETIF_MSG_PROBE, "igu_dsb_id %d igu_base_sb %d igu_sb_cnt %d\n",
+ bp->igu_dsb_id, bp->igu_base_sb, bp->igu_sb_cnt);
+
+ /*
+ * Initialize MF configuration
+ */
- val = (SHMEM_RD(bp, mf_cfg.func_mf_config[FUNC_0].e1hov_tag) &
+ bp->mf_ov = 0;
+ bp->mf_mode = 0;
+ vn = BP_E1HVN(bp);
+ if (!CHIP_IS_E1(bp) && !BP_NOMCP(bp)) {
+ if (SHMEM2_HAS(bp, mf_cfg_addr))
+ bp->common.mf_cfg_base = SHMEM2_RD(bp, mf_cfg_addr);
+ else
+ bp->common.mf_cfg_base = bp->common.shmem_base +
+ offsetof(struct shmem_region, func_mb) +
+ E1H_FUNC_MAX * sizeof(struct drv_func_mb);
+ bp->mf_config[vn] =
+ MF_CFG_RD(bp, func_mf_config[func].config);
+
+ val = (MF_CFG_RD(bp, func_mf_config[FUNC_0].e1hov_tag) &
FUNC_MF_CFG_E1HOV_TAG_MASK);
if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT)
- bp->e1hmf = 1;
+ bp->mf_mode = 1;
BNX2X_DEV_INFO("%s function mode\n",
- IS_E1HMF(bp) ? "multi" : "single");
+ IS_MF(bp) ? "multi" : "single");
- if (IS_E1HMF(bp)) {
- val = (SHMEM_RD(bp, mf_cfg.func_mf_config[func].
+ if (IS_MF(bp)) {
+ val = (MF_CFG_RD(bp, func_mf_config[func].
e1hov_tag) &
FUNC_MF_CFG_E1HOV_TAG_MASK);
if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) {
- bp->e1hov = val;
- BNX2X_DEV_INFO("E1HOV for func %d is %d "
+ bp->mf_ov = val;
+ BNX2X_DEV_INFO("MF OV for func %d is %d "
"(0x%04x)\n",
- func, bp->e1hov, bp->e1hov);
+ func, bp->mf_ov, bp->mf_ov);
} else {
- BNX2X_ERROR("No valid E1HOV for func %d,"
+ BNX2X_ERROR("No valid MF OV for func %d,"
" aborting\n", func);
rc = -EPERM;
}
} else {
- if (BP_E1HVN(bp)) {
+ if (BP_VN(bp)) {
BNX2X_ERROR("VN %d in single function mode,"
" aborting\n", BP_E1HVN(bp));
rc = -EPERM;
@@ -6605,17 +8226,31 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
}
}
+ /* adjust igu_sb_cnt to MF for E1x */
+ if (CHIP_IS_E1x(bp) && IS_MF(bp))
+ bp->igu_sb_cnt /= E1HVN_MAX;
+
+ /*
+ * adjust E2 sb count: to be removed when FW will support
+ * more then 16 L2 clients
+ */
+#define MAX_L2_CLIENTS 16
+ if (CHIP_IS_E2(bp))
+ bp->igu_sb_cnt = min_t(u8, bp->igu_sb_cnt,
+ MAX_L2_CLIENTS / (IS_MF(bp) ? 4 : 1));
+
if (!BP_NOMCP(bp)) {
bnx2x_get_port_hwinfo(bp);
- bp->fw_seq = (SHMEM_RD(bp, func_mb[func].drv_mb_header) &
- DRV_MSG_SEQ_NUMBER_MASK);
+ 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 (IS_E1HMF(bp)) {
- val2 = SHMEM_RD(bp, mf_cfg.func_mf_config[func].mac_upper);
- val = SHMEM_RD(bp, mf_cfg.func_mf_config[func].mac_lower);
+ if (IS_MF(bp)) {
+ val2 = MF_CFG_RD(bp, func_mf_config[func].mac_upper);
+ val = MF_CFG_RD(bp, func_mf_config[func].mac_lower);
if ((val2 != FUNC_MF_CFG_UPPERMAC_DEFAULT) &&
(val != FUNC_MF_CFG_LOWERMAC_DEFAULT)) {
bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff);
@@ -6709,7 +8344,7 @@ out_not_found:
static int __devinit bnx2x_init_bp(struct bnx2x *bp)
{
- int func = BP_FUNC(bp);
+ int func;
int timer_interval;
int rc;
@@ -6729,7 +8364,13 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
rc = bnx2x_get_hwinfo(bp);
+ if (!rc)
+ rc = bnx2x_alloc_mem_bp(bp);
+
bnx2x_read_fwinfo(bp);
+
+ func = BP_FUNC(bp);
+
/* need to reset chip if undi was active */
if (!BP_NOMCP(bp))
bnx2x_undi_unload(bp);
@@ -6771,13 +8412,12 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
bp->mrrs = mrrs;
bp->tx_ring_size = MAX_TX_AVAIL;
- bp->rx_ring_size = MAX_RX_AVAIL;
bp->rx_csum = 1;
/* make sure that the numbers are in the right granularity */
- bp->tx_ticks = (50 / (4 * BNX2X_BTR)) * (4 * BNX2X_BTR);
- bp->rx_ticks = (25 / (4 * BNX2X_BTR)) * (4 * BNX2X_BTR);
+ bp->tx_ticks = (50 / BNX2X_BTR) * BNX2X_BTR;
+ bp->rx_ticks = (25 / BNX2X_BTR) * BNX2X_BTR;
timer_interval = (CHIP_REV_IS_SLOW(bp) ? 5*HZ : HZ);
bp->current_interval = (poll ? poll : timer_interval);
@@ -6869,81 +8509,22 @@ void bnx2x_set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC)
rx_mode = BNX2X_RX_MODE_PROMISC;
-
else if ((dev->flags & IFF_ALLMULTI) ||
((netdev_mc_count(dev) > BNX2X_MAX_MULTICAST) &&
CHIP_IS_E1(bp)))
rx_mode = BNX2X_RX_MODE_ALLMULTI;
-
else { /* some multicasts */
if (CHIP_IS_E1(bp)) {
- int i, old, offset;
- struct netdev_hw_addr *ha;
- struct mac_configuration_cmd *config =
- bnx2x_sp(bp, mcast_config);
-
- i = 0;
- netdev_for_each_mc_addr(ha, dev) {
- config->config_table[i].
- cam_entry.msb_mac_addr =
- swab16(*(u16 *)&ha->addr[0]);
- config->config_table[i].
- cam_entry.middle_mac_addr =
- swab16(*(u16 *)&ha->addr[2]);
- config->config_table[i].
- cam_entry.lsb_mac_addr =
- swab16(*(u16 *)&ha->addr[4]);
- config->config_table[i].cam_entry.flags =
- cpu_to_le16(port);
- config->config_table[i].
- target_table_entry.flags = 0;
- config->config_table[i].target_table_entry.
- clients_bit_vector =
- cpu_to_le32(1 << BP_L_ID(bp));
- config->config_table[i].
- target_table_entry.vlan_id = 0;
-
- DP(NETIF_MSG_IFUP,
- "setting MCAST[%d] (%04x:%04x:%04x)\n", i,
- config->config_table[i].
- cam_entry.msb_mac_addr,
- config->config_table[i].
- cam_entry.middle_mac_addr,
- config->config_table[i].
- cam_entry.lsb_mac_addr);
- i++;
- }
- old = config->hdr.length;
- if (old > i) {
- for (; i < old; i++) {
- if (CAM_IS_INVALID(config->
- config_table[i])) {
- /* already invalidated */
- break;
- }
- /* invalidate */
- CAM_INVALIDATE(config->
- config_table[i]);
- }
- }
-
- if (CHIP_REV_IS_SLOW(bp))
- offset = BNX2X_MAX_EMUL_MULTI*(1 + port);
- else
- offset = BNX2X_MAX_MULTICAST*(1 + port);
-
- config->hdr.length = i;
- config->hdr.offset = offset;
- config->hdr.client_id = bp->fp->cl_id;
- config->hdr.reserved1 = 0;
-
- bp->set_mac_pending++;
- smp_wmb();
+ /*
+ * set mc list, do not wait as wait implies sleep
+ * and set_rx_mode can be invoked from non-sleepable
+ * context
+ */
+ u8 offset = (CHIP_REV_IS_SLOW(bp) ?
+ BNX2X_MAX_EMUL_MULTI*(1 + port) :
+ BNX2X_MAX_MULTICAST*(1 + port));
- bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
- U64_HI(bnx2x_sp_mapping(bp, mcast_config)),
- U64_LO(bnx2x_sp_mapping(bp, mcast_config)),
- 0);
+ bnx2x_set_e1_mc_list(bp, offset);
} else { /* E1H */
/* Accept one or more multicasts */
struct netdev_hw_addr *ha;
@@ -6955,9 +8536,10 @@ void bnx2x_set_rx_mode(struct net_device *dev)
netdev_for_each_mc_addr(ha, dev) {
DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n",
- ha->addr);
+ bnx2x_mc_addr(ha));
- crc = crc32c_le(0, ha->addr, ETH_ALEN);
+ crc = crc32c_le(0, bnx2x_mc_addr(ha),
+ ETH_ALEN);
bit = (crc >> 24) & 0xff;
regidx = bit >> 5;
bit &= 0x1f;
@@ -6974,7 +8556,6 @@ void bnx2x_set_rx_mode(struct net_device *dev)
bnx2x_set_storm_rx_mode(bp);
}
-
/* called with rtnl_lock */
static int bnx2x_mdio_read(struct net_device *netdev, int prtad,
int devad, u16 addr)
@@ -6982,23 +8563,15 @@ static int bnx2x_mdio_read(struct net_device *netdev, int prtad,
struct bnx2x *bp = netdev_priv(netdev);
u16 value;
int rc;
- u32 phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
DP(NETIF_MSG_LINK, "mdio_read: prtad 0x%x, devad 0x%x, addr 0x%x\n",
prtad, devad, addr);
- if (prtad != bp->mdio.prtad) {
- DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n",
- prtad, bp->mdio.prtad);
- return -EINVAL;
- }
-
/* The HW expects different devad if CL22 is used */
devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad;
bnx2x_acquire_phy_lock(bp);
- rc = bnx2x_cl45_read(bp, BP_PORT(bp), phy_type, prtad,
- devad, addr, &value);
+ rc = bnx2x_phy_read(&bp->link_params, prtad, devad, addr, &value);
bnx2x_release_phy_lock(bp);
DP(NETIF_MSG_LINK, "mdio_read_val 0x%x rc = 0x%x\n", value, rc);
@@ -7012,24 +8585,16 @@ static int bnx2x_mdio_write(struct net_device *netdev, int prtad, int devad,
u16 addr, u16 value)
{
struct bnx2x *bp = netdev_priv(netdev);
- u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
int rc;
DP(NETIF_MSG_LINK, "mdio_write: prtad 0x%x, devad 0x%x, addr 0x%x,"
" value 0x%x\n", prtad, devad, addr, value);
- if (prtad != bp->mdio.prtad) {
- DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n",
- prtad, bp->mdio.prtad);
- return -EINVAL;
- }
-
/* The HW expects different devad if CL22 is used */
devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad;
bnx2x_acquire_phy_lock(bp);
- rc = bnx2x_cl45_write(bp, BP_PORT(bp), ext_phy_type, prtad,
- devad, addr, value);
+ rc = bnx2x_phy_write(&bp->link_params, prtad, devad, addr, value);
bnx2x_release_phy_lock(bp);
return rc;
}
@@ -7070,9 +8635,6 @@ static const struct net_device_ops bnx2x_netdev_ops = {
.ndo_do_ioctl = bnx2x_ioctl,
.ndo_change_mtu = bnx2x_change_mtu,
.ndo_tx_timeout = bnx2x_tx_timeout,
-#ifdef BCM_VLAN
- .ndo_vlan_rx_register = bnx2x_vlan_rx_register,
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = poll_bnx2x,
#endif
@@ -7090,7 +8652,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
bp->dev = dev;
bp->pdev = pdev;
bp->flags = 0;
- bp->func = PCI_FUNC(pdev->devfn);
+ bp->pf_num = PCI_FUNC(pdev->devfn);
rc = pci_enable_device(pdev);
if (rc) {
@@ -7172,7 +8734,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
}
bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2),
- min_t(u64, BNX2X_DB_SIZE,
+ min_t(u64, BNX2X_DB_SIZE(bp),
pci_resource_len(pdev, 2)));
if (!bp->doorbells) {
dev_err(&bp->pdev->dev,
@@ -7204,9 +8766,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
dev->features |= NETIF_F_HIGHDMA;
dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
dev->features |= NETIF_F_TSO6;
-#ifdef BCM_VLAN
dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
- bp->flags |= (HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG);
dev->vlan_features |= NETIF_F_SG;
dev->vlan_features |= NETIF_F_HW_CSUM;
@@ -7214,7 +8774,6 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
dev->vlan_features |= NETIF_F_HIGHDMA;
dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
dev->vlan_features |= NETIF_F_TSO6;
-#endif
/* get_port_hwinfo() will set prtad and mmds properly */
bp->mdio.prtad = MDIO_PRTAD_NONE;
@@ -7259,7 +8818,7 @@ static void __devinit bnx2x_get_pcie_width_speed(struct bnx2x *bp,
*speed = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT;
}
-static int __devinit bnx2x_check_firmware(struct bnx2x *bp)
+static int bnx2x_check_firmware(struct bnx2x *bp)
{
const struct firmware *firmware = bp->firmware;
struct bnx2x_fw_file_hdr *fw_hdr;
@@ -7348,6 +8907,30 @@ static inline void bnx2x_prep_ops(const u8 *_source, u8 *_target, u32 n)
}
}
+/**
+ * IRO array is stored in the following format:
+ * {base(24bit), m1(16bit), m2(16bit), m3(16bit), size(16bit) }
+ */
+static inline void bnx2x_prep_iro(const u8 *_source, u8 *_target, u32 n)
+{
+ const __be32 *source = (const __be32 *)_source;
+ struct iro *target = (struct iro *)_target;
+ u32 i, j, tmp;
+
+ for (i = 0, j = 0; i < n/sizeof(struct iro); i++) {
+ target[i].base = be32_to_cpu(source[j]);
+ j++;
+ tmp = be32_to_cpu(source[j]);
+ target[i].m1 = (tmp >> 16) & 0xffff;
+ target[i].m2 = tmp & 0xffff;
+ j++;
+ tmp = be32_to_cpu(source[j]);
+ target[i].m3 = (tmp >> 16) & 0xffff;
+ target[i].size = tmp & 0xffff;
+ j++;
+ }
+}
+
static inline void be16_to_cpu_n(const u8 *_source, u8 *_target, u32 n)
{
const __be16 *source = (const __be16 *)_source;
@@ -7370,7 +8953,7 @@ do { \
(u8 *)bp->arr, len); \
} while (0)
-static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev)
+int bnx2x_init_firmware(struct bnx2x *bp)
{
const char *fw_file_name;
struct bnx2x_fw_file_hdr *fw_hdr;
@@ -7380,22 +8963,24 @@ static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev)
fw_file_name = FW_FILE_NAME_E1;
else if (CHIP_IS_E1H(bp))
fw_file_name = FW_FILE_NAME_E1H;
+ else if (CHIP_IS_E2(bp))
+ fw_file_name = FW_FILE_NAME_E2;
else {
- dev_err(dev, "Unsupported chip revision\n");
+ BNX2X_ERR("Unsupported chip revision\n");
return -EINVAL;
}
- dev_info(dev, "Loading %s\n", fw_file_name);
+ BNX2X_DEV_INFO("Loading %s\n", fw_file_name);
- rc = request_firmware(&bp->firmware, fw_file_name, dev);
+ rc = request_firmware(&bp->firmware, fw_file_name, &bp->pdev->dev);
if (rc) {
- dev_err(dev, "Can't load firmware file %s\n", fw_file_name);
+ BNX2X_ERR("Can't load firmware file %s\n", fw_file_name);
goto request_firmware_exit;
}
rc = bnx2x_check_firmware(bp);
if (rc) {
- dev_err(dev, "Corrupt firmware file %s\n", fw_file_name);
+ BNX2X_ERR("Corrupt firmware file %s\n", fw_file_name);
goto request_firmware_exit;
}
@@ -7429,9 +9014,13 @@ static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev)
be32_to_cpu(fw_hdr->csem_int_table_data.offset);
INIT_CSEM_PRAM_DATA(bp) = bp->firmware->data +
be32_to_cpu(fw_hdr->csem_pram_data.offset);
+ /* IRO */
+ BNX2X_ALLOC_AND_SET(iro_arr, iro_alloc_err, bnx2x_prep_iro);
return 0;
+iro_alloc_err:
+ kfree(bp->init_ops_offsets);
init_offsets_alloc_err:
kfree(bp->init_ops);
init_ops_alloc_err:
@@ -7442,6 +9031,15 @@ request_firmware_exit:
return rc;
}
+static inline int bnx2x_set_qm_cid_count(struct bnx2x *bp, int l2_cid_count)
+{
+ int cid_count = L2_FP_COUNT(l2_cid_count);
+
+#ifdef BCM_CNIC
+ cid_count += CNIC_CID_MAX;
+#endif
+ return roundup(cid_count, QM_CID_ROUND);
+}
static int __devinit bnx2x_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -7449,10 +9047,30 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
struct net_device *dev = NULL;
struct bnx2x *bp;
int pcie_width, pcie_speed;
- int rc;
+ int rc, cid_count;
+
+ switch (ent->driver_data) {
+ case BCM57710:
+ case BCM57711:
+ case BCM57711E:
+ cid_count = FP_SB_MAX_E1x;
+ break;
+
+ case BCM57712:
+ case BCM57712E:
+ cid_count = FP_SB_MAX_E2;
+ break;
+
+ default:
+ pr_err("Unknown board_type (%ld), aborting\n",
+ ent->driver_data);
+ return ENODEV;
+ }
+
+ cid_count += CNIC_CONTEXT_USE;
/* dev zeroed in init_etherdev */
- dev = alloc_etherdev_mq(sizeof(*bp), MAX_CONTEXT);
+ dev = alloc_etherdev_mq(sizeof(*bp), cid_count);
if (!dev) {
dev_err(&pdev->dev, "Cannot allocate net device\n");
return -ENOMEM;
@@ -7463,6 +9081,8 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
pci_set_drvdata(pdev, dev);
+ bp->l2_cid_count = cid_count;
+
rc = bnx2x_init_dev(pdev, dev);
if (rc < 0) {
free_netdev(dev);
@@ -7473,12 +9093,8 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
if (rc)
goto init_one_exit;
- /* Set init arrays */
- rc = bnx2x_init_firmware(bp, &pdev->dev);
- if (rc) {
- dev_err(&pdev->dev, "Error loading firmware\n");
- goto init_one_exit;
- }
+ /* calc qm_cid_count */
+ bp->qm_cid_count = bnx2x_set_qm_cid_count(bp, cid_count);
rc = register_netdev(dev);
if (rc) {
@@ -7486,11 +9102,23 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
goto init_one_exit;
}
+ /* Configure interupt mode: try to enable MSI-X/MSI if
+ * needed, set bp->num_queues appropriately.
+ */
+ bnx2x_set_int_mode(bp);
+
+ /* Add all NAPI objects */
+ bnx2x_add_all_napi(bp);
+
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, (pcie_speed == 2) ? "5GHz (Gen2)" : "2.5GHz",
+ 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);
@@ -7527,20 +9155,23 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev)
unregister_netdev(dev);
+ /* Delete all NAPI objects */
+ bnx2x_del_all_napi(bp);
+
+ /* Disable MSI/MSI-X */
+ bnx2x_disable_msi(bp);
+
/* Make sure RESET task is not scheduled before continuing */
cancel_delayed_work_sync(&bp->reset_task);
- kfree(bp->init_ops_offsets);
- kfree(bp->init_ops);
- kfree(bp->init_data);
- release_firmware(bp->firmware);
-
if (bp->regview)
iounmap(bp->regview);
if (bp->doorbells)
iounmap(bp->doorbells);
+ bnx2x_free_mem_bp(bp);
+
free_netdev(dev);
if (atomic_read(&pdev->enable_cnt) == 1)
@@ -7566,22 +9197,14 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n");
/* Release IRQs */
- bnx2x_free_irq(bp, false);
-
- if (CHIP_IS_E1(bp)) {
- struct mac_configuration_cmd *config =
- bnx2x_sp(bp, mcast_config);
-
- for (i = 0; i < config->hdr.length; i++)
- CAM_INVALIDATE(config->config_table[i]);
- }
+ bnx2x_free_irq(bp);
/* Free SKBs, SGEs, TPA pool and driver internals */
bnx2x_free_skbs(bp);
+
for_each_queue(bp, i)
bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
- for_each_queue(bp, i)
- netif_napi_del(&bnx2x_fp(bp, i, napi));
+
bnx2x_free_mem(bp);
bp->state = BNX2X_STATE_CLOSED;
@@ -7613,8 +9236,9 @@ static void bnx2x_eeh_recover(struct bnx2x *bp)
BNX2X_ERR("BAD MCP validity signature\n");
if (!BP_NOMCP(bp)) {
- bp->fw_seq = (SHMEM_RD(bp, func_mb[BP_FUNC(bp)].drv_mb_header)
- & DRV_MSG_SEQ_NUMBER_MASK);
+ 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);
}
}
@@ -7697,7 +9321,8 @@ static void bnx2x_io_resume(struct pci_dev *pdev)
struct bnx2x *bp = netdev_priv(dev);
if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
- printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+ printk(KERN_ERR "Handling parity error recovery. "
+ "Try again later\n");
return;
}
@@ -7772,19 +9397,53 @@ static void bnx2x_cnic_sp_post(struct bnx2x *bp, int count)
#endif
spin_lock_bh(&bp->spq_lock);
+ BUG_ON(bp->cnic_spq_pending < count);
bp->cnic_spq_pending -= count;
- for (; bp->cnic_spq_pending < bp->cnic_eth_dev.max_kwqe_pending;
- bp->cnic_spq_pending++) {
- if (!bp->cnic_kwq_pending)
+ for (; bp->cnic_kwq_pending; bp->cnic_kwq_pending--) {
+ u16 type = (le16_to_cpu(bp->cnic_kwq_cons->hdr.type)
+ & SPE_HDR_CONN_TYPE) >>
+ SPE_HDR_CONN_TYPE_SHIFT;
+
+ /* Set validation for iSCSI L2 client before sending SETUP
+ * ramrod
+ */
+ if (type == ETH_CONNECTION_TYPE) {
+ u8 cmd = (le32_to_cpu(bp->cnic_kwq_cons->
+ hdr.conn_and_cmd_data) >>
+ SPE_HDR_CMD_ID_SHIFT) & 0xff;
+
+ if (cmd == RAMROD_CMD_ID_ETH_CLIENT_SETUP)
+ bnx2x_set_ctx_validation(&bp->context.
+ vcxt[BNX2X_ISCSI_ETH_CID].eth,
+ HW_CID(bp, BNX2X_ISCSI_ETH_CID));
+ }
+
+ /* There may be not more than 8 L2 and COMMON SPEs and not more
+ * than 8 L5 SPEs in the air.
+ */
+ if ((type == NONE_CONNECTION_TYPE) ||
+ (type == ETH_CONNECTION_TYPE)) {
+ if (!atomic_read(&bp->spq_left))
+ break;
+ else
+ atomic_dec(&bp->spq_left);
+ } else if (type == ISCSI_CONNECTION_TYPE) {
+ if (bp->cnic_spq_pending >=
+ bp->cnic_eth_dev.max_kwqe_pending)
+ break;
+ else
+ bp->cnic_spq_pending++;
+ } else {
+ BNX2X_ERR("Unknown SPE type: %d\n", type);
+ bnx2x_panic();
break;
+ }
spe = bnx2x_sp_get_next(bp);
*spe = *bp->cnic_kwq_cons;
- bp->cnic_kwq_pending--;
-
DP(NETIF_MSG_TIMER, "pending on SPQ %d, on KWQ %d count %d\n",
bp->cnic_spq_pending, bp->cnic_kwq_pending, count);
@@ -7822,8 +9481,8 @@ static int bnx2x_cnic_sp_queue(struct net_device *dev,
DP(NETIF_MSG_TIMER, "L5 SPQE %x %x %x:%x pos %d\n",
spe->hdr.conn_and_cmd_data, spe->hdr.type,
- spe->data.mac_config_addr.hi,
- spe->data.mac_config_addr.lo,
+ spe->data.update_data_addr.hi,
+ spe->data.update_data_addr.lo,
bp->cnic_kwq_pending);
if (bp->cnic_kwq_prod == bp->cnic_kwq_last)
@@ -7889,7 +9548,7 @@ static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid)
ctl.data.comp.cid = cid;
bnx2x_cnic_ctl_send_bh(bp, &ctl);
- bnx2x_cnic_sp_post(bp, 1);
+ bnx2x_cnic_sp_post(bp, 0);
}
static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
@@ -7906,8 +9565,8 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
break;
}
- case DRV_CTL_COMPLETION_CMD: {
- int count = ctl->data.comp.comp_count;
+ case DRV_CTL_RET_L5_SPQ_CREDIT_CMD: {
+ int count = ctl->data.credit.credit_count;
bnx2x_cnic_sp_post(bp, count);
break;
@@ -7917,8 +9576,24 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
case DRV_CTL_START_L2_CMD: {
u32 cli = ctl->data.ring.client_id;
- bp->rx_mode_cl_mask |= (1 << cli);
- bnx2x_set_storm_rx_mode(bp);
+ /* Set iSCSI MAC address */
+ bnx2x_set_iscsi_eth_mac_addr(bp, 1);
+
+ mmiowb();
+ barrier();
+
+ /* Start accepting on iSCSI L2 ring. Accept all multicasts
+ * because it's the only way for UIO Client to accept
+ * multicasts (in non-promiscuous mode only one Client per
+ * function will receive multicast packets (leading in our
+ * case).
+ */
+ bnx2x_rxq_set_mac_filters(bp, cli,
+ BNX2X_ACCEPT_UNICAST |
+ BNX2X_ACCEPT_BROADCAST |
+ BNX2X_ACCEPT_ALL_MULTICAST);
+ storm_memset_mac_filters(bp, &bp->mac_filters, BP_FUNC(bp));
+
break;
}
@@ -7926,8 +9601,23 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
case DRV_CTL_STOP_L2_CMD: {
u32 cli = ctl->data.ring.client_id;
- bp->rx_mode_cl_mask &= ~(1 << cli);
- bnx2x_set_storm_rx_mode(bp);
+ /* Stop accepting on iSCSI L2 ring */
+ bnx2x_rxq_set_mac_filters(bp, cli, BNX2X_ACCEPT_NONE);
+ storm_memset_mac_filters(bp, &bp->mac_filters, BP_FUNC(bp));
+
+ mmiowb();
+ barrier();
+
+ /* Unset iSCSI L2 MAC */
+ bnx2x_set_iscsi_eth_mac_addr(bp, 0);
+ break;
+ }
+ case DRV_CTL_RET_L2_SPQ_CREDIT_CMD: {
+ int count = ctl->data.credit.credit_count;
+
+ smp_mb__before_atomic_inc();
+ atomic_add(count, &bp->spq_left);
+ smp_mb__after_atomic_inc();
break;
}
@@ -7951,10 +9641,16 @@ void bnx2x_setup_cnic_irq_info(struct bnx2x *bp)
cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
}
- cp->irq_arr[0].status_blk = bp->cnic_sb;
+ if (CHIP_IS_E2(bp))
+ cp->irq_arr[0].status_blk = (void *)bp->cnic_sb.e2_sb;
+ else
+ cp->irq_arr[0].status_blk = (void *)bp->cnic_sb.e1x_sb;
+
cp->irq_arr[0].status_blk_num = CNIC_SB_ID(bp);
+ cp->irq_arr[0].status_blk_num2 = CNIC_IGU_SB_ID(bp);
cp->irq_arr[1].status_blk = bp->def_status_blk;
cp->irq_arr[1].status_blk_num = DEF_SB_ID;
+ cp->irq_arr[1].status_blk_num2 = DEF_SB_IGU_ID;
cp->num_irq = 2;
}
@@ -7986,12 +9682,10 @@ static int bnx2x_register_cnic(struct net_device *dev, struct cnic_ops *ops,
cp->num_irq = 0;
cp->drv_state = CNIC_DRV_STATE_REGD;
-
- bnx2x_init_sb(bp, bp->cnic_sb, bp->cnic_sb_mapping, CNIC_SB_ID(bp));
+ cp->iro_arr = bp->iro_arr;
bnx2x_setup_cnic_irq_info(bp);
- bnx2x_set_iscsi_eth_mac_addr(bp, 1);
- bp->cnic_flags |= BNX2X_CNIC_FLAG_MAC_SET;
+
rcu_assign_pointer(bp->cnic_ops, ops);
return 0;
@@ -8028,15 +9722,24 @@ struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
cp->io_base = bp->regview;
cp->io_base2 = bp->doorbells;
cp->max_kwqe_pending = 8;
- cp->ctx_blk_size = CNIC_CTX_PER_ILT * sizeof(union cdu_context);
- cp->ctx_tbl_offset = FUNC_ILT_BASE(BP_FUNC(bp)) + 1;
+ cp->ctx_blk_size = CDU_ILT_PAGE_SZ;
+ cp->ctx_tbl_offset = FUNC_ILT_BASE(BP_FUNC(bp)) +
+ bnx2x_cid_ilt_lines(bp);
cp->ctx_tbl_len = CNIC_ILT_LINES;
- cp->starting_cid = BCM_CNIC_CID_START;
+ cp->starting_cid = bnx2x_cid_ilt_lines(bp) * ILT_PAGE_CIDS;
cp->drv_submit_kwqes_16 = bnx2x_cnic_sp_queue;
cp->drv_ctl = bnx2x_drv_ctl;
cp->drv_register_cnic = bnx2x_register_cnic;
cp->drv_unregister_cnic = bnx2x_unregister_cnic;
-
+ cp->iscsi_l2_client_id = BNX2X_ISCSI_ETH_CL_ID;
+ cp->iscsi_l2_cid = BNX2X_ISCSI_ETH_CID;
+
+ DP(BNX2X_MSG_SP, "page_size %d, tbl_offset %d, tbl_lines %d, "
+ "starting cid %d\n",
+ cp->ctx_blk_size,
+ cp->ctx_tbl_offset,
+ cp->ctx_tbl_len,
+ cp->starting_cid);
return cp;
}
EXPORT_SYMBOL(bnx2x_cnic_probe);
diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h
index a1f3bf0cd630..1cefe489a955 100644
--- a/drivers/net/bnx2x/bnx2x_reg.h
+++ b/drivers/net/bnx2x/bnx2x_reg.h
@@ -1,6 +1,6 @@
/* bnx2x_reg.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2009 Broadcom Corporation
+ * Copyright (c) 2007-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
@@ -19,7 +19,20 @@
*
*/
-
+#define ATC_ATC_INT_STS_REG_ADDRESS_ERROR (0x1<<0)
+#define ATC_ATC_INT_STS_REG_ATC_GPA_MULTIPLE_HITS (0x1<<2)
+#define ATC_ATC_INT_STS_REG_ATC_IREQ_LESS_THAN_STU (0x1<<5)
+#define ATC_ATC_INT_STS_REG_ATC_RCPL_TO_EMPTY_CNT (0x1<<3)
+#define ATC_ATC_INT_STS_REG_ATC_TCPL_ERROR (0x1<<4)
+#define ATC_ATC_INT_STS_REG_ATC_TCPL_TO_NOT_PEND (0x1<<1)
+/* [RW 1] Initiate the ATC array - reset all the valid bits */
+#define ATC_REG_ATC_INIT_ARRAY 0x1100b8
+/* [R 1] ATC initalization done */
+#define ATC_REG_ATC_INIT_DONE 0x1100bc
+/* [RC 6] Interrupt register #0 read clear */
+#define ATC_REG_ATC_INT_STS_CLR 0x1101c0
+/* [RW 19] Interrupt mask register #0 read/write */
+#define BRB1_REG_BRB1_INT_MASK 0x60128
/* [R 19] Interrupt register #0 read */
#define BRB1_REG_BRB1_INT_STS 0x6011c
/* [RW 4] Parity mask register #0 read/write */
@@ -27,9 +40,31 @@
/* [R 4] Parity register #0 read */
#define BRB1_REG_BRB1_PRTY_STS 0x6012c
/* [RW 10] At address BRB1_IND_FREE_LIST_PRS_CRDT initialize free head. At
- address BRB1_IND_FREE_LIST_PRS_CRDT+1 initialize free tail. At address
- BRB1_IND_FREE_LIST_PRS_CRDT+2 initialize parser initial credit. */
+ * address BRB1_IND_FREE_LIST_PRS_CRDT+1 initialize free tail. At address
+ * BRB1_IND_FREE_LIST_PRS_CRDT+2 initialize parser initial credit. Warning -
+ * following reset the first rbc access to this reg must be write; there can
+ * be no more rbc writes after the first one; there can be any number of rbc
+ * read following the first write; rbc access not following these rules will
+ * result in hang condition. */
#define BRB1_REG_FREE_LIST_PRS_CRDT 0x60200
+/* [RW 10] The number of free blocks below which the full signal to class 0
+ * is asserted */
+#define BRB1_REG_FULL_0_XOFF_THRESHOLD_0 0x601d0
+/* [RW 10] The number of free blocks above which the full signal to class 0
+ * is de-asserted */
+#define BRB1_REG_FULL_0_XON_THRESHOLD_0 0x601d4
+/* [RW 10] The number of free blocks below which the full signal to class 1
+ * is asserted */
+#define BRB1_REG_FULL_1_XOFF_THRESHOLD_0 0x601d8
+/* [RW 10] The number of free blocks above which the full signal to class 1
+ * is de-asserted */
+#define BRB1_REG_FULL_1_XON_THRESHOLD_0 0x601dc
+/* [RW 10] The number of free blocks below which the full signal to the LB
+ * port is asserted */
+#define BRB1_REG_FULL_LB_XOFF_THRESHOLD 0x601e0
+/* [RW 10] The number of free blocks above which the full signal to the LB
+ * port is de-asserted */
+#define BRB1_REG_FULL_LB_XON_THRESHOLD 0x601e4
/* [RW 10] The number of free blocks above which the High_llfc signal to
interface #n is de-asserted. */
#define BRB1_REG_HIGH_LLFC_HIGH_THRESHOLD_0 0x6014c
@@ -44,6 +79,9 @@
/* [RW 10] The number of free blocks below which the Low_llfc signal to
interface #n is asserted. */
#define BRB1_REG_LOW_LLFC_LOW_THRESHOLD_0 0x6015c
+/* [RW 10] The number of blocks guarantied for the MAC port */
+#define BRB1_REG_MAC_GUARANTIED_0 0x601e8
+#define BRB1_REG_MAC_GUARANTIED_1 0x60240
/* [R 24] The number of full blocks. */
#define BRB1_REG_NUM_OF_FULL_BLOCKS 0x60090
/* [ST 32] The number of cycles that the write_full signal towards MAC #0
@@ -55,7 +93,19 @@
asserted. */
#define BRB1_REG_NUM_OF_PAUSE_CYCLES_0 0x600b8
#define BRB1_REG_NUM_OF_PAUSE_CYCLES_1 0x600bc
-/* [RW 10] Write client 0: De-assert pause threshold. */
+/* [RW 10] The number of free blocks below which the pause signal to class 0
+ * is asserted */
+#define BRB1_REG_PAUSE_0_XOFF_THRESHOLD_0 0x601c0
+/* [RW 10] The number of free blocks above which the pause signal to class 0
+ * is de-asserted */
+#define BRB1_REG_PAUSE_0_XON_THRESHOLD_0 0x601c4
+/* [RW 10] The number of free blocks below which the pause signal to class 1
+ * is asserted */
+#define BRB1_REG_PAUSE_1_XOFF_THRESHOLD_0 0x601c8
+/* [RW 10] The number of free blocks above which the pause signal to class 1
+ * is de-asserted */
+#define BRB1_REG_PAUSE_1_XON_THRESHOLD_0 0x601cc
+/* [RW 10] Write client 0: De-assert pause threshold. Not Functional */
#define BRB1_REG_PAUSE_HIGH_THRESHOLD_0 0x60078
#define BRB1_REG_PAUSE_HIGH_THRESHOLD_1 0x6007c
/* [RW 10] Write client 0: Assert pause threshold. */
@@ -362,6 +412,7 @@
#define CFC_REG_NUM_LCIDS_ARRIVING 0x104004
/* [R 9] Number of Leaving LCIDs in Link List Block */
#define CFC_REG_NUM_LCIDS_LEAVING 0x104018
+#define CFC_REG_WEAK_ENABLE_PF 0x104124
/* [RW 8] The event id for aggregated interrupt 0 */
#define CSDM_REG_AGG_INT_EVENT_0 0xc2038
#define CSDM_REG_AGG_INT_EVENT_10 0xc2060
@@ -590,10 +641,17 @@
#define CSEM_REG_TS_8_AS 0x200058
/* [RW 3] The arbitration scheme of time_slot 9 */
#define CSEM_REG_TS_9_AS 0x20005c
+/* [W 7] VF or PF ID for reset error bit. Values 0-63 reset error bit for 64
+ * VF; values 64-67 reset error for 4 PF; values 68-127 are not valid. */
+#define CSEM_REG_VFPF_ERR_NUM 0x200380
/* [RW 1] Parity mask register #0 read/write */
#define DBG_REG_DBG_PRTY_MASK 0xc0a8
/* [R 1] Parity register #0 read */
#define DBG_REG_DBG_PRTY_STS 0xc09c
+/* [RW 1] When set the DMAE will process the commands as in E1.5. 1.The
+ * function that is used is always SRC-PCI; 2.VF_Valid = 0; 3.VFID=0;
+ * 4.Completion function=0; 5.Error handling=0 */
+#define DMAE_REG_BACKWARD_COMP_EN 0x10207c
/* [RW 32] Commands memory. The address to command X; row Y is to calculated
as 14*X+Y. */
#define DMAE_REG_CMD_MEM 0x102400
@@ -742,9 +800,13 @@
#define HC_REG_HC_PRTY_MASK 0x1080a0
/* [R 3] Parity register #0 read */
#define HC_REG_HC_PRTY_STS 0x108094
-#define HC_REG_INT_MASK 0x108108
+/* [RC 3] Parity register #0 read clear */
+#define HC_REG_HC_PRTY_STS_CLR 0x108098
+#define HC_REG_INT_MASK 0x108108
#define HC_REG_LEADING_EDGE_0 0x108040
#define HC_REG_LEADING_EDGE_1 0x108048
+#define HC_REG_MAIN_MEMORY 0x108800
+#define HC_REG_MAIN_MEMORY_SIZE 152
#define HC_REG_P0_PROD_CONS 0x108200
#define HC_REG_P1_PROD_CONS 0x108400
#define HC_REG_PBA_COMMAND 0x108140
@@ -758,6 +820,92 @@
#define HC_REG_USTORM_ADDR_FOR_COALESCE 0x108068
#define HC_REG_VQID_0 0x108008
#define HC_REG_VQID_1 0x10800c
+#define IGU_BLOCK_CONFIGURATION_REG_BACKWARD_COMP_EN (0x1<<1)
+#define IGU_REG_ATTENTION_ACK_BITS 0x130108
+/* [R 4] Debug: attn_fsm */
+#define IGU_REG_ATTN_FSM 0x130054
+#define IGU_REG_ATTN_MSG_ADDR_H 0x13011c
+#define IGU_REG_ATTN_MSG_ADDR_L 0x130120
+/* [R 4] Debug: [3] - attention write done message is pending (0-no pending;
+ * 1-pending). [2:0] = PFID. Pending means attention message was sent; but
+ * write done didnt receive. */
+#define IGU_REG_ATTN_WRITE_DONE_PENDING 0x130030
+#define IGU_REG_BLOCK_CONFIGURATION 0x130000
+#define IGU_REG_COMMAND_REG_32LSB_DATA 0x130124
+#define IGU_REG_COMMAND_REG_CTRL 0x13012c
+/* [WB_R 32] Cleanup bit status per SB. 1 = cleanup is set. 0 = cleanup bit
+ * is clear. The bits in this registers are set and clear via the producer
+ * command. Data valid only in addresses 0-4. all the rest are zero. */
+#define IGU_REG_CSTORM_TYPE_0_SB_CLEANUP 0x130200
+/* [R 5] Debug: ctrl_fsm */
+#define IGU_REG_CTRL_FSM 0x130064
+/* [R 1] data availble for error memory. If this bit is clear do not red
+ * from error_handling_memory. */
+#define IGU_REG_ERROR_HANDLING_DATA_VALID 0x130130
+/* [R 11] Parity register #0 read */
+#define IGU_REG_IGU_PRTY_STS 0x13009c
+/* [R 4] Debug: int_handle_fsm */
+#define IGU_REG_INT_HANDLE_FSM 0x130050
+#define IGU_REG_LEADING_EDGE_LATCH 0x130134
+/* [RW 14] mapping CAM; relevant for E2 operating mode only. [0] - valid.
+ * [6:1] - vector number; [13:7] - FID (if VF - [13] = 0; [12:7] = VF
+ * number; if PF - [13] = 1; [12:10] = 0; [9:7] = PF number); */
+#define IGU_REG_MAPPING_MEMORY 0x131000
+#define IGU_REG_MAPPING_MEMORY_SIZE 136
+#define IGU_REG_PBA_STATUS_LSB 0x130138
+#define IGU_REG_PBA_STATUS_MSB 0x13013c
+#define IGU_REG_PCI_PF_MSI_EN 0x130140
+#define IGU_REG_PCI_PF_MSIX_EN 0x130144
+#define IGU_REG_PCI_PF_MSIX_FUNC_MASK 0x130148
+/* [WB_R 32] Each bit represent the pending bits status for that SB. 0 = no
+ * pending; 1 = pending. Pendings means interrupt was asserted; and write
+ * done was not received. Data valid only in addresses 0-4. all the rest are
+ * zero. */
+#define IGU_REG_PENDING_BITS_STATUS 0x130300
+#define IGU_REG_PF_CONFIGURATION 0x130154
+/* [RW 20] producers only. E2 mode: address 0-135 match to the mapping
+ * memory; 136 - PF0 default prod; 137 PF1 default prod; 138 - PF2 default
+ * prod; 139 PF3 default prod; 140 - PF0 - ATTN prod; 141 - PF1 - ATTN prod;
+ * 142 - PF2 - ATTN prod; 143 - PF3 - ATTN prod; 144-147 reserved. E1.5 mode
+ * - In backward compatible mode; for non default SB; each even line in the
+ * memory holds the U producer and each odd line hold the C producer. The
+ * first 128 producer are for NDSB (PF0 - 0-31; PF1 - 32-63 and so on). The
+ * last 20 producers are for the DSB for each PF. each PF has five segments
+ * (the order inside each segment is PF0; PF1; PF2; PF3) - 128-131 U prods;
+ * 132-135 C prods; 136-139 X prods; 140-143 T prods; 144-147 ATTN prods; */
+#define IGU_REG_PROD_CONS_MEMORY 0x132000
+/* [R 3] Debug: pxp_arb_fsm */
+#define IGU_REG_PXP_ARB_FSM 0x130068
+/* [RW 6] Write one for each bit will reset the appropriate memory. When the
+ * memory reset finished the appropriate bit will be clear. Bit 0 - mapping
+ * memory; Bit 1 - SB memory; Bit 2 - SB interrupt and mask register; Bit 3
+ * - MSIX memory; Bit 4 - PBA memory; Bit 5 - statistics; */
+#define IGU_REG_RESET_MEMORIES 0x130158
+/* [R 4] Debug: sb_ctrl_fsm */
+#define IGU_REG_SB_CTRL_FSM 0x13004c
+#define IGU_REG_SB_INT_BEFORE_MASK_LSB 0x13015c
+#define IGU_REG_SB_INT_BEFORE_MASK_MSB 0x130160
+#define IGU_REG_SB_MASK_LSB 0x130164
+#define IGU_REG_SB_MASK_MSB 0x130168
+/* [RW 16] Number of command that were dropped without causing an interrupt
+ * due to: read access for WO BAR address; or write access for RO BAR
+ * address or any access for reserved address or PCI function error is set
+ * and address is not MSIX; PBA or cleanup */
+#define IGU_REG_SILENT_DROP 0x13016c
+/* [RW 10] Number of MSI/MSIX/ATTN messages sent for the function: 0-63 -
+ * number of MSIX messages per VF; 64-67 - number of MSI/MSIX messages per
+ * PF; 68-71 number of ATTN messages per PF */
+#define IGU_REG_STATISTIC_NUM_MESSAGE_SENT 0x130800
+/* [RW 32] Number of cycles the timer mask masking the IGU interrupt when a
+ * timer mask command arrives. Value must be bigger than 100. */
+#define IGU_REG_TIMER_MASKING_VALUE 0x13003c
+#define IGU_REG_TRAILING_EDGE_LATCH 0x130104
+#define IGU_REG_VF_CONFIGURATION 0x130170
+/* [WB_R 32] Each bit represent write done pending bits status for that SB
+ * (MSI/MSIX message was sent and write done was not received yet). 0 =
+ * clear; 1 = set. Data valid only in addresses 0-4. all the rest are zero. */
+#define IGU_REG_WRITE_DONE_PENDING 0x130480
+#define MCP_A_REG_MCPR_SCRATCH 0x3a0000
#define MCP_REG_MCPR_NVM_ACCESS_ENABLE 0x86424
#define MCP_REG_MCPR_NVM_ADDR 0x8640c
#define MCP_REG_MCPR_NVM_CFG4 0x8642c
@@ -880,6 +1028,11 @@
rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP Latched
ump_tx_parity; [31] MCP Latched scpad_parity; */
#define MISC_REG_AEU_AFTER_INVERT_4_MCP 0xa458
+/* [R 32] Read fifth 32 bit after inversion of function 0. 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]
+ * CNIG attention (reserved); [7] CNIG parity (reserved); [31-8] Reserved; */
+#define MISC_REG_AEU_AFTER_INVERT_5_FUNC_0 0xa700
/* [W 14] write to this register results with the clear of the latched
signals; one in d0 clears RBCR latch; one in d1 clears RBCT latch; one in
d2 clears RBCN latch; one in d3 clears RBCU latch; one in d4 clears RBCP
@@ -1251,6 +1404,7 @@
#define MISC_REG_E1HMF_MODE 0xa5f8
/* [RW 32] Debug only: spare RW register reset by core reset */
#define MISC_REG_GENERIC_CR_0 0xa460
+#define MISC_REG_GENERIC_CR_1 0xa464
/* [RW 32] Debug only: spare RW register reset by por reset */
#define MISC_REG_GENERIC_POR_1 0xa474
/* [RW 32] GPIO. [31-28] FLOAT port 0; [27-24] FLOAT port 0; When any of
@@ -1373,6 +1527,14 @@
#define MISC_REG_PLL_STORM_CTRL_2 0xa298
#define MISC_REG_PLL_STORM_CTRL_3 0xa29c
#define MISC_REG_PLL_STORM_CTRL_4 0xa2a0
+/* [R 1] Status of 4 port mode enable input pin. */
+#define MISC_REG_PORT4MODE_EN 0xa750
+/* [RW 2] 4 port mode enable overwrite.[0] - Overwrite control; if it is 0 -
+ * the port4mode_en output is equal to 4 port mode input pin; if it is 1 -
+ * the port4mode_en output is equal to bit[1] of this register; [1] -
+ * Overwrite value. If bit[0] of this register is 1 this is the value that
+ * receives the port4mode_en output . */
+#define MISC_REG_PORT4MODE_EN_OVWR 0xa720
/* [RW 32] reset reg#2; rite/read one = the specific block is out of reset;
write/read zero = the specific block is in reset; addr 0-wr- the write
value will be written to the register; addr 1-set - one will be written
@@ -1656,8 +1818,91 @@
/* [R 32] Interrupt register #0 read */
#define NIG_REG_NIG_INT_STS_0 0x103b0
#define NIG_REG_NIG_INT_STS_1 0x103c0
-/* [R 32] Parity register #0 read */
+/* [R 32] Legacy E1 and E1H location for parity error status register. */
#define NIG_REG_NIG_PRTY_STS 0x103d0
+/* [R 32] Parity register #0 read */
+#define NIG_REG_NIG_PRTY_STS_0 0x183bc
+#define NIG_REG_NIG_PRTY_STS_1 0x183cc
+/* [RW 6] Bit-map indicating which L2 hdrs may appear after the basic
+ * Ethernet header. */
+#define NIG_REG_P0_HDRS_AFTER_BASIC 0x18038
+/* [RW 1] HW PFC enable bit. Set this bit to enable the PFC functionality in
+ * the NIG. Other flow control modes such as PAUSE and SAFC/LLFC should be
+ * disabled when this bit is set. */
+#define NIG_REG_P0_HWPFC_ENABLE 0x18078
+#define NIG_REG_P0_LLH_FUNC_MEM2 0x18480
+#define NIG_REG_P0_LLH_FUNC_MEM2_ENABLE 0x18440
+/* [RW 32] Eight 4-bit configurations for specifying which COS (0-15 for
+ * future expansion) each priorty is to be mapped to. Bits 3:0 specify the
+ * COS for priority 0. Bits 31:28 specify the COS for priority 7. The 3-bit
+ * priority field is extracted from the outer-most VLAN in receive packet.
+ * Only COS 0 and COS 1 are supported in E2. */
+#define NIG_REG_P0_PKT_PRIORITY_TO_COS 0x18054
+/* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 0. A
+ * priority is mapped to COS 0 when the corresponding mask bit is 1. More
+ * than one bit may be set; allowing multiple priorities to be mapped to one
+ * COS. */
+#define NIG_REG_P0_RX_COS0_PRIORITY_MASK 0x18058
+/* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 1. A
+ * priority is mapped to COS 1 when the corresponding mask bit is 1. More
+ * than one bit may be set; allowing multiple priorities to be mapped to one
+ * COS. */
+#define NIG_REG_P0_RX_COS1_PRIORITY_MASK 0x1805c
+/* [RW 15] Specify which of the credit registers the client is to be mapped
+ * to. Bits[2:0] are for client 0; bits [14:12] are for client 4. For
+ * clients that are not subject to WFQ credit blocking - their
+ * specifications here are not used. */
+#define NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP 0x180f0
+/* [RW 5] Specify whether the client competes directly in the strict
+ * priority arbiter. The bits are mapped according to client ID (client IDs
+ * are defined in tx_arb_priority_client). Default value is set to enable
+ * strict priorities for clients 0-2 -- management and debug traffic. */
+#define NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT 0x180e8
+/* [RW 5] Specify whether the client is subject to WFQ credit blocking. The
+ * bits are mapped according to client ID (client IDs are defined in
+ * tx_arb_priority_client). Default value is 0 for not using WFQ credit
+ * blocking. */
+#define NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ 0x180ec
+/* [RW 32] Specify the upper bound that credit register 0 is allowed to
+ * reach. */
+#define NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0 0x1810c
+#define NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1 0x18110
+/* [RW 32] Specify the weight (in bytes) to be added to credit register 0
+ * when it is time to increment. */
+#define NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0 0x180f8
+#define NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1 0x180fc
+/* [RW 12] Specify the number of strict priority arbitration slots between
+ * two round-robin arbitration slots to avoid starvation. A value of 0 means
+ * no strict priority cycles - the strict priority with anti-starvation
+ * arbiter becomes a round-robin arbiter. */
+#define NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS 0x180f4
+/* [RW 15] Specify the client number to be assigned to each priority of the
+ * strict priority arbiter. Priority 0 is the highest priority. Bits [2:0]
+ * are for priority 0 client; bits [14:12] are for priority 4 client. The
+ * clients are assigned the following IDs: 0-management; 1-debug traffic
+ * from this port; 2-debug traffic from other port; 3-COS0 traffic; 4-COS1
+ * traffic. The reset value[14:0] is set to 0x4688 (15'b100_011_010_001_000)
+ * for management at priority 0; debug traffic at priorities 1 and 2; COS0
+ * traffic at priority 3; and COS1 traffic at priority 4. */
+#define NIG_REG_P0_TX_ARB_PRIORITY_CLIENT 0x180e4
+#define NIG_REG_P1_LLH_FUNC_MEM2 0x184c0
+#define NIG_REG_P1_LLH_FUNC_MEM2_ENABLE 0x18460
+/* [RW 32] Eight 4-bit configurations for specifying which COS (0-15 for
+ * future expansion) each priorty is to be mapped to. Bits 3:0 specify the
+ * COS for priority 0. Bits 31:28 specify the COS for priority 7. The 3-bit
+ * priority field is extracted from the outer-most VLAN in receive packet.
+ * Only COS 0 and COS 1 are supported in E2. */
+#define NIG_REG_P1_PKT_PRIORITY_TO_COS 0x181a8
+/* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 0. A
+ * priority is mapped to COS 0 when the corresponding mask bit is 1. More
+ * than one bit may be set; allowing multiple priorities to be mapped to one
+ * COS. */
+#define NIG_REG_P1_RX_COS0_PRIORITY_MASK 0x181ac
+/* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 1. A
+ * priority is mapped to COS 1 when the corresponding mask bit is 1. More
+ * than one bit may be set; allowing multiple priorities to be mapped to one
+ * COS. */
+#define NIG_REG_P1_RX_COS1_PRIORITY_MASK 0x181b0
/* [RW 1] Pause enable for port0. This register may get 1 only when
~safc_enable.safc_enable = 0 and ppp_enable.ppp_enable =0 for the same
port */
@@ -1742,6 +1987,10 @@
/* [RW 1] Disable processing further tasks from port 4 (after ending the
current task in process). */
#define PBF_REG_DISABLE_NEW_TASK_PROC_P4 0x14006c
+#define PBF_REG_DISABLE_PF 0x1402e8
+/* [RW 6] Bit-map indicating which L2 hdrs may appear after the basic
+ * Ethernet header. */
+#define PBF_REG_HDRS_AFTER_BASIC 0x15c0a8
#define PBF_REG_IF_ENABLE_REG 0x140044
/* [RW 1] Init bit. When set the initial credits are copied to the credit
registers (except the port credits). Should be set and then reset after
@@ -1765,6 +2014,8 @@
#define PBF_REG_MAC_IF1_ENABLE 0x140034
/* [RW 1] Enable for the loopback interface. */
#define PBF_REG_MAC_LB_ENABLE 0x140040
+/* [RW 6] Bit-map indicating which headers must appear in the packet */
+#define PBF_REG_MUST_HAVE_HDRS 0x15c0c4
/* [RW 10] Port 0 threshold used by arbiter in 16 byte lines used when pause
not suppoterd. */
#define PBF_REG_P0_ARB_THRSH 0x1400e4
@@ -1804,6 +2055,259 @@
#define PB_REG_PB_PRTY_MASK 0x38
/* [R 4] Parity register #0 read */
#define PB_REG_PB_PRTY_STS 0x2c
+#define PGLUE_B_PGLUE_B_INT_STS_REG_ADDRESS_ERROR (0x1<<0)
+#define PGLUE_B_PGLUE_B_INT_STS_REG_CSSNOOP_FIFO_OVERFLOW (0x1<<8)
+#define PGLUE_B_PGLUE_B_INT_STS_REG_INCORRECT_RCV_BEHAVIOR (0x1<<1)
+#define PGLUE_B_PGLUE_B_INT_STS_REG_TCPL_ERROR_ATTN (0x1<<6)
+#define PGLUE_B_PGLUE_B_INT_STS_REG_TCPL_IN_TWO_RCBS_ATTN (0x1<<7)
+#define PGLUE_B_PGLUE_B_INT_STS_REG_VF_GRC_SPACE_VIOLATION_ATTN (0x1<<4)
+#define PGLUE_B_PGLUE_B_INT_STS_REG_VF_LENGTH_VIOLATION_ATTN (0x1<<3)
+#define PGLUE_B_PGLUE_B_INT_STS_REG_VF_MSIX_BAR_VIOLATION_ATTN (0x1<<5)
+#define PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN (0x1<<2)
+/* [R 8] Config space A attention dirty bits. Each bit indicates that the
+ * corresponding PF generates config space A attention. Set by PXP. Reset by
+ * MCP writing 1 to icfg_space_a_request_clr. Note: register contains bits
+ * from both paths. */
+#define PGLUE_B_REG_CFG_SPACE_A_REQUEST 0x9010
+/* [R 8] Config space B attention dirty bits. Each bit indicates that the
+ * corresponding PF generates config space B attention. Set by PXP. Reset by
+ * MCP writing 1 to icfg_space_b_request_clr. Note: register contains bits
+ * from both paths. */
+#define PGLUE_B_REG_CFG_SPACE_B_REQUEST 0x9014
+/* [RW 1] Type A PF enable inbound interrupt table for CSDM. 0 - disable; 1
+ * - enable. */
+#define PGLUE_B_REG_CSDM_INB_INT_A_PF_ENABLE 0x9194
+/* [RW 18] Type B VF inbound interrupt table for CSDM: bits[17:9]-mask;
+ * its[8:0]-address. Bits [1:0] must be zero (DW resolution address). */
+#define PGLUE_B_REG_CSDM_INB_INT_B_VF 0x916c
+/* [RW 1] Type B VF enable inbound interrupt table for CSDM. 0 - disable; 1
+ * - enable. */
+#define PGLUE_B_REG_CSDM_INB_INT_B_VF_ENABLE 0x919c
+/* [RW 16] Start offset of CSDM zone A (queue zone) in the internal RAM */
+#define PGLUE_B_REG_CSDM_START_OFFSET_A 0x9100
+/* [RW 16] Start offset of CSDM zone B (legacy zone) in the internal RAM */
+#define PGLUE_B_REG_CSDM_START_OFFSET_B 0x9108
+/* [RW 5] VF Shift of CSDM zone B (legacy zone) in the internal RAM */
+#define PGLUE_B_REG_CSDM_VF_SHIFT_B 0x9110
+/* [RW 1] 0 - Zone A size is 136x32B; 1 - Zone A size is 152x32B. */
+#define PGLUE_B_REG_CSDM_ZONE_A_SIZE_PF 0x91ac
+/* [R 8] FLR request attention dirty bits for PFs 0 to 7. Each bit indicates
+ * that the FLR register of the corresponding PF was set. Set by PXP. Reset
+ * by MCP writing 1 to flr_request_pf_7_0_clr. Note: register contains bits
+ * from both paths. */
+#define PGLUE_B_REG_FLR_REQUEST_PF_7_0 0x9028
+/* [W 8] FLR request attention dirty bits clear for PFs 0 to 7. MCP writes 1
+ * to a bit in this register in order to clear the corresponding bit in
+ * flr_request_pf_7_0 register. Note: register contains bits from both
+ * paths. */
+#define PGLUE_B_REG_FLR_REQUEST_PF_7_0_CLR 0x9418
+/* [R 32] FLR request attention dirty bits for VFs 96 to 127. Each bit
+ * indicates that the FLR register of the corresponding VF was set. Set by
+ * PXP. Reset by MCP writing 1 to flr_request_vf_127_96_clr. */
+#define PGLUE_B_REG_FLR_REQUEST_VF_127_96 0x9024
+/* [R 32] FLR request attention dirty bits for VFs 0 to 31. Each bit
+ * indicates that the FLR register of the corresponding VF was set. Set by
+ * PXP. Reset by MCP writing 1 to flr_request_vf_31_0_clr. */
+#define PGLUE_B_REG_FLR_REQUEST_VF_31_0 0x9018
+/* [R 32] FLR request attention dirty bits for VFs 32 to 63. Each bit
+ * indicates that the FLR register of the corresponding VF was set. Set by
+ * PXP. Reset by MCP writing 1 to flr_request_vf_63_32_clr. */
+#define PGLUE_B_REG_FLR_REQUEST_VF_63_32 0x901c
+/* [R 32] FLR request attention dirty bits for VFs 64 to 95. Each bit
+ * indicates that the FLR register of the corresponding VF was set. Set by
+ * PXP. Reset by MCP writing 1 to flr_request_vf_95_64_clr. */
+#define PGLUE_B_REG_FLR_REQUEST_VF_95_64 0x9020
+/* [R 8] Each bit indicates an incorrect behavior in user RX interface. Bit
+ * 0 - Target memory read arrived with a correctable error. Bit 1 - Target
+ * memory read arrived with an uncorrectable error. Bit 2 - Configuration RW
+ * arrived with a correctable error. Bit 3 - Configuration RW arrived with
+ * an uncorrectable error. Bit 4 - Completion with Configuration Request
+ * Retry Status. Bit 5 - Expansion ROM access received with a write request.
+ * Bit 6 - Completion with pcie_rx_err of 0000; CMPL_STATUS of non-zero; and
+ * pcie_rx_last not asserted. Bit 7 - Completion with pcie_rx_err of 1010;
+ * and pcie_rx_last not asserted. */
+#define PGLUE_B_REG_INCORRECT_RCV_DETAILS 0x9068
+#define PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER 0x942c
+#define PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ 0x9430
+#define PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_WRITE 0x9434
+#define PGLUE_B_REG_INTERNAL_VFID_ENABLE 0x9438
+/* [R 9] Interrupt register #0 read */
+#define PGLUE_B_REG_PGLUE_B_INT_STS 0x9298
+/* [RC 9] Interrupt register #0 read clear */
+#define PGLUE_B_REG_PGLUE_B_INT_STS_CLR 0x929c
+/* [R 2] Parity register #0 read */
+#define PGLUE_B_REG_PGLUE_B_PRTY_STS 0x92a8
+/* [R 13] Details of first request received with error. [2:0] - PFID. [3] -
+ * VF_VALID. [9:4] - VFID. [11:10] - Error Code - 0 - Indicates Completion
+ * Timeout of a User Tx non-posted request. 1 - unsupported request. 2 -
+ * completer abort. 3 - Illegal value for this field. [12] valid - indicates
+ * if there was a completion error since the last time this register was
+ * cleared. */
+#define PGLUE_B_REG_RX_ERR_DETAILS 0x9080
+/* [R 18] Details of first ATS Translation Completion request received with
+ * error. [2:0] - PFID. [3] - VF_VALID. [9:4] - VFID. [11:10] - Error Code -
+ * 0 - Indicates Completion Timeout of a User Tx non-posted request. 1 -
+ * unsupported request. 2 - completer abort. 3 - Illegal value for this
+ * field. [16:12] - ATC OTB EntryID. [17] valid - indicates if there was a
+ * completion error since the last time this register was cleared. */
+#define PGLUE_B_REG_RX_TCPL_ERR_DETAILS 0x9084
+/* [W 8] Debug only - Shadow BME bits clear for PFs 0 to 7. MCP writes 1 to
+ * a bit in this register in order to clear the corresponding bit in
+ * shadow_bme_pf_7_0 register. MCP should never use this unless a
+ * work-around is needed. Note: register contains bits from both paths. */
+#define PGLUE_B_REG_SHADOW_BME_PF_7_0_CLR 0x9458
+/* [R 8] SR IOV disabled attention dirty bits. Each bit indicates that the
+ * VF enable register of the corresponding PF is written to 0 and was
+ * previously 1. Set by PXP. Reset by MCP writing 1 to
+ * sr_iov_disabled_request_clr. Note: register contains bits from both
+ * paths. */
+#define PGLUE_B_REG_SR_IOV_DISABLED_REQUEST 0x9030
+/* [R 32] Indicates the status of tags 32-63. 0 - tags is used - read
+ * completion did not return yet. 1 - tag is unused. Same functionality as
+ * pxp2_registers_pgl_exp_rom_data2 for tags 0-31. */
+#define PGLUE_B_REG_TAGS_63_32 0x9244
+/* [RW 1] Type A PF enable inbound interrupt table for TSDM. 0 - disable; 1
+ * - enable. */
+#define PGLUE_B_REG_TSDM_INB_INT_A_PF_ENABLE 0x9170
+/* [RW 16] Start offset of TSDM zone A (queue zone) in the internal RAM */
+#define PGLUE_B_REG_TSDM_START_OFFSET_A 0x90c4
+/* [RW 16] Start offset of TSDM zone B (legacy zone) in the internal RAM */
+#define PGLUE_B_REG_TSDM_START_OFFSET_B 0x90cc
+/* [RW 5] VF Shift of TSDM zone B (legacy zone) in the internal RAM */
+#define PGLUE_B_REG_TSDM_VF_SHIFT_B 0x90d4
+/* [RW 1] 0 - Zone A size is 136x32B; 1 - Zone A size is 152x32B. */
+#define PGLUE_B_REG_TSDM_ZONE_A_SIZE_PF 0x91a0
+/* [R 32] Address [31:0] of first read request not submitted due to error */
+#define PGLUE_B_REG_TX_ERR_RD_ADD_31_0 0x9098
+/* [R 32] Address [63:32] of first read request not submitted due to error */
+#define PGLUE_B_REG_TX_ERR_RD_ADD_63_32 0x909c
+/* [R 31] Details of first read request not submitted due to error. [4:0]
+ * VQID. [5] TREQ. 1 - Indicates the request is a Translation Request.
+ * [20:8] - Length in bytes. [23:21] - PFID. [24] - VF_VALID. [30:25] -
+ * VFID. */
+#define PGLUE_B_REG_TX_ERR_RD_DETAILS 0x90a0
+/* [R 26] Details of first read request not submitted due to error. [15:0]
+ * Request ID. [19:16] client ID. [20] - last SR. [24:21] - Error type -
+ * [21] - Indicates was_error was set; [22] - Indicates BME was cleared;
+ * [23] - Indicates FID_enable was cleared; [24] - Indicates VF with parent
+ * PF FLR_request or IOV_disable_request dirty bit is set. [25] valid -
+ * indicates if there was a request not submitted due to error since the
+ * last time this register was cleared. */
+#define PGLUE_B_REG_TX_ERR_RD_DETAILS2 0x90a4
+/* [R 32] Address [31:0] of first write request not submitted due to error */
+#define PGLUE_B_REG_TX_ERR_WR_ADD_31_0 0x9088
+/* [R 32] Address [63:32] of first write request not submitted due to error */
+#define PGLUE_B_REG_TX_ERR_WR_ADD_63_32 0x908c
+/* [R 31] Details of first write request not submitted due to error. [4:0]
+ * VQID. [20:8] - Length in bytes. [23:21] - PFID. [24] - VF_VALID. [30:25]
+ * - VFID. */
+#define PGLUE_B_REG_TX_ERR_WR_DETAILS 0x9090
+/* [R 26] Details of first write request not submitted due to error. [15:0]
+ * Request ID. [19:16] client ID. [20] - last SR. [24:21] - Error type -
+ * [21] - Indicates was_error was set; [22] - Indicates BME was cleared;
+ * [23] - Indicates FID_enable was cleared; [24] - Indicates VF with parent
+ * PF FLR_request or IOV_disable_request dirty bit is set. [25] valid -
+ * indicates if there was a request not submitted due to error since the
+ * last time this register was cleared. */
+#define PGLUE_B_REG_TX_ERR_WR_DETAILS2 0x9094
+/* [RW 10] Type A PF/VF inbound interrupt table for USDM: bits[9:5]-mask;
+ * its[4:0]-address relative to start_offset_a. Bits [1:0] can have any
+ * value (Byte resolution address). */
+#define PGLUE_B_REG_USDM_INB_INT_A_0 0x9128
+#define PGLUE_B_REG_USDM_INB_INT_A_1 0x912c
+#define PGLUE_B_REG_USDM_INB_INT_A_2 0x9130
+#define PGLUE_B_REG_USDM_INB_INT_A_3 0x9134
+#define PGLUE_B_REG_USDM_INB_INT_A_4 0x9138
+#define PGLUE_B_REG_USDM_INB_INT_A_5 0x913c
+#define PGLUE_B_REG_USDM_INB_INT_A_6 0x9140
+/* [RW 1] Type A PF enable inbound interrupt table for USDM. 0 - disable; 1
+ * - enable. */
+#define PGLUE_B_REG_USDM_INB_INT_A_PF_ENABLE 0x917c
+/* [RW 1] Type A VF enable inbound interrupt table for USDM. 0 - disable; 1
+ * - enable. */
+#define PGLUE_B_REG_USDM_INB_INT_A_VF_ENABLE 0x9180
+/* [RW 1] Type B VF enable inbound interrupt table for USDM. 0 - disable; 1
+ * - enable. */
+#define PGLUE_B_REG_USDM_INB_INT_B_VF_ENABLE 0x9184
+/* [RW 16] Start offset of USDM zone A (queue zone) in the internal RAM */
+#define PGLUE_B_REG_USDM_START_OFFSET_A 0x90d8
+/* [RW 16] Start offset of USDM zone B (legacy zone) in the internal RAM */
+#define PGLUE_B_REG_USDM_START_OFFSET_B 0x90e0
+/* [RW 5] VF Shift of USDM zone B (legacy zone) in the internal RAM */
+#define PGLUE_B_REG_USDM_VF_SHIFT_B 0x90e8
+/* [RW 1] 0 - Zone A size is 136x32B; 1 - Zone A size is 152x32B. */
+#define PGLUE_B_REG_USDM_ZONE_A_SIZE_PF 0x91a4
+/* [R 26] Details of first target VF request accessing VF GRC space that
+ * failed permission check. [14:0] Address. [15] w_nr: 0 - Read; 1 - Write.
+ * [21:16] VFID. [24:22] - PFID. [25] valid - indicates if there was a
+ * request accessing VF GRC space that failed permission check since the
+ * last time this register was cleared. Permission checks are: function
+ * permission; R/W permission; address range permission. */
+#define PGLUE_B_REG_VF_GRC_SPACE_VIOLATION_DETAILS 0x9234
+/* [R 31] Details of first target VF request with length violation (too many
+ * DWs) accessing BAR0. [12:0] Address in DWs (bits [14:2] of byte address).
+ * [14:13] BAR. [20:15] VFID. [23:21] - PFID. [29:24] - Length in DWs. [30]
+ * valid - indicates if there was a request with length violation since the
+ * last time this register was cleared. Length violations: length of more
+ * than 2DWs; length of 2DWs and address not QW aligned; window is GRC and
+ * length is more than 1 DW. */
+#define PGLUE_B_REG_VF_LENGTH_VIOLATION_DETAILS 0x9230
+/* [R 8] Was_error indication dirty bits for PFs 0 to 7. Each bit indicates
+ * that there was a completion with uncorrectable error for the
+ * corresponding PF. Set by PXP. Reset by MCP writing 1 to
+ * was_error_pf_7_0_clr. */
+#define PGLUE_B_REG_WAS_ERROR_PF_7_0 0x907c
+/* [W 8] Was_error indication dirty bits clear for PFs 0 to 7. MCP writes 1
+ * to a bit in this register in order to clear the corresponding bit in
+ * flr_request_pf_7_0 register. */
+#define PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR 0x9470
+/* [R 32] Was_error indication dirty bits for VFs 96 to 127. Each bit
+ * indicates that there was a completion with uncorrectable error for the
+ * corresponding VF. Set by PXP. Reset by MCP writing 1 to
+ * was_error_vf_127_96_clr. */
+#define PGLUE_B_REG_WAS_ERROR_VF_127_96 0x9078
+/* [W 32] Was_error indication dirty bits clear for VFs 96 to 127. MCP
+ * writes 1 to a bit in this register in order to clear the corresponding
+ * bit in was_error_vf_127_96 register. */
+#define PGLUE_B_REG_WAS_ERROR_VF_127_96_CLR 0x9474
+/* [R 32] Was_error indication dirty bits for VFs 0 to 31. Each bit
+ * indicates that there was a completion with uncorrectable error for the
+ * corresponding VF. Set by PXP. Reset by MCP writing 1 to
+ * was_error_vf_31_0_clr. */
+#define PGLUE_B_REG_WAS_ERROR_VF_31_0 0x906c
+/* [W 32] Was_error indication dirty bits clear for VFs 0 to 31. MCP writes
+ * 1 to a bit in this register in order to clear the corresponding bit in
+ * was_error_vf_31_0 register. */
+#define PGLUE_B_REG_WAS_ERROR_VF_31_0_CLR 0x9478
+/* [R 32] Was_error indication dirty bits for VFs 32 to 63. Each bit
+ * indicates that there was a completion with uncorrectable error for the
+ * corresponding VF. Set by PXP. Reset by MCP writing 1 to
+ * was_error_vf_63_32_clr. */
+#define PGLUE_B_REG_WAS_ERROR_VF_63_32 0x9070
+/* [W 32] Was_error indication dirty bits clear for VFs 32 to 63. MCP writes
+ * 1 to a bit in this register in order to clear the corresponding bit in
+ * was_error_vf_63_32 register. */
+#define PGLUE_B_REG_WAS_ERROR_VF_63_32_CLR 0x947c
+/* [R 32] Was_error indication dirty bits for VFs 64 to 95. Each bit
+ * indicates that there was a completion with uncorrectable error for the
+ * corresponding VF. Set by PXP. Reset by MCP writing 1 to
+ * was_error_vf_95_64_clr. */
+#define PGLUE_B_REG_WAS_ERROR_VF_95_64 0x9074
+/* [W 32] Was_error indication dirty bits clear for VFs 64 to 95. MCP writes
+ * 1 to a bit in this register in order to clear the corresponding bit in
+ * was_error_vf_95_64 register. */
+#define PGLUE_B_REG_WAS_ERROR_VF_95_64_CLR 0x9480
+/* [RW 1] Type A PF enable inbound interrupt table for XSDM. 0 - disable; 1
+ * - enable. */
+#define PGLUE_B_REG_XSDM_INB_INT_A_PF_ENABLE 0x9188
+/* [RW 16] Start offset of XSDM zone A (queue zone) in the internal RAM */
+#define PGLUE_B_REG_XSDM_START_OFFSET_A 0x90ec
+/* [RW 16] Start offset of XSDM zone B (legacy zone) in the internal RAM */
+#define PGLUE_B_REG_XSDM_START_OFFSET_B 0x90f4
+/* [RW 5] VF Shift of XSDM zone B (legacy zone) in the internal RAM */
+#define PGLUE_B_REG_XSDM_VF_SHIFT_B 0x90fc
+/* [RW 1] 0 - Zone A size is 136x32B; 1 - Zone A size is 152x32B. */
+#define PGLUE_B_REG_XSDM_ZONE_A_SIZE_PF 0x91a8
#define PRS_REG_A_PRSU_20 0x40134
/* [R 8] debug only: CFC load request current credit. Transaction based. */
#define PRS_REG_CFC_LD_CURRENT_CREDIT 0x40164
@@ -1866,9 +2370,13 @@
#define PRS_REG_FLUSH_REGIONS_TYPE_5 0x40018
#define PRS_REG_FLUSH_REGIONS_TYPE_6 0x4001c
#define PRS_REG_FLUSH_REGIONS_TYPE_7 0x40020
+/* [RW 6] Bit-map indicating which L2 hdrs may appear after the basic
+ * Ethernet header. */
+#define PRS_REG_HDRS_AFTER_BASIC 0x40238
/* [RW 4] The increment value to send in the CFC load request message */
#define PRS_REG_INC_VALUE 0x40048
-/* [RW 1] If set indicates not to send messages to CFC on received packets */
+/* [RW 6] Bit-map indicating which headers must appear in the packet */
+#define PRS_REG_MUST_HAVE_HDRS 0x40254
#define PRS_REG_NIC_MODE 0x40138
/* [RW 8] The 8-bit event ID for cases where there is no match on the
connection. Used in packet start message to TCM. */
@@ -1919,6 +2427,13 @@
#define PRS_REG_TCM_CURRENT_CREDIT 0x40160
/* [R 8] debug only: TSDM current credit. Transaction based. */
#define PRS_REG_TSDM_CURRENT_CREDIT 0x4015c
+#define PXP2_PXP2_INT_MASK_0_REG_PGL_CPL_AFT (0x1<<19)
+#define PXP2_PXP2_INT_MASK_0_REG_PGL_CPL_OF (0x1<<20)
+#define PXP2_PXP2_INT_MASK_0_REG_PGL_PCIE_ATTN (0x1<<22)
+#define PXP2_PXP2_INT_MASK_0_REG_PGL_READ_BLOCKED (0x1<<23)
+#define PXP2_PXP2_INT_MASK_0_REG_PGL_WRITE_BLOCKED (0x1<<24)
+#define PXP2_PXP2_INT_STS_0_REG_WR_PGLUE_EOP_ERROR (0x1<<7)
+#define PXP2_PXP2_INT_STS_CLR_0_REG_WR_PGLUE_EOP_ERROR (0x1<<7)
/* [R 6] Debug only: Number of used entries in the data FIFO */
#define PXP2_REG_HST_DATA_FIFO_STATUS 0x12047c
/* [R 7] Debug only: Number of used entries in the header FIFO */
@@ -2244,8 +2759,17 @@
/* [RW 1] When '1'; requests will enter input buffers but wont get out
towards the glue */
#define PXP2_REG_RQ_DISABLE_INPUTS 0x120330
-/* [RW 1] 1 - SR will be aligned by 64B; 0 - SR will be aligned by 8B */
+/* [RW 4] Determines alignment of write SRs when a request is split into
+ * several SRs. 0 - 8B aligned. 1 - 64B aligned. 2 - 128B aligned. 3 - 256B
+ * aligned. 4 - 512B aligned. */
#define PXP2_REG_RQ_DRAM_ALIGN 0x1205b0
+/* [RW 4] Determines alignment of read SRs when a request is split into
+ * several SRs. 0 - 8B aligned. 1 - 64B aligned. 2 - 128B aligned. 3 - 256B
+ * aligned. 4 - 512B aligned. */
+#define PXP2_REG_RQ_DRAM_ALIGN_RD 0x12092c
+/* [RW 1] when set the new alignment method (E2) will be applied; when reset
+ * the original alignment method (E1 E1H) will be applied */
+#define PXP2_REG_RQ_DRAM_ALIGN_SEL 0x120930
/* [RW 1] If 1 ILT failiue will not result in ELT access; An interrupt will
be asserted */
#define PXP2_REG_RQ_ELT_DISABLE 0x12066c
@@ -2436,7 +2960,8 @@
#define PXP_REG_PXP_INT_STS_1 0x103078
/* [RC 32] Interrupt register #0 read clear */
#define PXP_REG_PXP_INT_STS_CLR_0 0x10306c
-/* [RW 26] Parity mask register #0 read/write */
+#define PXP_REG_PXP_INT_STS_CLR_1 0x10307c
+/* [RW 27] Parity mask register #0 read/write */
#define PXP_REG_PXP_PRTY_MASK 0x103094
/* [R 26] Parity register #0 read */
#define PXP_REG_PXP_PRTY_STS 0x103088
@@ -2566,6 +3091,7 @@
#define QM_REG_PAUSESTATE7 0x16e698
/* [RW 2] The PCI attributes field used in the PCI request. */
#define QM_REG_PCIREQAT 0x168054
+#define QM_REG_PF_EN 0x16e70c
/* [R 16] The byte credit of port 0 */
#define QM_REG_PORT0BYTECRD 0x168300
/* [R 16] The byte credit of port 1 */
@@ -3402,6 +3928,14 @@
/* [R 32] Parity register #0 read */
#define TSEM_REG_TSEM_PRTY_STS_0 0x180114
#define TSEM_REG_TSEM_PRTY_STS_1 0x180124
+/* [W 7] VF or PF ID for reset error bit. Values 0-63 reset error bit for 64
+ * VF; values 64-67 reset error for 4 PF; values 68-127 are not valid. */
+#define TSEM_REG_VFPF_ERR_NUM 0x180380
+/* [RW 32] Indirect access to AG context with 32-bits granularity. The bits
+ * [10:8] of the address should be the offset within the accessed LCID
+ * context; the bits [7:0] are the accessed LCID.Example: to write to REG10
+ * LCID100. The RBC address should be 12'ha64. */
+#define UCM_REG_AG_CTX 0xe2000
/* [R 5] Used to read the XX protection CAM occupancy counter. */
#define UCM_REG_CAM_OCCUP 0xe0170
/* [RW 1] CDU AG read Interface enable. If 0 - the request input is
@@ -3851,6 +4385,17 @@
/* [R 32] Parity register #0 read */
#define USEM_REG_USEM_PRTY_STS_0 0x300124
#define USEM_REG_USEM_PRTY_STS_1 0x300134
+/* [W 7] VF or PF ID for reset error bit. Values 0-63 reset error bit for 64
+ * VF; values 64-67 reset error for 4 PF; values 68-127 are not valid. */
+#define USEM_REG_VFPF_ERR_NUM 0x300380
+#define VFC_MEMORIES_RST_REG_CAM_RST (0x1<<0)
+#define VFC_MEMORIES_RST_REG_RAM_RST (0x1<<1)
+#define VFC_REG_MEMORIES_RST 0x1943c
+/* [RW 32] Indirect access to AG context with 32-bits granularity. The bits
+ * [12:8] of the address should be the offset within the accessed LCID
+ * context; the bits [7:0] are the accessed LCID.Example: to write to REG10
+ * LCID100. The RBC address should be 13'ha64. */
+#define XCM_REG_AG_CTX 0x28000
/* [RW 2] The queue index for registration on Aux1 counter flag. */
#define XCM_REG_AUX1_Q 0x20134
/* [RW 2] Per each decision rule the queue index to register to. */
@@ -4333,6 +4878,9 @@
#define XSEM_REG_TS_8_AS 0x280058
/* [RW 3] The arbitration scheme of time_slot 9 */
#define XSEM_REG_TS_9_AS 0x28005c
+/* [W 7] VF or PF ID for reset error bit. Values 0-63 reset error bit for 64
+ * VF; values 64-67 reset error for 4 PF; values 68-127 are not valid. */
+#define XSEM_REG_VFPF_ERR_NUM 0x280380
/* [RW 32] Interrupt mask register #0 read/write */
#define XSEM_REG_XSEM_INT_MASK_0 0x280110
#define XSEM_REG_XSEM_INT_MASK_1 0x280120
@@ -4371,6 +4919,23 @@
#define BIGMAC_REGISTER_TX_SOURCE_ADDR (0x08<<3)
#define BIGMAC_REGISTER_TX_STAT_GTBYT (0x20<<3)
#define BIGMAC_REGISTER_TX_STAT_GTPKT (0x0C<<3)
+#define BIGMAC2_REGISTER_BMAC_CONTROL (0x00<<3)
+#define BIGMAC2_REGISTER_BMAC_XGXS_CONTROL (0x01<<3)
+#define BIGMAC2_REGISTER_CNT_MAX_SIZE (0x05<<3)
+#define BIGMAC2_REGISTER_PFC_CONTROL (0x06<<3)
+#define BIGMAC2_REGISTER_RX_CONTROL (0x3A<<3)
+#define BIGMAC2_REGISTER_RX_LLFC_MSG_FLDS (0x62<<3)
+#define BIGMAC2_REGISTER_RX_MAX_SIZE (0x3C<<3)
+#define BIGMAC2_REGISTER_RX_STAT_GR64 (0x40<<3)
+#define BIGMAC2_REGISTER_RX_STAT_GRIPJ (0x5f<<3)
+#define BIGMAC2_REGISTER_RX_STAT_GRPP (0x51<<3)
+#define BIGMAC2_REGISTER_TX_CONTROL (0x1C<<3)
+#define BIGMAC2_REGISTER_TX_MAX_SIZE (0x1E<<3)
+#define BIGMAC2_REGISTER_TX_PAUSE_CONTROL (0x20<<3)
+#define BIGMAC2_REGISTER_TX_SOURCE_ADDR (0x1D<<3)
+#define BIGMAC2_REGISTER_TX_STAT_GTBYT (0x39<<3)
+#define BIGMAC2_REGISTER_TX_STAT_GTPOK (0x22<<3)
+#define BIGMAC2_REGISTER_TX_STAT_GTPP (0x24<<3)
#define EMAC_LED_1000MB_OVERRIDE (1L<<1)
#define EMAC_LED_100MB_OVERRIDE (1L<<2)
#define EMAC_LED_10MB_OVERRIDE (1L<<3)
@@ -4478,6 +5043,8 @@
#define HW_LOCK_RESOURCE_SPIO 2
#define HW_LOCK_RESOURCE_UNDI 5
#define PRS_FLAG_OVERETH_IPV4 1
+#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 (1<<18)
#define AEU_INPUTS_ATTN_BITS_CCM_HW_INTERRUPT (1<<31)
#define AEU_INPUTS_ATTN_BITS_CDU_HW_INTERRUPT (1<<9)
@@ -4504,6 +5071,8 @@
#define AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR (1<<20)
#define AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR (1<<0)
#define AEU_INPUTS_ATTN_BITS_PBF_HW_INTERRUPT (1<<31)
+#define AEU_INPUTS_ATTN_BITS_PGLUE_HW_INTERRUPT (0x1<<2)
+#define AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR (0x1<<3)
#define AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT (1<<3)
#define AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR (1<<2)
#define AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_HW_INTERRUPT (1<<5)
@@ -4796,6 +5365,253 @@
#define PCI_ID_VAL1 0x434
#define PCI_ID_VAL2 0x438
+#define PXPCS_TL_CONTROL_5 0x814
+#define PXPCS_TL_CONTROL_5_UNKNOWNTYPE_ERR_ATTN (1 << 29) /*WC*/
+#define PXPCS_TL_CONTROL_5_BOUNDARY4K_ERR_ATTN (1 << 28) /*WC*/
+#define PXPCS_TL_CONTROL_5_MRRS_ERR_ATTN (1 << 27) /*WC*/
+#define PXPCS_TL_CONTROL_5_MPS_ERR_ATTN (1 << 26) /*WC*/
+#define PXPCS_TL_CONTROL_5_TTX_BRIDGE_FORWARD_ERR (1 << 25) /*WC*/
+#define PXPCS_TL_CONTROL_5_TTX_TXINTF_OVERFLOW (1 << 24) /*WC*/
+#define PXPCS_TL_CONTROL_5_PHY_ERR_ATTN (1 << 23) /*RO*/
+#define PXPCS_TL_CONTROL_5_DL_ERR_ATTN (1 << 22) /*RO*/
+#define PXPCS_TL_CONTROL_5_TTX_ERR_NP_TAG_IN_USE (1 << 21) /*WC*/
+#define PXPCS_TL_CONTROL_5_TRX_ERR_UNEXP_RTAG (1 << 20) /*WC*/
+#define PXPCS_TL_CONTROL_5_PRI_SIG_TARGET_ABORT1 (1 << 19) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_UNSPPORT1 (1 << 18) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_ECRC1 (1 << 17) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_MALF_TLP1 (1 << 16) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_RX_OFLOW1 (1 << 15) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_UNEXP_CPL1 (1 << 14) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_MASTER_ABRT1 (1 << 13) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_CPL_TIMEOUT1 (1 << 12) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_FC_PRTL1 (1 << 11) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_PSND_TLP1 (1 << 10) /*WC*/
+#define PXPCS_TL_CONTROL_5_PRI_SIG_TARGET_ABORT (1 << 9) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_UNSPPORT (1 << 8) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_ECRC (1 << 7) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_MALF_TLP (1 << 6) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_RX_OFLOW (1 << 5) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_UNEXP_CPL (1 << 4) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_MASTER_ABRT (1 << 3) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_CPL_TIMEOUT (1 << 2) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_FC_PRTL (1 << 1) /*WC*/
+#define PXPCS_TL_CONTROL_5_ERR_PSND_TLP (1 << 0) /*WC*/
+
+
+#define PXPCS_TL_FUNC345_STAT 0x854
+#define PXPCS_TL_FUNC345_STAT_PRI_SIG_TARGET_ABORT4 (1 << 29) /* WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_UNSPPORT4\
+ (1 << 28) /* Unsupported Request Error Status in function4, if \
+ set, generate pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_ECRC4\
+ (1 << 27) /* ECRC Error TLP Status Status in function 4, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_MALF_TLP4\
+ (1 << 26) /* Malformed TLP Status Status in function 4, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_RX_OFLOW4\
+ (1 << 25) /* Receiver Overflow Status Status in function 4, if \
+ set, generate pcie_err_attn output when this error is seen.. WC \
+ */
+#define PXPCS_TL_FUNC345_STAT_ERR_UNEXP_CPL4\
+ (1 << 24) /* Unexpected Completion Status Status in function 4, \
+ if set, generate pcie_err_attn output when this error is seen. WC \
+ */
+#define PXPCS_TL_FUNC345_STAT_ERR_MASTER_ABRT4\
+ (1 << 23) /* Receive UR Statusin function 4. If set, generate \
+ pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_CPL_TIMEOUT4\
+ (1 << 22) /* Completer Timeout Status Status in function 4, if \
+ set, generate pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_FC_PRTL4\
+ (1 << 21) /* Flow Control Protocol Error Status Status in \
+ function 4, if set, generate pcie_err_attn output when this error \
+ is seen. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_PSND_TLP4\
+ (1 << 20) /* Poisoned Error Status Status in function 4, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC345_STAT_PRI_SIG_TARGET_ABORT3 (1 << 19) /* WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_UNSPPORT3\
+ (1 << 18) /* Unsupported Request Error Status in function3, if \
+ set, generate pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_ECRC3\
+ (1 << 17) /* ECRC Error TLP Status Status in function 3, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_MALF_TLP3\
+ (1 << 16) /* Malformed TLP Status Status in function 3, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_RX_OFLOW3\
+ (1 << 15) /* Receiver Overflow Status Status in function 3, if \
+ set, generate pcie_err_attn output when this error is seen.. WC \
+ */
+#define PXPCS_TL_FUNC345_STAT_ERR_UNEXP_CPL3\
+ (1 << 14) /* Unexpected Completion Status Status in function 3, \
+ if set, generate pcie_err_attn output when this error is seen. WC \
+ */
+#define PXPCS_TL_FUNC345_STAT_ERR_MASTER_ABRT3\
+ (1 << 13) /* Receive UR Statusin function 3. If set, generate \
+ pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_CPL_TIMEOUT3\
+ (1 << 12) /* Completer Timeout Status Status in function 3, if \
+ set, generate pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_FC_PRTL3\
+ (1 << 11) /* Flow Control Protocol Error Status Status in \
+ function 3, if set, generate pcie_err_attn output when this error \
+ is seen. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_PSND_TLP3\
+ (1 << 10) /* Poisoned Error Status Status in function 3, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC345_STAT_PRI_SIG_TARGET_ABORT2 (1 << 9) /* WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_UNSPPORT2\
+ (1 << 8) /* Unsupported Request Error Status for Function 2, if \
+ set, generate pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_ECRC2\
+ (1 << 7) /* ECRC Error TLP Status Status for Function 2, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_MALF_TLP2\
+ (1 << 6) /* Malformed TLP Status Status for Function 2, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_RX_OFLOW2\
+ (1 << 5) /* Receiver Overflow Status Status for Function 2, if \
+ set, generate pcie_err_attn output when this error is seen.. WC \
+ */
+#define PXPCS_TL_FUNC345_STAT_ERR_UNEXP_CPL2\
+ (1 << 4) /* Unexpected Completion Status Status for Function 2, \
+ if set, generate pcie_err_attn output when this error is seen. WC \
+ */
+#define PXPCS_TL_FUNC345_STAT_ERR_MASTER_ABRT2\
+ (1 << 3) /* Receive UR Statusfor Function 2. If set, generate \
+ pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_CPL_TIMEOUT2\
+ (1 << 2) /* Completer Timeout Status Status for Function 2, if \
+ set, generate pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_FC_PRTL2\
+ (1 << 1) /* Flow Control Protocol Error Status Status for \
+ Function 2, if set, generate pcie_err_attn output when this error \
+ is seen. WC */
+#define PXPCS_TL_FUNC345_STAT_ERR_PSND_TLP2\
+ (1 << 0) /* Poisoned Error Status Status for Function 2, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+
+
+#define PXPCS_TL_FUNC678_STAT 0x85C
+#define PXPCS_TL_FUNC678_STAT_PRI_SIG_TARGET_ABORT7 (1 << 29) /* WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_UNSPPORT7\
+ (1 << 28) /* Unsupported Request Error Status in function7, if \
+ set, generate pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_ECRC7\
+ (1 << 27) /* ECRC Error TLP Status Status in function 7, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_MALF_TLP7\
+ (1 << 26) /* Malformed TLP Status Status in function 7, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_RX_OFLOW7\
+ (1 << 25) /* Receiver Overflow Status Status in function 7, if \
+ set, generate pcie_err_attn output when this error is seen.. WC \
+ */
+#define PXPCS_TL_FUNC678_STAT_ERR_UNEXP_CPL7\
+ (1 << 24) /* Unexpected Completion Status Status in function 7, \
+ if set, generate pcie_err_attn output when this error is seen. WC \
+ */
+#define PXPCS_TL_FUNC678_STAT_ERR_MASTER_ABRT7\
+ (1 << 23) /* Receive UR Statusin function 7. If set, generate \
+ pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_CPL_TIMEOUT7\
+ (1 << 22) /* Completer Timeout Status Status in function 7, if \
+ set, generate pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_FC_PRTL7\
+ (1 << 21) /* Flow Control Protocol Error Status Status in \
+ function 7, if set, generate pcie_err_attn output when this error \
+ is seen. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_PSND_TLP7\
+ (1 << 20) /* Poisoned Error Status Status in function 7, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC678_STAT_PRI_SIG_TARGET_ABORT6 (1 << 19) /* WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_UNSPPORT6\
+ (1 << 18) /* Unsupported Request Error Status in function6, if \
+ set, generate pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_ECRC6\
+ (1 << 17) /* ECRC Error TLP Status Status in function 6, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_MALF_TLP6\
+ (1 << 16) /* Malformed TLP Status Status in function 6, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_RX_OFLOW6\
+ (1 << 15) /* Receiver Overflow Status Status in function 6, if \
+ set, generate pcie_err_attn output when this error is seen.. WC \
+ */
+#define PXPCS_TL_FUNC678_STAT_ERR_UNEXP_CPL6\
+ (1 << 14) /* Unexpected Completion Status Status in function 6, \
+ if set, generate pcie_err_attn output when this error is seen. WC \
+ */
+#define PXPCS_TL_FUNC678_STAT_ERR_MASTER_ABRT6\
+ (1 << 13) /* Receive UR Statusin function 6. If set, generate \
+ pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_CPL_TIMEOUT6\
+ (1 << 12) /* Completer Timeout Status Status in function 6, if \
+ set, generate pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_FC_PRTL6\
+ (1 << 11) /* Flow Control Protocol Error Status Status in \
+ function 6, if set, generate pcie_err_attn output when this error \
+ is seen. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_PSND_TLP6\
+ (1 << 10) /* Poisoned Error Status Status in function 6, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC678_STAT_PRI_SIG_TARGET_ABORT5 (1 << 9) /* WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_UNSPPORT5\
+ (1 << 8) /* Unsupported Request Error Status for Function 5, if \
+ set, generate pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_ECRC5\
+ (1 << 7) /* ECRC Error TLP Status Status for Function 5, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_MALF_TLP5\
+ (1 << 6) /* Malformed TLP Status Status for Function 5, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_RX_OFLOW5\
+ (1 << 5) /* Receiver Overflow Status Status for Function 5, if \
+ set, generate pcie_err_attn output when this error is seen.. WC \
+ */
+#define PXPCS_TL_FUNC678_STAT_ERR_UNEXP_CPL5\
+ (1 << 4) /* Unexpected Completion Status Status for Function 5, \
+ if set, generate pcie_err_attn output when this error is seen. WC \
+ */
+#define PXPCS_TL_FUNC678_STAT_ERR_MASTER_ABRT5\
+ (1 << 3) /* Receive UR Statusfor Function 5. If set, generate \
+ pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_CPL_TIMEOUT5\
+ (1 << 2) /* Completer Timeout Status Status for Function 5, if \
+ set, generate pcie_err_attn output when this error is seen. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_FC_PRTL5\
+ (1 << 1) /* Flow Control Protocol Error Status Status for \
+ Function 5, if set, generate pcie_err_attn output when this error \
+ is seen. WC */
+#define PXPCS_TL_FUNC678_STAT_ERR_PSND_TLP5\
+ (1 << 0) /* Poisoned Error Status Status for Function 5, if set, \
+ generate pcie_err_attn output when this error is seen.. WC */
+
+
+#define BAR_USTRORM_INTMEM 0x400000
+#define BAR_CSTRORM_INTMEM 0x410000
+#define BAR_XSTRORM_INTMEM 0x420000
+#define BAR_TSTRORM_INTMEM 0x430000
+
+/* for accessing the IGU in case of status block ACK */
+#define BAR_IGU_INTMEM 0x440000
+
+#define BAR_DOORBELL_OFFSET 0x800000
+
+#define BAR_ME_REGISTER 0x450000
+#define ME_REG_PF_NUM_SHIFT 0
+#define ME_REG_PF_NUM\
+ (7L<<ME_REG_PF_NUM_SHIFT) /* Relative PF Num */
+#define ME_REG_VF_VALID (1<<8)
+#define ME_REG_VF_NUM_SHIFT 9
+#define ME_REG_VF_NUM_MASK (0x3f<<ME_REG_VF_NUM_SHIFT)
+#define ME_REG_VF_ERR (0x1<<3)
+#define ME_REG_ABS_PF_NUM_SHIFT 16
+#define ME_REG_ABS_PF_NUM\
+ (7L<<ME_REG_ABS_PF_NUM_SHIFT) /* Absolute PF Num */
+
#define MDIO_REG_BANK_CL73_IEEEB0 0x0
#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL 0x0
@@ -4964,6 +5780,8 @@
#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN 0x0001
#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_AN_FST_TMR 0x0040
#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1 0x14
+#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SGMII 0x0001
+#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_LINK 0x0002
#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_DUPLEX 0x0004
#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_MASK 0x0018
#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_SHIFT 3
@@ -5135,28 +5953,35 @@ Theotherbitsarereservedandshouldbezero*/
#define MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR 0x8005
#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF 0x8007
#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK 0xff
-#define MDIO_PMA_REG_8727_MISC_CTRL 0x8309
#define MDIO_PMA_REG_8727_TX_CTRL1 0xca02
#define MDIO_PMA_REG_8727_TX_CTRL2 0xca05
#define MDIO_PMA_REG_8727_PCS_OPT_CTRL 0xc808
#define MDIO_PMA_REG_8727_GPIO_CTRL 0xc80e
+#define MDIO_PMA_REG_8727_PCS_GP 0xc842
+
+#define MDIO_AN_REG_8727_MISC_CTRL 0x8309
#define MDIO_PMA_REG_8073_CHIP_REV 0xc801
#define MDIO_PMA_REG_8073_SPEED_LINK_STATUS 0xc820
#define MDIO_PMA_REG_8073_XAUI_WA 0xc841
+#define MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL 0xcd08
#define MDIO_PMA_REG_7101_RESET 0xc000
#define MDIO_PMA_REG_7107_LED_CNTL 0xc007
+#define MDIO_PMA_REG_7107_LINK_LED_CNTL 0xc009
#define MDIO_PMA_REG_7101_VER1 0xc026
#define MDIO_PMA_REG_7101_VER2 0xc027
-#define MDIO_PMA_REG_8481_PMD_SIGNAL 0xa811
-#define MDIO_PMA_REG_8481_LED1_MASK 0xa82c
-#define MDIO_PMA_REG_8481_LED2_MASK 0xa82f
-#define MDIO_PMA_REG_8481_LED3_MASK 0xa832
-#define MDIO_PMA_REG_8481_LED3_BLINK 0xa834
-#define MDIO_PMA_REG_8481_SIGNAL_MASK 0xa835
-#define MDIO_PMA_REG_8481_LINK_SIGNAL 0xa83b
+#define MDIO_PMA_REG_8481_PMD_SIGNAL 0xa811
+#define MDIO_PMA_REG_8481_LED1_MASK 0xa82c
+#define MDIO_PMA_REG_8481_LED2_MASK 0xa82f
+#define MDIO_PMA_REG_8481_LED3_MASK 0xa832
+#define MDIO_PMA_REG_8481_LED3_BLINK 0xa834
+#define MDIO_PMA_REG_8481_LED5_MASK 0xa838
+#define MDIO_PMA_REG_8481_SIGNAL_MASK 0xa835
+#define MDIO_PMA_REG_8481_LINK_SIGNAL 0xa83b
+#define MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK 0x800
+#define MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT 11
#define MDIO_WIS_DEVAD 0x2
@@ -5188,6 +6013,8 @@ Theotherbitsarereservedandshouldbezero*/
#define MDIO_XS_8706_REG_BANK_RX3 0x80ec
#define MDIO_XS_8706_REG_BANK_RXA 0x80fc
+#define MDIO_XS_REG_8073_RX_CTRL_PCIE 0x80FA
+
#define MDIO_AN_DEVAD 0x7
/*ieee*/
#define MDIO_AN_REG_CTRL 0x0000
@@ -5210,14 +6037,40 @@ Theotherbitsarereservedandshouldbezero*/
#define MDIO_AN_REG_CL37_FC_LP 0xffe5
#define MDIO_AN_REG_8073_2_5G 0x8329
+#define MDIO_AN_REG_8073_BAM 0x8350
+#define MDIO_AN_REG_8481_10GBASE_T_AN_CTRL 0x0020
#define MDIO_AN_REG_8481_LEGACY_MII_CTRL 0xffe0
+#define MDIO_AN_REG_8481_LEGACY_MII_STATUS 0xffe1
#define MDIO_AN_REG_8481_LEGACY_AN_ADV 0xffe4
+#define MDIO_AN_REG_8481_LEGACY_AN_EXPANSION 0xffe6
#define MDIO_AN_REG_8481_1000T_CTRL 0xffe9
#define MDIO_AN_REG_8481_EXPANSION_REG_RD_RW 0xfff5
#define MDIO_AN_REG_8481_EXPANSION_REG_ACCESS 0xfff7
+#define MDIO_AN_REG_8481_AUX_CTRL 0xfff8
#define MDIO_AN_REG_8481_LEGACY_SHADOW 0xfffc
+/* BCM84823 only */
+#define MDIO_CTL_DEVAD 0x1e
+#define MDIO_CTL_REG_84823_MEDIA 0x401a
+#define MDIO_CTL_REG_84823_MEDIA_MAC_MASK 0x0018
+ /* These pins configure the BCM84823 interface to MAC after reset. */
+#define MDIO_CTL_REG_84823_CTRL_MAC_XFI 0x0008
+#define MDIO_CTL_REG_84823_MEDIA_MAC_XAUI_M 0x0010
+ /* These pins configure the BCM84823 interface to Line after reset. */
+#define MDIO_CTL_REG_84823_MEDIA_LINE_MASK 0x0060
+#define MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L 0x0020
+#define MDIO_CTL_REG_84823_MEDIA_LINE_XFI 0x0040
+ /* When this pin is active high during reset, 10GBASE-T core is power
+ * down, When it is active low the 10GBASE-T is power up
+ */
+#define MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN 0x0080
+#define MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK 0x0100
+#define MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER 0x0000
+#define MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER 0x0100
+#define MDIO_CTL_REG_84823_MEDIA_FIBER_1G 0x1000
+
+
#define IGU_FUNC_BASE 0x0400
#define IGU_ADDR_MSIX 0x0000
@@ -5239,6 +6092,11 @@ Theotherbitsarereservedandshouldbezero*/
#define IGU_INT_NOP 2
#define IGU_INT_NOP2 3
+#define IGU_USE_REGISTER_ustorm_type_0_sb_cleanup 0
+#define IGU_USE_REGISTER_ustorm_type_1_sb_cleanup 1
+#define IGU_USE_REGISTER_cstorm_type_0_sb_cleanup 2
+#define IGU_USE_REGISTER_cstorm_type_1_sb_cleanup 3
+
#define COMMAND_REG_INT_ACK 0x0
#define COMMAND_REG_PROD_UPD 0x4
#define COMMAND_REG_ATTN_BITS_UPD 0x8
@@ -5281,6 +6139,50 @@ Theotherbitsarereservedandshouldbezero*/
#define IGU_REG_SISR_MDPC_WOMASK_UPPER 0x05a6
#define IGU_REG_RESERVED_UPPER 0x05ff
+/* Fields of IGU PF CONFIGRATION REGISTER */
+#define IGU_PF_CONF_FUNC_EN (0x1<<0) /* function enable */
+#define IGU_PF_CONF_MSI_MSIX_EN (0x1<<1) /* MSI/MSIX enable */
+#define IGU_PF_CONF_INT_LINE_EN (0x1<<2) /* INT enable */
+#define IGU_PF_CONF_ATTN_BIT_EN (0x1<<3) /* attention enable */
+#define IGU_PF_CONF_SINGLE_ISR_EN (0x1<<4) /* single ISR mode enable */
+#define IGU_PF_CONF_SIMD_MODE (0x1<<5) /* simd all ones mode */
+
+/* Fields of IGU VF CONFIGRATION REGISTER */
+#define IGU_VF_CONF_FUNC_EN (0x1<<0) /* function enable */
+#define IGU_VF_CONF_MSI_MSIX_EN (0x1<<1) /* MSI/MSIX enable */
+#define IGU_VF_CONF_PARENT_MASK (0x3<<2) /* Parent PF */
+#define IGU_VF_CONF_PARENT_SHIFT 2 /* Parent PF */
+#define IGU_VF_CONF_SINGLE_ISR_EN (0x1<<4) /* single ISR mode enable */
+
+
+#define IGU_BC_DSB_NUM_SEGS 5
+#define IGU_BC_NDSB_NUM_SEGS 2
+#define IGU_NORM_DSB_NUM_SEGS 2
+#define IGU_NORM_NDSB_NUM_SEGS 1
+#define IGU_BC_BASE_DSB_PROD 128
+#define IGU_NORM_BASE_DSB_PROD 136
+
+#define IGU_CTRL_CMD_TYPE_WR\
+ 1
+#define IGU_CTRL_CMD_TYPE_RD\
+ 0
+
+#define IGU_SEG_ACCESS_NORM 0
+#define IGU_SEG_ACCESS_DEF 1
+#define IGU_SEG_ACCESS_ATTN 2
+
+ /* FID (if VF - [6] = 0; [5:0] = VF number; if PF - [6] = 1; \
+ [5:2] = 0; [1:0] = PF number) */
+#define IGU_FID_ENCODE_IS_PF (0x1<<6)
+#define IGU_FID_ENCODE_IS_PF_SHIFT 6
+#define IGU_FID_VF_NUM_MASK (0x3f)
+#define IGU_FID_PF_NUM_MASK (0x7)
+
+#define IGU_REG_MAPPING_MEMORY_VALID (1<<0)
+#define IGU_REG_MAPPING_MEMORY_VECTOR_MASK (0x3F<<1)
+#define IGU_REG_MAPPING_MEMORY_VECTOR_SHIFT 1
+#define IGU_REG_MAPPING_MEMORY_FID_MASK (0x7F<<7)
+#define IGU_REG_MAPPING_MEMORY_FID_SHIFT 7
#define CDU_REGION_NUMBER_XCM_AG 2
diff --git a/drivers/net/bnx2x/bnx2x_stats.c b/drivers/net/bnx2x/bnx2x_stats.c
index c74724461020..4733c835dad9 100644
--- a/drivers/net/bnx2x/bnx2x_stats.c
+++ b/drivers/net/bnx2x/bnx2x_stats.c
@@ -14,8 +14,8 @@
* Statistics and Link management by Yitchak Gertner
*
*/
- #include "bnx2x_cmn.h"
- #include "bnx2x_stats.h"
+#include "bnx2x_cmn.h"
+#include "bnx2x_stats.h"
/* Statistics */
@@ -153,7 +153,7 @@ static inline long bnx2x_hilo(u32 *hiref)
static void bnx2x_storm_stats_post(struct bnx2x *bp)
{
if (!bp->stats_pending) {
- struct eth_query_ramrod_data ramrod_data = {0};
+ struct common_query_ramrod_data ramrod_data = {0};
int i, rc;
spin_lock_bh(&bp->stats_lock);
@@ -163,14 +163,11 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp)
for_each_queue(bp, i)
ramrod_data.ctr_id_vector |= (1 << bp->fp[i].cl_id);
- rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_STAT_QUERY, 0,
+ rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0,
((u32 *)&ramrod_data)[1],
- ((u32 *)&ramrod_data)[0], 0);
- if (rc == 0) {
- /* stats ramrod has it's own slot on the spq */
- bp->spq_left++;
+ ((u32 *)&ramrod_data)[0], 1);
+ if (rc == 0)
bp->stats_pending = 1;
- }
spin_unlock_bh(&bp->stats_lock);
}
@@ -188,20 +185,12 @@ static void bnx2x_hw_stats_post(struct bnx2x *bp)
/* loader */
if (bp->executer_idx) {
int loader_idx = PMF_DMAE_C(bp);
+ u32 opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_PCI, DMAE_DST_GRC,
+ true, DMAE_COMP_GRC);
+ opcode = bnx2x_dmae_opcode_clr_src_reset(opcode);
memset(dmae, 0, sizeof(struct dmae_command));
-
- dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
- DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
- DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (BP_PORT(bp) ? DMAE_CMD_PORT_1 :
- DMAE_CMD_PORT_0) |
- (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+ dmae->opcode = opcode;
dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, dmae[0]));
dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, dmae[0]));
dmae->dst_addr_lo = (DMAE_REG_CMD_MEM +
@@ -253,26 +242,17 @@ static void bnx2x_stats_pmf_update(struct bnx2x *bp)
u32 *stats_comp = bnx2x_sp(bp, stats_comp);
/* sanity */
- if (!IS_E1HMF(bp) || !bp->port.pmf || !bp->port.port_stx) {
+ if (!IS_MF(bp) || !bp->port.pmf || !bp->port.port_stx) {
BNX2X_ERR("BUG!\n");
return;
}
bp->executer_idx = 0;
- opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
- DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+ opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_GRC, DMAE_DST_PCI, false, 0);
dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = (opcode | DMAE_CMD_C_DST_GRC);
+ dmae->opcode = bnx2x_dmae_opcode_add_comp(opcode, DMAE_COMP_GRC);
dmae->src_addr_lo = bp->port.port_stx >> 2;
dmae->src_addr_hi = 0;
dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
@@ -283,7 +263,7 @@ static void bnx2x_stats_pmf_update(struct bnx2x *bp)
dmae->comp_val = 1;
dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI);
+ dmae->opcode = bnx2x_dmae_opcode_add_comp(opcode, DMAE_COMP_PCI);
dmae->src_addr_lo = (bp->port.port_stx >> 2) + DMAE_LEN32_RD_MAX;
dmae->src_addr_hi = 0;
dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats) +
@@ -304,7 +284,6 @@ static void bnx2x_port_stats_init(struct bnx2x *bp)
{
struct dmae_command *dmae;
int port = BP_PORT(bp);
- int vn = BP_E1HVN(bp);
u32 opcode;
int loader_idx = PMF_DMAE_C(bp);
u32 mac_addr;
@@ -319,16 +298,8 @@ static void bnx2x_port_stats_init(struct bnx2x *bp)
bp->executer_idx = 0;
/* MCP */
- opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
- DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (vn << DMAE_CMD_E1HVN_SHIFT));
+ opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_PCI, DMAE_DST_GRC,
+ true, DMAE_COMP_GRC);
if (bp->port.port_stx) {
@@ -359,16 +330,8 @@ static void bnx2x_port_stats_init(struct bnx2x *bp)
}
/* MAC */
- opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
- DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (vn << DMAE_CMD_E1HVN_SHIFT));
+ opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_GRC, DMAE_DST_PCI,
+ true, DMAE_COMP_GRC);
if (bp->link_vars.mac_type == MAC_TYPE_BMAC) {
@@ -379,13 +342,21 @@ static void bnx2x_port_stats_init(struct bnx2x *bp)
BIGMAC_REGISTER_TX_STAT_GTBYT */
dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
dmae->opcode = opcode;
- dmae->src_addr_lo = (mac_addr +
+ if (CHIP_IS_E1x(bp)) {
+ dmae->src_addr_lo = (mac_addr +
BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2;
+ dmae->len = (8 + BIGMAC_REGISTER_TX_STAT_GTBYT -
+ BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2;
+ } else {
+ dmae->src_addr_lo = (mac_addr +
+ BIGMAC2_REGISTER_TX_STAT_GTPOK) >> 2;
+ dmae->len = (8 + BIGMAC2_REGISTER_TX_STAT_GTBYT -
+ BIGMAC2_REGISTER_TX_STAT_GTPOK) >> 2;
+ }
+
dmae->src_addr_hi = 0;
dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats));
dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats));
- dmae->len = (8 + BIGMAC_REGISTER_TX_STAT_GTBYT -
- BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2;
dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
dmae->comp_addr_hi = 0;
dmae->comp_val = 1;
@@ -394,15 +365,31 @@ static void bnx2x_port_stats_init(struct bnx2x *bp)
BIGMAC_REGISTER_RX_STAT_GRIPJ */
dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
dmae->opcode = opcode;
- dmae->src_addr_lo = (mac_addr +
- BIGMAC_REGISTER_RX_STAT_GR64) >> 2;
dmae->src_addr_hi = 0;
- dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
- offsetof(struct bmac_stats, rx_stat_gr64_lo));
- dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
- offsetof(struct bmac_stats, rx_stat_gr64_lo));
- dmae->len = (8 + BIGMAC_REGISTER_RX_STAT_GRIPJ -
- BIGMAC_REGISTER_RX_STAT_GR64) >> 2;
+ if (CHIP_IS_E1x(bp)) {
+ dmae->src_addr_lo = (mac_addr +
+ BIGMAC_REGISTER_RX_STAT_GR64) >> 2;
+ dmae->dst_addr_lo =
+ U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
+ offsetof(struct bmac1_stats, rx_stat_gr64_lo));
+ dmae->dst_addr_hi =
+ U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
+ offsetof(struct bmac1_stats, rx_stat_gr64_lo));
+ dmae->len = (8 + BIGMAC_REGISTER_RX_STAT_GRIPJ -
+ BIGMAC_REGISTER_RX_STAT_GR64) >> 2;
+ } else {
+ dmae->src_addr_lo =
+ (mac_addr + BIGMAC2_REGISTER_RX_STAT_GR64) >> 2;
+ dmae->dst_addr_lo =
+ U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
+ offsetof(struct bmac2_stats, rx_stat_gr64_lo));
+ dmae->dst_addr_hi =
+ U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
+ offsetof(struct bmac2_stats, rx_stat_gr64_lo));
+ dmae->len = (8 + BIGMAC2_REGISTER_RX_STAT_GRIPJ -
+ BIGMAC2_REGISTER_RX_STAT_GR64) >> 2;
+ }
+
dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
dmae->comp_addr_hi = 0;
dmae->comp_val = 1;
@@ -483,16 +470,8 @@ static void bnx2x_port_stats_init(struct bnx2x *bp)
dmae->comp_val = 1;
dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
- DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (vn << DMAE_CMD_E1HVN_SHIFT));
+ dmae->opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_GRC, DMAE_DST_PCI,
+ true, DMAE_COMP_PCI);
dmae->src_addr_lo = (port ? NIG_REG_STAT1_EGRESS_MAC_PKT1 :
NIG_REG_STAT0_EGRESS_MAC_PKT1) >> 2;
dmae->src_addr_hi = 0;
@@ -522,16 +501,8 @@ static void bnx2x_func_stats_init(struct bnx2x *bp)
bp->executer_idx = 0;
memset(dmae, 0, sizeof(struct dmae_command));
- dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
- DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+ dmae->opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_PCI, DMAE_DST_GRC,
+ true, DMAE_COMP_PCI);
dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats));
dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats));
dmae->dst_addr_lo = bp->func_stx >> 2;
@@ -571,7 +542,6 @@ static void bnx2x_stats_restart(struct bnx2x *bp)
static void bnx2x_bmac_stats_update(struct bnx2x *bp)
{
- struct bmac_stats *new = bnx2x_sp(bp, mac_stats.bmac_stats);
struct host_port_stats *pstats = bnx2x_sp(bp, port_stats);
struct bnx2x_eth_stats *estats = &bp->eth_stats;
struct {
@@ -579,35 +549,74 @@ static void bnx2x_bmac_stats_update(struct bnx2x *bp)
u32 hi;
} diff;
- UPDATE_STAT64(rx_stat_grerb, rx_stat_ifhcinbadoctets);
- UPDATE_STAT64(rx_stat_grfcs, rx_stat_dot3statsfcserrors);
- UPDATE_STAT64(rx_stat_grund, rx_stat_etherstatsundersizepkts);
- UPDATE_STAT64(rx_stat_grovr, rx_stat_dot3statsframestoolong);
- UPDATE_STAT64(rx_stat_grfrg, rx_stat_etherstatsfragments);
- UPDATE_STAT64(rx_stat_grjbr, rx_stat_etherstatsjabbers);
- UPDATE_STAT64(rx_stat_grxcf, rx_stat_maccontrolframesreceived);
- UPDATE_STAT64(rx_stat_grxpf, rx_stat_xoffstateentered);
- UPDATE_STAT64(rx_stat_grxpf, rx_stat_bmac_xpf);
- UPDATE_STAT64(tx_stat_gtxpf, tx_stat_outxoffsent);
- UPDATE_STAT64(tx_stat_gtxpf, tx_stat_flowcontroldone);
- UPDATE_STAT64(tx_stat_gt64, tx_stat_etherstatspkts64octets);
- UPDATE_STAT64(tx_stat_gt127,
+ if (CHIP_IS_E1x(bp)) {
+ struct bmac1_stats *new = bnx2x_sp(bp, mac_stats.bmac1_stats);
+
+ /* the macros below will use "bmac1_stats" type */
+ UPDATE_STAT64(rx_stat_grerb, rx_stat_ifhcinbadoctets);
+ UPDATE_STAT64(rx_stat_grfcs, rx_stat_dot3statsfcserrors);
+ UPDATE_STAT64(rx_stat_grund, rx_stat_etherstatsundersizepkts);
+ UPDATE_STAT64(rx_stat_grovr, rx_stat_dot3statsframestoolong);
+ UPDATE_STAT64(rx_stat_grfrg, rx_stat_etherstatsfragments);
+ UPDATE_STAT64(rx_stat_grjbr, rx_stat_etherstatsjabbers);
+ UPDATE_STAT64(rx_stat_grxcf, rx_stat_maccontrolframesreceived);
+ UPDATE_STAT64(rx_stat_grxpf, rx_stat_xoffstateentered);
+ UPDATE_STAT64(rx_stat_grxpf, rx_stat_bmac_xpf);
+ UPDATE_STAT64(tx_stat_gtxpf, tx_stat_outxoffsent);
+ UPDATE_STAT64(tx_stat_gtxpf, tx_stat_flowcontroldone);
+ UPDATE_STAT64(tx_stat_gt64, tx_stat_etherstatspkts64octets);
+ UPDATE_STAT64(tx_stat_gt127,
+ tx_stat_etherstatspkts65octetsto127octets);
+ UPDATE_STAT64(tx_stat_gt255,
+ tx_stat_etherstatspkts128octetsto255octets);
+ UPDATE_STAT64(tx_stat_gt511,
+ tx_stat_etherstatspkts256octetsto511octets);
+ UPDATE_STAT64(tx_stat_gt1023,
+ tx_stat_etherstatspkts512octetsto1023octets);
+ UPDATE_STAT64(tx_stat_gt1518,
+ tx_stat_etherstatspkts1024octetsto1522octets);
+ UPDATE_STAT64(tx_stat_gt2047, tx_stat_bmac_2047);
+ UPDATE_STAT64(tx_stat_gt4095, tx_stat_bmac_4095);
+ UPDATE_STAT64(tx_stat_gt9216, tx_stat_bmac_9216);
+ UPDATE_STAT64(tx_stat_gt16383, tx_stat_bmac_16383);
+ UPDATE_STAT64(tx_stat_gterr,
+ tx_stat_dot3statsinternalmactransmiterrors);
+ UPDATE_STAT64(tx_stat_gtufl, tx_stat_bmac_ufl);
+
+ } else {
+ struct bmac2_stats *new = bnx2x_sp(bp, mac_stats.bmac2_stats);
+
+ /* the macros below will use "bmac2_stats" type */
+ UPDATE_STAT64(rx_stat_grerb, rx_stat_ifhcinbadoctets);
+ UPDATE_STAT64(rx_stat_grfcs, rx_stat_dot3statsfcserrors);
+ UPDATE_STAT64(rx_stat_grund, rx_stat_etherstatsundersizepkts);
+ UPDATE_STAT64(rx_stat_grovr, rx_stat_dot3statsframestoolong);
+ UPDATE_STAT64(rx_stat_grfrg, rx_stat_etherstatsfragments);
+ UPDATE_STAT64(rx_stat_grjbr, rx_stat_etherstatsjabbers);
+ UPDATE_STAT64(rx_stat_grxcf, rx_stat_maccontrolframesreceived);
+ UPDATE_STAT64(rx_stat_grxpf, rx_stat_xoffstateentered);
+ UPDATE_STAT64(rx_stat_grxpf, rx_stat_bmac_xpf);
+ UPDATE_STAT64(tx_stat_gtxpf, tx_stat_outxoffsent);
+ UPDATE_STAT64(tx_stat_gtxpf, tx_stat_flowcontroldone);
+ UPDATE_STAT64(tx_stat_gt64, tx_stat_etherstatspkts64octets);
+ UPDATE_STAT64(tx_stat_gt127,
tx_stat_etherstatspkts65octetsto127octets);
- UPDATE_STAT64(tx_stat_gt255,
+ UPDATE_STAT64(tx_stat_gt255,
tx_stat_etherstatspkts128octetsto255octets);
- UPDATE_STAT64(tx_stat_gt511,
+ UPDATE_STAT64(tx_stat_gt511,
tx_stat_etherstatspkts256octetsto511octets);
- UPDATE_STAT64(tx_stat_gt1023,
+ UPDATE_STAT64(tx_stat_gt1023,
tx_stat_etherstatspkts512octetsto1023octets);
- UPDATE_STAT64(tx_stat_gt1518,
+ UPDATE_STAT64(tx_stat_gt1518,
tx_stat_etherstatspkts1024octetsto1522octets);
- UPDATE_STAT64(tx_stat_gt2047, tx_stat_bmac_2047);
- UPDATE_STAT64(tx_stat_gt4095, tx_stat_bmac_4095);
- UPDATE_STAT64(tx_stat_gt9216, tx_stat_bmac_9216);
- UPDATE_STAT64(tx_stat_gt16383, tx_stat_bmac_16383);
- UPDATE_STAT64(tx_stat_gterr,
+ UPDATE_STAT64(tx_stat_gt2047, tx_stat_bmac_2047);
+ UPDATE_STAT64(tx_stat_gt4095, tx_stat_bmac_4095);
+ UPDATE_STAT64(tx_stat_gt9216, tx_stat_bmac_9216);
+ UPDATE_STAT64(tx_stat_gt16383, tx_stat_bmac_16383);
+ UPDATE_STAT64(tx_stat_gterr,
tx_stat_dot3statsinternalmactransmiterrors);
- UPDATE_STAT64(tx_stat_gtufl, tx_stat_bmac_ufl);
+ UPDATE_STAT64(tx_stat_gtufl, tx_stat_bmac_ufl);
+ }
estats->pause_frames_received_hi =
pstats->mac_stx[1].rx_stat_bmac_xpf_hi;
@@ -969,6 +978,7 @@ static void bnx2x_net_stats_update(struct bnx2x *bp)
{
struct bnx2x_eth_stats *estats = &bp->eth_stats;
struct net_device_stats *nstats = &bp->dev->stats;
+ unsigned long tmp;
int i;
nstats->rx_packets =
@@ -985,10 +995,10 @@ static void bnx2x_net_stats_update(struct bnx2x *bp)
nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi);
- nstats->rx_dropped = estats->mac_discard;
+ tmp = estats->mac_discard;
for_each_queue(bp, i)
- nstats->rx_dropped +=
- le32_to_cpu(bp->fp[i].old_tclient.checksum_discard);
+ tmp += le32_to_cpu(bp->fp[i].old_tclient.checksum_discard);
+ nstats->rx_dropped = tmp;
nstats->tx_dropped = 0;
@@ -1123,24 +1133,17 @@ static void bnx2x_port_stats_stop(struct bnx2x *bp)
bp->executer_idx = 0;
- opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
- DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+ opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_PCI, DMAE_DST_GRC, false, 0);
if (bp->port.port_stx) {
dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
if (bp->func_stx)
- dmae->opcode = (opcode | DMAE_CMD_C_DST_GRC);
+ dmae->opcode = bnx2x_dmae_opcode_add_comp(
+ opcode, DMAE_COMP_GRC);
else
- dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI);
+ dmae->opcode = bnx2x_dmae_opcode_add_comp(
+ opcode, DMAE_COMP_PCI);
dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
dmae->dst_addr_lo = bp->port.port_stx >> 2;
@@ -1164,7 +1167,8 @@ static void bnx2x_port_stats_stop(struct bnx2x *bp)
if (bp->func_stx) {
dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI);
+ dmae->opcode =
+ bnx2x_dmae_opcode_add_comp(opcode, DMAE_COMP_PCI);
dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats));
dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats));
dmae->dst_addr_lo = bp->func_stx >> 2;
@@ -1257,16 +1261,8 @@ static void bnx2x_port_stats_base_init(struct bnx2x *bp)
bp->executer_idx = 0;
dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
- DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+ dmae->opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_PCI, DMAE_DST_GRC,
+ true, DMAE_COMP_PCI);
dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
dmae->dst_addr_lo = bp->port.port_stx >> 2;
@@ -1283,9 +1279,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_E1HMF(bp) ? E1HVN_MAX : E1VN_MAX;
- int port = BP_PORT(bp);
- int func;
+ int vn, vn_max = IS_MF(bp) ? E1HVN_MAX : E1VN_MAX;
u32 func_stx;
/* sanity */
@@ -1298,9 +1292,9 @@ static void bnx2x_func_stats_base_init(struct bnx2x *bp)
func_stx = bp->func_stx;
for (vn = VN_0; vn < vn_max; vn++) {
- func = 2*vn + port;
+ int mb_idx = !CHIP_IS_E2(bp) ? 2*vn + BP_PORT(bp) : vn;
- bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param);
+ bp->func_stx = SHMEM_RD(bp, func_mb[mb_idx].fw_mb_param);
bnx2x_func_stats_init(bp);
bnx2x_hw_stats_post(bp);
bnx2x_stats_comp(bp);
@@ -1324,16 +1318,8 @@ static void bnx2x_func_stats_base_update(struct bnx2x *bp)
bp->executer_idx = 0;
memset(dmae, 0, sizeof(struct dmae_command));
- dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
- DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+ dmae->opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_GRC, DMAE_DST_PCI,
+ true, DMAE_COMP_PCI);
dmae->src_addr_lo = bp->func_stx >> 2;
dmae->src_addr_hi = 0;
dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats_base));
@@ -1351,8 +1337,9 @@ static void bnx2x_func_stats_base_update(struct bnx2x *bp)
void bnx2x_stats_init(struct bnx2x *bp)
{
int port = BP_PORT(bp);
- int func = BP_FUNC(bp);
+ int mb_idx = BP_FW_MB_IDX(bp);
int i;
+ struct eth_stats_query *stats = bnx2x_sp(bp, fw_stats);
bp->stats_pending = 0;
bp->executer_idx = 0;
@@ -1361,7 +1348,7 @@ void bnx2x_stats_init(struct bnx2x *bp)
/* port and func stats for management */
if (!BP_NOMCP(bp)) {
bp->port.port_stx = SHMEM_RD(bp, port_mb[port].port_stx);
- bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param);
+ bp->func_stx = SHMEM_RD(bp, func_mb[mb_idx].fw_mb_param);
} else {
bp->port.port_stx = 0;
@@ -1394,6 +1381,18 @@ void bnx2x_stats_init(struct bnx2x *bp)
memset(&fp->eth_q_stats, 0, sizeof(struct bnx2x_eth_q_stats));
}
+ for_each_queue(bp, i) {
+ /* Set initial stats counter in the stats ramrod data to -1 */
+ int cl_id = bp->fp[i].cl_id;
+
+ stats->xstorm_common.client_statistics[cl_id].
+ stats_counter = 0xffff;
+ stats->ustorm_common.client_statistics[cl_id].
+ stats_counter = 0xffff;
+ stats->tstorm_common.client_statistics[cl_id].
+ stats_counter = 0xffff;
+ }
+
memset(&bp->dev->stats, 0, sizeof(struct net_device_stats));
memset(&bp->eth_stats, 0, sizeof(struct bnx2x_eth_stats));
diff --git a/drivers/net/bnx2x/bnx2x_stats.h b/drivers/net/bnx2x/bnx2x_stats.h
index 38a4e908f4fb..afd15efa429a 100644
--- a/drivers/net/bnx2x/bnx2x_stats.h
+++ b/drivers/net/bnx2x/bnx2x_stats.h
@@ -9,6 +9,10 @@
* Maintained by: Eilon Greenstein <eilong@broadcom.com>
* Written by: Eliezer Tamir
* Based on code from Michael Chan's bnx2 driver
+ * UDP CSUM errata workaround by Arik Gendelman
+ * Slowpath and fastpath rework by Vladislav Zolotarov
+ * Statistics and Link management by Yitchak Gertner
+ *
*/
#ifndef BNX2X_STATS_H
@@ -228,12 +232,8 @@ struct bnx2x_eth_stats {
/* Forward declaration */
struct bnx2x;
-
void bnx2x_stats_init(struct bnx2x *bp);
extern const u32 dmae_reg_go_c[];
-extern int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
- u32 data_hi, u32 data_lo, int common);
-
#endif /* BNX2X_STATS_H */
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 0ddf4c66afe2..881914bc4e9c 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -93,7 +93,7 @@
// compare MAC addresses
#define MAC_ADDRESS_COMPARE(A, B) memcmp(A, B, ETH_ALEN)
-static struct mac_addr null_mac_addr = {{0, 0, 0, 0, 0, 0}};
+static struct mac_addr null_mac_addr = { { 0, 0, 0, 0, 0, 0 } };
static u16 ad_ticks_per_sec;
static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000;
@@ -129,9 +129,8 @@ static void ad_marker_response_received(struct bond_marker *marker, struct port
*/
static inline struct bonding *__get_bond_by_port(struct port *port)
{
- if (port->slave == NULL) {
+ if (port->slave == NULL)
return NULL;
- }
return bond_get_bond_by_slave(port->slave);
}
@@ -144,9 +143,8 @@ static inline struct bonding *__get_bond_by_port(struct port *port)
*/
static inline struct port *__get_first_port(struct bonding *bond)
{
- if (bond->slave_cnt == 0) {
+ if (bond->slave_cnt == 0)
return NULL;
- }
return &(SLAVE_AD_INFO(bond->first_slave).port);
}
@@ -164,9 +162,8 @@ static inline struct port *__get_next_port(struct port *port)
struct slave *slave = port->slave;
// If there's no bond for this port, or this is the last slave
- if ((bond == NULL) || (slave->next == bond->first_slave)) {
+ if ((bond == NULL) || (slave->next == bond->first_slave))
return NULL;
- }
return &(SLAVE_AD_INFO(slave->next).port);
}
@@ -183,9 +180,8 @@ static inline struct aggregator *__get_first_agg(struct port *port)
struct bonding *bond = __get_bond_by_port(port);
// If there's no bond for this port, or bond has no slaves
- if ((bond == NULL) || (bond->slave_cnt == 0)) {
+ if ((bond == NULL) || (bond->slave_cnt == 0))
return NULL;
- }
return &(SLAVE_AD_INFO(bond->first_slave).aggregator);
}
@@ -203,9 +199,8 @@ static inline struct aggregator *__get_next_agg(struct aggregator *aggregator)
struct bonding *bond = bond_get_bond_by_slave(slave);
// If there's no bond for this aggregator, or this is the last slave
- if ((bond == NULL) || (slave->next == bond->first_slave)) {
+ if ((bond == NULL) || (slave->next == bond->first_slave))
return NULL;
- }
return &(SLAVE_AD_INFO(slave->next).aggregator);
}
@@ -240,9 +235,8 @@ static inline void __enable_port(struct port *port)
{
struct slave *slave = port->slave;
- if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev)) {
+ if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev))
bond_set_slave_active_flags(slave);
- }
}
/**
@@ -252,7 +246,7 @@ static inline void __enable_port(struct port *port)
*/
static inline int __port_is_enabled(struct port *port)
{
- return(port->slave->state == BOND_STATE_ACTIVE);
+ return port->slave->state == BOND_STATE_ACTIVE;
}
/**
@@ -265,9 +259,8 @@ static inline u32 __get_agg_selection_mode(struct port *port)
{
struct bonding *bond = __get_bond_by_port(port);
- if (bond == NULL) {
+ if (bond == NULL)
return BOND_AD_STABLE;
- }
return BOND_AD_INFO(bond).agg_select_mode;
}
@@ -281,9 +274,8 @@ static inline int __check_agg_selection_timer(struct port *port)
{
struct bonding *bond = __get_bond_by_port(port);
- if (bond == NULL) {
+ if (bond == NULL)
return 0;
- }
return BOND_AD_INFO(bond).agg_select_timer ? 1 : 0;
}
@@ -328,9 +320,9 @@ static u16 __get_link_speed(struct port *port)
* link down, it sets the speed to 0.
* This is done in spite of the fact that the e100 driver reports 0 to be
* compatible with MVT in the future.*/
- if (slave->link != BOND_LINK_UP) {
- speed=0;
- } else {
+ if (slave->link != BOND_LINK_UP)
+ speed = 0;
+ else {
switch (slave->speed) {
case SPEED_10:
speed = AD_LINK_SPEED_BITMASK_10MBPS;
@@ -375,18 +367,18 @@ static u8 __get_duplex(struct port *port)
// handling a special case: when the configuration starts with
// link down, it sets the duplex to 0.
- if (slave->link != BOND_LINK_UP) {
- retval=0x0;
- } else {
+ if (slave->link != BOND_LINK_UP)
+ retval = 0x0;
+ else {
switch (slave->duplex) {
case DUPLEX_FULL:
- retval=0x1;
+ retval = 0x1;
pr_debug("Port %d Received status full duplex update from adapter\n",
port->actor_port_number);
break;
case DUPLEX_HALF:
default:
- retval=0x0;
+ retval = 0x0;
pr_debug("Port %d Received status NOT full duplex update from adapter\n",
port->actor_port_number);
break;
@@ -419,15 +411,14 @@ static inline void __initialize_port_locks(struct port *port)
*/
static u16 __ad_timer_to_ticks(u16 timer_type, u16 par)
{
- u16 retval=0; //to silence the compiler
+ u16 retval = 0; /* to silence the compiler */
switch (timer_type) {
case AD_CURRENT_WHILE_TIMER: // for rx machine usage
- if (par) { // for short or long timeout
+ if (par)
retval = (AD_SHORT_TIMEOUT_TIME*ad_ticks_per_sec); // short timeout
- } else {
+ else
retval = (AD_LONG_TIMEOUT_TIME*ad_ticks_per_sec); // long timeout
- }
break;
case AD_ACTOR_CHURN_TIMER: // for local churn machine
retval = (AD_CHURN_DETECTION_TIME*ad_ticks_per_sec);
@@ -519,11 +510,11 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port)
port->actor_oper_port_state &= ~AD_STATE_DEFAULTED;
// set the partner sync. to on if the partner is sync. and the port is matched
- if ((port->sm_vars & AD_PORT_MATCHED) && (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION)) {
+ if ((port->sm_vars & AD_PORT_MATCHED)
+ && (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION))
partner->port_state |= AD_STATE_SYNCHRONIZATION;
- } else {
+ else
partner->port_state &= ~AD_STATE_SYNCHRONIZATION;
- }
}
}
@@ -653,7 +644,7 @@ static void __update_ntt(struct lacpdu *lacpdu, struct port *port)
*/
static void __attach_bond_to_agg(struct port *port)
{
- port=NULL; // just to satisfy the compiler
+ port = NULL; /* just to satisfy the compiler */
// This function does nothing since the parser/multiplexer of the receive
// and the parser/multiplexer of the aggregator are already combined
}
@@ -668,7 +659,7 @@ static void __attach_bond_to_agg(struct port *port)
*/
static void __detach_bond_from_agg(struct port *port)
{
- port=NULL; // just to satisfy the compiler
+ port = NULL; /* just to satisfy the compiler */
// This function does nothing sience the parser/multiplexer of the receive
// and the parser/multiplexer of the aggregator are already combined
}
@@ -685,7 +676,9 @@ static int __agg_ports_are_ready(struct aggregator *aggregator)
if (aggregator) {
// scan all ports in this aggregator to verfy if they are all ready
- for (port=aggregator->lag_ports; port; port=port->next_port_in_aggregator) {
+ for (port = aggregator->lag_ports;
+ port;
+ port = port->next_port_in_aggregator) {
if (!(port->sm_vars & AD_PORT_READY_N)) {
retval = 0;
break;
@@ -706,12 +699,12 @@ static void __set_agg_ports_ready(struct aggregator *aggregator, int val)
{
struct port *port;
- for (port=aggregator->lag_ports; port; port=port->next_port_in_aggregator) {
- if (val) {
+ for (port = aggregator->lag_ports; port;
+ port = port->next_port_in_aggregator) {
+ if (val)
port->sm_vars |= AD_PORT_READY;
- } else {
+ else
port->sm_vars &= ~AD_PORT_READY;
- }
}
}
@@ -722,7 +715,7 @@ static void __set_agg_ports_ready(struct aggregator *aggregator, int val)
*/
static u32 __get_agg_bandwidth(struct aggregator *aggregator)
{
- u32 bandwidth=0;
+ u32 bandwidth = 0;
u32 basic_speed;
if (aggregator->num_of_ports) {
@@ -744,7 +737,7 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator)
bandwidth = aggregator->num_of_ports * 10000;
break;
default:
- bandwidth=0; // to silent the compilor ....
+ bandwidth = 0; /*to silence the compiler ....*/
}
}
return bandwidth;
@@ -835,9 +828,8 @@ static int ad_lacpdu_send(struct port *port)
int length = sizeof(struct lacpdu_header);
skb = dev_alloc_skb(length);
- if (!skb) {
+ if (!skb)
return -ENOMEM;
- }
skb->dev = slave->dev;
skb_reset_mac_header(skb);
@@ -876,9 +868,8 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker)
int length = sizeof(struct bond_marker_header);
skb = dev_alloc_skb(length + 16);
- if (!skb) {
+ if (!skb)
return -ENOMEM;
- }
skb_reserve(skb, 16);
@@ -919,9 +910,10 @@ static void ad_mux_machine(struct port *port)
} else {
switch (port->sm_mux_state) {
case AD_MUX_DETACHED:
- if ((port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY)) { // if SELECTED or STANDBY
+ if ((port->sm_vars & AD_PORT_SELECTED)
+ || (port->sm_vars & AD_PORT_STANDBY))
+ /* if SELECTED or STANDBY */
port->sm_mux_state = AD_MUX_WAITING; // next state
- }
break;
case AD_MUX_WAITING:
// if SELECTED == FALSE return to DETACH state
@@ -935,18 +927,18 @@ static void ad_mux_machine(struct port *port)
}
// check if the wait_while_timer expired
- if (port->sm_mux_timer_counter && !(--port->sm_mux_timer_counter)) {
+ if (port->sm_mux_timer_counter
+ && !(--port->sm_mux_timer_counter))
port->sm_vars |= AD_PORT_READY_N;
- }
// in order to withhold the selection logic to check all ports READY_N value
// every callback cycle to update ready variable, we check READY_N and update READY here
__set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
// if the wait_while_timer expired, and the port is in READY state, move to ATTACHED state
- if ((port->sm_vars & AD_PORT_READY) && !port->sm_mux_timer_counter) {
+ if ((port->sm_vars & AD_PORT_READY)
+ && !port->sm_mux_timer_counter)
port->sm_mux_state = AD_MUX_ATTACHED; // next state
- }
break;
case AD_MUX_ATTACHED:
// check also if agg_select_timer expired(so the edable port will take place only after this timer)
@@ -1041,13 +1033,14 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
// check if state machine should change state
// first, check if port was reinitialized
- if (port->sm_vars & AD_PORT_BEGIN) {
- port->sm_rx_state = AD_RX_INITIALIZE; // next state
- }
+ if (port->sm_vars & AD_PORT_BEGIN)
+ /* next state */
+ port->sm_rx_state = AD_RX_INITIALIZE;
// check if port is not enabled
- else if (!(port->sm_vars & AD_PORT_BEGIN) && !port->is_enabled && !(port->sm_vars & AD_PORT_MOVED)) {
- port->sm_rx_state = AD_RX_PORT_DISABLED; // next state
- }
+ else if (!(port->sm_vars & AD_PORT_BEGIN)
+ && !port->is_enabled && !(port->sm_vars & AD_PORT_MOVED))
+ /* next state */
+ port->sm_rx_state = AD_RX_PORT_DISABLED;
// check if new lacpdu arrived
else if (lacpdu && ((port->sm_rx_state == AD_RX_EXPIRED) || (port->sm_rx_state == AD_RX_DEFAULTED) || (port->sm_rx_state == AD_RX_CURRENT))) {
port->sm_rx_timer_counter = 0; // zero timer
@@ -1069,13 +1062,16 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
// if no lacpdu arrived and no timer is on
switch (port->sm_rx_state) {
case AD_RX_PORT_DISABLED:
- if (port->sm_vars & AD_PORT_MOVED) {
+ if (port->sm_vars & AD_PORT_MOVED)
port->sm_rx_state = AD_RX_INITIALIZE; // next state
- } else if (port->is_enabled && (port->sm_vars & AD_PORT_LACP_ENABLED)) {
+ else if (port->is_enabled
+ && (port->sm_vars
+ & AD_PORT_LACP_ENABLED))
port->sm_rx_state = AD_RX_EXPIRED; // next state
- } else if (port->is_enabled && ((port->sm_vars & AD_PORT_LACP_ENABLED) == 0)) {
+ else if (port->is_enabled
+ && ((port->sm_vars
+ & AD_PORT_LACP_ENABLED) == 0))
port->sm_rx_state = AD_RX_LACP_DISABLED; // next state
- }
break;
default: //to silence the compiler
break;
@@ -1091,11 +1087,10 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
port->sm_rx_state);
switch (port->sm_rx_state) {
case AD_RX_INITIALIZE:
- if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) {
+ if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS))
port->sm_vars &= ~AD_PORT_LACP_ENABLED;
- } else {
+ else
port->sm_vars |= AD_PORT_LACP_ENABLED;
- }
port->sm_vars &= ~AD_PORT_SELECTED;
__record_default(port);
port->actor_oper_port_state &= ~AD_STATE_EXPIRED;
@@ -1149,9 +1144,10 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
// 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)) {
+ if (port->aggregator
+ && port->aggregator->is_active
+ && !__port_is_enabled(port))
__enable_port(port);
- }
break;
default: //to silence the compiler
break;
@@ -1183,7 +1179,8 @@ static void ad_tx_machine(struct port *port)
}
}
// restart tx timer(to verify that we will not exceed AD_MAX_TX_IN_SECOND
- port->sm_tx_timer_counter=ad_ticks_per_sec/AD_MAX_TX_IN_SECOND;
+ port->sm_tx_timer_counter =
+ ad_ticks_per_sec/AD_MAX_TX_IN_SECOND;
}
}
@@ -1216,9 +1213,9 @@ static void ad_periodic_machine(struct port *port)
// If not expired, check if there is some new timeout parameter from the partner state
switch (port->sm_periodic_state) {
case AD_FAST_PERIODIC:
- if (!(port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) {
+ if (!(port->partner_oper.port_state
+ & AD_STATE_LACP_TIMEOUT))
port->sm_periodic_state = AD_SLOW_PERIODIC; // next state
- }
break;
case AD_SLOW_PERIODIC:
if ((port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) {
@@ -1237,11 +1234,11 @@ static void ad_periodic_machine(struct port *port)
port->sm_periodic_state = AD_FAST_PERIODIC; // next state
break;
case AD_PERIODIC_TX:
- if (!(port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) {
+ if (!(port->partner_oper.port_state
+ & AD_STATE_LACP_TIMEOUT))
port->sm_periodic_state = AD_SLOW_PERIODIC; // next state
- } else {
+ else
port->sm_periodic_state = AD_FAST_PERIODIC; // next state
- }
break;
default: //to silence the compiler
break;
@@ -1287,35 +1284,37 @@ static void ad_port_selection_logic(struct port *port)
int found = 0;
// if the port is already Selected, do nothing
- if (port->sm_vars & AD_PORT_SELECTED) {
+ if (port->sm_vars & AD_PORT_SELECTED)
return;
- }
// if the port is connected to other aggregator, detach it
if (port->aggregator) {
// detach the port from its former aggregator
- temp_aggregator=port->aggregator;
- for (curr_port=temp_aggregator->lag_ports; curr_port; last_port=curr_port, curr_port=curr_port->next_port_in_aggregator) {
+ temp_aggregator = port->aggregator;
+ for (curr_port = temp_aggregator->lag_ports; curr_port;
+ last_port = curr_port,
+ curr_port = curr_port->next_port_in_aggregator) {
if (curr_port == port) {
temp_aggregator->num_of_ports--;
if (!last_port) {// if it is the first port attached to the aggregator
- temp_aggregator->lag_ports=port->next_port_in_aggregator;
+ temp_aggregator->lag_ports =
+ port->next_port_in_aggregator;
} else {// not the first port attached to the aggregator
- last_port->next_port_in_aggregator=port->next_port_in_aggregator;
+ last_port->next_port_in_aggregator =
+ port->next_port_in_aggregator;
}
// clear the port's relations to this aggregator
port->aggregator = NULL;
- port->next_port_in_aggregator=NULL;
- port->actor_port_aggregator_identifier=0;
+ port->next_port_in_aggregator = NULL;
+ port->actor_port_aggregator_identifier = 0;
pr_debug("Port %d left LAG %d\n",
port->actor_port_number,
temp_aggregator->aggregator_identifier);
// if the aggregator is empty, clear its parameters, and set it ready to be attached
- if (!temp_aggregator->lag_ports) {
+ if (!temp_aggregator->lag_ports)
ad_clear_agg(temp_aggregator);
- }
break;
}
}
@@ -1333,9 +1332,8 @@ static void ad_port_selection_logic(struct port *port)
// keep a free aggregator for later use(if needed)
if (!aggregator->lag_ports) {
- if (!free_aggregator) {
- free_aggregator=aggregator;
- }
+ if (!free_aggregator)
+ free_aggregator = aggregator;
continue;
}
// check if current aggregator suits us
@@ -1350,10 +1348,11 @@ static void ad_port_selection_logic(struct port *port)
) {
// attach to the founded aggregator
port->aggregator = aggregator;
- port->actor_port_aggregator_identifier=port->aggregator->aggregator_identifier;
- port->next_port_in_aggregator=aggregator->lag_ports;
+ port->actor_port_aggregator_identifier =
+ port->aggregator->aggregator_identifier;
+ port->next_port_in_aggregator = aggregator->lag_ports;
port->aggregator->num_of_ports++;
- aggregator->lag_ports=port;
+ aggregator->lag_ports = port;
pr_debug("Port %d joined LAG %d(existing LAG)\n",
port->actor_port_number,
port->aggregator->aggregator_identifier);
@@ -1370,20 +1369,23 @@ static void ad_port_selection_logic(struct port *port)
if (free_aggregator) {
// assign port a new aggregator
port->aggregator = free_aggregator;
- port->actor_port_aggregator_identifier=port->aggregator->aggregator_identifier;
+ port->actor_port_aggregator_identifier =
+ port->aggregator->aggregator_identifier;
// update the new aggregator's parameters
// if port was responsed from the end-user
- if (port->actor_oper_port_key & AD_DUPLEX_KEY_BITS) {// if port is full duplex
+ if (port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)
+ /* if port is full duplex */
port->aggregator->is_individual = false;
- } else {
+ else
port->aggregator->is_individual = true;
- }
port->aggregator->actor_admin_aggregator_key = port->actor_admin_port_key;
port->aggregator->actor_oper_aggregator_key = port->actor_oper_port_key;
- port->aggregator->partner_system=port->partner_oper.system;
- port->aggregator->partner_system_priority = port->partner_oper.system_priority;
+ port->aggregator->partner_system =
+ port->partner_oper.system;
+ port->aggregator->partner_system_priority =
+ port->partner_oper.system_priority;
port->aggregator->partner_oper_aggregator_key = port->partner_oper.key;
port->aggregator->receive_state = 1;
port->aggregator->transmit_state = 1;
@@ -1704,9 +1706,8 @@ static void ad_initialize_port(struct port *port, int lacp_fast)
port->actor_admin_port_state = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY;
port->actor_oper_port_state = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY;
- if (lacp_fast) {
+ if (lacp_fast)
port->actor_oper_port_state |= AD_STATE_LACP_TIMEOUT;
- }
memcpy(&port->partner_admin, &tmpl, sizeof(tmpl));
memcpy(&port->partner_oper, &tmpl, sizeof(tmpl));
@@ -1785,13 +1786,16 @@ static void ad_marker_info_send(struct port *port)
marker.requester_port = (((port->actor_port_number & 0xFF) << 8) |((u16)(port->actor_port_number & 0xFF00) >> 8));
marker.requester_system = port->actor_system;
// convert requester_port(u32) to Big Endian
- marker.requester_transaction_id = (((++port->transaction_id & 0xFF) << 24) |((port->transaction_id & 0xFF00) << 8) |((port->transaction_id & 0xFF0000) >> 8) |((port->transaction_id & 0xFF000000) >> 24));
+ marker.requester_transaction_id =
+ (((++port->transaction_id & 0xFF) << 24)
+ | ((port->transaction_id & 0xFF00) << 8)
+ | ((port->transaction_id & 0xFF0000) >> 8)
+ | ((port->transaction_id & 0xFF000000) >> 24));
marker.pad = 0;
marker.tlv_type_terminator = 0x00;
marker.terminator_length = 0x00;
- for (index=0; index<90; index++) {
- marker.reserved_90[index]=0;
- }
+ for (index = 0; index < 90; index++)
+ marker.reserved_90[index] = 0;
// send the marker information
if (ad_marker_send(port, &marker) >= 0) {
@@ -1816,7 +1820,7 @@ static void ad_marker_info_received(struct bond_marker *marker_info,
//marker = *marker_info;
memcpy(&marker, marker_info, sizeof(struct bond_marker));
// change the marker subtype to marker response
- marker.tlv_type=AD_MARKER_RESPONSE_SUBTYPE;
+ marker.tlv_type = AD_MARKER_RESPONSE_SUBTYPE;
// send the marker response
if (ad_marker_send(port, &marker) >= 0) {
@@ -1837,8 +1841,8 @@ static void ad_marker_info_received(struct bond_marker *marker_info,
static void ad_marker_response_received(struct bond_marker *marker,
struct port *port)
{
- marker=NULL; // just to satisfy the compiler
- port=NULL; // just to satisfy the compiler
+ marker = NULL; /* just to satisfy the compiler */
+ port = NULL; /* just to satisfy the compiler */
// DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW
}
@@ -1932,9 +1936,8 @@ int bond_3ad_bind_slave(struct slave *slave)
port->actor_admin_port_key |= (__get_link_speed(port) << 1);
port->actor_oper_port_key = port->actor_admin_port_key;
// if the port is not full duplex, then the port should be not lacp Enabled
- if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) {
+ if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS))
port->sm_vars &= ~AD_PORT_LACP_ENABLED;
- }
// actor system is the bond's system
port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr;
// tx timer(to verify that no more than MAX_TX_IN_SECOND lacpdu's are sent in one second)
@@ -2006,9 +2009,10 @@ void bond_3ad_unbind_slave(struct slave *slave)
new_aggregator = __get_first_agg(port);
for (; new_aggregator; new_aggregator = __get_next_agg(new_aggregator)) {
// if the new aggregator is empty, or it is connected to our port only
- if (!new_aggregator->lag_ports || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator)) {
+ if (!new_aggregator->lag_ports
+ || ((new_aggregator->lag_ports == port)
+ && !new_aggregator->lag_ports->next_port_in_aggregator))
break;
- }
}
// if new aggregator found, copy the aggregator's parameters
// and connect the related lag_ports to the new aggregator
@@ -2037,17 +2041,17 @@ void bond_3ad_unbind_slave(struct slave *slave)
new_aggregator->num_of_ports = aggregator->num_of_ports;
// update the information that is written on the ports about the aggregator
- for (temp_port=aggregator->lag_ports; temp_port; temp_port=temp_port->next_port_in_aggregator) {
- temp_port->aggregator=new_aggregator;
+ for (temp_port = aggregator->lag_ports; temp_port;
+ temp_port = temp_port->next_port_in_aggregator) {
+ temp_port->aggregator = new_aggregator;
temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier;
}
// clear the aggregator
ad_clear_agg(aggregator);
- if (select_new_active_agg) {
+ if (select_new_active_agg)
ad_agg_selection_logic(__get_first_agg(port));
- }
} else {
pr_warning("%s: Warning: unbinding aggregator, and could not find a new aggregator for its ports\n",
slave->dev->master->name);
@@ -2071,15 +2075,16 @@ void bond_3ad_unbind_slave(struct slave *slave)
for (; temp_aggregator; temp_aggregator = __get_next_agg(temp_aggregator)) {
prev_port = NULL;
// search the port in the aggregator's related ports
- for (temp_port=temp_aggregator->lag_ports; temp_port; prev_port=temp_port, temp_port=temp_port->next_port_in_aggregator) {
+ for (temp_port = temp_aggregator->lag_ports; temp_port;
+ prev_port = temp_port,
+ temp_port = temp_port->next_port_in_aggregator) {
if (temp_port == port) { // the aggregator found - detach the port from this aggregator
- if (prev_port) {
+ if (prev_port)
prev_port->next_port_in_aggregator = temp_port->next_port_in_aggregator;
- } else {
+ else
temp_aggregator->lag_ports = temp_port->next_port_in_aggregator;
- }
temp_aggregator->num_of_ports--;
- if (temp_aggregator->num_of_ports==0) {
+ if (temp_aggregator->num_of_ports == 0) {
select_new_active_agg = temp_aggregator->is_active;
// clear the aggregator
ad_clear_agg(temp_aggregator);
@@ -2094,7 +2099,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
}
}
}
- port->slave=NULL;
+ port->slave = NULL;
}
/**
@@ -2119,14 +2124,12 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
read_lock(&bond->lock);
- if (bond->kill_timers) {
+ if (bond->kill_timers)
goto out;
- }
//check if there are any slaves
- if (bond->slave_cnt == 0) {
+ if (bond->slave_cnt == 0)
goto re_arm;
- }
// check if agg_select_timer timer after initialize is timed out
if (BOND_AD_INFO(bond).agg_select_timer && !(--BOND_AD_INFO(bond).agg_select_timer)) {
@@ -2159,9 +2162,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
ad_tx_machine(port);
// turn off the BEGIN bit, since we already handled it
- if (port->sm_vars & AD_PORT_BEGIN) {
+ if (port->sm_vars & AD_PORT_BEGIN)
port->sm_vars &= ~AD_PORT_BEGIN;
- }
}
re_arm:
@@ -2245,7 +2247,8 @@ void bond_3ad_adapter_speed_changed(struct slave *slave)
}
port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS;
- port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1);
+ port->actor_oper_port_key = port->actor_admin_port_key |=
+ (__get_link_speed(port) << 1);
pr_debug("Port %d changed speed\n", port->actor_port_number);
// there is no need to reselect a new aggregator, just signal the
// state machines to reinitialize
@@ -2262,7 +2265,7 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave)
{
struct port *port;
- port=&(SLAVE_AD_INFO(slave).port);
+ port = &(SLAVE_AD_INFO(slave).port);
// if slave is null, the whole port is not initialized
if (!port->slave) {
@@ -2272,7 +2275,8 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave)
}
port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS;
- port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port);
+ port->actor_oper_port_key = port->actor_admin_port_key |=
+ __get_duplex(port);
pr_debug("Port %d changed duplex\n", port->actor_port_number);
// there is no need to reselect a new aggregator, just signal the
// state machines to reinitialize
@@ -2304,14 +2308,17 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
if (link == BOND_LINK_UP) {
port->is_enabled = true;
port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS;
- port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port);
+ port->actor_oper_port_key = port->actor_admin_port_key |=
+ __get_duplex(port);
port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS;
- port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1);
+ port->actor_oper_port_key = port->actor_admin_port_key |=
+ (__get_link_speed(port) << 1);
} else {
/* link has failed */
port->is_enabled = false;
port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS;
- port->actor_oper_port_key= (port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS);
+ port->actor_oper_port_key = (port->actor_admin_port_key &=
+ ~AD_SPEED_KEY_BITS);
}
//BOND_PRINT_DBG(("Port %d changed link status to %s", port->actor_port_number, ((link == BOND_LINK_UP)?"UP":"DOWN")));
// there is no need to reselect a new aggregator, just signal the
@@ -2394,9 +2401,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
*/
read_lock(&bond->lock);
- if (!BOND_IS_OK(bond)) {
+ if (!BOND_IS_OK(bond))
goto out;
- }
if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
pr_debug("%s: Error: bond_3ad_get_active_agg_info failed\n",
@@ -2420,9 +2426,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
if (agg && (agg->aggregator_identifier == agg_id)) {
slave_agg_no--;
- if (slave_agg_no < 0) {
+ if (slave_agg_no < 0)
break;
- }
}
}
@@ -2438,9 +2443,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
int slave_agg_id = 0;
struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
- if (agg) {
+ if (agg)
slave_agg_id = agg->aggregator_identifier;
- }
if (SLAVE_IS_OK(slave) && agg && (slave_agg_id == agg_id)) {
res = bond_dev_queue_xmit(bond, skb, slave->dev);
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index e953c6ad6e6d..bdb68a600382 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -76,6 +76,7 @@
#include <linux/if_vlan.h>
#include <linux/if_bonding.h>
#include <linux/jiffies.h>
+#include <linux/preempt.h>
#include <net/route.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
@@ -109,6 +110,7 @@ static char *arp_validate;
static char *fail_over_mac;
static int all_slaves_active = 0;
static struct bond_params bonding_defaults;
+static int resend_igmp = BOND_DEFAULT_RESEND_IGMP;
module_param(max_bonds, int, 0);
MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
@@ -163,9 +165,15 @@ module_param(all_slaves_active, int, 0);
MODULE_PARM_DESC(all_slaves_active, "Keep all frames received on an interface"
"by setting active flag for all slaves. "
"0 for never (default), 1 for always.");
+module_param(resend_igmp, int, 0);
+MODULE_PARM_DESC(resend_igmp, "Number of IGMP membership reports to send on link failure");
/*----------------------------- Global variables ----------------------------*/
+#ifdef CONFIG_NET_POLL_CONTROLLER
+cpumask_var_t netpoll_block_tx;
+#endif
+
static const char * const version =
DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n";
@@ -176,9 +184,6 @@ static int arp_ip_count;
static int bond_mode = BOND_MODE_ROUNDROBIN;
static int xmit_hashtype = BOND_XMIT_POLICY_LAYER2;
static int lacp_fast;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static int disable_netpoll = 1;
-#endif
const struct bond_parm_tbl bond_lacp_tbl[] = {
{ "slow", AD_LACP_SLOW},
@@ -307,6 +312,7 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id)
pr_debug("bond: %s, vlan id %d\n", bond->dev->name, vlan_id);
+ block_netpoll_tx();
write_lock_bh(&bond->lock);
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
@@ -341,6 +347,7 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id)
out:
write_unlock_bh(&bond->lock);
+ unblock_netpoll_tx();
return res;
}
@@ -446,11 +453,9 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
if (unlikely(bond->dev->priv_flags & IFF_IN_NETPOLL)) {
struct netpoll *np = bond->dev->npinfo->netpoll;
slave_dev->npinfo = bond->dev->npinfo;
- np->real_dev = np->dev = skb->dev;
slave_dev->priv_flags |= IFF_IN_NETPOLL;
- netpoll_send_skb(np, skb);
+ netpoll_send_skb_on_dev(np, skb, slave_dev);
slave_dev->priv_flags &= ~IFF_IN_NETPOLL;
- np->dev = bond->dev;
} else
#endif
dev_queue_xmit(skb);
@@ -488,9 +493,9 @@ static void bond_vlan_rx_register(struct net_device *bond_dev,
struct slave *slave;
int i;
- write_lock(&bond->lock);
+ write_lock_bh(&bond->lock);
bond->vlgrp = grp;
- write_unlock(&bond->lock);
+ write_unlock_bh(&bond->lock);
bond_for_each_slave(bond, slave, i) {
struct net_device *slave_dev = slave->dev;
@@ -865,18 +870,13 @@ static void bond_mc_del(struct bonding *bond, void *addr)
}
-/*
- * Retrieve the list of registered multicast addresses for the bonding
- * device and retransmit an IGMP JOIN request to the current active
- * slave.
- */
-static void bond_resend_igmp_join_requests(struct bonding *bond)
+static void __bond_resend_igmp_join_requests(struct net_device *dev)
{
struct in_device *in_dev;
struct ip_mc_list *im;
rcu_read_lock();
- in_dev = __in_dev_get_rcu(bond->dev);
+ in_dev = __in_dev_get_rcu(dev);
if (in_dev) {
for (im = in_dev->mc_list; im; im = im->next)
ip_mc_rejoin_group(im);
@@ -886,6 +886,44 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
}
/*
+ * Retrieve the list of registered multicast addresses for the bonding
+ * device and retransmit an IGMP JOIN request to the current active
+ * slave.
+ */
+static void bond_resend_igmp_join_requests(struct bonding *bond)
+{
+ struct net_device *vlan_dev;
+ struct vlan_entry *vlan;
+
+ read_lock(&bond->lock);
+
+ /* rejoin all groups on bond device */
+ __bond_resend_igmp_join_requests(bond->dev);
+
+ /* rejoin all groups on vlan devices */
+ if (bond->vlgrp) {
+ list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
+ vlan_dev = vlan_group_get_device(bond->vlgrp,
+ vlan->vlan_id);
+ if (vlan_dev)
+ __bond_resend_igmp_join_requests(vlan_dev);
+ }
+ }
+
+ if (--bond->igmp_retrans > 0)
+ queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5);
+
+ read_unlock(&bond->lock);
+}
+
+static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
+{
+ struct bonding *bond = container_of(work, struct bonding,
+ mcast_work.work);
+ bond_resend_igmp_join_requests(bond);
+}
+
+/*
* flush all members of flush->mc_list from device dev->mc_list
*/
static void bond_mc_list_flush(struct net_device *bond_dev,
@@ -944,7 +982,6 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
netdev_for_each_mc_addr(ha, bond->dev)
dev_mc_add(new_active->dev, ha->addr);
- bond_resend_igmp_join_requests(bond);
}
}
@@ -1180,9 +1217,12 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
}
}
- /* resend IGMP joins since all were sent on curr_active_slave */
- if (bond->params.mode == BOND_MODE_ROUNDROBIN) {
- bond_resend_igmp_join_requests(bond);
+ /* resend IGMP joins since active slave has changed or
+ * all were sent on curr_active_slave */
+ if ((USES_PRIMARY(bond->params.mode) && new_active) ||
+ bond->params.mode == BOND_MODE_ROUNDROBIN) {
+ bond->igmp_retrans = bond->params.resend_igmp;
+ queue_delayed_work(bond->wq, &bond->mcast_work, 0);
}
}
@@ -1294,9 +1334,14 @@ static bool slaves_support_netpoll(struct net_device *bond_dev)
static void bond_poll_controller(struct net_device *bond_dev)
{
- struct net_device *dev = bond_dev->npinfo->netpoll->real_dev;
- if (dev != bond_dev)
- netpoll_poll_dev(dev);
+ struct bonding *bond = netdev_priv(bond_dev);
+ struct slave *slave;
+ int i;
+
+ bond_for_each_slave(bond, slave, i) {
+ if (slave->dev && IS_UP(slave->dev))
+ netpoll_poll_dev(slave->dev);
+ }
}
static void bond_netpoll_cleanup(struct net_device *bond_dev)
@@ -1763,23 +1808,15 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
bond_set_carrier(bond);
#ifdef CONFIG_NET_POLL_CONTROLLER
- /*
- * Netpoll and bonding is broken, make sure it is not initialized
- * until it is fixed.
- */
- if (disable_netpoll) {
+ if (slaves_support_netpoll(bond_dev)) {
+ bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
+ if (bond_dev->npinfo)
+ slave_dev->npinfo = bond_dev->npinfo;
+ } else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) {
bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
- } else {
- if (slaves_support_netpoll(bond_dev)) {
- bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
- if (bond_dev->npinfo)
- slave_dev->npinfo = bond_dev->npinfo;
- } else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) {
- bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
- pr_info("New slave device %s does not support netpoll\n",
- slave_dev->name);
- pr_info("Disabling netpoll support for %s\n", bond_dev->name);
- }
+ pr_info("New slave device %s does not support netpoll\n",
+ slave_dev->name);
+ pr_info("Disabling netpoll support for %s\n", bond_dev->name);
}
#endif
read_unlock(&bond->lock);
@@ -1851,6 +1888,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
return -EINVAL;
}
+ block_netpoll_tx();
netdev_bonding_change(bond_dev, NETDEV_BONDING_DESLAVE);
write_lock_bh(&bond->lock);
@@ -1860,6 +1898,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
pr_info("%s: %s not enslaved\n",
bond_dev->name, slave_dev->name);
write_unlock_bh(&bond->lock);
+ unblock_netpoll_tx();
return -EINVAL;
}
@@ -1953,6 +1992,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
}
write_unlock_bh(&bond->lock);
+ unblock_netpoll_tx();
/* must do this from outside any spinlocks */
bond_destroy_slave_symlinks(bond_dev, slave_dev);
@@ -1983,10 +2023,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
#ifdef CONFIG_NET_POLL_CONTROLLER
read_lock_bh(&bond->lock);
- /* Make sure netpoll over stays disabled until fixed. */
- if (!disable_netpoll)
- if (slaves_support_netpoll(bond_dev))
- bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
+ if (slaves_support_netpoll(bond_dev))
+ bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
read_unlock_bh(&bond->lock);
if (slave_dev->netdev_ops->ndo_netpoll_cleanup)
slave_dev->netdev_ops->ndo_netpoll_cleanup(slave_dev);
@@ -2019,8 +2057,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
* First release a slave and than destroy the bond if no more slaves are left.
* Must be under rtnl_lock when this function is called.
*/
-int bond_release_and_destroy(struct net_device *bond_dev,
- struct net_device *slave_dev)
+static int bond_release_and_destroy(struct net_device *bond_dev,
+ struct net_device *slave_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
int ret;
@@ -2142,7 +2180,6 @@ static int bond_release_all(struct net_device *bond_dev)
out:
write_unlock_bh(&bond->lock);
-
return 0;
}
@@ -2191,9 +2228,11 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi
(old_active) &&
(new_active->link == BOND_LINK_UP) &&
IS_UP(new_active->dev)) {
+ block_netpoll_tx();
write_lock_bh(&bond->curr_slave_lock);
bond_change_active_slave(bond, new_active);
write_unlock_bh(&bond->curr_slave_lock);
+ unblock_netpoll_tx();
} else
res = -EINVAL;
@@ -2368,8 +2407,11 @@ static void bond_miimon_commit(struct bonding *bond)
slave->state = BOND_STATE_BACKUP;
}
- pr_info("%s: link status definitely up for interface %s.\n",
- bond->dev->name, slave->dev->name);
+ bond_update_speed_duplex(slave);
+
+ pr_info("%s: link status definitely up for interface %s, %d Mbps %s duplex.\n",
+ bond->dev->name, slave->dev->name,
+ slave->speed, slave->duplex ? "full" : "half");
/* notify ad that the link status has changed */
if (bond->params.mode == BOND_MODE_8023AD)
@@ -2422,9 +2464,11 @@ static void bond_miimon_commit(struct bonding *bond)
do_failover:
ASSERT_RTNL();
+ block_netpoll_tx();
write_lock_bh(&bond->curr_slave_lock);
bond_select_active_slave(bond);
write_unlock_bh(&bond->curr_slave_lock);
+ unblock_netpoll_tx();
}
bond_set_carrier(bond);
@@ -2867,11 +2911,13 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
}
if (do_failover) {
+ block_netpoll_tx();
write_lock_bh(&bond->curr_slave_lock);
bond_select_active_slave(bond);
write_unlock_bh(&bond->curr_slave_lock);
+ unblock_netpoll_tx();
}
re_arm:
@@ -3030,9 +3076,11 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks)
do_failover:
ASSERT_RTNL();
+ block_netpoll_tx();
write_lock_bh(&bond->curr_slave_lock);
bond_select_active_slave(bond);
write_unlock_bh(&bond->curr_slave_lock);
+ unblock_netpoll_tx();
}
bond_set_carrier(bond);
@@ -3312,6 +3360,8 @@ static void bond_info_show_slave(struct seq_file *seq,
seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name);
seq_printf(seq, "MII Status: %s\n",
(slave->link == BOND_LINK_UP) ? "up" : "down");
+ seq_printf(seq, "Speed: %d Mbps\n", slave->speed);
+ seq_printf(seq, "Duplex: %s\n", slave->duplex ? "full" : "half");
seq_printf(seq, "Link Failure Count: %u\n",
slave->link_failure_count);
@@ -3744,6 +3794,8 @@ static int bond_open(struct net_device *bond_dev)
bond->kill_timers = 0;
+ INIT_DELAYED_WORK(&bond->mcast_work, bond_resend_igmp_join_requests_delayed);
+
if (bond_is_lb(bond)) {
/* bond_alb_initialize must be called before the timer
* is started.
@@ -3828,6 +3880,8 @@ static int bond_close(struct net_device *bond_dev)
break;
}
+ if (delayed_work_pending(&bond->mcast_work))
+ cancel_delayed_work(&bond->mcast_work);
if (bond_is_lb(bond)) {
/* Must be called only after all
@@ -4514,6 +4568,13 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct bonding *bond = netdev_priv(dev);
+ /*
+ * If we risk deadlock from transmitting this in the
+ * netpoll path, tell netpoll to queue the frame for later tx
+ */
+ if (is_netpoll_tx_blocked(dev))
+ return NETDEV_TX_BUSY;
+
if (TX_QUEUE_OVERRIDE(bond->params.mode)) {
if (!bond_slave_override(bond, skb))
return NETDEV_TX_OK;
@@ -4678,6 +4739,10 @@ static void bond_setup(struct net_device *bond_dev)
NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_FILTER);
+ /* By default, we enable GRO on bonding devices.
+ * Actual support requires lowlevel drivers are GRO ready.
+ */
+ bond_dev->features |= NETIF_F_GRO;
}
static void bond_work_cancel_all(struct bonding *bond)
@@ -4699,6 +4764,9 @@ static void bond_work_cancel_all(struct bonding *bond)
if (bond->params.mode == BOND_MODE_8023AD &&
delayed_work_pending(&bond->ad_work))
cancel_delayed_work(&bond->ad_work);
+
+ if (delayed_work_pending(&bond->mcast_work))
+ cancel_delayed_work(&bond->mcast_work);
}
/*
@@ -4891,6 +4959,13 @@ static int bond_check_params(struct bond_params *params)
all_slaves_active = 0;
}
+ if (resend_igmp < 0 || resend_igmp > 255) {
+ pr_warning("Warning: resend_igmp (%d) should be between "
+ "0 and 255, resetting to %d\n",
+ resend_igmp, BOND_DEFAULT_RESEND_IGMP);
+ resend_igmp = BOND_DEFAULT_RESEND_IGMP;
+ }
+
/* reset values for TLB/ALB */
if ((bond_mode == BOND_MODE_TLB) ||
(bond_mode == BOND_MODE_ALB)) {
@@ -5063,6 +5138,7 @@ static int bond_check_params(struct bond_params *params)
params->fail_over_mac = fail_over_mac_value;
params->tx_queues = tx_queues;
params->all_slaves_active = all_slaves_active;
+ params->resend_igmp = resend_igmp;
if (primary) {
strncpy(params->primary, primary, IFNAMSIZ);
@@ -5221,6 +5297,13 @@ static int __init bonding_init(void)
if (res)
goto out;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ if (!alloc_cpumask_var(&netpoll_block_tx, GFP_KERNEL)) {
+ res = -ENOMEM;
+ goto out;
+ }
+#endif
+
res = register_pernet_subsys(&bond_net_ops);
if (res)
goto out;
@@ -5239,6 +5322,7 @@ static int __init bonding_init(void)
if (res)
goto err;
+
register_netdevice_notifier(&bond_netdev_notifier);
register_inetaddr_notifier(&bond_inetaddr_notifier);
bond_register_ipv6_notifier();
@@ -5248,6 +5332,9 @@ err:
rtnl_link_unregister(&bond_link_ops);
err_link:
unregister_pernet_subsys(&bond_net_ops);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ free_cpumask_var(netpoll_block_tx);
+#endif
goto out;
}
@@ -5262,6 +5349,10 @@ static void __exit bonding_exit(void)
rtnl_link_unregister(&bond_link_ops);
unregister_pernet_subsys(&bond_net_ops);
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ free_cpumask_var(netpoll_block_tx);
+#endif
}
module_init(bonding_init);
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index c311aed9bd02..8fd0174c5380 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -1066,6 +1066,7 @@ static ssize_t bonding_store_primary(struct device *d,
if (!rtnl_trylock())
return restart_syscall();
+ block_netpoll_tx();
read_lock(&bond->lock);
write_lock_bh(&bond->curr_slave_lock);
@@ -1101,6 +1102,7 @@ static ssize_t bonding_store_primary(struct device *d,
out:
write_unlock_bh(&bond->curr_slave_lock);
read_unlock(&bond->lock);
+ unblock_netpoll_tx();
rtnl_unlock();
return count;
@@ -1146,11 +1148,13 @@ static ssize_t bonding_store_primary_reselect(struct device *d,
bond->dev->name, pri_reselect_tbl[new_value].modename,
new_value);
+ block_netpoll_tx();
read_lock(&bond->lock);
write_lock_bh(&bond->curr_slave_lock);
bond_select_active_slave(bond);
write_unlock_bh(&bond->curr_slave_lock);
read_unlock(&bond->lock);
+ unblock_netpoll_tx();
out:
rtnl_unlock();
return ret;
@@ -1232,6 +1236,8 @@ static ssize_t bonding_store_active_slave(struct device *d,
if (!rtnl_trylock())
return restart_syscall();
+
+ block_netpoll_tx();
read_lock(&bond->lock);
write_lock_bh(&bond->curr_slave_lock);
@@ -1288,6 +1294,8 @@ static ssize_t bonding_store_active_slave(struct device *d,
out:
write_unlock_bh(&bond->curr_slave_lock);
read_unlock(&bond->lock);
+ unblock_netpoll_tx();
+
rtnl_unlock();
return count;
@@ -1592,6 +1600,49 @@ out:
static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR,
bonding_show_slaves_active, bonding_store_slaves_active);
+/*
+ * Show and set the number of IGMP membership reports to send on link failure
+ */
+static ssize_t bonding_show_resend_igmp(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bonding *bond = to_bond(d);
+
+ return sprintf(buf, "%d\n", bond->params.resend_igmp);
+}
+
+static ssize_t bonding_store_resend_igmp(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int new_value, ret = count;
+ struct bonding *bond = to_bond(d);
+
+ if (sscanf(buf, "%d", &new_value) != 1) {
+ pr_err("%s: no resend_igmp value specified.\n",
+ bond->dev->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (new_value < 0) {
+ pr_err("%s: Invalid resend_igmp value %d not in range 0-255; rejected.\n",
+ bond->dev->name, new_value);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pr_info("%s: Setting resend_igmp to %d.\n",
+ bond->dev->name, new_value);
+ bond->params.resend_igmp = new_value;
+out:
+ return ret;
+}
+
+static DEVICE_ATTR(resend_igmp, S_IRUGO | S_IWUSR,
+ bonding_show_resend_igmp, bonding_store_resend_igmp);
+
static struct attribute *per_bond_attrs[] = {
&dev_attr_slaves.attr,
&dev_attr_mode.attr,
@@ -1619,6 +1670,7 @@ static struct attribute *per_bond_attrs[] = {
&dev_attr_ad_partner_mac.attr,
&dev_attr_queue_id.attr,
&dev_attr_all_slaves_active.attr,
+ &dev_attr_resend_igmp.attr,
NULL,
};
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index c6fdd851579a..4eedb12df6ca 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -19,6 +19,7 @@
#include <linux/proc_fs.h>
#include <linux/if_bonding.h>
#include <linux/kobject.h>
+#include <linux/cpumask.h>
#include <linux/in6.h>
#include "bond_3ad.h"
#include "bond_alb.h"
@@ -117,6 +118,35 @@
bond_for_each_slave_from(bond, pos, cnt, (bond)->first_slave)
+#ifdef CONFIG_NET_POLL_CONTROLLER
+extern cpumask_var_t netpoll_block_tx;
+
+static inline void block_netpoll_tx(void)
+{
+ preempt_disable();
+ BUG_ON(cpumask_test_and_set_cpu(smp_processor_id(),
+ netpoll_block_tx));
+}
+
+static inline void unblock_netpoll_tx(void)
+{
+ BUG_ON(!cpumask_test_and_clear_cpu(smp_processor_id(),
+ netpoll_block_tx));
+ preempt_enable();
+}
+
+static inline int is_netpoll_tx_blocked(struct net_device *dev)
+{
+ if (unlikely(dev->priv_flags & IFF_IN_NETPOLL))
+ return cpumask_test_cpu(smp_processor_id(), netpoll_block_tx);
+ return 0;
+}
+#else
+#define block_netpoll_tx()
+#define unblock_netpoll_tx()
+#define is_netpoll_tx_blocked(dev) (0)
+#endif
+
struct bond_params {
int mode;
int xmit_policy;
@@ -136,6 +166,7 @@ struct bond_params {
__be32 arp_targets[BOND_MAX_ARP_TARGETS];
int tx_queues;
int all_slaves_active;
+ int resend_igmp;
};
struct bond_parm_tbl {
@@ -202,6 +233,7 @@ struct bonding {
s8 send_grat_arp;
s8 send_unsol_na;
s8 setup_by_slave;
+ s8 igmp_retrans;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_entry;
char proc_file_name[IFNAMSIZ];
@@ -223,6 +255,7 @@ struct bonding {
struct delayed_work arp_work;
struct delayed_work alb_work;
struct delayed_work ad_work;
+ struct delayed_work mcast_work;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct in6_addr master_ipv6;
#endif
@@ -331,7 +364,6 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond)
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_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_create_sysfs(void);
void bond_destroy_sysfs(void);
void bond_prepare_sysfs_group(struct bonding *bond);
diff --git a/drivers/net/bsd_comp.c b/drivers/net/bsd_comp.c
index 88edb986691a..6e99d80ec409 100644
--- a/drivers/net/bsd_comp.c
+++ b/drivers/net/bsd_comp.c
@@ -429,7 +429,7 @@ static void *bsd_alloc (unsigned char *options, int opt_len, int decomp)
if (!db->lens)
{
bsd_free (db);
- return (NULL);
+ return NULL;
}
}
/*
diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
index 75bfc3a9d95f..09ed3f42d673 100644
--- a/drivers/net/caif/Kconfig
+++ b/drivers/net/caif/Kconfig
@@ -31,3 +31,10 @@ config CAIF_SPI_SYNC
Putting the next command and length in the start of the frame can
help to synchronize to the next transfer in case of over or under-runs.
This option also needs to be enabled on the modem.
+
+config CAIF_SHM
+ tristate "CAIF shared memory protocol driver"
+ depends on CAIF && U5500_MBOX
+ default n
+ ---help---
+ The CAIF shared memory protocol driver for the STE UX5500 platform.
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
index 3a11d619452b..b38d987da67d 100644
--- a/drivers/net/caif/Makefile
+++ b/drivers/net/caif/Makefile
@@ -8,3 +8,7 @@ obj-$(CONFIG_CAIF_TTY) += caif_serial.o
# SPI slave physical interfaces module
cfspi_slave-objs := caif_spi.o caif_spi_slave.o
obj-$(CONFIG_CAIF_SPI_SLAVE) += cfspi_slave.o
+
+# Shared memory
+caif_shm-objs := caif_shmcore.o caif_shm_u5500.o
+obj-$(CONFIG_CAIF_SHM) += caif_shm.o
diff --git a/drivers/net/caif/caif_shm_u5500.c b/drivers/net/caif/caif_shm_u5500.c
new file mode 100644
index 000000000000..1cd90da86f13
--- /dev/null
+++ b/drivers/net/caif/caif_shm_u5500.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author: Amarnath Revanna / amarnath.bangalore.revanna@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":" __func__ "():" fmt
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <mach/mbox.h>
+#include <net/caif/caif_shm.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CAIF Shared Memory protocol driver");
+
+#define MAX_SHM_INSTANCES 1
+
+enum {
+ MBX_ACC0,
+ MBX_ACC1,
+ MBX_DSP
+};
+
+static struct shmdev_layer shmdev_lyr[MAX_SHM_INSTANCES];
+
+static unsigned int shm_start;
+static unsigned int shm_size;
+
+module_param(shm_size, uint , 0440);
+MODULE_PARM_DESC(shm_total_size, "Start of SHM shared memory");
+
+module_param(shm_start, uint , 0440);
+MODULE_PARM_DESC(shm_total_start, "Total Size of SHM shared memory");
+
+static int shmdev_send_msg(u32 dev_id, u32 mbx_msg)
+{
+ /* Always block until msg is written successfully */
+ mbox_send(shmdev_lyr[dev_id].hmbx, mbx_msg, true);
+ return 0;
+}
+
+static int shmdev_mbx_setup(void *pshmdrv_cb, struct shmdev_layer *pshm_dev,
+ void *pshm_drv)
+{
+ /*
+ * For UX5500, we have only 1 SHM instance which uses MBX0
+ * for communication with the peer modem
+ */
+ pshm_dev->hmbx = mbox_setup(MBX_ACC0, pshmdrv_cb, pshm_drv);
+
+ if (!pshm_dev->hmbx)
+ return -ENODEV;
+ else
+ return 0;
+}
+
+static int __init caif_shmdev_init(void)
+{
+ int i, result;
+
+ /* Loop is currently overkill, there is only one instance */
+ for (i = 0; i < MAX_SHM_INSTANCES; i++) {
+
+ shmdev_lyr[i].shm_base_addr = shm_start;
+ shmdev_lyr[i].shm_total_sz = shm_size;
+
+ if (((char *)shmdev_lyr[i].shm_base_addr == NULL)
+ || (shmdev_lyr[i].shm_total_sz <= 0)) {
+ pr_warn("ERROR,"
+ "Shared memory Address and/or Size incorrect"
+ ", Bailing out ...\n");
+ result = -EINVAL;
+ goto clean;
+ }
+
+ pr_info("SHM AREA (instance %d) STARTS"
+ " AT %p\n", i, (char *)shmdev_lyr[i].shm_base_addr);
+
+ shmdev_lyr[i].shm_id = i;
+ shmdev_lyr[i].pshmdev_mbxsend = shmdev_send_msg;
+ shmdev_lyr[i].pshmdev_mbxsetup = shmdev_mbx_setup;
+
+ /*
+ * Finally, CAIF core module is called with details in place:
+ * 1. SHM base address
+ * 2. SHM size
+ * 3. MBX handle
+ */
+ result = caif_shmcore_probe(&shmdev_lyr[i]);
+ if (result) {
+ pr_warn("ERROR[%d],"
+ "Could not probe SHM core (instance %d)"
+ " Bailing out ...\n", result, i);
+ goto clean;
+ }
+ }
+
+ return 0;
+
+clean:
+ /*
+ * For now, we assume that even if one instance of SHM fails, we bail
+ * out of the driver support completely. For this, we need to release
+ * any memory allocated and unregister any instance of SHM net device.
+ */
+ for (i = 0; i < MAX_SHM_INSTANCES; i++) {
+ if (shmdev_lyr[i].pshm_netdev)
+ unregister_netdev(shmdev_lyr[i].pshm_netdev);
+ }
+ return result;
+}
+
+static void __exit caif_shmdev_exit(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_SHM_INSTANCES; i++) {
+ caif_shmcore_remove(shmdev_lyr[i].pshm_netdev);
+ kfree((void *)shmdev_lyr[i].shm_base_addr);
+ }
+
+}
+
+module_init(caif_shmdev_init);
+module_exit(caif_shmdev_exit);
diff --git a/drivers/net/caif/caif_shmcore.c b/drivers/net/caif/caif_shmcore.c
new file mode 100644
index 000000000000..19f9c0656667
--- /dev/null
+++ b/drivers/net/caif/caif_shmcore.c
@@ -0,0 +1,744 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Authors: Amarnath Revanna / amarnath.bangalore.revanna@stericsson.com,
+ * Daniel Martensson / daniel.martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":" __func__ "():" fmt
+
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/caif/caif_device.h>
+#include <net/caif/caif_shm.h>
+
+#define NR_TX_BUF 6
+#define NR_RX_BUF 6
+#define TX_BUF_SZ 0x2000
+#define RX_BUF_SZ 0x2000
+
+#define CAIF_NEEDED_HEADROOM 32
+
+#define CAIF_FLOW_ON 1
+#define CAIF_FLOW_OFF 0
+
+#define LOW_WATERMARK 3
+#define HIGH_WATERMARK 4
+
+/* Maximum number of CAIF buffers per shared memory buffer. */
+#define SHM_MAX_FRMS_PER_BUF 10
+
+/*
+ * Size in bytes of the descriptor area
+ * (With end of descriptor signalling)
+ */
+#define SHM_CAIF_DESC_SIZE ((SHM_MAX_FRMS_PER_BUF + 1) * \
+ sizeof(struct shm_pck_desc))
+
+/*
+ * Offset to the first CAIF frame within a shared memory buffer.
+ * Aligned on 32 bytes.
+ */
+#define SHM_CAIF_FRM_OFS (SHM_CAIF_DESC_SIZE + (SHM_CAIF_DESC_SIZE % 32))
+
+/* Number of bytes for CAIF shared memory header. */
+#define SHM_HDR_LEN 1
+
+/* Number of padding bytes for the complete CAIF frame. */
+#define SHM_FRM_PAD_LEN 4
+
+#define CAIF_MAX_MTU 4096
+
+#define SHM_SET_FULL(x) (((x+1) & 0x0F) << 0)
+#define SHM_GET_FULL(x) (((x >> 0) & 0x0F) - 1)
+
+#define SHM_SET_EMPTY(x) (((x+1) & 0x0F) << 4)
+#define SHM_GET_EMPTY(x) (((x >> 4) & 0x0F) - 1)
+
+#define SHM_FULL_MASK (0x0F << 0)
+#define SHM_EMPTY_MASK (0x0F << 4)
+
+struct shm_pck_desc {
+ /*
+ * Offset from start of shared memory area to start of
+ * shared memory CAIF frame.
+ */
+ u32 frm_ofs;
+ u32 frm_len;
+};
+
+struct buf_list {
+ unsigned char *desc_vptr;
+ u32 phy_addr;
+ u32 index;
+ u32 len;
+ u32 frames;
+ u32 frm_ofs;
+ struct list_head list;
+};
+
+struct shm_caif_frm {
+ /* Number of bytes of padding before the CAIF frame. */
+ u8 hdr_ofs;
+};
+
+struct shmdrv_layer {
+ /* caif_dev_common must always be first in the structure*/
+ struct caif_dev_common cfdev;
+
+ u32 shm_tx_addr;
+ u32 shm_rx_addr;
+ u32 shm_base_addr;
+ u32 tx_empty_available;
+ spinlock_t lock;
+
+ struct list_head tx_empty_list;
+ struct list_head tx_pend_list;
+ struct list_head tx_full_list;
+ struct list_head rx_empty_list;
+ struct list_head rx_pend_list;
+ struct list_head rx_full_list;
+
+ struct workqueue_struct *pshm_tx_workqueue;
+ struct workqueue_struct *pshm_rx_workqueue;
+
+ struct work_struct shm_tx_work;
+ struct work_struct shm_rx_work;
+
+ struct sk_buff_head sk_qhead;
+ struct shmdev_layer *pshm_dev;
+};
+
+static int shm_netdev_open(struct net_device *shm_netdev)
+{
+ netif_wake_queue(shm_netdev);
+ return 0;
+}
+
+static int shm_netdev_close(struct net_device *shm_netdev)
+{
+ netif_stop_queue(shm_netdev);
+ return 0;
+}
+
+int caif_shmdrv_rx_cb(u32 mbx_msg, void *priv)
+{
+ struct buf_list *pbuf;
+ struct shmdrv_layer *pshm_drv;
+ struct list_head *pos;
+ u32 avail_emptybuff = 0;
+ unsigned long flags = 0;
+
+ pshm_drv = (struct shmdrv_layer *)priv;
+
+ /* Check for received buffers. */
+ if (mbx_msg & SHM_FULL_MASK) {
+ int idx;
+
+ spin_lock_irqsave(&pshm_drv->lock, flags);
+
+ /* Check whether we have any outstanding buffers. */
+ if (list_empty(&pshm_drv->rx_empty_list)) {
+
+ /* Release spin lock. */
+ spin_unlock_irqrestore(&pshm_drv->lock, flags);
+
+ /* We print even in IRQ context... */
+ pr_warn("No empty Rx buffers to fill: "
+ "mbx_msg:%x\n", mbx_msg);
+
+ /* Bail out. */
+ goto err_sync;
+ }
+
+ pbuf =
+ list_entry(pshm_drv->rx_empty_list.next,
+ struct buf_list, list);
+ idx = pbuf->index;
+
+ /* Check buffer synchronization. */
+ if (idx != SHM_GET_FULL(mbx_msg)) {
+
+ /* We print even in IRQ context... */
+ pr_warn(
+ "phyif_shm_mbx_msg_cb: RX full out of sync:"
+ " idx:%d, msg:%x SHM_GET_FULL(mbx_msg):%x\n",
+ idx, mbx_msg, SHM_GET_FULL(mbx_msg));
+
+ spin_unlock_irqrestore(&pshm_drv->lock, flags);
+
+ /* Bail out. */
+ goto err_sync;
+ }
+
+ list_del_init(&pbuf->list);
+ list_add_tail(&pbuf->list, &pshm_drv->rx_full_list);
+
+ spin_unlock_irqrestore(&pshm_drv->lock, flags);
+
+ /* Schedule RX work queue. */
+ if (!work_pending(&pshm_drv->shm_rx_work))
+ queue_work(pshm_drv->pshm_rx_workqueue,
+ &pshm_drv->shm_rx_work);
+ }
+
+ /* Check for emptied buffers. */
+ if (mbx_msg & SHM_EMPTY_MASK) {
+ int idx;
+
+ spin_lock_irqsave(&pshm_drv->lock, flags);
+
+ /* Check whether we have any outstanding buffers. */
+ if (list_empty(&pshm_drv->tx_full_list)) {
+
+ /* We print even in IRQ context... */
+ pr_warn("No TX to empty: msg:%x\n", mbx_msg);
+
+ spin_unlock_irqrestore(&pshm_drv->lock, flags);
+
+ /* Bail out. */
+ goto err_sync;
+ }
+
+ pbuf =
+ list_entry(pshm_drv->tx_full_list.next,
+ struct buf_list, list);
+ idx = pbuf->index;
+
+ /* Check buffer synchronization. */
+ if (idx != SHM_GET_EMPTY(mbx_msg)) {
+
+ spin_unlock_irqrestore(&pshm_drv->lock, flags);
+
+ /* We print even in IRQ context... */
+ pr_warn("TX empty "
+ "out of sync:idx:%d, msg:%x\n", idx, mbx_msg);
+
+ /* Bail out. */
+ goto err_sync;
+ }
+ list_del_init(&pbuf->list);
+
+ /* Reset buffer parameters. */
+ pbuf->frames = 0;
+ pbuf->frm_ofs = SHM_CAIF_FRM_OFS;
+
+ list_add_tail(&pbuf->list, &pshm_drv->tx_empty_list);
+
+ /* Check the available no. of buffers in the empty list */
+ list_for_each(pos, &pshm_drv->tx_empty_list)
+ avail_emptybuff++;
+
+ /* Check whether we have to wake up the transmitter. */
+ if ((avail_emptybuff > HIGH_WATERMARK) &&
+ (!pshm_drv->tx_empty_available)) {
+ pshm_drv->tx_empty_available = 1;
+ pshm_drv->cfdev.flowctrl
+ (pshm_drv->pshm_dev->pshm_netdev,
+ CAIF_FLOW_ON);
+
+ spin_unlock_irqrestore(&pshm_drv->lock, flags);
+
+ /* Schedule the work queue. if required */
+ if (!work_pending(&pshm_drv->shm_tx_work))
+ queue_work(pshm_drv->pshm_tx_workqueue,
+ &pshm_drv->shm_tx_work);
+ } else
+ spin_unlock_irqrestore(&pshm_drv->lock, flags);
+ }
+
+ return 0;
+
+err_sync:
+ return -EIO;
+}
+
+static void shm_rx_work_func(struct work_struct *rx_work)
+{
+ struct shmdrv_layer *pshm_drv;
+ struct buf_list *pbuf;
+ unsigned long flags = 0;
+ struct sk_buff *skb;
+ char *p;
+ int ret;
+
+ pshm_drv = container_of(rx_work, struct shmdrv_layer, shm_rx_work);
+
+ while (1) {
+
+ struct shm_pck_desc *pck_desc;
+
+ spin_lock_irqsave(&pshm_drv->lock, flags);
+
+ /* Check for received buffers. */
+ if (list_empty(&pshm_drv->rx_full_list)) {
+ spin_unlock_irqrestore(&pshm_drv->lock, flags);
+ break;
+ }
+
+ pbuf =
+ list_entry(pshm_drv->rx_full_list.next, struct buf_list,
+ list);
+ list_del_init(&pbuf->list);
+
+ /* Retrieve pointer to start of the packet descriptor area. */
+ pck_desc = (struct shm_pck_desc *) pbuf->desc_vptr;
+
+ /*
+ * Check whether descriptor contains a CAIF shared memory
+ * frame.
+ */
+ while (pck_desc->frm_ofs) {
+ unsigned int frm_buf_ofs;
+ unsigned int frm_pck_ofs;
+ unsigned int frm_pck_len;
+ /*
+ * Check whether offset is within buffer limits
+ * (lower).
+ */
+ if (pck_desc->frm_ofs <
+ (pbuf->phy_addr - pshm_drv->shm_base_addr))
+ break;
+ /*
+ * Check whether offset is within buffer limits
+ * (higher).
+ */
+ if (pck_desc->frm_ofs >
+ ((pbuf->phy_addr - pshm_drv->shm_base_addr) +
+ pbuf->len))
+ break;
+
+ /* Calculate offset from start of buffer. */
+ frm_buf_ofs =
+ pck_desc->frm_ofs - (pbuf->phy_addr -
+ pshm_drv->shm_base_addr);
+
+ /*
+ * Calculate offset and length of CAIF packet while
+ * taking care of the shared memory header.
+ */
+ frm_pck_ofs =
+ frm_buf_ofs + SHM_HDR_LEN +
+ (*(pbuf->desc_vptr + frm_buf_ofs));
+ frm_pck_len =
+ (pck_desc->frm_len - SHM_HDR_LEN -
+ (*(pbuf->desc_vptr + frm_buf_ofs)));
+
+ /* Check whether CAIF packet is within buffer limits */
+ if ((frm_pck_ofs + pck_desc->frm_len) > pbuf->len)
+ break;
+
+ /* Get a suitable CAIF packet and copy in data. */
+ skb = netdev_alloc_skb(pshm_drv->pshm_dev->pshm_netdev,
+ frm_pck_len + 1);
+ BUG_ON(skb == NULL);
+
+ p = skb_put(skb, frm_pck_len);
+ memcpy(p, pbuf->desc_vptr + frm_pck_ofs, frm_pck_len);
+
+ skb->protocol = htons(ETH_P_CAIF);
+ skb_reset_mac_header(skb);
+ skb->dev = pshm_drv->pshm_dev->pshm_netdev;
+
+ /* Push received packet up the stack. */
+ ret = netif_rx_ni(skb);
+
+ if (!ret) {
+ pshm_drv->pshm_dev->pshm_netdev->stats.
+ rx_packets++;
+ pshm_drv->pshm_dev->pshm_netdev->stats.
+ rx_bytes += pck_desc->frm_len;
+ } else
+ ++pshm_drv->pshm_dev->pshm_netdev->stats.
+ rx_dropped;
+ /* Move to next packet descriptor. */
+ pck_desc++;
+ }
+
+ list_add_tail(&pbuf->list, &pshm_drv->rx_pend_list);
+
+ spin_unlock_irqrestore(&pshm_drv->lock, flags);
+
+ }
+
+ /* Schedule the work queue. if required */
+ if (!work_pending(&pshm_drv->shm_tx_work))
+ queue_work(pshm_drv->pshm_tx_workqueue, &pshm_drv->shm_tx_work);
+
+}
+
+static void shm_tx_work_func(struct work_struct *tx_work)
+{
+ u32 mbox_msg;
+ unsigned int frmlen, avail_emptybuff, append = 0;
+ unsigned long flags = 0;
+ struct buf_list *pbuf = NULL;
+ struct shmdrv_layer *pshm_drv;
+ struct shm_caif_frm *frm;
+ struct sk_buff *skb;
+ struct shm_pck_desc *pck_desc;
+ struct list_head *pos;
+
+ pshm_drv = container_of(tx_work, struct shmdrv_layer, shm_tx_work);
+
+ do {
+ /* Initialize mailbox message. */
+ mbox_msg = 0x00;
+ avail_emptybuff = 0;
+
+ spin_lock_irqsave(&pshm_drv->lock, flags);
+
+ /* Check for pending receive buffers. */
+ if (!list_empty(&pshm_drv->rx_pend_list)) {
+
+ pbuf = list_entry(pshm_drv->rx_pend_list.next,
+ struct buf_list, list);
+
+ list_del_init(&pbuf->list);
+ list_add_tail(&pbuf->list, &pshm_drv->rx_empty_list);
+ /*
+ * Value index is never changed,
+ * so read access should be safe.
+ */
+ mbox_msg |= SHM_SET_EMPTY(pbuf->index);
+ }
+
+ skb = skb_peek(&pshm_drv->sk_qhead);
+
+ if (skb == NULL)
+ goto send_msg;
+
+ /* Check the available no. of buffers in the empty list */
+ list_for_each(pos, &pshm_drv->tx_empty_list)
+ avail_emptybuff++;
+
+ if ((avail_emptybuff < LOW_WATERMARK) &&
+ pshm_drv->tx_empty_available) {
+ /* Update blocking condition. */
+ pshm_drv->tx_empty_available = 0;
+ pshm_drv->cfdev.flowctrl
+ (pshm_drv->pshm_dev->pshm_netdev,
+ CAIF_FLOW_OFF);
+ }
+ /*
+ * We simply return back to the caller if we do not have space
+ * either in Tx pending list or Tx empty list. In this case,
+ * we hold the received skb in the skb list, waiting to
+ * be transmitted once Tx buffers become available
+ */
+ if (list_empty(&pshm_drv->tx_empty_list))
+ goto send_msg;
+
+ /* Get the first free Tx buffer. */
+ pbuf = list_entry(pshm_drv->tx_empty_list.next,
+ struct buf_list, list);
+ do {
+ if (append) {
+ skb = skb_peek(&pshm_drv->sk_qhead);
+ if (skb == NULL)
+ break;
+ }
+
+ frm = (struct shm_caif_frm *)
+ (pbuf->desc_vptr + pbuf->frm_ofs);
+
+ frm->hdr_ofs = 0;
+ frmlen = 0;
+ frmlen += SHM_HDR_LEN + frm->hdr_ofs + skb->len;
+
+ /* Add tail padding if needed. */
+ if (frmlen % SHM_FRM_PAD_LEN)
+ frmlen += SHM_FRM_PAD_LEN -
+ (frmlen % SHM_FRM_PAD_LEN);
+
+ /*
+ * Verify that packet, header and additional padding
+ * can fit within the buffer frame area.
+ */
+ if (frmlen >= (pbuf->len - pbuf->frm_ofs))
+ break;
+
+ if (!append) {
+ list_del_init(&pbuf->list);
+ append = 1;
+ }
+
+ skb = skb_dequeue(&pshm_drv->sk_qhead);
+ /* Copy in CAIF frame. */
+ skb_copy_bits(skb, 0, pbuf->desc_vptr +
+ pbuf->frm_ofs + SHM_HDR_LEN +
+ frm->hdr_ofs, skb->len);
+
+ pshm_drv->pshm_dev->pshm_netdev->stats.tx_packets++;
+ pshm_drv->pshm_dev->pshm_netdev->stats.tx_bytes +=
+ frmlen;
+ dev_kfree_skb(skb);
+
+ /* Fill in the shared memory packet descriptor area. */
+ pck_desc = (struct shm_pck_desc *) (pbuf->desc_vptr);
+ /* Forward to current frame. */
+ pck_desc += pbuf->frames;
+ pck_desc->frm_ofs = (pbuf->phy_addr -
+ pshm_drv->shm_base_addr) +
+ pbuf->frm_ofs;
+ pck_desc->frm_len = frmlen;
+ /* Terminate packet descriptor area. */
+ pck_desc++;
+ pck_desc->frm_ofs = 0;
+ /* Update buffer parameters. */
+ pbuf->frames++;
+ pbuf->frm_ofs += frmlen + (frmlen % 32);
+
+ } while (pbuf->frames < SHM_MAX_FRMS_PER_BUF);
+
+ /* Assign buffer as full. */
+ list_add_tail(&pbuf->list, &pshm_drv->tx_full_list);
+ append = 0;
+ mbox_msg |= SHM_SET_FULL(pbuf->index);
+send_msg:
+ spin_unlock_irqrestore(&pshm_drv->lock, flags);
+
+ if (mbox_msg)
+ pshm_drv->pshm_dev->pshmdev_mbxsend
+ (pshm_drv->pshm_dev->shm_id, mbox_msg);
+ } while (mbox_msg);
+}
+
+static int shm_netdev_tx(struct sk_buff *skb, struct net_device *shm_netdev)
+{
+ struct shmdrv_layer *pshm_drv;
+ unsigned long flags = 0;
+
+ pshm_drv = netdev_priv(shm_netdev);
+
+ spin_lock_irqsave(&pshm_drv->lock, flags);
+
+ skb_queue_tail(&pshm_drv->sk_qhead, skb);
+
+ spin_unlock_irqrestore(&pshm_drv->lock, flags);
+
+ /* Schedule Tx work queue. for deferred processing of skbs*/
+ if (!work_pending(&pshm_drv->shm_tx_work))
+ queue_work(pshm_drv->pshm_tx_workqueue, &pshm_drv->shm_tx_work);
+
+ return 0;
+}
+
+static const struct net_device_ops netdev_ops = {
+ .ndo_open = shm_netdev_open,
+ .ndo_stop = shm_netdev_close,
+ .ndo_start_xmit = shm_netdev_tx,
+};
+
+static void shm_netdev_setup(struct net_device *pshm_netdev)
+{
+ struct shmdrv_layer *pshm_drv;
+ pshm_netdev->netdev_ops = &netdev_ops;
+
+ pshm_netdev->mtu = CAIF_MAX_MTU;
+ pshm_netdev->type = ARPHRD_CAIF;
+ pshm_netdev->hard_header_len = CAIF_NEEDED_HEADROOM;
+ pshm_netdev->tx_queue_len = 0;
+ pshm_netdev->destructor = free_netdev;
+
+ pshm_drv = netdev_priv(pshm_netdev);
+
+ /* Initialize structures in a clean state. */
+ memset(pshm_drv, 0, sizeof(struct shmdrv_layer));
+
+ pshm_drv->cfdev.link_select = CAIF_LINK_LOW_LATENCY;
+}
+
+int caif_shmcore_probe(struct shmdev_layer *pshm_dev)
+{
+ int result, j;
+ struct shmdrv_layer *pshm_drv = NULL;
+
+ pshm_dev->pshm_netdev = alloc_netdev(sizeof(struct shmdrv_layer),
+ "cfshm%d", shm_netdev_setup);
+ if (!pshm_dev->pshm_netdev)
+ return -ENOMEM;
+
+ pshm_drv = netdev_priv(pshm_dev->pshm_netdev);
+ pshm_drv->pshm_dev = pshm_dev;
+
+ /*
+ * Initialization starts with the verification of the
+ * availability of MBX driver by calling its setup function.
+ * MBX driver must be available by this time for proper
+ * functioning of SHM driver.
+ */
+ if ((pshm_dev->pshmdev_mbxsetup
+ (caif_shmdrv_rx_cb, pshm_dev, pshm_drv)) != 0) {
+ pr_warn("Could not config. SHM Mailbox,"
+ " Bailing out.....\n");
+ free_netdev(pshm_dev->pshm_netdev);
+ return -ENODEV;
+ }
+
+ skb_queue_head_init(&pshm_drv->sk_qhead);
+
+ pr_info("SHM DEVICE[%d] PROBED BY DRIVER, NEW SHM DRIVER"
+ " INSTANCE AT pshm_drv =0x%p\n",
+ pshm_drv->pshm_dev->shm_id, pshm_drv);
+
+ if (pshm_dev->shm_total_sz <
+ (NR_TX_BUF * TX_BUF_SZ + NR_RX_BUF * RX_BUF_SZ)) {
+
+ pr_warn("ERROR, Amount of available"
+ " Phys. SHM cannot accomodate current SHM "
+ "driver configuration, Bailing out ...\n");
+ free_netdev(pshm_dev->pshm_netdev);
+ return -ENOMEM;
+ }
+
+ pshm_drv->shm_base_addr = pshm_dev->shm_base_addr;
+ pshm_drv->shm_tx_addr = pshm_drv->shm_base_addr;
+
+ if (pshm_dev->shm_loopback)
+ pshm_drv->shm_rx_addr = pshm_drv->shm_tx_addr;
+ else
+ pshm_drv->shm_rx_addr = pshm_dev->shm_base_addr +
+ (NR_TX_BUF * TX_BUF_SZ);
+
+ INIT_LIST_HEAD(&pshm_drv->tx_empty_list);
+ INIT_LIST_HEAD(&pshm_drv->tx_pend_list);
+ INIT_LIST_HEAD(&pshm_drv->tx_full_list);
+
+ INIT_LIST_HEAD(&pshm_drv->rx_empty_list);
+ INIT_LIST_HEAD(&pshm_drv->rx_pend_list);
+ INIT_LIST_HEAD(&pshm_drv->rx_full_list);
+
+ INIT_WORK(&pshm_drv->shm_tx_work, shm_tx_work_func);
+ INIT_WORK(&pshm_drv->shm_rx_work, shm_rx_work_func);
+
+ pshm_drv->pshm_tx_workqueue =
+ create_singlethread_workqueue("shm_tx_work");
+ pshm_drv->pshm_rx_workqueue =
+ create_singlethread_workqueue("shm_rx_work");
+
+ for (j = 0; j < NR_TX_BUF; j++) {
+ struct buf_list *tx_buf =
+ kmalloc(sizeof(struct buf_list), GFP_KERNEL);
+
+ if (tx_buf == NULL) {
+ pr_warn("ERROR, Could not"
+ " allocate dynamic mem. for tx_buf,"
+ " Bailing out ...\n");
+ free_netdev(pshm_dev->pshm_netdev);
+ return -ENOMEM;
+ }
+ tx_buf->index = j;
+ tx_buf->phy_addr = pshm_drv->shm_tx_addr + (TX_BUF_SZ * j);
+ tx_buf->len = TX_BUF_SZ;
+ tx_buf->frames = 0;
+ tx_buf->frm_ofs = SHM_CAIF_FRM_OFS;
+
+ if (pshm_dev->shm_loopback)
+ tx_buf->desc_vptr = (char *)tx_buf->phy_addr;
+ else
+ tx_buf->desc_vptr =
+ ioremap(tx_buf->phy_addr, TX_BUF_SZ);
+
+ list_add_tail(&tx_buf->list, &pshm_drv->tx_empty_list);
+ }
+
+ for (j = 0; j < NR_RX_BUF; j++) {
+ struct buf_list *rx_buf =
+ kmalloc(sizeof(struct buf_list), GFP_KERNEL);
+
+ if (rx_buf == NULL) {
+ pr_warn("ERROR, Could not"
+ " allocate dynamic mem.for rx_buf,"
+ " Bailing out ...\n");
+ free_netdev(pshm_dev->pshm_netdev);
+ return -ENOMEM;
+ }
+ rx_buf->index = j;
+ rx_buf->phy_addr = pshm_drv->shm_rx_addr + (RX_BUF_SZ * j);
+ rx_buf->len = RX_BUF_SZ;
+
+ if (pshm_dev->shm_loopback)
+ rx_buf->desc_vptr = (char *)rx_buf->phy_addr;
+ else
+ rx_buf->desc_vptr =
+ ioremap(rx_buf->phy_addr, RX_BUF_SZ);
+ list_add_tail(&rx_buf->list, &pshm_drv->rx_empty_list);
+ }
+
+ pshm_drv->tx_empty_available = 1;
+ result = register_netdev(pshm_dev->pshm_netdev);
+ if (result)
+ pr_warn("ERROR[%d], SHM could not, "
+ "register with NW FRMWK Bailing out ...\n", result);
+
+ return result;
+}
+
+void caif_shmcore_remove(struct net_device *pshm_netdev)
+{
+ struct buf_list *pbuf;
+ struct shmdrv_layer *pshm_drv = NULL;
+
+ pshm_drv = netdev_priv(pshm_netdev);
+
+ while (!(list_empty(&pshm_drv->tx_pend_list))) {
+ pbuf =
+ list_entry(pshm_drv->tx_pend_list.next,
+ struct buf_list, list);
+
+ list_del(&pbuf->list);
+ kfree(pbuf);
+ }
+
+ while (!(list_empty(&pshm_drv->tx_full_list))) {
+ pbuf =
+ list_entry(pshm_drv->tx_full_list.next,
+ struct buf_list, list);
+ list_del(&pbuf->list);
+ kfree(pbuf);
+ }
+
+ while (!(list_empty(&pshm_drv->tx_empty_list))) {
+ pbuf =
+ list_entry(pshm_drv->tx_empty_list.next,
+ struct buf_list, list);
+ list_del(&pbuf->list);
+ kfree(pbuf);
+ }
+
+ while (!(list_empty(&pshm_drv->rx_full_list))) {
+ pbuf =
+ list_entry(pshm_drv->tx_full_list.next,
+ struct buf_list, list);
+ list_del(&pbuf->list);
+ kfree(pbuf);
+ }
+
+ while (!(list_empty(&pshm_drv->rx_pend_list))) {
+ pbuf =
+ list_entry(pshm_drv->tx_pend_list.next,
+ struct buf_list, list);
+ list_del(&pbuf->list);
+ kfree(pbuf);
+ }
+
+ while (!(list_empty(&pshm_drv->rx_empty_list))) {
+ pbuf =
+ list_entry(pshm_drv->rx_empty_list.next,
+ struct buf_list, list);
+ list_del(&pbuf->list);
+ kfree(pbuf);
+ }
+
+ /* Destroy work queues. */
+ destroy_workqueue(pshm_drv->pshm_tx_workqueue);
+ destroy_workqueue(pshm_drv->pshm_rx_workqueue);
+
+ unregister_netdev(pshm_netdev);
+}
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 9d9e45394433..080574b0fff0 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -82,6 +82,14 @@ config CAN_FLEXCAN
---help---
Say Y here if you want to support for Freescale FlexCAN.
+config PCH_CAN
+ tristate "PCH CAN"
+ depends on CAN_DEV && PCI
+ ---help---
+ This driver is for PCH CAN of Topcliff which is an IOH for x86
+ embedded processor.
+ This driver can access CAN bus.
+
source "drivers/net/can/mscan/Kconfig"
source "drivers/net/can/sja1000/Kconfig"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 00575373bbd0..90af15a4f106 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -17,5 +17,6 @@ obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
obj-$(CONFIG_CAN_BFIN) += bfin_can.o
obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
+obj-$(CONFIG_PCH_CAN) += pch_can.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index 2d8bd86bc5e2..cee98fa668bd 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -2,7 +2,7 @@
* at91_can.c - CAN network driver for AT91 SoC CAN controller
*
* (C) 2007 by Hans J. Koch <hjk@linutronix.de>
- * (C) 2008, 2009 by Marc Kleine-Budde <kernel@pengutronix.de>
+ * (C) 2008, 2009, 2010 by Marc Kleine-Budde <kernel@pengutronix.de>
*
* This software may be distributed under the terms of the GNU General
* Public License ("GPL") version 2 as distributed in the 'COPYING'
@@ -40,7 +40,6 @@
#include <mach/board.h>
-#define DRV_NAME "at91_can"
#define AT91_NAPI_WEIGHT 12
/*
@@ -172,6 +171,7 @@ struct at91_priv {
};
static struct can_bittiming_const at91_bittiming_const = {
+ .name = KBUILD_MODNAME,
.tseg1_min = 4,
.tseg1_max = 16,
.tseg2_min = 2,
@@ -199,13 +199,13 @@ static inline int get_tx_echo_mb(const struct at91_priv *priv)
static inline u32 at91_read(const struct at91_priv *priv, enum at91_reg reg)
{
- return readl(priv->reg_base + reg);
+ return __raw_readl(priv->reg_base + reg);
}
static inline void at91_write(const struct at91_priv *priv, enum at91_reg reg,
u32 value)
{
- writel(value, priv->reg_base + reg);
+ __raw_writel(value, priv->reg_base + reg);
}
static inline void set_mb_mode_prio(const struct at91_priv *priv,
@@ -243,6 +243,12 @@ static void at91_setup_mailboxes(struct net_device *dev)
set_mb_mode(priv, i, AT91_MB_MODE_RX);
set_mb_mode(priv, AT91_MB_RX_LAST, AT91_MB_MODE_RX_OVRWR);
+ /* reset acceptance mask and id register */
+ for (i = AT91_MB_RX_FIRST; i <= AT91_MB_RX_LAST; i++) {
+ at91_write(priv, AT91_MAM(i), 0x0 );
+ at91_write(priv, AT91_MID(i), AT91_MID_MIDE);
+ }
+
/* The last 4 mailboxes are used for transmitting. */
for (i = AT91_MB_TX_FIRST; i <= AT91_MB_TX_LAST; i++)
set_mb_mode_prio(priv, i, AT91_MB_MODE_TX, 0);
@@ -257,18 +263,30 @@ static int at91_set_bittiming(struct net_device *dev)
const struct can_bittiming *bt = &priv->can.bittiming;
u32 reg_br;
- reg_br = ((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) << 24) |
- ((bt->brp - 1) << 16) | ((bt->sjw - 1) << 12) |
+ reg_br = ((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 << 24 : 0) |
+ ((bt->brp - 1) << 16) | ((bt->sjw - 1) << 12) |
((bt->prop_seg - 1) << 8) | ((bt->phase_seg1 - 1) << 4) |
((bt->phase_seg2 - 1) << 0);
- dev_info(dev->dev.parent, "writing AT91_BR: 0x%08x\n", reg_br);
+ netdev_info(dev, "writing AT91_BR: 0x%08x\n", reg_br);
at91_write(priv, AT91_BR, reg_br);
return 0;
}
+static int at91_get_berr_counter(const struct net_device *dev,
+ struct can_berr_counter *bec)
+{
+ const struct at91_priv *priv = netdev_priv(dev);
+ u32 reg_ecr = at91_read(priv, AT91_ECR);
+
+ bec->rxerr = reg_ecr & 0xff;
+ bec->txerr = reg_ecr >> 16;
+
+ return 0;
+}
+
static void at91_chip_start(struct net_device *dev)
{
struct at91_priv *priv = netdev_priv(dev);
@@ -281,6 +299,7 @@ static void at91_chip_start(struct net_device *dev)
reg_mr = at91_read(priv, AT91_MR);
at91_write(priv, AT91_MR, reg_mr & ~AT91_MR_CANEN);
+ at91_set_bittiming(dev);
at91_setup_mailboxes(dev);
at91_transceiver_switch(priv, 1);
@@ -350,8 +369,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(!(at91_read(priv, AT91_MSR(mb)) & AT91_MSR_MRDY))) {
netif_stop_queue(dev);
- dev_err(dev->dev.parent,
- "BUG! TX buffer full when queue awake!\n");
+ netdev_err(dev, "BUG! TX buffer full when queue awake!\n");
return NETDEV_TX_BUSY;
}
@@ -435,7 +453,7 @@ static void at91_rx_overflow_err(struct net_device *dev)
struct sk_buff *skb;
struct can_frame *cf;
- dev_dbg(dev->dev.parent, "RX buffer overflow\n");
+ netdev_dbg(dev, "RX buffer overflow\n");
stats->rx_over_errors++;
stats->rx_errors++;
@@ -480,6 +498,9 @@ static void at91_read_mb(struct net_device *dev, unsigned int mb,
*(u32 *)(cf->data + 0) = at91_read(priv, AT91_MDL(mb));
*(u32 *)(cf->data + 4) = at91_read(priv, AT91_MDH(mb));
+ /* allow RX of extended frames */
+ at91_write(priv, AT91_MID(mb), AT91_MID_MIDE);
+
if (unlikely(mb == AT91_MB_RX_LAST && reg_msr & AT91_MSR_MMI))
at91_rx_overflow_err(dev);
}
@@ -565,8 +586,8 @@ static int at91_poll_rx(struct net_device *dev, int quota)
if (priv->rx_next > AT91_MB_RX_LOW_LAST &&
reg_sr & AT91_MB_RX_LOW_MASK)
- dev_info(dev->dev.parent,
- "order of incoming frames cannot be guaranteed\n");
+ netdev_info(dev,
+ "order of incoming frames cannot be guaranteed\n");
again:
for (mb = find_next_bit(addr, AT91_MB_RX_NUM, priv->rx_next);
@@ -604,7 +625,7 @@ static void at91_poll_err_frame(struct net_device *dev,
/* CRC error */
if (reg_sr & AT91_IRQ_CERR) {
- dev_dbg(dev->dev.parent, "CERR irq\n");
+ netdev_dbg(dev, "CERR irq\n");
dev->stats.rx_errors++;
priv->can.can_stats.bus_error++;
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
@@ -612,7 +633,7 @@ static void at91_poll_err_frame(struct net_device *dev,
/* Stuffing Error */
if (reg_sr & AT91_IRQ_SERR) {
- dev_dbg(dev->dev.parent, "SERR irq\n");
+ netdev_dbg(dev, "SERR irq\n");
dev->stats.rx_errors++;
priv->can.can_stats.bus_error++;
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
@@ -621,14 +642,14 @@ static void at91_poll_err_frame(struct net_device *dev,
/* Acknowledgement Error */
if (reg_sr & AT91_IRQ_AERR) {
- dev_dbg(dev->dev.parent, "AERR irq\n");
+ netdev_dbg(dev, "AERR irq\n");
dev->stats.tx_errors++;
cf->can_id |= CAN_ERR_ACK;
}
/* Form error */
if (reg_sr & AT91_IRQ_FERR) {
- dev_dbg(dev->dev.parent, "FERR irq\n");
+ netdev_dbg(dev, "FERR irq\n");
dev->stats.rx_errors++;
priv->can.can_stats.bus_error++;
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
@@ -637,7 +658,7 @@ static void at91_poll_err_frame(struct net_device *dev,
/* Bit Error */
if (reg_sr & AT91_IRQ_BERR) {
- dev_dbg(dev->dev.parent, "BERR irq\n");
+ netdev_dbg(dev, "BERR irq\n");
dev->stats.tx_errors++;
priv->can.can_stats.bus_error++;
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
@@ -755,12 +776,10 @@ static void at91_irq_err_state(struct net_device *dev,
struct can_frame *cf, enum can_state new_state)
{
struct at91_priv *priv = netdev_priv(dev);
- u32 reg_idr, reg_ier, reg_ecr;
- u8 tec, rec;
+ u32 reg_idr = 0, reg_ier = 0;
+ struct can_berr_counter bec;
- reg_ecr = at91_read(priv, AT91_ECR);
- rec = reg_ecr & 0xff;
- tec = reg_ecr >> 16;
+ at91_get_berr_counter(dev, &bec);
switch (priv->can.state) {
case CAN_STATE_ERROR_ACTIVE:
@@ -771,11 +790,11 @@ static void at91_irq_err_state(struct net_device *dev,
*/
if (new_state >= CAN_STATE_ERROR_WARNING &&
new_state <= CAN_STATE_BUS_OFF) {
- dev_dbg(dev->dev.parent, "Error Warning IRQ\n");
+ netdev_dbg(dev, "Error Warning IRQ\n");
priv->can.can_stats.error_warning++;
cf->can_id |= CAN_ERR_CRTL;
- cf->data[1] = (tec > rec) ?
+ cf->data[1] = (bec.txerr > bec.rxerr) ?
CAN_ERR_CRTL_TX_WARNING :
CAN_ERR_CRTL_RX_WARNING;
}
@@ -787,11 +806,11 @@ static void at91_irq_err_state(struct net_device *dev,
*/
if (new_state >= CAN_STATE_ERROR_PASSIVE &&
new_state <= CAN_STATE_BUS_OFF) {
- dev_dbg(dev->dev.parent, "Error Passive IRQ\n");
+ netdev_dbg(dev, "Error Passive IRQ\n");
priv->can.can_stats.error_passive++;
cf->can_id |= CAN_ERR_CRTL;
- cf->data[1] = (tec > rec) ?
+ cf->data[1] = (bec.txerr > bec.rxerr) ?
CAN_ERR_CRTL_TX_PASSIVE :
CAN_ERR_CRTL_RX_PASSIVE;
}
@@ -804,7 +823,7 @@ static void at91_irq_err_state(struct net_device *dev,
if (new_state <= CAN_STATE_ERROR_PASSIVE) {
cf->can_id |= CAN_ERR_RESTARTED;
- dev_dbg(dev->dev.parent, "restarted\n");
+ netdev_dbg(dev, "restarted\n");
priv->can.can_stats.restarts++;
netif_carrier_on(dev);
@@ -825,7 +844,7 @@ static void at91_irq_err_state(struct net_device *dev,
* circumstances. so just enable AT91_IRQ_ERRP, thus
* the "fallthrough"
*/
- dev_dbg(dev->dev.parent, "Error Active\n");
+ netdev_dbg(dev, "Error Active\n");
cf->can_id |= CAN_ERR_PROT;
cf->data[2] = CAN_ERR_PROT_ACTIVE;
case CAN_STATE_ERROR_WARNING: /* fallthrough */
@@ -843,7 +862,7 @@ static void at91_irq_err_state(struct net_device *dev,
cf->can_id |= CAN_ERR_BUSOFF;
- dev_dbg(dev->dev.parent, "bus-off\n");
+ netdev_dbg(dev, "bus-off\n");
netif_carrier_off(dev);
priv->can.can_stats.bus_off++;
@@ -881,7 +900,7 @@ static void at91_irq_err(struct net_device *dev)
else if (likely(reg_sr & AT91_IRQ_ERRA))
new_state = CAN_STATE_ERROR_ACTIVE;
else {
- dev_err(dev->dev.parent, "BUG! hardware in undefined state\n");
+ netdev_err(dev, "BUG! hardware in undefined state\n");
return;
}
@@ -1018,7 +1037,7 @@ static const struct net_device_ops at91_netdev_ops = {
.ndo_start_xmit = at91_start_xmit,
};
-static int __init at91_can_probe(struct platform_device *pdev)
+static int __devinit at91_can_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct at91_priv *priv;
@@ -1067,8 +1086,8 @@ static int __init at91_can_probe(struct platform_device *pdev)
priv = netdev_priv(dev);
priv->can.clock.freq = clk_get_rate(clk);
priv->can.bittiming_const = &at91_bittiming_const;
- priv->can.do_set_bittiming = at91_set_bittiming;
priv->can.do_set_mode = at91_set_mode;
+ priv->can.do_get_berr_counter = at91_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
priv->reg_base = addr;
priv->dev = dev;
@@ -1092,7 +1111,7 @@ static int __init at91_can_probe(struct platform_device *pdev)
return 0;
exit_free:
- free_netdev(dev);
+ free_candev(dev);
exit_iounmap:
iounmap(addr);
exit_release:
@@ -1113,8 +1132,6 @@ static int __devexit at91_can_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
- free_netdev(dev);
-
iounmap(priv->reg_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1122,6 +1139,8 @@ static int __devexit at91_can_remove(struct platform_device *pdev)
clk_put(priv->clk);
+ free_candev(dev);
+
return 0;
}
@@ -1129,21 +1148,19 @@ static struct platform_driver at91_can_driver = {
.probe = at91_can_probe,
.remove = __devexit_p(at91_can_remove),
.driver = {
- .name = DRV_NAME,
+ .name = KBUILD_MODNAME,
.owner = THIS_MODULE,
},
};
static int __init at91_can_module_init(void)
{
- printk(KERN_INFO "%s netdevice driver\n", DRV_NAME);
return platform_driver_register(&at91_can_driver);
}
static void __exit at91_can_module_exit(void)
{
platform_driver_unregister(&at91_can_driver);
- printk(KERN_INFO "%s: driver removed\n", DRV_NAME);
}
module_init(at91_can_module_init);
@@ -1151,4 +1168,4 @@ module_exit(at91_can_module_exit);
MODULE_AUTHOR("Marc Kleine-Budde <mkl@pengutronix.de>");
MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION(DRV_NAME " CAN netdevice driver");
+MODULE_DESCRIPTION(KBUILD_MODNAME " CAN netdevice driver");
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index ef443a090ba7..d4990568baee 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -992,7 +992,6 @@ static int __devexit flexcan_remove(struct platform_device *pdev)
unregister_flexcandev(dev);
platform_set_drvdata(pdev, NULL);
- free_candev(dev);
iounmap(priv->base);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1000,6 +999,8 @@ static int __devexit flexcan_remove(struct platform_device *pdev)
clk_put(priv->clk);
+ free_candev(dev);
+
return 0;
}
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
index b11a0cb5ed81..7ab534aee452 100644
--- a/drivers/net/can/mcp251x.c
+++ b/drivers/net/can/mcp251x.c
@@ -38,14 +38,14 @@
* static struct mcp251x_platform_data mcp251x_info = {
* .oscillator_frequency = 8000000,
* .board_specific_setup = &mcp251x_setup,
- * .model = CAN_MCP251X_MCP2510,
* .power_enable = mcp251x_power_enable,
* .transceiver_enable = NULL,
* };
*
* static struct spi_board_info spi_board_info[] = {
* {
- * .modalias = "mcp251x",
+ * .modalias = "mcp2510",
+ * // or "mcp2515" depending on your controller
* .platform_data = &mcp251x_info,
* .irq = IRQ_EINT13,
* .max_speed_hz = 2*1000*1000,
@@ -125,6 +125,9 @@
# define CANINTF_TX0IF 0x04
# define CANINTF_RX1IF 0x02
# define CANINTF_RX0IF 0x01
+# define CANINTF_RX (CANINTF_RX0IF | CANINTF_RX1IF)
+# define CANINTF_TX (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)
+# define CANINTF_ERR (CANINTF_ERRIF)
#define EFLG 0x2d
# define EFLG_EWARN 0x01
# define EFLG_RXWAR 0x02
@@ -166,6 +169,7 @@
# define RXBSIDH_SHIFT 3
#define RXBSIDL(n) (((n) * 0x10) + 0x60 + RXBSIDL_OFF)
# define RXBSIDL_IDE 0x08
+# define RXBSIDL_SRR 0x10
# define RXBSIDL_EID 3
# define RXBSIDL_SHIFT 5
#define RXBEID8(n) (((n) * 0x10) + 0x60 + RXBEID8_OFF)
@@ -222,10 +226,16 @@ static struct can_bittiming_const mcp251x_bittiming_const = {
.brp_inc = 1,
};
+enum mcp251x_model {
+ CAN_MCP251X_MCP2510 = 0x2510,
+ CAN_MCP251X_MCP2515 = 0x2515,
+};
+
struct mcp251x_priv {
struct can_priv can;
struct net_device *net;
struct spi_device *spi;
+ enum mcp251x_model model;
struct mutex mcp_lock; /* SPI device lock */
@@ -250,6 +260,16 @@ struct mcp251x_priv {
int restart_tx;
};
+#define MCP251X_IS(_model) \
+static inline int mcp251x_is_##_model(struct spi_device *spi) \
+{ \
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); \
+ return priv->model == CAN_MCP251X_MCP##_model; \
+}
+
+MCP251X_IS(2510);
+MCP251X_IS(2515);
+
static void mcp251x_clean(struct net_device *net)
{
struct mcp251x_priv *priv = netdev_priv(net);
@@ -319,6 +339,20 @@ static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
return val;
}
+static void mcp251x_read_2regs(struct spi_device *spi, uint8_t reg,
+ uint8_t *v1, uint8_t *v2)
+{
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+
+ priv->spi_tx_buf[0] = INSTRUCTION_READ;
+ priv->spi_tx_buf[1] = reg;
+
+ mcp251x_spi_trans(spi, 4);
+
+ *v1 = priv->spi_rx_buf[2];
+ *v2 = priv->spi_rx_buf[3];
+}
+
static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
{
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
@@ -346,10 +380,9 @@ static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
int len, int tx_buf_idx)
{
- struct mcp251x_platform_data *pdata = spi->dev.platform_data;
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
- if (pdata->model == CAN_MCP251X_MCP2510) {
+ if (mcp251x_is_2510(spi)) {
int i;
for (i = 1; i < TXBDAT_OFF + len; i++)
@@ -392,9 +425,8 @@ static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf,
int buf_idx)
{
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
- struct mcp251x_platform_data *pdata = spi->dev.platform_data;
- if (pdata->model == CAN_MCP251X_MCP2510) {
+ if (mcp251x_is_2510(spi)) {
int i, len;
for (i = 1; i < RXBDAT_OFF; i++)
@@ -444,6 +476,8 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
frame->can_id =
(buf[RXBSIDH_OFF] << RXBSIDH_SHIFT) |
(buf[RXBSIDL_OFF] >> RXBSIDL_SHIFT);
+ if (buf[RXBSIDL_OFF] & RXBSIDL_SRR)
+ frame->can_id |= CAN_RTR_FLAG;
}
/* Data length */
frame->can_dlc = get_can_dlc(buf[RXBDLC_OFF] & RXBDLC_LEN_MASK);
@@ -451,7 +485,7 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
priv->net->stats.rx_packets++;
priv->net->stats.rx_bytes += frame->can_dlc;
- netif_rx(skb);
+ netif_rx_ni(skb);
}
static void mcp251x_hw_sleep(struct spi_device *spi)
@@ -674,9 +708,9 @@ static void mcp251x_error_skb(struct net_device *net, int can_id, int data1)
skb = alloc_can_err_skb(net, &frame);
if (skb) {
- frame->can_id = can_id;
+ frame->can_id |= can_id;
frame->data[1] = data1;
- netif_rx(skb);
+ netif_rx_ni(skb);
} else {
dev_err(&net->dev,
"cannot allocate error skb\n");
@@ -754,24 +788,42 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
mutex_lock(&priv->mcp_lock);
while (!priv->force_quit) {
enum can_state new_state;
- u8 intf = mcp251x_read_reg(spi, CANINTF);
- u8 eflag;
+ u8 intf, eflag;
+ u8 clear_intf = 0;
int can_id = 0, data1 = 0;
+ mcp251x_read_2regs(spi, CANINTF, &intf, &eflag);
+
+ /* mask out flags we don't care about */
+ intf &= CANINTF_RX | CANINTF_TX | CANINTF_ERR;
+
+ /* receive buffer 0 */
if (intf & CANINTF_RX0IF) {
mcp251x_hw_rx(spi, 0);
- /* Free one buffer ASAP */
- mcp251x_write_bits(spi, CANINTF, intf & CANINTF_RX0IF,
- 0x00);
+ /*
+ * Free one buffer ASAP
+ * (The MCP2515 does this automatically.)
+ */
+ if (mcp251x_is_2510(spi))
+ mcp251x_write_bits(spi, CANINTF, CANINTF_RX0IF, 0x00);
}
- if (intf & CANINTF_RX1IF)
+ /* receive buffer 1 */
+ if (intf & CANINTF_RX1IF) {
mcp251x_hw_rx(spi, 1);
+ /* the MCP2515 does this automatically */
+ if (mcp251x_is_2510(spi))
+ clear_intf |= CANINTF_RX1IF;
+ }
- mcp251x_write_bits(spi, CANINTF, intf, 0x00);
+ /* any error or tx interrupt we need to clear? */
+ if (intf & (CANINTF_ERR | CANINTF_TX))
+ clear_intf |= intf & (CANINTF_ERR | CANINTF_TX);
+ if (clear_intf)
+ mcp251x_write_bits(spi, CANINTF, clear_intf, 0x00);
- eflag = mcp251x_read_reg(spi, EFLG);
- mcp251x_write_reg(spi, EFLG, 0x00);
+ if (eflag)
+ mcp251x_write_bits(spi, EFLG, eflag, 0x00);
/* Update can state */
if (eflag & EFLG_TXBO) {
@@ -816,10 +868,14 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
if (intf & CANINTF_ERRIF) {
/* Handle overflow counters */
if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
- if (eflag & EFLG_RX0OVR)
+ if (eflag & EFLG_RX0OVR) {
net->stats.rx_over_errors++;
- if (eflag & EFLG_RX1OVR)
+ net->stats.rx_errors++;
+ }
+ if (eflag & EFLG_RX1OVR) {
net->stats.rx_over_errors++;
+ net->stats.rx_errors++;
+ }
can_id |= CAN_ERR_CRTL;
data1 |= CAN_ERR_CRTL_RX_OVERFLOW;
}
@@ -838,7 +894,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
if (intf == 0)
break;
- if (intf & (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)) {
+ if (intf & CANINTF_TX) {
net->stats.tx_packets++;
net->stats.tx_bytes += priv->tx_len - 1;
if (priv->tx_len) {
@@ -921,16 +977,12 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
struct net_device *net;
struct mcp251x_priv *priv;
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
- int model = spi_get_device_id(spi)->driver_data;
int ret = -ENODEV;
if (!pdata)
/* Platform data is required for osc freq */
goto error_out;
- if (model)
- pdata->model = model;
-
/* Allocate can/net device */
net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX);
if (!net) {
@@ -947,6 +999,7 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
priv->can.clock.freq = pdata->oscillator_frequency / 2;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
+ priv->model = spi_get_device_id(spi)->driver_data;
priv->net = net;
dev_set_drvdata(&spi->dev, priv);
@@ -1120,8 +1173,7 @@ static int mcp251x_can_resume(struct spi_device *spi)
#define mcp251x_can_resume NULL
#endif
-static struct spi_device_id mcp251x_id_table[] = {
- { "mcp251x", 0 /* Use pdata.model */ },
+static const struct spi_device_id mcp251x_id_table[] = {
{ "mcp2510", CAN_MCP251X_MCP2510 },
{ "mcp2515", CAN_MCP251X_MCP2515 },
{ },
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index b1bdc909090f..312b9c8f4f3b 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -143,12 +143,12 @@ static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev,
np_clock = of_find_matching_node(NULL, mpc512x_clock_ids);
if (!np_clock) {
dev_err(&ofdev->dev, "couldn't find clock node\n");
- return -ENODEV;
+ return 0;
}
clockctl = of_iomap(np_clock, 0);
if (!clockctl) {
dev_err(&ofdev->dev, "couldn't map clock registers\n");
- return 0;
+ goto exit_put;
}
/* Determine the MSCAN device index from the physical address */
@@ -233,9 +233,9 @@ static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev,
clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv);
exit_unmap:
- of_node_put(np_clock);
iounmap(clockctl);
-
+exit_put:
+ of_node_put(np_clock);
return freq;
}
#else /* !CONFIG_PPC_MPC512x */
diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
new file mode 100644
index 000000000000..55ec324caaf4
--- /dev/null
+++ b/drivers/net/can/pch_can.c
@@ -0,0 +1,1463 @@
+/*
+ * Copyright (C) 1999 - 2010 Intel Corporation.
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+#define MAX_MSG_OBJ 32
+#define MSG_OBJ_RX 0 /* The receive message object flag. */
+#define MSG_OBJ_TX 1 /* The transmit message object flag. */
+
+#define ENABLE 1 /* The enable flag */
+#define DISABLE 0 /* The disable flag */
+#define CAN_CTRL_INIT 0x0001 /* The INIT bit of CANCONT register. */
+#define CAN_CTRL_IE 0x0002 /* The IE bit of CAN control register */
+#define CAN_CTRL_IE_SIE_EIE 0x000e
+#define CAN_CTRL_CCE 0x0040
+#define CAN_CTRL_OPT 0x0080 /* The OPT bit of CANCONT register. */
+#define CAN_OPT_SILENT 0x0008 /* The Silent bit of CANOPT reg. */
+#define CAN_OPT_LBACK 0x0010 /* The LoopBack bit of CANOPT reg. */
+#define CAN_CMASK_RX_TX_SET 0x00f3
+#define CAN_CMASK_RX_TX_GET 0x0073
+#define CAN_CMASK_ALL 0xff
+#define CAN_CMASK_RDWR 0x80
+#define CAN_CMASK_ARB 0x20
+#define CAN_CMASK_CTRL 0x10
+#define CAN_CMASK_MASK 0x40
+#define CAN_CMASK_NEWDAT 0x04
+#define CAN_CMASK_CLRINTPND 0x08
+
+#define CAN_IF_MCONT_NEWDAT 0x8000
+#define CAN_IF_MCONT_INTPND 0x2000
+#define CAN_IF_MCONT_UMASK 0x1000
+#define CAN_IF_MCONT_TXIE 0x0800
+#define CAN_IF_MCONT_RXIE 0x0400
+#define CAN_IF_MCONT_RMTEN 0x0200
+#define CAN_IF_MCONT_TXRQXT 0x0100
+#define CAN_IF_MCONT_EOB 0x0080
+#define CAN_IF_MCONT_DLC 0x000f
+#define CAN_IF_MCONT_MSGLOST 0x4000
+#define CAN_MASK2_MDIR_MXTD 0xc000
+#define CAN_ID2_DIR 0x2000
+#define CAN_ID_MSGVAL 0x8000
+
+#define CAN_STATUS_INT 0x8000
+#define CAN_IF_CREQ_BUSY 0x8000
+#define CAN_ID2_XTD 0x4000
+
+#define CAN_REC 0x00007f00
+#define CAN_TEC 0x000000ff
+
+#define PCH_RX_OK 0x00000010
+#define PCH_TX_OK 0x00000008
+#define PCH_BUS_OFF 0x00000080
+#define PCH_EWARN 0x00000040
+#define PCH_EPASSIV 0x00000020
+#define PCH_LEC0 0x00000001
+#define PCH_LEC1 0x00000002
+#define PCH_LEC2 0x00000004
+#define PCH_LEC_ALL (PCH_LEC0 | PCH_LEC1 | PCH_LEC2)
+#define PCH_STUF_ERR PCH_LEC0
+#define PCH_FORM_ERR PCH_LEC1
+#define PCH_ACK_ERR (PCH_LEC0 | PCH_LEC1)
+#define PCH_BIT1_ERR PCH_LEC2
+#define PCH_BIT0_ERR (PCH_LEC0 | PCH_LEC2)
+#define PCH_CRC_ERR (PCH_LEC1 | PCH_LEC2)
+
+/* bit position of certain controller bits. */
+#define BIT_BITT_BRP 0
+#define BIT_BITT_SJW 6
+#define BIT_BITT_TSEG1 8
+#define BIT_BITT_TSEG2 12
+#define BIT_IF1_MCONT_RXIE 10
+#define BIT_IF2_MCONT_TXIE 11
+#define BIT_BRPE_BRPE 6
+#define BIT_ES_TXERRCNT 0
+#define BIT_ES_RXERRCNT 8
+#define MSK_BITT_BRP 0x3f
+#define MSK_BITT_SJW 0xc0
+#define MSK_BITT_TSEG1 0xf00
+#define MSK_BITT_TSEG2 0x7000
+#define MSK_BRPE_BRPE 0x3c0
+#define MSK_BRPE_GET 0x0f
+#define MSK_CTRL_IE_SIE_EIE 0x07
+#define MSK_MCONT_TXIE 0x08
+#define MSK_MCONT_RXIE 0x10
+#define PCH_CAN_NO_TX_BUFF 1
+#define COUNTER_LIMIT 10
+
+#define PCH_CAN_CLK 50000000 /* 50MHz */
+
+/* Define the number of message object.
+ * PCH CAN communications are done via Message RAM.
+ * The Message RAM consists of 32 message objects. */
+#define PCH_RX_OBJ_NUM 26 /* 1~ PCH_RX_OBJ_NUM is Rx*/
+#define PCH_TX_OBJ_NUM 6 /* PCH_RX_OBJ_NUM is RX ~ Tx*/
+#define PCH_OBJ_NUM (PCH_TX_OBJ_NUM + PCH_RX_OBJ_NUM)
+
+#define PCH_FIFO_THRESH 16
+
+enum pch_can_mode {
+ PCH_CAN_ENABLE,
+ PCH_CAN_DISABLE,
+ PCH_CAN_ALL,
+ PCH_CAN_NONE,
+ PCH_CAN_STOP,
+ PCH_CAN_RUN
+};
+
+struct pch_can_regs {
+ u32 cont;
+ u32 stat;
+ u32 errc;
+ u32 bitt;
+ u32 intr;
+ u32 opt;
+ u32 brpe;
+ u32 reserve1;
+ u32 if1_creq;
+ u32 if1_cmask;
+ u32 if1_mask1;
+ u32 if1_mask2;
+ u32 if1_id1;
+ u32 if1_id2;
+ u32 if1_mcont;
+ u32 if1_dataa1;
+ u32 if1_dataa2;
+ u32 if1_datab1;
+ u32 if1_datab2;
+ u32 reserve2;
+ u32 reserve3[12];
+ u32 if2_creq;
+ u32 if2_cmask;
+ u32 if2_mask1;
+ u32 if2_mask2;
+ u32 if2_id1;
+ u32 if2_id2;
+ u32 if2_mcont;
+ u32 if2_dataa1;
+ u32 if2_dataa2;
+ u32 if2_datab1;
+ u32 if2_datab2;
+ u32 reserve4;
+ u32 reserve5[20];
+ u32 treq1;
+ u32 treq2;
+ u32 reserve6[2];
+ u32 reserve7[56];
+ u32 reserve8[3];
+ u32 srst;
+};
+
+struct pch_can_priv {
+ struct can_priv can;
+ unsigned int can_num;
+ struct pci_dev *dev;
+ unsigned int tx_enable[MAX_MSG_OBJ];
+ unsigned int rx_enable[MAX_MSG_OBJ];
+ unsigned int rx_link[MAX_MSG_OBJ];
+ unsigned int int_enables;
+ unsigned int int_stat;
+ struct net_device *ndev;
+ spinlock_t msgif_reg_lock; /* Message Interface Registers Access Lock*/
+ unsigned int msg_obj[MAX_MSG_OBJ];
+ struct pch_can_regs __iomem *regs;
+ struct napi_struct napi;
+ unsigned int tx_obj; /* Point next Tx Obj index */
+ unsigned int use_msi;
+};
+
+static struct can_bittiming_const pch_can_bittiming_const = {
+ .name = KBUILD_MODNAME,
+ .tseg1_min = 1,
+ .tseg1_max = 16,
+ .tseg2_min = 1,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 1024, /* 6bit + extended 4bit */
+ .brp_inc = 1,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(pch_pci_tbl) = {
+ {PCI_VENDOR_ID_INTEL, 0x8818, PCI_ANY_ID, PCI_ANY_ID,},
+ {0,}
+};
+MODULE_DEVICE_TABLE(pci, pch_pci_tbl);
+
+static inline void pch_can_bit_set(u32 *addr, u32 mask)
+{
+ iowrite32(ioread32(addr) | mask, addr);
+}
+
+static inline void pch_can_bit_clear(u32 *addr, u32 mask)
+{
+ iowrite32(ioread32(addr) & ~mask, addr);
+}
+
+static void pch_can_set_run_mode(struct pch_can_priv *priv,
+ enum pch_can_mode mode)
+{
+ switch (mode) {
+ case PCH_CAN_RUN:
+ pch_can_bit_clear(&priv->regs->cont, CAN_CTRL_INIT);
+ break;
+
+ case PCH_CAN_STOP:
+ pch_can_bit_set(&priv->regs->cont, CAN_CTRL_INIT);
+ break;
+
+ default:
+ dev_err(&priv->ndev->dev, "%s -> Invalid Mode.\n", __func__);
+ break;
+ }
+}
+
+static void pch_can_set_optmode(struct pch_can_priv *priv)
+{
+ u32 reg_val = ioread32(&priv->regs->opt);
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ reg_val |= CAN_OPT_SILENT;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
+ reg_val |= CAN_OPT_LBACK;
+
+ pch_can_bit_set(&priv->regs->cont, CAN_CTRL_OPT);
+ iowrite32(reg_val, &priv->regs->opt);
+}
+
+static void pch_can_set_int_custom(struct pch_can_priv *priv)
+{
+ /* Clearing the IE, SIE and EIE bits of Can control register. */
+ pch_can_bit_clear(&priv->regs->cont, CAN_CTRL_IE_SIE_EIE);
+
+ /* Appropriately setting them. */
+ pch_can_bit_set(&priv->regs->cont,
+ ((priv->int_enables & MSK_CTRL_IE_SIE_EIE) << 1));
+}
+
+/* This function retrieves interrupt enabled for the CAN device. */
+static void pch_can_get_int_enables(struct pch_can_priv *priv, u32 *enables)
+{
+ /* Obtaining the status of IE, SIE and EIE interrupt bits. */
+ *enables = ((ioread32(&priv->regs->cont) & CAN_CTRL_IE_SIE_EIE) >> 1);
+}
+
+static void pch_can_set_int_enables(struct pch_can_priv *priv,
+ enum pch_can_mode interrupt_no)
+{
+ switch (interrupt_no) {
+ case PCH_CAN_ENABLE:
+ pch_can_bit_set(&priv->regs->cont, CAN_CTRL_IE);
+ break;
+
+ case PCH_CAN_DISABLE:
+ pch_can_bit_clear(&priv->regs->cont, CAN_CTRL_IE);
+ break;
+
+ case PCH_CAN_ALL:
+ pch_can_bit_set(&priv->regs->cont, CAN_CTRL_IE_SIE_EIE);
+ break;
+
+ case PCH_CAN_NONE:
+ pch_can_bit_clear(&priv->regs->cont, CAN_CTRL_IE_SIE_EIE);
+ break;
+
+ default:
+ dev_err(&priv->ndev->dev, "Invalid interrupt number.\n");
+ break;
+ }
+}
+
+static void pch_can_check_if_busy(u32 __iomem *creq_addr, u32 num)
+{
+ u32 counter = COUNTER_LIMIT;
+ u32 ifx_creq;
+
+ iowrite32(num, creq_addr);
+ while (counter) {
+ ifx_creq = ioread32(creq_addr) & CAN_IF_CREQ_BUSY;
+ if (!ifx_creq)
+ break;
+ counter--;
+ udelay(1);
+ }
+ if (!counter)
+ pr_err("%s:IF1 BUSY Flag is set forever.\n", __func__);
+}
+
+static void pch_can_set_rx_enable(struct pch_can_priv *priv, u32 buff_num,
+ u32 set)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->msgif_reg_lock, flags);
+ /* Reading the receive buffer data from RAM to Interface1 registers */
+ iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if1_cmask);
+ pch_can_check_if_busy(&priv->regs->if1_creq, buff_num);
+
+ /* Setting the IF1MASK1 register to access MsgVal and RxIE bits */
+ iowrite32(CAN_CMASK_RDWR | CAN_CMASK_ARB | CAN_CMASK_CTRL,
+ &priv->regs->if1_cmask);
+
+ if (set == ENABLE) {
+ /* Setting the MsgVal and RxIE bits */
+ pch_can_bit_set(&priv->regs->if1_mcont, CAN_IF_MCONT_RXIE);
+ pch_can_bit_set(&priv->regs->if1_id2, CAN_ID_MSGVAL);
+
+ } else if (set == DISABLE) {
+ /* Resetting the MsgVal and RxIE bits */
+ pch_can_bit_clear(&priv->regs->if1_mcont, CAN_IF_MCONT_RXIE);
+ pch_can_bit_clear(&priv->regs->if1_id2, CAN_ID_MSGVAL);
+ }
+
+ pch_can_check_if_busy(&priv->regs->if1_creq, buff_num);
+ spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
+}
+
+static void pch_can_rx_enable_all(struct pch_can_priv *priv)
+{
+ int i;
+
+ /* Traversing to obtain the object configured as receivers. */
+ for (i = 0; i < PCH_OBJ_NUM; i++) {
+ if (priv->msg_obj[i] == MSG_OBJ_RX)
+ pch_can_set_rx_enable(priv, i + 1, ENABLE);
+ }
+}
+
+static void pch_can_rx_disable_all(struct pch_can_priv *priv)
+{
+ int i;
+
+ /* Traversing to obtain the object configured as receivers. */
+ for (i = 0; i < PCH_OBJ_NUM; i++) {
+ if (priv->msg_obj[i] == MSG_OBJ_RX)
+ pch_can_set_rx_enable(priv, i + 1, DISABLE);
+ }
+}
+
+static void pch_can_set_tx_enable(struct pch_can_priv *priv, u32 buff_num,
+ u32 set)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->msgif_reg_lock, flags);
+ /* Reading the Msg buffer from Message RAM to Interface2 registers. */
+ iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if2_cmask);
+ pch_can_check_if_busy(&priv->regs->if2_creq, buff_num);
+
+ /* Setting the IF2CMASK register for accessing the
+ MsgVal and TxIE bits */
+ iowrite32(CAN_CMASK_RDWR | CAN_CMASK_ARB | CAN_CMASK_CTRL,
+ &priv->regs->if2_cmask);
+
+ if (set == ENABLE) {
+ /* Setting the MsgVal and TxIE bits */
+ pch_can_bit_set(&priv->regs->if2_mcont, CAN_IF_MCONT_TXIE);
+ pch_can_bit_set(&priv->regs->if2_id2, CAN_ID_MSGVAL);
+ } else if (set == DISABLE) {
+ /* Resetting the MsgVal and TxIE bits. */
+ pch_can_bit_clear(&priv->regs->if2_mcont, CAN_IF_MCONT_TXIE);
+ pch_can_bit_clear(&priv->regs->if2_id2, CAN_ID_MSGVAL);
+ }
+
+ pch_can_check_if_busy(&priv->regs->if2_creq, buff_num);
+ spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
+}
+
+static void pch_can_tx_enable_all(struct pch_can_priv *priv)
+{
+ int i;
+
+ /* Traversing to obtain the object configured as transmit object. */
+ for (i = 0; i < PCH_OBJ_NUM; i++) {
+ if (priv->msg_obj[i] == MSG_OBJ_TX)
+ pch_can_set_tx_enable(priv, i + 1, ENABLE);
+ }
+}
+
+static void pch_can_tx_disable_all(struct pch_can_priv *priv)
+{
+ int i;
+
+ /* Traversing to obtain the object configured as transmit object. */
+ for (i = 0; i < PCH_OBJ_NUM; i++) {
+ if (priv->msg_obj[i] == MSG_OBJ_TX)
+ pch_can_set_tx_enable(priv, i + 1, DISABLE);
+ }
+}
+
+static void pch_can_get_rx_enable(struct pch_can_priv *priv, u32 buff_num,
+ u32 *enable)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->msgif_reg_lock, flags);
+ iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if1_cmask);
+ pch_can_check_if_busy(&priv->regs->if1_creq, buff_num);
+
+ if (((ioread32(&priv->regs->if1_id2)) & CAN_ID_MSGVAL) &&
+ ((ioread32(&priv->regs->if1_mcont)) &
+ CAN_IF_MCONT_RXIE))
+ *enable = ENABLE;
+ else
+ *enable = DISABLE;
+ spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
+}
+
+static void pch_can_get_tx_enable(struct pch_can_priv *priv, u32 buff_num,
+ u32 *enable)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->msgif_reg_lock, flags);
+ iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if2_cmask);
+ pch_can_check_if_busy(&priv->regs->if2_creq, buff_num);
+
+ if (((ioread32(&priv->regs->if2_id2)) & CAN_ID_MSGVAL) &&
+ ((ioread32(&priv->regs->if2_mcont)) &
+ CAN_IF_MCONT_TXIE)) {
+ *enable = ENABLE;
+ } else {
+ *enable = DISABLE;
+ }
+ spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
+}
+
+static int pch_can_int_pending(struct pch_can_priv *priv)
+{
+ return ioread32(&priv->regs->intr) & 0xffff;
+}
+
+static void pch_can_set_rx_buffer_link(struct pch_can_priv *priv,
+ u32 buffer_num, u32 set)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->msgif_reg_lock, flags);
+ iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if1_cmask);
+ pch_can_check_if_busy(&priv->regs->if1_creq, buffer_num);
+ iowrite32(CAN_CMASK_RDWR | CAN_CMASK_CTRL, &priv->regs->if1_cmask);
+ if (set == ENABLE)
+ pch_can_bit_clear(&priv->regs->if1_mcont, CAN_IF_MCONT_EOB);
+ else
+ pch_can_bit_set(&priv->regs->if1_mcont, CAN_IF_MCONT_EOB);
+
+ pch_can_check_if_busy(&priv->regs->if1_creq, buffer_num);
+ spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
+}
+
+static void pch_can_get_rx_buffer_link(struct pch_can_priv *priv,
+ u32 buffer_num, u32 *link)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->msgif_reg_lock, flags);
+ iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if1_cmask);
+ pch_can_check_if_busy(&priv->regs->if1_creq, buffer_num);
+
+ if (ioread32(&priv->regs->if1_mcont) & CAN_IF_MCONT_EOB)
+ *link = DISABLE;
+ else
+ *link = ENABLE;
+ spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
+}
+
+static void pch_can_clear_buffers(struct pch_can_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < PCH_RX_OBJ_NUM; i++) {
+ iowrite32(CAN_CMASK_RX_TX_SET, &priv->regs->if1_cmask);
+ iowrite32(0xffff, &priv->regs->if1_mask1);
+ iowrite32(0xffff, &priv->regs->if1_mask2);
+ iowrite32(0x0, &priv->regs->if1_id1);
+ iowrite32(0x0, &priv->regs->if1_id2);
+ iowrite32(0x0, &priv->regs->if1_mcont);
+ iowrite32(0x0, &priv->regs->if1_dataa1);
+ iowrite32(0x0, &priv->regs->if1_dataa2);
+ iowrite32(0x0, &priv->regs->if1_datab1);
+ iowrite32(0x0, &priv->regs->if1_datab2);
+ iowrite32(CAN_CMASK_RDWR | CAN_CMASK_MASK |
+ CAN_CMASK_ARB | CAN_CMASK_CTRL,
+ &priv->regs->if1_cmask);
+ pch_can_check_if_busy(&priv->regs->if1_creq, i+1);
+ }
+
+ for (i = i; i < PCH_OBJ_NUM; i++) {
+ iowrite32(CAN_CMASK_RX_TX_SET, &priv->regs->if2_cmask);
+ iowrite32(0xffff, &priv->regs->if2_mask1);
+ iowrite32(0xffff, &priv->regs->if2_mask2);
+ iowrite32(0x0, &priv->regs->if2_id1);
+ iowrite32(0x0, &priv->regs->if2_id2);
+ iowrite32(0x0, &priv->regs->if2_mcont);
+ iowrite32(0x0, &priv->regs->if2_dataa1);
+ iowrite32(0x0, &priv->regs->if2_dataa2);
+ iowrite32(0x0, &priv->regs->if2_datab1);
+ iowrite32(0x0, &priv->regs->if2_datab2);
+ iowrite32(CAN_CMASK_RDWR | CAN_CMASK_MASK |
+ CAN_CMASK_ARB | CAN_CMASK_CTRL,
+ &priv->regs->if2_cmask);
+ pch_can_check_if_busy(&priv->regs->if2_creq, i+1);
+ }
+}
+
+static void pch_can_config_rx_tx_buffers(struct pch_can_priv *priv)
+{
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->msgif_reg_lock, flags);
+
+ for (i = 0; i < PCH_OBJ_NUM; i++) {
+ if (priv->msg_obj[i] == MSG_OBJ_RX) {
+ iowrite32(CAN_CMASK_RX_TX_GET,
+ &priv->regs->if1_cmask);
+ pch_can_check_if_busy(&priv->regs->if1_creq, i+1);
+
+ iowrite32(0x0, &priv->regs->if1_id1);
+ iowrite32(0x0, &priv->regs->if1_id2);
+
+ pch_can_bit_set(&priv->regs->if1_mcont,
+ CAN_IF_MCONT_UMASK);
+
+ /* Set FIFO mode set to 0 except last Rx Obj*/
+ pch_can_bit_clear(&priv->regs->if1_mcont,
+ CAN_IF_MCONT_EOB);
+ /* In case FIFO mode, Last EoB of Rx Obj must be 1 */
+ if (i == (PCH_RX_OBJ_NUM - 1))
+ pch_can_bit_set(&priv->regs->if1_mcont,
+ CAN_IF_MCONT_EOB);
+
+ iowrite32(0, &priv->regs->if1_mask1);
+ pch_can_bit_clear(&priv->regs->if1_mask2,
+ 0x1fff | CAN_MASK2_MDIR_MXTD);
+
+ /* Setting CMASK for writing */
+ iowrite32(CAN_CMASK_RDWR | CAN_CMASK_MASK |
+ CAN_CMASK_ARB | CAN_CMASK_CTRL,
+ &priv->regs->if1_cmask);
+
+ pch_can_check_if_busy(&priv->regs->if1_creq, i+1);
+ } else if (priv->msg_obj[i] == MSG_OBJ_TX) {
+ iowrite32(CAN_CMASK_RX_TX_GET,
+ &priv->regs->if2_cmask);
+ pch_can_check_if_busy(&priv->regs->if2_creq, i+1);
+
+ /* Resetting DIR bit for reception */
+ iowrite32(0x0, &priv->regs->if2_id1);
+ iowrite32(0x0, &priv->regs->if2_id2);
+ pch_can_bit_set(&priv->regs->if2_id2, CAN_ID2_DIR);
+
+ /* Setting EOB bit for transmitter */
+ iowrite32(CAN_IF_MCONT_EOB, &priv->regs->if2_mcont);
+
+ pch_can_bit_set(&priv->regs->if2_mcont,
+ CAN_IF_MCONT_UMASK);
+
+ iowrite32(0, &priv->regs->if2_mask1);
+ pch_can_bit_clear(&priv->regs->if2_mask2, 0x1fff);
+
+ /* Setting CMASK for writing */
+ iowrite32(CAN_CMASK_RDWR | CAN_CMASK_MASK |
+ CAN_CMASK_ARB | CAN_CMASK_CTRL,
+ &priv->regs->if2_cmask);
+
+ pch_can_check_if_busy(&priv->regs->if2_creq, i+1);
+ }
+ }
+ spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
+}
+
+static void pch_can_init(struct pch_can_priv *priv)
+{
+ /* Stopping the Can device. */
+ pch_can_set_run_mode(priv, PCH_CAN_STOP);
+
+ /* Clearing all the message object buffers. */
+ pch_can_clear_buffers(priv);
+
+ /* Configuring the respective message object as either rx/tx object. */
+ pch_can_config_rx_tx_buffers(priv);
+
+ /* Enabling the interrupts. */
+ pch_can_set_int_enables(priv, PCH_CAN_ALL);
+}
+
+static void pch_can_release(struct pch_can_priv *priv)
+{
+ /* Stooping the CAN device. */
+ pch_can_set_run_mode(priv, PCH_CAN_STOP);
+
+ /* Disabling the interrupts. */
+ pch_can_set_int_enables(priv, PCH_CAN_NONE);
+
+ /* Disabling all the receive object. */
+ pch_can_rx_disable_all(priv);
+
+ /* Disabling all the transmit object. */
+ pch_can_tx_disable_all(priv);
+}
+
+/* This function clears interrupt(s) from the CAN device. */
+static void pch_can_int_clr(struct pch_can_priv *priv, u32 mask)
+{
+ if (mask == CAN_STATUS_INT) {
+ ioread32(&priv->regs->stat);
+ return;
+ }
+
+ /* Clear interrupt for transmit object */
+ if (priv->msg_obj[mask - 1] == MSG_OBJ_TX) {
+ /* Setting CMASK for clearing interrupts for
+ frame transmission. */
+ iowrite32(CAN_CMASK_RDWR | CAN_CMASK_CTRL | CAN_CMASK_ARB,
+ &priv->regs->if2_cmask);
+
+ /* Resetting the ID registers. */
+ pch_can_bit_set(&priv->regs->if2_id2,
+ CAN_ID2_DIR | (0x7ff << 2));
+ iowrite32(0x0, &priv->regs->if2_id1);
+
+ /* Claring NewDat, TxRqst & IntPnd */
+ pch_can_bit_clear(&priv->regs->if2_mcont,
+ CAN_IF_MCONT_NEWDAT | CAN_IF_MCONT_INTPND |
+ CAN_IF_MCONT_TXRQXT);
+ pch_can_check_if_busy(&priv->regs->if2_creq, mask);
+ } else if (priv->msg_obj[mask - 1] == MSG_OBJ_RX) {
+ /* Setting CMASK for clearing the reception interrupts. */
+ iowrite32(CAN_CMASK_RDWR | CAN_CMASK_CTRL | CAN_CMASK_ARB,
+ &priv->regs->if1_cmask);
+
+ /* Clearing the Dir bit. */
+ pch_can_bit_clear(&priv->regs->if1_id2, CAN_ID2_DIR);
+
+ /* Clearing NewDat & IntPnd */
+ pch_can_bit_clear(&priv->regs->if1_mcont,
+ CAN_IF_MCONT_NEWDAT | CAN_IF_MCONT_INTPND);
+
+ pch_can_check_if_busy(&priv->regs->if1_creq, mask);
+ }
+}
+
+static int pch_can_get_buffer_status(struct pch_can_priv *priv)
+{
+ return (ioread32(&priv->regs->treq1) & 0xffff) |
+ ((ioread32(&priv->regs->treq2) & 0xffff) << 16);
+}
+
+static void pch_can_reset(struct pch_can_priv *priv)
+{
+ /* write to sw reset register */
+ iowrite32(1, &priv->regs->srst);
+ iowrite32(0, &priv->regs->srst);
+}
+
+static void pch_can_error(struct net_device *ndev, u32 status)
+{
+ struct sk_buff *skb;
+ struct pch_can_priv *priv = netdev_priv(ndev);
+ struct can_frame *cf;
+ u32 errc;
+ struct net_device_stats *stats = &(priv->ndev->stats);
+ enum can_state state = priv->can.state;
+
+ skb = alloc_can_err_skb(ndev, &cf);
+ if (!skb)
+ return;
+
+ if (status & PCH_BUS_OFF) {
+ pch_can_tx_disable_all(priv);
+ pch_can_rx_disable_all(priv);
+ state = CAN_STATE_BUS_OFF;
+ cf->can_id |= CAN_ERR_BUSOFF;
+ can_bus_off(ndev);
+ pch_can_set_run_mode(priv, PCH_CAN_RUN);
+ dev_err(&ndev->dev, "%s -> Bus Off occurres.\n", __func__);
+ }
+
+ /* Warning interrupt. */
+ if (status & PCH_EWARN) {
+ state = CAN_STATE_ERROR_WARNING;
+ priv->can.can_stats.error_warning++;
+ cf->can_id |= CAN_ERR_CRTL;
+ errc = ioread32(&priv->regs->errc);
+ if (((errc & CAN_REC) >> 8) > 96)
+ cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
+ if ((errc & CAN_TEC) > 96)
+ cf->data[1] |= CAN_ERR_CRTL_TX_WARNING;
+ dev_warn(&ndev->dev,
+ "%s -> Error Counter is more than 96.\n", __func__);
+ }
+ /* Error passive interrupt. */
+ if (status & PCH_EPASSIV) {
+ priv->can.can_stats.error_passive++;
+ state = CAN_STATE_ERROR_PASSIVE;
+ cf->can_id |= CAN_ERR_CRTL;
+ errc = ioread32(&priv->regs->errc);
+ if (((errc & CAN_REC) >> 8) > 127)
+ cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+ if ((errc & CAN_TEC) > 127)
+ cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+ dev_err(&ndev->dev,
+ "%s -> CAN controller is ERROR PASSIVE .\n", __func__);
+ }
+
+ if (status & PCH_LEC_ALL) {
+ priv->can.can_stats.bus_error++;
+ stats->rx_errors++;
+ switch (status & PCH_LEC_ALL) {
+ case PCH_STUF_ERR:
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
+ break;
+ case PCH_FORM_ERR:
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ break;
+ case PCH_ACK_ERR:
+ cf->data[2] |= CAN_ERR_PROT_LOC_ACK |
+ CAN_ERR_PROT_LOC_ACK_DEL;
+ break;
+ case PCH_BIT1_ERR:
+ case PCH_BIT0_ERR:
+ cf->data[2] |= CAN_ERR_PROT_BIT;
+ break;
+ case PCH_CRC_ERR:
+ cf->data[2] |= CAN_ERR_PROT_LOC_CRC_SEQ |
+ CAN_ERR_PROT_LOC_CRC_DEL;
+ break;
+ default:
+ iowrite32(status | PCH_LEC_ALL, &priv->regs->stat);
+ break;
+ }
+
+ }
+
+ priv->can.state = state;
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+}
+
+static irqreturn_t pch_can_interrupt(int irq, void *dev_id)
+{
+ struct net_device *ndev = (struct net_device *)dev_id;
+ struct pch_can_priv *priv = netdev_priv(ndev);
+
+ pch_can_set_int_enables(priv, PCH_CAN_NONE);
+
+ napi_schedule(&priv->napi);
+
+ return IRQ_HANDLED;
+}
+
+static int pch_can_rx_normal(struct net_device *ndev, u32 int_stat)
+{
+ u32 reg;
+ canid_t id;
+ u32 ide;
+ u32 rtr;
+ int i, j, k;
+ int rcv_pkts = 0;
+ struct sk_buff *skb;
+ struct can_frame *cf;
+ struct pch_can_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &(priv->ndev->stats);
+
+ /* Reading the messsage object from the Message RAM */
+ iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if1_cmask);
+ pch_can_check_if_busy(&priv->regs->if1_creq, int_stat);
+
+ /* Reading the MCONT register. */
+ reg = ioread32(&priv->regs->if1_mcont);
+ reg &= 0xffff;
+
+ for (k = int_stat; !(reg & CAN_IF_MCONT_EOB); k++) {
+ /* If MsgLost bit set. */
+ if (reg & CAN_IF_MCONT_MSGLOST) {
+ dev_err(&priv->ndev->dev, "Msg Obj is overwritten.\n");
+ pch_can_bit_clear(&priv->regs->if1_mcont,
+ CAN_IF_MCONT_MSGLOST);
+ iowrite32(CAN_CMASK_RDWR | CAN_CMASK_CTRL,
+ &priv->regs->if1_cmask);
+ pch_can_check_if_busy(&priv->regs->if1_creq, k);
+
+ skb = alloc_can_err_skb(ndev, &cf);
+ if (!skb)
+ return -ENOMEM;
+
+ priv->can.can_stats.error_passive++;
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
+ cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ netif_receive_skb(skb);
+ rcv_pkts++;
+ goto RX_NEXT;
+ }
+ if (!(reg & CAN_IF_MCONT_NEWDAT))
+ goto RX_NEXT;
+
+ skb = alloc_can_skb(priv->ndev, &cf);
+ if (!skb)
+ return -ENOMEM;
+
+ /* Get Received data */
+ ide = ((ioread32(&priv->regs->if1_id2)) & CAN_ID2_XTD) >> 14;
+ if (ide) {
+ id = (ioread32(&priv->regs->if1_id1) & 0xffff);
+ id |= (((ioread32(&priv->regs->if1_id2)) &
+ 0x1fff) << 16);
+ cf->can_id = (id & CAN_EFF_MASK) | CAN_EFF_FLAG;
+ } else {
+ id = (((ioread32(&priv->regs->if1_id2)) &
+ (CAN_SFF_MASK << 2)) >> 2);
+ cf->can_id = (id & CAN_SFF_MASK);
+ }
+
+ rtr = (ioread32(&priv->regs->if1_id2) & CAN_ID2_DIR);
+ if (rtr) {
+ cf->can_dlc = 0;
+ cf->can_id |= CAN_RTR_FLAG;
+ } else {
+ cf->can_dlc = ((ioread32(&priv->regs->if1_mcont)) &
+ 0x0f);
+ }
+
+ for (i = 0, j = 0; i < cf->can_dlc; j++) {
+ reg = ioread32(&priv->regs->if1_dataa1 + j*4);
+ cf->data[i++] = cpu_to_le32(reg & 0xff);
+ if (i == cf->can_dlc)
+ break;
+ cf->data[i++] = cpu_to_le32((reg >> 8) & 0xff);
+ }
+
+ netif_receive_skb(skb);
+ rcv_pkts++;
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ if (k < PCH_FIFO_THRESH) {
+ iowrite32(CAN_CMASK_RDWR | CAN_CMASK_CTRL |
+ CAN_CMASK_ARB, &priv->regs->if1_cmask);
+
+ /* Clearing the Dir bit. */
+ pch_can_bit_clear(&priv->regs->if1_id2, CAN_ID2_DIR);
+
+ /* Clearing NewDat & IntPnd */
+ pch_can_bit_clear(&priv->regs->if1_mcont,
+ CAN_IF_MCONT_INTPND);
+ pch_can_check_if_busy(&priv->regs->if1_creq, k);
+ } else if (k > PCH_FIFO_THRESH) {
+ pch_can_int_clr(priv, k);
+ } else if (k == PCH_FIFO_THRESH) {
+ int cnt;
+ for (cnt = 0; cnt < PCH_FIFO_THRESH; cnt++)
+ pch_can_int_clr(priv, cnt+1);
+ }
+RX_NEXT:
+ /* Reading the messsage object from the Message RAM */
+ iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if1_cmask);
+ pch_can_check_if_busy(&priv->regs->if1_creq, k + 1);
+ reg = ioread32(&priv->regs->if1_mcont);
+ }
+
+ return rcv_pkts;
+}
+static int pch_can_rx_poll(struct napi_struct *napi, int quota)
+{
+ struct net_device *ndev = napi->dev;
+ struct pch_can_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &(priv->ndev->stats);
+ u32 dlc;
+ u32 int_stat;
+ int rcv_pkts = 0;
+ u32 reg_stat;
+ unsigned long flags;
+
+ int_stat = pch_can_int_pending(priv);
+ if (!int_stat)
+ return 0;
+
+INT_STAT:
+ if (int_stat == CAN_STATUS_INT) {
+ reg_stat = ioread32(&priv->regs->stat);
+ if (reg_stat & (PCH_BUS_OFF | PCH_LEC_ALL)) {
+ if ((reg_stat & PCH_LEC_ALL) != PCH_LEC_ALL)
+ pch_can_error(ndev, reg_stat);
+ }
+
+ if (reg_stat & PCH_TX_OK) {
+ spin_lock_irqsave(&priv->msgif_reg_lock, flags);
+ iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if2_cmask);
+ pch_can_check_if_busy(&priv->regs->if2_creq,
+ ioread32(&priv->regs->intr));
+ spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
+ pch_can_bit_clear(&priv->regs->stat, PCH_TX_OK);
+ }
+
+ if (reg_stat & PCH_RX_OK)
+ pch_can_bit_clear(&priv->regs->stat, PCH_RX_OK);
+
+ int_stat = pch_can_int_pending(priv);
+ if (int_stat == CAN_STATUS_INT)
+ goto INT_STAT;
+ }
+
+MSG_OBJ:
+ if ((int_stat >= 1) && (int_stat <= PCH_RX_OBJ_NUM)) {
+ spin_lock_irqsave(&priv->msgif_reg_lock, flags);
+ rcv_pkts = pch_can_rx_normal(ndev, int_stat);
+ spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
+ if (rcv_pkts < 0)
+ return 0;
+ } else if ((int_stat > PCH_RX_OBJ_NUM) && (int_stat <= PCH_OBJ_NUM)) {
+ if (priv->msg_obj[int_stat - 1] == MSG_OBJ_TX) {
+ /* Handle transmission interrupt */
+ can_get_echo_skb(ndev, int_stat - PCH_RX_OBJ_NUM - 1);
+ spin_lock_irqsave(&priv->msgif_reg_lock, flags);
+ iowrite32(CAN_CMASK_RX_TX_GET | CAN_CMASK_CLRINTPND,
+ &priv->regs->if2_cmask);
+ dlc = ioread32(&priv->regs->if2_mcont) &
+ CAN_IF_MCONT_DLC;
+ pch_can_check_if_busy(&priv->regs->if2_creq, int_stat);
+ spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
+ if (dlc > 8)
+ dlc = 8;
+ stats->tx_bytes += dlc;
+ stats->tx_packets++;
+ }
+ }
+
+ int_stat = pch_can_int_pending(priv);
+ if (int_stat == CAN_STATUS_INT)
+ goto INT_STAT;
+ else if (int_stat >= 1 && int_stat <= 32)
+ goto MSG_OBJ;
+
+ napi_complete(napi);
+ pch_can_set_int_enables(priv, PCH_CAN_ALL);
+
+ return rcv_pkts;
+}
+
+static int pch_set_bittiming(struct net_device *ndev)
+{
+ struct pch_can_priv *priv = netdev_priv(ndev);
+ const struct can_bittiming *bt = &priv->can.bittiming;
+ u32 canbit;
+ u32 bepe;
+ u32 brp;
+
+ /* Setting the CCE bit for accessing the Can Timing register. */
+ pch_can_bit_set(&priv->regs->cont, CAN_CTRL_CCE);
+
+ brp = (bt->tq) / (1000000000/PCH_CAN_CLK) - 1;
+ canbit = brp & MSK_BITT_BRP;
+ canbit |= (bt->sjw - 1) << BIT_BITT_SJW;
+ canbit |= (bt->phase_seg1 + bt->prop_seg - 1) << BIT_BITT_TSEG1;
+ canbit |= (bt->phase_seg2 - 1) << BIT_BITT_TSEG2;
+ bepe = (brp & MSK_BRPE_BRPE) >> BIT_BRPE_BRPE;
+ iowrite32(canbit, &priv->regs->bitt);
+ iowrite32(bepe, &priv->regs->brpe);
+ pch_can_bit_clear(&priv->regs->cont, CAN_CTRL_CCE);
+
+ return 0;
+}
+
+static void pch_can_start(struct net_device *ndev)
+{
+ struct pch_can_priv *priv = netdev_priv(ndev);
+
+ if (priv->can.state != CAN_STATE_STOPPED)
+ pch_can_reset(priv);
+
+ pch_set_bittiming(ndev);
+ pch_can_set_optmode(priv);
+
+ pch_can_tx_enable_all(priv);
+ pch_can_rx_enable_all(priv);
+
+ /* Setting the CAN to run mode. */
+ pch_can_set_run_mode(priv, PCH_CAN_RUN);
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ return;
+}
+
+static int pch_can_do_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+ int ret = 0;
+
+ switch (mode) {
+ case CAN_MODE_START:
+ pch_can_start(ndev);
+ netif_wake_queue(ndev);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static int pch_can_open(struct net_device *ndev)
+{
+ struct pch_can_priv *priv = netdev_priv(ndev);
+ int retval;
+
+ retval = pci_enable_msi(priv->dev);
+ if (retval) {
+ dev_info(&ndev->dev, "PCH CAN opened without MSI\n");
+ priv->use_msi = 0;
+ } else {
+ dev_info(&ndev->dev, "PCH CAN opened with MSI\n");
+ priv->use_msi = 1;
+ }
+
+ /* Regsitering the interrupt. */
+ retval = request_irq(priv->dev->irq, pch_can_interrupt, IRQF_SHARED,
+ ndev->name, ndev);
+ if (retval) {
+ dev_err(&ndev->dev, "request_irq failed.\n");
+ goto req_irq_err;
+ }
+
+ /* Open common can device */
+ retval = open_candev(ndev);
+ if (retval) {
+ dev_err(ndev->dev.parent, "open_candev() failed %d\n", retval);
+ goto err_open_candev;
+ }
+
+ pch_can_init(priv);
+ pch_can_start(ndev);
+ napi_enable(&priv->napi);
+ netif_start_queue(ndev);
+
+ return 0;
+
+err_open_candev:
+ free_irq(priv->dev->irq, ndev);
+req_irq_err:
+ if (priv->use_msi)
+ pci_disable_msi(priv->dev);
+
+ pch_can_release(priv);
+
+ return retval;
+}
+
+static int pch_close(struct net_device *ndev)
+{
+ struct pch_can_priv *priv = netdev_priv(ndev);
+
+ netif_stop_queue(ndev);
+ napi_disable(&priv->napi);
+ pch_can_release(priv);
+ free_irq(priv->dev->irq, ndev);
+ if (priv->use_msi)
+ pci_disable_msi(priv->dev);
+ close_candev(ndev);
+ priv->can.state = CAN_STATE_STOPPED;
+ return 0;
+}
+
+static int pch_get_msg_obj_sts(struct net_device *ndev, u32 obj_id)
+{
+ u32 buffer_status = 0;
+ struct pch_can_priv *priv = netdev_priv(ndev);
+
+ /* Getting the message object status. */
+ buffer_status = (u32) pch_can_get_buffer_status(priv);
+
+ return buffer_status & obj_id;
+}
+
+
+static netdev_tx_t pch_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ int i, j;
+ unsigned long flags;
+ struct pch_can_priv *priv = netdev_priv(ndev);
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ int tx_buffer_avail = 0;
+
+ if (can_dropped_invalid_skb(ndev, skb))
+ return NETDEV_TX_OK;
+
+ if (priv->tx_obj == (PCH_OBJ_NUM + 1)) { /* Point tail Obj */
+ while (pch_get_msg_obj_sts(ndev, (((1 << PCH_TX_OBJ_NUM)-1) <<
+ PCH_RX_OBJ_NUM)))
+ udelay(500);
+
+ priv->tx_obj = PCH_RX_OBJ_NUM + 1; /* Point head of Tx Obj ID */
+ tx_buffer_avail = priv->tx_obj; /* Point Tail of Tx Obj */
+ } else {
+ tx_buffer_avail = priv->tx_obj;
+ }
+ priv->tx_obj++;
+
+ /* Attaining the lock. */
+ spin_lock_irqsave(&priv->msgif_reg_lock, flags);
+
+ /* Reading the Msg Obj from the Msg RAM to the Interface register. */
+ iowrite32(CAN_CMASK_RX_TX_GET, &priv->regs->if2_cmask);
+ pch_can_check_if_busy(&priv->regs->if2_creq, tx_buffer_avail);
+
+ /* Setting the CMASK register. */
+ pch_can_bit_set(&priv->regs->if2_cmask, CAN_CMASK_ALL);
+
+ /* If ID extended is set. */
+ pch_can_bit_clear(&priv->regs->if2_id1, 0xffff);
+ pch_can_bit_clear(&priv->regs->if2_id2, 0x1fff | CAN_ID2_XTD);
+ if (cf->can_id & CAN_EFF_FLAG) {
+ pch_can_bit_set(&priv->regs->if2_id1, cf->can_id & 0xffff);
+ pch_can_bit_set(&priv->regs->if2_id2,
+ ((cf->can_id >> 16) & 0x1fff) | CAN_ID2_XTD);
+ } else {
+ pch_can_bit_set(&priv->regs->if2_id1, 0);
+ pch_can_bit_set(&priv->regs->if2_id2,
+ (cf->can_id & CAN_SFF_MASK) << 2);
+ }
+
+ /* If remote frame has to be transmitted.. */
+ if (cf->can_id & CAN_RTR_FLAG)
+ pch_can_bit_clear(&priv->regs->if2_id2, CAN_ID2_DIR);
+
+ for (i = 0, j = 0; i < cf->can_dlc; j++) {
+ iowrite32(le32_to_cpu(cf->data[i++]),
+ (&priv->regs->if2_dataa1) + j*4);
+ if (i == cf->can_dlc)
+ break;
+ iowrite32(le32_to_cpu(cf->data[i++] << 8),
+ (&priv->regs->if2_dataa1) + j*4);
+ }
+
+ can_put_echo_skb(skb, ndev, tx_buffer_avail - PCH_RX_OBJ_NUM - 1);
+
+ /* Updating the size of the data. */
+ pch_can_bit_clear(&priv->regs->if2_mcont, 0x0f);
+ pch_can_bit_set(&priv->regs->if2_mcont, cf->can_dlc);
+
+ /* Clearing IntPend, NewDat & TxRqst */
+ pch_can_bit_clear(&priv->regs->if2_mcont,
+ CAN_IF_MCONT_NEWDAT | CAN_IF_MCONT_INTPND |
+ CAN_IF_MCONT_TXRQXT);
+
+ /* Setting NewDat, TxRqst bits */
+ pch_can_bit_set(&priv->regs->if2_mcont,
+ CAN_IF_MCONT_NEWDAT | CAN_IF_MCONT_TXRQXT);
+
+ pch_can_check_if_busy(&priv->regs->if2_creq, tx_buffer_avail);
+
+ spin_unlock_irqrestore(&priv->msgif_reg_lock, flags);
+
+ return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops pch_can_netdev_ops = {
+ .ndo_open = pch_can_open,
+ .ndo_stop = pch_close,
+ .ndo_start_xmit = pch_xmit,
+};
+
+static void __devexit pch_can_remove(struct pci_dev *pdev)
+{
+ struct net_device *ndev = pci_get_drvdata(pdev);
+ struct pch_can_priv *priv = netdev_priv(ndev);
+
+ unregister_candev(priv->ndev);
+ free_candev(priv->ndev);
+ pci_iounmap(pdev, priv->regs);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ pch_can_reset(priv);
+}
+
+#ifdef CONFIG_PM
+static int pch_can_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ int i; /* Counter variable. */
+ int retval; /* Return value. */
+ u32 buf_stat; /* Variable for reading the transmit buffer status. */
+ u32 counter = 0xFFFFFF;
+
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct pch_can_priv *priv = netdev_priv(dev);
+
+ /* Stop the CAN controller */
+ pch_can_set_run_mode(priv, PCH_CAN_STOP);
+
+ /* Indicate that we are aboutto/in suspend */
+ priv->can.state = CAN_STATE_SLEEPING;
+
+ /* Waiting for all transmission to complete. */
+ while (counter) {
+ buf_stat = pch_can_get_buffer_status(priv);
+ if (!buf_stat)
+ break;
+ counter--;
+ udelay(1);
+ }
+ if (!counter)
+ dev_err(&pdev->dev, "%s -> Transmission time out.\n", __func__);
+
+ /* Save interrupt configuration and then disable them */
+ pch_can_get_int_enables(priv, &(priv->int_enables));
+ pch_can_set_int_enables(priv, PCH_CAN_DISABLE);
+
+ /* Save Tx buffer enable state */
+ for (i = 0; i < PCH_OBJ_NUM; i++) {
+ if (priv->msg_obj[i] == MSG_OBJ_TX)
+ pch_can_get_tx_enable(priv, i + 1,
+ &(priv->tx_enable[i]));
+ }
+
+ /* Disable all Transmit buffers */
+ pch_can_tx_disable_all(priv);
+
+ /* Save Rx buffer enable state */
+ for (i = 0; i < PCH_OBJ_NUM; i++) {
+ if (priv->msg_obj[i] == MSG_OBJ_RX) {
+ pch_can_get_rx_enable(priv, i + 1,
+ &(priv->rx_enable[i]));
+ pch_can_get_rx_buffer_link(priv, i + 1,
+ &(priv->rx_link[i]));
+ }
+ }
+
+ /* Disable all Receive buffers */
+ pch_can_rx_disable_all(priv);
+ retval = pci_save_state(pdev);
+ if (retval) {
+ dev_err(&pdev->dev, "pci_save_state failed.\n");
+ } else {
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ }
+
+ return retval;
+}
+
+static int pch_can_resume(struct pci_dev *pdev)
+{
+ int i; /* Counter variable. */
+ int retval; /* Return variable. */
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct pch_can_priv *priv = netdev_priv(dev);
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ retval = pci_enable_device(pdev);
+ if (retval) {
+ dev_err(&pdev->dev, "pci_enable_device failed.\n");
+ return retval;
+ }
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ /* Disabling all interrupts. */
+ pch_can_set_int_enables(priv, PCH_CAN_DISABLE);
+
+ /* Setting the CAN device in Stop Mode. */
+ pch_can_set_run_mode(priv, PCH_CAN_STOP);
+
+ /* Configuring the transmit and receive buffers. */
+ pch_can_config_rx_tx_buffers(priv);
+
+ /* Restore the CAN state */
+ pch_set_bittiming(dev);
+
+ /* Listen/Active */
+ pch_can_set_optmode(priv);
+
+ /* Enabling the transmit buffer. */
+ for (i = 0; i < PCH_OBJ_NUM; i++) {
+ if (priv->msg_obj[i] == MSG_OBJ_TX) {
+ pch_can_set_tx_enable(priv, i + 1,
+ priv->tx_enable[i]);
+ }
+ }
+
+ /* Configuring the receive buffer and enabling them. */
+ for (i = 0; i < PCH_OBJ_NUM; i++) {
+ if (priv->msg_obj[i] == MSG_OBJ_RX) {
+ /* Restore buffer link */
+ pch_can_set_rx_buffer_link(priv, i + 1,
+ priv->rx_link[i]);
+
+ /* Restore buffer enables */
+ pch_can_set_rx_enable(priv, i + 1, priv->rx_enable[i]);
+ }
+ }
+
+ /* Enable CAN Interrupts */
+ pch_can_set_int_custom(priv);
+
+ /* Restore Run Mode */
+ pch_can_set_run_mode(priv, PCH_CAN_RUN);
+
+ return retval;
+}
+#else
+#define pch_can_suspend NULL
+#define pch_can_resume NULL
+#endif
+
+static int pch_can_get_berr_counter(const struct net_device *dev,
+ struct can_berr_counter *bec)
+{
+ struct pch_can_priv *priv = netdev_priv(dev);
+
+ bec->txerr = ioread32(&priv->regs->errc) & CAN_TEC;
+ bec->rxerr = (ioread32(&priv->regs->errc) & CAN_REC) >> 8;
+
+ return 0;
+}
+
+static int __devinit pch_can_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct net_device *ndev;
+ struct pch_can_priv *priv;
+ int rc;
+ int index;
+ void __iomem *addr;
+
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ dev_err(&pdev->dev, "Failed pci_enable_device %d\n", rc);
+ goto probe_exit_endev;
+ }
+
+ rc = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (rc) {
+ dev_err(&pdev->dev, "Failed pci_request_regions %d\n", rc);
+ goto probe_exit_pcireq;
+ }
+
+ addr = pci_iomap(pdev, 1, 0);
+ if (!addr) {
+ rc = -EIO;
+ dev_err(&pdev->dev, "Failed pci_iomap\n");
+ goto probe_exit_ipmap;
+ }
+
+ ndev = alloc_candev(sizeof(struct pch_can_priv), PCH_TX_OBJ_NUM);
+ if (!ndev) {
+ rc = -ENOMEM;
+ dev_err(&pdev->dev, "Failed alloc_candev\n");
+ goto probe_exit_alloc_candev;
+ }
+
+ priv = netdev_priv(ndev);
+ priv->ndev = ndev;
+ priv->regs = addr;
+ priv->dev = pdev;
+ priv->can.bittiming_const = &pch_can_bittiming_const;
+ priv->can.do_set_mode = pch_can_do_set_mode;
+ priv->can.do_get_berr_counter = pch_can_get_berr_counter;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
+ CAN_CTRLMODE_LOOPBACK;
+ priv->tx_obj = PCH_RX_OBJ_NUM + 1; /* Point head of Tx Obj */
+
+ ndev->irq = pdev->irq;
+ ndev->flags |= IFF_ECHO;
+
+ pci_set_drvdata(pdev, ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+ ndev->netdev_ops = &pch_can_netdev_ops;
+
+ priv->can.clock.freq = PCH_CAN_CLK; /* Hz */
+ for (index = 0; index < PCH_RX_OBJ_NUM;)
+ priv->msg_obj[index++] = MSG_OBJ_RX;
+
+ for (index = index; index < PCH_OBJ_NUM;)
+ priv->msg_obj[index++] = MSG_OBJ_TX;
+
+ netif_napi_add(ndev, &priv->napi, pch_can_rx_poll, PCH_RX_OBJ_NUM);
+
+ rc = register_candev(ndev);
+ if (rc) {
+ dev_err(&pdev->dev, "Failed register_candev %d\n", rc);
+ goto probe_exit_reg_candev;
+ }
+
+ return 0;
+
+probe_exit_reg_candev:
+ free_candev(ndev);
+probe_exit_alloc_candev:
+ pci_iounmap(pdev, addr);
+probe_exit_ipmap:
+ pci_release_regions(pdev);
+probe_exit_pcireq:
+ pci_disable_device(pdev);
+probe_exit_endev:
+ return rc;
+}
+
+static struct pci_driver pch_can_pcidev = {
+ .name = "pch_can",
+ .id_table = pch_pci_tbl,
+ .probe = pch_can_probe,
+ .remove = __devexit_p(pch_can_remove),
+ .suspend = pch_can_suspend,
+ .resume = pch_can_resume,
+};
+
+static int __init pch_can_pci_init(void)
+{
+ return pci_register_driver(&pch_can_pcidev);
+}
+module_init(pch_can_pci_init);
+
+static void __exit pch_can_pci_exit(void)
+{
+ pci_unregister_driver(&pch_can_pcidev);
+}
+module_exit(pch_can_pci_exit);
+
+MODULE_DESCRIPTION("Controller Area Network Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.94");
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index ae3505afd682..6fdc031daaae 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -58,4 +58,16 @@ config CAN_PLX_PCI
- esd CAN-PCIe/2000
- Marathon CAN-bus-PCI card (http://www.marathon.ru/)
- TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)
+
+config CAN_TSCAN1
+ tristate "TS-CAN1 PC104 boards"
+ depends on ISA
+ help
+ This driver is for Technologic Systems' TSCAN-1 PC104 boards.
+ http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1
+ The driver supports multiple boards and automatically configures them:
+ PLD IO base addresses are read from jumpers JP1 and JP2,
+ IRQ numbers are read from jumpers JP4 and JP5,
+ SJA1000 IO base addresses are chosen heuristically (first that works).
+
endif
diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile
index ce924553995d..2c591eb321c7 100644
--- a/drivers/net/can/sja1000/Makefile
+++ b/drivers/net/can/sja1000/Makefile
@@ -9,5 +9,6 @@ obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
obj-$(CONFIG_CAN_PLX_PCI) += plx_pci.o
+obj-$(CONFIG_CAN_TSCAN1) += tscan1.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/sja1000/tscan1.c b/drivers/net/can/sja1000/tscan1.c
new file mode 100644
index 000000000000..9756099a883a
--- /dev/null
+++ b/drivers/net/can/sja1000/tscan1.c
@@ -0,0 +1,216 @@
+/*
+ * tscan1.c: driver for Technologic Systems TS-CAN1 PC104 boards
+ *
+ * Copyright 2010 Andre B. Oliveira
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * References:
+ * - Getting started with TS-CAN1, Technologic Systems, Jun 2009
+ * http://www.embeddedarm.com/documentation/ts-can1-manual.pdf
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/isa.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include "sja1000.h"
+
+MODULE_DESCRIPTION("Driver for Technologic Systems TS-CAN1 PC104 boards");
+MODULE_AUTHOR("Andre B. Oliveira <anbadeol@gmail.com>");
+MODULE_LICENSE("GPL");
+
+/* Maximum number of boards (one in each JP1:JP2 setting of IO address) */
+#define TSCAN1_MAXDEV 4
+
+/* PLD registers address offsets */
+#define TSCAN1_ID1 0
+#define TSCAN1_ID2 1
+#define TSCAN1_VERSION 2
+#define TSCAN1_LED 3
+#define TSCAN1_PAGE 4
+#define TSCAN1_MODE 5
+#define TSCAN1_JUMPERS 6
+
+/* PLD board identifier registers magic values */
+#define TSCAN1_ID1_VALUE 0xf6
+#define TSCAN1_ID2_VALUE 0xb9
+
+/* PLD mode register SJA1000 IO enable bit */
+#define TSCAN1_MODE_ENABLE 0x40
+
+/* PLD jumpers register bits */
+#define TSCAN1_JP4 0x10
+#define TSCAN1_JP5 0x20
+
+/* PLD IO base addresses start */
+#define TSCAN1_PLD_ADDRESS 0x150
+
+/* PLD register space size */
+#define TSCAN1_PLD_SIZE 8
+
+/* SJA1000 register space size */
+#define TSCAN1_SJA1000_SIZE 32
+
+/* SJA1000 crystal frequency (16MHz) */
+#define TSCAN1_SJA1000_XTAL 16000000
+
+/* SJA1000 IO base addresses */
+static const unsigned short tscan1_sja1000_addresses[] __devinitconst = {
+ 0x100, 0x120, 0x180, 0x1a0, 0x200, 0x240, 0x280, 0x320
+};
+
+/* Read SJA1000 register */
+static u8 tscan1_read(const struct sja1000_priv *priv, int reg)
+{
+ return inb((unsigned long)priv->reg_base + reg);
+}
+
+/* Write SJA1000 register */
+static void tscan1_write(const struct sja1000_priv *priv, int reg, u8 val)
+{
+ outb(val, (unsigned long)priv->reg_base + reg);
+}
+
+/* Probe for a TS-CAN1 board with JP2:JP1 jumper setting ID */
+static int __devinit tscan1_probe(struct device *dev, unsigned id)
+{
+ struct net_device *netdev;
+ struct sja1000_priv *priv;
+ unsigned long pld_base, sja1000_base;
+ int irq, i;
+
+ pld_base = TSCAN1_PLD_ADDRESS + id * TSCAN1_PLD_SIZE;
+ if (!request_region(pld_base, TSCAN1_PLD_SIZE, dev_name(dev)))
+ return -EBUSY;
+
+ if (inb(pld_base + TSCAN1_ID1) != TSCAN1_ID1_VALUE ||
+ inb(pld_base + TSCAN1_ID2) != TSCAN1_ID2_VALUE) {
+ release_region(pld_base, TSCAN1_PLD_SIZE);
+ return -ENODEV;
+ }
+
+ switch (inb(pld_base + TSCAN1_JUMPERS) & (TSCAN1_JP4 | TSCAN1_JP5)) {
+ case TSCAN1_JP4:
+ irq = 6;
+ break;
+ case TSCAN1_JP5:
+ irq = 7;
+ break;
+ case TSCAN1_JP4 | TSCAN1_JP5:
+ irq = 5;
+ break;
+ default:
+ dev_err(dev, "invalid JP4:JP5 setting (no IRQ)\n");
+ release_region(pld_base, TSCAN1_PLD_SIZE);
+ return -EINVAL;
+ }
+
+ netdev = alloc_sja1000dev(0);
+ if (!netdev) {
+ release_region(pld_base, TSCAN1_PLD_SIZE);
+ return -ENOMEM;
+ }
+
+ dev_set_drvdata(dev, netdev);
+ SET_NETDEV_DEV(netdev, dev);
+
+ netdev->base_addr = pld_base;
+ netdev->irq = irq;
+
+ priv = netdev_priv(netdev);
+ priv->read_reg = tscan1_read;
+ priv->write_reg = tscan1_write;
+ priv->can.clock.freq = TSCAN1_SJA1000_XTAL / 2;
+ priv->cdr = CDR_CBP | CDR_CLK_OFF;
+ priv->ocr = OCR_TX0_PUSHPULL;
+
+ /* Select the first SJA1000 IO address that is free and that works */
+ for (i = 0; i < ARRAY_SIZE(tscan1_sja1000_addresses); i++) {
+ sja1000_base = tscan1_sja1000_addresses[i];
+ if (!request_region(sja1000_base, TSCAN1_SJA1000_SIZE,
+ dev_name(dev)))
+ continue;
+
+ /* Set SJA1000 IO base address and enable it */
+ outb(TSCAN1_MODE_ENABLE | i, pld_base + TSCAN1_MODE);
+
+ priv->reg_base = (void __iomem *)sja1000_base;
+ if (!register_sja1000dev(netdev)) {
+ /* SJA1000 probe succeeded; turn LED off and return */
+ outb(0, pld_base + TSCAN1_LED);
+ netdev_info(netdev, "TS-CAN1 at 0x%lx 0x%lx irq %d\n",
+ pld_base, sja1000_base, irq);
+ return 0;
+ }
+
+ /* SJA1000 probe failed; release and try next address */
+ outb(0, pld_base + TSCAN1_MODE);
+ release_region(sja1000_base, TSCAN1_SJA1000_SIZE);
+ }
+
+ dev_err(dev, "failed to assign SJA1000 IO address\n");
+ dev_set_drvdata(dev, NULL);
+ free_sja1000dev(netdev);
+ release_region(pld_base, TSCAN1_PLD_SIZE);
+ return -ENXIO;
+}
+
+static int __devexit tscan1_remove(struct device *dev, unsigned id /*unused*/)
+{
+ struct net_device *netdev;
+ struct sja1000_priv *priv;
+ unsigned long pld_base, sja1000_base;
+
+ netdev = dev_get_drvdata(dev);
+ unregister_sja1000dev(netdev);
+ dev_set_drvdata(dev, NULL);
+
+ priv = netdev_priv(netdev);
+ pld_base = netdev->base_addr;
+ sja1000_base = (unsigned long)priv->reg_base;
+
+ outb(0, pld_base + TSCAN1_MODE); /* disable SJA1000 IO space */
+
+ release_region(sja1000_base, TSCAN1_SJA1000_SIZE);
+ release_region(pld_base, TSCAN1_PLD_SIZE);
+
+ free_sja1000dev(netdev);
+
+ return 0;
+}
+
+static struct isa_driver tscan1_isa_driver = {
+ .probe = tscan1_probe,
+ .remove = __devexit_p(tscan1_remove),
+ .driver = {
+ .name = "tscan1",
+ },
+};
+
+static int __init tscan1_init(void)
+{
+ return isa_register_driver(&tscan1_isa_driver, TSCAN1_MAXDEV);
+}
+module_init(tscan1_init);
+
+static void __exit tscan1_exit(void)
+{
+ isa_unregister_driver(&tscan1_isa_driver);
+}
+module_exit(tscan1_exit);
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 28c88eeec757..d6b6d6aa565a 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -419,7 +419,7 @@ static u16 cas_phy_read(struct cas *cp, int reg)
udelay(10);
cmd = readl(cp->regs + REG_MIF_FRAME);
if (cmd & MIF_FRAME_TURN_AROUND_LSB)
- return (cmd & MIF_FRAME_DATA_MASK);
+ return cmd & MIF_FRAME_DATA_MASK;
}
return 0xFFFF; /* -1 */
}
@@ -804,7 +804,7 @@ static int cas_reset_mii_phy(struct cas *cp)
break;
udelay(10);
}
- return (limit <= 0);
+ return limit <= 0;
}
static int cas_saturn_firmware_init(struct cas *cp)
@@ -2149,7 +2149,7 @@ end_copy_pkt:
skb->csum = csum_unfold(~csum);
skb->ip_summed = CHECKSUM_COMPLETE;
} else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
return len;
}
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index f01cfdb995de..70221ca32683 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -1388,7 +1388,7 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
++st->rx_cso_good;
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
if (unlikely(adapter->vlan_grp && p->vlan_valid)) {
st->vlan_xtract++;
@@ -1551,7 +1551,7 @@ static inline int responses_pending(const struct adapter *adapter)
const struct respQ *Q = &adapter->sge->respQ;
const struct respQ_e *e = &Q->entries[Q->cidx];
- return (e->GenerationBit == Q->genbit);
+ return e->GenerationBit == Q->genbit;
}
/*
@@ -1870,7 +1870,7 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
cpl->iff = dev->if_port;
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
- if (adapter->vlan_grp && vlan_tx_tag_present(skb)) {
+ if (vlan_tx_tag_present(skb)) {
cpl->vlan_valid = 1;
cpl->vlan = htons(vlan_tx_tag_get(skb));
st->vlan_insert++;
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index 599d178df62d..63ebf76d2390 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -314,14 +314,12 @@ static int mi1_mdio_write(struct net_device *dev, int phy_addr, int mmd_addr,
return 0;
}
-#if defined(CONFIG_CHELSIO_T1_1G)
static const struct mdio_ops mi1_mdio_ops = {
.init = mi1_mdio_init,
.read = mi1_mdio_read,
.write = mi1_mdio_write,
.mode_support = MDIO_SUPPORTS_C22
};
-#endif
#endif
diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c
index c844111cffeb..106a590f0d9a 100644
--- a/drivers/net/chelsio/vsc7326.c
+++ b/drivers/net/chelsio/vsc7326.c
@@ -255,7 +255,7 @@ static int bist_rd(adapter_t *adapter, int moduleid, int address)
else if ((result & (1 << 8)) != 0x0)
pr_err("bist read error: 0x%x\n", result);
- return (result & 0xff);
+ return result & 0xff;
}
static int bist_wr(adapter_t *adapter, int moduleid, int address, int value)
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 09610323a948..92bac19ad60a 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -60,6 +60,7 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(CNIC_MODULE_VERSION);
static LIST_HEAD(cnic_dev_list);
+static LIST_HEAD(cnic_udev_list);
static DEFINE_RWLOCK(cnic_dev_lock);
static DEFINE_MUTEX(cnic_lock);
@@ -81,29 +82,34 @@ static struct cnic_ops cnic_bnx2x_ops = {
.cnic_ctl = cnic_ctl,
};
+static struct workqueue_struct *cnic_wq;
+
static void cnic_shutdown_rings(struct cnic_dev *);
static void cnic_init_rings(struct cnic_dev *);
static int cnic_cm_set_pg(struct cnic_sock *);
static int cnic_uio_open(struct uio_info *uinfo, struct inode *inode)
{
- struct cnic_dev *dev = uinfo->priv;
- struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_uio_dev *udev = uinfo->priv;
+ struct cnic_dev *dev;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if (cp->uio_dev != -1)
+ if (udev->uio_dev != -1)
return -EBUSY;
rtnl_lock();
- if (!test_bit(CNIC_F_CNIC_UP, &dev->flags)) {
+ dev = udev->dev;
+
+ if (!dev || !test_bit(CNIC_F_CNIC_UP, &dev->flags)) {
rtnl_unlock();
return -ENODEV;
}
- cp->uio_dev = iminor(inode);
+ udev->uio_dev = iminor(inode);
+ cnic_shutdown_rings(dev);
cnic_init_rings(dev);
rtnl_unlock();
@@ -112,12 +118,9 @@ static int cnic_uio_open(struct uio_info *uinfo, struct inode *inode)
static int cnic_uio_close(struct uio_info *uinfo, struct inode *inode)
{
- struct cnic_dev *dev = uinfo->priv;
- struct cnic_local *cp = dev->cnic_priv;
-
- cnic_shutdown_rings(dev);
+ struct cnic_uio_dev *udev = uinfo->priv;
- cp->uio_dev = -1;
+ udev->uio_dev = -1;
return 0;
}
@@ -242,14 +245,14 @@ static int cnic_in_use(struct cnic_sock *csk)
return test_bit(SK_F_INUSE, &csk->flags);
}
-static void cnic_kwq_completion(struct cnic_dev *dev, u32 count)
+static void cnic_spq_completion(struct cnic_dev *dev, int cmd, u32 count)
{
struct cnic_local *cp = dev->cnic_priv;
struct cnic_eth_dev *ethdev = cp->ethdev;
struct drv_ctl_info info;
- info.cmd = DRV_CTL_COMPLETION_CMD;
- info.data.comp.comp_count = count;
+ info.cmd = cmd;
+ info.data.credit.credit_count = count;
ethdev->drv_ctl(dev->netdev, &info);
}
@@ -274,8 +277,9 @@ static int cnic_send_nlmsg(struct cnic_local *cp, u32 type,
u16 len = 0;
u32 msg_type = ISCSI_KEVENT_IF_DOWN;
struct cnic_ulp_ops *ulp_ops;
+ struct cnic_uio_dev *udev = cp->udev;
- if (cp->uio_dev == -1)
+ if (!udev || udev->uio_dev == -1)
return -ENODEV;
if (csk) {
@@ -406,8 +410,7 @@ static void cnic_uio_stop(void)
list_for_each_entry(dev, &cnic_dev_list, list) {
struct cnic_local *cp = dev->cnic_priv;
- if (cp->cnic_uinfo)
- cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
+ cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
}
read_unlock(&cnic_dev_lock);
}
@@ -768,31 +771,45 @@ static void cnic_free_context(struct cnic_dev *dev)
}
}
-static void cnic_free_resc(struct cnic_dev *dev)
+static void __cnic_free_uio(struct cnic_uio_dev *udev)
{
- struct cnic_local *cp = dev->cnic_priv;
- int i = 0;
+ uio_unregister_device(&udev->cnic_uinfo);
- if (cp->cnic_uinfo) {
- while (cp->uio_dev != -1 && i < 15) {
- msleep(100);
- i++;
- }
- uio_unregister_device(cp->cnic_uinfo);
- kfree(cp->cnic_uinfo);
- cp->cnic_uinfo = NULL;
+ if (udev->l2_buf) {
+ dma_free_coherent(&udev->pdev->dev, udev->l2_buf_size,
+ udev->l2_buf, udev->l2_buf_map);
+ udev->l2_buf = NULL;
}
- if (cp->l2_buf) {
- dma_free_coherent(&dev->pcidev->dev, cp->l2_buf_size,
- cp->l2_buf, cp->l2_buf_map);
- cp->l2_buf = NULL;
+ if (udev->l2_ring) {
+ dma_free_coherent(&udev->pdev->dev, udev->l2_ring_size,
+ udev->l2_ring, udev->l2_ring_map);
+ udev->l2_ring = NULL;
}
- if (cp->l2_ring) {
- dma_free_coherent(&dev->pcidev->dev, cp->l2_ring_size,
- cp->l2_ring, cp->l2_ring_map);
- cp->l2_ring = NULL;
+ pci_dev_put(udev->pdev);
+ kfree(udev);
+}
+
+static void cnic_free_uio(struct cnic_uio_dev *udev)
+{
+ if (!udev)
+ return;
+
+ write_lock(&cnic_dev_lock);
+ list_del_init(&udev->list);
+ write_unlock(&cnic_dev_lock);
+ __cnic_free_uio(udev);
+}
+
+static void cnic_free_resc(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_uio_dev *udev = cp->udev;
+
+ if (udev) {
+ udev->dev = NULL;
+ cp->udev = NULL;
}
cnic_free_context(dev);
@@ -894,37 +911,68 @@ static int cnic_alloc_kcq(struct cnic_dev *dev, struct kcq_info *info)
return 0;
}
-static int cnic_alloc_l2_rings(struct cnic_dev *dev, int pages)
+static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages)
{
struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_uio_dev *udev;
+
+ read_lock(&cnic_dev_lock);
+ list_for_each_entry(udev, &cnic_udev_list, list) {
+ if (udev->pdev == dev->pcidev) {
+ udev->dev = dev;
+ cp->udev = udev;
+ read_unlock(&cnic_dev_lock);
+ return 0;
+ }
+ }
+ read_unlock(&cnic_dev_lock);
+
+ udev = kzalloc(sizeof(struct cnic_uio_dev), GFP_ATOMIC);
+ if (!udev)
+ return -ENOMEM;
- cp->l2_ring_size = pages * BCM_PAGE_SIZE;
- cp->l2_ring = dma_alloc_coherent(&dev->pcidev->dev, cp->l2_ring_size,
- &cp->l2_ring_map,
- GFP_KERNEL | __GFP_COMP);
- if (!cp->l2_ring)
+ udev->uio_dev = -1;
+
+ udev->dev = dev;
+ udev->pdev = dev->pcidev;
+ udev->l2_ring_size = pages * BCM_PAGE_SIZE;
+ udev->l2_ring = dma_alloc_coherent(&udev->pdev->dev, udev->l2_ring_size,
+ &udev->l2_ring_map,
+ GFP_KERNEL | __GFP_COMP);
+ if (!udev->l2_ring)
return -ENOMEM;
- cp->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size;
- cp->l2_buf_size = PAGE_ALIGN(cp->l2_buf_size);
- cp->l2_buf = dma_alloc_coherent(&dev->pcidev->dev, cp->l2_buf_size,
- &cp->l2_buf_map,
- GFP_KERNEL | __GFP_COMP);
- if (!cp->l2_buf)
+ udev->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size;
+ udev->l2_buf_size = PAGE_ALIGN(udev->l2_buf_size);
+ udev->l2_buf = dma_alloc_coherent(&udev->pdev->dev, udev->l2_buf_size,
+ &udev->l2_buf_map,
+ GFP_KERNEL | __GFP_COMP);
+ if (!udev->l2_buf)
return -ENOMEM;
+ write_lock(&cnic_dev_lock);
+ list_add(&udev->list, &cnic_udev_list);
+ write_unlock(&cnic_dev_lock);
+
+ pci_dev_get(udev->pdev);
+
+ cp->udev = udev;
+
return 0;
}
-static int cnic_alloc_uio(struct cnic_dev *dev) {
+static int cnic_init_uio(struct cnic_dev *dev)
+{
struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_uio_dev *udev = cp->udev;
struct uio_info *uinfo;
- int ret;
+ int ret = 0;
- uinfo = kzalloc(sizeof(*uinfo), GFP_ATOMIC);
- if (!uinfo)
+ if (!udev)
return -ENOMEM;
+ uinfo = &udev->cnic_uinfo;
+
uinfo->mem[0].addr = dev->netdev->base_addr;
uinfo->mem[0].internal_addr = dev->regview;
uinfo->mem[0].size = dev->netdev->mem_end - dev->netdev->mem_start;
@@ -932,7 +980,7 @@ static int cnic_alloc_uio(struct cnic_dev *dev) {
if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
uinfo->mem[1].addr = (unsigned long) cp->status_blk.gen &
- PAGE_MASK;
+ PAGE_MASK;
if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9;
else
@@ -942,19 +990,19 @@ static int cnic_alloc_uio(struct cnic_dev *dev) {
} else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
uinfo->mem[1].addr = (unsigned long) cp->bnx2x_def_status_blk &
PAGE_MASK;
- uinfo->mem[1].size = sizeof(struct host_def_status_block);
+ uinfo->mem[1].size = sizeof(*cp->bnx2x_def_status_blk);
uinfo->name = "bnx2x_cnic";
}
uinfo->mem[1].memtype = UIO_MEM_LOGICAL;
- uinfo->mem[2].addr = (unsigned long) cp->l2_ring;
- uinfo->mem[2].size = cp->l2_ring_size;
+ uinfo->mem[2].addr = (unsigned long) udev->l2_ring;
+ uinfo->mem[2].size = udev->l2_ring_size;
uinfo->mem[2].memtype = UIO_MEM_LOGICAL;
- uinfo->mem[3].addr = (unsigned long) cp->l2_buf;
- uinfo->mem[3].size = cp->l2_buf_size;
+ uinfo->mem[3].addr = (unsigned long) udev->l2_buf;
+ uinfo->mem[3].size = udev->l2_buf_size;
uinfo->mem[3].memtype = UIO_MEM_LOGICAL;
uinfo->version = CNIC_MODULE_VERSION;
@@ -963,16 +1011,17 @@ static int cnic_alloc_uio(struct cnic_dev *dev) {
uinfo->open = cnic_uio_open;
uinfo->release = cnic_uio_close;
- uinfo->priv = dev;
+ if (udev->uio_dev == -1) {
+ if (!uinfo->priv) {
+ uinfo->priv = udev;
- ret = uio_register_device(&dev->pcidev->dev, uinfo);
- if (ret) {
- kfree(uinfo);
- return ret;
+ ret = uio_register_device(&udev->pdev->dev, uinfo);
+ }
+ } else {
+ cnic_init_rings(dev);
}
- cp->cnic_uinfo = uinfo;
- return 0;
+ return ret;
}
static int cnic_alloc_bnx2_resc(struct cnic_dev *dev)
@@ -993,11 +1042,11 @@ static int cnic_alloc_bnx2_resc(struct cnic_dev *dev)
if (ret)
goto error;
- ret = cnic_alloc_l2_rings(dev, 2);
+ ret = cnic_alloc_uio_rings(dev, 2);
if (ret)
goto error;
- ret = cnic_alloc_uio(dev);
+ ret = cnic_init_uio(dev);
if (ret)
goto error;
@@ -1022,13 +1071,13 @@ static int cnic_alloc_bnx2x_context(struct cnic_dev *dev)
if (blks > cp->ethdev->ctx_tbl_len)
return -ENOMEM;
- cp->ctx_arr = kzalloc(blks * sizeof(struct cnic_ctx), GFP_KERNEL);
+ cp->ctx_arr = kcalloc(blks, sizeof(struct cnic_ctx), GFP_KERNEL);
if (cp->ctx_arr == NULL)
return -ENOMEM;
cp->ctx_blks = blks;
cp->ctx_blk_size = ctx_blk_size;
- if (BNX2X_CHIP_IS_E1H(cp->chip_id))
+ if (!BNX2X_CHIP_IS_57710(cp->chip_id))
cp->ctx_align = 0;
else
cp->ctx_align = ctx_blk_size;
@@ -1063,6 +1112,8 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
int i, j, n, ret, pages;
struct cnic_dma *kwq_16_dma = &cp->kwq_16_data_info;
+ cp->iro_arr = ethdev->iro_arr;
+
cp->max_cid_space = MAX_ISCSI_TBL_SZ;
cp->iscsi_start_cid = start_cid;
if (start_cid < BNX2X_ISCSI_START_CID) {
@@ -1127,15 +1178,13 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
cp->bnx2x_def_status_blk = cp->ethdev->irq_arr[1].status_blk;
- memset(cp->status_blk.bnx2x, 0, sizeof(*cp->status_blk.bnx2x));
-
cp->l2_rx_ring_size = 15;
- ret = cnic_alloc_l2_rings(dev, 4);
+ ret = cnic_alloc_uio_rings(dev, 4);
if (ret)
goto error;
- ret = cnic_alloc_uio(dev);
+ ret = cnic_init_uio(dev);
if (ret)
goto error;
@@ -1209,9 +1258,9 @@ static int cnic_submit_kwqe_16(struct cnic_dev *dev, u32 cmd, u32 cid,
kwqe.hdr.conn_and_cmd_data =
cpu_to_le32(((cmd << SPE_HDR_CMD_ID_SHIFT) |
- BNX2X_HW_CID(cid, cp->func)));
+ BNX2X_HW_CID(cp, cid)));
kwqe.hdr.type = cpu_to_le16(type);
- kwqe.hdr.reserved = 0;
+ kwqe.hdr.reserved1 = 0;
kwqe.data.phy_address.lo = cpu_to_le32(l5_data->phy_address.lo);
kwqe.data.phy_address.hi = cpu_to_le32(l5_data->phy_address.hi);
@@ -1246,8 +1295,8 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
{
struct cnic_local *cp = dev->cnic_priv;
struct iscsi_kwqe_init1 *req1 = (struct iscsi_kwqe_init1 *) kwqe;
- int func = cp->func, pages;
- int hq_bds;
+ int hq_bds, pages;
+ u32 pfid = cp->pfid;
cp->num_iscsi_tasks = req1->num_tasks_per_conn;
cp->num_ccells = req1->num_ccells_per_conn;
@@ -1264,60 +1313,60 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
return 0;
/* init Tstorm RAM */
- CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_RQ_SIZE_OFFSET(func),
+ CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_RQ_SIZE_OFFSET(pfid),
req1->rq_num_wqes);
- CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_PAGE_SIZE_OFFSET(func),
+ CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
PAGE_SIZE);
CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
- TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT);
+ TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
CNIC_WR16(dev, BAR_TSTRORM_INTMEM +
- TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(func),
+ TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
req1->num_tasks_per_conn);
/* init Ustorm RAM */
CNIC_WR16(dev, BAR_USTRORM_INTMEM +
- USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(func),
+ USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfid),
req1->rq_buffer_size);
- CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_PAGE_SIZE_OFFSET(func),
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
PAGE_SIZE);
CNIC_WR8(dev, BAR_USTRORM_INTMEM +
- USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT);
+ USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
CNIC_WR16(dev, BAR_USTRORM_INTMEM +
- USTORM_ISCSI_NUM_OF_TASKS_OFFSET(func),
+ USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
req1->num_tasks_per_conn);
- CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_RQ_SIZE_OFFSET(func),
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_RQ_SIZE_OFFSET(pfid),
req1->rq_num_wqes);
- CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_CQ_SIZE_OFFSET(func),
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_CQ_SIZE_OFFSET(pfid),
req1->cq_num_wqes);
- CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_R2TQ_SIZE_OFFSET(func),
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_R2TQ_SIZE_OFFSET(pfid),
cp->num_iscsi_tasks * BNX2X_ISCSI_MAX_PENDING_R2TS);
/* init Xstorm RAM */
- CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_PAGE_SIZE_OFFSET(func),
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
PAGE_SIZE);
CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT);
+ XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
CNIC_WR16(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(func),
+ XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
req1->num_tasks_per_conn);
- CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_HQ_SIZE_OFFSET(func),
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_HQ_SIZE_OFFSET(pfid),
hq_bds);
- CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_SQ_SIZE_OFFSET(func),
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_SQ_SIZE_OFFSET(pfid),
req1->num_tasks_per_conn);
- CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_R2TQ_SIZE_OFFSET(func),
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_R2TQ_SIZE_OFFSET(pfid),
cp->num_iscsi_tasks * BNX2X_ISCSI_MAX_PENDING_R2TS);
/* init Cstorm RAM */
- CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_PAGE_SIZE_OFFSET(func),
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
PAGE_SIZE);
CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT);
+ CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(func),
+ CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
req1->num_tasks_per_conn);
- CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_CQ_SIZE_OFFSET(func),
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_CQ_SIZE_OFFSET(pfid),
req1->cq_num_wqes);
- CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_HQ_SIZE_OFFSET(func),
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_HQ_SIZE_OFFSET(pfid),
hq_bds);
return 0;
@@ -1327,7 +1376,7 @@ static int cnic_bnx2x_iscsi_init2(struct cnic_dev *dev, struct kwqe *kwqe)
{
struct iscsi_kwqe_init2 *req2 = (struct iscsi_kwqe_init2 *) kwqe;
struct cnic_local *cp = dev->cnic_priv;
- int func = cp->func;
+ u32 pfid = cp->pfid;
struct iscsi_kcqe kcqe;
struct kcqe *cqes[1];
@@ -1339,21 +1388,21 @@ static int cnic_bnx2x_iscsi_init2(struct cnic_dev *dev, struct kwqe *kwqe)
}
CNIC_WR(dev, BAR_TSTRORM_INTMEM +
- TSTORM_ISCSI_ERROR_BITMAP_OFFSET(func), req2->error_bit_map[0]);
+ TSTORM_ISCSI_ERROR_BITMAP_OFFSET(pfid), req2->error_bit_map[0]);
CNIC_WR(dev, BAR_TSTRORM_INTMEM +
- TSTORM_ISCSI_ERROR_BITMAP_OFFSET(func) + 4,
+ TSTORM_ISCSI_ERROR_BITMAP_OFFSET(pfid) + 4,
req2->error_bit_map[1]);
CNIC_WR16(dev, BAR_USTRORM_INTMEM +
- USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(func), req2->max_cq_sqn);
+ USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfid), req2->max_cq_sqn);
CNIC_WR(dev, BAR_USTRORM_INTMEM +
- USTORM_ISCSI_ERROR_BITMAP_OFFSET(func), req2->error_bit_map[0]);
+ USTORM_ISCSI_ERROR_BITMAP_OFFSET(pfid), req2->error_bit_map[0]);
CNIC_WR(dev, BAR_USTRORM_INTMEM +
- USTORM_ISCSI_ERROR_BITMAP_OFFSET(func) + 4,
+ USTORM_ISCSI_ERROR_BITMAP_OFFSET(pfid) + 4,
req2->error_bit_map[1]);
CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(func), req2->max_cq_sqn);
+ CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfid), req2->max_cq_sqn);
kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_SUCCESS;
@@ -1461,7 +1510,7 @@ static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[],
struct cnic_context *ctx = &cp->ctx_tbl[req1->iscsi_conn_id];
struct cnic_iscsi *iscsi = ctx->proto.iscsi;
u32 cid = ctx->cid;
- u32 hw_cid = BNX2X_HW_CID(cid, cp->func);
+ u32 hw_cid = BNX2X_HW_CID(cp, cid);
struct iscsi_context *ictx;
struct regpair context_addr;
int i, j, n = 2, n_max;
@@ -1527,8 +1576,10 @@ static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[],
ictx->tstorm_st_context.tcp.cwnd = 0x5A8;
ictx->tstorm_st_context.tcp.flags2 |=
TSTORM_TCP_ST_CONTEXT_SECTION_DA_EN;
+ ictx->tstorm_st_context.tcp.ooo_support_mode =
+ TCP_TSTORM_OOO_DROP_AND_PROC_ACK;
- ictx->timers_context.flags |= ISCSI_TIMERS_BLOCK_CONTEXT_CONN_VALID_FLG;
+ ictx->timers_context.flags |= TIMERS_BLOCK_CONTEXT_CONN_VALID_FLG;
ictx->ustorm_st_context.ring.rq.pbl_base.lo =
req2->rq_page_table_addr_lo;
@@ -1627,10 +1678,11 @@ static int cnic_bnx2x_iscsi_ofld1(struct cnic_dev *dev, struct kwqe *wqes[],
struct iscsi_kwqe_conn_offload1 *req1;
struct iscsi_kwqe_conn_offload2 *req2;
struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_context *ctx;
struct iscsi_kcqe kcqe;
struct kcqe *cqes[1];
u32 l5_cid;
- int ret;
+ int ret = 0;
if (num < 2) {
*work = num;
@@ -1654,9 +1706,15 @@ static int cnic_bnx2x_iscsi_ofld1(struct cnic_dev *dev, struct kwqe *wqes[],
kcqe.iscsi_conn_id = l5_cid;
kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE;
+ ctx = &cp->ctx_tbl[l5_cid];
+ if (test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags)) {
+ kcqe.completion_status =
+ ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY;
+ goto done;
+ }
+
if (atomic_inc_return(&cp->iscsi_conn) > dev->max_iscsi_conn) {
atomic_dec(&cp->iscsi_conn);
- ret = 0;
goto done;
}
ret = cnic_alloc_bnx2x_conn_resc(dev, l5_cid);
@@ -1673,8 +1731,7 @@ static int cnic_bnx2x_iscsi_ofld1(struct cnic_dev *dev, struct kwqe *wqes[],
}
kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_SUCCESS;
- kcqe.iscsi_conn_context_id = BNX2X_HW_CID(cp->ctx_tbl[l5_cid].cid,
- cp->func);
+ kcqe.iscsi_conn_context_id = BNX2X_HW_CID(cp, cp->ctx_tbl[l5_cid].cid);
done:
cqes[0] = (struct kcqe *) &kcqe;
@@ -1707,40 +1764,66 @@ static int cnic_bnx2x_iscsi_update(struct cnic_dev *dev, struct kwqe *kwqe)
return ret;
}
+static int cnic_bnx2x_destroy_ramrod(struct cnic_dev *dev, u32 l5_cid)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
+ union l5cm_specific_data l5_data;
+ int ret;
+ u32 hw_cid, type;
+
+ init_waitqueue_head(&ctx->waitq);
+ ctx->wait_cond = 0;
+ memset(&l5_data, 0, sizeof(l5_data));
+ hw_cid = BNX2X_HW_CID(cp, ctx->cid);
+ type = (NONE_CONNECTION_TYPE << SPE_HDR_CONN_TYPE_SHIFT)
+ & SPE_HDR_CONN_TYPE;
+ type |= ((cp->pfid << SPE_HDR_FUNCTION_ID_SHIFT) &
+ SPE_HDR_FUNCTION_ID);
+
+ ret = cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_COMMON_CFC_DEL,
+ hw_cid, type, &l5_data);
+
+ if (ret == 0)
+ wait_event(ctx->waitq, ctx->wait_cond);
+
+ return ret;
+}
+
static int cnic_bnx2x_iscsi_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
{
struct cnic_local *cp = dev->cnic_priv;
struct iscsi_kwqe_conn_destroy *req =
(struct iscsi_kwqe_conn_destroy *) kwqe;
- union l5cm_specific_data l5_data;
u32 l5_cid = req->reserved0;
struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
int ret = 0;
struct iscsi_kcqe kcqe;
struct kcqe *cqes[1];
- if (!(ctx->ctx_flags & CTX_FL_OFFLD_START))
+ if (!test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags))
goto skip_cfc_delete;
- while (!time_after(jiffies, ctx->timestamp + (2 * HZ)))
- msleep(250);
+ if (!time_after(jiffies, ctx->timestamp + (2 * HZ))) {
+ unsigned long delta = ctx->timestamp + (2 * HZ) - jiffies;
- init_waitqueue_head(&ctx->waitq);
- ctx->wait_cond = 0;
- memset(&l5_data, 0, sizeof(l5_data));
- ret = cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_ETH_CFC_DEL,
- req->context_id,
- ETH_CONNECTION_TYPE |
- (1 << SPE_HDR_COMMON_RAMROD_SHIFT),
- &l5_data);
- if (ret == 0)
- wait_event(ctx->waitq, ctx->wait_cond);
+ if (delta > (2 * HZ))
+ delta = 0;
+
+ set_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags);
+ queue_delayed_work(cnic_wq, &cp->delete_task, delta);
+ goto destroy_reply;
+ }
+
+ ret = cnic_bnx2x_destroy_ramrod(dev, l5_cid);
skip_cfc_delete:
cnic_free_bnx2x_conn_resc(dev, l5_cid);
atomic_dec(&cp->iscsi_conn);
+ clear_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags);
+destroy_reply:
memset(&kcqe, 0, sizeof(kcqe));
kcqe.op_code = ISCSI_KCQE_OPCODE_DESTROY_CONN;
kcqe.iscsi_conn_id = l5_cid;
@@ -1805,37 +1888,37 @@ static void cnic_init_storm_conn_bufs(struct cnic_dev *dev,
static void cnic_init_bnx2x_mac(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
- int func = CNIC_FUNC(cp);
+ u32 pfid = cp->pfid;
u8 *mac = dev->mac_addr;
CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(func), mac[0]);
+ XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(pfid), mac[0]);
CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(func), mac[1]);
+ XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfid), mac[1]);
CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(func), mac[2]);
+ XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfid), mac[2]);
CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(func), mac[3]);
+ XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfid), mac[3]);
CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(func), mac[4]);
+ XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfid), mac[4]);
CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(func), mac[5]);
+ XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfid), mac[5]);
CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
- TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(func), mac[5]);
+ TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfid), mac[5]);
CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
- TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(func) + 1,
+ TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfid) + 1,
mac[4]);
CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
- TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func), mac[3]);
+ TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfid), mac[3]);
CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
- TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func) + 1,
+ TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfid) + 1,
mac[2]);
CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
- TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func) + 2,
+ TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfid) + 2,
mac[1]);
CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
- TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func) + 3,
+ TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfid) + 3,
mac[0]);
}
@@ -1851,10 +1934,10 @@ static void cnic_bnx2x_set_tcp_timestamp(struct cnic_dev *dev, int tcp_ts)
}
CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->func), xstorm_flags);
+ XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->pfid), xstorm_flags);
CNIC_WR16(dev, BAR_TSTRORM_INTMEM +
- TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->func), tstorm_flags);
+ TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->pfid), tstorm_flags);
}
static int cnic_bnx2x_connect(struct cnic_dev *dev, struct kwqe *wqes[],
@@ -1929,7 +2012,7 @@ static int cnic_bnx2x_connect(struct cnic_dev *dev, struct kwqe *wqes[],
cnic_init_storm_conn_bufs(dev, kwqe1, kwqe3, conn_buf);
CNIC_WR16(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_LOCAL_VLAN_OFFSET(cp->func), csk->vlan_id);
+ XSTORM_ISCSI_LOCAL_VLAN_OFFSET(cp->pfid), csk->vlan_id);
cnic_bnx2x_set_tcp_timestamp(dev,
kwqe1->tcp_flags & L4_KWQ_CONNECT_REQ1_TIME_STAMP);
@@ -1937,7 +2020,7 @@ static int cnic_bnx2x_connect(struct cnic_dev *dev, struct kwqe *wqes[],
ret = cnic_submit_kwqe_16(dev, L5CM_RAMROD_CMD_ID_TCP_CONNECT,
kwqe1->cid, ISCSI_CONNECTION_TYPE, &l5_data);
if (!ret)
- ctx->ctx_flags |= CTX_FL_OFFLD_START;
+ set_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags);
return ret;
}
@@ -2063,7 +2146,7 @@ static int cnic_submit_bnx2x_kwqes(struct cnic_dev *dev, struct kwqe *wqes[],
static void service_kcqes(struct cnic_dev *dev, int num_cqes)
{
struct cnic_local *cp = dev->cnic_priv;
- int i, j;
+ int i, j, comp = 0;
i = 0;
j = 1;
@@ -2074,7 +2157,7 @@ static void service_kcqes(struct cnic_dev *dev, int num_cqes)
u32 kcqe_layer = kcqe_op_flag & KCQE_FLAGS_LAYER_MASK;
if (unlikely(kcqe_op_flag & KCQE_RAMROD_COMPLETION))
- cnic_kwq_completion(dev, 1);
+ comp++;
while (j < num_cqes) {
u32 next_op = cp->completed_kcq[i + j]->kcqe_op_flag;
@@ -2083,7 +2166,7 @@ static void service_kcqes(struct cnic_dev *dev, int num_cqes)
break;
if (unlikely(next_op & KCQE_RAMROD_COMPLETION))
- cnic_kwq_completion(dev, 1);
+ comp++;
j++;
}
@@ -2113,6 +2196,8 @@ end:
i += j;
j = 1;
}
+ if (unlikely(comp))
+ cnic_spq_completion(dev, DRV_CTL_RET_L5_SPQ_CREDIT_CMD, comp);
}
static u16 cnic_bnx2_next_idx(u16 idx)
@@ -2171,8 +2256,9 @@ static int cnic_get_kcqes(struct cnic_dev *dev, struct kcq_info *info)
static int cnic_l2_completion(struct cnic_local *cp)
{
u16 hw_cons, sw_cons;
+ struct cnic_uio_dev *udev = cp->udev;
union eth_rx_cqe *cqe, *cqe_ring = (union eth_rx_cqe *)
- (cp->l2_ring + (2 * BCM_PAGE_SIZE));
+ (udev->l2_ring + (2 * BCM_PAGE_SIZE));
u32 cmd;
int comp = 0;
@@ -2203,13 +2289,14 @@ static int cnic_l2_completion(struct cnic_local *cp)
static void cnic_chk_pkt_rings(struct cnic_local *cp)
{
- u16 rx_cons = *cp->rx_cons_ptr;
- u16 tx_cons = *cp->tx_cons_ptr;
+ u16 rx_cons, tx_cons;
int comp = 0;
- if (!test_bit(CNIC_F_CNIC_UP, &cp->dev->flags))
+ if (!test_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags))
return;
+ rx_cons = *cp->rx_cons_ptr;
+ tx_cons = *cp->tx_cons_ptr;
if (cp->tx_cons != tx_cons || cp->rx_cons != rx_cons) {
if (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags))
comp = cnic_l2_completion(cp);
@@ -2217,7 +2304,8 @@ static void cnic_chk_pkt_rings(struct cnic_local *cp)
cp->tx_cons = tx_cons;
cp->rx_cons = rx_cons;
- uio_event_notify(cp->cnic_uinfo);
+ if (cp->udev)
+ uio_event_notify(&cp->udev->cnic_uinfo);
}
if (comp)
clear_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags);
@@ -2318,14 +2406,38 @@ static inline void cnic_ack_bnx2x_int(struct cnic_dev *dev, u8 id, u8 storm,
CNIC_WR(dev, hc_addr, (*(u32 *)&igu_ack));
}
+static void cnic_ack_igu_sb(struct cnic_dev *dev, u8 igu_sb_id, u8 segment,
+ u16 index, u8 op, u8 update)
+{
+ struct igu_regular cmd_data;
+ u32 igu_addr = BAR_IGU_INTMEM + (IGU_CMD_INT_ACK_BASE + igu_sb_id) * 8;
+
+ cmd_data.sb_id_and_flags =
+ (index << IGU_REGULAR_SB_INDEX_SHIFT) |
+ (segment << IGU_REGULAR_SEGMENT_ACCESS_SHIFT) |
+ (update << IGU_REGULAR_BUPDATE_SHIFT) |
+ (op << IGU_REGULAR_ENABLE_INT_SHIFT);
+
+
+ CNIC_WR(dev, igu_addr, cmd_data.sb_id_and_flags);
+}
+
static void cnic_ack_bnx2x_msix(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
- cnic_ack_bnx2x_int(dev, cp->status_blk_num, CSTORM_ID, 0,
+ cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, CSTORM_ID, 0,
IGU_INT_DISABLE, 0);
}
+static void cnic_ack_bnx2x_e2_msix(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+
+ cnic_ack_igu_sb(dev, cp->bnx2x_igu_sb_id, IGU_SEG_ACCESS_DEF, 0,
+ IGU_INT_DISABLE, 0);
+}
+
static u32 cnic_service_bnx2x_kcq(struct cnic_dev *dev, struct kcq_info *info)
{
u32 last_status = *info->status_idx_ptr;
@@ -2357,8 +2469,12 @@ static void cnic_service_bnx2x_bh(unsigned long data)
status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq1);
CNIC_WR16(dev, cp->kcq1.io_addr, cp->kcq1.sw_prod_idx + MAX_KCQ_IDX);
- cnic_ack_bnx2x_int(dev, cp->status_blk_num, CSTORM_ID,
- status_idx, IGU_INT_ENABLE, 1);
+ if (BNX2X_CHIP_IS_E2(cp->chip_id))
+ cnic_ack_igu_sb(dev, cp->bnx2x_igu_sb_id, IGU_SEG_ACCESS_DEF,
+ status_idx, IGU_INT_ENABLE, 1);
+ else
+ cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, USTORM_ID,
+ status_idx, IGU_INT_ENABLE, 1);
}
static int cnic_service_bnx2x(void *data, void *status_blk)
@@ -2379,8 +2495,7 @@ static void cnic_ulp_stop(struct cnic_dev *dev)
struct cnic_local *cp = dev->cnic_priv;
int if_type;
- if (cp->cnic_uinfo)
- cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
+ cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
struct cnic_ulp_ops *ulp_ops;
@@ -2728,6 +2843,13 @@ static int cnic_cm_create(struct cnic_dev *dev, int ulp_type, u32 cid,
if (l5_cid >= MAX_CM_SK_TBL_SZ)
return -EINVAL;
+ if (cp->ctx_tbl) {
+ struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
+
+ if (test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags))
+ return -EAGAIN;
+ }
+
csk1 = &cp->csk_tbl[l5_cid];
if (atomic_read(&csk1->ref_count))
return -EAGAIN;
@@ -3279,39 +3401,106 @@ static void cnic_close_bnx2x_conn(struct cnic_sock *csk, u32 opcode)
static void cnic_cm_stop_bnx2x_hw(struct cnic_dev *dev)
{
+ struct cnic_local *cp = dev->cnic_priv;
+ int i;
+
+ if (!cp->ctx_tbl)
+ return;
+
+ if (!netif_running(dev->netdev))
+ return;
+
+ for (i = 0; i < cp->max_cid_space; i++) {
+ struct cnic_context *ctx = &cp->ctx_tbl[i];
+
+ while (test_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags))
+ msleep(10);
+
+ if (test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags))
+ netdev_warn(dev->netdev, "CID %x not deleted\n",
+ ctx->cid);
+ }
+
+ cancel_delayed_work(&cp->delete_task);
+ flush_workqueue(cnic_wq);
+
+ if (atomic_read(&cp->iscsi_conn) != 0)
+ netdev_warn(dev->netdev, "%d iSCSI connections not destroyed\n",
+ atomic_read(&cp->iscsi_conn));
}
static int cnic_cm_init_bnx2x_hw(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
- int func = CNIC_FUNC(cp);
+ u32 pfid = cp->pfid;
+ u32 port = CNIC_PORT(cp);
cnic_init_bnx2x_mac(dev);
cnic_bnx2x_set_tcp_timestamp(dev, 1);
CNIC_WR16(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_LOCAL_VLAN_OFFSET(func), 0);
+ XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfid), 0);
CNIC_WR(dev, BAR_XSTRORM_INTMEM +
- XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_ENABLED_OFFSET(func), 1);
+ XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_ENABLED_OFFSET(port), 1);
CNIC_WR(dev, BAR_XSTRORM_INTMEM +
- XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_MAX_COUNT_OFFSET(func),
+ XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_MAX_COUNT_OFFSET(port),
DEF_MAX_DA_COUNT);
CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(func), DEF_TTL);
+ XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(pfid), DEF_TTL);
CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(func), DEF_TOS);
+ XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(pfid), DEF_TOS);
CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(func), 2);
+ XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(pfid), 2);
CNIC_WR(dev, BAR_XSTRORM_INTMEM +
- XSTORM_TCP_TX_SWS_TIMER_VAL_OFFSET(func), DEF_SWS_TIMER);
+ XSTORM_TCP_TX_SWS_TIMER_VAL_OFFSET(pfid), DEF_SWS_TIMER);
- CNIC_WR(dev, BAR_TSTRORM_INTMEM + TSTORM_TCP_MAX_CWND_OFFSET(func),
+ CNIC_WR(dev, BAR_TSTRORM_INTMEM + TSTORM_TCP_MAX_CWND_OFFSET(pfid),
DEF_MAX_CWND);
return 0;
}
+static void cnic_delete_task(struct work_struct *work)
+{
+ struct cnic_local *cp;
+ struct cnic_dev *dev;
+ u32 i;
+ int need_resched = 0;
+
+ cp = container_of(work, struct cnic_local, delete_task.work);
+ dev = cp->dev;
+
+ for (i = 0; i < cp->max_cid_space; i++) {
+ struct cnic_context *ctx = &cp->ctx_tbl[i];
+
+ if (!test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags) ||
+ !test_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags))
+ continue;
+
+ if (!time_after(jiffies, ctx->timestamp + (2 * HZ))) {
+ need_resched = 1;
+ continue;
+ }
+
+ if (!test_and_clear_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags))
+ continue;
+
+ cnic_bnx2x_destroy_ramrod(dev, i);
+
+ cnic_free_bnx2x_conn_resc(dev, i);
+ if (ctx->ulp_proto_id == CNIC_ULP_ISCSI)
+ atomic_dec(&cp->iscsi_conn);
+
+ clear_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags);
+ }
+
+ if (need_resched)
+ queue_delayed_work(cnic_wq, &cp->delete_task,
+ msecs_to_jiffies(10));
+
+}
+
static int cnic_cm_open(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -3326,6 +3515,8 @@ static int cnic_cm_open(struct cnic_dev *dev)
if (err)
goto err_out;
+ INIT_DELAYED_WORK(&cp->delete_task, cnic_delete_task);
+
dev->cm_create = cnic_cm_create;
dev->cm_destroy = cnic_cm_destroy;
dev->cm_connect = cnic_cm_connect;
@@ -3418,11 +3609,24 @@ static void cnic_free_irq(struct cnic_dev *dev)
if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
cp->disable_int_sync(dev);
- tasklet_disable(&cp->cnic_irq_task);
+ tasklet_kill(&cp->cnic_irq_task);
free_irq(ethdev->irq_arr[0].vector, dev);
}
}
+static int cnic_request_irq(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ int err;
+
+ err = request_irq(ethdev->irq_arr[0].vector, cnic_irq, 0, "cnic", dev);
+ if (err)
+ tasklet_disable(&cp->cnic_irq_task);
+
+ return err;
+}
+
static int cnic_init_bnx2_irq(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -3443,12 +3647,10 @@ static int cnic_init_bnx2_irq(struct cnic_dev *dev)
cp->last_status_idx = cp->status_blk.bnx2->status_idx;
tasklet_init(&cp->cnic_irq_task, cnic_service_bnx2_msix,
(unsigned long) dev);
- err = request_irq(ethdev->irq_arr[0].vector, cnic_irq, 0,
- "cnic", dev);
- if (err) {
- tasklet_disable(&cp->cnic_irq_task);
+ err = cnic_request_irq(dev);
+ if (err)
return err;
- }
+
while (cp->status_blk.bnx2->status_completion_producer_index &&
i < 10) {
CNIC_WR(dev, BNX2_HC_COALESCE_NOW,
@@ -3515,11 +3717,12 @@ static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
struct cnic_eth_dev *ethdev = cp->ethdev;
+ struct cnic_uio_dev *udev = cp->udev;
u32 cid_addr, tx_cid, sb_id;
u32 val, offset0, offset1, offset2, offset3;
int i;
struct tx_bd *txbd;
- dma_addr_t buf_map;
+ dma_addr_t buf_map, ring_map = udev->l2_ring_map;
struct status_block *s_blk = cp->status_blk.gen;
sb_id = cp->status_blk_num;
@@ -3561,18 +3764,18 @@ static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev)
val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
cnic_ctx_wr(dev, cid_addr, offset1, val);
- txbd = (struct tx_bd *) cp->l2_ring;
+ txbd = (struct tx_bd *) udev->l2_ring;
- buf_map = cp->l2_buf_map;
+ buf_map = udev->l2_buf_map;
for (i = 0; i < MAX_TX_DESC_CNT; i++, txbd++) {
txbd->tx_bd_haddr_hi = (u64) buf_map >> 32;
txbd->tx_bd_haddr_lo = (u64) buf_map & 0xffffffff;
}
- val = (u64) cp->l2_ring_map >> 32;
+ val = (u64) ring_map >> 32;
cnic_ctx_wr(dev, cid_addr, offset2, val);
txbd->tx_bd_haddr_hi = val;
- val = (u64) cp->l2_ring_map & 0xffffffff;
+ val = (u64) ring_map & 0xffffffff;
cnic_ctx_wr(dev, cid_addr, offset3, val);
txbd->tx_bd_haddr_lo = val;
}
@@ -3581,10 +3784,12 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
struct cnic_eth_dev *ethdev = cp->ethdev;
+ struct cnic_uio_dev *udev = cp->udev;
u32 cid_addr, sb_id, val, coal_reg, coal_val;
int i;
struct rx_bd *rxbd;
struct status_block *s_blk = cp->status_blk.gen;
+ dma_addr_t ring_map = udev->l2_ring_map;
sb_id = cp->status_blk_num;
cnic_init_context(dev, 2);
@@ -3618,22 +3823,22 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
val = BNX2_L2CTX_L2_STATUSB_NUM(sb_id);
cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_HOST_BDIDX, val);
- rxbd = (struct rx_bd *) (cp->l2_ring + BCM_PAGE_SIZE);
+ rxbd = (struct rx_bd *) (udev->l2_ring + BCM_PAGE_SIZE);
for (i = 0; i < MAX_RX_DESC_CNT; i++, rxbd++) {
dma_addr_t buf_map;
int n = (i % cp->l2_rx_ring_size) + 1;
- buf_map = cp->l2_buf_map + (n * cp->l2_single_buf_size);
+ buf_map = udev->l2_buf_map + (n * cp->l2_single_buf_size);
rxbd->rx_bd_len = cp->l2_single_buf_size;
rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
rxbd->rx_bd_haddr_hi = (u64) buf_map >> 32;
rxbd->rx_bd_haddr_lo = (u64) buf_map & 0xffffffff;
}
- val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) >> 32;
+ val = (u64) (ring_map + BCM_PAGE_SIZE) >> 32;
cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
rxbd->rx_bd_haddr_hi = val;
- val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) & 0xffffffff;
+ val = (u64) (ring_map + BCM_PAGE_SIZE) & 0xffffffff;
cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
rxbd->rx_bd_haddr_lo = val;
@@ -3850,42 +4055,55 @@ static int cnic_init_bnx2x_irq(struct cnic_dev *dev)
tasklet_init(&cp->cnic_irq_task, cnic_service_bnx2x_bh,
(unsigned long) dev);
- if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
- err = request_irq(ethdev->irq_arr[0].vector, cnic_irq, 0,
- "cnic", dev);
- if (err)
- tasklet_disable(&cp->cnic_irq_task);
- }
+ if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
+ err = cnic_request_irq(dev);
+
return err;
}
+static inline void cnic_storm_memset_hc_disable(struct cnic_dev *dev,
+ u16 sb_id, u8 sb_index,
+ u8 disable)
+{
+
+ u32 addr = BAR_CSTRORM_INTMEM +
+ CSTORM_STATUS_BLOCK_DATA_OFFSET(sb_id) +
+ offsetof(struct hc_status_block_data_e1x, index_data) +
+ sizeof(struct hc_index_data)*sb_index +
+ offsetof(struct hc_index_data, flags);
+ u16 flags = CNIC_RD16(dev, addr);
+ /* clear and set */
+ flags &= ~HC_INDEX_DATA_HC_ENABLED;
+ flags |= (((~disable) << HC_INDEX_DATA_HC_ENABLED_SHIFT) &
+ HC_INDEX_DATA_HC_ENABLED);
+ CNIC_WR16(dev, addr, flags);
+}
+
static void cnic_enable_bnx2x_int(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
u8 sb_id = cp->status_blk_num;
- int port = CNIC_PORT(cp);
CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
- CSTORM_SB_HC_TIMEOUT_C_OFFSET(port, sb_id,
- HC_INDEX_C_ISCSI_EQ_CONS),
- 64 / 12);
- CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
- CSTORM_SB_HC_DISABLE_C_OFFSET(port, sb_id,
- HC_INDEX_C_ISCSI_EQ_CONS), 0);
+ CSTORM_STATUS_BLOCK_DATA_OFFSET(sb_id) +
+ offsetof(struct hc_status_block_data_e1x, index_data) +
+ sizeof(struct hc_index_data)*HC_INDEX_ISCSI_EQ_CONS +
+ offsetof(struct hc_index_data, timeout), 64 / 12);
+ cnic_storm_memset_hc_disable(dev, sb_id, HC_INDEX_ISCSI_EQ_CONS, 0);
}
static void cnic_disable_bnx2x_int_sync(struct cnic_dev *dev)
{
}
-static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev)
+static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev,
+ struct client_init_ramrod_data *data)
{
struct cnic_local *cp = dev->cnic_priv;
- union eth_tx_bd_types *txbd = (union eth_tx_bd_types *) cp->l2_ring;
- struct eth_context *context;
- struct regpair context_addr;
- dma_addr_t buf_map;
- int func = CNIC_FUNC(cp);
+ struct cnic_uio_dev *udev = cp->udev;
+ union eth_tx_bd_types *txbd = (union eth_tx_bd_types *) udev->l2_ring;
+ dma_addr_t buf_map, ring_map = udev->l2_ring_map;
+ struct host_sp_status_block *sb = cp->bnx2x_def_status_blk;
int port = CNIC_PORT(cp);
int i;
int cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
@@ -3893,7 +4111,7 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev)
memset(txbd, 0, BCM_PAGE_SIZE);
- buf_map = cp->l2_buf_map;
+ buf_map = udev->l2_buf_map;
for (i = 0; i < MAX_TX_DESC_CNT; i += 3, txbd += 3) {
struct eth_tx_start_bd *start_bd = &txbd->start_bd;
struct eth_tx_bd *reg_bd = &((txbd + 2)->reg_bd);
@@ -3910,33 +4128,23 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev)
start_bd->general_data |= (1 << ETH_TX_START_BD_HDR_NBDS_SHIFT);
}
- context = cnic_get_bnx2x_ctx(dev, BNX2X_ISCSI_L2_CID, 1, &context_addr);
- val = (u64) cp->l2_ring_map >> 32;
+ val = (u64) ring_map >> 32;
txbd->next_bd.addr_hi = cpu_to_le32(val);
- context->xstorm_st_context.tx_bd_page_base_hi = val;
+ data->tx.tx_bd_page_base.hi = cpu_to_le32(val);
- val = (u64) cp->l2_ring_map & 0xffffffff;
+ val = (u64) ring_map & 0xffffffff;
txbd->next_bd.addr_lo = cpu_to_le32(val);
- context->xstorm_st_context.tx_bd_page_base_lo = val;
-
- context->cstorm_st_context.sb_index_number =
- HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS;
- context->cstorm_st_context.status_block_id = BNX2X_DEF_SB_ID;
+ data->tx.tx_bd_page_base.lo = cpu_to_le32(val);
- if (cli < MAX_X_STAT_COUNTER_ID)
- context->xstorm_st_context.statistics_data = cli |
- XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE;
-
- context->xstorm_ag_context.cdu_reserved =
- CDU_RSRVD_VALUE_TYPE_A(BNX2X_HW_CID(BNX2X_ISCSI_L2_CID, func),
- CDU_REGION_NUMBER_XCM_AG,
- ETH_CONNECTION_TYPE);
+ /* Other ramrod params */
+ data->tx.tx_sb_index_number = HC_SP_INDEX_ETH_ISCSI_CQ_CONS;
+ data->tx.tx_status_block_id = BNX2X_DEF_SB_ID;
/* reset xstorm per client statistics */
- if (cli < MAX_X_STAT_COUNTER_ID) {
+ if (cli < MAX_STAT_COUNTER_ID) {
val = BAR_XSTRORM_INTMEM +
XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
for (i = 0; i < sizeof(struct xstorm_per_client_stats) / 4; i++)
@@ -3944,111 +4152,77 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev)
}
cp->tx_cons_ptr =
- &cp->bnx2x_def_status_blk->c_def_status_block.index_values[
- HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS];
+ &sb->sp_sb.index_values[HC_SP_INDEX_ETH_ISCSI_CQ_CONS];
}
-static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev)
+static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev,
+ struct client_init_ramrod_data *data)
{
struct cnic_local *cp = dev->cnic_priv;
- struct eth_rx_bd *rxbd = (struct eth_rx_bd *) (cp->l2_ring +
+ struct cnic_uio_dev *udev = cp->udev;
+ struct eth_rx_bd *rxbd = (struct eth_rx_bd *) (udev->l2_ring +
BCM_PAGE_SIZE);
struct eth_rx_cqe_next_page *rxcqe = (struct eth_rx_cqe_next_page *)
- (cp->l2_ring + (2 * BCM_PAGE_SIZE));
- struct eth_context *context;
- struct regpair context_addr;
+ (udev->l2_ring + (2 * BCM_PAGE_SIZE));
+ struct host_sp_status_block *sb = cp->bnx2x_def_status_blk;
int i;
int port = CNIC_PORT(cp);
- int func = CNIC_FUNC(cp);
int cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
+ int cl_qzone_id = BNX2X_CL_QZONE_ID(cp, cli);
u32 val;
- struct tstorm_eth_client_config tstorm_client = {0};
+ dma_addr_t ring_map = udev->l2_ring_map;
+
+ /* General data */
+ data->general.client_id = cli;
+ data->general.statistics_en_flg = 1;
+ data->general.statistics_counter_id = cli;
+ data->general.activate_flg = 1;
+ data->general.sp_client_id = cli;
for (i = 0; i < BNX2X_MAX_RX_DESC_CNT; i++, rxbd++) {
dma_addr_t buf_map;
int n = (i % cp->l2_rx_ring_size) + 1;
- buf_map = cp->l2_buf_map + (n * cp->l2_single_buf_size);
+ buf_map = udev->l2_buf_map + (n * cp->l2_single_buf_size);
rxbd->addr_hi = cpu_to_le32((u64) buf_map >> 32);
rxbd->addr_lo = cpu_to_le32(buf_map & 0xffffffff);
}
- context = cnic_get_bnx2x_ctx(dev, BNX2X_ISCSI_L2_CID, 0, &context_addr);
- val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) >> 32;
+ val = (u64) (ring_map + BCM_PAGE_SIZE) >> 32;
rxbd->addr_hi = cpu_to_le32(val);
+ data->rx.bd_page_base.hi = cpu_to_le32(val);
- context->ustorm_st_context.common.bd_page_base_hi = val;
-
- val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) & 0xffffffff;
+ val = (u64) (ring_map + BCM_PAGE_SIZE) & 0xffffffff;
rxbd->addr_lo = cpu_to_le32(val);
-
- context->ustorm_st_context.common.bd_page_base_lo = val;
-
- context->ustorm_st_context.common.sb_index_numbers =
- BNX2X_ISCSI_RX_SB_INDEX_NUM;
- context->ustorm_st_context.common.clientId = cli;
- context->ustorm_st_context.common.status_block_id = BNX2X_DEF_SB_ID;
- if (cli < MAX_U_STAT_COUNTER_ID) {
- context->ustorm_st_context.common.flags =
- USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS;
- context->ustorm_st_context.common.statistics_counter_id = cli;
- }
- context->ustorm_st_context.common.mc_alignment_log_size = 0;
- context->ustorm_st_context.common.bd_buff_size =
- cp->l2_single_buf_size;
-
- context->ustorm_ag_context.cdu_usage =
- CDU_RSRVD_VALUE_TYPE_A(BNX2X_HW_CID(BNX2X_ISCSI_L2_CID, func),
- CDU_REGION_NUMBER_UCM_AG,
- ETH_CONNECTION_TYPE);
+ data->rx.bd_page_base.lo = cpu_to_le32(val);
rxcqe += BNX2X_MAX_RCQ_DESC_CNT;
- val = (u64) (cp->l2_ring_map + (2 * BCM_PAGE_SIZE)) >> 32;
+ val = (u64) (ring_map + (2 * BCM_PAGE_SIZE)) >> 32;
rxcqe->addr_hi = cpu_to_le32(val);
+ data->rx.cqe_page_base.hi = cpu_to_le32(val);
- CNIC_WR(dev, BAR_USTRORM_INTMEM +
- USTORM_CQE_PAGE_BASE_OFFSET(port, cli) + 4, val);
-
- CNIC_WR(dev, BAR_USTRORM_INTMEM +
- USTORM_CQE_PAGE_NEXT_OFFSET(port, cli) + 4, val);
-
- val = (u64) (cp->l2_ring_map + (2 * BCM_PAGE_SIZE)) & 0xffffffff;
+ val = (u64) (ring_map + (2 * BCM_PAGE_SIZE)) & 0xffffffff;
rxcqe->addr_lo = cpu_to_le32(val);
+ data->rx.cqe_page_base.lo = cpu_to_le32(val);
- CNIC_WR(dev, BAR_USTRORM_INTMEM +
- USTORM_CQE_PAGE_BASE_OFFSET(port, cli), val);
-
- CNIC_WR(dev, BAR_USTRORM_INTMEM +
- USTORM_CQE_PAGE_NEXT_OFFSET(port, cli), val);
-
- /* client tstorm info */
- tstorm_client.mtu = cp->l2_single_buf_size - 14;
- tstorm_client.config_flags = TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE;
-
- if (cli < MAX_T_STAT_COUNTER_ID) {
- tstorm_client.config_flags |=
- TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE;
- tstorm_client.statistics_counter_id = cli;
- }
+ /* Other ramrod params */
+ data->rx.client_qzone_id = cl_qzone_id;
+ data->rx.rx_sb_index_number = HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS;
+ data->rx.status_block_id = BNX2X_DEF_SB_ID;
- CNIC_WR(dev, BAR_TSTRORM_INTMEM +
- TSTORM_CLIENT_CONFIG_OFFSET(port, cli),
- ((u32 *)&tstorm_client)[0]);
- CNIC_WR(dev, BAR_TSTRORM_INTMEM +
- TSTORM_CLIENT_CONFIG_OFFSET(port, cli) + 4,
- ((u32 *)&tstorm_client)[1]);
+ data->rx.cache_line_alignment_log_size = L1_CACHE_SHIFT;
+ data->rx.bd_buff_size = cpu_to_le16(cp->l2_single_buf_size);
- /* reset tstorm per client statistics */
- if (cli < MAX_T_STAT_COUNTER_ID) {
+ data->rx.mtu = cpu_to_le16(cp->l2_single_buf_size - 14);
+ data->rx.outer_vlan_removal_enable_flg = 1;
+ /* reset tstorm and ustorm per client statistics */
+ if (cli < MAX_STAT_COUNTER_ID) {
val = BAR_TSTRORM_INTMEM +
TSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
for (i = 0; i < sizeof(struct tstorm_per_client_stats) / 4; i++)
CNIC_WR(dev, val + i * 4, 0);
- }
- /* reset ustorm per client statistics */
- if (cli < MAX_U_STAT_COUNTER_ID) {
val = BAR_USTRORM_INTMEM +
USTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
for (i = 0; i < sizeof(struct ustorm_per_client_stats) / 4; i++)
@@ -4056,21 +4230,22 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev)
}
cp->rx_cons_ptr =
- &cp->bnx2x_def_status_blk->u_def_status_block.index_values[
- HC_INDEX_DEF_U_ETH_ISCSI_RX_CQ_CONS];
+ &sb->sp_sb.index_values[HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS];
}
static void cnic_get_bnx2x_iscsi_info(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
- u32 base, addr, val;
+ u32 base, base2, addr, val;
int port = CNIC_PORT(cp);
dev->max_iscsi_conn = 0;
base = CNIC_RD(dev, MISC_REG_SHARED_MEM_ADDR);
- if (base < 0xa0000 || base >= 0xc0000)
+ if (base == 0)
return;
+ base2 = CNIC_RD(dev, (CNIC_PATH(cp) ? MISC_REG_GENERIC_CR_1 :
+ MISC_REG_GENERIC_CR_0));
addr = BNX2X_SHMEM_ADDR(base,
dev_info.port_hw_config[port].iscsi_mac_upper);
@@ -4103,16 +4278,25 @@ static void cnic_get_bnx2x_iscsi_info(struct cnic_dev *dev)
val16 ^= 0x1e1e;
dev->max_iscsi_conn = val16;
}
- if (BNX2X_CHIP_IS_E1H(cp->chip_id)) {
+ if (BNX2X_CHIP_IS_E1H(cp->chip_id) || BNX2X_CHIP_IS_E2(cp->chip_id)) {
int func = CNIC_FUNC(cp);
+ u32 mf_cfg_addr;
+
+ if (BNX2X_SHMEM2_HAS(base2, mf_cfg_addr))
+ mf_cfg_addr = CNIC_RD(dev, BNX2X_SHMEM2_ADDR(base2,
+ mf_cfg_addr));
+ else
+ mf_cfg_addr = base + BNX2X_SHMEM_MF_BLK_OFFSET;
+
+ addr = mf_cfg_addr +
+ offsetof(struct mf_cfg, func_mf_config[func].e1hov_tag);
- addr = BNX2X_SHMEM_ADDR(base,
- mf_cfg.func_mf_config[func].e1hov_tag);
val = CNIC_RD(dev, addr);
val &= FUNC_MF_CFG_E1HOV_TAG_MASK;
if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) {
- addr = BNX2X_SHMEM_ADDR(base,
- mf_cfg.func_mf_config[func].config);
+ addr = mf_cfg_addr +
+ offsetof(struct mf_cfg,
+ func_mf_config[func].config);
val = CNIC_RD(dev, addr);
val &= FUNC_MF_CFG_PROTOCOL_MASK;
if (val != FUNC_MF_CFG_PROTOCOL_ISCSI)
@@ -4124,10 +4308,26 @@ static void cnic_get_bnx2x_iscsi_info(struct cnic_dev *dev)
static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
int func = CNIC_FUNC(cp), ret, i;
- int port = CNIC_PORT(cp);
- u16 eq_idx;
- u8 sb_id = cp->status_blk_num;
+ u32 pfid;
+
+ if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
+ u32 val = CNIC_RD(dev, MISC_REG_PORT4MODE_EN_OVWR);
+
+ if (!(val & 1))
+ val = CNIC_RD(dev, MISC_REG_PORT4MODE_EN);
+ else
+ val = (val >> 1) & 1;
+
+ if (val)
+ cp->pfid = func >> 1;
+ else
+ cp->pfid = func & 0x6;
+ } else {
+ cp->pfid = func;
+ }
+ pfid = cp->pfid;
ret = cnic_init_id_tbl(&cp->cid_tbl, MAX_ISCSI_TBL_SZ,
cp->iscsi_start_cid);
@@ -4135,86 +4335,98 @@ static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
if (ret)
return -ENOMEM;
+ cp->bnx2x_igu_sb_id = ethdev->irq_arr[0].status_blk_num2;
+
cp->kcq1.io_addr = BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_EQ_PROD_OFFSET(func, 0);
+ CSTORM_ISCSI_EQ_PROD_OFFSET(pfid, 0);
cp->kcq1.sw_prod_idx = 0;
- cp->kcq1.hw_prod_idx_ptr =
- &cp->status_blk.bnx2x->c_status_block.index_values[
- HC_INDEX_C_ISCSI_EQ_CONS];
- cp->kcq1.status_idx_ptr =
- &cp->status_blk.bnx2x->c_status_block.status_block_index;
+ if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
+ struct host_hc_status_block_e2 *sb = cp->status_blk.gen;
+
+ cp->kcq1.hw_prod_idx_ptr =
+ &sb->sb.index_values[HC_INDEX_ISCSI_EQ_CONS];
+ cp->kcq1.status_idx_ptr =
+ &sb->sb.running_index[SM_RX_ID];
+ } else {
+ struct host_hc_status_block_e1x *sb = cp->status_blk.gen;
+
+ cp->kcq1.hw_prod_idx_ptr =
+ &sb->sb.index_values[HC_INDEX_ISCSI_EQ_CONS];
+ cp->kcq1.status_idx_ptr =
+ &sb->sb.running_index[SM_RX_ID];
+ }
cnic_get_bnx2x_iscsi_info(dev);
/* Only 1 EQ */
CNIC_WR16(dev, cp->kcq1.io_addr, MAX_KCQ_IDX);
CNIC_WR(dev, BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_EQ_CONS_OFFSET(func, 0), 0);
+ CSTORM_ISCSI_EQ_CONS_OFFSET(pfid, 0), 0);
CNIC_WR(dev, BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(func, 0),
+ CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(pfid, 0),
cp->kcq1.dma.pg_map_arr[1] & 0xffffffff);
CNIC_WR(dev, BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(func, 0) + 4,
+ CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(pfid, 0) + 4,
(u64) cp->kcq1.dma.pg_map_arr[1] >> 32);
CNIC_WR(dev, BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(func, 0),
+ CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(pfid, 0),
cp->kcq1.dma.pg_map_arr[0] & 0xffffffff);
CNIC_WR(dev, BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(func, 0) + 4,
+ CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(pfid, 0) + 4,
(u64) cp->kcq1.dma.pg_map_arr[0] >> 32);
CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(func, 0), 1);
+ CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(pfid, 0), 1);
CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_EQ_SB_NUM_OFFSET(func, 0), cp->status_blk_num);
+ CSTORM_ISCSI_EQ_SB_NUM_OFFSET(pfid, 0), cp->status_blk_num);
CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(func, 0),
- HC_INDEX_C_ISCSI_EQ_CONS);
+ CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(pfid, 0),
+ HC_INDEX_ISCSI_EQ_CONS);
for (i = 0; i < cp->conn_buf_info.num_pages; i++) {
CNIC_WR(dev, BAR_TSTRORM_INTMEM +
- TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(func, i),
+ TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(pfid, i),
cp->conn_buf_info.pgtbl[2 * i]);
CNIC_WR(dev, BAR_TSTRORM_INTMEM +
- TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(func, i) + 4,
+ TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(pfid, i) + 4,
cp->conn_buf_info.pgtbl[(2 * i) + 1]);
}
CNIC_WR(dev, BAR_USTRORM_INTMEM +
- USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(func),
+ USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfid),
cp->gbl_buf_info.pg_map_arr[0] & 0xffffffff);
CNIC_WR(dev, BAR_USTRORM_INTMEM +
- USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(func) + 4,
+ USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfid) + 4,
(u64) cp->gbl_buf_info.pg_map_arr[0] >> 32);
+ CNIC_WR(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_TCP_LOCAL_ADV_WND_OFFSET(pfid), DEF_RCV_BUF);
+
cnic_setup_bnx2x_context(dev);
- eq_idx = CNIC_RD16(dev, BAR_CSTRORM_INTMEM +
- CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id) +
- offsetof(struct cstorm_status_block_c,
- index_values[HC_INDEX_C_ISCSI_EQ_CONS]));
- if (eq_idx != 0) {
- netdev_err(dev->netdev, "EQ cons index %x != 0\n", eq_idx);
- return -EBUSY;
- }
ret = cnic_init_bnx2x_irq(dev);
if (ret)
return ret;
- cnic_init_bnx2x_tx_ring(dev);
- cnic_init_bnx2x_rx_ring(dev);
-
return 0;
}
static void cnic_init_rings(struct cnic_dev *dev)
{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_uio_dev *udev = cp->udev;
+
+ if (test_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags))
+ return;
+
if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
cnic_init_bnx2_tx_ring(dev);
cnic_init_bnx2_rx_ring(dev);
+ set_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags);
} else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
- struct cnic_local *cp = dev->cnic_priv;
u32 cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
+ u32 cl_qzone_id, type;
+ struct client_init_ramrod_data *data;
union l5cm_specific_data l5_data;
struct ustorm_eth_rx_producers rx_prods = {0};
u32 off, i;
@@ -4223,21 +4435,38 @@ static void cnic_init_rings(struct cnic_dev *dev)
rx_prods.cqe_prod = BNX2X_MAX_RCQ_DESC_CNT;
barrier();
+ cl_qzone_id = BNX2X_CL_QZONE_ID(cp, cli);
+
off = BAR_USTRORM_INTMEM +
- USTORM_RX_PRODS_OFFSET(CNIC_PORT(cp), cli);
+ (BNX2X_CHIP_IS_E2(cp->chip_id) ?
+ USTORM_RX_PRODS_E2_OFFSET(cl_qzone_id) :
+ USTORM_RX_PRODS_E1X_OFFSET(CNIC_PORT(cp), cli));
for (i = 0; i < sizeof(struct ustorm_eth_rx_producers) / 4; i++)
CNIC_WR(dev, off + i * 4, ((u32 *) &rx_prods)[i]);
set_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags);
- cnic_init_bnx2x_tx_ring(dev);
- cnic_init_bnx2x_rx_ring(dev);
+ data = udev->l2_buf;
+
+ memset(data, 0, sizeof(*data));
+
+ cnic_init_bnx2x_tx_ring(dev, data);
+ cnic_init_bnx2x_rx_ring(dev, data);
+
+ l5_data.phy_address.lo = udev->l2_buf_map & 0xffffffff;
+ l5_data.phy_address.hi = (u64) udev->l2_buf_map >> 32;
+
+ type = (ETH_CONNECTION_TYPE << SPE_HDR_CONN_TYPE_SHIFT)
+ & SPE_HDR_CONN_TYPE;
+ type |= ((cp->pfid << SPE_HDR_FUNCTION_ID_SHIFT) &
+ SPE_HDR_FUNCTION_ID);
+
+ set_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags);
- l5_data.phy_address.lo = cli;
- l5_data.phy_address.hi = 0;
cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_ETH_CLIENT_SETUP,
- BNX2X_ISCSI_L2_CID, ETH_CONNECTION_TYPE, &l5_data);
+ BNX2X_ISCSI_L2_CID, type, &l5_data);
+
i = 0;
while (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags) &&
++i < 10)
@@ -4246,13 +4475,18 @@ static void cnic_init_rings(struct cnic_dev *dev)
if (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags))
netdev_err(dev->netdev,
"iSCSI CLIENT_SETUP did not complete\n");
- cnic_kwq_completion(dev, 1);
+ cnic_spq_completion(dev, DRV_CTL_RET_L2_SPQ_CREDIT_CMD, 1);
cnic_ring_ctl(dev, BNX2X_ISCSI_L2_CID, cli, 1);
}
}
static void cnic_shutdown_rings(struct cnic_dev *dev)
{
+ struct cnic_local *cp = dev->cnic_priv;
+
+ if (!test_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags))
+ return;
+
if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
cnic_shutdown_bnx2_rx_ring(dev);
} else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
@@ -4260,6 +4494,7 @@ static void cnic_shutdown_rings(struct cnic_dev *dev)
u32 cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
union l5cm_specific_data l5_data;
int i;
+ u32 type;
cnic_ring_ctl(dev, BNX2X_ISCSI_L2_CID, cli, 0);
@@ -4277,14 +4512,18 @@ static void cnic_shutdown_rings(struct cnic_dev *dev)
if (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags))
netdev_err(dev->netdev,
"iSCSI CLIENT_HALT did not complete\n");
- cnic_kwq_completion(dev, 1);
+ cnic_spq_completion(dev, DRV_CTL_RET_L2_SPQ_CREDIT_CMD, 1);
memset(&l5_data, 0, sizeof(l5_data));
- cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_ETH_CFC_DEL,
- BNX2X_ISCSI_L2_CID, ETH_CONNECTION_TYPE |
- (1 << SPE_HDR_COMMON_RAMROD_SHIFT), &l5_data);
+ type = (NONE_CONNECTION_TYPE << SPE_HDR_CONN_TYPE_SHIFT)
+ & SPE_HDR_CONN_TYPE;
+ type |= ((cp->pfid << SPE_HDR_FUNCTION_ID_SHIFT) &
+ SPE_HDR_FUNCTION_ID);
+ cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_COMMON_CFC_DEL,
+ BNX2X_ISCSI_L2_CID, type, &l5_data);
msleep(10);
}
+ clear_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags);
}
static int cnic_register_netdev(struct cnic_dev *dev)
@@ -4327,7 +4566,6 @@ static int cnic_start_hw(struct cnic_dev *dev)
return -EALREADY;
dev->regview = ethdev->io_base;
- cp->chip_id = ethdev->chip_id;
pci_dev_get(dev->pcidev);
cp->func = PCI_FUNC(dev->pcidev->devfn);
cp->status_blk.gen = ethdev->irq_arr[0].status_blk;
@@ -4379,17 +4617,11 @@ static void cnic_stop_bnx2_hw(struct cnic_dev *dev)
static void cnic_stop_bnx2x_hw(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
- u8 sb_id = cp->status_blk_num;
- int port = CNIC_PORT(cp);
cnic_free_irq(dev);
- CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
- CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id) +
- offsetof(struct cstorm_status_block_c,
- index_values[HC_INDEX_C_ISCSI_EQ_CONS]),
- 0);
+ *cp->kcq1.hw_prod_idx_ptr = 0;
CNIC_WR(dev, BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_EQ_CONS_OFFSET(cp->func, 0), 0);
+ CSTORM_ISCSI_EQ_CONS_OFFSET(cp->pfid, 0), 0);
CNIC_WR16(dev, cp->kcq1.io_addr, 0);
cnic_free_resc(dev);
}
@@ -4403,10 +4635,11 @@ static void cnic_stop_hw(struct cnic_dev *dev)
/* Need to wait for the ring shutdown event to complete
* before clearing the CNIC_UP flag.
*/
- while (cp->uio_dev != -1 && i < 15) {
+ while (cp->udev->uio_dev != -1 && i < 15) {
msleep(100);
i++;
}
+ cnic_shutdown_rings(dev);
clear_bit(CNIC_F_CNIC_UP, &dev->flags);
rcu_assign_pointer(cp->ulp_ops[CNIC_ULP_L4], NULL);
synchronize_rcu();
@@ -4455,7 +4688,6 @@ static struct cnic_dev *cnic_alloc_dev(struct net_device *dev,
cp = cdev->cnic_priv;
cp->dev = cdev;
- cp->uio_dev = -1;
cp->l2_single_buf_size = 0x400;
cp->l2_rx_ring_size = 3;
@@ -4510,6 +4742,7 @@ static struct cnic_dev *init_bnx2_cnic(struct net_device *dev)
cp = cdev->cnic_priv;
cp->ethdev = ethdev;
cdev->pcidev = pdev;
+ cp->chip_id = ethdev->chip_id;
cp->cnic_ops = &cnic_bnx2_ops;
cp->start_hw = cnic_start_bnx2_hw;
@@ -4564,6 +4797,7 @@ static struct cnic_dev *init_bnx2x_cnic(struct net_device *dev)
cp = cdev->cnic_priv;
cp->ethdev = ethdev;
cdev->pcidev = pdev;
+ cp->chip_id = ethdev->chip_id;
cp->cnic_ops = &cnic_bnx2x_ops;
cp->start_hw = cnic_start_bnx2x_hw;
@@ -4575,7 +4809,10 @@ static struct cnic_dev *init_bnx2x_cnic(struct net_device *dev)
cp->stop_cm = cnic_cm_stop_bnx2x_hw;
cp->enable_int = cnic_enable_bnx2x_int;
cp->disable_int_sync = cnic_disable_bnx2x_int_sync;
- cp->ack_int = cnic_ack_bnx2x_msix;
+ if (BNX2X_CHIP_IS_E2(cp->chip_id))
+ cp->ack_int = cnic_ack_bnx2x_e2_msix;
+ else
+ cp->ack_int = cnic_ack_bnx2x_msix;
cp->close_conn = cnic_close_bnx2x_conn;
cp->next_idx = cnic_bnx2x_next_idx;
cp->hw_idx = cnic_bnx2x_hw_idx;
@@ -4683,6 +4920,7 @@ static struct notifier_block cnic_netdev_notifier = {
static void cnic_release(void)
{
struct cnic_dev *dev;
+ struct cnic_uio_dev *udev;
while (!list_empty(&cnic_dev_list)) {
dev = list_entry(cnic_dev_list.next, struct cnic_dev, list);
@@ -4696,6 +4934,11 @@ static void cnic_release(void)
list_del_init(&dev->list);
cnic_free_dev(dev);
}
+ while (!list_empty(&cnic_udev_list)) {
+ udev = list_entry(cnic_udev_list.next, struct cnic_uio_dev,
+ list);
+ cnic_free_uio(udev);
+ }
}
static int __init cnic_init(void)
@@ -4710,6 +4953,13 @@ static int __init cnic_init(void)
return rc;
}
+ cnic_wq = create_singlethread_workqueue("cnic_wq");
+ if (!cnic_wq) {
+ cnic_release();
+ unregister_netdevice_notifier(&cnic_netdev_notifier);
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -4717,6 +4967,7 @@ static void __exit cnic_exit(void)
{
unregister_netdevice_notifier(&cnic_netdev_notifier);
cnic_release();
+ destroy_workqueue(cnic_wq);
}
module_init(cnic_init);
diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h
index 275c36114d85..6a4a0ae5cfe3 100644
--- a/drivers/net/cnic.h
+++ b/drivers/net/cnic.h
@@ -12,6 +12,13 @@
#ifndef CNIC_H
#define CNIC_H
+#define HC_INDEX_ISCSI_EQ_CONS 6
+
+#define HC_INDEX_FCOE_EQ_CONS 3
+
+#define HC_SP_INDEX_ETH_ISCSI_CQ_CONS 5
+#define HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS 1
+
#define KWQ_PAGE_CNT 4
#define KCQ_PAGE_CNT 16
@@ -161,8 +168,9 @@ struct cnic_context {
wait_queue_head_t waitq;
int wait_cond;
unsigned long timestamp;
- u32 ctx_flags;
-#define CTX_FL_OFFLD_START 0x00000001
+ unsigned long ctx_flags;
+#define CTX_FL_OFFLD_START 0
+#define CTX_FL_DELETE_WAIT 1
u8 ulp_proto_id;
union {
struct cnic_iscsi *iscsi;
@@ -179,6 +187,31 @@ struct kcq_info {
u32 io_addr;
};
+struct iro {
+ u32 base;
+ u16 m1;
+ u16 m2;
+ u16 m3;
+ u16 size;
+};
+
+struct cnic_uio_dev {
+ struct uio_info cnic_uinfo;
+ u32 uio_dev;
+
+ int l2_ring_size;
+ void *l2_ring;
+ dma_addr_t l2_ring_map;
+
+ int l2_buf_size;
+ void *l2_buf;
+ dma_addr_t l2_buf_map;
+
+ struct cnic_dev *dev;
+ struct pci_dev *pdev;
+ struct list_head list;
+};
+
struct cnic_local {
spinlock_t cnic_ulp_lock;
@@ -192,19 +225,15 @@ struct cnic_local {
unsigned long cnic_local_flags;
#define CNIC_LCL_FL_KWQ_INIT 0x0
#define CNIC_LCL_FL_L2_WAIT 0x1
+#define CNIC_LCL_FL_RINGS_INITED 0x2
struct cnic_dev *dev;
struct cnic_eth_dev *ethdev;
- void *l2_ring;
- dma_addr_t l2_ring_map;
- int l2_ring_size;
- int l2_rx_ring_size;
+ struct cnic_uio_dev *udev;
- void *l2_buf;
- dma_addr_t l2_buf_map;
- int l2_buf_size;
+ int l2_rx_ring_size;
int l2_single_buf_size;
u16 *rx_cons_ptr;
@@ -212,6 +241,9 @@ struct cnic_local {
u16 rx_cons;
u16 tx_cons;
+ struct iro *iro_arr;
+#define IRO (((struct cnic_local *) dev->cnic_priv)->iro_arr)
+
struct cnic_dma kwq_info;
struct kwqe **kwq;
@@ -230,12 +262,16 @@ struct cnic_local {
union {
void *gen;
struct status_block_msix *bnx2;
- struct host_status_block *bnx2x;
+ struct host_hc_status_block_e1x *bnx2x_e1x;
+ /* index values - which counter to update */
+ #define SM_RX_ID 0
+ #define SM_TX_ID 1
} status_blk;
- struct host_def_status_block *bnx2x_def_status_blk;
+ struct host_sp_status_block *bnx2x_def_status_blk;
u32 status_blk_num;
+ u32 bnx2x_igu_sb_id;
u32 int_num;
u32 last_status_idx;
struct tasklet_struct cnic_irq_task;
@@ -264,6 +300,8 @@ struct cnic_local {
int hq_size;
int num_cqs;
+ struct delayed_work delete_task;
+
struct cnic_ctx *ctx_arr;
int ctx_blks;
int ctx_blk_size;
@@ -272,11 +310,9 @@ struct cnic_local {
u32 chip_id;
int func;
+ u32 pfid;
u32 shmem_base;
- u32 uio_dev;
- struct uio_info *cnic_uinfo;
-
struct cnic_ops *cnic_ops;
int (*start_hw)(struct cnic_dev *);
void (*stop_hw)(struct cnic_dev *);
@@ -335,18 +371,36 @@ struct bnx2x_bd_chain_next {
#define BNX2X_ISCSI_GLB_BUF_SIZE 64
#define BNX2X_ISCSI_PBL_NOT_CACHED 0xff
#define BNX2X_ISCSI_PDU_HEADER_NOT_CACHED 0xff
-#define BNX2X_HW_CID(x, func) ((x) | (((func) % PORT_MAX) << 23) | \
- (((func) >> 1) << 17))
-#define BNX2X_SW_CID(x) (x & 0x1ffff)
+
+#define BNX2X_CHIP_NUM_57710 0x164e
#define BNX2X_CHIP_NUM_57711 0x164f
#define BNX2X_CHIP_NUM_57711E 0x1650
+#define BNX2X_CHIP_NUM_57712 0x1662
+#define BNX2X_CHIP_NUM_57712E 0x1663
+#define BNX2X_CHIP_NUM_57713 0x1651
+#define BNX2X_CHIP_NUM_57713E 0x1652
+
#define BNX2X_CHIP_NUM(x) (x >> 16)
+#define BNX2X_CHIP_IS_57710(x) \
+ (BNX2X_CHIP_NUM(x) == BNX2X_CHIP_NUM_57710)
#define BNX2X_CHIP_IS_57711(x) \
(BNX2X_CHIP_NUM(x) == BNX2X_CHIP_NUM_57711)
#define BNX2X_CHIP_IS_57711E(x) \
(BNX2X_CHIP_NUM(x) == BNX2X_CHIP_NUM_57711E)
#define BNX2X_CHIP_IS_E1H(x) \
(BNX2X_CHIP_IS_57711(x) || BNX2X_CHIP_IS_57711E(x))
+#define BNX2X_CHIP_IS_57712(x) \
+ (BNX2X_CHIP_NUM(x) == BNX2X_CHIP_NUM_57712)
+#define BNX2X_CHIP_IS_57712E(x) \
+ (BNX2X_CHIP_NUM(x) == BNX2X_CHIP_NUM_57712E)
+#define BNX2X_CHIP_IS_57713(x) \
+ (BNX2X_CHIP_NUM(x) == BNX2X_CHIP_NUM_57713)
+#define BNX2X_CHIP_IS_57713E(x) \
+ (BNX2X_CHIP_NUM(x) == BNX2X_CHIP_NUM_57713E)
+#define BNX2X_CHIP_IS_E2(x) \
+ (BNX2X_CHIP_IS_57712(x) || BNX2X_CHIP_IS_57712E(x) || \
+ BNX2X_CHIP_IS_57713(x) || BNX2X_CHIP_IS_57713E(x))
+
#define IS_E1H_OFFSET BNX2X_CHIP_IS_E1H(cp->chip_id)
#define BNX2X_RX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_bd))
@@ -358,19 +412,35 @@ struct bnx2x_bd_chain_next {
(BNX2X_MAX_RCQ_DESC_CNT - 1)) ? \
((x) + 2) : ((x) + 1)
-#define BNX2X_DEF_SB_ID 16
+#define BNX2X_DEF_SB_ID HC_SP_SB_ID
-#define BNX2X_ISCSI_RX_SB_INDEX_NUM \
- ((HC_INDEX_DEF_U_ETH_ISCSI_RX_CQ_CONS << \
- USTORM_ETH_ST_CONTEXT_CONFIG_CQE_SB_INDEX_NUMBER_SHIFT) & \
- USTORM_ETH_ST_CONTEXT_CONFIG_CQE_SB_INDEX_NUMBER)
+#define BNX2X_SHMEM_MF_BLK_OFFSET 0x7e4
#define BNX2X_SHMEM_ADDR(base, field) (base + \
offsetof(struct shmem_region, field))
-#define CNIC_PORT(cp) ((cp)->func % PORT_MAX)
+#define BNX2X_SHMEM2_ADDR(base, field) (base + \
+ offsetof(struct shmem2_region, field))
+
+#define BNX2X_SHMEM2_HAS(base, field) \
+ ((base) && \
+ (CNIC_RD(dev, BNX2X_SHMEM2_ADDR(base, size)) > \
+ offsetof(struct shmem2_region, field)))
+
+#define CNIC_PORT(cp) ((cp)->pfid & 1)
#define CNIC_FUNC(cp) ((cp)->func)
-#define CNIC_E1HVN(cp) ((cp)->func >> 1)
+#define CNIC_PATH(cp) (!BNX2X_CHIP_IS_E2(cp->chip_id) ? 0 :\
+ (CNIC_FUNC(cp) & 1))
+#define CNIC_E1HVN(cp) ((cp)->pfid >> 1)
+
+#define BNX2X_HW_CID(cp, x) ((CNIC_PORT(cp) << 23) | \
+ (CNIC_E1HVN(cp) << 17) | (x))
+
+#define BNX2X_SW_CID(x) (x & 0x1ffff)
+
+#define BNX2X_CL_QZONE_ID(cp, cli) \
+ (cli + (CNIC_PORT(cp) * ETH_MAX_RX_CLIENTS_E1H))
+#define TCP_TSTORM_OOO_DROP_AND_PROC_ACK (0<<4)
#endif
diff --git a/drivers/net/cnic_defs.h b/drivers/net/cnic_defs.h
index 7ce694d41b6b..328e8b2765a3 100644
--- a/drivers/net/cnic_defs.h
+++ b/drivers/net/cnic_defs.h
@@ -14,6 +14,7 @@
/* KWQ (kernel work queue) request op codes */
#define L2_KWQE_OPCODE_VALUE_FLUSH (4)
+#define L2_KWQE_OPCODE_VALUE_VM_FREE_RX_QUEUE (8)
#define L4_KWQE_OPCODE_VALUE_CONNECT1 (50)
#define L4_KWQE_OPCODE_VALUE_CONNECT2 (51)
@@ -48,11 +49,14 @@
#define L4_KCQE_OPCODE_VALUE_UPLOAD_PG (14)
/* KCQ (kernel completion queue) completion status */
-#define L4_KCQE_COMPLETION_STATUS_SUCCESS (0)
-#define L4_KCQE_COMPLETION_STATUS_TIMEOUT (0x93)
+#define L4_KCQE_COMPLETION_STATUS_SUCCESS (0)
+#define L4_KCQE_COMPLETION_STATUS_TIMEOUT (0x93)
-#define L4_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAIL (0x83)
-#define L4_KCQE_COMPLETION_STATUS_OFFLOADED_PG (0x89)
+#define L4_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAIL (0x83)
+#define L4_KCQE_COMPLETION_STATUS_OFFLOADED_PG (0x89)
+
+#define L4_KCQE_OPCODE_VALUE_OOO_EVENT_NOTIFICATION (0xa0)
+#define L4_KCQE_OPCODE_VALUE_OOO_FLUSH (0xa1)
#define L4_LAYER_CODE (4)
#define L2_LAYER_CODE (2)
@@ -585,6 +589,100 @@ struct l4_kwq_upload {
*/
/*
+ * The iscsi aggregative context of Cstorm
+ */
+struct cstorm_iscsi_ag_context {
+ u32 agg_vars1;
+#define CSTORM_ISCSI_AG_CONTEXT_STATE (0xFF<<0)
+#define CSTORM_ISCSI_AG_CONTEXT_STATE_SHIFT 0
+#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0 (0x1<<8)
+#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0_SHIFT 8
+#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1 (0x1<<9)
+#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1_SHIFT 9
+#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2 (0x1<<10)
+#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2_SHIFT 10
+#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3 (0x1<<11)
+#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3_SHIFT 11
+#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED_ULP_RX_SE_CF_EN (0x1<<12)
+#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED_ULP_RX_SE_CF_EN_SHIFT 12
+#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED_ULP_RX_INV_CF_EN (0x1<<13)
+#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED_ULP_RX_INV_CF_EN_SHIFT 13
+#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION3_CF (0x3<<14)
+#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION3_CF_SHIFT 14
+#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED66 (0x3<<16)
+#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED66_SHIFT 16
+#define __CSTORM_ISCSI_AG_CONTEXT_FIN_RECEIVED_CF_EN (0x1<<18)
+#define __CSTORM_ISCSI_AG_CONTEXT_FIN_RECEIVED_CF_EN_SHIFT 18
+#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION0_CF_EN (0x1<<19)
+#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION0_CF_EN_SHIFT 19
+#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION1_CF_EN (0x1<<20)
+#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION1_CF_EN_SHIFT 20
+#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION2_CF_EN (0x1<<21)
+#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION2_CF_EN_SHIFT 21
+#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION3_CF_EN (0x1<<22)
+#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION3_CF_EN_SHIFT 22
+#define __CSTORM_ISCSI_AG_CONTEXT_REL_SEQ_RULE (0x7<<23)
+#define __CSTORM_ISCSI_AG_CONTEXT_REL_SEQ_RULE_SHIFT 23
+#define CSTORM_ISCSI_AG_CONTEXT_HQ_PROD_RULE (0x3<<26)
+#define CSTORM_ISCSI_AG_CONTEXT_HQ_PROD_RULE_SHIFT 26
+#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED52 (0x3<<28)
+#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED52_SHIFT 28
+#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED53 (0x3<<30)
+#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED53_SHIFT 30
+#if defined(__BIG_ENDIAN)
+ u8 __aux1_th;
+ u8 __aux1_val;
+ u16 __agg_vars2;
+#elif defined(__LITTLE_ENDIAN)
+ u16 __agg_vars2;
+ u8 __aux1_val;
+ u8 __aux1_th;
+#endif
+ u32 rel_seq;
+ u32 rel_seq_th;
+#if defined(__BIG_ENDIAN)
+ u16 hq_cons;
+ u16 hq_prod;
+#elif defined(__LITTLE_ENDIAN)
+ u16 hq_prod;
+ u16 hq_cons;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 __reserved62;
+ u8 __reserved61;
+ u8 __reserved60;
+ u8 __reserved59;
+#elif defined(__LITTLE_ENDIAN)
+ u8 __reserved59;
+ u8 __reserved60;
+ u8 __reserved61;
+ u8 __reserved62;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 __reserved64;
+ u16 __cq_u_prod0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 __cq_u_prod0;
+ u16 __reserved64;
+#endif
+ u32 __cq_u_prod1;
+#if defined(__BIG_ENDIAN)
+ u16 __agg_vars3;
+ u16 __cq_u_prod2;
+#elif defined(__LITTLE_ENDIAN)
+ u16 __cq_u_prod2;
+ u16 __agg_vars3;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 __aux2_th;
+ u16 __cq_u_prod3;
+#elif defined(__LITTLE_ENDIAN)
+ u16 __cq_u_prod3;
+ u16 __aux2_th;
+#endif
+};
+
+/*
* iSCSI context region, used only in iSCSI
*/
struct ustorm_iscsi_rq_db {
@@ -696,7 +794,7 @@ struct ustorm_iscsi_st_context {
struct regpair task_pbl_base;
struct regpair tce_phy_addr;
struct ustorm_iscsi_placement_db place_db;
- u32 data_rcv_seq;
+ u32 reserved8;
u32 rem_rcv_len;
#if defined(__BIG_ENDIAN)
u16 hdr_itt;
@@ -713,8 +811,10 @@ struct ustorm_iscsi_st_context {
#define USTORM_ISCSI_ST_CONTEXT_BMIDDLEOFPDU_SHIFT 0
#define USTORM_ISCSI_ST_CONTEXT_BFENCECQE (0x1<<1)
#define USTORM_ISCSI_ST_CONTEXT_BFENCECQE_SHIFT 1
-#define USTORM_ISCSI_ST_CONTEXT_RESERVED1 (0x3F<<2)
-#define USTORM_ISCSI_ST_CONTEXT_RESERVED1_SHIFT 2
+#define USTORM_ISCSI_ST_CONTEXT_BRESETCRC (0x1<<2)
+#define USTORM_ISCSI_ST_CONTEXT_BRESETCRC_SHIFT 2
+#define USTORM_ISCSI_ST_CONTEXT_RESERVED1 (0x1F<<3)
+#define USTORM_ISCSI_ST_CONTEXT_RESERVED1_SHIFT 3
u8 task_pdu_cache_index;
u8 task_pbe_cache_index;
#elif defined(__LITTLE_ENDIAN)
@@ -725,8 +825,10 @@ struct ustorm_iscsi_st_context {
#define USTORM_ISCSI_ST_CONTEXT_BMIDDLEOFPDU_SHIFT 0
#define USTORM_ISCSI_ST_CONTEXT_BFENCECQE (0x1<<1)
#define USTORM_ISCSI_ST_CONTEXT_BFENCECQE_SHIFT 1
-#define USTORM_ISCSI_ST_CONTEXT_RESERVED1 (0x3F<<2)
-#define USTORM_ISCSI_ST_CONTEXT_RESERVED1_SHIFT 2
+#define USTORM_ISCSI_ST_CONTEXT_BRESETCRC (0x1<<2)
+#define USTORM_ISCSI_ST_CONTEXT_BRESETCRC_SHIFT 2
+#define USTORM_ISCSI_ST_CONTEXT_RESERVED1 (0x1F<<3)
+#define USTORM_ISCSI_ST_CONTEXT_RESERVED1_SHIFT 3
u8 hdr_second_byte_union;
#endif
#if defined(__BIG_ENDIAN)
@@ -777,14 +879,14 @@ struct ustorm_iscsi_st_context {
*/
struct tstorm_tcp_st_context_section {
u32 flags1;
-#define TSTORM_TCP_ST_CONTEXT_SECTION_RTT_SRTT_20B (0xFFFFFF<<0)
-#define TSTORM_TCP_ST_CONTEXT_SECTION_RTT_SRTT_20B_SHIFT 0
+#define TSTORM_TCP_ST_CONTEXT_SECTION_RTT_SRTT (0xFFFFFF<<0)
+#define TSTORM_TCP_ST_CONTEXT_SECTION_RTT_SRTT_SHIFT 0
#define TSTORM_TCP_ST_CONTEXT_SECTION_PAWS_INVALID (0x1<<24)
#define TSTORM_TCP_ST_CONTEXT_SECTION_PAWS_INVALID_SHIFT 24
#define TSTORM_TCP_ST_CONTEXT_SECTION_TIMESTAMP_EXISTS (0x1<<25)
#define TSTORM_TCP_ST_CONTEXT_SECTION_TIMESTAMP_EXISTS_SHIFT 25
-#define TSTORM_TCP_ST_CONTEXT_SECTION_ISLE_EXISTS (0x1<<26)
-#define TSTORM_TCP_ST_CONTEXT_SECTION_ISLE_EXISTS_SHIFT 26
+#define TSTORM_TCP_ST_CONTEXT_SECTION_RESERVED0 (0x1<<26)
+#define TSTORM_TCP_ST_CONTEXT_SECTION_RESERVED0_SHIFT 26
#define TSTORM_TCP_ST_CONTEXT_SECTION_STOP_RX_PAYLOAD (0x1<<27)
#define TSTORM_TCP_ST_CONTEXT_SECTION_STOP_RX_PAYLOAD_SHIFT 27
#define TSTORM_TCP_ST_CONTEXT_SECTION_KA_ENABLED (0x1<<28)
@@ -793,11 +895,11 @@ struct tstorm_tcp_st_context_section {
#define TSTORM_TCP_ST_CONTEXT_SECTION_FIRST_RTO_ESTIMATE_SHIFT 29
#define TSTORM_TCP_ST_CONTEXT_SECTION_MAX_SEG_RETRANSMIT_EN (0x1<<30)
#define TSTORM_TCP_ST_CONTEXT_SECTION_MAX_SEG_RETRANSMIT_EN_SHIFT 30
-#define TSTORM_TCP_ST_CONTEXT_SECTION_RESERVED3 (0x1<<31)
-#define TSTORM_TCP_ST_CONTEXT_SECTION_RESERVED3_SHIFT 31
+#define TSTORM_TCP_ST_CONTEXT_SECTION_LAST_ISLE_HAS_FIN (0x1<<31)
+#define TSTORM_TCP_ST_CONTEXT_SECTION_LAST_ISLE_HAS_FIN_SHIFT 31
u32 flags2;
-#define TSTORM_TCP_ST_CONTEXT_SECTION_RTT_VARIATION_20B (0xFFFFFF<<0)
-#define TSTORM_TCP_ST_CONTEXT_SECTION_RTT_VARIATION_20B_SHIFT 0
+#define TSTORM_TCP_ST_CONTEXT_SECTION_RTT_VARIATION (0xFFFFFF<<0)
+#define TSTORM_TCP_ST_CONTEXT_SECTION_RTT_VARIATION_SHIFT 0
#define TSTORM_TCP_ST_CONTEXT_SECTION_DA_EN (0x1<<24)
#define TSTORM_TCP_ST_CONTEXT_SECTION_DA_EN_SHIFT 24
#define TSTORM_TCP_ST_CONTEXT_SECTION_DA_COUNTER_EN (0x1<<25)
@@ -810,18 +912,18 @@ struct tstorm_tcp_st_context_section {
#define TSTORM_TCP_ST_CONTEXT_SECTION_UPDATE_L2_STATSTICS_SHIFT 28
#define TSTORM_TCP_ST_CONTEXT_SECTION_UPDATE_L4_STATSTICS (0x1<<29)
#define TSTORM_TCP_ST_CONTEXT_SECTION_UPDATE_L4_STATSTICS_SHIFT 29
-#define __TSTORM_TCP_ST_CONTEXT_SECTION_SECOND_ISLE_DROPPED (0x1<<30)
-#define __TSTORM_TCP_ST_CONTEXT_SECTION_SECOND_ISLE_DROPPED_SHIFT 30
-#define __TSTORM_TCP_ST_CONTEXT_SECTION_DONT_SUPPORT_OOO (0x1<<31)
-#define __TSTORM_TCP_ST_CONTEXT_SECTION_DONT_SUPPORT_OOO_SHIFT 31
+#define __TSTORM_TCP_ST_CONTEXT_SECTION_IN_WINDOW_RST_ATTACK (0x1<<30)
+#define __TSTORM_TCP_ST_CONTEXT_SECTION_IN_WINDOW_RST_ATTACK_SHIFT 30
+#define __TSTORM_TCP_ST_CONTEXT_SECTION_IN_WINDOW_SYN_ATTACK (0x1<<31)
+#define __TSTORM_TCP_ST_CONTEXT_SECTION_IN_WINDOW_SYN_ATTACK_SHIFT 31
#if defined(__BIG_ENDIAN)
- u16 reserved_slowpath;
- u8 tcp_sm_state_3b;
- u8 rto_exp_3b;
+ u16 mss;
+ u8 tcp_sm_state;
+ u8 rto_exp;
#elif defined(__LITTLE_ENDIAN)
- u8 rto_exp_3b;
- u8 tcp_sm_state_3b;
- u16 reserved_slowpath;
+ u8 rto_exp;
+ u8 tcp_sm_state;
+ u16 mss;
#endif
u32 rcv_nxt;
u32 timestamp_recent;
@@ -846,11 +948,11 @@ struct tstorm_tcp_st_context_section {
#if defined(__BIG_ENDIAN)
u8 statistics_counter_id;
u8 ooo_support_mode;
- u8 snd_wnd_scale_4b;
+ u8 snd_wnd_scale;
u8 dup_ack_count;
#elif defined(__LITTLE_ENDIAN)
u8 dup_ack_count;
- u8 snd_wnd_scale_4b;
+ u8 snd_wnd_scale;
u8 ooo_support_mode;
u8 statistics_counter_id;
#endif
@@ -860,13 +962,21 @@ struct tstorm_tcp_st_context_section {
u32 isle_start_seq;
u32 isle_end_seq;
#if defined(__BIG_ENDIAN)
- u16 mss;
+ u16 second_isle_address;
u16 recent_seg_wnd;
#elif defined(__LITTLE_ENDIAN)
u16 recent_seg_wnd;
- u16 mss;
+ u16 second_isle_address;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 max_isles_ever_happened;
+ u8 isles_number;
+ u16 last_isle_address;
+#elif defined(__LITTLE_ENDIAN)
+ u16 last_isle_address;
+ u8 isles_number;
+ u8 max_isles_ever_happened;
#endif
- u32 reserved4;
u32 max_rt_time;
#if defined(__BIG_ENDIAN)
u16 lsb_mac_address;
@@ -876,7 +986,7 @@ struct tstorm_tcp_st_context_section {
u16 lsb_mac_address;
#endif
u32 msb_mac_address;
- u32 reserved2;
+ u32 rightmost_received_seq;
};
/*
@@ -951,7 +1061,7 @@ struct tstorm_iscsi_st_context_section {
u8 scratchpad_idx;
struct iscsi_term_vars term_vars;
#endif
- u32 reserved2;
+ u32 process_nxt;
};
/*
@@ -1174,24 +1284,12 @@ struct xstorm_iscsi_ag_context {
#endif
#if defined(__BIG_ENDIAN)
u8 cdu_reserved;
- u8 agg_vars4;
-#define XSTORM_ISCSI_AG_CONTEXT_R2TQ_PROD_CF (0x3<<0)
-#define XSTORM_ISCSI_AG_CONTEXT_R2TQ_PROD_CF_SHIFT 0
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX21_CF (0x3<<2)
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX21_CF_SHIFT 2
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX18_CF_EN (0x1<<4)
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX18_CF_EN_SHIFT 4
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX19_CF_EN (0x1<<5)
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX19_CF_EN_SHIFT 5
-#define __XSTORM_ISCSI_AG_CONTEXT_R2TQ_PROD_CF_EN (0x1<<6)
-#define __XSTORM_ISCSI_AG_CONTEXT_R2TQ_PROD_CF_EN_SHIFT 6
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX21_CF_EN (0x1<<7)
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX21_CF_EN_SHIFT 7
+ u8 __agg_vars4;
u8 agg_vars3;
#define XSTORM_ISCSI_AG_CONTEXT_PHYSICAL_QUEUE_NUM2 (0x3F<<0)
#define XSTORM_ISCSI_AG_CONTEXT_PHYSICAL_QUEUE_NUM2_SHIFT 0
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX19_CF (0x3<<6)
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX19_CF_SHIFT 6
+#define __XSTORM_ISCSI_AG_CONTEXT_RX_TS_EN_CF (0x3<<6)
+#define __XSTORM_ISCSI_AG_CONTEXT_RX_TS_EN_CF_SHIFT 6
u8 agg_vars2;
#define __XSTORM_ISCSI_AG_CONTEXT_DQ_CF (0x3<<0)
#define __XSTORM_ISCSI_AG_CONTEXT_DQ_CF_SHIFT 0
@@ -1222,21 +1320,9 @@ struct xstorm_iscsi_ag_context {
u8 agg_vars3;
#define XSTORM_ISCSI_AG_CONTEXT_PHYSICAL_QUEUE_NUM2 (0x3F<<0)
#define XSTORM_ISCSI_AG_CONTEXT_PHYSICAL_QUEUE_NUM2_SHIFT 0
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX19_CF (0x3<<6)
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX19_CF_SHIFT 6
- u8 agg_vars4;
-#define XSTORM_ISCSI_AG_CONTEXT_R2TQ_PROD_CF (0x3<<0)
-#define XSTORM_ISCSI_AG_CONTEXT_R2TQ_PROD_CF_SHIFT 0
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX21_CF (0x3<<2)
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX21_CF_SHIFT 2
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX18_CF_EN (0x1<<4)
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX18_CF_EN_SHIFT 4
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX19_CF_EN (0x1<<5)
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX19_CF_EN_SHIFT 5
-#define __XSTORM_ISCSI_AG_CONTEXT_R2TQ_PROD_CF_EN (0x1<<6)
-#define __XSTORM_ISCSI_AG_CONTEXT_R2TQ_PROD_CF_EN_SHIFT 6
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX21_CF_EN (0x1<<7)
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX21_CF_EN_SHIFT 7
+#define __XSTORM_ISCSI_AG_CONTEXT_RX_TS_EN_CF (0x3<<6)
+#define __XSTORM_ISCSI_AG_CONTEXT_RX_TS_EN_CF_SHIFT 6
+ u8 __agg_vars4;
u8 cdu_reserved;
#endif
u32 more_to_send;
@@ -1270,8 +1356,8 @@ struct xstorm_iscsi_ag_context {
#define __XSTORM_ISCSI_AG_CONTEXT_AGG_VAL11_DECISION_RULE_SHIFT 0
#define __XSTORM_ISCSI_AG_CONTEXT_AUX13_FLAG (0x1<<3)
#define __XSTORM_ISCSI_AG_CONTEXT_AUX13_FLAG_SHIFT 3
-#define XSTORM_ISCSI_AG_CONTEXT_AUX18_CF (0x3<<4)
-#define XSTORM_ISCSI_AG_CONTEXT_AUX18_CF_SHIFT 4
+#define __XSTORM_ISCSI_AG_CONTEXT_STORMS_SYNC_CF (0x3<<4)
+#define __XSTORM_ISCSI_AG_CONTEXT_STORMS_SYNC_CF_SHIFT 4
#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE3 (0x3<<6)
#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE3_SHIFT 6
#define XSTORM_ISCSI_AG_CONTEXT_AUX1_CF (0x3<<8)
@@ -1286,8 +1372,8 @@ struct xstorm_iscsi_ag_context {
#define __XSTORM_ISCSI_AG_CONTEXT_AUX11_FLAG_SHIFT 13
#define __XSTORM_ISCSI_AG_CONTEXT_AUX12_FLAG (0x1<<14)
#define __XSTORM_ISCSI_AG_CONTEXT_AUX12_FLAG_SHIFT 14
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX2_FLAG (0x1<<15)
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX2_FLAG_SHIFT 15
+#define __XSTORM_ISCSI_AG_CONTEXT_RX_WND_SCL_EN (0x1<<15)
+#define __XSTORM_ISCSI_AG_CONTEXT_RX_WND_SCL_EN_SHIFT 15
u8 agg_val3_th;
u8 agg_vars6;
#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE6 (0x7<<0)
@@ -1310,8 +1396,8 @@ struct xstorm_iscsi_ag_context {
#define __XSTORM_ISCSI_AG_CONTEXT_AGG_VAL11_DECISION_RULE_SHIFT 0
#define __XSTORM_ISCSI_AG_CONTEXT_AUX13_FLAG (0x1<<3)
#define __XSTORM_ISCSI_AG_CONTEXT_AUX13_FLAG_SHIFT 3
-#define XSTORM_ISCSI_AG_CONTEXT_AUX18_CF (0x3<<4)
-#define XSTORM_ISCSI_AG_CONTEXT_AUX18_CF_SHIFT 4
+#define __XSTORM_ISCSI_AG_CONTEXT_STORMS_SYNC_CF (0x3<<4)
+#define __XSTORM_ISCSI_AG_CONTEXT_STORMS_SYNC_CF_SHIFT 4
#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE3 (0x3<<6)
#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE3_SHIFT 6
#define XSTORM_ISCSI_AG_CONTEXT_AUX1_CF (0x3<<8)
@@ -1326,14 +1412,14 @@ struct xstorm_iscsi_ag_context {
#define __XSTORM_ISCSI_AG_CONTEXT_AUX11_FLAG_SHIFT 13
#define __XSTORM_ISCSI_AG_CONTEXT_AUX12_FLAG (0x1<<14)
#define __XSTORM_ISCSI_AG_CONTEXT_AUX12_FLAG_SHIFT 14
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX2_FLAG (0x1<<15)
-#define __XSTORM_ISCSI_AG_CONTEXT_AUX2_FLAG_SHIFT 15
+#define __XSTORM_ISCSI_AG_CONTEXT_RX_WND_SCL_EN (0x1<<15)
+#define __XSTORM_ISCSI_AG_CONTEXT_RX_WND_SCL_EN_SHIFT 15
#endif
#if defined(__BIG_ENDIAN)
u16 __agg_val11_th;
- u16 __agg_val11;
+ u16 __gen_data;
#elif defined(__LITTLE_ENDIAN)
- u16 __agg_val11;
+ u16 __gen_data;
u16 __agg_val11_th;
#endif
#if defined(__BIG_ENDIAN)
@@ -1384,7 +1470,7 @@ struct xstorm_iscsi_ag_context {
#endif
u32 hq_cons_tcp_seq;
u32 exp_stat_sn;
- u32 agg_misc5;
+ u32 rst_seq_num;
};
/*
@@ -1478,12 +1564,12 @@ struct tstorm_iscsi_ag_context {
#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2_SHIFT 2
#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3 (0x1<<3)
#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3_SHIFT 3
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX3_CF (0x3<<4)
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX3_CF_SHIFT 4
+#define __TSTORM_ISCSI_AG_CONTEXT_QUEUES_FLUSH_Q0_CF (0x3<<4)
+#define __TSTORM_ISCSI_AG_CONTEXT_QUEUES_FLUSH_Q0_CF_SHIFT 4
#define __TSTORM_ISCSI_AG_CONTEXT_AUX3_FLAG (0x1<<6)
#define __TSTORM_ISCSI_AG_CONTEXT_AUX3_FLAG_SHIFT 6
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX4_FLAG (0x1<<7)
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX4_FLAG_SHIFT 7
+#define __TSTORM_ISCSI_AG_CONTEXT_ACK_ON_FIN_SENT_FLAG (0x1<<7)
+#define __TSTORM_ISCSI_AG_CONTEXT_ACK_ON_FIN_SENT_FLAG_SHIFT 7
u8 state;
#elif defined(__LITTLE_ENDIAN)
u8 state;
@@ -1496,63 +1582,63 @@ struct tstorm_iscsi_ag_context {
#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2_SHIFT 2
#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3 (0x1<<3)
#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3_SHIFT 3
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX3_CF (0x3<<4)
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX3_CF_SHIFT 4
+#define __TSTORM_ISCSI_AG_CONTEXT_QUEUES_FLUSH_Q0_CF (0x3<<4)
+#define __TSTORM_ISCSI_AG_CONTEXT_QUEUES_FLUSH_Q0_CF_SHIFT 4
#define __TSTORM_ISCSI_AG_CONTEXT_AUX3_FLAG (0x1<<6)
#define __TSTORM_ISCSI_AG_CONTEXT_AUX3_FLAG_SHIFT 6
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX4_FLAG (0x1<<7)
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX4_FLAG_SHIFT 7
+#define __TSTORM_ISCSI_AG_CONTEXT_ACK_ON_FIN_SENT_FLAG (0x1<<7)
+#define __TSTORM_ISCSI_AG_CONTEXT_ACK_ON_FIN_SENT_FLAG_SHIFT 7
u16 ulp_credit;
#endif
#if defined(__BIG_ENDIAN)
u16 __agg_val4;
u16 agg_vars2;
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX5_FLAG (0x1<<0)
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX5_FLAG_SHIFT 0
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX6_FLAG (0x1<<1)
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX6_FLAG_SHIFT 1
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX4_CF (0x3<<2)
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX4_CF_SHIFT 2
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX5_CF (0x3<<4)
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX5_CF_SHIFT 4
+#define __TSTORM_ISCSI_AG_CONTEXT_MSL_TIMER_SET_FLAG (0x1<<0)
+#define __TSTORM_ISCSI_AG_CONTEXT_MSL_TIMER_SET_FLAG_SHIFT 0
+#define __TSTORM_ISCSI_AG_CONTEXT_FIN_SENT_FIRST_FLAG (0x1<<1)
+#define __TSTORM_ISCSI_AG_CONTEXT_FIN_SENT_FIRST_FLAG_SHIFT 1
+#define __TSTORM_ISCSI_AG_CONTEXT_RST_SENT_CF (0x3<<2)
+#define __TSTORM_ISCSI_AG_CONTEXT_RST_SENT_CF_SHIFT 2
+#define __TSTORM_ISCSI_AG_CONTEXT_WAKEUP_CALL_CF (0x3<<4)
+#define __TSTORM_ISCSI_AG_CONTEXT_WAKEUP_CALL_CF_SHIFT 4
#define __TSTORM_ISCSI_AG_CONTEXT_AUX6_CF (0x3<<6)
#define __TSTORM_ISCSI_AG_CONTEXT_AUX6_CF_SHIFT 6
#define __TSTORM_ISCSI_AG_CONTEXT_AUX7_CF (0x3<<8)
#define __TSTORM_ISCSI_AG_CONTEXT_AUX7_CF_SHIFT 8
#define __TSTORM_ISCSI_AG_CONTEXT_AUX7_FLAG (0x1<<10)
#define __TSTORM_ISCSI_AG_CONTEXT_AUX7_FLAG_SHIFT 10
-#define TSTORM_ISCSI_AG_CONTEXT_AUX3_CF_EN (0x1<<11)
-#define TSTORM_ISCSI_AG_CONTEXT_AUX3_CF_EN_SHIFT 11
-#define TSTORM_ISCSI_AG_CONTEXT_AUX4_CF_EN (0x1<<12)
-#define TSTORM_ISCSI_AG_CONTEXT_AUX4_CF_EN_SHIFT 12
-#define TSTORM_ISCSI_AG_CONTEXT_AUX5_CF_EN (0x1<<13)
-#define TSTORM_ISCSI_AG_CONTEXT_AUX5_CF_EN_SHIFT 13
+#define __TSTORM_ISCSI_AG_CONTEXT_QUEUES_FLUSH_Q0_CF_EN (0x1<<11)
+#define __TSTORM_ISCSI_AG_CONTEXT_QUEUES_FLUSH_Q0_CF_EN_SHIFT 11
+#define __TSTORM_ISCSI_AG_CONTEXT_RST_SENT_CF_EN (0x1<<12)
+#define __TSTORM_ISCSI_AG_CONTEXT_RST_SENT_CF_EN_SHIFT 12
+#define __TSTORM_ISCSI_AG_CONTEXT_WAKEUP_CALL_CF_EN (0x1<<13)
+#define __TSTORM_ISCSI_AG_CONTEXT_WAKEUP_CALL_CF_EN_SHIFT 13
#define TSTORM_ISCSI_AG_CONTEXT_AUX6_CF_EN (0x1<<14)
#define TSTORM_ISCSI_AG_CONTEXT_AUX6_CF_EN_SHIFT 14
#define TSTORM_ISCSI_AG_CONTEXT_AUX7_CF_EN (0x1<<15)
#define TSTORM_ISCSI_AG_CONTEXT_AUX7_CF_EN_SHIFT 15
#elif defined(__LITTLE_ENDIAN)
u16 agg_vars2;
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX5_FLAG (0x1<<0)
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX5_FLAG_SHIFT 0
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX6_FLAG (0x1<<1)
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX6_FLAG_SHIFT 1
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX4_CF (0x3<<2)
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX4_CF_SHIFT 2
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX5_CF (0x3<<4)
-#define __TSTORM_ISCSI_AG_CONTEXT_AUX5_CF_SHIFT 4
+#define __TSTORM_ISCSI_AG_CONTEXT_MSL_TIMER_SET_FLAG (0x1<<0)
+#define __TSTORM_ISCSI_AG_CONTEXT_MSL_TIMER_SET_FLAG_SHIFT 0
+#define __TSTORM_ISCSI_AG_CONTEXT_FIN_SENT_FIRST_FLAG (0x1<<1)
+#define __TSTORM_ISCSI_AG_CONTEXT_FIN_SENT_FIRST_FLAG_SHIFT 1
+#define __TSTORM_ISCSI_AG_CONTEXT_RST_SENT_CF (0x3<<2)
+#define __TSTORM_ISCSI_AG_CONTEXT_RST_SENT_CF_SHIFT 2
+#define __TSTORM_ISCSI_AG_CONTEXT_WAKEUP_CALL_CF (0x3<<4)
+#define __TSTORM_ISCSI_AG_CONTEXT_WAKEUP_CALL_CF_SHIFT 4
#define __TSTORM_ISCSI_AG_CONTEXT_AUX6_CF (0x3<<6)
#define __TSTORM_ISCSI_AG_CONTEXT_AUX6_CF_SHIFT 6
#define __TSTORM_ISCSI_AG_CONTEXT_AUX7_CF (0x3<<8)
#define __TSTORM_ISCSI_AG_CONTEXT_AUX7_CF_SHIFT 8
#define __TSTORM_ISCSI_AG_CONTEXT_AUX7_FLAG (0x1<<10)
#define __TSTORM_ISCSI_AG_CONTEXT_AUX7_FLAG_SHIFT 10
-#define TSTORM_ISCSI_AG_CONTEXT_AUX3_CF_EN (0x1<<11)
-#define TSTORM_ISCSI_AG_CONTEXT_AUX3_CF_EN_SHIFT 11
-#define TSTORM_ISCSI_AG_CONTEXT_AUX4_CF_EN (0x1<<12)
-#define TSTORM_ISCSI_AG_CONTEXT_AUX4_CF_EN_SHIFT 12
-#define TSTORM_ISCSI_AG_CONTEXT_AUX5_CF_EN (0x1<<13)
-#define TSTORM_ISCSI_AG_CONTEXT_AUX5_CF_EN_SHIFT 13
+#define __TSTORM_ISCSI_AG_CONTEXT_QUEUES_FLUSH_Q0_CF_EN (0x1<<11)
+#define __TSTORM_ISCSI_AG_CONTEXT_QUEUES_FLUSH_Q0_CF_EN_SHIFT 11
+#define __TSTORM_ISCSI_AG_CONTEXT_RST_SENT_CF_EN (0x1<<12)
+#define __TSTORM_ISCSI_AG_CONTEXT_RST_SENT_CF_EN_SHIFT 12
+#define __TSTORM_ISCSI_AG_CONTEXT_WAKEUP_CALL_CF_EN (0x1<<13)
+#define __TSTORM_ISCSI_AG_CONTEXT_WAKEUP_CALL_CF_EN_SHIFT 13
#define TSTORM_ISCSI_AG_CONTEXT_AUX6_CF_EN (0x1<<14)
#define TSTORM_ISCSI_AG_CONTEXT_AUX6_CF_EN_SHIFT 14
#define TSTORM_ISCSI_AG_CONTEXT_AUX7_CF_EN (0x1<<15)
@@ -1563,100 +1649,6 @@ struct tstorm_iscsi_ag_context {
};
/*
- * The iscsi aggregative context of Cstorm
- */
-struct cstorm_iscsi_ag_context {
- u32 agg_vars1;
-#define CSTORM_ISCSI_AG_CONTEXT_STATE (0xFF<<0)
-#define CSTORM_ISCSI_AG_CONTEXT_STATE_SHIFT 0
-#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0 (0x1<<8)
-#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0_SHIFT 8
-#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1 (0x1<<9)
-#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1_SHIFT 9
-#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2 (0x1<<10)
-#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2_SHIFT 10
-#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3 (0x1<<11)
-#define __CSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3_SHIFT 11
-#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED_ULP_RX_SE_CF_EN (0x1<<12)
-#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED_ULP_RX_SE_CF_EN_SHIFT 12
-#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED_ULP_RX_INV_CF_EN (0x1<<13)
-#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED_ULP_RX_INV_CF_EN_SHIFT 13
-#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION3_CF (0x3<<14)
-#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION3_CF_SHIFT 14
-#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED66 (0x3<<16)
-#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED66_SHIFT 16
-#define __CSTORM_ISCSI_AG_CONTEXT_FIN_RECEIVED_CF_EN (0x1<<18)
-#define __CSTORM_ISCSI_AG_CONTEXT_FIN_RECEIVED_CF_EN_SHIFT 18
-#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION0_CF_EN (0x1<<19)
-#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION0_CF_EN_SHIFT 19
-#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION1_CF_EN (0x1<<20)
-#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION1_CF_EN_SHIFT 20
-#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION2_CF_EN (0x1<<21)
-#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION2_CF_EN_SHIFT 21
-#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION3_CF_EN (0x1<<22)
-#define __CSTORM_ISCSI_AG_CONTEXT_PENDING_COMPLETION3_CF_EN_SHIFT 22
-#define __CSTORM_ISCSI_AG_CONTEXT_REL_SEQ_RULE (0x7<<23)
-#define __CSTORM_ISCSI_AG_CONTEXT_REL_SEQ_RULE_SHIFT 23
-#define CSTORM_ISCSI_AG_CONTEXT_HQ_PROD_RULE (0x3<<26)
-#define CSTORM_ISCSI_AG_CONTEXT_HQ_PROD_RULE_SHIFT 26
-#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED52 (0x3<<28)
-#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED52_SHIFT 28
-#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED53 (0x3<<30)
-#define __CSTORM_ISCSI_AG_CONTEXT_RESERVED53_SHIFT 30
-#if defined(__BIG_ENDIAN)
- u8 __aux1_th;
- u8 __aux1_val;
- u16 __agg_vars2;
-#elif defined(__LITTLE_ENDIAN)
- u16 __agg_vars2;
- u8 __aux1_val;
- u8 __aux1_th;
-#endif
- u32 rel_seq;
- u32 rel_seq_th;
-#if defined(__BIG_ENDIAN)
- u16 hq_cons;
- u16 hq_prod;
-#elif defined(__LITTLE_ENDIAN)
- u16 hq_prod;
- u16 hq_cons;
-#endif
-#if defined(__BIG_ENDIAN)
- u8 __reserved62;
- u8 __reserved61;
- u8 __reserved60;
- u8 __reserved59;
-#elif defined(__LITTLE_ENDIAN)
- u8 __reserved59;
- u8 __reserved60;
- u8 __reserved61;
- u8 __reserved62;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 __reserved64;
- u16 __cq_u_prod0;
-#elif defined(__LITTLE_ENDIAN)
- u16 __cq_u_prod0;
- u16 __reserved64;
-#endif
- u32 __cq_u_prod1;
-#if defined(__BIG_ENDIAN)
- u16 __agg_vars3;
- u16 __cq_u_prod2;
-#elif defined(__LITTLE_ENDIAN)
- u16 __cq_u_prod2;
- u16 __agg_vars3;
-#endif
-#if defined(__BIG_ENDIAN)
- u16 __aux2_th;
- u16 __cq_u_prod3;
-#elif defined(__LITTLE_ENDIAN)
- u16 __cq_u_prod3;
- u16 __aux2_th;
-#endif
-};
-
-/*
* The iscsi aggregative context of Ustorm
*/
struct ustorm_iscsi_ag_context {
@@ -1746,8 +1738,8 @@ struct ustorm_iscsi_ag_context {
#define USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_RULE_SHIFT 0
#define __USTORM_ISCSI_AG_CONTEXT_AGG_VAL3_RULE (0x7<<3)
#define __USTORM_ISCSI_AG_CONTEXT_AGG_VAL3_RULE_SHIFT 3
-#define __USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_ARM_N_FLAG (0x1<<6)
-#define __USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_ARM_N_FLAG_SHIFT 6
+#define USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_ARM_N_FLAG (0x1<<6)
+#define USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_ARM_N_FLAG_SHIFT 6
#define __USTORM_ISCSI_AG_CONTEXT_RESERVED1 (0x1<<7)
#define __USTORM_ISCSI_AG_CONTEXT_RESERVED1_SHIFT 7
u8 decision_rule_enable_bits;
@@ -1790,8 +1782,8 @@ struct ustorm_iscsi_ag_context {
#define USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_RULE_SHIFT 0
#define __USTORM_ISCSI_AG_CONTEXT_AGG_VAL3_RULE (0x7<<3)
#define __USTORM_ISCSI_AG_CONTEXT_AGG_VAL3_RULE_SHIFT 3
-#define __USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_ARM_N_FLAG (0x1<<6)
-#define __USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_ARM_N_FLAG_SHIFT 6
+#define USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_ARM_N_FLAG (0x1<<6)
+#define USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_ARM_N_FLAG_SHIFT 6
#define __USTORM_ISCSI_AG_CONTEXT_RESERVED1 (0x1<<7)
#define __USTORM_ISCSI_AG_CONTEXT_RESERVED1_SHIFT 7
u16 __reserved2;
@@ -1799,22 +1791,6 @@ struct ustorm_iscsi_ag_context {
};
/*
- * Timers connection context
- */
-struct iscsi_timers_block_context {
- u32 __reserved_0;
- u32 __reserved_1;
- u32 __reserved_2;
- u32 flags;
-#define __ISCSI_TIMERS_BLOCK_CONTEXT_NUM_OF_ACTIVE_TIMERS (0x3<<0)
-#define __ISCSI_TIMERS_BLOCK_CONTEXT_NUM_OF_ACTIVE_TIMERS_SHIFT 0
-#define ISCSI_TIMERS_BLOCK_CONTEXT_CONN_VALID_FLG (0x1<<2)
-#define ISCSI_TIMERS_BLOCK_CONTEXT_CONN_VALID_FLG_SHIFT 2
-#define __ISCSI_TIMERS_BLOCK_CONTEXT_RESERVED0 (0x1FFFFFFF<<3)
-#define __ISCSI_TIMERS_BLOCK_CONTEXT_RESERVED0_SHIFT 3
-};
-
-/*
* Ethernet context section, shared in TOE, RDMA and ISCSI
*/
struct xstorm_eth_context_section {
@@ -1963,7 +1939,7 @@ struct xstorm_tcp_context_section {
#endif
#if defined(__BIG_ENDIAN)
u8 original_nagle_1b;
- u8 ts_enabled_1b;
+ u8 ts_enabled;
u16 tcp_params;
#define XSTORM_TCP_CONTEXT_SECTION_TOTAL_HEADER_SIZE (0xFF<<0)
#define XSTORM_TCP_CONTEXT_SECTION_TOTAL_HEADER_SIZE_SHIFT 0
@@ -1973,8 +1949,8 @@ struct xstorm_tcp_context_section {
#define __XSTORM_TCP_CONTEXT_SECTION_ECN_ENABLED_SHIFT 9
#define XSTORM_TCP_CONTEXT_SECTION_SACK_ENABLED (0x1<<10)
#define XSTORM_TCP_CONTEXT_SECTION_SACK_ENABLED_SHIFT 10
-#define XSTORM_TCP_CONTEXT_SECTION_KA_STATE (0x1<<11)
-#define XSTORM_TCP_CONTEXT_SECTION_KA_STATE_SHIFT 11
+#define XSTORM_TCP_CONTEXT_SECTION_SMALL_WIN_ADV (0x1<<11)
+#define XSTORM_TCP_CONTEXT_SECTION_SMALL_WIN_ADV_SHIFT 11
#define XSTORM_TCP_CONTEXT_SECTION_FIN_SENT_FLAG (0x1<<12)
#define XSTORM_TCP_CONTEXT_SECTION_FIN_SENT_FLAG_SHIFT 12
#define XSTORM_TCP_CONTEXT_SECTION_WINDOW_SATURATED (0x1<<13)
@@ -1991,15 +1967,15 @@ struct xstorm_tcp_context_section {
#define __XSTORM_TCP_CONTEXT_SECTION_ECN_ENABLED_SHIFT 9
#define XSTORM_TCP_CONTEXT_SECTION_SACK_ENABLED (0x1<<10)
#define XSTORM_TCP_CONTEXT_SECTION_SACK_ENABLED_SHIFT 10
-#define XSTORM_TCP_CONTEXT_SECTION_KA_STATE (0x1<<11)
-#define XSTORM_TCP_CONTEXT_SECTION_KA_STATE_SHIFT 11
+#define XSTORM_TCP_CONTEXT_SECTION_SMALL_WIN_ADV (0x1<<11)
+#define XSTORM_TCP_CONTEXT_SECTION_SMALL_WIN_ADV_SHIFT 11
#define XSTORM_TCP_CONTEXT_SECTION_FIN_SENT_FLAG (0x1<<12)
#define XSTORM_TCP_CONTEXT_SECTION_FIN_SENT_FLAG_SHIFT 12
#define XSTORM_TCP_CONTEXT_SECTION_WINDOW_SATURATED (0x1<<13)
#define XSTORM_TCP_CONTEXT_SECTION_WINDOW_SATURATED_SHIFT 13
#define XSTORM_TCP_CONTEXT_SECTION_SLOWPATH_QUEUES_FLUSH_COUNTER (0x3<<14)
#define XSTORM_TCP_CONTEXT_SECTION_SLOWPATH_QUEUES_FLUSH_COUNTER_SHIFT 14
- u8 ts_enabled_1b;
+ u8 ts_enabled;
u8 original_nagle_1b;
#endif
#if defined(__BIG_ENDIAN)
@@ -2030,8 +2006,8 @@ struct xstorm_common_context_section {
#define XSTORM_COMMON_CONTEXT_SECTION_UPDATE_L4_STATSTICS_SHIFT 1
#define XSTORM_COMMON_CONTEXT_SECTION_STATISTICS_COUNTER_ID (0x1F<<2)
#define XSTORM_COMMON_CONTEXT_SECTION_STATISTICS_COUNTER_ID_SHIFT 2
-#define XSTORM_COMMON_CONTEXT_SECTION_RESERVED0 (0x1<<7)
-#define XSTORM_COMMON_CONTEXT_SECTION_RESERVED0_SHIFT 7
+#define XSTORM_COMMON_CONTEXT_SECTION_DCB_EXISTS (0x1<<7)
+#define XSTORM_COMMON_CONTEXT_SECTION_DCB_EXISTS_SHIFT 7
u8 ip_version_1b;
#elif defined(__LITTLE_ENDIAN)
u8 ip_version_1b;
@@ -2042,8 +2018,8 @@ struct xstorm_common_context_section {
#define XSTORM_COMMON_CONTEXT_SECTION_UPDATE_L4_STATSTICS_SHIFT 1
#define XSTORM_COMMON_CONTEXT_SECTION_STATISTICS_COUNTER_ID (0x1F<<2)
#define XSTORM_COMMON_CONTEXT_SECTION_STATISTICS_COUNTER_ID_SHIFT 2
-#define XSTORM_COMMON_CONTEXT_SECTION_RESERVED0 (0x1<<7)
-#define XSTORM_COMMON_CONTEXT_SECTION_RESERVED0_SHIFT 7
+#define XSTORM_COMMON_CONTEXT_SECTION_DCB_EXISTS (0x1<<7)
+#define XSTORM_COMMON_CONTEXT_SECTION_DCB_EXISTS_SHIFT 7
u16 reserved;
#endif
};
@@ -2284,7 +2260,7 @@ struct iscsi_context {
struct tstorm_iscsi_ag_context tstorm_ag_context;
struct cstorm_iscsi_ag_context cstorm_ag_context;
struct ustorm_iscsi_ag_context ustorm_ag_context;
- struct iscsi_timers_block_context timers_context;
+ struct timers_block_context timers_context;
struct regpair upb_context;
struct xstorm_iscsi_st_context xstorm_st_context;
struct regpair xpb_context;
@@ -2434,16 +2410,16 @@ struct l5cm_packet_size {
* l5cm connection parameters
*/
union l5cm_reduce_param_union {
- u32 passive_side_scramble_key;
- u32 pcs_id;
+ u32 opaque1;
+ u32 opaque2;
};
/*
* l5cm connection parameters
*/
struct l5cm_reduce_conn {
- union l5cm_reduce_param_union param;
- u32 isn;
+ union l5cm_reduce_param_union opaque1;
+ u32 opaque2;
};
/*
diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h
index 344c842d55ab..0dbeaec4f03a 100644
--- a/drivers/net/cnic_if.h
+++ b/drivers/net/cnic_if.h
@@ -12,8 +12,8 @@
#ifndef CNIC_IF_H
#define CNIC_IF_H
-#define CNIC_MODULE_VERSION "2.1.3"
-#define CNIC_MODULE_RELDATE "June 24, 2010"
+#define CNIC_MODULE_VERSION "2.2.6"
+#define CNIC_MODULE_RELDATE "Oct 12, 2010"
#define CNIC_ULP_RDMA 0
#define CNIC_ULP_ISCSI 1
@@ -80,18 +80,15 @@ struct kcqe {
#define DRV_CTL_IO_RD_CMD 0x102
#define DRV_CTL_CTX_WR_CMD 0x103
#define DRV_CTL_CTXTBL_WR_CMD 0x104
-#define DRV_CTL_COMPLETION_CMD 0x105
+#define DRV_CTL_RET_L5_SPQ_CREDIT_CMD 0x105
#define DRV_CTL_START_L2_CMD 0x106
#define DRV_CTL_STOP_L2_CMD 0x107
+#define DRV_CTL_RET_L2_SPQ_CREDIT_CMD 0x10c
struct cnic_ctl_completion {
u32 cid;
};
-struct drv_ctl_completion {
- u32 comp_count;
-};
-
struct cnic_ctl_info {
int cmd;
union {
@@ -100,6 +97,10 @@ struct cnic_ctl_info {
} data;
};
+struct drv_ctl_spq_credit {
+ u32 credit_count;
+};
+
struct drv_ctl_io {
u32 cid_addr;
u32 offset;
@@ -115,7 +116,7 @@ struct drv_ctl_l2_ring {
struct drv_ctl_info {
int cmd;
union {
- struct drv_ctl_completion comp;
+ struct drv_ctl_spq_credit credit;
struct drv_ctl_io io;
struct drv_ctl_l2_ring ring;
char bytes[MAX_DRV_CTL_DATA];
@@ -138,6 +139,7 @@ struct cnic_irq {
unsigned int vector;
void *status_blk;
u32 status_blk_num;
+ u32 status_blk_num2;
u32 irq_flags;
#define CNIC_IRQ_FL_MSIX 0x00000001
};
@@ -152,6 +154,7 @@ struct cnic_eth_dev {
struct pci_dev *pdev;
void __iomem *io_base;
void __iomem *io_base2;
+ void *iro_arr;
u32 ctx_tbl_offset;
u32 ctx_tbl_len;
@@ -160,7 +163,9 @@ struct cnic_eth_dev {
u32 max_iscsi_conn;
u32 max_fcoe_conn;
u32 max_rdma_conn;
- u32 reserved0[2];
+ u32 fcoe_init_cid;
+ u16 iscsi_l2_client_id;
+ u16 iscsi_l2_cid;
int num_irq;
struct cnic_irq irq_arr[MAX_CNIC_VEC];
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
index e1f6156b3710..fec939f8f65f 100644
--- a/drivers/net/cpmac.c
+++ b/drivers/net/cpmac.c
@@ -38,7 +38,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
-#include <asm/gpio.h>
+#include <linux/gpio.h>
#include <asm/atomic.h>
MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>");
@@ -108,7 +108,7 @@ MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus");
#define CPMAC_RX_INT_CLEAR 0x019c
#define CPMAC_MAC_INT_ENABLE 0x01a8
#define CPMAC_MAC_INT_CLEAR 0x01ac
-#define CPMAC_MAC_ADDR_LO(channel) (0x01b0 + (channel) * 4)
+#define CPMAC_MAC_ADDR_LO(channel) (0x01b0 + (channel) * 4)
#define CPMAC_MAC_ADDR_MID 0x01d0
#define CPMAC_MAC_ADDR_HI 0x01d4
#define CPMAC_MAC_HASH_LO 0x01d8
@@ -227,7 +227,7 @@ static void cpmac_dump_regs(struct net_device *dev)
for (i = 0; i < CPMAC_REG_END; i += 4) {
if (i % 16 == 0) {
if (i)
- printk("\n");
+ pr_cont("\n");
printk(KERN_DEBUG "%s: reg[%p]:", dev->name,
priv->regs + i);
}
@@ -262,7 +262,7 @@ static void cpmac_dump_skb(struct net_device *dev, struct sk_buff *skb)
for (i = 0; i < skb->len; i++) {
if (i % 16 == 0) {
if (i)
- printk("\n");
+ pr_cont("\n");
printk(KERN_DEBUG "%s: data[%p]:", dev->name,
skb->data + i);
}
@@ -391,7 +391,7 @@ static struct sk_buff *cpmac_rx_one(struct cpmac_priv *priv,
if (likely(skb)) {
skb_put(desc->skb, desc->datalen);
desc->skb->protocol = eth_type_trans(desc->skb, priv->dev);
- desc->skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(desc->skb);
priv->dev->stats.rx_packets++;
priv->dev->stats.rx_bytes += desc->datalen;
result = desc->skb;
@@ -506,7 +506,7 @@ static int cpmac_poll(struct napi_struct *napi, int budget)
"restart rx from a descriptor that's "
"not free: %p\n",
priv->dev->name, restart);
- goto fatal_error;
+ goto fatal_error;
}
cpmac_write(priv->regs, CPMAC_RX_PTR(0), restart->mapping);
@@ -873,7 +873,8 @@ static int cpmac_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
return -EINVAL;
}
-static void cpmac_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
+static void cpmac_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
{
struct cpmac_priv *priv = netdev_priv(dev);
@@ -888,7 +889,8 @@ static void cpmac_get_ringparam(struct net_device *dev, struct ethtool_ringparam
ring->tx_pending = 1;
}
-static int cpmac_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
+static int cpmac_set_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
{
struct cpmac_priv *priv = netdev_priv(dev);
@@ -1012,8 +1014,8 @@ static int cpmac_open(struct net_device *dev)
priv->rx_head->prev->hw_next = (u32)0;
- if ((res = request_irq(dev->irq, cpmac_irq, IRQF_SHARED,
- dev->name, dev))) {
+ res = request_irq(dev->irq, cpmac_irq, IRQF_SHARED, dev->name, dev);
+ if (res) {
if (netif_msg_drv(priv))
printk(KERN_ERR "%s: failed to obtain irq\n",
dev->name);
@@ -1133,7 +1135,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
}
if (phy_id == PHY_MAX_ADDR) {
- dev_err(&pdev->dev, "no PHY present, falling back to switch on MDIO bus 0\n");
+ dev_err(&pdev->dev, "no PHY present, falling back "
+ "to switch on MDIO bus 0\n");
strncpy(mdio_bus_id, "0", MII_BUS_ID_SIZE); /* fixed phys bus */
phy_id = pdev->id;
}
@@ -1169,9 +1172,10 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
priv->msg_enable = netif_msg_init(debug_level, 0xff);
memcpy(dev->dev_addr, pdata->dev_addr, sizeof(pdata->dev_addr));
- snprintf(priv->phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id);
+ snprintf(priv->phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT,
+ mdio_bus_id, phy_id);
- priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, 0,
+ priv->phy = phy_connect(dev, priv->phy_name, cpmac_adjust_link, 0,
PHY_INTERFACE_MODE_MII);
if (IS_ERR(priv->phy)) {
@@ -1182,7 +1186,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
goto fail;
}
- if ((rc = register_netdev(dev))) {
+ rc = register_netdev(dev);
+ if (rc) {
printk(KERN_ERR "cpmac: error %i registering device %s\n", rc,
dev->name);
goto fail;
@@ -1248,11 +1253,13 @@ int __devinit cpmac_init(void)
cpmac_mii->reset(cpmac_mii);
- for (i = 0; i < 300; i++)
- if ((mask = cpmac_read(cpmac_mii->priv, CPMAC_MDIO_ALIVE)))
+ for (i = 0; i < 300; i++) {
+ mask = cpmac_read(cpmac_mii->priv, CPMAC_MDIO_ALIVE);
+ if (mask)
break;
else
msleep(10);
+ }
mask &= 0x7fffffff;
if (mask & (mask - 1)) {
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 4cd7f420766a..ef67be59680f 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -336,9 +336,6 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
int irq_vec_idx, const struct qset_params *p,
int ntxq, struct net_device *dev,
struct netdev_queue *netdevq);
-int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
- unsigned char *data);
-irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
extern struct workqueue_struct *cxgb3_wq;
int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size);
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index fe08a004b0dd..5ccb77d078aa 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -673,7 +673,6 @@ void t3_xgm_intr_enable(struct adapter *adapter, int idx);
void t3_xgm_intr_disable(struct adapter *adapter, int idx);
void t3_port_intr_enable(struct adapter *adapter, int idx);
void t3_port_intr_disable(struct adapter *adapter, int idx);
-void t3_port_intr_clear(struct adapter *adapter, int idx);
int t3_slow_intr_handler(struct adapter *adapter);
int t3_phy_intr_handler(struct adapter *adapter);
@@ -689,14 +688,10 @@ int t3_check_tpsram_version(struct adapter *adapter);
int t3_check_tpsram(struct adapter *adapter, const u8 *tp_ram,
unsigned int size);
int t3_set_proto_sram(struct adapter *adap, const u8 *data);
-int t3_read_flash(struct adapter *adapter, unsigned int addr,
- unsigned int nwords, u32 *data, int byte_oriented);
int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size);
int t3_get_fw_version(struct adapter *adapter, u32 *vers);
int t3_check_fw_version(struct adapter *adapter);
int t3_init_hw(struct adapter *adapter, u32 fw_params);
-void mac_prep(struct cmac *mac, struct adapter *adapter, int index);
-void early_hw_init(struct adapter *adapter, const struct adapter_info *ai);
int t3_reset_adapter(struct adapter *adapter);
int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
int reset);
@@ -706,8 +701,6 @@ void t3_fatal_err(struct adapter *adapter);
void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on);
void t3_config_rss(struct adapter *adapter, unsigned int rss_config,
const u8 * cpus, const u16 *rspq);
-int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map);
-int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask);
int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
unsigned int n, unsigned int *valp);
int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
@@ -731,19 +724,12 @@ void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode);
int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
unsigned int nroutes);
void t3_mc5_intr_handler(struct mc5 *mc5);
-int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start, unsigned int n,
- u32 *buf);
-int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh);
-void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size);
void t3_tp_set_offload_mode(struct adapter *adap, int enable);
void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps);
void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS],
unsigned short alpha[NCCTRL_WIN],
unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap);
-void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS]);
-void t3_get_cong_cntl_tab(struct adapter *adap,
- unsigned short incr[NMTUS][NCCTRL_WIN]);
void t3_config_trace_filter(struct adapter *adapter,
const struct trace_params *tp, int filter_index,
int invert, int enable);
@@ -769,10 +755,6 @@ int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable);
int t3_sge_disable_fl(struct adapter *adapter, unsigned int id);
int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id);
int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id);
-int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4]);
-int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4]);
-int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4]);
-int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4]);
int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
unsigned int credits);
diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h
index 47e53769af5b..920d918ed193 100644
--- a/drivers/net/cxgb3/cxgb3_defs.h
+++ b/drivers/net/cxgb3/cxgb3_defs.h
@@ -43,8 +43,6 @@
void *cxgb_alloc_mem(unsigned long size);
void cxgb_free_mem(void *addr);
-void cxgb_neigh_update(struct neighbour *neigh);
-void cxgb_redirect(struct dst_entry *old, struct dst_entry *new);
/*
* Map an ATID or STID to their entries in the corresponding TID tables.
@@ -111,7 +109,6 @@ static inline struct t3c_tid_entry *lookup_atid(const struct tid_info *t,
return &e->t3c_tid;
}
-int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n);
int attach_t3cdev(struct t3cdev *dev);
void detach_t3cdev(struct t3cdev *dev);
#endif
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index f208712c0b90..4e3c12371aae 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -1266,11 +1266,13 @@ static int cxgb_up(struct adapter *adap)
}
if (!(adap->flags & QUEUES_BOUND)) {
- err = bind_qsets(adap);
- if (err) {
- CH_ERR(adap, "failed to bind qsets, err %d\n", err);
+ int ret = bind_qsets(adap);
+
+ if (ret < 0) {
+ CH_ERR(adap, "failed to bind qsets, err %d\n", ret);
t3_intr_disable(adap);
free_irq_resources(adap);
+ err = ret;
goto out;
}
adap->flags |= QUEUES_BOUND;
@@ -1286,7 +1288,7 @@ irq_err:
/*
* Release resources when all the ports and offloading have been stopped.
*/
-static void cxgb_down(struct adapter *adapter)
+static void cxgb_down(struct adapter *adapter, int on_wq)
{
t3_sge_stop(adapter);
spin_lock_irq(&adapter->work_lock); /* sync with PHY intr task */
@@ -1296,7 +1298,8 @@ static void cxgb_down(struct adapter *adapter)
free_irq_resources(adapter);
quiesce_rx(adapter);
t3_sge_stop(adapter);
- flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */
+ if (!on_wq)
+ flush_workqueue(cxgb3_wq);/* wait for external IRQ handler */
}
static void schedule_chk_task(struct adapter *adap)
@@ -1374,7 +1377,7 @@ static int offload_close(struct t3cdev *tdev)
clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
if (!adapter->open_device_map)
- cxgb_down(adapter);
+ cxgb_down(adapter, 0);
cxgb3_offload_deactivate(adapter);
return 0;
@@ -1398,7 +1401,10 @@ static int cxgb_open(struct net_device *dev)
"Could not initialize offload capabilities\n");
}
- dev->real_num_tx_queues = pi->nqsets;
+ netif_set_real_num_tx_queues(dev, pi->nqsets);
+ err = netif_set_real_num_rx_queues(dev, pi->nqsets);
+ if (err)
+ return err;
link_start(dev);
t3_port_intr_enable(adapter, pi->port_id);
netif_tx_start_all_queues(dev);
@@ -1409,7 +1415,7 @@ static int cxgb_open(struct net_device *dev)
return 0;
}
-static int cxgb_close(struct net_device *dev)
+static int __cxgb_close(struct net_device *dev, int on_wq)
{
struct port_info *pi = netdev_priv(dev);
struct adapter *adapter = pi->adapter;
@@ -1436,12 +1442,17 @@ static int cxgb_close(struct net_device *dev)
cancel_delayed_work_sync(&adapter->adap_check_task);
if (!adapter->open_device_map)
- cxgb_down(adapter);
+ cxgb_down(adapter, on_wq);
cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_DOWN, pi->port_id);
return 0;
}
+static int cxgb_close(struct net_device *dev)
+{
+ return __cxgb_close(dev, 0);
+}
+
static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
{
struct port_info *pi = netdev_priv(dev);
@@ -2864,7 +2875,7 @@ void t3_os_link_fault_handler(struct adapter *adapter, int port_id)
spin_unlock(&adapter->work_lock);
}
-static int t3_adapter_error(struct adapter *adapter, int reset)
+static int t3_adapter_error(struct adapter *adapter, int reset, int on_wq)
{
int i, ret = 0;
@@ -2879,7 +2890,7 @@ static int t3_adapter_error(struct adapter *adapter, int reset)
struct net_device *netdev = adapter->port[i];
if (netif_running(netdev))
- cxgb_close(netdev);
+ __cxgb_close(netdev, on_wq);
}
/* Stop SGE timers */
@@ -2950,7 +2961,7 @@ static void fatal_error_task(struct work_struct *work)
int err = 0;
rtnl_lock();
- err = t3_adapter_error(adapter, 1);
+ err = t3_adapter_error(adapter, 1, 1);
if (!err)
err = t3_reenable_adapter(adapter);
if (!err)
@@ -3000,7 +3011,7 @@ static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev,
if (state == pci_channel_io_perm_failure)
return PCI_ERS_RESULT_DISCONNECT;
- ret = t3_adapter_error(adapter, 0);
+ ret = t3_adapter_error(adapter, 0, 0);
/* Request a slot reset. */
return PCI_ERS_RESULT_NEED_RESET;
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index c6485b39eb0e..bcf07532953d 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -60,11 +60,14 @@ static LIST_HEAD(adapter_list);
static const unsigned int MAX_ATIDS = 64 * 1024;
static const unsigned int ATID_BASE = 0x10000;
+static void cxgb_neigh_update(struct neighbour *neigh);
+static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new);
+
static inline int offload_activated(struct t3cdev *tdev)
{
const struct adapter *adapter = tdev2adap(tdev);
- return (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map));
+ return test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
}
/**
@@ -1015,7 +1018,7 @@ EXPORT_SYMBOL(t3_register_cpl_handler);
/*
* T3CDEV's receive method.
*/
-int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n)
+static int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n)
{
while (n--) {
struct sk_buff *skb = *skbs++;
@@ -1070,7 +1073,7 @@ static int is_offloading(struct net_device *dev)
return 0;
}
-void cxgb_neigh_update(struct neighbour *neigh)
+static void cxgb_neigh_update(struct neighbour *neigh)
{
struct net_device *dev = neigh->dev;
@@ -1104,7 +1107,7 @@ static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e)
tdev->send(tdev, skb);
}
-void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
+static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
{
struct net_device *olddev, *newdev;
struct tid_info *ti;
diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c
index 3b5517b8fbde..a8766fb2f9ab 100644
--- a/drivers/net/cxgb3/mc5.c
+++ b/drivers/net/cxgb3/mc5.c
@@ -374,44 +374,6 @@ int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
return err;
}
-/*
- * read_mc5_range - dump a part of the memory managed by MC5
- * @mc5: the MC5 handle
- * @start: the start address for the dump
- * @n: number of 72-bit words to read
- * @buf: result buffer
- *
- * Read n 72-bit words from MC5 memory from the given start location.
- */
-int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start,
- unsigned int n, u32 *buf)
-{
- u32 read_cmd;
- int err = 0;
- struct adapter *adap = mc5->adapter;
-
- if (mc5->part_type == IDT75P52100)
- read_cmd = IDT_CMD_READ;
- else if (mc5->part_type == IDT75N43102)
- read_cmd = IDT4_CMD_READ;
- else
- return -EINVAL;
-
- mc5_dbgi_mode_enable(mc5);
-
- while (n--) {
- t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR0, start++);
- if (mc5_cmd_write(adap, read_cmd)) {
- err = -EIO;
- break;
- }
- dbgi_rd_rsp3(adap, buf + 2, buf + 1, buf);
- buf += 3;
- }
-
- mc5_dbgi_mode_disable(mc5);
- return 0;
-}
#define MC5_INT_FATAL (F_PARITYERR | F_REQQPARERR | F_DISPQPARERR)
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
index cb42353c9fdd..6990f6c65221 100644
--- a/drivers/net/cxgb3/regs.h
+++ b/drivers/net/cxgb3/regs.h
@@ -1997,6 +1997,10 @@
#define A_PL_RST 0x6f0
+#define S_FATALPERREN 4
+#define V_FATALPERREN(x) ((x) << S_FATALPERREN)
+#define F_FATALPERREN V_FATALPERREN(1U)
+
#define S_CRSTWRM 1
#define V_CRSTWRM(x) ((x) << S_CRSTWRM)
#define F_CRSTWRM V_CRSTWRM(1U)
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index 8ff96c6f6de5..5d72bda54389 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -1145,7 +1145,7 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
cpl->len = htonl(skb->len);
cntrl = V_TXPKT_INTF(pi->port_id);
- if (vlan_tx_tag_present(skb) && pi->vlan_grp)
+ if (vlan_tx_tag_present(skb))
cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(vlan_tx_tag_get(skb));
tso_info = V_LSO_MSS(skb_shinfo(skb)->gso_size);
@@ -1279,7 +1279,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
qs->port_stats[SGE_PSTAT_TX_CSUM]++;
if (skb_shinfo(skb)->gso_size)
qs->port_stats[SGE_PSTAT_TSO]++;
- if (vlan_tx_tag_present(skb) && pi->vlan_grp)
+ if (vlan_tx_tag_present(skb))
qs->port_stats[SGE_PSTAT_VLANINS]++;
/*
@@ -2022,7 +2022,7 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++;
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
skb_record_rx_queue(skb, qs - &adap->sge.qs[0]);
if (unlikely(p->vlan_valid)) {
@@ -2554,7 +2554,7 @@ static inline int handle_responses(struct adapter *adap, struct sge_rspq *q)
* The MSI-X interrupt handler for an SGE response queue for the non-NAPI case
* (i.e., response queue serviced in hard interrupt).
*/
-irqreturn_t t3_sge_intr_msix(int irq, void *cookie)
+static irqreturn_t t3_sge_intr_msix(int irq, void *cookie)
{
struct sge_qset *qs = cookie;
struct adapter *adap = qs->adap;
@@ -3320,40 +3320,3 @@ void t3_sge_prep(struct adapter *adap, struct sge_params *p)
spin_lock_init(&adap->sge.reg_lock);
}
-
-/**
- * t3_get_desc - dump an SGE descriptor for debugging purposes
- * @qs: the queue set
- * @qnum: identifies the specific queue (0..2: Tx, 3:response, 4..5: Rx)
- * @idx: the descriptor index in the queue
- * @data: where to dump the descriptor contents
- *
- * Dumps the contents of a HW descriptor of an SGE queue. Returns the
- * size of the descriptor.
- */
-int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
- unsigned char *data)
-{
- if (qnum >= 6)
- return -EINVAL;
-
- if (qnum < 3) {
- if (!qs->txq[qnum].desc || idx >= qs->txq[qnum].size)
- return -EINVAL;
- memcpy(data, &qs->txq[qnum].desc[idx], sizeof(struct tx_desc));
- return sizeof(struct tx_desc);
- }
-
- if (qnum == 3) {
- if (!qs->rspq.desc || idx >= qs->rspq.size)
- return -EINVAL;
- memcpy(data, &qs->rspq.desc[idx], sizeof(struct rsp_desc));
- return sizeof(struct rsp_desc);
- }
-
- qnum -= 4;
- if (!qs->fl[qnum].desc || idx >= qs->fl[qnum].size)
- return -EINVAL;
- memcpy(data, &qs->fl[qnum].desc[idx], sizeof(struct rx_desc));
- return sizeof(struct rx_desc);
-}
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 427c451be1a7..3a6adf0b3e9d 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -34,6 +34,8 @@
#include "sge_defs.h"
#include "firmware_exports.h"
+static void t3_port_intr_clear(struct adapter *adapter, int idx);
+
/**
* t3_wait_op_done_val - wait until an operation is completed
* @adapter: the adapter performing the operation
@@ -840,8 +842,8 @@ static int flash_wait_op(struct adapter *adapter, int attempts, int delay)
* (i.e., big-endian), otherwise as 32-bit words in the platform's
* natural endianess.
*/
-int t3_read_flash(struct adapter *adapter, unsigned int addr,
- unsigned int nwords, u32 *data, int byte_oriented)
+static int t3_read_flash(struct adapter *adapter, unsigned int addr,
+ unsigned int nwords, u32 *data, int byte_oriented)
{
int ret;
@@ -1408,6 +1410,7 @@ static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
fatal++;
CH_ALERT(adapter, "%s (0x%x)\n",
acts->msg, status & acts->mask);
+ status &= ~acts->mask;
} else if (acts->msg)
CH_WARN(adapter, "%s (0x%x)\n",
acts->msg, status & acts->mask);
@@ -1843,11 +1846,10 @@ static int mac_intr_handler(struct adapter *adap, unsigned int idx)
t3_os_link_fault_handler(adap, idx);
}
- t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
-
if (cause & XGM_INTR_FATAL)
t3_fatal_err(adap);
+ t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
return cause != 0;
}
@@ -2111,7 +2113,7 @@ void t3_port_intr_disable(struct adapter *adapter, int idx)
* Clear port-specific (i.e., MAC and PHY) interrupts for the given
* adapter port.
*/
-void t3_port_intr_clear(struct adapter *adapter, int idx)
+static void t3_port_intr_clear(struct adapter *adapter, int idx)
{
struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
@@ -2484,98 +2486,6 @@ int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
}
/**
- * t3_sge_read_context - read an SGE context
- * @type: the context type
- * @adapter: the adapter
- * @id: the context id
- * @data: holds the retrieved context
- *
- * Read an SGE egress context. The caller is responsible for ensuring
- * only one context operation occurs at a time.
- */
-static int t3_sge_read_context(unsigned int type, struct adapter *adapter,
- unsigned int id, u32 data[4])
-{
- if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
- return -EBUSY;
-
- t3_write_reg(adapter, A_SG_CONTEXT_CMD,
- V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id));
- if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0,
- SG_CONTEXT_CMD_ATTEMPTS, 1))
- return -EIO;
- data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0);
- data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1);
- data[2] = t3_read_reg(adapter, A_SG_CONTEXT_DATA2);
- data[3] = t3_read_reg(adapter, A_SG_CONTEXT_DATA3);
- return 0;
-}
-
-/**
- * t3_sge_read_ecntxt - read an SGE egress context
- * @adapter: the adapter
- * @id: the context id
- * @data: holds the retrieved context
- *
- * Read an SGE egress context. The caller is responsible for ensuring
- * only one context operation occurs at a time.
- */
-int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4])
-{
- if (id >= 65536)
- return -EINVAL;
- return t3_sge_read_context(F_EGRESS, adapter, id, data);
-}
-
-/**
- * t3_sge_read_cq - read an SGE CQ context
- * @adapter: the adapter
- * @id: the context id
- * @data: holds the retrieved context
- *
- * Read an SGE CQ context. The caller is responsible for ensuring
- * only one context operation occurs at a time.
- */
-int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4])
-{
- if (id >= 65536)
- return -EINVAL;
- return t3_sge_read_context(F_CQ, adapter, id, data);
-}
-
-/**
- * t3_sge_read_fl - read an SGE free-list context
- * @adapter: the adapter
- * @id: the context id
- * @data: holds the retrieved context
- *
- * Read an SGE free-list context. The caller is responsible for ensuring
- * only one context operation occurs at a time.
- */
-int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4])
-{
- if (id >= SGE_QSETS * 2)
- return -EINVAL;
- return t3_sge_read_context(F_FREELIST, adapter, id, data);
-}
-
-/**
- * t3_sge_read_rspq - read an SGE response queue context
- * @adapter: the adapter
- * @id: the context id
- * @data: holds the retrieved context
- *
- * Read an SGE response queue context. The caller is responsible for
- * ensuring only one context operation occurs at a time.
- */
-int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4])
-{
- if (id >= SGE_QSETS)
- return -EINVAL;
- return t3_sge_read_context(F_RESPONSEQ, adapter, id, data);
-}
-
-/**
* t3_config_rss - configure Rx packet steering
* @adapter: the adapter
* @rss_config: RSS settings (written to TP_RSS_CONFIG)
@@ -2616,42 +2526,6 @@ void t3_config_rss(struct adapter *adapter, unsigned int rss_config,
}
/**
- * t3_read_rss - read the contents of the RSS tables
- * @adapter: the adapter
- * @lkup: holds the contents of the RSS lookup table
- * @map: holds the contents of the RSS map table
- *
- * Reads the contents of the receive packet steering tables.
- */
-int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map)
-{
- int i;
- u32 val;
-
- if (lkup)
- for (i = 0; i < RSS_TABLE_SIZE; ++i) {
- t3_write_reg(adapter, A_TP_RSS_LKP_TABLE,
- 0xffff0000 | i);
- val = t3_read_reg(adapter, A_TP_RSS_LKP_TABLE);
- if (!(val & 0x80000000))
- return -EAGAIN;
- *lkup++ = val;
- *lkup++ = (val >> 8);
- }
-
- if (map)
- for (i = 0; i < RSS_TABLE_SIZE; ++i) {
- t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
- 0xffff0000 | i);
- val = t3_read_reg(adapter, A_TP_RSS_MAP_TABLE);
- if (!(val & 0x80000000))
- return -EAGAIN;
- *map++ = val;
- }
- return 0;
-}
-
-/**
* t3_tp_set_offload_mode - put TP in NIC/offload mode
* @adap: the adapter
* @enable: 1 to select offload mode, 0 for regular NIC
@@ -2868,7 +2742,8 @@ static void tp_set_timers(struct adapter *adap, unsigned int core_clk)
*
* Set the receive coalescing size and PSH bit handling.
*/
-int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh)
+static int t3_tp_set_coalescing_size(struct adapter *adap,
+ unsigned int size, int psh)
{
u32 val;
@@ -2898,7 +2773,7 @@ int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh)
* Set TP's max receive size. This is the limit that applies when
* receive coalescing is disabled.
*/
-void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size)
+static void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size)
{
t3_write_reg(adap, A_TP_PARA_REG7,
V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size));
@@ -3018,48 +2893,6 @@ void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS],
}
/**
- * t3_read_hw_mtus - returns the values in the HW MTU table
- * @adap: the adapter
- * @mtus: where to store the HW MTU values
- *
- * Reads the HW MTU table.
- */
-void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS])
-{
- int i;
-
- for (i = 0; i < NMTUS; ++i) {
- unsigned int val;
-
- t3_write_reg(adap, A_TP_MTU_TABLE, 0xff000000 | i);
- val = t3_read_reg(adap, A_TP_MTU_TABLE);
- mtus[i] = val & 0x3fff;
- }
-}
-
-/**
- * t3_get_cong_cntl_tab - reads the congestion control table
- * @adap: the adapter
- * @incr: where to store the alpha values
- *
- * Reads the additive increments programmed into the HW congestion
- * control table.
- */
-void t3_get_cong_cntl_tab(struct adapter *adap,
- unsigned short incr[NMTUS][NCCTRL_WIN])
-{
- unsigned int mtu, w;
-
- for (mtu = 0; mtu < NMTUS; ++mtu)
- for (w = 0; w < NCCTRL_WIN; ++w) {
- t3_write_reg(adap, A_TP_CCTRL_TABLE,
- 0xffff0000 | (mtu << 5) | w);
- incr[mtu][w] = t3_read_reg(adap, A_TP_CCTRL_TABLE) &
- 0x1fff;
- }
-}
-
-/**
* t3_tp_get_mib_stats - read TP's MIB counters
* @adap: the adapter
* @tps: holds the returned counter values
@@ -3223,15 +3056,6 @@ static int tp_init(struct adapter *adap, const struct tp_params *p)
return busy;
}
-int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask)
-{
- if (port_mask & ~((1 << adap->params.nports) - 1))
- return -EINVAL;
- t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE,
- port_mask << S_PORT0ACTIVE);
- return 0;
-}
-
/*
* Perform the bits of HW initialization that are dependent on the Tx
* channels being used.
@@ -3569,6 +3393,7 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params)
t3_write_reg(adapter, A_PM1_TX_MODE, 0);
chan_init_hw(adapter, adapter->params.chan_map);
t3_sge_init(adapter, &adapter->params.sge);
+ t3_set_reg_field(adapter, A_PL_RST, 0, F_FATALPERREN);
t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter));
@@ -3682,11 +3507,11 @@ static void mc7_prep(struct adapter *adapter, struct mc7 *mc7,
mc7->name = name;
mc7->offset = base_addr - MC7_PMRX_BASE_ADDR;
cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
- mc7->size = mc7->size = G_DEN(cfg) == M_DEN ? 0 : mc7_calc_size(cfg);
+ mc7->size = G_DEN(cfg) == M_DEN ? 0 : mc7_calc_size(cfg);
mc7->width = G_WIDTH(cfg);
}
-void mac_prep(struct cmac *mac, struct adapter *adapter, int index)
+static void mac_prep(struct cmac *mac, struct adapter *adapter, int index)
{
u16 devid;
@@ -3706,7 +3531,8 @@ void mac_prep(struct cmac *mac, struct adapter *adapter, int index)
}
}
-void early_hw_init(struct adapter *adapter, const struct adapter_info *ai)
+static void early_hw_init(struct adapter *adapter,
+ const struct adapter_info *ai)
{
u32 val = V_PORTSPEED(is_10G(adapter) ? 3 : 2);
diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h
index 6e562c0dad7d..3d4253d311eb 100644
--- a/drivers/net/cxgb4/cxgb4.h
+++ b/drivers/net/cxgb4/cxgb4.h
@@ -281,7 +281,6 @@ struct sge_rspq;
struct port_info {
struct adapter *adapter;
- struct vlan_group *vlan_grp;
u16 viid;
s16 xact_addr_filt; /* index of exact MAC address filter */
u16 rss_size; /* size of VI's RSS table slice */
@@ -463,6 +462,8 @@ struct sge {
u8 counter_val[SGE_NCOUNTERS];
unsigned int starve_thres;
u8 idma_state[2];
+ unsigned int egr_start;
+ unsigned int ingr_start;
void *egr_map[MAX_EGRQ]; /* qid->queue egress queue map */
struct sge_rspq *ingr_map[MAX_INGQ]; /* qid->queue ingress queue map */
DECLARE_BITMAP(starving_fl, MAX_EGRQ);
@@ -590,7 +591,6 @@ void t4_os_portmod_changed(const struct adapter *adap, int port_id);
void t4_os_link_changed(struct adapter *adap, int port_id, int link_stat);
void *t4_alloc_mem(size_t size);
-void t4_free_mem(void *addr);
void t4_free_sge_resources(struct adapter *adap);
irq_handler_t t4_intr_handler(struct adapter *adap);
@@ -649,7 +649,6 @@ static inline int t4_wr_mbox_ns(struct adapter *adap, int mbox, const void *cmd,
void t4_intr_enable(struct adapter *adapter);
void t4_intr_disable(struct adapter *adapter);
-void t4_intr_clear(struct adapter *adapter);
int t4_slow_intr_handler(struct adapter *adapter);
int t4_wait_dev_ready(struct adapter *adap);
@@ -662,24 +661,16 @@ int t4_check_fw_version(struct adapter *adapter);
int t4_prep_adapter(struct adapter *adapter);
int t4_port_init(struct adapter *adap, int mbox, int pf, int vf);
void t4_fatal_err(struct adapter *adapter);
-int t4_set_trace_filter(struct adapter *adapter, const struct trace_params *tp,
- int filter_index, int enable);
-void t4_get_trace_filter(struct adapter *adapter, struct trace_params *tp,
- int filter_index, int *enabled);
int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid,
int start, int n, const u16 *rspq, unsigned int nrspq);
int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode,
unsigned int flags);
-int t4_read_rss(struct adapter *adapter, u16 *entries);
int t4_mc_read(struct adapter *adap, u32 addr, __be32 *data, u64 *parity);
int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data,
u64 *parity);
void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p);
-void t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p);
-
void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log);
-void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st);
void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
struct tp_tcp_stats *v6);
void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
@@ -709,8 +700,6 @@ int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf,
int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port,
unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac,
unsigned int *rss_size);
-int t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf,
- unsigned int vf, unsigned int viid);
int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
int mtu, int promisc, int all_multi, int bcast, int vlanex,
bool sleep_ok);
@@ -729,9 +718,6 @@ int t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
unsigned int mmd, unsigned int reg, u16 *valp);
int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
unsigned int mmd, unsigned int reg, u16 val);
-int t4_iq_start_stop(struct adapter *adap, unsigned int mbox, bool start,
- unsigned int pf, unsigned int vf, unsigned int iqid,
- unsigned int fl0id, unsigned int fl1id);
int t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int iqtype, unsigned int iqid,
unsigned int fl0id, unsigned int fl1id);
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index e2bf10d90add..f17703f410b3 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -175,16 +175,26 @@ enum {
static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = {
CH_DEVICE(0xa000, 0), /* PE10K */
- CH_DEVICE(0x4001, 0),
- CH_DEVICE(0x4002, 0),
- CH_DEVICE(0x4003, 0),
- CH_DEVICE(0x4004, 0),
- CH_DEVICE(0x4005, 0),
- CH_DEVICE(0x4006, 0),
- CH_DEVICE(0x4007, 0),
- CH_DEVICE(0x4008, 0),
- CH_DEVICE(0x4009, 0),
- CH_DEVICE(0x400a, 0),
+ CH_DEVICE(0x4001, -1),
+ CH_DEVICE(0x4002, -1),
+ CH_DEVICE(0x4003, -1),
+ CH_DEVICE(0x4004, -1),
+ CH_DEVICE(0x4005, -1),
+ CH_DEVICE(0x4006, -1),
+ CH_DEVICE(0x4007, -1),
+ CH_DEVICE(0x4008, -1),
+ CH_DEVICE(0x4009, -1),
+ CH_DEVICE(0x400a, -1),
+ CH_DEVICE(0x4401, 4),
+ CH_DEVICE(0x4402, 4),
+ CH_DEVICE(0x4403, 4),
+ CH_DEVICE(0x4404, 4),
+ CH_DEVICE(0x4405, 4),
+ CH_DEVICE(0x4406, 4),
+ CH_DEVICE(0x4407, 4),
+ CH_DEVICE(0x4408, 4),
+ CH_DEVICE(0x4409, 4),
+ CH_DEVICE(0x440a, 4),
{ 0, }
};
@@ -393,7 +403,7 @@ static int link_start(struct net_device *dev)
* that step explicitly.
*/
ret = t4_set_rxmode(pi->adapter, mb, pi->viid, dev->mtu, -1, -1, -1,
- pi->vlan_grp != NULL, true);
+ !!(dev->features & NETIF_F_HW_VLAN_RX), true);
if (ret == 0) {
ret = t4_change_mac(pi->adapter, mb, pi->viid,
pi->xact_addr_filt, dev->dev_addr, true,
@@ -423,10 +433,11 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,
if (likely(opcode == CPL_SGE_EGR_UPDATE)) {
const struct cpl_sge_egr_update *p = (void *)rsp;
unsigned int qid = EGR_QID(ntohl(p->opcode_qid));
- struct sge_txq *txq = q->adap->sge.egr_map[qid];
+ struct sge_txq *txq;
+ txq = q->adap->sge.egr_map[qid - q->adap->sge.egr_start];
txq->restarts++;
- if ((u8 *)txq < (u8 *)q->adap->sge.ethrxq) {
+ if ((u8 *)txq < (u8 *)q->adap->sge.ofldtxq) {
struct sge_eth_txq *eq;
eq = container_of(txq, struct sge_eth_txq, q);
@@ -658,6 +669,15 @@ static int setup_rss(struct adapter *adap)
}
/*
+ * Return the channel of the ingress queue with the given qid.
+ */
+static unsigned int rxq_to_chan(const struct sge *p, unsigned int qid)
+{
+ qid -= p->ingr_start;
+ return netdev2pinfo(p->ingr_map[qid]->netdev)->tx_chan;
+}
+
+/*
* Wait until all NAPI handlers are descheduled.
*/
static void quiesce_rx(struct adapter *adap)
@@ -860,7 +880,7 @@ void *t4_alloc_mem(size_t size)
/*
* Free memory allocated through alloc_mem().
*/
-void t4_free_mem(void *addr)
+static void t4_free_mem(void *addr)
{
if (is_vmalloc_addr(addr))
vfree(addr);
@@ -1671,27 +1691,41 @@ static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
return 0;
}
-/*
- * Translate a physical EEPROM address to virtual. The first 1K is accessed
- * through virtual addresses starting at 31K, the rest is accessed through
- * virtual addresses starting at 0. This mapping is correct only for PF0.
+/**
+ * eeprom_ptov - translate a physical EEPROM address to virtual
+ * @phys_addr: the physical EEPROM address
+ * @fn: the PCI function number
+ * @sz: size of function-specific area
+ *
+ * Translate a physical EEPROM address to virtual. The first 1K is
+ * accessed through virtual addresses starting at 31K, the rest is
+ * accessed through virtual addresses starting at 0.
+ *
+ * The mapping is as follows:
+ * [0..1K) -> [31K..32K)
+ * [1K..1K+A) -> [31K-A..31K)
+ * [1K+A..ES) -> [0..ES-A-1K)
+ *
+ * where A = @fn * @sz, and ES = EEPROM size.
*/
-static int eeprom_ptov(unsigned int phys_addr)
+static int eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz)
{
+ fn *= sz;
if (phys_addr < 1024)
return phys_addr + (31 << 10);
+ if (phys_addr < 1024 + fn)
+ return 31744 - fn + phys_addr - 1024;
if (phys_addr < EEPROMSIZE)
- return phys_addr - 1024;
+ return phys_addr - 1024 - fn;
return -EINVAL;
}
/*
* The next two routines implement eeprom read/write from physical addresses.
- * The physical->virtual translation is correct only for PF0.
*/
static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v)
{
- int vaddr = eeprom_ptov(phys_addr);
+ int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE);
if (vaddr >= 0)
vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v);
@@ -1700,7 +1734,7 @@ static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v)
static int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v)
{
- int vaddr = eeprom_ptov(phys_addr);
+ int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE);
if (vaddr >= 0)
vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v);
@@ -1743,6 +1777,14 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
aligned_offset = eeprom->offset & ~3;
aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
+ if (adapter->fn > 0) {
+ u32 start = 1024 + adapter->fn * EEPROMPFSIZE;
+
+ if (aligned_offset < start ||
+ aligned_offset + aligned_len > start + EEPROMPFSIZE)
+ return -EPERM;
+ }
+
if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
/*
* RMW possibly needed for first or last words.
@@ -1839,7 +1881,24 @@ static int set_tso(struct net_device *dev, u32 value)
static int set_flags(struct net_device *dev, u32 flags)
{
- return ethtool_op_set_flags(dev, flags, ETH_FLAG_RXHASH);
+ int err;
+ unsigned long old_feat = dev->features;
+
+ err = ethtool_op_set_flags(dev, flags, ETH_FLAG_RXHASH |
+ ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN);
+ if (err)
+ return err;
+
+ if ((old_feat ^ dev->features) & NETIF_F_HW_VLAN_RX) {
+ const struct port_info *pi = netdev_priv(dev);
+
+ err = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1,
+ -1, -1, -1, !!(flags & ETH_FLAG_RXVLAN),
+ true);
+ if (err)
+ dev->features = old_feat;
+ }
+ return err;
}
static int get_rss_table(struct net_device *dev, struct ethtool_rxfh_indir *p)
@@ -2165,8 +2224,8 @@ static void mk_tid_release(struct sk_buff *skb, unsigned int chan,
* Queue a TID release request and if necessary schedule a work queue to
* process it.
*/
-void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan,
- unsigned int tid)
+static void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan,
+ unsigned int tid)
{
void **p = &t->tid_tab[tid];
struct adapter *adap = container_of(t, struct adapter, tids);
@@ -2181,7 +2240,6 @@ void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan,
}
spin_unlock_bh(&adap->tid_release_lock);
}
-EXPORT_SYMBOL(cxgb4_queue_tid_release);
/*
* Process the list of pending TID release requests.
@@ -2305,7 +2363,7 @@ int cxgb4_create_server(const struct net_device *dev, unsigned int stid,
req->peer_port = htons(0);
req->local_ip = sip;
req->peer_ip = htonl(0);
- chan = netdev2pinfo(adap->sge.ingr_map[queue]->netdev)->tx_chan;
+ chan = rxq_to_chan(&adap->sge, queue);
req->opt0 = cpu_to_be64(TX_CHAN(chan));
req->opt1 = cpu_to_be64(CONN_POLICY_ASK |
SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue));
@@ -2314,48 +2372,6 @@ int cxgb4_create_server(const struct net_device *dev, unsigned int stid,
EXPORT_SYMBOL(cxgb4_create_server);
/**
- * cxgb4_create_server6 - create an IPv6 server
- * @dev: the device
- * @stid: the server TID
- * @sip: local IPv6 address to bind server to
- * @sport: the server's TCP port
- * @queue: queue to direct messages from this server to
- *
- * Create an IPv6 server for the given port and address.
- * Returns <0 on error and one of the %NET_XMIT_* values on success.
- */
-int cxgb4_create_server6(const struct net_device *dev, unsigned int stid,
- const struct in6_addr *sip, __be16 sport,
- unsigned int queue)
-{
- unsigned int chan;
- struct sk_buff *skb;
- struct adapter *adap;
- struct cpl_pass_open_req6 *req;
-
- skb = alloc_skb(sizeof(*req), GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
-
- adap = netdev2adap(dev);
- req = (struct cpl_pass_open_req6 *)__skb_put(skb, sizeof(*req));
- INIT_TP_WR(req, 0);
- OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ6, stid));
- req->local_port = sport;
- req->peer_port = htons(0);
- req->local_ip_hi = *(__be64 *)(sip->s6_addr);
- req->local_ip_lo = *(__be64 *)(sip->s6_addr + 8);
- req->peer_ip_hi = cpu_to_be64(0);
- req->peer_ip_lo = cpu_to_be64(0);
- chan = netdev2pinfo(adap->sge.ingr_map[queue]->netdev)->tx_chan;
- req->opt0 = cpu_to_be64(TX_CHAN(chan));
- req->opt1 = cpu_to_be64(CONN_POLICY_ASK |
- SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue));
- return t4_mgmt_tx(adap, skb);
-}
-EXPORT_SYMBOL(cxgb4_create_server6);
-
-/**
* cxgb4_best_mtu - find the entry in the MTU table closest to an MTU
* @mtus: the HW MTU table
* @mtu: the target MTU
@@ -2414,25 +2430,6 @@ unsigned int cxgb4_port_idx(const struct net_device *dev)
}
EXPORT_SYMBOL(cxgb4_port_idx);
-/**
- * cxgb4_netdev_by_hwid - return the net device of a HW port
- * @pdev: identifies the adapter
- * @id: the HW port id
- *
- * Return the net device associated with the interface with the given HW
- * id.
- */
-struct net_device *cxgb4_netdev_by_hwid(struct pci_dev *pdev, unsigned int id)
-{
- const struct adapter *adap = pci_get_drvdata(pdev);
-
- if (!adap || id >= NCHAN)
- return NULL;
- id = adap->chan_map[id];
- return id < MAX_NPORTS ? adap->port[id] : NULL;
-}
-EXPORT_SYMBOL(cxgb4_netdev_by_hwid);
-
void cxgb4_get_tcp_stats(struct pci_dev *pdev, struct tp_tcp_stats *v4,
struct tp_tcp_stats *v6)
{
@@ -2722,7 +2719,10 @@ static int cxgb_open(struct net_device *dev)
return err;
}
- dev->real_num_tx_queues = pi->nqsets;
+ netif_set_real_num_tx_queues(dev, pi->nqsets);
+ err = netif_set_real_num_rx_queues(dev, pi->nqsets);
+ if (err)
+ return err;
err = link_start(dev);
if (!err)
netif_tx_start_all_queues(dev);
@@ -2859,15 +2859,6 @@ static int cxgb_set_mac_addr(struct net_device *dev, void *p)
return 0;
}
-static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
-{
- struct port_info *pi = netdev_priv(dev);
-
- pi->vlan_grp = grp;
- t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1, -1, -1, -1,
- grp != NULL, true);
-}
-
#ifdef CONFIG_NET_POLL_CONTROLLER
static void cxgb_netpoll(struct net_device *dev)
{
@@ -2895,7 +2886,6 @@ static const struct net_device_ops cxgb4_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = cxgb_ioctl,
.ndo_change_mtu = cxgb_change_mtu,
- .ndo_vlan_rx_register = vlan_rx_register,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = cxgb_netpoll,
#endif
@@ -3062,12 +3052,16 @@ static int adap_init0(struct adapter *adap)
params[2] = FW_PARAM_PFVF(L2T_END);
params[3] = FW_PARAM_PFVF(FILTER_START);
params[4] = FW_PARAM_PFVF(FILTER_END);
- ret = t4_query_params(adap, adap->fn, adap->fn, 0, 5, params, val);
+ params[5] = FW_PARAM_PFVF(IQFLINT_START);
+ params[6] = FW_PARAM_PFVF(EQ_START);
+ ret = t4_query_params(adap, adap->fn, adap->fn, 0, 7, params, val);
if (ret < 0)
goto bye;
port_vec = val[0];
adap->tids.ftid_base = val[3];
adap->tids.nftids = val[4] - val[3] + 1;
+ adap->sge.ingr_start = val[5];
+ adap->sge.egr_start = val[6];
if (c.ofldcaps) {
/* query offload-related parameters */
@@ -3671,7 +3665,6 @@ static int __devinit init_one(struct pci_dev *pdev,
pi->rx_offload = RX_CSO;
pi->port_id = i;
netif_carrier_off(netdev);
- netif_tx_stop_all_queues(netdev);
netdev->irq = pdev->irq;
netdev->features |= NETIF_F_SG | TSO_FLAGS;
@@ -3743,6 +3736,7 @@ static int __devinit init_one(struct pci_dev *pdev,
__set_bit(i, &adapter->registered_device_map);
adapter->chan_map[adap2pinfo(adapter, i)->tx_chan] = i;
+ netif_tx_stop_all_queues(adapter->port[i]);
}
}
if (!adapter->registered_device_map) {
@@ -3815,7 +3809,7 @@ static void __devexit remove_one(struct pci_dev *pdev)
pci_disable_device(pdev);
pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
- } else if (PCI_FUNC(pdev->devfn) > 0)
+ } else
pci_release_regions(pdev);
}
diff --git a/drivers/net/cxgb4/cxgb4_uld.h b/drivers/net/cxgb4/cxgb4_uld.h
index 85d74e751ce0..1b48c0170145 100644
--- a/drivers/net/cxgb4/cxgb4_uld.h
+++ b/drivers/net/cxgb4/cxgb4_uld.h
@@ -139,16 +139,11 @@ int cxgb4_alloc_stid(struct tid_info *t, int family, void *data);
void cxgb4_free_atid(struct tid_info *t, unsigned int atid);
void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family);
void cxgb4_remove_tid(struct tid_info *t, unsigned int qid, unsigned int tid);
-void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan,
- unsigned int tid);
struct in6_addr;
int cxgb4_create_server(const struct net_device *dev, unsigned int stid,
__be32 sip, __be16 sport, unsigned int queue);
-int cxgb4_create_server6(const struct net_device *dev, unsigned int stid,
- const struct in6_addr *sip, __be16 sport,
- unsigned int queue);
static inline void set_wr_txq(struct sk_buff *skb, int prio, int queue)
{
@@ -233,7 +228,6 @@ int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb);
unsigned int cxgb4_port_chan(const struct net_device *dev);
unsigned int cxgb4_port_viid(const struct net_device *dev);
unsigned int cxgb4_port_idx(const struct net_device *dev);
-struct net_device *cxgb4_netdev_by_hwid(struct pci_dev *pdev, unsigned int id);
unsigned int cxgb4_best_mtu(const unsigned short *mtus, unsigned short mtu,
unsigned int *idx);
void cxgb4_get_tcp_stats(struct pci_dev *pdev, struct tp_tcp_stats *v4,
diff --git a/drivers/net/cxgb4/l2t.c b/drivers/net/cxgb4/l2t.c
index e8f0f55e9d08..a2d323c473f8 100644
--- a/drivers/net/cxgb4/l2t.c
+++ b/drivers/net/cxgb4/l2t.c
@@ -481,40 +481,6 @@ void t4_l2t_update(struct adapter *adap, struct neighbour *neigh)
handle_failed_resolution(adap, arpq);
}
-/*
- * Allocate an L2T entry for use by a switching rule. Such entries need to be
- * explicitly freed and while busy they are not on any hash chain, so normal
- * address resolution updates do not see them.
- */
-struct l2t_entry *t4_l2t_alloc_switching(struct l2t_data *d)
-{
- struct l2t_entry *e;
-
- write_lock_bh(&d->lock);
- e = alloc_l2e(d);
- if (e) {
- spin_lock(&e->lock); /* avoid race with t4_l2t_free */
- e->state = L2T_STATE_SWITCHING;
- atomic_set(&e->refcnt, 1);
- spin_unlock(&e->lock);
- }
- write_unlock_bh(&d->lock);
- return e;
-}
-
-/*
- * Sets/updates the contents of a switching L2T entry that has been allocated
- * with an earlier call to @t4_l2t_alloc_switching.
- */
-int t4_l2t_set_switching(struct adapter *adap, struct l2t_entry *e, u16 vlan,
- u8 port, u8 *eth_addr)
-{
- e->vlan = vlan;
- e->lport = port;
- memcpy(e->dmac, eth_addr, ETH_ALEN);
- return write_l2e(adap, e, 0);
-}
-
struct l2t_data *t4_init_l2t(void)
{
int i;
diff --git a/drivers/net/cxgb4/l2t.h b/drivers/net/cxgb4/l2t.h
index 643f27ed3cf4..7bd8f42378ff 100644
--- a/drivers/net/cxgb4/l2t.h
+++ b/drivers/net/cxgb4/l2t.h
@@ -100,9 +100,6 @@ struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh,
unsigned int priority);
void t4_l2t_update(struct adapter *adap, struct neighbour *neigh);
-struct l2t_entry *t4_l2t_alloc_switching(struct l2t_data *d);
-int t4_l2t_set_switching(struct adapter *adap, struct l2t_entry *e, u16 vlan,
- u8 port, u8 *eth_addr);
struct l2t_data *t4_init_l2t(void);
void do_l2t_write_rpl(struct adapter *p, const struct cpl_l2t_write_rpl *rpl);
diff --git a/drivers/net/cxgb4/sge.c b/drivers/net/cxgb4/sge.c
index bf38cfc57565..17022258ed68 100644
--- a/drivers/net/cxgb4/sge.c
+++ b/drivers/net/cxgb4/sge.c
@@ -557,7 +557,8 @@ out: cred = q->avail - cred;
if (unlikely(fl_starving(q))) {
smp_wmb();
- set_bit(q->cntxt_id, adap->sge.starving_fl);
+ set_bit(q->cntxt_id - adap->sge.egr_start,
+ adap->sge.starving_fl);
}
return cred;
@@ -974,7 +975,7 @@ out_free: dev_kfree_skb(skb);
}
cpl->ctrl0 = htonl(TXPKT_OPCODE(CPL_TX_PKT_XT) |
- TXPKT_INTF(pi->tx_chan) | TXPKT_PF(0));
+ TXPKT_INTF(pi->tx_chan) | TXPKT_PF(adap->fn));
cpl->pack = htons(0);
cpl->len = htons(skb->len);
cpl->ctrl1 = cpu_to_be64(cntrl);
@@ -1213,7 +1214,8 @@ static void txq_stop_maperr(struct sge_ofld_txq *q)
{
q->mapping_err++;
q->q.stops++;
- set_bit(q->q.cntxt_id, q->adap->sge.txq_maperr);
+ set_bit(q->q.cntxt_id - q->adap->sge.egr_start,
+ q->adap->sge.txq_maperr);
}
/**
@@ -1528,18 +1530,11 @@ static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl,
skb->rxhash = (__force u32)pkt->rsshdr.hash_val;
if (unlikely(pkt->vlan_ex)) {
- struct port_info *pi = netdev_priv(rxq->rspq.netdev);
- struct vlan_group *grp = pi->vlan_grp;
-
+ __vlan_hwaccel_put_tag(skb, ntohs(pkt->vlan));
rxq->stats.vlan_ex++;
- if (likely(grp)) {
- ret = vlan_gro_frags(&rxq->rspq.napi, grp,
- ntohs(pkt->vlan));
- goto stats;
- }
}
ret = napi_gro_frags(&rxq->rspq.napi);
-stats: if (ret == GRO_HELD)
+ if (ret == GRO_HELD)
rxq->stats.lro_pkts++;
else if (ret == GRO_MERGED || ret == GRO_MERGED_FREE)
rxq->stats.lro_merged++;
@@ -1603,19 +1598,13 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
rxq->stats.rx_cso++;
}
} else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
if (unlikely(pkt->vlan_ex)) {
- struct vlan_group *grp = pi->vlan_grp;
-
+ __vlan_hwaccel_put_tag(skb, ntohs(pkt->vlan));
rxq->stats.vlan_ex++;
- if (likely(grp))
- vlan_hwaccel_receive_skb(skb, grp, ntohs(pkt->vlan));
- else
- dev_kfree_skb_any(skb);
- } else
- netif_receive_skb(skb);
-
+ }
+ netif_receive_skb(skb);
return 0;
}
@@ -1835,6 +1824,7 @@ static unsigned int process_intrq(struct adapter *adap)
if (RSPD_TYPE(rc->type_gen) == RSP_TYPE_INTR) {
unsigned int qid = ntohl(rc->pldbuflen_qid);
+ qid -= adap->sge.ingr_start;
napi_schedule(&adap->sge.ingr_map[qid]->napi);
}
@@ -2050,14 +2040,14 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
/* set offset to -1 to distinguish ingress queues without FL */
iq->offset = fl ? 0 : -1;
- adap->sge.ingr_map[iq->cntxt_id] = iq;
+ adap->sge.ingr_map[iq->cntxt_id - adap->sge.ingr_start] = iq;
if (fl) {
fl->cntxt_id = ntohs(c.fl0id);
fl->avail = fl->pend_cred = 0;
fl->pidx = fl->cidx = 0;
fl->alloc_failed = fl->large_alloc_failed = fl->starving = 0;
- adap->sge.egr_map[fl->cntxt_id] = fl;
+ adap->sge.egr_map[fl->cntxt_id - adap->sge.egr_start] = fl;
refill_fl(adap, fl, fl_cap(fl), GFP_KERNEL);
}
return 0;
@@ -2087,7 +2077,7 @@ static void init_txq(struct adapter *adap, struct sge_txq *q, unsigned int id)
q->stops = q->restarts = 0;
q->stat = (void *)&q->desc[q->size];
q->cntxt_id = id;
- adap->sge.egr_map[id] = q;
+ adap->sge.egr_map[id - adap->sge.egr_start] = q;
}
int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
@@ -2259,7 +2249,7 @@ static void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq,
{
unsigned int fl_id = fl ? fl->cntxt_id : 0xffff;
- adap->sge.ingr_map[rq->cntxt_id] = NULL;
+ adap->sge.ingr_map[rq->cntxt_id - adap->sge.ingr_start] = NULL;
t4_iq_free(adap, adap->fn, adap->fn, 0, FW_IQ_TYPE_FL_INT_CAP,
rq->cntxt_id, fl_id, 0xffff);
dma_free_coherent(adap->pdev_dev, (rq->size + 1) * rq->iqe_len,
diff --git a/drivers/net/cxgb4/t4_hw.c b/drivers/net/cxgb4/t4_hw.c
index 9e1a4b49b47a..bb813d94aea8 100644
--- a/drivers/net/cxgb4/t4_hw.c
+++ b/drivers/net/cxgb4/t4_hw.c
@@ -120,30 +120,6 @@ static void t4_read_indirect(struct adapter *adap, unsigned int addr_reg,
}
}
-#if 0
-/**
- * t4_write_indirect - write indirectly addressed registers
- * @adap: the adapter
- * @addr_reg: register holding the indirect addresses
- * @data_reg: register holding the value for the indirect registers
- * @vals: values to write
- * @nregs: how many indirect registers to write
- * @start_idx: address of first indirect register to write
- *
- * Writes a sequential block of registers that are accessed indirectly
- * through an address/data register pair.
- */
-static void t4_write_indirect(struct adapter *adap, unsigned int addr_reg,
- unsigned int data_reg, const u32 *vals,
- unsigned int nregs, unsigned int start_idx)
-{
- while (nregs--) {
- t4_write_reg(adap, addr_reg, start_idx++);
- t4_write_reg(adap, data_reg, *vals++);
- }
-}
-#endif
-
/*
* Get the reply to a mailbox command and store it in @rpl in big-endian order.
*/
@@ -1560,44 +1536,6 @@ void t4_intr_disable(struct adapter *adapter)
}
/**
- * t4_intr_clear - clear all interrupts
- * @adapter: the adapter whose interrupts should be cleared
- *
- * Clears all interrupts. The caller must be a PCI function managing
- * global interrupts.
- */
-void t4_intr_clear(struct adapter *adapter)
-{
- static const unsigned int cause_reg[] = {
- SGE_INT_CAUSE1, SGE_INT_CAUSE2, SGE_INT_CAUSE3,
- PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
- PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
- PCIE_NONFAT_ERR, PCIE_INT_CAUSE,
- MC_INT_CAUSE,
- MA_INT_WRAP_STATUS, MA_PARITY_ERROR_STATUS, MA_INT_CAUSE,
- EDC_INT_CAUSE, EDC_REG(EDC_INT_CAUSE, 1),
- CIM_HOST_INT_CAUSE, CIM_HOST_UPACC_INT_CAUSE,
- MYPF_REG(CIM_PF_HOST_INT_CAUSE),
- TP_INT_CAUSE,
- ULP_RX_INT_CAUSE, ULP_TX_INT_CAUSE,
- PM_RX_INT_CAUSE, PM_TX_INT_CAUSE,
- MPS_RX_PERR_INT_CAUSE,
- CPL_INTR_CAUSE,
- MYPF_REG(PL_PF_INT_CAUSE),
- PL_PL_INT_CAUSE,
- LE_DB_INT_CAUSE,
- };
-
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(cause_reg); ++i)
- t4_write_reg(adapter, cause_reg[i], 0xffffffff);
-
- t4_write_reg(adapter, PL_INT_CAUSE, GLBL_INTR_MASK);
- (void) t4_read_reg(adapter, PL_INT_CAUSE); /* flush */
-}
-
-/**
* hash_mac_addr - return the hash value of a MAC address
* @addr: the 48-bit Ethernet MAC address
*
@@ -1709,36 +1647,6 @@ int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode,
return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL);
}
-/* Read an RSS table row */
-static int rd_rss_row(struct adapter *adap, int row, u32 *val)
-{
- t4_write_reg(adap, TP_RSS_LKP_TABLE, 0xfff00000 | row);
- return t4_wait_op_done_val(adap, TP_RSS_LKP_TABLE, LKPTBLROWVLD, 1,
- 5, 0, val);
-}
-
-/**
- * t4_read_rss - read the contents of the RSS mapping table
- * @adapter: the adapter
- * @map: holds the contents of the RSS mapping table
- *
- * Reads the contents of the RSS hash->queue mapping table.
- */
-int t4_read_rss(struct adapter *adapter, u16 *map)
-{
- u32 val;
- int i, ret;
-
- for (i = 0; i < RSS_NENTRIES / 2; ++i) {
- ret = rd_rss_row(adapter, i, &val);
- if (ret)
- return ret;
- *map++ = LKPTBLQUEUE0_GET(val);
- *map++ = LKPTBLQUEUE1_GET(val);
- }
- return 0;
-}
-
/**
* t4_tp_get_tcp_stats - read TP's TCP MIB counters
* @adap: the adapter
@@ -1779,29 +1687,6 @@ void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
}
/**
- * t4_tp_get_err_stats - read TP's error MIB counters
- * @adap: the adapter
- * @st: holds the counter values
- *
- * Returns the values of TP's error counters.
- */
-void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st)
-{
- t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, st->macInErrs,
- 12, TP_MIB_MAC_IN_ERR_0);
- t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, st->tnlCongDrops,
- 8, TP_MIB_TNL_CNG_DROP_0);
- t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, st->tnlTxDrops,
- 4, TP_MIB_TNL_DROP_0);
- t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, st->ofldVlanDrops,
- 4, TP_MIB_OFD_VLN_DROP_0);
- t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, st->tcp6InErrs,
- 4, TP_MIB_TCP_V6IN_ERR_0);
- t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, &st->ofldNoNeigh,
- 2, TP_MIB_OFD_ARP_DROP);
-}
-
-/**
* t4_read_mtu_tbl - returns the values in the HW path MTU table
* @adap: the adapter
* @mtus: where to store the MTU values
@@ -1916,122 +1801,6 @@ void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
}
/**
- * t4_set_trace_filter - configure one of the tracing filters
- * @adap: the adapter
- * @tp: the desired trace filter parameters
- * @idx: which filter to configure
- * @enable: whether to enable or disable the filter
- *
- * Configures one of the tracing filters available in HW. If @enable is
- * %0 @tp is not examined and may be %NULL.
- */
-int t4_set_trace_filter(struct adapter *adap, const struct trace_params *tp,
- int idx, int enable)
-{
- int i, ofst = idx * 4;
- u32 data_reg, mask_reg, cfg;
- u32 multitrc = TRCMULTIFILTER;
-
- if (!enable) {
- t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A + ofst, 0);
- goto out;
- }
-
- if (tp->port > 11 || tp->invert > 1 || tp->skip_len > 0x1f ||
- tp->skip_ofst > 0x1f || tp->min_len > 0x1ff ||
- tp->snap_len > 9600 || (idx && tp->snap_len > 256))
- return -EINVAL;
-
- if (tp->snap_len > 256) { /* must be tracer 0 */
- if ((t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A + 4) |
- t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A + 8) |
- t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A + 12)) & TFEN)
- return -EINVAL; /* other tracers are enabled */
- multitrc = 0;
- } else if (idx) {
- i = t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_B);
- if (TFCAPTUREMAX_GET(i) > 256 &&
- (t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A) & TFEN))
- return -EINVAL;
- }
-
- /* stop the tracer we'll be changing */
- t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A + ofst, 0);
-
- /* disable tracing globally if running in the wrong single/multi mode */
- cfg = t4_read_reg(adap, MPS_TRC_CFG);
- if ((cfg & TRCEN) && multitrc != (cfg & TRCMULTIFILTER)) {
- t4_write_reg(adap, MPS_TRC_CFG, cfg ^ TRCEN);
- t4_read_reg(adap, MPS_TRC_CFG); /* flush */
- msleep(1);
- if (!(t4_read_reg(adap, MPS_TRC_CFG) & TRCFIFOEMPTY))
- return -ETIMEDOUT;
- }
- /*
- * At this point either the tracing is enabled and in the right mode or
- * disabled.
- */
-
- idx *= (MPS_TRC_FILTER1_MATCH - MPS_TRC_FILTER0_MATCH);
- data_reg = MPS_TRC_FILTER0_MATCH + idx;
- mask_reg = MPS_TRC_FILTER0_DONT_CARE + idx;
-
- for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) {
- t4_write_reg(adap, data_reg, tp->data[i]);
- t4_write_reg(adap, mask_reg, ~tp->mask[i]);
- }
- t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_B + ofst,
- TFCAPTUREMAX(tp->snap_len) |
- TFMINPKTSIZE(tp->min_len));
- t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A + ofst,
- TFOFFSET(tp->skip_ofst) | TFLENGTH(tp->skip_len) |
- TFPORT(tp->port) | TFEN |
- (tp->invert ? TFINVERTMATCH : 0));
-
- cfg &= ~TRCMULTIFILTER;
- t4_write_reg(adap, MPS_TRC_CFG, cfg | TRCEN | multitrc);
-out: t4_read_reg(adap, MPS_TRC_CFG); /* flush */
- return 0;
-}
-
-/**
- * t4_get_trace_filter - query one of the tracing filters
- * @adap: the adapter
- * @tp: the current trace filter parameters
- * @idx: which trace filter to query
- * @enabled: non-zero if the filter is enabled
- *
- * Returns the current settings of one of the HW tracing filters.
- */
-void t4_get_trace_filter(struct adapter *adap, struct trace_params *tp, int idx,
- int *enabled)
-{
- u32 ctla, ctlb;
- int i, ofst = idx * 4;
- u32 data_reg, mask_reg;
-
- ctla = t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A + ofst);
- ctlb = t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_B + ofst);
-
- *enabled = !!(ctla & TFEN);
- tp->snap_len = TFCAPTUREMAX_GET(ctlb);
- tp->min_len = TFMINPKTSIZE_GET(ctlb);
- tp->skip_ofst = TFOFFSET_GET(ctla);
- tp->skip_len = TFLENGTH_GET(ctla);
- tp->invert = !!(ctla & TFINVERTMATCH);
- tp->port = TFPORT_GET(ctla);
-
- ofst = (MPS_TRC_FILTER1_MATCH - MPS_TRC_FILTER0_MATCH) * idx;
- data_reg = MPS_TRC_FILTER0_MATCH + ofst;
- mask_reg = MPS_TRC_FILTER0_DONT_CARE + ofst;
-
- for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) {
- tp->mask[i] = ~t4_read_reg(adap, mask_reg);
- tp->data[i] = t4_read_reg(adap, data_reg) & tp->mask[i];
- }
-}
-
-/**
* get_mps_bg_map - return the buffer groups associated with a port
* @adap: the adapter
* @idx: the port index
@@ -2133,52 +1902,6 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
}
/**
- * t4_get_lb_stats - collect loopback port statistics
- * @adap: the adapter
- * @idx: the loopback port index
- * @p: the stats structure to fill
- *
- * Return HW statistics for the given loopback port.
- */
-void t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p)
-{
- u32 bgmap = get_mps_bg_map(adap, idx);
-
-#define GET_STAT(name) \
- t4_read_reg64(adap, PORT_REG(idx, MPS_PORT_STAT_LB_PORT_##name##_L))
-#define GET_STAT_COM(name) t4_read_reg64(adap, MPS_STAT_##name##_L)
-
- p->octets = GET_STAT(BYTES);
- p->frames = GET_STAT(FRAMES);
- p->bcast_frames = GET_STAT(BCAST);
- p->mcast_frames = GET_STAT(MCAST);
- p->ucast_frames = GET_STAT(UCAST);
- p->error_frames = GET_STAT(ERROR);
-
- p->frames_64 = GET_STAT(64B);
- p->frames_65_127 = GET_STAT(65B_127B);
- p->frames_128_255 = GET_STAT(128B_255B);
- p->frames_256_511 = GET_STAT(256B_511B);
- p->frames_512_1023 = GET_STAT(512B_1023B);
- p->frames_1024_1518 = GET_STAT(1024B_1518B);
- p->frames_1519_max = GET_STAT(1519B_MAX);
- p->drop = t4_read_reg(adap, PORT_REG(idx,
- MPS_PORT_STAT_LB_PORT_DROP_FRAMES));
-
- p->ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_DROP_FRAME) : 0;
- p->ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_DROP_FRAME) : 0;
- p->ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_DROP_FRAME) : 0;
- p->ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_DROP_FRAME) : 0;
- p->trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_TRUNC_FRAME) : 0;
- p->trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_TRUNC_FRAME) : 0;
- p->trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_TRUNC_FRAME) : 0;
- p->trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_TRUNC_FRAME) : 0;
-
-#undef GET_STAT
-#undef GET_STAT_COM
-}
-
-/**
* t4_wol_magic_enable - enable/disable magic packet WoL
* @adap: the adapter
* @port: the physical port index
@@ -2584,30 +2307,6 @@ int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port,
}
/**
- * t4_free_vi - free a virtual interface
- * @adap: the adapter
- * @mbox: mailbox to use for the FW command
- * @pf: the PF owning the VI
- * @vf: the VF owning the VI
- * @viid: virtual interface identifiler
- *
- * Free a previously allocated virtual interface.
- */
-int t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf,
- unsigned int vf, unsigned int viid)
-{
- struct fw_vi_cmd c;
-
- memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP(FW_VI_CMD) | FW_CMD_REQUEST |
- FW_CMD_EXEC | FW_VI_CMD_PFN(pf) |
- FW_VI_CMD_VFN(vf));
- c.alloc_to_len16 = htonl(FW_VI_CMD_FREE | FW_LEN16(c));
- c.type_viid = htons(FW_VI_CMD_VIID(viid));
- return t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
-}
-
-/**
* t4_set_rxmode - set Rx properties of a virtual interface
* @adap: the adapter
* @mbox: mailbox to use for the FW command
@@ -2833,37 +2532,6 @@ int t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid,
}
/**
- * t4_iq_start_stop - enable/disable an ingress queue and its FLs
- * @adap: the adapter
- * @mbox: mailbox to use for the FW command
- * @start: %true to enable the queues, %false to disable them
- * @pf: the PF owning the queues
- * @vf: the VF owning the queues
- * @iqid: ingress queue id
- * @fl0id: FL0 queue id or 0xffff if no attached FL0
- * @fl1id: FL1 queue id or 0xffff if no attached FL1
- *
- * Starts or stops an ingress queue and its associated FLs, if any.
- */
-int t4_iq_start_stop(struct adapter *adap, unsigned int mbox, bool start,
- unsigned int pf, unsigned int vf, unsigned int iqid,
- unsigned int fl0id, unsigned int fl1id)
-{
- struct fw_iq_cmd c;
-
- memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) | FW_CMD_REQUEST |
- FW_CMD_EXEC | FW_IQ_CMD_PFN(pf) |
- FW_IQ_CMD_VFN(vf));
- c.alloc_to_len16 = htonl(FW_IQ_CMD_IQSTART(start) |
- FW_IQ_CMD_IQSTOP(!start) | FW_LEN16(c));
- c.iqid = htons(iqid);
- c.fl0id = htons(fl0id);
- c.fl1id = htons(fl1id);
- return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
-}
-
-/**
* t4_iq_free - free an ingress queue and its FLs
* @adap: the adapter
* @mbox: mailbox to use for the FW command
diff --git a/drivers/net/cxgb4/t4_hw.h b/drivers/net/cxgb4/t4_hw.h
index 10a055565776..c26b455f37de 100644
--- a/drivers/net/cxgb4/t4_hw.h
+++ b/drivers/net/cxgb4/t4_hw.h
@@ -42,6 +42,7 @@ enum {
MAX_MTU = 9600, /* max MAC MTU, excluding header + FCS */
EEPROMSIZE = 17408, /* Serial EEPROM physical size */
EEPROMVSIZE = 32768, /* Serial EEPROM virtual address space size */
+ EEPROMPFSIZE = 1024, /* EEPROM writable area size for PFn, n>0 */
RSS_NENTRIES = 2048, /* # of entries in RSS mapping table */
TCB_SIZE = 128, /* TCB size */
NMTUS = 16, /* size of MTU table */
diff --git a/drivers/net/cxgb4/t4fw_api.h b/drivers/net/cxgb4/t4fw_api.h
index 0969f2fbc1b0..940584a8a640 100644
--- a/drivers/net/cxgb4/t4fw_api.h
+++ b/drivers/net/cxgb4/t4fw_api.h
@@ -487,6 +487,11 @@ enum fw_params_param_pfvf {
FW_PARAMS_PARAM_PFVF_CPMASK = 0x25,
FW_PARAMS_PARAM_PFVF_OCQ_START = 0x26,
FW_PARAMS_PARAM_PFVF_OCQ_END = 0x27,
+ FW_PARAMS_PARAM_PFVF_CONM_MAP = 0x28,
+ FW_PARAMS_PARAM_PFVF_IQFLINT_START = 0x29,
+ FW_PARAMS_PARAM_PFVF_IQFLINT_END = 0x2A,
+ FW_PARAMS_PARAM_PFVF_EQ_START = 0x2B,
+ FW_PARAMS_PARAM_PFVF_EQ_END = 0x2C,
};
/*
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
index 7b6d07f50c71..555ecc5a2e93 100644
--- a/drivers/net/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -748,7 +748,10 @@ static int cxgb4vf_open(struct net_device *dev)
/*
* Note that this interface is up and start everything up ...
*/
- dev->real_num_tx_queues = pi->nqsets;
+ netif_set_real_num_tx_queues(dev, pi->nqsets);
+ err = netif_set_real_num_rx_queues(dev, pi->nqsets);
+ if (err)
+ return err;
set_bit(pi->port_id, &adapter->open_device_map);
link_start(dev);
netif_tx_start_all_queues(dev);
diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c
index eb5a1c9cb2d3..f10864ddafbe 100644
--- a/drivers/net/cxgb4vf/sge.c
+++ b/drivers/net/cxgb4vf/sge.c
@@ -1520,7 +1520,6 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
__skb_pull(skb, PKTSHIFT);
skb->protocol = eth_type_trans(skb, rspq->netdev);
skb_record_rx_queue(skb, rspq->idx);
- skb->dev->last_rx = jiffies; /* XXX removed 2.6.29 */
pi = netdev_priv(skb->dev);
rxq->stats.pkts++;
@@ -1535,7 +1534,7 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
}
rxq->stats.rx_cso++;
} else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
if (unlikely(pkt->vlan_ex)) {
struct vlan_group *grp = pi->vlan_grp;
diff --git a/drivers/net/cxgb4vf/t4vf_common.h b/drivers/net/cxgb4vf/t4vf_common.h
index 5c7bde7f9bae..873cb7d86c57 100644
--- a/drivers/net/cxgb4vf/t4vf_common.h
+++ b/drivers/net/cxgb4vf/t4vf_common.h
@@ -132,15 +132,15 @@ struct rss_params {
unsigned int mode; /* RSS mode */
union {
struct {
- int synmapen:1; /* SYN Map Enable */
- int syn4tupenipv6:1; /* enable hashing 4-tuple IPv6 SYNs */
- int syn2tupenipv6:1; /* enable hashing 2-tuple IPv6 SYNs */
- int syn4tupenipv4:1; /* enable hashing 4-tuple IPv4 SYNs */
- int syn2tupenipv4:1; /* enable hashing 2-tuple IPv4 SYNs */
- int ofdmapen:1; /* Offload Map Enable */
- int tnlmapen:1; /* Tunnel Map Enable */
- int tnlalllookup:1; /* Tunnel All Lookup */
- int hashtoeplitz:1; /* use Toeplitz hash */
+ unsigned int synmapen:1; /* SYN Map Enable */
+ unsigned int syn4tupenipv6:1; /* enable hashing 4-tuple IPv6 SYNs */
+ unsigned int syn2tupenipv6:1; /* enable hashing 2-tuple IPv6 SYNs */
+ unsigned int syn4tupenipv4:1; /* enable hashing 4-tuple IPv4 SYNs */
+ unsigned int syn2tupenipv4:1; /* enable hashing 2-tuple IPv4 SYNs */
+ unsigned int ofdmapen:1; /* Offload Map Enable */
+ unsigned int tnlmapen:1; /* Tunnel Map Enable */
+ unsigned int tnlalllookup:1; /* Tunnel All Lookup */
+ unsigned int hashtoeplitz:1; /* use Toeplitz hash */
} basicvirtual;
} u;
};
@@ -151,10 +151,10 @@ struct rss_params {
union rss_vi_config {
struct {
u16 defaultq; /* Ingress Queue ID for !tnlalllookup */
- int ip6fourtupen:1; /* hash 4-tuple IPv6 ingress packets */
- int ip6twotupen:1; /* hash 2-tuple IPv6 ingress packets */
- int ip4fourtupen:1; /* hash 4-tuple IPv4 ingress packets */
- int ip4twotupen:1; /* hash 2-tuple IPv4 ingress packets */
+ unsigned int ip6fourtupen:1; /* hash 4-tuple IPv6 ingress packets */
+ unsigned int ip6twotupen:1; /* hash 2-tuple IPv6 ingress packets */
+ unsigned int ip4fourtupen:1; /* hash 4-tuple IPv4 ingress packets */
+ unsigned int ip4twotupen:1; /* hash 2-tuple IPv4 ingress packets */
int udpen; /* hash 4-tuple UDP ingress packets */
} basicvirtual;
};
diff --git a/drivers/net/davinci_cpdma.c b/drivers/net/davinci_cpdma.c
new file mode 100644
index 000000000000..e92b2b6cd8c4
--- /dev/null
+++ b/drivers/net/davinci_cpdma.c
@@ -0,0 +1,965 @@
+/*
+ * Texas Instruments CPDMA Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; 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/spinlock.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+
+#include "davinci_cpdma.h"
+
+/* DMA Registers */
+#define CPDMA_TXIDVER 0x00
+#define CPDMA_TXCONTROL 0x04
+#define CPDMA_TXTEARDOWN 0x08
+#define CPDMA_RXIDVER 0x10
+#define CPDMA_RXCONTROL 0x14
+#define CPDMA_SOFTRESET 0x1c
+#define CPDMA_RXTEARDOWN 0x18
+#define CPDMA_TXINTSTATRAW 0x80
+#define CPDMA_TXINTSTATMASKED 0x84
+#define CPDMA_TXINTMASKSET 0x88
+#define CPDMA_TXINTMASKCLEAR 0x8c
+#define CPDMA_MACINVECTOR 0x90
+#define CPDMA_MACEOIVECTOR 0x94
+#define CPDMA_RXINTSTATRAW 0xa0
+#define CPDMA_RXINTSTATMASKED 0xa4
+#define CPDMA_RXINTMASKSET 0xa8
+#define CPDMA_RXINTMASKCLEAR 0xac
+#define CPDMA_DMAINTSTATRAW 0xb0
+#define CPDMA_DMAINTSTATMASKED 0xb4
+#define CPDMA_DMAINTMASKSET 0xb8
+#define CPDMA_DMAINTMASKCLEAR 0xbc
+#define CPDMA_DMAINT_HOSTERR BIT(1)
+
+/* the following exist only if has_ext_regs is set */
+#define CPDMA_DMACONTROL 0x20
+#define CPDMA_DMASTATUS 0x24
+#define CPDMA_RXBUFFOFS 0x28
+#define CPDMA_EM_CONTROL 0x2c
+
+/* Descriptor mode bits */
+#define CPDMA_DESC_SOP BIT(31)
+#define CPDMA_DESC_EOP BIT(30)
+#define CPDMA_DESC_OWNER BIT(29)
+#define CPDMA_DESC_EOQ BIT(28)
+#define CPDMA_DESC_TD_COMPLETE BIT(27)
+#define CPDMA_DESC_PASS_CRC BIT(26)
+
+#define CPDMA_TEARDOWN_VALUE 0xfffffffc
+
+struct cpdma_desc {
+ /* hardware fields */
+ u32 hw_next;
+ u32 hw_buffer;
+ u32 hw_len;
+ u32 hw_mode;
+ /* software fields */
+ void *sw_token;
+ u32 sw_buffer;
+ u32 sw_len;
+};
+
+struct cpdma_desc_pool {
+ u32 phys;
+ void __iomem *iomap; /* ioremap map */
+ void *cpumap; /* dma_alloc map */
+ int desc_size, mem_size;
+ int num_desc, used_desc;
+ unsigned long *bitmap;
+ struct device *dev;
+ spinlock_t lock;
+};
+
+enum cpdma_state {
+ CPDMA_STATE_IDLE,
+ CPDMA_STATE_ACTIVE,
+ CPDMA_STATE_TEARDOWN,
+};
+
+const char *cpdma_state_str[] = { "idle", "active", "teardown" };
+
+struct cpdma_ctlr {
+ enum cpdma_state state;
+ struct cpdma_params params;
+ struct device *dev;
+ struct cpdma_desc_pool *pool;
+ spinlock_t lock;
+ struct cpdma_chan *channels[2 * CPDMA_MAX_CHANNELS];
+};
+
+struct cpdma_chan {
+ enum cpdma_state state;
+ struct cpdma_ctlr *ctlr;
+ int chan_num;
+ spinlock_t lock;
+ struct cpdma_desc __iomem *head, *tail;
+ int count;
+ void __iomem *hdp, *cp, *rxfree;
+ u32 mask;
+ cpdma_handler_fn handler;
+ enum dma_data_direction dir;
+ struct cpdma_chan_stats stats;
+ /* offsets into dmaregs */
+ int int_set, int_clear, td;
+};
+
+/* The following make access to common cpdma_ctlr params more readable */
+#define dmaregs params.dmaregs
+#define num_chan params.num_chan
+
+/* various accessors */
+#define dma_reg_read(ctlr, ofs) __raw_readl((ctlr)->dmaregs + (ofs))
+#define chan_read(chan, fld) __raw_readl((chan)->fld)
+#define desc_read(desc, fld) __raw_readl(&(desc)->fld)
+#define dma_reg_write(ctlr, ofs, v) __raw_writel(v, (ctlr)->dmaregs + (ofs))
+#define chan_write(chan, fld, v) __raw_writel(v, (chan)->fld)
+#define desc_write(desc, fld, v) __raw_writel((u32)(v), &(desc)->fld)
+
+/*
+ * Utility constructs for a cpdma descriptor pool. Some devices (e.g. davinci
+ * emac) have dedicated on-chip memory for these descriptors. Some other
+ * devices (e.g. cpsw switches) use plain old memory. Descriptor pools
+ * abstract out these details
+ */
+static struct cpdma_desc_pool *
+cpdma_desc_pool_create(struct device *dev, u32 phys, int size, int align)
+{
+ int bitmap_size;
+ struct cpdma_desc_pool *pool;
+
+ pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+ if (!pool)
+ return NULL;
+
+ spin_lock_init(&pool->lock);
+
+ pool->dev = dev;
+ pool->mem_size = size;
+ pool->desc_size = ALIGN(sizeof(struct cpdma_desc), align);
+ pool->num_desc = size / pool->desc_size;
+
+ bitmap_size = (pool->num_desc / BITS_PER_LONG) * sizeof(long);
+ pool->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+ if (!pool->bitmap)
+ goto fail;
+
+ if (phys) {
+ pool->phys = phys;
+ pool->iomap = ioremap(phys, size);
+ } else {
+ pool->cpumap = dma_alloc_coherent(dev, size, &pool->phys,
+ GFP_KERNEL);
+ pool->iomap = (void __force __iomem *)pool->cpumap;
+ }
+
+ if (pool->iomap)
+ return pool;
+
+fail:
+ kfree(pool->bitmap);
+ kfree(pool);
+ return NULL;
+}
+
+static void cpdma_desc_pool_destroy(struct cpdma_desc_pool *pool)
+{
+ unsigned long flags;
+
+ if (!pool)
+ return;
+
+ spin_lock_irqsave(&pool->lock, flags);
+ WARN_ON(pool->used_desc);
+ kfree(pool->bitmap);
+ if (pool->cpumap) {
+ dma_free_coherent(pool->dev, pool->mem_size, pool->cpumap,
+ pool->phys);
+ } else {
+ iounmap(pool->iomap);
+ }
+ spin_unlock_irqrestore(&pool->lock, flags);
+ kfree(pool);
+}
+
+static inline dma_addr_t desc_phys(struct cpdma_desc_pool *pool,
+ struct cpdma_desc __iomem *desc)
+{
+ if (!desc)
+ return 0;
+ return pool->phys + (__force dma_addr_t)desc -
+ (__force dma_addr_t)pool->iomap;
+}
+
+static inline struct cpdma_desc __iomem *
+desc_from_phys(struct cpdma_desc_pool *pool, dma_addr_t dma)
+{
+ return dma ? pool->iomap + dma - pool->phys : NULL;
+}
+
+static struct cpdma_desc __iomem *
+cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc)
+{
+ unsigned long flags;
+ int index;
+ struct cpdma_desc __iomem *desc = NULL;
+
+ spin_lock_irqsave(&pool->lock, flags);
+
+ index = bitmap_find_next_zero_area(pool->bitmap, pool->num_desc, 0,
+ num_desc, 0);
+ if (index < pool->num_desc) {
+ bitmap_set(pool->bitmap, index, num_desc);
+ desc = pool->iomap + pool->desc_size * index;
+ pool->used_desc++;
+ }
+
+ spin_unlock_irqrestore(&pool->lock, flags);
+ return desc;
+}
+
+static void cpdma_desc_free(struct cpdma_desc_pool *pool,
+ struct cpdma_desc __iomem *desc, int num_desc)
+{
+ unsigned long flags, index;
+
+ index = ((unsigned long)desc - (unsigned long)pool->iomap) /
+ pool->desc_size;
+ spin_lock_irqsave(&pool->lock, flags);
+ bitmap_clear(pool->bitmap, index, num_desc);
+ pool->used_desc--;
+ spin_unlock_irqrestore(&pool->lock, flags);
+}
+
+struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params)
+{
+ struct cpdma_ctlr *ctlr;
+
+ ctlr = kzalloc(sizeof(*ctlr), GFP_KERNEL);
+ if (!ctlr)
+ return NULL;
+
+ ctlr->state = CPDMA_STATE_IDLE;
+ ctlr->params = *params;
+ ctlr->dev = params->dev;
+ spin_lock_init(&ctlr->lock);
+
+ ctlr->pool = cpdma_desc_pool_create(ctlr->dev,
+ ctlr->params.desc_mem_phys,
+ ctlr->params.desc_mem_size,
+ ctlr->params.desc_align);
+ if (!ctlr->pool) {
+ kfree(ctlr);
+ return NULL;
+ }
+
+ if (WARN_ON(ctlr->num_chan > CPDMA_MAX_CHANNELS))
+ ctlr->num_chan = CPDMA_MAX_CHANNELS;
+ return ctlr;
+}
+
+int cpdma_ctlr_start(struct cpdma_ctlr *ctlr)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+ if (ctlr->state != CPDMA_STATE_IDLE) {
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+ return -EBUSY;
+ }
+
+ if (ctlr->params.has_soft_reset) {
+ unsigned long timeout = jiffies + HZ/10;
+
+ dma_reg_write(ctlr, CPDMA_SOFTRESET, 1);
+ while (time_before(jiffies, timeout)) {
+ if (dma_reg_read(ctlr, CPDMA_SOFTRESET) == 0)
+ break;
+ }
+ WARN_ON(!time_before(jiffies, timeout));
+ }
+
+ for (i = 0; i < ctlr->num_chan; i++) {
+ __raw_writel(0, ctlr->params.txhdp + 4 * i);
+ __raw_writel(0, ctlr->params.rxhdp + 4 * i);
+ __raw_writel(0, ctlr->params.txcp + 4 * i);
+ __raw_writel(0, ctlr->params.rxcp + 4 * i);
+ }
+
+ dma_reg_write(ctlr, CPDMA_RXINTMASKCLEAR, 0xffffffff);
+ dma_reg_write(ctlr, CPDMA_TXINTMASKCLEAR, 0xffffffff);
+
+ dma_reg_write(ctlr, CPDMA_TXCONTROL, 1);
+ dma_reg_write(ctlr, CPDMA_RXCONTROL, 1);
+
+ ctlr->state = CPDMA_STATE_ACTIVE;
+
+ for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
+ if (ctlr->channels[i])
+ cpdma_chan_start(ctlr->channels[i]);
+ }
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+ return 0;
+}
+
+int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+ if (ctlr->state != CPDMA_STATE_ACTIVE) {
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+ return -EINVAL;
+ }
+
+ ctlr->state = CPDMA_STATE_TEARDOWN;
+
+ for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
+ if (ctlr->channels[i])
+ cpdma_chan_stop(ctlr->channels[i]);
+ }
+
+ dma_reg_write(ctlr, CPDMA_RXINTMASKCLEAR, 0xffffffff);
+ dma_reg_write(ctlr, CPDMA_TXINTMASKCLEAR, 0xffffffff);
+
+ dma_reg_write(ctlr, CPDMA_TXCONTROL, 0);
+ dma_reg_write(ctlr, CPDMA_RXCONTROL, 0);
+
+ ctlr->state = CPDMA_STATE_IDLE;
+
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+ return 0;
+}
+
+int cpdma_ctlr_dump(struct cpdma_ctlr *ctlr)
+{
+ struct device *dev = ctlr->dev;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+
+ dev_info(dev, "CPDMA: state: %s", cpdma_state_str[ctlr->state]);
+
+ dev_info(dev, "CPDMA: txidver: %x",
+ dma_reg_read(ctlr, CPDMA_TXIDVER));
+ dev_info(dev, "CPDMA: txcontrol: %x",
+ dma_reg_read(ctlr, CPDMA_TXCONTROL));
+ dev_info(dev, "CPDMA: txteardown: %x",
+ dma_reg_read(ctlr, CPDMA_TXTEARDOWN));
+ dev_info(dev, "CPDMA: rxidver: %x",
+ dma_reg_read(ctlr, CPDMA_RXIDVER));
+ dev_info(dev, "CPDMA: rxcontrol: %x",
+ dma_reg_read(ctlr, CPDMA_RXCONTROL));
+ dev_info(dev, "CPDMA: softreset: %x",
+ dma_reg_read(ctlr, CPDMA_SOFTRESET));
+ dev_info(dev, "CPDMA: rxteardown: %x",
+ dma_reg_read(ctlr, CPDMA_RXTEARDOWN));
+ dev_info(dev, "CPDMA: txintstatraw: %x",
+ dma_reg_read(ctlr, CPDMA_TXINTSTATRAW));
+ dev_info(dev, "CPDMA: txintstatmasked: %x",
+ dma_reg_read(ctlr, CPDMA_TXINTSTATMASKED));
+ dev_info(dev, "CPDMA: txintmaskset: %x",
+ dma_reg_read(ctlr, CPDMA_TXINTMASKSET));
+ dev_info(dev, "CPDMA: txintmaskclear: %x",
+ dma_reg_read(ctlr, CPDMA_TXINTMASKCLEAR));
+ dev_info(dev, "CPDMA: macinvector: %x",
+ dma_reg_read(ctlr, CPDMA_MACINVECTOR));
+ dev_info(dev, "CPDMA: maceoivector: %x",
+ dma_reg_read(ctlr, CPDMA_MACEOIVECTOR));
+ dev_info(dev, "CPDMA: rxintstatraw: %x",
+ dma_reg_read(ctlr, CPDMA_RXINTSTATRAW));
+ dev_info(dev, "CPDMA: rxintstatmasked: %x",
+ dma_reg_read(ctlr, CPDMA_RXINTSTATMASKED));
+ dev_info(dev, "CPDMA: rxintmaskset: %x",
+ dma_reg_read(ctlr, CPDMA_RXINTMASKSET));
+ dev_info(dev, "CPDMA: rxintmaskclear: %x",
+ dma_reg_read(ctlr, CPDMA_RXINTMASKCLEAR));
+ dev_info(dev, "CPDMA: dmaintstatraw: %x",
+ dma_reg_read(ctlr, CPDMA_DMAINTSTATRAW));
+ dev_info(dev, "CPDMA: dmaintstatmasked: %x",
+ dma_reg_read(ctlr, CPDMA_DMAINTSTATMASKED));
+ dev_info(dev, "CPDMA: dmaintmaskset: %x",
+ dma_reg_read(ctlr, CPDMA_DMAINTMASKSET));
+ dev_info(dev, "CPDMA: dmaintmaskclear: %x",
+ dma_reg_read(ctlr, CPDMA_DMAINTMASKCLEAR));
+
+ if (!ctlr->params.has_ext_regs) {
+ dev_info(dev, "CPDMA: dmacontrol: %x",
+ dma_reg_read(ctlr, CPDMA_DMACONTROL));
+ dev_info(dev, "CPDMA: dmastatus: %x",
+ dma_reg_read(ctlr, CPDMA_DMASTATUS));
+ dev_info(dev, "CPDMA: rxbuffofs: %x",
+ dma_reg_read(ctlr, CPDMA_RXBUFFOFS));
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++)
+ if (ctlr->channels[i])
+ cpdma_chan_dump(ctlr->channels[i]);
+
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+ return 0;
+}
+
+int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr)
+{
+ unsigned long flags;
+ int ret = 0, i;
+
+ if (!ctlr)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+ if (ctlr->state != CPDMA_STATE_IDLE)
+ cpdma_ctlr_stop(ctlr);
+
+ for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
+ if (ctlr->channels[i])
+ cpdma_chan_destroy(ctlr->channels[i]);
+ }
+
+ cpdma_desc_pool_destroy(ctlr->pool);
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+ kfree(ctlr);
+ return ret;
+}
+
+int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable)
+{
+ unsigned long flags;
+ int i, reg;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+ if (ctlr->state != CPDMA_STATE_ACTIVE) {
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+ return -EINVAL;
+ }
+
+ reg = enable ? CPDMA_DMAINTMASKSET : CPDMA_DMAINTMASKCLEAR;
+ dma_reg_write(ctlr, reg, CPDMA_DMAINT_HOSTERR);
+
+ for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
+ if (ctlr->channels[i])
+ cpdma_chan_int_ctrl(ctlr->channels[i], enable);
+ }
+
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+ return 0;
+}
+
+void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr)
+{
+ dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, 0);
+}
+
+struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,
+ cpdma_handler_fn handler)
+{
+ struct cpdma_chan *chan;
+ int ret, offset = (chan_num % CPDMA_MAX_CHANNELS) * 4;
+ unsigned long flags;
+
+ if (__chan_linear(chan_num) >= ctlr->num_chan)
+ return NULL;
+
+ ret = -ENOMEM;
+ chan = kzalloc(sizeof(*chan), GFP_KERNEL);
+ if (!chan)
+ goto err_chan_alloc;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+ ret = -EBUSY;
+ if (ctlr->channels[chan_num])
+ goto err_chan_busy;
+
+ chan->ctlr = ctlr;
+ chan->state = CPDMA_STATE_IDLE;
+ chan->chan_num = chan_num;
+ chan->handler = handler;
+
+ if (is_rx_chan(chan)) {
+ chan->hdp = ctlr->params.rxhdp + offset;
+ chan->cp = ctlr->params.rxcp + offset;
+ chan->rxfree = ctlr->params.rxfree + offset;
+ chan->int_set = CPDMA_RXINTMASKSET;
+ chan->int_clear = CPDMA_RXINTMASKCLEAR;
+ chan->td = CPDMA_RXTEARDOWN;
+ chan->dir = DMA_FROM_DEVICE;
+ } else {
+ chan->hdp = ctlr->params.txhdp + offset;
+ chan->cp = ctlr->params.txcp + offset;
+ chan->int_set = CPDMA_TXINTMASKSET;
+ chan->int_clear = CPDMA_TXINTMASKCLEAR;
+ chan->td = CPDMA_TXTEARDOWN;
+ chan->dir = DMA_TO_DEVICE;
+ }
+ chan->mask = BIT(chan_linear(chan));
+
+ spin_lock_init(&chan->lock);
+
+ ctlr->channels[chan_num] = chan;
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+ return chan;
+
+err_chan_busy:
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+ kfree(chan);
+err_chan_alloc:
+ return ERR_PTR(ret);
+}
+
+int cpdma_chan_destroy(struct cpdma_chan *chan)
+{
+ struct cpdma_ctlr *ctlr = chan->ctlr;
+ unsigned long flags;
+
+ if (!chan)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+ if (chan->state != CPDMA_STATE_IDLE)
+ cpdma_chan_stop(chan);
+ ctlr->channels[chan->chan_num] = NULL;
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+ kfree(chan);
+ return 0;
+}
+
+int cpdma_chan_get_stats(struct cpdma_chan *chan,
+ struct cpdma_chan_stats *stats)
+{
+ unsigned long flags;
+ if (!chan)
+ return -EINVAL;
+ spin_lock_irqsave(&chan->lock, flags);
+ memcpy(stats, &chan->stats, sizeof(*stats));
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return 0;
+}
+
+int cpdma_chan_dump(struct cpdma_chan *chan)
+{
+ unsigned long flags;
+ struct device *dev = chan->ctlr->dev;
+
+ spin_lock_irqsave(&chan->lock, flags);
+
+ dev_info(dev, "channel %d (%s %d) state %s",
+ chan->chan_num, is_rx_chan(chan) ? "rx" : "tx",
+ chan_linear(chan), cpdma_state_str[chan->state]);
+ dev_info(dev, "\thdp: %x\n", chan_read(chan, hdp));
+ dev_info(dev, "\tcp: %x\n", chan_read(chan, cp));
+ if (chan->rxfree) {
+ dev_info(dev, "\trxfree: %x\n",
+ chan_read(chan, rxfree));
+ }
+
+ dev_info(dev, "\tstats head_enqueue: %d\n",
+ chan->stats.head_enqueue);
+ dev_info(dev, "\tstats tail_enqueue: %d\n",
+ chan->stats.tail_enqueue);
+ dev_info(dev, "\tstats pad_enqueue: %d\n",
+ chan->stats.pad_enqueue);
+ dev_info(dev, "\tstats misqueued: %d\n",
+ chan->stats.misqueued);
+ dev_info(dev, "\tstats desc_alloc_fail: %d\n",
+ chan->stats.desc_alloc_fail);
+ dev_info(dev, "\tstats pad_alloc_fail: %d\n",
+ chan->stats.pad_alloc_fail);
+ dev_info(dev, "\tstats runt_receive_buff: %d\n",
+ chan->stats.runt_receive_buff);
+ dev_info(dev, "\tstats runt_transmit_buff: %d\n",
+ chan->stats.runt_transmit_buff);
+ dev_info(dev, "\tstats empty_dequeue: %d\n",
+ chan->stats.empty_dequeue);
+ dev_info(dev, "\tstats busy_dequeue: %d\n",
+ chan->stats.busy_dequeue);
+ dev_info(dev, "\tstats good_dequeue: %d\n",
+ chan->stats.good_dequeue);
+ dev_info(dev, "\tstats requeue: %d\n",
+ chan->stats.requeue);
+ dev_info(dev, "\tstats teardown_dequeue: %d\n",
+ chan->stats.teardown_dequeue);
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return 0;
+}
+
+static void __cpdma_chan_submit(struct cpdma_chan *chan,
+ struct cpdma_desc __iomem *desc)
+{
+ struct cpdma_ctlr *ctlr = chan->ctlr;
+ struct cpdma_desc __iomem *prev = chan->tail;
+ struct cpdma_desc_pool *pool = ctlr->pool;
+ dma_addr_t desc_dma;
+ u32 mode;
+
+ desc_dma = desc_phys(pool, desc);
+
+ /* simple case - idle channel */
+ if (!chan->head) {
+ chan->stats.head_enqueue++;
+ chan->head = desc;
+ chan->tail = desc;
+ if (chan->state == CPDMA_STATE_ACTIVE)
+ chan_write(chan, hdp, desc_dma);
+ return;
+ }
+
+ /* first chain the descriptor at the tail of the list */
+ desc_write(prev, hw_next, desc_dma);
+ chan->tail = desc;
+ chan->stats.tail_enqueue++;
+
+ /* next check if EOQ has been triggered already */
+ mode = desc_read(prev, hw_mode);
+ if (((mode & (CPDMA_DESC_EOQ | CPDMA_DESC_OWNER)) == CPDMA_DESC_EOQ) &&
+ (chan->state == CPDMA_STATE_ACTIVE)) {
+ desc_write(prev, hw_mode, mode & ~CPDMA_DESC_EOQ);
+ chan_write(chan, hdp, desc_dma);
+ chan->stats.misqueued++;
+ }
+}
+
+int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
+ int len, gfp_t gfp_mask)
+{
+ struct cpdma_ctlr *ctlr = chan->ctlr;
+ struct cpdma_desc __iomem *desc;
+ dma_addr_t buffer;
+ unsigned long flags;
+ u32 mode;
+ int ret = 0;
+
+ spin_lock_irqsave(&chan->lock, flags);
+
+ if (chan->state == CPDMA_STATE_TEARDOWN) {
+ ret = -EINVAL;
+ goto unlock_ret;
+ }
+
+ desc = cpdma_desc_alloc(ctlr->pool, 1);
+ if (!desc) {
+ chan->stats.desc_alloc_fail++;
+ ret = -ENOMEM;
+ goto unlock_ret;
+ }
+
+ if (len < ctlr->params.min_packet_size) {
+ len = ctlr->params.min_packet_size;
+ chan->stats.runt_transmit_buff++;
+ }
+
+ buffer = dma_map_single(ctlr->dev, data, len, chan->dir);
+ mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP;
+
+ desc_write(desc, hw_next, 0);
+ desc_write(desc, hw_buffer, buffer);
+ desc_write(desc, hw_len, len);
+ desc_write(desc, hw_mode, mode | len);
+ desc_write(desc, sw_token, token);
+ desc_write(desc, sw_buffer, buffer);
+ desc_write(desc, sw_len, len);
+
+ __cpdma_chan_submit(chan, desc);
+
+ if (chan->state == CPDMA_STATE_ACTIVE && chan->rxfree)
+ chan_write(chan, rxfree, 1);
+
+ chan->count++;
+
+unlock_ret:
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return ret;
+}
+
+static void __cpdma_chan_free(struct cpdma_chan *chan,
+ struct cpdma_desc __iomem *desc,
+ int outlen, int status)
+{
+ struct cpdma_ctlr *ctlr = chan->ctlr;
+ struct cpdma_desc_pool *pool = ctlr->pool;
+ dma_addr_t buff_dma;
+ int origlen;
+ void *token;
+
+ token = (void *)desc_read(desc, sw_token);
+ buff_dma = desc_read(desc, sw_buffer);
+ origlen = desc_read(desc, sw_len);
+
+ dma_unmap_single(ctlr->dev, buff_dma, origlen, chan->dir);
+ cpdma_desc_free(pool, desc, 1);
+ (*chan->handler)(token, outlen, status);
+}
+
+static int __cpdma_chan_process(struct cpdma_chan *chan)
+{
+ struct cpdma_ctlr *ctlr = chan->ctlr;
+ struct cpdma_desc __iomem *desc;
+ int status, outlen;
+ struct cpdma_desc_pool *pool = ctlr->pool;
+ dma_addr_t desc_dma;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->lock, flags);
+
+ desc = chan->head;
+ if (!desc) {
+ chan->stats.empty_dequeue++;
+ status = -ENOENT;
+ goto unlock_ret;
+ }
+ desc_dma = desc_phys(pool, desc);
+
+ status = __raw_readl(&desc->hw_mode);
+ outlen = status & 0x7ff;
+ if (status & CPDMA_DESC_OWNER) {
+ chan->stats.busy_dequeue++;
+ status = -EBUSY;
+ goto unlock_ret;
+ }
+ status = status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE);
+
+ chan->head = desc_from_phys(pool, desc_read(desc, hw_next));
+ chan_write(chan, cp, desc_dma);
+ chan->count--;
+ chan->stats.good_dequeue++;
+
+ if (status & CPDMA_DESC_EOQ) {
+ chan->stats.requeue++;
+ chan_write(chan, hdp, desc_phys(pool, chan->head));
+ }
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ __cpdma_chan_free(chan, desc, outlen, status);
+ return status;
+
+unlock_ret:
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return status;
+}
+
+int cpdma_chan_process(struct cpdma_chan *chan, int quota)
+{
+ int used = 0, ret = 0;
+
+ if (chan->state != CPDMA_STATE_ACTIVE)
+ return -EINVAL;
+
+ while (used < quota) {
+ ret = __cpdma_chan_process(chan);
+ if (ret < 0)
+ break;
+ used++;
+ }
+ return used;
+}
+
+int cpdma_chan_start(struct cpdma_chan *chan)
+{
+ struct cpdma_ctlr *ctlr = chan->ctlr;
+ struct cpdma_desc_pool *pool = ctlr->pool;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->state != CPDMA_STATE_IDLE) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -EBUSY;
+ }
+ if (ctlr->state != CPDMA_STATE_ACTIVE) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -EINVAL;
+ }
+ dma_reg_write(ctlr, chan->int_set, chan->mask);
+ chan->state = CPDMA_STATE_ACTIVE;
+ if (chan->head) {
+ chan_write(chan, hdp, desc_phys(pool, chan->head));
+ if (chan->rxfree)
+ chan_write(chan, rxfree, chan->count);
+ }
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return 0;
+}
+
+int cpdma_chan_stop(struct cpdma_chan *chan)
+{
+ struct cpdma_ctlr *ctlr = chan->ctlr;
+ struct cpdma_desc_pool *pool = ctlr->pool;
+ unsigned long flags;
+ int ret;
+ unsigned long timeout;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->state != CPDMA_STATE_ACTIVE) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -EINVAL;
+ }
+
+ chan->state = CPDMA_STATE_TEARDOWN;
+ dma_reg_write(ctlr, chan->int_clear, chan->mask);
+
+ /* trigger teardown */
+ dma_reg_write(ctlr, chan->td, chan->chan_num);
+
+ /* wait for teardown complete */
+ timeout = jiffies + HZ/10; /* 100 msec */
+ while (time_before(jiffies, timeout)) {
+ u32 cp = chan_read(chan, cp);
+ if ((cp & CPDMA_TEARDOWN_VALUE) == CPDMA_TEARDOWN_VALUE)
+ break;
+ cpu_relax();
+ }
+ WARN_ON(!time_before(jiffies, timeout));
+ chan_write(chan, cp, CPDMA_TEARDOWN_VALUE);
+
+ /* handle completed packets */
+ do {
+ ret = __cpdma_chan_process(chan);
+ if (ret < 0)
+ break;
+ } while ((ret & CPDMA_DESC_TD_COMPLETE) == 0);
+
+ /* remaining packets haven't been tx/rx'ed, clean them up */
+ while (chan->head) {
+ struct cpdma_desc __iomem *desc = chan->head;
+ dma_addr_t next_dma;
+
+ next_dma = desc_read(desc, hw_next);
+ chan->head = desc_from_phys(pool, next_dma);
+ chan->stats.teardown_dequeue++;
+
+ /* issue callback without locks held */
+ spin_unlock_irqrestore(&chan->lock, flags);
+ __cpdma_chan_free(chan, desc, 0, -ENOSYS);
+ spin_lock_irqsave(&chan->lock, flags);
+ }
+
+ chan->state = CPDMA_STATE_IDLE;
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return 0;
+}
+
+int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->state != CPDMA_STATE_ACTIVE) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -EINVAL;
+ }
+
+ dma_reg_write(chan->ctlr, enable ? chan->int_set : chan->int_clear,
+ chan->mask);
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ return 0;
+}
+
+struct cpdma_control_info {
+ u32 reg;
+ u32 shift, mask;
+ int access;
+#define ACCESS_RO BIT(0)
+#define ACCESS_WO BIT(1)
+#define ACCESS_RW (ACCESS_RO | ACCESS_WO)
+};
+
+struct cpdma_control_info controls[] = {
+ [CPDMA_CMD_IDLE] = {CPDMA_DMACONTROL, 3, 1, ACCESS_WO},
+ [CPDMA_COPY_ERROR_FRAMES] = {CPDMA_DMACONTROL, 4, 1, ACCESS_RW},
+ [CPDMA_RX_OFF_LEN_UPDATE] = {CPDMA_DMACONTROL, 2, 1, ACCESS_RW},
+ [CPDMA_RX_OWNERSHIP_FLIP] = {CPDMA_DMACONTROL, 1, 1, ACCESS_RW},
+ [CPDMA_TX_PRIO_FIXED] = {CPDMA_DMACONTROL, 0, 1, ACCESS_RW},
+ [CPDMA_STAT_IDLE] = {CPDMA_DMASTATUS, 31, 1, ACCESS_RO},
+ [CPDMA_STAT_TX_ERR_CODE] = {CPDMA_DMASTATUS, 20, 0xf, ACCESS_RW},
+ [CPDMA_STAT_TX_ERR_CHAN] = {CPDMA_DMASTATUS, 16, 0x7, ACCESS_RW},
+ [CPDMA_STAT_RX_ERR_CODE] = {CPDMA_DMASTATUS, 12, 0xf, ACCESS_RW},
+ [CPDMA_STAT_RX_ERR_CHAN] = {CPDMA_DMASTATUS, 8, 0x7, ACCESS_RW},
+ [CPDMA_RX_BUFFER_OFFSET] = {CPDMA_RXBUFFOFS, 0, 0xffff, ACCESS_RW},
+};
+
+int cpdma_control_get(struct cpdma_ctlr *ctlr, int control)
+{
+ unsigned long flags;
+ struct cpdma_control_info *info = &controls[control];
+ int ret;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+
+ ret = -ENOTSUPP;
+ if (!ctlr->params.has_ext_regs)
+ goto unlock_ret;
+
+ ret = -EINVAL;
+ if (ctlr->state != CPDMA_STATE_ACTIVE)
+ goto unlock_ret;
+
+ ret = -ENOENT;
+ if (control < 0 || control >= ARRAY_SIZE(controls))
+ goto unlock_ret;
+
+ ret = -EPERM;
+ if ((info->access & ACCESS_RO) != ACCESS_RO)
+ goto unlock_ret;
+
+ ret = (dma_reg_read(ctlr, info->reg) >> info->shift) & info->mask;
+
+unlock_ret:
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+ return ret;
+}
+
+int cpdma_control_set(struct cpdma_ctlr *ctlr, int control, int value)
+{
+ unsigned long flags;
+ struct cpdma_control_info *info = &controls[control];
+ int ret;
+ u32 val;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+
+ ret = -ENOTSUPP;
+ if (!ctlr->params.has_ext_regs)
+ goto unlock_ret;
+
+ ret = -EINVAL;
+ if (ctlr->state != CPDMA_STATE_ACTIVE)
+ goto unlock_ret;
+
+ ret = -ENOENT;
+ if (control < 0 || control >= ARRAY_SIZE(controls))
+ goto unlock_ret;
+
+ ret = -EPERM;
+ if ((info->access & ACCESS_WO) != ACCESS_WO)
+ goto unlock_ret;
+
+ val = dma_reg_read(ctlr, info->reg);
+ val &= ~(info->mask << info->shift);
+ val |= (value & info->mask) << info->shift;
+ dma_reg_write(ctlr, info->reg, val);
+ ret = 0;
+
+unlock_ret:
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+ return ret;
+}
diff --git a/drivers/net/davinci_cpdma.h b/drivers/net/davinci_cpdma.h
new file mode 100644
index 000000000000..868e50ebde45
--- /dev/null
+++ b/drivers/net/davinci_cpdma.h
@@ -0,0 +1,108 @@
+/*
+ * Texas Instruments CPDMA Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __DAVINCI_CPDMA_H__
+#define __DAVINCI_CPDMA_H__
+
+#define CPDMA_MAX_CHANNELS BITS_PER_LONG
+
+#define tx_chan_num(chan) (chan)
+#define rx_chan_num(chan) ((chan) + CPDMA_MAX_CHANNELS)
+#define is_rx_chan(chan) ((chan)->chan_num >= CPDMA_MAX_CHANNELS)
+#define is_tx_chan(chan) (!is_rx_chan(chan))
+#define __chan_linear(chan_num) ((chan_num) & (CPDMA_MAX_CHANNELS - 1))
+#define chan_linear(chan) __chan_linear((chan)->chan_num)
+
+struct cpdma_params {
+ struct device *dev;
+ void __iomem *dmaregs;
+ void __iomem *txhdp, *rxhdp, *txcp, *rxcp;
+ void __iomem *rxthresh, *rxfree;
+ int num_chan;
+ bool has_soft_reset;
+ int min_packet_size;
+ u32 desc_mem_phys;
+ int desc_mem_size;
+ int desc_align;
+
+ /*
+ * Some instances of embedded cpdma controllers have extra control and
+ * status registers. The following flag enables access to these
+ * "extended" registers.
+ */
+ bool has_ext_regs;
+};
+
+struct cpdma_chan_stats {
+ u32 head_enqueue;
+ u32 tail_enqueue;
+ u32 pad_enqueue;
+ u32 misqueued;
+ u32 desc_alloc_fail;
+ u32 pad_alloc_fail;
+ u32 runt_receive_buff;
+ u32 runt_transmit_buff;
+ u32 empty_dequeue;
+ u32 busy_dequeue;
+ u32 good_dequeue;
+ u32 requeue;
+ u32 teardown_dequeue;
+};
+
+struct cpdma_ctlr;
+struct cpdma_chan;
+
+typedef void (*cpdma_handler_fn)(void *token, int len, int status);
+
+struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params);
+int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr);
+int cpdma_ctlr_start(struct cpdma_ctlr *ctlr);
+int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr);
+int cpdma_ctlr_dump(struct cpdma_ctlr *ctlr);
+
+struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,
+ cpdma_handler_fn handler);
+int cpdma_chan_destroy(struct cpdma_chan *chan);
+int cpdma_chan_start(struct cpdma_chan *chan);
+int cpdma_chan_stop(struct cpdma_chan *chan);
+int cpdma_chan_dump(struct cpdma_chan *chan);
+
+int cpdma_chan_get_stats(struct cpdma_chan *chan,
+ struct cpdma_chan_stats *stats);
+int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
+ int len, gfp_t gfp_mask);
+int cpdma_chan_process(struct cpdma_chan *chan, int quota);
+
+int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable);
+void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr);
+int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable);
+
+enum cpdma_control {
+ CPDMA_CMD_IDLE, /* write-only */
+ CPDMA_COPY_ERROR_FRAMES, /* read-write */
+ CPDMA_RX_OFF_LEN_UPDATE, /* read-write */
+ CPDMA_RX_OWNERSHIP_FLIP, /* read-write */
+ CPDMA_TX_PRIO_FIXED, /* read-write */
+ CPDMA_STAT_IDLE, /* read-only */
+ CPDMA_STAT_TX_ERR_CHAN, /* read-only */
+ CPDMA_STAT_TX_ERR_CODE, /* read-only */
+ CPDMA_STAT_RX_ERR_CHAN, /* read-only */
+ CPDMA_STAT_RX_ERR_CODE, /* read-only */
+ CPDMA_RX_BUFFER_OFFSET, /* read-write */
+};
+
+int cpdma_control_get(struct cpdma_ctlr *ctlr, int control);
+int cpdma_control_set(struct cpdma_ctlr *ctlr, int control, int value);
+
+#endif
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index 7fbd052ddb0a..2a628d17d178 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -63,6 +63,8 @@
#include <asm/irq.h>
#include <asm/page.h>
+#include "davinci_cpdma.h"
+
static int debug_level;
module_param(debug_level, int, 0);
MODULE_PARM_DESC(debug_level, "DaVinci EMAC debug level (NETIF_MSG bits)");
@@ -113,7 +115,7 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
#define EMAC_DEF_MAX_FRAME_SIZE (1500 + 14 + 4 + 4)
#define EMAC_DEF_TX_CH (0) /* Default 0th channel */
#define EMAC_DEF_RX_CH (0) /* Default 0th channel */
-#define EMAC_DEF_MDIO_TICK_MS (10) /* typically 1 tick=1 ms) */
+#define EMAC_DEF_RX_NUM_DESC (128)
#define EMAC_DEF_MAX_TX_CH (1) /* Max TX channels configured */
#define EMAC_DEF_MAX_RX_CH (1) /* Max RX channels configured */
#define EMAC_POLL_WEIGHT (64) /* Default NAPI poll weight */
@@ -125,7 +127,6 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
/* EMAC register related defines */
#define EMAC_ALL_MULTI_REG_VALUE (0xFFFFFFFF)
#define EMAC_NUM_MULTICAST_BITS (64)
-#define EMAC_TEARDOWN_VALUE (0xFFFFFFFC)
#define EMAC_TX_CONTROL_TX_ENABLE_VAL (0x1)
#define EMAC_RX_CONTROL_RX_ENABLE_VAL (0x1)
#define EMAC_MAC_HOST_ERR_INTMASK_VAL (0x2)
@@ -212,24 +213,10 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
#define EMAC_DEF_MAX_MULTICAST_ADDRESSES (64) /* Max mcast addr's */
/* EMAC Peripheral Device Register Memory Layout structure */
-#define EMAC_TXIDVER 0x0
-#define EMAC_TXCONTROL 0x4
-#define EMAC_TXTEARDOWN 0x8
-#define EMAC_RXIDVER 0x10
-#define EMAC_RXCONTROL 0x14
-#define EMAC_RXTEARDOWN 0x18
-#define EMAC_TXINTSTATRAW 0x80
-#define EMAC_TXINTSTATMASKED 0x84
-#define EMAC_TXINTMASKSET 0x88
-#define EMAC_TXINTMASKCLEAR 0x8C
#define EMAC_MACINVECTOR 0x90
#define EMAC_DM646X_MACEOIVECTOR 0x94
-#define EMAC_RXINTSTATRAW 0xA0
-#define EMAC_RXINTSTATMASKED 0xA4
-#define EMAC_RXINTMASKSET 0xA8
-#define EMAC_RXINTMASKCLEAR 0xAC
#define EMAC_MACINTSTATRAW 0xB0
#define EMAC_MACINTSTATMASKED 0xB4
#define EMAC_MACINTMASKSET 0xB8
@@ -256,12 +243,6 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
#define EMAC_MACADDRHI 0x504
#define EMAC_MACINDEX 0x508
-/* EMAC HDP and Completion registors */
-#define EMAC_TXHDP(ch) (0x600 + (ch * 4))
-#define EMAC_RXHDP(ch) (0x620 + (ch * 4))
-#define EMAC_TXCP(ch) (0x640 + (ch * 4))
-#define EMAC_RXCP(ch) (0x660 + (ch * 4))
-
/* EMAC statistics registers */
#define EMAC_RXGOODFRAMES 0x200
#define EMAC_RXBCASTFRAMES 0x204
@@ -303,25 +284,6 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
#define EMAC_DM644X_INTMIN_INTVL 0x1
#define EMAC_DM644X_INTMAX_INTVL (EMAC_DM644X_EWINTCNT_MASK)
-/* EMAC MDIO related */
-/* Mask & Control defines */
-#define MDIO_CONTROL_CLKDIV (0xFF)
-#define MDIO_CONTROL_ENABLE BIT(30)
-#define MDIO_USERACCESS_GO BIT(31)
-#define MDIO_USERACCESS_WRITE BIT(30)
-#define MDIO_USERACCESS_READ (0)
-#define MDIO_USERACCESS_REGADR (0x1F << 21)
-#define MDIO_USERACCESS_PHYADR (0x1F << 16)
-#define MDIO_USERACCESS_DATA (0xFFFF)
-#define MDIO_USERPHYSEL_LINKSEL BIT(7)
-#define MDIO_VER_MODID (0xFFFF << 16)
-#define MDIO_VER_REVMAJ (0xFF << 8)
-#define MDIO_VER_REVMIN (0xFF)
-
-#define MDIO_USERACCESS(inst) (0x80 + (inst * 8))
-#define MDIO_USERPHYSEL(inst) (0x84 + (inst * 8))
-#define MDIO_CONTROL (0x04)
-
/* EMAC DM646X control module registers */
#define EMAC_DM646X_CMINTCTRL 0x0C
#define EMAC_DM646X_CMRXINTEN 0x14
@@ -345,120 +307,6 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
/* EMAC Stats Clear Mask */
#define EMAC_STATS_CLR_MASK (0xFFFFFFFF)
-/** net_buf_obj: EMAC network bufferdata structure
- *
- * EMAC network buffer data structure
- */
-struct emac_netbufobj {
- void *buf_token;
- char *data_ptr;
- int length;
-};
-
-/** net_pkt_obj: EMAC network packet data structure
- *
- * EMAC network packet data structure - supports buffer list (for future)
- */
-struct emac_netpktobj {
- void *pkt_token; /* data token may hold tx/rx chan id */
- struct emac_netbufobj *buf_list; /* array of network buffer objects */
- int num_bufs;
- int pkt_length;
-};
-
-/** emac_tx_bd: EMAC TX Buffer descriptor data structure
- *
- * EMAC TX Buffer descriptor data structure
- */
-struct emac_tx_bd {
- int h_next;
- int buff_ptr;
- int off_b_len;
- int mode; /* SOP, EOP, ownership, EOQ, teardown,Qstarv, length */
- struct emac_tx_bd __iomem *next;
- void *buf_token;
-};
-
-/** emac_txch: EMAC TX Channel data structure
- *
- * EMAC TX Channel data structure
- */
-struct emac_txch {
- /* Config related */
- u32 num_bd;
- u32 service_max;
-
- /* CPPI specific */
- u32 alloc_size;
- void __iomem *bd_mem;
- struct emac_tx_bd __iomem *bd_pool_head;
- struct emac_tx_bd __iomem *active_queue_head;
- struct emac_tx_bd __iomem *active_queue_tail;
- struct emac_tx_bd __iomem *last_hw_bdprocessed;
- u32 queue_active;
- u32 teardown_pending;
- u32 *tx_complete;
-
- /** statistics */
- u32 proc_count; /* TX: # of times emac_tx_bdproc is called */
- u32 mis_queued_packets;
- u32 queue_reinit;
- u32 end_of_queue_add;
- u32 out_of_tx_bd;
- u32 no_active_pkts; /* IRQ when there were no packets to process */
- u32 active_queue_count;
-};
-
-/** emac_rx_bd: EMAC RX Buffer descriptor data structure
- *
- * EMAC RX Buffer descriptor data structure
- */
-struct emac_rx_bd {
- int h_next;
- int buff_ptr;
- int off_b_len;
- int mode;
- struct emac_rx_bd __iomem *next;
- void *data_ptr;
- void *buf_token;
-};
-
-/** emac_rxch: EMAC RX Channel data structure
- *
- * EMAC RX Channel data structure
- */
-struct emac_rxch {
- /* configuration info */
- u32 num_bd;
- u32 service_max;
- u32 buf_size;
- char mac_addr[6];
-
- /** CPPI specific */
- u32 alloc_size;
- void __iomem *bd_mem;
- struct emac_rx_bd __iomem *bd_pool_head;
- struct emac_rx_bd __iomem *active_queue_head;
- struct emac_rx_bd __iomem *active_queue_tail;
- u32 queue_active;
- u32 teardown_pending;
-
- /* packet and buffer objects */
- struct emac_netpktobj pkt_queue;
- struct emac_netbufobj buf_queue;
-
- /** statistics */
- u32 proc_count; /* number of times emac_rx_bdproc is called */
- u32 processed_bd;
- u32 recycled_bd;
- u32 out_of_rx_bd;
- u32 out_of_rx_buffers;
- u32 queue_reinit;
- u32 end_of_queue_add;
- u32 end_of_queue;
- u32 mis_queued_packets;
-};
-
/* emac_priv: EMAC private data structure
*
* EMAC adapter private data structure
@@ -469,17 +317,13 @@ struct emac_priv {
struct platform_device *pdev;
struct napi_struct napi;
char mac_addr[6];
- spinlock_t tx_lock;
- spinlock_t rx_lock;
void __iomem *remap_addr;
u32 emac_base_phys;
void __iomem *emac_base;
void __iomem *ctrl_base;
- void __iomem *emac_ctrl_ram;
- u32 ctrl_ram_size;
- u32 hw_ram_addr;
- struct emac_txch *txch[EMAC_DEF_MAX_TX_CH];
- struct emac_rxch *rxch[EMAC_DEF_MAX_RX_CH];
+ struct cpdma_ctlr *dma;
+ struct cpdma_chan *txchan;
+ struct cpdma_chan *rxchan;
u32 link; /* 1=link on, 0=link off */
u32 speed; /* 0=Auto Neg, 1=No PHY, 10,100, 1000 - mbps */
u32 duplex; /* Link duplex: 0=Half, 1=Full */
@@ -493,13 +337,7 @@ struct emac_priv {
u32 mac_hash2;
u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS];
u32 rx_addr_type;
- /* periodic timer required for MDIO polling */
- struct timer_list periodic_timer;
- u32 periodic_ticks;
- u32 timer_active;
- u32 phy_mask;
- /* mii_bus,phy members */
- struct mii_bus *mii_bus;
+ const char *phy_id;
struct phy_device *phydev;
spinlock_t lock;
/*platform specific members*/
@@ -510,19 +348,6 @@ struct emac_priv {
/* clock frequency for EMAC */
static struct clk *emac_clk;
static unsigned long emac_bus_frequency;
-static unsigned long mdio_max_freq;
-
-#define emac_virt_to_phys(addr, priv) \
- (((u32 __force)(addr) - (u32 __force)(priv->emac_ctrl_ram)) \
- + priv->hw_ram_addr)
-
-/* Cache macros - Packet buffers would be from skb pool which is cached */
-#define EMAC_VIRT_NOCACHE(addr) (addr)
-
-/* DM644x does not have BD's in cached memory - so no cache functions */
-#define BD_CACHE_INVALIDATE(addr, size)
-#define BD_CACHE_WRITEBACK(addr, size)
-#define BD_CACHE_WRITEBACK_INVALIDATE(addr, size)
/* EMAC TX Host Error description strings */
static char *emac_txhost_errcodes[16] = {
@@ -548,9 +373,6 @@ static char *emac_rxhost_errcodes[16] = {
#define emac_ctrl_read(reg) ioread32((priv->ctrl_base + (reg)))
#define emac_ctrl_write(reg, val) iowrite32(val, (priv->ctrl_base + (reg)))
-#define emac_mdio_read(reg) ioread32(bus->priv + (reg))
-#define emac_mdio_write(reg, val) iowrite32(val, (bus->priv + (reg)))
-
/**
* emac_dump_regs: Dump important EMAC registers to debug terminal
* @priv: The DaVinci EMAC private adapter structure
@@ -569,20 +391,6 @@ static void emac_dump_regs(struct emac_priv *priv)
emac_ctrl_read(EMAC_CTRL_EWCTL),
emac_ctrl_read(EMAC_CTRL_EWINTTCNT));
}
- dev_info(emac_dev, "EMAC: TXID: %08X %s, RXID: %08X %s\n",
- emac_read(EMAC_TXIDVER),
- ((emac_read(EMAC_TXCONTROL)) ? "enabled" : "disabled"),
- emac_read(EMAC_RXIDVER),
- ((emac_read(EMAC_RXCONTROL)) ? "enabled" : "disabled"));
- dev_info(emac_dev, "EMAC: TXIntRaw:%08X, TxIntMasked: %08X, "\
- "TxIntMasSet: %08X\n", emac_read(EMAC_TXINTSTATRAW),
- emac_read(EMAC_TXINTSTATMASKED), emac_read(EMAC_TXINTMASKSET));
- dev_info(emac_dev, "EMAC: RXIntRaw:%08X, RxIntMasked: %08X, "\
- "RxIntMasSet: %08X\n", emac_read(EMAC_RXINTSTATRAW),
- emac_read(EMAC_RXINTSTATMASKED), emac_read(EMAC_RXINTMASKSET));
- dev_info(emac_dev, "EMAC: MacIntRaw:%08X, MacIntMasked: %08X, "\
- "MacInVector=%08X\n", emac_read(EMAC_MACINTSTATRAW),
- emac_read(EMAC_MACINTSTATMASKED), emac_read(EMAC_MACINVECTOR));
dev_info(emac_dev, "EMAC: EmuControl:%08X, FifoControl: %08X\n",
emac_read(EMAC_EMCONTROL), emac_read(EMAC_FIFOCONTROL));
dev_info(emac_dev, "EMAC: MBPEnable:%08X, RXUnicastSet: %08X, "\
@@ -591,8 +399,6 @@ static void emac_dump_regs(struct emac_priv *priv)
dev_info(emac_dev, "EMAC: MacControl:%08X, MacStatus: %08X, "\
"MacConfig=%08X\n", emac_read(EMAC_MACCONTROL),
emac_read(EMAC_MACSTATUS), emac_read(EMAC_MACCONFIG));
- dev_info(emac_dev, "EMAC: TXHDP[0]:%08X, RXHDP[0]: %08X\n",
- emac_read(EMAC_TXHDP(0)), emac_read(EMAC_RXHDP(0)));
dev_info(emac_dev, "EMAC Statistics\n");
dev_info(emac_dev, "EMAC: rx_good_frames:%d\n",
emac_read(EMAC_RXGOODFRAMES));
@@ -654,11 +460,10 @@ static void emac_dump_regs(struct emac_priv *priv)
emac_read(EMAC_RXMOFOVERRUNS));
dev_info(emac_dev, "EMAC: rx_dma_overruns:%d\n",
emac_read(EMAC_RXDMAOVERRUNS));
+
+ cpdma_ctlr_dump(priv->dma);
}
-/*************************************************************************
- * EMAC MDIO/Phy Functionality
- *************************************************************************/
/**
* emac_get_drvinfo: Get EMAC driver information
* @ndev: The DaVinci EMAC network adapter
@@ -686,7 +491,7 @@ static int emac_get_settings(struct net_device *ndev,
struct ethtool_cmd *ecmd)
{
struct emac_priv *priv = netdev_priv(ndev);
- if (priv->phy_mask)
+ if (priv->phydev)
return phy_ethtool_gset(priv->phydev, ecmd);
else
return -EOPNOTSUPP;
@@ -704,7 +509,7 @@ static int emac_get_settings(struct net_device *ndev,
static int emac_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
{
struct emac_priv *priv = netdev_priv(ndev);
- if (priv->phy_mask)
+ if (priv->phydev)
return phy_ethtool_sset(priv->phydev, ecmd);
else
return -EOPNOTSUPP;
@@ -841,7 +646,7 @@ static void emac_update_phystatus(struct emac_priv *priv)
mac_control = emac_read(EMAC_MACCONTROL);
cur_duplex = (mac_control & EMAC_MACCONTROL_FULLDUPLEXEN) ?
DUPLEX_FULL : DUPLEX_HALF;
- if (priv->phy_mask)
+ if (priv->phydev)
new_duplex = priv->phydev->duplex;
else
new_duplex = DUPLEX_FULL;
@@ -1184,371 +989,68 @@ static irqreturn_t emac_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-/** EMAC on-chip buffer descriptor memory
- *
- * WARNING: Please note that the on chip memory is used for both TX and RX
- * buffer descriptor queues and is equally divided between TX and RX desc's
- * If the number of TX or RX descriptors change this memory pointers need
- * to be adjusted. If external memory is allocated then these pointers can
- * pointer to the memory
- *
- */
-#define EMAC_TX_BD_MEM(priv) ((priv)->emac_ctrl_ram)
-#define EMAC_RX_BD_MEM(priv) ((priv)->emac_ctrl_ram + \
- (((priv)->ctrl_ram_size) >> 1))
-
-/**
- * emac_init_txch: TX channel initialization
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: RX channel number
- *
- * Called during device init to setup a TX channel (allocate buffer desc
- * create free pool and keep ready for transmission
- *
- * Returns success(0) or mem alloc failures error code
- */
-static int emac_init_txch(struct emac_priv *priv, u32 ch)
-{
- struct device *emac_dev = &priv->ndev->dev;
- u32 cnt, bd_size;
- void __iomem *mem;
- struct emac_tx_bd __iomem *curr_bd;
- struct emac_txch *txch = NULL;
-
- txch = kzalloc(sizeof(struct emac_txch), GFP_KERNEL);
- if (NULL == txch) {
- dev_err(emac_dev, "DaVinci EMAC: TX Ch mem alloc failed");
- return -ENOMEM;
- }
- priv->txch[ch] = txch;
- txch->service_max = EMAC_DEF_TX_MAX_SERVICE;
- txch->active_queue_head = NULL;
- txch->active_queue_tail = NULL;
- txch->queue_active = 0;
- txch->teardown_pending = 0;
-
- /* allocate memory for TX CPPI channel on a 4 byte boundry */
- txch->tx_complete = kzalloc(txch->service_max * sizeof(u32),
- GFP_KERNEL);
- if (NULL == txch->tx_complete) {
- dev_err(emac_dev, "DaVinci EMAC: Tx service mem alloc failed");
- kfree(txch);
- return -ENOMEM;
- }
-
- /* allocate buffer descriptor pool align every BD on four word
- * boundry for future requirements */
- bd_size = (sizeof(struct emac_tx_bd) + 0xF) & ~0xF;
- txch->num_bd = (priv->ctrl_ram_size >> 1) / bd_size;
- txch->alloc_size = (((bd_size * txch->num_bd) + 0xF) & ~0xF);
-
- /* alloc TX BD memory */
- txch->bd_mem = EMAC_TX_BD_MEM(priv);
- __memzero((void __force *)txch->bd_mem, txch->alloc_size);
-
- /* initialize the BD linked list */
- mem = (void __force __iomem *)
- (((u32 __force) txch->bd_mem + 0xF) & ~0xF);
- txch->bd_pool_head = NULL;
- for (cnt = 0; cnt < txch->num_bd; cnt++) {
- curr_bd = mem + (cnt * bd_size);
- curr_bd->next = txch->bd_pool_head;
- txch->bd_pool_head = curr_bd;
- }
-
- /* reset statistics counters */
- txch->out_of_tx_bd = 0;
- txch->no_active_pkts = 0;
- txch->active_queue_count = 0;
-
- return 0;
-}
-
-/**
- * emac_cleanup_txch: Book-keep function to clean TX channel resources
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: TX channel number
- *
- * Called to clean up TX channel resources
- *
- */
-static void emac_cleanup_txch(struct emac_priv *priv, u32 ch)
+static struct sk_buff *emac_rx_alloc(struct emac_priv *priv)
{
- struct emac_txch *txch = priv->txch[ch];
-
- if (txch) {
- if (txch->bd_mem)
- txch->bd_mem = NULL;
- kfree(txch->tx_complete);
- kfree(txch);
- priv->txch[ch] = NULL;
- }
+ struct sk_buff *skb = dev_alloc_skb(priv->rx_buf_size);
+ if (WARN_ON(!skb))
+ return NULL;
+ skb->dev = priv->ndev;
+ skb_reserve(skb, NET_IP_ALIGN);
+ return skb;
}
-/**
- * emac_net_tx_complete: TX packet completion function
- * @priv: The DaVinci EMAC private adapter structure
- * @net_data_tokens: packet token - skb pointer
- * @num_tokens: number of skb's to free
- * @ch: TX channel number
- *
- * Frees the skb once packet is transmitted
- *
- */
-static int emac_net_tx_complete(struct emac_priv *priv,
- void **net_data_tokens,
- int num_tokens, u32 ch)
+static void emac_rx_handler(void *token, int len, int status)
{
- struct net_device *ndev = priv->ndev;
- u32 cnt;
-
- if (unlikely(num_tokens && netif_queue_stopped(ndev)))
- netif_start_queue(ndev);
- for (cnt = 0; cnt < num_tokens; cnt++) {
- struct sk_buff *skb = (struct sk_buff *)net_data_tokens[cnt];
- if (skb == NULL)
- continue;
- ndev->stats.tx_packets++;
- ndev->stats.tx_bytes += skb->len;
+ struct sk_buff *skb = token;
+ struct net_device *ndev = skb->dev;
+ struct emac_priv *priv = netdev_priv(ndev);
+ struct device *emac_dev = &ndev->dev;
+ int ret;
+
+ /* free and bail if we are shutting down */
+ if (unlikely(!netif_running(ndev))) {
dev_kfree_skb_any(skb);
+ return;
}
- return 0;
-}
-
-/**
- * emac_txch_teardown: TX channel teardown
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: TX channel number
- *
- * Called to teardown TX channel
- *
- */
-static void emac_txch_teardown(struct emac_priv *priv, u32 ch)
-{
- struct device *emac_dev = &priv->ndev->dev;
- u32 teardown_cnt = 0xFFFFFFF0; /* Some high value */
- struct emac_txch *txch = priv->txch[ch];
- struct emac_tx_bd __iomem *curr_bd;
-
- while ((emac_read(EMAC_TXCP(ch)) & EMAC_TEARDOWN_VALUE) !=
- EMAC_TEARDOWN_VALUE) {
- /* wait till tx teardown complete */
- cpu_relax(); /* TODO: check if this helps ... */
- --teardown_cnt;
- if (0 == teardown_cnt) {
- dev_err(emac_dev, "EMAC: TX teardown aborted\n");
- break;
- }
- }
- emac_write(EMAC_TXCP(ch), EMAC_TEARDOWN_VALUE);
-
- /* process sent packets and return skb's to upper layer */
- if (1 == txch->queue_active) {
- curr_bd = txch->active_queue_head;
- while (curr_bd != NULL) {
- dma_unmap_single(emac_dev, curr_bd->buff_ptr,
- curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE,
- DMA_TO_DEVICE);
-
- emac_net_tx_complete(priv, (void __force *)
- &curr_bd->buf_token, 1, ch);
- if (curr_bd != txch->active_queue_tail)
- curr_bd = curr_bd->next;
- else
- break;
- }
- txch->bd_pool_head = txch->active_queue_head;
- txch->active_queue_head =
- txch->active_queue_tail = NULL;
- }
-}
-/**
- * emac_stop_txch: Stop TX channel operation
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: TX channel number
- *
- * Called to stop TX channel operation
- *
- */
-static void emac_stop_txch(struct emac_priv *priv, u32 ch)
-{
- struct emac_txch *txch = priv->txch[ch];
-
- if (txch) {
- txch->teardown_pending = 1;
- emac_write(EMAC_TXTEARDOWN, 0);
- emac_txch_teardown(priv, ch);
- txch->teardown_pending = 0;
- emac_write(EMAC_TXINTMASKCLEAR, BIT(ch));
+ /* recycle on recieve error */
+ if (status < 0) {
+ ndev->stats.rx_errors++;
+ goto recycle;
}
-}
-/**
- * emac_tx_bdproc: TX buffer descriptor (packet) processing
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: TX channel number to process buffer descriptors for
- * @budget: number of packets allowed to process
- * @pending: indication to caller that packets are pending to process
- *
- * Processes TX buffer descriptors after packets are transmitted - checks
- * ownership bit on the TX * descriptor and requeues it to free pool & frees
- * the SKB buffer. Only "budget" number of packets are processed and
- * indication of pending packets provided to the caller
- *
- * Returns number of packets processed
- */
-static int emac_tx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)
-{
- struct device *emac_dev = &priv->ndev->dev;
- unsigned long flags;
- u32 frame_status;
- u32 pkts_processed = 0;
- u32 tx_complete_cnt = 0;
- struct emac_tx_bd __iomem *curr_bd;
- struct emac_txch *txch = priv->txch[ch];
- u32 *tx_complete_ptr = txch->tx_complete;
-
- if (unlikely(1 == txch->teardown_pending)) {
- if (netif_msg_tx_err(priv) && net_ratelimit()) {
- dev_err(emac_dev, "DaVinci EMAC:emac_tx_bdproc: "\
- "teardown pending\n");
- }
- return 0; /* dont handle any pkt completions */
- }
+ /* feed received packet up the stack */
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, ndev);
+ netif_receive_skb(skb);
+ ndev->stats.rx_bytes += len;
+ ndev->stats.rx_packets++;
- ++txch->proc_count;
- spin_lock_irqsave(&priv->tx_lock, flags);
- curr_bd = txch->active_queue_head;
- if (NULL == curr_bd) {
- emac_write(EMAC_TXCP(ch),
- emac_virt_to_phys(txch->last_hw_bdprocessed, priv));
- txch->no_active_pkts++;
- spin_unlock_irqrestore(&priv->tx_lock, flags);
- return 0;
+ /* alloc a new packet for receive */
+ skb = emac_rx_alloc(priv);
+ if (!skb) {
+ if (netif_msg_rx_err(priv) && net_ratelimit())
+ dev_err(emac_dev, "failed rx buffer alloc\n");
+ return;
}
- BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
- frame_status = curr_bd->mode;
- while ((curr_bd) &&
- ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0) &&
- (pkts_processed < budget)) {
- emac_write(EMAC_TXCP(ch), emac_virt_to_phys(curr_bd, priv));
- txch->active_queue_head = curr_bd->next;
- if (frame_status & EMAC_CPPI_EOQ_BIT) {
- if (curr_bd->next) { /* misqueued packet */
- emac_write(EMAC_TXHDP(ch), curr_bd->h_next);
- ++txch->mis_queued_packets;
- } else {
- txch->queue_active = 0; /* end of queue */
- }
- }
- dma_unmap_single(emac_dev, curr_bd->buff_ptr,
- curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE,
- DMA_TO_DEVICE);
-
- *tx_complete_ptr = (u32) curr_bd->buf_token;
- ++tx_complete_ptr;
- ++tx_complete_cnt;
- curr_bd->next = txch->bd_pool_head;
- txch->bd_pool_head = curr_bd;
- --txch->active_queue_count;
- pkts_processed++;
- txch->last_hw_bdprocessed = curr_bd;
- curr_bd = txch->active_queue_head;
- if (curr_bd) {
- BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
- frame_status = curr_bd->mode;
- }
- } /* end of pkt processing loop */
-
- emac_net_tx_complete(priv,
- (void *)&txch->tx_complete[0],
- tx_complete_cnt, ch);
- spin_unlock_irqrestore(&priv->tx_lock, flags);
- return pkts_processed;
+recycle:
+ ret = cpdma_chan_submit(priv->rxchan, skb, skb->data,
+ skb_tailroom(skb), GFP_KERNEL);
+ if (WARN_ON(ret < 0))
+ dev_kfree_skb_any(skb);
}
-#define EMAC_ERR_TX_OUT_OF_BD -1
-
-/**
- * emac_send: EMAC Transmit function (internal)
- * @priv: The DaVinci EMAC private adapter structure
- * @pkt: packet pointer (contains skb ptr)
- * @ch: TX channel number
- *
- * Called by the transmit function to queue the packet in EMAC hardware queue
- *
- * Returns success(0) or error code (typically out of desc's)
- */
-static int emac_send(struct emac_priv *priv, struct emac_netpktobj *pkt, u32 ch)
+static void emac_tx_handler(void *token, int len, int status)
{
- unsigned long flags;
- struct emac_tx_bd __iomem *curr_bd;
- struct emac_txch *txch;
- struct emac_netbufobj *buf_list;
-
- txch = priv->txch[ch];
- buf_list = pkt->buf_list; /* get handle to the buffer array */
-
- /* check packet size and pad if short */
- if (pkt->pkt_length < EMAC_DEF_MIN_ETHPKTSIZE) {
- buf_list->length += (EMAC_DEF_MIN_ETHPKTSIZE - pkt->pkt_length);
- pkt->pkt_length = EMAC_DEF_MIN_ETHPKTSIZE;
- }
+ struct sk_buff *skb = token;
+ struct net_device *ndev = skb->dev;
- spin_lock_irqsave(&priv->tx_lock, flags);
- curr_bd = txch->bd_pool_head;
- if (curr_bd == NULL) {
- txch->out_of_tx_bd++;
- spin_unlock_irqrestore(&priv->tx_lock, flags);
- return EMAC_ERR_TX_OUT_OF_BD;
- }
-
- txch->bd_pool_head = curr_bd->next;
- curr_bd->buf_token = buf_list->buf_token;
- curr_bd->buff_ptr = dma_map_single(&priv->ndev->dev, buf_list->data_ptr,
- buf_list->length, DMA_TO_DEVICE);
- curr_bd->off_b_len = buf_list->length;
- curr_bd->h_next = 0;
- curr_bd->next = NULL;
- curr_bd->mode = (EMAC_CPPI_SOP_BIT | EMAC_CPPI_OWNERSHIP_BIT |
- EMAC_CPPI_EOP_BIT | pkt->pkt_length);
-
- /* flush the packet from cache if write back cache is present */
- BD_CACHE_WRITEBACK_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
-
- /* send the packet */
- if (txch->active_queue_head == NULL) {
- txch->active_queue_head = curr_bd;
- txch->active_queue_tail = curr_bd;
- if (1 != txch->queue_active) {
- emac_write(EMAC_TXHDP(ch),
- emac_virt_to_phys(curr_bd, priv));
- txch->queue_active = 1;
- }
- ++txch->queue_reinit;
- } else {
- register struct emac_tx_bd __iomem *tail_bd;
- register u32 frame_status;
-
- tail_bd = txch->active_queue_tail;
- tail_bd->next = curr_bd;
- txch->active_queue_tail = curr_bd;
- tail_bd = EMAC_VIRT_NOCACHE(tail_bd);
- tail_bd->h_next = (int)emac_virt_to_phys(curr_bd, priv);
- frame_status = tail_bd->mode;
- if (frame_status & EMAC_CPPI_EOQ_BIT) {
- emac_write(EMAC_TXHDP(ch),
- emac_virt_to_phys(curr_bd, priv));
- frame_status &= ~(EMAC_CPPI_EOQ_BIT);
- tail_bd->mode = frame_status;
- ++txch->end_of_queue_add;
- }
- }
- txch->active_queue_count++;
- spin_unlock_irqrestore(&priv->tx_lock, flags);
- return 0;
+ if (unlikely(netif_queue_stopped(ndev)))
+ netif_start_queue(ndev);
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += len;
+ dev_kfree_skb_any(skb);
}
/**
@@ -1565,42 +1067,36 @@ static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct device *emac_dev = &ndev->dev;
int ret_code;
- struct emac_netbufobj tx_buf; /* buffer obj-only single frame support */
- struct emac_netpktobj tx_packet; /* packet object */
struct emac_priv *priv = netdev_priv(ndev);
/* If no link, return */
if (unlikely(!priv->link)) {
if (netif_msg_tx_err(priv) && net_ratelimit())
dev_err(emac_dev, "DaVinci EMAC: No link to transmit");
- return NETDEV_TX_BUSY;
+ goto fail_tx;
+ }
+
+ ret_code = skb_padto(skb, EMAC_DEF_MIN_ETHPKTSIZE);
+ if (unlikely(ret_code < 0)) {
+ if (netif_msg_tx_err(priv) && net_ratelimit())
+ dev_err(emac_dev, "DaVinci EMAC: packet pad failed");
+ goto fail_tx;
}
- /* Build the buffer and packet objects - Since only single fragment is
- * supported, need not set length and token in both packet & object.
- * Doing so for completeness sake & to show that this needs to be done
- * in multifragment case
- */
- tx_packet.buf_list = &tx_buf;
- tx_packet.num_bufs = 1; /* only single fragment supported */
- tx_packet.pkt_length = skb->len;
- tx_packet.pkt_token = (void *)skb;
- tx_buf.length = skb->len;
- tx_buf.buf_token = (void *)skb;
- tx_buf.data_ptr = skb->data;
- ret_code = emac_send(priv, &tx_packet, EMAC_DEF_TX_CH);
+ ret_code = cpdma_chan_submit(priv->txchan, skb, skb->data, skb->len,
+ GFP_KERNEL);
if (unlikely(ret_code != 0)) {
- if (ret_code == EMAC_ERR_TX_OUT_OF_BD) {
- if (netif_msg_tx_err(priv) && net_ratelimit())
- dev_err(emac_dev, "DaVinci EMAC: xmit() fatal"\
- " err. Out of TX BD's");
- netif_stop_queue(priv->ndev);
- }
- ndev->stats.tx_dropped++;
- return NETDEV_TX_BUSY;
+ if (netif_msg_tx_err(priv) && net_ratelimit())
+ dev_err(emac_dev, "DaVinci EMAC: desc submit failed");
+ goto fail_tx;
}
return NETDEV_TX_OK;
+
+fail_tx:
+ ndev->stats.tx_dropped++;
+ netif_stop_queue(ndev);
+ return NETDEV_TX_BUSY;
}
/**
@@ -1621,218 +1117,16 @@ static void emac_dev_tx_timeout(struct net_device *ndev)
if (netif_msg_tx_err(priv))
dev_err(emac_dev, "DaVinci EMAC: xmit timeout, restarting TX");
+ emac_dump_regs(priv);
+
ndev->stats.tx_errors++;
emac_int_disable(priv);
- emac_stop_txch(priv, EMAC_DEF_TX_CH);
- emac_cleanup_txch(priv, EMAC_DEF_TX_CH);
- emac_init_txch(priv, EMAC_DEF_TX_CH);
- emac_write(EMAC_TXHDP(0), 0);
- emac_write(EMAC_TXINTMASKSET, BIT(EMAC_DEF_TX_CH));
+ cpdma_chan_stop(priv->txchan);
+ cpdma_chan_start(priv->txchan);
emac_int_enable(priv);
}
/**
- * emac_net_alloc_rx_buf: Allocate a skb for RX
- * @priv: The DaVinci EMAC private adapter structure
- * @buf_size: size of SKB data buffer to allocate
- * @data_token: data token returned (skb handle for storing in buffer desc)
- * @ch: RX channel number
- *
- * Called during RX channel setup - allocates skb buffer of required size
- * and provides the skb handle and allocated buffer data pointer to caller
- *
- * Returns skb data pointer or 0 on failure to alloc skb
- */
-static void *emac_net_alloc_rx_buf(struct emac_priv *priv, int buf_size,
- void **data_token, u32 ch)
-{
- struct net_device *ndev = priv->ndev;
- struct device *emac_dev = &ndev->dev;
- struct sk_buff *p_skb;
-
- p_skb = dev_alloc_skb(buf_size);
- if (unlikely(NULL == p_skb)) {
- if (netif_msg_rx_err(priv) && net_ratelimit())
- dev_err(emac_dev, "DaVinci EMAC: failed to alloc skb");
- return NULL;
- }
-
- /* set device pointer in skb and reserve space for extra bytes */
- p_skb->dev = ndev;
- skb_reserve(p_skb, NET_IP_ALIGN);
- *data_token = (void *) p_skb;
- return p_skb->data;
-}
-
-/**
- * emac_init_rxch: RX channel initialization
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: RX channel number
- * @param: mac address for RX channel
- *
- * Called during device init to setup a RX channel (allocate buffers and
- * buffer descriptors, create queue and keep ready for reception
- *
- * Returns success(0) or mem alloc failures error code
- */
-static int emac_init_rxch(struct emac_priv *priv, u32 ch, char *param)
-{
- struct device *emac_dev = &priv->ndev->dev;
- u32 cnt, bd_size;
- void __iomem *mem;
- struct emac_rx_bd __iomem *curr_bd;
- struct emac_rxch *rxch = NULL;
-
- rxch = kzalloc(sizeof(struct emac_rxch), GFP_KERNEL);
- if (NULL == rxch) {
- dev_err(emac_dev, "DaVinci EMAC: RX Ch mem alloc failed");
- return -ENOMEM;
- }
- priv->rxch[ch] = rxch;
- rxch->buf_size = priv->rx_buf_size;
- rxch->service_max = EMAC_DEF_RX_MAX_SERVICE;
- rxch->queue_active = 0;
- rxch->teardown_pending = 0;
-
- /* save mac address */
- for (cnt = 0; cnt < 6; cnt++)
- rxch->mac_addr[cnt] = param[cnt];
-
- /* allocate buffer descriptor pool align every BD on four word
- * boundry for future requirements */
- bd_size = (sizeof(struct emac_rx_bd) + 0xF) & ~0xF;
- rxch->num_bd = (priv->ctrl_ram_size >> 1) / bd_size;
- rxch->alloc_size = (((bd_size * rxch->num_bd) + 0xF) & ~0xF);
- rxch->bd_mem = EMAC_RX_BD_MEM(priv);
- __memzero((void __force *)rxch->bd_mem, rxch->alloc_size);
- rxch->pkt_queue.buf_list = &rxch->buf_queue;
-
- /* allocate RX buffer and initialize the BD linked list */
- mem = (void __force __iomem *)
- (((u32 __force) rxch->bd_mem + 0xF) & ~0xF);
- rxch->active_queue_head = NULL;
- rxch->active_queue_tail = mem;
- for (cnt = 0; cnt < rxch->num_bd; cnt++) {
- curr_bd = mem + (cnt * bd_size);
- /* for future use the last parameter contains the BD ptr */
- curr_bd->data_ptr = emac_net_alloc_rx_buf(priv,
- rxch->buf_size,
- (void __force **)&curr_bd->buf_token,
- EMAC_DEF_RX_CH);
- if (curr_bd->data_ptr == NULL) {
- dev_err(emac_dev, "DaVinci EMAC: RX buf mem alloc " \
- "failed for ch %d\n", ch);
- kfree(rxch);
- return -ENOMEM;
- }
-
- /* populate the hardware descriptor */
- curr_bd->h_next = emac_virt_to_phys(rxch->active_queue_head,
- priv);
- curr_bd->buff_ptr = dma_map_single(emac_dev, curr_bd->data_ptr,
- rxch->buf_size, DMA_FROM_DEVICE);
- curr_bd->off_b_len = rxch->buf_size;
- curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT;
-
- /* write back to hardware memory */
- BD_CACHE_WRITEBACK_INVALIDATE((u32) curr_bd,
- EMAC_BD_LENGTH_FOR_CACHE);
- curr_bd->next = rxch->active_queue_head;
- rxch->active_queue_head = curr_bd;
- }
-
- /* At this point rxCppi->activeQueueHead points to the first
- RX BD ready to be given to RX HDP and rxch->active_queue_tail
- points to the last RX BD
- */
- return 0;
-}
-
-/**
- * emac_rxch_teardown: RX channel teardown
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: RX channel number
- *
- * Called during device stop to teardown RX channel
- *
- */
-static void emac_rxch_teardown(struct emac_priv *priv, u32 ch)
-{
- struct device *emac_dev = &priv->ndev->dev;
- u32 teardown_cnt = 0xFFFFFFF0; /* Some high value */
-
- while ((emac_read(EMAC_RXCP(ch)) & EMAC_TEARDOWN_VALUE) !=
- EMAC_TEARDOWN_VALUE) {
- /* wait till tx teardown complete */
- cpu_relax(); /* TODO: check if this helps ... */
- --teardown_cnt;
- if (0 == teardown_cnt) {
- dev_err(emac_dev, "EMAC: RX teardown aborted\n");
- break;
- }
- }
- emac_write(EMAC_RXCP(ch), EMAC_TEARDOWN_VALUE);
-}
-
-/**
- * emac_stop_rxch: Stop RX channel operation
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: RX channel number
- *
- * Called during device stop to stop RX channel operation
- *
- */
-static void emac_stop_rxch(struct emac_priv *priv, u32 ch)
-{
- struct emac_rxch *rxch = priv->rxch[ch];
-
- if (rxch) {
- rxch->teardown_pending = 1;
- emac_write(EMAC_RXTEARDOWN, ch);
- /* wait for teardown complete */
- emac_rxch_teardown(priv, ch);
- rxch->teardown_pending = 0;
- emac_write(EMAC_RXINTMASKCLEAR, BIT(ch));
- }
-}
-
-/**
- * emac_cleanup_rxch: Book-keep function to clean RX channel resources
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: RX channel number
- *
- * Called during device stop to clean up RX channel resources
- *
- */
-static void emac_cleanup_rxch(struct emac_priv *priv, u32 ch)
-{
- struct emac_rxch *rxch = priv->rxch[ch];
- struct emac_rx_bd __iomem *curr_bd;
-
- if (rxch) {
- /* free the receive buffers previously allocated */
- curr_bd = rxch->active_queue_head;
- while (curr_bd) {
- if (curr_bd->buf_token) {
- dma_unmap_single(&priv->ndev->dev,
- curr_bd->buff_ptr,
- curr_bd->off_b_len
- & EMAC_RX_BD_BUF_SIZE,
- DMA_FROM_DEVICE);
-
- dev_kfree_skb_any((struct sk_buff *)\
- curr_bd->buf_token);
- }
- curr_bd = curr_bd->next;
- }
- if (rxch->bd_mem)
- rxch->bd_mem = NULL;
- kfree(rxch);
- priv->rxch[ch] = NULL;
- }
-}
-
-/**
* emac_set_type0addr: Set EMAC Type0 mac address
* @priv: The DaVinci EMAC private adapter structure
* @ch: RX channel number
@@ -1948,7 +1242,6 @@ static void emac_setmac(struct emac_priv *priv, u32 ch, char *mac_addr)
static int emac_dev_setmac_addr(struct net_device *ndev, void *addr)
{
struct emac_priv *priv = netdev_priv(ndev);
- struct emac_rxch *rxch = priv->rxch[EMAC_DEF_RX_CH];
struct device *emac_dev = &priv->ndev->dev;
struct sockaddr *sa = addr;
@@ -1959,11 +1252,10 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr)
memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len);
memcpy(ndev->dev_addr, sa->sa_data, ndev->addr_len);
- /* If the interface is down - rxch is NULL. */
/* MAC address is configured only after the interface is enabled. */
if (netif_running(ndev)) {
- memcpy(rxch->mac_addr, sa->sa_data, ndev->addr_len);
- emac_setmac(priv, EMAC_DEF_RX_CH, rxch->mac_addr);
+ memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len);
+ emac_setmac(priv, EMAC_DEF_RX_CH, priv->mac_addr);
}
if (netif_msg_drv(priv))
@@ -1974,194 +1266,6 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr)
}
/**
- * emac_addbd_to_rx_queue: Recycle RX buffer descriptor
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: RX channel number to process buffer descriptors for
- * @curr_bd: current buffer descriptor
- * @buffer: buffer pointer for descriptor
- * @buf_token: buffer token (stores skb information)
- *
- * Prepares the recycled buffer descriptor and addes it to hardware
- * receive queue - if queue empty this descriptor becomes the head
- * else addes the descriptor to end of queue
- *
- */
-static void emac_addbd_to_rx_queue(struct emac_priv *priv, u32 ch,
- struct emac_rx_bd __iomem *curr_bd,
- char *buffer, void *buf_token)
-{
- struct emac_rxch *rxch = priv->rxch[ch];
-
- /* populate the hardware descriptor */
- curr_bd->h_next = 0;
- curr_bd->buff_ptr = dma_map_single(&priv->ndev->dev, buffer,
- rxch->buf_size, DMA_FROM_DEVICE);
- curr_bd->off_b_len = rxch->buf_size;
- curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT;
- curr_bd->next = NULL;
- curr_bd->data_ptr = buffer;
- curr_bd->buf_token = buf_token;
-
- /* write back */
- BD_CACHE_WRITEBACK_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
- if (rxch->active_queue_head == NULL) {
- rxch->active_queue_head = curr_bd;
- rxch->active_queue_tail = curr_bd;
- if (0 != rxch->queue_active) {
- emac_write(EMAC_RXHDP(ch),
- emac_virt_to_phys(rxch->active_queue_head, priv));
- rxch->queue_active = 1;
- }
- } else {
- struct emac_rx_bd __iomem *tail_bd;
- u32 frame_status;
-
- tail_bd = rxch->active_queue_tail;
- rxch->active_queue_tail = curr_bd;
- tail_bd->next = curr_bd;
- tail_bd = EMAC_VIRT_NOCACHE(tail_bd);
- tail_bd->h_next = emac_virt_to_phys(curr_bd, priv);
- frame_status = tail_bd->mode;
- if (frame_status & EMAC_CPPI_EOQ_BIT) {
- emac_write(EMAC_RXHDP(ch),
- emac_virt_to_phys(curr_bd, priv));
- frame_status &= ~(EMAC_CPPI_EOQ_BIT);
- tail_bd->mode = frame_status;
- ++rxch->end_of_queue_add;
- }
- }
- ++rxch->recycled_bd;
-}
-
-/**
- * emac_net_rx_cb: Prepares packet and sends to upper layer
- * @priv: The DaVinci EMAC private adapter structure
- * @net_pkt_list: Network packet list (received packets)
- *
- * Invalidates packet buffer memory and sends the received packet to upper
- * layer
- *
- * Returns success or appropriate error code (none as of now)
- */
-static int emac_net_rx_cb(struct emac_priv *priv,
- struct emac_netpktobj *net_pkt_list)
-{
- struct net_device *ndev = priv->ndev;
- struct sk_buff *p_skb = net_pkt_list->pkt_token;
- /* set length of packet */
- skb_put(p_skb, net_pkt_list->pkt_length);
- p_skb->protocol = eth_type_trans(p_skb, priv->ndev);
- netif_receive_skb(p_skb);
- ndev->stats.rx_bytes += net_pkt_list->pkt_length;
- ndev->stats.rx_packets++;
- return 0;
-}
-
-/**
- * emac_rx_bdproc: RX buffer descriptor (packet) processing
- * @priv: The DaVinci EMAC private adapter structure
- * @ch: RX channel number to process buffer descriptors for
- * @budget: number of packets allowed to process
- * @pending: indication to caller that packets are pending to process
- *
- * Processes RX buffer descriptors - checks ownership bit on the RX buffer
- * descriptor, sends the receive packet to upper layer, allocates a new SKB
- * and recycles the buffer descriptor (requeues it in hardware RX queue).
- * Only "budget" number of packets are processed and indication of pending
- * packets provided to the caller.
- *
- * Returns number of packets processed (and indication of pending packets)
- */
-static int emac_rx_bdproc(struct emac_priv *priv, u32 ch, u32 budget)
-{
- unsigned long flags;
- u32 frame_status;
- u32 pkts_processed = 0;
- char *new_buffer;
- struct emac_rx_bd __iomem *curr_bd;
- struct emac_rx_bd __iomem *last_bd;
- struct emac_netpktobj *curr_pkt, pkt_obj;
- struct emac_netbufobj buf_obj;
- struct emac_netbufobj *rx_buf_obj;
- void *new_buf_token;
- struct emac_rxch *rxch = priv->rxch[ch];
-
- if (unlikely(1 == rxch->teardown_pending))
- return 0;
- ++rxch->proc_count;
- spin_lock_irqsave(&priv->rx_lock, flags);
- pkt_obj.buf_list = &buf_obj;
- curr_pkt = &pkt_obj;
- curr_bd = rxch->active_queue_head;
- BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
- frame_status = curr_bd->mode;
-
- while ((curr_bd) &&
- ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0) &&
- (pkts_processed < budget)) {
-
- new_buffer = emac_net_alloc_rx_buf(priv, rxch->buf_size,
- &new_buf_token, EMAC_DEF_RX_CH);
- if (unlikely(NULL == new_buffer)) {
- ++rxch->out_of_rx_buffers;
- goto end_emac_rx_bdproc;
- }
-
- /* populate received packet data structure */
- rx_buf_obj = &curr_pkt->buf_list[0];
- rx_buf_obj->data_ptr = (char *)curr_bd->data_ptr;
- rx_buf_obj->length = curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE;
- rx_buf_obj->buf_token = curr_bd->buf_token;
-
- dma_unmap_single(&priv->ndev->dev, curr_bd->buff_ptr,
- curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE,
- DMA_FROM_DEVICE);
-
- curr_pkt->pkt_token = curr_pkt->buf_list->buf_token;
- curr_pkt->num_bufs = 1;
- curr_pkt->pkt_length =
- (frame_status & EMAC_RX_BD_PKT_LENGTH_MASK);
- emac_write(EMAC_RXCP(ch), emac_virt_to_phys(curr_bd, priv));
- ++rxch->processed_bd;
- last_bd = curr_bd;
- curr_bd = last_bd->next;
- rxch->active_queue_head = curr_bd;
-
- /* check if end of RX queue ? */
- if (frame_status & EMAC_CPPI_EOQ_BIT) {
- if (curr_bd) {
- ++rxch->mis_queued_packets;
- emac_write(EMAC_RXHDP(ch),
- emac_virt_to_phys(curr_bd, priv));
- } else {
- ++rxch->end_of_queue;
- rxch->queue_active = 0;
- }
- }
-
- /* recycle BD */
- emac_addbd_to_rx_queue(priv, ch, last_bd, new_buffer,
- new_buf_token);
-
- /* return the packet to the user - BD ptr passed in
- * last parameter for potential *future* use */
- spin_unlock_irqrestore(&priv->rx_lock, flags);
- emac_net_rx_cb(priv, curr_pkt);
- spin_lock_irqsave(&priv->rx_lock, flags);
- curr_bd = rxch->active_queue_head;
- if (curr_bd) {
- BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
- frame_status = curr_bd->mode;
- }
- ++pkts_processed;
- }
-
-end_emac_rx_bdproc:
- spin_unlock_irqrestore(&priv->rx_lock, flags);
- return pkts_processed;
-}
-
-/**
* emac_hw_enable: Enable EMAC hardware for packet transmission/reception
* @priv: The DaVinci EMAC private adapter structure
*
@@ -2172,7 +1276,7 @@ end_emac_rx_bdproc:
*/
static int emac_hw_enable(struct emac_priv *priv)
{
- u32 ch, val, mbp_enable, mac_control;
+ u32 val, mbp_enable, mac_control;
/* Soft reset */
emac_write(EMAC_SOFTRESET, 1);
@@ -2215,26 +1319,9 @@ static int emac_hw_enable(struct emac_priv *priv)
emac_write(EMAC_RXUNICASTCLEAR, EMAC_RX_UNICAST_CLEAR_ALL);
priv->rx_addr_type = (emac_read(EMAC_MACCONFIG) >> 8) & 0xFF;
- val = emac_read(EMAC_TXCONTROL);
- val |= EMAC_TX_CONTROL_TX_ENABLE_VAL;
- emac_write(EMAC_TXCONTROL, val);
- val = emac_read(EMAC_RXCONTROL);
- val |= EMAC_RX_CONTROL_RX_ENABLE_VAL;
- emac_write(EMAC_RXCONTROL, val);
emac_write(EMAC_MACINTMASKSET, EMAC_MAC_HOST_ERR_INTMASK_VAL);
- for (ch = 0; ch < EMAC_DEF_MAX_TX_CH; ch++) {
- emac_write(EMAC_TXHDP(ch), 0);
- emac_write(EMAC_TXINTMASKSET, BIT(ch));
- }
- for (ch = 0; ch < EMAC_DEF_MAX_RX_CH; ch++) {
- struct emac_rxch *rxch = priv->rxch[ch];
- emac_setmac(priv, ch, rxch->mac_addr);
- emac_write(EMAC_RXINTMASKSET, BIT(ch));
- rxch->queue_active = 1;
- emac_write(EMAC_RXHDP(ch),
- emac_virt_to_phys(rxch->active_queue_head, priv));
- }
+ emac_setmac(priv, EMAC_DEF_RX_CH, priv->mac_addr);
/* Enable MII */
val = emac_read(EMAC_MACCONTROL);
@@ -2279,8 +1366,8 @@ static int emac_poll(struct napi_struct *napi, int budget)
mask = EMAC_DM646X_MAC_IN_VECTOR_TX_INT_VEC;
if (status & mask) {
- num_tx_pkts = emac_tx_bdproc(priv, EMAC_DEF_TX_CH,
- EMAC_DEF_TX_MAX_SERVICE);
+ num_tx_pkts = cpdma_chan_process(priv->txchan,
+ EMAC_DEF_TX_MAX_SERVICE);
} /* TX processing */
mask = EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC;
@@ -2289,7 +1376,7 @@ static int emac_poll(struct napi_struct *napi, int budget)
mask = EMAC_DM646X_MAC_IN_VECTOR_RX_INT_VEC;
if (status & mask) {
- num_rx_pkts = emac_rx_bdproc(priv, EMAC_DEF_RX_CH, budget);
+ num_rx_pkts = cpdma_chan_process(priv->rxchan, budget);
} /* RX processing */
mask = EMAC_DM644X_MAC_IN_VECTOR_HOST_INT;
@@ -2348,79 +1435,6 @@ void emac_poll_controller(struct net_device *ndev)
}
#endif
-/* PHY/MII bus related */
-
-/* Wait until mdio is ready for next command */
-#define MDIO_WAIT_FOR_USER_ACCESS\
- while ((emac_mdio_read((MDIO_USERACCESS(0))) &\
- MDIO_USERACCESS_GO) != 0)
-
-static int emac_mii_read(struct mii_bus *bus, int phy_id, int phy_reg)
-{
- unsigned int phy_data = 0;
- unsigned int phy_control;
-
- /* Wait until mdio is ready for next command */
- MDIO_WAIT_FOR_USER_ACCESS;
-
- phy_control = (MDIO_USERACCESS_GO |
- MDIO_USERACCESS_READ |
- ((phy_reg << 21) & MDIO_USERACCESS_REGADR) |
- ((phy_id << 16) & MDIO_USERACCESS_PHYADR) |
- (phy_data & MDIO_USERACCESS_DATA));
- emac_mdio_write(MDIO_USERACCESS(0), phy_control);
-
- /* Wait until mdio is ready for next command */
- MDIO_WAIT_FOR_USER_ACCESS;
-
- return emac_mdio_read(MDIO_USERACCESS(0)) & MDIO_USERACCESS_DATA;
-
-}
-
-static int emac_mii_write(struct mii_bus *bus, int phy_id,
- int phy_reg, u16 phy_data)
-{
-
- unsigned int control;
-
- /* until mdio is ready for next command */
- MDIO_WAIT_FOR_USER_ACCESS;
-
- control = (MDIO_USERACCESS_GO |
- MDIO_USERACCESS_WRITE |
- ((phy_reg << 21) & MDIO_USERACCESS_REGADR) |
- ((phy_id << 16) & MDIO_USERACCESS_PHYADR) |
- (phy_data & MDIO_USERACCESS_DATA));
- emac_mdio_write(MDIO_USERACCESS(0), control);
-
- return 0;
-}
-
-static int emac_mii_reset(struct mii_bus *bus)
-{
- unsigned int clk_div;
- int mdio_bus_freq = emac_bus_frequency;
-
- if (mdio_max_freq && mdio_bus_freq)
- clk_div = ((mdio_bus_freq / mdio_max_freq) - 1);
- else
- clk_div = 0xFF;
-
- clk_div &= MDIO_CONTROL_CLKDIV;
-
- /* Set enable and clock divider in MDIOControl */
- emac_mdio_write(MDIO_CONTROL, (clk_div | MDIO_CONTROL_ENABLE));
-
- return 0;
-
-}
-
-static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, PHY_POLL };
-
-/* emac_driver: EMAC MII bus structure */
-
-static struct mii_bus *emac_mii;
-
static void emac_adjust_link(struct net_device *ndev)
{
struct emac_priv *priv = netdev_priv(ndev);
@@ -2485,6 +1499,11 @@ static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd)
return -EOPNOTSUPP;
}
+static int match_first_device(struct device *dev, void *data)
+{
+ return 1;
+}
+
/**
* emac_dev_open: EMAC device open
* @ndev: The DaVinci EMAC network adapter
@@ -2498,10 +1517,9 @@ static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd)
static int emac_dev_open(struct net_device *ndev)
{
struct device *emac_dev = &ndev->dev;
- u32 rc, cnt, ch;
- int phy_addr;
+ u32 cnt;
struct resource *res;
- int q, m;
+ int q, m, ret;
int i = 0;
int k = 0;
struct emac_priv *priv = netdev_priv(ndev);
@@ -2513,29 +1531,21 @@ static int emac_dev_open(struct net_device *ndev)
/* Configuration items */
priv->rx_buf_size = EMAC_DEF_MAX_FRAME_SIZE + NET_IP_ALIGN;
- /* Clear basic hardware */
- for (ch = 0; ch < EMAC_MAX_TXRX_CHANNELS; ch++) {
- emac_write(EMAC_TXHDP(ch), 0);
- emac_write(EMAC_RXHDP(ch), 0);
- emac_write(EMAC_RXHDP(ch), 0);
- emac_write(EMAC_RXINTMASKCLEAR, EMAC_INT_MASK_CLEAR);
- emac_write(EMAC_TXINTMASKCLEAR, EMAC_INT_MASK_CLEAR);
- }
priv->mac_hash1 = 0;
priv->mac_hash2 = 0;
emac_write(EMAC_MACHASH1, 0);
emac_write(EMAC_MACHASH2, 0);
- /* multi ch not supported - open 1 TX, 1RX ch by default */
- rc = emac_init_txch(priv, EMAC_DEF_TX_CH);
- if (0 != rc) {
- dev_err(emac_dev, "DaVinci EMAC: emac_init_txch() failed");
- return rc;
- }
- rc = emac_init_rxch(priv, EMAC_DEF_RX_CH, priv->mac_addr);
- if (0 != rc) {
- dev_err(emac_dev, "DaVinci EMAC: emac_init_rxch() failed");
- return rc;
+ for (i = 0; i < EMAC_DEF_RX_NUM_DESC; i++) {
+ struct sk_buff *skb = emac_rx_alloc(priv);
+
+ if (!skb)
+ break;
+
+ ret = cpdma_chan_submit(priv->rxchan, skb, skb->data,
+ skb_tailroom(skb), GFP_KERNEL);
+ if (WARN_ON(ret < 0))
+ break;
}
/* Request IRQ */
@@ -2560,28 +1570,28 @@ static int emac_dev_open(struct net_device *ndev)
emac_set_coalesce(ndev, &coal);
}
- /* find the first phy */
+ cpdma_ctlr_start(priv->dma);
+
priv->phydev = NULL;
- if (priv->phy_mask) {
- emac_mii_reset(priv->mii_bus);
- for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
- if (priv->mii_bus->phy_map[phy_addr]) {
- priv->phydev = priv->mii_bus->phy_map[phy_addr];
- break;
- }
- }
+ /* use the first phy on the bus if pdata did not give us a phy id */
+ if (!priv->phy_id) {
+ struct device *phy;
- if (!priv->phydev) {
- printk(KERN_ERR "%s: no PHY found\n", ndev->name);
- return -1;
- }
+ phy = bus_find_device(&mdio_bus_type, NULL, NULL,
+ match_first_device);
+ if (phy)
+ priv->phy_id = dev_name(phy);
+ }
- priv->phydev = phy_connect(ndev, dev_name(&priv->phydev->dev),
- &emac_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+ if (priv->phy_id && *priv->phy_id) {
+ priv->phydev = phy_connect(ndev, priv->phy_id,
+ &emac_adjust_link, 0,
+ PHY_INTERFACE_MODE_MII);
if (IS_ERR(priv->phydev)) {
- printk(KERN_ERR "%s: Could not attach to PHY\n",
- ndev->name);
+ dev_err(emac_dev, "could not connect to phy %s\n",
+ priv->phy_id);
+ priv->phydev = NULL;
return PTR_ERR(priv->phydev);
}
@@ -2589,12 +1599,13 @@ static int emac_dev_open(struct net_device *ndev)
priv->speed = 0;
priv->duplex = ~0;
- printk(KERN_INFO "%s: attached PHY driver [%s] "
- "(mii_bus:phy_addr=%s, id=%x)\n", ndev->name,
+ dev_info(emac_dev, "attached PHY driver [%s] "
+ "(mii_bus:phy_addr=%s, id=%x)\n",
priv->phydev->drv->name, dev_name(&priv->phydev->dev),
priv->phydev->phy_id);
- } else{
+ } else {
/* No PHY , fix the link, speed and duplex settings */
+ dev_notice(emac_dev, "no phy, defaulting to 100/full\n");
priv->link = 1;
priv->speed = SPEED_100;
priv->duplex = DUPLEX_FULL;
@@ -2607,7 +1618,7 @@ static int emac_dev_open(struct net_device *ndev)
if (netif_msg_drv(priv))
dev_notice(emac_dev, "DaVinci EMAC: Opened %s\n", ndev->name);
- if (priv->phy_mask)
+ if (priv->phydev)
phy_start(priv->phydev);
return 0;
@@ -2648,10 +1659,7 @@ static int emac_dev_stop(struct net_device *ndev)
netif_carrier_off(ndev);
emac_int_disable(priv);
- emac_stop_txch(priv, EMAC_DEF_TX_CH);
- emac_stop_rxch(priv, EMAC_DEF_RX_CH);
- emac_cleanup_txch(priv, EMAC_DEF_TX_CH);
- emac_cleanup_rxch(priv, EMAC_DEF_RX_CH);
+ cpdma_ctlr_stop(priv->dma);
emac_write(EMAC_SOFTRESET, 1);
if (priv->phydev)
@@ -2756,9 +1764,10 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
struct resource *res;
struct net_device *ndev;
struct emac_priv *priv;
- unsigned long size;
+ unsigned long size, hw_ram_addr;
struct emac_platform_data *pdata;
struct device *emac_dev;
+ struct cpdma_params dma_params;
/* obtain emac clock from kernel */
emac_clk = clk_get(&pdev->dev, NULL);
@@ -2782,8 +1791,6 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
priv->ndev = ndev;
priv->msg_enable = netif_msg_init(debug_level, DAVINCI_EMAC_DEBUG);
- spin_lock_init(&priv->tx_lock);
- spin_lock_init(&priv->rx_lock);
spin_lock_init(&priv->lock);
pdata = pdev->dev.platform_data;
@@ -2794,7 +1801,7 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
/* MAC addr and PHY mask , RMII enable info from platform_data */
memcpy(priv->mac_addr, pdata->mac_addr, 6);
- priv->phy_mask = pdata->phy_mask;
+ priv->phy_id = pdata->phy_id;
priv->rmii_en = pdata->rmii_en;
priv->version = pdata->version;
priv->int_enable = pdata->interrupt_enable;
@@ -2831,14 +1838,41 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
ndev->base_addr = (unsigned long)priv->remap_addr;
priv->ctrl_base = priv->remap_addr + pdata->ctrl_mod_reg_offset;
- priv->ctrl_ram_size = pdata->ctrl_ram_size;
- priv->emac_ctrl_ram = priv->remap_addr + pdata->ctrl_ram_offset;
- if (pdata->hw_ram_addr)
- priv->hw_ram_addr = pdata->hw_ram_addr;
- else
- priv->hw_ram_addr = (u32 __force)res->start +
- pdata->ctrl_ram_offset;
+ hw_ram_addr = pdata->hw_ram_addr;
+ if (!hw_ram_addr)
+ hw_ram_addr = (u32 __force)res->start + pdata->ctrl_ram_offset;
+
+ memset(&dma_params, 0, sizeof(dma_params));
+ dma_params.dev = emac_dev;
+ dma_params.dmaregs = priv->emac_base;
+ dma_params.rxthresh = priv->emac_base + 0x120;
+ dma_params.rxfree = priv->emac_base + 0x140;
+ dma_params.txhdp = priv->emac_base + 0x600;
+ dma_params.rxhdp = priv->emac_base + 0x620;
+ dma_params.txcp = priv->emac_base + 0x640;
+ dma_params.rxcp = priv->emac_base + 0x660;
+ dma_params.num_chan = EMAC_MAX_TXRX_CHANNELS;
+ dma_params.min_packet_size = EMAC_DEF_MIN_ETHPKTSIZE;
+ dma_params.desc_mem_phys = hw_ram_addr;
+ dma_params.desc_mem_size = pdata->ctrl_ram_size;
+ dma_params.desc_align = 16;
+
+ priv->dma = cpdma_ctlr_create(&dma_params);
+ if (!priv->dma) {
+ dev_err(emac_dev, "DaVinci EMAC: Error initializing DMA\n");
+ rc = -ENOMEM;
+ goto no_dma;
+ }
+
+ priv->txchan = cpdma_chan_create(priv->dma, tx_chan_num(EMAC_DEF_TX_CH),
+ emac_tx_handler);
+ priv->rxchan = cpdma_chan_create(priv->dma, rx_chan_num(EMAC_DEF_RX_CH),
+ emac_rx_handler);
+ if (WARN_ON(!priv->txchan || !priv->rxchan)) {
+ rc = -ENOMEM;
+ goto no_irq_res;
+ }
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
@@ -2871,32 +1905,6 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
}
- /* MII/Phy intialisation, mdio bus registration */
- emac_mii = mdiobus_alloc();
- if (emac_mii == NULL) {
- dev_err(emac_dev, "DaVinci EMAC: Error allocating mii_bus\n");
- rc = -ENOMEM;
- goto mdio_alloc_err;
- }
-
- priv->mii_bus = emac_mii;
- emac_mii->name = "emac-mii",
- emac_mii->read = emac_mii_read,
- emac_mii->write = emac_mii_write,
- emac_mii->reset = emac_mii_reset,
- emac_mii->irq = mii_irqs,
- emac_mii->phy_mask = ~(priv->phy_mask);
- emac_mii->parent = &pdev->dev;
- emac_mii->priv = priv->remap_addr + pdata->mdio_reg_offset;
- snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", priv->pdev->id);
- mdio_max_freq = pdata->mdio_max_freq;
- emac_mii->reset(emac_mii);
-
- /* Register the MII bus */
- rc = mdiobus_register(emac_mii);
- if (rc)
- goto mdiobus_quit;
-
if (netif_msg_probe(priv)) {
dev_notice(emac_dev, "DaVinci EMAC Probe found device "\
"(regs: %p, irq: %d)\n",
@@ -2904,13 +1912,15 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
}
return 0;
-mdiobus_quit:
- mdiobus_free(emac_mii);
-
netdev_reg_err:
-mdio_alloc_err:
clk_disable(emac_clk);
no_irq_res:
+ if (priv->txchan)
+ cpdma_chan_destroy(priv->txchan);
+ if (priv->rxchan)
+ cpdma_chan_destroy(priv->rxchan);
+ cpdma_ctlr_destroy(priv->dma);
+no_dma:
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, res->end - res->start + 1);
iounmap(priv->remap_addr);
@@ -2938,8 +1948,12 @@ static int __devexit davinci_emac_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- mdiobus_unregister(priv->mii_bus);
- mdiobus_free(priv->mii_bus);
+
+ if (priv->txchan)
+ cpdma_chan_destroy(priv->txchan);
+ if (priv->rxchan)
+ cpdma_chan_destroy(priv->rxchan);
+ cpdma_ctlr_destroy(priv->dma);
release_mem_region(res->start, res->end - res->start + 1);
diff --git a/drivers/net/davinci_mdio.c b/drivers/net/davinci_mdio.c
new file mode 100644
index 000000000000..7615040df756
--- /dev/null
+++ b/drivers/net/davinci_mdio.c
@@ -0,0 +1,475 @@
+/*
+ * DaVinci MDIO Module driver
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * Shamelessly ripped out of davinci_emac.c, original copyrights follow:
+ *
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * ---------------------------------------------------------------------------
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/phy.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/davinci_emac.h>
+
+/*
+ * This timeout definition is a worst-case ultra defensive measure against
+ * unexpected controller lock ups. Ideally, we should never ever hit this
+ * scenario in practice.
+ */
+#define MDIO_TIMEOUT 100 /* msecs */
+
+#define PHY_REG_MASK 0x1f
+#define PHY_ID_MASK 0x1f
+
+#define DEF_OUT_FREQ 2200000 /* 2.2 MHz */
+
+struct davinci_mdio_regs {
+ u32 version;
+ u32 control;
+#define CONTROL_IDLE BIT(31)
+#define CONTROL_ENABLE BIT(30)
+#define CONTROL_MAX_DIV (0xff)
+
+ u32 alive;
+ u32 link;
+ u32 linkintraw;
+ u32 linkintmasked;
+ u32 __reserved_0[2];
+ u32 userintraw;
+ u32 userintmasked;
+ u32 userintmaskset;
+ u32 userintmaskclr;
+ u32 __reserved_1[20];
+
+ struct {
+ u32 access;
+#define USERACCESS_GO BIT(31)
+#define USERACCESS_WRITE BIT(30)
+#define USERACCESS_ACK BIT(29)
+#define USERACCESS_READ (0)
+#define USERACCESS_DATA (0xffff)
+
+ u32 physel;
+ } user[0];
+};
+
+struct mdio_platform_data default_pdata = {
+ .bus_freq = DEF_OUT_FREQ,
+};
+
+struct davinci_mdio_data {
+ struct mdio_platform_data pdata;
+ struct davinci_mdio_regs __iomem *regs;
+ spinlock_t lock;
+ struct clk *clk;
+ struct device *dev;
+ struct mii_bus *bus;
+ bool suspended;
+ unsigned long access_time; /* jiffies */
+};
+
+static void __davinci_mdio_reset(struct davinci_mdio_data *data)
+{
+ u32 mdio_in, div, mdio_out_khz, access_time;
+
+ mdio_in = clk_get_rate(data->clk);
+ div = (mdio_in / data->pdata.bus_freq) - 1;
+ if (div > CONTROL_MAX_DIV)
+ div = CONTROL_MAX_DIV;
+
+ /* set enable and clock divider */
+ __raw_writel(div | CONTROL_ENABLE, &data->regs->control);
+
+ /*
+ * One mdio transaction consists of:
+ * 32 bits of preamble
+ * 32 bits of transferred data
+ * 24 bits of bus yield (not needed unless shared?)
+ */
+ mdio_out_khz = mdio_in / (1000 * (div + 1));
+ access_time = (88 * 1000) / mdio_out_khz;
+
+ /*
+ * In the worst case, we could be kicking off a user-access immediately
+ * after the mdio bus scan state-machine triggered its own read. If
+ * so, our request could get deferred by one access cycle. We
+ * defensively allow for 4 access cycles.
+ */
+ data->access_time = usecs_to_jiffies(access_time * 4);
+ if (!data->access_time)
+ data->access_time = 1;
+}
+
+static int davinci_mdio_reset(struct mii_bus *bus)
+{
+ struct davinci_mdio_data *data = bus->priv;
+ u32 phy_mask, ver;
+
+ __davinci_mdio_reset(data);
+
+ /* wait for scan logic to settle */
+ msleep(PHY_MAX_ADDR * data->access_time);
+
+ /* dump hardware version info */
+ ver = __raw_readl(&data->regs->version);
+ dev_info(data->dev, "davinci mdio revision %d.%d\n",
+ (ver >> 8) & 0xff, ver & 0xff);
+
+ /* get phy mask from the alive register */
+ phy_mask = __raw_readl(&data->regs->alive);
+ if (phy_mask) {
+ /* restrict mdio bus to live phys only */
+ dev_info(data->dev, "detected phy mask %x\n", ~phy_mask);
+ phy_mask = ~phy_mask;
+ } else {
+ /* desperately scan all phys */
+ dev_warn(data->dev, "no live phy, scanning all\n");
+ phy_mask = 0;
+ }
+ data->bus->phy_mask = phy_mask;
+
+ return 0;
+}
+
+/* wait until hardware is ready for another user access */
+static inline int wait_for_user_access(struct davinci_mdio_data *data)
+{
+ struct davinci_mdio_regs __iomem *regs = data->regs;
+ unsigned long timeout = jiffies + msecs_to_jiffies(MDIO_TIMEOUT);
+ u32 reg;
+
+ while (time_after(timeout, jiffies)) {
+ reg = __raw_readl(&regs->user[0].access);
+ if ((reg & USERACCESS_GO) == 0)
+ return 0;
+
+ reg = __raw_readl(&regs->control);
+ if ((reg & CONTROL_IDLE) == 0)
+ continue;
+
+ /*
+ * An emac soft_reset may have clobbered the mdio controller's
+ * state machine. We need to reset and retry the current
+ * operation
+ */
+ dev_warn(data->dev, "resetting idled controller\n");
+ __davinci_mdio_reset(data);
+ return -EAGAIN;
+ }
+ dev_err(data->dev, "timed out waiting for user access\n");
+ return -ETIMEDOUT;
+}
+
+/* wait until hardware state machine is idle */
+static inline int wait_for_idle(struct davinci_mdio_data *data)
+{
+ struct davinci_mdio_regs __iomem *regs = data->regs;
+ unsigned long timeout = jiffies + msecs_to_jiffies(MDIO_TIMEOUT);
+
+ while (time_after(timeout, jiffies)) {
+ if (__raw_readl(&regs->control) & CONTROL_IDLE)
+ return 0;
+ }
+ dev_err(data->dev, "timed out waiting for idle\n");
+ return -ETIMEDOUT;
+}
+
+static int davinci_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg)
+{
+ struct davinci_mdio_data *data = bus->priv;
+ u32 reg;
+ int ret;
+
+ if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
+ return -EINVAL;
+
+ spin_lock(&data->lock);
+
+ if (data->suspended) {
+ spin_unlock(&data->lock);
+ return -ENODEV;
+ }
+
+ reg = (USERACCESS_GO | USERACCESS_READ | (phy_reg << 21) |
+ (phy_id << 16));
+
+ while (1) {
+ ret = wait_for_user_access(data);
+ if (ret == -EAGAIN)
+ continue;
+ if (ret < 0)
+ break;
+
+ __raw_writel(reg, &data->regs->user[0].access);
+
+ ret = wait_for_user_access(data);
+ if (ret == -EAGAIN)
+ continue;
+ if (ret < 0)
+ break;
+
+ reg = __raw_readl(&data->regs->user[0].access);
+ ret = (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -EIO;
+ break;
+ }
+
+ spin_unlock(&data->lock);
+
+ return ret;
+}
+
+static int davinci_mdio_write(struct mii_bus *bus, int phy_id,
+ int phy_reg, u16 phy_data)
+{
+ struct davinci_mdio_data *data = bus->priv;
+ u32 reg;
+ int ret;
+
+ if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
+ return -EINVAL;
+
+ spin_lock(&data->lock);
+
+ if (data->suspended) {
+ spin_unlock(&data->lock);
+ return -ENODEV;
+ }
+
+ reg = (USERACCESS_GO | USERACCESS_WRITE | (phy_reg << 21) |
+ (phy_id << 16) | (phy_data & USERACCESS_DATA));
+
+ while (1) {
+ ret = wait_for_user_access(data);
+ if (ret == -EAGAIN)
+ continue;
+ if (ret < 0)
+ break;
+
+ __raw_writel(reg, &data->regs->user[0].access);
+
+ ret = wait_for_user_access(data);
+ if (ret == -EAGAIN)
+ continue;
+ break;
+ }
+
+ spin_unlock(&data->lock);
+
+ return 0;
+}
+
+static int __devinit davinci_mdio_probe(struct platform_device *pdev)
+{
+ struct mdio_platform_data *pdata = pdev->dev.platform_data;
+ struct device *dev = &pdev->dev;
+ struct davinci_mdio_data *data;
+ struct resource *res;
+ struct phy_device *phy;
+ int ret, addr;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(dev, "failed to alloc device data\n");
+ return -ENOMEM;
+ }
+
+ data->pdata = pdata ? (*pdata) : default_pdata;
+
+ data->bus = mdiobus_alloc();
+ if (!data->bus) {
+ dev_err(dev, "failed to alloc mii bus\n");
+ ret = -ENOMEM;
+ goto bail_out;
+ }
+
+ data->bus->name = dev_name(dev);
+ data->bus->read = davinci_mdio_read,
+ data->bus->write = davinci_mdio_write,
+ data->bus->reset = davinci_mdio_reset,
+ data->bus->parent = dev;
+ data->bus->priv = data;
+ snprintf(data->bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
+
+ data->clk = clk_get(dev, NULL);
+ if (IS_ERR(data->clk)) {
+ data->clk = NULL;
+ dev_err(dev, "failed to get device clock\n");
+ ret = PTR_ERR(data->clk);
+ goto bail_out;
+ }
+
+ clk_enable(data->clk);
+
+ dev_set_drvdata(dev, data);
+ data->dev = dev;
+ spin_lock_init(&data->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "could not find register map resource\n");
+ ret = -ENOENT;
+ goto bail_out;
+ }
+
+ res = devm_request_mem_region(dev, res->start, resource_size(res),
+ dev_name(dev));
+ if (!res) {
+ dev_err(dev, "could not allocate register map resource\n");
+ ret = -ENXIO;
+ goto bail_out;
+ }
+
+ data->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
+ if (!data->regs) {
+ dev_err(dev, "could not map mdio registers\n");
+ ret = -ENOMEM;
+ goto bail_out;
+ }
+
+ /* register the mii bus */
+ ret = mdiobus_register(data->bus);
+ if (ret)
+ goto bail_out;
+
+ /* scan and dump the bus */
+ for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
+ phy = data->bus->phy_map[addr];
+ if (phy) {
+ dev_info(dev, "phy[%d]: device %s, driver %s\n",
+ phy->addr, dev_name(&phy->dev),
+ phy->drv ? phy->drv->name : "unknown");
+ }
+ }
+
+ return 0;
+
+bail_out:
+ if (data->bus)
+ mdiobus_free(data->bus);
+
+ if (data->clk) {
+ clk_disable(data->clk);
+ clk_put(data->clk);
+ }
+
+ kfree(data);
+
+ return ret;
+}
+
+static int __devexit davinci_mdio_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct davinci_mdio_data *data = dev_get_drvdata(dev);
+
+ if (data->bus)
+ mdiobus_free(data->bus);
+
+ if (data->clk) {
+ clk_disable(data->clk);
+ clk_put(data->clk);
+ }
+
+ dev_set_drvdata(dev, NULL);
+
+ kfree(data);
+
+ return 0;
+}
+
+static int davinci_mdio_suspend(struct device *dev)
+{
+ struct davinci_mdio_data *data = dev_get_drvdata(dev);
+ u32 ctrl;
+
+ spin_lock(&data->lock);
+
+ /* shutdown the scan state machine */
+ ctrl = __raw_readl(&data->regs->control);
+ ctrl &= ~CONTROL_ENABLE;
+ __raw_writel(ctrl, &data->regs->control);
+ wait_for_idle(data);
+
+ if (data->clk)
+ clk_disable(data->clk);
+
+ data->suspended = true;
+ spin_unlock(&data->lock);
+
+ return 0;
+}
+
+static int davinci_mdio_resume(struct device *dev)
+{
+ struct davinci_mdio_data *data = dev_get_drvdata(dev);
+ u32 ctrl;
+
+ spin_lock(&data->lock);
+ if (data->clk)
+ clk_enable(data->clk);
+
+ /* restart the scan state machine */
+ ctrl = __raw_readl(&data->regs->control);
+ ctrl |= CONTROL_ENABLE;
+ __raw_writel(ctrl, &data->regs->control);
+
+ data->suspended = false;
+ spin_unlock(&data->lock);
+
+ return 0;
+}
+
+static const struct dev_pm_ops davinci_mdio_pm_ops = {
+ .suspend = davinci_mdio_suspend,
+ .resume = davinci_mdio_resume,
+};
+
+static struct platform_driver davinci_mdio_driver = {
+ .driver = {
+ .name = "davinci_mdio",
+ .owner = THIS_MODULE,
+ .pm = &davinci_mdio_pm_ops,
+ },
+ .probe = davinci_mdio_probe,
+ .remove = __devexit_p(davinci_mdio_remove),
+};
+
+static int __init davinci_mdio_init(void)
+{
+ return platform_driver_register(&davinci_mdio_driver);
+}
+device_initcall(davinci_mdio_init);
+
+static void __exit davinci_mdio_exit(void)
+{
+ platform_driver_unregister(&davinci_mdio_driver);
+}
+module_exit(davinci_mdio_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DaVinci MDIO driver");
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index f3650fd096f4..1c51a7576119 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -676,7 +676,7 @@ static int de620_rx_intr(struct net_device *dev)
de620_set_register(dev, W_NPRF, next_rx_page);
pr_debug("next_rx_page=%d CPR=%d\n", next_rx_page, curr_page);
- return (next_rx_page != curr_page); /* That was slightly tricky... */
+ return next_rx_page != curr_page; /* That was slightly tricky... */
}
/*********************************************
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index d7de376d7178..219eb5ad5c12 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -1255,7 +1255,7 @@ static int __devinit dec_lance_probe(struct device *bdev, const int type)
*/
init_timer(&lp->multicast_timer);
lp->multicast_timer.data = (unsigned long) dev;
- lp->multicast_timer.function = &lance_set_multicast_retry;
+ lp->multicast_timer.function = lance_set_multicast_retry;
ret = register_netdev(dev);
if (ret) {
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index e5667c55844e..417e14385623 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -1024,7 +1024,7 @@ static int __devinit dfx_driver_init(struct net_device *dev,
&data) != DFX_K_SUCCESS) {
printk("%s: Could not read adapter factory MAC address!\n",
print_name);
- return(DFX_K_FAILURE);
+ return DFX_K_FAILURE;
}
le32 = cpu_to_le32(data);
memcpy(&bp->factory_mac_addr[0], &le32, sizeof(u32));
@@ -1033,7 +1033,7 @@ static int __devinit dfx_driver_init(struct net_device *dev,
&data) != DFX_K_SUCCESS) {
printk("%s: Could not read adapter factory MAC address!\n",
print_name);
- return(DFX_K_FAILURE);
+ return DFX_K_FAILURE;
}
le32 = cpu_to_le32(data);
memcpy(&bp->factory_mac_addr[4], &le32, sizeof(u16));
@@ -1075,7 +1075,7 @@ static int __devinit dfx_driver_init(struct net_device *dev,
if (top_v == NULL) {
printk("%s: Could not allocate memory for host buffers "
"and structures!\n", print_name);
- return(DFX_K_FAILURE);
+ return DFX_K_FAILURE;
}
memset(top_v, 0, alloc_size); /* zero out memory before continuing */
top_p = bp->kmalloced_dma; /* get physical address of buffer */
@@ -1145,7 +1145,7 @@ static int __devinit dfx_driver_init(struct net_device *dev,
DBG_printk("%s: Consumer block virt = %0lX, phys = %0X\n",
print_name, (long)bp->cons_block_virt, bp->cons_block_phys);
- return(DFX_K_SUCCESS);
+ return DFX_K_SUCCESS;
}
@@ -1195,7 +1195,7 @@ static int dfx_adap_init(DFX_board_t *bp, int get_buffers)
if (dfx_hw_dma_uninit(bp, bp->reset_type) != DFX_K_SUCCESS)
{
printk("%s: Could not uninitialize/reset adapter!\n", bp->dev->name);
- return(DFX_K_FAILURE);
+ return DFX_K_FAILURE;
}
/*
@@ -1229,7 +1229,7 @@ static int dfx_adap_init(DFX_board_t *bp, int get_buffers)
NULL) != DFX_K_SUCCESS)
{
printk("%s: Could not set adapter burst size!\n", bp->dev->name);
- return(DFX_K_FAILURE);
+ return DFX_K_FAILURE;
}
/*
@@ -1246,7 +1246,7 @@ static int dfx_adap_init(DFX_board_t *bp, int get_buffers)
NULL) != DFX_K_SUCCESS)
{
printk("%s: Could not set consumer block address!\n", bp->dev->name);
- return(DFX_K_FAILURE);
+ return DFX_K_FAILURE;
}
/*
@@ -1278,7 +1278,7 @@ static int dfx_adap_init(DFX_board_t *bp, int get_buffers)
if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
{
printk("%s: DMA command request failed!\n", bp->dev->name);
- return(DFX_K_FAILURE);
+ return DFX_K_FAILURE;
}
/* Set the initial values for eFDXEnable and MACTReq MIB objects */
@@ -1294,7 +1294,7 @@ static int dfx_adap_init(DFX_board_t *bp, int get_buffers)
if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
{
printk("%s: DMA command request failed!\n", bp->dev->name);
- return(DFX_K_FAILURE);
+ return DFX_K_FAILURE;
}
/* Initialize adapter CAM */
@@ -1302,7 +1302,7 @@ static int dfx_adap_init(DFX_board_t *bp, int get_buffers)
if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS)
{
printk("%s: Adapter CAM update failed!\n", bp->dev->name);
- return(DFX_K_FAILURE);
+ return DFX_K_FAILURE;
}
/* Initialize adapter filters */
@@ -1310,7 +1310,7 @@ static int dfx_adap_init(DFX_board_t *bp, int get_buffers)
if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS)
{
printk("%s: Adapter filters update failed!\n", bp->dev->name);
- return(DFX_K_FAILURE);
+ return DFX_K_FAILURE;
}
/*
@@ -1328,7 +1328,7 @@ static int dfx_adap_init(DFX_board_t *bp, int get_buffers)
printk("%s: Receive buffer allocation failed\n", bp->dev->name);
if (get_buffers)
dfx_rcv_flush(bp);
- return(DFX_K_FAILURE);
+ return DFX_K_FAILURE;
}
/* Issue START command and bring adapter to LINK_(UN)AVAILABLE state */
@@ -1339,13 +1339,13 @@ static int dfx_adap_init(DFX_board_t *bp, int get_buffers)
printk("%s: Start command failed\n", bp->dev->name);
if (get_buffers)
dfx_rcv_flush(bp);
- return(DFX_K_FAILURE);
+ return DFX_K_FAILURE;
}
/* Initialization succeeded, reenable PDQ interrupts */
dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_ENABLE_DEF_INTS);
- return(DFX_K_SUCCESS);
+ return DFX_K_SUCCESS;
}
@@ -1434,7 +1434,7 @@ static int dfx_open(struct net_device *dev)
/* Set device structure info */
netif_start_queue(dev);
- return(0);
+ return 0;
}
@@ -1526,7 +1526,7 @@ static int dfx_close(struct net_device *dev)
free_irq(dev->irq, dev);
- return(0);
+ return 0;
}
@@ -2027,7 +2027,7 @@ static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev)
bp->cmd_req_virt->cmd_type = PI_CMD_K_SMT_MIB_GET;
if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
- return((struct net_device_stats *) &bp->stats);
+ return (struct net_device_stats *)&bp->stats;
/* Fill the bp->stats structure with the SMT MIB object values */
@@ -2128,7 +2128,7 @@ static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev)
bp->cmd_req_virt->cmd_type = PI_CMD_K_CNTRS_GET;
if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
- return((struct net_device_stats *) &bp->stats);
+ return (struct net_device_stats *)&bp->stats;
/* Fill the bp->stats structure with the FDDI counter values */
@@ -2144,7 +2144,7 @@ static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev)
bp->stats.port_lem_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls;
bp->stats.port_lem_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls;
- return((struct net_device_stats *) &bp->stats);
+ return (struct net_device_stats *)&bp->stats;
}
@@ -2354,7 +2354,7 @@ static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr)
{
DBG_printk("%s: Adapter CAM updated with new MAC address\n", dev->name);
}
- return(0); /* always return zero */
+ return 0; /* always return zero */
}
@@ -2438,8 +2438,8 @@ static int dfx_ctl_update_cam(DFX_board_t *bp)
/* Issue command to update adapter CAM, then return */
if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
- return(DFX_K_FAILURE);
- return(DFX_K_SUCCESS);
+ return DFX_K_FAILURE;
+ return DFX_K_SUCCESS;
}
@@ -2504,8 +2504,8 @@ static int dfx_ctl_update_filters(DFX_board_t *bp)
/* Issue command to update adapter filters, then return */
if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
- return(DFX_K_FAILURE);
- return(DFX_K_SUCCESS);
+ return DFX_K_FAILURE;
+ return DFX_K_SUCCESS;
}
@@ -2561,7 +2561,7 @@ static int dfx_hw_dma_cmd_req(DFX_board_t *bp)
(status == PI_STATE_K_HALTED) ||
(status == PI_STATE_K_DMA_UNAVAIL) ||
(status == PI_STATE_K_UPGRADE))
- return(DFX_K_OUTSTATE);
+ return DFX_K_OUTSTATE;
/* Put response buffer on the command response queue */
@@ -2599,7 +2599,7 @@ static int dfx_hw_dma_cmd_req(DFX_board_t *bp)
udelay(100); /* wait for 100 microseconds */
}
if (timeout_cnt == 0)
- return(DFX_K_HW_TIMEOUT);
+ return DFX_K_HW_TIMEOUT;
/* Bump (and wrap) the completion index and write out to register */
@@ -2619,14 +2619,14 @@ static int dfx_hw_dma_cmd_req(DFX_board_t *bp)
udelay(100); /* wait for 100 microseconds */
}
if (timeout_cnt == 0)
- return(DFX_K_HW_TIMEOUT);
+ return DFX_K_HW_TIMEOUT;
/* Bump (and wrap) the completion index and write out to register */
bp->cmd_rsp_reg.index.comp += 1;
bp->cmd_rsp_reg.index.comp &= PI_CMD_RSP_K_NUM_ENTRIES-1;
dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword);
- return(DFX_K_SUCCESS);
+ return DFX_K_SUCCESS;
}
@@ -2700,7 +2700,7 @@ static int dfx_hw_port_ctrl_req(
udelay(100); /* wait for 100 microseconds */
}
if (timeout_cnt == 0)
- return(DFX_K_HW_TIMEOUT);
+ return DFX_K_HW_TIMEOUT;
/*
* If the address of host_data is non-zero, assume caller has supplied a
@@ -2710,7 +2710,7 @@ static int dfx_hw_port_ctrl_req(
if (host_data != NULL)
dfx_port_read_long(bp, PI_PDQ_K_REG_HOST_DATA, host_data);
- return(DFX_K_SUCCESS);
+ return DFX_K_SUCCESS;
}
@@ -2800,7 +2800,7 @@ static int dfx_hw_adap_state_rd(DFX_board_t *bp)
PI_UINT32 port_status; /* Port Status register value */
dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status);
- return((port_status & PI_PSTATUS_M_STATE) >> PI_PSTATUS_V_STATE);
+ return (port_status & PI_PSTATUS_M_STATE) >> PI_PSTATUS_V_STATE;
}
@@ -2852,8 +2852,8 @@ static int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type)
udelay(100); /* wait for 100 microseconds */
}
if (timeout_cnt == 0)
- return(DFX_K_HW_TIMEOUT);
- return(DFX_K_SUCCESS);
+ return DFX_K_HW_TIMEOUT;
+ return DFX_K_SUCCESS;
}
/*
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 44c0694c1f4e..91b3846ffc8a 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -1487,7 +1487,7 @@ static void __init depca_platform_probe (void)
if (!pldev->dev.driver) {
/* The driver was not bound to this device, there was
* no hardware at this address. Unregister it, as the
- * release fuction will take care of freeing the
+ * release function will take care of freeing the
* allocated structure */
depca_io_ports[i].device = NULL;
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index a2f238d20caa..e1a8216ff692 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -465,7 +465,7 @@ rio_open (struct net_device *dev)
init_timer (&np->timer);
np->timer.expires = jiffies + 1*HZ;
np->timer.data = (unsigned long) dev;
- np->timer.function = &rio_timer;
+ np->timer.function = rio_timer;
add_timer (&np->timer);
/* Start Tx/Rx */
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 4fd6b2b4554b..9f6aeefa06bf 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -1056,7 +1056,7 @@ dm9000_rx(struct net_device *dev)
if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
}
netif_rx(skb);
dev->stats.rx_packets++;
diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c
index 7c075756611a..9d8a20b72fa9 100644
--- a/drivers/net/dnet.c
+++ b/drivers/net/dnet.c
@@ -27,7 +27,7 @@
#undef DEBUG
/* function for reading internal MAC register */
-u16 dnet_readw_mac(struct dnet *bp, u16 reg)
+static u16 dnet_readw_mac(struct dnet *bp, u16 reg)
{
u16 data_read;
@@ -46,7 +46,7 @@ u16 dnet_readw_mac(struct dnet *bp, u16 reg)
}
/* function for writing internal MAC register */
-void dnet_writew_mac(struct dnet *bp, u16 reg, u16 val)
+static void dnet_writew_mac(struct dnet *bp, u16 reg, u16 val)
{
/* load data to write */
dnet_writel(bp, val, MACREG_DATA);
@@ -63,11 +63,11 @@ static void __dnet_set_hwaddr(struct dnet *bp)
{
u16 tmp;
- tmp = cpu_to_be16(*((u16 *) bp->dev->dev_addr));
+ tmp = be16_to_cpup((__be16 *)bp->dev->dev_addr);
dnet_writew_mac(bp, DNET_INTERNAL_MAC_ADDR_0_REG, tmp);
- tmp = cpu_to_be16(*((u16 *) (bp->dev->dev_addr + 2)));
+ tmp = be16_to_cpup((__be16 *)(bp->dev->dev_addr + 2));
dnet_writew_mac(bp, DNET_INTERNAL_MAC_ADDR_1_REG, tmp);
- tmp = cpu_to_be16(*((u16 *) (bp->dev->dev_addr + 4)));
+ tmp = be16_to_cpup((__be16 *)(bp->dev->dev_addr + 4));
dnet_writew_mac(bp, DNET_INTERNAL_MAC_ADDR_2_REG, tmp);
}
@@ -89,11 +89,11 @@ static void __devinit dnet_get_hwaddr(struct dnet *bp)
* Mac_addr[15:0]).
*/
tmp = dnet_readw_mac(bp, DNET_INTERNAL_MAC_ADDR_0_REG);
- *((u16 *) addr) = be16_to_cpu(tmp);
+ *((__be16 *)addr) = cpu_to_be16(tmp);
tmp = dnet_readw_mac(bp, DNET_INTERNAL_MAC_ADDR_1_REG);
- *((u16 *) (addr + 2)) = be16_to_cpu(tmp);
+ *((__be16 *)(addr + 2)) = cpu_to_be16(tmp);
tmp = dnet_readw_mac(bp, DNET_INTERNAL_MAC_ADDR_2_REG);
- *((u16 *) (addr + 4)) = be16_to_cpu(tmp);
+ *((__be16 *)(addr + 4)) = cpu_to_be16(tmp);
if (is_valid_ether_addr(addr))
memcpy(bp->dev->dev_addr, addr, sizeof(addr));
@@ -361,7 +361,7 @@ err_out:
}
/* For Neptune board: LINK1000 as Link LED and TX as activity LED */
-int dnet_phy_marvell_fixup(struct phy_device *phydev)
+static int dnet_phy_marvell_fixup(struct phy_device *phydev)
{
return phy_write(phydev, 0x18, 0x4148);
}
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 37dcfdc63456..ff2d29b17858 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -36,6 +36,7 @@
#include <linux/moduleparam.h>
#include <linux/rtnetlink.h>
#include <net/rtnetlink.h>
+#include <linux/u64_stats_sync.h>
static int numdummies = 1;
@@ -55,21 +56,69 @@ static void set_multicast_list(struct net_device *dev)
{
}
+struct pcpu_dstats {
+ u64 tx_packets;
+ u64 tx_bytes;
+ struct u64_stats_sync syncp;
+};
+
+static struct rtnl_link_stats64 *dummy_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
+{
+ int i;
+
+ for_each_possible_cpu(i) {
+ const struct pcpu_dstats *dstats;
+ u64 tbytes, tpackets;
+ unsigned int start;
+
+ dstats = per_cpu_ptr(dev->dstats, i);
+ do {
+ start = u64_stats_fetch_begin(&dstats->syncp);
+ tbytes = dstats->tx_bytes;
+ tpackets = dstats->tx_packets;
+ } while (u64_stats_fetch_retry(&dstats->syncp, start));
+ stats->tx_bytes += tbytes;
+ stats->tx_packets += tpackets;
+ }
+ return stats;
+}
static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev)
{
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
+ struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
+
+ u64_stats_update_begin(&dstats->syncp);
+ dstats->tx_packets++;
+ dstats->tx_bytes += skb->len;
+ u64_stats_update_end(&dstats->syncp);
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
+static int dummy_dev_init(struct net_device *dev)
+{
+ dev->dstats = alloc_percpu(struct pcpu_dstats);
+ if (!dev->dstats)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void dummy_dev_free(struct net_device *dev)
+{
+ free_percpu(dev->dstats);
+ free_netdev(dev);
+}
+
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_mac_address = dummy_set_address,
+ .ndo_get_stats64 = dummy_get_stats64,
};
static void dummy_setup(struct net_device *dev)
@@ -78,14 +127,17 @@ static void dummy_setup(struct net_device *dev)
/* Initialize the device structure. */
dev->netdev_ops = &dummy_netdev_ops;
- dev->destructor = free_netdev;
+ dev->destructor = dummy_dev_free;
/* Fill in device structure with ethernet-generic values. */
dev->tx_queue_len = 0;
dev->flags |= IFF_NOARP;
dev->flags &= ~IFF_MULTICAST;
+ dev->features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO;
+ dev->features |= NETIF_F_NO_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX;
random_ether_addr(dev->dev_addr);
}
+
static int dummy_validate(struct nlattr *tb[], struct nlattr *data[])
{
if (tb[IFLA_ADDRESS]) {
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 8e2eab4e7c75..b0aa9e68990a 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -2215,10 +2215,10 @@ static int e100_change_mtu(struct net_device *netdev, int new_mtu)
static int e100_asf(struct nic *nic)
{
/* ASF can be enabled from eeprom */
- return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1057) &&
+ return (nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1057) &&
(nic->eeprom[eeprom_config_asf] & eeprom_asf) &&
!(nic->eeprom[eeprom_config_asf] & eeprom_gcl) &&
- ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE));
+ ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE);
}
static int e100_up(struct nic *nic)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 99288b95aead..a881dd0093bd 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -310,6 +310,9 @@ struct e1000_adapter {
int need_ioport;
bool discarding;
+
+ struct work_struct fifo_stall_task;
+ struct work_struct phy_info_task;
};
enum e1000_state_t {
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 5cc39ed289c6..4686c3983fc3 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -123,8 +123,10 @@ 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_82547_tx_fifo_stall_task(struct work_struct *work);
static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
struct net_device *netdev);
static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
@@ -519,8 +521,21 @@ void e1000_down(struct e1000_adapter *adapter)
e1000_clean_all_rx_rings(adapter);
}
+static void e1000_reinit_safe(struct e1000_adapter *adapter)
+{
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
+ msleep(1);
+ rtnl_lock();
+ e1000_down(adapter);
+ e1000_up(adapter);
+ rtnl_unlock();
+ clear_bit(__E1000_RESETTING, &adapter->flags);
+}
+
void e1000_reinit_locked(struct e1000_adapter *adapter)
{
+ /* if rtnl_lock is not held the call path is bogus */
+ ASSERT_RTNL();
WARN_ON(in_interrupt());
while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
msleep(1);
@@ -790,6 +805,70 @@ static const struct net_device_ops e1000_netdev_ops = {
};
/**
+ * e1000_init_hw_struct - initialize members of hw struct
+ * @adapter: board private struct
+ * @hw: structure used by e1000_hw.c
+ *
+ * Factors out initialization of the e1000_hw struct to its own function
+ * that can be called very early at init (just after struct allocation).
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ * Returns negative error codes if MAC type setup fails.
+ */
+static int e1000_init_hw_struct(struct e1000_adapter *adapter,
+ struct e1000_hw *hw)
+{
+ struct pci_dev *pdev = adapter->pdev;
+
+ /* PCI config space info */
+ hw->vendor_id = pdev->vendor;
+ hw->device_id = pdev->device;
+ hw->subsystem_vendor_id = pdev->subsystem_vendor;
+ hw->subsystem_id = pdev->subsystem_device;
+ hw->revision_id = pdev->revision;
+
+ pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
+
+ hw->max_frame_size = adapter->netdev->mtu +
+ ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+ hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
+
+ /* identify the MAC */
+ if (e1000_set_mac_type(hw)) {
+ e_err(probe, "Unknown MAC Type\n");
+ return -EIO;
+ }
+
+ switch (hw->mac_type) {
+ default:
+ break;
+ case e1000_82541:
+ case e1000_82547:
+ case e1000_82541_rev_2:
+ case e1000_82547_rev_2:
+ hw->phy_init_script = 1;
+ break;
+ }
+
+ e1000_set_media_type(hw);
+ e1000_get_bus_info(hw);
+
+ hw->wait_autoneg_complete = false;
+ hw->tbi_compatibility_en = true;
+ hw->adaptive_ifs = true;
+
+ /* Copper options */
+
+ if (hw->media_type == e1000_media_type_copper) {
+ hw->mdix = AUTO_ALL_MODES;
+ hw->disable_polarity_correction = false;
+ hw->master_slave = E1000_MASTER_SLAVE;
+ }
+
+ return 0;
+}
+
+/**
* e1000_probe - Device Initialization Routine
* @pdev: PCI device information struct
* @ent: entry in e1000_pci_tbl
@@ -826,22 +905,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
if (err)
return err;
- if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) &&
- !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) {
- pci_using_dac = 1;
- } else {
- err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (err) {
- err = dma_set_coherent_mask(&pdev->dev,
- DMA_BIT_MASK(32));
- if (err) {
- pr_err("No usable DMA config, aborting\n");
- goto err_dma;
- }
- }
- pci_using_dac = 0;
- }
-
err = pci_request_selected_regions(pdev, bars, e1000_driver_name);
if (err)
goto err_pci_reg;
@@ -885,6 +948,32 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
}
}
+ /* make ready for any if (hw->...) below */
+ err = e1000_init_hw_struct(adapter, hw);
+ if (err)
+ goto err_sw_init;
+
+ /*
+ * there is a workaround being applied below that limits
+ * 64-bit DMA addresses to 64-bit hardware. There are some
+ * 32-bit adapters that Tx hang when given 64-bit DMA addresses
+ */
+ pci_using_dac = 0;
+ if ((hw->bus_type == e1000_bus_type_pcix) &&
+ !dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
+ /*
+ * according to DMA-API-HOWTO, coherent calls will always
+ * succeed if the set call did
+ */
+ dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
+ pci_using_dac = 1;
+ } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
+ dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+ } else {
+ pr_err("No usable DMA config, aborting\n");
+ goto err_dma;
+ }
+
netdev->netdev_ops = &e1000_netdev_ops;
e1000_set_ethtool_ops(netdev);
netdev->watchdog_timeo = 5 * HZ;
@@ -914,8 +1003,10 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
(hw->mac_type != e1000_82547))
netdev->features |= NETIF_F_TSO;
- if (pci_using_dac)
+ if (pci_using_dac) {
netdev->features |= NETIF_F_HIGHDMA;
+ netdev->vlan_features |= NETIF_F_HIGHDMA;
+ }
netdev->vlan_features |= NETIF_F_TSO;
netdev->vlan_features |= NETIF_F_HW_CSUM;
@@ -959,21 +1050,21 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
if (!is_valid_ether_addr(netdev->perm_addr))
e_err(probe, "Invalid MAC Address\n");
- e1000_get_bus_info(hw);
-
init_timer(&adapter->tx_fifo_stall_timer);
- adapter->tx_fifo_stall_timer.function = &e1000_82547_tx_fifo_stall;
+ 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.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.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_WORK(&adapter->reset_task, e1000_reset_task);
+ INIT_WORK(&adapter->phy_info_task, e1000_update_phy_info_task);
e1000_check_options(adapter);
@@ -1072,6 +1163,7 @@ err_eeprom:
iounmap(hw->flash_address);
kfree(adapter->tx_ring);
kfree(adapter->rx_ring);
+err_dma:
err_sw_init:
iounmap(hw->hw_addr);
err_ioremap:
@@ -1079,7 +1171,6 @@ err_ioremap:
err_alloc_etherdev:
pci_release_selected_regions(pdev, bars);
err_pci_reg:
-err_dma:
pci_disable_device(pdev);
return err;
}
@@ -1131,62 +1222,12 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
* @adapter: board private structure to initialize
*
* e1000_sw_init initializes the Adapter private data structure.
- * Fields are initialized based on PCI device information and
- * OS network device settings (MTU size).
+ * e1000_init_hw_struct MUST be called before this function
**/
static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
{
- struct e1000_hw *hw = &adapter->hw;
- struct net_device *netdev = adapter->netdev;
- struct pci_dev *pdev = adapter->pdev;
-
- /* PCI config space info */
-
- hw->vendor_id = pdev->vendor;
- hw->device_id = pdev->device;
- hw->subsystem_vendor_id = pdev->subsystem_vendor;
- hw->subsystem_id = pdev->subsystem_device;
- hw->revision_id = pdev->revision;
-
- pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
-
adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
- hw->max_frame_size = netdev->mtu +
- ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
- hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
-
- /* identify the MAC */
-
- if (e1000_set_mac_type(hw)) {
- e_err(probe, "Unknown MAC Type\n");
- return -EIO;
- }
-
- switch (hw->mac_type) {
- default:
- break;
- case e1000_82541:
- case e1000_82547:
- case e1000_82541_rev_2:
- case e1000_82547_rev_2:
- hw->phy_init_script = 1;
- break;
- }
-
- e1000_set_media_type(hw);
-
- hw->wait_autoneg_complete = false;
- hw->tbi_compatibility_en = true;
- hw->adaptive_ifs = true;
-
- /* Copper options */
-
- if (hw->media_type == e1000_media_type_copper) {
- hw->mdix = AUTO_ALL_MODES;
- hw->disable_polarity_correction = false;
- hw->master_slave = E1000_MASTER_SLAVE;
- }
adapter->num_tx_queues = 1;
adapter->num_rx_queues = 1;
@@ -2210,22 +2251,45 @@ static void e1000_set_rx_mode(struct net_device *netdev)
static void e1000_update_phy_info(unsigned long data)
{
struct e1000_adapter *adapter = (struct e1000_adapter *)data;
+ schedule_work(&adapter->phy_info_task);
+}
+
+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);
+}
+
+/**
+ * e1000_82547_tx_fifo_stall_task - task to complete work
+ * @work: work struct contained inside adapter struct
+ **/
+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_hw *hw = &adapter->hw;
struct net_device *netdev = adapter->netdev;
u32 tctl;
+ rtnl_lock();
if (atomic_read(&adapter->tx_fifo_stall)) {
if ((er32(TDT) == er32(TDH)) &&
(er32(TDFT) == er32(TDFH)) &&
@@ -2246,6 +2310,7 @@ static void e1000_82547_tx_fifo_stall(unsigned long data)
mod_timer(&adapter->tx_fifo_stall_timer, jiffies + 1);
}
}
+ rtnl_unlock();
}
bool e1000_has_link(struct e1000_adapter *adapter)
@@ -3054,7 +3119,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
}
}
- if (unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) {
+ if (unlikely(vlan_tx_tag_present(skb))) {
tx_flags |= E1000_TX_FLAGS_VLAN;
tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
}
@@ -3113,7 +3178,7 @@ static void e1000_reset_task(struct work_struct *work)
struct e1000_adapter *adapter =
container_of(work, struct e1000_adapter, reset_task);
- e1000_reinit_locked(adapter);
+ e1000_reinit_safe(adapter);
}
/**
@@ -3535,7 +3600,7 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
adapter->total_tx_packets += total_tx_packets;
netdev->stats.tx_bytes += total_tx_bytes;
netdev->stats.tx_packets += total_tx_packets;
- return (count < tx_ring->count);
+ return count < tx_ring->count;
}
/**
@@ -3552,7 +3617,8 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
struct e1000_hw *hw = &adapter->hw;
u16 status = (u16)status_err;
u8 errors = (u8)(status_err >> 24);
- skb->ip_summed = CHECKSUM_NONE;
+
+ skb_checksum_none_assert(skb);
/* 82543 or newer only */
if (unlikely(hw->mac_type < e1000_82543)) return;
@@ -3598,13 +3664,14 @@ static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb,
static void e1000_receive_skb(struct e1000_adapter *adapter, u8 status,
__le16 vlan, struct sk_buff *skb)
{
- if (unlikely(adapter->vlgrp && (status & E1000_RXD_STAT_VP))) {
- vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
- le16_to_cpu(vlan) &
- E1000_RXD_SPC_VLAN_MASK);
- } else {
- netif_receive_skb(skb);
- }
+ skb->protocol = eth_type_trans(skb, adapter->netdev);
+
+ if ((unlikely(adapter->vlgrp && (status & E1000_RXD_STAT_VP))))
+ vlan_gro_receive(&adapter->napi, adapter->vlgrp,
+ le16_to_cpu(vlan) & E1000_RXD_SPC_VLAN_MASK,
+ skb);
+ else
+ napi_gro_receive(&adapter->napi, skb);
}
/**
@@ -3762,8 +3829,6 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
goto next_desc;
}
- skb->protocol = eth_type_trans(skb, netdev);
-
e1000_receive_skb(adapter, status, rx_desc->special, skb);
next_desc:
@@ -3926,8 +3991,6 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
((u32)(rx_desc->errors) << 24),
le16_to_cpu(rx_desc->csum), skb);
- skb->protocol = eth_type_trans(skb, netdev);
-
e1000_receive_skb(adapter, status, rx_desc->special, skb);
next_desc:
@@ -4478,7 +4541,7 @@ static void e1000_restore_vlan(struct e1000_adapter *adapter)
if (adapter->vlgrp) {
u16 vid;
- for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ for (vid = 0; vid < VLAN_N_VID; vid++) {
if (!vlan_group_get_device(adapter->vlgrp, vid))
continue;
e1000_vlan_rx_add_vid(adapter->netdev, vid);
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index d3d4a57e2450..ca663f19d7df 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -1801,7 +1801,8 @@ struct e1000_info e1000_82571_info = {
| FLAG_RESET_OVERWRITES_LAA /* errata */
| FLAG_TARC_SPEED_MODE_BIT /* errata */
| FLAG_APME_CHECK_PORT_B,
- .flags2 = FLAG2_DISABLE_ASPM_L1, /* errata 13 */
+ .flags2 = FLAG2_DISABLE_ASPM_L1 /* errata 13 */
+ | FLAG2_DMA_BURST,
.pba = 38,
.max_hw_frame_size = DEFAULT_JUMBO,
.get_variants = e1000_get_variants_82571,
@@ -1819,7 +1820,8 @@ struct e1000_info e1000_82572_info = {
| FLAG_RX_CSUM_ENABLED
| FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_TARC_SPEED_MODE_BIT, /* errata */
- .flags2 = FLAG2_DISABLE_ASPM_L1, /* errata 13 */
+ .flags2 = FLAG2_DISABLE_ASPM_L1 /* errata 13 */
+ | FLAG2_DMA_BURST,
.pba = 38,
.max_hw_frame_size = DEFAULT_JUMBO,
.get_variants = e1000_get_variants_82571,
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
index 93b3bedae8d2..d3f7a9c3f973 100644
--- a/drivers/net/e1000e/defines.h
+++ b/drivers/net/e1000e/defines.h
@@ -446,7 +446,9 @@
/* Transmit Descriptor Control */
#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */
#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */
#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */
/* Enable the counting of desc. still to be processed. */
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index f9a31c82f871..cee882dd67bf 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -153,6 +153,33 @@ struct e1000_info;
/* Time to wait before putting the device into D3 if there's no link (in ms). */
#define LINK_TIMEOUT 100
+#define DEFAULT_RDTR 0
+#define DEFAULT_RADV 8
+#define BURST_RDTR 0x20
+#define BURST_RADV 0x20
+
+/*
+ * in the case of WTHRESH, it appears at least the 82571/2 hardware
+ * writes back 4 descriptors when WTHRESH=5, and 3 descriptors when
+ * WTHRESH=4, and since we want 64 bytes at a time written back, set
+ * it to 5
+ */
+#define E1000_TXDCTL_DMA_BURST_ENABLE \
+ (E1000_TXDCTL_GRAN | /* set descriptor granularity */ \
+ E1000_TXDCTL_COUNT_DESC | \
+ (5 << 16) | /* wthresh must be +1 more than desired */\
+ (1 << 8) | /* hthresh */ \
+ 0x1f) /* pthresh */
+
+#define E1000_RXDCTL_DMA_BURST_ENABLE \
+ (0x01000000 | /* set descriptor granularity */ \
+ (4 << 16) | /* set writeback threshold */ \
+ (4 << 8) | /* set prefetch threshold */ \
+ 0x20) /* set hthresh */
+
+#define E1000_TIDV_FPD (1 << 31)
+#define E1000_RDTR_FPD (1 << 31)
+
enum e1000_boards {
board_82571,
board_82572,
@@ -425,6 +452,8 @@ struct e1000_info {
#define FLAG2_DISABLE_ASPM_L1 (1 << 3)
#define FLAG2_HAS_PHY_STATS (1 << 4)
#define FLAG2_HAS_EEE (1 << 5)
+#define FLAG2_DMA_BURST (1 << 6)
+#define FLAG2_DISABLE_AIM (1 << 8)
#define E1000_RX_DESC_PS(R, i) \
(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c
index 45aebb4a6fe1..24f8ac9cf703 100644
--- a/drivers/net/e1000e/es2lan.c
+++ b/drivers/net/e1000e/es2lan.c
@@ -1494,6 +1494,7 @@ struct e1000_info e1000_es2_info = {
| FLAG_APME_CHECK_PORT_B
| FLAG_DISABLE_FC_PAUSE_TIME /* errata */
| FLAG_TIPG_MEDIUM_FOR_80003ESLAN,
+ .flags2 = FLAG2_DMA_BURST,
.pba = 38,
.max_hw_frame_size = DEFAULT_JUMBO,
.get_variants = e1000_get_variants_80003es2lan,
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index 6355a1b779d3..8984d165a39b 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -368,7 +368,7 @@ out:
static u32 e1000_get_rx_csum(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
- return (adapter->flags & FLAG_RX_CSUM_ENABLED);
+ return adapter->flags & FLAG_RX_CSUM_ENABLED;
}
static int e1000_set_rx_csum(struct net_device *netdev, u32 data)
@@ -389,7 +389,7 @@ static int e1000_set_rx_csum(struct net_device *netdev, u32 data)
static u32 e1000_get_tx_csum(struct net_device *netdev)
{
- return ((netdev->features & NETIF_F_HW_CSUM) != 0);
+ return (netdev->features & NETIF_F_HW_CSUM) != 0;
}
static int e1000_set_tx_csum(struct net_device *netdev, u32 data)
@@ -1717,13 +1717,6 @@ static void e1000_diag_test(struct net_device *netdev,
e_info("offline testing starting\n");
- /*
- * Link test performed before hardware reset so autoneg doesn't
- * interfere with test result
- */
- if (e1000_link_test(adapter, &data[4]))
- eth_test->flags |= ETH_TEST_FL_FAILED;
-
if (if_running)
/* indicate we're in test mode */
dev_close(netdev);
@@ -1747,15 +1740,19 @@ static void e1000_diag_test(struct net_device *netdev,
if (e1000_loopback_test(adapter, &data[3]))
eth_test->flags |= ETH_TEST_FL_FAILED;
+ /* force this routine to wait until autoneg complete/timeout */
+ adapter->hw.phy.autoneg_wait_to_complete = 1;
+ e1000e_reset(adapter);
+ adapter->hw.phy.autoneg_wait_to_complete = 0;
+
+ if (e1000_link_test(adapter, &data[4]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
/* restore speed, duplex, autoneg settings */
adapter->hw.phy.autoneg_advertised = autoneg_advertised;
adapter->hw.mac.forced_speed_duplex = forced_speed_duplex;
adapter->hw.mac.autoneg = autoneg;
-
- /* force this routine to wait until autoneg complete/timeout */
- adapter->hw.phy.autoneg_wait_to_complete = 1;
e1000e_reset(adapter);
- adapter->hw.phy.autoneg_wait_to_complete = 0;
clear_bit(__E1000_TESTING, &adapter->state);
if (if_running)
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index 57b5435599ab..e3374d9a2472 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -3986,7 +3986,7 @@ struct e1000_info e1000_pch2_info = {
| FLAG_APME_IN_WUC,
.flags2 = FLAG2_HAS_PHY_STATS
| FLAG2_HAS_EEE,
- .pba = 18,
+ .pba = 26,
.max_hw_frame_size = DEFAULT_JUMBO,
.get_variants = e1000_get_variants_ich8lan,
.mac_ops = &ich8_mac_ops,
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index e561d15c3eb1..ec8cf3f51423 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -475,7 +475,8 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
{
u16 status = (u16)status_err;
u8 errors = (u8)(status_err >> 24);
- skb->ip_summed = CHECKSUM_NONE;
+
+ skb_checksum_none_assert(skb);
/* Ignore Checksum bit is set */
if (status & E1000_RXD_STAT_IXSM)
@@ -1052,7 +1053,7 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
adapter->total_tx_packets += total_tx_packets;
netdev->stats.tx_bytes += total_tx_bytes;
netdev->stats.tx_packets += total_tx_packets;
- return (count < tx_ring->count);
+ return count < tx_ring->count;
}
/**
@@ -2289,6 +2290,11 @@ static void e1000_set_itr(struct e1000_adapter *adapter)
goto set_itr_now;
}
+ if (adapter->flags2 & FLAG2_DISABLE_AIM) {
+ new_itr = 0;
+ goto set_itr_now;
+ }
+
adapter->tx_itr = e1000_update_itr(adapter,
adapter->tx_itr,
adapter->total_tx_packets,
@@ -2337,7 +2343,10 @@ set_itr_now:
if (adapter->msix_entries)
adapter->rx_ring->set_itr = 1;
else
- ew32(ITR, 1000000000 / (new_itr * 256));
+ if (new_itr)
+ ew32(ITR, 1000000000 / (new_itr * 256));
+ else
+ ew32(ITR, 0);
}
}
@@ -2536,7 +2545,7 @@ static void e1000_restore_vlan(struct e1000_adapter *adapter)
if (!adapter->vlgrp)
return;
- for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ for (vid = 0; vid < VLAN_N_VID; vid++) {
if (!vlan_group_get_device(adapter->vlgrp, vid))
continue;
e1000_vlan_rx_add_vid(adapter->netdev, vid);
@@ -2649,6 +2658,26 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
/* Tx irq moderation */
ew32(TADV, adapter->tx_abs_int_delay);
+ if (adapter->flags2 & FLAG2_DMA_BURST) {
+ u32 txdctl = er32(TXDCTL(0));
+ txdctl &= ~(E1000_TXDCTL_PTHRESH | E1000_TXDCTL_HTHRESH |
+ E1000_TXDCTL_WTHRESH);
+ /*
+ * set up some performance related parameters to encourage the
+ * hardware to use the bus more efficiently in bursts, depends
+ * on the tx_int_delay to be enabled,
+ * wthresh = 5 ==> burst write a cacheline (64 bytes) at a time
+ * hthresh = 1 ==> prefetch when one or more available
+ * pthresh = 0x1f ==> prefetch if internal cache 31 or less
+ * BEWARE: this seems to work but should be considered first if
+ * there are tx hangs or other tx related bugs
+ */
+ txdctl |= E1000_TXDCTL_DMA_BURST_ENABLE;
+ ew32(TXDCTL(0), txdctl);
+ /* erratum work around: set txdctl the same for both queues */
+ ew32(TXDCTL(1), txdctl);
+ }
+
/* Program the Transmit Control Register */
tctl = er32(TCTL);
tctl &= ~E1000_TCTL_CT;
@@ -2871,12 +2900,35 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
e1e_flush();
msleep(10);
+ if (adapter->flags2 & FLAG2_DMA_BURST) {
+ /*
+ * set the writeback threshold (only takes effect if the RDTR
+ * is set). set GRAN=1 and write back up to 0x4 worth, and
+ * enable prefetching of 0x20 rx descriptors
+ * granularity = 01
+ * wthresh = 04,
+ * hthresh = 04,
+ * pthresh = 0x20
+ */
+ ew32(RXDCTL(0), E1000_RXDCTL_DMA_BURST_ENABLE);
+ ew32(RXDCTL(1), E1000_RXDCTL_DMA_BURST_ENABLE);
+
+ /*
+ * override the delay timers for enabling bursting, only if
+ * the value was not set by the user via module options
+ */
+ if (adapter->rx_int_delay == DEFAULT_RDTR)
+ adapter->rx_int_delay = BURST_RDTR;
+ if (adapter->rx_abs_int_delay == DEFAULT_RADV)
+ adapter->rx_abs_int_delay = BURST_RADV;
+ }
+
/* set the Receive Delay Timer Register */
ew32(RDTR, adapter->rx_int_delay);
/* irq moderation */
ew32(RADV, adapter->rx_abs_int_delay);
- if (adapter->itr_setting != 0)
+ if ((adapter->itr_setting != 0) && (adapter->itr != 0))
ew32(ITR, 1000000000 / (adapter->itr * 256));
ctrl_ext = er32(CTRL_EXT);
@@ -2921,11 +2973,13 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
* packet size is equal or larger than the specified value (in 8 byte
* units), e.g. using jumbo frames when setting to E1000_ERT_2048
*/
- if (adapter->flags & FLAG_HAS_ERT) {
+ if ((adapter->flags & FLAG_HAS_ERT) ||
+ (adapter->hw.mac.type == e1000_pch2lan)) {
if (adapter->netdev->mtu > ETH_DATA_LEN) {
u32 rxdctl = er32(RXDCTL(0));
ew32(RXDCTL(0), rxdctl | 0x3);
- ew32(ERT, E1000_ERT_2048 | (1 << 13));
+ if (adapter->flags & FLAG_HAS_ERT)
+ ew32(ERT, E1000_ERT_2048 | (1 << 13));
/*
* With jumbo frames and early-receive enabled,
* excessive C-state transition latencies result in
@@ -3188,9 +3242,35 @@ void e1000e_reset(struct e1000_adapter *adapter)
fc->low_water = 0x05048;
fc->pause_time = 0x0650;
fc->refresh_time = 0x0400;
+ if (adapter->netdev->mtu > ETH_DATA_LEN) {
+ pba = 14;
+ ew32(PBA, pba);
+ }
break;
}
+ /*
+ * Disable Adaptive Interrupt Moderation if 2 full packets cannot
+ * fit in receive buffer and early-receive not supported.
+ */
+ if (adapter->itr_setting & 0x3) {
+ if (((adapter->max_frame_size * 2) > (pba << 10)) &&
+ !(adapter->flags & FLAG_HAS_ERT)) {
+ if (!(adapter->flags2 & FLAG2_DISABLE_AIM)) {
+ dev_info(&adapter->pdev->dev,
+ "Interrupt Throttle Rate turned off\n");
+ adapter->flags2 |= FLAG2_DISABLE_AIM;
+ ew32(ITR, 0);
+ }
+ } else if (adapter->flags2 & FLAG2_DISABLE_AIM) {
+ dev_info(&adapter->pdev->dev,
+ "Interrupt Throttle Rate turned on\n");
+ adapter->flags2 &= ~FLAG2_DISABLE_AIM;
+ adapter->itr = 20000;
+ ew32(ITR, 1000000000 / (adapter->itr * 256));
+ }
+ }
+
/* Allow time for pending master requests to run */
mac->ops.reset_hw(hw);
@@ -3411,22 +3491,16 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
if (adapter->flags & FLAG_MSI_TEST_FAILED) {
adapter->int_mode = E1000E_INT_MODE_LEGACY;
- err = -EIO;
- e_info("MSI interrupt test failed!\n");
- }
+ e_info("MSI interrupt test failed, using legacy interrupt.\n");
+ } else
+ e_dbg("MSI interrupt test succeeded!\n");
free_irq(adapter->pdev->irq, netdev);
pci_disable_msi(adapter->pdev);
- if (err == -EIO)
- goto msi_test_failed;
-
- /* okay so the test worked, restore settings */
- e_dbg("MSI interrupt test succeeded!\n");
msi_test_failed:
e1000e_set_interrupt_capability(adapter);
- e1000_request_irq(adapter);
- return err;
+ return e1000_request_irq(adapter);
}
/**
@@ -3458,21 +3532,6 @@ static int e1000_test_msi(struct e1000_adapter *adapter)
pci_write_config_word(adapter->pdev, PCI_COMMAND, pci_cmd);
}
- /* success ! */
- if (!err)
- return 0;
-
- /* EIO means MSI test failed */
- if (err != -EIO)
- return err;
-
- /* back to INTx mode */
- e_warn("MSI interrupt test failed, using legacy interrupt.\n");
-
- e1000_free_irq(adapter);
-
- err = e1000_request_irq(adapter);
-
return err;
}
@@ -3530,7 +3589,8 @@ static int e1000_open(struct net_device *netdev)
e1000_update_mng_vlan(adapter);
/* DMA latency requirement to workaround early-receive/jumbo issue */
- if (adapter->flags & FLAG_HAS_ERT)
+ if ((adapter->flags & FLAG_HAS_ERT) ||
+ (adapter->hw.mac.type == e1000_pch2lan))
pm_qos_add_request(&adapter->netdev->pm_qos_req,
PM_QOS_CPU_DMA_LATENCY,
PM_QOS_DEFAULT_VALUE);
@@ -3639,7 +3699,8 @@ static int e1000_close(struct net_device *netdev)
if (adapter->flags & FLAG_HAS_AMT)
e1000_release_hw_control(adapter);
- if (adapter->flags & FLAG_HAS_ERT)
+ if ((adapter->flags & FLAG_HAS_ERT) ||
+ (adapter->hw.mac.type == e1000_pch2lan))
pm_qos_remove_request(&adapter->netdev->pm_qos_req);
pm_runtime_put_sync(&pdev->dev);
@@ -4255,6 +4316,16 @@ link_up:
/* Force detection of hung controller every watchdog period */
adapter->detect_tx_hung = 1;
+ /* flush partial descriptors to memory before detecting tx hang */
+ if (adapter->flags2 & FLAG2_DMA_BURST) {
+ ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD);
+ ew32(RDTR, adapter->rx_int_delay | E1000_RDTR_FPD);
+ /*
+ * no need to flush the writes because the timeout code does
+ * an er32 first thing
+ */
+ }
+
/*
* With 82571 controllers, LAA may be overwritten due to controller
* reset from the other port. Set the appropriate LAA in RAR[0]
@@ -4729,7 +4800,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
if (e1000_maybe_stop_tx(netdev, count + 2))
return NETDEV_TX_BUSY;
- if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+ if (vlan_tx_tag_present(skb)) {
tx_flags |= E1000_TX_FLAGS_VLAN;
tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
}
@@ -5712,8 +5783,10 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
netdev->vlan_features |= NETIF_F_HW_CSUM;
netdev->vlan_features |= NETIF_F_SG;
- if (pci_using_dac)
+ if (pci_using_dac) {
netdev->features |= NETIF_F_HIGHDMA;
+ netdev->vlan_features |= NETIF_F_HIGHDMA;
+ }
if (e1000e_enable_mng_pass_thru(&adapter->hw))
adapter->flags |= FLAG_MNG_PT_ENABLED;
@@ -5754,11 +5827,11 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
}
init_timer(&adapter->watchdog_timer);
- adapter->watchdog_timer.function = &e1000_watchdog;
+ 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.function = e1000_update_phy_info;
adapter->phy_info_timer.data = (unsigned long) adapter;
INIT_WORK(&adapter->reset_task, e1000_reset_task);
diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c
index 34aeec13bb16..3d36911f77f3 100644
--- a/drivers/net/e1000e/param.c
+++ b/drivers/net/e1000e/param.c
@@ -91,7 +91,6 @@ E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay");
* Valid Range: 0-65535
*/
E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
-#define DEFAULT_RDTR 0
#define MAX_RXDELAY 0xFFFF
#define MIN_RXDELAY 0
@@ -101,7 +100,6 @@ E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
* Valid Range: 0-65535
*/
E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
-#define DEFAULT_RADV 8
#define MAX_RXABSDELAY 0xFFFF
#define MIN_RXABSDELAY 0
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 8d97f168f018..7c826319ee5a 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -1457,11 +1457,11 @@ hardware_send_packet(struct net_device *dev, void *buf, short length)
if (net_debug > 5)
printk(KERN_DEBUG "%s: entering hardware_send_packet routine.\n", dev->name);
- /* determine how much of the transmit buffer space is available */
- if (lp->tx_end > lp->tx_start)
+ /* determine how much of the transmit buffer space is available */
+ if (lp->tx_end > lp->tx_start)
tx_available = lp->xmt_ram - (lp->tx_end - lp->tx_start);
- else if (lp->tx_end < lp->tx_start)
- tx_available = lp->tx_start - lp->tx_end;
+ else if (lp->tx_end < lp->tx_start)
+ tx_available = lp->tx_start - lp->tx_end;
else tx_available = lp->xmt_ram;
if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) >= tx_available) {
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 1846623c6ae6..8e745e74828d 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -396,7 +396,9 @@ struct ehea_port_res {
int swqe_ll_count;
u32 swqe_id_counter;
u64 tx_packets;
+ 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];
@@ -491,6 +493,8 @@ struct ehea_port {
u8 full_duplex;
u8 autoneg;
u8 num_def_qps;
+ wait_queue_head_t swqe_avail_wq;
+ wait_queue_head_t restart_wq;
};
struct port_res_cfg {
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 6372610ed240..182b2a7be8dc 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -180,7 +180,7 @@ static void ehea_update_firmware_handles(void)
num_portres * EHEA_NUM_PORTRES_FW_HANDLES;
if (num_fw_handles) {
- arr = kzalloc(num_fw_handles * sizeof(*arr), GFP_KERNEL);
+ arr = kcalloc(num_fw_handles, sizeof(*arr), GFP_KERNEL);
if (!arr)
goto out; /* Keep the existing array */
} else
@@ -265,7 +265,7 @@ static void ehea_update_bcmc_registrations(void)
}
if (num_registrations) {
- arr = kzalloc(num_registrations * sizeof(*arr), GFP_ATOMIC);
+ arr = kcalloc(num_registrations, sizeof(*arr), GFP_ATOMIC);
if (!arr)
goto out; /* Keep the existing array */
} else
@@ -330,7 +330,7 @@ static struct net_device_stats *ehea_get_stats(struct net_device *dev)
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;
+ u64 hret, rx_packets, tx_packets, rx_bytes = 0, tx_bytes = 0;
int i;
memset(stats, 0, sizeof(*stats));
@@ -353,18 +353,22 @@ static struct net_device_stats *ehea_get_stats(struct net_device *dev)
ehea_dump(cb2, sizeof(*cb2), "net_device_stats");
rx_packets = 0;
- for (i = 0; i < port->num_def_qps; i++)
+ 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++)
+ 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 = cb2->rxo;
- stats->tx_bytes = cb2->txo;
+ stats->rx_bytes = rx_bytes;
+ stats->tx_bytes = tx_bytes;
stats->rx_packets = rx_packets;
out_herr:
@@ -703,6 +707,7 @@ static int ehea_proc_rwqes(struct net_device *dev,
int skb_arr_rq2_len = pr->rq2_skba.len;
int skb_arr_rq3_len = pr->rq3_skba.len;
int processed, processed_rq1, processed_rq2, processed_rq3;
+ u64 processed_bytes = 0;
int wqe_index, last_wqe_index, rq, port_reset;
processed = processed_rq1 = processed_rq2 = processed_rq3 = 0;
@@ -760,6 +765,7 @@ static int ehea_proc_rwqes(struct net_device *dev,
processed_rq3++;
}
+ processed_bytes += skb->len;
ehea_proc_skb(pr, cqe, skb);
} else {
pr->p_stats.poll_receive_errors++;
@@ -775,6 +781,7 @@ static int ehea_proc_rwqes(struct net_device *dev,
lro_flush_all(&pr->lro_mgr);
pr->rx_packets += processed;
+ pr->rx_bytes += processed_bytes;
ehea_refill_rq1(pr, last_wqe_index, processed_rq1);
ehea_refill_rq2(pr, processed_rq2);
@@ -793,6 +800,7 @@ static void reset_sq_restart_flag(struct ehea_port *port)
struct ehea_port_res *pr = &port->port_res[i];
pr->sq_restart_flag = 0;
}
+ wake_up(&port->restart_wq);
}
static void check_sqs(struct ehea_port *port)
@@ -803,6 +811,7 @@ static void check_sqs(struct ehea_port *port)
for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
struct ehea_port_res *pr = &port->port_res[i];
+ int ret;
k = 0;
swqe = ehea_get_swqe(pr->qp, &swqe_index);
memset(swqe, 0, SWQE_HEADER_SIZE);
@@ -816,17 +825,16 @@ static void check_sqs(struct ehea_port *port)
ehea_post_swqe(pr->qp, swqe);
- while (pr->sq_restart_flag == 0) {
- msleep(5);
- if (++k == 100) {
- ehea_error("HW/SW queues out of sync");
- ehea_schedule_port_reset(pr->port);
- return;
- }
+ ret = wait_event_timeout(port->restart_wq,
+ pr->sq_restart_flag == 0,
+ msecs_to_jiffies(100));
+
+ if (!ret) {
+ ehea_error("HW/SW queues out of sync");
+ ehea_schedule_port_reset(pr->port);
+ return;
}
}
-
- return;
}
@@ -897,6 +905,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
pr->queue_stopped = 0;
}
spin_unlock_irqrestore(&pr->netif_queue, flags);
+ wake_up(&pr->port->swqe_avail_wq);
return cqe;
}
@@ -1507,9 +1516,20 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
enum ehea_eq_type eq_type = EHEA_EQ;
struct ehea_qp_init_attr *init_attr = NULL;
int ret = -EIO;
+ u64 tx_bytes, rx_bytes, tx_packets, rx_packets;
+
+ tx_bytes = pr->tx_bytes;
+ tx_packets = pr->tx_packets;
+ rx_bytes = pr->rx_bytes;
+ rx_packets = pr->rx_packets;
memset(pr, 0, sizeof(struct ehea_port_res));
+ pr->tx_bytes = rx_bytes;
+ pr->tx_packets = tx_packets;
+ pr->rx_bytes = rx_bytes;
+ pr->rx_packets = rx_packets;
+
pr->port = port;
spin_lock_init(&pr->xmit_lock);
spin_lock_init(&pr->netif_queue);
@@ -1923,7 +1943,7 @@ static void ehea_promiscuous(struct net_device *dev, int enable)
struct hcp_ehea_port_cb7 *cb7;
u64 hret;
- if ((enable && port->promisc) || (!enable && !port->promisc))
+ if (enable == port->promisc)
return;
cb7 = (void *)get_zeroed_page(GFP_ATOMIC);
@@ -2247,6 +2267,14 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
memset(swqe, 0, SWQE_HEADER_SIZE);
atomic_dec(&pr->swqe_avail);
+ if (vlan_tx_tag_present(skb)) {
+ swqe->tx_control |= EHEA_SWQE_VLAN_INSERT;
+ swqe->vlan_tag = vlan_tx_tag_get(skb);
+ }
+
+ pr->tx_packets++;
+ pr->tx_bytes += skb->len;
+
if (skb->len <= SWQE3_MAX_IMM) {
u32 sig_iv = port->sig_comp_iv;
u32 swqe_num = pr->swqe_id_counter;
@@ -2277,11 +2305,6 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
pr->swqe_id_counter += 1;
- if (port->vgrp && vlan_tx_tag_present(skb)) {
- swqe->tx_control |= EHEA_SWQE_VLAN_INSERT;
- swqe->vlan_tag = vlan_tx_tag_get(skb);
- }
-
if (netif_msg_tx_queued(port)) {
ehea_info("post swqe on QP %d", pr->qp->init_attr.qp_nr);
ehea_dump(swqe, 512, "swqe");
@@ -2293,7 +2316,6 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
ehea_post_swqe(pr->qp, swqe);
- pr->tx_packets++;
if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
spin_lock_irqsave(&pr->netif_queue, flags);
@@ -2661,6 +2683,9 @@ static int ehea_open(struct net_device *dev)
netif_start_queue(dev);
}
+ init_waitqueue_head(&port->swqe_avail_wq);
+ init_waitqueue_head(&port->restart_wq);
+
mutex_unlock(&port->port_lock);
return ret;
@@ -2733,13 +2758,15 @@ static void ehea_flush_sq(struct ehea_port *port)
for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
struct ehea_port_res *pr = &port->port_res[i];
int swqe_max = pr->sq_skba_size - 2 - pr->swqe_ll_count;
- int k = 0;
- while (atomic_read(&pr->swqe_avail) < swqe_max) {
- msleep(5);
- if (++k == 20) {
- ehea_error("WARNING: sq not flushed completely");
- break;
- }
+ int ret;
+
+ ret = wait_event_timeout(port->swqe_avail_wq,
+ atomic_read(&pr->swqe_avail) >= swqe_max,
+ msecs_to_jiffies(100));
+
+ if (!ret) {
+ ehea_error("WARNING: sq not flushed completely");
+ break;
}
}
}
@@ -3728,7 +3755,7 @@ int __init ehea_module_init(void)
if (ret)
ehea_info("failed registering memory remove notifier");
- ret = crash_shutdown_register(&ehea_crash_handler);
+ ret = crash_shutdown_register(ehea_crash_handler);
if (ret)
ehea_info("failed registering crash handler");
@@ -3753,7 +3780,7 @@ out3:
out2:
unregister_memory_notifier(&ehea_mem_nb);
unregister_reboot_notifier(&ehea_reboot_nb);
- crash_shutdown_unregister(&ehea_crash_handler);
+ crash_shutdown_unregister(ehea_crash_handler);
out:
return ret;
}
@@ -3766,7 +3793,7 @@ static void __exit ehea_module_exit(void)
driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities);
ibmebus_unregister_driver(&ehea_driver);
unregister_reboot_notifier(&ehea_reboot_nb);
- ret = crash_shutdown_unregister(&ehea_crash_handler);
+ ret = crash_shutdown_unregister(ehea_crash_handler);
if (ret)
ehea_info("failed unregistering crash handler");
unregister_memory_notifier(&ehea_mem_nb);
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index f239aa8c6f4c..c91d364c5527 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -32,7 +32,7 @@
#define DRV_NAME "enic"
#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver"
-#define DRV_VERSION "1.4.1.1"
+#define DRV_VERSION "1.4.1.6"
#define DRV_COPYRIGHT "Copyright 2008-2010 Cisco Systems, Inc"
#define ENIC_BARS_MAX 6
@@ -42,25 +42,6 @@
#define ENIC_CQ_MAX (ENIC_WQ_MAX + ENIC_RQ_MAX)
#define ENIC_INTR_MAX (ENIC_CQ_MAX + 2)
-enum enic_cq_index {
- ENIC_CQ_RQ,
- ENIC_CQ_WQ,
-};
-
-enum enic_intx_intr_index {
- ENIC_INTX_WQ_RQ,
- ENIC_INTX_ERR,
- ENIC_INTX_NOTIFY,
-};
-
-enum enic_msix_intr_index {
- ENIC_MSIX_RQ,
- ENIC_MSIX_WQ,
- ENIC_MSIX_ERR,
- ENIC_MSIX_NOTIFY,
- ENIC_MSIX_MAX,
-};
-
struct enic_msix_entry {
int requested;
char devname[IFNAMSIZ];
@@ -91,8 +72,8 @@ struct enic {
struct vnic_dev *vdev;
struct timer_list notify_timer;
struct work_struct reset;
- struct msix_entry msix_entry[ENIC_MSIX_MAX];
- struct enic_msix_entry msix[ENIC_MSIX_MAX];
+ struct msix_entry msix_entry[ENIC_INTR_MAX];
+ struct enic_msix_entry msix[ENIC_INTR_MAX];
u32 msg_enable;
spinlock_t devcmd_lock;
u8 mac_addr[ETH_ALEN];
@@ -119,7 +100,7 @@ struct enic {
int (*rq_alloc_buf)(struct vnic_rq *rq);
u64 rq_truncated_pkts;
u64 rq_bad_fcs;
- struct napi_struct napi;
+ struct napi_struct napi[ENIC_RQ_MAX];
/* interrupt resource cache line section */
____cacheline_aligned struct vnic_intr intr[ENIC_INTR_MAX];
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index 9aab85366d21..a466ef91dd43 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -122,6 +122,51 @@ static int enic_is_dynamic(struct enic *enic)
return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_DYN;
}
+static inline unsigned int enic_cq_rq(struct enic *enic, unsigned int rq)
+{
+ return rq;
+}
+
+static inline unsigned int enic_cq_wq(struct enic *enic, unsigned int wq)
+{
+ return enic->rq_count + wq;
+}
+
+static inline unsigned int enic_legacy_io_intr(void)
+{
+ return 0;
+}
+
+static inline unsigned int enic_legacy_err_intr(void)
+{
+ return 1;
+}
+
+static inline unsigned int enic_legacy_notify_intr(void)
+{
+ return 2;
+}
+
+static inline unsigned int enic_msix_rq_intr(struct enic *enic, unsigned int rq)
+{
+ return rq;
+}
+
+static inline unsigned int enic_msix_wq_intr(struct enic *enic, unsigned int wq)
+{
+ return enic->rq_count + wq;
+}
+
+static inline unsigned int enic_msix_err_intr(struct enic *enic)
+{
+ return enic->rq_count + enic->wq_count;
+}
+
+static inline unsigned int enic_msix_notify_intr(struct enic *enic)
+{
+ return enic->rq_count + enic->wq_count + 1;
+}
+
static int enic_get_settings(struct net_device *netdev,
struct ethtool_cmd *ecmd)
{
@@ -306,6 +351,7 @@ static int enic_set_coalesce(struct net_device *netdev,
struct enic *enic = netdev_priv(netdev);
u32 tx_coalesce_usecs;
u32 rx_coalesce_usecs;
+ unsigned int i, intr;
tx_coalesce_usecs = min_t(u32,
INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
@@ -319,7 +365,8 @@ static int enic_set_coalesce(struct net_device *netdev,
if (tx_coalesce_usecs != rx_coalesce_usecs)
return -EINVAL;
- vnic_intr_coalescing_timer_set(&enic->intr[ENIC_INTX_WQ_RQ],
+ intr = enic_legacy_io_intr();
+ vnic_intr_coalescing_timer_set(&enic->intr[intr],
INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
break;
case VNIC_DEV_INTR_MODE_MSI:
@@ -330,10 +377,18 @@ static int enic_set_coalesce(struct net_device *netdev,
INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
break;
case VNIC_DEV_INTR_MODE_MSIX:
- vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_WQ],
- INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
- vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_RQ],
- INTR_COALESCE_USEC_TO_HW(rx_coalesce_usecs));
+ for (i = 0; i < enic->wq_count; i++) {
+ intr = enic_msix_wq_intr(enic, i);
+ vnic_intr_coalescing_timer_set(&enic->intr[intr],
+ INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
+ }
+
+ for (i = 0; i < enic->rq_count; i++) {
+ intr = enic_msix_rq_intr(enic, i);
+ vnic_intr_coalescing_timer_set(&enic->intr[intr],
+ INTR_COALESCE_USEC_TO_HW(rx_coalesce_usecs));
+ }
+
break;
default:
break;
@@ -482,34 +537,37 @@ static irqreturn_t enic_isr_legacy(int irq, void *data)
{
struct net_device *netdev = data;
struct enic *enic = netdev_priv(netdev);
+ unsigned int io_intr = enic_legacy_io_intr();
+ unsigned int err_intr = enic_legacy_err_intr();
+ unsigned int notify_intr = enic_legacy_notify_intr();
u32 pba;
- vnic_intr_mask(&enic->intr[ENIC_INTX_WQ_RQ]);
+ vnic_intr_mask(&enic->intr[io_intr]);
pba = vnic_intr_legacy_pba(enic->legacy_pba);
if (!pba) {
- vnic_intr_unmask(&enic->intr[ENIC_INTX_WQ_RQ]);
+ vnic_intr_unmask(&enic->intr[io_intr]);
return IRQ_NONE; /* not our interrupt */
}
- if (ENIC_TEST_INTR(pba, ENIC_INTX_NOTIFY)) {
- vnic_intr_return_all_credits(&enic->intr[ENIC_INTX_NOTIFY]);
+ if (ENIC_TEST_INTR(pba, notify_intr)) {
+ vnic_intr_return_all_credits(&enic->intr[notify_intr]);
enic_notify_check(enic);
}
- if (ENIC_TEST_INTR(pba, ENIC_INTX_ERR)) {
- vnic_intr_return_all_credits(&enic->intr[ENIC_INTX_ERR]);
+ if (ENIC_TEST_INTR(pba, err_intr)) {
+ vnic_intr_return_all_credits(&enic->intr[err_intr]);
enic_log_q_error(enic);
/* schedule recovery from WQ/RQ error */
schedule_work(&enic->reset);
return IRQ_HANDLED;
}
- if (ENIC_TEST_INTR(pba, ENIC_INTX_WQ_RQ)) {
- if (napi_schedule_prep(&enic->napi))
- __napi_schedule(&enic->napi);
+ if (ENIC_TEST_INTR(pba, io_intr)) {
+ if (napi_schedule_prep(&enic->napi[0]))
+ __napi_schedule(&enic->napi[0]);
} else {
- vnic_intr_unmask(&enic->intr[ENIC_INTX_WQ_RQ]);
+ vnic_intr_unmask(&enic->intr[io_intr]);
}
return IRQ_HANDLED;
@@ -535,17 +593,17 @@ static irqreturn_t enic_isr_msi(int irq, void *data)
* writes).
*/
- napi_schedule(&enic->napi);
+ napi_schedule(&enic->napi[0]);
return IRQ_HANDLED;
}
static irqreturn_t enic_isr_msix_rq(int irq, void *data)
{
- struct enic *enic = data;
+ struct napi_struct *napi = data;
/* schedule NAPI polling for RQ cleanup */
- napi_schedule(&enic->napi);
+ napi_schedule(napi);
return IRQ_HANDLED;
}
@@ -553,13 +611,15 @@ static irqreturn_t enic_isr_msix_rq(int irq, void *data)
static irqreturn_t enic_isr_msix_wq(int irq, void *data)
{
struct enic *enic = data;
+ unsigned int cq = enic_cq_wq(enic, 0);
+ unsigned int intr = enic_msix_wq_intr(enic, 0);
unsigned int wq_work_to_do = -1; /* no limit */
unsigned int wq_work_done;
- wq_work_done = vnic_cq_service(&enic->cq[ENIC_CQ_WQ],
+ wq_work_done = vnic_cq_service(&enic->cq[cq],
wq_work_to_do, enic_wq_service, NULL);
- vnic_intr_return_credits(&enic->intr[ENIC_MSIX_WQ],
+ vnic_intr_return_credits(&enic->intr[intr],
wq_work_done,
1 /* unmask intr */,
1 /* reset intr timer */);
@@ -570,8 +630,9 @@ static irqreturn_t enic_isr_msix_wq(int irq, void *data)
static irqreturn_t enic_isr_msix_err(int irq, void *data)
{
struct enic *enic = data;
+ unsigned int intr = enic_msix_err_intr(enic);
- vnic_intr_return_all_credits(&enic->intr[ENIC_MSIX_ERR]);
+ vnic_intr_return_all_credits(&enic->intr[intr]);
enic_log_q_error(enic);
@@ -584,8 +645,9 @@ static irqreturn_t enic_isr_msix_err(int irq, void *data)
static irqreturn_t enic_isr_msix_notify(int irq, void *data)
{
struct enic *enic = data;
+ unsigned int intr = enic_msix_notify_intr(enic);
- vnic_intr_return_all_credits(&enic->intr[ENIC_MSIX_NOTIFY]);
+ vnic_intr_return_all_credits(&enic->intr[intr]);
enic_notify_check(enic);
return IRQ_HANDLED;
@@ -743,7 +805,7 @@ static inline void enic_queue_wq_skb(struct enic *enic,
int vlan_tag_insert = 0;
int loopback = 0;
- if (enic->vlan_group && vlan_tx_tag_present(skb)) {
+ if (vlan_tx_tag_present(skb)) {
/* VLAN tag from trunking driver */
vlan_tag_insert = 1;
vlan_tag = vlan_tx_tag_get(skb);
@@ -911,7 +973,20 @@ static int enic_set_mac_address_dynamic(struct net_device *netdev, void *p)
static int enic_set_mac_address(struct net_device *netdev, void *p)
{
- return -EOPNOTSUPP;
+ struct sockaddr *saddr = p;
+ char *addr = saddr->sa_data;
+ struct enic *enic = netdev_priv(netdev);
+ int err;
+
+ err = enic_dev_del_station_addr(enic);
+ if (err)
+ return err;
+
+ err = enic_set_mac_addr(netdev, addr);
+ if (err)
+ return err;
+
+ return enic_dev_add_station_addr(enic);
}
static int enic_dev_packet_filter(struct enic *enic, int directed,
@@ -1407,8 +1482,8 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
(vlan_tci & CQ_ENET_RQ_DESC_VLAN_TCI_VLAN_MASK)) {
if (netdev->features & NETIF_F_GRO)
- vlan_gro_receive(&enic->napi, enic->vlan_group,
- vlan_tci, skb);
+ vlan_gro_receive(&enic->napi[q_number],
+ enic->vlan_group, vlan_tci, skb);
else
vlan_hwaccel_receive_skb(skb,
enic->vlan_group, vlan_tci);
@@ -1416,12 +1491,11 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
} else {
if (netdev->features & NETIF_F_GRO)
- napi_gro_receive(&enic->napi, skb);
+ napi_gro_receive(&enic->napi[q_number], skb);
else
netif_receive_skb(skb);
}
-
} else {
/* Buffer overflow
@@ -1445,7 +1519,11 @@ static int enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
static int enic_poll(struct napi_struct *napi, int budget)
{
- struct enic *enic = container_of(napi, struct enic, napi);
+ struct net_device *netdev = napi->dev;
+ struct enic *enic = netdev_priv(netdev);
+ unsigned int cq_rq = enic_cq_rq(enic, 0);
+ unsigned int cq_wq = enic_cq_wq(enic, 0);
+ unsigned int intr = enic_legacy_io_intr();
unsigned int rq_work_to_do = budget;
unsigned int wq_work_to_do = -1; /* no limit */
unsigned int work_done, rq_work_done, wq_work_done;
@@ -1454,10 +1532,10 @@ static int enic_poll(struct napi_struct *napi, int budget)
/* Service RQ (first) and WQ
*/
- rq_work_done = vnic_cq_service(&enic->cq[ENIC_CQ_RQ],
+ rq_work_done = vnic_cq_service(&enic->cq[cq_rq],
rq_work_to_do, enic_rq_service, NULL);
- wq_work_done = vnic_cq_service(&enic->cq[ENIC_CQ_WQ],
+ wq_work_done = vnic_cq_service(&enic->cq[cq_wq],
wq_work_to_do, enic_wq_service, NULL);
/* Accumulate intr event credits for this polling
@@ -1468,7 +1546,7 @@ static int enic_poll(struct napi_struct *napi, int budget)
work_done = rq_work_done + wq_work_done;
if (work_done > 0)
- vnic_intr_return_credits(&enic->intr[ENIC_INTX_WQ_RQ],
+ vnic_intr_return_credits(&enic->intr[intr],
work_done,
0 /* don't unmask intr */,
0 /* don't reset intr timer */);
@@ -1489,7 +1567,7 @@ static int enic_poll(struct napi_struct *napi, int budget)
*/
napi_complete(napi);
- vnic_intr_unmask(&enic->intr[ENIC_INTX_WQ_RQ]);
+ vnic_intr_unmask(&enic->intr[intr]);
}
return rq_work_done;
@@ -1497,7 +1575,11 @@ static int enic_poll(struct napi_struct *napi, int budget)
static int enic_poll_msix(struct napi_struct *napi, int budget)
{
- struct enic *enic = container_of(napi, struct enic, napi);
+ struct net_device *netdev = napi->dev;
+ struct enic *enic = netdev_priv(netdev);
+ unsigned int rq = (napi - &enic->napi[0]);
+ unsigned int cq = enic_cq_rq(enic, rq);
+ unsigned int intr = enic_msix_rq_intr(enic, rq);
unsigned int work_to_do = budget;
unsigned int work_done;
int err;
@@ -1505,7 +1587,7 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
/* Service RQ
*/
- work_done = vnic_cq_service(&enic->cq[ENIC_CQ_RQ],
+ work_done = vnic_cq_service(&enic->cq[cq],
work_to_do, enic_rq_service, NULL);
/* Return intr event credits for this polling
@@ -1514,12 +1596,12 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
*/
if (work_done > 0)
- vnic_intr_return_credits(&enic->intr[ENIC_MSIX_RQ],
+ vnic_intr_return_credits(&enic->intr[intr],
work_done,
0 /* don't unmask intr */,
0 /* don't reset intr timer */);
- err = vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf);
+ err = vnic_rq_fill(&enic->rq[rq], enic->rq_alloc_buf);
/* Buffer allocation failed. Stay in polling mode
* so we can try to fill the ring again.
@@ -1535,7 +1617,7 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
*/
napi_complete(napi);
- vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]);
+ vnic_intr_unmask(&enic->intr[intr]);
}
return work_done;
@@ -1577,7 +1659,7 @@ static void enic_free_intr(struct enic *enic)
static int enic_request_intr(struct enic *enic)
{
struct net_device *netdev = enic->netdev;
- unsigned int i;
+ unsigned int i, intr;
int err = 0;
switch (vnic_dev_get_intr_mode(enic->vdev)) {
@@ -1596,27 +1678,38 @@ static int enic_request_intr(struct enic *enic)
case VNIC_DEV_INTR_MODE_MSIX:
- sprintf(enic->msix[ENIC_MSIX_RQ].devname,
- "%.11s-rx-0", netdev->name);
- enic->msix[ENIC_MSIX_RQ].isr = enic_isr_msix_rq;
- enic->msix[ENIC_MSIX_RQ].devid = enic;
+ for (i = 0; i < enic->rq_count; i++) {
+ intr = enic_msix_rq_intr(enic, i);
+ sprintf(enic->msix[intr].devname,
+ "%.11s-rx-%d", netdev->name, i);
+ enic->msix[intr].isr = enic_isr_msix_rq;
+ enic->msix[intr].devid = &enic->napi[i];
+ }
- sprintf(enic->msix[ENIC_MSIX_WQ].devname,
- "%.11s-tx-0", netdev->name);
- enic->msix[ENIC_MSIX_WQ].isr = enic_isr_msix_wq;
- enic->msix[ENIC_MSIX_WQ].devid = enic;
+ for (i = 0; i < enic->wq_count; i++) {
+ intr = enic_msix_wq_intr(enic, i);
+ sprintf(enic->msix[intr].devname,
+ "%.11s-tx-%d", netdev->name, i);
+ enic->msix[intr].isr = enic_isr_msix_wq;
+ enic->msix[intr].devid = enic;
+ }
- sprintf(enic->msix[ENIC_MSIX_ERR].devname,
+ intr = enic_msix_err_intr(enic);
+ sprintf(enic->msix[intr].devname,
"%.11s-err", netdev->name);
- enic->msix[ENIC_MSIX_ERR].isr = enic_isr_msix_err;
- enic->msix[ENIC_MSIX_ERR].devid = enic;
+ enic->msix[intr].isr = enic_isr_msix_err;
+ enic->msix[intr].devid = enic;
- sprintf(enic->msix[ENIC_MSIX_NOTIFY].devname,
+ intr = enic_msix_notify_intr(enic);
+ sprintf(enic->msix[intr].devname,
"%.11s-notify", netdev->name);
- enic->msix[ENIC_MSIX_NOTIFY].isr = enic_isr_msix_notify;
- enic->msix[ENIC_MSIX_NOTIFY].devid = enic;
+ enic->msix[intr].isr = enic_isr_msix_notify;
+ enic->msix[intr].devid = enic;
+
+ for (i = 0; i < ARRAY_SIZE(enic->msix); i++)
+ enic->msix[i].requested = 0;
- for (i = 0; i < ARRAY_SIZE(enic->msix); i++) {
+ for (i = 0; i < enic->intr_count; i++) {
err = request_irq(enic->msix_entry[i].vector,
enic->msix[i].isr, 0,
enic->msix[i].devname,
@@ -1662,10 +1755,12 @@ static int enic_dev_notify_set(struct enic *enic)
spin_lock(&enic->devcmd_lock);
switch (vnic_dev_get_intr_mode(enic->vdev)) {
case VNIC_DEV_INTR_MODE_INTX:
- err = vnic_dev_notify_set(enic->vdev, ENIC_INTX_NOTIFY);
+ err = vnic_dev_notify_set(enic->vdev,
+ enic_legacy_notify_intr());
break;
case VNIC_DEV_INTR_MODE_MSIX:
- err = vnic_dev_notify_set(enic->vdev, ENIC_MSIX_NOTIFY);
+ err = vnic_dev_notify_set(enic->vdev,
+ enic_msix_notify_intr(enic));
break;
default:
err = vnic_dev_notify_set(enic->vdev, -1 /* no intr */);
@@ -1692,7 +1787,7 @@ static int enic_dev_enable(struct enic *enic)
int err;
spin_lock(&enic->devcmd_lock);
- err = vnic_dev_enable(enic->vdev);
+ err = vnic_dev_enable_wait(enic->vdev);
spin_unlock(&enic->devcmd_lock);
return err;
@@ -1760,7 +1855,10 @@ static int enic_open(struct net_device *netdev)
enic_set_multicast_list(netdev);
netif_wake_queue(netdev);
- napi_enable(&enic->napi);
+
+ for (i = 0; i < enic->rq_count; i++)
+ napi_enable(&enic->napi[i]);
+
enic_dev_enable(enic);
for (i = 0; i < enic->intr_count; i++)
@@ -1795,7 +1893,10 @@ static int enic_stop(struct net_device *netdev)
del_timer_sync(&enic->notify_timer);
enic_dev_disable(enic);
- napi_disable(&enic->napi);
+
+ for (i = 0; i < enic->rq_count; i++)
+ napi_disable(&enic->napi[i]);
+
netif_carrier_off(netdev);
netif_tx_disable(netdev);
enic_dev_del_station_addr(enic);
@@ -1855,11 +1956,16 @@ static void enic_poll_controller(struct net_device *netdev)
{
struct enic *enic = netdev_priv(netdev);
struct vnic_dev *vdev = enic->vdev;
+ unsigned int i, intr;
switch (vnic_dev_get_intr_mode(vdev)) {
case VNIC_DEV_INTR_MODE_MSIX:
- enic_isr_msix_rq(enic->pdev->irq, enic);
- enic_isr_msix_wq(enic->pdev->irq, enic);
+ for (i = 0; i < enic->rq_count; i++) {
+ intr = enic_msix_rq_intr(enic, i);
+ enic_isr_msix_rq(enic->msix_entry[intr].vector, enic);
+ }
+ intr = enic_msix_wq_intr(enic, i);
+ enic_isr_msix_wq(enic->msix_entry[intr].vector, enic);
break;
case VNIC_DEV_INTR_MODE_MSI:
enic_isr_msi(enic->pdev->irq, enic);
@@ -1934,19 +2040,73 @@ static int enic_dev_hang_reset(struct enic *enic)
return err;
}
-static int enic_set_niccfg(struct enic *enic)
+static int enic_set_rsskey(struct enic *enic)
+{
+ u64 rss_key_buf_pa;
+ union vnic_rss_key *rss_key_buf_va = NULL;
+ union vnic_rss_key rss_key = {
+ .key[0].b = {85, 67, 83, 97, 119, 101, 115, 111, 109, 101},
+ .key[1].b = {80, 65, 76, 79, 117, 110, 105, 113, 117, 101},
+ .key[2].b = {76, 73, 78, 85, 88, 114, 111, 99, 107, 115},
+ .key[3].b = {69, 78, 73, 67, 105, 115, 99, 111, 111, 108},
+ };
+ int err;
+
+ rss_key_buf_va = pci_alloc_consistent(enic->pdev,
+ sizeof(union vnic_rss_key), &rss_key_buf_pa);
+ if (!rss_key_buf_va)
+ return -ENOMEM;
+
+ memcpy(rss_key_buf_va, &rss_key, sizeof(union vnic_rss_key));
+
+ spin_lock(&enic->devcmd_lock);
+ err = enic_set_rss_key(enic,
+ rss_key_buf_pa,
+ sizeof(union vnic_rss_key));
+ spin_unlock(&enic->devcmd_lock);
+
+ pci_free_consistent(enic->pdev, sizeof(union vnic_rss_key),
+ rss_key_buf_va, rss_key_buf_pa);
+
+ return err;
+}
+
+static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
+{
+ u64 rss_cpu_buf_pa;
+ union vnic_rss_cpu *rss_cpu_buf_va = NULL;
+ unsigned int i;
+ int err;
+
+ rss_cpu_buf_va = pci_alloc_consistent(enic->pdev,
+ sizeof(union vnic_rss_cpu), &rss_cpu_buf_pa);
+ if (!rss_cpu_buf_va)
+ return -ENOMEM;
+
+ for (i = 0; i < (1 << rss_hash_bits); i++)
+ (*rss_cpu_buf_va).cpu[i/4].b[i%4] = i % enic->rq_count;
+
+ spin_lock(&enic->devcmd_lock);
+ err = enic_set_rss_cpu(enic,
+ rss_cpu_buf_pa,
+ sizeof(union vnic_rss_cpu));
+ spin_unlock(&enic->devcmd_lock);
+
+ pci_free_consistent(enic->pdev, sizeof(union vnic_rss_cpu),
+ rss_cpu_buf_va, rss_cpu_buf_pa);
+
+ return err;
+}
+
+static int enic_set_niccfg(struct enic *enic, u8 rss_default_cpu,
+ u8 rss_hash_type, u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable)
{
- const u8 rss_default_cpu = 0;
- const u8 rss_hash_type = 0;
- const u8 rss_hash_bits = 0;
- const u8 rss_base_cpu = 0;
- const u8 rss_enable = 0;
const u8 tso_ipid_split_en = 0;
const u8 ig_vlan_strip_en = 1;
int err;
- /* Enable VLAN tag stripping. RSS not enabled (yet).
- */
+ /* Enable VLAN tag stripping.
+ */
spin_lock(&enic->devcmd_lock);
err = enic_set_nic_cfg(enic,
@@ -1959,6 +2119,35 @@ static int enic_set_niccfg(struct enic *enic)
return err;
}
+static int enic_set_rss_nic_cfg(struct enic *enic)
+{
+ struct device *dev = enic_get_dev(enic);
+ const u8 rss_default_cpu = 0;
+ const u8 rss_hash_type = NIC_CFG_RSS_HASH_TYPE_IPV4 |
+ NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 |
+ NIC_CFG_RSS_HASH_TYPE_IPV6 |
+ NIC_CFG_RSS_HASH_TYPE_TCP_IPV6;
+ const u8 rss_hash_bits = 7;
+ const u8 rss_base_cpu = 0;
+ u8 rss_enable = ENIC_SETTING(enic, RSS) && (enic->rq_count > 1);
+
+ if (rss_enable) {
+ if (!enic_set_rsskey(enic)) {
+ if (enic_set_rsscpu(enic, rss_hash_bits)) {
+ rss_enable = 0;
+ dev_warn(dev, "RSS disabled, "
+ "Failed to set RSS cpu indirection table.");
+ }
+ } else {
+ rss_enable = 0;
+ dev_warn(dev, "RSS disabled, Failed to set RSS key.\n");
+ }
+ }
+
+ return enic_set_niccfg(enic, rss_default_cpu, rss_hash_type,
+ rss_hash_bits, rss_base_cpu, rss_enable);
+}
+
static int enic_dev_hang_notify(struct enic *enic)
{
int err;
@@ -1970,7 +2159,7 @@ static int enic_dev_hang_notify(struct enic *enic)
return err;
}
-int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic)
+static int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic)
{
int err;
@@ -1996,7 +2185,7 @@ static void enic_reset(struct work_struct *work)
enic_dev_hang_reset(enic);
enic_reset_multicast_list(enic);
enic_init_vnic_resources(enic);
- enic_set_niccfg(enic);
+ enic_set_rss_nic_cfg(enic);
enic_dev_set_ig_vlan_rewrite_mode(enic);
enic_open(enic->netdev);
@@ -2005,12 +2194,12 @@ static void enic_reset(struct work_struct *work)
static int enic_set_intr_mode(struct enic *enic)
{
- unsigned int n = 1;
+ unsigned int n = min_t(unsigned int, enic->rq_count, ENIC_RQ_MAX);
unsigned int m = 1;
unsigned int i;
/* Set interrupt mode (INTx, MSI, MSI-X) depending
- * system capabilities.
+ * on system capabilities.
*
* Try MSI-X first
*
@@ -2023,21 +2212,47 @@ static int enic_set_intr_mode(struct enic *enic)
for (i = 0; i < n + m + 2; i++)
enic->msix_entry[i].entry = i;
- if (enic->config.intr_mode < 1 &&
+ /* Use multiple RQs if RSS is enabled
+ */
+
+ if (ENIC_SETTING(enic, RSS) &&
+ enic->config.intr_mode < 1 &&
enic->rq_count >= n &&
enic->wq_count >= m &&
enic->cq_count >= n + m &&
- enic->intr_count >= n + m + 2 &&
- !pci_enable_msix(enic->pdev, enic->msix_entry, n + m + 2)) {
+ enic->intr_count >= n + m + 2) {
- enic->rq_count = n;
- enic->wq_count = m;
- enic->cq_count = n + m;
- enic->intr_count = n + m + 2;
+ if (!pci_enable_msix(enic->pdev, enic->msix_entry, n + m + 2)) {
- vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_MSIX);
+ enic->rq_count = n;
+ enic->wq_count = m;
+ enic->cq_count = n + m;
+ enic->intr_count = n + m + 2;
- return 0;
+ vnic_dev_set_intr_mode(enic->vdev,
+ VNIC_DEV_INTR_MODE_MSIX);
+
+ return 0;
+ }
+ }
+
+ if (enic->config.intr_mode < 1 &&
+ enic->rq_count >= 1 &&
+ enic->wq_count >= m &&
+ enic->cq_count >= 1 + m &&
+ enic->intr_count >= 1 + m + 2) {
+ if (!pci_enable_msix(enic->pdev, enic->msix_entry, 1 + m + 2)) {
+
+ enic->rq_count = 1;
+ enic->wq_count = m;
+ enic->cq_count = 1 + m;
+ enic->intr_count = 1 + m + 2;
+
+ vnic_dev_set_intr_mode(enic->vdev,
+ VNIC_DEV_INTR_MODE_MSIX);
+
+ return 0;
+ }
}
/* Next try MSI
@@ -2145,28 +2360,22 @@ static const struct net_device_ops enic_netdev_ops = {
#endif
};
-void enic_dev_deinit(struct enic *enic)
+static void enic_dev_deinit(struct enic *enic)
{
- netif_napi_del(&enic->napi);
- enic_free_vnic_resources(enic);
- enic_clear_intr_mode(enic);
-}
-
-static int enic_dev_stats_clear(struct enic *enic)
-{
- int err;
+ unsigned int i;
- spin_lock(&enic->devcmd_lock);
- err = vnic_dev_stats_clear(enic->vdev);
- spin_unlock(&enic->devcmd_lock);
+ for (i = 0; i < enic->rq_count; i++)
+ netif_napi_del(&enic->napi[i]);
- return err;
+ enic_free_vnic_resources(enic);
+ enic_clear_intr_mode(enic);
}
-int enic_dev_init(struct enic *enic)
+static int enic_dev_init(struct enic *enic)
{
struct device *dev = enic_get_dev(enic);
struct net_device *netdev = enic->netdev;
+ unsigned int i;
int err;
/* Get vNIC configuration
@@ -2205,17 +2414,13 @@ int enic_dev_init(struct enic *enic)
enic_init_vnic_resources(enic);
- /* Clear LIF stats
- */
- enic_dev_stats_clear(enic);
-
err = enic_set_rq_alloc_buf(enic);
if (err) {
dev_err(dev, "Failed to set RQ buffer allocator, aborting\n");
goto err_out_free_vnic_resources;
}
- err = enic_set_niccfg(enic);
+ err = enic_set_rss_nic_cfg(enic);
if (err) {
dev_err(dev, "Failed to config nic, aborting\n");
goto err_out_free_vnic_resources;
@@ -2223,17 +2428,19 @@ int enic_dev_init(struct enic *enic)
err = enic_dev_set_ig_vlan_rewrite_mode(enic);
if (err) {
- netdev_err(netdev,
+ dev_err(dev,
"Failed to set ingress vlan rewrite mode, aborting.\n");
goto err_out_free_vnic_resources;
}
switch (vnic_dev_get_intr_mode(enic->vdev)) {
default:
- netif_napi_add(netdev, &enic->napi, enic_poll, 64);
+ netif_napi_add(netdev, &enic->napi[0], enic_poll, 64);
break;
case VNIC_DEV_INTR_MODE_MSIX:
- netif_napi_add(netdev, &enic->napi, enic_poll_msix, 64);
+ for (i = 0; i < enic->rq_count; i++)
+ netif_napi_add(netdev, &enic->napi[i],
+ enic_poll_msix, 64);
break;
}
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index 29ede8a17a2c..f111a37419ce 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/enic/enic_res.c
@@ -94,13 +94,14 @@ int enic_get_vnic_config(struct enic *enic)
INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
c->intr_timer_usec);
- dev_info(enic_get_dev(enic), "vNIC MAC addr %pM wq/rq %d/%d\n",
- enic->mac_addr, c->wq_desc_count, c->rq_desc_count);
- dev_info(enic_get_dev(enic), "vNIC mtu %d csum tx/rx %d/%d "
- "tso/lro %d/%d intr timer %d usec\n",
- c->mtu, ENIC_SETTING(enic, TXCSUM),
- ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO),
- ENIC_SETTING(enic, LRO), c->intr_timer_usec);
+ dev_info(enic_get_dev(enic),
+ "vNIC MAC addr %pM wq/rq %d/%d mtu %d\n",
+ enic->mac_addr, c->wq_desc_count, c->rq_desc_count, c->mtu);
+ dev_info(enic_get_dev(enic), "vNIC csum tx/rx %d/%d "
+ "tso/lro %d/%d intr timer %d usec rss %d\n",
+ ENIC_SETTING(enic, TXCSUM), ENIC_SETTING(enic, RXCSUM),
+ ENIC_SETTING(enic, TSO), ENIC_SETTING(enic, LRO),
+ c->intr_timer_usec, ENIC_SETTING(enic, RSS));
return 0;
}
@@ -181,18 +182,11 @@ void enic_free_vnic_resources(struct enic *enic)
void enic_get_res_counts(struct enic *enic)
{
- enic->wq_count = min_t(int,
- vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ),
- ENIC_WQ_MAX);
- enic->rq_count = min_t(int,
- vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ),
- ENIC_RQ_MAX);
- enic->cq_count = min_t(int,
- vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ),
- ENIC_CQ_MAX);
- enic->intr_count = min_t(int,
- vnic_dev_get_res_count(enic->vdev, RES_TYPE_INTR_CTRL),
- ENIC_INTR_MAX);
+ enic->wq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ);
+ enic->rq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ);
+ enic->cq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ);
+ enic->intr_count = vnic_dev_get_res_count(enic->vdev,
+ RES_TYPE_INTR_CTRL);
dev_info(enic_get_dev(enic),
"vNIC resources avail: wq %d rq %d cq %d intr %d\n",
diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h
index 83bd172c356c..9a103d9ef9e2 100644
--- a/drivers/net/enic/enic_res.h
+++ b/drivers/net/enic/enic_res.h
@@ -30,7 +30,7 @@
#define ENIC_MIN_RQ_DESCS 64
#define ENIC_MAX_RQ_DESCS 4096
-#define ENIC_MIN_MTU 576 /* minimum for IPv4 */
+#define ENIC_MIN_MTU 68
#define ENIC_MAX_MTU 9000
#define ENIC_MULTICAST_PERFECT_FILTERS 32
diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c
index 6a5b578a69e1..fb35d8b17668 100644
--- a/drivers/net/enic/vnic_dev.c
+++ b/drivers/net/enic/vnic_dev.c
@@ -74,6 +74,7 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
struct vnic_dev_bar *bar, unsigned int num_bars)
{
struct vnic_resource_header __iomem *rh;
+ struct mgmt_barmap_hdr __iomem *mrh;
struct vnic_resource __iomem *r;
u8 type;
@@ -85,22 +86,32 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
return -EINVAL;
}
- rh = bar->vaddr;
+ rh = bar->vaddr;
+ mrh = bar->vaddr;
if (!rh) {
pr_err("vNIC BAR0 res hdr not mem-mapped\n");
return -EINVAL;
}
- if (ioread32(&rh->magic) != VNIC_RES_MAGIC ||
- ioread32(&rh->version) != VNIC_RES_VERSION) {
- pr_err("vNIC BAR0 res magic/version error "
- "exp (%lx/%lx) curr (%x/%x)\n",
+ /* Check for mgmt vnic in addition to normal vnic */
+ if ((ioread32(&rh->magic) != VNIC_RES_MAGIC) ||
+ (ioread32(&rh->version) != VNIC_RES_VERSION)) {
+ if ((ioread32(&mrh->magic) != MGMTVNIC_MAGIC) ||
+ (ioread32(&mrh->version) != MGMTVNIC_VERSION)) {
+ pr_err("vNIC BAR0 res magic/version error "
+ "exp (%lx/%lx) or (%lx/%lx), curr (%x/%x)\n",
VNIC_RES_MAGIC, VNIC_RES_VERSION,
+ MGMTVNIC_MAGIC, MGMTVNIC_VERSION,
ioread32(&rh->magic), ioread32(&rh->version));
- return -EINVAL;
+ return -EINVAL;
+ }
}
- r = (struct vnic_resource __iomem *)(rh + 1);
+ if (ioread32(&mrh->magic) == MGMTVNIC_MAGIC)
+ r = (struct vnic_resource __iomem *)(mrh + 1);
+ else
+ r = (struct vnic_resource __iomem *)(rh + 1);
+
while ((type = ioread8(&r->type)) != RES_TYPE_EOL) {
@@ -175,22 +186,7 @@ void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type,
}
}
-dma_addr_t vnic_dev_get_res_bus_addr(struct vnic_dev *vdev,
- enum vnic_res_type type, unsigned int index)
-{
- switch (type) {
- case RES_TYPE_WQ:
- case RES_TYPE_RQ:
- case RES_TYPE_CQ:
- case RES_TYPE_INTR_CTRL:
- return vdev->res[type].bus_addr +
- index * VNIC_RES_STRIDE;
- default:
- return vdev->res[type].bus_addr;
- }
-}
-
-unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring,
+static unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring,
unsigned int desc_count, unsigned int desc_size)
{
/* The base address of the desc rings must be 512 byte aligned.
@@ -373,18 +369,6 @@ static int vnic_dev_cmd_no_proxy(struct vnic_dev *vdev,
return err;
}
-void vnic_dev_cmd_proxy_by_bdf_start(struct vnic_dev *vdev, u16 bdf)
-{
- vdev->proxy = PROXY_BY_BDF;
- vdev->proxy_index = bdf;
-}
-
-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)
{
@@ -477,13 +461,6 @@ int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size,
return err;
}
-int vnic_dev_stats_clear(struct vnic_dev *vdev)
-{
- u64 a0 = 0, a1 = 0;
- int wait = 1000;
- return vnic_dev_cmd(vdev, CMD_STATS_CLEAR, &a0, &a1, wait);
-}
-
int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats)
{
u64 a0, a1;
@@ -510,13 +487,6 @@ int vnic_dev_close(struct vnic_dev *vdev)
return vnic_dev_cmd(vdev, CMD_CLOSE, &a0, &a1, wait);
}
-int vnic_dev_enable(struct vnic_dev *vdev)
-{
- u64 a0 = 0, a1 = 0;
- int wait = 1000;
- return vnic_dev_cmd(vdev, CMD_ENABLE, &a0, &a1, wait);
-}
-
int vnic_dev_enable_wait(struct vnic_dev *vdev)
{
u64 a0 = 0, a1 = 0;
@@ -561,14 +531,14 @@ int vnic_dev_open_done(struct vnic_dev *vdev, int *done)
return 0;
}
-int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg)
+static int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg)
{
u64 a0 = (u32)arg, a1 = 0;
int wait = 1000;
return vnic_dev_cmd(vdev, CMD_SOFT_RESET, &a0, &a1, wait);
}
-int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done)
+static int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done)
{
u64 a0 = 0, a1 = 0;
int wait = 1000;
@@ -669,26 +639,6 @@ int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
return err;
}
-int vnic_dev_packet_filter_all(struct vnic_dev *vdev, int directed,
- int multicast, int broadcast, int promisc, int allmulti)
-{
- u64 a0, a1 = 0;
- int wait = 1000;
- int err;
-
- a0 = (directed ? CMD_PFILTER_DIRECTED : 0) |
- (multicast ? CMD_PFILTER_MULTICAST : 0) |
- (broadcast ? CMD_PFILTER_BROADCAST : 0) |
- (promisc ? CMD_PFILTER_PROMISCUOUS : 0) |
- (allmulti ? CMD_PFILTER_ALL_MULTICAST : 0);
-
- err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER_ALL, &a0, &a1, wait);
- if (err)
- pr_err("Can't set packet filter\n");
-
- return err;
-}
-
int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
{
u64 a0 = 0, a1 = 0;
@@ -737,20 +687,7 @@ int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev,
return err;
}
-int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr)
-{
- u64 a0 = intr, a1 = 0;
- int wait = 1000;
- int err;
-
- err = vnic_dev_cmd(vdev, CMD_IAR, &a0, &a1, wait);
- if (err)
- pr_err("Failed to raise INTR[%d], err %d\n", intr, err);
-
- return err;
-}
-
-int vnic_dev_notify_setcmd(struct vnic_dev *vdev,
+static int vnic_dev_notify_setcmd(struct vnic_dev *vdev,
void *notify_addr, dma_addr_t notify_pa, u16 intr)
{
u64 a0, a1;
@@ -789,7 +726,7 @@ int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
return vnic_dev_notify_setcmd(vdev, notify_addr, notify_pa, intr);
}
-int vnic_dev_notify_unsetcmd(struct vnic_dev *vdev)
+static int vnic_dev_notify_unsetcmd(struct vnic_dev *vdev)
{
u64 a0, a1;
int wait = 1000;
@@ -943,30 +880,6 @@ u32 vnic_dev_mtu(struct vnic_dev *vdev)
return vdev->notify_copy.mtu;
}
-u32 vnic_dev_link_down_cnt(struct vnic_dev *vdev)
-{
- if (!vnic_dev_notify_ready(vdev))
- return 0;
-
- return vdev->notify_copy.link_down_cnt;
-}
-
-u32 vnic_dev_notify_status(struct vnic_dev *vdev)
-{
- if (!vnic_dev_notify_ready(vdev))
- return 0;
-
- return vdev->notify_copy.status;
-}
-
-u32 vnic_dev_uif(struct vnic_dev *vdev)
-{
- if (!vnic_dev_notify_ready(vdev))
- return 0;
-
- return vdev->notify_copy.uif;
-}
-
void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
enum vnic_dev_intr_mode intr_mode)
{
diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h
index 3a61873138b6..05f9a24cd459 100644
--- a/drivers/net/enic/vnic_dev.h
+++ b/drivers/net/enic/vnic_dev.h
@@ -84,10 +84,6 @@ unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev,
enum vnic_res_type type);
void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type,
unsigned int index);
-dma_addr_t vnic_dev_get_res_bus_addr(struct vnic_dev *vdev,
- enum vnic_res_type type, unsigned int index);
-unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring,
- unsigned int desc_count, unsigned int desc_size);
void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring);
int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
unsigned int desc_count, unsigned int desc_size);
@@ -95,39 +91,26 @@ 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_bdf_start(struct vnic_dev *vdev, u16 bdf);
-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_hw_version(struct vnic_dev *vdev,
enum vnic_dev_hw_version *hw_ver);
int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size,
void *value);
-int vnic_dev_stats_clear(struct vnic_dev *vdev);
int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats);
int vnic_dev_hang_notify(struct vnic_dev *vdev);
int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
int broadcast, int promisc, int allmulti);
-int vnic_dev_packet_filter_all(struct vnic_dev *vdev, int directed,
- int multicast, int broadcast, int promisc, int allmulti);
int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr);
int vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr);
int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr);
-int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr);
-int vnic_dev_notify_setcmd(struct vnic_dev *vdev,
- void *notify_addr, dma_addr_t notify_pa, u16 intr);
int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr);
-int vnic_dev_notify_unsetcmd(struct vnic_dev *vdev);
int vnic_dev_notify_unset(struct vnic_dev *vdev);
int vnic_dev_link_status(struct vnic_dev *vdev);
u32 vnic_dev_port_speed(struct vnic_dev *vdev);
u32 vnic_dev_msg_lvl(struct vnic_dev *vdev);
u32 vnic_dev_mtu(struct vnic_dev *vdev);
-u32 vnic_dev_link_down_cnt(struct vnic_dev *vdev);
-u32 vnic_dev_notify_status(struct vnic_dev *vdev);
-u32 vnic_dev_uif(struct vnic_dev *vdev);
int vnic_dev_close(struct vnic_dev *vdev);
-int vnic_dev_enable(struct vnic_dev *vdev);
int vnic_dev_enable_wait(struct vnic_dev *vdev);
int vnic_dev_disable(struct vnic_dev *vdev);
int vnic_dev_open(struct vnic_dev *vdev, int arg);
@@ -136,8 +119,6 @@ int vnic_dev_init(struct vnic_dev *vdev, int arg);
int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err);
int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len);
int vnic_dev_deinit(struct vnic_dev *vdev);
-int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg);
-int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done);
int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg);
int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done);
void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h
index 20661755df6b..9abb3d51dea1 100644
--- a/drivers/net/enic/vnic_devcmd.h
+++ b/drivers/net/enic/vnic_devcmd.h
@@ -238,6 +238,18 @@ enum vnic_devcmd_cmd {
* out: (u32)a0=status of proxied cmd
* a1-a15=out args of proxied cmd */
CMD_PROXY_BY_BDF = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 42),
+
+ /*
+ * As for BY_BDF except a0 is index of hvnlink subordinate vnic
+ * or SR-IOV virtual vnic */
+ CMD_PROXY_BY_INDEX = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 43),
+
+ /*
+ * in: (u64)a0=paddr of buffer to put latest VIC VIF-CONFIG-INFO TLV in
+ * (u32)a1=length of buffer in a0
+ * out: (u64)a0=paddr of buffer with latest VIC VIF-CONFIG-INFO TLV
+ * (u32)a1=actual length of latest VIC VIF-CONFIG-INFO TLV */
+ CMD_CONFIG_INFO_GET = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 44),
};
/* flags for CMD_OPEN */
diff --git a/drivers/net/enic/vnic_enet.h b/drivers/net/enic/vnic_enet.h
index 3b3291248956..e8740e3704e4 100644
--- a/drivers/net/enic/vnic_enet.h
+++ b/drivers/net/enic/vnic_enet.h
@@ -30,7 +30,7 @@ struct vnic_enet_config {
u32 wq_desc_count;
u32 rq_desc_count;
u16 mtu;
- u16 intr_timer;
+ u16 intr_timer_deprecated;
u8 intr_timer_type;
u8 intr_mode;
char devname[16];
diff --git a/drivers/net/enic/vnic_intr.c b/drivers/net/enic/vnic_intr.c
index 52ab61af2750..3873771d75cc 100644
--- a/drivers/net/enic/vnic_intr.c
+++ b/drivers/net/enic/vnic_intr.c
@@ -65,8 +65,3 @@ void vnic_intr_clean(struct vnic_intr *intr)
{
iowrite32(0, &intr->ctrl->int_credits);
}
-
-void vnic_intr_raise(struct vnic_intr *intr)
-{
- vnic_dev_raise_intr(intr->vdev, (u16)intr->index);
-}
diff --git a/drivers/net/enic/vnic_resource.h b/drivers/net/enic/vnic_resource.h
index 810287beff14..e0a73f1ca6f4 100644
--- a/drivers/net/enic/vnic_resource.h
+++ b/drivers/net/enic/vnic_resource.h
@@ -22,6 +22,11 @@
#define VNIC_RES_MAGIC 0x766E6963L /* 'vnic' */
#define VNIC_RES_VERSION 0x00000000L
+#define MGMTVNIC_MAGIC 0x544d474dL /* 'MGMT' */
+#define MGMTVNIC_VERSION 0x00000000L
+
+/* The MAC address assigned to the CFG vNIC is fixed. */
+#define MGMTVNIC_MAC { 0x02, 0x00, 0x54, 0x4d, 0x47, 0x4d }
/* vNIC resource types */
enum vnic_res_type {
@@ -52,6 +57,14 @@ struct vnic_resource_header {
u32 version;
};
+struct mgmt_barmap_hdr {
+ u32 magic; /* magic number */
+ u32 version; /* header format version */
+ u16 lif; /* loopback lif for mgmt frames */
+ u16 pci_slot; /* installed pci slot */
+ char serial[16]; /* card serial number */
+};
+
struct vnic_resource {
u8 type;
u8 bar;
diff --git a/drivers/net/enic/vnic_rq.c b/drivers/net/enic/vnic_rq.c
index dbb2aca258b9..34105e0951a5 100644
--- a/drivers/net/enic/vnic_rq.c
+++ b/drivers/net/enic/vnic_rq.c
@@ -77,8 +77,10 @@ void vnic_rq_free(struct vnic_rq *rq)
vnic_dev_free_desc_ring(vdev, &rq->ring);
for (i = 0; i < VNIC_RQ_BUF_BLKS_MAX; i++) {
- kfree(rq->bufs[i]);
- rq->bufs[i] = NULL;
+ if (rq->bufs[i]) {
+ kfree(rq->bufs[i]);
+ rq->bufs[i] = NULL;
+ }
}
rq->ctrl = NULL;
@@ -113,7 +115,7 @@ int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index,
return 0;
}
-void vnic_rq_init_start(struct vnic_rq *rq, unsigned int cq_index,
+static void vnic_rq_init_start(struct vnic_rq *rq, unsigned int cq_index,
unsigned int fetch_index, unsigned int posted_index,
unsigned int error_interrupt_enable,
unsigned int error_interrupt_offset)
diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/enic/vnic_rq.h
index 2dc48f91abf7..37f08de2454a 100644
--- a/drivers/net/enic/vnic_rq.h
+++ b/drivers/net/enic/vnic_rq.h
@@ -143,7 +143,7 @@ static inline void vnic_rq_post(struct vnic_rq *rq,
static inline int vnic_rq_posting_soon(struct vnic_rq *rq)
{
- return ((rq->to_use->index & VNIC_RQ_RETURN_RATE) == 0);
+ return (rq->to_use->index & VNIC_RQ_RETURN_RATE) == 0;
}
static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count)
@@ -202,10 +202,6 @@ static inline int vnic_rq_fill(struct vnic_rq *rq,
void vnic_rq_free(struct vnic_rq *rq);
int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index,
unsigned int desc_count, unsigned int desc_size);
-void vnic_rq_init_start(struct vnic_rq *rq, unsigned int cq_index,
- unsigned int fetch_index, unsigned int posted_index,
- unsigned int error_interrupt_enable,
- unsigned int error_interrupt_offset);
void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index,
unsigned int error_interrupt_enable,
unsigned int error_interrupt_offset);
diff --git a/drivers/net/enic/vnic_rss.h b/drivers/net/enic/vnic_rss.h
index f62d18719629..fa421baf45b8 100644
--- a/drivers/net/enic/vnic_rss.h
+++ b/drivers/net/enic/vnic_rss.h
@@ -37,9 +37,4 @@ union vnic_rss_cpu {
u64 raw[32];
};
-void vnic_set_rss_key(union vnic_rss_key *rss_key, u8 *key);
-void vnic_set_rss_cpu(union vnic_rss_cpu *rss_cpu, u8 *cpu);
-void vnic_get_rss_key(union vnic_rss_key *rss_key, u8 *key);
-void vnic_get_rss_cpu(union vnic_rss_cpu *rss_cpu, u8 *cpu);
-
#endif /* _VNIC_RSS_H_ */
diff --git a/drivers/net/enic/vnic_vic.c b/drivers/net/enic/vnic_vic.c
index 197c9d24af82..4725b79de0ef 100644
--- a/drivers/net/enic/vnic_vic.c
+++ b/drivers/net/enic/vnic_vic.c
@@ -54,8 +54,8 @@ int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length,
if (!vp || !value)
return -EINVAL;
- if (ntohl(vp->length) + sizeof(*tlv) + length >
- VIC_PROVINFO_MAX_TLV_DATA)
+ if (ntohl(vp->length) + offsetof(struct vic_provinfo_tlv, value) +
+ length > VIC_PROVINFO_MAX_TLV_DATA)
return -ENOMEM;
tlv = (struct vic_provinfo_tlv *)((u8 *)vp->tlv +
@@ -66,7 +66,8 @@ int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length,
memcpy(tlv->value, value, length);
vp->num_tlvs = htonl(ntohl(vp->num_tlvs) + 1);
- vp->length = htonl(ntohl(vp->length) + sizeof(*tlv) + length);
+ vp->length = htonl(ntohl(vp->length) +
+ offsetof(struct vic_provinfo_tlv, value) + length);
return 0;
}
diff --git a/drivers/net/enic/vnic_wq.c b/drivers/net/enic/vnic_wq.c
index 122e33bcc578..df61bd932ea6 100644
--- a/drivers/net/enic/vnic_wq.c
+++ b/drivers/net/enic/vnic_wq.c
@@ -77,8 +77,10 @@ void vnic_wq_free(struct vnic_wq *wq)
vnic_dev_free_desc_ring(vdev, &wq->ring);
for (i = 0; i < VNIC_WQ_BUF_BLKS_MAX; i++) {
- kfree(wq->bufs[i]);
- wq->bufs[i] = NULL;
+ if (wq->bufs[i]) {
+ kfree(wq->bufs[i]);
+ wq->bufs[i] = NULL;
+ }
}
wq->ctrl = NULL;
@@ -113,7 +115,7 @@ int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index,
return 0;
}
-void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index,
+static void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index,
unsigned int fetch_index, unsigned int posted_index,
unsigned int error_interrupt_enable,
unsigned int error_interrupt_offset)
diff --git a/drivers/net/enic/vnic_wq.h b/drivers/net/enic/vnic_wq.h
index 94ac4621acc5..7dd937ac11c2 100644
--- a/drivers/net/enic/vnic_wq.h
+++ b/drivers/net/enic/vnic_wq.h
@@ -153,10 +153,6 @@ static inline void vnic_wq_service(struct vnic_wq *wq,
void vnic_wq_free(struct vnic_wq *wq);
int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index,
unsigned int desc_count, unsigned int desc_size);
-void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index,
- unsigned int fetch_index, unsigned int posted_index,
- unsigned int error_interrupt_enable,
- unsigned int error_interrupt_offset);
void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index,
unsigned int error_interrupt_enable,
unsigned int error_interrupt_offset);
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 57c8ac0ef3f1..aa56963ad558 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -131,8 +131,8 @@ IIIa. Ring buffers
IVb. References
-http://www.smsc.com/main/tools/discontinued/83c171.pdf
-http://www.smsc.com/main/tools/discontinued/83c175.pdf
+http://www.smsc.com/media/Downloads_Public/discontinued/83c171.pdf
+http://www.smsc.com/media/Downloads_Public/discontinued/83c175.pdf
http://scyld.com/expert/NWay.html
http://www.national.com/pf/DP/DP83840A.html
@@ -758,7 +758,7 @@ static int epic_open(struct net_device *dev)
init_timer(&ep->timer);
ep->timer.expires = jiffies + 3*HZ;
ep->timer.data = (unsigned long)dev;
- ep->timer.function = &epic_timer; /* timer handler */
+ ep->timer.function = epic_timer; /* timer handler */
add_timer(&ep->timer);
return 0;
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index 10e39f2b31c3..fb717be511f6 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -637,7 +637,9 @@ static void eth16i_initialize(struct net_device *dev, int boot)
/* Set interface port type */
if(boot) {
- char *porttype[] = {"BNC", "DIX", "TP", "AUTO", "FROM_EPROM" };
+ static const char * const porttype[] = {
+ "BNC", "DIX", "TP", "AUTO", "FROM_EPROM"
+ };
switch(dev->if_port)
{
@@ -794,7 +796,7 @@ static int eth16i_receive_probe_packet(int ioaddr)
if(eth16i_debug > 1)
printk(KERN_DEBUG "RECEIVE_PACKET\n");
- return(0); /* Found receive packet */
+ return 0; /* Found receive packet */
}
}
@@ -803,7 +805,7 @@ static int eth16i_receive_probe_packet(int ioaddr)
printk(KERN_DEBUG "RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG));
}
- return(0); /* Return success */
+ return 0; /* Return success */
}
#if 0
@@ -839,7 +841,7 @@ static int __init eth16i_get_irq(int ioaddr)
if( ioaddr < 0x1000) {
cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
- return( eth16i_irqmap[ ((cbyte & 0xC0) >> 6) ] );
+ return eth16i_irqmap[((cbyte & 0xC0) >> 6)];
} else { /* Oh..the card is EISA so method getting IRQ different */
unsigned short index = 0;
cbyte = inb(ioaddr + EISA_IRQ_REG);
@@ -847,7 +849,7 @@ static int __init eth16i_get_irq(int ioaddr)
cbyte = cbyte >> 1;
index++;
}
- return( eth32i_irqmap[ index ] );
+ return eth32i_irqmap[index];
}
}
@@ -907,7 +909,7 @@ static int eth16i_read_eeprom(int ioaddr, int offset)
data = eth16i_read_eeprom_word(ioaddr);
outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
- return(data);
+ return data;
}
static int eth16i_read_eeprom_word(int ioaddr)
@@ -926,7 +928,7 @@ static int eth16i_read_eeprom_word(int ioaddr)
eeprom_slow_io();
}
- return(data);
+ return data;
}
static void eth16i_eeprom_cmd(int ioaddr, unsigned char command)
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
index 6d653c459c1f..c5a2fe099a8d 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethoc.c
@@ -806,11 +806,6 @@ static void ethoc_tx_timeout(struct net_device *dev)
ethoc_interrupt(dev->irq, dev);
}
-static struct net_device_stats *ethoc_stats(struct net_device *dev)
-{
- return &dev->stats;
-}
-
static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ethoc *priv = netdev_priv(dev);
@@ -863,7 +858,6 @@ static const struct net_device_ops ethoc_netdev_ops = {
.ndo_set_multicast_list = ethoc_set_multicast_list,
.ndo_change_mtu = ethoc_change_mtu,
.ndo_tx_timeout = ethoc_tx_timeout,
- .ndo_get_stats = ethoc_stats,
.ndo_start_xmit = ethoc_start_xmit,
};
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index d7e8f6b8f4cf..dd54abe2f710 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -915,14 +915,14 @@ static int netdev_open(struct net_device *dev)
init_timer(&np->timer);
np->timer.expires = RUN_AT(3 * HZ);
np->timer.data = (unsigned long) dev;
- np->timer.function = &netdev_timer;
+ np->timer.function = netdev_timer;
/* timer handler */
add_timer(&np->timer);
init_timer(&np->reset_timer);
np->reset_timer.data = (unsigned long) dev;
- np->reset_timer.function = &reset_timer;
+ np->reset_timer.function = reset_timer;
np->reset_timer_armed = 0;
return 0;
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index e3e10b4add9c..e9f5d030bc26 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -771,11 +771,6 @@ static void mpc52xx_fec_reset(struct net_device *dev)
/* ethtool interface */
-static void mpc52xx_fec_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, DRIVER_NAME);
-}
static int mpc52xx_fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
@@ -810,7 +805,6 @@ static void mpc52xx_fec_set_msglevel(struct net_device *dev, u32 level)
}
static const struct ethtool_ops mpc52xx_fec_ethtool_ops = {
- .get_drvinfo = mpc52xx_fec_get_drvinfo,
.get_settings = mpc52xx_fec_get_settings,
.set_settings = mpc52xx_fec_set_settings,
.get_link = ethtool_op_get_link,
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 4da05b1b445c..0fa1776563a3 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -2321,14 +2321,11 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
/* vlan tag */
- if (likely(!np->vlangrp)) {
+ if (vlan_tx_tag_present(skb))
+ start_tx->txvlan = cpu_to_le32(NV_TX3_VLAN_TAG_PRESENT |
+ vlan_tx_tag_get(skb));
+ else
start_tx->txvlan = 0;
- } else {
- if (vlan_tx_tag_present(skb))
- start_tx->txvlan = cpu_to_le32(NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb));
- else
- start_tx->txvlan = 0;
- }
spin_lock_irqsave(&np->lock, flags);
@@ -4620,7 +4617,7 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam*
static u32 nv_get_rx_csum(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- return (np->rx_csum) != 0;
+ return np->rx_csum != 0;
}
static int nv_set_rx_csum(struct net_device *dev, u32 data)
@@ -5440,13 +5437,13 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
init_timer(&np->oom_kick);
np->oom_kick.data = (unsigned long) dev;
- np->oom_kick.function = &nv_do_rx_refill; /* timer handler */
+ np->oom_kick.function = nv_do_rx_refill; /* timer handler */
init_timer(&np->nic_poll);
np->nic_poll.data = (unsigned long) dev;
- np->nic_poll.function = &nv_do_nic_poll; /* timer handler */
+ np->nic_poll.function = nv_do_nic_poll; /* timer handler */
init_timer(&np->stats_poll);
np->stats_poll.data = (unsigned long) dev;
- np->stats_poll.function = &nv_do_stats_poll; /* timer handler */
+ np->stats_poll.function = nv_do_stats_poll; /* timer handler */
err = pci_enable_device(pci_dev);
if (err)
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index d6e3111959ab..d684f187de57 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -1036,7 +1036,7 @@ static int __devinit fs_enet_probe(struct platform_device *ofdev,
ndev = alloc_etherdev(privsize);
if (!ndev) {
ret = -ENOMEM;
- goto out_free_fpi;
+ goto out_put;
}
SET_NETDEV_DEV(ndev, &ofdev->dev);
@@ -1099,6 +1099,7 @@ out_cleanup_data:
out_free_dev:
free_netdev(ndev);
dev_set_drvdata(&ofdev->dev, NULL);
+out_put:
of_node_put(fpi->phy_node);
out_free_fpi:
kfree(fpi);
diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c
index d4bf91aac25f..8d3a2ccbc953 100644
--- a/drivers/net/fsl_pq_mdio.c
+++ b/drivers/net/fsl_pq_mdio.c
@@ -125,7 +125,7 @@ int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
struct fsl_pq_mdio __iomem *regs = fsl_pq_mdio_get_regs(bus);
/* Write to the local MII regs */
- return(fsl_pq_local_mdio_write(regs, mii_id, regnum, value));
+ return fsl_pq_local_mdio_write(regs, mii_id, regnum, value);
}
/*
@@ -137,7 +137,7 @@ int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
struct fsl_pq_mdio __iomem *regs = fsl_pq_mdio_get_regs(bus);
/* Read the local MII regs */
- return(fsl_pq_local_mdio_read(regs, mii_id, regnum));
+ return fsl_pq_local_mdio_read(regs, mii_id, regnum);
}
/* Reset the MIIM registers, and wait for the bus to free */
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 4f7c3f3ca234..49e4ce1246a7 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -654,9 +654,8 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
priv->node = ofdev->dev.of_node;
priv->ndev = dev;
- dev->num_tx_queues = num_tx_qs;
- dev->real_num_tx_queues = num_tx_qs;
priv->num_tx_queues = num_tx_qs;
+ netif_set_real_num_rx_queues(dev, num_rx_qs);
priv->num_rx_queues = num_rx_qs;
priv->num_grps = 0x0;
@@ -1859,7 +1858,7 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
printk(KERN_ERR "%s: Can't get IRQ %d\n",
dev->name, grp->interruptError);
- goto err_irq_fail;
+ goto err_irq_fail;
}
if ((err = request_irq(grp->interruptTransmit, gfar_transmit,
@@ -2048,7 +2047,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 bufaddr;
unsigned long flags;
unsigned int nr_frags, nr_txbds, length;
- union skb_shared_tx *shtx;
/*
* TOE=1 frames larger than 2500 bytes may see excess delays
@@ -2069,15 +2067,15 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
txq = netdev_get_tx_queue(dev, rq);
base = tx_queue->tx_bd_base;
regs = tx_queue->grp->regs;
- shtx = skb_tx(skb);
/* check if time stamp should be generated */
- if (unlikely(shtx->hardware && priv->hwts_tx_en))
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
+ priv->hwts_tx_en))
do_tstamp = 1;
/* make space for additional header when fcb is needed */
if (((skb->ip_summed == CHECKSUM_PARTIAL) ||
- (priv->vlgrp && vlan_tx_tag_present(skb)) ||
+ vlan_tx_tag_present(skb) ||
unlikely(do_tstamp)) &&
(skb_headroom(skb) < GMAC_FCB_LEN)) {
struct sk_buff *skb_new;
@@ -2163,7 +2161,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
gfar_tx_checksum(skb, fcb);
}
- if (priv->vlgrp && vlan_tx_tag_present(skb)) {
+ if (vlan_tx_tag_present(skb)) {
if (unlikely(NULL == fcb)) {
fcb = gfar_add_fcb(skb);
lstatus |= BD_LFLAG(TXBD_TOE);
@@ -2174,7 +2172,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Setup tx hardware time stamping if requested */
if (unlikely(do_tstamp)) {
- shtx->in_progress = 1;
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
if (fcb == NULL)
fcb = gfar_add_fcb(skb);
fcb->ptp = 1;
@@ -2446,7 +2444,6 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
int howmany = 0;
u32 lstatus;
size_t buflen;
- union skb_shared_tx *shtx;
rx_queue = priv->rx_queue[tx_queue->qindex];
bdp = tx_queue->dirty_tx;
@@ -2461,8 +2458,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
* When time stamping, one additional TxBD must be freed.
* Also, we need to dma_unmap_single() the TxPAL.
*/
- shtx = skb_tx(skb);
- if (unlikely(shtx->in_progress))
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS))
nr_txbds = frags + 2;
else
nr_txbds = frags + 1;
@@ -2476,7 +2472,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
(lstatus & BD_LENGTH_MASK))
break;
- if (unlikely(shtx->in_progress)) {
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
next = next_txbd(bdp, base, tx_ring_size);
buflen = next->length + GMAC_FCB_LEN;
} else
@@ -2485,7 +2481,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
dma_unmap_single(&priv->ofdev->dev, bdp->bufPtr,
buflen, DMA_TO_DEVICE);
- if (unlikely(shtx->in_progress)) {
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
struct skb_shared_hwtstamps shhwtstamps;
u64 *ns = (u64*) (((u32)skb->data + 0x10) & ~0x7);
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
@@ -2515,7 +2511,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
skb_recycle_check(skb, priv->rx_buffer_size +
RXBUF_ALIGNMENT)) {
gfar_align_skb(skb);
- __skb_queue_head(&priv->rx_recycle, skb);
+ skb_queue_head(&priv->rx_recycle, skb);
} else
dev_kfree_skb_any(skb);
@@ -2598,7 +2594,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev)
struct gfar_private *priv = netdev_priv(dev);
struct sk_buff *skb = NULL;
- skb = __skb_dequeue(&priv->rx_recycle);
+ skb = skb_dequeue(&priv->rx_recycle);
if (!skb)
skb = gfar_alloc_skb(dev);
@@ -2657,7 +2653,7 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
if ((fcb->flags & RXFCB_CSUM_MASK) == (RXFCB_CIP | RXFCB_CTU))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
}
@@ -2754,7 +2750,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
if (unlikely(!newskb))
newskb = skb;
else if (skb)
- __skb_queue_head(&priv->rx_recycle, skb);
+ skb_queue_head(&priv->rx_recycle, skb);
} else {
/* Increment the number of packets */
rx_queue->stats.rx_packets++;
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 9bda023c0235..5c566ebc54b8 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -254,7 +254,7 @@ static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int use
/* Make sure we return a number greater than 0
* if usecs > 0 */
- return ((usecs * 1000 + count - 1) / count);
+ return (usecs * 1000 + count - 1) / count;
}
/* Convert ethernet clock ticks to microseconds */
@@ -278,7 +278,7 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic
/* Make sure we return a number greater than 0 */
/* if ticks is > 0 */
- return ((ticks * count) / 1000);
+ return (ticks * count) / 1000;
}
/* Get the coalescing parameters, and put them in the cvals
@@ -538,7 +538,7 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
unlock_tx_qs(priv);
unlock_rx_qs(priv);
- local_irq_save(flags);
+ local_irq_restore(flags);
for (i = 0; i < priv->num_rx_queues; i++)
gfar_clean_rx_ring(priv->rx_queue[i],
diff --git a/drivers/net/greth.c b/drivers/net/greth.c
index f15c64f1cd38..27d6960ce09e 100644
--- a/drivers/net/greth.c
+++ b/drivers/net/greth.c
@@ -893,7 +893,7 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
if (greth->flags & GRETH_FLAG_RX_CSUM && hw_checksummed(status))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
skb->protocol = eth_type_trans(skb, dev);
dev->stats.rx_packets++;
@@ -1547,10 +1547,10 @@ static int __devinit greth_of_probe(struct platform_device *ofdev, const struct
dev->netdev_ops = &greth_netdev_ops;
dev->ethtool_ops = &greth_ethtool_ops;
- if (register_netdev(dev)) {
+ err = register_netdev(dev);
+ if (err) {
if (netif_msg_probe(greth))
dev_err(greth->dev, "netdevice registration failed.\n");
- err = -ENOMEM;
goto error5;
}
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 49aac7027fbb..9a6485892b3d 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -1004,7 +1004,7 @@ static int hamachi_open(struct net_device *dev)
init_timer(&hmp->timer);
hmp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */
hmp->timer.data = (unsigned long)dev;
- hmp->timer.function = &hamachi_timer; /* timer handler */
+ hmp->timer.function = hamachi_timer; /* timer handler */
add_timer(&hmp->timer);
return 0;
diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig
index 62d5d5cfd6a6..95dbcfdf131d 100644
--- a/drivers/net/hamradio/Kconfig
+++ b/drivers/net/hamradio/Kconfig
@@ -73,7 +73,7 @@ config DMASCC
certain parameters, such as channel access timing, clock mode, and
DMA channel. This is accomplished with a small utility program,
dmascc_cfg, available at
- <http://cacofonix.nt.tuwien.ac.at/~oe1kib/Linux/>. Please be sure to
+ <http://www.linux-ax25.org/wiki/Ax25-tools>. Please be sure to
get at least version 1.27 of dmascc_cfg, as older versions will not
work with the current driver.
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 14f01d156db9..ac1d323c5eb5 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -168,7 +168,7 @@ static inline struct net_device *bpq_get_ax25_dev(struct net_device *dev)
static inline int dev_is_ethdev(struct net_device *dev)
{
- return (dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5));
+ return dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5);
}
/* ------------------------------------------------------------------------ */
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index b8bdf9d51cd4..5b37579e84b7 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -110,7 +110,7 @@ static int calc_crc_ccitt(const unsigned char *buf, int cnt)
for (; cnt > 0; cnt--)
crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff];
crc ^= 0xffff;
- return (crc & 0xffff);
+ return crc & 0xffff;
}
#endif
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 9f64c8637208..33655814448e 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1069,7 +1069,8 @@ static void scc_tx_done(struct scc_channel *scc)
case KISS_DUPLEX_LINK:
scc->stat.tx_state = TXS_IDLE2;
if (scc->kiss.idletime != TIMER_OFF)
- scc_start_tx_timer(scc, t_idle, scc->kiss.idletime*100);
+ scc_start_tx_timer(scc, t_idle,
+ scc->kiss.idletime*100);
break;
case KISS_DUPLEX_OPTIMA:
scc_notify(scc, HWEV_ALL_SENT);
diff --git a/drivers/net/hp.c b/drivers/net/hp.c
index 86ececd3c658..d15d2f2ba78e 100644
--- a/drivers/net/hp.c
+++ b/drivers/net/hp.c
@@ -204,10 +204,10 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr)
ei_status.rx_start_page = HP_START_PG + TX_PAGES;
ei_status.stop_page = wordmode ? HP_16BSTOP_PG : HP_8BSTOP_PG;
- ei_status.reset_8390 = &hp_reset_8390;
- ei_status.get_8390_hdr = &hp_get_8390_hdr;
- ei_status.block_input = &hp_block_input;
- ei_status.block_output = &hp_block_output;
+ ei_status.reset_8390 = hp_reset_8390;
+ ei_status.get_8390_hdr = hp_get_8390_hdr;
+ ei_status.block_input = hp_block_input;
+ ei_status.block_output = hp_block_output;
hp_init_card(dev);
retval = register_netdev(dev);
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 095b17ecf609..8e2c4601b5f5 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1312,7 +1312,7 @@ static int hp100_build_rx_pdl(hp100_ring_t * ringptr,
for (p = (ringptr->pdl); p < (ringptr->pdl + 5); p++)
printk("hp100: %s: Adr 0x%.8x = 0x%.8x\n", dev->name, (u_int) p, (u_int) * p);
#endif
- return (1);
+ return 1;
}
/* else: */
/* alloc_skb failed (no memory) -> still can receive the header
@@ -1325,7 +1325,7 @@ static int hp100_build_rx_pdl(hp100_ring_t * ringptr,
ringptr->pdl[0] = 0x00010000; /* PDH: Count=1 Fragment */
- return (0);
+ return 0;
}
/*
@@ -2752,7 +2752,7 @@ static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin)
hp100_outw(HP100_MISC_ERROR, IRQ_STATUS);
if (val & HP100_LINK_UP_ST)
- return (0); /* login was ok */
+ return 0; /* login was ok */
else {
printk("hp100: %s: Training failed.\n", dev->name);
hp100_down_vg_link(dev);
diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c
index 07d8e5b634f3..c5ef62ceb840 100644
--- a/drivers/net/hydra.c
+++ b/drivers/net/hydra.c
@@ -155,10 +155,10 @@ static int __devinit hydra_init(struct zorro_dev *z)
ei_status.rx_start_page = start_page + TX_PAGES;
- ei_status.reset_8390 = &hydra_reset_8390;
- ei_status.block_input = &hydra_block_input;
- ei_status.block_output = &hydra_block_output;
- ei_status.get_8390_hdr = &hydra_get_8390_hdr;
+ ei_status.reset_8390 = hydra_reset_8390;
+ ei_status.block_input = hydra_block_input;
+ ei_status.block_output = hydra_block_output;
+ ei_status.get_8390_hdr = hydra_get_8390_hdr;
ei_status.reg_offset = hydra_offsets;
dev->netdev_ops = &hydra_netdev_ops;
@@ -173,9 +173,8 @@ static int __devinit hydra_init(struct zorro_dev *z)
zorro_set_drvdata(z, dev);
- printk(KERN_INFO "%s: Hydra at 0x%08llx, address "
- "%pM (hydra.c " HYDRA_VERSION ")\n",
- dev->name, (unsigned long long)z->resource.start, dev->dev_addr);
+ pr_info("%s: Hydra at %pR, address %pM (hydra.c " HYDRA_VERSION ")\n",
+ dev->name, &z->resource, dev->dev_addr);
return 0;
}
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index 519e19e23955..385dc3204cb7 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -2095,11 +2095,11 @@ static void *emac_dump_regs(struct emac_instance *dev, void *buf)
if (emac_has_feature(dev, EMAC_FTR_EMAC4)) {
hdr->version = EMAC4_ETHTOOL_REGS_VER;
memcpy_fromio(hdr + 1, dev->emacp, EMAC4_ETHTOOL_REGS_SIZE(dev));
- return ((void *)(hdr + 1) + EMAC4_ETHTOOL_REGS_SIZE(dev));
+ return (void *)(hdr + 1) + EMAC4_ETHTOOL_REGS_SIZE(dev);
} else {
hdr->version = EMAC_ETHTOOL_REGS_VER;
memcpy_fromio(hdr + 1, dev->emacp, EMAC_ETHTOOL_REGS_SIZE(dev));
- return ((void *)(hdr + 1) + EMAC_ETHTOOL_REGS_SIZE(dev));
+ return (void *)(hdr + 1) + EMAC_ETHTOOL_REGS_SIZE(dev);
}
}
@@ -2293,7 +2293,7 @@ static int __devinit emac_check_deps(struct emac_instance *dev,
if (deps[i].drvdata != NULL)
there++;
}
- return (there == EMAC_DEP_COUNT);
+ return there == EMAC_DEP_COUNT;
}
static void emac_put_deps(struct emac_instance *dev)
diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h
index 9e37e3d9c51d..4fec0844d59d 100644
--- a/drivers/net/ibm_newemac/core.h
+++ b/drivers/net/ibm_newemac/core.h
@@ -410,7 +410,7 @@ static inline u32 *emac_xaht_base(struct emac_instance *dev)
else
offset = offsetof(struct emac_regs, u0.emac4.iaht1);
- return ((u32 *)((ptrdiff_t)p + offset));
+ return (u32 *)((ptrdiff_t)p + offset);
}
static inline u32 *emac_gaht_base(struct emac_instance *dev)
@@ -418,7 +418,7 @@ static inline u32 *emac_gaht_base(struct emac_instance *dev)
/* GAHT registers always come after an identical number of
* IAHT registers.
*/
- return (emac_xaht_base(dev) + EMAC_XAHT_REGS(dev));
+ return emac_xaht_base(dev) + EMAC_XAHT_REGS(dev);
}
static inline u32 *emac_iaht_base(struct emac_instance *dev)
@@ -426,7 +426,7 @@ static inline u32 *emac_iaht_base(struct emac_instance *dev)
/* IAHT registers always come before an identical number of
* GAHT registers.
*/
- return (emac_xaht_base(dev));
+ return emac_xaht_base(dev);
}
/* Ethtool get_regs complex data.
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index 294ccfb427cf..94d9969ec0bb 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -23,7 +23,7 @@ paper sources:
'LAN Technical Reference Ethernet Adapter Interface Version 1 Release 1.0
Document Number SC30-3661-00' by IBM for info on the adapter itself
- Also see http://www.natsemi.com/
+ Also see http://www.national.com/analog
special acknowledgements to:
- Bob Eager for helping me out with documentation from IBM
@@ -602,7 +602,7 @@ static void irqrx_handler(struct net_device *dev)
/* set up skb fields */
skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
/* bookkeeping */
dev->stats.rx_packets++;
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 4734c939ad03..c454b45ca7ec 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -1,122 +1,84 @@
-/**************************************************************************/
-/* */
-/* IBM eServer i/pSeries Virtual Ethernet Device Driver */
-/* Copyright (C) 2003 IBM Corp. */
-/* Originally written by Dave Larson (larson1@us.ibm.com) */
-/* Maintained by Santiago Leon (santil@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; 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 */
-/* */
-/* This module contains the implementation of a virtual ethernet device */
-/* for use with IBM i/pSeries LPAR Linux. It utilizes the logical LAN */
-/* option of the RS/6000 Platform Architechture to interface with virtual */
-/* ethernet NICs that are presented to the partition by the hypervisor. */
-/* */
-/**************************************************************************/
/*
- TODO:
- - add support for sysfs
- - possibly remove procfs support
-*/
+ * IBM Power Virtual Ethernet Device Driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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.
+ *
+ * Copyright (C) IBM Corporation, 2003, 2010
+ *
+ * Authors: Dave Larson <larson1@us.ibm.com>
+ * Santiago Leon <santil@linux.vnet.ibm.com>
+ * Brian King <brking@linux.vnet.ibm.com>
+ * Robert Jennings <rcj@linux.vnet.ibm.com>
+ * Anton Blanchard <anton@au.ibm.com>
+ */
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/errno.h>
-#include <linux/ioport.h>
#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
-#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/pm.h>
#include <linux/ethtool.h>
-#include <linux/proc_fs.h>
#include <linux/in.h>
#include <linux/ip.h>
+#include <linux/ipv6.h>
#include <linux/slab.h>
-#include <net/net_namespace.h>
#include <asm/hvcall.h>
#include <asm/atomic.h>
#include <asm/vio.h>
#include <asm/iommu.h>
-#include <asm/uaccess.h>
#include <asm/firmware.h>
-#include <linux/seq_file.h>
#include "ibmveth.h"
-#undef DEBUG
-
-#define ibmveth_printk(fmt, args...) \
- printk(KERN_DEBUG "%s: " fmt, __FILE__, ## args)
-
-#define ibmveth_error_printk(fmt, args...) \
- printk(KERN_ERR "(%s:%3.3d ua:%x) ERROR: " fmt, __FILE__, __LINE__ , adapter->vdev->unit_address, ## args)
-
-#ifdef DEBUG
-#define ibmveth_debug_printk_no_adapter(fmt, args...) \
- printk(KERN_DEBUG "(%s:%3.3d): " fmt, __FILE__, __LINE__ , ## args)
-#define ibmveth_debug_printk(fmt, args...) \
- printk(KERN_DEBUG "(%s:%3.3d ua:%x): " fmt, __FILE__, __LINE__ , adapter->vdev->unit_address, ## args)
-#define ibmveth_assert(expr) \
- if(!(expr)) { \
- printk(KERN_DEBUG "assertion failed (%s:%3.3d ua:%x): %s\n", __FILE__, __LINE__, adapter->vdev->unit_address, #expr); \
- BUG(); \
- }
-#else
-#define ibmveth_debug_printk_no_adapter(fmt, args...)
-#define ibmveth_debug_printk(fmt, args...)
-#define ibmveth_assert(expr)
-#endif
-
-static int ibmveth_open(struct net_device *dev);
-static int ibmveth_close(struct net_device *dev);
-static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static int ibmveth_poll(struct napi_struct *napi, int budget);
-static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void ibmveth_set_multicast_list(struct net_device *dev);
-static int ibmveth_change_mtu(struct net_device *dev, int new_mtu);
-static void ibmveth_proc_register_driver(void);
-static void ibmveth_proc_unregister_driver(void);
-static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter);
-static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter);
static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance);
static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev);
-static struct kobj_type ktype_veth_pool;
+static struct kobj_type ktype_veth_pool;
-#ifdef CONFIG_PROC_FS
-#define IBMVETH_PROC_DIR "ibmveth"
-static struct proc_dir_entry *ibmveth_proc_dir;
-#endif
static const char ibmveth_driver_name[] = "ibmveth";
-static const char ibmveth_driver_string[] = "IBM i/pSeries Virtual Ethernet Driver";
-#define ibmveth_driver_version "1.03"
+static const char ibmveth_driver_string[] = "IBM Power Virtual Ethernet Driver";
+#define ibmveth_driver_version "1.04"
-MODULE_AUTHOR("Santiago Leon <santil@us.ibm.com>");
-MODULE_DESCRIPTION("IBM i/pSeries Virtual Ethernet Driver");
+MODULE_AUTHOR("Santiago Leon <santil@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("IBM Power Virtual Ethernet Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(ibmveth_driver_version);
+static unsigned int tx_copybreak __read_mostly = 128;
+module_param(tx_copybreak, uint, 0644);
+MODULE_PARM_DESC(tx_copybreak,
+ "Maximum size of packet that is copied to a new buffer on transmit");
+
+static unsigned int rx_copybreak __read_mostly = 128;
+module_param(rx_copybreak, uint, 0644);
+MODULE_PARM_DESC(rx_copybreak,
+ "Maximum size of packet that is copied to a new buffer on receive");
+
+static unsigned int rx_flush __read_mostly = 0;
+module_param(rx_flush, uint, 0644);
+MODULE_PARM_DESC(rx_flush, "Flush receive buffers before use");
+
struct ibmveth_stat {
char name[ETH_GSTRING_LEN];
int offset;
@@ -128,12 +90,16 @@ struct ibmveth_stat {
struct ibmveth_stat ibmveth_stats[] = {
{ "replenish_task_cycles", IBMVETH_STAT_OFF(replenish_task_cycles) },
{ "replenish_no_mem", IBMVETH_STAT_OFF(replenish_no_mem) },
- { "replenish_add_buff_failure", IBMVETH_STAT_OFF(replenish_add_buff_failure) },
- { "replenish_add_buff_success", IBMVETH_STAT_OFF(replenish_add_buff_success) },
+ { "replenish_add_buff_failure",
+ IBMVETH_STAT_OFF(replenish_add_buff_failure) },
+ { "replenish_add_buff_success",
+ IBMVETH_STAT_OFF(replenish_add_buff_success) },
{ "rx_invalid_buffer", IBMVETH_STAT_OFF(rx_invalid_buffer) },
{ "rx_no_buffer", IBMVETH_STAT_OFF(rx_no_buffer) },
{ "tx_map_failed", IBMVETH_STAT_OFF(tx_map_failed) },
{ "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) },
+ { "fw_enabled_ipv4_csum", IBMVETH_STAT_OFF(fw_ipv4_csum_support) },
+ { "fw_enabled_ipv6_csum", IBMVETH_STAT_OFF(fw_ipv6_csum_support) },
};
/* simple methods of getting data from the current rxq entry */
@@ -144,41 +110,44 @@ static inline u32 ibmveth_rxq_flags(struct ibmveth_adapter *adapter)
static inline int ibmveth_rxq_toggle(struct ibmveth_adapter *adapter)
{
- return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_TOGGLE) >> IBMVETH_RXQ_TOGGLE_SHIFT;
+ return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_TOGGLE) >>
+ IBMVETH_RXQ_TOGGLE_SHIFT;
}
static inline int ibmveth_rxq_pending_buffer(struct ibmveth_adapter *adapter)
{
- return (ibmveth_rxq_toggle(adapter) == adapter->rx_queue.toggle);
+ return ibmveth_rxq_toggle(adapter) == adapter->rx_queue.toggle;
}
static inline int ibmveth_rxq_buffer_valid(struct ibmveth_adapter *adapter)
{
- return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_VALID);
+ return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_VALID;
}
static inline int ibmveth_rxq_frame_offset(struct ibmveth_adapter *adapter)
{
- return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_OFF_MASK);
+ return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_OFF_MASK;
}
static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)
{
- return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].length);
+ return adapter->rx_queue.queue_addr[adapter->rx_queue.index].length;
}
static inline int ibmveth_rxq_csum_good(struct ibmveth_adapter *adapter)
{
- return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_CSUM_GOOD);
+ return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_CSUM_GOOD;
}
/* setup the initial settings for a buffer pool */
-static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active)
+static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool,
+ u32 pool_index, u32 pool_size,
+ u32 buff_size, u32 pool_active)
{
pool->size = pool_size;
pool->index = pool_index;
pool->buff_size = buff_size;
- pool->threshold = pool_size / 2;
+ pool->threshold = pool_size * 7 / 8;
pool->active = pool_active;
}
@@ -189,12 +158,11 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool)
pool->free_map = kmalloc(sizeof(u16) * pool->size, GFP_KERNEL);
- if(!pool->free_map) {
+ if (!pool->free_map)
return -1;
- }
pool->dma_addr = kmalloc(sizeof(dma_addr_t) * pool->size, GFP_KERNEL);
- if(!pool->dma_addr) {
+ if (!pool->dma_addr) {
kfree(pool->free_map);
pool->free_map = NULL;
return -1;
@@ -202,7 +170,7 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool)
pool->skbuff = kcalloc(pool->size, sizeof(void *), GFP_KERNEL);
- if(!pool->skbuff) {
+ if (!pool->skbuff) {
kfree(pool->dma_addr);
pool->dma_addr = NULL;
@@ -213,9 +181,8 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool)
memset(pool->dma_addr, 0, sizeof(dma_addr_t) * pool->size);
- for(i = 0; i < pool->size; ++i) {
+ for (i = 0; i < pool->size; ++i)
pool->free_map[i] = i;
- }
atomic_set(&pool->available, 0);
pool->producer_index = 0;
@@ -224,10 +191,19 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool)
return 0;
}
+static inline void ibmveth_flush_buffer(void *addr, unsigned long length)
+{
+ unsigned long offset;
+
+ for (offset = 0; offset < length; offset += SMP_CACHE_BYTES)
+ asm("dcbfl %0,%1" :: "b" (addr), "r" (offset));
+}
+
/* replenish the buffers for a pool. note that we don't need to
* skb_reserve these since they are used for incoming...
*/
-static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struct ibmveth_buff_pool *pool)
+static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter,
+ struct ibmveth_buff_pool *pool)
{
u32 i;
u32 count = pool->size - atomic_read(&pool->available);
@@ -240,23 +216,26 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc
mb();
- for(i = 0; i < count; ++i) {
+ for (i = 0; i < count; ++i) {
union ibmveth_buf_desc desc;
- skb = alloc_skb(pool->buff_size, GFP_ATOMIC);
+ skb = netdev_alloc_skb(adapter->netdev, pool->buff_size);
- if(!skb) {
- ibmveth_debug_printk("replenish: unable to allocate skb\n");
+ if (!skb) {
+ netdev_dbg(adapter->netdev,
+ "replenish: unable to allocate skb\n");
adapter->replenish_no_mem++;
break;
}
free_index = pool->consumer_index;
- pool->consumer_index = (pool->consumer_index + 1) % pool->size;
+ pool->consumer_index++;
+ if (pool->consumer_index >= pool->size)
+ pool->consumer_index = 0;
index = pool->free_map[free_index];
- ibmveth_assert(index != IBM_VETH_INVALID_MAP);
- ibmveth_assert(pool->skbuff[index] == NULL);
+ BUG_ON(index == IBM_VETH_INVALID_MAP);
+ BUG_ON(pool->skbuff[index] != NULL);
dma_addr = dma_map_single(&adapter->vdev->dev, skb->data,
pool->buff_size, DMA_FROM_DEVICE);
@@ -269,16 +248,23 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc
pool->skbuff[index] = skb;
correlator = ((u64)pool->index << 32) | index;
- *(u64*)skb->data = correlator;
+ *(u64 *)skb->data = correlator;
desc.fields.flags_len = IBMVETH_BUF_VALID | pool->buff_size;
desc.fields.address = dma_addr;
- lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc);
+ if (rx_flush) {
+ unsigned int len = min(pool->buff_size,
+ adapter->netdev->mtu +
+ IBMVETH_BUFF_OH);
+ ibmveth_flush_buffer(skb->data, len);
+ }
+ lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address,
+ desc.desc);
- if (lpar_rc != H_SUCCESS)
+ if (lpar_rc != H_SUCCESS) {
goto failure;
- else {
+ } else {
buffers_added++;
adapter->replenish_add_buff_success++;
}
@@ -313,26 +299,31 @@ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter)
adapter->replenish_task_cycles++;
- for (i = (IbmVethNumBufferPools - 1); i >= 0; i--)
- if(adapter->rx_buff_pool[i].active)
- ibmveth_replenish_buffer_pool(adapter,
- &adapter->rx_buff_pool[i]);
+ for (i = (IBMVETH_NUM_BUFF_POOLS - 1); i >= 0; i--) {
+ struct ibmveth_buff_pool *pool = &adapter->rx_buff_pool[i];
- adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8);
+ if (pool->active &&
+ (atomic_read(&pool->available) < pool->threshold))
+ ibmveth_replenish_buffer_pool(adapter, pool);
+ }
+
+ adapter->rx_no_buffer = *(u64 *)(((char*)adapter->buffer_list_addr) +
+ 4096 - 8);
}
/* empty and free ana buffer pool - also used to do cleanup in error paths */
-static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibmveth_buff_pool *pool)
+static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter,
+ struct ibmveth_buff_pool *pool)
{
int i;
kfree(pool->free_map);
pool->free_map = NULL;
- if(pool->skbuff && pool->dma_addr) {
- for(i = 0; i < pool->size; ++i) {
+ if (pool->skbuff && pool->dma_addr) {
+ for (i = 0; i < pool->size; ++i) {
struct sk_buff *skb = pool->skbuff[i];
- if(skb) {
+ if (skb) {
dma_unmap_single(&adapter->vdev->dev,
pool->dma_addr[i],
pool->buff_size,
@@ -343,31 +334,32 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibm
}
}
- if(pool->dma_addr) {
+ if (pool->dma_addr) {
kfree(pool->dma_addr);
pool->dma_addr = NULL;
}
- if(pool->skbuff) {
+ if (pool->skbuff) {
kfree(pool->skbuff);
pool->skbuff = NULL;
}
}
/* remove a buffer from a pool */
-static void ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter, u64 correlator)
+static void ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter,
+ u64 correlator)
{
unsigned int pool = correlator >> 32;
unsigned int index = correlator & 0xffffffffUL;
unsigned int free_index;
struct sk_buff *skb;
- ibmveth_assert(pool < IbmVethNumBufferPools);
- ibmveth_assert(index < adapter->rx_buff_pool[pool].size);
+ BUG_ON(pool >= IBMVETH_NUM_BUFF_POOLS);
+ BUG_ON(index >= adapter->rx_buff_pool[pool].size);
skb = adapter->rx_buff_pool[pool].skbuff[index];
- ibmveth_assert(skb != NULL);
+ BUG_ON(skb == NULL);
adapter->rx_buff_pool[pool].skbuff[index] = NULL;
@@ -377,9 +369,10 @@ static void ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter, u64
DMA_FROM_DEVICE);
free_index = adapter->rx_buff_pool[pool].producer_index;
- adapter->rx_buff_pool[pool].producer_index
- = (adapter->rx_buff_pool[pool].producer_index + 1)
- % adapter->rx_buff_pool[pool].size;
+ adapter->rx_buff_pool[pool].producer_index++;
+ if (adapter->rx_buff_pool[pool].producer_index >=
+ adapter->rx_buff_pool[pool].size)
+ adapter->rx_buff_pool[pool].producer_index = 0;
adapter->rx_buff_pool[pool].free_map[free_index] = index;
mb();
@@ -394,8 +387,8 @@ static inline struct sk_buff *ibmveth_rxq_get_buffer(struct ibmveth_adapter *ada
unsigned int pool = correlator >> 32;
unsigned int index = correlator & 0xffffffffUL;
- ibmveth_assert(pool < IbmVethNumBufferPools);
- ibmveth_assert(index < adapter->rx_buff_pool[pool].size);
+ BUG_ON(pool >= IBMVETH_NUM_BUFF_POOLS);
+ BUG_ON(index >= adapter->rx_buff_pool[pool].size);
return adapter->rx_buff_pool[pool].skbuff[index];
}
@@ -410,10 +403,10 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
union ibmveth_buf_desc desc;
unsigned long lpar_rc;
- ibmveth_assert(pool < IbmVethNumBufferPools);
- ibmveth_assert(index < adapter->rx_buff_pool[pool].size);
+ BUG_ON(pool >= IBMVETH_NUM_BUFF_POOLS);
+ BUG_ON(index >= adapter->rx_buff_pool[pool].size);
- if(!adapter->rx_buff_pool[pool].active) {
+ if (!adapter->rx_buff_pool[pool].active) {
ibmveth_rxq_harvest_buffer(adapter);
ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[pool]);
return;
@@ -425,12 +418,13 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc);
- if(lpar_rc != H_SUCCESS) {
- ibmveth_debug_printk("h_add_logical_lan_buffer failed during recycle rc=%ld", lpar_rc);
+ if (lpar_rc != H_SUCCESS) {
+ 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);
}
- if(++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
+ if (++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
adapter->rx_queue.index = 0;
adapter->rx_queue.toggle = !adapter->rx_queue.toggle;
}
@@ -440,7 +434,7 @@ static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter)
{
ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator);
- if(++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
+ if (++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
adapter->rx_queue.index = 0;
adapter->rx_queue.toggle = !adapter->rx_queue.toggle;
}
@@ -451,7 +445,7 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
int i;
struct device *dev = &adapter->vdev->dev;
- if(adapter->buffer_list_addr != NULL) {
+ if (adapter->buffer_list_addr != NULL) {
if (!dma_mapping_error(dev, adapter->buffer_list_dma)) {
dma_unmap_single(dev, adapter->buffer_list_dma, 4096,
DMA_BIDIRECTIONAL);
@@ -461,7 +455,7 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
adapter->buffer_list_addr = NULL;
}
- if(adapter->filter_list_addr != NULL) {
+ if (adapter->filter_list_addr != NULL) {
if (!dma_mapping_error(dev, adapter->filter_list_dma)) {
dma_unmap_single(dev, adapter->filter_list_dma, 4096,
DMA_BIDIRECTIONAL);
@@ -471,7 +465,7 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
adapter->filter_list_addr = NULL;
}
- if(adapter->rx_queue.queue_addr != NULL) {
+ if (adapter->rx_queue.queue_addr != NULL) {
if (!dma_mapping_error(dev, adapter->rx_queue.queue_dma)) {
dma_unmap_single(dev,
adapter->rx_queue.queue_dma,
@@ -483,7 +477,7 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
adapter->rx_queue.queue_addr = NULL;
}
- for(i = 0; i<IbmVethNumBufferPools; i++)
+ for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)
if (adapter->rx_buff_pool[i].active)
ibmveth_free_buffer_pool(adapter,
&adapter->rx_buff_pool[i]);
@@ -506,9 +500,11 @@ static int ibmveth_register_logical_lan(struct ibmveth_adapter *adapter,
{
int rc, try_again = 1;
- /* After a kexec the adapter will still be open, so our attempt to
- * open it will fail. So if we get a failure we free the adapter and
- * try again, but only once. */
+ /*
+ * After a kexec the adapter will still be open, so our attempt to
+ * open it will fail. So if we get a failure we free the adapter and
+ * try again, but only once.
+ */
retry:
rc = h_register_logical_lan(adapter->vdev->unit_address,
adapter->buffer_list_dma, rxq_desc.desc,
@@ -537,31 +533,32 @@ static int ibmveth_open(struct net_device *netdev)
int i;
struct device *dev;
- ibmveth_debug_printk("open starting\n");
+ netdev_dbg(netdev, "open starting\n");
napi_enable(&adapter->napi);
- for(i = 0; i<IbmVethNumBufferPools; i++)
+ for(i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)
rxq_entries += adapter->rx_buff_pool[i].size;
adapter->buffer_list_addr = (void*) get_zeroed_page(GFP_KERNEL);
adapter->filter_list_addr = (void*) get_zeroed_page(GFP_KERNEL);
- if(!adapter->buffer_list_addr || !adapter->filter_list_addr) {
- ibmveth_error_printk("unable to allocate filter or buffer list pages\n");
- ibmveth_cleanup(adapter);
- napi_disable(&adapter->napi);
- return -ENOMEM;
+ if (!adapter->buffer_list_addr || !adapter->filter_list_addr) {
+ netdev_err(netdev, "unable to allocate filter or buffer list "
+ "pages\n");
+ rc = -ENOMEM;
+ goto err_out;
}
- adapter->rx_queue.queue_len = sizeof(struct ibmveth_rx_q_entry) * rxq_entries;
- adapter->rx_queue.queue_addr = kmalloc(adapter->rx_queue.queue_len, GFP_KERNEL);
+ adapter->rx_queue.queue_len = sizeof(struct ibmveth_rx_q_entry) *
+ rxq_entries;
+ adapter->rx_queue.queue_addr = kmalloc(adapter->rx_queue.queue_len,
+ GFP_KERNEL);
- if(!adapter->rx_queue.queue_addr) {
- ibmveth_error_printk("unable to allocate rx queue pages\n");
- ibmveth_cleanup(adapter);
- napi_disable(&adapter->napi);
- return -ENOMEM;
+ if (!adapter->rx_queue.queue_addr) {
+ netdev_err(netdev, "unable to allocate rx queue pages\n");
+ rc = -ENOMEM;
+ goto err_out;
}
dev = &adapter->vdev->dev;
@@ -577,10 +574,10 @@ static int ibmveth_open(struct net_device *netdev)
if ((dma_mapping_error(dev, adapter->buffer_list_dma)) ||
(dma_mapping_error(dev, adapter->filter_list_dma)) ||
(dma_mapping_error(dev, adapter->rx_queue.queue_dma))) {
- ibmveth_error_printk("unable to map filter or buffer list pages\n");
- ibmveth_cleanup(adapter);
- napi_disable(&adapter->napi);
- return -ENOMEM;
+ netdev_err(netdev, "unable to map filter or buffer list "
+ "pages\n");
+ rc = -ENOMEM;
+ goto err_out;
}
adapter->rx_queue.index = 0;
@@ -590,79 +587,86 @@ static int ibmveth_open(struct net_device *netdev)
memcpy(&mac_address, netdev->dev_addr, netdev->addr_len);
mac_address = mac_address >> 16;
- rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | adapter->rx_queue.queue_len;
+ rxq_desc.fields.flags_len = IBMVETH_BUF_VALID |
+ adapter->rx_queue.queue_len;
rxq_desc.fields.address = adapter->rx_queue.queue_dma;
- ibmveth_debug_printk("buffer list @ 0x%p\n", adapter->buffer_list_addr);
- ibmveth_debug_printk("filter list @ 0x%p\n", adapter->filter_list_addr);
- ibmveth_debug_printk("receive q @ 0x%p\n", adapter->rx_queue.queue_addr);
+ netdev_dbg(netdev, "buffer list @ 0x%p\n", adapter->buffer_list_addr);
+ netdev_dbg(netdev, "filter list @ 0x%p\n", adapter->filter_list_addr);
+ netdev_dbg(netdev, "receive q @ 0x%p\n", adapter->rx_queue.queue_addr);
h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE);
lpar_rc = ibmveth_register_logical_lan(adapter, rxq_desc, mac_address);
- if(lpar_rc != H_SUCCESS) {
- ibmveth_error_printk("h_register_logical_lan failed with %ld\n", lpar_rc);
- ibmveth_error_printk("buffer TCE:0x%llx filter TCE:0x%llx rxq desc:0x%llx MAC:0x%llx\n",
+ if (lpar_rc != H_SUCCESS) {
+ netdev_err(netdev, "h_register_logical_lan failed with %ld\n",
+ lpar_rc);
+ netdev_err(netdev, "buffer TCE:0x%llx filter TCE:0x%llx rxq "
+ "desc:0x%llx MAC:0x%llx\n",
adapter->buffer_list_dma,
adapter->filter_list_dma,
rxq_desc.desc,
mac_address);
- ibmveth_cleanup(adapter);
- napi_disable(&adapter->napi);
- return -ENONET;
+ rc = -ENONET;
+ goto err_out;
}
- for(i = 0; i<IbmVethNumBufferPools; i++) {
- if(!adapter->rx_buff_pool[i].active)
+ for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
+ if (!adapter->rx_buff_pool[i].active)
continue;
if (ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[i])) {
- ibmveth_error_printk("unable to alloc pool\n");
+ netdev_err(netdev, "unable to alloc pool\n");
adapter->rx_buff_pool[i].active = 0;
- ibmveth_cleanup(adapter);
- napi_disable(&adapter->napi);
- return -ENOMEM ;
+ rc = -ENOMEM;
+ goto err_out;
}
}
- ibmveth_debug_printk("registering irq 0x%x\n", netdev->irq);
- if((rc = request_irq(netdev->irq, ibmveth_interrupt, 0, netdev->name, netdev)) != 0) {
- ibmveth_error_printk("unable to request irq 0x%x, rc %d\n", netdev->irq, rc);
+ netdev_dbg(netdev, "registering irq 0x%x\n", netdev->irq);
+ rc = request_irq(netdev->irq, ibmveth_interrupt, 0, netdev->name,
+ netdev);
+ if (rc != 0) {
+ 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));
- ibmveth_cleanup(adapter);
- napi_disable(&adapter->napi);
- return rc;
+ goto err_out;
}
adapter->bounce_buffer =
kmalloc(netdev->mtu + IBMVETH_BUFF_OH, GFP_KERNEL);
if (!adapter->bounce_buffer) {
- ibmveth_error_printk("unable to allocate bounce buffer\n");
- ibmveth_cleanup(adapter);
- napi_disable(&adapter->napi);
- return -ENOMEM;
+ netdev_err(netdev, "unable to allocate bounce buffer\n");
+ rc = -ENOMEM;
+ goto err_out_free_irq;
}
adapter->bounce_buffer_dma =
dma_map_single(&adapter->vdev->dev, adapter->bounce_buffer,
netdev->mtu + IBMVETH_BUFF_OH, DMA_BIDIRECTIONAL);
if (dma_mapping_error(dev, adapter->bounce_buffer_dma)) {
- ibmveth_error_printk("unable to map bounce buffer\n");
- ibmveth_cleanup(adapter);
- napi_disable(&adapter->napi);
- return -ENOMEM;
+ netdev_err(netdev, "unable to map bounce buffer\n");
+ rc = -ENOMEM;
+ goto err_out_free_irq;
}
- ibmveth_debug_printk("initial replenish cycle\n");
+ netdev_dbg(netdev, "initial replenish cycle\n");
ibmveth_interrupt(netdev->irq, netdev);
netif_start_queue(netdev);
- ibmveth_debug_printk("open complete\n");
+ netdev_dbg(netdev, "open complete\n");
return 0;
+
+err_out_free_irq:
+ free_irq(netdev->irq, netdev);
+err_out:
+ ibmveth_cleanup(adapter);
+ napi_disable(&adapter->napi);
+ return rc;
}
static int ibmveth_close(struct net_device *netdev)
@@ -670,7 +674,7 @@ static int ibmveth_close(struct net_device *netdev)
struct ibmveth_adapter *adapter = netdev_priv(netdev);
long lpar_rc;
- ibmveth_debug_printk("close starting\n");
+ netdev_dbg(netdev, "close starting\n");
napi_disable(&adapter->napi);
@@ -683,26 +687,29 @@ static int ibmveth_close(struct net_device *netdev)
lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
} while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY));
- if(lpar_rc != H_SUCCESS)
- {
- ibmveth_error_printk("h_free_logical_lan failed with %lx, continuing with close\n",
- lpar_rc);
+ if (lpar_rc != H_SUCCESS) {
+ netdev_err(netdev, "h_free_logical_lan failed with %lx, "
+ "continuing with close\n", lpar_rc);
}
free_irq(netdev->irq, netdev);
- adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8);
+ adapter->rx_no_buffer = *(u64 *)(((char *)adapter->buffer_list_addr) +
+ 4096 - 8);
ibmveth_cleanup(adapter);
- ibmveth_debug_printk("close complete\n");
+ netdev_dbg(netdev, "close complete\n");
return 0;
}
-static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) {
- cmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
- cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg | ADVERTISED_FIBRE);
+static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ cmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
+ SUPPORTED_FIBRE);
+ cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg |
+ ADVERTISED_FIBRE);
cmd->speed = SPEED_1000;
cmd->duplex = DUPLEX_FULL;
cmd->port = PORT_FIBRE;
@@ -714,12 +721,16 @@ static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
return 0;
}
-static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) {
+static void netdev_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
strncpy(info->driver, ibmveth_driver_name, sizeof(info->driver) - 1);
- strncpy(info->version, ibmveth_driver_version, sizeof(info->version) - 1);
+ strncpy(info->version, ibmveth_driver_version,
+ sizeof(info->version) - 1);
}
-static u32 netdev_get_link(struct net_device *dev) {
+static u32 netdev_get_link(struct net_device *dev)
+{
return 1;
}
@@ -727,18 +738,20 @@ static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data)
{
struct ibmveth_adapter *adapter = netdev_priv(dev);
- if (data)
+ if (data) {
adapter->rx_csum = 1;
- else {
+ } else {
/*
- * Since the ibmveth firmware interface does not have the concept of
- * separate tx/rx checksum offload enable, if rx checksum is disabled
- * we also have to disable tx checksum offload. Once we disable rx
- * checksum offload, we are no longer allowed to send tx buffers that
- * are not properly checksummed.
+ * Since the ibmveth firmware interface does not have the
+ * concept of separate tx/rx checksum offload enable, if rx
+ * checksum is disabled we also have to disable tx checksum
+ * offload. Once we disable rx checksum offload, we are no
+ * longer allowed to send tx buffers that are not properly
+ * checksummed.
*/
adapter->rx_csum = 0;
dev->features &= ~NETIF_F_IP_CSUM;
+ dev->features &= ~NETIF_F_IPV6_CSUM;
}
}
@@ -747,10 +760,15 @@ static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data)
struct ibmveth_adapter *adapter = netdev_priv(dev);
if (data) {
- dev->features |= NETIF_F_IP_CSUM;
+ if (adapter->fw_ipv4_csum_support)
+ dev->features |= NETIF_F_IP_CSUM;
+ if (adapter->fw_ipv6_csum_support)
+ dev->features |= NETIF_F_IPV6_CSUM;
adapter->rx_csum = 1;
- } else
+ } else {
dev->features &= ~NETIF_F_IP_CSUM;
+ dev->features &= ~NETIF_F_IPV6_CSUM;
+ }
}
static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
@@ -758,7 +776,8 @@ 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;
- long ret;
+ unsigned long set_attr6, clr_attr6;
+ long ret, ret6;
int rc1 = 0, rc2 = 0;
int restart = 0;
@@ -772,10 +791,13 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
set_attr = 0;
clr_attr = 0;
- if (data)
+ if (data) {
set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
- else
+ set_attr6 = IBMVETH_ILLAN_IPV6_TCP_CSUM;
+ } else {
clr_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
+ clr_attr6 = IBMVETH_ILLAN_IPV6_TCP_CSUM;
+ }
ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr);
@@ -786,18 +808,39 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
set_attr, &ret_attr);
if (ret != H_SUCCESS) {
- rc1 = -EIO;
- ibmveth_error_printk("unable to change checksum offload settings."
- " %d rc=%ld\n", data, ret);
+ netdev_err(dev, "unable to change IPv4 checksum "
+ "offload settings. %d rc=%ld\n",
+ data, ret);
ret = h_illan_attributes(adapter->vdev->unit_address,
set_attr, clr_attr, &ret_attr);
+ } else {
+ adapter->fw_ipv4_csum_support = data;
+ }
+
+ ret6 = h_illan_attributes(adapter->vdev->unit_address,
+ clr_attr6, set_attr6, &ret_attr);
+
+ if (ret6 != H_SUCCESS) {
+ netdev_err(dev, "unable to change IPv6 checksum "
+ "offload settings. %d rc=%ld\n",
+ data, ret);
+
+ 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)
done(dev, data);
+ else
+ rc1 = -EIO;
} else {
rc1 = -EIO;
- ibmveth_error_printk("unable to change checksum offload settings."
- " %d rc=%ld ret_attr=%lx\n", data, ret, ret_attr);
+ netdev_err(dev, "unable to change checksum offload settings."
+ " %d rc=%ld ret_attr=%lx\n", data, ret,
+ ret_attr);
}
if (restart)
@@ -821,13 +864,14 @@ static int ibmveth_set_tx_csum(struct net_device *dev, u32 data)
struct ibmveth_adapter *adapter = netdev_priv(dev);
int rc = 0;
- if (data && (dev->features & NETIF_F_IP_CSUM))
+ if (data && (dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)))
return 0;
- if (!data && !(dev->features & NETIF_F_IP_CSUM))
+ if (!data && !(dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)))
return 0;
if (data && !adapter->rx_csum)
- rc = ibmveth_set_csum_offload(dev, data, ibmveth_set_tx_csum_flags);
+ rc = ibmveth_set_csum_offload(dev, data,
+ ibmveth_set_tx_csum_flags);
else
ibmveth_set_tx_csum_flags(dev, data);
@@ -881,6 +925,7 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.get_strings = ibmveth_get_strings,
.get_sset_count = ibmveth_get_sset_count,
.get_ethtool_stats = ibmveth_get_ethtool_stats,
+ .set_sg = ethtool_op_set_sg,
};
static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -890,129 +935,216 @@ static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
#define page_offset(v) ((unsigned long)(v) & ((1 << 12) - 1))
-static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb,
- struct net_device *netdev)
+static int ibmveth_send(struct ibmveth_adapter *adapter,
+ union ibmveth_buf_desc *descs)
{
- struct ibmveth_adapter *adapter = netdev_priv(netdev);
- union ibmveth_buf_desc desc;
- unsigned long lpar_rc;
unsigned long correlator;
- unsigned long flags;
unsigned int retry_count;
- unsigned int tx_dropped = 0;
- unsigned int tx_bytes = 0;
- unsigned int tx_packets = 0;
- unsigned int tx_send_failed = 0;
- unsigned int tx_map_failed = 0;
- int used_bounce = 0;
- unsigned long data_dma_addr;
+ unsigned long ret;
- desc.fields.flags_len = IBMVETH_BUF_VALID | skb->len;
+ /*
+ * The retry count sets a maximum for the number of broadcast and
+ * multicast destinations within the system.
+ */
+ retry_count = 1024;
+ correlator = 0;
+ do {
+ ret = h_send_logical_lan(adapter->vdev->unit_address,
+ descs[0].desc, descs[1].desc,
+ descs[2].desc, descs[3].desc,
+ descs[4].desc, descs[5].desc,
+ correlator, &correlator);
+ } while ((ret == H_BUSY) && (retry_count--));
+ if (ret != H_SUCCESS && ret != H_DROPPED) {
+ netdev_err(adapter->netdev, "tx: h_send_logical_lan failed "
+ "with rc=%ld\n", ret);
+ return 1;
+ }
+
+ return 0;
+}
+
+static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ struct ibmveth_adapter *adapter = netdev_priv(netdev);
+ unsigned int desc_flags;
+ union ibmveth_buf_desc descs[6];
+ int last, i;
+ int force_bounce = 0;
+
+ /*
+ * veth handles a maximum of 6 segments including the header, so
+ * we have to linearize the skb if there are more than this.
+ */
+ if (skb_shinfo(skb)->nr_frags > 5 && __skb_linearize(skb)) {
+ netdev->stats.tx_dropped++;
+ goto out;
+ }
+
+ /* veth can't checksum offload UDP */
if (skb->ip_summed == CHECKSUM_PARTIAL &&
- ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) {
- ibmveth_error_printk("tx: failed to checksum packet\n");
- tx_dropped++;
+ ((skb->protocol == htons(ETH_P_IP) &&
+ ip_hdr(skb)->protocol != IPPROTO_TCP) ||
+ (skb->protocol == htons(ETH_P_IPV6) &&
+ ipv6_hdr(skb)->nexthdr != IPPROTO_TCP)) &&
+ skb_checksum_help(skb)) {
+
+ netdev_err(netdev, "tx: failed to checksum packet\n");
+ netdev->stats.tx_dropped++;
goto out;
}
+ desc_flags = IBMVETH_BUF_VALID;
+
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- unsigned char *buf = skb_transport_header(skb) + skb->csum_offset;
+ unsigned char *buf = skb_transport_header(skb) +
+ skb->csum_offset;
- desc.fields.flags_len |= (IBMVETH_BUF_NO_CSUM | IBMVETH_BUF_CSUM_GOOD);
+ desc_flags |= (IBMVETH_BUF_NO_CSUM | IBMVETH_BUF_CSUM_GOOD);
/* Need to zero out the checksum */
buf[0] = 0;
buf[1] = 0;
}
- data_dma_addr = dma_map_single(&adapter->vdev->dev, skb->data,
- skb->len, DMA_TO_DEVICE);
- if (dma_mapping_error(&adapter->vdev->dev, data_dma_addr)) {
- if (!firmware_has_feature(FW_FEATURE_CMO))
- ibmveth_error_printk("tx: unable to map xmit buffer\n");
+retry_bounce:
+ memset(descs, 0, sizeof(descs));
+
+ /*
+ * If a linear packet is below the rx threshold then
+ * copy it into the static bounce buffer. This avoids the
+ * cost of a TCE insert and remove.
+ */
+ if (force_bounce || (!skb_is_nonlinear(skb) &&
+ (skb->len < tx_copybreak))) {
skb_copy_from_linear_data(skb, adapter->bounce_buffer,
skb->len);
- desc.fields.address = adapter->bounce_buffer_dma;
- tx_map_failed++;
- used_bounce = 1;
- wmb();
- } else
- desc.fields.address = data_dma_addr;
-
- /* send the frame. Arbitrarily set retrycount to 1024 */
- correlator = 0;
- retry_count = 1024;
- do {
- lpar_rc = h_send_logical_lan(adapter->vdev->unit_address,
- desc.desc, 0, 0, 0, 0, 0,
- correlator, &correlator);
- } while ((lpar_rc == H_BUSY) && (retry_count--));
-
- if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) {
- ibmveth_error_printk("tx: h_send_logical_lan failed with rc=%ld\n", lpar_rc);
- ibmveth_error_printk("tx: valid=%d, len=%d, address=0x%08x\n",
- (desc.fields.flags_len & IBMVETH_BUF_VALID) ? 1 : 0,
- skb->len, desc.fields.address);
- tx_send_failed++;
- tx_dropped++;
- } else {
- tx_packets++;
- tx_bytes += skb->len;
- netdev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
+
+ descs[0].fields.flags_len = desc_flags | skb->len;
+ descs[0].fields.address = adapter->bounce_buffer_dma;
+
+ if (ibmveth_send(adapter, descs)) {
+ adapter->tx_send_failed++;
+ netdev->stats.tx_dropped++;
+ } else {
+ netdev->stats.tx_packets++;
+ netdev->stats.tx_bytes += skb->len;
+ }
+
+ goto out;
+ }
+
+ /* 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))
+ goto map_failed;
+
+ descs[0].fields.flags_len = desc_flags | skb_headlen(skb);
+
+ /* 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];
+
+ dma_addr = dma_map_page(&adapter->vdev->dev, frag->page,
+ frag->page_offset, frag->size,
+ 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.address = dma_addr;
}
- if (!used_bounce)
- dma_unmap_single(&adapter->vdev->dev, data_dma_addr,
- skb->len, DMA_TO_DEVICE);
+ if (ibmveth_send(adapter, descs)) {
+ adapter->tx_send_failed++;
+ netdev->stats.tx_dropped++;
+ } else {
+ netdev->stats.tx_packets++;
+ netdev->stats.tx_bytes += skb->len;
+ }
-out: spin_lock_irqsave(&adapter->stats_lock, flags);
- netdev->stats.tx_dropped += tx_dropped;
- netdev->stats.tx_bytes += tx_bytes;
- netdev->stats.tx_packets += tx_packets;
- adapter->tx_send_failed += tx_send_failed;
- adapter->tx_map_failed += tx_map_failed;
- spin_unlock_irqrestore(&adapter->stats_lock, flags);
+ for (i = 0; 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);
+out:
dev_kfree_skb(skb);
return NETDEV_TX_OK;
+
+map_failed_frags:
+ last = i+1;
+ for (i = 0; i < last; i++)
+ dma_unmap_page(&adapter->vdev->dev, descs[i].fields.address,
+ descs[i].fields.flags_len & IBMVETH_BUF_LEN_MASK,
+ DMA_TO_DEVICE);
+
+map_failed:
+ if (!firmware_has_feature(FW_FEATURE_CMO))
+ netdev_err(netdev, "tx: unable to map xmit buffer\n");
+ adapter->tx_map_failed++;
+ skb_linearize(skb);
+ force_bounce = 1;
+ goto retry_bounce;
}
static int ibmveth_poll(struct napi_struct *napi, int budget)
{
- struct ibmveth_adapter *adapter = container_of(napi, struct ibmveth_adapter, napi);
+ struct ibmveth_adapter *adapter =
+ container_of(napi, struct ibmveth_adapter, napi);
struct net_device *netdev = adapter->netdev;
int frames_processed = 0;
unsigned long lpar_rc;
- restart_poll:
+restart_poll:
do {
- struct sk_buff *skb;
-
if (!ibmveth_rxq_pending_buffer(adapter))
break;
- rmb();
+ smp_rmb();
if (!ibmveth_rxq_buffer_valid(adapter)) {
wmb(); /* suggested by larson1 */
adapter->rx_invalid_buffer++;
- ibmveth_debug_printk("recycling invalid buffer\n");
+ netdev_dbg(netdev, "recycling invalid buffer\n");
ibmveth_rxq_recycle_buffer(adapter);
} else {
+ struct sk_buff *skb, *new_skb;
int length = ibmveth_rxq_frame_length(adapter);
int offset = ibmveth_rxq_frame_offset(adapter);
int csum_good = ibmveth_rxq_csum_good(adapter);
skb = ibmveth_rxq_get_buffer(adapter);
- if (csum_good)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- ibmveth_rxq_harvest_buffer(adapter);
+ new_skb = NULL;
+ if (length < rx_copybreak)
+ new_skb = netdev_alloc_skb(netdev, length);
+
+ if (new_skb) {
+ skb_copy_to_linear_data(new_skb,
+ skb->data + offset,
+ length);
+ if (rx_flush)
+ ibmveth_flush_buffer(skb->data,
+ length + offset);
+ skb = new_skb;
+ ibmveth_rxq_recycle_buffer(adapter);
+ } else {
+ ibmveth_rxq_harvest_buffer(adapter);
+ skb_reserve(skb, offset);
+ }
- skb_reserve(skb, offset);
skb_put(skb, length);
skb->protocol = eth_type_trans(skb, netdev);
+ if (csum_good)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
netif_receive_skb(skb); /* send it up */
netdev->stats.rx_packets++;
@@ -1030,7 +1162,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
lpar_rc = h_vio_signal(adapter->vdev->unit_address,
VIO_IRQ_ENABLE);
- ibmveth_assert(lpar_rc == H_SUCCESS);
+ BUG_ON(lpar_rc != H_SUCCESS);
napi_complete(napi);
@@ -1054,7 +1186,7 @@ static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance)
if (napi_schedule_prep(&adapter->napi)) {
lpar_rc = h_vio_signal(adapter->vdev->unit_address,
VIO_IRQ_DISABLE);
- ibmveth_assert(lpar_rc == H_SUCCESS);
+ BUG_ON(lpar_rc != H_SUCCESS);
__napi_schedule(&adapter->napi);
}
return IRQ_HANDLED;
@@ -1071,8 +1203,9 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
IbmVethMcastEnableRecv |
IbmVethMcastDisableFiltering,
0);
- if(lpar_rc != H_SUCCESS) {
- ibmveth_error_printk("h_multicast_ctrl rc=%ld when entering promisc mode\n", lpar_rc);
+ if (lpar_rc != H_SUCCESS) {
+ netdev_err(netdev, "h_multicast_ctrl rc=%ld when "
+ "entering promisc mode\n", lpar_rc);
}
} else {
struct netdev_hw_addr *ha;
@@ -1082,19 +1215,23 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
IbmVethMcastDisableFiltering |
IbmVethMcastClearFilterTable,
0);
- if(lpar_rc != H_SUCCESS) {
- ibmveth_error_printk("h_multicast_ctrl rc=%ld when attempting to clear filter table\n", lpar_rc);
+ if (lpar_rc != H_SUCCESS) {
+ netdev_err(netdev, "h_multicast_ctrl rc=%ld when "
+ "attempting to clear filter table\n",
+ lpar_rc);
}
/* add the addresses to the filter table */
netdev_for_each_mc_addr(ha, netdev) {
- // add the multicast address to the filter table
+ /* add the multicast address to the filter table */
unsigned long mcast_addr = 0;
memcpy(((char *)&mcast_addr)+2, ha->addr, 6);
lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
IbmVethMcastAddFilter,
mcast_addr);
- if(lpar_rc != H_SUCCESS) {
- ibmveth_error_printk("h_multicast_ctrl rc=%ld when adding an entry to the filter table\n", lpar_rc);
+ if (lpar_rc != H_SUCCESS) {
+ netdev_err(netdev, "h_multicast_ctrl rc=%ld "
+ "when adding an entry to the filter "
+ "table\n", lpar_rc);
}
}
@@ -1102,8 +1239,9 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
IbmVethMcastEnableFiltering,
0);
- if(lpar_rc != H_SUCCESS) {
- ibmveth_error_printk("h_multicast_ctrl rc=%ld when enabling filtering\n", lpar_rc);
+ if (lpar_rc != H_SUCCESS) {
+ netdev_err(netdev, "h_multicast_ctrl rc=%ld when "
+ "enabling filtering\n", lpar_rc);
}
}
}
@@ -1116,14 +1254,14 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu)
int i, rc;
int need_restart = 0;
- if (new_mtu < IBMVETH_MAX_MTU)
+ if (new_mtu < IBMVETH_MIN_MTU)
return -EINVAL;
- for (i = 0; i < IbmVethNumBufferPools; i++)
+ for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)
if (new_mtu_oh < adapter->rx_buff_pool[i].buff_size)
break;
- if (i == IbmVethNumBufferPools)
+ if (i == IBMVETH_NUM_BUFF_POOLS)
return -EINVAL;
/* Deactivate all the buffer pools so that the next loop can activate
@@ -1136,7 +1274,7 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu)
}
/* Look for an active buffer pool that can hold the new MTU */
- for(i = 0; i<IbmVethNumBufferPools; i++) {
+ for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
adapter->rx_buff_pool[i].active = 1;
if (new_mtu_oh < adapter->rx_buff_pool[i].buff_size) {
@@ -1190,7 +1328,7 @@ static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev)
ret = IBMVETH_BUFF_LIST_SIZE + IBMVETH_FILT_LIST_SIZE;
ret += IOMMU_PAGE_ALIGN(netdev->mtu);
- for (i = 0; i < IbmVethNumBufferPools; i++) {
+ for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
/* add the size of the active receive buffers */
if (adapter->rx_buff_pool[i].active)
ret +=
@@ -1219,41 +1357,36 @@ static const struct net_device_ops ibmveth_netdev_ops = {
#endif
};
-static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
+static int __devinit ibmveth_probe(struct vio_dev *dev,
+ const struct vio_device_id *id)
{
int rc, i;
- long ret;
struct net_device *netdev;
struct ibmveth_adapter *adapter;
- unsigned long set_attr, ret_attr;
-
unsigned char *mac_addr_p;
unsigned int *mcastFilterSize_p;
+ dev_dbg(&dev->dev, "entering ibmveth_probe for UA 0x%x\n",
+ dev->unit_address);
- ibmveth_debug_printk_no_adapter("entering ibmveth_probe for UA 0x%x\n",
- dev->unit_address);
-
- mac_addr_p = (unsigned char *) vio_get_attribute(dev,
- VETH_MAC_ADDR, NULL);
- if(!mac_addr_p) {
- printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find VETH_MAC_ADDR "
- "attribute\n", __FILE__, __LINE__);
- return 0;
+ mac_addr_p = (unsigned char *)vio_get_attribute(dev, VETH_MAC_ADDR,
+ NULL);
+ if (!mac_addr_p) {
+ dev_err(&dev->dev, "Can't find VETH_MAC_ADDR attribute\n");
+ return -EINVAL;
}
- mcastFilterSize_p = (unsigned int *) vio_get_attribute(dev,
+ mcastFilterSize_p = (unsigned int *)vio_get_attribute(dev,
VETH_MCAST_FILTER_SIZE, NULL);
- if(!mcastFilterSize_p) {
- printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find "
- "VETH_MCAST_FILTER_SIZE attribute\n",
- __FILE__, __LINE__);
- return 0;
+ if (!mcastFilterSize_p) {
+ dev_err(&dev->dev, "Can't find VETH_MCAST_FILTER_SIZE "
+ "attribute\n");
+ return -EINVAL;
}
netdev = alloc_etherdev(sizeof(struct ibmveth_adapter));
- if(!netdev)
+ if (!netdev)
return -ENOMEM;
adapter = netdev_priv(netdev);
@@ -1261,19 +1394,19 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
adapter->vdev = dev;
adapter->netdev = netdev;
- adapter->mcastFilterSize= *mcastFilterSize_p;
+ adapter->mcastFilterSize = *mcastFilterSize_p;
adapter->pool_config = 0;
netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16);
- /* Some older boxes running PHYP non-natively have an OF that
- returns a 8-byte local-mac-address field (and the first
- 2 bytes have to be ignored) while newer boxes' OF return
- a 6-byte field. Note that IEEE 1275 specifies that
- local-mac-address must be a 6-byte field.
- The RPA doc specifies that the first byte must be 10b, so
- we'll just look for it to solve this 8 vs. 6 byte field issue */
-
+ /*
+ * Some older boxes running PHYP non-natively have an OF that returns
+ * a 8-byte local-mac-address field (and the first 2 bytes have to be
+ * ignored) while newer boxes' OF return a 6-byte field. Note that
+ * IEEE 1275 specifies that local-mac-address must be a 6-byte field.
+ * The RPA doc specifies that the first byte must be 10b, so we'll
+ * just look for it to solve this 8 vs. 6 byte field issue
+ */
if ((*mac_addr_p & 0x3) != 0x02)
mac_addr_p += 2;
@@ -1284,12 +1417,11 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
netdev->netdev_ops = &ibmveth_netdev_ops;
netdev->ethtool_ops = &netdev_ethtool_ops;
SET_NETDEV_DEV(netdev, &dev->dev);
- netdev->features |= NETIF_F_LLTX;
- spin_lock_init(&adapter->stats_lock);
+ netdev->features |= NETIF_F_SG;
memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len);
- for(i = 0; i<IbmVethNumBufferPools; i++) {
+ for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
struct kobject *kobj = &adapter->rx_buff_pool[i].kobj;
int error;
@@ -1302,41 +1434,25 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
kobject_uevent(kobj, KOBJ_ADD);
}
- ibmveth_debug_printk("adapter @ 0x%p\n", adapter);
+ netdev_dbg(netdev, "adapter @ 0x%p\n", adapter);
adapter->buffer_list_dma = DMA_ERROR_CODE;
adapter->filter_list_dma = DMA_ERROR_CODE;
adapter->rx_queue.queue_dma = DMA_ERROR_CODE;
- ibmveth_debug_printk("registering netdev...\n");
+ netdev_dbg(netdev, "registering netdev...\n");
- ret = h_illan_attributes(dev->unit_address, 0, 0, &ret_attr);
-
- if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) &&
- !(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) &&
- (ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) {
- set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
-
- ret = h_illan_attributes(dev->unit_address, 0, set_attr, &ret_attr);
-
- if (ret == H_SUCCESS) {
- adapter->rx_csum = 1;
- netdev->features |= NETIF_F_IP_CSUM;
- } else
- ret = h_illan_attributes(dev->unit_address, set_attr, 0, &ret_attr);
- }
+ ibmveth_set_csum_offload(netdev, 1, ibmveth_set_tx_csum_flags);
rc = register_netdev(netdev);
- if(rc) {
- ibmveth_debug_printk("failed to register netdev rc=%d\n", rc);
+ if (rc) {
+ netdev_dbg(netdev, "failed to register netdev rc=%d\n", rc);
free_netdev(netdev);
return rc;
}
- ibmveth_debug_printk("registered\n");
-
- ibmveth_proc_register_adapter(adapter);
+ netdev_dbg(netdev, "registered\n");
return 0;
}
@@ -1347,114 +1463,23 @@ static int __devexit ibmveth_remove(struct vio_dev *dev)
struct ibmveth_adapter *adapter = netdev_priv(netdev);
int i;
- for(i = 0; i<IbmVethNumBufferPools; i++)
+ for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)
kobject_put(&adapter->rx_buff_pool[i].kobj);
unregister_netdev(netdev);
- ibmveth_proc_unregister_adapter(adapter);
-
free_netdev(netdev);
dev_set_drvdata(&dev->dev, NULL);
return 0;
}
-#ifdef CONFIG_PROC_FS
-static void ibmveth_proc_register_driver(void)
-{
- ibmveth_proc_dir = proc_mkdir(IBMVETH_PROC_DIR, init_net.proc_net);
- if (ibmveth_proc_dir) {
- }
-}
-
-static void ibmveth_proc_unregister_driver(void)
-{
- remove_proc_entry(IBMVETH_PROC_DIR, init_net.proc_net);
-}
-
-static int ibmveth_show(struct seq_file *seq, void *v)
-{
- struct ibmveth_adapter *adapter = seq->private;
- char *current_mac = (char *) adapter->netdev->dev_addr;
- char *firmware_mac = (char *) &adapter->mac_addr;
-
- seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version);
-
- seq_printf(seq, "Unit Address: 0x%x\n", adapter->vdev->unit_address);
- seq_printf(seq, "Current MAC: %pM\n", current_mac);
- seq_printf(seq, "Firmware MAC: %pM\n", firmware_mac);
-
- seq_printf(seq, "\nAdapter Statistics:\n");
- seq_printf(seq, " TX: vio_map_single failres: %lld\n", adapter->tx_map_failed);
- seq_printf(seq, " send failures: %lld\n", adapter->tx_send_failed);
- seq_printf(seq, " RX: replenish task cycles: %lld\n", adapter->replenish_task_cycles);
- seq_printf(seq, " alloc_skb_failures: %lld\n", adapter->replenish_no_mem);
- seq_printf(seq, " add buffer failures: %lld\n", adapter->replenish_add_buff_failure);
- seq_printf(seq, " invalid buffers: %lld\n", adapter->rx_invalid_buffer);
- seq_printf(seq, " no buffers: %lld\n", adapter->rx_no_buffer);
-
- return 0;
-}
-
-static int ibmveth_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ibmveth_show, PDE(inode)->data);
-}
-
-static const struct file_operations ibmveth_proc_fops = {
- .owner = THIS_MODULE,
- .open = ibmveth_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter)
-{
- struct proc_dir_entry *entry;
- if (ibmveth_proc_dir) {
- char u_addr[10];
- sprintf(u_addr, "%x", adapter->vdev->unit_address);
- entry = proc_create_data(u_addr, S_IFREG, ibmveth_proc_dir,
- &ibmveth_proc_fops, adapter);
- if (!entry)
- ibmveth_error_printk("Cannot create adapter proc entry");
- }
-}
-
-static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter)
-{
- if (ibmveth_proc_dir) {
- char u_addr[10];
- sprintf(u_addr, "%x", adapter->vdev->unit_address);
- remove_proc_entry(u_addr, ibmveth_proc_dir);
- }
-}
-
-#else /* CONFIG_PROC_FS */
-static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter)
-{
-}
-
-static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter)
-{
-}
-static void ibmveth_proc_register_driver(void)
-{
-}
-
-static void ibmveth_proc_unregister_driver(void)
-{
-}
-#endif /* CONFIG_PROC_FS */
-
static struct attribute veth_active_attr;
static struct attribute veth_num_attr;
static struct attribute veth_size_attr;
-static ssize_t veth_pool_show(struct kobject * kobj,
- struct attribute * attr, char * buf)
+static ssize_t veth_pool_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
{
struct ibmveth_buff_pool *pool = container_of(kobj,
struct ibmveth_buff_pool,
@@ -1469,8 +1494,8 @@ static ssize_t veth_pool_show(struct kobject * kobj,
return 0;
}
-static ssize_t veth_pool_store(struct kobject * kobj, struct attribute * attr,
-const char * buf, size_t count)
+static ssize_t veth_pool_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
{
struct ibmveth_buff_pool *pool = container_of(kobj,
struct ibmveth_buff_pool,
@@ -1484,8 +1509,9 @@ const char * buf, size_t count)
if (attr == &veth_active_attr) {
if (value && !pool->active) {
if (netif_running(netdev)) {
- if(ibmveth_alloc_buffer_pool(pool)) {
- ibmveth_error_printk("unable to alloc pool\n");
+ if (ibmveth_alloc_buffer_pool(pool)) {
+ netdev_err(netdev,
+ "unable to alloc pool\n");
return -ENOMEM;
}
pool->active = 1;
@@ -1494,14 +1520,15 @@ const char * buf, size_t count)
adapter->pool_config = 0;
if ((rc = ibmveth_open(netdev)))
return rc;
- } else
+ } else {
pool->active = 1;
+ }
} else if (!value && pool->active) {
int mtu = netdev->mtu + IBMVETH_BUFF_OH;
int i;
/* Make sure there is a buffer pool with buffers that
can hold a packet of the size of the MTU */
- for (i = 0; i < IbmVethNumBufferPools; i++) {
+ for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
if (pool == &adapter->rx_buff_pool[i])
continue;
if (!adapter->rx_buff_pool[i].active)
@@ -1510,8 +1537,8 @@ const char * buf, size_t count)
break;
}
- if (i == IbmVethNumBufferPools) {
- ibmveth_error_printk("no active pool >= MTU\n");
+ if (i == IBMVETH_NUM_BUFF_POOLS) {
+ netdev_err(netdev, "no active pool >= MTU\n");
return -EPERM;
}
@@ -1526,9 +1553,9 @@ const char * buf, size_t count)
pool->active = 0;
}
} else if (attr == &veth_num_attr) {
- if (value <= 0 || value > IBMVETH_MAX_POOL_COUNT)
+ if (value <= 0 || value > IBMVETH_MAX_POOL_COUNT) {
return -EINVAL;
- else {
+ } else {
if (netif_running(netdev)) {
adapter->pool_config = 1;
ibmveth_close(netdev);
@@ -1536,13 +1563,14 @@ const char * buf, size_t count)
pool->size = value;
if ((rc = ibmveth_open(netdev)))
return rc;
- } else
+ } else {
pool->size = value;
+ }
}
} else if (attr == &veth_size_attr) {
- if (value <= IBMVETH_BUFF_OH || value > IBMVETH_MAX_BUF_SIZE)
+ if (value <= IBMVETH_BUFF_OH || value > IBMVETH_MAX_BUF_SIZE) {
return -EINVAL;
- else {
+ } else {
if (netif_running(netdev)) {
adapter->pool_config = 1;
ibmveth_close(netdev);
@@ -1550,8 +1578,9 @@ const char * buf, size_t count)
pool->buff_size = value;
if ((rc = ibmveth_open(netdev)))
return rc;
- } else
+ } else {
pool->buff_size = value;
+ }
}
}
@@ -1561,16 +1590,16 @@ const char * buf, size_t count)
}
-#define ATTR(_name, _mode) \
- struct attribute veth_##_name##_attr = { \
- .name = __stringify(_name), .mode = _mode, \
- };
+#define ATTR(_name, _mode) \
+ struct attribute veth_##_name##_attr = { \
+ .name = __stringify(_name), .mode = _mode, \
+ };
static ATTR(active, 0644);
static ATTR(num, 0644);
static ATTR(size, 0644);
-static struct attribute * veth_pool_attrs[] = {
+static struct attribute *veth_pool_attrs[] = {
&veth_active_attr,
&veth_num_attr,
&veth_size_attr,
@@ -1595,7 +1624,7 @@ static int ibmveth_resume(struct device *dev)
return 0;
}
-static struct vio_device_id ibmveth_device_table[] __devinitdata= {
+static struct vio_device_id ibmveth_device_table[] __devinitdata = {
{ "network", "IBM,l-lan"},
{ "", "" }
};
@@ -1619,9 +1648,8 @@ static struct vio_driver ibmveth_driver = {
static int __init ibmveth_module_init(void)
{
- ibmveth_printk("%s: %s %s\n", ibmveth_driver_name, ibmveth_driver_string, ibmveth_driver_version);
-
- ibmveth_proc_register_driver();
+ printk(KERN_DEBUG "%s: %s %s\n", ibmveth_driver_name,
+ ibmveth_driver_string, ibmveth_driver_version);
return vio_register_driver(&ibmveth_driver);
}
@@ -1629,7 +1657,6 @@ static int __init ibmveth_module_init(void)
static void __exit ibmveth_module_exit(void)
{
vio_unregister_driver(&ibmveth_driver);
- ibmveth_proc_unregister_driver();
}
module_init(ibmveth_module_init);
diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h
index ec76ace66c6b..43a794fab9ff 100644
--- a/drivers/net/ibmveth.h
+++ b/drivers/net/ibmveth.h
@@ -1,26 +1,28 @@
-/**************************************************************************/
-/* */
-/* IBM eServer i/[Series Virtual Ethernet Device Driver */
-/* Copyright (C) 2003 IBM Corp. */
-/* Dave Larson (larson1@us.ibm.com) */
-/* Santiago Leon (santil@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; 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 */
-/* */
-/**************************************************************************/
+/*
+ * IBM Power Virtual Ethernet Device Driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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.
+ *
+ * Copyright (C) IBM Corporation, 2003, 2010
+ *
+ * Authors: Dave Larson <larson1@us.ibm.com>
+ * Santiago Leon <santil@linux.vnet.ibm.com>
+ * Brian King <brking@linux.vnet.ibm.com>
+ * Robert Jennings <rcj@linux.vnet.ibm.com>
+ * Anton Blanchard <anton@au.ibm.com>
+ */
#ifndef _IBMVETH_H
#define _IBMVETH_H
@@ -92,17 +94,17 @@ static inline long h_illan_attributes(unsigned long unit_address,
#define h_change_logical_lan_mac(ua, mac) \
plpar_hcall_norets(H_CHANGE_LOGICAL_LAN_MAC, ua, mac)
-#define IbmVethNumBufferPools 5
+#define IBMVETH_NUM_BUFF_POOLS 5
#define IBMVETH_IO_ENTITLEMENT_DEFAULT 4243456 /* MTU of 1500 needs 4.2Mb */
#define IBMVETH_BUFF_OH 22 /* Overhead: 14 ethernet header + 8 opaque handle */
-#define IBMVETH_MAX_MTU 68
+#define IBMVETH_MIN_MTU 68
#define IBMVETH_MAX_POOL_COUNT 4096
#define IBMVETH_BUFF_LIST_SIZE 4096
#define IBMVETH_FILT_LIST_SIZE 4096
#define IBMVETH_MAX_BUF_SIZE (1024 * 128)
static int pool_size[] = { 512, 1024 * 2, 1024 * 16, 1024 * 32, 1024 * 64 };
-static int pool_count[] = { 256, 768, 256, 256, 256 };
+static int pool_count[] = { 256, 512, 256, 256, 256 };
static int pool_active[] = { 1, 1, 0, 0, 0};
#define IBM_VETH_INVALID_MAP ((u16)0xffff)
@@ -142,13 +144,15 @@ struct ibmveth_adapter {
void * filter_list_addr;
dma_addr_t buffer_list_dma;
dma_addr_t filter_list_dma;
- struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools];
+ struct ibmveth_buff_pool rx_buff_pool[IBMVETH_NUM_BUFF_POOLS];
struct ibmveth_rx_q rx_queue;
int pool_config;
int rx_csum;
void *bounce_buffer;
dma_addr_t bounce_buffer_dma;
+ u64 fw_ipv6_csum_support;
+ u64 fw_ipv4_csum_support;
/* adapter specific stats */
u64 replenish_task_cycles;
u64 replenish_no_mem;
@@ -158,7 +162,6 @@ struct ibmveth_adapter {
u64 rx_no_buffer;
u64 tx_map_failed;
u64 tx_send_failed;
- spinlock_t stats_lock;
};
struct ibmveth_buf_desc_fields {
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index 187622f1c816..bc183f5487cb 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -132,6 +132,8 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
case E1000_DEV_ID_82580_SERDES:
case E1000_DEV_ID_82580_SGMII:
case E1000_DEV_ID_82580_COPPER_DUAL:
+ case E1000_DEV_ID_DH89XXCC_SGMII:
+ case E1000_DEV_ID_DH89XXCC_SERDES:
mac->type = e1000_82580;
break;
case E1000_DEV_ID_I350_COPPER:
@@ -282,10 +284,18 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
/* Verify phy id and set remaining function pointers */
switch (phy->id) {
+ case I347AT4_E_PHY_ID:
+ case M88E1112_E_PHY_ID:
case M88E1111_I_PHY_ID:
phy->type = e1000_phy_m88;
phy->ops.get_phy_info = igb_get_phy_info_m88;
- phy->ops.get_cable_length = igb_get_cable_length_m88;
+
+ if (phy->id == I347AT4_E_PHY_ID ||
+ phy->id == M88E1112_E_PHY_ID)
+ phy->ops.get_cable_length = igb_get_cable_length_m88_gen2;
+ else
+ phy->ops.get_cable_length = igb_get_cable_length_m88;
+
phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
break;
case IGP03E1000_E_PHY_ID:
@@ -1058,7 +1068,11 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
}
switch (hw->phy.type) {
case e1000_phy_m88:
- ret_val = igb_copper_link_setup_m88(hw);
+ if (hw->phy.id == I347AT4_E_PHY_ID ||
+ hw->phy.id == M88E1112_E_PHY_ID)
+ ret_val = igb_copper_link_setup_m88_gen2(hw);
+ else
+ ret_val = igb_copper_link_setup_m88(hw);
break;
case e1000_phy_igp_3:
ret_val = igb_copper_link_setup_igp(hw);
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h
index bbd2ec308eb0..62222796a8b3 100644
--- a/drivers/net/igb/e1000_defines.h
+++ b/drivers/net/igb/e1000_defines.h
@@ -634,6 +634,8 @@
* E = External
*/
#define M88E1111_I_PHY_ID 0x01410CC0
+#define M88E1112_E_PHY_ID 0x01410C90
+#define I347AT4_E_PHY_ID 0x01410DC0
#define IGP03E1000_E_PHY_ID 0x02A80390
#define I82580_I_PHY_ID 0x015403A0
#define I350_I_PHY_ID 0x015403B0
@@ -702,6 +704,35 @@
#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100
#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
+/* Intel i347-AT4 Registers */
+
+#define I347AT4_PCDL 0x10 /* PHY Cable Diagnostics Length */
+#define I347AT4_PCDC 0x15 /* PHY Cable Diagnostics Control */
+#define I347AT4_PAGE_SELECT 0x16
+
+/* i347-AT4 Extended PHY Specific Control Register */
+
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master
+ */
+#define I347AT4_PSCR_DOWNSHIFT_ENABLE 0x0800
+#define I347AT4_PSCR_DOWNSHIFT_MASK 0x7000
+#define I347AT4_PSCR_DOWNSHIFT_1X 0x0000
+#define I347AT4_PSCR_DOWNSHIFT_2X 0x1000
+#define I347AT4_PSCR_DOWNSHIFT_3X 0x2000
+#define I347AT4_PSCR_DOWNSHIFT_4X 0x3000
+#define I347AT4_PSCR_DOWNSHIFT_5X 0x4000
+#define I347AT4_PSCR_DOWNSHIFT_6X 0x5000
+#define I347AT4_PSCR_DOWNSHIFT_7X 0x6000
+#define I347AT4_PSCR_DOWNSHIFT_8X 0x7000
+
+/* i347-AT4 PHY Cable Diagnostics Control */
+#define I347AT4_PCDC_CABLE_LENGTH_UNIT 0x0400 /* 0=cm 1=meters */
+
+/* Marvell 1112 only registers */
+#define M88E1112_VCT_DSP_DISTANCE 0x001A
+
/* M88EC018 Rev 2 specific DownShift settings */
#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00
#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800
diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h
index cb8db78b1a05..c0b017f8d782 100644
--- a/drivers/net/igb/e1000_hw.h
+++ b/drivers/net/igb/e1000_hw.h
@@ -54,6 +54,8 @@ struct e1000_hw;
#define E1000_DEV_ID_82580_SERDES 0x1510
#define E1000_DEV_ID_82580_SGMII 0x1511
#define E1000_DEV_ID_82580_COPPER_DUAL 0x1516
+#define E1000_DEV_ID_DH89XXCC_SGMII 0x0436
+#define E1000_DEV_ID_DH89XXCC_SERDES 0x0438
#define E1000_DEV_ID_I350_COPPER 0x1521
#define E1000_DEV_ID_I350_FIBER 0x1522
#define E1000_DEV_ID_I350_SERDES 0x1523
diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c
index cf1f32300923..ddd036a78999 100644
--- a/drivers/net/igb/e1000_phy.c
+++ b/drivers/net/igb/e1000_phy.c
@@ -570,6 +570,89 @@ out:
}
/**
+ * igb_copper_link_setup_m88_gen2 - Setup m88 PHY's for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Sets up MDI/MDI-X and polarity for i347-AT4, m88e1322 and m88e1112 PHY's.
+ * Also enables and sets the downshift parameters.
+ **/
+s32 igb_copper_link_setup_m88_gen2(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data;
+
+ if (phy->reset_disable) {
+ ret_val = 0;
+ goto out;
+ }
+
+ /* Enable CRS on Tx. This must be set for half-duplex operation. */
+ ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ /*
+ * Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+ switch (phy->mdix) {
+ case 1:
+ phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+ break;
+ case 2:
+ phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+ break;
+ case 3:
+ /* M88E1112 does not support this mode) */
+ if (phy->id != M88E1112_E_PHY_ID) {
+ phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+ break;
+ }
+ case 0:
+ default:
+ phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+ break;
+ }
+
+ /*
+ * Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+ if (phy->disable_polarity_correction == 1)
+ phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+
+ /* Enable downshift and setting it to X6 */
+ phy_data &= ~I347AT4_PSCR_DOWNSHIFT_MASK;
+ phy_data |= I347AT4_PSCR_DOWNSHIFT_6X;
+ phy_data |= I347AT4_PSCR_DOWNSHIFT_ENABLE;
+
+ ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ goto out;
+
+ /* Commit the changes. */
+ ret_val = igb_phy_sw_reset(hw);
+ if (ret_val) {
+ hw_dbg("Error committing the PHY changes\n");
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
* igb_copper_link_setup_igp - Setup igp PHY's for copper link
* @hw: pointer to the HW structure
*
@@ -1124,18 +1207,25 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
goto out;
if (!link) {
- /*
- * We didn't get link.
- * Reset the DSP and cross our fingers.
- */
- ret_val = phy->ops.write_reg(hw,
- M88E1000_PHY_PAGE_SELECT,
- 0x001d);
- if (ret_val)
- goto out;
- ret_val = igb_phy_reset_dsp(hw);
- if (ret_val)
- goto out;
+ if (hw->phy.type != e1000_phy_m88 ||
+ hw->phy.id == I347AT4_E_PHY_ID ||
+ hw->phy.id == M88E1112_E_PHY_ID) {
+ hw_dbg("Link taking longer than expected.\n");
+ } else {
+
+ /*
+ * We didn't get link.
+ * Reset the DSP and cross our fingers.
+ */
+ ret_val = phy->ops.write_reg(hw,
+ M88E1000_PHY_PAGE_SELECT,
+ 0x001d);
+ if (ret_val)
+ goto out;
+ ret_val = igb_phy_reset_dsp(hw);
+ if (ret_val)
+ goto out;
+ }
}
/* Try once more */
@@ -1145,6 +1235,11 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
goto out;
}
+ if (hw->phy.type != e1000_phy_m88 ||
+ hw->phy.id == I347AT4_E_PHY_ID ||
+ hw->phy.id == M88E1112_E_PHY_ID)
+ goto out;
+
ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
if (ret_val)
goto out;
@@ -1557,6 +1652,93 @@ out:
return ret_val;
}
+s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data, phy_data2, index, default_page, is_cm;
+
+ switch (hw->phy.id) {
+ case I347AT4_E_PHY_ID:
+ /* Remember the original page select and set it to 7 */
+ ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT,
+ &default_page);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0x07);
+ if (ret_val)
+ goto out;
+
+ /* Get cable length from PHY Cable Diagnostics Control Reg */
+ ret_val = phy->ops.read_reg(hw, (I347AT4_PCDL + phy->addr),
+ &phy_data);
+ if (ret_val)
+ goto out;
+
+ /* Check if the unit of cable length is meters or cm */
+ ret_val = phy->ops.read_reg(hw, I347AT4_PCDC, &phy_data2);
+ if (ret_val)
+ goto out;
+
+ is_cm = !(phy_data & I347AT4_PCDC_CABLE_LENGTH_UNIT);
+
+ /* Populate the phy structure with cable length in meters */
+ phy->min_cable_length = phy_data / (is_cm ? 100 : 1);
+ phy->max_cable_length = phy_data / (is_cm ? 100 : 1);
+ phy->cable_length = phy_data / (is_cm ? 100 : 1);
+
+ /* Reset the page selec to its original value */
+ ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT,
+ default_page);
+ if (ret_val)
+ goto out;
+ break;
+ case M88E1112_E_PHY_ID:
+ /* Remember the original page select and set it to 5 */
+ ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT,
+ &default_page);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0x05);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, M88E1112_VCT_DSP_DISTANCE,
+ &phy_data);
+ if (ret_val)
+ goto out;
+
+ index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+ if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+ phy->min_cable_length = e1000_m88_cable_length_table[index];
+ phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
+
+ phy->cable_length = (phy->min_cable_length +
+ phy->max_cable_length) / 2;
+
+ /* Reset the page select to its original value */
+ ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT,
+ default_page);
+ if (ret_val)
+ goto out;
+
+ break;
+ default:
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
/**
* igb_get_cable_length_igp_2 - Determine cable length for igp2 PHY
* @hw: pointer to the HW structure
diff --git a/drivers/net/igb/e1000_phy.h b/drivers/net/igb/e1000_phy.h
index 565a6dbb3714..2cc117705a31 100644
--- a/drivers/net/igb/e1000_phy.h
+++ b/drivers/net/igb/e1000_phy.h
@@ -45,9 +45,11 @@ s32 igb_check_downshift(struct e1000_hw *hw);
s32 igb_check_reset_block(struct e1000_hw *hw);
s32 igb_copper_link_setup_igp(struct e1000_hw *hw);
s32 igb_copper_link_setup_m88(struct e1000_hw *hw);
+s32 igb_copper_link_setup_m88_gen2(struct e1000_hw *hw);
s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw);
s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw);
s32 igb_get_cable_length_m88(struct e1000_hw *hw);
+s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw);
s32 igb_get_cable_length_igp_2(struct e1000_hw *hw);
s32 igb_get_phy_id(struct e1000_hw *hw);
s32 igb_get_phy_info_igp(struct e1000_hw *hw);
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h
index 6e63d9a7fc75..edab9c442399 100644
--- a/drivers/net/igb/igb.h
+++ b/drivers/net/igb/igb.h
@@ -143,7 +143,7 @@ struct igb_buffer {
u16 next_to_watch;
unsigned int bytecount;
u16 gso_segs;
- union skb_shared_tx shtx;
+ u8 tx_flags;
u8 mapped_as_page;
};
/* RX */
@@ -159,6 +159,7 @@ struct igb_tx_queue_stats {
u64 packets;
u64 bytes;
u64 restart_queue;
+ u64 restart_queue2;
};
struct igb_rx_queue_stats {
@@ -210,11 +211,14 @@ struct igb_ring {
/* TX */
struct {
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;
};
};
@@ -288,6 +292,9 @@ struct igb_adapter {
struct timecompare compare;
struct hwtstamp_config hwtstamp_config;
+ spinlock_t stats64_lock;
+ struct rtnl_link_stats64 stats64;
+
/* structs defined in e1000_hw.h */
struct e1000_hw hw;
struct e1000_hw_stats stats;
@@ -357,7 +364,7 @@ extern netdev_tx_t igb_xmit_frame_ring_adv(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);
-extern void igb_update_stats(struct igb_adapter *);
+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 *);
extern void igb_power_up_link(struct igb_adapter *);
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index 26bf6a13d1c1..a70e16bcfa7e 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -90,8 +90,8 @@ static const struct igb_stats igb_gstrings_stats[] = {
#define IGB_NETDEV_STAT(_net_stat) { \
.stat_string = __stringify(_net_stat), \
- .sizeof_stat = FIELD_SIZEOF(struct net_device_stats, _net_stat), \
- .stat_offset = offsetof(struct net_device_stats, _net_stat) \
+ .sizeof_stat = FIELD_SIZEOF(struct rtnl_link_stats64, _net_stat), \
+ .stat_offset = offsetof(struct rtnl_link_stats64, _net_stat) \
}
static const struct igb_stats igb_gstrings_net_stats[] = {
IGB_NETDEV_STAT(rx_errors),
@@ -111,8 +111,9 @@ static const struct igb_stats igb_gstrings_net_stats[] = {
(sizeof(igb_gstrings_net_stats) / sizeof(struct igb_stats))
#define IGB_RX_QUEUE_STATS_LEN \
(sizeof(struct igb_rx_queue_stats) / sizeof(u64))
-#define IGB_TX_QUEUE_STATS_LEN \
- (sizeof(struct igb_tx_queue_stats) / sizeof(u64))
+
+#define IGB_TX_QUEUE_STATS_LEN 3 /* packets, bytes, restart_queue */
+
#define IGB_QUEUE_STATS_LEN \
((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues * \
IGB_RX_QUEUE_STATS_LEN) + \
@@ -2070,12 +2071,14 @@ static void igb_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, u64 *data)
{
struct igb_adapter *adapter = netdev_priv(netdev);
- struct net_device_stats *net_stats = &netdev->stats;
- u64 *queue_stat;
- int i, j, k;
+ struct rtnl_link_stats64 *net_stats = &adapter->stats64;
+ unsigned int start;
+ struct igb_ring *ring;
+ int i, j;
char *p;
- igb_update_stats(adapter);
+ spin_lock(&adapter->stats64_lock);
+ igb_update_stats(adapter, net_stats);
for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) {
p = (char *)adapter + igb_gstrings_stats[i].stat_offset;
@@ -2088,15 +2091,36 @@ static void igb_get_ethtool_stats(struct net_device *netdev,
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
for (j = 0; j < adapter->num_tx_queues; j++) {
- queue_stat = (u64 *)&adapter->tx_ring[j]->tx_stats;
- for (k = 0; k < IGB_TX_QUEUE_STATS_LEN; k++, i++)
- data[i] = queue_stat[k];
+ u64 restart2;
+
+ ring = adapter->tx_ring[j];
+ do {
+ start = u64_stats_fetch_begin_bh(&ring->tx_syncp);
+ data[i] = ring->tx_stats.packets;
+ data[i+1] = ring->tx_stats.bytes;
+ data[i+2] = ring->tx_stats.restart_queue;
+ } while (u64_stats_fetch_retry_bh(&ring->tx_syncp, start));
+ do {
+ start = u64_stats_fetch_begin_bh(&ring->tx_syncp2);
+ restart2 = ring->tx_stats.restart_queue2;
+ } while (u64_stats_fetch_retry_bh(&ring->tx_syncp2, start));
+ data[i+2] += restart2;
+
+ i += IGB_TX_QUEUE_STATS_LEN;
}
for (j = 0; j < adapter->num_rx_queues; j++) {
- queue_stat = (u64 *)&adapter->rx_ring[j]->rx_stats;
- for (k = 0; k < IGB_RX_QUEUE_STATS_LEN; k++, i++)
- data[i] = queue_stat[k];
+ ring = adapter->rx_ring[j];
+ do {
+ start = u64_stats_fetch_begin_bh(&ring->rx_syncp);
+ data[i] = ring->rx_stats.packets;
+ data[i+1] = ring->rx_stats.bytes;
+ data[i+2] = ring->rx_stats.drops;
+ data[i+3] = ring->rx_stats.csum_err;
+ data[i+4] = ring->rx_stats.alloc_failed;
+ } while (u64_stats_fetch_retry_bh(&ring->rx_syncp, start));
+ i += IGB_RX_QUEUE_STATS_LEN;
}
+ spin_unlock(&adapter->stats64_lock);
}
static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 9b4e5895f5f9..14db09e2fa8b 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -71,6 +71,8 @@ static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SERDES), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SGMII), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER_DUAL), board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SGMII), board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SERDES), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS_SERDES), board_82575 },
@@ -94,7 +96,6 @@ static int igb_setup_all_rx_resources(struct igb_adapter *);
static void igb_free_all_tx_resources(struct igb_adapter *);
static void igb_free_all_rx_resources(struct igb_adapter *);
static void igb_setup_mrqc(struct igb_adapter *);
-void igb_update_stats(struct igb_adapter *);
static int igb_probe(struct pci_dev *, const struct pci_device_id *);
static void __devexit igb_remove(struct pci_dev *pdev);
static int igb_sw_init(struct igb_adapter *);
@@ -111,7 +112,8 @@ 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 struct net_device_stats *igb_get_stats(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);
static int igb_set_mac(struct net_device *, void *);
static void igb_set_uta(struct igb_adapter *adapter);
@@ -986,7 +988,7 @@ static void igb_clear_interrupt_scheme(struct igb_adapter *adapter)
* Attempt to configure interrupts using the best available
* capabilities of the hardware and kernel.
**/
-static void igb_set_interrupt_capability(struct igb_adapter *adapter)
+static int igb_set_interrupt_capability(struct igb_adapter *adapter)
{
int err;
int numvecs, i;
@@ -1052,8 +1054,10 @@ msi_only:
if (!pci_enable_msi(adapter->pdev))
adapter->flags |= IGB_FLAG_HAS_MSI;
out:
- /* Notify the stack of the (possibly) reduced Tx Queue count. */
- adapter->netdev->real_num_tx_queues = adapter->num_tx_queues;
+ /* Notify the stack of the (possibly) reduced queue counts. */
+ netif_set_real_num_tx_queues(adapter->netdev, adapter->num_tx_queues);
+ return netif_set_real_num_rx_queues(adapter->netdev,
+ adapter->num_rx_queues);
}
/**
@@ -1152,7 +1156,9 @@ static int igb_init_interrupt_scheme(struct igb_adapter *adapter)
struct pci_dev *pdev = adapter->pdev;
int err;
- igb_set_interrupt_capability(adapter);
+ err = igb_set_interrupt_capability(adapter);
+ if (err)
+ return err;
err = igb_alloc_q_vectors(adapter);
if (err) {
@@ -1530,7 +1536,9 @@ void igb_down(struct igb_adapter *adapter)
netif_carrier_off(netdev);
/* record the stats before reset*/
- igb_update_stats(adapter);
+ spin_lock(&adapter->stats64_lock);
+ igb_update_stats(adapter, &adapter->stats64);
+ spin_unlock(&adapter->stats64_lock);
adapter->link_speed = 0;
adapter->link_duplex = 0;
@@ -1683,7 +1691,7 @@ 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_get_stats = igb_get_stats,
+ .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,
@@ -1856,8 +1864,10 @@ static int __devinit igb_probe(struct pci_dev *pdev,
netdev->vlan_features |= NETIF_F_IPV6_CSUM;
netdev->vlan_features |= NETIF_F_SG;
- if (pci_using_dac)
+ if (pci_using_dac) {
netdev->features |= NETIF_F_HIGHDMA;
+ netdev->vlan_features |= NETIF_F_HIGHDMA;
+ }
if (hw->mac.type >= e1000_82576)
netdev->features |= NETIF_F_SCTP_CSUM;
@@ -1888,9 +1898,9 @@ static int __devinit igb_probe(struct pci_dev *pdev,
goto err_eeprom;
}
- setup_timer(&adapter->watchdog_timer, &igb_watchdog,
+ setup_timer(&adapter->watchdog_timer, igb_watchdog,
(unsigned long) adapter);
- setup_timer(&adapter->phy_info_timer, &igb_update_phy_info,
+ setup_timer(&adapter->phy_info_timer, igb_update_phy_info,
(unsigned long) adapter);
INIT_WORK(&adapter->reset_task, igb_reset_task);
@@ -2268,6 +2278,7 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+ spin_lock_init(&adapter->stats64_lock);
#ifdef CONFIG_PCI_IOV
if (hw->mac.type == e1000_82576)
adapter->vfs_allocated_count = (max_vfs > 7) ? 7 : max_vfs;
@@ -3475,7 +3486,9 @@ static void igb_watchdog_task(struct work_struct *work)
}
}
- igb_update_stats(adapter);
+ spin_lock(&adapter->stats64_lock);
+ igb_update_stats(adapter, &adapter->stats64);
+ spin_unlock(&adapter->stats64_lock);
for (i = 0; i < adapter->num_tx_queues; i++) {
struct igb_ring *tx_ring = adapter->tx_ring[i];
@@ -3527,7 +3540,7 @@ enum latency_range {
* Stores a new ITR value based on strictly on packet size. This
* algorithm is less sophisticated than that used in igb_update_itr,
* due to the difficulty of synchronizing statistics across multiple
- * receive rings. The divisors and thresholds used by this fuction
+ * receive rings. The divisors and thresholds used by this function
* were determined based on theoretical maximum wire speed and testing
* data, in order to minimize response time while increasing bulk
* throughput.
@@ -3542,6 +3555,8 @@ 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.
@@ -3551,16 +3566,21 @@ static void igb_update_ring_itr(struct igb_q_vector *q_vector)
goto set_itr_val;
}
- if (q_vector->rx_ring && q_vector->rx_ring->total_packets) {
- struct igb_ring *ring = q_vector->rx_ring;
- avg_wire_size = ring->total_bytes / ring->total_packets;
+ ring = q_vector->rx_ring;
+ if (ring) {
+ packets = ACCESS_ONCE(ring->total_packets);
+
+ if (packets)
+ avg_wire_size = ring->total_bytes / packets;
}
- if (q_vector->tx_ring && q_vector->tx_ring->total_packets) {
- struct igb_ring *ring = q_vector->tx_ring;
- avg_wire_size = max_t(u32, avg_wire_size,
- (ring->total_bytes /
- ring->total_packets));
+ ring = q_vector->tx_ring;
+ if (ring) {
+ packets = ACCESS_ONCE(ring->total_packets);
+
+ if (packets)
+ avg_wire_size = max_t(u32, avg_wire_size,
+ ring->total_bytes / packets);
}
/* if avg_wire_size isn't set no work was done */
@@ -3954,7 +3974,7 @@ static inline int igb_tx_map_adv(struct igb_ring *tx_ring, struct sk_buff *skb,
}
tx_ring->buffer_info[i].skb = skb;
- tx_ring->buffer_info[i].shtx = skb_shinfo(skb)->tx_flags;
+ 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;
@@ -4069,7 +4089,11 @@ static int __igb_maybe_stop_tx(struct igb_ring *tx_ring, int size)
/* A reprieve! */
netif_wake_subqueue(netdev, tx_ring->queue_index);
- tx_ring->tx_stats.restart_queue++;
+
+ u64_stats_update_begin(&tx_ring->tx_syncp2);
+ tx_ring->tx_stats.restart_queue2++;
+ u64_stats_update_end(&tx_ring->tx_syncp2);
+
return 0;
}
@@ -4088,7 +4112,6 @@ netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb,
u32 tx_flags = 0;
u16 first;
u8 hdr_len = 0;
- union skb_shared_tx *shtx = skb_tx(skb);
/* need: 1 descriptor per page,
* + 2 desc gap to keep tail from touching head,
@@ -4100,12 +4123,12 @@ netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb,
return NETDEV_TX_BUSY;
}
- if (unlikely(shtx->hardware)) {
- shtx->in_progress = 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;
}
- if (vlan_tx_tag_present(skb) && adapter->vlgrp) {
+ if (vlan_tx_tag_present(skb)) {
tx_flags |= IGB_TX_FLAGS_VLAN;
tx_flags |= (vlan_tx_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT);
}
@@ -4207,16 +4230,22 @@ static void igb_reset_task(struct work_struct *work)
}
/**
- * igb_get_stats - Get System Network Statistics
+ * igb_get_stats64 - Get System Network Statistics
* @netdev: network interface device structure
+ * @stats: rtnl_link_stats64 pointer
*
- * Returns the address of the device statistics structure.
- * The statistics are actually updated from the timer callback.
**/
-static struct net_device_stats *igb_get_stats(struct net_device *netdev)
+static struct rtnl_link_stats64 *igb_get_stats64(struct net_device *netdev,
+ struct rtnl_link_stats64 *stats)
{
- /* only return the current stats */
- return &netdev->stats;
+ struct igb_adapter *adapter = netdev_priv(netdev);
+
+ spin_lock(&adapter->stats64_lock);
+ igb_update_stats(adapter, &adapter->stats64);
+ memcpy(stats, &adapter->stats64, sizeof(*stats));
+ spin_unlock(&adapter->stats64_lock);
+
+ return stats;
}
/**
@@ -4298,15 +4327,17 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu)
* @adapter: board private structure
**/
-void igb_update_stats(struct igb_adapter *adapter)
+void igb_update_stats(struct igb_adapter *adapter,
+ struct rtnl_link_stats64 *net_stats)
{
- struct net_device_stats *net_stats = igb_get_stats(adapter->netdev);
struct e1000_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
u32 reg, mpc;
u16 phy_tmp;
int i;
u64 bytes, packets;
+ unsigned int start;
+ u64 _bytes, _packets;
#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
@@ -4324,10 +4355,17 @@ void igb_update_stats(struct igb_adapter *adapter)
for (i = 0; i < adapter->num_rx_queues; i++) {
u32 rqdpc_tmp = rd32(E1000_RQDPC(i)) & 0x0FFF;
struct igb_ring *ring = adapter->rx_ring[i];
+
ring->rx_stats.drops += rqdpc_tmp;
net_stats->rx_fifo_errors += rqdpc_tmp;
- bytes += ring->rx_stats.bytes;
- packets += ring->rx_stats.packets;
+
+ do {
+ start = u64_stats_fetch_begin_bh(&ring->rx_syncp);
+ _bytes = ring->rx_stats.bytes;
+ _packets = ring->rx_stats.packets;
+ } while (u64_stats_fetch_retry_bh(&ring->rx_syncp, start));
+ bytes += _bytes;
+ packets += _packets;
}
net_stats->rx_bytes = bytes;
@@ -4337,8 +4375,13 @@ void igb_update_stats(struct igb_adapter *adapter)
packets = 0;
for (i = 0; i < adapter->num_tx_queues; i++) {
struct igb_ring *ring = adapter->tx_ring[i];
- bytes += ring->tx_stats.bytes;
- packets += ring->tx_stats.packets;
+ do {
+ start = u64_stats_fetch_begin_bh(&ring->tx_syncp);
+ _bytes = ring->tx_stats.bytes;
+ _packets = ring->tx_stats.packets;
+ } while (u64_stats_fetch_retry_bh(&ring->tx_syncp, start));
+ bytes += _bytes;
+ packets += _packets;
}
net_stats->tx_bytes = bytes;
net_stats->tx_packets = packets;
@@ -4660,12 +4703,13 @@ static int igb_set_vf_promisc(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
u32 vmolr = rd32(E1000_VMOLR(vf));
struct vf_data_storage *vf_data = &adapter->vf_data[vf];
- vf_data->flags |= ~(IGB_VF_FLAG_UNI_PROMISC |
+ vf_data->flags &= ~(IGB_VF_FLAG_UNI_PROMISC |
IGB_VF_FLAG_MULTI_PROMISC);
vmolr &= ~(E1000_VMOLR_ROPE | E1000_VMOLR_ROMPE | E1000_VMOLR_MPME);
if (*msgbuf & E1000_VF_SET_PROMISC_MULTICAST) {
vmolr |= E1000_VMOLR_MPME;
+ vf_data->flags |= IGB_VF_FLAG_MULTI_PROMISC;
*msgbuf &= ~E1000_VF_SET_PROMISC_MULTICAST;
} else {
/*
@@ -5319,7 +5363,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->shtx.hardware) ||
+ if (likely(!(buffer_info->tx_flags & SKBTX_HW_TSTAMP)) ||
!(rd32(E1000_TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID))
return;
@@ -5389,7 +5433,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
if (__netif_subqueue_stopped(netdev, tx_ring->queue_index) &&
!(test_bit(__IGB_DOWN, &adapter->state))) {
netif_wake_subqueue(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);
}
}
@@ -5429,9 +5476,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
}
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;
- return (count < tx_ring->count);
+ u64_stats_update_end(&tx_ring->tx_syncp);
+ return count < tx_ring->count;
}
/**
@@ -5456,7 +5505,7 @@ static void igb_receive_skb(struct igb_q_vector *q_vector,
static inline void igb_rx_checksum_adv(struct igb_ring *ring,
u32 status_err, struct sk_buff *skb)
{
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
/* Ignore Checksum bit is set or checksum is disabled through ethtool */
if (!(ring->flags & IGB_RING_FLAG_RX_CSUM) ||
@@ -5472,9 +5521,11 @@ static inline void igb_rx_checksum_adv(struct igb_ring *ring,
* packets, (aka let the stack check the crc32c)
*/
if ((skb->len == 60) &&
- (ring->flags & IGB_RING_FLAG_RX_SCTP_CSUM))
+ (ring->flags & IGB_RING_FLAG_RX_SCTP_CSUM)) {
+ u64_stats_update_begin(&ring->rx_syncp);
ring->rx_stats.csum_err++;
-
+ u64_stats_update_end(&ring->rx_syncp);
+ }
/* let the stack verify checksum errors */
return;
}
@@ -5500,7 +5551,7 @@ static void igb_rx_hwtstamp(struct igb_q_vector *q_vector, u32 staterr,
* values must belong to this one here and therefore we don't need to
* compare any of the additional attributes stored for it.
*
- * If nothing went wrong, then it should have a skb_shared_tx that we
+ * 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) {
@@ -5661,8 +5712,10 @@ next_desc:
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;
}
@@ -5690,8 +5743,10 @@ void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, int cleaned_count)
if ((bufsz < IGB_RXBUFFER_1024) && !buffer_info->page_dma) {
if (!buffer_info->page) {
buffer_info->page = netdev_alloc_page(netdev);
- if (!buffer_info->page) {
+ 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;
@@ -5706,7 +5761,9 @@ void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, int cleaned_count)
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;
}
}
@@ -5714,8 +5771,10 @@ void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, int cleaned_count)
skb = buffer_info->skb;
if (!skb) {
skb = netdev_alloc_skb_ip_align(netdev, bufsz);
- if (!skb) {
+ 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;
}
@@ -5729,7 +5788,9 @@ void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, int cleaned_count)
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;
}
}
@@ -6092,7 +6153,7 @@ static void igb_restore_vlan(struct igb_adapter *adapter)
if (adapter->vlgrp) {
u16 vid;
- for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ for (vid = 0; vid < VLAN_N_VID; vid++) {
if (!vlan_group_get_device(adapter->vlgrp, vid))
continue;
igb_vlan_rx_add_vid(adapter->netdev, vid);
@@ -6107,6 +6168,13 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx)
mac->autoneg = 0;
+ /* Fiber NIC's only allow 1000 Gbps Full duplex */
+ if ((adapter->hw.phy.media_type == e1000_media_type_internal_serdes) &&
+ spddplx != (SPEED_1000 + DUPLEX_FULL)) {
+ dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n");
+ return -EINVAL;
+ }
+
switch (spddplx) {
case SPEED_10 + DUPLEX_HALF:
mac->forced_speed_duplex = ADVERTISE_10_HALF;
diff --git a/drivers/net/igbvf/ethtool.c b/drivers/net/igbvf/ethtool.c
index 103b3aa1afc2..33add708bcbe 100644
--- a/drivers/net/igbvf/ethtool.c
+++ b/drivers/net/igbvf/ethtool.c
@@ -153,7 +153,7 @@ static int igbvf_set_rx_csum(struct net_device *netdev, u32 data)
static u32 igbvf_get_tx_csum(struct net_device *netdev)
{
- return ((netdev->features & NETIF_F_IP_CSUM) != 0);
+ return (netdev->features & NETIF_F_IP_CSUM) != 0;
}
static int igbvf_set_tx_csum(struct net_device *netdev, u32 data)
diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c
index c539f7c9c3e0..ebfaa68ee630 100644
--- a/drivers/net/igbvf/netdev.c
+++ b/drivers/net/igbvf/netdev.c
@@ -41,14 +41,12 @@
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
-#include <linux/pm_qos_params.h>
#include "igbvf.h"
#define DRV_VERSION "1.0.0-k0"
char igbvf_driver_name[] = "igbvf";
const char igbvf_driver_version[] = DRV_VERSION;
-static struct pm_qos_request_list igbvf_driver_pm_qos_req;
static const char igbvf_driver_string[] =
"Intel(R) Virtual Function Network Driver";
static const char igbvf_copyright[] = "Copyright (c) 2009 Intel Corporation.";
@@ -103,7 +101,7 @@ static void igbvf_receive_skb(struct igbvf_adapter *adapter,
static inline void igbvf_rx_checksum_adv(struct igbvf_adapter *adapter,
u32 status_err, struct sk_buff *skb)
{
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
/* Ignore Checksum bit is set or checksum is disabled through ethtool */
if ((status_err & E1000_RXD_STAT_IXSM) ||
@@ -845,7 +843,7 @@ static bool igbvf_clean_tx_irq(struct igbvf_ring *tx_ring)
}
adapter->net_stats.tx_bytes += total_bytes;
adapter->net_stats.tx_packets += total_packets;
- return (count < tx_ring->count);
+ return count < tx_ring->count;
}
static irqreturn_t igbvf_msix_other(int irq, void *data)
@@ -1256,7 +1254,7 @@ static void igbvf_restore_vlan(struct igbvf_adapter *adapter)
if (!adapter->vlgrp)
return;
- for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ for (vid = 0; vid < VLAN_N_VID; vid++) {
if (!vlan_group_get_device(adapter->vlgrp, vid))
continue;
igbvf_vlan_rx_add_vid(adapter->netdev, vid);
@@ -2904,8 +2902,6 @@ static int __init igbvf_init_module(void)
printk(KERN_INFO "%s\n", igbvf_copyright);
ret = pci_register_driver(&igbvf_driver);
- pm_qos_add_request(&igbvf_driver_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
return ret;
}
@@ -2920,7 +2916,6 @@ module_init(igbvf_init_module);
static void __exit igbvf_exit_module(void)
{
pci_unregister_driver(&igbvf_driver);
- pm_qos_remove_request(&igbvf_driver_pm_qos_req);
}
module_exit(igbvf_exit_module);
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index 0b3f6df5cff7..c8ee8d28767b 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -827,7 +827,7 @@ static void ioc3_mii_start(struct ioc3_private *ip)
{
ip->ioc3_timer.expires = jiffies + (12 * HZ)/10; /* 1.2 sec. */
ip->ioc3_timer.data = (unsigned long) ip;
- ip->ioc3_timer.function = &ioc3_timer;
+ ip->ioc3_timer.function = ioc3_timer;
add_timer(&ip->ioc3_timer);
}
diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c
index 72e3d2da9e9f..dc0198092343 100644
--- a/drivers/net/ipg.c
+++ b/drivers/net/ipg.c
@@ -1213,7 +1213,7 @@ static void ipg_nic_rx_with_start_and_end(struct net_device *dev,
skb_put(skb, framelen);
skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
netif_rx(skb);
sp->rx_buff[entry] = NULL;
}
@@ -1278,7 +1278,7 @@ static void ipg_nic_rx_with_end(struct net_device *dev,
jumbo->skb->protocol =
eth_type_trans(jumbo->skb, dev);
- jumbo->skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(jumbo->skb);
netif_rx(jumbo->skb);
}
}
@@ -1476,7 +1476,7 @@ static int ipg_nic_rx(struct net_device *dev)
* IP/TCP/UDP frame was received. Let the
* upper layer decide.
*/
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
/* Hand off frame for higher layer processing.
* The function netif_rx() releases the sk_buff
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index a3cb109006a5..92631eb6f6a3 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -142,7 +142,7 @@ static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable);
* Function ali_ircc_init ()
*
* Initialize chip. Find out whay kinds of chips we are dealing with
- * and their configuation registers address
+ * and their configuration registers address
*/
static int __init ali_ircc_init(void)
{
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 48bd5ec9f29b..b626cccbccd1 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -217,7 +217,7 @@ toshoboe_checkfcs (unsigned char *buf, int len)
for (i = 0; i < len; ++i)
fcs.value = irda_fcs (fcs.value, *(buf++));
- return (fcs.value == GOOD_FCS);
+ return fcs.value == GOOD_FCS;
}
/***********************************************************************/
@@ -759,7 +759,7 @@ toshoboe_maketestpacket (unsigned char *buf, int badcrc, int fir)
if (fir)
{
memset (buf, 0, TT_LEN);
- return (TT_LEN);
+ return TT_LEN;
}
fcs.value = INIT_FCS;
diff --git a/drivers/net/irda/donauboe.h b/drivers/net/irda/donauboe.h
index 36c3060411d2..4dc39e5f0156 100644
--- a/drivers/net/irda/donauboe.h
+++ b/drivers/net/irda/donauboe.h
@@ -54,7 +54,7 @@
/* anyone who has. HOWEVER the chip bears a striking resemblence */
/* to the IrDA controller in the Toshiba RISC TMPR3922 chip */
/* the documentation for this is freely available at */
-/* http://www.toshiba.com/taec/components/Generic/TMPR3922.shtml */
+/* http://www.madingley.org/james/resources/toshoboe/TMPR3922.pdf */
/* The mapping between the registers in that document and the */
/* Registers in the 701 oboe chip are as follows */
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 4441fa3389c2..e4ea61944c22 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1124,11 +1124,11 @@ static int stir421x_patch_device(struct irda_usb_cb *self)
* The actual image starts after the "STMP" keyword
* so forward to the firmware header tag
*/
- for (i = 0; (fw->data[i] != STIR421X_PATCH_END_OF_HDR_TAG) &&
- (i < fw->size); i++) ;
+ for (i = 0; i < fw->size && fw->data[i] !=
+ STIR421X_PATCH_END_OF_HDR_TAG; i++) ;
/* here we check for the out of buffer case */
- if ((STIR421X_PATCH_END_OF_HDR_TAG == fw->data[i]) &&
- (i < STIR421X_PATCH_CODE_OFFSET)) {
+ if (i < STIR421X_PATCH_CODE_OFFSET && i < fw->size &&
+ STIR421X_PATCH_END_OF_HDR_TAG == fw->data[i]) {
if (!memcmp(fw->data + i + 1, STIR421X_PATCH_STMP_TAG,
sizeof(STIR421X_PATCH_STMP_TAG) - 1)) {
@@ -1514,7 +1514,7 @@ static inline int irda_usb_parse_endpoints(struct irda_usb_cb *self, struct usb_
IRDA_DEBUG(0, "%s(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n",
__func__, self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep);
- return((self->bulk_in_ep != 0) && (self->bulk_out_ep != 0));
+ return (self->bulk_in_ep != 0) && (self->bulk_out_ep != 0);
}
#ifdef IU_DUMP_CLASS_DESC
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index 5b1036ac38d7..74b20f179cea 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -734,7 +734,7 @@ static int mcs_net_open(struct net_device *netdev)
}
if (!mcs_setup_urbs(mcs))
- goto error3;
+ goto error3;
ret = mcs_receive_start(mcs);
if (ret)
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index e30cdbb14745..559fe854d76d 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -1348,7 +1348,7 @@ static __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed)
outb(bank, iobase+BSR);
/* Make sure interrupt handlers keep the proper interrupt mask */
- return(ier);
+ return ier;
}
/*
diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c
index 51d74447f8f8..efe05bb34dd8 100644
--- a/drivers/net/irda/sir_dev.c
+++ b/drivers/net/irda/sir_dev.c
@@ -336,7 +336,7 @@ static int sirdev_is_receiving(struct sir_dev *dev)
if (!atomic_read(&dev->enable_rx))
return 0;
- return (dev->rx_buff.state != OUTSIDE_FRAME);
+ return dev->rx_buff.state != OUTSIDE_FRAME;
}
int sirdev_set_dongle(struct sir_dev *dev, IRDA_DONGLE type)
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 850ca1c5ee19..8c57bfb5f098 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -2051,7 +2051,7 @@ static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len)
*/
static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self)
{
- return (self->rx_buff.state != OUTSIDE_FRAME);
+ return self->rx_buff.state != OUTSIDE_FRAME;
}
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index e5698fa30a4f..41c96b3d8152 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -219,7 +219,7 @@ static inline int read_reg(struct stir_cb *stir, __u16 reg,
static inline int isfir(u32 speed)
{
- return (speed == 4000000);
+ return speed == 4000000;
}
/*
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index b0a6cd815be1..67c0ad42d818 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -1182,12 +1182,13 @@ F01_E */
skb = dev_alloc_skb(len + 1 - 4);
/*
- * if frame size,data ptr,or skb ptr are wrong ,the get next
+ * if frame size, data ptr, or skb ptr are wrong, then get next
* entry.
*/
if ((skb == NULL) || (skb->data == NULL) ||
(self->rx_buff.data == NULL) || (len < 6)) {
self->netdev->stats.rx_dropped++;
+ kfree_skb(skb);
return TRUE;
}
skb_reserve(skb, 1);
diff --git a/drivers/net/irda/via-ircc.h b/drivers/net/irda/via-ircc.h
index 5a84822b5a43..c6f58482b769 100644
--- a/drivers/net/irda/via-ircc.h
+++ b/drivers/net/irda/via-ircc.h
@@ -238,7 +238,7 @@ static void WriteLPCReg(int iRegNum, unsigned char iVal)
static __u8 ReadReg(unsigned int BaseAddr, int iRegNum)
{
- return ((__u8) inb(BaseAddr + iRegNum));
+ return (__u8) inb(BaseAddr + iRegNum);
}
static void WriteReg(unsigned int BaseAddr, int iRegNum, unsigned char iVal)
diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h
index 3f24a1f33022..d66fab854bf1 100644
--- a/drivers/net/irda/vlsi_ir.h
+++ b/drivers/net/irda/vlsi_ir.h
@@ -595,7 +595,7 @@ struct ring_descr {
static inline int rd_is_active(struct ring_descr *rd)
{
- return ((rd->hw->rd_status & RD_ACTIVE) != 0);
+ return (rd->hw->rd_status & RD_ACTIVE) != 0;
}
static inline void rd_activate(struct ring_descr *rd)
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index ba1de5973fb2..8df645e78f2e 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -1524,7 +1524,7 @@ static void veth_receive(struct veth_lpar_connection *cnx,
skb_put(skb, length);
skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
netif_rx(skb); /* send it up */
dev->stats.rx_packets++;
dev->stats.rx_bytes += length;
diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c
index 813993f9c65c..c982ab9f9005 100644
--- a/drivers/net/ixgb/ixgb_ee.c
+++ b/drivers/net/ixgb/ixgb_ee.c
@@ -296,12 +296,12 @@ ixgb_wait_eeprom_command(struct ixgb_hw *hw)
eecd_reg = IXGB_READ_REG(hw, EECD);
if (eecd_reg & IXGB_EECD_DO)
- return (true);
+ return true;
udelay(50);
}
ASSERT(0);
- return (false);
+ return false;
}
/******************************************************************************
@@ -327,9 +327,9 @@ ixgb_validate_eeprom_checksum(struct ixgb_hw *hw)
checksum += ixgb_read_eeprom(hw, i);
if (checksum == (u16) EEPROM_SUM)
- return (true);
+ return true;
else
- return (false);
+ return false;
}
/******************************************************************************
@@ -439,7 +439,7 @@ ixgb_read_eeprom(struct ixgb_hw *hw,
/* End this read operation */
ixgb_standby_eeprom(hw);
- return (data);
+ return data;
}
/******************************************************************************
@@ -476,16 +476,16 @@ ixgb_get_eeprom_data(struct ixgb_hw *hw)
/* clear the init_ctrl_reg_1 to signify that the cache is
* invalidated */
ee_map->init_ctrl_reg_1 = cpu_to_le16(EEPROM_ICW1_SIGNATURE_CLEAR);
- return (false);
+ return false;
}
if ((ee_map->init_ctrl_reg_1 & cpu_to_le16(EEPROM_ICW1_SIGNATURE_MASK))
!= cpu_to_le16(EEPROM_ICW1_SIGNATURE_VALID)) {
pr_debug("Signature invalid\n");
- return(false);
+ return false;
}
- return(true);
+ return true;
}
/******************************************************************************
@@ -505,7 +505,7 @@ ixgb_check_and_get_eeprom_data (struct ixgb_hw* hw)
if ((ee_map->init_ctrl_reg_1 & cpu_to_le16(EEPROM_ICW1_SIGNATURE_MASK))
== cpu_to_le16(EEPROM_ICW1_SIGNATURE_VALID)) {
- return (true);
+ return true;
} else {
return ixgb_get_eeprom_data(hw);
}
@@ -526,10 +526,10 @@ ixgb_get_eeprom_word(struct ixgb_hw *hw, u16 index)
if ((index < IXGB_EEPROM_SIZE) &&
(ixgb_check_and_get_eeprom_data(hw) == true)) {
- return(hw->eeprom[index]);
+ return hw->eeprom[index];
}
- return(0);
+ return 0;
}
/******************************************************************************
@@ -570,10 +570,10 @@ u32
ixgb_get_ee_pba_number(struct ixgb_hw *hw)
{
if (ixgb_check_and_get_eeprom_data(hw) == true)
- return (le16_to_cpu(hw->eeprom[EEPROM_PBA_1_2_REG])
- | (le16_to_cpu(hw->eeprom[EEPROM_PBA_3_4_REG])<<16));
+ return le16_to_cpu(hw->eeprom[EEPROM_PBA_1_2_REG])
+ | (le16_to_cpu(hw->eeprom[EEPROM_PBA_3_4_REG])<<16);
- return(0);
+ return 0;
}
@@ -591,8 +591,8 @@ ixgb_get_ee_device_id(struct ixgb_hw *hw)
struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
if (ixgb_check_and_get_eeprom_data(hw) == true)
- return (le16_to_cpu(ee_map->device_id));
+ return le16_to_cpu(ee_map->device_id);
- return (0);
+ return 0;
}
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index a4ed96caae69..43994c199991 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -410,7 +410,7 @@ static int
ixgb_get_eeprom_len(struct net_device *netdev)
{
/* return size in bytes */
- return (IXGB_EEPROM_SIZE << 1);
+ return IXGB_EEPROM_SIZE << 1;
}
static int
diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c
index 397acabccab6..6cb2e42ff4c1 100644
--- a/drivers/net/ixgb/ixgb_hw.c
+++ b/drivers/net/ixgb/ixgb_hw.c
@@ -167,7 +167,7 @@ ixgb_adapter_stop(struct ixgb_hw *hw)
/* Clear any pending interrupt events. */
icr_reg = IXGB_READ_REG(hw, ICR);
- return (ctrl_reg & IXGB_CTRL0_RST);
+ return ctrl_reg & IXGB_CTRL0_RST;
}
@@ -209,7 +209,7 @@ ixgb_identify_xpak_vendor(struct ixgb_hw *hw)
xpak_vendor = ixgb_xpak_vendor_infineon;
}
- return (xpak_vendor);
+ return xpak_vendor;
}
/******************************************************************************
@@ -273,7 +273,7 @@ ixgb_identify_phy(struct ixgb_hw *hw)
if (hw->subsystem_vendor_id == SUN_SUBVENDOR_ID)
phy_type = ixgb_phy_type_bcm;
- return (phy_type);
+ return phy_type;
}
/******************************************************************************
@@ -366,7 +366,7 @@ ixgb_init_hw(struct ixgb_hw *hw)
/* 82597EX errata: Call check-for-link in case lane deskew is locked */
ixgb_check_for_link(hw);
- return (status);
+ return status;
}
/******************************************************************************
@@ -531,7 +531,7 @@ ixgb_hash_mc_addr(struct ixgb_hw *hw,
}
hash_value &= 0xFFF;
- return (hash_value);
+ return hash_value;
}
/******************************************************************************
@@ -715,7 +715,7 @@ ixgb_setup_fc(struct ixgb_hw *hw)
}
IXGB_WRITE_REG(hw, FCRTH, hw->fc.high_water);
}
- return (status);
+ return status;
}
/******************************************************************************
@@ -1140,7 +1140,7 @@ mac_addr_valid(u8 *mac_addr)
pr_debug("MAC address is all zeros\n");
is_valid = false;
}
- return (is_valid);
+ return is_valid;
}
/******************************************************************************
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 45fc89b9ba64..666207a9c039 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -446,8 +446,10 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
NETIF_F_HW_VLAN_FILTER;
netdev->features |= NETIF_F_TSO;
- if (pci_using_dac)
+ if (pci_using_dac) {
netdev->features |= NETIF_F_HIGHDMA;
+ netdev->vlan_features |= NETIF_F_HIGHDMA;
+ }
/* make sure the EEPROM is good */
@@ -470,7 +472,7 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->part_num = ixgb_get_ee_pba_number(&adapter->hw);
init_timer(&adapter->watchdog_timer);
- adapter->watchdog_timer.function = &ixgb_watchdog;
+ adapter->watchdog_timer.function = ixgb_watchdog;
adapter->watchdog_timer.data = (unsigned long)adapter;
INIT_WORK(&adapter->tx_timeout_task, ixgb_tx_timeout_task);
@@ -1905,7 +1907,7 @@ ixgb_rx_checksum(struct ixgb_adapter *adapter,
*/
if ((rx_desc->status & IXGB_RX_DESC_STATUS_IXSM) ||
(!(rx_desc->status & IXGB_RX_DESC_STATUS_TCPCS))) {
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
return;
}
@@ -1913,7 +1915,7 @@ ixgb_rx_checksum(struct ixgb_adapter *adapter,
/* now look at the TCP checksum error bit */
if (rx_desc->errors & IXGB_RX_DESC_ERRORS_TCPE) {
/* let the stack verify checksum errors */
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
adapter->hw_csum_rx_error++;
} else {
/* TCP checksum is good */
@@ -2221,7 +2223,7 @@ ixgb_restore_vlan(struct ixgb_adapter *adapter)
if (adapter->vlgrp) {
u16 vid;
- for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ for (vid = 0; vid < VLAN_N_VID; vid++) {
if (!vlan_group_get_device(adapter->vlgrp, vid))
continue;
ixgb_vlan_rx_add_vid(adapter->netdev, vid);
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index 9e15eb93860e..ed8703cfffb7 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -28,10 +28,13 @@
#ifndef _IXGBE_H_
#define _IXGBE_H_
+#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
+#include <linux/cpumask.h>
#include <linux/aer.h>
+#include <linux/if_vlan.h>
#include "ixgbe_type.h"
#include "ixgbe_common.h"
@@ -69,15 +72,20 @@
#define IXGBE_MAX_FCPAUSE 0xFFFF
/* Supported Rx Buffer Sizes */
-#define IXGBE_RXBUFFER_64 64 /* Used for packet split */
-#define IXGBE_RXBUFFER_128 128 /* Used for packet split */
-#define IXGBE_RXBUFFER_256 256 /* Used for packet split */
+#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_RX_HDR_SIZE IXGBE_RXBUFFER_256
+/*
+ * NOTE: netdev_alloc_skb reserves up to 64 bytes, NET_IP_ALIGN mans we
+ * reserve 2 more, and skb_shared_info adds an additional 384 bytes more,
+ * this adds up to 512 bytes of extra data meaning the smallest allocation
+ * we could have is 1K.
+ * i.e. RXBUFFER_512 --> size-1024 slab
+ */
+#define IXGBE_RX_HDR_SIZE IXGBE_RXBUFFER_512
#define MAXIMUM_ETHERNET_VLAN_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN)
@@ -174,8 +182,9 @@ struct ixgbe_ring {
*/
struct ixgbe_queue_stats stats;
- unsigned long reinit_state;
+ struct u64_stats_sync syncp;
int numa_node;
+ unsigned long reinit_state;
u64 rsc_count; /* stat for coalesced packets */
u64 rsc_flush; /* stats for flushed packets */
u32 restart_queue; /* track tx queue restarts */
@@ -236,6 +245,7 @@ struct ixgbe_q_vector {
u8 tx_itr;
u8 rx_itr;
u32 eitr;
+ cpumask_var_t affinity_mask;
};
/* Helper macros to switch between ints/sec and what the register uses.
@@ -251,11 +261,11 @@ struct ixgbe_q_vector {
(R)->next_to_clean - (R)->next_to_use - 1)
#define IXGBE_RX_DESC_ADV(R, i) \
- (&(((union ixgbe_adv_rx_desc *)((R).desc))[i]))
+ (&(((union ixgbe_adv_rx_desc *)((R)->desc))[i]))
#define IXGBE_TX_DESC_ADV(R, i) \
- (&(((union ixgbe_adv_tx_desc *)((R).desc))[i]))
+ (&(((union ixgbe_adv_tx_desc *)((R)->desc))[i]))
#define IXGBE_TX_CTXTDESC_ADV(R, i) \
- (&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i]))
+ (&(((struct ixgbe_adv_tx_context_desc *)((R)->desc))[i]))
#define IXGBE_MAX_JUMBO_FRAME_SIZE 16128
#ifdef IXGBE_FCOE
@@ -280,7 +290,7 @@ struct ixgbe_q_vector {
/* board specific private data structure */
struct ixgbe_adapter {
struct timer_list watchdog_timer;
- struct vlan_group *vlgrp;
+ unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
u16 bd_number;
struct work_struct reset_task;
struct ixgbe_q_vector *q_vector[MAX_MSIX_Q_VECTORS];
@@ -448,9 +458,20 @@ extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *)
extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
extern void ixgbe_free_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
extern void ixgbe_free_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
+extern void ixgbe_configure_rx_ring(struct ixgbe_adapter *,struct ixgbe_ring *);
+extern void ixgbe_configure_tx_ring(struct ixgbe_adapter *,struct ixgbe_ring *);
extern void ixgbe_update_stats(struct ixgbe_adapter *adapter);
extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter);
extern void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter);
+extern netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *,
+ struct net_device *,
+ struct ixgbe_adapter *,
+ struct ixgbe_ring *);
+extern void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *,
+ struct ixgbe_tx_buffer *);
+extern void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rx_ring,
+ int cleaned_count);
extern void ixgbe_write_eitr(struct ixgbe_q_vector *);
extern int ethtool_ioctl(struct ifreq *ifr);
extern s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw);
diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c
index 3e06a61da921..0bd8fbb5bfd0 100644
--- a/drivers/net/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ixgbe/ixgbe_82599.c
@@ -39,20 +39,20 @@
#define IXGBE_82599_MC_TBL_SIZE 128
#define IXGBE_82599_VFT_TBL_SIZE 128
-void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
-void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
-void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
-s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
- ixgbe_link_speed speed,
- bool autoneg,
- bool autoneg_wait_to_complete);
+static void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
+static void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
+static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
+static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
+ ixgbe_link_speed speed,
+ bool autoneg,
+ bool autoneg_wait_to_complete);
static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
bool autoneg,
bool autoneg_wait_to_complete);
-s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw,
- bool autoneg_wait_to_complete);
-s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
+static s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw,
+ bool autoneg_wait_to_complete);
+static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
bool autoneg,
bool autoneg_wait_to_complete);
@@ -369,7 +369,7 @@ out:
* Configures link settings based on values in the ixgbe_hw struct.
* Restarts the link. Performs autonegotiation if needed.
**/
-s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw,
+static s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw,
bool autoneg_wait_to_complete)
{
u32 autoc_reg;
@@ -418,7 +418,7 @@ s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw,
* PHY states. This includes selectively shutting down the Tx
* laser on the PHY, effectively halting physical link.
**/
-void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
+static void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
{
u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
@@ -437,7 +437,7 @@ void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
* PHY states. This includes selectively turning on the Tx
* laser on the PHY, effectively starting physical link.
**/
-void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
+static void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
{
u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
@@ -460,7 +460,7 @@ void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
* end. This is consistent with true clause 37 autoneg, which also
* involves a loss of signal.
**/
-void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
+static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
{
hw_dbg(hw, "ixgbe_flap_tx_laser_multispeed_fiber\n");
@@ -729,7 +729,7 @@ out:
*
* Set the link speed in the AUTOC register and restarts link.
**/
-s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
+static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
ixgbe_link_speed speed, bool autoneg,
bool autoneg_wait_to_complete)
{
@@ -1415,92 +1415,6 @@ s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 dst_addr)
}
/**
- * ixgbe_atr_set_src_ipv6_82599 - Sets the source IPv6 address
- * @input: input stream to modify
- * @src_addr_1: the first 4 bytes of the IP address to load
- * @src_addr_2: the second 4 bytes of the IP address to load
- * @src_addr_3: the third 4 bytes of the IP address to load
- * @src_addr_4: the fourth 4 bytes of the IP address to load
- **/
-s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input,
- u32 src_addr_1, u32 src_addr_2,
- u32 src_addr_3, u32 src_addr_4)
-{
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET] = src_addr_4 & 0xff;
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 1] =
- (src_addr_4 >> 8) & 0xff;
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 2] =
- (src_addr_4 >> 16) & 0xff;
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 3] = src_addr_4 >> 24;
-
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 4] = src_addr_3 & 0xff;
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 5] =
- (src_addr_3 >> 8) & 0xff;
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 6] =
- (src_addr_3 >> 16) & 0xff;
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 7] = src_addr_3 >> 24;
-
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 8] = src_addr_2 & 0xff;
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 9] =
- (src_addr_2 >> 8) & 0xff;
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 10] =
- (src_addr_2 >> 16) & 0xff;
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 11] = src_addr_2 >> 24;
-
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 12] = src_addr_1 & 0xff;
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 13] =
- (src_addr_1 >> 8) & 0xff;
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 14] =
- (src_addr_1 >> 16) & 0xff;
- input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 15] = src_addr_1 >> 24;
-
- return 0;
-}
-
-/**
- * ixgbe_atr_set_dst_ipv6_82599 - Sets the destination IPv6 address
- * @input: input stream to modify
- * @dst_addr_1: the first 4 bytes of the IP address to load
- * @dst_addr_2: the second 4 bytes of the IP address to load
- * @dst_addr_3: the third 4 bytes of the IP address to load
- * @dst_addr_4: the fourth 4 bytes of the IP address to load
- **/
-s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input,
- u32 dst_addr_1, u32 dst_addr_2,
- u32 dst_addr_3, u32 dst_addr_4)
-{
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET] = dst_addr_4 & 0xff;
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 1] =
- (dst_addr_4 >> 8) & 0xff;
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 2] =
- (dst_addr_4 >> 16) & 0xff;
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 3] = dst_addr_4 >> 24;
-
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 4] = dst_addr_3 & 0xff;
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 5] =
- (dst_addr_3 >> 8) & 0xff;
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 6] =
- (dst_addr_3 >> 16) & 0xff;
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 7] = dst_addr_3 >> 24;
-
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 8] = dst_addr_2 & 0xff;
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 9] =
- (dst_addr_2 >> 8) & 0xff;
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 10] =
- (dst_addr_2 >> 16) & 0xff;
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 11] = dst_addr_2 >> 24;
-
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 12] = dst_addr_1 & 0xff;
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 13] =
- (dst_addr_1 >> 8) & 0xff;
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 14] =
- (dst_addr_1 >> 16) & 0xff;
- input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 15] = dst_addr_1 >> 24;
-
- return 0;
-}
-
-/**
* ixgbe_atr_set_src_port_82599 - Sets the source port
* @input: input stream to modify
* @src_port: the source port to load
@@ -1540,19 +1454,6 @@ s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, u16 flex_byte)
}
/**
- * ixgbe_atr_set_vm_pool_82599 - Sets the Virtual Machine pool
- * @input: input stream to modify
- * @vm_pool: the Virtual Machine pool to load
- **/
-s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input,
- u8 vm_pool)
-{
- input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET] = vm_pool;
-
- return 0;
-}
-
-/**
* ixgbe_atr_set_l4type_82599 - Sets the layer 4 packet type
* @input: input stream to modify
* @l4type: the layer 4 type value to load
@@ -1645,41 +1546,6 @@ static s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input,
}
/**
- * ixgbe_atr_get_dst_ipv6_82599 - Gets the destination IPv6 address
- * @input: input stream to search
- * @dst_addr_1: the first 4 bytes of the IP address to load
- * @dst_addr_2: the second 4 bytes of the IP address to load
- * @dst_addr_3: the third 4 bytes of the IP address to load
- * @dst_addr_4: the fourth 4 bytes of the IP address to load
- **/
-s32 ixgbe_atr_get_dst_ipv6_82599(struct ixgbe_atr_input *input,
- u32 *dst_addr_1, u32 *dst_addr_2,
- u32 *dst_addr_3, u32 *dst_addr_4)
-{
- *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 12];
- *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 13] << 8;
- *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 14] << 16;
- *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 15] << 24;
-
- *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 8];
- *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 9] << 8;
- *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 10] << 16;
- *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 11] << 24;
-
- *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 4];
- *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 5] << 8;
- *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 6] << 16;
- *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 7] << 24;
-
- *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET];
- *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 1] << 8;
- *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 2] << 16;
- *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 3] << 24;
-
- return 0;
-}
-
-/**
* ixgbe_atr_get_src_port_82599 - Gets the source port
* @input: input stream to modify
* @src_port: the source port to load
@@ -1732,19 +1598,6 @@ static s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input,
}
/**
- * ixgbe_atr_get_vm_pool_82599 - Gets the Virtual Machine pool
- * @input: input stream to modify
- * @vm_pool: the Virtual Machine pool to load
- **/
-s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input,
- u8 *vm_pool)
-{
- *vm_pool = input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET];
-
- return 0;
-}
-
-/**
* ixgbe_atr_get_l4type_82599 - Gets the layer 4 packet type
* @input: input stream to modify
* @l4type: the layer 4 type value to load
@@ -1910,56 +1763,27 @@ s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
(dst_port << IXGBE_FDIRPORT_DESTINATION_SHIFT)));
/*
- * Program the relevant mask registers. If src/dst_port or src/dst_addr
- * are zero, then assume a full mask for that field. Also assume that
- * a VLAN of 0 is unspecified, so mask that out as well. L4type
- * cannot be masked out in this implementation.
+ * Program the relevant mask registers. L4type cannot be
+ * masked out in this implementation.
*
* This also assumes IPv4 only. IPv6 masking isn't supported at this
* point in time.
*/
- if (src_ipv4 == 0)
- IXGBE_WRITE_REG(hw, IXGBE_FDIRSIP4M, 0xffffffff);
- else
- IXGBE_WRITE_REG(hw, IXGBE_FDIRSIP4M, input_masks->src_ip_mask);
-
- if (dst_ipv4 == 0)
- IXGBE_WRITE_REG(hw, IXGBE_FDIRDIP4M, 0xffffffff);
- else
- IXGBE_WRITE_REG(hw, IXGBE_FDIRDIP4M, input_masks->dst_ip_mask);
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRSIP4M, input_masks->src_ip_mask);
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRDIP4M, input_masks->dst_ip_mask);
switch (l4type & IXGBE_ATR_L4TYPE_MASK) {
case IXGBE_ATR_L4TYPE_TCP:
- if (src_port == 0)
- IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, 0xffff);
- else
- IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM,
- input_masks->src_port_mask);
-
- if (dst_port == 0)
- IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM,
- (IXGBE_READ_REG(hw, IXGBE_FDIRTCPM) |
- (0xffff << 16)));
- else
- IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM,
- (IXGBE_READ_REG(hw, IXGBE_FDIRTCPM) |
- (input_masks->dst_port_mask << 16)));
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, input_masks->src_port_mask);
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM,
+ (IXGBE_READ_REG(hw, IXGBE_FDIRTCPM) |
+ (input_masks->dst_port_mask << 16)));
break;
case IXGBE_ATR_L4TYPE_UDP:
- if (src_port == 0)
- IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, 0xffff);
- else
- IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM,
- input_masks->src_port_mask);
-
- if (dst_port == 0)
- IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM,
- (IXGBE_READ_REG(hw, IXGBE_FDIRUDPM) |
- (0xffff << 16)));
- else
- IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM,
- (IXGBE_READ_REG(hw, IXGBE_FDIRUDPM) |
- (input_masks->src_port_mask << 16)));
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, input_masks->src_port_mask);
+ IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM,
+ (IXGBE_READ_REG(hw, IXGBE_FDIRUDPM) |
+ (input_masks->src_port_mask << 16)));
break;
default:
/* this already would have failed above */
@@ -1967,11 +1791,11 @@ s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
}
/* Program the last mask register, FDIRM */
- if (input_masks->vlan_id_mask || !vlan_id)
+ if (input_masks->vlan_id_mask)
/* Mask both VLAN and VLANP - bits 0 and 1 */
fdirm |= 0x3;
- if (input_masks->data_mask || !flex_bytes)
+ if (input_masks->data_mask)
/* Flex bytes need masking, so mask the whole thing - bit 4 */
fdirm |= 0x10;
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c
index 9595b1bfb8dd..e3eca1316389 100644
--- a/drivers/net/ixgbe/ixgbe_common.c
+++ b/drivers/net/ixgbe/ixgbe_common.c
@@ -52,6 +52,7 @@ static void ixgbe_disable_rar(struct ixgbe_hw *hw, u32 index);
static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr);
static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq);
static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num);
+static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg);
/**
* ixgbe_start_hw_generic - Prepare hardware for Tx/Rx
@@ -637,7 +638,7 @@ out:
* Polls the status bit (bit 1) of the EERD or EEWR to determine when the
* read or write is done respectively.
**/
-s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg)
+static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg)
{
u32 i;
u32 reg;
@@ -2449,7 +2450,7 @@ s32 ixgbe_init_uta_tables_generic(struct ixgbe_hw *hw)
* return the VLVF index where this VLAN id should be placed
*
**/
-s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan)
+static s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan)
{
u32 bits = 0;
u32 first_empty_slot = 0;
@@ -2704,48 +2705,3 @@ s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
return 0;
}
-
-/**
- * ixgbe_get_wwn_prefix_generic - Get alternative WWNN/WWPN prefix from
- * the EEPROM
- * @hw: pointer to hardware structure
- * @wwnn_prefix: the alternative WWNN prefix
- * @wwpn_prefix: the alternative WWPN prefix
- *
- * This function will read the EEPROM from the alternative SAN MAC address
- * block to check the support for the alternative WWNN/WWPN prefix support.
- **/
-s32 ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix,
- u16 *wwpn_prefix)
-{
- u16 offset, caps;
- u16 alt_san_mac_blk_offset;
-
- /* clear output first */
- *wwnn_prefix = 0xFFFF;
- *wwpn_prefix = 0xFFFF;
-
- /* check if alternative SAN MAC is supported */
- hw->eeprom.ops.read(hw, IXGBE_ALT_SAN_MAC_ADDR_BLK_PTR,
- &alt_san_mac_blk_offset);
-
- if ((alt_san_mac_blk_offset == 0) ||
- (alt_san_mac_blk_offset == 0xFFFF))
- goto wwn_prefix_out;
-
- /* check capability in alternative san mac address block */
- offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_CAPS_OFFSET;
- hw->eeprom.ops.read(hw, offset, &caps);
- if (!(caps & IXGBE_ALT_SAN_MAC_ADDR_CAPS_ALTWWN))
- goto wwn_prefix_out;
-
- /* get the corresponding prefix for WWNN/WWPN */
- offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_WWNN_OFFSET;
- hw->eeprom.ops.read(hw, offset, wwnn_prefix);
-
- offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_WWPN_OFFSET;
- hw->eeprom.ops.read(hw, offset, wwpn_prefix);
-
-wwn_prefix_out:
- return 0;
-}
diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h
index 5cf15aa11cac..424c223437dc 100644
--- a/drivers/net/ixgbe/ixgbe_common.h
+++ b/drivers/net/ixgbe/ixgbe_common.h
@@ -52,7 +52,6 @@ s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw,
u16 *checksum_val);
s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw);
-s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg);
s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq,
u32 enable_addr);
diff --git a/drivers/net/ixgbe/ixgbe_dcb.c b/drivers/net/ixgbe/ixgbe_dcb.c
index 9aea4f04bbd2..8bb9ddb6dffe 100644
--- a/drivers/net/ixgbe/ixgbe_dcb.c
+++ b/drivers/net/ixgbe/ixgbe_dcb.c
@@ -34,98 +34,6 @@
#include "ixgbe_dcb_82599.h"
/**
- * ixgbe_dcb_config - Struct containing DCB settings.
- * @dcb_config: Pointer to DCB config structure
- *
- * This function checks DCB rules for DCB settings.
- * The following rules are checked:
- * 1. The sum of bandwidth percentages of all Bandwidth Groups must total 100%.
- * 2. The sum of bandwidth percentages of all Traffic Classes within a Bandwidth
- * Group must total 100.
- * 3. A Traffic Class should not be set to both Link Strict Priority
- * and Group Strict Priority.
- * 4. Link strict Bandwidth Groups can only have link strict traffic classes
- * with zero bandwidth.
- */
-s32 ixgbe_dcb_check_config(struct ixgbe_dcb_config *dcb_config)
-{
- struct tc_bw_alloc *p;
- s32 ret_val = 0;
- u8 i, j, bw = 0, bw_id;
- u8 bw_sum[2][MAX_BW_GROUP];
- bool link_strict[2][MAX_BW_GROUP];
-
- memset(bw_sum, 0, sizeof(bw_sum));
- memset(link_strict, 0, sizeof(link_strict));
-
- /* First Tx, then Rx */
- for (i = 0; i < 2; i++) {
- /* Check each traffic class for rule violation */
- for (j = 0; j < MAX_TRAFFIC_CLASS; j++) {
- p = &dcb_config->tc_config[j].path[i];
-
- bw = p->bwg_percent;
- bw_id = p->bwg_id;
-
- if (bw_id >= MAX_BW_GROUP) {
- ret_val = DCB_ERR_CONFIG;
- goto err_config;
- }
- if (p->prio_type == prio_link) {
- link_strict[i][bw_id] = true;
- /* Link strict should have zero bandwidth */
- if (bw) {
- ret_val = DCB_ERR_LS_BW_NONZERO;
- goto err_config;
- }
- } else if (!bw) {
- /*
- * Traffic classes without link strict
- * should have non-zero bandwidth.
- */
- ret_val = DCB_ERR_TC_BW_ZERO;
- goto err_config;
- }
- bw_sum[i][bw_id] += bw;
- }
-
- bw = 0;
-
- /* Check each bandwidth group for rule violation */
- for (j = 0; j < MAX_BW_GROUP; j++) {
- bw += dcb_config->bw_percentage[i][j];
- /*
- * Sum of bandwidth percentages of all traffic classes
- * within a Bandwidth Group must total 100 except for
- * link strict group (zero bandwidth).
- */
- if (link_strict[i][j]) {
- if (bw_sum[i][j]) {
- /*
- * Link strict group should have zero
- * bandwidth.
- */
- ret_val = DCB_ERR_LS_BWG_NONZERO;
- goto err_config;
- }
- } else if (bw_sum[i][j] != BW_PERCENT &&
- bw_sum[i][j] != 0) {
- ret_val = DCB_ERR_TC_BW;
- goto err_config;
- }
- }
-
- if (bw != BW_PERCENT) {
- ret_val = DCB_ERR_BW_GROUP;
- goto err_config;
- }
- }
-
-err_config:
- return ret_val;
-}
-
-/**
* ixgbe_dcb_calculate_tc_credits - Calculates traffic class credits
* @ixgbe_dcb_config: Struct containing DCB settings.
* @direction: Configuring either Tx or Rx.
@@ -203,133 +111,6 @@ out:
}
/**
- * ixgbe_dcb_get_tc_stats - Returns status of each traffic class
- * @hw: pointer to hardware structure
- * @stats: pointer to statistics structure
- * @tc_count: Number of elements in bwg_array.
- *
- * This function returns the status data for each of the Traffic Classes in use.
- */
-s32 ixgbe_dcb_get_tc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats,
- u8 tc_count)
-{
- s32 ret = 0;
- if (hw->mac.type == ixgbe_mac_82598EB)
- ret = ixgbe_dcb_get_tc_stats_82598(hw, stats, tc_count);
- else if (hw->mac.type == ixgbe_mac_82599EB)
- ret = ixgbe_dcb_get_tc_stats_82599(hw, stats, tc_count);
- return ret;
-}
-
-/**
- * ixgbe_dcb_get_pfc_stats - Returns CBFC status of each traffic class
- * hw - pointer to hardware structure
- * stats - pointer to statistics structure
- * tc_count - Number of elements in bwg_array.
- *
- * This function returns the CBFC status data for each of the Traffic Classes.
- */
-s32 ixgbe_dcb_get_pfc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats,
- u8 tc_count)
-{
- s32 ret = 0;
- if (hw->mac.type == ixgbe_mac_82598EB)
- ret = ixgbe_dcb_get_pfc_stats_82598(hw, stats, tc_count);
- else if (hw->mac.type == ixgbe_mac_82599EB)
- ret = ixgbe_dcb_get_pfc_stats_82599(hw, stats, tc_count);
- return ret;
-}
-
-/**
- * ixgbe_dcb_config_rx_arbiter - Config Rx arbiter
- * @hw: pointer to hardware structure
- * @dcb_config: pointer to ixgbe_dcb_config structure
- *
- * Configure Rx Data Arbiter and credits for each traffic class.
- */
-s32 ixgbe_dcb_config_rx_arbiter(struct ixgbe_hw *hw,
- struct ixgbe_dcb_config *dcb_config)
-{
- s32 ret = 0;
- if (hw->mac.type == ixgbe_mac_82598EB)
- ret = ixgbe_dcb_config_rx_arbiter_82598(hw, dcb_config);
- else if (hw->mac.type == ixgbe_mac_82599EB)
- ret = ixgbe_dcb_config_rx_arbiter_82599(hw, dcb_config);
- return ret;
-}
-
-/**
- * ixgbe_dcb_config_tx_desc_arbiter - Config Tx Desc arbiter
- * @hw: pointer to hardware structure
- * @dcb_config: pointer to ixgbe_dcb_config structure
- *
- * Configure Tx Descriptor Arbiter and credits for each traffic class.
- */
-s32 ixgbe_dcb_config_tx_desc_arbiter(struct ixgbe_hw *hw,
- struct ixgbe_dcb_config *dcb_config)
-{
- s32 ret = 0;
- if (hw->mac.type == ixgbe_mac_82598EB)
- ret = ixgbe_dcb_config_tx_desc_arbiter_82598(hw, dcb_config);
- else if (hw->mac.type == ixgbe_mac_82599EB)
- ret = ixgbe_dcb_config_tx_desc_arbiter_82599(hw, dcb_config);
- return ret;
-}
-
-/**
- * ixgbe_dcb_config_tx_data_arbiter - Config Tx data arbiter
- * @hw: pointer to hardware structure
- * @dcb_config: pointer to ixgbe_dcb_config structure
- *
- * Configure Tx Data Arbiter and credits for each traffic class.
- */
-s32 ixgbe_dcb_config_tx_data_arbiter(struct ixgbe_hw *hw,
- struct ixgbe_dcb_config *dcb_config)
-{
- s32 ret = 0;
- if (hw->mac.type == ixgbe_mac_82598EB)
- ret = ixgbe_dcb_config_tx_data_arbiter_82598(hw, dcb_config);
- else if (hw->mac.type == ixgbe_mac_82599EB)
- ret = ixgbe_dcb_config_tx_data_arbiter_82599(hw, dcb_config);
- return ret;
-}
-
-/**
- * ixgbe_dcb_config_pfc - Config priority flow control
- * @hw: pointer to hardware structure
- * @dcb_config: pointer to ixgbe_dcb_config structure
- *
- * Configure Priority Flow Control for each traffic class.
- */
-s32 ixgbe_dcb_config_pfc(struct ixgbe_hw *hw,
- struct ixgbe_dcb_config *dcb_config)
-{
- s32 ret = 0;
- if (hw->mac.type == ixgbe_mac_82598EB)
- ret = ixgbe_dcb_config_pfc_82598(hw, dcb_config);
- else if (hw->mac.type == ixgbe_mac_82599EB)
- ret = ixgbe_dcb_config_pfc_82599(hw, dcb_config);
- return ret;
-}
-
-/**
- * ixgbe_dcb_config_tc_stats - Config traffic class statistics
- * @hw: pointer to hardware structure
- *
- * Configure queue statistics registers, all queues belonging to same traffic
- * class uses a single set of queue statistics counters.
- */
-s32 ixgbe_dcb_config_tc_stats(struct ixgbe_hw *hw)
-{
- s32 ret = 0;
- if (hw->mac.type == ixgbe_mac_82598EB)
- ret = ixgbe_dcb_config_tc_stats_82598(hw);
- else if (hw->mac.type == ixgbe_mac_82599EB)
- ret = ixgbe_dcb_config_tc_stats_82599(hw);
- return ret;
-}
-
-/**
* ixgbe_dcb_hw_config - Config and enable DCB
* @hw: pointer to hardware structure
* @dcb_config: pointer to ixgbe_dcb_config structure
diff --git a/drivers/net/ixgbe/ixgbe_dcb.h b/drivers/net/ixgbe/ixgbe_dcb.h
index 5caafd4afbc3..eb1059f09da0 100644
--- a/drivers/net/ixgbe/ixgbe_dcb.h
+++ b/drivers/net/ixgbe/ixgbe_dcb.h
@@ -149,27 +149,9 @@ struct ixgbe_dcb_config {
/* DCB driver APIs */
-/* DCB rule checking function.*/
-s32 ixgbe_dcb_check_config(struct ixgbe_dcb_config *config);
-
/* DCB credits calculation */
s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *, u8);
-/* DCB PFC functions */
-s32 ixgbe_dcb_config_pfc(struct ixgbe_hw *, struct ixgbe_dcb_config *g);
-s32 ixgbe_dcb_get_pfc_stats(struct ixgbe_hw *, struct ixgbe_hw_stats *, u8);
-
-/* DCB traffic class stats */
-s32 ixgbe_dcb_config_tc_stats(struct ixgbe_hw *);
-s32 ixgbe_dcb_get_tc_stats(struct ixgbe_hw *, struct ixgbe_hw_stats *, u8);
-
-/* DCB config arbiters */
-s32 ixgbe_dcb_config_tx_desc_arbiter(struct ixgbe_hw *,
- struct ixgbe_dcb_config *);
-s32 ixgbe_dcb_config_tx_data_arbiter(struct ixgbe_hw *,
- struct ixgbe_dcb_config *);
-s32 ixgbe_dcb_config_rx_arbiter(struct ixgbe_hw *, struct ixgbe_dcb_config *);
-
/* DCB hw initialization */
s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *);
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ixgbe/ixgbe_dcb_82598.c
index f0e9279d4669..50288bcadc59 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82598.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c
@@ -32,65 +32,6 @@
#include "ixgbe_dcb_82598.h"
/**
- * ixgbe_dcb_get_tc_stats_82598 - Return status data for each traffic class
- * @hw: pointer to hardware structure
- * @stats: pointer to statistics structure
- * @tc_count: Number of elements in bwg_array.
- *
- * This function returns the status data for each of the Traffic Classes in use.
- */
-s32 ixgbe_dcb_get_tc_stats_82598(struct ixgbe_hw *hw,
- struct ixgbe_hw_stats *stats,
- u8 tc_count)
-{
- int tc;
-
- if (tc_count > MAX_TRAFFIC_CLASS)
- return DCB_ERR_PARAM;
-
- /* Statistics pertaining to each traffic class */
- for (tc = 0; tc < tc_count; tc++) {
- /* Transmitted Packets */
- stats->qptc[tc] += IXGBE_READ_REG(hw, IXGBE_QPTC(tc));
- /* Transmitted Bytes */
- stats->qbtc[tc] += IXGBE_READ_REG(hw, IXGBE_QBTC(tc));
- /* Received Packets */
- stats->qprc[tc] += IXGBE_READ_REG(hw, IXGBE_QPRC(tc));
- /* Received Bytes */
- stats->qbrc[tc] += IXGBE_READ_REG(hw, IXGBE_QBRC(tc));
- }
-
- return 0;
-}
-
-/**
- * ixgbe_dcb_get_pfc_stats_82598 - Returns CBFC status data
- * @hw: pointer to hardware structure
- * @stats: pointer to statistics structure
- * @tc_count: Number of elements in bwg_array.
- *
- * This function returns the CBFC status data for each of the Traffic Classes.
- */
-s32 ixgbe_dcb_get_pfc_stats_82598(struct ixgbe_hw *hw,
- struct ixgbe_hw_stats *stats,
- u8 tc_count)
-{
- int tc;
-
- if (tc_count > MAX_TRAFFIC_CLASS)
- return DCB_ERR_PARAM;
-
- for (tc = 0; tc < tc_count; tc++) {
- /* Priority XOFF Transmitted */
- stats->pxofftxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(tc));
- /* Priority XOFF Received */
- stats->pxoffrxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(tc));
- }
-
- return 0;
-}
-
-/**
* ixgbe_dcb_config_packet_buffers_82598 - Configure packet buffers
* @hw: pointer to hardware structure
* @dcb_config: pointer to ixgbe_dcb_config structure
@@ -137,7 +78,7 @@ static s32 ixgbe_dcb_config_packet_buffers_82598(struct ixgbe_hw *hw,
*
* Configure Rx Data Arbiter and credits for each traffic class.
*/
-s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw,
+static s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw,
struct ixgbe_dcb_config *dcb_config)
{
struct tc_bw_alloc *p;
@@ -194,7 +135,7 @@ s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw,
*
* Configure Tx Descriptor Arbiter and credits for each traffic class.
*/
-s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw,
+static s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw,
struct ixgbe_dcb_config *dcb_config)
{
struct tc_bw_alloc *p;
@@ -242,7 +183,7 @@ s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw,
*
* Configure Tx Data Arbiter and credits for each traffic class.
*/
-s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw,
+static s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw,
struct ixgbe_dcb_config *dcb_config)
{
struct tc_bw_alloc *p;
@@ -355,7 +296,7 @@ out:
* Configure queue statistics registers, all queues belonging to same traffic
* class uses a single set of queue statistics counters.
*/
-s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw)
+static s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw)
{
u32 reg = 0;
u8 i = 0;
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.h b/drivers/net/ixgbe/ixgbe_dcb_82598.h
index cc728fa092e2..abc03ccfa088 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82598.h
+++ b/drivers/net/ixgbe/ixgbe_dcb_82598.h
@@ -72,21 +72,6 @@
/* DCB PFC functions */
s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *, struct ixgbe_dcb_config *);
-s32 ixgbe_dcb_get_pfc_stats_82598(struct ixgbe_hw *, struct ixgbe_hw_stats *,
- u8);
-
-/* DCB traffic class stats */
-s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *);
-s32 ixgbe_dcb_get_tc_stats_82598(struct ixgbe_hw *, struct ixgbe_hw_stats *,
- u8);
-
-/* DCB config arbiters */
-s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *,
- struct ixgbe_dcb_config *);
-s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *,
- struct ixgbe_dcb_config *);
-s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *,
- struct ixgbe_dcb_config *);
/* DCB hw initialization */
s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *, struct ixgbe_dcb_config *);
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c
index 25b02fb425ac..67c219f86c3a 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82599.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c
@@ -31,70 +31,13 @@
#include "ixgbe_dcb_82599.h"
/**
- * ixgbe_dcb_get_tc_stats_82599 - Returns status for each traffic class
- * @hw: pointer to hardware structure
- * @stats: pointer to statistics structure
- * @tc_count: Number of elements in bwg_array.
- *
- * This function returns the status data for each of the Traffic Classes in use.
- */
-s32 ixgbe_dcb_get_tc_stats_82599(struct ixgbe_hw *hw,
- struct ixgbe_hw_stats *stats,
- u8 tc_count)
-{
- int tc;
-
- if (tc_count > MAX_TRAFFIC_CLASS)
- return DCB_ERR_PARAM;
- /* Statistics pertaining to each traffic class */
- for (tc = 0; tc < tc_count; tc++) {
- /* Transmitted Packets */
- stats->qptc[tc] += IXGBE_READ_REG(hw, IXGBE_QPTC(tc));
- /* Transmitted Bytes */
- stats->qbtc[tc] += IXGBE_READ_REG(hw, IXGBE_QBTC(tc));
- /* Received Packets */
- stats->qprc[tc] += IXGBE_READ_REG(hw, IXGBE_QPRC(tc));
- /* Received Bytes */
- stats->qbrc[tc] += IXGBE_READ_REG(hw, IXGBE_QBRC(tc));
- }
-
- return 0;
-}
-
-/**
- * ixgbe_dcb_get_pfc_stats_82599 - Return CBFC status data
- * @hw: pointer to hardware structure
- * @stats: pointer to statistics structure
- * @tc_count: Number of elements in bwg_array.
- *
- * This function returns the CBFC status data for each of the Traffic Classes.
- */
-s32 ixgbe_dcb_get_pfc_stats_82599(struct ixgbe_hw *hw,
- struct ixgbe_hw_stats *stats,
- u8 tc_count)
-{
- int tc;
-
- if (tc_count > MAX_TRAFFIC_CLASS)
- return DCB_ERR_PARAM;
- for (tc = 0; tc < tc_count; tc++) {
- /* Priority XOFF Transmitted */
- stats->pxofftxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(tc));
- /* Priority XOFF Received */
- stats->pxoffrxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFRXCNT(tc));
- }
-
- return 0;
-}
-
-/**
* ixgbe_dcb_config_packet_buffers_82599 - Configure DCB packet buffers
* @hw: pointer to hardware structure
* @dcb_config: pointer to ixgbe_dcb_config structure
*
* Configure packet buffers for DCB mode.
*/
-s32 ixgbe_dcb_config_packet_buffers_82599(struct ixgbe_hw *hw,
+static s32 ixgbe_dcb_config_packet_buffers_82599(struct ixgbe_hw *hw,
struct ixgbe_dcb_config *dcb_config)
{
s32 ret_val = 0;
@@ -136,7 +79,7 @@ s32 ixgbe_dcb_config_packet_buffers_82599(struct ixgbe_hw *hw,
*
* Configure Rx Packet Arbiter and credits for each traffic class.
*/
-s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw,
+static s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw,
struct ixgbe_dcb_config *dcb_config)
{
struct tc_bw_alloc *p;
@@ -191,7 +134,7 @@ s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw,
*
* Configure Tx Descriptor Arbiter and credits for each traffic class.
*/
-s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw,
+static s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw,
struct ixgbe_dcb_config *dcb_config)
{
struct tc_bw_alloc *p;
@@ -238,7 +181,7 @@ s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw,
*
* Configure Tx Packet Arbiter and credits for each traffic class.
*/
-s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw,
+static s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw,
struct ixgbe_dcb_config *dcb_config)
{
struct tc_bw_alloc *p;
@@ -359,7 +302,7 @@ out:
* Configure queue statistics registers, all queues belonging to same traffic
* class uses a single set of queue statistics counters.
*/
-s32 ixgbe_dcb_config_tc_stats_82599(struct ixgbe_hw *hw)
+static s32 ixgbe_dcb_config_tc_stats_82599(struct ixgbe_hw *hw)
{
u32 reg = 0;
u8 i = 0;
@@ -412,7 +355,7 @@ s32 ixgbe_dcb_config_tc_stats_82599(struct ixgbe_hw *hw)
*
* Configure general DCB parameters.
*/
-s32 ixgbe_dcb_config_82599(struct ixgbe_hw *hw)
+static s32 ixgbe_dcb_config_82599(struct ixgbe_hw *hw)
{
u32 reg;
u32 q;
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ixgbe/ixgbe_dcb_82599.h
index 0f3f791e1e1d..18d7fbf6c292 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82599.h
+++ b/drivers/net/ixgbe/ixgbe_dcb_82599.h
@@ -101,24 +101,6 @@
/* DCB PFC functions */
s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw,
struct ixgbe_dcb_config *dcb_config);
-s32 ixgbe_dcb_get_pfc_stats_82599(struct ixgbe_hw *hw,
- struct ixgbe_hw_stats *stats,
- u8 tc_count);
-
-/* DCB traffic class stats */
-s32 ixgbe_dcb_config_tc_stats_82599(struct ixgbe_hw *hw);
-s32 ixgbe_dcb_get_tc_stats_82599(struct ixgbe_hw *hw,
- struct ixgbe_hw_stats *stats,
- u8 tc_count);
-
-/* DCB config arbiters */
-s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw,
- struct ixgbe_dcb_config *dcb_config);
-s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw,
- struct ixgbe_dcb_config *dcb_config);
-s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw,
- struct ixgbe_dcb_config *dcb_config);
-
/* DCB hw initialization */
s32 ixgbe_dcb_hw_config_82599(struct ixgbe_hw *hw,
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index dcebc82c6f4d..3dc731c22ff2 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -401,7 +401,7 @@ static int ixgbe_set_pauseparam(struct net_device *netdev,
static u32 ixgbe_get_rx_csum(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
- return (adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED);
+ return adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED;
}
static int ixgbe_set_rx_csum(struct net_device *netdev, u32 data)
@@ -820,16 +820,19 @@ static void ixgbe_get_drvinfo(struct net_device *netdev,
struct ixgbe_adapter *adapter = netdev_priv(netdev);
char firmware_version[32];
- strncpy(drvinfo->driver, ixgbe_driver_name, 32);
- strncpy(drvinfo->version, ixgbe_driver_version, 32);
+ strncpy(drvinfo->driver, ixgbe_driver_name, sizeof(drvinfo->driver));
+ strncpy(drvinfo->version, ixgbe_driver_version,
+ sizeof(drvinfo->version));
- sprintf(firmware_version, "%d.%d-%d",
- (adapter->eeprom_version & 0xF000) >> 12,
- (adapter->eeprom_version & 0x0FF0) >> 4,
- adapter->eeprom_version & 0x000F);
+ snprintf(firmware_version, sizeof(firmware_version), "%d.%d-%d",
+ (adapter->eeprom_version & 0xF000) >> 12,
+ (adapter->eeprom_version & 0x0FF0) >> 4,
+ adapter->eeprom_version & 0x000F);
- strncpy(drvinfo->fw_version, firmware_version, 32);
- strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+ strncpy(drvinfo->fw_version, firmware_version,
+ sizeof(drvinfo->fw_version));
+ strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
+ sizeof(drvinfo->bus_info));
drvinfo->n_stats = IXGBE_STATS_LEN;
drvinfo->testinfo_len = IXGBE_TEST_LEN;
drvinfo->regdump_len = ixgbe_get_regs_len(netdev);
@@ -985,8 +988,8 @@ static int ixgbe_get_sset_count(struct net_device *netdev, int sset)
case ETH_SS_STATS:
return IXGBE_STATS_LEN;
case ETH_SS_NTUPLE_FILTERS:
- return (ETHTOOL_MAX_NTUPLE_LIST_ENTRY *
- ETHTOOL_MAX_NTUPLE_STRING_PER_ENTRY);
+ return ETHTOOL_MAX_NTUPLE_LIST_ENTRY *
+ ETHTOOL_MAX_NTUPLE_STRING_PER_ENTRY;
default:
return -EOPNOTSUPP;
}
@@ -996,12 +999,11 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, u64 *data)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
- u64 *queue_stat;
- int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64);
struct rtnl_link_stats64 temp;
const struct rtnl_link_stats64 *net_stats;
- int j, k;
- int i;
+ unsigned int start;
+ struct ixgbe_ring *ring;
+ int i, j;
char *p = NULL;
ixgbe_update_stats(adapter);
@@ -1022,16 +1024,22 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
for (j = 0; j < adapter->num_tx_queues; j++) {
- queue_stat = (u64 *)&adapter->tx_ring[j]->stats;
- for (k = 0; k < stat_count; k++)
- data[i + k] = queue_stat[k];
- i += k;
+ ring = adapter->tx_ring[j];
+ do {
+ start = u64_stats_fetch_begin_bh(&ring->syncp);
+ data[i] = ring->stats.packets;
+ data[i+1] = ring->stats.bytes;
+ } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+ i += 2;
}
for (j = 0; j < adapter->num_rx_queues; j++) {
- queue_stat = (u64 *)&adapter->rx_ring[j]->stats;
- for (k = 0; k < stat_count; k++)
- data[i + k] = queue_stat[k];
- i += k;
+ ring = adapter->rx_ring[j];
+ do {
+ start = u64_stats_fetch_begin_bh(&ring->syncp);
+ data[i] = ring->stats.packets;
+ data[i+1] = ring->stats.bytes;
+ } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+ i += 2;
}
if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
for (j = 0; j < MAX_TX_PACKET_BUFFERS; j++) {
@@ -1435,9 +1443,7 @@ static void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter)
struct ixgbe_ring *tx_ring = &adapter->test_tx_ring;
struct ixgbe_ring *rx_ring = &adapter->test_rx_ring;
struct ixgbe_hw *hw = &adapter->hw;
- struct pci_dev *pdev = adapter->pdev;
u32 reg_ctl;
- int i;
/* shut down the DMA engines now so they can be reinitialized later */
@@ -1445,14 +1451,15 @@ static void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter)
reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
reg_ctl &= ~IXGBE_RXCTRL_RXEN;
IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_ctl);
- reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(0));
+ reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->reg_idx));
reg_ctl &= ~IXGBE_RXDCTL_ENABLE;
- IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(0), reg_ctl);
+ IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->reg_idx), reg_ctl);
/* now Tx */
- reg_ctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(0));
+ reg_ctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(tx_ring->reg_idx));
reg_ctl &= ~IXGBE_TXDCTL_ENABLE;
- IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(0), reg_ctl);
+ IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(tx_ring->reg_idx), reg_ctl);
+
if (hw->mac.type == ixgbe_mac_82599EB) {
reg_ctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
reg_ctl &= ~IXGBE_DMATXCTL_TE;
@@ -1461,221 +1468,57 @@ static void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter)
ixgbe_reset(adapter);
- if (tx_ring->desc && tx_ring->tx_buffer_info) {
- for (i = 0; i < tx_ring->count; i++) {
- struct ixgbe_tx_buffer *buf =
- &(tx_ring->tx_buffer_info[i]);
- if (buf->dma)
- dma_unmap_single(&pdev->dev, buf->dma,
- buf->length, DMA_TO_DEVICE);
- if (buf->skb)
- dev_kfree_skb(buf->skb);
- }
- }
-
- if (rx_ring->desc && rx_ring->rx_buffer_info) {
- for (i = 0; i < rx_ring->count; i++) {
- struct ixgbe_rx_buffer *buf =
- &(rx_ring->rx_buffer_info[i]);
- if (buf->dma)
- dma_unmap_single(&pdev->dev, buf->dma,
- IXGBE_RXBUFFER_2048,
- DMA_FROM_DEVICE);
- if (buf->skb)
- dev_kfree_skb(buf->skb);
- }
- }
-
- if (tx_ring->desc) {
- dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
- tx_ring->dma);
- tx_ring->desc = NULL;
- }
- if (rx_ring->desc) {
- dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
- rx_ring->dma);
- rx_ring->desc = NULL;
- }
-
- kfree(tx_ring->tx_buffer_info);
- tx_ring->tx_buffer_info = NULL;
- kfree(rx_ring->rx_buffer_info);
- rx_ring->rx_buffer_info = NULL;
+ ixgbe_free_tx_resources(adapter, &adapter->test_tx_ring);
+ ixgbe_free_rx_resources(adapter, &adapter->test_rx_ring);
}
static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
{
struct ixgbe_ring *tx_ring = &adapter->test_tx_ring;
struct ixgbe_ring *rx_ring = &adapter->test_rx_ring;
- struct pci_dev *pdev = adapter->pdev;
u32 rctl, reg_data;
- int i, ret_val;
+ int ret_val;
+ int err;
/* Setup Tx descriptor ring and Tx buffers */
+ tx_ring->count = IXGBE_DEFAULT_TXD;
+ tx_ring->queue_index = 0;
+ tx_ring->reg_idx = adapter->tx_ring[0]->reg_idx;
+ tx_ring->numa_node = adapter->node;
- if (!tx_ring->count)
- tx_ring->count = IXGBE_DEFAULT_TXD;
-
- tx_ring->tx_buffer_info = kcalloc(tx_ring->count,
- sizeof(struct ixgbe_tx_buffer),
- GFP_KERNEL);
- if (!(tx_ring->tx_buffer_info)) {
- ret_val = 1;
- goto err_nomem;
- }
-
- tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc);
- tx_ring->size = ALIGN(tx_ring->size, 4096);
- tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size,
- &tx_ring->dma, GFP_KERNEL);
- if (!(tx_ring->desc)) {
- ret_val = 2;
- goto err_nomem;
- }
- tx_ring->next_to_use = tx_ring->next_to_clean = 0;
-
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAL(0),
- ((u64) tx_ring->dma & 0x00000000FFFFFFFF));
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAH(0),
- ((u64) tx_ring->dma >> 32));
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDLEN(0),
- tx_ring->count * sizeof(union ixgbe_adv_tx_desc));
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDH(0), 0);
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), 0);
-
- reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0);
- reg_data |= IXGBE_HLREG0_TXPADEN;
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data);
+ err = ixgbe_setup_tx_resources(adapter, tx_ring);
+ if (err)
+ return 1;
if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_DMATXCTL);
reg_data |= IXGBE_DMATXCTL_TE;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_DMATXCTL, reg_data);
}
- reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_TXDCTL(0));
- reg_data |= IXGBE_TXDCTL_ENABLE;
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(0), reg_data);
-
- for (i = 0; i < tx_ring->count; i++) {
- union ixgbe_adv_tx_desc *desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
- struct sk_buff *skb;
- unsigned int size = 1024;
-
- skb = alloc_skb(size, GFP_KERNEL);
- if (!skb) {
- ret_val = 3;
- goto err_nomem;
- }
- skb_put(skb, size);
- tx_ring->tx_buffer_info[i].skb = skb;
- tx_ring->tx_buffer_info[i].length = skb->len;
- tx_ring->tx_buffer_info[i].dma =
- dma_map_single(&pdev->dev, skb->data, skb->len,
- DMA_TO_DEVICE);
- desc->read.buffer_addr =
- cpu_to_le64(tx_ring->tx_buffer_info[i].dma);
- desc->read.cmd_type_len = cpu_to_le32(skb->len);
- desc->read.cmd_type_len |= cpu_to_le32(IXGBE_TXD_CMD_EOP |
- IXGBE_TXD_CMD_IFCS |
- IXGBE_TXD_CMD_RS);
- desc->read.olinfo_status = 0;
- if (adapter->hw.mac.type == ixgbe_mac_82599EB)
- desc->read.olinfo_status |=
- (skb->len << IXGBE_ADVTXD_PAYLEN_SHIFT);
- }
+ ixgbe_configure_tx_ring(adapter, tx_ring);
/* Setup Rx Descriptor ring and Rx buffers */
-
- if (!rx_ring->count)
- rx_ring->count = IXGBE_DEFAULT_RXD;
-
- rx_ring->rx_buffer_info = kcalloc(rx_ring->count,
- sizeof(struct ixgbe_rx_buffer),
- GFP_KERNEL);
- if (!(rx_ring->rx_buffer_info)) {
+ rx_ring->count = IXGBE_DEFAULT_RXD;
+ rx_ring->queue_index = 0;
+ rx_ring->reg_idx = adapter->rx_ring[0]->reg_idx;
+ rx_ring->rx_buf_len = IXGBE_RXBUFFER_2048;
+ rx_ring->numa_node = adapter->node;
+
+ err = ixgbe_setup_rx_resources(adapter, rx_ring);
+ if (err) {
ret_val = 4;
goto err_nomem;
}
- rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc);
- rx_ring->size = ALIGN(rx_ring->size, 4096);
- rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
- &rx_ring->dma, GFP_KERNEL);
- if (!(rx_ring->desc)) {
- ret_val = 5;
- goto err_nomem;
- }
- rx_ring->next_to_use = rx_ring->next_to_clean = 0;
-
rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl & ~IXGBE_RXCTRL_RXEN);
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDBAL(0),
- ((u64)rx_ring->dma & 0xFFFFFFFF));
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDBAH(0),
- ((u64) rx_ring->dma >> 32));
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDLEN(0), rx_ring->size);
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDH(0), 0);
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(0), 0);
- reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
- reg_data |= IXGBE_FCTRL_BAM | IXGBE_FCTRL_SBP | IXGBE_FCTRL_MPE;
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_data);
-
- reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0);
- reg_data &= ~IXGBE_HLREG0_LPBK;
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data);
-
- reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_RDRXCTL);
-#define IXGBE_RDRXCTL_RDMTS_MASK 0x00000003 /* Receive Descriptor Minimum
- Threshold Size mask */
- reg_data &= ~IXGBE_RDRXCTL_RDMTS_MASK;
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDRXCTL, reg_data);
-
- reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_MCSTCTRL);
-#define IXGBE_MCSTCTRL_MO_MASK 0x00000003 /* Multicast Offset mask */
- reg_data &= ~IXGBE_MCSTCTRL_MO_MASK;
- reg_data |= adapter->hw.mac.mc_filter_type;
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_MCSTCTRL, reg_data);
-
- reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(0));
- reg_data |= IXGBE_RXDCTL_ENABLE;
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(0), reg_data);
- if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
- int j = adapter->rx_ring[0]->reg_idx;
- u32 k;
- for (k = 0; k < 10; k++) {
- if (IXGBE_READ_REG(&adapter->hw,
- IXGBE_RXDCTL(j)) & IXGBE_RXDCTL_ENABLE)
- break;
- else
- msleep(1);
- }
- }
+ ixgbe_configure_rx_ring(adapter, rx_ring);
rctl |= IXGBE_RXCTRL_RXEN | IXGBE_RXCTRL_DMBYPS;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl);
- for (i = 0; i < rx_ring->count; i++) {
- union ixgbe_adv_rx_desc *rx_desc =
- IXGBE_RX_DESC_ADV(*rx_ring, i);
- struct sk_buff *skb;
-
- skb = alloc_skb(IXGBE_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL);
- if (!skb) {
- ret_val = 6;
- goto err_nomem;
- }
- skb_reserve(skb, NET_IP_ALIGN);
- rx_ring->rx_buffer_info[i].skb = skb;
- rx_ring->rx_buffer_info[i].dma =
- dma_map_single(&pdev->dev, skb->data,
- IXGBE_RXBUFFER_2048, DMA_FROM_DEVICE);
- rx_desc->read.pkt_addr =
- cpu_to_le64(rx_ring->rx_buffer_info[i].dma);
- memset(skb->data, 0x00, skb->len);
- }
-
return 0;
err_nomem:
@@ -1689,16 +1532,21 @@ static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter)
u32 reg_data;
/* right now we only support MAC loopback in the driver */
-
- /* Setup MAC loopback */
reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0);
+ /* Setup MAC loopback */
reg_data |= IXGBE_HLREG0_LPBK;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data);
+ reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
+ reg_data |= IXGBE_FCTRL_BAM | IXGBE_FCTRL_SBP | IXGBE_FCTRL_MPE;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_data);
+
reg_data = IXGBE_READ_REG(&adapter->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);
+ msleep(10);
/* Disable Atlas Tx lanes; re-enabled in reset path */
if (hw->mac.type == ixgbe_mac_82598EB) {
@@ -1756,15 +1604,81 @@ static int ixgbe_check_lbtest_frame(struct sk_buff *skb,
return 13;
}
+static u16 ixgbe_clean_test_rings(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rx_ring,
+ struct ixgbe_ring *tx_ring,
+ unsigned int size)
+{
+ union ixgbe_adv_rx_desc *rx_desc;
+ struct ixgbe_rx_buffer *rx_buffer_info;
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ const int bufsz = rx_ring->rx_buf_len;
+ u32 staterr;
+ 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 = IXGBE_RX_DESC_ADV(rx_ring, rx_ntc);
+ staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+
+ while (staterr & IXGBE_RXD_STAT_DD) {
+ /* check Rx buffer */
+ rx_buffer_info = &rx_ring->rx_buffer_info[rx_ntc];
+
+ /* unmap Rx buffer, will be remapped by alloc_rx_buffers */
+ dma_unmap_single(&adapter->pdev->dev,
+ rx_buffer_info->dma,
+ bufsz,
+ DMA_FROM_DEVICE);
+ rx_buffer_info->dma = 0;
+
+ /* verify contents of skb */
+ if (!ixgbe_check_lbtest_frame(rx_buffer_info->skb, size))
+ count++;
+
+ /* unmap buffer on Tx side */
+ tx_buffer_info = &tx_ring->tx_buffer_info[tx_ntc];
+ ixgbe_unmap_and_free_tx_resource(adapter, tx_buffer_info);
+
+ /* increment Rx/Tx next to clean counters */
+ rx_ntc++;
+ if (rx_ntc == rx_ring->count)
+ rx_ntc = 0;
+ tx_ntc++;
+ if (tx_ntc == tx_ring->count)
+ tx_ntc = 0;
+
+ /* fetch next descriptor */
+ rx_desc = IXGBE_RX_DESC_ADV(rx_ring, rx_ntc);
+ staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+ }
+
+ /* re-map buffers to ring, store next to clean values */
+ ixgbe_alloc_rx_buffers(adapter, rx_ring, count);
+ rx_ring->next_to_clean = rx_ntc;
+ tx_ring->next_to_clean = tx_ntc;
+
+ return count;
+}
+
static int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter)
{
struct ixgbe_ring *tx_ring = &adapter->test_tx_ring;
struct ixgbe_ring *rx_ring = &adapter->test_rx_ring;
- struct pci_dev *pdev = adapter->pdev;
- int i, j, k, l, lc, good_cnt, ret_val = 0;
- unsigned long time;
+ int i, j, lc, good_cnt, ret_val = 0;
+ unsigned int size = 1024;
+ netdev_tx_t tx_ret_val;
+ struct sk_buff *skb;
+
+ /* allocate test skb */
+ skb = alloc_skb(size, GFP_KERNEL);
+ if (!skb)
+ return 11;
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(0), rx_ring->count - 1);
+ /* place data into test skb */
+ ixgbe_create_lbtest_frame(skb, size);
+ skb_put(skb, size);
/*
* Calculate the loop count based on the largest descriptor ring
@@ -1777,54 +1691,40 @@ static int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter)
else
lc = ((rx_ring->count / 64) * 2) + 1;
- k = l = 0;
for (j = 0; j <= lc; j++) {
- for (i = 0; i < 64; i++) {
- ixgbe_create_lbtest_frame(
- tx_ring->tx_buffer_info[k].skb,
- 1024);
- dma_sync_single_for_device(&pdev->dev,
- tx_ring->tx_buffer_info[k].dma,
- tx_ring->tx_buffer_info[k].length,
- DMA_TO_DEVICE);
- if (unlikely(++k == tx_ring->count))
- k = 0;
- }
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), k);
- msleep(200);
- /* set the start time for the receive */
- time = jiffies;
+ /* reset count of good packets */
good_cnt = 0;
- do {
- /* receive the sent packets */
- dma_sync_single_for_cpu(&pdev->dev,
- rx_ring->rx_buffer_info[l].dma,
- IXGBE_RXBUFFER_2048,
- DMA_FROM_DEVICE);
- ret_val = ixgbe_check_lbtest_frame(
- rx_ring->rx_buffer_info[l].skb, 1024);
- if (!ret_val)
+
+ /* place 64 packets on the transmit queue*/
+ for (i = 0; i < 64; i++) {
+ skb_get(skb);
+ tx_ret_val = ixgbe_xmit_frame_ring(skb,
+ adapter->netdev,
+ adapter,
+ tx_ring);
+ if (tx_ret_val == NETDEV_TX_OK)
good_cnt++;
- if (++l == rx_ring->count)
- l = 0;
- /*
- * time + 20 msecs (200 msecs on 2.4) is more than
- * enough time to complete the receives, if it's
- * exceeded, break and error off
- */
- } while (good_cnt < 64 && jiffies < (time + 20));
+ }
+
if (good_cnt != 64) {
- /* ret_val is the same as mis-compare */
- ret_val = 13;
+ ret_val = 12;
break;
}
- if (jiffies >= (time + 20)) {
- /* Error code for time out error */
- ret_val = 14;
+
+ /* allow 200 milliseconds for packets to go from Tx to Rx */
+ msleep(200);
+
+ good_cnt = ixgbe_clean_test_rings(adapter, rx_ring,
+ tx_ring, size);
+ if (good_cnt != 64) {
+ ret_val = 13;
break;
}
}
+ /* free the original skb */
+ kfree_skb(skb);
+
return ret_val;
}
@@ -2218,7 +2118,17 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data)
bool need_reset = false;
int rc;
- rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_LRO | ETH_FLAG_NTUPLE);
+#ifdef CONFIG_IXGBE_DCB
+ if ((adapter->flags & IXGBE_FLAG_DCB_ENABLED) &&
+ !(data & ETH_FLAG_RXVLAN))
+ return -EINVAL;
+#endif
+
+ need_reset = (data & ETH_FLAG_RXVLAN) !=
+ (netdev->features & NETIF_F_HW_VLAN_RX);
+
+ rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_LRO |
+ ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN);
if (rc)
return rc;
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c
index 072327c5e41a..05efa6a8ce8e 100644
--- a/drivers/net/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ixgbe/ixgbe_fcoe.c
@@ -304,12 +304,13 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
if (!ixgbe_rx_is_fcoe(rx_desc))
goto ddp_out;
- skb->ip_summed = CHECKSUM_UNNECESSARY;
sterr = le32_to_cpu(rx_desc->wb.upper.status_error);
fcerr = (sterr & IXGBE_RXDADV_ERR_FCERR);
fceofe = (sterr & IXGBE_RXDADV_ERR_FCEOFE);
if (fcerr == IXGBE_FCERR_BADCRC)
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
+ else
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
if (eth_hdr(skb)->h_proto == htons(ETH_P_8021Q))
fh = (struct fc_frame_header *)(skb->data +
@@ -471,7 +472,7 @@ int ixgbe_fso(struct ixgbe_adapter *adapter,
/* write context desc */
i = tx_ring->next_to_use;
- context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i);
+ context_desc = IXGBE_TX_CTXTDESC_ADV(tx_ring, i);
context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
context_desc->seqnum_seed = cpu_to_le32(fcoe_sof_eof);
context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd);
@@ -603,11 +604,13 @@ int ixgbe_fcoe_enable(struct net_device *netdev)
{
int rc = -EINVAL;
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_fcoe *fcoe = &adapter->fcoe;
if (!(adapter->flags & IXGBE_FLAG_FCOE_CAPABLE))
goto out_enable;
+ atomic_inc(&fcoe->refcnt);
if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
goto out_enable;
@@ -647,6 +650,7 @@ int ixgbe_fcoe_disable(struct net_device *netdev)
{
int rc = -EINVAL;
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_fcoe *fcoe = &adapter->fcoe;
if (!(adapter->flags & IXGBE_FLAG_FCOE_CAPABLE))
goto out_disable;
@@ -654,6 +658,9 @@ int ixgbe_fcoe_disable(struct net_device *netdev)
if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))
goto out_disable;
+ if (!atomic_dec_and_test(&fcoe->refcnt))
+ goto out_disable;
+
e_info(drv, "Disabling FCoE offload features.\n");
netdev->features &= ~NETIF_F_FCOE_CRC;
netdev->features &= ~NETIF_F_FSO;
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.h b/drivers/net/ixgbe/ixgbe_fcoe.h
index abf4b2b3f252..4bc2c551c8db 100644
--- a/drivers/net/ixgbe/ixgbe_fcoe.h
+++ b/drivers/net/ixgbe/ixgbe_fcoe.h
@@ -66,6 +66,7 @@ struct ixgbe_fcoe {
u8 tc;
u8 up;
#endif
+ atomic_t refcnt;
spinlock_t lock;
struct pci_pool *pool;
struct ixgbe_fcoe_ddp ddp[IXGBE_FCOE_DDP_MAX];
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index e32af434cc9d..f85631263af8 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -50,7 +50,7 @@
char ixgbe_driver_name[] = "ixgbe";
static const char ixgbe_driver_string[] =
- "Intel(R) 10 Gigabit PCI Express Network Driver";
+ "Intel(R) 10 Gigabit PCI Express Network Driver";
#define DRV_VERSION "2.0.84-k2"
const char ixgbe_driver_version[] = DRV_VERSION;
@@ -120,7 +120,7 @@ MODULE_DEVICE_TABLE(pci, ixgbe_pci_tbl);
#ifdef CONFIG_IXGBE_DCA
static int ixgbe_notify_dca(struct notifier_block *, unsigned long event,
- void *p);
+ void *p);
static struct notifier_block dca_notifier = {
.notifier_call = ixgbe_notify_dca,
.next = NULL,
@@ -131,8 +131,8 @@ static struct notifier_block dca_notifier = {
#ifdef CONFIG_PCI_IOV
static unsigned int max_vfs;
module_param(max_vfs, uint, 0);
-MODULE_PARM_DESC(max_vfs, "Maximum number of virtual functions to allocate "
- "per physical function");
+MODULE_PARM_DESC(max_vfs,
+ "Maximum number of virtual functions to allocate per physical function");
#endif /* CONFIG_PCI_IOV */
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
@@ -169,8 +169,8 @@ static inline void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
/* take a breather then clean up driver data */
msleep(100);
- if (adapter->vfinfo)
- kfree(adapter->vfinfo);
+
+ kfree(adapter->vfinfo);
adapter->vfinfo = NULL;
adapter->num_vfs = 0;
@@ -282,17 +282,17 @@ static void ixgbe_regdump(struct ixgbe_hw *hw, struct ixgbe_reg_info *reginfo)
regs[i] = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
break;
default:
- printk(KERN_INFO "%-15s %08x\n", reginfo->name,
+ pr_info("%-15s %08x\n", reginfo->name,
IXGBE_READ_REG(hw, reginfo->ofs));
return;
}
for (i = 0; i < 8; i++) {
snprintf(rname, 16, "%s[%d-%d]", reginfo->name, i*8, i*8+7);
- printk(KERN_ERR "%-15s ", rname);
+ pr_err("%-15s", rname);
for (j = 0; j < 8; j++)
- printk(KERN_CONT "%08x ", regs[i*8+j]);
- printk(KERN_CONT "\n");
+ pr_cont(" %08x", regs[i*8+j]);
+ pr_cont("\n");
}
}
@@ -322,18 +322,18 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
/* Print netdevice Info */
if (netdev) {
dev_info(&adapter->pdev->dev, "Net device Info\n");
- printk(KERN_INFO "Device Name state "
+ pr_info("Device Name state "
"trans_start last_rx\n");
- printk(KERN_INFO "%-15s %016lX %016lX %016lX\n",
- netdev->name,
- netdev->state,
- netdev->trans_start,
- netdev->last_rx);
+ pr_info("%-15s %016lX %016lX %016lX\n",
+ netdev->name,
+ netdev->state,
+ netdev->trans_start,
+ netdev->last_rx);
}
/* Print Registers */
dev_info(&adapter->pdev->dev, "Register Dump\n");
- printk(KERN_INFO " Register Name Value\n");
+ pr_info(" Register Name Value\n");
for (reginfo = (struct ixgbe_reg_info *)ixgbe_reg_info_tbl;
reginfo->name; reginfo++) {
ixgbe_regdump(hw, reginfo);
@@ -344,13 +344,12 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
goto exit;
dev_info(&adapter->pdev->dev, "TX Rings Summary\n");
- printk(KERN_INFO "Queue [NTU] [NTC] [bi(ntc)->dma ] "
- "leng ntw timestamp\n");
+ pr_info("Queue [NTU] [NTC] [bi(ntc)->dma ] leng ntw timestamp\n");
for (n = 0; n < adapter->num_tx_queues; n++) {
tx_ring = adapter->tx_ring[n];
tx_buffer_info =
&tx_ring->tx_buffer_info[tx_ring->next_to_clean];
- printk(KERN_INFO " %5d %5X %5X %016llX %04X %3X %016llX\n",
+ pr_info(" %5d %5X %5X %016llX %04X %3X %016llX\n",
n, tx_ring->next_to_use, tx_ring->next_to_clean,
(u64)tx_buffer_info->dma,
tx_buffer_info->length,
@@ -377,18 +376,18 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
for (n = 0; n < adapter->num_tx_queues; n++) {
tx_ring = adapter->tx_ring[n];
- printk(KERN_INFO "------------------------------------\n");
- printk(KERN_INFO "TX QUEUE INDEX = %d\n", tx_ring->queue_index);
- printk(KERN_INFO "------------------------------------\n");
- printk(KERN_INFO "T [desc] [address 63:0 ] "
+ pr_info("------------------------------------\n");
+ pr_info("TX QUEUE INDEX = %d\n", tx_ring->queue_index);
+ pr_info("------------------------------------\n");
+ pr_info("T [desc] [address 63:0 ] "
"[PlPOIdStDDt Ln] [bi->dma ] "
"leng ntw timestamp bi->skb\n");
for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
- tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+ tx_desc = IXGBE_TX_DESC_ADV(tx_ring, i);
tx_buffer_info = &tx_ring->tx_buffer_info[i];
u0 = (struct my_u0 *)tx_desc;
- printk(KERN_INFO "T [0x%03X] %016llX %016llX %016llX"
+ pr_info("T [0x%03X] %016llX %016llX %016llX"
" %04X %3X %016llX %p", i,
le64_to_cpu(u0->a),
le64_to_cpu(u0->b),
@@ -399,13 +398,13 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
tx_buffer_info->skb);
if (i == tx_ring->next_to_use &&
i == tx_ring->next_to_clean)
- printk(KERN_CONT " NTC/U\n");
+ pr_cont(" NTC/U\n");
else if (i == tx_ring->next_to_use)
- printk(KERN_CONT " NTU\n");
+ pr_cont(" NTU\n");
else if (i == tx_ring->next_to_clean)
- printk(KERN_CONT " NTC\n");
+ pr_cont(" NTC\n");
else
- printk(KERN_CONT "\n");
+ pr_cont("\n");
if (netif_msg_pktdata(adapter) &&
tx_buffer_info->dma != 0)
@@ -419,11 +418,11 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
/* Print RX Rings Summary */
rx_ring_summary:
dev_info(&adapter->pdev->dev, "RX Rings Summary\n");
- printk(KERN_INFO "Queue [NTU] [NTC]\n");
+ pr_info("Queue [NTU] [NTC]\n");
for (n = 0; n < adapter->num_rx_queues; n++) {
rx_ring = adapter->rx_ring[n];
- printk(KERN_INFO "%5d %5X %5X\n", n,
- rx_ring->next_to_use, rx_ring->next_to_clean);
+ pr_info("%5d %5X %5X\n",
+ n, rx_ring->next_to_use, rx_ring->next_to_clean);
}
/* Print RX Rings */
@@ -454,30 +453,30 @@ rx_ring_summary:
*/
for (n = 0; n < adapter->num_rx_queues; n++) {
rx_ring = adapter->rx_ring[n];
- printk(KERN_INFO "------------------------------------\n");
- printk(KERN_INFO "RX QUEUE INDEX = %d\n", rx_ring->queue_index);
- printk(KERN_INFO "------------------------------------\n");
- printk(KERN_INFO "R [desc] [ PktBuf A0] "
+ pr_info("------------------------------------\n");
+ pr_info("RX QUEUE INDEX = %d\n", rx_ring->queue_index);
+ pr_info("------------------------------------\n");
+ pr_info("R [desc] [ PktBuf A0] "
"[ HeadBuf DD] [bi->dma ] [bi->skb] "
"<-- Adv Rx Read format\n");
- printk(KERN_INFO "RWB[desc] [PcsmIpSHl PtRs] "
+ pr_info("RWB[desc] [PcsmIpSHl PtRs] "
"[vl er S cks ln] ---------------- [bi->skb] "
"<-- Adv Rx Write-Back format\n");
for (i = 0; i < rx_ring->count; i++) {
rx_buffer_info = &rx_ring->rx_buffer_info[i];
- rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+ rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
u0 = (struct my_u0 *)rx_desc;
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
if (staterr & IXGBE_RXD_STAT_DD) {
/* Descriptor Done */
- printk(KERN_INFO "RWB[0x%03X] %016llX "
+ pr_info("RWB[0x%03X] %016llX "
"%016llX ---------------- %p", i,
le64_to_cpu(u0->a),
le64_to_cpu(u0->b),
rx_buffer_info->skb);
} else {
- printk(KERN_INFO "R [0x%03X] %016llX "
+ pr_info("R [0x%03X] %016llX "
"%016llX %016llX %p", i,
le64_to_cpu(u0->a),
le64_to_cpu(u0->b),
@@ -503,11 +502,11 @@ rx_ring_summary:
}
if (i == rx_ring->next_to_use)
- printk(KERN_CONT " NTU\n");
+ pr_cont(" NTU\n");
else if (i == rx_ring->next_to_clean)
- printk(KERN_CONT " NTC\n");
+ pr_cont(" NTC\n");
else
- printk(KERN_CONT "\n");
+ pr_cont("\n");
}
}
@@ -523,7 +522,7 @@ static void ixgbe_release_hw_control(struct ixgbe_adapter *adapter)
/* Let firmware take over control of h/w */
ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
- ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
+ ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
}
static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter)
@@ -533,7 +532,7 @@ static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter)
/* Let firmware know the driver has taken over */
ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
- ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
+ ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
}
/*
@@ -545,7 +544,7 @@ static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter)
*
*/
static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction,
- u8 queue, u8 msix_vector)
+ u8 queue, u8 msix_vector)
{
u32 ivar, index;
struct ixgbe_hw *hw = &adapter->hw;
@@ -586,7 +585,7 @@ static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction,
}
static inline void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter,
- u64 qmask)
+ u64 qmask)
{
u32 mask;
@@ -601,9 +600,9 @@ static inline void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter,
}
}
-static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
- struct ixgbe_tx_buffer
- *tx_buffer_info)
+void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
+ struct ixgbe_tx_buffer
+ *tx_buffer_info)
{
if (tx_buffer_info->dma) {
if (tx_buffer_info->mapped_as_page)
@@ -637,7 +636,7 @@ static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
* Returns : true if in xon state (currently not paused)
*/
static inline bool ixgbe_tx_xon_state(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring)
+ struct ixgbe_ring *tx_ring)
{
u32 txoff = IXGBE_TFCS_TXOFF;
@@ -682,8 +681,8 @@ static inline bool ixgbe_tx_xon_state(struct ixgbe_adapter *adapter,
}
static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring,
- unsigned int eop)
+ struct ixgbe_ring *tx_ring,
+ unsigned int eop)
{
struct ixgbe_hw *hw = &adapter->hw;
@@ -695,7 +694,7 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
ixgbe_tx_xon_state(adapter, tx_ring)) {
/* detected Tx unit hang */
union ixgbe_adv_tx_desc *tx_desc;
- tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
+ tx_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
e_err(drv, "Detected Tx Unit Hang\n"
" Tx Queue <%d>\n"
" TDH, TDT <%x>, <%x>\n"
@@ -732,7 +731,7 @@ static void ixgbe_tx_timeout(struct net_device *netdev);
* @tx_ring: tx ring to clean
**/
static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
- struct ixgbe_ring *tx_ring)
+ struct ixgbe_ring *tx_ring)
{
struct ixgbe_adapter *adapter = q_vector->adapter;
struct net_device *netdev = adapter->netdev;
@@ -743,7 +742,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
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);
+ eop_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
while ((eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) &&
(count < tx_ring->work_limit)) {
@@ -751,7 +750,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
rmb(); /* read buffer_info after eop_desc */
for ( ; !cleaned; count++) {
struct sk_buff *skb;
- tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+ tx_desc = IXGBE_TX_DESC_ADV(tx_ring, i);
tx_buffer_info = &tx_ring->tx_buffer_info[i];
cleaned = (i == eop);
skb = tx_buffer_info->skb;
@@ -781,7 +780,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
}
ixgbe_unmap_and_free_tx_resource(adapter,
- tx_buffer_info);
+ tx_buffer_info);
tx_desc->wb.status = 0;
@@ -791,14 +790,14 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
}
eop = tx_ring->tx_buffer_info[i].next_to_watch;
- eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
+ eop_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
}
tx_ring->next_to_clean = i;
#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
if (unlikely(count && netif_carrier_ok(netdev) &&
- (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) {
+ (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) {
/* Make sure that anybody stopping the queue after this
* sees the new next_to_clean.
*/
@@ -825,14 +824,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
tx_ring->total_bytes += total_bytes;
tx_ring->total_packets += total_packets;
+ u64_stats_update_begin(&tx_ring->syncp);
tx_ring->stats.packets += total_packets;
tx_ring->stats.bytes += total_bytes;
- return (count < tx_ring->work_limit);
+ u64_stats_update_end(&tx_ring->syncp);
+ return count < tx_ring->work_limit;
}
#ifdef CONFIG_IXGBE_DCA
static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *rx_ring)
+ struct ixgbe_ring *rx_ring)
{
u32 rxctrl;
int cpu = get_cpu();
@@ -846,13 +847,13 @@ static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter,
} else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK_82599;
rxctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
- IXGBE_DCA_RXCTRL_CPUID_SHIFT_82599);
+ IXGBE_DCA_RXCTRL_CPUID_SHIFT_82599);
}
rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN;
rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN;
rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_RRO_EN);
rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN |
- IXGBE_DCA_RXCTRL_DESC_HSRO_EN);
+ IXGBE_DCA_RXCTRL_DESC_HSRO_EN);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q), rxctrl);
rx_ring->cpu = cpu;
}
@@ -860,7 +861,7 @@ static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter,
}
static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring)
+ struct ixgbe_ring *tx_ring)
{
u32 txctrl;
int cpu = get_cpu();
@@ -878,7 +879,7 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter,
txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(q));
txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK_82599;
txctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
- IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599);
+ IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599);
txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(q), txctrl);
}
@@ -946,27 +947,22 @@ static int __ixgbe_notify_dca(struct device *dev, void *data)
* @rx_desc: rx descriptor
**/
static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector,
- struct sk_buff *skb, u8 status,
- struct ixgbe_ring *ring,
- union ixgbe_adv_rx_desc *rx_desc)
+ struct sk_buff *skb, u8 status,
+ struct ixgbe_ring *ring,
+ union ixgbe_adv_rx_desc *rx_desc)
{
struct ixgbe_adapter *adapter = q_vector->adapter;
struct napi_struct *napi = &q_vector->napi;
bool is_vlan = (status & IXGBE_RXD_STAT_VP);
u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan);
- skb_record_rx_queue(skb, ring->queue_index);
- if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) {
- if (adapter->vlgrp && is_vlan && (tag & VLAN_VID_MASK))
- vlan_gro_receive(napi, adapter->vlgrp, tag, skb);
- else
- napi_gro_receive(napi, skb);
- } else {
- if (adapter->vlgrp && is_vlan && (tag & VLAN_VID_MASK))
- vlan_hwaccel_rx(skb, adapter->vlgrp, tag);
- else
- netif_rx(skb);
- }
+ if (is_vlan && (tag & VLAN_VID_MASK))
+ __vlan_hwaccel_put_tag(skb, tag);
+
+ if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL))
+ napi_gro_receive(napi, skb);
+ else
+ netif_rx(skb);
}
/**
@@ -981,7 +977,7 @@ static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
{
u32 status_err = le32_to_cpu(rx_desc->wb.upper.status_error);
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
/* Rx csum disabled */
if (!(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
@@ -1017,7 +1013,7 @@ static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
}
static inline void ixgbe_release_rx_desc(struct ixgbe_hw *hw,
- struct ixgbe_ring *rx_ring, u32 val)
+ struct ixgbe_ring *rx_ring, u32 val)
{
/*
* Force memory writes to complete before letting h/w
@@ -1033,25 +1029,27 @@ static inline void ixgbe_release_rx_desc(struct ixgbe_hw *hw,
* ixgbe_alloc_rx_buffers - Replace used receive buffers; packet split
* @adapter: address of board private structure
**/
-static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *rx_ring,
- int cleaned_count)
+void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rx_ring,
+ int cleaned_count)
{
+ struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
union ixgbe_adv_rx_desc *rx_desc;
struct ixgbe_rx_buffer *bi;
unsigned int i;
+ unsigned int bufsz = rx_ring->rx_buf_len;
i = rx_ring->next_to_use;
bi = &rx_ring->rx_buffer_info[i];
while (cleaned_count--) {
- rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+ rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
if (!bi->page_dma &&
(rx_ring->flags & IXGBE_RING_RX_PS_ENABLED)) {
if (!bi->page) {
- bi->page = alloc_page(GFP_ATOMIC);
+ bi->page = netdev_alloc_page(netdev);
if (!bi->page) {
adapter->alloc_rx_page_failed++;
goto no_buffers;
@@ -1063,29 +1061,28 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
}
bi->page_dma = dma_map_page(&pdev->dev, bi->page,
- bi->page_offset,
- (PAGE_SIZE / 2),
+ bi->page_offset,
+ (PAGE_SIZE / 2),
DMA_FROM_DEVICE);
}
if (!bi->skb) {
- struct sk_buff *skb;
- /* netdev_alloc_skb reserves 32 bytes up front!! */
- uint bufsz = rx_ring->rx_buf_len + SMP_CACHE_BYTES;
- skb = netdev_alloc_skb(adapter->netdev, bufsz);
+ struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev,
+ bufsz);
+ bi->skb = skb;
if (!skb) {
adapter->alloc_rx_buff_failed++;
goto no_buffers;
}
+ /* initialize queue mapping */
+ skb_record_rx_queue(skb, rx_ring->queue_index);
+ }
- /* advance the data pointer to the next cache line */
- skb_reserve(skb, (PTR_ALIGN(skb->data, SMP_CACHE_BYTES)
- - skb->data));
-
- bi->skb = skb;
- bi->dma = dma_map_single(&pdev->dev, skb->data,
- rx_ring->rx_buf_len,
+ if (!bi->dma) {
+ bi->dma = dma_map_single(&pdev->dev,
+ bi->skb->data,
+ rx_ring->rx_buf_len,
DMA_FROM_DEVICE);
}
/* Refresh the desc even if buffer_addrs didn't change because
@@ -1095,6 +1092,7 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
rx_desc->read.hdr_addr = cpu_to_le64(bi->dma);
} else {
rx_desc->read.pkt_addr = cpu_to_le64(bi->dma);
+ rx_desc->read.hdr_addr = 0;
}
i++;
@@ -1126,8 +1124,8 @@ static inline u16 ixgbe_get_pkt_info(union ixgbe_adv_rx_desc *rx_desc)
static inline u32 ixgbe_get_rsc_count(union ixgbe_adv_rx_desc *rx_desc)
{
return (le32_to_cpu(rx_desc->wb.lower.lo_dword.data) &
- IXGBE_RXDADV_RSCCNT_MASK) >>
- IXGBE_RXDADV_RSCCNT_SHIFT;
+ IXGBE_RXDADV_RSCCNT_MASK) >>
+ IXGBE_RXDADV_RSCCNT_SHIFT;
}
/**
@@ -1140,7 +1138,7 @@ static inline u32 ixgbe_get_rsc_count(union ixgbe_adv_rx_desc *rx_desc)
* turns it into the frag list owner.
**/
static inline struct sk_buff *ixgbe_transform_rsc_queue(struct sk_buff *skb,
- u64 *count)
+ u64 *count)
{
unsigned int frag_list_size = 0;
@@ -1168,11 +1166,10 @@ struct ixgbe_rsc_cb {
#define IXGBE_RSC_CB(skb) ((struct ixgbe_rsc_cb *)(skb)->cb)
static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- struct ixgbe_ring *rx_ring,
- int *work_done, int work_to_do)
+ struct ixgbe_ring *rx_ring,
+ int *work_done, int work_to_do)
{
struct ixgbe_adapter *adapter = q_vector->adapter;
- struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
union ixgbe_adv_rx_desc *rx_desc, *next_rxd;
struct ixgbe_rx_buffer *rx_buffer_info, *next_buffer;
@@ -1188,7 +1185,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
#endif /* IXGBE_FCOE */
i = rx_ring->next_to_clean;
- rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+ rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
rx_buffer_info = &rx_ring->rx_buffer_info[i];
@@ -1231,9 +1228,9 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
IXGBE_RSC_CB(skb)->dma = rx_buffer_info->dma;
} else {
dma_unmap_single(&pdev->dev,
- rx_buffer_info->dma,
- rx_ring->rx_buf_len,
- DMA_FROM_DEVICE);
+ rx_buffer_info->dma,
+ rx_ring->rx_buf_len,
+ DMA_FROM_DEVICE);
}
rx_buffer_info->dma = 0;
skb_put(skb, len);
@@ -1244,9 +1241,9 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
PAGE_SIZE / 2, DMA_FROM_DEVICE);
rx_buffer_info->page_dma = 0;
skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
- rx_buffer_info->page,
- rx_buffer_info->page_offset,
- upper_len);
+ rx_buffer_info->page,
+ rx_buffer_info->page_offset,
+ upper_len);
if ((rx_ring->rx_buf_len > (PAGE_SIZE / 2)) ||
(page_count(rx_buffer_info->page) != 1))
@@ -1263,7 +1260,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
if (i == rx_ring->count)
i = 0;
- next_rxd = IXGBE_RX_DESC_ADV(*rx_ring, i);
+ next_rxd = IXGBE_RX_DESC_ADV(rx_ring, i);
prefetch(next_rxd);
cleaned_count++;
@@ -1280,24 +1277,28 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
if (staterr & IXGBE_RXD_STAT_EOP) {
if (skb->prev)
- skb = ixgbe_transform_rsc_queue(skb, &(rx_ring->rsc_count));
+ skb = ixgbe_transform_rsc_queue(skb,
+ &(rx_ring->rsc_count));
if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
if (IXGBE_RSC_CB(skb)->delay_unmap) {
dma_unmap_single(&pdev->dev,
IXGBE_RSC_CB(skb)->dma,
- rx_ring->rx_buf_len,
+ rx_ring->rx_buf_len,
DMA_FROM_DEVICE);
IXGBE_RSC_CB(skb)->dma = 0;
IXGBE_RSC_CB(skb)->delay_unmap = false;
}
if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED)
- rx_ring->rsc_count += skb_shinfo(skb)->nr_frags;
+ rx_ring->rsc_count +=
+ skb_shinfo(skb)->nr_frags;
else
rx_ring->rsc_count++;
rx_ring->rsc_flush++;
}
+ u64_stats_update_begin(&rx_ring->syncp);
rx_ring->stats.packets++;
rx_ring->stats.bytes += skb->len;
+ u64_stats_update_end(&rx_ring->syncp);
} else {
if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED) {
rx_buffer_info->skb = next_buffer->skb;
@@ -1373,8 +1374,6 @@ next_desc:
rx_ring->total_packets += total_rx_packets;
rx_ring->total_bytes += total_rx_bytes;
- netdev->stats.rx_bytes += total_rx_bytes;
- netdev->stats.rx_packets += total_rx_packets;
return cleaned;
}
@@ -1403,24 +1402,24 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
q_vector = adapter->q_vector[v_idx];
/* XXX for_each_set_bit(...) */
r_idx = find_first_bit(q_vector->rxr_idx,
- adapter->num_rx_queues);
+ adapter->num_rx_queues);
for (i = 0; i < q_vector->rxr_count; i++) {
j = adapter->rx_ring[r_idx]->reg_idx;
ixgbe_set_ivar(adapter, 0, j, v_idx);
r_idx = find_next_bit(q_vector->rxr_idx,
- adapter->num_rx_queues,
- r_idx + 1);
+ adapter->num_rx_queues,
+ r_idx + 1);
}
r_idx = find_first_bit(q_vector->txr_idx,
- adapter->num_tx_queues);
+ adapter->num_tx_queues);
for (i = 0; i < q_vector->txr_count; i++) {
j = adapter->tx_ring[r_idx]->reg_idx;
ixgbe_set_ivar(adapter, 1, j, v_idx);
r_idx = find_next_bit(q_vector->txr_idx,
- adapter->num_tx_queues,
- r_idx + 1);
+ adapter->num_tx_queues,
+ r_idx + 1);
}
if (q_vector->txr_count && !q_vector->rxr_count)
@@ -1431,11 +1430,26 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
q_vector->eitr = adapter->rx_eitr_param;
ixgbe_write_eitr(q_vector);
+ /* If Flow Director is enabled, set interrupt affinity */
+ if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) ||
+ (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_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);
+ }
}
if (adapter->hw.mac.type == ixgbe_mac_82598EB)
ixgbe_set_ivar(adapter, -1, IXGBE_IVAR_OTHER_CAUSES_INDEX,
- v_idx);
+ v_idx);
else if (adapter->hw.mac.type == ixgbe_mac_82599EB)
ixgbe_set_ivar(adapter, -1, 1, v_idx);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx), 1950);
@@ -1477,8 +1491,8 @@ enum latency_range {
* parameter (see ixgbe_param.c)
**/
static u8 ixgbe_update_itr(struct ixgbe_adapter *adapter,
- u32 eitr, u8 itr_setting,
- int packets, int bytes)
+ u32 eitr, u8 itr_setting,
+ int packets, int bytes)
{
unsigned int retval = itr_setting;
u32 timepassed_us;
@@ -1567,30 +1581,30 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
for (i = 0; i < q_vector->txr_count; i++) {
tx_ring = adapter->tx_ring[r_idx];
ret_itr = ixgbe_update_itr(adapter, q_vector->eitr,
- q_vector->tx_itr,
- tx_ring->total_packets,
- tx_ring->total_bytes);
+ q_vector->tx_itr,
+ tx_ring->total_packets,
+ tx_ring->total_bytes);
/* if the result for this queue would decrease interrupt
* rate for this vector then use that result */
q_vector->tx_itr = ((q_vector->tx_itr > ret_itr) ?
- q_vector->tx_itr - 1 : ret_itr);
+ q_vector->tx_itr - 1 : ret_itr);
r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
- r_idx + 1);
+ r_idx + 1);
}
r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
for (i = 0; i < q_vector->rxr_count; i++) {
rx_ring = adapter->rx_ring[r_idx];
ret_itr = ixgbe_update_itr(adapter, q_vector->eitr,
- q_vector->rx_itr,
- rx_ring->total_packets,
- rx_ring->total_bytes);
+ q_vector->rx_itr,
+ rx_ring->total_packets,
+ rx_ring->total_bytes);
/* if the result for this queue would decrease interrupt
* rate for this vector then use that result */
q_vector->rx_itr = ((q_vector->rx_itr > ret_itr) ?
- q_vector->rx_itr - 1 : ret_itr);
+ q_vector->rx_itr - 1 : ret_itr);
r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
- r_idx + 1);
+ r_idx + 1);
}
current_itr = max(q_vector->rx_itr, q_vector->tx_itr);
@@ -1627,39 +1641,40 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
static void ixgbe_check_overtemp_task(struct work_struct *work)
{
struct ixgbe_adapter *adapter = container_of(work,
- struct ixgbe_adapter,
- check_overtemp_task);
+ struct ixgbe_adapter,
+ check_overtemp_task);
struct ixgbe_hw *hw = &adapter->hw;
u32 eicr = adapter->interrupt_event;
- if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) {
- switch (hw->device_id) {
- case IXGBE_DEV_ID_82599_T3_LOM: {
- u32 autoneg;
- bool link_up = false;
+ if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE))
+ return;
- if (hw->mac.ops.check_link)
- hw->mac.ops.check_link(hw, &autoneg, &link_up, false);
+ switch (hw->device_id) {
+ case IXGBE_DEV_ID_82599_T3_LOM: {
+ u32 autoneg;
+ bool link_up = false;
- if (((eicr & IXGBE_EICR_GPI_SDP0) && (!link_up)) ||
- (eicr & IXGBE_EICR_LSC))
- /* Check if this is due to overtemp */
- if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP)
- break;
- }
+ if (hw->mac.ops.check_link)
+ hw->mac.ops.check_link(hw, &autoneg, &link_up, false);
+
+ if (((eicr & IXGBE_EICR_GPI_SDP0) && (!link_up)) ||
+ (eicr & IXGBE_EICR_LSC))
+ /* Check if this is due to overtemp */
+ if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP)
+ break;
+ return;
+ }
+ default:
+ if (!(eicr & IXGBE_EICR_GPI_SDP0))
return;
- default:
- if (!(eicr & IXGBE_EICR_GPI_SDP0))
- return;
- break;
- }
- 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");
- /* write to clear the interrupt */
- IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0);
+ break;
}
+ 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");
+ /* write to clear the interrupt */
+ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0);
}
static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr)
@@ -1746,9 +1761,9 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
netif_tx_stop_all_queues(netdev);
for (i = 0; i < adapter->num_tx_queues; i++) {
struct ixgbe_ring *tx_ring =
- adapter->tx_ring[i];
+ adapter->tx_ring[i];
if (test_and_clear_bit(__IXGBE_FDIR_INIT_DONE,
- &tx_ring->reinit_state))
+ &tx_ring->reinit_state))
schedule_work(&adapter->fdir_reinit_task);
}
}
@@ -1777,7 +1792,7 @@ static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter,
}
static inline void ixgbe_irq_disable_queues(struct ixgbe_adapter *adapter,
- u64 qmask)
+ u64 qmask)
{
u32 mask;
@@ -1809,7 +1824,7 @@ static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data)
tx_ring->total_bytes = 0;
tx_ring->total_packets = 0;
r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
- r_idx + 1);
+ r_idx + 1);
}
/* EIAM disabled interrupts (on this vector) for us */
@@ -1837,7 +1852,7 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data)
rx_ring->total_bytes = 0;
rx_ring->total_packets = 0;
r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
- r_idx + 1);
+ r_idx + 1);
}
if (!q_vector->rxr_count)
@@ -1867,7 +1882,7 @@ static irqreturn_t ixgbe_msix_clean_many(int irq, void *data)
ring->total_bytes = 0;
ring->total_packets = 0;
r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
- r_idx + 1);
+ r_idx + 1);
}
r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
@@ -1876,7 +1891,7 @@ static irqreturn_t ixgbe_msix_clean_many(int irq, void *data)
ring->total_bytes = 0;
ring->total_packets = 0;
r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
- r_idx + 1);
+ r_idx + 1);
}
/* EIAM disabled interrupts (on this vector) for us */
@@ -1896,7 +1911,7 @@ static irqreturn_t ixgbe_msix_clean_many(int irq, void *data)
static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
{
struct ixgbe_q_vector *q_vector =
- container_of(napi, struct ixgbe_q_vector, napi);
+ 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;
@@ -1918,7 +1933,7 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
ixgbe_set_itr_msix(q_vector);
if (!test_bit(__IXGBE_DOWN, &adapter->state))
ixgbe_irq_enable_queues(adapter,
- ((u64)1 << q_vector->v_idx));
+ ((u64)1 << q_vector->v_idx));
}
return work_done;
@@ -1935,7 +1950,7 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
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);
+ 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;
@@ -1951,7 +1966,7 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
#endif
tx_clean_complete &= ixgbe_clean_tx_irq(q_vector, ring);
r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
- r_idx + 1);
+ r_idx + 1);
}
/* attempt to distribute budget to each queue fairly, but don't allow
@@ -1967,7 +1982,7 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
#endif
ixgbe_clean_rx_irq(q_vector, ring, &work_done, budget);
r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
- r_idx + 1);
+ r_idx + 1);
}
r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
@@ -1979,7 +1994,7 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
ixgbe_set_itr_msix(q_vector);
if (!test_bit(__IXGBE_DOWN, &adapter->state))
ixgbe_irq_enable_queues(adapter,
- ((u64)1 << q_vector->v_idx));
+ ((u64)1 << q_vector->v_idx));
return 0;
}
@@ -1997,7 +2012,7 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
static int ixgbe_clean_txonly(struct napi_struct *napi, int budget)
{
struct ixgbe_q_vector *q_vector =
- container_of(napi, struct ixgbe_q_vector, napi);
+ 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;
@@ -2019,14 +2034,15 @@ static int ixgbe_clean_txonly(struct napi_struct *napi, int budget)
if (adapter->tx_itr_setting & 1)
ixgbe_set_itr_msix(q_vector);
if (!test_bit(__IXGBE_DOWN, &adapter->state))
- ixgbe_irq_enable_queues(adapter, ((u64)1 << q_vector->v_idx));
+ ixgbe_irq_enable_queues(adapter,
+ ((u64)1 << q_vector->v_idx));
}
return work_done;
}
static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx,
- int r_idx)
+ int r_idx)
{
struct ixgbe_q_vector *q_vector = a->q_vector[v_idx];
@@ -2035,7 +2051,7 @@ static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx,
}
static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx,
- int t_idx)
+ int t_idx)
{
struct ixgbe_q_vector *q_vector = a->q_vector[v_idx];
@@ -2055,7 +2071,7 @@ static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx,
* mapping configurations in here.
**/
static int ixgbe_map_rings_to_vectors(struct ixgbe_adapter *adapter,
- int vectors)
+ int vectors)
{
int v_start = 0;
int rxr_idx = 0, txr_idx = 0;
@@ -2122,7 +2138,7 @@ 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 ri=0, ti=0;
+ int ri = 0, ti = 0;
/* Decrement for Other and TCP Timer vectors */
q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
@@ -2133,26 +2149,24 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
goto out;
#define SET_HANDLER(_v) ((!(_v)->rxr_count) ? &ixgbe_msix_clean_tx : \
- (!(_v)->txr_count) ? &ixgbe_msix_clean_rx : \
- &ixgbe_msix_clean_many)
+ (!(_v)->txr_count) ? &ixgbe_msix_clean_rx : \
+ &ixgbe_msix_clean_many)
for (vector = 0; vector < q_vectors; vector++) {
handler = SET_HANDLER(adapter->q_vector[vector]);
- if(handler == &ixgbe_msix_clean_rx) {
+ if (handler == &ixgbe_msix_clean_rx) {
sprintf(adapter->name[vector], "%s-%s-%d",
netdev->name, "rx", ri++);
- }
- else if(handler == &ixgbe_msix_clean_tx) {
+ } else if (handler == &ixgbe_msix_clean_tx) {
sprintf(adapter->name[vector], "%s-%s-%d",
netdev->name, "tx", ti++);
- }
- else
+ } else
sprintf(adapter->name[vector], "%s-%s-%d",
netdev->name, "TxRx", vector);
err = request_irq(adapter->msix_entries[vector].vector,
- handler, 0, adapter->name[vector],
- adapter->q_vector[vector]);
+ handler, 0, adapter->name[vector],
+ adapter->q_vector[vector]);
if (err) {
e_err(probe, "request_irq failed for MSIX interrupt "
"Error: %d\n", err);
@@ -2162,7 +2176,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
sprintf(adapter->name[vector], "%s:lsc", netdev->name);
err = request_irq(adapter->msix_entries[vector].vector,
- ixgbe_msix_lsc, 0, adapter->name[vector], netdev);
+ ixgbe_msix_lsc, 0, adapter->name[vector], netdev);
if (err) {
e_err(probe, "request_irq for msix_lsc failed: %d\n", err);
goto free_queue_irqs;
@@ -2173,7 +2187,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
free_queue_irqs:
for (i = vector - 1; i >= 0; i--)
free_irq(adapter->msix_entries[--vector].vector,
- adapter->q_vector[i]);
+ adapter->q_vector[i]);
adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
pci_disable_msix(adapter->pdev);
kfree(adapter->msix_entries);
@@ -2191,13 +2205,13 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter)
struct ixgbe_ring *tx_ring = adapter->tx_ring[0];
q_vector->tx_itr = ixgbe_update_itr(adapter, new_itr,
- q_vector->tx_itr,
- tx_ring->total_packets,
- tx_ring->total_bytes);
+ q_vector->tx_itr,
+ tx_ring->total_packets,
+ tx_ring->total_bytes);
q_vector->rx_itr = ixgbe_update_itr(adapter, new_itr,
- q_vector->rx_itr,
- rx_ring->total_packets,
- rx_ring->total_bytes);
+ q_vector->rx_itr,
+ rx_ring->total_packets,
+ rx_ring->total_bytes);
current_itr = max(q_vector->rx_itr, q_vector->tx_itr);
@@ -2231,7 +2245,8 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter)
* ixgbe_irq_enable - Enable default interrupt generation settings
* @adapter: board private structure
**/
-static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
+static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter, bool queues,
+ bool flush)
{
u32 mask;
@@ -2252,8 +2267,10 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
mask |= IXGBE_EIMS_FLOW_DIR;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
- ixgbe_irq_enable_queues(adapter, ~0);
- IXGBE_WRITE_FLUSH(&adapter->hw);
+ 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;
@@ -2275,7 +2292,7 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
u32 eicr;
/*
- * Workaround for silicon errata. Mask the interrupts
+ * Workaround for silicon errata on 82598. Mask the interrupts
* before the read of EICR.
*/
IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK);
@@ -2284,10 +2301,15 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
* therefore no explict interrupt disable is necessary */
eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
if (!eicr) {
- /* shared interrupt alert!
+ /*
+ * shared interrupt alert!
* make sure interrupts are enabled because the read will
- * have disabled interrupts due to EIAM */
- ixgbe_irq_enable(adapter);
+ * have disabled interrupts due to EIAM
+ * finish the workaround of silicon errata on 82598. Unmask
+ * the interrupt that we masked before the EICR read.
+ */
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ ixgbe_irq_enable(adapter, true, true);
return IRQ_NONE; /* Not our interrupt */
}
@@ -2311,6 +2333,14 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
__napi_schedule(&(q_vector->napi));
}
+ /*
+ * re-enable link(maybe) and non-queue interrupts, no flush.
+ * ixgbe_poll will re-enable the queue interrupts
+ */
+
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ ixgbe_irq_enable(adapter, false, false);
+
return IRQ_HANDLED;
}
@@ -2343,10 +2373,10 @@ static int ixgbe_request_irq(struct ixgbe_adapter *adapter)
err = ixgbe_request_msix_irqs(adapter);
} else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) {
err = request_irq(adapter->pdev->irq, ixgbe_intr, 0,
- netdev->name, netdev);
+ netdev->name, netdev);
} else {
err = request_irq(adapter->pdev->irq, ixgbe_intr, IRQF_SHARED,
- netdev->name, netdev);
+ netdev->name, netdev);
}
if (err)
@@ -2370,7 +2400,7 @@ static void ixgbe_free_irq(struct ixgbe_adapter *adapter)
i--;
for (; i >= 0; i--) {
free_irq(adapter->msix_entries[i].vector,
- adapter->q_vector[i]);
+ adapter->q_vector[i]);
}
ixgbe_reset_q_vectors(adapter);
@@ -2413,7 +2443,7 @@ static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter)
struct ixgbe_hw *hw = &adapter->hw;
IXGBE_WRITE_REG(hw, IXGBE_EITR(0),
- EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr_param));
+ EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr_param));
ixgbe_set_ivar(adapter, 0, 0, 0);
ixgbe_set_ivar(adapter, 1, 0, 0);
@@ -2425,95 +2455,140 @@ static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter)
}
/**
- * ixgbe_configure_tx - Configure 8259x Transmit Unit after Reset
+ * ixgbe_configure_tx_ring - Configure 8259x Tx ring after Reset
* @adapter: board private structure
+ * @ring: structure containing ring specific data
*
- * Configure the Tx unit of the MAC after a reset.
+ * Configure the Tx descriptor ring after a reset.
**/
-static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
+void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *ring)
{
- u64 tdba;
struct ixgbe_hw *hw = &adapter->hw;
- u32 i, j, tdlen, txctrl;
+ u64 tdba = ring->dma;
+ int wait_loop = 10;
+ u32 txdctl;
+ u16 reg_idx = ring->reg_idx;
- /* Setup the HW Tx Head and Tail descriptor pointers */
- for (i = 0; i < adapter->num_tx_queues; i++) {
- struct ixgbe_ring *ring = adapter->tx_ring[i];
- j = ring->reg_idx;
- tdba = ring->dma;
- tdlen = ring->count * sizeof(union ixgbe_adv_tx_desc);
- IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j),
- (tdba & DMA_BIT_MASK(32)));
- IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32));
- IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), tdlen);
- IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0);
- IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0);
- adapter->tx_ring[i]->head = IXGBE_TDH(j);
- adapter->tx_ring[i]->tail = IXGBE_TDT(j);
- /*
- * Disable Tx Head Writeback RO bit, since this hoses
- * bookkeeping if things aren't delivered in order.
- */
- switch (hw->mac.type) {
- case ixgbe_mac_82598EB:
- txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j));
- break;
- case ixgbe_mac_82599EB:
- default:
- txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(j));
- break;
- }
- txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
- switch (hw->mac.type) {
- case ixgbe_mac_82598EB:
- IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl);
- break;
- case ixgbe_mac_82599EB:
- default:
- IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(j), txctrl);
- break;
- }
+ /* 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_FLUSH(hw);
+
+ IXGBE_WRITE_REG(hw, IXGBE_TDBAL(reg_idx),
+ (tdba & DMA_BIT_MASK(32)));
+ IXGBE_WRITE_REG(hw, IXGBE_TDBAH(reg_idx), (tdba >> 32));
+ IXGBE_WRITE_REG(hw, IXGBE_TDLEN(reg_idx),
+ ring->count * sizeof(union ixgbe_adv_tx_desc));
+ IXGBE_WRITE_REG(hw, IXGBE_TDH(reg_idx), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_TDT(reg_idx), 0);
+ ring->head = IXGBE_TDH(reg_idx);
+ ring->tail = 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;
}
- if (hw->mac.type == ixgbe_mac_82599EB) {
- u32 rttdcs;
- u32 mask;
+ /* reinitialize flowdirector state */
+ set_bit(__IXGBE_FDIR_INIT_DONE, &ring->reinit_state);
- /* disable the arbiter while setting MTQC */
- rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
- rttdcs |= IXGBE_RTTDCS_ARBDIS;
- IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
+ /* enable queue */
+ txdctl |= IXGBE_TXDCTL_ENABLE;
+ IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
- /* set transmit pool layout */
- mask = (IXGBE_FLAG_SRIOV_ENABLED | IXGBE_FLAG_DCB_ENABLED);
- switch (adapter->flags & mask) {
+ /* TXDCTL.EN will return 0 on 82598 if link is down, so skip it */
+ if (hw->mac.type == ixgbe_mac_82598EB &&
+ !(IXGBE_READ_REG(hw, IXGBE_LINKS) & IXGBE_LINKS_UP))
+ return;
- case (IXGBE_FLAG_SRIOV_ENABLED):
- IXGBE_WRITE_REG(hw, IXGBE_MTQC,
- (IXGBE_MTQC_VT_ENA | IXGBE_MTQC_64VF));
- break;
+ /* poll to verify queue is enabled */
+ do {
+ msleep(1);
+ txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
+ } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
+ if (!wait_loop)
+ e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+}
- case (IXGBE_FLAG_DCB_ENABLED):
- /* We enable 8 traffic classes, DCB only */
- IXGBE_WRITE_REG(hw, IXGBE_MTQC,
- (IXGBE_MTQC_RT_ENA | IXGBE_MTQC_8TC_8TQ));
- break;
+static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 rttdcs;
+ u32 mask;
- default:
- IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB);
- break;
- }
+ if (hw->mac.type == ixgbe_mac_82598EB)
+ return;
+
+ /* disable the arbiter while setting MTQC */
+ rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
+ rttdcs |= IXGBE_RTTDCS_ARBDIS;
+ IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
+
+ /* set transmit pool layout */
+ mask = (IXGBE_FLAG_SRIOV_ENABLED | IXGBE_FLAG_DCB_ENABLED);
+ switch (adapter->flags & mask) {
+
+ case (IXGBE_FLAG_SRIOV_ENABLED):
+ IXGBE_WRITE_REG(hw, IXGBE_MTQC,
+ (IXGBE_MTQC_VT_ENA | IXGBE_MTQC_64VF));
+ break;
+
+ case (IXGBE_FLAG_DCB_ENABLED):
+ /* We enable 8 traffic classes, DCB only */
+ IXGBE_WRITE_REG(hw, IXGBE_MTQC,
+ (IXGBE_MTQC_RT_ENA | IXGBE_MTQC_8TC_8TQ));
+ break;
+
+ default:
+ IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB);
+ break;
+ }
+
+ /* re-enable the arbiter */
+ rttdcs &= ~IXGBE_RTTDCS_ARBDIS;
+ IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
+}
- /* re-eable the arbiter */
- rttdcs &= ~IXGBE_RTTDCS_ARBDIS;
- IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
+/**
+ * ixgbe_configure_tx - Configure 8259x Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 dmatxctl;
+ u32 i;
+
+ ixgbe_setup_mtqc(adapter);
+
+ if (hw->mac.type != ixgbe_mac_82598EB) {
+ /* DMATXCTL.EN must be before Tx queues are enabled */
+ dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
+ dmatxctl |= IXGBE_DMATXCTL_TE;
+ IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl);
}
+
+ /* Setup the HW Tx Head and Tail descriptor pointers */
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ ixgbe_configure_tx_ring(adapter, adapter->tx_ring[i]);
}
#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2
static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *rx_ring)
+ struct ixgbe_ring *rx_ring)
{
u32 srrctl;
int index;
@@ -2529,6 +2604,8 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter,
srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK;
srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK;
+ if (adapter->num_vfs)
+ srrctl |= IXGBE_SRRCTL_DROP_EN;
srrctl |= (IXGBE_RX_HDR_SIZE << IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
IXGBE_SRRCTL_BSIZEHDR_MASK;
@@ -2549,20 +2626,46 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter,
IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(index), srrctl);
}
-static u32 ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
+static void ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
{
- u32 mrqc = 0;
+ struct ixgbe_hw *hw = &adapter->hw;
+ static const u32 seed[10] = { 0xE291D73D, 0x1805EC6C, 0x2A94B30D,
+ 0xA54F2BEC, 0xEA49AF7C, 0xE214AD3D, 0xB855AABE,
+ 0x6A3E67EA, 0x14364D17, 0x3BED200D};
+ u32 mrqc = 0, reta = 0;
+ u32 rxcsum;
+ int i, j;
int mask;
- if (!(adapter->hw.mac.type == ixgbe_mac_82599EB))
- return mrqc;
+ /* Fill out hash function seeds */
+ for (i = 0; i < 10; i++)
+ IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), seed[i]);
- mask = adapter->flags & (IXGBE_FLAG_RSS_ENABLED
+ /* Fill out redirection table */
+ for (i = 0, j = 0; i < 128; i++, j++) {
+ if (j == adapter->ring_feature[RING_F_RSS].indices)
+ j = 0;
+ /* reta = 4-byte sliding window of
+ * 0x00..(indices-1)(indices-1)00..etc. */
+ reta = (reta << 8) | (j * 0x11);
+ if ((i & 3) == 3)
+ IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
+ }
+
+ /* Disable indicating checksum in descriptor, enables RSS hash */
+ rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
+ rxcsum |= IXGBE_RXCSUM_PCSD;
+ IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
+
+ if (adapter->hw.mac.type == ixgbe_mac_82598EB)
+ mask = adapter->flags & IXGBE_FLAG_RSS_ENABLED;
+ else
+ mask = adapter->flags & (IXGBE_FLAG_RSS_ENABLED
#ifdef CONFIG_IXGBE_DCB
- | IXGBE_FLAG_DCB_ENABLED
+ | IXGBE_FLAG_DCB_ENABLED
#endif
- | IXGBE_FLAG_SRIOV_ENABLED
- );
+ | IXGBE_FLAG_SRIOV_ENABLED
+ );
switch (mask) {
case (IXGBE_FLAG_RSS_ENABLED):
@@ -2580,7 +2683,13 @@ static u32 ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
break;
}
- return mrqc;
+ /* Perform hash on these packet types */
+ mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4
+ | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
+ | IXGBE_MRQC_RSS_FIELD_IPV6
+ | IXGBE_MRQC_RSS_FIELD_IPV6_TCP;
+
+ IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
}
/**
@@ -2588,25 +2697,26 @@ static u32 ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
* @adapter: address of board private structure
* @index: index of ring to set
**/
-static void ixgbe_configure_rscctl(struct ixgbe_adapter *adapter, int index)
+static void ixgbe_configure_rscctl(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *ring)
{
- struct ixgbe_ring *rx_ring;
struct ixgbe_hw *hw = &adapter->hw;
- int j;
u32 rscctrl;
int rx_buf_len;
+ u16 reg_idx = ring->reg_idx;
+
+ if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))
+ return;
- rx_ring = adapter->rx_ring[index];
- j = rx_ring->reg_idx;
- rx_buf_len = rx_ring->rx_buf_len;
- rscctrl = IXGBE_READ_REG(hw, IXGBE_RSCCTL(j));
+ rx_buf_len = ring->rx_buf_len;
+ rscctrl = IXGBE_READ_REG(hw, IXGBE_RSCCTL(reg_idx));
rscctrl |= IXGBE_RSCCTL_RSCEN;
/*
* we must limit the number of descriptors so that the
* total size of max desc * buf_len is not greater
* than 65535
*/
- if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED) {
+ if (ring->flags & IXGBE_RING_RX_PS_ENABLED) {
#if (MAX_SKB_FRAGS > 16)
rscctrl |= IXGBE_RSCCTL_MAXDESC_16;
#elif (MAX_SKB_FRAGS > 8)
@@ -2624,31 +2734,181 @@ static void ixgbe_configure_rscctl(struct ixgbe_adapter *adapter, int index)
else
rscctrl |= IXGBE_RSCCTL_MAXDESC_4;
}
- IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(j), rscctrl);
+ IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(reg_idx), rscctrl);
}
/**
- * ixgbe_configure_rx - Configure 8259x Receive Unit after Reset
- * @adapter: board private structure
+ * ixgbe_set_uta - Set unicast filter table address
+ * @adapter: board private structure
*
- * Configure the Rx unit of the MAC after a reset.
+ * The unicast table address is a register array of 32-bit registers.
+ * The table is meant to be used in a way similar to how the MTA is used
+ * however due to certain limitations in the hardware it is necessary to
+ * set all the hash bits to 1 and use the VMOLR ROPE bit as a promiscuous
+ * enable bit to allow vlan tag stripping when promiscuous mode is enabled
**/
-static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
+static void ixgbe_set_uta(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ int i;
+
+ /* The UTA table only exists on 82599 hardware and newer */
+ if (hw->mac.type < ixgbe_mac_82599EB)
+ return;
+
+ /* we only need to do this if VMDq is enabled */
+ if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
+ return;
+
+ for (i = 0; i < 128; i++)
+ IXGBE_WRITE_REG(hw, IXGBE_UTA(i), ~0);
+}
+
+#define IXGBE_MAX_RX_DESC_POLL 10
+static void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *ring)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ int reg_idx = ring->reg_idx;
+ int wait_loop = IXGBE_MAX_RX_DESC_POLL;
+ u32 rxdctl;
+
+ /* RXDCTL.EN will return 0 on 82598 if link is down, so skip it */
+ if (hw->mac.type == ixgbe_mac_82598EB &&
+ !(IXGBE_READ_REG(hw, IXGBE_LINKS) & IXGBE_LINKS_UP))
+ return;
+
+ do {
+ msleep(1);
+ rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
+ } while (--wait_loop && !(rxdctl & IXGBE_RXDCTL_ENABLE));
+
+ if (!wait_loop) {
+ e_err(drv, "RXDCTL.ENABLE on Rx queue %d not set within "
+ "the polling period\n", reg_idx);
+ }
+}
+
+void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *ring)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u64 rdba = ring->dma;
+ u32 rxdctl;
+ u16 reg_idx = ring->reg_idx;
+
+ /* disable queue to avoid issues while updating state */
+ rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
+ IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx),
+ rxdctl & ~IXGBE_RXDCTL_ENABLE);
+ IXGBE_WRITE_FLUSH(hw);
+
+ IXGBE_WRITE_REG(hw, IXGBE_RDBAL(reg_idx), (rdba & DMA_BIT_MASK(32)));
+ IXGBE_WRITE_REG(hw, IXGBE_RDBAH(reg_idx), (rdba >> 32));
+ IXGBE_WRITE_REG(hw, IXGBE_RDLEN(reg_idx),
+ ring->count * sizeof(union ixgbe_adv_rx_desc));
+ IXGBE_WRITE_REG(hw, IXGBE_RDH(reg_idx), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_RDT(reg_idx), 0);
+ ring->head = IXGBE_RDH(reg_idx);
+ ring->tail = IXGBE_RDT(reg_idx);
+
+ ixgbe_configure_srrctl(adapter, ring);
+ ixgbe_configure_rscctl(adapter, ring);
+
+ if (hw->mac.type == ixgbe_mac_82598EB) {
+ /*
+ * enable cache line friendly hardware writes:
+ * PTHRESH=32 descriptors (half the internal cache),
+ * this also removes ugly rx_no_buffer_count increment
+ * HTHRESH=4 descriptors (to minimize latency on fetch)
+ * WTHRESH=8 burst writeback up to two cache lines
+ */
+ rxdctl &= ~0x3FFFFF;
+ rxdctl |= 0x080420;
+ }
+
+ /* enable receive descriptor ring */
+ rxdctl |= IXGBE_RXDCTL_ENABLE;
+ IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+
+ ixgbe_rx_desc_queue_enable(adapter, ring);
+ ixgbe_alloc_rx_buffers(adapter, ring, IXGBE_DESC_UNUSED(ring));
+}
+
+static void ixgbe_setup_psrtype(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ int p;
+
+ /* PSRTYPE must be initialized in non 82598 adapters */
+ u32 psrtype = IXGBE_PSRTYPE_TCPHDR |
+ IXGBE_PSRTYPE_UDPHDR |
+ IXGBE_PSRTYPE_IPV4HDR |
+ IXGBE_PSRTYPE_L2HDR |
+ IXGBE_PSRTYPE_IPV6HDR;
+
+ if (hw->mac.type == ixgbe_mac_82598EB)
+ return;
+
+ if (adapter->flags & IXGBE_FLAG_RSS_ENABLED)
+ psrtype |= (adapter->num_rx_queues_per_pool << 29);
+
+ for (p = 0; p < adapter->num_rx_pools; p++)
+ IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(adapter->num_vfs + p),
+ psrtype);
+}
+
+static void ixgbe_configure_virtualization(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 gcr_ext;
+ u32 vt_reg_bits;
+ u32 reg_offset, vf_shift;
+ u32 vmdctl;
+
+ if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
+ return;
+
+ vmdctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
+ vt_reg_bits = IXGBE_VMD_CTL_VMDQ_EN | IXGBE_VT_CTL_REPLEN;
+ vt_reg_bits |= (adapter->num_vfs << IXGBE_VT_CTL_POOL_SHIFT);
+ IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vmdctl | vt_reg_bits);
+
+ vf_shift = adapter->num_vfs % 32;
+ reg_offset = (adapter->num_vfs > 32) ? 1 : 0;
+
+ /* Enable only the PF's pool for Tx/Rx */
+ IXGBE_WRITE_REG(hw, IXGBE_VFRE(reg_offset), (1 << vf_shift));
+ IXGBE_WRITE_REG(hw, IXGBE_VFRE(reg_offset ^ 1), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset), (1 << vf_shift));
+ IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset ^ 1), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
+
+ /* Map PF MAC address in RAR Entry 0 to first pool following VFs */
+ hw->mac.ops.set_vmdq(hw, 0, adapter->num_vfs);
+
+ /*
+ * Set up VF register offsets for selected VT Mode,
+ * i.e. 32 or 64 VFs for SR-IOV
+ */
+ gcr_ext = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
+ gcr_ext |= IXGBE_GCR_EXT_MSIX_EN;
+ gcr_ext |= IXGBE_GCR_EXT_VT_MODE_64;
+ IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext);
+
+ /* enable Tx loopback for VF/PF communication */
+ IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
+}
+
+static void ixgbe_set_rx_buffer_len(struct ixgbe_adapter *adapter)
{
- u64 rdba;
struct ixgbe_hw *hw = &adapter->hw;
- struct ixgbe_ring *rx_ring;
struct net_device *netdev = adapter->netdev;
int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
- int i, j;
- u32 rdlen, rxctrl, rxcsum;
- static const u32 seed[10] = { 0xE291D73D, 0x1805EC6C, 0x2A94B30D,
- 0xA54F2BEC, 0xEA49AF7C, 0xE214AD3D, 0xB855AABE,
- 0x6A3E67EA, 0x14364D17, 0x3BED200D};
- u32 fctrl, hlreg0;
- u32 reta = 0, mrqc = 0;
- u32 rdrxctl;
int rx_buf_len;
+ struct ixgbe_ring *rx_ring;
+ int i;
+ u32 mhadd, hlreg0;
/* Decide whether to use packet split mode or not */
/* Do not use packet split if we're in SR-IOV Mode */
@@ -2658,62 +2918,40 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
/* Set the RX buffer length according to the mode */
if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
rx_buf_len = IXGBE_RX_HDR_SIZE;
- if (hw->mac.type == ixgbe_mac_82599EB) {
- /* PSRTYPE must be initialized in 82599 */
- u32 psrtype = IXGBE_PSRTYPE_TCPHDR |
- IXGBE_PSRTYPE_UDPHDR |
- IXGBE_PSRTYPE_IPV4HDR |
- IXGBE_PSRTYPE_IPV6HDR |
- IXGBE_PSRTYPE_L2HDR;
- IXGBE_WRITE_REG(hw,
- IXGBE_PSRTYPE(adapter->num_vfs),
- psrtype);
- }
} 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, 1024);
+ rx_buf_len = ALIGN(max_frame + VLAN_HLEN, 1024);
}
- fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
- fctrl |= IXGBE_FCTRL_BAM;
- fctrl |= IXGBE_FCTRL_DPF; /* discard pause frames when FC enabled */
- fctrl |= IXGBE_FCTRL_PMCF;
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl);
+#ifdef IXGBE_FCOE
+ /* adjust max frame to be able to do baby jumbo for FCoE */
+ if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) &&
+ (max_frame < IXGBE_FCOE_JUMBO_FRAME_SIZE))
+ max_frame = IXGBE_FCOE_JUMBO_FRAME_SIZE;
+
+#endif /* IXGBE_FCOE */
+ mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
+ if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) {
+ mhadd &= ~IXGBE_MHADD_MFS_MASK;
+ mhadd |= max_frame << IXGBE_MHADD_MFS_SHIFT;
+
+ IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd);
+ }
hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
- if (adapter->netdev->mtu <= ETH_DATA_LEN)
- hlreg0 &= ~IXGBE_HLREG0_JUMBOEN;
- else
- hlreg0 |= IXGBE_HLREG0_JUMBOEN;
-#ifdef IXGBE_FCOE
- if (netdev->features & NETIF_F_FCOE_MTU)
- hlreg0 |= IXGBE_HLREG0_JUMBOEN;
-#endif
+ /* set jumbo enable since MHADD.MFS is keeping size locked at max_frame */
+ hlreg0 |= IXGBE_HLREG0_JUMBOEN;
IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
- rdlen = adapter->rx_ring[0]->count * sizeof(union ixgbe_adv_rx_desc);
- /* disable receives while setting up the descriptors */
- rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
- IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
-
/*
* Setup the HW Rx Head and Tail Descriptor Pointers and
* the Base and Length of the Rx Descriptor Ring
*/
for (i = 0; i < adapter->num_rx_queues; i++) {
rx_ring = adapter->rx_ring[i];
- rdba = rx_ring->dma;
- j = rx_ring->reg_idx;
- IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j), (rdba & DMA_BIT_MASK(32)));
- IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32));
- IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j), rdlen);
- IXGBE_WRITE_REG(hw, IXGBE_RDH(j), 0);
- IXGBE_WRITE_REG(hw, IXGBE_RDT(j), 0);
- rx_ring->head = IXGBE_RDH(j);
- rx_ring->tail = IXGBE_RDT(j);
rx_ring->rx_buf_len = rx_buf_len;
if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)
@@ -2729,15 +2967,21 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
rx_ring->flags &= ~IXGBE_RING_RX_PS_ENABLED;
if (rx_buf_len < IXGBE_FCOE_JUMBO_FRAME_SIZE)
rx_ring->rx_buf_len =
- IXGBE_FCOE_JUMBO_FRAME_SIZE;
+ IXGBE_FCOE_JUMBO_FRAME_SIZE;
}
}
-
#endif /* IXGBE_FCOE */
- ixgbe_configure_srrctl(adapter, rx_ring);
}
- if (hw->mac.type == ixgbe_mac_82598EB) {
+}
+
+static void ixgbe_setup_rdrxctl(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
+
+ switch (hw->mac.type) {
+ case ixgbe_mac_82598EB:
/*
* For VMDq support of different descriptor types or
* buffer sizes through the use of multiple SRRCTL
@@ -2748,110 +2992,66 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
* effects of setting this bit are only that SRRCTL must be
* fully programmed [0..15]
*/
- rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
rdrxctl |= IXGBE_RDRXCTL_MVMEN;
- IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
+ break;
+ case ixgbe_mac_82599EB:
+ /* Disable RSC for ACK packets */
+ IXGBE_WRITE_REG(hw, IXGBE_RSCDBU,
+ (IXGBE_RSCDBU_RSCACKDIS | IXGBE_READ_REG(hw, IXGBE_RSCDBU)));
+ rdrxctl &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;
+ /* hardware requires some bits to be set by default */
+ rdrxctl |= (IXGBE_RDRXCTL_RSCACKC | IXGBE_RDRXCTL_FCOE_WRFIX);
+ rdrxctl |= IXGBE_RDRXCTL_CRCSTRIP;
+ break;
+ default:
+ /* We should do nothing since we don't know this hardware */
+ return;
}
- if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
- u32 vt_reg_bits;
- u32 reg_offset, vf_shift;
- u32 vmdctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
- vt_reg_bits = IXGBE_VMD_CTL_VMDQ_EN
- | IXGBE_VT_CTL_REPLEN;
- vt_reg_bits |= (adapter->num_vfs <<
- IXGBE_VT_CTL_POOL_SHIFT);
- IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vmdctl | vt_reg_bits);
- IXGBE_WRITE_REG(hw, IXGBE_MRQC, 0);
-
- vf_shift = adapter->num_vfs % 32;
- reg_offset = adapter->num_vfs / 32;
- IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), 0);
- IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), 0);
- IXGBE_WRITE_REG(hw, IXGBE_VFTE(0), 0);
- IXGBE_WRITE_REG(hw, IXGBE_VFTE(1), 0);
- /* Enable only the PF's pool for Tx/Rx */
- IXGBE_WRITE_REG(hw, IXGBE_VFRE(reg_offset), (1 << vf_shift));
- IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset), (1 << vf_shift));
- IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
- ixgbe_set_vmolr(hw, adapter->num_vfs, true);
- }
-
- /* Program MRQC for the distribution of queues */
- mrqc = ixgbe_setup_mrqc(adapter);
-
- if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
- /* Fill out redirection table */
- for (i = 0, j = 0; i < 128; i++, j++) {
- if (j == adapter->ring_feature[RING_F_RSS].indices)
- j = 0;
- /* reta = 4-byte sliding window of
- * 0x00..(indices-1)(indices-1)00..etc. */
- reta = (reta << 8) | (j * 0x11);
- if ((i & 3) == 3)
- IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
- }
-
- /* Fill out hash function seeds */
- for (i = 0; i < 10; i++)
- IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), seed[i]);
-
- if (hw->mac.type == ixgbe_mac_82598EB)
- mrqc |= IXGBE_MRQC_RSSEN;
- /* Perform hash on these packet types */
- mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4
- | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
- | IXGBE_MRQC_RSS_FIELD_IPV6
- | IXGBE_MRQC_RSS_FIELD_IPV6_TCP;
- }
- IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
+ IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
+}
- if (adapter->num_vfs) {
- u32 reg;
+/**
+ * ixgbe_configure_rx - Configure 8259x Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ int i;
+ u32 rxctrl;
- /* Map PF MAC address in RAR Entry 0 to first pool
- * following VFs */
- hw->mac.ops.set_vmdq(hw, 0, adapter->num_vfs);
+ /* disable receives while setting up the descriptors */
+ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+ IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
- /* Set up VF register offsets for selected VT Mode, i.e.
- * 64 VFs for SR-IOV */
- reg = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
- reg |= IXGBE_GCR_EXT_SRIOV;
- IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, reg);
- }
+ ixgbe_setup_psrtype(adapter);
+ ixgbe_setup_rdrxctl(adapter);
- rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
+ /* Program registers for the distribution of queues */
+ ixgbe_setup_mrqc(adapter);
- if (adapter->flags & IXGBE_FLAG_RSS_ENABLED ||
- adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED) {
- /* Disable indicating checksum in descriptor, enables
- * RSS hash */
- rxcsum |= IXGBE_RXCSUM_PCSD;
- }
- if (!(rxcsum & IXGBE_RXCSUM_PCSD)) {
- /* Enable IPv4 payload checksum for UDP fragments
- * if PCSD is not set */
- rxcsum |= IXGBE_RXCSUM_IPPCSE;
- }
+ ixgbe_set_uta(adapter);
- IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
+ /* set_rx_buffer_len must be called before ring initialization */
+ ixgbe_set_rx_buffer_len(adapter);
- if (hw->mac.type == ixgbe_mac_82599EB) {
- rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
- rdrxctl |= IXGBE_RDRXCTL_CRCSTRIP;
- rdrxctl &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;
- IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
- }
+ /*
+ * Setup the HW Rx Head and Tail Descriptor Pointers and
+ * the Base and Length of the Rx Descriptor Ring
+ */
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ ixgbe_configure_rx_ring(adapter, adapter->rx_ring[i]);
- if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
- /* Enable 82599 HW-RSC */
- for (i = 0; i < adapter->num_rx_queues; i++)
- ixgbe_configure_rscctl(adapter, i);
+ /* disable drop enable for 82598 parts */
+ if (hw->mac.type == ixgbe_mac_82598EB)
+ rxctrl |= IXGBE_RXCTRL_DMBYPS;
- /* Disable RSC for ACK packets */
- IXGBE_WRITE_REG(hw, IXGBE_RSCDBU,
- (IXGBE_RSCDBU_RSCACKDIS | IXGBE_READ_REG(hw, IXGBE_RSCDBU)));
- }
+ /* enable all receives */
+ rxctrl |= IXGBE_RXCTRL_RXEN;
+ hw->mac.ops.enable_rx_dma(hw, rxctrl);
}
static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
@@ -2862,6 +3062,7 @@ static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
/* add VID to filter table */
hw->mac.ops.set_vfta(&adapter->hw, vid, pool_ndx, true);
+ set_bit(vid, adapter->active_vlans);
}
static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
@@ -2870,16 +3071,9 @@ static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
struct ixgbe_hw *hw = &adapter->hw;
int pool_ndx = adapter->num_vfs;
- if (!test_bit(__IXGBE_DOWN, &adapter->state))
- ixgbe_irq_disable(adapter);
-
- vlan_group_set_device(adapter->vlgrp, vid, NULL);
-
- if (!test_bit(__IXGBE_DOWN, &adapter->state))
- ixgbe_irq_enable(adapter);
-
/* remove VID from filter table */
hw->mac.ops.set_vfta(&adapter->hw, vid, pool_ndx, false);
+ clear_bit(vid, adapter->active_vlans);
}
/**
@@ -2889,27 +3083,45 @@ static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
static void ixgbe_vlan_filter_disable(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
- u32 vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+ u32 vlnctrl;
+
+ vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+ vlnctrl &= ~(IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN);
+ IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
+}
+
+/**
+ * ixgbe_vlan_filter_enable - helper to enable hw vlan filtering
+ * @adapter: driver data
+ */
+static void ixgbe_vlan_filter_enable(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 vlnctrl;
+
+ vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+ vlnctrl |= IXGBE_VLNCTRL_VFE;
+ vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
+ IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
+}
+
+/**
+ * ixgbe_vlan_strip_disable - helper to disable hw vlan stripping
+ * @adapter: driver data
+ */
+static void ixgbe_vlan_strip_disable(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 vlnctrl;
int i, j;
switch (hw->mac.type) {
case ixgbe_mac_82598EB:
- vlnctrl &= ~IXGBE_VLNCTRL_VFE;
-#ifdef CONFIG_IXGBE_DCB
- if (!(adapter->flags & IXGBE_FLAG_DCB_ENABLED))
- vlnctrl &= ~IXGBE_VLNCTRL_VME;
-#endif
- vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
+ vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+ vlnctrl &= ~IXGBE_VLNCTRL_VME;
IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
break;
case ixgbe_mac_82599EB:
- vlnctrl &= ~IXGBE_VLNCTRL_VFE;
- vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
- IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
-#ifdef CONFIG_IXGBE_DCB
- if (adapter->flags & IXGBE_FLAG_DCB_ENABLED)
- break;
-#endif
for (i = 0; i < adapter->num_rx_queues; i++) {
j = adapter->rx_ring[i]->reg_idx;
vlnctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
@@ -2923,25 +3135,22 @@ static void ixgbe_vlan_filter_disable(struct ixgbe_adapter *adapter)
}
/**
- * ixgbe_vlan_filter_enable - helper to enable hw vlan filtering
+ * ixgbe_vlan_strip_enable - helper to enable hw vlan stripping
* @adapter: driver data
*/
-static void ixgbe_vlan_filter_enable(struct ixgbe_adapter *adapter)
+static void ixgbe_vlan_strip_enable(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
- u32 vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+ u32 vlnctrl;
int i, j;
switch (hw->mac.type) {
case ixgbe_mac_82598EB:
- vlnctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE;
- vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
+ vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+ vlnctrl |= IXGBE_VLNCTRL_VME;
IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
break;
case ixgbe_mac_82599EB:
- vlnctrl |= IXGBE_VLNCTRL_VFE;
- vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
- IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
for (i = 0; i < adapter->num_rx_queues; i++) {
j = adapter->rx_ring[i]->reg_idx;
vlnctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
@@ -2954,40 +3163,14 @@ static void ixgbe_vlan_filter_enable(struct ixgbe_adapter *adapter)
}
}
-static void ixgbe_vlan_rx_register(struct net_device *netdev,
- struct vlan_group *grp)
-{
- struct ixgbe_adapter *adapter = netdev_priv(netdev);
-
- if (!test_bit(__IXGBE_DOWN, &adapter->state))
- ixgbe_irq_disable(adapter);
- adapter->vlgrp = grp;
-
- /*
- * For a DCB driver, always enable VLAN tag stripping so we can
- * still receive traffic from a DCB-enabled host even if we're
- * not in DCB mode.
- */
- ixgbe_vlan_filter_enable(adapter);
-
- ixgbe_vlan_rx_add_vid(netdev, 0);
-
- if (!test_bit(__IXGBE_DOWN, &adapter->state))
- ixgbe_irq_enable(adapter);
-}
-
static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
{
- ixgbe_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+ u16 vid;
- if (adapter->vlgrp) {
- u16 vid;
- for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
- if (!vlan_group_get_device(adapter->vlgrp, vid))
- continue;
- ixgbe_vlan_rx_add_vid(adapter->netdev, vid);
- }
- }
+ ixgbe_vlan_rx_add_vid(adapter->netdev, 0);
+
+ for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID)
+ ixgbe_vlan_rx_add_vid(adapter->netdev, vid);
}
/**
@@ -3052,6 +3235,11 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+ /* set all bits that we expect to always be set */
+ fctrl |= IXGBE_FCTRL_BAM;
+ fctrl |= IXGBE_FCTRL_DPF; /* discard pause frames when FC enabled */
+ fctrl |= IXGBE_FCTRL_PMCF;
+
/* clear the bits we are changing the status of */
fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
@@ -3097,6 +3285,11 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
}
IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
+
+ if (netdev->features & NETIF_F_HW_VLAN_RX)
+ ixgbe_vlan_strip_enable(adapter);
+ else
+ ixgbe_vlan_strip_disable(adapter);
}
static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter)
@@ -3157,7 +3350,15 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
u32 txdctl;
int i, j;
- ixgbe_dcb_check_config(&adapter->dcb_cfg);
+ if (!(adapter->flags & IXGBE_FLAG_DCB_ENABLED)) {
+ if (hw->mac.type == ixgbe_mac_82598EB)
+ netif_set_gso_max_size(adapter->netdev, 65536);
+ return;
+ }
+
+ if (hw->mac.type == ixgbe_mac_82598EB)
+ netif_set_gso_max_size(adapter->netdev, 32768);
+
ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_TX_CONFIG);
ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_RX_CONFIG);
@@ -3172,7 +3373,7 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
}
/* Enable VLAN tag insert/strip */
- ixgbe_vlan_filter_enable(adapter);
+ adapter->netdev->features |= NETIF_F_HW_VLAN_RX;
hw->mac.ops.set_vfta(&adapter->hw, 0, 0, true);
}
@@ -3184,23 +3385,13 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
struct ixgbe_hw *hw = &adapter->hw;
int i;
- ixgbe_set_rx_mode(netdev);
-
- ixgbe_restore_vlan(adapter);
#ifdef CONFIG_IXGBE_DCB
- if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
- if (hw->mac.type == ixgbe_mac_82598EB)
- netif_set_gso_max_size(netdev, 32768);
- else
- netif_set_gso_max_size(netdev, 65536);
- ixgbe_configure_dcb(adapter);
- } else {
- netif_set_gso_max_size(netdev, 65536);
- }
-#else
- netif_set_gso_max_size(netdev, 65536);
+ ixgbe_configure_dcb(adapter);
#endif
+ ixgbe_set_rx_mode(netdev);
+ ixgbe_restore_vlan(adapter);
+
#ifdef IXGBE_FCOE
if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
ixgbe_configure_fcoe(adapter);
@@ -3209,17 +3400,15 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
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;
+ adapter->atr_sample_rate;
ixgbe_init_fdir_signature_82599(hw, adapter->fdir_pballoc);
} else if (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) {
ixgbe_init_fdir_perfect_82599(hw, adapter->fdir_pballoc);
}
+ ixgbe_configure_virtualization(adapter);
ixgbe_configure_tx(adapter);
ixgbe_configure_rx(adapter);
- for (i = 0; i < adapter->num_rx_queues; i++)
- ixgbe_alloc_rx_buffers(adapter, adapter->rx_ring[i],
- (adapter->rx_ring[i]->count - 1));
}
static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw)
@@ -3290,7 +3479,8 @@ static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw)
goto link_cfg_out;
if (hw->mac.ops.get_link_capabilities)
- ret = hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation);
+ ret = hw->mac.ops.get_link_capabilities(hw, &autoneg,
+ &negotiation);
if (ret)
goto link_cfg_out;
@@ -3300,62 +3490,15 @@ link_cfg_out:
return ret;
}
-#define IXGBE_MAX_RX_DESC_POLL 10
-static inline void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
- int rxr)
+static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
{
- int j = adapter->rx_ring[rxr]->reg_idx;
- int k;
-
- for (k = 0; k < IXGBE_MAX_RX_DESC_POLL; k++) {
- if (IXGBE_READ_REG(&adapter->hw,
- IXGBE_RXDCTL(j)) & IXGBE_RXDCTL_ENABLE)
- break;
- else
- msleep(1);
- }
- if (k >= IXGBE_MAX_RX_DESC_POLL) {
- e_err(drv, "RXDCTL.ENABLE on Rx queue %d not set within "
- "the polling period\n", rxr);
- }
- ixgbe_release_rx_desc(&adapter->hw, adapter->rx_ring[rxr],
- (adapter->rx_ring[rxr]->count - 1));
-}
-
-static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
-{
- struct net_device *netdev = adapter->netdev;
struct ixgbe_hw *hw = &adapter->hw;
- int i, j = 0;
- int num_rx_rings = adapter->num_rx_queues;
- int err;
- int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
- u32 txdctl, rxdctl, mhadd;
- u32 dmatxctl;
- u32 gpie;
- u32 ctrl_ext;
-
- ixgbe_get_hw_control(adapter);
-
- if ((adapter->flags & IXGBE_FLAG_MSIX_ENABLED) ||
- (adapter->flags & IXGBE_FLAG_MSI_ENABLED)) {
- if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
- gpie = (IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_EIAME |
- IXGBE_GPIE_PBA_SUPPORT | IXGBE_GPIE_OCD);
- } else {
- /* MSI only */
- gpie = 0;
- }
- if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
- gpie &= ~IXGBE_GPIE_VTMODE_MASK;
- gpie |= IXGBE_GPIE_VTMODE_64;
- }
- /* XXX: to interrupt immediately for EICS writes, enable this */
- /* gpie |= IXGBE_GPIE_EIMEN; */
- IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
- }
+ u32 gpie = 0;
if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+ gpie = IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_PBA_SUPPORT |
+ IXGBE_GPIE_OCD;
+ gpie |= IXGBE_GPIE_EIAME;
/*
* use EIAM to auto-mask when MSI-X interrupt is asserted
* this saves a register write for every interrupt
@@ -3376,98 +3519,33 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE);
}
- /* Enable Thermal over heat sensor interrupt */
- if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) {
- gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
- gpie |= IXGBE_SDP0_GPIEN;
- IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
+ /* XXX: to interrupt immediately for EICS writes, enable this */
+ /* gpie |= IXGBE_GPIE_EIMEN; */
+
+ if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
+ gpie &= ~IXGBE_GPIE_VTMODE_MASK;
+ gpie |= IXGBE_GPIE_VTMODE_64;
}
- /* Enable fan failure interrupt if media type is copper */
- if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) {
- gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
+ /* Enable fan failure interrupt */
+ if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
gpie |= IXGBE_SDP1_GPIEN;
- IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
- }
- if (hw->mac.type == ixgbe_mac_82599EB) {
- gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
+ if (hw->mac.type == ixgbe_mac_82599EB)
gpie |= IXGBE_SDP1_GPIEN;
gpie |= IXGBE_SDP2_GPIEN;
- IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
- }
-#ifdef IXGBE_FCOE
- /* adjust max frame to be able to do baby jumbo for FCoE */
- if ((netdev->features & NETIF_F_FCOE_MTU) &&
- (max_frame < IXGBE_FCOE_JUMBO_FRAME_SIZE))
- max_frame = IXGBE_FCOE_JUMBO_FRAME_SIZE;
-
-#endif /* IXGBE_FCOE */
- mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
- if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) {
- mhadd &= ~IXGBE_MHADD_MFS_MASK;
- mhadd |= max_frame << IXGBE_MHADD_MFS_SHIFT;
-
- IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd);
- }
-
- for (i = 0; i < adapter->num_tx_queues; i++) {
- j = adapter->tx_ring[i]->reg_idx;
- txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
- 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);
- }
- IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
- }
+ IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
+}
- if (hw->mac.type == ixgbe_mac_82599EB) {
- /* DMATXCTL.EN must be set after all Tx queue config is done */
- dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
- dmatxctl |= IXGBE_DMATXCTL_TE;
- IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl);
- }
- for (i = 0; i < adapter->num_tx_queues; i++) {
- j = adapter->tx_ring[i]->reg_idx;
- txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
- txdctl |= IXGBE_TXDCTL_ENABLE;
- IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
- if (hw->mac.type == ixgbe_mac_82599EB) {
- int wait_loop = 10;
- /* poll for Tx Enable ready */
- do {
- msleep(1);
- txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
- } while (--wait_loop &&
- !(txdctl & IXGBE_TXDCTL_ENABLE));
- if (!wait_loop)
- e_err(drv, "Could not enable Tx Queue %d\n", j);
- }
- }
+static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ int err;
+ u32 ctrl_ext;
- for (i = 0; i < num_rx_rings; i++) {
- j = adapter->rx_ring[i]->reg_idx;
- rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
- /* enable PTHRESH=32 descriptors (half the internal cache)
- * and HTHRESH=0 descriptors (to minimize latency on fetch),
- * this also removes a pesky rx_no_buffer_count increment */
- rxdctl |= 0x0020;
- rxdctl |= IXGBE_RXDCTL_ENABLE;
- IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(j), rxdctl);
- if (hw->mac.type == ixgbe_mac_82599EB)
- ixgbe_rx_desc_queue_enable(adapter, i);
- }
- /* enable all receives */
- rxdctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
- if (hw->mac.type == ixgbe_mac_82598EB)
- rxdctl |= (IXGBE_RXCTRL_DMBYPS | IXGBE_RXCTRL_RXEN);
- else
- rxdctl |= IXGBE_RXCTRL_RXEN;
- hw->mac.ops.enable_rx_dma(hw, rxdctl);
+ ixgbe_get_hw_control(adapter);
+ ixgbe_setup_gpie(adapter);
if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
ixgbe_configure_msix(adapter);
@@ -3483,8 +3561,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
/* clear any pending interrupts, may auto mask */
IXGBE_READ_REG(hw, IXGBE_EICR);
-
- ixgbe_irq_enable(adapter);
+ ixgbe_irq_enable(adapter, true, true);
/*
* If this adapter has a fan, check to see if we had a failure
@@ -3525,12 +3602,8 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
e_err(probe, "link_config FAILED %d\n", err);
}
- for (i = 0; i < adapter->num_tx_queues; i++)
- set_bit(__IXGBE_FDIR_INIT_DONE,
- &(adapter->tx_ring[i]->reinit_state));
-
/* enable transmits */
- netif_tx_start_all_queues(netdev);
+ netif_tx_start_all_queues(adapter->netdev);
/* bring the link up in the watchdog, this could race with our first
* link up interrupt but shouldn't be a problem */
@@ -3609,21 +3682,24 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
* @rx_ring: ring to free buffers from
**/
static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *rx_ring)
+ struct ixgbe_ring *rx_ring)
{
struct pci_dev *pdev = adapter->pdev;
unsigned long size;
unsigned int i;
- /* Free all the Rx ring sk_buffs */
+ /* ring already cleared, nothing to do */
+ if (!rx_ring->rx_buffer_info)
+ return;
+ /* Free all the Rx ring sk_buffs */
for (i = 0; i < rx_ring->count; i++) {
struct ixgbe_rx_buffer *rx_buffer_info;
rx_buffer_info = &rx_ring->rx_buffer_info[i];
if (rx_buffer_info->dma) {
dma_unmap_single(&pdev->dev, rx_buffer_info->dma,
- rx_ring->rx_buf_len,
+ rx_ring->rx_buf_len,
DMA_FROM_DEVICE);
rx_buffer_info->dma = 0;
}
@@ -3635,7 +3711,7 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
if (IXGBE_RSC_CB(this)->delay_unmap) {
dma_unmap_single(&pdev->dev,
IXGBE_RSC_CB(this)->dma,
- rx_ring->rx_buf_len,
+ rx_ring->rx_buf_len,
DMA_FROM_DEVICE);
IXGBE_RSC_CB(this)->dma = 0;
IXGBE_RSC_CB(skb)->delay_unmap = false;
@@ -3677,14 +3753,17 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
* @tx_ring: ring to be cleaned
**/
static void ixgbe_clean_tx_ring(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring)
+ struct ixgbe_ring *tx_ring)
{
struct ixgbe_tx_buffer *tx_buffer_info;
unsigned long size;
unsigned int i;
- /* Free all the Tx ring sk_buffs */
+ /* ring already cleared, nothing to do */
+ if (!tx_ring->tx_buffer_info)
+ return;
+ /* Free all the Tx ring sk_buffs */
for (i = 0; i < tx_ring->count; i++) {
tx_buffer_info = &tx_ring->tx_buffer_info[i];
ixgbe_unmap_and_free_tx_resource(adapter, tx_buffer_info);
@@ -3736,6 +3815,7 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
u32 rxctrl;
u32 txdctl;
int i, j;
+ 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);
@@ -3774,6 +3854,15 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
ixgbe_napi_disable_all(adapter);
+ /* 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);
+ }
+
if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
cancel_work_sync(&adapter->fdir_reinit_task);
@@ -3786,13 +3875,13 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
j = adapter->tx_ring[i]->reg_idx;
txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j),
- (txdctl & ~IXGBE_TXDCTL_ENABLE));
+ (txdctl & ~IXGBE_TXDCTL_ENABLE));
}
/* Disable the Tx DMA engine on 82599 */
if (hw->mac.type == ixgbe_mac_82599EB)
IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL,
- (IXGBE_READ_REG(hw, IXGBE_DMATXCTL) &
- ~IXGBE_DMATXCTL_TE));
+ (IXGBE_READ_REG(hw, IXGBE_DMATXCTL) &
+ ~IXGBE_DMATXCTL_TE));
/* power down the optics */
if (hw->phy.multispeed_fiber)
@@ -3822,7 +3911,7 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
static int ixgbe_poll(struct napi_struct *napi, int budget)
{
struct ixgbe_q_vector *q_vector =
- container_of(napi, struct ixgbe_q_vector, napi);
+ container_of(napi, struct ixgbe_q_vector, napi);
struct ixgbe_adapter *adapter = q_vector->adapter;
int tx_clean_complete, work_done = 0;
@@ -3932,7 +4021,7 @@ static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter)
* Rx load across CPUs using RSS.
*
**/
-static bool inline ixgbe_set_fdir_queues(struct ixgbe_adapter *adapter)
+static inline bool ixgbe_set_fdir_queues(struct ixgbe_adapter *adapter)
{
bool ret = false;
struct ixgbe_ring_feature *f_fdir = &adapter->ring_feature[RING_F_FDIR];
@@ -4024,7 +4113,7 @@ static inline bool ixgbe_set_sriov_queues(struct ixgbe_adapter *adapter)
* fallthrough conditions.
*
**/
-static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
+static int ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
{
/* Start with base case */
adapter->num_rx_queues = 1;
@@ -4033,7 +4122,7 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
adapter->num_rx_queues_per_pool = 1;
if (ixgbe_set_sriov_queues(adapter))
- return;
+ goto done;
#ifdef IXGBE_FCOE
if (ixgbe_set_fcoe_queues(adapter))
@@ -4056,12 +4145,14 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
adapter->num_tx_queues = 1;
done:
- /* Notify the stack of the (possibly) reduced Tx Queue count. */
+ /* Notify the stack of the (possibly) reduced queue counts. */
netif_set_real_num_tx_queues(adapter->netdev, adapter->num_tx_queues);
+ return netif_set_real_num_rx_queues(adapter->netdev,
+ adapter->num_rx_queues);
}
static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
- int vectors)
+ int vectors)
{
int err, vector_threshold;
@@ -4080,7 +4171,7 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
*/
while (vectors >= vector_threshold) {
err = pci_enable_msix(adapter->pdev, adapter->msix_entries,
- vectors);
+ vectors);
if (!err) /* Success in acquiring all requested vectors. */
break;
else if (err < 0)
@@ -4107,7 +4198,7 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
* vectors we were allocated.
*/
adapter->num_msix_vectors = min(vectors,
- adapter->max_msix_q_vectors + NON_Q_VECTORS);
+ adapter->max_msix_q_vectors + NON_Q_VECTORS);
}
}
@@ -4178,12 +4269,12 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter)
}
for ( ; i < 5; i++) {
adapter->tx_ring[i]->reg_idx =
- ((i + 2) << 4);
+ ((i + 2) << 4);
adapter->rx_ring[i]->reg_idx = i << 4;
}
for ( ; i < dcb_i; i++) {
adapter->tx_ring[i]->reg_idx =
- ((i + 8) << 3);
+ ((i + 8) << 3);
adapter->rx_ring[i]->reg_idx = i << 4;
}
@@ -4226,7 +4317,7 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter)
* Cache the descriptor ring offsets for Flow Director to the assigned rings.
*
**/
-static bool inline ixgbe_cache_ring_fdir(struct ixgbe_adapter *adapter)
+static inline bool ixgbe_cache_ring_fdir(struct ixgbe_adapter *adapter)
{
int i;
bool ret = false;
@@ -4383,7 +4474,7 @@ static int ixgbe_alloc_queues(struct ixgbe_adapter *adapter)
adapter->node = cur_node;
}
ring = kzalloc_node(sizeof(struct ixgbe_ring), GFP_KERNEL,
- adapter->node);
+ adapter->node);
if (!ring)
ring = kzalloc(sizeof(struct ixgbe_ring), GFP_KERNEL);
if (!ring)
@@ -4407,7 +4498,7 @@ static int ixgbe_alloc_queues(struct ixgbe_adapter *adapter)
adapter->node = cur_node;
}
ring = kzalloc_node(sizeof(struct ixgbe_ring), GFP_KERNEL,
- adapter->node);
+ adapter->node);
if (!ring)
ring = kzalloc(sizeof(struct ixgbe_ring), GFP_KERNEL);
if (!ring)
@@ -4453,7 +4544,7 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
* (roughly) the same number of vectors as there are CPU's.
*/
v_budget = min(adapter->num_rx_queues + adapter->num_tx_queues,
- (int)num_online_cpus()) + NON_Q_VECTORS;
+ (int)num_online_cpus()) + NON_Q_VECTORS;
/*
* At the same time, hardware can only support a maximum of
@@ -4467,7 +4558,7 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
/* A failure in MSI-X entry allocation isn't fatal, but it does
* mean we disable MSI-X capabilities of the adapter. */
adapter->msix_entries = kcalloc(v_budget,
- sizeof(struct msix_entry), GFP_KERNEL);
+ sizeof(struct msix_entry), GFP_KERNEL);
if (adapter->msix_entries) {
for (vector = 0; vector < v_budget; vector++)
adapter->msix_entries[vector].entry = vector;
@@ -4486,7 +4577,9 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
ixgbe_disable_sriov(adapter);
- ixgbe_set_num_queues(adapter);
+ err = ixgbe_set_num_queues(adapter);
+ if (err)
+ return err;
err = pci_enable_msi(adapter->pdev);
if (!err) {
@@ -4529,10 +4622,10 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter)
for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
q_vector = kzalloc_node(sizeof(struct ixgbe_q_vector),
- GFP_KERNEL, adapter->node);
+ GFP_KERNEL, adapter->node);
if (!q_vector)
q_vector = kzalloc(sizeof(struct ixgbe_q_vector),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!q_vector)
goto err_out;
q_vector->adapter = adapter;
@@ -4611,7 +4704,9 @@ int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter)
int err;
/* Number of supported queues */
- ixgbe_set_num_queues(adapter);
+ err = ixgbe_set_num_queues(adapter);
+ if (err)
+ return err;
err = ixgbe_set_interrupt_capability(adapter);
if (err) {
@@ -4693,8 +4788,8 @@ static void ixgbe_sfp_timer(unsigned long data)
static void ixgbe_sfp_task(struct work_struct *work)
{
struct ixgbe_adapter *adapter = container_of(work,
- struct ixgbe_adapter,
- sfp_task);
+ struct ixgbe_adapter,
+ sfp_task);
struct ixgbe_hw *hw = &adapter->hw;
if ((hw->phy.type == ixgbe_phy_nl) &&
@@ -4719,7 +4814,7 @@ static void ixgbe_sfp_task(struct work_struct *work)
reschedule:
if (test_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state))
mod_timer(&adapter->sfp_timer,
- round_jiffies(jiffies + (2 * HZ)));
+ round_jiffies(jiffies + (2 * HZ)));
}
/**
@@ -4775,7 +4870,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
adapter->atr_sample_rate = 20;
}
adapter->ring_feature[RING_F_FDIR].indices =
- IXGBE_MAX_FDIR_INDICES;
+ IXGBE_MAX_FDIR_INDICES;
adapter->fdir_pballoc = 0;
#ifdef IXGBE_FCOE
adapter->flags |= IXGBE_FLAG_FCOE_CAPABLE;
@@ -4806,7 +4901,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
adapter->dcb_cfg.round_robin_enable = false;
adapter->dcb_set_bitmap = 0x00;
ixgbe_copy_dcb_cfg(&adapter->dcb_cfg, &adapter->temp_dcb_cfg,
- adapter->ring_feature[RING_F_DCB].indices);
+ adapter->ring_feature[RING_F_DCB].indices);
#endif
@@ -4861,7 +4956,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
* Return 0 on success, negative on failure
**/
int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring)
+ struct ixgbe_ring *tx_ring)
{
struct pci_dev *pdev = adapter->pdev;
int size;
@@ -4928,7 +5023,7 @@ static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter)
* Returns 0 on success, negative on failure
**/
int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *rx_ring)
+ struct ixgbe_ring *rx_ring)
{
struct pci_dev *pdev = adapter->pdev;
int size;
@@ -5001,7 +5096,7 @@ static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter)
* Free all transmit software resources
**/
void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring)
+ struct ixgbe_ring *tx_ring)
{
struct pci_dev *pdev = adapter->pdev;
@@ -5039,7 +5134,7 @@ static void ixgbe_free_all_tx_resources(struct ixgbe_adapter *adapter)
* Free all receive software resources
**/
void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *rx_ring)
+ struct ixgbe_ring *rx_ring)
{
struct pci_dev *pdev = adapter->pdev;
@@ -5333,6 +5428,7 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
u64 total_mpc = 0;
u32 i, missed_rx = 0, mpc, bprc, lxon, lxoff, xon_off_tot;
u64 non_eop_descs = 0, restart_queue = 0;
+ struct ixgbe_hw_stats *hwstats = &adapter->stats;
if (test_bit(__IXGBE_DOWN, &adapter->state) ||
test_bit(__IXGBE_RESETTING, &adapter->state))
@@ -5343,7 +5439,7 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
u64 rsc_flush = 0;
for (i = 0; i < 16; i++)
adapter->hw_rx_no_dma_resources +=
- IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
+ IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
for (i = 0; i < adapter->num_rx_queues; i++) {
rsc_count += adapter->rx_ring[i]->rsc_count;
rsc_flush += adapter->rx_ring[i]->rsc_flush;
@@ -5361,119 +5457,118 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
non_eop_descs += adapter->rx_ring[i]->non_eop_descs;
adapter->non_eop_descs = non_eop_descs;
- adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
+ hwstats->crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
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;
- adapter->stats.mpc[i] += mpc;
- total_mpc += adapter->stats.mpc[i];
+ hwstats->mpc[i] += mpc;
+ total_mpc += hwstats->mpc[i];
if (hw->mac.type == ixgbe_mac_82598EB)
- adapter->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i));
- adapter->stats.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
- adapter->stats.qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC(i));
- adapter->stats.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
- adapter->stats.qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC(i));
+ 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));
if (hw->mac.type == ixgbe_mac_82599EB) {
- adapter->stats.pxonrxc[i] += IXGBE_READ_REG(hw,
- IXGBE_PXONRXCNT(i));
- adapter->stats.pxoffrxc[i] += IXGBE_READ_REG(hw,
- IXGBE_PXOFFRXCNT(i));
- adapter->stats.qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
+ hwstats->pxonrxc[i] +=
+ IXGBE_READ_REG(hw, IXGBE_PXONRXCNT(i));
+ hwstats->pxoffrxc[i] +=
+ IXGBE_READ_REG(hw, IXGBE_PXOFFRXCNT(i));
+ hwstats->qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
} else {
- adapter->stats.pxonrxc[i] += IXGBE_READ_REG(hw,
- IXGBE_PXONRXC(i));
- adapter->stats.pxoffrxc[i] += IXGBE_READ_REG(hw,
- IXGBE_PXOFFRXC(i));
+ hwstats->pxonrxc[i] +=
+ IXGBE_READ_REG(hw, IXGBE_PXONRXC(i));
+ hwstats->pxoffrxc[i] +=
+ IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i));
}
- adapter->stats.pxontxc[i] += IXGBE_READ_REG(hw,
- IXGBE_PXONTXC(i));
- adapter->stats.pxofftxc[i] += IXGBE_READ_REG(hw,
- IXGBE_PXOFFTXC(i));
+ hwstats->pxontxc[i] += IXGBE_READ_REG(hw, IXGBE_PXONTXC(i));
+ hwstats->pxofftxc[i] += IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i));
}
- adapter->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC);
+ hwstats->gprc += IXGBE_READ_REG(hw, IXGBE_GPRC);
/* work around hardware counting issue */
- adapter->stats.gprc -= missed_rx;
+ hwstats->gprc -= missed_rx;
/* 82598 hardware only has a 32 bit counter in the high register */
if (hw->mac.type == ixgbe_mac_82599EB) {
u64 tmp;
- adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL);
- tmp = IXGBE_READ_REG(hw, IXGBE_GORCH) & 0xF; /* 4 high bits of GORC */
- adapter->stats.gorc += (tmp << 32);
- adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL);
- tmp = IXGBE_READ_REG(hw, IXGBE_GOTCH) & 0xF; /* 4 high bits of GOTC */
- adapter->stats.gotc += (tmp << 32);
- adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORL);
- IXGBE_READ_REG(hw, IXGBE_TORH); /* to clear */
- adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT);
- adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT);
- adapter->stats.fdirmatch += IXGBE_READ_REG(hw, IXGBE_FDIRMATCH);
- adapter->stats.fdirmiss += IXGBE_READ_REG(hw, IXGBE_FDIRMISS);
+ hwstats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCL);
+ tmp = IXGBE_READ_REG(hw, IXGBE_GORCH) & 0xF;
+ /* 4 high bits of GORC */
+ hwstats->gorc += (tmp << 32);
+ hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL);
+ tmp = IXGBE_READ_REG(hw, IXGBE_GOTCH) & 0xF;
+ /* 4 high bits of GOTC */
+ hwstats->gotc += (tmp << 32);
+ hwstats->tor += IXGBE_READ_REG(hw, IXGBE_TORL);
+ IXGBE_READ_REG(hw, IXGBE_TORH); /* to clear */
+ hwstats->lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT);
+ hwstats->lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT);
+ hwstats->fdirmatch += IXGBE_READ_REG(hw, IXGBE_FDIRMATCH);
+ hwstats->fdirmiss += IXGBE_READ_REG(hw, IXGBE_FDIRMISS);
#ifdef IXGBE_FCOE
- adapter->stats.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC);
- adapter->stats.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC);
- adapter->stats.fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC);
- adapter->stats.fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC);
- adapter->stats.fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC);
- adapter->stats.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC);
+ hwstats->fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC);
+ hwstats->fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC);
+ hwstats->fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC);
+ hwstats->fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC);
+ hwstats->fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC);
+ hwstats->fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC);
#endif /* IXGBE_FCOE */
} else {
- adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
- adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
- adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
- adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
- adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
+ hwstats->lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
+ hwstats->lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
+ hwstats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
+ hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
+ hwstats->tor += IXGBE_READ_REG(hw, IXGBE_TORH);
}
bprc = IXGBE_READ_REG(hw, IXGBE_BPRC);
- adapter->stats.bprc += bprc;
- adapter->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
+ hwstats->bprc += bprc;
+ hwstats->mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
if (hw->mac.type == ixgbe_mac_82598EB)
- adapter->stats.mprc -= bprc;
- adapter->stats.roc += IXGBE_READ_REG(hw, IXGBE_ROC);
- adapter->stats.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64);
- adapter->stats.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127);
- adapter->stats.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255);
- adapter->stats.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511);
- adapter->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
- adapter->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
- adapter->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
+ hwstats->mprc -= bprc;
+ hwstats->roc += IXGBE_READ_REG(hw, IXGBE_ROC);
+ hwstats->prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64);
+ hwstats->prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127);
+ hwstats->prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255);
+ hwstats->prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511);
+ hwstats->prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
+ hwstats->prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
+ hwstats->rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC);
- adapter->stats.lxontxc += lxon;
+ hwstats->lxontxc += lxon;
lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
- adapter->stats.lxofftxc += lxoff;
- adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
- adapter->stats.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC);
- adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
+ 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);
/*
* 82598 errata - tx of flow control packets is included in tx counters
*/
xon_off_tot = lxon + lxoff;
- adapter->stats.gptc -= xon_off_tot;
- adapter->stats.mptc -= xon_off_tot;
- adapter->stats.gotc -= (xon_off_tot * (ETH_ZLEN + ETH_FCS_LEN));
- adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
- adapter->stats.rfc += IXGBE_READ_REG(hw, IXGBE_RFC);
- adapter->stats.rjc += IXGBE_READ_REG(hw, IXGBE_RJC);
- adapter->stats.tpr += IXGBE_READ_REG(hw, IXGBE_TPR);
- adapter->stats.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64);
- adapter->stats.ptc64 -= xon_off_tot;
- adapter->stats.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127);
- adapter->stats.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255);
- adapter->stats.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511);
- adapter->stats.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023);
- adapter->stats.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522);
- adapter->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC);
+ hwstats->gptc -= xon_off_tot;
+ hwstats->mptc -= xon_off_tot;
+ hwstats->gotc -= (xon_off_tot * (ETH_ZLEN + ETH_FCS_LEN));
+ hwstats->ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
+ hwstats->rfc += IXGBE_READ_REG(hw, IXGBE_RFC);
+ hwstats->rjc += IXGBE_READ_REG(hw, IXGBE_RJC);
+ hwstats->tpr += IXGBE_READ_REG(hw, IXGBE_TPR);
+ hwstats->ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64);
+ hwstats->ptc64 -= xon_off_tot;
+ hwstats->ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127);
+ hwstats->ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255);
+ hwstats->ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511);
+ hwstats->ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023);
+ hwstats->ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522);
+ hwstats->bptc += IXGBE_READ_REG(hw, IXGBE_BPTC);
/* Fill out the OS statistics structure */
- netdev->stats.multicast = adapter->stats.mprc;
+ netdev->stats.multicast = hwstats->mprc;
/* Rx Errors */
- netdev->stats.rx_errors = adapter->stats.crcerrs +
- adapter->stats.rlec;
+ netdev->stats.rx_errors = hwstats->crcerrs + hwstats->rlec;
netdev->stats.rx_dropped = 0;
- netdev->stats.rx_length_errors = adapter->stats.rlec;
- netdev->stats.rx_crc_errors = adapter->stats.crcerrs;
+ netdev->stats.rx_length_errors = hwstats->rlec;
+ netdev->stats.rx_crc_errors = hwstats->crcerrs;
netdev->stats.rx_missed_errors = total_mpc;
}
@@ -5532,8 +5627,8 @@ watchdog_short_circuit:
static void ixgbe_multispeed_fiber_task(struct work_struct *work)
{
struct ixgbe_adapter *adapter = container_of(work,
- struct ixgbe_adapter,
- multispeed_fiber_task);
+ struct ixgbe_adapter,
+ multispeed_fiber_task);
struct ixgbe_hw *hw = &adapter->hw;
u32 autoneg;
bool negotiation;
@@ -5556,8 +5651,8 @@ static void ixgbe_multispeed_fiber_task(struct work_struct *work)
static void ixgbe_sfp_config_module_task(struct work_struct *work)
{
struct ixgbe_adapter *adapter = container_of(work,
- struct ixgbe_adapter,
- sfp_config_module_task);
+ struct ixgbe_adapter,
+ sfp_config_module_task);
struct ixgbe_hw *hw = &adapter->hw;
u32 err;
@@ -5590,15 +5685,15 @@ static void ixgbe_sfp_config_module_task(struct work_struct *work)
static void ixgbe_fdir_reinit_task(struct work_struct *work)
{
struct ixgbe_adapter *adapter = container_of(work,
- struct ixgbe_adapter,
- fdir_reinit_task);
+ struct ixgbe_adapter,
+ fdir_reinit_task);
struct ixgbe_hw *hw = &adapter->hw;
int i;
if (ixgbe_reinit_fdir_tables_82599(hw) == 0) {
for (i = 0; i < adapter->num_tx_queues; i++)
set_bit(__IXGBE_FDIR_INIT_DONE,
- &(adapter->tx_ring[i]->reinit_state));
+ &(adapter->tx_ring[i]->reinit_state));
} else {
e_err(probe, "failed to finish FDIR re-initialization, "
"ignored adding FDIR ATR filters\n");
@@ -5616,8 +5711,8 @@ static DEFINE_MUTEX(ixgbe_watchdog_lock);
static void ixgbe_watchdog_task(struct work_struct *work)
{
struct ixgbe_adapter *adapter = container_of(work,
- struct ixgbe_adapter,
- watchdog_task);
+ struct ixgbe_adapter,
+ watchdog_task);
struct net_device *netdev = adapter->netdev;
struct ixgbe_hw *hw = &adapter->hw;
u32 link_speed;
@@ -5648,7 +5743,7 @@ static void ixgbe_watchdog_task(struct work_struct *work)
if (link_up ||
time_after(jiffies, (adapter->link_check_timeout +
- IXGBE_TRY_LINK_TIMEOUT))) {
+ IXGBE_TRY_LINK_TIMEOUT))) {
adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC);
}
@@ -5719,8 +5814,8 @@ static void ixgbe_watchdog_task(struct work_struct *work)
}
static int ixgbe_tso(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring, struct sk_buff *skb,
- u32 tx_flags, u8 *hdr_len)
+ struct ixgbe_ring *tx_ring, struct sk_buff *skb,
+ u32 tx_flags, u8 *hdr_len)
{
struct ixgbe_adv_tx_context_desc *context_desc;
unsigned int i;
@@ -5743,28 +5838,28 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
iph->tot_len = 0;
iph->check = 0;
tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
- iph->daddr, 0,
- IPPROTO_TCP,
- 0);
+ iph->daddr, 0,
+ IPPROTO_TCP,
+ 0);
} 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);
+ &ipv6_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0);
}
i = tx_ring->next_to_use;
tx_buffer_info = &tx_ring->tx_buffer_info[i];
- context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i);
+ context_desc = IXGBE_TX_CTXTDESC_ADV(tx_ring, i);
/* VLAN MACLEN IPLEN */
if (tx_flags & IXGBE_TX_FLAGS_VLAN)
vlan_macip_lens |=
(tx_flags & IXGBE_TX_FLAGS_VLAN_MASK);
vlan_macip_lens |= ((skb_network_offset(skb)) <<
- IXGBE_ADVTXD_MACLEN_SHIFT);
+ IXGBE_ADVTXD_MACLEN_SHIFT);
*hdr_len += skb_network_offset(skb);
vlan_macip_lens |=
(skb_transport_header(skb) - skb_network_header(skb));
@@ -5775,7 +5870,7 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
/* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
type_tucmd_mlhl = (IXGBE_TXD_CMD_DEXT |
- IXGBE_ADVTXD_DTYP_CTXT);
+ IXGBE_ADVTXD_DTYP_CTXT);
if (skb->protocol == htons(ETH_P_IP))
type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
@@ -5803,9 +5898,53 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
return false;
}
+static u32 ixgbe_psum(struct ixgbe_adapter *adapter, struct sk_buff *skb)
+{
+ u32 rtn = 0;
+ __be16 protocol;
+
+ if (skb->protocol == cpu_to_be16(ETH_P_8021Q))
+ protocol = ((const struct vlan_ethhdr *)skb->data)->
+ h_vlan_encapsulated_proto;
+ else
+ protocol = skb->protocol;
+
+ switch (protocol) {
+ case cpu_to_be16(ETH_P_IP):
+ rtn |= IXGBE_ADVTXD_TUCMD_IPV4;
+ switch (ip_hdr(skb)->protocol) {
+ case IPPROTO_TCP:
+ rtn |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
+ break;
+ case IPPROTO_SCTP:
+ rtn |= IXGBE_ADVTXD_TUCMD_L4T_SCTP;
+ break;
+ }
+ break;
+ case cpu_to_be16(ETH_P_IPV6):
+ /* XXX what about other V6 headers?? */
+ switch (ipv6_hdr(skb)->nexthdr) {
+ case IPPROTO_TCP:
+ rtn |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
+ break;
+ case IPPROTO_SCTP:
+ rtn |= IXGBE_ADVTXD_TUCMD_L4T_SCTP;
+ break;
+ }
+ break;
+ default:
+ if (unlikely(net_ratelimit()))
+ e_warn(probe, "partial checksum but proto=%x!\n",
+ skb->protocol);
+ break;
+ }
+
+ return rtn;
+}
+
static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring,
- struct sk_buff *skb, u32 tx_flags)
+ struct ixgbe_ring *tx_ring,
+ struct sk_buff *skb, u32 tx_flags)
{
struct ixgbe_adv_tx_context_desc *context_desc;
unsigned int i;
@@ -5816,63 +5955,25 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
(tx_flags & IXGBE_TX_FLAGS_VLAN)) {
i = tx_ring->next_to_use;
tx_buffer_info = &tx_ring->tx_buffer_info[i];
- context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i);
+ context_desc = IXGBE_TX_CTXTDESC_ADV(tx_ring, i);
if (tx_flags & IXGBE_TX_FLAGS_VLAN)
vlan_macip_lens |=
(tx_flags & IXGBE_TX_FLAGS_VLAN_MASK);
vlan_macip_lens |= (skb_network_offset(skb) <<
- IXGBE_ADVTXD_MACLEN_SHIFT);
+ IXGBE_ADVTXD_MACLEN_SHIFT);
if (skb->ip_summed == CHECKSUM_PARTIAL)
vlan_macip_lens |= (skb_transport_header(skb) -
- skb_network_header(skb));
+ skb_network_header(skb));
context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
context_desc->seqnum_seed = 0;
type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT |
- IXGBE_ADVTXD_DTYP_CTXT);
-
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- __be16 protocol;
-
- if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) {
- const struct vlan_ethhdr *vhdr =
- (const struct vlan_ethhdr *)skb->data;
-
- protocol = vhdr->h_vlan_encapsulated_proto;
- } else {
- protocol = skb->protocol;
- }
+ IXGBE_ADVTXD_DTYP_CTXT);
- switch (protocol) {
- case cpu_to_be16(ETH_P_IP):
- type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
- if (ip_hdr(skb)->protocol == IPPROTO_TCP)
- type_tucmd_mlhl |=
- IXGBE_ADVTXD_TUCMD_L4T_TCP;
- else if (ip_hdr(skb)->protocol == IPPROTO_SCTP)
- type_tucmd_mlhl |=
- IXGBE_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)
- type_tucmd_mlhl |=
- IXGBE_ADVTXD_TUCMD_L4T_TCP;
- else if (ipv6_hdr(skb)->nexthdr == IPPROTO_SCTP)
- type_tucmd_mlhl |=
- IXGBE_ADVTXD_TUCMD_L4T_SCTP;
- break;
- default:
- if (unlikely(net_ratelimit())) {
- e_warn(probe, "partial checksum "
- "but proto=%x!\n",
- skb->protocol);
- }
- break;
- }
- }
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ type_tucmd_mlhl |= ixgbe_psum(adapter, skb);
context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
/* use index zero for tx checksum offload */
@@ -5893,9 +5994,9 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
}
static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring,
- struct sk_buff *skb, u32 tx_flags,
- unsigned int first)
+ struct ixgbe_ring *tx_ring,
+ struct sk_buff *skb, u32 tx_flags,
+ unsigned int first)
{
struct pci_dev *pdev = adapter->pdev;
struct ixgbe_tx_buffer *tx_buffer_info;
@@ -5990,7 +6091,7 @@ dma_error:
/* clear timestamp and dma mappings for remaining portion of packet */
while (count--) {
- if (i==0)
+ if (i == 0)
i += tx_ring->count;
i--;
tx_buffer_info = &tx_ring->tx_buffer_info[i];
@@ -6001,8 +6102,8 @@ dma_error:
}
static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring,
- int tx_flags, int count, u32 paylen, u8 hdr_len)
+ 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;
@@ -6021,17 +6122,17 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE;
olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
- IXGBE_ADVTXD_POPTS_SHIFT;
+ IXGBE_ADVTXD_POPTS_SHIFT;
/* 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;
+ IXGBE_ADVTXD_POPTS_SHIFT;
} else if (tx_flags & IXGBE_TX_FLAGS_CSUM)
olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
- IXGBE_ADVTXD_POPTS_SHIFT;
+ IXGBE_ADVTXD_POPTS_SHIFT;
if (tx_flags & IXGBE_TX_FLAGS_FCOE) {
olinfo_status |= IXGBE_ADVTXD_CC;
@@ -6045,10 +6146,10 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
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 = 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);
+ cpu_to_le32(cmd_type_len | tx_buffer_info->length);
tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
i++;
if (i == tx_ring->count)
@@ -6070,7 +6171,7 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
}
static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb,
- int queue, u32 tx_flags)
+ int queue, u32 tx_flags)
{
struct ixgbe_atr_input atr_input;
struct tcphdr *th;
@@ -6098,7 +6199,7 @@ static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb,
memset(&atr_input, 0, sizeof(struct ixgbe_atr_input));
vlan_id = (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK) >>
- IXGBE_TX_FLAGS_VLAN_SHIFT;
+ IXGBE_TX_FLAGS_VLAN_SHIFT;
src_ipv4_addr = iph->saddr;
dst_ipv4_addr = iph->daddr;
flex_bytes = eth->h_proto;
@@ -6117,7 +6218,7 @@ static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb,
}
static int __ixgbe_maybe_stop_tx(struct net_device *netdev,
- struct ixgbe_ring *tx_ring, int size)
+ struct ixgbe_ring *tx_ring, int size)
{
netif_stop_subqueue(netdev, tx_ring->queue_index);
/* Herbert's original patch had:
@@ -6137,7 +6238,7 @@ static int __ixgbe_maybe_stop_tx(struct net_device *netdev,
}
static int ixgbe_maybe_stop_tx(struct net_device *netdev,
- struct ixgbe_ring *tx_ring, int size)
+ struct ixgbe_ring *tx_ring, int size)
{
if (likely(IXGBE_DESC_UNUSED(tx_ring) >= size))
return 0;
@@ -6183,11 +6284,10 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
return skb_tx_hash(dev, skb);
}
-static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
- struct net_device *netdev)
+netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev,
+ struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring)
{
- struct ixgbe_adapter *adapter = netdev_priv(netdev);
- struct ixgbe_ring *tx_ring;
struct netdev_queue *txq;
unsigned int first;
unsigned int tx_flags = 0;
@@ -6196,7 +6296,7 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
int count = 0;
unsigned int f;
- if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+ 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;
@@ -6211,8 +6311,6 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
tx_flags |= IXGBE_TX_FLAGS_VLAN;
}
- tx_ring = adapter->tx_ring[skb->queue_mapping];
-
#ifdef IXGBE_FCOE
/* for FCoE with DCB, we force the priority to what
* was specified by the switch */
@@ -6283,10 +6381,10 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
if (tx_ring->atr_sample_rate) {
++tx_ring->atr_count;
if ((tx_ring->atr_count >= tx_ring->atr_sample_rate) &&
- test_bit(__IXGBE_FDIR_INIT_DONE,
- &tx_ring->reinit_state)) {
+ test_bit(__IXGBE_FDIR_INIT_DONE,
+ &tx_ring->reinit_state)) {
ixgbe_atr(adapter, skb, tx_ring->queue_index,
- tx_flags);
+ tx_flags);
tx_ring->atr_count = 0;
}
}
@@ -6294,7 +6392,7 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
txq->tx_bytes += skb->len;
txq->tx_packets++;
ixgbe_tx_queue(adapter, tx_ring, tx_flags, count, skb->len,
- hdr_len);
+ hdr_len);
ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED);
} else {
@@ -6306,6 +6404,15 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
return NETDEV_TX_OK;
}
+static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_ring *tx_ring;
+
+ tx_ring = adapter->tx_ring[skb->queue_mapping];
+ return ixgbe_xmit_frame_ring(skb, netdev, adapter, tx_ring);
+}
+
/**
* ixgbe_set_mac - Change the Ethernet Address of the NIC
* @netdev: network interface device structure
@@ -6436,8 +6543,40 @@ static void ixgbe_netpoll(struct net_device *netdev)
}
#endif
+static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ int i;
+
+ /* accurate rx/tx bytes/packets stats */
+ dev_txq_stats_fold(netdev, stats);
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ struct ixgbe_ring *ring = adapter->rx_ring[i];
+ u64 bytes, packets;
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin_bh(&ring->syncp);
+ packets = ring->stats.packets;
+ bytes = ring->stats.bytes;
+ } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+ stats->rx_packets += packets;
+ stats->rx_bytes += bytes;
+ }
+
+ /* following stats updated by ixgbe_watchdog_task() */
+ stats->multicast = netdev->stats.multicast;
+ stats->rx_errors = netdev->stats.rx_errors;
+ stats->rx_length_errors = netdev->stats.rx_length_errors;
+ stats->rx_crc_errors = netdev->stats.rx_crc_errors;
+ stats->rx_missed_errors = netdev->stats.rx_missed_errors;
+ return stats;
+}
+
+
static const struct net_device_ops ixgbe_netdev_ops = {
- .ndo_open = ixgbe_open,
+ .ndo_open = ixgbe_open,
.ndo_stop = ixgbe_close,
.ndo_start_xmit = ixgbe_xmit_frame,
.ndo_select_queue = ixgbe_select_queue,
@@ -6447,7 +6586,6 @@ static const struct net_device_ops ixgbe_netdev_ops = {
.ndo_set_mac_address = ixgbe_set_mac,
.ndo_change_mtu = ixgbe_change_mtu,
.ndo_tx_timeout = ixgbe_tx_timeout,
- .ndo_vlan_rx_register = ixgbe_vlan_rx_register,
.ndo_vlan_rx_add_vid = ixgbe_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = ixgbe_vlan_rx_kill_vid,
.ndo_do_ioctl = ixgbe_ioctl,
@@ -6455,6 +6593,7 @@ static const struct net_device_ops ixgbe_netdev_ops = {
.ndo_set_vf_vlan = ixgbe_ndo_set_vf_vlan,
.ndo_set_vf_tx_rate = ixgbe_ndo_set_vf_bw,
.ndo_get_vf_config = ixgbe_ndo_get_vf_config,
+ .ndo_get_stats64 = ixgbe_get_stats64,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ixgbe_netpoll,
#endif
@@ -6532,7 +6671,7 @@ err_novfs:
* and a hardware reset occur.
**/
static int __devinit ixgbe_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
struct net_device *netdev;
struct ixgbe_adapter *adapter = NULL;
@@ -6577,7 +6716,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
}
err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
- IORESOURCE_MEM), ixgbe_driver_name);
+ IORESOURCE_MEM), ixgbe_driver_name);
if (err) {
dev_err(&pdev->dev,
"pci_request_selected_regions failed 0x%x\n", err);
@@ -6617,7 +6756,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
hw->hw_addr = ioremap(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
+ pci_resource_len(pdev, 0));
if (!hw->hw_addr) {
err = -EIO;
goto err_ioremap;
@@ -6661,7 +6800,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
* which might start the timer
*/
init_timer(&adapter->sfp_timer);
- adapter->sfp_timer.function = &ixgbe_sfp_timer;
+ adapter->sfp_timer.function = ixgbe_sfp_timer;
adapter->sfp_timer.data = (unsigned long) adapter;
INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task);
@@ -6671,7 +6810,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
/* a new SFP+ module arrival, called from GPI SDP2 context */
INIT_WORK(&adapter->sfp_config_module_task,
- ixgbe_sfp_config_module_task);
+ ixgbe_sfp_config_module_task);
ii->get_invariants(hw);
@@ -6723,10 +6862,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
ixgbe_probe_vf(adapter, ii);
netdev->features = NETIF_F_SG |
- NETIF_F_IP_CSUM |
- NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER;
+ NETIF_F_IP_CSUM |
+ 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;
@@ -6766,8 +6905,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
netdev->vlan_features |= NETIF_F_FCOE_MTU;
}
#endif /* IXGBE_FCOE */
- if (pci_using_dac)
+ if (pci_using_dac) {
netdev->features |= NETIF_F_HIGHDMA;
+ netdev->vlan_features |= NETIF_F_HIGHDMA;
+ }
if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
netdev->features |= NETIF_F_LRO;
@@ -6793,7 +6934,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
hw->mac.ops.disable_tx_laser(hw);
init_timer(&adapter->watchdog_timer);
- adapter->watchdog_timer.function = &ixgbe_watchdog;
+ adapter->watchdog_timer.function = ixgbe_watchdog;
adapter->watchdog_timer.data = (unsigned long)adapter;
INIT_WORK(&adapter->reset_task, ixgbe_reset_task);
@@ -6806,7 +6947,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
switch (pdev->device) {
case IXGBE_DEV_ID_82599_KX4:
adapter->wol = (IXGBE_WUFC_MAG | IXGBE_WUFC_EX |
- IXGBE_WUFC_MC | IXGBE_WUFC_BC);
+ IXGBE_WUFC_MC | IXGBE_WUFC_BC);
break;
default:
adapter->wol = 0;
@@ -6819,13 +6960,14 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
/* print bus type/speed/width info */
e_dev_info("(PCI Express:%s:%s) %pM\n",
- ((hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0Gb/s":
- (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5Gb/s":"Unknown"),
- ((hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" :
- (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" :
- (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" :
- "Unknown"),
- netdev->dev_addr);
+ (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0Gb/s" :
+ hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5Gb/s" :
+ "Unknown"),
+ (hw->bus.width == ixgbe_bus_width_pcie_x8 ? "Width x8" :
+ hw->bus.width == ixgbe_bus_width_pcie_x4 ? "Width x4" :
+ hw->bus.width == ixgbe_bus_width_pcie_x1 ? "Width x1" :
+ "Unknown"),
+ netdev->dev_addr);
ixgbe_read_pba_num_generic(hw, &part_num);
if (ixgbe_is_sfp(hw) && hw->phy.sfp_type != ixgbe_sfp_type_not_present)
e_dev_info("MAC: %d, PHY: %d, SFP+: %d, "
@@ -6872,7 +7014,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
INIT_WORK(&adapter->fdir_reinit_task, ixgbe_fdir_reinit_task);
if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
- INIT_WORK(&adapter->check_overtemp_task, ixgbe_check_overtemp_task);
+ INIT_WORK(&adapter->check_overtemp_task,
+ ixgbe_check_overtemp_task);
#ifdef CONFIG_IXGBE_DCA
if (dca_add_requester(&pdev->dev) == 0) {
adapter->flags |= IXGBE_FLAG_DCA_ENABLED;
@@ -6908,8 +7051,8 @@ err_eeprom:
err_ioremap:
free_netdev(netdev);
err_alloc_etherdev:
- pci_release_selected_regions(pdev, pci_select_bars(pdev,
- IORESOURCE_MEM));
+ pci_release_selected_regions(pdev,
+ pci_select_bars(pdev, IORESOURCE_MEM));
err_pci_reg:
err_dma:
pci_disable_device(pdev);
@@ -6976,7 +7119,7 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
iounmap(adapter->hw.hw_addr);
pci_release_selected_regions(pdev, pci_select_bars(pdev,
- IORESOURCE_MEM));
+ IORESOURCE_MEM));
e_dev_info("complete\n");
@@ -6996,7 +7139,7 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
* this device has been detected.
*/
static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
- pci_channel_state_t state)
+ pci_channel_state_t state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -7102,8 +7245,7 @@ static struct pci_driver ixgbe_driver = {
static int __init ixgbe_init_module(void)
{
int ret;
- pr_info("%s - version %s\n", ixgbe_driver_string,
- ixgbe_driver_version);
+ pr_info("%s - version %s\n", ixgbe_driver_string, ixgbe_driver_version);
pr_info("%s\n", ixgbe_copyright);
#ifdef CONFIG_IXGBE_DCA
@@ -7132,12 +7274,12 @@ static void __exit ixgbe_exit_module(void)
#ifdef CONFIG_IXGBE_DCA
static int ixgbe_notify_dca(struct notifier_block *nb, unsigned long event,
- void *p)
+ void *p)
{
int ret_val;
ret_val = driver_for_each_device(&ixgbe_driver.driver, NULL, &event,
- __ixgbe_notify_dca);
+ __ixgbe_notify_dca);
return ret_val ? NOTIFY_BAD : NOTIFY_DONE;
}
diff --git a/drivers/net/ixgbe/ixgbe_mbx.c b/drivers/net/ixgbe/ixgbe_mbx.c
index d75f9148eb1f..471f0f2cdb98 100644
--- a/drivers/net/ixgbe/ixgbe_mbx.c
+++ b/drivers/net/ixgbe/ixgbe_mbx.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -200,7 +200,8 @@ out:
* returns SUCCESS if it successfully received a message notification and
* copied it into the receive buffer.
**/
-s32 ixgbe_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+static s32 ixgbe_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size,
+ u16 mbx_id)
{
struct ixgbe_mbx_info *mbx = &hw->mbx;
s32 ret_val = IXGBE_ERR_MBX;
@@ -227,7 +228,7 @@ out:
* returns SUCCESS if it successfully copied message into the buffer and
* received an ack to that message within delay * timeout period
**/
-s32 ixgbe_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size,
+static s32 ixgbe_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size,
u16 mbx_id)
{
struct ixgbe_mbx_info *mbx = &hw->mbx;
@@ -247,20 +248,6 @@ out:
return ret_val;
}
-/**
- * ixgbe_init_mbx_ops_generic - Initialize MB function pointers
- * @hw: pointer to the HW structure
- *
- * Setup the mailbox read and write message function pointers
- **/
-void ixgbe_init_mbx_ops_generic(struct ixgbe_hw *hw)
-{
- struct ixgbe_mbx_info *mbx = &hw->mbx;
-
- mbx->ops.read_posted = ixgbe_read_posted_mbx;
- mbx->ops.write_posted = ixgbe_write_posted_mbx;
-}
-
static s32 ixgbe_check_for_bit_pf(struct ixgbe_hw *hw, u32 mask, s32 index)
{
u32 mbvficr = IXGBE_READ_REG(hw, IXGBE_MBVFICR(index));
diff --git a/drivers/net/ixgbe/ixgbe_mbx.h b/drivers/net/ixgbe/ixgbe_mbx.h
index be7ab3309ab7..7e0d08ff5b53 100644
--- a/drivers/net/ixgbe/ixgbe_mbx.h
+++ b/drivers/net/ixgbe/ixgbe_mbx.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -83,12 +83,9 @@
s32 ixgbe_read_mbx(struct ixgbe_hw *, u32 *, u16, u16);
s32 ixgbe_write_mbx(struct ixgbe_hw *, u32 *, u16, u16);
-s32 ixgbe_read_posted_mbx(struct ixgbe_hw *, u32 *, u16, u16);
-s32 ixgbe_write_posted_mbx(struct ixgbe_hw *, u32 *, u16, u16);
s32 ixgbe_check_for_msg(struct ixgbe_hw *, u16);
s32 ixgbe_check_for_ack(struct ixgbe_hw *, u16);
s32 ixgbe_check_for_rst(struct ixgbe_hw *, u16);
-void ixgbe_init_mbx_ops_generic(struct ixgbe_hw *hw);
void ixgbe_init_mbx_params_pf(struct ixgbe_hw *);
extern struct ixgbe_mbx_operations mbx_ops_82599;
diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c
index 49661a138e22..5428153af8f3 100644
--- a/drivers/net/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ixgbe/ixgbe_sriov.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -43,8 +43,8 @@
#include "ixgbe_sriov.h"
-int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
- int entries, u16 *hash_list, u32 vf)
+static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
+ int entries, u16 *hash_list, u32 vf)
{
struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
struct ixgbe_hw *hw = &adapter->hw;
@@ -104,13 +104,14 @@ void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter)
}
}
-int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid, u32 vf)
+static int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid,
+ u32 vf)
{
return adapter->hw.mac.ops.set_vfta(&adapter->hw, vid, vf, (bool)add);
}
-void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf, bool aupe)
+static void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf, bool aupe)
{
u32 vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf));
vmolr |= (IXGBE_VMOLR_ROMPE |
@@ -134,7 +135,7 @@ static void ixgbe_set_vmvir(struct ixgbe_adapter *adapter, u32 vid, u32 vf)
IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf), 0);
}
-inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
+static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
{
struct ixgbe_hw *hw = &adapter->hw;
int rar_entry = hw->mac.num_rar_entries - (vf + 1);
@@ -162,8 +163,8 @@ inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
hw->mac.ops.clear_rar(hw, rar_entry);
}
-int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
- int vf, unsigned char *mac_addr)
+static int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
+ int vf, unsigned char *mac_addr)
{
struct ixgbe_hw *hw = &adapter->hw;
int rar_entry = hw->mac.num_rar_entries - (vf + 1);
@@ -197,7 +198,7 @@ int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask)
return 0;
}
-inline void ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf)
+static inline void ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf)
{
struct ixgbe_hw *hw = &adapter->hw;
u32 reg;
diff --git a/drivers/net/ixgbe/ixgbe_sriov.h b/drivers/net/ixgbe/ixgbe_sriov.h
index 184730ecdfb6..49dc14debef7 100644
--- a/drivers/net/ixgbe/ixgbe_sriov.h
+++ b/drivers/net/ixgbe/ixgbe_sriov.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -28,16 +28,8 @@
#ifndef _IXGBE_SRIOV_H_
#define _IXGBE_SRIOV_H_
-int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
- int entries, u16 *hash_list, u32 vf);
void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter);
-int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid, u32 vf);
-void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf, bool aupe);
-void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf);
-void ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf);
void ixgbe_msg_task(struct ixgbe_adapter *adapter);
-int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
- int vf, unsigned char *mac_addr);
int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask);
void ixgbe_disable_tx_rx(struct ixgbe_adapter *adapter);
void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter);
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index 9587d975d66c..d3cc6ce7c973 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -871,6 +871,8 @@
#define IXGBE_RDRXCTL_MVMEN 0x00000020
#define IXGBE_RDRXCTL_DMAIDONE 0x00000008 /* DMA init cycle done */
#define IXGBE_RDRXCTL_AGGDIS 0x00010000 /* Aggregation disable */
+#define IXGBE_RDRXCTL_RSCACKC 0x02000000 /* must set 1 when RSC enabled */
+#define IXGBE_RDRXCTL_FCOE_WRFIX 0x04000000 /* must set 1 when RSC enabled */
/* RQTC Bit Masks and Shifts */
#define IXGBE_RQTC_SHIFT_TC(_i) ((_i) * 4)
diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ixgbevf/ethtool.c
index 4680b069b84f..4cc817acfb62 100644
--- a/drivers/net/ixgbevf/ethtool.c
+++ b/drivers/net/ixgbevf/ethtool.c
@@ -330,10 +330,8 @@ static int ixgbevf_set_ringparam(struct net_device *netdev,
{
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
struct ixgbevf_ring *tx_ring = NULL, *rx_ring = NULL;
- int i, err;
+ int i, err = 0;
u32 new_rx_count, new_tx_count;
- bool need_tx_update = false;
- bool need_rx_update = false;
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL;
@@ -355,89 +353,96 @@ static int ixgbevf_set_ringparam(struct net_device *netdev,
while (test_and_set_bit(__IXGBEVF_RESETTING, &adapter->state))
msleep(1);
- if (new_tx_count != adapter->tx_ring_count) {
- tx_ring = kcalloc(adapter->num_tx_queues,
- sizeof(struct ixgbevf_ring), GFP_KERNEL);
- if (!tx_ring) {
- err = -ENOMEM;
- goto err_setup;
- }
- memcpy(tx_ring, adapter->tx_ring,
- adapter->num_tx_queues * sizeof(struct ixgbevf_ring));
- for (i = 0; i < adapter->num_tx_queues; i++) {
- tx_ring[i].count = new_tx_count;
- err = ixgbevf_setup_tx_resources(adapter,
- &tx_ring[i]);
- if (err) {
- while (i) {
- i--;
- ixgbevf_free_tx_resources(adapter,
- &tx_ring[i]);
- }
- kfree(tx_ring);
- goto err_setup;
- }
- tx_ring[i].v_idx = adapter->tx_ring[i].v_idx;
- }
- need_tx_update = true;
+ /*
+ * If the adapter isn't up and running then just set the
+ * new parameters and scurry for the exits.
+ */
+ if (!netif_running(adapter->netdev)) {
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ adapter->tx_ring[i].count = new_tx_count;
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ adapter->rx_ring[i].count = new_rx_count;
+ adapter->tx_ring_count = new_tx_count;
+ adapter->rx_ring_count = new_rx_count;
+ goto clear_reset;
}
- if (new_rx_count != adapter->rx_ring_count) {
- rx_ring = kcalloc(adapter->num_rx_queues,
- sizeof(struct ixgbevf_ring), GFP_KERNEL);
- if ((!rx_ring) && (need_tx_update)) {
- err = -ENOMEM;
- goto err_rx_setup;
- }
- memcpy(rx_ring, adapter->rx_ring,
- adapter->num_rx_queues * sizeof(struct ixgbevf_ring));
- for (i = 0; i < adapter->num_rx_queues; i++) {
- rx_ring[i].count = new_rx_count;
- err = ixgbevf_setup_rx_resources(adapter,
- &rx_ring[i]);
- if (err) {
- while (i) {
- i--;
- ixgbevf_free_rx_resources(adapter,
- &rx_ring[i]);
- }
- kfree(rx_ring);
- goto err_rx_setup;
- }
- rx_ring[i].v_idx = adapter->rx_ring[i].v_idx;
- }
- need_rx_update = true;
+ tx_ring = kcalloc(adapter->num_tx_queues,
+ sizeof(struct ixgbevf_ring), GFP_KERNEL);
+ if (!tx_ring) {
+ err = -ENOMEM;
+ goto clear_reset;
}
-err_rx_setup:
- /* if rings need to be updated, here's the place to do it in one shot */
- if (need_tx_update || need_rx_update) {
- if (netif_running(netdev))
- ixgbevf_down(adapter);
+ rx_ring = kcalloc(adapter->num_rx_queues,
+ sizeof(struct ixgbevf_ring), GFP_KERNEL);
+ if (!rx_ring) {
+ err = -ENOMEM;
+ goto err_rx_setup;
}
- /* tx */
- if (need_tx_update) {
- kfree(adapter->tx_ring);
- adapter->tx_ring = tx_ring;
- tx_ring = NULL;
- adapter->tx_ring_count = new_tx_count;
+ ixgbevf_down(adapter);
+
+ memcpy(tx_ring, adapter->tx_ring,
+ adapter->num_tx_queues * sizeof(struct ixgbevf_ring));
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ tx_ring[i].count = new_tx_count;
+ err = ixgbevf_setup_tx_resources(adapter, &tx_ring[i]);
+ if (err) {
+ while (i) {
+ i--;
+ ixgbevf_free_tx_resources(adapter,
+ &tx_ring[i]);
+ }
+ goto err_tx_ring_setup;
+ }
+ tx_ring[i].v_idx = adapter->tx_ring[i].v_idx;
}
- /* rx */
- if (need_rx_update) {
- kfree(adapter->rx_ring);
- adapter->rx_ring = rx_ring;
- rx_ring = NULL;
- adapter->rx_ring_count = new_rx_count;
+ memcpy(rx_ring, adapter->rx_ring,
+ adapter->num_rx_queues * sizeof(struct ixgbevf_ring));
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ rx_ring[i].count = new_rx_count;
+ err = ixgbevf_setup_rx_resources(adapter, &rx_ring[i]);
+ if (err) {
+ while (i) {
+ i--;
+ ixgbevf_free_rx_resources(adapter,
+ &rx_ring[i]);
+ }
+ goto err_rx_ring_setup;
+ }
+ rx_ring[i].v_idx = adapter->rx_ring[i].v_idx;
}
+ /*
+ * Only switch to new rings if all the prior allocations
+ * and ring setups have succeeded.
+ */
+ kfree(adapter->tx_ring);
+ adapter->tx_ring = tx_ring;
+ adapter->tx_ring_count = new_tx_count;
+
+ kfree(adapter->rx_ring);
+ adapter->rx_ring = rx_ring;
+ adapter->rx_ring_count = new_rx_count;
+
/* success! */
- err = 0;
- if (netif_running(netdev))
- ixgbevf_up(adapter);
+ ixgbevf_up(adapter);
+
+ goto clear_reset;
+
+err_rx_ring_setup:
+ for(i = 0; i < adapter->num_tx_queues; i++)
+ ixgbevf_free_tx_resources(adapter, &tx_ring[i]);
+
+err_tx_ring_setup:
+ kfree(rx_ring);
+
+err_rx_setup:
+ kfree(tx_ring);
-err_setup:
+clear_reset:
clear_bit(__IXGBEVF_RESETTING, &adapter->state);
return err;
}
diff --git a/drivers/net/ixgbevf/ixgbevf.h b/drivers/net/ixgbevf/ixgbevf.h
index f7015efbff05..da4033c6efa2 100644
--- a/drivers/net/ixgbevf/ixgbevf.h
+++ b/drivers/net/ixgbevf/ixgbevf.h
@@ -243,7 +243,6 @@ struct ixgbevf_adapter {
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
- struct net_device_stats net_stats;
/* structs defined in ixgbe_vf.h */
struct ixgbe_hw hw;
diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c
index 918c00359b0a..dc03c9652389 100644
--- a/drivers/net/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ixgbevf/ixgbevf_main.c
@@ -308,10 +308,10 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter,
tx_ring->total_bytes += total_bytes;
tx_ring->total_packets += total_packets;
- adapter->net_stats.tx_bytes += total_bytes;
- adapter->net_stats.tx_packets += total_packets;
+ netdev->stats.tx_bytes += total_bytes;
+ netdev->stats.tx_packets += total_packets;
- return (count < tx_ring->work_limit);
+ return count < tx_ring->work_limit;
}
/**
@@ -356,7 +356,7 @@ static void ixgbevf_receive_skb(struct ixgbevf_q_vector *q_vector,
static inline void ixgbevf_rx_checksum(struct ixgbevf_adapter *adapter,
u32 status_err, struct sk_buff *skb)
{
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
/* Rx csum disabled */
if (!(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
@@ -639,8 +639,8 @@ next_desc:
rx_ring->total_packets += total_rx_packets;
rx_ring->total_bytes += total_rx_bytes;
- adapter->net_stats.rx_bytes += total_rx_bytes;
- adapter->net_stats.rx_packets += total_rx_packets;
+ adapter->netdev->stats.rx_bytes += total_rx_bytes;
+ adapter->netdev->stats.rx_packets += total_rx_packets;
return cleaned;
}
@@ -1495,7 +1495,7 @@ static void ixgbevf_restore_vlan(struct ixgbevf_adapter *adapter)
if (adapter->vlgrp) {
u16 vid;
- for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ for (vid = 0; vid < VLAN_N_VID; vid++) {
if (!vlan_group_get_device(adapter->vlgrp, vid))
continue;
ixgbevf_vlan_rx_add_vid(adapter->netdev, vid);
@@ -2297,7 +2297,7 @@ void ixgbevf_update_stats(struct ixgbevf_adapter *adapter)
adapter->stats.vfmprc);
/* Fill out the OS statistics structure */
- adapter->net_stats.multicast = adapter->stats.vfmprc -
+ adapter->netdev->stats.multicast = adapter->stats.vfmprc -
adapter->stats.base_vfmprc;
}
@@ -3134,7 +3134,7 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
tx_ring = &adapter->tx_ring[r_idx];
- if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+ if (vlan_tx_tag_present(skb)) {
tx_flags |= vlan_tx_tag_get(skb);
tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
tx_flags |= IXGBE_TX_FLAGS_VLAN;
@@ -3181,21 +3181,6 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
}
/**
- * ixgbevf_get_stats - Get System Network Statistics
- * @netdev: network interface device structure
- *
- * Returns the address of the device statistics structure.
- * The statistics are actually updated from the timer callback.
- **/
-static struct net_device_stats *ixgbevf_get_stats(struct net_device *netdev)
-{
- struct ixgbevf_adapter *adapter = netdev_priv(netdev);
-
- /* only return the current stats */
- return &adapter->net_stats;
-}
-
-/**
* ixgbevf_set_mac - Change the Ethernet Address of the NIC
* @netdev: network interface device structure
* @p: pointer to an address structure
@@ -3272,7 +3257,6 @@ static const struct net_device_ops ixgbe_netdev_ops = {
.ndo_open = &ixgbevf_open,
.ndo_stop = &ixgbevf_close,
.ndo_start_xmit = &ixgbevf_xmit_frame,
- .ndo_get_stats = &ixgbevf_get_stats,
.ndo_set_rx_mode = &ixgbevf_set_rx_mode,
.ndo_set_multicast_list = &ixgbevf_set_rx_mode,
.ndo_validate_addr = eth_validate_addr,
@@ -3426,7 +3410,7 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
}
init_timer(&adapter->watchdog_timer);
- adapter->watchdog_timer.function = &ixgbevf_watchdog;
+ adapter->watchdog_timer.function = ixgbevf_watchdog;
adapter->watchdog_timer.data = (unsigned long)adapter;
INIT_WORK(&adapter->reset_task, ixgbevf_reset_task);
diff --git a/drivers/net/ixgbevf/mbx.c b/drivers/net/ixgbevf/mbx.c
index b8143501e6fc..84ac486f4a65 100644
--- a/drivers/net/ixgbevf/mbx.c
+++ b/drivers/net/ixgbevf/mbx.c
@@ -308,7 +308,7 @@ out_no_read:
*
* Initializes the hw->mbx struct to correct values for vf mailbox
*/
-s32 ixgbevf_init_mbx_params_vf(struct ixgbe_hw *hw)
+static s32 ixgbevf_init_mbx_params_vf(struct ixgbe_hw *hw)
{
struct ixgbe_mbx_info *mbx = &hw->mbx;
diff --git a/drivers/net/ixgbevf/mbx.h b/drivers/net/ixgbevf/mbx.h
index 1b0e0bf4c0f5..8c063bebee7f 100644
--- a/drivers/net/ixgbevf/mbx.h
+++ b/drivers/net/ixgbevf/mbx.h
@@ -95,6 +95,4 @@
/* forward declaration of the HW struct */
struct ixgbe_hw;
-s32 ixgbevf_init_mbx_params_vf(struct ixgbe_hw *);
-
#endif /* _IXGBE_MBX_H_ */
diff --git a/drivers/net/ixgbevf/vf.c b/drivers/net/ixgbevf/vf.c
index f6f929958ba0..bfe42c1fcfaf 100644
--- a/drivers/net/ixgbevf/vf.c
+++ b/drivers/net/ixgbevf/vf.c
@@ -368,7 +368,7 @@ static s32 ixgbevf_check_mac_link_vf(struct ixgbe_hw *hw,
return 0;
}
-struct ixgbe_mac_operations ixgbevf_mac_ops = {
+static struct ixgbe_mac_operations ixgbevf_mac_ops = {
.init_hw = ixgbevf_init_hw_vf,
.reset_hw = ixgbevf_reset_hw_vf,
.start_hw = ixgbevf_start_hw_vf,
diff --git a/drivers/net/ixgbevf/vf.h b/drivers/net/ixgbevf/vf.h
index 94b750b8874f..61f9dc831424 100644
--- a/drivers/net/ixgbevf/vf.h
+++ b/drivers/net/ixgbevf/vf.h
@@ -124,8 +124,6 @@ struct ixgbe_hw {
void *back;
u8 __iomem *hw_addr;
- u8 *flash_address;
- unsigned long io_base;
struct ixgbe_mac_info mac;
struct ixgbe_mbx_info mbx;
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 99f24f5cac53..d85edf3119c2 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -3,6 +3,7 @@
*
* Copyright 2008 JMicron Technology Corporation
* http://www.jmicron.com/
+ * Copyright (c) 2009 - 2010 Guo-Fu Tseng <cooldavid@cooldavid.org>
*
* Author: Guo-Fu Tseng <cooldavid@cooldavid.org>
*
@@ -21,6 +22,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -73,7 +76,7 @@ read_again:
}
if (i == 0) {
- jeprintk(jme->pdev, "phy(%d) read timeout : %d\n", phy, reg);
+ pr_err("phy(%d) read timeout : %d\n", phy, reg);
return 0;
}
@@ -102,7 +105,7 @@ jme_mdio_write(struct net_device *netdev,
}
if (i == 0)
- jeprintk(jme->pdev, "phy(%d) write timeout : %d\n", phy, reg);
+ pr_err("phy(%d) write timeout : %d\n", phy, reg);
}
static inline void
@@ -227,7 +230,7 @@ jme_reload_eeprom(struct jme_adapter *jme)
}
if (i == 0) {
- jeprintk(jme->pdev, "eeprom reload timeout\n");
+ pr_err("eeprom reload timeout\n");
return -EIO;
}
}
@@ -397,8 +400,7 @@ jme_check_link(struct net_device *netdev, int testonly)
phylink = jread32(jme, JME_PHY_LINK);
}
if (!cnt)
- jeprintk(jme->pdev,
- "Waiting speed resolve timeout.\n");
+ pr_err("Waiting speed resolve timeout\n");
strcat(linkmsg, "ANed: ");
}
@@ -480,13 +482,13 @@ jme_check_link(struct net_device *netdev, int testonly)
strcat(linkmsg, (phylink & PHY_LINK_MDI_STAT) ?
"MDI-X" :
"MDI");
- netif_info(jme, link, jme->dev, "Link is up at %s.\n", linkmsg);
+ netif_info(jme, link, jme->dev, "Link is up at %s\n", linkmsg);
netif_carrier_on(netdev);
} else {
if (testonly)
goto out;
- netif_info(jme, link, jme->dev, "Link is down.\n");
+ netif_info(jme, link, jme->dev, "Link is down\n");
jme->phylink = 0;
netif_carrier_off(netdev);
}
@@ -648,7 +650,7 @@ jme_disable_tx_engine(struct jme_adapter *jme)
}
if (!i)
- jeprintk(jme->pdev, "Disable TX engine timeout.\n");
+ pr_err("Disable TX engine timeout\n");
}
static void
@@ -867,7 +869,7 @@ jme_disable_rx_engine(struct jme_adapter *jme)
}
if (!i)
- jeprintk(jme->pdev, "Disable RX engine timeout.\n");
+ pr_err("Disable RX engine timeout\n");
}
@@ -887,13 +889,13 @@ jme_rxsum_ok(struct jme_adapter *jme, u16 flags)
if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_UDPON | RXWBFLAG_UDPCS))
== RXWBFLAG_UDPON)) {
if (flags & RXWBFLAG_IPV4)
- netif_err(jme, rx_err, jme->dev, "UDP Checksum error.\n");
+ netif_err(jme, rx_err, jme->dev, "UDP Checksum error\n");
return false;
}
if (unlikely((flags & (RXWBFLAG_IPV4 | RXWBFLAG_IPCS))
== RXWBFLAG_IPV4)) {
- netif_err(jme, rx_err, jme->dev, "IPv4 Checksum error.\n");
+ netif_err(jme, rx_err, jme->dev, "IPv4 Checksum error\n");
return false;
}
@@ -936,7 +938,7 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx)
if (jme_rxsum_ok(jme, le16_to_cpu(rxdesc->descwb.flags)))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
if (rxdesc->descwb.flags & cpu_to_le16(RXWBFLAG_TAGON)) {
if (jme->vlgrp) {
@@ -988,6 +990,7 @@ jme_process_receive(struct jme_adapter *jme, int limit)
goto out;
--limit;
+ rmb();
desccnt = rxdesc->descwb.desccnt & RXWBDCNT_DCNT;
if (unlikely(desccnt > 1 ||
@@ -1185,9 +1188,9 @@ jme_link_change_tasklet(unsigned long arg)
while (!atomic_dec_and_test(&jme->link_changing)) {
atomic_inc(&jme->link_changing);
- netif_info(jme, intr, jme->dev, "Get link change lock failed.\n");
+ netif_info(jme, intr, jme->dev, "Get link change lock failed\n");
while (atomic_read(&jme->link_changing) != 1)
- netif_info(jme, intr, jme->dev, "Waiting link change lock.\n");
+ netif_info(jme, intr, jme->dev, "Waiting link change lock\n");
}
if (jme_check_link(netdev, 1) && jme->old_mtu == netdev->mtu)
@@ -1221,15 +1224,13 @@ jme_link_change_tasklet(unsigned long arg)
if (netif_carrier_ok(netdev)) {
rc = jme_setup_rx_resources(jme);
if (rc) {
- jeprintk(jme->pdev, "Allocating resources for RX error"
- ", Device STOPPED!\n");
+ pr_err("Allocating resources for RX error, Device STOPPED!\n");
goto out_enable_tasklet;
}
rc = jme_setup_tx_resources(jme);
if (rc) {
- jeprintk(jme->pdev, "Allocating resources for TX error"
- ", Device STOPPED!\n");
+ pr_err("Allocating resources for TX error, Device STOPPED!\n");
goto err_out_free_rx_resources;
}
@@ -1324,7 +1325,7 @@ jme_wake_queue_if_stopped(struct jme_adapter *jme)
smp_wmb();
if (unlikely(netif_queue_stopped(jme->dev) &&
atomic_read(&txring->nr_free) >= (jme->tx_wake_threshold))) {
- netif_info(jme, tx_done, jme->dev, "TX Queue Waked.\n");
+ netif_info(jme, tx_done, jme->dev, "TX Queue Waked\n");
netif_wake_queue(jme->dev);
}
@@ -1339,7 +1340,7 @@ jme_tx_clean_tasklet(unsigned long arg)
struct jme_buffer_info *txbi = txring->bufinf, *ctxbi, *ttxbi;
int i, j, cnt = 0, max, err, mask;
- tx_dbg(jme, "Into txclean.\n");
+ tx_dbg(jme, "Into txclean\n");
if (unlikely(!atomic_dec_and_test(&jme->tx_cleaning)))
goto out;
@@ -1361,7 +1362,7 @@ jme_tx_clean_tasklet(unsigned long arg)
!(txdesc[i].descwb.flags & TXWBFLAG_OWN))) {
tx_dbg(jme, "txclean: %d+%d@%lu\n",
- i, ctxbi->nr_desc, jiffies);
+ i, ctxbi->nr_desc, jiffies);
err = txdesc[i].descwb.flags & TXWBFLAG_ALLERR;
@@ -1402,7 +1403,7 @@ jme_tx_clean_tasklet(unsigned long arg)
ctxbi->nr_desc = 0;
}
- tx_dbg(jme, "txclean: done %d@%lu.\n", i, jiffies);
+ tx_dbg(jme, "txclean: done %d@%lu\n", i, jiffies);
atomic_set(&txring->next_to_clean, i);
atomic_add(cnt, &txring->nr_free);
@@ -1548,10 +1549,10 @@ jme_request_irq(struct jme_adapter *jme)
rc = request_irq(jme->pdev->irq, handler, irq_flags, netdev->name,
netdev);
if (rc) {
- jeprintk(jme->pdev,
- "Unable to request %s interrupt (return: %d)\n",
- test_bit(JME_FLAG_MSI, &jme->flags) ? "MSI" : "INTx",
- rc);
+ netdev_err(netdev,
+ "Unable to request %s interrupt (return: %d)\n",
+ test_bit(JME_FLAG_MSI, &jme->flags) ? "MSI" : "INTx",
+ rc);
if (test_bit(JME_FLAG_MSI, &jme->flags)) {
pci_disable_msi(jme->pdev);
@@ -1575,6 +1576,16 @@ jme_free_irq(struct jme_adapter *jme)
}
}
+static inline void
+jme_phy_on(struct jme_adapter *jme)
+{
+ u32 bmcr;
+
+ bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR);
+ bmcr &= ~BMCR_PDOWN;
+ jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr);
+}
+
static int
jme_open(struct net_device *netdev)
{
@@ -1595,10 +1606,12 @@ jme_open(struct net_device *netdev)
jme_start_irq(jme);
- if (test_bit(JME_FLAG_SSET, &jme->flags))
+ if (test_bit(JME_FLAG_SSET, &jme->flags)) {
+ jme_phy_on(jme);
jme_set_settings(netdev, &jme->old_ecmd);
- else
+ } else {
jme_reset_phy_processor(jme);
+ }
jme_reset_link(jme);
@@ -1610,12 +1623,12 @@ err_out:
return rc;
}
-#ifdef CONFIG_PM
static void
jme_set_100m_half(struct jme_adapter *jme)
{
u32 bmcr, tmp;
+ jme_phy_on(jme);
bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR);
tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
BMCR_SPEED1000 | BMCR_FULLDPLX);
@@ -1643,7 +1656,6 @@ jme_wait_link(struct jme_adapter *jme)
phylink = jme_linkstat_from_phy(jme);
}
}
-#endif
static inline void
jme_phy_off(struct jme_adapter *jme)
@@ -1651,6 +1663,21 @@ jme_phy_off(struct jme_adapter *jme)
jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, BMCR_PDOWN);
}
+static void
+jme_powersave_phy(struct jme_adapter *jme)
+{
+ if (jme->reg_pmcs) {
+ jme_set_100m_half(jme);
+
+ if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
+ jme_wait_link(jme);
+
+ jwrite32(jme, JME_PMCS, jme->reg_pmcs);
+ } else {
+ jme_phy_off(jme);
+ }
+}
+
static int
jme_close(struct net_device *netdev)
{
@@ -1834,7 +1861,7 @@ jme_tx_csum(struct jme_adapter *jme, struct sk_buff *skb, u8 *flags)
*flags |= TXFLAG_UDPCS;
break;
default:
- netif_err(jme, tx_err, jme->dev, "Error upper layer protocol.\n");
+ netif_err(jme, tx_err, jme->dev, "Error upper layer protocol\n");
break;
}
}
@@ -1909,12 +1936,12 @@ jme_stop_queue_if_full(struct jme_adapter *jme)
smp_wmb();
if (unlikely(atomic_read(&txring->nr_free) < (MAX_SKB_FRAGS+2))) {
netif_stop_queue(jme->dev);
- netif_info(jme, tx_queued, jme->dev, "TX Queue Paused.\n");
+ netif_info(jme, tx_queued, jme->dev, "TX Queue Paused\n");
smp_wmb();
if (atomic_read(&txring->nr_free)
>= (jme->tx_wake_threshold)) {
netif_wake_queue(jme->dev);
- netif_info(jme, tx_queued, jme->dev, "TX Queue Fast Waked.\n");
+ netif_info(jme, tx_queued, jme->dev, "TX Queue Fast Waked\n");
}
}
@@ -1922,7 +1949,8 @@ jme_stop_queue_if_full(struct jme_adapter *jme)
(jiffies - txbi->start_xmit) >= TX_TIMEOUT &&
txbi->skb)) {
netif_stop_queue(jme->dev);
- netif_info(jme, tx_queued, jme->dev, "TX Queue Stopped %d@%lu.\n", idx, jiffies);
+ netif_info(jme, tx_queued, jme->dev,
+ "TX Queue Stopped %d@%lu\n", idx, jiffies);
}
}
@@ -1945,7 +1973,8 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev)
if (unlikely(idx < 0)) {
netif_stop_queue(netdev);
- netif_err(jme, tx_err, jme->dev, "BUG! Tx ring full when queue awake!\n");
+ netif_err(jme, tx_err, jme->dev,
+ "BUG! Tx ring full when queue awake!\n");
return NETDEV_TX_BUSY;
}
@@ -1957,9 +1986,8 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev)
TXCS_QUEUE0S |
TXCS_ENABLE);
- tx_dbg(jme, "xmit: %d+%d@%lu\n", idx,
- skb_shinfo(skb)->nr_frags + 2,
- jiffies);
+ tx_dbg(jme, "xmit: %d+%d@%lu\n",
+ idx, skb_shinfo(skb)->nr_frags + 2, jiffies);
jme_stop_queue_if_full(jme);
return NETDEV_TX_OK;
@@ -2382,6 +2410,10 @@ jme_set_settings(struct net_device *netdev,
if (ecmd->speed == SPEED_1000 && ecmd->autoneg != AUTONEG_ENABLE)
return -EINVAL;
+ /*
+ * Check If user changed duplex only while force_media.
+ * Hardware would not generate link change interrupt.
+ */
if (jme->mii_if.force_media &&
ecmd->autoneg != AUTONEG_ENABLE &&
(jme->mii_if.full_duplex != ecmd->duplex))
@@ -2391,12 +2423,40 @@ jme_set_settings(struct net_device *netdev,
rc = mii_ethtool_sset(&(jme->mii_if), ecmd);
spin_unlock_bh(&jme->phy_lock);
- if (!rc && fdc)
- jme_reset_link(jme);
-
if (!rc) {
- set_bit(JME_FLAG_SSET, &jme->flags);
+ if (fdc)
+ jme_reset_link(jme);
jme->old_ecmd = *ecmd;
+ set_bit(JME_FLAG_SSET, &jme->flags);
+ }
+
+ return rc;
+}
+
+static int
+jme_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+ int rc;
+ struct jme_adapter *jme = netdev_priv(netdev);
+ struct mii_ioctl_data *mii_data = if_mii(rq);
+ unsigned int duplex_chg;
+
+ if (cmd == SIOCSMIIREG) {
+ u16 val = mii_data->val_in;
+ if (!(val & (BMCR_RESET|BMCR_ANENABLE)) &&
+ (val & BMCR_SPEED1000))
+ return -EINVAL;
+ }
+
+ spin_lock_bh(&jme->phy_lock);
+ rc = generic_mii_ioctl(&jme->mii_if, mii_data, cmd, &duplex_chg);
+ spin_unlock_bh(&jme->phy_lock);
+
+ if (!rc && (cmd == SIOCSMIIREG)) {
+ if (duplex_chg)
+ jme_reset_link(jme);
+ jme_get_settings(netdev, &jme->old_ecmd);
+ set_bit(JME_FLAG_SSET, &jme->flags);
}
return rc;
@@ -2501,7 +2561,7 @@ jme_smb_read(struct jme_adapter *jme, unsigned int addr)
val = jread32(jme, JME_SMBCSR);
}
if (!to) {
- netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n");
+ netif_err(jme, hw, jme->dev, "SMB Bus Busy\n");
return 0xFF;
}
@@ -2517,7 +2577,7 @@ jme_smb_read(struct jme_adapter *jme, unsigned int addr)
val = jread32(jme, JME_SMBINTF);
}
if (!to) {
- netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n");
+ netif_err(jme, hw, jme->dev, "SMB Bus Busy\n");
return 0xFF;
}
@@ -2537,7 +2597,7 @@ jme_smb_write(struct jme_adapter *jme, unsigned int addr, u8 data)
val = jread32(jme, JME_SMBCSR);
}
if (!to) {
- netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n");
+ netif_err(jme, hw, jme->dev, "SMB Bus Busy\n");
return;
}
@@ -2554,7 +2614,7 @@ jme_smb_write(struct jme_adapter *jme, unsigned int addr, u8 data)
val = jread32(jme, JME_SMBINTF);
}
if (!to) {
- netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n");
+ netif_err(jme, hw, jme->dev, "SMB Bus Busy\n");
return;
}
@@ -2676,6 +2736,7 @@ static const struct net_device_ops jme_netdev_ops = {
.ndo_open = jme_open,
.ndo_stop = jme_close,
.ndo_validate_addr = eth_validate_addr,
+ .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,
@@ -2699,26 +2760,26 @@ jme_init_one(struct pci_dev *pdev,
*/
rc = pci_enable_device(pdev);
if (rc) {
- jeprintk(pdev, "Cannot enable PCI device.\n");
+ pr_err("Cannot enable PCI device\n");
goto err_out;
}
using_dac = jme_pci_dma64(pdev);
if (using_dac < 0) {
- jeprintk(pdev, "Cannot set PCI DMA Mask.\n");
+ pr_err("Cannot set PCI DMA Mask\n");
rc = -EIO;
goto err_out_disable_pdev;
}
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- jeprintk(pdev, "No PCI resource region found.\n");
+ pr_err("No PCI resource region found\n");
rc = -ENOMEM;
goto err_out_disable_pdev;
}
rc = pci_request_regions(pdev, DRV_NAME);
if (rc) {
- jeprintk(pdev, "Cannot obtain PCI resource region.\n");
+ pr_err("Cannot obtain PCI resource region\n");
goto err_out_disable_pdev;
}
@@ -2729,7 +2790,7 @@ jme_init_one(struct pci_dev *pdev,
*/
netdev = alloc_etherdev(sizeof(*jme));
if (!netdev) {
- jeprintk(pdev, "Cannot allocate netdev structure.\n");
+ pr_err("Cannot allocate netdev structure\n");
rc = -ENOMEM;
goto err_out_release_regions;
}
@@ -2767,7 +2828,7 @@ jme_init_one(struct pci_dev *pdev,
jme->regs = ioremap(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (!(jme->regs)) {
- jeprintk(pdev, "Mapping PCI resource region error.\n");
+ pr_err("Mapping PCI resource region error\n");
rc = -ENOMEM;
goto err_out_free_netdev;
}
@@ -2855,8 +2916,8 @@ jme_init_one(struct pci_dev *pdev,
if (!jme->mii_if.phy_id) {
rc = -EIO;
- jeprintk(pdev, "Can not find phy_id.\n");
- goto err_out_unmap;
+ pr_err("Can not find phy_id\n");
+ goto err_out_unmap;
}
jme->reg_ghc |= GHC_LINK_POLL;
@@ -2867,6 +2928,8 @@ jme_init_one(struct pci_dev *pdev,
jme->mii_if.supports_gmii = true;
else
jme->mii_if.supports_gmii = false;
+ jme->mii_if.phy_id_mask = 0x1F;
+ jme->mii_if.reg_num_mask = 0x1F;
jme->mii_if.mdio_read = jme_mdio_read;
jme->mii_if.mdio_write = jme_mdio_write;
@@ -2883,8 +2946,7 @@ jme_init_one(struct pci_dev *pdev,
jme_reset_mac_processor(jme);
rc = jme_reload_eeprom(jme);
if (rc) {
- jeprintk(pdev,
- "Reload eeprom for reading MAC Address error.\n");
+ pr_err("Reload eeprom for reading MAC Address error\n");
goto err_out_unmap;
}
jme_load_macaddr(netdev);
@@ -2900,7 +2962,7 @@ jme_init_one(struct pci_dev *pdev,
*/
rc = register_netdev(netdev);
if (rc) {
- jeprintk(pdev, "Cannot register net device.\n");
+ pr_err("Cannot register net device\n");
goto err_out_unmap;
}
@@ -2943,6 +3005,16 @@ jme_remove_one(struct pci_dev *pdev)
}
+static void
+jme_shutdown(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct jme_adapter *jme = netdev_priv(netdev);
+
+ jme_powersave_phy(jme);
+ pci_pme_active(pdev, true);
+}
+
#ifdef CONFIG_PM
static int
jme_suspend(struct pci_dev *pdev, pm_message_t state)
@@ -2980,19 +3052,9 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state)
tasklet_hi_enable(&jme->rxempty_task);
pci_save_state(pdev);
- if (jme->reg_pmcs) {
- jme_set_100m_half(jme);
-
- if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
- jme_wait_link(jme);
-
- jwrite32(jme, JME_PMCS, jme->reg_pmcs);
-
- pci_enable_wake(pdev, PCI_D3cold, true);
- } else {
- jme_phy_off(jme);
- }
- pci_set_power_state(pdev, PCI_D3cold);
+ jme_powersave_phy(jme);
+ pci_enable_wake(jme->pdev, PCI_D3hot, true);
+ pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
@@ -3006,10 +3068,12 @@ jme_resume(struct pci_dev *pdev)
jme_clear_pm(jme);
pci_restore_state(pdev);
- if (test_bit(JME_FLAG_SSET, &jme->flags))
+ if (test_bit(JME_FLAG_SSET, &jme->flags)) {
+ jme_phy_on(jme);
jme_set_settings(netdev, &jme->old_ecmd);
- else
+ } else {
jme_reset_phy_processor(jme);
+ }
jme_start_irq(jme);
netif_device_attach(netdev);
@@ -3037,13 +3101,13 @@ static struct pci_driver jme_driver = {
.suspend = jme_suspend,
.resume = jme_resume,
#endif /* CONFIG_PM */
+ .shutdown = jme_shutdown,
};
static int __init
jme_init_module(void)
{
- printk(KERN_INFO PFX "JMicron JMC2XX ethernet "
- "driver version %s\n", DRV_VERSION);
+ pr_info("JMicron JMC2XX ethernet driver version %s\n", DRV_VERSION);
return pci_register_driver(&jme_driver);
}
diff --git a/drivers/net/jme.h b/drivers/net/jme.h
index 07ad3a457185..eac09264bf2a 100644
--- a/drivers/net/jme.h
+++ b/drivers/net/jme.h
@@ -3,6 +3,7 @@
*
* Copyright 2008 JMicron Technology Corporation
* http://www.jmicron.com/
+ * Copyright (c) 2009 - 2010 Guo-Fu Tseng <cooldavid@cooldavid.org>
*
* Author: Guo-Fu Tseng <cooldavid@cooldavid.org>
*
@@ -25,7 +26,7 @@
#define __JME_H_INCLUDED__
#define DRV_NAME "jme"
-#define DRV_VERSION "1.0.6"
+#define DRV_VERSION "1.0.7"
#define PFX DRV_NAME ": "
#define PCI_DEVICE_ID_JMICRON_JMC250 0x0250
@@ -41,9 +42,6 @@
NETIF_MSG_TX_ERR | \
NETIF_MSG_HW)
-#define jeprintk(pdev, fmt, args...) \
- printk(KERN_ERR PFX fmt, ## args)
-
#ifdef TX_DEBUG
#define tx_dbg(priv, fmt, args...) \
printk(KERN_DEBUG "%s: " fmt, (priv)->dev->name, ##args)
diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c
index 87f0a93b165c..9f8e7027b0b3 100644
--- a/drivers/net/ll_temac_main.c
+++ b/drivers/net/ll_temac_main.c
@@ -495,7 +495,7 @@ static u32 temac_setoptions(struct net_device *ndev, u32 options)
lp->options |= options;
mutex_unlock(&lp->indirect_mutex);
- return (0);
+ return 0;
}
/* Initialize temac */
@@ -761,7 +761,7 @@ static void ll_temac_recv(struct net_device *ndev)
skb_put(skb, length);
skb->dev = ndev;
skb->protocol = eth_type_trans(skb, ndev);
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
/* if we're doing rx csum offload, set it up */
if (((lp->temac_features & TEMAC_FEATURE_RX_CSUM) != 0) &&
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 9a0996795321..2d9663a1c54d 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -64,7 +64,6 @@ struct pcpu_lstats {
u64 packets;
u64 bytes;
struct u64_stats_sync syncp;
- unsigned long drops;
};
/*
@@ -74,7 +73,6 @@ struct pcpu_lstats {
static netdev_tx_t loopback_xmit(struct sk_buff *skb,
struct net_device *dev)
{
- struct pcpu_lstats __percpu *pcpu_lstats;
struct pcpu_lstats *lb_stats;
int len;
@@ -83,8 +81,7 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
skb->protocol = eth_type_trans(skb, dev);
/* it's OK to use per_cpu_ptr() because BHs are off */
- pcpu_lstats = (void __percpu __force *)dev->ml_priv;
- lb_stats = this_cpu_ptr(pcpu_lstats);
+ lb_stats = this_cpu_ptr(dev->lstats);
len = skb->len;
if (likely(netif_rx(skb) == NET_RX_SUCCESS)) {
@@ -92,8 +89,7 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
lb_stats->bytes += len;
lb_stats->packets++;
u64_stats_update_end(&lb_stats->syncp);
- } else
- lb_stats->drops++;
+ }
return NETDEV_TX_OK;
}
@@ -101,32 +97,26 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev,
struct rtnl_link_stats64 *stats)
{
- const struct pcpu_lstats __percpu *pcpu_lstats;
u64 bytes = 0;
u64 packets = 0;
- u64 drops = 0;
int i;
- pcpu_lstats = (void __percpu __force *)dev->ml_priv;
for_each_possible_cpu(i) {
const struct pcpu_lstats *lb_stats;
u64 tbytes, tpackets;
unsigned int start;
- lb_stats = per_cpu_ptr(pcpu_lstats, i);
+ lb_stats = per_cpu_ptr(dev->lstats, i);
do {
start = u64_stats_fetch_begin(&lb_stats->syncp);
tbytes = lb_stats->bytes;
tpackets = lb_stats->packets;
} while (u64_stats_fetch_retry(&lb_stats->syncp, start));
- drops += lb_stats->drops;
bytes += tbytes;
packets += tpackets;
}
stats->rx_packets = packets;
stats->tx_packets = packets;
- stats->rx_dropped = drops;
- stats->rx_errors = drops;
stats->rx_bytes = bytes;
stats->tx_bytes = bytes;
return stats;
@@ -147,22 +137,16 @@ static const struct ethtool_ops loopback_ethtool_ops = {
static int loopback_dev_init(struct net_device *dev)
{
- struct pcpu_lstats __percpu *lstats;
-
- lstats = alloc_percpu(struct pcpu_lstats);
- if (!lstats)
+ dev->lstats = alloc_percpu(struct pcpu_lstats);
+ if (!dev->lstats)
return -ENOMEM;
- dev->ml_priv = (void __force *)lstats;
return 0;
}
static void loopback_dev_free(struct net_device *dev)
{
- struct pcpu_lstats __percpu *lstats =
- (void __percpu __force *)dev->ml_priv;
-
- free_percpu(lstats);
+ free_percpu(dev->lstats);
free_netdev(dev);
}
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index 3df046a58b1d..3698824744cb 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -460,7 +460,7 @@ init_rx_bufs(struct net_device *dev, int num) {
}
lp->rbd_tail->next = rfd->rbd;
#endif
- return (i);
+ return i;
}
static inline void
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index 3832fa4961dd..f84f5e6ededb 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -562,19 +562,19 @@ static int __init mac8390_initdev(struct net_device *dev,
case ACCESS_16:
/* 16 bit card, register map is reversed */
- ei_status.reset_8390 = &mac8390_no_reset;
- ei_status.block_input = &slow_sane_block_input;
- ei_status.block_output = &slow_sane_block_output;
- ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+ ei_status.reset_8390 = mac8390_no_reset;
+ ei_status.block_input = slow_sane_block_input;
+ ei_status.block_output = slow_sane_block_output;
+ ei_status.get_8390_hdr = slow_sane_get_8390_hdr;
ei_status.reg_offset = back4_offsets;
break;
case ACCESS_32:
/* 32 bit card, register map is reversed */
- ei_status.reset_8390 = &mac8390_no_reset;
- ei_status.block_input = &sane_block_input;
- ei_status.block_output = &sane_block_output;
- ei_status.get_8390_hdr = &sane_get_8390_hdr;
+ ei_status.reset_8390 = mac8390_no_reset;
+ ei_status.block_input = sane_block_input;
+ ei_status.block_output = sane_block_output;
+ ei_status.get_8390_hdr = sane_get_8390_hdr;
ei_status.reg_offset = back4_offsets;
access_bitmode = 1;
break;
@@ -586,19 +586,19 @@ static int __init mac8390_initdev(struct net_device *dev,
* but overwrite system memory when run at 32 bit.
* so we run them all at 16 bit.
*/
- ei_status.reset_8390 = &mac8390_no_reset;
- ei_status.block_input = &slow_sane_block_input;
- ei_status.block_output = &slow_sane_block_output;
- ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+ ei_status.reset_8390 = mac8390_no_reset;
+ ei_status.block_input = slow_sane_block_input;
+ ei_status.block_output = slow_sane_block_output;
+ ei_status.get_8390_hdr = slow_sane_get_8390_hdr;
ei_status.reg_offset = back4_offsets;
break;
case MAC8390_CABLETRON:
/* 16 bit card, register map is short forward */
- ei_status.reset_8390 = &mac8390_no_reset;
- ei_status.block_input = &slow_sane_block_input;
- ei_status.block_output = &slow_sane_block_output;
- ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+ ei_status.reset_8390 = mac8390_no_reset;
+ ei_status.block_input = slow_sane_block_input;
+ ei_status.block_output = slow_sane_block_output;
+ ei_status.get_8390_hdr = slow_sane_get_8390_hdr;
ei_status.reg_offset = fwrd2_offsets;
break;
@@ -606,19 +606,19 @@ static int __init mac8390_initdev(struct net_device *dev,
case MAC8390_KINETICS:
/* 16 bit memory, register map is forward */
/* dayna and similar */
- ei_status.reset_8390 = &mac8390_no_reset;
- ei_status.block_input = &dayna_block_input;
- ei_status.block_output = &dayna_block_output;
- ei_status.get_8390_hdr = &dayna_get_8390_hdr;
+ ei_status.reset_8390 = mac8390_no_reset;
+ ei_status.block_input = dayna_block_input;
+ ei_status.block_output = dayna_block_output;
+ ei_status.get_8390_hdr = dayna_get_8390_hdr;
ei_status.reg_offset = fwrd4_offsets;
break;
case MAC8390_INTERLAN:
/* 16 bit memory, register map is forward */
- ei_status.reset_8390 = &interlan_reset;
- ei_status.block_input = &slow_sane_block_input;
- ei_status.block_output = &slow_sane_block_output;
- ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+ ei_status.reset_8390 = interlan_reset;
+ ei_status.block_input = slow_sane_block_input;
+ ei_status.block_output = slow_sane_block_output;
+ ei_status.get_8390_hdr = slow_sane_get_8390_hdr;
ei_status.reg_offset = fwrd4_offsets;
break;
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index ff2f158ab0b9..f69e73e2191e 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -407,7 +407,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
}
skb_reserve(skb, RX_OFFSET);
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
skb_put(skb, len);
for (frag = first_frag; ; frag = NEXT_RX(frag)) {
@@ -515,14 +515,15 @@ static int macb_poll(struct napi_struct *napi, int budget)
(unsigned long)status, budget);
work_done = macb_rx(bp, budget);
- if (work_done < budget)
+ if (work_done < budget) {
napi_complete(napi);
- /*
- * We've done what we can to clean the buffers. Make sure we
- * get notified when new packets arrive.
- */
- macb_writel(bp, IER, MACB_RX_INT_FLAGS);
+ /*
+ * We've done what we can to clean the buffers. Make sure we
+ * get notified when new packets arrive.
+ */
+ macb_writel(bp, IER, MACB_RX_INT_FLAGS);
+ }
/* TODO: Handle errors */
@@ -550,12 +551,16 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
}
if (status & MACB_RX_INT_FLAGS) {
+ /*
+ * There's no point taking any more interrupts
+ * until we have processed the buffers. The
+ * scheduling call may fail if the poll routine
+ * is already scheduled, so disable interrupts
+ * now.
+ */
+ macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
+
if (napi_schedule_prep(&bp->napi)) {
- /*
- * There's no point taking any more interrupts
- * until we have processed the buffers
- */
- macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
dev_dbg(&bp->pdev->dev,
"scheduling RX softirq\n");
__napi_schedule(&bp->napi);
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 0ef0eb0db945..0fc9dc7f20db 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -788,6 +788,10 @@ static int macvlan_device_event(struct notifier_block *unused,
}
break;
case NETDEV_UNREGISTER:
+ /* twiddle thumbs on netns device moves */
+ if (dev->reg_state != NETREG_UNREGISTERING)
+ break;
+
list_for_each_entry_safe(vlan, next, &port->vlans, list)
vlan->dev->rtnl_link_ops->dellink(vlan->dev, NULL);
break;
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 3b1c54a9c6ef..42567279843e 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -84,26 +84,45 @@ static const struct proto_ops macvtap_socket_ops;
static DEFINE_SPINLOCK(macvtap_lock);
/*
- * Choose the next free queue, for now there is only one
+ * get_slot: return a [unused/occupied] slot in vlan->taps[]:
+ * - if 'q' is NULL, return the first empty slot;
+ * - otherwise, return the slot this pointer occupies.
*/
+static int get_slot(struct macvlan_dev *vlan, struct macvtap_queue *q)
+{
+ int i;
+
+ for (i = 0; i < MAX_MACVTAP_QUEUES; i++) {
+ if (rcu_dereference(vlan->taps[i]) == q)
+ return i;
+ }
+
+ /* Should never happen */
+ BUG_ON(1);
+}
+
static int macvtap_set_queue(struct net_device *dev, struct file *file,
struct macvtap_queue *q)
{
struct macvlan_dev *vlan = netdev_priv(dev);
+ int index;
int err = -EBUSY;
spin_lock(&macvtap_lock);
- if (rcu_dereference(vlan->tap))
+ if (vlan->numvtaps == MAX_MACVTAP_QUEUES)
goto out;
err = 0;
+ index = get_slot(vlan, NULL);
rcu_assign_pointer(q->vlan, vlan);
- rcu_assign_pointer(vlan->tap, q);
+ rcu_assign_pointer(vlan->taps[index], q);
sock_hold(&q->sk);
q->file = file;
file->private_data = q;
+ vlan->numvtaps++;
+
out:
spin_unlock(&macvtap_lock);
return err;
@@ -124,9 +143,12 @@ static void macvtap_put_queue(struct macvtap_queue *q)
spin_lock(&macvtap_lock);
vlan = rcu_dereference(q->vlan);
if (vlan) {
- rcu_assign_pointer(vlan->tap, NULL);
+ int index = get_slot(vlan, q);
+
+ rcu_assign_pointer(vlan->taps[index], NULL);
rcu_assign_pointer(q->vlan, NULL);
sock_put(&q->sk);
+ --vlan->numvtaps;
}
spin_unlock(&macvtap_lock);
@@ -136,39 +158,82 @@ static void macvtap_put_queue(struct macvtap_queue *q)
}
/*
- * Since we only support one queue, just dereference the pointer.
+ * Select a queue based on the rxq of the device on which this packet
+ * arrived. If the incoming device is not mq, calculate a flow hash
+ * to select a queue. If all fails, find the first available queue.
+ * Cache vlan->numvtaps since it can become zero during the execution
+ * of this function.
*/
static struct macvtap_queue *macvtap_get_queue(struct net_device *dev,
struct sk_buff *skb)
{
struct macvlan_dev *vlan = netdev_priv(dev);
+ struct macvtap_queue *tap = NULL;
+ int numvtaps = vlan->numvtaps;
+ __u32 rxq;
+
+ if (!numvtaps)
+ goto out;
+
+ if (likely(skb_rx_queue_recorded(skb))) {
+ rxq = skb_get_rx_queue(skb);
+
+ while (unlikely(rxq >= numvtaps))
+ rxq -= numvtaps;
+
+ tap = rcu_dereference(vlan->taps[rxq]);
+ if (tap)
+ goto out;
+ }
+
+ /* Check if we can use flow to select a queue */
+ rxq = skb_get_rxhash(skb);
+ if (rxq) {
+ tap = rcu_dereference(vlan->taps[rxq % numvtaps]);
+ if (tap)
+ goto out;
+ }
- return rcu_dereference(vlan->tap);
+ /* Everything failed - find first available queue */
+ for (rxq = 0; rxq < MAX_MACVTAP_QUEUES; rxq++) {
+ tap = rcu_dereference(vlan->taps[rxq]);
+ if (tap)
+ break;
+ }
+
+out:
+ return tap;
}
/*
* The net_device is going away, give up the reference
- * that it holds on the queue (all the queues one day)
- * and safely set the pointer from the queues to NULL.
+ * that it holds on all queues and safely set the pointer
+ * from the queues to NULL.
*/
static void macvtap_del_queues(struct net_device *dev)
{
struct macvlan_dev *vlan = netdev_priv(dev);
- struct macvtap_queue *q;
+ struct macvtap_queue *q, *qlist[MAX_MACVTAP_QUEUES];
+ int i, j = 0;
+ /* macvtap_put_queue can free some slots, so go through all slots */
spin_lock(&macvtap_lock);
- q = rcu_dereference(vlan->tap);
- if (!q) {
- spin_unlock(&macvtap_lock);
- return;
+ for (i = 0; i < MAX_MACVTAP_QUEUES && vlan->numvtaps; i++) {
+ q = rcu_dereference(vlan->taps[i]);
+ if (q) {
+ qlist[j++] = q;
+ rcu_assign_pointer(vlan->taps[i], NULL);
+ rcu_assign_pointer(q->vlan, NULL);
+ vlan->numvtaps--;
+ }
}
-
- rcu_assign_pointer(vlan->tap, NULL);
- rcu_assign_pointer(q->vlan, NULL);
+ BUG_ON(vlan->numvtaps != 0);
spin_unlock(&macvtap_lock);
synchronize_rcu();
- sock_put(&q->sk);
+
+ for (--j; j >= 0; j--)
+ sock_put(&qlist[j]->sk);
}
/*
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
index 42e3294671d7..60135aa55802 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -461,7 +461,7 @@ static int meth_tx_full(struct net_device *dev)
{
struct meth_private *priv = netdev_priv(dev);
- return (priv->tx_count >= TX_RING_ENTRIES - 1);
+ return priv->tx_count >= TX_RING_ENTRIES - 1;
}
static void meth_tx_cleanup(struct net_device* dev, unsigned long int_status)
diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile
index 1fd068e1d930..d1aa45a15854 100644
--- a/drivers/net/mlx4/Makefile
+++ b/drivers/net/mlx4/Makefile
@@ -6,4 +6,4 @@ mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \
obj-$(CONFIG_MLX4_EN) += mlx4_en.o
mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \
- en_resources.o en_netdev.o
+ en_resources.o en_netdev.o en_selftest.o
diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c
index 8c8515619b8e..8f4bf1f07c11 100644
--- a/drivers/net/mlx4/alloc.c
+++ b/drivers/net/mlx4/alloc.c
@@ -74,7 +74,7 @@ void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj)
u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align)
{
- u32 obj, i;
+ u32 obj;
if (likely(cnt == 1 && align == 1))
return mlx4_bitmap_alloc(bitmap);
@@ -91,8 +91,7 @@ u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align)
}
if (obj < bitmap->max) {
- for (i = 0; i < cnt; i++)
- set_bit(obj + i, bitmap->table);
+ bitmap_set(bitmap->table, obj, cnt);
if (obj == bitmap->last) {
bitmap->last = (obj + cnt);
if (bitmap->last >= bitmap->max)
@@ -109,13 +108,10 @@ u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align)
void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt)
{
- u32 i;
-
obj &= bitmap->max + bitmap->reserved_top - 1;
spin_lock(&bitmap->lock);
- for (i = 0; i < cnt; i++)
- clear_bit(obj + i, bitmap->table);
+ bitmap_clear(bitmap->table, obj, cnt);
bitmap->last = min(bitmap->last, obj);
bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
& bitmap->mask;
@@ -125,8 +121,6 @@ void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt)
int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask,
u32 reserved_bot, u32 reserved_top)
{
- int i;
-
/* num must be a power of 2 */
if (num != roundup_pow_of_two(num))
return -EINVAL;
@@ -142,8 +136,7 @@ int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask,
if (!bitmap->table)
return -ENOMEM;
- for (i = 0; i < reserved_bot; ++i)
- set_bit(i, bitmap->table);
+ bitmap_set(bitmap->table, 0, reserved_bot);
return 0;
}
@@ -188,7 +181,7 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE;
buf->npages = buf->nbufs;
buf->page_shift = PAGE_SHIFT;
- buf->page_list = kzalloc(buf->nbufs * sizeof *buf->page_list,
+ buf->page_list = kcalloc(buf->nbufs, sizeof(*buf->page_list),
GFP_KERNEL);
if (!buf->page_list)
return -ENOMEM;
diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c
index b275238fe70d..056152b3ff58 100644
--- a/drivers/net/mlx4/en_ethtool.c
+++ b/drivers/net/mlx4/en_ethtool.c
@@ -39,21 +39,6 @@
#include "en_port.h"
-static void mlx4_en_update_lro_stats(struct mlx4_en_priv *priv)
-{
- int i;
-
- priv->port_stats.lro_aggregated = 0;
- priv->port_stats.lro_flushed = 0;
- priv->port_stats.lro_no_desc = 0;
-
- for (i = 0; i < priv->rx_ring_num; i++) {
- priv->port_stats.lro_aggregated += priv->rx_ring[i].lro.stats.aggregated;
- priv->port_stats.lro_flushed += priv->rx_ring[i].lro.stats.flushed;
- priv->port_stats.lro_no_desc += priv->rx_ring[i].lro.stats.no_desc;
- }
-}
-
static void
mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
{
@@ -112,7 +97,7 @@ static const char main_strings[][ETH_GSTRING_LEN] = {
"tx_heartbeat_errors", "tx_window_errors",
/* port statistics */
- "lro_aggregated", "lro_flushed", "lro_no_desc", "tso_packets",
+ "tso_packets",
"queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed",
"rx_csum_good", "rx_csum_none", "tx_chksum_offload",
@@ -125,6 +110,14 @@ static const char main_strings[][ETH_GSTRING_LEN] = {
#define NUM_MAIN_STATS 21
#define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS)
+static const char mlx4_en_test_names[][ETH_GSTRING_LEN]= {
+ "Interupt Test",
+ "Link Test",
+ "Speed Test",
+ "Register Test",
+ "Loopback Test",
+};
+
static u32 mlx4_en_get_msglevel(struct net_device *dev)
{
return ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable;
@@ -146,10 +139,15 @@ static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
- if (sset != ETH_SS_STATS)
+ switch (sset) {
+ case ETH_SS_STATS:
+ return NUM_ALL_STATS +
+ (priv->tx_ring_num + priv->rx_ring_num) * 2;
+ case ETH_SS_TEST:
+ return MLX4_EN_NUM_SELF_TEST - !(priv->mdev->dev->caps.loopback_support) * 2;
+ default:
return -EOPNOTSUPP;
-
- return NUM_ALL_STATS + (priv->tx_ring_num + priv->rx_ring_num) * 2;
+ }
}
static void mlx4_en_get_ethtool_stats(struct net_device *dev,
@@ -161,8 +159,6 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,
spin_lock_bh(&priv->stats_lock);
- mlx4_en_update_lro_stats(priv);
-
for (i = 0; i < NUM_MAIN_STATS; i++)
data[index++] = ((unsigned long *) &priv->stats)[i];
for (i = 0; i < NUM_PORT_STATS; i++)
@@ -181,6 +177,12 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,
}
+static void mlx4_en_self_test(struct net_device *dev,
+ struct ethtool_test *etest, u64 *buf)
+{
+ mlx4_en_ex_selftest(dev, &etest->flags, buf);
+}
+
static void mlx4_en_get_strings(struct net_device *dev,
uint32_t stringset, uint8_t *data)
{
@@ -188,44 +190,76 @@ static void mlx4_en_get_strings(struct net_device *dev,
int index = 0;
int i;
- if (stringset != ETH_SS_STATS)
- return;
-
- /* Add main counters */
- for (i = 0; i < NUM_MAIN_STATS; i++)
- strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]);
- for (i = 0; i < NUM_PORT_STATS; i++)
- strcpy(data + (index++) * ETH_GSTRING_LEN,
+ switch (stringset) {
+ case ETH_SS_TEST:
+ for (i = 0; i < MLX4_EN_NUM_SELF_TEST - 2; i++)
+ strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]);
+ if (priv->mdev->dev->caps.loopback_support)
+ for (; i < MLX4_EN_NUM_SELF_TEST; i++)
+ strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]);
+ break;
+
+ case ETH_SS_STATS:
+ /* Add main counters */
+ for (i = 0; i < NUM_MAIN_STATS; i++)
+ strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]);
+ for (i = 0; i< NUM_PORT_STATS; i++)
+ strcpy(data + (index++) * ETH_GSTRING_LEN,
main_strings[i + NUM_MAIN_STATS]);
- for (i = 0; i < priv->tx_ring_num; i++) {
- sprintf(data + (index++) * ETH_GSTRING_LEN,
- "tx%d_packets", i);
- sprintf(data + (index++) * ETH_GSTRING_LEN,
- "tx%d_bytes", i);
- }
- for (i = 0; i < priv->rx_ring_num; i++) {
- sprintf(data + (index++) * ETH_GSTRING_LEN,
- "rx%d_packets", i);
- sprintf(data + (index++) * ETH_GSTRING_LEN,
- "rx%d_bytes", i);
- }
- for (i = 0; i < NUM_PKT_STATS; i++)
- strcpy(data + (index++) * ETH_GSTRING_LEN,
+ for (i = 0; i < priv->tx_ring_num; i++) {
+ sprintf(data + (index++) * ETH_GSTRING_LEN,
+ "tx%d_packets", i);
+ sprintf(data + (index++) * ETH_GSTRING_LEN,
+ "tx%d_bytes", i);
+ }
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ sprintf(data + (index++) * ETH_GSTRING_LEN,
+ "rx%d_packets", i);
+ sprintf(data + (index++) * ETH_GSTRING_LEN,
+ "rx%d_bytes", i);
+ }
+ for (i = 0; i< NUM_PKT_STATS; i++)
+ strcpy(data + (index++) * ETH_GSTRING_LEN,
main_strings[i + NUM_MAIN_STATS + NUM_PORT_STATS]);
+ break;
+ }
}
static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ int trans_type;
+
cmd->autoneg = AUTONEG_DISABLE;
cmd->supported = SUPPORTED_10000baseT_Full;
- cmd->advertising = ADVERTISED_1000baseT_Full;
+ cmd->advertising = ADVERTISED_10000baseT_Full;
+
+ if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
+ return -ENOMEM;
+
+ trans_type = priv->port_state.transciver;
if (netif_carrier_ok(dev)) {
- cmd->speed = SPEED_10000;
+ cmd->speed = priv->port_state.link_speed;
cmd->duplex = DUPLEX_FULL;
} else {
cmd->speed = -1;
cmd->duplex = -1;
}
+
+ if (trans_type > 0 && trans_type <= 0xC) {
+ cmd->port = PORT_FIBRE;
+ cmd->transceiver = XCVR_EXTERNAL;
+ cmd->supported |= SUPPORTED_FIBRE;
+ cmd->advertising |= ADVERTISED_FIBRE;
+ } else if (trans_type == 0x80 || trans_type == 0) {
+ cmd->port = PORT_TP;
+ cmd->transceiver = XCVR_INTERNAL;
+ cmd->supported |= SUPPORTED_TP;
+ cmd->advertising |= ADVERTISED_TP;
+ } else {
+ cmd->port = -1;
+ cmd->transceiver = -1;
+ }
return 0;
}
@@ -343,8 +377,9 @@ static int mlx4_en_set_ringparam(struct net_device *dev,
tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE);
tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE);
- if (rx_size == priv->prof->rx_ring_size &&
- tx_size == priv->prof->tx_ring_size)
+ if (rx_size == (priv->port_up ? priv->rx_ring[0].actual_size :
+ priv->rx_ring[0].size) &&
+ tx_size == priv->tx_ring[0].size)
return 0;
mutex_lock(&mdev->state_lock);
@@ -378,49 +413,13 @@ static void mlx4_en_get_ringparam(struct net_device *dev,
struct ethtool_ringparam *param)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
memset(param, 0, sizeof(*param));
param->rx_max_pending = MLX4_EN_MAX_RX_SIZE;
param->tx_max_pending = MLX4_EN_MAX_TX_SIZE;
- param->rx_pending = mdev->profile.prof[priv->port].rx_ring_size;
- param->tx_pending = mdev->profile.prof[priv->port].tx_ring_size;
-}
-
-static int mlx4_ethtool_op_set_flags(struct net_device *dev, u32 data)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
- int rc = 0;
- int changed = 0;
-
- if (data & ~ETH_FLAG_LRO)
- return -EOPNOTSUPP;
-
- if (data & ETH_FLAG_LRO) {
- if (mdev->profile.num_lro == 0)
- return -EOPNOTSUPP;
- if (!(dev->features & NETIF_F_LRO))
- changed = 1;
- } else if (dev->features & NETIF_F_LRO) {
- changed = 1;
- }
-
- if (changed) {
- if (netif_running(dev)) {
- mutex_lock(&mdev->state_lock);
- mlx4_en_stop_port(dev);
- }
- dev->features ^= NETIF_F_LRO;
- if (netif_running(dev)) {
- rc = mlx4_en_start_port(dev);
- if (rc)
- en_err(priv, "Failed to restart port\n");
- mutex_unlock(&mdev->state_lock);
- }
- }
-
- return rc;
+ param->rx_pending = priv->port_up ?
+ priv->rx_ring[0].actual_size : priv->rx_ring[0].size;
+ param->tx_pending = priv->tx_ring[0].size;
}
const struct ethtool_ops mlx4_en_ethtool_ops = {
@@ -441,6 +440,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
.get_strings = mlx4_en_get_strings,
.get_sset_count = mlx4_en_get_sset_count,
.get_ethtool_stats = mlx4_en_get_ethtool_stats,
+ .self_test = mlx4_en_self_test,
.get_wol = mlx4_en_get_wol,
.get_msglevel = mlx4_en_get_msglevel,
.set_msglevel = mlx4_en_set_msglevel,
@@ -451,7 +451,6 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
.get_ringparam = mlx4_en_get_ringparam,
.set_ringparam = mlx4_en_set_ringparam,
.get_flags = ethtool_op_get_flags,
- .set_flags = mlx4_ethtool_op_set_flags,
};
diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c
index 97934f1ec53a..f6e0d40cd876 100644
--- a/drivers/net/mlx4/en_main.c
+++ b/drivers/net/mlx4/en_main.c
@@ -63,15 +63,12 @@ static const char mlx4_en_version[] =
*/
-/* Use a XOR rathern than Toeplitz hash function for RSS */
-MLX4_EN_PARM_INT(rss_xor, 0, "Use XOR hash function for RSS");
-
-/* RSS hash type mask - default to <saddr, daddr, sport, dport> */
-MLX4_EN_PARM_INT(rss_mask, 0xf, "RSS hash type bitmask");
-
-/* Number of LRO sessions per Rx ring (rounded up to a power of two) */
-MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS,
- "Number of LRO sessions per ring or disabled (0)");
+/* Enable RSS TCP traffic */
+MLX4_EN_PARM_INT(tcp_rss, 1,
+ "Enable RSS for incomming TCP traffic or disabled (0)");
+/* Enable RSS UDP traffic */
+MLX4_EN_PARM_INT(udp_rss, 1,
+ "Enable RSS for incomming UDP traffic or disabled (0)");
/* Priority pausing */
MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]."
@@ -107,9 +104,12 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
struct mlx4_en_profile *params = &mdev->profile;
int i;
- params->rss_xor = (rss_xor != 0);
- params->rss_mask = rss_mask & 0x1f;
- params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS);
+ params->tcp_rss = tcp_rss;
+ params->udp_rss = udp_rss;
+ if (params->udp_rss && !mdev->dev->caps.udp_rss) {
+ mlx4_warn(mdev, "UDP RSS is not supported on this device.\n");
+ params->udp_rss = 0;
+ }
for (i = 1; i <= MLX4_MAX_PORTS; i++) {
params->prof[i].rx_pause = 1;
params->prof[i].rx_ppp = pfcrx;
@@ -124,6 +124,13 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
return 0;
}
+static void *mlx4_en_get_netdev(struct mlx4_dev *dev, void *ctx, u8 port)
+{
+ struct mlx4_en_dev *endev = ctx;
+
+ return endev->pndev[port];
+}
+
static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr,
enum mlx4_dev_event event, int port)
{
@@ -282,9 +289,11 @@ err_free_res:
}
static struct mlx4_interface mlx4_en_interface = {
- .add = mlx4_en_add,
- .remove = mlx4_en_remove,
- .event = mlx4_en_event,
+ .add = mlx4_en_add,
+ .remove = mlx4_en_remove,
+ .event = mlx4_en_event,
+ .get_dev = mlx4_en_get_netdev,
+ .protocol = MLX4_PROTOCOL_EN,
};
static int __init mlx4_en_init(void)
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index a0d8a26f5a02..6d6806b361e3 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -69,6 +69,7 @@ static void mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev;
int err;
+ int idx;
if (!priv->vlgrp)
return;
@@ -83,7 +84,10 @@ static void mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
if (err)
en_err(priv, "Failed configuring VLAN filter\n");
}
+ if (mlx4_register_vlan(mdev->dev, priv->port, vid, &idx))
+ en_err(priv, "failed adding vlan %d\n", vid);
mutex_unlock(&mdev->state_lock);
+
}
static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
@@ -91,6 +95,7 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev;
int err;
+ int idx;
if (!priv->vlgrp)
return;
@@ -101,6 +106,11 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
/* Remove VID from port VLAN filter */
mutex_lock(&mdev->state_lock);
+ if (!mlx4_find_cached_vlan(mdev->dev, priv->port, vid, &idx))
+ mlx4_unregister_vlan(mdev->dev, priv->port, idx);
+ else
+ en_err(priv, "could not find vid %d in cache\n", vid);
+
if (mdev->device_up && priv->port_up) {
err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp);
if (err)
@@ -109,7 +119,7 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
mutex_unlock(&mdev->state_lock);
}
-static u64 mlx4_en_mac_to_u64(u8 *addr)
+u64 mlx4_en_mac_to_u64(u8 *addr)
{
u64 mac = 0;
int i;
@@ -513,6 +523,10 @@ static void mlx4_en_do_get_stats(struct work_struct *work)
queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
}
+ if (mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port]) {
+ queue_work(mdev->workqueue, &priv->mac_task);
+ mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port] = 0;
+ }
mutex_unlock(&mdev->state_lock);
}
@@ -528,10 +542,10 @@ static void mlx4_en_linkstate(struct work_struct *work)
* report to system log */
if (priv->last_link_state != linkstate) {
if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) {
- en_dbg(LINK, priv, "Link Down\n");
+ en_info(priv, "Link Down\n");
netif_carrier_off(priv->dev);
} else {
- en_dbg(LINK, priv, "Link Up\n");
+ en_info(priv, "Link Up\n");
netif_carrier_on(priv->dev);
}
}
@@ -653,6 +667,7 @@ int mlx4_en_start_port(struct net_device *dev)
en_err(priv, "Failed setting port mac\n");
goto tx_err;
}
+ mdev->mac_removed[priv->port] = 0;
/* Init port */
en_dbg(HW, priv, "Initializing port\n");
@@ -704,12 +719,12 @@ void mlx4_en_stop_port(struct net_device *dev)
netif_tx_stop_all_queues(dev);
netif_tx_unlock_bh(dev);
- /* close port*/
+ /* Set port as not active */
priv->port_up = false;
- mlx4_CLOSE_PORT(mdev->dev, priv->port);
/* Unregister Mac address for the port */
mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index);
+ mdev->mac_removed[priv->port] = 1;
/* Free TX Rings */
for (i = 0; i < priv->tx_ring_num; i++) {
@@ -731,6 +746,9 @@ void mlx4_en_stop_port(struct net_device *dev)
msleep(1);
mlx4_en_deactivate_cq(priv, &priv->rx_cq[i]);
}
+
+ /* close port*/
+ mlx4_CLOSE_PORT(mdev->dev, priv->port);
}
static void mlx4_en_restart(struct work_struct *work)
@@ -1017,15 +1035,17 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
*/
dev->netdev_ops = &mlx4_netdev_ops;
dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT;
- dev->real_num_tx_queues = MLX4_EN_NUM_TX_RINGS;
+ netif_set_real_num_tx_queues(dev, priv->tx_ring_num);
+ netif_set_real_num_rx_queues(dev, priv->rx_ring_num);
SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops);
/* Set defualt MAC */
dev->addr_len = ETH_ALEN;
- for (i = 0; i < ETH_ALEN; i++)
- dev->dev_addr[ETH_ALEN - 1 - i] =
- (u8) (priv->mac >> (8 * i));
+ for (i = 0; i < ETH_ALEN; i++) {
+ dev->dev_addr[ETH_ALEN - 1 - i] = (u8) (priv->mac >> (8 * i));
+ dev->perm_addr[ETH_ALEN - 1 - i] = (u8) (priv->mac >> (8 * i));
+ }
/*
* Set driver features
@@ -1038,8 +1058,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
dev->features |= NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_FILTER;
- if (mdev->profile.num_lro)
- dev->features |= NETIF_F_LRO;
+ dev->features |= NETIF_F_GRO;
if (mdev->LSO_support) {
dev->features |= NETIF_F_TSO;
dev->features |= NETIF_F_TSO6;
diff --git a/drivers/net/mlx4/en_port.c b/drivers/net/mlx4/en_port.c
index a29abe845d2e..7f5a3221e0c1 100644
--- a/drivers/net/mlx4/en_port.c
+++ b/drivers/net/mlx4/en_port.c
@@ -127,8 +127,8 @@ 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->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | base_qpn);
- context->mcast = cpu_to_be32(1 << SET_PORT_PROMISC_SHIFT | base_qpn);
+ context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_EN_SHIFT | base_qpn);
+ context->mcast = cpu_to_be32(1 << SET_PORT_PROMISC_MODE_SHIFT | base_qpn);
context->intra_no_vlan = 0;
context->no_vlan = MLX4_NO_VLAN_IDX;
context->intra_vlan_miss = 0;
@@ -142,6 +142,38 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
return err;
}
+int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port)
+{
+ struct mlx4_en_query_port_context *qport_context;
+ struct mlx4_en_priv *priv = netdev_priv(mdev->pndev[port]);
+ struct mlx4_en_port_state *state = &priv->port_state;
+ struct mlx4_cmd_mailbox *mailbox;
+ int err;
+
+ mailbox = mlx4_alloc_cmd_mailbox(mdev->dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ memset(mailbox->buf, 0, sizeof(*qport_context));
+ err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, port, 0,
+ MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B);
+ if (err)
+ goto out;
+ qport_context = mailbox->buf;
+
+ /* 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)
+ state->link_speed = 1000;
+ else
+ state->link_speed = 10000;
+ state->transciver = qport_context->transceiver;
+
+out:
+ mlx4_free_cmd_mailbox(mdev->dev, mailbox);
+ return err;
+}
int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
{
diff --git a/drivers/net/mlx4/en_port.h b/drivers/net/mlx4/en_port.h
index e6477f12beb5..092e814b1981 100644
--- a/drivers/net/mlx4/en_port.h
+++ b/drivers/net/mlx4/en_port.h
@@ -36,7 +36,8 @@
#define SET_PORT_GEN_ALL_VALID 0x7
-#define SET_PORT_PROMISC_SHIFT 31
+#define SET_PORT_PROMISC_EN_SHIFT 31
+#define SET_PORT_PROMISC_MODE_SHIFT 30
enum {
MLX4_CMD_SET_VLAN_FLTR = 0x47,
@@ -84,6 +85,20 @@ enum {
MLX4_MCAST_ENABLE = 2,
};
+struct mlx4_en_query_port_context {
+ u8 link_up;
+#define MLX4_EN_LINK_UP_MASK 0x80
+ u8 reserved;
+ __be16 mtu;
+ u8 reserved2;
+ u8 link_speed;
+#define MLX4_EN_SPEED_MASK 0x3
+#define MLX4_EN_1G_SPEED 0x2
+ u16 reserved3[5];
+ __be64 mac;
+ u8 transceiver;
+};
+
struct mlx4_en_stat_out_mbox {
/* Received frames with a length of 64 octets */
diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c
index 8e2fcb7103c3..570f2508fb30 100644
--- a/drivers/net/mlx4/en_rx.c
+++ b/drivers/net/mlx4/en_rx.c
@@ -42,18 +42,6 @@
#include "mlx4_en.h"
-static int mlx4_en_get_frag_header(struct skb_frag_struct *frags, void **mac_hdr,
- void **ip_hdr, void **tcpudp_hdr,
- u64 *hdr_flags, void *priv)
-{
- *mac_hdr = page_address(frags->page) + frags->page_offset;
- *ip_hdr = *mac_hdr + ETH_HLEN;
- *tcpudp_hdr = (struct tcphdr *)(*ip_hdr + sizeof(struct iphdr));
- *hdr_flags = LRO_IPV4 | LRO_TCP;
-
- return 0;
-}
-
static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv,
struct mlx4_en_rx_desc *rx_desc,
struct skb_frag_struct *skb_frags,
@@ -251,7 +239,6 @@ reduce_rings:
ring->prod--;
mlx4_en_free_rx_desc(priv, ring, ring->actual_size);
}
- ring->size_mask = ring->actual_size - 1;
}
return 0;
@@ -313,28 +300,8 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
}
ring->buf = ring->wqres.buf.direct.buf;
- /* Configure lro mngr */
- memset(&ring->lro, 0, sizeof(struct net_lro_mgr));
- ring->lro.dev = priv->dev;
- ring->lro.features = LRO_F_NAPI;
- ring->lro.frag_align_pad = NET_IP_ALIGN;
- ring->lro.ip_summed = CHECKSUM_UNNECESSARY;
- ring->lro.ip_summed_aggr = CHECKSUM_UNNECESSARY;
- ring->lro.max_desc = mdev->profile.num_lro;
- ring->lro.max_aggr = MAX_SKB_FRAGS;
- ring->lro.lro_arr = kzalloc(mdev->profile.num_lro *
- sizeof(struct net_lro_desc),
- GFP_KERNEL);
- if (!ring->lro.lro_arr) {
- en_err(priv, "Failed to allocate lro array\n");
- goto err_map;
- }
- ring->lro.get_frag_header = mlx4_en_get_frag_header;
-
return 0;
-err_map:
- mlx4_en_unmap_buffer(&ring->wqres.buf);
err_hwq:
mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size);
err_ring:
@@ -389,6 +356,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv)
for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) {
ring = &priv->rx_ring[ring_ind];
+ ring->size_mask = ring->actual_size - 1;
mlx4_en_update_rx_prod_db(ring);
}
@@ -412,7 +380,6 @@ void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv,
{
struct mlx4_en_dev *mdev = priv->mdev;
- kfree(ring->lro.lro_arr);
mlx4_en_unmap_buffer(&ring->wqres.buf);
mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size + TXBB_SIZE);
vfree(ring->rx_info);
@@ -459,7 +426,7 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv,
goto fail;
/* Unmap buffer */
- pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size,
+ pci_unmap_single(mdev->pdev, dma, skb_frags_rx[nr].size,
PCI_DMA_FROMDEVICE);
}
/* Adjust size of last fragment to match actual length */
@@ -541,6 +508,21 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
return skb;
}
+static void validate_loopback(struct mlx4_en_priv *priv, struct sk_buff *skb)
+{
+ int i;
+ int offset = ETH_HLEN;
+
+ for (i = 0; i < MLX4_LOOPBACK_TEST_PAYLOAD; i++, offset++) {
+ if (*(skb->data + offset) != (unsigned char) (i & 0xff))
+ goto out_loopback;
+ }
+ /* Loopback found */
+ priv->loopback_ok = 1;
+
+out_loopback:
+ dev_kfree_skb_any(skb);
+}
int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget)
{
@@ -548,7 +530,6 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
struct mlx4_cqe *cqe;
struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring];
struct skb_frag_struct *skb_frags;
- struct skb_frag_struct lro_frags[MLX4_EN_MAX_RX_FRAGS];
struct mlx4_en_rx_desc *rx_desc;
struct sk_buff *skb;
int index;
@@ -608,37 +589,35 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
* - TCP/IP (v4)
* - without IP options
* - not an IP fragment */
- if (mlx4_en_can_lro(cqe->status) &&
- dev->features & NETIF_F_LRO) {
+ if (dev->features & NETIF_F_GRO) {
+ struct sk_buff *gro_skb = napi_get_frags(&cq->napi);
+ if (!gro_skb)
+ goto next;
nr = mlx4_en_complete_rx_desc(
priv, rx_desc,
- skb_frags, lro_frags,
+ skb_frags, skb_shinfo(gro_skb)->frags,
ring->page_alloc, length);
if (!nr)
goto next;
+ 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 (priv->vlgrp && (cqe->vlan_my_qpn &
- cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK))) {
- lro_vlan_hwaccel_receive_frags(
- &ring->lro, lro_frags,
- length, length,
- priv->vlgrp,
- be16_to_cpu(cqe->sl_vid),
- NULL, 0);
- } else
- lro_receive_frags(&ring->lro,
- lro_frags,
- length,
- length,
- NULL, 0);
+ cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)))
+ vlan_gro_frags(&cq->napi, priv->vlgrp, be16_to_cpu(cqe->sl_vid));
+ else
+ napi_gro_frags(&cq->napi);
goto next;
}
/* LRO not possible, complete processing here */
ip_summed = CHECKSUM_UNNECESSARY;
- INC_PERF_COUNTER(priv->pstats.lro_misses);
} else {
ip_summed = CHECKSUM_NONE;
priv->port_stats.rx_chksum_none++;
@@ -655,6 +634,11 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
goto next;
}
+ if (unlikely(priv->validate_loopback)) {
+ validate_loopback(priv, skb);
+ goto next;
+ }
+
skb->ip_summed = ip_summed;
skb->protocol = eth_type_trans(skb, dev);
skb_record_rx_queue(skb, cq->ring);
@@ -674,14 +658,10 @@ next:
if (++polled == budget) {
/* We are here because we reached the NAPI budget -
* flush only pending LRO sessions */
- lro_flush_all(&ring->lro);
goto out;
}
}
- /* If CQ is empty flush all LRO sessions unconditionally */
- lro_flush_all(&ring->lro);
-
out:
AVG_PERF_COUNTER(priv->pstats.rx_coal_avg, polled);
mlx4_cq_set_ci(&cq->mcq);
@@ -816,7 +796,7 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn,
qp->event = mlx4_en_sqp_event;
memset(context, 0, sizeof *context);
- mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 0, 0,
+ mlx4_en_fill_qp_context(priv, ring->actual_size, ring->stride, 0, 0,
qpn, ring->cqn, context);
context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma);
@@ -839,8 +819,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
struct mlx4_qp_context context;
struct mlx4_en_rss_context *rss_context;
void *ptr;
- int rss_xor = mdev->profile.rss_xor;
- u8 rss_mask = mdev->profile.rss_mask;
+ u8 rss_mask = 0x3f;
int i, qpn;
int err = 0;
int good_qps = 0;
@@ -886,9 +865,10 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
rss_context->base_qpn = cpu_to_be32(ilog2(priv->rx_ring_num) << 24 |
(rss_map->base_qpn));
rss_context->default_qpn = cpu_to_be32(rss_map->base_qpn);
- rss_context->hash_fn = rss_xor & 0x3;
- rss_context->flags = rss_mask << 2;
+ rss_context->flags = rss_mask;
+ if (priv->mdev->profile.udp_rss)
+ rss_context->base_qpn_udp = rss_context->default_qpn;
err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, &context,
&rss_map->indir_qp, &rss_map->indir_state);
if (err)
diff --git a/drivers/net/mlx4/en_selftest.c b/drivers/net/mlx4/en_selftest.c
new file mode 100644
index 000000000000..9c91a92da705
--- /dev/null
+++ b/drivers/net/mlx4/en_selftest.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/mlx4/driver.h>
+
+#include "mlx4_en.h"
+
+
+static int mlx4_en_test_registers(struct mlx4_en_priv *priv)
+{
+ return mlx4_cmd(priv->mdev->dev, 0, 0, 0, MLX4_CMD_HW_HEALTH_CHECK,
+ MLX4_CMD_TIME_CLASS_A);
+}
+
+static int mlx4_en_test_loopback_xmit(struct mlx4_en_priv *priv)
+{
+ struct sk_buff *skb;
+ struct ethhdr *ethh;
+ unsigned char *packet;
+ unsigned int packet_size = MLX4_LOOPBACK_TEST_PAYLOAD;
+ unsigned int i;
+ int err;
+
+
+ /* build the pkt before xmit */
+ skb = netdev_alloc_skb(priv->dev, MLX4_LOOPBACK_TEST_PAYLOAD + ETH_HLEN + NET_IP_ALIGN);
+ if (!skb) {
+ en_err(priv, "-LOOPBACK_TEST_XMIT- failed to create skb for xmit\n");
+ return -ENOMEM;
+ }
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ ethh = (struct ethhdr *)skb_put(skb, sizeof(struct ethhdr));
+ packet = (unsigned char *)skb_put(skb, packet_size);
+ memcpy(ethh->h_dest, priv->dev->dev_addr, ETH_ALEN);
+ memset(ethh->h_source, 0, ETH_ALEN);
+ ethh->h_proto = htons(ETH_P_ARP);
+ skb_set_mac_header(skb, 0);
+ for (i = 0; i < packet_size; ++i) /* fill our packet */
+ packet[i] = (unsigned char)(i & 0xff);
+
+ /* xmit the pkt */
+ err = mlx4_en_xmit(skb, priv->dev);
+ return err;
+}
+
+static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
+{
+ u32 loopback_ok = 0;
+ int i;
+
+
+ priv->loopback_ok = 0;
+ priv->validate_loopback = 1;
+
+ /* xmit */
+ if (mlx4_en_test_loopback_xmit(priv)) {
+ en_err(priv, "Transmitting loopback packet failed\n");
+ goto mlx4_en_test_loopback_exit;
+ }
+
+ /* polling for result */
+ for (i = 0; i < MLX4_EN_LOOPBACK_RETRIES; ++i) {
+ msleep(MLX4_EN_LOOPBACK_TIMEOUT);
+ if (priv->loopback_ok) {
+ loopback_ok = 1;
+ break;
+ }
+ }
+ if (!loopback_ok)
+ en_err(priv, "Loopback packet didn't arrive\n");
+
+mlx4_en_test_loopback_exit:
+
+ priv->validate_loopback = 0;
+ return !loopback_ok;
+}
+
+
+static int mlx4_en_test_link(struct mlx4_en_priv *priv)
+{
+ if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
+ return -ENOMEM;
+ if (priv->port_state.link_state == 1)
+ return 0;
+ else
+ return 1;
+}
+
+static int mlx4_en_test_speed(struct mlx4_en_priv *priv)
+{
+
+ if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
+ return -ENOMEM;
+
+ /* The device currently only supports 10G speed */
+ if (priv->port_state.link_speed != SPEED_10000)
+ return priv->port_state.link_speed;
+ return 0;
+}
+
+
+void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_en_tx_ring *tx_ring;
+ int i, carrier_ok;
+
+ memset(buf, 0, sizeof(u64) * MLX4_EN_NUM_SELF_TEST);
+
+ if (*flags & ETH_TEST_FL_OFFLINE) {
+ /* disable the interface */
+ carrier_ok = netif_carrier_ok(dev);
+
+ netif_carrier_off(dev);
+retry_tx:
+ /* Wait untill all tx queues are empty.
+ * there should not be any additional incoming traffic
+ * since we turned the carrier off */
+ msleep(200);
+ for (i = 0; i < priv->tx_ring_num && carrier_ok; i++) {
+ tx_ring = &priv->tx_ring[i];
+ if (tx_ring->prod != (tx_ring->cons + tx_ring->last_nr_txbb))
+ goto retry_tx;
+ }
+
+ if (priv->mdev->dev->caps.loopback_support){
+ buf[3] = mlx4_en_test_registers(priv);
+ buf[4] = mlx4_en_test_loopback(priv);
+ }
+
+ if (carrier_ok)
+ netif_carrier_on(dev);
+
+ }
+ buf[0] = mlx4_test_interrupts(mdev->dev);
+ buf[1] = mlx4_en_test_link(priv);
+ buf[2] = mlx4_en_test_speed(priv);
+
+ for (i = 0; i < MLX4_EN_NUM_SELF_TEST; i++) {
+ if (buf[i])
+ *flags |= ETH_TEST_FL_FAILED;
+ }
+}
diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c
index 580968f304eb..a680cd4a5ab6 100644
--- a/drivers/net/mlx4/en_tx.c
+++ b/drivers/net/mlx4/en_tx.c
@@ -38,6 +38,7 @@
#include <linux/skbuff.h>
#include <linux/if_vlan.h>
#include <linux/vmalloc.h>
+#include <linux/tcp.h>
#include "mlx4_en.h"
@@ -582,7 +583,7 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb)
/* If we support per priority flow control and the packet contains
* a vlan tag, send the packet to the TX ring assigned to that priority
*/
- if (priv->prof->rx_ppp && priv->vlgrp && vlan_tx_tag_present(skb)) {
+ if (priv->prof->rx_ppp && vlan_tx_tag_present(skb)) {
vlan_tag = vlan_tx_tag_get(skb);
return MLX4_EN_NUM_TX_RINGS + (vlan_tag >> 13);
}
@@ -600,6 +601,9 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
struct mlx4_wqe_data_seg *data;
struct skb_frag_struct *frag;
struct mlx4_en_tx_info *tx_info;
+ struct ethhdr *ethh;
+ u64 mac;
+ u32 mac_l, mac_h;
int tx_ind = 0;
int nr_txbb;
int desc_size;
@@ -612,6 +616,9 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
int lso_header_size;
void *fragptr;
+ if (!priv->port_up)
+ goto tx_drop;
+
real_size = get_real_size(skb, dev, &lso_header_size);
if (unlikely(!real_size))
goto tx_drop;
@@ -627,7 +634,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
tx_ind = skb->queue_mapping;
ring = &priv->tx_ring[tx_ind];
- if (priv->vlgrp && vlan_tx_tag_present(skb))
+ if (vlan_tx_tag_present(skb))
vlan_tag = vlan_tx_tag_get(skb);
/* Check available TXBBs And 2K spare for prefetch */
@@ -676,6 +683,19 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
priv->port_stats.tx_chksum_offload++;
}
+ if (unlikely(priv->validate_loopback)) {
+ /* Copy dst mac address to wqe */
+ skb_reset_mac_header(skb);
+ ethh = eth_hdr(skb);
+ if (ethh && ethh->h_dest) {
+ mac = mlx4_en_mac_to_u64(ethh->h_dest);
+ mac_h = (u32) ((mac & 0xffff00000000ULL) >> 16);
+ mac_l = (u32) (mac & 0xffffffff);
+ tx_desc->ctrl.srcrb_flags |= cpu_to_be32(mac_h);
+ tx_desc->ctrl.imm = cpu_to_be32(mac_l);
+ }
+ }
+
/* Handle LSO (TSO) packets */
if (lso_header_size) {
/* Mark opcode as LSO */
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index 6d7b2bf210ce..552d0fce6f67 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -699,3 +699,47 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
kfree(priv->eq_table.uar_map);
}
+
+/* A test that verifies that we can accept interrupts on all
+ * the irq vectors of the device.
+ * Interrupts are checked using the NOP command.
+ */
+int mlx4_test_interrupts(struct mlx4_dev *dev)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ int i;
+ int err;
+
+ err = mlx4_NOP(dev);
+ /* When not in MSI_X, there is only one irq to check */
+ if (!(dev->flags & MLX4_FLAG_MSI_X))
+ return err;
+
+ /* A loop over all completion vectors, for each vector we will check
+ * whether it works by mapping command completions to that vector
+ * and performing a NOP command
+ */
+ for(i = 0; !err && (i < dev->caps.num_comp_vectors); ++i) {
+ /* Temporary use polling for command completions */
+ mlx4_cmd_use_polling(dev);
+
+ /* Map the new eq to handle all asyncronous events */
+ err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0,
+ priv->eq_table.eq[i].eqn);
+ if (err) {
+ mlx4_warn(dev, "Failed mapping eq for interrupt test\n");
+ mlx4_cmd_use_events(dev);
+ break;
+ }
+
+ /* Go back to using events */
+ mlx4_cmd_use_events(dev);
+ err = mlx4_NOP(dev);
+ }
+
+ /* Return to default */
+ mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0,
+ priv->eq_table.eq[dev->caps.num_comp_vectors].eqn);
+ return err;
+}
+EXPORT_SYMBOL(mlx4_test_interrupts);
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
index 04f42ae1eda0..b68eee2414c2 100644
--- a/drivers/net/mlx4/fw.c
+++ b/drivers/net/mlx4/fw.c
@@ -98,7 +98,8 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u32 flags)
[20] = "Address vector port checking support",
[21] = "UD multicast support",
[24] = "Demand paging support",
- [25] = "Router support"
+ [25] = "Router support",
+ [30] = "IBoE support"
};
int i;
@@ -141,6 +142,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
struct mlx4_cmd_mailbox *mailbox;
u32 *outbox;
u8 field;
+ u32 field32;
u16 size;
u16 stat_rate;
int err;
@@ -178,6 +180,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
#define QUERY_DEV_CAP_MAX_GID_OFFSET 0x3b
#define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET 0x3c
#define QUERY_DEV_CAP_MAX_PKEY_OFFSET 0x3f
+#define QUERY_DEV_CAP_UDP_RSS_OFFSET 0x42
+#define QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET 0x43
#define QUERY_DEV_CAP_FLAGS_OFFSET 0x44
#define QUERY_DEV_CAP_RSVD_UAR_OFFSET 0x48
#define QUERY_DEV_CAP_UAR_SZ_OFFSET 0x49
@@ -268,6 +272,10 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev_cap->max_msg_sz = 1 << (field & 0x1f);
MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET);
dev_cap->stat_rate_support = stat_rate;
+ MLX4_GET(field, outbox, QUERY_DEV_CAP_UDP_RSS_OFFSET);
+ dev_cap->udp_rss = field & 0x1;
+ MLX4_GET(field, outbox, QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET);
+ dev_cap->loopback_support = field & 0x1;
MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET);
MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET);
dev_cap->reserved_uars = field >> 4;
@@ -365,6 +373,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
#define QUERY_PORT_MAX_MACVLAN_OFFSET 0x0a
#define QUERY_PORT_MAX_VL_OFFSET 0x0b
#define QUERY_PORT_MAC_OFFSET 0x10
+#define QUERY_PORT_TRANS_VENDOR_OFFSET 0x18
+#define QUERY_PORT_WAVELENGTH_OFFSET 0x1c
+#define QUERY_PORT_TRANS_CODE_OFFSET 0x20
for (i = 1; i <= dev_cap->num_ports; ++i) {
err = mlx4_cmd_box(dev, 0, mailbox->dma, i, 0, MLX4_CMD_QUERY_PORT,
@@ -388,6 +399,11 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev_cap->log_max_vlans[i] = field >> 4;
MLX4_GET(dev_cap->eth_mtu[i], outbox, QUERY_PORT_ETH_MTU_OFFSET);
MLX4_GET(dev_cap->def_mac[i], outbox, QUERY_PORT_MAC_OFFSET);
+ MLX4_GET(field32, outbox, QUERY_PORT_TRANS_VENDOR_OFFSET);
+ dev_cap->trans_type[i] = field32 >> 24;
+ dev_cap->vendor_oui[i] = field32 & 0xffffff;
+ MLX4_GET(dev_cap->wavelength[i], outbox, QUERY_PORT_WAVELENGTH_OFFSET);
+ MLX4_GET(dev_cap->trans_code[i], outbox, QUERY_PORT_TRANS_CODE_OFFSET);
}
}
diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h
index 526d7f30c041..65cc72eb899d 100644
--- a/drivers/net/mlx4/fw.h
+++ b/drivers/net/mlx4/fw.h
@@ -73,7 +73,13 @@ struct mlx4_dev_cap {
int max_pkeys[MLX4_MAX_PORTS + 1];
u64 def_mac[MLX4_MAX_PORTS + 1];
u16 eth_mtu[MLX4_MAX_PORTS + 1];
+ int trans_type[MLX4_MAX_PORTS + 1];
+ int vendor_oui[MLX4_MAX_PORTS + 1];
+ u16 wavelength[MLX4_MAX_PORTS + 1];
+ u64 trans_code[MLX4_MAX_PORTS + 1];
u16 stat_rate_support;
+ int udp_rss;
+ int loopback_support;
u32 flags;
int reserved_uars;
int uar_size;
diff --git a/drivers/net/mlx4/icm.c b/drivers/net/mlx4/icm.c
index b07e4dee80aa..02393fdf44c1 100644
--- a/drivers/net/mlx4/icm.c
+++ b/drivers/net/mlx4/icm.c
@@ -210,38 +210,12 @@ static int mlx4_MAP_ICM(struct mlx4_dev *dev, struct mlx4_icm *icm, u64 virt)
return mlx4_map_cmd(dev, MLX4_CMD_MAP_ICM, icm, virt);
}
-int mlx4_UNMAP_ICM(struct mlx4_dev *dev, u64 virt, u32 page_count)
+static int mlx4_UNMAP_ICM(struct mlx4_dev *dev, u64 virt, u32 page_count)
{
return mlx4_cmd(dev, virt, page_count, 0, MLX4_CMD_UNMAP_ICM,
MLX4_CMD_TIME_CLASS_B);
}
-int mlx4_MAP_ICM_page(struct mlx4_dev *dev, u64 dma_addr, u64 virt)
-{
- struct mlx4_cmd_mailbox *mailbox;
- __be64 *inbox;
- int err;
-
- mailbox = mlx4_alloc_cmd_mailbox(dev);
- if (IS_ERR(mailbox))
- return PTR_ERR(mailbox);
- inbox = mailbox->buf;
-
- inbox[0] = cpu_to_be64(virt);
- inbox[1] = cpu_to_be64(dma_addr);
-
- err = mlx4_cmd(dev, mailbox->dma, 1, 0, MLX4_CMD_MAP_ICM,
- MLX4_CMD_TIME_CLASS_B);
-
- mlx4_free_cmd_mailbox(dev, mailbox);
-
- if (!err)
- mlx4_dbg(dev, "Mapped page at %llx to %llx for ICM.\n",
- (unsigned long long) dma_addr, (unsigned long long) virt);
-
- return err;
-}
-
int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm)
{
return mlx4_map_cmd(dev, MLX4_CMD_MAP_ICM_AUX, icm, -1);
diff --git a/drivers/net/mlx4/icm.h b/drivers/net/mlx4/icm.h
index ab56a2f89b65..b10c07a1dc1a 100644
--- a/drivers/net/mlx4/icm.h
+++ b/drivers/net/mlx4/icm.h
@@ -128,8 +128,6 @@ static inline unsigned long mlx4_icm_size(struct mlx4_icm_iter *iter)
return sg_dma_len(&iter->chunk->mem[iter->page_idx]);
}
-int mlx4_UNMAP_ICM(struct mlx4_dev *dev, u64 virt, u32 page_count);
-int mlx4_MAP_ICM_page(struct mlx4_dev *dev, u64 dma_addr, u64 virt);
int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm);
int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev);
diff --git a/drivers/net/mlx4/intf.c b/drivers/net/mlx4/intf.c
index 555067802751..73c94fcdfddf 100644
--- a/drivers/net/mlx4/intf.c
+++ b/drivers/net/mlx4/intf.c
@@ -161,3 +161,24 @@ void mlx4_unregister_device(struct mlx4_dev *dev)
mutex_unlock(&intf_mutex);
}
+
+void *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, int port)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_device_context *dev_ctx;
+ unsigned long flags;
+ void *result = NULL;
+
+ spin_lock_irqsave(&priv->ctx_lock, flags);
+
+ list_for_each_entry(dev_ctx, &priv->ctx_list, list)
+ if (dev_ctx->intf->protocol == proto && dev_ctx->intf->get_dev) {
+ result = dev_ctx->intf->get_dev(dev, dev_ctx->context, port);
+ break;
+ }
+
+ spin_unlock_irqrestore(&priv->ctx_lock, flags);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(mlx4_get_protocol_dev);
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 5102ab1ac561..782f11d8fa71 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -103,7 +103,7 @@ MODULE_PARM_DESC(use_prio, "Enable steering by VLAN priority on ETH ports "
static int log_mtts_per_seg = ilog2(MLX4_MTT_ENTRY_PER_SEG);
module_param_named(log_mtts_per_seg, log_mtts_per_seg, int, 0444);
-MODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment (1-5)");
+MODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment (1-7)");
int mlx4_check_port_params(struct mlx4_dev *dev,
enum mlx4_port_type *port_type)
@@ -184,6 +184,10 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev->caps.eth_mtu_cap[i] = dev_cap->eth_mtu[i];
dev->caps.def_mac[i] = dev_cap->def_mac[i];
dev->caps.supported_type[i] = dev_cap->supported_port_types[i];
+ dev->caps.trans_type[i] = dev_cap->trans_type[i];
+ dev->caps.vendor_oui[i] = dev_cap->vendor_oui[i];
+ dev->caps.wavelength[i] = dev_cap->wavelength[i];
+ dev->caps.trans_code[i] = dev_cap->trans_code[i];
}
dev->caps.num_uars = dev_cap->uar_size / PAGE_SIZE;
@@ -221,6 +225,8 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev->caps.bmme_flags = dev_cap->bmme_flags;
dev->caps.reserved_lkey = dev_cap->reserved_lkey;
dev->caps.stat_rate_support = dev_cap->stat_rate_support;
+ dev->caps.udp_rss = dev_cap->udp_rss;
+ dev->caps.loopback_support = dev_cap->loopback_support;
dev->caps.max_gso_sz = dev_cap->max_gso_sz;
dev->caps.log_num_macs = log_num_mac;
@@ -1304,7 +1310,7 @@ static int __init mlx4_verify_params(void)
return -1;
}
- if ((log_mtts_per_seg < 1) || (log_mtts_per_seg > 5)) {
+ if ((log_mtts_per_seg < 1) || (log_mtts_per_seg > 7)) {
pr_warning("mlx4_core: bad log_mtts_per_seg: %d\n", log_mtts_per_seg);
return -1;
}
diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h
index 449210994ee9..dfed6a07c2d7 100644
--- a/drivers/net/mlx4/mlx4_en.h
+++ b/drivers/net/mlx4/mlx4_en.h
@@ -38,19 +38,19 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/netdevice.h>
-#include <linux/inet_lro.h>
#include <linux/mlx4/device.h>
#include <linux/mlx4/qp.h>
#include <linux/mlx4/cq.h>
#include <linux/mlx4/srq.h>
#include <linux/mlx4/doorbell.h>
+#include <linux/mlx4/cmd.h>
#include "en_port.h"
#define DRV_NAME "mlx4_en"
-#define DRV_VERSION "1.4.1.1"
-#define DRV_RELDATE "June 2009"
+#define DRV_VERSION "1.5.1.6"
+#define DRV_RELDATE "August 2010"
#define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN)
@@ -61,7 +61,6 @@
#define MLX4_EN_PAGE_SHIFT 12
#define MLX4_EN_PAGE_SIZE (1 << MLX4_EN_PAGE_SHIFT)
-#define MAX_TX_RINGS 16
#define MAX_RX_RINGS 16
#define TXBB_SIZE 64
#define HEADROOM (2048 / TXBB_SIZE + 1)
@@ -107,6 +106,7 @@ enum {
#define MLX4_EN_SMALL_PKT_SIZE 64
#define MLX4_EN_NUM_TX_RINGS 8
#define MLX4_EN_NUM_PPP_RINGS 8
+#define MAX_TX_RINGS (MLX4_EN_NUM_TX_RINGS + MLX4_EN_NUM_PPP_RINGS)
#define MLX4_EN_DEF_TX_RING_SIZE 512
#define MLX4_EN_DEF_RX_RING_SIZE 1024
@@ -139,10 +139,14 @@ enum {
#define SMALL_PACKET_SIZE (256 - NET_IP_ALIGN)
#define HEADER_COPY_SIZE (128 - NET_IP_ALIGN)
+#define MLX4_LOOPBACK_TEST_PAYLOAD (HEADER_COPY_SIZE - ETH_HLEN)
#define MLX4_EN_MIN_MTU 46
#define ETH_BCAST 0xffffffffffffULL
+#define MLX4_EN_LOOPBACK_RETRIES 5
+#define MLX4_EN_LOOPBACK_TIMEOUT 100
+
#ifdef MLX4_EN_PERF_STAT
/* Number of samples to 'average' */
#define AVG_SIZE 128
@@ -249,7 +253,6 @@ struct mlx4_en_rx_desc {
struct mlx4_en_rx_ring {
struct mlx4_hwq_resources wqres;
struct mlx4_en_rx_alloc page_alloc[MLX4_EN_MAX_RX_FRAGS];
- struct net_lro_mgr lro;
u32 size ; /* number of Rx descs*/
u32 actual_size;
u32 size_mask;
@@ -313,7 +316,8 @@ struct mlx4_en_port_profile {
struct mlx4_en_profile {
int rss_xor;
- int num_lro;
+ int tcp_rss;
+ int udp_rss;
u8 rss_mask;
u32 active_ports;
u32 small_pkt_int;
@@ -337,6 +341,7 @@ struct mlx4_en_dev {
struct mlx4_mr mr;
u32 priv_pdn;
spinlock_t uar_lock;
+ u8 mac_removed[MLX4_MAX_PORTS + 1];
};
@@ -355,6 +360,13 @@ struct mlx4_en_rss_context {
u8 hash_fn;
u8 flags;
__be32 rss_key[10];
+ __be32 base_qpn_udp;
+};
+
+struct mlx4_en_port_state {
+ int link_state;
+ int link_speed;
+ int transciver;
};
struct mlx4_en_pkt_stats {
@@ -365,9 +377,6 @@ struct mlx4_en_pkt_stats {
};
struct mlx4_en_port_stats {
- unsigned long lro_aggregated;
- unsigned long lro_flushed;
- unsigned long lro_no_desc;
unsigned long tso_packets;
unsigned long queue_stopped;
unsigned long wake_queue;
@@ -376,7 +385,7 @@ struct mlx4_en_port_stats {
unsigned long rx_chksum_good;
unsigned long rx_chksum_none;
unsigned long tx_chksum_offload;
-#define NUM_PORT_STATS 11
+#define NUM_PORT_STATS 8
};
struct mlx4_en_perf_stats {
@@ -405,6 +414,7 @@ struct mlx4_en_priv {
struct vlan_group *vlgrp;
struct net_device_stats stats;
struct net_device_stats ret_stats;
+ struct mlx4_en_port_state port_state;
spinlock_t stats_lock;
unsigned long last_moder_packets;
@@ -423,6 +433,8 @@ struct mlx4_en_priv {
u16 sample_interval;
u16 adaptive_rx_coal;
u32 msg_enable;
+ u32 loopback_ok;
+ u32 validate_loopback;
struct mlx4_hwq_resources res;
int link_state;
@@ -463,6 +475,7 @@ struct mlx4_en_priv {
char *mc_addrs;
int mc_addrs_cnt;
struct mlx4_en_stat_out_mbox hw_stats;
+ int vids[128];
};
@@ -531,6 +544,11 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
u8 promisc);
int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset);
+int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port);
+
+#define MLX4_EN_NUM_SELF_TEST 5
+void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf);
+u64 mlx4_en_mac_to_u64(u8 *addr);
/*
* Globals
@@ -555,6 +573,8 @@ do { \
en_print(KERN_WARNING, priv, format, ##arg)
#define en_err(priv, format, arg...) \
en_print(KERN_ERR, priv, format, ##arg)
+#define en_info(priv, format, arg...) \
+ en_print(KERN_INFO, priv, format, ## arg)
#define mlx4_err(mdev, format, arg...) \
pr_err("%s %s: " format, DRV_NAME, \
diff --git a/drivers/net/mlx4/port.c b/drivers/net/mlx4/port.c
index 606aa58afdea..451339559bdc 100644
--- a/drivers/net/mlx4/port.c
+++ b/drivers/net/mlx4/port.c
@@ -111,6 +111,12 @@ int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index)
goto out;
}
}
+
+ if (free < 0) {
+ err = -ENOMEM;
+ goto out;
+ }
+
mlx4_dbg(dev, "Free MAC index is %d\n", free);
if (table->total == table->max) {
@@ -182,6 +188,25 @@ static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
return err;
}
+int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
+{
+ struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
+ int i;
+
+ for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) {
+ if (table->refs[i] &&
+ (vid == (MLX4_VLAN_MASK &
+ be32_to_cpu(table->entries[i])))) {
+ /* VLAN already registered, increase reference count */
+ *idx = i;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
+
int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
{
struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
@@ -205,6 +230,11 @@ int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
}
}
+ if (free < 0) {
+ err = -ENOMEM;
+ goto out;
+ }
+
if (table->total == table->max) {
/* No free vlan entries */
err = -ENOSPC;
diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c
index 5caf0115fa5b..e749f82865fe 100644
--- a/drivers/net/mlx4/profile.c
+++ b/drivers/net/mlx4/profile.c
@@ -85,7 +85,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev,
struct mlx4_resource tmp;
int i, j;
- profile = kzalloc(MLX4_RES_NUM * sizeof *profile, GFP_KERNEL);
+ profile = kcalloc(MLX4_RES_NUM, sizeof(*profile), GFP_KERNEL);
if (!profile)
return -ENOMEM;
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 2d488abcf62d..dd2b6a71c6d7 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -2901,7 +2901,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
mp->dev = dev;
set_params(mp, pd);
- dev->real_num_tx_queues = mp->txq_count;
+ netif_set_real_num_tx_queues(dev, mp->txq_count);
+ netif_set_real_num_rx_queues(dev, mp->rxq_count);
if (pd->phy_addr != MV643XX_ETH_PHY_NONE)
mp->phy = phy_scan(mp, pd->phy_addr);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index fb2c0927d3cc..8524cc40ec57 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -225,6 +225,7 @@ struct myri10ge_priv {
struct msix_entry *msix_vectors;
#ifdef CONFIG_MYRI10GE_DCA
int dca_enabled;
+ int relaxed_order;
#endif
u32 link_state;
unsigned int rdma_tags_available;
@@ -990,7 +991,7 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
* RX queues, so if we get an error, first retry using a
* single TX queue before giving up */
if (status != 0 && mgp->dev->real_num_tx_queues > 1) {
- mgp->dev->real_num_tx_queues = 1;
+ netif_set_real_num_tx_queues(mgp->dev, 1);
cmd.data0 = mgp->num_slices;
cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE;
status = myri10ge_send_cmd(mgp,
@@ -1074,10 +1075,28 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
}
#ifdef CONFIG_MYRI10GE_DCA
+static int myri10ge_toggle_relaxed(struct pci_dev *pdev, int on)
+{
+ int ret, cap, err;
+ u16 ctl;
+
+ cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ if (!cap)
+ return 0;
+
+ err = pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
+ ret = (ctl & PCI_EXP_DEVCTL_RELAX_EN) >> 4;
+ if (ret != on) {
+ ctl &= ~PCI_EXP_DEVCTL_RELAX_EN;
+ ctl |= (on << 4);
+ pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
+ }
+ return ret;
+}
+
static void
myri10ge_write_dca(struct myri10ge_slice_state *ss, int cpu, int tag)
{
- ss->cpu = cpu;
ss->cached_dca_tag = tag;
put_be32(htonl(tag), ss->dca_tag);
}
@@ -1088,9 +1107,10 @@ static inline void myri10ge_update_dca(struct myri10ge_slice_state *ss)
int tag;
if (cpu != ss->cpu) {
- tag = dca_get_tag(cpu);
+ tag = dca3_get_tag(&ss->mgp->pdev->dev, cpu);
if (ss->cached_dca_tag != tag)
myri10ge_write_dca(ss, cpu, tag);
+ ss->cpu = cpu;
}
put_cpu();
}
@@ -1113,9 +1133,13 @@ static void myri10ge_setup_dca(struct myri10ge_priv *mgp)
"dca_add_requester() failed, err=%d\n", err);
return;
}
+ mgp->relaxed_order = myri10ge_toggle_relaxed(pdev, 0);
mgp->dca_enabled = 1;
- for (i = 0; i < mgp->num_slices; i++)
- myri10ge_write_dca(&mgp->ss[i], -1, 0);
+ for (i = 0; i < mgp->num_slices; i++) {
+ mgp->ss[i].cpu = -1;
+ mgp->ss[i].cached_dca_tag = -1;
+ myri10ge_update_dca(&mgp->ss[i]);
+ }
}
static void myri10ge_teardown_dca(struct myri10ge_priv *mgp)
@@ -1126,6 +1150,8 @@ static void myri10ge_teardown_dca(struct myri10ge_priv *mgp)
if (!mgp->dca_enabled)
return;
mgp->dca_enabled = 0;
+ if (mgp->relaxed_order)
+ myri10ge_toggle_relaxed(pdev, 1);
err = dca_remove_requester(&pdev->dev);
}
@@ -1555,12 +1581,12 @@ static irqreturn_t myri10ge_intr(int irq, void *arg)
* valid since MSI-X irqs are not shared */
if ((mgp->dev->real_num_tx_queues == 1) && (ss != mgp->ss)) {
napi_schedule(&ss->napi);
- return (IRQ_HANDLED);
+ return IRQ_HANDLED;
}
/* make sure it is our IRQ, and that the DMA has finished */
if (unlikely(!stats->valid))
- return (IRQ_NONE);
+ return IRQ_NONE;
/* low bit indicates receives are present, so schedule
* napi poll handler */
@@ -1599,7 +1625,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg)
myri10ge_check_statblock(mgp);
put_be32(htonl(3), ss->irq_claim + 1);
- return (IRQ_HANDLED);
+ return IRQ_HANDLED;
}
static int
@@ -3753,8 +3779,8 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
* slices. We give up on MSI-X if we can only get a single
* vector. */
- mgp->msix_vectors = kzalloc(mgp->num_slices *
- sizeof(*mgp->msix_vectors), GFP_KERNEL);
+ mgp->msix_vectors = kcalloc(mgp->num_slices, sizeof(*mgp->msix_vectors),
+ GFP_KERNEL);
if (mgp->msix_vectors == NULL)
goto disable_msix;
for (i = 0; i < mgp->num_slices; i++) {
@@ -3923,7 +3949,8 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_err(&pdev->dev, "failed to alloc slice state\n");
goto abort_with_firmware;
}
- netdev->real_num_tx_queues = mgp->num_slices;
+ netif_set_real_num_tx_queues(netdev, mgp->num_slices);
+ netif_set_real_num_rx_queues(netdev, mgp->num_slices);
status = myri10ge_reset(mgp);
if (status != 0) {
dev_err(&pdev->dev, "failed reset\n");
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 617f898ba5f0..4846e131a04e 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -735,7 +735,7 @@ static int myri_header(struct sk_buff *skb, struct net_device *dev,
int i;
for (i = 0; i < dev->addr_len; i++)
eth->h_dest[i] = 0;
- return(dev->hard_header_len);
+ return dev->hard_header_len;
}
if (daddr) {
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index a6033d48b5cc..2fd39630b1e5 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -1570,7 +1570,7 @@ static int netdev_open(struct net_device *dev)
init_timer(&np->timer);
np->timer.expires = round_jiffies(jiffies + NATSEMI_TIMER_FREQ);
np->timer.data = (unsigned long)dev;
- np->timer.function = &netdev_timer; /* timer handler */
+ np->timer.function = netdev_timer; /* timer handler */
add_timer(&np->timer);
return 0;
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index ca142c47b2e4..94255f09093d 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -678,7 +678,14 @@ static int netconsole_netdev_event(struct notifier_block *this,
strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);
break;
case NETDEV_UNREGISTER:
- netpoll_cleanup(&nt->np);
+ /*
+ * rtnl_lock already held
+ */
+ if (nt->np.dev) {
+ __netpoll_cleanup(&nt->np);
+ dev_put(nt->np.dev);
+ nt->np.dev = NULL;
+ }
/* Fall through */
case NETDEV_GOING_DOWN:
case NETDEV_BONDING_DESLAVE:
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index 6dca3574e355..8e8a97839cb0 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -175,7 +175,10 @@
#define MAX_NUM_CARDS 4
#define MAX_BUFFERS_PER_CMD 32
-#define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + 4)
+#define MAX_TSO_HEADER_DESC 2
+#define MGMT_CMD_DESC_RESV 4
+#define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \
+ + MGMT_CMD_DESC_RESV)
#define NX_MAX_TX_TIMEOUTS 2
/*
@@ -1253,19 +1256,9 @@ struct netxen_adapter {
const struct firmware *fw;
};
-int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port);
-int netxen_niu_disable_xg_port(struct netxen_adapter *adapter);
-
int nx_fw_cmd_query_phy(struct netxen_adapter *adapter, u32 reg, u32 *val);
int nx_fw_cmd_set_phy(struct netxen_adapter *adapter, u32 reg, u32 val);
-/* Functions available from netxen_nic_hw.c */
-int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu);
-int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu);
-
-int netxen_p2_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr);
-int netxen_p3_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr);
-
#define NXRD32(adapter, off) \
(adapter->crb_read(adapter, off))
#define NXWR32(adapter, off, val) \
@@ -1345,11 +1338,8 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid,
struct nx_host_rds_ring *rds_ring);
int netxen_process_cmd_ring(struct netxen_adapter *adapter);
int netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max);
-void netxen_p2_nic_set_multi(struct net_device *netdev);
-void netxen_p3_nic_set_multi(struct net_device *netdev);
+
void netxen_p3_free_mac_list(struct netxen_adapter *adapter);
-int netxen_p2_nic_set_promisc(struct netxen_adapter *adapter, u32 mode);
-int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32);
int netxen_config_intr_coalesce(struct netxen_adapter *adapter);
int netxen_config_rss(struct netxen_adapter *adapter, int enable);
int netxen_config_ipaddr(struct netxen_adapter *adapter, u32 ip, int cmd);
@@ -1364,9 +1354,6 @@ int netxen_config_hw_lro(struct netxen_adapter *adapter, int enable);
int netxen_config_bridged_mode(struct netxen_adapter *adapter, int enable);
int netxen_send_lro_cleanup(struct netxen_adapter *adapter);
-int netxen_nic_set_mac(struct net_device *netdev, void *p);
-struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev);
-
void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
struct nx_host_tx_ring *tx_ring);
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index 29d7b93d0493..37d3ebd65be8 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -319,6 +319,8 @@ static unsigned crb_hub_agt[64] =
#define NETXEN_PCIE_SEM_TIMEOUT 10000
+static int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu);
+
int
netxen_pcie_sem_lock(struct netxen_adapter *adapter, int sem, u32 id_reg)
{
@@ -345,7 +347,7 @@ netxen_pcie_sem_unlock(struct netxen_adapter *adapter, int sem)
NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM_UNLOCK(sem)));
}
-int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port)
+static int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port)
{
if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_1+(0x10000*port), 0x1447);
@@ -356,7 +358,7 @@ int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port)
}
/* Disable an XG interface */
-int netxen_niu_disable_xg_port(struct netxen_adapter *adapter)
+static int netxen_niu_disable_xg_port(struct netxen_adapter *adapter)
{
__u32 mac_cfg;
u32 port = adapter->physical_port;
@@ -383,7 +385,7 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter)
#define MAC_LO(addr) \
((addr[5] << 16) | (addr[4] << 8) | (addr[3]))
-int netxen_p2_nic_set_promisc(struct netxen_adapter *adapter, u32 mode)
+static int netxen_p2_nic_set_promisc(struct netxen_adapter *adapter, u32 mode)
{
u32 mac_cfg;
u32 cnt = 0;
@@ -434,7 +436,7 @@ int netxen_p2_nic_set_promisc(struct netxen_adapter *adapter, u32 mode)
return 0;
}
-int netxen_p2_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr)
+static int netxen_p2_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr)
{
u32 mac_hi, mac_lo;
u32 reg_hi, reg_lo;
@@ -531,7 +533,7 @@ netxen_nic_set_mcast_addr(struct netxen_adapter *adapter,
return 0;
}
-void netxen_p2_nic_set_multi(struct net_device *netdev)
+static void netxen_p2_nic_set_multi(struct net_device *netdev)
{
struct netxen_adapter *adapter = netdev_priv(netdev);
struct netdev_hw_addr *ha;
@@ -598,8 +600,14 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter,
if (nr_desc >= netxen_tx_avail(tx_ring)) {
netif_tx_stop_queue(tx_ring->txq);
- __netif_tx_unlock_bh(tx_ring->txq);
- return -EBUSY;
+ smp_mb();
+ if (netxen_tx_avail(tx_ring) > nr_desc) {
+ if (netxen_tx_avail(tx_ring) > TX_STOP_THRESH)
+ netif_tx_wake_queue(tx_ring->txq);
+ } else {
+ __netif_tx_unlock_bh(tx_ring->txq);
+ return -EBUSY;
+ }
}
do {
@@ -674,7 +682,7 @@ static int nx_p3_nic_add_mac(struct netxen_adapter *adapter,
cur->mac_addr, NETXEN_MAC_ADD);
}
-void netxen_p3_nic_set_multi(struct net_device *netdev)
+static void netxen_p3_nic_set_multi(struct net_device *netdev)
{
struct netxen_adapter *adapter = netdev_priv(netdev);
struct netdev_hw_addr *ha;
@@ -721,7 +729,7 @@ send_fw_cmd:
}
}
-int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32 mode)
+static int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32 mode)
{
nx_nic_req_t req;
u64 word;
@@ -754,7 +762,7 @@ void netxen_p3_free_mac_list(struct netxen_adapter *adapter)
}
}
-int netxen_p3_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr)
+static int netxen_p3_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr)
{
/* assuming caller has already copied new addr to netdev */
netxen_p3_nic_set_multi(adapter->netdev);
@@ -1816,14 +1824,14 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter)
if (netxen_rom_fast_read(adapter, offset, &board_type))
return -EIO;
- adapter->ahw.board_type = board_type;
-
if (board_type == NETXEN_BRDTYPE_P3_4_GB_MM) {
u32 gpio = NXRD32(adapter, NETXEN_ROMUSB_GLB_PAD_GPIO_I);
if ((gpio & 0x8000) == 0)
board_type = NETXEN_BRDTYPE_P3_10G_TP;
}
+ adapter->ahw.board_type = board_type;
+
switch (board_type) {
case NETXEN_BRDTYPE_P2_SB35_4G:
adapter->ahw.port_type = NETXEN_NIC_GBE;
@@ -1867,16 +1875,7 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter)
}
/* NIU access sections */
-
-int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu)
-{
- new_mtu += MTU_FUDGE_FACTOR;
- NXWR32(adapter, NETXEN_NIU_GB_MAX_FRAME_SIZE(adapter->physical_port),
- new_mtu);
- return 0;
-}
-
-int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu)
+static int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu)
{
new_mtu += MTU_FUDGE_FACTOR;
if (adapter->physical_port == 0)
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index b075a35b85d4..95fe552aa279 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -346,7 +346,7 @@ static u32 netxen_decode_crb_addr(u32 addr)
if (pci_base == NETXEN_ADDR_ERROR)
return pci_base;
else
- return (pci_base + offset);
+ return pci_base + offset;
}
#define NETXEN_MAX_ROM_WAIT_USEC 100
@@ -1763,14 +1763,10 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter)
smp_mb();
- if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
- __netif_tx_lock(tx_ring->txq, smp_processor_id());
- if (netxen_tx_avail(tx_ring) > TX_STOP_THRESH) {
+ if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev))
+ if (netxen_tx_avail(tx_ring) > TX_STOP_THRESH)
netif_wake_queue(netdev);
- adapter->tx_timeo_cnt = 0;
- }
- __netif_tx_unlock(tx_ring->txq);
- }
+ adapter->tx_timeo_cnt = 0;
}
/*
* If everything is freed up to consumer then check if the ring is full
@@ -1789,7 +1785,7 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter)
done = (sw_consumer == hw_consumer);
spin_unlock(&adapter->tx_clean_lock);
- return (done);
+ return done;
}
void
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 73d314592230..50820beac3aa 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -95,6 +95,8 @@ 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 struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev);
+static int netxen_nic_set_mac(struct net_device *netdev, void *p);
/* PCI Device ID Table */
#define ENTRY(device) \
@@ -125,11 +127,6 @@ netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
struct nx_host_tx_ring *tx_ring)
{
NXWRIO(adapter, tx_ring->crb_cmd_producer, tx_ring->producer);
-
- if (netxen_tx_avail(tx_ring) <= TX_STOP_THRESH) {
- netif_stop_queue(adapter->netdev);
- smp_mb();
- }
}
static uint32_t crb_cmd_consumer[4] = {
@@ -177,7 +174,7 @@ netxen_alloc_sds_rings(struct netxen_recv_context *recv_ctx, int count)
recv_ctx->sds_rings = kzalloc(size, GFP_KERNEL);
- return (recv_ctx->sds_rings == NULL);
+ return recv_ctx->sds_rings == NULL;
}
static void
@@ -460,7 +457,7 @@ netxen_read_mac_addr(struct netxen_adapter *adapter)
return 0;
}
-int netxen_nic_set_mac(struct net_device *netdev, void *p)
+static int netxen_nic_set_mac(struct net_device *netdev, void *p)
{
struct netxen_adapter *adapter = netdev_priv(netdev);
struct sockaddr *addr = p;
@@ -1209,7 +1206,7 @@ netxen_setup_netdev(struct netxen_adapter *adapter,
adapter->max_mc_count = 16;
netdev->netdev_ops = &netxen_netdev_ops;
- netdev->watchdog_timeo = 2*HZ;
+ netdev->watchdog_timeo = 5*HZ;
netxen_nic_change_mtu(netdev, netdev->mtu);
@@ -1254,6 +1251,28 @@ netxen_setup_netdev(struct netxen_adapter *adapter,
return 0;
}
+#ifdef CONFIG_PCIEAER
+static void netxen_mask_aer_correctable(struct netxen_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct pci_dev *root = pdev->bus->self;
+ u32 aer_pos;
+
+ if (adapter->ahw.board_type != NETXEN_BRDTYPE_P3_4_GB_MM &&
+ adapter->ahw.board_type != NETXEN_BRDTYPE_P3_10G_TP)
+ return;
+
+ if (root->pcie_type != PCI_EXP_TYPE_ROOT_PORT)
+ return;
+
+ aer_pos = pci_find_ext_capability(root, PCI_EXT_CAP_ID_ERR);
+ if (!aer_pos)
+ return;
+
+ pci_write_config_dword(root, aer_pos + PCI_ERR_COR_MASK, 0xffff);
+}
+#endif
+
static int __devinit
netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -1322,6 +1341,10 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_iounmap;
}
+#ifdef CONFIG_PCIEAER
+ netxen_mask_aer_correctable(adapter);
+#endif
+
/* Mezz cards have PCI function 0,2,3 enabled */
switch (adapter->ahw.board_type) {
case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ:
@@ -1825,9 +1848,13 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
/* 4 fragments per cmd des */
no_of_desc = (frag_count + 3) >> 2;
- if (unlikely(no_of_desc + 2 > netxen_tx_avail(tx_ring))) {
+ if (unlikely(netxen_tx_avail(tx_ring) <= TX_STOP_THRESH)) {
netif_stop_queue(netdev);
- return NETDEV_TX_BUSY;
+ smp_mb();
+ if (netxen_tx_avail(tx_ring) > TX_STOP_THRESH)
+ netif_start_queue(netdev);
+ else
+ return NETDEV_TX_BUSY;
}
producer = tx_ring->producer;
@@ -2027,7 +2054,7 @@ request_reset:
clear_bit(__NX_RESETTING, &adapter->state);
}
-struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev)
+static struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev)
{
struct netxen_adapter *adapter = netdev_priv(netdev);
struct net_device_stats *stats = &netdev->stats;
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index fe6983af6918..781e368329f9 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -283,7 +283,7 @@ static int niu_enable_interrupts(struct niu *np, int on)
static u32 phy_encode(u32 type, int port)
{
- return (type << (port * 2));
+ return type << (port * 2);
}
static u32 phy_decode(u32 val, int port)
@@ -3043,8 +3043,7 @@ static int tcam_flush_all(struct niu *np)
static u64 hash_addr_regval(unsigned long index, unsigned long num_entries)
{
- return ((u64)index | (num_entries == 1 ?
- HASH_TBL_ADDR_AUTOINC : 0));
+ return (u64)index | (num_entries == 1 ? HASH_TBL_ADDR_AUTOINC : 0);
}
#if 0
@@ -3276,7 +3275,7 @@ static u16 tcam_get_index(struct niu *np, u16 idx)
/* One entry reserved for IP fragment rule */
if (idx >= (np->clas.tcam_sz - 1))
idx = 0;
- return (np->clas.tcam_top + ((idx+1) * np->parent->num_ports));
+ return np->clas.tcam_top + ((idx+1) * np->parent->num_ports);
}
static u16 tcam_get_size(struct niu *np)
@@ -3313,7 +3312,7 @@ static unsigned int niu_hash_rxaddr(struct rx_ring_info *rp, u64 a)
a >>= PAGE_SHIFT;
a ^= (a >> ilog2(MAX_RBR_RING_SIZE));
- return (a & (MAX_RBR_RING_SIZE - 1));
+ return a & (MAX_RBR_RING_SIZE - 1);
}
static struct page *niu_find_rxpage(struct rx_ring_info *rp, u64 addr,
@@ -3484,7 +3483,7 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np,
RCR_ENTRY_ERROR)))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
} else if (!(val & RCR_ENTRY_MULTI))
append_size = len - skb->len;
@@ -4502,9 +4501,10 @@ static int niu_alloc_channels(struct niu *np)
np->num_rx_rings = parent->rxchan_per_port[port];
np->num_tx_rings = parent->txchan_per_port[port];
- np->dev->real_num_tx_queues = np->num_tx_rings;
+ netif_set_real_num_rx_queues(np->dev, np->num_rx_rings);
+ netif_set_real_num_tx_queues(np->dev, np->num_tx_rings);
- np->rx_rings = kzalloc(np->num_rx_rings * sizeof(struct rx_ring_info),
+ np->rx_rings = kcalloc(np->num_rx_rings, sizeof(struct rx_ring_info),
GFP_KERNEL);
err = -ENOMEM;
if (!np->rx_rings)
@@ -4538,7 +4538,7 @@ static int niu_alloc_channels(struct niu *np)
return err;
}
- np->tx_rings = kzalloc(np->num_tx_rings * sizeof(struct tx_ring_info),
+ np->tx_rings = kcalloc(np->num_tx_rings, sizeof(struct tx_ring_info),
GFP_KERNEL);
err = -ENOMEM;
if (!np->tx_rings)
@@ -7090,24 +7090,20 @@ static int niu_get_hash_opts(struct niu *np, struct ethtool_rxnfc *nfc)
static void niu_get_ip4fs_from_tcam_key(struct niu_tcam_entry *tp,
struct ethtool_rx_flow_spec *fsp)
{
+ u32 tmp;
+ u16 prt;
- fsp->h_u.tcp_ip4_spec.ip4src = (tp->key[3] & TCAM_V4KEY3_SADDR) >>
- TCAM_V4KEY3_SADDR_SHIFT;
- fsp->h_u.tcp_ip4_spec.ip4dst = (tp->key[3] & TCAM_V4KEY3_DADDR) >>
- TCAM_V4KEY3_DADDR_SHIFT;
- fsp->m_u.tcp_ip4_spec.ip4src = (tp->key_mask[3] & TCAM_V4KEY3_SADDR) >>
- TCAM_V4KEY3_SADDR_SHIFT;
- fsp->m_u.tcp_ip4_spec.ip4dst = (tp->key_mask[3] & TCAM_V4KEY3_DADDR) >>
- TCAM_V4KEY3_DADDR_SHIFT;
-
- fsp->h_u.tcp_ip4_spec.ip4src =
- cpu_to_be32(fsp->h_u.tcp_ip4_spec.ip4src);
- fsp->m_u.tcp_ip4_spec.ip4src =
- cpu_to_be32(fsp->m_u.tcp_ip4_spec.ip4src);
- fsp->h_u.tcp_ip4_spec.ip4dst =
- cpu_to_be32(fsp->h_u.tcp_ip4_spec.ip4dst);
- fsp->m_u.tcp_ip4_spec.ip4dst =
- cpu_to_be32(fsp->m_u.tcp_ip4_spec.ip4dst);
+ tmp = (tp->key[3] & TCAM_V4KEY3_SADDR) >> TCAM_V4KEY3_SADDR_SHIFT;
+ fsp->h_u.tcp_ip4_spec.ip4src = cpu_to_be32(tmp);
+
+ tmp = (tp->key[3] & TCAM_V4KEY3_DADDR) >> TCAM_V4KEY3_DADDR_SHIFT;
+ fsp->h_u.tcp_ip4_spec.ip4dst = cpu_to_be32(tmp);
+
+ tmp = (tp->key_mask[3] & TCAM_V4KEY3_SADDR) >> TCAM_V4KEY3_SADDR_SHIFT;
+ fsp->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(tmp);
+
+ tmp = (tp->key_mask[3] & TCAM_V4KEY3_DADDR) >> TCAM_V4KEY3_DADDR_SHIFT;
+ fsp->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(tmp);
fsp->h_u.tcp_ip4_spec.tos = (tp->key[2] & TCAM_V4KEY2_TOS) >>
TCAM_V4KEY2_TOS_SHIFT;
@@ -7118,54 +7114,40 @@ static void niu_get_ip4fs_from_tcam_key(struct niu_tcam_entry *tp,
case TCP_V4_FLOW:
case UDP_V4_FLOW:
case SCTP_V4_FLOW:
- fsp->h_u.tcp_ip4_spec.psrc =
- ((tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
- TCAM_V4KEY2_PORT_SPI_SHIFT) >> 16;
- fsp->h_u.tcp_ip4_spec.pdst =
- ((tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
- TCAM_V4KEY2_PORT_SPI_SHIFT) & 0xffff;
- fsp->m_u.tcp_ip4_spec.psrc =
- ((tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
- TCAM_V4KEY2_PORT_SPI_SHIFT) >> 16;
- fsp->m_u.tcp_ip4_spec.pdst =
- ((tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
- TCAM_V4KEY2_PORT_SPI_SHIFT) & 0xffff;
+ prt = ((tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
+ TCAM_V4KEY2_PORT_SPI_SHIFT) >> 16;
+ fsp->h_u.tcp_ip4_spec.psrc = cpu_to_be16(prt);
- fsp->h_u.tcp_ip4_spec.psrc =
- cpu_to_be16(fsp->h_u.tcp_ip4_spec.psrc);
- fsp->h_u.tcp_ip4_spec.pdst =
- cpu_to_be16(fsp->h_u.tcp_ip4_spec.pdst);
- fsp->m_u.tcp_ip4_spec.psrc =
- cpu_to_be16(fsp->m_u.tcp_ip4_spec.psrc);
- fsp->m_u.tcp_ip4_spec.pdst =
- cpu_to_be16(fsp->m_u.tcp_ip4_spec.pdst);
+ prt = ((tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
+ TCAM_V4KEY2_PORT_SPI_SHIFT) & 0xffff;
+ fsp->h_u.tcp_ip4_spec.pdst = cpu_to_be16(prt);
+
+ prt = ((tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
+ TCAM_V4KEY2_PORT_SPI_SHIFT) >> 16;
+ fsp->m_u.tcp_ip4_spec.psrc = cpu_to_be16(prt);
+
+ prt = ((tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
+ TCAM_V4KEY2_PORT_SPI_SHIFT) & 0xffff;
+ fsp->m_u.tcp_ip4_spec.pdst = cpu_to_be16(prt);
break;
case AH_V4_FLOW:
case ESP_V4_FLOW:
- fsp->h_u.ah_ip4_spec.spi =
- (tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
- TCAM_V4KEY2_PORT_SPI_SHIFT;
- fsp->m_u.ah_ip4_spec.spi =
- (tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
+ tmp = (tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
TCAM_V4KEY2_PORT_SPI_SHIFT;
+ fsp->h_u.ah_ip4_spec.spi = cpu_to_be32(tmp);
- fsp->h_u.ah_ip4_spec.spi =
- cpu_to_be32(fsp->h_u.ah_ip4_spec.spi);
- fsp->m_u.ah_ip4_spec.spi =
- cpu_to_be32(fsp->m_u.ah_ip4_spec.spi);
+ tmp = (tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
+ TCAM_V4KEY2_PORT_SPI_SHIFT;
+ fsp->m_u.ah_ip4_spec.spi = cpu_to_be32(tmp);
break;
case IP_USER_FLOW:
- fsp->h_u.usr_ip4_spec.l4_4_bytes =
- (tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
- TCAM_V4KEY2_PORT_SPI_SHIFT;
- fsp->m_u.usr_ip4_spec.l4_4_bytes =
- (tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
+ tmp = (tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
TCAM_V4KEY2_PORT_SPI_SHIFT;
+ fsp->h_u.usr_ip4_spec.l4_4_bytes = cpu_to_be32(tmp);
- fsp->h_u.usr_ip4_spec.l4_4_bytes =
- cpu_to_be32(fsp->h_u.usr_ip4_spec.l4_4_bytes);
- fsp->m_u.usr_ip4_spec.l4_4_bytes =
- cpu_to_be32(fsp->m_u.usr_ip4_spec.l4_4_bytes);
+ tmp = (tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
+ TCAM_V4KEY2_PORT_SPI_SHIFT;
+ fsp->m_u.usr_ip4_spec.l4_4_bytes = cpu_to_be32(tmp);
fsp->h_u.usr_ip4_spec.proto =
(tp->key[2] & TCAM_V4KEY2_PROTO) >>
@@ -7462,10 +7444,12 @@ static int niu_add_ethtool_tcam_entry(struct niu *np,
if (fsp->flow_type == IP_USER_FLOW) {
int i;
int add_usr_cls = 0;
- int ipv6 = 0;
struct ethtool_usrip4_spec *uspec = &fsp->h_u.usr_ip4_spec;
struct ethtool_usrip4_spec *umask = &fsp->m_u.usr_ip4_spec;
+ if (uspec->ip_ver != ETH_RX_NFC_IP4)
+ return -EINVAL;
+
niu_lock_parent(np, flags);
for (i = 0; i < NIU_L3_PROG_CLS; i++) {
@@ -7494,9 +7478,7 @@ static int niu_add_ethtool_tcam_entry(struct niu *np,
default:
break;
}
- if (uspec->ip_ver == ETH_RX_NFC_IP6)
- ipv6 = 1;
- ret = tcam_user_ip_class_set(np, class, ipv6,
+ ret = tcam_user_ip_class_set(np, class, 0,
uspec->proto,
uspec->tos,
umask->tos);
@@ -7553,16 +7535,7 @@ static int niu_add_ethtool_tcam_entry(struct niu *np,
ret = -EINVAL;
goto out;
case IP_USER_FLOW:
- if (fsp->h_u.usr_ip4_spec.ip_ver == ETH_RX_NFC_IP4) {
- niu_get_tcamkey_from_ip4fs(fsp, tp, l2_rdc_table,
- class);
- } else {
- /* Not yet implemented */
- netdev_info(np->dev, "niu%d: In %s(): usr flow for IPv6 not implemented\n",
- parent->index, __func__);
- ret = -EINVAL;
- goto out;
- }
+ niu_get_tcamkey_from_ip4fs(fsp, tp, l2_rdc_table, class);
break;
default:
netdev_info(np->dev, "niu%d: In %s(): Unknown flow type %d\n",
@@ -7805,11 +7778,11 @@ static int niu_get_sset_count(struct net_device *dev, int stringset)
if (stringset != ETH_SS_STATS)
return -EINVAL;
- return ((np->flags & NIU_FLAGS_XMAC ?
+ return (np->flags & NIU_FLAGS_XMAC ?
NUM_XMAC_STAT_KEYS :
NUM_BMAC_STAT_KEYS) +
(np->num_rx_rings * NUM_RXCHAN_STAT_KEYS) +
- (np->num_tx_rings * NUM_TXCHAN_STAT_KEYS));
+ (np->num_tx_rings * NUM_TXCHAN_STAT_KEYS);
}
static void niu_get_ethtool_stats(struct net_device *dev,
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 5a3488f76b38..84134c766f3a 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -772,7 +772,7 @@ static int ns83820_setup_rx(struct net_device *ndev)
phy_intr(ndev);
/* Okay, let it rip */
- spin_lock_irq(&dev->misc_lock);
+ spin_lock(&dev->misc_lock);
dev->IMR_cache |= ISR_PHY;
dev->IMR_cache |= ISR_RXRCMP;
//dev->IMR_cache |= ISR_RXERR;
@@ -923,7 +923,7 @@ static void rx_irq(struct net_device *ndev)
if ((extsts & 0x002a0000) && !(extsts & 0x00540000)) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else {
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
}
skb->protocol = eth_type_trans(skb, ndev);
#ifdef NS83820_VLAN_ACCEL_SUPPORT
@@ -1246,7 +1246,6 @@ static int ns83820_get_settings(struct net_device *ndev,
{
struct ns83820 *dev = PRIV(ndev);
u32 cfg, tanar, tbicr;
- int have_optical = 0;
int fullduplex = 0;
/*
@@ -1267,25 +1266,25 @@ static int ns83820_get_settings(struct net_device *ndev,
tanar = readl(dev->base + TANAR);
tbicr = readl(dev->base + TBICR);
- if (dev->CFG_cache & CFG_TBI_EN) {
- /* we have an optical interface */
- have_optical = 1;
- fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
-
- } else {
- /* We have copper */
- fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
- }
+ fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
cmd->supported = SUPPORTED_Autoneg;
- /* we have optical interface */
if (dev->CFG_cache & CFG_TBI_EN) {
+ /* we have optical interface */
cmd->supported |= SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE;
cmd->port = PORT_FIBRE;
- } /* TODO: else copper related support */
+ } else {
+ /* we have copper */
+ cmd->supported |= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_MII;
+ cmd->port = PORT_MII;
+ }
cmd->duplex = fullduplex ? DUPLEX_FULL : DUPLEX_HALF;
switch (cfg / CFG_SPDSTS0 & 3) {
@@ -1299,7 +1298,8 @@ static int ns83820_get_settings(struct net_device *ndev,
cmd->speed = SPEED_10;
break;
}
- cmd->autoneg = (tbicr & TBICR_MR_AN_ENABLE) ? 1: 0;
+ cmd->autoneg = (tbicr & TBICR_MR_AN_ENABLE)
+ ? AUTONEG_ENABLE : AUTONEG_DISABLE;
return 0;
}
@@ -1405,6 +1405,13 @@ static const struct ethtool_ops ops = {
.get_link = ns83820_get_link
};
+static inline void ns83820_disable_interrupts(struct ns83820 *dev)
+{
+ writel(0, dev->base + IMR);
+ writel(0, dev->base + IER);
+ readl(dev->base + IER);
+}
+
/* this function is called in irq context from the ISR */
static void ns83820_mib_isr(struct ns83820 *dev)
{
@@ -1557,10 +1564,7 @@ static int ns83820_stop(struct net_device *ndev)
/* FIXME: protect against interrupt handler? */
del_timer_sync(&dev->tx_watchdog);
- /* disable interrupts */
- writel(0, dev->base + IMR);
- writel(0, dev->base + IER);
- readl(dev->base + IER);
+ ns83820_disable_interrupts(dev);
dev->rx_info.up = 0;
synchronize_irq(dev->pci_dev->irq);
@@ -2023,10 +2027,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev,
dev->tx_descs, (long)dev->tx_phy_descs,
dev->rx_info.descs, (long)dev->rx_info.phy_descs);
- /* disable interrupts */
- writel(0, dev->base + IMR);
- writel(0, dev->base + IER);
- readl(dev->base + IER);
+ ns83820_disable_interrupts(dev);
dev->IMR_cache = 0;
@@ -2250,9 +2251,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev,
return 0;
out_cleanup:
- writel(0, dev->base + IMR); /* paranoia */
- writel(0, dev->base + IER);
- readl(dev->base + IER);
+ ns83820_disable_interrupts(dev); /* paranoia */
out_free_irq:
rtnl_unlock();
free_irq(pci_dev->irq, ndev);
@@ -2277,9 +2276,7 @@ static void __devexit ns83820_remove_one(struct pci_dev *pci_dev)
if (!ndev) /* paranoia */
return;
- writel(0, dev->base + IMR); /* paranoia */
- writel(0, dev->base + IER);
- readl(dev->base + IER);
+ ns83820_disable_interrupts(dev); /* paranoia */
unregister_netdev(ndev);
free_irq(dev->pci_dev->irq, ndev);
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index 8ab6ae0a6107..828e97cacdbf 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -808,7 +808,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac_rxring *rx,
skb->csum = (macrx & XCT_MACRX_CSUM_M) >>
XCT_MACRX_CSUM_S;
} else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
packets++;
tot_bytes += len;
diff --git a/drivers/net/pasemi_mac_ethtool.c b/drivers/net/pasemi_mac_ethtool.c
index fefa79e34b95..4825959a0efe 100644
--- a/drivers/net/pasemi_mac_ethtool.c
+++ b/drivers/net/pasemi_mac_ethtool.c
@@ -90,21 +90,6 @@ pasemi_mac_ethtool_set_settings(struct net_device *netdev,
return phy_ethtool_sset(phydev, cmd);
}
-static void
-pasemi_mac_ethtool_get_drvinfo(struct net_device *netdev,
- struct ethtool_drvinfo *drvinfo)
-{
- struct pasemi_mac *mac;
- mac = netdev_priv(netdev);
-
- /* clear and fill out info */
- memset(drvinfo, 0, sizeof(struct ethtool_drvinfo));
- strncpy(drvinfo->driver, "pasemi_mac", 12);
- strcpy(drvinfo->version, "N/A");
- strcpy(drvinfo->fw_version, "N/A");
- strncpy(drvinfo->bus_info, pci_name(mac->pdev), 32);
-}
-
static u32
pasemi_mac_ethtool_get_msglevel(struct net_device *netdev)
{
@@ -164,7 +149,6 @@ static void pasemi_mac_get_strings(struct net_device *netdev, u32 stringset,
const struct ethtool_ops pasemi_mac_ethtool_ops = {
.get_settings = pasemi_mac_ethtool_get_settings,
.set_settings = pasemi_mac_ethtool_set_settings,
- .get_drvinfo = pasemi_mac_ethtool_get_drvinfo,
.get_msglevel = pasemi_mac_ethtool_get_msglevel,
.set_msglevel = pasemi_mac_ethtool_set_msglevel,
.get_link = ethtool_op_get_link,
diff --git a/drivers/net/pch_gbe/Makefile b/drivers/net/pch_gbe/Makefile
new file mode 100644
index 000000000000..31288d4ad248
--- /dev/null
+++ b/drivers/net/pch_gbe/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_PCH_GBE) += pch_gbe.o
+
+pch_gbe-y := pch_gbe_phy.o pch_gbe_ethtool.o pch_gbe_param.o
+pch_gbe-y += pch_gbe_api.o pch_gbe_main.o
diff --git a/drivers/net/pch_gbe/pch_gbe.h b/drivers/net/pch_gbe/pch_gbe.h
new file mode 100644
index 000000000000..a0c26a99520f
--- /dev/null
+++ b/drivers/net/pch_gbe/pch_gbe.h
@@ -0,0 +1,659 @@
+/*
+ * Copyright (C) 1999 - 2010 Intel Corporation.
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This code was derived from the Intel e1000e Linux driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _PCH_GBE_H_
+#define _PCH_GBE_H_
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/mii.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/vmalloc.h>
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+
+/**
+ * pch_gbe_regs_mac_adr - Structure holding values of mac address registers
+ * @high Denotes the 1st to 4th byte from the initial of MAC address
+ * @low Denotes the 5th to 6th byte from the initial of MAC address
+ */
+struct pch_gbe_regs_mac_adr {
+ u32 high;
+ u32 low;
+};
+/**
+ * pch_udc_regs - Structure holding values of MAC registers
+ */
+struct pch_gbe_regs {
+ u32 INT_ST;
+ u32 INT_EN;
+ u32 MODE;
+ u32 RESET;
+ u32 TCPIP_ACC;
+ u32 EX_LIST;
+ u32 INT_ST_HOLD;
+ u32 PHY_INT_CTRL;
+ u32 MAC_RX_EN;
+ u32 RX_FCTRL;
+ u32 PAUSE_REQ;
+ u32 RX_MODE;
+ u32 TX_MODE;
+ u32 RX_FIFO_ST;
+ u32 TX_FIFO_ST;
+ u32 TX_FID;
+ u32 TX_RESULT;
+ u32 PAUSE_PKT1;
+ u32 PAUSE_PKT2;
+ u32 PAUSE_PKT3;
+ u32 PAUSE_PKT4;
+ u32 PAUSE_PKT5;
+ u32 reserve[2];
+ struct pch_gbe_regs_mac_adr mac_adr[16];
+ u32 ADDR_MASK;
+ u32 MIIM;
+ u32 reserve2;
+ u32 RGMII_ST;
+ u32 RGMII_CTRL;
+ u32 reserve3[3];
+ u32 DMA_CTRL;
+ u32 reserve4[3];
+ u32 RX_DSC_BASE;
+ u32 RX_DSC_SIZE;
+ u32 RX_DSC_HW_P;
+ u32 RX_DSC_HW_P_HLD;
+ u32 RX_DSC_SW_P;
+ u32 reserve5[3];
+ u32 TX_DSC_BASE;
+ u32 TX_DSC_SIZE;
+ u32 TX_DSC_HW_P;
+ u32 TX_DSC_HW_P_HLD;
+ u32 TX_DSC_SW_P;
+ u32 reserve6[3];
+ u32 RX_DMA_ST;
+ u32 TX_DMA_ST;
+ u32 reserve7[2];
+ u32 WOL_ST;
+ u32 WOL_CTRL;
+ u32 WOL_ADDR_MASK;
+};
+
+/* Interrupt Status */
+/* Interrupt Status Hold */
+/* Interrupt Enable */
+#define PCH_GBE_INT_RX_DMA_CMPLT 0x00000001 /* Receive DMA Transfer Complete */
+#define PCH_GBE_INT_RX_VALID 0x00000002 /* MAC Normal Receive Complete */
+#define PCH_GBE_INT_RX_FRAME_ERR 0x00000004 /* Receive frame error */
+#define PCH_GBE_INT_RX_FIFO_ERR 0x00000008 /* Receive FIFO Overflow */
+#define PCH_GBE_INT_RX_DMA_ERR 0x00000010 /* Receive DMA Transfer Error */
+#define PCH_GBE_INT_RX_DSC_EMP 0x00000020 /* Receive Descriptor Empty */
+#define PCH_GBE_INT_TX_CMPLT 0x00000100 /* MAC Transmission Complete */
+#define PCH_GBE_INT_TX_DMA_CMPLT 0x00000200 /* DMA Transfer Complete */
+#define PCH_GBE_INT_TX_FIFO_ERR 0x00000400 /* Transmission FIFO underflow. */
+#define PCH_GBE_INT_TX_DMA_ERR 0x00000800 /* Transmission DMA Error */
+#define PCH_GBE_INT_PAUSE_CMPLT 0x00001000 /* Pause Transmission complete */
+#define PCH_GBE_INT_MIIM_CMPLT 0x00010000 /* MIIM I/F Read completion */
+#define PCH_GBE_INT_PHY_INT 0x00100000 /* Interruption from PHY */
+#define PCH_GBE_INT_WOL_DET 0x01000000 /* Wake On LAN Event detection. */
+#define PCH_GBE_INT_TCPIP_ERR 0x10000000 /* TCP/IP Accelerator Error */
+
+/* Mode */
+#define PCH_GBE_MODE_MII_ETHER 0x00000000 /* GIGA Ethernet Mode [MII] */
+#define PCH_GBE_MODE_GMII_ETHER 0x80000000 /* GIGA Ethernet Mode [GMII] */
+#define PCH_GBE_MODE_HALF_DUPLEX 0x00000000 /* Duplex Mode [half duplex] */
+#define PCH_GBE_MODE_FULL_DUPLEX 0x40000000 /* Duplex Mode [full duplex] */
+#define PCH_GBE_MODE_FR_BST 0x04000000 /* Frame bursting is done */
+
+/* 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 */
+
+/* TCP/IP Accelerator Control */
+#define PCH_GBE_EX_LIST_EN 0x00000008 /* External List Enable */
+#define PCH_GBE_RX_TCPIPACC_OFF 0x00000004 /* RX TCP/IP ACC Disabled */
+#define PCH_GBE_TX_TCPIPACC_EN 0x00000002 /* TX TCP/IP ACC Enable */
+#define PCH_GBE_RX_TCPIPACC_EN 0x00000001 /* RX TCP/IP ACC Enable */
+
+/* MAC RX Enable */
+#define PCH_GBE_MRE_MAC_RX_EN 0x00000001 /* MAC Receive Enable */
+
+/* RX Flow Control */
+#define PCH_GBE_FL_CTRL_EN 0x80000000 /* Pause packet is enabled */
+
+/* Pause Packet Request */
+#define PCH_GBE_PS_PKT_RQ 0x80000000 /* Pause packet Request */
+
+/* RX Mode */
+#define PCH_GBE_ADD_FIL_EN 0x80000000 /* Address Filtering Enable */
+/* Multicast Filtering Enable */
+#define PCH_GBE_MLT_FIL_EN 0x40000000
+/* Receive Almost Empty Threshold */
+#define PCH_GBE_RH_ALM_EMP_4 0x00000000 /* 4 words */
+#define PCH_GBE_RH_ALM_EMP_8 0x00004000 /* 8 words */
+#define PCH_GBE_RH_ALM_EMP_16 0x00008000 /* 16 words */
+#define PCH_GBE_RH_ALM_EMP_32 0x0000C000 /* 32 words */
+/* Receive Almost Full Threshold */
+#define PCH_GBE_RH_ALM_FULL_4 0x00000000 /* 4 words */
+#define PCH_GBE_RH_ALM_FULL_8 0x00001000 /* 8 words */
+#define PCH_GBE_RH_ALM_FULL_16 0x00002000 /* 16 words */
+#define PCH_GBE_RH_ALM_FULL_32 0x00003000 /* 32 words */
+/* RX FIFO Read Triger Threshold */
+#define PCH_GBE_RH_RD_TRG_4 0x00000000 /* 4 words */
+#define PCH_GBE_RH_RD_TRG_8 0x00000200 /* 8 words */
+#define PCH_GBE_RH_RD_TRG_16 0x00000400 /* 16 words */
+#define PCH_GBE_RH_RD_TRG_32 0x00000600 /* 32 words */
+#define PCH_GBE_RH_RD_TRG_64 0x00000800 /* 64 words */
+#define PCH_GBE_RH_RD_TRG_128 0x00000A00 /* 128 words */
+#define PCH_GBE_RH_RD_TRG_256 0x00000C00 /* 256 words */
+#define PCH_GBE_RH_RD_TRG_512 0x00000E00 /* 512 words */
+
+/* Receive Descriptor bit definitions */
+#define PCH_GBE_RXD_ACC_STAT_BCAST 0x00000400
+#define PCH_GBE_RXD_ACC_STAT_MCAST 0x00000200
+#define PCH_GBE_RXD_ACC_STAT_UCAST 0x00000100
+#define PCH_GBE_RXD_ACC_STAT_TCPIPOK 0x000000C0
+#define PCH_GBE_RXD_ACC_STAT_IPOK 0x00000080
+#define PCH_GBE_RXD_ACC_STAT_TCPOK 0x00000040
+#define PCH_GBE_RXD_ACC_STAT_IP6ERR 0x00000020
+#define PCH_GBE_RXD_ACC_STAT_OFLIST 0x00000010
+#define PCH_GBE_RXD_ACC_STAT_TYPEIP 0x00000008
+#define PCH_GBE_RXD_ACC_STAT_MACL 0x00000004
+#define PCH_GBE_RXD_ACC_STAT_PPPOE 0x00000002
+#define PCH_GBE_RXD_ACC_STAT_VTAGT 0x00000001
+#define PCH_GBE_RXD_GMAC_STAT_PAUSE 0x0200
+#define PCH_GBE_RXD_GMAC_STAT_MARBR 0x0100
+#define PCH_GBE_RXD_GMAC_STAT_MARMLT 0x0080
+#define PCH_GBE_RXD_GMAC_STAT_MARIND 0x0040
+#define PCH_GBE_RXD_GMAC_STAT_MARNOTMT 0x0020
+#define PCH_GBE_RXD_GMAC_STAT_TLONG 0x0010
+#define PCH_GBE_RXD_GMAC_STAT_TSHRT 0x0008
+#define PCH_GBE_RXD_GMAC_STAT_NOTOCTAL 0x0004
+#define PCH_GBE_RXD_GMAC_STAT_NBLERR 0x0002
+#define PCH_GBE_RXD_GMAC_STAT_CRCERR 0x0001
+
+/* Transmit Descriptor bit definitions */
+#define PCH_GBE_TXD_CTRL_TCPIP_ACC_OFF 0x0008
+#define PCH_GBE_TXD_CTRL_ITAG 0x0004
+#define PCH_GBE_TXD_CTRL_ICRC 0x0002
+#define PCH_GBE_TXD_CTRL_APAD 0x0001
+#define PCH_GBE_TXD_WORDS_SHIFT 2
+#define PCH_GBE_TXD_GMAC_STAT_CMPLT 0x2000
+#define PCH_GBE_TXD_GMAC_STAT_ABT 0x1000
+#define PCH_GBE_TXD_GMAC_STAT_EXCOL 0x0800
+#define PCH_GBE_TXD_GMAC_STAT_SNGCOL 0x0400
+#define PCH_GBE_TXD_GMAC_STAT_MLTCOL 0x0200
+#define PCH_GBE_TXD_GMAC_STAT_CRSER 0x0100
+#define PCH_GBE_TXD_GMAC_STAT_TLNG 0x0080
+#define PCH_GBE_TXD_GMAC_STAT_TSHRT 0x0040
+#define PCH_GBE_TXD_GMAC_STAT_LTCOL 0x0020
+#define PCH_GBE_TXD_GMAC_STAT_TFUNDFLW 0x0010
+#define PCH_GBE_TXD_GMAC_STAT_RTYCNT_MASK 0x000F
+
+/* TX Mode */
+#define PCH_GBE_TM_NO_RTRY 0x80000000 /* No Retransmission */
+#define PCH_GBE_TM_LONG_PKT 0x40000000 /* Long Packt TX Enable */
+#define PCH_GBE_TM_ST_AND_FD 0x20000000 /* Stare and Forward */
+#define PCH_GBE_TM_SHORT_PKT 0x10000000 /* Short Packet TX Enable */
+#define PCH_GBE_TM_LTCOL_RETX 0x08000000 /* Retransmission at Late Collision */
+/* Frame Start Threshold */
+#define PCH_GBE_TM_TH_TX_STRT_4 0x00000000 /* 4 words */
+#define PCH_GBE_TM_TH_TX_STRT_8 0x00004000 /* 8 words */
+#define PCH_GBE_TM_TH_TX_STRT_16 0x00008000 /* 16 words */
+#define PCH_GBE_TM_TH_TX_STRT_32 0x0000C000 /* 32 words */
+/* Transmit Almost Empty Threshold */
+#define PCH_GBE_TM_TH_ALM_EMP_4 0x00000000 /* 4 words */
+#define PCH_GBE_TM_TH_ALM_EMP_8 0x00000800 /* 8 words */
+#define PCH_GBE_TM_TH_ALM_EMP_16 0x00001000 /* 16 words */
+#define PCH_GBE_TM_TH_ALM_EMP_32 0x00001800 /* 32 words */
+#define PCH_GBE_TM_TH_ALM_EMP_64 0x00002000 /* 64 words */
+#define PCH_GBE_TM_TH_ALM_EMP_128 0x00002800 /* 128 words */
+#define PCH_GBE_TM_TH_ALM_EMP_256 0x00003000 /* 256 words */
+#define PCH_GBE_TM_TH_ALM_EMP_512 0x00003800 /* 512 words */
+/* Transmit Almost Full Threshold */
+#define PCH_GBE_TM_TH_ALM_FULL_4 0x00000000 /* 4 words */
+#define PCH_GBE_TM_TH_ALM_FULL_8 0x00000200 /* 8 words */
+#define PCH_GBE_TM_TH_ALM_FULL_16 0x00000400 /* 16 words */
+#define PCH_GBE_TM_TH_ALM_FULL_32 0x00000600 /* 32 words */
+
+/* RX FIFO Status */
+#define PCH_GBE_RF_ALM_FULL 0x80000000 /* RX FIFO is almost full. */
+#define PCH_GBE_RF_ALM_EMP 0x40000000 /* RX FIFO is almost empty. */
+#define PCH_GBE_RF_RD_TRG 0x20000000 /* Become more than RH_RD_TRG. */
+#define PCH_GBE_RF_STRWD 0x1FFE0000 /* The word count of RX FIFO. */
+#define PCH_GBE_RF_RCVING 0x00010000 /* Stored in RX FIFO. */
+
+/* MAC Address Mask */
+#define PCH_GBE_BUSY 0x80000000
+
+/* MIIM */
+#define PCH_GBE_MIIM_OPER_WRITE 0x04000000
+#define PCH_GBE_MIIM_OPER_READ 0x00000000
+#define PCH_GBE_MIIM_OPER_READY 0x04000000
+#define PCH_GBE_MIIM_PHY_ADDR_SHIFT 21
+#define PCH_GBE_MIIM_REG_ADDR_SHIFT 16
+
+/* RGMII Status */
+#define PCH_GBE_LINK_UP 0x80000008
+#define PCH_GBE_RXC_SPEED_MSK 0x00000006
+#define PCH_GBE_RXC_SPEED_2_5M 0x00000000 /* 2.5MHz */
+#define PCH_GBE_RXC_SPEED_25M 0x00000002 /* 25MHz */
+#define PCH_GBE_RXC_SPEED_125M 0x00000004 /* 100MHz */
+#define PCH_GBE_DUPLEX_FULL 0x00000001
+
+/* RGMII Control */
+#define PCH_GBE_CRS_SEL 0x00000010
+#define PCH_GBE_RGMII_RATE_125M 0x00000000
+#define PCH_GBE_RGMII_RATE_25M 0x00000008
+#define PCH_GBE_RGMII_RATE_2_5M 0x0000000C
+#define PCH_GBE_RGMII_MODE_GMII 0x00000000
+#define PCH_GBE_RGMII_MODE_RGMII 0x00000002
+#define PCH_GBE_CHIP_TYPE_EXTERNAL 0x00000000
+#define PCH_GBE_CHIP_TYPE_INTERNAL 0x00000001
+
+/* DMA Control */
+#define PCH_GBE_RX_DMA_EN 0x00000002 /* Enables Receive DMA */
+#define PCH_GBE_TX_DMA_EN 0x00000001 /* Enables Transmission DMA */
+
+/* Wake On LAN Status */
+#define PCH_GBE_WLS_BR 0x00000008 /* Broadcas Address */
+#define PCH_GBE_WLS_MLT 0x00000004 /* Multicast Address */
+
+/* The Frame registered in Address Recognizer */
+#define PCH_GBE_WLS_IND 0x00000002
+#define PCH_GBE_WLS_MP 0x00000001 /* Magic packet Address */
+
+/* Wake On LAN Control */
+#define PCH_GBE_WLC_WOL_MODE 0x00010000
+#define PCH_GBE_WLC_IGN_TLONG 0x00000100
+#define PCH_GBE_WLC_IGN_TSHRT 0x00000080
+#define PCH_GBE_WLC_IGN_OCTER 0x00000040
+#define PCH_GBE_WLC_IGN_NBLER 0x00000020
+#define PCH_GBE_WLC_IGN_CRCER 0x00000010
+#define PCH_GBE_WLC_BR 0x00000008
+#define PCH_GBE_WLC_MLT 0x00000004
+#define PCH_GBE_WLC_IND 0x00000002
+#define PCH_GBE_WLC_MP 0x00000001
+
+/* Wake On LAN Address Mask */
+#define PCH_GBE_WLA_BUSY 0x80000000
+
+
+
+/* TX/RX descriptor defines */
+#define PCH_GBE_MAX_TXD 4096
+#define PCH_GBE_DEFAULT_TXD 256
+#define PCH_GBE_MIN_TXD 8
+#define PCH_GBE_MAX_RXD 4096
+#define PCH_GBE_DEFAULT_RXD 256
+#define PCH_GBE_MIN_RXD 8
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define PCH_GBE_TX_DESC_MULTIPLE 8
+#define PCH_GBE_RX_DESC_MULTIPLE 8
+
+/* Read/Write operation is done through MII Management IF */
+#define PCH_GBE_HAL_MIIM_READ ((u32)0x00000000)
+#define PCH_GBE_HAL_MIIM_WRITE ((u32)0x04000000)
+
+/* flow control values */
+#define PCH_GBE_FC_NONE 0
+#define PCH_GBE_FC_RX_PAUSE 1
+#define PCH_GBE_FC_TX_PAUSE 2
+#define PCH_GBE_FC_FULL 3
+#define PCH_GBE_FC_DEFAULT PCH_GBE_FC_FULL
+
+
+struct pch_gbe_hw;
+/**
+ * struct pch_gbe_functions - HAL APi function pointer
+ * @get_bus_info: for pch_gbe_hal_get_bus_info
+ * @init_hw: for pch_gbe_hal_init_hw
+ * @read_phy_reg: for pch_gbe_hal_read_phy_reg
+ * @write_phy_reg: for pch_gbe_hal_write_phy_reg
+ * @reset_phy: for pch_gbe_hal_phy_hw_reset
+ * @sw_reset_phy: for pch_gbe_hal_phy_sw_reset
+ * @power_up_phy: for pch_gbe_hal_power_up_phy
+ * @power_down_phy: for pch_gbe_hal_power_down_phy
+ * @read_mac_addr: for pch_gbe_hal_read_mac_addr
+ */
+struct pch_gbe_functions {
+ void (*get_bus_info) (struct pch_gbe_hw *);
+ s32 (*init_hw) (struct pch_gbe_hw *);
+ s32 (*read_phy_reg) (struct pch_gbe_hw *, u32, u16 *);
+ s32 (*write_phy_reg) (struct pch_gbe_hw *, u32, u16);
+ void (*reset_phy) (struct pch_gbe_hw *);
+ void (*sw_reset_phy) (struct pch_gbe_hw *);
+ void (*power_up_phy) (struct pch_gbe_hw *hw);
+ void (*power_down_phy) (struct pch_gbe_hw *hw);
+ s32 (*read_mac_addr) (struct pch_gbe_hw *);
+};
+
+/**
+ * struct pch_gbe_mac_info - MAC infomation
+ * @addr[6]: Store the MAC address
+ * @fc: Mode of flow control
+ * @fc_autoneg: Auto negotiation enable for flow control setting
+ * @tx_fc_enable: Enable flag of Transmit flow control
+ * @max_frame_size: Max transmit frame size
+ * @min_frame_size: Min transmit frame size
+ * @autoneg: Auto negotiation enable
+ * @link_speed: Link speed
+ * @link_duplex: Link duplex
+ */
+struct pch_gbe_mac_info {
+ u8 addr[6];
+ u8 fc;
+ u8 fc_autoneg;
+ u8 tx_fc_enable;
+ u32 max_frame_size;
+ u32 min_frame_size;
+ u8 autoneg;
+ u16 link_speed;
+ u16 link_duplex;
+};
+
+/**
+ * struct pch_gbe_phy_info - PHY infomation
+ * @addr: PHY address
+ * @id: PHY's identifier
+ * @revision: PHY's revision
+ * @reset_delay_us: HW reset delay time[us]
+ * @autoneg_advertised: Autoneg advertised
+ */
+struct pch_gbe_phy_info {
+ u32 addr;
+ u32 id;
+ u32 revision;
+ u32 reset_delay_us;
+ u16 autoneg_advertised;
+};
+
+/*!
+ * @ingroup Gigabit Ether driver Layer
+ * @struct pch_gbe_bus_info
+ * @brief Bus infomation
+ */
+struct pch_gbe_bus_info {
+ u8 type;
+ u8 speed;
+ u8 width;
+};
+
+/*!
+ * @ingroup Gigabit Ether driver Layer
+ * @struct pch_gbe_hw
+ * @brief Hardware infomation
+ */
+struct pch_gbe_hw {
+ void *back;
+
+ struct pch_gbe_regs __iomem *reg;
+ spinlock_t miim_lock;
+
+ const struct pch_gbe_functions *func;
+ struct pch_gbe_mac_info mac;
+ struct pch_gbe_phy_info phy;
+ struct pch_gbe_bus_info bus;
+};
+
+/**
+ * struct pch_gbe_rx_desc - Receive Descriptor
+ * @buffer_addr: RX Frame Buffer Address
+ * @tcp_ip_status: TCP/IP Accelerator Status
+ * @rx_words_eob: RX word count and Byte position
+ * @gbec_status: GMAC Status
+ * @dma_status: DMA Status
+ * @reserved1: Reserved
+ * @reserved2: Reserved
+ */
+struct pch_gbe_rx_desc {
+ u32 buffer_addr;
+ u32 tcp_ip_status;
+ u16 rx_words_eob;
+ u16 gbec_status;
+ u8 dma_status;
+ u8 reserved1;
+ u16 reserved2;
+};
+
+/**
+ * struct pch_gbe_tx_desc - Transmit Descriptor
+ * @buffer_addr: TX Frame Buffer Address
+ * @length: Data buffer length
+ * @reserved1: Reserved
+ * @tx_words_eob: TX word count and Byte position
+ * @tx_frame_ctrl: TX Frame Control
+ * @dma_status: DMA Status
+ * @reserved2: Reserved
+ * @gbec_status: GMAC Status
+ */
+struct pch_gbe_tx_desc {
+ u32 buffer_addr;
+ u16 length;
+ u16 reserved1;
+ u16 tx_words_eob;
+ u16 tx_frame_ctrl;
+ u8 dma_status;
+ u8 reserved2;
+ u16 gbec_status;
+};
+
+
+/**
+ * struct pch_gbe_buffer - Buffer infomation
+ * @skb: pointer to a socket buffer
+ * @dma: DMA address
+ * @time_stamp: time stamp
+ * @length: data size
+ */
+struct pch_gbe_buffer {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ unsigned long time_stamp;
+ u16 length;
+ bool mapped;
+};
+
+/**
+ * struct pch_gbe_tx_ring - tx ring infomation
+ * @tx_lock: spinlock structs
+ * @desc: pointer to the descriptor ring memory
+ * @dma: physical address of the descriptor ring
+ * @size: length of descriptor ring in bytes
+ * @count: number of descriptors in the ring
+ * @next_to_use: next descriptor to associate a buffer with
+ * @next_to_clean: next descriptor to check for DD status bit
+ * @buffer_info: array of buffer information structs
+ */
+struct pch_gbe_tx_ring {
+ spinlock_t tx_lock;
+ struct pch_gbe_tx_desc *desc;
+ dma_addr_t dma;
+ unsigned int size;
+ unsigned int count;
+ unsigned int next_to_use;
+ unsigned int next_to_clean;
+ struct pch_gbe_buffer *buffer_info;
+};
+
+/**
+ * struct pch_gbe_rx_ring - rx ring infomation
+ * @desc: pointer to the descriptor ring memory
+ * @dma: physical address of the descriptor ring
+ * @size: length of descriptor ring in bytes
+ * @count: number of descriptors in the ring
+ * @next_to_use: next descriptor to associate a buffer with
+ * @next_to_clean: next descriptor to check for DD status bit
+ * @buffer_info: array of buffer information structs
+ */
+struct pch_gbe_rx_ring {
+ struct pch_gbe_rx_desc *desc;
+ dma_addr_t dma;
+ unsigned int size;
+ unsigned int count;
+ unsigned int next_to_use;
+ unsigned int next_to_clean;
+ struct pch_gbe_buffer *buffer_info;
+};
+
+/**
+ * struct pch_gbe_hw_stats - Statistics counters collected by the MAC
+ * @rx_packets: total packets received
+ * @tx_packets: total packets transmitted
+ * @rx_bytes: total bytes received
+ * @tx_bytes: total bytes transmitted
+ * @rx_errors: bad packets received
+ * @tx_errors: packet transmit problems
+ * @rx_dropped: no space in Linux buffers
+ * @tx_dropped: no space available in Linux
+ * @multicast: multicast packets received
+ * @collisions: collisions
+ * @rx_crc_errors: received packet with crc error
+ * @rx_frame_errors: received frame alignment error
+ * @rx_alloc_buff_failed: allocate failure of a receive buffer
+ * @tx_length_errors: transmit length error
+ * @tx_aborted_errors: transmit aborted error
+ * @tx_carrier_errors: transmit carrier error
+ * @tx_timeout_count: Number of transmit timeout
+ * @tx_restart_count: Number of transmit restert
+ * @intr_rx_dsc_empty_count: Interrupt count of receive descriptor empty
+ * @intr_rx_frame_err_count: Interrupt count of receive frame error
+ * @intr_rx_fifo_err_count: Interrupt count of receive FIFO error
+ * @intr_rx_dma_err_count: Interrupt count of receive DMA error
+ * @intr_tx_fifo_err_count: Interrupt count of transmit FIFO error
+ * @intr_tx_dma_err_count: Interrupt count of transmit DMA error
+ * @intr_tcpip_err_count: Interrupt count of TCP/IP Accelerator
+ */
+struct pch_gbe_hw_stats {
+ u32 rx_packets;
+ u32 tx_packets;
+ u32 rx_bytes;
+ u32 tx_bytes;
+ u32 rx_errors;
+ u32 tx_errors;
+ u32 rx_dropped;
+ u32 tx_dropped;
+ u32 multicast;
+ u32 collisions;
+ u32 rx_crc_errors;
+ u32 rx_frame_errors;
+ u32 rx_alloc_buff_failed;
+ u32 tx_length_errors;
+ u32 tx_aborted_errors;
+ u32 tx_carrier_errors;
+ u32 tx_timeout_count;
+ u32 tx_restart_count;
+ u32 intr_rx_dsc_empty_count;
+ u32 intr_rx_frame_err_count;
+ u32 intr_rx_fifo_err_count;
+ u32 intr_rx_dma_err_count;
+ u32 intr_tx_fifo_err_count;
+ u32 intr_tx_dma_err_count;
+ u32 intr_tcpip_err_count;
+};
+
+/**
+ * struct pch_gbe_adapter - board specific private data structure
+ * @stats_lock: Spinlock structure for status
+ * @tx_queue_lock: Spinlock structure for transmit
+ * @ethtool_lock: Spinlock structure for ethtool
+ * @irq_sem: Semaphore for interrupt
+ * @netdev: Pointer of network device structure
+ * @pdev: Pointer of pci device structure
+ * @polling_netdev: Pointer of polling network device structure
+ * @napi: NAPI structure
+ * @hw: Pointer of hardware structure
+ * @stats: Hardware status
+ * @reset_task: Reset task
+ * @mii: MII information structure
+ * @watchdog_timer: Watchdog timer list
+ * @wake_up_evt: Wake up event
+ * @config_space: Configuration space
+ * @msg_enable: Driver message level
+ * @led_status: LED status
+ * @tx_ring: Pointer of Tx descriptor ring structure
+ * @rx_ring: Pointer of Rx descriptor ring structure
+ * @rx_buffer_len: Receive buffer length
+ * @tx_queue_len: Transmit queue length
+ * @rx_csum: Receive TCP/IP checksum enable/disable
+ * @tx_csum: Transmit TCP/IP checksum enable/disable
+ * @have_msi: PCI MSI mode flag
+ */
+
+struct pch_gbe_adapter {
+ spinlock_t stats_lock;
+ spinlock_t tx_queue_lock;
+ spinlock_t ethtool_lock;
+ atomic_t irq_sem;
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct net_device *polling_netdev;
+ struct napi_struct napi;
+ struct pch_gbe_hw hw;
+ struct pch_gbe_hw_stats stats;
+ struct work_struct reset_task;
+ struct mii_if_info mii;
+ struct timer_list watchdog_timer;
+ u32 wake_up_evt;
+ u32 *config_space;
+ unsigned long led_status;
+ struct pch_gbe_tx_ring *tx_ring;
+ struct pch_gbe_rx_ring *rx_ring;
+ unsigned long rx_buffer_len;
+ unsigned long tx_queue_len;
+ bool rx_csum;
+ bool tx_csum;
+ bool have_msi;
+};
+
+extern const char pch_driver_version[];
+
+/* pch_gbe_main.c */
+extern int pch_gbe_up(struct pch_gbe_adapter *adapter);
+extern void pch_gbe_down(struct pch_gbe_adapter *adapter);
+extern void pch_gbe_reinit_locked(struct pch_gbe_adapter *adapter);
+extern void pch_gbe_reset(struct pch_gbe_adapter *adapter);
+extern int pch_gbe_setup_tx_resources(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_tx_ring *txdr);
+extern int pch_gbe_setup_rx_resources(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_rx_ring *rxdr);
+extern void pch_gbe_free_tx_resources(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_tx_ring *tx_ring);
+extern void pch_gbe_free_rx_resources(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_rx_ring *rx_ring);
+extern void pch_gbe_update_stats(struct pch_gbe_adapter *adapter);
+
+/* pch_gbe_param.c */
+extern void pch_gbe_check_options(struct pch_gbe_adapter *adapter);
+
+/* pch_gbe_ethtool.c */
+extern void pch_gbe_set_ethtool_ops(struct net_device *netdev);
+
+/* pch_gbe_mac.c */
+extern s32 pch_gbe_mac_force_mac_fc(struct pch_gbe_hw *hw);
+extern s32 pch_gbe_mac_read_mac_addr(struct pch_gbe_hw *hw);
+extern u16 pch_gbe_mac_ctrl_miim(struct pch_gbe_hw *hw,
+ u32 addr, u32 dir, u32 reg, u16 data);
+#endif /* _PCH_GBE_H_ */
diff --git a/drivers/net/pch_gbe/pch_gbe_api.c b/drivers/net/pch_gbe/pch_gbe_api.c
new file mode 100644
index 000000000000..e48f084ad226
--- /dev/null
+++ b/drivers/net/pch_gbe/pch_gbe_api.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 1999 - 2010 Intel Corporation.
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This code was derived from the Intel e1000e Linux driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include "pch_gbe.h"
+#include "pch_gbe_phy.h"
+
+/* bus type values */
+#define pch_gbe_bus_type_unknown 0
+#define pch_gbe_bus_type_pci 1
+#define pch_gbe_bus_type_pcix 2
+#define pch_gbe_bus_type_pci_express 3
+#define pch_gbe_bus_type_reserved 4
+
+/* bus speed values */
+#define pch_gbe_bus_speed_unknown 0
+#define pch_gbe_bus_speed_33 1
+#define pch_gbe_bus_speed_66 2
+#define pch_gbe_bus_speed_100 3
+#define pch_gbe_bus_speed_120 4
+#define pch_gbe_bus_speed_133 5
+#define pch_gbe_bus_speed_2500 6
+#define pch_gbe_bus_speed_reserved 7
+
+/* bus width values */
+#define pch_gbe_bus_width_unknown 0
+#define pch_gbe_bus_width_pcie_x1 1
+#define pch_gbe_bus_width_pcie_x2 2
+#define pch_gbe_bus_width_pcie_x4 4
+#define pch_gbe_bus_width_32 5
+#define pch_gbe_bus_width_64 6
+#define pch_gbe_bus_width_reserved 7
+
+/**
+ * pch_gbe_plat_get_bus_info - Obtain bus information for adapter
+ * @hw: Pointer to the HW structure
+ */
+static void pch_gbe_plat_get_bus_info(struct pch_gbe_hw *hw)
+{
+ hw->bus.type = pch_gbe_bus_type_pci_express;
+ hw->bus.speed = pch_gbe_bus_speed_2500;
+ hw->bus.width = pch_gbe_bus_width_pcie_x1;
+}
+
+/**
+ * pch_gbe_plat_init_hw - Initialize hardware
+ * @hw: Pointer to the HW structure
+ * Returns
+ * 0: Successfully
+ * Negative value: Failed-EBUSY
+ */
+static s32 pch_gbe_plat_init_hw(struct pch_gbe_hw *hw)
+{
+ s32 ret_val;
+
+ ret_val = pch_gbe_phy_get_id(hw);
+ if (ret_val) {
+ pr_err("pch_gbe_phy_get_id error\n");
+ return ret_val;
+ }
+ pch_gbe_phy_init_setting(hw);
+ /* Setup Mac interface option RGMII */
+#ifdef PCH_GBE_MAC_IFOP_RGMII
+ pch_gbe_phy_set_rgmii(hw);
+#endif
+ return ret_val;
+}
+
+static const struct pch_gbe_functions pch_gbe_ops = {
+ .get_bus_info = pch_gbe_plat_get_bus_info,
+ .init_hw = pch_gbe_plat_init_hw,
+ .read_phy_reg = pch_gbe_phy_read_reg_miic,
+ .write_phy_reg = pch_gbe_phy_write_reg_miic,
+ .reset_phy = pch_gbe_phy_hw_reset,
+ .sw_reset_phy = pch_gbe_phy_sw_reset,
+ .power_up_phy = pch_gbe_phy_power_up,
+ .power_down_phy = pch_gbe_phy_power_down,
+ .read_mac_addr = pch_gbe_mac_read_mac_addr
+};
+
+/**
+ * pch_gbe_plat_init_function_pointers - Init func ptrs
+ * @hw: Pointer to the HW structure
+ */
+static void pch_gbe_plat_init_function_pointers(struct pch_gbe_hw *hw)
+{
+ /* Set PHY parameter */
+ hw->phy.reset_delay_us = PCH_GBE_PHY_RESET_DELAY_US;
+ /* Set function pointers */
+ hw->func = &pch_gbe_ops;
+}
+
+/**
+ * pch_gbe_hal_setup_init_funcs - Initializes function pointers
+ * @hw: Pointer to the HW structure
+ * Returns
+ * 0: Successfully
+ * ENOSYS: Function is not registered
+ */
+inline s32 pch_gbe_hal_setup_init_funcs(struct pch_gbe_hw *hw)
+{
+ if (!hw->reg) {
+ pr_err("ERROR: Registers not mapped\n");
+ return -ENOSYS;
+ }
+ pch_gbe_plat_init_function_pointers(hw);
+ return 0;
+}
+
+/**
+ * pch_gbe_hal_get_bus_info - Obtain bus information for adapter
+ * @hw: Pointer to the HW structure
+ */
+inline void pch_gbe_hal_get_bus_info(struct pch_gbe_hw *hw)
+{
+ if (!hw->func->get_bus_info)
+ pr_err("ERROR: configuration\n");
+ else
+ hw->func->get_bus_info(hw);
+}
+
+/**
+ * pch_gbe_hal_init_hw - Initialize hardware
+ * @hw: Pointer to the HW structure
+ * Returns
+ * 0: Successfully
+ * ENOSYS: Function is not registered
+ */
+inline s32 pch_gbe_hal_init_hw(struct pch_gbe_hw *hw)
+{
+ if (!hw->func->init_hw) {
+ pr_err("ERROR: configuration\n");
+ return -ENOSYS;
+ }
+ return hw->func->init_hw(hw);
+}
+
+/**
+ * pch_gbe_hal_read_phy_reg - Reads PHY register
+ * @hw: Pointer to the HW structure
+ * @offset: The register to read
+ * @data: The buffer to store the 16-bit read.
+ * Returns
+ * 0: Successfully
+ * Negative value: Failed
+ */
+inline s32 pch_gbe_hal_read_phy_reg(struct pch_gbe_hw *hw, u32 offset,
+ u16 *data)
+{
+ if (!hw->func->read_phy_reg)
+ return 0;
+ return hw->func->read_phy_reg(hw, offset, data);
+}
+
+/**
+ * pch_gbe_hal_write_phy_reg - Writes PHY register
+ * @hw: Pointer to the HW structure
+ * @offset: The register to read
+ * @data: The value to write.
+ * Returns
+ * 0: Successfully
+ * Negative value: Failed
+ */
+inline s32 pch_gbe_hal_write_phy_reg(struct pch_gbe_hw *hw, u32 offset,
+ u16 data)
+{
+ if (!hw->func->write_phy_reg)
+ return 0;
+ return hw->func->write_phy_reg(hw, offset, data);
+}
+
+/**
+ * pch_gbe_hal_phy_hw_reset - Hard PHY reset
+ * @hw: Pointer to the HW structure
+ */
+inline void pch_gbe_hal_phy_hw_reset(struct pch_gbe_hw *hw)
+{
+ if (!hw->func->reset_phy)
+ pr_err("ERROR: configuration\n");
+ else
+ hw->func->reset_phy(hw);
+}
+
+/**
+ * pch_gbe_hal_phy_sw_reset - Soft PHY reset
+ * @hw: Pointer to the HW structure
+ */
+inline void pch_gbe_hal_phy_sw_reset(struct pch_gbe_hw *hw)
+{
+ if (!hw->func->sw_reset_phy)
+ pr_err("ERROR: configuration\n");
+ else
+ hw->func->sw_reset_phy(hw);
+}
+
+/**
+ * pch_gbe_hal_read_mac_addr - Reads MAC address
+ * @hw: Pointer to the HW structure
+ * Returns
+ * 0: Successfully
+ * ENOSYS: Function is not registered
+ */
+inline s32 pch_gbe_hal_read_mac_addr(struct pch_gbe_hw *hw)
+{
+ if (!hw->func->read_mac_addr) {
+ pr_err("ERROR: configuration\n");
+ return -ENOSYS;
+ }
+ return hw->func->read_mac_addr(hw);
+}
+
+/**
+ * pch_gbe_hal_power_up_phy - Power up PHY
+ * @hw: Pointer to the HW structure
+ */
+inline void pch_gbe_hal_power_up_phy(struct pch_gbe_hw *hw)
+{
+ if (hw->func->power_up_phy)
+ hw->func->power_up_phy(hw);
+}
+
+/**
+ * pch_gbe_hal_power_down_phy - Power down PHY
+ * @hw: Pointer to the HW structure
+ */
+inline void pch_gbe_hal_power_down_phy(struct pch_gbe_hw *hw)
+{
+ if (hw->func->power_down_phy)
+ hw->func->power_down_phy(hw);
+}
diff --git a/drivers/net/pch_gbe/pch_gbe_api.h b/drivers/net/pch_gbe/pch_gbe_api.h
new file mode 100644
index 000000000000..94aaac5b057b
--- /dev/null
+++ b/drivers/net/pch_gbe/pch_gbe_api.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 1999 - 2010 Intel Corporation.
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This code was derived from the Intel e1000e Linux driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef _PCH_GBE_API_H_
+#define _PCH_GBE_API_H_
+
+#include "pch_gbe_phy.h"
+
+s32 pch_gbe_hal_setup_init_funcs(struct pch_gbe_hw *hw);
+void pch_gbe_hal_get_bus_info(struct pch_gbe_hw *hw);
+s32 pch_gbe_hal_init_hw(struct pch_gbe_hw *hw);
+s32 pch_gbe_hal_read_phy_reg(struct pch_gbe_hw *hw, u32 offset, u16 *data);
+s32 pch_gbe_hal_write_phy_reg(struct pch_gbe_hw *hw, u32 offset, u16 data);
+void pch_gbe_hal_phy_hw_reset(struct pch_gbe_hw *hw);
+void pch_gbe_hal_phy_sw_reset(struct pch_gbe_hw *hw);
+s32 pch_gbe_hal_read_mac_addr(struct pch_gbe_hw *hw);
+void pch_gbe_hal_power_up_phy(struct pch_gbe_hw *hw);
+void pch_gbe_hal_power_down_phy(struct pch_gbe_hw *hw);
+
+#endif
diff --git a/drivers/net/pch_gbe/pch_gbe_ethtool.c b/drivers/net/pch_gbe/pch_gbe_ethtool.c
new file mode 100644
index 000000000000..c8cc32c0edc9
--- /dev/null
+++ b/drivers/net/pch_gbe/pch_gbe_ethtool.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright (C) 1999 - 2010 Intel Corporation.
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This code was derived from the Intel e1000e Linux driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include "pch_gbe.h"
+#include "pch_gbe_api.h"
+
+/**
+ * pch_gbe_stats - Stats item infomation
+ */
+struct pch_gbe_stats {
+ char string[ETH_GSTRING_LEN];
+ size_t size;
+ size_t offset;
+};
+
+#define PCH_GBE_STAT(m) \
+{ \
+ .string = #m, \
+ .size = FIELD_SIZEOF(struct pch_gbe_hw_stats, m), \
+ .offset = offsetof(struct pch_gbe_hw_stats, m), \
+}
+
+/**
+ * pch_gbe_gstrings_stats - ethtool information status name list
+ */
+static const struct pch_gbe_stats pch_gbe_gstrings_stats[] = {
+ PCH_GBE_STAT(rx_packets),
+ PCH_GBE_STAT(tx_packets),
+ PCH_GBE_STAT(rx_bytes),
+ PCH_GBE_STAT(tx_bytes),
+ PCH_GBE_STAT(rx_errors),
+ PCH_GBE_STAT(tx_errors),
+ PCH_GBE_STAT(rx_dropped),
+ PCH_GBE_STAT(tx_dropped),
+ PCH_GBE_STAT(multicast),
+ PCH_GBE_STAT(collisions),
+ PCH_GBE_STAT(rx_crc_errors),
+ PCH_GBE_STAT(rx_frame_errors),
+ PCH_GBE_STAT(rx_alloc_buff_failed),
+ PCH_GBE_STAT(tx_length_errors),
+ PCH_GBE_STAT(tx_aborted_errors),
+ PCH_GBE_STAT(tx_carrier_errors),
+ PCH_GBE_STAT(tx_timeout_count),
+ PCH_GBE_STAT(tx_restart_count),
+ PCH_GBE_STAT(intr_rx_dsc_empty_count),
+ PCH_GBE_STAT(intr_rx_frame_err_count),
+ PCH_GBE_STAT(intr_rx_fifo_err_count),
+ PCH_GBE_STAT(intr_rx_dma_err_count),
+ PCH_GBE_STAT(intr_tx_fifo_err_count),
+ PCH_GBE_STAT(intr_tx_dma_err_count),
+ PCH_GBE_STAT(intr_tcpip_err_count)
+};
+
+#define PCH_GBE_QUEUE_STATS_LEN 0
+#define PCH_GBE_GLOBAL_STATS_LEN ARRAY_SIZE(pch_gbe_gstrings_stats)
+#define PCH_GBE_STATS_LEN (PCH_GBE_GLOBAL_STATS_LEN + PCH_GBE_QUEUE_STATS_LEN)
+
+#define PCH_GBE_MAC_REGS_LEN (sizeof(struct pch_gbe_regs) / 4)
+#define PCH_GBE_REGS_LEN (PCH_GBE_MAC_REGS_LEN + PCH_GBE_PHY_REGS_LEN)
+/**
+ * pch_gbe_get_settings - Get device-specific settings
+ * @netdev: Network interface device structure
+ * @ecmd: Ethtool command
+ * Returns
+ * 0: Successful.
+ * Negative value: Failed.
+ */
+static int pch_gbe_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ int ret;
+
+ ret = mii_ethtool_gset(&adapter->mii, ecmd);
+ ecmd->supported &= ~(SUPPORTED_TP | SUPPORTED_1000baseT_Half);
+ ecmd->advertising &= ~(ADVERTISED_TP | ADVERTISED_1000baseT_Half);
+
+ if (!netif_carrier_ok(adapter->netdev))
+ ecmd->speed = -1;
+ return ret;
+}
+
+/**
+ * pch_gbe_set_settings - Set device-specific settings
+ * @netdev: Network interface device structure
+ * @ecmd: Ethtool command
+ * Returns
+ * 0: Successful.
+ * Negative value: Failed.
+ */
+static int pch_gbe_set_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_hw *hw = &adapter->hw;
+ int ret;
+
+ pch_gbe_hal_write_phy_reg(hw, MII_BMCR, BMCR_RESET);
+
+ if (ecmd->speed == USHRT_MAX) {
+ ecmd->speed = SPEED_1000;
+ ecmd->duplex = DUPLEX_FULL;
+ }
+ ret = mii_ethtool_sset(&adapter->mii, ecmd);
+ if (ret) {
+ pr_err("Error: mii_ethtool_sset\n");
+ return ret;
+ }
+ hw->mac.link_speed = ecmd->speed;
+ hw->mac.link_duplex = ecmd->duplex;
+ hw->phy.autoneg_advertised = ecmd->advertising;
+ hw->mac.autoneg = ecmd->autoneg;
+ pch_gbe_hal_phy_sw_reset(hw);
+
+ /* reset the link */
+ if (netif_running(adapter->netdev)) {
+ pch_gbe_down(adapter);
+ ret = pch_gbe_up(adapter);
+ } else {
+ pch_gbe_reset(adapter);
+ }
+ return ret;
+}
+
+/**
+ * pch_gbe_get_regs_len - Report the size of device registers
+ * @netdev: Network interface device structure
+ * Returns: the size of device registers.
+ */
+static int pch_gbe_get_regs_len(struct net_device *netdev)
+{
+ return PCH_GBE_REGS_LEN * (int)sizeof(u32);
+}
+
+/**
+ * pch_gbe_get_drvinfo - Report driver information
+ * @netdev: Network interface device structure
+ * @drvinfo: Driver information structure
+ */
+static void pch_gbe_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+
+ strcpy(drvinfo->driver, KBUILD_MODNAME);
+ strcpy(drvinfo->version, pch_driver_version);
+ strcpy(drvinfo->fw_version, "N/A");
+ strcpy(drvinfo->bus_info, pci_name(adapter->pdev));
+ drvinfo->regdump_len = pch_gbe_get_regs_len(netdev);
+}
+
+/**
+ * pch_gbe_get_regs - Get device registers
+ * @netdev: Network interface device structure
+ * @regs: Ethtool register structure
+ * @p: Buffer pointer of read device register date
+ */
+static void pch_gbe_get_regs(struct net_device *netdev,
+ struct ethtool_regs *regs, void *p)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_hw *hw = &adapter->hw;
+ struct pci_dev *pdev = adapter->pdev;
+ u32 *regs_buff = p;
+ u16 i, tmp;
+
+ regs->version = 0x1000000 | (__u32)pdev->revision << 16 | pdev->device;
+ for (i = 0; i < PCH_GBE_MAC_REGS_LEN; i++)
+ *regs_buff++ = ioread32(&hw->reg->INT_ST + i);
+ /* PHY register */
+ for (i = 0; i < PCH_GBE_PHY_REGS_LEN; i++) {
+ pch_gbe_hal_read_phy_reg(&adapter->hw, i, &tmp);
+ *regs_buff++ = tmp;
+ }
+}
+
+/**
+ * pch_gbe_get_wol - Report whether Wake-on-Lan is enabled
+ * @netdev: Network interface device structure
+ * @wol: Wake-on-Lan information
+ */
+static void pch_gbe_get_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+
+ wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
+ wol->wolopts = 0;
+
+ if ((adapter->wake_up_evt & PCH_GBE_WLC_IND))
+ wol->wolopts |= WAKE_UCAST;
+ if ((adapter->wake_up_evt & PCH_GBE_WLC_MLT))
+ wol->wolopts |= WAKE_MCAST;
+ if ((adapter->wake_up_evt & PCH_GBE_WLC_BR))
+ wol->wolopts |= WAKE_BCAST;
+ if ((adapter->wake_up_evt & PCH_GBE_WLC_MP))
+ wol->wolopts |= WAKE_MAGIC;
+}
+
+/**
+ * pch_gbe_set_wol - Turn Wake-on-Lan on or off
+ * @netdev: Network interface device structure
+ * @wol: Pointer of wake-on-Lan information straucture
+ * Returns
+ * 0: Successful.
+ * Negative value: Failed.
+ */
+static int pch_gbe_set_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+
+ if ((wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)))
+ return -EOPNOTSUPP;
+ /* these settings will always override what we currently have */
+ adapter->wake_up_evt = 0;
+
+ if ((wol->wolopts & WAKE_UCAST))
+ adapter->wake_up_evt |= PCH_GBE_WLC_IND;
+ if ((wol->wolopts & WAKE_MCAST))
+ adapter->wake_up_evt |= PCH_GBE_WLC_MLT;
+ if ((wol->wolopts & WAKE_BCAST))
+ adapter->wake_up_evt |= PCH_GBE_WLC_BR;
+ if ((wol->wolopts & WAKE_MAGIC))
+ adapter->wake_up_evt |= PCH_GBE_WLC_MP;
+ return 0;
+}
+
+/**
+ * pch_gbe_nway_reset - Restart autonegotiation
+ * @netdev: Network interface device structure
+ * Returns
+ * 0: Successful.
+ * Negative value: Failed.
+ */
+static int pch_gbe_nway_reset(struct net_device *netdev)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+
+ return mii_nway_restart(&adapter->mii);
+}
+
+/**
+ * pch_gbe_get_ringparam - Report ring sizes
+ * @netdev: Network interface device structure
+ * @ring: Ring param structure
+ */
+static void pch_gbe_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_tx_ring *txdr = adapter->tx_ring;
+ struct pch_gbe_rx_ring *rxdr = adapter->rx_ring;
+
+ 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;
+}
+
+/**
+ * pch_gbe_set_ringparam - Set ring sizes
+ * @netdev: Network interface device structure
+ * @ring: Ring param structure
+ * Returns
+ * 0: Successful.
+ * Negative value: Failed.
+ */
+static int pch_gbe_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_tx_ring *txdr, *tx_old;
+ struct pch_gbe_rx_ring *rxdr, *rx_old;
+ int tx_ring_size, rx_ring_size;
+ int err = 0;
+
+ if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+ return -EINVAL;
+ tx_ring_size = (int)sizeof(struct pch_gbe_tx_ring);
+ rx_ring_size = (int)sizeof(struct pch_gbe_rx_ring);
+
+ if ((netif_running(adapter->netdev)))
+ pch_gbe_down(adapter);
+ tx_old = adapter->tx_ring;
+ rx_old = adapter->rx_ring;
+
+ txdr = kzalloc(tx_ring_size, GFP_KERNEL);
+ if (!txdr) {
+ err = -ENOMEM;
+ goto err_alloc_tx;
+ }
+ rxdr = kzalloc(rx_ring_size, GFP_KERNEL);
+ if (!rxdr) {
+ err = -ENOMEM;
+ goto err_alloc_rx;
+ }
+ adapter->tx_ring = txdr;
+ adapter->rx_ring = rxdr;
+
+ rxdr->count =
+ clamp_val(ring->rx_pending, PCH_GBE_MIN_RXD, PCH_GBE_MAX_RXD);
+ rxdr->count = roundup(rxdr->count, PCH_GBE_RX_DESC_MULTIPLE);
+
+ txdr->count =
+ clamp_val(ring->tx_pending, PCH_GBE_MIN_RXD, PCH_GBE_MAX_RXD);
+ txdr->count = roundup(txdr->count, PCH_GBE_TX_DESC_MULTIPLE);
+
+ if ((netif_running(adapter->netdev))) {
+ /* Try to get new resources before deleting old */
+ err = pch_gbe_setup_rx_resources(adapter, adapter->rx_ring);
+ if (err)
+ goto err_setup_rx;
+ err = pch_gbe_setup_tx_resources(adapter, adapter->tx_ring);
+ if (err)
+ goto err_setup_tx;
+ /* save the new, restore the old in order to free it,
+ * then restore the new back again */
+#ifdef RINGFREE
+ adapter->rx_ring = rx_old;
+ adapter->tx_ring = tx_old;
+ pch_gbe_free_rx_resources(adapter, adapter->rx_ring);
+ pch_gbe_free_tx_resources(adapter, adapter->tx_ring);
+ kfree(tx_old);
+ kfree(rx_old);
+ adapter->rx_ring = rxdr;
+ adapter->tx_ring = txdr;
+#else
+ pch_gbe_free_rx_resources(adapter, rx_old);
+ pch_gbe_free_tx_resources(adapter, tx_old);
+ kfree(tx_old);
+ kfree(rx_old);
+ adapter->rx_ring = rxdr;
+ adapter->tx_ring = txdr;
+#endif
+ err = pch_gbe_up(adapter);
+ }
+ return err;
+
+err_setup_tx:
+ pch_gbe_free_rx_resources(adapter, adapter->rx_ring);
+err_setup_rx:
+ adapter->rx_ring = rx_old;
+ adapter->tx_ring = tx_old;
+ kfree(rxdr);
+err_alloc_rx:
+ kfree(txdr);
+err_alloc_tx:
+ if (netif_running(adapter->netdev))
+ pch_gbe_up(adapter);
+ return err;
+}
+
+/**
+ * pch_gbe_get_pauseparam - Report pause parameters
+ * @netdev: Network interface device structure
+ * @pause: Pause parameters structure
+ */
+static void pch_gbe_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_hw *hw = &adapter->hw;
+
+ pause->autoneg =
+ ((hw->mac.fc_autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE);
+
+ if (hw->mac.fc == PCH_GBE_FC_RX_PAUSE) {
+ pause->rx_pause = 1;
+ } else if (hw->mac.fc == PCH_GBE_FC_TX_PAUSE) {
+ pause->tx_pause = 1;
+ } else if (hw->mac.fc == PCH_GBE_FC_FULL) {
+ pause->rx_pause = 1;
+ pause->tx_pause = 1;
+ }
+}
+
+/**
+ * pch_gbe_set_pauseparam - Set pause paramters
+ * @netdev: Network interface device structure
+ * @pause: Pause parameters structure
+ * Returns
+ * 0: Successful.
+ * Negative value: Failed.
+ */
+static int pch_gbe_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_hw *hw = &adapter->hw;
+ int ret = 0;
+
+ hw->mac.fc_autoneg = pause->autoneg;
+ if ((pause->rx_pause) && (pause->tx_pause))
+ hw->mac.fc = PCH_GBE_FC_FULL;
+ else if ((pause->rx_pause) && (!pause->tx_pause))
+ hw->mac.fc = PCH_GBE_FC_RX_PAUSE;
+ else if ((!pause->rx_pause) && (pause->tx_pause))
+ hw->mac.fc = PCH_GBE_FC_TX_PAUSE;
+ else if ((!pause->rx_pause) && (!pause->tx_pause))
+ hw->mac.fc = PCH_GBE_FC_NONE;
+
+ if (hw->mac.fc_autoneg == AUTONEG_ENABLE) {
+ if ((netif_running(adapter->netdev))) {
+ pch_gbe_down(adapter);
+ ret = pch_gbe_up(adapter);
+ } else {
+ pch_gbe_reset(adapter);
+ }
+ } else {
+ ret = pch_gbe_mac_force_mac_fc(hw);
+ }
+ return ret;
+}
+
+/**
+ * pch_gbe_get_rx_csum - Report whether receive checksums are turned on or off
+ * @netdev: Network interface device structure
+ * Returns
+ * true(1): Checksum On
+ * false(0): Checksum Off
+ */
+static u32 pch_gbe_get_rx_csum(struct net_device *netdev)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+
+ return adapter->rx_csum;
+}
+
+/**
+ * pch_gbe_set_rx_csum - Turn receive checksum on or off
+ * @netdev: Network interface device structure
+ * @data: Checksum On[true] or Off[false]
+ * Returns
+ * 0: Successful.
+ * Negative value: Failed.
+ */
+static int pch_gbe_set_rx_csum(struct net_device *netdev, u32 data)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+
+ adapter->rx_csum = data;
+ if ((netif_running(netdev)))
+ pch_gbe_reinit_locked(adapter);
+ else
+ pch_gbe_reset(adapter);
+
+ return 0;
+}
+
+/**
+ * pch_gbe_get_tx_csum - Report whether transmit checksums are turned on or off
+ * @netdev: Network interface device structure
+ * Returns
+ * true(1): Checksum On
+ * false(0): Checksum Off
+ */
+static u32 pch_gbe_get_tx_csum(struct net_device *netdev)
+{
+ return (netdev->features & NETIF_F_HW_CSUM) != 0;
+}
+
+/**
+ * pch_gbe_set_tx_csum - Turn transmit checksums on or off
+ * @netdev: Network interface device structure
+ * @data: Checksum on[true] or off[false]
+ * Returns
+ * 0: Successful.
+ * Negative value: Failed.
+ */
+static int pch_gbe_set_tx_csum(struct net_device *netdev, u32 data)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+
+ adapter->tx_csum = data;
+ if (data)
+ netdev->features |= NETIF_F_HW_CSUM;
+ else
+ netdev->features &= ~NETIF_F_HW_CSUM;
+ return 0;
+}
+
+/**
+ * pch_gbe_get_strings - Return a set of strings that describe the requested
+ * objects
+ * @netdev: Network interface device structure
+ * @stringset: Select the stringset. [ETH_SS_TEST] [ETH_SS_STATS]
+ * @data: Pointer of read string data.
+ */
+static void pch_gbe_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *data)
+{
+ u8 *p = data;
+ int i;
+
+ switch (stringset) {
+ case (u32) ETH_SS_STATS:
+ for (i = 0; i < PCH_GBE_GLOBAL_STATS_LEN; i++) {
+ memcpy(p, pch_gbe_gstrings_stats[i].string,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ break;
+ }
+}
+
+/**
+ * pch_gbe_get_ethtool_stats - Return statistics about the device
+ * @netdev: Network interface device structure
+ * @stats: Ethtool statue structure
+ * @data: Pointer of read status area
+ */
+static void pch_gbe_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ int i;
+ const struct pch_gbe_stats *gstats = pch_gbe_gstrings_stats;
+ char *hw_stats = (char *)&adapter->stats;
+
+ pch_gbe_update_stats(adapter);
+ for (i = 0; i < PCH_GBE_GLOBAL_STATS_LEN; i++) {
+ char *p = hw_stats + gstats->offset;
+ data[i] = gstats->size == sizeof(u64) ? *(u64 *)p:(*(u32 *)p);
+ gstats++;
+ }
+}
+
+static int pch_gbe_get_sset_count(struct net_device *netdev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return PCH_GBE_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static const struct ethtool_ops pch_gbe_ethtool_ops = {
+ .get_settings = pch_gbe_get_settings,
+ .set_settings = pch_gbe_set_settings,
+ .get_drvinfo = pch_gbe_get_drvinfo,
+ .get_regs_len = pch_gbe_get_regs_len,
+ .get_regs = pch_gbe_get_regs,
+ .get_wol = pch_gbe_get_wol,
+ .set_wol = pch_gbe_set_wol,
+ .nway_reset = pch_gbe_nway_reset,
+ .get_link = ethtool_op_get_link,
+ .get_ringparam = pch_gbe_get_ringparam,
+ .set_ringparam = pch_gbe_set_ringparam,
+ .get_pauseparam = pch_gbe_get_pauseparam,
+ .set_pauseparam = pch_gbe_set_pauseparam,
+ .get_rx_csum = pch_gbe_get_rx_csum,
+ .set_rx_csum = pch_gbe_set_rx_csum,
+ .get_tx_csum = pch_gbe_get_tx_csum,
+ .set_tx_csum = pch_gbe_set_tx_csum,
+ .get_strings = pch_gbe_get_strings,
+ .get_ethtool_stats = pch_gbe_get_ethtool_stats,
+ .get_sset_count = pch_gbe_get_sset_count,
+};
+
+void pch_gbe_set_ethtool_ops(struct net_device *netdev)
+{
+ SET_ETHTOOL_OPS(netdev, &pch_gbe_ethtool_ops);
+}
diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c
new file mode 100644
index 000000000000..472056b47440
--- /dev/null
+++ b/drivers/net/pch_gbe/pch_gbe_main.c
@@ -0,0 +1,2477 @@
+/*
+ * Copyright (C) 1999 - 2010 Intel Corporation.
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This code was derived from the Intel e1000e Linux driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "pch_gbe.h"
+#include "pch_gbe_api.h"
+
+#define DRV_VERSION "1.00"
+const char pch_driver_version[] = DRV_VERSION;
+
+#define PCI_DEVICE_ID_INTEL_IOH1_GBE 0x8802 /* Pci device ID */
+#define PCH_GBE_MAR_ENTRIES 16
+#define PCH_GBE_SHORT_PKT 64
+#define DSC_INIT16 0xC000
+#define PCH_GBE_DMA_ALIGN 0
+#define PCH_GBE_WATCHDOG_PERIOD (1 * HZ) /* watchdog time */
+#define PCH_GBE_COPYBREAK_DEFAULT 256
+#define PCH_GBE_PCI_BAR 1
+
+#define PCH_GBE_TX_WEIGHT 64
+#define PCH_GBE_RX_WEIGHT 64
+#define PCH_GBE_RX_BUFFER_WRITE 16
+
+/* Initialize the wake-on-LAN settings */
+#define PCH_GBE_WL_INIT_SETTING (PCH_GBE_WLC_MP)
+
+#define PCH_GBE_MAC_RGMII_CTRL_SETTING ( \
+ PCH_GBE_CHIP_TYPE_INTERNAL | \
+ PCH_GBE_RGMII_MODE_RGMII | \
+ PCH_GBE_CRS_SEL \
+ )
+
+/* Ethertype field values */
+#define PCH_GBE_MAX_JUMBO_FRAME_SIZE 10318
+#define PCH_GBE_FRAME_SIZE_2048 2048
+#define PCH_GBE_FRAME_SIZE_4096 4096
+#define PCH_GBE_FRAME_SIZE_8192 8192
+
+#define PCH_GBE_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i]))
+#define PCH_GBE_RX_DESC(R, i) PCH_GBE_GET_DESC(R, i, pch_gbe_rx_desc)
+#define PCH_GBE_TX_DESC(R, i) PCH_GBE_GET_DESC(R, i, pch_gbe_tx_desc)
+#define PCH_GBE_DESC_UNUSED(R) \
+ ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+ (R)->next_to_clean - (R)->next_to_use - 1)
+
+/* Pause packet value */
+#define PCH_GBE_PAUSE_PKT1_VALUE 0x00C28001
+#define PCH_GBE_PAUSE_PKT2_VALUE 0x00000100
+#define PCH_GBE_PAUSE_PKT4_VALUE 0x01000888
+#define PCH_GBE_PAUSE_PKT5_VALUE 0x0000FFFF
+
+#define PCH_GBE_ETH_ALEN 6
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register. Each bit is documented below:
+ * o RXT0 = Receiver Timer Interrupt (ring 0)
+ * o TXDW = Transmit Descriptor Written Back
+ * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ * o RXSEQ = Receive Sequence Error
+ * o LSC = Link Status Change
+ */
+#define PCH_GBE_INT_ENABLE_MASK ( \
+ PCH_GBE_INT_RX_DMA_CMPLT | \
+ PCH_GBE_INT_RX_DSC_EMP | \
+ PCH_GBE_INT_WOL_DET | \
+ PCH_GBE_INT_TX_CMPLT \
+ )
+
+
+static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT;
+
+static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg);
+static void pch_gbe_mdio_write(struct net_device *netdev, int addr, int reg,
+ int data);
+/**
+ * pch_gbe_mac_read_mac_addr - Read MAC address
+ * @hw: Pointer to the HW structure
+ * Returns
+ * 0: Successful.
+ */
+s32 pch_gbe_mac_read_mac_addr(struct pch_gbe_hw *hw)
+{
+ u32 adr1a, adr1b;
+
+ adr1a = ioread32(&hw->reg->mac_adr[0].high);
+ adr1b = ioread32(&hw->reg->mac_adr[0].low);
+
+ hw->mac.addr[0] = (u8)(adr1a & 0xFF);
+ hw->mac.addr[1] = (u8)((adr1a >> 8) & 0xFF);
+ hw->mac.addr[2] = (u8)((adr1a >> 16) & 0xFF);
+ hw->mac.addr[3] = (u8)((adr1a >> 24) & 0xFF);
+ hw->mac.addr[4] = (u8)(adr1b & 0xFF);
+ hw->mac.addr[5] = (u8)((adr1b >> 8) & 0xFF);
+
+ pr_debug("hw->mac.addr : %pM\n", hw->mac.addr);
+ return 0;
+}
+
+/**
+ * pch_gbe_wait_clr_bit - Wait to clear a bit
+ * @reg: Pointer of register
+ * @busy: Busy bit
+ */
+static void pch_gbe_wait_clr_bit(void *reg, u32 bit)
+{
+ u32 tmp;
+ /* wait busy */
+ tmp = 1000;
+ while ((ioread32(reg) & bit) && --tmp)
+ cpu_relax();
+ if (!tmp)
+ pr_err("Error: busy bit is not cleared\n");
+}
+/**
+ * pch_gbe_mac_mar_set - Set MAC address register
+ * @hw: Pointer to the HW structure
+ * @addr: Pointer to the MAC address
+ * @index: MAC address array register
+ */
+static void pch_gbe_mac_mar_set(struct pch_gbe_hw *hw, u8 * addr, u32 index)
+{
+ u32 mar_low, mar_high, adrmask;
+
+ pr_debug("index : 0x%x\n", index);
+
+ /*
+ * HW expects these in little endian so we reverse the byte order
+ * from network order (big endian) to little endian
+ */
+ mar_high = ((u32) addr[0] | ((u32) addr[1] << 8) |
+ ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
+ mar_low = ((u32) addr[4] | ((u32) addr[5] << 8));
+ /* Stop the MAC Address of index. */
+ adrmask = ioread32(&hw->reg->ADDR_MASK);
+ iowrite32((adrmask | (0x0001 << index)), &hw->reg->ADDR_MASK);
+ /* wait busy */
+ pch_gbe_wait_clr_bit(&hw->reg->ADDR_MASK, PCH_GBE_BUSY);
+ /* Set the MAC address to the MAC address 1A/1B register */
+ iowrite32(mar_high, &hw->reg->mac_adr[index].high);
+ iowrite32(mar_low, &hw->reg->mac_adr[index].low);
+ /* Start the MAC address of index */
+ iowrite32((adrmask & ~(0x0001 << index)), &hw->reg->ADDR_MASK);
+ /* wait busy */
+ pch_gbe_wait_clr_bit(&hw->reg->ADDR_MASK, PCH_GBE_BUSY);
+}
+
+/**
+ * pch_gbe_mac_reset_hw - Reset hardware
+ * @hw: Pointer to the HW structure
+ */
+static void pch_gbe_mac_reset_hw(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_ALL_RST, &hw->reg->RESET);
+#ifdef PCH_GBE_MAC_IFOP_RGMII
+ iowrite32(PCH_GBE_MODE_GMII_ETHER, &hw->reg->MODE);
+#endif
+ pch_gbe_wait_clr_bit(&hw->reg->RESET, PCH_GBE_ALL_RST);
+ /* Setup the receive 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
+ * @mar_count: Receive address registers
+ */
+static void pch_gbe_mac_init_rx_addrs(struct pch_gbe_hw *hw, u16 mar_count)
+{
+ u32 i;
+
+ /* Setup the receive address */
+ pch_gbe_mac_mar_set(hw, hw->mac.addr, 0);
+
+ /* Zero out the other receive addresses */
+ for (i = 1; i < mar_count; i++) {
+ iowrite32(0, &hw->reg->mac_adr[i].high);
+ iowrite32(0, &hw->reg->mac_adr[i].low);
+ }
+ iowrite32(0xFFFE, &hw->reg->ADDR_MASK);
+ /* wait busy */
+ pch_gbe_wait_clr_bit(&hw->reg->ADDR_MASK, PCH_GBE_BUSY);
+}
+
+
+/**
+ * pch_gbe_mac_mc_addr_list_update - Update Multicast addresses
+ * @hw: Pointer to the HW structure
+ * @mc_addr_list: Array of multicast addresses to program
+ * @mc_addr_count: Number of multicast addresses to program
+ * @mar_used_count: The first MAC Address register free to program
+ * @mar_total_num: Total number of supported MAC Address Registers
+ */
+static void pch_gbe_mac_mc_addr_list_update(struct pch_gbe_hw *hw,
+ u8 *mc_addr_list, u32 mc_addr_count,
+ u32 mar_used_count, u32 mar_total_num)
+{
+ u32 i, adrmask;
+
+ /* Load the first set of multicast addresses into the exact
+ * filters (RAR). If there are not enough to fill the RAR
+ * array, clear the filters.
+ */
+ for (i = mar_used_count; i < mar_total_num; i++) {
+ if (mc_addr_count) {
+ pch_gbe_mac_mar_set(hw, mc_addr_list, i);
+ mc_addr_count--;
+ mc_addr_list += PCH_GBE_ETH_ALEN;
+ } else {
+ /* Clear MAC address mask */
+ adrmask = ioread32(&hw->reg->ADDR_MASK);
+ iowrite32((adrmask | (0x0001 << i)),
+ &hw->reg->ADDR_MASK);
+ /* wait busy */
+ pch_gbe_wait_clr_bit(&hw->reg->ADDR_MASK, PCH_GBE_BUSY);
+ /* Clear MAC address */
+ iowrite32(0, &hw->reg->mac_adr[i].high);
+ iowrite32(0, &hw->reg->mac_adr[i].low);
+ }
+ }
+}
+
+/**
+ * pch_gbe_mac_force_mac_fc - Force the MAC's flow control settings
+ * @hw: Pointer to the HW structure
+ * Returns
+ * 0: Successful.
+ * Negative value: Failed.
+ */
+s32 pch_gbe_mac_force_mac_fc(struct pch_gbe_hw *hw)
+{
+ struct pch_gbe_mac_info *mac = &hw->mac;
+ u32 rx_fctrl;
+
+ pr_debug("mac->fc = %u\n", mac->fc);
+
+ rx_fctrl = ioread32(&hw->reg->RX_FCTRL);
+
+ switch (mac->fc) {
+ case PCH_GBE_FC_NONE:
+ rx_fctrl &= ~PCH_GBE_FL_CTRL_EN;
+ mac->tx_fc_enable = false;
+ break;
+ case PCH_GBE_FC_RX_PAUSE:
+ rx_fctrl |= PCH_GBE_FL_CTRL_EN;
+ mac->tx_fc_enable = false;
+ break;
+ case PCH_GBE_FC_TX_PAUSE:
+ rx_fctrl &= ~PCH_GBE_FL_CTRL_EN;
+ mac->tx_fc_enable = true;
+ break;
+ case PCH_GBE_FC_FULL:
+ rx_fctrl |= PCH_GBE_FL_CTRL_EN;
+ mac->tx_fc_enable = true;
+ break;
+ default:
+ pr_err("Flow control param set incorrectly\n");
+ return -EINVAL;
+ }
+ if (mac->link_duplex == DUPLEX_HALF)
+ rx_fctrl &= ~PCH_GBE_FL_CTRL_EN;
+ iowrite32(rx_fctrl, &hw->reg->RX_FCTRL);
+ pr_debug("RX_FCTRL reg : 0x%08x mac->tx_fc_enable : %d\n",
+ ioread32(&hw->reg->RX_FCTRL), mac->tx_fc_enable);
+ return 0;
+}
+
+/**
+ * pch_gbe_mac_set_wol_event - Set wake-on-lan event
+ * @hw: Pointer to the HW structure
+ * @wu_evt: Wake up event
+ */
+static void pch_gbe_mac_set_wol_event(struct pch_gbe_hw *hw, u32 wu_evt)
+{
+ u32 addr_mask;
+
+ pr_debug("wu_evt : 0x%08x ADDR_MASK reg : 0x%08x\n",
+ wu_evt, ioread32(&hw->reg->ADDR_MASK));
+
+ if (wu_evt) {
+ /* Set Wake-On-Lan address mask */
+ addr_mask = ioread32(&hw->reg->ADDR_MASK);
+ iowrite32(addr_mask, &hw->reg->WOL_ADDR_MASK);
+ /* wait busy */
+ pch_gbe_wait_clr_bit(&hw->reg->WOL_ADDR_MASK, PCH_GBE_WLA_BUSY);
+ iowrite32(0, &hw->reg->WOL_ST);
+ iowrite32((wu_evt | PCH_GBE_WLC_WOL_MODE), &hw->reg->WOL_CTRL);
+ iowrite32(0x02, &hw->reg->TCPIP_ACC);
+ iowrite32(PCH_GBE_INT_ENABLE_MASK, &hw->reg->INT_EN);
+ } else {
+ iowrite32(0, &hw->reg->WOL_CTRL);
+ iowrite32(0, &hw->reg->WOL_ST);
+ }
+ return;
+}
+
+/**
+ * pch_gbe_mac_ctrl_miim - Control MIIM interface
+ * @hw: Pointer to the HW structure
+ * @addr: Address of PHY
+ * @dir: Operetion. (Write or Read)
+ * @reg: Access register of PHY
+ * @data: Write data.
+ *
+ * Returns: Read date.
+ */
+u16 pch_gbe_mac_ctrl_miim(struct pch_gbe_hw *hw, u32 addr, u32 dir, u32 reg,
+ u16 data)
+{
+ u32 data_out = 0;
+ unsigned int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hw->miim_lock, flags);
+
+ for (i = 100; i; --i) {
+ if ((ioread32(&hw->reg->MIIM) & PCH_GBE_MIIM_OPER_READY))
+ break;
+ udelay(20);
+ }
+ if (i == 0) {
+ pr_err("pch-gbe.miim won't go Ready\n");
+ spin_unlock_irqrestore(&hw->miim_lock, flags);
+ return 0; /* No way to indicate timeout error */
+ }
+ iowrite32(((reg << PCH_GBE_MIIM_REG_ADDR_SHIFT) |
+ (addr << PCH_GBE_MIIM_PHY_ADDR_SHIFT) |
+ dir | data), &hw->reg->MIIM);
+ for (i = 0; i < 100; i++) {
+ udelay(20);
+ data_out = ioread32(&hw->reg->MIIM);
+ if ((data_out & PCH_GBE_MIIM_OPER_READY))
+ break;
+ }
+ spin_unlock_irqrestore(&hw->miim_lock, flags);
+
+ pr_debug("PHY %s: reg=%d, data=0x%04X\n",
+ dir == PCH_GBE_MIIM_OPER_READ ? "READ" : "WRITE", reg,
+ dir == PCH_GBE_MIIM_OPER_READ ? data_out : data);
+ return (u16) data_out;
+}
+
+/**
+ * pch_gbe_mac_set_pause_packet - Set pause packet
+ * @hw: Pointer to the HW structure
+ */
+static void pch_gbe_mac_set_pause_packet(struct pch_gbe_hw *hw)
+{
+ unsigned long tmp2, tmp3;
+
+ /* Set Pause packet */
+ tmp2 = hw->mac.addr[1];
+ tmp2 = (tmp2 << 8) | hw->mac.addr[0];
+ tmp2 = PCH_GBE_PAUSE_PKT2_VALUE | (tmp2 << 16);
+
+ tmp3 = hw->mac.addr[5];
+ tmp3 = (tmp3 << 8) | hw->mac.addr[4];
+ tmp3 = (tmp3 << 8) | hw->mac.addr[3];
+ tmp3 = (tmp3 << 8) | hw->mac.addr[2];
+
+ iowrite32(PCH_GBE_PAUSE_PKT1_VALUE, &hw->reg->PAUSE_PKT1);
+ iowrite32(tmp2, &hw->reg->PAUSE_PKT2);
+ iowrite32(tmp3, &hw->reg->PAUSE_PKT3);
+ iowrite32(PCH_GBE_PAUSE_PKT4_VALUE, &hw->reg->PAUSE_PKT4);
+ iowrite32(PCH_GBE_PAUSE_PKT5_VALUE, &hw->reg->PAUSE_PKT5);
+
+ /* Transmit Pause Packet */
+ iowrite32(PCH_GBE_PS_PKT_RQ, &hw->reg->PAUSE_REQ);
+
+ pr_debug("PAUSE_PKT1-5 reg : 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ ioread32(&hw->reg->PAUSE_PKT1), ioread32(&hw->reg->PAUSE_PKT2),
+ ioread32(&hw->reg->PAUSE_PKT3), ioread32(&hw->reg->PAUSE_PKT4),
+ ioread32(&hw->reg->PAUSE_PKT5));
+
+ return;
+}
+
+
+/**
+ * pch_gbe_alloc_queues - Allocate memory for all rings
+ * @adapter: Board private structure to initialize
+ * Returns
+ * 0: Successfully
+ * Negative value: Failed
+ */
+static int pch_gbe_alloc_queues(struct pch_gbe_adapter *adapter)
+{
+ int size;
+
+ size = (int)sizeof(struct pch_gbe_tx_ring);
+ adapter->tx_ring = kzalloc(size, GFP_KERNEL);
+ if (!adapter->tx_ring)
+ return -ENOMEM;
+ size = (int)sizeof(struct pch_gbe_rx_ring);
+ adapter->rx_ring = kzalloc(size, GFP_KERNEL);
+ if (!adapter->rx_ring) {
+ kfree(adapter->tx_ring);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/**
+ * pch_gbe_init_stats - Initialize status
+ * @adapter: Board private structure to initialize
+ */
+static void pch_gbe_init_stats(struct pch_gbe_adapter *adapter)
+{
+ memset(&adapter->stats, 0, sizeof(adapter->stats));
+ return;
+}
+
+/**
+ * pch_gbe_init_phy - Initialize PHY
+ * @adapter: Board private structure to initialize
+ * Returns
+ * 0: Successfully
+ * Negative value: Failed
+ */
+static int pch_gbe_init_phy(struct pch_gbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ u32 addr;
+ u16 bmcr, stat;
+
+ /* Discover phy addr by searching addrs in order {1,0,2,..., 31} */
+ for (addr = 0; addr < PCH_GBE_PHY_REGS_LEN; addr++) {
+ adapter->mii.phy_id = (addr == 0) ? 1 : (addr == 1) ? 0 : addr;
+ bmcr = pch_gbe_mdio_read(netdev, adapter->mii.phy_id, MII_BMCR);
+ stat = pch_gbe_mdio_read(netdev, adapter->mii.phy_id, MII_BMSR);
+ stat = pch_gbe_mdio_read(netdev, adapter->mii.phy_id, MII_BMSR);
+ if (!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0))))
+ break;
+ }
+ adapter->hw.phy.addr = adapter->mii.phy_id;
+ pr_debug("phy_addr = %d\n", adapter->mii.phy_id);
+ if (addr == 32)
+ return -EAGAIN;
+ /* Selected the phy and isolate the rest */
+ for (addr = 0; addr < PCH_GBE_PHY_REGS_LEN; addr++) {
+ if (addr != adapter->mii.phy_id) {
+ pch_gbe_mdio_write(netdev, addr, MII_BMCR,
+ BMCR_ISOLATE);
+ } else {
+ bmcr = pch_gbe_mdio_read(netdev, addr, MII_BMCR);
+ pch_gbe_mdio_write(netdev, addr, MII_BMCR,
+ bmcr & ~BMCR_ISOLATE);
+ }
+ }
+
+ /* MII setup */
+ adapter->mii.phy_id_mask = 0x1F;
+ adapter->mii.reg_num_mask = 0x1F;
+ adapter->mii.dev = adapter->netdev;
+ adapter->mii.mdio_read = pch_gbe_mdio_read;
+ adapter->mii.mdio_write = pch_gbe_mdio_write;
+ adapter->mii.supports_gmii = mii_check_gmii_support(&adapter->mii);
+ return 0;
+}
+
+/**
+ * pch_gbe_mdio_read - The read function for mii
+ * @netdev: Network interface device structure
+ * @addr: Phy ID
+ * @reg: Access location
+ * Returns
+ * 0: Successfully
+ * Negative value: Failed
+ */
+static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_hw *hw = &adapter->hw;
+
+ return pch_gbe_mac_ctrl_miim(hw, addr, PCH_GBE_HAL_MIIM_READ, reg,
+ (u16) 0);
+}
+
+/**
+ * pch_gbe_mdio_write - The write function for mii
+ * @netdev: Network interface device structure
+ * @addr: Phy ID (not used)
+ * @reg: Access location
+ * @data: Write data
+ */
+static void pch_gbe_mdio_write(struct net_device *netdev,
+ int addr, int reg, int data)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_hw *hw = &adapter->hw;
+
+ pch_gbe_mac_ctrl_miim(hw, addr, PCH_GBE_HAL_MIIM_WRITE, reg, data);
+}
+
+/**
+ * pch_gbe_reset_task - Reset processing at the time of transmission timeout
+ * @work: Pointer of board private structure
+ */
+static void pch_gbe_reset_task(struct work_struct *work)
+{
+ struct pch_gbe_adapter *adapter;
+ adapter = container_of(work, struct pch_gbe_adapter, reset_task);
+
+ pch_gbe_reinit_locked(adapter);
+}
+
+/**
+ * pch_gbe_reinit_locked- Re-initialization
+ * @adapter: Board private structure
+ */
+void pch_gbe_reinit_locked(struct pch_gbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ rtnl_lock();
+ if (netif_running(netdev)) {
+ pch_gbe_down(adapter);
+ pch_gbe_up(adapter);
+ }
+ rtnl_unlock();
+}
+
+/**
+ * pch_gbe_reset - Reset GbE
+ * @adapter: Board private structure
+ */
+void pch_gbe_reset(struct pch_gbe_adapter *adapter)
+{
+ pch_gbe_mac_reset_hw(&adapter->hw);
+ /* Setup the receive address. */
+ pch_gbe_mac_init_rx_addrs(&adapter->hw, PCH_GBE_MAR_ENTRIES);
+ if (pch_gbe_hal_init_hw(&adapter->hw))
+ pr_err("Hardware Error\n");
+}
+
+/**
+ * pch_gbe_free_irq - Free an interrupt
+ * @adapter: Board private structure
+ */
+static void pch_gbe_free_irq(struct pch_gbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ free_irq(adapter->pdev->irq, netdev);
+ if (adapter->have_msi) {
+ pci_disable_msi(adapter->pdev);
+ pr_debug("call pci_disable_msi\n");
+ }
+}
+
+/**
+ * pch_gbe_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: Board private structure
+ */
+static void pch_gbe_irq_disable(struct pch_gbe_adapter *adapter)
+{
+ struct pch_gbe_hw *hw = &adapter->hw;
+
+ atomic_inc(&adapter->irq_sem);
+ iowrite32(0, &hw->reg->INT_EN);
+ ioread32(&hw->reg->INT_ST);
+ synchronize_irq(adapter->pdev->irq);
+
+ pr_debug("INT_EN reg : 0x%08x\n", ioread32(&hw->reg->INT_EN));
+}
+
+/**
+ * pch_gbe_irq_enable - Enable default interrupt generation settings
+ * @adapter: Board private structure
+ */
+static void pch_gbe_irq_enable(struct pch_gbe_adapter *adapter)
+{
+ struct pch_gbe_hw *hw = &adapter->hw;
+
+ if (likely(atomic_dec_and_test(&adapter->irq_sem)))
+ iowrite32(PCH_GBE_INT_ENABLE_MASK, &hw->reg->INT_EN);
+ ioread32(&hw->reg->INT_ST);
+ pr_debug("INT_EN reg : 0x%08x\n", ioread32(&hw->reg->INT_EN));
+}
+
+
+
+/**
+ * pch_gbe_setup_tctl - configure the Transmit control registers
+ * @adapter: Board private structure
+ */
+static void pch_gbe_setup_tctl(struct pch_gbe_adapter *adapter)
+{
+ struct pch_gbe_hw *hw = &adapter->hw;
+ u32 tx_mode, tcpip;
+
+ tx_mode = PCH_GBE_TM_LONG_PKT |
+ PCH_GBE_TM_ST_AND_FD |
+ PCH_GBE_TM_SHORT_PKT |
+ PCH_GBE_TM_TH_TX_STRT_8 |
+ PCH_GBE_TM_TH_ALM_EMP_4 | PCH_GBE_TM_TH_ALM_FULL_8;
+
+ iowrite32(tx_mode, &hw->reg->TX_MODE);
+
+ tcpip = ioread32(&hw->reg->TCPIP_ACC);
+ tcpip |= PCH_GBE_TX_TCPIPACC_EN;
+ iowrite32(tcpip, &hw->reg->TCPIP_ACC);
+ return;
+}
+
+/**
+ * pch_gbe_configure_tx - Configure Transmit Unit after Reset
+ * @adapter: Board private structure
+ */
+static void pch_gbe_configure_tx(struct pch_gbe_adapter *adapter)
+{
+ struct pch_gbe_hw *hw = &adapter->hw;
+ u32 tdba, tdlen, dctrl;
+
+ pr_debug("dma addr = 0x%08llx size = 0x%08x\n",
+ (unsigned long long)adapter->tx_ring->dma,
+ adapter->tx_ring->size);
+
+ /* Setup the HW Tx Head and Tail descriptor pointers */
+ tdba = adapter->tx_ring->dma;
+ tdlen = adapter->tx_ring->size - 0x10;
+ iowrite32(tdba, &hw->reg->TX_DSC_BASE);
+ iowrite32(tdlen, &hw->reg->TX_DSC_SIZE);
+ iowrite32(tdba, &hw->reg->TX_DSC_SW_P);
+
+ /* Enables Transmission DMA */
+ dctrl = ioread32(&hw->reg->DMA_CTRL);
+ dctrl |= PCH_GBE_TX_DMA_EN;
+ iowrite32(dctrl, &hw->reg->DMA_CTRL);
+}
+
+/**
+ * pch_gbe_setup_rctl - Configure the receive control registers
+ * @adapter: Board private structure
+ */
+static void pch_gbe_setup_rctl(struct pch_gbe_adapter *adapter)
+{
+ struct pch_gbe_hw *hw = &adapter->hw;
+ u32 rx_mode, tcpip;
+
+ rx_mode = PCH_GBE_ADD_FIL_EN | PCH_GBE_MLT_FIL_EN |
+ PCH_GBE_RH_ALM_EMP_4 | PCH_GBE_RH_ALM_FULL_4 | PCH_GBE_RH_RD_TRG_8;
+
+ iowrite32(rx_mode, &hw->reg->RX_MODE);
+
+ tcpip = ioread32(&hw->reg->TCPIP_ACC);
+
+ if (adapter->rx_csum) {
+ 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;
+ }
+ iowrite32(tcpip, &hw->reg->TCPIP_ACC);
+ return;
+}
+
+/**
+ * pch_gbe_configure_rx - Configure Receive Unit after Reset
+ * @adapter: Board private structure
+ */
+static void pch_gbe_configure_rx(struct pch_gbe_adapter *adapter)
+{
+ struct pch_gbe_hw *hw = &adapter->hw;
+ u32 rdba, rdlen, rctl, rxdma;
+
+ pr_debug("dma adr = 0x%08llx size = 0x%08x\n",
+ (unsigned long long)adapter->rx_ring->dma,
+ adapter->rx_ring->size);
+
+ pch_gbe_mac_force_mac_fc(hw);
+
+ /* Disables Receive MAC */
+ rctl = ioread32(&hw->reg->MAC_RX_EN);
+ iowrite32((rctl & ~PCH_GBE_MRE_MAC_RX_EN), &hw->reg->MAC_RX_EN);
+
+ /* Disables Receive DMA */
+ rxdma = ioread32(&hw->reg->DMA_CTRL);
+ rxdma &= ~PCH_GBE_RX_DMA_EN;
+ iowrite32(rxdma, &hw->reg->DMA_CTRL);
+
+ pr_debug("MAC_RX_EN reg = 0x%08x DMA_CTRL reg = 0x%08x\n",
+ ioread32(&hw->reg->MAC_RX_EN),
+ ioread32(&hw->reg->DMA_CTRL));
+
+ /* Setup the HW Rx Head and Tail Descriptor Pointers and
+ * the Base and Length of the Rx Descriptor Ring */
+ rdba = adapter->rx_ring->dma;
+ rdlen = adapter->rx_ring->size - 0x10;
+ 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);
+}
+
+/**
+ * pch_gbe_unmap_and_free_tx_resource - Unmap and free tx socket buffer
+ * @adapter: Board private structure
+ * @buffer_info: Buffer information structure
+ */
+static void pch_gbe_unmap_and_free_tx_resource(
+ struct pch_gbe_adapter *adapter, struct pch_gbe_buffer *buffer_info)
+{
+ if (buffer_info->mapped) {
+ dma_unmap_single(&adapter->pdev->dev, buffer_info->dma,
+ buffer_info->length, DMA_TO_DEVICE);
+ buffer_info->mapped = false;
+ }
+ if (buffer_info->skb) {
+ dev_kfree_skb_any(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+}
+
+/**
+ * pch_gbe_unmap_and_free_rx_resource - Unmap and free rx socket buffer
+ * @adapter: Board private structure
+ * @buffer_info: Buffer information structure
+ */
+static void pch_gbe_unmap_and_free_rx_resource(
+ struct pch_gbe_adapter *adapter,
+ struct pch_gbe_buffer *buffer_info)
+{
+ if (buffer_info->mapped) {
+ dma_unmap_single(&adapter->pdev->dev, buffer_info->dma,
+ buffer_info->length, DMA_FROM_DEVICE);
+ buffer_info->mapped = false;
+ }
+ if (buffer_info->skb) {
+ dev_kfree_skb_any(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+}
+
+/**
+ * pch_gbe_clean_tx_ring - Free Tx Buffers
+ * @adapter: Board private structure
+ * @tx_ring: Ring to be cleaned
+ */
+static void pch_gbe_clean_tx_ring(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_tx_ring *tx_ring)
+{
+ struct pch_gbe_hw *hw = &adapter->hw;
+ struct pch_gbe_buffer *buffer_info;
+ unsigned long size;
+ unsigned int i;
+
+ /* Free all the Tx ring sk_buffs */
+ for (i = 0; i < tx_ring->count; i++) {
+ buffer_info = &tx_ring->buffer_info[i];
+ pch_gbe_unmap_and_free_tx_resource(adapter, buffer_info);
+ }
+ pr_debug("call pch_gbe_unmap_and_free_tx_resource() %d count\n", i);
+
+ size = (unsigned long)sizeof(struct pch_gbe_buffer) * tx_ring->count;
+ memset(tx_ring->buffer_info, 0, size);
+
+ /* Zero out the descriptor ring */
+ memset(tx_ring->desc, 0, tx_ring->size);
+ tx_ring->next_to_use = 0;
+ tx_ring->next_to_clean = 0;
+ iowrite32(tx_ring->dma, &hw->reg->TX_DSC_HW_P);
+ iowrite32((tx_ring->size - 0x10), &hw->reg->TX_DSC_SIZE);
+}
+
+/**
+ * pch_gbe_clean_rx_ring - Free Rx Buffers
+ * @adapter: Board private structure
+ * @rx_ring: Ring to free buffers from
+ */
+static void
+pch_gbe_clean_rx_ring(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_rx_ring *rx_ring)
+{
+ struct pch_gbe_hw *hw = &adapter->hw;
+ struct pch_gbe_buffer *buffer_info;
+ unsigned long size;
+ unsigned int i;
+
+ /* Free all the Rx ring sk_buffs */
+ for (i = 0; i < rx_ring->count; i++) {
+ buffer_info = &rx_ring->buffer_info[i];
+ pch_gbe_unmap_and_free_rx_resource(adapter, buffer_info);
+ }
+ pr_debug("call pch_gbe_unmap_and_free_rx_resource() %d count\n", i);
+ size = (unsigned long)sizeof(struct pch_gbe_buffer) * rx_ring->count;
+ memset(rx_ring->buffer_info, 0, size);
+
+ /* Zero out the descriptor ring */
+ memset(rx_ring->desc, 0, rx_ring->size);
+ rx_ring->next_to_clean = 0;
+ rx_ring->next_to_use = 0;
+ iowrite32(rx_ring->dma, &hw->reg->RX_DSC_HW_P);
+ iowrite32((rx_ring->size - 0x10), &hw->reg->RX_DSC_SIZE);
+}
+
+static void pch_gbe_set_rgmii_ctrl(struct pch_gbe_adapter *adapter, u16 speed,
+ u16 duplex)
+{
+ struct pch_gbe_hw *hw = &adapter->hw;
+ unsigned long rgmii = 0;
+
+ /* Set the RGMII control. */
+#ifdef PCH_GBE_MAC_IFOP_RGMII
+ switch (speed) {
+ case SPEED_10:
+ rgmii = (PCH_GBE_RGMII_RATE_2_5M |
+ PCH_GBE_MAC_RGMII_CTRL_SETTING);
+ break;
+ case SPEED_100:
+ rgmii = (PCH_GBE_RGMII_RATE_25M |
+ PCH_GBE_MAC_RGMII_CTRL_SETTING);
+ break;
+ case SPEED_1000:
+ rgmii = (PCH_GBE_RGMII_RATE_125M |
+ PCH_GBE_MAC_RGMII_CTRL_SETTING);
+ break;
+ }
+ iowrite32(rgmii, &hw->reg->RGMII_CTRL);
+#else /* GMII */
+ rgmii = 0;
+ iowrite32(rgmii, &hw->reg->RGMII_CTRL);
+#endif
+}
+static void pch_gbe_set_mode(struct pch_gbe_adapter *adapter, u16 speed,
+ u16 duplex)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pch_gbe_hw *hw = &adapter->hw;
+ unsigned long mode = 0;
+
+ /* Set the communication mode */
+ switch (speed) {
+ case SPEED_10:
+ mode = PCH_GBE_MODE_MII_ETHER;
+ netdev->tx_queue_len = 10;
+ break;
+ case SPEED_100:
+ mode = PCH_GBE_MODE_MII_ETHER;
+ netdev->tx_queue_len = 100;
+ break;
+ case SPEED_1000:
+ mode = PCH_GBE_MODE_GMII_ETHER;
+ break;
+ }
+ if (duplex == DUPLEX_FULL)
+ mode |= PCH_GBE_MODE_FULL_DUPLEX;
+ else
+ mode |= PCH_GBE_MODE_HALF_DUPLEX;
+ iowrite32(mode, &hw->reg->MODE);
+}
+
+/**
+ * pch_gbe_watchdog - Watchdog process
+ * @data: Board private structure
+ */
+static void pch_gbe_watchdog(unsigned long data)
+{
+ struct pch_gbe_adapter *adapter = (struct pch_gbe_adapter *)data;
+ struct net_device *netdev = adapter->netdev;
+ struct pch_gbe_hw *hw = &adapter->hw;
+ struct ethtool_cmd cmd;
+
+ pr_debug("right now = %ld\n", jiffies);
+
+ pch_gbe_update_stats(adapter);
+ if ((mii_link_ok(&adapter->mii)) && (!netif_carrier_ok(netdev))) {
+ netdev->tx_queue_len = adapter->tx_queue_len;
+ /* mii library handles link maintenance tasks */
+ if (mii_ethtool_gset(&adapter->mii, &cmd)) {
+ pr_err("ethtool get setting Error\n");
+ mod_timer(&adapter->watchdog_timer,
+ round_jiffies(jiffies +
+ PCH_GBE_WATCHDOG_PERIOD));
+ return;
+ }
+ hw->mac.link_speed = cmd.speed;
+ hw->mac.link_duplex = cmd.duplex;
+ /* Set the RGMII control. */
+ pch_gbe_set_rgmii_ctrl(adapter, hw->mac.link_speed,
+ hw->mac.link_duplex);
+ /* Set the communication mode */
+ pch_gbe_set_mode(adapter, hw->mac.link_speed,
+ hw->mac.link_duplex);
+ netdev_dbg(netdev,
+ "Link is Up %d Mbps %s-Duplex\n",
+ cmd.speed,
+ cmd.duplex == DUPLEX_FULL ? "Full" : "Half");
+ netif_carrier_on(netdev);
+ netif_wake_queue(netdev);
+ } else if ((!mii_link_ok(&adapter->mii)) &&
+ (netif_carrier_ok(netdev))) {
+ netdev_dbg(netdev, "NIC Link is Down\n");
+ hw->mac.link_speed = SPEED_10;
+ hw->mac.link_duplex = DUPLEX_HALF;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+ mod_timer(&adapter->watchdog_timer,
+ round_jiffies(jiffies + PCH_GBE_WATCHDOG_PERIOD));
+}
+
+/**
+ * pch_gbe_tx_queue - Carry out queuing of the transmission data
+ * @adapter: Board private structure
+ * @tx_ring: Tx descriptor ring structure
+ * @skb: Sockt buffer structure
+ */
+static void pch_gbe_tx_queue(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_tx_ring *tx_ring,
+ struct sk_buff *skb)
+{
+ struct pch_gbe_hw *hw = &adapter->hw;
+ struct pch_gbe_tx_desc *tx_desc;
+ struct pch_gbe_buffer *buffer_info;
+ struct sk_buff *tmp_skb;
+ unsigned int frame_ctrl;
+ unsigned int ring_num;
+ unsigned long flags;
+
+ /*-- Set frame control --*/
+ frame_ctrl = 0;
+ if (unlikely(skb->len < PCH_GBE_SHORT_PKT))
+ frame_ctrl |= PCH_GBE_TXD_CTRL_APAD;
+ if (unlikely(!adapter->tx_csum))
+ frame_ctrl |= PCH_GBE_TXD_CTRL_TCPIP_ACC_OFF;
+
+ /* Performs checksum processing */
+ /*
+ * It is because the hardware accelerator does not support a checksum,
+ * when the received data size is less than 64 bytes.
+ */
+ if ((skb->len < PCH_GBE_SHORT_PKT) && (adapter->tx_csum)) {
+ frame_ctrl |= PCH_GBE_TXD_CTRL_APAD |
+ PCH_GBE_TXD_CTRL_TCPIP_ACC_OFF;
+ if (skb->protocol == htons(ETH_P_IP)) {
+ struct iphdr *iph = ip_hdr(skb);
+ unsigned int offset;
+ iph->check = 0;
+ iph->check = ip_fast_csum((u8 *) iph, iph->ihl);
+ offset = skb_transport_offset(skb);
+ if (iph->protocol == IPPROTO_TCP) {
+ skb->csum = 0;
+ tcp_hdr(skb)->check = 0;
+ skb->csum = skb_checksum(skb, offset,
+ skb->len - offset, 0);
+ tcp_hdr(skb)->check =
+ csum_tcpudp_magic(iph->saddr,
+ iph->daddr,
+ skb->len - offset,
+ IPPROTO_TCP,
+ skb->csum);
+ } else if (iph->protocol == IPPROTO_UDP) {
+ skb->csum = 0;
+ udp_hdr(skb)->check = 0;
+ skb->csum =
+ skb_checksum(skb, offset,
+ skb->len - offset, 0);
+ udp_hdr(skb)->check =
+ csum_tcpudp_magic(iph->saddr,
+ iph->daddr,
+ skb->len - offset,
+ IPPROTO_UDP,
+ skb->csum);
+ }
+ }
+ }
+ spin_lock_irqsave(&tx_ring->tx_lock, flags);
+ ring_num = tx_ring->next_to_use;
+ if (unlikely((ring_num + 1) == tx_ring->count))
+ tx_ring->next_to_use = 0;
+ else
+ tx_ring->next_to_use = ring_num + 1;
+
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+ buffer_info = &tx_ring->buffer_info[ring_num];
+ tmp_skb = buffer_info->skb;
+
+ /* [Header:14][payload] ---> [Header:14][paddong:2][payload] */
+ memcpy(tmp_skb->data, skb->data, ETH_HLEN);
+ tmp_skb->data[ETH_HLEN] = 0x00;
+ tmp_skb->data[ETH_HLEN + 1] = 0x00;
+ tmp_skb->len = skb->len;
+ memcpy(&tmp_skb->data[ETH_HLEN + 2], &skb->data[ETH_HLEN],
+ (skb->len - ETH_HLEN));
+ /*-- Set Buffer infomation --*/
+ buffer_info->length = tmp_skb->len;
+ buffer_info->dma = dma_map_single(&adapter->pdev->dev, tmp_skb->data,
+ buffer_info->length,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma)) {
+ pr_err("TX DMA map failed\n");
+ buffer_info->dma = 0;
+ buffer_info->time_stamp = 0;
+ tx_ring->next_to_use = ring_num;
+ return;
+ }
+ buffer_info->mapped = true;
+ buffer_info->time_stamp = jiffies;
+
+ /*-- Set Tx descriptor --*/
+ tx_desc = PCH_GBE_TX_DESC(*tx_ring, ring_num);
+ tx_desc->buffer_addr = (buffer_info->dma);
+ tx_desc->length = (tmp_skb->len);
+ tx_desc->tx_words_eob = ((tmp_skb->len + 3));
+ tx_desc->tx_frame_ctrl = (frame_ctrl);
+ tx_desc->gbec_status = (DSC_INIT16);
+
+ if (unlikely(++ring_num == tx_ring->count))
+ ring_num = 0;
+
+ /* Update software pointer of TX descriptor */
+ iowrite32(tx_ring->dma +
+ (int)sizeof(struct pch_gbe_tx_desc) * ring_num,
+ &hw->reg->TX_DSC_SW_P);
+ dev_kfree_skb_any(skb);
+}
+
+/**
+ * pch_gbe_update_stats - Update the board statistics counters
+ * @adapter: Board private structure
+ */
+void pch_gbe_update_stats(struct pch_gbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct pch_gbe_hw_stats *stats = &adapter->stats;
+ unsigned long flags;
+
+ /*
+ * Prevent stats update while adapter is being reset, or if the pci
+ * connection is down.
+ */
+ if ((pdev->error_state) && (pdev->error_state != pci_channel_io_normal))
+ return;
+
+ spin_lock_irqsave(&adapter->stats_lock, flags);
+
+ /* Update device status "adapter->stats" */
+ stats->rx_errors = stats->rx_crc_errors + stats->rx_frame_errors;
+ stats->tx_errors = stats->tx_length_errors +
+ stats->tx_aborted_errors +
+ stats->tx_carrier_errors + stats->tx_timeout_count;
+
+ /* Update network device status "adapter->net_stats" */
+ netdev->stats.rx_packets = stats->rx_packets;
+ netdev->stats.rx_bytes = stats->rx_bytes;
+ netdev->stats.rx_dropped = stats->rx_dropped;
+ netdev->stats.tx_packets = stats->tx_packets;
+ netdev->stats.tx_bytes = stats->tx_bytes;
+ netdev->stats.tx_dropped = stats->tx_dropped;
+ /* Fill out the OS statistics structure */
+ netdev->stats.multicast = stats->multicast;
+ netdev->stats.collisions = stats->collisions;
+ /* Rx Errors */
+ netdev->stats.rx_errors = stats->rx_errors;
+ netdev->stats.rx_crc_errors = stats->rx_crc_errors;
+ netdev->stats.rx_frame_errors = stats->rx_frame_errors;
+ /* Tx Errors */
+ netdev->stats.tx_errors = stats->tx_errors;
+ netdev->stats.tx_aborted_errors = stats->tx_aborted_errors;
+ netdev->stats.tx_carrier_errors = stats->tx_carrier_errors;
+
+ spin_unlock_irqrestore(&adapter->stats_lock, flags);
+}
+
+/**
+ * pch_gbe_intr - Interrupt Handler
+ * @irq: Interrupt number
+ * @data: Pointer to a network interface device structure
+ * Returns
+ * - IRQ_HANDLED: Our interrupt
+ * - IRQ_NONE: Not our interrupt
+ */
+static irqreturn_t pch_gbe_intr(int irq, void *data)
+{
+ struct net_device *netdev = data;
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_hw *hw = &adapter->hw;
+ u32 int_st;
+ u32 int_en;
+
+ /* Check request status */
+ int_st = ioread32(&hw->reg->INT_ST);
+ int_st = int_st & ioread32(&hw->reg->INT_EN);
+ /* When request status is no interruption factor */
+ if (unlikely(!int_st))
+ return IRQ_NONE; /* Not our interrupt. End processing. */
+ pr_debug("%s occur int_st = 0x%08x\n", __func__, int_st);
+ 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 (int_st & PCH_GBE_INT_RX_DMA_ERR)
+ adapter->stats.intr_rx_dma_err_count++;
+ if (int_st & PCH_GBE_INT_TX_FIFO_ERR)
+ adapter->stats.intr_tx_fifo_err_count++;
+ if (int_st & PCH_GBE_INT_TX_DMA_ERR)
+ adapter->stats.intr_tx_dma_err_count++;
+ if (int_st & PCH_GBE_INT_TCPIP_ERR)
+ adapter->stats.intr_tcpip_err_count++;
+ /* 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");
+ 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 (likely(napi_schedule_prep(&adapter->napi))) {
+ /* Enable only Rx Descriptor empty */
+ atomic_inc(&adapter->irq_sem);
+ int_en = ioread32(&hw->reg->INT_EN);
+ int_en &=
+ ~(PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT);
+ iowrite32(int_en, &hw->reg->INT_EN);
+ /* Start polling for NAPI */
+ __napi_schedule(&adapter->napi);
+ }
+ }
+ pr_debug("return = 0x%08x INT_EN reg = 0x%08x\n",
+ IRQ_HANDLED, ioread32(&hw->reg->INT_EN));
+ return IRQ_HANDLED;
+}
+
+/**
+ * pch_gbe_alloc_rx_buffers - Replace used receive buffers; legacy & extended
+ * @adapter: Board private structure
+ * @rx_ring: Rx descriptor ring
+ * @cleaned_count: Cleaned count
+ */
+static void
+pch_gbe_alloc_rx_buffers(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_rx_ring *rx_ring, int cleaned_count)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct pch_gbe_hw *hw = &adapter->hw;
+ struct pch_gbe_rx_desc *rx_desc;
+ struct pch_gbe_buffer *buffer_info;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned int bufsz;
+
+ bufsz = adapter->rx_buffer_len + PCH_GBE_DMA_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;
+ }
+ buffer_info->dma = dma_map_single(&pdev->dev,
+ skb->data,
+ buffer_info->length,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma)) {
+ dev_kfree_skb(skb);
+ buffer_info->skb = NULL;
+ buffer_info->dma = 0;
+ adapter->stats.rx_alloc_buff_failed++;
+ break; /* while !buffer_info->skb */
+ }
+ buffer_info->mapped = true;
+ rx_desc = PCH_GBE_RX_DESC(*rx_ring, i);
+ rx_desc->buffer_addr = (buffer_info->dma);
+ rx_desc->gbec_status = DSC_INIT16;
+
+ pr_debug("i = %d buffer_info->dma = 0x08%llx buffer_info->length = 0x%x\n",
+ i, (unsigned long long)buffer_info->dma,
+ buffer_info->length);
+
+ if (unlikely(++i == rx_ring->count))
+ i = 0;
+ }
+ if (likely(rx_ring->next_to_use != i)) {
+ rx_ring->next_to_use = i;
+ if (unlikely(i-- == 0))
+ i = (rx_ring->count - 1);
+ iowrite32(rx_ring->dma +
+ (int)sizeof(struct pch_gbe_rx_desc) * i,
+ &hw->reg->RX_DSC_SW_P);
+ }
+ return;
+}
+
+/**
+ * pch_gbe_alloc_tx_buffers - Allocate transmit buffers
+ * @adapter: Board private structure
+ * @tx_ring: Tx descriptor ring
+ */
+static void pch_gbe_alloc_tx_buffers(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_tx_ring *tx_ring)
+{
+ struct pch_gbe_buffer *buffer_info;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned int bufsz;
+ struct pch_gbe_tx_desc *tx_desc;
+
+ bufsz =
+ adapter->hw.mac.max_frame_size + PCH_GBE_DMA_ALIGN + NET_IP_ALIGN;
+
+ for (i = 0; i < tx_ring->count; i++) {
+ buffer_info = &tx_ring->buffer_info[i];
+ skb = netdev_alloc_skb(adapter->netdev, bufsz);
+ skb_reserve(skb, PCH_GBE_DMA_ALIGN);
+ buffer_info->skb = skb;
+ tx_desc = PCH_GBE_TX_DESC(*tx_ring, i);
+ tx_desc->gbec_status = (DSC_INIT16);
+ }
+ return;
+}
+
+/**
+ * pch_gbe_clean_tx - Reclaim resources after transmit completes
+ * @adapter: Board private structure
+ * @tx_ring: Tx descriptor ring
+ * Returns
+ * true: Cleaned the descriptor
+ * false: Not cleaned the descriptor
+ */
+static bool
+pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_tx_ring *tx_ring)
+{
+ struct pch_gbe_tx_desc *tx_desc;
+ struct pch_gbe_buffer *buffer_info;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned int cleaned_count = 0;
+ bool cleaned = false;
+
+ pr_debug("next_to_clean : %d\n", tx_ring->next_to_clean);
+
+ i = tx_ring->next_to_clean;
+ tx_desc = PCH_GBE_TX_DESC(*tx_ring, i);
+ pr_debug("gbec_status:0x%04x dma_status:0x%04x\n",
+ tx_desc->gbec_status, tx_desc->dma_status);
+
+ 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;
+
+ if ((tx_desc->gbec_status & PCH_GBE_TXD_GMAC_STAT_ABT)) {
+ adapter->stats.tx_aborted_errors++;
+ pr_err("Transfer Abort Error\n");
+ } else if ((tx_desc->gbec_status & PCH_GBE_TXD_GMAC_STAT_CRSER)
+ ) {
+ adapter->stats.tx_carrier_errors++;
+ pr_err("Transfer Carrier Sense Error\n");
+ } else if ((tx_desc->gbec_status & PCH_GBE_TXD_GMAC_STAT_EXCOL)
+ ) {
+ adapter->stats.tx_aborted_errors++;
+ pr_err("Transfer Collision Abort Error\n");
+ } else if ((tx_desc->gbec_status &
+ (PCH_GBE_TXD_GMAC_STAT_SNGCOL |
+ PCH_GBE_TXD_GMAC_STAT_MLTCOL))) {
+ adapter->stats.collisions++;
+ adapter->stats.tx_packets++;
+ adapter->stats.tx_bytes += skb->len;
+ pr_debug("Transfer Collision\n");
+ } else if ((tx_desc->gbec_status & PCH_GBE_TXD_GMAC_STAT_CMPLT)
+ ) {
+ adapter->stats.tx_packets++;
+ adapter->stats.tx_bytes += skb->len;
+ }
+ if (buffer_info->mapped) {
+ pr_debug("unmap buffer_info->dma : %d\n", i);
+ dma_unmap_single(&adapter->pdev->dev, buffer_info->dma,
+ buffer_info->length, DMA_TO_DEVICE);
+ buffer_info->mapped = false;
+ }
+ if (buffer_info->skb) {
+ pr_debug("trim buffer_info->skb : %d\n", i);
+ skb_trim(buffer_info->skb, 0);
+ }
+ tx_desc->gbec_status = DSC_INIT16;
+ if (unlikely(++i == tx_ring->count))
+ i = 0;
+ 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)
+ break;
+ }
+ pr_debug("called pch_gbe_unmap_and_free_tx_resource() %d count\n",
+ cleaned_count);
+ /* Recover from running out of Tx resources in xmit_frame */
+ if (unlikely(cleaned && (netif_queue_stopped(adapter->netdev)))) {
+ netif_wake_queue(adapter->netdev);
+ adapter->stats.tx_restart_count++;
+ pr_debug("Tx wake queue\n");
+ }
+ spin_lock(&adapter->tx_queue_lock);
+ tx_ring->next_to_clean = i;
+ spin_unlock(&adapter->tx_queue_lock);
+ pr_debug("next_to_clean : %d\n", tx_ring->next_to_clean);
+ return cleaned;
+}
+
+/**
+ * pch_gbe_clean_rx - Send received data up the network stack; legacy
+ * @adapter: Board private structure
+ * @rx_ring: Rx descriptor ring
+ * @work_done: Completed count
+ * @work_to_do: Request count
+ * Returns
+ * true: Cleaned the descriptor
+ * false: Not cleaned the descriptor
+ */
+static bool
+pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_rx_ring *rx_ring,
+ int *work_done, int work_to_do)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct pch_gbe_buffer *buffer_info;
+ struct pch_gbe_rx_desc *rx_desc;
+ u32 length;
+ unsigned char tmp_packet[ETH_HLEN];
+ unsigned int i;
+ unsigned int cleaned_count = 0;
+ bool cleaned = false;
+ struct sk_buff *skb;
+ u8 dma_status;
+ u16 gbec_status;
+ u32 tcp_ip_status;
+ u8 skb_copy_flag = 0;
+ u8 skb_padding_flag = 0;
+
+ i = rx_ring->next_to_clean;
+
+ while (*work_done < work_to_do) {
+ /* Check Rx descriptor status */
+ rx_desc = PCH_GBE_RX_DESC(*rx_ring, i);
+ if (rx_desc->gbec_status == DSC_INIT16)
+ break;
+ cleaned = true;
+ cleaned_count++;
+
+ dma_status = rx_desc->dma_status;
+ gbec_status = rx_desc->gbec_status;
+ tcp_ip_status = rx_desc->tcp_ip_status;
+ rx_desc->gbec_status = DSC_INIT16;
+ buffer_info = &rx_ring->buffer_info[i];
+ skb = buffer_info->skb;
+
+ /* 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",
+ i, dma_status, gbec_status, tcp_ip_status,
+ buffer_info);
+ /* Error check */
+ if (unlikely(gbec_status & PCH_GBE_RXD_GMAC_STAT_NOTOCTAL)) {
+ adapter->stats.rx_frame_errors++;
+ pr_err("Receive Not Octal Error\n");
+ } else if (unlikely(gbec_status &
+ PCH_GBE_RXD_GMAC_STAT_NBLERR)) {
+ adapter->stats.rx_frame_errors++;
+ pr_err("Receive Nibble Error\n");
+ } else if (unlikely(gbec_status &
+ PCH_GBE_RXD_GMAC_STAT_CRCERR)) {
+ adapter->stats.rx_crc_errors++;
+ pr_err("Receive CRC Error\n");
+ } else {
+ /* get receive length */
+ /* length convert[-3], padding[-2] */
+ length = (rx_desc->rx_words_eob) - 3 - 2;
+
+ /* Decide the data conversion method */
+ if (!adapter->rx_csum) {
+ /* [Header:14][payload] */
+ skb_padding_flag = 0;
+ skb_copy_flag = 1;
+ } else {
+ /* [Header:14][padding:2][payload] */
+ skb_padding_flag = 1;
+ if (length < copybreak)
+ skb_copy_flag = 1;
+ else
+ skb_copy_flag = 0;
+ }
+
+ /* Data conversion */
+ if (skb_copy_flag) { /* recycle skb */
+ struct sk_buff *new_skb;
+ new_skb =
+ netdev_alloc_skb(netdev,
+ length + NET_IP_ALIGN);
+ if (new_skb) {
+ if (!skb_padding_flag) {
+ skb_reserve(new_skb,
+ NET_IP_ALIGN);
+ }
+ memcpy(new_skb->data, skb->data,
+ length);
+ /* save the skb
+ * in buffer_info as good */
+ skb = new_skb;
+ } else if (!skb_padding_flag) {
+ /* dorrop error */
+ pr_err("New skb allocation Error\n");
+ goto dorrop;
+ }
+ } else {
+ buffer_info->skb = NULL;
+ }
+ if (skb_padding_flag) {
+ memcpy(&tmp_packet[0], &skb->data[0], ETH_HLEN);
+ memcpy(&skb->data[NET_IP_ALIGN], &tmp_packet[0],
+ ETH_HLEN);
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ }
+
+ /* update status of driver */
+ adapter->stats.rx_bytes += length;
+ adapter->stats.rx_packets++;
+ if ((gbec_status & PCH_GBE_RXD_GMAC_STAT_MARMLT))
+ adapter->stats.multicast++;
+ /* Write meta date of skb */
+ skb_put(skb, length);
+ skb->protocol = eth_type_trans(skb, netdev);
+ if ((tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK) ==
+ PCH_GBE_RXD_ACC_STAT_TCPIPOK) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+ napi_gro_receive(&adapter->napi, skb);
+ (*work_done)++;
+ 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,
+ cleaned_count);
+ cleaned_count = 0;
+ }
+ if (++i == rx_ring->count)
+ i = 0;
+ }
+ rx_ring->next_to_clean = i;
+ if (cleaned_count)
+ pch_gbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
+ return cleaned;
+}
+
+/**
+ * pch_gbe_setup_tx_resources - Allocate Tx resources (Descriptors)
+ * @adapter: Board private structure
+ * @tx_ring: Tx descriptor ring (for a specific queue) to setup
+ * Returns
+ * 0: Successfully
+ * Negative value: Failed
+ */
+int pch_gbe_setup_tx_resources(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_tx_ring *tx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct pch_gbe_tx_desc *tx_desc;
+ int size;
+ int desNo;
+
+ size = (int)sizeof(struct pch_gbe_buffer) * tx_ring->count;
+ tx_ring->buffer_info = vmalloc(size);
+ if (!tx_ring->buffer_info) {
+ pr_err("Unable to allocate memory for the buffer infomation\n");
+ return -ENOMEM;
+ }
+ memset(tx_ring->buffer_info, 0, size);
+
+ tx_ring->size = tx_ring->count * (int)sizeof(struct pch_gbe_tx_desc);
+
+ tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size,
+ &tx_ring->dma, GFP_KERNEL);
+ if (!tx_ring->desc) {
+ vfree(tx_ring->buffer_info);
+ pr_err("Unable to allocate memory for the transmit descriptor ring\n");
+ return -ENOMEM;
+ }
+ memset(tx_ring->desc, 0, tx_ring->size);
+
+ tx_ring->next_to_use = 0;
+ tx_ring->next_to_clean = 0;
+ spin_lock_init(&tx_ring->tx_lock);
+
+ for (desNo = 0; desNo < tx_ring->count; desNo++) {
+ tx_desc = PCH_GBE_TX_DESC(*tx_ring, desNo);
+ tx_desc->gbec_status = DSC_INIT16;
+ }
+ pr_debug("tx_ring->desc = 0x%p tx_ring->dma = 0x%08llx\n"
+ "next_to_clean = 0x%08x next_to_use = 0x%08x\n",
+ tx_ring->desc, (unsigned long long)tx_ring->dma,
+ tx_ring->next_to_clean, tx_ring->next_to_use);
+ return 0;
+}
+
+/**
+ * pch_gbe_setup_rx_resources - Allocate Rx resources (Descriptors)
+ * @adapter: Board private structure
+ * @rx_ring: Rx descriptor ring (for a specific queue) to setup
+ * Returns
+ * 0: Successfully
+ * Negative value: Failed
+ */
+int pch_gbe_setup_rx_resources(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_rx_ring *rx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct pch_gbe_rx_desc *rx_desc;
+ int size;
+ int desNo;
+
+ size = (int)sizeof(struct pch_gbe_buffer) * rx_ring->count;
+ rx_ring->buffer_info = vmalloc(size);
+ if (!rx_ring->buffer_info) {
+ pr_err("Unable to allocate memory for the receive descriptor ring\n");
+ return -ENOMEM;
+ }
+ memset(rx_ring->buffer_info, 0, size);
+ rx_ring->size = rx_ring->count * (int)sizeof(struct pch_gbe_rx_desc);
+ rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
+ &rx_ring->dma, GFP_KERNEL);
+
+ if (!rx_ring->desc) {
+ pr_err("Unable to allocate memory for the receive descriptor ring\n");
+ vfree(rx_ring->buffer_info);
+ return -ENOMEM;
+ }
+ memset(rx_ring->desc, 0, rx_ring->size);
+ rx_ring->next_to_clean = 0;
+ rx_ring->next_to_use = 0;
+ for (desNo = 0; desNo < rx_ring->count; desNo++) {
+ rx_desc = PCH_GBE_RX_DESC(*rx_ring, desNo);
+ rx_desc->gbec_status = DSC_INIT16;
+ }
+ pr_debug("rx_ring->desc = 0x%p rx_ring->dma = 0x%08llx "
+ "next_to_clean = 0x%08x next_to_use = 0x%08x\n",
+ rx_ring->desc, (unsigned long long)rx_ring->dma,
+ rx_ring->next_to_clean, rx_ring->next_to_use);
+ return 0;
+}
+
+/**
+ * pch_gbe_free_tx_resources - Free Tx Resources
+ * @adapter: Board private structure
+ * @tx_ring: Tx descriptor ring for a specific queue
+ */
+void pch_gbe_free_tx_resources(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_tx_ring *tx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+
+ pch_gbe_clean_tx_ring(adapter, tx_ring);
+ vfree(tx_ring->buffer_info);
+ tx_ring->buffer_info = NULL;
+ pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma);
+ tx_ring->desc = NULL;
+}
+
+/**
+ * pch_gbe_free_rx_resources - Free Rx Resources
+ * @adapter: Board private structure
+ * @rx_ring: Ring to clean the resources from
+ */
+void pch_gbe_free_rx_resources(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_rx_ring *rx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+
+ pch_gbe_clean_rx_ring(adapter, rx_ring);
+ vfree(rx_ring->buffer_info);
+ rx_ring->buffer_info = NULL;
+ pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
+ rx_ring->desc = NULL;
+}
+
+/**
+ * pch_gbe_request_irq - Allocate an interrupt line
+ * @adapter: Board private structure
+ * Returns
+ * 0: Successfully
+ * Negative value: Failed
+ */
+static int pch_gbe_request_irq(struct pch_gbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int err;
+ int flags;
+
+ flags = IRQF_SHARED;
+ adapter->have_msi = false;
+ err = pci_enable_msi(adapter->pdev);
+ pr_debug("call pci_enable_msi\n");
+ if (err) {
+ pr_debug("call pci_enable_msi - Error: %d\n", err);
+ } else {
+ flags = 0;
+ adapter->have_msi = true;
+ }
+ err = request_irq(adapter->pdev->irq, &pch_gbe_intr,
+ flags, netdev->name, netdev);
+ if (err)
+ pr_err("Unable to allocate interrupt Error: %d\n", err);
+ pr_debug("adapter->have_msi : %d flags : 0x%04x return : 0x%04x\n",
+ adapter->have_msi, flags, err);
+ return err;
+}
+
+
+static void pch_gbe_set_multi(struct net_device *netdev);
+/**
+ * pch_gbe_up - Up GbE network device
+ * @adapter: Board private structure
+ * Returns
+ * 0: Successfully
+ * Negative value: Failed
+ */
+int pch_gbe_up(struct pch_gbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pch_gbe_tx_ring *tx_ring = adapter->tx_ring;
+ struct pch_gbe_rx_ring *rx_ring = adapter->rx_ring;
+ int err;
+
+ /* hardware has been reset, we need to reload some things */
+ pch_gbe_set_multi(netdev);
+
+ pch_gbe_setup_tctl(adapter);
+ pch_gbe_configure_tx(adapter);
+ pch_gbe_setup_rctl(adapter);
+ pch_gbe_configure_rx(adapter);
+
+ err = pch_gbe_request_irq(adapter);
+ 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;
+
+ mod_timer(&adapter->watchdog_timer, jiffies);
+
+ napi_enable(&adapter->napi);
+ pch_gbe_irq_enable(adapter);
+ netif_start_queue(adapter->netdev);
+
+ return 0;
+}
+
+/**
+ * pch_gbe_down - Down GbE network device
+ * @adapter: Board private structure
+ */
+void pch_gbe_down(struct pch_gbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ /* signal that we're down so the interrupt handler does not
+ * reschedule our watchdog timer */
+ napi_disable(&adapter->napi);
+ atomic_set(&adapter->irq_sem, 0);
+
+ pch_gbe_irq_disable(adapter);
+ pch_gbe_free_irq(adapter);
+
+ del_timer_sync(&adapter->watchdog_timer);
+
+ netdev->tx_queue_len = adapter->tx_queue_len;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ pch_gbe_reset(adapter);
+ pch_gbe_clean_tx_ring(adapter, adapter->tx_ring);
+ pch_gbe_clean_rx_ring(adapter, adapter->rx_ring);
+}
+
+/**
+ * pch_gbe_sw_init - Initialize general software structures (struct pch_gbe_adapter)
+ * @adapter: Board private structure to initialize
+ * Returns
+ * 0: Successfully
+ * Negative value: Failed
+ */
+static int pch_gbe_sw_init(struct pch_gbe_adapter *adapter)
+{
+ struct pch_gbe_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+
+ adapter->rx_buffer_len = PCH_GBE_FRAME_SIZE_2048;
+ hw->mac.max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+ hw->mac.min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+
+ /* Initialize the hardware-specific values */
+ if (pch_gbe_hal_setup_init_funcs(hw)) {
+ pr_err("Hardware Initialization Failure\n");
+ return -EIO;
+ }
+ if (pch_gbe_alloc_queues(adapter)) {
+ pr_err("Unable to allocate memory for queues\n");
+ return -ENOMEM;
+ }
+ spin_lock_init(&adapter->hw.miim_lock);
+ spin_lock_init(&adapter->tx_queue_lock);
+ spin_lock_init(&adapter->stats_lock);
+ spin_lock_init(&adapter->ethtool_lock);
+ atomic_set(&adapter->irq_sem, 0);
+ pch_gbe_irq_disable(adapter);
+
+ pch_gbe_init_stats(adapter);
+
+ pr_debug("rx_buffer_len : %d mac.min_frame_size : %d mac.max_frame_size : %d\n",
+ (u32) adapter->rx_buffer_len,
+ hw->mac.min_frame_size, hw->mac.max_frame_size);
+ return 0;
+}
+
+/**
+ * pch_gbe_open - Called when a network interface is made active
+ * @netdev: Network interface device structure
+ * Returns
+ * 0: Successfully
+ * Negative value: Failed
+ */
+static int pch_gbe_open(struct net_device *netdev)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_hw *hw = &adapter->hw;
+ int err;
+
+ /* allocate transmit descriptors */
+ err = pch_gbe_setup_tx_resources(adapter, adapter->tx_ring);
+ if (err)
+ goto err_setup_tx;
+ /* allocate receive descriptors */
+ err = pch_gbe_setup_rx_resources(adapter, adapter->rx_ring);
+ if (err)
+ goto err_setup_rx;
+ pch_gbe_hal_power_up_phy(hw);
+ err = pch_gbe_up(adapter);
+ if (err)
+ goto err_up;
+ pr_debug("Success End\n");
+ return 0;
+
+err_up:
+ if (!adapter->wake_up_evt)
+ pch_gbe_hal_power_down_phy(hw);
+ pch_gbe_free_rx_resources(adapter, adapter->rx_ring);
+err_setup_rx:
+ pch_gbe_free_tx_resources(adapter, adapter->tx_ring);
+err_setup_tx:
+ pch_gbe_reset(adapter);
+ pr_err("Error End\n");
+ return err;
+}
+
+/**
+ * pch_gbe_stop - Disables a network interface
+ * @netdev: Network interface device structure
+ * Returns
+ * 0: Successfully
+ */
+static int pch_gbe_stop(struct net_device *netdev)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_hw *hw = &adapter->hw;
+
+ pch_gbe_down(adapter);
+ if (!adapter->wake_up_evt)
+ pch_gbe_hal_power_down_phy(hw);
+ pch_gbe_free_tx_resources(adapter, adapter->tx_ring);
+ pch_gbe_free_rx_resources(adapter, adapter->rx_ring);
+ return 0;
+}
+
+/**
+ * pch_gbe_xmit_frame - Packet transmitting start
+ * @skb: Socket buffer structure
+ * @netdev: Network interface device structure
+ * Returns
+ * - NETDEV_TX_OK: Normal end
+ * - NETDEV_TX_BUSY: Error end
+ */
+static int pch_gbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_tx_ring *tx_ring = adapter->tx_ring;
+ unsigned long flags;
+
+ if (unlikely(skb->len > (adapter->hw.mac.max_frame_size - 4))) {
+ pr_err("Transfer length Error: skb len: %d > max: %d\n",
+ skb->len, adapter->hw.mac.max_frame_size);
+ dev_kfree_skb_any(skb);
+ adapter->stats.tx_length_errors++;
+ return NETDEV_TX_OK;
+ }
+ if (!spin_trylock_irqsave(&tx_ring->tx_lock, flags)) {
+ /* Collision - tell upper layer to requeue */
+ return NETDEV_TX_LOCKED;
+ }
+ if (unlikely(!PCH_GBE_DESC_UNUSED(tx_ring))) {
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+ pr_debug("Return : BUSY next_to use : 0x%08x next_to clean : 0x%08x\n",
+ tx_ring->next_to_use, tx_ring->next_to_clean);
+ return NETDEV_TX_BUSY;
+ }
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+
+ /* CRC,ITAG no support */
+ pch_gbe_tx_queue(adapter, tx_ring, skb);
+ return NETDEV_TX_OK;
+}
+
+/**
+ * pch_gbe_get_stats - Get System Network Statistics
+ * @netdev: Network interface device structure
+ * Returns: The current stats
+ */
+static struct net_device_stats *pch_gbe_get_stats(struct net_device *netdev)
+{
+ /* only return the current stats */
+ return &netdev->stats;
+}
+
+/**
+ * pch_gbe_set_multi - Multicast and Promiscuous mode set
+ * @netdev: Network interface device structure
+ */
+static void pch_gbe_set_multi(struct net_device *netdev)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_hw *hw = &adapter->hw;
+ struct netdev_hw_addr *ha;
+ u8 *mta_list;
+ u32 rctl;
+ int i;
+ int mc_count;
+
+ pr_debug("netdev->flags : 0x%08x\n", netdev->flags);
+
+ /* Check for Promiscuous and All Multicast modes */
+ rctl = ioread32(&hw->reg->RX_MODE);
+ mc_count = netdev_mc_count(netdev);
+ if ((netdev->flags & IFF_PROMISC)) {
+ rctl &= ~PCH_GBE_ADD_FIL_EN;
+ rctl &= ~PCH_GBE_MLT_FIL_EN;
+ } else if ((netdev->flags & IFF_ALLMULTI)) {
+ /* all the multicasting receive permissions */
+ rctl |= PCH_GBE_ADD_FIL_EN;
+ rctl &= ~PCH_GBE_MLT_FIL_EN;
+ } else {
+ if (mc_count >= PCH_GBE_MAR_ENTRIES) {
+ /* all the multicasting receive permissions */
+ rctl |= PCH_GBE_ADD_FIL_EN;
+ rctl &= ~PCH_GBE_MLT_FIL_EN;
+ } else {
+ rctl |= (PCH_GBE_ADD_FIL_EN | PCH_GBE_MLT_FIL_EN);
+ }
+ }
+ iowrite32(rctl, &hw->reg->RX_MODE);
+
+ if (mc_count >= PCH_GBE_MAR_ENTRIES)
+ return;
+ mta_list = kmalloc(mc_count * ETH_ALEN, GFP_ATOMIC);
+ if (!mta_list)
+ return;
+
+ /* The shared function expects a packed array of only addresses. */
+ i = 0;
+ netdev_for_each_mc_addr(ha, netdev) {
+ if (i == mc_count)
+ break;
+ memcpy(mta_list + (i++ * ETH_ALEN), &ha->addr, ETH_ALEN);
+ }
+ pch_gbe_mac_mc_addr_list_update(hw, mta_list, i, 1,
+ PCH_GBE_MAR_ENTRIES);
+ kfree(mta_list);
+
+ pr_debug("RX_MODE reg(check bit31,30 ADD,MLT) : 0x%08x netdev->mc_count : 0x%08x\n",
+ ioread32(&hw->reg->RX_MODE), mc_count);
+}
+
+/**
+ * pch_gbe_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: Network interface device structure
+ * @addr: Pointer to an address structure
+ * Returns
+ * 0: Successfully
+ * -EADDRNOTAVAIL: Failed
+ */
+static int pch_gbe_set_mac(struct net_device *netdev, void *addr)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct sockaddr *skaddr = addr;
+ int ret_val;
+
+ if (!is_valid_ether_addr(skaddr->sa_data)) {
+ ret_val = -EADDRNOTAVAIL;
+ } else {
+ memcpy(netdev->dev_addr, skaddr->sa_data, netdev->addr_len);
+ memcpy(adapter->hw.mac.addr, skaddr->sa_data, netdev->addr_len);
+ pch_gbe_mac_mar_set(&adapter->hw, adapter->hw.mac.addr, 0);
+ ret_val = 0;
+ }
+ pr_debug("ret_val : 0x%08x\n", ret_val);
+ pr_debug("dev_addr : %pM\n", netdev->dev_addr);
+ pr_debug("mac_addr : %pM\n", adapter->hw.mac.addr);
+ pr_debug("MAC_ADR1AB reg : 0x%08x 0x%08x\n",
+ ioread32(&adapter->hw.reg->mac_adr[0].high),
+ ioread32(&adapter->hw.reg->mac_adr[0].low));
+ return ret_val;
+}
+
+/**
+ * pch_gbe_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: Network interface device structure
+ * @new_mtu: New value for maximum frame size
+ * Returns
+ * 0: Successfully
+ * -EINVAL: Failed
+ */
+static int pch_gbe_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ int max_frame;
+
+ max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+ if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
+ (max_frame > PCH_GBE_MAX_JUMBO_FRAME_SIZE)) {
+ pr_err("Invalid MTU setting\n");
+ return -EINVAL;
+ }
+ if (max_frame <= PCH_GBE_FRAME_SIZE_2048)
+ adapter->rx_buffer_len = PCH_GBE_FRAME_SIZE_2048;
+ else if (max_frame <= PCH_GBE_FRAME_SIZE_4096)
+ adapter->rx_buffer_len = PCH_GBE_FRAME_SIZE_4096;
+ 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;
+
+ if (netif_running(netdev))
+ pch_gbe_reinit_locked(adapter);
+ else
+ pch_gbe_reset(adapter);
+
+ 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,
+ adapter->hw.mac.max_frame_size);
+ return 0;
+}
+
+/**
+ * pch_gbe_ioctl - Controls register through a MII interface
+ * @netdev: Network interface device structure
+ * @ifr: Pointer to ifr structure
+ * @cmd: Control command
+ * Returns
+ * 0: Successfully
+ * Negative value: Failed
+ */
+static int pch_gbe_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+
+ pr_debug("cmd : 0x%04x\n", cmd);
+
+ return generic_mii_ioctl(&adapter->mii, if_mii(ifr), cmd, NULL);
+}
+
+/**
+ * pch_gbe_tx_timeout - Respond to a Tx Hang
+ * @netdev: Network interface device structure
+ */
+static void pch_gbe_tx_timeout(struct net_device *netdev)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+
+ /* Do the reset outside of interrupt context */
+ adapter->stats.tx_timeout_count++;
+ schedule_work(&adapter->reset_task);
+}
+
+/**
+ * pch_gbe_napi_poll - NAPI receive and transfer polling callback
+ * @napi: Pointer of polling device struct
+ * @budget: The maximum number of a packet
+ * Returns
+ * false: Exit the polling mode
+ * true: Continue the polling mode
+ */
+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;
+
+ 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);
+
+ 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 (poll_end_flag) {
+ napi_complete(napi);
+ pch_gbe_irq_enable(adapter);
+ }
+
+ pr_debug("poll_end_flag : %d work_done : %d budget : %d\n",
+ poll_end_flag, work_done, budget);
+
+ return work_done;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/**
+ * pch_gbe_netpoll - Used by things like netconsole to send skbs
+ * @netdev: Network interface device structure
+ */
+static void pch_gbe_netpoll(struct net_device *netdev)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+
+ disable_irq(adapter->pdev->irq);
+ pch_gbe_intr(adapter->pdev->irq, netdev);
+ enable_irq(adapter->pdev->irq);
+}
+#endif
+
+static const struct net_device_ops pch_gbe_netdev_ops = {
+ .ndo_open = pch_gbe_open,
+ .ndo_stop = pch_gbe_stop,
+ .ndo_start_xmit = pch_gbe_xmit_frame,
+ .ndo_get_stats = pch_gbe_get_stats,
+ .ndo_set_mac_address = pch_gbe_set_mac,
+ .ndo_tx_timeout = pch_gbe_tx_timeout,
+ .ndo_change_mtu = pch_gbe_change_mtu,
+ .ndo_do_ioctl = pch_gbe_ioctl,
+ .ndo_set_multicast_list = &pch_gbe_set_multi,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = pch_gbe_netpoll,
+#endif
+};
+
+static pci_ers_result_t pch_gbe_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+
+ netif_device_detach(netdev);
+ if (netif_running(netdev))
+ pch_gbe_down(adapter);
+ pci_disable_device(pdev);
+ /* Request a slot slot reset. */
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t pch_gbe_io_slot_reset(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_hw *hw = &adapter->hw;
+
+ if (pci_enable_device(pdev)) {
+ pr_err("Cannot re-enable PCI device after reset\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ pci_set_master(pdev);
+ pci_enable_wake(pdev, PCI_D0, 0);
+ pch_gbe_hal_power_up_phy(hw);
+ pch_gbe_reset(adapter);
+ /* Clear wake up status */
+ pch_gbe_mac_set_wol_event(hw, 0);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void pch_gbe_io_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+
+ if (netif_running(netdev)) {
+ if (pch_gbe_up(adapter)) {
+ pr_debug("can't bring device back up after reset\n");
+ return;
+ }
+ }
+ netif_device_attach(netdev);
+}
+
+static int __pch_gbe_suspend(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_hw *hw = &adapter->hw;
+ u32 wufc = adapter->wake_up_evt;
+ int retval = 0;
+
+ netif_device_detach(netdev);
+ if (netif_running(netdev))
+ pch_gbe_down(adapter);
+ if (wufc) {
+ pch_gbe_set_multi(netdev);
+ pch_gbe_setup_rctl(adapter);
+ pch_gbe_configure_rx(adapter);
+ pch_gbe_set_rgmii_ctrl(adapter, hw->mac.link_speed,
+ hw->mac.link_duplex);
+ pch_gbe_set_mode(adapter, hw->mac.link_speed,
+ hw->mac.link_duplex);
+ pch_gbe_mac_set_wol_event(hw, wufc);
+ pci_disable_device(pdev);
+ } else {
+ pch_gbe_hal_power_down_phy(hw);
+ pch_gbe_mac_set_wol_event(hw, wufc);
+ pci_disable_device(pdev);
+ }
+ return retval;
+}
+
+#ifdef CONFIG_PM
+static int pch_gbe_suspend(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+
+ return __pch_gbe_suspend(pdev);
+}
+
+static int pch_gbe_resume(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ struct pch_gbe_hw *hw = &adapter->hw;
+ u32 err;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ pr_err("Cannot enable PCI device from suspend\n");
+ return err;
+ }
+ pci_set_master(pdev);
+ pch_gbe_hal_power_up_phy(hw);
+ pch_gbe_reset(adapter);
+ /* Clear wake on lan control and status */
+ pch_gbe_mac_set_wol_event(hw, 0);
+
+ if (netif_running(netdev))
+ pch_gbe_up(adapter);
+ netif_device_attach(netdev);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static void pch_gbe_shutdown(struct pci_dev *pdev)
+{
+ __pch_gbe_suspend(pdev);
+ if (system_state == SYSTEM_POWER_OFF) {
+ pci_wake_from_d3(pdev, true);
+ pci_set_power_state(pdev, PCI_D3hot);
+ }
+}
+
+static void pch_gbe_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+
+ flush_scheduled_work();
+ unregister_netdev(netdev);
+
+ pch_gbe_hal_phy_hw_reset(&adapter->hw);
+
+ kfree(adapter->tx_ring);
+ kfree(adapter->rx_ring);
+
+ iounmap(adapter->hw.reg);
+ pci_release_regions(pdev);
+ free_netdev(netdev);
+ pci_disable_device(pdev);
+}
+
+static int pch_gbe_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pci_id)
+{
+ struct net_device *netdev;
+ struct pch_gbe_adapter *adapter;
+ int ret;
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
+ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret) {
+ ret = pci_set_consistent_dma_mask(pdev,
+ DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(&pdev->dev, "ERR: No usable DMA "
+ "configuration, aborting\n");
+ goto err_disable_device;
+ }
+ }
+ }
+
+ ret = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "ERR: Can't reserve PCI I/O and memory resources\n");
+ goto err_disable_device;
+ }
+ pci_set_master(pdev);
+
+ netdev = alloc_etherdev((int)sizeof(struct pch_gbe_adapter));
+ if (!netdev) {
+ ret = -ENOMEM;
+ dev_err(&pdev->dev,
+ "ERR: Can't allocate and set up an Ethernet device\n");
+ goto err_release_pci;
+ }
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ pci_set_drvdata(pdev, netdev);
+ adapter = netdev_priv(netdev);
+ adapter->netdev = netdev;
+ adapter->pdev = pdev;
+ adapter->hw.back = adapter;
+ adapter->hw.reg = pci_iomap(pdev, PCH_GBE_PCI_BAR, 0);
+ if (!adapter->hw.reg) {
+ ret = -EIO;
+ dev_err(&pdev->dev, "Can't ioremap\n");
+ goto err_free_netdev;
+ }
+
+ netdev->netdev_ops = &pch_gbe_netdev_ops;
+ netdev->watchdog_timeo = PCH_GBE_WATCHDOG_PERIOD;
+ netif_napi_add(netdev, &adapter->napi,
+ pch_gbe_napi_poll, PCH_GBE_RX_WEIGHT);
+ netdev->features = NETIF_F_HW_CSUM | NETIF_F_GRO;
+ pch_gbe_set_ethtool_ops(netdev);
+
+ pch_gbe_mac_reset_hw(&adapter->hw);
+
+ /* setup the private structure */
+ ret = pch_gbe_sw_init(adapter);
+ if (ret)
+ goto err_iounmap;
+
+ /* Initialize PHY */
+ ret = pch_gbe_init_phy(adapter);
+ if (ret) {
+ dev_err(&pdev->dev, "PHY initialize error\n");
+ goto err_free_adapter;
+ }
+ pch_gbe_hal_get_bus_info(&adapter->hw);
+
+ /* Read the MAC address. and store to the private data */
+ ret = pch_gbe_hal_read_mac_addr(&adapter->hw);
+ if (ret) {
+ dev_err(&pdev->dev, "MAC address Read Error\n");
+ goto err_free_adapter;
+ }
+
+ memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
+ dev_err(&pdev->dev, "Invalid MAC Address\n");
+ ret = -EIO;
+ goto err_free_adapter;
+ }
+ setup_timer(&adapter->watchdog_timer, pch_gbe_watchdog,
+ (unsigned long)adapter);
+
+ INIT_WORK(&adapter->reset_task, pch_gbe_reset_task);
+
+ pch_gbe_check_options(adapter);
+
+ if (adapter->tx_csum)
+ netdev->features |= NETIF_F_HW_CSUM;
+ else
+ netdev->features &= ~NETIF_F_HW_CSUM;
+
+ /* initialize the wol settings based on the eeprom settings */
+ adapter->wake_up_evt = PCH_GBE_WL_INIT_SETTING;
+ dev_info(&pdev->dev, "MAC address : %pM\n", netdev->dev_addr);
+
+ /* reset the hardware with the new settings */
+ pch_gbe_reset(adapter);
+
+ ret = register_netdev(netdev);
+ if (ret)
+ goto err_free_adapter;
+ /* tell the stack to leave us alone until pch_gbe_open() is called */
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ dev_dbg(&pdev->dev, "OKIsemi(R) PCH Network Connection\n");
+
+ device_set_wakeup_enable(&pdev->dev, 1);
+ return 0;
+
+err_free_adapter:
+ pch_gbe_hal_phy_hw_reset(&adapter->hw);
+ kfree(adapter->tx_ring);
+ kfree(adapter->rx_ring);
+err_iounmap:
+ iounmap(adapter->hw.reg);
+err_free_netdev:
+ free_netdev(netdev);
+err_release_pci:
+ pci_release_regions(pdev);
+err_disable_device:
+ pci_disable_device(pdev);
+ return ret;
+}
+
+static DEFINE_PCI_DEVICE_TABLE(pch_gbe_pcidev_id) = {
+ {.vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_IOH1_GBE,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = (PCI_CLASS_NETWORK_ETHERNET << 8),
+ .class_mask = (0xFFFF00)
+ },
+ /* required last entry */
+ {0}
+};
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops pch_gbe_pm_ops = {
+ .suspend = pch_gbe_suspend,
+ .resume = pch_gbe_resume,
+ .freeze = pch_gbe_suspend,
+ .thaw = pch_gbe_resume,
+ .poweroff = pch_gbe_suspend,
+ .restore = pch_gbe_resume,
+};
+#endif
+
+static struct pci_error_handlers pch_gbe_err_handler = {
+ .error_detected = pch_gbe_io_error_detected,
+ .slot_reset = pch_gbe_io_slot_reset,
+ .resume = pch_gbe_io_resume
+};
+
+static struct pci_driver pch_gbe_pcidev = {
+ .name = KBUILD_MODNAME,
+ .id_table = pch_gbe_pcidev_id,
+ .probe = pch_gbe_probe,
+ .remove = pch_gbe_remove,
+#ifdef CONFIG_PM_OPS
+ .driver.pm = &pch_gbe_pm_ops,
+#endif
+ .shutdown = pch_gbe_shutdown,
+ .err_handler = &pch_gbe_err_handler
+};
+
+
+static int __init pch_gbe_init_module(void)
+{
+ int ret;
+
+ ret = pci_register_driver(&pch_gbe_pcidev);
+ if (copybreak != PCH_GBE_COPYBREAK_DEFAULT) {
+ if (copybreak == 0) {
+ pr_info("copybreak disabled\n");
+ } else {
+ pr_info("copybreak enabled for packets <= %u bytes\n",
+ copybreak);
+ }
+ }
+ return ret;
+}
+
+static void __exit pch_gbe_exit_module(void)
+{
+ pci_unregister_driver(&pch_gbe_pcidev);
+}
+
+module_init(pch_gbe_init_module);
+module_exit(pch_gbe_exit_module);
+
+MODULE_DESCRIPTION("OKI semiconductor PCH Gigabit ethernet Driver");
+MODULE_AUTHOR("OKI semiconductor, <masa-korg@dsn.okisemi.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, pch_gbe_pcidev_id);
+
+module_param(copybreak, uint, 0644);
+MODULE_PARM_DESC(copybreak,
+ "Maximum size of packet that is copied to a new buffer on receive");
+
+/* pch_gbe_main.c */
diff --git a/drivers/net/pch_gbe/pch_gbe_param.c b/drivers/net/pch_gbe/pch_gbe_param.c
new file mode 100644
index 000000000000..2510146fc560
--- /dev/null
+++ b/drivers/net/pch_gbe/pch_gbe_param.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 1999 - 2010 Intel Corporation.
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This code was derived from the Intel e1000e Linux driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "pch_gbe.h"
+
+#define OPTION_UNSET -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED 1
+
+/**
+ * TxDescriptors - Transmit Descriptor Count
+ * @Valid Range: PCH_GBE_MIN_TXD - PCH_GBE_MAX_TXD
+ * @Default Value: PCH_GBE_DEFAULT_TXD
+ */
+static int TxDescriptors = OPTION_UNSET;
+module_param(TxDescriptors, int, 0);
+MODULE_PARM_DESC(TxDescriptors, "Number of transmit descriptors");
+
+/**
+ * RxDescriptors -Receive Descriptor Count
+ * @Valid Range: PCH_GBE_MIN_RXD - PCH_GBE_MAX_RXD
+ * @Default Value: PCH_GBE_DEFAULT_RXD
+ */
+static int RxDescriptors = OPTION_UNSET;
+module_param(RxDescriptors, int, 0);
+MODULE_PARM_DESC(RxDescriptors, "Number of receive descriptors");
+
+/**
+ * Speed - User Specified Speed Override
+ * @Valid Range: 0, 10, 100, 1000
+ * - 0: auto-negotiate at all supported speeds
+ * - 10: only link at 10 Mbps
+ * - 100: only link at 100 Mbps
+ * - 1000: only link at 1000 Mbps
+ * @Default Value: 0
+ */
+static int Speed = OPTION_UNSET;
+module_param(Speed, int, 0);
+MODULE_PARM_DESC(Speed, "Speed setting");
+
+/**
+ * Duplex - User Specified Duplex Override
+ * @Valid Range: 0-2
+ * - 0: auto-negotiate for duplex
+ * - 1: only link at half duplex
+ * - 2: only link at full duplex
+ * @Default Value: 0
+ */
+static int Duplex = OPTION_UNSET;
+module_param(Duplex, int, 0);
+MODULE_PARM_DESC(Duplex, "Duplex setting");
+
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+/**
+ * AutoNeg - Auto-negotiation Advertisement Override
+ * @Valid Range: 0x01-0x0F, 0x20-0x2F
+ *
+ * The AutoNeg value is a bit mask describing which speed and duplex
+ * combinations should be advertised during auto-negotiation.
+ * The supported speed and duplex modes are listed below
+ *
+ * Bit 7 6 5 4 3 2 1 0
+ * Speed (Mbps) N/A N/A 1000 N/A 100 100 10 10
+ * Duplex Full Full Half Full Half
+ *
+ * @Default Value: 0x2F (copper)
+ */
+static int AutoNeg = OPTION_UNSET;
+module_param(AutoNeg, int, 0);
+MODULE_PARM_DESC(AutoNeg, "Advertised auto-negotiation setting");
+
+#define PHY_ADVERTISE_10_HALF 0x0001
+#define PHY_ADVERTISE_10_FULL 0x0002
+#define PHY_ADVERTISE_100_HALF 0x0004
+#define PHY_ADVERTISE_100_FULL 0x0008
+#define PHY_ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */
+#define PHY_ADVERTISE_1000_FULL 0x0020
+#define PCH_AUTONEG_ADVERTISE_DEFAULT 0x2F
+
+/**
+ * FlowControl - User Specified Flow Control Override
+ * @Valid Range: 0-3
+ * - 0: No Flow Control
+ * - 1: Rx only, respond to PAUSE frames but do not generate them
+ * - 2: Tx only, generate PAUSE frames but ignore them on receive
+ * - 3: Full Flow Control Support
+ * @Default Value: Read flow control settings from the EEPROM
+ */
+static int FlowControl = OPTION_UNSET;
+module_param(FlowControl, int, 0);
+MODULE_PARM_DESC(FlowControl, "Flow Control setting");
+
+/*
+ * XsumRX - Receive Checksum Offload Enable/Disable
+ * @Valid Range: 0, 1
+ * - 0: disables all checksum offload
+ * - 1: enables receive IP/TCP/UDP checksum offload
+ * @Default Value: PCH_GBE_DEFAULT_RX_CSUM
+ */
+static int XsumRX = OPTION_UNSET;
+module_param(XsumRX, int, 0);
+MODULE_PARM_DESC(XsumRX, "Disable or enable Receive Checksum offload");
+
+#define PCH_GBE_DEFAULT_RX_CSUM true /* trueorfalse */
+
+/*
+ * XsumTX - Transmit Checksum Offload Enable/Disable
+ * @Valid Range: 0, 1
+ * - 0: disables all checksum offload
+ * - 1: enables transmit IP/TCP/UDP checksum offload
+ * @Default Value: PCH_GBE_DEFAULT_TX_CSUM
+ */
+static int XsumTX = OPTION_UNSET;
+module_param(XsumTX, int, 0);
+MODULE_PARM_DESC(XsumTX, "Disable or enable Transmit Checksum offload");
+
+#define PCH_GBE_DEFAULT_TX_CSUM true /* trueorfalse */
+
+/**
+ * pch_gbe_option - Force the MAC's flow control settings
+ * @hw: Pointer to the HW structure
+ * Returns
+ * 0: Successful.
+ * Negative value: Failed.
+ */
+struct pch_gbe_option {
+ enum { enable_option, range_option, list_option } type;
+ char *name;
+ char *err;
+ int def;
+ union {
+ struct { /* range_option info */
+ int min;
+ int max;
+ } r;
+ struct { /* list_option info */
+ int nr;
+ const struct pch_gbe_opt_list { int i; char *str; } *p;
+ } l;
+ } arg;
+};
+
+static const struct pch_gbe_opt_list speed_list[] = {
+ { 0, "" },
+ { SPEED_10, "" },
+ { SPEED_100, "" },
+ { SPEED_1000, "" }
+};
+
+static const struct pch_gbe_opt_list dplx_list[] = {
+ { 0, "" },
+ { HALF_DUPLEX, "" },
+ { FULL_DUPLEX, "" }
+};
+
+static const struct pch_gbe_opt_list an_list[] =
+ #define AA "AutoNeg advertising "
+ {{ 0x01, AA "10/HD" },
+ { 0x02, AA "10/FD" },
+ { 0x03, AA "10/FD, 10/HD" },
+ { 0x04, AA "100/HD" },
+ { 0x05, AA "100/HD, 10/HD" },
+ { 0x06, AA "100/HD, 10/FD" },
+ { 0x07, AA "100/HD, 10/FD, 10/HD" },
+ { 0x08, AA "100/FD" },
+ { 0x09, AA "100/FD, 10/HD" },
+ { 0x0a, AA "100/FD, 10/FD" },
+ { 0x0b, AA "100/FD, 10/FD, 10/HD" },
+ { 0x0c, AA "100/FD, 100/HD" },
+ { 0x0d, AA "100/FD, 100/HD, 10/HD" },
+ { 0x0e, AA "100/FD, 100/HD, 10/FD" },
+ { 0x0f, AA "100/FD, 100/HD, 10/FD, 10/HD" },
+ { 0x20, AA "1000/FD" },
+ { 0x21, AA "1000/FD, 10/HD" },
+ { 0x22, AA "1000/FD, 10/FD" },
+ { 0x23, AA "1000/FD, 10/FD, 10/HD" },
+ { 0x24, AA "1000/FD, 100/HD" },
+ { 0x25, AA "1000/FD, 100/HD, 10/HD" },
+ { 0x26, AA "1000/FD, 100/HD, 10/FD" },
+ { 0x27, AA "1000/FD, 100/HD, 10/FD, 10/HD" },
+ { 0x28, AA "1000/FD, 100/FD" },
+ { 0x29, AA "1000/FD, 100/FD, 10/HD" },
+ { 0x2a, AA "1000/FD, 100/FD, 10/FD" },
+ { 0x2b, AA "1000/FD, 100/FD, 10/FD, 10/HD" },
+ { 0x2c, AA "1000/FD, 100/FD, 100/HD" },
+ { 0x2d, AA "1000/FD, 100/FD, 100/HD, 10/HD" },
+ { 0x2e, AA "1000/FD, 100/FD, 100/HD, 10/FD" },
+ { 0x2f, AA "1000/FD, 100/FD, 100/HD, 10/FD, 10/HD" }
+};
+
+static const struct pch_gbe_opt_list fc_list[] = {
+ { PCH_GBE_FC_NONE, "Flow Control Disabled" },
+ { PCH_GBE_FC_RX_PAUSE, "Flow Control Receive Only" },
+ { PCH_GBE_FC_TX_PAUSE, "Flow Control Transmit Only" },
+ { PCH_GBE_FC_FULL, "Flow Control Enabled" }
+};
+
+/**
+ * pch_gbe_validate_option - Validate option
+ * @value: value
+ * @opt: option
+ * @adapter: Board private structure
+ * Returns
+ * 0: Successful.
+ * Negative value: Failed.
+ */
+static int pch_gbe_validate_option(int *value,
+ const struct pch_gbe_option *opt,
+ struct pch_gbe_adapter *adapter)
+{
+ if (*value == OPTION_UNSET) {
+ *value = opt->def;
+ return 0;
+ }
+
+ switch (opt->type) {
+ case enable_option:
+ switch (*value) {
+ case OPTION_ENABLED:
+ pr_debug("%s Enabled\n", opt->name);
+ return 0;
+ case OPTION_DISABLED:
+ pr_debug("%s Disabled\n", opt->name);
+ return 0;
+ }
+ break;
+ case range_option:
+ if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
+ pr_debug("%s set to %i\n", opt->name, *value);
+ return 0;
+ }
+ break;
+ case list_option: {
+ int i;
+ const struct pch_gbe_opt_list *ent;
+
+ for (i = 0; i < opt->arg.l.nr; i++) {
+ ent = &opt->arg.l.p[i];
+ if (*value == ent->i) {
+ if (ent->str[0] != '\0')
+ pr_debug("%s\n", ent->str);
+ return 0;
+ }
+ }
+ }
+ break;
+ default:
+ BUG();
+ }
+
+ pr_debug("Invalid %s value specified (%i) %s\n",
+ opt->name, *value, opt->err);
+ *value = opt->def;
+ return -1;
+}
+
+/**
+ * pch_gbe_check_copper_options - Range Checking for Link Options, Copper Version
+ * @adapter: Board private structure
+ */
+static void pch_gbe_check_copper_options(struct pch_gbe_adapter *adapter)
+{
+ struct pch_gbe_hw *hw = &adapter->hw;
+ int speed, dplx;
+
+ { /* Speed */
+ static const struct pch_gbe_option opt = {
+ .type = list_option,
+ .name = "Speed",
+ .err = "parameter ignored",
+ .def = 0,
+ .arg = { .l = { .nr = (int)ARRAY_SIZE(speed_list),
+ .p = speed_list } }
+ };
+ speed = Speed;
+ pch_gbe_validate_option(&speed, &opt, adapter);
+ }
+ { /* Duplex */
+ static const struct pch_gbe_option opt = {
+ .type = list_option,
+ .name = "Duplex",
+ .err = "parameter ignored",
+ .def = 0,
+ .arg = { .l = { .nr = (int)ARRAY_SIZE(dplx_list),
+ .p = dplx_list } }
+ };
+ dplx = Duplex;
+ pch_gbe_validate_option(&dplx, &opt, adapter);
+ }
+
+ { /* Autoneg */
+ static const struct pch_gbe_option opt = {
+ .type = list_option,
+ .name = "AutoNeg",
+ .err = "parameter ignored",
+ .def = PCH_AUTONEG_ADVERTISE_DEFAULT,
+ .arg = { .l = { .nr = (int)ARRAY_SIZE(an_list),
+ .p = an_list} }
+ };
+ if (speed || dplx) {
+ pr_debug("AutoNeg specified along with Speed or Duplex, AutoNeg parameter ignored\n");
+ hw->phy.autoneg_advertised = opt.def;
+ } else {
+ hw->phy.autoneg_advertised = AutoNeg;
+ pch_gbe_validate_option(
+ (int *)(&hw->phy.autoneg_advertised),
+ &opt, adapter);
+ }
+ }
+
+ switch (speed + dplx) {
+ case 0:
+ hw->mac.autoneg = hw->mac.fc_autoneg = 1;
+ if ((speed || dplx))
+ pr_debug("Speed and duplex autonegotiation enabled\n");
+ hw->mac.link_speed = SPEED_10;
+ hw->mac.link_duplex = DUPLEX_HALF;
+ break;
+ case HALF_DUPLEX:
+ pr_debug("Half Duplex specified without Speed\n");
+ pr_debug("Using Autonegotiation at Half Duplex only\n");
+ hw->mac.autoneg = hw->mac.fc_autoneg = 1;
+ hw->phy.autoneg_advertised = PHY_ADVERTISE_10_HALF |
+ PHY_ADVERTISE_100_HALF;
+ hw->mac.link_speed = SPEED_10;
+ hw->mac.link_duplex = DUPLEX_HALF;
+ break;
+ case FULL_DUPLEX:
+ pr_debug("Full Duplex specified without Speed\n");
+ pr_debug("Using Autonegotiation at Full Duplex only\n");
+ hw->mac.autoneg = hw->mac.fc_autoneg = 1;
+ hw->phy.autoneg_advertised = PHY_ADVERTISE_10_FULL |
+ PHY_ADVERTISE_100_FULL |
+ PHY_ADVERTISE_1000_FULL;
+ hw->mac.link_speed = SPEED_10;
+ hw->mac.link_duplex = DUPLEX_FULL;
+ break;
+ case SPEED_10:
+ pr_debug("10 Mbps Speed specified without Duplex\n");
+ pr_debug("Using Autonegotiation at 10 Mbps only\n");
+ hw->mac.autoneg = hw->mac.fc_autoneg = 1;
+ hw->phy.autoneg_advertised = PHY_ADVERTISE_10_HALF |
+ PHY_ADVERTISE_10_FULL;
+ hw->mac.link_speed = SPEED_10;
+ hw->mac.link_duplex = DUPLEX_HALF;
+ break;
+ case SPEED_10 + HALF_DUPLEX:
+ pr_debug("Forcing to 10 Mbps Half Duplex\n");
+ hw->mac.autoneg = hw->mac.fc_autoneg = 0;
+ hw->phy.autoneg_advertised = 0;
+ hw->mac.link_speed = SPEED_10;
+ hw->mac.link_duplex = DUPLEX_HALF;
+ break;
+ case SPEED_10 + FULL_DUPLEX:
+ pr_debug("Forcing to 10 Mbps Full Duplex\n");
+ hw->mac.autoneg = hw->mac.fc_autoneg = 0;
+ hw->phy.autoneg_advertised = 0;
+ hw->mac.link_speed = SPEED_10;
+ hw->mac.link_duplex = DUPLEX_FULL;
+ break;
+ case SPEED_100:
+ pr_debug("100 Mbps Speed specified without Duplex\n");
+ pr_debug("Using Autonegotiation at 100 Mbps only\n");
+ hw->mac.autoneg = hw->mac.fc_autoneg = 1;
+ hw->phy.autoneg_advertised = PHY_ADVERTISE_100_HALF |
+ PHY_ADVERTISE_100_FULL;
+ hw->mac.link_speed = SPEED_100;
+ hw->mac.link_duplex = DUPLEX_HALF;
+ break;
+ case SPEED_100 + HALF_DUPLEX:
+ pr_debug("Forcing to 100 Mbps Half Duplex\n");
+ hw->mac.autoneg = hw->mac.fc_autoneg = 0;
+ hw->phy.autoneg_advertised = 0;
+ hw->mac.link_speed = SPEED_100;
+ hw->mac.link_duplex = DUPLEX_HALF;
+ break;
+ case SPEED_100 + FULL_DUPLEX:
+ pr_debug("Forcing to 100 Mbps Full Duplex\n");
+ hw->mac.autoneg = hw->mac.fc_autoneg = 0;
+ hw->phy.autoneg_advertised = 0;
+ hw->mac.link_speed = SPEED_100;
+ hw->mac.link_duplex = DUPLEX_FULL;
+ break;
+ case SPEED_1000:
+ pr_debug("1000 Mbps Speed specified without Duplex\n");
+ goto full_duplex_only;
+ case SPEED_1000 + HALF_DUPLEX:
+ pr_debug("Half Duplex is not supported at 1000 Mbps\n");
+ /* fall through */
+ case SPEED_1000 + FULL_DUPLEX:
+full_duplex_only:
+ pr_debug("Using Autonegotiation at 1000 Mbps Full Duplex only\n");
+ hw->mac.autoneg = hw->mac.fc_autoneg = 1;
+ hw->phy.autoneg_advertised = PHY_ADVERTISE_1000_FULL;
+ hw->mac.link_speed = SPEED_1000;
+ hw->mac.link_duplex = DUPLEX_FULL;
+ break;
+ default:
+ BUG();
+ }
+}
+
+/**
+ * pch_gbe_check_options - Range Checking for Command Line Parameters
+ * @adapter: Board private structure
+ */
+void pch_gbe_check_options(struct pch_gbe_adapter *adapter)
+{
+ struct pch_gbe_hw *hw = &adapter->hw;
+
+ { /* Transmit Descriptor Count */
+ static const struct pch_gbe_option opt = {
+ .type = range_option,
+ .name = "Transmit Descriptors",
+ .err = "using default of "
+ __MODULE_STRING(PCH_GBE_DEFAULT_TXD),
+ .def = PCH_GBE_DEFAULT_TXD,
+ .arg = { .r = { .min = PCH_GBE_MIN_TXD } },
+ .arg = { .r = { .max = PCH_GBE_MAX_TXD } }
+ };
+ struct pch_gbe_tx_ring *tx_ring = adapter->tx_ring;
+ tx_ring->count = TxDescriptors;
+ pch_gbe_validate_option(&tx_ring->count, &opt, adapter);
+ tx_ring->count = roundup(tx_ring->count,
+ PCH_GBE_TX_DESC_MULTIPLE);
+ }
+ { /* Receive Descriptor Count */
+ static const struct pch_gbe_option opt = {
+ .type = range_option,
+ .name = "Receive Descriptors",
+ .err = "using default of "
+ __MODULE_STRING(PCH_GBE_DEFAULT_RXD),
+ .def = PCH_GBE_DEFAULT_RXD,
+ .arg = { .r = { .min = PCH_GBE_MIN_RXD } },
+ .arg = { .r = { .max = PCH_GBE_MAX_RXD } }
+ };
+ struct pch_gbe_rx_ring *rx_ring = adapter->rx_ring;
+ rx_ring->count = RxDescriptors;
+ pch_gbe_validate_option(&rx_ring->count, &opt, adapter);
+ rx_ring->count = roundup(rx_ring->count,
+ PCH_GBE_RX_DESC_MULTIPLE);
+ }
+ { /* Checksum Offload Enable/Disable */
+ static const struct pch_gbe_option opt = {
+ .type = enable_option,
+ .name = "Checksum Offload",
+ .err = "defaulting to Enabled",
+ .def = PCH_GBE_DEFAULT_RX_CSUM
+ };
+ adapter->rx_csum = XsumRX;
+ pch_gbe_validate_option((int *)(&adapter->rx_csum),
+ &opt, adapter);
+ }
+ { /* Checksum Offload Enable/Disable */
+ static const struct pch_gbe_option opt = {
+ .type = enable_option,
+ .name = "Checksum Offload",
+ .err = "defaulting to Enabled",
+ .def = PCH_GBE_DEFAULT_TX_CSUM
+ };
+ adapter->tx_csum = XsumTX;
+ pch_gbe_validate_option((int *)(&adapter->tx_csum),
+ &opt, adapter);
+ }
+ { /* Flow Control */
+ static const struct pch_gbe_option opt = {
+ .type = list_option,
+ .name = "Flow Control",
+ .err = "reading default settings from EEPROM",
+ .def = PCH_GBE_FC_DEFAULT,
+ .arg = { .l = { .nr = (int)ARRAY_SIZE(fc_list),
+ .p = fc_list } }
+ };
+ hw->mac.fc = FlowControl;
+ pch_gbe_validate_option((int *)(&hw->mac.fc),
+ &opt, adapter);
+ }
+
+ pch_gbe_check_copper_options(adapter);
+}
diff --git a/drivers/net/pch_gbe/pch_gbe_phy.c b/drivers/net/pch_gbe/pch_gbe_phy.c
new file mode 100644
index 000000000000..923a687acd30
--- /dev/null
+++ b/drivers/net/pch_gbe/pch_gbe_phy.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 1999 - 2010 Intel Corporation.
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This code was derived from the Intel e1000e Linux driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "pch_gbe.h"
+#include "pch_gbe_phy.h"
+
+#define PHY_MAX_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CONTROL 0x00 /* Control Register */
+#define PHY_STATUS 0x01 /* Status Regiser */
+#define PHY_ID1 0x02 /* Phy Id Register (word 1) */
+#define PHY_ID2 0x03 /* Phy Id Register (word 2) */
+#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Register */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Register */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Register */
+#define PHY_EXT_STATUS 0x0F /* Extended Status Register */
+#define PHY_PHYSP_CONTROL 0x10 /* PHY Specific Control Register */
+#define PHY_EXT_PHYSP_CONTROL 0x14 /* Extended PHY Specific Control Register */
+#define PHY_LED_CONTROL 0x18 /* LED Control Register */
+#define PHY_EXT_PHYSP_STATUS 0x1B /* Extended PHY Specific Status Register */
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_1000 0x0040
+#define MII_CR_SPEED_100 0x2000
+#define MII_CR_SPEED_10 0x0000
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
+#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
+
+/* Phy Id Register (word 2) */
+#define PHY_REVISION_MASK 0x000F
+
+/* PHY Specific Control Register */
+#define PHYSP_CTRL_ASSERT_CRS_TX 0x0800
+
+
+/* Default value of PHY register */
+#define PHY_CONTROL_DEFAULT 0x1140 /* Control Register */
+#define PHY_AUTONEG_ADV_DEFAULT 0x01e0 /* Autoneg Advertisement */
+#define PHY_NEXT_PAGE_TX_DEFAULT 0x2001 /* Next Page TX */
+#define PHY_1000T_CTRL_DEFAULT 0x0300 /* 1000Base-T Control Register */
+#define PHY_PHYSP_CONTROL_DEFAULT 0x01EE /* PHY Specific Control Register */
+
+/**
+ * pch_gbe_phy_get_id - Retrieve the PHY ID and revision
+ * @hw: Pointer to the HW structure
+ * Returns
+ * 0: Successful.
+ * Negative value: Failed.
+ */
+s32 pch_gbe_phy_get_id(struct pch_gbe_hw *hw)
+{
+ struct pch_gbe_phy_info *phy = &hw->phy;
+ s32 ret;
+ u16 phy_id1;
+ u16 phy_id2;
+
+ ret = pch_gbe_phy_read_reg_miic(hw, PHY_ID1, &phy_id1);
+ if (ret)
+ return ret;
+ ret = pch_gbe_phy_read_reg_miic(hw, PHY_ID2, &phy_id2);
+ if (ret)
+ return ret;
+ /*
+ * PHY_ID1: [bit15-0:ID(21-6)]
+ * PHY_ID2: [bit15-10:ID(5-0)][bit9-4:Model][bit3-0:revision]
+ */
+ phy->id = (u32)phy_id1;
+ phy->id = ((phy->id << 6) | ((phy_id2 & 0xFC00) >> 10));
+ phy->revision = (u32) (phy_id2 & 0x000F);
+ pr_debug("phy->id : 0x%08x phy->revision : 0x%08x\n",
+ phy->id, phy->revision);
+ return 0;
+}
+
+/**
+ * pch_gbe_phy_read_reg_miic - Read MII control register
+ * @hw: Pointer to the HW structure
+ * @offset: Register offset to be read
+ * @data: Pointer to the read data
+ * Returns
+ * 0: Successful.
+ * -EINVAL: Invalid argument.
+ */
+s32 pch_gbe_phy_read_reg_miic(struct pch_gbe_hw *hw, u32 offset, u16 *data)
+{
+ struct pch_gbe_phy_info *phy = &hw->phy;
+
+ if (offset > PHY_MAX_REG_ADDRESS) {
+ pr_err("PHY Address %d is out of range\n", offset);
+ return -EINVAL;
+ }
+ *data = pch_gbe_mac_ctrl_miim(hw, phy->addr, PCH_GBE_HAL_MIIM_READ,
+ offset, (u16)0);
+ return 0;
+}
+
+/**
+ * pch_gbe_phy_write_reg_miic - Write MII control register
+ * @hw: Pointer to the HW structure
+ * @offset: Register offset to be read
+ * @data: data to write to register at offset
+ * Returns
+ * 0: Successful.
+ * -EINVAL: Invalid argument.
+ */
+s32 pch_gbe_phy_write_reg_miic(struct pch_gbe_hw *hw, u32 offset, u16 data)
+{
+ struct pch_gbe_phy_info *phy = &hw->phy;
+
+ if (offset > PHY_MAX_REG_ADDRESS) {
+ pr_err("PHY Address %d is out of range\n", offset);
+ return -EINVAL;
+ }
+ pch_gbe_mac_ctrl_miim(hw, phy->addr, PCH_GBE_HAL_MIIM_WRITE,
+ offset, data);
+ return 0;
+}
+
+/**
+ * pch_gbe_phy_sw_reset - PHY software reset
+ * @hw: Pointer to the HW structure
+ */
+void pch_gbe_phy_sw_reset(struct pch_gbe_hw *hw)
+{
+ u16 phy_ctrl;
+
+ pch_gbe_phy_read_reg_miic(hw, PHY_CONTROL, &phy_ctrl);
+ phy_ctrl |= MII_CR_RESET;
+ pch_gbe_phy_write_reg_miic(hw, PHY_CONTROL, phy_ctrl);
+ udelay(1);
+}
+
+/**
+ * pch_gbe_phy_hw_reset - PHY hardware reset
+ * @hw: Pointer to the HW structure
+ */
+void pch_gbe_phy_hw_reset(struct pch_gbe_hw *hw)
+{
+ pch_gbe_phy_write_reg_miic(hw, PHY_CONTROL, PHY_CONTROL_DEFAULT);
+ pch_gbe_phy_write_reg_miic(hw, PHY_AUTONEG_ADV,
+ PHY_AUTONEG_ADV_DEFAULT);
+ pch_gbe_phy_write_reg_miic(hw, PHY_NEXT_PAGE_TX,
+ PHY_NEXT_PAGE_TX_DEFAULT);
+ pch_gbe_phy_write_reg_miic(hw, PHY_1000T_CTRL, PHY_1000T_CTRL_DEFAULT);
+ pch_gbe_phy_write_reg_miic(hw, PHY_PHYSP_CONTROL,
+ PHY_PHYSP_CONTROL_DEFAULT);
+}
+
+/**
+ * pch_gbe_phy_power_up - restore link in case the phy was powered down
+ * @hw: Pointer to the HW structure
+ */
+void pch_gbe_phy_power_up(struct pch_gbe_hw *hw)
+{
+ u16 mii_reg;
+
+ mii_reg = 0;
+ /* Just clear the power down bit to wake the phy back up */
+ /* according to the manual, the phy will retain its
+ * settings across a power-down/up cycle */
+ pch_gbe_phy_read_reg_miic(hw, PHY_CONTROL, &mii_reg);
+ mii_reg &= ~MII_CR_POWER_DOWN;
+ pch_gbe_phy_write_reg_miic(hw, PHY_CONTROL, mii_reg);
+}
+
+/**
+ * pch_gbe_phy_power_down - Power down PHY
+ * @hw: Pointer to the HW structure
+ */
+void pch_gbe_phy_power_down(struct pch_gbe_hw *hw)
+{
+ u16 mii_reg;
+
+ mii_reg = 0;
+ /* Power down the PHY so no link is implied when interface is down *
+ * The PHY cannot be powered down if any of the following is TRUE *
+ * (a) WoL is enabled
+ * (b) AMT is active
+ */
+ pch_gbe_phy_read_reg_miic(hw, PHY_CONTROL, &mii_reg);
+ mii_reg |= MII_CR_POWER_DOWN;
+ pch_gbe_phy_write_reg_miic(hw, PHY_CONTROL, mii_reg);
+ mdelay(1);
+}
+
+/**
+ * pch_gbe_phy_set_rgmii - RGMII interface setting
+ * @hw: Pointer to the HW structure
+ */
+inline void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw)
+{
+ pch_gbe_phy_sw_reset(hw);
+}
+
+/**
+ * pch_gbe_phy_init_setting - PHY initial setting
+ * @hw: Pointer to the HW structure
+ */
+void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw)
+{
+ struct pch_gbe_adapter *adapter;
+ struct ethtool_cmd cmd;
+ int ret;
+ u16 mii_reg;
+
+ adapter = container_of(hw, struct pch_gbe_adapter, hw);
+ ret = mii_ethtool_gset(&adapter->mii, &cmd);
+ if (ret)
+ pr_err("Error: mii_ethtool_gset\n");
+
+ cmd.speed = hw->mac.link_speed;
+ cmd.duplex = hw->mac.link_duplex;
+ cmd.advertising = hw->phy.autoneg_advertised;
+ cmd.autoneg = hw->mac.autoneg;
+ pch_gbe_phy_write_reg_miic(hw, MII_BMCR, BMCR_RESET);
+ ret = mii_ethtool_sset(&adapter->mii, &cmd);
+ if (ret)
+ pr_err("Error: mii_ethtool_sset\n");
+
+ pch_gbe_phy_sw_reset(hw);
+
+ pch_gbe_phy_read_reg_miic(hw, PHY_PHYSP_CONTROL, &mii_reg);
+ mii_reg |= PHYSP_CTRL_ASSERT_CRS_TX;
+ pch_gbe_phy_write_reg_miic(hw, PHY_PHYSP_CONTROL, mii_reg);
+
+}
diff --git a/drivers/net/pch_gbe/pch_gbe_phy.h b/drivers/net/pch_gbe/pch_gbe_phy.h
new file mode 100644
index 000000000000..03264dc7b5ec
--- /dev/null
+++ b/drivers/net/pch_gbe/pch_gbe_phy.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 1999 - 2010 Intel Corporation.
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This code was derived from the Intel e1000e Linux driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef _PCH_GBE_PHY_H_
+#define _PCH_GBE_PHY_H_
+
+#define PCH_GBE_PHY_REGS_LEN 32
+#define PCH_GBE_PHY_RESET_DELAY_US 10
+#define PCH_GBE_MAC_IFOP_RGMII
+
+s32 pch_gbe_phy_get_id(struct pch_gbe_hw *hw);
+s32 pch_gbe_phy_read_reg_miic(struct pch_gbe_hw *hw, u32 offset, u16 *data);
+s32 pch_gbe_phy_write_reg_miic(struct pch_gbe_hw *hw, u32 offset, u16 data);
+void pch_gbe_phy_sw_reset(struct pch_gbe_hw *hw);
+void pch_gbe_phy_hw_reset(struct pch_gbe_hw *hw);
+void pch_gbe_phy_power_up(struct pch_gbe_hw *hw);
+void pch_gbe_phy_power_down(struct pch_gbe_hw *hw);
+void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw);
+void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw);
+
+#endif /* _PCH_GBE_PHY_H_ */
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index 56f3fc45dbaa..1766dc4f07e1 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -78,7 +78,7 @@ that almost all frames will need to be copied to an alignment buffer.
IVb. References
-http://www.realtek.com.tw/cn/cn.html
+http://www.realtek.com.tw/
http://www.scyld.com/expert/NWay.html
IVc. Errata
@@ -1125,7 +1125,7 @@ static int netdrv_open(struct net_device *dev)
init_timer(&tp->timer);
tp->timer.expires = jiffies + 3 * HZ;
tp->timer.data = (unsigned long) dev;
- tp->timer.function = &netdrv_timer;
+ tp->timer.function = netdrv_timer;
add_timer(&tp->timer);
DPRINTK("EXIT, returning 0\n");
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index ff824e11f0b6..321b12f82645 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -62,13 +62,15 @@ invalid ramWidth is Very Bad.
V. References
http://www.scyld.com/expert/NWay.html
-http://www.national.com/pf/DP/DP83840.html
+http://www.national.com/opf/DP/DP83840A.html
Thanks to Terry Murphy of 3Com for providing development information for
earlier 3Com products.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -83,7 +85,6 @@ earlier 3Com products.
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/ioport.h>
-#include <linux/ethtool.h>
#include <linux/bitops.h>
#include <linux/mii.h>
@@ -237,7 +238,6 @@ static int el3_rx(struct net_device *dev, int worklimit);
static int el3_close(struct net_device *dev);
static void el3_tx_timeout(struct net_device *dev);
static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static const struct ethtool_ops netdev_ethtool_ops;
static void set_rx_mode(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
@@ -283,7 +283,6 @@ static int tc574_probe(struct pcmcia_device *link)
link->config_index = 1;
dev->netdev_ops = &el3_netdev_ops;
- SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
dev->watchdog_timeo = TX_TIMEOUT;
return tc574_config(link);
@@ -359,8 +358,8 @@ static int tc574_config(struct pcmcia_device *link)
for (i = 0; i < 3; i++)
phys_addr[i] = htons(read_eeprom(ioaddr, i + 10));
if (phys_addr[0] == htons(0x6060)) {
- printk(KERN_NOTICE "3c574_cs: IO port conflict at 0x%03lx"
- "-0x%03lx\n", dev->base_addr, dev->base_addr+15);
+ pr_notice("IO port conflict at 0x%03lx-0x%03lx\n",
+ dev->base_addr, dev->base_addr+15);
goto failed;
}
}
@@ -374,7 +373,7 @@ static int tc574_config(struct pcmcia_device *link)
outw(2<<11, ioaddr + RunnerRdCtrl);
mcr = inb(ioaddr + 2);
outw(0<<11, ioaddr + RunnerRdCtrl);
- printk(KERN_INFO " ASIC rev %d,", mcr>>3);
+ pr_info(" ASIC rev %d,", mcr>>3);
EL3WINDOW(3);
config = inl(ioaddr + Wn3_Config);
lp->default_media = (config & Xcvr) >> Xcvr_shift;
@@ -411,7 +410,7 @@ static int tc574_config(struct pcmcia_device *link)
}
}
if (phy > 32) {
- printk(KERN_NOTICE " No MII transceivers found!\n");
+ pr_notice(" No MII transceivers found!\n");
goto failed;
}
i = mdio_read(ioaddr, lp->phys, 16) | 0x40;
@@ -427,18 +426,16 @@ static int tc574_config(struct pcmcia_device *link)
SET_NETDEV_DEV(dev, &link->dev);
if (register_netdev(dev) != 0) {
- printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n");
+ pr_notice("register_netdev() failed\n");
goto failed;
}
- printk(KERN_INFO "%s: %s at io %#3lx, irq %d, "
- "hw_addr %pM.\n",
- dev->name, cardname, dev->base_addr, dev->irq,
- dev->dev_addr);
- printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n",
- 8 << config & Ram_size,
- ram_split[(config & Ram_split) >> Ram_split_shift],
- config & Autoselect ? "autoselect " : "");
+ netdev_info(dev, "%s at io %#3lx, irq %d, hw_addr %pM\n",
+ cardname, dev->base_addr, dev->irq, dev->dev_addr);
+ netdev_info(dev, " %dK FIFO split %s Rx:Tx, %sMII interface.\n",
+ 8 << config & Ram_size,
+ ram_split[(config & Ram_split) >> Ram_split_shift],
+ config & Autoselect ? "autoselect " : "");
return 0;
@@ -479,14 +476,14 @@ static void dump_status(struct net_device *dev)
{
unsigned int ioaddr = dev->base_addr;
EL3WINDOW(1);
- printk(KERN_INFO " irq status %04x, rx status %04x, tx status "
- "%02x, tx free %04x\n", inw(ioaddr+EL3_STATUS),
- inw(ioaddr+RxStatus), inb(ioaddr+TxStatus),
- inw(ioaddr+TxFree));
+ netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x, tx free %04x\n",
+ inw(ioaddr+EL3_STATUS),
+ inw(ioaddr+RxStatus), inb(ioaddr+TxStatus),
+ inw(ioaddr+TxFree));
EL3WINDOW(4);
- printk(KERN_INFO " diagnostics: fifo %04x net %04x ethernet %04x"
- " media %04x\n", inw(ioaddr+0x04), inw(ioaddr+0x06),
- inw(ioaddr+0x08), inw(ioaddr+0x0a));
+ netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %04x\n",
+ inw(ioaddr+0x04), inw(ioaddr+0x06),
+ inw(ioaddr+0x08), inw(ioaddr+0x0a));
EL3WINDOW(1);
}
@@ -500,7 +497,7 @@ static void tc574_wait_for_completion(struct net_device *dev, int cmd)
while (--i > 0)
if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
if (i == 0)
- printk(KERN_NOTICE "%s: command 0x%04x did not complete!\n", dev->name, cmd);
+ netdev_notice(dev, "command 0x%04x did not complete!\n", cmd);
}
/* Read a word from the EEPROM using the regular EEPROM access register.
@@ -687,7 +684,7 @@ static int el3_open(struct net_device *dev)
netif_start_queue(dev);
tc574_reset(dev);
- lp->media.function = &media_check;
+ lp->media.function = media_check;
lp->media.data = (unsigned long) dev;
lp->media.expires = jiffies + HZ;
add_timer(&lp->media);
@@ -702,7 +699,7 @@ static void el3_tx_timeout(struct net_device *dev)
{
unsigned int ioaddr = dev->base_addr;
- printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name);
+ netdev_notice(dev, "Transmit timed out!\n");
dump_status(dev);
dev->stats.tx_errors++;
dev->trans_start = jiffies; /* prevent tx timeout */
@@ -825,8 +822,8 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id)
EL3WINDOW(4);
fifo_diag = inw(ioaddr + Wn4_FIFODiag);
EL3WINDOW(1);
- printk(KERN_NOTICE "%s: adapter failure, FIFO diagnostic"
- " register %04x.\n", dev->name, fifo_diag);
+ netdev_notice(dev, "adapter failure, FIFO diagnostic register %04x\n",
+ fifo_diag);
if (fifo_diag & 0x0400) {
/* Tx overrun */
tc574_wait_for_completion(dev, TxReset);
@@ -880,7 +877,7 @@ static void media_check(unsigned long arg)
this, we can limp along even if the interrupt is blocked */
if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + Timer) == 0xff)) {
if (!lp->fast_poll)
- printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+ netdev_info(dev, "interrupt(s) dropped!\n");
local_irq_save(flags);
el3_interrupt(dev->irq, dev);
@@ -903,23 +900,21 @@ static void media_check(unsigned long arg)
if (media != lp->media_status) {
if ((media ^ lp->media_status) & 0x0004)
- printk(KERN_INFO "%s: %s link beat\n", dev->name,
- (lp->media_status & 0x0004) ? "lost" : "found");
+ netdev_info(dev, "%s link beat\n",
+ (lp->media_status & 0x0004) ? "lost" : "found");
if ((media ^ lp->media_status) & 0x0020) {
lp->partner = 0;
if (lp->media_status & 0x0020) {
- printk(KERN_INFO "%s: autonegotiation restarted\n",
- dev->name);
+ netdev_info(dev, "autonegotiation restarted\n");
} else if (partner) {
partner &= lp->advertising;
lp->partner = partner;
- printk(KERN_INFO "%s: autonegotiation complete: "
- "%sbaseT-%cD selected\n", dev->name,
- ((partner & 0x0180) ? "100" : "10"),
- ((partner & 0x0140) ? 'F' : 'H'));
+ netdev_info(dev, "autonegotiation complete: "
+ "%dbaseT-%cD selected\n",
+ (partner & 0x0180) ? 100 : 10,
+ (partner & 0x0140) ? 'F' : 'H');
} else {
- printk(KERN_INFO "%s: link partner did not autonegotiate\n",
- dev->name);
+ netdev_info(dev, "link partner did not autonegotiate\n");
}
EL3WINDOW(3);
@@ -929,10 +924,9 @@ static void media_check(unsigned long arg)
}
if (media & 0x0010)
- printk(KERN_INFO "%s: remote fault detected\n",
- dev->name);
+ netdev_info(dev, "remote fault detected\n");
if (media & 0x0002)
- printk(KERN_INFO "%s: jabber detected\n", dev->name);
+ netdev_info(dev, "jabber detected\n");
lp->media_status = media;
}
spin_unlock_irqrestore(&lp->window_lock, flags);
@@ -1042,16 +1036,6 @@ static int el3_rx(struct net_device *dev, int worklimit)
return worklimit;
}
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, "3c574_cs");
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
-};
-
/* Provide ioctl() calls to examine the MII xcvr state. */
static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index a07e22295330..79b9ca0dbdb4 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -19,6 +19,8 @@
======================================================================*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define DRV_NAME "3c589_cs"
#define DRV_VERSION "1.162-ac"
@@ -237,7 +239,7 @@ static int tc589_config(struct pcmcia_device *link)
__be16 *phys_addr;
int ret, i, j, multi = 0, fifo;
unsigned int ioaddr;
- char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+ static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
u8 *buf;
size_t len;
@@ -246,8 +248,7 @@ static int tc589_config(struct pcmcia_device *link)
phys_addr = (__be16 *)dev->dev_addr;
/* Is this a 3c562? */
if (link->manf_id != MANFID_3COM)
- printk(KERN_INFO "3c589_cs: hmmm, is this really a "
- "3Com card??\n");
+ dev_info(&link->dev, "hmmm, is this really a 3Com card??\n");
multi = (link->card_id == PRODID_3COM_3C562);
link->io_lines = 16;
@@ -288,8 +289,8 @@ static int tc589_config(struct pcmcia_device *link)
for (i = 0; i < 3; i++)
phys_addr[i] = htons(read_eeprom(ioaddr, i));
if (phys_addr[0] == htons(0x6060)) {
- printk(KERN_ERR "3c589_cs: IO port conflict at 0x%03lx"
- "-0x%03lx\n", dev->base_addr, dev->base_addr+15);
+ dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n",
+ dev->base_addr, dev->base_addr+15);
goto failed;
}
}
@@ -303,12 +304,12 @@ static int tc589_config(struct pcmcia_device *link)
if ((if_port >= 0) && (if_port <= 3))
dev->if_port = if_port;
else
- printk(KERN_ERR "3c589_cs: invalid if_port requested\n");
+ dev_err(&link->dev, "invalid if_port requested\n");
SET_NETDEV_DEV(dev, &link->dev);
if (register_netdev(dev) != 0) {
- printk(KERN_ERR "3c589_cs: register_netdev() failed\n");
+ dev_err(&link->dev, "register_netdev() failed\n");
goto failed;
}
@@ -502,7 +503,7 @@ static int el3_open(struct net_device *dev)
tc589_reset(dev);
init_timer(&lp->media);
- lp->media.function = &media_check;
+ lp->media.function = media_check;
lp->media.data = (unsigned long) dev;
lp->media.expires = jiffies + HZ;
add_timer(&lp->media);
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 9e8b28b271ae..d2e166e29dda 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -24,6 +24,8 @@
======================================================================*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -32,7 +34,6 @@
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
-#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/crc32.h>
@@ -85,7 +86,6 @@ static netdev_tx_t axnet_start_xmit(struct sk_buff *skb,
static struct net_device_stats *get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static void axnet_tx_timeout(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
static irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
static void ei_watchdog(u_long arg);
static void axnet_reset_8390(struct net_device *dev);
@@ -161,7 +161,6 @@ static int axnet_probe(struct pcmcia_device *link)
dev->netdev_ops = &axnet_netdev_ops;
- SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
dev->watchdog_timeo = TX_TIMEOUT;
return axnet_config(link);
@@ -300,8 +299,8 @@ static int axnet_config(struct pcmcia_device *link)
dev->base_addr = link->resource[0]->start;
if (!get_prom(link)) {
- printk(KERN_NOTICE "axnet_cs: this is not an AX88190 card!\n");
- printk(KERN_NOTICE "axnet_cs: use pcnet_cs instead.\n");
+ pr_notice("this is not an AX88190 card!\n");
+ pr_notice("use pcnet_cs instead.\n");
goto failed;
}
@@ -310,10 +309,10 @@ static int axnet_config(struct pcmcia_device *link)
ei_status.tx_start_page = AXNET_START_PG;
ei_status.rx_start_page = AXNET_START_PG + TX_PAGES;
ei_status.stop_page = AXNET_STOP_PG;
- ei_status.reset_8390 = &axnet_reset_8390;
- ei_status.get_8390_hdr = &get_8390_hdr;
- ei_status.block_input = &block_input;
- ei_status.block_output = &block_output;
+ ei_status.reset_8390 = axnet_reset_8390;
+ ei_status.get_8390_hdr = get_8390_hdr;
+ ei_status.block_input = block_input;
+ ei_status.block_output = block_output;
if (inb(dev->base_addr + AXNET_TEST) != 0)
info->flags |= IS_AX88790;
@@ -346,19 +345,18 @@ static int axnet_config(struct pcmcia_device *link)
SET_NETDEV_DEV(dev, &link->dev);
if (register_netdev(dev) != 0) {
- printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n");
+ pr_notice("register_netdev() failed\n");
goto failed;
}
- printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, "
- "hw_addr %pM\n",
- dev->name, ((info->flags & IS_AX88790) ? 7 : 1),
- dev->base_addr, dev->irq,
- dev->dev_addr);
+ netdev_info(dev, "Asix AX88%d90: io %#3lx, irq %d, hw_addr %pM\n",
+ ((info->flags & IS_AX88790) ? 7 : 1),
+ dev->base_addr, dev->irq, dev->dev_addr);
if (info->phy_id != -1) {
- dev_dbg(&link->dev, " MII transceiver at index %d, status %x.\n", info->phy_id, j);
+ netdev_dbg(dev, " MII transceiver at index %d, status %x\n",
+ info->phy_id, j);
} else {
- printk(KERN_NOTICE " No MII transceivers found!\n");
+ netdev_notice(dev, " No MII transceivers found!\n");
}
return 0;
@@ -477,7 +475,7 @@ static int axnet_open(struct net_device *dev)
info->link_status = 0x00;
init_timer(&info->watchdog);
- info->watchdog.function = &ei_watchdog;
+ info->watchdog.function = ei_watchdog;
info->watchdog.data = (u_long)dev;
info->watchdog.expires = jiffies + HZ;
add_timer(&info->watchdog);
@@ -530,8 +528,7 @@ static void axnet_reset_8390(struct net_device *dev)
outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */
if (i == 100)
- printk(KERN_ERR "%s: axnet_reset_8390() did not complete.\n",
- dev->name);
+ netdev_err(dev, "axnet_reset_8390() did not complete\n");
} /* axnet_reset_8390 */
@@ -558,7 +555,7 @@ static void ei_watchdog(u_long arg)
this, we can limp along even if the interrupt is blocked */
if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
if (!info->fast_poll)
- printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+ netdev_info(dev, "interrupt(s) dropped!\n");
ei_irq_wrapper(dev->irq, dev);
info->fast_poll = HZ;
}
@@ -573,7 +570,7 @@ static void ei_watchdog(u_long arg)
goto reschedule;
link = mdio_read(mii_addr, info->phy_id, 1);
if (!link || (link == 0xffff)) {
- printk(KERN_INFO "%s: MII is missing!\n", dev->name);
+ netdev_info(dev, "MII is missing!\n");
info->phy_id = -1;
goto reschedule;
}
@@ -581,18 +578,14 @@ static void ei_watchdog(u_long arg)
link &= 0x0004;
if (link != info->link_status) {
u_short p = mdio_read(mii_addr, info->phy_id, 5);
- printk(KERN_INFO "%s: %s link beat\n", dev->name,
- (link) ? "found" : "lost");
+ netdev_info(dev, "%s link beat\n", link ? "found" : "lost");
if (link) {
info->duplex_flag = (p & 0x0140) ? 0x80 : 0x00;
if (p)
- printk(KERN_INFO "%s: autonegotiation complete: "
- "%sbaseT-%cD selected\n", dev->name,
- ((p & 0x0180) ? "100" : "10"),
- ((p & 0x0140) ? 'F' : 'H'));
+ netdev_info(dev, "autonegotiation complete: %dbaseT-%cD selected\n",
+ (p & 0x0180) ? 100 : 10, (p & 0x0140) ? 'F' : 'H');
else
- printk(KERN_INFO "%s: link partner did not autonegotiate\n",
- dev->name);
+ netdev_info(dev, "link partner did not autonegotiate\n");
AX88190_init(dev, 1);
}
info->link_status = link;
@@ -603,16 +596,6 @@ reschedule:
add_timer(&info->watchdog);
}
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, "axnet_cs");
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
-};
-
/*====================================================================*/
static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -798,9 +781,6 @@ module_exit(exit_axnet_cs);
*/
-static const char version_8390[] = KERN_INFO \
- "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@scyld.com)\n";
-
#include <linux/bitops.h>
#include <asm/irq.h>
#include <linux/fcntl.h>
@@ -947,9 +927,11 @@ static void axnet_tx_timeout(struct net_device *dev)
isr = inb(e8390_base+EN0_ISR);
spin_unlock_irqrestore(&ei_local->page_lock, flags);
- printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
- dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
- (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
+ netdev_printk(KERN_DEBUG, dev,
+ "Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
+ (txsr & ENTSR_ABT) ? "excess collisions." :
+ (isr) ? "lost interrupt?" : "cable problem?",
+ txsr, isr, tickssofar);
if (!isr && !dev->stats.tx_packets)
{
@@ -1019,22 +1001,28 @@ static netdev_tx_t axnet_start_xmit(struct sk_buff *skb,
output_page = ei_local->tx_start_page;
ei_local->tx1 = send_length;
if (ei_debug && ei_local->tx2 > 0)
- printk(KERN_DEBUG "%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
- dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing);
+ netdev_printk(KERN_DEBUG, dev,
+ "idle transmitter tx2=%d, lasttx=%d, txing=%d\n",
+ ei_local->tx2, ei_local->lasttx,
+ ei_local->txing);
}
else if (ei_local->tx2 == 0)
{
output_page = ei_local->tx_start_page + TX_PAGES/2;
ei_local->tx2 = send_length;
if (ei_debug && ei_local->tx1 > 0)
- printk(KERN_DEBUG "%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
- dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing);
+ netdev_printk(KERN_DEBUG, dev,
+ "idle transmitter, tx1=%d, lasttx=%d, txing=%d\n",
+ ei_local->tx1, ei_local->lasttx,
+ ei_local->txing);
}
else
{ /* We should never get here. */
if (ei_debug)
- printk(KERN_DEBUG "%s: No Tx buffers free! tx1=%d tx2=%d last=%d\n",
- dev->name, ei_local->tx1, ei_local->tx2, ei_local->lasttx);
+ netdev_printk(KERN_DEBUG, dev,
+ "No Tx buffers free! tx1=%d tx2=%d last=%d\n",
+ ei_local->tx1, ei_local->tx2,
+ ei_local->lasttx);
ei_local->irqlock = 0;
netif_stop_queue(dev);
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
@@ -1122,23 +1110,26 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id)
spin_lock_irqsave(&ei_local->page_lock, flags);
- if (ei_local->irqlock)
- {
+ if (ei_local->irqlock) {
#if 1 /* This might just be an interrupt for a PCI device sharing this line */
+ const char *msg;
/* The "irqlock" check is only for testing. */
- printk(ei_local->irqlock
- ? "%s: Interrupted while interrupts are masked! isr=%#2x imr=%#2x.\n"
- : "%s: Reentering the interrupt handler! isr=%#2x imr=%#2x.\n",
- dev->name, inb_p(e8390_base + EN0_ISR),
- inb_p(e8390_base + EN0_IMR));
+ if (ei_local->irqlock)
+ msg = "Interrupted while interrupts are masked!";
+ else
+ msg = "Reentering the interrupt handler!";
+ netdev_info(dev, "%s, isr=%#2x imr=%#2x\n",
+ msg,
+ inb_p(e8390_base + EN0_ISR),
+ inb_p(e8390_base + EN0_IMR));
#endif
spin_unlock_irqrestore(&ei_local->page_lock, flags);
return IRQ_NONE;
}
if (ei_debug > 3)
- printk(KERN_DEBUG "%s: interrupt(isr=%#2.2x).\n", dev->name,
- inb_p(e8390_base + EN0_ISR));
+ netdev_printk(KERN_DEBUG, dev, "interrupt(isr=%#2.2x)\n",
+ inb_p(e8390_base + EN0_ISR));
outb_p(0x00, e8390_base + EN0_ISR);
ei_local->irqlock = 1;
@@ -1149,7 +1140,8 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id)
{
if (!netif_running(dev) || (interrupts == 0xff)) {
if (ei_debug > 1)
- printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name);
+ netdev_warn(dev,
+ "interrupt from stopped card\n");
outb_p(interrupts, e8390_base + EN0_ISR);
interrupts = 0;
break;
@@ -1192,11 +1184,12 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id)
{
/* 0xFF is valid for a card removal */
if(interrupts!=0xFF)
- printk(KERN_WARNING "%s: Too much work at interrupt, status %#2.2x\n",
- dev->name, interrupts);
+ netdev_warn(dev, "Too much work at interrupt, status %#2.2x\n",
+ interrupts);
outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
} else {
- printk(KERN_WARNING "%s: unknown interrupt %#2x\n", dev->name, interrupts);
+ netdev_warn(dev, "unknown interrupt %#2x\n",
+ interrupts);
outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
}
}
@@ -1230,18 +1223,19 @@ static void ei_tx_err(struct net_device *dev)
unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
#ifdef VERBOSE_ERROR_DUMP
- printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
+ netdev_printk(KERN_DEBUG, dev,
+ "transmitter error (%#2x):", txsr);
if (txsr & ENTSR_ABT)
- printk("excess-collisions ");
+ pr_cont(" excess-collisions");
if (txsr & ENTSR_ND)
- printk("non-deferral ");
+ pr_cont(" non-deferral");
if (txsr & ENTSR_CRS)
- printk("lost-carrier ");
+ pr_cont(" lost-carrier");
if (txsr & ENTSR_FU)
- printk("FIFO-underrun ");
+ pr_cont(" FIFO-underrun");
if (txsr & ENTSR_CDH)
- printk("lost-heartbeat ");
- printk("\n");
+ pr_cont(" lost-heartbeat");
+ pr_cont("\n");
#endif
if (tx_was_aborted)
@@ -1278,8 +1272,9 @@ static void ei_tx_intr(struct net_device *dev)
if (ei_local->tx1 < 0)
{
if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
- printk(KERN_ERR "%s: bogus last_tx_buffer %d, tx1=%d.\n",
- ei_local->name, ei_local->lasttx, ei_local->tx1);
+ netdev_err(dev, "%s: bogus last_tx_buffer %d, tx1=%d\n",
+ ei_local->name, ei_local->lasttx,
+ ei_local->tx1);
ei_local->tx1 = 0;
if (ei_local->tx2 > 0)
{
@@ -1294,8 +1289,9 @@ static void ei_tx_intr(struct net_device *dev)
else if (ei_local->tx2 < 0)
{
if (ei_local->lasttx != 2 && ei_local->lasttx != -2)
- printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
- ei_local->name, ei_local->lasttx, ei_local->tx2);
+ netdev_info(dev, "%s: bogus last_tx_buffer %d, tx2=%d\n",
+ ei_local->name, ei_local->lasttx,
+ ei_local->tx2);
ei_local->tx2 = 0;
if (ei_local->tx1 > 0)
{
@@ -1308,8 +1304,9 @@ static void ei_tx_intr(struct net_device *dev)
else
ei_local->lasttx = 10, ei_local->txing = 0;
}
-// else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n",
-// dev->name, ei_local->lasttx);
+// else
+// netdev_warn(dev, "unexpected TX-done interrupt, lasttx=%d\n",
+// ei_local->lasttx);
/* Minimize Tx latency: update the statistics after we restart TXing. */
if (status & ENTSR_COL)
@@ -1372,8 +1369,8 @@ static void ei_receive(struct net_device *dev)
is that some clones crash in roughly the same way.
*/
if (ei_debug > 0 && this_frame != ei_local->current_page && (this_frame!=0x0 || rxing_page!=0xFF))
- printk(KERN_ERR "%s: mismatched read page pointers %2x vs %2x.\n",
- dev->name, this_frame, ei_local->current_page);
+ netdev_err(dev, "mismatched read page pointers %2x vs %2x\n",
+ this_frame, ei_local->current_page);
if (this_frame == rxing_page) /* Read all the frames? */
break; /* Done for now */
@@ -1389,9 +1386,10 @@ static void ei_receive(struct net_device *dev)
if (pkt_len < 60 || pkt_len > 1518)
{
if (ei_debug)
- printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
- dev->name, rx_frame.count, rx_frame.status,
- rx_frame.next);
+ netdev_printk(KERN_DEBUG, dev,
+ "bogus packet size: %d, status=%#2x nxpg=%#2x\n",
+ rx_frame.count, rx_frame.status,
+ rx_frame.next);
dev->stats.rx_errors++;
dev->stats.rx_length_errors++;
}
@@ -1403,8 +1401,9 @@ static void ei_receive(struct net_device *dev)
if (skb == NULL)
{
if (ei_debug > 1)
- printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n",
- dev->name, pkt_len);
+ netdev_printk(KERN_DEBUG, dev,
+ "Couldn't allocate a sk_buff of size %d\n",
+ pkt_len);
dev->stats.rx_dropped++;
break;
}
@@ -1424,9 +1423,10 @@ static void ei_receive(struct net_device *dev)
else
{
if (ei_debug)
- printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
- dev->name, rx_frame.status, rx_frame.next,
- rx_frame.count);
+ netdev_printk(KERN_DEBUG, dev,
+ "bogus packet: status=%#2x nxpg=%#2x size=%d\n",
+ rx_frame.status, rx_frame.next,
+ rx_frame.count);
dev->stats.rx_errors++;
/* NB: The NIC counts CRC, frame and missed errors. */
if (pkt_stat & ENRSR_FO)
@@ -1436,8 +1436,8 @@ static void ei_receive(struct net_device *dev)
/* This _should_ never happen: it's here for avoiding bad clones. */
if (next_frame >= ei_local->stop_page) {
- printk("%s: next frame inconsistency, %#2x\n", dev->name,
- next_frame);
+ netdev_info(dev, "next frame inconsistency, %#2x\n",
+ next_frame);
next_frame = ei_local->rx_start_page;
}
ei_local->current_page = next_frame;
@@ -1472,7 +1472,7 @@ static void ei_rx_overrun(struct net_device *dev)
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
if (ei_debug > 1)
- printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name);
+ netdev_printk(KERN_DEBUG, dev, "Receiver overrun\n");
dev->stats.rx_over_errors++;
/*
@@ -1669,7 +1669,7 @@ static void AX88190_init(struct net_device *dev, int startp)
{
outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
- printk(KERN_ERR "Hw. address read/write mismap %d\n",i);
+ netdev_err(dev, "Hw. address read/write mismap %d\n", i);
}
outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
@@ -1706,8 +1706,7 @@ static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
if (inb_p(e8390_base) & E8390_TRANS)
{
- printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n",
- dev->name);
+ netdev_warn(dev, "trigger_send() called with the transmitter busy\n");
return;
}
outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
index b706a7249477..27bfad76fc40 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/pcmcia/com20020_cs.c
@@ -51,23 +51,23 @@
#define VERSION "arcnet: COM20020 PCMCIA support loaded.\n"
-#ifdef DEBUG
static void regdump(struct net_device *dev)
{
+#ifdef DEBUG
int ioaddr = dev->base_addr;
int count;
- printk("com20020 register dump:\n");
+ netdev_dbg(dev, "register dump:\n");
for (count = ioaddr; count < ioaddr + 16; count++)
{
if (!(count % 16))
- printk("\n%04X: ", count);
- printk("%02X ", inb(count));
+ pr_cont("%04X:", count);
+ pr_cont(" %02X", inb(count));
}
- printk("\n");
+ pr_cont("\n");
- printk("buffer0 dump:\n");
+ netdev_dbg(dev, "buffer0 dump:\n");
/* set up the address register */
count = 0;
outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI);
@@ -76,19 +76,15 @@ static void regdump(struct net_device *dev)
for (count = 0; count < 256+32; count++)
{
if (!(count % 16))
- printk("\n%04X: ", count);
+ pr_cont("%04X:", count);
/* copy the data */
- printk("%02X ", inb(_MEMDATA));
+ pr_cont(" %02X", inb(_MEMDATA));
}
- printk("\n");
+ pr_cont("\n");
+#endif
}
-#else
-
-static inline void regdump(struct net_device *dev) { }
-
-#endif
/*====================================================================*/
@@ -274,13 +270,13 @@ static int com20020_config(struct pcmcia_device *link)
i = com20020_found(dev, 0); /* calls register_netdev */
if (i != 0) {
- dev_printk(KERN_NOTICE, &link->dev,
- "com20020_cs: com20020_found() failed\n");
+ dev_notice(&link->dev,
+ "com20020_found() failed\n");
goto failed;
}
- dev_dbg(&link->dev,KERN_INFO "%s: port %#3lx, irq %d\n",
- dev->name, dev->base_addr, dev->irq);
+ netdev_dbg(dev, "port %#3lx, irq %d\n",
+ dev->base_addr, dev->irq);
return 0;
failed:
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 1c327598bbe8..9226cda4d054 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -28,6 +28,8 @@
======================================================================*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define DRV_NAME "fmvj18x_cs"
#define DRV_VERSION "2.9"
@@ -289,7 +291,7 @@ static int mfc_try_io_port(struct pcmcia_device *link)
link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
if (link->resource[1]->start == 0) {
link->resource[1]->end = 0;
- printk(KERN_NOTICE "fmvj18x_cs: out of resource for serial\n");
+ pr_notice("out of resource for serial\n");
}
ret = pcmcia_request_io(link);
if (ret == 0)
@@ -497,7 +499,7 @@ static int fmvj18x_config(struct pcmcia_device *link)
case XXX10304:
/* Read MACID from Buggy CIS */
if (fmvj18x_get_hwinfo(link, buggybuf) == -1) {
- printk(KERN_NOTICE "fmvj18x_cs: unable to read hardware net address.\n");
+ pr_notice("unable to read hardware net address\n");
goto failed;
}
for (i = 0 ; i < 6; i++) {
@@ -518,15 +520,14 @@ static int fmvj18x_config(struct pcmcia_device *link)
SET_NETDEV_DEV(dev, &link->dev);
if (register_netdev(dev) != 0) {
- printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n");
+ pr_notice("register_netdev() failed\n");
goto failed;
}
/* print current configuration */
- printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, "
- "hw_addr %pM\n",
- dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2",
- dev->base_addr, dev->irq, dev->dev_addr);
+ netdev_info(dev, "%s, sram %s, port %#3lx, irq %d, hw_addr %pM\n",
+ card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2",
+ dev->base_addr, dev->irq, dev->dev_addr);
return 0;
@@ -597,7 +598,7 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link)
lp->base = ioremap(link->resource[3]->start,
resource_size(link->resource[3]));
if (lp->base == NULL) {
- printk(KERN_NOTICE "fmvj18x_cs: ioremap failed\n");
+ netdev_notice(dev, "ioremap failed\n");
return -1;
}
@@ -787,17 +788,16 @@ static void fjn_tx_timeout(struct net_device *dev)
struct local_info_t *lp = netdev_priv(dev);
unsigned int ioaddr = dev->base_addr;
- printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
- dev->name, htons(inw(ioaddr + TX_STATUS)),
- inb(ioaddr + TX_STATUS) & F_TMT_RDY
- ? "IRQ conflict" : "network cable problem");
- printk(KERN_NOTICE "%s: timeout registers: %04x %04x %04x "
- "%04x %04x %04x %04x %04x.\n",
- dev->name, htons(inw(ioaddr + 0)),
- htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)),
- htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),
- htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),
- htons(inw(ioaddr +14)));
+ netdev_notice(dev, "transmit timed out with status %04x, %s?\n",
+ htons(inw(ioaddr + TX_STATUS)),
+ inb(ioaddr + TX_STATUS) & F_TMT_RDY
+ ? "IRQ conflict" : "network cable problem");
+ netdev_notice(dev, "timeout registers: %04x %04x %04x "
+ "%04x %04x %04x %04x %04x.\n",
+ htons(inw(ioaddr + 0)), htons(inw(ioaddr + 2)),
+ htons(inw(ioaddr + 4)), htons(inw(ioaddr + 6)),
+ htons(inw(ioaddr + 8)), htons(inw(ioaddr + 10)),
+ htons(inw(ioaddr + 12)), htons(inw(ioaddr + 14)));
dev->stats.tx_errors++;
/* ToDo: We should try to restart the adaptor... */
local_irq_disable();
@@ -832,13 +832,13 @@ static netdev_tx_t fjn_start_xmit(struct sk_buff *skb,
unsigned char *buf = skb->data;
if (length > ETH_FRAME_LEN) {
- printk(KERN_NOTICE "%s: Attempting to send a large packet"
- " (%d bytes).\n", dev->name, length);
+ netdev_notice(dev, "Attempting to send a large packet (%d bytes)\n",
+ length);
return NETDEV_TX_BUSY;
}
- pr_debug("%s: Transmitting a packet of length %lu.\n",
- dev->name, (unsigned long)skb->len);
+ netdev_dbg(dev, "Transmitting a packet of length %lu\n",
+ (unsigned long)skb->len);
dev->stats.tx_bytes += skb->len;
/* Disable both interrupts. */
@@ -891,7 +891,7 @@ static void fjn_reset(struct net_device *dev)
unsigned int ioaddr = dev->base_addr;
int i;
- pr_debug("fjn_reset(%s) called.\n",dev->name);
+ netdev_dbg(dev, "fjn_reset() called\n");
/* Reset controller */
if( sram_config == 0 )
@@ -975,8 +975,8 @@ static void fjn_rx(struct net_device *dev)
while ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
u_short status = inw(ioaddr + DATAPORT);
- pr_debug("%s: Rxing packet mode %02x status %04x.\n",
- dev->name, inb(ioaddr + RX_MODE), status);
+ netdev_dbg(dev, "Rxing packet mode %02x status %04x.\n",
+ inb(ioaddr + RX_MODE), status);
#ifndef final_version
if (status == 0) {
outb(F_SKP_PKT, ioaddr + RX_SKIP);
@@ -995,16 +995,16 @@ static void fjn_rx(struct net_device *dev)
struct sk_buff *skb;
if (pkt_len > 1550) {
- printk(KERN_NOTICE "%s: The FMV-18x claimed a very "
- "large packet, size %d.\n", dev->name, pkt_len);
+ netdev_notice(dev, "The FMV-18x claimed a very large packet, size %d\n",
+ pkt_len);
outb(F_SKP_PKT, ioaddr + RX_SKIP);
dev->stats.rx_errors++;
break;
}
skb = dev_alloc_skb(pkt_len+2);
if (skb == NULL) {
- printk(KERN_NOTICE "%s: Memory squeeze, dropping "
- "packet (len %d).\n", dev->name, pkt_len);
+ netdev_notice(dev, "Memory squeeze, dropping packet (len %d)\n",
+ pkt_len);
outb(F_SKP_PKT, ioaddr + RX_SKIP);
dev->stats.rx_dropped++;
break;
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
index bf7dff96d881..15d57f5b6f29 100644
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -45,6 +45,8 @@
======================================================================*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ptrace.h>
@@ -52,7 +54,6 @@
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/module.h>
-#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/trdevice.h>
#include <linux/ibmtr.h>
@@ -105,16 +106,6 @@ typedef struct ibmtr_dev_t {
struct tok_info *ti;
} ibmtr_dev_t;
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, "ibmtr_cs");
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
-};
-
static irqreturn_t ibmtr_interrupt(int irq, void *dev_id) {
ibmtr_dev_t *info = dev_id;
struct net_device *dev = info->dev;
@@ -148,8 +139,6 @@ static int __devinit ibmtr_attach(struct pcmcia_device *link)
info->dev = dev;
- SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
-
return ibmtr_config(link);
} /* ibmtr_attach */
@@ -256,15 +245,14 @@ static int __devinit ibmtr_config(struct pcmcia_device *link)
i = ibmtr_probe_card(dev);
if (i != 0) {
- printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n");
+ pr_notice("register_netdev() failed\n");
goto failed;
}
- printk(KERN_INFO
- "%s: port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM\n",
- dev->name, dev->base_addr, dev->irq,
- (u_long)ti->mmio, (u_long)(ti->sram_base << 12),
- dev->dev_addr);
+ netdev_info(dev, "port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM\n",
+ dev->base_addr, dev->irq,
+ (u_long)ti->mmio, (u_long)(ti->sram_base << 12),
+ dev->dev_addr);
return 0;
failed:
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 1eca4f5a6e78..0a2b0f9cdf33 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -111,6 +111,8 @@ Log: nmclan_cs.c,v
---------------------------------------------------------------------------- */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define DRV_NAME "nmclan_cs"
#define DRV_VERSION "0.16"
@@ -502,7 +504,7 @@ static int mace_read(mace_private *lp, unsigned int ioaddr, int reg)
spin_unlock_irqrestore(&lp->bank_lock, flags);
break;
}
- return (data & 0xFF);
+ return data & 0xFF;
} /* mace_read */
/* ----------------------------------------------------------------------------
@@ -546,7 +548,7 @@ static int mace_init(mace_private *lp, unsigned int ioaddr, char *enet_addr)
/* Wait for reset bit to be cleared automatically after <= 200ns */;
if(++ct > 500)
{
- printk(KERN_ERR "mace: reset failed, card removed ?\n");
+ pr_err("reset failed, card removed?\n");
return -1;
}
udelay(1);
@@ -593,7 +595,7 @@ static int mace_init(mace_private *lp, unsigned int ioaddr, char *enet_addr)
{
if(++ ct > 500)
{
- printk(KERN_ERR "mace: ADDRCHG timeout, card removed ?\n");
+ pr_err("ADDRCHG timeout, card removed?\n");
return -1;
}
}
@@ -654,8 +656,8 @@ static int nmclan_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "nmclan_cs configured: mace id=%x %x\n",
sig[0], sig[1]);
} else {
- printk(KERN_NOTICE "nmclan_cs: mace id not found: %x %x should"
- " be 0x40 0x?9\n", sig[0], sig[1]);
+ pr_notice("mace id not found: %x %x should be 0x40 0x?9\n",
+ sig[0], sig[1]);
return -ENODEV;
}
}
@@ -667,20 +669,18 @@ static int nmclan_config(struct pcmcia_device *link)
if (if_port <= 2)
dev->if_port = if_port;
else
- printk(KERN_NOTICE "nmclan_cs: invalid if_port requested\n");
+ pr_notice("invalid if_port requested\n");
SET_NETDEV_DEV(dev, &link->dev);
i = register_netdev(dev);
if (i != 0) {
- printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n");
+ pr_notice("register_netdev() failed\n");
goto failed;
}
- printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port,"
- " hw_addr %pM\n",
- dev->name, dev->base_addr, dev->irq, if_names[dev->if_port],
- dev->dev_addr);
+ netdev_info(dev, "nmclan: port %#3lx, irq %d, %s port, hw_addr %pM\n",
+ dev->base_addr, dev->irq, if_names[dev->if_port], dev->dev_addr);
return 0;
failed:
@@ -768,8 +768,7 @@ static int mace_config(struct net_device *dev, struct ifmap *map)
if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
if (map->port <= 2) {
dev->if_port = map->port;
- printk(KERN_INFO "%s: switched to %s port\n", dev->name,
- if_names[dev->if_port]);
+ netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
} else
return -EINVAL;
}
@@ -848,12 +847,12 @@ static void mace_tx_timeout(struct net_device *dev)
mace_private *lp = netdev_priv(dev);
struct pcmcia_device *link = lp->p_dev;
- printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name);
+ netdev_notice(dev, "transmit timed out -- ");
#if RESET_ON_TIMEOUT
- printk("resetting card\n");
+ pr_cont("resetting card\n");
pcmcia_reset_card(link->socket);
#else /* #if RESET_ON_TIMEOUT */
- printk("NOT resetting card\n");
+ pr_cont("NOT resetting card\n");
#endif /* #if RESET_ON_TIMEOUT */
dev->trans_start = jiffies; /* prevent tx timeout */
netif_wake_queue(dev);
@@ -935,22 +934,21 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
ioaddr = dev->base_addr;
if (lp->tx_irq_disabled) {
- printk(
- (lp->tx_irq_disabled?
- KERN_NOTICE "%s: Interrupt with tx_irq_disabled "
- "[isr=%02X, imr=%02X]\n":
- KERN_NOTICE "%s: Re-entering the interrupt handler "
- "[isr=%02X, imr=%02X]\n"),
- dev->name,
- inb(ioaddr + AM2150_MACE_BASE + MACE_IR),
- inb(ioaddr + AM2150_MACE_BASE + MACE_IMR)
- );
+ const char *msg;
+ if (lp->tx_irq_disabled)
+ msg = "Interrupt with tx_irq_disabled";
+ else
+ msg = "Re-entering the interrupt handler";
+ netdev_notice(dev, "%s [isr=%02X, imr=%02X]\n",
+ msg,
+ inb(ioaddr + AM2150_MACE_BASE + MACE_IR),
+ inb(ioaddr + AM2150_MACE_BASE + MACE_IMR));
/* WARNING: MACE_IR has been read! */
return IRQ_NONE;
}
if (!netif_device_present(dev)) {
- pr_debug("%s: interrupt from dead card\n", dev->name);
+ netdev_dbg(dev, "interrupt from dead card\n");
return IRQ_NONE;
}
@@ -1348,8 +1346,8 @@ static void BuildLAF(int *ladrf, int *adr)
printk(KERN_DEBUG " adr =%pM\n", adr);
printk(KERN_DEBUG " hashcode = %d(decimal), ladrf[0:63] =", hashcode);
for (i = 0; i < 8; i++)
- printk(KERN_CONT " %02X", ladrf[i]);
- printk(KERN_CONT "\n");
+ pr_cont(" %02X", ladrf[i]);
+ pr_cont("\n");
#endif
} /* BuildLAF */
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 5d7d1d3088ae..03096c80103d 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -28,6 +28,8 @@
======================================================================*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -35,7 +37,6 @@
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/delay.h>
-#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/log2.h>
#include <linux/etherdevice.h>
@@ -99,7 +100,6 @@ static void pcnet_release(struct pcmcia_device *link);
static int pcnet_open(struct net_device *dev);
static int pcnet_close(struct net_device *dev);
static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static const struct ethtool_ops netdev_ethtool_ops;
static irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
static void ei_watchdog(u_long arg);
static void pcnet_reset_8390(struct net_device *dev);
@@ -415,8 +415,6 @@ static hw_info_t *get_ax88190(struct pcmcia_device *link)
dev->dev_addr[i] = j & 0xff;
dev->dev_addr[i+1] = j >> 8;
}
- printk(KERN_NOTICE "pcnet_cs: this is an AX88190 card!\n");
- printk(KERN_NOTICE "pcnet_cs: use axnet_cs instead.\n");
return NULL;
}
@@ -604,9 +602,7 @@ static int pcnet_config(struct pcmcia_device *link)
ei_status.name = "NE2000";
ei_status.word16 = 1;
- ei_status.reset_8390 = &pcnet_reset_8390;
-
- SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
+ ei_status.reset_8390 = pcnet_reset_8390;
if (info->flags & (IS_DL10019|IS_DL10022))
mii_phy_probe(dev);
@@ -614,25 +610,25 @@ static int pcnet_config(struct pcmcia_device *link)
SET_NETDEV_DEV(dev, &link->dev);
if (register_netdev(dev) != 0) {
- printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n");
+ pr_notice("register_netdev() failed\n");
goto failed;
}
if (info->flags & (IS_DL10019|IS_DL10022)) {
u_char id = inb(dev->base_addr + 0x1a);
- printk(KERN_INFO "%s: NE2000 (DL100%d rev %02x): ",
- dev->name, ((info->flags & IS_DL10022) ? 22 : 19), id);
+ netdev_info(dev, "NE2000 (DL100%d rev %02x): ",
+ (info->flags & IS_DL10022) ? 22 : 19, id);
if (info->pna_phy)
- printk("PNA, ");
+ pr_cont("PNA, ");
} else {
- printk(KERN_INFO "%s: NE2000 Compatible: ", dev->name);
+ netdev_info(dev, "NE2000 Compatible: ");
}
- printk("io %#3lx, irq %d,", dev->base_addr, dev->irq);
+ pr_cont("io %#3lx, irq %d,", dev->base_addr, dev->irq);
if (info->flags & USE_SHMEM)
- printk (" mem %#5lx,", dev->mem_start);
+ pr_cont(" mem %#5lx,", dev->mem_start);
if (info->flags & HAS_MISC_REG)
- printk(" %s xcvr,", if_names[dev->if_port]);
- printk(" hw_addr %pM\n", dev->dev_addr);
+ pr_cont(" %s xcvr,", if_names[dev->if_port]);
+ pr_cont(" hw_addr %pM\n", dev->dev_addr);
return 0;
failed:
@@ -889,7 +885,7 @@ static void mii_phy_probe(struct net_device *dev)
phyid = tmp << 16;
phyid |= mdio_read(mii_addr, i, MII_PHYID_REG2);
phyid &= MII_PHYID_REV_MASK;
- pr_debug("%s: MII at %d is 0x%08x\n", dev->name, i, phyid);
+ netdev_dbg(dev, "MII at %d is 0x%08x\n", i, phyid);
if (phyid == AM79C9XX_HOME_PHY) {
info->pna_phy = i;
} else if (phyid != AM79C9XX_ETH_PHY) {
@@ -922,7 +918,7 @@ static int pcnet_open(struct net_device *dev)
info->phy_id = info->eth_phy;
info->link_status = 0x00;
init_timer(&info->watchdog);
- info->watchdog.function = &ei_watchdog;
+ info->watchdog.function = ei_watchdog;
info->watchdog.data = (u_long)dev;
info->watchdog.expires = jiffies + HZ;
add_timer(&info->watchdog);
@@ -975,8 +971,8 @@ static void pcnet_reset_8390(struct net_device *dev)
outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */
if (i == 100)
- printk(KERN_ERR "%s: pcnet_reset_8390() did not complete.\n",
- dev->name);
+ netdev_err(dev, "pcnet_reset_8390() did not complete.\n");
+
set_misc_reg(dev);
} /* pcnet_reset_8390 */
@@ -992,8 +988,7 @@ static int set_config(struct net_device *dev, struct ifmap *map)
else if ((map->port < 1) || (map->port > 2))
return -EINVAL;
dev->if_port = map->port;
- printk(KERN_INFO "%s: switched to %s port\n",
- dev->name, if_names[dev->if_port]);
+ netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
NS8390_init(dev, 1);
}
return 0;
@@ -1028,7 +1023,7 @@ static void ei_watchdog(u_long arg)
this, we can limp along even if the interrupt is blocked */
if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
if (!info->fast_poll)
- printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+ netdev_info(dev, "interrupt(s) dropped!\n");
ei_irq_wrapper(dev->irq, dev);
info->fast_poll = HZ;
}
@@ -1048,7 +1043,7 @@ static void ei_watchdog(u_long arg)
if (info->eth_phy) {
info->phy_id = info->eth_phy = 0;
} else {
- printk(KERN_INFO "%s: MII is missing!\n", dev->name);
+ netdev_info(dev, "MII is missing!\n");
info->flags &= ~HAS_MII;
}
goto reschedule;
@@ -1057,8 +1052,7 @@ static void ei_watchdog(u_long arg)
link &= 0x0004;
if (link != info->link_status) {
u_short p = mdio_read(mii_addr, info->phy_id, 5);
- printk(KERN_INFO "%s: %s link beat\n", dev->name,
- (link) ? "found" : "lost");
+ netdev_info(dev, "%s link beat\n", link ? "found" : "lost");
if (link && (info->flags & IS_DL10022)) {
/* Disable collision detection on full duplex links */
outb((p & 0x0140) ? 4 : 0, nic_base + DLINK_DIAG);
@@ -1069,13 +1063,12 @@ static void ei_watchdog(u_long arg)
if (link) {
if (info->phy_id == info->eth_phy) {
if (p)
- printk(KERN_INFO "%s: autonegotiation complete: "
- "%sbaseT-%cD selected\n", dev->name,
+ netdev_info(dev, "autonegotiation complete: "
+ "%sbaseT-%cD selected\n",
((p & 0x0180) ? "100" : "10"),
((p & 0x0140) ? 'F' : 'H'));
else
- printk(KERN_INFO "%s: link partner did not "
- "autonegotiate\n", dev->name);
+ netdev_info(dev, "link partner did not autonegotiate\n");
}
NS8390_init(dev, 1);
}
@@ -1088,7 +1081,7 @@ static void ei_watchdog(u_long arg)
/* isolate this MII and try flipping to the other one */
mdio_write(mii_addr, info->phy_id, 0, 0x0400);
info->phy_id ^= info->pna_phy ^ info->eth_phy;
- printk(KERN_INFO "%s: switched to %s transceiver\n", dev->name,
+ netdev_info(dev, "switched to %s transceiver\n",
(info->phy_id == info->eth_phy) ? "ethernet" : "PNA");
mdio_write(mii_addr, info->phy_id, 0,
(info->phy_id == info->eth_phy) ? 0x1000 : 0);
@@ -1104,18 +1097,6 @@ reschedule:
/*====================================================================*/
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, "pcnet_cs");
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
-};
-
-/*====================================================================*/
-
static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
@@ -1148,9 +1129,9 @@ static void dma_get_8390_hdr(struct net_device *dev,
unsigned int nic_base = dev->base_addr;
if (ei_status.dmaing) {
- printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input."
+ netdev_notice(dev, "DMAing conflict in dma_block_input."
"[DMAstat:%1x][irqlock:%1x]\n",
- dev->name, ei_status.dmaing, ei_status.irqlock);
+ ei_status.dmaing, ei_status.irqlock);
return;
}
@@ -1181,11 +1162,11 @@ static void dma_block_input(struct net_device *dev, int count,
char *buf = skb->data;
if ((ei_debug > 4) && (count != 4))
- pr_debug("%s: [bi=%d]\n", dev->name, count+4);
+ netdev_dbg(dev, "[bi=%d]\n", count+4);
if (ei_status.dmaing) {
- printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input."
+ netdev_notice(dev, "DMAing conflict in dma_block_input."
"[DMAstat:%1x][irqlock:%1x]\n",
- dev->name, ei_status.dmaing, ei_status.irqlock);
+ ei_status.dmaing, ei_status.irqlock);
return;
}
ei_status.dmaing |= 0x01;
@@ -1215,9 +1196,9 @@ static void dma_block_input(struct net_device *dev, int count,
break;
} while (--tries > 0);
if (tries <= 0)
- printk(KERN_NOTICE "%s: RX transfer address mismatch,"
+ netdev_notice(dev, "RX transfer address mismatch,"
"%#4.4x (expected) vs. %#4.4x (actual).\n",
- dev->name, ring_offset + xfer_count, addr);
+ ring_offset + xfer_count, addr);
}
#endif
outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
@@ -1238,7 +1219,7 @@ static void dma_block_output(struct net_device *dev, int count,
#ifdef PCMCIA_DEBUG
if (ei_debug > 4)
- printk(KERN_DEBUG "%s: [bo=%d]\n", dev->name, count);
+ netdev_dbg(dev, "[bo=%d]\n", count);
#endif
/* Round the count up for word writes. Do we need to do this?
@@ -1247,9 +1228,9 @@ static void dma_block_output(struct net_device *dev, int count,
if (count & 0x01)
count++;
if (ei_status.dmaing) {
- printk(KERN_NOTICE "%s: DMAing conflict in dma_block_output."
+ netdev_notice(dev, "DMAing conflict in dma_block_output."
"[DMAstat:%1x][irqlock:%1x]\n",
- dev->name, ei_status.dmaing, ei_status.irqlock);
+ ei_status.dmaing, ei_status.irqlock);
return;
}
ei_status.dmaing |= 0x01;
@@ -1286,9 +1267,9 @@ static void dma_block_output(struct net_device *dev, int count,
break;
} while (--tries > 0);
if (tries <= 0) {
- printk(KERN_NOTICE "%s: Tx packet transfer address mismatch,"
+ netdev_notice(dev, "Tx packet transfer address mismatch,"
"%#4.4x (expected) vs. %#4.4x (actual).\n",
- dev->name, (start_page << 8) + count, addr);
+ (start_page << 8) + count, addr);
if (retries++ == 0)
goto retry;
}
@@ -1297,8 +1278,7 @@ static void dma_block_output(struct net_device *dev, int count,
while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
if (time_after(jiffies, dma_start + PCNET_RDC_TIMEOUT)) {
- printk(KERN_NOTICE "%s: timeout waiting for Tx RDC.\n",
- dev->name);
+ netdev_notice(dev, "timeout waiting for Tx RDC.\n");
pcnet_reset_8390(dev);
NS8390_init(dev, 1);
break;
@@ -1322,9 +1302,9 @@ static int setup_dma_config(struct pcmcia_device *link, int start_pg,
ei_status.stop_page = stop_pg;
/* set up block i/o functions */
- ei_status.get_8390_hdr = &dma_get_8390_hdr;
- ei_status.block_input = &dma_block_input;
- ei_status.block_output = &dma_block_output;
+ ei_status.get_8390_hdr = dma_get_8390_hdr;
+ ei_status.block_input = dma_block_input;
+ ei_status.block_output = dma_block_output;
return 0;
}
@@ -1470,9 +1450,9 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
(resource_size(link->resource[3]) - offset) >> 8);
/* set up block i/o functions */
- ei_status.get_8390_hdr = &shmem_get_8390_hdr;
- ei_status.block_input = &shmem_block_input;
- ei_status.block_output = &shmem_block_output;
+ ei_status.get_8390_hdr = shmem_get_8390_hdr;
+ ei_status.block_input = shmem_block_input;
+ ei_status.block_output = shmem_block_output;
info->flags |= USE_SHMEM;
return 0;
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 0af2fc8ec164..8a9ff5318923 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -25,6 +25,8 @@
======================================================================*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -293,7 +295,7 @@ static const struct net_device_ops smc_netdev_ops = {
.ndo_tx_timeout = smc_tx_timeout,
.ndo_set_config = s9k_config,
.ndo_set_multicast_list = set_rx_mode,
- .ndo_do_ioctl = &smc_ioctl,
+ .ndo_do_ioctl = smc_ioctl,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
@@ -788,11 +790,11 @@ static int check_sig(struct pcmcia_device *link)
((s >> 8) != (s & 0xff))) {
SMC_SELECT_BANK(3);
s = inw(ioaddr + REVISION);
- return (s & 0xff);
+ return s & 0xff;
}
if (width) {
- printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n");
+ pr_info("using 8-bit IO window\n");
smc91c92_suspend(link);
pcmcia_fixup_iowidth(link);
@@ -845,7 +847,7 @@ static int smc91c92_config(struct pcmcia_device *link)
if ((if_port >= 0) && (if_port <= 2))
dev->if_port = if_port;
else
- printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n");
+ dev_notice(&link->dev, "invalid if_port requested\n");
switch (smc->manfid) {
case MANFID_OSITECH:
@@ -863,7 +865,7 @@ static int smc91c92_config(struct pcmcia_device *link)
}
if (i != 0) {
- printk(KERN_NOTICE "smc91c92_cs: Unable to find hardware address.\n");
+ dev_notice(&link->dev, "Unable to find hardware address.\n");
goto config_failed;
}
@@ -916,30 +918,28 @@ static int smc91c92_config(struct pcmcia_device *link)
SET_NETDEV_DEV(dev, &link->dev);
if (register_netdev(dev) != 0) {
- printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
+ dev_err(&link->dev, "register_netdev() failed\n");
goto config_undo;
}
- printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "
- "hw_addr %pM\n",
- dev->name, name, (rev & 0x0f), dev->base_addr, dev->irq,
- dev->dev_addr);
+ netdev_info(dev, "smc91c%s rev %d: io %#3lx, irq %d, hw_addr %pM\n",
+ name, (rev & 0x0f), dev->base_addr, dev->irq, dev->dev_addr);
if (rev > 0) {
if (mir & 0x3ff)
- printk(KERN_INFO " %lu byte", mir);
+ netdev_info(dev, " %lu byte", mir);
else
- printk(KERN_INFO " %lu kb", mir>>10);
- printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ?
- "MII" : if_names[dev->if_port]);
+ netdev_info(dev, " %lu kb", mir>>10);
+ pr_cont(" buffer, %s xcvr\n",
+ (smc->cfg & CFG_MII_SELECT) ? "MII" : if_names[dev->if_port]);
}
if (smc->cfg & CFG_MII_SELECT) {
if (smc->mii_if.phy_id != -1) {
- dev_dbg(&link->dev, " MII transceiver at index %d, status %x.\n",
- smc->mii_if.phy_id, j);
+ netdev_dbg(dev, " MII transceiver at index %d, status %x\n",
+ smc->mii_if.phy_id, j);
} else {
- printk(KERN_NOTICE " No MII transceivers found!\n");
+ netdev_notice(dev, " No MII transceivers found!\n");
}
}
return 0;
@@ -1037,10 +1037,10 @@ static void smc_dump(struct net_device *dev)
save = inw(ioaddr + BANK_SELECT);
for (w = 0; w < 4; w++) {
SMC_SELECT_BANK(w);
- printk(KERN_DEBUG "bank %d: ", w);
+ netdev_printk(KERN_DEBUG, dev, "bank %d: ", w);
for (i = 0; i < 14; i += 2)
- printk(" %04x", inw(ioaddr + i));
- printk("\n");
+ pr_cont(" %04x", inw(ioaddr + i));
+ pr_cont("\n");
}
outw(save, ioaddr + BANK_SELECT);
}
@@ -1062,7 +1062,7 @@ static int smc_open(struct net_device *dev)
return -ENODEV;
/* Physical device present signature. */
if (check_sig(link) < 0) {
- printk("smc91c92_cs: Yikes! Bad chip signature!\n");
+ netdev_info(dev, "Yikes! Bad chip signature!\n");
return -ENODEV;
}
link->open++;
@@ -1073,7 +1073,7 @@ static int smc_open(struct net_device *dev)
smc_reset(dev);
init_timer(&smc->media);
- smc->media.function = &media_check;
+ smc->media.function = media_check;
smc->media.data = (u_long) dev;
smc->media.expires = jiffies + HZ;
add_timer(&smc->media);
@@ -1128,7 +1128,7 @@ static void smc_hardware_send_packet(struct net_device * dev)
u_char packet_no;
if (!skb) {
- printk(KERN_ERR "%s: In XMIT with no packet to send.\n", dev->name);
+ netdev_err(dev, "In XMIT with no packet to send\n");
return;
}
@@ -1136,8 +1136,8 @@ static void smc_hardware_send_packet(struct net_device * dev)
packet_no = inw(ioaddr + PNR_ARR) >> 8;
if (packet_no & 0x80) {
/* If not, there is a hardware problem! Likely an ejected card. */
- printk(KERN_WARNING "%s: 91c92 hardware Tx buffer allocation"
- " failed, status %#2.2x.\n", dev->name, packet_no);
+ netdev_warn(dev, "hardware Tx buffer allocation failed, status %#2.2x\n",
+ packet_no);
dev_kfree_skb_irq(skb);
smc->saved_skb = NULL;
netif_start_queue(dev);
@@ -1156,8 +1156,7 @@ static void smc_hardware_send_packet(struct net_device * dev)
u_char *buf = skb->data;
u_int length = skb->len; /* The chip will pad to ethernet min. */
- pr_debug("%s: Trying to xmit packet of length %d.\n",
- dev->name, length);
+ netdev_dbg(dev, "Trying to xmit packet of length %d\n", length);
/* send the packet length: +6 for status word, length, and ctl */
outw(0, ioaddr + DATA_1);
@@ -1189,9 +1188,8 @@ static void smc_tx_timeout(struct net_device *dev)
struct smc_private *smc = netdev_priv(dev);
unsigned int ioaddr = dev->base_addr;
- printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
- "Tx_status %2.2x status %4.4x.\n",
- dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));
+ netdev_notice(dev, "transmit timed out, Tx_status %2.2x status %4.4x.\n",
+ inw(ioaddr)&0xff, inw(ioaddr + 2));
dev->stats.tx_errors++;
smc_reset(dev);
dev->trans_start = jiffies; /* prevent tx timeout */
@@ -1210,14 +1208,14 @@ static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
netif_stop_queue(dev);
- pr_debug("%s: smc_start_xmit(length = %d) called,"
- " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));
+ netdev_dbg(dev, "smc_start_xmit(length = %d) called, status %04x\n",
+ skb->len, inw(ioaddr + 2));
if (smc->saved_skb) {
/* THIS SHOULD NEVER HAPPEN. */
dev->stats.tx_aborted_errors++;
- printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n",
- dev->name);
+ netdev_printk(KERN_DEBUG, dev,
+ "Internal error -- sent packet while busy\n");
return NETDEV_TX_BUSY;
}
smc->saved_skb = skb;
@@ -1225,7 +1223,7 @@ static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
num_pages = skb->len >> 8;
if (num_pages > 7) {
- printk(KERN_ERR "%s: Far too big packet error.\n", dev->name);
+ netdev_err(dev, "Far too big packet error: %d pages\n", num_pages);
dev_kfree_skb (skb);
smc->saved_skb = NULL;
dev->stats.tx_dropped++;
@@ -1295,8 +1293,7 @@ static void smc_tx_err(struct net_device * dev)
}
if (tx_status & TS_SUCCESS) {
- printk(KERN_NOTICE "%s: Successful packet caused error "
- "interrupt?\n", dev->name);
+ netdev_notice(dev, "Successful packet caused error interrupt?\n");
}
/* re-enable transmit */
SMC_SELECT_BANK(0);
@@ -1486,8 +1483,7 @@ static void smc_rx(struct net_device *dev)
/* Assertion: we are in Window 2. */
if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) {
- printk(KERN_ERR "%s: smc_rx() with nothing on Rx FIFO.\n",
- dev->name);
+ netdev_err(dev, "smc_rx() with nothing on Rx FIFO\n");
return;
}
@@ -1602,8 +1598,7 @@ static int s9k_config(struct net_device *dev, struct ifmap *map)
else if (map->port > 2)
return -EINVAL;
dev->if_port = map->port;
- printk(KERN_INFO "%s: switched to %s port\n",
- dev->name, if_names[dev->if_port]);
+ netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
smc_reset(dev);
}
return 0;
@@ -1754,7 +1749,7 @@ static void media_check(u_long arg)
this, we can limp along even if the interrupt is blocked */
if (smc->watchdog++ && ((i>>8) & i)) {
if (!smc->fast_poll)
- printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+ netdev_info(dev, "interrupt(s) dropped!\n");
local_irq_save(flags);
smc_interrupt(dev->irq, dev);
local_irq_restore(flags);
@@ -1778,7 +1773,7 @@ static void media_check(u_long arg)
SMC_SELECT_BANK(3);
link = mdio_read(dev, smc->mii_if.phy_id, 1);
if (!link || (link == 0xffff)) {
- printk(KERN_INFO "%s: MII is missing!\n", dev->name);
+ netdev_info(dev, "MII is missing!\n");
smc->mii_if.phy_id = -1;
goto reschedule;
}
@@ -1786,15 +1781,13 @@ static void media_check(u_long arg)
link &= 0x0004;
if (link != smc->link_status) {
u_short p = mdio_read(dev, smc->mii_if.phy_id, 5);
- printk(KERN_INFO "%s: %s link beat\n", dev->name,
- (link) ? "found" : "lost");
+ netdev_info(dev, "%s link beat\n", link ? "found" : "lost");
smc->duplex = (((p & 0x0100) || ((p & 0x1c0) == 0x40))
? TCR_FDUPLX : 0);
if (link) {
- printk(KERN_INFO "%s: autonegotiation complete: "
- "%sbaseT-%cD selected\n", dev->name,
- ((p & 0x0180) ? "100" : "10"),
- (smc->duplex ? 'F' : 'H'));
+ netdev_info(dev, "autonegotiation complete: "
+ "%dbaseT-%cD selected\n",
+ (p & 0x0180) ? 100 : 10, smc->duplex ? 'F' : 'H');
}
SMC_SELECT_BANK(0);
outw(inw(ioaddr + TCR) | smc->duplex, ioaddr + TCR);
@@ -1813,25 +1806,23 @@ static void media_check(u_long arg)
if (media != smc->media_status) {
if ((media & smc->media_status & 1) &&
((smc->media_status ^ media) & EPH_LINK_OK))
- printk(KERN_INFO "%s: %s link beat\n", dev->name,
- (smc->media_status & EPH_LINK_OK ? "lost" : "found"));
+ netdev_info(dev, "%s link beat\n",
+ smc->media_status & EPH_LINK_OK ? "lost" : "found");
else if ((media & smc->media_status & 2) &&
((smc->media_status ^ media) & EPH_16COL))
- printk(KERN_INFO "%s: coax cable %s\n", dev->name,
- (media & EPH_16COL ? "problem" : "ok"));
+ netdev_info(dev, "coax cable %s\n",
+ media & EPH_16COL ? "problem" : "ok");
if (dev->if_port == 0) {
if (media & 1) {
if (media & EPH_LINK_OK)
- printk(KERN_INFO "%s: flipped to 10baseT\n",
- dev->name);
+ netdev_info(dev, "flipped to 10baseT\n");
else
smc_set_xcvr(dev, 2);
} else {
if (media & EPH_16COL)
smc_set_xcvr(dev, 1);
else
- printk(KERN_INFO "%s: flipped to 10base2\n",
- dev->name);
+ netdev_info(dev, "flipped to 10base2\n");
}
}
smc->media_status = media;
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 1fece617c069..a46b7fd6c0f5 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -63,6 +63,8 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -209,13 +211,6 @@ enum xirc_cmd { /* Commands */
static const char *if_names[] = { "Auto", "10BaseT", "10Base2", "AUI", "100BaseT" };
-
-#define KDBG_XIRC KERN_DEBUG "xirc2ps_cs: "
-#define KERR_XIRC KERN_ERR "xirc2ps_cs: "
-#define KWRN_XIRC KERN_WARNING "xirc2ps_cs: "
-#define KNOT_XIRC KERN_NOTICE "xirc2ps_cs: "
-#define KINF_XIRC KERN_INFO "xirc2ps_cs: "
-
/* card types */
#define XIR_UNKNOWN 0 /* unknown: not supported */
#define XIR_CE 1 /* (prodid 1) different hardware: not supported */
@@ -327,26 +322,26 @@ PrintRegisters(struct net_device *dev)
if (pc_debug > 1) {
int i, page;
- printk(KDBG_XIRC "Register common: ");
+ printk(KERN_DEBUG pr_fmt("Register common: "));
for (i = 0; i < 8; i++)
- printk(" %2.2x", GetByte(i));
- printk("\n");
+ pr_cont(" %2.2x", GetByte(i));
+ pr_cont("\n");
for (page = 0; page <= 8; page++) {
- printk(KDBG_XIRC "Register page %2x: ", page);
+ printk(KERN_DEBUG pr_fmt("Register page %2x: "), page);
SelectPage(page);
for (i = 8; i < 16; i++)
- printk(" %2.2x", GetByte(i));
- printk("\n");
+ pr_cont(" %2.2x", GetByte(i));
+ pr_cont("\n");
}
for (page=0x40 ; page <= 0x5f; page++) {
if (page == 0x43 || (page >= 0x46 && page <= 0x4f) ||
(page >= 0x51 && page <=0x5e))
continue;
- printk(KDBG_XIRC "Register page %2x: ", page);
+ printk(KERN_DEBUG pr_fmt("Register page %2x: "), page);
SelectPage(page);
for (i = 8; i < 16; i++)
- printk(" %2.2x", GetByte(i));
- printk("\n");
+ pr_cont(" %2.2x", GetByte(i));
+ pr_cont("\n");
}
}
}
@@ -566,11 +561,11 @@ set_card_type(struct pcmcia_device *link)
local->modem = 0;
local->card_type = XIR_UNKNOWN;
if (!(prodid & 0x40)) {
- printk(KNOT_XIRC "Ooops: Not a creditcard\n");
+ pr_notice("Oops: Not a creditcard\n");
return 0;
}
if (!(mediaid & 0x01)) {
- printk(KNOT_XIRC "Not an Ethernet card\n");
+ pr_notice("Not an Ethernet card\n");
return 0;
}
if (mediaid & 0x10) {
@@ -601,12 +596,11 @@ set_card_type(struct pcmcia_device *link)
}
}
if (local->card_type == XIR_CE || local->card_type == XIR_CEM) {
- printk(KNOT_XIRC "Sorry, this is an old CE card\n");
+ pr_notice("Sorry, this is an old CE card\n");
return 0;
}
if (local->card_type == XIR_UNKNOWN)
- printk(KNOT_XIRC "unknown card (mediaid=%02x prodid=%02x)\n",
- mediaid, prodid);
+ pr_notice("unknown card (mediaid=%02x prodid=%02x)\n", mediaid, prodid);
return 1;
}
@@ -710,7 +704,7 @@ xirc2ps_config(struct pcmcia_device * link)
/* Is this a valid card */
if (link->has_manf_id == 0) {
- printk(KNOT_XIRC "manfid not found in CIS\n");
+ pr_notice("manfid not found in CIS\n");
goto failure;
}
@@ -732,14 +726,14 @@ xirc2ps_config(struct pcmcia_device * link)
local->manf_str = "Toshiba";
break;
default:
- printk(KNOT_XIRC "Unknown Card Manufacturer ID: 0x%04x\n",
- (unsigned)link->manf_id);
+ pr_notice("Unknown Card Manufacturer ID: 0x%04x\n",
+ (unsigned)link->manf_id);
goto failure;
}
dev_dbg(&link->dev, "found %s card\n", local->manf_str);
if (!set_card_type(link)) {
- printk(KNOT_XIRC "this card is not supported\n");
+ pr_notice("this card is not supported\n");
goto failure;
}
@@ -765,7 +759,7 @@ xirc2ps_config(struct pcmcia_device * link)
err = pcmcia_loop_tuple(link, CISTPL_FUNCE, pcmcia_get_mac_ce, dev);
if (err) {
- printk(KNOT_XIRC "node-id not found in CIS\n");
+ pr_notice("node-id not found in CIS\n");
goto failure;
}
@@ -792,7 +786,7 @@ xirc2ps_config(struct pcmcia_device * link)
* try to configure as Ethernet only.
* .... */
}
- printk(KNOT_XIRC "no ports available\n");
+ pr_notice("no ports available\n");
} else {
link->io_lines = 10;
link->resource[0]->end = 16;
@@ -865,24 +859,24 @@ xirc2ps_config(struct pcmcia_device * link)
#if 0
{
u_char tmp;
- printk(KERN_INFO "ECOR:");
+ pr_info("ECOR:");
for (i=0; i < 7; i++) {
tmp = readb(local->dingo_ccr + i*2);
- printk(" %02x", tmp);
+ pr_cont(" %02x", tmp);
}
- printk("\n");
- printk(KERN_INFO "DCOR:");
+ pr_cont("\n");
+ pr_info("DCOR:");
for (i=0; i < 4; i++) {
tmp = readb(local->dingo_ccr + 0x20 + i*2);
- printk(" %02x", tmp);
+ pr_cont(" %02x", tmp);
}
- printk("\n");
- printk(KERN_INFO "SCOR:");
+ pr_cont("\n");
+ pr_info("SCOR:");
for (i=0; i < 10; i++) {
tmp = readb(local->dingo_ccr + 0x40 + i*2);
- printk(" %02x", tmp);
+ pr_cont(" %02x", tmp);
}
- printk("\n");
+ pr_cont("\n");
}
#endif
@@ -901,7 +895,7 @@ xirc2ps_config(struct pcmcia_device * link)
(local->mohawk && if_port==4))
dev->if_port = if_port;
else
- printk(KNOT_XIRC "invalid if_port requested\n");
+ pr_notice("invalid if_port requested\n");
/* we can now register the device with the net subsystem */
dev->irq = link->irq;
@@ -913,14 +907,14 @@ xirc2ps_config(struct pcmcia_device * link)
SET_NETDEV_DEV(dev, &link->dev);
if ((err=register_netdev(dev))) {
- printk(KNOT_XIRC "register_netdev() failed\n");
+ pr_notice("register_netdev() failed\n");
goto config_error;
}
/* give some infos about the hardware */
- printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr %pM\n",
- dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq,
- dev->dev_addr);
+ netdev_info(dev, "%s: port %#3lx, irq %d, hwaddr %pM\n",
+ local->manf_str, (u_long)dev->base_addr, (int)dev->irq,
+ dev->dev_addr);
return 0;
@@ -1047,8 +1041,7 @@ xirc2ps_interrupt(int irq, void *dev_id)
skb = dev_alloc_skb(pktlen+3); /* 1 extra so we can use insw */
if (!skb) {
- printk(KNOT_XIRC "low memory, packet dropped (size=%u)\n",
- pktlen);
+ pr_notice("low memory, packet dropped (size=%u)\n", pktlen);
dev->stats.rx_dropped++;
} else { /* okay get the packet */
skb_reserve(skb, 2);
@@ -1217,7 +1210,7 @@ xirc_tx_timeout(struct net_device *dev)
{
local_info_t *lp = netdev_priv(dev);
dev->stats.tx_errors++;
- printk(KERN_NOTICE "%s: transmit timed out\n", dev->name);
+ netdev_notice(dev, "transmit timed out\n");
schedule_work(&lp->tx_timeout_task);
}
@@ -1384,8 +1377,7 @@ do_config(struct net_device *dev, struct ifmap *map)
local->probe_port = 0;
dev->if_port = map->port;
}
- printk(KERN_INFO "%s: switching to %s port\n",
- dev->name, if_names[dev->if_port]);
+ netdev_info(dev, "switching to %s port\n", if_names[dev->if_port]);
do_reset(dev,1); /* not the fine way :-) */
}
return 0;
@@ -1525,7 +1517,7 @@ do_reset(struct net_device *dev, int full)
{
SelectPage(0);
value = GetByte(XIRCREG_ESR); /* read the ESR */
- printk(KERN_DEBUG "%s: ESR is: %#02x\n", dev->name, value);
+ pr_debug("%s: ESR is: %#02x\n", dev->name, value);
}
#endif
@@ -1575,13 +1567,12 @@ do_reset(struct net_device *dev, int full)
if (full && local->mohawk && init_mii(dev)) {
if (dev->if_port == 4 || local->dingo || local->new_mii) {
- printk(KERN_INFO "%s: MII selected\n", dev->name);
+ netdev_info(dev, "MII selected\n");
SelectPage(2);
PutByte(XIRCREG2_MSR, GetByte(XIRCREG2_MSR) | 0x08);
msleep(20);
} else {
- printk(KERN_INFO "%s: MII detected; using 10mbs\n",
- dev->name);
+ netdev_info(dev, "MII detected; using 10mbs\n");
SelectPage(0x42);
if (dev->if_port == 2) /* enable 10Base2 */
PutByte(XIRCREG42_SWC1, 0xC0);
@@ -1626,8 +1617,8 @@ do_reset(struct net_device *dev, int full)
}
if (full)
- printk(KERN_INFO "%s: media %s, silicon revision %d\n",
- dev->name, if_names[dev->if_port], local->silicon);
+ netdev_info(dev, "media %s, silicon revision %d\n",
+ if_names[dev->if_port], local->silicon);
/* We should switch back to page 0 to avoid a bug in revision 0
* where regs with offset below 8 can't be read after an access
* to the MAC registers */
@@ -1669,8 +1660,7 @@ init_mii(struct net_device *dev)
control = mii_rd(ioaddr, 0, 0);
if (control & 0x0400) {
- printk(KERN_NOTICE "%s can't take PHY out of isolation mode\n",
- dev->name);
+ netdev_notice(dev, "can't take PHY out of isolation mode\n");
local->probe_port = 0;
return 0;
}
@@ -1688,8 +1678,7 @@ init_mii(struct net_device *dev)
}
if (!(status & 0x0020)) {
- printk(KERN_INFO "%s: autonegotiation failed;"
- " using 10mbs\n", dev->name);
+ netdev_info(dev, "autonegotiation failed; using 10mbs\n");
if (!local->new_mii) {
control = 0x0000;
mii_wr(ioaddr, 0, 0, control, 16);
@@ -1699,8 +1688,7 @@ init_mii(struct net_device *dev)
}
} else {
linkpartner = mii_rd(ioaddr, 0, 5);
- printk(KERN_INFO "%s: MII link partner: %04x\n",
- dev->name, linkpartner);
+ netdev_info(dev, "MII link partner: %04x\n", linkpartner);
if (linkpartner & 0x0080) {
dev->if_port = 4;
} else
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index c200c2821730..aee3bb0358bf 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -376,7 +376,7 @@ static void pcnet32_wio_reset(unsigned long addr)
static int pcnet32_wio_check(unsigned long addr)
{
outw(88, addr + PCNET32_WIO_RAP);
- return (inw(addr + PCNET32_WIO_RAP) == 88);
+ return inw(addr + PCNET32_WIO_RAP) == 88;
}
static struct pcnet32_access pcnet32_wio = {
@@ -431,7 +431,7 @@ static void pcnet32_dwio_reset(unsigned long addr)
static int pcnet32_dwio_check(unsigned long addr)
{
outl(88, addr + PCNET32_DWIO_RAP);
- return ((inl(addr + PCNET32_DWIO_RAP) & 0xffff) == 88);
+ return (inl(addr + PCNET32_DWIO_RAP) & 0xffff) == 88;
}
static struct pcnet32_access pcnet32_dwio = {
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index eb799b36c86a..cb3d13e4e074 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -58,7 +58,6 @@ config BROADCOM_PHY
config BCM63XX_PHY
tristate "Drivers for Broadcom 63xx SOCs internal PHY"
- depends on BCM63XX
---help---
Currently supports the 6348 and 6358 PHYs.
diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
index c12815679837..e16f98cb4f04 100644
--- a/drivers/net/phy/bcm63xx.c
+++ b/drivers/net/phy/bcm63xx.c
@@ -131,7 +131,7 @@ static void __exit bcm63xx_phy_exit(void)
module_init(bcm63xx_phy_init);
module_exit(bcm63xx_phy_exit);
-static struct mdio_device_id bcm63xx_tbl[] = {
+static struct mdio_device_id __maybe_unused bcm63xx_tbl[] = {
{ 0x00406000, 0xfffffc00 },
{ 0x002bdc00, 0xfffffc00 },
{ }
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 4accd83d3dfe..d84c4224dd12 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -930,7 +930,7 @@ static void __exit broadcom_exit(void)
module_init(broadcom_init);
module_exit(broadcom_exit);
-static struct mdio_device_id broadcom_tbl[] = {
+static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
{ PHY_ID_BCM5411, 0xfffffff0 },
{ PHY_ID_BCM5421, 0xfffffff0 },
{ PHY_ID_BCM5461, 0xfffffff0 },
diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c
index 1a325d63756b..d28173161c21 100644
--- a/drivers/net/phy/cicada.c
+++ b/drivers/net/phy/cicada.c
@@ -159,7 +159,7 @@ static void __exit cicada_exit(void)
module_init(cicada_init);
module_exit(cicada_exit);
-static struct mdio_device_id cicada_tbl[] = {
+static struct mdio_device_id __maybe_unused cicada_tbl[] = {
{ 0x000fc410, 0x000ffff0 },
{ 0x000fc440, 0x000fffc0 },
{ }
diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c
index 29c17617a2ec..2f774acdb551 100644
--- a/drivers/net/phy/davicom.c
+++ b/drivers/net/phy/davicom.c
@@ -219,7 +219,7 @@ static void __exit davicom_exit(void)
module_init(davicom_init);
module_exit(davicom_exit);
-static struct mdio_device_id davicom_tbl[] = {
+static struct mdio_device_id __maybe_unused davicom_tbl[] = {
{ 0x0181b880, 0x0ffffff0 },
{ 0x0181b8a0, 0x0ffffff0 },
{ 0x00181b80, 0x0ffffff0 },
diff --git a/drivers/net/phy/et1011c.c b/drivers/net/phy/et1011c.c
index 13995f52d6af..a8eb19ec3183 100644
--- a/drivers/net/phy/et1011c.c
+++ b/drivers/net/phy/et1011c.c
@@ -111,7 +111,7 @@ static void __exit et1011c_exit(void)
module_init(et1011c_init);
module_exit(et1011c_exit);
-static struct mdio_device_id et1011c_tbl[] = {
+static struct mdio_device_id __maybe_unused et1011c_tbl[] = {
{ 0x0282f014, 0xfffffff0 },
{ }
};
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
index 3f2583f18a39..c1d2d251fe8b 100644
--- a/drivers/net/phy/icplus.c
+++ b/drivers/net/phy/icplus.c
@@ -134,7 +134,7 @@ static void __exit ip175c_exit(void)
module_init(ip175c_init);
module_exit(ip175c_exit);
-static struct mdio_device_id icplus_tbl[] = {
+static struct mdio_device_id __maybe_unused icplus_tbl[] = {
{ 0x02430d80, 0x0ffffff0 },
{ }
};
diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c
index 29c39ff85de5..6f6e8b616a62 100644
--- a/drivers/net/phy/lxt.c
+++ b/drivers/net/phy/lxt.c
@@ -223,7 +223,7 @@ static void __exit lxt_exit(void)
module_init(lxt_init);
module_exit(lxt_exit);
-static struct mdio_device_id lxt_tbl[] = {
+static struct mdio_device_id __maybe_unused lxt_tbl[] = {
{ 0x78100000, 0xfffffff0 },
{ 0x001378e0, 0xfffffff0 },
{ 0x00137a10, 0xfffffff0 },
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 0101f2bdf400..e2afdce0a437 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -196,20 +196,27 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
MII_88E1121_PHY_MSCR_PAGE);
if (err < 0)
return err;
- mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) &
- MII_88E1121_PHY_MSCR_DELAY_MASK;
- if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
- mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY |
- MII_88E1121_PHY_MSCR_TX_DELAY);
- else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
- mscr |= MII_88E1121_PHY_MSCR_RX_DELAY;
- else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
- mscr |= MII_88E1121_PHY_MSCR_TX_DELAY;
+ if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
+ (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+ (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
+ (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
- err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
- if (err < 0)
- return err;
+ mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) &
+ MII_88E1121_PHY_MSCR_DELAY_MASK;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+ mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY |
+ MII_88E1121_PHY_MSCR_TX_DELAY);
+ else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+ mscr |= MII_88E1121_PHY_MSCR_RX_DELAY;
+ else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+ mscr |= MII_88E1121_PHY_MSCR_TX_DELAY;
+
+ err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
+ if (err < 0)
+ return err;
+ }
phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
@@ -721,7 +728,7 @@ static void __exit marvell_exit(void)
module_init(marvell_init);
module_exit(marvell_exit);
-static struct mdio_device_id marvell_tbl[] = {
+static struct mdio_device_id __maybe_unused marvell_tbl[] = {
{ 0x01410c60, 0xfffffff0 },
{ 0x01410c90, 0xfffffff0 },
{ 0x01410cc0, 0xfffffff0 },
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 8bb7db676a5c..0fd1678bc5a9 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -231,7 +231,7 @@ MODULE_DESCRIPTION("Micrel PHY driver");
MODULE_AUTHOR("David J. Choi");
MODULE_LICENSE("GPL");
-static struct mdio_device_id micrel_tbl[] = {
+static struct mdio_device_id __maybe_unused micrel_tbl[] = {
{ PHY_ID_KSZ9021, 0x000fff10 },
{ PHY_ID_KS8001, 0x00fffff0 },
{ PHY_ID_KS8737, 0x00fffff0 },
diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c
index a73ba0bcc0ce..0620ba963508 100644
--- a/drivers/net/phy/national.c
+++ b/drivers/net/phy/national.c
@@ -151,7 +151,7 @@ MODULE_LICENSE("GPL");
module_init(ns_init);
module_exit(ns_exit);
-static struct mdio_device_id ns_tbl[] = {
+static struct mdio_device_id __maybe_unused ns_tbl[] = {
{ DP83865_PHY_ID, 0xfffffff0 },
{ }
};
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 1bb16cb79433..7670aac0e93f 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -65,7 +65,7 @@ EXPORT_SYMBOL(phy_print_status);
*
* Returns 0 on success on < 0 on error.
*/
-int phy_clear_interrupt(struct phy_device *phydev)
+static int phy_clear_interrupt(struct phy_device *phydev)
{
int err = 0;
@@ -82,7 +82,7 @@ int phy_clear_interrupt(struct phy_device *phydev)
*
* Returns 0 on success on < 0 on error.
*/
-int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
+static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
{
int err = 0;
@@ -208,7 +208,7 @@ static inline int phy_find_valid(int idx, u32 features)
* duplexes. Drop down by one in this order: 1000/FULL,
* 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF.
*/
-void phy_sanitize_settings(struct phy_device *phydev)
+static void phy_sanitize_settings(struct phy_device *phydev)
{
u32 features = phydev->supported;
int idx;
@@ -223,7 +223,6 @@ void phy_sanitize_settings(struct phy_device *phydev)
phydev->speed = settings[idx].speed;
phydev->duplex = settings[idx].duplex;
}
-EXPORT_SYMBOL(phy_sanitize_settings);
/**
* phy_ethtool_sset - generic ethtool sset function, handles all the details
@@ -532,7 +531,7 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat)
* phy_enable_interrupts - Enable the interrupts from the PHY side
* @phydev: target phy_device struct
*/
-int phy_enable_interrupts(struct phy_device *phydev)
+static int phy_enable_interrupts(struct phy_device *phydev)
{
int err;
@@ -545,13 +544,12 @@ int phy_enable_interrupts(struct phy_device *phydev)
return err;
}
-EXPORT_SYMBOL(phy_enable_interrupts);
/**
* phy_disable_interrupts - Disable the PHY interrupts from the PHY side
* @phydev: target phy_device struct
*/
-int phy_disable_interrupts(struct phy_device *phydev)
+static int phy_disable_interrupts(struct phy_device *phydev)
{
int err;
@@ -574,7 +572,6 @@ phy_err:
return err;
}
-EXPORT_SYMBOL(phy_disable_interrupts);
/**
* phy_start_interrupts - request and enable interrupts for a PHY device
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 16ddc77313cb..993c52c82aeb 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -57,6 +57,9 @@ extern void mdio_bus_exit(void);
static LIST_HEAD(phy_fixup_list);
static DEFINE_MUTEX(phy_fixup_lock);
+static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
+ u32 flags, phy_interface_t interface);
+
/*
* Creates a new phy_fixup and adds it to the list
* @bus_id: A string which matches phydev->dev.bus_id (or PHY_ANY_ID)
@@ -146,7 +149,8 @@ int phy_scan_fixups(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_scan_fixups);
-struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
+static struct phy_device* phy_device_create(struct mii_bus *bus,
+ int addr, int phy_id)
{
struct phy_device *dev;
@@ -193,7 +197,6 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
return dev;
}
-EXPORT_SYMBOL(phy_device_create);
/**
* get_phy_id - reads the specified addr for its ID.
@@ -316,7 +319,7 @@ EXPORT_SYMBOL(phy_find_first);
* If you want to monitor your own link state, don't call
* this function.
*/
-void phy_prepare_link(struct phy_device *phydev,
+static void phy_prepare_link(struct phy_device *phydev,
void (*handler)(struct net_device *))
{
phydev->adjust_link = handler;
@@ -435,8 +438,8 @@ int phy_init_hw(struct phy_device *phydev)
* the attaching device, and given a callback for link status
* change. The phy_device is returned to the attaching driver.
*/
-int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
- u32 flags, phy_interface_t interface)
+static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
+ u32 flags, phy_interface_t interface)
{
struct device *d = &phydev->dev;
@@ -473,7 +476,6 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
* (dev_flags and interface) */
return phy_init_hw(phydev);
}
-EXPORT_SYMBOL(phy_attach_direct);
/**
* phy_attach - attach a network device to a particular PHY device
@@ -540,7 +542,7 @@ EXPORT_SYMBOL(phy_detach);
* what is supported. Returns < 0 on error, 0 if the PHY's advertisement
* hasn't changed, and > 0 if it has changed.
*/
-int genphy_config_advert(struct phy_device *phydev)
+static int genphy_config_advert(struct phy_device *phydev)
{
u32 advertise;
int oldadv, adv;
@@ -605,7 +607,6 @@ int genphy_config_advert(struct phy_device *phydev)
return changed;
}
-EXPORT_SYMBOL(genphy_config_advert);
/**
* genphy_setup_forced - configures/forces speed/duplex from @phydev
@@ -615,7 +616,7 @@ EXPORT_SYMBOL(genphy_config_advert);
* to the values in phydev. Assumes that the values are valid.
* Please see phy_sanitize_settings().
*/
-int genphy_setup_forced(struct phy_device *phydev)
+static int genphy_setup_forced(struct phy_device *phydev)
{
int err;
int ctl = 0;
diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c
index 6736b23f1b28..fe0d0a15d5e1 100644
--- a/drivers/net/phy/qsemi.c
+++ b/drivers/net/phy/qsemi.c
@@ -138,7 +138,7 @@ static void __exit qs6612_exit(void)
module_init(qs6612_init);
module_exit(qs6612_exit);
-static struct mdio_device_id qs6612_tbl[] = {
+static struct mdio_device_id __maybe_unused qs6612_tbl[] = {
{ 0x00181440, 0xfffffff0 },
{ }
};
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index f567c0e1aaa1..a4eae750a414 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -79,7 +79,7 @@ static void __exit realtek_exit(void)
module_init(realtek_init);
module_exit(realtek_exit);
-static struct mdio_device_id realtek_tbl[] = {
+static struct mdio_device_id __maybe_unused realtek_tbl[] = {
{ 0x001cc912, 0x001fffff },
{ }
};
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index 78fa988256fc..342505c976d6 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -254,7 +254,7 @@ MODULE_LICENSE("GPL");
module_init(smsc_init);
module_exit(smsc_exit);
-static struct mdio_device_id smsc_tbl[] = {
+static struct mdio_device_id __maybe_unused smsc_tbl[] = {
{ 0x0007c0a0, 0xfffffff0 },
{ 0x0007c0b0, 0xfffffff0 },
{ 0x0007c0c0, 0xfffffff0 },
diff --git a/drivers/net/phy/ste10Xp.c b/drivers/net/phy/ste10Xp.c
index 72290099e5e1..187a2fa814f2 100644
--- a/drivers/net/phy/ste10Xp.c
+++ b/drivers/net/phy/ste10Xp.c
@@ -132,7 +132,7 @@ static void __exit ste10Xp_exit(void)
module_init(ste10Xp_init);
module_exit(ste10Xp_exit);
-static struct mdio_device_id ste10Xp_tbl[] = {
+static struct mdio_device_id __maybe_unused ste10Xp_tbl[] = {
{ STE101P_PHY_ID, 0xfffffff0 },
{ STE100P_PHY_ID, 0xffffffff },
{ }
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index 45cce50a2799..5d8f6e17bd55 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -192,7 +192,7 @@ static void __exit vsc82xx_exit(void)
module_init(vsc82xx_init);
module_exit(vsc82xx_exit);
-static struct mdio_device_id vitesse_tbl[] = {
+static struct mdio_device_id __maybe_unused vitesse_tbl[] = {
{ PHY_ID_VSC8244, 0x000fffc0 },
{ PHY_ID_VSC8221, 0x000ffff0 },
{ }
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index ec0349e84a8a..ca4df7f4cf21 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -995,8 +995,10 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
static void
plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth)
{
- const struct in_device *in_dev = dev->ip_ptr;
+ const struct in_device *in_dev;
+ rcu_read_lock();
+ in_dev = __in_dev_get_rcu(dev);
if (in_dev) {
/* Any address will do - we take the first */
const struct in_ifaddr *ifa = in_dev->ifa_list;
@@ -1006,6 +1008,7 @@ plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth)
memcpy(eth->h_dest+2, &ifa->ifa_address, 4);
}
}
+ rcu_read_unlock();
}
static int
@@ -1088,7 +1091,8 @@ plip_open(struct net_device *dev)
when the device address isn't identical to the address of a
received frame, the kernel incorrectly drops it). */
- if ((in_dev=dev->ip_ptr) != NULL) {
+ in_dev=__in_dev_get_rtnl(dev);
+ if (in_dev) {
/* Any address will do - we take the first. We already
have the first two bytes filled with 0xfc, from
plip_init_dev(). */
@@ -1279,7 +1283,6 @@ static void plip_attach (struct parport *port)
if (!nl->pardev) {
printk(KERN_ERR "%s: parport_register failed\n", name);
goto err_free_dev;
- return;
}
plip_init_netdev(dev);
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 4bddb2afdd15..09cf56d0416a 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -1548,9 +1548,11 @@ ppp_channel_push(struct channel *pch)
* Receive-side routines.
*/
-/* misuse a few fields of the skb for MP reconstruction */
-#define sequence priority
-#define BEbits cb[0]
+struct ppp_mp_skb_parm {
+ u32 sequence;
+ u8 BEbits;
+};
+#define PPP_MP_CB(skb) ((struct ppp_mp_skb_parm *)((skb)->cb))
static inline void
ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
@@ -1879,13 +1881,13 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
seq = (skb->data[3] << 16) | (skb->data[4] << 8)| skb->data[5];
mask = 0xffffff;
}
- skb->BEbits = skb->data[2];
+ PPP_MP_CB(skb)->BEbits = skb->data[2];
skb_pull(skb, mphdrlen); /* pull off PPP and MP headers */
/*
* Do protocol ID decompression on the first fragment of each packet.
*/
- if ((skb->BEbits & B) && (skb->data[0] & 1))
+ if ((PPP_MP_CB(skb)->BEbits & B) && (skb->data[0] & 1))
*skb_push(skb, 1) = 0;
/*
@@ -1897,7 +1899,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
seq += mask + 1;
else if ((int)(seq - ppp->minseq) > (int)(mask >> 1))
seq -= mask + 1; /* should never happen */
- skb->sequence = seq;
+ PPP_MP_CB(skb)->sequence = seq;
pch->lastseq = seq;
/*
@@ -1933,8 +1935,8 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
before the start of the queue. */
if (skb_queue_len(&ppp->mrq) >= PPP_MP_MAX_QLEN) {
struct sk_buff *mskb = skb_peek(&ppp->mrq);
- if (seq_before(ppp->minseq, mskb->sequence))
- ppp->minseq = mskb->sequence;
+ if (seq_before(ppp->minseq, PPP_MP_CB(mskb)->sequence))
+ ppp->minseq = PPP_MP_CB(mskb)->sequence;
}
/* Pull completed packets off the queue and receive them. */
@@ -1964,12 +1966,12 @@ ppp_mp_insert(struct ppp *ppp, struct sk_buff *skb)
{
struct sk_buff *p;
struct sk_buff_head *list = &ppp->mrq;
- u32 seq = skb->sequence;
+ u32 seq = PPP_MP_CB(skb)->sequence;
/* N.B. we don't need to lock the list lock because we have the
ppp unit receive-side lock. */
skb_queue_walk(list, p) {
- if (seq_before(seq, p->sequence))
+ if (seq_before(seq, PPP_MP_CB(p)->sequence))
break;
}
__skb_queue_before(list, p, skb);
@@ -1998,22 +2000,22 @@ ppp_mp_reconstruct(struct ppp *ppp)
tail = NULL;
for (p = head; p != (struct sk_buff *) list; p = next) {
next = p->next;
- if (seq_before(p->sequence, seq)) {
+ if (seq_before(PPP_MP_CB(p)->sequence, seq)) {
/* this can't happen, anyway ignore the skb */
printk(KERN_ERR "ppp_mp_reconstruct bad seq %u < %u\n",
- p->sequence, seq);
+ PPP_MP_CB(p)->sequence, seq);
head = next;
continue;
}
- if (p->sequence != seq) {
+ if (PPP_MP_CB(p)->sequence != seq) {
/* Fragment `seq' is missing. If it is after
minseq, it might arrive later, so stop here. */
if (seq_after(seq, minseq))
break;
/* Fragment `seq' is lost, keep going. */
lost = 1;
- seq = seq_before(minseq, p->sequence)?
- minseq + 1: p->sequence;
+ seq = seq_before(minseq, PPP_MP_CB(p)->sequence)?
+ minseq + 1: PPP_MP_CB(p)->sequence;
next = p;
continue;
}
@@ -2027,7 +2029,7 @@ ppp_mp_reconstruct(struct ppp *ppp)
*/
/* B bit set indicates this fragment starts a packet */
- if (p->BEbits & B) {
+ if (PPP_MP_CB(p)->BEbits & B) {
head = p;
lost = 0;
len = 0;
@@ -2036,7 +2038,8 @@ ppp_mp_reconstruct(struct ppp *ppp)
len += p->len;
/* Got a complete packet yet? */
- if (lost == 0 && (p->BEbits & E) && (head->BEbits & B)) {
+ if (lost == 0 && (PPP_MP_CB(p)->BEbits & E) &&
+ (PPP_MP_CB(head)->BEbits & B)) {
if (len > ppp->mrru + 2) {
++ppp->dev->stats.rx_length_errors;
printk(KERN_DEBUG "PPP: reconstructed packet"
@@ -2062,7 +2065,7 @@ ppp_mp_reconstruct(struct ppp *ppp)
* and we haven't found a complete valid packet yet,
* we can discard up to and including this fragment.
*/
- if (p->BEbits & E)
+ if (PPP_MP_CB(p)->BEbits & E)
head = next;
++seq;
@@ -2072,10 +2075,11 @@ ppp_mp_reconstruct(struct ppp *ppp)
if (tail != NULL) {
/* If we have discarded any fragments,
signal a receive error. */
- if (head->sequence != ppp->nextseq) {
+ if (PPP_MP_CB(head)->sequence != ppp->nextseq) {
if (ppp->debug & 1)
printk(KERN_DEBUG " missed pkts %u..%u\n",
- ppp->nextseq, head->sequence-1);
+ ppp->nextseq,
+ PPP_MP_CB(head)->sequence-1);
++ppp->dev->stats.rx_dropped;
ppp_receive_error(ppp);
}
@@ -2084,7 +2088,7 @@ ppp_mp_reconstruct(struct ppp *ppp)
/* copy to a single skb */
for (p = head; p != tail->next; p = p->next)
skb_copy_bits(p, 0, skb_put(skb, p->len), p->len);
- ppp->nextseq = tail->sequence + 1;
+ ppp->nextseq = PPP_MP_CB(tail)->sequence + 1;
head = tail->next;
}
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index c07de359dc07..d72fb0519a2a 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -1124,7 +1124,7 @@ static const struct proto_ops pppoe_ops = {
.ioctl = pppox_ioctl,
};
-static struct pppox_proto pppoe_proto = {
+static const struct pppox_proto pppoe_proto = {
.create = pppoe_create,
.ioctl = pppoe_ioctl,
.owner = THIS_MODULE,
diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c
index d4191ef9cad1..8c0d170dabcd 100644
--- a/drivers/net/pppox.c
+++ b/drivers/net/pppox.c
@@ -36,9 +36,9 @@
#include <asm/uaccess.h>
-static struct pppox_proto *pppox_protos[PX_MAX_PROTO + 1];
+static const struct pppox_proto *pppox_protos[PX_MAX_PROTO + 1];
-int register_pppox_proto(int proto_num, struct pppox_proto *pp)
+int register_pppox_proto(int proto_num, const struct pppox_proto *pp)
{
if (proto_num < 0 || proto_num > PX_MAX_PROTO)
return -EINVAL;
diff --git a/drivers/net/pptp.c b/drivers/net/pptp.c
new file mode 100644
index 000000000000..ccbc91326bfa
--- /dev/null
+++ b/drivers/net/pptp.c
@@ -0,0 +1,726 @@
+/*
+ * Point-to-Point Tunneling Protocol for Linux
+ *
+ * Authors: Dmitry Kozlov <xeb@mail.ru>
+ *
+ * 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/string.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/ppp_channel.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_pppox.h>
+#include <linux/if_ppp.h>
+#include <linux/notifier.h>
+#include <linux/file.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/version.h>
+#include <linux/rcupdate.h>
+#include <linux/spinlock.h>
+
+#include <net/sock.h>
+#include <net/protocol.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/route.h>
+#include <net/gre.h>
+
+#include <linux/uaccess.h>
+
+#define PPTP_DRIVER_VERSION "0.8.5"
+
+#define MAX_CALLID 65535
+
+static DECLARE_BITMAP(callid_bitmap, MAX_CALLID + 1);
+static struct pppox_sock **callid_sock;
+
+static DEFINE_SPINLOCK(chan_lock);
+
+static struct proto pptp_sk_proto __read_mostly;
+static const struct ppp_channel_ops pptp_chan_ops;
+static const struct proto_ops pptp_ops;
+
+#define PPP_LCP_ECHOREQ 0x09
+#define PPP_LCP_ECHOREP 0x0A
+#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
+
+#define MISSING_WINDOW 20
+#define WRAPPED(curseq, lastseq)\
+ ((((curseq) & 0xffffff00) == 0) &&\
+ (((lastseq) & 0xffffff00) == 0xffffff00))
+
+#define PPTP_GRE_PROTO 0x880B
+#define PPTP_GRE_VER 0x1
+
+#define PPTP_GRE_FLAG_C 0x80
+#define PPTP_GRE_FLAG_R 0x40
+#define PPTP_GRE_FLAG_K 0x20
+#define PPTP_GRE_FLAG_S 0x10
+#define PPTP_GRE_FLAG_A 0x80
+
+#define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C)
+#define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R)
+#define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K)
+#define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S)
+#define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A)
+
+#define PPTP_HEADER_OVERHEAD (2+sizeof(struct pptp_gre_header))
+struct pptp_gre_header {
+ u8 flags;
+ u8 ver;
+ u16 protocol;
+ u16 payload_len;
+ u16 call_id;
+ u32 seq;
+ u32 ack;
+} __packed;
+
+static struct pppox_sock *lookup_chan(u16 call_id, __be32 s_addr)
+{
+ struct pppox_sock *sock;
+ struct pptp_opt *opt;
+
+ rcu_read_lock();
+ sock = rcu_dereference(callid_sock[call_id]);
+ if (sock) {
+ opt = &sock->proto.pptp;
+ if (opt->dst_addr.sin_addr.s_addr != s_addr)
+ sock = NULL;
+ else
+ sock_hold(sk_pppox(sock));
+ }
+ rcu_read_unlock();
+
+ return sock;
+}
+
+static int lookup_chan_dst(u16 call_id, __be32 d_addr)
+{
+ struct pppox_sock *sock;
+ struct pptp_opt *opt;
+ int i;
+
+ rcu_read_lock();
+ for (i = find_next_bit(callid_bitmap, MAX_CALLID, 1); i < MAX_CALLID;
+ i = find_next_bit(callid_bitmap, MAX_CALLID, i + 1)) {
+ sock = rcu_dereference(callid_sock[i]);
+ if (!sock)
+ continue;
+ opt = &sock->proto.pptp;
+ if (opt->dst_addr.call_id == call_id &&
+ opt->dst_addr.sin_addr.s_addr == d_addr)
+ break;
+ }
+ rcu_read_unlock();
+
+ return i < MAX_CALLID;
+}
+
+static int add_chan(struct pppox_sock *sock)
+{
+ static int call_id;
+
+ spin_lock(&chan_lock);
+ if (!sock->proto.pptp.src_addr.call_id) {
+ call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, call_id + 1);
+ if (call_id == MAX_CALLID) {
+ call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, 1);
+ if (call_id == MAX_CALLID)
+ goto out_err;
+ }
+ sock->proto.pptp.src_addr.call_id = call_id;
+ } else if (test_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap))
+ goto out_err;
+
+ set_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap);
+ rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], sock);
+ spin_unlock(&chan_lock);
+
+ return 0;
+
+out_err:
+ spin_unlock(&chan_lock);
+ return -1;
+}
+
+static void del_chan(struct pppox_sock *sock)
+{
+ spin_lock(&chan_lock);
+ clear_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap);
+ rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], NULL);
+ spin_unlock(&chan_lock);
+ synchronize_rcu();
+}
+
+static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
+{
+ struct sock *sk = (struct sock *) chan->private;
+ struct pppox_sock *po = pppox_sk(sk);
+ struct pptp_opt *opt = &po->proto.pptp;
+ struct pptp_gre_header *hdr;
+ unsigned int header_len = sizeof(*hdr);
+ int err = 0;
+ int islcp;
+ int len;
+ unsigned char *data;
+ __u32 seq_recv;
+
+
+ struct rtable *rt;
+ struct net_device *tdev;
+ struct iphdr *iph;
+ int max_headroom;
+
+ if (sk_pppox(po)->sk_state & PPPOX_DEAD)
+ goto tx_error;
+
+ {
+ struct flowi fl = { .oif = 0,
+ .nl_u = {
+ .ip4_u = {
+ .daddr = opt->dst_addr.sin_addr.s_addr,
+ .saddr = opt->src_addr.sin_addr.s_addr,
+ .tos = RT_TOS(0) } },
+ .proto = IPPROTO_GRE };
+ err = ip_route_output_key(&init_net, &rt, &fl);
+ if (err)
+ goto tx_error;
+ }
+ tdev = rt->dst.dev;
+
+ max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(*iph) + sizeof(*hdr) + 2;
+
+ if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
+ struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
+ if (!new_skb) {
+ ip_rt_put(rt);
+ goto tx_error;
+ }
+ if (skb->sk)
+ skb_set_owner_w(new_skb, skb->sk);
+ kfree_skb(skb);
+ skb = new_skb;
+ }
+
+ data = skb->data;
+ islcp = ((data[0] << 8) + data[1]) == PPP_LCP && 1 <= data[2] && data[2] <= 7;
+
+ /* compress protocol field */
+ if ((opt->ppp_flags & SC_COMP_PROT) && data[0] == 0 && !islcp)
+ skb_pull(skb, 1);
+
+ /* Put in the address/control bytes if necessary */
+ if ((opt->ppp_flags & SC_COMP_AC) == 0 || islcp) {
+ data = skb_push(skb, 2);
+ data[0] = PPP_ALLSTATIONS;
+ data[1] = PPP_UI;
+ }
+
+ len = skb->len;
+
+ seq_recv = opt->seq_recv;
+
+ if (opt->ack_sent == seq_recv)
+ header_len -= sizeof(hdr->ack);
+
+ /* Push down and install GRE header */
+ skb_push(skb, header_len);
+ hdr = (struct pptp_gre_header *)(skb->data);
+
+ hdr->flags = PPTP_GRE_FLAG_K;
+ hdr->ver = PPTP_GRE_VER;
+ hdr->protocol = htons(PPTP_GRE_PROTO);
+ hdr->call_id = htons(opt->dst_addr.call_id);
+
+ hdr->flags |= PPTP_GRE_FLAG_S;
+ hdr->seq = htonl(++opt->seq_sent);
+ if (opt->ack_sent != seq_recv) {
+ /* send ack with this message */
+ hdr->ver |= PPTP_GRE_FLAG_A;
+ hdr->ack = htonl(seq_recv);
+ opt->ack_sent = seq_recv;
+ }
+ hdr->payload_len = htons(len);
+
+ /* Push down and install the IP header. */
+
+ skb_reset_transport_header(skb);
+ skb_push(skb, sizeof(*iph));
+ skb_reset_network_header(skb);
+ memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+ IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED);
+
+ iph = ip_hdr(skb);
+ iph->version = 4;
+ iph->ihl = sizeof(struct iphdr) >> 2;
+ if (ip_dont_fragment(sk, &rt->dst))
+ iph->frag_off = htons(IP_DF);
+ else
+ iph->frag_off = 0;
+ iph->protocol = IPPROTO_GRE;
+ iph->tos = 0;
+ iph->daddr = rt->rt_dst;
+ iph->saddr = rt->rt_src;
+ iph->ttl = dst_metric(&rt->dst, RTAX_HOPLIMIT);
+ iph->tot_len = htons(skb->len);
+
+ skb_dst_drop(skb);
+ skb_dst_set(skb, &rt->dst);
+
+ nf_reset(skb);
+
+ skb->ip_summed = CHECKSUM_NONE;
+ ip_select_ident(iph, &rt->dst, NULL);
+ ip_send_check(iph);
+
+ ip_local_out(skb);
+
+tx_error:
+ return 1;
+}
+
+static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb)
+{
+ struct pppox_sock *po = pppox_sk(sk);
+ struct pptp_opt *opt = &po->proto.pptp;
+ int headersize, payload_len, seq;
+ __u8 *payload;
+ struct pptp_gre_header *header;
+
+ if (!(sk->sk_state & PPPOX_CONNECTED)) {
+ if (sock_queue_rcv_skb(sk, skb))
+ goto drop;
+ return NET_RX_SUCCESS;
+ }
+
+ header = (struct pptp_gre_header *)(skb->data);
+
+ /* 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 */
+
+ ack = ntohl(ack);
+
+ if (ack > opt->ack_recv)
+ opt->ack_recv = ack;
+ /* also handle sequence number wrap-around */
+ if (WRAPPED(ack, opt->ack_recv))
+ opt->ack_recv = 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)
+ goto drop;
+
+ payload = skb->data + headersize;
+ /* check for expected sequence number */
+ if (seq < opt->seq_recv + 1 || WRAPPED(opt->seq_recv, seq)) {
+ if ((payload[0] == PPP_ALLSTATIONS) && (payload[1] == PPP_UI) &&
+ (PPP_PROTOCOL(payload) == PPP_LCP) &&
+ ((payload[4] == PPP_LCP_ECHOREQ) || (payload[4] == PPP_LCP_ECHOREP)))
+ goto allow_packet;
+ } else {
+ opt->seq_recv = seq;
+allow_packet:
+ skb_pull(skb, headersize);
+
+ if (payload[0] == PPP_ALLSTATIONS && payload[1] == PPP_UI) {
+ /* chop off address/control */
+ if (skb->len < 3)
+ goto drop;
+ skb_pull(skb, 2);
+ }
+
+ if ((*skb->data) & 1) {
+ /* protocol is compressed */
+ skb_push(skb, 1)[0] = 0;
+ }
+
+ skb->ip_summed = CHECKSUM_NONE;
+ skb_set_network_header(skb, skb->head-skb->data);
+ ppp_input(&po->chan, skb);
+
+ return NET_RX_SUCCESS;
+ }
+drop:
+ kfree_skb(skb);
+ return NET_RX_DROP;
+}
+
+static int pptp_rcv(struct sk_buff *skb)
+{
+ struct pppox_sock *po;
+ struct pptp_gre_header *header;
+ struct iphdr *iph;
+
+ if (skb->pkt_type != PACKET_HOST)
+ goto drop;
+
+ if (!pskb_may_pull(skb, 12))
+ goto drop;
+
+ iph = ip_hdr(skb);
+
+ header = (struct pptp_gre_header *)skb->data;
+
+ if (ntohs(header->protocol) != PPTP_GRE_PROTO || /* PPTP-GRE protocol for PPTP */
+ PPTP_GRE_IS_C(header->flags) || /* flag C should be clear */
+ PPTP_GRE_IS_R(header->flags) || /* flag R should be clear */
+ !PPTP_GRE_IS_K(header->flags) || /* flag K should be set */
+ (header->flags&0xF) != 0) /* routing and recursion ctrl = 0 */
+ /* if invalid, discard this packet */
+ goto drop;
+
+ po = lookup_chan(htons(header->call_id), iph->saddr);
+ if (po) {
+ skb_dst_drop(skb);
+ nf_reset(skb);
+ return sk_receive_skb(sk_pppox(po), skb, 0);
+ }
+drop:
+ kfree_skb(skb);
+ return NET_RX_DROP;
+}
+
+static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr,
+ int sockaddr_len)
+{
+ struct sock *sk = sock->sk;
+ struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
+ struct pppox_sock *po = pppox_sk(sk);
+ struct pptp_opt *opt = &po->proto.pptp;
+ int error = 0;
+
+ lock_sock(sk);
+
+ opt->src_addr = sp->sa_addr.pptp;
+ if (add_chan(po)) {
+ release_sock(sk);
+ error = -EBUSY;
+ }
+
+ release_sock(sk);
+ return error;
+}
+
+static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
+ int sockaddr_len, int flags)
+{
+ struct sock *sk = sock->sk;
+ struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
+ struct pppox_sock *po = pppox_sk(sk);
+ struct pptp_opt *opt = &po->proto.pptp;
+ struct rtable *rt;
+ int error = 0;
+
+ if (sp->sa_protocol != PX_PROTO_PPTP)
+ return -EINVAL;
+
+ if (lookup_chan_dst(sp->sa_addr.pptp.call_id, sp->sa_addr.pptp.sin_addr.s_addr))
+ return -EALREADY;
+
+ lock_sock(sk);
+ /* Check for already bound sockets */
+ if (sk->sk_state & PPPOX_CONNECTED) {
+ error = -EBUSY;
+ goto end;
+ }
+
+ /* Check for already disconnected sockets, on attempts to disconnect */
+ if (sk->sk_state & PPPOX_DEAD) {
+ error = -EALREADY;
+ goto end;
+ }
+
+ if (!opt->src_addr.sin_addr.s_addr || !sp->sa_addr.pptp.sin_addr.s_addr) {
+ error = -EINVAL;
+ goto end;
+ }
+
+ po->chan.private = sk;
+ po->chan.ops = &pptp_chan_ops;
+
+ {
+ struct flowi fl = {
+ .nl_u = {
+ .ip4_u = {
+ .daddr = opt->dst_addr.sin_addr.s_addr,
+ .saddr = opt->src_addr.sin_addr.s_addr,
+ .tos = RT_CONN_FLAGS(sk) } },
+ .proto = IPPROTO_GRE };
+ security_sk_classify_flow(sk, &fl);
+ if (ip_route_output_key(&init_net, &rt, &fl)) {
+ error = -EHOSTUNREACH;
+ goto end;
+ }
+ sk_setup_caps(sk, &rt->dst);
+ }
+ po->chan.mtu = dst_mtu(&rt->dst);
+ if (!po->chan.mtu)
+ po->chan.mtu = PPP_MTU;
+ ip_rt_put(rt);
+ po->chan.mtu -= PPTP_HEADER_OVERHEAD;
+
+ po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header);
+ error = ppp_register_channel(&po->chan);
+ if (error) {
+ pr_err("PPTP: failed to register PPP channel (%d)\n", error);
+ goto end;
+ }
+
+ opt->dst_addr = sp->sa_addr.pptp;
+ sk->sk_state = PPPOX_CONNECTED;
+
+ end:
+ release_sock(sk);
+ return error;
+}
+
+static int pptp_getname(struct socket *sock, struct sockaddr *uaddr,
+ int *usockaddr_len, int peer)
+{
+ int len = sizeof(struct sockaddr_pppox);
+ struct sockaddr_pppox sp;
+
+ sp.sa_family = AF_PPPOX;
+ sp.sa_protocol = PX_PROTO_PPTP;
+ sp.sa_addr.pptp = pppox_sk(sock->sk)->proto.pptp.src_addr;
+
+ memcpy(uaddr, &sp, len);
+
+ *usockaddr_len = len;
+
+ return 0;
+}
+
+static int pptp_release(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+ struct pppox_sock *po;
+ struct pptp_opt *opt;
+ int error = 0;
+
+ if (!sk)
+ return 0;
+
+ lock_sock(sk);
+
+ if (sock_flag(sk, SOCK_DEAD)) {
+ release_sock(sk);
+ return -EBADF;
+ }
+
+ po = pppox_sk(sk);
+ opt = &po->proto.pptp;
+ del_chan(po);
+
+ pppox_unbind_sock(sk);
+ sk->sk_state = PPPOX_DEAD;
+
+ sock_orphan(sk);
+ sock->sk = NULL;
+
+ release_sock(sk);
+ sock_put(sk);
+
+ return error;
+}
+
+static void pptp_sock_destruct(struct sock *sk)
+{
+ if (!(sk->sk_state & PPPOX_DEAD)) {
+ del_chan(pppox_sk(sk));
+ pppox_unbind_sock(sk);
+ }
+ skb_queue_purge(&sk->sk_receive_queue);
+}
+
+static int pptp_create(struct net *net, struct socket *sock)
+{
+ int error = -ENOMEM;
+ struct sock *sk;
+ struct pppox_sock *po;
+ struct pptp_opt *opt;
+
+ sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pptp_sk_proto);
+ if (!sk)
+ goto out;
+
+ sock_init_data(sock, sk);
+
+ sock->state = SS_UNCONNECTED;
+ sock->ops = &pptp_ops;
+
+ sk->sk_backlog_rcv = pptp_rcv_core;
+ sk->sk_state = PPPOX_NONE;
+ sk->sk_type = SOCK_STREAM;
+ sk->sk_family = PF_PPPOX;
+ sk->sk_protocol = PX_PROTO_PPTP;
+ sk->sk_destruct = pptp_sock_destruct;
+
+ po = pppox_sk(sk);
+ opt = &po->proto.pptp;
+
+ opt->seq_sent = 0; opt->seq_recv = 0;
+ opt->ack_recv = 0; opt->ack_sent = 0;
+
+ error = 0;
+out:
+ return error;
+}
+
+static int pptp_ppp_ioctl(struct ppp_channel *chan, unsigned int cmd,
+ unsigned long arg)
+{
+ struct sock *sk = (struct sock *) chan->private;
+ struct pppox_sock *po = pppox_sk(sk);
+ struct pptp_opt *opt = &po->proto.pptp;
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ int err, val;
+
+ err = -EFAULT;
+ switch (cmd) {
+ case PPPIOCGFLAGS:
+ val = opt->ppp_flags;
+ if (put_user(val, p))
+ break;
+ err = 0;
+ break;
+ case PPPIOCSFLAGS:
+ if (get_user(val, p))
+ break;
+ opt->ppp_flags = val & ~SC_RCV_BITS;
+ err = 0;
+ break;
+ default:
+ err = -ENOTTY;
+ }
+
+ return err;
+}
+
+static const struct ppp_channel_ops pptp_chan_ops = {
+ .start_xmit = pptp_xmit,
+ .ioctl = pptp_ppp_ioctl,
+};
+
+static struct proto pptp_sk_proto __read_mostly = {
+ .name = "PPTP",
+ .owner = THIS_MODULE,
+ .obj_size = sizeof(struct pppox_sock),
+};
+
+static const struct proto_ops pptp_ops = {
+ .family = AF_PPPOX,
+ .owner = THIS_MODULE,
+ .release = pptp_release,
+ .bind = pptp_bind,
+ .connect = pptp_connect,
+ .socketpair = sock_no_socketpair,
+ .accept = sock_no_accept,
+ .getname = pptp_getname,
+ .poll = sock_no_poll,
+ .listen = sock_no_listen,
+ .shutdown = sock_no_shutdown,
+ .setsockopt = sock_no_setsockopt,
+ .getsockopt = sock_no_getsockopt,
+ .sendmsg = sock_no_sendmsg,
+ .recvmsg = sock_no_recvmsg,
+ .mmap = sock_no_mmap,
+ .ioctl = pppox_ioctl,
+};
+
+static const struct pppox_proto pppox_pptp_proto = {
+ .create = pptp_create,
+ .owner = THIS_MODULE,
+};
+
+static const struct gre_protocol gre_pptp_protocol = {
+ .handler = pptp_rcv,
+};
+
+static int __init pptp_init_module(void)
+{
+ int err = 0;
+ pr_info("PPTP driver version " PPTP_DRIVER_VERSION "\n");
+
+ callid_sock = __vmalloc((MAX_CALLID + 1) * sizeof(void *),
+ GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+ if (!callid_sock) {
+ pr_err("PPTP: cann't allocate memory\n");
+ return -ENOMEM;
+ }
+
+ err = gre_add_protocol(&gre_pptp_protocol, GREPROTO_PPTP);
+ if (err) {
+ pr_err("PPTP: can't add gre protocol\n");
+ goto out_mem_free;
+ }
+
+ err = proto_register(&pptp_sk_proto, 0);
+ if (err) {
+ pr_err("PPTP: can't register sk_proto\n");
+ goto out_gre_del_protocol;
+ }
+
+ err = register_pppox_proto(PX_PROTO_PPTP, &pppox_pptp_proto);
+ if (err) {
+ pr_err("PPTP: can't register pppox_proto\n");
+ goto out_unregister_sk_proto;
+ }
+
+ return 0;
+
+out_unregister_sk_proto:
+ proto_unregister(&pptp_sk_proto);
+out_gre_del_protocol:
+ gre_del_protocol(&gre_pptp_protocol, GREPROTO_PPTP);
+out_mem_free:
+ vfree(callid_sock);
+
+ return err;
+}
+
+static void __exit pptp_exit_module(void)
+{
+ unregister_pppox_proto(PX_PROTO_PPTP);
+ proto_unregister(&pptp_sk_proto);
+ gre_del_protocol(&gre_pptp_protocol, GREPROTO_PPTP);
+ vfree(callid_sock);
+}
+
+module_init(pptp_init_module);
+module_exit(pptp_exit_module);
+
+MODULE_DESCRIPTION("Point-to-Point Tunneling Protocol");
+MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c
index 87d6b8f36304..5ecfa4b1e758 100644
--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ps3_gelic_net.c
@@ -642,7 +642,7 @@ static inline void gelic_card_disable_rxdmac(struct gelic_card *card)
status = lv1_net_stop_rx_dma(bus_id(card), dev_id(card), 0);
if (status)
dev_err(ctodev(card),
- "lv1_net_stop_rx_dma faild, %d\n", status);
+ "lv1_net_stop_rx_dma failed, %d\n", status);
}
/**
@@ -660,7 +660,7 @@ static inline void gelic_card_disable_txdmac(struct gelic_card *card)
status = lv1_net_stop_tx_dma(bus_id(card), dev_id(card), 0);
if (status)
dev_err(ctodev(card),
- "lv1_net_stop_tx_dma faild, status=%d\n", status);
+ "lv1_net_stop_tx_dma failed, status=%d\n", status);
}
/**
@@ -956,9 +956,9 @@ static void gelic_net_pass_skb_up(struct gelic_descr *descr,
(!(data_error & GELIC_DESCR_DATA_ERROR_CHK_MASK)))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
} else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
/* update netdevice statistics */
netdev->stats.rx_packets++;
diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c
index 43b8d7797f0a..4a624a29393f 100644
--- a/drivers/net/ps3_gelic_wireless.c
+++ b/drivers/net/ps3_gelic_wireless.c
@@ -85,12 +85,12 @@ static const int bitrate_list[] = {
*/
static inline int wpa2_capable(void)
{
- return (0 <= ps3_compare_firmware_version(2, 0, 0));
+ return 0 <= ps3_compare_firmware_version(2, 0, 0);
}
static inline int precise_ie(void)
{
- return (0 <= ps3_compare_firmware_version(2, 2, 0));
+ return 0 <= ps3_compare_firmware_version(2, 2, 0);
}
/*
* post_eurus_cmd helpers
@@ -506,7 +506,7 @@ static size_t gelic_wl_synthesize_ie(u8 *buf,
start[1] = (buf - start - 2);
pr_debug("%s: ->\n", __func__);
- return (buf - start);
+ return buf - start;
}
struct ie_item {
diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c
index 85eddda276bd..18c0297743f1 100644
--- a/drivers/net/pxa168_eth.c
+++ b/drivers/net/pxa168_eth.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2010 Marvell International Ltd.
* Sachin Sanap <ssanap@marvell.com>
+ * Zhangfei Gao <zgao6@marvell.com>
* Philip Rakity <prakity@marvell.com>
* Mark Brown <markb@marvell.com>
*
@@ -42,8 +43,6 @@
#include <linux/types.h>
#include <asm/pgtable.h>
#include <asm/system.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
#include <asm/cacheflush.h>
#include <linux/pxa168_eth.h>
@@ -850,7 +849,6 @@ static int rxq_process(struct net_device *dev, int budget)
skb->protocol = eth_type_trans(skb, dev);
netif_receive_skb(skb);
}
- dev->last_rx = jiffies;
}
/* Fill RX ring with skb's */
rxq_refill(dev);
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 6168a130f33f..7496ed2c34ab 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -2029,7 +2029,7 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
dma_unmap_len(lrg_buf_cb2, maplen),
PCI_DMA_FROMDEVICE);
prefetch(skb->data);
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
skb->protocol = eth_type_trans(skb, qdev->ndev);
netif_receive_skb(skb);
@@ -2076,7 +2076,7 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
PCI_DMA_FROMDEVICE);
prefetch(skb2->data);
- skb2->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb2);
if (qdev->device_id == QL3022_DEVICE_ID) {
/*
* Copy the ethhdr from first buffer to second. This
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 970389331bbc..8ecc170c9b74 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -51,9 +51,11 @@
#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 7
-#define QLCNIC_LINUX_VERSIONID "5.0.7"
+#define _QLCNIC_LINUX_SUBVERSION 11
+#define QLCNIC_LINUX_VERSIONID "5.0.11"
#define QLCNIC_DRV_IDC_VER 0x01
+#define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\
+ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
#define QLCNIC_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c))
#define _major(v) (((v) >> 24) & 0xff)
@@ -92,11 +94,12 @@
#define FIRST_PAGE_GROUP_START 0
#define FIRST_PAGE_GROUP_END 0x100000
-#define P3_MAX_MTU (9600)
+#define P3P_MAX_MTU (9600)
+#define P3P_MIN_MTU (68)
#define QLCNIC_MAX_ETHERHDR 32 /* This contains some padding */
-#define QLCNIC_P3_RX_BUF_MAX_LEN (QLCNIC_MAX_ETHERHDR + ETH_DATA_LEN)
-#define QLCNIC_P3_RX_JUMBO_BUF_MAX_LEN (QLCNIC_MAX_ETHERHDR + P3_MAX_MTU)
+#define QLCNIC_P3P_RX_BUF_MAX_LEN (QLCNIC_MAX_ETHERHDR + ETH_DATA_LEN)
+#define QLCNIC_P3P_RX_JUMBO_BUF_MAX_LEN (QLCNIC_MAX_ETHERHDR + P3P_MAX_MTU)
#define QLCNIC_CT_DEFAULT_RX_BUF_LEN 2048
#define QLCNIC_LRO_BUFFER_EXTRA 2048
@@ -143,11 +146,14 @@
#define MAX_CMD_DESCRIPTORS 1024
#define MAX_RCV_DESCRIPTORS_1G 4096
#define MAX_RCV_DESCRIPTORS_10G 8192
+#define MAX_RCV_DESCRIPTORS_VF 2048
#define MAX_JUMBO_RCV_DESCRIPTORS_1G 512
#define MAX_JUMBO_RCV_DESCRIPTORS_10G 1024
#define DEFAULT_RCV_DESCRIPTORS_1G 2048
#define DEFAULT_RCV_DESCRIPTORS_10G 4096
+#define DEFAULT_RCV_DESCRIPTORS_VF 1024
+#define MAX_RDS_RINGS 2
#define get_next_index(index, length) \
(((index) + 1) & ((length) - 1))
@@ -172,7 +178,7 @@
((_desc)->port_ctxid = ((_port) & 0xf) | (((_port) << 4) & 0xf0))
#define qlcnic_set_tx_flags_opcode(_desc, _flags, _opcode) \
- ((_desc)->flags_opcode = \
+ ((_desc)->flags_opcode |= \
cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7)))
#define qlcnic_set_tx_frags_len(_desc, _frags, _len) \
@@ -221,7 +227,8 @@ struct rcv_desc {
#define QLCNIC_LRO_DESC 0x12
/* for status field in status_desc */
-#define STATUS_CKSUM_OK (2)
+#define STATUS_CKSUM_LOOP 0
+#define STATUS_CKSUM_OK 2
/* owner bits of status_desc */
#define STATUS_OWNER_HOST (0x1ULL << 56)
@@ -302,20 +309,20 @@ struct uni_data_desc{
/* Magic number to let user know flash is programmed */
#define QLCNIC_BDINFO_MAGIC 0x12345678
-#define QLCNIC_BRDTYPE_P3_REF_QG 0x0021
-#define QLCNIC_BRDTYPE_P3_HMEZ 0x0022
-#define QLCNIC_BRDTYPE_P3_10G_CX4_LP 0x0023
-#define QLCNIC_BRDTYPE_P3_4_GB 0x0024
-#define QLCNIC_BRDTYPE_P3_IMEZ 0x0025
-#define QLCNIC_BRDTYPE_P3_10G_SFP_PLUS 0x0026
-#define QLCNIC_BRDTYPE_P3_10000_BASE_T 0x0027
-#define QLCNIC_BRDTYPE_P3_XG_LOM 0x0028
-#define QLCNIC_BRDTYPE_P3_4_GB_MM 0x0029
-#define QLCNIC_BRDTYPE_P3_10G_SFP_CT 0x002a
-#define QLCNIC_BRDTYPE_P3_10G_SFP_QT 0x002b
-#define QLCNIC_BRDTYPE_P3_10G_CX4 0x0031
-#define QLCNIC_BRDTYPE_P3_10G_XFP 0x0032
-#define QLCNIC_BRDTYPE_P3_10G_TP 0x0080
+#define QLCNIC_BRDTYPE_P3P_REF_QG 0x0021
+#define QLCNIC_BRDTYPE_P3P_HMEZ 0x0022
+#define QLCNIC_BRDTYPE_P3P_10G_CX4_LP 0x0023
+#define QLCNIC_BRDTYPE_P3P_4_GB 0x0024
+#define QLCNIC_BRDTYPE_P3P_IMEZ 0x0025
+#define QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS 0x0026
+#define QLCNIC_BRDTYPE_P3P_10000_BASE_T 0x0027
+#define QLCNIC_BRDTYPE_P3P_XG_LOM 0x0028
+#define QLCNIC_BRDTYPE_P3P_4_GB_MM 0x0029
+#define QLCNIC_BRDTYPE_P3P_10G_SFP_CT 0x002a
+#define QLCNIC_BRDTYPE_P3P_10G_SFP_QT 0x002b
+#define QLCNIC_BRDTYPE_P3P_10G_CX4 0x0031
+#define QLCNIC_BRDTYPE_P3P_10G_XFP 0x0032
+#define QLCNIC_BRDTYPE_P3P_10G_TP 0x0080
#define QLCNIC_MSIX_TABLE_OFFSET 0x44
@@ -555,6 +562,8 @@ struct qlcnic_recv_context {
#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS 0x00000026
#define QLCNIC_CDRP_CMD_SET_PORTMIRRORING 0x00000027
#define QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH 0x00000028
+#define QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG 0x00000029
+#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATS 0x0000002a
#define QLCNIC_RCODE_SUCCESS 0
#define QLCNIC_RCODE_TIMEOUT 17
@@ -712,11 +721,13 @@ struct qlcnic_cardrsp_tx_ctx {
/* MAC */
-#define MC_COUNT_P3 38
+#define MC_COUNT_P3P 38
#define QLCNIC_MAC_NOOP 0
#define QLCNIC_MAC_ADD 1
#define QLCNIC_MAC_DEL 2
+#define QLCNIC_MAC_VLAN_ADD 3
+#define QLCNIC_MAC_VLAN_DEL 4
struct qlcnic_mac_list_s {
struct list_head list;
@@ -890,12 +901,28 @@ struct qlcnic_mac_req {
u8 mac_addr[6];
};
+struct qlcnic_vlan_req {
+ __le16 vlan_id;
+ __le16 rsvd[3];
+};
+
+struct qlcnic_ipaddr {
+ __be32 ipv4;
+ __be32 ipv6[4];
+};
+
#define QLCNIC_MSI_ENABLED 0x02
#define QLCNIC_MSIX_ENABLED 0x04
#define QLCNIC_LRO_ENABLED 0x08
+#define QLCNIC_LRO_DISABLED 0x00
#define QLCNIC_BRIDGE_ENABLED 0X10
#define QLCNIC_DIAG_ENABLED 0x20
#define QLCNIC_ESWITCH_ENABLED 0x40
+#define QLCNIC_ADAPTER_INITIALIZED 0x80
+#define QLCNIC_TAGGING_ENABLED 0x100
+#define QLCNIC_MACSPOOF 0x200
+#define QLCNIC_MAC_OVERRIDE_DISABLED 0x400
+#define QLCNIC_PROMISC_DISABLED 0x800
#define QLCNIC_IS_MSI_FAMILY(adapter) \
((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
@@ -916,6 +943,23 @@ struct qlcnic_mac_req {
#define QLCNIC_INTERRUPT_TEST 1
#define QLCNIC_LOOPBACK_TEST 2
+#define QLCNIC_FILTER_AGE 80
+#define QLCNIC_READD_AGE 20
+#define QLCNIC_LB_MAX_FILTERS 64
+
+struct qlcnic_filter {
+ struct hlist_node fnode;
+ u8 faddr[ETH_ALEN];
+ __le16 vlan_id;
+ unsigned long ftime;
+};
+
+struct qlcnic_filter_hash {
+ struct hlist_head *fhead;
+ u8 fnum;
+ u8 fmax;
+};
+
struct qlcnic_adapter {
struct qlcnic_hardware_context ahw;
@@ -924,14 +968,16 @@ struct qlcnic_adapter {
struct list_head mac_list;
spinlock_t tx_clean_lock;
+ spinlock_t mac_learn_lock;
u16 num_txd;
u16 num_rxd;
u16 num_jumbo_rxd;
+ u16 max_rxd;
+ u16 max_jumbo_rxd;
u8 max_rds_rings;
u8 max_sds_rings;
- u8 driver_mismatch;
u8 msix_supported;
u8 rx_csum;
u8 portnum;
@@ -961,6 +1007,7 @@ struct qlcnic_adapter {
u16 max_tx_ques;
u16 max_rx_ques;
u16 max_mtu;
+ u16 pvid;
u32 fw_hal_version;
u32 capabilities;
@@ -969,7 +1016,7 @@ struct qlcnic_adapter {
u32 temp;
u32 int_vec_bit;
- u32 heartbit;
+ u32 heartbeat;
u8 max_mac_filters;
u8 dev_state;
@@ -983,6 +1030,7 @@ struct qlcnic_adapter {
u64 dev_rst_time;
+ struct vlan_group *vlgrp;
struct qlcnic_npar_info *npars;
struct qlcnic_eswitch *eswitch;
struct qlcnic_nic_template *nic_ops;
@@ -1003,6 +1051,8 @@ struct qlcnic_adapter {
struct qlcnic_nic_intr_coalesce coal;
+ struct qlcnic_filter_hash fhash;
+
unsigned long state;
__le32 file_prd_off; /*File fw product offset*/
u32 fw_version;
@@ -1042,7 +1092,7 @@ struct qlcnic_pci_info {
};
struct qlcnic_npar_info {
- u16 vlan_id;
+ u16 pvid;
u16 min_bw;
u16 max_bw;
u8 phy_port;
@@ -1050,11 +1100,13 @@ struct qlcnic_npar_info {
u8 active;
u8 enable_pm;
u8 dest_npar;
- u8 host_vlan_tag;
- u8 promisc_mode;
u8 discard_tagged;
- u8 mac_learning;
+ u8 mac_override;
+ u8 mac_anti_spoof;
+ u8 promisc_mode;
+ u8 offload_flags;
};
+
struct qlcnic_eswitch {
u8 port;
u8 active_vports;
@@ -1082,11 +1134,10 @@ struct qlcnic_eswitch {
#define MAX_RX_QUEUES 4
#define DEFAULT_MAC_LEARN 1
-#define IS_VALID_VLAN(vlan) (vlan >= MIN_VLAN_ID && vlan <= MAX_VLAN_ID)
+#define IS_VALID_VLAN(vlan) (vlan >= MIN_VLAN_ID && vlan < MAX_VLAN_ID)
#define IS_VALID_BW(bw) (bw >= MIN_BW && bw <= MAX_BW)
#define IS_VALID_TX_QUEUES(que) (que > 0 && que <= MAX_TX_QUEUES)
#define IS_VALID_RX_QUEUES(que) (que > 0 && que <= MAX_RX_QUEUES)
-#define IS_VALID_MODE(mode) (mode == 0 || mode == 1)
struct qlcnic_pci_func_cfg {
u16 func_type;
@@ -1118,12 +1169,53 @@ struct qlcnic_pm_func_cfg {
struct qlcnic_esw_func_cfg {
u16 vlan_id;
+ u8 op_mode;
+ u8 op_type;
u8 pci_func;
u8 host_vlan_tag;
u8 promisc_mode;
u8 discard_tagged;
- u8 mac_learning;
- u8 reserved;
+ u8 mac_override;
+ u8 mac_anti_spoof;
+ u8 offload_flags;
+ u8 reserved[5];
+};
+
+#define QLCNIC_STATS_VERSION 1
+#define QLCNIC_STATS_PORT 1
+#define QLCNIC_STATS_ESWITCH 2
+#define QLCNIC_QUERY_RX_COUNTER 0
+#define QLCNIC_QUERY_TX_COUNTER 1
+#define QLCNIC_ESW_STATS_NOT_AVAIL 0xffffffffffffffffULL
+
+#define QLCNIC_ADD_ESW_STATS(VAL1, VAL2)\
+do { \
+ if (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) && \
+ ((VAL2) != QLCNIC_ESW_STATS_NOT_AVAIL)) \
+ (VAL1) = (VAL2); \
+ else if (((VAL1) != QLCNIC_ESW_STATS_NOT_AVAIL) && \
+ ((VAL2) != QLCNIC_ESW_STATS_NOT_AVAIL)) \
+ (VAL1) += (VAL2); \
+} while (0)
+
+struct __qlcnic_esw_statistics {
+ __le16 context_id;
+ __le16 version;
+ __le16 size;
+ __le16 unused;
+ __le64 unicast_frames;
+ __le64 multicast_frames;
+ __le64 broadcast_frames;
+ __le64 dropped_frames;
+ __le64 errors;
+ __le64 local_frames;
+ __le64 numbytes;
+ __le64 rsvd[3];
+};
+
+struct qlcnic_esw_statistics {
+ struct __qlcnic_esw_statistics rx;
+ struct __qlcnic_esw_statistics tx;
};
int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val);
@@ -1171,6 +1263,8 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
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);
+void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter);
+void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter);
/* Functions from qlcnic_init.c */
int qlcnic_load_firmware(struct qlcnic_adapter *adapter);
@@ -1199,7 +1293,7 @@ void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter);
void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter);
void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter);
-int qlcnic_init_firmware(struct qlcnic_adapter *adapter);
+int qlcnic_check_fw_status(struct qlcnic_adapter *adapter);
void qlcnic_watchdog_task(struct work_struct *work);
void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid,
struct qlcnic_host_rds_ring *rds_ring);
@@ -1209,7 +1303,7 @@ void qlcnic_free_mac_list(struct qlcnic_adapter *adapter);
int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32);
int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter);
int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable);
-int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, u32 ip, int cmd);
+int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int cmd);
int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable);
void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup);
@@ -1220,12 +1314,13 @@ int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable);
int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
struct qlcnic_host_tx_ring *tx_ring);
-int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u8 *mac);
void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter);
int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter);
void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *);
/* Functions from qlcnic_main.c */
+int qlcnic_request_quiscent_mode(struct qlcnic_adapter *adapter);
+void qlcnic_clear_quiscent_mode(struct qlcnic_adapter *adapter);
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);
@@ -1236,22 +1331,22 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
/* Management functions */
-int qlcnic_set_mac_address(struct qlcnic_adapter *, u8*);
int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
int qlcnic_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
int qlcnic_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
int qlcnic_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*);
-int qlcnic_reset_partition(struct qlcnic_adapter *, u8);
/* eSwitch management functions */
-int qlcnic_get_eswitch_capabilities(struct qlcnic_adapter *, u8,
- struct qlcnic_eswitch *);
-int qlcnic_get_eswitch_status(struct qlcnic_adapter *, u8,
- struct qlcnic_eswitch *);
-int qlcnic_toggle_eswitch(struct qlcnic_adapter *, u8, u8);
-int qlcnic_config_switch_port(struct qlcnic_adapter *, u8, int, u8, u8,
- u8, u8, u16);
+int qlcnic_config_switch_port(struct qlcnic_adapter *,
+ struct qlcnic_esw_func_cfg *);
+int qlcnic_get_eswitch_port_config(struct qlcnic_adapter *,
+ struct qlcnic_esw_func_cfg *);
int qlcnic_config_port_mirroring(struct qlcnic_adapter *, u8, u8, u8);
+int qlcnic_get_port_stats(struct qlcnic_adapter *, const u8, const u8,
+ struct __qlcnic_esw_statistics *);
+int qlcnic_get_eswitch_stats(struct qlcnic_adapter *, const u8, u8,
+ struct __qlcnic_esw_statistics *);
+int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, u8, u8, u8);
extern int qlcnic_config_tso;
/*
@@ -1280,6 +1375,8 @@ static const struct qlcnic_brdinfo qlcnic_boards[] = {
"3200 Series Quad Port 1Gb Intelligent Ethernet Adapter"},
{0x1077, 0x8020, 0x1077, 0x20f,
"3200 Series Single Port 10Gb Intelligent Ethernet Adapter"},
+ {0x1077, 0x8020, 0x103c, 0x3733,
+ "NC523SFP 10Gb 2-port Server Adapter"},
{0x1077, 0x8020, 0x0, 0x0, "cLOM8214 1/10GbE Controller"},
};
@@ -1298,7 +1395,6 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
extern const struct ethtool_ops qlcnic_ethtool_ops;
struct qlcnic_nic_template {
- int (*get_mac_addr) (struct qlcnic_adapter *, u8*);
int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
int (*config_led) (struct qlcnic_adapter *, u32, u32);
int (*start_firmware) (struct qlcnic_adapter *);
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
index cc5d861d9a12..1cdc05dade6b 100644
--- a/drivers/net/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/qlcnic/qlcnic_ctx.c
@@ -556,32 +556,6 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
}
}
-/* Set MAC address of a NIC partition */
-int qlcnic_set_mac_address(struct qlcnic_adapter *adapter, u8* mac)
-{
- int err = 0;
- u32 arg1, arg2, arg3;
-
- arg1 = adapter->ahw.pci_func | BIT_9;
- arg2 = mac[0] | (mac[1] << 8) | (mac[2] << 16) | (mac[3] << 24);
- arg3 = mac[4] | (mac[5] << 16);
-
- err = qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
- adapter->fw_hal_version,
- arg1,
- arg2,
- arg3,
- QLCNIC_CDRP_CMD_MAC_ADDRESS);
-
- if (err != QLCNIC_RCODE_SUCCESS) {
- dev_err(&adapter->pdev->dev,
- "Failed to set mac address%d\n", err);
- err = -EIO;
- }
-
- return err;
-}
/* Get MAC address of a NIC partition */
int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
@@ -742,15 +716,15 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
if (err == QLCNIC_RCODE_SUCCESS) {
for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++, pci_info++) {
- pci_info->id = le32_to_cpu(npar->id);
- pci_info->active = le32_to_cpu(npar->active);
- pci_info->type = le32_to_cpu(npar->type);
+ pci_info->id = le16_to_cpu(npar->id);
+ pci_info->active = le16_to_cpu(npar->active);
+ pci_info->type = le16_to_cpu(npar->type);
pci_info->default_port =
- le32_to_cpu(npar->default_port);
+ le16_to_cpu(npar->default_port);
pci_info->tx_min_bw =
- le32_to_cpu(npar->tx_min_bw);
+ le16_to_cpu(npar->tx_min_bw);
pci_info->tx_max_bw =
- le32_to_cpu(npar->tx_max_bw);
+ le16_to_cpu(npar->tx_max_bw);
memcpy(pci_info->mac, npar->mac, ETH_ALEN);
}
} else {
@@ -764,222 +738,319 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
return err;
}
-/* Reset a NIC partition */
-
-int qlcnic_reset_partition(struct qlcnic_adapter *adapter, u8 func_no)
+/* Configure eSwitch for port mirroring */
+int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
+ u8 enable_mirroring, u8 pci_func)
{
int err = -EIO;
+ u32 arg1;
- if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC ||
+ !(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE))
return err;
+ arg1 = id | (enable_mirroring ? BIT_4 : 0);
+ arg1 |= pci_func << 8;
+
err = qlcnic_issue_cmd(adapter,
adapter->ahw.pci_func,
adapter->fw_hal_version,
- func_no,
+ arg1,
0,
0,
- QLCNIC_CDRP_CMD_RESET_NPAR);
+ QLCNIC_CDRP_CMD_SET_PORTMIRRORING);
if (err != QLCNIC_RCODE_SUCCESS) {
dev_err(&adapter->pdev->dev,
- "Failed to issue reset partition%d\n", err);
- err = -EIO;
+ "Failed to configure port mirroring%d on eswitch:%d\n",
+ pci_func, id);
+ } else {
+ dev_info(&adapter->pdev->dev,
+ "Configured eSwitch %d for port mirroring:%d\n",
+ id, pci_func);
}
return err;
}
-/* Get eSwitch Capabilities */
-int qlcnic_get_eswitch_capabilities(struct qlcnic_adapter *adapter, u8 port,
- struct qlcnic_eswitch *eswitch)
-{
- int err = -EIO;
- u32 arg1, arg2;
+int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
+ const u8 rx_tx, struct __qlcnic_esw_statistics *esw_stats) {
- if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
- return err;
+ size_t stats_size = sizeof(struct __qlcnic_esw_statistics);
+ struct __qlcnic_esw_statistics *stats;
+ dma_addr_t stats_dma_t;
+ void *stats_addr;
+ u32 arg1;
+ int err;
- err = qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
- adapter->fw_hal_version,
- port,
- 0,
- 0,
- QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY);
+ if (esw_stats == NULL)
+ return -ENOMEM;
- if (err == QLCNIC_RCODE_SUCCESS) {
- arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
- arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
-
- eswitch->port = arg1 & 0xf;
- eswitch->active_vports = LSB(arg2);
- eswitch->max_ucast_filters = MSB(arg2);
- eswitch->max_active_vlans = LSB(MSW(arg2));
- if (arg1 & BIT_6)
- eswitch->flags |= QLCNIC_SWITCH_VLAN_FILTERING;
- if (arg1 & BIT_7)
- eswitch->flags |= QLCNIC_SWITCH_PROMISC_MODE;
- if (arg1 & BIT_8)
- eswitch->flags |= QLCNIC_SWITCH_PORT_MIRRORING;
- } else {
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC &&
+ func != adapter->ahw.pci_func) {
dev_err(&adapter->pdev->dev,
- "Failed to get eswitch capabilities%d\n", err);
+ "Not privilege to query stats for func=%d", func);
+ return -EIO;
}
- return err;
-}
-
-/* Get current status of eswitch */
-int qlcnic_get_eswitch_status(struct qlcnic_adapter *adapter, u8 port,
- struct qlcnic_eswitch *eswitch)
-{
- int err = -EIO;
- u32 arg1, arg2;
+ stats_addr = pci_alloc_consistent(adapter->pdev, stats_size,
+ &stats_dma_t);
+ if (!stats_addr) {
+ dev_err(&adapter->pdev->dev, "Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+ memset(stats_addr, 0, stats_size);
- if (adapter->op_mode != QLCNIC_MGMT_FUNC)
- return err;
+ 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,
- port,
- 0,
- 0,
- QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS);
-
- if (err == QLCNIC_RCODE_SUCCESS) {
- arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
- arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
-
- eswitch->port = arg1 & 0xf;
- eswitch->active_vports = LSB(arg2);
- eswitch->active_ucast_filters = MSB(arg2);
- eswitch->active_vlans = LSB(MSW(arg2));
- if (arg1 & BIT_6)
- eswitch->flags |= QLCNIC_SWITCH_VLAN_FILTERING;
- if (arg1 & BIT_8)
- eswitch->flags |= QLCNIC_SWITCH_PORT_MIRRORING;
-
- } else {
- dev_err(&adapter->pdev->dev,
- "Failed to get eswitch status%d\n", err);
+ arg1,
+ MSD(stats_dma_t),
+ LSD(stats_dma_t),
+ QLCNIC_CDRP_CMD_GET_ESWITCH_STATS);
+
+ if (!err) {
+ stats = (struct __qlcnic_esw_statistics *)stats_addr;
+ esw_stats->context_id = le16_to_cpu(stats->context_id);
+ esw_stats->version = le16_to_cpu(stats->version);
+ esw_stats->size = le16_to_cpu(stats->size);
+ esw_stats->multicast_frames =
+ le64_to_cpu(stats->multicast_frames);
+ esw_stats->broadcast_frames =
+ le64_to_cpu(stats->broadcast_frames);
+ esw_stats->unicast_frames = le64_to_cpu(stats->unicast_frames);
+ esw_stats->dropped_frames = le64_to_cpu(stats->dropped_frames);
+ esw_stats->local_frames = le64_to_cpu(stats->local_frames);
+ esw_stats->errors = le64_to_cpu(stats->errors);
+ esw_stats->numbytes = le64_to_cpu(stats->numbytes);
}
+ pci_free_consistent(adapter->pdev, stats_size, stats_addr,
+ stats_dma_t);
return err;
}
-/* Enable/Disable eSwitch */
-int qlcnic_toggle_eswitch(struct qlcnic_adapter *adapter, u8 id, u8 enable)
+int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch,
+ const u8 rx_tx, struct __qlcnic_esw_statistics *esw_stats) {
+
+ struct __qlcnic_esw_statistics port_stats;
+ u8 i;
+ int ret = -EIO;
+
+ if (esw_stats == NULL)
+ return -ENOMEM;
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return -EIO;
+ if (adapter->npars == NULL)
+ return -EIO;
+
+ memset(esw_stats, 0, sizeof(u64));
+ esw_stats->unicast_frames = QLCNIC_ESW_STATS_NOT_AVAIL;
+ esw_stats->multicast_frames = QLCNIC_ESW_STATS_NOT_AVAIL;
+ esw_stats->broadcast_frames = QLCNIC_ESW_STATS_NOT_AVAIL;
+ esw_stats->dropped_frames = QLCNIC_ESW_STATS_NOT_AVAIL;
+ esw_stats->errors = QLCNIC_ESW_STATS_NOT_AVAIL;
+ esw_stats->local_frames = QLCNIC_ESW_STATS_NOT_AVAIL;
+ esw_stats->numbytes = QLCNIC_ESW_STATS_NOT_AVAIL;
+ esw_stats->context_id = eswitch;
+
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+ if (adapter->npars[i].phy_port != eswitch)
+ continue;
+
+ memset(&port_stats, 0, sizeof(struct __qlcnic_esw_statistics));
+ if (qlcnic_get_port_stats(adapter, i, rx_tx, &port_stats))
+ continue;
+
+ esw_stats->size = port_stats.size;
+ esw_stats->version = port_stats.version;
+ QLCNIC_ADD_ESW_STATS(esw_stats->unicast_frames,
+ port_stats.unicast_frames);
+ QLCNIC_ADD_ESW_STATS(esw_stats->multicast_frames,
+ port_stats.multicast_frames);
+ QLCNIC_ADD_ESW_STATS(esw_stats->broadcast_frames,
+ port_stats.broadcast_frames);
+ QLCNIC_ADD_ESW_STATS(esw_stats->dropped_frames,
+ port_stats.dropped_frames);
+ QLCNIC_ADD_ESW_STATS(esw_stats->errors,
+ port_stats.errors);
+ QLCNIC_ADD_ESW_STATS(esw_stats->local_frames,
+ port_stats.local_frames);
+ QLCNIC_ADD_ESW_STATS(esw_stats->numbytes,
+ port_stats.numbytes);
+ ret = 0;
+ }
+ return ret;
+}
+
+int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,
+ const u8 port, const u8 rx_tx)
{
- int err = -EIO;
- u32 arg1, arg2;
- struct qlcnic_eswitch *eswitch;
+
+ u32 arg1;
if (adapter->op_mode != QLCNIC_MGMT_FUNC)
- return err;
+ return -EIO;
- eswitch = &adapter->eswitch[id];
- if (!eswitch)
- return err;
+ if (func_esw == QLCNIC_STATS_PORT) {
+ if (port >= QLCNIC_MAX_PCI_FUNC)
+ goto err_ret;
+ } else if (func_esw == QLCNIC_STATS_ESWITCH) {
+ if (port >= QLCNIC_NIU_MAX_XG_PORTS)
+ goto err_ret;
+ } else {
+ goto err_ret;
+ }
- arg1 = eswitch->port | (enable ? BIT_4 : 0);
- arg2 = eswitch->active_vports | (eswitch->max_ucast_filters << 8) |
- (eswitch->max_active_vlans << 16);
- err = qlcnic_issue_cmd(adapter,
+ if (rx_tx > QLCNIC_QUERY_TX_COUNTER)
+ goto err_ret;
+
+ 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,
- arg2,
0,
- QLCNIC_CDRP_CMD_TOGGLE_ESWITCH);
-
- if (err != QLCNIC_RCODE_SUCCESS) {
- dev_err(&adapter->pdev->dev,
- "Failed to enable eswitch%d\n", eswitch->port);
- eswitch->flags &= ~QLCNIC_SWITCH_ENABLE;
- err = -EIO;
- } else {
- eswitch->flags |= QLCNIC_SWITCH_ENABLE;
- dev_info(&adapter->pdev->dev,
- "Enabled eSwitch for port %d\n", eswitch->port);
- }
+ 0,
+ QLCNIC_CDRP_CMD_GET_ESWITCH_STATS);
- return err;
+err_ret:
+ dev_err(&adapter->pdev->dev, "Invalid argument func_esw=%d port=%d"
+ "rx_ctx=%d\n", func_esw, port, rx_tx);
+ return -EIO;
}
-/* Configure eSwitch for port mirroring */
-int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
- u8 enable_mirroring, u8 pci_func)
+static int
+__qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
+ u32 *arg1, u32 *arg2)
{
int err = -EIO;
- u32 arg1;
-
- if (adapter->op_mode != QLCNIC_MGMT_FUNC ||
- !(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE))
- return err;
-
- arg1 = id | (enable_mirroring ? BIT_4 : 0);
- arg1 |= pci_func << 8;
-
+ u8 pci_func;
+ pci_func = (*arg1 >> 8);
err = qlcnic_issue_cmd(adapter,
adapter->ahw.pci_func,
adapter->fw_hal_version,
- arg1,
+ *arg1,
0,
0,
- QLCNIC_CDRP_CMD_SET_PORTMIRRORING);
+ QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG);
- if (err != QLCNIC_RCODE_SUCCESS) {
- dev_err(&adapter->pdev->dev,
- "Failed to configure port mirroring%d on eswitch:%d\n",
- pci_func, id);
- } else {
+ if (err == QLCNIC_RCODE_SUCCESS) {
+ *arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+ *arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
dev_info(&adapter->pdev->dev,
- "Configured eSwitch %d for port mirroring:%d\n",
- id, pci_func);
+ "eSwitch port config for pci func %d\n", pci_func);
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get eswitch port config for pci func %d\n",
+ pci_func);
}
-
return err;
}
-
-/* Configure eSwitch port */
-int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, u8 id,
- int vlan_tagging, u8 discard_tagged, u8 promsc_mode,
- u8 mac_learn, u8 pci_func, u16 vlan_id)
+/* Configure eSwitch port
+op_mode = 0 for setting default port behavior
+op_mode = 1 for setting vlan id
+op_mode = 2 for deleting vlan id
+op_type = 0 for vlan_id
+op_type = 1 for port vlan_id
+*/
+int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
+ struct qlcnic_esw_func_cfg *esw_cfg)
{
int err = -EIO;
- u32 arg1;
- struct qlcnic_eswitch *eswitch;
+ u32 arg1, arg2 = 0;
+ u8 pci_func;
if (adapter->op_mode != QLCNIC_MGMT_FUNC)
return err;
+ pci_func = esw_cfg->pci_func;
+ arg1 = (adapter->npars[pci_func].phy_port & BIT_0);
+ arg1 |= (pci_func << 8);
- eswitch = &adapter->eswitch[id];
- if (!(eswitch->flags & QLCNIC_SWITCH_ENABLE))
+ if (__qlcnic_get_eswitch_port_config(adapter, &arg1, &arg2))
return err;
-
- arg1 = eswitch->port | (discard_tagged ? BIT_4 : 0);
- arg1 |= (promsc_mode ? BIT_6 : 0) | (mac_learn ? BIT_7 : 0);
- arg1 |= pci_func << 8;
- if (vlan_tagging)
- arg1 |= BIT_5 | (vlan_id << 16);
+ arg1 &= ~(0x0ff << 8);
+ arg1 |= (pci_func << 8);
+ arg1 &= ~(BIT_2 | BIT_3);
+ switch (esw_cfg->op_mode) {
+ case QLCNIC_PORT_DEFAULTS:
+ arg1 |= (BIT_4 | BIT_6 | BIT_7);
+ arg2 |= (BIT_0 | BIT_1);
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO)
+ arg2 |= (BIT_2 | BIT_3);
+ if (!(esw_cfg->discard_tagged))
+ arg1 &= ~BIT_4;
+ if (!(esw_cfg->promisc_mode))
+ arg1 &= ~BIT_6;
+ if (!(esw_cfg->mac_override))
+ arg1 &= ~BIT_7;
+ if (!(esw_cfg->mac_anti_spoof))
+ arg2 &= ~BIT_0;
+ if (!(esw_cfg->offload_flags & BIT_0))
+ arg2 &= ~(BIT_1 | BIT_2 | BIT_3);
+ if (!(esw_cfg->offload_flags & BIT_1))
+ arg2 &= ~BIT_2;
+ if (!(esw_cfg->offload_flags & BIT_2))
+ arg2 &= ~BIT_3;
+ break;
+ case QLCNIC_ADD_VLAN:
+ arg1 |= (BIT_2 | BIT_5);
+ arg1 |= (esw_cfg->vlan_id << 16);
+ break;
+ case QLCNIC_DEL_VLAN:
+ arg1 |= (BIT_3 | BIT_5);
+ arg1 &= ~(0x0ffff << 16);
+ break;
+ default:
+ return err;
+ }
err = qlcnic_issue_cmd(adapter,
adapter->ahw.pci_func,
adapter->fw_hal_version,
arg1,
- 0,
+ arg2,
0,
QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH);
if (err != QLCNIC_RCODE_SUCCESS) {
dev_err(&adapter->pdev->dev,
- "Failed to configure eswitch port%d\n", eswitch->port);
+ "Failed to configure eswitch pci func %d\n", pci_func);
} else {
dev_info(&adapter->pdev->dev,
- "Configured eSwitch for port %d\n", eswitch->port);
+ "Configured eSwitch for pci func %d\n", pci_func);
}
return err;
}
+
+int
+qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
+ struct qlcnic_esw_func_cfg *esw_cfg)
+{
+ u32 arg1, arg2;
+ u8 phy_port;
+ if (adapter->op_mode == QLCNIC_MGMT_FUNC)
+ phy_port = adapter->npars[esw_cfg->pci_func].phy_port;
+ else
+ phy_port = adapter->physical_port;
+ arg1 = phy_port;
+ arg1 |= (esw_cfg->pci_func << 8);
+ if (__qlcnic_get_eswitch_port_config(adapter, &arg1, &arg2))
+ return -EIO;
+
+ esw_cfg->discard_tagged = !!(arg1 & BIT_4);
+ esw_cfg->host_vlan_tag = !!(arg1 & BIT_5);
+ esw_cfg->promisc_mode = !!(arg1 & BIT_6);
+ esw_cfg->mac_override = !!(arg1 & BIT_7);
+ esw_cfg->vlan_id = LSW(arg1 >> 16);
+ esw_cfg->mac_anti_spoof = (arg2 & 0x1);
+ esw_cfg->offload_flags = ((arg2 >> 1) & 0x7);
+
+ return 0;
+}
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 9328d59e21e0..ec21d24015c4 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -78,7 +78,25 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
};
+static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
+ "rx unicast frames",
+ "rx multicast frames",
+ "rx broadcast frames",
+ "rx dropped frames",
+ "rx errors",
+ "rx local frames",
+ "rx numbytes",
+ "tx unicast frames",
+ "tx multicast frames",
+ "tx broadcast frames",
+ "tx dropped frames",
+ "tx errors",
+ "tx local frames",
+ "tx numbytes",
+};
+
#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
+#define QLCNIC_DEVICE_STATS_LEN ARRAY_SIZE(qlcnic_device_gstrings_stats)
static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
"Register_Test_on_offline",
@@ -96,10 +114,10 @@ static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
static const u32 diag_registers[] = {
CRB_CMDPEG_STATE,
CRB_RCVPEG_STATE,
- CRB_XG_STATE_P3,
+ CRB_XG_STATE_P3P,
CRB_FW_CAPABILITIES_1,
ISR_INT_STATE_REG,
- QLCNIC_CRB_DEV_REF_COUNT,
+ QLCNIC_CRB_DRV_ACTIVE,
QLCNIC_CRB_DEV_STATE,
QLCNIC_CRB_DRV_STATE,
QLCNIC_CRB_DRV_SCRATCH,
@@ -115,9 +133,13 @@ static const u32 diag_registers[] = {
-1
};
+#define QLCNIC_MGMT_API_VERSION 2
+#define QLCNIC_DEV_INFO_SIZE 1
+#define QLCNIC_ETHTOOL_REGS_VER 2
static int qlcnic_get_regs_len(struct net_device *dev)
{
- return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN;
+ return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN +
+ QLCNIC_DEV_INFO_SIZE + 1;
}
static int qlcnic_get_eeprom_len(struct net_device *dev)
@@ -185,9 +207,9 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
goto skip;
}
- val = QLCRD32(adapter, P3_LINK_SPEED_REG(pcifn));
- ecmd->speed = P3_LINK_SPEED_MHZ *
- P3_LINK_SPEED_VAL(pcifn, val);
+ val = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn));
+ ecmd->speed = P3P_LINK_SPEED_MHZ *
+ P3P_LINK_SPEED_VAL(pcifn, val);
ecmd->duplex = DUPLEX_FULL;
ecmd->autoneg = AUTONEG_DISABLE;
} else
@@ -198,42 +220,42 @@ skip:
ecmd->transceiver = XCVR_EXTERNAL;
switch (adapter->ahw.board_type) {
- case QLCNIC_BRDTYPE_P3_REF_QG:
- case QLCNIC_BRDTYPE_P3_4_GB:
- case QLCNIC_BRDTYPE_P3_4_GB_MM:
+ case QLCNIC_BRDTYPE_P3P_REF_QG:
+ case QLCNIC_BRDTYPE_P3P_4_GB:
+ case QLCNIC_BRDTYPE_P3P_4_GB_MM:
ecmd->supported |= SUPPORTED_Autoneg;
ecmd->advertising |= ADVERTISED_Autoneg;
- case QLCNIC_BRDTYPE_P3_10G_CX4:
- case QLCNIC_BRDTYPE_P3_10G_CX4_LP:
- case QLCNIC_BRDTYPE_P3_10000_BASE_T:
+ case QLCNIC_BRDTYPE_P3P_10G_CX4:
+ case QLCNIC_BRDTYPE_P3P_10G_CX4_LP:
+ case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
ecmd->supported |= SUPPORTED_TP;
ecmd->advertising |= ADVERTISED_TP;
ecmd->port = PORT_TP;
ecmd->autoneg = adapter->link_autoneg;
break;
- case QLCNIC_BRDTYPE_P3_IMEZ:
- case QLCNIC_BRDTYPE_P3_XG_LOM:
- case QLCNIC_BRDTYPE_P3_HMEZ:
+ case QLCNIC_BRDTYPE_P3P_IMEZ:
+ case QLCNIC_BRDTYPE_P3P_XG_LOM:
+ case QLCNIC_BRDTYPE_P3P_HMEZ:
ecmd->supported |= SUPPORTED_MII;
ecmd->advertising |= ADVERTISED_MII;
ecmd->port = PORT_MII;
ecmd->autoneg = AUTONEG_DISABLE;
break;
- case QLCNIC_BRDTYPE_P3_10G_SFP_PLUS:
- case QLCNIC_BRDTYPE_P3_10G_SFP_CT:
- case QLCNIC_BRDTYPE_P3_10G_SFP_QT:
+ case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS:
+ case QLCNIC_BRDTYPE_P3P_10G_SFP_CT:
+ case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
ecmd->advertising |= ADVERTISED_TP;
ecmd->supported |= SUPPORTED_TP;
check_sfp_module = netif_running(dev) &&
adapter->has_link_events;
- case QLCNIC_BRDTYPE_P3_10G_XFP:
+ case QLCNIC_BRDTYPE_P3P_10G_XFP:
ecmd->supported |= SUPPORTED_FIBRE;
ecmd->advertising |= ADVERTISED_FIBRE;
ecmd->port = PORT_FIBRE;
ecmd->autoneg = AUTONEG_DISABLE;
break;
- case QLCNIC_BRDTYPE_P3_10G_TP:
+ case QLCNIC_BRDTYPE_P3P_10G_TP:
if (adapter->ahw.port_type == QLCNIC_XGBE) {
ecmd->autoneg = AUTONEG_DISABLE;
ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
@@ -339,14 +361,17 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
struct qlcnic_host_sds_ring *sds_ring;
u32 *regs_buff = p;
- int ring, i = 0;
+ int ring, i = 0, j = 0;
memset(p, 0, qlcnic_get_regs_len(dev));
- regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) |
- (adapter->pdev)->device;
+ regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
+ (adapter->ahw.revision_id << 16) | (adapter->pdev)->device;
+
+ regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
+ regs_buff[1] = QLCNIC_MGMT_API_VERSION;
- for (i = 0; diag_registers[i] != -1; i++)
- regs_buff[i] = QLCRD32(adapter, diag_registers[i]);
+ for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
+ regs_buff[i] = QLCRD32(adapter, diag_registers[j]);
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
return;
@@ -374,9 +399,9 @@ static u32 qlcnic_test_link(struct net_device *dev)
struct qlcnic_adapter *adapter = netdev_priv(dev);
u32 val;
- val = QLCRD32(adapter, CRB_XG_STATE_P3);
- val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val);
- return (val == XG_LINK_UP_P3) ? 0 : 1;
+ val = QLCRD32(adapter, CRB_XG_STATE_P3P);
+ val = XG_LINK_STATE_P3P(adapter->ahw.pci_func, val);
+ return (val == XG_LINK_UP_P3P) ? 0 : 1;
}
static int
@@ -412,14 +437,8 @@ qlcnic_get_ringparam(struct net_device *dev,
ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
ring->tx_pending = adapter->num_txd;
- if (adapter->ahw.port_type == QLCNIC_GBE) {
- ring->rx_max_pending = MAX_RCV_DESCRIPTORS_1G;
- ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_1G;
- } else {
- ring->rx_max_pending = MAX_RCV_DESCRIPTORS_10G;
- ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_10G;
- }
-
+ 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;
@@ -447,24 +466,17 @@ qlcnic_set_ringparam(struct net_device *dev,
struct ethtool_ringparam *ring)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
- u16 max_rcv_desc = MAX_RCV_DESCRIPTORS_10G;
- u16 max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
u16 num_rxd, num_jumbo_rxd, num_txd;
-
if (ring->rx_mini_pending)
return -EOPNOTSUPP;
- if (adapter->ahw.port_type == QLCNIC_GBE) {
- max_rcv_desc = MAX_RCV_DESCRIPTORS_1G;
- max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
- }
-
num_rxd = qlcnic_validate_ringparam(ring->rx_pending,
- MIN_RCV_DESCRIPTORS, max_rcv_desc, "rx");
+ MIN_RCV_DESCRIPTORS, adapter->max_rxd, "rx");
num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending,
- MIN_JUMBO_DESCRIPTORS, max_jumbo_desc, "rx jumbo");
+ MIN_JUMBO_DESCRIPTORS, adapter->max_jumbo_rxd,
+ "rx jumbo");
num_txd = qlcnic_validate_ringparam(ring->tx_pending,
MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
@@ -618,10 +630,13 @@ static int qlcnic_reg_test(struct net_device *dev)
static int qlcnic_get_sset_count(struct net_device *dev, int sset)
{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
switch (sset) {
case ETH_SS_TEST:
return QLCNIC_TEST_LEN;
case ETH_SS_STATS:
+ if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
+ return QLCNIC_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
return QLCNIC_STATS_LEN;
default:
return -EOPNOTSUPP;
@@ -629,6 +644,8 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset)
}
#define QLC_ILB_PKT_SIZE 64
+#define QLC_NUM_ILB_PKT 16
+#define QLC_ILB_MAX_RCV_LOOP 10
static void qlcnic_create_loopback_buff(unsigned char *data)
{
@@ -650,24 +667,34 @@ static int qlcnic_do_ilb_test(struct qlcnic_adapter *adapter)
struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
struct sk_buff *skb;
- int i;
+ int i, loop, cnt = 0;
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < QLC_NUM_ILB_PKT; i++) {
skb = dev_alloc_skb(QLC_ILB_PKT_SIZE);
qlcnic_create_loopback_buff(skb->data);
skb_put(skb, QLC_ILB_PKT_SIZE);
adapter->diag_cnt = 0;
-
qlcnic_xmit_frame(skb, adapter->netdev);
- msleep(5);
-
- qlcnic_process_rcv_ring_diag(sds_ring);
+ loop = 0;
+ do {
+ msleep(1);
+ qlcnic_process_rcv_ring_diag(sds_ring);
+ } while (loop++ < QLC_ILB_MAX_RCV_LOOP &&
+ !adapter->diag_cnt);
dev_kfree_skb_any(skb);
+
if (!adapter->diag_cnt)
- return -1;
+ dev_warn(&adapter->pdev->dev, "ILB Test: %dth packet"
+ " not recevied\n", i + 1);
+ else
+ cnt++;
+ }
+ if (cnt != i) {
+ dev_warn(&adapter->pdev->dev, "ILB Test failed\n");
+ return -1;
}
return 0;
}
@@ -687,6 +714,11 @@ static int qlcnic_loopback_test(struct net_device *netdev)
if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
return -EIO;
+ if (qlcnic_request_quiscent_mode(adapter)) {
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ return -EIO;
+ }
+
ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
if (ret)
goto clear_it;
@@ -703,6 +735,7 @@ done:
qlcnic_diag_free_res(netdev, max_sds_rings);
clear_it:
+ qlcnic_clear_quiscent_mode(adapter);
adapter->max_sds_rings = max_sds_rings;
clear_bit(__QLCNIC_RESETTING, &adapter->state);
return ret;
@@ -747,6 +780,14 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
{
memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
+ data[0] = qlcnic_reg_test(dev);
+ if (data[0])
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ data[1] = (u64) qlcnic_test_link(dev);
+ if (data[1])
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
data[2] = qlcnic_irq_test(dev);
if (data[2])
@@ -757,21 +798,13 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
eth_test->flags |= ETH_TEST_FL_FAILED;
}
-
- data[0] = qlcnic_reg_test(dev);
- if (data[0])
- eth_test->flags |= ETH_TEST_FL_FAILED;
-
- /* link test */
- data[1] = (u64) qlcnic_test_link(dev);
- if (data[1])
- eth_test->flags |= ETH_TEST_FL_FAILED;
}
static void
qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
{
- int index;
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ int index, i;
switch (stringset) {
case ETH_SS_TEST:
@@ -784,16 +817,43 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
qlcnic_gstrings_stats[index].stat_string,
ETH_GSTRING_LEN);
}
- break;
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
+ return;
+ for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
+ memcpy(data + index * ETH_GSTRING_LEN,
+ qlcnic_device_gstrings_stats[i],
+ ETH_GSTRING_LEN);
+ }
}
}
+#define QLCNIC_FILL_ESWITCH_STATS(VAL1) \
+ (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) ? 0 : VAL1)
+
+static void
+qlcnic_fill_device_stats(int *index, u64 *data,
+ struct __qlcnic_esw_statistics *stats)
+{
+ int ind = *index;
+
+ data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->unicast_frames);
+ data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->multicast_frames);
+ data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->broadcast_frames);
+ data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->dropped_frames);
+ data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->errors);
+ data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->local_frames);
+ data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->numbytes);
+
+ *index = ind;
+}
+
static void
qlcnic_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 * data)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
- int index;
+ struct qlcnic_esw_statistics port_stats;
+ int index, ret;
for (index = 0; index < QLCNIC_STATS_LEN; index++) {
char *p =
@@ -803,8 +863,40 @@ qlcnic_get_ethtool_stats(struct net_device *dev,
(qlcnic_gstrings_stats[index].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
}
+
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
+ return;
+
+ memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics));
+ ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func,
+ QLCNIC_QUERY_RX_COUNTER, &port_stats.rx);
+ if (ret)
+ return;
+
+ qlcnic_fill_device_stats(&index, data, &port_stats.rx);
+
+ ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func,
+ QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
+ if (ret)
+ return;
+
+ qlcnic_fill_device_stats(&index, data, &port_stats.tx);
}
+static int qlcnic_set_tx_csum(struct net_device *dev, u32 data)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+ if ((adapter->flags & QLCNIC_ESWITCH_ENABLED))
+ return -EOPNOTSUPP;
+ if (data)
+ dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+ else
+ dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+
+ return 0;
+
+}
static u32 qlcnic_get_tx_csum(struct net_device *dev)
{
return dev->features & NETIF_F_IP_CSUM;
@@ -819,7 +911,23 @@ static u32 qlcnic_get_rx_csum(struct net_device *dev)
static int qlcnic_set_rx_csum(struct net_device *dev, u32 data)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+ if ((adapter->flags & QLCNIC_ESWITCH_ENABLED))
+ return -EOPNOTSUPP;
+ if (!!data) {
+ adapter->rx_csum = !!data;
+ return 0;
+ }
+
+ if (dev->features & NETIF_F_LRO) {
+ if (qlcnic_config_hw_lro(adapter, QLCNIC_LRO_DISABLED))
+ return -EIO;
+
+ dev->features &= ~NETIF_F_LRO;
+ qlcnic_send_lro_cleanup(adapter);
+ }
adapter->rx_csum = !!data;
+ dev_info(&adapter->pdev->dev, "disabling LRO as rx_csum is off\n");
return 0;
}
@@ -1002,6 +1110,15 @@ static int qlcnic_set_flags(struct net_device *netdev, u32 data)
if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO))
return -EINVAL;
+ if (!adapter->rx_csum) {
+ dev_info(&adapter->pdev->dev, "rx csum is off, "
+ "cannot toggle lro\n");
+ return -EINVAL;
+ }
+
+ if ((data & ETH_FLAG_LRO) && (netdev->features & NETIF_F_LRO))
+ return 0;
+
if (data & ETH_FLAG_LRO) {
hw_lro = QLCNIC_LRO_ENABLED;
netdev->features |= NETIF_F_LRO;
@@ -1048,7 +1165,7 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
.get_pauseparam = qlcnic_get_pauseparam,
.set_pauseparam = qlcnic_set_pauseparam,
.get_tx_csum = qlcnic_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
+ .set_tx_csum = qlcnic_set_tx_csum,
.set_sg = ethtool_op_set_sg,
.get_tso = qlcnic_get_tso,
.set_tso = qlcnic_set_tso,
diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h
index 15fc32070be3..4290b80cde1a 100644
--- a/drivers/net/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/qlcnic/qlcnic_hdr.h
@@ -556,18 +556,18 @@ enum {
#define XG_LINK_UP 0x10
#define XG_LINK_DOWN 0x20
-#define XG_LINK_UP_P3 0x01
-#define XG_LINK_DOWN_P3 0x02
-#define XG_LINK_STATE_P3_MASK 0xf
-#define XG_LINK_STATE_P3(pcifn, val) \
- (((val) >> ((pcifn) * 4)) & XG_LINK_STATE_P3_MASK)
-
-#define P3_LINK_SPEED_MHZ 100
-#define P3_LINK_SPEED_MASK 0xff
-#define P3_LINK_SPEED_REG(pcifn) \
+#define XG_LINK_UP_P3P 0x01
+#define XG_LINK_DOWN_P3P 0x02
+#define XG_LINK_STATE_P3P_MASK 0xf
+#define XG_LINK_STATE_P3P(pcifn, val) \
+ (((val) >> ((pcifn) * 4)) & XG_LINK_STATE_P3P_MASK)
+
+#define P3P_LINK_SPEED_MHZ 100
+#define P3P_LINK_SPEED_MASK 0xff
+#define P3P_LINK_SPEED_REG(pcifn) \
(CRB_PF_LINK_SPEED_1 + (((pcifn) / 4) * 4))
-#define P3_LINK_SPEED_VAL(pcifn, reg) \
- (((reg) >> (8 * ((pcifn) & 0x3))) & P3_LINK_SPEED_MASK)
+#define P3P_LINK_SPEED_VAL(pcifn, reg) \
+ (((reg) >> (8 * ((pcifn) & 0x3))) & P3P_LINK_SPEED_MASK)
#define QLCNIC_CAM_RAM_BASE (QLCNIC_CRB_CAM + 0x02000)
#define QLCNIC_CAM_RAM(reg) (QLCNIC_CAM_RAM_BASE + (reg))
@@ -592,7 +592,7 @@ enum {
#define CRB_CMDPEG_STATE (QLCNIC_REG(0x50))
#define CRB_RCVPEG_STATE (QLCNIC_REG(0x13c))
-#define CRB_XG_STATE_P3 (QLCNIC_REG(0x98))
+#define CRB_XG_STATE_P3P (QLCNIC_REG(0x98))
#define CRB_PF_LINK_SPEED_1 (QLCNIC_REG(0xe8))
#define CRB_PF_LINK_SPEED_2 (QLCNIC_REG(0xec))
@@ -698,7 +698,7 @@ enum {
#define QLCNIC_PEG_ALIVE_COUNTER (QLCNIC_CAM_RAM(0xb0))
#define QLCNIC_PEG_HALT_STATUS1 (QLCNIC_CAM_RAM(0xa8))
#define QLCNIC_PEG_HALT_STATUS2 (QLCNIC_CAM_RAM(0xac))
-#define QLCNIC_CRB_DEV_REF_COUNT (QLCNIC_CAM_RAM(0x138))
+#define QLCNIC_CRB_DRV_ACTIVE (QLCNIC_CAM_RAM(0x138))
#define QLCNIC_CRB_DEV_STATE (QLCNIC_CAM_RAM(0x140))
#define QLCNIC_CRB_DRV_STATE (QLCNIC_CAM_RAM(0x144))
@@ -718,8 +718,9 @@ enum {
#define QLCNIC_DEV_FAILED 0x6
#define QLCNIC_DEV_QUISCENT 0x7
-#define QLCNIC_DEV_NPAR_NOT_RDY 0
-#define QLCNIC_DEV_NPAR_RDY 1
+#define QLCNIC_DEV_NPAR_NON_OPER 0 /* NON Operational */
+#define QLCNIC_DEV_NPAR_OPER 1 /* NPAR Operational */
+#define QLCNIC_DEV_NPAR_OPER_TIMEO 30 /* Operational time out */
#define QLC_DEV_CHECK_ACTIVE(VAL, FN) ((VAL) &= (1 << (FN * 4)))
#define QLC_DEV_SET_REF_CNT(VAL, FN) ((VAL) |= (1 << (FN * 4)))
@@ -744,6 +745,15 @@ enum {
#define FW_POLL_DELAY (1 * HZ)
#define FW_FAIL_THRESH 2
+#define QLCNIC_RESET_TIMEOUT_SECS 10
+#define QLCNIC_INIT_TIMEOUT_SECS 30
+#define QLCNIC_RCVPEG_CHECK_RETRY_COUNT 2000
+#define QLCNIC_RCVPEG_CHECK_DELAY 10
+#define QLCNIC_CMDPEG_CHECK_RETRY_COUNT 60
+#define QLCNIC_CMDPEG_CHECK_DELAY 500
+#define QLCNIC_HEARTBEAT_PERIOD_MSECS 200
+#define QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT 45
+
#define ISR_MSI_INT_TRIGGER(FUNC) (QLCNIC_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
#define ISR_LEGACY_INT_TRIGGERED(VAL) (((VAL) & 0x300) == 0x200)
@@ -770,6 +780,7 @@ struct qlcnic_legacy_intr_set {
#define QLCNIC_DRV_OP_MODE 0x1b2170
#define QLCNIC_MSIX_BASE 0x132110
#define QLCNIC_MAX_PCI_FUNC 8
+#define QLCNIC_MAX_VLAN_FILTERS 64
/* PCI function operational mode */
enum {
@@ -778,6 +789,12 @@ enum {
QLCNIC_NON_PRIV_FUNC = 2
};
+enum {
+ QLCNIC_PORT_DEFAULTS = 0,
+ QLCNIC_ADD_VLAN = 1,
+ QLCNIC_DEL_VLAN = 2
+};
+
#define QLC_DEV_DRV_DEFAULT 0x11111111
#define LSB(x) ((uint8_t)(x))
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c
index e08c8b0556a4..7a47a2a7ee27 100644
--- a/drivers/net/qlcnic/qlcnic_hw.c
+++ b/drivers/net/qlcnic/qlcnic_hw.c
@@ -297,8 +297,8 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
break;
if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) {
dev_err(&adapter->pdev->dev,
- "Failed to acquire sem=%d lock;reg_id=%d\n",
- sem, id_reg);
+ "Failed to acquire sem=%d lock; holdby=%d\n",
+ sem, id_reg ? QLCRD32(adapter, id_reg) : -1);
return -EIO;
}
msleep(1);
@@ -375,10 +375,11 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
static int
qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
- unsigned op)
+ __le16 vlan_id, unsigned op)
{
struct qlcnic_nic_req req;
struct qlcnic_mac_req *mac_req;
+ struct qlcnic_vlan_req *vlan_req;
u64 word;
memset(&req, 0, sizeof(struct qlcnic_nic_req));
@@ -391,6 +392,9 @@ qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
mac_req->op = op;
memcpy(mac_req->mac_addr, addr, 6);
+ vlan_req = (struct qlcnic_vlan_req *)&req.words[1];
+ vlan_req->vlan_id = vlan_id;
+
return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
}
@@ -415,7 +419,7 @@ static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, u8 *addr)
memcpy(cur->mac_addr, addr, ETH_ALEN);
if (qlcnic_sre_macaddr_change(adapter,
- cur->mac_addr, QLCNIC_MAC_ADD)) {
+ cur->mac_addr, 0, QLCNIC_MAC_ADD)) {
kfree(cur);
return -EIO;
}
@@ -438,7 +442,8 @@ void qlcnic_set_multi(struct net_device *netdev)
qlcnic_nic_add_mac(adapter, bcast_addr);
if (netdev->flags & IFF_PROMISC) {
- mode = VPORT_MISS_MODE_ACCEPT_ALL;
+ if (!(adapter->flags & QLCNIC_PROMISC_DISABLED))
+ mode = VPORT_MISS_MODE_ACCEPT_ALL;
goto send_fw_cmd;
}
@@ -485,12 +490,63 @@ void qlcnic_free_mac_list(struct qlcnic_adapter *adapter)
while (!list_empty(head)) {
cur = list_entry(head->next, struct qlcnic_mac_list_s, list);
qlcnic_sre_macaddr_change(adapter,
- cur->mac_addr, QLCNIC_MAC_DEL);
+ cur->mac_addr, 0, QLCNIC_MAC_DEL);
list_del(&cur->list);
kfree(cur);
}
}
+void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_filter *tmp_fil;
+ struct hlist_node *tmp_hnode, *n;
+ struct hlist_head *head;
+ int i;
+
+ for (i = 0; i < adapter->fhash.fmax; i++) {
+ head = &(adapter->fhash.fhead[i]);
+
+ hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode)
+ {
+ if (jiffies >
+ (QLCNIC_FILTER_AGE * HZ + tmp_fil->ftime)) {
+ qlcnic_sre_macaddr_change(adapter,
+ tmp_fil->faddr, tmp_fil->vlan_id,
+ tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
+ QLCNIC_MAC_DEL);
+ spin_lock_bh(&adapter->mac_learn_lock);
+ adapter->fhash.fnum--;
+ hlist_del(&tmp_fil->fnode);
+ spin_unlock_bh(&adapter->mac_learn_lock);
+ kfree(tmp_fil);
+ }
+ }
+ }
+}
+
+void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_filter *tmp_fil;
+ struct hlist_node *tmp_hnode, *n;
+ struct hlist_head *head;
+ int i;
+
+ for (i = 0; i < adapter->fhash.fmax; i++) {
+ head = &(adapter->fhash.fhead[i]);
+
+ hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
+ qlcnic_sre_macaddr_change(adapter, tmp_fil->faddr,
+ tmp_fil->vlan_id, tmp_fil->vlan_id ?
+ QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL);
+ spin_lock_bh(&adapter->mac_learn_lock);
+ adapter->fhash.fnum--;
+ hlist_del(&tmp_fil->fnode);
+ spin_unlock_bh(&adapter->mac_learn_lock);
+ kfree(tmp_fil);
+ }
+ }
+}
+
#define QLCNIC_CONFIG_INTR_COALESCE 3
/*
@@ -527,9 +583,6 @@ int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
u64 word;
int rv;
- if ((adapter->flags & QLCNIC_LRO_ENABLED) == enable)
- return 0;
-
memset(&req, 0, sizeof(struct qlcnic_nic_req));
req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
@@ -544,8 +597,6 @@ int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
dev_err(&adapter->netdev->dev,
"Could not send configure hw lro request\n");
- adapter->flags ^= QLCNIC_LRO_ENABLED;
-
return rv;
}
@@ -623,9 +674,10 @@ int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
return rv;
}
-int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, u32 ip, int cmd)
+int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int cmd)
{
struct qlcnic_nic_req req;
+ struct qlcnic_ipaddr *ipa;
u64 word;
int rv;
@@ -636,7 +688,8 @@ int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, u32 ip, int cmd)
req.req_hdr = cpu_to_le64(word);
req.words[0] = cpu_to_le64(cmd);
- req.words[1] = cpu_to_le64(ip);
+ ipa = (struct qlcnic_ipaddr *)&req.words[1];
+ ipa->ipv4 = ip;
rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
if (rv != 0)
@@ -701,9 +754,9 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu)
struct qlcnic_adapter *adapter = netdev_priv(netdev);
int rc = 0;
- if (mtu > P3_MAX_MTU) {
- dev_err(&adapter->netdev->dev, "mtu > %d bytes unsupported\n",
- P3_MAX_MTU);
+ if (mtu < P3P_MIN_MTU || mtu > P3P_MAX_MTU) {
+ dev_err(&adapter->netdev->dev, "%d bytes < mtu < %d bytes"
+ " not supported\n", P3P_MAX_MTU, P3P_MIN_MTU);
return -EINVAL;
}
@@ -715,19 +768,6 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu)
return rc;
}
-int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u8 *mac)
-{
- u32 crbaddr;
- int pci_func = adapter->ahw.pci_func;
-
- crbaddr = CRB_MAC_BLOCK_START +
- (4 * ((pci_func/2) * 3)) + (4 * (pci_func & 1));
-
- qlcnic_fetch_mac(adapter, crbaddr, crbaddr+4, pci_func & 1, mac);
-
- return 0;
-}
-
/*
* Changes the CRB window to the specified window.
*/
@@ -1121,31 +1161,31 @@ int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
adapter->ahw.board_type = board_type;
- if (board_type == QLCNIC_BRDTYPE_P3_4_GB_MM) {
+ if (board_type == QLCNIC_BRDTYPE_P3P_4_GB_MM) {
u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I);
if ((gpio & 0x8000) == 0)
- board_type = QLCNIC_BRDTYPE_P3_10G_TP;
+ board_type = QLCNIC_BRDTYPE_P3P_10G_TP;
}
switch (board_type) {
- case QLCNIC_BRDTYPE_P3_HMEZ:
- case QLCNIC_BRDTYPE_P3_XG_LOM:
- case QLCNIC_BRDTYPE_P3_10G_CX4:
- case QLCNIC_BRDTYPE_P3_10G_CX4_LP:
- case QLCNIC_BRDTYPE_P3_IMEZ:
- case QLCNIC_BRDTYPE_P3_10G_SFP_PLUS:
- case QLCNIC_BRDTYPE_P3_10G_SFP_CT:
- case QLCNIC_BRDTYPE_P3_10G_SFP_QT:
- case QLCNIC_BRDTYPE_P3_10G_XFP:
- case QLCNIC_BRDTYPE_P3_10000_BASE_T:
+ case QLCNIC_BRDTYPE_P3P_HMEZ:
+ case QLCNIC_BRDTYPE_P3P_XG_LOM:
+ case QLCNIC_BRDTYPE_P3P_10G_CX4:
+ case QLCNIC_BRDTYPE_P3P_10G_CX4_LP:
+ case QLCNIC_BRDTYPE_P3P_IMEZ:
+ case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS:
+ case QLCNIC_BRDTYPE_P3P_10G_SFP_CT:
+ case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
+ case QLCNIC_BRDTYPE_P3P_10G_XFP:
+ case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
adapter->ahw.port_type = QLCNIC_XGBE;
break;
- case QLCNIC_BRDTYPE_P3_REF_QG:
- case QLCNIC_BRDTYPE_P3_4_GB:
- case QLCNIC_BRDTYPE_P3_4_GB_MM:
+ case QLCNIC_BRDTYPE_P3P_REF_QG:
+ case QLCNIC_BRDTYPE_P3P_4_GB:
+ case QLCNIC_BRDTYPE_P3P_4_GB_MM:
adapter->ahw.port_type = QLCNIC_GBE;
break;
- case QLCNIC_BRDTYPE_P3_10G_TP:
+ case QLCNIC_BRDTYPE_P3P_10G_TP:
adapter->ahw.port_type = (adapter->portnum < 2) ?
QLCNIC_XGBE : QLCNIC_GBE;
break;
@@ -1245,4 +1285,5 @@ void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter)
mode = VPORT_MISS_MODE_ACCEPT_MULTI;
qlcnic_nic_set_promisc(adapter, mode);
+ msleep(1000);
}
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c
index 2c7cf0b64811..0d180c6e41fe 100644
--- a/drivers/net/qlcnic/qlcnic_init.c
+++ b/drivers/net/qlcnic/qlcnic_init.c
@@ -25,6 +25,7 @@
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/if_vlan.h>
#include "qlcnic.h"
struct crb_addr_pair {
@@ -45,6 +46,9 @@ static void
qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
struct qlcnic_host_rds_ring *rds_ring);
+static int
+qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter);
+
static void crb_addr_transform_setup(void)
{
crb_addr_transform(XDMA);
@@ -136,8 +140,6 @@ void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter)
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
rds_ring = &recv_ctx->rds_rings[ring];
- spin_lock(&rds_ring->lock);
-
INIT_LIST_HEAD(&rds_ring->free_list);
rx_buf = rds_ring->rx_buf_arr;
@@ -146,8 +148,6 @@ void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter)
&rds_ring->free_list);
rx_buf++;
}
-
- spin_unlock(&rds_ring->lock);
}
}
@@ -259,14 +259,14 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
switch (ring) {
case RCV_RING_NORMAL:
rds_ring->num_desc = adapter->num_rxd;
- rds_ring->dma_size = QLCNIC_P3_RX_BUF_MAX_LEN;
+ rds_ring->dma_size = QLCNIC_P3P_RX_BUF_MAX_LEN;
rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN;
break;
case RCV_RING_JUMBO:
rds_ring->num_desc = adapter->num_jumbo_rxd;
rds_ring->dma_size =
- QLCNIC_P3_RX_JUMBO_BUF_MAX_LEN;
+ QLCNIC_P3P_RX_JUMBO_BUF_MAX_LEN;
if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
rds_ring->dma_size += QLCNIC_LRO_BUFFER_EXTRA;
@@ -439,11 +439,14 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
u32 off;
struct pci_dev *pdev = adapter->pdev;
- /* resetall */
+ QLCWR32(adapter, CRB_CMDPEG_STATE, 0);
+ QLCWR32(adapter, CRB_RCVPEG_STATE, 0);
+
qlcnic_rom_lock(adapter);
QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0xfeffffff);
qlcnic_rom_unlock(adapter);
+ /* Init HW CRB block */
if (qlcnic_rom_fast_read(adapter, 0, &n) != 0 || (n != 0xcafecafe) ||
qlcnic_rom_fast_read(adapter, 4, &n) != 0) {
dev_err(&pdev->dev, "ERROR Reading crb_init area: val:%x\n", n);
@@ -524,13 +527,10 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
}
kfree(buf);
- /* p2dn replyCount */
+ /* Initialize protocol process engine */
QLCWR32(adapter, QLCNIC_CRB_PEG_NET_D + 0xec, 0x1e);
- /* disable_peg_cache 0 & 1*/
QLCWR32(adapter, QLCNIC_CRB_PEG_NET_D + 0x4c, 8);
QLCWR32(adapter, QLCNIC_CRB_PEG_NET_I + 0x4c, 8);
-
- /* peg_clr_all */
QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x8, 0);
QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0xc, 0);
QLCWR32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x8, 0);
@@ -539,10 +539,88 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
QLCWR32(adapter, QLCNIC_CRB_PEG_NET_2 + 0xc, 0);
QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x8, 0);
QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0xc, 0);
+ QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x8, 0);
+ QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0xc, 0);
+ msleep(1);
+ QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
+ QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
+ return 0;
+}
+
+static int qlcnic_cmd_peg_ready(struct qlcnic_adapter *adapter)
+{
+ u32 val;
+ int retries = QLCNIC_CMDPEG_CHECK_RETRY_COUNT;
+
+ do {
+ val = QLCRD32(adapter, CRB_CMDPEG_STATE);
+
+ switch (val) {
+ case PHAN_INITIALIZE_COMPLETE:
+ case PHAN_INITIALIZE_ACK:
+ return 0;
+ case PHAN_INITIALIZE_FAILED:
+ goto out_err;
+ default:
+ break;
+ }
+
+ msleep(QLCNIC_CMDPEG_CHECK_DELAY);
+
+ } while (--retries);
+
+ QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
+
+out_err:
+ dev_err(&adapter->pdev->dev, "Command Peg initialization not "
+ "complete, state: 0x%x.\n", val);
+ return -EIO;
+}
+
+static int
+qlcnic_receive_peg_ready(struct qlcnic_adapter *adapter)
+{
+ u32 val;
+ int retries = QLCNIC_RCVPEG_CHECK_RETRY_COUNT;
+
+ do {
+ val = QLCRD32(adapter, CRB_RCVPEG_STATE);
+
+ if (val == PHAN_PEG_RCV_INITIALIZED)
+ return 0;
+
+ msleep(QLCNIC_RCVPEG_CHECK_DELAY);
+
+ } while (--retries);
+
+ if (!retries) {
+ dev_err(&adapter->pdev->dev, "Receive Peg initialization not "
+ "complete, state: 0x%x.\n", val);
+ return -EIO;
+ }
+
return 0;
}
int
+qlcnic_check_fw_status(struct qlcnic_adapter *adapter)
+{
+ int err;
+
+ err = qlcnic_cmd_peg_ready(adapter);
+ if (err)
+ return err;
+
+ err = qlcnic_receive_peg_ready(adapter);
+ if (err)
+ return err;
+
+ QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
+
+ return err;
+}
+
+int
qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) {
int timeo;
@@ -557,12 +635,12 @@ qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) {
}
adapter->physical_port = (val >> 2);
if (qlcnic_rom_fast_read(adapter, QLCNIC_ROM_DEV_INIT_TIMEOUT, &timeo))
- timeo = 30;
+ timeo = QLCNIC_INIT_TIMEOUT_SECS;
adapter->dev_init_timeo = timeo;
if (qlcnic_rom_fast_read(adapter, QLCNIC_ROM_DRV_RESET_TIMEOUT, &timeo))
- timeo = 10;
+ timeo = QLCNIC_RESET_TIMEOUT_SECS;
adapter->reset_ack_timeo = timeo;
@@ -906,54 +984,47 @@ qlcnic_get_bios_version(struct qlcnic_adapter *adapter)
return (bios_ver << 16) + ((bios_ver >> 8) & 0xff00) + (bios_ver >> 24);
}
-int
-qlcnic_need_fw_reset(struct qlcnic_adapter *adapter)
+static void qlcnic_rom_lock_recovery(struct qlcnic_adapter *adapter)
{
- u32 count, old_count;
- u32 val, version, major, minor, build;
- int i, timeout;
-
- if (adapter->need_fw_reset)
- return 1;
+ if (qlcnic_pcie_sem_lock(adapter, 2, QLCNIC_ROM_LOCK_ID))
+ dev_info(&adapter->pdev->dev, "Resetting rom_lock\n");
- /* last attempt had failed */
- if (QLCRD32(adapter, CRB_CMDPEG_STATE) == PHAN_INITIALIZE_FAILED)
- return 1;
+ qlcnic_pcie_sem_unlock(adapter, 2);
+}
- old_count = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+static int
+qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter)
+{
+ u32 heartbeat, ret = -EIO;
+ int retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT;
- for (i = 0; i < 10; i++) {
+ adapter->heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
- timeout = msleep_interruptible(200);
- if (timeout) {
- QLCWR32(adapter, CRB_CMDPEG_STATE,
- PHAN_INITIALIZE_FAILED);
- return -EINTR;
+ do {
+ msleep(QLCNIC_HEARTBEAT_PERIOD_MSECS);
+ heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+ if (heartbeat != adapter->heartbeat) {
+ ret = QLCNIC_RCODE_SUCCESS;
+ break;
}
+ } while (--retries);
- count = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
- if (count != old_count)
- break;
- }
+ return ret;
+}
- /* firmware is dead */
- if (count == old_count)
+int
+qlcnic_need_fw_reset(struct qlcnic_adapter *adapter)
+{
+ if (qlcnic_check_fw_hearbeat(adapter)) {
+ qlcnic_rom_lock_recovery(adapter);
return 1;
+ }
- /* check if we have got newer or different file firmware */
- if (adapter->fw) {
-
- val = qlcnic_get_fw_version(adapter);
-
- version = QLCNIC_DECODE_VERSION(val);
-
- major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
- minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
- build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
+ if (adapter->need_fw_reset)
+ return 1;
- if (version > QLCNIC_VERSION_CODE(major, minor, build))
- return 1;
- }
+ if (adapter->fw)
+ return 1;
return 0;
}
@@ -1089,18 +1160,6 @@ qlcnic_validate_firmware(struct qlcnic_adapter *adapter)
return -EINVAL;
}
- /* check if flashed firmware is newer */
- if (qlcnic_rom_fast_read(adapter,
- QLCNIC_FW_VERSION_OFFSET, (int *)&val))
- return -EIO;
-
- val = QLCNIC_DECODE_VERSION(val);
- if (val > ver) {
- dev_info(&pdev->dev, "%s: firmware is older than flash\n",
- fw_name[fw_type]);
- return -EINVAL;
- }
-
QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC);
return 0;
}
@@ -1162,78 +1221,6 @@ qlcnic_release_firmware(struct qlcnic_adapter *adapter)
adapter->fw = NULL;
}
-static int qlcnic_cmd_peg_ready(struct qlcnic_adapter *adapter)
-{
- u32 val;
- int retries = 60;
-
- do {
- val = QLCRD32(adapter, CRB_CMDPEG_STATE);
-
- switch (val) {
- case PHAN_INITIALIZE_COMPLETE:
- case PHAN_INITIALIZE_ACK:
- return 0;
- case PHAN_INITIALIZE_FAILED:
- goto out_err;
- default:
- break;
- }
-
- msleep(500);
-
- } while (--retries);
-
- QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
-
-out_err:
- dev_err(&adapter->pdev->dev, "Command Peg initialization not "
- "complete, state: 0x%x.\n", val);
- return -EIO;
-}
-
-static int
-qlcnic_receive_peg_ready(struct qlcnic_adapter *adapter)
-{
- u32 val;
- int retries = 2000;
-
- do {
- val = QLCRD32(adapter, CRB_RCVPEG_STATE);
-
- if (val == PHAN_PEG_RCV_INITIALIZED)
- return 0;
-
- msleep(10);
-
- } while (--retries);
-
- if (!retries) {
- dev_err(&adapter->pdev->dev, "Receive Peg initialization not "
- "complete, state: 0x%x.\n", val);
- return -EIO;
- }
-
- return 0;
-}
-
-int qlcnic_init_firmware(struct qlcnic_adapter *adapter)
-{
- int err;
-
- err = qlcnic_cmd_peg_ready(adapter);
- if (err)
- return err;
-
- err = qlcnic_receive_peg_ready(adapter);
- if (err)
- return err;
-
- QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
-
- return err;
-}
-
static void
qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
struct qlcnic_fw_msg *msg)
@@ -1351,11 +1338,12 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
skb = buffer->skb;
- if (likely(adapter->rx_csum && cksum == STATUS_CKSUM_OK)) {
+ if (likely(adapter->rx_csum && (cksum == STATUS_CKSUM_OK ||
+ cksum == STATUS_CKSUM_LOOP))) {
adapter->stats.csummed++;
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else {
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
}
skb->dev = adapter->netdev;
@@ -1365,6 +1353,31 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
return skb;
}
+static int
+qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb,
+ u16 *vlan_tag)
+{
+ struct ethhdr *eth_hdr;
+
+ if (!__vlan_get_tag(skb, vlan_tag)) {
+ eth_hdr = (struct ethhdr *) skb->data;
+ memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
+ skb_pull(skb, VLAN_HLEN);
+ }
+ if (!adapter->pvid)
+ return 0;
+
+ if (*vlan_tag == adapter->pvid) {
+ /* Outer vlan tag. Packet should follow non-vlan path */
+ *vlan_tag = 0xffff;
+ return 0;
+ }
+ if (adapter->flags & QLCNIC_TAGGING_ENABLED)
+ return 0;
+
+ return -EINVAL;
+}
+
static struct qlcnic_rx_buffer *
qlcnic_process_rcv(struct qlcnic_adapter *adapter,
struct qlcnic_host_sds_ring *sds_ring,
@@ -1376,6 +1389,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
struct sk_buff *skb;
struct qlcnic_host_rds_ring *rds_ring;
int index, length, cksum, pkt_offset;
+ u16 vid = 0xffff;
if (unlikely(ring >= adapter->max_rds_rings))
return NULL;
@@ -1404,9 +1418,18 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
if (pkt_offset)
skb_pull(skb, pkt_offset);
+ if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+ adapter->stats.rxdropped++;
+ dev_kfree_skb(skb);
+ return buffer;
+ }
+
skb->protocol = eth_type_trans(skb, netdev);
- napi_gro_receive(&sds_ring->napi, skb);
+ if ((vid != 0xffff) && adapter->vlgrp)
+ vlan_gro_receive(&sds_ring->napi, adapter->vlgrp, vid, skb);
+ else
+ napi_gro_receive(&sds_ring->napi, skb);
adapter->stats.rx_pkts++;
adapter->stats.rxbytes += length;
@@ -1435,6 +1458,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
int index;
u16 lro_length, length, data_offset;
u32 seq_number;
+ u16 vid = 0xffff;
if (unlikely(ring > adapter->max_rds_rings))
return NULL;
@@ -1466,6 +1490,13 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
skb_put(skb, lro_length + data_offset);
skb_pull(skb, l2_hdr_offset);
+
+ if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+ adapter->stats.rxdropped++;
+ dev_kfree_skb(skb);
+ return buffer;
+ }
+
skb->protocol = eth_type_trans(skb, netdev);
iph = (struct iphdr *)skb->data;
@@ -1480,7 +1511,10 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
length = skb->len;
- netif_receive_skb(skb);
+ if ((vid != 0xffff) && adapter->vlgrp)
+ vlan_hwaccel_receive_skb(skb, adapter->vlgrp, vid);
+ else
+ netif_receive_skb(skb);
adapter->stats.lro_pkts++;
adapter->stats.lrobytes += length;
@@ -1584,8 +1618,6 @@ qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid,
int producer, count = 0;
struct list_head *head;
- spin_lock(&rds_ring->lock);
-
producer = rds_ring->producer;
head = &rds_ring->free_list;
@@ -1615,7 +1647,6 @@ qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid,
writel((producer-1) & (rds_ring->num_desc-1),
rds_ring->crb_rcv_producer);
}
- spin_unlock(&rds_ring->lock);
}
static void
@@ -1662,6 +1693,18 @@ qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
spin_unlock(&rds_ring->lock);
}
+static void dump_skb(struct sk_buff *skb)
+{
+ int i;
+ unsigned char *data = skb->data;
+
+ for (i = 0; i < skb->len; i++) {
+ printk("%02x ", data[i]);
+ if ((i & 0x0f) == 8)
+ printk("\n");
+ }
+}
+
static struct qlcnic_rx_buffer *
qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter,
struct qlcnic_host_sds_ring *sds_ring,
@@ -1692,13 +1735,18 @@ qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter,
if (!skb)
return buffer;
- skb_put(skb, rds_ring->skb_size);
+ if (length > rds_ring->skb_size)
+ skb_put(skb, rds_ring->skb_size);
+ else
+ skb_put(skb, length);
if (pkt_offset)
skb_pull(skb, pkt_offset);
if (!qlcnic_check_loopback_buff(skb->data))
adapter->diag_cnt++;
+ else
+ dump_skb(skb);
dev_kfree_skb_any(skb);
adapter->stats.rx_pkts++;
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 66eea5972020..7a298cdf9ab3 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -28,6 +28,7 @@
#include "qlcnic.h"
+#include <linux/swab.h>
#include <linux/dma-mapping.h>
#include <linux/if_vlan.h>
#include <net/ip.h>
@@ -45,10 +46,10 @@ char qlcnic_driver_name[] = "qlcnic";
static const char qlcnic_driver_string[] = "QLogic 1/10 GbE "
"Converged/Intelligent Ethernet Driver v" QLCNIC_LINUX_VERSIONID;
-static int port_mode = QLCNIC_PORT_MODE_AUTO_NEG;
-
-/* Default to restricted 1G auto-neg mode */
-static int wol_port_mode = 5;
+static struct workqueue_struct *qlcnic_wq;
+static int qlcnic_mac_learn;
+module_param(qlcnic_mac_learn, int, 0644);
+MODULE_PARM_DESC(qlcnic_mac_learn, "Mac Filter (0=disabled, 1=enabled)");
static int use_msi = 1;
module_param(use_msi, int, 0644);
@@ -94,7 +95,7 @@ static void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter);
static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter);
static void qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding);
-static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter);
+static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8);
static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter);
static irqreturn_t qlcnic_tmp_intr(int irq, void *data);
@@ -103,13 +104,17 @@ static irqreturn_t qlcnic_msi_intr(int irq, void *data);
static irqreturn_t qlcnic_msix_intr(int irq, void *data);
static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
-static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long);
+static void qlcnic_restore_indev_addr(struct net_device *dev, unsigned long);
static int qlcnic_start_firmware(struct qlcnic_adapter *);
+static void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter);
+static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter);
static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *);
static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
+static void qlcnic_set_netdev_features(struct qlcnic_adapter *,
+ struct qlcnic_esw_func_cfg *);
/* PCI Device ID Table */
#define ENTRY(device) \
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
@@ -164,7 +169,7 @@ qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count)
recv_ctx->sds_rings = kzalloc(size, GFP_KERNEL);
- return (recv_ctx->sds_rings == NULL);
+ return recv_ctx->sds_rings == NULL;
}
static void
@@ -255,40 +260,6 @@ static void qlcnic_clear_stats(struct qlcnic_adapter *adapter)
memset(&adapter->stats, 0, sizeof(adapter->stats));
}
-static void qlcnic_set_port_mode(struct qlcnic_adapter *adapter)
-{
- u32 val, data;
-
- val = adapter->ahw.board_type;
- if ((val == QLCNIC_BRDTYPE_P3_HMEZ) ||
- (val == QLCNIC_BRDTYPE_P3_XG_LOM)) {
- if (port_mode == QLCNIC_PORT_MODE_802_3_AP) {
- data = QLCNIC_PORT_MODE_802_3_AP;
- QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
- } else if (port_mode == QLCNIC_PORT_MODE_XG) {
- data = QLCNIC_PORT_MODE_XG;
- QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
- } else if (port_mode == QLCNIC_PORT_MODE_AUTO_NEG_1G) {
- data = QLCNIC_PORT_MODE_AUTO_NEG_1G;
- QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
- } else if (port_mode == QLCNIC_PORT_MODE_AUTO_NEG_XG) {
- data = QLCNIC_PORT_MODE_AUTO_NEG_XG;
- QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
- } else {
- data = QLCNIC_PORT_MODE_AUTO_NEG;
- QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
- }
-
- if ((wol_port_mode != QLCNIC_PORT_MODE_802_3_AP) &&
- (wol_port_mode != QLCNIC_PORT_MODE_XG) &&
- (wol_port_mode != QLCNIC_PORT_MODE_AUTO_NEG_1G) &&
- (wol_port_mode != QLCNIC_PORT_MODE_AUTO_NEG_XG)) {
- wol_port_mode = QLCNIC_PORT_MODE_AUTO_NEG;
- }
- QLCWR32(adapter, QLCNIC_WOL_PORT_MODE, wol_port_mode);
- }
-}
-
static void qlcnic_set_msix_bit(struct pci_dev *pdev, int enable)
{
u32 control;
@@ -320,7 +291,7 @@ qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
- if (adapter->nic_ops->get_mac_addr(adapter, mac_addr) != 0)
+ if (qlcnic_get_mac_address(adapter, mac_addr) != 0)
return -EIO;
memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
@@ -341,6 +312,9 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct sockaddr *addr = p;
+ if ((adapter->flags & QLCNIC_MAC_OVERRIDE_DISABLED))
+ return -EOPNOTSUPP;
+
if (!is_valid_ether_addr(addr->sa_data))
return -EINVAL;
@@ -360,6 +334,13 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
return 0;
}
+static void qlcnic_vlan_rx_register(struct net_device *netdev,
+ struct vlan_group *grp)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ adapter->vlgrp = grp;
+}
+
static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_open = qlcnic_open,
.ndo_stop = qlcnic_close,
@@ -370,20 +351,19 @@ static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_set_mac_address = qlcnic_set_mac,
.ndo_change_mtu = qlcnic_change_mtu,
.ndo_tx_timeout = qlcnic_tx_timeout,
+ .ndo_vlan_rx_register = qlcnic_vlan_rx_register,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = qlcnic_poll_controller,
#endif
};
static struct qlcnic_nic_template qlcnic_ops = {
- .get_mac_addr = qlcnic_get_mac_address,
.config_bridged_mode = qlcnic_config_bridged_mode,
.config_led = qlcnic_config_led,
.start_firmware = qlcnic_start_firmware
};
static struct qlcnic_nic_template qlcnic_vf_ops = {
- .get_mac_addr = qlcnic_get_mac_address,
.config_bridged_mode = qlcnicvf_config_bridged_mode,
.config_led = qlcnicvf_config_led,
.start_firmware = qlcnicvf_start_firmware
@@ -474,7 +454,7 @@ static int
qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
{
struct qlcnic_pci_info *pci_info;
- int i, ret = 0, err;
+ int i, ret = 0;
u8 pfn;
pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
@@ -484,14 +464,14 @@ qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
QLCNIC_MAX_PCI_FUNC, GFP_KERNEL);
if (!adapter->npars) {
- err = -ENOMEM;
+ ret = -ENOMEM;
goto err_pci_info;
}
adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
if (!adapter->eswitch) {
- err = -ENOMEM;
+ ret = -ENOMEM;
goto err_npars;
}
@@ -503,10 +483,9 @@ qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
pfn = pci_info[i].id;
if (pfn > QLCNIC_MAX_PCI_FUNC)
return QL_STATUS_INVALID_PARAM;
- adapter->npars[pfn].active = pci_info[i].active;
- adapter->npars[pfn].type = pci_info[i].type;
- adapter->npars[pfn].phy_port = pci_info[i].default_port;
- adapter->npars[pfn].mac_learning = DEFAULT_MAC_LEARN;
+ adapter->npars[pfn].active = (u8)pci_info[i].active;
+ adapter->npars[pfn].type = (u8)pci_info[i].type;
+ adapter->npars[pfn].phy_port = (u8)pci_info[i].default_port;
adapter->npars[pfn].min_bw = pci_info[i].tx_min_bw;
adapter->npars[pfn].max_bw = pci_info[i].tx_max_bw;
}
@@ -539,12 +518,10 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
void __iomem *priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
/* If other drivers are not in use set their privilege level */
- ref_count = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+ ref_count = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
ret = qlcnic_api_lock(adapter);
if (ret)
goto err_lock;
- if (QLC_DEV_CLR_REF_CNT(ref_count, adapter->ahw.pci_func))
- goto err_npar;
if (qlcnic_config_npars) {
for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
@@ -562,18 +539,16 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
adapter->ahw.pci_func));
}
writel(data, priv_op);
-err_npar:
qlcnic_api_unlock(adapter);
err_lock:
return ret;
}
-static u32
-qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
+static void
+qlcnic_check_vf(struct qlcnic_adapter *adapter)
{
void __iomem *msix_base_addr;
void __iomem *priv_op;
- struct qlcnic_info nic_info;
u32 func;
u32 msix_base;
u32 op_mode, priv_level;
@@ -588,20 +563,6 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
adapter->ahw.pci_func = func;
- if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
- adapter->capabilities = nic_info.capabilities;
-
- if (adapter->capabilities & BIT_6)
- adapter->flags |= QLCNIC_ESWITCH_ENABLED;
- else
- adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
- }
-
- if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
- adapter->nic_ops = &qlcnic_ops;
- return adapter->fw_hal_version;
- }
-
/* Determine function privilege level */
priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
op_mode = readl(priv_op);
@@ -610,37 +571,14 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
else
priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
- switch (priv_level) {
- case QLCNIC_MGMT_FUNC:
- adapter->op_mode = QLCNIC_MGMT_FUNC;
- adapter->nic_ops = &qlcnic_ops;
- qlcnic_init_pci_info(adapter);
- /* Set privilege level for other functions */
- qlcnic_set_function_modes(adapter);
- dev_info(&adapter->pdev->dev,
- "HAL Version: %d, Management function\n",
- adapter->fw_hal_version);
- break;
- case QLCNIC_PRIV_FUNC:
- adapter->op_mode = QLCNIC_PRIV_FUNC;
- dev_info(&adapter->pdev->dev,
- "HAL Version: %d, Privileged function\n",
- adapter->fw_hal_version);
- adapter->nic_ops = &qlcnic_ops;
- break;
- case QLCNIC_NON_PRIV_FUNC:
+ if (priv_level == QLCNIC_NON_PRIV_FUNC) {
adapter->op_mode = QLCNIC_NON_PRIV_FUNC;
dev_info(&adapter->pdev->dev,
"HAL Version: %d Non Privileged function\n",
adapter->fw_hal_version);
adapter->nic_ops = &qlcnic_vf_ops;
- break;
- default:
- dev_info(&adapter->pdev->dev, "Unknown function mode: %d\n",
- priv_level);
- return 0;
- }
- return adapter->fw_hal_version;
+ } else
+ adapter->nic_ops = &qlcnic_ops;
}
static int
@@ -673,10 +611,7 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
adapter->ahw.pci_base0 = mem_ptr0;
adapter->ahw.pci_len0 = pci_len0;
- if (!qlcnic_get_driver_mode(adapter)) {
- iounmap(adapter->ahw.pci_base0);
- return -EIO;
- }
+ qlcnic_check_vf(adapter);
adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter,
QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(adapter->ahw.pci_func)));
@@ -711,25 +646,7 @@ static void
qlcnic_check_options(struct qlcnic_adapter *adapter)
{
u32 fw_major, fw_minor, fw_build;
- char brd_name[QLCNIC_MAX_BOARD_NAME_LEN];
- char serial_num[32];
- int i, offset, val;
- int *ptr32;
struct pci_dev *pdev = adapter->pdev;
- struct qlcnic_info nic_info;
- adapter->driver_mismatch = 0;
-
- ptr32 = (int *)&serial_num;
- offset = QLCNIC_FW_SERIAL_NUM_OFFSET;
- for (i = 0; i < 8; i++) {
- if (qlcnic_rom_fast_read(adapter, offset, &val) == -1) {
- dev_err(&pdev->dev, "error reading board info\n");
- adapter->driver_mismatch = 1;
- return;
- }
- ptr32[i] = cpu_to_le32(val);
- offset += sizeof(u32);
- }
fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
@@ -737,35 +654,25 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
- if (adapter->portnum == 0) {
- get_brd_name(adapter, brd_name);
-
- pr_info("%s: %s Board Chip rev 0x%x\n",
- module_name(THIS_MODULE),
- brd_name, adapter->ahw.revision_id);
- }
-
dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
fw_major, fw_minor, fw_build);
-
- adapter->flags &= ~QLCNIC_LRO_ENABLED;
-
if (adapter->ahw.port_type == QLCNIC_XGBE) {
- adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
+ if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
+ adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF;
+ adapter->max_rxd = MAX_RCV_DESCRIPTORS_VF;
+ } else {
+ adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
+ adapter->max_rxd = MAX_RCV_DESCRIPTORS_10G;
+ }
+
adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+
} else if (adapter->ahw.port_type == QLCNIC_GBE) {
adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
- }
-
- if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
- adapter->physical_port = nic_info.phys_port;
- adapter->switch_mode = nic_info.switch_mode;
- adapter->max_tx_ques = nic_info.max_tx_ques;
- adapter->max_rx_ques = nic_info.max_rx_ques;
- adapter->capabilities = nic_info.capabilities;
- adapter->max_mac_filters = nic_info.max_mac_filters;
- adapter->max_mtu = nic_info.max_mtu;
+ adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+ adapter->max_rxd = MAX_RCV_DESCRIPTORS_1G;
}
adapter->msix_supported = !!use_msi_x;
@@ -773,121 +680,359 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
adapter->num_txd = MAX_CMD_DESCRIPTORS;
- adapter->max_rds_rings = 2;
+ adapter->max_rds_rings = MAX_RDS_RINGS;
+}
+
+static int
+qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
+{
+ int err;
+ struct qlcnic_info nic_info;
+
+ err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func);
+ if (err)
+ return err;
+
+ adapter->physical_port = (u8)nic_info.phys_port;
+ adapter->switch_mode = nic_info.switch_mode;
+ adapter->max_tx_ques = nic_info.max_tx_ques;
+ adapter->max_rx_ques = nic_info.max_rx_ques;
+ adapter->capabilities = nic_info.capabilities;
+ adapter->max_mac_filters = nic_info.max_mac_filters;
+ adapter->max_mtu = nic_info.max_mtu;
+
+ if (adapter->capabilities & BIT_6)
+ adapter->flags |= QLCNIC_ESWITCH_ENABLED;
+ else
+ adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+
+ return err;
+}
+
+static void
+qlcnic_set_vlan_config(struct qlcnic_adapter *adapter,
+ struct qlcnic_esw_func_cfg *esw_cfg)
+{
+ if (esw_cfg->discard_tagged)
+ adapter->flags &= ~QLCNIC_TAGGING_ENABLED;
+ else
+ adapter->flags |= QLCNIC_TAGGING_ENABLED;
+
+ if (esw_cfg->vlan_id)
+ adapter->pvid = esw_cfg->vlan_id;
+ else
+ adapter->pvid = 0;
+}
+
+static void
+qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
+ struct qlcnic_esw_func_cfg *esw_cfg)
+{
+ adapter->flags &= ~(QLCNIC_MACSPOOF | QLCNIC_MAC_OVERRIDE_DISABLED |
+ QLCNIC_PROMISC_DISABLED);
+
+ if (esw_cfg->mac_anti_spoof)
+ adapter->flags |= QLCNIC_MACSPOOF;
+
+ if (!esw_cfg->mac_override)
+ adapter->flags |= QLCNIC_MAC_OVERRIDE_DISABLED;
+
+ if (!esw_cfg->promisc_mode)
+ adapter->flags |= QLCNIC_PROMISC_DISABLED;
+
+ qlcnic_set_netdev_features(adapter, esw_cfg);
+}
+
+static int
+qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_esw_func_cfg esw_cfg;
+
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
+ return 0;
+
+ esw_cfg.pci_func = adapter->ahw.pci_func;
+ if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg))
+ return -EIO;
+ qlcnic_set_vlan_config(adapter, &esw_cfg);
+ qlcnic_set_eswitch_port_features(adapter, &esw_cfg);
+
+ return 0;
+}
+
+static void
+qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
+ struct qlcnic_esw_func_cfg *esw_cfg)
+{
+ struct net_device *netdev = adapter->netdev;
+ unsigned long features, vlan_features;
+
+ features = (NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM | NETIF_F_GRO);
+ vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM);
+
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) {
+ features |= (NETIF_F_TSO | NETIF_F_TSO6);
+ vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
+ }
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
+ features |= NETIF_F_LRO;
+
+ if (esw_cfg->offload_flags & BIT_0) {
+ netdev->features |= features;
+ adapter->rx_csum = 1;
+ if (!(esw_cfg->offload_flags & BIT_1))
+ netdev->features &= ~NETIF_F_TSO;
+ if (!(esw_cfg->offload_flags & BIT_2))
+ netdev->features &= ~NETIF_F_TSO6;
+ } else {
+ netdev->features &= ~features;
+ adapter->rx_csum = 0;
+ }
+
+ netdev->vlan_features = (features & vlan_features);
+}
+
+static int
+qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
+{
+ void __iomem *priv_op;
+ u32 op_mode, priv_level;
+ int err = 0;
+
+ err = qlcnic_initialize_nic(adapter);
+ if (err)
+ return err;
+
+ if (adapter->flags & QLCNIC_ADAPTER_INITIALIZED)
+ return 0;
+
+ priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+ op_mode = readl(priv_op);
+ priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
+
+ if (op_mode == QLC_DEV_DRV_DEFAULT)
+ priv_level = QLCNIC_MGMT_FUNC;
+ else
+ priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
+
+ if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
+ if (priv_level == QLCNIC_MGMT_FUNC) {
+ adapter->op_mode = QLCNIC_MGMT_FUNC;
+ err = qlcnic_init_pci_info(adapter);
+ if (err)
+ return err;
+ /* Set privilege level for other functions */
+ qlcnic_set_function_modes(adapter);
+ dev_info(&adapter->pdev->dev,
+ "HAL Version: %d, Management function\n",
+ adapter->fw_hal_version);
+ } else if (priv_level == QLCNIC_PRIV_FUNC) {
+ adapter->op_mode = QLCNIC_PRIV_FUNC;
+ dev_info(&adapter->pdev->dev,
+ "HAL Version: %d, Privileged function\n",
+ adapter->fw_hal_version);
+ }
+ }
+
+ adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+ return err;
+}
+
+static int
+qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_esw_func_cfg esw_cfg;
+ struct qlcnic_npar_info *npar;
+ u8 i;
+
+ if (adapter->need_fw_reset)
+ return 0;
+
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+ if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+ continue;
+ memset(&esw_cfg, 0, sizeof(struct qlcnic_esw_func_cfg));
+ esw_cfg.pci_func = i;
+ esw_cfg.offload_flags = BIT_0;
+ esw_cfg.mac_override = BIT_0;
+ esw_cfg.promisc_mode = BIT_0;
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO)
+ esw_cfg.offload_flags |= (BIT_1 | BIT_2);
+ if (qlcnic_config_switch_port(adapter, &esw_cfg))
+ return -EIO;
+ npar = &adapter->npars[i];
+ npar->pvid = esw_cfg.vlan_id;
+ npar->mac_override = esw_cfg.mac_override;
+ npar->mac_anti_spoof = esw_cfg.mac_anti_spoof;
+ npar->discard_tagged = esw_cfg.discard_tagged;
+ npar->promisc_mode = esw_cfg.promisc_mode;
+ npar->offload_flags = esw_cfg.offload_flags;
+ }
+
+ return 0;
+}
+
+static int
+qlcnic_reset_eswitch_config(struct qlcnic_adapter *adapter,
+ struct qlcnic_npar_info *npar, int pci_func)
+{
+ struct qlcnic_esw_func_cfg esw_cfg;
+ esw_cfg.op_mode = QLCNIC_PORT_DEFAULTS;
+ esw_cfg.pci_func = pci_func;
+ esw_cfg.vlan_id = npar->pvid;
+ esw_cfg.mac_override = npar->mac_override;
+ esw_cfg.discard_tagged = npar->discard_tagged;
+ esw_cfg.mac_anti_spoof = npar->mac_anti_spoof;
+ esw_cfg.offload_flags = npar->offload_flags;
+ esw_cfg.promisc_mode = npar->promisc_mode;
+ if (qlcnic_config_switch_port(adapter, &esw_cfg))
+ return -EIO;
+
+ esw_cfg.op_mode = QLCNIC_ADD_VLAN;
+ if (qlcnic_config_switch_port(adapter, &esw_cfg))
+ return -EIO;
+
+ return 0;
}
static int
qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
{
- int i, err = 0;
+ int i, err;
struct qlcnic_npar_info *npar;
struct qlcnic_info nic_info;
- if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
- !adapter->need_fw_reset)
+ if (!adapter->need_fw_reset)
return 0;
- if (adapter->op_mode == QLCNIC_MGMT_FUNC) {
- /* Set the NPAR config data after FW reset */
- for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
- npar = &adapter->npars[i];
- if (npar->type != QLCNIC_TYPE_NIC)
- continue;
- err = qlcnic_get_nic_info(adapter, &nic_info, i);
- if (err)
- goto err_out;
- nic_info.min_tx_bw = npar->min_bw;
- nic_info.max_tx_bw = npar->max_bw;
- err = qlcnic_set_nic_info(adapter, &nic_info);
+ /* Set the NPAR config data after FW reset */
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+ npar = &adapter->npars[i];
+ if (npar->type != QLCNIC_TYPE_NIC)
+ continue;
+ err = qlcnic_get_nic_info(adapter, &nic_info, i);
+ if (err)
+ return err;
+ nic_info.min_tx_bw = npar->min_bw;
+ nic_info.max_tx_bw = npar->max_bw;
+ err = qlcnic_set_nic_info(adapter, &nic_info);
+ if (err)
+ return err;
+
+ if (npar->enable_pm) {
+ err = qlcnic_config_port_mirroring(adapter,
+ npar->dest_npar, 1, i);
if (err)
- goto err_out;
+ return err;
+ }
+ err = qlcnic_reset_eswitch_config(adapter, npar, i);
+ if (err)
+ return err;
+ }
+ return 0;
+}
- if (npar->enable_pm) {
- err = qlcnic_config_port_mirroring(adapter,
- npar->dest_npar, 1, i);
- if (err)
- goto err_out;
+static int qlcnic_check_npar_opertional(struct qlcnic_adapter *adapter)
+{
+ u8 npar_opt_timeo = QLCNIC_DEV_NPAR_OPER_TIMEO;
+ u32 npar_state;
- }
- npar->mac_learning = DEFAULT_MAC_LEARN;
- npar->host_vlan_tag = 0;
- npar->promisc_mode = 0;
- npar->discard_tagged = 0;
- npar->vlan_id = 0;
- }
+ if (adapter->op_mode == QLCNIC_MGMT_FUNC)
+ return 0;
+
+ npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+ while (npar_state != QLCNIC_DEV_NPAR_OPER && --npar_opt_timeo) {
+ msleep(1000);
+ npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
}
-err_out:
+ if (!npar_opt_timeo) {
+ dev_err(&adapter->pdev->dev,
+ "Waiting for NPAR state to opertional timeout\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static int
+qlcnic_set_mgmt_operations(struct qlcnic_adapter *adapter)
+{
+ int err;
+
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+ adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return 0;
+
+ err = qlcnic_set_default_offload_settings(adapter);
+ if (err)
+ return err;
+
+ err = qlcnic_reset_npar_config(adapter);
+ if (err)
+ return err;
+
+ qlcnic_dev_set_npar_ready(adapter);
+
return err;
}
static int
qlcnic_start_firmware(struct qlcnic_adapter *adapter)
{
- int val, err, first_boot;
+ int err;
err = qlcnic_can_start_firmware(adapter);
if (err < 0)
return err;
else if (!err)
- goto wait_init;
-
- first_boot = QLCRD32(adapter, QLCNIC_CAM_RAM(0x1fc));
- if (first_boot == 0x55555555)
- /* This is the first boot after power up */
- QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC);
+ goto check_fw_status;
if (load_fw_file)
qlcnic_request_firmware(adapter);
else {
- if (qlcnic_check_flash_fw_ver(adapter))
+ err = qlcnic_check_flash_fw_ver(adapter);
+ if (err)
goto err_out;
adapter->fw_type = QLCNIC_FLASH_ROMIMAGE;
}
err = qlcnic_need_fw_reset(adapter);
- if (err < 0)
- goto err_out;
if (err == 0)
- goto wait_init;
+ goto check_fw_status;
- if (first_boot != 0x55555555) {
- QLCWR32(adapter, CRB_CMDPEG_STATE, 0);
- QLCWR32(adapter, CRB_RCVPEG_STATE, 0);
- qlcnic_pinit_from_rom(adapter);
- msleep(1);
- }
-
- QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
- QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
-
- qlcnic_set_port_mode(adapter);
+ err = qlcnic_pinit_from_rom(adapter);
+ if (err)
+ goto err_out;
err = qlcnic_load_firmware(adapter);
if (err)
goto err_out;
qlcnic_release_firmware(adapter);
+ QLCWR32(adapter, CRB_DRIVER_VERSION, QLCNIC_DRIVER_VERSION);
- val = (_QLCNIC_LINUX_MAJOR << 16)
- | ((_QLCNIC_LINUX_MINOR << 8))
- | (_QLCNIC_LINUX_SUBVERSION);
- QLCWR32(adapter, CRB_DRIVER_VERSION, val);
-
-wait_init:
- /* Handshake with the card before we register the devices. */
- err = qlcnic_init_firmware(adapter);
+check_fw_status:
+ err = qlcnic_check_fw_status(adapter);
if (err)
goto err_out;
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
qlcnic_idc_debug_info(adapter, 1);
- qlcnic_check_options(adapter);
- if (qlcnic_reset_npar_config(adapter))
+ err = qlcnic_check_eswitch_mode(adapter);
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "Memory allocation failed for eswitch\n");
+ goto err_out;
+ }
+ err = qlcnic_set_mgmt_operations(adapter);
+ if (err)
goto err_out;
- qlcnic_dev_set_npar_ready(adapter);
+ qlcnic_check_options(adapter);
adapter->need_fw_reset = 0;
qlcnic_release_firmware(adapter);
@@ -896,6 +1041,7 @@ wait_init:
err_out:
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
dev_err(&adapter->pdev->dev, "Device state set to failed\n");
+
qlcnic_release_firmware(adapter);
return err;
}
@@ -979,6 +1125,8 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
return 0;
+ if (qlcnic_set_eswitch_port_config(adapter))
+ return -EIO;
if (qlcnic_fw_create_ctx(adapter))
return -EIO;
@@ -998,7 +1146,7 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
qlcnic_config_intr_coalesce(adapter);
- if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
+ if (netdev->features & NETIF_F_LRO)
qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED);
qlcnic_napi_enable(adapter);
@@ -1041,6 +1189,9 @@ __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
qlcnic_free_mac_list(adapter);
+ if (adapter->fhash.fnum)
+ qlcnic_delete_lb_filters(adapter);
+
qlcnic_nic_set_promisc(adapter, QLCNIC_NIU_NON_PROMISC_MODE);
qlcnic_napi_disable(adapter);
@@ -1277,7 +1428,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM | NETIF_F_GRO);
+ NETIF_F_IPV6_CSUM | NETIF_F_GRO | NETIF_F_HW_VLAN_RX);
netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM);
@@ -1296,12 +1447,8 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
netdev->features |= NETIF_F_LRO;
-
netdev->irq = adapter->msix_entries[0].vector;
- if (qlcnic_read_mac_addr(adapter))
- dev_warn(&pdev->dev, "failed to read mac addr\n");
-
netif_carrier_off(netdev);
netif_stop_queue(netdev);
@@ -1338,6 +1485,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
int err;
uint8_t revision_id;
uint8_t pci_using_dac;
+ char brd_name[QLCNIC_MAX_BOARD_NAME_LEN];
err = pci_enable_device(pdev);
if (err)
@@ -1395,10 +1543,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_iounmap;
}
- if (qlcnic_read_mac_addr(adapter))
- dev_warn(&pdev->dev, "failed to read mac addr\n");
-
- if (qlcnic_setup_idc_param(adapter))
+ err = qlcnic_setup_idc_param(adapter);
+ if (err)
goto err_out_iounmap;
err = adapter->nic_ops->start_firmware(adapter);
@@ -1407,6 +1553,17 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_decr_ref;
}
+ if (qlcnic_read_mac_addr(adapter))
+ dev_warn(&pdev->dev, "failed to read mac addr\n");
+
+ if (adapter->portnum == 0) {
+ get_brd_name(adapter, brd_name);
+
+ pr_info("%s: %s Board Chip rev 0x%x\n",
+ module_name(THIS_MODULE),
+ brd_name, adapter->ahw.revision_id);
+ }
+
qlcnic_clear_stats(adapter);
qlcnic_setup_intr(adapter);
@@ -1430,6 +1587,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
break;
}
+ qlcnic_alloc_lb_filters_mem(adapter);
qlcnic_create_diag_entries(adapter);
return 0;
@@ -1438,7 +1596,7 @@ err_out_disable_msi:
qlcnic_teardown_intr(adapter);
err_out_decr_ref:
- qlcnic_clr_all_drv_state(adapter);
+ qlcnic_clr_all_drv_state(adapter, 0);
err_out_iounmap:
qlcnic_cleanup_pci_map(adapter);
@@ -1477,10 +1635,12 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev)
if (adapter->eswitch != NULL)
kfree(adapter->eswitch);
- qlcnic_clr_all_drv_state(adapter);
+ qlcnic_clr_all_drv_state(adapter, 0);
clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ qlcnic_free_lb_filters_mem(adapter);
+
qlcnic_teardown_intr(adapter);
qlcnic_remove_diag_entries(adapter);
@@ -1509,7 +1669,7 @@ static int __qlcnic_shutdown(struct pci_dev *pdev)
if (netif_running(netdev))
qlcnic_down(adapter, netdev);
- qlcnic_clr_all_drv_state(adapter);
+ qlcnic_clr_all_drv_state(adapter, 0);
clear_bit(__QLCNIC_RESETTING, &adapter->state);
@@ -1573,7 +1733,7 @@ qlcnic_resume(struct pci_dev *pdev)
if (err)
goto done;
- qlcnic_config_indev_addr(netdev, NETDEV_UP);
+ qlcnic_restore_indev_addr(netdev, NETDEV_UP);
}
done:
netif_device_attach(netdev);
@@ -1587,9 +1747,6 @@ static int qlcnic_open(struct net_device *netdev)
struct qlcnic_adapter *adapter = netdev_priv(netdev);
int err;
- if (adapter->driver_mismatch)
- return -EIO;
-
err = qlcnic_attach(adapter);
if (err)
return err;
@@ -1619,6 +1776,126 @@ static int qlcnic_close(struct net_device *netdev)
}
static void
+qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter)
+{
+ void *head;
+ int i;
+
+ if (!qlcnic_mac_learn)
+ return;
+
+ spin_lock_init(&adapter->mac_learn_lock);
+
+ head = kcalloc(QLCNIC_LB_MAX_FILTERS, sizeof(struct hlist_head),
+ GFP_KERNEL);
+ if (!head)
+ return;
+
+ adapter->fhash.fmax = QLCNIC_LB_MAX_FILTERS;
+ adapter->fhash.fhead = (struct hlist_head *)head;
+
+ for (i = 0; i < adapter->fhash.fmax; i++)
+ INIT_HLIST_HEAD(&adapter->fhash.fhead[i]);
+}
+
+static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
+{
+ if (adapter->fhash.fmax && adapter->fhash.fhead)
+ kfree(adapter->fhash.fhead);
+
+ adapter->fhash.fhead = NULL;
+ adapter->fhash.fmax = 0;
+}
+
+static void qlcnic_change_filter(struct qlcnic_adapter *adapter,
+ u64 uaddr, __le16 vlan_id, struct qlcnic_host_tx_ring *tx_ring)
+{
+ struct cmd_desc_type0 *hwdesc;
+ struct qlcnic_nic_req *req;
+ struct qlcnic_mac_req *mac_req;
+ struct qlcnic_vlan_req *vlan_req;
+ u32 producer;
+ u64 word;
+
+ producer = tx_ring->producer;
+ hwdesc = &tx_ring->desc_head[tx_ring->producer];
+
+ req = (struct qlcnic_nic_req *)hwdesc;
+ memset(req, 0, sizeof(struct qlcnic_nic_req));
+ req->qhdr = cpu_to_le64(QLCNIC_REQUEST << 23);
+
+ word = QLCNIC_MAC_EVENT | ((u64)(adapter->portnum) << 16);
+ req->req_hdr = cpu_to_le64(word);
+
+ mac_req = (struct qlcnic_mac_req *)&(req->words[0]);
+ mac_req->op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
+ memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN);
+
+ vlan_req = (struct qlcnic_vlan_req *)&req->words[1];
+ vlan_req->vlan_id = vlan_id;
+
+ tx_ring->producer = get_next_index(producer, tx_ring->num_desc);
+}
+
+#define QLCNIC_MAC_HASH(MAC)\
+ ((((MAC) & 0x70000) >> 0x10) | (((MAC) & 0x70000000000ULL) >> 0x25))
+
+static void
+qlcnic_send_filter(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx_ring,
+ struct cmd_desc_type0 *first_desc,
+ struct sk_buff *skb)
+{
+ struct ethhdr *phdr = (struct ethhdr *)(skb->data);
+ struct qlcnic_filter *fil, *tmp_fil;
+ struct hlist_node *tmp_hnode, *n;
+ struct hlist_head *head;
+ u64 src_addr = 0;
+ __le16 vlan_id = 0;
+ u8 hindex;
+
+ if (!compare_ether_addr(phdr->h_source, adapter->mac_addr))
+ return;
+
+ if (adapter->fhash.fnum >= adapter->fhash.fmax)
+ return;
+
+ /* Only NPAR capable devices support vlan based learning*/
+ if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
+ vlan_id = first_desc->vlan_TCI;
+ memcpy(&src_addr, phdr->h_source, ETH_ALEN);
+ hindex = QLCNIC_MAC_HASH(src_addr) & (QLCNIC_LB_MAX_FILTERS - 1);
+ head = &(adapter->fhash.fhead[hindex]);
+
+ hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
+ if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
+ tmp_fil->vlan_id == vlan_id) {
+
+ if (jiffies >
+ (QLCNIC_READD_AGE * HZ + tmp_fil->ftime))
+ qlcnic_change_filter(adapter, src_addr, vlan_id,
+ tx_ring);
+ tmp_fil->ftime = jiffies;
+ return;
+ }
+ }
+
+ fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
+ if (!fil)
+ return;
+
+ qlcnic_change_filter(adapter, src_addr, vlan_id, tx_ring);
+
+ fil->ftime = jiffies;
+ fil->vlan_id = vlan_id;
+ memcpy(fil->faddr, &src_addr, ETH_ALEN);
+ spin_lock(&adapter->mac_learn_lock);
+ hlist_add_head(&(fil->fnode), head);
+ adapter->fhash.fnum++;
+ spin_unlock(&adapter->mac_learn_lock);
+}
+
+static void
qlcnic_tso_check(struct net_device *netdev,
struct qlcnic_host_tx_ring *tx_ring,
struct cmd_desc_type0 *first_desc,
@@ -1626,26 +1903,14 @@ qlcnic_tso_check(struct net_device *netdev,
{
u8 opcode = TX_ETHER_PKT;
__be16 protocol = skb->protocol;
- u16 flags = 0, vid = 0;
- int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0;
+ u16 flags = 0;
+ int copied, offset, copy_len, hdr_len = 0, tso = 0;
struct cmd_desc_type0 *hwdesc;
struct vlan_ethhdr *vh;
struct qlcnic_adapter *adapter = netdev_priv(netdev);
u32 producer = tx_ring->producer;
-
- if (protocol == cpu_to_be16(ETH_P_8021Q)) {
-
- vh = (struct vlan_ethhdr *)skb->data;
- protocol = vh->h_vlan_encapsulated_proto;
- flags = FLAGS_VLAN_TAGGED;
-
- } else if (vlan_tx_tag_present(skb)) {
-
- flags = FLAGS_VLAN_OOB;
- vid = vlan_tx_tag_get(skb);
- qlcnic_set_tx_vlan_tci(first_desc, vid);
- vlan_oob = 1;
- }
+ __le16 vlan_oob = first_desc->flags_opcode &
+ cpu_to_le16(FLAGS_VLAN_OOB);
if (*(skb->data) & BIT_0) {
flags |= BIT_0;
@@ -1716,7 +1981,8 @@ qlcnic_tso_check(struct net_device *netdev,
vh = (struct vlan_ethhdr *)((char *)hwdesc + 2);
skb_copy_from_linear_data(skb, vh, 12);
vh->h_vlan_proto = htons(ETH_P_8021Q);
- vh->h_vlan_TCI = htons(vid);
+ vh->h_vlan_TCI = (__be16)swab16((u16)first_desc->vlan_TCI);
+
skb_copy_from_linear_data_offset(skb, 12,
(char *)vh + 16, copy_len - 16);
@@ -1796,11 +2062,47 @@ out_err:
return -ENOMEM;
}
+static int
+qlcnic_check_tx_tagging(struct qlcnic_adapter *adapter,
+ struct sk_buff *skb,
+ struct cmd_desc_type0 *first_desc)
+{
+ u8 opcode = 0;
+ u16 flags = 0;
+ __be16 protocol = skb->protocol;
+ struct vlan_ethhdr *vh;
+
+ if (protocol == cpu_to_be16(ETH_P_8021Q)) {
+ vh = (struct vlan_ethhdr *)skb->data;
+ protocol = vh->h_vlan_encapsulated_proto;
+ flags = FLAGS_VLAN_TAGGED;
+ qlcnic_set_tx_vlan_tci(first_desc, ntohs(vh->h_vlan_TCI));
+ } else if (vlan_tx_tag_present(skb)) {
+ flags = FLAGS_VLAN_OOB;
+ qlcnic_set_tx_vlan_tci(first_desc, vlan_tx_tag_get(skb));
+ }
+ if (unlikely(adapter->pvid)) {
+ if (first_desc->vlan_TCI &&
+ !(adapter->flags & QLCNIC_TAGGING_ENABLED))
+ return -EIO;
+ if (first_desc->vlan_TCI &&
+ (adapter->flags & QLCNIC_TAGGING_ENABLED))
+ goto set_flags;
+
+ flags = FLAGS_VLAN_OOB;
+ qlcnic_set_tx_vlan_tci(first_desc, adapter->pvid);
+ }
+set_flags:
+ qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
+ return 0;
+}
+
static inline void
qlcnic_clear_cmddesc(u64 *desc)
{
desc[0] = 0ULL;
desc[2] = 0ULL;
+ desc[7] = 0ULL;
}
netdev_tx_t
@@ -1812,6 +2114,7 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
struct qlcnic_skb_frag *buffrag;
struct cmd_desc_type0 *hwdesc, *first_desc;
struct pci_dev *pdev;
+ struct ethhdr *phdr;
int i, k;
u32 producer;
@@ -1823,6 +2126,13 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_BUSY;
}
+ if (adapter->flags & QLCNIC_MACSPOOF) {
+ phdr = (struct ethhdr *)skb->data;
+ if (compare_ether_addr(phdr->h_source,
+ adapter->mac_addr))
+ goto drop_packet;
+ }
+
frag_count = skb_shinfo(skb)->nr_frags + 1;
/* 4 fragments per cmd des */
@@ -1844,6 +2154,12 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
pdev = adapter->pdev;
+ first_desc = hwdesc = &tx_ring->desc_head[producer];
+ qlcnic_clear_cmddesc((u64 *)hwdesc);
+
+ if (qlcnic_check_tx_tagging(adapter, skb, first_desc))
+ goto drop_packet;
+
if (qlcnic_map_tx_skb(pdev, skb, pbuf)) {
adapter->stats.tx_dma_map_error++;
goto drop_packet;
@@ -1852,9 +2168,6 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
pbuf->skb = skb;
pbuf->frag_count = frag_count;
- first_desc = hwdesc = &tx_ring->desc_head[producer];
- qlcnic_clear_cmddesc((u64 *)hwdesc);
-
qlcnic_set_tx_frags_len(first_desc, frag_count, skb->len);
qlcnic_set_tx_port(first_desc, adapter->portnum);
@@ -1893,6 +2206,9 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
qlcnic_tso_check(netdev, tx_ring, first_desc, skb);
+ if (qlcnic_mac_learn)
+ qlcnic_send_filter(adapter, tx_ring, first_desc, skb);
+
qlcnic_update_cmd_producer(adapter, tx_ring);
adapter->stats.txbytes += skb->len;
@@ -1947,14 +2263,14 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
struct net_device *netdev = adapter->netdev;
if (adapter->ahw.linkup && !linkup) {
- dev_info(&netdev->dev, "NIC Link is down\n");
+ netdev_info(netdev, "NIC Link is down\n");
adapter->ahw.linkup = 0;
if (netif_running(netdev)) {
netif_carrier_off(netdev);
netif_stop_queue(netdev);
}
} else if (!adapter->ahw.linkup && linkup) {
- dev_info(&netdev->dev, "NIC Link is up\n");
+ netdev_info(netdev, "NIC Link is up\n");
adapter->ahw.linkup = 1;
if (netif_running(netdev)) {
netif_carrier_on(netdev);
@@ -2258,18 +2574,22 @@ qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
}
static void
-qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter)
+qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed)
{
u32 val;
if (qlcnic_api_lock(adapter))
goto err;
- val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+ val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
QLC_DEV_CLR_REF_CNT(val, adapter->portnum);
- QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val);
+ QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
- if (!(val & 0x11111111))
+ if (failed) {
+ QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
+ dev_info(&adapter->pdev->dev,
+ "Device state set to Failed. Please Reboot\n");
+ } else if (!(val & 0x11111111))
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD);
val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
@@ -2290,7 +2610,7 @@ qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
int act, state;
state = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
- act = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+ act = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
if (((state & 0x11111111) == (act & 0x11111111)) ||
((act & 0x11111111) == ((state >> 1) & 0x11111111)))
@@ -2325,10 +2645,10 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
if (qlcnic_api_lock(adapter))
return -1;
- val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+ val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
if (!(val & (1 << (portnum * 4)))) {
QLC_DEV_SET_REF_CNT(val, portnum);
- QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val);
+ QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
}
prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
@@ -2403,13 +2723,14 @@ qlcnic_fwinit_work(struct work_struct *work)
{
struct qlcnic_adapter *adapter = container_of(work,
struct qlcnic_adapter, fw_work.work);
- u32 dev_state = 0xf, npar_state;
+ u32 dev_state = 0xf;
if (qlcnic_api_lock(adapter))
goto err_ret;
dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
- if (dev_state == QLCNIC_DEV_QUISCENT) {
+ if (dev_state == QLCNIC_DEV_QUISCENT ||
+ dev_state == QLCNIC_DEV_NEED_QUISCENT) {
qlcnic_api_unlock(adapter);
qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
FW_POLL_DELAY * 2);
@@ -2417,16 +2738,8 @@ qlcnic_fwinit_work(struct work_struct *work)
}
if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
- npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
- if (npar_state == QLCNIC_DEV_NPAR_RDY) {
- qlcnic_api_unlock(adapter);
- goto wait_npar;
- } else {
- qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
- FW_POLL_DELAY);
- qlcnic_api_unlock(adapter);
- return;
- }
+ qlcnic_api_unlock(adapter);
+ goto wait_npar;
}
if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
@@ -2439,18 +2752,6 @@ qlcnic_fwinit_work(struct work_struct *work)
skip_ack_check:
dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
- if (dev_state == QLCNIC_DEV_NEED_QUISCENT) {
- QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
- QLCNIC_DEV_QUISCENT);
- qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
- FW_POLL_DELAY * 2);
- QLCDB(adapter, DRV, "Quiscing the driver\n");
- qlcnic_idc_debug_info(adapter, 0);
-
- qlcnic_api_unlock(adapter);
- return;
- }
-
if (dev_state == QLCNIC_DEV_NEED_RESET) {
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
QLCNIC_DEV_INITIALIZING);
@@ -2463,6 +2764,7 @@ skip_ack_check:
if (!adapter->nic_ops->start_firmware(adapter)) {
qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
+ adapter->fw_wait_cnt = 0;
return;
}
goto err_ret;
@@ -2475,27 +2777,25 @@ wait_npar:
QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
switch (dev_state) {
- case QLCNIC_DEV_QUISCENT:
- case QLCNIC_DEV_NEED_QUISCENT:
- case QLCNIC_DEV_NEED_RESET:
- qlcnic_schedule_work(adapter,
- qlcnic_fwinit_work, FW_POLL_DELAY);
- return;
- case QLCNIC_DEV_FAILED:
- break;
-
- default:
+ case QLCNIC_DEV_READY:
if (!adapter->nic_ops->start_firmware(adapter)) {
qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
+ adapter->fw_wait_cnt = 0;
return;
}
+ case QLCNIC_DEV_FAILED:
+ break;
+ default:
+ qlcnic_schedule_work(adapter,
+ qlcnic_fwinit_work, FW_POLL_DELAY);
+ return;
}
err_ret:
dev_err(&adapter->pdev->dev, "Fwinit work failed state=%u "
"fw_wait_cnt=%u\n", dev_state, adapter->fw_wait_cnt);
netif_device_attach(adapter->netdev);
- qlcnic_clr_all_drv_state(adapter);
+ qlcnic_clr_all_drv_state(adapter, 0);
}
static void
@@ -2508,7 +2808,12 @@ qlcnic_detach_work(struct work_struct *work)
netif_device_detach(netdev);
- qlcnic_down(adapter, netdev);
+ /* Dont grab rtnl lock during Quiscent mode */
+ if (adapter->dev_state == QLCNIC_DEV_NEED_QUISCENT) {
+ if (netif_running(netdev))
+ __qlcnic_down(adapter, netdev);
+ } else
+ qlcnic_down(adapter, netdev);
status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
@@ -2531,8 +2836,78 @@ 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);
+ qlcnic_clr_all_drv_state(adapter, 1);
+}
+
+/*Transit NPAR state to NON Operational */
+static void
+qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)
+{
+ u32 state;
+
+ state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+ if (state == QLCNIC_DEV_NPAR_NON_OPER)
+ return;
+
+ if (qlcnic_api_lock(adapter))
+ return;
+ QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
+ qlcnic_api_unlock(adapter);
+}
+/* Caller should held RESETTING bit.
+ * This should be call in sync with qlcnic_request_quiscent_mode.
+ */
+void qlcnic_clear_quiscent_mode(struct qlcnic_adapter *adapter)
+{
+ qlcnic_clr_drv_state(adapter);
+ qlcnic_api_lock(adapter);
+ QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
+ qlcnic_api_unlock(adapter);
+}
+
+/* Caller should held RESETTING bit.
+ */
+int qlcnic_request_quiscent_mode(struct qlcnic_adapter *adapter)
+{
+ u8 timeo = adapter->dev_init_timeo / 2;
+ u32 state;
+
+ if (qlcnic_api_lock(adapter))
+ return -EIO;
+
+ state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+ if (state != QLCNIC_DEV_READY)
+ return -EIO;
+
+ QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_QUISCENT);
+ qlcnic_api_unlock(adapter);
+ QLCDB(adapter, DRV, "NEED QUISCENT state set\n");
+ qlcnic_idc_debug_info(adapter, 0);
+
+ qlcnic_set_drv_state(adapter, QLCNIC_DEV_NEED_QUISCENT);
+
+ do {
+ msleep(2000);
+ state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+ if (state == QLCNIC_DEV_QUISCENT)
+ return 0;
+ if (!qlcnic_check_drv_state(adapter)) {
+ if (qlcnic_api_lock(adapter))
+ return -EIO;
+ QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
+ QLCNIC_DEV_QUISCENT);
+ qlcnic_api_unlock(adapter);
+ QLCDB(adapter, DRV, "QUISCENT mode set\n");
+ return 0;
+ }
+ } while (--timeo);
+
+ dev_err(&adapter->pdev->dev, "Failed to quiesce device, DRV_STATE=%08x"
+ " DRV_ACTIVE=%08x\n", QLCRD32(adapter, QLCNIC_CRB_DRV_STATE),
+ QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE));
+ qlcnic_clear_quiscent_mode(adapter);
+ return -EIO;
}
/*Transit to RESET state from READY state only */
@@ -2553,6 +2928,7 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
qlcnic_idc_debug_info(adapter, 0);
}
+ QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
qlcnic_api_unlock(adapter);
}
@@ -2560,21 +2936,11 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
static void
qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
{
- u32 state;
-
- if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
- adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
- return;
if (qlcnic_api_lock(adapter))
return;
- state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
-
- if (state != QLCNIC_DEV_NPAR_RDY) {
- QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
- QLCNIC_DEV_NPAR_RDY);
- QLCDB(adapter, DRV, "NPAR READY state set\n");
- }
+ QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_OPER);
+ QLCDB(adapter, DRV, "NPAR operational state set\n");
qlcnic_api_unlock(adapter);
}
@@ -2587,7 +2953,8 @@ qlcnic_schedule_work(struct qlcnic_adapter *adapter,
return;
INIT_DELAYED_WORK(&adapter->fw_work, func);
- schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay));
+ queue_delayed_work(qlcnic_wq, &adapter->fw_work,
+ round_jiffies_relative(delay));
}
static void
@@ -2605,12 +2972,26 @@ qlcnic_attach_work(struct work_struct *work)
struct qlcnic_adapter *adapter = container_of(work,
struct qlcnic_adapter, fw_work.work);
struct net_device *netdev = adapter->netdev;
+ u32 npar_state;
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC) {
+ npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+ if (adapter->fw_wait_cnt++ > QLCNIC_DEV_NPAR_OPER_TIMEO)
+ qlcnic_clr_all_drv_state(adapter, 0);
+ else if (npar_state != QLCNIC_DEV_NPAR_OPER)
+ qlcnic_schedule_work(adapter, qlcnic_attach_work,
+ FW_POLL_DELAY);
+ else
+ goto attach;
+ QLCDB(adapter, DRV, "Waiting for NPAR state to operational\n");
+ return;
+ }
+attach:
if (netif_running(netdev)) {
if (qlcnic_up(adapter, netdev))
goto done;
- qlcnic_config_indev_addr(netdev, NETDEV_UP);
+ qlcnic_restore_indev_addr(netdev, NETDEV_UP);
}
done:
@@ -2626,7 +3007,7 @@ done:
static int
qlcnic_check_health(struct qlcnic_adapter *adapter)
{
- u32 state = 0, heartbit;
+ u32 state = 0, heartbeat;
struct net_device *netdev = adapter->netdev;
if (qlcnic_check_temp(adapter))
@@ -2636,12 +3017,15 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
qlcnic_dev_request_reset(adapter);
state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
- if (state == QLCNIC_DEV_NEED_RESET || state == QLCNIC_DEV_NEED_QUISCENT)
+ if (state == QLCNIC_DEV_NEED_RESET) {
+ qlcnic_set_npar_non_operational(adapter);
adapter->need_fw_reset = 1;
+ } else if (state == QLCNIC_DEV_NEED_QUISCENT)
+ goto detach;
- heartbit = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
- if (heartbit != adapter->heartbit) {
- adapter->heartbit = heartbit;
+ heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+ if (heartbeat != adapter->heartbeat) {
+ adapter->heartbeat = heartbeat;
adapter->fw_fail_cnt = 0;
if (adapter->need_fw_reset)
goto detach;
@@ -2692,6 +3076,9 @@ qlcnic_fw_poll_work(struct work_struct *work)
if (qlcnic_check_health(adapter))
return;
+ if (adapter->fhash.fnum)
+ qlcnic_prune_lb_filters(adapter);
+
reschedule:
qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
}
@@ -2738,7 +3125,7 @@ static int qlcnic_attach_func(struct pci_dev *pdev)
if (qlcnic_api_lock(adapter))
return -EINVAL;
- if (first_func) {
+ if (adapter->op_mode != QLCNIC_NON_PRIV_FUNC && first_func) {
adapter->need_fw_reset = 1;
set_bit(__QLCNIC_START_FW, &adapter->state);
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
@@ -2756,7 +3143,7 @@ static int qlcnic_attach_func(struct pci_dev *pdev)
if (netif_running(netdev)) {
err = qlcnic_attach(adapter);
if (err) {
- qlcnic_clr_all_drv_state(adapter);
+ qlcnic_clr_all_drv_state(adapter, 1);
clear_bit(__QLCNIC_AER, &adapter->state);
netif_device_attach(netdev);
return err;
@@ -2766,7 +3153,7 @@ static int qlcnic_attach_func(struct pci_dev *pdev)
if (err)
goto done;
- qlcnic_config_indev_addr(netdev, NETDEV_UP);
+ qlcnic_restore_indev_addr(netdev, NETDEV_UP);
}
done:
netif_device_attach(netdev);
@@ -2822,7 +3209,6 @@ static void qlcnic_io_resume(struct pci_dev *pdev)
FW_POLL_DELAY);
}
-
static int
qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
{
@@ -2832,8 +3218,20 @@ qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
if (err)
return err;
+ err = qlcnic_check_npar_opertional(adapter);
+ if (err)
+ return err;
+
+ err = qlcnic_initialize_nic(adapter);
+ if (err)
+ return err;
+
qlcnic_check_options(adapter);
+ err = qlcnic_set_eswitch_port_config(adapter);
+ if (err)
+ return err;
+
adapter->need_fw_reset = 0;
return err;
@@ -3093,9 +3491,6 @@ validate_pm_config(struct qlcnic_adapter *adapter,
if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
return QL_STATUS_INVALID_PARAM;
- if (!IS_VALID_MODE(pm_cfg[i].action))
- return QL_STATUS_INVALID_PARAM;
-
s_esw_id = adapter->npars[src_pci_func].phy_port;
d_esw_id = adapter->npars[dest_pci_func].phy_port;
@@ -3129,7 +3524,7 @@ qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
return ret;
for (i = 0; i < count; i++) {
pci_func = pm_cfg[i].pci_func;
- action = pm_cfg[i].action;
+ action = !!pm_cfg[i].action;
id = adapter->npars[pci_func].phy_port;
ret = qlcnic_config_port_mirroring(adapter, id,
action, pci_func);
@@ -3140,7 +3535,7 @@ qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
for (i = 0; i < count; i++) {
pci_func = pm_cfg[i].pci_func;
id = adapter->npars[pci_func].phy_port;
- adapter->npars[pci_func].enable_pm = pm_cfg[i].action;
+ adapter->npars[pci_func].enable_pm = !!pm_cfg[i].action;
adapter->npars[pci_func].dest_npar = id;
}
return size;
@@ -3172,30 +3567,46 @@ qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
static int
validate_esw_config(struct qlcnic_adapter *adapter,
- struct qlcnic_esw_func_cfg *esw_cfg, int count)
+ struct qlcnic_esw_func_cfg *esw_cfg, int count)
{
+ u32 op_mode;
u8 pci_func;
int i;
+ op_mode = readl(adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE);
+
for (i = 0; i < count; i++) {
pci_func = esw_cfg[i].pci_func;
if (pci_func >= QLCNIC_MAX_PCI_FUNC)
return QL_STATUS_INVALID_PARAM;
- if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
- return QL_STATUS_INVALID_PARAM;
+ if (adapter->op_mode == QLCNIC_MGMT_FUNC)
+ if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
+ return QL_STATUS_INVALID_PARAM;
- if (esw_cfg->host_vlan_tag == 1)
+ switch (esw_cfg[i].op_mode) {
+ case QLCNIC_PORT_DEFAULTS:
+ if (QLC_DEV_GET_DRV(op_mode, pci_func) !=
+ QLCNIC_NON_PRIV_FUNC) {
+ esw_cfg[i].mac_anti_spoof = 0;
+ esw_cfg[i].mac_override = 1;
+ esw_cfg[i].promisc_mode = 1;
+ }
+ break;
+ case QLCNIC_ADD_VLAN:
if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
return QL_STATUS_INVALID_PARAM;
-
- if (!IS_VALID_MODE(esw_cfg[i].promisc_mode)
- || !IS_VALID_MODE(esw_cfg[i].host_vlan_tag)
- || !IS_VALID_MODE(esw_cfg[i].mac_learning)
- || !IS_VALID_MODE(esw_cfg[i].discard_tagged))
+ if (!esw_cfg[i].op_type)
+ return QL_STATUS_INVALID_PARAM;
+ break;
+ case QLCNIC_DEL_VLAN:
+ if (!esw_cfg[i].op_type)
+ return QL_STATUS_INVALID_PARAM;
+ break;
+ default:
return QL_STATUS_INVALID_PARAM;
+ }
}
-
return 0;
}
@@ -3206,8 +3617,9 @@ qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
struct qlcnic_esw_func_cfg *esw_cfg;
+ struct qlcnic_npar_info *npar;
int count, rem, i, ret;
- u8 id, pci_func;
+ u8 pci_func, op_mode = 0;
count = size / sizeof(struct qlcnic_esw_func_cfg);
rem = size % sizeof(struct qlcnic_esw_func_cfg);
@@ -3220,30 +3632,55 @@ qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
return ret;
for (i = 0; i < count; i++) {
- pci_func = esw_cfg[i].pci_func;
- id = adapter->npars[pci_func].phy_port;
- ret = qlcnic_config_switch_port(adapter, id,
- esw_cfg[i].host_vlan_tag,
- esw_cfg[i].discard_tagged,
- esw_cfg[i].promisc_mode,
- esw_cfg[i].mac_learning,
- esw_cfg[i].pci_func,
- esw_cfg[i].vlan_id);
- if (ret)
- return ret;
+ if (adapter->op_mode == QLCNIC_MGMT_FUNC)
+ if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
+ return QL_STATUS_INVALID_PARAM;
+
+ if (adapter->ahw.pci_func != esw_cfg[i].pci_func)
+ continue;
+
+ op_mode = esw_cfg[i].op_mode;
+ qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]);
+ esw_cfg[i].op_mode = op_mode;
+ esw_cfg[i].pci_func = adapter->ahw.pci_func;
+
+ switch (esw_cfg[i].op_mode) {
+ case QLCNIC_PORT_DEFAULTS:
+ qlcnic_set_eswitch_port_features(adapter, &esw_cfg[i]);
+ break;
+ case QLCNIC_ADD_VLAN:
+ qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
+ break;
+ case QLCNIC_DEL_VLAN:
+ esw_cfg[i].vlan_id = 0;
+ qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
+ break;
+ }
}
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ goto out;
+
for (i = 0; i < count; i++) {
pci_func = esw_cfg[i].pci_func;
- adapter->npars[pci_func].promisc_mode = esw_cfg[i].promisc_mode;
- adapter->npars[pci_func].mac_learning = esw_cfg[i].mac_learning;
- adapter->npars[pci_func].vlan_id = esw_cfg[i].vlan_id;
- adapter->npars[pci_func].discard_tagged =
- esw_cfg[i].discard_tagged;
- adapter->npars[pci_func].host_vlan_tag =
- esw_cfg[i].host_vlan_tag;
+ npar = &adapter->npars[pci_func];
+ switch (esw_cfg[i].op_mode) {
+ case QLCNIC_PORT_DEFAULTS:
+ npar->promisc_mode = esw_cfg[i].promisc_mode;
+ npar->mac_override = esw_cfg[i].mac_override;
+ npar->offload_flags = esw_cfg[i].offload_flags;
+ npar->mac_anti_spoof = esw_cfg[i].mac_anti_spoof;
+ npar->discard_tagged = esw_cfg[i].discard_tagged;
+ break;
+ case QLCNIC_ADD_VLAN:
+ npar->pvid = esw_cfg[i].vlan_id;
+ break;
+ case QLCNIC_DEL_VLAN:
+ npar->pvid = 0;
+ break;
+ }
}
-
+out:
return size;
}
@@ -3254,7 +3691,7 @@ qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
- int i;
+ u8 i;
if (size != sizeof(esw_cfg))
return QL_STATUS_INVALID_PARAM;
@@ -3262,12 +3699,9 @@ qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
continue;
-
- esw_cfg[i].host_vlan_tag = adapter->npars[i].host_vlan_tag;
- esw_cfg[i].promisc_mode = adapter->npars[i].promisc_mode;
- esw_cfg[i].discard_tagged = adapter->npars[i].discard_tagged;
- esw_cfg[i].vlan_id = adapter->npars[i].vlan_id;
- esw_cfg[i].mac_learning = adapter->npars[i].mac_learning;
+ esw_cfg[i].pci_func = i;
+ if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]))
+ return QL_STATUS_INVALID_PARAM;
}
memcpy(buf, &esw_cfg, size);
@@ -3357,7 +3791,7 @@ qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
return ret;
np_cfg[i].pci_func = i;
- np_cfg[i].op_mode = nic_info.op_mode;
+ np_cfg[i].op_mode = (u8)nic_info.op_mode;
np_cfg[i].port_num = nic_info.phys_port;
np_cfg[i].fw_capab = nic_info.capabilities;
np_cfg[i].min_bw = nic_info.min_tx_bw ;
@@ -3370,6 +3804,115 @@ qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
}
static ssize_t
+qlcnic_sysfs_get_port_stats(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_esw_statistics port_stats;
+ int ret;
+
+ if (size != sizeof(struct qlcnic_esw_statistics))
+ return QL_STATUS_INVALID_PARAM;
+
+ if (offset >= QLCNIC_MAX_PCI_FUNC)
+ return QL_STATUS_INVALID_PARAM;
+
+ memset(&port_stats, 0, size);
+ ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
+ &port_stats.rx);
+ if (ret)
+ return ret;
+
+ ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
+ &port_stats.tx);
+ if (ret)
+ return ret;
+
+ memcpy(buf, &port_stats, size);
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_get_esw_stats(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_esw_statistics esw_stats;
+ int ret;
+
+ if (size != sizeof(struct qlcnic_esw_statistics))
+ return QL_STATUS_INVALID_PARAM;
+
+ if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
+ return QL_STATUS_INVALID_PARAM;
+
+ memset(&esw_stats, 0, size);
+ ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
+ &esw_stats.rx);
+ if (ret)
+ return ret;
+
+ ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
+ &esw_stats.tx);
+ if (ret)
+ return ret;
+
+ memcpy(buf, &esw_stats, size);
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_clear_esw_stats(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ int ret;
+
+ if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
+ return QL_STATUS_INVALID_PARAM;
+
+ ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
+ QLCNIC_QUERY_RX_COUNTER);
+ if (ret)
+ return ret;
+
+ ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
+ QLCNIC_QUERY_TX_COUNTER);
+ if (ret)
+ return ret;
+
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_clear_port_stats(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ int ret;
+
+ if (offset >= QLCNIC_MAX_PCI_FUNC)
+ return QL_STATUS_INVALID_PARAM;
+
+ ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
+ QLCNIC_QUERY_RX_COUNTER);
+ if (ret)
+ return ret;
+
+ ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
+ QLCNIC_QUERY_TX_COUNTER);
+ if (ret)
+ return ret;
+
+ return size;
+}
+
+static ssize_t
qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
{
@@ -3418,6 +3961,20 @@ static struct bin_attribute bin_attr_pci_config = {
.write = NULL,
};
+static struct bin_attribute bin_attr_port_stats = {
+ .attr = {.name = "port_stats", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_get_port_stats,
+ .write = qlcnic_sysfs_clear_port_stats,
+};
+
+static struct bin_attribute bin_attr_esw_stats = {
+ .attr = {.name = "esw_stats", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_get_esw_stats,
+ .write = qlcnic_sysfs_clear_esw_stats,
+};
+
static struct bin_attribute bin_attr_esw_config = {
.attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
.size = 0,
@@ -3457,6 +4014,9 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
{
struct device *dev = &adapter->pdev->dev;
+ if (device_create_bin_file(dev, &bin_attr_port_stats))
+ dev_info(dev, "failed to create port stats sysfs entry");
+
if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
return;
if (device_create_file(dev, &dev_attr_diag_mode))
@@ -3465,18 +4025,20 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
dev_info(dev, "failed to create crb sysfs entry\n");
if (device_create_bin_file(dev, &bin_attr_mem))
dev_info(dev, "failed to create mem sysfs entry\n");
- if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
- adapter->op_mode != QLCNIC_MGMT_FUNC)
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
+ return;
+ if (device_create_bin_file(dev, &bin_attr_esw_config))
+ dev_info(dev, "failed to create esw config sysfs entry");
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
return;
if (device_create_bin_file(dev, &bin_attr_pci_config))
dev_info(dev, "failed to create pci config sysfs entry");
if (device_create_bin_file(dev, &bin_attr_npar_config))
dev_info(dev, "failed to create npar config sysfs entry");
- if (device_create_bin_file(dev, &bin_attr_esw_config))
- dev_info(dev, "failed to create esw config sysfs entry");
if (device_create_bin_file(dev, &bin_attr_pm_config))
dev_info(dev, "failed to create pm config sysfs entry");
-
+ if (device_create_bin_file(dev, &bin_attr_esw_stats))
+ dev_info(dev, "failed to create eswitch stats sysfs entry");
}
static void
@@ -3484,18 +4046,22 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
{
struct device *dev = &adapter->pdev->dev;
+ device_remove_bin_file(dev, &bin_attr_port_stats);
+
if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
return;
device_remove_file(dev, &dev_attr_diag_mode);
device_remove_bin_file(dev, &bin_attr_crb);
device_remove_bin_file(dev, &bin_attr_mem);
- if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
- adapter->op_mode != QLCNIC_MGMT_FUNC)
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
+ return;
+ device_remove_bin_file(dev, &bin_attr_esw_config);
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
return;
device_remove_bin_file(dev, &bin_attr_pci_config);
device_remove_bin_file(dev, &bin_attr_npar_config);
- device_remove_bin_file(dev, &bin_attr_esw_config);
device_remove_bin_file(dev, &bin_attr_pm_config);
+ device_remove_bin_file(dev, &bin_attr_esw_stats);
}
#ifdef CONFIG_INET
@@ -3503,10 +4069,10 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
#define is_qlcnic_netdev(dev) (dev->netdev_ops == &qlcnic_netdev_ops)
static void
-qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
+qlcnic_config_indev_addr(struct qlcnic_adapter *adapter,
+ struct net_device *dev, unsigned long event)
{
struct in_device *indev;
- struct qlcnic_adapter *adapter = netdev_priv(dev);
indev = in_dev_get(dev);
if (!indev)
@@ -3530,6 +4096,27 @@ qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
in_dev_put(indev);
}
+static void
+qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct net_device *dev;
+ u16 vid;
+
+ qlcnic_config_indev_addr(adapter, netdev, event);
+
+ if (!adapter->vlgrp)
+ return;
+
+ for (vid = 0; vid < VLAN_N_VID; vid++) {
+ dev = vlan_group_get_device(adapter->vlgrp, vid);
+ if (!dev)
+ continue;
+
+ qlcnic_config_indev_addr(adapter, dev, event);
+ }
+}
+
static int qlcnic_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
@@ -3556,7 +4143,7 @@ recheck:
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
goto done;
- qlcnic_config_indev_addr(dev, event);
+ qlcnic_config_indev_addr(adapter, dev, event);
done:
return NOTIFY_DONE;
}
@@ -3573,7 +4160,7 @@ qlcnic_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) {
@@ -3616,7 +4203,7 @@ static struct notifier_block qlcnic_inetaddr_cb = {
};
#else
static void
-qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
+qlcnic_restore_indev_addr(struct net_device *dev, unsigned long event)
{ }
#endif
static struct pci_error_handlers qlcnic_err_handler = {
@@ -3645,6 +4232,12 @@ static int __init qlcnic_init_module(void)
printk(KERN_INFO "%s\n", qlcnic_driver_string);
+ qlcnic_wq = create_singlethread_workqueue("qlcnic");
+ if (qlcnic_wq == NULL) {
+ printk(KERN_ERR "qlcnic: cannot create workqueue\n");
+ return -ENOMEM;
+ }
+
#ifdef CONFIG_INET
register_netdevice_notifier(&qlcnic_netdev_cb);
register_inetaddr_notifier(&qlcnic_inetaddr_cb);
@@ -3656,6 +4249,7 @@ static int __init qlcnic_init_module(void)
unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
unregister_netdevice_notifier(&qlcnic_netdev_cb);
#endif
+ destroy_workqueue(qlcnic_wq);
}
return ret;
@@ -3672,6 +4266,7 @@ static void __exit qlcnic_exit_module(void)
unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
unregister_netdevice_notifier(&qlcnic_netdev_cb);
#endif
+ destroy_workqueue(qlcnic_wq);
}
module_exit(qlcnic_exit_module);
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index a478786840a6..22821398fc63 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -2226,7 +2226,6 @@ int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf,
int ql_core_dump(struct ql_adapter *qdev,
struct ql_mpi_coredump *mpi_coredump);
int ql_mb_about_fw(struct ql_adapter *qdev);
-int ql_wol(struct ql_adapter *qdev);
int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol);
int ql_mb_wol_mode(struct ql_adapter *qdev, u32 wol);
int ql_mb_set_led_cfg(struct ql_adapter *qdev, u32 led_config);
@@ -2243,16 +2242,13 @@ netdev_tx_t ql_lb_send(struct sk_buff *skb, struct net_device *ndev);
void ql_check_lb_frame(struct ql_adapter *, struct sk_buff *);
int ql_own_firmware(struct ql_adapter *qdev);
int ql_clean_lb_rx_ring(struct rx_ring *rx_ring, int budget);
-void qlge_set_multicast_list(struct net_device *ndev);
-#if 1
-#define QL_ALL_DUMP
-#define QL_REG_DUMP
-#define QL_DEV_DUMP
-#define QL_CB_DUMP
+/* #define QL_ALL_DUMP */
+/* #define QL_REG_DUMP */
+/* #define QL_DEV_DUMP */
+/* #define QL_CB_DUMP */
/* #define QL_IB_DUMP */
/* #define QL_OB_DUMP */
-#endif
#ifdef QL_REG_DUMP
extern void ql_dump_xgmac_control_regs(struct ql_adapter *qdev);
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 5f89e83501f4..c30e0fe55a31 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -94,6 +94,9 @@ static DEFINE_PCI_DEVICE_TABLE(qlge_pci_tbl) = {
MODULE_DEVICE_TABLE(pci, qlge_pci_tbl);
+static int ql_wol(struct ql_adapter *qdev);
+static void qlge_set_multicast_list(struct net_device *ndev);
+
/* This hardware semaphore causes exclusive access to
* resources shared between the NIC driver, MPI firmware,
* FCOE firmware and the FC driver.
@@ -1566,7 +1569,7 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,
rx_ring->rx_packets++;
rx_ring->rx_bytes += skb->len;
skb->protocol = eth_type_trans(skb, ndev);
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
if (qdev->rx_csum &&
!(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) {
@@ -1676,7 +1679,7 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev,
rx_ring->rx_packets++;
rx_ring->rx_bytes += skb->len;
skb->protocol = eth_type_trans(skb, ndev);
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
/* If rx checksum is on, and there are no
* csum or frame errors.
@@ -1996,7 +1999,7 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,
}
skb->protocol = eth_type_trans(skb, ndev);
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
/* If rx checksum is on, and there are no
* csum or frame errors.
@@ -2222,10 +2225,11 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring)
ql_update_cq(rx_ring);
prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
}
+ if (!net_rsp)
+ return 0;
ql_write_cq_idx(rx_ring);
tx_ring = &qdev->tx_ring[net_rsp->txq_idx];
- if (__netif_subqueue_stopped(qdev->ndev, tx_ring->wq_id) &&
- net_rsp != NULL) {
+ if (__netif_subqueue_stopped(qdev->ndev, tx_ring->wq_id)) {
if (atomic_read(&tx_ring->queue_stopped) &&
(atomic_read(&tx_ring->tx_count) > (tx_ring->wq_len / 4)))
/*
@@ -2381,6 +2385,20 @@ static void qlge_vlan_rx_kill_vid(struct net_device *ndev, u16 vid)
}
+static void qlge_restore_vlan(struct ql_adapter *qdev)
+{
+ qlge_vlan_rx_register(qdev->ndev, qdev->vlgrp);
+
+ if (qdev->vlgrp) {
+ u16 vid;
+ for (vid = 0; vid < VLAN_N_VID; vid++) {
+ if (!vlan_group_get_device(qdev->vlgrp, vid))
+ continue;
+ qlge_vlan_rx_add_vid(qdev->ndev, vid);
+ }
+ }
+}
+
/* MSI-X Multiple Vector Interrupt Handler for inbound completions. */
static irqreturn_t qlge_msix_rx_isr(int irq, void *dev_id)
{
@@ -2571,7 +2589,7 @@ static netdev_tx_t qlge_send(struct sk_buff *skb, struct net_device *ndev)
mac_iocb_ptr->frame_len = cpu_to_le16((u16) skb->len);
- if (qdev->vlgrp && vlan_tx_tag_present(skb)) {
+ if (vlan_tx_tag_present(skb)) {
netif_printk(qdev, tx_queued, KERN_DEBUG, qdev->ndev,
"Adding a vlan tag %d.\n", vlan_tx_tag_get(skb));
mac_iocb_ptr->flags3 |= OB_MAC_IOCB_V;
@@ -3841,7 +3859,7 @@ static void ql_display_dev_info(struct net_device *ndev)
"MAC address %pM\n", ndev->dev_addr);
}
-int ql_wol(struct ql_adapter *qdev)
+static int ql_wol(struct ql_adapter *qdev)
{
int status = 0;
u32 wol = MB_WOL_DISABLE;
@@ -3888,11 +3906,8 @@ int ql_wol(struct ql_adapter *qdev)
return status;
}
-static int ql_adapter_down(struct ql_adapter *qdev)
+static void ql_cancel_all_work_sync(struct ql_adapter *qdev)
{
- int i, status = 0;
-
- ql_link_off(qdev);
/* Don't kill the reset worker thread if we
* are in the process of recovery.
@@ -3904,6 +3919,15 @@ static int ql_adapter_down(struct ql_adapter *qdev)
cancel_delayed_work_sync(&qdev->mpi_idc_work);
cancel_delayed_work_sync(&qdev->mpi_core_to_log);
cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
+}
+
+static int ql_adapter_down(struct ql_adapter *qdev)
+{
+ int i, status = 0;
+
+ ql_link_off(qdev);
+
+ ql_cancel_all_work_sync(qdev);
for (i = 0; i < qdev->rss_ring_count; i++)
napi_disable(&qdev->rx_ring[i].napi);
@@ -3950,6 +3974,9 @@ static int ql_adapter_up(struct ql_adapter *qdev)
clear_bit(QL_PROMISCUOUS, &qdev->flags);
qlge_set_multicast_list(qdev->ndev);
+ /* Restore vlan setting. */
+ qlge_restore_vlan(qdev);
+
ql_enable_interrupts(qdev);
ql_enable_all_completion_interrupts(qdev);
netif_tx_start_all_queues(qdev->ndev);
@@ -4235,7 +4262,7 @@ static struct net_device_stats *qlge_get_stats(struct net_device
return &ndev->stats;
}
-void qlge_set_multicast_list(struct net_device *ndev)
+static void qlge_set_multicast_list(struct net_device *ndev)
{
struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
struct netdev_hw_addr *ha;
@@ -4726,6 +4753,7 @@ static void __devexit qlge_remove(struct pci_dev *pdev)
struct net_device *ndev = pci_get_drvdata(pdev);
struct ql_adapter *qdev = netdev_priv(ndev);
del_timer_sync(&qdev->timer);
+ ql_cancel_all_work_sync(qdev);
unregister_netdev(ndev);
ql_release_all(pdev);
pci_disable_device(pdev);
@@ -4745,13 +4773,7 @@ static void ql_eeh_close(struct net_device *ndev)
/* Disabling the timer */
del_timer_sync(&qdev->timer);
- if (test_bit(QL_ADAPTER_UP, &qdev->flags))
- cancel_delayed_work_sync(&qdev->asic_reset_work);
- cancel_delayed_work_sync(&qdev->mpi_reset_work);
- cancel_delayed_work_sync(&qdev->mpi_work);
- cancel_delayed_work_sync(&qdev->mpi_idc_work);
- cancel_delayed_work_sync(&qdev->mpi_core_to_log);
- cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
+ ql_cancel_all_work_sync(qdev);
for (i = 0; i < qdev->rss_ring_count; i++)
netif_napi_del(&qdev->rx_ring[i].napi);
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index f84e8570c7cb..0e7c7c7ee164 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -87,7 +87,7 @@ exit:
return status;
}
-int ql_soft_reset_mpi_risc(struct ql_adapter *qdev)
+static int ql_soft_reset_mpi_risc(struct ql_adapter *qdev)
{
int status;
status = ql_write_mpi_reg(qdev, 0x00001010, 1);
@@ -681,7 +681,7 @@ int ql_mb_get_fw_state(struct ql_adapter *qdev)
/* Send and ACK mailbox command to the firmware to
* let it continue with the change.
*/
-int ql_mb_idc_ack(struct ql_adapter *qdev)
+static int ql_mb_idc_ack(struct ql_adapter *qdev)
{
struct mbox_params mbc;
struct mbox_params *mbcp = &mbc;
@@ -744,7 +744,7 @@ int ql_mb_set_port_cfg(struct ql_adapter *qdev)
return status;
}
-int ql_mb_dump_ram(struct ql_adapter *qdev, u64 req_dma, u32 addr,
+static int ql_mb_dump_ram(struct ql_adapter *qdev, u64 req_dma, u32 addr,
u32 size)
{
int status = 0;
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 142c381e1d73..0b014c894686 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -200,7 +200,7 @@ struct r6040_private {
int old_duplex;
};
-static char version[] __devinitdata = KERN_INFO DRV_NAME
+static char version[] __devinitdata = DRV_NAME
": RDC R6040 NAPI net driver,"
"version "DRV_VERSION " (" DRV_RELDATE ")";
@@ -224,7 +224,8 @@ static int r6040_phy_read(void __iomem *ioaddr, int phy_addr, int reg)
}
/* Write a word data from PHY Chip */
-static void r6040_phy_write(void __iomem *ioaddr, int phy_addr, int reg, u16 val)
+static void r6040_phy_write(void __iomem *ioaddr,
+ int phy_addr, int reg, u16 val)
{
int limit = 2048;
u16 cmd;
@@ -348,8 +349,8 @@ static int r6040_alloc_rxbufs(struct net_device *dev)
}
desc->skb_ptr = skb;
desc->buf = cpu_to_le32(pci_map_single(lp->pdev,
- desc->skb_ptr->data,
- MAX_BUF_SIZE, PCI_DMA_FROMDEVICE));
+ desc->skb_ptr->data,
+ MAX_BUF_SIZE, PCI_DMA_FROMDEVICE));
desc->status = DSC_OWNER_MAC;
desc = desc->vndescp;
} while (desc != lp->rx_ring);
@@ -491,12 +492,14 @@ static int r6040_close(struct net_device *dev)
/* Free Descriptor memory */
if (lp->rx_ring) {
- pci_free_consistent(pdev, RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma);
+ pci_free_consistent(pdev,
+ RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma);
lp->rx_ring = NULL;
}
if (lp->tx_ring) {
- pci_free_consistent(pdev, TX_DESC_SIZE, lp->tx_ring, lp->tx_ring_dma);
+ pci_free_consistent(pdev,
+ TX_DESC_SIZE, lp->tx_ring, lp->tx_ring_dma);
lp->tx_ring = NULL;
}
@@ -547,7 +550,7 @@ static int r6040_rx(struct net_device *dev, int limit)
}
goto next_descr;
}
-
+
/* Packet successfully received */
new_skb = netdev_alloc_skb(dev, MAX_BUF_SIZE);
if (!new_skb) {
@@ -556,13 +559,13 @@ static int r6040_rx(struct net_device *dev, int limit)
}
skb_ptr = descptr->skb_ptr;
skb_ptr->dev = priv->dev;
-
+
/* Do not count the CRC */
skb_put(skb_ptr, descptr->len - 4);
pci_unmap_single(priv->pdev, le32_to_cpu(descptr->buf),
MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);
skb_ptr->protocol = eth_type_trans(skb_ptr, priv->dev);
-
+
/* Send to upper layer */
netif_receive_skb(skb_ptr);
dev->stats.rx_packets++;
@@ -710,8 +713,10 @@ static int r6040_up(struct net_device *dev)
return ret;
/* improve performance (by RDC guys) */
- r6040_phy_write(ioaddr, 30, 17, (r6040_phy_read(ioaddr, 30, 17) | 0x4000));
- r6040_phy_write(ioaddr, 30, 17, ~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000));
+ r6040_phy_write(ioaddr, 30, 17,
+ (r6040_phy_read(ioaddr, 30, 17) | 0x4000));
+ r6040_phy_write(ioaddr, 30, 17,
+ ~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000));
r6040_phy_write(ioaddr, 0, 19, 0x0000);
r6040_phy_write(ioaddr, 0, 30, 0x01F0);
@@ -740,6 +745,9 @@ static void r6040_mac_address(struct net_device *dev)
iowrite16(adrp[0], ioaddr + MID_0L);
iowrite16(adrp[1], ioaddr + MID_0M);
iowrite16(adrp[2], ioaddr + MID_0H);
+
+ /* Store MAC Address in perm_addr */
+ memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
}
static int r6040_open(struct net_device *dev)
@@ -751,7 +759,7 @@ static int r6040_open(struct net_device *dev)
ret = request_irq(dev->irq, r6040_interrupt,
IRQF_SHARED, dev->name, dev);
if (ret)
- return ret;
+ goto out;
/* Set MAC address */
r6040_mac_address(dev);
@@ -759,30 +767,37 @@ static int r6040_open(struct net_device *dev)
/* Allocate Descriptor memory */
lp->rx_ring =
pci_alloc_consistent(lp->pdev, RX_DESC_SIZE, &lp->rx_ring_dma);
- if (!lp->rx_ring)
- return -ENOMEM;
+ if (!lp->rx_ring) {
+ ret = -ENOMEM;
+ goto err_free_irq;
+ }
lp->tx_ring =
pci_alloc_consistent(lp->pdev, TX_DESC_SIZE, &lp->tx_ring_dma);
if (!lp->tx_ring) {
- pci_free_consistent(lp->pdev, RX_DESC_SIZE, lp->rx_ring,
- lp->rx_ring_dma);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_free_rx_ring;
}
ret = r6040_up(dev);
- if (ret) {
- pci_free_consistent(lp->pdev, TX_DESC_SIZE, lp->tx_ring,
- lp->tx_ring_dma);
- pci_free_consistent(lp->pdev, RX_DESC_SIZE, lp->rx_ring,
- lp->rx_ring_dma);
- return ret;
- }
+ if (ret)
+ goto err_free_tx_ring;
napi_enable(&lp->napi);
netif_start_queue(dev);
return 0;
+
+err_free_tx_ring:
+ pci_free_consistent(lp->pdev, TX_DESC_SIZE, lp->tx_ring,
+ lp->tx_ring_dma);
+err_free_rx_ring:
+ pci_free_consistent(lp->pdev, RX_DESC_SIZE, lp->rx_ring,
+ lp->rx_ring_dma);
+err_free_irq:
+ free_irq(dev->irq, dev);
+out:
+ return ret;
}
static netdev_tx_t r6040_start_xmit(struct sk_buff *skb,
@@ -893,16 +908,18 @@ static void r6040_multicast_list(struct net_device *dev)
/* Multicast Address 1~4 case */
i = 0;
netdev_for_each_mc_addr(ha, dev) {
- if (i < MCAST_MAX) {
- adrp = (u16 *) ha->addr;
- iowrite16(adrp[0], ioaddr + MID_1L + 8 * i);
- iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
- iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
- } else {
- iowrite16(0xffff, ioaddr + MID_1L + 8 * i);
- iowrite16(0xffff, ioaddr + MID_1M + 8 * i);
- iowrite16(0xffff, ioaddr + MID_1H + 8 * i);
- }
+ if (i >= MCAST_MAX)
+ break;
+ adrp = (u16 *) ha->addr;
+ iowrite16(adrp[0], ioaddr + MID_1L + 8 * i);
+ iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
+ iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
+ i++;
+ }
+ while (i < MCAST_MAX) {
+ iowrite16(0xffff, ioaddr + MID_1L + 8 * i);
+ iowrite16(0xffff, ioaddr + MID_1M + 8 * i);
+ iowrite16(0xffff, ioaddr + MID_1H + 8 * i);
i++;
}
}
@@ -946,7 +963,7 @@ static const struct net_device_ops r6040_netdev_ops = {
.ndo_set_multicast_list = r6040_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_do_ioctl = r6040_ioctl,
.ndo_tx_timeout = r6040_tx_timeout,
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1039,7 +1056,7 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
u16 *adrp;
int i;
- printk("%s\n", version);
+ pr_info("%s\n", version);
err = pci_enable_device(pdev);
if (err)
@@ -1113,7 +1130,8 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
/* Some bootloader/BIOSes do not initialize
* MAC address, warn about that */
if (!(adrp[0] || adrp[1] || adrp[2])) {
- netdev_warn(dev, "MAC address not initialized, generating random\n");
+ netdev_warn(dev, "MAC address not initialized, "
+ "generating random\n");
random_ether_addr(dev->dev_addr);
}
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 992db2fa136e..d88ce9fb1cbd 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -187,12 +187,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = {
MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);
-/*
- * we set our copybreak very high so that we don't have
- * to allocate 16k frames all the time (see note in
- * rtl8169_open()
- */
-static int rx_copybreak = 16383;
+static int rx_buf_sz = 16383;
static int use_dac;
static struct {
u32 msg_enable;
@@ -484,10 +479,8 @@ struct rtl8169_private {
struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */
dma_addr_t TxPhyAddr;
dma_addr_t RxPhyAddr;
- struct sk_buff *Rx_skbuff[NUM_RX_DESC]; /* Rx data buffers */
+ void *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */
- unsigned align;
- unsigned rx_buf_sz;
struct timer_list timer;
u16 cp_cmd;
u16 intr_event;
@@ -515,8 +508,6 @@ struct rtl8169_private {
MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
-module_param(rx_copybreak, int, 0);
-MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
module_param(use_dac, int, 0);
MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot.");
module_param_named(debug, debug.msg_enable, int, 0);
@@ -1043,7 +1034,7 @@ static int rtl8169_set_rx_csum(struct net_device *dev, u32 data)
static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
struct sk_buff *skb)
{
- return (tp->vlgrp && vlan_tx_tag_present(skb)) ?
+ return (vlan_tx_tag_present(skb)) ?
TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;
}
@@ -1076,7 +1067,12 @@ static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
int ret;
if (vlgrp && (opts2 & RxVlanTag)) {
- __vlan_hwaccel_rx(skb, vlgrp, swab16(opts2 & 0xffff), polling);
+ u16 vtag = swab16(opts2 & 0xffff);
+
+ if (likely(polling))
+ vlan_gro_receive(&tp->napi, vlgrp, vtag, skb);
+ else
+ __vlan_hwaccel_rx(skb, vlgrp, vtag, polling);
ret = 0;
} else
ret = -1;
@@ -1204,6 +1200,7 @@ static void rtl8169_update_counters(struct net_device *dev)
dma_addr_t paddr;
u32 cmd;
int wait = 1000;
+ struct device *d = &tp->pci_dev->dev;
/*
* Some chips are unable to dump tally counters when the receiver
@@ -1212,8 +1209,7 @@ static void rtl8169_update_counters(struct net_device *dev)
if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0)
return;
- counters = dma_alloc_coherent(&tp->pci_dev->dev, sizeof(*counters),
- &paddr, GFP_KERNEL);
+ counters = dma_alloc_coherent(d, sizeof(*counters), &paddr, GFP_KERNEL);
if (!counters)
return;
@@ -1234,8 +1230,7 @@ static void rtl8169_update_counters(struct net_device *dev)
RTL_W32(CounterAddrLow, 0);
RTL_W32(CounterAddrHigh, 0);
- dma_free_coherent(&tp->pci_dev->dev, sizeof(*counters), counters,
- paddr);
+ dma_free_coherent(d, sizeof(*counters), counters, paddr);
}
static void rtl8169_get_ethtool_stats(struct net_device *dev,
@@ -3188,9 +3183,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef CONFIG_R8169_VLAN
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
#endif
+ dev->features |= NETIF_F_GRO;
tp->intr_mask = 0xffff;
- tp->align = cfg->align;
tp->hw_start = cfg->hw_start;
tp->intr_event = cfg->intr_event;
tp->napi_event = cfg->napi_event;
@@ -3260,18 +3255,6 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
}
-static void rtl8169_set_rxbufsize(struct rtl8169_private *tp,
- unsigned int mtu)
-{
- unsigned int max_frame = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
-
- if (max_frame != 16383)
- printk(KERN_WARNING PFX "WARNING! Changing of MTU on this "
- "NIC may lead to frame reception errors!\n");
-
- tp->rx_buf_sz = (max_frame > RX_BUF_SIZE) ? max_frame : RX_BUF_SIZE;
-}
-
static int rtl8169_open(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
@@ -3281,18 +3264,6 @@ static int rtl8169_open(struct net_device *dev)
pm_runtime_get_sync(&pdev->dev);
/*
- * Note that we use a magic value here, its wierd I know
- * its done because, some subset of rtl8169 hardware suffers from
- * a problem in which frames received that are longer than
- * the size set in RxMaxSize register return garbage sizes
- * when received. To avoid this we need to turn off filtering,
- * which is done by setting a value of 16383 in the RxMaxSize register
- * and allocating 16k frames to handle the largest possible rx value
- * thats what the magic math below does.
- */
- rtl8169_set_rxbufsize(tp, 16383 - VLAN_ETH_HLEN - ETH_FCS_LEN);
-
- /*
* Rx and Tx desscriptors needs 256 bytes alignment.
* dma_alloc_coherent provides more.
*/
@@ -3468,7 +3439,7 @@ static void rtl_hw_start_8169(struct net_device *dev)
RTL_W8(EarlyTxThres, EarlyTxThld);
- rtl_set_rx_max_size(ioaddr, tp->rx_buf_sz);
+ rtl_set_rx_max_size(ioaddr, rx_buf_sz);
if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
(tp->mac_version == RTL_GIGA_MAC_VER_02) ||
@@ -3729,7 +3700,7 @@ static void rtl_hw_start_8168(struct net_device *dev)
RTL_W8(EarlyTxThres, EarlyTxThld);
- rtl_set_rx_max_size(ioaddr, tp->rx_buf_sz);
+ rtl_set_rx_max_size(ioaddr, rx_buf_sz);
tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
@@ -3909,7 +3880,7 @@ static void rtl_hw_start_8101(struct net_device *dev)
RTL_W8(EarlyTxThres, EarlyTxThld);
- rtl_set_rx_max_size(ioaddr, tp->rx_buf_sz);
+ rtl_set_rx_max_size(ioaddr, rx_buf_sz);
tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
@@ -3937,33 +3908,11 @@ static void rtl_hw_start_8101(struct net_device *dev)
static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
{
- struct rtl8169_private *tp = netdev_priv(dev);
- int ret = 0;
-
if (new_mtu < ETH_ZLEN || new_mtu > SafeMtu)
return -EINVAL;
dev->mtu = new_mtu;
-
- if (!netif_running(dev))
- goto out;
-
- rtl8169_down(dev);
-
- rtl8169_set_rxbufsize(tp, dev->mtu);
-
- ret = rtl8169_init_ring(dev);
- if (ret < 0)
- goto out;
-
- napi_enable(&tp->napi);
-
- rtl_hw_start(dev);
-
- rtl8169_request_timer(dev);
-
-out:
- return ret;
+ return 0;
}
static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc)
@@ -3972,15 +3921,14 @@ static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc)
desc->opts1 &= ~cpu_to_le32(DescOwn | RsvdMask);
}
-static void rtl8169_free_rx_skb(struct rtl8169_private *tp,
- struct sk_buff **sk_buff, struct RxDesc *desc)
+static void rtl8169_free_rx_databuff(struct rtl8169_private *tp,
+ void **data_buff, struct RxDesc *desc)
{
- struct pci_dev *pdev = tp->pci_dev;
+ dma_unmap_single(&tp->pci_dev->dev, le64_to_cpu(desc->addr), rx_buf_sz,
+ DMA_FROM_DEVICE);
- dma_unmap_single(&pdev->dev, le64_to_cpu(desc->addr), tp->rx_buf_sz,
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb(*sk_buff);
- *sk_buff = NULL;
+ kfree(*data_buff);
+ *data_buff = NULL;
rtl8169_make_unusable_by_asic(desc);
}
@@ -3999,33 +3947,45 @@ static inline void rtl8169_map_to_asic(struct RxDesc *desc, dma_addr_t mapping,
rtl8169_mark_to_asic(desc, rx_buf_sz);
}
-static struct sk_buff *rtl8169_alloc_rx_skb(struct pci_dev *pdev,
- struct net_device *dev,
- struct RxDesc *desc, int rx_buf_sz,
- unsigned int align, gfp_t gfp)
+static inline void *rtl8169_align(void *data)
{
- struct sk_buff *skb;
- dma_addr_t mapping;
- unsigned int pad;
+ return (void *)ALIGN((long)data, 16);
+}
- pad = align ? align : NET_IP_ALIGN;
+static struct sk_buff *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
+ struct RxDesc *desc)
+{
+ void *data;
+ dma_addr_t mapping;
+ struct device *d = &tp->pci_dev->dev;
+ struct net_device *dev = tp->dev;
+ int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
- skb = __netdev_alloc_skb(dev, rx_buf_sz + pad, gfp);
- if (!skb)
- goto err_out;
+ data = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
+ if (!data)
+ return NULL;
- skb_reserve(skb, align ? ((pad - 1) & (unsigned long)skb->data) : pad);
+ if (rtl8169_align(data) != data) {
+ kfree(data);
+ data = kmalloc_node(rx_buf_sz + 15, GFP_KERNEL, node);
+ if (!data)
+ return NULL;
+ }
- mapping = dma_map_single(&pdev->dev, skb->data, rx_buf_sz,
- PCI_DMA_FROMDEVICE);
+ mapping = dma_map_single(d, rtl8169_align(data), rx_buf_sz,
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(d, mapping))) {
+ if (net_ratelimit())
+ netif_err(tp, drv, tp->dev, "Failed to map RX DMA!\n");
+ goto err_out;
+ }
rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
-out:
- return skb;
+ return data;
err_out:
- rtl8169_make_unusable_by_asic(desc);
- goto out;
+ kfree(data);
+ return NULL;
}
static void rtl8169_rx_clear(struct rtl8169_private *tp)
@@ -4033,41 +3993,42 @@ static void rtl8169_rx_clear(struct rtl8169_private *tp)
unsigned int i;
for (i = 0; i < NUM_RX_DESC; i++) {
- if (tp->Rx_skbuff[i]) {
- rtl8169_free_rx_skb(tp, tp->Rx_skbuff + i,
+ if (tp->Rx_databuff[i]) {
+ rtl8169_free_rx_databuff(tp, tp->Rx_databuff + i,
tp->RxDescArray + i);
}
}
}
-static u32 rtl8169_rx_fill(struct rtl8169_private *tp, struct net_device *dev,
- u32 start, u32 end, gfp_t gfp)
+static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
{
- u32 cur;
+ desc->opts1 |= cpu_to_le32(RingEnd);
+}
- for (cur = start; end - cur != 0; cur++) {
- struct sk_buff *skb;
- unsigned int i = cur % NUM_RX_DESC;
+static int rtl8169_rx_fill(struct rtl8169_private *tp)
+{
+ unsigned int i;
- WARN_ON((s32)(end - cur) < 0);
+ for (i = 0; i < NUM_RX_DESC; i++) {
+ void *data;
- if (tp->Rx_skbuff[i])
+ if (tp->Rx_databuff[i])
continue;
- skb = rtl8169_alloc_rx_skb(tp->pci_dev, dev,
- tp->RxDescArray + i,
- tp->rx_buf_sz, tp->align, gfp);
- if (!skb)
- break;
-
- tp->Rx_skbuff[i] = skb;
+ data = rtl8169_alloc_rx_data(tp, tp->RxDescArray + i);
+ if (!data) {
+ rtl8169_make_unusable_by_asic(tp->RxDescArray + i);
+ goto err_out;
+ }
+ tp->Rx_databuff[i] = data;
}
- return cur - start;
-}
-static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
-{
- desc->opts1 |= cpu_to_le32(RingEnd);
+ rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1);
+ return 0;
+
+err_out:
+ rtl8169_rx_clear(tp);
+ return -ENOMEM;
}
static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
@@ -4082,54 +4043,51 @@ static int rtl8169_init_ring(struct net_device *dev)
rtl8169_init_ring_indexes(tp);
memset(tp->tx_skb, 0x0, NUM_TX_DESC * sizeof(struct ring_info));
- memset(tp->Rx_skbuff, 0x0, NUM_RX_DESC * sizeof(struct sk_buff *));
-
- if (rtl8169_rx_fill(tp, dev, 0, NUM_RX_DESC, GFP_KERNEL) != NUM_RX_DESC)
- goto err_out;
-
- rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1);
-
- return 0;
+ memset(tp->Rx_databuff, 0x0, NUM_RX_DESC * sizeof(void *));
-err_out:
- rtl8169_rx_clear(tp);
- return -ENOMEM;
+ return rtl8169_rx_fill(tp);
}
-static void rtl8169_unmap_tx_skb(struct pci_dev *pdev, struct ring_info *tx_skb,
+static void rtl8169_unmap_tx_skb(struct device *d, struct ring_info *tx_skb,
struct TxDesc *desc)
{
unsigned int len = tx_skb->len;
- dma_unmap_single(&pdev->dev, le64_to_cpu(desc->addr), len,
- PCI_DMA_TODEVICE);
+ dma_unmap_single(d, le64_to_cpu(desc->addr), len, DMA_TO_DEVICE);
+
desc->opts1 = 0x00;
desc->opts2 = 0x00;
desc->addr = 0x00;
tx_skb->len = 0;
}
-static void rtl8169_tx_clear(struct rtl8169_private *tp)
+static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start,
+ unsigned int n)
{
unsigned int i;
- for (i = tp->dirty_tx; i < tp->dirty_tx + NUM_TX_DESC; i++) {
- unsigned int entry = i % NUM_TX_DESC;
+ for (i = 0; i < n; i++) {
+ unsigned int entry = (start + i) % NUM_TX_DESC;
struct ring_info *tx_skb = tp->tx_skb + entry;
unsigned int len = tx_skb->len;
if (len) {
struct sk_buff *skb = tx_skb->skb;
- rtl8169_unmap_tx_skb(tp->pci_dev, tx_skb,
+ rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
tp->TxDescArray + entry);
if (skb) {
+ tp->dev->stats.tx_dropped++;
dev_kfree_skb(skb);
tx_skb->skb = NULL;
}
- tp->dev->stats.tx_dropped++;
}
}
+}
+
+static void rtl8169_tx_clear(struct rtl8169_private *tp)
+{
+ rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC);
tp->cur_tx = tp->dirty_tx = 0;
}
@@ -4233,6 +4191,7 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
struct skb_shared_info *info = skb_shinfo(skb);
unsigned int cur_frag, entry;
struct TxDesc * uninitialized_var(txd);
+ struct device *d = &tp->pci_dev->dev;
entry = tp->cur_tx;
for (cur_frag = 0; cur_frag < info->nr_frags; cur_frag++) {
@@ -4246,8 +4205,13 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
txd = tp->TxDescArray + entry;
len = frag->size;
addr = ((void *) page_address(frag->page)) + frag->page_offset;
- mapping = dma_map_single(&tp->pci_dev->dev, addr, len,
- PCI_DMA_TODEVICE);
+ mapping = dma_map_single(d, addr, len, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(d, mapping))) {
+ if (net_ratelimit())
+ netif_err(tp, drv, tp->dev,
+ "Failed to map TX fragments DMA!\n");
+ goto err_out;
+ }
/* anti gcc 2.95.3 bugware (sic) */
status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
@@ -4264,6 +4228,10 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
}
return cur_frag;
+
+err_out:
+ rtl8169_tx_clear_range(tp, tp->cur_tx + 1, cur_frag);
+ return -EIO;
}
static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev)
@@ -4290,40 +4258,47 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
- unsigned int frags, entry = tp->cur_tx % NUM_TX_DESC;
+ unsigned int entry = tp->cur_tx % NUM_TX_DESC;
struct TxDesc *txd = tp->TxDescArray + entry;
void __iomem *ioaddr = tp->mmio_addr;
+ struct device *d = &tp->pci_dev->dev;
dma_addr_t mapping;
u32 status, len;
u32 opts1;
+ int frags;
if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) {
netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n");
- goto err_stop;
+ goto err_stop_0;
}
if (unlikely(le32_to_cpu(txd->opts1) & DescOwn))
- goto err_stop;
+ goto err_stop_0;
+
+ len = skb_headlen(skb);
+ mapping = dma_map_single(d, skb->data, len, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(d, mapping))) {
+ if (net_ratelimit())
+ netif_err(tp, drv, dev, "Failed to map TX DMA!\n");
+ goto err_dma_0;
+ }
+
+ tp->tx_skb[entry].len = len;
+ txd->addr = cpu_to_le64(mapping);
+ txd->opts2 = cpu_to_le32(rtl8169_tx_vlan_tag(tp, skb));
opts1 = DescOwn | rtl8169_tso_csum(skb, dev);
frags = rtl8169_xmit_frags(tp, skb, opts1);
- if (frags) {
- len = skb_headlen(skb);
+ if (frags < 0)
+ goto err_dma_1;
+ else if (frags)
opts1 |= FirstFrag;
- } else {
- len = skb->len;
+ else {
opts1 |= FirstFrag | LastFrag;
tp->tx_skb[entry].skb = skb;
}
- mapping = dma_map_single(&tp->pci_dev->dev, skb->data, len,
- PCI_DMA_TODEVICE);
-
- tp->tx_skb[entry].len = len;
- txd->addr = cpu_to_le64(mapping);
- txd->opts2 = cpu_to_le32(rtl8169_tx_vlan_tag(tp, skb));
-
wmb();
/* anti gcc 2.95.3 bugware (sic) */
@@ -4345,7 +4320,14 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
-err_stop:
+err_dma_1:
+ rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd);
+err_dma_0:
+ dev_kfree_skb(skb);
+ dev->stats.tx_dropped++;
+ return NETDEV_TX_OK;
+
+err_stop_0:
netif_stop_queue(dev);
dev->stats.tx_dropped++;
return NETDEV_TX_BUSY;
@@ -4410,7 +4392,6 @@ static void rtl8169_tx_interrupt(struct net_device *dev,
while (tx_left > 0) {
unsigned int entry = dirty_tx % NUM_TX_DESC;
struct ring_info *tx_skb = tp->tx_skb + entry;
- u32 len = tx_skb->len;
u32 status;
rmb();
@@ -4418,12 +4399,11 @@ static void rtl8169_tx_interrupt(struct net_device *dev,
if (status & DescOwn)
break;
- dev->stats.tx_bytes += len;
- dev->stats.tx_packets++;
-
- rtl8169_unmap_tx_skb(tp->pci_dev, tx_skb, tp->TxDescArray + entry);
-
+ rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
+ tp->TxDescArray + entry);
if (status & LastFrag) {
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += tx_skb->skb->len;
dev_kfree_skb(tx_skb->skb);
tx_skb->skb = NULL;
}
@@ -4455,9 +4435,8 @@ static inline int rtl8169_fragmented_frame(u32 status)
return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
}
-static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc)
+static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
{
- u32 opts1 = le32_to_cpu(desc->opts1);
u32 status = opts1 & RxProtoMask;
if (((status == RxProtoTCP) && !(opts1 & TCPFail)) ||
@@ -4465,30 +4444,26 @@ static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc)
((status == RxProtoIP) && !(opts1 & IPFail)))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
}
-static inline bool rtl8169_try_rx_copy(struct sk_buff **sk_buff,
- struct rtl8169_private *tp, int pkt_size,
- dma_addr_t addr)
+static struct sk_buff *rtl8169_try_rx_copy(void *data,
+ struct rtl8169_private *tp,
+ int pkt_size,
+ dma_addr_t addr)
{
struct sk_buff *skb;
- bool done = false;
-
- if (pkt_size >= rx_copybreak)
- goto out;
+ struct device *d = &tp->pci_dev->dev;
+ data = rtl8169_align(data);
+ dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE);
+ prefetch(data);
skb = netdev_alloc_skb_ip_align(tp->dev, pkt_size);
- if (!skb)
- goto out;
+ if (skb)
+ memcpy(skb->data, data, pkt_size);
+ dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
- dma_sync_single_for_cpu(&tp->pci_dev->dev, addr, pkt_size,
- PCI_DMA_FROMDEVICE);
- skb_copy_from_linear_data(*sk_buff, skb->data, pkt_size);
- *sk_buff = skb;
- done = true;
-out:
- return done;
+ return skb;
}
/*
@@ -4503,7 +4478,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
void __iomem *ioaddr, u32 budget)
{
unsigned int cur_rx, rx_left;
- unsigned int delta, count;
+ unsigned int count;
int polling = (budget != ~(u32)0) ? 1 : 0;
cur_rx = tp->cur_rx;
@@ -4532,12 +4507,11 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
rtl8169_schedule_work(dev, rtl8169_reset_task);
dev->stats.rx_fifo_errors++;
}
- rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
+ rtl8169_mark_to_asic(desc, rx_buf_sz);
} else {
- struct sk_buff *skb = tp->Rx_skbuff[entry];
+ struct sk_buff *skb;
dma_addr_t addr = le64_to_cpu(desc->addr);
int pkt_size = (status & 0x00001FFF) - 4;
- struct pci_dev *pdev = tp->pci_dev;
/*
* The driver does not support incoming fragmented
@@ -4547,28 +4521,25 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
if (unlikely(rtl8169_fragmented_frame(status))) {
dev->stats.rx_dropped++;
dev->stats.rx_length_errors++;
- rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
+ rtl8169_mark_to_asic(desc, rx_buf_sz);
continue;
}
- rtl8169_rx_csum(skb, desc);
-
- if (rtl8169_try_rx_copy(&skb, tp, pkt_size, addr)) {
- dma_sync_single_for_device(&pdev->dev, addr,
- pkt_size, PCI_DMA_FROMDEVICE);
- rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
- } else {
- dma_unmap_single(&pdev->dev, addr, tp->rx_buf_sz,
- PCI_DMA_FROMDEVICE);
- tp->Rx_skbuff[entry] = NULL;
+ skb = rtl8169_try_rx_copy(tp->Rx_databuff[entry],
+ tp, pkt_size, addr);
+ rtl8169_mark_to_asic(desc, rx_buf_sz);
+ if (!skb) {
+ dev->stats.rx_dropped++;
+ continue;
}
+ rtl8169_rx_csum(skb, status);
skb_put(skb, pkt_size);
skb->protocol = eth_type_trans(skb, dev);
if (rtl8169_rx_vlan_skb(tp, desc, skb, polling) < 0) {
if (likely(polling))
- netif_receive_skb(skb);
+ napi_gro_receive(&tp->napi, skb);
else
netif_rx(skb);
}
@@ -4588,20 +4559,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
count = cur_rx - tp->cur_rx;
tp->cur_rx = cur_rx;
- delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx, GFP_ATOMIC);
- if (!delta && count)
- netif_info(tp, intr, dev, "no Rx buffer allocated\n");
- tp->dirty_rx += delta;
-
- /*
- * FIXME: until there is periodic timer to try and refill the ring,
- * a temporary shortage may definitely kill the Rx process.
- * - disable the asic to try and avoid an overflow and kick it again
- * after refill ?
- * - how do others driver handle this condition (Uh oh...).
- */
- if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx)
- netif_emerg(tp, intr, dev, "Rx buffers exhausted\n");
+ tp->dirty_rx += count;
return count;
}
@@ -4716,7 +4674,6 @@ static void rtl8169_down(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
- unsigned int intrmask;
rtl8169_delete_timer(dev);
@@ -4724,11 +4681,14 @@ static void rtl8169_down(struct net_device *dev)
napi_disable(&tp->napi);
-core_down:
spin_lock_irq(&tp->lock);
rtl8169_asic_down(ioaddr);
-
+ /*
+ * At this point device interrupts can not be enabled in any function,
+ * as netif_running is not true (rtl8169_interrupt, rtl8169_reset_task,
+ * rtl8169_reinit_task) and napi is disabled (rtl8169_poll).
+ */
rtl8169_rx_missed(dev, ioaddr);
spin_unlock_irq(&tp->lock);
@@ -4738,23 +4698,6 @@ core_down:
/* Give a racing hard_start_xmit a few cycles to complete. */
synchronize_sched(); /* FIXME: should this be synchronize_irq()? */
- /*
- * And now for the 50k$ question: are IRQ disabled or not ?
- *
- * Two paths lead here:
- * 1) dev->close
- * -> netif_running() is available to sync the current code and the
- * IRQ handler. See rtl8169_interrupt for details.
- * 2) dev->change_mtu
- * -> rtl8169_poll can not be issued again and re-enable the
- * interruptions. Let's simply issue the IRQ down sequence again.
- *
- * No loop if hotpluged or major error (0xffff).
- */
- intrmask = RTL_R16(IntrMask);
- if (intrmask && (intrmask != 0xffff))
- goto core_down;
-
rtl8169_tx_clear(tp);
rtl8169_rx_clear(tp);
@@ -4891,6 +4834,9 @@ static int rtl8169_resume(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct net_device *dev = pci_get_drvdata(pdev);
+ struct rtl8169_private *tp = netdev_priv(dev);
+
+ rtl8169_init_phy(dev, tp);
if (netif_running(dev))
__rtl8169_resume(dev);
@@ -4931,6 +4877,8 @@ static int rtl8169_runtime_resume(struct device *device)
tp->saved_wolopts = 0;
spin_unlock_irq(&tp->lock);
+ rtl8169_init_phy(dev, tp);
+
__rtl8169_resume(dev);
return 0;
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index e26e107f93e0..e68c941926f1 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -1245,7 +1245,7 @@ static int rr_open(struct net_device *dev)
init_timer(&rrpriv->timer);
rrpriv->timer.expires = RUN_AT(5*HZ); /* 5 sec. watchdog */
rrpriv->timer.data = (unsigned long)dev;
- rrpriv->timer.function = &rr_timer; /* timer handler */
+ rrpriv->timer.function = rr_timer; /* timer handler */
add_timer(&rrpriv->timer);
netif_start_queue(dev);
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 18bc5b718bbb..ecc25aab896a 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -38,8 +38,6 @@
* Tx descriptors that can be associated with each corresponding FIFO.
* intr_type: This defines the type of interrupt. The values can be 0(INTA),
* 2(MSI_X). Default value is '2(MSI_X)'
- * lro: Specifies whether to enable Large Receive Offload (LRO) or not.
- * Possible values '1' for enable '0' for disable. Default is '0'
* lro_max_pkts: This parameter defines maximum number of packets can be
* aggregated as a single large packet
* napi: This parameter used to enable/disable NAPI (polling Rx)
@@ -90,7 +88,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.26.26"
+#define DRV_VERSION "2.0.26.27"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -496,8 +494,6 @@ S2IO_PARM_INT(rxsync_frequency, 3);
/* Interrupt type. Values can be 0(INTA), 2(MSI_X) */
S2IO_PARM_INT(intr_type, 2);
/* Large receive offload feature */
-static unsigned int lro_enable = 1;
-module_param_named(lro, lro_enable, uint, 0);
/* Max pkts to be aggregated by LRO at one time. If not specified,
* aggregation happens until we hit max IP pkt size(64K)
@@ -4105,7 +4101,7 @@ static netdev_tx_t s2io_xmit(struct sk_buff *skb, struct net_device *dev)
}
queue = 0;
- if (sp->vlgrp && vlan_tx_tag_present(skb))
+ if (vlan_tx_tag_present(skb))
vlan_tag = vlan_tx_tag_get(skb);
if (sp->config.tx_steering_type == TX_DEFAULT_STEERING) {
if (skb->protocol == htons(ETH_P_IP)) {
@@ -5124,8 +5120,6 @@ static void s2io_set_multicast(struct net_device *dev)
/* Create the new Rx filter list and update the same in H/W. */
i = 0;
netdev_for_each_mc_addr(ha, dev) {
- memcpy(sp->usr_addrs[i].addr, ha->addr,
- ETH_ALEN);
mac_addr = 0;
for (j = 0; j < ETH_ALEN; j++) {
mac_addr |= ha->addr[j];
@@ -6735,13 +6729,10 @@ static int s2io_ethtool_set_flags(struct net_device *dev, u32 data)
return -EINVAL;
if (data & ETH_FLAG_LRO) {
- if (lro_enable) {
- if (!(dev->features & NETIF_F_LRO)) {
- dev->features |= NETIF_F_LRO;
- changed = 1;
- }
- } else
- rc = -EINVAL;
+ if (!(dev->features & NETIF_F_LRO)) {
+ dev->features |= NETIF_F_LRO;
+ changed = 1;
+ }
} else if (dev->features & NETIF_F_LRO) {
dev->features &= ~NETIF_F_LRO;
changed = 1;
@@ -6750,7 +6741,6 @@ static int s2io_ethtool_set_flags(struct net_device *dev, u32 data)
if (changed && netif_running(dev)) {
s2io_stop_all_tx_queue(sp);
s2io_card_down(sp);
- sp->lro = !!(dev->features & NETIF_F_LRO);
rc = s2io_card_up(sp);
if (rc)
s2io_reset(sp);
@@ -7307,7 +7297,7 @@ static int s2io_card_up(struct s2io_nic *sp)
struct ring_info *ring = &mac_control->rings[i];
ring->mtu = dev->mtu;
- ring->lro = sp->lro;
+ ring->lro = !!(dev->features & NETIF_F_LRO);
ret = fill_rx_buffers(sp, ring, 1);
if (ret) {
DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
@@ -7341,7 +7331,7 @@ static int s2io_card_up(struct s2io_nic *sp)
/* Setting its receive mode */
s2io_set_multicast(dev);
- if (sp->lro) {
+ if (dev->features & NETIF_F_LRO) {
/* Initialize max aggregatable pkts per session based on MTU */
sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu;
/* Check if we can use (if specified) user provided value */
@@ -7613,10 +7603,10 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
* Packet with erroneous checksum, let the
* upper layers deal with it.
*/
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
}
} else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
swstats->mem_freed += skb->truesize;
send_up:
@@ -7911,7 +7901,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
else
sp->device_type = XFRAME_I_DEVICE;
- sp->lro = lro_enable;
/* Initialize some PCI/PCI-X fields of the NIC. */
s2io_init_pci(sp);
@@ -8047,8 +8036,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
dev->netdev_ops = &s2io_netdev_ops;
SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
- if (lro_enable)
- dev->features |= NETIF_F_LRO;
+ dev->features |= NETIF_F_LRO;
dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
if (sp->high_dma_flag == true)
dev->features |= NETIF_F_HIGHDMA;
@@ -8283,9 +8271,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
dev->name);
}
- if (sp->lro)
- DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
- dev->name);
+ DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
+ dev->name);
if (ufo)
DBG_PRINT(ERR_DBG,
"%s: UDP Fragmentation Offload(UFO) enabled\n",
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 0af033533905..00b8614efe48 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -816,12 +816,6 @@ struct mac_info {
struct stat_block *stats_info; /* Logical address of the stat block */
};
-/* structure representing the user defined MAC addresses */
-struct usr_addr {
- char addr[ETH_ALEN];
- int usage_cnt;
-};
-
/* Default Tunable parameters of the NIC. */
#define DEFAULT_FIFO_0_LEN 4096
#define DEFAULT_FIFO_1_7_LEN 512
@@ -894,9 +888,7 @@ struct s2io_nic {
#define ALL_MULTI 2
#define MAX_ADDRS_SUPPORTED 64
- u16 usr_addr_count;
u16 mc_addr_count;
- struct usr_addr usr_addrs[256];
u16 m_cast_flg;
u16 all_multi_pos;
@@ -971,7 +963,6 @@ struct s2io_nic {
unsigned long clubbed_frms_cnt;
unsigned long sending_both;
- u8 lro;
u16 lro_max_aggr_per_sess;
volatile unsigned long state;
u64 general_int_mask;
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index a9ae505e1baf..66c2f1a01963 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -961,9 +961,9 @@ sb1000_open(struct net_device *dev)
lp->rx_error_count = 0;
lp->rx_error_dpc_count = 0;
lp->rx_session_id[0] = 0x50;
- lp->rx_session_id[0] = 0x48;
- lp->rx_session_id[0] = 0x44;
- lp->rx_session_id[0] = 0x42;
+ lp->rx_session_id[1] = 0x48;
+ lp->rx_session_id[2] = 0x44;
+ lp->rx_session_id[3] = 0x42;
lp->rx_frame_id[0] = 0;
lp->rx_frame_id[1] = 0;
lp->rx_frame_id[2] = 0;
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index 8e6bd45b9f31..d96d2f7a3f14 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -95,7 +95,7 @@ MODULE_PARM_DESC(int_timeout_rx, "RX timeout value");
#include <asm/sibyte/sb1250_regs.h>
#include <asm/sibyte/sb1250_int.h>
#else
-#error invalid SiByte MAC configuation
+#error invalid SiByte MAC configuration
#endif
#include <asm/sibyte/sb1250_scd.h>
#include <asm/sibyte/sb1250_mac.h>
@@ -106,7 +106,7 @@ MODULE_PARM_DESC(int_timeout_rx, "RX timeout value");
#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
#define UNIT_INT(n) (K_INT_MAC_0 + (n))
#else
-#error invalid SiByte MAC configuation
+#error invalid SiByte MAC configuration
#endif
#ifdef K_INT_PHY
@@ -1170,7 +1170,7 @@ again:
sb->ip_summed = CHECKSUM_UNNECESSARY;
/* don't need to set sb->csum */
} else {
- sb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(sb);
}
}
prefetch(sb->data);
@@ -1568,7 +1568,7 @@ static void sbmac_channel_start(struct sbmac_softc *s)
M_MAC_RX_ENABLE |
M_MAC_TX_ENABLE, s->sbm_macenable);
#else
-#error invalid SiByte MAC configuation
+#error invalid SiByte MAC configuration
#endif
#ifdef CONFIG_SBMAC_COALESCE
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
index 8c4067af32b0..417adf372828 100644
--- a/drivers/net/sc92031.c
+++ b/drivers/net/sc92031.c
@@ -15,7 +15,7 @@
* Rewritten for 2.6 by Cesar Eduardo Barros
*
* A datasheet for this chip can be found at
- * http://www.silan.com.cn/english/products/pdf/SC92031AY.pdf
+ * http://www.silan.com.cn/english/product/pdf/SC92031AY.pdf
*/
/* Note about set_mac_address: I don't know how to change the hardware
@@ -1251,16 +1251,6 @@ static int sc92031_ethtool_set_settings(struct net_device *dev,
return 0;
}
-static void sc92031_ethtool_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *drvinfo)
-{
- struct sc92031_priv *priv = netdev_priv(dev);
- struct pci_dev *pdev = priv->pdev;
-
- strcpy(drvinfo->driver, SC92031_NAME);
- strcpy(drvinfo->bus_info, pci_name(pdev));
-}
-
static void sc92031_ethtool_get_wol(struct net_device *dev,
struct ethtool_wolinfo *wolinfo)
{
@@ -1382,7 +1372,6 @@ static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev,
static const struct ethtool_ops sc92031_ethtool_ops = {
.get_settings = sc92031_ethtool_get_settings,
.set_settings = sc92031_ethtool_set_settings,
- .get_drvinfo = sc92031_ethtool_get_drvinfo,
.get_wol = sc92031_ethtool_get_wol,
.set_wol = sc92031_ethtool_set_wol,
.nway_reset = sc92031_ethtool_nway_reset,
diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile
index 1047b19c60a5..ab31c7124db1 100644
--- a/drivers/net/sfc/Makefile
+++ b/drivers/net/sfc/Makefile
@@ -1,7 +1,8 @@
-sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o \
- falcon_gmac.o falcon_xmac.o mcdi_mac.o \
+sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o filter.o \
+ falcon_xmac.o mcdi_mac.o \
selftest.o ethtool.o qt202x_phy.o mdio_10g.o \
- tenxpress.o falcon_boards.o mcdi.o mcdi_phy.o
+ tenxpress.o txc43128_phy.o falcon_boards.o \
+ mcdi.o mcdi_phy.o
sfc-$(CONFIG_SFC_MTD) += mtd.o
obj-$(CONFIG_SFC) += sfc.o
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index ba674c5ca29e..05df20e47976 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -68,14 +68,6 @@ const char *efx_loopback_mode_names[] = {
[LOOPBACK_PHYXS_WS] = "PHYXS_WS",
};
-/* Interrupt mode names (see INT_MODE())) */
-const unsigned int efx_interrupt_mode_max = EFX_INT_MODE_MAX;
-const char *efx_interrupt_mode_names[] = {
- [EFX_INT_MODE_MSIX] = "MSI-X",
- [EFX_INT_MODE_MSI] = "MSI",
- [EFX_INT_MODE_LEGACY] = "legacy",
-};
-
const unsigned int efx_reset_type_max = RESET_TYPE_MAX;
const char *efx_reset_type_names[] = {
[RESET_TYPE_INVISIBLE] = "INVISIBLE",
@@ -114,7 +106,7 @@ static struct workqueue_struct *reset_workqueue;
* This is only used in MSI-X interrupt mode
*/
static unsigned int separate_tx_channels;
-module_param(separate_tx_channels, uint, 0644);
+module_param(separate_tx_channels, uint, 0444);
MODULE_PARM_DESC(separate_tx_channels,
"Use separate channels for TX and RX");
@@ -124,10 +116,11 @@ MODULE_PARM_DESC(separate_tx_channels,
static int napi_weight = 64;
/* This is the time (in jiffies) between invocations of the hardware
- * monitor, which checks for known hardware bugs and resets the
- * hardware and driver as necessary.
+ * monitor. On Falcon-based NICs, this will:
+ * - Check the on-board hardware monitor;
+ * - Poll the link state and reconfigure the hardware as necessary.
*/
-unsigned int efx_monitor_interval = 1 * HZ;
+static unsigned int efx_monitor_interval = 1 * HZ;
/* This controls whether or not the driver will initialise devices
* with invalid MAC addresses stored in the EEPROM or flash. If true,
@@ -201,10 +194,13 @@ MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value");
* Utility functions and prototypes
*
*************************************************************************/
-static void efx_remove_channel(struct efx_channel *channel);
+
+static void efx_remove_channels(struct efx_nic *efx);
static void efx_remove_port(struct efx_nic *efx);
static void efx_fini_napi(struct efx_nic *efx);
-static void efx_fini_channels(struct efx_nic *efx);
+static void efx_fini_struct(struct efx_nic *efx);
+static void efx_start_all(struct efx_nic *efx);
+static void efx_stop_all(struct efx_nic *efx);
#define EFX_ASSERT_RESET_SERIALISED(efx) \
do { \
@@ -248,7 +244,7 @@ static int efx_process_channel(struct efx_channel *channel, int budget)
efx_rx_strategy(channel);
- efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]);
+ efx_fast_push_rx_descriptors(efx_channel_get_rx_queue(channel));
return spent;
}
@@ -334,6 +330,7 @@ void efx_process_channel_now(struct efx_channel *channel)
{
struct efx_nic *efx = channel->efx;
+ BUG_ON(channel->channel >= efx->n_channels);
BUG_ON(!channel->enabled);
/* Disable interrupts and wait for ISRs to complete */
@@ -347,7 +344,7 @@ void efx_process_channel_now(struct efx_channel *channel)
napi_disable(&channel->napi_str);
/* Poll the channel */
- efx_process_channel(channel, EFX_EVQ_SIZE);
+ efx_process_channel(channel, channel->eventq_mask + 1);
/* Ack the eventq. This may cause an interrupt to be generated
* when they are reenabled */
@@ -364,9 +361,18 @@ void efx_process_channel_now(struct efx_channel *channel)
*/
static int efx_probe_eventq(struct efx_channel *channel)
{
+ struct efx_nic *efx = channel->efx;
+ unsigned long entries;
+
netif_dbg(channel->efx, probe, channel->efx->net_dev,
"chan %d create event queue\n", channel->channel);
+ /* Build an event queue with room for one event per tx and rx buffer,
+ * plus some extra for link state events and MCDI completions. */
+ entries = roundup_pow_of_two(efx->rxq_entries + efx->txq_entries + 128);
+ EFX_BUG_ON_PARANOID(entries > EFX_MAX_EVQ_SIZE);
+ channel->eventq_mask = max(entries, EFX_MIN_EVQ_SIZE) - 1;
+
return efx_nic_probe_eventq(channel);
}
@@ -403,6 +409,63 @@ static void efx_remove_eventq(struct efx_channel *channel)
*
*************************************************************************/
+/* Allocate and initialise a channel structure, optionally copying
+ * parameters (but not resources) from an old channel structure. */
+static struct efx_channel *
+efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel)
+{
+ struct efx_channel *channel;
+ struct efx_rx_queue *rx_queue;
+ struct efx_tx_queue *tx_queue;
+ int j;
+
+ if (old_channel) {
+ channel = kmalloc(sizeof(*channel), GFP_KERNEL);
+ if (!channel)
+ return NULL;
+
+ *channel = *old_channel;
+
+ memset(&channel->eventq, 0, sizeof(channel->eventq));
+
+ rx_queue = &channel->rx_queue;
+ rx_queue->buffer = NULL;
+ memset(&rx_queue->rxd, 0, sizeof(rx_queue->rxd));
+
+ for (j = 0; j < EFX_TXQ_TYPES; j++) {
+ tx_queue = &channel->tx_queue[j];
+ if (tx_queue->channel)
+ tx_queue->channel = channel;
+ tx_queue->buffer = NULL;
+ memset(&tx_queue->txd, 0, sizeof(tx_queue->txd));
+ }
+ } else {
+ channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+ if (!channel)
+ return NULL;
+
+ channel->efx = efx;
+ channel->channel = i;
+
+ for (j = 0; j < EFX_TXQ_TYPES; j++) {
+ tx_queue = &channel->tx_queue[j];
+ tx_queue->efx = efx;
+ tx_queue->queue = i * EFX_TXQ_TYPES + j;
+ tx_queue->channel = channel;
+ }
+ }
+
+ spin_lock_init(&channel->tx_stop_lock);
+ atomic_set(&channel->tx_stop_count, 1);
+
+ rx_queue = &channel->rx_queue;
+ rx_queue->efx = efx;
+ setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill,
+ (unsigned long)rx_queue);
+
+ return channel;
+}
+
static int efx_probe_channel(struct efx_channel *channel)
{
struct efx_tx_queue *tx_queue;
@@ -459,11 +522,38 @@ static void efx_set_channel_names(struct efx_nic *efx)
number -= efx->n_rx_channels;
}
}
- snprintf(channel->name, sizeof(channel->name),
+ snprintf(efx->channel_name[channel->channel],
+ sizeof(efx->channel_name[0]),
"%s%s-%d", efx->name, type, number);
}
}
+static int efx_probe_channels(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ int rc;
+
+ /* Restart special buffer allocation */
+ efx->next_buffer_table = 0;
+
+ efx_for_each_channel(channel, efx) {
+ rc = efx_probe_channel(channel);
+ if (rc) {
+ netif_err(efx, probe, efx->net_dev,
+ "failed to create channel %d\n",
+ channel->channel);
+ goto fail;
+ }
+ }
+ efx_set_channel_names(efx);
+
+ return 0;
+
+fail:
+ efx_remove_channels(efx);
+ return rc;
+}
+
/* Channels are shutdown and reinitialised whilst the NIC is running
* to propagate configuration changes (mtu, checksum offload), or
* to clear hardware error conditions
@@ -601,6 +691,75 @@ static void efx_remove_channel(struct efx_channel *channel)
efx_remove_eventq(channel);
}
+static void efx_remove_channels(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ efx_for_each_channel(channel, efx)
+ efx_remove_channel(channel);
+}
+
+int
+efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
+{
+ struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel;
+ u32 old_rxq_entries, old_txq_entries;
+ unsigned i;
+ int rc;
+
+ efx_stop_all(efx);
+ efx_fini_channels(efx);
+
+ /* Clone channels */
+ memset(other_channel, 0, sizeof(other_channel));
+ for (i = 0; i < efx->n_channels; i++) {
+ channel = efx_alloc_channel(efx, i, efx->channel[i]);
+ if (!channel) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ other_channel[i] = channel;
+ }
+
+ /* Swap entry counts and channel pointers */
+ old_rxq_entries = efx->rxq_entries;
+ old_txq_entries = efx->txq_entries;
+ efx->rxq_entries = rxq_entries;
+ efx->txq_entries = txq_entries;
+ for (i = 0; i < efx->n_channels; i++) {
+ channel = efx->channel[i];
+ efx->channel[i] = other_channel[i];
+ other_channel[i] = channel;
+ }
+
+ rc = efx_probe_channels(efx);
+ if (rc)
+ goto rollback;
+
+ /* Destroy old channels */
+ for (i = 0; i < efx->n_channels; i++)
+ efx_remove_channel(other_channel[i]);
+out:
+ /* Free unused channel structures */
+ for (i = 0; i < efx->n_channels; i++)
+ kfree(other_channel[i]);
+
+ efx_init_channels(efx);
+ efx_start_all(efx);
+ return rc;
+
+rollback:
+ /* Swap back */
+ efx->rxq_entries = old_rxq_entries;
+ efx->txq_entries = old_txq_entries;
+ for (i = 0; i < efx->n_channels; i++) {
+ channel = efx->channel[i];
+ efx->channel[i] = other_channel[i];
+ other_channel[i] = channel;
+ }
+ goto out;
+}
+
void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue)
{
mod_timer(&rx_queue->slow_fill, jiffies + msecs_to_jiffies(100));
@@ -761,7 +920,7 @@ static int efx_probe_port(struct efx_nic *efx)
/* Connect up MAC/PHY operations table */
rc = efx->type->probe_port(efx);
if (rc)
- goto err;
+ return rc;
/* Sanity check MAC address */
if (is_valid_ether_addr(efx->mac_address)) {
@@ -782,7 +941,7 @@ static int efx_probe_port(struct efx_nic *efx)
return 0;
err:
- efx_remove_port(efx);
+ efx->type->remove_port(efx);
return rc;
}
@@ -1050,7 +1209,8 @@ static void efx_probe_interrupts(struct efx_nic *efx)
efx->n_rx_channels = efx->n_channels;
}
for (i = 0; i < n_channels; i++)
- efx->channel[i].irq = xentries[i].vector;
+ efx_get_channel(efx, i)->irq =
+ xentries[i].vector;
} else {
/* Fall back to single channel MSI */
efx->interrupt_mode = EFX_INT_MODE_MSI;
@@ -1066,7 +1226,7 @@ static void efx_probe_interrupts(struct efx_nic *efx)
efx->n_tx_channels = 1;
rc = pci_enable_msi(efx->pci_dev);
if (rc == 0) {
- efx->channel[0].irq = efx->pci_dev->irq;
+ efx_get_channel(efx, 0)->irq = efx->pci_dev->irq;
} else {
netif_err(efx, drv, efx->net_dev,
"could not enable MSI\n");
@@ -1097,26 +1257,32 @@ static void efx_remove_interrupts(struct efx_nic *efx)
efx->legacy_irq = 0;
}
+struct efx_tx_queue *
+efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type)
+{
+ unsigned tx_channel_offset =
+ separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0;
+ EFX_BUG_ON_PARANOID(index >= efx->n_tx_channels ||
+ type >= EFX_TXQ_TYPES);
+ return &efx->channel[tx_channel_offset + index]->tx_queue[type];
+}
+
static void efx_set_channels(struct efx_nic *efx)
{
struct efx_channel *channel;
struct efx_tx_queue *tx_queue;
- struct efx_rx_queue *rx_queue;
unsigned tx_channel_offset =
separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0;
+ /* Channel pointers were set in efx_init_struct() but we now
+ * need to clear them for TX queues in any RX-only channels. */
efx_for_each_channel(channel, efx) {
- if (channel->channel - tx_channel_offset < efx->n_tx_channels) {
- channel->tx_queue = &efx->tx_queue[
- (channel->channel - tx_channel_offset) *
- EFX_TXQ_TYPES];
+ if (channel->channel - tx_channel_offset >=
+ efx->n_tx_channels) {
efx_for_each_channel_tx_queue(tx_queue, channel)
- tx_queue->channel = channel;
+ tx_queue->channel = NULL;
}
}
-
- efx_for_each_rx_queue(rx_queue, efx)
- rx_queue->channel = &efx->channel[rx_queue->queue];
}
static int efx_probe_nic(struct efx_nic *efx)
@@ -1141,7 +1307,8 @@ static int efx_probe_nic(struct efx_nic *efx)
efx->rx_indir_table[i] = i % efx->n_rx_channels;
efx_set_channels(efx);
- efx->net_dev->real_num_tx_queues = efx->n_tx_channels;
+ netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels);
+ 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);
@@ -1165,40 +1332,37 @@ static void efx_remove_nic(struct efx_nic *efx)
static int efx_probe_all(struct efx_nic *efx)
{
- struct efx_channel *channel;
int rc;
- /* Create NIC */
rc = efx_probe_nic(efx);
if (rc) {
netif_err(efx, probe, efx->net_dev, "failed to create NIC\n");
goto fail1;
}
- /* Create port */
rc = efx_probe_port(efx);
if (rc) {
netif_err(efx, probe, efx->net_dev, "failed to create port\n");
goto fail2;
}
- /* Create channels */
- efx_for_each_channel(channel, efx) {
- rc = efx_probe_channel(channel);
- if (rc) {
- netif_err(efx, probe, efx->net_dev,
- "failed to create channel %d\n",
- channel->channel);
- goto fail3;
- }
+ efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE;
+ rc = efx_probe_channels(efx);
+ if (rc)
+ goto fail3;
+
+ rc = efx_probe_filters(efx);
+ if (rc) {
+ netif_err(efx, probe, efx->net_dev,
+ "failed to create filter tables\n");
+ goto fail4;
}
- efx_set_channel_names(efx);
return 0;
+ fail4:
+ efx_remove_channels(efx);
fail3:
- efx_for_each_channel(channel, efx)
- efx_remove_channel(channel);
efx_remove_port(efx);
fail2:
efx_remove_nic(efx);
@@ -1328,10 +1492,8 @@ static void efx_stop_all(struct efx_nic *efx)
static void efx_remove_all(struct efx_nic *efx)
{
- struct efx_channel *channel;
-
- efx_for_each_channel(channel, efx)
- efx_remove_channel(channel);
+ efx_remove_filters(efx);
+ efx_remove_channels(efx);
efx_remove_port(efx);
efx_remove_nic(efx);
}
@@ -1355,20 +1517,20 @@ static unsigned irq_mod_ticks(int usecs, int resolution)
void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs,
bool rx_adaptive)
{
- struct efx_tx_queue *tx_queue;
- struct efx_rx_queue *rx_queue;
+ struct efx_channel *channel;
unsigned tx_ticks = irq_mod_ticks(tx_usecs, EFX_IRQ_MOD_RESOLUTION);
unsigned rx_ticks = irq_mod_ticks(rx_usecs, EFX_IRQ_MOD_RESOLUTION);
EFX_ASSERT_RESET_SERIALISED(efx);
- efx_for_each_tx_queue(tx_queue, efx)
- tx_queue->channel->irq_moderation = tx_ticks;
-
efx->irq_rx_adaptive = rx_adaptive;
efx->irq_rx_moderation = rx_ticks;
- efx_for_each_rx_queue(rx_queue, efx)
- rx_queue->channel->irq_moderation = rx_ticks;
+ efx_for_each_channel(channel, efx) {
+ if (efx_channel_get_rx_queue(channel))
+ channel->irq_moderation = rx_ticks;
+ else if (efx_channel_get_tx_queue(channel, 0))
+ channel->irq_moderation = tx_ticks;
+ }
}
/**************************************************************************
@@ -1377,8 +1539,7 @@ void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs,
*
**************************************************************************/
-/* Run periodically off the general workqueue. Serialised against
- * efx_reconfigure_port via the mac_lock */
+/* Run periodically off the general workqueue */
static void efx_monitor(struct work_struct *data)
{
struct efx_nic *efx = container_of(data, struct efx_nic,
@@ -1391,16 +1552,13 @@ static void efx_monitor(struct work_struct *data)
/* If the mac_lock is already held then it is likely a port
* reconfiguration is already in place, which will likely do
- * most of the work of check_hw() anyway. */
- if (!mutex_trylock(&efx->mac_lock))
- goto out_requeue;
- if (!efx->port_enabled)
- goto out_unlock;
- efx->type->monitor(efx);
+ * most of the work of monitor() anyway. */
+ if (mutex_trylock(&efx->mac_lock)) {
+ if (efx->port_enabled)
+ efx->type->monitor(efx);
+ mutex_unlock(&efx->mac_lock);
+ }
-out_unlock:
- mutex_unlock(&efx->mac_lock);
-out_requeue:
queue_delayed_work(efx->workqueue, &efx->monitor_work,
efx_monitor_interval);
}
@@ -1546,11 +1704,11 @@ static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev, struc
stats->tx_packets = mac_stats->tx_packets;
stats->rx_bytes = mac_stats->rx_bytes;
stats->tx_bytes = mac_stats->tx_bytes;
+ stats->rx_dropped = efx->n_rx_nodesc_drop_cnt;
stats->multicast = mac_stats->rx_multicast;
stats->collisions = mac_stats->tx_collision;
stats->rx_length_errors = (mac_stats->rx_gtjumbo +
mac_stats->rx_length_error);
- stats->rx_over_errors = efx->n_rx_nodesc_drop_cnt;
stats->rx_crc_errors = mac_stats->rx_bad;
stats->rx_frame_errors = mac_stats->rx_align_error;
stats->rx_fifo_errors = mac_stats->rx_overflow;
@@ -1767,6 +1925,7 @@ fail_registered:
static void efx_unregister_netdev(struct efx_nic *efx)
{
+ struct efx_channel *channel;
struct efx_tx_queue *tx_queue;
if (!efx->net_dev)
@@ -1777,8 +1936,10 @@ static void efx_unregister_netdev(struct efx_nic *efx)
/* Free up any skbs still remaining. This has to happen before
* we try to unregister the netdev as running their destructors
* may be needed to get the device ref. count to 0. */
- efx_for_each_tx_queue(tx_queue, efx)
- efx_release_tx_buffers(tx_queue);
+ efx_for_each_channel(channel, efx) {
+ efx_for_each_channel_tx_queue(tx_queue, channel)
+ efx_release_tx_buffers(tx_queue);
+ }
if (efx_dev_registered(efx)) {
strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name));
@@ -1841,6 +2002,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
efx->mac_op->reconfigure(efx);
efx_init_channels(efx);
+ efx_restore_filters(efx);
mutex_unlock(&efx->spi_lock);
mutex_unlock(&efx->mac_lock);
@@ -2010,10 +2172,8 @@ int efx_port_dummy_op_int(struct efx_nic *efx)
return 0;
}
void efx_port_dummy_op_void(struct efx_nic *efx) {}
-void efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
-{
-}
-bool efx_port_dummy_op_poll(struct efx_nic *efx)
+
+static bool efx_port_dummy_op_poll(struct efx_nic *efx)
{
return false;
}
@@ -2037,9 +2197,6 @@ static struct efx_phy_operations efx_dummy_phy_operations = {
static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
struct pci_dev *pci_dev, struct net_device *net_dev)
{
- struct efx_channel *channel;
- struct efx_tx_queue *tx_queue;
- struct efx_rx_queue *rx_queue;
int i;
/* Initialise common structures */
@@ -2068,36 +2225,13 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
INIT_WORK(&efx->mac_work, efx_mac_work);
for (i = 0; i < EFX_MAX_CHANNELS; i++) {
- channel = &efx->channel[i];
- channel->efx = efx;
- channel->channel = i;
- channel->work_pending = false;
- spin_lock_init(&channel->tx_stop_lock);
- atomic_set(&channel->tx_stop_count, 1);
- }
- for (i = 0; i < EFX_MAX_TX_QUEUES; i++) {
- tx_queue = &efx->tx_queue[i];
- tx_queue->efx = efx;
- tx_queue->queue = i;
- tx_queue->buffer = NULL;
- tx_queue->channel = &efx->channel[0]; /* for safety */
- tx_queue->tso_headers_free = NULL;
- }
- for (i = 0; i < EFX_MAX_RX_QUEUES; i++) {
- rx_queue = &efx->rx_queue[i];
- rx_queue->efx = efx;
- rx_queue->queue = i;
- rx_queue->channel = &efx->channel[0]; /* for safety */
- rx_queue->buffer = NULL;
- setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill,
- (unsigned long)rx_queue);
+ efx->channel[i] = efx_alloc_channel(efx, i, NULL);
+ if (!efx->channel[i])
+ goto fail;
}
efx->type = type;
- /* As close as we can get to guaranteeing that we don't overflow */
- BUILD_BUG_ON(EFX_EVQ_SIZE < EFX_TXQ_SIZE + EFX_RXQ_SIZE);
-
EFX_BUG_ON_PARANOID(efx->type->phys_addr_channels > EFX_MAX_CHANNELS);
/* Higher numbered interrupt modes are less capable! */
@@ -2109,13 +2243,22 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
pci_name(pci_dev));
efx->workqueue = create_singlethread_workqueue(efx->workqueue_name);
if (!efx->workqueue)
- return -ENOMEM;
+ goto fail;
return 0;
+
+fail:
+ efx_fini_struct(efx);
+ return -ENOMEM;
}
static void efx_fini_struct(struct efx_nic *efx)
{
+ int i;
+
+ for (i = 0; i < EFX_MAX_CHANNELS; i++)
+ kfree(efx->channel[i]);
+
if (efx->workqueue) {
destroy_workqueue(efx->workqueue);
efx->workqueue = NULL;
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index 060dc952a0fd..10a1bf40da96 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -12,6 +12,7 @@
#define EFX_EFX_H
#include "net_driver.h"
+#include "filter.h"
/* PCI IDs */
#define EFX_VENDID_SFC 0x1924
@@ -37,8 +38,6 @@ efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
extern void efx_stop_queue(struct efx_channel *channel);
extern void efx_wake_queue(struct efx_channel *channel);
-#define EFX_TXQ_SIZE 1024
-#define EFX_TXQ_MASK (EFX_TXQ_SIZE - 1)
/* RX */
extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
@@ -53,23 +52,42 @@ extern void __efx_rx_packet(struct efx_channel *channel,
extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
unsigned int len, bool checksummed, bool discard);
extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue);
-#define EFX_RXQ_SIZE 1024
-#define EFX_RXQ_MASK (EFX_RXQ_SIZE - 1)
+
+#define EFX_MAX_DMAQ_SIZE 4096UL
+#define EFX_DEFAULT_DMAQ_SIZE 1024UL
+#define EFX_MIN_DMAQ_SIZE 512UL
+
+#define EFX_MAX_EVQ_SIZE 16384UL
+#define EFX_MIN_EVQ_SIZE 512UL
+
+/* The smallest [rt]xq_entries that the driver supports. Callers of
+ * efx_wake_queue() assume that they can subsequently send at least one
+ * skb. Falcon/A1 may require up to three descriptors per skb_frag. */
+#define EFX_MIN_RING_SIZE (roundup_pow_of_two(2 * 3 * MAX_SKB_FRAGS))
+
+/* Filters */
+extern int efx_probe_filters(struct efx_nic *efx);
+extern void efx_restore_filters(struct efx_nic *efx);
+extern void efx_remove_filters(struct efx_nic *efx);
+extern int efx_filter_insert_filter(struct efx_nic *efx,
+ struct efx_filter_spec *spec,
+ bool replace);
+extern int efx_filter_remove_filter(struct efx_nic *efx,
+ struct efx_filter_spec *spec);
+extern void efx_filter_table_clear(struct efx_nic *efx,
+ enum efx_filter_table_id table_id,
+ enum efx_filter_priority priority);
/* Channels */
extern void efx_process_channel_now(struct efx_channel *channel);
-#define EFX_EVQ_SIZE 4096
-#define EFX_EVQ_MASK (EFX_EVQ_SIZE - 1)
+extern int
+efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries);
/* Ports */
extern int efx_reconfigure_port(struct efx_nic *efx);
extern int __efx_reconfigure_port(struct efx_nic *efx);
/* Ethtool support */
-extern int efx_ethtool_get_settings(struct net_device *net_dev,
- struct ethtool_cmd *ecmd);
-extern int efx_ethtool_set_settings(struct net_device *net_dev,
- struct ethtool_cmd *ecmd);
extern const struct ethtool_ops efx_ethtool_ops;
/* Reset handling */
@@ -81,15 +99,11 @@ extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok);
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_request_power(struct efx_nic *efx, int mw, const char *name);
-extern void efx_hex_dump(const u8 *, unsigned int, const char *);
/* Dummy PHY ops for PHY drivers */
extern int efx_port_dummy_op_int(struct efx_nic *efx);
extern void efx_port_dummy_op_void(struct efx_nic *efx);
-extern void
-efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
-extern bool efx_port_dummy_op_poll(struct efx_nic *efx);
+
/* MTD */
#ifdef CONFIG_SFC_MTD
@@ -102,8 +116,6 @@ static inline void efx_mtd_rename(struct efx_nic *efx) {}
static inline void efx_mtd_remove(struct efx_nic *efx) {}
#endif
-extern unsigned int efx_monitor_interval;
-
static inline void efx_schedule_channel(struct efx_channel *channel)
{
netif_vdbg(channel->efx, intr, channel->efx->net_dev,
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index fd19d6ab97a2..edb9d16b8b47 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -15,6 +15,7 @@
#include "workarounds.h"
#include "selftest.h"
#include "efx.h"
+#include "filter.h"
#include "nic.h"
#include "spi.h"
#include "mdio_10g.h"
@@ -186,8 +187,8 @@ static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count)
}
/* This must be called with rtnl_lock held. */
-int efx_ethtool_get_settings(struct net_device *net_dev,
- struct ethtool_cmd *ecmd)
+static int efx_ethtool_get_settings(struct net_device *net_dev,
+ struct ethtool_cmd *ecmd)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_link_state *link_state = &efx->link_state;
@@ -210,8 +211,8 @@ int efx_ethtool_get_settings(struct net_device *net_dev,
}
/* This must be called with rtnl_lock held. */
-int efx_ethtool_set_settings(struct net_device *net_dev,
- struct ethtool_cmd *ecmd)
+static int efx_ethtool_set_settings(struct net_device *net_dev,
+ struct ethtool_cmd *ecmd)
{
struct efx_nic *efx = netdev_priv(net_dev);
int rc;
@@ -328,9 +329,10 @@ static int efx_fill_loopback_test(struct efx_nic *efx,
unsigned int test_index,
struct ethtool_string *strings, u64 *data)
{
+ struct efx_channel *channel = efx_get_channel(efx, 0);
struct efx_tx_queue *tx_queue;
- efx_for_each_channel_tx_queue(tx_queue, &efx->channel[0]) {
+ efx_for_each_channel_tx_queue(tx_queue, channel) {
efx_fill_test(test_index++, strings, data,
&lb_tests->tx_sent[tx_queue->queue],
EFX_TX_QUEUE_NAME(tx_queue),
@@ -550,9 +552,22 @@ static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev)
static int efx_ethtool_set_flags(struct net_device *net_dev, u32 data)
{
struct efx_nic *efx = netdev_priv(net_dev);
- u32 supported = efx->type->offload_features & ETH_FLAG_RXHASH;
+ u32 supported = (efx->type->offload_features &
+ (ETH_FLAG_RXHASH | ETH_FLAG_NTUPLE));
+ int rc;
+
+ rc = ethtool_op_set_flags(net_dev, data, supported);
+ if (rc)
+ return rc;
- return ethtool_op_set_flags(net_dev, data, supported);
+ if (!(data & ETH_FLAG_NTUPLE)) {
+ efx_filter_table_clear(efx, EFX_FILTER_TABLE_RX_IP,
+ EFX_FILTER_PRI_MANUAL);
+ efx_filter_table_clear(efx, EFX_FILTER_TABLE_RX_MAC,
+ EFX_FILTER_PRI_MANUAL);
+ }
+
+ return 0;
}
static void efx_ethtool_self_test(struct net_device *net_dev,
@@ -673,15 +688,15 @@ 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_tx_queue *tx_queue;
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_tx_queue(tx_queue, efx) {
- channel = tx_queue->channel;
+ efx_for_each_channel(channel, efx) {
+ if (!efx_channel_get_tx_queue(channel, 0))
+ continue;
if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) {
if (channel->channel < efx->n_rx_channels)
coalesce->tx_coalesce_usecs_irq =
@@ -708,7 +723,6 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_channel *channel;
- struct efx_tx_queue *tx_queue;
unsigned tx_usecs, rx_usecs, adaptive;
if (coalesce->use_adaptive_tx_coalesce)
@@ -725,8 +739,9 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
adaptive = coalesce->use_adaptive_rx_coalesce;
/* If the channel is shared only allow RX parameters to be set */
- efx_for_each_tx_queue(tx_queue, efx) {
- if ((tx_queue->channel->channel < efx->n_rx_channels) &&
+ efx_for_each_channel(channel, efx) {
+ if (efx_channel_get_rx_queue(channel) &&
+ efx_channel_get_tx_queue(channel, 0) &&
tx_usecs) {
netif_err(efx, drv, efx->net_dev, "Channel is shared. "
"Only RX coalescing may be set\n");
@@ -741,6 +756,42 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
return 0;
}
+static void efx_ethtool_get_ringparam(struct net_device *net_dev,
+ struct ethtool_ringparam *ring)
+{
+ struct efx_nic *efx = netdev_priv(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,
+ struct ethtool_ringparam *ring)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+
+ if (ring->rx_mini_pending || ring->rx_jumbo_pending ||
+ ring->rx_pending > EFX_MAX_DMAQ_SIZE ||
+ ring->tx_pending > EFX_MAX_DMAQ_SIZE)
+ return -EINVAL;
+
+ if (ring->rx_pending < EFX_MIN_RING_SIZE ||
+ ring->tx_pending < EFX_MIN_RING_SIZE) {
+ netif_err(efx, drv, efx->net_dev,
+ "TX and RX queues cannot be smaller than %ld\n",
+ EFX_MIN_RING_SIZE);
+ return -EINVAL;
+ }
+
+ return efx_realloc_channels(efx, ring->rx_pending, ring->tx_pending);
+}
+
static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
struct ethtool_pauseparam *pause)
{
@@ -840,7 +891,7 @@ static int efx_ethtool_set_wol(struct net_device *net_dev,
return efx->type->set_wol(efx, wol->wolopts);
}
-extern int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
+static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
{
struct efx_nic *efx = netdev_priv(net_dev);
enum reset_type method;
@@ -918,6 +969,105 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev,
}
}
+static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev,
+ struct ethtool_rx_ntuple *ntuple)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+ struct ethtool_tcpip4_spec *ip_entry = &ntuple->fs.h_u.tcp_ip4_spec;
+ struct ethtool_tcpip4_spec *ip_mask = &ntuple->fs.m_u.tcp_ip4_spec;
+ struct ethhdr *mac_entry = &ntuple->fs.h_u.ether_spec;
+ struct ethhdr *mac_mask = &ntuple->fs.m_u.ether_spec;
+ struct efx_filter_spec filter;
+
+ /* Range-check action */
+ if (ntuple->fs.action < ETHTOOL_RXNTUPLE_ACTION_CLEAR ||
+ ntuple->fs.action >= (s32)efx->n_rx_channels)
+ return -EINVAL;
+
+ if (~ntuple->fs.data_mask)
+ return -EINVAL;
+
+ switch (ntuple->fs.flow_type) {
+ case TCP_V4_FLOW:
+ case UDP_V4_FLOW:
+ /* Must match all of destination, */
+ if (ip_mask->ip4dst | ip_mask->pdst)
+ return -EINVAL;
+ /* all or none of source, */
+ if ((ip_mask->ip4src | ip_mask->psrc) &&
+ ((__force u32)~ip_mask->ip4src |
+ (__force u16)~ip_mask->psrc))
+ return -EINVAL;
+ /* and nothing else */
+ if ((u8)~ip_mask->tos | (u16)~ntuple->fs.vlan_tag_mask)
+ return -EINVAL;
+ break;
+ case ETHER_FLOW:
+ /* Must match all of destination, */
+ if (!is_zero_ether_addr(mac_mask->h_dest))
+ return -EINVAL;
+ /* all or none of VID, */
+ if (ntuple->fs.vlan_tag_mask != 0xf000 &&
+ ntuple->fs.vlan_tag_mask != 0xffff)
+ return -EINVAL;
+ /* and nothing else */
+ if (!is_broadcast_ether_addr(mac_mask->h_source) ||
+ mac_mask->h_proto != htons(0xffff))
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ filter.priority = EFX_FILTER_PRI_MANUAL;
+ filter.flags = 0;
+
+ switch (ntuple->fs.flow_type) {
+ case TCP_V4_FLOW:
+ if (!ip_mask->ip4src)
+ efx_filter_set_rx_tcp_full(&filter,
+ htonl(ip_entry->ip4src),
+ htons(ip_entry->psrc),
+ htonl(ip_entry->ip4dst),
+ htons(ip_entry->pdst));
+ else
+ efx_filter_set_rx_tcp_wild(&filter,
+ htonl(ip_entry->ip4dst),
+ htons(ip_entry->pdst));
+ break;
+ case UDP_V4_FLOW:
+ if (!ip_mask->ip4src)
+ efx_filter_set_rx_udp_full(&filter,
+ htonl(ip_entry->ip4src),
+ htons(ip_entry->psrc),
+ htonl(ip_entry->ip4dst),
+ htons(ip_entry->pdst));
+ else
+ efx_filter_set_rx_udp_wild(&filter,
+ htonl(ip_entry->ip4dst),
+ htons(ip_entry->pdst));
+ break;
+ case ETHER_FLOW:
+ if (ntuple->fs.vlan_tag_mask == 0xf000)
+ efx_filter_set_rx_mac_full(&filter,
+ ntuple->fs.vlan_tag & 0xfff,
+ mac_entry->h_dest);
+ else
+ efx_filter_set_rx_mac_wild(&filter, mac_entry->h_dest);
+ break;
+ }
+
+ if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_CLEAR) {
+ return efx_filter_remove_filter(efx, &filter);
+ } else {
+ if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP)
+ filter.dmaq_id = 0xfff;
+ else
+ filter.dmaq_id = ntuple->fs.action;
+ return efx_filter_insert_filter(efx, &filter, true);
+ }
+}
+
static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev,
struct ethtool_rxfh_indir *indir)
{
@@ -971,6 +1121,8 @@ const struct ethtool_ops efx_ethtool_ops = {
.set_eeprom = efx_ethtool_set_eeprom,
.get_coalesce = efx_ethtool_get_coalesce,
.set_coalesce = efx_ethtool_set_coalesce,
+ .get_ringparam = efx_ethtool_get_ringparam,
+ .set_ringparam = efx_ethtool_set_ringparam,
.get_pauseparam = efx_ethtool_get_pauseparam,
.set_pauseparam = efx_ethtool_set_pauseparam,
.get_rx_csum = efx_ethtool_get_rx_csum,
@@ -994,6 +1146,7 @@ const struct ethtool_ops efx_ethtool_ops = {
.set_wol = efx_ethtool_set_wol,
.reset = efx_ethtool_reset,
.get_rxnfc = efx_ethtool_get_rxnfc,
+ .set_rx_ntuple = efx_ethtool_set_rx_ntuple,
.get_rxfh_indir = efx_ethtool_get_rxfh_indir,
.set_rxfh_indir = efx_ethtool_set_rxfh_indir,
};
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 4f9d33f3cca1..267019bb2b15 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -159,7 +159,6 @@ irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
{
struct efx_nic *efx = dev_id;
efx_oword_t *int_ker = efx->irq_status.addr;
- struct efx_channel *channel;
int syserr;
int queues;
@@ -194,15 +193,10 @@ irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
wmb(); /* Ensure the vector is cleared before interrupt ack */
falcon_irq_ack_a1(efx);
- /* Schedule processing of any interrupting queues */
- channel = &efx->channel[0];
- while (queues) {
- if (queues & 0x01)
- efx_schedule_channel(channel);
- channel++;
- queues >>= 1;
- }
-
+ if (queues & 1)
+ efx_schedule_channel(efx_get_channel(efx, 0));
+ if (queues & 2)
+ efx_schedule_channel(efx_get_channel(efx, 1));
return IRQ_HANDLED;
}
/**************************************************************************
@@ -452,30 +446,19 @@ static void falcon_reset_macs(struct efx_nic *efx)
/* It's not safe to use GLB_CTL_REG to reset the
* macs, so instead use the internal MAC resets
*/
- if (!EFX_IS10G(efx)) {
- EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 1);
- efx_writeo(efx, &reg, FR_AB_GM_CFG1);
- udelay(1000);
-
- EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 0);
- efx_writeo(efx, &reg, FR_AB_GM_CFG1);
- udelay(1000);
- return;
- } else {
- EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1);
- efx_writeo(efx, &reg, FR_AB_XM_GLB_CFG);
-
- for (count = 0; count < 10000; count++) {
- efx_reado(efx, &reg, FR_AB_XM_GLB_CFG);
- if (EFX_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) ==
- 0)
- return;
- udelay(10);
- }
-
- netif_err(efx, hw, efx->net_dev,
- "timed out waiting for XMAC core reset\n");
+ EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1);
+ efx_writeo(efx, &reg, FR_AB_XM_GLB_CFG);
+
+ for (count = 0; count < 10000; count++) {
+ efx_reado(efx, &reg, FR_AB_XM_GLB_CFG);
+ if (EFX_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) ==
+ 0)
+ return;
+ udelay(10);
}
+
+ netif_err(efx, hw, efx->net_dev,
+ "timed out waiting for XMAC core reset\n");
}
/* Mac stats will fail whist the TX fifo is draining */
@@ -514,7 +497,6 @@ static void falcon_reset_macs(struct efx_nic *efx)
* are re-enabled by the caller */
efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL);
- /* This can run even when the GMAC is selected */
falcon_setup_xaui(efx);
}
@@ -652,8 +634,6 @@ static void falcon_stats_timer_func(unsigned long context)
spin_unlock(&efx->stats_lock);
}
-static void falcon_switch_mac(struct efx_nic *efx);
-
static bool falcon_loopback_link_poll(struct efx_nic *efx)
{
struct efx_link_state old_state = efx->link_state;
@@ -664,11 +644,7 @@ static bool falcon_loopback_link_poll(struct efx_nic *efx)
efx->link_state.fd = true;
efx->link_state.fc = efx->wanted_fc;
efx->link_state.up = true;
-
- if (efx->loopback_mode == LOOPBACK_GMAC)
- efx->link_state.speed = 1000;
- else
- efx->link_state.speed = 10000;
+ efx->link_state.speed = 10000;
return !efx_link_state_equal(&efx->link_state, &old_state);
}
@@ -691,7 +667,7 @@ static int falcon_reconfigure_port(struct efx_nic *efx)
falcon_stop_nic_stats(efx);
falcon_deconfigure_mac_wrapper(efx);
- falcon_switch_mac(efx);
+ falcon_reset_macs(efx);
efx->phy_op->reconfigure(efx);
rc = efx->mac_op->reconfigure(efx);
@@ -841,73 +817,23 @@ out:
return rc;
}
-static void falcon_clock_mac(struct efx_nic *efx)
-{
- unsigned strap_val;
- efx_oword_t nic_stat;
-
- /* Configure the NIC generated MAC clock correctly */
- efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
- strap_val = EFX_IS10G(efx) ? 5 : 3;
- if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
- EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP_EN, 1);
- EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP, strap_val);
- efx_writeo(efx, &nic_stat, FR_AB_NIC_STAT);
- } else {
- /* Falcon A1 does not support 1G/10G speed switching
- * and must not be used with a PHY that does. */
- BUG_ON(EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_PINS) !=
- strap_val);
- }
-}
-
-static void falcon_switch_mac(struct efx_nic *efx)
-{
- struct efx_mac_operations *old_mac_op = efx->mac_op;
- struct falcon_nic_data *nic_data = efx->nic_data;
- unsigned int stats_done_offset;
-
- WARN_ON(!mutex_is_locked(&efx->mac_lock));
- WARN_ON(nic_data->stats_disable_count == 0);
-
- efx->mac_op = (EFX_IS10G(efx) ?
- &falcon_xmac_operations : &falcon_gmac_operations);
-
- if (EFX_IS10G(efx))
- stats_done_offset = XgDmaDone_offset;
- else
- stats_done_offset = GDmaDone_offset;
- nic_data->stats_dma_done = efx->stats_buffer.addr + stats_done_offset;
-
- if (old_mac_op == efx->mac_op)
- return;
-
- falcon_clock_mac(efx);
-
- netif_dbg(efx, hw, efx->net_dev, "selected %cMAC\n",
- EFX_IS10G(efx) ? 'X' : 'G');
- /* Not all macs support a mac-level link state */
- efx->xmac_poll_required = false;
- falcon_reset_macs(efx);
-}
-
/* This call is responsible for hooking in the MAC and PHY operations */
static int falcon_probe_port(struct efx_nic *efx)
{
+ struct falcon_nic_data *nic_data = efx->nic_data;
int rc;
switch (efx->phy_type) {
case PHY_TYPE_SFX7101:
efx->phy_op = &falcon_sfx7101_phy_ops;
break;
- case PHY_TYPE_SFT9001A:
- case PHY_TYPE_SFT9001B:
- efx->phy_op = &falcon_sft9001_phy_ops;
- break;
case PHY_TYPE_QT2022C2:
case PHY_TYPE_QT2025C:
efx->phy_op = &falcon_qt202x_phy_ops;
break;
+ case PHY_TYPE_TXC43128:
+ efx->phy_op = &falcon_txc_phy_ops;
+ break;
default:
netif_err(efx, probe, efx->net_dev, "Unknown PHY type %d\n",
efx->phy_type);
@@ -943,6 +869,7 @@ static int falcon_probe_port(struct efx_nic *efx)
(u64)efx->stats_buffer.dma_addr,
efx->stats_buffer.addr,
(u64)virt_to_phys(efx->stats_buffer.addr));
+ nic_data->stats_dma_done = efx->stats_buffer.addr + XgDmaDone_offset;
return 0;
}
@@ -1207,7 +1134,7 @@ static void falcon_monitor(struct efx_nic *efx)
falcon_stop_nic_stats(efx);
falcon_deconfigure_mac_wrapper(efx);
- falcon_switch_mac(efx);
+ falcon_reset_macs(efx);
rc = efx->mac_op->reconfigure(efx);
BUG_ON(rc);
@@ -1216,8 +1143,7 @@ static void falcon_monitor(struct efx_nic *efx)
efx_link_status_changed(efx);
}
- if (EFX_IS10G(efx))
- falcon_poll_xmac(efx);
+ falcon_poll_xmac(efx);
}
/* Zeroes out the SRAM contents. This routine must be called in
@@ -1610,16 +1536,6 @@ static int falcon_init_nic(struct efx_nic *efx)
EFX_SET_OWORD_FIELD(temp, FRF_AB_ONCHIP_SRAM, 1);
efx_writeo(efx, &temp, FR_AB_NIC_STAT);
- /* Set the source of the GMAC clock */
- if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) {
- efx_reado(efx, &temp, FR_AB_GPIO_CTL);
- EFX_SET_OWORD_FIELD(temp, FRF_AB_USE_NIC_CLK, true);
- efx_writeo(efx, &temp, FR_AB_GPIO_CTL);
- }
-
- /* Select the correct MAC */
- falcon_clock_mac(efx);
-
rc = falcon_reset_sram(efx);
if (rc)
return rc;
@@ -1880,7 +1796,7 @@ struct efx_nic_type falcon_b0_nic_type = {
* channels */
.tx_dc_base = 0x130000,
.rx_dc_base = 0x100000,
- .offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH,
+ .offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE,
.reset_world_flags = ETH_RESET_IRQ,
};
diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c
index 3d950c2cf205..cfc6a5b5a477 100644
--- a/drivers/net/sfc/falcon_boards.c
+++ b/drivers/net/sfc/falcon_boards.c
@@ -26,7 +26,7 @@
/* Board types */
#define FALCON_BOARD_SFE4001 0x01
#define FALCON_BOARD_SFE4002 0x02
-#define FALCON_BOARD_SFN4111T 0x51
+#define FALCON_BOARD_SFE4003 0x03
#define FALCON_BOARD_SFN4112F 0x52
/* Board temperature is about 15°C above ambient when air flow is
@@ -142,17 +142,17 @@ static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask)
#endif /* CONFIG_SENSORS_LM87 */
/*****************************************************************************
- * Support for the SFE4001 and SFN4111T NICs.
+ * Support for the SFE4001 NIC.
*
* The SFE4001 does not power-up fully at reset due to its high power
* consumption. We control its power via a PCA9539 I/O expander.
- * Both boards have a MAX6647 temperature monitor which we expose to
+ * It also has a MAX6647 temperature monitor which we expose to
* the lm90 driver.
*
* This also provides minimal support for reflashing the PHY, which is
* initiated by resetting it with the FLASH_CFG_1 pin pulled down.
* On SFE4001 rev A2 and later this is connected to the 3V3X output of
- * the IO-expander; on the SFN4111T it is connected to Falcon's GPIO3.
+ * the IO-expander.
* We represent reflash mode as PHY_MODE_SPECIAL and make it mutually
* exclusive with the network device being open.
*/
@@ -304,34 +304,6 @@ fail_on:
return rc;
}
-static int sfn4111t_reset(struct efx_nic *efx)
-{
- struct falcon_board *board = falcon_board(efx);
- efx_oword_t reg;
-
- /* GPIO 3 and the GPIO register are shared with I2C, so block that */
- i2c_lock_adapter(&board->i2c_adap);
-
- /* Pull RST_N (GPIO 2) low then let it up again, setting the
- * FLASH_CFG_1 strap (GPIO 3) appropriately. Only change the
- * output enables; the output levels should always be 0 (low)
- * and we rely on external pull-ups. */
- efx_reado(efx, &reg, FR_AB_GPIO_CTL);
- EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO2_OEN, true);
- efx_writeo(efx, &reg, FR_AB_GPIO_CTL);
- msleep(1000);
- EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO2_OEN, false);
- EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO3_OEN,
- !!(efx->phy_mode & PHY_MODE_SPECIAL));
- efx_writeo(efx, &reg, FR_AB_GPIO_CTL);
- msleep(1);
-
- i2c_unlock_adapter(&board->i2c_adap);
-
- ssleep(1);
- return 0;
-}
-
static ssize_t show_phy_flash_cfg(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -363,10 +335,7 @@ static ssize_t set_phy_flash_cfg(struct device *dev,
efx->phy_mode = new_mode;
if (new_mode & PHY_MODE_SPECIAL)
falcon_stop_nic_stats(efx);
- if (falcon_board(efx)->type->id == FALCON_BOARD_SFE4001)
- err = sfe4001_poweron(efx);
- else
- err = sfn4111t_reset(efx);
+ err = sfe4001_poweron(efx);
if (!err)
err = efx_reconfigure_port(efx);
if (!(new_mode & PHY_MODE_SPECIAL))
@@ -479,83 +448,6 @@ fail_hwmon:
return rc;
}
-static int sfn4111t_check_hw(struct efx_nic *efx)
-{
- s32 status;
-
- /* If XAUI link is up then do not monitor */
- if (EFX_WORKAROUND_7884(efx) && !efx->xmac_poll_required)
- return 0;
-
- /* Test LHIGH, RHIGH, FAULT, EOT and IOT alarms */
- status = i2c_smbus_read_byte_data(falcon_board(efx)->hwmon_client,
- MAX664X_REG_RSL);
- if (status < 0)
- return -EIO;
- if (status & 0x57)
- return -ERANGE;
- return 0;
-}
-
-static void sfn4111t_fini(struct efx_nic *efx)
-{
- netif_info(efx, drv, efx->net_dev, "%s\n", __func__);
-
- device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
- i2c_unregister_device(falcon_board(efx)->hwmon_client);
-}
-
-static struct i2c_board_info sfn4111t_a0_hwmon_info = {
- I2C_BOARD_INFO("max6647", 0x4e),
-};
-
-static struct i2c_board_info sfn4111t_r5_hwmon_info = {
- I2C_BOARD_INFO("max6646", 0x4d),
-};
-
-static void sfn4111t_init_phy(struct efx_nic *efx)
-{
- if (!(efx->phy_mode & PHY_MODE_SPECIAL)) {
- if (sft9001_wait_boot(efx) != -EINVAL)
- return;
-
- efx->phy_mode = PHY_MODE_SPECIAL;
- falcon_stop_nic_stats(efx);
- }
-
- sfn4111t_reset(efx);
- sft9001_wait_boot(efx);
-}
-
-static int sfn4111t_init(struct efx_nic *efx)
-{
- struct falcon_board *board = falcon_board(efx);
- int rc;
-
- board->hwmon_client =
- i2c_new_device(&board->i2c_adap,
- (board->minor < 5) ?
- &sfn4111t_a0_hwmon_info :
- &sfn4111t_r5_hwmon_info);
- if (!board->hwmon_client)
- return -EIO;
-
- rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
- if (rc)
- goto fail_hwmon;
-
- if (efx->phy_mode & PHY_MODE_SPECIAL)
- /* PHY may not generate a 156.25 MHz clock and MAC
- * stats fetch will fail. */
- falcon_stop_nic_stats(efx);
-
- return 0;
-
-fail_hwmon:
- i2c_unregister_device(board->hwmon_client);
- return rc;
-}
-
/*****************************************************************************
* Support for the SFE4002
*
@@ -691,6 +583,75 @@ static int sfn4112f_init(struct efx_nic *efx)
return efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs);
}
+/*****************************************************************************
+ * Support for the SFE4003
+ *
+ */
+static u8 sfe4003_lm87_channel = 0x03; /* use AIN not FAN inputs */
+
+static const u8 sfe4003_lm87_regs[] = {
+ LM87_IN_LIMITS(0, 0x67, 0x7f), /* 2.5V: 1.5V +/- 10% */
+ LM87_IN_LIMITS(1, 0x4c, 0x5e), /* Vccp1: 1.2V +/- 10% */
+ LM87_IN_LIMITS(2, 0xac, 0xd4), /* 3.3V: 3.3V +/- 10% */
+ LM87_IN_LIMITS(4, 0xac, 0xe0), /* 12V: 10.8-14V */
+ LM87_IN_LIMITS(5, 0x3f, 0x4f), /* Vccp2: 1.0V +/- 10% */
+ LM87_TEMP_INT_LIMITS(0, 70 + FALCON_BOARD_TEMP_BIAS),
+ 0
+};
+
+static struct i2c_board_info sfe4003_hwmon_info = {
+ I2C_BOARD_INFO("lm87", 0x2e),
+ .platform_data = &sfe4003_lm87_channel,
+};
+
+/* Board-specific LED info. */
+#define SFE4003_RED_LED_GPIO 11
+#define SFE4003_LED_ON 1
+#define SFE4003_LED_OFF 0
+
+static void sfe4003_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
+{
+ struct falcon_board *board = falcon_board(efx);
+
+ /* The LEDs were not wired to GPIOs before A3 */
+ if (board->minor < 3 && board->major == 0)
+ return;
+
+ falcon_txc_set_gpio_val(
+ efx, SFE4003_RED_LED_GPIO,
+ (mode == EFX_LED_ON) ? SFE4003_LED_ON : SFE4003_LED_OFF);
+}
+
+static void sfe4003_init_phy(struct efx_nic *efx)
+{
+ struct falcon_board *board = falcon_board(efx);
+
+ /* The LEDs were not wired to GPIOs before A3 */
+ if (board->minor < 3 && board->major == 0)
+ return;
+
+ falcon_txc_set_gpio_dir(efx, SFE4003_RED_LED_GPIO, TXC_GPIO_DIR_OUTPUT);
+ falcon_txc_set_gpio_val(efx, SFE4003_RED_LED_GPIO, SFE4003_LED_OFF);
+}
+
+static int sfe4003_check_hw(struct efx_nic *efx)
+{
+ struct falcon_board *board = falcon_board(efx);
+
+ /* A0/A1/A2 board rev. 4003s report a temperature fault the whole time
+ * (bad sensor) so we mask it out. */
+ unsigned alarm_mask =
+ (board->major == 0 && board->minor <= 2) ?
+ ~LM87_ALARM_TEMP_EXT1 : ~0;
+
+ return efx_check_lm87(efx, alarm_mask);
+}
+
+static int sfe4003_init(struct efx_nic *efx)
+{
+ return efx_init_lm87(efx, &sfe4003_hwmon_info, sfe4003_lm87_regs);
+}
+
static const struct falcon_board_type board_types[] = {
{
.id = FALCON_BOARD_SFE4001,
@@ -713,14 +674,14 @@ static const struct falcon_board_type board_types[] = {
.monitor = sfe4002_check_hw,
},
{
- .id = FALCON_BOARD_SFN4111T,
- .ref_model = "SFN4111T",
- .gen_type = "100/1000/10GBASE-T adapter",
- .init = sfn4111t_init,
- .init_phy = sfn4111t_init_phy,
- .fini = sfn4111t_fini,
- .set_id_led = tenxpress_set_id_led,
- .monitor = sfn4111t_check_hw,
+ .id = FALCON_BOARD_SFE4003,
+ .ref_model = "SFE4003",
+ .gen_type = "10GBASE-CX4 adapter",
+ .init = sfe4003_init,
+ .init_phy = sfe4003_init_phy,
+ .fini = efx_fini_lm87,
+ .set_id_led = sfe4003_set_id_led,
+ .monitor = sfe4003_check_hw,
},
{
.id = FALCON_BOARD_SFN4112F,
diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c
deleted file mode 100644
index 7dadfcbd6ce7..000000000000
--- a/drivers/net/sfc/falcon_gmac.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2009 Solarflare Communications 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, incorporated herein by reference.
- */
-
-#include <linux/delay.h>
-#include "net_driver.h"
-#include "efx.h"
-#include "nic.h"
-#include "mac.h"
-#include "regs.h"
-#include "io.h"
-
-/**************************************************************************
- *
- * MAC operations
- *
- *************************************************************************/
-
-static int falcon_reconfigure_gmac(struct efx_nic *efx)
-{
- struct efx_link_state *link_state = &efx->link_state;
- bool loopback, tx_fc, rx_fc, bytemode;
- int if_mode;
- unsigned int max_frame_len;
- efx_oword_t reg;
-
- /* Configuration register 1 */
- tx_fc = (link_state->fc & EFX_FC_TX) || !link_state->fd;
- rx_fc = !!(link_state->fc & EFX_FC_RX);
- loopback = (efx->loopback_mode == LOOPBACK_GMAC);
- bytemode = (link_state->speed == 1000);
-
- EFX_POPULATE_OWORD_5(reg,
- FRF_AB_GM_LOOP, loopback,
- FRF_AB_GM_TX_EN, 1,
- FRF_AB_GM_TX_FC_EN, tx_fc,
- FRF_AB_GM_RX_EN, 1,
- FRF_AB_GM_RX_FC_EN, rx_fc);
- efx_writeo(efx, &reg, FR_AB_GM_CFG1);
- udelay(10);
-
- /* Configuration register 2 */
- if_mode = (bytemode) ? 2 : 1;
- EFX_POPULATE_OWORD_5(reg,
- FRF_AB_GM_IF_MODE, if_mode,
- FRF_AB_GM_PAD_CRC_EN, 1,
- FRF_AB_GM_LEN_CHK, 1,
- FRF_AB_GM_FD, link_state->fd,
- FRF_AB_GM_PAMBL_LEN, 0x7/*datasheet recommended */);
-
- efx_writeo(efx, &reg, FR_AB_GM_CFG2);
- udelay(10);
-
- /* Max frame len register */
- max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
- EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_MAX_FLEN, max_frame_len);
- efx_writeo(efx, &reg, FR_AB_GM_MAX_FLEN);
- udelay(10);
-
- /* FIFO configuration register 0 */
- EFX_POPULATE_OWORD_5(reg,
- FRF_AB_GMF_FTFENREQ, 1,
- FRF_AB_GMF_STFENREQ, 1,
- FRF_AB_GMF_FRFENREQ, 1,
- FRF_AB_GMF_SRFENREQ, 1,
- FRF_AB_GMF_WTMENREQ, 1);
- efx_writeo(efx, &reg, FR_AB_GMF_CFG0);
- udelay(10);
-
- /* FIFO configuration register 1 */
- EFX_POPULATE_OWORD_2(reg,
- FRF_AB_GMF_CFGFRTH, 0x12,
- FRF_AB_GMF_CFGXOFFRTX, 0xffff);
- efx_writeo(efx, &reg, FR_AB_GMF_CFG1);
- udelay(10);
-
- /* FIFO configuration register 2 */
- EFX_POPULATE_OWORD_2(reg,
- FRF_AB_GMF_CFGHWM, 0x3f,
- FRF_AB_GMF_CFGLWM, 0xa);
- efx_writeo(efx, &reg, FR_AB_GMF_CFG2);
- udelay(10);
-
- /* FIFO configuration register 3 */
- EFX_POPULATE_OWORD_2(reg,
- FRF_AB_GMF_CFGHWMFT, 0x1c,
- FRF_AB_GMF_CFGFTTH, 0x08);
- efx_writeo(efx, &reg, FR_AB_GMF_CFG3);
- udelay(10);
-
- /* FIFO configuration register 4 */
- EFX_POPULATE_OWORD_1(reg, FRF_AB_GMF_HSTFLTRFRM_PAUSE, 1);
- efx_writeo(efx, &reg, FR_AB_GMF_CFG4);
- udelay(10);
-
- /* FIFO configuration register 5 */
- efx_reado(efx, &reg, FR_AB_GMF_CFG5);
- EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_CFGBYTMODE, bytemode);
- EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_CFGHDPLX, !link_state->fd);
- EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_HSTDRPLT64, !link_state->fd);
- EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_HSTFLTRFRMDC_PAUSE, 0);
- efx_writeo(efx, &reg, FR_AB_GMF_CFG5);
- udelay(10);
-
- /* MAC address */
- EFX_POPULATE_OWORD_4(reg,
- FRF_AB_GM_ADR_B0, efx->net_dev->dev_addr[5],
- FRF_AB_GM_ADR_B1, efx->net_dev->dev_addr[4],
- FRF_AB_GM_ADR_B2, efx->net_dev->dev_addr[3],
- FRF_AB_GM_ADR_B3, efx->net_dev->dev_addr[2]);
- efx_writeo(efx, &reg, FR_AB_GM_ADR1);
- udelay(10);
- EFX_POPULATE_OWORD_2(reg,
- FRF_AB_GM_ADR_B4, efx->net_dev->dev_addr[1],
- FRF_AB_GM_ADR_B5, efx->net_dev->dev_addr[0]);
- efx_writeo(efx, &reg, FR_AB_GM_ADR2);
- udelay(10);
-
- falcon_reconfigure_mac_wrapper(efx);
-
- return 0;
-}
-
-static void falcon_update_stats_gmac(struct efx_nic *efx)
-{
- struct efx_mac_stats *mac_stats = &efx->mac_stats;
- unsigned long old_rx_pause, old_tx_pause;
- unsigned long new_rx_pause, new_tx_pause;
-
- /* Pause frames are erroneously counted as errors (SFC bug 3269) */
- old_rx_pause = mac_stats->rx_pause;
- old_tx_pause = mac_stats->tx_pause;
-
- /* Update MAC stats from DMAed values */
- FALCON_STAT(efx, GRxGoodOct, rx_good_bytes);
- FALCON_STAT(efx, GRxBadOct, rx_bad_bytes);
- FALCON_STAT(efx, GRxMissPkt, rx_missed);
- FALCON_STAT(efx, GRxFalseCRS, rx_false_carrier);
- FALCON_STAT(efx, GRxPausePkt, rx_pause);
- FALCON_STAT(efx, GRxBadPkt, rx_bad);
- FALCON_STAT(efx, GRxUcastPkt, rx_unicast);
- FALCON_STAT(efx, GRxMcastPkt, rx_multicast);
- FALCON_STAT(efx, GRxBcastPkt, rx_broadcast);
- FALCON_STAT(efx, GRxGoodLt64Pkt, rx_good_lt64);
- FALCON_STAT(efx, GRxBadLt64Pkt, rx_bad_lt64);
- FALCON_STAT(efx, GRx64Pkt, rx_64);
- FALCON_STAT(efx, GRx65to127Pkt, rx_65_to_127);
- FALCON_STAT(efx, GRx128to255Pkt, rx_128_to_255);
- FALCON_STAT(efx, GRx256to511Pkt, rx_256_to_511);
- FALCON_STAT(efx, GRx512to1023Pkt, rx_512_to_1023);
- FALCON_STAT(efx, GRx1024to15xxPkt, rx_1024_to_15xx);
- FALCON_STAT(efx, GRx15xxtoJumboPkt, rx_15xx_to_jumbo);
- FALCON_STAT(efx, GRxGtJumboPkt, rx_gtjumbo);
- FALCON_STAT(efx, GRxFcsErr64to15xxPkt, rx_bad_64_to_15xx);
- FALCON_STAT(efx, GRxFcsErr15xxtoJumboPkt, rx_bad_15xx_to_jumbo);
- FALCON_STAT(efx, GRxFcsErrGtJumboPkt, rx_bad_gtjumbo);
- FALCON_STAT(efx, GTxGoodBadOct, tx_bytes);
- FALCON_STAT(efx, GTxGoodOct, tx_good_bytes);
- FALCON_STAT(efx, GTxSglColPkt, tx_single_collision);
- FALCON_STAT(efx, GTxMultColPkt, tx_multiple_collision);
- FALCON_STAT(efx, GTxExColPkt, tx_excessive_collision);
- FALCON_STAT(efx, GTxDefPkt, tx_deferred);
- FALCON_STAT(efx, GTxLateCol, tx_late_collision);
- FALCON_STAT(efx, GTxExDefPkt, tx_excessive_deferred);
- FALCON_STAT(efx, GTxPausePkt, tx_pause);
- FALCON_STAT(efx, GTxBadPkt, tx_bad);
- FALCON_STAT(efx, GTxUcastPkt, tx_unicast);
- FALCON_STAT(efx, GTxMcastPkt, tx_multicast);
- FALCON_STAT(efx, GTxBcastPkt, tx_broadcast);
- FALCON_STAT(efx, GTxLt64Pkt, tx_lt64);
- FALCON_STAT(efx, GTx64Pkt, tx_64);
- FALCON_STAT(efx, GTx65to127Pkt, tx_65_to_127);
- FALCON_STAT(efx, GTx128to255Pkt, tx_128_to_255);
- FALCON_STAT(efx, GTx256to511Pkt, tx_256_to_511);
- FALCON_STAT(efx, GTx512to1023Pkt, tx_512_to_1023);
- FALCON_STAT(efx, GTx1024to15xxPkt, tx_1024_to_15xx);
- FALCON_STAT(efx, GTx15xxtoJumboPkt, tx_15xx_to_jumbo);
- FALCON_STAT(efx, GTxGtJumboPkt, tx_gtjumbo);
- FALCON_STAT(efx, GTxNonTcpUdpPkt, tx_non_tcpudp);
- FALCON_STAT(efx, GTxMacSrcErrPkt, tx_mac_src_error);
- FALCON_STAT(efx, GTxIpSrcErrPkt, tx_ip_src_error);
-
- /* Pause frames are erroneously counted as errors (SFC bug 3269) */
- new_rx_pause = mac_stats->rx_pause;
- new_tx_pause = mac_stats->tx_pause;
- mac_stats->rx_bad -= (new_rx_pause - old_rx_pause);
- mac_stats->tx_bad -= (new_tx_pause - old_tx_pause);
-
- /* Derive stats that the MAC doesn't provide directly */
- mac_stats->tx_bad_bytes =
- mac_stats->tx_bytes - mac_stats->tx_good_bytes;
- mac_stats->tx_packets =
- mac_stats->tx_lt64 + mac_stats->tx_64 +
- mac_stats->tx_65_to_127 + mac_stats->tx_128_to_255 +
- mac_stats->tx_256_to_511 + mac_stats->tx_512_to_1023 +
- mac_stats->tx_1024_to_15xx + mac_stats->tx_15xx_to_jumbo +
- mac_stats->tx_gtjumbo;
- mac_stats->tx_collision =
- mac_stats->tx_single_collision +
- mac_stats->tx_multiple_collision +
- mac_stats->tx_excessive_collision +
- mac_stats->tx_late_collision;
- mac_stats->rx_bytes =
- mac_stats->rx_good_bytes + mac_stats->rx_bad_bytes;
- mac_stats->rx_packets =
- mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64 +
- mac_stats->rx_64 + mac_stats->rx_65_to_127 +
- mac_stats->rx_128_to_255 + mac_stats->rx_256_to_511 +
- mac_stats->rx_512_to_1023 + mac_stats->rx_1024_to_15xx +
- mac_stats->rx_15xx_to_jumbo + mac_stats->rx_gtjumbo;
- mac_stats->rx_good = mac_stats->rx_packets - mac_stats->rx_bad;
- mac_stats->rx_lt64 = mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64;
-}
-
-static bool falcon_gmac_check_fault(struct efx_nic *efx)
-{
- return false;
-}
-
-struct efx_mac_operations falcon_gmac_operations = {
- .reconfigure = falcon_reconfigure_gmac,
- .update_stats = falcon_update_stats_gmac,
- .check_fault = falcon_gmac_check_fault,
-};
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index bae656dd2c4e..b31f595ebb5b 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -143,7 +143,7 @@ static bool falcon_xmac_link_ok(struct efx_nic *efx)
efx_mdio_phyxgxs_lane_sync(efx));
}
-void falcon_reconfigure_xmac_core(struct efx_nic *efx)
+static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
{
unsigned int max_frame_len;
efx_oword_t reg;
diff --git a/drivers/net/sfc/filter.c b/drivers/net/sfc/filter.c
new file mode 100644
index 000000000000..52cb6082b910
--- /dev/null
+++ b/drivers/net/sfc/filter.c
@@ -0,0 +1,454 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2010 Solarflare Communications 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, incorporated herein by reference.
+ */
+
+#include "efx.h"
+#include "filter.h"
+#include "io.h"
+#include "nic.h"
+#include "regs.h"
+
+/* "Fudge factors" - difference between programmed value and actual depth.
+ * Due to pipelined implementation we need to program H/W with a value that
+ * is larger than the hop limit we want.
+ */
+#define FILTER_CTL_SRCH_FUDGE_WILD 3
+#define FILTER_CTL_SRCH_FUDGE_FULL 1
+
+/* Hard maximum hop limit. Hardware will time-out beyond 200-something.
+ * We also need to avoid infinite loops in efx_filter_search() when the
+ * table is full.
+ */
+#define FILTER_CTL_SRCH_MAX 200
+
+struct efx_filter_table {
+ u32 offset; /* address of table relative to BAR */
+ unsigned size; /* number of entries */
+ unsigned step; /* step between entries */
+ unsigned used; /* number currently used */
+ unsigned long *used_bitmap;
+ struct efx_filter_spec *spec;
+};
+
+struct efx_filter_state {
+ spinlock_t lock;
+ struct efx_filter_table table[EFX_FILTER_TABLE_COUNT];
+ unsigned search_depth[EFX_FILTER_TYPE_COUNT];
+};
+
+/* The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
+ * key derived from the n-tuple. The initial LFSR state is 0xffff. */
+static u16 efx_filter_hash(u32 key)
+{
+ u16 tmp;
+
+ /* First 16 rounds */
+ tmp = 0x1fff ^ key >> 16;
+ tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
+ tmp = tmp ^ tmp >> 9;
+ /* Last 16 rounds */
+ tmp = tmp ^ tmp << 13 ^ key;
+ tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
+ return tmp ^ tmp >> 9;
+}
+
+/* To allow for hash collisions, filter search continues at these
+ * increments from the first possible entry selected by the hash. */
+static u16 efx_filter_increment(u32 key)
+{
+ return key * 2 - 1;
+}
+
+static enum efx_filter_table_id
+efx_filter_type_table_id(enum efx_filter_type type)
+{
+ BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_TCP_FULL >> 2));
+ BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_TCP_WILD >> 2));
+ BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_UDP_FULL >> 2));
+ BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_UDP_WILD >> 2));
+ BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_RX_MAC_FULL >> 2));
+ BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_RX_MAC_WILD >> 2));
+ return type >> 2;
+}
+
+static void
+efx_filter_table_reset_search_depth(struct efx_filter_state *state,
+ enum efx_filter_table_id table_id)
+{
+ memset(state->search_depth + (table_id << 2), 0,
+ sizeof(state->search_depth[0]) << 2);
+}
+
+static void efx_filter_push_rx_limits(struct efx_nic *efx)
+{
+ struct efx_filter_state *state = efx->filter_state;
+ efx_oword_t filter_ctl;
+
+ efx_reado(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL);
+
+ EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_FULL_SRCH_LIMIT,
+ state->search_depth[EFX_FILTER_RX_TCP_FULL] +
+ FILTER_CTL_SRCH_FUDGE_FULL);
+ EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_WILD_SRCH_LIMIT,
+ state->search_depth[EFX_FILTER_RX_TCP_WILD] +
+ FILTER_CTL_SRCH_FUDGE_WILD);
+ EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_FULL_SRCH_LIMIT,
+ state->search_depth[EFX_FILTER_RX_UDP_FULL] +
+ FILTER_CTL_SRCH_FUDGE_FULL);
+ EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_WILD_SRCH_LIMIT,
+ state->search_depth[EFX_FILTER_RX_UDP_WILD] +
+ FILTER_CTL_SRCH_FUDGE_WILD);
+
+ if (state->table[EFX_FILTER_TABLE_RX_MAC].size) {
+ EFX_SET_OWORD_FIELD(
+ filter_ctl, FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
+ state->search_depth[EFX_FILTER_RX_MAC_FULL] +
+ FILTER_CTL_SRCH_FUDGE_FULL);
+ EFX_SET_OWORD_FIELD(
+ filter_ctl, FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
+ state->search_depth[EFX_FILTER_RX_MAC_WILD] +
+ FILTER_CTL_SRCH_FUDGE_WILD);
+ }
+
+ efx_writeo(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL);
+}
+
+/* Build a filter entry and return its n-tuple key. */
+static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec)
+{
+ u32 data3;
+
+ switch (efx_filter_type_table_id(spec->type)) {
+ case EFX_FILTER_TABLE_RX_IP: {
+ bool is_udp = (spec->type == EFX_FILTER_RX_UDP_FULL ||
+ spec->type == EFX_FILTER_RX_UDP_WILD);
+ EFX_POPULATE_OWORD_7(
+ *filter,
+ FRF_BZ_RSS_EN,
+ !!(spec->flags & EFX_FILTER_FLAG_RX_RSS),
+ FRF_BZ_SCATTER_EN,
+ !!(spec->flags & EFX_FILTER_FLAG_RX_SCATTER),
+ FRF_BZ_TCP_UDP, is_udp,
+ FRF_BZ_RXQ_ID, spec->dmaq_id,
+ EFX_DWORD_2, spec->data[2],
+ EFX_DWORD_1, spec->data[1],
+ EFX_DWORD_0, spec->data[0]);
+ data3 = is_udp;
+ break;
+ }
+
+ case EFX_FILTER_TABLE_RX_MAC: {
+ bool is_wild = spec->type == EFX_FILTER_RX_MAC_WILD;
+ EFX_POPULATE_OWORD_8(
+ *filter,
+ FRF_CZ_RMFT_RSS_EN,
+ !!(spec->flags & EFX_FILTER_FLAG_RX_RSS),
+ FRF_CZ_RMFT_SCATTER_EN,
+ !!(spec->flags & EFX_FILTER_FLAG_RX_SCATTER),
+ FRF_CZ_RMFT_IP_OVERRIDE,
+ !!(spec->flags & EFX_FILTER_FLAG_RX_OVERRIDE_IP),
+ FRF_CZ_RMFT_RXQ_ID, spec->dmaq_id,
+ FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
+ FRF_CZ_RMFT_DEST_MAC_HI, spec->data[2],
+ FRF_CZ_RMFT_DEST_MAC_LO, spec->data[1],
+ FRF_CZ_RMFT_VLAN_ID, spec->data[0]);
+ data3 = is_wild;
+ break;
+ }
+
+ default:
+ BUG();
+ }
+
+ return spec->data[0] ^ spec->data[1] ^ spec->data[2] ^ data3;
+}
+
+static bool efx_filter_equal(const struct efx_filter_spec *left,
+ const struct efx_filter_spec *right)
+{
+ if (left->type != right->type ||
+ memcmp(left->data, right->data, sizeof(left->data)))
+ return false;
+
+ return true;
+}
+
+static int efx_filter_search(struct efx_filter_table *table,
+ struct efx_filter_spec *spec, u32 key,
+ bool for_insert, int *depth_required)
+{
+ unsigned hash, incr, filter_idx, depth;
+ struct efx_filter_spec *cmp;
+
+ hash = efx_filter_hash(key);
+ incr = efx_filter_increment(key);
+
+ for (depth = 1, filter_idx = hash & (table->size - 1);
+ depth <= FILTER_CTL_SRCH_MAX &&
+ test_bit(filter_idx, table->used_bitmap);
+ ++depth) {
+ cmp = &table->spec[filter_idx];
+ if (efx_filter_equal(spec, cmp))
+ goto found;
+ filter_idx = (filter_idx + incr) & (table->size - 1);
+ }
+ if (!for_insert)
+ return -ENOENT;
+ if (depth > FILTER_CTL_SRCH_MAX)
+ return -EBUSY;
+found:
+ *depth_required = depth;
+ return filter_idx;
+}
+
+/**
+ * efx_filter_insert_filter - add or replace a filter
+ * @efx: NIC in which to insert the filter
+ * @spec: Specification for the filter
+ * @replace: Flag for whether the specified filter may replace a filter
+ * with an identical match expression and equal or lower priority
+ *
+ * On success, return the filter index within its table.
+ * On failure, return a negative error code.
+ */
+int efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec,
+ bool replace)
+{
+ struct efx_filter_state *state = efx->filter_state;
+ enum efx_filter_table_id table_id =
+ efx_filter_type_table_id(spec->type);
+ struct efx_filter_table *table = &state->table[table_id];
+ struct efx_filter_spec *saved_spec;
+ efx_oword_t filter;
+ int filter_idx, depth;
+ u32 key;
+ int rc;
+
+ if (table->size == 0)
+ return -EINVAL;
+
+ key = efx_filter_build(&filter, spec);
+
+ netif_vdbg(efx, hw, efx->net_dev,
+ "%s: type %d search_depth=%d", __func__, spec->type,
+ state->search_depth[spec->type]);
+
+ spin_lock_bh(&state->lock);
+
+ rc = efx_filter_search(table, spec, key, true, &depth);
+ if (rc < 0)
+ goto out;
+ filter_idx = rc;
+ BUG_ON(filter_idx >= table->size);
+ saved_spec = &table->spec[filter_idx];
+
+ if (test_bit(filter_idx, table->used_bitmap)) {
+ /* Should we replace the existing filter? */
+ if (!replace) {
+ rc = -EEXIST;
+ goto out;
+ }
+ if (spec->priority < saved_spec->priority) {
+ rc = -EPERM;
+ goto out;
+ }
+ } else {
+ __set_bit(filter_idx, table->used_bitmap);
+ ++table->used;
+ }
+ *saved_spec = *spec;
+
+ if (state->search_depth[spec->type] < depth) {
+ state->search_depth[spec->type] = depth;
+ efx_filter_push_rx_limits(efx);
+ }
+
+ efx_writeo(efx, &filter, table->offset + table->step * filter_idx);
+
+ netif_vdbg(efx, hw, efx->net_dev,
+ "%s: filter type %d index %d rxq %u set",
+ __func__, spec->type, filter_idx, spec->dmaq_id);
+
+out:
+ spin_unlock_bh(&state->lock);
+ return rc;
+}
+
+static void efx_filter_table_clear_entry(struct efx_nic *efx,
+ struct efx_filter_table *table,
+ int filter_idx)
+{
+ static efx_oword_t filter;
+
+ if (test_bit(filter_idx, table->used_bitmap)) {
+ __clear_bit(filter_idx, table->used_bitmap);
+ --table->used;
+ memset(&table->spec[filter_idx], 0, sizeof(table->spec[0]));
+
+ efx_writeo(efx, &filter,
+ table->offset + table->step * filter_idx);
+ }
+}
+
+/**
+ * efx_filter_remove_filter - remove a filter by specification
+ * @efx: NIC from which to remove the filter
+ * @spec: Specification for the filter
+ *
+ * On success, return zero.
+ * On failure, return a negative error code.
+ */
+int efx_filter_remove_filter(struct efx_nic *efx, struct efx_filter_spec *spec)
+{
+ struct efx_filter_state *state = efx->filter_state;
+ enum efx_filter_table_id table_id =
+ efx_filter_type_table_id(spec->type);
+ struct efx_filter_table *table = &state->table[table_id];
+ struct efx_filter_spec *saved_spec;
+ efx_oword_t filter;
+ int filter_idx, depth;
+ u32 key;
+ int rc;
+
+ key = efx_filter_build(&filter, spec);
+
+ spin_lock_bh(&state->lock);
+
+ rc = efx_filter_search(table, spec, key, false, &depth);
+ if (rc < 0)
+ goto out;
+ filter_idx = rc;
+ saved_spec = &table->spec[filter_idx];
+
+ if (spec->priority < saved_spec->priority) {
+ rc = -EPERM;
+ goto out;
+ }
+
+ efx_filter_table_clear_entry(efx, table, filter_idx);
+ if (table->used == 0)
+ efx_filter_table_reset_search_depth(state, table_id);
+ rc = 0;
+
+out:
+ spin_unlock_bh(&state->lock);
+ return rc;
+}
+
+/**
+ * efx_filter_table_clear - remove filters from a table by priority
+ * @efx: NIC from which to remove the filters
+ * @table_id: Table from which to remove the filters
+ * @priority: Maximum priority to remove
+ */
+void efx_filter_table_clear(struct efx_nic *efx,
+ enum efx_filter_table_id table_id,
+ enum efx_filter_priority priority)
+{
+ struct efx_filter_state *state = efx->filter_state;
+ struct efx_filter_table *table = &state->table[table_id];
+ int filter_idx;
+
+ spin_lock_bh(&state->lock);
+
+ for (filter_idx = 0; filter_idx < table->size; ++filter_idx)
+ if (table->spec[filter_idx].priority <= priority)
+ efx_filter_table_clear_entry(efx, table, filter_idx);
+ if (table->used == 0)
+ efx_filter_table_reset_search_depth(state, table_id);
+
+ spin_unlock_bh(&state->lock);
+}
+
+/* Restore filter stater after reset */
+void efx_restore_filters(struct efx_nic *efx)
+{
+ struct efx_filter_state *state = efx->filter_state;
+ enum efx_filter_table_id table_id;
+ struct efx_filter_table *table;
+ efx_oword_t filter;
+ int filter_idx;
+
+ spin_lock_bh(&state->lock);
+
+ for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) {
+ table = &state->table[table_id];
+ for (filter_idx = 0; filter_idx < table->size; filter_idx++) {
+ if (!test_bit(filter_idx, table->used_bitmap))
+ continue;
+ efx_filter_build(&filter, &table->spec[filter_idx]);
+ efx_writeo(efx, &filter,
+ table->offset + table->step * filter_idx);
+ }
+ }
+
+ efx_filter_push_rx_limits(efx);
+
+ spin_unlock_bh(&state->lock);
+}
+
+int efx_probe_filters(struct efx_nic *efx)
+{
+ struct efx_filter_state *state;
+ struct efx_filter_table *table;
+ unsigned table_id;
+
+ state = kzalloc(sizeof(*efx->filter_state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+ efx->filter_state = state;
+
+ spin_lock_init(&state->lock);
+
+ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
+ table = &state->table[EFX_FILTER_TABLE_RX_IP];
+ table->offset = FR_BZ_RX_FILTER_TBL0;
+ table->size = FR_BZ_RX_FILTER_TBL0_ROWS;
+ table->step = FR_BZ_RX_FILTER_TBL0_STEP;
+ }
+
+ if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) {
+ table = &state->table[EFX_FILTER_TABLE_RX_MAC];
+ table->offset = FR_CZ_RX_MAC_FILTER_TBL0;
+ table->size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
+ table->step = FR_CZ_RX_MAC_FILTER_TBL0_STEP;
+ }
+
+ for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) {
+ table = &state->table[table_id];
+ if (table->size == 0)
+ continue;
+ table->used_bitmap = kcalloc(BITS_TO_LONGS(table->size),
+ sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!table->used_bitmap)
+ goto fail;
+ table->spec = vmalloc(table->size * sizeof(*table->spec));
+ if (!table->spec)
+ goto fail;
+ memset(table->spec, 0, table->size * sizeof(*table->spec));
+ }
+
+ return 0;
+
+fail:
+ efx_remove_filters(efx);
+ return -ENOMEM;
+}
+
+void efx_remove_filters(struct efx_nic *efx)
+{
+ struct efx_filter_state *state = efx->filter_state;
+ enum efx_filter_table_id table_id;
+
+ for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) {
+ kfree(state->table[table_id].used_bitmap);
+ vfree(state->table[table_id].spec);
+ }
+ kfree(state);
+}
diff --git a/drivers/net/sfc/filter.h b/drivers/net/sfc/filter.h
new file mode 100644
index 000000000000..a53319ded79c
--- /dev/null
+++ b/drivers/net/sfc/filter.h
@@ -0,0 +1,189 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2010 Solarflare Communications 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, incorporated herein by reference.
+ */
+
+#ifndef EFX_FILTER_H
+#define EFX_FILTER_H
+
+#include <linux/types.h>
+
+enum efx_filter_table_id {
+ EFX_FILTER_TABLE_RX_IP = 0,
+ EFX_FILTER_TABLE_RX_MAC,
+ EFX_FILTER_TABLE_COUNT,
+};
+
+/**
+ * enum efx_filter_type - type of hardware filter
+ * @EFX_FILTER_RX_TCP_FULL: RX, matching TCP/IPv4 4-tuple
+ * @EFX_FILTER_RX_TCP_WILD: RX, matching TCP/IPv4 destination (host, port)
+ * @EFX_FILTER_RX_UDP_FULL: RX, matching UDP/IPv4 4-tuple
+ * @EFX_FILTER_RX_UDP_WILD: RX, matching UDP/IPv4 destination (host, port)
+ * @EFX_FILTER_RX_MAC_FULL: RX, matching Ethernet destination MAC address, VID
+ * @EFX_FILTER_RX_MAC_WILD: RX, matching Ethernet destination MAC address
+ *
+ * Falcon NICs only support the RX TCP/IPv4 and UDP/IPv4 filter types.
+ */
+enum efx_filter_type {
+ EFX_FILTER_RX_TCP_FULL = 0,
+ EFX_FILTER_RX_TCP_WILD,
+ EFX_FILTER_RX_UDP_FULL,
+ EFX_FILTER_RX_UDP_WILD,
+ EFX_FILTER_RX_MAC_FULL = 4,
+ EFX_FILTER_RX_MAC_WILD,
+ EFX_FILTER_TYPE_COUNT,
+};
+
+/**
+ * enum efx_filter_priority - priority of a hardware filter specification
+ * @EFX_FILTER_PRI_HINT: Performance hint
+ * @EFX_FILTER_PRI_MANUAL: Manually configured filter
+ * @EFX_FILTER_PRI_REQUIRED: Required for correct behaviour
+ */
+enum efx_filter_priority {
+ EFX_FILTER_PRI_HINT = 0,
+ EFX_FILTER_PRI_MANUAL,
+ EFX_FILTER_PRI_REQUIRED,
+};
+
+/**
+ * enum efx_filter_flags - flags for hardware filter specifications
+ * @EFX_FILTER_FLAG_RX_RSS: Use RSS to spread across multiple queues.
+ * By default, matching packets will be delivered only to the
+ * specified queue. If this flag is set, they will be delivered
+ * to a range of queues offset from the specified queue number
+ * according to the indirection table.
+ * @EFX_FILTER_FLAG_RX_SCATTER: Enable DMA scatter on the receiving
+ * queue.
+ * @EFX_FILTER_FLAG_RX_OVERRIDE_IP: Enables a MAC filter to override
+ * any IP filter that matches the same packet. By default, IP
+ * filters take precedence.
+ *
+ * Currently, no flags are defined for TX filters.
+ */
+enum efx_filter_flags {
+ EFX_FILTER_FLAG_RX_RSS = 0x01,
+ EFX_FILTER_FLAG_RX_SCATTER = 0x02,
+ EFX_FILTER_FLAG_RX_OVERRIDE_IP = 0x04,
+};
+
+/**
+ * struct efx_filter_spec - specification for a hardware filter
+ * @type: Type of match to be performed, from &enum efx_filter_type
+ * @priority: Priority of the filter, from &enum efx_filter_priority
+ * @flags: Miscellaneous flags, from &enum efx_filter_flags
+ * @dmaq_id: Source/target queue index
+ * @data: Match data (type-dependent)
+ *
+ * Use the efx_filter_set_*() functions to initialise the @type and
+ * @data fields.
+ */
+struct efx_filter_spec {
+ u8 type:4;
+ u8 priority:4;
+ u8 flags;
+ u16 dmaq_id;
+ u32 data[3];
+};
+
+/**
+ * efx_filter_set_rx_tcp_full - specify RX filter with TCP/IPv4 full match
+ * @spec: Specification to initialise
+ * @shost: Source host address (host byte order)
+ * @sport: Source port (host byte order)
+ * @dhost: Destination host address (host byte order)
+ * @dport: Destination port (host byte order)
+ */
+static inline void
+efx_filter_set_rx_tcp_full(struct efx_filter_spec *spec,
+ u32 shost, u16 sport, u32 dhost, u16 dport)
+{
+ spec->type = EFX_FILTER_RX_TCP_FULL;
+ spec->data[0] = sport | shost << 16;
+ spec->data[1] = dport << 16 | shost >> 16;
+ spec->data[2] = dhost;
+}
+
+/**
+ * efx_filter_set_rx_tcp_wild - specify RX filter with TCP/IPv4 wildcard match
+ * @spec: Specification to initialise
+ * @dhost: Destination host address (host byte order)
+ * @dport: Destination port (host byte order)
+ */
+static inline void
+efx_filter_set_rx_tcp_wild(struct efx_filter_spec *spec, u32 dhost, u16 dport)
+{
+ spec->type = EFX_FILTER_RX_TCP_WILD;
+ spec->data[0] = 0;
+ spec->data[1] = dport << 16;
+ spec->data[2] = dhost;
+}
+
+/**
+ * efx_filter_set_rx_udp_full - specify RX filter with UDP/IPv4 full match
+ * @spec: Specification to initialise
+ * @shost: Source host address (host byte order)
+ * @sport: Source port (host byte order)
+ * @dhost: Destination host address (host byte order)
+ * @dport: Destination port (host byte order)
+ */
+static inline void
+efx_filter_set_rx_udp_full(struct efx_filter_spec *spec,
+ u32 shost, u16 sport, u32 dhost, u16 dport)
+{
+ spec->type = EFX_FILTER_RX_UDP_FULL;
+ spec->data[0] = sport | shost << 16;
+ spec->data[1] = dport << 16 | shost >> 16;
+ spec->data[2] = dhost;
+}
+
+/**
+ * efx_filter_set_rx_udp_wild - specify RX filter with UDP/IPv4 wildcard match
+ * @spec: Specification to initialise
+ * @dhost: Destination host address (host byte order)
+ * @dport: Destination port (host byte order)
+ */
+static inline void
+efx_filter_set_rx_udp_wild(struct efx_filter_spec *spec, u32 dhost, u16 dport)
+{
+ spec->type = EFX_FILTER_RX_UDP_WILD;
+ spec->data[0] = dport;
+ spec->data[1] = 0;
+ spec->data[2] = dhost;
+}
+
+/**
+ * efx_filter_set_rx_mac_full - specify RX filter with MAC full match
+ * @spec: Specification to initialise
+ * @vid: VLAN ID
+ * @addr: Destination MAC address
+ */
+static inline void efx_filter_set_rx_mac_full(struct efx_filter_spec *spec,
+ u16 vid, const u8 *addr)
+{
+ spec->type = EFX_FILTER_RX_MAC_FULL;
+ spec->data[0] = vid;
+ spec->data[1] = addr[2] << 24 | addr[3] << 16 | addr[4] << 8 | addr[5];
+ spec->data[2] = addr[0] << 8 | addr[1];
+}
+
+/**
+ * efx_filter_set_rx_mac_full - specify RX filter with MAC wildcard match
+ * @spec: Specification to initialise
+ * @addr: Destination MAC address
+ */
+static inline void efx_filter_set_rx_mac_wild(struct efx_filter_spec *spec,
+ const u8 *addr)
+{
+ spec->type = EFX_FILTER_RX_MAC_WILD;
+ spec->data[0] = 0;
+ spec->data[1] = addr[2] << 24 | addr[3] << 16 | addr[4] << 8 | addr[5];
+ spec->data[2] = addr[0] << 8 | addr[1];
+}
+
+#endif /* EFX_FILTER_H */
diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h
index f1aa5f374890..6886cdf87c12 100644
--- a/drivers/net/sfc/mac.h
+++ b/drivers/net/sfc/mac.h
@@ -13,10 +13,8 @@
#include "net_driver.h"
-extern struct efx_mac_operations falcon_gmac_operations;
extern struct efx_mac_operations falcon_xmac_operations;
extern struct efx_mac_operations efx_mcdi_mac_operations;
-extern void falcon_reconfigure_xmac_core(struct efx_nic *efx);
extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
u32 dma_len, int enable, int clear);
diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c
index 3912b8fed912..12cf910c2ce7 100644
--- a/drivers/net/sfc/mcdi.c
+++ b/drivers/net/sfc/mcdi.c
@@ -1093,8 +1093,8 @@ int efx_mcdi_reset_mc(struct efx_nic *efx)
return rc;
}
-int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type,
- const u8 *mac, int *id_out)
+static int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type,
+ const u8 *mac, int *id_out)
{
u8 inbuf[MC_CMD_WOL_FILTER_SET_IN_LEN];
u8 outbuf[MC_CMD_WOL_FILTER_SET_OUT_LEN];
diff --git a/drivers/net/sfc/mcdi.h b/drivers/net/sfc/mcdi.h
index f1f89ad4075a..c792f1d65e48 100644
--- a/drivers/net/sfc/mcdi.h
+++ b/drivers/net/sfc/mcdi.h
@@ -121,8 +121,6 @@ extern int efx_mcdi_handle_assertion(struct efx_nic *efx);
extern void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
extern int efx_mcdi_reset_port(struct efx_nic *efx);
extern int efx_mcdi_reset_mc(struct efx_nic *efx);
-extern int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type,
- const u8 *mac, int *id_out);
extern int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx,
const u8 *mac, int *id_out);
extern int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out);
diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c
index 0121e71702bf..c992742446b1 100644
--- a/drivers/net/sfc/mcdi_phy.c
+++ b/drivers/net/sfc/mcdi_phy.c
@@ -713,7 +713,8 @@ static int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results,
return 0;
}
-const char *efx_mcdi_phy_test_name(struct efx_nic *efx, unsigned int index)
+static const char *efx_mcdi_phy_test_name(struct efx_nic *efx,
+ unsigned int index)
{
struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index eeaf0bd64bd3..98d946020429 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -286,46 +286,24 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
*/
void efx_mdio_an_reconfigure(struct efx_nic *efx)
{
- bool xnp = (efx->link_advertising & ADVERTISED_10000baseT_Full
- || EFX_WORKAROUND_13204(efx));
int reg;
WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN));
/* Set up the base page */
- reg = ADVERTISE_CSMA;
- if (efx->link_advertising & ADVERTISED_10baseT_Half)
- reg |= ADVERTISE_10HALF;
- if (efx->link_advertising & ADVERTISED_10baseT_Full)
- reg |= ADVERTISE_10FULL;
- if (efx->link_advertising & ADVERTISED_100baseT_Half)
- reg |= ADVERTISE_100HALF;
- if (efx->link_advertising & ADVERTISED_100baseT_Full)
- reg |= ADVERTISE_100FULL;
- if (xnp)
- reg |= ADVERTISE_RESV;
- else if (efx->link_advertising & (ADVERTISED_1000baseT_Half |
- ADVERTISED_1000baseT_Full))
- reg |= ADVERTISE_NPAGE;
+ reg = ADVERTISE_CSMA | ADVERTISE_RESV;
if (efx->link_advertising & ADVERTISED_Pause)
reg |= ADVERTISE_PAUSE_CAP;
if (efx->link_advertising & ADVERTISED_Asym_Pause)
reg |= ADVERTISE_PAUSE_ASYM;
efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
- /* Set up the (extended) next page if necessary */
- if (efx->phy_op->set_npage_adv)
- efx->phy_op->set_npage_adv(efx, efx->link_advertising);
+ /* Set up the (extended) next page */
+ efx->phy_op->set_npage_adv(efx, efx->link_advertising);
/* Enable and restart AN */
reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1);
- reg |= MDIO_AN_CTRL1_ENABLE;
- if (!(EFX_WORKAROUND_15195(efx) && LOOPBACK_EXTERNAL(efx)))
- reg |= MDIO_AN_CTRL1_RESTART;
- if (xnp)
- reg |= MDIO_AN_CTRL1_XNP;
- else
- reg &= ~MDIO_AN_CTRL1_XNP;
+ reg |= MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART | MDIO_AN_CTRL1_XNP;
efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg);
}
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 64e7caa4bbb5..0a7e26d73b52 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -29,6 +29,7 @@
#include <linux/device.h>
#include <linux/highmem.h>
#include <linux/workqueue.h>
+#include <linux/vmalloc.h>
#include <linux/i2c.h>
#include "enum.h"
@@ -137,6 +138,7 @@ struct efx_tx_buffer {
* @channel: The associated channel
* @buffer: The software buffer ring
* @txd: The hardware descriptor ring
+ * @ptr_mask: The size of the ring minus 1.
* @flushed: Used when handling queue flushing
* @read_count: Current read pointer.
* This is the number of buffers that have been removed from both rings.
@@ -170,6 +172,7 @@ struct efx_tx_queue {
struct efx_nic *nic;
struct efx_tx_buffer *buffer;
struct efx_special_buffer txd;
+ unsigned int ptr_mask;
enum efx_flush_state flushed;
/* Members used mainly on the completion path */
@@ -225,10 +228,9 @@ struct efx_rx_page_state {
/**
* struct efx_rx_queue - An Efx RX queue
* @efx: The associated Efx NIC
- * @queue: DMA queue number
- * @channel: The associated channel
* @buffer: The software buffer ring
* @rxd: The hardware descriptor ring
+ * @ptr_mask: The size of the ring minus 1.
* @added_count: Number of buffers added to the receive queue.
* @notified_count: Number of buffers given to NIC (<= @added_count).
* @removed_count: Number of buffers removed from the receive queue.
@@ -240,9 +242,6 @@ struct efx_rx_page_state {
* @min_fill: RX descriptor minimum non-zero fill level.
* This records the minimum fill level observed when a ring
* refill was triggered.
- * @min_overfill: RX descriptor minimum overflow fill level.
- * This records the minimum fill level at which RX queue
- * overflow was observed. It should never be set.
* @alloc_page_count: RX allocation strategy counter.
* @alloc_skb_count: RX allocation strategy counter.
* @slow_fill: Timer used to defer efx_nic_generate_fill_event().
@@ -250,10 +249,9 @@ struct efx_rx_page_state {
*/
struct efx_rx_queue {
struct efx_nic *efx;
- int queue;
- struct efx_channel *channel;
struct efx_rx_buffer *buffer;
struct efx_special_buffer rxd;
+ unsigned int ptr_mask;
int added_count;
int notified_count;
@@ -302,7 +300,6 @@ enum efx_rx_alloc_method {
*
* @efx: Associated Efx NIC
* @channel: Channel instance number
- * @name: Name for channel and IRQ
* @enabled: Channel enabled indicator
* @irq: IRQ number (MSI and MSI-X only)
* @irq_moderation: IRQ moderation value (in hardware ticks)
@@ -311,6 +308,7 @@ enum efx_rx_alloc_method {
* @reset_work: Scheduled reset work thread
* @work_pending: Is work pending via NAPI?
* @eventq: Event queue buffer
+ * @eventq_mask: Event queue pointer mask
* @eventq_read_ptr: Event queue read pointer
* @last_eventq_read_ptr: Last event queue read pointer value.
* @magic_count: Event queue test event count
@@ -327,14 +325,14 @@ enum efx_rx_alloc_method {
* @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors
* @n_rx_overlength: Count of RX_OVERLENGTH errors
* @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun
- * @tx_queue: Pointer to first TX queue, or %NULL if not used for TX
+ * @rx_queue: RX queue for this channel
* @tx_stop_count: Core TX queue stop count
* @tx_stop_lock: Core TX queue stop lock
+ * @tx_queue: TX queues for this channel
*/
struct efx_channel {
struct efx_nic *efx;
int channel;
- char name[IFNAMSIZ + 6];
bool enabled;
int irq;
unsigned int irq_moderation;
@@ -342,6 +340,7 @@ struct efx_channel {
struct napi_struct napi_str;
bool work_pending;
struct efx_special_buffer eventq;
+ unsigned int eventq_mask;
unsigned int eventq_read_ptr;
unsigned int last_eventq_read_ptr;
unsigned int magic_count;
@@ -366,9 +365,12 @@ struct efx_channel {
struct efx_rx_buffer *rx_pkt;
bool rx_pkt_csummed;
- struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue rx_queue;
+
atomic_t tx_stop_count;
spinlock_t tx_stop_lock;
+
+ struct efx_tx_queue tx_queue[2];
};
enum efx_led_mode {
@@ -385,11 +387,6 @@ extern const unsigned int efx_loopback_mode_max;
#define LOOPBACK_MODE(efx) \
STRING_TABLE_LOOKUP((efx)->loopback_mode, efx_loopback_mode)
-extern const char *efx_interrupt_mode_names[];
-extern const unsigned int efx_interrupt_mode_max;
-#define INT_MODE(efx) \
- STRING_TABLE_LOOKUP(efx->interrupt_mode, efx_interrupt_mode)
-
extern const char *efx_reset_type_names[];
extern const unsigned int efx_reset_type_max;
#define RESET_TYPE(type) \
@@ -404,8 +401,6 @@ enum efx_int_mode {
};
#define EFX_INT_MODE_USE_MSI(x) (((x)->interrupt_mode) <= EFX_INT_MODE_MSI)
-#define EFX_IS10G(efx) ((efx)->link_state.speed == 10000)
-
enum nic_state {
STATE_INIT = 0,
STATE_RUNNING = 1,
@@ -618,6 +613,8 @@ union efx_multicast_hash {
efx_oword_t oword[EFX_MCAST_HASH_ENTRIES / sizeof(efx_oword_t) / 8];
};
+struct efx_filter_state;
+
/**
* struct efx_nic - an Efx NIC
* @name: Device name (net device name or bus id before net device registered)
@@ -641,6 +638,9 @@ union efx_multicast_hash {
* @tx_queue: TX DMA queues
* @rx_queue: RX DMA queues
* @channel: Channels
+ * @channel_name: Names for channels and their IRQs
+ * @rxq_entries: Size of receive queues requested by user.
+ * @txq_entries: Size of transmit queues requested by user.
* @next_buffer_table: First available buffer table id
* @n_channels: Number of channels in use
* @n_rx_channels: Number of channels used for RX (= number of RX queues)
@@ -724,10 +724,11 @@ struct efx_nic {
enum nic_state state;
enum reset_type reset_pending;
- struct efx_tx_queue tx_queue[EFX_MAX_TX_QUEUES];
- struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES];
- struct efx_channel channel[EFX_MAX_CHANNELS];
+ struct efx_channel *channel[EFX_MAX_CHANNELS];
+ char channel_name[EFX_MAX_CHANNELS][IFNAMSIZ + 6];
+ unsigned rxq_entries;
+ unsigned txq_entries;
unsigned next_buffer_table;
unsigned n_channels;
unsigned n_rx_channels;
@@ -794,6 +795,8 @@ struct efx_nic {
u64 loopback_modes;
void *loopback_selftest;
+
+ struct efx_filter_state *filter_state;
};
static inline int efx_dev_registered(struct efx_nic *efx)
@@ -909,39 +912,67 @@ struct efx_nic_type {
*
*************************************************************************/
+static inline struct efx_channel *
+efx_get_channel(struct efx_nic *efx, unsigned index)
+{
+ EFX_BUG_ON_PARANOID(index >= efx->n_channels);
+ return efx->channel[index];
+}
+
/* Iterate over all used channels */
#define efx_for_each_channel(_channel, _efx) \
- for (_channel = &((_efx)->channel[0]); \
- _channel < &((_efx)->channel[(efx)->n_channels]); \
- _channel++)
-
-/* Iterate over all used TX queues */
-#define efx_for_each_tx_queue(_tx_queue, _efx) \
- for (_tx_queue = &((_efx)->tx_queue[0]); \
- _tx_queue < &((_efx)->tx_queue[EFX_TXQ_TYPES * \
- (_efx)->n_tx_channels]); \
- _tx_queue++)
+ for (_channel = (_efx)->channel[0]; \
+ _channel; \
+ _channel = (_channel->channel + 1 < (_efx)->n_channels) ? \
+ (_efx)->channel[_channel->channel + 1] : NULL)
+
+extern struct efx_tx_queue *
+efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type);
+
+static inline struct efx_tx_queue *
+efx_channel_get_tx_queue(struct efx_channel *channel, unsigned type)
+{
+ struct efx_tx_queue *tx_queue = channel->tx_queue;
+ EFX_BUG_ON_PARANOID(type >= EFX_TXQ_TYPES);
+ return tx_queue->channel ? tx_queue + type : NULL;
+}
/* Iterate over all TX queues belonging to a channel */
#define efx_for_each_channel_tx_queue(_tx_queue, _channel) \
- for (_tx_queue = (_channel)->tx_queue; \
+ for (_tx_queue = efx_channel_get_tx_queue(channel, 0); \
_tx_queue && _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES; \
_tx_queue++)
-/* Iterate over all used RX queues */
-#define efx_for_each_rx_queue(_rx_queue, _efx) \
- for (_rx_queue = &((_efx)->rx_queue[0]); \
- _rx_queue < &((_efx)->rx_queue[(_efx)->n_rx_channels]); \
- _rx_queue++)
+static inline struct efx_rx_queue *
+efx_get_rx_queue(struct efx_nic *efx, unsigned index)
+{
+ EFX_BUG_ON_PARANOID(index >= efx->n_rx_channels);
+ return &efx->channel[index]->rx_queue;
+}
+
+static inline struct efx_rx_queue *
+efx_channel_get_rx_queue(struct efx_channel *channel)
+{
+ return channel->channel < channel->efx->n_rx_channels ?
+ &channel->rx_queue : NULL;
+}
/* Iterate over all RX queues belonging to a channel */
#define efx_for_each_channel_rx_queue(_rx_queue, _channel) \
- for (_rx_queue = &((_channel)->efx->rx_queue[(_channel)->channel]); \
+ for (_rx_queue = efx_channel_get_rx_queue(channel); \
_rx_queue; \
- _rx_queue = NULL) \
- if (_rx_queue->channel != (_channel)) \
- continue; \
- else
+ _rx_queue = NULL)
+
+static inline struct efx_channel *
+efx_rx_queue_channel(struct efx_rx_queue *rx_queue)
+{
+ return container_of(rx_queue, struct efx_channel, rx_queue);
+}
+
+static inline int efx_rx_queue_index(struct efx_rx_queue *rx_queue)
+{
+ return efx_rx_queue_channel(rx_queue)->channel;
+}
/* Returns a pointer to the specified receive buffer in the RX
* descriptor queue.
@@ -949,7 +980,7 @@ struct efx_nic_type {
static inline struct efx_rx_buffer *efx_rx_buffer(struct efx_rx_queue *rx_queue,
unsigned int index)
{
- return (&rx_queue->buffer[index]);
+ return &rx_queue->buffer[index];
}
/* Set bit in a little-endian bitfield */
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index f595d920c7c4..41c36b9a4244 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -104,7 +104,7 @@ static inline void efx_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value,
static inline efx_qword_t *efx_event(struct efx_channel *channel,
unsigned int index)
{
- return (((efx_qword_t *) (channel->eventq.addr)) + index);
+ return ((efx_qword_t *) (channel->eventq.addr)) + index;
}
/* See if an event is present
@@ -119,8 +119,8 @@ static inline efx_qword_t *efx_event(struct efx_channel *channel,
*/
static inline int efx_event_present(efx_qword_t *event)
{
- return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) |
- EFX_DWORD_IS_ALL_ONES(event->dword[1])));
+ return !(EFX_DWORD_IS_ALL_ONES(event->dword[0]) |
+ EFX_DWORD_IS_ALL_ONES(event->dword[1]));
}
static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b,
@@ -263,8 +263,8 @@ static int efx_alloc_special_buffer(struct efx_nic *efx,
{
len = ALIGN(len, EFX_BUF_SIZE);
- buffer->addr = pci_alloc_consistent(efx->pci_dev, len,
- &buffer->dma_addr);
+ buffer->addr = dma_alloc_coherent(&efx->pci_dev->dev, len,
+ &buffer->dma_addr, GFP_KERNEL);
if (!buffer->addr)
return -ENOMEM;
buffer->len = len;
@@ -301,8 +301,8 @@ efx_free_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer)
(u64)buffer->dma_addr, buffer->len,
buffer->addr, (u64)virt_to_phys(buffer->addr));
- pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr,
- buffer->dma_addr);
+ dma_free_coherent(&efx->pci_dev->dev, buffer->len, buffer->addr,
+ buffer->dma_addr);
buffer->addr = NULL;
buffer->entries = 0;
}
@@ -347,7 +347,7 @@ void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer)
static inline efx_qword_t *
efx_tx_desc(struct efx_tx_queue *tx_queue, unsigned int index)
{
- return (((efx_qword_t *) (tx_queue->txd.addr)) + index);
+ return ((efx_qword_t *) (tx_queue->txd.addr)) + index;
}
/* This writes to the TX_DESC_WPTR; write pointer for TX descriptor ring */
@@ -356,7 +356,7 @@ static inline void efx_notify_tx_desc(struct efx_tx_queue *tx_queue)
unsigned write_ptr;
efx_dword_t reg;
- write_ptr = tx_queue->write_count & EFX_TXQ_MASK;
+ write_ptr = tx_queue->write_count & tx_queue->ptr_mask;
EFX_POPULATE_DWORD_1(reg, FRF_AZ_TX_DESC_WPTR_DWORD, write_ptr);
efx_writed_page(tx_queue->efx, &reg,
FR_AZ_TX_DESC_UPD_DWORD_P0, tx_queue->queue);
@@ -377,7 +377,7 @@ void efx_nic_push_buffers(struct efx_tx_queue *tx_queue)
BUG_ON(tx_queue->write_count == tx_queue->insert_count);
do {
- write_ptr = tx_queue->write_count & EFX_TXQ_MASK;
+ write_ptr = tx_queue->write_count & tx_queue->ptr_mask;
buffer = &tx_queue->buffer[write_ptr];
txd = efx_tx_desc(tx_queue, write_ptr);
++tx_queue->write_count;
@@ -398,10 +398,11 @@ void efx_nic_push_buffers(struct efx_tx_queue *tx_queue)
int efx_nic_probe_tx(struct efx_tx_queue *tx_queue)
{
struct efx_nic *efx = tx_queue->efx;
- BUILD_BUG_ON(EFX_TXQ_SIZE < 512 || EFX_TXQ_SIZE > 4096 ||
- EFX_TXQ_SIZE & EFX_TXQ_MASK);
+ unsigned entries;
+
+ entries = tx_queue->ptr_mask + 1;
return efx_alloc_special_buffer(efx, &tx_queue->txd,
- EFX_TXQ_SIZE * sizeof(efx_qword_t));
+ entries * sizeof(efx_qword_t));
}
void efx_nic_init_tx(struct efx_tx_queue *tx_queue)
@@ -501,7 +502,7 @@ void efx_nic_remove_tx(struct efx_tx_queue *tx_queue)
static inline efx_qword_t *
efx_rx_desc(struct efx_rx_queue *rx_queue, unsigned int index)
{
- return (((efx_qword_t *) (rx_queue->rxd.addr)) + index);
+ return ((efx_qword_t *) (rx_queue->rxd.addr)) + index;
}
/* This creates an entry in the RX descriptor queue */
@@ -526,30 +527,32 @@ efx_build_rx_desc(struct efx_rx_queue *rx_queue, unsigned index)
*/
void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue)
{
+ struct efx_nic *efx = rx_queue->efx;
efx_dword_t reg;
unsigned write_ptr;
while (rx_queue->notified_count != rx_queue->added_count) {
- efx_build_rx_desc(rx_queue,
- rx_queue->notified_count &
- EFX_RXQ_MASK);
+ efx_build_rx_desc(
+ rx_queue,
+ rx_queue->notified_count & rx_queue->ptr_mask);
++rx_queue->notified_count;
}
wmb();
- write_ptr = rx_queue->added_count & EFX_RXQ_MASK;
+ write_ptr = rx_queue->added_count & rx_queue->ptr_mask;
EFX_POPULATE_DWORD_1(reg, FRF_AZ_RX_DESC_WPTR_DWORD, write_ptr);
- efx_writed_page(rx_queue->efx, &reg,
- FR_AZ_RX_DESC_UPD_DWORD_P0, rx_queue->queue);
+ efx_writed_page(efx, &reg, FR_AZ_RX_DESC_UPD_DWORD_P0,
+ efx_rx_queue_index(rx_queue));
}
int efx_nic_probe_rx(struct efx_rx_queue *rx_queue)
{
struct efx_nic *efx = rx_queue->efx;
- BUILD_BUG_ON(EFX_RXQ_SIZE < 512 || EFX_RXQ_SIZE > 4096 ||
- EFX_RXQ_SIZE & EFX_RXQ_MASK);
+ unsigned entries;
+
+ entries = rx_queue->ptr_mask + 1;
return efx_alloc_special_buffer(efx, &rx_queue->rxd,
- EFX_RXQ_SIZE * sizeof(efx_qword_t));
+ entries * sizeof(efx_qword_t));
}
void efx_nic_init_rx(struct efx_rx_queue *rx_queue)
@@ -561,7 +564,7 @@ void efx_nic_init_rx(struct efx_rx_queue *rx_queue)
netif_dbg(efx, hw, efx->net_dev,
"RX queue %d ring in special buffers %d-%d\n",
- rx_queue->queue, rx_queue->rxd.index,
+ efx_rx_queue_index(rx_queue), rx_queue->rxd.index,
rx_queue->rxd.index + rx_queue->rxd.entries - 1);
rx_queue->flushed = FLUSH_NONE;
@@ -575,9 +578,10 @@ void efx_nic_init_rx(struct efx_rx_queue *rx_queue)
FRF_AZ_RX_ISCSI_HDIG_EN, iscsi_digest_en,
FRF_AZ_RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index,
FRF_AZ_RX_DESCQ_EVQ_ID,
- rx_queue->channel->channel,
+ efx_rx_queue_channel(rx_queue)->channel,
FRF_AZ_RX_DESCQ_OWNER_ID, 0,
- FRF_AZ_RX_DESCQ_LABEL, rx_queue->queue,
+ FRF_AZ_RX_DESCQ_LABEL,
+ efx_rx_queue_index(rx_queue),
FRF_AZ_RX_DESCQ_SIZE,
__ffs(rx_queue->rxd.entries),
FRF_AZ_RX_DESCQ_TYPE, 0 /* kernel queue */ ,
@@ -585,7 +589,7 @@ void efx_nic_init_rx(struct efx_rx_queue *rx_queue)
FRF_AZ_RX_DESCQ_JUMBO, !is_b0,
FRF_AZ_RX_DESCQ_EN, 1);
efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
- rx_queue->queue);
+ efx_rx_queue_index(rx_queue));
}
static void efx_flush_rx_queue(struct efx_rx_queue *rx_queue)
@@ -598,7 +602,8 @@ static void efx_flush_rx_queue(struct efx_rx_queue *rx_queue)
/* Post a flush command */
EFX_POPULATE_OWORD_2(rx_flush_descq,
FRF_AZ_RX_FLUSH_DESCQ_CMD, 1,
- FRF_AZ_RX_FLUSH_DESCQ, rx_queue->queue);
+ FRF_AZ_RX_FLUSH_DESCQ,
+ efx_rx_queue_index(rx_queue));
efx_writeo(efx, &rx_flush_descq, FR_AZ_RX_FLUSH_DESCQ);
}
@@ -613,7 +618,7 @@ void efx_nic_fini_rx(struct efx_rx_queue *rx_queue)
/* Remove RX descriptor ring from card */
EFX_ZERO_OWORD(rx_desc_ptr);
efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
- rx_queue->queue);
+ efx_rx_queue_index(rx_queue));
/* Unpin RX descriptor ring */
efx_fini_special_buffer(efx, &rx_queue->rxd);
@@ -648,7 +653,7 @@ void efx_nic_eventq_read_ack(struct efx_channel *channel)
}
/* Use HW to insert a SW defined event */
-void efx_generate_event(struct efx_channel *channel, efx_qword_t *event)
+static void efx_generate_event(struct efx_channel *channel, efx_qword_t *event)
{
efx_oword_t drv_ev_reg;
@@ -680,15 +685,17 @@ efx_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
/* Transmit completion */
tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_DESC_PTR);
tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL);
- tx_queue = &efx->tx_queue[tx_ev_q_label];
+ tx_queue = efx_channel_get_tx_queue(
+ channel, tx_ev_q_label % EFX_TXQ_TYPES);
tx_packets = ((tx_ev_desc_ptr - tx_queue->read_count) &
- EFX_TXQ_MASK);
+ tx_queue->ptr_mask);
channel->irq_mod_score += tx_packets;
efx_xmit_done(tx_queue, tx_ev_desc_ptr);
} else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_WQ_FF_FULL)) {
/* Rewrite the FIFO write pointer */
tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL);
- tx_queue = &efx->tx_queue[tx_ev_q_label];
+ tx_queue = efx_channel_get_tx_queue(
+ channel, tx_ev_q_label % EFX_TXQ_TYPES);
if (efx_dev_registered(efx))
netif_tx_lock(efx->net_dev);
@@ -714,6 +721,7 @@ static void efx_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
bool *rx_ev_pkt_ok,
bool *discard)
{
+ struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
struct efx_nic *efx = rx_queue->efx;
bool rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err;
bool rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err;
@@ -746,14 +754,14 @@ static void efx_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
/* Count errors that are not in MAC stats. Ignore expected
* checksum errors during self-test. */
if (rx_ev_frm_trunc)
- ++rx_queue->channel->n_rx_frm_trunc;
+ ++channel->n_rx_frm_trunc;
else if (rx_ev_tobe_disc)
- ++rx_queue->channel->n_rx_tobe_disc;
+ ++channel->n_rx_tobe_disc;
else if (!efx->loopback_selftest) {
if (rx_ev_ip_hdr_chksum_err)
- ++rx_queue->channel->n_rx_ip_hdr_chksum_err;
+ ++channel->n_rx_ip_hdr_chksum_err;
else if (rx_ev_tcp_udp_chksum_err)
- ++rx_queue->channel->n_rx_tcp_udp_chksum_err;
+ ++channel->n_rx_tcp_udp_chksum_err;
}
/* The frame must be discarded if any of these are true. */
@@ -769,7 +777,7 @@ static void efx_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
netif_dbg(efx, rx_err, efx->net_dev,
" RX queue %d unexpected RX event "
EFX_QWORD_FMT "%s%s%s%s%s%s%s%s\n",
- rx_queue->queue, EFX_QWORD_VAL(*event),
+ efx_rx_queue_index(rx_queue), EFX_QWORD_VAL(*event),
rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "",
rx_ev_ip_hdr_chksum_err ?
" [IP_HDR_CHKSUM_ERR]" : "",
@@ -791,8 +799,8 @@ efx_handle_rx_bad_index(struct efx_rx_queue *rx_queue, unsigned index)
struct efx_nic *efx = rx_queue->efx;
unsigned expected, dropped;
- expected = rx_queue->removed_count & EFX_RXQ_MASK;
- dropped = (index - expected) & EFX_RXQ_MASK;
+ expected = rx_queue->removed_count & rx_queue->ptr_mask;
+ dropped = (index - expected) & rx_queue->ptr_mask;
netif_info(efx, rx_err, efx->net_dev,
"dropped %d events (index=%d expected=%d)\n",
dropped, index, expected);
@@ -827,10 +835,10 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_Q_LABEL) !=
channel->channel);
- rx_queue = &efx->rx_queue[channel->channel];
+ rx_queue = efx_channel_get_rx_queue(channel);
rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_DESC_PTR);
- expected_ptr = rx_queue->removed_count & EFX_RXQ_MASK;
+ expected_ptr = rx_queue->removed_count & rx_queue->ptr_mask;
if (unlikely(rx_ev_desc_ptr != expected_ptr))
efx_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr);
@@ -879,7 +887,7 @@ efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event)
/* The queue must be empty, so we won't receive any rx
* events, so efx_process_channel() won't refill the
* queue. Refill it here */
- efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]);
+ efx_fast_push_rx_descriptors(efx_channel_get_rx_queue(channel));
else
netif_dbg(efx, hw, efx->net_dev, "channel %d received "
"generated event "EFX_QWORD_FMT"\n",
@@ -997,6 +1005,7 @@ efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
int efx_nic_process_eventq(struct efx_channel *channel, int budget)
{
+ struct efx_nic *efx = channel->efx;
unsigned int read_ptr;
efx_qword_t event, *p_event;
int ev_code;
@@ -1021,7 +1030,7 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget)
EFX_SET_QWORD(*p_event);
/* Increment read pointer */
- read_ptr = (read_ptr + 1) & EFX_EVQ_MASK;
+ read_ptr = (read_ptr + 1) & channel->eventq_mask;
ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE);
@@ -1033,7 +1042,7 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget)
break;
case FSE_AZ_EV_CODE_TX_EV:
tx_packets += efx_handle_tx_event(channel, &event);
- if (tx_packets >= EFX_TXQ_SIZE) {
+ if (tx_packets > efx->txq_entries) {
spent = budget;
goto out;
}
@@ -1068,10 +1077,11 @@ out:
int efx_nic_probe_eventq(struct efx_channel *channel)
{
struct efx_nic *efx = channel->efx;
- BUILD_BUG_ON(EFX_EVQ_SIZE < 512 || EFX_EVQ_SIZE > 32768 ||
- EFX_EVQ_SIZE & EFX_EVQ_MASK);
+ unsigned entries;
+
+ entries = channel->eventq_mask + 1;
return efx_alloc_special_buffer(efx, &channel->eventq,
- EFX_EVQ_SIZE * sizeof(efx_qword_t));
+ entries * sizeof(efx_qword_t));
}
void efx_nic_init_eventq(struct efx_channel *channel)
@@ -1163,11 +1173,11 @@ void efx_nic_generate_fill_event(struct efx_channel *channel)
static void efx_poll_flush_events(struct efx_nic *efx)
{
- struct efx_channel *channel = &efx->channel[0];
+ struct efx_channel *channel = efx_get_channel(efx, 0);
struct efx_tx_queue *tx_queue;
struct efx_rx_queue *rx_queue;
unsigned int read_ptr = channel->eventq_read_ptr;
- unsigned int end_ptr = (read_ptr - 1) & EFX_EVQ_MASK;
+ unsigned int end_ptr = (read_ptr - 1) & channel->eventq_mask;
do {
efx_qword_t *event = efx_event(channel, read_ptr);
@@ -1185,7 +1195,9 @@ static void efx_poll_flush_events(struct efx_nic *efx)
ev_queue = EFX_QWORD_FIELD(*event,
FSF_AZ_DRIVER_EV_SUBDATA);
if (ev_queue < EFX_TXQ_TYPES * efx->n_tx_channels) {
- tx_queue = efx->tx_queue + ev_queue;
+ tx_queue = efx_get_tx_queue(
+ efx, ev_queue / EFX_TXQ_TYPES,
+ ev_queue % EFX_TXQ_TYPES);
tx_queue->flushed = FLUSH_DONE;
}
} else if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV &&
@@ -1195,7 +1207,7 @@ static void efx_poll_flush_events(struct efx_nic *efx)
ev_failed = EFX_QWORD_FIELD(
*event, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL);
if (ev_queue < efx->n_rx_channels) {
- rx_queue = efx->rx_queue + ev_queue;
+ rx_queue = efx_get_rx_queue(efx, ev_queue);
rx_queue->flushed =
ev_failed ? FLUSH_FAILED : FLUSH_DONE;
}
@@ -1205,7 +1217,7 @@ static void efx_poll_flush_events(struct efx_nic *efx)
* it's ok to throw away every non-flush event */
EFX_SET_QWORD(*event);
- read_ptr = (read_ptr + 1) & EFX_EVQ_MASK;
+ read_ptr = (read_ptr + 1) & channel->eventq_mask;
} while (read_ptr != end_ptr);
channel->eventq_read_ptr = read_ptr;
@@ -1216,6 +1228,7 @@ static void efx_poll_flush_events(struct efx_nic *efx)
* serialise them */
int efx_nic_flush_queues(struct efx_nic *efx)
{
+ struct efx_channel *channel;
struct efx_rx_queue *rx_queue;
struct efx_tx_queue *tx_queue;
int i, tx_pending, rx_pending;
@@ -1224,29 +1237,35 @@ int efx_nic_flush_queues(struct efx_nic *efx)
efx->type->prepare_flush(efx);
/* Flush all tx queues in parallel */
- efx_for_each_tx_queue(tx_queue, efx)
- efx_flush_tx_queue(tx_queue);
+ efx_for_each_channel(channel, efx) {
+ efx_for_each_channel_tx_queue(tx_queue, channel)
+ efx_flush_tx_queue(tx_queue);
+ }
/* The hardware supports four concurrent rx flushes, each of which may
* need to be retried if there is an outstanding descriptor fetch */
for (i = 0; i < EFX_FLUSH_POLL_COUNT; ++i) {
rx_pending = tx_pending = 0;
- efx_for_each_rx_queue(rx_queue, efx) {
- if (rx_queue->flushed == FLUSH_PENDING)
- ++rx_pending;
- }
- efx_for_each_rx_queue(rx_queue, efx) {
- if (rx_pending == EFX_RX_FLUSH_COUNT)
- break;
- if (rx_queue->flushed == FLUSH_FAILED ||
- rx_queue->flushed == FLUSH_NONE) {
- efx_flush_rx_queue(rx_queue);
- ++rx_pending;
+ efx_for_each_channel(channel, efx) {
+ efx_for_each_channel_rx_queue(rx_queue, channel) {
+ if (rx_queue->flushed == FLUSH_PENDING)
+ ++rx_pending;
}
}
- efx_for_each_tx_queue(tx_queue, efx) {
- if (tx_queue->flushed != FLUSH_DONE)
- ++tx_pending;
+ efx_for_each_channel(channel, efx) {
+ efx_for_each_channel_rx_queue(rx_queue, channel) {
+ if (rx_pending == EFX_RX_FLUSH_COUNT)
+ break;
+ if (rx_queue->flushed == FLUSH_FAILED ||
+ rx_queue->flushed == FLUSH_NONE) {
+ efx_flush_rx_queue(rx_queue);
+ ++rx_pending;
+ }
+ }
+ efx_for_each_channel_tx_queue(tx_queue, channel) {
+ if (tx_queue->flushed != FLUSH_DONE)
+ ++tx_pending;
+ }
}
if (rx_pending == 0 && tx_pending == 0)
@@ -1258,19 +1277,21 @@ int efx_nic_flush_queues(struct efx_nic *efx)
/* Mark the queues as all flushed. We're going to return failure
* leading to a reset, or fake up success anyway */
- efx_for_each_tx_queue(tx_queue, efx) {
- if (tx_queue->flushed != FLUSH_DONE)
- netif_err(efx, hw, efx->net_dev,
- "tx queue %d flush command timed out\n",
- tx_queue->queue);
- tx_queue->flushed = FLUSH_DONE;
- }
- efx_for_each_rx_queue(rx_queue, efx) {
- if (rx_queue->flushed != FLUSH_DONE)
- netif_err(efx, hw, efx->net_dev,
- "rx queue %d flush command timed out\n",
- rx_queue->queue);
- rx_queue->flushed = FLUSH_DONE;
+ efx_for_each_channel(channel, efx) {
+ efx_for_each_channel_tx_queue(tx_queue, channel) {
+ if (tx_queue->flushed != FLUSH_DONE)
+ netif_err(efx, hw, efx->net_dev,
+ "tx queue %d flush command timed out\n",
+ tx_queue->queue);
+ tx_queue->flushed = FLUSH_DONE;
+ }
+ efx_for_each_channel_rx_queue(rx_queue, channel) {
+ if (rx_queue->flushed != FLUSH_DONE)
+ netif_err(efx, hw, efx->net_dev,
+ "rx queue %d flush command timed out\n",
+ efx_rx_queue_index(rx_queue));
+ rx_queue->flushed = FLUSH_DONE;
+ }
}
return -ETIMEDOUT;
@@ -1457,7 +1478,7 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id)
*/
static irqreturn_t efx_msi_interrupt(int irq, void *dev_id)
{
- struct efx_channel *channel = dev_id;
+ struct efx_channel *channel = *(struct efx_channel **)dev_id;
struct efx_nic *efx = channel->efx;
efx_oword_t *int_ker = efx->irq_status.addr;
int syserr;
@@ -1532,7 +1553,8 @@ int efx_nic_init_interrupt(struct efx_nic *efx)
efx_for_each_channel(channel, efx) {
rc = request_irq(channel->irq, efx_msi_interrupt,
IRQF_PROBE_SHARED, /* Not shared */
- channel->name, channel);
+ efx->channel_name[channel->channel],
+ &efx->channel[channel->channel]);
if (rc) {
netif_err(efx, drv, efx->net_dev,
"failed to hook IRQ %d\n", channel->irq);
@@ -1544,7 +1566,7 @@ int efx_nic_init_interrupt(struct efx_nic *efx)
fail2:
efx_for_each_channel(channel, efx)
- free_irq(channel->irq, channel);
+ free_irq(channel->irq, &efx->channel[channel->channel]);
fail1:
return rc;
}
@@ -1557,7 +1579,7 @@ void efx_nic_fini_interrupt(struct efx_nic *efx)
/* Disable MSI/MSI-X interrupts */
efx_for_each_channel(channel, efx) {
if (channel->irq)
- free_irq(channel->irq, channel);
+ free_irq(channel->irq, &efx->channel[channel->channel]);
}
/* ACK legacy interrupt */
@@ -1827,8 +1849,7 @@ static const struct efx_nic_reg_table efx_nic_reg_tables[] = {
REGISTER_TABLE_BB_CZ(TX_DESC_PTR_TBL),
REGISTER_TABLE_AA(EVQ_PTR_TBL_KER),
REGISTER_TABLE_BB_CZ(EVQ_PTR_TBL),
- /* The register buffer is allocated with slab, so we can't
- * reasonably read all of the buffer table (up to 8MB!).
+ /* We can't reasonably read all of the buffer table (up to 8MB!).
* However this driver will only use a few entries. Reading
* 1K entries allows for some expansion of queue count and
* size before we need to change the version. */
@@ -1836,7 +1857,6 @@ static const struct efx_nic_reg_table efx_nic_reg_tables[] = {
A, A, 8, 1024),
REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL, FR_BZ_BUF_FULL_TBL,
B, Z, 8, 1024),
- /* RX_FILTER_TBL{0,1} is huge and not used by this driver */
REGISTER_TABLE_CZ(RX_MAC_FILTER_TBL0),
REGISTER_TABLE_BB_CZ(TIMER_TBL),
REGISTER_TABLE_BB_CZ(TX_PACE_TBL),
@@ -1846,6 +1866,7 @@ static const struct efx_nic_reg_table efx_nic_reg_tables[] = {
REGISTER_TABLE_CZ(MC_TREG_SMEM),
/* MSIX_PBA_TABLE is not mapped */
/* SRM_DBG is not mapped (and is redundant with BUF_FLL_TBL) */
+ REGISTER_TABLE_BZ(RX_FILTER_TBL0),
};
size_t efx_nic_get_regs_len(struct efx_nic *efx)
diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h
index 5bc26137257b..1dab609757fb 100644
--- a/drivers/net/sfc/phy.h
+++ b/drivers/net/sfc/phy.h
@@ -11,17 +11,12 @@
#define EFX_PHY_H
/****************************************************************************
- * 10Xpress (SFX7101 and SFT9001) PHYs
+ * 10Xpress (SFX7101) PHY
*/
extern struct efx_phy_operations falcon_sfx7101_phy_ops;
-extern struct efx_phy_operations falcon_sft9001_phy_ops;
extern void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
-/* Wait for the PHY to boot. Return 0 on success, -EINVAL if the PHY failed
- * to boot due to corrupt flash, or some other negative error code. */
-extern int sft9001_wait_boot(struct efx_nic *efx);
-
/****************************************************************************
* AMCC/Quake QT202x PHYs
*/
@@ -42,6 +37,17 @@ extern struct efx_phy_operations falcon_qt202x_phy_ops;
extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state);
/****************************************************************************
+* Transwitch CX4 retimer
+*/
+extern struct efx_phy_operations falcon_txc_phy_ops;
+
+#define TXC_GPIO_DIR_INPUT 0
+#define TXC_GPIO_DIR_OUTPUT 1
+
+extern void falcon_txc_set_gpio_dir(struct efx_nic *efx, int pin, int dir);
+extern void falcon_txc_set_gpio_val(struct efx_nic *efx, int pin, int val);
+
+/****************************************************************************
* Siena managed PHYs
*/
extern struct efx_phy_operations efx_mcdi_phy_ops;
diff --git a/drivers/net/sfc/regs.h b/drivers/net/sfc/regs.h
index 18a3be428348..96430ed81c36 100644
--- a/drivers/net/sfc/regs.h
+++ b/drivers/net/sfc/regs.h
@@ -2893,6 +2893,20 @@
#define FRF_AB_XX_FORCE_SIG_WIDTH 8
#define FFE_AB_XX_FORCE_SIG_ALL_LANES 0xff
+/* RX_MAC_FILTER_TBL0 */
+/* RMFT_DEST_MAC is wider than 32 bits */
+#define FRF_CZ_RMFT_DEST_MAC_LO_LBN 12
+#define FRF_CZ_RMFT_DEST_MAC_LO_WIDTH 32
+#define FRF_CZ_RMFT_DEST_MAC_HI_LBN 44
+#define FRF_CZ_RMFT_DEST_MAC_HI_WIDTH 16
+
+/* TX_MAC_FILTER_TBL0 */
+/* TMFT_SRC_MAC is wider than 32 bits */
+#define FRF_CZ_TMFT_SRC_MAC_LO_LBN 12
+#define FRF_CZ_TMFT_SRC_MAC_LO_WIDTH 32
+#define FRF_CZ_TMFT_SRC_MAC_HI_LBN 44
+#define FRF_CZ_TMFT_SRC_MAC_HI_WIDTH 16
+
/* DRIVER_EV */
/* Sub-fields of an RX flush completion event */
#define FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL_LBN 12
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index 799c461ce7b8..6d0959b5158e 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -133,7 +133,7 @@ static int efx_init_rx_buffers_skb(struct efx_rx_queue *rx_queue)
unsigned index, count;
for (count = 0; count < EFX_RX_BATCH; ++count) {
- index = rx_queue->added_count & EFX_RXQ_MASK;
+ index = rx_queue->added_count & rx_queue->ptr_mask;
rx_buf = efx_rx_buffer(rx_queue, index);
rx_buf->skb = netdev_alloc_skb(net_dev, skb_len);
@@ -208,7 +208,7 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
dma_addr += sizeof(struct efx_rx_page_state);
split:
- index = rx_queue->added_count & EFX_RXQ_MASK;
+ index = rx_queue->added_count & rx_queue->ptr_mask;
rx_buf = efx_rx_buffer(rx_queue, index);
rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN;
rx_buf->skb = NULL;
@@ -285,7 +285,7 @@ static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue,
* we'd like to insert an additional descriptor whilst leaving
* EFX_RXD_HEAD_ROOM for the non-recycle path */
fill_level = (rx_queue->added_count - rx_queue->removed_count + 2);
- if (unlikely(fill_level >= EFX_RXQ_SIZE - EFX_RXD_HEAD_ROOM)) {
+ if (unlikely(fill_level > rx_queue->max_fill)) {
/* We could place "state" on a list, and drain the list in
* efx_fast_push_rx_descriptors(). For now, this will do. */
return;
@@ -294,7 +294,7 @@ static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue,
++state->refcnt;
get_page(rx_buf->page);
- index = rx_queue->added_count & EFX_RXQ_MASK;
+ index = rx_queue->added_count & rx_queue->ptr_mask;
new_buf = efx_rx_buffer(rx_queue, index);
new_buf->dma_addr = rx_buf->dma_addr ^ (PAGE_SIZE >> 1);
new_buf->skb = NULL;
@@ -311,7 +311,7 @@ static void efx_recycle_rx_buffer(struct efx_channel *channel,
struct efx_rx_buffer *rx_buf)
{
struct efx_nic *efx = channel->efx;
- struct efx_rx_queue *rx_queue = &efx->rx_queue[channel->channel];
+ struct efx_rx_queue *rx_queue = efx_channel_get_rx_queue(channel);
struct efx_rx_buffer *new_buf;
unsigned index;
@@ -319,7 +319,7 @@ static void efx_recycle_rx_buffer(struct efx_channel *channel,
page_count(rx_buf->page) == 1)
efx_resurrect_rx_buffer(rx_queue, rx_buf);
- index = rx_queue->added_count & EFX_RXQ_MASK;
+ index = rx_queue->added_count & rx_queue->ptr_mask;
new_buf = efx_rx_buffer(rx_queue, index);
memcpy(new_buf, rx_buf, sizeof(*new_buf));
@@ -341,13 +341,13 @@ static void efx_recycle_rx_buffer(struct efx_channel *channel,
*/
void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
{
- struct efx_channel *channel = rx_queue->channel;
+ struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
unsigned fill_level;
int space, rc = 0;
/* Calculate current fill level, and exit if we don't need to fill */
fill_level = (rx_queue->added_count - rx_queue->removed_count);
- EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE);
+ EFX_BUG_ON_PARANOID(fill_level > rx_queue->efx->rxq_entries);
if (fill_level >= rx_queue->fast_fill_trigger)
goto out;
@@ -364,7 +364,8 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
netif_vdbg(rx_queue->efx, rx_status, rx_queue->efx->net_dev,
"RX queue %d fast-filling descriptor ring from"
" level %d to level %d using %s allocation\n",
- rx_queue->queue, fill_level, rx_queue->fast_fill_limit,
+ efx_rx_queue_index(rx_queue), fill_level,
+ rx_queue->fast_fill_limit,
channel->rx_alloc_push_pages ? "page" : "skb");
do {
@@ -382,7 +383,7 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
netif_vdbg(rx_queue->efx, rx_status, rx_queue->efx->net_dev,
"RX queue %d fast-filled descriptor ring "
- "to level %d\n", rx_queue->queue,
+ "to level %d\n", efx_rx_queue_index(rx_queue),
rx_queue->added_count - rx_queue->removed_count);
out:
@@ -393,7 +394,7 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
void efx_rx_slow_fill(unsigned long context)
{
struct efx_rx_queue *rx_queue = (struct efx_rx_queue *)context;
- struct efx_channel *channel = rx_queue->channel;
+ struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
/* Post an event to cause NAPI to run and refill the queue */
efx_nic_generate_fill_event(channel);
@@ -421,7 +422,7 @@ static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
netif_err(efx, rx_err, efx->net_dev,
" RX queue %d seriously overlength "
"RX event (0x%x > 0x%x+0x%x). Leaking\n",
- rx_queue->queue, len, max_len,
+ efx_rx_queue_index(rx_queue), len, max_len,
efx->type->rx_buffer_padding);
/* If this buffer was skb-allocated, then the meta
* data at the end of the skb will be trashed. So
@@ -434,10 +435,10 @@ static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
netif_err(efx, rx_err, efx->net_dev,
" RX queue %d overlength RX event "
"(0x%x > 0x%x)\n",
- rx_queue->queue, len, max_len);
+ efx_rx_queue_index(rx_queue), len, max_len);
}
- rx_queue->channel->n_rx_overlength++;
+ efx_rx_queue_channel(rx_queue)->n_rx_overlength++;
}
/* Pass a received packet up through the generic LRO stack
@@ -507,7 +508,7 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
unsigned int len, bool checksummed, bool discard)
{
struct efx_nic *efx = rx_queue->efx;
- struct efx_channel *channel = rx_queue->channel;
+ struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
struct efx_rx_buffer *rx_buf;
bool leak_packet = false;
@@ -528,7 +529,7 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
netif_vdbg(efx, rx_status, efx->net_dev,
"RX queue %d received id %x at %llx+%x %s%s\n",
- rx_queue->queue, index,
+ efx_rx_queue_index(rx_queue), index,
(unsigned long long)rx_buf->dma_addr, len,
(checksummed ? " [SUMMED]" : ""),
(discard ? " [DISCARD]" : ""));
@@ -560,12 +561,11 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
*/
rx_buf->len = len;
out:
- if (rx_queue->channel->rx_pkt)
- __efx_rx_packet(rx_queue->channel,
- rx_queue->channel->rx_pkt,
- rx_queue->channel->rx_pkt_csummed);
- rx_queue->channel->rx_pkt = rx_buf;
- rx_queue->channel->rx_pkt_csummed = checksummed;
+ if (channel->rx_pkt)
+ __efx_rx_packet(channel,
+ channel->rx_pkt, channel->rx_pkt_csummed);
+ channel->rx_pkt = rx_buf;
+ channel->rx_pkt_csummed = checksummed;
}
/* Handle a received packet. Second half: Touches packet payload. */
@@ -615,7 +615,7 @@ void __efx_rx_packet(struct efx_channel *channel,
EFX_BUG_ON_PARANOID(!skb);
/* Set the SKB flags */
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
/* Pass the packet up */
netif_receive_skb(skb);
@@ -650,15 +650,22 @@ void efx_rx_strategy(struct efx_channel *channel)
int efx_probe_rx_queue(struct efx_rx_queue *rx_queue)
{
struct efx_nic *efx = rx_queue->efx;
- unsigned int rxq_size;
+ unsigned int entries;
int rc;
+ /* Create the smallest power-of-two aligned ring */
+ entries = max(roundup_pow_of_two(efx->rxq_entries), EFX_MIN_DMAQ_SIZE);
+ EFX_BUG_ON_PARANOID(entries > EFX_MAX_DMAQ_SIZE);
+ rx_queue->ptr_mask = entries - 1;
+
netif_dbg(efx, probe, efx->net_dev,
- "creating RX queue %d\n", rx_queue->queue);
+ "creating RX queue %d size %#x mask %#x\n",
+ efx_rx_queue_index(rx_queue), efx->rxq_entries,
+ rx_queue->ptr_mask);
/* Allocate RX buffers */
- rxq_size = EFX_RXQ_SIZE * sizeof(*rx_queue->buffer);
- rx_queue->buffer = kzalloc(rxq_size, GFP_KERNEL);
+ rx_queue->buffer = kzalloc(entries * sizeof(*rx_queue->buffer),
+ GFP_KERNEL);
if (!rx_queue->buffer)
return -ENOMEM;
@@ -672,20 +679,20 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue)
void efx_init_rx_queue(struct efx_rx_queue *rx_queue)
{
+ struct efx_nic *efx = rx_queue->efx;
unsigned int max_fill, trigger, limit;
netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev,
- "initialising RX queue %d\n", rx_queue->queue);
+ "initialising RX queue %d\n", efx_rx_queue_index(rx_queue));
/* Initialise ptr fields */
rx_queue->added_count = 0;
rx_queue->notified_count = 0;
rx_queue->removed_count = 0;
rx_queue->min_fill = -1U;
- rx_queue->min_overfill = -1U;
/* Initialise limit fields */
- max_fill = EFX_RXQ_SIZE - EFX_RXD_HEAD_ROOM;
+ max_fill = efx->rxq_entries - EFX_RXD_HEAD_ROOM;
trigger = max_fill * min(rx_refill_threshold, 100U) / 100U;
limit = max_fill * min(rx_refill_limit, 100U) / 100U;
@@ -703,14 +710,14 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
struct efx_rx_buffer *rx_buf;
netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev,
- "shutting down RX queue %d\n", rx_queue->queue);
+ "shutting down RX queue %d\n", efx_rx_queue_index(rx_queue));
del_timer_sync(&rx_queue->slow_fill);
efx_nic_fini_rx(rx_queue);
/* Release RX buffers NB start at index 0 not current HW ptr */
if (rx_queue->buffer) {
- for (i = 0; i <= EFX_RXQ_MASK; i++) {
+ for (i = 0; i <= rx_queue->ptr_mask; i++) {
rx_buf = efx_rx_buffer(rx_queue, i);
efx_fini_rx_buffer(rx_queue, rx_buf);
}
@@ -720,7 +727,7 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)
{
netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev,
- "destroying RX queue %d\n", rx_queue->queue);
+ "destroying RX queue %d\n", efx_rx_queue_index(rx_queue));
efx_nic_remove_rx(rx_queue);
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 85f015f005d5..0ebfb99f1299 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -48,6 +48,16 @@ static const unsigned char payload_source[ETH_ALEN] = {
static const char payload_msg[] =
"Hello world! This is an Efx loopback test in progress!";
+/* Interrupt mode names */
+static const unsigned int efx_interrupt_mode_max = EFX_INT_MODE_MAX;
+static const char *efx_interrupt_mode_names[] = {
+ [EFX_INT_MODE_MSIX] = "MSI-X",
+ [EFX_INT_MODE_MSI] = "MSI",
+ [EFX_INT_MODE_LEGACY] = "legacy",
+};
+#define INT_MODE(efx) \
+ STRING_TABLE_LOOKUP(efx->interrupt_mode, efx_interrupt_mode)
+
/**
* efx_loopback_state - persistent state during a loopback selftest
* @flush: Drop all packets in efx_loopback_rx_packet
@@ -506,7 +516,7 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
for (i = 0; i < 3; i++) {
/* Determine how many packets to send */
- state->packet_count = EFX_TXQ_SIZE / 3;
+ state->packet_count = efx->txq_entries / 3;
state->packet_count = min(1 << (i << 2), state->packet_count);
state->skbs = kzalloc(sizeof(state->skbs[0]) *
state->packet_count, GFP_KERNEL);
@@ -567,7 +577,7 @@ static int efx_wait_for_link(struct efx_nic *efx)
efx->type->monitor(efx);
mutex_unlock(&efx->mac_lock);
} else {
- struct efx_channel *channel = &efx->channel[0];
+ struct efx_channel *channel = efx_get_channel(efx, 0);
if (channel->work_pending)
efx_process_channel_now(channel);
}
@@ -594,6 +604,7 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
{
enum efx_loopback_mode mode;
struct efx_loopback_state *state;
+ struct efx_channel *channel = efx_get_channel(efx, 0);
struct efx_tx_queue *tx_queue;
int rc = 0;
@@ -634,7 +645,7 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
}
/* Test both types of TX queue */
- efx_for_each_channel_tx_queue(tx_queue, &efx->channel[0]) {
+ efx_for_each_channel_tx_queue(tx_queue, channel) {
state->offload_csum = (tx_queue->queue &
EFX_TXQ_TYPE_OFFLOAD);
rc = efx_test_loopback(tx_queue,
diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
index 3fab030f8ab5..45236f58a258 100644
--- a/drivers/net/sfc/siena.c
+++ b/drivers/net/sfc/siena.c
@@ -129,7 +129,7 @@ static int siena_probe_port(struct efx_nic *efx)
return 0;
}
-void siena_remove_port(struct efx_nic *efx)
+static void siena_remove_port(struct efx_nic *efx)
{
efx->phy_op->remove(efx);
efx_nic_free_buffer(efx, &efx->stats_buffer);
@@ -450,7 +450,7 @@ static int siena_try_update_nic_stats(struct efx_nic *efx)
mac_stats->rx_bad_bytes);
MAC_STAT(rx_packets, RX_PKTS);
MAC_STAT(rx_good, RX_GOOD_PKTS);
- mac_stats->rx_bad = mac_stats->rx_packets - mac_stats->rx_good;
+ MAC_STAT(rx_bad, RX_BAD_FCS_PKTS);
MAC_STAT(rx_pause, RX_PAUSE_PKTS);
MAC_STAT(rx_control, RX_CONTROL_PKTS);
MAC_STAT(rx_unicast, RX_UNICAST_PKTS);
@@ -651,6 +651,6 @@ struct efx_nic_type siena_a0_nic_type = {
.tx_dc_base = 0x88000,
.rx_dc_base = 0x68000,
.offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_RXHASH),
+ NETIF_F_RXHASH | NETIF_F_NTUPLE),
.reset_world_flags = ETH_RESET_MGMT << ETH_RESET_SHARED_SHIFT,
};
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index 6791be90c2fe..1bc6c48c96ee 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -19,10 +19,7 @@
#include "workarounds.h"
#include "selftest.h"
-/* We expect these MMDs to be in the package. SFT9001 also has a
- * clause 22 extension MMD, but since it doesn't have all the generic
- * MMD registers it is pointless to include it here.
- */
+/* We expect these MMDs to be in the package. */
#define TENXPRESS_REQUIRED_DEVS (MDIO_DEVS_PMAPMD | \
MDIO_DEVS_PCS | \
MDIO_DEVS_PHYXS | \
@@ -33,12 +30,6 @@
(1 << LOOPBACK_PMAPMD) | \
(1 << LOOPBACK_PHYXS_WS))
-#define SFT9001_LOOPBACKS ((1 << LOOPBACK_GPHY) | \
- (1 << LOOPBACK_PHYXS) | \
- (1 << LOOPBACK_PCS) | \
- (1 << LOOPBACK_PMAPMD) | \
- (1 << LOOPBACK_PHYXS_WS))
-
/* We complain if we fail to see the link partner as 10G capable this many
* times in a row (must be > 1 as sampling the autoneg. registers is racy)
*/
@@ -50,9 +41,8 @@
#define PMA_PMD_EXT_GMII_EN_WIDTH 1
#define PMA_PMD_EXT_CLK_OUT_LBN 2
#define PMA_PMD_EXT_CLK_OUT_WIDTH 1
-#define PMA_PMD_LNPGA_POWERDOWN_LBN 8 /* SFX7101 only */
+#define PMA_PMD_LNPGA_POWERDOWN_LBN 8
#define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1
-#define PMA_PMD_EXT_CLK312_LBN 8 /* SFT9001 only */
#define PMA_PMD_EXT_CLK312_WIDTH 1
#define PMA_PMD_EXT_LPOWER_LBN 12
#define PMA_PMD_EXT_LPOWER_WIDTH 1
@@ -84,7 +74,6 @@
#define PMA_PMD_LED_FLASH (3)
#define PMA_PMD_LED_MASK 3
/* All LEDs under hardware control */
-#define SFT9001_PMA_PMD_LED_DEFAULT 0
/* Green and Amber under hardware control, Red off */
#define SFX7101_PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN)
@@ -98,31 +87,7 @@
#define PMA_PMD_SPEED_LBN 4
#define PMA_PMD_SPEED_WIDTH 4
-/* Cable diagnostics - SFT9001 only */
-#define PMA_PMD_CDIAG_CTRL_REG 49213
-#define CDIAG_CTRL_IMMED_LBN 15
-#define CDIAG_CTRL_BRK_LINK_LBN 12
-#define CDIAG_CTRL_IN_PROG_LBN 11
-#define CDIAG_CTRL_LEN_UNIT_LBN 10
-#define CDIAG_CTRL_LEN_METRES 1
-#define PMA_PMD_CDIAG_RES_REG 49174
-#define CDIAG_RES_A_LBN 12
-#define CDIAG_RES_B_LBN 8
-#define CDIAG_RES_C_LBN 4
-#define CDIAG_RES_D_LBN 0
-#define CDIAG_RES_WIDTH 4
-#define CDIAG_RES_OPEN 2
-#define CDIAG_RES_OK 1
-#define CDIAG_RES_INVALID 0
-/* Set of 4 registers for pairs A-D */
-#define PMA_PMD_CDIAG_LEN_REG 49175
-
-/* Serdes control registers - SFT9001 only */
-#define PMA_PMD_CSERDES_CTRL_REG 64258
-/* Set the 156.25 MHz output to 312.5 MHz to drive Falcon's XMAC */
-#define PMA_PMD_CSERDES_DEFAULT 0x000f
-
-/* Misc register defines - SFX7101 only */
+/* Misc register defines */
#define PCS_CLOCK_CTRL_REG 55297
#define PLL312_RST_N_LBN 2
@@ -185,121 +150,17 @@ struct tenxpress_phy_data {
int bad_lp_tries;
};
-static ssize_t show_phy_short_reach(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
- int reg;
-
- reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR);
- return sprintf(buf, "%d\n", !!(reg & MDIO_PMA_10GBT_TXPWR_SHORT));
-}
-
-static ssize_t set_phy_short_reach(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
- int rc;
-
- rtnl_lock();
- if (efx->state != STATE_RUNNING) {
- rc = -EBUSY;
- } else {
- efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR,
- MDIO_PMA_10GBT_TXPWR_SHORT,
- count != 0 && *buf != '0');
- rc = efx_reconfigure_port(efx);
- }
- rtnl_unlock();
-
- return rc < 0 ? rc : (ssize_t)count;
-}
-
-static DEVICE_ATTR(phy_short_reach, 0644, show_phy_short_reach,
- set_phy_short_reach);
-
-int sft9001_wait_boot(struct efx_nic *efx)
-{
- unsigned long timeout = jiffies + HZ + 1;
- int boot_stat;
-
- for (;;) {
- boot_stat = efx_mdio_read(efx, MDIO_MMD_PCS,
- PCS_BOOT_STATUS_REG);
- if (boot_stat >= 0) {
- netif_dbg(efx, hw, efx->net_dev,
- "PHY boot status = %#x\n", boot_stat);
- switch (boot_stat &
- ((1 << PCS_BOOT_FATAL_ERROR_LBN) |
- (3 << PCS_BOOT_PROGRESS_LBN) |
- (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN) |
- (1 << PCS_BOOT_CODE_STARTED_LBN))) {
- case ((1 << PCS_BOOT_FATAL_ERROR_LBN) |
- (PCS_BOOT_PROGRESS_CHECKSUM <<
- PCS_BOOT_PROGRESS_LBN)):
- case ((1 << PCS_BOOT_FATAL_ERROR_LBN) |
- (PCS_BOOT_PROGRESS_INIT <<
- PCS_BOOT_PROGRESS_LBN) |
- (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN)):
- return -EINVAL;
- case ((PCS_BOOT_PROGRESS_WAIT_MDIO <<
- PCS_BOOT_PROGRESS_LBN) |
- (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN)):
- return (efx->phy_mode & PHY_MODE_SPECIAL) ?
- 0 : -EIO;
- case ((PCS_BOOT_PROGRESS_JUMP <<
- PCS_BOOT_PROGRESS_LBN) |
- (1 << PCS_BOOT_CODE_STARTED_LBN)):
- case ((PCS_BOOT_PROGRESS_JUMP <<
- PCS_BOOT_PROGRESS_LBN) |
- (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN) |
- (1 << PCS_BOOT_CODE_STARTED_LBN)):
- return (efx->phy_mode & PHY_MODE_SPECIAL) ?
- -EIO : 0;
- default:
- if (boot_stat & (1 << PCS_BOOT_FATAL_ERROR_LBN))
- return -EIO;
- break;
- }
- }
-
- if (time_after_eq(jiffies, timeout))
- return -ETIMEDOUT;
-
- msleep(50);
- }
-}
-
static int tenxpress_init(struct efx_nic *efx)
{
- int reg;
-
- if (efx->phy_type == PHY_TYPE_SFX7101) {
- /* Enable 312.5 MHz clock */
- efx_mdio_write(efx, MDIO_MMD_PCS, PCS_TEST_SELECT_REG,
- 1 << CLK312_EN_LBN);
- } else {
- /* Enable 312.5 MHz clock and GMII */
- reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
- reg |= ((1 << PMA_PMD_EXT_GMII_EN_LBN) |
- (1 << PMA_PMD_EXT_CLK_OUT_LBN) |
- (1 << PMA_PMD_EXT_CLK312_LBN) |
- (1 << PMA_PMD_EXT_ROBUST_LBN));
-
- efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
- efx_mdio_set_flag(efx, MDIO_MMD_C22EXT,
- GPHY_XCONTROL_REG, 1 << GPHY_ISOLATE_LBN,
- false);
- }
+ /* Enable 312.5 MHz clock */
+ efx_mdio_write(efx, MDIO_MMD_PCS, PCS_TEST_SELECT_REG,
+ 1 << CLK312_EN_LBN);
/* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */
- if (efx->phy_type == PHY_TYPE_SFX7101) {
- efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG,
- 1 << PMA_PMA_LED_ACTIVITY_LBN, true);
- efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG,
- SFX7101_PMA_PMD_LED_DEFAULT);
- }
+ efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG,
+ 1 << PMA_PMA_LED_ACTIVITY_LBN, true);
+ efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG,
+ SFX7101_PMA_PMD_LED_DEFAULT);
return 0;
}
@@ -307,7 +168,6 @@ static int tenxpress_init(struct efx_nic *efx)
static int tenxpress_phy_probe(struct efx_nic *efx)
{
struct tenxpress_phy_data *phy_data;
- int rc;
/* Allocate phy private storage */
phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
@@ -316,42 +176,15 @@ static int tenxpress_phy_probe(struct efx_nic *efx)
efx->phy_data = phy_data;
phy_data->phy_mode = efx->phy_mode;
- /* Create any special files */
- if (efx->phy_type == PHY_TYPE_SFT9001B) {
- rc = device_create_file(&efx->pci_dev->dev,
- &dev_attr_phy_short_reach);
- if (rc)
- goto fail;
- }
-
- if (efx->phy_type == PHY_TYPE_SFX7101) {
- efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;
- efx->mdio.mode_support = MDIO_SUPPORTS_C45;
-
- efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS;
+ efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;
+ efx->mdio.mode_support = MDIO_SUPPORTS_C45;
- efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg |
- ADVERTISED_10000baseT_Full);
- } else {
- efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;
- efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+ efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS;
- efx->loopback_modes = (SFT9001_LOOPBACKS |
- FALCON_XMAC_LOOPBACKS |
- FALCON_GMAC_LOOPBACKS);
-
- efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg |
- ADVERTISED_10000baseT_Full |
- ADVERTISED_1000baseT_Full |
- ADVERTISED_100baseT_Full);
- }
+ efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg |
+ ADVERTISED_10000baseT_Full);
return 0;
-
-fail:
- kfree(efx->phy_data);
- efx->phy_data = NULL;
- return rc;
}
static int tenxpress_phy_init(struct efx_nic *efx)
@@ -361,16 +194,6 @@ static int tenxpress_phy_init(struct efx_nic *efx)
falcon_board(efx)->type->init_phy(efx);
if (!(efx->phy_mode & PHY_MODE_SPECIAL)) {
- if (efx->phy_type == PHY_TYPE_SFT9001A) {
- int reg;
- reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
- PMA_PMD_XCONTROL_REG);
- reg |= (1 << PMA_PMD_EXT_SSR_LBN);
- efx_mdio_write(efx, MDIO_MMD_PMAPMD,
- PMA_PMD_XCONTROL_REG, reg);
- mdelay(200);
- }
-
rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);
if (rc < 0)
return rc;
@@ -403,7 +226,7 @@ static int tenxpress_special_reset(struct efx_nic *efx)
{
int rc, reg;
- /* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so
+ /* The XGMAC clock is driven from the SFX7101 312MHz clock, so
* a special software reset can glitch the XGMAC sufficiently for stats
* requests to fail. */
falcon_stop_nic_stats(efx);
@@ -484,53 +307,18 @@ static bool sfx7101_link_ok(struct efx_nic *efx)
MDIO_DEVS_PHYXS);
}
-static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd)
-{
- u32 reg;
-
- if (efx_phy_mode_disabled(efx->phy_mode))
- return false;
- else if (efx->loopback_mode == LOOPBACK_GPHY)
- return true;
- else if (efx->loopback_mode)
- return efx_mdio_links_ok(efx,
- MDIO_DEVS_PMAPMD |
- MDIO_DEVS_PHYXS);
-
- /* We must use the same definition of link state as LASI,
- * otherwise we can miss a link state transition
- */
- if (ecmd->speed == 10000) {
- reg = efx_mdio_read(efx, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1);
- return reg & MDIO_PCS_10GBRT_STAT1_BLKLK;
- } else {
- reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_STATUS_REG);
- return reg & (1 << C22EXT_STATUS_LINK_LBN);
- }
-}
-
static void tenxpress_ext_loopback(struct efx_nic *efx)
{
efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, PHYXS_TEST1,
1 << LOOPBACK_NEAR_LBN,
efx->loopback_mode == LOOPBACK_PHYXS);
- if (efx->phy_type != PHY_TYPE_SFX7101)
- efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, GPHY_XCONTROL_REG,
- 1 << GPHY_LOOPBACK_NEAR_LBN,
- efx->loopback_mode == LOOPBACK_GPHY);
}
static void tenxpress_low_power(struct efx_nic *efx)
{
- if (efx->phy_type == PHY_TYPE_SFX7101)
- efx_mdio_set_mmds_lpower(
- efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER),
- TENXPRESS_REQUIRED_DEVS);
- else
- efx_mdio_set_flag(
- efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG,
- 1 << PMA_PMD_EXT_LPOWER_LBN,
- !!(efx->phy_mode & PHY_MODE_LOW_POWER));
+ efx_mdio_set_mmds_lpower(
+ efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER),
+ TENXPRESS_REQUIRED_DEVS);
}
static int tenxpress_phy_reconfigure(struct efx_nic *efx)
@@ -550,12 +338,7 @@ static int tenxpress_phy_reconfigure(struct efx_nic *efx)
if (loop_reset || phy_mode_change) {
tenxpress_special_reset(efx);
-
- /* Reset XAUI if we were in 10G, and are staying
- * in 10G. If we're moving into and out of 10G
- * then xaui will be reset anyway */
- if (EFX_IS10G(efx))
- falcon_reset_xaui(efx);
+ falcon_reset_xaui(efx);
}
tenxpress_low_power(efx);
@@ -578,29 +361,12 @@ static bool tenxpress_phy_poll(struct efx_nic *efx)
{
struct efx_link_state old_state = efx->link_state;
- if (efx->phy_type == PHY_TYPE_SFX7101) {
- efx->link_state.up = sfx7101_link_ok(efx);
- efx->link_state.speed = 10000;
- efx->link_state.fd = true;
- efx->link_state.fc = efx_mdio_get_pause(efx);
-
- sfx7101_check_bad_lp(efx, efx->link_state.up);
- } else {
- struct ethtool_cmd ecmd;
-
- /* Check the LASI alarm first */
- if (efx->loopback_mode == LOOPBACK_NONE &&
- !(efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT) &
- MDIO_PMA_LASI_LSALARM))
- return false;
+ efx->link_state.up = sfx7101_link_ok(efx);
+ efx->link_state.speed = 10000;
+ efx->link_state.fd = true;
+ efx->link_state.fc = efx_mdio_get_pause(efx);
- tenxpress_get_settings(efx, &ecmd);
-
- efx->link_state.up = sft9001_link_ok(efx, &ecmd);
- efx->link_state.speed = ecmd.speed;
- efx->link_state.fd = (ecmd.duplex == DUPLEX_FULL);
- efx->link_state.fc = efx_mdio_get_pause(efx);
- }
+ sfx7101_check_bad_lp(efx, efx->link_state.up);
return !efx_link_state_equal(&efx->link_state, &old_state);
}
@@ -621,10 +387,6 @@ static void sfx7101_phy_fini(struct efx_nic *efx)
static void tenxpress_phy_remove(struct efx_nic *efx)
{
- if (efx->phy_type == PHY_TYPE_SFT9001B)
- device_remove_file(&efx->pci_dev->dev,
- &dev_attr_phy_short_reach);
-
kfree(efx->phy_data);
efx->phy_data = NULL;
}
@@ -647,10 +409,7 @@ void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
(PMA_PMD_LED_ON << PMA_PMD_LED_LINK_LBN);
break;
default:
- if (efx->phy_type == PHY_TYPE_SFX7101)
- reg = SFX7101_PMA_PMD_LED_DEFAULT;
- else
- reg = SFT9001_PMA_PMD_LED_DEFAULT;
+ reg = SFX7101_PMA_PMD_LED_DEFAULT;
break;
}
@@ -685,102 +444,12 @@ sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags)
return rc;
}
-static const char *const sft9001_test_names[] = {
- "bist",
- "cable.pairA.status",
- "cable.pairB.status",
- "cable.pairC.status",
- "cable.pairD.status",
- "cable.pairA.length",
- "cable.pairB.length",
- "cable.pairC.length",
- "cable.pairD.length",
-};
-
-static const char *sft9001_test_name(struct efx_nic *efx, unsigned int index)
-{
- if (index < ARRAY_SIZE(sft9001_test_names))
- return sft9001_test_names[index];
- return NULL;
-}
-
-static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
-{
- int rc = 0, rc2, i, ctrl_reg, res_reg;
-
- /* Initialise cable diagnostic results to unknown failure */
- for (i = 1; i < 9; ++i)
- results[i] = -1;
-
- /* Run cable diagnostics; wait up to 5 seconds for them to complete.
- * A cable fault is not a self-test failure, but a timeout is. */
- ctrl_reg = ((1 << CDIAG_CTRL_IMMED_LBN) |
- (CDIAG_CTRL_LEN_METRES << CDIAG_CTRL_LEN_UNIT_LBN));
- if (flags & ETH_TEST_FL_OFFLINE) {
- /* Break the link in order to run full diagnostics. We
- * must reset the PHY to resume normal service. */
- ctrl_reg |= (1 << CDIAG_CTRL_BRK_LINK_LBN);
- }
- efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG,
- ctrl_reg);
- i = 0;
- while (efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG) &
- (1 << CDIAG_CTRL_IN_PROG_LBN)) {
- if (++i == 50) {
- rc = -ETIMEDOUT;
- goto out;
- }
- msleep(100);
- }
- res_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_RES_REG);
- for (i = 0; i < 4; i++) {
- int pair_res =
- (res_reg >> (CDIAG_RES_A_LBN - i * CDIAG_RES_WIDTH))
- & ((1 << CDIAG_RES_WIDTH) - 1);
- int len_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
- PMA_PMD_CDIAG_LEN_REG + i);
- if (pair_res == CDIAG_RES_OK)
- results[1 + i] = 1;
- else if (pair_res == CDIAG_RES_INVALID)
- results[1 + i] = -1;
- else
- results[1 + i] = -pair_res;
- if (pair_res != CDIAG_RES_INVALID &&
- pair_res != CDIAG_RES_OPEN &&
- len_reg != 0xffff)
- results[5 + i] = len_reg;
- }
-
-out:
- if (flags & ETH_TEST_FL_OFFLINE) {
- /* Reset, running the BIST and then resuming normal service. */
- rc2 = tenxpress_special_reset(efx);
- results[0] = rc2 ? -1 : 1;
- if (!rc)
- rc = rc2;
-
- efx_mdio_an_reconfigure(efx);
- }
-
- return rc;
-}
-
static void
tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{
u32 adv = 0, lpa = 0;
int reg;
- if (efx->phy_type != PHY_TYPE_SFX7101) {
- reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL);
- if (reg & (1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN))
- adv |= ADVERTISED_1000baseT_Full;
- reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_STATUS);
- if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN))
- lpa |= ADVERTISED_1000baseT_Half;
- if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN))
- lpa |= ADVERTISED_1000baseT_Full;
- }
reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL);
if (reg & MDIO_AN_10GBT_CTRL_ADV10G)
adv |= ADVERTISED_10000baseT_Full;
@@ -790,23 +459,9 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa);
- if (efx->phy_type != PHY_TYPE_SFX7101) {
- ecmd->supported |= (SUPPORTED_100baseT_Full |
- SUPPORTED_1000baseT_Full);
- if (ecmd->speed != SPEED_10000) {
- ecmd->eth_tp_mdix =
- (efx_mdio_read(efx, MDIO_MMD_PMAPMD,
- PMA_PMD_XSTATUS_REG) &
- (1 << PMA_PMD_XSTAT_MDIX_LBN))
- ? ETH_TP_MDI_X : ETH_TP_MDI;
- }
- }
-
/* In loopback, the PHY automatically brings up the correct interface,
* but doesn't advertise the correct speed. So override it */
- if (efx->loopback_mode == LOOPBACK_GPHY)
- ecmd->speed = SPEED_1000;
- else if (LOOPBACK_EXTERNAL(efx))
+ if (LOOPBACK_EXTERNAL(efx))
ecmd->speed = SPEED_10000;
}
@@ -825,16 +480,6 @@ static void sfx7101_set_npage_adv(struct efx_nic *efx, u32 advertising)
advertising & ADVERTISED_10000baseT_Full);
}
-static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising)
-{
- efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL,
- 1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN,
- advertising & ADVERTISED_1000baseT_Full);
- efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
- MDIO_AN_10GBT_CTRL_ADV10G,
- advertising & ADVERTISED_10000baseT_Full);
-}
-
struct efx_phy_operations falcon_sfx7101_phy_ops = {
.probe = tenxpress_phy_probe,
.init = tenxpress_phy_init,
@@ -849,18 +494,3 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = {
.test_name = sfx7101_test_name,
.run_tests = sfx7101_run_tests,
};
-
-struct efx_phy_operations falcon_sft9001_phy_ops = {
- .probe = tenxpress_phy_probe,
- .init = tenxpress_phy_init,
- .reconfigure = tenxpress_phy_reconfigure,
- .poll = tenxpress_phy_poll,
- .fini = efx_port_dummy_op_void,
- .remove = tenxpress_phy_remove,
- .get_settings = tenxpress_get_settings,
- .set_settings = tenxpress_set_settings,
- .set_npage_adv = sft9001_set_npage_adv,
- .test_alive = efx_mdio_test_alive,
- .test_name = sft9001_test_name,
- .run_tests = sft9001_run_tests,
-};
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
index c6942da2c99a..11726989fe2d 100644
--- a/drivers/net/sfc/tx.c
+++ b/drivers/net/sfc/tx.c
@@ -28,7 +28,7 @@
* The tx_queue descriptor ring fill-level must fall below this value
* before we restart the netif queue
*/
-#define EFX_TXQ_THRESHOLD (EFX_TXQ_MASK / 2u)
+#define EFX_TXQ_THRESHOLD(_efx) ((_efx)->txq_entries / 2u)
/* We need to be able to nest calls to netif_tx_stop_queue(), partly
* because of the 2 hardware queues associated with each core queue,
@@ -37,8 +37,9 @@
void efx_stop_queue(struct efx_channel *channel)
{
struct efx_nic *efx = channel->efx;
+ struct efx_tx_queue *tx_queue = efx_channel_get_tx_queue(channel, 0);
- if (!channel->tx_queue)
+ if (!tx_queue)
return;
spin_lock_bh(&channel->tx_stop_lock);
@@ -46,9 +47,8 @@ void efx_stop_queue(struct efx_channel *channel)
atomic_inc(&channel->tx_stop_count);
netif_tx_stop_queue(
- netdev_get_tx_queue(
- efx->net_dev,
- channel->tx_queue->queue / EFX_TXQ_TYPES));
+ netdev_get_tx_queue(efx->net_dev,
+ tx_queue->queue / EFX_TXQ_TYPES));
spin_unlock_bh(&channel->tx_stop_lock);
}
@@ -57,8 +57,9 @@ void efx_stop_queue(struct efx_channel *channel)
void efx_wake_queue(struct efx_channel *channel)
{
struct efx_nic *efx = channel->efx;
+ struct efx_tx_queue *tx_queue = efx_channel_get_tx_queue(channel, 0);
- if (!channel->tx_queue)
+ if (!tx_queue)
return;
local_bh_disable();
@@ -66,9 +67,8 @@ void efx_wake_queue(struct efx_channel *channel)
&channel->tx_stop_lock)) {
netif_vdbg(efx, tx_queued, efx->net_dev, "waking TX queue\n");
netif_tx_wake_queue(
- netdev_get_tx_queue(
- efx->net_dev,
- channel->tx_queue->queue / EFX_TXQ_TYPES));
+ netdev_get_tx_queue(efx->net_dev,
+ tx_queue->queue / EFX_TXQ_TYPES));
spin_unlock(&channel->tx_stop_lock);
}
local_bh_enable();
@@ -207,7 +207,7 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
}
fill_level = tx_queue->insert_count - tx_queue->old_read_count;
- q_space = EFX_TXQ_MASK - 1 - fill_level;
+ q_space = efx->txq_entries - 1 - fill_level;
/* Map for DMA. Use pci_map_single rather than pci_map_page
* since this is more efficient on machines with sparse
@@ -244,14 +244,14 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
&tx_queue->read_count;
fill_level = (tx_queue->insert_count
- tx_queue->old_read_count);
- q_space = EFX_TXQ_MASK - 1 - fill_level;
+ q_space = efx->txq_entries - 1 - fill_level;
if (unlikely(q_space-- <= 0))
goto stop;
smp_mb();
--tx_queue->stopped;
}
- insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK;
+ insert_ptr = tx_queue->insert_count & tx_queue->ptr_mask;
buffer = &tx_queue->buffer[insert_ptr];
efx_tsoh_free(tx_queue, buffer);
EFX_BUG_ON_PARANOID(buffer->tsoh);
@@ -320,7 +320,7 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
/* Work backwards until we hit the original insert pointer value */
while (tx_queue->insert_count != tx_queue->write_count) {
--tx_queue->insert_count;
- insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK;
+ insert_ptr = tx_queue->insert_count & tx_queue->ptr_mask;
buffer = &tx_queue->buffer[insert_ptr];
efx_dequeue_buffer(tx_queue, buffer);
buffer->len = 0;
@@ -350,8 +350,8 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
struct efx_nic *efx = tx_queue->efx;
unsigned int stop_index, read_ptr;
- stop_index = (index + 1) & EFX_TXQ_MASK;
- read_ptr = tx_queue->read_count & EFX_TXQ_MASK;
+ stop_index = (index + 1) & tx_queue->ptr_mask;
+ read_ptr = tx_queue->read_count & tx_queue->ptr_mask;
while (read_ptr != stop_index) {
struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr];
@@ -368,7 +368,7 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
buffer->len = 0;
++tx_queue->read_count;
- read_ptr = tx_queue->read_count & EFX_TXQ_MASK;
+ read_ptr = tx_queue->read_count & tx_queue->ptr_mask;
}
}
@@ -390,9 +390,9 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb,
if (unlikely(efx->port_inhibited))
return NETDEV_TX_BUSY;
- tx_queue = &efx->tx_queue[EFX_TXQ_TYPES * skb_get_queue_mapping(skb)];
- if (likely(skb->ip_summed == CHECKSUM_PARTIAL))
- tx_queue += EFX_TXQ_TYPE_OFFLOAD;
+ tx_queue = efx_get_tx_queue(efx, skb_get_queue_mapping(skb),
+ skb->ip_summed == CHECKSUM_PARTIAL ?
+ EFX_TXQ_TYPE_OFFLOAD : 0);
return efx_enqueue_skb(tx_queue, skb);
}
@@ -402,7 +402,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
unsigned fill_level;
struct efx_nic *efx = tx_queue->efx;
- EFX_BUG_ON_PARANOID(index > EFX_TXQ_MASK);
+ EFX_BUG_ON_PARANOID(index > tx_queue->ptr_mask);
efx_dequeue_buffers(tx_queue, index);
@@ -412,7 +412,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
smp_mb();
if (unlikely(tx_queue->stopped) && likely(efx->port_enabled)) {
fill_level = tx_queue->insert_count - tx_queue->read_count;
- if (fill_level < EFX_TXQ_THRESHOLD) {
+ if (fill_level < EFX_TXQ_THRESHOLD(efx)) {
EFX_BUG_ON_PARANOID(!efx_dev_registered(efx));
/* Do this under netif_tx_lock(), to avoid racing
@@ -430,18 +430,24 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
int efx_probe_tx_queue(struct efx_tx_queue *tx_queue)
{
struct efx_nic *efx = tx_queue->efx;
- unsigned int txq_size;
+ unsigned int entries;
int i, rc;
- netif_dbg(efx, probe, efx->net_dev, "creating TX queue %d\n",
- tx_queue->queue);
+ /* Create the smallest power-of-two aligned ring */
+ entries = max(roundup_pow_of_two(efx->txq_entries), EFX_MIN_DMAQ_SIZE);
+ EFX_BUG_ON_PARANOID(entries > EFX_MAX_DMAQ_SIZE);
+ tx_queue->ptr_mask = entries - 1;
+
+ netif_dbg(efx, probe, efx->net_dev,
+ "creating TX queue %d size %#x mask %#x\n",
+ tx_queue->queue, efx->txq_entries, tx_queue->ptr_mask);
/* Allocate software ring */
- txq_size = EFX_TXQ_SIZE * sizeof(*tx_queue->buffer);
- tx_queue->buffer = kzalloc(txq_size, GFP_KERNEL);
+ tx_queue->buffer = kzalloc(entries * sizeof(*tx_queue->buffer),
+ GFP_KERNEL);
if (!tx_queue->buffer)
return -ENOMEM;
- for (i = 0; i <= EFX_TXQ_MASK; ++i)
+ for (i = 0; i <= tx_queue->ptr_mask; ++i)
tx_queue->buffer[i].continuation = true;
/* Allocate hardware ring */
@@ -481,7 +487,7 @@ void efx_release_tx_buffers(struct efx_tx_queue *tx_queue)
/* Free any buffers left in the ring */
while (tx_queue->read_count != tx_queue->write_count) {
- buffer = &tx_queue->buffer[tx_queue->read_count & EFX_TXQ_MASK];
+ buffer = &tx_queue->buffer[tx_queue->read_count & tx_queue->ptr_mask];
efx_dequeue_buffer(tx_queue, buffer);
buffer->continuation = true;
buffer->len = 0;
@@ -741,7 +747,7 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue,
fill_level = tx_queue->insert_count - tx_queue->old_read_count;
/* -1 as there is no way to represent all descriptors used */
- q_space = EFX_TXQ_MASK - 1 - fill_level;
+ q_space = efx->txq_entries - 1 - fill_level;
while (1) {
if (unlikely(q_space-- <= 0)) {
@@ -757,7 +763,7 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue,
*(volatile unsigned *)&tx_queue->read_count;
fill_level = (tx_queue->insert_count
- tx_queue->old_read_count);
- q_space = EFX_TXQ_MASK - 1 - fill_level;
+ q_space = efx->txq_entries - 1 - fill_level;
if (unlikely(q_space-- <= 0)) {
*final_buffer = NULL;
return 1;
@@ -766,13 +772,13 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue,
--tx_queue->stopped;
}
- insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK;
+ insert_ptr = tx_queue->insert_count & tx_queue->ptr_mask;
buffer = &tx_queue->buffer[insert_ptr];
++tx_queue->insert_count;
EFX_BUG_ON_PARANOID(tx_queue->insert_count -
- tx_queue->read_count >
- EFX_TXQ_MASK);
+ tx_queue->read_count >=
+ efx->txq_entries);
efx_tsoh_free(tx_queue, buffer);
EFX_BUG_ON_PARANOID(buffer->len);
@@ -813,7 +819,7 @@ static void efx_tso_put_header(struct efx_tx_queue *tx_queue,
{
struct efx_tx_buffer *buffer;
- buffer = &tx_queue->buffer[tx_queue->insert_count & EFX_TXQ_MASK];
+ buffer = &tx_queue->buffer[tx_queue->insert_count & tx_queue->ptr_mask];
efx_tsoh_free(tx_queue, buffer);
EFX_BUG_ON_PARANOID(buffer->len);
EFX_BUG_ON_PARANOID(buffer->unmap_len);
@@ -838,7 +844,7 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue)
while (tx_queue->insert_count != tx_queue->write_count) {
--tx_queue->insert_count;
buffer = &tx_queue->buffer[tx_queue->insert_count &
- EFX_TXQ_MASK];
+ tx_queue->ptr_mask];
efx_tsoh_free(tx_queue, buffer);
EFX_BUG_ON_PARANOID(buffer->skb);
if (buffer->unmap_len) {
@@ -1168,7 +1174,7 @@ static void efx_fini_tso(struct efx_tx_queue *tx_queue)
unsigned i;
if (tx_queue->buffer) {
- for (i = 0; i <= EFX_TXQ_MASK; ++i)
+ for (i = 0; i <= tx_queue->ptr_mask; ++i)
efx_tsoh_free(tx_queue, &tx_queue->buffer[i]);
}
diff --git a/drivers/net/sfc/txc43128_phy.c b/drivers/net/sfc/txc43128_phy.c
new file mode 100644
index 000000000000..351794a79215
--- /dev/null
+++ b/drivers/net/sfc/txc43128_phy.c
@@ -0,0 +1,560 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006-2010 Solarflare Communications 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, incorporated herein by reference.
+ */
+
+/*
+ * Driver for Transwitch/Mysticom CX4 retimer
+ * see www.transwitch.com, part is TXC-43128
+ */
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include "efx.h"
+#include "mdio_10g.h"
+#include "phy.h"
+#include "nic.h"
+
+/* We expect these MMDs to be in the package */
+#define TXC_REQUIRED_DEVS (MDIO_DEVS_PCS | \
+ MDIO_DEVS_PMAPMD | \
+ MDIO_DEVS_PHYXS)
+
+#define TXC_LOOPBACKS ((1 << LOOPBACK_PCS) | \
+ (1 << LOOPBACK_PMAPMD) | \
+ (1 << LOOPBACK_PHYXS_WS))
+
+/**************************************************************************
+ *
+ * Compile-time config
+ *
+ **************************************************************************
+ */
+#define TXCNAME "TXC43128"
+/* Total length of time we'll wait for the PHY to come out of reset (ms) */
+#define TXC_MAX_RESET_TIME 500
+/* Interval between checks (ms) */
+#define TXC_RESET_WAIT 10
+/* How long to run BIST (us) */
+#define TXC_BIST_DURATION 50
+
+/**************************************************************************
+ *
+ * Register definitions
+ *
+ **************************************************************************
+ */
+
+/* Command register */
+#define TXC_GLRGS_GLCMD 0xc004
+/* Useful bits in command register */
+/* Lane power-down */
+#define TXC_GLCMD_L01PD_LBN 5
+#define TXC_GLCMD_L23PD_LBN 6
+/* Limited SW reset: preserves configuration but
+ * initiates a logic reset. Self-clearing */
+#define TXC_GLCMD_LMTSWRST_LBN 14
+
+/* Signal Quality Control */
+#define TXC_GLRGS_GSGQLCTL 0xc01a
+/* Enable bit */
+#define TXC_GSGQLCT_SGQLEN_LBN 15
+/* Lane selection */
+#define TXC_GSGQLCT_LNSL_LBN 13
+#define TXC_GSGQLCT_LNSL_WIDTH 2
+
+/* Analog TX control */
+#define TXC_ALRGS_ATXCTL 0xc040
+/* Lane power-down */
+#define TXC_ATXCTL_TXPD3_LBN 15
+#define TXC_ATXCTL_TXPD2_LBN 14
+#define TXC_ATXCTL_TXPD1_LBN 13
+#define TXC_ATXCTL_TXPD0_LBN 12
+
+/* Amplitude on lanes 0, 1 */
+#define TXC_ALRGS_ATXAMP0 0xc041
+/* Amplitude on lanes 2, 3 */
+#define TXC_ALRGS_ATXAMP1 0xc042
+/* Bit position of value for lane 0 (or 2) */
+#define TXC_ATXAMP_LANE02_LBN 3
+/* Bit position of value for lane 1 (or 3) */
+#define TXC_ATXAMP_LANE13_LBN 11
+
+#define TXC_ATXAMP_1280_mV 0
+#define TXC_ATXAMP_1200_mV 8
+#define TXC_ATXAMP_1120_mV 12
+#define TXC_ATXAMP_1060_mV 14
+#define TXC_ATXAMP_0820_mV 25
+#define TXC_ATXAMP_0720_mV 26
+#define TXC_ATXAMP_0580_mV 27
+#define TXC_ATXAMP_0440_mV 28
+
+#define TXC_ATXAMP_0820_BOTH \
+ ((TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE02_LBN) \
+ | (TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE13_LBN))
+
+#define TXC_ATXAMP_DEFAULT 0x6060 /* From databook */
+
+/* Preemphasis on lanes 0, 1 */
+#define TXC_ALRGS_ATXPRE0 0xc043
+/* Preemphasis on lanes 2, 3 */
+#define TXC_ALRGS_ATXPRE1 0xc044
+
+#define TXC_ATXPRE_NONE 0
+#define TXC_ATXPRE_DEFAULT 0x1010 /* From databook */
+
+#define TXC_ALRGS_ARXCTL 0xc045
+/* Lane power-down */
+#define TXC_ARXCTL_RXPD3_LBN 15
+#define TXC_ARXCTL_RXPD2_LBN 14
+#define TXC_ARXCTL_RXPD1_LBN 13
+#define TXC_ARXCTL_RXPD0_LBN 12
+
+/* Main control */
+#define TXC_MRGS_CTL 0xc340
+/* Bits in main control */
+#define TXC_MCTL_RESET_LBN 15 /* Self clear */
+#define TXC_MCTL_TXLED_LBN 14 /* 1 to show align status */
+#define TXC_MCTL_RXLED_LBN 13 /* 1 to show align status */
+
+/* GPIO output */
+#define TXC_GPIO_OUTPUT 0xc346
+#define TXC_GPIO_DIR 0xc348
+
+/* Vendor-specific BIST registers */
+#define TXC_BIST_CTL 0xc280
+#define TXC_BIST_TXFRMCNT 0xc281
+#define TXC_BIST_RX0FRMCNT 0xc282
+#define TXC_BIST_RX1FRMCNT 0xc283
+#define TXC_BIST_RX2FRMCNT 0xc284
+#define TXC_BIST_RX3FRMCNT 0xc285
+#define TXC_BIST_RX0ERRCNT 0xc286
+#define TXC_BIST_RX1ERRCNT 0xc287
+#define TXC_BIST_RX2ERRCNT 0xc288
+#define TXC_BIST_RX3ERRCNT 0xc289
+
+/* BIST type (controls bit patter in test) */
+#define TXC_BIST_CTRL_TYPE_LBN 10
+#define TXC_BIST_CTRL_TYPE_TSD 0 /* TranSwitch Deterministic */
+#define TXC_BIST_CTRL_TYPE_CRP 1 /* CRPAT standard */
+#define TXC_BIST_CTRL_TYPE_CJP 2 /* CJPAT standard */
+#define TXC_BIST_CTRL_TYPE_TSR 3 /* TranSwitch pseudo-random */
+/* Set this to 1 for 10 bit and 0 for 8 bit */
+#define TXC_BIST_CTRL_B10EN_LBN 12
+/* Enable BIST (write 0 to disable) */
+#define TXC_BIST_CTRL_ENAB_LBN 13
+/* Stop BIST (self-clears when stop complete) */
+#define TXC_BIST_CTRL_STOP_LBN 14
+/* Start BIST (cleared by writing 1 to STOP) */
+#define TXC_BIST_CTRL_STRT_LBN 15
+
+/* Mt. Diablo test configuration */
+#define TXC_MTDIABLO_CTRL 0xc34f
+#define TXC_MTDIABLO_CTRL_PMA_LOOP_LBN 10
+
+struct txc43128_data {
+ unsigned long bug10934_timer;
+ enum efx_phy_mode phy_mode;
+ enum efx_loopback_mode loopback_mode;
+};
+
+/* The PHY sometimes needs a reset to bring the link back up. So long as
+ * it reports link down, we reset it every 5 seconds.
+ */
+#define BUG10934_RESET_INTERVAL (5 * HZ)
+
+/* Perform a reset that doesn't clear configuration changes */
+static void txc_reset_logic(struct efx_nic *efx);
+
+/* Set the output value of a gpio */
+void falcon_txc_set_gpio_val(struct efx_nic *efx, int pin, int on)
+{
+ efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, TXC_GPIO_OUTPUT, 1 << pin, on);
+}
+
+/* Set up the GPIO direction register */
+void falcon_txc_set_gpio_dir(struct efx_nic *efx, int pin, int dir)
+{
+ efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, TXC_GPIO_DIR, 1 << pin, dir);
+}
+
+/* Reset the PMA/PMD MMD. The documentation is explicit that this does a
+ * global reset (it's less clear what reset of other MMDs does).*/
+static int txc_reset_phy(struct efx_nic *efx)
+{
+ int rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PMAPMD,
+ TXC_MAX_RESET_TIME / TXC_RESET_WAIT,
+ TXC_RESET_WAIT);
+ if (rc < 0)
+ goto fail;
+
+ /* Check that all the MMDs we expect are present and responding. */
+ rc = efx_mdio_check_mmds(efx, TXC_REQUIRED_DEVS, 0);
+ if (rc < 0)
+ goto fail;
+
+ return 0;
+
+fail:
+ netif_err(efx, hw, efx->net_dev, TXCNAME ": reset timed out!\n");
+ return rc;
+}
+
+/* Run a single BIST on one MMD */
+static int txc_bist_one(struct efx_nic *efx, int mmd, int test)
+{
+ int ctrl, bctl;
+ int lane;
+ int rc = 0;
+
+ /* Set PMA to test into loopback using Mt Diablo reg as per app note */
+ ctrl = efx_mdio_read(efx, MDIO_MMD_PCS, TXC_MTDIABLO_CTRL);
+ ctrl |= (1 << TXC_MTDIABLO_CTRL_PMA_LOOP_LBN);
+ efx_mdio_write(efx, MDIO_MMD_PCS, TXC_MTDIABLO_CTRL, ctrl);
+
+ /* The BIST app. note lists these as 3 distinct steps. */
+ /* Set the BIST type */
+ bctl = (test << TXC_BIST_CTRL_TYPE_LBN);
+ efx_mdio_write(efx, mmd, TXC_BIST_CTL, bctl);
+
+ /* Set the BSTEN bit in the BIST Control register to enable */
+ bctl |= (1 << TXC_BIST_CTRL_ENAB_LBN);
+ efx_mdio_write(efx, mmd, TXC_BIST_CTL, bctl);
+
+ /* Set the BSTRT bit in the BIST Control register */
+ efx_mdio_write(efx, mmd, TXC_BIST_CTL,
+ bctl | (1 << TXC_BIST_CTRL_STRT_LBN));
+
+ /* Wait. */
+ udelay(TXC_BIST_DURATION);
+
+ /* Set the BSTOP bit in the BIST Control register */
+ bctl |= (1 << TXC_BIST_CTRL_STOP_LBN);
+ efx_mdio_write(efx, mmd, TXC_BIST_CTL, bctl);
+
+ /* The STOP bit should go off when things have stopped */
+ while (bctl & (1 << TXC_BIST_CTRL_STOP_LBN))
+ bctl = efx_mdio_read(efx, mmd, TXC_BIST_CTL);
+
+ /* Check all the error counts are 0 and all the frame counts are
+ non-zero */
+ for (lane = 0; lane < 4; lane++) {
+ int count = efx_mdio_read(efx, mmd, TXC_BIST_RX0ERRCNT + lane);
+ if (count != 0) {
+ netif_err(efx, hw, efx->net_dev, TXCNAME": BIST error. "
+ "Lane %d had %d errs\n", lane, count);
+ rc = -EIO;
+ }
+ count = efx_mdio_read(efx, mmd, TXC_BIST_RX0FRMCNT + lane);
+ if (count == 0) {
+ netif_err(efx, hw, efx->net_dev, TXCNAME": BIST error. "
+ "Lane %d got 0 frames\n", lane);
+ rc = -EIO;
+ }
+ }
+
+ if (rc == 0)
+ netif_info(efx, hw, efx->net_dev, TXCNAME": BIST pass\n");
+
+ /* Disable BIST */
+ efx_mdio_write(efx, mmd, TXC_BIST_CTL, 0);
+
+ /* Turn off loopback */
+ ctrl &= ~(1 << TXC_MTDIABLO_CTRL_PMA_LOOP_LBN);
+ efx_mdio_write(efx, MDIO_MMD_PCS, TXC_MTDIABLO_CTRL, ctrl);
+
+ return rc;
+}
+
+static int txc_bist(struct efx_nic *efx)
+{
+ return txc_bist_one(efx, MDIO_MMD_PCS, TXC_BIST_CTRL_TYPE_TSD);
+}
+
+/* Push the non-configurable defaults into the PHY. This must be
+ * done after every full reset */
+static void txc_apply_defaults(struct efx_nic *efx)
+{
+ int mctrl;
+
+ /* Turn amplitude down and preemphasis off on the host side
+ * (PHY<->MAC) as this is believed less likely to upset Falcon
+ * and no adverse effects have been noted. It probably also
+ * saves a picowatt or two */
+
+ /* Turn off preemphasis */
+ efx_mdio_write(efx, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE0, TXC_ATXPRE_NONE);
+ efx_mdio_write(efx, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE1, TXC_ATXPRE_NONE);
+
+ /* Turn down the amplitude */
+ efx_mdio_write(efx, MDIO_MMD_PHYXS,
+ TXC_ALRGS_ATXAMP0, TXC_ATXAMP_0820_BOTH);
+ efx_mdio_write(efx, MDIO_MMD_PHYXS,
+ TXC_ALRGS_ATXAMP1, TXC_ATXAMP_0820_BOTH);
+
+ /* Set the line side amplitude and preemphasis to the databook
+ * defaults as an erratum causes them to be 0 on at least some
+ * PHY rev.s */
+ efx_mdio_write(efx, MDIO_MMD_PMAPMD,
+ TXC_ALRGS_ATXPRE0, TXC_ATXPRE_DEFAULT);
+ efx_mdio_write(efx, MDIO_MMD_PMAPMD,
+ TXC_ALRGS_ATXPRE1, TXC_ATXPRE_DEFAULT);
+ efx_mdio_write(efx, MDIO_MMD_PMAPMD,
+ TXC_ALRGS_ATXAMP0, TXC_ATXAMP_DEFAULT);
+ efx_mdio_write(efx, MDIO_MMD_PMAPMD,
+ TXC_ALRGS_ATXAMP1, TXC_ATXAMP_DEFAULT);
+
+ /* Set up the LEDs */
+ mctrl = efx_mdio_read(efx, MDIO_MMD_PHYXS, TXC_MRGS_CTL);
+
+ /* Set the Green and Red LEDs to their default modes */
+ mctrl &= ~((1 << TXC_MCTL_TXLED_LBN) | (1 << TXC_MCTL_RXLED_LBN));
+ efx_mdio_write(efx, MDIO_MMD_PHYXS, TXC_MRGS_CTL, mctrl);
+
+ /* Databook recommends doing this after configuration changes */
+ txc_reset_logic(efx);
+
+ falcon_board(efx)->type->init_phy(efx);
+}
+
+static int txc43128_phy_probe(struct efx_nic *efx)
+{
+ struct txc43128_data *phy_data;
+
+ /* Allocate phy private storage */
+ phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
+ if (!phy_data)
+ return -ENOMEM;
+ efx->phy_data = phy_data;
+ phy_data->phy_mode = efx->phy_mode;
+
+ efx->mdio.mmds = TXC_REQUIRED_DEVS;
+ efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+
+ efx->loopback_modes = TXC_LOOPBACKS | FALCON_XMAC_LOOPBACKS;
+
+ return 0;
+}
+
+/* Initialisation entry point for this PHY driver */
+static int txc43128_phy_init(struct efx_nic *efx)
+{
+ int rc;
+
+ rc = txc_reset_phy(efx);
+ if (rc < 0)
+ return rc;
+
+ rc = txc_bist(efx);
+ if (rc < 0)
+ return rc;
+
+ txc_apply_defaults(efx);
+
+ return 0;
+}
+
+/* Set the lane power down state in the global registers */
+static void txc_glrgs_lane_power(struct efx_nic *efx, int mmd)
+{
+ int pd = (1 << TXC_GLCMD_L01PD_LBN) | (1 << TXC_GLCMD_L23PD_LBN);
+ int ctl = efx_mdio_read(efx, mmd, TXC_GLRGS_GLCMD);
+
+ if (!(efx->phy_mode & PHY_MODE_LOW_POWER))
+ ctl &= ~pd;
+ else
+ ctl |= pd;
+
+ efx_mdio_write(efx, mmd, TXC_GLRGS_GLCMD, ctl);
+}
+
+/* Set the lane power down state in the analog control registers */
+static void txc_analog_lane_power(struct efx_nic *efx, int mmd)
+{
+ int txpd = (1 << TXC_ATXCTL_TXPD3_LBN) | (1 << TXC_ATXCTL_TXPD2_LBN)
+ | (1 << TXC_ATXCTL_TXPD1_LBN) | (1 << TXC_ATXCTL_TXPD0_LBN);
+ int rxpd = (1 << TXC_ARXCTL_RXPD3_LBN) | (1 << TXC_ARXCTL_RXPD2_LBN)
+ | (1 << TXC_ARXCTL_RXPD1_LBN) | (1 << TXC_ARXCTL_RXPD0_LBN);
+ int txctl = efx_mdio_read(efx, mmd, TXC_ALRGS_ATXCTL);
+ int rxctl = efx_mdio_read(efx, mmd, TXC_ALRGS_ARXCTL);
+
+ if (!(efx->phy_mode & PHY_MODE_LOW_POWER)) {
+ txctl &= ~txpd;
+ rxctl &= ~rxpd;
+ } else {
+ txctl |= txpd;
+ rxctl |= rxpd;
+ }
+
+ efx_mdio_write(efx, mmd, TXC_ALRGS_ATXCTL, txctl);
+ efx_mdio_write(efx, mmd, TXC_ALRGS_ARXCTL, rxctl);
+}
+
+static void txc_set_power(struct efx_nic *efx)
+{
+ /* According to the data book, all the MMDs can do low power */
+ efx_mdio_set_mmds_lpower(efx,
+ !!(efx->phy_mode & PHY_MODE_LOW_POWER),
+ TXC_REQUIRED_DEVS);
+
+ /* Global register bank is in PCS, PHY XS. These control the host
+ * side and line side settings respectively. */
+ txc_glrgs_lane_power(efx, MDIO_MMD_PCS);
+ txc_glrgs_lane_power(efx, MDIO_MMD_PHYXS);
+
+ /* Analog register bank in PMA/PMD, PHY XS */
+ txc_analog_lane_power(efx, MDIO_MMD_PMAPMD);
+ txc_analog_lane_power(efx, MDIO_MMD_PHYXS);
+}
+
+static void txc_reset_logic_mmd(struct efx_nic *efx, int mmd)
+{
+ int val = efx_mdio_read(efx, mmd, TXC_GLRGS_GLCMD);
+ int tries = 50;
+
+ val |= (1 << TXC_GLCMD_LMTSWRST_LBN);
+ efx_mdio_write(efx, mmd, TXC_GLRGS_GLCMD, val);
+ while (tries--) {
+ val = efx_mdio_read(efx, mmd, TXC_GLRGS_GLCMD);
+ if (!(val & (1 << TXC_GLCMD_LMTSWRST_LBN)))
+ break;
+ udelay(1);
+ }
+ if (!tries)
+ netif_info(efx, hw, efx->net_dev,
+ TXCNAME " Logic reset timed out!\n");
+}
+
+/* Perform a logic reset. This preserves the configuration registers
+ * and is needed for some configuration changes to take effect */
+static void txc_reset_logic(struct efx_nic *efx)
+{
+ /* The data sheet claims we can do the logic reset on either the
+ * PCS or the PHYXS and the result is a reset of both host- and
+ * line-side logic. */
+ txc_reset_logic_mmd(efx, MDIO_MMD_PCS);
+}
+
+static bool txc43128_phy_read_link(struct efx_nic *efx)
+{
+ return efx_mdio_links_ok(efx, TXC_REQUIRED_DEVS);
+}
+
+static int txc43128_phy_reconfigure(struct efx_nic *efx)
+{
+ struct txc43128_data *phy_data = efx->phy_data;
+ enum efx_phy_mode mode_change = efx->phy_mode ^ phy_data->phy_mode;
+ bool loop_change = LOOPBACK_CHANGED(phy_data, efx, TXC_LOOPBACKS);
+
+ if (efx->phy_mode & mode_change & PHY_MODE_TX_DISABLED) {
+ txc_reset_phy(efx);
+ txc_apply_defaults(efx);
+ falcon_reset_xaui(efx);
+ mode_change &= ~PHY_MODE_TX_DISABLED;
+ }
+
+ efx_mdio_transmit_disable(efx);
+ efx_mdio_phy_reconfigure(efx);
+ if (mode_change & PHY_MODE_LOW_POWER)
+ txc_set_power(efx);
+
+ /* The data sheet claims this is required after every reconfiguration
+ * (note at end of 7.1), but we mustn't do it when nothing changes as
+ * it glitches the link, and reconfigure gets called on link change,
+ * so we get an IRQ storm on link up. */
+ if (loop_change || mode_change)
+ txc_reset_logic(efx);
+
+ phy_data->phy_mode = efx->phy_mode;
+ phy_data->loopback_mode = efx->loopback_mode;
+
+ return 0;
+}
+
+static void txc43128_phy_fini(struct efx_nic *efx)
+{
+ /* Disable link events */
+ efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0);
+}
+
+static void txc43128_phy_remove(struct efx_nic *efx)
+{
+ kfree(efx->phy_data);
+ efx->phy_data = NULL;
+}
+
+/* Periodic callback: this exists mainly to poll link status as we
+ * don't use LASI interrupts */
+static bool txc43128_phy_poll(struct efx_nic *efx)
+{
+ struct txc43128_data *data = efx->phy_data;
+ bool was_up = efx->link_state.up;
+
+ efx->link_state.up = txc43128_phy_read_link(efx);
+ efx->link_state.speed = 10000;
+ efx->link_state.fd = true;
+ efx->link_state.fc = efx->wanted_fc;
+
+ if (efx->link_state.up || (efx->loopback_mode != LOOPBACK_NONE)) {
+ data->bug10934_timer = jiffies;
+ } else {
+ if (time_after_eq(jiffies, (data->bug10934_timer +
+ BUG10934_RESET_INTERVAL))) {
+ data->bug10934_timer = jiffies;
+ txc_reset_logic(efx);
+ }
+ }
+
+ return efx->link_state.up != was_up;
+}
+
+static const char *txc43128_test_names[] = {
+ "bist"
+};
+
+static const char *txc43128_test_name(struct efx_nic *efx, unsigned int index)
+{
+ if (index < ARRAY_SIZE(txc43128_test_names))
+ return txc43128_test_names[index];
+ return NULL;
+}
+
+static int txc43128_run_tests(struct efx_nic *efx, int *results, unsigned flags)
+{
+ int rc;
+
+ if (!(flags & ETH_TEST_FL_OFFLINE))
+ return 0;
+
+ rc = txc_reset_phy(efx);
+ if (rc < 0)
+ return rc;
+
+ rc = txc_bist(efx);
+ txc_apply_defaults(efx);
+ results[0] = rc ? -1 : 1;
+ return rc;
+}
+
+static void txc43128_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+ mdio45_ethtool_gset(&efx->mdio, ecmd);
+}
+
+struct efx_phy_operations falcon_txc_phy_ops = {
+ .probe = txc43128_phy_probe,
+ .init = txc43128_phy_init,
+ .reconfigure = txc43128_phy_reconfigure,
+ .poll = txc43128_phy_poll,
+ .fini = txc43128_phy_fini,
+ .remove = txc43128_phy_remove,
+ .get_settings = txc43128_get_settings,
+ .set_settings = efx_mdio_set_settings,
+ .test_alive = efx_mdio_test_alive,
+ .run_tests = txc43128_run_tests,
+ .test_name = txc43128_test_name,
+};
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index 782e45a613d6..e0d63083c3a8 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -19,9 +19,7 @@
#define EFX_WORKAROUND_FALCON_A(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_A1)
#define EFX_WORKAROUND_FALCON_AB(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_B0)
#define EFX_WORKAROUND_SIENA(efx) (efx_nic_rev(efx) == EFX_REV_SIENA_A0)
-#define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx)
-#define EFX_WORKAROUND_SFT9001(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A || \
- (efx)->phy_type == PHY_TYPE_SFT9001B)
+#define EFX_WORKAROUND_10G(efx) 1
/* XAUI resets if link not detected */
#define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS
@@ -58,9 +56,4 @@
/* Leak overlength packets rather than free */
#define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A
-/* Need to send XNP pages for 100BaseT */
-#define EFX_WORKAROUND_13204 EFX_WORKAROUND_SFT9001
-/* Don't restart AN in near-side loopback */
-#define EFX_WORKAROUND_15195 EFX_WORKAROUND_SFT9001
-
#endif /* EFX_WORKAROUNDS_H */
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 9265315baa0b..3a0cc63428ee 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -531,7 +531,7 @@ static int sgiseeq_open(struct net_device *dev)
if (request_irq(irq, sgiseeq_interrupt, 0, sgiseeqstr, dev)) {
printk(KERN_ERR "Seeq8003: Can't get irq %d\n", dev->irq);
- err = -EAGAIN;
+ return -EAGAIN;
}
err = init_seeq(dev, sp, sregs);
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 79fd02bc69fd..50259dfec583 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -798,7 +798,7 @@ static int sh_eth_rx(struct net_device *ndev)
skb->dev = ndev;
sh_eth_set_receive_align(skb);
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4));
}
if (entry >= RX_RING_SIZE - 1)
@@ -1031,7 +1031,7 @@ static int sh_eth_phy_init(struct net_device *ndev)
mdp->duplex = -1;
/* Try connect to PHY */
- phydev = phy_connect(ndev, phy_id, &sh_eth_adjust_link,
+ phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link,
0, PHY_INTERFACE_MODE_MII);
if (IS_ERR(phydev)) {
dev_err(&ndev->dev, "phy_connect failed\n");
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index bbbded76ff14..581836867098 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -832,7 +832,7 @@ static u16 __devinit read_eeprom(long ioaddr, int location)
outl(0, ee_addr);
eeprom_delay();
- return (retval);
+ return retval;
}
/* Read and write the MII management registers using software-generated
@@ -1042,7 +1042,7 @@ sis900_open(struct net_device *net_dev)
init_timer(&sis_priv->timer);
sis_priv->timer.expires = jiffies + HZ;
sis_priv->timer.data = (unsigned long)net_dev;
- sis_priv->timer.function = &sis900_timer;
+ sis_priv->timer.function = sis900_timer;
add_timer(&sis_priv->timer);
return 0;
@@ -2247,9 +2247,9 @@ static inline u16 sis900_mcast_bitnr(u8 *addr, u8 revision)
/* leave 8 or 7 most siginifant bits */
if ((revision >= SIS635A_900_REV) || (revision == SIS900B_900_REV))
- return ((int)(crc >> 24));
+ return (int)(crc >> 24);
else
- return ((int)(crc >> 25));
+ return (int)(crc >> 25);
}
/**
diff --git a/drivers/net/skfp/cfm.c b/drivers/net/skfp/cfm.c
index 5310d39b5737..e395ace3120b 100644
--- a/drivers/net/skfp/cfm.c
+++ b/drivers/net/skfp/cfm.c
@@ -542,8 +542,8 @@ static void cfm_fsm(struct s_smc *smc, int cmd)
*/
int cfm_get_mac_input(struct s_smc *smc)
{
- return((smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
- smc->mib.fddiSMTCF_State == SC5_THRU_B) ? PB : PA) ;
+ return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
+ smc->mib.fddiSMTCF_State == SC5_THRU_B) ? PB : PA;
}
/*
@@ -553,8 +553,8 @@ int cfm_get_mac_input(struct s_smc *smc)
*/
int cfm_get_mac_output(struct s_smc *smc)
{
- return((smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
- smc->mib.fddiSMTCF_State == SC4_THRU_A) ? PB : PA) ;
+ return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
+ smc->mib.fddiSMTCF_State == SC4_THRU_A) ? PB : PA;
}
static char path_iso[] = {
@@ -623,5 +623,5 @@ int cem_build_path(struct s_smc *smc, char *to, int path_index)
LINT_USE(path_index);
- return(len) ;
+ return len;
}
diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c
index c77cc14b3227..07da97c303d6 100644
--- a/drivers/net/skfp/drvfbi.c
+++ b/drivers/net/skfp/drvfbi.c
@@ -267,7 +267,7 @@ void timer_irq(struct s_smc *smc)
int pcm_get_s_port(struct s_smc *smc)
{
SK_UNUSED(smc) ;
- return(PS) ;
+ return PS;
}
/*
@@ -366,7 +366,7 @@ void sm_pm_bypass_req(struct s_smc *smc, int mode)
*/
int sm_pm_bypass_present(struct s_smc *smc)
{
- return( (inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE: FALSE) ;
+ return (inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE : FALSE;
}
void plc_clear_irq(struct s_smc *smc, int p)
@@ -483,9 +483,9 @@ static int is_equal_num(char comp1[], char comp2[], int num)
for (i = 0 ; i < num ; i++) {
if (comp1[i] != comp2[i])
- return (0) ;
+ return 0;
}
- return (1) ;
+ return 1;
} /* is_equal_num */
@@ -522,18 +522,18 @@ int set_oi_id_def(struct s_smc *smc)
i++ ;
break ; /* entry ok */
default:
- return (1) ; /* invalid oi_status */
+ return 1; /* invalid oi_status */
}
}
if (i == 0)
- return (2) ;
+ return 2;
if (!act_entries)
- return (3) ;
+ return 3;
/* ok, we have a valid OEM data base with an active entry */
smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[sel_id] ;
- return (0) ;
+ return 0;
}
#endif /* MULT_OEM */
diff --git a/drivers/net/skfp/ess.c b/drivers/net/skfp/ess.c
index e8387d25f24a..8639a0884f5c 100644
--- a/drivers/net/skfp/ess.c
+++ b/drivers/net/skfp/ess.c
@@ -135,7 +135,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
*/
if (!(p = (void *) sm_to_para(smc,sm,SMT_P0015))) {
DB_ESS("ESS: RAF frame error, parameter type not found\n",0,0) ;
- return(fs) ;
+ return fs;
}
msg_res_type = ((struct smt_p_0015 *)p)->res_type ;
@@ -147,7 +147,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
* error in frame: para ESS command was not found
*/
DB_ESS("ESS: RAF frame error, parameter command not found\n",0,0);
- return(fs) ;
+ return fs;
}
DB_ESSN(2,"fc %x ft %x\n",sm->smt_class,sm->smt_type) ;
@@ -175,12 +175,12 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
* local and no static allocation is used
*/
if (!local || smc->mib.fddiESSPayload)
- return(fs) ;
+ return fs;
p = (void *) sm_to_para(smc,sm,SMT_P0019) ;
for (i = 0; i < 5; i++) {
if (((struct smt_p_0019 *)p)->alloc_addr.a[i]) {
- return(fs) ;
+ return fs;
}
}
@@ -199,10 +199,10 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
sm->smt_dest = smt_sba_da ;
if (smc->ess.local_sba_active)
- return(fs | I_INDICATOR) ;
+ return fs | I_INDICATOR;
if (!(db = smt_get_mbuf(smc)))
- return(fs) ;
+ return fs;
db->sm_len = mb->sm_len ;
db->sm_off = mb->sm_off ;
@@ -212,7 +212,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
(struct smt_header *)(db->sm_data+db->sm_off),
"RAF") ;
smt_send_frame(smc,db,FC_SMT_INFO,0) ;
- return(fs) ;
+ return fs;
}
/*
@@ -221,7 +221,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
*/
if (smt_check_para(smc,sm,plist_raf_alc_res)) {
DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ;
- return(fs) ;
+ return fs;
}
/*
@@ -242,7 +242,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
(sm->smt_tid != smc->ess.alloc_trans_id)) {
DB_ESS("ESS: Allocation Responce not accepted\n",0,0) ;
- return(fs) ;
+ return fs;
}
/*
@@ -268,7 +268,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
*/
(void)process_bw_alloc(smc,(long)payload,(long)overhead) ;
- return(fs) ;
+ return fs;
/* end of Process Allocation Request */
/*
@@ -280,7 +280,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
*/
if (sm->smt_type != SMT_REQUEST) {
DB_ESS("ESS: Do not process Change Responses\n",0,0) ;
- return(fs) ;
+ return fs;
}
/*
@@ -288,7 +288,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
*/
if (smt_check_para(smc,sm,plist_raf_chg_req)) {
DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ;
- return(fs) ;
+ return fs;
}
/*
@@ -300,7 +300,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
if ((((struct smt_p_320b *)sm_to_para(smc,sm,SMT_P320B))->path_index
!= PRIMARY_RING) || (msg_res_type != SYNC_BW)) {
DB_ESS("ESS: RAF frame with para problem, ignoring\n",0,0) ;
- return(fs) ;
+ return fs;
}
/*
@@ -319,14 +319,14 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
* process the bandwidth allocation
*/
if(!process_bw_alloc(smc,(long)payload,(long)overhead))
- return(fs) ;
+ return fs;
/*
* send an RAF Change Reply
*/
ess_send_response(smc,sm,CHANGE_ALLOCATION) ;
- return(fs) ;
+ return fs;
/* end of Process Change Request */
/*
@@ -338,7 +338,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
*/
if (sm->smt_type != SMT_REQUEST) {
DB_ESS("ESS: Do not process a Report Reply\n",0,0) ;
- return(fs) ;
+ return fs;
}
DB_ESSN(2,"ESS: Report Request from %s\n",
@@ -349,7 +349,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
*/
if (msg_res_type != SYNC_BW) {
DB_ESS("ESS: ignoring RAF with para problem\n",0,0) ;
- return(fs) ;
+ return fs;
}
/*
@@ -357,7 +357,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
*/
ess_send_response(smc,sm,REPORT_ALLOCATION) ;
- return(fs) ;
+ return fs;
/* end of Process Report Request */
default:
@@ -368,7 +368,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
break ;
}
- return(fs) ;
+ return fs;
}
/*
@@ -418,17 +418,17 @@ static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhe
*/
/* if (smt_set_obj(smc,SMT_P320F,payload,S_SET)) {
DB_ESS("ESS: SMT does not accept the payload value\n",0,0) ;
- return(FALSE) ;
+ return FALSE;
}
if (smt_set_obj(smc,SMT_P3210,overhead,S_SET)) {
DB_ESS("ESS: SMT does not accept the overhead value\n",0,0) ;
- return(FALSE) ;
+ return FALSE;
} */
/* premliminary */
if (payload > MAX_PAYLOAD || overhead > 5000) {
DB_ESS("ESS: payload / overhead not accepted\n",0,0) ;
- return(FALSE) ;
+ return FALSE;
}
/*
@@ -468,7 +468,7 @@ static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhe
ess_config_fifo(smc) ;
set_formac_tsync(smc,smc->ess.sync_bw) ;
- return(TRUE) ;
+ return TRUE;
}
static void ess_send_response(struct s_smc *smc, struct smt_header *sm,
diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c
index 9d8d1ac48176..ca4e7bb6a5a8 100644
--- a/drivers/net/skfp/fplustm.c
+++ b/drivers/net/skfp/fplustm.c
@@ -112,8 +112,8 @@ static u_long mac_get_tneg(struct s_smc *smc)
u_long tneg ;
tneg = (u_long)((long)inpw(FM_A(FM_TNEG))<<5) ;
- return((u_long)((tneg + ((inpw(FM_A(FM_TMRS))>>10)&0x1f)) |
- 0xffe00000L)) ;
+ return (u_long)((tneg + ((inpw(FM_A(FM_TMRS))>>10)&0x1f)) |
+ 0xffe00000L) ;
}
void mac_update_counter(struct s_smc *smc)
@@ -163,7 +163,7 @@ static u_long read_mdr(struct s_smc *smc, unsigned int addr)
/* is used */
p = (u_long)inpw(FM_A(FM_MDRU))<<16 ;
p += (u_long)inpw(FM_A(FM_MDRL)) ;
- return(p) ;
+ return p;
}
#endif
@@ -887,7 +887,7 @@ int init_fplus(struct s_smc *smc)
/* make sure all PCI settings are correct */
mac_do_pci_fix(smc) ;
- return(init_mac(smc,1)) ;
+ return init_mac(smc, 1);
/* enable_formac(smc) ; */
}
@@ -989,7 +989,7 @@ static int init_mac(struct s_smc *smc, int all)
}
smc->hw.hw_state = STARTED ;
- return(0) ;
+ return 0;
}
@@ -1049,7 +1049,7 @@ void sm_ma_control(struct s_smc *smc, int mode)
int sm_mac_get_tx_state(struct s_smc *smc)
{
- return((inpw(FM_A(FM_STMCHN))>>4)&7) ;
+ return (inpw(FM_A(FM_STMCHN))>>4) & 7;
}
/*
@@ -1084,9 +1084,9 @@ static struct s_fpmc* mac_get_mc_table(struct s_smc *smc,
}
if (memcmp((char *)&tb->a,(char *)own,6))
continue ;
- return(tb) ;
+ return tb;
}
- return(slot) ; /* return first free or NULL */
+ return slot; /* return first free or NULL */
}
/*
@@ -1152,12 +1152,12 @@ int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can)
*/
if (can & 0x80) {
if (smc->hw.fp.smt_slots_used >= SMT_MAX_MULTI) {
- return(1) ;
+ return 1;
}
}
else {
if (smc->hw.fp.os_slots_used >= FPMAX_MULTICAST-SMT_MAX_MULTI) {
- return(1) ;
+ return 1;
}
}
@@ -1165,7 +1165,7 @@ int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can)
* find empty slot
*/
if (!(tb = mac_get_mc_table(smc,addr,&own,0,can & ~0x80)))
- return(1) ;
+ return 1;
tb->n++ ;
tb->a = own ;
tb->perm = (can & 0x80) ? 1 : 0 ;
@@ -1175,7 +1175,7 @@ int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can)
else
smc->hw.fp.os_slots_used++ ;
- return(0) ;
+ return 0;
}
/*
diff --git a/drivers/net/skfp/hwmtm.c b/drivers/net/skfp/hwmtm.c
index d322f1b702ac..af5a755e269d 100644
--- a/drivers/net/skfp/hwmtm.c
+++ b/drivers/net/skfp/hwmtm.c
@@ -232,16 +232,16 @@ u_int mac_drv_check_space(void)
#ifdef COMMON_MB_POOL
call_count++ ;
if (call_count == 1) {
- return(EXT_VIRT_MEM) ;
+ return EXT_VIRT_MEM;
}
else {
- return(EXT_VIRT_MEM_2) ;
+ return EXT_VIRT_MEM_2;
}
#else
- return (EXT_VIRT_MEM) ;
+ return EXT_VIRT_MEM;
#endif
#else
- return (0) ;
+ return 0;
#endif
}
@@ -271,7 +271,7 @@ int mac_drv_init(struct s_smc *smc)
if (!(smc->os.hwm.descr_p = (union s_fp_descr volatile *)
mac_drv_get_desc_mem(smc,(u_int)
(RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)))) {
- return(1) ; /* no space the hwm modul can't work */
+ return 1; /* no space the hwm modul can't work */
}
/*
@@ -283,18 +283,18 @@ int mac_drv_init(struct s_smc *smc)
#ifndef COMMON_MB_POOL
if (!(smc->os.hwm.mbuf_pool.mb_start = (SMbuf *) mac_drv_get_space(smc,
MAX_MBUF*sizeof(SMbuf)))) {
- return(1) ; /* no space the hwm modul can't work */
+ return 1; /* no space the hwm modul can't work */
}
#else
if (!mb_start) {
if (!(mb_start = (SMbuf *) mac_drv_get_space(smc,
MAX_MBUF*sizeof(SMbuf)))) {
- return(1) ; /* no space the hwm modul can't work */
+ return 1; /* no space the hwm modul can't work */
}
}
#endif
#endif
- return (0) ;
+ return 0;
}
/*
@@ -349,7 +349,7 @@ static u_long init_descr_ring(struct s_smc *smc,
DRV_BUF_FLUSH(&d1->r,DDI_DMA_SYNC_FORDEV) ;
d1++;
}
- return(phys) ;
+ return phys;
}
static void init_txd_ring(struct s_smc *smc)
@@ -502,7 +502,7 @@ SMbuf *smt_get_mbuf(struct s_smc *smc)
mb->sm_use_count = 1 ;
}
DB_GEN("get SMbuf: mb = %x",(void *)mb,0,3) ;
- return (mb) ; /* May be NULL */
+ return mb; /* May be NULL */
}
void smt_free_mbuf(struct s_smc *smc, SMbuf *mb)
@@ -621,7 +621,7 @@ static u_long repair_txd_ring(struct s_smc *smc, struct s_smt_tx_queue *queue)
t = t->txd_next ;
tx_used-- ;
}
- return(phys) ;
+ return phys;
}
/*
@@ -673,7 +673,7 @@ static u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue)
r = r->rxd_next ;
rx_used-- ;
}
- return(phys) ;
+ return phys;
}
@@ -1595,7 +1595,7 @@ int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len,
}
DB_TX("frame_status = %x",frame_status,0,3) ;
NDD_TRACE("THiE",frame_status,smc->os.hwm.tx_p->tx_free,0) ;
- return(frame_status) ;
+ return frame_status;
}
/*
@@ -1764,7 +1764,7 @@ static SMbuf *get_llc_rx(struct s_smc *smc)
smc->os.hwm.llc_rx_pipe = mb->sm_next ;
}
DB_GEN("get_llc_rx: mb = 0x%x",(void *)mb,0,4) ;
- return(mb) ;
+ return mb;
}
/*
@@ -1797,7 +1797,7 @@ static SMbuf *get_txd_mb(struct s_smc *smc)
smc->os.hwm.txd_tx_pipe = mb->sm_next ;
}
DB_GEN("get_txd_mb: mb = 0x%x",(void *)mb,0,4) ;
- return(mb) ;
+ return mb;
}
/*
diff --git a/drivers/net/skfp/hwt.c b/drivers/net/skfp/hwt.c
index 053151468f93..c0798fd2ca69 100644
--- a/drivers/net/skfp/hwt.c
+++ b/drivers/net/skfp/hwt.c
@@ -179,7 +179,7 @@ u_long hwt_read(struct s_smc *smc)
else
smc->hw.t_stop = smc->hw.t_start - tr ;
}
- return (smc->hw.t_stop) ;
+ return smc->hw.t_stop;
}
#ifdef PCI
@@ -208,7 +208,7 @@ u_long hwt_quick_read(struct s_smc *smc)
outpw(ADDR(B2_TI_CRTL), TIM_START) ;
outpd(ADDR(B2_TI_INI),interval) ;
- return(time) ;
+ return time;
}
/************************
@@ -221,7 +221,7 @@ u_long hwt_quick_read(struct s_smc *smc)
* para start start time
* duration time to wait
*
- * NOTE: The fuction will return immediately, if the timer is not
+ * NOTE: The function will return immediately, if the timer is not
* started
************************/
void hwt_wait_time(struct s_smc *smc, u_long start, long int duration)
diff --git a/drivers/net/skfp/pcmplc.c b/drivers/net/skfp/pcmplc.c
index ba45bc794d77..112d35b1bf0e 100644
--- a/drivers/net/skfp/pcmplc.c
+++ b/drivers/net/skfp/pcmplc.c
@@ -504,7 +504,7 @@ int sm_pm_get_ls(struct s_smc *smc, int phy)
#ifdef CONCENTRATOR
if (!plc_is_installed(smc,phy))
- return(PC_QLS) ;
+ return PC_QLS;
#endif
state = inpw(PLC(phy,PL_STATUS_A)) & PL_LINE_ST ;
@@ -528,7 +528,7 @@ int sm_pm_get_ls(struct s_smc *smc, int phy)
default :
state = PC_LS_NONE ;
}
- return(state) ;
+ return state;
}
static int plc_send_bits(struct s_smc *smc, struct s_phy *phy, int len)
@@ -547,7 +547,7 @@ static int plc_send_bits(struct s_smc *smc, struct s_phy *phy, int len)
#if 0
printf("PL_PCM_SIGNAL is set\n") ;
#endif
- return(1) ;
+ return 1;
}
/* write bit[n] & length = 1 to regs */
outpw(PLC(np,PL_VECTOR_LEN),len-1) ; /* len=nr-1 */
@@ -562,7 +562,7 @@ static int plc_send_bits(struct s_smc *smc, struct s_phy *phy, int len)
printf("SIGNALING bit %d .. %d\n",phy->bitn,phy->bitn+len-1) ;
#endif
#endif
- return(0) ;
+ return 0;
}
/*
@@ -1590,12 +1590,12 @@ int pcm_status_twisted(struct s_smc *smc)
{
int twist = 0 ;
if (smc->s.sas != SMT_DAS)
- return(0) ;
+ return 0;
if (smc->y[PA].twisted && (smc->y[PA].mib->fddiPORTPCMState == PC8_ACTIVE))
twist |= 1 ;
if (smc->y[PB].twisted && (smc->y[PB].mib->fddiPORTPCMState == PC8_ACTIVE))
twist |= 2 ;
- return(twist) ;
+ return twist;
}
/*
@@ -1636,9 +1636,9 @@ int pcm_rooted_station(struct s_smc *smc)
for (n = 0 ; n < NUMPHYS ; n++) {
if (smc->y[n].mib->fddiPORTPCMState == PC8_ACTIVE &&
smc->y[n].mib->fddiPORTNeighborType == TM)
- return(0) ;
+ return 0;
}
- return(1) ;
+ return 1;
}
/*
@@ -1915,7 +1915,7 @@ int get_pcm_state(struct s_smc *smc, int np)
case PL_PC9 : pcs = PC_MAINT ; break ;
default : pcs = PC_DISABLE ; break ;
}
- return(pcs) ;
+ return pcs;
}
char *get_linestate(struct s_smc *smc, int np)
@@ -1937,7 +1937,7 @@ char *get_linestate(struct s_smc *smc, int np)
default: ls = "unknown" ; break ;
#endif
}
- return(ls) ;
+ return ls;
}
char *get_pcmstate(struct s_smc *smc, int np)
@@ -1959,7 +1959,7 @@ char *get_pcmstate(struct s_smc *smc, int np)
case PL_PC9 : pcs = "MAINT" ; break ;
default : pcs = "UNKNOWN" ; break ;
}
- return(pcs) ;
+ return pcs;
}
void list_phy(struct s_smc *smc)
diff --git a/drivers/net/skfp/pmf.c b/drivers/net/skfp/pmf.c
index a320fdb3727d..9ac4665d7411 100644
--- a/drivers/net/skfp/pmf.c
+++ b/drivers/net/skfp/pmf.c
@@ -328,7 +328,7 @@ static SMbuf *smt_build_pmf_response(struct s_smc *smc, struct smt_header *req,
* build SMT header
*/
if (!(mb = smt_get_mbuf(smc)))
- return(mb) ;
+ return mb;
smt = smtod(mb, struct smt_header *) ;
smt->smt_dest = req->smt_source ; /* DA == source of request */
@@ -493,7 +493,7 @@ static SMbuf *smt_build_pmf_response(struct s_smc *smc, struct smt_header *req,
smt_add_para(smc,&set_pcon,(u_short) SMT_P1035,0,0) ;
smt_add_para(smc,&set_pcon,(u_short) SMT_P1036,0,0) ;
}
- return(mb) ;
+ return mb;
}
static int smt_authorize(struct s_smc *smc, struct smt_header *sm)
@@ -511,7 +511,7 @@ static int smt_authorize(struct s_smc *smc, struct smt_header *sm)
if (i != 8) {
if (memcmp((char *) &sm->smt_sid,
(char *) &smc->mib.fddiPRPMFStation,8))
- return(1) ;
+ return 1;
}
/*
* check authoriziation parameter if passwd not zero
@@ -522,13 +522,13 @@ static int smt_authorize(struct s_smc *smc, struct smt_header *sm)
if (i != 8) {
pa = (struct smt_para *) sm_to_para(smc,sm,SMT_P_AUTHOR) ;
if (!pa)
- return(1) ;
+ return 1;
if (pa->p_len != 8)
- return(1) ;
+ return 1;
if (memcmp((char *)(pa+1),(char *)smc->mib.fddiPRPMFPasswd,8))
- return(1) ;
+ return 1;
}
- return(0) ;
+ return 0;
}
static int smt_check_set_count(struct s_smc *smc, struct smt_header *sm)
@@ -542,9 +542,9 @@ static int smt_check_set_count(struct s_smc *smc, struct smt_header *sm)
if ((smc->mib.fddiSMTSetCount.count != sc->count) ||
memcmp((char *) smc->mib.fddiSMTSetCount.timestamp,
(char *)sc->timestamp,8))
- return(1) ;
+ return 1;
}
- return(0) ;
+ return 0;
}
void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para,
@@ -1109,7 +1109,7 @@ static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
break ;
case 0x2000 :
if (mac < 0 || mac >= NUMMACS) {
- return(SMT_RDF_NOPARAM) ;
+ return SMT_RDF_NOPARAM;
}
mib_m = &smc->mib.m[mac] ;
mib_addr = (char *) mib_m ;
@@ -1118,7 +1118,7 @@ static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
break ;
case 0x3000 :
if (path < 0 || path >= NUMPATHS) {
- return(SMT_RDF_NOPARAM) ;
+ return SMT_RDF_NOPARAM;
}
mib_a = &smc->mib.a[path] ;
mib_addr = (char *) mib_a ;
@@ -1127,7 +1127,7 @@ static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
break ;
case 0x4000 :
if (port < 0 || port >= smt_mib_phys(smc)) {
- return(SMT_RDF_NOPARAM) ;
+ return SMT_RDF_NOPARAM;
}
mib_p = &smc->mib.p[port_to_mib(smc,port)] ;
mib_addr = (char *) mib_p ;
@@ -1151,22 +1151,20 @@ static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
case SMT_P10F9 :
#endif
case SMT_P20F1 :
- if (!local) {
- return(SMT_RDF_NOPARAM) ;
- }
+ if (!local)
+ return SMT_RDF_NOPARAM;
break ;
}
pt = smt_get_ptab(pa->p_type) ;
- if (!pt) {
- return( (pa->p_type & 0xff00) ? SMT_RDF_NOPARAM :
- SMT_RDF_ILLEGAL ) ;
- }
+ if (!pt)
+ return (pa->p_type & 0xff00) ? SMT_RDF_NOPARAM :
+ SMT_RDF_ILLEGAL;
switch (pt->p_access) {
case AC_GR :
case AC_S :
break ;
default :
- return(SMT_RDF_ILLEGAL) ;
+ return SMT_RDF_ILLEGAL;
}
to = mib_addr + pt->p_offset ;
swap = pt->p_swap ; /* pointer to swap string */
@@ -1292,7 +1290,7 @@ static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
break ;
default :
SMT_PANIC(smc,SMT_E0120, SMT_E0120_MSG) ;
- return(SMT_RDF_ILLEGAL) ;
+ return SMT_RDF_ILLEGAL;
}
}
/*
@@ -1501,15 +1499,15 @@ change_mac_para:
default :
break ;
}
- return(0) ;
+ return 0;
val_error:
/* parameter value in frame is out of range */
- return(SMT_RDF_RANGE) ;
+ return SMT_RDF_RANGE;
len_error:
/* parameter value in frame is too short */
- return(SMT_RDF_LENGTH) ;
+ return SMT_RDF_LENGTH;
#if 0
no_author_error:
@@ -1518,7 +1516,7 @@ no_author_error:
* because SBA denied is not a valid return code in the
* PMF protocol.
*/
- return(SMT_RDF_AUTHOR) ;
+ return SMT_RDF_AUTHOR;
#endif
}
@@ -1527,7 +1525,7 @@ static const struct s_p_tab *smt_get_ptab(u_short para)
const struct s_p_tab *pt ;
for (pt = p_tab ; pt->p_num && pt->p_num != para ; pt++)
;
- return(pt->p_num ? pt : NULL) ;
+ return pt->p_num ? pt : NULL;
}
static int smt_mib_phys(struct s_smc *smc)
@@ -1535,11 +1533,11 @@ static int smt_mib_phys(struct s_smc *smc)
#ifdef CONCENTRATOR
SK_UNUSED(smc) ;
- return(NUMPHYS) ;
+ return NUMPHYS;
#else
if (smc->s.sas == SMT_SAS)
- return(1) ;
- return(NUMPHYS) ;
+ return 1;
+ return NUMPHYS;
#endif
}
@@ -1548,11 +1546,11 @@ static int port_to_mib(struct s_smc *smc, int p)
#ifdef CONCENTRATOR
SK_UNUSED(smc) ;
- return(p) ;
+ return p;
#else
if (smc->s.sas == SMT_SAS)
- return(PS) ;
- return(p) ;
+ return PS;
+ return p;
#endif
}
diff --git a/drivers/net/skfp/queue.c b/drivers/net/skfp/queue.c
index 09adb3d68b7c..c1a0df455a59 100644
--- a/drivers/net/skfp/queue.c
+++ b/drivers/net/skfp/queue.c
@@ -128,7 +128,7 @@ u_short smt_online(struct s_smc *smc, int on)
{
queue_event(smc,EVENT_ECM,on ? EC_CONNECT : EC_DISCONNECT) ;
ev_dispatcher(smc) ;
- return(smc->mib.fddiSMTCF_State) ;
+ return smc->mib.fddiSMTCF_State;
}
/*
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index 31b2dabf094c..0a66fed52e8e 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -33,7 +33,7 @@
* The driver architecture is based on the DEC FDDI driver by
* Lawrence V. Stefani and several ethernet drivers.
* I also used an existing Windows NT miniport driver.
- * All hardware dependent fuctions are handled by the SysKonnect
+ * All hardware dependent functions are handled by the SysKonnect
* Hardware Module.
* The only headerfiles that are directly related to this source
* are skfddi.c, h/types.h, h/osdef1st.h, h/targetos.h.
@@ -209,7 +209,7 @@ static int skfp_init_one(struct pci_dev *pdev,
void __iomem *mem;
int err;
- pr_debug(KERN_INFO "entering skfp_init_one\n");
+ pr_debug("entering skfp_init_one\n");
if (num_boards == 0)
printk("%s\n", boot_msg);
@@ -385,7 +385,7 @@ static int skfp_driver_init(struct net_device *dev)
skfddi_priv *bp = &smc->os;
int err = -EIO;
- pr_debug(KERN_INFO "entering skfp_driver_init\n");
+ pr_debug("entering skfp_driver_init\n");
// set the io address in private structures
bp->base_addr = dev->base_addr;
@@ -405,7 +405,7 @@ static int skfp_driver_init(struct net_device *dev)
// Determine the required size of the 'shared' memory area.
bp->SharedMemSize = mac_drv_check_space();
- pr_debug(KERN_INFO "Memory for HWM: %ld\n", bp->SharedMemSize);
+ pr_debug("Memory for HWM: %ld\n", bp->SharedMemSize);
if (bp->SharedMemSize > 0) {
bp->SharedMemSize += 16; // for descriptor alignment
@@ -429,18 +429,18 @@ static int skfp_driver_init(struct net_device *dev)
card_stop(smc); // Reset adapter.
- pr_debug(KERN_INFO "mac_drv_init()..\n");
+ pr_debug("mac_drv_init()..\n");
if (mac_drv_init(smc) != 0) {
- pr_debug(KERN_INFO "mac_drv_init() failed.\n");
+ pr_debug("mac_drv_init() failed\n");
goto fail;
}
read_address(smc, NULL);
- pr_debug(KERN_INFO "HW-Addr: %pMF\n", smc->hw.fddi_canon_addr.a);
+ pr_debug("HW-Addr: %pMF\n", smc->hw.fddi_canon_addr.a);
memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6);
smt_reset_defaults(smc, 0);
- return (0);
+ return 0;
fail:
if (bp->SharedMemAddr) {
@@ -485,7 +485,7 @@ static int skfp_open(struct net_device *dev)
struct s_smc *smc = netdev_priv(dev);
int err;
- pr_debug(KERN_INFO "entering skfp_open\n");
+ pr_debug("entering skfp_open\n");
/* Register IRQ - support shared interrupts by passing device ptr */
err = request_irq(dev->irq, skfp_interrupt, IRQF_SHARED,
dev->name, dev);
@@ -516,7 +516,7 @@ static int skfp_open(struct net_device *dev)
mac_drv_rx_mode(smc, RX_DISABLE_PROMISC);
netif_start_queue(dev);
- return (0);
+ return 0;
} // skfp_open
@@ -565,7 +565,7 @@ static int skfp_close(struct net_device *dev)
skb_queue_purge(&bp->SendSkbQueue);
bp->QueueSkb = MAX_TX_QUEUE_LEN;
- return (0);
+ return 0;
} // skfp_close
@@ -794,7 +794,7 @@ static struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev)
bp->stats.port_lem_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls;
#endif
- return ((struct net_device_stats *) &bp->os.MacStat);
+ return (struct net_device_stats *)&bp->os.MacStat;
} // ctl_get_stat
@@ -856,12 +856,12 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev)
/* Enable promiscuous mode, if necessary */
if (dev->flags & IFF_PROMISC) {
mac_drv_rx_mode(smc, RX_ENABLE_PROMISC);
- pr_debug(KERN_INFO "PROMISCUOUS MODE ENABLED\n");
+ pr_debug("PROMISCUOUS MODE ENABLED\n");
}
/* Else, update multicast address table */
else {
mac_drv_rx_mode(smc, RX_DISABLE_PROMISC);
- pr_debug(KERN_INFO "PROMISCUOUS MODE DISABLED\n");
+ pr_debug("PROMISCUOUS MODE DISABLED\n");
// Reset all MC addresses
mac_clear_multicast(smc);
@@ -869,7 +869,7 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev)
if (dev->flags & IFF_ALLMULTI) {
mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI);
- pr_debug(KERN_INFO "ENABLE ALL MC ADDRESSES\n");
+ pr_debug("ENABLE ALL MC ADDRESSES\n");
} else if (!netdev_mc_empty(dev)) {
if (netdev_mc_count(dev) <= FPMAX_MULTICAST) {
/* use exact filtering */
@@ -880,18 +880,18 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev)
(struct fddi_addr *)ha->addr,
1);
- pr_debug(KERN_INFO "ENABLE MC ADDRESS: %pMF\n",
- ha->addr);
+ pr_debug("ENABLE MC ADDRESS: %pMF\n",
+ ha->addr);
}
} else { // more MC addresses than HW supports
mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI);
- pr_debug(KERN_INFO "ENABLE ALL MC ADDRESSES\n");
+ pr_debug("ENABLE ALL MC ADDRESSES\n");
}
} else { // no MC addresses
- pr_debug(KERN_INFO "DISABLE ALL MC ADDRESSES\n");
+ pr_debug("DISABLE ALL MC ADDRESSES\n");
}
/* Update adapter filters */
@@ -932,7 +932,7 @@ static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr)
ResetAdapter(smc);
spin_unlock_irqrestore(&bp->DriverLock, Flags);
- return (0); /* always return zero */
+ return 0; /* always return zero */
} // skfp_ctl_set_mac_address
@@ -1045,7 +1045,7 @@ static netdev_tx_t skfp_send_pkt(struct sk_buff *skb,
struct s_smc *smc = netdev_priv(dev);
skfddi_priv *bp = &smc->os;
- pr_debug(KERN_INFO "skfp_send_pkt\n");
+ pr_debug("skfp_send_pkt\n");
/*
* Verify that incoming transmit request is OK
@@ -1114,13 +1114,13 @@ static void send_queued_packets(struct s_smc *smc)
int frame_status; // HWM tx frame status.
- pr_debug(KERN_INFO "send queued packets\n");
+ pr_debug("send queued packets\n");
for (;;) {
// send first buffer from queue
skb = skb_dequeue(&bp->SendSkbQueue);
if (!skb) {
- pr_debug(KERN_INFO "queue empty\n");
+ pr_debug("queue empty\n");
return;
} // queue empty !
@@ -1232,7 +1232,7 @@ static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr)
static void ResetAdapter(struct s_smc *smc)
{
- pr_debug(KERN_INFO "[fddi: ResetAdapter]\n");
+ pr_debug("[fddi: ResetAdapter]\n");
// Stop the adapter.
@@ -1278,7 +1278,7 @@ void llc_restart_tx(struct s_smc *smc)
{
skfddi_priv *bp = &smc->os;
- pr_debug(KERN_INFO "[llc_restart_tx]\n");
+ pr_debug("[llc_restart_tx]\n");
// Try to send queued packets
spin_unlock(&bp->DriverLock);
@@ -1308,21 +1308,21 @@ void *mac_drv_get_space(struct s_smc *smc, unsigned int size)
{
void *virt;
- pr_debug(KERN_INFO "mac_drv_get_space (%d bytes), ", size);
+ pr_debug("mac_drv_get_space (%d bytes), ", size);
virt = (void *) (smc->os.SharedMemAddr + smc->os.SharedMemHeap);
if ((smc->os.SharedMemHeap + size) > smc->os.SharedMemSize) {
printk("Unexpected SMT memory size requested: %d\n", size);
- return (NULL);
+ return NULL;
}
smc->os.SharedMemHeap += size; // Move heap pointer.
- pr_debug(KERN_INFO "mac_drv_get_space end\n");
- pr_debug(KERN_INFO "virt addr: %lx\n", (ulong) virt);
- pr_debug(KERN_INFO "bus addr: %lx\n", (ulong)
+ pr_debug("mac_drv_get_space end\n");
+ pr_debug("virt addr: %lx\n", (ulong) virt);
+ pr_debug("bus addr: %lx\n", (ulong)
(smc->os.SharedMemDMA +
((char *) virt - (char *)smc->os.SharedMemAddr)));
- return (virt);
+ return virt;
} // mac_drv_get_space
@@ -1349,7 +1349,7 @@ void *mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size)
char *virt;
- pr_debug(KERN_INFO "mac_drv_get_desc_mem\n");
+ pr_debug("mac_drv_get_desc_mem\n");
// Descriptor memory must be aligned on 16-byte boundary.
@@ -1363,9 +1363,9 @@ void *mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size)
if (!mac_drv_get_space(smc, size)) {
printk("fddi: Unable to align descriptor memory.\n");
- return (NULL);
+ return NULL;
}
- return (virt + size);
+ return virt + size;
} // mac_drv_get_desc_mem
@@ -1384,8 +1384,8 @@ void *mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size)
************************/
unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt)
{
- return (smc->os.SharedMemDMA +
- ((char *) virt - (char *)smc->os.SharedMemAddr));
+ return smc->os.SharedMemDMA +
+ ((char *) virt - (char *)smc->os.SharedMemAddr);
} // mac_drv_virt2phys
@@ -1419,8 +1419,8 @@ unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt)
************************/
u_long dma_master(struct s_smc * smc, void *virt, int len, int flag)
{
- return (smc->os.SharedMemDMA +
- ((char *) virt - (char *)smc->os.SharedMemAddr));
+ return smc->os.SharedMemDMA +
+ ((char *) virt - (char *)smc->os.SharedMemAddr);
} // dma_master
@@ -1493,7 +1493,7 @@ void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd)
{
struct sk_buff *skb;
- pr_debug(KERN_INFO "entering mac_drv_tx_complete\n");
+ pr_debug("entering mac_drv_tx_complete\n");
// Check if this TxD points to a skb
if (!(skb = txd->txd_os.skb)) {
@@ -1513,7 +1513,7 @@ void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd)
// free the skb
dev_kfree_skb_irq(skb);
- pr_debug(KERN_INFO "leaving mac_drv_tx_complete\n");
+ pr_debug("leaving mac_drv_tx_complete\n");
} // mac_drv_tx_complete
@@ -1580,7 +1580,7 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
unsigned short ri;
u_int RifLength;
- pr_debug(KERN_INFO "entering mac_drv_rx_complete (len=%d)\n", len);
+ pr_debug("entering mac_drv_rx_complete (len=%d)\n", len);
if (frag_count != 1) { // This is not allowed to happen.
printk("fddi: Multi-fragment receive!\n");
@@ -1589,7 +1589,7 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
}
skb = rxd->rxd_os.skb;
if (!skb) {
- pr_debug(KERN_INFO "No skb in rxd\n");
+ pr_debug("No skb in rxd\n");
smc->os.MacStat.gen.rx_errors++;
goto RequeueRxd;
}
@@ -1619,7 +1619,7 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
else {
int n;
// goos: RIF removal has still to be tested
- pr_debug(KERN_INFO "RIF found\n");
+ pr_debug("RIF found\n");
// Get RIF length from Routing Control (RC) field.
cp = virt + FDDI_MAC_HDR_LEN; // Point behind MAC header.
@@ -1664,7 +1664,7 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
return;
RequeueRxd:
- pr_debug(KERN_INFO "Rx: re-queue RXD.\n");
+ pr_debug("Rx: re-queue RXD.\n");
mac_drv_requeue_rxd(smc, rxd, frag_count);
smc->os.MacStat.gen.rx_errors++; // Count receive packets
// not indicated.
@@ -1775,7 +1775,7 @@ void mac_drv_fill_rxd(struct s_smc *smc)
struct sk_buff *skb;
volatile struct s_smt_fp_rxd *rxd;
- pr_debug(KERN_INFO "entering mac_drv_fill_rxd\n");
+ pr_debug("entering mac_drv_fill_rxd\n");
// Walk through the list of free receive buffers, passing receive
// buffers to the HWM as long as RXDs are available.
@@ -1783,7 +1783,7 @@ void mac_drv_fill_rxd(struct s_smc *smc)
MaxFrameSize = smc->os.MaxFrameSize;
// Check if there is any RXD left.
while (HWM_GET_RX_FREE(smc) > 0) {
- pr_debug(KERN_INFO ".\n");
+ pr_debug(".\n");
rxd = HWM_GET_CURR_RXD(smc);
skb = alloc_skb(MaxFrameSize + 3, GFP_ATOMIC);
@@ -1814,7 +1814,7 @@ void mac_drv_fill_rxd(struct s_smc *smc)
hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize,
FIRST_FRAG | LAST_FRAG);
}
- pr_debug(KERN_INFO "leaving mac_drv_fill_rxd\n");
+ pr_debug("leaving mac_drv_fill_rxd\n");
} // mac_drv_fill_rxd
@@ -1904,12 +1904,12 @@ int mac_drv_rx_init(struct s_smc *smc, int len, int fc,
pr_debug("fddi: Discard invalid local SMT frame\n");
pr_debug(" len=%d, la_len=%d, (ULONG) look_ahead=%08lXh.\n",
len, la_len, (unsigned long) look_ahead);
- return (0);
+ return 0;
}
skb = alloc_skb(len + 3, GFP_ATOMIC);
if (!skb) {
pr_debug("fddi: Local SMT: skb memory exhausted.\n");
- return (0);
+ return 0;
}
skb_reserve(skb, 3);
skb_put(skb, len);
@@ -1919,7 +1919,7 @@ int mac_drv_rx_init(struct s_smc *smc, int len, int fc,
skb->protocol = fddi_type_trans(skb, smc->os.dev);
netif_rx(skb);
- return (0);
+ return 0;
} // mac_drv_rx_init
@@ -2034,17 +2034,17 @@ void smt_stat_counter(struct s_smc *smc, int stat)
{
// BOOLEAN RingIsUp ;
- pr_debug(KERN_INFO "smt_stat_counter\n");
+ pr_debug("smt_stat_counter\n");
switch (stat) {
case 0:
- pr_debug(KERN_INFO "Ring operational change.\n");
+ pr_debug("Ring operational change.\n");
break;
case 1:
- pr_debug(KERN_INFO "Receive fifo overflow.\n");
+ pr_debug("Receive fifo overflow.\n");
smc->os.MacStat.gen.rx_errors++;
break;
default:
- pr_debug(KERN_INFO "Unknown status (%d).\n", stat);
+ pr_debug("Unknown status (%d).\n", stat);
break;
}
} // smt_stat_counter
@@ -2100,10 +2100,10 @@ void cfm_state_change(struct s_smc *smc, int c_state)
s = "SC11_C_WRAP_S";
break;
default:
- pr_debug(KERN_INFO "cfm_state_change: unknown %d\n", c_state);
+ pr_debug("cfm_state_change: unknown %d\n", c_state);
return;
}
- pr_debug(KERN_INFO "cfm_state_change: %s\n", s);
+ pr_debug("cfm_state_change: %s\n", s);
#endif // DRIVERDEBUG
} // cfm_state_change
@@ -2158,7 +2158,7 @@ void ecm_state_change(struct s_smc *smc, int e_state)
s = "unknown";
break;
}
- pr_debug(KERN_INFO "ecm_state_change: %s\n", s);
+ pr_debug("ecm_state_change: %s\n", s);
#endif //DRIVERDEBUG
} // ecm_state_change
@@ -2213,7 +2213,7 @@ void rmt_state_change(struct s_smc *smc, int r_state)
s = "unknown";
break;
}
- pr_debug(KERN_INFO "[rmt_state_change: %s]\n", s);
+ pr_debug("[rmt_state_change: %s]\n", s);
#endif // DRIVERDEBUG
} // rmt_state_change
@@ -2233,7 +2233,7 @@ void rmt_state_change(struct s_smc *smc, int r_state)
************************/
void drv_reset_indication(struct s_smc *smc)
{
- pr_debug(KERN_INFO "entering drv_reset_indication\n");
+ pr_debug("entering drv_reset_indication\n");
smc->os.ResetRequested = TRUE; // Set flag.
diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
index 6f35bb77595f..2d9941c045bc 100644
--- a/drivers/net/skfp/smt.c
+++ b/drivers/net/skfp/smt.c
@@ -127,22 +127,22 @@ static inline int is_my_addr(const struct s_smc *smc,
static inline int is_broadcast(const struct fddi_addr *addr)
{
- return(*(u_short *)(&addr->a[0]) == 0xffff &&
+ return *(u_short *)(&addr->a[0]) == 0xffff &&
*(u_short *)(&addr->a[2]) == 0xffff &&
- *(u_short *)(&addr->a[4]) == 0xffff ) ;
+ *(u_short *)(&addr->a[4]) == 0xffff;
}
static inline int is_individual(const struct fddi_addr *addr)
{
- return(!(addr->a[0] & GROUP_ADDR)) ;
+ return !(addr->a[0] & GROUP_ADDR);
}
static inline int is_equal(const struct fddi_addr *addr1,
const struct fddi_addr *addr2)
{
- return(*(u_short *)(&addr1->a[0]) == *(u_short *)(&addr2->a[0]) &&
+ return *(u_short *)(&addr1->a[0]) == *(u_short *)(&addr2->a[0]) &&
*(u_short *)(&addr1->a[2]) == *(u_short *)(&addr2->a[2]) &&
- *(u_short *)(&addr1->a[4]) == *(u_short *)(&addr2->a[4]) ) ;
+ *(u_short *)(&addr1->a[4]) == *(u_short *)(&addr2->a[4]);
}
/*
@@ -457,8 +457,8 @@ static int div_ratio(u_long upper, u_long lower)
else
upper <<= 16L ;
if (!lower)
- return(0) ;
- return((int)(upper/lower)) ;
+ return 0;
+ return (int)(upper/lower) ;
}
#ifndef SLIM_SMT
@@ -1111,11 +1111,11 @@ SMbuf *smt_build_frame(struct s_smc *smc, int class, int type,
#if 0
if (!smc->r.sm_ma_avail) {
- return(0) ;
+ return 0;
}
#endif
if (!(mb = smt_get_mbuf(smc)))
- return(mb) ;
+ return mb;
mb->sm_len = length ;
smt = smtod(mb, struct smt_header *) ;
@@ -1136,7 +1136,7 @@ SMbuf *smt_build_frame(struct s_smc *smc, int class, int type,
smt->smt_tid = smt_get_tid(smc) ; /* set transaction ID */
smt->smt_pad = 0 ;
smt->smt_len = length - sizeof(struct smt_header) ;
- return(mb) ;
+ return mb;
}
static void smt_add_frame_len(SMbuf *mb, int len)
@@ -1375,7 +1375,7 @@ static int smt_fill_path(struct s_smc *smc, struct smt_p_path *path)
pd_mac = (struct smt_mac_rec *) phy ;
pd_mac->mac_addr = smc->mib.m[MAC0].fddiMACSMTAddress ;
pd_mac->mac_resource_idx = mac_con_resource_index(smc,1) ;
- return(len) ;
+ return len;
}
/*
@@ -1563,7 +1563,7 @@ u_long smt_get_tid(struct s_smc *smc)
u_long tid ;
while ((tid = ++(smc->sm.smt_tid) ^ SMT_TID_MAGIC) == 0)
;
- return(tid & 0x3fffffffL) ;
+ return tid & 0x3fffffffL;
}
@@ -1654,11 +1654,11 @@ int smt_check_para(struct s_smc *smc, struct smt_header *sm,
while (*p) {
if (!sm_to_para(smc,sm,(int) *p)) {
DB_SMT("SMT: smt_check_para - missing para %x\n",*p,0);
- return(-1) ;
+ return -1;
}
p++ ;
}
- return(0) ;
+ return 0;
}
void *sm_to_para(struct s_smc *smc, struct smt_header *sm, int para)
@@ -1687,7 +1687,7 @@ void *sm_to_para(struct s_smc *smc, struct smt_header *sm, int para)
return NULL;
}
if (found)
- return(found) ;
+ return found;
}
return NULL;
}
@@ -1732,7 +1732,7 @@ char *addr_to_string(struct fddi_addr *addr)
string[i * 3 + 2] = ':';
}
string[5 * 3 + 2] = 0;
- return(string);
+ return string;
}
#endif
@@ -1742,9 +1742,9 @@ int smt_ifconfig(int argc, char *argv[])
if (argc >= 2 && !strcmp(argv[0],"opt_bypass") &&
!strcmp(argv[1],"yes")) {
smc->mib.fddiSMTBypassPresent = 1 ;
- return(0) ;
+ return 0;
}
- return(amdfddi_config(0,argc,argv)) ;
+ return amdfddi_config(0, argc, argv);
}
#endif
@@ -1756,9 +1756,9 @@ static int mac_index(struct s_smc *smc, int mac)
SK_UNUSED(mac) ;
#ifdef CONCENTRATOR
SK_UNUSED(smc) ;
- return(NUMPHYS+1) ;
+ return NUMPHYS + 1;
#else
- return((smc->s.sas == SMT_SAS) ? 2 : 3) ;
+ return (smc->s.sas == SMT_SAS) ? 2 : 3;
#endif
}
@@ -1768,7 +1768,7 @@ static int mac_index(struct s_smc *smc, int mac)
static int phy_index(struct s_smc *smc, int phy)
{
SK_UNUSED(smc) ;
- return(phy+1);
+ return phy + 1;
}
/*
@@ -1779,19 +1779,19 @@ static int mac_con_resource_index(struct s_smc *smc, int mac)
#ifdef CONCENTRATOR
SK_UNUSED(smc) ;
SK_UNUSED(mac) ;
- return(entity_to_index(smc,cem_get_downstream(smc,ENTITY_MAC))) ;
+ return entity_to_index(smc, cem_get_downstream(smc, ENTITY_MAC));
#else
SK_UNUSED(mac) ;
switch (smc->mib.fddiSMTCF_State) {
case SC9_C_WRAP_A :
case SC5_THRU_B :
case SC11_C_WRAP_S :
- return(1) ;
+ return 1;
case SC10_C_WRAP_B :
case SC4_THRU_A :
- return(2) ;
+ return 2;
}
- return(smc->s.sas == SMT_SAS ? 2 : 3) ;
+ return smc->s.sas == SMT_SAS ? 2 : 3;
#endif
}
@@ -1801,21 +1801,21 @@ static int mac_con_resource_index(struct s_smc *smc, int mac)
static int phy_con_resource_index(struct s_smc *smc, int phy)
{
#ifdef CONCENTRATOR
- return(entity_to_index(smc,cem_get_downstream(smc,ENTITY_PHY(phy)))) ;
+ return entity_to_index(smc, cem_get_downstream(smc, ENTITY_PHY(phy))) ;
#else
switch (smc->mib.fddiSMTCF_State) {
case SC9_C_WRAP_A :
- return(phy == PA ? 3 : 2) ;
+ return phy == PA ? 3 : 2;
case SC10_C_WRAP_B :
- return(phy == PA ? 1 : 3) ;
+ return phy == PA ? 1 : 3;
case SC4_THRU_A :
- return(phy == PA ? 3 : 1) ;
+ return phy == PA ? 3 : 1;
case SC5_THRU_B :
- return(phy == PA ? 2 : 3) ;
+ return phy == PA ? 2 : 3;
case SC11_C_WRAP_S :
- return(2) ;
+ return 2;
}
- return(phy) ;
+ return phy;
#endif
}
@@ -1823,16 +1823,16 @@ static int phy_con_resource_index(struct s_smc *smc, int phy)
static int entity_to_index(struct s_smc *smc, int e)
{
if (e == ENTITY_MAC)
- return(mac_index(smc,1)) ;
+ return mac_index(smc, 1);
else
- return(phy_index(smc,e - ENTITY_PHY(0))) ;
+ return phy_index(smc, e - ENTITY_PHY(0));
}
#endif
#ifdef LITTLE_ENDIAN
static int smt_swap_short(u_short s)
{
- return(((s>>8)&0xff)|((s&0xff)<<8)) ;
+ return ((s>>8)&0xff) | ((s&0xff)<<8);
}
void smt_swap_para(struct smt_header *sm, int len, int direction)
@@ -1996,7 +1996,7 @@ int smt_action(struct s_smc *smc, int class, int code, int index)
}
break ;
default :
- return(1) ;
+ return 1;
}
break ;
case SMT_PORT_ACTION :
@@ -2017,14 +2017,14 @@ int smt_action(struct s_smc *smc, int class, int code, int index)
event = PC_STOP ;
break ;
default :
- return(1) ;
+ return 1;
}
queue_event(smc,EVENT_PCM+index,event) ;
break ;
default :
- return(1) ;
+ return 1;
}
- return(0) ;
+ return 0;
}
/*
diff --git a/drivers/net/skfp/smtdef.c b/drivers/net/skfp/smtdef.c
index 4e07ff7073f1..1acab0b368e3 100644
--- a/drivers/net/skfp/smtdef.c
+++ b/drivers/net/skfp/smtdef.c
@@ -303,7 +303,7 @@ int smt_set_mac_opvalues(struct s_smc *smc)
FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_T_REQ,
smt_get_event_word(smc));
}
- return(st) ;
+ return st;
}
void smt_fixup_mib(struct s_smc *smc)
@@ -350,6 +350,6 @@ static int set_min_max(int maxflag, u_long mib, u_long limit, u_long *oper)
*oper = limit ;
else
*oper = mib ;
- return(old != *oper) ;
+ return old != *oper;
}
diff --git a/drivers/net/skfp/smtinit.c b/drivers/net/skfp/smtinit.c
index 3c8964ce1837..e3a0c0bc2233 100644
--- a/drivers/net/skfp/smtinit.c
+++ b/drivers/net/skfp/smtinit.c
@@ -120,6 +120,6 @@ int init_smt(struct s_smc *smc, u_char *mac_addr)
PNMI_INIT(smc) ; /* PNMI initialization */
- return(0) ;
+ return 0;
}
diff --git a/drivers/net/skfp/srf.c b/drivers/net/skfp/srf.c
index 40882b3faba6..f6f7baf9f27a 100644
--- a/drivers/net/skfp/srf.c
+++ b/drivers/net/skfp/srf.c
@@ -165,7 +165,7 @@ static struct s_srf_evc *smt_get_evc(struct s_smc *smc, int code, int index)
for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
if (evc->evc_code == code && evc->evc_index == index)
- return(evc) ;
+ return evc;
}
return NULL;
}
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 465ae7e84507..bfec2e0f5275 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -3179,8 +3179,7 @@ static int skge_poll(struct napi_struct *napi, int to_do)
skb = skge_rx_get(dev, e, control, rd->status, rd->csum2);
if (likely(skb)) {
- netif_receive_skb(skb);
-
+ napi_gro_receive(napi, skb);
++work_done;
}
}
@@ -3193,6 +3192,7 @@ static int skge_poll(struct napi_struct *napi, int to_do)
if (work_done < to_do) {
unsigned long flags;
+ napi_gro_flush(napi);
spin_lock_irqsave(&hw->hw_lock, flags);
__napi_complete(napi);
hw->intr_mask |= napimask[skge->port];
@@ -3850,6 +3850,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
skge->rx_csum = 1;
}
+ dev->features |= NETIF_F_GRO;
/* read the mac address */
memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN);
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 194e5cf8c763..d6577084ce70 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -1782,7 +1782,7 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
ctrl = 0;
#ifdef SKY2_VLAN_TAG_USED
/* Add VLAN tag, can piggyback on LRGLEN or ADDR64 */
- if (sky2->vlgrp && vlan_tx_tag_present(skb)) {
+ if (vlan_tx_tag_present(skb)) {
if (!le) {
le = get_tx_le(sky2, &slot);
le->addr = 0;
@@ -4581,7 +4581,8 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
sky2->port = port;
- dev->features |= NETIF_F_TSO | NETIF_F_IP_CSUM | NETIF_F_SG;
+ dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG
+ | NETIF_F_TSO | NETIF_F_GRO;
if (highmem)
dev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c
index ac279fad9d45..ab9e3b785b5b 100644
--- a/drivers/net/slhc.c
+++ b/drivers/net/slhc.c
@@ -688,18 +688,8 @@ slhc_toss(struct slcompress *comp)
return 0;
}
-
-/* VJ header compression */
-EXPORT_SYMBOL(slhc_init);
-EXPORT_SYMBOL(slhc_free);
-EXPORT_SYMBOL(slhc_remember);
-EXPORT_SYMBOL(slhc_compress);
-EXPORT_SYMBOL(slhc_uncompress);
-EXPORT_SYMBOL(slhc_toss);
-
#else /* CONFIG_INET */
-
int
slhc_toss(struct slcompress *comp)
{
@@ -738,6 +728,10 @@ slhc_init(int rslots, int tslots)
printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init");
return NULL;
}
+
+#endif /* CONFIG_INET */
+
+/* VJ header compression */
EXPORT_SYMBOL(slhc_init);
EXPORT_SYMBOL(slhc_free);
EXPORT_SYMBOL(slhc_remember);
@@ -745,5 +739,4 @@ EXPORT_SYMBOL(slhc_compress);
EXPORT_SYMBOL(slhc_uncompress);
EXPORT_SYMBOL(slhc_toss);
-#endif /* CONFIG_INET */
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index fa434fb8fb7c..86cbb9ea2f26 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -271,7 +271,7 @@ static int sl_realloc_bufs(struct slip *sl, int mtu)
memcpy(sl->xbuff, sl->xhead, sl->xleft);
} else {
sl->xleft = 0;
- sl->tx_dropped++;
+ dev->stats.tx_dropped++;
}
}
sl->xhead = sl->xbuff;
@@ -281,7 +281,7 @@ static int sl_realloc_bufs(struct slip *sl, int mtu)
memcpy(sl->rbuff, rbuff, sl->rcount);
} else {
sl->rcount = 0;
- sl->rx_over_errors++;
+ dev->stats.rx_over_errors++;
set_bit(SLF_ERROR, &sl->flags);
}
}
@@ -319,6 +319,7 @@ static inline void sl_unlock(struct slip *sl)
/* Send one completely decapsulated IP datagram to the IP layer. */
static void sl_bump(struct slip *sl)
{
+ struct net_device *dev = sl->dev;
struct sk_buff *skb;
int count;
@@ -329,13 +330,13 @@ static void sl_bump(struct slip *sl)
if (c & SL_TYPE_COMPRESSED_TCP) {
/* ignore compressed packets when CSLIP is off */
if (!(sl->mode & SL_MODE_CSLIP)) {
- printk(KERN_WARNING "%s: compressed packet ignored\n", sl->dev->name);
+ printk(KERN_WARNING "%s: compressed packet ignored\n", dev->name);
return;
}
/* make sure we've reserved enough space for uncompress
to use */
if (count + 80 > sl->buffsize) {
- sl->rx_over_errors++;
+ dev->stats.rx_over_errors++;
return;
}
count = slhc_uncompress(sl->slcomp, sl->rbuff, count);
@@ -346,7 +347,7 @@ static void sl_bump(struct slip *sl)
/* turn on header compression */
sl->mode |= SL_MODE_CSLIP;
sl->mode &= ~SL_MODE_ADAPTIVE;
- printk(KERN_INFO "%s: header compression turned on\n", sl->dev->name);
+ printk(KERN_INFO "%s: header compression turned on\n", dev->name);
}
sl->rbuff[0] &= 0x4f;
if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0)
@@ -355,20 +356,20 @@ static void sl_bump(struct slip *sl)
}
#endif /* SL_INCLUDE_CSLIP */
- sl->rx_bytes += count;
+ dev->stats.rx_bytes += count;
skb = dev_alloc_skb(count);
if (skb == NULL) {
- printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n", sl->dev->name);
- sl->rx_dropped++;
+ printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name);
+ dev->stats.rx_dropped++;
return;
}
- skb->dev = sl->dev;
+ skb->dev = dev;
memcpy(skb_put(skb, count), sl->rbuff, count);
skb_reset_mac_header(skb);
skb->protocol = htons(ETH_P_IP);
netif_rx(skb);
- sl->rx_packets++;
+ dev->stats.rx_packets++;
}
/* Encapsulate one IP datagram and stuff into a TTY queue. */
@@ -379,7 +380,7 @@ static void sl_encaps(struct slip *sl, unsigned char *icp, int len)
if (len > sl->mtu) { /* Sigh, shouldn't occur BUT ... */
printk(KERN_WARNING "%s: truncating oversized transmit packet!\n", sl->dev->name);
- sl->tx_dropped++;
+ sl->dev->stats.tx_dropped++;
sl_unlock(sl);
return;
}
@@ -433,7 +434,7 @@ static void slip_write_wakeup(struct tty_struct *tty)
if (sl->xleft <= 0) {
/* Now serial buffer is almost free & we can start
* transmission of another packet */
- sl->tx_packets++;
+ sl->dev->stats.tx_packets++;
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
sl_unlock(sl);
return;
@@ -496,7 +497,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev)
}
sl_lock(sl);
- sl->tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
sl_encaps(sl, skb->data, skb->len);
spin_unlock(&sl->lock);
@@ -558,39 +559,39 @@ static int sl_change_mtu(struct net_device *dev, int new_mtu)
/* Netdevice get statistics request */
-static struct net_device_stats *
-sl_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *
+sl_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
- static struct net_device_stats stats;
- struct slip *sl = netdev_priv(dev);
+ struct net_device_stats *devstats = &dev->stats;
+ unsigned long c_rx_dropped = 0;
#ifdef SL_INCLUDE_CSLIP
- struct slcompress *comp;
-#endif
+ 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;
- memset(&stats, 0, sizeof(struct net_device_stats));
-
- stats.rx_packets = sl->rx_packets;
- stats.tx_packets = sl->tx_packets;
- stats.rx_bytes = sl->rx_bytes;
- stats.tx_bytes = sl->tx_bytes;
- stats.rx_dropped = sl->rx_dropped;
- stats.tx_dropped = sl->tx_dropped;
- stats.tx_errors = sl->tx_errors;
- stats.rx_errors = sl->rx_errors;
- stats.rx_over_errors = sl->rx_over_errors;
-#ifdef SL_INCLUDE_CSLIP
- stats.rx_fifo_errors = sl->rx_compressed;
- stats.tx_fifo_errors = sl->tx_compressed;
- stats.collisions = sl->tx_misses;
- comp = sl->slcomp;
if (comp) {
- 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;
+ 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;
}
-#endif /* CONFIG_INET */
- return (&stats);
+ 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->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;
+
+ return stats;
}
/* Netdevice register callback */
@@ -633,7 +634,7 @@ static const struct net_device_ops sl_netdev_ops = {
.ndo_open = sl_open,
.ndo_stop = sl_close,
.ndo_start_xmit = sl_xmit,
- .ndo_get_stats = sl_get_stats,
+ .ndo_get_stats64 = sl_get_stats64,
.ndo_change_mtu = sl_change_mtu,
.ndo_tx_timeout = sl_tx_timeout,
#ifdef CONFIG_SLIP_SMART
@@ -681,7 +682,7 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
while (count--) {
if (fp && *fp++) {
if (!test_and_set_bit(SLF_ERROR, &sl->flags))
- sl->rx_errors++;
+ sl->dev->stats.rx_errors++;
cp++;
continue;
}
@@ -943,7 +944,7 @@ static int slip_esc(unsigned char *s, unsigned char *d, int len)
}
}
*ptr++ = END;
- return (ptr - d);
+ return ptr - d;
}
static void slip_unesc(struct slip *sl, unsigned char s)
@@ -981,7 +982,7 @@ static void slip_unesc(struct slip *sl, unsigned char s)
sl->rbuff[sl->rcount++] = s;
return;
}
- sl->rx_over_errors++;
+ sl->dev->stats.rx_over_errors++;
set_bit(SLF_ERROR, &sl->flags);
}
}
@@ -1057,7 +1058,7 @@ static void slip_unesc6(struct slip *sl, unsigned char s)
sl->rbuff[sl->rcount++] = c;
return;
}
- sl->rx_over_errors++;
+ sl->dev->stats.rx_over_errors++;
set_bit(SLF_ERROR, &sl->flags);
}
}
diff --git a/drivers/net/slip.h b/drivers/net/slip.h
index 9ea5c11287d2..914e958abbfc 100644
--- a/drivers/net/slip.h
+++ b/drivers/net/slip.h
@@ -67,15 +67,6 @@ struct slip {
int xleft; /* bytes left in XMIT queue */
/* SLIP interface statistics. */
- unsigned long rx_packets; /* inbound frames counter */
- unsigned long tx_packets; /* outbound frames counter */
- unsigned long rx_bytes; /* inbound byte counte */
- unsigned long tx_bytes; /* outbound byte counter */
- unsigned long rx_errors; /* Parity, etc. errors */
- unsigned long tx_errors; /* Planned stuff */
- unsigned long rx_dropped; /* No memory for skb */
- unsigned long tx_dropped; /* When MTU change */
- unsigned long rx_over_errors; /* Frame bigger than SLIP buf. */
#ifdef SL_INCLUDE_CSLIP
unsigned long tx_compressed;
unsigned long rx_compressed;
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index 8150ba154116..64bfdae5956f 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -1049,7 +1049,7 @@ static int smsc911x_poll(struct napi_struct *napi, int budget)
smsc911x_rx_readfifo(pdata, (unsigned int *)skb->head,
pktwords);
skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
netif_receive_skb(skb);
/* Update counters */
@@ -2075,7 +2075,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
} else {
/* Try reading mac address from device. if EEPROM is present
* it will already have been set */
- smsc911x_read_mac_address(dev);
+ smsc_get_mac(dev);
if (is_valid_ether_addr(dev->dev_addr)) {
/* eeprom values are valid so use them */
@@ -2176,6 +2176,7 @@ static struct platform_driver smsc911x_driver = {
/* Entry point for loading the module */
static int __init smsc911x_init_module(void)
{
+ SMSC_INITIALIZE();
return platform_driver_register(&smsc911x_driver);
}
diff --git a/drivers/net/smsc911x.h b/drivers/net/smsc911x.h
index 016360c65ce2..52f38e12a879 100644
--- a/drivers/net/smsc911x.h
+++ b/drivers/net/smsc911x.h
@@ -394,4 +394,15 @@
#define LPA_PAUSE_ALL (LPA_PAUSE_CAP | \
LPA_PAUSE_ASYM)
+/*
+ * Provide hooks to let the arch add to the initialisation procedure
+ * and to override the source of the MAC address.
+ */
+#define SMSC_INITIALIZE() do {} while (0)
+#define smsc_get_mac(dev) smsc911x_read_mac_address((dev))
+
+#ifdef CONFIG_SMSC911X_ARCH_HOOKS
+#include <asm/smsc911x.h>
+#endif
+
#endif /* __SMSC911X_H__ */
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 1636a34d95dd..cb6bcca9d541 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -1000,9 +1000,9 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
!(data_error & SPIDER_NET_DATA_ERR_CKSUM_MASK))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
} else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
if (data_status & SPIDER_NET_VLAN_PACKET) {
/* further enhancements: HW-accel VLAN
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index a42b6873370b..4adf12422787 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -148,7 +148,7 @@ static int full_duplex[MAX_UNITS] = {0, };
* This SUCKS.
* We need a much better method to determine if dma_addr_t is 64-bit.
*/
-#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR))
+#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) || (defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT))
/* 64-bit dma_addr_t */
#define ADDR_64BITS /* This chip uses 64 bit addresses. */
#define netdrv_addr_t __le64
@@ -302,7 +302,7 @@ enum chipset {
};
static DEFINE_PCI_DEVICE_TABLE(starfire_pci_tbl) = {
- { 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 },
+ { PCI_VDEVICE(ADAPTEC, 0x6915), CH_6915 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, starfire_pci_tbl);
@@ -2078,11 +2078,7 @@ static int __init starfire_init (void)
printk(KERN_INFO DRV_NAME ": polling (NAPI) enabled\n");
#endif
- /* we can do this test only at run-time... sigh */
- if (sizeof(dma_addr_t) != sizeof(netdrv_addr_t)) {
- printk("This driver has dma_addr_t issues, please send email to maintainer\n");
- return -ENODEV;
- }
+ BUILD_BUG_ON(sizeof(dma_addr_t) != sizeof(netdrv_addr_t));
return pci_register_driver(&starfire_driver);
}
diff --git a/drivers/net/stmmac/Kconfig b/drivers/net/stmmac/Kconfig
index eb63d44748a7..7df7df4e79c5 100644
--- a/drivers/net/stmmac/Kconfig
+++ b/drivers/net/stmmac/Kconfig
@@ -3,10 +3,10 @@ config STMMAC_ETH
select MII
select PHYLIB
select CRC32
- depends on NETDEVICES && CPU_SUBTYPE_ST40
+ depends on NETDEVICES && HAS_IOMEM
help
This is the driver for the Ethernet IPs are built around a
- Synopsys IP Core and fully tested on the STMicroelectronics
+ Synopsys IP Core and only tested on the STMicroelectronics
platforms.
if STMMAC_ETH
@@ -32,6 +32,7 @@ config STMMAC_DUAL_MAC
config STMMAC_TIMER
bool "STMMAC Timer optimisation"
default n
+ depends on RTC_HCTOSYS_DEVICE
help
Use an external timer for mitigating the number of network
interrupts. Currently, for SH architectures, it is possible
diff --git a/drivers/net/stmmac/common.h b/drivers/net/stmmac/common.h
index 66b9da0260fe..375ea193e139 100644
--- a/drivers/net/stmmac/common.h
+++ b/drivers/net/stmmac/common.h
@@ -102,8 +102,6 @@ struct stmmac_extra_stats {
#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
-#define HW_CSUM 1
-#define NO_HW_CSUM 0
enum rx_frame_status { /* IPC status */
good_frame = 0,
discard_frame = 1,
@@ -167,7 +165,7 @@ struct stmmac_desc_ops {
int (*get_tx_ls) (struct dma_desc *p);
/* Return the transmit status looking at the TDES1 */
int (*tx_status) (void *data, struct stmmac_extra_stats *x,
- struct dma_desc *p, unsigned long ioaddr);
+ struct dma_desc *p, void __iomem *ioaddr);
/* Get the buffer size from the descriptor */
int (*get_tx_len) (struct dma_desc *p);
/* Handle extra events on specific interrupts hw dependent */
@@ -182,44 +180,46 @@ struct stmmac_desc_ops {
struct stmmac_dma_ops {
/* DMA core initialization */
- int (*init) (unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx);
+ int (*init) (void __iomem *ioaddr, int pbl, u32 dma_tx, u32 dma_rx);
/* Dump DMA registers */
- void (*dump_regs) (unsigned long ioaddr);
+ void (*dump_regs) (void __iomem *ioaddr);
/* Set tx/rx threshold in the csr6 register
* An invalid value enables the store-and-forward mode */
- void (*dma_mode) (unsigned long ioaddr, int txmode, int rxmode);
+ void (*dma_mode) (void __iomem *ioaddr, int txmode, int rxmode);
/* To track extra statistic (if supported) */
void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
- unsigned long ioaddr);
- void (*enable_dma_transmission) (unsigned long ioaddr);
- void (*enable_dma_irq) (unsigned long ioaddr);
- void (*disable_dma_irq) (unsigned long ioaddr);
- void (*start_tx) (unsigned long ioaddr);
- void (*stop_tx) (unsigned long ioaddr);
- void (*start_rx) (unsigned long ioaddr);
- void (*stop_rx) (unsigned long ioaddr);
- int (*dma_interrupt) (unsigned long ioaddr,
+ void __iomem *ioaddr);
+ void (*enable_dma_transmission) (void __iomem *ioaddr);
+ void (*enable_dma_irq) (void __iomem *ioaddr);
+ void (*disable_dma_irq) (void __iomem *ioaddr);
+ void (*start_tx) (void __iomem *ioaddr);
+ void (*stop_tx) (void __iomem *ioaddr);
+ void (*start_rx) (void __iomem *ioaddr);
+ void (*stop_rx) (void __iomem *ioaddr);
+ int (*dma_interrupt) (void __iomem *ioaddr,
struct stmmac_extra_stats *x);
};
struct stmmac_ops {
/* MAC core initialization */
- void (*core_init) (unsigned long ioaddr) ____cacheline_aligned;
+ void (*core_init) (void __iomem *ioaddr) ____cacheline_aligned;
+ /* Support checksum offload engine */
+ int (*rx_coe) (void __iomem *ioaddr);
/* Dump MAC registers */
- void (*dump_regs) (unsigned long ioaddr);
+ void (*dump_regs) (void __iomem *ioaddr);
/* Handle extra events on specific interrupts hw dependent */
- void (*host_irq_status) (unsigned long ioaddr);
+ void (*host_irq_status) (void __iomem *ioaddr);
/* Multicast filter setting */
void (*set_filter) (struct net_device *dev);
/* Flow control setting */
- void (*flow_ctrl) (unsigned long ioaddr, unsigned int duplex,
+ void (*flow_ctrl) (void __iomem *ioaddr, unsigned int duplex,
unsigned int fc, unsigned int pause_time);
/* Set power management mode (e.g. magic frame) */
- void (*pmt) (unsigned long ioaddr, unsigned long mode);
+ void (*pmt) (void __iomem *ioaddr, unsigned long mode);
/* Set/Get Unicast MAC addresses */
- void (*set_umac_addr) (unsigned long ioaddr, unsigned char *addr,
+ void (*set_umac_addr) (void __iomem *ioaddr, unsigned char *addr,
unsigned int reg_n);
- void (*get_umac_addr) (unsigned long ioaddr, unsigned char *addr,
+ void (*get_umac_addr) (void __iomem *ioaddr, unsigned char *addr,
unsigned int reg_n);
};
@@ -235,19 +235,18 @@ struct mii_regs {
};
struct mac_device_info {
- struct stmmac_ops *mac;
- struct stmmac_desc_ops *desc;
- struct stmmac_dma_ops *dma;
- unsigned int pmt; /* support Power-Down */
+ const struct stmmac_ops *mac;
+ const struct stmmac_desc_ops *desc;
+ const struct stmmac_dma_ops *dma;
struct mii_regs mii; /* MII register Addresses */
struct mac_link link;
};
-struct mac_device_info *dwmac1000_setup(unsigned long addr);
-struct mac_device_info *dwmac100_setup(unsigned long addr);
+struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr);
+struct mac_device_info *dwmac100_setup(void __iomem *ioaddr);
-extern void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6],
+extern void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
unsigned int high, unsigned int low);
-extern void stmmac_get_mac_addr(unsigned long ioaddr, unsigned char *addr,
+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(unsigned long ioaddr);
+extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
diff --git a/drivers/net/stmmac/dwmac100.h b/drivers/net/stmmac/dwmac100.h
index 97956cbf1cb4..7c6d857a9cc7 100644
--- a/drivers/net/stmmac/dwmac100.h
+++ b/drivers/net/stmmac/dwmac100.h
@@ -118,4 +118,4 @@ enum ttc_control {
#define DMA_MISSED_FRAME_OVE_M 0x00010000 /* Missed Frame Overflow */
#define DMA_MISSED_FRAME_M_CNTR 0x0000ffff /* Missed Frame Couinter */
-extern struct stmmac_dma_ops dwmac100_dma_ops;
+extern const struct stmmac_dma_ops dwmac100_dma_ops;
diff --git a/drivers/net/stmmac/dwmac1000.h b/drivers/net/stmmac/dwmac1000.h
index 8b20b19971cb..cfcef0ea0fa5 100644
--- a/drivers/net/stmmac/dwmac1000.h
+++ b/drivers/net/stmmac/dwmac1000.h
@@ -99,7 +99,7 @@ enum inter_frame_gap {
#define GMAC_CONTROL_RE 0x00000004 /* Receiver Enable */
#define GMAC_CORE_INIT (GMAC_CONTROL_JD | GMAC_CONTROL_PS | GMAC_CONTROL_ACS | \
- GMAC_CONTROL_IPC | GMAC_CONTROL_JE | GMAC_CONTROL_BE)
+ GMAC_CONTROL_JE | GMAC_CONTROL_BE)
/* GMAC Frame Filter defines */
#define GMAC_FRAME_FILTER_PR 0x00000001 /* Promiscuous Mode */
@@ -205,4 +205,4 @@ enum rtc_control {
#define GMAC_MMC_TX_INTR 0x108
#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
-extern struct stmmac_dma_ops dwmac1000_dma_ops;
+extern const struct stmmac_dma_ops dwmac1000_dma_ops;
diff --git a/drivers/net/stmmac/dwmac1000_core.c b/drivers/net/stmmac/dwmac1000_core.c
index 2b2f5c8caf1c..6ae4c3f4c63c 100644
--- a/drivers/net/stmmac/dwmac1000_core.c
+++ b/drivers/net/stmmac/dwmac1000_core.c
@@ -30,7 +30,7 @@
#include <linux/slab.h>
#include "dwmac1000.h"
-static void dwmac1000_core_init(unsigned long ioaddr)
+static void dwmac1000_core_init(void __iomem *ioaddr)
{
u32 value = readl(ioaddr + GMAC_CONTROL);
value |= GMAC_CORE_INIT;
@@ -50,10 +50,22 @@ static void dwmac1000_core_init(unsigned long ioaddr)
#endif
}
-static void dwmac1000_dump_regs(unsigned long ioaddr)
+static int dwmac1000_rx_coe_supported(void __iomem *ioaddr)
+{
+ u32 value = readl(ioaddr + GMAC_CONTROL);
+
+ value |= GMAC_CONTROL_IPC;
+ writel(value, ioaddr + GMAC_CONTROL);
+
+ value = readl(ioaddr + GMAC_CONTROL);
+
+ return !!(value & GMAC_CONTROL_IPC);
+}
+
+static void dwmac1000_dump_regs(void __iomem *ioaddr)
{
int i;
- pr_info("\tDWMAC1000 regs (base addr = 0x%8x)\n", (unsigned int)ioaddr);
+ pr_info("\tDWMAC1000 regs (base addr = 0x%p)\n", ioaddr);
for (i = 0; i < 55; i++) {
int offset = i * 4;
@@ -62,14 +74,14 @@ static void dwmac1000_dump_regs(unsigned long ioaddr)
}
}
-static void dwmac1000_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
+static void dwmac1000_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
unsigned int reg_n)
{
stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
GMAC_ADDR_LOW(reg_n));
}
-static void dwmac1000_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
+static void dwmac1000_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
unsigned int reg_n)
{
stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
@@ -78,7 +90,7 @@ static void dwmac1000_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
static void dwmac1000_set_filter(struct net_device *dev)
{
- unsigned long ioaddr = dev->base_addr;
+ void __iomem *ioaddr = (void __iomem *) dev->base_addr;
unsigned int value = 0;
CHIP_DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n",
@@ -139,7 +151,7 @@ static void dwmac1000_set_filter(struct net_device *dev)
readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW));
}
-static void dwmac1000_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
+static void dwmac1000_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
unsigned int fc, unsigned int pause_time)
{
unsigned int flow = 0;
@@ -162,7 +174,7 @@ static void dwmac1000_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
writel(flow, ioaddr + GMAC_FLOW_CTRL);
}
-static void dwmac1000_pmt(unsigned long ioaddr, unsigned long mode)
+static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
{
unsigned int pmt = 0;
@@ -178,7 +190,7 @@ static void dwmac1000_pmt(unsigned long ioaddr, unsigned long mode)
}
-static void dwmac1000_irq_status(unsigned long ioaddr)
+static void dwmac1000_irq_status(void __iomem *ioaddr)
{
u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
@@ -200,8 +212,9 @@ static void dwmac1000_irq_status(unsigned long ioaddr)
}
}
-struct stmmac_ops dwmac1000_ops = {
+static const struct stmmac_ops dwmac1000_ops = {
.core_init = dwmac1000_core_init,
+ .rx_coe = dwmac1000_rx_coe_supported,
.dump_regs = dwmac1000_dump_regs,
.host_irq_status = dwmac1000_irq_status,
.set_filter = dwmac1000_set_filter,
@@ -211,7 +224,7 @@ struct stmmac_ops dwmac1000_ops = {
.get_umac_addr = dwmac1000_get_umac_addr,
};
-struct mac_device_info *dwmac1000_setup(unsigned long ioaddr)
+struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
{
struct mac_device_info *mac;
u32 uid = readl(ioaddr + GMAC_VERSION);
@@ -226,7 +239,6 @@ struct mac_device_info *dwmac1000_setup(unsigned long ioaddr)
mac->mac = &dwmac1000_ops;
mac->dma = &dwmac1000_dma_ops;
- mac->pmt = PMT_SUPPORTED;
mac->link.port = GMAC_CONTROL_PS;
mac->link.duplex = GMAC_CONTROL_DM;
mac->link.speed = GMAC_CONTROL_FES;
diff --git a/drivers/net/stmmac/dwmac1000_dma.c b/drivers/net/stmmac/dwmac1000_dma.c
index 415805057cb0..2c47712d45d0 100644
--- a/drivers/net/stmmac/dwmac1000_dma.c
+++ b/drivers/net/stmmac/dwmac1000_dma.c
@@ -29,14 +29,22 @@
#include "dwmac1000.h"
#include "dwmac_dma.h"
-static int dwmac1000_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
+static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx,
u32 dma_rx)
{
u32 value = readl(ioaddr + DMA_BUS_MODE);
+ int limit;
+
/* DMA SW reset */
value |= DMA_BUS_MODE_SFT_RESET;
writel(value, ioaddr + DMA_BUS_MODE);
- do {} while ((readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET));
+ limit = 15000;
+ while (limit--) {
+ if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
+ break;
+ }
+ if (limit < 0)
+ return -EBUSY;
value = /* DMA_BUS_MODE_FB | */ DMA_BUS_MODE_4PBL |
((pbl << DMA_BUS_MODE_PBL_SHIFT) |
@@ -58,7 +66,7 @@ static int dwmac1000_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
return 0;
}
-static void dwmac1000_dma_operation_mode(unsigned long ioaddr, int txmode,
+static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
int rxmode)
{
u32 csr6 = readl(ioaddr + DMA_CONTROL);
@@ -111,12 +119,12 @@ static void dwmac1000_dma_operation_mode(unsigned long ioaddr, int txmode,
/* Not yet implemented --- no RMON module */
static void dwmac1000_dma_diagnostic_fr(void *data,
- struct stmmac_extra_stats *x, unsigned long ioaddr)
+ struct stmmac_extra_stats *x, void __iomem *ioaddr)
{
return;
}
-static void dwmac1000_dump_dma_regs(unsigned long ioaddr)
+static void dwmac1000_dump_dma_regs(void __iomem *ioaddr)
{
int i;
pr_info(" DMA registers\n");
@@ -130,7 +138,7 @@ static void dwmac1000_dump_dma_regs(unsigned long ioaddr)
}
}
-struct stmmac_dma_ops dwmac1000_dma_ops = {
+const struct stmmac_dma_ops dwmac1000_dma_ops = {
.init = dwmac1000_dma_init,
.dump_regs = dwmac1000_dump_dma_regs,
.dma_mode = dwmac1000_dma_operation_mode,
diff --git a/drivers/net/stmmac/dwmac100_core.c b/drivers/net/stmmac/dwmac100_core.c
index 2fb165fa2ba0..c724fc36a24f 100644
--- a/drivers/net/stmmac/dwmac100_core.c
+++ b/drivers/net/stmmac/dwmac100_core.c
@@ -31,7 +31,7 @@
#include <linux/crc32.h>
#include "dwmac100.h"
-static void dwmac100_core_init(unsigned long ioaddr)
+static void dwmac100_core_init(void __iomem *ioaddr)
{
u32 value = readl(ioaddr + MAC_CONTROL);
@@ -42,12 +42,17 @@ static void dwmac100_core_init(unsigned long ioaddr)
#endif
}
-static void dwmac100_dump_mac_regs(unsigned long ioaddr)
+static int dwmac100_rx_coe_supported(void __iomem *ioaddr)
+{
+ return 0;
+}
+
+static void dwmac100_dump_mac_regs(void __iomem *ioaddr)
{
pr_info("\t----------------------------------------------\n"
- "\t DWMAC 100 CSR (base addr = 0x%8x)\n"
+ "\t DWMAC 100 CSR (base addr = 0x%p)\n"
"\t----------------------------------------------\n",
- (unsigned int)ioaddr);
+ ioaddr);
pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL,
readl(ioaddr + MAC_CONTROL));
pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", MAC_ADDR_HIGH,
@@ -77,18 +82,18 @@ static void dwmac100_dump_mac_regs(unsigned long ioaddr)
MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK));
}
-static void dwmac100_irq_status(unsigned long ioaddr)
+static void dwmac100_irq_status(void __iomem *ioaddr)
{
return;
}
-static void dwmac100_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
+static void dwmac100_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
unsigned int reg_n)
{
stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
}
-static void dwmac100_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
+static void dwmac100_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
unsigned int reg_n)
{
stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
@@ -96,7 +101,7 @@ static void dwmac100_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
static void dwmac100_set_filter(struct net_device *dev)
{
- unsigned long ioaddr = dev->base_addr;
+ void __iomem *ioaddr = (void __iomem *) dev->base_addr;
u32 value = readl(ioaddr + MAC_CONTROL);
if (dev->flags & IFF_PROMISC) {
@@ -145,7 +150,7 @@ static void dwmac100_set_filter(struct net_device *dev)
readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW));
}
-static void dwmac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
+static void dwmac100_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
unsigned int fc, unsigned int pause_time)
{
unsigned int flow = MAC_FLOW_CTRL_ENABLE;
@@ -158,13 +163,14 @@ static void dwmac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
/* No PMT module supported for this Ethernet Controller.
* Tested on ST platforms only.
*/
-static void dwmac100_pmt(unsigned long ioaddr, unsigned long mode)
+static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode)
{
return;
}
-struct stmmac_ops dwmac100_ops = {
+static const struct stmmac_ops dwmac100_ops = {
.core_init = dwmac100_core_init,
+ .rx_coe = dwmac100_rx_coe_supported,
.dump_regs = dwmac100_dump_mac_regs,
.host_irq_status = dwmac100_irq_status,
.set_filter = dwmac100_set_filter,
@@ -174,7 +180,7 @@ struct stmmac_ops dwmac100_ops = {
.get_umac_addr = dwmac100_get_umac_addr,
};
-struct mac_device_info *dwmac100_setup(unsigned long ioaddr)
+struct mac_device_info *dwmac100_setup(void __iomem *ioaddr)
{
struct mac_device_info *mac;
@@ -187,7 +193,6 @@ struct mac_device_info *dwmac100_setup(unsigned long ioaddr)
mac->mac = &dwmac100_ops;
mac->dma = &dwmac100_dma_ops;
- mac->pmt = PMT_NOT_SUPPORTED;
mac->link.port = MAC_CONTROL_PS;
mac->link.duplex = MAC_CONTROL_F;
mac->link.speed = 0;
diff --git a/drivers/net/stmmac/dwmac100_dma.c b/drivers/net/stmmac/dwmac100_dma.c
index 2fece7b72727..e3e224b7d9e2 100644
--- a/drivers/net/stmmac/dwmac100_dma.c
+++ b/drivers/net/stmmac/dwmac100_dma.c
@@ -31,14 +31,22 @@
#include "dwmac100.h"
#include "dwmac_dma.h"
-static int dwmac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
+static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx,
u32 dma_rx)
{
u32 value = readl(ioaddr + DMA_BUS_MODE);
+ int limit;
+
/* DMA SW reset */
value |= DMA_BUS_MODE_SFT_RESET;
writel(value, ioaddr + DMA_BUS_MODE);
- do {} while ((readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET));
+ limit = 15000;
+ while (limit--) {
+ if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
+ break;
+ }
+ if (limit < 0)
+ return -EBUSY;
/* Enable Application Access by writing to DMA CSR0 */
writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT),
@@ -58,7 +66,7 @@ static int dwmac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
/* Store and Forward capability is not used at all..
* The transmit threshold can be programmed by
* setting the TTC bits in the DMA control register.*/
-static void dwmac100_dma_operation_mode(unsigned long ioaddr, int txmode,
+static void dwmac100_dma_operation_mode(void __iomem *ioaddr, int txmode,
int rxmode)
{
u32 csr6 = readl(ioaddr + DMA_CONTROL);
@@ -73,7 +81,7 @@ static void dwmac100_dma_operation_mode(unsigned long ioaddr, int txmode,
writel(csr6, ioaddr + DMA_CONTROL);
}
-static void dwmac100_dump_dma_regs(unsigned long ioaddr)
+static void dwmac100_dump_dma_regs(void __iomem *ioaddr)
{
int i;
@@ -91,7 +99,7 @@ static void dwmac100_dump_dma_regs(unsigned long ioaddr)
/* DMA controller has two counters to track the number of
* the receive missed frames. */
static void dwmac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
- unsigned long ioaddr)
+ void __iomem *ioaddr)
{
struct net_device_stats *stats = (struct net_device_stats *)data;
u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
@@ -118,7 +126,7 @@ static void dwmac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
}
}
-struct stmmac_dma_ops dwmac100_dma_ops = {
+const struct stmmac_dma_ops dwmac100_dma_ops = {
.init = dwmac100_dma_init,
.dump_regs = dwmac100_dump_dma_regs,
.dma_mode = dwmac100_dma_operation_mode,
diff --git a/drivers/net/stmmac/dwmac_dma.h b/drivers/net/stmmac/dwmac_dma.h
index 7b815a1b7b8c..da3f5ccf83d3 100644
--- a/drivers/net/stmmac/dwmac_dma.h
+++ b/drivers/net/stmmac/dwmac_dma.h
@@ -97,12 +97,12 @@
#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */
#define DMA_CONTROL_FTF 0x00100000 /* Flush transmit FIFO */
-extern void dwmac_enable_dma_transmission(unsigned long ioaddr);
-extern void dwmac_enable_dma_irq(unsigned long ioaddr);
-extern void dwmac_disable_dma_irq(unsigned long ioaddr);
-extern void dwmac_dma_start_tx(unsigned long ioaddr);
-extern void dwmac_dma_stop_tx(unsigned long ioaddr);
-extern void dwmac_dma_start_rx(unsigned long ioaddr);
-extern void dwmac_dma_stop_rx(unsigned long ioaddr);
-extern int dwmac_dma_interrupt(unsigned long ioaddr,
+extern void dwmac_enable_dma_transmission(void __iomem *ioaddr);
+extern void dwmac_enable_dma_irq(void __iomem *ioaddr);
+extern void dwmac_disable_dma_irq(void __iomem *ioaddr);
+extern void dwmac_dma_start_tx(void __iomem *ioaddr);
+extern void dwmac_dma_stop_tx(void __iomem *ioaddr);
+extern void dwmac_dma_start_rx(void __iomem *ioaddr);
+extern void dwmac_dma_stop_rx(void __iomem *ioaddr);
+extern int dwmac_dma_interrupt(void __iomem *ioaddr,
struct stmmac_extra_stats *x);
diff --git a/drivers/net/stmmac/dwmac_lib.c b/drivers/net/stmmac/dwmac_lib.c
index a85415216ef4..d65fab1ba790 100644
--- a/drivers/net/stmmac/dwmac_lib.c
+++ b/drivers/net/stmmac/dwmac_lib.c
@@ -32,43 +32,43 @@
#endif
/* CSR1 enables the transmit DMA to check for new descriptor */
-void dwmac_enable_dma_transmission(unsigned long ioaddr)
+void dwmac_enable_dma_transmission(void __iomem *ioaddr)
{
writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
}
-void dwmac_enable_dma_irq(unsigned long ioaddr)
+void dwmac_enable_dma_irq(void __iomem *ioaddr)
{
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
}
-void dwmac_disable_dma_irq(unsigned long ioaddr)
+void dwmac_disable_dma_irq(void __iomem *ioaddr)
{
writel(0, ioaddr + DMA_INTR_ENA);
}
-void dwmac_dma_start_tx(unsigned long ioaddr)
+void dwmac_dma_start_tx(void __iomem *ioaddr)
{
u32 value = readl(ioaddr + DMA_CONTROL);
value |= DMA_CONTROL_ST;
writel(value, ioaddr + DMA_CONTROL);
}
-void dwmac_dma_stop_tx(unsigned long ioaddr)
+void dwmac_dma_stop_tx(void __iomem *ioaddr)
{
u32 value = readl(ioaddr + DMA_CONTROL);
value &= ~DMA_CONTROL_ST;
writel(value, ioaddr + DMA_CONTROL);
}
-void dwmac_dma_start_rx(unsigned long ioaddr)
+void dwmac_dma_start_rx(void __iomem *ioaddr)
{
u32 value = readl(ioaddr + DMA_CONTROL);
value |= DMA_CONTROL_SR;
writel(value, ioaddr + DMA_CONTROL);
}
-void dwmac_dma_stop_rx(unsigned long ioaddr)
+void dwmac_dma_stop_rx(void __iomem *ioaddr)
{
u32 value = readl(ioaddr + DMA_CONTROL);
value &= ~DMA_CONTROL_SR;
@@ -145,7 +145,7 @@ static void show_rx_process_state(unsigned int status)
}
#endif
-int dwmac_dma_interrupt(unsigned long ioaddr,
+int dwmac_dma_interrupt(void __iomem *ioaddr,
struct stmmac_extra_stats *x)
{
int ret = 0;
@@ -219,7 +219,7 @@ int dwmac_dma_interrupt(unsigned long ioaddr,
return ret;
}
-void dwmac_dma_flush_tx_fifo(unsigned long ioaddr)
+void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr)
{
u32 csr6 = readl(ioaddr + DMA_CONTROL);
writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);
@@ -227,7 +227,7 @@ void dwmac_dma_flush_tx_fifo(unsigned long ioaddr)
do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));
}
-void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6],
+void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
unsigned int high, unsigned int low)
{
unsigned long data;
@@ -238,7 +238,7 @@ void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6],
writel(data, ioaddr + low);
}
-void stmmac_get_mac_addr(unsigned long ioaddr, unsigned char *addr,
+void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
unsigned int high, unsigned int low)
{
unsigned int hi_addr, lo_addr;
diff --git a/drivers/net/stmmac/enh_desc.c b/drivers/net/stmmac/enh_desc.c
index f612f986a7e1..e5dfb6a30182 100644
--- a/drivers/net/stmmac/enh_desc.c
+++ b/drivers/net/stmmac/enh_desc.c
@@ -25,7 +25,7 @@
#include "common.h"
static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
- struct dma_desc *p, unsigned long ioaddr)
+ struct dma_desc *p, void __iomem *ioaddr)
{
int ret = 0;
struct net_device_stats *stats = (struct net_device_stats *)data;
@@ -284,7 +284,7 @@ static void enh_desc_release_tx_desc(struct dma_desc *p)
{
int ter = p->des01.etx.end_ring;
- memset(p, 0, sizeof(struct dma_desc));
+ memset(p, 0, offsetof(struct dma_desc, des2));
p->des01.etx.end_ring = ter;
}
@@ -318,7 +318,7 @@ static int enh_desc_get_rx_frame_len(struct dma_desc *p)
return p->des01.erx.frame_length;
}
-struct stmmac_desc_ops enh_desc_ops = {
+const struct stmmac_desc_ops enh_desc_ops = {
.tx_status = enh_desc_get_tx_status,
.rx_status = enh_desc_get_rx_status,
.get_tx_len = enh_desc_get_tx_len,
diff --git a/drivers/net/stmmac/norm_desc.c b/drivers/net/stmmac/norm_desc.c
index 31ad53643792..cd0cc76f7a1c 100644
--- a/drivers/net/stmmac/norm_desc.c
+++ b/drivers/net/stmmac/norm_desc.c
@@ -25,7 +25,7 @@
#include "common.h"
static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
- struct dma_desc *p, unsigned long ioaddr)
+ struct dma_desc *p, void __iomem *ioaddr)
{
int ret = 0;
struct net_device_stats *stats = (struct net_device_stats *)data;
@@ -174,22 +174,7 @@ static void ndesc_release_tx_desc(struct dma_desc *p)
{
int ter = p->des01.tx.end_ring;
- /* clean field used within the xmit */
- p->des01.tx.first_segment = 0;
- p->des01.tx.last_segment = 0;
- p->des01.tx.buffer1_size = 0;
-
- /* clean status reported */
- p->des01.tx.error_summary = 0;
- p->des01.tx.underflow_error = 0;
- p->des01.tx.no_carrier = 0;
- p->des01.tx.loss_carrier = 0;
- p->des01.tx.excessive_deferral = 0;
- p->des01.tx.excessive_collisions = 0;
- p->des01.tx.late_collision = 0;
- p->des01.tx.heartbeat_fail = 0;
- p->des01.tx.deferred = 0;
-
+ memset(p, 0, offsetof(struct dma_desc, des2));
/* set termination field */
p->des01.tx.end_ring = ter;
}
@@ -217,7 +202,7 @@ static int ndesc_get_rx_frame_len(struct dma_desc *p)
return p->des01.rx.frame_length;
}
-struct stmmac_desc_ops ndesc_ops = {
+const struct stmmac_desc_ops ndesc_ops = {
.tx_status = ndesc_get_tx_status,
.rx_status = ndesc_get_rx_status,
.get_tx_len = ndesc_get_tx_len,
diff --git a/drivers/net/stmmac/stmmac.h b/drivers/net/stmmac/stmmac.h
index ebebc644b1b8..79bdc2e13224 100644
--- a/drivers/net/stmmac/stmmac.h
+++ b/drivers/net/stmmac/stmmac.h
@@ -21,6 +21,7 @@
*******************************************************************************/
#define DRV_MODULE_VERSION "Apr_2010"
+#include <linux/platform_device.h>
#include <linux/stmmac.h>
#include "common.h"
@@ -50,10 +51,10 @@ struct stmmac_priv {
int is_gmac;
dma_addr_t dma_rx_phy;
unsigned int dma_rx_size;
- int rx_csum;
unsigned int dma_buf_sz;
struct device *device;
struct mac_device_info *hw;
+ void __iomem *ioaddr;
struct stmmac_extra_stats xstats;
struct napi_struct napi;
@@ -65,7 +66,7 @@ struct stmmac_priv {
int phy_mask;
int (*phy_reset) (void *priv);
void (*fix_mac_speed) (void *priv, unsigned int speed);
- void (*bus_setup)(unsigned long ioaddr);
+ void (*bus_setup)(void __iomem *ioaddr);
void *bsp_priv;
int phy_irq;
@@ -76,6 +77,7 @@ struct stmmac_priv {
unsigned int flow_ctrl;
unsigned int pause;
struct mii_bus *mii;
+ int mii_clk_csr;
u32 msg_enable;
spinlock_t lock;
@@ -89,6 +91,9 @@ struct stmmac_priv {
struct vlan_group *vlgrp;
#endif
int enh_desc;
+ int rx_coe;
+ int bugged_jumbo;
+ int no_csum_insertion;
};
#ifdef CONFIG_STM_DRIVERS
@@ -116,5 +121,5 @@ static inline int stmmac_claim_resource(struct platform_device *pdev)
extern int stmmac_mdio_unregister(struct net_device *ndev);
extern int stmmac_mdio_register(struct net_device *ndev);
extern void stmmac_set_ethtool_ops(struct net_device *netdev);
-extern struct stmmac_desc_ops enh_desc_ops;
-extern struct stmmac_desc_ops ndesc_ops;
+extern const struct stmmac_desc_ops enh_desc_ops;
+extern const struct stmmac_desc_ops ndesc_ops;
diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c
index f080509923f0..6d65482e789a 100644
--- a/drivers/net/stmmac/stmmac_ethtool.c
+++ b/drivers/net/stmmac/stmmac_ethtool.c
@@ -89,8 +89,8 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
};
#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats)
-void stmmac_ethtool_getdrvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
+static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
{
struct stmmac_priv *priv = netdev_priv(dev);
@@ -104,7 +104,8 @@ void stmmac_ethtool_getdrvinfo(struct net_device *dev,
info->n_stats = STMMAC_STATS_LEN;
}
-int stmmac_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int stmmac_ethtool_getsettings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
{
struct stmmac_priv *priv = netdev_priv(dev);
struct phy_device *phy = priv->phydev;
@@ -126,7 +127,8 @@ int stmmac_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
return rc;
}
-int stmmac_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int stmmac_ethtool_setsettings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
{
struct stmmac_priv *priv = netdev_priv(dev);
struct phy_device *phy = priv->phydev;
@@ -139,32 +141,32 @@ int stmmac_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
return rc;
}
-u32 stmmac_ethtool_getmsglevel(struct net_device *dev)
+static u32 stmmac_ethtool_getmsglevel(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
return priv->msg_enable;
}
-void stmmac_ethtool_setmsglevel(struct net_device *dev, u32 level)
+static void stmmac_ethtool_setmsglevel(struct net_device *dev, u32 level)
{
struct stmmac_priv *priv = netdev_priv(dev);
priv->msg_enable = level;
}
-int stmmac_check_if_running(struct net_device *dev)
+static int stmmac_check_if_running(struct net_device *dev)
{
if (!netif_running(dev))
return -EBUSY;
return 0;
}
-int stmmac_ethtool_get_regs_len(struct net_device *dev)
+static int stmmac_ethtool_get_regs_len(struct net_device *dev)
{
return REG_SPACE_SIZE;
}
-void stmmac_ethtool_gregs(struct net_device *dev,
+static void stmmac_ethtool_gregs(struct net_device *dev,
struct ethtool_regs *regs, void *space)
{
int i;
@@ -177,25 +179,25 @@ void stmmac_ethtool_gregs(struct net_device *dev,
if (!priv->is_gmac) {
/* MAC registers */
for (i = 0; i < 12; i++)
- reg_space[i] = readl(dev->base_addr + (i * 4));
+ reg_space[i] = readl(priv->ioaddr + (i * 4));
/* DMA registers */
for (i = 0; i < 9; i++)
reg_space[i + 12] =
- readl(dev->base_addr + (DMA_BUS_MODE + (i * 4)));
- reg_space[22] = readl(dev->base_addr + DMA_CUR_TX_BUF_ADDR);
- reg_space[23] = readl(dev->base_addr + DMA_CUR_RX_BUF_ADDR);
+ readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4)));
+ reg_space[22] = readl(priv->ioaddr + DMA_CUR_TX_BUF_ADDR);
+ reg_space[23] = readl(priv->ioaddr + DMA_CUR_RX_BUF_ADDR);
} else {
/* MAC registers */
for (i = 0; i < 55; i++)
- reg_space[i] = readl(dev->base_addr + (i * 4));
+ reg_space[i] = readl(priv->ioaddr + (i * 4));
/* DMA registers */
for (i = 0; i < 22; i++)
reg_space[i + 55] =
- readl(dev->base_addr + (DMA_BUS_MODE + (i * 4)));
+ readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4)));
}
}
-int stmmac_ethtool_set_tx_csum(struct net_device *netdev, u32 data)
+static int stmmac_ethtool_set_tx_csum(struct net_device *netdev, u32 data)
{
if (data)
netdev->features |= NETIF_F_HW_CSUM;
@@ -205,11 +207,11 @@ int stmmac_ethtool_set_tx_csum(struct net_device *netdev, u32 data)
return 0;
}
-u32 stmmac_ethtool_get_rx_csum(struct net_device *dev)
+static u32 stmmac_ethtool_get_rx_csum(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
- return priv->rx_csum;
+ return priv->rx_coe;
}
static void
@@ -263,11 +265,9 @@ stmmac_set_pauseparam(struct net_device *netdev,
cmd.phy_address = phy->addr;
ret = phy_ethtool_sset(phy, &cmd);
}
- } else {
- unsigned long ioaddr = netdev->base_addr;
- priv->hw->mac->flow_ctrl(ioaddr, phy->duplex,
+ } else
+ priv->hw->mac->flow_ctrl(priv->ioaddr, phy->duplex,
priv->flow_ctrl, priv->pause);
- }
spin_unlock(&priv->lock);
return ret;
}
@@ -276,12 +276,11 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *dummy, u64 *data)
{
struct stmmac_priv *priv = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
int i;
/* Update HW stats if supported */
priv->hw->dma->dma_diagnostic_fr(&dev->stats, (void *) &priv->xstats,
- ioaddr);
+ priv->ioaddr);
for (i = 0; i < STMMAC_STATS_LEN; i++) {
char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset;
@@ -325,7 +324,7 @@ static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
struct stmmac_priv *priv = netdev_priv(dev);
spin_lock_irq(&priv->lock);
- if (priv->wolenabled == PMT_SUPPORTED) {
+ if (device_can_wakeup(priv->device)) {
wol->supported = WAKE_MAGIC;
wol->wolopts = priv->wolopts;
}
@@ -337,16 +336,20 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
struct stmmac_priv *priv = netdev_priv(dev);
u32 support = WAKE_MAGIC;
- if (priv->wolenabled == PMT_NOT_SUPPORTED)
+ if (!device_can_wakeup(priv->device))
return -EINVAL;
if (wol->wolopts & ~support)
return -EINVAL;
- if (wol->wolopts == 0)
- device_set_wakeup_enable(priv->device, 0);
- else
+ if (wol->wolopts) {
+ pr_info("stmmac: wakeup enable\n");
device_set_wakeup_enable(priv->device, 1);
+ enable_irq_wake(dev->irq);
+ } else {
+ device_set_wakeup_enable(priv->device, 0);
+ disable_irq_wake(dev->irq);
+ }
spin_lock_irq(&priv->lock);
priv->wolopts = wol->wolopts;
@@ -377,10 +380,8 @@ static struct ethtool_ops stmmac_ethtool_ops = {
.get_wol = stmmac_get_wol,
.set_wol = stmmac_set_wol,
.get_sset_count = stmmac_get_sset_count,
-#ifdef NETIF_F_TSO
.get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
-#endif
};
void stmmac_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c
index ea0461eb2dbe..823b9e6431d5 100644
--- a/drivers/net/stmmac/stmmac_main.c
+++ b/drivers/net/stmmac/stmmac_main.c
@@ -134,13 +134,6 @@ static int buf_sz = DMA_BUFFER_SIZE;
module_param(buf_sz, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(buf_sz, "DMA buffer size");
-/* In case of Giga ETH, we can enable/disable the COE for the
- * transmit HW checksum computation.
- * Note that, if tx csum is off in HW, SG will be still supported. */
-static int tx_coe = HW_CSUM;
-module_param(tx_coe, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(tx_coe, "GMAC COE type 2 [on/off]");
-
static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
NETIF_MSG_LINK | NETIF_MSG_IFUP |
NETIF_MSG_IFDOWN | NETIF_MSG_TIMER);
@@ -202,7 +195,6 @@ static void stmmac_adjust_link(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
struct phy_device *phydev = priv->phydev;
- unsigned long ioaddr = dev->base_addr;
unsigned long flags;
int new_state = 0;
unsigned int fc = priv->flow_ctrl, pause_time = priv->pause;
@@ -215,7 +207,7 @@ static void stmmac_adjust_link(struct net_device *dev)
spin_lock_irqsave(&priv->lock, flags);
if (phydev->link) {
- u32 ctrl = readl(ioaddr + MAC_CTRL_REG);
+ u32 ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
/* Now we make sure that we can be in full duplex mode.
* If not, we operate in half-duplex mode. */
@@ -229,7 +221,7 @@ static void stmmac_adjust_link(struct net_device *dev)
}
/* Flow Control operation */
if (phydev->pause)
- priv->hw->mac->flow_ctrl(ioaddr, phydev->duplex,
+ priv->hw->mac->flow_ctrl(priv->ioaddr, phydev->duplex,
fc, pause_time);
if (phydev->speed != priv->speed) {
@@ -238,6 +230,9 @@ static void stmmac_adjust_link(struct net_device *dev)
case 1000:
if (likely(priv->is_gmac))
ctrl &= ~priv->hw->link.port;
+ if (likely(priv->fix_mac_speed))
+ priv->fix_mac_speed(priv->bsp_priv,
+ phydev->speed);
break;
case 100:
case 10:
@@ -265,7 +260,7 @@ static void stmmac_adjust_link(struct net_device *dev)
priv->speed = phydev->speed;
}
- writel(ctrl, ioaddr + MAC_CTRL_REG);
+ writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
if (!priv->oldlink) {
new_state = 1;
@@ -342,7 +337,7 @@ static int stmmac_init_phy(struct net_device *dev)
return 0;
}
-static inline void stmmac_mac_enable_rx(unsigned long ioaddr)
+static inline void stmmac_mac_enable_rx(void __iomem *ioaddr)
{
u32 value = readl(ioaddr + MAC_CTRL_REG);
value |= MAC_RNABLE_RX;
@@ -350,7 +345,7 @@ static inline void stmmac_mac_enable_rx(unsigned long ioaddr)
writel(value, ioaddr + MAC_CTRL_REG);
}
-static inline void stmmac_mac_enable_tx(unsigned long ioaddr)
+static inline void stmmac_mac_enable_tx(void __iomem *ioaddr)
{
u32 value = readl(ioaddr + MAC_CTRL_REG);
value |= MAC_ENABLE_TX;
@@ -358,14 +353,14 @@ static inline void stmmac_mac_enable_tx(unsigned long ioaddr)
writel(value, ioaddr + MAC_CTRL_REG);
}
-static inline void stmmac_mac_disable_rx(unsigned long ioaddr)
+static inline void stmmac_mac_disable_rx(void __iomem *ioaddr)
{
u32 value = readl(ioaddr + MAC_CTRL_REG);
value &= ~MAC_RNABLE_RX;
writel(value, ioaddr + MAC_CTRL_REG);
}
-static inline void stmmac_mac_disable_tx(unsigned long ioaddr)
+static inline void stmmac_mac_disable_tx(void __iomem *ioaddr)
{
u32 value = readl(ioaddr + MAC_CTRL_REG);
value &= ~MAC_ENABLE_TX;
@@ -567,29 +562,22 @@ static void free_dma_desc_resources(struct stmmac_priv *priv)
* stmmac_dma_operation_mode - HW DMA operation mode
* @priv : pointer to the private device structure.
* Description: it sets the DMA operation mode: tx/rx DMA thresholds
- * or Store-And-Forward capability. It also verifies the COE for the
- * transmission in case of Giga ETH.
+ * or Store-And-Forward capability.
*/
static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
{
- if (!priv->is_gmac) {
- /* MAC 10/100 */
- priv->hw->dma->dma_mode(priv->dev->base_addr, tc, 0);
- priv->tx_coe = NO_HW_CSUM;
- } else {
- if ((priv->dev->mtu <= ETH_DATA_LEN) && (tx_coe)) {
- priv->hw->dma->dma_mode(priv->dev->base_addr,
- SF_DMA_MODE, SF_DMA_MODE);
- tc = SF_DMA_MODE;
- priv->tx_coe = HW_CSUM;
- } else {
- /* Checksum computation is performed in software. */
- priv->hw->dma->dma_mode(priv->dev->base_addr, tc,
- SF_DMA_MODE);
- priv->tx_coe = NO_HW_CSUM;
- }
- }
- tx_coe = priv->tx_coe;
+ if (likely((priv->tx_coe) && (!priv->no_csum_insertion))) {
+ /* In case of GMAC, SF mode has to be enabled
+ * to perform the TX COE. This depends on:
+ * 1) TX COE if actually supported
+ * 2) There is no bugged Jumbo frame support
+ * that needs to not insert csum in the TDES.
+ */
+ priv->hw->dma->dma_mode(priv->ioaddr,
+ SF_DMA_MODE, SF_DMA_MODE);
+ tc = SF_DMA_MODE;
+ } else
+ priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE);
}
/**
@@ -600,7 +588,6 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
static void stmmac_tx(struct stmmac_priv *priv)
{
unsigned int txsize = priv->dma_tx_size;
- unsigned long ioaddr = priv->dev->base_addr;
while (priv->dirty_tx != priv->cur_tx) {
int last;
@@ -618,7 +605,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
int tx_error =
priv->hw->desc->tx_status(&priv->dev->stats,
&priv->xstats, p,
- ioaddr);
+ priv->ioaddr);
if (likely(tx_error == 0)) {
priv->dev->stats.tx_packets++;
priv->xstats.tx_pkt_n++;
@@ -674,7 +661,7 @@ static inline void stmmac_enable_irq(struct stmmac_priv *priv)
priv->tm->timer_start(tmrate);
else
#endif
- priv->hw->dma->enable_dma_irq(priv->dev->base_addr);
+ priv->hw->dma->enable_dma_irq(priv->ioaddr);
}
static inline void stmmac_disable_irq(struct stmmac_priv *priv)
@@ -684,7 +671,7 @@ static inline void stmmac_disable_irq(struct stmmac_priv *priv)
priv->tm->timer_stop();
else
#endif
- priv->hw->dma->disable_dma_irq(priv->dev->base_addr);
+ priv->hw->dma->disable_dma_irq(priv->ioaddr);
}
static int stmmac_has_work(struct stmmac_priv *priv)
@@ -739,14 +726,15 @@ 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->dev->base_addr);
+ priv->hw->dma->stop_tx(priv->ioaddr);
dma_free_tx_skbufs(priv);
priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
priv->dirty_tx = 0;
priv->cur_tx = 0;
- priv->hw->dma->start_tx(priv->dev->base_addr);
+ priv->hw->dma->start_tx(priv->ioaddr);
priv->dev->stats.tx_errors++;
netif_wake_queue(priv->dev);
@@ -755,11 +743,9 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
static void stmmac_dma_interrupt(struct stmmac_priv *priv)
{
- unsigned long ioaddr = priv->dev->base_addr;
int status;
- status = priv->hw->dma->dma_interrupt(priv->dev->base_addr,
- &priv->xstats);
+ status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats);
if (likely(status == handle_tx_rx))
_stmmac_schedule(priv);
@@ -767,7 +753,7 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
/* Try to bump up the dma threshold on this failure */
if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) {
tc += 64;
- priv->hw->dma->dma_mode(ioaddr, tc, SF_DMA_MODE);
+ priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE);
priv->xstats.threshold = tc;
}
stmmac_tx_err(priv);
@@ -787,7 +773,6 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
static int stmmac_open(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
int ret;
/* Check that the MAC address is valid. If its not, refuse
@@ -843,7 +828,8 @@ static int stmmac_open(struct net_device *dev)
init_dma_desc_rings(dev);
/* DMA initialization and SW reset */
- if (unlikely(priv->hw->dma->init(ioaddr, priv->pbl, priv->dma_tx_phy,
+ if (unlikely(priv->hw->dma->init(priv->ioaddr, priv->pbl,
+ priv->dma_tx_phy,
priv->dma_rx_phy) < 0)) {
pr_err("%s: DMA initialization failed\n", __func__);
@@ -851,22 +837,28 @@ static int stmmac_open(struct net_device *dev)
}
/* Copy the MAC addr into the HW */
- priv->hw->mac->set_umac_addr(ioaddr, dev->dev_addr, 0);
+ priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0);
/* If required, perform hw setup of the bus. */
if (priv->bus_setup)
- priv->bus_setup(ioaddr);
+ priv->bus_setup(priv->ioaddr);
/* Initialize the MAC Core */
- priv->hw->mac->core_init(ioaddr);
+ priv->hw->mac->core_init(priv->ioaddr);
+
+ priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr);
+ if (priv->rx_coe)
+ pr_info("stmmac: Rx Checksum Offload Engine supported\n");
+ if (priv->tx_coe)
+ pr_info("\tTX Checksum insertion supported\n");
priv->shutdown = 0;
/* Initialise the MMC (if present) to disable all interrupts. */
- writel(0xffffffff, ioaddr + MMC_HIGH_INTR_MASK);
- writel(0xffffffff, ioaddr + MMC_LOW_INTR_MASK);
+ writel(0xffffffff, priv->ioaddr + MMC_HIGH_INTR_MASK);
+ writel(0xffffffff, priv->ioaddr + MMC_LOW_INTR_MASK);
/* Enable the MAC Rx/Tx */
- stmmac_mac_enable_rx(ioaddr);
- stmmac_mac_enable_tx(ioaddr);
+ stmmac_mac_enable_rx(priv->ioaddr);
+ stmmac_mac_enable_tx(priv->ioaddr);
/* Set the HW DMA mode and the COE */
stmmac_dma_operation_mode(priv);
@@ -877,16 +869,16 @@ static int stmmac_open(struct net_device *dev)
/* Start the ball rolling... */
DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name);
- priv->hw->dma->start_tx(ioaddr);
- priv->hw->dma->start_rx(ioaddr);
+ priv->hw->dma->start_tx(priv->ioaddr);
+ priv->hw->dma->start_rx(priv->ioaddr);
#ifdef CONFIG_STMMAC_TIMER
priv->tm->timer_start(tmrate);
#endif
/* Dump DMA/MAC registers */
if (netif_msg_hw(priv)) {
- priv->hw->mac->dump_regs(ioaddr);
- priv->hw->dma->dump_regs(ioaddr);
+ priv->hw->mac->dump_regs(priv->ioaddr);
+ priv->hw->dma->dump_regs(priv->ioaddr);
}
if (priv->phydev)
@@ -930,15 +922,15 @@ static int stmmac_release(struct net_device *dev)
free_irq(dev->irq, dev);
/* Stop TX/RX DMA and clear the descriptors */
- priv->hw->dma->stop_tx(dev->base_addr);
- priv->hw->dma->stop_rx(dev->base_addr);
+ priv->hw->dma->stop_tx(priv->ioaddr);
+ priv->hw->dma->stop_rx(priv->ioaddr);
/* Release and free the Rx/Tx resources */
free_dma_desc_resources(priv);
/* Disable the MAC core */
- stmmac_mac_disable_tx(dev->base_addr);
- stmmac_mac_disable_rx(dev->base_addr);
+ stmmac_mac_disable_tx(priv->ioaddr);
+ stmmac_mac_disable_rx(priv->ioaddr);
netif_carrier_off(dev);
@@ -1066,7 +1058,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
return stmmac_sw_tso(priv, skb);
if (likely((skb->ip_summed == CHECKSUM_PARTIAL))) {
- if (likely(priv->tx_coe == NO_HW_CSUM))
+ if (unlikely((!priv->tx_coe) || (priv->no_csum_insertion)))
skb_checksum_help(skb);
else
csum_insertion = 1;
@@ -1140,7 +1132,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += skb->len;
- priv->hw->dma->enable_dma_transmission(dev->base_addr);
+ priv->hw->dma->enable_dma_transmission(priv->ioaddr);
return NETDEV_TX_OK;
}
@@ -1256,7 +1248,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
if (unlikely(status == csum_none)) {
/* always for the old mac 10/100 */
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
netif_receive_skb(skb);
} else {
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1390,6 +1382,15 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
return -EINVAL;
}
+ /* Some GMAC devices have a bugged Jumbo frame support that
+ * needs to have the Tx COE disabled for oversized frames
+ * (due to limited buffer sizes). In this case we disable
+ * the TX csum insertionin the TDES and not use SF. */
+ if ((priv->bugged_jumbo) && (priv->dev->mtu > ETH_DATA_LEN))
+ priv->no_csum_insertion = 1;
+ else
+ priv->no_csum_insertion = 0;
+
dev->mtu = new_mtu;
return 0;
@@ -1405,11 +1406,9 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
return IRQ_NONE;
}
- if (priv->is_gmac) {
- unsigned long ioaddr = dev->base_addr;
+ if (priv->is_gmac)
/* To handle GMAC own interrupts */
- priv->hw->mac->host_irq_status(ioaddr);
- }
+ priv->hw->mac->host_irq_status((void __iomem *) dev->base_addr);
stmmac_dma_interrupt(priv);
@@ -1512,9 +1511,6 @@ static int stmmac_probe(struct net_device *dev)
#endif
priv->msg_enable = netif_msg_init(debug, default_msg_level);
- if (priv->is_gmac)
- priv->rx_csum = 1;
-
if (flow_ctrl)
priv->flow_ctrl = FLOW_AUTO; /* RX/TX pause on */
@@ -1522,7 +1518,8 @@ static int stmmac_probe(struct net_device *dev)
netif_napi_add(dev, &priv->napi, stmmac_poll, 64);
/* Get the MAC address */
- priv->hw->mac->get_umac_addr(dev->base_addr, dev->dev_addr, 0);
+ priv->hw->mac->get_umac_addr((void __iomem *) dev->base_addr,
+ dev->dev_addr, 0);
if (!is_valid_ether_addr(dev->dev_addr))
pr_warning("\tno valid MAC address;"
@@ -1552,14 +1549,13 @@ static int stmmac_probe(struct net_device *dev)
static int stmmac_mac_device_setup(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
struct mac_device_info *device;
if (priv->is_gmac)
- device = dwmac1000_setup(ioaddr);
+ device = dwmac1000_setup(priv->ioaddr);
else
- device = dwmac100_setup(ioaddr);
+ device = dwmac100_setup(priv->ioaddr);
if (!device)
return -ENOMEM;
@@ -1572,9 +1568,8 @@ static int stmmac_mac_device_setup(struct net_device *dev)
priv->hw = device;
- priv->wolenabled = priv->hw->pmt; /* PMT supported */
- if (priv->wolenabled == PMT_SUPPORTED)
- priv->wolopts = WAKE_MAGIC; /* Magic Frame */
+ if (device_can_wakeup(priv->device))
+ priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */
return 0;
}
@@ -1653,7 +1648,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
{
int ret = 0;
struct resource *res;
- unsigned int *addr = NULL;
+ void __iomem *addr = NULL;
struct net_device *ndev = NULL;
struct stmmac_priv *priv;
struct plat_stmmacenet_data *plat_dat;
@@ -1664,7 +1659,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
ret = -ENODEV;
goto out;
}
- pr_info("done!\n");
+ pr_info("\tdone!\n");
if (!request_mem_region(res->start, resource_size(res),
pdev->name)) {
@@ -1706,8 +1701,18 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
plat_dat = pdev->dev.platform_data;
priv->bus_id = plat_dat->bus_id;
priv->pbl = plat_dat->pbl; /* TLI */
+ priv->mii_clk_csr = plat_dat->clk_csr;
+ priv->tx_coe = plat_dat->tx_coe;
+ priv->bugged_jumbo = plat_dat->bugged_jumbo;
priv->is_gmac = plat_dat->has_gmac; /* GMAC is on board */
priv->enh_desc = plat_dat->enh_desc;
+ priv->ioaddr = addr;
+
+ /* PMT module is not integrated in all the MAC devices. */
+ if (plat_dat->pmt) {
+ pr_info("\tPMT module supported\n");
+ device_set_wakeup_capable(&pdev->dev, 1);
+ }
platform_set_drvdata(pdev, ndev);
@@ -1743,8 +1748,8 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
priv->bsp_priv = plat_dat->bsp_priv;
pr_info("\t%s - (dev. name: %s - id: %d, IRQ #%d\n"
- "\tIO base addr: 0x%08x)\n", ndev->name, pdev->name,
- pdev->id, ndev->irq, (unsigned int)addr);
+ "\tIO base addr: 0x%p)\n", ndev->name, pdev->name,
+ pdev->id, ndev->irq, addr);
/* MDIO bus Registration */
pr_debug("\tMDIO bus (id: %d)...", priv->bus_id);
@@ -1779,11 +1784,11 @@ static int stmmac_dvr_remove(struct platform_device *pdev)
pr_info("%s:\n\tremoving driver", __func__);
- priv->hw->dma->stop_rx(ndev->base_addr);
- priv->hw->dma->stop_tx(ndev->base_addr);
+ priv->hw->dma->stop_rx(priv->ioaddr);
+ priv->hw->dma->stop_tx(priv->ioaddr);
- stmmac_mac_disable_rx(ndev->base_addr);
- stmmac_mac_disable_tx(ndev->base_addr);
+ stmmac_mac_disable_rx(priv->ioaddr);
+ stmmac_mac_disable_tx(priv->ioaddr);
netif_carrier_off(ndev);
@@ -1792,7 +1797,7 @@ static int stmmac_dvr_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
unregister_netdev(ndev);
- iounmap((void *)ndev->base_addr);
+ iounmap((void *)priv->ioaddr);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
@@ -1827,23 +1832,20 @@ static int stmmac_suspend(struct platform_device *pdev, pm_message_t state)
napi_disable(&priv->napi);
/* Stop TX/RX DMA */
- priv->hw->dma->stop_tx(dev->base_addr);
- priv->hw->dma->stop_rx(dev->base_addr);
+ priv->hw->dma->stop_tx(priv->ioaddr);
+ priv->hw->dma->stop_rx(priv->ioaddr);
/* Clear the Rx/Tx descriptors */
priv->hw->desc->init_rx_desc(priv->dma_rx, priv->dma_rx_size,
dis_ic);
priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
- stmmac_mac_disable_tx(dev->base_addr);
+ stmmac_mac_disable_tx(priv->ioaddr);
- if (device_may_wakeup(&(pdev->dev))) {
- /* Enable Power down mode by programming the PMT regs */
- if (priv->wolenabled == PMT_SUPPORTED)
- priv->hw->mac->pmt(dev->base_addr,
- priv->wolopts);
- } else {
- stmmac_mac_disable_rx(dev->base_addr);
- }
+ /* Enable Power down mode by programming the PMT regs */
+ if (device_can_wakeup(priv->device))
+ priv->hw->mac->pmt(priv->ioaddr, priv->wolopts);
+ else
+ stmmac_mac_disable_rx(priv->ioaddr);
} else {
priv->shutdown = 1;
/* Although this can appear slightly redundant it actually
@@ -1860,7 +1862,6 @@ static int stmmac_resume(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct stmmac_priv *priv = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
if (!netif_running(dev))
return 0;
@@ -1879,17 +1880,16 @@ static int stmmac_resume(struct platform_device *pdev)
* is received. Anyway, it's better to manually clear
* this bit because it can generate problems while resuming
* from another devices (e.g. serial console). */
- if (device_may_wakeup(&(pdev->dev)))
- if (priv->wolenabled == PMT_SUPPORTED)
- priv->hw->mac->pmt(dev->base_addr, 0);
+ if (device_can_wakeup(priv->device))
+ priv->hw->mac->pmt(priv->ioaddr, 0);
netif_device_attach(dev);
/* Enable the MAC and DMA */
- stmmac_mac_enable_rx(ioaddr);
- stmmac_mac_enable_tx(ioaddr);
- priv->hw->dma->start_tx(ioaddr);
- priv->hw->dma->start_rx(ioaddr);
+ stmmac_mac_enable_rx(priv->ioaddr);
+ stmmac_mac_enable_tx(priv->ioaddr);
+ priv->hw->dma->start_tx(priv->ioaddr);
+ priv->hw->dma->start_rx(priv->ioaddr);
#ifdef CONFIG_STMMAC_TIMER
priv->tm->timer_start(tmrate);
@@ -1968,8 +1968,6 @@ static int __init stmmac_cmdline_opt(char *str)
strict_strtoul(opt + 7, 0, (unsigned long *)&buf_sz);
else if (!strncmp(opt, "tc:", 3))
strict_strtoul(opt + 3, 0, (unsigned long *)&tc);
- else if (!strncmp(opt, "tx_coe:", 7))
- strict_strtoul(opt + 7, 0, (unsigned long *)&tx_coe);
else if (!strncmp(opt, "watchdog:", 9))
strict_strtoul(opt + 9, 0, (unsigned long *)&watchdog);
else if (!strncmp(opt, "flow_ctrl:", 10))
diff --git a/drivers/net/stmmac/stmmac_mdio.c b/drivers/net/stmmac/stmmac_mdio.c
index 40b2c7929719..d7441616357d 100644
--- a/drivers/net/stmmac/stmmac_mdio.c
+++ b/drivers/net/stmmac/stmmac_mdio.c
@@ -47,21 +47,20 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
{
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
- unsigned long ioaddr = ndev->base_addr;
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
int data;
u16 regValue = (((phyaddr << 11) & (0x0000F800)) |
((phyreg << 6) & (0x000007C0)));
- regValue |= MII_BUSY; /* in case of GMAC */
+ regValue |= MII_BUSY | ((priv->mii_clk_csr & 7) << 2);
- do {} while (((readl(ioaddr + mii_address)) & MII_BUSY) == 1);
- writel(regValue, ioaddr + mii_address);
- do {} while (((readl(ioaddr + mii_address)) & MII_BUSY) == 1);
+ do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1);
+ writel(regValue, priv->ioaddr + mii_address);
+ do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1);
/* Read the data from the MII data register */
- data = (int)readl(ioaddr + mii_data);
+ data = (int)readl(priv->ioaddr + mii_data);
return data;
}
@@ -79,7 +78,6 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
{
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
- unsigned long ioaddr = ndev->base_addr;
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
@@ -87,17 +85,18 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
(((phyaddr << 11) & (0x0000F800)) | ((phyreg << 6) & (0x000007C0)))
| MII_WRITE;
- value |= MII_BUSY;
+ value |= MII_BUSY | ((priv->mii_clk_csr & 7) << 2);
+
/* Wait until any existing MII operation is complete */
- do {} while (((readl(ioaddr + mii_address)) & MII_BUSY) == 1);
+ do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1);
/* Set the MII address register to write */
- writel(phydata, ioaddr + mii_data);
- writel(value, ioaddr + mii_address);
+ writel(phydata, priv->ioaddr + mii_data);
+ writel(value, priv->ioaddr + mii_address);
/* Wait until any existing MII operation is complete */
- do {} while (((readl(ioaddr + mii_address)) & MII_BUSY) == 1);
+ do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1);
return 0;
}
@@ -111,7 +110,6 @@ static int stmmac_mdio_reset(struct mii_bus *bus)
{
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
- unsigned long ioaddr = ndev->base_addr;
unsigned int mii_address = priv->hw->mii.addr;
if (priv->phy_reset) {
@@ -123,7 +121,7 @@ static int stmmac_mdio_reset(struct mii_bus *bus)
* It doesn't complete its reset until at least one clock cycle
* on MDC, so perform a dummy mdio read.
*/
- writel(0, ioaddr + mii_address);
+ writel(0, priv->ioaddr + mii_address);
return 0;
}
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index 358c22f9acbe..7d9ec23aabf6 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -436,7 +436,7 @@ static int lance_open( struct net_device *dev )
DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n",
dev->name, i, DREG ));
DREG = CSR0_STOP;
- return( -EIO );
+ return -EIO;
}
DREG = CSR0_IDON | CSR0_STRT | CSR0_INEA;
@@ -445,7 +445,7 @@ static int lance_open( struct net_device *dev )
DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
- return( 0 );
+ return 0;
}
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 618643e3ca3e..0a6a5ced3c1c 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -617,7 +617,7 @@ static void bigmac_begin_auto_negotiation(struct bigmac *bp)
bp->timer_ticks = 0;
bp->bigmac_timer.expires = jiffies + (12 * HZ) / 10;
bp->bigmac_timer.data = (unsigned long) bp;
- bp->bigmac_timer.function = &bigmac_timer;
+ bp->bigmac_timer.function = bigmac_timer;
add_timer(&bp->bigmac_timer);
}
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 2678588ea4b2..3ed2a67bd6d3 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -96,16 +96,10 @@ static char *media[MAX_UNITS];
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
-#ifndef _COMPAT_WITH_OLD_KERNEL
+#include <linux/dma-mapping.h>
#include <linux/crc32.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
-#else
-#include "crc32.h"
-#include "ethtool.h"
-#include "mii.h"
-#include "compat.h"
-#endif
/* These identify the driver base version and may not be removed. */
static const char version[] __devinitconst =
@@ -369,9 +363,21 @@ struct netdev_private {
dma_addr_t tx_ring_dma;
dma_addr_t rx_ring_dma;
struct timer_list timer; /* Media monitoring timer. */
+ /* ethtool extra stats */
+ struct {
+ u64 tx_multiple_collisions;
+ u64 tx_single_collisions;
+ u64 tx_late_collisions;
+ u64 tx_deferred;
+ u64 tx_deferred_excessive;
+ u64 tx_aborted;
+ u64 tx_bcasts;
+ u64 rx_bcasts;
+ u64 tx_mcasts;
+ u64 rx_mcasts;
+ } xstats;
/* Frequently used values: keep some adjacent for cache effect. */
spinlock_t lock;
- spinlock_t rx_lock; /* Group with Tx control cache line. */
int msg_enable;
int chip_id;
unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
@@ -396,6 +402,7 @@ struct netdev_private {
unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */
struct pci_dev *pci_dev;
void __iomem *base;
+ spinlock_t statlock;
};
/* The station address location in the EEPROM. */
@@ -520,16 +527,19 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
np->chip_id = chip_idx;
np->msg_enable = (1 << debug) - 1;
spin_lock_init(&np->lock);
+ spin_lock_init(&np->statlock);
tasklet_init(&np->rx_tasklet, rx_poll, (unsigned long)dev);
tasklet_init(&np->tx_tasklet, tx_poll, (unsigned long)dev);
- ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
+ ring_space = dma_alloc_coherent(&pdev->dev, TX_TOTAL_SIZE,
+ &ring_dma, GFP_KERNEL);
if (!ring_space)
goto err_out_cleardev;
np->tx_ring = (struct netdev_desc *)ring_space;
np->tx_ring_dma = ring_dma;
- ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);
+ ring_space = dma_alloc_coherent(&pdev->dev, RX_TOTAL_SIZE,
+ &ring_dma, GFP_KERNEL);
if (!ring_space)
goto err_out_unmap_tx;
np->rx_ring = (struct netdev_desc *)ring_space;
@@ -663,9 +673,11 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
err_out_unregister:
unregister_netdev(dev);
err_out_unmap_rx:
- pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);
+ dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE,
+ np->rx_ring, np->rx_ring_dma);
err_out_unmap_tx:
- pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma);
+ dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE,
+ np->tx_ring, np->tx_ring_dma);
err_out_cleardev:
pci_set_drvdata(pdev, NULL);
pci_iounmap(pdev, ioaddr);
@@ -874,7 +886,7 @@ static int netdev_open(struct net_device *dev)
init_timer(&np->timer);
np->timer.expires = jiffies + 3*HZ;
np->timer.data = (unsigned long)dev;
- np->timer.function = &netdev_timer; /* timer handler */
+ np->timer.function = netdev_timer; /* timer handler */
add_timer(&np->timer);
/* Enable interrupts by setting the interrupt mask. */
@@ -1011,8 +1023,14 @@ static void init_ring(struct net_device *dev)
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* 16 byte align the IP header. */
np->rx_ring[i].frag[0].addr = cpu_to_le32(
- pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz,
- PCI_DMA_FROMDEVICE));
+ dma_map_single(&np->pci_dev->dev, skb->data,
+ np->rx_buf_sz, DMA_FROM_DEVICE));
+ if (dma_mapping_error(&np->pci_dev->dev,
+ np->rx_ring[i].frag[0].addr)) {
+ dev_kfree_skb(skb);
+ np->rx_skbuff[i] = NULL;
+ break;
+ }
np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag);
}
np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
@@ -1063,9 +1081,11 @@ start_tx (struct sk_buff *skb, struct net_device *dev)
txdesc->next_desc = 0;
txdesc->status = cpu_to_le32 ((entry << 2) | DisableAlign);
- txdesc->frag[0].addr = cpu_to_le32 (pci_map_single (np->pci_dev, skb->data,
- skb->len,
- PCI_DMA_TODEVICE));
+ txdesc->frag[0].addr = cpu_to_le32(dma_map_single(&np->pci_dev->dev,
+ skb->data, skb->len, DMA_TO_DEVICE));
+ if (dma_mapping_error(&np->pci_dev->dev,
+ txdesc->frag[0].addr))
+ goto drop_frame;
txdesc->frag[0].length = cpu_to_le32 (skb->len | LastFrag);
/* Increment cur_tx before tasklet_schedule() */
@@ -1087,6 +1107,12 @@ start_tx (struct sk_buff *skb, struct net_device *dev)
dev->name, np->cur_tx, entry);
}
return NETDEV_TX_OK;
+
+drop_frame:
+ dev_kfree_skb(skb);
+ np->tx_skbuff[entry] = NULL;
+ dev->stats.tx_dropped++;
+ return NETDEV_TX_OK;
}
/* Reset hardware tx and free all of tx buffers */
@@ -1097,7 +1123,6 @@ reset_tx (struct net_device *dev)
void __iomem *ioaddr = np->base;
struct sk_buff *skb;
int i;
- int irq = in_interrupt();
/* Reset tx logic, TxListPtr will be cleaned */
iowrite16 (TxDisable, ioaddr + MACCtrl1);
@@ -1109,13 +1134,10 @@ reset_tx (struct net_device *dev)
skb = np->tx_skbuff[i];
if (skb) {
- pci_unmap_single(np->pci_dev,
+ dma_unmap_single(&np->pci_dev->dev,
le32_to_cpu(np->tx_ring[i].frag[0].addr),
- skb->len, PCI_DMA_TODEVICE);
- if (irq)
- dev_kfree_skb_irq (skb);
- else
- dev_kfree_skb (skb);
+ skb->len, DMA_TO_DEVICE);
+ dev_kfree_skb_any(skb);
np->tx_skbuff[i] = NULL;
dev->stats.tx_dropped++;
}
@@ -1233,9 +1255,9 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
break;
skb = np->tx_skbuff[entry];
/* Free the original skb. */
- pci_unmap_single(np->pci_dev,
+ dma_unmap_single(&np->pci_dev->dev,
le32_to_cpu(np->tx_ring[entry].frag[0].addr),
- skb->len, PCI_DMA_TODEVICE);
+ skb->len, DMA_TO_DEVICE);
dev_kfree_skb_irq (np->tx_skbuff[entry]);
np->tx_skbuff[entry] = NULL;
np->tx_ring[entry].frag[0].addr = 0;
@@ -1252,9 +1274,9 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
break;
skb = np->tx_skbuff[entry];
/* Free the original skb. */
- pci_unmap_single(np->pci_dev,
+ dma_unmap_single(&np->pci_dev->dev,
le32_to_cpu(np->tx_ring[entry].frag[0].addr),
- skb->len, PCI_DMA_TODEVICE);
+ skb->len, DMA_TO_DEVICE);
dev_kfree_skb_irq (np->tx_skbuff[entry]);
np->tx_skbuff[entry] = NULL;
np->tx_ring[entry].frag[0].addr = 0;
@@ -1334,22 +1356,18 @@ static void rx_poll(unsigned long data)
if (pkt_len < rx_copybreak &&
(skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
skb_reserve(skb, 2); /* 16 byte align the IP header */
- pci_dma_sync_single_for_cpu(np->pci_dev,
- le32_to_cpu(desc->frag[0].addr),
- np->rx_buf_sz,
- PCI_DMA_FROMDEVICE);
-
+ dma_sync_single_for_cpu(&np->pci_dev->dev,
+ le32_to_cpu(desc->frag[0].addr),
+ np->rx_buf_sz, DMA_FROM_DEVICE);
skb_copy_to_linear_data(skb, np->rx_skbuff[entry]->data, pkt_len);
- pci_dma_sync_single_for_device(np->pci_dev,
- le32_to_cpu(desc->frag[0].addr),
- np->rx_buf_sz,
- PCI_DMA_FROMDEVICE);
+ dma_sync_single_for_device(&np->pci_dev->dev,
+ le32_to_cpu(desc->frag[0].addr),
+ np->rx_buf_sz, DMA_FROM_DEVICE);
skb_put(skb, pkt_len);
} else {
- pci_unmap_single(np->pci_dev,
+ dma_unmap_single(&np->pci_dev->dev,
le32_to_cpu(desc->frag[0].addr),
- np->rx_buf_sz,
- PCI_DMA_FROMDEVICE);
+ np->rx_buf_sz, DMA_FROM_DEVICE);
skb_put(skb = np->rx_skbuff[entry], pkt_len);
np->rx_skbuff[entry] = NULL;
}
@@ -1396,8 +1414,14 @@ static void refill_rx (struct net_device *dev)
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
np->rx_ring[entry].frag[0].addr = cpu_to_le32(
- pci_map_single(np->pci_dev, skb->data,
- np->rx_buf_sz, PCI_DMA_FROMDEVICE));
+ dma_map_single(&np->pci_dev->dev, skb->data,
+ np->rx_buf_sz, DMA_FROM_DEVICE));
+ if (dma_mapping_error(&np->pci_dev->dev,
+ np->rx_ring[entry].frag[0].addr)) {
+ dev_kfree_skb_irq(skb);
+ np->rx_skbuff[entry] = NULL;
+ break;
+ }
}
/* Perhaps we need not reset this field. */
np->rx_ring[entry].frag[0].length =
@@ -1475,27 +1499,41 @@ static struct net_device_stats *get_stats(struct net_device *dev)
{
struct netdev_private *np = netdev_priv(dev);
void __iomem *ioaddr = np->base;
- int i;
+ unsigned long flags;
+ u8 late_coll, single_coll, mult_coll;
- /* We should lock this segment of code for SMP eventually, although
- the vulnerability window is very small and statistics are
- non-critical. */
+ spin_lock_irqsave(&np->statlock, flags);
/* The chip only need report frame silently dropped. */
dev->stats.rx_missed_errors += ioread8(ioaddr + RxMissed);
dev->stats.tx_packets += ioread16(ioaddr + TxFramesOK);
dev->stats.rx_packets += ioread16(ioaddr + RxFramesOK);
- dev->stats.collisions += ioread8(ioaddr + StatsLateColl);
- dev->stats.collisions += ioread8(ioaddr + StatsMultiColl);
- dev->stats.collisions += ioread8(ioaddr + StatsOneColl);
dev->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError);
- ioread8(ioaddr + StatsTxDefer);
- for (i = StatsTxDefer; i <= StatsMcastRx; i++)
- ioread8(ioaddr + i);
+
+ mult_coll = ioread8(ioaddr + StatsMultiColl);
+ np->xstats.tx_multiple_collisions += mult_coll;
+ single_coll = ioread8(ioaddr + StatsOneColl);
+ np->xstats.tx_single_collisions += single_coll;
+ late_coll = ioread8(ioaddr + StatsLateColl);
+ np->xstats.tx_late_collisions += late_coll;
+ dev->stats.collisions += mult_coll
+ + single_coll
+ + late_coll;
+
+ np->xstats.tx_deferred += ioread8(ioaddr + StatsTxDefer);
+ np->xstats.tx_deferred_excessive += ioread8(ioaddr + StatsTxXSDefer);
+ np->xstats.tx_aborted += ioread8(ioaddr + StatsTxAbort);
+ np->xstats.tx_bcasts += ioread8(ioaddr + StatsBcastTx);
+ np->xstats.rx_bcasts += ioread8(ioaddr + StatsBcastRx);
+ np->xstats.tx_mcasts += ioread8(ioaddr + StatsMcastTx);
+ np->xstats.rx_mcasts += ioread8(ioaddr + StatsMcastRx);
+
dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow);
dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16;
dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow);
dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16;
+ spin_unlock_irqrestore(&np->statlock, flags);
+
return &dev->stats;
}
@@ -1554,6 +1592,21 @@ static int __set_mac_addr(struct net_device *dev)
return 0;
}
+static const struct {
+ const char name[ETH_GSTRING_LEN];
+} sundance_stats[] = {
+ { "tx_multiple_collisions" },
+ { "tx_single_collisions" },
+ { "tx_late_collisions" },
+ { "tx_deferred" },
+ { "tx_deferred_excessive" },
+ { "tx_aborted" },
+ { "tx_bcasts" },
+ { "rx_bcasts" },
+ { "tx_mcasts" },
+ { "rx_mcasts" },
+};
+
static int check_if_running(struct net_device *dev)
{
if (!netif_running(dev))
@@ -1612,6 +1665,42 @@ static void set_msglevel(struct net_device *dev, u32 val)
np->msg_enable = val;
}
+static void get_strings(struct net_device *dev, u32 stringset,
+ u8 *data)
+{
+ if (stringset == ETH_SS_STATS)
+ memcpy(data, sundance_stats, sizeof(sundance_stats));
+}
+
+static int get_sset_count(struct net_device *dev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(sundance_stats);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct netdev_private *np = netdev_priv(dev);
+ int i = 0;
+
+ get_stats(dev);
+ data[i++] = np->xstats.tx_multiple_collisions;
+ data[i++] = np->xstats.tx_single_collisions;
+ data[i++] = np->xstats.tx_late_collisions;
+ data[i++] = np->xstats.tx_deferred;
+ data[i++] = np->xstats.tx_deferred_excessive;
+ data[i++] = np->xstats.tx_aborted;
+ data[i++] = np->xstats.tx_bcasts;
+ data[i++] = np->xstats.rx_bcasts;
+ data[i++] = np->xstats.tx_mcasts;
+ data[i++] = np->xstats.rx_mcasts;
+}
+
static const struct ethtool_ops ethtool_ops = {
.begin = check_if_running,
.get_drvinfo = get_drvinfo,
@@ -1621,6 +1710,9 @@ static const struct ethtool_ops ethtool_ops = {
.get_link = get_link,
.get_msglevel = get_msglevel,
.set_msglevel = set_msglevel,
+ .get_strings = get_strings,
+ .get_sset_count = get_sset_count,
+ .get_ethtool_stats = get_ethtool_stats,
};
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1715,9 +1807,9 @@ static int netdev_close(struct net_device *dev)
np->rx_ring[i].status = 0;
skb = np->rx_skbuff[i];
if (skb) {
- pci_unmap_single(np->pci_dev,
+ dma_unmap_single(&np->pci_dev->dev,
le32_to_cpu(np->rx_ring[i].frag[0].addr),
- np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ np->rx_buf_sz, DMA_FROM_DEVICE);
dev_kfree_skb(skb);
np->rx_skbuff[i] = NULL;
}
@@ -1727,9 +1819,9 @@ static int netdev_close(struct net_device *dev)
np->tx_ring[i].next_desc = 0;
skb = np->tx_skbuff[i];
if (skb) {
- pci_unmap_single(np->pci_dev,
+ dma_unmap_single(&np->pci_dev->dev,
le32_to_cpu(np->tx_ring[i].frag[0].addr),
- skb->len, PCI_DMA_TODEVICE);
+ skb->len, DMA_TO_DEVICE);
dev_kfree_skb(skb);
np->tx_skbuff[i] = NULL;
}
@@ -1743,25 +1835,72 @@ static void __devexit sundance_remove1 (struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
if (dev) {
- struct netdev_private *np = netdev_priv(dev);
-
- unregister_netdev(dev);
- pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring,
- np->rx_ring_dma);
- pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring,
- np->tx_ring_dma);
- pci_iounmap(pdev, np->base);
- pci_release_regions(pdev);
- free_netdev(dev);
- pci_set_drvdata(pdev, NULL);
+ struct netdev_private *np = netdev_priv(dev);
+ unregister_netdev(dev);
+ dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE,
+ np->rx_ring, np->rx_ring_dma);
+ dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE,
+ np->tx_ring, np->tx_ring_dma);
+ pci_iounmap(pdev, np->base);
+ pci_release_regions(pdev);
+ free_netdev(dev);
+ pci_set_drvdata(pdev, NULL);
+ }
+}
+
+#ifdef CONFIG_PM
+
+static int sundance_suspend(struct pci_dev *pci_dev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pci_dev);
+
+ if (!netif_running(dev))
+ return 0;
+
+ netdev_close(dev);
+ netif_device_detach(dev);
+
+ pci_save_state(pci_dev);
+ pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
+
+ return 0;
+}
+
+static int sundance_resume(struct pci_dev *pci_dev)
+{
+ struct net_device *dev = pci_get_drvdata(pci_dev);
+ int err = 0;
+
+ if (!netif_running(dev))
+ return 0;
+
+ pci_set_power_state(pci_dev, PCI_D0);
+ pci_restore_state(pci_dev);
+
+ err = netdev_open(dev);
+ if (err) {
+ printk(KERN_ERR "%s: Can't resume interface!\n",
+ dev->name);
+ goto out;
}
+
+ netif_device_attach(dev);
+
+out:
+ return err;
}
+#endif /* CONFIG_PM */
+
static struct pci_driver sundance_driver = {
.name = DRV_NAME,
.id_table = sundance_pci_tbl,
.probe = sundance_probe1,
.remove = __devexit_p(sundance_remove1),
+#ifdef CONFIG_PM
+ .suspend = sundance_suspend,
+ .resume = sundance_resume,
+#endif /* CONFIG_PM */
};
static int __init sundance_init(void)
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 434f9d735333..4ceb3cf6a9a9 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -31,6 +31,8 @@
* about when we can start taking interrupts or get xmit() called...
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -105,7 +107,6 @@ MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver");
MODULE_LICENSE("GPL");
#define GEM_MODULE_NAME "gem"
-#define PFX GEM_MODULE_NAME ": "
static DEFINE_PCI_DEVICE_TABLE(gem_pci_tbl) = {
{ PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_GEM,
@@ -262,8 +263,7 @@ static int gem_pcs_interrupt(struct net_device *dev, struct gem *gp, u32 gem_sta
gp->dev->name, pcs_istat);
if (!(pcs_istat & PCS_ISTAT_LSC)) {
- printk(KERN_ERR "%s: PCS irq but no link status change???\n",
- dev->name);
+ netdev_err(dev, "PCS irq but no link status change???\n");
return 0;
}
@@ -282,20 +282,16 @@ static int gem_pcs_interrupt(struct net_device *dev, struct gem *gp, u32 gem_sta
* when autoneg has completed.
*/
if (pcs_miistat & PCS_MIISTAT_RF)
- printk(KERN_INFO "%s: PCS AutoNEG complete, "
- "RemoteFault\n", dev->name);
+ netdev_info(dev, "PCS AutoNEG complete, RemoteFault\n");
else
- printk(KERN_INFO "%s: PCS AutoNEG complete.\n",
- dev->name);
+ netdev_info(dev, "PCS AutoNEG complete\n");
}
if (pcs_miistat & PCS_MIISTAT_LS) {
- printk(KERN_INFO "%s: PCS link is now up.\n",
- dev->name);
+ netdev_info(dev, "PCS link is now up\n");
netif_carrier_on(gp->dev);
} else {
- printk(KERN_INFO "%s: PCS link is now down.\n",
- dev->name);
+ netdev_info(dev, "PCS link is now down\n");
netif_carrier_off(gp->dev);
/* If this happens and the link timer is not running,
* reset so we re-negotiate.
@@ -323,14 +319,12 @@ static int gem_txmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_s
return 0;
if (txmac_stat & MAC_TXSTAT_URUN) {
- printk(KERN_ERR "%s: TX MAC xmit underrun.\n",
- dev->name);
+ netdev_err(dev, "TX MAC xmit underrun\n");
gp->net_stats.tx_fifo_errors++;
}
if (txmac_stat & MAC_TXSTAT_MPE) {
- printk(KERN_ERR "%s: TX MAC max packet size error.\n",
- dev->name);
+ netdev_err(dev, "TX MAC max packet size error\n");
gp->net_stats.tx_errors++;
}
@@ -377,8 +371,7 @@ static int gem_rxmac_reset(struct gem *gp)
udelay(10);
}
if (limit == 5000) {
- printk(KERN_ERR "%s: RX MAC will not reset, resetting whole "
- "chip.\n", dev->name);
+ netdev_err(dev, "RX MAC will not reset, resetting whole chip\n");
return 1;
}
@@ -390,8 +383,7 @@ static int gem_rxmac_reset(struct gem *gp)
udelay(10);
}
if (limit == 5000) {
- printk(KERN_ERR "%s: RX MAC will not disable, resetting whole "
- "chip.\n", dev->name);
+ netdev_err(dev, "RX MAC will not disable, resetting whole chip\n");
return 1;
}
@@ -403,8 +395,7 @@ static int gem_rxmac_reset(struct gem *gp)
udelay(10);
}
if (limit == 5000) {
- printk(KERN_ERR "%s: RX DMA will not disable, resetting whole "
- "chip.\n", dev->name);
+ netdev_err(dev, "RX DMA will not disable, resetting whole chip\n");
return 1;
}
@@ -419,8 +410,7 @@ static int gem_rxmac_reset(struct gem *gp)
udelay(10);
}
if (limit == 5000) {
- printk(KERN_ERR "%s: RX reset command will not execute, resetting "
- "whole chip.\n", dev->name);
+ netdev_err(dev, "RX reset command will not execute, resetting whole chip\n");
return 1;
}
@@ -429,8 +419,7 @@ static int gem_rxmac_reset(struct gem *gp)
struct gem_rxd *rxd = &gp->init_block->rxd[i];
if (gp->rx_skbs[i] == NULL) {
- printk(KERN_ERR "%s: Parts of RX ring empty, resetting "
- "whole chip.\n", dev->name);
+ netdev_err(dev, "Parts of RX ring empty, resetting whole chip\n");
return 1;
}
@@ -479,8 +468,7 @@ static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_s
if (rxmac_stat & MAC_RXSTAT_OFLW) {
u32 smac = readl(gp->regs + MAC_SMACHINE);
- printk(KERN_ERR "%s: RX MAC fifo overflow smac[%08x].\n",
- dev->name, smac);
+ netdev_err(dev, "RX MAC fifo overflow smac[%08x]\n", smac);
gp->net_stats.rx_over_errors++;
gp->net_stats.rx_fifo_errors++;
@@ -542,19 +530,18 @@ static int gem_pci_interrupt(struct net_device *dev, struct gem *gp, u32 gem_sta
if (gp->pdev->vendor == PCI_VENDOR_ID_SUN &&
gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) {
- printk(KERN_ERR "%s: PCI error [%04x] ",
- dev->name, pci_estat);
+ netdev_err(dev, "PCI error [%04x]", pci_estat);
if (pci_estat & GREG_PCIESTAT_BADACK)
- printk("<No ACK64# during ABS64 cycle> ");
+ pr_cont(" <No ACK64# during ABS64 cycle>");
if (pci_estat & GREG_PCIESTAT_DTRTO)
- printk("<Delayed transaction timeout> ");
+ pr_cont(" <Delayed transaction timeout>");
if (pci_estat & GREG_PCIESTAT_OTHER)
- printk("<other>");
- printk("\n");
+ pr_cont(" <other>");
+ pr_cont("\n");
} else {
pci_estat |= GREG_PCIESTAT_OTHER;
- printk(KERN_ERR "%s: PCI error\n", dev->name);
+ netdev_err(dev, "PCI error\n");
}
if (pci_estat & GREG_PCIESTAT_OTHER) {
@@ -565,26 +552,20 @@ static int gem_pci_interrupt(struct net_device *dev, struct gem *gp, u32 gem_sta
*/
pci_read_config_word(gp->pdev, PCI_STATUS,
&pci_cfg_stat);
- printk(KERN_ERR "%s: Read PCI cfg space status [%04x]\n",
- dev->name, pci_cfg_stat);
+ netdev_err(dev, "Read PCI cfg space status [%04x]\n",
+ pci_cfg_stat);
if (pci_cfg_stat & PCI_STATUS_PARITY)
- printk(KERN_ERR "%s: PCI parity error detected.\n",
- dev->name);
+ netdev_err(dev, "PCI parity error detected\n");
if (pci_cfg_stat & PCI_STATUS_SIG_TARGET_ABORT)
- printk(KERN_ERR "%s: PCI target abort.\n",
- dev->name);
+ netdev_err(dev, "PCI target abort\n");
if (pci_cfg_stat & PCI_STATUS_REC_TARGET_ABORT)
- printk(KERN_ERR "%s: PCI master acks target abort.\n",
- dev->name);
+ netdev_err(dev, "PCI master acks target abort\n");
if (pci_cfg_stat & PCI_STATUS_REC_MASTER_ABORT)
- printk(KERN_ERR "%s: PCI master abort.\n",
- dev->name);
+ netdev_err(dev, "PCI master abort\n");
if (pci_cfg_stat & PCI_STATUS_SIG_SYSTEM_ERROR)
- printk(KERN_ERR "%s: PCI system error SERR#.\n",
- dev->name);
+ netdev_err(dev, "PCI system error SERR#\n");
if (pci_cfg_stat & PCI_STATUS_DETECTED_PARITY)
- printk(KERN_ERR "%s: PCI parity error.\n",
- dev->name);
+ netdev_err(dev, "PCI parity error\n");
/* Write the error bits back to clear them. */
pci_cfg_stat &= (PCI_STATUS_PARITY |
@@ -874,8 +855,7 @@ static int gem_rx(struct gem *gp, int work_to_do)
gp->rx_new = entry;
if (drops)
- printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n",
- gp->dev->name);
+ netdev_info(gp->dev, "Memory squeeze, deferring packet\n");
return work_done;
}
@@ -981,21 +961,19 @@ static void gem_tx_timeout(struct net_device *dev)
{
struct gem *gp = netdev_priv(dev);
- printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
+ netdev_err(dev, "transmit timed out, resetting\n");
if (!gp->running) {
- printk("%s: hrm.. hw not running !\n", dev->name);
+ netdev_err(dev, "hrm.. hw not running !\n");
return;
}
- printk(KERN_ERR "%s: TX_STATE[%08x:%08x:%08x]\n",
- dev->name,
- readl(gp->regs + TXDMA_CFG),
- readl(gp->regs + MAC_TXSTAT),
- readl(gp->regs + MAC_TXCFG));
- printk(KERN_ERR "%s: RX_STATE[%08x:%08x:%08x]\n",
- dev->name,
- readl(gp->regs + RXDMA_CFG),
- readl(gp->regs + MAC_RXSTAT),
- readl(gp->regs + MAC_RXCFG));
+ netdev_err(dev, "TX_STATE[%08x:%08x:%08x]\n",
+ readl(gp->regs + TXDMA_CFG),
+ readl(gp->regs + MAC_TXSTAT),
+ readl(gp->regs + MAC_TXCFG));
+ netdev_err(dev, "RX_STATE[%08x:%08x:%08x]\n",
+ readl(gp->regs + RXDMA_CFG),
+ readl(gp->regs + MAC_RXSTAT),
+ readl(gp->regs + MAC_RXCFG));
spin_lock_irq(&gp->lock);
spin_lock(&gp->tx_lock);
@@ -1048,8 +1026,7 @@ static netdev_tx_t gem_start_xmit(struct sk_buff *skb,
if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(dev);
spin_unlock_irqrestore(&gp->tx_lock, flags);
- printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
- dev->name);
+ netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
return NETDEV_TX_BUSY;
}
@@ -1158,8 +1135,7 @@ static void gem_pcs_reset(struct gem *gp)
break;
}
if (limit < 0)
- printk(KERN_WARNING "%s: PCS reset bit would not clear.\n",
- gp->dev->name);
+ netdev_warn(gp->dev, "PCS reset bit would not clear\n");
}
static void gem_pcs_reinit_adv(struct gem *gp)
@@ -1230,7 +1206,7 @@ static void gem_reset(struct gem *gp)
} while (val & (GREG_SWRST_TXRST | GREG_SWRST_RXRST));
if (limit < 0)
- printk(KERN_ERR "%s: SW reset is ghetto.\n", gp->dev->name);
+ netdev_err(gp->dev, "SW reset is ghetto\n");
if (gp->phy_type == phy_serialink || gp->phy_type == phy_serdes)
gem_pcs_reinit_adv(gp);
@@ -1395,9 +1371,8 @@ static int gem_set_link_modes(struct gem *gp)
speed = SPEED_1000;
}
- if (netif_msg_link(gp))
- printk(KERN_INFO "%s: Link is up at %d Mbps, %s-duplex.\n",
- gp->dev->name, speed, (full_duplex ? "full" : "half"));
+ netif_info(gp, link, gp->dev, "Link is up at %d Mbps, %s-duplex\n",
+ speed, (full_duplex ? "full" : "half"));
if (!gp->running)
return 0;
@@ -1451,15 +1426,13 @@ static int gem_set_link_modes(struct gem *gp)
if (netif_msg_link(gp)) {
if (pause) {
- printk(KERN_INFO "%s: Pause is enabled "
- "(rxfifo: %d off: %d on: %d)\n",
- gp->dev->name,
- gp->rx_fifo_sz,
- gp->rx_pause_off,
- gp->rx_pause_on);
+ netdev_info(gp->dev,
+ "Pause is enabled (rxfifo: %d off: %d on: %d)\n",
+ gp->rx_fifo_sz,
+ gp->rx_pause_off,
+ gp->rx_pause_on);
} else {
- printk(KERN_INFO "%s: Pause is disabled\n",
- gp->dev->name);
+ netdev_info(gp->dev, "Pause is disabled\n");
}
}
@@ -1484,9 +1457,8 @@ static int gem_mdio_link_not_up(struct gem *gp)
{
switch (gp->lstate) {
case link_force_ret:
- if (netif_msg_link(gp))
- printk(KERN_INFO "%s: Autoneg failed again, keeping"
- " forced mode\n", gp->dev->name);
+ netif_info(gp, link, gp->dev,
+ "Autoneg failed again, keeping forced mode\n");
gp->phy_mii.def->ops->setup_forced(&gp->phy_mii,
gp->last_forced_speed, DUPLEX_HALF);
gp->timer_ticks = 5;
@@ -1499,9 +1471,7 @@ static int gem_mdio_link_not_up(struct gem *gp)
*/
if (gp->phy_mii.def->magic_aneg)
return 1;
- if (netif_msg_link(gp))
- printk(KERN_INFO "%s: switching to forced 100bt\n",
- gp->dev->name);
+ netif_info(gp, link, gp->dev, "switching to forced 100bt\n");
/* Try forced modes. */
gp->phy_mii.def->ops->setup_forced(&gp->phy_mii, SPEED_100,
DUPLEX_HALF);
@@ -1517,9 +1487,8 @@ static int gem_mdio_link_not_up(struct gem *gp)
gp->phy_mii.def->ops->setup_forced(&gp->phy_mii, SPEED_10,
DUPLEX_HALF);
gp->timer_ticks = 5;
- if (netif_msg_link(gp))
- printk(KERN_INFO "%s: switching to forced 10bt\n",
- gp->dev->name);
+ netif_info(gp, link, gp->dev,
+ "switching to forced 10bt\n");
return 0;
} else
return 1;
@@ -1574,8 +1543,8 @@ static void gem_link_timer(unsigned long data)
gp->last_forced_speed = gp->phy_mii.speed;
gp->timer_ticks = 5;
if (netif_msg_link(gp))
- printk(KERN_INFO "%s: Got link after fallback, retrying"
- " autoneg once...\n", gp->dev->name);
+ netdev_info(gp->dev,
+ "Got link after fallback, retrying autoneg once...\n");
gp->phy_mii.def->ops->setup_aneg(&gp->phy_mii, gp->phy_mii.advertising);
} else if (gp->lstate != link_up) {
gp->lstate = link_up;
@@ -1589,9 +1558,7 @@ static void gem_link_timer(unsigned long data)
*/
if (gp->lstate == link_up) {
gp->lstate = link_down;
- if (netif_msg_link(gp))
- printk(KERN_INFO "%s: Link down\n",
- gp->dev->name);
+ netif_info(gp, link, gp->dev, "Link down\n");
netif_carrier_off(gp->dev);
gp->reset_task_pending = 1;
schedule_work(&gp->reset_task);
@@ -1746,8 +1713,7 @@ static void gem_init_phy(struct gem *gp)
if (phy_read(gp, MII_BMCR) != 0xffff)
break;
if (i == 2)
- printk(KERN_WARNING "%s: GMAC PHY not responding !\n",
- gp->dev->name);
+ netdev_warn(gp->dev, "GMAC PHY not responding !\n");
}
}
@@ -2038,7 +2004,7 @@ static int gem_check_invariants(struct gem *gp)
* as this chip has no gigabit PHY.
*/
if ((mif_cfg & (MIF_CFG_MDI0 | MIF_CFG_MDI1)) == 0) {
- printk(KERN_ERR PFX "RIO GEM lacks MII phy, mif_cfg[%08x]\n",
+ pr_err("RIO GEM lacks MII phy, mif_cfg[%08x]\n",
mif_cfg);
return -1;
}
@@ -2078,7 +2044,7 @@ static int gem_check_invariants(struct gem *gp)
}
if (i == 32) {
if (pdev->device != PCI_DEVICE_ID_SUN_GEM) {
- printk(KERN_ERR PFX "RIO MII phy will not respond.\n");
+ pr_err("RIO MII phy will not respond\n");
return -1;
}
gp->phy_type = phy_serdes;
@@ -2093,7 +2059,7 @@ static int gem_check_invariants(struct gem *gp)
if (pdev->device == PCI_DEVICE_ID_SUN_GEM) {
if (gp->tx_fifo_sz != (9 * 1024) ||
gp->rx_fifo_sz != (20 * 1024)) {
- printk(KERN_ERR PFX "GEM has bogus fifo sizes tx(%d) rx(%d)\n",
+ pr_err("GEM has bogus fifo sizes tx(%d) rx(%d)\n",
gp->tx_fifo_sz, gp->rx_fifo_sz);
return -1;
}
@@ -2101,7 +2067,7 @@ static int gem_check_invariants(struct gem *gp)
} else {
if (gp->tx_fifo_sz != (2 * 1024) ||
gp->rx_fifo_sz != (2 * 1024)) {
- printk(KERN_ERR PFX "RIO GEM has bogus fifo sizes tx(%d) rx(%d)\n",
+ pr_err("RIO GEM has bogus fifo sizes tx(%d) rx(%d)\n",
gp->tx_fifo_sz, gp->rx_fifo_sz);
return -1;
}
@@ -2239,7 +2205,7 @@ static int gem_do_start(struct net_device *dev)
if (request_irq(gp->pdev->irq, gem_interrupt,
IRQF_SHARED, dev->name, (void *)dev)) {
- printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name);
+ netdev_err(dev, "failed to request irq !\n");
spin_lock_irqsave(&gp->lock, flags);
spin_lock(&gp->tx_lock);
@@ -2378,9 +2344,8 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state)
mutex_lock(&gp->pm_mutex);
- printk(KERN_INFO "%s: suspending, WakeOnLan %s\n",
- dev->name,
- (gp->wake_on_lan && gp->opened) ? "enabled" : "disabled");
+ netdev_info(dev, "suspending, WakeOnLan %s\n",
+ (gp->wake_on_lan && gp->opened) ? "enabled" : "disabled");
/* Keep the cell enabled during the entire operation */
spin_lock_irqsave(&gp->lock, flags);
@@ -2440,7 +2405,7 @@ static int gem_resume(struct pci_dev *pdev)
struct gem *gp = netdev_priv(dev);
unsigned long flags;
- printk(KERN_INFO "%s: resuming\n", dev->name);
+ netdev_info(dev, "resuming\n");
mutex_lock(&gp->pm_mutex);
@@ -2452,8 +2417,7 @@ static int gem_resume(struct pci_dev *pdev)
/* Make sure PCI access and bus master are enabled */
if (pci_enable_device(gp->pdev)) {
- printk(KERN_ERR "%s: Can't re-enable chip !\n",
- dev->name);
+ netdev_err(dev, "Can't re-enable chip !\n");
/* Put cell and forget it for now, it will be considered as
* still asleep, a new sleep cycle may bring it back
*/
@@ -2938,7 +2902,7 @@ static int __devinit gem_get_device_address(struct gem *gp)
addr = idprom->id_ethaddr;
#else
printk("\n");
- printk(KERN_ERR "%s: can't get mac-address\n", dev->name);
+ pr_err("%s: can't get mac-address\n", dev->name);
return -1;
#endif
}
@@ -3009,14 +2973,12 @@ static const struct net_device_ops gem_netdev_ops = {
static int __devinit gem_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- static int gem_version_printed = 0;
unsigned long gemreg_base, gemreg_len;
struct net_device *dev;
struct gem *gp;
int err, pci_using_dac;
- if (gem_version_printed++ == 0)
- printk(KERN_INFO "%s", version);
+ printk_once(KERN_INFO "%s", version);
/* Apple gmac note: during probe, the chip is powered up by
* the arch code to allow the code below to work (and to let
@@ -3026,8 +2988,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
*/
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "Cannot enable MMIO operation, "
- "aborting.\n");
+ pr_err("Cannot enable MMIO operation, aborting\n");
return err;
}
pci_set_master(pdev);
@@ -3048,8 +3009,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
} else {
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (err) {
- printk(KERN_ERR PFX "No usable DMA configuration, "
- "aborting.\n");
+ pr_err("No usable DMA configuration, aborting\n");
goto err_disable_device;
}
pci_using_dac = 0;
@@ -3059,15 +3019,14 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
gemreg_len = pci_resource_len(pdev, 0);
if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0) {
- printk(KERN_ERR PFX "Cannot find proper PCI device "
- "base address, aborting.\n");
+ pr_err("Cannot find proper PCI device base address, aborting\n");
err = -ENODEV;
goto err_disable_device;
}
dev = alloc_etherdev(sizeof(*gp));
if (!dev) {
- printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+ pr_err("Etherdev alloc failed, aborting\n");
err = -ENOMEM;
goto err_disable_device;
}
@@ -3077,8 +3036,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
err = pci_request_regions(pdev, DRV_NAME);
if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources, "
- "aborting.\n");
+ pr_err("Cannot obtain PCI resources, aborting\n");
goto err_out_free_netdev;
}
@@ -3104,8 +3062,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
gp->regs = ioremap(gemreg_base, gemreg_len);
if (!gp->regs) {
- printk(KERN_ERR PFX "Cannot map device registers, "
- "aborting.\n");
+ pr_err("Cannot map device registers, aborting\n");
err = -EIO;
goto err_out_free_res;
}
@@ -3150,8 +3107,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
pci_alloc_consistent(pdev, sizeof(struct gem_init_block),
&gp->gblock_dvma);
if (!gp->init_block) {
- printk(KERN_ERR PFX "Cannot allocate init block, "
- "aborting.\n");
+ pr_err("Cannot allocate init block, aborting\n");
err = -ENOMEM;
goto err_out_iounmap;
}
@@ -3180,19 +3136,18 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
/* Register with kernel */
if (register_netdev(dev)) {
- printk(KERN_ERR PFX "Cannot register net device, "
- "aborting.\n");
+ pr_err("Cannot register net device, aborting\n");
err = -ENOMEM;
goto err_out_free_consistent;
}
- printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet %pM\n",
- dev->name, dev->dev_addr);
+ netdev_info(dev, "Sun GEM (PCI) 10/100/1000BaseT Ethernet %pM\n",
+ dev->dev_addr);
if (gp->phy_type == phy_mii_mdio0 ||
gp->phy_type == phy_mii_mdio1)
- printk(KERN_INFO "%s: Found %s PHY\n", dev->name,
- gp->phy_mii.def ? gp->phy_mii.def->name : "no");
+ netdev_info(dev, "Found %s PHY\n",
+ gp->phy_mii.def ? gp->phy_mii.def->name : "no");
/* GEM can do it all... */
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_LLTX;
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
index 78f8cee5fd74..d16880d7099b 100644
--- a/drivers/net/sungem_phy.c
+++ b/drivers/net/sungem_phy.c
@@ -88,7 +88,7 @@ static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
if ((val & BMCR_ISOLATE) && limit > 0)
__phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
- return (limit <= 0);
+ return limit <= 0;
}
static int bcm5201_init(struct mii_phy* phy)
@@ -1175,7 +1175,8 @@ int mii_phy_probe(struct mii_phy *phy, int mii_id)
/* Read ID and find matching entry */
id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
- printk(KERN_DEBUG "PHY ID: %x, addr: %x\n", id, mii_id);
+ printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n",
+ id, mii_id);
for (i=0; (def = mii_phy_table[i]) != NULL; i++)
if ((id & def->phy_id_mask) == def->phy_id)
break;
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index bd0df1c14955..5e28c414421a 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -1409,7 +1409,7 @@ force_link:
hp->timer_ticks = 0;
hp->happy_timer.expires = jiffies + (12 * HZ)/10; /* 1.2 sec. */
hp->happy_timer.data = (unsigned long) hp;
- hp->happy_timer.function = &happy_meal_timer;
+ hp->happy_timer.function = happy_meal_timer;
add_timer(&hp->happy_timer);
}
@@ -2497,7 +2497,7 @@ static u32 hme_get_link(struct net_device *dev)
hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR);
spin_unlock_irq(&hp->happy_lock);
- return (hp->sw_bmsr & BMSR_LSTATUS);
+ return hp->sw_bmsr & BMSR_LSTATUS;
}
static const struct ethtool_ops hme_ethtool_ops = {
@@ -2808,7 +2808,8 @@ static int __devinit happy_meal_sbus_probe_one(struct platform_device *op, int i
happy_meal_set_initial_advertisement(hp);
spin_unlock_irq(&hp->happy_lock);
- if (register_netdev(hp->dev)) {
+ err = register_netdev(hp->dev);
+ if (err) {
printk(KERN_ERR "happymeal: Cannot register net device, "
"aborting.\n");
goto err_out_free_coherent;
@@ -3130,7 +3131,8 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
happy_meal_set_initial_advertisement(hp);
spin_unlock_irq(&hp->happy_lock);
- if (register_netdev(hp->dev)) {
+ err = register_netdev(hp->dev);
+ if (err) {
printk(KERN_ERR "happymeal(PCI): Cannot register net device, "
"aborting.\n");
goto err_out_iounmap;
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 8dcb858f2168..2cf84e5968b2 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1483,7 +1483,7 @@ no_link_test:
*/
init_timer(&lp->multicast_timer);
lp->multicast_timer.data = (unsigned long) dev;
- lp->multicast_timer.function = &lance_set_multicast_retry;
+ lp->multicast_timer.function = lance_set_multicast_retry;
if (register_netdev(dev)) {
printk(KERN_ERR "SunLance: Cannot register device.\n");
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index 72e65d4666ef..9536b2f010be 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -711,7 +711,7 @@ static u32 qe_get_link(struct net_device *dev)
phyconfig = sbus_readb(mregs + MREGS_PHYCONFIG);
spin_unlock_irq(&qep->lock);
- return (phyconfig & MREGS_PHYCONFIG_LSTAT);
+ return phyconfig & MREGS_PHYCONFIG_LSTAT;
}
static const struct ethtool_ops qe_ethtool_ops = {
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index d281a7b34701..bf3c762de620 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -3,6 +3,8 @@
* Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -20,7 +22,6 @@
#include "sunvnet.h"
#define DRV_MODULE_NAME "sunvnet"
-#define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "1.0"
#define DRV_MODULE_RELDATE "June 25, 2007"
@@ -45,9 +46,9 @@ static int vnet_handle_unknown(struct vnet_port *port, void *arg)
{
struct vio_msg_tag *pkt = arg;
- printk(KERN_ERR PFX "Received unknown msg [%02x:%02x:%04x:%08x]\n",
+ pr_err("Received unknown msg [%02x:%02x:%04x:%08x]\n",
pkt->type, pkt->stype, pkt->stype_env, pkt->sid);
- printk(KERN_ERR PFX "Resetting connection.\n");
+ pr_err("Resetting connection\n");
ldc_disconnect(port->vio.lp);
@@ -400,8 +401,8 @@ static int vnet_rx(struct vnet_port *port, void *msgbuf)
if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA))
return 0;
if (unlikely(pkt->seq != dr->rcv_nxt)) {
- printk(KERN_ERR PFX "RX out of sequence seq[0x%llx] "
- "rcv_nxt[0x%llx]\n", pkt->seq, dr->rcv_nxt);
+ pr_err("RX out of sequence seq[0x%llx] rcv_nxt[0x%llx]\n",
+ pkt->seq, dr->rcv_nxt);
return 0;
}
@@ -464,8 +465,7 @@ static int handle_mcast(struct vnet_port *port, void *msgbuf)
struct vio_net_mcast_info *pkt = msgbuf;
if (pkt->tag.stype != VIO_SUBTYPE_ACK)
- printk(KERN_ERR PFX "%s: Got unexpected MCAST reply "
- "[%02x:%02x:%04x:%08x]\n",
+ pr_err("%s: Got unexpected MCAST reply [%02x:%02x:%04x:%08x]\n",
port->vp->dev->name,
pkt->tag.type,
pkt->tag.stype,
@@ -520,7 +520,7 @@ static void vnet_event(void *arg, int event)
}
if (unlikely(event != LDC_EVENT_DATA_READY)) {
- printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
+ pr_warning("Unexpected LDC event %d\n", event);
spin_unlock_irqrestore(&vio->lock, flags);
return;
}
@@ -662,8 +662,7 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
/* This is a hard error, log it. */
- printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
- "queue awake!\n", dev->name);
+ netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
dev->stats.tx_errors++;
}
spin_unlock_irqrestore(&port->vio.lock, flags);
@@ -696,8 +695,7 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
err = __vnet_tx_trigger(port);
if (unlikely(err < 0)) {
- printk(KERN_INFO PFX "%s: TX trigger error %d\n",
- dev->name, err);
+ netdev_info(dev, "TX trigger error %d\n", err);
d->hdr.state = VIO_DESC_FREE;
dev->stats.tx_carrier_errors++;
goto out_dropped_unlock;
@@ -952,12 +950,12 @@ static int __devinit vnet_port_alloc_tx_bufs(struct vnet_port *port)
err = -ENOMEM;
if (!buf) {
- printk(KERN_ERR "TX buffer allocation failure\n");
+ pr_err("TX buffer allocation failure\n");
goto err_out;
}
err = -EFAULT;
if ((unsigned long)buf & (8UL - 1)) {
- printk(KERN_ERR "TX buffer misaligned\n");
+ pr_err("TX buffer misaligned\n");
kfree(buf);
goto err_out;
}
@@ -1030,7 +1028,7 @@ static struct vnet * __devinit vnet_new(const u64 *local_mac)
dev = alloc_etherdev(sizeof(*vp));
if (!dev) {
- printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+ pr_err("Etherdev alloc failed, aborting\n");
return ERR_PTR(-ENOMEM);
}
@@ -1056,12 +1054,11 @@ static struct vnet * __devinit vnet_new(const u64 *local_mac)
err = register_netdev(dev);
if (err) {
- printk(KERN_ERR PFX "Cannot register net device, "
- "aborting.\n");
+ pr_err("Cannot register net device, aborting\n");
goto err_out_free_dev;
}
- printk(KERN_INFO "%s: Sun LDOM vnet %pM\n", dev->name, dev->dev_addr);
+ netdev_info(dev, "Sun LDOM vnet %pM\n", dev->dev_addr);
list_add(&vp->list, &vnet_list);
@@ -1133,10 +1130,7 @@ static struct vio_driver_ops vnet_vio_ops = {
static void __devinit print_version(void)
{
- static int version_printed;
-
- if (version_printed++ == 0)
- printk(KERN_INFO "%s", version);
+ printk_once(KERN_INFO "%s", version);
}
const char *remote_macaddr_prop = "remote-mac-address";
@@ -1157,7 +1151,7 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
vp = vnet_find_parent(hp, vdev->mp);
if (IS_ERR(vp)) {
- printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
+ pr_err("Cannot find port parent vnet\n");
err = PTR_ERR(vp);
goto err_out_put_mdesc;
}
@@ -1165,15 +1159,14 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len);
err = -ENODEV;
if (!rmac) {
- printk(KERN_ERR PFX "Port lacks %s property.\n",
- remote_macaddr_prop);
+ pr_err("Port lacks %s property\n", remote_macaddr_prop);
goto err_out_put_mdesc;
}
port = kzalloc(sizeof(*port), GFP_KERNEL);
err = -ENOMEM;
if (!port) {
- printk(KERN_ERR PFX "Cannot allocate vnet_port.\n");
+ pr_err("Cannot allocate vnet_port\n");
goto err_out_put_mdesc;
}
@@ -1214,9 +1207,8 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
dev_set_drvdata(&vdev->dev, port);
- printk(KERN_INFO "%s: PORT ( remote-mac %pM%s )\n",
- vp->dev->name, port->raddr,
- switch_port ? " switch-port" : "");
+ pr_info("%s: PORT ( remote-mac %pM%s )\n",
+ vp->dev->name, port->raddr, switch_port ? " switch-port" : "");
vio_port_up(&port->vio);
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index 99e423a5b9f1..b6eec8cea209 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1167,7 +1167,7 @@ static void print_eth(const u8 *add)
static int tc35815_tx_full(struct net_device *dev)
{
struct tc35815_local *lp = netdev_priv(dev);
- return ((lp->tfd_start + 1) % TX_FD_NUM == lp->tfd_end);
+ return (lp->tfd_start + 1) % TX_FD_NUM == lp->tfd_end;
}
static void tc35815_restart(struct net_device *dev)
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index 737df6032bbc..8b3dc1eb4015 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -92,7 +92,7 @@ static void bdx_rx_free(struct bdx_priv *priv);
static void bdx_tx_free(struct bdx_priv *priv);
/* Definitions needed by bdx_probe */
-static void bdx_ethtool_ops(struct net_device *netdev);
+static void bdx_set_ethtool_ops(struct net_device *netdev);
/*************************************************************************
* Print Info *
@@ -927,13 +927,6 @@ static void bdx_update_stats(struct bdx_priv *priv)
BDX_ASSERT((sizeof(struct bdx_stats) / sizeof(u64)) != i);
}
-static struct net_device_stats *bdx_get_stats(struct net_device *ndev)
-{
- struct bdx_priv *priv = netdev_priv(ndev);
- struct net_device_stats *net_stat = &priv->net_stats;
- return net_stat;
-}
-
static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len,
u16 rxd_vlan);
static void print_rxfd(struct rxf_desc *rxfd);
@@ -1220,6 +1213,7 @@ static void bdx_recycle_skb(struct bdx_priv *priv, struct rxd_desc *rxdd)
static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget)
{
+ struct net_device *ndev = priv->ndev;
struct sk_buff *skb, *skb2;
struct rxd_desc *rxdd;
struct rx_map *dm;
@@ -1273,7 +1267,7 @@ static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget)
if (unlikely(GET_RXD_ERR(rxd_val1))) {
DBG("rxd_err = 0x%x\n", GET_RXD_ERR(rxd_val1));
- priv->net_stats.rx_errors++;
+ ndev->stats.rx_errors++;
bdx_recycle_skb(priv, rxdd);
continue;
}
@@ -1300,15 +1294,16 @@ static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget)
bdx_rxdb_free_elem(db, rxdd->va_lo);
}
- priv->net_stats.rx_bytes += len;
+ ndev->stats.rx_bytes += len;
skb_put(skb, len);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- skb->protocol = eth_type_trans(skb, priv->ndev);
+ skb->protocol = eth_type_trans(skb, ndev);
/* Non-IP packets aren't checksum-offloaded */
if (GET_RXD_PKT_ID(rxd_val1) == 0)
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
+ else
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
NETIF_RX_MUX(priv, rxd_val1, rxd_vlan, skb);
@@ -1316,7 +1311,7 @@ static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget)
break;
}
- priv->net_stats.rx_packets += done;
+ ndev->stats.rx_packets += done;
/* FIXME: do smth to minimize pci accesses */
WRITE_REG(priv, f->m.reg_RPTR, f->m.rptr & TXF_WPTR_WR_PTR);
@@ -1712,8 +1707,8 @@ static netdev_tx_t bdx_tx_transmit(struct sk_buff *skb,
#ifdef BDX_LLTX
ndev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
#endif
- priv->net_stats.tx_packets++;
- priv->net_stats.tx_bytes += skb->len;
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += skb->len;
if (priv->tx_level < BDX_MIN_TX_LEVEL) {
DBG("%s: %s: TX Q STOP level %d\n",
@@ -1888,7 +1883,6 @@ static const struct net_device_ops bdx_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = bdx_ioctl,
.ndo_set_multicast_list = bdx_setmulti,
- .ndo_get_stats = bdx_get_stats,
.ndo_change_mtu = bdx_change_mtu,
.ndo_set_mac_address = bdx_set_mac,
.ndo_vlan_rx_register = bdx_vlan_rx_register,
@@ -2012,7 +2006,7 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ndev->netdev_ops = &bdx_netdev_ops;
ndev->tx_queue_len = BDX_NDEV_TXQ_LEN;
- bdx_ethtool_ops(ndev); /* ethtool interface */
+ bdx_set_ethtool_ops(ndev); /* ethtool interface */
/* these fields are used for info purposes only
* so we can have them same for all ports of the board */
@@ -2417,10 +2411,10 @@ static void bdx_get_ethtool_stats(struct net_device *netdev,
}
/*
- * bdx_ethtool_ops - ethtool interface implementation
+ * bdx_set_ethtool_ops - ethtool interface implementation
* @netdev
*/
-static void bdx_ethtool_ops(struct net_device *netdev)
+static void bdx_set_ethtool_ops(struct net_device *netdev)
{
static const struct ethtool_ops bdx_ethtool_ops = {
.get_settings = bdx_get_settings,
diff --git a/drivers/net/tehuti.h b/drivers/net/tehuti.h
index 67e3b71bf705..b6ba8601e2b5 100644
--- a/drivers/net/tehuti.h
+++ b/drivers/net/tehuti.h
@@ -269,7 +269,6 @@ struct bdx_priv {
u32 msg_enable;
int stats_flag;
struct bdx_stats hw_stats;
- struct net_device_stats net_stats;
struct pci_dev *pdev;
struct pci_nic *nic;
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 1ec4b9e0239a..30ccbb6d097a 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -69,10 +69,10 @@
#define DRV_MODULE_NAME "tg3"
#define TG3_MAJ_NUM 3
-#define TG3_MIN_NUM 113
+#define TG3_MIN_NUM 115
#define DRV_MODULE_VERSION \
__stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE "August 2, 2010"
+#define DRV_MODULE_RELDATE "October 14, 2010"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -101,9 +101,15 @@
* You can't change the ring sizes, but you can change where you place
* them in the NIC onboard memory.
*/
-#define TG3_RX_RING_SIZE 512
+#define TG3_RX_STD_RING_SIZE(tp) \
+ ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || \
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ? \
+ RX_STD_MAX_SIZE_5717 : 512)
#define TG3_DEF_RX_RING_PENDING 200
-#define TG3_RX_JUMBO_RING_SIZE 256
+#define TG3_RX_JMB_RING_SIZE(tp) \
+ ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || \
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ? \
+ 1024 : 256)
#define TG3_DEF_RX_JUMBO_RING_PENDING 100
#define TG3_RSS_INDIR_TBL_SIZE 128
@@ -113,19 +119,16 @@
* hw multiply/modulo instructions. Another solution would be to
* replace things like '% foo' with '& (foo - 1)'.
*/
-#define TG3_RX_RCB_RING_SIZE(tp) \
- (((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && \
- !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) ? 1024 : 512)
#define TG3_TX_RING_SIZE 512
#define TG3_DEF_TX_RING_PENDING (TG3_TX_RING_SIZE - 1)
-#define TG3_RX_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * \
- TG3_RX_RING_SIZE)
-#define TG3_RX_JUMBO_RING_BYTES (sizeof(struct tg3_ext_rx_buffer_desc) * \
- TG3_RX_JUMBO_RING_SIZE)
-#define TG3_RX_RCB_RING_BYTES(tp) (sizeof(struct tg3_rx_buffer_desc) * \
- TG3_RX_RCB_RING_SIZE(tp))
+#define TG3_RX_STD_RING_BYTES(tp) \
+ (sizeof(struct tg3_rx_buffer_desc) * TG3_RX_STD_RING_SIZE(tp))
+#define TG3_RX_JMB_RING_BYTES(tp) \
+ (sizeof(struct tg3_ext_rx_buffer_desc) * TG3_RX_JMB_RING_SIZE(tp))
+#define TG3_RX_RCB_RING_BYTES(tp) \
+ (sizeof(struct tg3_rx_buffer_desc) * (tp->rx_ret_ring_mask + 1))
#define TG3_TX_RING_BYTES (sizeof(struct tg3_tx_buffer_desc) * \
TG3_TX_RING_SIZE)
#define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1))
@@ -143,11 +146,11 @@
#define TG3_RX_STD_MAP_SZ TG3_RX_DMA_TO_MAP_SZ(TG3_RX_STD_DMA_SZ)
#define TG3_RX_JMB_MAP_SZ TG3_RX_DMA_TO_MAP_SZ(TG3_RX_JMB_DMA_SZ)
-#define TG3_RX_STD_BUFF_RING_SIZE \
- (sizeof(struct ring_info) * TG3_RX_RING_SIZE)
+#define TG3_RX_STD_BUFF_RING_SIZE(tp) \
+ (sizeof(struct ring_info) * TG3_RX_STD_RING_SIZE(tp))
-#define TG3_RX_JMB_BUFF_RING_SIZE \
- (sizeof(struct ring_info) * TG3_RX_JUMBO_RING_SIZE)
+#define TG3_RX_JMB_BUFF_RING_SIZE(tp) \
+ (sizeof(struct ring_info) * TG3_RX_JMB_RING_SIZE(tp))
/* Due to a hardware bug, the 5701 can only DMA to memory addresses
* that are at least dword aligned when used in PCIX mode. The driver
@@ -264,7 +267,6 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57788)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5717)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5718)},
- {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5724)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57781)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57785)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57761)},
@@ -752,42 +754,6 @@ static void tg3_int_reenable(struct tg3_napi *tnapi)
HOSTCC_MODE_ENABLE | tnapi->coal_now);
}
-static void tg3_napi_disable(struct tg3 *tp)
-{
- int i;
-
- for (i = tp->irq_cnt - 1; i >= 0; i--)
- napi_disable(&tp->napi[i].napi);
-}
-
-static void tg3_napi_enable(struct tg3 *tp)
-{
- int i;
-
- for (i = 0; i < tp->irq_cnt; i++)
- napi_enable(&tp->napi[i].napi);
-}
-
-static inline void tg3_netif_stop(struct tg3 *tp)
-{
- tp->dev->trans_start = jiffies; /* prevent tx timeout */
- tg3_napi_disable(tp);
- netif_tx_disable(tp->dev);
-}
-
-static inline void tg3_netif_start(struct tg3 *tp)
-{
- /* NOTE: unconditional netif_tx_wake_all_queues is only
- * appropriate so long as all callers are assured to
- * have free tx slots (such as after tg3_init_hw)
- */
- netif_tx_wake_all_queues(tp->dev);
-
- tg3_napi_enable(tp);
- tp->napi[0].hw_status->status |= SD_STATUS_UPDATED;
- tg3_enable_ints(tp);
-}
-
static void tg3_switch_clocks(struct tg3 *tp)
{
u32 clock_ctrl;
@@ -1196,6 +1162,52 @@ static void tg3_mdio_fini(struct tg3 *tp)
}
}
+static int tg3_phy_cl45_write(struct tg3 *tp, u32 devad, u32 addr, u32 val)
+{
+ int err;
+
+ err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad);
+ if (err)
+ goto done;
+
+ err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr);
+ if (err)
+ goto done;
+
+ err = tg3_writephy(tp, MII_TG3_MMD_CTRL,
+ MII_TG3_MMD_CTRL_DATA_NOINC | devad);
+ if (err)
+ goto done;
+
+ err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, val);
+
+done:
+ return err;
+}
+
+static int tg3_phy_cl45_read(struct tg3 *tp, u32 devad, u32 addr, u32 *val)
+{
+ int err;
+
+ err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad);
+ if (err)
+ goto done;
+
+ err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr);
+ if (err)
+ goto done;
+
+ err = tg3_writephy(tp, MII_TG3_MMD_CTRL,
+ MII_TG3_MMD_CTRL_DATA_NOINC | devad);
+ if (err)
+ goto done;
+
+ err = tg3_readphy(tp, MII_TG3_MMD_ADDRESS, val);
+
+done:
+ return err;
+}
+
/* tp->lock is held. */
static inline void tg3_generate_fw_event(struct tg3 *tp)
{
@@ -1572,6 +1584,17 @@ static void tg3_phy_fini(struct tg3 *tp)
}
}
+static int tg3_phydsp_read(struct tg3 *tp, u32 reg, u32 *val)
+{
+ int err;
+
+ err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg);
+ if (!err)
+ err = tg3_readphy(tp, MII_TG3_DSP_RW_PORT, val);
+
+ return err;
+}
+
static int tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val)
{
int err;
@@ -1735,6 +1758,42 @@ static void tg3_phy_apply_otp(struct tg3 *tp)
tg3_writephy(tp, MII_TG3_AUX_CTRL, phy);
}
+static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
+{
+ u32 val;
+
+ if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP))
+ return;
+
+ tp->setlpicnt = 0;
+
+ if (tp->link_config.autoneg == AUTONEG_ENABLE &&
+ current_link_up == 1 &&
+ (tp->link_config.active_speed == SPEED_1000 ||
+ (tp->link_config.active_speed == SPEED_100 &&
+ tp->link_config.active_duplex == DUPLEX_FULL))) {
+ u32 eeectl;
+
+ if (tp->link_config.active_speed == SPEED_1000)
+ eeectl = TG3_CPMU_EEE_CTRL_EXIT_16_5_US;
+ else
+ eeectl = TG3_CPMU_EEE_CTRL_EXIT_36_US;
+
+ tw32(TG3_CPMU_EEE_CTRL, eeectl);
+
+ tg3_phy_cl45_read(tp, 0x7, TG3_CL45_D7_EEERES_STAT, &val);
+
+ if (val == TG3_CL45_D7_EEERES_STAT_LP_1000T ||
+ val == TG3_CL45_D7_EEERES_STAT_LP_100TX)
+ tp->setlpicnt = 2;
+ }
+
+ if (!tp->setlpicnt) {
+ val = tr32(TG3_CPMU_EEE_MODE);
+ tw32(TG3_CPMU_EEE_MODE, val & ~TG3_CPMU_EEEMD_LPI_ENABLE);
+ }
+}
+
static int tg3_wait_macro_done(struct tg3 *tp)
{
int limit = 100;
@@ -1917,19 +1976,16 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
*/
static int tg3_phy_reset(struct tg3 *tp)
{
- u32 cpmuctrl;
- u32 phy_status;
+ u32 val, cpmuctrl;
int err;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
- u32 val;
-
val = tr32(GRC_MISC_CFG);
tw32_f(GRC_MISC_CFG, val & ~GRC_MISC_CFG_EPHY_IDDQ);
udelay(40);
}
- err = tg3_readphy(tp, MII_BMSR, &phy_status);
- err |= tg3_readphy(tp, MII_BMSR, &phy_status);
+ err = tg3_readphy(tp, MII_BMSR, &val);
+ err |= tg3_readphy(tp, MII_BMSR, &val);
if (err != 0)
return -EBUSY;
@@ -1961,18 +2017,14 @@ static int tg3_phy_reset(struct tg3 *tp)
return err;
if (cpmuctrl & CPMU_CTRL_GPHY_10MB_RXONLY) {
- u32 phy;
-
- phy = MII_TG3_DSP_EXP8_AEDW | MII_TG3_DSP_EXP8_REJ2MHz;
- tg3_phydsp_write(tp, MII_TG3_DSP_EXP8, phy);
+ val = MII_TG3_DSP_EXP8_AEDW | MII_TG3_DSP_EXP8_REJ2MHz;
+ tg3_phydsp_write(tp, MII_TG3_DSP_EXP8, val);
tw32(TG3_CPMU_CTRL, cpmuctrl);
}
if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX ||
GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5761_AX) {
- u32 val;
-
val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
if ((val & CPMU_LSPD_1000MB_MACCLK_MASK) ==
CPMU_LSPD_1000MB_MACCLK_12_5) {
@@ -2028,23 +2080,19 @@ out:
/* Cannot do read-modify-write on 5401 */
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20);
} else if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) {
- u32 phy_reg;
-
/* Set bit 14 with read-modify-write to preserve other bits */
if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0007) &&
- !tg3_readphy(tp, MII_TG3_AUX_CTRL, &phy_reg))
- tg3_writephy(tp, MII_TG3_AUX_CTRL, phy_reg | 0x4000);
+ !tg3_readphy(tp, MII_TG3_AUX_CTRL, &val))
+ tg3_writephy(tp, MII_TG3_AUX_CTRL, val | 0x4000);
}
/* Set phy register 0x10 bit 0 to high fifo elasticity to support
* jumbo frames transmission.
*/
if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) {
- u32 phy_reg;
-
- if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &phy_reg))
+ if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &val))
tg3_writephy(tp, MII_TG3_EXT_CTRL,
- phy_reg | MII_TG3_EXT_CTRL_FIFO_ELASTIC);
+ val | MII_TG3_EXT_CTRL_FIFO_ELASTIC);
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
@@ -2920,6 +2968,44 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
tg3_writephy(tp, MII_TG3_CTRL, new_adv);
}
+ if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
+ u32 val = 0;
+
+ tw32(TG3_CPMU_EEE_MODE,
+ tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE);
+
+ /* Enable SM_DSP clock and tx 6dB coding. */
+ val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL |
+ MII_TG3_AUXCTL_ACTL_SMDSP_ENA |
+ MII_TG3_AUXCTL_ACTL_TX_6DB;
+ tg3_writephy(tp, MII_TG3_AUX_CTRL, val);
+
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) &&
+ !tg3_phydsp_read(tp, MII_TG3_DSP_CH34TP2, &val))
+ tg3_phydsp_write(tp, MII_TG3_DSP_CH34TP2,
+ val | MII_TG3_DSP_CH34TP2_HIBW01);
+
+ if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+ /* Advertise 100-BaseTX EEE ability */
+ if (tp->link_config.advertising &
+ (ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full))
+ val |= TG3_CL45_D7_EEEADV_CAP_100TX;
+ /* Advertise 1000-BaseT EEE ability */
+ if (tp->link_config.advertising &
+ (ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full))
+ val |= TG3_CL45_D7_EEEADV_CAP_1000T;
+ }
+ tg3_phy_cl45_write(tp, 0x7, TG3_CL45_D7_EEEADV_CAP, val);
+
+ /* Turn off SM_DSP clock. */
+ val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL |
+ MII_TG3_AUXCTL_ACTL_TX_6DB;
+ tg3_writephy(tp, MII_TG3_AUX_CTRL, val);
+ }
+
if (tp->link_config.autoneg == AUTONEG_DISABLE &&
tp->link_config.speed != SPEED_INVALID) {
u32 bmcr, orig_bmcr;
@@ -3060,7 +3146,7 @@ static int tg3_adv_1000T_flowctrl_ok(struct tg3 *tp, u32 *lcladv, u32 *rmtadv)
static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
{
int current_link_up;
- u32 bmsr, dummy;
+ u32 bmsr, val;
u32 lcl_adv, rmt_adv;
u16 current_speed;
u8 current_duplex;
@@ -3140,8 +3226,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
}
/* Clear pending interrupts... */
- tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
- tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
+ tg3_readphy(tp, MII_TG3_ISTAT, &val);
+ tg3_readphy(tp, MII_TG3_ISTAT, &val);
if (tp->phy_flags & TG3_PHYFLG_USE_MI_INTERRUPT)
tg3_writephy(tp, MII_TG3_IMASK, ~MII_TG3_INT_LINKCHG);
@@ -3162,8 +3248,6 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
current_duplex = DUPLEX_INVALID;
if (tp->phy_flags & TG3_PHYFLG_CAPACITIVE_COUPLING) {
- u32 val;
-
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4007);
tg3_readphy(tp, MII_TG3_AUX_CTRL, &val);
if (!(val & (1 << 10))) {
@@ -3238,13 +3322,11 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
relink:
if (current_link_up == 0 || (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
- u32 tmp;
-
tg3_phy_copper_begin(tp);
- tg3_readphy(tp, MII_BMSR, &tmp);
- if (!tg3_readphy(tp, MII_BMSR, &tmp) &&
- (tmp & BMSR_LSTATUS))
+ tg3_readphy(tp, MII_BMSR, &bmsr);
+ if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
+ (bmsr & BMSR_LSTATUS))
current_link_up = 1;
}
@@ -3285,6 +3367,8 @@ relink:
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
+ tg3_phy_eee_adjust(tp, current_link_up);
+
if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) {
/* Polled via timer. */
tw32_f(MAC_EVENT, 0);
@@ -4353,6 +4437,11 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
return err;
}
+static inline int tg3_irq_sync(struct tg3 *tp)
+{
+ return tp->irq_sync;
+}
+
/* This is called whenever we suspect that the system chipset is re-
* ordering the sequence of MMIO to the tx send mailbox. The symptom
* is bogus tx completions. We try to recover by setting the
@@ -4484,22 +4573,21 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, struct tg3_rx_prodring_set *tpr,
u32 opaque_key, u32 dest_idx_unmasked)
{
struct tg3_rx_buffer_desc *desc;
- struct ring_info *map, *src_map;
+ struct ring_info *map;
struct sk_buff *skb;
dma_addr_t mapping;
int skb_size, dest_idx;
- src_map = NULL;
switch (opaque_key) {
case RXD_OPAQUE_RING_STD:
- dest_idx = dest_idx_unmasked % TG3_RX_RING_SIZE;
+ dest_idx = dest_idx_unmasked & tp->rx_std_ring_mask;
desc = &tpr->rx_std[dest_idx];
map = &tpr->rx_std_buffers[dest_idx];
skb_size = tp->rx_pkt_map_sz;
break;
case RXD_OPAQUE_RING_JUMBO:
- dest_idx = dest_idx_unmasked % TG3_RX_JUMBO_RING_SIZE;
+ dest_idx = dest_idx_unmasked & tp->rx_jmb_ring_mask;
desc = &tpr->rx_jmb[dest_idx].std;
map = &tpr->rx_jmb_buffers[dest_idx];
skb_size = TG3_RX_JMB_MAP_SZ;
@@ -4549,12 +4637,12 @@ static void tg3_recycle_rx(struct tg3_napi *tnapi,
struct tg3 *tp = tnapi->tp;
struct tg3_rx_buffer_desc *src_desc, *dest_desc;
struct ring_info *src_map, *dest_map;
- struct tg3_rx_prodring_set *spr = &tp->prodring[0];
+ struct tg3_rx_prodring_set *spr = &tp->napi[0].prodring;
int dest_idx;
switch (opaque_key) {
case RXD_OPAQUE_RING_STD:
- dest_idx = dest_idx_unmasked % TG3_RX_RING_SIZE;
+ dest_idx = dest_idx_unmasked & tp->rx_std_ring_mask;
dest_desc = &dpr->rx_std[dest_idx];
dest_map = &dpr->rx_std_buffers[dest_idx];
src_desc = &spr->rx_std[src_idx];
@@ -4562,7 +4650,7 @@ static void tg3_recycle_rx(struct tg3_napi *tnapi,
break;
case RXD_OPAQUE_RING_JUMBO:
- dest_idx = dest_idx_unmasked % TG3_RX_JUMBO_RING_SIZE;
+ dest_idx = dest_idx_unmasked & tp->rx_jmb_ring_mask;
dest_desc = &dpr->rx_jmb[dest_idx].std;
dest_map = &dpr->rx_jmb_buffers[dest_idx];
src_desc = &spr->rx_jmb[src_idx].std;
@@ -4619,7 +4707,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
u32 sw_idx = tnapi->rx_rcb_ptr;
u16 hw_idx;
int received;
- struct tg3_rx_prodring_set *tpr = tnapi->prodring;
+ struct tg3_rx_prodring_set *tpr = &tnapi->prodring;
hw_idx = *(tnapi->rx_rcb_prod_idx);
/*
@@ -4644,13 +4732,13 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
if (opaque_key == RXD_OPAQUE_RING_STD) {
- ri = &tp->prodring[0].rx_std_buffers[desc_idx];
+ ri = &tp->napi[0].prodring.rx_std_buffers[desc_idx];
dma_addr = dma_unmap_addr(ri, mapping);
skb = ri->skb;
post_ptr = &std_prod_idx;
rx_std_posted++;
} else if (opaque_key == RXD_OPAQUE_RING_JUMBO) {
- ri = &tp->prodring[0].rx_jmb_buffers[desc_idx];
+ ri = &tp->napi[0].prodring.rx_jmb_buffers[desc_idx];
dma_addr = dma_unmap_addr(ri, mapping);
skb = ri->skb;
post_ptr = &jmb_prod_idx;
@@ -4719,7 +4807,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
>> RXD_TCPCSUM_SHIFT) == 0xffff))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
skb->protocol = eth_type_trans(skb, tp->dev);
@@ -4762,7 +4850,8 @@ next_pkt:
(*post_ptr)++;
if (unlikely(rx_std_posted >= tp->rx_std_max_post)) {
- tpr->rx_std_prod_idx = std_prod_idx % TG3_RX_RING_SIZE;
+ tpr->rx_std_prod_idx = std_prod_idx &
+ tp->rx_std_ring_mask;
tw32_rx_mbox(TG3_RX_STD_PROD_IDX_REG,
tpr->rx_std_prod_idx);
work_mask &= ~RXD_OPAQUE_RING_STD;
@@ -4770,7 +4859,7 @@ next_pkt:
}
next_pkt_nopost:
sw_idx++;
- sw_idx &= (TG3_RX_RCB_RING_SIZE(tp) - 1);
+ sw_idx &= tp->rx_ret_ring_mask;
/* Refresh hw_idx to see if there is new work */
if (sw_idx == hw_idx) {
@@ -4786,13 +4875,14 @@ next_pkt_nopost:
/* Refill RX ring(s). */
if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)) {
if (work_mask & RXD_OPAQUE_RING_STD) {
- tpr->rx_std_prod_idx = std_prod_idx % TG3_RX_RING_SIZE;
+ tpr->rx_std_prod_idx = std_prod_idx &
+ tp->rx_std_ring_mask;
tw32_rx_mbox(TG3_RX_STD_PROD_IDX_REG,
tpr->rx_std_prod_idx);
}
if (work_mask & RXD_OPAQUE_RING_JUMBO) {
- tpr->rx_jmb_prod_idx = jmb_prod_idx %
- TG3_RX_JUMBO_RING_SIZE;
+ tpr->rx_jmb_prod_idx = jmb_prod_idx &
+ tp->rx_jmb_ring_mask;
tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG,
tpr->rx_jmb_prod_idx);
}
@@ -4803,8 +4893,8 @@ next_pkt_nopost:
*/
smp_wmb();
- tpr->rx_std_prod_idx = std_prod_idx % TG3_RX_RING_SIZE;
- tpr->rx_jmb_prod_idx = jmb_prod_idx % TG3_RX_JUMBO_RING_SIZE;
+ tpr->rx_std_prod_idx = std_prod_idx & tp->rx_std_ring_mask;
+ tpr->rx_jmb_prod_idx = jmb_prod_idx & tp->rx_jmb_ring_mask;
if (tnapi != &tp->napi[1])
napi_schedule(&tp->napi[1].napi);
@@ -4860,9 +4950,11 @@ static int tg3_rx_prodring_xfer(struct tg3 *tp,
if (spr->rx_std_cons_idx < src_prod_idx)
cpycnt = src_prod_idx - spr->rx_std_cons_idx;
else
- cpycnt = TG3_RX_RING_SIZE - spr->rx_std_cons_idx;
+ cpycnt = tp->rx_std_ring_mask + 1 -
+ spr->rx_std_cons_idx;
- cpycnt = min(cpycnt, TG3_RX_RING_SIZE - dpr->rx_std_prod_idx);
+ cpycnt = min(cpycnt,
+ tp->rx_std_ring_mask + 1 - dpr->rx_std_prod_idx);
si = spr->rx_std_cons_idx;
di = dpr->rx_std_prod_idx;
@@ -4896,10 +4988,10 @@ static int tg3_rx_prodring_xfer(struct tg3 *tp,
dbd->addr_lo = sbd->addr_lo;
}
- spr->rx_std_cons_idx = (spr->rx_std_cons_idx + cpycnt) %
- TG3_RX_RING_SIZE;
- dpr->rx_std_prod_idx = (dpr->rx_std_prod_idx + cpycnt) %
- TG3_RX_RING_SIZE;
+ spr->rx_std_cons_idx = (spr->rx_std_cons_idx + cpycnt) &
+ tp->rx_std_ring_mask;
+ dpr->rx_std_prod_idx = (dpr->rx_std_prod_idx + cpycnt) &
+ tp->rx_std_ring_mask;
}
while (1) {
@@ -4916,10 +5008,11 @@ static int tg3_rx_prodring_xfer(struct tg3 *tp,
if (spr->rx_jmb_cons_idx < src_prod_idx)
cpycnt = src_prod_idx - spr->rx_jmb_cons_idx;
else
- cpycnt = TG3_RX_JUMBO_RING_SIZE - spr->rx_jmb_cons_idx;
+ cpycnt = tp->rx_jmb_ring_mask + 1 -
+ spr->rx_jmb_cons_idx;
cpycnt = min(cpycnt,
- TG3_RX_JUMBO_RING_SIZE - dpr->rx_jmb_prod_idx);
+ tp->rx_jmb_ring_mask + 1 - dpr->rx_jmb_prod_idx);
si = spr->rx_jmb_cons_idx;
di = dpr->rx_jmb_prod_idx;
@@ -4953,10 +5046,10 @@ static int tg3_rx_prodring_xfer(struct tg3 *tp,
dbd->addr_lo = sbd->addr_lo;
}
- spr->rx_jmb_cons_idx = (spr->rx_jmb_cons_idx + cpycnt) %
- TG3_RX_JUMBO_RING_SIZE;
- dpr->rx_jmb_prod_idx = (dpr->rx_jmb_prod_idx + cpycnt) %
- TG3_RX_JUMBO_RING_SIZE;
+ spr->rx_jmb_cons_idx = (spr->rx_jmb_cons_idx + cpycnt) &
+ tp->rx_jmb_ring_mask;
+ dpr->rx_jmb_prod_idx = (dpr->rx_jmb_prod_idx + cpycnt) &
+ tp->rx_jmb_ring_mask;
}
return err;
@@ -4981,14 +5074,14 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget)
work_done += tg3_rx(tnapi, budget - work_done);
if ((tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) && tnapi == &tp->napi[1]) {
- struct tg3_rx_prodring_set *dpr = &tp->prodring[0];
+ struct tg3_rx_prodring_set *dpr = &tp->napi[0].prodring;
int i, err = 0;
u32 std_prod_idx = dpr->rx_std_prod_idx;
u32 jmb_prod_idx = dpr->rx_jmb_prod_idx;
for (i = 1; i < tp->irq_cnt; i++)
err |= tg3_rx_prodring_xfer(tp, dpr,
- tp->napi[i].prodring);
+ &tp->napi[i].prodring);
wmb();
@@ -5098,6 +5191,59 @@ tx_recovery:
return work_done;
}
+static void tg3_napi_disable(struct tg3 *tp)
+{
+ int i;
+
+ for (i = tp->irq_cnt - 1; i >= 0; i--)
+ napi_disable(&tp->napi[i].napi);
+}
+
+static void tg3_napi_enable(struct tg3 *tp)
+{
+ int i;
+
+ for (i = 0; i < tp->irq_cnt; i++)
+ napi_enable(&tp->napi[i].napi);
+}
+
+static void tg3_napi_init(struct tg3 *tp)
+{
+ int i;
+
+ netif_napi_add(tp->dev, &tp->napi[0].napi, tg3_poll, 64);
+ for (i = 1; i < tp->irq_cnt; i++)
+ netif_napi_add(tp->dev, &tp->napi[i].napi, tg3_poll_msix, 64);
+}
+
+static void tg3_napi_fini(struct tg3 *tp)
+{
+ int i;
+
+ for (i = 0; i < tp->irq_cnt; i++)
+ netif_napi_del(&tp->napi[i].napi);
+}
+
+static inline void tg3_netif_stop(struct tg3 *tp)
+{
+ tp->dev->trans_start = jiffies; /* prevent tx timeout */
+ tg3_napi_disable(tp);
+ netif_tx_disable(tp->dev);
+}
+
+static inline void tg3_netif_start(struct tg3 *tp)
+{
+ /* NOTE: unconditional netif_tx_wake_all_queues is only
+ * appropriate so long as all callers are assured to
+ * have free tx slots (such as after tg3_init_hw)
+ */
+ netif_tx_wake_all_queues(tp->dev);
+
+ tg3_napi_enable(tp);
+ tp->napi[0].hw_status->status |= SD_STATUS_UPDATED;
+ tg3_enable_ints(tp);
+}
+
static void tg3_irq_quiesce(struct tg3 *tp)
{
int i;
@@ -5111,11 +5257,6 @@ static void tg3_irq_quiesce(struct tg3 *tp)
synchronize_irq(tp->napi[i].irq_vec);
}
-static inline int tg3_irq_sync(struct tg3 *tp)
-{
- return tp->irq_sync;
-}
-
/* Fully shutdown all tg3 driver activity elsewhere in the system.
* If irq_sync is non-zero, then the IRQ handler must be synchronized
* with as well. Most of the time, this is not necessary except when
@@ -5404,8 +5545,7 @@ static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len)
{
u32 base = (u32) mapping & 0xffffffff;
- return ((base > 0xffffdcc0) &&
- (base + len + 8 < base));
+ return (base > 0xffffdcc0) && (base + len + 8 < base);
}
/* Test for DMA addresses > 40-bit */
@@ -5414,7 +5554,7 @@ static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping,
{
#if defined(CONFIG_HIGHMEM) && (BITS_PER_LONG == 64)
if (tp->tg3_flags & TG3_FLAG_40BIT_DMA_BUG)
- return (((u64) mapping + len) > DMA_BIT_MASK(40));
+ return ((u64) mapping + len) > DMA_BIT_MASK(40);
return 0;
#else
return 0;
@@ -5574,9 +5714,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
goto out_unlock;
}
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+ if (skb_is_gso_v6(skb)) {
hdrlen = skb_headlen(skb) - ETH_HLEN;
- else {
+ } else {
struct iphdr *iph = ip_hdr(skb);
tcp_opt_len = tcp_optlen(skb);
@@ -5605,7 +5745,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
}
#if TG3_VLAN_TAG_USED
- if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
+ if (vlan_tx_tag_present(skb))
base_flags |= (TXD_FLAG_VLAN |
(vlan_tx_tag_get(skb) << 16));
#endif
@@ -5798,7 +5938,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
iph = ip_hdr(skb);
tcp_opt_len = tcp_optlen(skb);
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
+ if (skb_is_gso_v6(skb)) {
hdr_len = skb_headlen(skb) - ETH_HLEN;
} else {
u32 ip_tcp_len;
@@ -5851,7 +5991,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
}
}
#if TG3_VLAN_TAG_USED
- if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
+ if (vlan_tx_tag_present(skb))
base_flags |= (TXD_FLAG_VLAN |
(vlan_tx_tag_get(skb) << 16));
#endif
@@ -6057,16 +6197,16 @@ static void tg3_rx_prodring_free(struct tg3 *tp,
{
int i;
- if (tpr != &tp->prodring[0]) {
+ if (tpr != &tp->napi[0].prodring) {
for (i = tpr->rx_std_cons_idx; i != tpr->rx_std_prod_idx;
- i = (i + 1) % TG3_RX_RING_SIZE)
+ i = (i + 1) & tp->rx_std_ring_mask)
tg3_rx_skb_free(tp, &tpr->rx_std_buffers[i],
tp->rx_pkt_map_sz);
if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) {
for (i = tpr->rx_jmb_cons_idx;
i != tpr->rx_jmb_prod_idx;
- i = (i + 1) % TG3_RX_JUMBO_RING_SIZE) {
+ i = (i + 1) & tp->rx_jmb_ring_mask) {
tg3_rx_skb_free(tp, &tpr->rx_jmb_buffers[i],
TG3_RX_JMB_MAP_SZ);
}
@@ -6075,12 +6215,13 @@ static void tg3_rx_prodring_free(struct tg3 *tp,
return;
}
- for (i = 0; i < TG3_RX_RING_SIZE; i++)
+ for (i = 0; i <= tp->rx_std_ring_mask; i++)
tg3_rx_skb_free(tp, &tpr->rx_std_buffers[i],
tp->rx_pkt_map_sz);
- if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) {
- for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++)
+ if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) &&
+ !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
+ for (i = 0; i <= tp->rx_jmb_ring_mask; i++)
tg3_rx_skb_free(tp, &tpr->rx_jmb_buffers[i],
TG3_RX_JMB_MAP_SZ);
}
@@ -6103,16 +6244,17 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp,
tpr->rx_jmb_cons_idx = 0;
tpr->rx_jmb_prod_idx = 0;
- if (tpr != &tp->prodring[0]) {
- memset(&tpr->rx_std_buffers[0], 0, TG3_RX_STD_BUFF_RING_SIZE);
- if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE)
+ if (tpr != &tp->napi[0].prodring) {
+ memset(&tpr->rx_std_buffers[0], 0,
+ TG3_RX_STD_BUFF_RING_SIZE(tp));
+ if (tpr->rx_jmb_buffers)
memset(&tpr->rx_jmb_buffers[0], 0,
- TG3_RX_JMB_BUFF_RING_SIZE);
+ TG3_RX_JMB_BUFF_RING_SIZE(tp));
goto done;
}
/* Zero out all descriptors. */
- memset(tpr->rx_std, 0, TG3_RX_RING_BYTES);
+ memset(tpr->rx_std, 0, TG3_RX_STD_RING_BYTES(tp));
rx_pkt_dma_sz = TG3_RX_STD_DMA_SZ;
if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) &&
@@ -6124,7 +6266,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp,
* stuff once. This works because the card does not
* write into the rx buffer posting rings.
*/
- for (i = 0; i < TG3_RX_RING_SIZE; i++) {
+ for (i = 0; i <= tp->rx_std_ring_mask; i++) {
struct tg3_rx_buffer_desc *rxd;
rxd = &tpr->rx_std[i];
@@ -6148,15 +6290,16 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp,
}
}
- if (!(tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE))
+ if (!(tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) ||
+ (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
goto done;
- memset(tpr->rx_jmb, 0, TG3_RX_JUMBO_RING_BYTES);
+ memset(tpr->rx_jmb, 0, TG3_RX_JMB_RING_BYTES(tp));
if (!(tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE))
goto done;
- for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) {
+ for (i = 0; i <= tp->rx_jmb_ring_mask; i++) {
struct tg3_rx_buffer_desc *rxd;
rxd = &tpr->rx_jmb[i].std;
@@ -6196,12 +6339,12 @@ static void tg3_rx_prodring_fini(struct tg3 *tp,
kfree(tpr->rx_jmb_buffers);
tpr->rx_jmb_buffers = NULL;
if (tpr->rx_std) {
- pci_free_consistent(tp->pdev, TG3_RX_RING_BYTES,
+ pci_free_consistent(tp->pdev, TG3_RX_STD_RING_BYTES(tp),
tpr->rx_std, tpr->rx_std_mapping);
tpr->rx_std = NULL;
}
if (tpr->rx_jmb) {
- pci_free_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES,
+ pci_free_consistent(tp->pdev, TG3_RX_JMB_RING_BYTES(tp),
tpr->rx_jmb, tpr->rx_jmb_mapping);
tpr->rx_jmb = NULL;
}
@@ -6210,23 +6353,25 @@ static void tg3_rx_prodring_fini(struct tg3 *tp,
static int tg3_rx_prodring_init(struct tg3 *tp,
struct tg3_rx_prodring_set *tpr)
{
- tpr->rx_std_buffers = kzalloc(TG3_RX_STD_BUFF_RING_SIZE, GFP_KERNEL);
+ tpr->rx_std_buffers = kzalloc(TG3_RX_STD_BUFF_RING_SIZE(tp),
+ GFP_KERNEL);
if (!tpr->rx_std_buffers)
return -ENOMEM;
- tpr->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_RING_BYTES,
+ tpr->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_STD_RING_BYTES(tp),
&tpr->rx_std_mapping);
if (!tpr->rx_std)
goto err_out;
- if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) {
- tpr->rx_jmb_buffers = kzalloc(TG3_RX_JMB_BUFF_RING_SIZE,
+ if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) &&
+ !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
+ tpr->rx_jmb_buffers = kzalloc(TG3_RX_JMB_BUFF_RING_SIZE(tp),
GFP_KERNEL);
if (!tpr->rx_jmb_buffers)
goto err_out;
tpr->rx_jmb = pci_alloc_consistent(tp->pdev,
- TG3_RX_JUMBO_RING_BYTES,
+ TG3_RX_JMB_RING_BYTES(tp),
&tpr->rx_jmb_mapping);
if (!tpr->rx_jmb)
goto err_out;
@@ -6253,7 +6398,7 @@ static void tg3_free_rings(struct tg3 *tp)
for (j = 0; j < tp->irq_cnt; j++) {
struct tg3_napi *tnapi = &tp->napi[j];
- tg3_rx_prodring_free(tp, &tp->prodring[j]);
+ tg3_rx_prodring_free(tp, &tnapi->prodring);
if (!tnapi->tx_buffers)
continue;
@@ -6325,7 +6470,7 @@ static int tg3_init_rings(struct tg3 *tp)
if (tnapi->rx_rcb)
memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp));
- if (tg3_rx_prodring_alloc(tp, &tp->prodring[i])) {
+ if (tg3_rx_prodring_alloc(tp, &tnapi->prodring)) {
tg3_free_rings(tp);
return -ENOMEM;
}
@@ -6361,6 +6506,8 @@ static void tg3_free_consistent(struct tg3 *tp)
tnapi->rx_rcb = NULL;
}
+ tg3_rx_prodring_fini(tp, &tnapi->prodring);
+
if (tnapi->hw_status) {
pci_free_consistent(tp->pdev, TG3_HW_STATUS_SIZE,
tnapi->hw_status,
@@ -6374,9 +6521,6 @@ static void tg3_free_consistent(struct tg3 *tp)
tp->hw_stats, tp->stats_mapping);
tp->hw_stats = NULL;
}
-
- for (i = 0; i < tp->irq_cnt; i++)
- tg3_rx_prodring_fini(tp, &tp->prodring[i]);
}
/*
@@ -6387,11 +6531,6 @@ static int tg3_alloc_consistent(struct tg3 *tp)
{
int i;
- for (i = 0; i < tp->irq_cnt; i++) {
- if (tg3_rx_prodring_init(tp, &tp->prodring[i]))
- goto err_out;
- }
-
tp->hw_stats = pci_alloc_consistent(tp->pdev,
sizeof(struct tg3_hw_stats),
&tp->stats_mapping);
@@ -6413,6 +6552,9 @@ static int tg3_alloc_consistent(struct tg3 *tp)
memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE);
sblk = tnapi->hw_status;
+ if (tg3_rx_prodring_init(tp, &tnapi->prodring))
+ goto err_out;
+
/* If multivector TSS is enabled, vector 0 does not handle
* tx interrupts. Don't allocate any resources for it.
*/
@@ -6452,8 +6594,6 @@ static int tg3_alloc_consistent(struct tg3 *tp)
break;
}
- tnapi->prodring = &tp->prodring[i];
-
/*
* If multivector RSS is enabled, vector 0 does not handle
* rx or tx interrupts. Don't allocate any resources for it.
@@ -6596,6 +6736,10 @@ static void tg3_ape_send_event(struct tg3 *tp, u32 event)
int i;
u32 apedata;
+ /* NCSI does not support APE events */
+ if (tp->tg3_flags3 & TG3_FLG3_APE_HAS_NCSI)
+ return;
+
apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG);
if (apedata != APE_SEG_SIG_MAGIC)
return;
@@ -6647,6 +6791,8 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
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;
@@ -6658,6 +6804,16 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
*/
tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0);
+ if (device_may_wakeup(&tp->pdev->dev) &&
+ (tp->tg3_flags & TG3_FLAG_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:
@@ -7515,6 +7671,9 @@ static void tg3_rings_reset(struct tg3 *tp)
/* Disable all transmit rings but the first. */
if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 16;
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+ limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 4;
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 2;
else
@@ -7548,7 +7707,7 @@ static void tg3_rings_reset(struct tg3 *tp)
/* Zero mailbox registers. */
if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) {
- for (i = 1; i < TG3_IRQ_MAX_VECS; i++) {
+ for (i = 1; i < tp->irq_max; i++) {
tp->napi[i].tx_prod = 0;
tp->napi[i].tx_cons = 0;
if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)
@@ -7594,8 +7753,8 @@ static void tg3_rings_reset(struct tg3 *tp)
if (tnapi->rx_rcb) {
tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping,
- (TG3_RX_RCB_RING_SIZE(tp) <<
- BDINFO_FLAGS_MAXLEN_SHIFT), 0);
+ (tp->rx_ret_ring_mask + 1) <<
+ BDINFO_FLAGS_MAXLEN_SHIFT, 0);
rxrcb += TG3_BDINFO_SIZE;
}
@@ -7618,7 +7777,7 @@ static void tg3_rings_reset(struct tg3 *tp)
}
tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping,
- (TG3_RX_RCB_RING_SIZE(tp) <<
+ ((tp->rx_ret_ring_mask + 1) <<
BDINFO_FLAGS_MAXLEN_SHIFT), 0);
stblk += 8;
@@ -7631,7 +7790,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
{
u32 val, rdmac_mode;
int i, err, limit;
- struct tg3_rx_prodring_set *tpr = &tp->prodring[0];
+ struct tg3_rx_prodring_set *tpr = &tp->napi[0].prodring;
tg3_disable_ints(tp);
@@ -7720,6 +7879,22 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(TG3_CPMU_LSPD_10MB_CLK, val);
}
+ /* Enable MAC control of LPI */
+ if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
+ tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL,
+ TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
+ TG3_CPMU_EEE_LNKIDL_UART_IDL);
+
+ tw32_f(TG3_CPMU_EEE_CTRL,
+ TG3_CPMU_EEE_CTRL_EXIT_20_1_US);
+
+ tw32_f(TG3_CPMU_EEE_MODE,
+ TG3_CPMU_EEEMD_ERLY_L1_XIT_DET |
+ TG3_CPMU_EEEMD_LPI_IN_TX |
+ TG3_CPMU_EEEMD_LPI_IN_RX |
+ TG3_CPMU_EEEMD_EEE_ENABLE);
+ }
+
/* This works around an issue with Athlon chipsets on
* B3 tigon3 silicon. This bit has no effect on any
* other revision. But do not set this on PCI Express
@@ -7845,7 +8020,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(BUFMGR_DMA_HIGH_WATER,
tp->bufmgr_config.dma_high_water);
- tw32(BUFMGR_MODE, BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE);
+ val = BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+ val |= BUFMGR_MODE_NO_TX_UNDERRUN;
+ tw32(BUFMGR_MODE, val);
for (i = 0; i < 2000; i++) {
if (tr32(BUFMGR_MODE) & BUFMGR_MODE_ENABLE)
break;
@@ -7928,10 +8106,14 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
BDINFO_FLAGS_DISABLED);
}
- if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)
- val = (RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT) |
- (TG3_RX_STD_DMA_SZ << 2);
- else
+ if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+ val = RX_STD_MAX_SIZE_5705;
+ else
+ val = RX_STD_MAX_SIZE_5717;
+ val <<= BDINFO_FLAGS_MAXLEN_SHIFT;
+ val |= (TG3_RX_STD_DMA_SZ << 2);
+ } else
val = TG3_RX_STD_DMA_SZ << BDINFO_FLAGS_MAXLEN_SHIFT;
} else
val = RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT;
@@ -8015,6 +8197,23 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
rdmac_mode |= RDMAC_MODE_IPV6_LSO_EN;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
+ (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) {
+ val = tr32(TG3_RDMA_RSRVCTRL_REG);
+ tw32(TG3_RDMA_RSRVCTRL_REG,
+ val | TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX);
+ }
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+ val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL);
+ tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val |
+ TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K |
+ TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_LSO_4K);
+ }
+
/* Receive/send statistics. */
if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
val = tr32(RCVLPC_STATS_ENABLE);
@@ -8197,7 +8396,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE);
tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB);
- tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ);
+ val = RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+ val |= RCVDBDI_MODE_LRG_RING_SZ;
+ tw32(RCVDBDI_MODE, val);
tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8);
@@ -8500,6 +8703,12 @@ static void tg3_timer(unsigned long __opaque)
if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
tg3_periodic_fetch_stats(tp);
+ if (tp->setlpicnt && !--tp->setlpicnt) {
+ u32 val = tr32(TG3_CPMU_EEE_MODE);
+ tw32(TG3_CPMU_EEE_MODE,
+ val | TG3_CPMU_EEEMD_LPI_ENABLE);
+ }
+
if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) {
u32 mac_stat;
int phy_event;
@@ -8816,16 +9025,14 @@ static bool tg3_enable_msix(struct tg3 *tp)
for (i = 0; i < tp->irq_max; i++)
tp->napi[i].irq_vec = msix_ent[i].vector;
- tp->dev->real_num_tx_queues = 1;
- if (tp->irq_cnt > 1) {
- tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS;
-
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
- tp->tg3_flags3 |= TG3_FLG3_ENABLE_TSS;
- tp->dev->real_num_tx_queues = tp->irq_cnt - 1;
- }
+ netif_set_real_num_tx_queues(tp->dev, 1);
+ rc = tp->irq_cnt > 1 ? tp->irq_cnt - 1 : 1;
+ if (netif_set_real_num_rx_queues(tp->dev, rc)) {
+ pci_disable_msix(tp->pdev);
+ return false;
}
+ if (tp->irq_cnt > 1)
+ tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS;
return true;
}
@@ -8858,7 +9065,8 @@ defcfg:
if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) {
tp->irq_cnt = 1;
tp->napi[0].irq_vec = tp->pdev->irq;
- tp->dev->real_num_tx_queues = 1;
+ netif_set_real_num_tx_queues(tp->dev, 1);
+ netif_set_real_num_rx_queues(tp->dev, 1);
}
}
@@ -8917,6 +9125,8 @@ static int tg3_open(struct net_device *dev)
if (err)
goto err_out1;
+ tg3_napi_init(tp);
+
tg3_napi_enable(tp);
for (i = 0; i < tp->irq_cnt; i++) {
@@ -9004,6 +9214,7 @@ err_out3:
err_out2:
tg3_napi_disable(tp);
+ tg3_napi_fini(tp);
tg3_free_consistent(tp);
err_out1:
@@ -9051,6 +9262,8 @@ static int tg3_close(struct net_device *dev)
memcpy(&tp->estats_prev, tg3_get_estats(tp),
sizeof(tp->estats_prev));
+ tg3_napi_fini(tp);
+
tg3_free_consistent(tp);
tg3_set_power_state(tp, PCI_D3hot);
@@ -9596,6 +9809,9 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (netif_running(dev)) {
cmd->speed = tp->link_config.active_speed;
cmd->duplex = tp->link_config.active_duplex;
+ } else {
+ cmd->speed = SPEED_INVALID;
+ cmd->duplex = DUPLEX_INVALID;
}
cmd->phy_address = tp->phy_addr;
cmd->transceiver = XCVR_INTERNAL;
@@ -9732,16 +9948,16 @@ static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
!((tp->tg3_flags & TG3_FLAG_WOL_CAP) && device_can_wakeup(dp)))
return -EINVAL;
+ device_set_wakeup_enable(dp, wol->wolopts & WAKE_MAGIC);
+
spin_lock_bh(&tp->lock);
- if (wol->wolopts & WAKE_MAGIC) {
+ if (device_may_wakeup(dp))
tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
- device_set_wakeup_enable(dp, true);
- } else {
+ else
tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
- device_set_wakeup_enable(dp, false);
- }
spin_unlock_bh(&tp->lock);
+
return 0;
}
@@ -9822,10 +10038,10 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *
{
struct tg3 *tp = netdev_priv(dev);
- ering->rx_max_pending = TG3_RX_RING_SIZE - 1;
+ ering->rx_max_pending = tp->rx_std_ring_mask;
ering->rx_mini_max_pending = 0;
if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE)
- ering->rx_jumbo_max_pending = TG3_RX_JUMBO_RING_SIZE - 1;
+ ering->rx_jumbo_max_pending = tp->rx_jmb_ring_mask;
else
ering->rx_jumbo_max_pending = 0;
@@ -9846,8 +10062,8 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
struct tg3 *tp = netdev_priv(dev);
int i, irq_sync = 0, err = 0;
- if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) ||
- (ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
+ if ((ering->rx_pending > tp->rx_std_ring_mask) ||
+ (ering->rx_jumbo_pending > tp->rx_jmb_ring_mask) ||
(ering->tx_pending > TG3_TX_RING_SIZE - 1) ||
(ering->tx_pending <= MAX_SKB_FRAGS) ||
((tp->tg3_flags2 & TG3_FLG2_TSO_BUG) &&
@@ -9869,7 +10085,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
tp->rx_pending = 63;
tp->rx_jumbo_pending = ering->rx_jumbo_pending;
- for (i = 0; i < TG3_IRQ_MAX_VECS; i++)
+ for (i = 0; i < tp->irq_max; i++)
tp->napi[i].tx_pending = ering->tx_pending;
if (netif_running(dev)) {
@@ -9917,8 +10133,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
if (!(phydev->supported & SUPPORTED_Pause) ||
(!(phydev->supported & SUPPORTED_Asym_Pause) &&
- ((epause->rx_pause && !epause->tx_pause) ||
- (!epause->rx_pause && epause->tx_pause))))
+ (epause->rx_pause != epause->tx_pause)))
return -EINVAL;
tp->link_config.flowctrl = 0;
@@ -10610,12 +10825,13 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
int num_pkts, tx_len, rx_len, i, err;
struct tg3_rx_buffer_desc *desc;
struct tg3_napi *tnapi, *rnapi;
- struct tg3_rx_prodring_set *tpr = &tp->prodring[0];
+ struct tg3_rx_prodring_set *tpr = &tp->napi[0].prodring;
tnapi = &tp->napi[0];
rnapi = &tp->napi[0];
if (tp->irq_cnt > 1) {
- rnapi = &tp->napi[1];
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)
+ rnapi = &tp->napi[1];
if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)
tnapi = &tp->napi[1];
}
@@ -12332,6 +12548,11 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
}
}
+ if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
+ tp->pci_chip_rev_id != CHIPREV_ID_57765_A0))
+ tp->phy_flags |= TG3_PHYFLG_EEE_CAP;
+
if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) &&
!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
@@ -12403,14 +12624,18 @@ skip_phy_reset:
static void __devinit tg3_read_vpd(struct tg3 *tp)
{
- u8 vpd_data[TG3_NVM_VPD_LEN];
+ u8 *vpd_data;
unsigned int block_end, rosize, len;
int j, i = 0;
u32 magic;
if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) ||
tg3_nvram_read(tp, 0x0, &magic))
- goto out_not_found;
+ goto out_no_vpd;
+
+ vpd_data = kmalloc(TG3_NVM_VPD_LEN, GFP_KERNEL);
+ if (!vpd_data)
+ goto out_no_vpd;
if (magic == TG3_EEPROM_MAGIC) {
for (i = 0; i < TG3_NVM_VPD_LEN; i += 4) {
@@ -12494,43 +12719,51 @@ partno:
memcpy(tp->board_part_number, &vpd_data[i], len);
- return;
-
out_not_found:
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ kfree(vpd_data);
+ if (tp->board_part_number[0])
+ return;
+
+out_no_vpd:
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
+ if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717)
+ strcpy(tp->board_part_number, "BCM5717");
+ else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718)
+ strcpy(tp->board_part_number, "BCM5718");
+ else
+ goto nomatch;
+ } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
+ if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57780)
+ strcpy(tp->board_part_number, "BCM57780");
+ else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57760)
+ strcpy(tp->board_part_number, "BCM57760");
+ else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790)
+ strcpy(tp->board_part_number, "BCM57790");
+ else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57788)
+ strcpy(tp->board_part_number, "BCM57788");
+ else
+ goto nomatch;
+ } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+ if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57761)
+ strcpy(tp->board_part_number, "BCM57761");
+ else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57765)
+ strcpy(tp->board_part_number, "BCM57765");
+ else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57781)
+ strcpy(tp->board_part_number, "BCM57781");
+ else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57785)
+ strcpy(tp->board_part_number, "BCM57785");
+ else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57791)
+ strcpy(tp->board_part_number, "BCM57791");
+ else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57795)
+ strcpy(tp->board_part_number, "BCM57795");
+ else
+ goto nomatch;
+ } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
strcpy(tp->board_part_number, "BCM95906");
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 &&
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57780)
- strcpy(tp->board_part_number, "BCM57780");
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 &&
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57760)
- strcpy(tp->board_part_number, "BCM57760");
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 &&
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790)
- strcpy(tp->board_part_number, "BCM57790");
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 &&
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57788)
- strcpy(tp->board_part_number, "BCM57788");
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57761)
- strcpy(tp->board_part_number, "BCM57761");
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57765)
- strcpy(tp->board_part_number, "BCM57765");
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57781)
- strcpy(tp->board_part_number, "BCM57781");
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57785)
- strcpy(tp->board_part_number, "BCM57785");
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57791)
- strcpy(tp->board_part_number, "BCM57791");
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_57795)
- strcpy(tp->board_part_number, "BCM57795");
- else
+ } else {
+nomatch:
strcpy(tp->board_part_number, "none");
+ }
}
static int __devinit tg3_fw_img_is_valid(struct tg3 *tp, u32 offset)
@@ -12639,6 +12872,9 @@ static void __devinit tg3_read_sb_ver(struct tg3 *tp, u32 val)
case TG3_EEPROM_SB_REVISION_5:
offset = TG3_EEPROM_SB_F1R5_EDH_OFF;
break;
+ case TG3_EEPROM_SB_REVISION_6:
+ offset = TG3_EEPROM_SB_F1R6_EDH_OFF;
+ break;
default:
return;
}
@@ -12738,10 +12974,12 @@ static void __devinit tg3_read_dash_ver(struct tg3 *tp)
apedata = tg3_ape_read32(tp, TG3_APE_FW_VERSION);
- if (tg3_ape_read32(tp, TG3_APE_FW_FEATURES) & TG3_APE_FW_FEATURE_NCSI)
+ if (tg3_ape_read32(tp, TG3_APE_FW_FEATURES) & TG3_APE_FW_FEATURE_NCSI) {
+ tp->tg3_flags3 |= TG3_FLG3_APE_HAS_NCSI;
fwtype = "NCSI";
- else
+ } else {
fwtype = "DASH";
+ }
vlen = strlen(tp->fw_ver);
@@ -12797,6 +13035,18 @@ static void inline vlan_features_add(struct net_device *dev, unsigned long flags
#endif
}
+static inline u32 tg3_rx_ret_ring_size(struct tg3 *tp)
+{
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+ return 4096;
+ else if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) &&
+ !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
+ return 1024;
+ else
+ return 512;
+}
+
static int __devinit tg3_get_invariants(struct tg3 *tp)
{
static struct pci_device_id write_reorder_chipsets[] = {
@@ -12841,7 +13091,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_5724 ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719)
pci_read_config_dword(tp->pdev,
TG3PCI_GEN2_PRODID_ASICREV,
@@ -13412,10 +13661,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (err)
return err;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
- tp->pci_chip_rev_id != CHIPREV_ID_5717_A0)
- return -ENOTSUPP;
-
/* Initialize data/descriptor byte/word swapping. */
val = tr32(GRC_MODE);
val &= GRC_MODE_HOST_STACKUP;
@@ -13555,7 +13800,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
#endif
}
- tp->rx_std_max_post = TG3_RX_RING_SIZE;
+ tp->rx_std_ring_mask = TG3_RX_STD_RING_SIZE(tp) - 1;
+ tp->rx_jmb_ring_mask = TG3_RX_JMB_RING_SIZE(tp) - 1;
+ tp->rx_ret_ring_mask = tg3_rx_ret_ring_size(tp) - 1;
+
+ tp->rx_std_max_post = tp->rx_std_ring_mask + 1;
/* Increment the rx prod index on the rx std ring by at most
* 8 for these chips to workaround hw errata.
@@ -14444,7 +14693,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
}
if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) &&
- tp->pci_chip_rev_id != CHIPREV_ID_5717_A0 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719)
dev->netdev_ops = &tg3_netdev_ops;
else
@@ -14583,7 +14832,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
intmbx = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW;
rcvmbx = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW;
sndmbx = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW;
- for (i = 0; i < TG3_IRQ_MAX_VECS; i++) {
+ for (i = 0; i < tp->irq_max; i++) {
struct tg3_napi *tnapi = &tp->napi[i];
tnapi->tp = tp;
@@ -14598,13 +14847,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tnapi->consmbox = rcvmbx;
tnapi->prodmbox = sndmbx;
- if (i) {
+ if (i)
tnapi->coal_now = HOSTCC_MODE_COAL_VEC1_NOW << (i - 1);
- netif_napi_add(dev, &tnapi->napi, tg3_poll_msix, 64);
- } else {
+ else
tnapi->coal_now = HOSTCC_MODE_NOW;
- netif_napi_add(dev, &tnapi->napi, tg3_poll, 64);
- }
if (!(tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX))
break;
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index be7ff138a7f9..4a1974804b9f 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -26,6 +26,7 @@
#define TG3_RX_INTERNAL_RING_SZ_5906 32
#define RX_STD_MAX_SIZE_5705 512
+#define RX_STD_MAX_SIZE_5717 2048
#define RX_JUMBO_MAX_SIZE 0xdeadbeef /* XXX */
/* First 256 bytes are a mirror of PCI config space. */
@@ -46,7 +47,6 @@
#define TG3PCI_DEVICE_TIGON3_5785_F 0x16a0 /* 10/100 only */
#define TG3PCI_DEVICE_TIGON3_5717 0x1655
#define TG3PCI_DEVICE_TIGON3_5718 0x1656
-#define TG3PCI_DEVICE_TIGON3_5724 0x165c
#define TG3PCI_DEVICE_TIGON3_57781 0x16b1
#define TG3PCI_DEVICE_TIGON3_57785 0x16b5
#define TG3PCI_DEVICE_TIGON3_57761 0x16b0
@@ -973,6 +973,7 @@
#define RCVDBDI_MODE_JUMBOBD_NEEDED 0x00000004
#define RCVDBDI_MODE_FRM_TOO_BIG 0x00000008
#define RCVDBDI_MODE_INV_RING_SZ 0x00000010
+#define RCVDBDI_MODE_LRG_RING_SZ 0x00010000
#define RCVDBDI_STATUS 0x00002404
#define RCVDBDI_STATUS_JUMBOBD_NEEDED 0x00000004
#define RCVDBDI_STATUS_FRM_TOO_BIG 0x00000008
@@ -1090,7 +1091,26 @@
#define CPMU_MUTEX_GNT_DRIVER 0x00001000
#define TG3_CPMU_PHY_STRAP 0x00003664
#define TG3_CPMU_PHY_STRAP_IS_SERDES 0x00000020
-/* 0x3664 --> 0x3800 unused */
+/* 0x3664 --> 0x36b0 unused */
+
+#define TG3_CPMU_EEE_MODE 0x000036b0
+#define TG3_CPMU_EEEMD_ERLY_L1_XIT_DET 0x00000008
+#define TG3_CPMU_EEEMD_LPI_ENABLE 0x00000080
+#define TG3_CPMU_EEEMD_LPI_IN_TX 0x00000100
+#define TG3_CPMU_EEEMD_LPI_IN_RX 0x00000200
+#define TG3_CPMU_EEEMD_EEE_ENABLE 0x00100000
+/* 0x36b4 --> 0x36b8 unused */
+
+#define TG3_CPMU_EEE_LNKIDL_CTRL 0x000036bc
+#define TG3_CPMU_EEE_LNKIDL_PCIE_NL0 0x01000000
+#define TG3_CPMU_EEE_LNKIDL_UART_IDL 0x00000004
+/* 0x36c0 --> 0x36d0 unused */
+
+#define TG3_CPMU_EEE_CTRL 0x000036d0
+#define TG3_CPMU_EEE_CTRL_EXIT_16_5_US 0x0000019d
+#define TG3_CPMU_EEE_CTRL_EXIT_36_US 0x00000384
+#define TG3_CPMU_EEE_CTRL_EXIT_20_1_US 0x000001f8
+/* 0x36d4 --> 0x3800 unused */
/* Mbuf cluster free registers */
#define MBFREE_MODE 0x00003800
@@ -1225,6 +1245,7 @@
#define BUFMGR_MODE_ATTN_ENABLE 0x00000004
#define BUFMGR_MODE_BM_TEST 0x00000008
#define BUFMGR_MODE_MBLOW_ATTN_ENAB 0x00000010
+#define BUFMGR_MODE_NO_TX_UNDERRUN 0x80000000
#define BUFMGR_STATUS 0x00004404
#define BUFMGR_STATUS_ERROR 0x00000004
#define BUFMGR_STATUS_MBLOW 0x00000010
@@ -1302,7 +1323,16 @@
#define RDMAC_STATUS_FIFOURUN 0x00000080
#define RDMAC_STATUS_FIFOOREAD 0x00000100
#define RDMAC_STATUS_LNGREAD 0x00000200
-/* 0x4808 --> 0x4c00 unused */
+/* 0x4808 --> 0x4900 unused */
+
+#define TG3_RDMA_RSRVCTRL_REG 0x00004900
+#define TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX 0x00000004
+/* 0x4904 --> 0x4910 unused */
+
+#define TG3_LSO_RD_DMA_CRPTEN_CTRL 0x00004910
+#define TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K 0x00030000
+#define TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_LSO_4K 0x000c0000
+/* 0x4914 --> 0x4c00 unused */
/* Write DMA control registers */
#define WDMAC_MODE 0x00004c00
@@ -1904,6 +1934,7 @@
#define TG3_EEPROM_SB_REVISION_3 0x00030000
#define TG3_EEPROM_SB_REVISION_4 0x00040000
#define TG3_EEPROM_SB_REVISION_5 0x00050000
+#define TG3_EEPROM_SB_REVISION_6 0x00060000
#define TG3_EEPROM_MAGIC_HW 0xabcd
#define TG3_EEPROM_MAGIC_HW_MSK 0xffff
@@ -1923,6 +1954,7 @@
#define TG3_EEPROM_SB_F1R3_EDH_OFF 0x18
#define TG3_EEPROM_SB_F1R4_EDH_OFF 0x1c
#define TG3_EEPROM_SB_F1R5_EDH_OFF 0x20
+#define TG3_EEPROM_SB_F1R6_EDH_OFF 0x4c
#define TG3_EEPROM_SB_EDH_MAJ_MASK 0x00000700
#define TG3_EEPROM_SB_EDH_MAJ_SHFT 8
#define TG3_EEPROM_SB_EDH_MIN_MASK 0x000000ff
@@ -2048,6 +2080,10 @@
#define MII_TG3_CTRL_AS_MASTER 0x0800
#define MII_TG3_CTRL_ENABLE_AS_MASTER 0x1000
+#define MII_TG3_MMD_CTRL 0x0d /* MMD Access Control register */
+#define MII_TG3_MMD_CTRL_DATA_NOINC 0x4000
+#define MII_TG3_MMD_ADDRESS 0x0e /* MMD Address Data register */
+
#define MII_TG3_EXT_CTRL 0x10 /* Extended control register */
#define MII_TG3_EXT_CTRL_FIFO_ELASTIC 0x0001
#define MII_TG3_EXT_CTRL_LNK3_LED_MODE 0x0002
@@ -2065,6 +2101,8 @@
#define MII_TG3_DSP_TAP1 0x0001
#define MII_TG3_DSP_TAP1_AGCTGT_DFLT 0x0007
#define MII_TG3_DSP_AADJ1CH0 0x001f
+#define MII_TG3_DSP_CH34TP2 0x4022
+#define MII_TG3_DSP_CH34TP2_HIBW01 0x0010
#define MII_TG3_DSP_AADJ1CH3 0x601f
#define MII_TG3_DSP_AADJ1CH3_ADCCKADJ 0x0002
#define MII_TG3_DSP_EXP1_INT_STAT 0x0f01
@@ -2131,6 +2169,14 @@
#define MII_TG3_TEST1_TRIM_EN 0x0010
#define MII_TG3_TEST1_CRC_EN 0x8000
+/* Clause 45 expansion registers */
+#define TG3_CL45_D7_EEEADV_CAP 0x003c
+#define TG3_CL45_D7_EEEADV_CAP_100TX 0x0002
+#define TG3_CL45_D7_EEEADV_CAP_1000T 0x0004
+#define TG3_CL45_D7_EEERES_STAT 0x803e
+#define TG3_CL45_D7_EEERES_STAT_LP_100TX 0x0002
+#define TG3_CL45_D7_EEERES_STAT_LP_1000T 0x0004
+
/* Fast Ethernet Tranceiver definitions */
#define MII_TG3_FET_PTEST 0x17
@@ -2176,7 +2222,7 @@
#define TG3_APE_HOST_SEG_SIG 0x4200
#define APE_HOST_SEG_SIG_MAGIC 0x484f5354
#define TG3_APE_HOST_SEG_LEN 0x4204
-#define APE_HOST_SEG_LEN_MAGIC 0x0000001c
+#define APE_HOST_SEG_LEN_MAGIC 0x00000020
#define TG3_APE_HOST_INIT_COUNT 0x4208
#define TG3_APE_HOST_DRIVER_ID 0x420c
#define APE_HOST_DRIVER_ID_LINUX 0xf0000000
@@ -2188,6 +2234,12 @@
#define APE_HOST_HEARTBEAT_INT_DISABLE 0
#define APE_HOST_HEARTBEAT_INT_5SEC 5000
#define TG3_APE_HOST_HEARTBEAT_COUNT 0x4218
+#define TG3_APE_HOST_DRVR_STATE 0x421c
+#define TG3_APE_HOST_DRVR_STATE_START 0x00000001
+#define TG3_APE_HOST_DRVR_STATE_UNLOAD 0x00000002
+#define TG3_APE_HOST_DRVR_STATE_WOL 0x00000003
+#define TG3_APE_HOST_WOL_SPEED 0x4224
+#define TG3_APE_HOST_WOL_SPEED_AUTO 0x00008000
#define TG3_APE_EVENT_STATUS 0x4300
@@ -2649,7 +2701,8 @@ struct tg3_rx_prodring_set {
dma_addr_t rx_jmb_mapping;
};
-#define TG3_IRQ_MAX_VECS 5
+#define TG3_IRQ_MAX_VECS_RSS 5
+#define TG3_IRQ_MAX_VECS TG3_IRQ_MAX_VECS_RSS
struct tg3_napi {
struct napi_struct napi ____cacheline_aligned;
@@ -2668,7 +2721,7 @@ struct tg3_napi {
u32 consmbox;
u32 rx_rcb_ptr;
u16 *rx_rcb_prod_idx;
- struct tg3_rx_prodring_set *prodring;
+ struct tg3_rx_prodring_set prodring;
struct tg3_rx_buffer_desc *rx_rcb;
struct tg3_tx_buffer_desc *tx_ring;
@@ -2746,6 +2799,9 @@ struct tg3 {
void (*write32_rx_mbox) (struct tg3 *, u32,
u32);
u32 rx_copy_thresh;
+ u32 rx_std_ring_mask;
+ u32 rx_jmb_ring_mask;
+ u32 rx_ret_ring_mask;
u32 rx_pending;
u32 rx_jumbo_pending;
u32 rx_std_max_post;
@@ -2755,8 +2811,6 @@ struct tg3 {
struct vlan_group *vlgrp;
#endif
- struct tg3_rx_prodring_set prodring[TG3_IRQ_MAX_VECS];
-
/* begin "everything else" cacheline(s) section */
unsigned long rx_dropped;
@@ -2850,6 +2904,7 @@ struct tg3 {
#define TG3_FLG3_USE_JUMBO_BDFLAG 0x00400000
#define TG3_FLG3_L1PLLPD_EN 0x00800000
#define TG3_FLG3_5717_PLUS 0x01000000
+#define TG3_FLG3_APE_HAS_NCSI 0x02000000
struct timer_list timer;
u16 timer_counter;
@@ -2966,9 +3021,11 @@ struct tg3 {
#define TG3_PHYFLG_BER_BUG 0x00008000
#define TG3_PHYFLG_SERDES_PREEMPHASIS 0x00010000
#define TG3_PHYFLG_PARALLEL_DETECT 0x00020000
+#define TG3_PHYFLG_EEE_CAP 0x00040000
u32 led_ctrl;
u32 phy_otp;
+ u32 setlpicnt;
#define TG3_BPN_SIZE 24
char board_part_number[TG3_BPN_SIZE];
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index ccee3eddc5f4..f8e463cd8ecc 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -78,7 +78,7 @@
* - Updated tlan.txt accordingly.
* - Adjusted minimum/maximum frame length.
* - There is now a TLAN website up at
- * http://tlan.kernel.dk
+ * http://hp.sourceforge.net/
*
* v1.7 April 07, 2000 - Started to implement custom ioctls. Driver now
* reports PHY information when used with Donald
@@ -393,7 +393,7 @@ TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type )
spin_unlock_irqrestore(&priv->lock, flags);
return;
}
- priv->timer.function = &TLan_Timer;
+ priv->timer.function = TLan_Timer;
if (!in_irq())
spin_unlock_irqrestore(&priv->lock, flags);
@@ -1453,7 +1453,7 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int )
TLan_DioWrite8( dev->base_addr,
TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
if ( priv->timer.function == NULL ) {
- priv->timer.function = &TLan_Timer;
+ priv->timer.function = TLan_Timer;
priv->timer.data = (unsigned long) dev;
priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
priv->timerSetAt = jiffies;
@@ -1601,7 +1601,7 @@ drop_and_reuse:
TLan_DioWrite8( dev->base_addr,
TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
if ( priv->timer.function == NULL ) {
- priv->timer.function = &TLan_Timer;
+ priv->timer.function = TLan_Timer;
priv->timer.data = (unsigned long) dev;
priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
priv->timerSetAt = jiffies;
@@ -1897,7 +1897,7 @@ static void TLan_Timer( unsigned long data )
TLan_DioWrite8( dev->base_addr,
TLAN_LED_REG, TLAN_LED_LINK );
} else {
- priv->timer.function = &TLan_Timer;
+ priv->timer.function = TLan_Timer;
priv->timer.expires = priv->timerSetAt
+ TLAN_TIMER_ACT_DELAY;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -3187,7 +3187,7 @@ static int TLan_EeSendByte( u16 io_base, u8 data, int stop )
TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
}
- return ( err );
+ return err;
} /* TLan_EeSendByte */
diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h
index d13ff12d7500..3315ced774e2 100644
--- a/drivers/net/tlan.h
+++ b/drivers/net/tlan.h
@@ -442,7 +442,7 @@ typedef struct tlan_private_tag {
static inline u8 TLan_DioRead8(u16 base_addr, u16 internal_addr)
{
outw(internal_addr, base_addr + TLAN_DIO_ADR);
- return (inb((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x3)));
+ return inb((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x3));
} /* TLan_DioRead8 */
@@ -452,7 +452,7 @@ static inline u8 TLan_DioRead8(u16 base_addr, u16 internal_addr)
static inline u16 TLan_DioRead16(u16 base_addr, u16 internal_addr)
{
outw(internal_addr, base_addr + TLAN_DIO_ADR);
- return (inw((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x2)));
+ return inw((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x2));
} /* TLan_DioRead16 */
@@ -462,7 +462,7 @@ static inline u16 TLan_DioRead16(u16 base_addr, u16 internal_addr)
static inline u32 TLan_DioRead32(u16 base_addr, u16 internal_addr)
{
outw(internal_addr, base_addr + TLAN_DIO_ADR);
- return (inl(base_addr + TLAN_DIO_DATA));
+ return inl(base_addr + TLAN_DIO_DATA);
} /* TLan_DioRead32 */
@@ -537,6 +537,6 @@ static inline u32 TLan_HashFunc( const u8 *a )
hash ^= ((a[2]^a[5])<<4); /* & 060 */
hash ^= ((a[2]^a[5])>>2); /* & 077 */
- return (hash & 077);
+ return hash & 077;
}
#endif
diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c
index 16e8783ee9cd..8d362e64a40e 100644
--- a/drivers/net/tokenring/proteon.c
+++ b/drivers/net/tokenring/proteon.c
@@ -110,7 +110,7 @@ static int __init proteon_probe1(struct net_device *dev, int ioaddr)
}
dev->base_addr = ioaddr;
- return (0);
+ return 0;
nodev:
release_region(ioaddr, PROTEON_IO_EXTENT);
return -ENODEV;
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index 0929fff5982c..63db5a6762ae 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -435,7 +435,7 @@ static int smctr_alloc_shared_memory(struct net_device *dev)
RX_DATA_BUFFER_SIZE * tp->num_rx_bdbs[NON_MAC_QUEUE]);
tp->rx_buff_end[NON_MAC_QUEUE] = (__u16 *)smctr_malloc(dev, 0);
- return (0);
+ return 0;
}
/* Enter Bypass state. */
@@ -448,7 +448,7 @@ static int smctr_bypass_state(struct net_device *dev)
err = smctr_setup_single_cmd(dev, ACB_CMD_CHANGE_JOIN_STATE, JS_BYPASS_STATE);
- return (err);
+ return err;
}
static int smctr_checksum_firmware(struct net_device *dev)
@@ -471,9 +471,9 @@ static int smctr_checksum_firmware(struct net_device *dev)
smctr_disable_adapter_ctrl_store(dev);
if(checksum)
- return (checksum);
+ return checksum;
- return (0);
+ return 0;
}
static int __init smctr_chk_mca(struct net_device *dev)
@@ -485,7 +485,7 @@ static int __init smctr_chk_mca(struct net_device *dev)
current_slot = mca_find_unused_adapter(smctr_posid, 0);
if(current_slot == MCA_NOTFOUND)
- return (-ENODEV);
+ return -ENODEV;
mca_set_adapter_name(current_slot, smctr_name);
mca_mark_as_used(current_slot);
@@ -622,9 +622,9 @@ static int __init smctr_chk_mca(struct net_device *dev)
break;
}
- return (0);
+ return 0;
#else
- return (-1);
+ return -1;
#endif /* CONFIG_MCA_LEGACY */
}
@@ -677,18 +677,18 @@ static int smctr_chg_rx_mask(struct net_device *dev)
if((err = smctr_issue_write_word_cmd(dev, RW_CONFIG_REGISTER_0,
&tp->config_word0)))
{
- return (err);
+ return err;
}
if((err = smctr_issue_write_word_cmd(dev, RW_CONFIG_REGISTER_1,
&tp->config_word1)))
{
- return (err);
+ return err;
}
smctr_disable_16bit(dev);
- return (0);
+ return 0;
}
static int smctr_clear_int(struct net_device *dev)
@@ -697,7 +697,7 @@ static int smctr_clear_int(struct net_device *dev)
outb((tp->trc_mask | CSR_CLRTINT), dev->base_addr + CSR);
- return (0);
+ return 0;
}
static int smctr_clear_trc_reset(int ioaddr)
@@ -707,7 +707,7 @@ static int smctr_clear_trc_reset(int ioaddr)
r = inb(ioaddr + MSR);
outb(~MSR_RST & r, ioaddr + MSR);
- return (0);
+ return 0;
}
/*
@@ -725,7 +725,7 @@ static int smctr_close(struct net_device *dev)
/* Check to see if adapter is already in a closed state. */
if(tp->status != OPEN)
- return (0);
+ return 0;
smctr_enable_16bit(dev);
smctr_set_page(dev, (__u8 *)tp->ram_access);
@@ -733,7 +733,7 @@ static int smctr_close(struct net_device *dev)
if((err = smctr_issue_remove_cmd(dev)))
{
smctr_disable_16bit(dev);
- return (err);
+ return err;
}
for(;;)
@@ -746,7 +746,7 @@ static int smctr_close(struct net_device *dev)
}
- return (0);
+ return 0;
}
static int smctr_decode_firmware(struct net_device *dev,
@@ -807,12 +807,12 @@ static int smctr_decode_firmware(struct net_device *dev,
if(buff)
*(mem++) = SWAP_BYTES(buff);
- return (0);
+ return 0;
}
static int smctr_disable_16bit(struct net_device *dev)
{
- return (0);
+ return 0;
}
/*
@@ -832,7 +832,7 @@ static int smctr_disable_adapter_ctrl_store(struct net_device *dev)
tp->trc_mask |= CSR_WCSS;
outb(tp->trc_mask, ioaddr + CSR);
- return (0);
+ return 0;
}
static int smctr_disable_bic_int(struct net_device *dev)
@@ -844,7 +844,7 @@ static int smctr_disable_bic_int(struct net_device *dev)
| CSR_MSKTINT | CSR_WCSS;
outb(tp->trc_mask, ioaddr + CSR);
- return (0);
+ return 0;
}
static int smctr_enable_16bit(struct net_device *dev)
@@ -858,7 +858,7 @@ static int smctr_enable_16bit(struct net_device *dev)
outb((r | LAAR_MEM16ENB), dev->base_addr + LAAR);
}
- return (0);
+ return 0;
}
/*
@@ -881,7 +881,7 @@ static int smctr_enable_adapter_ctrl_store(struct net_device *dev)
tp->trc_mask &= ~CSR_WCSS;
outb(tp->trc_mask, ioaddr + CSR);
- return (0);
+ return 0;
}
static int smctr_enable_adapter_ram(struct net_device *dev)
@@ -895,7 +895,7 @@ static int smctr_enable_adapter_ram(struct net_device *dev)
r = inb(ioaddr + MSR);
outb(MSR_MEMB | r, ioaddr + MSR);
- return (0);
+ return 0;
}
static int smctr_enable_bic_int(struct net_device *dev)
@@ -921,7 +921,7 @@ static int smctr_enable_bic_int(struct net_device *dev)
break;
}
- return (0);
+ return 0;
}
static int __init smctr_chk_isa(struct net_device *dev)
@@ -1145,7 +1145,7 @@ static int __init smctr_chk_isa(struct net_device *dev)
*/
}
- return (0);
+ return 0;
out2:
release_region(ioaddr, SMCTR_IO_EXTENT);
@@ -1199,7 +1199,7 @@ static int __init smctr_get_boardid(struct net_device *dev, int mca)
* return;
*/
if(IdByte & 0xF8)
- return (-1);
+ return -1;
r1 = inb(ioaddr + BID_REG_1);
r1 &= BID_ICR_MASK;
@@ -1250,21 +1250,21 @@ static int __init smctr_get_boardid(struct net_device *dev, int mca)
while(r1 & BID_RECALL_DONE_MASK)
r1 = inb(ioaddr + BID_REG_1);
- return (BoardIdMask);
+ return BoardIdMask;
}
static int smctr_get_group_address(struct net_device *dev)
{
smctr_issue_read_word_cmd(dev, RW_INDIVIDUAL_GROUP_ADDR);
- return(smctr_wait_cmd(dev));
+ return smctr_wait_cmd(dev);
}
static int smctr_get_functional_address(struct net_device *dev)
{
smctr_issue_read_word_cmd(dev, RW_FUNCTIONAL_ADDR);
- return(smctr_wait_cmd(dev));
+ return smctr_wait_cmd(dev);
}
/* Calculate number of Non-MAC receive BDB's and data buffers.
@@ -1346,14 +1346,14 @@ static unsigned int smctr_get_num_rx_bdbs(struct net_device *dev)
*/
mem_used += 0x100;
- return((0xffff - mem_used) / (RX_DATA_BUFFER_SIZE + sizeof(BDBlock)));
+ return (0xffff - mem_used) / (RX_DATA_BUFFER_SIZE + sizeof(BDBlock));
}
static int smctr_get_physical_drop_number(struct net_device *dev)
{
smctr_issue_read_word_cmd(dev, RW_PHYSICAL_DROP_NUMBER);
- return(smctr_wait_cmd(dev));
+ return smctr_wait_cmd(dev);
}
static __u8 * smctr_get_rx_pointer(struct net_device *dev, short queue)
@@ -1366,14 +1366,14 @@ static __u8 * smctr_get_rx_pointer(struct net_device *dev, short queue)
tp->rx_fcb_curr[queue]->bdb_ptr = bdb;
- return ((__u8 *)bdb->data_block_ptr);
+ return (__u8 *)bdb->data_block_ptr;
}
static int smctr_get_station_id(struct net_device *dev)
{
smctr_issue_read_word_cmd(dev, RW_INDIVIDUAL_MAC_ADDRESS);
- return(smctr_wait_cmd(dev));
+ return smctr_wait_cmd(dev);
}
/*
@@ -1384,7 +1384,7 @@ static struct net_device_stats *smctr_get_stats(struct net_device *dev)
{
struct net_local *tp = netdev_priv(dev);
- return ((struct net_device_stats *)&tp->MacStat);
+ return (struct net_device_stats *)&tp->MacStat;
}
static FCBlock *smctr_get_tx_fcb(struct net_device *dev, __u16 queue,
@@ -1401,14 +1401,14 @@ static FCBlock *smctr_get_tx_fcb(struct net_device *dev, __u16 queue,
/* check if there is enough FCB blocks */
if(tp->num_tx_fcbs_used[queue] >= tp->num_tx_fcbs[queue])
- return ((FCBlock *)(-1L));
+ return (FCBlock *)(-1L);
/* round off the input pkt size to the nearest even number */
alloc_size = (bytes_count + 1) & 0xfffe;
/* check if enough mem */
if((tp->tx_buff_used[queue] + alloc_size) > tp->tx_buff_size[queue])
- return ((FCBlock *)(-1L));
+ return (FCBlock *)(-1L);
/* check if past the end ;
* if exactly enough mem to end of ring, alloc from front.
@@ -1425,7 +1425,7 @@ static FCBlock *smctr_get_tx_fcb(struct net_device *dev, __u16 queue,
if((tp->tx_buff_used[queue] + alloc_size)
> tp->tx_buff_size[queue])
{
- return ((FCBlock *)(-1L));
+ return (FCBlock *)(-1L);
}
/* ring wrap */
@@ -1448,14 +1448,14 @@ static FCBlock *smctr_get_tx_fcb(struct net_device *dev, __u16 queue,
pFCB = tp->tx_fcb_curr[queue];
tp->tx_fcb_curr[queue] = tp->tx_fcb_curr[queue]->next_ptr;
- return (pFCB);
+ return pFCB;
}
static int smctr_get_upstream_neighbor_addr(struct net_device *dev)
{
smctr_issue_read_word_cmd(dev, RW_UPSTREAM_NEIGHBOR_ADDRESS);
- return(smctr_wait_cmd(dev));
+ return smctr_wait_cmd(dev);
}
static int smctr_hardware_send_packet(struct net_device *dev,
@@ -1469,21 +1469,22 @@ static int smctr_hardware_send_packet(struct net_device *dev,
printk(KERN_DEBUG"%s: smctr_hardware_send_packet\n", dev->name);
if(tp->status != OPEN)
- return (-1);
+ return -1;
if(tp->monitor_state_ready != 1)
- return (-1);
+ return -1;
for(;;)
{
/* Send first buffer from queue */
skb = skb_dequeue(&tp->SendSkbQueue);
if(skb == NULL)
- return (-1);
+ return -1;
tp->QueueSkb++;
- if(skb->len < SMC_HEADER_SIZE || skb->len > tp->max_packet_size) return (-1);
+ if(skb->len < SMC_HEADER_SIZE || skb->len > tp->max_packet_size)
+ return -1;
smctr_enable_16bit(dev);
smctr_set_page(dev, (__u8 *)tp->ram_access);
@@ -1492,7 +1493,7 @@ static int smctr_hardware_send_packet(struct net_device *dev,
== (FCBlock *)(-1L))
{
smctr_disable_16bit(dev);
- return (-1);
+ return -1;
}
smctr_tx_move_frame(dev, skb,
@@ -1508,7 +1509,7 @@ static int smctr_hardware_send_packet(struct net_device *dev,
smctr_disable_16bit(dev);
}
- return (0);
+ return 0;
}
static int smctr_init_acbs(struct net_device *dev)
@@ -1552,7 +1553,7 @@ static int smctr_init_acbs(struct net_device *dev)
tp->acb_curr = tp->acb_head->next_ptr;
tp->num_acbs_used = 0;
- return (0);
+ return 0;
}
static int smctr_init_adapter(struct net_device *dev)
@@ -1590,13 +1591,14 @@ static int smctr_init_adapter(struct net_device *dev)
if(smctr_checksum_firmware(dev))
{
- printk(KERN_ERR "%s: Previously loaded firmware is missing\n",dev->name); return (-ENOENT);
+ printk(KERN_ERR "%s: Previously loaded firmware is missing\n",dev->name);
+ return -ENOENT;
}
if((err = smctr_ram_memory_test(dev)))
{
printk(KERN_ERR "%s: RAM memory test failed.\n", dev->name);
- return (-EIO);
+ return -EIO;
}
smctr_set_rx_look_ahead(dev);
@@ -1608,7 +1610,7 @@ static int smctr_init_adapter(struct net_device *dev)
{
printk(KERN_ERR "%s: Initialization of card failed (%d)\n",
dev->name, err);
- return (-EINVAL);
+ return -EINVAL;
}
/* This routine clobbers the TRC's internal registers. */
@@ -1616,7 +1618,7 @@ static int smctr_init_adapter(struct net_device *dev)
{
printk(KERN_ERR "%s: Card failed internal self test (%d)\n",
dev->name, err);
- return (-EINVAL);
+ return -EINVAL;
}
/* Re-Initialize adapter's internal registers */
@@ -1625,17 +1627,17 @@ static int smctr_init_adapter(struct net_device *dev)
{
printk(KERN_ERR "%s: Initialization of card failed (%d)\n",
dev->name, err);
- return (-EINVAL);
+ return -EINVAL;
}
smctr_enable_bic_int(dev);
if((err = smctr_issue_enable_int_cmd(dev, TRC_INTERRUPT_ENABLE_MASK)))
- return (err);
+ return err;
smctr_disable_16bit(dev);
- return (0);
+ return 0;
}
static int smctr_init_card_real(struct net_device *dev)
@@ -1703,15 +1705,15 @@ static int smctr_init_card_real(struct net_device *dev)
smctr_init_shared_memory(dev);
if((err = smctr_issue_init_timers_cmd(dev)))
- return (err);
+ return err;
if((err = smctr_issue_init_txrx_cmd(dev)))
{
printk(KERN_ERR "%s: Hardware failure\n", dev->name);
- return (err);
+ return err;
}
- return (0);
+ return 0;
}
static int smctr_init_rx_bdbs(struct net_device *dev)
@@ -1763,7 +1765,7 @@ static int smctr_init_rx_bdbs(struct net_device *dev)
tp->rx_bdb_curr[i] = tp->rx_bdb_head[i]->next_ptr;
}
- return (0);
+ return 0;
}
static int smctr_init_rx_fcbs(struct net_device *dev)
@@ -1813,7 +1815,7 @@ static int smctr_init_rx_fcbs(struct net_device *dev)
tp->rx_fcb_curr[i] = tp->rx_fcb_head[i]->next_ptr;
}
- return(0);
+ return 0;
}
static int smctr_init_shared_memory(struct net_device *dev)
@@ -1871,7 +1873,7 @@ static int smctr_init_shared_memory(struct net_device *dev)
smctr_init_rx_bdbs(dev);
smctr_init_rx_fcbs(dev);
- return (0);
+ return 0;
}
static int smctr_init_tx_bdbs(struct net_device *dev)
@@ -1901,7 +1903,7 @@ static int smctr_init_tx_bdbs(struct net_device *dev)
tp->tx_bdb_head[i]->back_ptr = bdb;
}
- return (0);
+ return 0;
}
static int smctr_init_tx_fcbs(struct net_device *dev)
@@ -1940,7 +1942,7 @@ static int smctr_init_tx_fcbs(struct net_device *dev)
tp->num_tx_fcbs_used[i] = 0;
}
- return (0);
+ return 0;
}
static int smctr_internal_self_test(struct net_device *dev)
@@ -1949,33 +1951,33 @@ static int smctr_internal_self_test(struct net_device *dev)
int err;
if((err = smctr_issue_test_internal_rom_cmd(dev)))
- return (err);
+ return err;
if((err = smctr_wait_cmd(dev)))
- return (err);
+ return err;
if(tp->acb_head->cmd_done_status & 0xff)
- return (-1);
+ return -1;
if((err = smctr_issue_test_hic_cmd(dev)))
- return (err);
+ return err;
if((err = smctr_wait_cmd(dev)))
- return (err);
+ return err;
if(tp->acb_head->cmd_done_status & 0xff)
- return (-1);
+ return -1;
if((err = smctr_issue_test_mac_reg_cmd(dev)))
- return (err);
+ return err;
if((err = smctr_wait_cmd(dev)))
- return (err);
+ return err;
if(tp->acb_head->cmd_done_status & 0xff)
- return (-1);
+ return -1;
- return (0);
+ return 0;
}
/*
@@ -2468,14 +2470,14 @@ static int smctr_issue_enable_int_cmd(struct net_device *dev,
int err;
if((err = smctr_wait_while_cbusy(dev)))
- return (err);
+ return err;
tp->sclb_ptr->int_mask_control = interrupt_enable_mask;
tp->sclb_ptr->valid_command = SCLB_VALID | SCLB_CMD_CLEAR_INTERRUPT_MASK;
smctr_set_ctrl_attention(dev);
- return (0);
+ return 0;
}
static int smctr_issue_int_ack(struct net_device *dev, __u16 iack_code, __u16 ibits)
@@ -2483,7 +2485,7 @@ static int smctr_issue_int_ack(struct net_device *dev, __u16 iack_code, __u16 ib
struct net_local *tp = netdev_priv(dev);
if(smctr_wait_while_cbusy(dev))
- return (-1);
+ return -1;
tp->sclb_ptr->int_mask_control = ibits;
tp->sclb_ptr->iack_code = iack_code << 1; /* use the offset from base */ tp->sclb_ptr->resume_control = 0;
@@ -2491,7 +2493,7 @@ static int smctr_issue_int_ack(struct net_device *dev, __u16 iack_code, __u16 ib
smctr_set_ctrl_attention(dev);
- return (0);
+ return 0;
}
static int smctr_issue_init_timers_cmd(struct net_device *dev)
@@ -2502,10 +2504,10 @@ static int smctr_issue_init_timers_cmd(struct net_device *dev)
__u16 *pTimer_Struc = (__u16 *)tp->misc_command_data;
if((err = smctr_wait_while_cbusy(dev)))
- return (err);
+ return err;
if((err = smctr_wait_cmd(dev)))
- return (err);
+ return err;
tp->config_word0 = THDREN | DMA_TRIGGER | USETPT | NO_AUTOREMOVE;
tp->config_word1 = 0;
@@ -2648,7 +2650,7 @@ static int smctr_issue_init_timers_cmd(struct net_device *dev)
err = smctr_setup_single_cmd_w_data(dev, ACB_CMD_INIT_TRC_TIMERS, 0);
- return (err);
+ return err;
}
static int smctr_issue_init_txrx_cmd(struct net_device *dev)
@@ -2659,12 +2661,12 @@ static int smctr_issue_init_txrx_cmd(struct net_device *dev)
void **txrx_ptrs = (void *)tp->misc_command_data;
if((err = smctr_wait_while_cbusy(dev)))
- return (err);
+ return err;
if((err = smctr_wait_cmd(dev)))
{
printk(KERN_ERR "%s: Hardware failure\n", dev->name);
- return (err);
+ return err;
}
/* Initialize Transmit Queue Pointers that are used, to point to
@@ -2695,7 +2697,7 @@ static int smctr_issue_init_txrx_cmd(struct net_device *dev)
err = smctr_setup_single_cmd_w_data(dev, ACB_CMD_INIT_TX_RX, 0);
- return (err);
+ return err;
}
static int smctr_issue_insert_cmd(struct net_device *dev)
@@ -2704,7 +2706,7 @@ static int smctr_issue_insert_cmd(struct net_device *dev)
err = smctr_setup_single_cmd(dev, ACB_CMD_INSERT, ACB_SUB_CMD_NOP);
- return (err);
+ return err;
}
static int smctr_issue_read_ring_status_cmd(struct net_device *dev)
@@ -2712,15 +2714,15 @@ static int smctr_issue_read_ring_status_cmd(struct net_device *dev)
int err;
if((err = smctr_wait_while_cbusy(dev)))
- return (err);
+ return err;
if((err = smctr_wait_cmd(dev)))
- return (err);
+ return err;
err = smctr_setup_single_cmd_w_data(dev, ACB_CMD_READ_TRC_STATUS,
RW_TRC_STATUS_BLOCK);
- return (err);
+ return err;
}
static int smctr_issue_read_word_cmd(struct net_device *dev, __u16 aword_cnt)
@@ -2728,15 +2730,15 @@ static int smctr_issue_read_word_cmd(struct net_device *dev, __u16 aword_cnt)
int err;
if((err = smctr_wait_while_cbusy(dev)))
- return (err);
+ return err;
if((err = smctr_wait_cmd(dev)))
- return (err);
+ return err;
err = smctr_setup_single_cmd_w_data(dev, ACB_CMD_MCT_READ_VALUE,
aword_cnt);
- return (err);
+ return err;
}
static int smctr_issue_remove_cmd(struct net_device *dev)
@@ -2745,14 +2747,14 @@ static int smctr_issue_remove_cmd(struct net_device *dev)
int err;
if((err = smctr_wait_while_cbusy(dev)))
- return (err);
+ return err;
tp->sclb_ptr->resume_control = 0;
tp->sclb_ptr->valid_command = SCLB_VALID | SCLB_CMD_REMOVE;
smctr_set_ctrl_attention(dev);
- return (0);
+ return 0;
}
static int smctr_issue_resume_acb_cmd(struct net_device *dev)
@@ -2761,7 +2763,7 @@ static int smctr_issue_resume_acb_cmd(struct net_device *dev)
int err;
if((err = smctr_wait_while_cbusy(dev)))
- return (err);
+ return err;
tp->sclb_ptr->resume_control = SCLB_RC_ACB;
tp->sclb_ptr->valid_command = SCLB_VALID | SCLB_RESUME_CONTROL_VALID;
@@ -2770,7 +2772,7 @@ static int smctr_issue_resume_acb_cmd(struct net_device *dev)
smctr_set_ctrl_attention(dev);
- return (0);
+ return 0;
}
static int smctr_issue_resume_rx_bdb_cmd(struct net_device *dev, __u16 queue)
@@ -2779,7 +2781,7 @@ static int smctr_issue_resume_rx_bdb_cmd(struct net_device *dev, __u16 queue)
int err;
if((err = smctr_wait_while_cbusy(dev)))
- return (err);
+ return err;
if(queue == MAC_QUEUE)
tp->sclb_ptr->resume_control = SCLB_RC_RX_MAC_BDB;
@@ -2790,7 +2792,7 @@ static int smctr_issue_resume_rx_bdb_cmd(struct net_device *dev, __u16 queue)
smctr_set_ctrl_attention(dev);
- return (0);
+ return 0;
}
static int smctr_issue_resume_rx_fcb_cmd(struct net_device *dev, __u16 queue)
@@ -2801,7 +2803,7 @@ static int smctr_issue_resume_rx_fcb_cmd(struct net_device *dev, __u16 queue)
printk(KERN_DEBUG "%s: smctr_issue_resume_rx_fcb_cmd\n", dev->name);
if(smctr_wait_while_cbusy(dev))
- return (-1);
+ return -1;
if(queue == MAC_QUEUE)
tp->sclb_ptr->resume_control = SCLB_RC_RX_MAC_FCB;
@@ -2812,7 +2814,7 @@ static int smctr_issue_resume_rx_fcb_cmd(struct net_device *dev, __u16 queue)
smctr_set_ctrl_attention(dev);
- return (0);
+ return 0;
}
static int smctr_issue_resume_tx_fcb_cmd(struct net_device *dev, __u16 queue)
@@ -2823,14 +2825,14 @@ static int smctr_issue_resume_tx_fcb_cmd(struct net_device *dev, __u16 queue)
printk(KERN_DEBUG "%s: smctr_issue_resume_tx_fcb_cmd\n", dev->name);
if(smctr_wait_while_cbusy(dev))
- return (-1);
+ return -1;
tp->sclb_ptr->resume_control = (SCLB_RC_TFCB0 << queue);
tp->sclb_ptr->valid_command = SCLB_RESUME_CONTROL_VALID | SCLB_VALID;
smctr_set_ctrl_attention(dev);
- return (0);
+ return 0;
}
static int smctr_issue_test_internal_rom_cmd(struct net_device *dev)
@@ -2840,7 +2842,7 @@ static int smctr_issue_test_internal_rom_cmd(struct net_device *dev)
err = smctr_setup_single_cmd(dev, ACB_CMD_MCT_TEST,
TRC_INTERNAL_ROM_TEST);
- return (err);
+ return err;
}
static int smctr_issue_test_hic_cmd(struct net_device *dev)
@@ -2850,7 +2852,7 @@ static int smctr_issue_test_hic_cmd(struct net_device *dev)
err = smctr_setup_single_cmd(dev, ACB_CMD_HIC_TEST,
TRC_HOST_INTERFACE_REG_TEST);
- return (err);
+ return err;
}
static int smctr_issue_test_mac_reg_cmd(struct net_device *dev)
@@ -2860,7 +2862,7 @@ static int smctr_issue_test_mac_reg_cmd(struct net_device *dev)
err = smctr_setup_single_cmd(dev, ACB_CMD_MCT_TEST,
TRC_MAC_REGISTERS_TEST);
- return (err);
+ return err;
}
static int smctr_issue_trc_loopback_cmd(struct net_device *dev)
@@ -2870,7 +2872,7 @@ static int smctr_issue_trc_loopback_cmd(struct net_device *dev)
err = smctr_setup_single_cmd(dev, ACB_CMD_MCT_TEST,
TRC_INTERNAL_LOOPBACK);
- return (err);
+ return err;
}
static int smctr_issue_tri_loopback_cmd(struct net_device *dev)
@@ -2880,7 +2882,7 @@ static int smctr_issue_tri_loopback_cmd(struct net_device *dev)
err = smctr_setup_single_cmd(dev, ACB_CMD_MCT_TEST,
TRC_TRI_LOOPBACK);
- return (err);
+ return err;
}
static int smctr_issue_write_byte_cmd(struct net_device *dev,
@@ -2891,10 +2893,10 @@ static int smctr_issue_write_byte_cmd(struct net_device *dev,
int err;
if((err = smctr_wait_while_cbusy(dev)))
- return (err);
+ return err;
if((err = smctr_wait_cmd(dev)))
- return (err);
+ return err;
for(iword = 0, ibyte = 0; iword < (unsigned int)(aword_cnt & 0xff);
iword++, ibyte += 2)
@@ -2903,8 +2905,8 @@ static int smctr_issue_write_byte_cmd(struct net_device *dev,
| (*((__u8 *)byte + ibyte + 1));
}
- return (smctr_setup_single_cmd_w_data(dev, ACB_CMD_MCT_WRITE_VALUE,
- aword_cnt));
+ return smctr_setup_single_cmd_w_data(dev, ACB_CMD_MCT_WRITE_VALUE,
+ aword_cnt);
}
static int smctr_issue_write_word_cmd(struct net_device *dev,
@@ -2914,10 +2916,10 @@ static int smctr_issue_write_word_cmd(struct net_device *dev,
unsigned int i, err;
if((err = smctr_wait_while_cbusy(dev)))
- return (err);
+ return err;
if((err = smctr_wait_cmd(dev)))
- return (err);
+ return err;
for(i = 0; i < (unsigned int)(aword_cnt & 0xff); i++)
tp->misc_command_data[i] = *((__u16 *)word + i);
@@ -2925,7 +2927,7 @@ static int smctr_issue_write_word_cmd(struct net_device *dev,
err = smctr_setup_single_cmd_w_data(dev, ACB_CMD_MCT_WRITE_VALUE,
aword_cnt);
- return (err);
+ return err;
}
static int smctr_join_complete_state(struct net_device *dev)
@@ -2935,7 +2937,7 @@ static int smctr_join_complete_state(struct net_device *dev)
err = smctr_setup_single_cmd(dev, ACB_CMD_CHANGE_JOIN_STATE,
JS_JOIN_COMPLETE_STATE);
- return (err);
+ return err;
}
static int smctr_link_tx_fcbs_to_bdbs(struct net_device *dev)
@@ -2959,7 +2961,7 @@ static int smctr_link_tx_fcbs_to_bdbs(struct net_device *dev)
}
}
- return (0);
+ return 0;
}
static int smctr_load_firmware(struct net_device *dev)
@@ -2974,7 +2976,7 @@ static int smctr_load_firmware(struct net_device *dev)
if (request_firmware(&fw, "tr_smctr.bin", &dev->dev)) {
printk(KERN_ERR "%s: firmware not found\n", dev->name);
- return (UCODE_NOT_PRESENT);
+ return UCODE_NOT_PRESENT;
}
tp->num_of_tx_buffs = 4;
@@ -3036,7 +3038,7 @@ static int smctr_load_firmware(struct net_device *dev)
smctr_disable_16bit(dev);
out:
release_firmware(fw);
- return (err);
+ return err;
}
static int smctr_load_node_addr(struct net_device *dev)
@@ -3052,7 +3054,7 @@ static int smctr_load_node_addr(struct net_device *dev)
}
dev->addr_len = 6;
- return (0);
+ return 0;
}
/* Lobe Media Test.
@@ -3146,14 +3148,14 @@ static int smctr_lobe_media_test_cmd(struct net_device *dev)
if(smctr_wait_cmd(dev))
{
printk(KERN_ERR "Lobe Failed test state\n");
- return (LOBE_MEDIA_TEST_FAILED);
+ return LOBE_MEDIA_TEST_FAILED;
}
}
err = smctr_setup_single_cmd(dev, ACB_CMD_MCT_TEST,
TRC_LOBE_MEDIA_TEST);
- return (err);
+ return err;
}
static int smctr_lobe_media_test_state(struct net_device *dev)
@@ -3163,7 +3165,7 @@ static int smctr_lobe_media_test_state(struct net_device *dev)
err = smctr_setup_single_cmd(dev, ACB_CMD_CHANGE_JOIN_STATE,
JS_LOBE_TEST_STATE);
- return (err);
+ return err;
}
static int smctr_make_8025_hdr(struct net_device *dev,
@@ -3212,7 +3214,7 @@ static int smctr_make_8025_hdr(struct net_device *dev,
break;
}
- return (0);
+ return 0;
}
static int smctr_make_access_pri(struct net_device *dev, MAC_SUB_VECTOR *tsv)
@@ -3225,7 +3227,7 @@ static int smctr_make_access_pri(struct net_device *dev, MAC_SUB_VECTOR *tsv)
tsv->svv[0] = MSB(tp->authorized_access_priority);
tsv->svv[1] = LSB(tp->authorized_access_priority);
- return (0);
+ return 0;
}
static int smctr_make_addr_mod(struct net_device *dev, MAC_SUB_VECTOR *tsv)
@@ -3236,7 +3238,7 @@ static int smctr_make_addr_mod(struct net_device *dev, MAC_SUB_VECTOR *tsv)
tsv->svv[0] = 0;
tsv->svv[1] = 0;
- return (0);
+ return 0;
}
static int smctr_make_auth_funct_class(struct net_device *dev,
@@ -3250,7 +3252,7 @@ static int smctr_make_auth_funct_class(struct net_device *dev,
tsv->svv[0] = MSB(tp->authorized_function_classes);
tsv->svv[1] = LSB(tp->authorized_function_classes);
- return (0);
+ return 0;
}
static int smctr_make_corr(struct net_device *dev,
@@ -3262,7 +3264,7 @@ static int smctr_make_corr(struct net_device *dev,
tsv->svv[0] = MSB(correlator);
tsv->svv[1] = LSB(correlator);
- return (0);
+ return 0;
}
static int smctr_make_funct_addr(struct net_device *dev, MAC_SUB_VECTOR *tsv)
@@ -3280,7 +3282,7 @@ static int smctr_make_funct_addr(struct net_device *dev, MAC_SUB_VECTOR *tsv)
tsv->svv[2] = MSB(tp->misc_command_data[1]);
tsv->svv[3] = LSB(tp->misc_command_data[1]);
- return (0);
+ return 0;
}
static int smctr_make_group_addr(struct net_device *dev, MAC_SUB_VECTOR *tsv)
@@ -3305,7 +3307,7 @@ static int smctr_make_group_addr(struct net_device *dev, MAC_SUB_VECTOR *tsv)
tsv->svv[2] == 0x00 && tsv->svv[3] == 0x00)
tsv->svv[0] = 0x00;
- return (0);
+ return 0;
}
static int smctr_make_phy_drop_num(struct net_device *dev,
@@ -3324,7 +3326,7 @@ static int smctr_make_phy_drop_num(struct net_device *dev,
tsv->svv[2] = MSB(tp->misc_command_data[1]);
tsv->svv[3] = LSB(tp->misc_command_data[1]);
- return (0);
+ return 0;
}
static int smctr_make_product_id(struct net_device *dev, MAC_SUB_VECTOR *tsv)
@@ -3337,7 +3339,7 @@ static int smctr_make_product_id(struct net_device *dev, MAC_SUB_VECTOR *tsv)
for(i = 0; i < 18; i++)
tsv->svv[i] = 0xF0;
- return (0);
+ return 0;
}
static int smctr_make_station_id(struct net_device *dev, MAC_SUB_VECTOR *tsv)
@@ -3358,7 +3360,7 @@ static int smctr_make_station_id(struct net_device *dev, MAC_SUB_VECTOR *tsv)
tsv->svv[4] = MSB(tp->misc_command_data[2]);
tsv->svv[5] = LSB(tp->misc_command_data[2]);
- return (0);
+ return 0;
}
static int smctr_make_ring_station_status(struct net_device *dev,
@@ -3374,7 +3376,7 @@ static int smctr_make_ring_station_status(struct net_device *dev,
tsv->svv[4] = 0;
tsv->svv[5] = 0;
- return (0);
+ return 0;
}
static int smctr_make_ring_station_version(struct net_device *dev,
@@ -3400,7 +3402,7 @@ static int smctr_make_ring_station_version(struct net_device *dev,
else
tsv->svv[9] = 0xc4; /* EBCDIC - D */
- return (0);
+ return 0;
}
static int smctr_make_tx_status_code(struct net_device *dev,
@@ -3414,7 +3416,7 @@ static int smctr_make_tx_status_code(struct net_device *dev,
/* Stripped frame status of Transmitted Frame */
tsv->svv[1] = tx_fstatus & 0xff;
- return (0);
+ return 0;
}
static int smctr_make_upstream_neighbor_addr(struct net_device *dev,
@@ -3436,7 +3438,7 @@ static int smctr_make_upstream_neighbor_addr(struct net_device *dev,
tsv->svv[4] = MSB(tp->misc_command_data[2]);
tsv->svv[5] = LSB(tp->misc_command_data[2]);
- return (0);
+ return 0;
}
static int smctr_make_wrap_data(struct net_device *dev, MAC_SUB_VECTOR *tsv)
@@ -3444,7 +3446,7 @@ static int smctr_make_wrap_data(struct net_device *dev, MAC_SUB_VECTOR *tsv)
tsv->svi = WRAP_DATA;
tsv->svl = S_WRAP_DATA;
- return (0);
+ return 0;
}
/*
@@ -3464,9 +3466,9 @@ static int smctr_open(struct net_device *dev)
err = smctr_init_adapter(dev);
if(err < 0)
- return (err);
+ return err;
- return (err);
+ return err;
}
/* Interrupt driven open of Token card. */
@@ -3481,9 +3483,9 @@ static int smctr_open_tr(struct net_device *dev)
/* Now we can actually open the adapter. */
if(tp->status == OPEN)
- return (0);
+ return 0;
if(tp->status != INITIALIZED)
- return (-1);
+ return -1;
/* FIXME: it would work a lot better if we masked the irq sources
on the card here, then we could skip the locking and poll nicely */
@@ -3560,7 +3562,7 @@ static int smctr_open_tr(struct net_device *dev)
out:
spin_unlock_irqrestore(&tp->lock, flags);
- return (err);
+ return err;
}
/* Check for a network adapter of this type,
@@ -3675,7 +3677,7 @@ static int __init smctr_probe1(struct net_device *dev, int ioaddr)
dev->netdev_ops = &smctr_netdev_ops;
dev->watchdog_timeo = HZ;
- return (0);
+ return 0;
out:
return err;
@@ -3699,13 +3701,13 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
case INIT:
if((rcode = smctr_rcv_init(dev, rmf, &correlator)) == HARDWARE_FAILED)
{
- return (rcode);
+ return rcode;
}
if((err = smctr_send_rsp(dev, rmf, rcode,
correlator)))
{
- return (err);
+ return err;
}
break;
@@ -3713,13 +3715,13 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
if((rcode = smctr_rcv_chg_param(dev, rmf,
&correlator)) ==HARDWARE_FAILED)
{
- return (rcode);
+ return rcode;
}
if((err = smctr_send_rsp(dev, rmf, rcode,
correlator)))
{
- return (err);
+ return err;
}
break;
@@ -3728,16 +3730,16 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
rmf, &correlator)) != POSITIVE_ACK)
{
if(rcode == HARDWARE_FAILED)
- return (rcode);
+ return rcode;
else
- return (smctr_send_rsp(dev, rmf,
- rcode, correlator));
+ return smctr_send_rsp(dev, rmf,
+ rcode, correlator);
}
if((err = smctr_send_rpt_addr(dev, rmf,
correlator)))
{
- return (err);
+ return err;
}
break;
@@ -3746,17 +3748,17 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
rmf, &correlator)) != POSITIVE_ACK)
{
if(rcode == HARDWARE_FAILED)
- return (rcode);
+ return rcode;
else
- return (smctr_send_rsp(dev, rmf,
+ return smctr_send_rsp(dev, rmf,
rcode,
- correlator));
+ correlator);
}
if((err = smctr_send_rpt_attch(dev, rmf,
correlator)))
{
- return (err);
+ return err;
}
break;
@@ -3765,17 +3767,17 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
rmf, &correlator)) != POSITIVE_ACK)
{
if(rcode == HARDWARE_FAILED)
- return (rcode);
+ return rcode;
else
- return (smctr_send_rsp(dev, rmf,
+ return smctr_send_rsp(dev, rmf,
rcode,
- correlator));
+ correlator);
}
if((err = smctr_send_rpt_state(dev, rmf,
correlator)))
{
- return (err);
+ return err;
}
break;
@@ -3786,17 +3788,17 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
!= POSITIVE_ACK)
{
if(rcode == HARDWARE_FAILED)
- return (rcode);
+ return rcode;
else
- return (smctr_send_rsp(dev, rmf,
+ return smctr_send_rsp(dev, rmf,
rcode,
- correlator));
+ correlator);
}
if((err = smctr_send_tx_forward(dev, rmf,
&tx_fstatus)) == HARDWARE_FAILED)
{
- return (err);
+ return err;
}
if(err == A_FRAME_WAS_FORWARDED)
@@ -3805,7 +3807,7 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
rmf, tx_fstatus))
== HARDWARE_FAILED)
{
- return (err);
+ return err;
}
}
break;
@@ -3834,7 +3836,7 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
if((err = smctr_send_rsp(dev, rmf,rcode,
correlator)))
{
- return (err);
+ return err;
}
}
@@ -3899,7 +3901,7 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
err = 0;
}
- return (err);
+ return err;
}
/* Adapter RAM test. Incremental word ODD boundary data test. */
@@ -3942,7 +3944,7 @@ static int smctr_ram_memory_test(struct net_device *dev)
err_offset = j;
err_word = word_read;
err_pattern = word_pattern;
- return (RAM_TEST_FAILED);
+ return RAM_TEST_FAILED;
}
}
}
@@ -3966,14 +3968,14 @@ static int smctr_ram_memory_test(struct net_device *dev)
err_offset = j;
err_word = word_read;
err_pattern = word_pattern;
- return (RAM_TEST_FAILED);
+ return RAM_TEST_FAILED;
}
}
}
smctr_set_page(dev, (__u8 *)tp->ram_access);
- return (0);
+ return 0;
}
static int smctr_rcv_chg_param(struct net_device *dev, MAC_HEADER *rmf,
@@ -3986,7 +3988,7 @@ static int smctr_rcv_chg_param(struct net_device *dev, MAC_HEADER *rmf,
/* This Frame can only come from a CRS */
if((rmf->dc_sc & SC_MASK) != SC_CRS)
- return(E_INAPPROPRIATE_SOURCE_CLASS);
+ return E_INAPPROPRIATE_SOURCE_CLASS;
/* Remove MVID Length from total length. */
vlen = (signed short)rmf->vl - 4;
@@ -4058,7 +4060,7 @@ static int smctr_rcv_chg_param(struct net_device *dev, MAC_HEADER *rmf,
}
}
- return (rcode);
+ return rcode;
}
static int smctr_rcv_init(struct net_device *dev, MAC_HEADER *rmf,
@@ -4071,7 +4073,7 @@ static int smctr_rcv_init(struct net_device *dev, MAC_HEADER *rmf,
/* This Frame can only come from a RPS */
if((rmf->dc_sc & SC_MASK) != SC_RPS)
- return (E_INAPPROPRIATE_SOURCE_CLASS);
+ return E_INAPPROPRIATE_SOURCE_CLASS;
/* Remove MVID Length from total length. */
vlen = (signed short)rmf->vl - 4;
@@ -4133,7 +4135,7 @@ static int smctr_rcv_init(struct net_device *dev, MAC_HEADER *rmf,
}
}
- return (rcode);
+ return rcode;
}
static int smctr_rcv_tx_forward(struct net_device *dev, MAC_HEADER *rmf)
@@ -4145,7 +4147,7 @@ static int smctr_rcv_tx_forward(struct net_device *dev, MAC_HEADER *rmf)
/* This Frame can only come from a CRS */
if((rmf->dc_sc & SC_MASK) != SC_CRS)
- return (E_INAPPROPRIATE_SOURCE_CLASS);
+ return E_INAPPROPRIATE_SOURCE_CLASS;
/* Remove MVID Length from total length */
vlen = (signed short)rmf->vl - 4;
@@ -4193,7 +4195,7 @@ static int smctr_rcv_tx_forward(struct net_device *dev, MAC_HEADER *rmf)
}
}
- return (rcode);
+ return rcode;
}
static int smctr_rcv_rq_addr_state_attch(struct net_device *dev,
@@ -4250,7 +4252,7 @@ static int smctr_rcv_rq_addr_state_attch(struct net_device *dev,
}
}
- return (rcode);
+ return rcode;
}
static int smctr_rcv_unknown(struct net_device *dev, MAC_HEADER *rmf,
@@ -4284,7 +4286,7 @@ static int smctr_rcv_unknown(struct net_device *dev, MAC_HEADER *rmf,
rsv = (MAC_SUB_VECTOR *)((__u32)rsv + rsv->svl);
}
- return (E_UNRECOGNIZED_VECTOR_ID);
+ return E_UNRECOGNIZED_VECTOR_ID;
}
/*
@@ -4311,7 +4313,7 @@ static int smctr_reset_adapter(struct net_device *dev)
*/
outb(tp->trc_mask | CSR_CLRTINT | CSR_CLRCBUSY, ioaddr + CSR);
- return (0);
+ return 0;
}
static int smctr_restart_tx_chain(struct net_device *dev, short queue)
@@ -4329,7 +4331,7 @@ static int smctr_restart_tx_chain(struct net_device *dev, short queue)
err = smctr_issue_resume_tx_fcb_cmd(dev, queue);
}
- return (err);
+ return err;
}
static int smctr_ring_status_chg(struct net_device *dev)
@@ -4371,7 +4373,7 @@ static int smctr_ring_status_chg(struct net_device *dev)
}
if(!(tp->ring_status_flags & RING_STATUS_CHANGED))
- return (0);
+ return 0;
switch(tp->ring_status)
{
@@ -4421,7 +4423,7 @@ static int smctr_ring_status_chg(struct net_device *dev)
break;
}
- return (0);
+ return 0;
}
static int smctr_rx_frame(struct net_device *dev)
@@ -4486,7 +4488,7 @@ static int smctr_rx_frame(struct net_device *dev)
break;
}
- return (err);
+ return err;
}
static int smctr_send_dat(struct net_device *dev)
@@ -4502,7 +4504,7 @@ static int smctr_send_dat(struct net_device *dev)
if((fcb = smctr_get_tx_fcb(dev, MAC_QUEUE,
sizeof(MAC_HEADER))) == (FCBlock *)(-1L))
{
- return (OUT_OF_RESOURCES);
+ return OUT_OF_RESOURCES;
}
/* Initialize DAT Data Fields. */
@@ -4524,7 +4526,7 @@ static int smctr_send_dat(struct net_device *dev)
/* Start Transmit. */
if((err = smctr_trc_send_packet(dev, fcb, MAC_QUEUE)))
- return (err);
+ return err;
/* Wait for Transmit to Complete */
for(i = 0; i < 10000; i++)
@@ -4538,7 +4540,7 @@ static int smctr_send_dat(struct net_device *dev)
if(!(fcb->frame_status & FCB_COMMAND_DONE) ||
fcb->frame_status & (FCB_TX_STATUS_E | FCB_TX_AC_BITS))
{
- return (INITIALIZE_FAILED);
+ return INITIALIZE_FAILED;
}
/* De-allocated Tx FCB and Frame Buffer
@@ -4549,7 +4551,7 @@ static int smctr_send_dat(struct net_device *dev)
tp->tx_queue_status[MAC_QUEUE] = NOT_TRANSMITING;
smctr_update_tx_chain(dev, fcb, MAC_QUEUE);
- return (0);
+ return 0;
}
static void smctr_timeout(struct net_device *dev)
@@ -4610,7 +4612,7 @@ static int smctr_send_lobe_media_test(struct net_device *dev)
if((fcb = smctr_get_tx_fcb(dev, MAC_QUEUE, sizeof(struct trh_hdr)
+ S_WRAP_DATA + S_WRAP_DATA)) == (FCBlock *)(-1L))
{
- return (OUT_OF_RESOURCES);
+ return OUT_OF_RESOURCES;
}
/* Initialize DAT Data Fields. */
@@ -4639,7 +4641,7 @@ static int smctr_send_lobe_media_test(struct net_device *dev)
/* Start Transmit. */
tmf->vl = SWAP_BYTES(tmf->vl);
if((err = smctr_trc_send_packet(dev, fcb, MAC_QUEUE)))
- return (err);
+ return err;
/* Wait for Transmit to Complete. (10 ms). */
for(i=0; i < 10000; i++)
@@ -4653,7 +4655,7 @@ static int smctr_send_lobe_media_test(struct net_device *dev)
if(!(fcb->frame_status & FCB_COMMAND_DONE) ||
fcb->frame_status & (FCB_TX_STATUS_E | FCB_TX_AC_BITS))
{
- return (LOBE_MEDIA_TEST_FAILED);
+ return LOBE_MEDIA_TEST_FAILED;
}
/* De-allocated Tx FCB and Frame Buffer
@@ -4664,7 +4666,7 @@ static int smctr_send_lobe_media_test(struct net_device *dev)
tp->tx_queue_status[MAC_QUEUE] = NOT_TRANSMITING;
smctr_update_tx_chain(dev, fcb, MAC_QUEUE);
- return (0);
+ return 0;
}
static int smctr_send_rpt_addr(struct net_device *dev, MAC_HEADER *rmf,
@@ -4679,7 +4681,7 @@ static int smctr_send_rpt_addr(struct net_device *dev, MAC_HEADER *rmf,
+ S_ADDRESS_MODIFER + S_GROUP_ADDRESS + S_FUNCTIONAL_ADDRESS))
== (FCBlock *)(-1L))
{
- return (0);
+ return 0;
}
tmf = (MAC_HEADER *)fcb->bdb_ptr->data_block_ptr;
@@ -4722,7 +4724,7 @@ static int smctr_send_rpt_addr(struct net_device *dev, MAC_HEADER *rmf,
*/
tmf->vl = SWAP_BYTES(tmf->vl);
- return (smctr_trc_send_packet(dev, fcb, MAC_QUEUE));
+ return smctr_trc_send_packet(dev, fcb, MAC_QUEUE);
}
static int smctr_send_rpt_attch(struct net_device *dev, MAC_HEADER *rmf,
@@ -4737,7 +4739,7 @@ static int smctr_send_rpt_attch(struct net_device *dev, MAC_HEADER *rmf,
+ S_AUTHORIZED_FUNCTION_CLASS + S_AUTHORIZED_ACCESS_PRIORITY))
== (FCBlock *)(-1L))
{
- return (0);
+ return 0;
}
tmf = (MAC_HEADER *)fcb->bdb_ptr->data_block_ptr;
@@ -4776,7 +4778,7 @@ static int smctr_send_rpt_attch(struct net_device *dev, MAC_HEADER *rmf,
*/
tmf->vl = SWAP_BYTES(tmf->vl);
- return (smctr_trc_send_packet(dev, fcb, MAC_QUEUE));
+ return smctr_trc_send_packet(dev, fcb, MAC_QUEUE);
}
static int smctr_send_rpt_state(struct net_device *dev, MAC_HEADER *rmf,
@@ -4791,7 +4793,7 @@ static int smctr_send_rpt_state(struct net_device *dev, MAC_HEADER *rmf,
+ S_RING_STATION_STATUS + S_STATION_IDENTIFER))
== (FCBlock *)(-1L))
{
- return (0);
+ return 0;
}
tmf = (MAC_HEADER *)fcb->bdb_ptr->data_block_ptr;
@@ -4826,7 +4828,7 @@ static int smctr_send_rpt_state(struct net_device *dev, MAC_HEADER *rmf,
*/
tmf->vl = SWAP_BYTES(tmf->vl);
- return (smctr_trc_send_packet(dev, fcb, MAC_QUEUE));
+ return smctr_trc_send_packet(dev, fcb, MAC_QUEUE);
}
static int smctr_send_rpt_tx_forward(struct net_device *dev,
@@ -4839,7 +4841,7 @@ static int smctr_send_rpt_tx_forward(struct net_device *dev,
if((fcb = smctr_get_tx_fcb(dev, MAC_QUEUE, sizeof(MAC_HEADER)
+ S_TRANSMIT_STATUS_CODE)) == (FCBlock *)(-1L))
{
- return (0);
+ return 0;
}
tmf = (MAC_HEADER *)fcb->bdb_ptr->data_block_ptr;
@@ -4862,7 +4864,7 @@ static int smctr_send_rpt_tx_forward(struct net_device *dev,
*/
tmf->vl = SWAP_BYTES(tmf->vl);
- return(smctr_trc_send_packet(dev, fcb, MAC_QUEUE));
+ return smctr_trc_send_packet(dev, fcb, MAC_QUEUE);
}
static int smctr_send_rsp(struct net_device *dev, MAC_HEADER *rmf,
@@ -4875,7 +4877,7 @@ static int smctr_send_rsp(struct net_device *dev, MAC_HEADER *rmf,
if((fcb = smctr_get_tx_fcb(dev, MAC_QUEUE, sizeof(MAC_HEADER)
+ S_CORRELATOR + S_RESPONSE_CODE)) == (FCBlock *)(-1L))
{
- return (0);
+ return 0;
}
tmf = (MAC_HEADER *)fcb->bdb_ptr->data_block_ptr;
@@ -4888,7 +4890,7 @@ static int smctr_send_rsp(struct net_device *dev, MAC_HEADER *rmf,
tsv = (MAC_SUB_VECTOR *)((__u32)tmf + sizeof(MAC_HEADER));
smctr_make_corr(dev, tsv, correlator);
- return (0);
+ return 0;
}
static int smctr_send_rq_init(struct net_device *dev)
@@ -4907,7 +4909,7 @@ static int smctr_send_rq_init(struct net_device *dev)
+ S_RING_STATION_VERSION_NUMBER + S_ADDRESS_MODIFER))
== (FCBlock *)(-1L)))
{
- return (0);
+ return 0;
}
tmf = (MAC_HEADER *)fcb->bdb_ptr->data_block_ptr;
@@ -4943,7 +4945,7 @@ static int smctr_send_rq_init(struct net_device *dev)
tmf->vl = SWAP_BYTES(tmf->vl);
if((err = smctr_trc_send_packet(dev, fcb, MAC_QUEUE)))
- return (err);
+ return err;
/* Wait for Transmit to Complete */
for(i = 0; i < 10000; i++)
@@ -4957,7 +4959,7 @@ static int smctr_send_rq_init(struct net_device *dev)
fstatus = fcb->frame_status;
if(!(fstatus & FCB_COMMAND_DONE))
- return (HARDWARE_FAILED);
+ return HARDWARE_FAILED;
if(!(fstatus & FCB_TX_STATUS_E))
count++;
@@ -4971,7 +4973,7 @@ static int smctr_send_rq_init(struct net_device *dev)
smctr_update_tx_chain(dev, fcb, MAC_QUEUE);
} while(count < 4 && ((fstatus & FCB_TX_AC_BITS) ^ FCB_TX_AC_BITS));
- return (smctr_join_complete_state(dev));
+ return smctr_join_complete_state(dev);
}
static int smctr_send_tx_forward(struct net_device *dev, MAC_HEADER *rmf,
@@ -4984,13 +4986,13 @@ static int smctr_send_tx_forward(struct net_device *dev, MAC_HEADER *rmf,
/* Check if this is the END POINT of the Transmit Forward Chain. */
if(rmf->vl <= 18)
- return (0);
+ return 0;
/* Allocate Transmit FCB only by requesting 0 bytes
* of data buffer.
*/
if((fcb = smctr_get_tx_fcb(dev, MAC_QUEUE, 0)) == (FCBlock *)(-1L))
- return (0);
+ return 0;
/* Set pointer to Transmit Frame Buffer to the data
* portion of the received TX Forward frame, making
@@ -5006,7 +5008,7 @@ static int smctr_send_tx_forward(struct net_device *dev, MAC_HEADER *rmf,
fcb->bdb_ptr->buffer_length = rmf->vl - 4 - 2;
if((err = smctr_trc_send_packet(dev, fcb, MAC_QUEUE)))
- return (err);
+ return err;
/* Wait for Transmit to Complete */
for(i = 0; i < 10000; i++)
@@ -5020,7 +5022,7 @@ static int smctr_send_tx_forward(struct net_device *dev, MAC_HEADER *rmf,
if(!(fcb->frame_status & FCB_COMMAND_DONE))
{
if((err = smctr_issue_resume_tx_fcb_cmd(dev, MAC_QUEUE)))
- return (err);
+ return err;
for(i = 0; i < 10000; i++)
{
@@ -5030,12 +5032,12 @@ static int smctr_send_tx_forward(struct net_device *dev, MAC_HEADER *rmf,
}
if(!(fcb->frame_status & FCB_COMMAND_DONE))
- return (HARDWARE_FAILED);
+ return HARDWARE_FAILED;
}
*tx_fstatus = fcb->frame_status;
- return (A_FRAME_WAS_FORWARDED);
+ return A_FRAME_WAS_FORWARDED;
}
static int smctr_set_auth_access_pri(struct net_device *dev,
@@ -5044,11 +5046,11 @@ static int smctr_set_auth_access_pri(struct net_device *dev,
struct net_local *tp = netdev_priv(dev);
if(rsv->svl != S_AUTHORIZED_ACCESS_PRIORITY)
- return (E_SUB_VECTOR_LENGTH_ERROR);
+ return E_SUB_VECTOR_LENGTH_ERROR;
tp->authorized_access_priority = (rsv->svv[0] << 8 | rsv->svv[1]);
- return (POSITIVE_ACK);
+ return POSITIVE_ACK;
}
static int smctr_set_auth_funct_class(struct net_device *dev,
@@ -5057,22 +5059,22 @@ static int smctr_set_auth_funct_class(struct net_device *dev,
struct net_local *tp = netdev_priv(dev);
if(rsv->svl != S_AUTHORIZED_FUNCTION_CLASS)
- return (E_SUB_VECTOR_LENGTH_ERROR);
+ return E_SUB_VECTOR_LENGTH_ERROR;
tp->authorized_function_classes = (rsv->svv[0] << 8 | rsv->svv[1]);
- return (POSITIVE_ACK);
+ return POSITIVE_ACK;
}
static int smctr_set_corr(struct net_device *dev, MAC_SUB_VECTOR *rsv,
__u16 *correlator)
{
if(rsv->svl != S_CORRELATOR)
- return (E_SUB_VECTOR_LENGTH_ERROR);
+ return E_SUB_VECTOR_LENGTH_ERROR;
*correlator = (rsv->svv[0] << 8 | rsv->svv[1]);
- return (POSITIVE_ACK);
+ return POSITIVE_ACK;
}
static int smctr_set_error_timer_value(struct net_device *dev,
@@ -5082,34 +5084,34 @@ static int smctr_set_error_timer_value(struct net_device *dev,
int err;
if(rsv->svl != S_ERROR_TIMER_VALUE)
- return (E_SUB_VECTOR_LENGTH_ERROR);
+ return E_SUB_VECTOR_LENGTH_ERROR;
err_tval = (rsv->svv[0] << 8 | rsv->svv[1])*10;
smctr_issue_write_word_cmd(dev, RW_TER_THRESHOLD, &err_tval);
if((err = smctr_wait_cmd(dev)))
- return (err);
+ return err;
- return (POSITIVE_ACK);
+ return POSITIVE_ACK;
}
static int smctr_set_frame_forward(struct net_device *dev,
MAC_SUB_VECTOR *rsv, __u8 dc_sc)
{
if((rsv->svl < 2) || (rsv->svl > S_FRAME_FORWARD))
- return (E_SUB_VECTOR_LENGTH_ERROR);
+ return E_SUB_VECTOR_LENGTH_ERROR;
if((dc_sc & DC_MASK) != DC_CRS)
{
if(rsv->svl >= 2 && rsv->svl < 20)
- return (E_TRANSMIT_FORWARD_INVALID);
+ return E_TRANSMIT_FORWARD_INVALID;
if((rsv->svv[0] != 0) || (rsv->svv[1] != 0))
- return (E_TRANSMIT_FORWARD_INVALID);
+ return E_TRANSMIT_FORWARD_INVALID;
}
- return (POSITIVE_ACK);
+ return POSITIVE_ACK;
}
static int smctr_set_local_ring_num(struct net_device *dev,
@@ -5118,13 +5120,13 @@ static int smctr_set_local_ring_num(struct net_device *dev,
struct net_local *tp = netdev_priv(dev);
if(rsv->svl != S_LOCAL_RING_NUMBER)
- return (E_SUB_VECTOR_LENGTH_ERROR);
+ return E_SUB_VECTOR_LENGTH_ERROR;
if(tp->ptr_local_ring_num)
*(__u16 *)(tp->ptr_local_ring_num)
= (rsv->svv[0] << 8 | rsv->svv[1]);
- return (POSITIVE_ACK);
+ return POSITIVE_ACK;
}
static unsigned short smctr_set_ctrl_attention(struct net_device *dev)
@@ -5140,7 +5142,7 @@ static unsigned short smctr_set_ctrl_attention(struct net_device *dev)
outb(tp->trc_mask, ioaddr + CSR);
}
- return (0);
+ return 0;
}
static void smctr_set_multicast_list(struct net_device *dev)
@@ -5159,7 +5161,7 @@ static int smctr_set_page(struct net_device *dev, __u8 *buf)
amask = (__u8)((tptr & PR_PAGE_MASK) >> 8);
outb(amask, dev->base_addr + PR);
- return (0);
+ return 0;
}
static int smctr_set_phy_drop(struct net_device *dev, MAC_SUB_VECTOR *rsv)
@@ -5167,13 +5169,13 @@ static int smctr_set_phy_drop(struct net_device *dev, MAC_SUB_VECTOR *rsv)
int err;
if(rsv->svl != S_PHYSICAL_DROP)
- return (E_SUB_VECTOR_LENGTH_ERROR);
+ return E_SUB_VECTOR_LENGTH_ERROR;
smctr_issue_write_byte_cmd(dev, RW_PHYSICAL_DROP_NUMBER, &rsv->svv[0]);
if((err = smctr_wait_cmd(dev)))
- return (err);
+ return err;
- return (POSITIVE_ACK);
+ return POSITIVE_ACK;
}
/* Reset the ring speed to the opposite of what it was. This auto-pilot
@@ -5195,16 +5197,16 @@ static int smctr_set_ring_speed(struct net_device *dev)
smctr_reset_adapter(dev);
if((err = smctr_init_card_real(dev)))
- return (err);
+ return err;
smctr_enable_bic_int(dev);
if((err = smctr_issue_enable_int_cmd(dev, TRC_INTERRUPT_ENABLE_MASK)))
- return (err);
+ return err;
smctr_disable_16bit(dev);
- return (0);
+ return 0;
}
static int smctr_set_rx_look_ahead(struct net_device *dev)
@@ -5233,7 +5235,7 @@ static int smctr_set_rx_look_ahead(struct net_device *dev)
*((__u16 *)(tp->ram_access)) = sword;
}
- return (0);
+ return 0;
}
static int smctr_set_trc_reset(int ioaddr)
@@ -5243,7 +5245,7 @@ static int smctr_set_trc_reset(int ioaddr)
r = inb(ioaddr + MSR);
outb(MSR_RST | r, ioaddr + MSR);
- return (0);
+ return 0;
}
/*
@@ -5259,10 +5261,10 @@ static int smctr_setup_single_cmd(struct net_device *dev,
printk(KERN_DEBUG "%s: smctr_setup_single_cmd\n", dev->name);
if((err = smctr_wait_while_cbusy(dev)))
- return (err);
+ return err;
if((err = (unsigned int)smctr_wait_cmd(dev)))
- return (err);
+ return err;
tp->acb_head->cmd_done_status = 0;
tp->acb_head->cmd = command;
@@ -5270,7 +5272,7 @@ static int smctr_setup_single_cmd(struct net_device *dev,
err = smctr_issue_resume_acb_cmd(dev);
- return (err);
+ return err;
}
/*
@@ -5287,7 +5289,7 @@ static int smctr_setup_single_cmd_w_data(struct net_device *dev,
tp->acb_head->data_offset_lo
= (__u16)TRC_POINTER(tp->misc_command_data);
- return(smctr_issue_resume_acb_cmd(dev));
+ return smctr_issue_resume_acb_cmd(dev);
}
static char *smctr_malloc(struct net_device *dev, __u16 size)
@@ -5298,7 +5300,7 @@ static char *smctr_malloc(struct net_device *dev, __u16 size)
m = (char *)(tp->ram_access + tp->sh_mem_used);
tp->sh_mem_used += (__u32)size;
- return (m);
+ return m;
}
static int smctr_status_chg(struct net_device *dev)
@@ -5333,7 +5335,7 @@ static int smctr_status_chg(struct net_device *dev)
break;
}
- return (0);
+ return 0;
}
static int smctr_trc_send_packet(struct net_device *dev, FCBlock *fcb,
@@ -5355,7 +5357,7 @@ static int smctr_trc_send_packet(struct net_device *dev, FCBlock *fcb,
err = smctr_issue_resume_tx_fcb_cmd(dev, queue);
}
- return (err);
+ return err;
}
static __u16 smctr_tx_complete(struct net_device *dev, __u16 queue)
@@ -5409,7 +5411,7 @@ static __u16 smctr_tx_complete(struct net_device *dev, __u16 queue)
break;
}
- return (err);
+ return err;
}
static unsigned short smctr_tx_move_frame(struct net_device *dev,
@@ -5450,7 +5452,7 @@ static unsigned short smctr_tx_move_frame(struct net_device *dev,
pbuff += len;
}
- return (0);
+ return 0;
}
/* Update the error statistic counters for this adapter. */
@@ -5493,7 +5495,7 @@ static int smctr_update_err_stats(struct net_device *dev)
if(tstat->token_errors)
tstat->token_errors += *(tp->misc_command_data + 5) >> 8;
- return (0);
+ return 0;
}
static int smctr_update_rx_chain(struct net_device *dev, __u16 queue)
@@ -5530,7 +5532,7 @@ static int smctr_update_rx_chain(struct net_device *dev, __u16 queue)
tp->rx_bdb_curr[queue]->back_ptr->info = BDB_NOT_CHAIN_END;
tp->rx_bdb_curr[queue] = bdb;
- return (0);
+ return 0;
}
static int smctr_update_tx_chain(struct net_device *dev, FCBlock *fcb,
@@ -5542,13 +5544,13 @@ static int smctr_update_tx_chain(struct net_device *dev, FCBlock *fcb,
printk(KERN_DEBUG "smctr_update_tx_chain\n");
if(tp->num_tx_fcbs_used[queue] <= 0)
- return (HARDWARE_FAILED);
+ return HARDWARE_FAILED;
else
{
if(tp->tx_buff_used[queue] < fcb->memory_alloc)
{
tp->tx_buff_used[queue] = 0;
- return (HARDWARE_FAILED);
+ return HARDWARE_FAILED;
}
tp->tx_buff_used[queue] -= fcb->memory_alloc;
@@ -5566,7 +5568,7 @@ static int smctr_update_tx_chain(struct net_device *dev, FCBlock *fcb,
fcb->frame_status = 0;
tp->tx_fcb_end[queue] = fcb->next_ptr;
netif_wake_queue(dev);
- return (0);
+ return 0;
}
}
@@ -5587,12 +5589,12 @@ static int smctr_wait_cmd(struct net_device *dev)
}
if(loop_count == 0)
- return(HARDWARE_FAILED);
+ return HARDWARE_FAILED;
if(tp->acb_head->cmd_done_status & 0xff)
- return(HARDWARE_FAILED);
+ return HARDWARE_FAILED;
- return (0);
+ return 0;
}
static int smctr_wait_while_cbusy(struct net_device *dev)
@@ -5624,9 +5626,9 @@ static int smctr_wait_while_cbusy(struct net_device *dev)
}
if(timeout)
- return (0);
+ return 0;
else
- return (HARDWARE_FAILED);
+ return HARDWARE_FAILED;
}
#ifdef MODULE
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index 435ef7d5470f..793020347e54 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -5,7 +5,7 @@
* Originally sktr.c: Written 1997 by Christoph Goos
*
* A fine result of the Linux Systems Network Architecture Project.
- * http://www.linux-sna.org
+ * http://www.vanheusden.com/sna/
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
@@ -224,7 +224,7 @@ static int madgemc_sifprobe(struct net_device *dev)
chk2 ^= 0x0FE;
if(chk1 != chk2)
- return (-1); /* No adapter */
+ return -1; /* No adapter */
chk1 -= 2;
} while(chk1 != 0); /* Repeat 128 times (all byte values) */
@@ -232,7 +232,7 @@ static int madgemc_sifprobe(struct net_device *dev)
/* Restore the SIFADR value */
SIFWRITEB(old, SIFADR);
- return (0);
+ return 0;
}
#endif
@@ -271,7 +271,7 @@ int tms380tr_open(struct net_device *dev)
{
printk(KERN_INFO "%s: Chipset initialization error\n",
dev->name);
- return (-1);
+ return -1;
}
tp->timer.expires = jiffies + 30*HZ;
@@ -298,7 +298,7 @@ int tms380tr_open(struct net_device *dev)
if(tp->AdapterVirtOpenFlag == 0)
{
tms380tr_disable_interrupts(dev);
- return (-1);
+ return -1;
}
tp->StartTime = jiffies;
@@ -309,7 +309,7 @@ int tms380tr_open(struct net_device *dev)
tp->timer.data = (unsigned long)dev;
add_timer(&tp->timer);
- return (0);
+ return 0;
}
/*
@@ -343,23 +343,23 @@ static int tms380tr_chipset_init(struct net_device *dev)
printk(KERN_DEBUG "%s: Resetting adapter...\n", dev->name);
err = tms380tr_reset_adapter(dev);
if(err < 0)
- return (-1);
+ return -1;
if(tms380tr_debug > 3)
printk(KERN_DEBUG "%s: Bringup diags...\n", dev->name);
err = tms380tr_bringup_diags(dev);
if(err < 0)
- return (-1);
+ return -1;
if(tms380tr_debug > 3)
printk(KERN_DEBUG "%s: Init adapter...\n", dev->name);
err = tms380tr_init_adapter(dev);
if(err < 0)
- return (-1);
+ return -1;
if(tms380tr_debug > 3)
printk(KERN_DEBUG "%s: Done!\n", dev->name);
- return (0);
+ return 0;
}
/*
@@ -877,7 +877,7 @@ static unsigned char tms380tr_chk_ssb(struct net_local *tp, unsigned short IrqTy
IrqType != STS_IRQ_COMMAND_STATUS &&
IrqType != STS_IRQ_RING_STATUS)
{
- return (1); /* SSB not involved. */
+ return 1; /* SSB not involved. */
}
/* Note: All fields of the SSB have been set to all ones (-1) after it
@@ -887,21 +887,21 @@ static unsigned char tms380tr_chk_ssb(struct net_local *tp, unsigned short IrqTy
*/
if(ssb->STS == (unsigned short) -1)
- return (0); /* Command field not yet available. */
+ return 0; /* Command field not yet available. */
if(IrqType == STS_IRQ_COMMAND_STATUS)
- return (1); /* Status fields not always affected. */
+ return 1; /* Status fields not always affected. */
if(ssb->Parm[0] == (unsigned short) -1)
- return (0); /* Status 1 field not yet available. */
+ return 0; /* Status 1 field not yet available. */
if(IrqType == STS_IRQ_RING_STATUS)
- return (1); /* Status 2 & 3 fields not affected. */
+ return 1; /* Status 2 & 3 fields not affected. */
/* Note: At this point, the interrupt is either TRANSMIT or RECEIVE. */
if(ssb->Parm[1] == (unsigned short) -1)
- return (0); /* Status 2 field not yet available. */
+ return 0; /* Status 2 field not yet available. */
if(ssb->Parm[2] == (unsigned short) -1)
- return (0); /* Status 3 field not yet available. */
+ return 0; /* Status 3 field not yet available. */
- return (1); /* All SSB fields have been written by the adapter. */
+ return 1; /* All SSB fields have been written by the adapter. */
}
/*
@@ -1143,7 +1143,7 @@ int tms380tr_close(struct net_device *dev)
#endif
tms380tr_cancel_tx_queue(tp);
- return (0);
+ return 0;
}
/*
@@ -1154,7 +1154,7 @@ static struct net_device_stats *tms380tr_get_stats(struct net_device *dev)
{
struct net_local *tp = netdev_priv(dev);
- return ((struct net_device_stats *)&tp->MacStat);
+ return (struct net_device_stats *)&tp->MacStat;
}
/*
@@ -1220,7 +1220,7 @@ void tms380tr_wait(unsigned long time)
tmp = schedule_timeout_interruptible(tmp);
} while(time_after(tmp, jiffies));
#else
- udelay(time);
+ mdelay(time / 1000);
#endif
}
@@ -1256,7 +1256,7 @@ static int tms380tr_reset_adapter(struct net_device *dev)
if (request_firmware(&fw_entry, "tms380tr.bin", tp->pdev) != 0) {
printk(KERN_ALERT "%s: firmware %s is missing, cannot start.\n",
dev->name, "tms380tr.bin");
- return (-1);
+ return -1;
}
fw_ptr = (unsigned short *)fw_entry->data;
@@ -1321,16 +1321,14 @@ static int tms380tr_reset_adapter(struct net_device *dev)
/* Clear CPHALT and start BUD */
SIFWRITEW(c, SIFACL);
- if (fw_entry)
- release_firmware(fw_entry);
- return (1);
+ release_firmware(fw_entry);
+ return 1;
}
} while(count == 0);
- if (fw_entry)
- release_firmware(fw_entry);
+ release_firmware(fw_entry);
printk(KERN_INFO "%s: Adapter Download Failed\n", dev->name);
- return (-1);
+ return -1;
}
MODULE_FIRMWARE("tms380tr.bin");
@@ -1365,7 +1363,7 @@ static int tms380tr_bringup_diags(struct net_device *dev)
printk(KERN_DEBUG " %04X\n", Status);
/* BUD successfully completed */
if(Status == STS_INITIALIZE)
- return (1);
+ return 1;
/* Unrecoverable hardware error, BUD not completed? */
} while((loop_cnt > 0) && ((Status & (STS_ERROR | STS_TEST))
!= (STS_ERROR | STS_TEST)));
@@ -1392,7 +1390,7 @@ static int tms380tr_bringup_diags(struct net_device *dev)
else
printk(KERN_INFO "%s: Bring Up Diagnostics Error (%04X) occurred\n", dev->name, Status & 0x000f);
- return (-1);
+ return -1;
}
/*
@@ -1466,7 +1464,7 @@ static int tms380tr_init_adapter(struct net_device *dev)
{
printk(KERN_INFO "%s: DMA failed\n", dev->name);
/* DMA data error: wrong data in SCB */
- return (-1);
+ return -1;
}
i++;
} while(i < 6);
@@ -1475,11 +1473,11 @@ static int tms380tr_init_adapter(struct net_device *dev)
do { /* Test if contents of SSB is valid */
if(SSB_Test[i] != *(sb_ptr + i))
/* DMA data error: wrong data in SSB */
- return (-1);
+ return -1;
i++;
} while (i < 8);
- return (1); /* Adapter successfully initialized */
+ return 1; /* Adapter successfully initialized */
}
else
{
@@ -1490,7 +1488,7 @@ static int tms380tr_init_adapter(struct net_device *dev)
Status &= STS_ERROR_MASK;
/* ShowInitialisationErrorCode(Status); */
printk(KERN_INFO "%s: Status error: %d\n", dev->name, Status);
- return (-1); /* Unrecoverable error */
+ return -1; /* Unrecoverable error */
}
else
{
@@ -1505,7 +1503,7 @@ static int tms380tr_init_adapter(struct net_device *dev)
} while(retry_cnt > 0);
printk(KERN_INFO "%s: Retry exceeded\n", dev->name);
- return (-1);
+ return -1;
}
/*
diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c
index d4c7c0c0a3d6..d3e788a9cd1c 100644
--- a/drivers/net/tokenring/tmspci.c
+++ b/drivers/net/tokenring/tmspci.c
@@ -125,18 +125,16 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
dev->irq = pci_irq_line;
dev->dma = 0;
- printk("%s: %s\n", dev->name, cardinfo->name);
- printk("%s: IO: %#4lx IRQ: %d\n",
- dev->name, dev->base_addr, dev->irq);
+ dev_info(&pdev->dev, "%s\n", cardinfo->name);
+ dev_info(&pdev->dev, " IO: %#4lx IRQ: %d\n", dev->base_addr, dev->irq);
tms_pci_read_eeprom(dev);
- printk("%s: Ring Station Address: %pM\n",
- dev->name, dev->dev_addr);
+ dev_info(&pdev->dev, " Ring Station Address: %pM\n", dev->dev_addr);
ret = tmsdev_init(dev, &pdev->dev);
if (ret) {
- printk("%s: unable to get memory for dev->priv.\n", dev->name);
+ dev_info(&pdev->dev, "unable to get memory for dev->priv.\n");
goto err_out_region;
}
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index a03730bd1da5..5c633a32eaeb 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -219,7 +219,7 @@ static int tsi108_read_mii(struct tsi108_prv_data *data, int reg)
if (i == 100)
return 0xffff;
else
- return (TSI_READ_PHY(TSI108_MAC_MII_DATAIN));
+ return TSI_READ_PHY(TSI108_MAC_MII_DATAIN);
}
static void tsi108_write_mii(struct tsi108_prv_data *data,
diff --git a/drivers/net/tulip/Kconfig b/drivers/net/tulip/Kconfig
index 516713fa0a05..1f8d4a8d8ea4 100644
--- a/drivers/net/tulip/Kconfig
+++ b/drivers/net/tulip/Kconfig
@@ -11,8 +11,8 @@ menuconfig NET_TULIP
if NET_TULIP
config DE2104X
- tristate "Early DECchip Tulip (dc2104x) PCI support (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ tristate "Early DECchip Tulip (dc2104x) PCI support"
+ depends on PCI
select CRC32
---help---
This driver is developed for the SMC EtherPower series Ethernet
@@ -151,7 +151,7 @@ config ULI526X
select CRC32
---help---
This driver is for ULi M5261/M5263 10/100M Ethernet Controller
- (<http://www.uli.com.tw/>).
+ (<http://www.nvidia.com/page/uli_drivers.html>).
To compile this driver as a module, choose M here. The module will
be called uli526x.
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index 6888e3d41462..28e1ffb13db9 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -948,8 +948,9 @@ static void de_set_media (struct de_private *de)
else
macmode &= ~FullDuplex;
- if (netif_msg_link(de)) {
+ if (netif_msg_link(de))
dev_info(&de->dev->dev, "set link %s\n", media_name[media]);
+ if (netif_msg_hw(de)) {
dev_info(&de->dev->dev, "mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n",
dr32(MacMode), dr32(SIAStatus),
dr32(CSR13), dr32(CSR14), dr32(CSR15));
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 75a64c88cf7a..4dbd493b996b 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -1448,7 +1448,7 @@ de4x5_sw_reset(struct net_device *dev)
status = -EIO;
}
- lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+ lp->tx_new = (lp->tx_new + 1) % lp->txRingSize;
lp->tx_old = lp->tx_new;
return status;
@@ -1506,7 +1506,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
lp->stats.tx_bytes += skb->len;
outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */
- lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+ lp->tx_new = (lp->tx_new + 1) % lp->txRingSize;
if (TX_BUFFS_AVAIL) {
netif_start_queue(dev); /* Another pkt may be queued */
@@ -1657,7 +1657,7 @@ de4x5_rx(struct net_device *dev)
}
/* Change buffer ownership for this frame, back to the adapter */
- for (;lp->rx_old!=entry;lp->rx_old=(++lp->rx_old)%lp->rxRingSize) {
+ for (;lp->rx_old!=entry;lp->rx_old=(lp->rx_old + 1)%lp->rxRingSize) {
lp->rx_ring[lp->rx_old].status = cpu_to_le32(R_OWN);
barrier();
}
@@ -1668,7 +1668,7 @@ de4x5_rx(struct net_device *dev)
/*
** Update entry information
*/
- lp->rx_new = (++lp->rx_new) % lp->rxRingSize;
+ lp->rx_new = (lp->rx_new + 1) % lp->rxRingSize;
}
return 0;
@@ -1726,7 +1726,7 @@ de4x5_tx(struct net_device *dev)
}
/* Update all the pointers */
- lp->tx_old = (++lp->tx_old) % lp->txRingSize;
+ lp->tx_old = (lp->tx_old + 1) % lp->txRingSize;
}
/* Any resources available? */
@@ -1801,7 +1801,7 @@ de4x5_rx_ovfc(struct net_device *dev)
for (; (s32)le32_to_cpu(lp->rx_ring[lp->rx_new].status)>=0;) {
lp->rx_ring[lp->rx_new].status = cpu_to_le32(R_OWN);
- lp->rx_new = (++lp->rx_new % lp->rxRingSize);
+ lp->rx_new = (lp->rx_new + 1) % lp->rxRingSize;
}
outl(omr, DE4X5_OMR);
@@ -1932,7 +1932,7 @@ set_multicast_list(struct net_device *dev)
load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
SETUP_FRAME_LEN, (struct sk_buff *)1);
- lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+ lp->tx_new = (lp->tx_new + 1) % lp->txRingSize;
outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
dev->trans_start = jiffies; /* prevent tx timeout */
}
@@ -3119,7 +3119,7 @@ dc2114x_autoconf(struct net_device *dev)
if (lp->media == _100Mb) {
if ((slnk = test_for_100Mb(dev, 6500)) < 0) {
lp->media = SPD_DET;
- return (slnk & ~TIMER_CB);
+ return slnk & ~TIMER_CB;
}
} else {
if (wait_for_link(dev) < 0) {
@@ -3484,7 +3484,7 @@ is_spd_100(struct net_device *dev)
spd = ((~gep_rd(dev)) & GEP_SLNK);
} else {
if ((lp->ibn == 2) || !lp->asBitValid)
- return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0);
+ return (lp->chipset == DC21143) ? (~inl(DE4X5_SISR)&SISR_LS100) : 0;
spd = (lp->asBitValid & (lp->asPolarity ^ (gep_rd(dev) & lp->asBit))) |
(lp->linkOK & ~lp->asBitValid);
@@ -3502,15 +3502,15 @@ is_100_up(struct net_device *dev)
if (lp->useMII) {
/* Double read for sticky bits & temporary drops */
mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
- return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
+ return mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS;
} else if (!lp->useSROM) { /* de500-xa */
- return ((~gep_rd(dev)) & GEP_SLNK);
+ return (~gep_rd(dev)) & GEP_SLNK;
} else {
if ((lp->ibn == 2) || !lp->asBitValid)
- return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0);
+ return (lp->chipset == DC21143) ? (~inl(DE4X5_SISR)&SISR_LS100) : 0;
- return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
- (lp->linkOK & ~lp->asBitValid));
+ return (lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
+ (lp->linkOK & ~lp->asBitValid);
}
}
@@ -3523,17 +3523,17 @@ is_10_up(struct net_device *dev)
if (lp->useMII) {
/* Double read for sticky bits & temporary drops */
mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
- return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
+ return mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS;
} else if (!lp->useSROM) { /* de500-xa */
- return ((~gep_rd(dev)) & GEP_LNP);
+ return (~gep_rd(dev)) & GEP_LNP;
} else {
if ((lp->ibn == 2) || !lp->asBitValid)
- return (((lp->chipset & ~0x00ff) == DC2114x) ?
+ return ((lp->chipset & ~0x00ff) == DC2114x) ?
(~inl(DE4X5_SISR)&SISR_LS10):
- 0);
+ 0;
- return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
- (lp->linkOK & ~lp->asBitValid));
+ return (lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
+ (lp->linkOK & ~lp->asBitValid);
}
}
@@ -3544,7 +3544,7 @@ is_anc_capable(struct net_device *dev)
u_long iobase = dev->base_addr;
if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
- return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII));
+ return mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
} else if ((lp->chipset & ~0x00ff) == DC2114x) {
return (inl(DE4X5_SISR) & SISR_LPN) >> 12;
} else {
@@ -3568,7 +3568,7 @@ ping_media(struct net_device *dev, int msec)
lp->tmp = lp->tx_new; /* Remember the ring position */
load_packet(dev, lp->frame, TD_LS | TD_FS | sizeof(lp->frame), (struct sk_buff *)1);
- lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+ lp->tx_new = (lp->tx_new + 1) % lp->txRingSize;
outl(POLL_DEMAND, DE4X5_TPD);
}
@@ -4930,7 +4930,7 @@ getfrom_mii(u32 command, u_long ioaddr)
outl(command | MII_MDC, ioaddr);
udelay(1);
- return ((inl(ioaddr) >> 19) & 1);
+ return (inl(ioaddr) >> 19) & 1;
}
/*
@@ -4975,8 +4975,8 @@ mii_get_oui(u_char phyaddr, u_long ioaddr)
a.breg[0]=a.breg[1];
a.breg[1]=i;
- return ((a.reg<<8)|ret); */ /* SEEQ and Cypress way */
-/* return ((r2<<6)|(u_int)(r3>>10)); */ /* NATIONAL and BROADCOM way */
+ return (a.reg<<8)|ret; */ /* SEEQ and Cypress way */
+/* return (r2<<6)|(u_int)(r3>>10); */ /* NATIONAL and BROADCOM way */
return r2; /* (I did it) My way */
}
@@ -5144,7 +5144,7 @@ gep_rd(struct net_device *dev)
if (lp->chipset == DC21140) {
return inl(DE4X5_GEP);
} else if ((lp->chipset & ~0x00ff) == DC2114x) {
- return (inl(DE4X5_SIGR) & 0x000fffff);
+ return inl(DE4X5_SIGR) & 0x000fffff;
}
return 0;
@@ -5417,7 +5417,7 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
/* Set up the descriptor and give ownership to the card */
load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
SETUP_FRAME_LEN, (struct sk_buff *)1);
- lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+ lp->tx_new = (lp->tx_new + 1) % lp->txRingSize;
outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
netif_wake_queue(dev); /* Unlock the TX ring */
break;
@@ -5474,7 +5474,8 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
tmp.lval[6] = inl(DE4X5_STRR); j+=4;
tmp.lval[7] = inl(DE4X5_SIGR); j+=4;
ioc->len = j;
- if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT;
+ if (copy_to_user(ioc->data, tmp.lval, ioc->len))
+ return -EFAULT;
break;
#define DE4X5_DUMP 0x0f /* Dump the DE4X5 Status */
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index 0bc4f3030a80..a9f7d5d1a269 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -599,7 +599,7 @@ static int dmfe_open(struct DEVICE *dev)
init_timer(&db->timer);
db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
db->timer.data = (unsigned long)dev;
- db->timer.function = &dmfe_timer;
+ db->timer.function = dmfe_timer;
add_timer(&db->timer);
return 0;
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index 1faf7a4d7202..0013642903ee 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -180,21 +180,24 @@ int tulip_poll(struct napi_struct *napi, int budget)
dev_warn(&dev->dev,
"Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
status);
- tp->stats.rx_length_errors++;
- }
+ dev->stats.rx_length_errors++;
+ }
} else {
/* There was a fatal error. */
if (tulip_debug > 2)
printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n",
dev->name, status);
- tp->stats.rx_errors++; /* end of a packet.*/
- if (pkt_len > 1518 ||
- (status & RxDescRunt))
- tp->stats.rx_length_errors++;
-
- if (status & 0x0004) tp->stats.rx_frame_errors++;
- if (status & 0x0002) tp->stats.rx_crc_errors++;
- if (status & 0x0001) tp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++; /* end of a packet.*/
+ if (pkt_len > 1518 ||
+ (status & RxDescRunt))
+ dev->stats.rx_length_errors++;
+
+ if (status & 0x0004)
+ dev->stats.rx_frame_errors++;
+ if (status & 0x0002)
+ dev->stats.rx_crc_errors++;
+ if (status & 0x0001)
+ dev->stats.rx_fifo_errors++;
}
} else {
struct sk_buff *skb;
@@ -244,8 +247,8 @@ int tulip_poll(struct napi_struct *napi, int budget)
netif_receive_skb(skb);
- tp->stats.rx_packets++;
- tp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
received++;
@@ -404,20 +407,23 @@ static int tulip_rx(struct net_device *dev)
dev_warn(&dev->dev,
"Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
status);
- tp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
} else {
/* There was a fatal error. */
if (tulip_debug > 2)
printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n",
dev->name, status);
- tp->stats.rx_errors++; /* end of a packet.*/
+ dev->stats.rx_errors++; /* end of a packet.*/
if (pkt_len > 1518 ||
(status & RxDescRunt))
- tp->stats.rx_length_errors++;
- if (status & 0x0004) tp->stats.rx_frame_errors++;
- if (status & 0x0002) tp->stats.rx_crc_errors++;
- if (status & 0x0001) tp->stats.rx_fifo_errors++;
+ dev->stats.rx_length_errors++;
+ if (status & 0x0004)
+ dev->stats.rx_frame_errors++;
+ if (status & 0x0002)
+ dev->stats.rx_crc_errors++;
+ if (status & 0x0001)
+ dev->stats.rx_fifo_errors++;
}
} else {
struct sk_buff *skb;
@@ -467,8 +473,8 @@ static int tulip_rx(struct net_device *dev)
netif_rx(skb);
- tp->stats.rx_packets++;
- tp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
received++;
entry = (++tp->cur_rx) % RX_RING_SIZE;
@@ -602,18 +608,22 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
printk(KERN_DEBUG "%s: Transmit error, Tx status %08x\n",
dev->name, status);
#endif
- tp->stats.tx_errors++;
- if (status & 0x4104) tp->stats.tx_aborted_errors++;
- if (status & 0x0C00) tp->stats.tx_carrier_errors++;
- if (status & 0x0200) tp->stats.tx_window_errors++;
- if (status & 0x0002) tp->stats.tx_fifo_errors++;
+ dev->stats.tx_errors++;
+ if (status & 0x4104)
+ dev->stats.tx_aborted_errors++;
+ if (status & 0x0C00)
+ dev->stats.tx_carrier_errors++;
+ if (status & 0x0200)
+ dev->stats.tx_window_errors++;
+ if (status & 0x0002)
+ dev->stats.tx_fifo_errors++;
if ((status & 0x0080) && tp->full_duplex == 0)
- tp->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
} else {
- tp->stats.tx_bytes +=
+ dev->stats.tx_bytes +=
tp->tx_buffers[entry].skb->len;
- tp->stats.collisions += (status >> 3) & 15;
- tp->stats.tx_packets++;
+ dev->stats.collisions += (status >> 3) & 15;
+ dev->stats.tx_packets++;
}
pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping,
@@ -655,7 +665,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */
if (csr5 == 0xffffffff)
break;
- if (csr5 & TxJabber) tp->stats.tx_errors++;
+ if (csr5 & TxJabber)
+ dev->stats.tx_errors++;
if (csr5 & TxFIFOUnderflow) {
if ((tp->csr6 & 0xC000) != 0xC000)
tp->csr6 += 0x4000; /* Bump up the Tx threshold */
@@ -672,8 +683,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
}
}
if (csr5 & RxDied) { /* Missed a Rx frame. */
- tp->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff;
- tp->stats.rx_errors++;
+ dev->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff;
+ dev->stats.rx_errors++;
tulip_start_rxtx(tp);
}
/*
@@ -789,7 +800,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
#endif /* CONFIG_TULIP_NAPI */
if ((missed = ioread32(ioaddr + CSR8) & 0x1ffff)) {
- tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
+ dev->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
}
if (tulip_debug > 4)
diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c
index b8197666021e..4690c8e69207 100644
--- a/drivers/net/tulip/pnic2.c
+++ b/drivers/net/tulip/pnic2.c
@@ -59,7 +59,7 @@
* Bit 14:12 - autonegotiation state (write 001 to start autonegotiate)
* Bit 3 - Autopolarity state
* Bit 2 - LS10B - link state of 10baseT 0 - good, 1 - failed
- * Bit 1 - LS100B - link state of 100baseT 0 - good, 1- faild
+ * Bit 1 - LS100B - link state of 100baseT 0 - good, 1 - failed
*
*
* Data Port Selection Info
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index e525875ed67d..ed66a16711dc 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -417,7 +417,6 @@ struct tulip_private {
int revision;
int flags;
struct napi_struct napi;
- struct net_device_stats stats;
struct timer_list timer; /* Media selection timer. */
struct timer_list oom_timer; /* Out of memory timer. */
u32 mc_filter[2];
@@ -570,7 +569,7 @@ static inline void tulip_tx_timeout_complete(struct tulip_private *tp, void __io
/* Trigger an immediate transmit demand. */
iowrite32(0, ioaddr + CSR1);
- tp->stats.tx_errors++;
+ tp->dev->stats.tx_errors++;
}
#endif /* __NET_TULIP_H__ */
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 3a8d7efa2acf..2c39f2591216 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -725,7 +725,7 @@ static void tulip_clean_tx_ring(struct tulip_private *tp)
int status = le32_to_cpu(tp->tx_ring[entry].status);
if (status < 0) {
- tp->stats.tx_errors++; /* It wasn't Txed */
+ tp->dev->stats.tx_errors++; /* It wasn't Txed */
tp->tx_ring[entry].status = 0;
}
@@ -781,8 +781,8 @@ static void tulip_down (struct net_device *dev)
/* release any unconsumed transmit buffers */
tulip_clean_tx_ring(tp);
- if (ioread32 (ioaddr + CSR6) != 0xffffffff)
- tp->stats.rx_missed_errors += ioread32 (ioaddr + CSR8) & 0xffff;
+ if (ioread32(ioaddr + CSR6) != 0xffffffff)
+ dev->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff;
spin_unlock_irqrestore (&tp->lock, flags);
@@ -864,12 +864,12 @@ static struct net_device_stats *tulip_get_stats(struct net_device *dev)
spin_lock_irqsave (&tp->lock, flags);
- tp->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff;
+ dev->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff;
spin_unlock_irqrestore(&tp->lock, flags);
}
- return &tp->stats;
+ return &dev->stats;
}
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index 96de5829b940..74217dbf0143 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -480,7 +480,7 @@ static int uli526x_open(struct net_device *dev)
init_timer(&db->timer);
db->timer.expires = ULI526X_TIMER_WUT + HZ * 2;
db->timer.data = (unsigned long)dev;
- db->timer.function = &uli526x_timer;
+ db->timer.function = uli526x_timer;
add_timer(&db->timer);
return 0;
@@ -1747,7 +1747,7 @@ static u16 phy_readby_cr10(unsigned long iobase, u8 phy_addr, u8 offset)
if(cr10_value&0x10000000)
break;
}
- return (cr10_value&0x0ffff);
+ return cr10_value & 0x0ffff;
}
static void phy_writeby_cr10(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data)
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 66d41cf8da29..f0b231035dee 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -662,7 +662,7 @@ static int netdev_open(struct net_device *dev)
init_timer(&np->timer);
np->timer.expires = jiffies + 1*HZ;
np->timer.data = (unsigned long)dev;
- np->timer.function = &netdev_timer; /* timer handler */
+ np->timer.function = netdev_timer; /* timer handler */
add_timer(&np->timer);
return 0;
out_err:
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index a439e93be22d..5a73752be2ca 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -29,7 +29,6 @@
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/init.h>
-#include <linux/ethtool.h>
#include <linux/bitops.h>
#include <asm/uaccess.h>
@@ -181,19 +180,6 @@ static void print_binary(unsigned int number)
}
#endif
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- struct xircom_private *private = netdev_priv(dev);
-
- strcpy(info->driver, "xircom_cb");
- strcpy(info->bus_info, pci_name(private->pdev));
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
-};
-
static const struct net_device_ops netdev_ops = {
.ndo_open = xircom_open,
.ndo_stop = xircom_close,
@@ -279,7 +265,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
setup_descriptors(private);
dev->netdev_ops = &netdev_ops;
- SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
pci_set_drvdata(pdev, dev);
if (register_netdev(dev)) {
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 2e50077ff450..5b83c3f35f47 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -24,10 +24,6 @@
3XP Processor. It has been tested on x86 and sparc64.
KNOWN ISSUES:
- *) The current firmware always strips the VLAN tag off, even if
- we tell it not to. You should filter VLANs at the switch
- as a workaround (good practice in any event) until we can
- get this fixed.
*) Cannot DMA Rx packets to a 2 byte aligned address. Also firmware
issue. Hopefully 3Com will fix it.
*) Waiting for a command response takes 8ms due to non-preemptable
@@ -280,8 +276,6 @@ struct typhoon {
struct pci_dev * pdev;
struct net_device * dev;
struct napi_struct napi;
- spinlock_t state_lock;
- struct vlan_group * vlgrp;
struct basic_ring rxHiRing;
struct basic_ring rxBuffRing;
struct rxbuff_ent rxbuffers[RXENT_ENTRIES];
@@ -541,7 +535,7 @@ cleanup:
indexes->respCleared = cpu_to_le32(cleared);
wmb();
- return (resp_save == NULL);
+ return resp_save == NULL;
}
static inline int
@@ -695,44 +689,6 @@ out:
return err;
}
-static void
-typhoon_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
-{
- struct typhoon *tp = netdev_priv(dev);
- struct cmd_desc xp_cmd;
- int err;
-
- spin_lock_bh(&tp->state_lock);
- if(!tp->vlgrp != !grp) {
- /* We've either been turned on for the first time, or we've
- * been turned off. Update the 3XP.
- */
- if(grp)
- tp->offload |= TYPHOON_OFFLOAD_VLAN;
- else
- tp->offload &= ~TYPHOON_OFFLOAD_VLAN;
-
- /* If the interface is up, the runtime is running -- and we
- * must be up for the vlan core to call us.
- *
- * Do the command outside of the spin lock, as it is slow.
- */
- INIT_COMMAND_WITH_RESPONSE(&xp_cmd,
- TYPHOON_CMD_SET_OFFLOAD_TASKS);
- xp_cmd.parm2 = tp->offload;
- xp_cmd.parm3 = tp->offload;
- spin_unlock_bh(&tp->state_lock);
- err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
- if(err < 0)
- netdev_err(tp->dev, "vlan offload error %d\n", -err);
- spin_lock_bh(&tp->state_lock);
- }
-
- /* now make the change visible */
- tp->vlgrp = grp;
- spin_unlock_bh(&tp->state_lock);
-}
-
static inline void
typhoon_tso_fill(struct sk_buff *skb, struct transmit_ring *txRing,
u32 ring_dma)
@@ -818,7 +774,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
first_txd->processFlags |=
TYPHOON_TX_PF_INSERT_VLAN | TYPHOON_TX_PF_VLAN_PRIORITY;
first_txd->processFlags |=
- cpu_to_le32(ntohs(vlan_tx_tag_get(skb)) <<
+ cpu_to_le32(htons(vlan_tx_tag_get(skb)) <<
TYPHOON_TX_PF_VLAN_TAG_SHIFT);
}
@@ -936,7 +892,7 @@ typhoon_set_rx_mode(struct net_device *dev)
filter |= TYPHOON_RX_FILTER_MCAST_HASH;
}
- INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_RX_FILTER);
+ INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_RX_FILTER);
xp_cmd.parm1 = filter;
typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
}
@@ -962,36 +918,34 @@ typhoon_do_get_stats(struct typhoon *tp)
* The extra status reported would be a good candidate for
* ethtool_ops->get_{strings,stats}()
*/
- stats->tx_packets = le32_to_cpu(s->txPackets);
- stats->tx_bytes = le64_to_cpu(s->txBytes);
- stats->tx_errors = le32_to_cpu(s->txCarrierLost);
- stats->tx_carrier_errors = le32_to_cpu(s->txCarrierLost);
- stats->collisions = le32_to_cpu(s->txMultipleCollisions);
- stats->rx_packets = le32_to_cpu(s->rxPacketsGood);
- stats->rx_bytes = le64_to_cpu(s->rxBytesGood);
- stats->rx_fifo_errors = le32_to_cpu(s->rxFifoOverruns);
+ stats->tx_packets = le32_to_cpu(s->txPackets) +
+ saved->tx_packets;
+ stats->tx_bytes = le64_to_cpu(s->txBytes) +
+ saved->tx_bytes;
+ stats->tx_errors = le32_to_cpu(s->txCarrierLost) +
+ saved->tx_errors;
+ stats->tx_carrier_errors = le32_to_cpu(s->txCarrierLost) +
+ saved->tx_carrier_errors;
+ stats->collisions = le32_to_cpu(s->txMultipleCollisions) +
+ saved->collisions;
+ stats->rx_packets = le32_to_cpu(s->rxPacketsGood) +
+ saved->rx_packets;
+ stats->rx_bytes = le64_to_cpu(s->rxBytesGood) +
+ saved->rx_bytes;
+ stats->rx_fifo_errors = le32_to_cpu(s->rxFifoOverruns) +
+ saved->rx_fifo_errors;
stats->rx_errors = le32_to_cpu(s->rxFifoOverruns) +
- le32_to_cpu(s->BadSSD) + le32_to_cpu(s->rxCrcErrors);
- stats->rx_crc_errors = le32_to_cpu(s->rxCrcErrors);
- stats->rx_length_errors = le32_to_cpu(s->rxOversized);
+ le32_to_cpu(s->BadSSD) + le32_to_cpu(s->rxCrcErrors) +
+ saved->rx_errors;
+ stats->rx_crc_errors = le32_to_cpu(s->rxCrcErrors) +
+ saved->rx_crc_errors;
+ stats->rx_length_errors = le32_to_cpu(s->rxOversized) +
+ saved->rx_length_errors;
tp->speed = (s->linkStatus & TYPHOON_LINK_100MBPS) ?
SPEED_100 : SPEED_10;
tp->duplex = (s->linkStatus & TYPHOON_LINK_FULL_DUPLEX) ?
DUPLEX_FULL : DUPLEX_HALF;
- /* add in the saved statistics
- */
- stats->tx_packets += saved->tx_packets;
- stats->tx_bytes += saved->tx_bytes;
- stats->tx_errors += saved->tx_errors;
- stats->collisions += saved->collisions;
- stats->rx_packets += saved->rx_packets;
- stats->rx_bytes += saved->rx_bytes;
- stats->rx_fifo_errors += saved->rx_fifo_errors;
- stats->rx_errors += saved->rx_errors;
- stats->rx_crc_errors += saved->rx_crc_errors;
- stats->rx_length_errors += saved->rx_length_errors;
-
return 0;
}
@@ -1200,6 +1154,20 @@ typhoon_get_rx_csum(struct net_device *dev)
return 1;
}
+static int
+typhoon_set_flags(struct net_device *dev, u32 data)
+{
+ /* There's no way to turn off the RX VLAN offloading and stripping
+ * on the current 3XP firmware -- it does not respect the offload
+ * settings -- so we only allow the user to toggle the TX processing.
+ */
+ if (!(data & ETH_FLAG_RXVLAN))
+ return -EINVAL;
+
+ return ethtool_op_set_flags(dev, data,
+ ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN);
+}
+
static void
typhoon_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
{
@@ -1226,6 +1194,8 @@ static const struct ethtool_ops typhoon_ethtool_ops = {
.set_sg = ethtool_op_set_sg,
.set_tso = ethtool_op_set_tso,
.get_ringparam = typhoon_get_ringparam,
+ .set_flags = typhoon_set_flags,
+ .get_flags = ethtool_op_get_flags,
};
static int
@@ -1311,9 +1281,9 @@ typhoon_init_interface(struct typhoon *tp)
tp->offload = TYPHOON_OFFLOAD_IP_CHKSUM | TYPHOON_OFFLOAD_TCP_CHKSUM;
tp->offload |= TYPHOON_OFFLOAD_UDP_CHKSUM | TSO_OFFLOAD_ON;
+ tp->offload |= TYPHOON_OFFLOAD_VLAN;
spin_lock_init(&tp->command_lock);
- spin_lock_init(&tp->state_lock);
/* Force the writes to the shared memory area out before continuing. */
wmb();
@@ -1330,7 +1300,7 @@ typhoon_init_rings(struct typhoon *tp)
tp->rxHiRing.lastWrite = 0;
tp->rxBuffRing.lastWrite = 0;
tp->cmdRing.lastWrite = 0;
- tp->cmdRing.lastWrite = 0;
+ tp->respRing.lastWrite = 0;
tp->txLoRing.lastRead = 0;
tp->txHiRing.lastRead = 0;
@@ -1762,15 +1732,12 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile __le32 * read
(TYPHOON_RX_IP_CHK_GOOD | TYPHOON_RX_UDP_CHK_GOOD)) {
new_skb->ip_summed = CHECKSUM_UNNECESSARY;
} else
- new_skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(new_skb);
- spin_lock(&tp->state_lock);
- if(tp->vlgrp != NULL && rx->rxStatus & TYPHOON_RX_VLAN)
- vlan_hwaccel_receive_skb(new_skb, tp->vlgrp,
- ntohl(rx->vlanTag) & 0xffff);
- else
- netif_receive_skb(new_skb);
- spin_unlock(&tp->state_lock);
+ if (rx->rxStatus & TYPHOON_RX_VLAN)
+ __vlan_hwaccel_put_tag(new_skb,
+ ntohl(rx->vlanTag) & 0xffff);
+ netif_receive_skb(new_skb);
received++;
budget--;
@@ -1991,11 +1958,9 @@ typhoon_start_runtime(struct typhoon *tp)
goto error_out;
INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_OFFLOAD_TASKS);
- spin_lock_bh(&tp->state_lock);
xp_cmd.parm2 = tp->offload;
xp_cmd.parm3 = tp->offload;
err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
- spin_unlock_bh(&tp->state_lock);
if(err < 0)
goto error_out;
@@ -2233,13 +2198,9 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state)
if(!netif_running(dev))
return 0;
- spin_lock_bh(&tp->state_lock);
- if(tp->vlgrp && tp->wol_events & TYPHOON_WAKE_MAGIC_PKT) {
- spin_unlock_bh(&tp->state_lock);
- netdev_err(dev, "cannot do WAKE_MAGIC with VLANS\n");
- return -EBUSY;
- }
- spin_unlock_bh(&tp->state_lock);
+ /* TYPHOON_OFFLOAD_VLAN is always on now, so this doesn't work */
+ if(tp->wol_events & TYPHOON_WAKE_MAGIC_PKT)
+ netdev_warn(dev, "cannot do WAKE_MAGIC with VLAN offloading\n");
netif_device_detach(dev);
@@ -2340,7 +2301,6 @@ static const struct net_device_ops typhoon_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = typhoon_set_mac_address,
.ndo_change_mtu = eth_change_mtu,
- .ndo_vlan_rx_register = typhoon_vlan_rx_register,
};
static int __devinit
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index d7b7018a1de1..52ffabe6db0e 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -358,6 +358,14 @@ config USB_NET_ZAURUS
really need this non-conformant variant of CDC Ethernet (or in
some cases CDC MDLM) protocol, not "g_ether".
+config USB_NET_CX82310_ETH
+ tristate "Conexant CX82310 USB ethernet port"
+ depends on USB_USBNET
+ help
+ Choose this option if you're using a Conexant CX82310-based ADSL
+ router with USB ethernet port. This driver is for routers only,
+ it will not work with ADSL modems (use cxacru driver instead).
+
config USB_HSO
tristate "Option USB High Speed Mobile Devices"
depends on USB && RFKILL
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index b13a279663ba..a19b0259ae16 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -25,4 +25,5 @@ obj-$(CONFIG_USB_NET_INT51X1) += int51x1.o
obj-$(CONFIG_USB_CDC_PHONET) += cdc-phonet.o
obj-$(CONFIG_USB_IPHETH) += ipheth.o
obj-$(CONFIG_USB_SIERRA_NET) += sierra_net.o
+obj-$(CONFIG_USB_NET_CX82310_ETH) += cx82310_eth.o
diff --git a/drivers/net/usb/cx82310_eth.c b/drivers/net/usb/cx82310_eth.c
new file mode 100644
index 000000000000..8969f124c18c
--- /dev/null
+++ b/drivers/net/usb/cx82310_eth.c
@@ -0,0 +1,346 @@
+/*
+ * Driver for USB ethernet port of Conexant CX82310-based ADSL routers
+ * Copyright (C) 2010 by Ondrej Zary
+ * some parts inspired by the cxacru driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/usb/usbnet.h>
+
+enum cx82310_cmd {
+ CMD_START = 0x84, /* no effect? */
+ CMD_STOP = 0x85, /* no effect? */
+ CMD_GET_STATUS = 0x90, /* returns nothing? */
+ CMD_GET_MAC_ADDR = 0x91, /* read MAC address */
+ CMD_GET_LINK_STATUS = 0x92, /* not useful, link is always up */
+ CMD_ETHERNET_MODE = 0x99, /* unknown, needed during init */
+};
+
+enum cx82310_status {
+ STATUS_UNDEFINED,
+ STATUS_SUCCESS,
+ STATUS_ERROR,
+ STATUS_UNSUPPORTED,
+ STATUS_UNIMPLEMENTED,
+ STATUS_PARAMETER_ERROR,
+ STATUS_DBG_LOOPBACK,
+};
+
+#define CMD_PACKET_SIZE 64
+/* first command after power on can take around 8 seconds */
+#define CMD_TIMEOUT 15000
+#define CMD_REPLY_RETRY 5
+
+#define CX82310_MTU 1514
+#define CMD_EP 0x01
+
+/*
+ * execute control command
+ * - optionally send some data (command parameters)
+ * - optionally wait for the reply
+ * - optionally read some data from the reply
+ */
+static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply,
+ u8 *wdata, int wlen, u8 *rdata, int rlen)
+{
+ int actual_len, retries, ret;
+ struct usb_device *udev = dev->udev;
+ u8 *buf = kzalloc(CMD_PACKET_SIZE, GFP_KERNEL);
+
+ if (!buf)
+ return -ENOMEM;
+
+ /* create command packet */
+ buf[0] = cmd;
+ if (wdata)
+ memcpy(buf + 4, wdata, min_t(int, wlen, CMD_PACKET_SIZE - 4));
+
+ /* send command packet */
+ ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, CMD_EP), buf,
+ CMD_PACKET_SIZE, &actual_len, CMD_TIMEOUT);
+ if (ret < 0) {
+ dev_err(&dev->udev->dev, "send command %#x: error %d\n",
+ cmd, ret);
+ goto end;
+ }
+
+ if (reply) {
+ /* wait for reply, retry if it's empty */
+ for (retries = 0; retries < CMD_REPLY_RETRY; retries++) {
+ ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, CMD_EP),
+ buf, CMD_PACKET_SIZE, &actual_len,
+ CMD_TIMEOUT);
+ if (ret < 0) {
+ dev_err(&dev->udev->dev,
+ "reply receive error %d\n", ret);
+ goto end;
+ }
+ if (actual_len > 0)
+ break;
+ }
+ if (actual_len == 0) {
+ dev_err(&dev->udev->dev, "no reply to command %#x\n",
+ cmd);
+ ret = -EIO;
+ goto end;
+ }
+ if (buf[0] != cmd) {
+ dev_err(&dev->udev->dev,
+ "got reply to command %#x, expected: %#x\n",
+ buf[0], cmd);
+ ret = -EIO;
+ goto end;
+ }
+ if (buf[1] != STATUS_SUCCESS) {
+ dev_err(&dev->udev->dev, "command %#x failed: %#x\n",
+ cmd, buf[1]);
+ ret = -EIO;
+ goto end;
+ }
+ if (rdata)
+ memcpy(rdata, buf + 4,
+ min_t(int, rlen, CMD_PACKET_SIZE - 4));
+ }
+end:
+ kfree(buf);
+ return ret;
+}
+
+#define partial_len data[0] /* length of partial packet data */
+#define partial_rem data[1] /* remaining (missing) data length */
+#define partial_data data[2] /* partial packet data */
+
+static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ int ret;
+ char buf[15];
+ struct usb_device *udev = dev->udev;
+
+ /* avoid ADSL modems - continue only if iProduct is "USB NET CARD" */
+ if (usb_string(udev, udev->descriptor.iProduct, buf, sizeof(buf)) > 0
+ && strcmp(buf, "USB NET CARD")) {
+ dev_info(&udev->dev, "ignoring: probably an ADSL modem\n");
+ return -ENODEV;
+ }
+
+ ret = usbnet_get_endpoints(dev, intf);
+ if (ret)
+ return ret;
+
+ /*
+ * this must not include ethernet header as the device can send partial
+ * packets with no header (and sometimes even empty URBs)
+ */
+ dev->net->hard_header_len = 0;
+ /* we can send at most 1514 bytes of data (+ 2-byte header) per URB */
+ dev->hard_mtu = CX82310_MTU + 2;
+ /* we can receive URBs up to 4KB from the device */
+ dev->rx_urb_size = 4096;
+
+ dev->partial_data = (unsigned long) kmalloc(dev->hard_mtu, GFP_KERNEL);
+ if (!dev->partial_data)
+ return -ENOMEM;
+
+ /* enable ethernet mode (?) */
+ ret = cx82310_cmd(dev, CMD_ETHERNET_MODE, true, "\x01", 1, NULL, 0);
+ if (ret) {
+ dev_err(&udev->dev, "unable to enable ethernet mode: %d\n",
+ ret);
+ goto err;
+ }
+
+ /* get the MAC address */
+ ret = cx82310_cmd(dev, CMD_GET_MAC_ADDR, true, NULL, 0,
+ dev->net->dev_addr, ETH_ALEN);
+ if (ret) {
+ dev_err(&udev->dev, "unable to read MAC address: %d\n", ret);
+ goto err;
+ }
+
+ /* start (does not seem to have any effect?) */
+ ret = cx82310_cmd(dev, CMD_START, false, NULL, 0, NULL, 0);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ kfree((void *)dev->partial_data);
+ return ret;
+}
+
+static void cx82310_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+ kfree((void *)dev->partial_data);
+}
+
+/*
+ * RX is NOT easy - we can receive multiple packets per skb, each having 2-byte
+ * packet length at the beginning.
+ * The last packet might be incomplete (when it crosses the 4KB URB size),
+ * continuing in the next skb (without any headers).
+ * If a packet has odd length, there is one extra byte at the end (before next
+ * packet or at the end of the URB).
+ */
+static int cx82310_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ int len;
+ struct sk_buff *skb2;
+
+ /*
+ * If the last skb ended with an incomplete packet, this skb contains
+ * end of that packet at the beginning.
+ */
+ if (dev->partial_rem) {
+ len = dev->partial_len + dev->partial_rem;
+ skb2 = alloc_skb(len, GFP_ATOMIC);
+ if (!skb2)
+ return 0;
+ skb_put(skb2, len);
+ memcpy(skb2->data, (void *)dev->partial_data,
+ dev->partial_len);
+ memcpy(skb2->data + dev->partial_len, skb->data,
+ dev->partial_rem);
+ usbnet_skb_return(dev, skb2);
+ skb_pull(skb, (dev->partial_rem + 1) & ~1);
+ dev->partial_rem = 0;
+ if (skb->len < 2)
+ return 1;
+ }
+
+ /* a skb can contain multiple packets */
+ while (skb->len > 1) {
+ /* first two bytes are packet length */
+ len = skb->data[0] | (skb->data[1] << 8);
+ skb_pull(skb, 2);
+
+ /* if last packet in the skb, let usbnet to process it */
+ if (len == skb->len || len + 1 == skb->len) {
+ skb_trim(skb, len);
+ break;
+ }
+
+ if (len > CX82310_MTU) {
+ dev_err(&dev->udev->dev, "RX packet too long: %d B\n",
+ len);
+ return 0;
+ }
+
+ /* incomplete packet, save it for the next skb */
+ if (len > skb->len) {
+ dev->partial_len = skb->len;
+ dev->partial_rem = len - skb->len;
+ memcpy((void *)dev->partial_data, skb->data,
+ dev->partial_len);
+ skb_pull(skb, skb->len);
+ break;
+ }
+
+ skb2 = alloc_skb(len, GFP_ATOMIC);
+ if (!skb2)
+ return 0;
+ skb_put(skb2, len);
+ memcpy(skb2->data, skb->data, len);
+ /* process the packet */
+ usbnet_skb_return(dev, skb2);
+
+ skb_pull(skb, (len + 1) & ~1);
+ }
+
+ /* let usbnet process the last packet */
+ return 1;
+}
+
+/* TX is easy, just add 2 bytes of length at the beginning */
+static struct sk_buff *cx82310_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+ gfp_t flags)
+{
+ int len = skb->len;
+
+ if (skb_headroom(skb) < 2) {
+ struct sk_buff *skb2 = skb_copy_expand(skb, 2, 0, flags);
+ dev_kfree_skb_any(skb);
+ skb = skb2;
+ if (!skb)
+ return NULL;
+ }
+ skb_push(skb, 2);
+
+ skb->data[0] = len;
+ skb->data[1] = len >> 8;
+
+ return skb;
+}
+
+
+static const struct driver_info cx82310_info = {
+ .description = "Conexant CX82310 USB ethernet",
+ .flags = FLAG_ETHER,
+ .bind = cx82310_bind,
+ .unbind = cx82310_unbind,
+ .rx_fixup = cx82310_rx_fixup,
+ .tx_fixup = cx82310_tx_fixup,
+};
+
+#define USB_DEVICE_CLASS(vend, prod, cl, sc, pr) \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+ USB_DEVICE_ID_MATCH_DEV_INFO, \
+ .idVendor = (vend), \
+ .idProduct = (prod), \
+ .bDeviceClass = (cl), \
+ .bDeviceSubClass = (sc), \
+ .bDeviceProtocol = (pr)
+
+static const struct usb_device_id products[] = {
+ {
+ USB_DEVICE_CLASS(0x0572, 0xcb01, 0xff, 0, 0),
+ .driver_info = (unsigned long) &cx82310_info
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver cx82310_driver = {
+ .name = "cx82310_eth",
+ .id_table = products,
+ .probe = usbnet_probe,
+ .disconnect = usbnet_disconnect,
+ .suspend = usbnet_suspend,
+ .resume = usbnet_resume,
+};
+
+static int __init cx82310_init(void)
+{
+ return usb_register(&cx82310_driver);
+}
+module_init(cx82310_init);
+
+static void __exit cx82310_exit(void)
+{
+ usb_deregister(&cx82310_driver);
+}
+module_exit(cx82310_exit);
+
+MODULE_AUTHOR("Ondrej Zary");
+MODULE_DESCRIPTION("Conexant CX82310-based ADSL router USB ethernet driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index b8e957249132..b154a94de03e 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -843,16 +843,7 @@ static netdev_tx_t hso_net_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
-static void hso_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
-{
- struct hso_net *odev = netdev_priv(net);
-
- strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
- usb_make_path(odev->parent->usb, info->bus_info, sizeof info->bus_info);
-}
-
static const struct ethtool_ops ops = {
- .get_drvinfo = hso_get_drvinfo,
.get_link = ethtool_op_get_link
};
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 2b7b39cad1ce..5e98643a4a21 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -759,14 +759,6 @@ static int kaweth_close(struct net_device *net)
return 0;
}
-static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
- struct kaweth_device *kaweth = netdev_priv(dev);
-
- strlcpy(info->driver, driver_name, sizeof(info->driver));
- usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info));
-}
-
static u32 kaweth_get_link(struct net_device *dev)
{
struct kaweth_device *kaweth = netdev_priv(dev);
@@ -775,7 +767,6 @@ static u32 kaweth_get_link(struct net_device *dev)
}
static const struct ethtool_ops ops = {
- .get_drvinfo = kaweth_get_drvinfo,
.get_link = kaweth_get_link
};
diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c
index 08555f8b15f4..08ad269f6b4e 100644
--- a/drivers/net/usb/plusb.c
+++ b/drivers/net/usb/plusb.c
@@ -32,7 +32,7 @@
/*
- * Prolific PL-2301/PL-2302 driver ... http://www.prolifictech.com
+ * Prolific PL-2301/PL-2302 driver ... http://www.prolific.com.tw/
*
* The protocol and handshaking used here should be bug-compatible
* with the Linux 2.2 "plusb" driver, by Deti Fliegl.
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index ee85c8b9a858..d1ac15c95faf 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -203,7 +203,7 @@ static inline void sierra_net_set_private(struct usbnet *dev,
/* is packet IPv4 */
static inline int is_ip(struct sk_buff *skb)
{
- return (skb->protocol == cpu_to_be16(ETH_P_IP));
+ return skb->protocol == cpu_to_be16(ETH_P_IP);
}
/*
@@ -354,7 +354,7 @@ static void sierra_net_set_ctx_index(struct sierra_net_data *priv, u8 ctx_ix)
static inline int sierra_net_is_valid_addrlen(u8 len)
{
- return (len == sizeof(struct in_addr));
+ return len == sizeof(struct in_addr);
}
static int sierra_net_parse_lsi(struct usbnet *dev, char *data, int datalen)
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 12a3c88c5282..65cb1abfbe57 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -805,8 +805,6 @@ static int smsc95xx_reset(struct usbnet *dev)
return ret;
}
- smsc95xx_init_mac_address(dev);
-
ret = smsc95xx_set_mac_address(dev);
if (ret < 0)
return ret;
@@ -1047,6 +1045,8 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE;
pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE;
+ smsc95xx_init_mac_address(dev);
+
/* Init all registers */
ret = smsc95xx_reset(dev);
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 5ec542dd5b50..0bbc0c323135 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -250,7 +250,7 @@ static int veth_close(struct net_device *dev)
static int is_valid_veth_mtu(int new_mtu)
{
- return (new_mtu >= MIN_MTU && new_mtu <= MAX_MTU);
+ return new_mtu >= MIN_MTU && new_mtu <= MAX_MTU;
}
static int veth_change_mtu(struct net_device *dev, int new_mtu)
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index f53412368ce1..cab96ad49e60 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -312,13 +312,14 @@ VELOCITY_PARAM(flow_control, "Enable flow control ability");
#define MED_LNK_DEF 0
#define MED_LNK_MIN 0
-#define MED_LNK_MAX 4
+#define MED_LNK_MAX 5
/* speed_duplex[] is used for setting the speed and duplex mode of NIC.
0: indicate autonegotiation for both speed and duplex mode
1: indicate 100Mbps half duplex mode
2: indicate 100Mbps full duplex mode
3: indicate 10Mbps half duplex mode
4: indicate 10Mbps full duplex mode
+ 5: indicate 1000Mbps full duplex mode
Note:
if EEPROM have been set to the force mode, this option is ignored
@@ -617,6 +618,9 @@ static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
case SPD_DPX_10_HALF:
status = VELOCITY_SPEED_10;
break;
+ case SPD_DPX_1000_FULL:
+ status = VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
+ break;
}
vptr->mii_status = status;
return status;
@@ -922,6 +926,7 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
/* enable AUTO-NEGO mode */
mii_set_auto_on(vptr);
} else {
+ u16 CTRL1000;
u16 ANAR;
u8 CHIPGCR;
@@ -936,7 +941,11 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
CHIPGCR = readb(&regs->CHIPGCR);
- CHIPGCR &= ~CHIPGCR_FCGMII;
+
+ if (mii_status & VELOCITY_SPEED_1000)
+ CHIPGCR |= CHIPGCR_FCGMII;
+ else
+ CHIPGCR &= ~CHIPGCR_FCGMII;
if (mii_status & VELOCITY_DUPLEX_FULL) {
CHIPGCR |= CHIPGCR_FCFDX;
@@ -952,7 +961,13 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
}
- MII_REG_BITS_OFF(ADVERTISE_1000FULL | ADVERTISE_1000HALF, MII_CTRL1000, vptr->mac_regs);
+ velocity_mii_read(vptr->mac_regs, MII_CTRL1000, &CTRL1000);
+ CTRL1000 &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+ if ((mii_status & VELOCITY_SPEED_1000) &&
+ (mii_status & VELOCITY_DUPLEX_FULL)) {
+ CTRL1000 |= ADVERTISE_1000FULL;
+ }
+ velocity_mii_write(vptr->mac_regs, MII_CTRL1000, CTRL1000);
if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10))
BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
@@ -967,7 +982,7 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
ANAR |= ADVERTISE_100FULL;
else
ANAR |= ADVERTISE_100HALF;
- } else {
+ } else if (mii_status & VELOCITY_SPEED_10) {
if (mii_status & VELOCITY_DUPLEX_FULL)
ANAR |= ADVERTISE_10FULL;
else
@@ -1013,6 +1028,9 @@ static void velocity_print_link_status(struct velocity_info *vptr)
} else {
VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
switch (vptr->options.spd_dpx) {
+ case SPD_DPX_1000_FULL:
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps full duplex\n");
+ break;
case SPD_DPX_100_HALF:
VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");
break;
@@ -1954,7 +1972,7 @@ static int velocity_tx_srv(struct velocity_info *vptr)
*/
static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
{
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
if (rd->rdesc1.CSM & CSM_IPKT) {
if (rd->rdesc1.CSM & CSM_IPOK) {
@@ -2574,7 +2592,7 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16;
- if (vptr->vlgrp && vlan_tx_tag_present(skb)) {
+ if (vlan_tx_tag_present(skb)) {
td_ptr->tdesc1.vlan = cpu_to_le16(vlan_tx_tag_get(skb));
td_ptr->tdesc1.TCR |= TCR0_VETAG;
}
@@ -3170,6 +3188,37 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full;
+
+ cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg;
+ if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+ cmd->advertising |=
+ ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full;
+ } else {
+ switch (vptr->options.spd_dpx) {
+ case SPD_DPX_1000_FULL:
+ cmd->advertising |= ADVERTISED_1000baseT_Full;
+ break;
+ case SPD_DPX_100_HALF:
+ cmd->advertising |= ADVERTISED_100baseT_Half;
+ break;
+ case SPD_DPX_100_FULL:
+ cmd->advertising |= ADVERTISED_100baseT_Full;
+ break;
+ case SPD_DPX_10_HALF:
+ cmd->advertising |= ADVERTISED_10baseT_Half;
+ break;
+ case SPD_DPX_10_FULL:
+ cmd->advertising |= ADVERTISED_10baseT_Full;
+ break;
+ default:
+ break;
+ }
+ }
if (status & VELOCITY_SPEED_1000)
cmd->speed = SPEED_1000;
else if (status & VELOCITY_SPEED_100)
@@ -3200,14 +3249,35 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd
curr_status &= (~VELOCITY_LINK_FAIL);
new_status |= ((cmd->autoneg) ? VELOCITY_AUTONEG_ENABLE : 0);
+ new_status |= ((cmd->speed == SPEED_1000) ? VELOCITY_SPEED_1000 : 0);
new_status |= ((cmd->speed == SPEED_100) ? VELOCITY_SPEED_100 : 0);
new_status |= ((cmd->speed == SPEED_10) ? VELOCITY_SPEED_10 : 0);
new_status |= ((cmd->duplex == DUPLEX_FULL) ? VELOCITY_DUPLEX_FULL : 0);
- if ((new_status & VELOCITY_AUTONEG_ENABLE) && (new_status != (curr_status | VELOCITY_AUTONEG_ENABLE)))
+ if ((new_status & VELOCITY_AUTONEG_ENABLE) &&
+ (new_status != (curr_status | VELOCITY_AUTONEG_ENABLE))) {
ret = -EINVAL;
- else
+ } else {
+ enum speed_opt spd_dpx;
+
+ if (new_status & VELOCITY_AUTONEG_ENABLE)
+ spd_dpx = SPD_DPX_AUTO;
+ else if ((new_status & VELOCITY_SPEED_1000) &&
+ (new_status & VELOCITY_DUPLEX_FULL)) {
+ spd_dpx = SPD_DPX_1000_FULL;
+ } else if (new_status & VELOCITY_SPEED_100)
+ spd_dpx = (new_status & VELOCITY_DUPLEX_FULL) ?
+ SPD_DPX_100_FULL : SPD_DPX_100_HALF;
+ else if (new_status & VELOCITY_SPEED_10)
+ spd_dpx = (new_status & VELOCITY_DUPLEX_FULL) ?
+ SPD_DPX_10_FULL : SPD_DPX_10_HALF;
+ else
+ return -EOPNOTSUPP;
+
+ vptr->options.spd_dpx = spd_dpx;
+
velocity_set_media_mode(vptr, new_status);
+ }
return ret;
}
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index f7b33ae7a703..aa2e69b9ff61 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -848,7 +848,7 @@ enum velocity_owner {
* Bits in CHIPGCR register
*/
-#define CHIPGCR_FCGMII 0x80
+#define CHIPGCR_FCGMII 0x80 /* enable GMII mode */
#define CHIPGCR_FCFDX 0x40
#define CHIPGCR_FCRESV 0x20
#define CHIPGCR_FCMODE 0x10
@@ -1390,7 +1390,8 @@ enum speed_opt {
SPD_DPX_100_HALF = 1,
SPD_DPX_100_FULL = 2,
SPD_DPX_10_HALF = 3,
- SPD_DPX_10_FULL = 4
+ SPD_DPX_10_FULL = 4,
+ SPD_DPX_1000_FULL = 5
};
enum velocity_init_type {
@@ -1504,22 +1505,25 @@ struct velocity_info {
* addresses on this chain then we use the first - multi-IP WOL is not
* supported.
*
- * CHECK ME: locking
*/
static inline int velocity_get_ip(struct velocity_info *vptr)
{
- struct in_device *in_dev = (struct in_device *) vptr->dev->ip_ptr;
+ struct in_device *in_dev;
struct in_ifaddr *ifa;
+ int res = -ENOENT;
+ rcu_read_lock();
+ in_dev = __in_dev_get_rcu(vptr->dev);
if (in_dev != NULL) {
ifa = (struct in_ifaddr *) in_dev->ifa_list;
if (ifa != NULL) {
memcpy(vptr->ip_addr, &ifa->ifa_address, 4);
- return 0;
+ res = 0;
}
}
- return -ENOENT;
+ rcu_read_unlock();
+ return res;
}
/**
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 4598e9d2608f..bb6b67f6b0cc 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -705,19 +705,6 @@ static int virtnet_close(struct net_device *dev)
return 0;
}
-static void virtnet_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *drvinfo)
-{
- struct virtnet_info *vi = netdev_priv(dev);
- struct virtio_device *vdev = vi->vdev;
-
- strncpy(drvinfo->driver, KBUILD_MODNAME, ARRAY_SIZE(drvinfo->driver));
- strncpy(drvinfo->version, "N/A", ARRAY_SIZE(drvinfo->version));
- strncpy(drvinfo->fw_version, "N/A", ARRAY_SIZE(drvinfo->fw_version));
- strncpy(drvinfo->bus_info, dev_name(&vdev->dev),
- ARRAY_SIZE(drvinfo->bus_info));
-}
-
static int virtnet_set_tx_csum(struct net_device *dev, u32 data)
{
struct virtnet_info *vi = netdev_priv(dev);
@@ -830,7 +817,6 @@ static void virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid)
}
static const struct ethtool_ops virtnet_ethtool_ops = {
- .get_drvinfo = virtnet_get_drvinfo,
.set_tx_csum = virtnet_set_tx_csum,
.set_sg = ethtool_op_set_sg,
.set_tso = ethtool_op_set_tso,
diff --git a/drivers/net/vmxnet3/upt1_defs.h b/drivers/net/vmxnet3/upt1_defs.h
index 37108fb226d3..969c751ee404 100644
--- a/drivers/net/vmxnet3/upt1_defs.h
+++ b/drivers/net/vmxnet3/upt1_defs.h
@@ -88,9 +88,9 @@ struct UPT1_RSSConf {
/* features */
enum {
- UPT1_F_RXCSUM = 0x0001, /* rx csum verification */
- UPT1_F_RSS = 0x0002,
- UPT1_F_RXVLAN = 0x0004, /* VLAN tag stripping */
- UPT1_F_LRO = 0x0008,
+ UPT1_F_RXCSUM = cpu_to_le64(0x0001), /* rx csum verification */
+ UPT1_F_RSS = cpu_to_le64(0x0002),
+ UPT1_F_RXVLAN = cpu_to_le64(0x0004), /* VLAN tag stripping */
+ UPT1_F_LRO = cpu_to_le64(0x0008),
};
#endif
diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h
index ca7727b940ad..4d84912c99ba 100644
--- a/drivers/net/vmxnet3/vmxnet3_defs.h
+++ b/drivers/net/vmxnet3/vmxnet3_defs.h
@@ -523,9 +523,9 @@ struct Vmxnet3_RxFilterConf {
#define VMXNET3_PM_MAX_PATTERN_SIZE 128
#define VMXNET3_PM_MAX_MASK_SIZE (VMXNET3_PM_MAX_PATTERN_SIZE / 8)
-#define VMXNET3_PM_WAKEUP_MAGIC 0x01 /* wake up on magic pkts */
-#define VMXNET3_PM_WAKEUP_FILTER 0x02 /* wake up on pkts matching
- * filters */
+#define VMXNET3_PM_WAKEUP_MAGIC cpu_to_le16(0x01) /* wake up on magic pkts */
+#define VMXNET3_PM_WAKEUP_FILTER cpu_to_le16(0x02) /* wake up on pkts matching
+ * filters */
struct Vmxnet3_PM_PktFilter {
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index abe0ff53daf3..e3658e10db39 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -1042,11 +1042,11 @@ vmxnet3_rx_csum(struct vmxnet3_adapter *adapter,
skb->csum = htons(gdesc->rcd.csum);
skb->ip_summed = CHECKSUM_PARTIAL;
} else {
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
}
}
} else {
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
}
}
@@ -1548,23 +1548,6 @@ vmxnet3_free_irqs(struct vmxnet3_adapter *adapter)
}
}
-
-inline void set_flag_le16(__le16 *data, u16 flag)
-{
- *data = cpu_to_le16(le16_to_cpu(*data) | flag);
-}
-
-inline void set_flag_le64(__le64 *data, u64 flag)
-{
- *data = cpu_to_le64(le64_to_cpu(*data) | flag);
-}
-
-inline void reset_flag_le64(__le64 *data, u64 flag)
-{
- *data = cpu_to_le64(le64_to_cpu(*data) & ~flag);
-}
-
-
static void
vmxnet3_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
{
@@ -1580,8 +1563,7 @@ vmxnet3_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
adapter->vlan_grp = grp;
/* update FEATURES to device */
- set_flag_le64(&devRead->misc.uptFeatures,
- UPT1_F_RXVLAN);
+ devRead->misc.uptFeatures |= UPT1_F_RXVLAN;
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_FEATURE);
/*
@@ -1604,7 +1586,7 @@ vmxnet3_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
struct Vmxnet3_DSDevRead *devRead = &shared->devRead;
adapter->vlan_grp = NULL;
- if (le64_to_cpu(devRead->misc.uptFeatures) & UPT1_F_RXVLAN) {
+ if (devRead->misc.uptFeatures & UPT1_F_RXVLAN) {
int i;
for (i = 0; i < VMXNET3_VFT_SIZE; i++) {
@@ -1617,8 +1599,7 @@ vmxnet3_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
VMXNET3_CMD_UPDATE_VLAN_FILTERS);
/* update FEATURES to device */
- reset_flag_le64(&devRead->misc.uptFeatures,
- UPT1_F_RXVLAN);
+ devRead->misc.uptFeatures &= ~UPT1_F_RXVLAN;
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_FEATURE);
}
@@ -1634,7 +1615,7 @@ vmxnet3_restore_vlan(struct vmxnet3_adapter *adapter)
u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
bool activeVlan = false;
- for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ for (vid = 0; vid < VLAN_N_VID; vid++) {
if (vlan_group_get_device(adapter->vlan_grp, vid)) {
VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid);
activeVlan = true;
@@ -1779,15 +1760,15 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
/* set up feature flags */
if (adapter->rxcsum)
- set_flag_le64(&devRead->misc.uptFeatures, UPT1_F_RXCSUM);
+ devRead->misc.uptFeatures |= UPT1_F_RXCSUM;
if (adapter->lro) {
- set_flag_le64(&devRead->misc.uptFeatures, UPT1_F_LRO);
+ devRead->misc.uptFeatures |= UPT1_F_LRO;
devRead->misc.maxNumRxSG = cpu_to_le16(1 + MAX_SKB_FRAGS);
}
if ((adapter->netdev->features & NETIF_F_HW_VLAN_RX) &&
adapter->vlan_grp) {
- set_flag_le64(&devRead->misc.uptFeatures, UPT1_F_RXVLAN);
+ devRead->misc.uptFeatures |= UPT1_F_RXVLAN;
}
devRead->misc.mtu = cpu_to_le32(adapter->netdev->mtu);
@@ -2594,7 +2575,7 @@ vmxnet3_suspend(struct device *device)
memcpy(pmConf->filters[i].pattern, netdev->dev_addr, ETH_ALEN);
pmConf->filters[i].mask[0] = 0x3F; /* LSB ETH_ALEN bits */
- set_flag_le16(&pmConf->wakeUpEvents, VMXNET3_PM_WAKEUP_FILTER);
+ pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_FILTER;
i++;
}
@@ -2636,13 +2617,13 @@ vmxnet3_suspend(struct device *device)
pmConf->filters[i].mask[5] = 0x03; /* IPv4 TIP */
in_dev_put(in_dev);
- set_flag_le16(&pmConf->wakeUpEvents, VMXNET3_PM_WAKEUP_FILTER);
+ pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_FILTER;
i++;
}
skip_arp:
if (adapter->wol & WAKE_MAGIC)
- set_flag_le16(&pmConf->wakeUpEvents, VMXNET3_PM_WAKEUP_MAGIC);
+ pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_MAGIC;
pmConf->numFilters = i;
@@ -2684,7 +2665,7 @@ vmxnet3_resume(struct device *device)
adapter->shared->devRead.pmConfDesc.confVer = cpu_to_le32(1);
adapter->shared->devRead.pmConfDesc.confLen = cpu_to_le32(sizeof(
*pmConf));
- adapter->shared->devRead.pmConfDesc.confPA = cpu_to_le32(virt_to_phys(
+ adapter->shared->devRead.pmConfDesc.confPA = cpu_to_le64(virt_to_phys(
pmConf));
netif_device_attach(netdev);
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index 7e4b5a89165a..b79070bcc92e 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -50,13 +50,11 @@ vmxnet3_set_rx_csum(struct net_device *netdev, u32 val)
adapter->rxcsum = val;
if (netif_running(netdev)) {
if (val)
- set_flag_le64(
- &adapter->shared->devRead.misc.uptFeatures,
- UPT1_F_RXCSUM);
+ adapter->shared->devRead.misc.uptFeatures |=
+ UPT1_F_RXCSUM;
else
- reset_flag_le64(
- &adapter->shared->devRead.misc.uptFeatures,
- UPT1_F_RXCSUM);
+ adapter->shared->devRead.misc.uptFeatures &=
+ ~UPT1_F_RXCSUM;
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_FEATURE);
@@ -292,10 +290,10 @@ vmxnet3_set_flags(struct net_device *netdev, u32 data)
/* update harware LRO capability accordingly */
if (lro_requested)
adapter->shared->devRead.misc.uptFeatures |=
- cpu_to_le64(UPT1_F_LRO);
+ UPT1_F_LRO;
else
adapter->shared->devRead.misc.uptFeatures &=
- cpu_to_le64(~UPT1_F_LRO);
+ ~UPT1_F_LRO;
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_FEATURE);
}
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index 2121c735cabd..8a2f4712284c 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -301,8 +301,8 @@ struct vmxnet3_adapter {
struct net_device *netdev;
struct pci_dev *pdev;
- u8 *hw_addr0; /* for BAR 0 */
- u8 *hw_addr1; /* for BAR 1 */
+ u8 __iomem *hw_addr0; /* for BAR 0 */
+ u8 __iomem *hw_addr1; /* for BAR 1 */
/* feature control */
bool rxcsum;
@@ -353,10 +353,6 @@ struct vmxnet3_adapter {
#define VMXNET3_MAX_ETH_HDR_SIZE 22
#define VMXNET3_MAX_SKB_BUF_SIZE (3*1024)
-void set_flag_le16(__le16 *data, u16 flag);
-void set_flag_le64(__le64 *data, u64 flag);
-void reset_flag_le64(__le64 *data, u64 flag);
-
int
vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter);
diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c
index 0e6db5935609..906a3ca3676b 100644
--- a/drivers/net/vxge/vxge-config.c
+++ b/drivers/net/vxge/vxge-config.c
@@ -20,6 +20,179 @@
#include "vxge-traffic.h"
#include "vxge-config.h"
+static enum vxge_hw_status
+__vxge_hw_fifo_create(
+ struct __vxge_hw_vpath_handle *vpath_handle,
+ struct vxge_hw_fifo_attr *attr);
+
+static enum vxge_hw_status
+__vxge_hw_fifo_abort(
+ struct __vxge_hw_fifo *fifoh);
+
+static enum vxge_hw_status
+__vxge_hw_fifo_reset(
+ struct __vxge_hw_fifo *ringh);
+
+static enum vxge_hw_status
+__vxge_hw_fifo_delete(
+ struct __vxge_hw_vpath_handle *vpath_handle);
+
+static struct __vxge_hw_blockpool_entry *
+__vxge_hw_blockpool_block_allocate(struct __vxge_hw_device *hldev,
+ u32 size);
+
+static void
+__vxge_hw_blockpool_block_free(struct __vxge_hw_device *hldev,
+ struct __vxge_hw_blockpool_entry *entry);
+
+static void vxge_hw_blockpool_block_add(struct __vxge_hw_device *devh,
+ void *block_addr,
+ u32 length,
+ struct pci_dev *dma_h,
+ struct pci_dev *acc_handle);
+
+static enum vxge_hw_status
+__vxge_hw_blockpool_create(struct __vxge_hw_device *hldev,
+ struct __vxge_hw_blockpool *blockpool,
+ u32 pool_size,
+ u32 pool_max);
+
+static void
+__vxge_hw_blockpool_destroy(struct __vxge_hw_blockpool *blockpool);
+
+static void *
+__vxge_hw_blockpool_malloc(struct __vxge_hw_device *hldev,
+ u32 size,
+ struct vxge_hw_mempool_dma *dma_object);
+
+static void
+__vxge_hw_blockpool_free(struct __vxge_hw_device *hldev,
+ void *memblock,
+ u32 size,
+ struct vxge_hw_mempool_dma *dma_object);
+
+
+static struct __vxge_hw_channel*
+__vxge_hw_channel_allocate(struct __vxge_hw_vpath_handle *vph,
+ enum __vxge_hw_channel_type type, u32 length,
+ u32 per_dtr_space, void *userdata);
+
+static void
+__vxge_hw_channel_free(
+ struct __vxge_hw_channel *channel);
+
+static enum vxge_hw_status
+__vxge_hw_channel_initialize(
+ struct __vxge_hw_channel *channel);
+
+static enum vxge_hw_status
+__vxge_hw_channel_reset(
+ struct __vxge_hw_channel *channel);
+
+static enum vxge_hw_status __vxge_hw_ring_delete(struct __vxge_hw_vpath_handle *vp);
+
+static enum vxge_hw_status
+__vxge_hw_device_fifo_config_check(struct vxge_hw_fifo_config *fifo_config);
+
+static enum vxge_hw_status
+__vxge_hw_device_config_check(struct vxge_hw_device_config *new_config);
+
+static void
+__vxge_hw_device_id_get(struct __vxge_hw_device *hldev);
+
+static void
+__vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev);
+
+static enum vxge_hw_status
+__vxge_hw_vpath_card_info_get(
+ u32 vp_id,
+ struct vxge_hw_vpath_reg __iomem *vpath_reg,
+ struct vxge_hw_device_hw_info *hw_info);
+
+static enum vxge_hw_status
+__vxge_hw_device_initialize(struct __vxge_hw_device *hldev);
+
+static void
+__vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev);
+
+static enum vxge_hw_status
+__vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev);
+
+static enum vxge_hw_status
+__vxge_hw_device_register_poll(
+ void __iomem *reg,
+ u64 mask, u32 max_millis);
+
+static inline enum vxge_hw_status
+__vxge_hw_pio_mem_write64(u64 val64, void __iomem *addr,
+ u64 mask, u32 max_millis)
+{
+ __vxge_hw_pio_mem_write32_lower((u32)vxge_bVALn(val64, 32, 32), addr);
+ wmb();
+
+ __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32), addr);
+ wmb();
+
+ return __vxge_hw_device_register_poll(addr, mask, max_millis);
+}
+
+static struct vxge_hw_mempool*
+__vxge_hw_mempool_create(struct __vxge_hw_device *devh, u32 memblock_size,
+ u32 item_size, u32 private_size, u32 items_initial,
+ u32 items_max, struct vxge_hw_mempool_cbs *mp_callback,
+ void *userdata);
+static void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool);
+
+static enum vxge_hw_status
+__vxge_hw_vpath_stats_get(struct __vxge_hw_virtualpath *vpath,
+ struct vxge_hw_vpath_stats_hw_info *hw_stats);
+
+static enum vxge_hw_status
+vxge_hw_vpath_stats_enable(struct __vxge_hw_vpath_handle *vpath_handle);
+
+static enum vxge_hw_status
+__vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg);
+
+static u64
+__vxge_hw_vpath_pci_func_mode_get(u32 vp_id,
+ struct vxge_hw_vpath_reg __iomem *vpath_reg);
+
+static u32
+__vxge_hw_vpath_func_id_get(u32 vp_id, struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg);
+
+static enum vxge_hw_status
+__vxge_hw_vpath_addr_get(u32 vp_id, struct vxge_hw_vpath_reg __iomem *vpath_reg,
+ u8 (macaddr)[ETH_ALEN], u8 (macaddr_mask)[ETH_ALEN]);
+
+static enum vxge_hw_status
+__vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath);
+
+
+static enum vxge_hw_status
+__vxge_hw_vpath_sw_reset(struct __vxge_hw_device *devh, u32 vp_id);
+
+static enum vxge_hw_status
+__vxge_hw_vpath_fw_ver_get(u32 vp_id, struct vxge_hw_vpath_reg __iomem *vpath_reg,
+ struct vxge_hw_device_hw_info *hw_info);
+
+static enum vxge_hw_status
+__vxge_hw_vpath_mac_configure(struct __vxge_hw_device *devh, u32 vp_id);
+
+static void
+__vxge_hw_vp_terminate(struct __vxge_hw_device *devh, u32 vp_id);
+
+static enum vxge_hw_status
+__vxge_hw_vpath_stats_access(struct __vxge_hw_virtualpath *vpath,
+ u32 operation, u32 offset, u64 *stat);
+
+static enum vxge_hw_status
+__vxge_hw_vpath_xmac_tx_stats_get(struct __vxge_hw_virtualpath *vpath,
+ struct vxge_hw_xmac_vpath_tx_stats *vpath_tx_stats);
+
+static enum vxge_hw_status
+__vxge_hw_vpath_xmac_rx_stats_get(struct __vxge_hw_virtualpath *vpath,
+ struct vxge_hw_xmac_vpath_rx_stats *vpath_rx_stats);
+
/*
* __vxge_hw_channel_allocate - Allocate memory for channel
* This function allocates required memory for the channel and various arrays
@@ -190,7 +363,7 @@ __vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev)
* Will poll certain register for specified amount of time.
* Will poll until masked bit is not cleared.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_device_register_poll(void __iomem *reg, u64 mask, u32 max_millis)
{
u64 val64;
@@ -221,7 +394,7 @@ __vxge_hw_device_register_poll(void __iomem *reg, u64 mask, u32 max_millis)
* in progress
* This routine checks the vpath reset in progress register is turned zero
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_device_vpath_reset_in_prog_check(u64 __iomem *vpath_rst_in_prog)
{
enum vxge_hw_status status;
@@ -236,7 +409,7 @@ __vxge_hw_device_vpath_reset_in_prog_check(u64 __iomem *vpath_rst_in_prog)
* This routine sets the swapper and reads the toc pointer and returns the
* memory mapped address of the toc
*/
-struct vxge_hw_toc_reg __iomem *
+static struct vxge_hw_toc_reg __iomem *
__vxge_hw_device_toc_get(void __iomem *bar0)
{
u64 val64;
@@ -779,7 +952,7 @@ exit:
* vxge_hw_device_xmac_aggr_stats_get - Get the Statistics on aggregate port
* Get the Statistics on aggregate port
*/
-enum vxge_hw_status
+static enum vxge_hw_status
vxge_hw_device_xmac_aggr_stats_get(struct __vxge_hw_device *hldev, u32 port,
struct vxge_hw_xmac_aggr_stats *aggr_stats)
{
@@ -814,7 +987,7 @@ exit:
* vxge_hw_device_xmac_port_stats_get - Get the Statistics on a port
* Get the Statistics on port
*/
-enum vxge_hw_status
+static enum vxge_hw_status
vxge_hw_device_xmac_port_stats_get(struct __vxge_hw_device *hldev, u32 port,
struct vxge_hw_xmac_port_stats *port_stats)
{
@@ -952,20 +1125,6 @@ u32 vxge_hw_device_trace_level_get(struct __vxge_hw_device *hldev)
return 0;
#endif
}
-/*
- * vxge_hw_device_debug_mask_get - Get the debug mask
- * This routine returns the current debug mask set
- */
-u32 vxge_hw_device_debug_mask_get(struct __vxge_hw_device *hldev)
-{
-#if defined(VXGE_DEBUG_TRACE_MASK) || defined(VXGE_DEBUG_ERR_MASK)
- if (hldev == NULL)
- return 0;
- return hldev->debug_module_mask;
-#else
- return 0;
-#endif
-}
/*
* vxge_hw_getpause_data -Pause frame frame generation and reception.
@@ -1090,7 +1249,7 @@ __vxge_hw_ring_block_next_pointer_set(u8 *block, dma_addr_t dma_next)
* first block
* Returns the dma address of the first RxD block
*/
-u64 __vxge_hw_ring_first_block_address_get(struct __vxge_hw_ring *ring)
+static u64 __vxge_hw_ring_first_block_address_get(struct __vxge_hw_ring *ring)
{
struct vxge_hw_mempool_dma *dma_object;
@@ -1252,7 +1411,7 @@ exit:
* This function creates Ring and initializes it.
*
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_ring_create(struct __vxge_hw_vpath_handle *vp,
struct vxge_hw_ring_attr *attr)
{
@@ -1363,7 +1522,7 @@ exit:
* __vxge_hw_ring_abort - Returns the RxD
* This function terminates the RxDs of ring
*/
-enum vxge_hw_status __vxge_hw_ring_abort(struct __vxge_hw_ring *ring)
+static enum vxge_hw_status __vxge_hw_ring_abort(struct __vxge_hw_ring *ring)
{
void *rxdh;
struct __vxge_hw_channel *channel;
@@ -1392,7 +1551,7 @@ enum vxge_hw_status __vxge_hw_ring_abort(struct __vxge_hw_ring *ring)
* __vxge_hw_ring_reset - Resets the ring
* This function resets the ring during vpath reset operation
*/
-enum vxge_hw_status __vxge_hw_ring_reset(struct __vxge_hw_ring *ring)
+static enum vxge_hw_status __vxge_hw_ring_reset(struct __vxge_hw_ring *ring)
{
enum vxge_hw_status status = VXGE_HW_OK;
struct __vxge_hw_channel *channel;
@@ -1419,7 +1578,7 @@ exit:
* __vxge_hw_ring_delete - Removes the ring
* This function freeup the memory pool and removes the ring
*/
-enum vxge_hw_status __vxge_hw_ring_delete(struct __vxge_hw_vpath_handle *vp)
+static enum vxge_hw_status __vxge_hw_ring_delete(struct __vxge_hw_vpath_handle *vp)
{
struct __vxge_hw_ring *ring = vp->vpath->ringh;
@@ -1438,7 +1597,7 @@ enum vxge_hw_status __vxge_hw_ring_delete(struct __vxge_hw_vpath_handle *vp)
* __vxge_hw_mempool_grow
* Will resize mempool up to %num_allocate value.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_mempool_grow(struct vxge_hw_mempool *mempool, u32 num_allocate,
u32 *num_allocated)
{
@@ -1527,7 +1686,7 @@ exit:
* with size enough to hold %items_initial number of items. Memory is
* DMA-able but client must map/unmap before interoperating with the device.
*/
-struct vxge_hw_mempool*
+static struct vxge_hw_mempool*
__vxge_hw_mempool_create(
struct __vxge_hw_device *devh,
u32 memblock_size,
@@ -1644,7 +1803,7 @@ exit:
/*
* vxge_hw_mempool_destroy
*/
-void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool)
+static void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool)
{
u32 i, j;
struct __vxge_hw_device *devh = mempool->devh;
@@ -1700,7 +1859,7 @@ __vxge_hw_device_fifo_config_check(struct vxge_hw_fifo_config *fifo_config)
* __vxge_hw_device_vpath_config_check - Check vpath configuration.
* Check the vpath configuration
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_device_vpath_config_check(struct vxge_hw_vp_config *vp_config)
{
enum vxge_hw_status status;
@@ -1922,7 +2081,7 @@ vxge_hw_device_config_default_get(struct vxge_hw_device_config *device_config)
* _hw_legacy_swapper_set - Set the swapper bits for the legacy secion.
* Set the swapper bits appropriately for the lagacy section.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg)
{
u64 val64;
@@ -1977,7 +2136,7 @@ __vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg)
* __vxge_hw_vpath_swapper_set - Set the swapper bits for the vpath.
* Set the swapper bits appropriately for the vpath.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vpath_swapper_set(struct vxge_hw_vpath_reg __iomem *vpath_reg)
{
#ifndef __BIG_ENDIAN
@@ -1996,7 +2155,7 @@ __vxge_hw_vpath_swapper_set(struct vxge_hw_vpath_reg __iomem *vpath_reg)
* __vxge_hw_kdfc_swapper_set - Set the swapper bits for the kdfc.
* Set the swapper bits appropriately for the vpath.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_kdfc_swapper_set(
struct vxge_hw_legacy_reg __iomem *legacy_reg,
struct vxge_hw_vpath_reg __iomem *vpath_reg)
@@ -2021,28 +2180,6 @@ __vxge_hw_kdfc_swapper_set(
}
/*
- * vxge_hw_mgmt_device_config - Retrieve device configuration.
- * Get device configuration. Permits to retrieve at run-time configuration
- * values that were used to initialize and configure the device.
- */
-enum vxge_hw_status
-vxge_hw_mgmt_device_config(struct __vxge_hw_device *hldev,
- struct vxge_hw_device_config *dev_config, int size)
-{
-
- if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC))
- return VXGE_HW_ERR_INVALID_DEVICE;
-
- if (size != sizeof(struct vxge_hw_device_config))
- return VXGE_HW_ERR_VERSION_CONFLICT;
-
- memcpy(dev_config, &hldev->config,
- sizeof(struct vxge_hw_device_config));
-
- return VXGE_HW_OK;
-}
-
-/*
* vxge_hw_mgmt_reg_read - Read Titan register.
*/
enum vxge_hw_status
@@ -2438,7 +2575,7 @@ exit:
* __vxge_hw_fifo_abort - Returns the TxD
* This function terminates the TxDs of fifo
*/
-enum vxge_hw_status __vxge_hw_fifo_abort(struct __vxge_hw_fifo *fifo)
+static enum vxge_hw_status __vxge_hw_fifo_abort(struct __vxge_hw_fifo *fifo)
{
void *txdlh;
@@ -2466,7 +2603,7 @@ enum vxge_hw_status __vxge_hw_fifo_abort(struct __vxge_hw_fifo *fifo)
* __vxge_hw_fifo_reset - Resets the fifo
* This function resets the fifo during vpath reset operation
*/
-enum vxge_hw_status __vxge_hw_fifo_reset(struct __vxge_hw_fifo *fifo)
+static enum vxge_hw_status __vxge_hw_fifo_reset(struct __vxge_hw_fifo *fifo)
{
enum vxge_hw_status status = VXGE_HW_OK;
@@ -2501,7 +2638,7 @@ enum vxge_hw_status __vxge_hw_fifo_delete(struct __vxge_hw_vpath_handle *vp)
* in pci config space.
* Read from the vpath pci config space.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vpath_pci_read(struct __vxge_hw_virtualpath *vpath,
u32 phy_func_0, u32 offset, u32 *val)
{
@@ -2542,7 +2679,7 @@ exit:
* __vxge_hw_vpath_func_id_get - Get the function id of the vpath.
* Returns the function number of the vpath.
*/
-u32
+static u32
__vxge_hw_vpath_func_id_get(u32 vp_id,
struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg)
{
@@ -2573,7 +2710,7 @@ __vxge_hw_read_rts_ds(struct vxge_hw_vpath_reg __iomem *vpath_reg,
* __vxge_hw_vpath_card_info_get - Get the serial numbers,
* part number and product description.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vpath_card_info_get(
u32 vp_id,
struct vxge_hw_vpath_reg __iomem *vpath_reg,
@@ -2695,7 +2832,7 @@ __vxge_hw_vpath_card_info_get(
* __vxge_hw_vpath_fw_ver_get - Get the fw version
* Returns FW Version
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vpath_fw_ver_get(
u32 vp_id,
struct vxge_hw_vpath_reg __iomem *vpath_reg,
@@ -2789,7 +2926,7 @@ exit:
* __vxge_hw_vpath_pci_func_mode_get - Get the pci mode
* Returns pci function mode
*/
-u64
+static u64
__vxge_hw_vpath_pci_func_mode_get(
u32 vp_id,
struct vxge_hw_vpath_reg __iomem *vpath_reg)
@@ -2995,7 +3132,7 @@ exit:
* __vxge_hw_vpath_addr_get - Get the hw address entry for this vpath
* from MAC address table.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vpath_addr_get(
u32 vp_id, struct vxge_hw_vpath_reg __iomem *vpath_reg,
u8 (macaddr)[ETH_ALEN], u8 (macaddr_mask)[ETH_ALEN])
@@ -3347,7 +3484,7 @@ __vxge_hw_vpath_mgmt_read(
* This routine checks the vpath_rst_in_prog register to see if
* adapter completed the reset process for the vpath
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath)
{
enum vxge_hw_status status;
@@ -3365,7 +3502,7 @@ __vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath)
* __vxge_hw_vpath_reset
* This routine resets the vpath on the device
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vpath_reset(struct __vxge_hw_device *hldev, u32 vp_id)
{
u64 val64;
@@ -3383,7 +3520,7 @@ __vxge_hw_vpath_reset(struct __vxge_hw_device *hldev, u32 vp_id)
* __vxge_hw_vpath_sw_reset
* This routine resets the vpath structures
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vpath_sw_reset(struct __vxge_hw_device *hldev, u32 vp_id)
{
enum vxge_hw_status status = VXGE_HW_OK;
@@ -3408,7 +3545,7 @@ exit:
* This routine configures the prc registers of virtual path using the config
* passed
*/
-void
+static void
__vxge_hw_vpath_prc_configure(struct __vxge_hw_device *hldev, u32 vp_id)
{
u64 val64;
@@ -3480,7 +3617,7 @@ __vxge_hw_vpath_prc_configure(struct __vxge_hw_device *hldev, u32 vp_id)
* This routine configures the kdfc registers of virtual path using the
* config passed
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vpath_kdfc_configure(struct __vxge_hw_device *hldev, u32 vp_id)
{
u64 val64;
@@ -3553,7 +3690,7 @@ exit:
* __vxge_hw_vpath_mac_configure
* This routine configures the mac of virtual path using the config passed
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vpath_mac_configure(struct __vxge_hw_device *hldev, u32 vp_id)
{
u64 val64;
@@ -3621,7 +3758,7 @@ __vxge_hw_vpath_mac_configure(struct __vxge_hw_device *hldev, u32 vp_id)
* This routine configures the tim registers of virtual path using the config
* passed
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vpath_tim_configure(struct __vxge_hw_device *hldev, u32 vp_id)
{
u64 val64;
@@ -3897,7 +4034,7 @@ vxge_hw_vpath_tti_ci_set(struct __vxge_hw_device *hldev, u32 vp_id)
* This routine is the final phase of init which initializes the
* registers of the vpath using the configuration passed.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vpath_initialize(struct __vxge_hw_device *hldev, u32 vp_id)
{
u64 val64;
@@ -3966,7 +4103,7 @@ exit:
* This routine is the initial phase of init which resets the vpath and
* initializes the software support structures.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id,
struct vxge_hw_vp_config *config)
{
@@ -4022,7 +4159,7 @@ exit:
* __vxge_hw_vp_terminate - Terminate Virtual Path structure
* This routine closes all channels it opened and freeup memory
*/
-void
+static void
__vxge_hw_vp_terminate(struct __vxge_hw_device *hldev, u32 vp_id)
{
struct __vxge_hw_virtualpath *vpath;
@@ -4384,7 +4521,7 @@ vxge_hw_vpath_enable(struct __vxge_hw_vpath_handle *vp)
* Enable the DMA vpath statistics. The function is to be called to re-enable
* the adapter to update stats into the host memory
*/
-enum vxge_hw_status
+static enum vxge_hw_status
vxge_hw_vpath_stats_enable(struct __vxge_hw_vpath_handle *vp)
{
enum vxge_hw_status status = VXGE_HW_OK;
@@ -4409,7 +4546,7 @@ exit:
* __vxge_hw_vpath_stats_access - Get the statistics from the given location
* and offset and perform an operation
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vpath_stats_access(struct __vxge_hw_virtualpath *vpath,
u32 operation, u32 offset, u64 *stat)
{
@@ -4445,7 +4582,7 @@ vpath_stats_access_exit:
/*
* __vxge_hw_vpath_xmac_tx_stats_get - Get the TX Statistics of a vpath
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vpath_xmac_tx_stats_get(
struct __vxge_hw_virtualpath *vpath,
struct vxge_hw_xmac_vpath_tx_stats *vpath_tx_stats)
@@ -4478,9 +4615,9 @@ exit:
/*
* __vxge_hw_vpath_xmac_rx_stats_get - Get the RX Statistics of a vpath
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_vpath_xmac_rx_stats_get(struct __vxge_hw_virtualpath *vpath,
- struct vxge_hw_xmac_vpath_rx_stats *vpath_rx_stats)
+ struct vxge_hw_xmac_vpath_rx_stats *vpath_rx_stats)
{
u64 *val64;
enum vxge_hw_status status = VXGE_HW_OK;
@@ -4509,9 +4646,9 @@ exit:
/*
* __vxge_hw_vpath_stats_get - Get the vpath hw statistics.
*/
-enum vxge_hw_status __vxge_hw_vpath_stats_get(
- struct __vxge_hw_virtualpath *vpath,
- struct vxge_hw_vpath_stats_hw_info *hw_stats)
+static enum vxge_hw_status
+__vxge_hw_vpath_stats_get(struct __vxge_hw_virtualpath *vpath,
+ struct vxge_hw_vpath_stats_hw_info *hw_stats)
{
u64 val64;
enum vxge_hw_status status = VXGE_HW_OK;
@@ -4643,6 +4780,32 @@ exit:
return status;
}
+
+static void vxge_os_dma_malloc_async(struct pci_dev *pdev, void *devh,
+ unsigned long size)
+{
+ gfp_t flags;
+ void *vaddr;
+
+ if (in_interrupt())
+ flags = GFP_ATOMIC | GFP_DMA;
+ else
+ flags = GFP_KERNEL | GFP_DMA;
+
+ vaddr = kmalloc((size), flags);
+
+ vxge_hw_blockpool_block_add(devh, vaddr, size, pdev, pdev);
+}
+
+static void vxge_os_dma_free(struct pci_dev *pdev, const void *vaddr,
+ struct pci_dev **p_dma_acch)
+{
+ unsigned long misaligned = *(unsigned long *)p_dma_acch;
+ u8 *tmp = (u8 *)vaddr;
+ tmp -= misaligned;
+ kfree((void *)tmp);
+}
+
/*
* __vxge_hw_blockpool_create - Create block pool
*/
@@ -4845,12 +5008,11 @@ void __vxge_hw_blockpool_blocks_remove(struct __vxge_hw_blockpool *blockpool)
* vxge_hw_blockpool_block_add - callback for vxge_os_dma_malloc_async
* Adds a block to block pool
*/
-void vxge_hw_blockpool_block_add(
- struct __vxge_hw_device *devh,
- void *block_addr,
- u32 length,
- struct pci_dev *dma_h,
- struct pci_dev *acc_handle)
+static void vxge_hw_blockpool_block_add(struct __vxge_hw_device *devh,
+ void *block_addr,
+ u32 length,
+ struct pci_dev *dma_h,
+ struct pci_dev *acc_handle)
{
struct __vxge_hw_blockpool *blockpool;
struct __vxge_hw_blockpool_entry *entry = NULL;
diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h
index 1a94343023cb..5c00861b6c2c 100644
--- a/drivers/net/vxge/vxge-config.h
+++ b/drivers/net/vxge/vxge-config.h
@@ -183,11 +183,6 @@ struct vxge_hw_device_version {
char version[VXGE_HW_FW_STRLEN];
};
-u64
-__vxge_hw_vpath_pci_func_mode_get(
- u32 vp_id,
- struct vxge_hw_vpath_reg __iomem *vpath_reg);
-
/**
* struct vxge_hw_fifo_config - Configuration of fifo.
* @enable: Is this fifo to be commissioned
@@ -1426,9 +1421,6 @@ struct vxge_hw_rth_hash_types {
u8 hash_type_ipv6ex_en;
};
-u32
-vxge_hw_device_debug_mask_get(struct __vxge_hw_device *devh);
-
void vxge_hw_device_debug_set(
struct __vxge_hw_device *devh,
enum vxge_debug_level level,
@@ -1440,9 +1432,6 @@ vxge_hw_device_error_level_get(struct __vxge_hw_device *devh);
u32
vxge_hw_device_trace_level_get(struct __vxge_hw_device *devh);
-u32
-vxge_hw_device_debug_mask_get(struct __vxge_hw_device *devh);
-
/**
* vxge_hw_ring_rxd_size_get - Get the size of ring descriptor.
* @buf_mode: Buffer mode (1, 3 or 5)
@@ -1817,60 +1806,10 @@ struct vxge_hw_vpath_attr {
struct vxge_hw_fifo_attr fifo_attr;
};
-enum vxge_hw_status
-__vxge_hw_blockpool_create(struct __vxge_hw_device *hldev,
- struct __vxge_hw_blockpool *blockpool,
- u32 pool_size,
- u32 pool_max);
-
-void
-__vxge_hw_blockpool_destroy(struct __vxge_hw_blockpool *blockpool);
-
-struct __vxge_hw_blockpool_entry *
-__vxge_hw_blockpool_block_allocate(struct __vxge_hw_device *hldev,
- u32 size);
-
-void
-__vxge_hw_blockpool_block_free(struct __vxge_hw_device *hldev,
- struct __vxge_hw_blockpool_entry *entry);
-
-void *
-__vxge_hw_blockpool_malloc(struct __vxge_hw_device *hldev,
- u32 size,
- struct vxge_hw_mempool_dma *dma_object);
-
-void
-__vxge_hw_blockpool_free(struct __vxge_hw_device *hldev,
- void *memblock,
- u32 size,
- struct vxge_hw_mempool_dma *dma_object);
-
-enum vxge_hw_status
-__vxge_hw_device_fifo_config_check(struct vxge_hw_fifo_config *fifo_config);
-
-enum vxge_hw_status
-__vxge_hw_device_config_check(struct vxge_hw_device_config *new_config);
-
-enum vxge_hw_status
-vxge_hw_mgmt_device_config(struct __vxge_hw_device *devh,
- struct vxge_hw_device_config *dev_config, int size);
-
enum vxge_hw_status __devinit vxge_hw_device_hw_info_get(
void __iomem *bar0,
struct vxge_hw_device_hw_info *hw_info);
-enum vxge_hw_status
-__vxge_hw_vpath_fw_ver_get(
- u32 vp_id,
- struct vxge_hw_vpath_reg __iomem *vpath_reg,
- struct vxge_hw_device_hw_info *hw_info);
-
-enum vxge_hw_status
-__vxge_hw_vpath_card_info_get(
- u32 vp_id,
- struct vxge_hw_vpath_reg __iomem *vpath_reg,
- struct vxge_hw_device_hw_info *hw_info);
-
enum vxge_hw_status __devinit vxge_hw_device_config_default_get(
struct vxge_hw_device_config *device_config);
@@ -1954,38 +1893,6 @@ out:
return vaddr;
}
-extern void vxge_hw_blockpool_block_add(
- struct __vxge_hw_device *devh,
- void *block_addr,
- u32 length,
- struct pci_dev *dma_h,
- struct pci_dev *acc_handle);
-
-static inline void vxge_os_dma_malloc_async(struct pci_dev *pdev, void *devh,
- unsigned long size)
-{
- gfp_t flags;
- void *vaddr;
-
- if (in_interrupt())
- flags = GFP_ATOMIC | GFP_DMA;
- else
- flags = GFP_KERNEL | GFP_DMA;
-
- vaddr = kmalloc((size), flags);
-
- vxge_hw_blockpool_block_add(devh, vaddr, size, pdev, pdev);
-}
-
-static inline void vxge_os_dma_free(struct pci_dev *pdev, const void *vaddr,
- struct pci_dev **p_dma_acch)
-{
- unsigned long misaligned = *(unsigned long *)p_dma_acch;
- u8 *tmp = (u8 *)vaddr;
- tmp -= misaligned;
- kfree((void *)tmp);
-}
-
/*
* __vxge_hw_mempool_item_priv - will return pointer on per item private space
*/
@@ -2010,40 +1917,6 @@ __vxge_hw_mempool_item_priv(
(*memblock_item_idx) * mempool->items_priv_size;
}
-enum vxge_hw_status
-__vxge_hw_mempool_grow(
- struct vxge_hw_mempool *mempool,
- u32 num_allocate,
- u32 *num_allocated);
-
-struct vxge_hw_mempool*
-__vxge_hw_mempool_create(
- struct __vxge_hw_device *devh,
- u32 memblock_size,
- u32 item_size,
- u32 private_size,
- u32 items_initial,
- u32 items_max,
- struct vxge_hw_mempool_cbs *mp_callback,
- void *userdata);
-
-struct __vxge_hw_channel*
-__vxge_hw_channel_allocate(struct __vxge_hw_vpath_handle *vph,
- enum __vxge_hw_channel_type type, u32 length,
- u32 per_dtr_space, void *userdata);
-
-void
-__vxge_hw_channel_free(
- struct __vxge_hw_channel *channel);
-
-enum vxge_hw_status
-__vxge_hw_channel_initialize(
- struct __vxge_hw_channel *channel);
-
-enum vxge_hw_status
-__vxge_hw_channel_reset(
- struct __vxge_hw_channel *channel);
-
/*
* __vxge_hw_fifo_txdl_priv - Return the max fragments allocated
* for the fifo.
@@ -2065,9 +1938,6 @@ enum vxge_hw_status vxge_hw_vpath_open(
struct vxge_hw_vpath_attr *attr,
struct __vxge_hw_vpath_handle **vpath_handle);
-enum vxge_hw_status
-__vxge_hw_device_vpath_reset_in_prog_check(u64 __iomem *vpath_rst_in_prog);
-
enum vxge_hw_status vxge_hw_vpath_close(
struct __vxge_hw_vpath_handle *vpath_handle);
@@ -2089,54 +1959,9 @@ enum vxge_hw_status vxge_hw_vpath_mtu_set(
struct __vxge_hw_vpath_handle *vpath_handle,
u32 new_mtu);
-enum vxge_hw_status vxge_hw_vpath_stats_enable(
- struct __vxge_hw_vpath_handle *vpath_handle);
-
-enum vxge_hw_status
-__vxge_hw_vpath_stats_access(
- struct __vxge_hw_virtualpath *vpath,
- u32 operation,
- u32 offset,
- u64 *stat);
-
-enum vxge_hw_status
-__vxge_hw_vpath_xmac_tx_stats_get(
- struct __vxge_hw_virtualpath *vpath,
- struct vxge_hw_xmac_vpath_tx_stats *vpath_tx_stats);
-
-enum vxge_hw_status
-__vxge_hw_vpath_xmac_rx_stats_get(
- struct __vxge_hw_virtualpath *vpath,
- struct vxge_hw_xmac_vpath_rx_stats *vpath_rx_stats);
-
-enum vxge_hw_status
-__vxge_hw_vpath_stats_get(
- struct __vxge_hw_virtualpath *vpath,
- struct vxge_hw_vpath_stats_hw_info *hw_stats);
-
void
vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_vpath_handle *vp);
-enum vxge_hw_status
-__vxge_hw_device_vpath_config_check(struct vxge_hw_vp_config *vp_config);
-
-void
-__vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev);
-
-enum vxge_hw_status
-__vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg);
-
-enum vxge_hw_status
-__vxge_hw_vpath_swapper_set(struct vxge_hw_vpath_reg __iomem *vpath_reg);
-
-enum vxge_hw_status
-__vxge_hw_kdfc_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg,
- struct vxge_hw_vpath_reg __iomem *vpath_reg);
-
-enum vxge_hw_status
-__vxge_hw_device_register_poll(
- void __iomem *reg,
- u64 mask, u32 max_millis);
#ifndef readq
static inline u64 readq(void __iomem *addr)
@@ -2168,62 +1993,12 @@ static inline void __vxge_hw_pio_mem_write32_lower(u32 val, void __iomem *addr)
writel(val, addr);
}
-static inline enum vxge_hw_status
-__vxge_hw_pio_mem_write64(u64 val64, void __iomem *addr,
- u64 mask, u32 max_millis)
-{
- enum vxge_hw_status status = VXGE_HW_OK;
-
- __vxge_hw_pio_mem_write32_lower((u32)vxge_bVALn(val64, 32, 32), addr);
- wmb();
- __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32), addr);
- wmb();
-
- status = __vxge_hw_device_register_poll(addr, mask, max_millis);
- return status;
-}
-
-struct vxge_hw_toc_reg __iomem *
-__vxge_hw_device_toc_get(void __iomem *bar0);
-
-enum vxge_hw_status
-__vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev);
-
-void
-__vxge_hw_device_id_get(struct __vxge_hw_device *hldev);
-
-void
-__vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev);
-
enum vxge_hw_status
vxge_hw_device_flick_link_led(struct __vxge_hw_device *devh, u64 on_off);
enum vxge_hw_status
-__vxge_hw_device_initialize(struct __vxge_hw_device *hldev);
-
-enum vxge_hw_status
-__vxge_hw_vpath_pci_read(
- struct __vxge_hw_virtualpath *vpath,
- u32 phy_func_0,
- u32 offset,
- u32 *val);
-
-enum vxge_hw_status
-__vxge_hw_vpath_addr_get(
- u32 vp_id,
- struct vxge_hw_vpath_reg __iomem *vpath_reg,
- u8 (macaddr)[ETH_ALEN],
- u8 (macaddr_mask)[ETH_ALEN]);
-
-u32
-__vxge_hw_vpath_func_id_get(
- u32 vp_id, struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg);
-
-enum vxge_hw_status
-__vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath);
-
-enum vxge_hw_status
vxge_hw_vpath_strip_fcs_check(struct __vxge_hw_device *hldev, u64 vpath_mask);
+
/**
* vxge_debug
* @level: level of debug verbosity.
diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c
index 05679e306fdd..b67746eef923 100644
--- a/drivers/net/vxge/vxge-ethtool.c
+++ b/drivers/net/vxge/vxge-ethtool.c
@@ -1142,7 +1142,7 @@ static const struct ethtool_ops vxge_ethtool_ops = {
.get_ethtool_stats = vxge_get_ethtool_stats,
};
-void initialize_ethtool_ops(struct net_device *ndev)
+void vxge_initialize_ethtool_ops(struct net_device *ndev)
{
SET_ETHTOOL_OPS(ndev, &vxge_ethtool_ops);
}
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c
index c7c5605b3728..813829f3d024 100644
--- a/drivers/net/vxge/vxge-main.c
+++ b/drivers/net/vxge/vxge-main.c
@@ -82,6 +82,16 @@ module_param_array(bw_percentage, uint, NULL, 0);
static struct vxge_drv_config *driver_config;
+static enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev,
+ struct macInfo *mac);
+static enum vxge_hw_status vxge_del_mac_addr(struct vxgedev *vdev,
+ struct macInfo *mac);
+static int vxge_mac_list_add(struct vxge_vpath *vpath, struct macInfo *mac);
+static int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac);
+static enum vxge_hw_status vxge_restore_vpath_vid_table(struct vxge_vpath *vpath);
+static enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath);
+static enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev);
+
static inline int is_vxge_card_up(struct vxgedev *vdev)
{
return test_bit(__VXGE_STATE_CARD_UP, &vdev->state);
@@ -138,7 +148,7 @@ static inline void VXGE_COMPLETE_ALL_RX(struct vxgedev *vdev)
* This function is called during interrupt context to notify link up state
* change.
*/
-void
+static void
vxge_callback_link_up(struct __vxge_hw_device *hldev)
{
struct net_device *dev = hldev->ndev;
@@ -162,7 +172,7 @@ vxge_callback_link_up(struct __vxge_hw_device *hldev)
* This function is called during interrupt context to notify link down state
* change.
*/
-void
+static void
vxge_callback_link_down(struct __vxge_hw_device *hldev)
{
struct net_device *dev = hldev->ndev;
@@ -354,7 +364,7 @@ static inline void vxge_post(int *dtr_cnt, void **first_dtr,
* If the interrupt is because of a received frame or if the receive ring
* contains fresh as yet un-processed frames, this function is called.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
u8 t_code, void *userdata)
{
@@ -501,7 +511,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
ext_info.l4_cksum == VXGE_HW_L4_CKSUM_OK)
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
vxge_rx_complete(ring, skb, ext_info.vlan,
pkt_length, &ext_info);
@@ -531,7 +541,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
* freed and frees all skbs whose data have already DMA'ed into the NICs
* internal memory.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
enum vxge_hw_fifo_tcode t_code, void *userdata,
struct sk_buff ***skb_ptr, int nr_skb, int *more)
@@ -822,7 +832,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
dev->name, __func__, __LINE__,
fifo_hw, dtr, dtr_priv);
- if (vdev->vlgrp && vlan_tx_tag_present(skb)) {
+ if (vlan_tx_tag_present(skb)) {
u16 vlan_tag = vlan_tx_tag_get(skb);
vxge_hw_fifo_txdl_vlan_set(dtr, vlan_tag);
}
@@ -1246,7 +1256,7 @@ static int vxge_set_mac_addr(struct net_device *dev, void *p)
*
* Enables the interrupts for the vpath
*/
-void vxge_vpath_intr_enable(struct vxgedev *vdev, int vp_id)
+static void vxge_vpath_intr_enable(struct vxgedev *vdev, int vp_id)
{
struct vxge_vpath *vpath = &vdev->vpaths[vp_id];
int msix_id = 0;
@@ -1279,7 +1289,7 @@ void vxge_vpath_intr_enable(struct vxgedev *vdev, int vp_id)
*
* Disables the interrupts for the vpath
*/
-void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id)
+static void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id)
{
struct vxge_vpath *vpath = &vdev->vpaths[vp_id];
int msix_id;
@@ -1553,7 +1563,7 @@ out:
*
* driver may reset the chip on events of serr, eccerr, etc
*/
-int vxge_reset(struct vxgedev *vdev)
+static int vxge_reset(struct vxgedev *vdev)
{
return do_vxge_reset(vdev, VXGE_LL_FULL_RESET);
}
@@ -1724,7 +1734,7 @@ static enum vxge_hw_status vxge_rth_configure(struct vxgedev *vdev)
return status;
}
-int vxge_mac_list_add(struct vxge_vpath *vpath, struct macInfo *mac)
+static int vxge_mac_list_add(struct vxge_vpath *vpath, struct macInfo *mac)
{
struct vxge_mac_addrs *new_mac_entry;
u8 *mac_address = NULL;
@@ -1757,7 +1767,8 @@ int vxge_mac_list_add(struct vxge_vpath *vpath, struct macInfo *mac)
}
/* Add a mac address to DA table */
-enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev, struct macInfo *mac)
+static enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev,
+ struct macInfo *mac)
{
enum vxge_hw_status status = VXGE_HW_OK;
struct vxge_vpath *vpath;
@@ -1782,7 +1793,7 @@ enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev, struct macInfo *mac)
return status;
}
-int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac)
+static int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac)
{
struct list_head *entry, *next;
u64 del_mac = 0;
@@ -1807,7 +1818,8 @@ int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac)
return FALSE;
}
/* delete a mac address from DA table */
-enum vxge_hw_status vxge_del_mac_addr(struct vxgedev *vdev, struct macInfo *mac)
+static enum vxge_hw_status vxge_del_mac_addr(struct vxgedev *vdev,
+ struct macInfo *mac)
{
enum vxge_hw_status status = VXGE_HW_OK;
struct vxge_vpath *vpath;
@@ -1854,7 +1866,7 @@ static vxge_search_mac_addr_in_da_table(struct vxge_vpath *vpath,
}
/* Store all vlan ids from the list to the vid table */
-enum vxge_hw_status vxge_restore_vpath_vid_table(struct vxge_vpath *vpath)
+static enum vxge_hw_status vxge_restore_vpath_vid_table(struct vxge_vpath *vpath)
{
enum vxge_hw_status status = VXGE_HW_OK;
struct vxgedev *vdev = vpath->vdev;
@@ -1862,7 +1874,7 @@ enum vxge_hw_status vxge_restore_vpath_vid_table(struct vxge_vpath *vpath)
if (vdev->vlgrp && vpath->is_open) {
- for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ for (vid = 0; vid < VLAN_N_VID; vid++) {
if (!vlan_group_get_device(vdev->vlgrp, vid))
continue;
/* Add these vlan to the vid table */
@@ -1874,7 +1886,7 @@ enum vxge_hw_status vxge_restore_vpath_vid_table(struct vxge_vpath *vpath)
}
/* Store all mac addresses from the list to the DA table */
-enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath)
+static enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath)
{
enum vxge_hw_status status = VXGE_HW_OK;
struct macInfo mac_info;
@@ -1916,7 +1928,7 @@ enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath)
}
/* reset vpaths */
-enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev)
+static enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev)
{
enum vxge_hw_status status = VXGE_HW_OK;
struct vxge_vpath *vpath;
@@ -1948,7 +1960,7 @@ enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev)
}
/* close vpaths */
-void vxge_close_vpaths(struct vxgedev *vdev, int index)
+static void vxge_close_vpaths(struct vxgedev *vdev, int index)
{
struct vxge_vpath *vpath;
int i;
@@ -1966,7 +1978,7 @@ void vxge_close_vpaths(struct vxgedev *vdev, int index)
}
/* open vpaths */
-int vxge_open_vpaths(struct vxgedev *vdev)
+static int vxge_open_vpaths(struct vxgedev *vdev)
{
struct vxge_hw_vpath_attr attr;
enum vxge_hw_status status;
@@ -2159,8 +2171,8 @@ start:
/* Alarm MSIX Vectors count */
vdev->intr_cnt++;
- vdev->entries = kzalloc(vdev->intr_cnt * sizeof(struct msix_entry),
- GFP_KERNEL);
+ vdev->entries = kcalloc(vdev->intr_cnt, sizeof(struct msix_entry),
+ GFP_KERNEL);
if (!vdev->entries) {
vxge_debug_init(VXGE_ERR,
"%s: memory allocation failed",
@@ -2169,9 +2181,9 @@ start:
goto alloc_entries_failed;
}
- vdev->vxge_entries =
- kzalloc(vdev->intr_cnt * sizeof(struct vxge_msix_entry),
- GFP_KERNEL);
+ vdev->vxge_entries = kcalloc(vdev->intr_cnt,
+ sizeof(struct vxge_msix_entry),
+ GFP_KERNEL);
if (!vdev->vxge_entries) {
vxge_debug_init(VXGE_ERR, "%s: memory allocation failed",
VXGE_DRIVER_NAME);
@@ -2517,7 +2529,7 @@ static void vxge_poll_vp_lockup(unsigned long data)
* Return value: '0' on success and an appropriate (-)ve integer as
* defined in errno.h file on failure.
*/
-int
+static int
vxge_open(struct net_device *dev)
{
enum vxge_hw_status status;
@@ -2721,7 +2733,7 @@ out0:
}
/* Loop throught the mac address list and delete all the entries */
-void vxge_free_mac_add_list(struct vxge_vpath *vpath)
+static void vxge_free_mac_add_list(struct vxge_vpath *vpath)
{
struct list_head *entry, *next;
@@ -2745,7 +2757,7 @@ static void vxge_napi_del_all(struct vxgedev *vdev)
}
}
-int do_vxge_close(struct net_device *dev, int do_io)
+static int do_vxge_close(struct net_device *dev, int do_io)
{
enum vxge_hw_status status;
struct vxgedev *vdev;
@@ -2856,7 +2868,7 @@ int do_vxge_close(struct net_device *dev, int do_io)
* Return value: '0' on success and an appropriate (-)ve integer as
* defined in errno.h file on failure.
*/
-int
+static int
vxge_close(struct net_device *dev)
{
do_vxge_close(dev, 1);
@@ -2914,26 +2926,18 @@ static int vxge_change_mtu(struct net_device *dev, int new_mtu)
}
/**
- * vxge_get_stats
+ * vxge_get_stats64
* @dev: pointer to the device structure
+ * @stats: pointer to struct rtnl_link_stats64
*
- * Updates the device statistics structure. This function updates the device
- * statistics structure in the net_device structure and returns a pointer
- * to the same.
*/
-static struct net_device_stats *
-vxge_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *
+vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
{
- struct vxgedev *vdev;
- struct net_device_stats *net_stats;
+ struct vxgedev *vdev = netdev_priv(dev);
int k;
- vdev = netdev_priv(dev);
-
- net_stats = &vdev->stats.net_stats;
-
- memset(net_stats, 0, sizeof(struct net_device_stats));
-
+ /* net_stats already zeroed by caller */
for (k = 0; k < vdev->no_of_vpath; k++) {
net_stats->rx_packets += vdev->vpaths[k].ring.stats.rx_frms;
net_stats->rx_bytes += vdev->vpaths[k].ring.stats.rx_bytes;
@@ -3102,7 +3106,7 @@ vxge_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
static const struct net_device_ops vxge_netdev_ops = {
.ndo_open = vxge_open,
.ndo_stop = vxge_close,
- .ndo_get_stats = vxge_get_stats,
+ .ndo_get_stats64 = vxge_get_stats64,
.ndo_start_xmit = vxge_xmit,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_multicast_list = vxge_set_multicast,
@@ -3121,10 +3125,10 @@ static const struct net_device_ops vxge_netdev_ops = {
#endif
};
-int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
- struct vxge_config *config,
- int high_dma, int no_of_vpath,
- struct vxgedev **vdev_out)
+static int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
+ struct vxge_config *config,
+ int high_dma, int no_of_vpath,
+ struct vxgedev **vdev_out)
{
struct net_device *ndev;
enum vxge_hw_status status = VXGE_HW_OK;
@@ -3172,7 +3176,7 @@ int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
ndev->watchdog_timeo = VXGE_LL_WATCH_DOG_TIMEOUT;
- initialize_ethtool_ops(ndev);
+ vxge_initialize_ethtool_ops(ndev);
/* Allocate memory for vpath */
vdev->vpaths = kzalloc((sizeof(struct vxge_vpath)) *
@@ -3257,7 +3261,7 @@ _out0:
*
* This function will unregister and free network device
*/
-void
+static void
vxge_device_unregister(struct __vxge_hw_device *hldev)
{
struct vxgedev *vdev;
diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h
index 2e3b064b8e4b..de64536cb7d0 100644
--- a/drivers/net/vxge/vxge-main.h
+++ b/drivers/net/vxge/vxge-main.h
@@ -172,7 +172,6 @@ struct vxge_msix_entry {
struct vxge_sw_stats {
/* Network Stats (interface stats) */
- struct net_device_stats net_stats;
/* Tx */
u64 tx_frms;
@@ -397,64 +396,7 @@ struct vxge_tx_priv {
mod_timer(&timer, (jiffies + exp)); \
} while (0);
-int __devinit vxge_device_register(struct __vxge_hw_device *devh,
- struct vxge_config *config,
- int high_dma, int no_of_vpath,
- struct vxgedev **vdev);
-
-void vxge_device_unregister(struct __vxge_hw_device *devh);
-
-void vxge_vpath_intr_enable(struct vxgedev *vdev, int vp_id);
-
-void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id);
-
-void vxge_callback_link_up(struct __vxge_hw_device *devh);
-
-void vxge_callback_link_down(struct __vxge_hw_device *devh);
-
-enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev,
- struct macInfo *mac);
-
-int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac);
-
-int vxge_reset(struct vxgedev *vdev);
-
-enum vxge_hw_status
-vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
- u8 t_code, void *userdata);
-
-enum vxge_hw_status
-vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
- enum vxge_hw_fifo_tcode t_code, void *userdata,
- struct sk_buff ***skb_ptr, int nr_skbs, int *more);
-
-int vxge_close(struct net_device *dev);
-
-int vxge_open(struct net_device *dev);
-
-void vxge_close_vpaths(struct vxgedev *vdev, int index);
-
-int vxge_open_vpaths(struct vxgedev *vdev);
-
-enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev);
-
-enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev,
- struct macInfo *mac);
-
-enum vxge_hw_status vxge_del_mac_addr(struct vxgedev *vdev,
- struct macInfo *mac);
-
-int vxge_mac_list_add(struct vxge_vpath *vpath,
- struct macInfo *mac);
-
-void vxge_free_mac_add_list(struct vxge_vpath *vpath);
-
-enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath);
-
-enum vxge_hw_status vxge_restore_vpath_vid_table(struct vxge_vpath *vpath);
-
-int do_vxge_close(struct net_device *dev, int do_io);
-extern void initialize_ethtool_ops(struct net_device *ndev);
+extern void vxge_initialize_ethtool_ops(struct net_device *ndev);
/**
* #define VXGE_DEBUG_INIT: debug for initialization functions
* #define VXGE_DEBUG_TX : debug transmit related functions
diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c
index cedf08f99cb3..4bdb611a6842 100644
--- a/drivers/net/vxge/vxge-traffic.c
+++ b/drivers/net/vxge/vxge-traffic.c
@@ -17,6 +17,13 @@
#include "vxge-config.h"
#include "vxge-main.h"
+static enum vxge_hw_status
+__vxge_hw_device_handle_error(struct __vxge_hw_device *hldev,
+ u32 vp_id, enum vxge_hw_event type);
+static enum vxge_hw_status
+__vxge_hw_vpath_alarm_process(struct __vxge_hw_virtualpath *vpath,
+ u32 skip_alarms);
+
/*
* vxge_hw_vpath_intr_enable - Enable vpath interrupts.
* @vp: Virtual Path handle.
@@ -513,7 +520,7 @@ exit:
* Link up indication handler. The function is invoked by HW when
* Titan indicates that the link is up for programmable amount of time.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_device_handle_link_up_ind(struct __vxge_hw_device *hldev)
{
/*
@@ -538,7 +545,7 @@ exit:
* Link down indication handler. The function is invoked by HW when
* Titan indicates that the link is down.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_device_handle_link_down_ind(struct __vxge_hw_device *hldev)
{
/*
@@ -564,7 +571,7 @@ exit:
*
* Handle error.
*/
-enum vxge_hw_status
+static enum vxge_hw_status
__vxge_hw_device_handle_error(
struct __vxge_hw_device *hldev,
u32 vp_id,
@@ -646,7 +653,7 @@ void vxge_hw_device_clear_tx_rx(struct __vxge_hw_device *hldev)
* it swaps the reserve and free arrays.
*
*/
-enum vxge_hw_status
+static enum vxge_hw_status
vxge_hw_channel_dtr_alloc(struct __vxge_hw_channel *channel, void **dtrh)
{
void **tmp_arr;
@@ -692,7 +699,8 @@ _alloc_after_swap:
* Posts a dtr to work array.
*
*/
-void vxge_hw_channel_dtr_post(struct __vxge_hw_channel *channel, void *dtrh)
+static void vxge_hw_channel_dtr_post(struct __vxge_hw_channel *channel,
+ void *dtrh)
{
vxge_assert(channel->work_arr[channel->post_index] == NULL);
@@ -1658,37 +1666,6 @@ exit:
}
/**
- * vxge_hw_vpath_vid_get_next - Get the next vid entry for this vpath
- * from vlan id table.
- * @vp: Vpath handle.
- * @vid: Buffer to return vlan id
- *
- * Returns the next vlan id in the list for this vpath.
- * see also: vxge_hw_vpath_vid_get
- *
- */
-enum vxge_hw_status
-vxge_hw_vpath_vid_get_next(struct __vxge_hw_vpath_handle *vp, u64 *vid)
-{
- u64 data;
- enum vxge_hw_status status = VXGE_HW_OK;
-
- if (vp == NULL) {
- status = VXGE_HW_ERR_INVALID_HANDLE;
- goto exit;
- }
-
- status = __vxge_hw_vpath_rts_table_get(vp,
- VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_NEXT_ENTRY,
- VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_VID,
- 0, vid, &data);
-
- *vid = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_VLAN_ID(*vid);
-exit:
- return status;
-}
-
-/**
* vxge_hw_vpath_vid_delete - Delete the vlan id entry for this vpath
* to vlan id table.
* @vp: Vpath handle.
@@ -1898,9 +1875,9 @@ exit:
* Process vpath alarms.
*
*/
-enum vxge_hw_status __vxge_hw_vpath_alarm_process(
- struct __vxge_hw_virtualpath *vpath,
- u32 skip_alarms)
+static enum vxge_hw_status
+__vxge_hw_vpath_alarm_process(struct __vxge_hw_virtualpath *vpath,
+ u32 skip_alarms)
{
u64 val64;
u64 alarm_status;
@@ -2265,36 +2242,6 @@ vxge_hw_vpath_msix_mask(struct __vxge_hw_vpath_handle *vp, int msix_id)
}
/**
- * vxge_hw_vpath_msix_clear - Clear MSIX Vector.
- * @vp: Virtual Path handle.
- * @msix_id: MSI ID
- *
- * The function clears the msix interrupt for the given msix_id
- *
- * Returns: 0,
- * Otherwise, VXGE_HW_ERR_WRONG_IRQ if the msix index is out of range
- * status.
- * See also:
- */
-void
-vxge_hw_vpath_msix_clear(struct __vxge_hw_vpath_handle *vp, int msix_id)
-{
- struct __vxge_hw_device *hldev = vp->vpath->hldev;
- if (hldev->config.intr_mode ==
- VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) {
- __vxge_hw_pio_mem_write32_upper(
- (u32)vxge_bVALn(vxge_mBIT(msix_id >> 2), 0, 32),
- &hldev->common_reg->
- clr_msix_one_shot_vec[msix_id%4]);
- } else {
- __vxge_hw_pio_mem_write32_upper(
- (u32)vxge_bVALn(vxge_mBIT(msix_id >> 2), 0, 32),
- &hldev->common_reg->
- clear_msix_mask_vect[msix_id%4]);
- }
-}
-
-/**
* vxge_hw_vpath_msix_unmask - Unmask the MSIX Vector.
* @vp: Virtual Path handle.
* @msix_id: MSI ID
@@ -2316,22 +2263,6 @@ vxge_hw_vpath_msix_unmask(struct __vxge_hw_vpath_handle *vp, int msix_id)
}
/**
- * vxge_hw_vpath_msix_mask_all - Mask all MSIX vectors for the vpath.
- * @vp: Virtual Path handle.
- *
- * The function masks all msix interrupt for the given vpath
- *
- */
-void
-vxge_hw_vpath_msix_mask_all(struct __vxge_hw_vpath_handle *vp)
-{
-
- __vxge_hw_pio_mem_write32_upper(
- (u32)vxge_bVALn(vxge_mBIT(vp->vpath->vp_id), 0, 32),
- &vp->vpath->hldev->common_reg->set_msix_mask_all_vect);
-}
-
-/**
* vxge_hw_vpath_inta_mask_tx_rx - Mask Tx and Rx interrupts.
* @vp: Virtual Path handle.
*
diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h
index 6fa07d13798e..9890d4d596d0 100644
--- a/drivers/net/vxge/vxge-traffic.h
+++ b/drivers/net/vxge/vxge-traffic.h
@@ -1749,14 +1749,6 @@ vxge_hw_mrpcim_stats_access(
u64 *stat);
enum vxge_hw_status
-vxge_hw_device_xmac_aggr_stats_get(struct __vxge_hw_device *devh, u32 port,
- struct vxge_hw_xmac_aggr_stats *aggr_stats);
-
-enum vxge_hw_status
-vxge_hw_device_xmac_port_stats_get(struct __vxge_hw_device *devh, u32 port,
- struct vxge_hw_xmac_port_stats *port_stats);
-
-enum vxge_hw_status
vxge_hw_device_xmac_stats_get(struct __vxge_hw_device *devh,
struct vxge_hw_xmac_stats *xmac_stats);
@@ -2117,49 +2109,10 @@ struct __vxge_hw_ring_rxd_priv {
#endif
};
-/* ========================= RING PRIVATE API ============================= */
-u64
-__vxge_hw_ring_first_block_address_get(
- struct __vxge_hw_ring *ringh);
-
-enum vxge_hw_status
-__vxge_hw_ring_create(
- struct __vxge_hw_vpath_handle *vpath_handle,
- struct vxge_hw_ring_attr *attr);
-
-enum vxge_hw_status
-__vxge_hw_ring_abort(
- struct __vxge_hw_ring *ringh);
-
-enum vxge_hw_status
-__vxge_hw_ring_reset(
- struct __vxge_hw_ring *ringh);
-
-enum vxge_hw_status
-__vxge_hw_ring_delete(
- struct __vxge_hw_vpath_handle *vpath_handle);
-
/* ========================= FIFO PRIVATE API ============================= */
struct vxge_hw_fifo_attr;
-enum vxge_hw_status
-__vxge_hw_fifo_create(
- struct __vxge_hw_vpath_handle *vpath_handle,
- struct vxge_hw_fifo_attr *attr);
-
-enum vxge_hw_status
-__vxge_hw_fifo_abort(
- struct __vxge_hw_fifo *fifoh);
-
-enum vxge_hw_status
-__vxge_hw_fifo_reset(
- struct __vxge_hw_fifo *ringh);
-
-enum vxge_hw_status
-__vxge_hw_fifo_delete(
- struct __vxge_hw_vpath_handle *vpath_handle);
-
struct vxge_hw_mempool_cbs {
void (*item_func_alloc)(
struct vxge_hw_mempool *mempoolh,
@@ -2169,10 +2122,6 @@ struct vxge_hw_mempool_cbs {
u32 is_last);
};
-void
-__vxge_hw_mempool_destroy(
- struct vxge_hw_mempool *mempool);
-
#define VXGE_HW_VIRTUAL_PATH_HANDLE(vpath) \
((struct __vxge_hw_vpath_handle *)(vpath)->vpath_handles.next)
@@ -2195,61 +2144,10 @@ __vxge_hw_vpath_rts_table_set(
u64 data2);
enum vxge_hw_status
-__vxge_hw_vpath_reset(
- struct __vxge_hw_device *devh,
- u32 vp_id);
-
-enum vxge_hw_status
-__vxge_hw_vpath_sw_reset(
- struct __vxge_hw_device *devh,
- u32 vp_id);
-
-enum vxge_hw_status
__vxge_hw_vpath_enable(
struct __vxge_hw_device *devh,
u32 vp_id);
-void
-__vxge_hw_vpath_prc_configure(
- struct __vxge_hw_device *devh,
- u32 vp_id);
-
-enum vxge_hw_status
-__vxge_hw_vpath_kdfc_configure(
- struct __vxge_hw_device *devh,
- u32 vp_id);
-
-enum vxge_hw_status
-__vxge_hw_vpath_mac_configure(
- struct __vxge_hw_device *devh,
- u32 vp_id);
-
-enum vxge_hw_status
-__vxge_hw_vpath_tim_configure(
- struct __vxge_hw_device *devh,
- u32 vp_id);
-
-enum vxge_hw_status
-__vxge_hw_vpath_initialize(
- struct __vxge_hw_device *devh,
- u32 vp_id);
-
-enum vxge_hw_status
-__vxge_hw_vp_initialize(
- struct __vxge_hw_device *devh,
- u32 vp_id,
- struct vxge_hw_vp_config *config);
-
-void
-__vxge_hw_vp_terminate(
- struct __vxge_hw_device *devh,
- u32 vp_id);
-
-enum vxge_hw_status
-__vxge_hw_vpath_alarm_process(
- struct __vxge_hw_virtualpath *vpath,
- u32 skip_alarms);
-
void vxge_hw_device_intr_enable(
struct __vxge_hw_device *devh);
@@ -2321,11 +2219,6 @@ vxge_hw_vpath_vid_get(
u64 *vid);
enum vxge_hw_status
-vxge_hw_vpath_vid_get_next(
- struct __vxge_hw_vpath_handle *vpath_handle,
- u64 *vid);
-
-enum vxge_hw_status
vxge_hw_vpath_vid_delete(
struct __vxge_hw_vpath_handle *vpath_handle,
u64 vid);
@@ -2387,16 +2280,9 @@ vxge_hw_vpath_msix_mask(struct __vxge_hw_vpath_handle *vpath_handle,
void vxge_hw_device_flush_io(struct __vxge_hw_device *devh);
void
-vxge_hw_vpath_msix_clear(struct __vxge_hw_vpath_handle *vpath_handle,
- int msix_id);
-
-void
vxge_hw_vpath_msix_unmask(struct __vxge_hw_vpath_handle *vpath_handle,
int msix_id);
-void
-vxge_hw_vpath_msix_mask_all(struct __vxge_hw_vpath_handle *vpath_handle);
-
enum vxge_hw_status vxge_hw_vpath_intr_enable(
struct __vxge_hw_vpath_handle *vpath_handle);
@@ -2415,12 +2301,6 @@ vxge_hw_channel_msix_mask(struct __vxge_hw_channel *channelh, int msix_id);
void
vxge_hw_channel_msix_unmask(struct __vxge_hw_channel *channelh, int msix_id);
-enum vxge_hw_status
-vxge_hw_channel_dtr_alloc(struct __vxge_hw_channel *channel, void **dtrh);
-
-void
-vxge_hw_channel_dtr_post(struct __vxge_hw_channel *channel, void *dtrh);
-
void
vxge_hw_channel_dtr_try_complete(struct __vxge_hw_channel *channel,
void **dtrh);
@@ -2436,18 +2316,4 @@ vxge_hw_channel_dtr_count(struct __vxge_hw_channel *channel);
void
vxge_hw_vpath_tti_ci_set(struct __vxge_hw_device *hldev, u32 vp_id);
-/* ========================== PRIVATE API ================================= */
-
-enum vxge_hw_status
-__vxge_hw_device_handle_link_up_ind(struct __vxge_hw_device *hldev);
-
-enum vxge_hw_status
-__vxge_hw_device_handle_link_down_ind(struct __vxge_hw_device *hldev);
-
-enum vxge_hw_status
-__vxge_hw_device_handle_error(
- struct __vxge_hw_device *hldev,
- u32 vp_id,
- enum vxge_hw_event type);
-
#endif
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index d08ce6a264cb..423eb26386c8 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -409,7 +409,7 @@ config CYCLADES_SYNC
tristate "Cyclom 2X(tm) cards (EXPERIMENTAL)"
depends on WAN_ROUTER_DRIVERS && (PCI || ISA)
---help---
- Cyclom 2X from Cyclades Corporation <http://www.cyclades.com/> is an
+ Cyclom 2X from Cyclades Corporation <http://www.avocent.com/> is an
intelligent multiprotocol WAN adapter with data transfer rates up to
512 Kbps. These cards support the X.25 and SNA related protocols.
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
index 0bd898c94759..4ac85a09c5a6 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -264,7 +264,7 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
new_line.clock_type != CLOCK_TXFROMRX &&
new_line.clock_type != CLOCK_INT &&
new_line.clock_type != CLOCK_TXINT)
- return -EINVAL; /* No such clock setting */
+ return -EINVAL; /* No such clock setting */
if (new_line.loopback != 0 && new_line.loopback != 1)
return -EINVAL;
diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c
index a5ddc6c8963e..164c3624ba89 100644
--- a/drivers/net/wan/cycx_drv.c
+++ b/drivers/net/wan/cycx_drv.c
@@ -73,7 +73,7 @@ static int reset_cyc2x(void __iomem *addr);
static int detect_cyc2x(void __iomem *addr);
/* Miscellaneous functions */
-static int get_option_index(long *optlist, long optval);
+static int get_option_index(const long *optlist, long optval);
static u16 checksum(u8 *buf, u32 len);
#define wait_cyc(addr) cycx_exec(addr + CMD_OFFSET)
@@ -81,23 +81,23 @@ static u16 checksum(u8 *buf, u32 len);
/* Global Data */
/* private data */
-static char modname[] = "cycx_drv";
-static char fullname[] = "Cyclom 2X Support Module";
-static char copyright[] = "(c) 1998-2003 Arnaldo Carvalho de Melo "
+static const char modname[] = "cycx_drv";
+static const char fullname[] = "Cyclom 2X Support Module";
+static const char copyright[] = "(c) 1998-2003 Arnaldo Carvalho de Melo "
"<acme@conectiva.com.br>";
/* Hardware configuration options.
* These are arrays of configuration options used by verification routines.
* The first element of each array is its size (i.e. number of options).
*/
-static long cyc2x_dpmbase_options[] = {
+static const long cyc2x_dpmbase_options[] = {
20,
0xA0000, 0xA4000, 0xA8000, 0xAC000, 0xB0000, 0xB4000, 0xB8000,
0xBC000, 0xC0000, 0xC4000, 0xC8000, 0xCC000, 0xD0000, 0xD4000,
0xD8000, 0xDC000, 0xE0000, 0xE4000, 0xE8000, 0xEC000
};
-static long cycx_2x_irq_options[] = { 7, 3, 5, 9, 10, 11, 12, 15 };
+static const long cycx_2x_irq_options[] = { 7, 3, 5, 9, 10, 11, 12, 15 };
/* Kernel Loadable Module Entry Points */
/* Module 'insert' entry point.
@@ -529,7 +529,7 @@ static int detect_cyc2x(void __iomem *addr)
/* Miscellaneous */
/* Get option's index into the options list.
* Return option's index (1 .. N) or zero if option is invalid. */
-static int get_option_index(long *optlist, long optval)
+static int get_option_index(const long *optlist, long optval)
{
int i = 1;
diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
index a0e8611ad8e8..859dba9b972e 100644
--- a/drivers/net/wan/cycx_main.c
+++ b/drivers/net/wan/cycx_main.c
@@ -81,9 +81,9 @@ static irqreturn_t cycx_isr(int irq, void *dev_id);
*/
/* private data */
-static char cycx_drvname[] = "cyclomx";
-static char cycx_fullname[] = "CYCLOM 2X(tm) Sync Card Driver";
-static char cycx_copyright[] = "(c) 1998-2003 Arnaldo Carvalho de Melo "
+static const char cycx_drvname[] = "cyclomx";
+static const char cycx_fullname[] = "CYCLOM 2X(tm) Sync Card Driver";
+static const char cycx_copyright[] = "(c) 1998-2003 Arnaldo Carvalho de Melo "
"<acme@conectiva.com.br>";
static int cycx_ncards = CONFIG_CYCX_CARDS;
static struct cycx_device *cycx_card_array; /* adapter data space */
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 421d0715310e..1481a446fefb 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -97,11 +97,11 @@ static int dlci_header(struct sk_buff *skb, struct net_device *dev,
dest = skb_push(skb, hlen);
if (!dest)
- return(0);
+ return 0;
memcpy(dest, &hdr, hlen);
- return(hlen);
+ return hlen;
}
static void dlci_receive(struct sk_buff *skb, struct net_device *dev)
@@ -211,14 +211,14 @@ static int dlci_config(struct net_device *dev, struct dlci_conf __user *conf, in
if (copy_from_user(&config, conf, sizeof(struct dlci_conf)))
return -EFAULT;
if (config.flags & ~DLCI_VALID_FLAGS)
- return(-EINVAL);
+ return -EINVAL;
memcpy(&dlp->config, &config, sizeof(struct dlci_conf));
dlp->configured = 1;
}
err = (*flp->dlci_conf)(dlp->slave, dev, get);
if (err)
- return(err);
+ return err;
if (get)
{
@@ -226,7 +226,7 @@ static int dlci_config(struct net_device *dev, struct dlci_conf __user *conf, in
return -EFAULT;
}
- return(0);
+ return 0;
}
static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -234,7 +234,7 @@ static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
struct dlci_local *dlp;
if (!capable(CAP_NET_ADMIN))
- return(-EPERM);
+ return -EPERM;
dlp = netdev_priv(dev);
@@ -242,7 +242,7 @@ static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
case DLCI_GET_SLAVE:
if (!*(short *)(dev->dev_addr))
- return(-EINVAL);
+ return -EINVAL;
strncpy(ifr->ifr_slave, dlp->slave->name, sizeof(ifr->ifr_slave));
break;
@@ -250,15 +250,15 @@ static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case DLCI_GET_CONF:
case DLCI_SET_CONF:
if (!*(short *)(dev->dev_addr))
- return(-EINVAL);
+ return -EINVAL;
- return(dlci_config(dev, ifr->ifr_data, cmd == DLCI_GET_CONF));
+ return dlci_config(dev, ifr->ifr_data, cmd == DLCI_GET_CONF);
break;
default:
- return(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
}
- return(0);
+ return 0;
}
static int dlci_change_mtu(struct net_device *dev, int new_mtu)
@@ -277,15 +277,15 @@ static int dlci_open(struct net_device *dev)
dlp = netdev_priv(dev);
if (!*(short *)(dev->dev_addr))
- return(-EINVAL);
+ return -EINVAL;
if (!netif_running(dlp->slave))
- return(-ENOTCONN);
+ return -ENOTCONN;
flp = netdev_priv(dlp->slave);
err = (*flp->activate)(dlp->slave, dev);
if (err)
- return(err);
+ return err;
netif_start_queue(dev);
@@ -365,14 +365,14 @@ static int dlci_add(struct dlci_add *dlci)
list_add(&dlp->list, &dlci_devs);
rtnl_unlock();
- return(0);
+ return 0;
err2:
rtnl_unlock();
free_netdev(master);
err1:
dev_put(slave);
- return(err);
+ return err;
}
static int dlci_del(struct dlci_add *dlci)
@@ -385,10 +385,10 @@ static int dlci_del(struct dlci_add *dlci)
/* validate slave device */
master = __dev_get_by_name(&init_net, dlci->devname);
if (!master)
- return(-ENODEV);
+ return -ENODEV;
if (netif_running(master)) {
- return(-EBUSY);
+ return -EBUSY;
}
dlp = netdev_priv(master);
@@ -406,7 +406,7 @@ static int dlci_del(struct dlci_add *dlci)
}
rtnl_unlock();
- return(err);
+ return err;
}
static int dlci_ioctl(unsigned int cmd, void __user *arg)
@@ -415,7 +415,7 @@ static int dlci_ioctl(unsigned int cmd, void __user *arg)
int err;
if (!capable(CAP_NET_ADMIN))
- return(-EPERM);
+ return -EPERM;
if (copy_from_user(&add, arg, sizeof(struct dlci_add)))
return -EFAULT;
@@ -438,7 +438,7 @@ static int dlci_ioctl(unsigned int cmd, void __user *arg)
err = -EINVAL;
}
- return(err);
+ return err;
}
static const struct header_ops dlci_header_ops = {
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index 9937bbab938d..5d4bb615ccce 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -109,7 +109,7 @@ static int hdlc_device_event(struct notifier_block *this, unsigned long event,
return NOTIFY_DONE; /* not an HDLC device */
if (event != NETDEV_CHANGE)
- return NOTIFY_DONE; /* Only interrested in carrier changes */
+ return NOTIFY_DONE; /* Only interested in carrier changes */
on = netif_carrier_ok(dev);
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index b38ffa149aba..b1e5e5b69c2a 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -191,7 +191,8 @@ static int cisco_rx(struct sk_buff *skb)
switch (ntohl (cisco_data->type)) {
case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
- in_dev = dev->ip_ptr;
+ rcu_read_lock();
+ in_dev = __in_dev_get_rcu(dev);
addr = 0;
mask = ~cpu_to_be32(0); /* is the mask correct? */
@@ -211,6 +212,7 @@ static int cisco_rx(struct sk_buff *skb)
cisco_keepalive_send(dev, CISCO_ADDR_REPLY,
addr, mask);
}
+ rcu_read_unlock();
dev_kfree_skb_any(skb);
return NET_RX_SUCCESS;
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index 4d4dc38c7290..7f5bb913c8b9 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -46,7 +46,7 @@
#include <net/x25device.h>
-static char bcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+static const u8 bcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
/* If this number is made larger, check that the temporary string buffer
* in lapbeth_new_device is large enough to store the probe device name.*/
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index e2c6f7f4f51c..70feb84df670 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -1022,7 +1022,7 @@ static int lmc_open(struct net_device *dev)
if (sc->lmc_ok){
lmc_trace(dev, "lmc_open lmc_ok out");
- return (0);
+ return 0;
}
lmc_softreset (sc);
@@ -1105,12 +1105,12 @@ static int lmc_open(struct net_device *dev)
init_timer (&sc->timer);
sc->timer.expires = jiffies + HZ;
sc->timer.data = (unsigned long) dev;
- sc->timer.function = &lmc_watchdog;
+ sc->timer.function = lmc_watchdog;
add_timer (&sc->timer);
lmc_trace(dev, "lmc_open out");
- return (0);
+ return 0;
}
/* Total reset to compensate for the AdTran DSU doing bad things
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c
index 5394b51bdb2f..17d408fe693f 100644
--- a/drivers/net/wan/n2.c
+++ b/drivers/net/wan/n2.c
@@ -282,7 +282,7 @@ static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
new_line.clock_type != CLOCK_TXFROMRX &&
new_line.clock_type != CLOCK_INT &&
new_line.clock_type != CLOCK_TXINT)
- return -EINVAL; /* No such clock setting */
+ return -EINVAL; /* No such clock setting */
if (new_line.loopback != 0 && new_line.loopback != 1)
return -EINVAL;
@@ -379,14 +379,14 @@ static int __init n2_run(unsigned long io, unsigned long irq,
if (request_irq(irq, sca_intr, 0, devname, card)) {
printk(KERN_ERR "n2: could not allocate IRQ\n");
n2_destroy_card(card);
- return(-EBUSY);
+ return -EBUSY;
}
card->irq = irq;
if (!request_mem_region(winbase, USE_WINDOWSIZE, devname)) {
printk(KERN_ERR "n2: could not request RAM window\n");
n2_destroy_card(card);
- return(-EBUSY);
+ return -EBUSY;
}
card->phy_winbase = winbase;
card->winbase = ioremap(winbase, USE_WINDOWSIZE);
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index c6aa66e5b52f..f875cfae3093 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -1,5 +1,5 @@
#define USE_PCI_CLOCK
-static char rcsid[] =
+static const char rcsid[] =
"Revision: 3.4.5 Date: 2002/03/07 ";
/*
@@ -451,11 +451,11 @@ static int dma_get_rx_frame_size(pc300_t * card, int ch)
if ((status & DST_EOM) || (first_bd == card->chan[ch].rx_last_bd)) {
/* Return the size of a good frame or incomplete bad frame
* (dma_buf_read will clean the buffer descriptors in this case). */
- return (rcvd);
+ return rcvd;
}
ptdescr = (card->hw.rambase + cpc_readl(&ptdescr->next));
}
- return (-1);
+ return -1;
}
/*
@@ -557,7 +557,7 @@ static int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb)
cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch),
RX_BD_ADDR(ch, chan->rx_last_bd));
}
- return (rcvd);
+ return rcvd;
}
static void tx_dma_stop(pc300_t * card, int ch)
@@ -1733,7 +1733,7 @@ static u16 falc_pattern_test_error(pc300_t * card, int ch)
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
falc_t *pfalc = (falc_t *) & chan->falc;
- return (pfalc->bec);
+ return pfalc->bec;
}
/**********************************/
@@ -2819,7 +2819,7 @@ static int clock_rate_calc(u32 rate, u32 clock, int *br_io)
*br_io = 0;
if (rate == 0)
- return (0);
+ return 0;
for (br = 0, br_pwr = 1; br <= 9; br++, br_pwr <<= 1) {
if ((tc = clock / br_pwr / rate) <= 0xff) {
@@ -2832,11 +2832,11 @@ static int clock_rate_calc(u32 rate, u32 clock, int *br_io)
error = ((rate - (clock / br_pwr / rate)) / rate) * 1000;
/* Errors bigger than +/- 1% won't be tolerated */
if (error < -10 || error > 10)
- return (-1);
+ return -1;
else
- return (tc);
+ return tc;
} else {
- return (-1);
+ return -1;
}
}
@@ -3207,7 +3207,7 @@ static u32 detect_ram(pc300_t * card)
break;
}
}
- return (i);
+ return i;
}
static void plx_init(pc300_t * card)
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c
index 4293889e287e..515d9b8af01e 100644
--- a/drivers/net/wan/pc300_tty.c
+++ b/drivers/net/wan/pc300_tty.c
@@ -540,7 +540,7 @@ static int cpc_tty_chars_in_buffer(struct tty_struct *tty)
return -ENODEV;
}
- return(0);
+ return 0;
}
static int pc300_tiocmset(struct tty_struct *tty, struct file *file,
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index e2cff64a446a..fd7375955e41 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -220,7 +220,7 @@ static int pci200_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
new_line.clock_type != CLOCK_TXFROMRX &&
new_line.clock_type != CLOCK_INT &&
new_line.clock_type != CLOCK_TXINT)
- return -EINVAL; /* No such clock setting */
+ return -EINVAL; /* No such clock setting */
if (new_line.loopback != 0 && new_line.loopback != 1)
return -EINVAL;
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index f4125da2762f..3f4e2b5684db 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -178,7 +178,7 @@ static char sdla_byte(struct net_device *dev, int addr)
byte = *temp;
spin_unlock_irqrestore(&sdla_lock, flags);
- return(byte);
+ return byte;
}
static void sdla_stop(struct net_device *dev)
@@ -267,7 +267,7 @@ static int sdla_z80_poll(struct net_device *dev, int z80_addr, int jiffs, char r
resp = *temp;
}
}
- return(time_before(jiffies, done) ? jiffies - start : -1);
+ return time_before(jiffies, done) ? jiffies - start : -1;
}
/* constants for Z80 CPU speed */
@@ -283,13 +283,13 @@ static int sdla_cpuspeed(struct net_device *dev, struct ifreq *ifr)
sdla_start(dev);
if (sdla_z80_poll(dev, 0, 3*HZ, Z80_READY, 0) < 0)
- return(-EIO);
+ return -EIO;
data = LOADER_READY;
sdla_write(dev, 0, &data, 1);
if ((jiffs = sdla_z80_poll(dev, 0, 8*HZ, Z80_SCC_OK, Z80_SCC_BAD)) < 0)
- return(-EIO);
+ return -EIO;
sdla_stop(dev);
sdla_read(dev, 0, &data, 1);
@@ -297,11 +297,11 @@ static int sdla_cpuspeed(struct net_device *dev, struct ifreq *ifr)
if (data == Z80_SCC_BAD)
{
printk("%s: SCC bad\n", dev->name);
- return(-EIO);
+ return -EIO;
}
if (data != Z80_SCC_OK)
- return(-EINVAL);
+ return -EINVAL;
if (jiffs < 165)
ifr->ifr_mtu = SDLA_CPU_16M;
@@ -316,7 +316,7 @@ static int sdla_cpuspeed(struct net_device *dev, struct ifreq *ifr)
else
ifr->ifr_mtu = SDLA_CPU_3M;
- return(0);
+ return 0;
}
/************************************************
@@ -493,7 +493,7 @@ static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags,
if (ret != SDLA_RET_OK)
sdla_errors(dev, cmd, dlci, ret, len, &status);
- return(ret);
+ return ret;
}
/***********************************************
@@ -516,14 +516,14 @@ static int sdla_activate(struct net_device *slave, struct net_device *master)
break;
if (i == CONFIG_DLCI_MAX)
- return(-ENODEV);
+ return -ENODEV;
flp->dlci[i] = abs(flp->dlci[i]);
if (netif_running(slave) && (flp->config.station == FRAD_STATION_NODE))
sdla_cmd(slave, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
- return(0);
+ return 0;
}
static int sdla_deactivate(struct net_device *slave, struct net_device *master)
@@ -538,14 +538,14 @@ static int sdla_deactivate(struct net_device *slave, struct net_device *master)
break;
if (i == CONFIG_DLCI_MAX)
- return(-ENODEV);
+ return -ENODEV;
flp->dlci[i] = -abs(flp->dlci[i]);
if (netif_running(slave) && (flp->config.station == FRAD_STATION_NODE))
sdla_cmd(slave, SDLA_DEACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
- return(0);
+ return 0;
}
static int sdla_assoc(struct net_device *slave, struct net_device *master)
@@ -554,7 +554,7 @@ static int sdla_assoc(struct net_device *slave, struct net_device *master)
int i;
if (master->type != ARPHRD_DLCI)
- return(-EINVAL);
+ return -EINVAL;
flp = netdev_priv(slave);
@@ -563,11 +563,11 @@ static int sdla_assoc(struct net_device *slave, struct net_device *master)
if (!flp->master[i])
break;
if (abs(flp->dlci[i]) == *(short *)(master->dev_addr))
- return(-EADDRINUSE);
+ return -EADDRINUSE;
}
if (i == CONFIG_DLCI_MAX)
- return(-EMLINK); /* #### Alan: Comments on this ?? */
+ return -EMLINK; /* #### Alan: Comments on this ?? */
flp->master[i] = master;
@@ -581,7 +581,7 @@ static int sdla_assoc(struct net_device *slave, struct net_device *master)
sdla_cmd(slave, SDLA_ADD_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
}
- return(0);
+ return 0;
}
static int sdla_deassoc(struct net_device *slave, struct net_device *master)
@@ -596,7 +596,7 @@ static int sdla_deassoc(struct net_device *slave, struct net_device *master)
break;
if (i == CONFIG_DLCI_MAX)
- return(-ENODEV);
+ return -ENODEV;
flp->master[i] = NULL;
flp->dlci[i] = 0;
@@ -609,7 +609,7 @@ static int sdla_deassoc(struct net_device *slave, struct net_device *master)
sdla_cmd(slave, SDLA_DELETE_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL);
}
- return(0);
+ return 0;
}
static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get)
@@ -626,7 +626,7 @@ static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, i
break;
if (i == CONFIG_DLCI_MAX)
- return(-ENODEV);
+ return -ENODEV;
dlp = netdev_priv(master);
@@ -641,7 +641,7 @@ static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, i
&dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
}
- return(ret == SDLA_RET_OK ? 0 : -EIO);
+ return ret == SDLA_RET_OK ? 0 : -EIO;
}
/**************************
@@ -986,7 +986,7 @@ static int sdla_close(struct net_device *dev)
netif_stop_queue(dev);
- return(0);
+ return 0;
}
struct conf_data {
@@ -1006,10 +1006,10 @@ static int sdla_open(struct net_device *dev)
flp = netdev_priv(dev);
if (!flp->initialized)
- return(-EPERM);
+ return -EPERM;
if (!flp->configured)
- return(-EPERM);
+ return -EPERM;
/* time to send in the configuration */
len = 0;
@@ -1087,7 +1087,7 @@ static int sdla_open(struct net_device *dev)
netif_start_queue(dev);
- return(0);
+ return 0;
}
static int sdla_config(struct net_device *dev, struct frad_conf __user *conf, int get)
@@ -1098,48 +1098,48 @@ static int sdla_config(struct net_device *dev, struct frad_conf __user *conf, in
short size;
if (dev->type == 0xFFFF)
- return(-EUNATCH);
+ return -EUNATCH;
flp = netdev_priv(dev);
if (!get)
{
if (netif_running(dev))
- return(-EBUSY);
+ return -EBUSY;
if(copy_from_user(&data.config, conf, sizeof(struct frad_conf)))
return -EFAULT;
if (data.config.station & ~FRAD_STATION_NODE)
- return(-EINVAL);
+ return -EINVAL;
if (data.config.flags & ~FRAD_VALID_FLAGS)
- return(-EINVAL);
+ return -EINVAL;
if ((data.config.kbaud < 0) ||
((data.config.kbaud > 128) && (flp->type != SDLA_S508)))
- return(-EINVAL);
+ return -EINVAL;
if (data.config.clocking & ~(FRAD_CLOCK_INT | SDLA_S508_PORT_RS232))
- return(-EINVAL);
+ return -EINVAL;
if ((data.config.mtu < 0) || (data.config.mtu > SDLA_MAX_MTU))
- return(-EINVAL);
+ return -EINVAL;
if ((data.config.T391 < 5) || (data.config.T391 > 30))
- return(-EINVAL);
+ return -EINVAL;
if ((data.config.T392 < 5) || (data.config.T392 > 30))
- return(-EINVAL);
+ return -EINVAL;
if ((data.config.N391 < 1) || (data.config.N391 > 255))
- return(-EINVAL);
+ return -EINVAL;
if ((data.config.N392 < 1) || (data.config.N392 > 10))
- return(-EINVAL);
+ return -EINVAL;
if ((data.config.N393 < 1) || (data.config.N393 > 10))
- return(-EINVAL);
+ return -EINVAL;
memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
flp->config.flags |= SDLA_DIRECT_RECV;
@@ -1171,7 +1171,7 @@ static int sdla_config(struct net_device *dev, struct frad_conf __user *conf, in
{
size = sizeof(data);
if (sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, NULL, 0, &data, &size) != SDLA_RET_OK)
- return(-EIO);
+ return -EIO;
}
else
if (flp->configured)
@@ -1185,7 +1185,7 @@ static int sdla_config(struct net_device *dev, struct frad_conf __user *conf, in
return copy_to_user(conf, &data.config, sizeof(struct frad_conf))?-EFAULT:0;
}
- return(0);
+ return 0;
}
static int sdla_xfer(struct net_device *dev, struct sdla_mem __user *info, int read)
@@ -1200,7 +1200,7 @@ static int sdla_xfer(struct net_device *dev, struct sdla_mem __user *info, int r
{
temp = kzalloc(mem.len, GFP_KERNEL);
if (!temp)
- return(-ENOMEM);
+ return -ENOMEM;
sdla_read(dev, mem.addr, temp, mem.len);
if(copy_to_user(mem.data, temp, mem.len))
{
@@ -1217,7 +1217,7 @@ static int sdla_xfer(struct net_device *dev, struct sdla_mem __user *info, int r
sdla_write(dev, mem.addr, temp, mem.len);
kfree(temp);
}
- return(0);
+ return 0;
}
static int sdla_reconfig(struct net_device *dev)
@@ -1241,7 +1241,7 @@ static int sdla_reconfig(struct net_device *dev)
sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL);
sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
- return(0);
+ return 0;
}
static int sdla_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -1254,20 +1254,20 @@ static int sdla_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
flp = netdev_priv(dev);
if (!flp->initialized)
- return(-EINVAL);
+ return -EINVAL;
switch (cmd)
{
case FRAD_GET_CONF:
case FRAD_SET_CONF:
- return(sdla_config(dev, ifr->ifr_data, cmd == FRAD_GET_CONF));
+ return sdla_config(dev, ifr->ifr_data, cmd == FRAD_GET_CONF);
case SDLA_IDENTIFY:
ifr->ifr_flags = flp->type;
break;
case SDLA_CPUSPEED:
- return(sdla_cpuspeed(dev, ifr));
+ return sdla_cpuspeed(dev, ifr);
/* ==========================================================
NOTE: This is rather a useless action right now, as the
@@ -1277,7 +1277,7 @@ NOTE: This is rather a useless action right now, as the
============================================================*/
case SDLA_PROTOCOL:
if (flp->configured)
- return(-EALREADY);
+ return -EALREADY;
switch (ifr->ifr_flags)
{
@@ -1285,7 +1285,7 @@ NOTE: This is rather a useless action right now, as the
dev->type = ifr->ifr_flags;
break;
default:
- return(-ENOPROTOOPT);
+ return -ENOPROTOOPT;
}
break;
@@ -1297,7 +1297,7 @@ NOTE: This is rather a useless action right now, as the
case SDLA_READMEM:
if(!capable(CAP_SYS_RAWIO))
return -EPERM;
- return(sdla_xfer(dev, ifr->ifr_data, cmd == SDLA_READMEM));
+ return sdla_xfer(dev, ifr->ifr_data, cmd == SDLA_READMEM);
case SDLA_START:
sdla_start(dev);
@@ -1308,9 +1308,9 @@ NOTE: This is rather a useless action right now, as the
break;
default:
- return(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
}
- return(0);
+ return 0;
}
static int sdla_change_mtu(struct net_device *dev, int new_mtu)
@@ -1320,10 +1320,10 @@ static int sdla_change_mtu(struct net_device *dev, int new_mtu)
flp = netdev_priv(dev);
if (netif_running(dev))
- return(-EBUSY);
+ return -EBUSY;
/* for now, you can't change the MTU! */
- return(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
}
static int sdla_set_config(struct net_device *dev, struct ifmap *map)
@@ -1337,18 +1337,18 @@ static int sdla_set_config(struct net_device *dev, struct ifmap *map)
flp = netdev_priv(dev);
if (flp->initialized)
- return(-EINVAL);
+ return -EINVAL;
for(i=0; i < ARRAY_SIZE(valid_port); i++)
if (valid_port[i] == map->base_addr)
break;
if (i == ARRAY_SIZE(valid_port))
- return(-EINVAL);
+ return -EINVAL;
if (!request_region(map->base_addr, SDLA_IO_EXTENTS, dev->name)){
printk(KERN_WARNING "SDLA: io-port 0x%04lx in use\n", dev->base_addr);
- return(-EINVAL);
+ return -EINVAL;
}
base = map->base_addr;
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index e47f5a986b1c..d81ad8397885 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -648,7 +648,7 @@ static int x25_asy_esc(unsigned char *s, unsigned char *d, int len)
}
}
*ptr++ = X25_END;
- return (ptr - d);
+ return ptr - d;
}
static void x25_asy_unesc(struct x25_asy *sl, unsigned char s)
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index fbf5e843d48c..93956861ea21 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -766,7 +766,7 @@ irqreturn_t z8530_interrupt(int irq, void *dev_id)
EXPORT_SYMBOL(z8530_interrupt);
-static char reg_init[16]=
+static const u8 reg_init[16]=
{
0,0,0,0,
0,0,0,0,
@@ -1206,7 +1206,7 @@ EXPORT_SYMBOL(z8530_sync_txdma_close);
* it exists...
*/
-static char *z8530_type_name[]={
+static const char *z8530_type_name[]={
"Z8530",
"Z85C30",
"Z85230"
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index eb72c67699ab..f1549fff0edc 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -342,10 +342,10 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
model_name, dev->irq, dev->mem_start, dev->mem_end-1);
- ei_status.reset_8390 = &wd_reset_8390;
- ei_status.block_input = &wd_block_input;
- ei_status.block_output = &wd_block_output;
- ei_status.get_8390_hdr = &wd_get_8390_hdr;
+ ei_status.reset_8390 = wd_reset_8390;
+ ei_status.block_input = wd_block_input;
+ ei_status.block_output = wd_block_output;
+ ei_status.get_8390_hdr = wd_get_8390_hdr;
dev->netdev_ops = &wd_netdev_ops;
NS8390_init(dev, 0);
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index 9fb03082153a..12b84ed0e38a 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -98,7 +98,7 @@ MODULE_PARM_DESC(power_save_disabled,
"False by default (so the device is told to do power "
"saving).");
-int i2400m_passive_mode; /* 0 (passive mode disabled) by default */
+static int i2400m_passive_mode; /* 0 (passive mode disabled) by default */
module_param_named(passive_mode, i2400m_passive_mode, int, 0644);
MODULE_PARM_DESC(passive_mode,
"If true, the driver will not do any device setup "
@@ -558,8 +558,9 @@ void i2400m_report_hook(struct i2400m *i2400m,
* processing should be done in the function that calls the
* command. This is here for some cases where it can't happen...
*/
-void i2400m_msg_ack_hook(struct i2400m *i2400m,
- const struct i2400m_l3l4_hdr *l3l4_hdr, size_t size)
+static void i2400m_msg_ack_hook(struct i2400m *i2400m,
+ const struct i2400m_l3l4_hdr *l3l4_hdr,
+ size_t size)
{
int result;
struct device *dev = i2400m_dev(i2400m);
@@ -1135,7 +1136,7 @@ error_alloc:
* i2400m_report_state_hook() to parse the answer. This will set the
* carrier state, as well as the RF Kill switches state.
*/
-int i2400m_cmd_get_state(struct i2400m *i2400m)
+static int i2400m_cmd_get_state(struct i2400m *i2400m)
{
int result;
struct device *dev = i2400m_dev(i2400m);
@@ -1177,8 +1178,6 @@ error_msg_to_dev:
error_alloc:
return result;
}
-EXPORT_SYMBOL_GPL(i2400m_cmd_get_state);
-
/**
* Set basic configuration settings
@@ -1190,8 +1189,9 @@ EXPORT_SYMBOL_GPL(i2400m_cmd_get_state);
* right endianess (LE).
* @arg_size: number of pointers in the @args array
*/
-int i2400m_set_init_config(struct i2400m *i2400m,
- const struct i2400m_tlv_hdr **arg, size_t args)
+static int i2400m_set_init_config(struct i2400m *i2400m,
+ const struct i2400m_tlv_hdr **arg,
+ size_t args)
{
int result;
struct device *dev = i2400m_dev(i2400m);
@@ -1258,8 +1258,6 @@ none:
return result;
}
-EXPORT_SYMBOL_GPL(i2400m_set_init_config);
-
/**
* i2400m_set_idle_timeout - Set the device's idle mode timeout
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 9c8b78d4abd2..cdedab46ba21 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -122,7 +122,7 @@ struct i2400m_work *__i2400m_work_setup(
* works struct was already queued, but we have just allocated it, so
* it should not happen.
*/
-int i2400m_schedule_work(struct i2400m *i2400m,
+static int i2400m_schedule_work(struct i2400m *i2400m,
void (*fn)(struct work_struct *), gfp_t gfp_flags,
const void *pl, size_t pl_size)
{
diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h
index 360d4fb195f4..1d63ffdedfde 100644
--- a/drivers/net/wimax/i2400m/i2400m-sdio.h
+++ b/drivers/net/wimax/i2400m/i2400m-sdio.h
@@ -140,7 +140,6 @@ void i2400ms_init(struct i2400ms *i2400ms)
extern int i2400ms_rx_setup(struct i2400ms *);
extern void i2400ms_rx_release(struct i2400ms *);
-extern ssize_t __i2400ms_rx_get_size(struct i2400ms *);
extern int i2400ms_tx_setup(struct i2400ms *);
extern void i2400ms_tx_release(struct i2400ms *);
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index fa74777fd65f..59ac7705e76e 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -910,28 +910,19 @@ struct i2400m_work {
u8 pl[0];
};
-extern int i2400m_schedule_work(struct i2400m *,
- void (*)(struct work_struct *), gfp_t,
- const void *, size_t);
-
extern int i2400m_msg_check_status(const struct i2400m_l3l4_hdr *,
char *, size_t);
extern int i2400m_msg_size_check(struct i2400m *,
const struct i2400m_l3l4_hdr *, size_t);
extern struct sk_buff *i2400m_msg_to_dev(struct i2400m *, const void *, size_t);
extern void i2400m_msg_to_dev_cancel_wait(struct i2400m *, int);
-extern void i2400m_msg_ack_hook(struct i2400m *,
- const struct i2400m_l3l4_hdr *, size_t);
extern void i2400m_report_hook(struct i2400m *,
const struct i2400m_l3l4_hdr *, size_t);
extern void i2400m_report_hook_work(struct work_struct *);
extern int i2400m_cmd_enter_powersave(struct i2400m *);
-extern int i2400m_cmd_get_state(struct i2400m *);
extern int i2400m_cmd_exit_idle(struct i2400m *);
extern struct sk_buff *i2400m_get_device_info(struct i2400m *);
extern int i2400m_firmware_check(struct i2400m *);
-extern int i2400m_set_init_config(struct i2400m *,
- const struct i2400m_tlv_hdr **, size_t);
extern int i2400m_set_idle_timeout(struct i2400m *, unsigned);
static inline
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index 1737d1488b35..844133b44af0 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -922,7 +922,7 @@ void i2400m_roq_queue_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq,
* rx_roq_refcount becomes zero. This routine gets executed when
* rx_roq_refcount becomes zero.
*/
-void i2400m_rx_roq_destroy(struct kref *ref)
+static void i2400m_rx_roq_destroy(struct kref *ref)
{
unsigned itr;
struct i2400m *i2400m
diff --git a/drivers/net/wimax/i2400m/sdio-rx.c b/drivers/net/wimax/i2400m/sdio-rx.c
index 8b809c2ead6c..fb6396dd115f 100644
--- a/drivers/net/wimax/i2400m/sdio-rx.c
+++ b/drivers/net/wimax/i2400m/sdio-rx.c
@@ -87,7 +87,7 @@ static const __le32 i2400m_ACK_BARKER[4] = {
*
* sdio_readl() doesn't work.
*/
-ssize_t __i2400ms_rx_get_size(struct i2400ms *i2400ms)
+static ssize_t __i2400ms_rx_get_size(struct i2400ms *i2400ms)
{
int ret, cnt, val;
ssize_t rx_size;
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 174e3442d519..4de4410cd38e 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -279,6 +279,7 @@ source "drivers/net/wireless/libertas/Kconfig"
source "drivers/net/wireless/orinoco/Kconfig"
source "drivers/net/wireless/p54/Kconfig"
source "drivers/net/wireless/rt2x00/Kconfig"
+source "drivers/net/wireless/wl1251/Kconfig"
source "drivers/net/wireless/wl12xx/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 5d4ce4d2b32b..06f8ca26c5c1 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -49,6 +49,8 @@ obj-$(CONFIG_ATH_COMMON) += ath/
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
+obj-$(CONFIG_WL1251) += wl1251/
obj-$(CONFIG_WL12XX) += wl12xx/
+obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/
obj-$(CONFIG_IWM) += iwmc3200wifi/
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index ce77575e88b3..a36e7870b03e 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -105,7 +105,7 @@ static struct pci_driver airo_driver = {
of statistics in the /proc filesystem */
#define IGNLABEL(comment) NULL
-static char *statsLabels[] = {
+static const char *statsLabels[] = {
"RxOverrun",
IGNLABEL("RxPlcpCrcErr"),
IGNLABEL("RxPlcpFormatErr"),
@@ -217,7 +217,6 @@ static char *statsLabels[] = {
(no spaces) list of rates (up to 8). */
static int rates[8];
-static int basic_rate;
static char *ssids[3];
static int io[4];
@@ -250,7 +249,6 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350");
module_param_array(io, int, NULL, 0);
module_param_array(irq, int, NULL, 0);
-module_param(basic_rate, int, 0);
module_param_array(rates, int, NULL, 0);
module_param_array(ssids, charp, NULL, 0);
module_param(auto_wep, int, 0);
@@ -932,7 +930,7 @@ typedef struct aironet_ioctl {
unsigned char __user *data; // d-data
} aironet_ioctl;
-static char swversion[] = "2.1";
+static const char swversion[] = "2.1";
#endif /* CISCO_EXT */
#define NUM_MODULES 2
@@ -1374,7 +1372,7 @@ static int micsetup(struct airo_info *ai) {
return SUCCESS;
}
-static char micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
+static const u8 micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
/*===========================================================================
* Description: Mic a packet
@@ -2723,9 +2721,8 @@ static int airo_networks_allocate(struct airo_info *ai)
if (ai->networks)
return 0;
- ai->networks =
- kzalloc(AIRO_MAX_NETWORK_COUNT * sizeof(BSSListElement),
- GFP_KERNEL);
+ ai->networks = kcalloc(AIRO_MAX_NETWORK_COUNT, sizeof(BSSListElement),
+ GFP_KERNEL);
if (!ai->networks) {
airo_print_warn("", "Out of memory allocating beacons");
return -ENOMEM;
@@ -3884,15 +3881,6 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
ai->config.rates[i] = rates[i];
}
}
- if ( basic_rate > 0 ) {
- for( i = 0; i < 8; i++ ) {
- if ( ai->config.rates[i] == basic_rate ||
- !ai->config.rates ) {
- ai->config.rates[i] = basic_rate | 0x80;
- break;
- }
- }
- }
set_bit (FLAG_COMMIT, &ai->flags);
}
@@ -5032,7 +5020,7 @@ static void proc_config_on_close(struct inode *inode, struct file *file)
airo_config_commit(dev, NULL, NULL, NULL);
}
-static char *get_rmode(__le16 mode)
+static const char *get_rmode(__le16 mode)
{
switch(mode & RXMODE_MASK) {
case RXMODE_RFMON: return "rfmon";
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 1128fa8c9ed5..1476314afa8a 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1525,8 +1525,7 @@ static void at76_rx_tasklet(unsigned long param)
if (priv->device_unplugged) {
at76_dbg(DBG_DEVSTART, "device unplugged");
- if (urb)
- at76_dbg(DBG_DEVSTART, "urb status %d", urb->status);
+ at76_dbg(DBG_DEVSTART, "urb status %d", urb->status);
return;
}
@@ -2061,11 +2060,12 @@ static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
int i;
- at76_dbg(DBG_MAC80211, "%s(): cmd %d key->alg %d key->keyidx %d "
+ at76_dbg(DBG_MAC80211, "%s(): cmd %d key->cipher %d key->keyidx %d "
"key->keylen %d",
- __func__, cmd, key->alg, key->keyidx, key->keylen);
+ __func__, cmd, key->cipher, key->keyidx, key->keylen);
- if (key->alg != ALG_WEP)
+ if ((key->cipher != WLAN_CIPHER_SUITE_WEP40) &&
+ (key->cipher != WLAN_CIPHER_SUITE_WEP104))
return -EOPNOTSUPP;
key->hw_key_idx = key->keyidx;
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
index 0a75be027afa..92c216263ee9 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/ar9170/Kconfig"
+source "drivers/net/wireless/ath/carl9170/Kconfig"
endif
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile
index 8113a5042afa..6d711ec97ec2 100644
--- a/drivers/net/wireless/ath/Makefile
+++ b/drivers/net/wireless/ath/Makefile
@@ -1,11 +1,13 @@
obj-$(CONFIG_ATH5K) += ath5k/
obj-$(CONFIG_ATH9K_HW) += ath9k/
obj-$(CONFIG_AR9170_USB) += ar9170/
+obj-$(CONFIG_CARL9170) += carl9170/
obj-$(CONFIG_ATH_COMMON) += ath.o
ath-objs := main.o \
regd.o \
- hw.o
+ hw.o \
+ key.o
ath-$(CONFIG_ATH_DEBUG) += debug.o
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index debfb0fbc7c5..32bf79e6a320 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -1190,14 +1190,13 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
if (info->control.hw_key) {
icv = info->control.hw_key->icv_len;
- switch (info->control.hw_key->alg) {
- case ALG_WEP:
+ switch (info->control.hw_key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ case WLAN_CIPHER_SUITE_TKIP:
keytype = AR9170_TX_MAC_ENCR_RC4;
break;
- case ALG_TKIP:
- keytype = AR9170_TX_MAC_ENCR_RC4;
- break;
- case ALG_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
keytype = AR9170_TX_MAC_ENCR_AES;
break;
default:
@@ -1778,17 +1777,17 @@ static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if ((!ar->vif) || (ar->disable_offload))
return -EOPNOTSUPP;
- switch (key->alg) {
- case ALG_WEP:
- if (key->keylen == WLAN_KEY_LEN_WEP40)
- ktype = AR9170_ENC_ALG_WEP64;
- else
- ktype = AR9170_ENC_ALG_WEP128;
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ ktype = AR9170_ENC_ALG_WEP64;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ ktype = AR9170_ENC_ALG_WEP128;
break;
- case ALG_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
ktype = AR9170_ENC_ALG_TKIP;
break;
- case ALG_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
ktype = AR9170_ENC_ALG_AESCCMP;
break;
default:
@@ -1827,7 +1826,7 @@ static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (err)
goto out;
- if (key->alg == ALG_TKIP) {
+ if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL,
ktype, 1, key->key + 16, 16);
if (err)
@@ -1864,7 +1863,7 @@ static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (err)
goto out;
- if (key->alg == ALG_TKIP) {
+ if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
err = ar9170_upload_key(ar, key->hw_key_idx,
NULL,
AR9170_ENC_ALG_NONE, 1,
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index a93dc18a45c3..5dbb5361fd51 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -54,8 +54,6 @@ MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless");
MODULE_FIRMWARE("ar9170.fw");
-MODULE_FIRMWARE("ar9170-1.fw");
-MODULE_FIRMWARE("ar9170-2.fw");
enum ar9170_requirements {
AR9170_REQ_FW1_ONLY = 1,
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index d32f2828b098..501050c0296f 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -19,6 +19,7 @@
#include <linux/skbuff.h>
#include <linux/if_ether.h>
+#include <linux/spinlock.h>
#include <net/mac80211.h>
/*
@@ -35,7 +36,6 @@ static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
struct ath_ani {
bool caldone;
- int16_t noise_floor;
unsigned int longcal_timer;
unsigned int shortcal_timer;
unsigned int resetcal_timer;
@@ -43,6 +43,13 @@ struct ath_ani {
struct timer_list timer;
};
+struct ath_cycle_counters {
+ u32 cycles;
+ u32 rx_busy;
+ u32 rx_frame;
+ u32 tx_frame;
+};
+
enum ath_device_state {
ATH_HW_UNAVAILABLE,
ATH_HW_INITIALIZED,
@@ -71,20 +78,44 @@ struct ath_regulatory {
struct reg_dmn_pair_mapping *regpair;
};
+enum ath_crypt_caps {
+ ATH_CRYPT_CAP_CIPHER_AESCCM = BIT(0),
+ ATH_CRYPT_CAP_MIC_COMBINED = BIT(1),
+};
+
+struct ath_keyval {
+ u8 kv_type;
+ u8 kv_pad;
+ u16 kv_len;
+ u8 kv_val[16]; /* TK */
+ u8 kv_mic[8]; /* Michael MIC key */
+ u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware
+ * supports both MIC keys in the same key cache entry;
+ * in that case, kv_mic is the RX key) */
+};
+
+enum ath_cipher {
+ ATH_CIPHER_WEP = 0,
+ ATH_CIPHER_AES_OCB = 1,
+ ATH_CIPHER_AES_CCM = 2,
+ ATH_CIPHER_CKIP = 3,
+ ATH_CIPHER_TKIP = 4,
+ ATH_CIPHER_CLR = 5,
+ ATH_CIPHER_MIC = 127
+};
+
/**
* struct ath_ops - Register read/write operations
*
* @read: Register read
* @write: Register write
* @enable_write_buffer: Enable multiple register writes
- * @disable_write_buffer: Disable multiple register writes
- * @write_flush: Flush buffered register writes
+ * @write_flush: flush buffered register writes and disable buffering
*/
struct ath_ops {
unsigned int (*read)(void *, u32 reg_offset);
void (*write)(void *, u32 val, u32 reg_offset);
void (*enable_write_buffer)(void *);
- void (*disable_write_buffer)(void *);
void (*write_flush) (void *);
};
@@ -119,7 +150,14 @@ struct ath_common {
u32 keymax;
DECLARE_BITMAP(keymap, ATH_KEYMAX);
- u8 splitmic;
+ DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX);
+ enum ath_crypt_caps crypt_caps;
+
+ unsigned int clockrate;
+
+ spinlock_t cc_lock;
+ struct ath_cycle_counters cc_ani;
+ struct ath_cycle_counters cc_survey;
struct ath_regulatory regulatory;
const struct ath_ops *ops;
@@ -131,5 +169,13 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
gfp_t gfp_mask);
void ath_hw_setbssidmask(struct ath_common *common);
+void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key);
+int ath_key_config(struct ath_common *common,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key);
+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);
#endif /* ATH_H */
diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c
index 26dbe65fedb0..f1419198a479 100644
--- a/drivers/net/wireless/ath/ath5k/ani.c
+++ b/drivers/net/wireless/ath/ath5k/ani.c
@@ -355,41 +355,28 @@ ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as)
/**
- * ath5k_hw_ani_get_listen_time() - Calculate time spent listening
+ * ath5k_hw_ani_get_listen_time() - Update counters and return listening time
*
* Return an approximation of the time spent "listening" in milliseconds (ms)
- * since the last call of this function by deducting the cycles spent
- * transmitting and receiving from the total cycle count.
- * Save profile count values for debugging/statistics and because we might want
- * to use them later.
- *
- * We assume no one else clears these registers!
+ * since the last call of this function.
+ * Save a snapshot of the counter values for debugging/statistics.
*/
static int
ath5k_hw_ani_get_listen_time(struct ath5k_hw *ah, struct ath5k_ani_state *as)
{
+ struct ath_common *common = ath5k_hw_common(ah);
int listen;
- /* freeze */
- ath5k_hw_reg_write(ah, AR5K_MIBC_FMC, AR5K_MIBC);
- /* read */
- as->pfc_cycles = ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE);
- as->pfc_busy = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR);
- as->pfc_tx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX);
- as->pfc_rx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX);
- /* clear */
- ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX);
- ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX);
- ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
- ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
- /* un-freeze */
- ath5k_hw_reg_write(ah, 0, AR5K_MIBC);
-
- /* TODO: where does 44000 come from? (11g clock rate?) */
- listen = (as->pfc_cycles - as->pfc_rx - as->pfc_tx) / 44000;
-
- if (as->pfc_cycles == 0 || listen < 0)
- return 0;
+ spin_lock_bh(&common->cc_lock);
+
+ ath_hw_cycle_counters_update(common);
+ memcpy(&as->last_cc, &common->cc_ani, sizeof(as->last_cc));
+
+ /* clears common->cc_ani */
+ listen = ath_hw_get_listen_time(common);
+
+ spin_unlock_bh(&common->cc_lock);
+
return listen;
}
@@ -552,9 +539,9 @@ ath5k_ani_mib_intr(struct ath5k_hw *ah)
if (ah->ah_sc->ani_state.ani_mode != ATH5K_ANI_MODE_AUTO)
return;
- /* if one of the errors triggered, we can get a superfluous second
- * interrupt, even though we have already reset the register. the
- * function detects that so we can return early */
+ /* If one of the errors triggered, we can get a superfluous second
+ * interrupt, even though we have already reset the register. The
+ * function detects that so we can return early. */
if (ath5k_ani_save_and_clear_phy_errors(ah, as) == 0)
return;
diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h
index 55cf26d8522c..d0a664039c87 100644
--- a/drivers/net/wireless/ath/ath5k/ani.h
+++ b/drivers/net/wireless/ath/ath5k/ani.h
@@ -75,10 +75,7 @@ struct ath5k_ani_state {
unsigned int cck_errors;
/* debug/statistics only: numbers from last ANI calibration */
- unsigned int pfc_tx;
- unsigned int pfc_rx;
- unsigned int pfc_busy;
- unsigned int pfc_cycles;
+ struct ath_cycle_counters last_cc;
unsigned int last_listen;
unsigned int last_ofdm_errors;
unsigned int last_cck_errors;
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index ea6362a8988d..308b79e1ff08 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -175,7 +175,7 @@
#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_LEN / 64) + 1)
+#define AR5K_TUNE_MAX_TX_FIFO_THRES ((IEEE80211_MAX_FRAME_LEN / 64) + 1)
#define AR5K_TUNE_REGISTER_TIMEOUT 20000
/* Register for RSSI threshold has a mask of 0xff, so 255 seems to
* be the max value. */
@@ -206,6 +206,8 @@
#define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI 1000 /* 1 sec */
#define ATH5K_TUNE_CALIBRATION_INTERVAL_NF 60000 /* 60 sec */
+#define ATH5K_TX_COMPLETE_POLL_INT 3000 /* 3 sec */
+
#define AR5K_INIT_CARR_SENSE_EN 1
/*Swap RX/TX Descriptor for big endian archs*/
@@ -256,8 +258,6 @@
(AR5K_INIT_PROG_IFS_TURBO) \
)
-/* token to use for aifs, cwmin, cwmax in MadWiFi */
-#define AR5K_TXQ_USEDEFAULT ((u32) -1)
/* GENERIC CHIPSET DEFINITIONS */
@@ -343,15 +343,12 @@ struct ath5k_srev_name {
#define AR5K_SREV_PHY_5413 0x61
#define AR5K_SREV_PHY_2425 0x70
-/* IEEE defs */
-#define IEEE80211_MAX_LEN 2500
-
/* TODO add support to mac80211 for vendor-specific rates and modes */
/*
* Some of this information is based on Documentation from:
*
- * http://madwifi.org/wiki/ChipsetFeatures/SuperAG
+ * http://madwifi-project.org/wiki/ChipsetFeatures/SuperAG
*
* Modulation for Atheros' eXtended Range - range enhancing extension that is
* supposed to double the distance an Atheros client device can keep a
@@ -531,9 +528,9 @@ struct ath5k_txq_info {
enum ath5k_tx_queue tqi_type;
enum ath5k_tx_queue_subtype tqi_subtype;
u16 tqi_flags; /* Tx queue flags (see above) */
- u32 tqi_aifs; /* Arbitrated Interframe Space */
- s32 tqi_cw_min; /* Minimum Contention Window */
- s32 tqi_cw_max; /* Maximum Contention Window */
+ u8 tqi_aifs; /* Arbitrated Interframe Space */
+ u16 tqi_cw_min; /* Minimum Contention Window */
+ u16 tqi_cw_max; /* Maximum Contention Window */
u32 tqi_cbr_period; /* Constant bit rate period */
u32 tqi_cbr_overflow_limit;
u32 tqi_burst_time;
@@ -1031,8 +1028,6 @@ struct ath5k_hw {
bool ah_turbo;
bool ah_calibration;
bool ah_single_chip;
- bool ah_aes_support;
- bool ah_combined_mic;
enum ath5k_version ah_version;
enum ath5k_radio ah_radio;
@@ -1046,10 +1041,6 @@ struct ath5k_hw {
#define ah_modes ah_capabilities.cap_mode
#define ah_ee_version ah_capabilities.cap_eeprom.ee_version
- u32 ah_atim_window;
- u32 ah_aifs;
- u32 ah_cw_min;
- u32 ah_cw_max;
u32 ah_limit_tx_retries;
u8 ah_coverage_class;
@@ -1190,7 +1181,7 @@ extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode);
void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class);
/* BSSID Functions */
int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
-void ath5k_hw_set_associd(struct ath5k_hw *ah);
+void ath5k_hw_set_bssid(struct ath5k_hw *ah);
void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
/* Receive start/stop functions */
void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
@@ -1204,17 +1195,13 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah);
void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64);
void ath5k_hw_reset_tsf(struct ath5k_hw *ah);
void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval);
+bool ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval);
/* ACK bit rate */
void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high);
/* Clock rate related functions */
unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec);
unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock);
-unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah);
-/* Key table (WEP) functions */
-int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry);
-int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
- const struct ieee80211_key_conf *key, const u8 *mac);
-int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac);
+void ath5k_hw_set_clockrate(struct ath5k_hw *ah);
/* Queue Control Unit, DFS Control Unit Functions */
int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index b32e28caeee2..cd0b14a0a93a 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -118,9 +118,6 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
ah->ah_turbo = false;
ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
ah->ah_imr = 0;
- ah->ah_atim_window = 0;
- ah->ah_aifs = AR5K_TUNE_AIFS;
- ah->ah_cw_min = AR5K_TUNE_CWMIN;
ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
ah->ah_software_retry = false;
ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT;
@@ -139,12 +136,12 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
else
ah->ah_version = AR5K_AR5212;
- /*Fill the ath5k_hw struct with the needed functions*/
+ /* Fill the ath5k_hw struct with the needed functions */
ret = ath5k_hw_init_desc_functions(ah);
if (ret)
goto err_free;
- /* Bring device out of sleep and reset it's units */
+ /* Bring device out of sleep and reset its units */
ret = ath5k_hw_nic_wakeup(ah, 0, true);
if (ret)
goto err_free;
@@ -158,7 +155,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
CHANNEL_5GHZ);
ah->ah_phy = AR5K_PHY(0);
- /* Try to identify radio chip based on it's srev */
+ /* Try to identify radio chip based on its srev */
switch (ah->ah_radio_5ghz_revision & 0xf0) {
case AR5K_SREV_RAD_5111:
ah->ah_radio = AR5K_RF5111;
@@ -314,12 +311,16 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
}
/* Crypto settings */
- ah->ah_aes_support = srev >= AR5K_SREV_AR5212_V4 &&
- (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 &&
- !AR5K_EEPROM_AES_DIS(ee->ee_misc5));
+ common->keymax = (sc->ah->ah_version == AR5K_AR5210 ?
+ AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211);
+
+ if (srev >= AR5K_SREV_AR5212_V4 &&
+ (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 &&
+ !AR5K_EEPROM_AES_DIS(ee->ee_misc5)))
+ common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
if (srev >= AR5K_SREV_AR2414) {
- ah->ah_combined_mic = true;
+ common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE,
AR5K_MISC_MODE_COMBINED_MIC);
}
@@ -329,7 +330,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN);
- ath5k_hw_set_associd(ah);
+ ath5k_hw_set_bssid(ah);
ath5k_hw_set_opmode(ah, sc->opmode);
ath5k_hw_rfgain_opt_init(ah);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index d77ce9906b6c..8251946842e6 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -52,6 +52,7 @@
#include <linux/ethtool.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
+#include <linux/etherdevice.h>
#include <net/ieee80211_radiotap.h>
@@ -61,6 +62,7 @@
#include "reg.h"
#include "debug.h"
#include "ani.h"
+#include "../debug.h"
static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
@@ -70,11 +72,6 @@ static int modparam_all_channels;
module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO);
MODULE_PARM_DESC(all_channels, "Expose all channels the device can use.");
-
-/******************\
-* Internal defines *
-\******************/
-
/* Module info */
MODULE_AUTHOR("Jiri Slaby");
MODULE_AUTHOR("Nick Kossifidis");
@@ -83,6 +80,10 @@ MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION("0.6.0 (EXPERIMENTAL)");
+static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan);
+static int ath5k_beacon_update(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
+static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
/* Known PCI ids */
static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = {
@@ -190,129 +191,6 @@ static const struct ieee80211_rate ath5k_rates[] = {
/* XR missing */
};
-/*
- * Prototypes - PCI stack related functions
- */
-static int __devinit ath5k_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *id);
-static void __devexit ath5k_pci_remove(struct pci_dev *pdev);
-#ifdef CONFIG_PM_SLEEP
-static int ath5k_pci_suspend(struct device *dev);
-static int ath5k_pci_resume(struct device *dev);
-
-static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume);
-#define ATH5K_PM_OPS (&ath5k_pm_ops)
-#else
-#define ATH5K_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
-
-static struct pci_driver ath5k_pci_driver = {
- .name = KBUILD_MODNAME,
- .id_table = ath5k_pci_id_table,
- .probe = ath5k_pci_probe,
- .remove = __devexit_p(ath5k_pci_remove),
- .driver.pm = ATH5K_PM_OPS,
-};
-
-
-
-/*
- * Prototypes - MAC 802.11 stack related functions
- */
-static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
-static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ath5k_txq *txq);
-static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan);
-static int ath5k_start(struct ieee80211_hw *hw);
-static void ath5k_stop(struct ieee80211_hw *hw);
-static int ath5k_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif);
-static void ath5k_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif);
-static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
-static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
- struct netdev_hw_addr_list *mc_list);
-static void ath5k_configure_filter(struct ieee80211_hw *hw,
- unsigned int changed_flags,
- unsigned int *new_flags,
- u64 multicast);
-static int ath5k_set_key(struct ieee80211_hw *hw,
- enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key);
-static int ath5k_get_stats(struct ieee80211_hw *hw,
- struct ieee80211_low_level_stats *stats);
-static int ath5k_get_survey(struct ieee80211_hw *hw,
- int idx, struct survey_info *survey);
-static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
-static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf);
-static void ath5k_reset_tsf(struct ieee80211_hw *hw);
-static int ath5k_beacon_update(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif);
-static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *bss_conf,
- u32 changes);
-static void ath5k_sw_scan_start(struct ieee80211_hw *hw);
-static void ath5k_sw_scan_complete(struct ieee80211_hw *hw);
-static void ath5k_set_coverage_class(struct ieee80211_hw *hw,
- u8 coverage_class);
-
-static const struct ieee80211_ops ath5k_hw_ops = {
- .tx = ath5k_tx,
- .start = ath5k_start,
- .stop = ath5k_stop,
- .add_interface = ath5k_add_interface,
- .remove_interface = ath5k_remove_interface,
- .config = ath5k_config,
- .prepare_multicast = ath5k_prepare_multicast,
- .configure_filter = ath5k_configure_filter,
- .set_key = ath5k_set_key,
- .get_stats = ath5k_get_stats,
- .get_survey = ath5k_get_survey,
- .conf_tx = NULL,
- .get_tsf = ath5k_get_tsf,
- .set_tsf = ath5k_set_tsf,
- .reset_tsf = ath5k_reset_tsf,
- .bss_info_changed = ath5k_bss_info_changed,
- .sw_scan_start = ath5k_sw_scan_start,
- .sw_scan_complete = ath5k_sw_scan_complete,
- .set_coverage_class = ath5k_set_coverage_class,
-};
-
-/*
- * Prototypes - Internal functions
- */
-/* Attach detach */
-static int ath5k_attach(struct pci_dev *pdev,
- struct ieee80211_hw *hw);
-static void ath5k_detach(struct pci_dev *pdev,
- struct ieee80211_hw *hw);
-/* Channel/mode setup */
-static inline short ath5k_ieee2mhz(short chan);
-static unsigned int ath5k_copy_channels(struct ath5k_hw *ah,
- struct ieee80211_channel *channels,
- unsigned int mode,
- unsigned int max);
-static int ath5k_setup_bands(struct ieee80211_hw *hw);
-static int ath5k_chan_set(struct ath5k_softc *sc,
- struct ieee80211_channel *chan);
-static void ath5k_setcurmode(struct ath5k_softc *sc,
- unsigned int mode);
-static void ath5k_mode_setup(struct ath5k_softc *sc);
-
-/* Descriptor setup */
-static int ath5k_desc_alloc(struct ath5k_softc *sc,
- struct pci_dev *pdev);
-static void ath5k_desc_free(struct ath5k_softc *sc,
- struct pci_dev *pdev);
-/* Buffers setup */
-static int ath5k_rxbuf_setup(struct ath5k_softc *sc,
- struct ath5k_buf *bf);
-static int ath5k_txbuf_setup(struct ath5k_softc *sc,
- struct ath5k_buf *bf,
- struct ath5k_txq *txq, int padsize);
-
static inline void ath5k_txbuf_free_skb(struct ath5k_softc *sc,
struct ath5k_buf *bf)
{
@@ -345,35 +223,6 @@ static inline void ath5k_rxbuf_free_skb(struct ath5k_softc *sc,
}
-/* Queues setup */
-static struct ath5k_txq *ath5k_txq_setup(struct ath5k_softc *sc,
- int qtype, int subtype);
-static int ath5k_beaconq_setup(struct ath5k_hw *ah);
-static int ath5k_beaconq_config(struct ath5k_softc *sc);
-static void ath5k_txq_drainq(struct ath5k_softc *sc,
- struct ath5k_txq *txq);
-static void ath5k_txq_cleanup(struct ath5k_softc *sc);
-static void ath5k_txq_release(struct ath5k_softc *sc);
-/* Rx handling */
-static int ath5k_rx_start(struct ath5k_softc *sc);
-static void ath5k_rx_stop(struct ath5k_softc *sc);
-static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc,
- struct sk_buff *skb,
- struct ath5k_rx_status *rs);
-static void ath5k_tasklet_rx(unsigned long data);
-/* Tx handling */
-static void ath5k_tx_processq(struct ath5k_softc *sc,
- struct ath5k_txq *txq);
-static void ath5k_tasklet_tx(unsigned long data);
-/* Beacon handling */
-static int ath5k_beacon_setup(struct ath5k_softc *sc,
- struct ath5k_buf *bf);
-static void ath5k_beacon_send(struct ath5k_softc *sc);
-static void ath5k_beacon_config(struct ath5k_softc *sc);
-static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
-static void ath5k_tasklet_beacon(unsigned long data);
-static void ath5k_tasklet_ani(unsigned long data);
-
static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
{
u64 tsf = ath5k_hw_get_tsf64(ah);
@@ -384,50 +233,6 @@ static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
return (tsf & ~0x7fff) | rstamp;
}
-/* Interrupt handling */
-static int ath5k_init(struct ath5k_softc *sc);
-static int ath5k_stop_locked(struct ath5k_softc *sc);
-static int ath5k_stop_hw(struct ath5k_softc *sc);
-static irqreturn_t ath5k_intr(int irq, void *dev_id);
-static void ath5k_reset_work(struct work_struct *work);
-
-static void ath5k_tasklet_calibrate(unsigned long data);
-
-/*
- * Module init/exit functions
- */
-static int __init
-init_ath5k_pci(void)
-{
- int ret;
-
- ath5k_debug_init();
-
- ret = pci_register_driver(&ath5k_pci_driver);
- if (ret) {
- printk(KERN_ERR "ath5k_pci: can't register pci driver\n");
- return ret;
- }
-
- return 0;
-}
-
-static void __exit
-exit_ath5k_pci(void)
-{
- pci_unregister_driver(&ath5k_pci_driver);
-
- ath5k_debug_finish();
-}
-
-module_init(init_ath5k_pci);
-module_exit(exit_ath5k_pci);
-
-
-/********************\
-* PCI Initialization *
-\********************/
-
static const char *
ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val)
{
@@ -466,299 +271,6 @@ static const struct ath_ops ath5k_common_ops = {
.write = ath5k_iowrite32,
};
-static int __devinit
-ath5k_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- void __iomem *mem;
- struct ath5k_softc *sc;
- struct ath_common *common;
- struct ieee80211_hw *hw;
- int ret;
- u8 csz;
-
- /*
- * L0s needs to be disabled on all ath5k cards.
- *
- * For distributions shipping with CONFIG_PCIEASPM (this will be enabled
- * by default in the future in 2.6.36) this will also mean both L1 and
- * L0s will be disabled when a pre 1.1 PCIe device is detected. We do
- * know L1 works correctly even for all ath5k pre 1.1 PCIe devices
- * though but cannot currently undue the effect of a blacklist, for
- * details you can read pcie_aspm_sanity_check() and see how it adjusts
- * the device link capability.
- *
- * It may be possible in the future to implement some PCI API to allow
- * drivers to override blacklists for pre 1.1 PCIe but for now it is
- * best to accept that both L0s and L1 will be disabled completely for
- * distributions shipping with CONFIG_PCIEASPM rather than having this
- * issue present. Motivation for adding this new API will be to help
- * with power consumption for some of these devices.
- */
- pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S);
-
- ret = pci_enable_device(pdev);
- if (ret) {
- dev_err(&pdev->dev, "can't enable device\n");
- goto err;
- }
-
- /* XXX 32-bit addressing only */
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (ret) {
- dev_err(&pdev->dev, "32-bit DMA not available\n");
- goto err_dis;
- }
-
- /*
- * Cache line size is used to size and align various
- * structures used to communicate with the hardware.
- */
- pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
- if (csz == 0) {
- /*
- * Linux 2.4.18 (at least) writes the cache line size
- * register as a 16-bit wide register which is wrong.
- * We must have this setup properly for rx buffer
- * DMA to work so force a reasonable value here if it
- * comes up zero.
- */
- csz = L1_CACHE_BYTES >> 2;
- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
- }
- /*
- * The default setting of latency timer yields poor results,
- * set it to the value used by other systems. It may be worth
- * tweaking this setting more.
- */
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
-
- /* Enable bus mastering */
- pci_set_master(pdev);
-
- /*
- * Disable the RETRY_TIMEOUT register (0x41) to keep
- * PCI Tx retries from interfering with C3 CPU state.
- */
- pci_write_config_byte(pdev, 0x41, 0);
-
- ret = pci_request_region(pdev, 0, "ath5k");
- if (ret) {
- dev_err(&pdev->dev, "cannot reserve PCI memory region\n");
- goto err_dis;
- }
-
- mem = pci_iomap(pdev, 0, 0);
- if (!mem) {
- dev_err(&pdev->dev, "cannot remap PCI memory region\n") ;
- ret = -EIO;
- goto err_reg;
- }
-
- /*
- * Allocate hw (mac80211 main struct)
- * and hw->priv (driver private data)
- */
- hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops);
- if (hw == NULL) {
- dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n");
- ret = -ENOMEM;
- goto err_map;
- }
-
- dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy));
-
- /* Initialize driver private data */
- SET_IEEE80211_DEV(hw, &pdev->dev);
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
-
- hw->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_MESH_POINT);
-
- hw->extra_tx_headroom = 2;
- hw->channel_change_time = 5000;
- sc = hw->priv;
- sc->hw = hw;
- sc->pdev = pdev;
-
- ath5k_debug_init_device(sc);
-
- /*
- * Mark the device as detached to avoid processing
- * interrupts until setup is complete.
- */
- __set_bit(ATH_STAT_INVALID, sc->status);
-
- sc->iobase = mem; /* So we can unmap it on detach */
- sc->opmode = NL80211_IFTYPE_STATION;
- sc->bintval = 1000;
- mutex_init(&sc->lock);
- spin_lock_init(&sc->rxbuflock);
- spin_lock_init(&sc->txbuflock);
- spin_lock_init(&sc->block);
-
- /* Set private data */
- pci_set_drvdata(pdev, sc);
-
- /* Setup interrupt handler */
- ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
- if (ret) {
- ATH5K_ERR(sc, "request_irq failed\n");
- goto err_free;
- }
-
- /*If we passed the test malloc a ath5k_hw struct*/
- sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
- if (!sc->ah) {
- ret = -ENOMEM;
- ATH5K_ERR(sc, "out of memory\n");
- goto err_irq;
- }
-
- sc->ah->ah_sc = sc;
- sc->ah->ah_iobase = sc->iobase;
- common = ath5k_hw_common(sc->ah);
- common->ops = &ath5k_common_ops;
- common->ah = sc->ah;
- common->hw = hw;
- common->cachelsz = csz << 2; /* convert to bytes */
-
- /* Initialize device */
- ret = ath5k_hw_attach(sc);
- if (ret) {
- goto err_free_ah;
- }
-
- /* set up multi-rate retry capabilities */
- if (sc->ah->ah_version == AR5K_AR5212) {
- hw->max_rates = 4;
- hw->max_rate_tries = 11;
- }
-
- /* Finish private driver data initialization */
- ret = ath5k_attach(pdev, hw);
- if (ret)
- goto err_ah;
-
- ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev),
- sc->ah->ah_mac_srev,
- sc->ah->ah_phy_revision);
-
- if (!sc->ah->ah_single_chip) {
- /* Single chip radio (!RF5111) */
- if (sc->ah->ah_radio_5ghz_revision &&
- !sc->ah->ah_radio_2ghz_revision) {
- /* No 5GHz support -> report 2GHz radio */
- if (!test_bit(AR5K_MODE_11A,
- sc->ah->ah_capabilities.cap_mode)) {
- ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_RAD,
- sc->ah->ah_radio_5ghz_revision),
- sc->ah->ah_radio_5ghz_revision);
- /* No 2GHz support (5110 and some
- * 5Ghz only cards) -> report 5Ghz radio */
- } else if (!test_bit(AR5K_MODE_11B,
- sc->ah->ah_capabilities.cap_mode)) {
- ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_RAD,
- sc->ah->ah_radio_5ghz_revision),
- sc->ah->ah_radio_5ghz_revision);
- /* Multiband radio */
- } else {
- ATH5K_INFO(sc, "RF%s multiband radio found"
- " (0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_RAD,
- sc->ah->ah_radio_5ghz_revision),
- sc->ah->ah_radio_5ghz_revision);
- }
- }
- /* Multi chip radio (RF5111 - RF2111) ->
- * report both 2GHz/5GHz radios */
- else if (sc->ah->ah_radio_5ghz_revision &&
- sc->ah->ah_radio_2ghz_revision){
- ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_RAD,
- sc->ah->ah_radio_5ghz_revision),
- sc->ah->ah_radio_5ghz_revision);
- ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
- ath5k_chip_name(AR5K_VERSION_RAD,
- sc->ah->ah_radio_2ghz_revision),
- sc->ah->ah_radio_2ghz_revision);
- }
- }
-
-
- /* ready to process interrupts */
- __clear_bit(ATH_STAT_INVALID, sc->status);
-
- return 0;
-err_ah:
- ath5k_hw_detach(sc->ah);
-err_irq:
- free_irq(pdev->irq, sc);
-err_free_ah:
- kfree(sc->ah);
-err_free:
- ieee80211_free_hw(hw);
-err_map:
- pci_iounmap(pdev, mem);
-err_reg:
- pci_release_region(pdev, 0);
-err_dis:
- pci_disable_device(pdev);
-err:
- return ret;
-}
-
-static void __devexit
-ath5k_pci_remove(struct pci_dev *pdev)
-{
- struct ath5k_softc *sc = pci_get_drvdata(pdev);
-
- ath5k_debug_finish_device(sc);
- ath5k_detach(pdev, sc->hw);
- ath5k_hw_detach(sc->ah);
- kfree(sc->ah);
- free_irq(pdev->irq, sc);
- pci_iounmap(pdev, sc->iobase);
- pci_release_region(pdev, 0);
- pci_disable_device(pdev);
- ieee80211_free_hw(sc->hw);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int ath5k_pci_suspend(struct device *dev)
-{
- struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev));
-
- ath5k_led_off(sc);
- return 0;
-}
-
-static int ath5k_pci_resume(struct device *dev)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct ath5k_softc *sc = pci_get_drvdata(pdev);
-
- /*
- * Suspend/Resume resets the PCI configuration space, so we have to
- * re-disable the RETRY_TIMEOUT register (0x41) to keep
- * PCI Tx retries from interfering with C3 CPU state
- */
- pci_write_config_byte(pdev, 0x41, 0);
-
- ath5k_led_enable(sc);
- return 0;
-}
-#endif /* CONFIG_PM_SLEEP */
-
-
/***********************\
* Driver Initialization *
\***********************/
@@ -772,170 +284,6 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re
return ath_reg_notifier_apply(wiphy, request, regulatory);
}
-static int
-ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
-{
- struct ath5k_softc *sc = hw->priv;
- struct ath5k_hw *ah = sc->ah;
- struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah);
- u8 mac[ETH_ALEN] = {};
- int ret;
-
- ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device);
-
- /*
- * Check if the MAC has multi-rate retry support.
- * We do this by trying to setup a fake extended
- * descriptor. MAC's that don't have support will
- * return false w/o doing anything. MAC's that do
- * support it will return true w/o doing anything.
- */
- ret = ath5k_hw_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
-
- if (ret < 0)
- goto err;
- if (ret > 0)
- __set_bit(ATH_STAT_MRRETRY, sc->status);
-
- /*
- * Collect the channel list. The 802.11 layer
- * is resposible for filtering this list based
- * on settings like the phy mode and regulatory
- * domain restrictions.
- */
- ret = ath5k_setup_bands(hw);
- if (ret) {
- ATH5K_ERR(sc, "can't get channels\n");
- goto err;
- }
-
- /* NB: setup here so ath5k_rate_update is happy */
- if (test_bit(AR5K_MODE_11A, ah->ah_modes))
- ath5k_setcurmode(sc, AR5K_MODE_11A);
- else
- ath5k_setcurmode(sc, AR5K_MODE_11B);
-
- /*
- * Allocate tx+rx descriptors and populate the lists.
- */
- ret = ath5k_desc_alloc(sc, pdev);
- if (ret) {
- ATH5K_ERR(sc, "can't allocate descriptors\n");
- goto err;
- }
-
- /*
- * Allocate hardware transmit queues: one queue for
- * beacon frames and one data queue for each QoS
- * priority. Note that hw functions handle reseting
- * these queues at the needed time.
- */
- ret = ath5k_beaconq_setup(ah);
- if (ret < 0) {
- ATH5K_ERR(sc, "can't setup a beacon xmit queue\n");
- goto err_desc;
- }
- sc->bhalq = ret;
- sc->cabq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_CAB, 0);
- if (IS_ERR(sc->cabq)) {
- ATH5K_ERR(sc, "can't setup cab queue\n");
- ret = PTR_ERR(sc->cabq);
- goto err_bhal;
- }
-
- sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK);
- if (IS_ERR(sc->txq)) {
- ATH5K_ERR(sc, "can't setup xmit queue\n");
- ret = PTR_ERR(sc->txq);
- goto err_queues;
- }
-
- tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
- tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
- tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc);
- tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc);
- tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc);
-
- INIT_WORK(&sc->reset_work, ath5k_reset_work);
-
- ret = ath5k_eeprom_read_mac(ah, mac);
- if (ret) {
- ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
- sc->pdev->device);
- goto err_queues;
- }
-
- SET_IEEE80211_PERM_ADDR(hw, mac);
- /* All MAC address bits matter for ACKs */
- memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN);
- ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
-
- regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain;
- ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier);
- if (ret) {
- ATH5K_ERR(sc, "can't initialize regulatory system\n");
- goto err_queues;
- }
-
- ret = ieee80211_register_hw(hw);
- if (ret) {
- ATH5K_ERR(sc, "can't register ieee80211 hw\n");
- goto err_queues;
- }
-
- if (!ath_is_world_regd(regulatory))
- regulatory_hint(hw->wiphy, regulatory->alpha2);
-
- ath5k_init_leds(sc);
-
- ath5k_sysfs_register(sc);
-
- return 0;
-err_queues:
- ath5k_txq_release(sc);
-err_bhal:
- ath5k_hw_release_tx_queue(ah, sc->bhalq);
-err_desc:
- ath5k_desc_free(sc, pdev);
-err:
- return ret;
-}
-
-static void
-ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
-{
- struct ath5k_softc *sc = hw->priv;
-
- /*
- * NB: the order of these is important:
- * o call the 802.11 layer before detaching ath5k_hw to
- * insure callbacks into the driver to delete global
- * key cache entries can be handled
- * o reclaim the tx queue data structures after calling
- * the 802.11 layer as we'll get called back to reclaim
- * node state and potentially want to use them
- * o to cleanup the tx queues the hal is called, so detach
- * it last
- * XXX: ??? detach ath5k_hw ???
- * Other than that, it's straightforward...
- */
- ieee80211_unregister_hw(hw);
- ath5k_desc_free(sc, pdev);
- ath5k_txq_release(sc);
- ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
- ath5k_unregister_leds(sc);
-
- ath5k_sysfs_unregister(sc);
- /*
- * NB: can't reclaim these until after ieee80211_ifdetach
- * returns because we'll get called back to reclaim node
- * state and potentially want to use them.
- */
-}
-
-
-
-
/********************\
* Channel/mode setup *
\********************/
@@ -1163,8 +511,101 @@ ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
}
}
+struct ath_vif_iter_data {
+ const u8 *hw_macaddr;
+ u8 mask[ETH_ALEN];
+ u8 active_mac[ETH_ALEN]; /* first active MAC */
+ bool need_set_hw_addr;
+ bool found_active;
+ bool any_assoc;
+ enum nl80211_iftype opmode;
+};
+
+static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+ struct ath_vif_iter_data *iter_data = data;
+ int i;
+ struct ath5k_vif *avf = (void *)vif->drv_priv;
+
+ if (iter_data->hw_macaddr)
+ for (i = 0; i < ETH_ALEN; i++)
+ iter_data->mask[i] &=
+ ~(iter_data->hw_macaddr[i] ^ mac[i]);
+
+ if (!iter_data->found_active) {
+ iter_data->found_active = true;
+ memcpy(iter_data->active_mac, mac, ETH_ALEN);
+ }
+
+ if (iter_data->need_set_hw_addr && iter_data->hw_macaddr)
+ if (compare_ether_addr(iter_data->hw_macaddr, mac) == 0)
+ iter_data->need_set_hw_addr = false;
+
+ if (!iter_data->any_assoc) {
+ if (avf->assoc)
+ iter_data->any_assoc = true;
+ }
+
+ /* Calculate combined mode - when APs are active, operate in AP mode.
+ * Otherwise use the mode of the new interface. This can currently
+ * only deal with combinations of APs and STAs. Only one ad-hoc
+ * interfaces is allowed above.
+ */
+ if (avf->opmode == NL80211_IFTYPE_AP)
+ iter_data->opmode = NL80211_IFTYPE_AP;
+ else
+ if (iter_data->opmode == NL80211_IFTYPE_UNSPECIFIED)
+ iter_data->opmode = avf->opmode;
+}
+
+static void ath_do_set_opmode(struct ath5k_softc *sc)
+{
+ struct ath5k_hw *ah = sc->ah;
+ ath5k_hw_set_opmode(ah, sc->opmode);
+ ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d (%s)\n",
+ sc->opmode, ath_opmode_to_string(sc->opmode));
+}
+
+void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
+ struct ieee80211_vif *vif)
+{
+ struct ath_common *common = ath5k_hw_common(sc->ah);
+ struct ath_vif_iter_data iter_data;
+
+ /*
+ * Use the hardware MAC address as reference, the hardware uses it
+ * together with the BSSID mask when matching addresses.
+ */
+ iter_data.hw_macaddr = common->macaddr;
+ memset(&iter_data.mask, 0xff, ETH_ALEN);
+ iter_data.found_active = false;
+ iter_data.need_set_hw_addr = true;
+ iter_data.opmode = NL80211_IFTYPE_UNSPECIFIED;
+
+ if (vif)
+ ath_vif_iter(&iter_data, vif->addr, vif);
+
+ /* Get list of all active MAC addresses */
+ ieee80211_iterate_active_interfaces_atomic(sc->hw, ath_vif_iter,
+ &iter_data);
+ memcpy(sc->bssidmask, iter_data.mask, ETH_ALEN);
+
+ sc->opmode = iter_data.opmode;
+ if (sc->opmode == NL80211_IFTYPE_UNSPECIFIED)
+ /* Nothing active, default to station mode */
+ sc->opmode = NL80211_IFTYPE_STATION;
+
+ ath_do_set_opmode(sc);
+
+ if (iter_data.need_set_hw_addr && iter_data.found_active)
+ ath5k_hw_set_lladdr(sc->ah, iter_data.active_mac);
+
+ if (ath5k_hw_hasbssidmask(sc->ah))
+ ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
+}
+
static void
-ath5k_mode_setup(struct ath5k_softc *sc)
+ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif)
{
struct ath5k_hw *ah = sc->ah;
u32 rfilt;
@@ -1172,15 +613,9 @@ ath5k_mode_setup(struct ath5k_softc *sc)
/* configure rx filter */
rfilt = sc->filter_flags;
ath5k_hw_set_rx_filter(ah, rfilt);
-
- if (ath5k_hw_hasbssidmask(ah))
- ath5k_hw_set_bssid_mask(ah, sc->bssidmask);
-
- /* configure operational mode */
- ath5k_hw_set_opmode(ah, sc->opmode);
-
- ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d\n", sc->opmode);
ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt);
+
+ ath5k_update_bssid_mask_and_opmode(sc, vif);
}
static inline int
@@ -1352,13 +787,13 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
flags |= AR5K_TXDESC_RTSENA;
cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value;
duration = le16_to_cpu(ieee80211_rts_duration(sc->hw,
- sc->vif, pktlen, info));
+ info->control.vif, pktlen, info));
}
if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
flags |= AR5K_TXDESC_CTSENA;
cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value;
duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw,
- sc->vif, pktlen, info));
+ info->control.vif, pktlen, info));
}
ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
ieee80211_get_hdrlen_from_skb(skb), padsize,
@@ -1391,6 +826,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
spin_lock_bh(&txq->lock);
list_add_tail(&bf->list, &txq->q);
+ txq->txq_len++;
if (txq->link == NULL) /* is this first packet? */
ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr);
else /* no, so only link it */
@@ -1459,10 +895,13 @@ ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev)
list_add_tail(&bf->list, &sc->txbuf);
}
- /* beacon buffer */
- bf->desc = ds;
- bf->daddr = da;
- sc->bbuf = bf;
+ /* beacon buffers */
+ INIT_LIST_HEAD(&sc->bcbuf);
+ for (i = 0; i < ATH_BCBUF; i++, bf++, ds++, da += sizeof(*ds)) {
+ bf->desc = ds;
+ bf->daddr = da;
+ list_add_tail(&bf->list, &sc->bcbuf);
+ }
return 0;
err_free:
@@ -1477,11 +916,12 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
{
struct ath5k_buf *bf;
- ath5k_txbuf_free_skb(sc, sc->bbuf);
list_for_each_entry(bf, &sc->txbuf, list)
ath5k_txbuf_free_skb(sc, bf);
list_for_each_entry(bf, &sc->rxbuf, list)
ath5k_rxbuf_free_skb(sc, bf);
+ list_for_each_entry(bf, &sc->bcbuf, list)
+ ath5k_txbuf_free_skb(sc, bf);
/* Free memory associated with all descriptors */
pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
@@ -1490,13 +930,9 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
kfree(sc->bufptr);
sc->bufptr = NULL;
- sc->bbuf = NULL;
}
-
-
-
/**************\
* Queues setup *
\**************/
@@ -1509,16 +945,18 @@ ath5k_txq_setup(struct ath5k_softc *sc,
struct ath5k_txq *txq;
struct ath5k_txq_info qi = {
.tqi_subtype = subtype,
- .tqi_aifs = AR5K_TXQ_USEDEFAULT,
- .tqi_cw_min = AR5K_TXQ_USEDEFAULT,
- .tqi_cw_max = AR5K_TXQ_USEDEFAULT
+ /* XXX: default values not correct for B and XR channels,
+ * but who cares? */
+ .tqi_aifs = AR5K_TUNE_AIFS,
+ .tqi_cw_min = AR5K_TUNE_CWMIN,
+ .tqi_cw_max = AR5K_TUNE_CWMAX
};
int qnum;
/*
* Enable interrupts only for EOL and DESC conditions.
* We mark tx descriptors to receive a DESC interrupt
- * when a tx queue gets deep; otherwise waiting for the
+ * when a tx queue gets deep; otherwise we wait for the
* EOL to reap descriptors. Note that this is done to
* reduce interrupt load and this only defers reaping
* descriptors, never transmitting frames. Aside from
@@ -1550,6 +988,9 @@ ath5k_txq_setup(struct ath5k_softc *sc,
INIT_LIST_HEAD(&txq->q);
spin_lock_init(&txq->lock);
txq->setup = true;
+ txq->txq_len = 0;
+ txq->txq_poll_mark = false;
+ txq->txq_stuck = 0;
}
return &sc->txqs[qnum];
}
@@ -1558,9 +999,11 @@ static int
ath5k_beaconq_setup(struct ath5k_hw *ah)
{
struct ath5k_txq_info qi = {
- .tqi_aifs = AR5K_TXQ_USEDEFAULT,
- .tqi_cw_min = AR5K_TXQ_USEDEFAULT,
- .tqi_cw_max = AR5K_TXQ_USEDEFAULT,
+ /* XXX: default values not correct for B and XR channels,
+ * but who cares? */
+ .tqi_aifs = AR5K_TUNE_AIFS,
+ .tqi_cw_min = AR5K_TUNE_CWMIN,
+ .tqi_cw_max = AR5K_TUNE_CWMAX,
/* NB: for dynamic turbo, don't enable any other interrupts */
.tqi_flags = AR5K_TXQ_FLAG_TXDESCINT_ENABLE
};
@@ -1594,7 +1037,7 @@ ath5k_beaconq_config(struct ath5k_softc *sc)
*/
qi.tqi_aifs = 0;
qi.tqi_cw_min = 0;
- qi.tqi_cw_max = 2 * ah->ah_cw_min;
+ qi.tqi_cw_max = 2 * AR5K_TUNE_CWMIN;
}
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
@@ -1644,9 +1087,11 @@ ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
spin_lock_bh(&sc->txbuflock);
list_move_tail(&bf->list, &sc->txbuf);
sc->txbuf_len++;
+ txq->txq_len--;
spin_unlock_bh(&sc->txbuflock);
}
txq->link = NULL;
+ txq->txq_poll_mark = false;
spin_unlock_bh(&txq->lock);
}
@@ -1696,8 +1141,6 @@ ath5k_txq_release(struct ath5k_softc *sc)
}
-
-
/*************\
* RX Handling *
\*************/
@@ -1713,7 +1156,7 @@ ath5k_rx_start(struct ath5k_softc *sc)
struct ath5k_buf *bf;
int ret;
- common->rx_bufsize = roundup(IEEE80211_MAX_LEN, common->cachelsz);
+ common->rx_bufsize = roundup(IEEE80211_MAX_FRAME_LEN, common->cachelsz);
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rx_bufsize %u\n",
common->cachelsz, common->rx_bufsize);
@@ -1732,7 +1175,7 @@ ath5k_rx_start(struct ath5k_softc *sc)
spin_unlock_bh(&sc->rxbuflock);
ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */
- ath5k_mode_setup(sc); /* set filters, etc. */
+ ath5k_mode_setup(sc, NULL); /* set filters, etc. */
ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */
return 0;
@@ -1840,6 +1283,15 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
*/
if (hw_tu >= sc->nexttbtt)
ath5k_beacon_update_timers(sc, bc_tstamp);
+
+ /* Check if the beacon timers are still correct, because a TSF
+ * update might have created a window between them - for a
+ * longer description see the comment of this function: */
+ if (!ath5k_hw_check_beacon_timers(sc->ah, sc->bintval)) {
+ ath5k_beacon_update_timers(sc, bc_tstamp);
+ ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+ "fixed beacon timers after beacon receive\n");
+ }
}
}
@@ -1863,7 +1315,7 @@ ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi)
}
/*
- * Compute padding position. skb must contains an IEEE 802.11 frame
+ * Compute padding position. skb must contain an IEEE 802.11 frame
*/
static int ath5k_common_padpos(struct sk_buff *skb)
{
@@ -1882,10 +1334,9 @@ static int ath5k_common_padpos(struct sk_buff *skb)
}
/*
- * This function expects a 802.11 frame and returns the number of
- * bytes added, or -1 if we don't have enought header room.
+ * This function expects an 802.11 frame and returns the number of
+ * bytes added, or -1 if we don't have enough header room.
*/
-
static int ath5k_add_padding(struct sk_buff *skb)
{
int padpos = ath5k_common_padpos(skb);
@@ -1905,10 +1356,18 @@ static int ath5k_add_padding(struct sk_buff *skb)
}
/*
- * This function expects a 802.11 frame and returns the number of
- * bytes removed
+ * The MAC header is padded to have 32-bit boundary if the
+ * packet payload is non-zero. The general calculation for
+ * padsize would take into account odd header lengths:
+ * padsize = 4 - (hdrlen & 3); however, since only
+ * even-length headers are used, padding can only be 0 or 2
+ * bytes and we can optimize this a bit. We must not try to
+ * remove padding from short control frames that do not have a
+ * payload.
+ *
+ * This function expects an 802.11 frame and returns the number of
+ * bytes removed.
*/
-
static int ath5k_remove_padding(struct sk_buff *skb)
{
int padpos = ath5k_common_padpos(skb);
@@ -1929,14 +1388,6 @@ ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb,
{
struct ieee80211_rx_status *rxs;
- /* The MAC header is padded to have 32-bit boundary if the
- * packet payload is non-zero. The general calculation for
- * padsize would take into account odd header lengths:
- * padsize = (4 - hdrlen % 4) % 4; However, since only
- * even-length headers are used, padding can only be 0 or 2
- * bytes and we can optimize this a bit. In addition, we must
- * not try to remove padding from short control frames that do
- * not have payload. */
ath5k_remove_padding(skb);
rxs = IEEE80211_SKB_RXCB(skb);
@@ -2007,6 +1458,7 @@ static bool
ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs)
{
sc->stats.rx_all_count++;
+ sc->stats.rx_bytes_count += rs->rs_datalen;
if (unlikely(rs->rs_status)) {
if (rs->rs_status & AR5K_RXERR_CRC)
@@ -2040,9 +1492,8 @@ ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs)
return true;
}
- /* let crypto-error packets fall through in MNTR */
- if ((rs->rs_status & ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) ||
- sc->opmode != NL80211_IFTYPE_MONITOR)
+ /* reject any frames with non-crypto errors */
+ if (rs->rs_status & ~(AR5K_RXERR_DECRYPT))
return false;
}
@@ -2123,6 +1574,118 @@ unlock:
* TX Handling *
\*************/
+static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ath5k_txq *txq)
+{
+ struct ath5k_softc *sc = hw->priv;
+ struct ath5k_buf *bf;
+ unsigned long flags;
+ int padsize;
+
+ ath5k_debug_dump_skb(sc, skb, "TX ", 1);
+
+ /*
+ * The hardware expects the header padded to 4 byte boundaries.
+ * If this is not the case, we add the padding after the header.
+ */
+ padsize = ath5k_add_padding(skb);
+ if (padsize < 0) {
+ ATH5K_ERR(sc, "tx hdrlen not %%4: not enough"
+ " headroom to pad");
+ goto drop_packet;
+ }
+
+ if (txq->txq_len >= ATH5K_TXQ_LEN_MAX)
+ ieee80211_stop_queue(hw, txq->qnum);
+
+ spin_lock_irqsave(&sc->txbuflock, flags);
+ if (list_empty(&sc->txbuf)) {
+ ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");
+ spin_unlock_irqrestore(&sc->txbuflock, flags);
+ ieee80211_stop_queues(hw);
+ goto drop_packet;
+ }
+ bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list);
+ list_del(&bf->list);
+ sc->txbuf_len--;
+ if (list_empty(&sc->txbuf))
+ ieee80211_stop_queues(hw);
+ spin_unlock_irqrestore(&sc->txbuflock, flags);
+
+ bf->skb = skb;
+
+ if (ath5k_txbuf_setup(sc, bf, txq, padsize)) {
+ bf->skb = NULL;
+ spin_lock_irqsave(&sc->txbuflock, flags);
+ list_add_tail(&bf->list, &sc->txbuf);
+ sc->txbuf_len++;
+ spin_unlock_irqrestore(&sc->txbuflock, flags);
+ goto drop_packet;
+ }
+ return NETDEV_TX_OK;
+
+drop_packet:
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+}
+
+static void
+ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb,
+ struct ath5k_tx_status *ts)
+{
+ struct ieee80211_tx_info *info;
+ int i;
+
+ sc->stats.tx_all_count++;
+ sc->stats.tx_bytes_count += skb->len;
+ info = IEEE80211_SKB_CB(skb);
+
+ ieee80211_tx_info_clear_status(info);
+ for (i = 0; i < 4; i++) {
+ struct ieee80211_tx_rate *r =
+ &info->status.rates[i];
+
+ if (ts->ts_rate[i]) {
+ r->idx = ath5k_hw_to_driver_rix(sc, ts->ts_rate[i]);
+ r->count = ts->ts_retry[i];
+ } else {
+ r->idx = -1;
+ r->count = 0;
+ }
+ }
+
+ /* count the successful attempt as well */
+ info->status.rates[ts->ts_final_idx].count++;
+
+ if (unlikely(ts->ts_status)) {
+ sc->stats.ack_fail++;
+ if (ts->ts_status & AR5K_TXERR_FILT) {
+ info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+ sc->stats.txerr_filt++;
+ }
+ if (ts->ts_status & AR5K_TXERR_XRETRY)
+ sc->stats.txerr_retry++;
+ if (ts->ts_status & AR5K_TXERR_FIFO)
+ sc->stats.txerr_fifo++;
+ } else {
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ info->status.ack_signal = ts->ts_rssi;
+ }
+
+ /*
+ * Remove MAC header padding before giving the frame
+ * back to mac80211.
+ */
+ ath5k_remove_padding(skb);
+
+ if (ts->ts_antenna > 0 && ts->ts_antenna < 5)
+ sc->stats.antenna_tx[ts->ts_antenna]++;
+ else
+ sc->stats.antenna_tx[0]++; /* invalid */
+
+ ieee80211_tx_status(sc->hw, skb);
+}
+
static void
ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
{
@@ -2130,96 +1693,51 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
struct ath5k_buf *bf, *bf0;
struct ath5k_desc *ds;
struct sk_buff *skb;
- struct ieee80211_tx_info *info;
- int i, ret;
+ int ret;
spin_lock(&txq->lock);
list_for_each_entry_safe(bf, bf0, &txq->q, list) {
- ds = bf->desc;
- /*
- * It's possible that the hardware can say the buffer is
- * completed when it hasn't yet loaded the ds_link from
- * host memory and moved on. If there are more TX
- * descriptors in the queue, wait for TXDP to change
- * before processing this one.
- */
- if (ath5k_hw_get_txdp(sc->ah, txq->qnum) == bf->daddr &&
- !list_is_last(&bf->list, &txq->q))
- break;
+ txq->txq_poll_mark = false;
- ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts);
- if (unlikely(ret == -EINPROGRESS))
- break;
- else if (unlikely(ret)) {
- ATH5K_ERR(sc, "error %d while processing queue %u\n",
- ret, txq->qnum);
- break;
- }
-
- sc->stats.tx_all_count++;
- skb = bf->skb;
- info = IEEE80211_SKB_CB(skb);
- bf->skb = NULL;
-
- pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
- PCI_DMA_TODEVICE);
+ /* skb might already have been processed last time. */
+ if (bf->skb != NULL) {
+ ds = bf->desc;
- ieee80211_tx_info_clear_status(info);
- for (i = 0; i < 4; i++) {
- struct ieee80211_tx_rate *r =
- &info->status.rates[i];
-
- if (ts.ts_rate[i]) {
- r->idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]);
- r->count = ts.ts_retry[i];
- } else {
- r->idx = -1;
- r->count = 0;
+ ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts);
+ if (unlikely(ret == -EINPROGRESS))
+ break;
+ else if (unlikely(ret)) {
+ ATH5K_ERR(sc,
+ "error %d while processing "
+ "queue %u\n", ret, txq->qnum);
+ break;
}
- }
- /* count the successful attempt as well */
- info->status.rates[ts.ts_final_idx].count++;
-
- if (unlikely(ts.ts_status)) {
- sc->stats.ack_fail++;
- if (ts.ts_status & AR5K_TXERR_FILT) {
- info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
- sc->stats.txerr_filt++;
- }
- if (ts.ts_status & AR5K_TXERR_XRETRY)
- sc->stats.txerr_retry++;
- if (ts.ts_status & AR5K_TXERR_FIFO)
- sc->stats.txerr_fifo++;
- } else {
- info->flags |= IEEE80211_TX_STAT_ACK;
- info->status.ack_signal = ts.ts_rssi;
+ skb = bf->skb;
+ bf->skb = NULL;
+ pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
+ PCI_DMA_TODEVICE);
+ ath5k_tx_frame_completed(sc, skb, &ts);
}
/*
- * Remove MAC header padding before giving the frame
- * back to mac80211.
+ * It's possible that the hardware can say the buffer is
+ * completed when it hasn't yet loaded the ds_link from
+ * host memory and moved on.
+ * Always keep the last descriptor to avoid HW races...
*/
- ath5k_remove_padding(skb);
-
- if (ts.ts_antenna > 0 && ts.ts_antenna < 5)
- sc->stats.antenna_tx[ts.ts_antenna]++;
- else
- sc->stats.antenna_tx[0]++; /* invalid */
-
- ieee80211_tx_status(sc->hw, skb);
-
- spin_lock(&sc->txbuflock);
- list_move_tail(&bf->list, &sc->txbuf);
- sc->txbuf_len++;
- spin_unlock(&sc->txbuflock);
+ if (ath5k_hw_get_txdp(sc->ah, txq->qnum) != bf->daddr) {
+ spin_lock(&sc->txbuflock);
+ list_move_tail(&bf->list, &sc->txbuf);
+ sc->txbuf_len++;
+ txq->txq_len--;
+ spin_unlock(&sc->txbuflock);
+ }
}
- if (likely(list_empty(&txq->q)))
- txq->link = NULL;
spin_unlock(&txq->lock);
- if (sc->txbuf_len > ATH_TXBUF / 5)
- ieee80211_wake_queues(sc->hw);
+ if (txq->txq_len < ATH5K_TXQ_LEN_LOW && txq->qnum < 4)
+ ieee80211_wake_queue(sc->hw, txq->qnum);
}
static void
@@ -2285,10 +1803,11 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
* default antenna which is supposed to be an omni.
*
* Note2: On sectored scenarios it's possible to have
- * multiple antennas (1omni -the default- and 14 sectors)
- * so if we choose to actually support this mode we need
- * to allow user to set how many antennas we have and tweak
- * the code below to send beacons on all of them.
+ * multiple antennas (1 omni -- the default -- and 14
+ * sectors), so if we choose to actually support this
+ * mode, we need to allow the user to set how many antennas
+ * we have and tweak the code below to send beacons
+ * on all of them.
*/
if (ah->ah_ant_mode == AR5K_ANTMODE_SECTOR_AP)
antenna = sc->bsent & 4 ? 2 : 1;
@@ -2314,6 +1833,44 @@ err_unmap:
}
/*
+ * Updates the beacon that is sent by ath5k_beacon_send. For adhoc,
+ * this is called only once at config_bss time, for AP we do it every
+ * SWBA interrupt so that the TIM will reflect buffered frames.
+ *
+ * Called with the beacon lock.
+ */
+static int
+ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+ int ret;
+ struct ath5k_softc *sc = hw->priv;
+ struct ath5k_vif *avf = (void *)vif->drv_priv;
+ struct sk_buff *skb;
+
+ if (WARN_ON(!vif)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ skb = ieee80211_beacon_get(hw, vif);
+
+ if (!skb) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ath5k_debug_dump_skb(sc, skb, "BC ", 1);
+
+ ath5k_txbuf_free_skb(sc, avf->bbuf);
+ avf->bbuf->skb = skb;
+ ret = ath5k_beacon_setup(sc, avf->bbuf);
+ if (ret)
+ avf->bbuf->skb = NULL;
+out:
+ return ret;
+}
+
+/*
* Transmit a beacon frame at SWBA. Dynamic updates to the
* frame contents are done as needed and the slot time is
* also adjusted based on current state.
@@ -2324,20 +1881,17 @@ err_unmap:
static void
ath5k_beacon_send(struct ath5k_softc *sc)
{
- struct ath5k_buf *bf = sc->bbuf;
struct ath5k_hw *ah = sc->ah;
+ struct ieee80211_vif *vif;
+ struct ath5k_vif *avf;
+ struct ath5k_buf *bf;
struct sk_buff *skb;
ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
- if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION ||
- sc->opmode == NL80211_IFTYPE_MONITOR)) {
- ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
- return;
- }
/*
* Check if the previous beacon has gone out. If
- * not don't don't try to post another, skip this
+ * not, don't don't try to post another: skip this
* period and wait for the next. Missed beacons
* indicate a problem and should not occur. If we
* miss too many consecutive beacons reset the device.
@@ -2363,6 +1917,28 @@ ath5k_beacon_send(struct ath5k_softc *sc)
sc->bmisscount = 0;
}
+ if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) {
+ u64 tsf = ath5k_hw_get_tsf64(ah);
+ u32 tsftu = TSF_TO_TU(tsf);
+ int slot = ((tsftu % sc->bintval) * ATH_BCBUF) / sc->bintval;
+ vif = sc->bslot[(slot + 1) % ATH_BCBUF];
+ ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
+ "tsf %llx tsftu %x intval %u slot %u vif %p\n",
+ (unsigned long long)tsf, tsftu, sc->bintval, slot, vif);
+ } else /* only one interface */
+ vif = sc->bslot[0];
+
+ if (!vif)
+ return;
+
+ avf = (void *)vif->drv_priv;
+ bf = avf->bbuf;
+ if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION ||
+ sc->opmode == NL80211_IFTYPE_MONITOR)) {
+ ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
+ return;
+ }
+
/*
* Stop any current dma and put the new frame on the queue.
* This should never fail since we check above that no frames
@@ -2375,23 +1951,22 @@ ath5k_beacon_send(struct ath5k_softc *sc)
/* refresh the beacon for AP mode */
if (sc->opmode == NL80211_IFTYPE_AP)
- ath5k_beacon_update(sc->hw, sc->vif);
+ ath5k_beacon_update(sc->hw, vif);
ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr);
ath5k_hw_start_tx_dma(ah, sc->bhalq);
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
sc->bhalq, (unsigned long long)bf->daddr, bf->desc);
- skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+ skb = ieee80211_get_buffered_bc(sc->hw, vif);
while (skb) {
ath5k_tx_queue(sc->hw, skb, sc->cabq);
- skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+ skb = ieee80211_get_buffered_bc(sc->hw, vif);
}
sc->bsent++;
}
-
/**
* ath5k_beacon_update_timers - update beacon timers
*
@@ -2416,6 +1991,12 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
u64 hw_tsf;
intval = sc->bintval & AR5K_BEACON_PERIOD;
+ if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) {
+ intval /= ATH_BCBUF; /* staggered multi-bss beacons */
+ if (intval < 15)
+ ATH5K_WARN(sc, "intval %u is too low, min 15\n",
+ intval);
+ }
if (WARN_ON(!intval))
return;
@@ -2426,8 +2007,11 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
hw_tsf = ath5k_hw_get_tsf64(ah);
hw_tu = TSF_TO_TU(hw_tsf);
-#define FUDGE 3
- /* we use FUDGE to make sure the next TBTT is ahead of the current TU */
+#define FUDGE AR5K_TUNE_SW_BEACON_RESP + 3
+ /* We use FUDGE to make sure the next TBTT is ahead of the current TU.
+ * Since we later substract AR5K_TUNE_SW_BEACON_RESP (10) in the timer
+ * configuration we need to make sure it is bigger than that. */
+
if (bc_tsf == -1) {
/*
* no beacons received, called internally.
@@ -2493,7 +2077,6 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
intval & AR5K_BEACON_RESET_TSF ? "AR5K_BEACON_RESET_TSF" : "");
}
-
/**
* ath5k_beacon_config - Configure the beacon queues and interrupts
*
@@ -2572,155 +2155,6 @@ static void ath5k_tasklet_beacon(unsigned long data)
* Interrupt handling *
\********************/
-static int
-ath5k_init(struct ath5k_softc *sc)
-{
- struct ath5k_hw *ah = sc->ah;
- int ret, i;
-
- mutex_lock(&sc->lock);
-
- ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode);
-
- /*
- * Stop anything previously setup. This is safe
- * no matter this is the first time through or not.
- */
- ath5k_stop_locked(sc);
-
- /*
- * The basic interface to setting the hardware in a good
- * state is ``reset''. On return the hardware is known to
- * be powered up and with interrupts disabled. This must
- * be followed by initialization of the appropriate bits
- * and then setup of the interrupt mask.
- */
- sc->curchan = sc->hw->conf.channel;
- sc->curband = &sc->sbands[sc->curchan->band];
- sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
- AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
- AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB;
-
- ret = ath5k_reset(sc, NULL);
- if (ret)
- goto done;
-
- ath5k_rfkill_hw_start(ah);
-
- /*
- * Reset the key cache since some parts do not reset the
- * contents on initial power up or resume from suspend.
- */
- for (i = 0; i < AR5K_KEYTABLE_SIZE; i++)
- ath5k_hw_reset_key(ah, i);
-
- ath5k_hw_set_ack_bitrate_high(ah, true);
- ret = 0;
-done:
- mmiowb();
- mutex_unlock(&sc->lock);
- return ret;
-}
-
-static int
-ath5k_stop_locked(struct ath5k_softc *sc)
-{
- struct ath5k_hw *ah = sc->ah;
-
- ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "invalid %u\n",
- test_bit(ATH_STAT_INVALID, sc->status));
-
- /*
- * Shutdown the hardware and driver:
- * stop output from above
- * disable interrupts
- * turn off timers
- * turn off the radio
- * clear transmit machinery
- * clear receive machinery
- * drain and release tx queues
- * reclaim beacon resources
- * power down hardware
- *
- * Note that some of this work is not possible if the
- * hardware is gone (invalid).
- */
- ieee80211_stop_queues(sc->hw);
-
- if (!test_bit(ATH_STAT_INVALID, sc->status)) {
- ath5k_led_off(sc);
- ath5k_hw_set_imr(ah, 0);
- synchronize_irq(sc->pdev->irq);
- }
- ath5k_txq_cleanup(sc);
- if (!test_bit(ATH_STAT_INVALID, sc->status)) {
- ath5k_rx_stop(sc);
- ath5k_hw_phy_disable(ah);
- }
-
- return 0;
-}
-
-static void stop_tasklets(struct ath5k_softc *sc)
-{
- tasklet_kill(&sc->rxtq);
- tasklet_kill(&sc->txtq);
- tasklet_kill(&sc->calib);
- tasklet_kill(&sc->beacontq);
- tasklet_kill(&sc->ani_tasklet);
-}
-
-/*
- * Stop the device, grabbing the top-level lock to protect
- * against concurrent entry through ath5k_init (which can happen
- * if another thread does a system call and the thread doing the
- * stop is preempted).
- */
-static int
-ath5k_stop_hw(struct ath5k_softc *sc)
-{
- int ret;
-
- mutex_lock(&sc->lock);
- ret = ath5k_stop_locked(sc);
- if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) {
- /*
- * Don't set the card in full sleep mode!
- *
- * a) When the device is in this state it must be carefully
- * woken up or references to registers in the PCI clock
- * domain may freeze the bus (and system). This varies
- * by chip and is mostly an issue with newer parts
- * (madwifi sources mentioned srev >= 0x78) that go to
- * sleep more quickly.
- *
- * b) On older chips full sleep results a weird behaviour
- * during wakeup. I tested various cards with srev < 0x78
- * and they don't wake up after module reload, a second
- * module reload is needed to bring the card up again.
- *
- * Until we figure out what's going on don't enable
- * full chip reset on any chip (this is what Legacy HAL
- * and Sam's HAL do anyway). Instead Perform a full reset
- * on the device (same as initial state after attach) and
- * leave it idle (keep MAC/BB on warm reset) */
- ret = ath5k_hw_on_hold(sc->ah);
-
- ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
- "putting device to sleep\n");
- }
- ath5k_txbuf_free_skb(sc, sc->bbuf);
-
- mmiowb();
- mutex_unlock(&sc->lock);
-
- stop_tasklets(sc);
-
- ath5k_rfkill_hw_stop(sc->ah);
-
- return ret;
-}
-
static void
ath5k_intr_calibration_poll(struct ath5k_hw *ah)
{
@@ -2857,14 +2291,13 @@ ath5k_tasklet_calibrate(unsigned long data)
sc->curchan->center_freq));
/* Noise floor calibration interrupts rx/tx path while I/Q calibration
- * doesn't. We stop the queues so that calibration doesn't interfere
- * with TX and don't run it as often */
+ * doesn't.
+ * TODO: We should stop TX here, so that it doesn't interfere.
+ * Note that stopping the queues is not enough to stop TX! */
if (time_is_before_eq_jiffies(ah->ah_cal_next_nf)) {
ah->ah_cal_next_nf = jiffies +
msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_NF);
- ieee80211_stop_queues(sc->hw);
ath5k_hw_update_noise_floor(ah);
- ieee80211_wake_queues(sc->hw);
}
ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
@@ -2883,71 +2316,208 @@ ath5k_tasklet_ani(unsigned long data)
}
-/********************\
-* Mac80211 functions *
-\********************/
+static void
+ath5k_tx_complete_poll_work(struct work_struct *work)
+{
+ struct ath5k_softc *sc = container_of(work, struct ath5k_softc,
+ tx_complete_work.work);
+ struct ath5k_txq *txq;
+ int i;
+ bool needreset = false;
+
+ for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) {
+ if (sc->txqs[i].setup) {
+ txq = &sc->txqs[i];
+ spin_lock_bh(&txq->lock);
+ if (txq->txq_len > 1) {
+ if (txq->txq_poll_mark) {
+ ATH5K_DBG(sc, ATH5K_DEBUG_XMIT,
+ "TX queue stuck %d\n",
+ txq->qnum);
+ needreset = true;
+ txq->txq_stuck++;
+ spin_unlock_bh(&txq->lock);
+ break;
+ } else {
+ txq->txq_poll_mark = true;
+ }
+ }
+ spin_unlock_bh(&txq->lock);
+ }
+ }
+
+ if (needreset) {
+ ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
+ "TX queues stuck, resetting\n");
+ ath5k_reset(sc, sc->curchan);
+ }
+
+ ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
+ msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT));
+}
+
+
+/*************************\
+* Initialization routines *
+\*************************/
static int
-ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+ath5k_stop_locked(struct ath5k_softc *sc)
{
- struct ath5k_softc *sc = hw->priv;
+ struct ath5k_hw *ah = sc->ah;
+
+ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "invalid %u\n",
+ test_bit(ATH_STAT_INVALID, sc->status));
+
+ /*
+ * Shutdown the hardware and driver:
+ * stop output from above
+ * disable interrupts
+ * turn off timers
+ * turn off the radio
+ * clear transmit machinery
+ * clear receive machinery
+ * drain and release tx queues
+ * reclaim beacon resources
+ * power down hardware
+ *
+ * Note that some of this work is not possible if the
+ * hardware is gone (invalid).
+ */
+ ieee80211_stop_queues(sc->hw);
- return ath5k_tx_queue(hw, skb, sc->txq);
+ if (!test_bit(ATH_STAT_INVALID, sc->status)) {
+ ath5k_led_off(sc);
+ ath5k_hw_set_imr(ah, 0);
+ synchronize_irq(sc->pdev->irq);
+ }
+ ath5k_txq_cleanup(sc);
+ if (!test_bit(ATH_STAT_INVALID, sc->status)) {
+ ath5k_rx_stop(sc);
+ ath5k_hw_phy_disable(ah);
+ }
+
+ return 0;
}
-static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ath5k_txq *txq)
+static int
+ath5k_init(struct ath5k_softc *sc)
{
- struct ath5k_softc *sc = hw->priv;
- struct ath5k_buf *bf;
- unsigned long flags;
- int padsize;
+ struct ath5k_hw *ah = sc->ah;
+ struct ath_common *common = ath5k_hw_common(ah);
+ int ret, i;
- ath5k_debug_dump_skb(sc, skb, "TX ", 1);
+ mutex_lock(&sc->lock);
- if (sc->opmode == NL80211_IFTYPE_MONITOR)
- ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n");
+ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode);
/*
- * the hardware expects the header padded to 4 byte boundaries
- * if this is not the case we add the padding after the header
+ * Stop anything previously setup. This is safe
+ * no matter this is the first time through or not.
*/
- padsize = ath5k_add_padding(skb);
- if (padsize < 0) {
- ATH5K_ERR(sc, "tx hdrlen not %%4: not enough"
- " headroom to pad");
- goto drop_packet;
- }
+ ath5k_stop_locked(sc);
- spin_lock_irqsave(&sc->txbuflock, flags);
- if (list_empty(&sc->txbuf)) {
- ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");
- spin_unlock_irqrestore(&sc->txbuflock, flags);
- ieee80211_stop_queue(hw, skb_get_queue_mapping(skb));
- goto drop_packet;
- }
- bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list);
- list_del(&bf->list);
- sc->txbuf_len--;
- if (list_empty(&sc->txbuf))
- ieee80211_stop_queues(hw);
- spin_unlock_irqrestore(&sc->txbuflock, flags);
+ /*
+ * The basic interface to setting the hardware in a good
+ * state is ``reset''. On return the hardware is known to
+ * be powered up and with interrupts disabled. This must
+ * be followed by initialization of the appropriate bits
+ * and then setup of the interrupt mask.
+ */
+ sc->curchan = sc->hw->conf.channel;
+ sc->curband = &sc->sbands[sc->curchan->band];
+ sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
+ AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
+ AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB;
- bf->skb = skb;
+ ret = ath5k_reset(sc, NULL);
+ if (ret)
+ goto done;
- if (ath5k_txbuf_setup(sc, bf, txq, padsize)) {
- bf->skb = NULL;
- spin_lock_irqsave(&sc->txbuflock, flags);
- list_add_tail(&bf->list, &sc->txbuf);
- sc->txbuf_len++;
- spin_unlock_irqrestore(&sc->txbuflock, flags);
- goto drop_packet;
+ ath5k_rfkill_hw_start(ah);
+
+ /*
+ * Reset the key cache since some parts do not reset the
+ * contents on initial power up or resume from suspend.
+ */
+ for (i = 0; i < common->keymax; i++)
+ ath_hw_keyreset(common, (u16) i);
+
+ ath5k_hw_set_ack_bitrate_high(ah, true);
+
+ for (i = 0; i < ARRAY_SIZE(sc->bslot); i++)
+ sc->bslot[i] = NULL;
+
+ ret = 0;
+done:
+ mmiowb();
+ mutex_unlock(&sc->lock);
+
+ ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
+ msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT));
+
+ return ret;
+}
+
+static void stop_tasklets(struct ath5k_softc *sc)
+{
+ tasklet_kill(&sc->rxtq);
+ tasklet_kill(&sc->txtq);
+ tasklet_kill(&sc->calib);
+ tasklet_kill(&sc->beacontq);
+ tasklet_kill(&sc->ani_tasklet);
+}
+
+/*
+ * Stop the device, grabbing the top-level lock to protect
+ * against concurrent entry through ath5k_init (which can happen
+ * if another thread does a system call and the thread doing the
+ * stop is preempted).
+ */
+static int
+ath5k_stop_hw(struct ath5k_softc *sc)
+{
+ int ret;
+
+ mutex_lock(&sc->lock);
+ ret = ath5k_stop_locked(sc);
+ if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) {
+ /*
+ * Don't set the card in full sleep mode!
+ *
+ * a) When the device is in this state it must be carefully
+ * woken up or references to registers in the PCI clock
+ * domain may freeze the bus (and system). This varies
+ * by chip and is mostly an issue with newer parts
+ * (madwifi sources mentioned srev >= 0x78) that go to
+ * sleep more quickly.
+ *
+ * b) On older chips full sleep results a weird behaviour
+ * during wakeup. I tested various cards with srev < 0x78
+ * and they don't wake up after module reload, a second
+ * module reload is needed to bring the card up again.
+ *
+ * Until we figure out what's going on don't enable
+ * full chip reset on any chip (this is what Legacy HAL
+ * and Sam's HAL do anyway). Instead Perform a full reset
+ * on the device (same as initial state after attach) and
+ * leave it idle (keep MAC/BB on warm reset) */
+ ret = ath5k_hw_on_hold(sc->ah);
+
+ ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
+ "putting device to sleep\n");
}
- return NETDEV_TX_OK;
-drop_packet:
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
+ mmiowb();
+ mutex_unlock(&sc->lock);
+
+ stop_tasklets(sc);
+
+ cancel_delayed_work_sync(&sc->tx_complete_work);
+
+ ath5k_rfkill_hw_stop(sc->ah);
+
+ return ret;
}
/*
@@ -3024,6 +2594,208 @@ static void ath5k_reset_work(struct work_struct *work)
mutex_unlock(&sc->lock);
}
+static int
+ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
+{
+ struct ath5k_softc *sc = hw->priv;
+ struct ath5k_hw *ah = sc->ah;
+ struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah);
+ struct ath5k_txq *txq;
+ u8 mac[ETH_ALEN] = {};
+ int ret;
+
+ ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device);
+
+ /*
+ * Check if the MAC has multi-rate retry support.
+ * We do this by trying to setup a fake extended
+ * descriptor. MACs that don't have support will
+ * return false w/o doing anything. MACs that do
+ * support it will return true w/o doing anything.
+ */
+ ret = ath5k_hw_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
+
+ if (ret < 0)
+ goto err;
+ if (ret > 0)
+ __set_bit(ATH_STAT_MRRETRY, sc->status);
+
+ /*
+ * Collect the channel list. The 802.11 layer
+ * is resposible for filtering this list based
+ * on settings like the phy mode and regulatory
+ * domain restrictions.
+ */
+ ret = ath5k_setup_bands(hw);
+ if (ret) {
+ ATH5K_ERR(sc, "can't get channels\n");
+ goto err;
+ }
+
+ /* NB: setup here so ath5k_rate_update is happy */
+ if (test_bit(AR5K_MODE_11A, ah->ah_modes))
+ ath5k_setcurmode(sc, AR5K_MODE_11A);
+ else
+ ath5k_setcurmode(sc, AR5K_MODE_11B);
+
+ /*
+ * Allocate tx+rx descriptors and populate the lists.
+ */
+ ret = ath5k_desc_alloc(sc, pdev);
+ if (ret) {
+ ATH5K_ERR(sc, "can't allocate descriptors\n");
+ goto err;
+ }
+
+ /*
+ * Allocate hardware transmit queues: one queue for
+ * beacon frames and one data queue for each QoS
+ * priority. Note that hw functions handle resetting
+ * these queues at the needed time.
+ */
+ ret = ath5k_beaconq_setup(ah);
+ if (ret < 0) {
+ ATH5K_ERR(sc, "can't setup a beacon xmit queue\n");
+ goto err_desc;
+ }
+ sc->bhalq = ret;
+ sc->cabq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_CAB, 0);
+ if (IS_ERR(sc->cabq)) {
+ ATH5K_ERR(sc, "can't setup cab queue\n");
+ ret = PTR_ERR(sc->cabq);
+ goto err_bhal;
+ }
+
+ /* This order matches mac80211's queue priority, so we can
+ * directly use the mac80211 queue number without any mapping */
+ txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_VO);
+ if (IS_ERR(txq)) {
+ ATH5K_ERR(sc, "can't setup xmit queue\n");
+ ret = PTR_ERR(txq);
+ goto err_queues;
+ }
+ txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_VI);
+ if (IS_ERR(txq)) {
+ ATH5K_ERR(sc, "can't setup xmit queue\n");
+ ret = PTR_ERR(txq);
+ goto err_queues;
+ }
+ txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BE);
+ if (IS_ERR(txq)) {
+ ATH5K_ERR(sc, "can't setup xmit queue\n");
+ ret = PTR_ERR(txq);
+ goto err_queues;
+ }
+ txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK);
+ if (IS_ERR(txq)) {
+ ATH5K_ERR(sc, "can't setup xmit queue\n");
+ ret = PTR_ERR(txq);
+ goto err_queues;
+ }
+ hw->queues = 4;
+
+ tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
+ tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
+ tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc);
+ tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc);
+ tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc);
+
+ INIT_WORK(&sc->reset_work, ath5k_reset_work);
+ INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work);
+
+ ret = ath5k_eeprom_read_mac(ah, mac);
+ if (ret) {
+ ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
+ sc->pdev->device);
+ goto err_queues;
+ }
+
+ SET_IEEE80211_PERM_ADDR(hw, mac);
+ memcpy(&sc->lladdr, mac, ETH_ALEN);
+ /* All MAC address bits matter for ACKs */
+ ath5k_update_bssid_mask_and_opmode(sc, NULL);
+
+ regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain;
+ ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier);
+ if (ret) {
+ ATH5K_ERR(sc, "can't initialize regulatory system\n");
+ goto err_queues;
+ }
+
+ ret = ieee80211_register_hw(hw);
+ if (ret) {
+ ATH5K_ERR(sc, "can't register ieee80211 hw\n");
+ goto err_queues;
+ }
+
+ if (!ath_is_world_regd(regulatory))
+ regulatory_hint(hw->wiphy, regulatory->alpha2);
+
+ ath5k_init_leds(sc);
+
+ ath5k_sysfs_register(sc);
+
+ return 0;
+err_queues:
+ ath5k_txq_release(sc);
+err_bhal:
+ ath5k_hw_release_tx_queue(ah, sc->bhalq);
+err_desc:
+ ath5k_desc_free(sc, pdev);
+err:
+ return ret;
+}
+
+static void
+ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
+{
+ struct ath5k_softc *sc = hw->priv;
+
+ /*
+ * NB: the order of these is important:
+ * o call the 802.11 layer before detaching ath5k_hw to
+ * ensure callbacks into the driver to delete global
+ * key cache entries can be handled
+ * o reclaim the tx queue data structures after calling
+ * the 802.11 layer as we'll get called back to reclaim
+ * node state and potentially want to use them
+ * o to cleanup the tx queues the hal is called, so detach
+ * it last
+ * XXX: ??? detach ath5k_hw ???
+ * Other than that, it's straightforward...
+ */
+ ieee80211_unregister_hw(hw);
+ ath5k_desc_free(sc, pdev);
+ ath5k_txq_release(sc);
+ ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
+ ath5k_unregister_leds(sc);
+
+ ath5k_sysfs_unregister(sc);
+ /*
+ * NB: can't reclaim these until after ieee80211_ifdetach
+ * returns because we'll get called back to reclaim node
+ * state and potentially want to use them.
+ */
+}
+
+/********************\
+* Mac80211 functions *
+\********************/
+
+static int
+ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct ath5k_softc *sc = hw->priv;
+ u16 qnum = skb_get_queue_mapping(skb);
+
+ if (WARN_ON(qnum >= sc->ah->ah_capabilities.cap_queues.q_tx_num)) {
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+
+ return ath5k_tx_queue(hw, skb, &sc->txqs[qnum]);
+}
+
static int ath5k_start(struct ieee80211_hw *hw)
{
return ath5k_init(hw->priv);
@@ -3039,32 +2811,78 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
{
struct ath5k_softc *sc = hw->priv;
int ret;
+ struct ath5k_vif *avf = (void *)vif->drv_priv;
mutex_lock(&sc->lock);
- if (sc->vif) {
- ret = 0;
+
+ if ((vif->type == NL80211_IFTYPE_AP ||
+ vif->type == NL80211_IFTYPE_ADHOC)
+ && (sc->num_ap_vifs + sc->num_adhoc_vifs) >= ATH_BCBUF) {
+ ret = -ELNRNG;
goto end;
}
- sc->vif = vif;
+ /* Don't allow other interfaces if one ad-hoc is configured.
+ * TODO: Fix the problems with ad-hoc and multiple other interfaces.
+ * We would need to operate the HW in ad-hoc mode to allow TSF updates
+ * for the IBSS, but this breaks with additional AP or STA interfaces
+ * at the moment. */
+ if (sc->num_adhoc_vifs ||
+ (sc->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {
+ ATH5K_ERR(sc, "Only one single ad-hoc interface is allowed.\n");
+ ret = -ELNRNG;
+ goto end;
+ }
switch (vif->type) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
- case NL80211_IFTYPE_MONITOR:
- sc->opmode = vif->type;
+ avf->opmode = vif->type;
break;
default:
ret = -EOPNOTSUPP;
goto end;
}
- ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", sc->opmode);
+ sc->nvifs++;
+ ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode);
+
+ /* Assign the vap/adhoc to a beacon xmit slot. */
+ if ((avf->opmode == NL80211_IFTYPE_AP) ||
+ (avf->opmode == NL80211_IFTYPE_ADHOC)) {
+ int slot;
+ WARN_ON(list_empty(&sc->bcbuf));
+ avf->bbuf = list_first_entry(&sc->bcbuf, struct ath5k_buf,
+ list);
+ list_del(&avf->bbuf->list);
+
+ avf->bslot = 0;
+ for (slot = 0; slot < ATH_BCBUF; slot++) {
+ if (!sc->bslot[slot]) {
+ avf->bslot = slot;
+ break;
+ }
+ }
+ BUG_ON(sc->bslot[avf->bslot] != NULL);
+ sc->bslot[avf->bslot] = vif;
+ if (avf->opmode == NL80211_IFTYPE_AP)
+ sc->num_ap_vifs++;
+ else
+ sc->num_adhoc_vifs++;
+ }
+
+ /* Any MAC address is fine, all others are included through the
+ * filter.
+ */
+ memcpy(&sc->lladdr, vif->addr, ETH_ALEN);
ath5k_hw_set_lladdr(sc->ah, vif->addr);
- ath5k_mode_setup(sc);
+
+ memcpy(&avf->lladdr, vif->addr, ETH_ALEN);
+
+ ath5k_mode_setup(sc, vif);
ret = 0;
end:
@@ -3077,15 +2895,29 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct ath5k_softc *sc = hw->priv;
- u8 mac[ETH_ALEN] = {};
+ struct ath5k_vif *avf = (void *)vif->drv_priv;
+ unsigned int i;
mutex_lock(&sc->lock);
- if (sc->vif != vif)
- goto end;
+ sc->nvifs--;
+
+ if (avf->bbuf) {
+ ath5k_txbuf_free_skb(sc, avf->bbuf);
+ list_add_tail(&avf->bbuf->list, &sc->bcbuf);
+ for (i = 0; i < ATH_BCBUF; i++) {
+ if (sc->bslot[i] == vif) {
+ sc->bslot[i] = NULL;
+ break;
+ }
+ }
+ avf->bbuf = NULL;
+ }
+ if (avf->opmode == NL80211_IFTYPE_AP)
+ sc->num_ap_vifs--;
+ else if (avf->opmode == NL80211_IFTYPE_ADHOC)
+ sc->num_adhoc_vifs--;
- ath5k_hw_set_lladdr(sc->ah, mac);
- sc->vif = NULL;
-end:
+ ath5k_update_bssid_mask_and_opmode(sc, NULL);
mutex_unlock(&sc->lock);
}
@@ -3168,6 +3000,19 @@ static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
return ((u64)(mfilt[1]) << 32) | mfilt[0];
}
+static bool ath_any_vif_assoc(struct ath5k_softc *sc)
+{
+ struct ath_vif_iter_data iter_data;
+ iter_data.hw_macaddr = NULL;
+ iter_data.any_assoc = false;
+ iter_data.need_set_hw_addr = false;
+ iter_data.found_active = true;
+
+ ieee80211_iterate_active_interfaces_atomic(sc->hw, ath_vif_iter,
+ &iter_data);
+ return iter_data.any_assoc;
+}
+
#define SUPPORTED_FIF_FLAGS \
FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \
FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
@@ -3237,9 +3082,9 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
rfilt |= AR5K_RX_FILTER_PHYERR;
/* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
- * and probes for any BSSID, this needs testing */
- if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
- rfilt |= AR5K_RX_FILTER_BEACON | AR5K_RX_FILTER_PROBEREQ;
+ * and probes for any BSSID */
+ if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (sc->nvifs > 1))
+ rfilt |= AR5K_RX_FILTER_BEACON;
/* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
* set we should only pass on control frames for this
@@ -3255,7 +3100,6 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
switch (sc->opmode) {
case NL80211_IFTYPE_MESH_POINT:
- case NL80211_IFTYPE_MONITOR:
rfilt |= AR5K_RX_FILTER_CONTROL |
AR5K_RX_FILTER_BEACON |
AR5K_RX_FILTER_PROBEREQ |
@@ -3278,7 +3122,7 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
/* Set multicast bits */
ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
- /* Set the cached hw filter flags, this will alter actually
+ /* Set the cached hw filter flags, this will later actually
* be set in HW */
sc->filter_flags = rfilt;
@@ -3298,17 +3142,14 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (modparam_nohwcrypt)
return -EOPNOTSUPP;
- if (sc->opmode == NL80211_IFTYPE_AP)
- return -EOPNOTSUPP;
-
- switch (key->alg) {
- case ALG_WEP:
- case ALG_TKIP:
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ case WLAN_CIPHER_SUITE_TKIP:
break;
- case ALG_CCMP:
- if (sc->ah->ah_aes_support)
+ case WLAN_CIPHER_SUITE_CCMP:
+ if (common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)
break;
-
return -EOPNOTSUPP;
default:
WARN_ON(1);
@@ -3319,27 +3160,25 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
switch (cmd) {
case SET_KEY:
- ret = ath5k_hw_set_key(sc->ah, key->keyidx, key,
- sta ? sta->addr : NULL);
- if (ret) {
- ATH5K_ERR(sc, "can't set the key\n");
- goto unlock;
+ ret = ath_key_config(common, vif, sta, key);
+ if (ret >= 0) {
+ key->hw_key_idx = ret;
+ /* push IV and Michael MIC generation to stack */
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
+ key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
+ ret = 0;
}
- __set_bit(key->keyidx, common->keymap);
- key->hw_key_idx = key->keyidx;
- key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV |
- IEEE80211_KEY_FLAG_GENERATE_MMIC);
break;
case DISABLE_KEY:
- ath5k_hw_reset_key(sc->ah, key->keyidx);
- __clear_bit(key->keyidx, common->keymap);
+ ath_key_delete(common, key);
break;
default:
ret = -EINVAL;
- goto unlock;
}
-unlock:
mmiowb();
mutex_unlock(&sc->lock);
return ret;
@@ -3409,43 +3248,6 @@ ath5k_reset_tsf(struct ieee80211_hw *hw)
ath5k_hw_reset_tsf(sc->ah);
}
-/*
- * Updates the beacon that is sent by ath5k_beacon_send. For adhoc,
- * this is called only once at config_bss time, for AP we do it every
- * SWBA interrupt so that the TIM will reflect buffered frames.
- *
- * Called with the beacon lock.
- */
-static int
-ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
- int ret;
- struct ath5k_softc *sc = hw->priv;
- struct sk_buff *skb;
-
- if (WARN_ON(!vif)) {
- ret = -EINVAL;
- goto out;
- }
-
- skb = ieee80211_beacon_get(hw, vif);
-
- if (!skb) {
- ret = -ENOMEM;
- goto out;
- }
-
- ath5k_debug_dump_skb(sc, skb, "BC ", 1);
-
- ath5k_txbuf_free_skb(sc, sc->bbuf);
- sc->bbuf->skb = skb;
- ret = ath5k_beacon_setup(sc, sc->bbuf);
- if (ret)
- sc->bbuf->skb = NULL;
-out:
- return ret;
-}
-
static void
set_beacon_filter(struct ieee80211_hw *hw, bool enable)
{
@@ -3466,20 +3268,19 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *bss_conf,
u32 changes)
{
+ struct ath5k_vif *avf = (void *)vif->drv_priv;
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
struct ath_common *common = ath5k_hw_common(ah);
unsigned long flags;
mutex_lock(&sc->lock);
- if (WARN_ON(sc->vif != vif))
- goto unlock;
if (changes & BSS_CHANGED_BSSID) {
/* Cache for later use during resets */
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
common->curaid = 0;
- ath5k_hw_set_associd(ah);
+ ath5k_hw_set_bssid(ah);
mmiowb();
}
@@ -3487,7 +3288,12 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
sc->bintval = bss_conf->beacon_int;
if (changes & BSS_CHANGED_ASSOC) {
- sc->assoc = bss_conf->assoc;
+ avf->assoc = bss_conf->assoc;
+ if (bss_conf->assoc)
+ sc->assoc = bss_conf->assoc;
+ else
+ sc->assoc = ath_any_vif_assoc(sc);
+
if (sc->opmode == NL80211_IFTYPE_STATION)
set_beacon_filter(hw, sc->assoc);
ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
@@ -3497,7 +3303,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
"Bss Info ASSOC %d, bssid: %pM\n",
bss_conf->aid, common->curbssid);
common->curaid = bss_conf->aid;
- ath5k_hw_set_associd(ah);
+ ath5k_hw_set_bssid(ah);
/* Once ANI is available you would start it here */
}
}
@@ -3515,7 +3321,6 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
BSS_CHANGED_BEACON_INT))
ath5k_beacon_config(sc);
- unlock:
mutex_unlock(&sc->lock);
}
@@ -3551,3 +3356,400 @@ static void ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
ath5k_hw_set_coverage_class(sc->ah, coverage_class);
mutex_unlock(&sc->lock);
}
+
+static int ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct ath5k_softc *sc = hw->priv;
+ struct ath5k_hw *ah = sc->ah;
+ struct ath5k_txq_info qi;
+ int ret = 0;
+
+ if (queue >= ah->ah_capabilities.cap_queues.q_tx_num)
+ return 0;
+
+ mutex_lock(&sc->lock);
+
+ ath5k_hw_get_tx_queueprops(ah, queue, &qi);
+
+ qi.tqi_aifs = params->aifs;
+ qi.tqi_cw_min = params->cw_min;
+ qi.tqi_cw_max = params->cw_max;
+ qi.tqi_burst_time = params->txop;
+
+ ATH5K_DBG(sc, ATH5K_DEBUG_ANY,
+ "Configure tx [queue %d], "
+ "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
+ queue, params->aifs, params->cw_min,
+ params->cw_max, params->txop);
+
+ if (ath5k_hw_set_tx_queueprops(ah, queue, &qi)) {
+ ATH5K_ERR(sc,
+ "Unable to update hardware queue %u!\n", queue);
+ ret = -EIO;
+ } else
+ ath5k_hw_reset_tx_queue(ah, queue);
+
+ mutex_unlock(&sc->lock);
+
+ return ret;
+}
+
+static const struct ieee80211_ops ath5k_hw_ops = {
+ .tx = ath5k_tx,
+ .start = ath5k_start,
+ .stop = ath5k_stop,
+ .add_interface = ath5k_add_interface,
+ .remove_interface = ath5k_remove_interface,
+ .config = ath5k_config,
+ .prepare_multicast = ath5k_prepare_multicast,
+ .configure_filter = ath5k_configure_filter,
+ .set_key = ath5k_set_key,
+ .get_stats = ath5k_get_stats,
+ .get_survey = ath5k_get_survey,
+ .conf_tx = ath5k_conf_tx,
+ .get_tsf = ath5k_get_tsf,
+ .set_tsf = ath5k_set_tsf,
+ .reset_tsf = ath5k_reset_tsf,
+ .bss_info_changed = ath5k_bss_info_changed,
+ .sw_scan_start = ath5k_sw_scan_start,
+ .sw_scan_complete = ath5k_sw_scan_complete,
+ .set_coverage_class = ath5k_set_coverage_class,
+};
+
+/********************\
+* PCI Initialization *
+\********************/
+
+static int __devinit
+ath5k_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ void __iomem *mem;
+ struct ath5k_softc *sc;
+ struct ath_common *common;
+ struct ieee80211_hw *hw;
+ int ret;
+ u8 csz;
+
+ /*
+ * L0s needs to be disabled on all ath5k cards.
+ *
+ * For distributions shipping with CONFIG_PCIEASPM (this will be enabled
+ * by default in the future in 2.6.36) this will also mean both L1 and
+ * L0s will be disabled when a pre 1.1 PCIe device is detected. We do
+ * know L1 works correctly even for all ath5k pre 1.1 PCIe devices
+ * though but cannot currently undue the effect of a blacklist, for
+ * details you can read pcie_aspm_sanity_check() and see how it adjusts
+ * the device link capability.
+ *
+ * It may be possible in the future to implement some PCI API to allow
+ * drivers to override blacklists for pre 1.1 PCIe but for now it is
+ * best to accept that both L0s and L1 will be disabled completely for
+ * distributions shipping with CONFIG_PCIEASPM rather than having this
+ * issue present. Motivation for adding this new API will be to help
+ * with power consumption for some of these devices.
+ */
+ pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S);
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "can't enable device\n");
+ goto err;
+ }
+
+ /* XXX 32-bit addressing only */
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(&pdev->dev, "32-bit DMA not available\n");
+ goto err_dis;
+ }
+
+ /*
+ * Cache line size is used to size and align various
+ * structures used to communicate with the hardware.
+ */
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
+ if (csz == 0) {
+ /*
+ * Linux 2.4.18 (at least) writes the cache line size
+ * register as a 16-bit wide register which is wrong.
+ * We must have this setup properly for rx buffer
+ * DMA to work so force a reasonable value here if it
+ * comes up zero.
+ */
+ csz = L1_CACHE_BYTES >> 2;
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
+ }
+ /*
+ * The default setting of latency timer yields poor results,
+ * set it to the value used by other systems. It may be worth
+ * tweaking this setting more.
+ */
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
+
+ /* Enable bus mastering */
+ pci_set_master(pdev);
+
+ /*
+ * Disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state.
+ */
+ pci_write_config_byte(pdev, 0x41, 0);
+
+ ret = pci_request_region(pdev, 0, "ath5k");
+ if (ret) {
+ dev_err(&pdev->dev, "cannot reserve PCI memory region\n");
+ goto err_dis;
+ }
+
+ mem = pci_iomap(pdev, 0, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "cannot remap PCI memory region\n") ;
+ ret = -EIO;
+ goto err_reg;
+ }
+
+ /*
+ * Allocate hw (mac80211 main struct)
+ * and hw->priv (driver private data)
+ */
+ hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops);
+ if (hw == NULL) {
+ dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n");
+ ret = -ENOMEM;
+ goto err_map;
+ }
+
+ dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy));
+
+ /* Initialize driver private data */
+ SET_IEEE80211_DEV(hw, &pdev->dev);
+ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+ IEEE80211_HW_SIGNAL_DBM;
+
+ hw->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_MESH_POINT);
+
+ hw->extra_tx_headroom = 2;
+ hw->channel_change_time = 5000;
+ sc = hw->priv;
+ sc->hw = hw;
+ sc->pdev = pdev;
+
+ /*
+ * Mark the device as detached to avoid processing
+ * interrupts until setup is complete.
+ */
+ __set_bit(ATH_STAT_INVALID, sc->status);
+
+ sc->iobase = mem; /* So we can unmap it on detach */
+ sc->opmode = NL80211_IFTYPE_STATION;
+ sc->bintval = 1000;
+ mutex_init(&sc->lock);
+ spin_lock_init(&sc->rxbuflock);
+ spin_lock_init(&sc->txbuflock);
+ spin_lock_init(&sc->block);
+
+ /* Set private data */
+ pci_set_drvdata(pdev, sc);
+
+ /* Setup interrupt handler */
+ ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
+ if (ret) {
+ ATH5K_ERR(sc, "request_irq failed\n");
+ goto err_free;
+ }
+
+ /* If we passed the test, malloc an ath5k_hw struct */
+ sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
+ if (!sc->ah) {
+ ret = -ENOMEM;
+ ATH5K_ERR(sc, "out of memory\n");
+ goto err_irq;
+ }
+
+ sc->ah->ah_sc = sc;
+ sc->ah->ah_iobase = sc->iobase;
+ common = ath5k_hw_common(sc->ah);
+ common->ops = &ath5k_common_ops;
+ common->ah = sc->ah;
+ common->hw = hw;
+ common->cachelsz = csz << 2; /* convert to bytes */
+ spin_lock_init(&common->cc_lock);
+
+ /* Initialize device */
+ ret = ath5k_hw_attach(sc);
+ if (ret) {
+ goto err_free_ah;
+ }
+
+ /* set up multi-rate retry capabilities */
+ if (sc->ah->ah_version == AR5K_AR5212) {
+ hw->max_rates = 4;
+ hw->max_rate_tries = 11;
+ }
+
+ hw->vif_data_size = sizeof(struct ath5k_vif);
+
+ /* Finish private driver data initialization */
+ ret = ath5k_attach(pdev, hw);
+ if (ret)
+ goto err_ah;
+
+ ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
+ ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev),
+ sc->ah->ah_mac_srev,
+ sc->ah->ah_phy_revision);
+
+ if (!sc->ah->ah_single_chip) {
+ /* Single chip radio (!RF5111) */
+ if (sc->ah->ah_radio_5ghz_revision &&
+ !sc->ah->ah_radio_2ghz_revision) {
+ /* No 5GHz support -> report 2GHz radio */
+ if (!test_bit(AR5K_MODE_11A,
+ sc->ah->ah_capabilities.cap_mode)) {
+ ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
+ ath5k_chip_name(AR5K_VERSION_RAD,
+ sc->ah->ah_radio_5ghz_revision),
+ sc->ah->ah_radio_5ghz_revision);
+ /* No 2GHz support (5110 and some
+ * 5Ghz only cards) -> report 5Ghz radio */
+ } else if (!test_bit(AR5K_MODE_11B,
+ sc->ah->ah_capabilities.cap_mode)) {
+ ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
+ ath5k_chip_name(AR5K_VERSION_RAD,
+ sc->ah->ah_radio_5ghz_revision),
+ sc->ah->ah_radio_5ghz_revision);
+ /* Multiband radio */
+ } else {
+ ATH5K_INFO(sc, "RF%s multiband radio found"
+ " (0x%x)\n",
+ ath5k_chip_name(AR5K_VERSION_RAD,
+ sc->ah->ah_radio_5ghz_revision),
+ sc->ah->ah_radio_5ghz_revision);
+ }
+ }
+ /* Multi chip radio (RF5111 - RF2111) ->
+ * report both 2GHz/5GHz radios */
+ else if (sc->ah->ah_radio_5ghz_revision &&
+ sc->ah->ah_radio_2ghz_revision){
+ ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
+ ath5k_chip_name(AR5K_VERSION_RAD,
+ sc->ah->ah_radio_5ghz_revision),
+ sc->ah->ah_radio_5ghz_revision);
+ ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
+ ath5k_chip_name(AR5K_VERSION_RAD,
+ sc->ah->ah_radio_2ghz_revision),
+ sc->ah->ah_radio_2ghz_revision);
+ }
+ }
+
+ ath5k_debug_init_device(sc);
+
+ /* ready to process interrupts */
+ __clear_bit(ATH_STAT_INVALID, sc->status);
+
+ return 0;
+err_ah:
+ ath5k_hw_detach(sc->ah);
+err_free_ah:
+ kfree(sc->ah);
+err_irq:
+ free_irq(pdev->irq, sc);
+err_free:
+ ieee80211_free_hw(hw);
+err_map:
+ pci_iounmap(pdev, mem);
+err_reg:
+ pci_release_region(pdev, 0);
+err_dis:
+ pci_disable_device(pdev);
+err:
+ return ret;
+}
+
+static void __devexit
+ath5k_pci_remove(struct pci_dev *pdev)
+{
+ struct ath5k_softc *sc = pci_get_drvdata(pdev);
+
+ ath5k_debug_finish_device(sc);
+ ath5k_detach(pdev, sc->hw);
+ ath5k_hw_detach(sc->ah);
+ kfree(sc->ah);
+ free_irq(pdev->irq, sc);
+ pci_iounmap(pdev, sc->iobase);
+ pci_release_region(pdev, 0);
+ pci_disable_device(pdev);
+ ieee80211_free_hw(sc->hw);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ath5k_pci_suspend(struct device *dev)
+{
+ struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev));
+
+ ath5k_led_off(sc);
+ return 0;
+}
+
+static int ath5k_pci_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct ath5k_softc *sc = pci_get_drvdata(pdev);
+
+ /*
+ * Suspend/Resume resets the PCI configuration space, so we have to
+ * re-disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state
+ */
+ pci_write_config_byte(pdev, 0x41, 0);
+
+ ath5k_led_enable(sc);
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume);
+#define ATH5K_PM_OPS (&ath5k_pm_ops)
+#else
+#define ATH5K_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static struct pci_driver ath5k_pci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ath5k_pci_id_table,
+ .probe = ath5k_pci_probe,
+ .remove = __devexit_p(ath5k_pci_remove),
+ .driver.pm = ATH5K_PM_OPS,
+};
+
+/*
+ * Module init/exit functions
+ */
+static int __init
+init_ath5k_pci(void)
+{
+ int ret;
+
+ ret = pci_register_driver(&ath5k_pci_driver);
+ if (ret) {
+ printk(KERN_ERR "ath5k_pci: can't register pci driver\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit
+exit_ath5k_pci(void)
+{
+ pci_unregister_driver(&ath5k_pci_driver);
+}
+
+module_init(init_ath5k_pci);
+module_exit(exit_ath5k_pci);
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index dc1241f9c4e8..9a79773cdc2a 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -58,7 +58,9 @@
#define ATH_RXBUF 40 /* number of RX buffers */
#define ATH_TXBUF 200 /* number of TX buffers */
-#define ATH_BCBUF 1 /* number of beacon buffers */
+#define ATH_BCBUF 4 /* number of beacon buffers */
+#define ATH5K_TXQ_LEN_MAX (ATH_TXBUF / 4) /* bufs per queue */
+#define ATH5K_TXQ_LEN_LOW (ATH5K_TXQ_LEN_MAX / 2) /* low mark */
struct ath5k_buf {
struct list_head list;
@@ -83,6 +85,9 @@ struct ath5k_txq {
struct list_head q; /* transmit queue */
spinlock_t lock; /* lock on q and link */
bool setup;
+ int txq_len; /* number of queued buffers */
+ bool txq_poll_mark;
+ unsigned int txq_stuck; /* informational counter */
};
#define ATH5K_LED_MAX_NAME_LEN 31
@@ -116,6 +121,13 @@ struct ath5k_statistics {
/* frame errors */
unsigned int rx_all_count; /* all RX frames, including errors */
unsigned int tx_all_count; /* all TX frames, including errors */
+ unsigned int rx_bytes_count; /* all RX bytes, including errored pks
+ * and the MAC headers for each packet
+ */
+ unsigned int tx_bytes_count; /* all TX bytes, including errored pkts
+ * and the MAC headers and padding for
+ * each packet.
+ */
unsigned int rxerr_crc;
unsigned int rxerr_phy;
unsigned int rxerr_phy_code[32];
@@ -146,6 +158,14 @@ struct ath5k_statistics {
#define ATH_CHAN_MAX (14+14+14+252+20)
#endif
+struct ath5k_vif {
+ bool assoc; /* are we associated or not */
+ enum nl80211_iftype opmode;
+ int bslot;
+ struct ath5k_buf *bbuf; /* beacon buffer */
+ u8 lladdr[ETH_ALEN];
+};
+
/* Software Carrier, keeps track of the driver state
* associated with an instance of a device */
struct ath5k_softc {
@@ -182,10 +202,11 @@ struct ath5k_softc {
unsigned int curmode; /* current phy mode */
struct ieee80211_channel *curchan; /* current h/w channel */
- struct ieee80211_vif *vif;
+ u16 nvifs;
enum ath5k_int imask; /* interrupt mask copy */
+ u8 lladdr[ETH_ALEN];
u8 bssidmask[ETH_ALEN];
unsigned int led_pin, /* GPIO pin for driving LED */
@@ -204,7 +225,6 @@ struct ath5k_softc {
spinlock_t txbuflock;
unsigned int txbuf_len; /* buf count in txbuf list */
struct ath5k_txq txqs[AR5K_NUM_TX_QUEUES]; /* tx queues */
- struct ath5k_txq *txq; /* main tx queue */
struct tasklet_struct txtq; /* tx intr tasklet */
struct ath5k_led tx_led; /* tx led */
@@ -214,7 +234,10 @@ struct ath5k_softc {
spinlock_t block; /* protects beacon */
struct tasklet_struct beacontq; /* beacon intr tasklet */
- struct ath5k_buf *bbuf; /* beacon buffer */
+ struct list_head bcbuf; /* beacon buffer */
+ struct ieee80211_vif *bslot[ATH_BCBUF];
+ u16 num_ap_vifs;
+ u16 num_adhoc_vifs;
unsigned int bhalq, /* SW q for outgoing beacons */
bmisscount, /* missed beacon transmits */
bintval, /* beacon interval in TU */
@@ -230,6 +253,8 @@ struct ath5k_softc {
struct ath5k_ani_state ani_state;
struct tasklet_struct ani_tasklet; /* ANI calibration */
+
+ struct delayed_work tx_complete_work;
};
#define ath5k_hw_hasbssidmask(_ah) \
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index fb339c3852ee..acda56ee521b 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -60,6 +60,7 @@
#include "base.h"
#include "debug.h"
+#include "../debug.h"
static unsigned int ath5k_debug;
module_param_named(debug, ath5k_debug, uint, 0);
@@ -71,8 +72,6 @@ module_param_named(debug, ath5k_debug, uint, 0);
#include "reg.h"
#include "ani.h"
-static struct dentry *ath5k_global_debugfs;
-
static int ath5k_debugfs_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
@@ -314,6 +313,7 @@ static const struct {
{ ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" },
{ ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" },
{ ATH5K_DEBUG_ANI, "ani", "adaptive noise immunity" },
+ { ATH5K_DEBUG_DESC, "desc", "descriptor chains" },
{ ATH5K_DEBUG_ANY, "all", "show all debug levels" },
};
@@ -486,6 +486,60 @@ static const struct file_operations fops_antenna = {
.llseek = default_llseek,
};
+/* debugfs: misc */
+
+static ssize_t read_file_misc(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath5k_softc *sc = file->private_data;
+ char buf[700];
+ unsigned int len = 0;
+ u32 filt = ath5k_hw_get_rx_filter(sc->ah);
+
+ len += snprintf(buf+len, sizeof(buf)-len, "bssid-mask: %pM\n",
+ sc->bssidmask);
+ len += snprintf(buf+len, sizeof(buf)-len, "filter-flags: 0x%x ",
+ filt);
+ if (filt & AR5K_RX_FILTER_UCAST)
+ len += snprintf(buf+len, sizeof(buf)-len, " UCAST");
+ if (filt & AR5K_RX_FILTER_MCAST)
+ len += snprintf(buf+len, sizeof(buf)-len, " MCAST");
+ if (filt & AR5K_RX_FILTER_BCAST)
+ len += snprintf(buf+len, sizeof(buf)-len, " BCAST");
+ if (filt & AR5K_RX_FILTER_CONTROL)
+ len += snprintf(buf+len, sizeof(buf)-len, " CONTROL");
+ if (filt & AR5K_RX_FILTER_BEACON)
+ len += snprintf(buf+len, sizeof(buf)-len, " BEACON");
+ if (filt & AR5K_RX_FILTER_PROM)
+ len += snprintf(buf+len, sizeof(buf)-len, " PROM");
+ if (filt & AR5K_RX_FILTER_XRPOLL)
+ len += snprintf(buf+len, sizeof(buf)-len, " XRPOLL");
+ if (filt & AR5K_RX_FILTER_PROBEREQ)
+ len += snprintf(buf+len, sizeof(buf)-len, " PROBEREQ");
+ if (filt & AR5K_RX_FILTER_PHYERR_5212)
+ len += snprintf(buf+len, sizeof(buf)-len, " PHYERR-5212");
+ if (filt & AR5K_RX_FILTER_RADARERR_5212)
+ len += snprintf(buf+len, sizeof(buf)-len, " RADARERR-5212");
+ if (filt & AR5K_RX_FILTER_PHYERR_5211)
+ snprintf(buf+len, sizeof(buf)-len, " PHYERR-5211");
+ if (filt & AR5K_RX_FILTER_RADARERR_5211)
+ len += snprintf(buf+len, sizeof(buf)-len, " RADARERR-5211");
+
+ len += snprintf(buf+len, sizeof(buf)-len, "\nopmode: %s (%d)\n",
+ ath_opmode_to_string(sc->opmode), sc->opmode);
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_misc = {
+ .read = read_file_misc,
+ .open = ath5k_debugfs_open,
+ .owner = THIS_MODULE,
+};
+
/* debugfs: frameerrors */
@@ -537,6 +591,8 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
st->rxerr_jumbo*100/st->rx_all_count : 0);
len += snprintf(buf+len, sizeof(buf)-len, "[RX all\t%d]\n",
st->rx_all_count);
+ len += snprintf(buf+len, sizeof(buf)-len, "RX-all-bytes\t%d\n",
+ st->rx_bytes_count);
len += snprintf(buf+len, sizeof(buf)-len,
"\nTX\n---------------------\n");
@@ -554,6 +610,8 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
st->txerr_filt*100/st->tx_all_count : 0);
len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%d]\n",
st->tx_all_count);
+ len += snprintf(buf+len, sizeof(buf)-len, "TX-all-bytes\t%d\n",
+ st->tx_bytes_count);
if (len > sizeof(buf))
len = sizeof(buf);
@@ -662,20 +720,21 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf,
len += snprintf(buf+len, sizeof(buf)-len,
"beacon RSSI average:\t%d\n",
sc->ah->ah_beacon_rssi_avg.avg);
+
+#define CC_PRINT(_struct, _field) \
+ _struct._field, \
+ _struct.cycles > 0 ? \
+ _struct._field*100/_struct.cycles : 0
+
len += snprintf(buf+len, sizeof(buf)-len, "profcnt tx\t\t%u\t(%d%%)\n",
- as->pfc_tx,
- as->pfc_cycles > 0 ?
- as->pfc_tx*100/as->pfc_cycles : 0);
+ CC_PRINT(as->last_cc, tx_frame));
len += snprintf(buf+len, sizeof(buf)-len, "profcnt rx\t\t%u\t(%d%%)\n",
- as->pfc_rx,
- as->pfc_cycles > 0 ?
- as->pfc_rx*100/as->pfc_cycles : 0);
+ CC_PRINT(as->last_cc, rx_frame));
len += snprintf(buf+len, sizeof(buf)-len, "profcnt busy\t\t%u\t(%d%%)\n",
- as->pfc_busy,
- as->pfc_cycles > 0 ?
- as->pfc_busy*100/as->pfc_cycles : 0);
+ CC_PRINT(as->last_cc, rx_busy));
+#undef CC_PRINT
len += snprintf(buf+len, sizeof(buf)-len, "profcnt cycles\t\t%u\n",
- as->pfc_cycles);
+ as->last_cc.cycles);
len += snprintf(buf+len, sizeof(buf)-len,
"listen time\t\t%d\tlast: %d\n",
as->listen_time, as->last_listen);
@@ -768,7 +827,7 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf,
struct ath5k_txq *txq;
struct ath5k_buf *bf, *bf0;
- int i, n = 0;
+ int i, n;
len += snprintf(buf+len, sizeof(buf)-len,
"available txbuffers: %d\n", sc->txbuf_len);
@@ -782,9 +841,16 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf,
if (!txq->setup)
continue;
+ n = 0;
+ spin_lock_bh(&txq->lock);
list_for_each_entry_safe(bf, bf0, &txq->q, list)
n++;
- len += snprintf(buf+len, sizeof(buf)-len, " len: %d\n", n);
+ spin_unlock_bh(&txq->lock);
+
+ len += snprintf(buf+len, sizeof(buf)-len,
+ " len: %d bufs: %d\n", txq->txq_len, n);
+ len += snprintf(buf+len, sizeof(buf)-len,
+ " stuck: %d\n", txq->txq_stuck);
}
if (len > sizeof(buf))
@@ -821,21 +887,13 @@ static const struct file_operations fops_queue = {
};
-/* init */
-
-void
-ath5k_debug_init(void)
-{
- ath5k_global_debugfs = debugfs_create_dir("ath5k", NULL);
-}
-
void
ath5k_debug_init_device(struct ath5k_softc *sc)
{
sc->debug.level = ath5k_debug;
- sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
- ath5k_global_debugfs);
+ sc->debug.debugfs_phydir = debugfs_create_dir("ath5k",
+ sc->hw->wiphy->debugfsdir);
sc->debug.debugfs_debug = debugfs_create_file("debug",
S_IWUSR | S_IRUSR,
@@ -855,6 +913,10 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
S_IWUSR | S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_antenna);
+ sc->debug.debugfs_misc = debugfs_create_file("misc",
+ S_IRUSR,
+ sc->debug.debugfs_phydir, sc, &fops_misc);
+
sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors",
S_IWUSR | S_IRUSR,
sc->debug.debugfs_phydir, sc,
@@ -872,12 +934,6 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
}
void
-ath5k_debug_finish(void)
-{
- debugfs_remove(ath5k_global_debugfs);
-}
-
-void
ath5k_debug_finish_device(struct ath5k_softc *sc)
{
debugfs_remove(sc->debug.debugfs_debug);
@@ -885,6 +941,7 @@ ath5k_debug_finish_device(struct ath5k_softc *sc)
debugfs_remove(sc->debug.debugfs_beacon);
debugfs_remove(sc->debug.debugfs_reset);
debugfs_remove(sc->debug.debugfs_antenna);
+ debugfs_remove(sc->debug.debugfs_misc);
debugfs_remove(sc->debug.debugfs_frameerrors);
debugfs_remove(sc->debug.debugfs_ani);
debugfs_remove(sc->debug.debugfs_queue);
@@ -962,7 +1019,7 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah)
struct ath5k_rx_status rs = {};
int status;
- if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
+ if (likely(!(sc->debug.level & ATH5K_DEBUG_DESC)))
return;
printk(KERN_DEBUG "rxdp %x, rxlink %p\n",
@@ -1004,7 +1061,7 @@ ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf)
struct ath5k_tx_status ts = {};
int done;
- if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
+ if (likely(!(sc->debug.level & ATH5K_DEBUG_DESC)))
return;
done = sc->ah->ah_proc_tx_desc(sc->ah, bf->desc, &ts);
diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h
index 606ae94a9157..236edbd2507d 100644
--- a/drivers/net/wireless/ath/ath5k/debug.h
+++ b/drivers/net/wireless/ath/ath5k/debug.h
@@ -75,6 +75,7 @@ struct ath5k_dbg_info {
struct dentry *debugfs_beacon;
struct dentry *debugfs_reset;
struct dentry *debugfs_antenna;
+ struct dentry *debugfs_misc;
struct dentry *debugfs_frameerrors;
struct dentry *debugfs_ani;
struct dentry *debugfs_queue;
@@ -95,6 +96,7 @@ struct ath5k_dbg_info {
* @ATH5K_DEBUG_DUMP_TX: print transmit skb content
* @ATH5K_DEBUG_DUMPBANDS: dump bands
* @ATH5K_DEBUG_TRACE: trace function calls
+ * @ATH5K_DEBUG_DESC: descriptor setup
* @ATH5K_DEBUG_ANY: show at any debug level
*
* The debug level is used to control the amount and type of debugging output
@@ -117,6 +119,7 @@ enum ath5k_debug_level {
ATH5K_DEBUG_DUMP_TX = 0x00000200,
ATH5K_DEBUG_DUMPBANDS = 0x00000400,
ATH5K_DEBUG_ANI = 0x00002000,
+ ATH5K_DEBUG_DESC = 0x00004000,
ATH5K_DEBUG_ANY = 0xffffffff
};
@@ -135,15 +138,9 @@ enum ath5k_debug_level {
} while (0)
void
-ath5k_debug_init(void);
-
-void
ath5k_debug_init_device(struct ath5k_softc *sc);
void
-ath5k_debug_finish(void);
-
-void
ath5k_debug_finish_device(struct ath5k_softc *sc);
void
@@ -171,15 +168,9 @@ ATH5K_DBG_UNLIMIT(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...)
{}
static inline void
-ath5k_debug_init(void) {}
-
-static inline void
ath5k_debug_init_device(struct ath5k_softc *sc) {}
static inline void
-ath5k_debug_finish(void) {}
-
-static inline void
ath5k_debug_finish_device(struct ath5k_softc *sc) {}
static inline void
diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c
index 484f31870ba8..923c9ca5c4f0 100644
--- a/drivers/net/wireless/ath/ath5k/dma.c
+++ b/drivers/net/wireless/ath/ath5k/dma.c
@@ -244,7 +244,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
/* Force channel idle high */
AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
- AR5K_DIAG_SW_CHANEL_IDLE_HIGH);
+ AR5K_DIAG_SW_CHANNEL_IDLE_HIGH);
/* Wait a while and disable mechanism */
udelay(200);
@@ -261,7 +261,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
} while (--i && pending);
AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211,
- AR5K_DIAG_SW_CHANEL_IDLE_HIGH);
+ AR5K_DIAG_SW_CHANNEL_IDLE_HIGH);
}
/* Clear register */
@@ -377,11 +377,11 @@ int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
*
* This function increases/decreases the tx trigger level for the tx fifo
* buffer (aka FIFO threshold) that is used to indicate when PCU flushes
- * the buffer and transmits it's data. Lowering this results sending small
+ * the buffer and transmits its data. Lowering this results sending small
* frames more quickly but can lead to tx underruns, raising it a lot can
* result other problems (i think bmiss is related). Right now we start with
* the lowest possible (64Bytes) and if we get tx underrun we increase it using
- * the increase flag. Returns -EIO if we have have reached maximum/minimum.
+ * the increase flag. Returns -EIO if we have reached maximum/minimum.
*
* XXX: Link this with tx DMA size ?
* XXX: Use it to save interrupts ?
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index ae316fec4a6a..39722dd73e43 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -661,7 +661,7 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
* (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC
* steps that match with the power values we read from eeprom. On
* older eeprom versions (< 3.2) these steps are equaly spaced at
- * 10% of the pcdac curve -until the curve reaches it's maximum-
+ * 10% of the pcdac curve -until the curve reaches its maximum-
* (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2)
* these 11 steps are spaced in a different way. This function returns
* the pcdac steps based on eeprom version and curve min/max so that we
@@ -1113,7 +1113,7 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
*/
/* For RF2413 power calibration data doesn't start on a fixed location and
- * if a mode is not supported, it's section is missing -not zeroed-.
+ * if a mode is not supported, its section is missing -not zeroed-.
* So we need to calculate the starting offset for each section by using
* these two functions */
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index 86fdb6ddfaaa..074b4c644399 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -137,11 +137,11 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
* ath5k_hw_set_ack_bitrate - set bitrate for ACKs
*
* @ah: The &struct ath5k_hw
- * @high: Flag to determine if we want to use high transmition rate
+ * @high: Flag to determine if we want to use high transmission rate
* for ACKs or not
*
* If high flag is set, we tell hw to use a set of control rates based on
- * the current transmition rate (check out control_rates array inside reset.c).
+ * the current transmission rate (check out control_rates array inside reset.c).
* If not hw just uses the lowest rate available for the current modulation
* scheme being used (1Mbit for CCK and 6Mbits for OFDM).
*/
@@ -207,7 +207,8 @@ static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
*/
unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
{
- return usec * ath5k_hw_get_clockrate(ah);
+ struct ath_common *common = ath5k_hw_common(ah);
+ return usec * common->clockrate;
}
/**
@@ -216,17 +217,19 @@ unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
*/
unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock)
{
- return clock / ath5k_hw_get_clockrate(ah);
+ struct ath_common *common = ath5k_hw_common(ah);
+ return clock / common->clockrate;
}
/**
- * ath5k_hw_get_clockrate - Get the clock rate for current mode
+ * ath5k_hw_set_clockrate - Set common->clockrate for the current channel
*
* @ah: The &struct ath5k_hw
*/
-unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah)
+void ath5k_hw_set_clockrate(struct ath5k_hw *ah)
{
struct ieee80211_channel *channel = ah->ah_current_channel;
+ struct ath_common *common = ath5k_hw_common(ah);
int clock;
if (channel->hw_value & CHANNEL_5GHZ)
@@ -240,7 +243,7 @@ unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah)
if (channel->hw_value & CHANNEL_TURBO)
clock *= 2;
- return clock;
+ common->clockrate = clock;
}
/**
@@ -308,27 +311,26 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
}
/**
- * ath5k_hw_set_associd - Set BSSID for association
+ * ath5k_hw_set_bssid - Set current BSSID on hw
*
* @ah: The &struct ath5k_hw
- * @bssid: BSSID
- * @assoc_id: Assoc id
*
- * Sets the BSSID which trigers the "SME Join" operation
+ * Sets the current BSSID and BSSID mask we have from the
+ * common struct into the hardware
*/
-void ath5k_hw_set_associd(struct ath5k_hw *ah)
+void ath5k_hw_set_bssid(struct ath5k_hw *ah)
{
struct ath_common *common = ath5k_hw_common(ah);
u16 tim_offset = 0;
/*
- * Set simple BSSID mask on 5212
+ * Set BSSID mask on 5212
*/
if (ah->ah_version == AR5K_AR5212)
ath_hw_setbssidmask(common);
/*
- * Set BSSID which triggers the "SME Join" operation
+ * Set BSSID
*/
ath5k_hw_reg_write(ah,
get_unaligned_le32(common->curbssid),
@@ -496,6 +498,10 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
{
u32 tsf_lower, tsf_upper1, tsf_upper2;
int i;
+ unsigned long flags;
+
+ /* This code is time critical - we don't want to be interrupted here */
+ local_irq_save(flags);
/*
* While reading TSF upper and then lower part, the clock is still
@@ -518,6 +524,8 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
tsf_upper1 = tsf_upper2;
}
+ local_irq_restore(flags);
+
WARN_ON( i == ATH5K_MAX_TSF_READ );
return (((u64)tsf_upper1 << 32) | tsf_lower);
@@ -601,7 +609,7 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
/* Timer3 marks the end of our ATIM window
* a zero length window is not allowed because
* we 'll get no beacons */
- timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1);
+ timer3 = next_beacon + 1;
/*
* Set the beacon register and enable all timers.
@@ -641,198 +649,95 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
}
-
-/*********************\
-* Key table functions *
-\*********************/
-
-/*
- * Reset a key entry on the table
+/**
+ * ath5k_check_timer_win - Check if timer B is timer A + window
+ *
+ * @a: timer a (before b)
+ * @b: timer b (after a)
+ * @window: difference between a and b
+ * @intval: timers are increased by this interval
+ *
+ * This helper function checks if timer B is timer A + window and covers
+ * cases where timer A or B might have already been updated or wrapped
+ * around (Timers are 16 bit).
+ *
+ * Returns true if O.K.
*/
-int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
+static inline bool
+ath5k_check_timer_win(int a, int b, int window, int intval)
{
- unsigned int i, type;
- u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
-
- AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
-
- type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
-
- for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
- ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
-
- /* Reset associated MIC entry if TKIP
- * is enabled located at offset (entry + 64) */
- if (type == AR5K_KEYTABLE_TYPE_TKIP) {
- AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE);
- for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++)
- ath5k_hw_reg_write(ah, 0,
- AR5K_KEYTABLE_OFF(micentry, i));
- }
-
/*
- * Set NULL encryption on AR5212+
- *
- * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5)
- * AR5K_KEYTABLE_TYPE_NULL -> 0x00000007
- *
- * Note2: Windows driver (ndiswrapper) sets this to
- * 0x00000714 instead of 0x00000007
+ * 1.) usually B should be A + window
+ * 2.) A already updated, B not updated yet
+ * 3.) A already updated and has wrapped around
+ * 4.) B has wrapped around
*/
- if (ah->ah_version >= AR5K_AR5211) {
- ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
- AR5K_KEYTABLE_TYPE(entry));
-
- if (type == AR5K_KEYTABLE_TYPE_TKIP) {
- ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
- AR5K_KEYTABLE_TYPE(micentry));
- }
- }
-
- return 0;
+ if ((b - a == window) || /* 1.) */
+ (a - b == intval - window) || /* 2.) */
+ ((a | 0x10000) - b == intval - window) || /* 3.) */
+ ((b | 0x10000) - a == window)) /* 4.) */
+ return true; /* O.K. */
+ return false;
}
-static
-int ath5k_keycache_type(const struct ieee80211_key_conf *key)
-{
- switch (key->alg) {
- case ALG_TKIP:
- return AR5K_KEYTABLE_TYPE_TKIP;
- case ALG_CCMP:
- return AR5K_KEYTABLE_TYPE_CCM;
- case ALG_WEP:
- if (key->keylen == WLAN_KEY_LEN_WEP40)
- return AR5K_KEYTABLE_TYPE_40;
- else if (key->keylen == WLAN_KEY_LEN_WEP104)
- return AR5K_KEYTABLE_TYPE_104;
- return -EINVAL;
- default:
- return -EINVAL;
- }
- return -EINVAL;
-}
-
-/*
- * Set a key entry on the table
+/**
+ * ath5k_hw_check_beacon_timers - Check if the beacon timers are correct
+ *
+ * @ah: The &struct ath5k_hw
+ * @intval: beacon interval
+ *
+ * This is a workaround for IBSS mode:
+ *
+ * The need for this function arises from the fact that we have 4 separate
+ * HW timer registers (TIMER0 - TIMER3), which are closely related to the
+ * next beacon target time (NBTT), and that the HW updates these timers
+ * seperately based on the current TSF value. The hardware increments each
+ * timer by the beacon interval, when the local TSF coverted to TU is equal
+ * to the value stored in the timer.
+ *
+ * The reception of a beacon with the same BSSID can update the local HW TSF
+ * at any time - this is something we can't avoid. If the TSF jumps to a
+ * time which is later than the time stored in a timer, this timer will not
+ * be updated until the TSF in TU wraps around at 16 bit (the size of the
+ * timers) and reaches the time which is stored in the timer.
+ *
+ * The problem is that these timers are closely related to TIMER0 (NBTT) and
+ * that they define a time "window". When the TSF jumps between two timers
+ * (e.g. ATIM and NBTT), the one in the past will be left behind (not
+ * updated), while the one in the future will be updated every beacon
+ * interval. This causes the window to get larger, until the TSF wraps
+ * around as described above and the timer which was left behind gets
+ * updated again. But - because the beacon interval is usually not an exact
+ * divisor of the size of the timers (16 bit), an unwanted "window" between
+ * these timers has developed!
+ *
+ * This is especially important with the ATIM window, because during
+ * the ATIM window only ATIM frames and no data frames are allowed to be
+ * sent, which creates transmission pauses after each beacon. This symptom
+ * has been described as "ramping ping" because ping times increase linearly
+ * for some time and then drop down again. A wrong window on the DMA beacon
+ * timer has the same effect, so we check for these two conditions.
+ *
+ * Returns true if O.K.
*/
-int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
- const struct ieee80211_key_conf *key, const u8 *mac)
-{
- unsigned int i;
- int keylen;
- __le32 key_v[5] = {};
- __le32 key0 = 0, key1 = 0;
- __le32 *rxmic, *txmic;
- int keytype;
- u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
- bool is_tkip;
- const u8 *key_ptr;
-
- is_tkip = (key->alg == ALG_TKIP);
-
- /*
- * key->keylen comes in from mac80211 in bytes.
- * TKIP is 128 bit + 128 bit mic
- */
- keylen = (is_tkip) ? (128 / 8) : key->keylen;
-
- if (entry > AR5K_KEYTABLE_SIZE ||
- (is_tkip && micentry > AR5K_KEYTABLE_SIZE))
- return -EOPNOTSUPP;
-
- if (unlikely(keylen > 16))
- return -EOPNOTSUPP;
-
- keytype = ath5k_keycache_type(key);
- if (keytype < 0)
- return keytype;
-
- /*
- * each key block is 6 bytes wide, written as pairs of
- * alternating 32 and 16 bit le values.
- */
- key_ptr = key->key;
- for (i = 0; keylen >= 6; keylen -= 6) {
- memcpy(&key_v[i], key_ptr, 6);
- i += 2;
- key_ptr += 6;
- }
- if (keylen)
- memcpy(&key_v[i], key_ptr, keylen);
-
- /* intentionally corrupt key until mic is installed */
- if (is_tkip) {
- key0 = key_v[0] = ~key_v[0];
- key1 = key_v[1] = ~key_v[1];
- }
-
- for (i = 0; i < ARRAY_SIZE(key_v); i++)
- ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
- AR5K_KEYTABLE_OFF(entry, i));
-
- ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
-
- if (is_tkip) {
- /* Install rx/tx MIC */
- rxmic = (__le32 *) &key->key[16];
- txmic = (__le32 *) &key->key[24];
-
- if (ah->ah_combined_mic) {
- key_v[0] = rxmic[0];
- key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16);
- key_v[2] = rxmic[1];
- key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff);
- key_v[4] = txmic[1];
- } else {
- key_v[0] = rxmic[0];
- key_v[1] = 0;
- key_v[2] = rxmic[1];
- key_v[3] = 0;
- key_v[4] = 0;
- }
- for (i = 0; i < ARRAY_SIZE(key_v); i++)
- ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
- AR5K_KEYTABLE_OFF(micentry, i));
-
- ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
- AR5K_KEYTABLE_TYPE(micentry));
- ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry));
- ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry));
-
- /* restore first 2 words of key */
- ath5k_hw_reg_write(ah, le32_to_cpu(~key0),
- AR5K_KEYTABLE_OFF(entry, 0));
- ath5k_hw_reg_write(ah, le32_to_cpu(~key1),
- AR5K_KEYTABLE_OFF(entry, 1));
- }
-
- return ath5k_hw_set_key_lladdr(ah, entry, mac);
-}
-
-int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
+bool
+ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval)
{
- u32 low_id, high_id;
-
- /* Invalid entry (key table overflow) */
- AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
+ unsigned int nbtt, atim, dma;
- /*
- * MAC may be NULL if it's a broadcast key. In this case no need to
- * to compute get_unaligned_le32 and get_unaligned_le16 as we
- * already know it.
- */
- if (!mac) {
- low_id = 0xffffffff;
- high_id = 0xffff | AR5K_KEYTABLE_VALID;
- } else {
- low_id = get_unaligned_le32(mac);
- high_id = get_unaligned_le16(mac + 4) | AR5K_KEYTABLE_VALID;
- }
+ nbtt = ath5k_hw_reg_read(ah, AR5K_TIMER0);
+ atim = ath5k_hw_reg_read(ah, AR5K_TIMER3);
+ dma = ath5k_hw_reg_read(ah, AR5K_TIMER1) >> 3;
- ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry));
- ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry));
+ /* NOTE: SWBA is different. Having a wrong window there does not
+ * stop us from sending data and this condition is catched thru
+ * other means (SWBA interrupt) */
- return 0;
+ if (ath5k_check_timer_win(nbtt, atim, 1, intval) &&
+ ath5k_check_timer_win(dma, nbtt, AR5K_TUNE_DMA_BEACON_RESP,
+ intval))
+ return true; /* O.K. */
+ return false;
}
/**
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 6284c389ba18..219367884e64 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -115,7 +115,7 @@ static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
\**********************/
/*
- * This code is used to optimize rf gain on different environments
+ * This code is used to optimize RF gain on different environments
* (temperature mostly) based on feedback from a power detector.
*
* It's only used on RF5111 and RF5112, later RF chips seem to have
@@ -302,7 +302,7 @@ static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
}
/* Perform gain_F adjustment by choosing the right set
- * of parameters from rf gain optimization ladder */
+ * of parameters from RF gain optimization ladder */
static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah)
{
const struct ath5k_gain_opt *go;
@@ -367,7 +367,7 @@ done:
return ret;
}
-/* Main callback for thermal rf gain calibration engine
+/* Main callback for thermal RF gain calibration engine
* Check for a new gain reading and schedule an adjustment
* if needed.
*
@@ -433,7 +433,7 @@ done:
return ah->ah_gain.g_state;
}
-/* Write initial rf gain table to set the RF sensitivity
+/* Write initial RF gain table to set the RF sensitivity
* this one works on all RF chips and has nothing to do
* with gain_F calibration */
int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
@@ -496,7 +496,7 @@ int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
/*
- * Setup RF registers by writing rf buffer on hw
+ * Setup RF registers by writing RF buffer on hw
*/
int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
unsigned int mode)
@@ -571,7 +571,7 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
return -EINVAL;
}
- /* If it's the first time we set rf buffer, allocate
+ /* If it's the first time we set RF buffer, allocate
* ah->ah_rf_banks based on ah->ah_rf_banks_size
* we set above */
if (ah->ah_rf_banks == NULL) {
@@ -1093,6 +1093,7 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
ah->ah_current_channel = channel;
ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false;
+ ath5k_hw_set_clockrate(ah);
return 0;
}
@@ -1257,7 +1258,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
* Disable beacons and RX/TX queues, wait
*/
AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210,
- AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
+ AR5K_DIAG_SW_DIS_TX_5210 | AR5K_DIAG_SW_DIS_RX_5210);
beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210);
ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210);
@@ -1336,7 +1337,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
* Re-enable RX/TX and beacons
*/
AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210,
- AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
+ AR5K_DIAG_SW_DIS_TX_5210 | AR5K_DIAG_SW_DIS_RX_5210);
ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210);
return 0;
@@ -1377,7 +1378,7 @@ ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah)
/* protect against divide by 0 and loss of sign bits */
if (i_coffd == 0 || q_coffd < 2)
- return -1;
+ return 0;
i_coff = (-iq_corr) / i_coffd;
i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */
@@ -1582,7 +1583,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
else if (curr_sym_off >= 31 && curr_sym_off <= 46)
mag_mask[2] |=
plt_mag_map << (curr_sym_off - 31) * 2;
- else if (curr_sym_off >= 46 && curr_sym_off <= 53)
+ else if (curr_sym_off >= 47 && curr_sym_off <= 53)
mag_mask[3] |=
plt_mag_map << (curr_sym_off - 47) * 2;
@@ -2987,7 +2988,7 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
/*
- * Set transmition power
+ * Set transmission power
*/
int
ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
@@ -3035,9 +3036,6 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
/* Limit max power if we have a CTL available */
ath5k_get_max_ctl_power(ah, channel);
- /* FIXME: Tx power limit for this regdomain
- * XXX: Mac80211/CRDA will do that anyway ? */
-
/* FIXME: Antenna reduction stuff */
/* FIXME: Limit power on turbo modes */
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index 4186ff4c6e9c..84c717ded1c5 100644
--- a/drivers/net/wireless/ath/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
@@ -36,24 +36,58 @@ int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
}
/*
+ * Make sure cw is a power of 2 minus 1 and smaller than 1024
+ */
+static u16 ath5k_cw_validate(u16 cw_req)
+{
+ u32 cw = 1;
+ cw_req = min(cw_req, (u16)1023);
+
+ while (cw < cw_req)
+ cw = (cw << 1) | 1;
+
+ return cw;
+}
+
+/*
* Set properties for a transmit queue
*/
int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
- const struct ath5k_txq_info *queue_info)
+ const struct ath5k_txq_info *qinfo)
{
+ struct ath5k_txq_info *qi;
+
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
- if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
+ qi = &ah->ah_txq[queue];
+
+ if (qi->tqi_type == AR5K_TX_QUEUE_INACTIVE)
return -EIO;
- memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info));
+ /* copy and validate values */
+ qi->tqi_type = qinfo->tqi_type;
+ qi->tqi_subtype = qinfo->tqi_subtype;
+ qi->tqi_flags = qinfo->tqi_flags;
+ /*
+ * According to the docs: Although the AIFS field is 8 bit wide,
+ * the maximum supported value is 0xFC. Setting it higher than that
+ * will cause the DCU to hang.
+ */
+ qi->tqi_aifs = min(qinfo->tqi_aifs, (u8)0xFC);
+ qi->tqi_cw_min = ath5k_cw_validate(qinfo->tqi_cw_min);
+ qi->tqi_cw_max = ath5k_cw_validate(qinfo->tqi_cw_max);
+ qi->tqi_cbr_period = qinfo->tqi_cbr_period;
+ qi->tqi_cbr_overflow_limit = qinfo->tqi_cbr_overflow_limit;
+ qi->tqi_burst_time = qinfo->tqi_burst_time;
+ qi->tqi_ready_time = qinfo->tqi_ready_time;
/*XXX: Is this supported on 5210 ?*/
- if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA &&
- ((queue_info->tqi_subtype == AR5K_WME_AC_VI) ||
- (queue_info->tqi_subtype == AR5K_WME_AC_VO))) ||
- queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD)
- ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
+ /*XXX: Is this correct for AR5K_WME_AC_VI,VO ???*/
+ if ((qinfo->tqi_type == AR5K_TX_QUEUE_DATA &&
+ ((qinfo->tqi_subtype == AR5K_WME_AC_VI) ||
+ (qinfo->tqi_subtype == AR5K_WME_AC_VO))) ||
+ qinfo->tqi_type == AR5K_TX_QUEUE_UAPSD)
+ qi->tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
return 0;
}
@@ -186,7 +220,7 @@ void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
*/
int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
{
- u32 cw_min, cw_max, retry_lg, retry_sh;
+ u32 retry_lg, retry_sh;
struct ath5k_txq_info *tq = &ah->ah_txq[queue];
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
@@ -217,14 +251,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
/* Set IFS0 */
if (ah->ah_turbo) {
ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
- (ah->ah_aifs + tq->tqi_aifs) *
- AR5K_INIT_SLOT_TIME_TURBO) <<
+ tq->tqi_aifs * AR5K_INIT_SLOT_TIME_TURBO) <<
AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
AR5K_IFS0);
} else {
ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
- (ah->ah_aifs + tq->tqi_aifs) *
- AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) |
+ tq->tqi_aifs * AR5K_INIT_SLOT_TIME) <<
+ AR5K_IFS0_DIFS_S) |
AR5K_INIT_SIFS, AR5K_IFS0);
}
@@ -248,35 +281,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
}
/*
- * Calculate cwmin/max by channel mode
- */
- cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN;
- cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX;
- ah->ah_aifs = AR5K_TUNE_AIFS;
- /*XR is only supported on 5212*/
- if (IS_CHAN_XR(ah->ah_current_channel) &&
- ah->ah_version == AR5K_AR5212) {
- cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR;
- cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR;
- ah->ah_aifs = AR5K_TUNE_AIFS_XR;
- /*B mode is not supported on 5210*/
- } else if (IS_CHAN_B(ah->ah_current_channel) &&
- ah->ah_version != AR5K_AR5210) {
- cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B;
- cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B;
- ah->ah_aifs = AR5K_TUNE_AIFS_11B;
- }
-
- cw_min = 1;
- while (cw_min < ah->ah_cw_min)
- cw_min = (cw_min << 1) | 1;
-
- cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) :
- ((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1);
- cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) :
- ((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1);
-
- /*
* Calculate and set retry limits
*/
if (ah->ah_software_retry) {
@@ -292,7 +296,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
/*No QCU/DCU [5210]*/
if (ah->ah_version == AR5K_AR5210) {
ath5k_hw_reg_write(ah,
- (cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
+ (tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
| AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
AR5K_NODCU_RETRY_LMT_SLG_RETRY)
| AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
@@ -314,14 +318,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
/*===Rest is also for QCU/DCU only [5211+]===*/
/*
- * Set initial content window (cw_min/cw_max)
+ * Set contention window (cw_min/cw_max)
* and arbitrated interframe space (aifs)...
*/
ath5k_hw_reg_write(ah,
- AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
- AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
- AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs,
- AR5K_DCU_LCL_IFS_AIFS),
+ AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
+ AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
+ AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS),
AR5K_QUEUE_DFS_LOCAL_IFS(queue));
/*
diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h
index 55b4ac6d236f..ca79ecd832fd 100644
--- a/drivers/net/wireless/ath/ath5k/reg.h
+++ b/drivers/net/wireless/ath/ath5k/reg.h
@@ -26,7 +26,6 @@
* Atheros presentations and papers like these:
*
* 5210 - http://nova.stanford.edu/~bbaas/ps/isscc2002_slides.pdf
- * http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf
*
* 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf
*
@@ -1387,10 +1386,9 @@
/*
- * PCU control register
+ * PCU Diagnostic register
*
- * Only DIS_RX is used in the code, the rest i guess are
- * for tweaking/diagnostics.
+ * Used for tweaking/diagnostics.
*/
#define AR5K_DIAG_SW_5210 0x8068 /* Register Address [5210] */
#define AR5K_DIAG_SW_5211 0x8048 /* Register Address [5211+] */
@@ -1399,22 +1397,22 @@
#define AR5K_DIAG_SW_DIS_WEP_ACK 0x00000001 /* Disable ACKs if WEP key is invalid */
#define AR5K_DIAG_SW_DIS_ACK 0x00000002 /* Disable ACKs */
#define AR5K_DIAG_SW_DIS_CTS 0x00000004 /* Disable CTSs */
-#define AR5K_DIAG_SW_DIS_ENC 0x00000008 /* Disable encryption */
-#define AR5K_DIAG_SW_DIS_DEC 0x00000010 /* Disable decryption */
-#define AR5K_DIAG_SW_DIS_TX 0x00000020 /* Disable transmit [5210] */
-#define AR5K_DIAG_SW_DIS_RX_5210 0x00000040 /* Disable recieve */
+#define AR5K_DIAG_SW_DIS_ENC 0x00000008 /* Disable HW encryption */
+#define AR5K_DIAG_SW_DIS_DEC 0x00000010 /* Disable HW decryption */
+#define AR5K_DIAG_SW_DIS_TX_5210 0x00000020 /* Disable transmit [5210] */
+#define AR5K_DIAG_SW_DIS_RX_5210 0x00000040 /* Disable receive */
#define AR5K_DIAG_SW_DIS_RX_5211 0x00000020
#define AR5K_DIAG_SW_DIS_RX (ah->ah_version == AR5K_AR5210 ? \
AR5K_DIAG_SW_DIS_RX_5210 : AR5K_DIAG_SW_DIS_RX_5211)
-#define AR5K_DIAG_SW_LOOP_BACK_5210 0x00000080 /* Loopback (i guess it goes with DIS_TX) [5210] */
+#define AR5K_DIAG_SW_LOOP_BACK_5210 0x00000080 /* TX Data Loopback (i guess it goes with DIS_TX) [5210] */
#define AR5K_DIAG_SW_LOOP_BACK_5211 0x00000040
#define AR5K_DIAG_SW_LOOP_BACK (ah->ah_version == AR5K_AR5210 ? \
AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211)
-#define AR5K_DIAG_SW_CORR_FCS_5210 0x00000100 /* Corrupted FCS */
+#define AR5K_DIAG_SW_CORR_FCS_5210 0x00000100 /* Generate invalid TX FCS */
#define AR5K_DIAG_SW_CORR_FCS_5211 0x00000080
#define AR5K_DIAG_SW_CORR_FCS (ah->ah_version == AR5K_AR5210 ? \
AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211)
-#define AR5K_DIAG_SW_CHAN_INFO_5210 0x00000200 /* Dump channel info */
+#define AR5K_DIAG_SW_CHAN_INFO_5210 0x00000200 /* Add 56 bytes of channel info before the frame data in the RX buffer */
#define AR5K_DIAG_SW_CHAN_INFO_5211 0x00000100
#define AR5K_DIAG_SW_CHAN_INFO (ah->ah_version == AR5K_AR5210 ? \
AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211)
@@ -1426,17 +1424,17 @@
#define AR5K_DIAG_SW_SCVRAM_SEED 0x0003f800 /* [5210] */
#define AR5K_DIAG_SW_SCRAM_SEED_M 0x0001fc00 /* Scrambler seed mask */
#define AR5K_DIAG_SW_SCRAM_SEED_S 10
-#define AR5K_DIAG_SW_DIS_SEQ_INC 0x00040000 /* Disable seqnum increment (?)[5210] */
+#define AR5K_DIAG_SW_DIS_SEQ_INC_5210 0x00040000 /* Disable seqnum increment (?)[5210] */
#define AR5K_DIAG_SW_FRAME_NV0_5210 0x00080000
#define AR5K_DIAG_SW_FRAME_NV0_5211 0x00020000 /* Accept frames of non-zero protocol number */
#define AR5K_DIAG_SW_FRAME_NV0 (ah->ah_version == AR5K_AR5210 ? \
AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211)
#define AR5K_DIAG_SW_OBSPT_M 0x000c0000 /* Observation point select (?) */
#define AR5K_DIAG_SW_OBSPT_S 18
-#define AR5K_DIAG_SW_RX_CLEAR_HIGH 0x0010000 /* Force RX Clear high */
-#define AR5K_DIAG_SW_IGNORE_CARR_SENSE 0x0020000 /* Ignore virtual carrier sense */
-#define AR5K_DIAG_SW_CHANEL_IDLE_HIGH 0x0040000 /* Force channel idle high */
-#define AR5K_DIAG_SW_PHEAR_ME 0x0080000 /* ??? */
+#define AR5K_DIAG_SW_RX_CLEAR_HIGH 0x00100000 /* Ignore carrier sense */
+#define AR5K_DIAG_SW_IGNORE_CARR_SENSE 0x00200000 /* Ignore virtual carrier sense */
+#define AR5K_DIAG_SW_CHANNEL_IDLE_HIGH 0x00400000 /* Force channel idle high */
+#define AR5K_DIAG_SW_PHEAR_ME 0x00800000 /* ??? */
/*
* TSF (clock) register (lower 32 bits)
@@ -1822,50 +1820,8 @@
/*===5212 end===*/
-/*
- * Key table (WEP) register
- */
-#define AR5K_KEYTABLE_0_5210 0x9000
-#define AR5K_KEYTABLE_0_5211 0x8800
-#define AR5K_KEYTABLE_5210(_n) (AR5K_KEYTABLE_0_5210 + ((_n) << 5))
-#define AR5K_KEYTABLE_5211(_n) (AR5K_KEYTABLE_0_5211 + ((_n) << 5))
-#define AR5K_KEYTABLE(_n) (ah->ah_version == AR5K_AR5210 ? \
- AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n))
-#define AR5K_KEYTABLE_OFF(_n, x) (AR5K_KEYTABLE(_n) + (x << 2))
-#define AR5K_KEYTABLE_TYPE(_n) AR5K_KEYTABLE_OFF(_n, 5)
-#define AR5K_KEYTABLE_TYPE_40 0x00000000
-#define AR5K_KEYTABLE_TYPE_104 0x00000001
-#define AR5K_KEYTABLE_TYPE_128 0x00000003
-#define AR5K_KEYTABLE_TYPE_TKIP 0x00000004 /* [5212+] */
-#define AR5K_KEYTABLE_TYPE_AES 0x00000005 /* [5211+] */
-#define AR5K_KEYTABLE_TYPE_CCM 0x00000006 /* [5212+] */
-#define AR5K_KEYTABLE_TYPE_NULL 0x00000007 /* [5211+] */
-#define AR5K_KEYTABLE_ANTENNA 0x00000008 /* [5212+] */
-#define AR5K_KEYTABLE_MAC0(_n) AR5K_KEYTABLE_OFF(_n, 6)
-#define AR5K_KEYTABLE_MAC1(_n) AR5K_KEYTABLE_OFF(_n, 7)
-#define AR5K_KEYTABLE_VALID 0x00008000
-
-/* If key type is TKIP and MIC is enabled
- * MIC key goes in offset entry + 64 */
-#define AR5K_KEYTABLE_MIC_OFFSET 64
-
-/* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit
- * WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit
- * WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit
- *
- * Some vendors have introduced bigger WEP keys to address
- * security vulnerabilities in WEP. This includes:
- *
- * WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit
- *
- * We can expand this if we find ar5k Atheros cards with a larger
- * key table size.
- */
#define AR5K_KEYTABLE_SIZE_5210 64
#define AR5K_KEYTABLE_SIZE_5211 128
-#define AR5K_KEYTABLE_SIZE (ah->ah_version == AR5K_AR5210 ? \
- AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211)
-
/*===PHY REGISTERS===*/
@@ -1911,7 +1867,7 @@
#define AR5K_PHY_TURBO 0x9804 /* Register Address */
#define AR5K_PHY_TURBO_MODE 0x00000001 /* Enable turbo mode */
#define AR5K_PHY_TURBO_SHORT 0x00000002 /* Set short symbols to turbo mode */
-#define AR5K_PHY_TURBO_MIMO 0x00000004 /* Set turbo for mimo mimo */
+#define AR5K_PHY_TURBO_MIMO 0x00000004 /* Set turbo for mimo */
/*
* PHY agility command register
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 498aa28ea9e6..5b179d01f97d 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -167,7 +167,7 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
* ieee80211_duration() for a brief description of
* what rate we should choose to TX ACKs. */
tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw,
- sc->vif, 10, rate));
+ NULL, 10, rate));
ath5k_hw_reg_write(ah, tx_time, reg);
@@ -326,7 +326,7 @@ commit:
* register). After this MAC and Baseband are
* disabled and a full reset is needed to come
* back. This way we save as much power as possible
- * without puting the card on full sleep.
+ * without putting the card on full sleep.
*/
int ath5k_hw_on_hold(struct ath5k_hw *ah)
{
@@ -344,7 +344,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
/*
* Put chipset on warm reset...
*
- * Note: puting PCI core on warm reset on PCI-E cards
+ * Note: putting PCI core on warm reset on PCI-E cards
* results card to hang and always return 0xffff... so
* we ingore that flag for PCI-E cards. On PCI cards
* this flag gets cleared after 64 PCI clocks.
@@ -400,7 +400,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
/*
* Put chipset on warm reset...
*
- * Note: puting PCI core on warm reset on PCI-E cards
+ * Note: putting PCI core on warm reset on PCI-E cards
* results card to hang and always return 0xffff... so
* we ingore that flag for PCI-E cards. On PCI cards
* this flag gets cleared after 64 PCI clocks.
@@ -959,7 +959,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
AR5K_QUEUE_DCU_SEQNUM(0));
}
- /* TSF accelerates on AR5211 durring reset
+ /* TSF accelerates on AR5211 during reset
* As a workaround save it here and restore
* it later so that it's back in time after
* reset. This way it'll get re-synced on the
@@ -1060,7 +1060,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
* XXX: rethink this after new mode changes to
* mac80211 are integrated */
if (ah->ah_version == AR5K_AR5212 &&
- ah->ah_sc->vif != NULL)
+ ah->ah_sc->nvifs)
ath5k_hw_write_rate_duration(ah, mode);
/*
@@ -1080,7 +1080,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
return ret;
/* Spur info is available only from EEPROM versions
- * bigger than 5.3 but but the EEPOM routines will use
+ * greater than 5.3, but the EEPROM routines will use
* static values for older versions */
if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
ath5k_hw_set_spur_mitigation_filter(ah,
@@ -1160,7 +1160,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
*/
/* Restore bssid and bssid mask */
- ath5k_hw_set_associd(ah);
+ ath5k_hw_set_bssid(ah);
/* Set PCU config */
ath5k_hw_set_opmode(ah, op_mode);
@@ -1173,11 +1173,11 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
/* Set RSSI/BRSSI thresholds
*
* Note: If we decide to set this value
- * dynamicaly, have in mind that when AR5K_RSSI_THR
- * register is read it might return 0x40 if we haven't
- * wrote anything to it plus BMISS RSSI threshold is zeroed.
+ * dynamically, keep in mind that when AR5K_RSSI_THR
+ * register is read, it might return 0x40 if we haven't
+ * written anything to it. Also, BMISS RSSI threshold is zeroed.
* So doing a save/restore procedure here isn't the right
- * choice. Instead store it on ath5k_hw */
+ * choice. Instead, store it in ath5k_hw */
ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES |
AR5K_TUNE_BMISS_THRES <<
AR5K_RSSI_THR_BMISS_S),
@@ -1235,7 +1235,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
/*
* Perform ADC test to see if baseband is ready
- * Set tx hold and check adc test register
+ * Set TX hold and check ADC test register
*/
phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
@@ -1254,15 +1254,15 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
*
* This method is used to calibrate some static offsets
* used together with on-the fly I/Q calibration (the
- * one performed via ath5k_hw_phy_calibrate), that doesn't
+ * one performed via ath5k_hw_phy_calibrate), which doesn't
* interrupt rx path.
*
* While rx path is re-routed to the power detector we also
- * start a noise floor calibration, to measure the
+ * start a noise floor calibration to measure the
* card's noise floor (the noise we measure when we are not
- * transmiting or receiving anything).
+ * transmitting or receiving anything).
*
- * If we are in a noisy environment AGC calibration may time
+ * If we are in a noisy environment, AGC calibration may time
* out and/or noise floor calibration might timeout.
*/
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
diff --git a/drivers/net/wireless/ath/ath5k/rfbuffer.h b/drivers/net/wireless/ath/ath5k/rfbuffer.h
index e50baff66175..3ac4cff4239d 100644
--- a/drivers/net/wireless/ath/ath5k/rfbuffer.h
+++ b/drivers/net/wireless/ath/ath5k/rfbuffer.h
@@ -25,10 +25,10 @@
*
* We don't write on those registers directly but
* we send a data packet on the chip, using a special register,
- * that holds all the settings we need. After we 've sent the
+ * that holds all the settings we need. After we've sent the
* data packet, we write on another special register to notify hw
* to apply the settings. This is done so that control registers
- * can be dynamicaly programmed during operation and the settings
+ * can be dynamically programmed during operation and the settings
* are applied faster on the hw.
*
* We call each data packet an "RF Bank" and all the data we write
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index 35f23bdc442f..ad57a6d23110 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -32,6 +32,14 @@ config ATH9K_DEBUGFS
Also required for changing debug message flags at run time.
+config ATH9K_RATE_CONTROL
+ bool "Atheros ath9k rate control"
+ depends on ATH9K
+ default y
+ ---help---
+ Say Y, if you want to use the ath9k specific rate control
+ module instead of minstrel_ht.
+
config ATH9K_HTC
tristate "Atheros HTC based wireless cards support"
depends on USB && MAC80211
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 973ae4f49f35..aca01621c205 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -5,8 +5,8 @@ ath9k-y += beacon.o \
recv.o \
xmit.o \
virtual.o \
- rc.o
+ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
ath9k-$(CONFIG_PCI) += pci.o
ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o
ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
@@ -46,6 +46,7 @@ ath9k_htc-y += htc_hst.o \
htc_drv_txrx.o \
htc_drv_main.o \
htc_drv_beacon.o \
- htc_drv_init.o
+ htc_drv_init.o \
+ htc_drv_gpio.o
obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index a3d95cca8f0c..63ccb39cdcd4 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/kernel.h>
#include "hw.h"
#include "hw-ops.h"
@@ -48,7 +49,7 @@ static const struct ani_ofdm_level_entry ofdm_level_table[] = {
{ 7, 8, 0 } /* lvl 9 */
};
#define ATH9K_ANI_OFDM_NUM_LEVEL \
- (sizeof(ofdm_level_table)/sizeof(ofdm_level_table[0]))
+ ARRAY_SIZE(ofdm_level_table)
#define ATH9K_ANI_OFDM_MAX_LEVEL \
(ATH9K_ANI_OFDM_NUM_LEVEL-1)
#define ATH9K_ANI_OFDM_DEF_LEVEL \
@@ -94,7 +95,7 @@ static const struct ani_cck_level_entry cck_level_table[] = {
};
#define ATH9K_ANI_CCK_NUM_LEVEL \
- (sizeof(cck_level_table)/sizeof(cck_level_table[0]))
+ ARRAY_SIZE(cck_level_table)
#define ATH9K_ANI_CCK_MAX_LEVEL \
(ATH9K_ANI_CCK_NUM_LEVEL-1)
#define ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI \
@@ -102,31 +103,9 @@ static const struct ani_cck_level_entry cck_level_table[] = {
#define ATH9K_ANI_CCK_DEF_LEVEL \
2 /* default level - matches the INI settings */
-/* Private to ani.c */
-static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
+static bool use_new_ani(struct ath_hw *ah)
{
- ath9k_hw_private_ops(ah)->ani_lower_immunity(ah);
-}
-
-int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
- if (ah->ani[i].c &&
- ah->ani[i].c->channel == chan->channel)
- return i;
- if (ah->ani[i].c == NULL) {
- ah->ani[i].c = chan;
- return i;
- }
- }
-
- ath_print(ath9k_hw_common(ah), ATH_DBG_ANI,
- "No more channel states left. Using channel 0\n");
-
- return 0;
+ return AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani;
}
static void ath9k_hw_update_mibstats(struct ath_hw *ah,
@@ -139,82 +118,34 @@ static void ath9k_hw_update_mibstats(struct ath_hw *ah,
stats->beacons += REG_READ(ah, AR_BEACON_CNT);
}
-static void ath9k_ani_restart_old(struct ath_hw *ah)
+static void ath9k_ani_restart(struct ath_hw *ah)
{
struct ar5416AniState *aniState;
struct ath_common *common = ath9k_hw_common(ah);
+ u32 ofdm_base = 0, cck_base = 0;
if (!DO_ANI(ah))
return;
- aniState = ah->curani;
+ aniState = &ah->curchan->ani;
aniState->listenTime = 0;
- if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
- aniState->ofdmPhyErrBase = 0;
- ath_print(common, ATH_DBG_ANI,
- "OFDM Trigger is too high for hw counters\n");
- } else {
- aniState->ofdmPhyErrBase =
- AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
- }
- if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
- aniState->cckPhyErrBase = 0;
- ath_print(common, ATH_DBG_ANI,
- "CCK Trigger is too high for hw counters\n");
- } else {
- aniState->cckPhyErrBase =
- AR_PHY_COUNTMAX - aniState->cckTrigHigh;
+ if (!use_new_ani(ah)) {
+ ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
+ cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
}
- ath_print(common, ATH_DBG_ANI,
- "Writing ofdmbase=%u cckbase=%u\n",
- aniState->ofdmPhyErrBase,
- aniState->cckPhyErrBase);
-
- ENABLE_REGWRITE_BUFFER(ah);
-
- REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
- REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
-
- REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
-
- ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
-
- aniState->ofdmPhyErrCount = 0;
- aniState->cckPhyErrCount = 0;
-}
-
-static void ath9k_ani_restart_new(struct ath_hw *ah)
-{
- struct ar5416AniState *aniState;
- struct ath_common *common = ath9k_hw_common(ah);
-
- if (!DO_ANI(ah))
- return;
-
- aniState = ah->curani;
- aniState->listenTime = 0;
-
- aniState->ofdmPhyErrBase = 0;
- aniState->cckPhyErrBase = 0;
ath_print(common, ATH_DBG_ANI,
- "Writing ofdmbase=%08x cckbase=%08x\n",
- aniState->ofdmPhyErrBase,
- aniState->cckPhyErrBase);
+ "Writing ofdmbase=%u cckbase=%u\n", ofdm_base, cck_base);
ENABLE_REGWRITE_BUFFER(ah);
- REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
+ REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
@@ -228,10 +159,7 @@ static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah)
struct ar5416AniState *aniState;
int32_t rssi;
- if (!DO_ANI(ah))
- return;
-
- aniState = ah->curani;
+ aniState = &ah->curchan->ani;
if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
@@ -300,10 +228,7 @@ static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah)
struct ar5416AniState *aniState;
int32_t rssi;
- if (!DO_ANI(ah))
- return;
-
- aniState = ah->curani;
+ aniState = &ah->curchan->ani;
if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
aniState->noiseImmunityLevel + 1)) {
@@ -335,7 +260,7 @@ static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah)
/* Adjust the OFDM Noise Immunity Level */
static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
{
- struct ar5416AniState *aniState = ah->curani;
+ struct ar5416AniState *aniState = &ah->curchan->ani;
struct ath_common *common = ath9k_hw_common(ah);
const struct ani_ofdm_level_entry *entry_ofdm;
const struct ani_cck_level_entry *entry_cck;
@@ -380,14 +305,19 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
}
}
-static void ath9k_hw_ani_ofdm_err_trigger_new(struct ath_hw *ah)
+static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
{
struct ar5416AniState *aniState;
if (!DO_ANI(ah))
return;
- aniState = ah->curani;
+ if (!use_new_ani(ah)) {
+ ath9k_hw_ani_ofdm_err_trigger_old(ah);
+ return;
+ }
+
+ aniState = &ah->curchan->ani;
if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1);
@@ -398,7 +328,7 @@ static void ath9k_hw_ani_ofdm_err_trigger_new(struct ath_hw *ah)
*/
static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
{
- struct ar5416AniState *aniState = ah->curani;
+ struct ar5416AniState *aniState = &ah->curchan->ani;
struct ath_common *common = ath9k_hw_common(ah);
const struct ani_ofdm_level_entry *entry_ofdm;
const struct ani_cck_level_entry *entry_cck;
@@ -437,14 +367,19 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
entry_cck->mrc_cck_on);
}
-static void ath9k_hw_ani_cck_err_trigger_new(struct ath_hw *ah)
+static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
{
struct ar5416AniState *aniState;
if (!DO_ANI(ah))
return;
- aniState = ah->curani;
+ if (!use_new_ani(ah)) {
+ ath9k_hw_ani_cck_err_trigger_old(ah);
+ return;
+ }
+
+ aniState = &ah->curchan->ani;
if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1);
@@ -455,7 +390,7 @@ static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
struct ar5416AniState *aniState;
int32_t rssi;
- aniState = ah->curani;
+ aniState = &ah->curchan->ani;
if (ah->opmode == NL80211_IFTYPE_AP) {
if (aniState->firstepLevel > 0) {
@@ -507,11 +442,16 @@ static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
* only lower either OFDM or CCK errors per turn
* we lower the other one next time
*/
-static void ath9k_hw_ani_lower_immunity_new(struct ath_hw *ah)
+static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
{
struct ar5416AniState *aniState;
- aniState = ah->curani;
+ aniState = &ah->curchan->ani;
+
+ if (!use_new_ani(ah)) {
+ ath9k_hw_ani_lower_immunity_old(ah);
+ return;
+ }
/* lower OFDM noise immunity */
if (aniState->ofdmNoiseImmunityLevel > 0 &&
@@ -525,87 +465,18 @@ static void ath9k_hw_ani_lower_immunity_new(struct ath_hw *ah)
ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1);
}
-static u8 ath9k_hw_chan_2_clockrate_mhz(struct ath_hw *ah)
-{
- struct ath9k_channel *chan = ah->curchan;
- struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
- u8 clockrate; /* in MHz */
-
- if (!ah->curchan) /* should really check for CCK instead */
- clockrate = ATH9K_CLOCK_RATE_CCK;
- else if (conf->channel->band == IEEE80211_BAND_2GHZ)
- clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM;
- else if (IS_CHAN_A_FAST_CLOCK(ah, chan))
- clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM;
- else
- clockrate = ATH9K_CLOCK_RATE_5GHZ_OFDM;
-
- if (conf_is_ht40(conf))
- return clockrate * 2;
-
- return clockrate;
-}
-
-static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
-{
- struct ar5416AniState *aniState;
- struct ath_common *common = ath9k_hw_common(ah);
- u32 txFrameCount, rxFrameCount, cycleCount;
- int32_t listenTime;
-
- txFrameCount = REG_READ(ah, AR_TFCNT);
- rxFrameCount = REG_READ(ah, AR_RFCNT);
- cycleCount = REG_READ(ah, AR_CCCNT);
-
- aniState = ah->curani;
- if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
- listenTime = 0;
- ah->stats.ast_ani_lzero++;
- ath_print(common, ATH_DBG_ANI,
- "1st call: aniState->cycleCount=%d\n",
- aniState->cycleCount);
- } else {
- int32_t ccdelta = cycleCount - aniState->cycleCount;
- int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
- int32_t tfdelta = txFrameCount - aniState->txFrameCount;
- int32_t clock_rate;
-
- /*
- * convert HW counter values to ms using mode
- * specifix clock rate
- */
- clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000;;
-
- listenTime = (ccdelta - rfdelta - tfdelta) / clock_rate;
-
- ath_print(common, ATH_DBG_ANI,
- "cyclecount=%d, rfcount=%d, "
- "tfcount=%d, listenTime=%d CLOCK_RATE=%d\n",
- ccdelta, rfdelta, tfdelta, listenTime, clock_rate);
- }
-
- aniState->cycleCount = cycleCount;
- aniState->txFrameCount = txFrameCount;
- aniState->rxFrameCount = rxFrameCount;
-
- return listenTime;
-}
-
static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
{
struct ar5416AniState *aniState;
struct ath9k_channel *chan = ah->curchan;
struct ath_common *common = ath9k_hw_common(ah);
- int index;
if (!DO_ANI(ah))
return;
- index = ath9k_hw_get_ani_channel_idx(ah, chan);
- aniState = &ah->ani[index];
- ah->curani = aniState;
+ aniState = &ah->curchan->ani;
- if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION
+ if (ah->opmode != NL80211_IFTYPE_STATION
&& ah->opmode != NL80211_IFTYPE_ADHOC) {
ath_print(common, ATH_DBG_ANI,
"Reset ANI state opmode %u\n", ah->opmode);
@@ -634,17 +505,7 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
ATH9K_RX_FILTER_PHYERR);
- if (ah->opmode == NL80211_IFTYPE_AP) {
- ah->curani->ofdmTrigHigh =
- ah->config.ofdm_trig_high;
- ah->curani->ofdmTrigLow =
- ah->config.ofdm_trig_low;
- ah->curani->cckTrigHigh =
- ah->config.cck_trig_high;
- ah->curani->cckTrigLow =
- ah->config.cck_trig_low;
- }
- ath9k_ani_restart_old(ah);
+ ath9k_ani_restart(ah);
return;
}
@@ -666,7 +527,7 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
~ATH9K_RX_FILTER_PHYERR);
- ath9k_ani_restart_old(ah);
+ ath9k_ani_restart(ah);
ENABLE_REGWRITE_BUFFER(ah);
@@ -674,7 +535,6 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
}
/*
@@ -682,15 +542,18 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
* This routine should be called for every hardware reset and for
* every channel change.
*/
-static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning)
+void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
{
- struct ar5416AniState *aniState = ah->curani;
+ struct ar5416AniState *aniState = &ah->curchan->ani;
struct ath9k_channel *chan = ah->curchan;
struct ath_common *common = ath9k_hw_common(ah);
if (!DO_ANI(ah))
return;
+ if (!use_new_ani(ah))
+ return ath9k_ani_reset_old(ah, is_scanning);
+
BUG_ON(aniState == NULL);
ah->stats.ast_ani_reset++;
@@ -760,7 +623,7 @@ static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning)
* enable phy counters if hw supports or if not, enable phy
* interrupts (so we can count each one)
*/
- ath9k_ani_restart_new(ah);
+ ath9k_ani_restart(ah);
ENABLE_REGWRITE_BUFFER(ah);
@@ -768,28 +631,30 @@ static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning)
REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
}
-static void ath9k_hw_ani_monitor_old(struct ath_hw *ah,
- struct ath9k_channel *chan)
+static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
{
- struct ar5416AniState *aniState;
struct ath_common *common = ath9k_hw_common(ah);
- int32_t listenTime;
- u32 phyCnt1, phyCnt2;
+ struct ar5416AniState *aniState = &ah->curchan->ani;
+ u32 ofdm_base = 0;
+ u32 cck_base = 0;
u32 ofdmPhyErrCnt, cckPhyErrCnt;
+ u32 phyCnt1, phyCnt2;
+ int32_t listenTime;
- if (!DO_ANI(ah))
- return;
-
- aniState = ah->curani;
+ ath_hw_cycle_counters_update(common);
+ listenTime = ath_hw_get_listen_time(common);
- listenTime = ath9k_hw_ani_get_listen_time(ah);
- if (listenTime < 0) {
+ if (listenTime <= 0) {
ah->stats.ast_ani_lneg++;
- ath9k_ani_restart_old(ah);
- return;
+ ath9k_ani_restart(ah);
+ return false;
+ }
+
+ if (!use_new_ani(ah)) {
+ ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
+ cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
}
aniState->listenTime += listenTime;
@@ -799,145 +664,55 @@ static void ath9k_hw_ani_monitor_old(struct ath_hw *ah,
phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
- if (phyCnt1 < aniState->ofdmPhyErrBase ||
- phyCnt2 < aniState->cckPhyErrBase) {
- if (phyCnt1 < aniState->ofdmPhyErrBase) {
+ if (!use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) {
+ if (phyCnt1 < ofdm_base) {
ath_print(common, ATH_DBG_ANI,
"phyCnt1 0x%x, resetting "
"counter value to 0x%x\n",
- phyCnt1,
- aniState->ofdmPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_1,
- aniState->ofdmPhyErrBase);
+ phyCnt1, ofdm_base);
+ REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
REG_WRITE(ah, AR_PHY_ERR_MASK_1,
AR_PHY_ERR_OFDM_TIMING);
}
- if (phyCnt2 < aniState->cckPhyErrBase) {
+ if (phyCnt2 < cck_base) {
ath_print(common, ATH_DBG_ANI,
"phyCnt2 0x%x, resetting "
"counter value to 0x%x\n",
- phyCnt2,
- aniState->cckPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_2,
- aniState->cckPhyErrBase);
+ phyCnt2, cck_base);
+ REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
REG_WRITE(ah, AR_PHY_ERR_MASK_2,
AR_PHY_ERR_CCK_TIMING);
}
- return;
+ return false;
}
- ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
+ ofdmPhyErrCnt = phyCnt1 - ofdm_base;
ah->stats.ast_ani_ofdmerrs +=
ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
- cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
+ cckPhyErrCnt = phyCnt2 - cck_base;
ah->stats.ast_ani_cckerrs +=
cckPhyErrCnt - aniState->cckPhyErrCount;
aniState->cckPhyErrCount = cckPhyErrCnt;
-
- if (aniState->listenTime > 5 * ah->aniperiod) {
- if (aniState->ofdmPhyErrCount <= aniState->listenTime *
- aniState->ofdmTrigLow / 1000 &&
- aniState->cckPhyErrCount <= aniState->listenTime *
- aniState->cckTrigLow / 1000)
- ath9k_hw_ani_lower_immunity(ah);
- ath9k_ani_restart_old(ah);
- } else if (aniState->listenTime > ah->aniperiod) {
- if (aniState->ofdmPhyErrCount > aniState->listenTime *
- aniState->ofdmTrigHigh / 1000) {
- ath9k_hw_ani_ofdm_err_trigger_old(ah);
- ath9k_ani_restart_old(ah);
- } else if (aniState->cckPhyErrCount >
- aniState->listenTime * aniState->cckTrigHigh /
- 1000) {
- ath9k_hw_ani_cck_err_trigger_old(ah);
- ath9k_ani_restart_old(ah);
- }
- }
+ return true;
}
-static void ath9k_hw_ani_monitor_new(struct ath_hw *ah,
- struct ath9k_channel *chan)
+void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
{
struct ar5416AniState *aniState;
struct ath_common *common = ath9k_hw_common(ah);
- int32_t listenTime;
- u32 phyCnt1, phyCnt2;
- u32 ofdmPhyErrCnt, cckPhyErrCnt;
u32 ofdmPhyErrRate, cckPhyErrRate;
if (!DO_ANI(ah))
return;
- aniState = ah->curani;
+ aniState = &ah->curchan->ani;
if (WARN_ON(!aniState))
return;
- listenTime = ath9k_hw_ani_get_listen_time(ah);
- if (listenTime <= 0) {
- ah->stats.ast_ani_lneg++;
- /* restart ANI period if listenTime is invalid */
- ath_print(common, ATH_DBG_ANI,
- "listenTime=%d - on new ani monitor\n",
- listenTime);
- ath9k_ani_restart_new(ah);
- return;
- }
-
- aniState->listenTime += listenTime;
-
- ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
-
- phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
- phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
-
- if (phyCnt1 < aniState->ofdmPhyErrBase ||
- phyCnt2 < aniState->cckPhyErrBase) {
- if (phyCnt1 < aniState->ofdmPhyErrBase) {
- ath_print(common, ATH_DBG_ANI,
- "phyCnt1 0x%x, resetting "
- "counter value to 0x%x\n",
- phyCnt1,
- aniState->ofdmPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_1,
- aniState->ofdmPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_MASK_1,
- AR_PHY_ERR_OFDM_TIMING);
- }
- if (phyCnt2 < aniState->cckPhyErrBase) {
- ath_print(common, ATH_DBG_ANI,
- "phyCnt2 0x%x, resetting "
- "counter value to 0x%x\n",
- phyCnt2,
- aniState->cckPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_2,
- aniState->cckPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_MASK_2,
- AR_PHY_ERR_CCK_TIMING);
- }
+ if (!ath9k_hw_ani_read_counters(ah))
return;
- }
-
- ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
- ah->stats.ast_ani_ofdmerrs +=
- ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
- aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
-
- cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
- ah->stats.ast_ani_cckerrs +=
- cckPhyErrCnt - aniState->cckPhyErrCount;
- aniState->cckPhyErrCount = cckPhyErrCnt;
-
- ath_print(common, ATH_DBG_ANI,
- "Errors: OFDM=0x%08x-0x%08x=%d "
- "CCK=0x%08x-0x%08x=%d\n",
- phyCnt1,
- aniState->ofdmPhyErrBase,
- ofdmPhyErrCnt,
- phyCnt2,
- aniState->cckPhyErrBase,
- cckPhyErrCnt);
ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 /
aniState->listenTime;
@@ -947,61 +722,34 @@ static void ath9k_hw_ani_monitor_new(struct ath_hw *ah,
ath_print(common, ATH_DBG_ANI,
"listenTime=%d OFDM:%d errs=%d/s CCK:%d "
"errs=%d/s ofdm_turn=%d\n",
- listenTime, aniState->ofdmNoiseImmunityLevel,
+ aniState->listenTime,
+ aniState->ofdmNoiseImmunityLevel,
ofdmPhyErrRate, aniState->cckNoiseImmunityLevel,
cckPhyErrRate, aniState->ofdmsTurn);
if (aniState->listenTime > 5 * ah->aniperiod) {
- if (ofdmPhyErrRate <= aniState->ofdmTrigLow &&
- cckPhyErrRate <= aniState->cckTrigLow) {
- ath_print(common, ATH_DBG_ANI,
- "1. listenTime=%d OFDM:%d errs=%d/s(<%d) "
- "CCK:%d errs=%d/s(<%d) -> "
- "ath9k_hw_ani_lower_immunity()\n",
- aniState->listenTime,
- aniState->ofdmNoiseImmunityLevel,
- ofdmPhyErrRate,
- aniState->ofdmTrigLow,
- aniState->cckNoiseImmunityLevel,
- cckPhyErrRate,
- aniState->cckTrigLow);
+ if (ofdmPhyErrRate <= ah->config.ofdm_trig_low &&
+ cckPhyErrRate <= ah->config.cck_trig_low) {
ath9k_hw_ani_lower_immunity(ah);
aniState->ofdmsTurn = !aniState->ofdmsTurn;
}
- ath_print(common, ATH_DBG_ANI,
- "1 listenTime=%d ofdm=%d/s cck=%d/s - "
- "calling ath9k_ani_restart_new()\n",
- aniState->listenTime, ofdmPhyErrRate, cckPhyErrRate);
- ath9k_ani_restart_new(ah);
+ ath9k_ani_restart(ah);
} else if (aniState->listenTime > ah->aniperiod) {
/* check to see if need to raise immunity */
- if (ofdmPhyErrRate > aniState->ofdmTrigHigh &&
- (cckPhyErrRate <= aniState->cckTrigHigh ||
+ if (ofdmPhyErrRate > ah->config.ofdm_trig_high &&
+ (cckPhyErrRate <= ah->config.cck_trig_high ||
aniState->ofdmsTurn)) {
- ath_print(common, ATH_DBG_ANI,
- "2 listenTime=%d OFDM:%d errs=%d/s(>%d) -> "
- "ath9k_hw_ani_ofdm_err_trigger_new()\n",
- aniState->listenTime,
- aniState->ofdmNoiseImmunityLevel,
- ofdmPhyErrRate,
- aniState->ofdmTrigHigh);
- ath9k_hw_ani_ofdm_err_trigger_new(ah);
- ath9k_ani_restart_new(ah);
+ ath9k_hw_ani_ofdm_err_trigger(ah);
+ ath9k_ani_restart(ah);
aniState->ofdmsTurn = false;
- } else if (cckPhyErrRate > aniState->cckTrigHigh) {
- ath_print(common, ATH_DBG_ANI,
- "3 listenTime=%d CCK:%d errs=%d/s(>%d) -> "
- "ath9k_hw_ani_cck_err_trigger_new()\n",
- aniState->listenTime,
- aniState->cckNoiseImmunityLevel,
- cckPhyErrRate,
- aniState->cckTrigHigh);
- ath9k_hw_ani_cck_err_trigger_new(ah);
- ath9k_ani_restart_new(ah);
+ } else if (cckPhyErrRate > ah->config.cck_trig_high) {
+ ath9k_hw_ani_cck_err_trigger(ah);
+ ath9k_ani_restart(ah);
aniState->ofdmsTurn = true;
}
}
}
+EXPORT_SYMBOL(ath9k_hw_ani_monitor);
void ath9k_enable_mib_counters(struct ath_hw *ah)
{
@@ -1022,7 +770,6 @@ void ath9k_enable_mib_counters(struct ath_hw *ah)
REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
}
/* Freeze the MIB counters, get the stats and then clear them */
@@ -1040,53 +787,12 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
}
EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
-u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
- u32 *rxc_pcnt,
- u32 *rxf_pcnt,
- u32 *txf_pcnt)
-{
- struct ath_common *common = ath9k_hw_common(ah);
- static u32 cycles, rx_clear, rx_frame, tx_frame;
- u32 good = 1;
-
- u32 rc = REG_READ(ah, AR_RCCNT);
- u32 rf = REG_READ(ah, AR_RFCNT);
- u32 tf = REG_READ(ah, AR_TFCNT);
- u32 cc = REG_READ(ah, AR_CCCNT);
-
- if (cycles == 0 || cycles > cc) {
- ath_print(common, ATH_DBG_ANI,
- "cycle counter wrap. ExtBusy = 0\n");
- good = 0;
- } else {
- u32 cc_d = cc - cycles;
- u32 rc_d = rc - rx_clear;
- u32 rf_d = rf - rx_frame;
- u32 tf_d = tf - tx_frame;
-
- if (cc_d != 0) {
- *rxc_pcnt = rc_d * 100 / cc_d;
- *rxf_pcnt = rf_d * 100 / cc_d;
- *txf_pcnt = tf_d * 100 / cc_d;
- } else {
- good = 0;
- }
- }
-
- cycles = cc;
- rx_frame = rf;
- rx_clear = rc;
- tx_frame = tf;
-
- return good;
-}
-
/*
* Process a MIB interrupt. We may potentially be invoked because
* any of the MIB counters overflow/trigger so don't assume we're
* here because a PHY error counter triggered.
*/
-static void ath9k_hw_proc_mib_event_old(struct ath_hw *ah)
+void ath9k_hw_proc_mib_event(struct ath_hw *ah)
{
u32 phyCnt1, phyCnt2;
@@ -1114,72 +820,15 @@ static void ath9k_hw_proc_mib_event_old(struct ath_hw *ah)
phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
- struct ar5416AniState *aniState = ah->curani;
- u32 ofdmPhyErrCnt, cckPhyErrCnt;
-
- /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
- ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
- ah->stats.ast_ani_ofdmerrs +=
- ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
- aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
- cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
- ah->stats.ast_ani_cckerrs +=
- cckPhyErrCnt - aniState->cckPhyErrCount;
- aniState->cckPhyErrCount = cckPhyErrCnt;
+ if (!use_new_ani(ah))
+ ath9k_hw_ani_read_counters(ah);
- /*
- * NB: figure out which counter triggered. If both
- * trigger we'll only deal with one as the processing
- * clobbers the error counter so the trigger threshold
- * check will never be true.
- */
- if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
- ath9k_hw_ani_ofdm_err_trigger_new(ah);
- if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
- ath9k_hw_ani_cck_err_trigger_old(ah);
/* NB: always restart to insure the h/w counters are reset */
- ath9k_ani_restart_old(ah);
- }
-}
-
-/*
- * Process a MIB interrupt. We may potentially be invoked because
- * any of the MIB counters overflow/trigger so don't assume we're
- * here because a PHY error counter triggered.
- */
-static void ath9k_hw_proc_mib_event_new(struct ath_hw *ah)
-{
- u32 phyCnt1, phyCnt2;
-
- /* Reset these counters regardless */
- REG_WRITE(ah, AR_FILT_OFDM, 0);
- REG_WRITE(ah, AR_FILT_CCK, 0);
- if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
- REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
-
- /* Clear the mib counters and save them in the stats */
- ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
-
- if (!DO_ANI(ah)) {
- /*
- * We must always clear the interrupt cause by
- * resetting the phy error regs.
- */
- REG_WRITE(ah, AR_PHY_ERR_1, 0);
- REG_WRITE(ah, AR_PHY_ERR_2, 0);
- return;
+ ath9k_ani_restart(ah);
}
-
- /* NB: these are not reset-on-read */
- phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
- phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
-
- /* NB: always restart to insure the h/w counters are reset */
- if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
- ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK))
- ath9k_ani_restart_new(ah);
}
+EXPORT_SYMBOL(ath9k_hw_proc_mib_event);
void ath9k_hw_ani_setup(struct ath_hw *ah)
{
@@ -1205,61 +854,58 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
ath_print(common, ATH_DBG_ANI, "Initialize ANI\n");
- memset(ah->ani, 0, sizeof(ah->ani));
- for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
- if (AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani) {
- ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH_NEW;
- ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW_NEW;
+ if (use_new_ani(ah)) {
+ ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW;
+ ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_NEW;
- ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH_NEW;
- ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW_NEW;
+ ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_NEW;
+ ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_NEW;
+ } else {
+ ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
+ ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
- ah->ani[i].spurImmunityLevel =
- ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
+ ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
+ ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
+ }
- ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
+ for (i = 0; i < ARRAY_SIZE(ah->channels); i++) {
+ struct ath9k_channel *chan = &ah->channels[i];
+ struct ar5416AniState *ani = &chan->ani;
- ah->ani[i].ofdmPhyErrBase = 0;
- ah->ani[i].cckPhyErrBase = 0;
+ if (use_new_ani(ah)) {
+ ani->spurImmunityLevel =
+ ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
+
+ ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
if (AR_SREV_9300_20_OR_LATER(ah))
- ah->ani[i].mrcCCKOff =
+ ani->mrcCCKOff =
!ATH9K_ANI_ENABLE_MRC_CCK;
else
- ah->ani[i].mrcCCKOff = true;
+ ani->mrcCCKOff = true;
- ah->ani[i].ofdmsTurn = true;
+ ani->ofdmsTurn = true;
} else {
- ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
- ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
-
- ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
- ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW_OLD;
-
- ah->ani[i].spurImmunityLevel =
+ ani->spurImmunityLevel =
ATH9K_ANI_SPUR_IMMUNE_LVL_OLD;
- ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD;
+ ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD;
- ah->ani[i].ofdmPhyErrBase =
- AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
- ah->ani[i].cckPhyErrBase =
- AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH_OLD;
- ah->ani[i].cckWeakSigThreshold =
+ ani->cckWeakSigThreshold =
ATH9K_ANI_CCK_WEAK_SIG_THR;
}
- ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
- ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
- ah->ani[i].ofdmWeakSigDetectOff =
+ ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
+ ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
+ ani->ofdmWeakSigDetectOff =
!ATH9K_ANI_USE_OFDM_WEAK_SIG;
- ah->ani[i].cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
+ ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
}
/*
* since we expect some ongoing maintenance on the tables, let's sanity
* check here default level should not modify INI setting.
*/
- if (AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani) {
+ if (use_new_ani(ah)) {
const struct ani_ofdm_level_entry *entry_ofdm;
const struct ani_cck_level_entry *entry_cck;
@@ -1273,50 +919,9 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD;
}
- ath_print(common, ATH_DBG_ANI,
- "Setting OfdmErrBase = 0x%08x\n",
- ah->ani[0].ofdmPhyErrBase);
- ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
- ah->ani[0].cckPhyErrBase);
-
- ENABLE_REGWRITE_BUFFER(ah);
-
- REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
-
- REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
-
- ath9k_enable_mib_counters(ah);
-
if (ah->config.enable_ani)
ah->proc_phyerr |= HAL_PROCESS_ANI;
-}
-
-void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah)
-{
- struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
- struct ath_hw_ops *ops = ath9k_hw_ops(ah);
-
- priv_ops->ani_reset = ath9k_ani_reset_old;
- priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_old;
-
- ops->ani_proc_mib_event = ath9k_hw_proc_mib_event_old;
- ops->ani_monitor = ath9k_hw_ani_monitor_old;
- ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v1\n");
-}
-
-void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah)
-{
- struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
- struct ath_hw_ops *ops = ath9k_hw_ops(ah);
-
- priv_ops->ani_reset = ath9k_ani_reset_new;
- priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_new;
-
- ops->ani_proc_mib_event = ath9k_hw_proc_mib_event_new;
- ops->ani_monitor = ath9k_hw_ani_monitor_new;
-
- ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v2\n");
+ ath9k_ani_restart(ah);
+ ath9k_enable_mib_counters(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h
index f4d0a4d48b37..0cd6783de883 100644
--- a/drivers/net/wireless/ath/ath9k/ani.h
+++ b/drivers/net/wireless/ath/ath9k/ani.h
@@ -19,7 +19,7 @@
#define HAL_PROCESS_ANI 0x00000001
-#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI))
+#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI) && ah->curchan)
#define BEACON_RSSI(ahp) (ahp->stats.avgbrssi)
@@ -123,20 +123,11 @@ struct ar5416AniState {
u8 ofdmWeakSigDetectOff;
u8 cckWeakSigThreshold;
u32 listenTime;
- u32 ofdmTrigHigh;
- u32 ofdmTrigLow;
- int32_t cckTrigHigh;
- int32_t cckTrigLow;
int32_t rssiThrLow;
int32_t rssiThrHigh;
u32 noiseFloor;
- u32 txFrameCount;
- u32 rxFrameCount;
- u32 cycleCount;
u32 ofdmPhyErrCount;
u32 cckPhyErrCount;
- u32 ofdmPhyErrBase;
- u32 cckPhyErrBase;
int16_t pktRssi[2];
int16_t ofdmErrRssi[2];
int16_t cckErrRssi[2];
@@ -166,8 +157,6 @@ struct ar5416Stats {
void ath9k_enable_mib_counters(struct ath_hw *ah);
void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
-u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt,
- u32 *rxf_pcnt, u32 *txf_pcnt);
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,
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index 3d2c8679bc85..ea9f4497f58c 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -118,7 +118,7 @@ static void ar5008_hw_force_bias(struct ath_hw *ah, u16 synth_freq)
if (!AR_SREV_5416(ah) || synth_freq >= 3000)
return;
- BUG_ON(AR_SREV_9280_10_OR_LATER(ah));
+ BUG_ON(AR_SREV_9280_20_OR_LATER(ah));
if (synth_freq < 2412)
new_bias = 0;
@@ -454,7 +454,7 @@ static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
- BUG_ON(AR_SREV_9280_10_OR_LATER(ah));
+ BUG_ON(AR_SREV_9280_20_OR_LATER(ah));
ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows);
ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows);
@@ -484,7 +484,7 @@ static void ar5008_hw_rf_free_ext_banks(struct ath_hw *ah)
bank = NULL; \
} while (0);
- BUG_ON(AR_SREV_9280_10_OR_LATER(ah));
+ BUG_ON(AR_SREV_9280_20_OR_LATER(ah));
ATH_FREE_BANK(ah->analogBank0Data);
ATH_FREE_BANK(ah->analogBank1Data);
@@ -525,7 +525,7 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah,
* for single chip devices, that is AR9280 or anything
* after that.
*/
- if (AR_SREV_9280_10_OR_LATER(ah))
+ if (AR_SREV_9280_20_OR_LATER(ah))
return true;
/* Setup rf parameters */
@@ -613,14 +613,11 @@ static void ar5008_hw_init_chain_masks(struct ath_hw *ah)
rx_chainmask = ah->rxchainmask;
tx_chainmask = ah->txchainmask;
- ENABLE_REGWRITE_BUFFER(ah);
switch (rx_chainmask) {
case 0x5:
- DISABLE_REGWRITE_BUFFER(ah);
REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
AR_PHY_SWAP_ALT_CHAIN);
- ENABLE_REGWRITE_BUFFER(ah);
case 0x3:
if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) {
REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
@@ -630,17 +627,18 @@ static void ar5008_hw_init_chain_masks(struct ath_hw *ah)
case 0x1:
case 0x2:
case 0x7:
+ ENABLE_REGWRITE_BUFFER(ah);
REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
break;
default:
+ ENABLE_REGWRITE_BUFFER(ah);
break;
}
REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
if (tx_chainmask == 0x5) {
REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
@@ -663,20 +661,20 @@ static void ar5008_hw_override_ini(struct ath_hw *ah,
*/
REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
- if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
val = REG_READ(ah, AR_PCU_MISC_MODE2);
if (!AR_SREV_9271(ah))
val &= ~AR_PCU_MISC_MODE2_HWWAR1;
- if (AR_SREV_9287_10_OR_LATER(ah))
+ if (AR_SREV_9287_11_OR_LATER(ah))
val = val & (~AR_PCU_MISC_MODE2_HWWAR2);
REG_WRITE(ah, AR_PCU_MISC_MODE2, val);
}
if (!AR_SREV_5416_20_OR_LATER(ah) ||
- AR_SREV_9280_10_OR_LATER(ah))
+ AR_SREV_9280_20_OR_LATER(ah))
return;
/*
* Disable BB clock gating
@@ -701,7 +699,7 @@ static void ar5008_hw_set_channel_regs(struct ath_hw *ah,
u32 phymode;
u32 enableDacFifo = 0;
- if (AR_SREV_9285_10_OR_LATER(ah))
+ if (AR_SREV_9285_12_OR_LATER(ah))
enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) &
AR_PHY_FC_ENABLE_DAC_FIFO);
@@ -726,7 +724,6 @@ static void ar5008_hw_set_channel_regs(struct ath_hw *ah,
REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
}
@@ -818,13 +815,12 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
}
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
- if (AR_SREV_9280(ah) || AR_SREV_9287_10_OR_LATER(ah))
+ if (AR_SREV_9280(ah) || AR_SREV_9287_11_OR_LATER(ah))
REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites);
if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah) ||
- AR_SREV_9287_10_OR_LATER(ah))
+ AR_SREV_9287_11_OR_LATER(ah))
REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
if (AR_SREV_9271_10(ah))
@@ -849,7 +845,6 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
}
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
if (AR_SREV_9271(ah)) {
if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == 1)
@@ -900,7 +895,7 @@ static void ar5008_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan)
rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
- if (!AR_SREV_9280_10_OR_LATER(ah))
+ if (!AR_SREV_9280_20_OR_LATER(ah))
rfMode |= (IS_CHAN_5GHZ(chan)) ?
AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ;
@@ -1053,7 +1048,7 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah,
enum ath9k_ani_cmd cmd,
int param)
{
- struct ar5416AniState *aniState = ah->curani;
+ struct ar5416AniState *aniState = &ah->curchan->ani;
struct ath_common *common = ath9k_hw_common(ah);
switch (cmd & ah->ani_function) {
@@ -1225,8 +1220,7 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah,
aniState->firstepLevel,
aniState->listenTime);
ath_print(common, ATH_DBG_ANI,
- "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
- aniState->cycleCount,
+ "ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
aniState->ofdmPhyErrCount,
aniState->cckPhyErrCount);
@@ -1237,9 +1231,9 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
enum ath9k_ani_cmd cmd,
int param)
{
- struct ar5416AniState *aniState = ah->curani;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan;
+ struct ar5416AniState *aniState = &chan->ani;
s32 value, value2;
switch (cmd & ah->ani_function) {
@@ -1478,15 +1472,13 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
ath_print(common, ATH_DBG_ANI,
"ANI parameters: SI=%d, ofdmWS=%s FS=%d "
- "MRCcck=%s listenTime=%d CC=%d listen=%d "
+ "MRCcck=%s listenTime=%d "
"ofdmErrs=%d cckErrs=%d\n",
aniState->spurImmunityLevel,
!aniState->ofdmWeakSigDetectOff ? "on" : "off",
aniState->firstepLevel,
!aniState->mrcCCKOff ? "on" : "off",
aniState->listenTime,
- aniState->cycleCount,
- aniState->listenTime,
aniState->ofdmPhyErrCount,
aniState->cckPhyErrCount);
return true;
@@ -1526,16 +1518,12 @@ static void ar5008_hw_do_getnf(struct ath_hw *ah,
*/
static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
{
- struct ar5416AniState *aniState;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan;
+ struct ar5416AniState *aniState = &chan->ani;
struct ath9k_ani_default *iniDef;
- int index;
u32 val;
- index = ath9k_hw_get_ani_channel_idx(ah, chan);
- aniState = &ah->ani[index];
- ah->curani = aniState;
iniDef = &aniState->iniDef;
ath_print(common, ATH_DBG_ANI,
@@ -1579,8 +1567,6 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
aniState->mrcCCKOff = true; /* not available on pre AR9003 */
-
- aniState->cycleCount = 0;
}
static void ar5008_hw_set_nf_limits(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index fe7418aefc4a..15f62cd0cc38 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -20,6 +20,13 @@
#define AR9285_CLCAL_REDO_THRESH 1
+enum ar9002_cal_types {
+ ADC_GAIN_CAL = BIT(0),
+ ADC_DC_CAL = BIT(1),
+ IQ_MISMATCH_CAL = BIT(2),
+};
+
+
static void ar9002_hw_setup_calibration(struct ath_hw *ah,
struct ath9k_cal_list *currCal)
{
@@ -45,13 +52,6 @@ static void ar9002_hw_setup_calibration(struct ath_hw *ah,
ath_print(common, ATH_DBG_CALIBRATE,
"starting ADC DC Calibration\n");
break;
- case ADC_DC_INIT_CAL:
- REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
- ath_print(common, ATH_DBG_CALIBRATE,
- "starting Init ADC DC Calibration\n");
- break;
- case TEMP_COMP_CAL:
- break; /* Not supported */
}
REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
@@ -96,25 +96,6 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah,
return iscaldone;
}
-/* Assumes you are talking about the currently configured channel */
-static bool ar9002_hw_iscal_supported(struct ath_hw *ah,
- enum ath9k_cal_types calType)
-{
- struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
-
- switch (calType & ah->supp_cals) {
- case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */
- return true;
- case ADC_GAIN_CAL:
- case ADC_DC_CAL:
- if (!(conf->channel->band == IEEE80211_BAND_2GHZ &&
- conf_is_ht20(conf)))
- return true;
- break;
- }
- return false;
-}
-
static void ar9002_hw_iqcal_collect(struct ath_hw *ah)
{
int i;
@@ -541,7 +522,6 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset)
REG_WRITE(ah, regList[i][0], regList[i][1]);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
}
static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset)
@@ -567,11 +547,6 @@ static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset)
AR5416_EEP_TXGAIN_HIGH_POWER)
return;
- if (AR_SREV_9285_11(ah)) {
- REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
- udelay(10);
- }
-
for (i = 0; i < ARRAY_SIZE(regList); i++)
regList[i][1] = REG_READ(ah, regList[i][0]);
@@ -651,10 +626,6 @@ static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset)
REG_WRITE(ah, regList[i][0], regList[i][1]);
REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org);
-
- if (AR_SREV_9285_11(ah))
- REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
-
}
static void ar9002_hw_pa_cal(struct ath_hw *ah, bool is_reset)
@@ -664,7 +635,7 @@ static void ar9002_hw_pa_cal(struct ath_hw *ah, bool is_reset)
ar9271_hw_pa_cal(ah, is_reset);
else
ah->pacal_info.skipcount--;
- } else if (AR_SREV_9285_11_OR_LATER(ah)) {
+ } else if (AR_SREV_9285_12_OR_LATER(ah)) {
if (is_reset || !ah->pacal_info.skipcount)
ar9285_hw_pa_cal(ah, is_reset);
else
@@ -841,8 +812,8 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
if (!ar9285_hw_clc(ah, chan))
return false;
} else {
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- if (!AR_SREV_9287_10_OR_LATER(ah))
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
+ if (!AR_SREV_9287_11_OR_LATER(ah))
REG_CLR_BIT(ah, AR_PHY_ADC_CTL,
AR_PHY_ADC_CTL_OFF_PWDADC);
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
@@ -864,8 +835,8 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
return false;
}
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- if (!AR_SREV_9287_10_OR_LATER(ah))
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
+ if (!AR_SREV_9287_11_OR_LATER(ah))
REG_SET_BIT(ah, AR_PHY_ADC_CTL,
AR_PHY_ADC_CTL_OFF_PWDADC);
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
@@ -886,24 +857,28 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
/* Enable IQ, ADC Gain and ADC DC offset CALs */
if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
- if (ar9002_hw_iscal_supported(ah, ADC_GAIN_CAL)) {
+ ah->supp_cals = IQ_MISMATCH_CAL;
+
+ if (AR_SREV_9160_10_OR_LATER(ah) &&
+ !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) {
+ ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL;
+
+
INIT_CAL(&ah->adcgain_caldata);
INSERT_CAL(ah, &ah->adcgain_caldata);
ath_print(common, ATH_DBG_CALIBRATE,
"enabling ADC Gain Calibration.\n");
- }
- if (ar9002_hw_iscal_supported(ah, ADC_DC_CAL)) {
+
INIT_CAL(&ah->adcdc_caldata);
INSERT_CAL(ah, &ah->adcdc_caldata);
ath_print(common, ATH_DBG_CALIBRATE,
"enabling ADC DC Calibration.\n");
}
- if (ar9002_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
- INIT_CAL(&ah->iq_caldata);
- INSERT_CAL(ah, &ah->iq_caldata);
- ath_print(common, ATH_DBG_CALIBRATE,
- "enabling IQ Calibration.\n");
- }
+
+ INIT_CAL(&ah->iq_caldata);
+ INSERT_CAL(ah, &ah->iq_caldata);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "enabling IQ Calibration.\n");
ah->cal_list_curr = ah->cal_list;
@@ -959,13 +934,6 @@ static const struct ath9k_percal_data adc_dc_cal_single_sample = {
ar9002_hw_adc_dccal_collect,
ar9002_hw_adc_dccal_calibrate
};
-static const struct ath9k_percal_data adc_init_dc_cal = {
- ADC_DC_INIT_CAL,
- MIN_CAL_SAMPLES,
- INIT_LOG_COUNT,
- ar9002_hw_adc_dccal_collect,
- ar9002_hw_adc_dccal_calibrate
-};
static void ar9002_hw_init_cal_settings(struct ath_hw *ah)
{
@@ -976,22 +944,18 @@ static void ar9002_hw_init_cal_settings(struct ath_hw *ah)
}
if (AR_SREV_9160_10_OR_LATER(ah)) {
- if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
ah->iq_caldata.calData = &iq_cal_single_sample;
ah->adcgain_caldata.calData =
&adc_gain_cal_single_sample;
ah->adcdc_caldata.calData =
&adc_dc_cal_single_sample;
- ah->adcdc_calinitdata.calData =
- &adc_init_dc_cal;
} else {
ah->iq_caldata.calData = &iq_cal_multi_sample;
ah->adcgain_caldata.calData =
&adc_gain_cal_multi_sample;
ah->adcdc_caldata.calData =
&adc_dc_cal_multi_sample;
- ah->adcdc_calinitdata.calData =
- &adc_init_dc_cal;
}
ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
}
@@ -1005,7 +969,6 @@ void ar9002_hw_attach_calib_ops(struct ath_hw *ah)
priv_ops->init_cal_settings = ar9002_hw_init_cal_settings;
priv_ops->init_cal = ar9002_hw_init_cal;
priv_ops->setup_calibration = ar9002_hw_setup_calibration;
- priv_ops->iscal_supported = ar9002_hw_iscal_supported;
ops->calibrate = ar9002_hw_calibrate;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index 303c63da5ea3..a0471f2e1c7a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -371,7 +371,6 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
}
udelay(1000);
@@ -468,7 +467,6 @@ static int ar9002_hw_get_radiorev(struct ath_hw *ah)
REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
@@ -569,14 +567,57 @@ void ar9002_hw_attach_ops(struct ath_hw *ah)
ops->config_pci_powersave = ar9002_hw_configpcipowersave;
ar5008_hw_attach_phy_ops(ah);
- if (AR_SREV_9280_10_OR_LATER(ah))
+ if (AR_SREV_9280_20_OR_LATER(ah))
ar9002_hw_attach_phy_ops(ah);
ar9002_hw_attach_calib_ops(ah);
ar9002_hw_attach_mac_ops(ah);
+}
+
+void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+ u32 modesIndex;
+ int i;
+
+ 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;
+ }
+
+ ENABLE_REGWRITE_BUFFER(ah);
- if (modparam_force_new_ani)
- ath9k_hw_attach_ani_ops_new(ah);
- else
- ath9k_hw_attach_ani_ops_old(ah);
+ for (i = 0; i < ah->iniModes_9271_ANI_reg.ia_rows; i++) {
+ u32 reg = INI_RA(&ah->iniModes_9271_ANI_reg, i, 0);
+ u32 val = INI_RA(&ah->iniModes_9271_ANI_reg, i, modesIndex);
+ u32 val_orig;
+
+ if (reg == AR_PHY_CCK_DETECT) {
+ val_orig = REG_READ(ah, reg);
+ val &= AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK;
+ val_orig &= ~AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK;
+
+ REG_WRITE(ah, reg, val|val_orig);
+ } else
+ REG_WRITE(ah, reg, val);
+ }
+
+ REGWRITE_BUFFER_FLUSH(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index adbf031fbc5a..c00cdc67b55b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -415,7 +415,6 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
}
static void ar9002_olc_init(struct ath_hw *ah)
@@ -530,3 +529,38 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
ar9002_hw_set_nf_limits(ah);
}
+
+void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf)
+{
+ u32 regval;
+
+ regval = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
+ antconf->main_lna_conf = (regval & AR_PHY_9285_ANT_DIV_MAIN_LNACONF) >>
+ AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S;
+ antconf->alt_lna_conf = (regval & AR_PHY_9285_ANT_DIV_ALT_LNACONF) >>
+ AR_PHY_9285_ANT_DIV_ALT_LNACONF_S;
+ antconf->fast_div_bias = (regval & AR_PHY_9285_FAST_DIV_BIAS) >>
+ AR_PHY_9285_FAST_DIV_BIAS_S;
+}
+EXPORT_SYMBOL(ath9k_hw_antdiv_comb_conf_get);
+
+void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf)
+{
+ u32 regval;
+
+ regval = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
+ regval &= ~(AR_PHY_9285_ANT_DIV_MAIN_LNACONF |
+ AR_PHY_9285_ANT_DIV_ALT_LNACONF |
+ AR_PHY_9285_FAST_DIV_BIAS);
+ regval |= ((antconf->main_lna_conf << AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S)
+ & AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
+ regval |= ((antconf->alt_lna_conf << AR_PHY_9285_ANT_DIV_ALT_LNACONF_S)
+ & AR_PHY_9285_ANT_DIV_ALT_LNACONF);
+ regval |= ((antconf->fast_div_bias << AR_PHY_9285_FAST_DIV_BIAS_S)
+ & AR_PHY_9285_FAST_DIV_BIAS);
+
+ REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
+}
+EXPORT_SYMBOL(ath9k_hw_antdiv_comb_conf_set);
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
index c5151a4dd10b..37663dbbcf57 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
@@ -302,6 +302,8 @@
#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000
#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac
+#define AR_PHY_9285_FAST_DIV_BIAS 0x00007E00
+#define AR_PHY_9285_FAST_DIV_BIAS_S 9
#define AR_PHY_9285_ANT_DIV_CTL_ALL 0x7f000000
#define AR_PHY_9285_ANT_DIV_CTL 0x01000000
#define AR_PHY_9285_ANT_DIV_CTL_S 24
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h
deleted file mode 100644
index d3375fc4ce8b..000000000000
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h
+++ /dev/null
@@ -1,1784 +0,0 @@
-/*
- * Copyright (c) 2010 Atheros Communications Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef INITVALS_9003_2P0_H
-#define INITVALS_9003_2P0_H
-
-/* AR9003 2.0 */
-
-static const u32 ar9300_2p0_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 ar9300Modes_lowest_ob_db_tx_gain_table_2p0[][5] = {
- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {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},
- {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, 0x21820220, 0x21820220, 0x16800402, 0x16800402},
- {0x0000a59c, 0x27820223, 0x27820223, 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, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83},
- {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84},
- {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3},
- {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5},
- {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9},
- {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb},
- {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
- {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
- {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
- {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
- {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
- {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
- {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
- {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 ar9300Modes_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, 0x03721821, 0x03721821},
- {0x0000a230, 0x0000000b, 0x00000016},
- {0x0000a254, 0x00000898, 0x00001130},
-};
-
-static const u32 ar9300_2p0_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, 0x40000004},
- {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 ar9300Common_rx_gain_table_merlin_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 ar9300_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 ar9300_2p0_soc_postamble[][5] = {
- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023},
-};
-
-static const u32 ar9200_merlin_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 ar9300_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, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044},
- {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
- {0x00009e04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
- {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
- {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
- {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
- {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
- {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
- {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
- {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
- {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
- {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
- {0x0000a204, 0x000037c0, 0x000037c4, 0x000037c4, 0x000037c0},
- {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
- {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
- {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, 0x00071981, 0x00071981, 0x00071981, 0x00071982},
- {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
- {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
- {0x0000ae04, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
- {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, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
- {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
- {0x0000be20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
- {0x0000c284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
-};
-
-static const u32 ar9300_2p0_baseband_core[][2] = {
- /* Addr allmodes */
- {0x00009800, 0xafe68e30},
- {0x00009804, 0xfd14e000},
- {0x00009808, 0x9c0a9f6b},
- {0x0000980c, 0x04900000},
- {0x00009814, 0x9280c00a},
- {0x00009818, 0x00000000},
- {0x0000981c, 0x00020028},
- {0x00009834, 0x5f3ca3de},
- {0x00009838, 0x0108ecff},
- {0x0000983c, 0x14750600},
- {0x00009880, 0x201fff00},
- {0x00009884, 0x00001042},
- {0x000098a4, 0x00200400},
- {0x000098b0, 0x52440bbe},
- {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},
- {0x00009e3c, 0xcf946222},
- {0x00009e40, 0x0d261820},
- {0x00009e4c, 0x00001004},
- {0x00009e50, 0x00ff03f1},
- {0x00009e54, 0x00000000},
- {0x00009fc0, 0x803e4788},
- {0x00009fc4, 0x0001efb5},
- {0x00009fcc, 0x40000014},
- {0x00009fd0, 0x01193b93},
- {0x0000a20c, 0x00000000},
- {0x0000a220, 0x00000000},
- {0x0000a224, 0x00000000},
- {0x0000a228, 0x10002310},
- {0x0000a22c, 0x01036a1e},
- {0x0000a234, 0x10000fff},
- {0x0000a23c, 0x00000000},
- {0x0000a244, 0x0c000000},
- {0x0000a2a0, 0x00000001},
- {0x0000a2c0, 0x00000001},
- {0x0000a2c8, 0x00000000},
- {0x0000a2cc, 0x18c43433},
- {0x0000a2d4, 0x00000000},
- {0x0000a2dc, 0x00000000},
- {0x0000a2e0, 0x00000000},
- {0x0000a2e4, 0x00000000},
- {0x0000a2e8, 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, 0x00000246},
- {0x0000a3f8, 0x0cdbd380},
- {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, 0x00000000},
- {0x0000a440, 0x00000000},
- {0x0000a444, 0x00000000},
- {0x0000a448, 0x04000080},
- {0x0000a44c, 0x00000001},
- {0x0000a450, 0x00010000},
- {0x0000a458, 0x00000000},
- {0x0000a600, 0x00000000},
- {0x0000a604, 0x00000000},
- {0x0000a608, 0x00000000},
- {0x0000a60c, 0x00000000},
- {0x0000a610, 0x00000000},
- {0x0000a614, 0x00000000},
- {0x0000a618, 0x00000000},
- {0x0000a61c, 0x00000000},
- {0x0000a620, 0x00000000},
- {0x0000a624, 0x00000000},
- {0x0000a628, 0x00000000},
- {0x0000a62c, 0x00000000},
- {0x0000a630, 0x00000000},
- {0x0000a634, 0x00000000},
- {0x0000a638, 0x00000000},
- {0x0000a63c, 0x00000000},
- {0x0000a640, 0x00000000},
- {0x0000a644, 0x3fad9d74},
- {0x0000a648, 0x0048060a},
- {0x0000a64c, 0x00000637},
- {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, 0x00000001},
- {0x0000a8d0, 0x004b6a8e},
- {0x0000a8d4, 0x00000820},
- {0x0000a8dc, 0x00000000},
- {0x0000a8f0, 0x00000000},
- {0x0000a8f4, 0x00000000},
- {0x0000b2d0, 0x00000080},
- {0x0000b2d4, 0x00000000},
- {0x0000b2dc, 0x00000000},
- {0x0000b2e0, 0x00000000},
- {0x0000b2e4, 0x00000000},
- {0x0000b2e8, 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},
- {0x0000c2dc, 0x00000000},
- {0x0000c2e0, 0x00000000},
- {0x0000c2e4, 0x00000000},
- {0x0000c2e8, 0x00000000},
- {0x0000c2ec, 0x00000000},
- {0x0000c2f0, 0x00000000},
- {0x0000c2f4, 0x00000000},
- {0x0000c2f8, 0x00000000},
- {0x0000c408, 0x0e79e5c0},
- {0x0000c40c, 0x00820820},
- {0x0000c420, 0x00000000},
-};
-
-static const u32 ar9300Modes_high_power_tx_gain_table_2p0[][5] = {
- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {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, 0x59025eb5, 0x59025eb5, 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},
- {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},
-};
-
-static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p0[][5] = {
- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {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, 0x59025eb5, 0x59025eb5, 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},
- {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 ar9300Common_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, 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 ar9300Modes_low_ob_db_tx_gain_table_2p0[][5] = {
- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {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},
- {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, 0x21820220, 0x21820220, 0x16800402, 0x16800402},
- {0x0000a59c, 0x27820223, 0x27820223, 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, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83},
- {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84},
- {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3},
- {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5},
- {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9},
- {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb},
- {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
- {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
- {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
- {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
- {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
- {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
- {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
- {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
- {0x00016048, 0x64000001, 0x64000001, 0x64000001, 0x64000001},
- {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
- {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
- {0x00016448, 0x64000001, 0x64000001, 0x64000001, 0x64000001},
- {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
- {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
- {0x00016848, 0x64000001, 0x64000001, 0x64000001, 0x64000001},
- {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
-};
-
-static const u32 ar9300_2p0_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, 0x13881c20},
- {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},
- {0x00008170, 0x18486200},
- {0x00008174, 0x33332210},
- {0x00008178, 0x00000000},
- {0x0000817c, 0x00020000},
- {0x000081c0, 0x00000000},
- {0x000081c4, 0x33332210},
- {0x000081c8, 0x00000000},
- {0x000081cc, 0x00000000},
- {0x000081d4, 0x00000000},
- {0x000081ec, 0x00000000},
- {0x000081f0, 0x00000000},
- {0x000081f4, 0x00000000},
- {0x000081f8, 0x00000000},
- {0x000081fc, 0x00000000},
- {0x00008240, 0x00100000},
- {0x00008244, 0x0010f424},
- {0x00008248, 0x00000800},
- {0x0000824c, 0x0001e848},
- {0x00008250, 0x00000000},
- {0x00008254, 0x00000000},
- {0x00008258, 0x00000000},
- {0x0000825c, 0x40000000},
- {0x00008260, 0x00080922},
- {0x00008264, 0x98a00010},
- {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 ar9300Common_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 ar9300_2p0_soc_preamble[][2] = {
- /* Addr allmodes */
- {0x000040a4, 0x00a0c1c9},
- {0x00007008, 0x00000000},
- {0x00007020, 0x00000000},
- {0x00007034, 0x00000002},
- {0x00007038, 0x000004c2},
-};
-
-static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p0[][2] = {
- /* Addr allmodes */
- {0x00004040, 0x08212e5e},
- {0x00004040, 0x0008003b},
- {0x00004044, 0x00000000},
-};
-
-static const u32 ar9300PciePhy_clkreq_enable_L1_2p0[][2] = {
- /* Addr allmodes */
- {0x00004040, 0x08253e5e},
- {0x00004040, 0x0008003b},
- {0x00004044, 0x00000000},
-};
-
-static const u32 ar9300PciePhy_clkreq_disable_L1_2p0[][2] = {
- /* Addr allmodes */
- {0x00004040, 0x08213e5e},
- {0x00004040, 0x0008003b},
- {0x00004044, 0x00000000},
-};
-
-#endif /* INITVALS_9003_2P0_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index ec98ab50748a..a14a5e43cf56 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -34,6 +34,10 @@ static const u32 ar9300_2p2_radio_postamble[][5] = {
static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
+ {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
+ {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
@@ -99,6 +103,30 @@ static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
{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, 0x00637800, 0x00637800},
+ {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
+ {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
+ {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
+ {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@@ -118,7 +146,7 @@ static const u32 ar9300Modes_fast_clock_2p2[][3] = {
{0x00008014, 0x044c044c, 0x08980898},
{0x0000801c, 0x148ec02b, 0x148ec057},
{0x00008318, 0x000044c0, 0x00008980},
- {0x00009e00, 0x03721821, 0x03721821},
+ {0x00009e00, 0x0372131c, 0x0372131c},
{0x0000a230, 0x0000000b, 0x00000016},
{0x0000a254, 0x00000898, 0x00001130},
};
@@ -595,15 +623,16 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = {
{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
{0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
{0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
- {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
- {0x00009e04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
+ {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
+ {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
- {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
+ {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},
@@ -624,16 +653,16 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = {
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
{0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982},
- {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
+ {0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a},
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
- {0x0000ae04, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {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, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {0x0000be04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000},
{0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
{0x0000be20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
@@ -649,13 +678,13 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
{0x00009814, 0x9280c00a},
{0x00009818, 0x00000000},
{0x0000981c, 0x00020028},
- {0x00009834, 0x5f3ca3de},
+ {0x00009834, 0x6400a290},
{0x00009838, 0x0108ecff},
{0x0000983c, 0x14750600},
{0x00009880, 0x201fff00},
{0x00009884, 0x00001042},
{0x000098a4, 0x00200400},
- {0x000098b0, 0x52440bbe},
+ {0x000098b0, 0x32840bbe},
{0x000098d0, 0x004b6a8e},
{0x000098d4, 0x00000820},
{0x000098dc, 0x00000000},
@@ -681,7 +710,6 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
{0x00009e30, 0x06336f77},
{0x00009e34, 0x6af6532f},
{0x00009e38, 0x0cc80c00},
- {0x00009e3c, 0xcf946222},
{0x00009e40, 0x0d261820},
{0x00009e4c, 0x00001004},
{0x00009e50, 0x00ff03f1},
@@ -694,7 +722,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
{0x0000a220, 0x00000000},
{0x0000a224, 0x00000000},
{0x0000a228, 0x10002310},
- {0x0000a22c, 0x01036a1e},
+ {0x0000a22c, 0x01036a27},
{0x0000a23c, 0x00000000},
{0x0000a244, 0x0c000000},
{0x0000a2a0, 0x00000001},
@@ -702,10 +730,6 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
{0x0000a2c8, 0x00000000},
{0x0000a2cc, 0x18c43433},
{0x0000a2d4, 0x00000000},
- {0x0000a2dc, 0x00000000},
- {0x0000a2e0, 0x00000000},
- {0x0000a2e4, 0x00000000},
- {0x0000a2e8, 0x00000000},
{0x0000a2ec, 0x00000000},
{0x0000a2f0, 0x00000000},
{0x0000a2f4, 0x00000000},
@@ -753,33 +777,17 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
{0x0000a430, 0x1ce739ce},
{0x0000a434, 0x00000000},
{0x0000a438, 0x00001801},
- {0x0000a43c, 0x00000000},
+ {0x0000a43c, 0x00100000},
{0x0000a440, 0x00000000},
{0x0000a444, 0x00000000},
{0x0000a448, 0x06000080},
{0x0000a44c, 0x00000001},
{0x0000a450, 0x00010000},
{0x0000a458, 0x00000000},
- {0x0000a600, 0x00000000},
- {0x0000a604, 0x00000000},
- {0x0000a608, 0x00000000},
- {0x0000a60c, 0x00000000},
- {0x0000a610, 0x00000000},
- {0x0000a614, 0x00000000},
- {0x0000a618, 0x00000000},
- {0x0000a61c, 0x00000000},
- {0x0000a620, 0x00000000},
- {0x0000a624, 0x00000000},
- {0x0000a628, 0x00000000},
- {0x0000a62c, 0x00000000},
- {0x0000a630, 0x00000000},
- {0x0000a634, 0x00000000},
- {0x0000a638, 0x00000000},
- {0x0000a63c, 0x00000000},
{0x0000a640, 0x00000000},
{0x0000a644, 0x3fad9d74},
{0x0000a648, 0x0048060a},
- {0x0000a64c, 0x00000637},
+ {0x0000a64c, 0x00003c37},
{0x0000a670, 0x03020100},
{0x0000a674, 0x09080504},
{0x0000a678, 0x0d0c0b0a},
@@ -802,10 +810,6 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
{0x0000a8f4, 0x00000000},
{0x0000b2d0, 0x00000080},
{0x0000b2d4, 0x00000000},
- {0x0000b2dc, 0x00000000},
- {0x0000b2e0, 0x00000000},
- {0x0000b2e4, 0x00000000},
- {0x0000b2e8, 0x00000000},
{0x0000b2ec, 0x00000000},
{0x0000b2f0, 0x00000000},
{0x0000b2f4, 0x00000000},
@@ -820,10 +824,6 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
{0x0000b8f4, 0x00000000},
{0x0000c2d0, 0x00000080},
{0x0000c2d4, 0x00000000},
- {0x0000c2dc, 0x00000000},
- {0x0000c2e0, 0x00000000},
- {0x0000c2e4, 0x00000000},
- {0x0000c2e8, 0x00000000},
{0x0000c2ec, 0x00000000},
{0x0000c2f0, 0x00000000},
{0x0000c2f4, 0x00000000},
@@ -835,6 +835,10 @@ 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, 0x00637800, 0x00637800},
+ {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
+ {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
@@ -855,7 +859,7 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
- {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
+ {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
@@ -900,6 +904,30 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
{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, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
+ {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
+ {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
+ {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
+ {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
{0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
{0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
@@ -913,6 +941,10 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800},
+ {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000},
+ {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
@@ -933,7 +965,7 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
- {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
+ {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
@@ -978,6 +1010,30 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
{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, 0x00637800, 0x00637800},
+ {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000},
+ {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000c2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800},
+ {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000},
+ {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
{0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@@ -1151,14 +1207,14 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
{0x0000b074, 0x00000000},
{0x0000b078, 0x00000000},
{0x0000b07c, 0x00000000},
- {0x0000b080, 0x32323232},
- {0x0000b084, 0x2f2f3232},
- {0x0000b088, 0x23282a2d},
- {0x0000b08c, 0x1c1e2123},
- {0x0000b090, 0x14171919},
- {0x0000b094, 0x0e0e1214},
- {0x0000b098, 0x03050707},
- {0x0000b09c, 0x00030303},
+ {0x0000b080, 0x2a2d2f32},
+ {0x0000b084, 0x21232328},
+ {0x0000b088, 0x19191c1e},
+ {0x0000b08c, 0x12141417},
+ {0x0000b090, 0x07070e0e},
+ {0x0000b094, 0x03030305},
+ {0x0000b098, 0x00000003},
+ {0x0000b09c, 0x00000000},
{0x0000b0a0, 0x00000000},
{0x0000b0a4, 0x00000000},
{0x0000b0a8, 0x00000000},
@@ -1251,6 +1307,10 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
+ {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
+ {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
@@ -1316,6 +1376,30 @@ static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
{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, 0x00637800, 0x00637800},
+ {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
+ {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
+ {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
+ {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@@ -1414,15 +1498,10 @@ static const u32 ar9300_2p2_mac_core[][2] = {
{0x00008144, 0xffffffff},
{0x00008168, 0x00000000},
{0x0000816c, 0x00000000},
- {0x00008170, 0x18486200},
- {0x00008174, 0x33332210},
- {0x00008178, 0x00000000},
- {0x0000817c, 0x00020000},
{0x000081c0, 0x00000000},
{0x000081c4, 0x33332210},
{0x000081c8, 0x00000000},
{0x000081cc, 0x00000000},
- {0x000081d4, 0x00000000},
{0x000081ec, 0x00000000},
{0x000081f0, 0x00000000},
{0x000081f4, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 4674ea8c9c99..9e6edffe0bd1 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -18,6 +18,11 @@
#include "hw-ops.h"
#include "ar9003_phy.h"
+enum ar9003_cal_types {
+ IQ_MISMATCH_CAL = BIT(0),
+ TEMP_COMP_CAL = BIT(1),
+};
+
static void ar9003_hw_setup_calibration(struct ath_hw *ah,
struct ath9k_cal_list *currCal)
{
@@ -50,11 +55,6 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah,
ath_print(common, ATH_DBG_CALIBRATE,
"starting Temperature Compensation Calibration\n");
break;
- case ADC_DC_INIT_CAL:
- case ADC_GAIN_CAL:
- case ADC_DC_CAL:
- /* Not yet */
- break;
}
}
@@ -314,27 +314,6 @@ static const struct ath9k_percal_data iq_cal_single_sample = {
static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
{
ah->iq_caldata.calData = &iq_cal_single_sample;
- ah->supp_cals = IQ_MISMATCH_CAL;
-}
-
-static bool ar9003_hw_iscal_supported(struct ath_hw *ah,
- enum ath9k_cal_types calType)
-{
- switch (calType & ah->supp_cals) {
- case IQ_MISMATCH_CAL:
- /*
- * XXX: Run IQ Mismatch for non-CCK only
- * Note that CHANNEL_B is never set though.
- */
- return true;
- case ADC_GAIN_CAL:
- case ADC_DC_CAL:
- return false;
- case TEMP_COMP_CAL:
- return true;
- }
-
- return false;
}
/*
@@ -773,15 +752,16 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
/* Initialize list pointers */
ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
+ ah->supp_cals = IQ_MISMATCH_CAL;
- if (ar9003_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
+ if (ah->supp_cals & IQ_MISMATCH_CAL) {
INIT_CAL(&ah->iq_caldata);
INSERT_CAL(ah, &ah->iq_caldata);
ath_print(common, ATH_DBG_CALIBRATE,
"enabling IQ Calibration.\n");
}
- if (ar9003_hw_iscal_supported(ah, TEMP_COMP_CAL)) {
+ if (ah->supp_cals & TEMP_COMP_CAL) {
INIT_CAL(&ah->tempCompCalData);
INSERT_CAL(ah, &ah->tempCompCalData);
ath_print(common, ATH_DBG_CALIBRATE,
@@ -808,7 +788,6 @@ void ar9003_hw_attach_calib_ops(struct ath_hw *ah)
priv_ops->init_cal_settings = ar9003_hw_init_cal_settings;
priv_ops->init_cal = ar9003_hw_init_cal;
priv_ops->setup_calibration = ar9003_hw_setup_calibration;
- priv_ops->iscal_supported = ar9003_hw_iscal_supported;
ops->calibrate = ar9003_hw_calibrate;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 057fb69ddf7f..c4182359bee4 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -968,7 +968,7 @@ static int ath9k_hw_ar9300_get_eeprom_rev(struct ath_hw *ah)
}
static u8 ath9k_hw_ar9300_get_num_ant_config(struct ath_hw *ah,
- enum ieee80211_band freq_band)
+ enum ath9k_hal_freq_band freq_band)
{
return 1;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index 064168909108..c2a057156bfa 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -16,7 +16,6 @@
#include "hw.h"
#include "ar9003_mac.h"
-#include "ar9003_2p0_initvals.h"
#include "ar9003_2p2_initvals.h"
/* General hardware code for the AR9003 hadware family */
@@ -32,79 +31,12 @@ static bool ar9003_hw_macversion_supported(u32 macversion)
return false;
}
-/* AR9003 2.0 */
-static void ar9003_2p0_hw_init_mode_regs(struct ath_hw *ah)
-{
- /* mac */
- INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
- INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
- ar9300_2p0_mac_core,
- ARRAY_SIZE(ar9300_2p0_mac_core), 2);
- INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
- ar9300_2p0_mac_postamble,
- ARRAY_SIZE(ar9300_2p0_mac_postamble), 5);
-
- /* bb */
- INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
- INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
- ar9300_2p0_baseband_core,
- ARRAY_SIZE(ar9300_2p0_baseband_core), 2);
- INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
- ar9300_2p0_baseband_postamble,
- ARRAY_SIZE(ar9300_2p0_baseband_postamble), 5);
-
- /* radio */
- INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
- INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
- ar9300_2p0_radio_core,
- ARRAY_SIZE(ar9300_2p0_radio_core), 2);
- INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
- ar9300_2p0_radio_postamble,
- ARRAY_SIZE(ar9300_2p0_radio_postamble), 5);
-
- /* soc */
- INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
- ar9300_2p0_soc_preamble,
- ARRAY_SIZE(ar9300_2p0_soc_preamble), 2);
- INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
- INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
- ar9300_2p0_soc_postamble,
- ARRAY_SIZE(ar9300_2p0_soc_postamble), 5);
-
- /* rx/tx gain */
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9300Common_rx_gain_table_2p0,
- ARRAY_SIZE(ar9300Common_rx_gain_table_2p0), 2);
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_lowest_ob_db_tx_gain_table_2p0,
- ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p0),
- 5);
-
- /* Load PCIE SERDES settings from INI */
-
- /* Awake Setting */
-
- INIT_INI_ARRAY(&ah->iniPcieSerdes,
- ar9300PciePhy_pll_on_clkreq_disable_L1_2p0,
- ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p0),
- 2);
-
- /* Sleep Setting */
-
- INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
- ar9300PciePhy_clkreq_enable_L1_2p0,
- ARRAY_SIZE(ar9300PciePhy_clkreq_enable_L1_2p0),
- 2);
-
- /* Fast clock modal settings */
- INIT_INI_ARRAY(&ah->iniModesAdditional,
- ar9300Modes_fast_clock_2p0,
- ARRAY_SIZE(ar9300Modes_fast_clock_2p0),
- 3);
-}
-
-/* AR9003 2.2 */
-static void ar9003_2p2_hw_init_mode_regs(struct ath_hw *ah)
+/*
+ * The AR9003 family uses a new INI format (pre, core, post
+ * arrays per subsystem). This provides support for the
+ * AR9003 2.2 chipsets.
+ */
+static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
{
/* mac */
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
@@ -174,57 +106,27 @@ static void ar9003_2p2_hw_init_mode_regs(struct ath_hw *ah)
3);
}
-/*
- * The AR9003 family uses a new INI format (pre, core, post
- * arrays per subsystem).
- */
-static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
-{
- if (AR_SREV_9300_20(ah))
- ar9003_2p0_hw_init_mode_regs(ah);
- else
- ar9003_2p2_hw_init_mode_regs(ah);
-}
-
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_9300_20(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_lowest_ob_db_tx_gain_table_2p0,
- ARRAY_SIZE(ar9300Modes_lowest_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);
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
+ 5);
break;
case 1:
- if (AR_SREV_9300_20(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_high_ob_db_tx_gain_table_2p0,
- ARRAY_SIZE(ar9300Modes_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);
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_high_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2),
+ 5);
break;
case 2:
- if (AR_SREV_9300_20(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_low_ob_db_tx_gain_table_2p0,
- ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p0),
- 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);
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_low_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2),
+ 5);
break;
}
}
@@ -234,28 +136,16 @@ 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_9300_20(ah))
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9300Common_rx_gain_table_2p0,
- ARRAY_SIZE(ar9300Common_rx_gain_table_2p0),
- 2);
- else
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9300Common_rx_gain_table_2p2,
- ARRAY_SIZE(ar9300Common_rx_gain_table_2p2),
- 2);
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_rx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Common_rx_gain_table_2p2),
+ 2);
break;
case 1:
- if (AR_SREV_9300_20(ah))
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9300Common_wo_xlna_rx_gain_table_2p0,
- ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p0),
- 2);
- else
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9300Common_wo_xlna_rx_gain_table_2p2,
- ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2),
- 2);
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_wo_xlna_rx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2),
+ 2);
break;
}
}
@@ -333,6 +223,4 @@ void ar9003_hw_attach_ops(struct ath_hw *ah)
ar9003_hw_attach_phy_ops(ah);
ar9003_hw_attach_calib_ops(ah);
ar9003_hw_attach_mac_ops(ah);
-
- ath9k_hw_attach_ani_ops_new(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 5b995bee70ae..3b424ca1ba84 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -185,7 +185,7 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
ath_print(common, ATH_DBG_INTERRUPT,
"AR_INTR_SYNC_LOCAL_TIMEOUT\n");
- REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
+ REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
(void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
}
@@ -616,7 +616,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;
}
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
index 7c38229ba670..716db414c258 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
@@ -347,6 +347,10 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)
(((Y[6] - Y[3]) * 1 << scale_factor) +
(x_est[6] - x_est[3])) / (x_est[6] - x_est[3]);
+ /* prevent division by zero */
+ if (G_fxp == 0)
+ return false;
+
Y_intercept =
(G_fxp * (x_est[0] - x_est[3]) +
(1 << scale_factor)) / (1 << scale_factor) + Y[3];
@@ -356,14 +360,12 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)
for (i = 0; i <= 3; i++) {
y_est[i] = i * 32;
-
- /* prevent division by zero */
- if (G_fxp == 0)
- return false;
-
x_est[i] = ((y_est[i] * 1 << scale_factor) + G_fxp) / G_fxp;
}
+ if (y_est[max_index] == 0)
+ return false;
+
x_est_fxp1_nonlin =
x_est[max_index] - ((1 << scale_factor) * y_est[max_index] +
G_fxp) / G_fxp;
@@ -457,6 +459,8 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)
Q_scale_B = find_proper_scale(find_expn(abs(scale_B)), 10);
scale_B = scale_B / (1 << Q_scale_B);
+ if (scale_B == 0)
+ return false;
Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10);
Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10);
beta_raw = beta_raw / (1 << Q_beta);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index a491854fa38a..669b777729b3 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -747,9 +747,9 @@ static void ar9003_hw_set_diversity(struct ath_hw *ah, bool value)
static bool ar9003_hw_ani_control(struct ath_hw *ah,
enum ath9k_ani_cmd cmd, int param)
{
- struct ar5416AniState *aniState = ah->curani;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan;
+ struct ar5416AniState *aniState = &chan->ani;
s32 value, value2;
switch (cmd & ah->ani_function) {
@@ -1005,15 +1005,13 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
ath_print(common, ATH_DBG_ANI,
"ANI parameters: SI=%d, ofdmWS=%s FS=%d "
- "MRCcck=%s listenTime=%d CC=%d listen=%d "
+ "MRCcck=%s listenTime=%d "
"ofdmErrs=%d cckErrs=%d\n",
aniState->spurImmunityLevel,
!aniState->ofdmWeakSigDetectOff ? "on" : "off",
aniState->firstepLevel,
!aniState->mrcCCKOff ? "on" : "off",
aniState->listenTime,
- aniState->cycleCount,
- aniState->listenTime,
aniState->ofdmPhyErrCount,
aniState->cckPhyErrCount);
return true;
@@ -1067,12 +1065,9 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan;
struct ath9k_ani_default *iniDef;
- int index;
u32 val;
- index = ath9k_hw_get_ani_channel_idx(ah, chan);
- aniState = &ah->ani[index];
- ah->curani = aniState;
+ aniState = &ah->curchan->ani;
iniDef = &aniState->iniDef;
ath_print(common, ATH_DBG_ANI,
@@ -1116,8 +1111,6 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
aniState->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK;
-
- aniState->cycleCount = 0;
}
void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
@@ -1232,7 +1225,7 @@ void ar9003_hw_bb_watchdog_read(struct ath_hw *ah)
void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
- u32 rxc_pcnt = 0, rxf_pcnt = 0, txf_pcnt = 0, status;
+ u32 status;
if (likely(!(common->debug_mask & ATH_DBG_RESET)))
return;
@@ -1261,11 +1254,12 @@ void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah)
"** BB mode: BB_gen_controls=0x%08x **\n",
REG_READ(ah, AR_PHY_GEN_CTRL));
- if (ath9k_hw_GetMibCycleCountsPct(ah, &rxc_pcnt, &rxf_pcnt, &txf_pcnt))
+#define PCT(_field) (common->cc_survey._field * 100 / common->cc_survey.cycles)
+ if (common->cc_survey.cycles)
ath_print(common, ATH_DBG_RESET,
"** BB busy times: rx_clear=%d%%, "
"rx_frame=%d%%, tx_frame=%d%% **\n",
- rxc_pcnt, rxf_pcnt, txf_pcnt);
+ PCT(rx_busy), PCT(rx_frame), PCT(tx_frame));
ath_print(common, ATH_DBG_RESET,
"==== BB update: done ====\n\n");
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 07f26ee7a723..973c919fdd27 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -239,13 +239,11 @@ struct ath_buf {
struct sk_buff *bf_mpdu; /* enclosing frame structure */
void *bf_desc; /* virtual addr of desc */
dma_addr_t bf_daddr; /* physical addr of desc */
- dma_addr_t bf_buf_addr; /* physical addr of data buffer */
+ dma_addr_t bf_buf_addr; /* physical addr of data buffer, for DMA */
bool bf_stale;
- bool bf_isnullfunc;
bool bf_tx_aborted;
u16 bf_flags;
struct ath_buf_state bf_state;
- dma_addr_t bf_dmacontext;
struct ath_wiphy *aphy;
};
@@ -254,7 +252,7 @@ struct ath_atx_tid {
struct list_head buf_q;
struct ath_node *an;
struct ath_atx_ac *ac;
- struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
+ unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)];
u16 seq_start;
u16 seq_next;
u16 baw_size;
@@ -345,12 +343,10 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
void ath_tx_tasklet(struct ath_softc *sc);
void ath_tx_edma_tasklet(struct ath_softc *sc);
void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb);
-bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
-void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
- u16 tid, u16 *ssn);
+int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+ u16 tid, u16 *ssn);
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 ath9k_enable_ps(struct ath_softc *sc);
/********/
/* VIFs */
@@ -423,6 +419,7 @@ int ath_beaconq_config(struct ath_softc *sc);
#define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */
#define ATH_ANI_POLLINTERVAL_OLD 100 /* 100 ms */
#define ATH_ANI_POLLINTERVAL_NEW 1000 /* 1000 ms */
+#define ATH_LONG_CALINTERVAL_INT 1000 /* 1000 ms */
#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
@@ -436,14 +433,6 @@ void ath_ani_calibrate(unsigned long data);
/* BTCOEX */
/**********/
-/* Defines the BT AR_BT_COEX_WGHT used */
-enum ath_stomp_type {
- ATH_BTCOEX_NO_STOMP,
- ATH_BTCOEX_STOMP_ALL,
- ATH_BTCOEX_STOMP_LOW,
- ATH_BTCOEX_STOMP_NONE
-};
-
struct ath_btcoex {
bool hw_timer_enabled;
spinlock_t btcoex_lock;
@@ -488,6 +477,60 @@ struct ath_led {
void ath_init_leds(struct ath_softc *sc);
void ath_deinit_leds(struct ath_softc *sc);
+/* Antenna diversity/combining */
+#define ATH_ANT_RX_CURRENT_SHIFT 4
+#define ATH_ANT_RX_MAIN_SHIFT 2
+#define ATH_ANT_RX_MASK 0x3
+
+#define ATH_ANT_DIV_COMB_SHORT_SCAN_INTR 50
+#define ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT 0x100
+#define ATH_ANT_DIV_COMB_MAX_PKTCOUNT 0x200
+#define ATH_ANT_DIV_COMB_INIT_COUNT 95
+#define ATH_ANT_DIV_COMB_MAX_COUNT 100
+#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30
+#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20
+
+#define ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA -3
+#define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1
+#define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4
+#define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2
+#define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2
+
+enum ath9k_ant_div_comb_lna_conf {
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2,
+ ATH_ANT_DIV_COMB_LNA2,
+ ATH_ANT_DIV_COMB_LNA1,
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2,
+};
+
+struct ath_ant_comb {
+ u16 count;
+ u16 total_pkt_count;
+ bool scan;
+ bool scan_not_start;
+ int main_total_rssi;
+ int alt_total_rssi;
+ int alt_recv_cnt;
+ int main_recv_cnt;
+ int rssi_lna1;
+ int rssi_lna2;
+ int rssi_add;
+ int rssi_sub;
+ int rssi_first;
+ int rssi_second;
+ int rssi_third;
+ bool alt_good;
+ int quick_scan_cnt;
+ int main_conf;
+ enum ath9k_ant_div_comb_lna_conf first_quick_scan_conf;
+ enum ath9k_ant_div_comb_lna_conf second_quick_scan_conf;
+ int first_bias;
+ int second_bias;
+ bool first_ratio;
+ bool second_ratio;
+ unsigned long scan_start_time;
+};
+
/********************/
/* Main driver core */
/********************/
@@ -516,7 +559,6 @@ void ath_deinit_leds(struct ath_softc *sc);
#define SC_OP_RXFLUSH BIT(7)
#define SC_OP_LED_ASSOCIATED BIT(8)
#define SC_OP_LED_ON BIT(9)
-#define SC_OP_SCANNING BIT(10)
#define SC_OP_TSF_RESET BIT(11)
#define SC_OP_BT_PRIORITY_DETECTED BIT(12)
#define SC_OP_BT_SCAN BIT(13)
@@ -528,8 +570,6 @@ void ath_deinit_leds(struct ath_softc *sc);
#define PS_WAIT_FOR_PSPOLL_DATA BIT(2)
#define PS_WAIT_FOR_TX_ACK BIT(3)
#define PS_BEACON_SYNC BIT(4)
-#define PS_NULLFUNC_COMPLETED BIT(5)
-#define PS_ENABLED BIT(6)
struct ath_wiphy;
struct ath_rate_table;
@@ -552,6 +592,8 @@ struct ath_softc {
struct delayed_work wiphy_work;
unsigned long wiphy_scheduler_int;
int wiphy_scheduler_index;
+ struct survey_info *cur_survey;
+ struct survey_info survey[ATH9K_NUM_CHANNELS];
struct tasklet_struct intr_tq;
struct tasklet_struct bcon_tasklet;
@@ -580,8 +622,6 @@ struct ath_softc {
struct ath_rx rx;
struct ath_tx tx;
struct ath_beacon beacon;
- const struct ath_rate_table *cur_rate_table;
- enum wireless_mode cur_rate_mode;
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
struct ath_led radio_led;
@@ -604,6 +644,8 @@ struct ath_softc {
struct ath_btcoex btcoex;
struct ath_descdma txsdma;
+
+ struct ath_ant_comb ant_comb;
};
struct ath_wiphy {
@@ -670,7 +712,7 @@ static inline void ath_ahb_exit(void) {};
void ath9k_ps_wakeup(struct ath_softc *sc);
void ath9k_ps_restore(struct ath_softc *sc);
-void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
+void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int ath9k_wiphy_add(struct ath_softc *sc);
int ath9k_wiphy_del(struct ath_wiphy *aphy);
void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 4d4b22d52dfd..19891e7d49ae 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -136,9 +136,10 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
bf = avp->av_bcbuf;
skb = bf->bf_mpdu;
if (skb) {
- dma_unmap_single(sc->dev, bf->bf_dmacontext,
+ dma_unmap_single(sc->dev, bf->bf_buf_addr,
skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
+ bf->bf_buf_addr = 0;
}
/* Get a new beacon from mac80211 */
@@ -162,12 +163,12 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
}
- bf->bf_buf_addr = bf->bf_dmacontext =
- dma_map_single(sc->dev, skb->data,
- skb->len, DMA_TO_DEVICE);
+ bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
+ skb->len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
+ bf->bf_buf_addr = 0;
ath_print(common, ATH_DBG_FATAL,
"dma_mapping_error on beaconing\n");
return NULL;
@@ -252,10 +253,11 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
bf = avp->av_bcbuf;
if (bf->bf_mpdu != NULL) {
skb = bf->bf_mpdu;
- dma_unmap_single(sc->dev, bf->bf_dmacontext,
+ dma_unmap_single(sc->dev, bf->bf_buf_addr,
skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
+ bf->bf_buf_addr = 0;
}
/* NB: the beacon data buffer must be 32-bit aligned. */
@@ -296,12 +298,12 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
avp->tsf_adjust = cpu_to_le64(0);
bf->bf_mpdu = skb;
- bf->bf_buf_addr = bf->bf_dmacontext =
- dma_map_single(sc->dev, skb->data,
- skb->len, DMA_TO_DEVICE);
+ bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
+ skb->len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
+ bf->bf_buf_addr = 0;
ath_print(common, ATH_DBG_FATAL,
"dma_mapping_error on beacon alloc\n");
return -ENOMEM;
@@ -324,10 +326,11 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
bf = avp->av_bcbuf;
if (bf->bf_mpdu != NULL) {
struct sk_buff *skb = bf->bf_mpdu;
- dma_unmap_single(sc->dev, bf->bf_dmacontext,
+ dma_unmap_single(sc->dev, bf->bf_buf_addr,
skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
+ bf->bf_buf_addr = 0;
}
list_add_tail(&bf->list, &sc->beacon.bbuf);
@@ -359,21 +362,22 @@ void ath_beacon_tasklet(unsigned long data)
sc->beacon.bmisscnt++;
if (sc->beacon.bmisscnt < BSTUCK_THRESH) {
- ath_print(common, ATH_DBG_BEACON,
+ ath_print(common, ATH_DBG_BSTUCK,
"missed %u consecutive beacons\n",
sc->beacon.bmisscnt);
+ ath9k_hw_bstuck_nfcal(ah);
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
- ath_print(common, ATH_DBG_BEACON,
+ ath_print(common, ATH_DBG_BSTUCK,
"beacon is officially stuck\n");
sc->sc_flags |= SC_OP_TSF_RESET;
- ath_reset(sc, false);
+ ath_reset(sc, true);
}
return;
}
if (sc->beacon.bmisscnt != 0) {
- ath_print(common, ATH_DBG_BEACON,
+ ath_print(common, ATH_DBG_BSTUCK,
"resume beacon xmit after %u misses\n",
sc->beacon.bmisscnt);
sc->beacon.bmisscnt = 0;
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
index fb4ac15f3b93..6a92e57fddf0 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.c
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -168,6 +168,7 @@ EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight);
static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
{
struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
+ u32 val;
/*
* Program coex mode and weight registers to
@@ -177,6 +178,12 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights);
REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2);
+ if (AR_SREV_9271(ah)) {
+ val = REG_READ(ah, 0x50040);
+ val &= 0xFFFFFEFF;
+ REG_WRITE(ah, 0x50040, val);
+ }
+
REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 45208690c0ec..6d509484b5f6 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -19,8 +19,7 @@
/* Common calibration code */
-/* We can tune this as we go by monitoring really low values */
-#define ATH9K_NF_TOO_LOW -60
+#define ATH9K_NF_TOO_HIGH -60
static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
{
@@ -45,11 +44,39 @@ static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
return nfval;
}
-static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
+static struct ath_nf_limits *ath9k_hw_get_nf_limits(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ struct ath_nf_limits *limit;
+
+ if (!chan || IS_CHAN_2GHZ(chan))
+ limit = &ah->nf_2g;
+ else
+ limit = &ah->nf_5g;
+
+ return limit;
+}
+
+static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ return ath9k_hw_get_nf_limits(ah, chan)->nominal;
+}
+
+
+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 ath_nf_limits *limit;
+ struct ath9k_nfcal_hist *h;
+ bool high_nf_mid = false;
int i;
+ h = cal->nfCalHist;
+ limit = ath9k_hw_get_nf_limits(ah, ah->curchan);
+
for (i = 0; i < NUM_NF_READINGS; i++) {
h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
@@ -63,7 +90,39 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
h[i].privNF =
ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
}
+
+ if (!h[i].privNF)
+ continue;
+
+ if (h[i].privNF > limit->max) {
+ high_nf_mid = true;
+
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NFmid[%d] (%d) > MAX (%d), %s\n",
+ i, h[i].privNF, limit->max,
+ (cal->nfcal_interference ?
+ "not corrected (due to interference)" :
+ "correcting to MAX"));
+
+ /*
+ * Normally we limit the average noise floor by the
+ * hardware specific maximum here. However if we have
+ * encountered stuck beacons because of interference,
+ * we bypass this limit here in order to better deal
+ * with our environment.
+ */
+ if (!cal->nfcal_interference)
+ h[i].privNF = limit->max;
+ }
}
+
+ /*
+ * If the noise floor seems normal for all chains, assume that
+ * there is no significant interference in the environment anymore.
+ * Re-enable the enforcement of the NF maximum again.
+ */
+ if (!high_nf_mid)
+ cal->nfcal_interference = false;
}
static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah,
@@ -104,19 +163,6 @@ void ath9k_hw_reset_calibration(struct ath_hw *ah,
ah->cal_samples = 0;
}
-static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- struct ath_nf_limits *limit;
-
- if (!chan || IS_CHAN_2GHZ(chan))
- limit = &ah->nf_2g;
- else
- limit = &ah->nf_5g;
-
- return limit->nominal;
-}
-
/* This is done for the currently configured channel */
bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
{
@@ -140,7 +186,7 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
return true;
}
- if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType))
+ if (!(ah->supp_cals & currCal->calData->calType))
return true;
ath_print(common, ATH_DBG_CALIBRATE,
@@ -254,7 +300,6 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
}
}
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
}
@@ -277,10 +322,10 @@ static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
"NF calibrated [%s] [chain %d] is %d\n",
(i >= 3 ? "ext" : "ctl"), i % 3, nf[i]);
- if (nf[i] > limit->max) {
+ if (nf[i] > ATH9K_NF_TOO_HIGH) {
ath_print(common, ATH_DBG_CALIBRATE,
"NF[%d] (%d) > MAX (%d), correcting to MAX",
- i, nf[i], limit->max);
+ i, nf[i], ATH9K_NF_TOO_HIGH);
nf[i] = limit->max;
} else if (nf[i] < limit->min) {
ath_print(common, ATH_DBG_CALIBRATE,
@@ -300,34 +345,34 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
struct ieee80211_channel *c = chan->chan;
struct ath9k_hw_cal_data *caldata = ah->caldata;
- if (!caldata)
- return false;
-
chan->channelFlags &= (~CHANNEL_CW_INT);
if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
ath_print(common, ATH_DBG_CALIBRATE,
"NF did not complete in calibration window\n");
- nf = 0;
- caldata->rawNoiseFloor = nf;
return false;
- } else {
- ath9k_hw_do_getnf(ah, nfarray);
- ath9k_hw_nf_sanitize(ah, nfarray);
- nf = nfarray[0];
- if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
- && nf > nfThresh) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "noise floor failed detected; "
- "detected %d, threshold %d\n",
- nf, nfThresh);
- chan->channelFlags |= CHANNEL_CW_INT;
- }
+ }
+
+ ath9k_hw_do_getnf(ah, nfarray);
+ ath9k_hw_nf_sanitize(ah, nfarray);
+ nf = nfarray[0];
+ if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
+ && nf > nfThresh) {
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "noise floor failed detected; "
+ "detected %d, threshold %d\n",
+ nf, nfThresh);
+ chan->channelFlags |= CHANNEL_CW_INT;
+ }
+
+ if (!caldata) {
+ chan->noisefloor = nf;
+ return false;
}
h = caldata->nfCalHist;
caldata->nfcal_pending = false;
- ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
- caldata->rawNoiseFloor = h[0].privNF;
+ ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray);
+ chan->noisefloor = h[0].privNF;
return true;
}
@@ -355,9 +400,34 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
{
- if (!ah->caldata || !ah->caldata->rawNoiseFloor)
+ if (!ah->curchan || !ah->curchan->noisefloor)
return ath9k_hw_get_default_nf(ah, chan);
- return ah->caldata->rawNoiseFloor;
+ return ah->curchan->noisefloor;
}
EXPORT_SYMBOL(ath9k_hw_getchan_noise);
+
+void ath9k_hw_bstuck_nfcal(struct ath_hw *ah)
+{
+ struct ath9k_hw_cal_data *caldata = ah->caldata;
+
+ if (unlikely(!caldata))
+ return;
+
+ /*
+ * If beacons are stuck, the most likely cause is interference.
+ * Triggering a noise floor calibration at this point helps the
+ * hardware adapt to a noisy environment much faster.
+ * To ensure that we recover from stuck beacons quickly, let
+ * the baseband update the internal NF value itself, similar to
+ * what is being done after a full reset.
+ */
+ if (!caldata->nfcal_pending)
+ ath9k_hw_start_nfcal(ah, true);
+ else if (!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF))
+ ath9k_hw_getnf(ah, ah->curchan);
+
+ caldata->nfcal_interference = true;
+}
+EXPORT_SYMBOL(ath9k_hw_bstuck_nfcal);
+
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index 0a304b3eeeb6..b8973eb8d858 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -58,14 +58,6 @@ struct ar5416IniArray {
} \
} while (0)
-enum ath9k_cal_types {
- ADC_DC_INIT_CAL = 0x1,
- ADC_GAIN_CAL = 0x2,
- ADC_DC_CAL = 0x4,
- IQ_MISMATCH_CAL = 0x8,
- TEMP_COMP_CAL = 0x10,
-};
-
enum ath9k_cal_state {
CAL_INACTIVE,
CAL_WAITING,
@@ -80,7 +72,7 @@ enum ath9k_cal_state {
#define PER_MAX_LOG_COUNT 10
struct ath9k_percal_data {
- enum ath9k_cal_types calType;
+ u32 calType;
u32 calNumSamples;
u32 calCountMax;
void (*calCollect) (struct ath_hw *);
@@ -113,6 +105,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan);
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
struct ath9k_channel *chan);
+void ath9k_hw_bstuck_nfcal(struct ath_hw *ah);
s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
void ath9k_hw_reset_calibration(struct ath_hw *ah,
struct ath9k_cal_list *currCal);
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index c86f7d3593ab..f43a2d98421c 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -46,12 +46,17 @@ int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb)
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
if (tx_info->control.hw_key) {
- if (tx_info->control.hw_key->alg == ALG_WEP)
+ switch (tx_info->control.hw_key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
return ATH9K_KEY_TYPE_WEP;
- else if (tx_info->control.hw_key->alg == ALG_TKIP)
+ case WLAN_CIPHER_SUITE_TKIP:
return ATH9K_KEY_TYPE_TKIP;
- else if (tx_info->control.hw_key->alg == ALG_CCMP)
+ case WLAN_CIPHER_SUITE_CCMP:
return ATH9K_KEY_TYPE_AES;
+ default:
+ break;
+ }
}
return ATH9K_KEY_TYPE_CLEAR;
@@ -143,276 +148,49 @@ struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ath9k_cmn_get_curchannel);
-static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key,
- struct ath9k_keyval *hk, const u8 *addr,
- bool authenticator)
-{
- struct ath_hw *ah = common->ah;
- const u8 *key_rxmic;
- const u8 *key_txmic;
-
- key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
- key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
-
- if (addr == NULL) {
- /*
- * Group key installation - only two key cache entries are used
- * regardless of splitmic capability since group key is only
- * used either for TX or RX.
- */
- if (authenticator) {
- memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
- memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic));
- } else {
- memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
- memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));
- }
- return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
- }
- if (!common->splitmic) {
- /* TX and RX keys share the same key cache entry. */
- memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
- memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
- return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
- }
-
- /* Separate key cache entries for TX and RX */
-
- /* TX key goes at first index, RX key at +32. */
- memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
- if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) {
- /* TX MIC entry failed. No need to proceed further */
- ath_print(common, ATH_DBG_FATAL,
- "Setting TX MIC Key Failed\n");
- return 0;
- }
-
- memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
- /* XXX delete tx key on failure? */
- return ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr);
-}
-
-static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
-{
- int i;
-
- for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
- if (test_bit(i, common->keymap) ||
- test_bit(i + 64, common->keymap))
- continue; /* At least one part of TKIP key allocated */
- if (common->splitmic &&
- (test_bit(i + 32, common->keymap) ||
- test_bit(i + 64 + 32, common->keymap)))
- continue; /* At least one part of TKIP key allocated */
-
- /* Found a free slot for a TKIP key */
- return i;
- }
- return -1;
-}
-
-static int ath_reserve_key_cache_slot(struct ath_common *common,
- enum ieee80211_key_alg alg)
+int ath9k_cmn_count_streams(unsigned int chainmask, int max)
{
- int i;
-
- if (alg == ALG_TKIP)
- return ath_reserve_key_cache_slot_tkip(common);
-
- /* First, try to find slots that would not be available for TKIP. */
- if (common->splitmic) {
- for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {
- if (!test_bit(i, common->keymap) &&
- (test_bit(i + 32, common->keymap) ||
- test_bit(i + 64, common->keymap) ||
- test_bit(i + 64 + 32, common->keymap)))
- return i;
- if (!test_bit(i + 32, common->keymap) &&
- (test_bit(i, common->keymap) ||
- test_bit(i + 64, common->keymap) ||
- test_bit(i + 64 + 32, common->keymap)))
- return i + 32;
- if (!test_bit(i + 64, common->keymap) &&
- (test_bit(i , common->keymap) ||
- test_bit(i + 32, common->keymap) ||
- test_bit(i + 64 + 32, common->keymap)))
- return i + 64;
- if (!test_bit(i + 64 + 32, common->keymap) &&
- (test_bit(i, common->keymap) ||
- test_bit(i + 32, common->keymap) ||
- test_bit(i + 64, common->keymap)))
- return i + 64 + 32;
- }
- } else {
- for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
- if (!test_bit(i, common->keymap) &&
- test_bit(i + 64, common->keymap))
- return i;
- if (test_bit(i, common->keymap) &&
- !test_bit(i + 64, common->keymap))
- return i + 64;
- }
- }
-
- /* No partially used TKIP slots, pick any available slot */
- for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) {
- /* Do not allow slots that could be needed for TKIP group keys
- * to be used. This limitation could be removed if we know that
- * TKIP will not be used. */
- if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
- continue;
- if (common->splitmic) {
- if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
- continue;
- if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
- continue;
- }
+ int streams = 0;
- if (!test_bit(i, common->keymap))
- return i; /* Found a free slot for a key */
- }
+ do {
+ if (++streams == max)
+ break;
+ } while ((chainmask = chainmask & (chainmask - 1)));
- /* No free slot found */
- return -1;
+ return streams;
}
+EXPORT_SYMBOL(ath9k_cmn_count_streams);
/*
- * Configure encryption in the HW.
+ * Configures appropriate weight based on stomp type.
*/
-int ath9k_cmn_key_config(struct ath_common *common,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
+void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,
+ enum ath_stomp_type stomp_type)
{
struct ath_hw *ah = common->ah;
- struct ath9k_keyval hk;
- const u8 *mac = NULL;
- u8 gmac[ETH_ALEN];
- int ret = 0;
- int idx;
- memset(&hk, 0, sizeof(hk));
-
- switch (key->alg) {
- case ALG_WEP:
- hk.kv_type = ATH9K_CIPHER_WEP;
+ switch (stomp_type) {
+ case ATH_BTCOEX_STOMP_ALL:
+ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+ AR_STOMP_ALL_WLAN_WGHT);
break;
- case ALG_TKIP:
- hk.kv_type = ATH9K_CIPHER_TKIP;
+ case ATH_BTCOEX_STOMP_LOW:
+ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+ AR_STOMP_LOW_WLAN_WGHT);
break;
- case ALG_CCMP:
- hk.kv_type = ATH9K_CIPHER_AES_CCM;
+ case ATH_BTCOEX_STOMP_NONE:
+ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+ AR_STOMP_NONE_WLAN_WGHT);
break;
default:
- return -EOPNOTSUPP;
- }
-
- hk.kv_len = key->keylen;
- memcpy(hk.kv_val, key->key, key->keylen);
-
- if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
- switch (vif->type) {
- case NL80211_IFTYPE_AP:
- memcpy(gmac, vif->addr, ETH_ALEN);
- gmac[0] |= 0x01;
- mac = gmac;
- idx = ath_reserve_key_cache_slot(common, key->alg);
- break;
- case NL80211_IFTYPE_ADHOC:
- if (!sta) {
- idx = key->keyidx;
- break;
- }
- memcpy(gmac, sta->addr, ETH_ALEN);
- gmac[0] |= 0x01;
- mac = gmac;
- idx = ath_reserve_key_cache_slot(common, key->alg);
- break;
- default:
- idx = key->keyidx;
- break;
- }
- } else if (key->keyidx) {
- if (WARN_ON(!sta))
- return -EOPNOTSUPP;
- mac = sta->addr;
-
- if (vif->type != NL80211_IFTYPE_AP) {
- /* Only keyidx 0 should be used with unicast key, but
- * allow this for client mode for now. */
- idx = key->keyidx;
- } else
- return -EIO;
- } else {
- if (WARN_ON(!sta))
- return -EOPNOTSUPP;
- mac = sta->addr;
-
- idx = ath_reserve_key_cache_slot(common, key->alg);
- }
-
- if (idx < 0)
- return -ENOSPC; /* no free key cache entries */
-
- if (key->alg == ALG_TKIP)
- ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
- vif->type == NL80211_IFTYPE_AP);
- else
- ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac);
-
- if (!ret)
- return -EIO;
-
- set_bit(idx, common->keymap);
- if (key->alg == ALG_TKIP) {
- set_bit(idx + 64, common->keymap);
- if (common->splitmic) {
- set_bit(idx + 32, common->keymap);
- set_bit(idx + 64 + 32, common->keymap);
- }
- }
-
- return idx;
-}
-EXPORT_SYMBOL(ath9k_cmn_key_config);
-
-/*
- * Delete Key.
- */
-void ath9k_cmn_key_delete(struct ath_common *common,
- struct ieee80211_key_conf *key)
-{
- struct ath_hw *ah = common->ah;
-
- ath9k_hw_keyreset(ah, key->hw_key_idx);
- if (key->hw_key_idx < IEEE80211_WEP_NKID)
- return;
-
- clear_bit(key->hw_key_idx, common->keymap);
- if (key->alg != ALG_TKIP)
- return;
-
- clear_bit(key->hw_key_idx + 64, common->keymap);
- if (common->splitmic) {
- ath9k_hw_keyreset(ah, key->hw_key_idx + 32);
- clear_bit(key->hw_key_idx + 32, common->keymap);
- clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
+ ath_print(common, ATH_DBG_BTCOEX,
+ "Invalid Stomptype\n");
+ break;
}
-}
-EXPORT_SYMBOL(ath9k_cmn_key_delete);
-
-int ath9k_cmn_count_streams(unsigned int chainmask, int max)
-{
- int streams = 0;
-
- do {
- if (++streams == max)
- break;
- } while ((chainmask = chainmask & (chainmask - 1)));
- return streams;
+ ath9k_hw_btcoex_enable(ah);
}
-EXPORT_SYMBOL(ath9k_cmn_count_streams);
+EXPORT_SYMBOL(ath9k_cmn_btcoex_bt_stomp);
static int __init ath9k_cmn_init(void)
{
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
index 97809d39c73f..fea3b3315391 100644
--- a/drivers/net/wireless/ath/ath9k/common.h
+++ b/drivers/net/wireless/ath/ath9k/common.h
@@ -52,16 +52,20 @@
#define ATH_EP_RND(x, mul) \
((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+/* Defines the BT AR_BT_COEX_WGHT used */
+enum ath_stomp_type {
+ ATH_BTCOEX_NO_STOMP,
+ ATH_BTCOEX_STOMP_ALL,
+ ATH_BTCOEX_STOMP_LOW,
+ ATH_BTCOEX_STOMP_NONE
+};
+
int ath9k_cmn_padpos(__le16 frame_control);
int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
struct ath9k_channel *ichan);
struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
struct ath_hw *ah);
-int ath9k_cmn_key_config(struct ath_common *common,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key);
-void ath9k_cmn_key_delete(struct ath_common *common,
- struct ieee80211_key_conf *key);
int ath9k_cmn_count_streams(unsigned int chainmask, int max);
+void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,
+ enum ath_stomp_type stomp_type);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index cf500bf25ad5..43e71a944cb1 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -383,96 +383,6 @@ static const struct file_operations fops_interrupt = {
.llseek = default_llseek,
};
-void ath_debug_stat_rc(struct ath_softc *sc, int final_rate)
-{
- struct ath_rc_stats *stats;
-
- stats = &sc->debug.stats.rcstats[final_rate];
- stats->success++;
-}
-
-void ath_debug_stat_retries(struct ath_softc *sc, int rix,
- int xretries, int retries, u8 per)
-{
- struct ath_rc_stats *stats = &sc->debug.stats.rcstats[rix];
-
- stats->xretries += xretries;
- stats->retries += retries;
- stats->per = per;
-}
-
-static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ath_softc *sc = file->private_data;
- char *buf;
- unsigned int len = 0, max;
- int i = 0;
- ssize_t retval;
-
- if (sc->cur_rate_table == NULL)
- return 0;
-
- max = 80 + sc->cur_rate_table->rate_cnt * 1024 + 1;
- buf = kmalloc(max, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- len += sprintf(buf, "%6s %6s %6s "
- "%10s %10s %10s %10s\n",
- "HT", "MCS", "Rate",
- "Success", "Retries", "XRetries", "PER");
-
- for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) {
- u32 ratekbps = sc->cur_rate_table->info[i].ratekbps;
- struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i];
- char mcs[5];
- char htmode[5];
- int used_mcs = 0, used_htmode = 0;
-
- if (WLAN_RC_PHY_HT(sc->cur_rate_table->info[i].phy)) {
- used_mcs = snprintf(mcs, 5, "%d",
- sc->cur_rate_table->info[i].ratecode);
-
- if (WLAN_RC_PHY_40(sc->cur_rate_table->info[i].phy))
- used_htmode = snprintf(htmode, 5, "HT40");
- else if (WLAN_RC_PHY_20(sc->cur_rate_table->info[i].phy))
- used_htmode = snprintf(htmode, 5, "HT20");
- else
- used_htmode = snprintf(htmode, 5, "????");
- }
-
- mcs[used_mcs] = '\0';
- htmode[used_htmode] = '\0';
-
- len += snprintf(buf + len, max - len,
- "%6s %6s %3u.%d: "
- "%10u %10u %10u %10u\n",
- htmode,
- mcs,
- ratekbps / 1000,
- (ratekbps % 1000) / 100,
- stats->success,
- stats->retries,
- stats->xretries,
- stats->per);
- }
-
- if (len > max)
- len = max;
-
- retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
- kfree(buf);
- return retval;
-}
-
-static const struct file_operations fops_rcstat = {
- .read = read_file_rcstat,
- .open = ath9k_debugfs_open,
- .owner = THIS_MODULE,
- .llseek = default_llseek,
-};
-
static const char * ath_wiphy_state_str(enum ath_wiphy_state state)
{
switch (state) {
@@ -494,26 +404,20 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
+ struct ath_wiphy *aphy = sc->pri_wiphy;
+ struct ieee80211_channel *chan = aphy->hw->conf.channel;
char buf[512];
unsigned int len = 0;
int i;
u8 addr[ETH_ALEN];
+ u32 tmp;
len += snprintf(buf + len, sizeof(buf) - len,
"primary: %s (%s chan=%d ht=%d)\n",
wiphy_name(sc->pri_wiphy->hw->wiphy),
ath_wiphy_state_str(sc->pri_wiphy->state),
- sc->pri_wiphy->chan_idx, sc->pri_wiphy->chan_is_ht);
- for (i = 0; i < sc->num_sec_wiphy; i++) {
- struct ath_wiphy *aphy = sc->sec_wiphy[i];
- if (aphy == NULL)
- continue;
- len += snprintf(buf + len, sizeof(buf) - len,
- "secondary: %s (%s chan=%d ht=%d)\n",
- wiphy_name(aphy->hw->wiphy),
- ath_wiphy_state_str(aphy->state),
- aphy->chan_idx, aphy->chan_is_ht);
- }
+ ieee80211_frequency_to_channel(chan->center_freq),
+ aphy->chan_is_ht);
put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
@@ -523,7 +427,51 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4);
len += snprintf(buf + len, sizeof(buf) - len,
"addrmask: %pM\n", addr);
-
+ tmp = ath9k_hw_getrxfilter(sc->sc_ah);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "rfilt: 0x%x", tmp);
+ if (tmp & ATH9K_RX_FILTER_UCAST)
+ len += snprintf(buf + len, sizeof(buf) - len, " UCAST");
+ if (tmp & ATH9K_RX_FILTER_MCAST)
+ len += snprintf(buf + len, sizeof(buf) - len, " MCAST");
+ if (tmp & ATH9K_RX_FILTER_BCAST)
+ len += snprintf(buf + len, sizeof(buf) - len, " BCAST");
+ if (tmp & ATH9K_RX_FILTER_CONTROL)
+ len += snprintf(buf + len, sizeof(buf) - len, " CONTROL");
+ if (tmp & ATH9K_RX_FILTER_BEACON)
+ len += snprintf(buf + len, sizeof(buf) - len, " BEACON");
+ if (tmp & ATH9K_RX_FILTER_PROM)
+ len += snprintf(buf + len, sizeof(buf) - len, " PROM");
+ if (tmp & ATH9K_RX_FILTER_PROBEREQ)
+ len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
+ if (tmp & ATH9K_RX_FILTER_PHYERR)
+ len += snprintf(buf + len, sizeof(buf) - len, " PHYERR");
+ if (tmp & ATH9K_RX_FILTER_MYBEACON)
+ len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON");
+ if (tmp & ATH9K_RX_FILTER_COMP_BAR)
+ len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR");
+ if (tmp & ATH9K_RX_FILTER_PSPOLL)
+ len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL");
+ if (tmp & ATH9K_RX_FILTER_PHYRADAR)
+ len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR");
+ if (tmp & ATH9K_RX_FILTER_MCAST_BCAST_ALL)
+ len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL\n");
+ else
+ len += snprintf(buf + len, sizeof(buf) - len, "\n");
+
+ /* Put variable-length stuff down here, and check for overflows. */
+ for (i = 0; i < sc->num_sec_wiphy; i++) {
+ struct ath_wiphy *aphy = sc->sec_wiphy[i];
+ if (aphy == NULL)
+ continue;
+ chan = aphy->hw->conf.channel;
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "secondary: %s (%s chan=%d ht=%d)\n",
+ wiphy_name(aphy->hw->wiphy),
+ ath_wiphy_state_str(aphy->state),
+ ieee80211_frequency_to_channel(chan->center_freq),
+ aphy->chan_is_ht);
+ }
if (len > sizeof(buf))
len = sizeof(buf);
@@ -670,6 +618,8 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
PR("DESC CFG Error: ", desc_cfg_err);
PR("DATA Underrun: ", data_underrun);
PR("DELIM Underrun: ", delim_underrun);
+ PR("TX-Pkts-All: ", tx_pkts_all);
+ PR("TX-Bytes-All: ", tx_bytes_all);
if (len > size)
len = size;
@@ -683,6 +633,9 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf, struct ath_tx_status *ts)
{
+ TX_STAT_INC(txq->axq_qnum, tx_pkts_all);
+ sc->debug.stats.txstats[txq->axq_qnum].tx_bytes_all += bf->bf_mpdu->len;
+
if (bf_isampdu(bf)) {
if (bf_isxretried(bf))
TX_STAT_INC(txq->axq_qnum, a_xretries);
@@ -778,6 +731,13 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL);
+ len += snprintf(buf + len, size - len,
+ "%18s : %10u\n", "RX-Pkts-All",
+ sc->debug.stats.rxstats.rx_pkts_all);
+ len += snprintf(buf + len, size - len,
+ "%18s : %10u\n", "RX-Bytes-All",
+ sc->debug.stats.rxstats.rx_bytes_all);
+
if (len > size)
len = size;
@@ -796,6 +756,9 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
u32 phyerr;
+ RX_STAT_INC(rx_pkts_all);
+ sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen;
+
if (rs->rs_status & ATH9K_RXERR_CRC)
RX_STAT_INC(crc_err);
if (rs->rs_status & ATH9K_RXERR_DECRYPT)
@@ -935,10 +898,6 @@ int ath9k_init_debug(struct ath_hw *ah)
sc, &fops_interrupt))
goto err;
- if (!debugfs_create_file("rcstat", S_IRUSR, sc->debug.debugfs_phy,
- sc, &fops_rcstat))
- goto err;
-
if (!debugfs_create_file("wiphy", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc, &fops_wiphy))
goto err;
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 5d21704e87ff..bb0823242ba0 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -80,15 +80,12 @@ struct ath_interrupt_stats {
u32 bb_watchdog;
};
-struct ath_rc_stats {
- u32 success;
- u32 retries;
- u32 xretries;
- u8 per;
-};
-
/**
* struct ath_tx_stats - Statistics about TX
+ * @tx_pkts_all: No. of total frames transmitted, including ones that
+ may have had errors.
+ * @tx_bytes_all: No. of total bytes transmitted, including ones that
+ may have had errors.
* @queued: Total MPDUs (non-aggr) queued
* @completed: Total MPDUs (non-aggr) completed
* @a_aggr: Total no. of aggregates queued
@@ -107,6 +104,8 @@ struct ath_rc_stats {
* @delim_urn: TX delimiter underrun errors
*/
struct ath_tx_stats {
+ u32 tx_pkts_all;
+ u32 tx_bytes_all;
u32 queued;
u32 completed;
u32 a_aggr;
@@ -124,6 +123,10 @@ struct ath_tx_stats {
/**
* struct ath_rx_stats - RX Statistics
+ * @rx_pkts_all: No. of total frames received, including ones that
+ may have had errors.
+ * @rx_bytes_all: No. of total bytes received, including ones that
+ may have had errors.
* @crc_err: No. of frames with incorrect CRC value
* @decrypt_crc_err: No. of frames whose CRC check failed after
decryption process completed
@@ -136,6 +139,8 @@ struct ath_tx_stats {
* @phy_err_stats: Individual PHY error statistics
*/
struct ath_rx_stats {
+ u32 rx_pkts_all;
+ u32 rx_bytes_all;
u32 crc_err;
u32 decrypt_crc_err;
u32 phy_err;
@@ -148,7 +153,6 @@ struct ath_rx_stats {
struct ath_stats {
struct ath_interrupt_stats istats;
- struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
struct ath_rx_stats rxstats;
};
@@ -165,12 +169,9 @@ void ath9k_exit_debug(struct ath_hw *ah);
int ath9k_debug_create_root(void);
void ath9k_debug_remove_root(void);
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
-void ath_debug_stat_rc(struct ath_softc *sc, int final_rate);
void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf, struct ath_tx_status *ts);
void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs);
-void ath_debug_stat_retries(struct ath_softc *sc, int rix,
- int xretries, int retries, u8 per);
#else
@@ -197,11 +198,6 @@ static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
{
}
-static inline void ath_debug_stat_rc(struct ath_softc *sc,
- int final_rate)
-{
-}
-
static inline void ath_debug_stat_tx(struct ath_softc *sc,
struct ath_txq *txq,
struct ath_buf *bf,
@@ -214,11 +210,6 @@ static inline void ath_debug_stat_rx(struct ath_softc *sc,
{
}
-static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix,
- int xretries, int retries, u8 per)
-{
-}
-
#endif /* CONFIG_ATH9K_DEBUGFS */
#endif /* DEBUG_H */
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 0b09db0f8e7d..dacb45e1b906 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -101,7 +101,7 @@
#define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK)
#define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \
ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
-#define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_10_OR_LATER(ah) && \
+#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
@@ -266,6 +266,8 @@ enum eeprom_param {
EEP_INTERNAL_REGULATOR,
EEP_SWREG,
EEP_PAPRD,
+ EEP_MODAL_VER,
+ EEP_ANT_DIV_CTL1,
};
enum ar5416_rates {
@@ -670,7 +672,8 @@ struct eeprom_ops {
bool (*fill_eeprom)(struct ath_hw *hw);
int (*get_eeprom_ver)(struct ath_hw *hw);
int (*get_eeprom_rev)(struct ath_hw *hw);
- u8 (*get_num_ant_config)(struct ath_hw *hw, enum ieee80211_band band);
+ u8 (*get_num_ant_config)(struct ath_hw *hw,
+ enum ath9k_hal_freq_band band);
u32 (*get_eeprom_antenna_cfg)(struct ath_hw *hw,
struct ath9k_channel *chan);
void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan);
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 9cccd12e8f21..4fa4d8e28c64 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -179,6 +179,9 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
struct modal_eep_4k_header *pModal = &eep->modalHeader;
struct base_eep_header_4k *pBase = &eep->baseEepHeader;
+ u16 ver_minor;
+
+ ver_minor = pBase->version & AR5416_EEP_VER_MINOR_MASK;
switch (param) {
case EEP_NFTHRESH_2:
@@ -204,7 +207,7 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
case EEP_DB_2:
return pModal->db1_1;
case EEP_MINOR_REV:
- return pBase->version & AR5416_EEP_VER_MINOR_MASK;
+ return ver_minor;
case EEP_TX_MASK:
return pBase->txMask;
case EEP_RX_MASK:
@@ -213,6 +216,15 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
return 0;
case EEP_PWR_TABLE_OFFSET:
return AR5416_PWR_TABLE_OFFSET_DB;
+ case EEP_MODAL_VER:
+ return pModal->version;
+ 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;
default:
return 0;
}
@@ -329,7 +341,7 @@ static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah,
}
if (i == 0) {
- if (AR_SREV_9280_10_OR_LATER(ah))
+ if (AR_SREV_9280_20_OR_LATER(ah))
ss = (int16_t)(0 - (minPwrT4[i] / 2));
else
ss = 0;
@@ -496,7 +508,6 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
}
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
}
}
@@ -757,7 +768,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
regulatory->max_power_level = ratesArray[i];
- if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
for (i = 0; i < Ar5416RateSize; i++)
ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
}
@@ -828,7 +839,6 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
}
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
}
static void ath9k_hw_4k_set_addac(struct ath_hw *ah,
@@ -905,9 +915,6 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
-
- if (AR_SREV_9285_11(ah))
- REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
}
/*
@@ -1105,9 +1112,6 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
}
- if (AR_SREV_9285_11(ah))
- REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
-
REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
pModal->switchSettling);
REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
@@ -1157,7 +1161,7 @@ static u32 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah,
}
static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah,
- enum ieee80211_band freq_band)
+ enum ath9k_hal_freq_band freq_band)
{
return 1;
}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index dff2da777312..966b9496a9dd 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -324,7 +324,7 @@ static void ath9k_hw_get_ar9287_gain_boundaries_pdadcs(struct ath_hw *ah,
minDelta = 0;
if (i == 0) {
- if (AR_SREV_9280_10_OR_LATER(ah))
+ if (AR_SREV_9280_20_OR_LATER(ah))
ss = (int16_t)(0 - (minPwrT4[i] / 2));
else
ss = 0;
@@ -883,7 +883,7 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
ratesArray[i] = AR9287_MAX_RATE_POWER;
}
- if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
for (i = 0; i < Ar5416RateSize; i++)
ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
}
@@ -977,7 +977,7 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
else
i = rate6mb;
- if (AR_SREV_9280_10_OR_LATER(ah))
+ if (AR_SREV_9280_20_OR_LATER(ah))
regulatory->max_power_level =
ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2;
else
@@ -1126,7 +1126,7 @@ static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
}
static u8 ath9k_hw_ar9287_get_num_ant_config(struct ath_hw *ah,
- enum ieee80211_band freq_band)
+ enum ath9k_hal_freq_band freq_band)
{
return 1;
}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index afa2b73ddbdd..76b4d65472dd 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -223,7 +223,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
}
/* Enable fixup for AR_AN_TOP2 if necessary */
- if (AR_SREV_9280_10_OR_LATER(ah) &&
+ if (AR_SREV_9280_20_OR_LATER(ah) &&
(eep->baseEepHeader.version & 0xff) > 0x0a &&
eep->baseEepHeader.pwdclkind == 0)
ah->need_an_top2_fixup = 1;
@@ -317,7 +317,7 @@ static void ath9k_hw_def_set_gain(struct ath_hw *ah,
if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) {
txRxAttenLocal = pModal->txRxAttenCh[i];
- if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
pModal->bswMargin[i]);
@@ -344,7 +344,7 @@ static void ath9k_hw_def_set_gain(struct ath_hw *ah,
}
}
- if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
REG_RMW_FIELD(ah,
AR_PHY_RXGAIN + regChainOffset,
AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
@@ -408,7 +408,7 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
regChainOffset, i);
}
- if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
if (IS_CHAN_2GHZ(chan)) {
ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
AR_AN_RF2G1_CH0_OB,
@@ -461,7 +461,7 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
pModal->adcDesiredSize);
- if (!AR_SREV_9280_10_OR_LATER(ah))
+ if (!AR_SREV_9280_20_OR_LATER(ah))
REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
AR_PHY_DESIRED_SZ_PGA,
pModal->pgaDesiredSize);
@@ -478,7 +478,7 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
pModal->txEndToRxOn);
- if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
pModal->thresh62);
REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
@@ -696,7 +696,7 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
}
if (i == 0) {
- if (AR_SREV_9280_10_OR_LATER(ah))
+ if (AR_SREV_9280_20_OR_LATER(ah))
ss = (int16_t)(0 - (minPwrT4[i] / 2));
else
ss = 0;
@@ -1291,7 +1291,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
ratesArray[i] = AR5416_MAX_RATE_POWER;
}
- if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
for (i = 0; i < Ar5416RateSize; i++) {
int8_t pwr_table_offset;
@@ -1395,7 +1395,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
else if (IS_CHAN_HT20(chan))
i = rateHt20_0;
- if (AR_SREV_9280_10_OR_LATER(ah))
+ if (AR_SREV_9280_20_OR_LATER(ah))
regulatory->max_power_level =
ratesArray[i] + AR5416_PWR_TABLE_OFFSET_DB * 2;
else
@@ -1418,11 +1418,11 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
}
static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah,
- enum ieee80211_band freq_band)
+ enum ath9k_hal_freq_band freq_band)
{
struct ar5416_eeprom_def *eep = &ah->eeprom.def;
struct modal_eep_header *pModal =
- &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]);
+ &(eep->modalHeader[freq_band]);
struct base_eep_header *pBase = &eep->baseEepHeader;
u8 num_ant_config;
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index 3a8ee999da5d..4a9a68bba324 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -251,36 +251,6 @@ static void ath_detect_bt_priority(struct ath_softc *sc)
}
}
-/*
- * Configures appropriate weight based on stomp type.
- */
-static void ath9k_btcoex_bt_stomp(struct ath_softc *sc,
- enum ath_stomp_type stomp_type)
-{
- struct ath_hw *ah = sc->sc_ah;
-
- switch (stomp_type) {
- case ATH_BTCOEX_STOMP_ALL:
- ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
- AR_STOMP_ALL_WLAN_WGHT);
- break;
- case ATH_BTCOEX_STOMP_LOW:
- ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
- AR_STOMP_LOW_WLAN_WGHT);
- break;
- case ATH_BTCOEX_STOMP_NONE:
- ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
- AR_STOMP_NONE_WLAN_WGHT);
- break;
- default:
- ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
- "Invalid Stomptype\n");
- break;
- }
-
- ath9k_hw_btcoex_enable(ah);
-}
-
static void ath9k_gen_timer_start(struct ath_hw *ah,
struct ath_gen_timer *timer,
u32 timer_next,
@@ -319,6 +289,7 @@ static void ath_btcoex_period_timer(unsigned long data)
struct ath_softc *sc = (struct ath_softc *) data;
struct ath_hw *ah = sc->sc_ah;
struct ath_btcoex *btcoex = &sc->btcoex;
+ struct ath_common *common = ath9k_hw_common(ah);
u32 timer_period;
bool is_btscan;
@@ -328,7 +299,7 @@ static void ath_btcoex_period_timer(unsigned long data)
spin_lock_bh(&btcoex->btcoex_lock);
- ath9k_btcoex_bt_stomp(sc, is_btscan ? ATH_BTCOEX_STOMP_ALL :
+ ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL :
btcoex->bt_stomp_type);
spin_unlock_bh(&btcoex->btcoex_lock);
@@ -359,17 +330,18 @@ static void ath_btcoex_no_stomp_timer(void *arg)
struct ath_softc *sc = (struct ath_softc *)arg;
struct ath_hw *ah = sc->sc_ah;
struct ath_btcoex *btcoex = &sc->btcoex;
+ struct ath_common *common = ath9k_hw_common(ah);
bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
- ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ ath_print(common, ATH_DBG_BTCOEX,
"no stomp timer running\n");
spin_lock_bh(&btcoex->btcoex_lock);
if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
- ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE);
+ ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE);
else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
- ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW);
+ ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW);
spin_unlock_bh(&btcoex->btcoex_lock);
}
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 17e7a9a367e7..728d904c74d7 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -92,10 +92,10 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
cmd->skb = skb;
cmd->hif_dev = hif_dev;
- usb_fill_int_urb(urb, hif_dev->udev,
- usb_sndintpipe(hif_dev->udev, USB_REG_OUT_PIPE),
+ usb_fill_bulk_urb(urb, hif_dev->udev,
+ usb_sndbulkpipe(hif_dev->udev, USB_REG_OUT_PIPE),
skb->data, skb->len,
- hif_usb_regout_cb, cmd, 1);
+ hif_usb_regout_cb, cmd);
usb_anchor_urb(urb, &hif_dev->regout_submitted);
ret = usb_submit_urb(urb, GFP_KERNEL);
@@ -541,7 +541,8 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
}
usb_fill_int_urb(urb, hif_dev->udev,
- usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE),
+ usb_rcvbulkpipe(hif_dev->udev,
+ USB_REG_IN_PIPE),
nskb->data, MAX_REG_IN_BUF_SIZE,
ath9k_hif_usb_reg_in_cb, nskb, 1);
@@ -720,7 +721,8 @@ static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev)
goto err;
usb_fill_int_urb(hif_dev->reg_in_urb, hif_dev->udev,
- usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE),
+ usb_rcvbulkpipe(hif_dev->udev,
+ USB_REG_IN_PIPE),
skb->data, MAX_REG_IN_BUF_SIZE,
ath9k_hif_usb_reg_in_cb, skb, 1);
@@ -822,7 +824,9 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
{
- int ret;
+ int ret, idx;
+ struct usb_host_interface *alt = &hif_dev->interface->altsetting[0];
+ struct usb_endpoint_descriptor *endp;
/* Request firmware */
ret = request_firmware(&hif_dev->firmware, hif_dev->fw_name,
@@ -850,6 +854,22 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
goto err_fw_download;
}
+ /* On downloading the firmware to the target, the USB descriptor of EP4
+ * is 'patched' to change the type of the endpoint to Bulk. This will
+ * bring down CPU usage during the scan period.
+ */
+ for (idx = 0; idx < alt->desc.bNumEndpoints; idx++) {
+ endp = &alt->endpoint[idx].desc;
+ if (((endp->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
+ == 0x04) &&
+ ((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_INT)) {
+ endp->bmAttributes &= ~USB_ENDPOINT_XFERTYPE_MASK;
+ endp->bmAttributes |= USB_ENDPOINT_XFER_BULK;
+ endp->bInterval = 0;
+ }
+ }
+
return 0;
err_fw_download:
@@ -920,7 +940,8 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
}
ret = ath9k_htc_hw_init(hif_dev->htc_handle,
- &hif_dev->udev->dev, hif_dev->device_id);
+ &hif_dev->udev->dev, hif_dev->device_id,
+ hif_dev->udev->product);
if (ret) {
ret = -EINVAL;
goto err_htc_hw_init;
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 43b9e21bc562..75ecf6a30d25 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -316,17 +316,32 @@ struct htc_beacon_config {
u8 dtim_count;
};
-#define OP_INVALID BIT(0)
-#define OP_SCANNING BIT(1)
-#define OP_FULL_RESET BIT(2)
-#define OP_LED_ASSOCIATED BIT(3)
-#define OP_LED_ON BIT(4)
-#define OP_PREAMBLE_SHORT BIT(5)
-#define OP_PROTECT_ENABLE BIT(6)
-#define OP_ASSOCIATED BIT(7)
-#define OP_ENABLE_BEACON BIT(8)
-#define OP_LED_DEINIT BIT(9)
-#define OP_UNPLUGGED BIT(10)
+struct ath_btcoex {
+ u32 bt_priority_cnt;
+ unsigned long bt_priority_time;
+ int bt_stomp_type; /* Types of BT stomping */
+ u32 btcoex_no_stomp;
+ u32 btcoex_period;
+ u32 btscan_no_stomp;
+};
+
+void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv);
+void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv);
+void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv);
+
+#define OP_INVALID BIT(0)
+#define OP_SCANNING BIT(1)
+#define OP_FULL_RESET BIT(2)
+#define OP_LED_ASSOCIATED BIT(3)
+#define OP_LED_ON BIT(4)
+#define OP_PREAMBLE_SHORT BIT(5)
+#define OP_PROTECT_ENABLE BIT(6)
+#define OP_ASSOCIATED BIT(7)
+#define OP_ENABLE_BEACON BIT(8)
+#define OP_LED_DEINIT BIT(9)
+#define OP_UNPLUGGED BIT(10)
+#define OP_BT_PRIORITY_DETECTED BIT(11)
+#define OP_BT_SCAN BIT(12)
struct ath9k_htc_priv {
struct device *dev;
@@ -391,6 +406,9 @@ struct ath9k_htc_priv {
int cabq;
int hwq_map[WME_NUM_AC];
+ struct ath_btcoex btcoex;
+ struct delayed_work coex_period_work;
+ struct delayed_work duty_cycle_work;
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
struct ath9k_debug debug;
#endif
@@ -443,7 +461,7 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv);
void ath9k_deinit_leds(struct ath9k_htc_priv *priv);
int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
- u16 devid);
+ u16 devid, char *product);
void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug);
#ifdef CONFIG_PM
int ath9k_htc_resume(struct htc_target *htc_handle);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index bd1506e69105..1b72aa482ac7 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -235,7 +235,14 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
ath9k_hw_get_txq_props(ah, qnum, &qi_be);
qi.tqi_aifs = qi_be.tqi_aifs;
- qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
+ /* For WIFI Beacon Distribution
+ * Long slot time : 2x cwmin
+ * Short slot time : 4x cwmin
+ */
+ if (ah->slottime == ATH9K_SLOT_TIME_20)
+ qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
+ else
+ qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
qi.tqi_cwmax = qi_be.tqi_cwmax;
if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) {
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
new file mode 100644
index 000000000000..50eec9a3b88c
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
@@ -0,0 +1,134 @@
+#include "htc.h"
+
+/******************/
+/* BTCOEX */
+/******************/
+
+/*
+ * Detects if there is any priority bt traffic
+ */
+static void ath_detect_bt_priority(struct ath9k_htc_priv *priv)
+{
+ struct ath_btcoex *btcoex = &priv->btcoex;
+ struct ath_hw *ah = priv->ah;
+
+ if (ath9k_hw_gpio_get(ah, ah->btcoex_hw.btpriority_gpio))
+ btcoex->bt_priority_cnt++;
+
+ if (time_after(jiffies, btcoex->bt_priority_time +
+ msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
+ priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
+ /* Detect if colocated bt started scanning */
+ if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
+ ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "BT scan detected");
+ priv->op_flags |= (OP_BT_SCAN |
+ OP_BT_PRIORITY_DETECTED);
+ } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
+ ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "BT priority traffic detected");
+ priv->op_flags |= OP_BT_PRIORITY_DETECTED;
+ }
+
+ btcoex->bt_priority_cnt = 0;
+ btcoex->bt_priority_time = jiffies;
+ }
+}
+
+/*
+ * This is the master bt coex work which runs for every
+ * 45ms, bt traffic will be given priority during 55% of this
+ * period while wlan gets remaining 45%
+ */
+static void ath_btcoex_period_work(struct work_struct *work)
+{
+ struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
+ coex_period_work.work);
+ struct ath_btcoex *btcoex = &priv->btcoex;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ u32 timer_period;
+ bool is_btscan;
+ int ret;
+ u8 cmd_rsp, aggr;
+
+ ath_detect_bt_priority(priv);
+
+ is_btscan = !!(priv->op_flags & OP_BT_SCAN);
+
+ aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED;
+
+ WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr);
+
+ ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL :
+ btcoex->bt_stomp_type);
+
+ timer_period = is_btscan ? btcoex->btscan_no_stomp :
+ btcoex->btcoex_no_stomp;
+ ieee80211_queue_delayed_work(priv->hw, &priv->duty_cycle_work,
+ msecs_to_jiffies(timer_period));
+ ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work,
+ msecs_to_jiffies(btcoex->btcoex_period));
+}
+
+/*
+ * Work to time slice between wlan and bt traffic and
+ * configure weight registers
+ */
+static void ath_btcoex_duty_cycle_work(struct work_struct *work)
+{
+ struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
+ duty_cycle_work.work);
+ struct ath_hw *ah = priv->ah;
+ struct ath_btcoex *btcoex = &priv->btcoex;
+ struct ath_common *common = ath9k_hw_common(ah);
+ bool is_btscan = priv->op_flags & OP_BT_SCAN;
+
+ ath_print(common, ATH_DBG_BTCOEX,
+ "time slice work for bt and wlan\n");
+
+ if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
+ ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE);
+ else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
+ ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW);
+}
+
+void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
+{
+ struct ath_btcoex *btcoex = &priv->btcoex;
+
+ btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
+ btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
+ btcoex->btcoex_period / 100;
+ btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
+ btcoex->btcoex_period / 100;
+ INIT_DELAYED_WORK(&priv->coex_period_work, ath_btcoex_period_work);
+ INIT_DELAYED_WORK(&priv->duty_cycle_work, ath_btcoex_duty_cycle_work);
+}
+
+/*
+ * (Re)start btcoex work
+ */
+
+void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
+{
+ struct ath_btcoex *btcoex = &priv->btcoex;
+ struct ath_hw *ah = priv->ah;
+
+ ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "Starting btcoex work");
+
+ btcoex->bt_priority_cnt = 0;
+ btcoex->bt_priority_time = jiffies;
+ priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
+ ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work, 0);
+}
+
+
+/*
+ * Cancel btcoex and bt duty cycle work.
+ */
+void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
+{
+ cancel_delayed_work_sync(&priv->coex_period_work);
+ cancel_delayed_work_sync(&priv->duty_cycle_work);
+}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 2d4279191d7a..3d7b97f1b3ae 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -41,6 +41,8 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
.max_power = 20, \
}
+#define ATH_HTC_BTCOEX_PRODUCT_ID "wb193"
+
static struct ieee80211_channel ath9k_2ghz_channels[] = {
CHAN2G(2412, 0), /* Channel 1 */
CHAN2G(2417, 1), /* Channel 2 */
@@ -378,15 +380,6 @@ static void ath9k_enable_regwrite_buffer(void *hw_priv)
atomic_inc(&priv->wmi->mwrite_cnt);
}
-static void ath9k_disable_regwrite_buffer(void *hw_priv)
-{
- struct ath_hw *ah = (struct ath_hw *) hw_priv;
- struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
-
- atomic_dec(&priv->wmi->mwrite_cnt);
-}
-
static void ath9k_regwrite_flush(void *hw_priv)
{
struct ath_hw *ah = (struct ath_hw *) hw_priv;
@@ -395,6 +388,8 @@ static void ath9k_regwrite_flush(void *hw_priv)
u32 rsp_status;
int r;
+ atomic_dec(&priv->wmi->mwrite_cnt);
+
mutex_lock(&priv->wmi->multi_write_mutex);
if (priv->wmi->multi_write_idx) {
@@ -418,7 +413,6 @@ static const struct ath_ops ath9k_common_ops = {
.read = ath9k_regread,
.write = ath9k_regwrite,
.enable_write_buffer = ath9k_enable_regwrite_buffer,
- .disable_write_buffer = ath9k_disable_regwrite_buffer,
.write_flush = ath9k_regwrite_flush,
};
@@ -559,17 +553,20 @@ static void ath9k_init_crypto(struct ath9k_htc_priv *priv)
common->keymax = ATH_KEYMAX;
}
+ 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++)
- ath9k_hw_keyreset(priv->ah, (u16) i);
+ ath_hw_keyreset(common, (u16) i);
}
static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
{
- if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes)) {
+ if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
priv->sbands[IEEE80211_BAND_2GHZ].channels =
ath9k_2ghz_channels;
priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
@@ -580,7 +577,7 @@ static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
ARRAY_SIZE(ath9k_legacy_rates);
}
- if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes)) {
+ if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels;
priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
priv->sbands[IEEE80211_BAND_5GHZ].n_channels =
@@ -599,13 +596,36 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv)
common->tx_chainmask = priv->ah->caps.tx_chainmask;
common->rx_chainmask = priv->ah->caps.rx_chainmask;
- if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
- memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
+ memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
priv->ah->opmode = NL80211_IFTYPE_STATION;
}
-static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid)
+static void ath9k_init_btcoex(struct ath9k_htc_priv *priv)
+{
+ int qnum;
+
+ switch (priv->ah->btcoex_hw.scheme) {
+ case ATH_BTCOEX_CFG_NONE:
+ break;
+ case ATH_BTCOEX_CFG_3WIRE:
+ priv->ah->btcoex_hw.btactive_gpio = 7;
+ priv->ah->btcoex_hw.btpriority_gpio = 6;
+ priv->ah->btcoex_hw.wlanactive_gpio = 8;
+ priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+ ath9k_hw_btcoex_init_3wire(priv->ah);
+ ath_htc_init_btcoex_work(priv);
+ qnum = priv->hwq_map[WME_AC_BE];
+ ath9k_hw_init_btcoex_hw(priv->ah, qnum);
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+}
+
+static int ath9k_init_priv(struct ath9k_htc_priv *priv,
+ u16 devid, char *product)
{
struct ath_hw *ah = NULL;
struct ath_common *common;
@@ -672,6 +692,11 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid)
ath9k_init_channels_rates(priv);
ath9k_init_misc(priv);
+ if (product && strncmp(product, ATH_HTC_BTCOEX_PRODUCT_ID, 5) == 0) {
+ ah->btcoex_hw.scheme = ATH_BTCOEX_CFG_3WIRE;
+ ath9k_init_btcoex(priv);
+ }
+
return 0;
err_queues:
@@ -715,18 +740,18 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
hw->extra_tx_headroom = sizeof(struct tx_frame_hdr) +
sizeof(struct htc_frame_hdr) + 4;
- if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes))
+ if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&priv->sbands[IEEE80211_BAND_2GHZ];
- if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes))
+ if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&priv->sbands[IEEE80211_BAND_5GHZ];
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
- if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes))
+ if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
setup_ht_cap(priv,
&priv->sbands[IEEE80211_BAND_2GHZ].ht_cap);
- if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes))
+ if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
setup_ht_cap(priv,
&priv->sbands[IEEE80211_BAND_5GHZ].ht_cap);
}
@@ -734,7 +759,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
}
-static int ath9k_init_device(struct ath9k_htc_priv *priv, u16 devid)
+static int ath9k_init_device(struct ath9k_htc_priv *priv,
+ u16 devid, char *product)
{
struct ieee80211_hw *hw = priv->hw;
struct ath_common *common;
@@ -743,7 +769,7 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, u16 devid)
struct ath_regulatory *reg;
/* Bring up device */
- error = ath9k_init_priv(priv, devid);
+ error = ath9k_init_priv(priv, devid, product);
if (error != 0)
goto err_init;
@@ -801,7 +827,7 @@ err_init:
}
int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
- u16 devid)
+ u16 devid, char *product)
{
struct ieee80211_hw *hw;
struct ath9k_htc_priv *priv;
@@ -835,7 +861,7 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
/* The device may have been unplugged earlier. */
priv->op_flags &= ~OP_UNPLUGGED;
- ret = ath9k_init_device(priv, devid);
+ ret = ath9k_init_device(priv, devid, product);
if (ret)
goto err_init;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index bc2ca7d898e9..9a3be8da755d 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -137,8 +137,6 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
if (priv->op_flags & OP_FULL_RESET)
fastcc = false;
- /* Fiddle around with fastcc later on, for now just use full reset */
- fastcc = false;
ath9k_htc_ps_wakeup(priv);
htc_stop(priv->htc);
WMI_CMD(WMI_DISABLE_INTR_CMDID);
@@ -146,9 +144,10 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
WMI_CMD(WMI_STOP_RECV_CMDID);
ath_print(common, ATH_DBG_CONFIG,
- "(%u MHz) -> (%u MHz), HT: %d, HT40: %d\n",
+ "(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n",
priv->ah->curchan->channel,
- channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf));
+ channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf),
+ fastcc);
caldata = &priv->caldata[channel->hw_value];
ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
@@ -764,23 +763,12 @@ void ath9k_ani_work(struct work_struct *work)
ath9k_hw_ani_monitor(ah, ah->curchan);
/* Perform calibration if necessary */
- if (longcal || shortcal) {
+ if (longcal || shortcal)
common->ani.caldone =
ath9k_hw_calibrate(ah, ah->curchan,
common->rx_chainmask,
longcal);
- if (longcal)
- common->ani.noise_floor =
- ath9k_hw_getchan_noise(ah, ah->curchan);
-
- ath_print(common, ATH_DBG_ANI,
- " calibrate chan %u/%x nf: %d\n",
- ah->curchan->channel,
- ah->curchan->channelFlags,
- common->ani.noise_floor);
- }
-
ath9k_htc_ps_restore(priv);
}
@@ -1213,6 +1201,12 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
ieee80211_wake_queues(hw);
+ if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) {
+ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+ AR_STOMP_LOW_WLAN_WGHT);
+ ath9k_hw_btcoex_enable(ah);
+ ath_htc_resume_btcoex_work(priv);
+ }
mutex_unlock(&priv->mutex);
return ret;
@@ -1236,7 +1230,6 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
/* Cancel all the running timers/work .. */
cancel_work_sync(&priv->ps_work);
- cancel_delayed_work_sync(&priv->ath9k_ani_work);
cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
ath9k_led_stop_brightness(priv);
@@ -1257,6 +1250,12 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
"Monitor interface removed\n");
}
+ if (ah->btcoex_hw.enabled) {
+ ath9k_hw_btcoex_disable(ah);
+ if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath_htc_cancel_btcoex_work(priv);
+ }
+
ath9k_hw_phy_disable(ah);
ath9k_hw_disable(ah);
ath9k_hw_configpcipowersave(ah, 1, 1);
@@ -1458,6 +1457,7 @@ out:
FIF_PSPOLL | \
FIF_OTHER_BSS | \
FIF_BCN_PRBRESP_PROMISC | \
+ FIF_PROBE_REQ | \
FIF_FCSFAIL)
static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
@@ -1583,20 +1583,21 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
switch (cmd) {
case SET_KEY:
- ret = ath9k_cmn_key_config(common, vif, sta, key);
+ ret = ath_key_config(common, vif, sta, key);
if (ret >= 0) {
key->hw_key_idx = ret;
/* push IV and Michael MIC generation to stack */
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- if (key->alg == ALG_TKIP)
+ if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
- if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
+ if (priv->ah->sw_mgmt_crypto &&
+ key->cipher == WLAN_CIPHER_SUITE_CCMP)
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
ret = 0;
}
break;
case DISABLE_KEY:
- ath9k_cmn_key_delete(common, key);
+ ath_key_delete(common, key);
break;
default:
ret = -EINVAL;
@@ -1777,7 +1778,8 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
priv->op_flags |= OP_SCANNING;
spin_unlock_bh(&priv->beacon_lock);
cancel_work_sync(&priv->ps_work);
- cancel_delayed_work_sync(&priv->ath9k_ani_work);
+ if (priv->op_flags & OP_ASSOCIATED)
+ cancel_delayed_work_sync(&priv->ath9k_ani_work);
mutex_unlock(&priv->mutex);
}
@@ -1791,9 +1793,10 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
priv->op_flags &= ~OP_SCANNING;
spin_unlock_bh(&priv->beacon_lock);
priv->op_flags |= OP_FULL_RESET;
- if (priv->op_flags & OP_ASSOCIATED)
+ if (priv->op_flags & OP_ASSOCIATED) {
ath9k_htc_beacon_config(priv, priv->vif);
- ath_start_ani(priv);
+ ath_start_ani(priv);
+ }
ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 2a6e45a293a9..3d19b5bc937f 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -369,8 +369,7 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
| ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
| ATH9K_RX_FILTER_MCAST;
- /* If not a STA, enable processing of Probe Requests */
- if (ah->opmode != NL80211_IFTYPE_STATION)
+ if (priv->rxfilter & FIF_PROBE_REQ)
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
/*
@@ -415,8 +414,7 @@ static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv)
ath9k_hw_setrxfilter(ah, rfilt);
/* configure bssid mask */
- if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
- ath_hw_setbssidmask(common);
+ ath_hw_setbssidmask(common);
/* configure operational mode */
ath9k_hw_setopmode(ah);
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index 705c0f342e1c..861ec9269309 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -462,9 +462,9 @@ void ath9k_htc_hw_free(struct htc_target *htc)
}
int ath9k_htc_hw_init(struct htc_target *target,
- struct device *dev, u16 devid)
+ struct device *dev, u16 devid, char *product)
{
- if (ath9k_htc_probe_device(target, dev, devid)) {
+ if (ath9k_htc_probe_device(target, dev, devid, product)) {
printk(KERN_ERR "Failed to initialize the device\n");
return -ENODEV;
}
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h
index faba6790328b..07b6509d5896 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.h
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.h
@@ -239,7 +239,7 @@ struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
struct device *dev);
void ath9k_htc_hw_free(struct htc_target *htc);
int ath9k_htc_hw_init(struct htc_target *target,
- struct device *dev, u16 devid);
+ struct device *dev, u16 devid, char *product);
void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug);
#endif /* HTC_HST_H */
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index ffecbadaea4a..0a4ad348b699 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -128,17 +128,6 @@ static inline void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds,
ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf);
}
-static inline void ath9k_hw_procmibevent(struct ath_hw *ah)
-{
- ath9k_hw_ops(ah)->ani_proc_mib_event(ah);
-}
-
-static inline void ath9k_hw_ani_monitor(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- ath9k_hw_ops(ah)->ani_monitor(ah, chan);
-}
-
/* Private hardware call ops */
/* PHY ops */
@@ -276,15 +265,4 @@ static inline void ath9k_hw_setup_calibration(struct ath_hw *ah,
ath9k_hw_private_ops(ah)->setup_calibration(ah, currCal);
}
-static inline bool ath9k_hw_iscal_supported(struct ath_hw *ah,
- enum ath9k_cal_types calType)
-{
- return ath9k_hw_private_ops(ah)->iscal_supported(ah, calType);
-}
-
-static inline void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
-{
- ath9k_hw_private_ops(ah)->ani_reset(ah, is_scanning);
-}
-
#endif /* ATH9K_HW_OPS_H */
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 3384ca164562..cc13ee117823 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -88,29 +88,32 @@ static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah)
/* Helper Functions */
/********************/
-static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs)
+static void ath9k_hw_set_clockrate(struct ath_hw *ah)
{
struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
+ struct ath_common *common = ath9k_hw_common(ah);
+ unsigned int clockrate;
if (!ah->curchan) /* should really check for CCK instead */
- return usecs *ATH9K_CLOCK_RATE_CCK;
- if (conf->channel->band == IEEE80211_BAND_2GHZ)
- return usecs *ATH9K_CLOCK_RATE_2GHZ_OFDM;
-
- if (ah->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK)
- return usecs * ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM;
+ clockrate = ATH9K_CLOCK_RATE_CCK;
+ else if (conf->channel->band == IEEE80211_BAND_2GHZ)
+ clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM;
+ else if (ah->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK)
+ clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM;
else
- return usecs * ATH9K_CLOCK_RATE_5GHZ_OFDM;
+ clockrate = ATH9K_CLOCK_RATE_5GHZ_OFDM;
+
+ if (conf_is_ht40(conf))
+ clockrate *= 2;
+
+ common->clockrate = clockrate;
}
static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs)
{
- struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
+ struct ath_common *common = ath9k_hw_common(ah);
- if (conf_is_ht40(conf))
- return ath9k_hw_mac_clks(ah, usecs) * 2;
- else
- return ath9k_hw_mac_clks(ah, usecs);
+ return usecs * common->clockrate;
}
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
@@ -299,7 +302,6 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
}
/* This should work for all families including legacy */
@@ -371,10 +373,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
ah->config.pcie_clock_req = 0;
ah->config.pcie_waen = 0;
ah->config.analog_shiftreg = 1;
- ah->config.ofdm_trig_low = 200;
- ah->config.ofdm_trig_high = 500;
- ah->config.cck_trig_high = 200;
- ah->config.cck_trig_low = 100;
ah->config.enable_ani = true;
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
@@ -565,7 +563,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
ath9k_hw_init_cal_settings(ah);
ah->ani_function = ATH9K_ANI_ALL;
- if (AR_SREV_9280_10_OR_LATER(ah) && !AR_SREV_9300_20_OR_LATER(ah))
+ if (AR_SREV_9280_20_OR_LATER(ah) && !AR_SREV_9300_20_OR_LATER(ah))
ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
if (!AR_SREV_9300_20_OR_LATER(ah))
ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
@@ -676,7 +674,6 @@ static void ath9k_hw_init_qos(struct ath_hw *ah)
REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
}
static void ath9k_hw_init_pll(struct ath_hw *ah,
@@ -741,7 +738,6 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
}
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
if (AR_SREV_9300_20_OR_LATER(ah)) {
REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE, 0);
@@ -885,7 +881,6 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
/*
* Restore TX Trigger Level to its pre-reset value.
@@ -933,7 +928,6 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
}
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
if (AR_SREV_9300_20_OR_LATER(ah))
ath9k_hw_reset_txstatus_ring(ah);
@@ -1031,7 +1025,6 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
REG_WRITE(ah, AR_RTC_RC, rst_flags);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
udelay(50);
@@ -1070,7 +1063,6 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
udelay(2);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
if (!AR_SREV_9300_20_OR_LATER(ah))
udelay(2);
@@ -1167,6 +1159,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
"Failed to set channel\n");
return false;
}
+ ath9k_hw_set_clockrate(ah);
ah->eep_ops->set_txpower(ah, chan,
ath9k_regd_get_ctl(regulatory, chan),
@@ -1190,7 +1183,7 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
int count = 50;
u32 reg;
- if (AR_SREV_9285_10_OR_LATER(ah))
+ if (AR_SREV_9285_12_OR_LATER(ah))
return true;
do {
@@ -1239,7 +1232,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
return -EIO;
- if (curchan && !ah->chip_fullsleep && ah->caldata)
+ if (curchan && !ah->chip_fullsleep)
ath9k_hw_getnf(ah, curchan);
ah->caldata = caldata;
@@ -1258,11 +1251,13 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
(chan->channel != ah->curchan->channel) &&
((chan->channelFlags & CHANNEL_ALL) ==
(ah->curchan->channelFlags & CHANNEL_ALL)) &&
- !AR_SREV_9280(ah)) {
+ (!AR_SREV_9280(ah) || AR_DEVID_7010(ah))) {
if (ath9k_hw_channel_change(ah, chan)) {
ath9k_hw_loadnf(ah, ah->curchan);
ath9k_hw_start_nfcal(ah, true);
+ if (AR_SREV_9271(ah))
+ ar9002_hw_load_ani_reg(ah, chan);
return 0;
}
}
@@ -1310,7 +1305,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (tsf)
ath9k_hw_settsf64(ah, tsf);
- if (AR_SREV_9280_10_OR_LATER(ah))
+ if (AR_SREV_9280_20_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
if (!AR_SREV_9300_20_OR_LATER(ah))
@@ -1372,19 +1367,19 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
r = ath9k_hw_rf_set_freq(ah, chan);
if (r)
return r;
+ ath9k_hw_set_clockrate(ah);
+
ENABLE_REGWRITE_BUFFER(ah);
for (i = 0; i < AR_NUM_DCU; i++)
REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
ah->intr_txqs = 0;
for (i = 0; i < ah->caps.total_queues; i++)
@@ -1432,7 +1427,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
/*
* For big endian systems turn on swapping for descriptors
@@ -1474,283 +1468,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
}
EXPORT_SYMBOL(ath9k_hw_reset);
-/************************/
-/* Key Cache Management */
-/************************/
-
-bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
-{
- u32 keyType;
-
- if (entry >= ah->caps.keycache_size) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
- "keychache entry %u out of range\n", entry);
- return false;
- }
-
- keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
-
- REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
- REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
- REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
- REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
-
- if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
- u16 micentry = entry + 64;
-
- REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
-
- }
-
- return true;
-}
-EXPORT_SYMBOL(ath9k_hw_keyreset);
-
-static bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
-{
- u32 macHi, macLo;
- u32 unicast_flag = AR_KEYTABLE_VALID;
-
- if (entry >= ah->caps.keycache_size) {
- ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
- "keychache entry %u out of range\n", entry);
- return false;
- }
-
- if (mac != NULL) {
- /*
- * AR_KEYTABLE_VALID indicates that the address is a unicast
- * address, which must match the transmitter address for
- * decrypting frames.
- * Not setting this bit allows the hardware to use the key
- * for multicast frame decryption.
- */
- if (mac[0] & 0x01)
- unicast_flag = 0;
-
- macHi = (mac[5] << 8) | mac[4];
- macLo = (mac[3] << 24) |
- (mac[2] << 16) |
- (mac[1] << 8) |
- mac[0];
- macLo >>= 1;
- macLo |= (macHi & 1) << 31;
- macHi >>= 1;
- } else {
- macLo = macHi = 0;
- }
- REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
- REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag);
-
- return true;
-}
-
-bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
- const struct ath9k_keyval *k,
- const u8 *mac)
-{
- const struct ath9k_hw_capabilities *pCap = &ah->caps;
- struct ath_common *common = ath9k_hw_common(ah);
- u32 key0, key1, key2, key3, key4;
- u32 keyType;
-
- if (entry >= pCap->keycache_size) {
- ath_print(common, ATH_DBG_FATAL,
- "keycache entry %u out of range\n", entry);
- return false;
- }
-
- switch (k->kv_type) {
- case ATH9K_CIPHER_AES_OCB:
- keyType = AR_KEYTABLE_TYPE_AES;
- break;
- case ATH9K_CIPHER_AES_CCM:
- if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
- ath_print(common, ATH_DBG_ANY,
- "AES-CCM not supported by mac rev 0x%x\n",
- ah->hw_version.macRev);
- return false;
- }
- keyType = AR_KEYTABLE_TYPE_CCM;
- break;
- case ATH9K_CIPHER_TKIP:
- keyType = AR_KEYTABLE_TYPE_TKIP;
- if (ATH9K_IS_MIC_ENABLED(ah)
- && entry + 64 >= pCap->keycache_size) {
- ath_print(common, ATH_DBG_ANY,
- "entry %u inappropriate for TKIP\n", entry);
- return false;
- }
- break;
- case ATH9K_CIPHER_WEP:
- if (k->kv_len < WLAN_KEY_LEN_WEP40) {
- ath_print(common, ATH_DBG_ANY,
- "WEP key length %u too small\n", k->kv_len);
- return false;
- }
- if (k->kv_len <= WLAN_KEY_LEN_WEP40)
- keyType = AR_KEYTABLE_TYPE_40;
- else if (k->kv_len <= WLAN_KEY_LEN_WEP104)
- keyType = AR_KEYTABLE_TYPE_104;
- else
- keyType = AR_KEYTABLE_TYPE_128;
- break;
- case ATH9K_CIPHER_CLR:
- keyType = AR_KEYTABLE_TYPE_CLR;
- break;
- default:
- ath_print(common, ATH_DBG_FATAL,
- "cipher %u not supported\n", k->kv_type);
- return false;
- }
-
- key0 = get_unaligned_le32(k->kv_val + 0);
- key1 = get_unaligned_le16(k->kv_val + 4);
- key2 = get_unaligned_le32(k->kv_val + 6);
- key3 = get_unaligned_le16(k->kv_val + 10);
- key4 = get_unaligned_le32(k->kv_val + 12);
- if (k->kv_len <= WLAN_KEY_LEN_WEP104)
- key4 &= 0xff;
-
- /*
- * Note: Key cache registers access special memory area that requires
- * two 32-bit writes to actually update the values in the internal
- * memory. Consequently, the exact order and pairs used here must be
- * maintained.
- */
-
- if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
- u16 micentry = entry + 64;
-
- /*
- * Write inverted key[47:0] first to avoid Michael MIC errors
- * on frames that could be sent or received at the same time.
- * The correct key will be written in the end once everything
- * else is ready.
- */
- REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
- REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
-
- /* Write key[95:48] */
- REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
- REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
-
- /* Write key[127:96] and key type */
- REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
- REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
-
- /* Write MAC address for the entry */
- (void) ath9k_hw_keysetmac(ah, entry, mac);
-
- if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) {
- /*
- * TKIP uses two key cache entries:
- * Michael MIC TX/RX keys in the same key cache entry
- * (idx = main index + 64):
- * key0 [31:0] = RX key [31:0]
- * key1 [15:0] = TX key [31:16]
- * key1 [31:16] = reserved
- * key2 [31:0] = RX key [63:32]
- * key3 [15:0] = TX key [15:0]
- * key3 [31:16] = reserved
- * key4 [31:0] = TX key [63:32]
- */
- u32 mic0, mic1, mic2, mic3, mic4;
-
- mic0 = get_unaligned_le32(k->kv_mic + 0);
- mic2 = get_unaligned_le32(k->kv_mic + 4);
- mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
- mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
- mic4 = get_unaligned_le32(k->kv_txmic + 4);
-
- /* Write RX[31:0] and TX[31:16] */
- REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
- REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
-
- /* Write RX[63:32] and TX[15:0] */
- REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
- REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
-
- /* Write TX[63:32] and keyType(reserved) */
- REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
- REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
- AR_KEYTABLE_TYPE_CLR);
-
- } else {
- /*
- * TKIP uses four key cache entries (two for group
- * keys):
- * Michael MIC TX/RX keys are in different key cache
- * entries (idx = main index + 64 for TX and
- * main index + 32 + 96 for RX):
- * key0 [31:0] = TX/RX MIC key [31:0]
- * key1 [31:0] = reserved
- * key2 [31:0] = TX/RX MIC key [63:32]
- * key3 [31:0] = reserved
- * key4 [31:0] = reserved
- *
- * Upper layer code will call this function separately
- * for TX and RX keys when these registers offsets are
- * used.
- */
- u32 mic0, mic2;
-
- mic0 = get_unaligned_le32(k->kv_mic + 0);
- mic2 = get_unaligned_le32(k->kv_mic + 4);
-
- /* Write MIC key[31:0] */
- REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
- REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
-
- /* Write MIC key[63:32] */
- REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
- REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
-
- /* Write TX[63:32] and keyType(reserved) */
- REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
- REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
- AR_KEYTABLE_TYPE_CLR);
- }
-
- /* MAC address registers are reserved for the MIC entry */
- REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
- REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
-
- /*
- * Write the correct (un-inverted) key[47:0] last to enable
- * TKIP now that all other registers are set with correct
- * values.
- */
- REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
- REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
- } else {
- /* Write key[47:0] */
- REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
- REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
-
- /* Write key[95:48] */
- REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
- REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
-
- /* Write key[127:96] and key type */
- REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
- REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
-
- /* Write MAC address for the entry */
- (void) ath9k_hw_keysetmac(ah, entry, mac);
- }
-
- return true;
-}
-EXPORT_SYMBOL(ath9k_hw_set_keycache_entry);
-
/******************************/
/* Power Management (Chipset) */
/******************************/
@@ -1959,7 +1676,6 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period));
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
beacon_period &= ~ATH9K_BEACON_ENA;
if (beacon_period & ATH9K_BEACON_RESET_TSF) {
@@ -1987,7 +1703,6 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD));
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
REG_RMW_FIELD(ah, AR_RSSI_THR,
AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold);
@@ -2033,7 +1748,6 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
REG_SET_BIT(ah, AR_TIMER_MODE,
AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN |
@@ -2056,12 +1770,13 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
u16 capField = 0, eeval;
+ u8 ant_div_ctl1;
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_10_OR_LATER(ah))
+ if (AR_SREV_9285_12_OR_LATER(ah))
eeval |= AR9285_RDEXT_DEFAULT;
regulatory->current_rd_ext = eeval;
@@ -2085,37 +1800,11 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
return -EINVAL;
}
- bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX);
+ if (eeval & AR5416_OPFLAGS_11A)
+ pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
- if (eeval & AR5416_OPFLAGS_11A) {
- set_bit(ATH9K_MODE_11A, pCap->wireless_modes);
- if (ah->config.ht_enable) {
- if (!(eeval & AR5416_OPFLAGS_N_5G_HT20))
- set_bit(ATH9K_MODE_11NA_HT20,
- pCap->wireless_modes);
- if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) {
- set_bit(ATH9K_MODE_11NA_HT40PLUS,
- pCap->wireless_modes);
- set_bit(ATH9K_MODE_11NA_HT40MINUS,
- pCap->wireless_modes);
- }
- }
- }
-
- if (eeval & AR5416_OPFLAGS_11G) {
- set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
- if (ah->config.ht_enable) {
- if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
- set_bit(ATH9K_MODE_11NG_HT20,
- pCap->wireless_modes);
- if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) {
- set_bit(ATH9K_MODE_11NG_HT40PLUS,
- pCap->wireless_modes);
- set_bit(ATH9K_MODE_11NG_HT40MINUS,
- pCap->wireless_modes);
- }
- }
- }
+ if (eeval & AR5416_OPFLAGS_11G)
+ pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK);
/*
@@ -2131,8 +1820,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
/* Use rx_chainmask from EEPROM. */
pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK);
- if (!(AR_SREV_9280(ah) && (ah->hw_version.macRev == 0)))
- ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA;
+ ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA;
pCap->low_2ghz_chan = 2312;
pCap->high_2ghz_chan = 2732;
@@ -2140,24 +1828,13 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->low_5ghz_chan = 4920;
pCap->high_5ghz_chan = 6100;
- pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP;
- pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP;
- pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM;
-
- pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP;
- pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP;
- pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM;
+ common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
if (ah->config.ht_enable)
pCap->hw_caps |= ATH9K_HW_CAP_HT;
else
pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
- pCap->hw_caps |= ATH9K_HW_CAP_GTT;
- pCap->hw_caps |= ATH9K_HW_CAP_VEOL;
- pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK;
- pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH;
-
if (capField & AR_EEPROM_EEPCAP_MAXQCU)
pCap->total_queues =
MS(capField, AR_EEPROM_EEPCAP_MAXQCU);
@@ -2170,8 +1847,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
else
pCap->keycache_size = AR_KEYTABLE_SIZE;
- pCap->hw_caps |= ATH9K_HW_CAP_FASTCC;
-
if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1;
else
@@ -2181,9 +1856,9 @@ 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_9285_10_OR_LATER(ah))
+ else if (AR_SREV_9285_12_OR_LATER(ah))
pCap->num_gpio_pins = AR9285_NUM_GPIO;
- else if (AR_SREV_9280_10_OR_LATER(ah))
+ else if (AR_SREV_9280_20_OR_LATER(ah))
pCap->num_gpio_pins = AR928X_NUM_GPIO;
else
pCap->num_gpio_pins = AR_NUM_GPIO;
@@ -2240,7 +1915,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->num_antcfg_2ghz =
ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
- if (AR_SREV_9280_10_OR_LATER(ah) &&
+ if (AR_SREV_9280_20_OR_LATER(ah) &&
ath9k_hw_btcoex_supported(ah)) {
btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO;
btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO;
@@ -2277,9 +1952,17 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if (AR_SREV_9300_20_OR_LATER(ah))
pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED;
- if (AR_SREV_9287_10_OR_LATER(ah) || AR_SREV_9271(ah))
+ if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah))
pCap->hw_caps |= ATH9K_HW_CAP_SGI_20;
+ if (AR_SREV_9285(ah))
+ if (ah->eep_ops->get_eeprom(ah, EEP_MODAL_VER) >= 3) {
+ ant_div_ctl1 =
+ ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
+ if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1))
+ pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
+ }
+
return 0;
}
@@ -2353,11 +2036,11 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
return MS_REG_READ(AR9300, gpio) != 0;
else if (AR_SREV_9271(ah))
return MS_REG_READ(AR9271, gpio) != 0;
- else if (AR_SREV_9287_10_OR_LATER(ah))
+ else if (AR_SREV_9287_11_OR_LATER(ah))
return MS_REG_READ(AR9287, gpio) != 0;
- else if (AR_SREV_9285_10_OR_LATER(ah))
+ else if (AR_SREV_9285_12_OR_LATER(ah))
return MS_REG_READ(AR9285, gpio) != 0;
- else if (AR_SREV_9280_10_OR_LATER(ah))
+ else if (AR_SREV_9280_20_OR_LATER(ah))
return MS_REG_READ(AR928X, gpio) != 0;
else
return MS_REG_READ(AR, gpio) != 0;
@@ -2456,7 +2139,6 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
}
EXPORT_SYMBOL(ath9k_hw_setrxfilter);
@@ -2854,7 +2536,7 @@ void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len)
int used;
/* chipsets >= AR9280 are single-chip */
- if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
used = snprintf(hw_name, len,
"Atheros AR%s Rev:%x",
ath9k_hw_mac_bb_name(ah->hw_version.macVersion),
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 399f7c1283cd..d032939768b0 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -61,6 +61,8 @@
#define ATH9K_RSSI_BAD -128
+#define ATH9K_NUM_CHANNELS 38
+
/* Register read/write primitives */
#define REG_WRITE(_ah, _reg, _val) \
ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg))
@@ -70,19 +72,13 @@
#define ENABLE_REGWRITE_BUFFER(_ah) \
do { \
- if (AR_SREV_9271(_ah)) \
+ if (ath9k_hw_common(_ah)->ops->enable_write_buffer) \
ath9k_hw_common(_ah)->ops->enable_write_buffer((_ah)); \
} while (0)
-#define DISABLE_REGWRITE_BUFFER(_ah) \
- do { \
- if (AR_SREV_9271(_ah)) \
- ath9k_hw_common(_ah)->ops->disable_write_buffer((_ah)); \
- } while (0)
-
#define REGWRITE_BUFFER_FLUSH(_ah) \
do { \
- if (AR_SREV_9271(_ah)) \
+ if (ath9k_hw_common(_ah)->ops->write_flush) \
ath9k_hw_common(_ah)->ops->write_flush((_ah)); \
} while (0)
@@ -168,47 +164,26 @@ enum ath_ini_subsys {
ATH_INI_NUM_SPLIT,
};
-enum wireless_mode {
- ATH9K_MODE_11A = 0,
- ATH9K_MODE_11G,
- ATH9K_MODE_11NA_HT20,
- ATH9K_MODE_11NG_HT20,
- ATH9K_MODE_11NA_HT40PLUS,
- ATH9K_MODE_11NA_HT40MINUS,
- ATH9K_MODE_11NG_HT40PLUS,
- ATH9K_MODE_11NG_HT40MINUS,
- ATH9K_MODE_MAX,
-};
-
enum ath9k_hw_caps {
- ATH9K_HW_CAP_MIC_AESCCM = BIT(0),
- ATH9K_HW_CAP_MIC_CKIP = BIT(1),
- ATH9K_HW_CAP_MIC_TKIP = BIT(2),
- ATH9K_HW_CAP_CIPHER_AESCCM = BIT(3),
- ATH9K_HW_CAP_CIPHER_CKIP = BIT(4),
- ATH9K_HW_CAP_CIPHER_TKIP = BIT(5),
- ATH9K_HW_CAP_VEOL = BIT(6),
- ATH9K_HW_CAP_BSSIDMASK = BIT(7),
- ATH9K_HW_CAP_MCAST_KEYSEARCH = BIT(8),
- ATH9K_HW_CAP_HT = BIT(9),
- ATH9K_HW_CAP_GTT = BIT(10),
- ATH9K_HW_CAP_FASTCC = BIT(11),
- ATH9K_HW_CAP_RFSILENT = BIT(12),
- ATH9K_HW_CAP_CST = BIT(13),
- ATH9K_HW_CAP_ENHANCEDPM = BIT(14),
- ATH9K_HW_CAP_AUTOSLEEP = BIT(15),
- ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(16),
- ATH9K_HW_CAP_EDMA = BIT(17),
- ATH9K_HW_CAP_RAC_SUPPORTED = BIT(18),
- ATH9K_HW_CAP_LDPC = BIT(19),
- ATH9K_HW_CAP_FASTCLOCK = BIT(20),
- ATH9K_HW_CAP_SGI_20 = BIT(21),
- ATH9K_HW_CAP_PAPRD = BIT(22),
+ ATH9K_HW_CAP_HT = BIT(0),
+ ATH9K_HW_CAP_RFSILENT = BIT(1),
+ ATH9K_HW_CAP_CST = BIT(2),
+ ATH9K_HW_CAP_ENHANCEDPM = BIT(3),
+ ATH9K_HW_CAP_AUTOSLEEP = BIT(4),
+ ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(5),
+ ATH9K_HW_CAP_EDMA = BIT(6),
+ ATH9K_HW_CAP_RAC_SUPPORTED = BIT(7),
+ ATH9K_HW_CAP_LDPC = BIT(8),
+ ATH9K_HW_CAP_FASTCLOCK = BIT(9),
+ ATH9K_HW_CAP_SGI_20 = BIT(10),
+ ATH9K_HW_CAP_PAPRD = BIT(11),
+ ATH9K_HW_CAP_ANT_DIV_COMB = BIT(12),
+ ATH9K_HW_CAP_2GHZ = BIT(13),
+ ATH9K_HW_CAP_5GHZ = BIT(14),
};
struct ath9k_hw_capabilities {
u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */
- DECLARE_BITMAP(wireless_modes, ATH9K_MODE_MAX); /* ATH9K_MODE_* */
u16 total_queues;
u16 keycache_size;
u16 low_5ghz_chan, high_5ghz_chan;
@@ -352,9 +327,9 @@ struct ath9k_hw_cal_data {
int32_t CalValid;
int8_t iCoff;
int8_t qCoff;
- int16_t rawNoiseFloor;
bool paprd_done;
bool nfcal_pending;
+ bool nfcal_interference;
u16 small_signal_gain[AR9300_MAX_CHAINS];
u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
@@ -362,9 +337,11 @@ struct ath9k_hw_cal_data {
struct ath9k_channel {
struct ieee80211_channel *chan;
+ struct ar5416AniState ani;
u16 channel;
u32 channelFlags;
u32 chanmode;
+ s16 noisefloor;
};
#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
@@ -494,6 +471,12 @@ struct ath_gen_timer_table {
} timer_mask;
};
+struct ath_hw_antcomb_conf {
+ u8 main_lna_conf;
+ u8 alt_lna_conf;
+ u8 fast_div_bias;
+};
+
/**
* struct ath_hw_private_ops - callbacks used internally by hardware code
*
@@ -517,14 +500,6 @@ struct ath_gen_timer_table {
* @setup_calibration: set up calibration
* @iscal_supported: used to query if a type of calibration is supported
*
- * @ani_reset: reset ANI parameters to default values
- * @ani_lower_immunity: lower the noise immunity level. The level controls
- * the power-based packet detection on hardware. If a power jump is
- * detected the adapter takes it as an indication that a packet has
- * arrived. The level ranges from 0-5. Each level corresponds to a
- * few dB more of noise immunity. If you have a strong time-varying
- * interference that is causing false detections (OFDM timing errors or
- * CCK timing errors) the level can be increased.
* @ani_cache_ini_regs: cache the values for ANI from the initial
* register settings through the register initialization.
*/
@@ -538,8 +513,6 @@ struct ath_hw_private_ops {
bool (*macversion_supported)(u32 macversion);
void (*setup_calibration)(struct ath_hw *ah,
struct ath9k_cal_list *currCal);
- bool (*iscal_supported)(struct ath_hw *ah,
- enum ath9k_cal_types calType);
/* PHY ops */
int (*rf_set_freq)(struct ath_hw *ah,
@@ -571,8 +544,6 @@ struct ath_hw_private_ops {
void (*do_getnf)(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]);
/* ANI */
- void (*ani_reset)(struct ath_hw *ah, bool is_scanning);
- void (*ani_lower_immunity)(struct ath_hw *ah);
void (*ani_cache_ini_regs)(struct ath_hw *ah);
};
@@ -584,11 +555,6 @@ struct ath_hw_private_ops {
*
* @config_pci_powersave:
* @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
- *
- * @ani_proc_mib_event: process MIB events, this would happen upon specific ANI
- * thresholds being reached or having overflowed.
- * @ani_monitor: called periodically by the core driver to collect
- * MIB stats and adjust ANI if specific thresholds have been reached.
*/
struct ath_hw_ops {
void (*config_pci_powersave)(struct ath_hw *ah,
@@ -629,9 +595,6 @@ struct ath_hw_ops {
u32 burstDuration);
void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds,
u32 vmf);
-
- void (*ani_proc_mib_event)(struct ath_hw *ah);
- void (*ani_monitor)(struct ath_hw *ah, struct ath9k_channel *chan);
};
struct ath_nf_limits {
@@ -646,7 +609,7 @@ struct ath_hw {
struct ath9k_hw_version hw_version;
struct ath9k_ops_config config;
struct ath9k_hw_capabilities caps;
- struct ath9k_channel channels[38];
+ struct ath9k_channel channels[ATH9K_NUM_CHANNELS];
struct ath9k_channel *curchan;
union {
@@ -692,10 +655,9 @@ struct ath_hw {
u32 atim_window;
/* Calibration */
- enum ath9k_cal_types supp_cals;
+ u32 supp_cals;
struct ath9k_cal_list iq_caldata;
struct ath9k_cal_list adcgain_caldata;
- struct ath9k_cal_list adcdc_calinitdata;
struct ath9k_cal_list adcdc_caldata;
struct ath9k_cal_list tempCompCalData;
struct ath9k_cal_list *cal_list;
@@ -764,8 +726,6 @@ struct ath_hw {
/* ANI */
u32 proc_phyerr;
u32 aniperiod;
- struct ar5416AniState *curani;
- struct ar5416AniState ani[255];
int totalSizeDesired[5];
int coarse_high[5];
int coarse_low[5];
@@ -873,12 +833,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
int ath9k_hw_fill_cap_info(struct ath_hw *ah);
u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan);
-/* Key Cache Management */
-bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry);
-bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
- const struct ath9k_keyval *k,
- const u8 *mac);
-
/* GPIO / RFKILL / Antennae */
void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio);
u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio);
@@ -887,6 +841,10 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val);
u32 ath9k_hw_getdefantenna(struct ath_hw *ah);
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
+void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf);
+void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf);
/* General Operation */
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
@@ -984,6 +942,7 @@ void ar9003_hw_attach_calib_ops(struct ath_hw *ah);
void ar9002_hw_attach_ops(struct ath_hw *ah);
void ar9003_hw_attach_ops(struct ath_hw *ah);
+void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan);
/*
* ANI work can be shared between all families but a next
* generation implementation of ANI will be used only for AR9003 only
@@ -992,8 +951,9 @@ void ar9003_hw_attach_ops(struct ath_hw *ah);
* older families (AR5008, AR9001, AR9002) by using modparam_force_new_ani.
*/
extern int modparam_force_new_ani;
-void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah);
-void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah);
+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
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 243c1775f343..95b41db0d86b 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -33,7 +33,7 @@ int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
-int led_blink = 1;
+int led_blink;
module_param_named(blink, led_blink, int, 0444);
MODULE_PARM_DESC(blink, "Enable LED blink on activity");
@@ -56,7 +56,7 @@ MODULE_PARM_DESC(blink, "Enable LED blink on activity");
* on 5 MHz steps, we support the channels which we know
* we have calibration data for all cards though to make
* this static */
-static struct ieee80211_channel ath9k_2ghz_chantable[] = {
+static const struct ieee80211_channel ath9k_2ghz_chantable[] = {
CHAN2G(2412, 0), /* Channel 1 */
CHAN2G(2417, 1), /* Channel 2 */
CHAN2G(2422, 2), /* Channel 3 */
@@ -77,7 +77,7 @@ static struct ieee80211_channel ath9k_2ghz_chantable[] = {
* on 5 MHz steps, we support the channels which we know
* we have calibration data for all cards though to make
* this static */
-static struct ieee80211_channel ath9k_5ghz_chantable[] = {
+static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
/* _We_ call this UNII 1 */
CHAN5G(5180, 14), /* Channel 36 */
CHAN5G(5200, 15), /* Channel 40 */
@@ -211,7 +211,7 @@ static void setup_ht_cap(struct ath_softc *sc,
else
max_streams = 2;
- if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
if (max_streams >= 2)
ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
@@ -381,7 +381,7 @@ static void ath9k_init_crypto(struct ath_softc *sc)
* reset the contents on initial power up.
*/
for (i = 0; i < common->keymax; i++)
- ath9k_hw_keyreset(sc->sc_ah, (u16) i);
+ ath_hw_keyreset(common, (u16) i);
/*
* Check whether the separate key cache entries
@@ -389,8 +389,8 @@ static void ath9k_init_crypto(struct ath_softc *sc)
* 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->splitmic = 1;
+ 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)
@@ -477,10 +477,21 @@ err:
return -EIO;
}
-static void ath9k_init_channels_rates(struct ath_softc *sc)
+static int ath9k_init_channels_rates(struct ath_softc *sc)
{
- if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) {
- sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable;
+ void *channels;
+
+ BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) +
+ ARRAY_SIZE(ath9k_5ghz_chantable) !=
+ ATH9K_NUM_CHANNELS);
+
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
+ channels = kmemdup(ath9k_2ghz_chantable,
+ sizeof(ath9k_2ghz_chantable), GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ sc->sbands[IEEE80211_BAND_2GHZ].channels = channels;
sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
ARRAY_SIZE(ath9k_2ghz_chantable);
@@ -489,8 +500,16 @@ static void ath9k_init_channels_rates(struct ath_softc *sc)
ARRAY_SIZE(ath9k_legacy_rates);
}
- if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) {
- sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable;
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
+ channels = kmemdup(ath9k_5ghz_chantable,
+ sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
+ if (!channels) {
+ if (sc->sbands[IEEE80211_BAND_2GHZ].channels)
+ kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels);
+ return -ENOMEM;
+ }
+
+ sc->sbands[IEEE80211_BAND_5GHZ].channels = channels;
sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
ARRAY_SIZE(ath9k_5ghz_chantable);
@@ -499,6 +518,7 @@ static void ath9k_init_channels_rates(struct ath_softc *sc)
sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
ARRAY_SIZE(ath9k_legacy_rates) - 4;
}
+ return 0;
}
static void ath9k_init_misc(struct ath_softc *sc)
@@ -506,7 +526,6 @@ static void ath9k_init_misc(struct ath_softc *sc)
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int i = 0;
- common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR;
setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
sc->config.txpowlimit = ATH_TXPOWER_MAX;
@@ -522,8 +541,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
ath9k_hw_set_diversity(sc->sc_ah, true);
sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah);
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
- memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
+ memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
sc->beacon.slottime = ATH9K_SLOT_TIME_9;
@@ -531,6 +549,9 @@ static void ath9k_init_misc(struct ath_softc *sc)
sc->beacon.bslot[i] = NULL;
sc->beacon.bslot_aphy[i] = NULL;
}
+
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
+ sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT;
}
static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
@@ -556,6 +577,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
common->hw = sc->hw;
common->priv = sc;
common->debug_mask = ath9k_debug;
+ spin_lock_init(&common->cc_lock);
spin_lock_init(&sc->wiphy_lock);
spin_lock_init(&sc->sc_resetlock);
@@ -593,8 +615,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
if (ret)
goto err_btcoex;
+ ret = ath9k_init_channels_rates(sc);
+ if (ret)
+ goto err_btcoex;
+
ath9k_init_crypto(sc);
- ath9k_init_channels_rates(sc);
ath9k_init_misc(sc);
return 0;
@@ -637,11 +662,13 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_WDS) |
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT);
- hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+ if (AR_SREV_5416(sc->sc_ah))
+ hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->queues = 4;
hw->max_rates = 4;
@@ -651,19 +678,21 @@ 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);
+#ifdef CONFIG_ATH9K_RATE_CONTROL
hw->rate_control_algorithm = "ath9k_rate_control";
+#endif
- if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes))
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&sc->sbands[IEEE80211_BAND_2GHZ];
- if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&sc->sbands[IEEE80211_BAND_5GHZ];
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
- if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes))
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
- if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
}
@@ -751,6 +780,12 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
{
int i = 0;
+ if (sc->sbands[IEEE80211_BAND_2GHZ].channels)
+ kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels);
+
+ if (sc->sbands[IEEE80211_BAND_5GHZ].channels)
+ kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels);
+
if ((sc->btcoex.no_stomp_timer) &&
sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index e955bb9d98cb..8c13479b17cd 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -40,7 +40,6 @@ static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
}
u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
@@ -492,8 +491,6 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
REG_WRITE(ah, AR_DMISC(q),
AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
- REGWRITE_BUFFER_FLUSH(ah);
-
if (qi->tqi_cbrPeriod) {
REG_WRITE(ah, AR_QCBRCFG(q),
SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
@@ -509,8 +506,6 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
AR_Q_RDYTIMECFG_EN);
}
- REGWRITE_BUFFER_FLUSH(ah);
-
REG_WRITE(ah, AR_DCHNTIME(q),
SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
(qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
@@ -530,7 +525,6 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
}
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
REG_WRITE(ah, AR_DMISC(q),
@@ -553,7 +547,6 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
| AR_D_MISC_POST_FR_BKOFF_DIS);
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
/*
* cwmin and cwmax should be 0 for beacon queue
@@ -585,7 +578,6 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
break;
case ATH9K_TX_QUEUE_PSPOLL:
@@ -711,8 +703,11 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
rs->rs_phyerr = phyerr;
} else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
rs->rs_status |= ATH9K_RXERR_DECRYPT;
- else if (ads.ds_rxstatus8 & AR_MichaelErr)
+ else if ((ads.ds_rxstatus8 & AR_MichaelErr) &&
+ rs->rs_keyix != ATH9K_RXKEYIX_INVALID)
rs->rs_status |= ATH9K_RXERR_MIC;
+ else if (ads.ds_rxstatus8 & AR_KeyMiss)
+ rs->rs_status |= ATH9K_RXERR_DECRYPT;
}
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 2633896d3998..7c1a34d64f6d 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -660,17 +660,6 @@ struct ath9k_11n_rate_series {
u32 RateFlags;
};
-struct ath9k_keyval {
- u8 kv_type;
- u8 kv_pad;
- u16 kv_len;
- u8 kv_val[16]; /* TK */
- u8 kv_mic[8]; /* Michael MIC key */
- u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware
- * supports both MIC keys in the same key cache entry;
- * in that case, kv_mic is the RX key) */
-};
-
enum ath9k_key_type {
ATH9K_KEY_TYPE_CLEAR,
ATH9K_KEY_TYPE_WEP,
@@ -678,16 +667,6 @@ enum ath9k_key_type {
ATH9K_KEY_TYPE_TKIP,
};
-enum ath9k_cipher {
- ATH9K_CIPHER_WEP = 0,
- ATH9K_CIPHER_AES_OCB = 1,
- ATH9K_CIPHER_AES_CCM = 2,
- ATH9K_CIPHER_CKIP = 3,
- ATH9K_CIPHER_TKIP = 4,
- ATH9K_CIPHER_CLR = 5,
- ATH9K_CIPHER_MIC = 127
-};
-
struct ath_hw;
struct ath9k_channel;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 3caa32316e7b..c6ec800d7a6b 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -18,36 +18,6 @@
#include "ath9k.h"
#include "btcoex.h"
-static void ath_cache_conf_rate(struct ath_softc *sc,
- struct ieee80211_conf *conf)
-{
- switch (conf->channel->band) {
- case IEEE80211_BAND_2GHZ:
- if (conf_is_ht20(conf))
- sc->cur_rate_mode = ATH9K_MODE_11NG_HT20;
- else if (conf_is_ht40_minus(conf))
- sc->cur_rate_mode = ATH9K_MODE_11NG_HT40MINUS;
- else if (conf_is_ht40_plus(conf))
- sc->cur_rate_mode = ATH9K_MODE_11NG_HT40PLUS;
- else
- sc->cur_rate_mode = ATH9K_MODE_11G;
- break;
- case IEEE80211_BAND_5GHZ:
- if (conf_is_ht20(conf))
- sc->cur_rate_mode = ATH9K_MODE_11NA_HT20;
- else if (conf_is_ht40_minus(conf))
- sc->cur_rate_mode = ATH9K_MODE_11NA_HT40MINUS;
- else if (conf_is_ht40_plus(conf))
- sc->cur_rate_mode = ATH9K_MODE_11NA_HT40PLUS;
- else
- sc->cur_rate_mode = ATH9K_MODE_11A;
- break;
- default:
- BUG_ON(1);
- break;
- }
-}
-
static void ath_update_txpow(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
@@ -121,6 +91,7 @@ bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
void ath9k_ps_wakeup(struct ath_softc *sc)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
unsigned long flags;
spin_lock_irqsave(&sc->sc_pm_lock, flags);
@@ -129,18 +100,33 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
+ /*
+ * While the hardware is asleep, the cycle counters contain no
+ * useful data. Better clear them now so that they don't mess up
+ * survey data results.
+ */
+ spin_lock(&common->cc_lock);
+ ath_hw_cycle_counters_update(common);
+ memset(&common->cc_survey, 0, sizeof(common->cc_survey));
+ spin_unlock(&common->cc_lock);
+
unlock:
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
}
void ath9k_ps_restore(struct ath_softc *sc)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
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);
else if (sc->ps_enabled &&
@@ -175,6 +161,48 @@ static void ath_start_ani(struct ath_common *common)
msecs_to_jiffies((u32)ah->config.ani_poll_interval));
}
+static void ath_update_survey_nf(struct ath_softc *sc, int channel)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath9k_channel *chan = &ah->channels[channel];
+ struct survey_info *survey = &sc->survey[channel];
+
+ if (chan->noisefloor) {
+ survey->filled |= SURVEY_INFO_NOISE_DBM;
+ survey->noise = chan->noisefloor;
+ }
+}
+
+static void ath_update_survey_stats(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ int pos = ah->curchan - &ah->channels[0];
+ struct survey_info *survey = &sc->survey[pos];
+ struct ath_cycle_counters *cc = &common->cc_survey;
+ unsigned int div = common->clockrate * 1000;
+
+ if (!ah->curchan)
+ return;
+
+ if (ah->power_mode == ATH9K_PM_AWAKE)
+ ath_hw_cycle_counters_update(common);
+
+ if (cc->cycles > 0) {
+ survey->filled |= SURVEY_INFO_CHANNEL_TIME |
+ SURVEY_INFO_CHANNEL_TIME_BUSY |
+ SURVEY_INFO_CHANNEL_TIME_RX |
+ SURVEY_INFO_CHANNEL_TIME_TX;
+ survey->channel_time += cc->cycles / div;
+ survey->channel_time_busy += cc->rx_busy / div;
+ survey->channel_time_rx += cc->rx_frame / div;
+ survey->channel_time_tx += cc->tx_frame / div;
+ }
+ memset(cc, 0, sizeof(*cc));
+
+ ath_update_survey_nf(sc, pos);
+}
+
/*
* 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
@@ -226,9 +254,10 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
caldata = &aphy->caldata;
ath_print(common, ATH_DBG_CONFIG,
- "(%u MHz) -> (%u MHz), conf_is_ht40: %d\n",
+ "(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n",
sc->sc_ah->curchan->channel,
- channel->center_freq, conf_is_ht40(conf));
+ channel->center_freq, conf_is_ht40(conf),
+ fastcc);
spin_lock_bh(&sc->sc_resetlock);
@@ -250,14 +279,13 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
goto ps_restore;
}
- ath_cache_conf_rate(sc, &hw->conf);
ath_update_txpow(sc);
ath9k_hw_set_interrupts(ah, ah->imask);
- if (!(sc->sc_flags & (SC_OP_OFFCHANNEL | SC_OP_SCANNING))) {
- ath_start_ani(common);
- ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
+ if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
ath_beacon_config(sc, NULL);
+ ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
+ ath_start_ani(common);
}
ps_restore:
@@ -269,6 +297,7 @@ 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)
@@ -277,7 +306,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 (!(ah->caps.tx_chainmask & BIT(chain)))
+ if (!(common->tx_chainmask & BIT(chain)))
continue;
ar9003_paprd_populate_single_table(ah, caldata, chain);
@@ -299,6 +328,7 @@ void ath_paprd_calibrate(struct work_struct *work)
struct ieee80211_supported_band *sband = &sc->sbands[band];
struct ath_tx_control txctl;
struct ath9k_hw_cal_data *caldata = ah->caldata;
+ struct ath_common *common = ath9k_hw_common(ah);
int qnum, ftype;
int chain_ok = 0;
int chain;
@@ -332,7 +362,7 @@ void ath_paprd_calibrate(struct work_struct *work)
ath9k_ps_wakeup(sc);
ar9003_paprd_init_table(ah);
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
- if (!(ah->caps.tx_chainmask & BIT(chain)))
+ if (!(common->tx_chainmask & BIT(chain)))
continue;
chain_ok = 0;
@@ -395,7 +425,13 @@ void ath_ani_calibrate(unsigned long data)
bool shortcal = false;
bool aniflag = false;
unsigned int timestamp = jiffies_to_msecs(jiffies);
- u32 cal_interval, short_cal_interval;
+ u32 cal_interval, short_cal_interval, long_cal_interval;
+ unsigned long flags;
+
+ if (ah->caldata && ah->caldata->nfcal_interference)
+ long_cal_interval = ATH_LONG_CALINTERVAL_INT;
+ else
+ long_cal_interval = ATH_LONG_CALINTERVAL;
short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
@@ -407,7 +443,7 @@ void ath_ani_calibrate(unsigned long data)
ath9k_ps_wakeup(sc);
/* Long calibration runs independently of short calibration. */
- if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
+ if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
longcal = true;
ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
common->ani.longcal_timer = timestamp;
@@ -441,8 +477,12 @@ void ath_ani_calibrate(unsigned long data)
/* Skip all processing if there's nothing to do. */
if (longcal || shortcal || aniflag) {
/* Call ANI routine if necessary */
- if (aniflag)
+ if (aniflag) {
+ spin_lock_irqsave(&common->cc_lock, flags);
ath9k_hw_ani_monitor(ah, ah->curchan);
+ ath_update_survey_stats(sc);
+ spin_unlock_irqrestore(&common->cc_lock, flags);
+ }
/* Perform calibration if necessary */
if (longcal || shortcal) {
@@ -451,16 +491,6 @@ void ath_ani_calibrate(unsigned long data)
ah->curchan,
common->rx_chainmask,
longcal);
-
- if (longcal)
- common->ani.noise_floor = ath9k_hw_getchan_noise(ah,
- ah->curchan);
-
- ath_print(common, ATH_DBG_ANI,
- " calibrate chan %u/%x nf: %d\n",
- ah->curchan->channel,
- ah->curchan->channelFlags,
- common->ani.noise_floor);
}
}
@@ -550,7 +580,7 @@ void ath_hw_check(struct work_struct *work)
msleep(1);
}
- ath_reset(sc, false);
+ ath_reset(sc, true);
out:
ath9k_ps_restore(sc);
@@ -568,7 +598,7 @@ void ath9k_tasklet(unsigned long data)
ath9k_ps_wakeup(sc);
if (status & ATH9K_INT_FATAL) {
- ath_reset(sc, false);
+ ath_reset(sc, true);
ath9k_ps_restore(sc);
return;
}
@@ -637,6 +667,7 @@ irqreturn_t ath_isr(int irq, void *dev)
struct ath_softc *sc = dev;
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
enum ath9k_int status;
bool sched = false;
@@ -686,7 +717,12 @@ irqreturn_t ath_isr(int irq, void *dev)
if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
(status & ATH9K_INT_BB_WATCHDOG)) {
+
+ spin_lock(&common->cc_lock);
+ ath_hw_cycle_counters_update(common);
ar9003_hw_bb_watchdog_dbg_info(ah);
+ spin_unlock(&common->cc_lock);
+
goto chip_reset;
}
@@ -715,7 +751,9 @@ irqreturn_t ath_isr(int irq, void *dev)
* it will clear whatever condition caused
* the interrupt.
*/
- ath9k_hw_procmibevent(ah);
+ spin_lock(&common->cc_lock);
+ ath9k_hw_proc_mib_event(ah);
+ spin_unlock(&common->cc_lock);
ath9k_hw_set_interrupts(ah, ah->imask);
}
@@ -947,11 +985,9 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
* that changes the channel so update any state that
* might change as a result.
*/
- ath_cache_conf_rate(sc, &hw->conf);
-
ath_update_txpow(sc);
- if (sc->sc_flags & SC_OP_BEACONS)
+ if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL)))
ath_beacon_config(sc, NULL); /* restart beacons */
ath9k_hw_set_interrupts(ah, ah->imask);
@@ -1150,14 +1186,11 @@ static int ath9k_start(struct ieee80211_hw *hw)
else
ah->imask |= ATH9K_INT_RX;
- if (ah->caps.hw_caps & ATH9K_HW_CAP_GTT)
- ah->imask |= ATH9K_INT_GTT;
+ ah->imask |= ATH9K_INT_GTT;
if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
ah->imask |= ATH9K_INT_CST;
- ath_cache_conf_rate(sc, &hw->conf);
-
sc->sc_flags &= ~SC_OP_INVALID;
/* Disable BMISS interrupt when we're not associated */
@@ -1373,16 +1406,13 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
mutex_lock(&sc->mutex);
- if (!(ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) &&
- sc->nvifs > 0) {
- ret = -ENOBUFS;
- goto out;
- }
-
switch (vif->type) {
case NL80211_IFTYPE_STATION:
ic_opmode = NL80211_IFTYPE_STATION;
break;
+ case NL80211_IFTYPE_WDS:
+ ic_opmode = NL80211_IFTYPE_WDS;
+ break;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
@@ -1408,8 +1438,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
sc->nvifs++;
- if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
- ath9k_set_bssid_mask(hw);
+ ath9k_set_bssid_mask(hw, vif);
if (sc->nvifs > 1)
goto out; /* skip global settings for secondary vif */
@@ -1491,7 +1520,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
mutex_unlock(&sc->mutex);
}
-void ath9k_enable_ps(struct ath_softc *sc)
+static void ath9k_enable_ps(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
@@ -1505,13 +1534,33 @@ void ath9k_enable_ps(struct ath_softc *sc)
}
}
+static void ath9k_disable_ps(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+
+ sc->ps_enabled = false;
+ ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
+ if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+ ath9k_hw_setrxabort(ah, 0);
+ sc->ps_flags &= ~(PS_WAIT_FOR_BEACON |
+ PS_WAIT_FOR_CAB |
+ PS_WAIT_FOR_PSPOLL_DATA |
+ 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);
+ }
+ }
+
+}
+
static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ieee80211_conf *conf = &hw->conf;
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_conf *conf = &hw->conf;
bool disable_radio;
mutex_lock(&sc->mutex);
@@ -1556,35 +1605,13 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
* IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode.
*/
if (changed & IEEE80211_CONF_CHANGE_PS) {
- if (conf->flags & IEEE80211_CONF_PS) {
- sc->ps_flags |= PS_ENABLED;
- /*
- * At this point we know hardware has received an ACK
- * of a previously sent null data frame.
- */
- if ((sc->ps_flags & PS_NULLFUNC_COMPLETED)) {
- sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
- ath9k_enable_ps(sc);
- }
- } else {
- sc->ps_enabled = false;
- sc->ps_flags &= ~(PS_ENABLED |
- PS_NULLFUNC_COMPLETED);
- ath9k_setpower(sc, ATH9K_PM_AWAKE);
- if (!(ah->caps.hw_caps &
- ATH9K_HW_CAP_AUTOSLEEP)) {
- ath9k_hw_setrxabort(sc->sc_ah, 0);
- sc->ps_flags &= ~(PS_WAIT_FOR_BEACON |
- PS_WAIT_FOR_CAB |
- PS_WAIT_FOR_PSPOLL_DATA |
- PS_WAIT_FOR_TX_ACK);
- if (ah->imask & ATH9K_INT_TIM_TIMER) {
- ah->imask &= ~ATH9K_INT_TIM_TIMER;
- ath9k_hw_set_interrupts(sc->sc_ah,
- ah->imask);
- }
- }
- }
+ unsigned long flags;
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ if (conf->flags & IEEE80211_CONF_PS)
+ ath9k_enable_ps(sc);
+ else
+ ath9k_disable_ps(sc);
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
}
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
@@ -1598,6 +1625,11 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
struct ieee80211_channel *curchan = hw->conf.channel;
int pos = curchan->hw_value;
+ int old_pos = -1;
+ unsigned long flags;
+
+ if (ah->curchan)
+ old_pos = ah->curchan - &ah->channels[0];
aphy->chan_idx = pos;
aphy->chan_is_ht = conf_is_ht(conf);
@@ -1625,12 +1657,45 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
ath_update_chainmask(sc, conf_is_ht(conf));
+ /* 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);
+
+ /*
+ * 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
+ * back to the operating channel from an off-channel operation.
+ */
+ if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) &&
+ sc->cur_survey != &sc->survey[pos]) {
+
+ if (sc->cur_survey)
+ sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE;
+
+ sc->cur_survey = &sc->survey[pos];
+
+ memset(sc->cur_survey, 0, sizeof(struct survey_info));
+ sc->cur_survey->filled |= SURVEY_INFO_IN_USE;
+ } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) {
+ memset(&sc->survey[pos], 0, sizeof(struct survey_info));
+ }
+
if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
ath_print(common, ATH_DBG_FATAL,
"Unable to set channel\n");
mutex_unlock(&sc->mutex);
return -EINVAL;
}
+
+ /*
+ * The most recent snapshot of channel->noisefloor for the old
+ * channel is only available after the hardware reset. Copy it to
+ * the survey stats now.
+ */
+ if (old_pos >= 0)
+ ath_update_survey_nf(sc, old_pos);
}
skip_chan_change:
@@ -1661,6 +1726,7 @@ skip_chan_change:
FIF_PSPOLL | \
FIF_OTHER_BSS | \
FIF_BCN_PRBRESP_PROMISC | \
+ FIF_PROBE_REQ | \
FIF_FCSFAIL)
/* FIXME: sc->sc_full_reset ? */
@@ -1771,20 +1837,21 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
switch (cmd) {
case SET_KEY:
- ret = ath9k_cmn_key_config(common, vif, sta, key);
+ ret = ath_key_config(common, vif, sta, key);
if (ret >= 0) {
key->hw_key_idx = ret;
/* push IV and Michael MIC generation to stack */
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- if (key->alg == ALG_TKIP)
+ if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
- if (sc->sc_ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
+ if (sc->sc_ah->sw_mgmt_crypto &&
+ key->cipher == WLAN_CIPHER_SUITE_CCMP)
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
ret = 0;
}
break;
case DISABLE_KEY:
- ath9k_cmn_key_delete(common, key);
+ ath_key_delete(common, key);
break;
default:
ret = -EINVAL;
@@ -1968,8 +2035,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
break;
case IEEE80211_AMPDU_TX_START:
ath9k_ps_wakeup(sc);
- ath_tx_aggr_start(sc, sta, tid, ssn);
- ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ ret = ath_tx_aggr_start(sc, sta, tid, ssn);
+ if (!ret)
+ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
ath9k_ps_restore(sc);
break;
case IEEE80211_AMPDU_TX_STOP:
@@ -1998,16 +2066,35 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
- struct ieee80211_conf *conf = &hw->conf;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *chan;
+ unsigned long flags;
+ int pos;
+
+ spin_lock_irqsave(&common->cc_lock, flags);
+ if (idx == 0)
+ ath_update_survey_stats(sc);
+
+ sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ];
+ if (sband && idx >= sband->n_channels) {
+ idx -= sband->n_channels;
+ sband = NULL;
+ }
+
+ if (!sband)
+ sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ];
- if (idx != 0)
+ if (!sband || idx >= sband->n_channels) {
+ spin_unlock_irqrestore(&common->cc_lock, flags);
return -ENOENT;
+ }
- survey->channel = conf->channel;
- survey->filled = SURVEY_INFO_NOISE_DBM;
- survey->noise = common->ani.noise_floor;
+ chan = &sband->channels[idx];
+ pos = chan->hw_value;
+ memcpy(survey, &sc->survey[pos], sizeof(*survey));
+ survey->channel = chan;
+ spin_unlock_irqrestore(&common->cc_lock, flags);
return 0;
}
@@ -2032,7 +2119,6 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
aphy->state = ATH_WIPHY_SCAN;
ath9k_wiphy_pause_all_forced(sc, aphy);
- sc->sc_flags |= SC_OP_SCANNING;
mutex_unlock(&sc->mutex);
}
@@ -2047,7 +2133,6 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
mutex_lock(&sc->mutex);
aphy->state = ATH_WIPHY_ACTIVE;
- sc->sc_flags &= ~SC_OP_SCANNING;
mutex_unlock(&sc->mutex);
}
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
index e724c2c1ae2a..17969af842f6 100644
--- a/drivers/net/wireless/ath/ath9k/phy.h
+++ b/drivers/net/wireless/ath/ath9k/phy.h
@@ -45,9 +45,6 @@
} \
} while (0)
-#define ATH9K_IS_MIC_ENABLED(ah) \
- ((ah)->sta_id1_defaults & AR_STA_ID1_CRPT_MIC_ENABLE)
-
#define ANTSWAP_AB 0x0001
#define REDUCE_CHAIN_0 0x00000050
#define REDUCE_CHAIN_1 0x00000051
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index e49be733d546..0cee90cf8dc9 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -302,7 +302,7 @@ static const struct ath_rate_table ar5416_11ng_ratetable = {
[64] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000,
205100, 20, 20, 8, 64, 65, 65 }, /* 243 Mb */
[65] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000,
- 224700, 20, 20, 8, 64, 65, 65 }, /* 170 Mb */
+ 224700, 20, 20, 8, 64, 65, 65 }, /* 270 Mb */
[66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000,
263100, 21, 21, 8, 66, 67, 67 }, /* 324 Mb */
[67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000,
@@ -378,17 +378,6 @@ static const struct ath_rate_table ar5416_11g_ratetable = {
0, /* Phy rates allowed initially */
};
-static const struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX] = {
- [ATH9K_MODE_11A] = &ar5416_11a_ratetable,
- [ATH9K_MODE_11G] = &ar5416_11g_ratetable,
- [ATH9K_MODE_11NA_HT20] = &ar5416_11na_ratetable,
- [ATH9K_MODE_11NG_HT20] = &ar5416_11ng_ratetable,
- [ATH9K_MODE_11NA_HT40PLUS] = &ar5416_11na_ratetable,
- [ATH9K_MODE_11NA_HT40MINUS] = &ar5416_11na_ratetable,
- [ATH9K_MODE_11NG_HT40PLUS] = &ar5416_11ng_ratetable,
- [ATH9K_MODE_11NG_HT40MINUS] = &ar5416_11ng_ratetable,
-};
-
static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
struct ieee80211_tx_rate *rate);
@@ -791,7 +780,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
*/
try_per_rate = 4;
- rate_table = sc->cur_rate_table;
+ rate_table = ath_rc_priv->rate_table;
rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe);
/*
@@ -1026,6 +1015,16 @@ static bool ath_rc_update_per(struct ath_softc *sc,
return state_change;
}
+static void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
+ int xretries, int retries, u8 per)
+{
+ struct ath_rc_stats *stats = &rc->rcstats[rix];
+
+ stats->xretries += xretries;
+ stats->retries += retries;
+ stats->per = per;
+}
+
/* Update PER, RSSI and whatever else that the code thinks it is doing.
If you can make sense of all this, you really need to go out more. */
@@ -1038,7 +1037,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
int rate;
u8 last_per;
bool state_change = false;
- const struct ath_rate_table *rate_table = sc->cur_rate_table;
+ const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
int size = ath_rc_priv->rate_table_size;
if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt))
@@ -1098,7 +1097,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
ath_rc_priv->per_down_time = now_msec;
}
- ath_debug_stat_retries(sc, tx_rate, xretries, retries,
+ ath_debug_stat_retries(ath_rc_priv, tx_rate, xretries, retries,
ath_rc_priv->per[tx_rate]);
}
@@ -1140,7 +1139,7 @@ static void ath_rc_tx_status(struct ath_softc *sc,
u8 flags;
u32 i = 0, rix;
- rate_table = sc->cur_rate_table;
+ rate_table = ath_rc_priv->rate_table;
/*
* If the first rate is not the final index, there
@@ -1190,39 +1189,23 @@ static void ath_rc_tx_status(struct ath_softc *sc,
static const
struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
enum ieee80211_band band,
- bool is_ht,
- bool is_cw_40)
+ bool is_ht)
{
- int mode = 0;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
switch(band) {
case IEEE80211_BAND_2GHZ:
- mode = ATH9K_MODE_11G;
if (is_ht)
- mode = ATH9K_MODE_11NG_HT20;
- if (is_cw_40)
- mode = ATH9K_MODE_11NG_HT40PLUS;
- break;
+ return &ar5416_11ng_ratetable;
+ return &ar5416_11g_ratetable;
case IEEE80211_BAND_5GHZ:
- mode = ATH9K_MODE_11A;
if (is_ht)
- mode = ATH9K_MODE_11NA_HT20;
- if (is_cw_40)
- mode = ATH9K_MODE_11NA_HT40PLUS;
- break;
+ return &ar5416_11na_ratetable;
+ return &ar5416_11a_ratetable;
default:
ath_print(common, ATH_DBG_CONFIG, "Invalid band\n");
return NULL;
}
-
- BUG_ON(mode >= ATH9K_MODE_MAX);
-
- ath_print(common, ATH_DBG_CONFIG,
- "Choosing rate table for mode: %d\n", mode);
-
- sc->cur_rate_mode = mode;
- return hw_rate_table[mode];
}
static void ath_rc_init(struct ath_softc *sc,
@@ -1293,7 +1276,7 @@ static void ath_rc_init(struct ath_softc *sc,
ath_rc_priv->max_valid_rate = k;
ath_rc_sort_validrates(rate_table, ath_rc_priv);
ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4];
- sc->cur_rate_table = rate_table;
+ ath_rc_priv->rate_table = rate_table;
ath_print(common, ATH_DBG_CONFIG,
"RC Initialized with capabilities: 0x%x\n",
@@ -1320,10 +1303,35 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta,
return caps;
}
+static bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an,
+ u8 tidno)
+{
+ struct ath_atx_tid *txtid;
+
+ if (!(sc->sc_flags & SC_OP_TXAGGR))
+ return false;
+
+ txtid = ATH_AN_2_TID(an, tidno);
+
+ if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
+ return true;
+ return false;
+}
+
+
/***********************************/
/* mac80211 Rate Control callbacks */
/***********************************/
+static void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate)
+{
+ struct ath_rc_stats *stats;
+
+ stats = &rc->rcstats[final_rate];
+ stats->success++;
+}
+
+
static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb)
@@ -1359,6 +1367,12 @@ 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 an underrun error is seen assume it as an excessive retry only
* if max frame trigger level has been reached (2 KB for singel stream,
@@ -1397,8 +1411,9 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
}
}
- ath_debug_stat_rc(sc, ath_rc_get_rateindex(sc->cur_rate_table,
- &tx_info->status.rates[final_ts_idx]));
+ ath_debug_stat_rc(ath_rc_priv,
+ ath_rc_get_rateindex(ath_rc_priv->rate_table,
+ &tx_info->status.rates[final_ts_idx]));
}
static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
@@ -1438,14 +1453,8 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
/* Choose rate table first */
- if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) ||
- (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) ||
- (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) {
- rate_table = ath_choose_rate_table(sc, sband->band,
- sta->ht_cap.ht_supported, is_cw40);
- } else {
- rate_table = hw_rate_table[sc->cur_rate_mode];
- }
+ rate_table = ath_choose_rate_table(sc, sband->band,
+ sta->ht_cap.ht_supported);
ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi);
ath_rc_init(sc, priv_sta, sband, sta, rate_table);
@@ -1485,8 +1494,7 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
if ((local_cw40 != oper_cw40) || (local_sgi != oper_sgi)) {
rate_table = ath_choose_rate_table(sc, sband->band,
- sta->ht_cap.ht_supported,
- oper_cw40);
+ sta->ht_cap.ht_supported);
ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta,
oper_cw40, oper_sgi);
ath_rc_init(sc, priv_sta, sband, sta, rate_table);
@@ -1494,11 +1502,98 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
"Operating HT Bandwidth changed to: %d\n",
sc->hw->conf.channel_type);
- sc->cur_rate_table = hw_rate_table[sc->cur_rate_mode];
}
}
}
+#ifdef CONFIG_ATH9K_DEBUGFS
+
+static int ath9k_debugfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_rate_priv *rc = file->private_data;
+ char *buf;
+ unsigned int len = 0, max;
+ int i = 0;
+ ssize_t retval;
+
+ if (rc->rate_table == NULL)
+ return 0;
+
+ max = 80 + rc->rate_table->rate_cnt * 1024 + 1;
+ buf = kmalloc(max, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ len += sprintf(buf, "%6s %6s %6s "
+ "%10s %10s %10s %10s\n",
+ "HT", "MCS", "Rate",
+ "Success", "Retries", "XRetries", "PER");
+
+ for (i = 0; i < rc->rate_table->rate_cnt; i++) {
+ u32 ratekbps = rc->rate_table->info[i].ratekbps;
+ struct ath_rc_stats *stats = &rc->rcstats[i];
+ char mcs[5];
+ char htmode[5];
+ int used_mcs = 0, used_htmode = 0;
+
+ if (WLAN_RC_PHY_HT(rc->rate_table->info[i].phy)) {
+ used_mcs = snprintf(mcs, 5, "%d",
+ rc->rate_table->info[i].ratecode);
+
+ if (WLAN_RC_PHY_40(rc->rate_table->info[i].phy))
+ used_htmode = snprintf(htmode, 5, "HT40");
+ else if (WLAN_RC_PHY_20(rc->rate_table->info[i].phy))
+ used_htmode = snprintf(htmode, 5, "HT20");
+ else
+ used_htmode = snprintf(htmode, 5, "????");
+ }
+
+ mcs[used_mcs] = '\0';
+ htmode[used_htmode] = '\0';
+
+ len += snprintf(buf + len, max - len,
+ "%6s %6s %3u.%d: "
+ "%10u %10u %10u %10u\n",
+ htmode,
+ mcs,
+ ratekbps / 1000,
+ (ratekbps % 1000) / 100,
+ stats->success,
+ stats->retries,
+ stats->xretries,
+ stats->per);
+ }
+
+ if (len > max)
+ len = max;
+
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+ return retval;
+}
+
+static const struct file_operations fops_rcstat = {
+ .read = read_file_rcstat,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE
+};
+
+static void ath_rate_add_sta_debugfs(void *priv, void *priv_sta,
+ struct dentry *dir)
+{
+ struct ath_rate_priv *rc = priv_sta;
+ debugfs_create_file("rc_stats", S_IRUGO, dir, rc, &fops_rcstat);
+}
+
+#endif /* CONFIG_ATH9K_DEBUGFS */
+
static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
{
struct ath_wiphy *aphy = hw->priv;
@@ -1545,6 +1640,9 @@ static struct rate_control_ops ath_rate_ops = {
.free = ath_rate_free,
.alloc_sta = ath_rate_alloc_sta,
.free_sta = ath_rate_free_sta,
+#ifdef CONFIG_ATH9K_DEBUGFS
+ .add_sta_debugfs = ath_rate_add_sta_debugfs,
+#endif
};
int ath_rate_control_register(void)
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index dc1082654501..2f46a2266ba1 100644
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -135,20 +135,21 @@ enum {
/**
* struct ath_rate_table - Rate Control table
- * @valid: valid for use in rate control
- * @valid_single_stream: valid for use in rate control for
- * single stream operation
- * @phy: CCK/OFDM
+ * @rate_cnt: total number of rates for the given wireless mode
+ * @mcs_start: MCS rate index offset
+ * @rate_flags: Rate Control flags
+ * @phy: CCK/OFDM/HT20/HT40
* @ratekbps: rate in Kbits per second
* @user_ratekbps: user rate in Kbits per second
* @ratecode: rate that goes into HW descriptors
- * @short_preamble: Mask for enabling short preamble in ratecode for CCK
* @dot11rate: value that goes into supported
* rates info element of MLME
* @ctrl_rate: Index of next lower basic rate, used for duration computation
- * @max_4ms_framelen: maximum frame length(bytes) for tx duration
+ * @cw40index: Index of rates having 40MHz channel width
+ * @sgi_index: Index of rates having Short Guard Interval
+ * @ht_index: high throughput rates having 40MHz channel width and
+ * Short Guard Interval
* @probe_interval: interval for rate control to probe for other rates
- * @rssi_reduce_interval: interval for rate control to reduce rssi
* @initial_ratemax: initial ratemax value
*/
struct ath_rate_table {
@@ -175,6 +176,13 @@ struct ath_rateset {
u8 rs_rates[ATH_RATE_MAX];
};
+struct ath_rc_stats {
+ u32 success;
+ u32 retries;
+ u32 xretries;
+ u8 per;
+};
+
/**
* struct ath_rate_priv - Rate Control priv data
* @state: RC state
@@ -211,6 +219,10 @@ struct ath_rate_priv {
struct ath_rateset neg_rates;
struct ath_rateset neg_ht_rates;
struct ath_rate_softc *asc;
+ const struct ath_rate_table *rate_table;
+
+ struct dentry *debugfs_rcstats;
+ struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
};
#define ATH_TX_INFO_FRAME_TYPE_INTERNAL (1 << 0)
@@ -224,7 +236,18 @@ enum ath9k_internal_frame_type {
ATH9K_IFT_UNPAUSE
};
+#ifdef CONFIG_ATH9K_RATE_CONTROL
int ath_rate_control_register(void);
void ath_rate_control_unregister(void);
+#else
+static inline int ath_rate_control_register(void)
+{
+ return 0;
+}
+
+static inline void ath_rate_control_unregister(void)
+{
+}
+#endif
#endif /* RC_H */
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index a3fc987ebab0..fe73fc50082a 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -19,6 +19,15 @@
#define SKB_CB_ATHBUF(__skb) (*((struct ath_buf **)__skb->cb))
+static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
+ int mindelta, int main_rssi_avg,
+ int alt_rssi_avg, int pkt_count)
+{
+ return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+ (alt_rssi_avg > main_rssi_avg + maxdelta)) ||
+ (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
+}
+
static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)
{
return sc->ps_enabled &&
@@ -110,8 +119,7 @@ static void ath_opmode_init(struct ath_softc *sc)
ath9k_hw_setrxfilter(ah, rfilt);
/* configure bssid mask */
- if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
- ath_hw_setbssidmask(common);
+ ath_hw_setbssidmask(common);
/* configure operational mode */
ath9k_hw_setopmode(ah);
@@ -260,6 +268,7 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)
bf->bf_buf_addr))) {
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
+ bf->bf_buf_addr = 0;
ath_print(common, ATH_DBG_FATAL,
"dma_mapping_error() on RX init\n");
error = -ENOMEM;
@@ -292,7 +301,7 @@ static void ath_edma_start_recv(struct ath_softc *sc)
ath_opmode_init(sc);
- ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_SCANNING));
+ ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
}
static void ath_edma_stop_recv(struct ath_softc *sc)
@@ -350,12 +359,12 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
bf->bf_buf_addr))) {
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
+ bf->bf_buf_addr = 0;
ath_print(common, ATH_DBG_FATAL,
"dma_mapping_error() on RX init\n");
error = -ENOMEM;
goto err;
}
- bf->bf_dmacontext = bf->bf_buf_addr;
}
sc->rx.rxlink = NULL;
}
@@ -385,6 +394,8 @@ void ath_rx_cleanup(struct ath_softc *sc)
common->rx_bufsize,
DMA_FROM_DEVICE);
dev_kfree_skb(skb);
+ bf->bf_buf_addr = 0;
+ bf->bf_mpdu = NULL;
}
}
@@ -422,8 +433,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
| ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
| ATH9K_RX_FILTER_MCAST;
- /* If not a STA, enable processing of Probe Requests */
- if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
+ if (sc->rx.rxfilter & FIF_PROBE_REQ)
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
/*
@@ -440,13 +450,14 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
rfilt |= ATH9K_RX_FILTER_CONTROL;
if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
+ (sc->nvifs <= 1) &&
!(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC))
rfilt |= ATH9K_RX_FILTER_MYBEACON;
else
rfilt |= ATH9K_RX_FILTER_BEACON;
- if ((AR_SREV_9280_10_OR_LATER(sc->sc_ah) ||
- AR_SREV_9285_10_OR_LATER(sc->sc_ah)) &&
+ if ((AR_SREV_9280_20_OR_LATER(sc->sc_ah) ||
+ AR_SREV_9285_12_OR_LATER(sc->sc_ah)) &&
(sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
(sc->rx.rxfilter & FIF_PSPOLL))
rfilt |= ATH9K_RX_FILTER_PSPOLL;
@@ -454,9 +465,8 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (conf_is_ht(&sc->hw->conf))
rfilt |= ATH9K_RX_FILTER_COMP_BAR;
- if (sc->sec_wiphy || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
- /* TODO: only needed if more than one BSSID is in use in
- * station/adhoc mode */
+ if (sc->sec_wiphy || (sc->nvifs > 1) ||
+ (sc->rx.rxfilter & FIF_OTHER_BSS)) {
/* The following may also be needed for other older chips */
if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160)
rfilt |= ATH9K_RX_FILTER_PROM;
@@ -498,7 +508,7 @@ int ath_startrecv(struct ath_softc *sc)
start_recv:
spin_unlock_bh(&sc->rx.rxbuflock);
ath_opmode_init(sc);
- ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_SCANNING));
+ ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
return 0;
}
@@ -631,7 +641,7 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
* No more broadcast/multicast frames to be received at this
* point.
*/
- sc->ps_flags &= ~PS_WAIT_FOR_CAB;
+ sc->ps_flags &= ~(PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON);
ath_print(common, ATH_DBG_PS,
"All PS CAB frames received, back to sleep\n");
} else if ((sc->ps_flags & PS_WAIT_FOR_PSPOLL_DATA) &&
@@ -870,15 +880,18 @@ static bool ath9k_rx_accept(struct ath_common *common,
if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
*decrypt_error = true;
} else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
- if (ieee80211_is_ctl(fc))
- /*
- * Sometimes, we get invalid
- * MIC failures on valid control frames.
- * Remove these mic errors.
- */
- rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
- else
+ /*
+ * The MIC error bit is only valid if the frame
+ * is not a control frame or fragment, and it was
+ * decrypted using a valid TKIP key.
+ */
+ if (!ieee80211_is_ctl(fc) &&
+ !ieee80211_has_morefrags(fc) &&
+ !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) &&
+ test_bit(rx_stats->rs_keyix, common->tkip_keymap))
rxs->flag |= RX_FLAG_MMIC_ERROR;
+ else
+ rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
}
/*
* Reject error frames with the exception of
@@ -966,7 +979,11 @@ static void ath9k_process_rssi(struct ath_common *common,
* at least one sdata of a wiphy on mac80211 but with ath9k virtual
* wiphy you'd have to iterate over every wiphy and each sdata.
*/
- sta = ieee80211_find_sta_by_hw(hw, hdr->addr2);
+ if (is_multicast_ether_addr(hdr->addr1))
+ sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
+ else
+ sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, hdr->addr1);
+
if (sta) {
an = (struct ath_node *) sta->drv_priv;
if (rx_stats->rs_rssi != ATH9K_RSSI_BAD &&
@@ -1073,6 +1090,539 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
rxs->flag &= ~RX_FLAG_DECRYPTED;
}
+static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
+ struct ath_hw_antcomb_conf ant_conf,
+ int main_rssi_avg)
+{
+ antcomb->quick_scan_cnt = 0;
+
+ if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
+ antcomb->rssi_lna2 = main_rssi_avg;
+ else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
+ antcomb->rssi_lna1 = main_rssi_avg;
+
+ switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
+ case (0x10): /* LNA2 A-B */
+ antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->first_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
+ break;
+ case (0x20): /* LNA1 A-B */
+ antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->first_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
+ break;
+ case (0x21): /* LNA1 LNA2 */
+ antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
+ antcomb->first_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->second_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ break;
+ case (0x12): /* LNA2 LNA1 */
+ antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
+ antcomb->first_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->second_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ break;
+ case (0x13): /* LNA2 A+B */
+ antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ antcomb->first_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
+ break;
+ case (0x23): /* LNA1 A+B */
+ antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ antcomb->first_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
+ break;
+ default:
+ break;
+ }
+}
+
+static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
+ struct ath_hw_antcomb_conf *div_ant_conf,
+ int main_rssi_avg, int alt_rssi_avg,
+ int alt_ratio)
+{
+ /* alt_good */
+ switch (antcomb->quick_scan_cnt) {
+ case 0:
+ /* set alt to main, and alt to first conf */
+ div_ant_conf->main_lna_conf = antcomb->main_conf;
+ div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
+ break;
+ case 1:
+ /* set alt to main, and alt to first conf */
+ div_ant_conf->main_lna_conf = antcomb->main_conf;
+ div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
+ antcomb->rssi_first = main_rssi_avg;
+ antcomb->rssi_second = alt_rssi_avg;
+
+ if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
+ /* main is LNA1 */
+ if (ath_is_alt_ant_ratio_better(alt_ratio,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ main_rssi_avg, alt_rssi_avg,
+ antcomb->total_pkt_count))
+ antcomb->first_ratio = true;
+ else
+ antcomb->first_ratio = false;
+ } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
+ if (ath_is_alt_ant_ratio_better(alt_ratio,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ main_rssi_avg, alt_rssi_avg,
+ antcomb->total_pkt_count))
+ antcomb->first_ratio = true;
+ else
+ antcomb->first_ratio = false;
+ } else {
+ if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+ (alt_rssi_avg > main_rssi_avg +
+ ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+ (alt_rssi_avg > main_rssi_avg)) &&
+ (antcomb->total_pkt_count > 50))
+ antcomb->first_ratio = true;
+ else
+ antcomb->first_ratio = false;
+ }
+ break;
+ case 2:
+ antcomb->alt_good = false;
+ antcomb->scan_not_start = false;
+ antcomb->scan = false;
+ antcomb->rssi_first = main_rssi_avg;
+ antcomb->rssi_third = alt_rssi_avg;
+
+ if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1)
+ antcomb->rssi_lna1 = alt_rssi_avg;
+ else if (antcomb->second_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA2)
+ antcomb->rssi_lna2 = alt_rssi_avg;
+ else if (antcomb->second_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
+ if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
+ antcomb->rssi_lna2 = main_rssi_avg;
+ else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
+ antcomb->rssi_lna1 = main_rssi_avg;
+ }
+
+ if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
+ ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
+ div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+ else
+ div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+
+ if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
+ if (ath_is_alt_ant_ratio_better(alt_ratio,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ main_rssi_avg, alt_rssi_avg,
+ antcomb->total_pkt_count))
+ antcomb->second_ratio = true;
+ else
+ antcomb->second_ratio = false;
+ } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
+ if (ath_is_alt_ant_ratio_better(alt_ratio,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ main_rssi_avg, alt_rssi_avg,
+ antcomb->total_pkt_count))
+ antcomb->second_ratio = true;
+ else
+ antcomb->second_ratio = false;
+ } else {
+ if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+ (alt_rssi_avg > main_rssi_avg +
+ ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+ (alt_rssi_avg > main_rssi_avg)) &&
+ (antcomb->total_pkt_count > 50))
+ antcomb->second_ratio = true;
+ else
+ antcomb->second_ratio = false;
+ }
+
+ /* set alt to the conf with maximun ratio */
+ if (antcomb->first_ratio && antcomb->second_ratio) {
+ if (antcomb->rssi_second > antcomb->rssi_third) {
+ /* first alt*/
+ if ((antcomb->first_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA1) ||
+ (antcomb->first_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA2))
+ /* Set alt LNA1 or LNA2*/
+ if (div_ant_conf->main_lna_conf ==
+ ATH_ANT_DIV_COMB_LNA2)
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ else
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ else
+ /* Set alt to A+B or A-B */
+ div_ant_conf->alt_lna_conf =
+ antcomb->first_quick_scan_conf;
+ } else if ((antcomb->second_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA1) ||
+ (antcomb->second_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA2)) {
+ /* Set alt LNA1 or LNA2 */
+ if (div_ant_conf->main_lna_conf ==
+ ATH_ANT_DIV_COMB_LNA2)
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ else
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ } else {
+ /* Set alt to A+B or A-B */
+ div_ant_conf->alt_lna_conf =
+ antcomb->second_quick_scan_conf;
+ }
+ } else if (antcomb->first_ratio) {
+ /* first alt */
+ if ((antcomb->first_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA1) ||
+ (antcomb->first_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA2))
+ /* Set alt LNA1 or LNA2 */
+ if (div_ant_conf->main_lna_conf ==
+ ATH_ANT_DIV_COMB_LNA2)
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ else
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ else
+ /* Set alt to A+B or A-B */
+ div_ant_conf->alt_lna_conf =
+ antcomb->first_quick_scan_conf;
+ } else if (antcomb->second_ratio) {
+ /* second alt */
+ if ((antcomb->second_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA1) ||
+ (antcomb->second_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA2))
+ /* Set alt LNA1 or LNA2 */
+ if (div_ant_conf->main_lna_conf ==
+ ATH_ANT_DIV_COMB_LNA2)
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ else
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ else
+ /* Set alt to A+B or A-B */
+ div_ant_conf->alt_lna_conf =
+ antcomb->second_quick_scan_conf;
+ } else {
+ /* main is largest */
+ if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
+ (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
+ /* Set alt LNA1 or LNA2 */
+ if (div_ant_conf->main_lna_conf ==
+ ATH_ANT_DIV_COMB_LNA2)
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ else
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ else
+ /* Set alt to A+B or A-B */
+ div_ant_conf->alt_lna_conf = antcomb->main_conf;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf)
+{
+ /* Adjust the fast_div_bias based on main and alt lna conf */
+ switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) {
+ case (0x01): /* A-B LNA2 */
+ ant_conf->fast_div_bias = 0x3b;
+ break;
+ case (0x02): /* A-B LNA1 */
+ ant_conf->fast_div_bias = 0x3d;
+ break;
+ case (0x03): /* A-B A+B */
+ ant_conf->fast_div_bias = 0x1;
+ break;
+ case (0x10): /* LNA2 A-B */
+ ant_conf->fast_div_bias = 0x7;
+ break;
+ case (0x12): /* LNA2 LNA1 */
+ ant_conf->fast_div_bias = 0x2;
+ break;
+ case (0x13): /* LNA2 A+B */
+ ant_conf->fast_div_bias = 0x7;
+ break;
+ case (0x20): /* LNA1 A-B */
+ ant_conf->fast_div_bias = 0x6;
+ break;
+ case (0x21): /* LNA1 LNA2 */
+ ant_conf->fast_div_bias = 0x0;
+ break;
+ case (0x23): /* LNA1 A+B */
+ ant_conf->fast_div_bias = 0x6;
+ break;
+ case (0x30): /* A+B A-B */
+ ant_conf->fast_div_bias = 0x1;
+ break;
+ case (0x31): /* A+B LNA2 */
+ ant_conf->fast_div_bias = 0x3b;
+ break;
+ case (0x32): /* A+B LNA1 */
+ ant_conf->fast_div_bias = 0x3d;
+ break;
+ default:
+ break;
+ }
+}
+
+/* Antenna diversity and combining */
+static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
+{
+ struct ath_hw_antcomb_conf div_ant_conf;
+ struct ath_ant_comb *antcomb = &sc->ant_comb;
+ int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
+ int curr_main_set, curr_bias;
+ int main_rssi = rs->rs_rssi_ctl0;
+ int alt_rssi = rs->rs_rssi_ctl1;
+ int rx_ant_conf, main_ant_conf;
+ bool short_scan = false;
+
+ rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
+ ATH_ANT_RX_MASK;
+ main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
+ ATH_ANT_RX_MASK;
+
+ /* Record packet only when alt_rssi is positive */
+ if (alt_rssi > 0) {
+ antcomb->total_pkt_count++;
+ antcomb->main_total_rssi += main_rssi;
+ antcomb->alt_total_rssi += alt_rssi;
+ if (main_ant_conf == rx_ant_conf)
+ antcomb->main_recv_cnt++;
+ else
+ antcomb->alt_recv_cnt++;
+ }
+
+ /* Short scan check */
+ if (antcomb->scan && antcomb->alt_good) {
+ if (time_after(jiffies, antcomb->scan_start_time +
+ msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
+ short_scan = true;
+ else
+ if (antcomb->total_pkt_count ==
+ ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
+ alt_ratio = ((antcomb->alt_recv_cnt * 100) /
+ antcomb->total_pkt_count);
+ if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
+ short_scan = true;
+ }
+ }
+
+ if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
+ rs->rs_moreaggr) && !short_scan)
+ return;
+
+ if (antcomb->total_pkt_count) {
+ alt_ratio = ((antcomb->alt_recv_cnt * 100) /
+ antcomb->total_pkt_count);
+ main_rssi_avg = (antcomb->main_total_rssi /
+ antcomb->total_pkt_count);
+ alt_rssi_avg = (antcomb->alt_total_rssi /
+ antcomb->total_pkt_count);
+ }
+
+
+ ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
+ curr_alt_set = div_ant_conf.alt_lna_conf;
+ curr_main_set = div_ant_conf.main_lna_conf;
+ curr_bias = div_ant_conf.fast_div_bias;
+
+ antcomb->count++;
+
+ if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
+ if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
+ ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
+ main_rssi_avg);
+ antcomb->alt_good = true;
+ } else {
+ antcomb->alt_good = false;
+ }
+
+ antcomb->count = 0;
+ antcomb->scan = true;
+ antcomb->scan_not_start = true;
+ }
+
+ if (!antcomb->scan) {
+ if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
+ if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
+ /* Switch main and alt LNA */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ }
+
+ goto div_comb_done;
+ } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
+ (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
+ /* Set alt to another LNA */
+ if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+
+ goto div_comb_done;
+ }
+
+ if ((alt_rssi_avg < (main_rssi_avg +
+ ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA)))
+ goto div_comb_done;
+ }
+
+ if (!antcomb->scan_not_start) {
+ switch (curr_alt_set) {
+ case ATH_ANT_DIV_COMB_LNA2:
+ antcomb->rssi_lna2 = alt_rssi_avg;
+ antcomb->rssi_lna1 = main_rssi_avg;
+ antcomb->scan = true;
+ /* set to A+B */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ break;
+ case ATH_ANT_DIV_COMB_LNA1:
+ antcomb->rssi_lna1 = alt_rssi_avg;
+ antcomb->rssi_lna2 = main_rssi_avg;
+ antcomb->scan = true;
+ /* set to A+B */
+ div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ break;
+ case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
+ antcomb->rssi_add = alt_rssi_avg;
+ antcomb->scan = true;
+ /* set to A-B */
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ break;
+ case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
+ antcomb->rssi_sub = alt_rssi_avg;
+ antcomb->scan = false;
+ if (antcomb->rssi_lna2 >
+ (antcomb->rssi_lna1 +
+ ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
+ /* use LNA2 as main LNA */
+ if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
+ (antcomb->rssi_add > antcomb->rssi_sub)) {
+ /* set to A+B */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ } else if (antcomb->rssi_sub >
+ antcomb->rssi_lna1) {
+ /* set to A-B */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ } else {
+ /* set to LNA1 */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ }
+ } else {
+ /* use LNA1 as main LNA */
+ if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
+ (antcomb->rssi_add > antcomb->rssi_sub)) {
+ /* set to A+B */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ } else if (antcomb->rssi_sub >
+ antcomb->rssi_lna1) {
+ /* set to A-B */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ } else {
+ /* set to LNA2 */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ if (!antcomb->alt_good) {
+ antcomb->scan_not_start = false;
+ /* Set alt to another LNA */
+ if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ }
+ goto div_comb_done;
+ }
+ }
+
+ ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
+ main_rssi_avg, alt_rssi_avg,
+ alt_ratio);
+
+ antcomb->quick_scan_cnt++;
+
+div_comb_done:
+ ath_ant_div_conf_fast_divbias(&div_ant_conf);
+
+ ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
+
+ antcomb->scan_start_time = jiffies;
+ antcomb->total_pkt_count = 0;
+ antcomb->main_total_rssi = 0;
+ antcomb->alt_total_rssi = 0;
+ antcomb->main_recv_cnt = 0;
+ antcomb->alt_recv_cnt = 0;
+}
+
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
{
struct ath_buf *bf;
@@ -1096,6 +1646,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
u8 rx_status_len = ah->caps.rx_status_len;
u64 tsf = 0;
u32 tsf_lower = 0;
+ unsigned long flags;
if (edma)
dma_type = DMA_BIDIRECTIONAL;
@@ -1186,12 +1737,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
bf->bf_buf_addr))) {
dev_kfree_skb_any(requeue_skb);
bf->bf_mpdu = NULL;
+ bf->bf_buf_addr = 0;
ath_print(common, ATH_DBG_FATAL,
"dma_mapping_error() on RX\n");
ath_rx_send_to_mac80211(hw, sc, skb, rxs);
break;
}
- bf->bf_dmacontext = bf->bf_buf_addr;
/*
* change the default rx antenna if rx diversity chooses the
@@ -1204,11 +1755,16 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
sc->rx.rxotherant = 0;
}
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
if (unlikely(ath9k_check_auto_sleep(sc) ||
(sc->ps_flags & (PS_WAIT_FOR_BEACON |
PS_WAIT_FOR_CAB |
PS_WAIT_FOR_PSPOLL_DATA))))
ath_rx_ps(sc, skb);
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
+ ath_ant_comb_scan(sc, &rs);
ath_rx_send_to_mac80211(hw, sc, skb, rxs);
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index d01c4adab8d6..42976b0a01c1 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -107,12 +107,6 @@
#define AR_RXCFG_DMASZ_256B 6
#define AR_RXCFG_DMASZ_512B 7
-#define AR_MIBC 0x0040
-#define AR_MIBC_COW 0x00000001
-#define AR_MIBC_FMC 0x00000002
-#define AR_MIBC_CMC 0x00000004
-#define AR_MIBC_MCS 0x00000008
-
#define AR_TOPS 0x0044
#define AR_TOPS_MASK 0x0000FFFF
@@ -819,49 +813,23 @@
((_ah)->hw_version.macRev == AR_SREV_REVISION_9160_11))
#define AR_SREV_9280(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280))
-#define AR_SREV_9280_10_OR_LATER(_ah) \
+#define AR_SREV_9280_20_OR_LATER(_ah) \
(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9280))
#define AR_SREV_9280_20(_ah) \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280) && \
- ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9280_20))
-#define AR_SREV_9280_20_OR_LATER(_ah) \
- (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9280) || \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280) && \
- ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9280_20)))
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280))
#define AR_SREV_9285(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9285))
-#define AR_SREV_9285_10_OR_LATER(_ah) \
- (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9285))
-#define AR_SREV_9285_11(_ah) \
- (AR_SREV_9285(ah) && \
- ((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_11))
-#define AR_SREV_9285_11_OR_LATER(_ah) \
- (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \
- (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \
- AR_SREV_REVISION_9285_11)))
-#define AR_SREV_9285_12(_ah) \
- (AR_SREV_9285(ah) && \
- ((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_12))
#define AR_SREV_9285_12_OR_LATER(_ah) \
- (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \
- (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \
- AR_SREV_REVISION_9285_12)))
+ (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9285))
#define AR_SREV_9287(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287))
-#define AR_SREV_9287_10_OR_LATER(_ah) \
+#define AR_SREV_9287_11_OR_LATER(_ah) \
(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9287))
-#define AR_SREV_9287_10(_ah) \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
- ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_10))
#define AR_SREV_9287_11(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_11))
-#define AR_SREV_9287_11_OR_LATER(_ah) \
- (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
- ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11)))
#define AR_SREV_9287_12(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_12))
@@ -885,9 +853,6 @@
#define AR_SREV_9300(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300))
-#define AR_SREV_9300_20(_ah) \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \
- ((_ah)->hw_version.macRev == AR_SREV_REVISION_9300_20))
#define AR_SREV_9300_20_OR_LATER(_ah) \
(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9300) || \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \
@@ -1550,11 +1515,6 @@ enum {
#define AR_TPC_CHIRP 0x003f0000
#define AR_TPC_CHIRP_S 0x16
-#define AR_TFCNT 0x80ec
-#define AR_RFCNT 0x80f0
-#define AR_RCCNT 0x80f4
-#define AR_CCCNT 0x80f8
-
#define AR_QUIET1 0x80fc
#define AR_QUIET1_NEXT_QUIET_S 0
#define AR_QUIET1_NEXT_QUIET_M 0x0000ffff
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index fd20241f57d8..ec7cf5ee56bc 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -19,45 +19,36 @@
#include "ath9k.h"
struct ath9k_vif_iter_data {
- int count;
- u8 *addr;
+ const u8 *hw_macaddr;
+ u8 mask[ETH_ALEN];
};
static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
{
struct ath9k_vif_iter_data *iter_data = data;
- u8 *nbuf;
-
- nbuf = krealloc(iter_data->addr, (iter_data->count + 1) * ETH_ALEN,
- GFP_ATOMIC);
- if (nbuf == NULL)
- return;
+ int i;
- memcpy(nbuf + iter_data->count * ETH_ALEN, mac, ETH_ALEN);
- iter_data->addr = nbuf;
- iter_data->count++;
+ for (i = 0; i < ETH_ALEN; i++)
+ iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]);
}
-void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
+void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_vif_iter_data iter_data;
- int i, j;
- u8 mask[ETH_ALEN];
+ int i;
/*
- * Add primary MAC address even if it is not in active use since it
- * will be configured to the hardware as the starting point and the
- * BSSID mask will need to be changed if another address is active.
+ * Use the hardware MAC address as reference, the hardware uses it
+ * together with the BSSID mask when matching addresses.
*/
- iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC);
- if (iter_data.addr) {
- memcpy(iter_data.addr, common->macaddr, ETH_ALEN);
- iter_data.count = 1;
- } else
- iter_data.count = 0;
+ iter_data.hw_macaddr = common->macaddr;
+ memset(&iter_data.mask, 0xff, ETH_ALEN);
+
+ if (vif)
+ ath9k_vif_iter(&iter_data, vif->addr, vif);
/* Get list of all active MAC addresses */
spin_lock_bh(&sc->wiphy_lock);
@@ -71,31 +62,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
}
spin_unlock_bh(&sc->wiphy_lock);
- /* Generate an address mask to cover all active addresses */
- memset(mask, 0, ETH_ALEN);
- for (i = 0; i < iter_data.count; i++) {
- u8 *a1 = iter_data.addr + i * ETH_ALEN;
- for (j = i + 1; j < iter_data.count; j++) {
- u8 *a2 = iter_data.addr + j * ETH_ALEN;
- mask[0] |= a1[0] ^ a2[0];
- mask[1] |= a1[1] ^ a2[1];
- mask[2] |= a1[2] ^ a2[2];
- mask[3] |= a1[3] ^ a2[3];
- mask[4] |= a1[4] ^ a2[4];
- mask[5] |= a1[5] ^ a2[5];
- }
- }
-
- kfree(iter_data.addr);
-
- /* Invert the mask and configure hardware */
- common->bssidmask[0] = ~mask[0];
- common->bssidmask[1] = ~mask[1];
- common->bssidmask[2] = ~mask[2];
- common->bssidmask[3] = ~mask[3];
- common->bssidmask[4] = ~mask[4];
- common->bssidmask[5] = ~mask[5];
-
+ memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
ath_hw_setbssidmask(common);
}
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index 6260faa658a2..93a8bda09c25 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -85,6 +85,8 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
return "WMI_TGT_DETACH_CMDID";
case WMI_TGT_TXQ_ENABLE_CMDID:
return "WMI_TGT_TXQ_ENABLE_CMDID";
+ case WMI_AGGR_LIMIT_CMD:
+ return "WMI_AGGR_LIMIT_CMD";
}
return "Bogus";
@@ -122,55 +124,11 @@ void ath9k_wmi_tasklet(unsigned long data)
{
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
struct ath_common *common = ath9k_hw_common(priv->ah);
- struct wmi_cmd_hdr *hdr;
- struct wmi_swba *swba_hdr;
- enum wmi_event_id event;
- struct sk_buff *skb;
- void *wmi_event;
- unsigned long flags;
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
- __be32 txrate;
-#endif
- spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
- skb = priv->wmi->wmi_skb;
- spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);
+ ath_print(common, ATH_DBG_WMI, "SWBA Event received\n");
- hdr = (struct wmi_cmd_hdr *) skb->data;
- event = be16_to_cpu(hdr->command_id);
- wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
+ ath9k_htc_swba(priv, priv->wmi->beacon_pending);
- ath_print(common, ATH_DBG_WMI,
- "WMI Event: 0x%x\n", event);
-
- switch (event) {
- case WMI_TGT_RDY_EVENTID:
- break;
- case WMI_SWBA_EVENTID:
- swba_hdr = (struct wmi_swba *) wmi_event;
- ath9k_htc_swba(priv, swba_hdr->beacon_pending);
- break;
- case WMI_FATAL_EVENTID:
- break;
- case WMI_TXTO_EVENTID:
- break;
- case WMI_BMISS_EVENTID:
- break;
- case WMI_WLAN_TXCOMP_EVENTID:
- break;
- case WMI_DELBA_EVENTID:
- break;
- case WMI_TXRATE_EVENTID:
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
- txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
- priv->debug.txrate = be32_to_cpu(txrate);
-#endif
- break;
- default:
- break;
- }
-
- kfree_skb(skb);
}
static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
@@ -189,6 +147,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
struct wmi *wmi = (struct wmi *) priv;
struct wmi_cmd_hdr *hdr;
u16 cmd_id;
+ void *wmi_event;
+#ifdef CONFIG_ATH9K_HTC_DEBUGFS
+ __be32 txrate;
+#endif
if (unlikely(wmi->stopped))
goto free_skb;
@@ -197,10 +159,22 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
cmd_id = be16_to_cpu(hdr->command_id);
if (cmd_id & 0x1000) {
- spin_lock(&wmi->wmi_lock);
- wmi->wmi_skb = skb;
- spin_unlock(&wmi->wmi_lock);
- tasklet_schedule(&wmi->drv_priv->wmi_tasklet);
+ wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
+ switch (cmd_id) {
+ case WMI_SWBA_EVENTID:
+ wmi->beacon_pending = *(u8 *)wmi_event;
+ tasklet_schedule(&wmi->drv_priv->wmi_tasklet);
+ break;
+ case WMI_TXRATE_EVENTID:
+#ifdef CONFIG_ATH9K_HTC_DEBUGFS
+ txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
+ wmi->drv_priv->debug.txrate = be32_to_cpu(txrate);
+#endif
+ break;
+ default:
+ break;
+ }
+ kfree_skb(skb);
return;
}
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index 765db5faa2d3..ac61074af8ac 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -31,10 +31,6 @@ struct wmi_cmd_hdr {
__be16 seq_no;
} __packed;
-struct wmi_swba {
- u8 beacon_pending;
-} __packed;
-
enum wmi_cmd_id {
WMI_ECHO_CMDID = 0x0001,
WMI_ACCESS_MEMORY_CMDID,
@@ -71,6 +67,7 @@ enum wmi_cmd_id {
WMI_TX_AGGR_ENABLE_CMDID,
WMI_TGT_DETACH_CMDID,
WMI_TGT_TXQ_ENABLE_CMDID,
+ WMI_AGGR_LIMIT_CMD = 0x0026,
};
enum wmi_event_id {
@@ -103,7 +100,7 @@ struct wmi {
u32 cmd_rsp_len;
bool stopped;
- struct sk_buff *wmi_skb;
+ u8 beacon_pending;
spinlock_t wmi_lock;
atomic_t mwrite_cnt;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 4dda14e36227..30ef2dfc1ed2 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -61,6 +61,8 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
struct ath_tx_status *ts, int txok);
static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
int nbad, int txok, bool update_rc);
+static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
+ int seqno);
enum {
MCS_HT20,
@@ -143,18 +145,23 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
struct ath_buf *bf;
struct list_head bf_head;
- INIT_LIST_HEAD(&bf_head);
+ struct ath_tx_status ts;
- WARN_ON(!tid->paused);
+ INIT_LIST_HEAD(&bf_head);
+ memset(&ts, 0, sizeof(ts));
spin_lock_bh(&txq->axq_lock);
- tid->paused = false;
while (!list_empty(&tid->buf_q)) {
bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
- BUG_ON(bf_isretried(bf));
list_move_tail(&bf->list, &bf_head);
- ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
+
+ if (bf_isretried(bf)) {
+ ath_tx_update_baw(sc, tid, bf->bf_seqno);
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
+ } else {
+ ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
+ }
}
spin_unlock_bh(&txq->axq_lock);
@@ -168,9 +175,9 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
index = ATH_BA_INDEX(tid->seq_start, seqno);
cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
- tid->tx_buf[cindex] = NULL;
+ __clear_bit(cindex, tid->tx_buf);
- while (tid->baw_head != tid->baw_tail && !tid->tx_buf[tid->baw_head]) {
+ while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) {
INCR(tid->seq_start, IEEE80211_SEQ_MAX);
INCR(tid->baw_head, ATH_TID_MAX_BUFS);
}
@@ -186,9 +193,7 @@ static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno);
cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
-
- BUG_ON(tid->tx_buf[cindex] != NULL);
- tid->tx_buf[cindex] = bf;
+ __set_bit(cindex, tid->tx_buf);
if (index >= ((tid->baw_tail - tid->baw_head) &
(ATH_TID_MAX_BUFS - 1))) {
@@ -289,7 +294,6 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
tbf->bf_buf_addr = bf->bf_buf_addr;
memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
tbf->bf_state = bf->bf_state;
- tbf->bf_dmacontext = bf->bf_dmacontext;
return tbf;
}
@@ -312,6 +316,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
bool rc_update = true;
struct ieee80211_tx_rate rates[4];
+ int nframes;
skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data;
@@ -320,11 +325,11 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
hw = bf->aphy->hw;
memcpy(rates, tx_info->control.rates, sizeof(rates));
+ nframes = bf->bf_nframes;
rcu_read_lock();
- /* XXX: use ieee80211_find_sta! */
- sta = ieee80211_find_sta_by_hw(hw, hdr->addr1);
+ sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
if (!sta) {
rcu_read_unlock();
@@ -337,7 +342,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
!bf->bf_stale || bf_next != NULL)
list_move_tail(&bf->list, &bf_head);
- ath_tx_rc_status(bf, ts, 0, 0, false);
+ ath_tx_rc_status(bf, ts, 1, 0, false);
ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
0, 0);
@@ -431,7 +436,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
list_move_tail(&bf->list, &bf_head);
}
- if (!txpending) {
+ if (!txpending || (tid->state & AGGR_CLEANUP)) {
/*
* complete the acked-ones/xretried ones; update
* block-ack window
@@ -442,6 +447,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
memcpy(tx_info->control.rates, rates, sizeof(rates));
+ bf->bf_nframes = nframes;
ath_tx_rc_status(bf, ts, nbad, txok, true);
rc_update = false;
} else {
@@ -510,15 +516,12 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
}
if (tid->state & AGGR_CLEANUP) {
+ ath_tx_flush_tid(sc, tid);
+
if (tid->baw_head == tid->baw_tail) {
tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->state &= ~AGGR_CLEANUP;
-
- /* send buffered frames as singles */
- ath_tx_flush_tid(sc, tid);
}
- rcu_read_unlock();
- return;
}
rcu_read_unlock();
@@ -670,6 +673,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
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;
bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
@@ -696,6 +700,11 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
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)))
+ break;
+
/* do not exceed subframe limit */
if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
status = ATH_AGGR_LIMITED;
@@ -785,17 +794,23 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
status != ATH_AGGR_BAW_CLOSED);
}
-void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
- u16 tid, u16 *ssn)
+int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+ u16 tid, u16 *ssn)
{
struct ath_atx_tid *txtid;
struct ath_node *an;
an = (struct ath_node *)sta->drv_priv;
txtid = ATH_AN_2_TID(an, tid);
+
+ if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
+ return -EAGAIN;
+
txtid->state |= AGGR_ADDBA_PROGRESS;
txtid->paused = true;
*ssn = txtid->seq_start;
+
+ return 0;
}
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
@@ -803,12 +818,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
struct ath_node *an = (struct ath_node *)sta->drv_priv;
struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum];
- struct ath_tx_status ts;
- struct ath_buf *bf;
- struct list_head bf_head;
-
- memset(&ts, 0, sizeof(ts));
- INIT_LIST_HEAD(&bf_head);
if (txtid->state & AGGR_CLEANUP)
return;
@@ -818,31 +827,22 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
return;
}
- /* drop all software retried frames and mark this TID */
spin_lock_bh(&txq->axq_lock);
txtid->paused = true;
- while (!list_empty(&txtid->buf_q)) {
- bf = list_first_entry(&txtid->buf_q, struct ath_buf, list);
- if (!bf_isretried(bf)) {
- /*
- * NB: it's based on the assumption that
- * software retried frame will always stay
- * at the head of software queue.
- */
- break;
- }
- list_move_tail(&bf->list, &bf_head);
- ath_tx_update_baw(sc, txtid, bf->bf_seqno);
- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
- }
- spin_unlock_bh(&txq->axq_lock);
- if (txtid->baw_head != txtid->baw_tail) {
+ /*
+ * If frames are still being transmitted for this TID, they will be
+ * cleaned up during tx completion. To prevent race conditions, this
+ * TID can only be reused after all in-progress subframes have been
+ * completed.
+ */
+ if (txtid->baw_head != txtid->baw_tail)
txtid->state |= AGGR_CLEANUP;
- } else {
+ else
txtid->state &= ~AGGR_ADDBA_COMPLETE;
- ath_tx_flush_tid(sc, txtid);
- }
+ spin_unlock_bh(&txq->axq_lock);
+
+ ath_tx_flush_tid(sc, txtid);
}
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
@@ -862,20 +862,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid
}
}
-bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
-{
- struct ath_atx_tid *txtid;
-
- if (!(sc->sc_flags & SC_OP_TXAGGR))
- return false;
-
- txtid = ATH_AN_2_TID(an, tidno);
-
- if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
- return true;
- return false;
-}
-
/********************/
/* Queue Management */
/********************/
@@ -1407,22 +1393,6 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
return htype;
}
-static int get_hw_crypto_keytype(struct sk_buff *skb)
-{
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-
- if (tx_info->control.hw_key) {
- if (tx_info->control.hw_key->alg == ALG_WEP)
- return ATH9K_KEY_TYPE_WEP;
- else if (tx_info->control.hw_key->alg == ALG_TKIP)
- return ATH9K_KEY_TYPE_TKIP;
- else if (tx_info->control.hw_key->alg == ALG_CCMP)
- return ATH9K_KEY_TYPE_AES;
- }
-
- return ATH9K_KEY_TYPE_CLEAR;
-}
-
static void assign_aggr_tid_seqno(struct sk_buff *skb,
struct ath_buf *bf)
{
@@ -1661,7 +1631,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
bf->bf_state.bfs_paprd_timestamp = jiffies;
bf->bf_flags = setup_tx_flags(skb, use_ldpc);
- bf->bf_keytype = get_hw_crypto_keytype(skb);
+ bf->bf_keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
bf->bf_frmlen += tx_info->control.hw_key->icv_len;
bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
@@ -1675,24 +1645,16 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
bf->bf_mpdu = skb;
- bf->bf_dmacontext = dma_map_single(sc->dev, skb->data,
- skb->len, DMA_TO_DEVICE);
- if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
+ bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
+ skb->len, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
bf->bf_mpdu = NULL;
+ bf->bf_buf_addr = 0;
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
"dma_mapping_error() on TX\n");
return -ENOMEM;
}
- bf->bf_buf_addr = bf->bf_dmacontext;
-
- /* tag if this is a nullfunc frame to enable PS when AP acks it */
- if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
- bf->bf_isnullfunc = true;
- sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
- } else
- bf->bf_isnullfunc = false;
-
bf->bf_tx_aborted = false;
return 0;
@@ -1956,7 +1918,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
tx_flags |= ATH_TX_XRETRY;
}
- dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
+ dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
+ bf->bf_buf_addr = 0;
if (bf->bf_state.bfs_paprd) {
if (time_after(jiffies,
@@ -1966,9 +1929,13 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
else
complete(&sc->paprd_complete);
} else {
- ath_tx_complete(sc, skb, bf->aphy, tx_flags);
ath_debug_stat_tx(sc, txq, bf, ts);
+ ath_tx_complete(sc, skb, bf->aphy, tx_flags);
}
+ /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
+ * accidentally reference it later.
+ */
+ bf->bf_mpdu = NULL;
/*
* Return the list of ath_buf of this mpdu to free queue
@@ -2024,9 +1991,15 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
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) && update_rc) {
tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
+ BUG_ON(nbad > bf->bf_nframes);
+
+ tx_info->status.ampdu_len = bf->bf_nframes;
+ tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
+ }
+
if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
(bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
if (ieee80211_is_data(hdr->frame_control)) {
@@ -2036,8 +2009,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
(ts->ts_status & ATH9K_TXERR_FIFO))
tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
- tx_info->status.ampdu_len = bf->bf_nframes;
- tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
}
}
@@ -2120,18 +2091,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
}
/*
- * We now know the nullfunc frame has been ACKed so we
- * can disable RX.
- */
- if (bf->bf_isnullfunc &&
- (ts.ts_status & ATH9K_TX_ACKED)) {
- if ((sc->ps_flags & PS_ENABLED))
- ath9k_enable_ps(sc);
- else
- sc->ps_flags |= PS_NULLFUNC_COMPLETED;
- }
-
- /*
* Remove ath_buf's of the same transmit unit from txq,
* however leave the last descriptor back as the holding
* descriptor for hw.
@@ -2159,7 +2118,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
*/
if (ts.ts_status & ATH9K_TXERR_XRETRY)
bf->bf_state.bf_type |= BUF_XRETRY;
- ath_tx_rc_status(bf, &ts, 0, txok, true);
+ ath_tx_rc_status(bf, &ts, txok ? 0 : 1, txok, true);
}
if (bf_isampdu(bf))
@@ -2204,7 +2163,7 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
"tx hung, resetting the chip\n");
ath9k_ps_wakeup(sc);
- ath_reset(sc, false);
+ ath_reset(sc, true);
ath9k_ps_restore(sc);
}
@@ -2274,21 +2233,10 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
txok = !(txs.ts_status & ATH9K_TXERR_MASK);
- /*
- * Make sure null func frame is acked before configuring
- * hw into ps mode.
- */
- if (bf->bf_isnullfunc && txok) {
- if ((sc->ps_flags & PS_ENABLED))
- ath9k_enable_ps(sc);
- else
- sc->ps_flags |= PS_NULLFUNC_COMPLETED;
- }
-
if (!bf_isampdu(bf)) {
if (txs.ts_status & ATH9K_TXERR_XRETRY)
bf->bf_state.bf_type |= BUF_XRETRY;
- ath_tx_rc_status(bf, &txs, 0, txok, true);
+ ath_tx_rc_status(bf, &txs, txok ? 0 : 1, txok, true);
}
if (bf_isampdu(bf))
diff --git a/drivers/net/wireless/ath/carl9170/Kconfig b/drivers/net/wireless/ath/carl9170/Kconfig
new file mode 100644
index 000000000000..2d1b821b440d
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/Kconfig
@@ -0,0 +1,41 @@
+config CARL9170
+ tristate "Linux Community AR9170 802.11n USB support"
+ depends on USB && MAC80211 && EXPERIMENTAL
+ select FW_LOADER
+ select CRC32
+ help
+ This is another driver for the Atheros "otus" 802.11n USB devices.
+
+ This driver provides more features than the original,
+ but it needs a special firmware (carl9170-1.fw) to do that.
+
+ The firmware can be downloaded from our wiki here:
+ <http://wireless.kernel.org/en/users/Drivers/carl9170>
+
+ If you choose to build a module, it'll be called carl9170.
+
+config CARL9170_LEDS
+ bool "SoftLED Support"
+ depends on CARL9170
+ select MAC80211_LEDS
+ select LEDS_CLASS
+ select NEW_LEDS
+ default y
+ help
+ This option is necessary, if you want your device' LEDs to blink
+
+ Say Y, unless you need the LEDs for firmware debugging.
+
+config CARL9170_DEBUGFS
+ bool "DebugFS Support"
+ depends on CARL9170 && DEBUG_FS && MAC80211_DEBUGFS
+ default n
+ help
+ Export several driver and device internals to user space.
+
+ Say N.
+
+config CARL9170_WPC
+ bool
+ depends on CARL9170 && (INPUT = y || INPUT = CARL9170)
+ default y
diff --git a/drivers/net/wireless/ath/carl9170/Makefile b/drivers/net/wireless/ath/carl9170/Makefile
new file mode 100644
index 000000000000..f64ed76af8ad
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/Makefile
@@ -0,0 +1,4 @@
+carl9170-objs := main.o usb.o cmd.o mac.o phy.o led.o fw.o tx.o rx.o
+carl9170-$(CONFIG_CARL9170_DEBUGFS) += debug.o
+
+obj-$(CONFIG_CARL9170) += carl9170.o
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
new file mode 100644
index 000000000000..6cf0c9ef47aa
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -0,0 +1,628 @@
+/*
+ * Atheros CARL9170 driver
+ *
+ * Driver specific definitions
+ *
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.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; see the file COPYING. If not, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2007-2008 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 __CARL9170_H
+#define __CARL9170_H
+
+#include <linux/kernel.h>
+#include <linux/firmware.h>
+#include <linux/completion.h>
+#include <linux/spinlock.h>
+#include <net/cfg80211.h>
+#include <net/mac80211.h>
+#include <linux/usb.h>
+#ifdef CONFIG_CARL9170_LEDS
+#include <linux/leds.h>
+#endif /* CONFIG_CARL170_LEDS */
+#ifdef CONFIG_CARL9170_WPC
+#include <linux/input.h>
+#endif /* CONFIG_CARL9170_WPC */
+#include "eeprom.h"
+#include "wlan.h"
+#include "hw.h"
+#include "fwdesc.h"
+#include "fwcmd.h"
+#include "../regd.h"
+
+#ifdef CONFIG_CARL9170_DEBUGFS
+#include "debug.h"
+#endif /* CONFIG_CARL9170_DEBUGFS */
+
+#define CARL9170FW_NAME "carl9170-1.fw"
+
+#define PAYLOAD_MAX (CARL9170_MAX_CMD_LEN / 4 - 1)
+
+enum carl9170_rf_init_mode {
+ CARL9170_RFI_NONE,
+ CARL9170_RFI_WARM,
+ CARL9170_RFI_COLD,
+};
+
+#define CARL9170_MAX_RX_BUFFER_SIZE 8192
+
+enum carl9170_device_state {
+ CARL9170_UNKNOWN_STATE,
+ CARL9170_STOPPED,
+ CARL9170_IDLE,
+ CARL9170_STARTED,
+};
+
+#define CARL9170_NUM_TID 16
+#define WME_BA_BMP_SIZE 64
+#define CARL9170_TX_USER_RATE_TRIES 3
+
+#define WME_AC_BE 2
+#define WME_AC_BK 3
+#define WME_AC_VI 1
+#define WME_AC_VO 0
+
+#define TID_TO_WME_AC(_tid) \
+ ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
+ (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
+ (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
+ WME_AC_VO)
+
+#define SEQ_DIFF(_start, _seq) \
+ (((_start) - (_seq)) & 0x0fff)
+#define SEQ_PREV(_seq) \
+ (((_seq) - 1) & 0x0fff)
+#define SEQ_NEXT(_seq) \
+ (((_seq) + 1) & 0x0fff)
+#define BAW_WITHIN(_start, _bawsz, _seqno) \
+ ((((_seqno) - (_start)) & 0xfff) < (_bawsz))
+
+enum carl9170_tid_state {
+ CARL9170_TID_STATE_INVALID,
+ CARL9170_TID_STATE_KILLED,
+ CARL9170_TID_STATE_SHUTDOWN,
+ CARL9170_TID_STATE_SUSPEND,
+ CARL9170_TID_STATE_PROGRESS,
+ CARL9170_TID_STATE_IDLE,
+ CARL9170_TID_STATE_XMIT,
+};
+
+#define CARL9170_BAW_BITS (2 * WME_BA_BMP_SIZE)
+#define CARL9170_BAW_SIZE (BITS_TO_LONGS(CARL9170_BAW_BITS))
+#define CARL9170_BAW_LEN (DIV_ROUND_UP(CARL9170_BAW_BITS, BITS_PER_BYTE))
+
+struct carl9170_sta_tid {
+ /* must be the first entry! */
+ struct list_head list;
+
+ /* temporary list for RCU unlink procedure */
+ struct list_head tmp_list;
+
+ /* lock for the following data structures */
+ spinlock_t lock;
+
+ unsigned int counter;
+ enum carl9170_tid_state state;
+ u8 tid; /* TID number ( 0 - 15 ) */
+ u16 max; /* max. AMPDU size */
+
+ u16 snx; /* awaiting _next_ frame */
+ u16 hsn; /* highest _queued_ sequence */
+ u16 bsn; /* base of the tx/agg bitmap */
+ unsigned long bitmap[CARL9170_BAW_SIZE];
+
+ /* Preaggregation reorder queue */
+ struct sk_buff_head queue;
+};
+
+#define CARL9170_QUEUE_TIMEOUT 256
+#define CARL9170_BUMP_QUEUE 1000
+#define CARL9170_TX_TIMEOUT 2500
+#define CARL9170_JANITOR_DELAY 128
+#define CARL9170_QUEUE_STUCK_TIMEOUT 5500
+
+#define CARL9170_NUM_TX_AGG_MAX 30
+
+/*
+ * Tradeoff between stability/latency and speed.
+ *
+ * AR9170_TXQ_DEPTH is devised by dividing the amount of available
+ * tx buffers with the size of a full ethernet frame + overhead.
+ *
+ * Naturally: The higher the limit, the faster the device CAN send.
+ * However, even a slight over-commitment at the wrong time and the
+ * hardware is doomed to send all already-queued frames at suboptimal
+ * rates. This in turn leads to an enourmous amount of unsuccessful
+ * retries => Latency goes up, whereas the throughput goes down. CRASH!
+ */
+#define CARL9170_NUM_TX_LIMIT_HARD ((AR9170_TXQ_DEPTH * 3) / 2)
+#define CARL9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH)
+
+struct carl9170_tx_queue_stats {
+ unsigned int count;
+ unsigned int limit;
+ unsigned int len;
+};
+
+struct carl9170_vif {
+ unsigned int id;
+ struct ieee80211_vif *vif;
+};
+
+struct carl9170_vif_info {
+ struct list_head list;
+ bool active;
+ unsigned int id;
+ struct sk_buff *beacon;
+ bool enable_beacon;
+};
+
+#define AR9170_NUM_RX_URBS 16
+#define AR9170_NUM_RX_URBS_MUL 2
+#define AR9170_NUM_TX_URBS 8
+#define AR9170_NUM_RX_URBS_POOL (AR9170_NUM_RX_URBS_MUL * AR9170_NUM_RX_URBS)
+
+enum carl9170_device_features {
+ CARL9170_WPS_BUTTON = BIT(0),
+ CARL9170_ONE_LED = BIT(1),
+};
+
+#ifdef CONFIG_CARL9170_LEDS
+struct ar9170;
+
+struct carl9170_led {
+ struct ar9170 *ar;
+ struct led_classdev l;
+ char name[32];
+ unsigned int toggled;
+ bool last_state;
+ bool registered;
+};
+#endif /* CONFIG_CARL9170_LEDS */
+
+enum carl9170_restart_reasons {
+ CARL9170_RR_NO_REASON = 0,
+ CARL9170_RR_FATAL_FIRMWARE_ERROR,
+ CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS,
+ CARL9170_RR_WATCHDOG,
+ CARL9170_RR_STUCK_TX,
+ CARL9170_RR_SLOW_SYSTEM,
+ CARL9170_RR_COMMAND_TIMEOUT,
+ CARL9170_RR_TOO_MANY_PHY_ERRORS,
+ CARL9170_RR_LOST_RSP,
+ CARL9170_RR_INVALID_RSP,
+ CARL9170_RR_USER_REQUEST,
+
+ __CARL9170_RR_LAST,
+};
+
+enum carl9170_erp_modes {
+ CARL9170_ERP_INVALID,
+ CARL9170_ERP_AUTO,
+ CARL9170_ERP_MAC80211,
+ CARL9170_ERP_OFF,
+ CARL9170_ERP_CTS,
+ CARL9170_ERP_RTS,
+ __CARL9170_ERP_NUM,
+};
+
+struct ar9170 {
+ struct ath_common common;
+ struct ieee80211_hw *hw;
+ struct mutex mutex;
+ enum carl9170_device_state state;
+ spinlock_t state_lock;
+ enum carl9170_restart_reasons last_reason;
+ bool registered;
+
+ /* USB */
+ struct usb_device *udev;
+ struct usb_interface *intf;
+ struct usb_anchor rx_anch;
+ struct usb_anchor rx_work;
+ struct usb_anchor rx_pool;
+ struct usb_anchor tx_wait;
+ struct usb_anchor tx_anch;
+ struct usb_anchor tx_cmd;
+ struct usb_anchor tx_err;
+ struct tasklet_struct usb_tasklet;
+ atomic_t tx_cmd_urbs;
+ atomic_t tx_anch_urbs;
+ atomic_t rx_anch_urbs;
+ atomic_t rx_work_urbs;
+ atomic_t rx_pool_urbs;
+ kernel_ulong_t features;
+
+ /* firmware settings */
+ struct completion fw_load_wait;
+ struct completion fw_boot_wait;
+ struct {
+ const struct carl9170fw_desc_head *desc;
+ const struct firmware *fw;
+ unsigned int offset;
+ unsigned int address;
+ unsigned int cmd_bufs;
+ unsigned int api_version;
+ unsigned int vif_num;
+ unsigned int err_counter;
+ unsigned int bug_counter;
+ u32 beacon_addr;
+ unsigned int beacon_max_len;
+ bool rx_stream;
+ bool tx_stream;
+ bool rx_filter;
+ unsigned int mem_blocks;
+ unsigned int mem_block_size;
+ unsigned int rx_size;
+ } fw;
+
+ /* reset / stuck frames/queue detection */
+ struct work_struct restart_work;
+ unsigned int restart_counter;
+ unsigned long queue_stop_timeout[__AR9170_NUM_TXQ];
+ unsigned long max_queue_stop_timeout[__AR9170_NUM_TXQ];
+ bool needs_full_reset;
+ atomic_t pending_restarts;
+
+ /* interface mode settings */
+ struct list_head vif_list;
+ unsigned long vif_bitmap;
+ unsigned int vifs;
+ struct carl9170_vif vif_priv[AR9170_MAX_VIRTUAL_MAC];
+
+ /* beaconing */
+ spinlock_t beacon_lock;
+ unsigned int global_pretbtt;
+ unsigned int global_beacon_int;
+ struct carl9170_vif_info *beacon_iter;
+ unsigned int beacon_enabled;
+
+ /* cryptographic engine */
+ u64 usedkeys;
+ bool rx_software_decryption;
+ bool disable_offload;
+
+ /* filter settings */
+ u64 cur_mc_hash;
+ u32 cur_filter;
+ unsigned int filter_state;
+ unsigned int rx_filter_caps;
+ bool sniffer_enabled;
+
+ /* MAC */
+ enum carl9170_erp_modes erp_mode;
+
+ /* PHY */
+ struct ieee80211_channel *channel;
+ int noise[4];
+ unsigned int chan_fail;
+ unsigned int total_chan_fail;
+ u8 heavy_clip;
+ u8 ht_settings;
+
+ /* power calibration data */
+ u8 power_5G_leg[4];
+ u8 power_2G_cck[4];
+ u8 power_2G_ofdm[4];
+ u8 power_5G_ht20[8];
+ u8 power_5G_ht40[8];
+ u8 power_2G_ht20[8];
+ u8 power_2G_ht40[8];
+
+#ifdef CONFIG_CARL9170_LEDS
+ /* LED */
+ struct delayed_work led_work;
+ struct carl9170_led leds[AR9170_NUM_LEDS];
+#endif /* CONFIG_CARL9170_LEDS */
+
+ /* qos queue settings */
+ spinlock_t tx_stats_lock;
+ struct carl9170_tx_queue_stats tx_stats[__AR9170_NUM_TXQ];
+ struct ieee80211_tx_queue_params edcf[5];
+ struct completion tx_flush;
+
+ /* CMD */
+ int cmd_seq;
+ int readlen;
+ u8 *readbuf;
+ spinlock_t cmd_lock;
+ struct completion cmd_wait;
+ union {
+ __le32 cmd_buf[PAYLOAD_MAX + 1];
+ struct carl9170_cmd cmd;
+ struct carl9170_rsp rsp;
+ };
+
+ /* statistics */
+ unsigned int tx_dropped;
+ unsigned int tx_ack_failures;
+ unsigned int tx_fcs_errors;
+ unsigned int rx_dropped;
+
+ /* EEPROM */
+ struct ar9170_eeprom eeprom;
+
+ /* tx queuing */
+ struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
+ struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
+ struct delayed_work tx_janitor;
+ unsigned long tx_janitor_last_run;
+ bool tx_schedule;
+
+ /* tx ampdu */
+ struct work_struct ampdu_work;
+ spinlock_t tx_ampdu_list_lock;
+ struct carl9170_sta_tid *tx_ampdu_iter;
+ struct list_head tx_ampdu_list;
+ atomic_t tx_ampdu_upload;
+ atomic_t tx_ampdu_scheduler;
+ atomic_t tx_total_pending;
+ atomic_t tx_total_queued;
+ unsigned int tx_ampdu_list_len;
+ int current_density;
+ int current_factor;
+ bool tx_ampdu_schedule;
+
+ /* internal memory management */
+ spinlock_t mem_lock;
+ unsigned long *mem_bitmap;
+ atomic_t mem_free_blocks;
+ atomic_t mem_allocs;
+
+ /* rxstream mpdu merge */
+ struct ar9170_rx_head rx_plcp;
+ bool rx_has_plcp;
+ struct sk_buff *rx_failover;
+ int rx_failover_missing;
+
+#ifdef CONFIG_CARL9170_WPC
+ struct {
+ bool pbc_state;
+ struct input_dev *pbc;
+ char name[32];
+ char phys[32];
+ } wps;
+#endif /* CONFIG_CARL9170_WPC */
+
+#ifdef CONFIG_CARL9170_DEBUGFS
+ struct carl9170_debug debug;
+ struct dentry *debug_dir;
+#endif /* CONFIG_CARL9170_DEBUGFS */
+
+ /* PSM */
+ struct work_struct ps_work;
+ struct {
+ unsigned int dtim_counter;
+ unsigned long last_beacon;
+ unsigned long last_action;
+ unsigned long last_slept;
+ unsigned int sleep_ms;
+ unsigned int off_override;
+ bool state;
+ } ps;
+};
+
+enum carl9170_ps_off_override_reasons {
+ PS_OFF_VIF = BIT(0),
+ PS_OFF_BCN = BIT(1),
+ PS_OFF_5GHZ = BIT(2),
+};
+
+struct carl9170_ba_stats {
+ u8 ampdu_len;
+ u8 ampdu_ack_len;
+ bool clear;
+};
+
+struct carl9170_sta_info {
+ bool ht_sta;
+ unsigned int ampdu_max_len;
+ struct carl9170_sta_tid *agg[CARL9170_NUM_TID];
+ struct carl9170_ba_stats stats[CARL9170_NUM_TID];
+};
+
+struct carl9170_tx_info {
+ unsigned long timeout;
+ struct ar9170 *ar;
+ struct kref ref;
+};
+
+#define CHK_DEV_STATE(a, s) (((struct ar9170 *)a)->state >= (s))
+#define IS_INITIALIZED(a) (CHK_DEV_STATE(a, CARL9170_STOPPED))
+#define IS_ACCEPTING_CMD(a) (CHK_DEV_STATE(a, CARL9170_IDLE))
+#define IS_STARTED(a) (CHK_DEV_STATE(a, CARL9170_STARTED))
+
+static inline void __carl9170_set_state(struct ar9170 *ar,
+ enum carl9170_device_state newstate)
+{
+ ar->state = newstate;
+}
+
+static inline void carl9170_set_state(struct ar9170 *ar,
+ enum carl9170_device_state newstate)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ar->state_lock, flags);
+ __carl9170_set_state(ar, newstate);
+ spin_unlock_irqrestore(&ar->state_lock, flags);
+}
+
+static inline void carl9170_set_state_when(struct ar9170 *ar,
+ enum carl9170_device_state min, enum carl9170_device_state newstate)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ar->state_lock, flags);
+ if (CHK_DEV_STATE(ar, min))
+ __carl9170_set_state(ar, newstate);
+ spin_unlock_irqrestore(&ar->state_lock, flags);
+}
+
+/* exported interface */
+void *carl9170_alloc(size_t priv_size);
+int carl9170_register(struct ar9170 *ar);
+void carl9170_unregister(struct ar9170 *ar);
+void carl9170_free(struct ar9170 *ar);
+void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r);
+void carl9170_ps_check(struct ar9170 *ar);
+
+/* USB back-end */
+int carl9170_usb_open(struct ar9170 *ar);
+void carl9170_usb_stop(struct ar9170 *ar);
+void carl9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb);
+void carl9170_usb_handle_tx_err(struct ar9170 *ar);
+int carl9170_exec_cmd(struct ar9170 *ar, const enum carl9170_cmd_oids,
+ u32 plen, void *payload, u32 rlen, void *resp);
+int __carl9170_exec_cmd(struct ar9170 *ar, struct carl9170_cmd *cmd,
+ const bool free_buf);
+int carl9170_usb_restart(struct ar9170 *ar);
+void carl9170_usb_reset(struct ar9170 *ar);
+
+/* MAC */
+int carl9170_init_mac(struct ar9170 *ar);
+int carl9170_set_qos(struct ar9170 *ar);
+int carl9170_update_multicast(struct ar9170 *ar, const u64 mc_hast);
+int carl9170_mod_virtual_mac(struct ar9170 *ar, const unsigned int id,
+ const u8 *mac);
+int carl9170_set_operating_mode(struct ar9170 *ar);
+int carl9170_set_beacon_timers(struct ar9170 *ar);
+int carl9170_set_dyn_sifs_ack(struct ar9170 *ar);
+int carl9170_set_rts_cts_rate(struct ar9170 *ar);
+int carl9170_set_ampdu_settings(struct ar9170 *ar);
+int carl9170_set_slot_time(struct ar9170 *ar);
+int carl9170_set_mac_rates(struct ar9170 *ar);
+int carl9170_set_hwretry_limit(struct ar9170 *ar, const u32 max_retry);
+int carl9170_update_beacon(struct ar9170 *ar, const bool submit);
+int carl9170_upload_key(struct ar9170 *ar, const u8 id, const u8 *mac,
+ const u8 ktype, const u8 keyidx, const u8 *keydata, const int keylen);
+int carl9170_disable_key(struct ar9170 *ar, const u8 id);
+
+/* RX */
+void carl9170_rx(struct ar9170 *ar, void *buf, unsigned int len);
+void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len);
+
+/* TX */
+int carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
+void carl9170_tx_janitor(struct work_struct *work);
+void carl9170_tx_process_status(struct ar9170 *ar,
+ const struct carl9170_rsp *cmd);
+void carl9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
+ const bool success);
+void carl9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb);
+void carl9170_tx_drop(struct ar9170 *ar, struct sk_buff *skb);
+void carl9170_tx_scheduler(struct ar9170 *ar);
+void carl9170_tx_get_skb(struct sk_buff *skb);
+int carl9170_tx_put_skb(struct sk_buff *skb);
+
+/* LEDs */
+#ifdef CONFIG_CARL9170_LEDS
+int carl9170_led_register(struct ar9170 *ar);
+void carl9170_led_unregister(struct ar9170 *ar);
+#endif /* CONFIG_CARL9170_LEDS */
+int carl9170_led_init(struct ar9170 *ar);
+int carl9170_led_set_state(struct ar9170 *ar, const u32 led_state);
+
+/* PHY / RF */
+int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
+ enum nl80211_channel_type bw, enum carl9170_rf_init_mode rfi);
+int carl9170_get_noisefloor(struct ar9170 *ar);
+
+/* FW */
+int carl9170_parse_firmware(struct ar9170 *ar);
+int carl9170_fw_fix_eeprom(struct ar9170 *ar);
+
+extern struct ieee80211_rate __carl9170_ratetable[];
+extern int modparam_noht;
+
+static inline struct ar9170 *carl9170_get_priv(struct carl9170_vif *carl_vif)
+{
+ return container_of(carl_vif, struct ar9170,
+ vif_priv[carl_vif->id]);
+}
+
+static inline struct ieee80211_hdr *carl9170_get_hdr(struct sk_buff *skb)
+{
+ return (void *)((struct _carl9170_tx_superframe *)
+ skb->data)->frame_data;
+}
+
+static inline u16 get_seq_h(struct ieee80211_hdr *hdr)
+{
+ return le16_to_cpu(hdr->seq_ctrl) >> 4;
+}
+
+static inline u16 carl9170_get_seq(struct sk_buff *skb)
+{
+ return get_seq_h(carl9170_get_hdr(skb));
+}
+
+static inline u16 get_tid_h(struct ieee80211_hdr *hdr)
+{
+ return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
+static inline u16 carl9170_get_tid(struct sk_buff *skb)
+{
+ return get_tid_h(carl9170_get_hdr(skb));
+}
+
+static inline struct ieee80211_vif *
+carl9170_get_vif(struct carl9170_vif_info *priv)
+{
+ return container_of((void *)priv, struct ieee80211_vif, drv_priv);
+}
+
+/* Protected by ar->mutex or RCU */
+static inline struct ieee80211_vif *carl9170_get_main_vif(struct ar9170 *ar)
+{
+ struct carl9170_vif_info *cvif;
+
+ list_for_each_entry_rcu(cvif, &ar->vif_list, list) {
+ if (cvif->active)
+ return carl9170_get_vif(cvif);
+ }
+
+ return NULL;
+}
+
+static inline bool is_main_vif(struct ar9170 *ar, struct ieee80211_vif *vif)
+{
+ bool ret;
+
+ rcu_read_lock();
+ ret = (carl9170_get_main_vif(ar) == vif);
+ rcu_read_unlock();
+ return ret;
+}
+
+#endif /* __CARL9170_H */
diff --git a/drivers/net/wireless/ath/carl9170/cmd.c b/drivers/net/wireless/ath/carl9170/cmd.c
new file mode 100644
index 000000000000..c21f3364bfec
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/cmd.c
@@ -0,0 +1,188 @@
+/*
+ * Atheros CARL9170 driver
+ *
+ * Basic HW register/memory/command access functions
+ *
+ * Copyright 2008, 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 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, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2007-2008 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 "carl9170.h"
+#include "cmd.h"
+
+int carl9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val)
+{
+ __le32 buf[2] = {
+ cpu_to_le32(reg),
+ cpu_to_le32(val),
+ };
+ int err;
+
+ err = carl9170_exec_cmd(ar, CARL9170_CMD_WREG, sizeof(buf),
+ (u8 *) buf, 0, NULL);
+ if (err) {
+ if (net_ratelimit()) {
+ wiphy_err(ar->hw->wiphy, "writing reg %#x "
+ "(val %#x) failed (%d)\n", reg, val, err);
+ }
+ }
+ return err;
+}
+
+int carl9170_read_mreg(struct ar9170 *ar, const int nregs,
+ const u32 *regs, u32 *out)
+{
+ int i, err;
+ __le32 *offs, *res;
+
+ /* abuse "out" for the register offsets, must be same length */
+ offs = (__le32 *)out;
+ for (i = 0; i < nregs; i++)
+ offs[i] = cpu_to_le32(regs[i]);
+
+ /* also use the same buffer for the input */
+ res = (__le32 *)out;
+
+ err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG,
+ 4 * nregs, (u8 *)offs,
+ 4 * nregs, (u8 *)res);
+ if (err) {
+ if (net_ratelimit()) {
+ wiphy_err(ar->hw->wiphy, "reading regs failed (%d)\n",
+ err);
+ }
+ return err;
+ }
+
+ /* convert result to cpu endian */
+ for (i = 0; i < nregs; i++)
+ out[i] = le32_to_cpu(res[i]);
+
+ return 0;
+}
+
+int carl9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val)
+{
+ return carl9170_read_mreg(ar, 1, &reg, val);
+}
+
+int carl9170_echo_test(struct ar9170 *ar, const u32 v)
+{
+ u32 echores;
+ int err;
+
+ err = carl9170_exec_cmd(ar, CARL9170_CMD_ECHO,
+ 4, (u8 *)&v,
+ 4, (u8 *)&echores);
+ if (err)
+ return err;
+
+ if (v != echores) {
+ wiphy_info(ar->hw->wiphy, "wrong echo %x != %x", v, echores);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+struct carl9170_cmd *carl9170_cmd_buf(struct ar9170 *ar,
+ const enum carl9170_cmd_oids cmd, const unsigned int len)
+{
+ struct carl9170_cmd *tmp;
+
+ tmp = kzalloc(sizeof(struct carl9170_cmd_head) + len, GFP_ATOMIC);
+ if (tmp) {
+ tmp->hdr.cmd = cmd;
+ tmp->hdr.len = len;
+ }
+
+ return tmp;
+}
+
+int carl9170_reboot(struct ar9170 *ar)
+{
+ struct carl9170_cmd *cmd;
+ int err;
+
+ cmd = carl9170_cmd_buf(ar, CARL9170_CMD_REBOOT_ASYNC, 0);
+ if (!cmd)
+ return -ENOMEM;
+
+ err = __carl9170_exec_cmd(ar, (struct carl9170_cmd *)cmd, true);
+ return err;
+}
+
+int carl9170_mac_reset(struct ar9170 *ar)
+{
+ return carl9170_exec_cmd(ar, CARL9170_CMD_SWRST,
+ 0, NULL, 0, NULL);
+}
+
+int carl9170_bcn_ctrl(struct ar9170 *ar, const unsigned int vif_id,
+ const u32 mode, const u32 addr, const u32 len)
+{
+ struct carl9170_cmd *cmd;
+
+ cmd = carl9170_cmd_buf(ar, CARL9170_CMD_BCN_CTRL_ASYNC,
+ sizeof(struct carl9170_bcn_ctrl_cmd));
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->bcn_ctrl.vif_id = cpu_to_le32(vif_id);
+ cmd->bcn_ctrl.mode = cpu_to_le32(mode);
+ cmd->bcn_ctrl.bcn_addr = cpu_to_le32(addr);
+ cmd->bcn_ctrl.bcn_len = cpu_to_le32(len);
+
+ return __carl9170_exec_cmd(ar, cmd, true);
+}
+
+int carl9170_powersave(struct ar9170 *ar, const bool ps)
+{
+ struct carl9170_cmd *cmd;
+ u32 state;
+
+ cmd = carl9170_cmd_buf(ar, CARL9170_CMD_PSM_ASYNC,
+ sizeof(struct carl9170_psm));
+ if (!cmd)
+ return -ENOMEM;
+
+ if (ps) {
+ /* Sleep until next TBTT */
+ state = CARL9170_PSM_SLEEP | 1;
+ } else {
+ /* wake up immediately */
+ state = 1;
+ }
+
+ cmd->psm.state = cpu_to_le32(state);
+ return __carl9170_exec_cmd(ar, cmd, true);
+}
diff --git a/drivers/net/wireless/ath/carl9170/cmd.h b/drivers/net/wireless/ath/carl9170/cmd.h
new file mode 100644
index 000000000000..568174c71b94
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/cmd.h
@@ -0,0 +1,173 @@
+/*
+ * Atheros CARL9170 driver
+ *
+ * Basic HW register/memory/command access functions
+ *
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2010, Christian Lamparter <chunkeey@googlemail.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; see the file COPYING. If not, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2007-2008 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 __CMD_H
+#define __CMD_H
+
+#include "carl9170.h"
+
+/* basic HW access */
+int carl9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val);
+int carl9170_read_reg(struct ar9170 *ar, const u32 reg, u32 *val);
+int carl9170_read_mreg(struct ar9170 *ar, const int nregs,
+ const u32 *regs, u32 *out);
+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_bcn_ctrl(struct ar9170 *ar, const unsigned int vif_id,
+ const u32 mode, const u32 addr, const u32 len);
+
+static inline int carl9170_flush_cab(struct ar9170 *ar,
+ const unsigned int vif_id)
+{
+ return carl9170_bcn_ctrl(ar, vif_id, CARL9170_BCN_CTRL_DRAIN, 0, 0);
+}
+
+static inline int carl9170_rx_filter(struct ar9170 *ar,
+ const unsigned int _rx_filter)
+{
+ __le32 rx_filter = cpu_to_le32(_rx_filter);
+
+ return carl9170_exec_cmd(ar, CARL9170_CMD_RX_FILTER,
+ sizeof(rx_filter), (u8 *)&rx_filter,
+ 0, NULL);
+}
+
+struct carl9170_cmd *carl9170_cmd_buf(struct ar9170 *ar,
+ const enum carl9170_cmd_oids cmd, const unsigned int len);
+
+/*
+ * Macros to facilitate writing multiple registers in a single
+ * write-combining USB command. Note that when the first group
+ * fails the whole thing will fail without any others attempted,
+ * but you won't know which write in the group failed.
+ */
+#define carl9170_regwrite_begin(ar) \
+do { \
+ int __nreg = 0, __err = 0; \
+ struct ar9170 *__ar = ar;
+
+#define carl9170_regwrite(r, v) do { \
+ __ar->cmd_buf[2 * __nreg + 1] = cpu_to_le32(r); \
+ __ar->cmd_buf[2 * __nreg + 2] = cpu_to_le32(v); \
+ __nreg++; \
+ if ((__nreg >= PAYLOAD_MAX/2)) { \
+ if (IS_ACCEPTING_CMD(__ar)) \
+ __err = carl9170_exec_cmd(__ar, \
+ CARL9170_CMD_WREG, 8 * __nreg, \
+ (u8 *) &__ar->cmd_buf[1], 0, NULL); \
+ else \
+ goto __regwrite_out; \
+ \
+ __nreg = 0; \
+ if (__err) \
+ goto __regwrite_out; \
+ } \
+} while (0)
+
+#define carl9170_regwrite_finish() \
+__regwrite_out : \
+ if (__err == 0 && __nreg) { \
+ if (IS_ACCEPTING_CMD(__ar)) \
+ __err = carl9170_exec_cmd(__ar, \
+ CARL9170_CMD_WREG, 8 * __nreg, \
+ (u8 *) &__ar->cmd_buf[1], 0, NULL); \
+ __nreg = 0; \
+ }
+
+#define carl9170_regwrite_result() \
+ __err; \
+} while (0);
+
+
+#define carl9170_async_regwrite_get_buf() \
+do { \
+ __nreg = 0; \
+ __cmd = carl9170_cmd_buf(__carl, CARL9170_CMD_WREG_ASYNC, \
+ CARL9170_MAX_CMD_PAYLOAD_LEN); \
+ if (__cmd == NULL) { \
+ __err = -ENOMEM; \
+ goto __async_regwrite_out; \
+ } \
+} while (0);
+
+#define carl9170_async_regwrite_begin(carl) \
+do { \
+ struct ar9170 *__carl = carl; \
+ struct carl9170_cmd *__cmd; \
+ unsigned int __nreg; \
+ int __err = 0; \
+ carl9170_async_regwrite_get_buf(); \
+
+#define carl9170_async_regwrite_flush() \
+do { \
+ if (__cmd == NULL || __nreg == 0) \
+ break; \
+ \
+ if (IS_ACCEPTING_CMD(__carl) && __nreg) { \
+ __cmd->hdr.len = 8 * __nreg; \
+ __err = __carl9170_exec_cmd(__carl, __cmd, true); \
+ __cmd = NULL; \
+ break; \
+ } \
+ goto __async_regwrite_out; \
+} while (0)
+
+#define carl9170_async_regwrite(r, v) do { \
+ if (__cmd == NULL) \
+ carl9170_async_regwrite_get_buf(); \
+ __cmd->wreg.regs[__nreg].addr = cpu_to_le32(r); \
+ __cmd->wreg.regs[__nreg].val = cpu_to_le32(v); \
+ __nreg++; \
+ if ((__nreg >= PAYLOAD_MAX / 2)) \
+ carl9170_async_regwrite_flush(); \
+} while (0)
+
+#define carl9170_async_regwrite_finish() do { \
+__async_regwrite_out : \
+ if (__cmd != NULL && __err == 0) \
+ carl9170_async_regwrite_flush(); \
+ kfree(__cmd); \
+} while (0) \
+
+#define carl9170_async_regwrite_result() \
+ __err; \
+} while (0);
+
+#endif /* __CMD_H */
diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c
new file mode 100644
index 000000000000..0ac1124c2a0b
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/debug.c
@@ -0,0 +1,902 @@
+/*
+ * Atheros CARL9170 driver
+ *
+ * debug(fs) probing
+ *
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.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; see the file COPYING. If not, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2008-2009 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/vmalloc.h>
+#include "carl9170.h"
+#include "cmd.h"
+
+#define ADD(buf, off, max, fmt, args...) \
+ off += snprintf(&buf[off], max - off, fmt, ##args);
+
+static int carl9170_debugfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+struct carl9170_debugfs_fops {
+ unsigned int read_bufsize;
+ mode_t attr;
+ char *(*read)(struct ar9170 *ar, char *buf, size_t bufsize,
+ ssize_t *len);
+ ssize_t (*write)(struct ar9170 *aru, const char *buf, size_t size);
+ const struct file_operations fops;
+
+ enum carl9170_device_state req_dev_state;
+};
+
+static ssize_t carl9170_debugfs_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct carl9170_debugfs_fops *dfops;
+ struct ar9170 *ar;
+ char *buf = NULL, *res_buf = NULL;
+ ssize_t ret = 0;
+ int err = 0;
+
+ if (!count)
+ return 0;
+
+ ar = file->private_data;
+
+ if (!ar)
+ return -ENODEV;
+ dfops = container_of(file->f_op, struct carl9170_debugfs_fops, fops);
+
+ if (!dfops->read)
+ return -ENOSYS;
+
+ if (dfops->read_bufsize) {
+ buf = vmalloc(dfops->read_bufsize);
+ if (!buf)
+ return -ENOMEM;
+ }
+
+ mutex_lock(&ar->mutex);
+ if (!CHK_DEV_STATE(ar, dfops->req_dev_state)) {
+ err = -ENODEV;
+ res_buf = buf;
+ goto out_free;
+ }
+
+ res_buf = dfops->read(ar, buf, dfops->read_bufsize, &ret);
+
+ if (ret > 0)
+ err = simple_read_from_buffer(userbuf, count, ppos,
+ res_buf, ret);
+ else
+ err = ret;
+
+ WARN_ON_ONCE(dfops->read_bufsize && (res_buf != buf));
+
+out_free:
+ vfree(res_buf);
+ mutex_unlock(&ar->mutex);
+ return err;
+}
+
+static ssize_t carl9170_debugfs_write(struct file *file,
+ const char __user *userbuf, size_t count, loff_t *ppos)
+{
+ struct carl9170_debugfs_fops *dfops;
+ struct ar9170 *ar;
+ char *buf = NULL;
+ int err = 0;
+
+ if (!count)
+ return 0;
+
+ if (count > PAGE_SIZE)
+ return -E2BIG;
+
+ ar = file->private_data;
+
+ if (!ar)
+ return -ENODEV;
+ dfops = container_of(file->f_op, struct carl9170_debugfs_fops, fops);
+
+ if (!dfops->write)
+ return -ENOSYS;
+
+ buf = vmalloc(count);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, userbuf, count)) {
+ err = -EFAULT;
+ goto out_free;
+ }
+
+ if (mutex_trylock(&ar->mutex) == 0) {
+ err = -EAGAIN;
+ goto out_free;
+ }
+
+ if (!CHK_DEV_STATE(ar, dfops->req_dev_state)) {
+ err = -ENODEV;
+ goto out_unlock;
+ }
+
+ err = dfops->write(ar, buf, count);
+ if (err)
+ goto out_unlock;
+
+out_unlock:
+ mutex_unlock(&ar->mutex);
+
+out_free:
+ vfree(buf);
+ return err;
+}
+
+#define __DEBUGFS_DECLARE_FILE(name, _read, _write, _read_bufsize, \
+ _attr, _dstate) \
+static const struct carl9170_debugfs_fops carl_debugfs_##name ##_ops = {\
+ .read_bufsize = _read_bufsize, \
+ .read = _read, \
+ .write = _write, \
+ .attr = _attr, \
+ .req_dev_state = _dstate, \
+ .fops = { \
+ .open = carl9170_debugfs_open, \
+ .read = carl9170_debugfs_read, \
+ .write = carl9170_debugfs_write, \
+ .owner = THIS_MODULE \
+ }, \
+}
+
+#define DEBUGFS_DECLARE_FILE(name, _read, _write, _read_bufsize, _attr) \
+ __DEBUGFS_DECLARE_FILE(name, _read, _write, _read_bufsize, \
+ _attr, CARL9170_STARTED) \
+
+#define DEBUGFS_DECLARE_RO_FILE(name, _read_bufsize) \
+ DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \
+ NULL, _read_bufsize, S_IRUSR)
+
+#define DEBUGFS_DECLARE_WO_FILE(name) \
+ DEBUGFS_DECLARE_FILE(name, NULL, carl9170_debugfs_##name ##_write,\
+ 0, S_IWUSR)
+
+#define DEBUGFS_DECLARE_RW_FILE(name, _read_bufsize) \
+ DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \
+ carl9170_debugfs_##name ##_write, \
+ _read_bufsize, S_IRUSR | S_IWUSR)
+
+#define __DEBUGFS_DECLARE_RW_FILE(name, _read_bufsize, _dstate) \
+ __DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \
+ carl9170_debugfs_##name ##_write, \
+ _read_bufsize, S_IRUSR | S_IWUSR, _dstate)
+
+#define DEBUGFS_READONLY_FILE(name, _read_bufsize, fmt, value...) \
+static char *carl9170_debugfs_ ##name ## _read(struct ar9170 *ar, \
+ char *buf, size_t buf_size,\
+ ssize_t *len) \
+{ \
+ ADD(buf, *len, buf_size, fmt "\n", ##value); \
+ return buf; \
+} \
+DEBUGFS_DECLARE_RO_FILE(name, _read_bufsize)
+
+static char *carl9170_debugfs_mem_usage_read(struct ar9170 *ar, char *buf,
+ size_t bufsize, ssize_t *len)
+{
+ ADD(buf, *len, bufsize, "jar: [");
+
+ spin_lock_bh(&ar->mem_lock);
+
+ *len += bitmap_scnprintf(&buf[*len], bufsize - *len,
+ ar->mem_bitmap, ar->fw.mem_blocks);
+
+ ADD(buf, *len, bufsize, "]\n");
+
+ ADD(buf, *len, bufsize, "cookies: used:%3d / total:%3d, allocs:%d\n",
+ bitmap_weight(ar->mem_bitmap, ar->fw.mem_blocks),
+ ar->fw.mem_blocks, atomic_read(&ar->mem_allocs));
+
+ ADD(buf, *len, bufsize, "memory: free:%3d (%3d KiB) / total:%3d KiB)\n",
+ atomic_read(&ar->mem_free_blocks),
+ (atomic_read(&ar->mem_free_blocks) * ar->fw.mem_block_size) / 1024,
+ (ar->fw.mem_blocks * ar->fw.mem_block_size) / 1024);
+
+ spin_unlock_bh(&ar->mem_lock);
+
+ return buf;
+}
+DEBUGFS_DECLARE_RO_FILE(mem_usage, 512);
+
+static char *carl9170_debugfs_qos_stat_read(struct ar9170 *ar, char *buf,
+ size_t bufsize, ssize_t *len)
+{
+ ADD(buf, *len, bufsize, "%s QoS AC\n", modparam_noht ? "Hardware" :
+ "Software");
+
+ ADD(buf, *len, bufsize, "[ VO VI "
+ " BE BK ]\n");
+
+ spin_lock_bh(&ar->tx_stats_lock);
+ ADD(buf, *len, bufsize, "[length/limit length/limit "
+ "length/limit length/limit ]\n"
+ "[ %3d/%3d %3d/%3d "
+ " %3d/%3d %3d/%3d ]\n\n",
+ ar->tx_stats[0].len, ar->tx_stats[0].limit,
+ ar->tx_stats[1].len, ar->tx_stats[1].limit,
+ ar->tx_stats[2].len, ar->tx_stats[2].limit,
+ ar->tx_stats[3].len, ar->tx_stats[3].limit);
+
+ ADD(buf, *len, bufsize, "[ total total "
+ " total total ]\n"
+ "[%10d %10d %10d %10d ]\n\n",
+ ar->tx_stats[0].count, ar->tx_stats[1].count,
+ ar->tx_stats[2].count, ar->tx_stats[3].count);
+
+ spin_unlock_bh(&ar->tx_stats_lock);
+
+ ADD(buf, *len, bufsize, "[ pend/waittx pend/waittx "
+ " pend/waittx pend/waittx]\n"
+ "[ %3d/%3d %3d/%3d "
+ " %3d/%3d %3d/%3d ]\n\n",
+ skb_queue_len(&ar->tx_pending[0]),
+ skb_queue_len(&ar->tx_status[0]),
+ skb_queue_len(&ar->tx_pending[1]),
+ skb_queue_len(&ar->tx_status[1]),
+ skb_queue_len(&ar->tx_pending[2]),
+ skb_queue_len(&ar->tx_status[2]),
+ skb_queue_len(&ar->tx_pending[3]),
+ skb_queue_len(&ar->tx_status[3]));
+
+ return buf;
+}
+DEBUGFS_DECLARE_RO_FILE(qos_stat, 512);
+
+static void carl9170_debugfs_format_frame(struct ar9170 *ar,
+ struct sk_buff *skb, const char *prefix, char *buf,
+ ssize_t *off, ssize_t bufsize)
+{
+ struct _carl9170_tx_superframe *txc = (void *) skb->data;
+ struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
+ struct carl9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
+ struct ieee80211_hdr *hdr = (void *) txc->frame_data;
+
+ ADD(buf, *off, bufsize, "%s %p, c:%2x, DA:%pM, sq:%4d, mc:%.4x, "
+ "pc:%.8x, to:%d ms\n", prefix, skb, txc->s.cookie,
+ ieee80211_get_DA(hdr), get_seq_h(hdr),
+ le16_to_cpu(txc->f.mac_control), le32_to_cpu(txc->f.phy_control),
+ jiffies_to_msecs(jiffies - arinfo->timeout));
+}
+
+
+static char *carl9170_debugfs_ampdu_state_read(struct ar9170 *ar, char *buf,
+ size_t bufsize, ssize_t *len)
+{
+ struct carl9170_sta_tid *iter;
+ struct sk_buff *skb;
+ int cnt = 0, fc;
+ int offset;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(iter, &ar->tx_ampdu_list, list) {
+
+ spin_lock_bh(&iter->lock);
+ ADD(buf, *len, bufsize, "Entry: #%2d TID:%1d, BSN:%4d, "
+ "SNX:%4d, HSN:%4d, BAW:%2d, state:%1d, toggles:%d\n",
+ cnt, iter->tid, iter->bsn, iter->snx, iter->hsn,
+ iter->max, iter->state, iter->counter);
+
+ ADD(buf, *len, bufsize, "\tWindow: [");
+
+ *len += bitmap_scnprintf(&buf[*len], bufsize - *len,
+ iter->bitmap, CARL9170_BAW_BITS);
+
+#define BM_STR_OFF(offset) \
+ ((CARL9170_BAW_BITS - (offset) - 1) / 4 + \
+ (CARL9170_BAW_BITS - (offset) - 1) / 32 + 1)
+
+ ADD(buf, *len, bufsize, ",W]\n");
+
+ offset = BM_STR_OFF(0);
+ ADD(buf, *len, bufsize, "\tBase Seq: %*s\n", offset, "T");
+
+ offset = BM_STR_OFF(SEQ_DIFF(iter->snx, iter->bsn));
+ ADD(buf, *len, bufsize, "\tNext Seq: %*s\n", offset, "W");
+
+ offset = BM_STR_OFF(((int)iter->hsn - (int)iter->bsn) %
+ CARL9170_BAW_BITS);
+ ADD(buf, *len, bufsize, "\tLast Seq: %*s\n", offset, "N");
+
+ ADD(buf, *len, bufsize, "\tPre-Aggregation reorder buffer: "
+ " currently queued:%d\n", skb_queue_len(&iter->queue));
+
+ fc = 0;
+ skb_queue_walk(&iter->queue, skb) {
+ char prefix[32];
+
+ snprintf(prefix, sizeof(prefix), "\t\t%3d :", fc);
+ carl9170_debugfs_format_frame(ar, skb, prefix, buf,
+ len, bufsize);
+
+ fc++;
+ }
+ spin_unlock_bh(&iter->lock);
+ cnt++;
+ }
+ rcu_read_unlock();
+
+ return buf;
+}
+DEBUGFS_DECLARE_RO_FILE(ampdu_state, 8000);
+
+static void carl9170_debugfs_queue_dump(struct ar9170 *ar, char *buf,
+ ssize_t *len, size_t bufsize, struct sk_buff_head *queue)
+{
+ struct sk_buff *skb;
+ char prefix[16];
+ int fc = 0;
+
+ spin_lock_bh(&queue->lock);
+ skb_queue_walk(queue, skb) {
+ snprintf(prefix, sizeof(prefix), "%3d :", fc);
+ carl9170_debugfs_format_frame(ar, skb, prefix, buf,
+ len, bufsize);
+ fc++;
+ }
+ spin_unlock_bh(&queue->lock);
+}
+
+#define DEBUGFS_QUEUE_DUMP(q, qi) \
+static char *carl9170_debugfs_##q ##_##qi ##_read(struct ar9170 *ar, \
+ char *buf, size_t bufsize, ssize_t *len) \
+{ \
+ carl9170_debugfs_queue_dump(ar, buf, len, bufsize, &ar->q[qi]); \
+ return buf; \
+} \
+DEBUGFS_DECLARE_RO_FILE(q##_##qi, 8000);
+
+static char *carl9170_debugfs_sta_psm_read(struct ar9170 *ar, char *buf,
+ size_t bufsize, ssize_t *len)
+{
+ ADD(buf, *len, bufsize, "psm state: %s\n", (ar->ps.off_override ?
+ "FORCE CAM" : (ar->ps.state ? "PSM" : "CAM")));
+
+ ADD(buf, *len, bufsize, "sleep duration: %d ms.\n", ar->ps.sleep_ms);
+ ADD(buf, *len, bufsize, "last power-state transition: %d ms ago.\n",
+ jiffies_to_msecs(jiffies - ar->ps.last_action));
+ ADD(buf, *len, bufsize, "last CAM->PSM transition: %d ms ago.\n",
+ jiffies_to_msecs(jiffies - ar->ps.last_slept));
+
+ return buf;
+}
+DEBUGFS_DECLARE_RO_FILE(sta_psm, 160);
+
+static char *carl9170_debugfs_tx_stuck_read(struct ar9170 *ar, char *buf,
+ size_t bufsize, ssize_t *len)
+{
+ int i;
+
+ for (i = 0; i < ar->hw->queues; i++) {
+ ADD(buf, *len, bufsize, "TX queue [%d]: %10d max:%10d ms.\n",
+ i, ieee80211_queue_stopped(ar->hw, i) ?
+ jiffies_to_msecs(jiffies - ar->queue_stop_timeout[i]) : 0,
+ jiffies_to_msecs(ar->max_queue_stop_timeout[i]));
+
+ ar->max_queue_stop_timeout[i] = 0;
+ }
+
+ return buf;
+}
+DEBUGFS_DECLARE_RO_FILE(tx_stuck, 180);
+
+static char *carl9170_debugfs_phy_noise_read(struct ar9170 *ar, char *buf,
+ size_t bufsize, ssize_t *len)
+{
+ int err;
+
+ err = carl9170_get_noisefloor(ar);
+ if (err) {
+ *len = err;
+ return buf;
+ }
+
+ ADD(buf, *len, bufsize, "Chain 0: %10d dBm, ext. chan.:%10d dBm\n",
+ ar->noise[0], ar->noise[2]);
+ ADD(buf, *len, bufsize, "Chain 2: %10d dBm, ext. chan.:%10d dBm\n",
+ ar->noise[1], ar->noise[3]);
+
+ return buf;
+}
+DEBUGFS_DECLARE_RO_FILE(phy_noise, 180);
+
+static char *carl9170_debugfs_vif_dump_read(struct ar9170 *ar, char *buf,
+ size_t bufsize, ssize_t *len)
+{
+ struct carl9170_vif_info *iter;
+ int i = 0;
+
+ ADD(buf, *len, bufsize, "registered VIFs:%d \\ %d\n",
+ ar->vifs, ar->fw.vif_num);
+
+ ADD(buf, *len, bufsize, "VIF bitmap: [");
+
+ *len += bitmap_scnprintf(&buf[*len], bufsize - *len,
+ &ar->vif_bitmap, ar->fw.vif_num);
+
+ ADD(buf, *len, bufsize, "]\n");
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(iter, &ar->vif_list, list) {
+ struct ieee80211_vif *vif = carl9170_get_vif(iter);
+ ADD(buf, *len, bufsize, "\t%d = [%s VIF, id:%d, type:%x "
+ " mac:%pM %s]\n", i, (carl9170_get_main_vif(ar) == vif ?
+ "Master" : " Slave"), iter->id, vif->type, vif->addr,
+ iter->enable_beacon ? "beaconing " : "");
+ i++;
+ }
+ rcu_read_unlock();
+
+ return buf;
+}
+DEBUGFS_DECLARE_RO_FILE(vif_dump, 8000);
+
+#define UPDATE_COUNTER(ar, name) ({ \
+ u32 __tmp[ARRAY_SIZE(name##_regs)]; \
+ unsigned int __i, __err = -ENODEV; \
+ \
+ for (__i = 0; __i < ARRAY_SIZE(name##_regs); __i++) { \
+ __tmp[__i] = name##_regs[__i].reg; \
+ ar->debug.stats.name##_counter[__i] = 0; \
+ } \
+ \
+ if (IS_STARTED(ar)) \
+ __err = carl9170_read_mreg(ar, ARRAY_SIZE(name##_regs), \
+ __tmp, ar->debug.stats.name##_counter); \
+ (__err); })
+
+#define TALLY_SUM_UP(ar, name) do { \
+ unsigned int __i; \
+ \
+ for (__i = 0; __i < ARRAY_SIZE(name##_regs); __i++) { \
+ ar->debug.stats.name##_sum[__i] += \
+ ar->debug.stats.name##_counter[__i]; \
+ } \
+} while (0)
+
+#define DEBUGFS_HW_TALLY_FILE(name, f) \
+static char *carl9170_debugfs_##name ## _read(struct ar9170 *ar, \
+ char *dum, size_t bufsize, ssize_t *ret) \
+{ \
+ char *buf; \
+ int i, max_len, err; \
+ \
+ max_len = ARRAY_SIZE(name##_regs) * 80; \
+ buf = vmalloc(max_len); \
+ if (!buf) \
+ return NULL; \
+ \
+ err = UPDATE_COUNTER(ar, name); \
+ if (err) { \
+ *ret = err; \
+ return buf; \
+ } \
+ \
+ TALLY_SUM_UP(ar, name); \
+ \
+ for (i = 0; i < ARRAY_SIZE(name##_regs); i++) { \
+ ADD(buf, *ret, max_len, "%22s = %" f "[+%" f "]\n", \
+ name##_regs[i].nreg, ar->debug.stats.name ##_sum[i],\
+ ar->debug.stats.name ##_counter[i]); \
+ } \
+ \
+ return buf; \
+} \
+DEBUGFS_DECLARE_RO_FILE(name, 0);
+
+#define DEBUGFS_HW_REG_FILE(name, f) \
+static char *carl9170_debugfs_##name ## _read(struct ar9170 *ar, \
+ char *dum, size_t bufsize, ssize_t *ret) \
+{ \
+ char *buf; \
+ int i, max_len, err; \
+ \
+ max_len = ARRAY_SIZE(name##_regs) * 80; \
+ buf = vmalloc(max_len); \
+ if (!buf) \
+ return NULL; \
+ \
+ err = UPDATE_COUNTER(ar, name); \
+ if (err) { \
+ *ret = err; \
+ return buf; \
+ } \
+ \
+ for (i = 0; i < ARRAY_SIZE(name##_regs); i++) { \
+ ADD(buf, *ret, max_len, "%22s = %" f "\n", \
+ name##_regs[i].nreg, \
+ ar->debug.stats.name##_counter[i]); \
+ } \
+ \
+ return buf; \
+} \
+DEBUGFS_DECLARE_RO_FILE(name, 0);
+
+static ssize_t carl9170_debugfs_hw_ioread32_write(struct ar9170 *ar,
+ const char *buf, size_t count)
+{
+ int err = 0, i, n = 0, max_len = 32, res;
+ unsigned int reg, tmp;
+
+ if (!count)
+ return 0;
+
+ if (count > max_len)
+ return -E2BIG;
+
+ res = sscanf(buf, "0x%X %d", &reg, &n);
+ if (res < 1) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (res == 1)
+ n = 1;
+
+ if (n > 15) {
+ err = -EMSGSIZE;
+ goto out;
+ }
+
+ if ((reg >= 0x280000) || ((reg + (n << 2)) >= 0x280000)) {
+ err = -EADDRNOTAVAIL;
+ goto out;
+ }
+
+ if (reg & 3) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < n; i++) {
+ err = carl9170_read_reg(ar, reg + (i << 2), &tmp);
+ if (err)
+ goto out;
+
+ ar->debug.ring[ar->debug.ring_tail].reg = reg + (i << 2);
+ ar->debug.ring[ar->debug.ring_tail].value = tmp;
+ ar->debug.ring_tail++;
+ ar->debug.ring_tail %= CARL9170_DEBUG_RING_SIZE;
+ }
+
+out:
+ return err ? err : count;
+}
+
+static char *carl9170_debugfs_hw_ioread32_read(struct ar9170 *ar, char *buf,
+ size_t bufsize, ssize_t *ret)
+{
+ int i = 0;
+
+ while (ar->debug.ring_head != ar->debug.ring_tail) {
+ ADD(buf, *ret, bufsize, "%.8x = %.8x\n",
+ ar->debug.ring[ar->debug.ring_head].reg,
+ ar->debug.ring[ar->debug.ring_head].value);
+
+ ar->debug.ring_head++;
+ ar->debug.ring_head %= CARL9170_DEBUG_RING_SIZE;
+
+ if (i++ == 64)
+ break;
+ }
+ ar->debug.ring_head = ar->debug.ring_tail;
+ return buf;
+}
+DEBUGFS_DECLARE_RW_FILE(hw_ioread32, CARL9170_DEBUG_RING_SIZE * 40);
+
+static ssize_t carl9170_debugfs_bug_write(struct ar9170 *ar, const char *buf,
+ size_t count)
+{
+ int err;
+
+ if (count < 1)
+ return -EINVAL;
+
+ switch (buf[0]) {
+ case 'F':
+ ar->needs_full_reset = true;
+ break;
+
+ case 'R':
+ if (!IS_STARTED(ar)) {
+ err = -EAGAIN;
+ goto out;
+ }
+
+ ar->needs_full_reset = false;
+ break;
+
+ case 'M':
+ err = carl9170_mac_reset(ar);
+ if (err < 0)
+ count = err;
+
+ goto out;
+
+ case 'P':
+ err = carl9170_set_channel(ar, ar->hw->conf.channel,
+ ar->hw->conf.channel_type, CARL9170_RFI_COLD);
+ if (err < 0)
+ count = err;
+
+ goto out;
+
+ default:
+ return -EINVAL;
+ }
+
+ carl9170_restart(ar, CARL9170_RR_USER_REQUEST);
+
+out:
+ return count;
+}
+
+static char *carl9170_debugfs_bug_read(struct ar9170 *ar, char *buf,
+ size_t bufsize, ssize_t *ret)
+{
+ ADD(buf, *ret, bufsize, "[P]hy reinit, [R]estart, [F]ull usb reset, "
+ "[M]ac reset\n");
+ ADD(buf, *ret, bufsize, "firmware restarts:%d, last reason:%d\n",
+ ar->restart_counter, ar->last_reason);
+ ADD(buf, *ret, bufsize, "phy reinit errors:%d (%d)\n",
+ ar->total_chan_fail, ar->chan_fail);
+ ADD(buf, *ret, bufsize, "reported firmware errors:%d\n",
+ ar->fw.err_counter);
+ ADD(buf, *ret, bufsize, "reported firmware BUGs:%d\n",
+ ar->fw.bug_counter);
+ ADD(buf, *ret, bufsize, "pending restart requests:%d\n",
+ atomic_read(&ar->pending_restarts));
+ return buf;
+}
+__DEBUGFS_DECLARE_RW_FILE(bug, 400, CARL9170_STOPPED);
+
+static const char *erp_modes[] = {
+ [CARL9170_ERP_INVALID] = "INVALID",
+ [CARL9170_ERP_AUTO] = "Automatic",
+ [CARL9170_ERP_MAC80211] = "Set by MAC80211",
+ [CARL9170_ERP_OFF] = "Force Off",
+ [CARL9170_ERP_RTS] = "Force RTS",
+ [CARL9170_ERP_CTS] = "Force CTS"
+};
+
+static char *carl9170_debugfs_erp_read(struct ar9170 *ar, char *buf,
+ size_t bufsize, ssize_t *ret)
+{
+ ADD(buf, *ret, bufsize, "ERP Setting: (%d) -> %s\n", ar->erp_mode,
+ erp_modes[ar->erp_mode]);
+ return buf;
+}
+
+static ssize_t carl9170_debugfs_erp_write(struct ar9170 *ar, const char *buf,
+ size_t count)
+{
+ int res, val;
+
+ if (count < 1)
+ return -EINVAL;
+
+ res = sscanf(buf, "%d", &val);
+ if (res != 1)
+ return -EINVAL;
+
+ if (!((val > CARL9170_ERP_INVALID) &&
+ (val < __CARL9170_ERP_NUM)))
+ return -EINVAL;
+
+ ar->erp_mode = val;
+ return count;
+}
+
+DEBUGFS_DECLARE_RW_FILE(erp, 80);
+
+static ssize_t carl9170_debugfs_hw_iowrite32_write(struct ar9170 *ar,
+ const char *buf, size_t count)
+{
+ int err = 0, max_len = 22, res;
+ u32 reg, val;
+
+ if (!count)
+ return 0;
+
+ if (count > max_len)
+ return -E2BIG;
+
+ res = sscanf(buf, "0x%X 0x%X", &reg, &val);
+ if (res != 2) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (reg <= 0x100000 || reg >= 0x280000) {
+ err = -EADDRNOTAVAIL;
+ goto out;
+ }
+
+ if (reg & 3) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = carl9170_write_reg(ar, reg, val);
+ if (err)
+ goto out;
+
+out:
+ return err ? err : count;
+}
+DEBUGFS_DECLARE_WO_FILE(hw_iowrite32);
+
+DEBUGFS_HW_TALLY_FILE(hw_tx_tally, "u");
+DEBUGFS_HW_TALLY_FILE(hw_rx_tally, "u");
+DEBUGFS_HW_TALLY_FILE(hw_phy_errors, "u");
+DEBUGFS_HW_REG_FILE(hw_wlan_queue, ".8x");
+DEBUGFS_HW_REG_FILE(hw_pta_queue, ".8x");
+DEBUGFS_HW_REG_FILE(hw_ampdu_info, ".8x");
+DEBUGFS_QUEUE_DUMP(tx_status, 0);
+DEBUGFS_QUEUE_DUMP(tx_status, 1);
+DEBUGFS_QUEUE_DUMP(tx_status, 2);
+DEBUGFS_QUEUE_DUMP(tx_status, 3);
+DEBUGFS_QUEUE_DUMP(tx_pending, 0);
+DEBUGFS_QUEUE_DUMP(tx_pending, 1);
+DEBUGFS_QUEUE_DUMP(tx_pending, 2);
+DEBUGFS_QUEUE_DUMP(tx_pending, 3);
+DEBUGFS_READONLY_FILE(usb_tx_anch_urbs, 20, "%d",
+ atomic_read(&ar->tx_anch_urbs));
+DEBUGFS_READONLY_FILE(usb_rx_anch_urbs, 20, "%d",
+ atomic_read(&ar->rx_anch_urbs));
+DEBUGFS_READONLY_FILE(usb_rx_work_urbs, 20, "%d",
+ atomic_read(&ar->rx_work_urbs));
+DEBUGFS_READONLY_FILE(usb_rx_pool_urbs, 20, "%d",
+ atomic_read(&ar->rx_pool_urbs));
+
+DEBUGFS_READONLY_FILE(tx_total_queued, 20, "%d",
+ atomic_read(&ar->tx_total_queued));
+DEBUGFS_READONLY_FILE(tx_ampdu_scheduler, 20, "%d",
+ atomic_read(&ar->tx_ampdu_scheduler));
+
+DEBUGFS_READONLY_FILE(tx_total_pending, 20, "%d",
+ atomic_read(&ar->tx_total_pending));
+
+DEBUGFS_READONLY_FILE(tx_ampdu_list_len, 20, "%d",
+ ar->tx_ampdu_list_len);
+
+DEBUGFS_READONLY_FILE(tx_ampdu_upload, 20, "%d",
+ atomic_read(&ar->tx_ampdu_upload));
+
+DEBUGFS_READONLY_FILE(tx_janitor_last_run, 64, "last run:%d ms ago",
+ jiffies_to_msecs(jiffies - ar->tx_janitor_last_run));
+
+DEBUGFS_READONLY_FILE(tx_dropped, 20, "%d", ar->tx_dropped);
+
+DEBUGFS_READONLY_FILE(rx_dropped, 20, "%d", ar->rx_dropped);
+
+DEBUGFS_READONLY_FILE(sniffer_enabled, 20, "%d", ar->sniffer_enabled);
+DEBUGFS_READONLY_FILE(rx_software_decryption, 20, "%d",
+ ar->rx_software_decryption);
+DEBUGFS_READONLY_FILE(ampdu_factor, 20, "%d",
+ ar->current_factor);
+DEBUGFS_READONLY_FILE(ampdu_density, 20, "%d",
+ ar->current_density);
+
+DEBUGFS_READONLY_FILE(beacon_int, 20, "%d TU", ar->global_beacon_int);
+DEBUGFS_READONLY_FILE(pretbtt, 20, "%d TU", ar->global_pretbtt);
+
+void carl9170_debugfs_register(struct ar9170 *ar)
+{
+ ar->debug_dir = debugfs_create_dir(KBUILD_MODNAME,
+ ar->hw->wiphy->debugfsdir);
+
+#define DEBUGFS_ADD(name) \
+ debugfs_create_file(#name, carl_debugfs_##name ##_ops.attr, \
+ ar->debug_dir, ar, \
+ &carl_debugfs_##name ## _ops.fops);
+
+ DEBUGFS_ADD(usb_tx_anch_urbs);
+ DEBUGFS_ADD(usb_rx_pool_urbs);
+ DEBUGFS_ADD(usb_rx_anch_urbs);
+ DEBUGFS_ADD(usb_rx_work_urbs);
+
+ DEBUGFS_ADD(tx_total_queued);
+ DEBUGFS_ADD(tx_total_pending);
+ DEBUGFS_ADD(tx_dropped);
+ DEBUGFS_ADD(tx_stuck);
+ DEBUGFS_ADD(tx_ampdu_upload);
+ DEBUGFS_ADD(tx_ampdu_scheduler);
+ DEBUGFS_ADD(tx_ampdu_list_len);
+
+ DEBUGFS_ADD(rx_dropped);
+ DEBUGFS_ADD(sniffer_enabled);
+ DEBUGFS_ADD(rx_software_decryption);
+
+ DEBUGFS_ADD(mem_usage);
+ DEBUGFS_ADD(qos_stat);
+ DEBUGFS_ADD(sta_psm);
+ DEBUGFS_ADD(ampdu_state);
+
+ DEBUGFS_ADD(hw_tx_tally);
+ DEBUGFS_ADD(hw_rx_tally);
+ DEBUGFS_ADD(hw_phy_errors);
+ DEBUGFS_ADD(phy_noise);
+
+ DEBUGFS_ADD(hw_wlan_queue);
+ DEBUGFS_ADD(hw_pta_queue);
+ DEBUGFS_ADD(hw_ampdu_info);
+
+ DEBUGFS_ADD(ampdu_density);
+ DEBUGFS_ADD(ampdu_factor);
+
+ DEBUGFS_ADD(tx_janitor_last_run);
+
+ DEBUGFS_ADD(tx_status_0);
+ DEBUGFS_ADD(tx_status_1);
+ DEBUGFS_ADD(tx_status_2);
+ DEBUGFS_ADD(tx_status_3);
+
+ DEBUGFS_ADD(tx_pending_0);
+ DEBUGFS_ADD(tx_pending_1);
+ DEBUGFS_ADD(tx_pending_2);
+ DEBUGFS_ADD(tx_pending_3);
+
+ DEBUGFS_ADD(hw_ioread32);
+ DEBUGFS_ADD(hw_iowrite32);
+ DEBUGFS_ADD(bug);
+
+ DEBUGFS_ADD(erp);
+
+ DEBUGFS_ADD(vif_dump);
+
+ DEBUGFS_ADD(beacon_int);
+ DEBUGFS_ADD(pretbtt);
+
+#undef DEBUGFS_ADD
+}
+
+void carl9170_debugfs_unregister(struct ar9170 *ar)
+{
+ debugfs_remove_recursive(ar->debug_dir);
+}
diff --git a/drivers/net/wireless/ath/carl9170/debug.h b/drivers/net/wireless/ath/carl9170/debug.h
new file mode 100644
index 000000000000..ea4b97524122
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/debug.h
@@ -0,0 +1,134 @@
+/*
+ * Atheros CARL9170 driver
+ *
+ * debug header
+ *
+ * Copyright 2010, Christian Lamparter <chunkeey@googlemail.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; see the file COPYING. If not, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2007-2008 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 "eeprom.h"
+#include "wlan.h"
+#include "hw.h"
+#include "fwdesc.h"
+#include "fwcmd.h"
+#include "../regd.h"
+
+struct hw_stat_reg_entry {
+ u32 reg;
+ char nreg[32];
+};
+
+#define STAT_MAC_REG(reg) \
+ { (AR9170_MAC_REG_##reg), #reg }
+
+#define STAT_PTA_REG(reg) \
+ { (AR9170_PTA_REG_##reg), #reg }
+
+#define STAT_USB_REG(reg) \
+ { (AR9170_USB_REG_##reg), #reg }
+
+static const struct hw_stat_reg_entry hw_rx_tally_regs[] = {
+ STAT_MAC_REG(RX_CRC32), STAT_MAC_REG(RX_CRC16),
+ STAT_MAC_REG(RX_TIMEOUT_COUNT), STAT_MAC_REG(RX_ERR_DECRYPTION_UNI),
+ STAT_MAC_REG(RX_ERR_DECRYPTION_MUL), STAT_MAC_REG(RX_MPDU),
+ STAT_MAC_REG(RX_DROPPED_MPDU), STAT_MAC_REG(RX_DEL_MPDU),
+};
+
+static const struct hw_stat_reg_entry hw_phy_errors_regs[] = {
+ STAT_MAC_REG(RX_PHY_MISC_ERROR), STAT_MAC_REG(RX_PHY_XR_ERROR),
+ STAT_MAC_REG(RX_PHY_OFDM_ERROR), STAT_MAC_REG(RX_PHY_CCK_ERROR),
+ STAT_MAC_REG(RX_PHY_HT_ERROR), STAT_MAC_REG(RX_PHY_TOTAL),
+};
+
+static const struct hw_stat_reg_entry hw_tx_tally_regs[] = {
+ STAT_MAC_REG(TX_TOTAL), STAT_MAC_REG(TX_UNDERRUN),
+ STAT_MAC_REG(TX_RETRY),
+};
+
+static const struct hw_stat_reg_entry hw_wlan_queue_regs[] = {
+ STAT_MAC_REG(DMA_STATUS), STAT_MAC_REG(DMA_TRIGGER),
+ STAT_MAC_REG(DMA_TXQ0_ADDR), STAT_MAC_REG(DMA_TXQ0_CURR_ADDR),
+ STAT_MAC_REG(DMA_TXQ1_ADDR), STAT_MAC_REG(DMA_TXQ1_CURR_ADDR),
+ STAT_MAC_REG(DMA_TXQ2_ADDR), STAT_MAC_REG(DMA_TXQ2_CURR_ADDR),
+ STAT_MAC_REG(DMA_TXQ3_ADDR), STAT_MAC_REG(DMA_TXQ3_CURR_ADDR),
+ STAT_MAC_REG(DMA_RXQ_ADDR), STAT_MAC_REG(DMA_RXQ_CURR_ADDR),
+};
+
+static const struct hw_stat_reg_entry hw_ampdu_info_regs[] = {
+ STAT_MAC_REG(AMPDU_DENSITY), STAT_MAC_REG(AMPDU_FACTOR),
+};
+
+static const struct hw_stat_reg_entry hw_pta_queue_regs[] = {
+ STAT_PTA_REG(DN_CURR_ADDRH), STAT_PTA_REG(DN_CURR_ADDRL),
+ STAT_PTA_REG(UP_CURR_ADDRH), STAT_PTA_REG(UP_CURR_ADDRL),
+ STAT_PTA_REG(DMA_STATUS), STAT_PTA_REG(DMA_MODE_CTRL),
+};
+
+#define DEFINE_TALLY(name) \
+ u32 name##_sum[ARRAY_SIZE(name##_regs)], \
+ name##_counter[ARRAY_SIZE(name##_regs)] \
+
+#define DEFINE_STAT(name) \
+ u32 name##_counter[ARRAY_SIZE(name##_regs)] \
+
+struct ath_stats {
+ DEFINE_TALLY(hw_tx_tally);
+ DEFINE_TALLY(hw_rx_tally);
+ DEFINE_TALLY(hw_phy_errors);
+ DEFINE_STAT(hw_wlan_queue);
+ DEFINE_STAT(hw_pta_queue);
+ DEFINE_STAT(hw_ampdu_info);
+};
+
+struct carl9170_debug_mem_rbe {
+ u32 reg;
+ u32 value;
+};
+
+#define CARL9170_DEBUG_RING_SIZE 64
+
+struct carl9170_debug {
+ struct ath_stats stats;
+ struct carl9170_debug_mem_rbe ring[CARL9170_DEBUG_RING_SIZE];
+ struct mutex ring_lock;
+ unsigned int ring_head, ring_tail;
+ struct delayed_work update_tally;
+};
+
+struct ar9170;
+
+void carl9170_debugfs_register(struct ar9170 *ar);
+void carl9170_debugfs_unregister(struct ar9170 *ar);
+#endif /* __DEBUG_H */
diff --git a/drivers/net/wireless/ath/carl9170/eeprom.h b/drivers/net/wireless/ath/carl9170/eeprom.h
new file mode 100644
index 000000000000..7cff40ac7759
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/eeprom.h
@@ -0,0 +1,216 @@
+/*
+ * Shared Atheros AR9170 Header
+ *
+ * EEPROM layout
+ *
+ * Copyright 2008, 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 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, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2007-2008 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 __CARL9170_SHARED_EEPROM_H
+#define __CARL9170_SHARED_EEPROM_H
+
+#define AR9170_EEPROM_START 0x1600
+
+#define AR5416_MAX_CHAINS 2
+#define AR5416_MODAL_SPURS 5
+
+struct ar9170_eeprom_modal {
+ __le32 antCtrlChain[AR5416_MAX_CHAINS];
+ __le32 antCtrlCommon;
+ s8 antennaGainCh[AR5416_MAX_CHAINS];
+ u8 switchSettling;
+ u8 txRxAttenCh[AR5416_MAX_CHAINS];
+ u8 rxTxMarginCh[AR5416_MAX_CHAINS];
+ s8 adcDesiredSize;
+ s8 pgaDesiredSize;
+ u8 xlnaGainCh[AR5416_MAX_CHAINS];
+ u8 txEndToXpaOff;
+ u8 txEndToRxOn;
+ u8 txFrameToXpaOn;
+ u8 thresh62;
+ s8 noiseFloorThreshCh[AR5416_MAX_CHAINS];
+ u8 xpdGain;
+ u8 xpd;
+ s8 iqCalICh[AR5416_MAX_CHAINS];
+ s8 iqCalQCh[AR5416_MAX_CHAINS];
+ u8 pdGainOverlap;
+ u8 ob;
+ u8 db;
+ u8 xpaBiasLvl;
+ u8 pwrDecreaseFor2Chain;
+ u8 pwrDecreaseFor3Chain;
+ u8 txFrameToDataStart;
+ u8 txFrameToPaOn;
+ u8 ht40PowerIncForPdadc;
+ u8 bswAtten[AR5416_MAX_CHAINS];
+ u8 bswMargin[AR5416_MAX_CHAINS];
+ u8 swSettleHt40;
+ u8 reserved[22];
+ struct spur_channel {
+ __le16 spurChan;
+ u8 spurRangeLow;
+ u8 spurRangeHigh;
+ } __packed spur_channels[AR5416_MODAL_SPURS];
+} __packed;
+
+#define AR5416_NUM_PD_GAINS 4
+#define AR5416_PD_GAIN_ICEPTS 5
+
+struct ar9170_calibration_data_per_freq {
+ u8 pwr_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
+ u8 vpd_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
+} __packed;
+
+#define AR5416_NUM_5G_CAL_PIERS 8
+#define AR5416_NUM_2G_CAL_PIERS 4
+
+#define AR5416_NUM_5G_TARGET_PWRS 8
+#define AR5416_NUM_2G_CCK_TARGET_PWRS 3
+#define AR5416_NUM_2G_OFDM_TARGET_PWRS 4
+#define AR5416_MAX_NUM_TGT_PWRS 8
+
+struct ar9170_calibration_target_power_legacy {
+ u8 freq;
+ u8 power[4];
+} __packed;
+
+struct ar9170_calibration_target_power_ht {
+ u8 freq;
+ u8 power[8];
+} __packed;
+
+#define AR5416_NUM_CTLS 24
+
+struct ar9170_calctl_edges {
+ u8 channel;
+#define AR9170_CALCTL_EDGE_FLAGS 0xC0
+ u8 power_flags;
+} __packed;
+
+#define AR5416_NUM_BAND_EDGES 8
+
+struct ar9170_calctl_data {
+ struct ar9170_calctl_edges
+ control_edges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
+} __packed;
+
+struct ar9170_eeprom {
+ __le16 length;
+ __le16 checksum;
+ __le16 version;
+ u8 operating_flags;
+#define AR9170_OPFLAG_5GHZ 1
+#define AR9170_OPFLAG_2GHZ 2
+ u8 misc;
+ __le16 reg_domain[2];
+ u8 mac_address[6];
+ u8 rx_mask;
+ u8 tx_mask;
+ __le16 rf_silent;
+ __le16 bluetooth_options;
+ __le16 device_capabilities;
+ __le32 build_number;
+ u8 deviceType;
+ u8 reserved[33];
+
+ u8 customer_data[64];
+
+ struct ar9170_eeprom_modal
+ modal_header[2];
+
+ u8 cal_freq_pier_5G[AR5416_NUM_5G_CAL_PIERS];
+ u8 cal_freq_pier_2G[AR5416_NUM_2G_CAL_PIERS];
+
+ struct ar9170_calibration_data_per_freq
+ cal_pier_data_5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS],
+ cal_pier_data_2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS];
+
+ /* power calibration data */
+ struct ar9170_calibration_target_power_legacy
+ cal_tgt_pwr_5G[AR5416_NUM_5G_TARGET_PWRS];
+ struct ar9170_calibration_target_power_ht
+ cal_tgt_pwr_5G_ht20[AR5416_NUM_5G_TARGET_PWRS],
+ cal_tgt_pwr_5G_ht40[AR5416_NUM_5G_TARGET_PWRS];
+
+ struct ar9170_calibration_target_power_legacy
+ cal_tgt_pwr_2G_cck[AR5416_NUM_2G_CCK_TARGET_PWRS],
+ cal_tgt_pwr_2G_ofdm[AR5416_NUM_2G_OFDM_TARGET_PWRS];
+ struct ar9170_calibration_target_power_ht
+ cal_tgt_pwr_2G_ht20[AR5416_NUM_2G_OFDM_TARGET_PWRS],
+ cal_tgt_pwr_2G_ht40[AR5416_NUM_2G_OFDM_TARGET_PWRS];
+
+ /* conformance testing limits */
+ u8 ctl_index[AR5416_NUM_CTLS];
+ struct ar9170_calctl_data
+ ctl_data[AR5416_NUM_CTLS];
+
+ u8 pad;
+ __le16 subsystem_id;
+} __packed;
+
+#define AR9170_LED_MODE_POWER_ON 0x0001
+#define AR9170_LED_MODE_RESERVED 0x0002
+#define AR9170_LED_MODE_DISABLE_STATE 0x0004
+#define AR9170_LED_MODE_OFF_IN_PSM 0x0008
+
+/* AR9170_LED_MODE BIT is set */
+#define AR9170_LED_MODE_FREQUENCY_S 4
+#define AR9170_LED_MODE_FREQUENCY 0x0030
+#define AR9170_LED_MODE_FREQUENCY_1HZ 0x0000
+#define AR9170_LED_MODE_FREQUENCY_0_5HZ 0x0010
+#define AR9170_LED_MODE_FREQUENCY_0_25HZ 0x0020
+#define AR9170_LED_MODE_FREQUENCY_0_125HZ 0x0030
+
+/* AR9170_LED_MODE BIT is not set */
+#define AR9170_LED_MODE_CONN_STATE_S 4
+#define AR9170_LED_MODE_CONN_STATE 0x0030
+#define AR9170_LED_MODE_CONN_STATE_FORCE_OFF 0x0000
+#define AR9170_LED_MODE_CONN_STATE_FORCE_ON 0x0010
+/* Idle off / Active on */
+#define AR9170_LED_MODE_CONN_STATE_IOFF_AON 0x0020
+/* Idle on / Active off */
+#define AR9170_LED_MODE_CONN_STATE_ION_AOFF 0x0010
+
+#define AR9170_LED_MODE_MODE 0x0040
+#define AR9170_LED_MODE_RESERVED2 0x0080
+
+#define AR9170_LED_MODE_TON_SCAN_S 8
+#define AR9170_LED_MODE_TON_SCAN 0x0f00
+
+#define AR9170_LED_MODE_TOFF_SCAN_S 12
+#define AR9170_LED_MODE_TOFF_SCAN 0xf000
+
+struct ar9170_led_mode {
+ __le16 led;
+};
+
+#endif /* __CARL9170_SHARED_EEPROM_H */
diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c
new file mode 100644
index 000000000000..ae6c006bbc56
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/fw.c
@@ -0,0 +1,402 @@
+/*
+ * Atheros CARL9170 driver
+ *
+ * firmware parser
+ *
+ * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.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; see the file COPYING. If not, see
+ * http://www.gnu.org/licenses/.
+ */
+
+#include <linux/kernel.h>
+#include <linux/firmware.h>
+#include <linux/crc32.h>
+#include "carl9170.h"
+#include "fwcmd.h"
+#include "version.h"
+
+#define MAKE_STR(symbol) #symbol
+#define TO_STR(symbol) MAKE_STR(symbol)
+#define CARL9170FW_API_VER_STR TO_STR(CARL9170FW_API_MAX_VER)
+MODULE_VERSION(CARL9170FW_API_VER_STR ":" CARL9170FW_VERSION_GIT);
+
+static const u8 otus_magic[4] = { OTUS_MAGIC };
+
+static const void *carl9170_fw_find_desc(struct ar9170 *ar, const u8 descid[4],
+ const unsigned int len, const u8 compatible_revision)
+{
+ const struct carl9170fw_desc_head *iter;
+
+ carl9170fw_for_each_hdr(iter, ar->fw.desc) {
+ if (carl9170fw_desc_cmp(iter, descid, len,
+ compatible_revision))
+ return (void *)iter;
+ }
+
+ /* needed to find the LAST desc */
+ if (carl9170fw_desc_cmp(iter, descid, len,
+ compatible_revision))
+ return (void *)iter;
+
+ return NULL;
+}
+
+static int carl9170_fw_verify_descs(struct ar9170 *ar,
+ const struct carl9170fw_desc_head *head, unsigned int max_len)
+{
+ const struct carl9170fw_desc_head *pos;
+ unsigned long pos_addr, end_addr;
+ unsigned int pos_length;
+
+ if (max_len < sizeof(*pos))
+ return -ENODATA;
+
+ max_len = min_t(unsigned int, CARL9170FW_DESC_MAX_LENGTH, max_len);
+
+ pos = head;
+ pos_addr = (unsigned long) pos;
+ end_addr = pos_addr + max_len;
+
+ while (pos_addr < end_addr) {
+ if (pos_addr + sizeof(*head) > end_addr)
+ return -E2BIG;
+
+ pos_length = le16_to_cpu(pos->length);
+
+ if (pos_length < sizeof(*head))
+ return -EBADMSG;
+
+ if (pos_length > max_len)
+ return -EOVERFLOW;
+
+ if (pos_addr + pos_length > end_addr)
+ return -EMSGSIZE;
+
+ if (carl9170fw_desc_cmp(pos, LAST_MAGIC,
+ CARL9170FW_LAST_DESC_SIZE,
+ CARL9170FW_LAST_DESC_CUR_VER))
+ return 0;
+
+ pos_addr += pos_length;
+ pos = (void *)pos_addr;
+ max_len -= pos_length;
+ }
+ return -EINVAL;
+}
+
+static void carl9170_fw_info(struct ar9170 *ar)
+{
+ const struct carl9170fw_motd_desc *motd_desc;
+ unsigned int str_ver_len;
+ u32 fw_date;
+
+ dev_info(&ar->udev->dev, "driver API: %s 2%03d-%02d-%02d [%d-%d]\n",
+ CARL9170FW_VERSION_GIT, CARL9170FW_VERSION_YEAR,
+ CARL9170FW_VERSION_MONTH, CARL9170FW_VERSION_DAY,
+ CARL9170FW_API_MIN_VER, CARL9170FW_API_MAX_VER);
+
+ motd_desc = carl9170_fw_find_desc(ar, MOTD_MAGIC,
+ sizeof(*motd_desc), CARL9170FW_MOTD_DESC_CUR_VER);
+
+ if (motd_desc) {
+ str_ver_len = strnlen(motd_desc->release,
+ CARL9170FW_MOTD_RELEASE_LEN);
+
+ fw_date = le32_to_cpu(motd_desc->fw_year_month_day);
+
+ dev_info(&ar->udev->dev, "firmware API: %.*s 2%03d-%02d-%02d\n",
+ str_ver_len, motd_desc->release,
+ CARL9170FW_GET_YEAR(fw_date),
+ CARL9170FW_GET_MONTH(fw_date),
+ CARL9170FW_GET_DAY(fw_date));
+
+ strlcpy(ar->hw->wiphy->fw_version, motd_desc->release,
+ sizeof(ar->hw->wiphy->fw_version));
+ }
+}
+
+static bool valid_dma_addr(const u32 address)
+{
+ if (address >= AR9170_SRAM_OFFSET &&
+ address < (AR9170_SRAM_OFFSET + AR9170_SRAM_SIZE))
+ return true;
+
+ return false;
+}
+
+static bool valid_cpu_addr(const u32 address)
+{
+ if (valid_dma_addr(address) || (address >= AR9170_PRAM_OFFSET &&
+ address < (AR9170_PRAM_OFFSET + AR9170_PRAM_SIZE)))
+ return true;
+
+ return false;
+}
+
+static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
+{
+ const struct carl9170fw_otus_desc *otus_desc;
+ const struct carl9170fw_chk_desc *chk_desc;
+ const struct carl9170fw_last_desc *last_desc;
+
+ last_desc = carl9170_fw_find_desc(ar, LAST_MAGIC,
+ sizeof(*last_desc), CARL9170FW_LAST_DESC_CUR_VER);
+ if (!last_desc)
+ return -EINVAL;
+
+ otus_desc = carl9170_fw_find_desc(ar, OTUS_MAGIC,
+ sizeof(*otus_desc), CARL9170FW_OTUS_DESC_CUR_VER);
+ if (!otus_desc) {
+ dev_err(&ar->udev->dev, "failed to find compatible firmware "
+ "descriptor.\n");
+ return -ENODATA;
+ }
+
+ chk_desc = carl9170_fw_find_desc(ar, CHK_MAGIC,
+ sizeof(*chk_desc), CARL9170FW_CHK_DESC_CUR_VER);
+
+ if (chk_desc) {
+ unsigned long fin, diff;
+ unsigned int dsc_len;
+ u32 crc32;
+
+ dsc_len = min_t(unsigned int, len,
+ (unsigned long)chk_desc - (unsigned long)otus_desc);
+
+ fin = (unsigned long) last_desc + sizeof(*last_desc);
+ diff = fin - (unsigned long) otus_desc;
+
+ if (diff < len)
+ len -= diff;
+
+ if (len < 256)
+ return -EIO;
+
+ crc32 = crc32_le(~0, data, len);
+ if (cpu_to_le32(crc32) != chk_desc->fw_crc32) {
+ dev_err(&ar->udev->dev, "fw checksum test failed.\n");
+ return -ENOEXEC;
+ }
+
+ crc32 = crc32_le(crc32, (void *)otus_desc, dsc_len);
+ if (cpu_to_le32(crc32) != chk_desc->hdr_crc32) {
+ dev_err(&ar->udev->dev, "descriptor check failed.\n");
+ return -EINVAL;
+ }
+ } else {
+ dev_warn(&ar->udev->dev, "Unprotected firmware image.\n");
+ }
+
+#define SUPP(feat) \
+ (carl9170fw_supports(otus_desc->feature_set, feat))
+
+ if (!SUPP(CARL9170FW_DUMMY_FEATURE)) {
+ dev_err(&ar->udev->dev, "invalid firmware descriptor "
+ "format detected.\n");
+ return -EINVAL;
+ }
+
+ ar->fw.api_version = otus_desc->api_ver;
+
+ if (ar->fw.api_version < CARL9170FW_API_MIN_VER ||
+ ar->fw.api_version > CARL9170FW_API_MAX_VER) {
+ dev_err(&ar->udev->dev, "unsupported firmware api version.\n");
+ return -EINVAL;
+ }
+
+ if (!SUPP(CARL9170FW_COMMAND_PHY) || SUPP(CARL9170FW_UNUSABLE) ||
+ !SUPP(CARL9170FW_HANDLE_BACK_REQ)) {
+ dev_err(&ar->udev->dev, "firmware does support "
+ "mandatory features.\n");
+ return -ECANCELED;
+ }
+
+ if (ilog2(le32_to_cpu(otus_desc->feature_set)) >=
+ __CARL9170FW_FEATURE_NUM) {
+ dev_warn(&ar->udev->dev, "driver does not support all "
+ "firmware features.\n");
+ }
+
+ if (!SUPP(CARL9170FW_COMMAND_CAM)) {
+ dev_info(&ar->udev->dev, "crypto offloading is disabled "
+ "by firmware.\n");
+ ar->disable_offload = true;
+ }
+
+ if (SUPP(CARL9170FW_PSM))
+ ar->hw->flags |= IEEE80211_HW_SUPPORTS_PS;
+
+ if (!SUPP(CARL9170FW_USB_INIT_FIRMWARE)) {
+ dev_err(&ar->udev->dev, "firmware does not provide "
+ "mandatory interfaces.\n");
+ return -EINVAL;
+ }
+
+ if (SUPP(CARL9170FW_MINIBOOT))
+ ar->fw.offset = le16_to_cpu(otus_desc->miniboot_size);
+ else
+ ar->fw.offset = 0;
+
+ if (SUPP(CARL9170FW_USB_DOWN_STREAM)) {
+ ar->hw->extra_tx_headroom += sizeof(struct ar9170_stream);
+ ar->fw.tx_stream = true;
+ }
+
+ if (SUPP(CARL9170FW_USB_UP_STREAM))
+ ar->fw.rx_stream = true;
+
+ if (SUPP(CARL9170FW_RX_FILTER)) {
+ ar->fw.rx_filter = true;
+ ar->rx_filter_caps = FIF_FCSFAIL | FIF_PLCPFAIL |
+ FIF_CONTROL | FIF_PSPOLL | FIF_OTHER_BSS |
+ FIF_PROMISC_IN_BSS;
+ }
+
+ ar->fw.vif_num = otus_desc->vif_num;
+ ar->fw.cmd_bufs = otus_desc->cmd_bufs;
+ ar->fw.address = le32_to_cpu(otus_desc->fw_address);
+ ar->fw.rx_size = le16_to_cpu(otus_desc->rx_max_frame_len);
+ ar->fw.mem_blocks = min_t(unsigned int, otus_desc->tx_descs, 0xfe);
+ atomic_set(&ar->mem_free_blocks, ar->fw.mem_blocks);
+ ar->fw.mem_block_size = le16_to_cpu(otus_desc->tx_frag_len);
+
+ if (ar->fw.vif_num >= AR9170_MAX_VIRTUAL_MAC || !ar->fw.vif_num ||
+ ar->fw.mem_blocks < 16 || !ar->fw.cmd_bufs ||
+ ar->fw.mem_block_size < 64 || ar->fw.mem_block_size > 512 ||
+ ar->fw.rx_size > 32768 || ar->fw.rx_size < 4096 ||
+ !valid_cpu_addr(ar->fw.address)) {
+ dev_err(&ar->udev->dev, "firmware shows obvious signs of "
+ "malicious tampering.\n");
+ return -EINVAL;
+ }
+
+ ar->fw.beacon_addr = le32_to_cpu(otus_desc->bcn_addr);
+ ar->fw.beacon_max_len = le16_to_cpu(otus_desc->bcn_len);
+
+ if (valid_dma_addr(ar->fw.beacon_addr) && ar->fw.beacon_max_len >=
+ AR9170_MAC_BCN_LENGTH_MAX) {
+ ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
+
+ if (SUPP(CARL9170FW_WLANTX_CAB)) {
+ ar->hw->wiphy->interface_modes |=
+ BIT(NL80211_IFTYPE_AP);
+ }
+ }
+
+#undef SUPPORTED
+ return 0;
+}
+
+static struct carl9170fw_desc_head *
+carl9170_find_fw_desc(struct ar9170 *ar, const __u8 *fw_data, const size_t len)
+
+{
+ int scan = 0, found = 0;
+
+ if (!carl9170fw_size_check(len)) {
+ dev_err(&ar->udev->dev, "firmware size is out of bound.\n");
+ return NULL;
+ }
+
+ while (scan < len - sizeof(struct carl9170fw_desc_head)) {
+ if (fw_data[scan++] == otus_magic[found])
+ found++;
+ else
+ found = 0;
+
+ if (scan >= len)
+ break;
+
+ if (found == sizeof(otus_magic))
+ break;
+ }
+
+ if (found != sizeof(otus_magic))
+ return NULL;
+
+ return (void *)&fw_data[scan - found];
+}
+
+int carl9170_fw_fix_eeprom(struct ar9170 *ar)
+{
+ const struct carl9170fw_fix_desc *fix_desc = NULL;
+ unsigned int i, n, off;
+ u32 *data = (void *)&ar->eeprom;
+
+ fix_desc = carl9170_fw_find_desc(ar, FIX_MAGIC,
+ sizeof(*fix_desc), CARL9170FW_FIX_DESC_CUR_VER);
+
+ if (!fix_desc)
+ return 0;
+
+ n = (le16_to_cpu(fix_desc->head.length) - sizeof(*fix_desc)) /
+ sizeof(struct carl9170fw_fix_entry);
+
+ for (i = 0; i < n; i++) {
+ off = le32_to_cpu(fix_desc->data[i].address) -
+ AR9170_EEPROM_START;
+
+ if (off >= sizeof(struct ar9170_eeprom) || (off & 3)) {
+ dev_err(&ar->udev->dev, "Skip invalid entry %d\n", i);
+ continue;
+ }
+
+ data[off / sizeof(*data)] &=
+ le32_to_cpu(fix_desc->data[i].mask);
+ data[off / sizeof(*data)] |=
+ le32_to_cpu(fix_desc->data[i].value);
+ }
+
+ return 0;
+}
+
+int carl9170_parse_firmware(struct ar9170 *ar)
+{
+ const struct carl9170fw_desc_head *fw_desc = NULL;
+ const struct firmware *fw = ar->fw.fw;
+ unsigned long header_offset = 0;
+ int err;
+
+ if (WARN_ON(!fw))
+ return -EINVAL;
+
+ fw_desc = carl9170_find_fw_desc(ar, fw->data, fw->size);
+
+ if (!fw_desc) {
+ dev_err(&ar->udev->dev, "unsupported firmware.\n");
+ return -ENODATA;
+ }
+
+ header_offset = (unsigned long)fw_desc - (unsigned long)fw->data;
+
+ err = carl9170_fw_verify_descs(ar, fw_desc, fw->size - header_offset);
+ if (err) {
+ dev_err(&ar->udev->dev, "damaged firmware (%d).\n", err);
+ return err;
+ }
+
+ ar->fw.desc = fw_desc;
+
+ carl9170_fw_info(ar);
+
+ err = carl9170_fw(ar, fw->data, fw->size);
+ if (err) {
+ dev_err(&ar->udev->dev, "failed to parse firmware (%d).\n",
+ err);
+ return err;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/wireless/ath/carl9170/fwcmd.h b/drivers/net/wireless/ath/carl9170/fwcmd.h
new file mode 100644
index 000000000000..d552166db505
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/fwcmd.h
@@ -0,0 +1,284 @@
+/*
+ * Shared Atheros AR9170 Header
+ *
+ * Firmware command interface definitions
+ *
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.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.
+ *
+ * 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, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2007-2008 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 __CARL9170_SHARED_FWCMD_H
+#define __CARL9170_SHARED_FWCMD_H
+
+#define CARL9170_MAX_CMD_LEN 64
+#define CARL9170_MAX_CMD_PAYLOAD_LEN 60
+
+#define CARL9170FW_API_MIN_VER 1
+#define CARL9170FW_API_MAX_VER 1
+
+enum carl9170_cmd_oids {
+ CARL9170_CMD_RREG = 0x00,
+ CARL9170_CMD_WREG = 0x01,
+ CARL9170_CMD_ECHO = 0x02,
+ CARL9170_CMD_SWRST = 0x03,
+ CARL9170_CMD_REBOOT = 0x04,
+ CARL9170_CMD_BCN_CTRL = 0x05,
+ CARL9170_CMD_READ_TSF = 0x06,
+ CARL9170_CMD_RX_FILTER = 0x07,
+
+ /* CAM */
+ CARL9170_CMD_EKEY = 0x10,
+ CARL9170_CMD_DKEY = 0x11,
+
+ /* RF / PHY */
+ CARL9170_CMD_FREQUENCY = 0x20,
+ CARL9170_CMD_RF_INIT = 0x21,
+ CARL9170_CMD_SYNTH = 0x22,
+ CARL9170_CMD_FREQ_START = 0x23,
+ CARL9170_CMD_PSM = 0x24,
+
+ /* Asychronous command flag */
+ CARL9170_CMD_ASYNC_FLAG = 0x40,
+ CARL9170_CMD_WREG_ASYNC = (CARL9170_CMD_WREG |
+ CARL9170_CMD_ASYNC_FLAG),
+ CARL9170_CMD_REBOOT_ASYNC = (CARL9170_CMD_REBOOT |
+ CARL9170_CMD_ASYNC_FLAG),
+ CARL9170_CMD_BCN_CTRL_ASYNC = (CARL9170_CMD_BCN_CTRL |
+ CARL9170_CMD_ASYNC_FLAG),
+ CARL9170_CMD_PSM_ASYNC = (CARL9170_CMD_PSM |
+ CARL9170_CMD_ASYNC_FLAG),
+
+ /* responses and traps */
+ CARL9170_RSP_FLAG = 0xc0,
+ CARL9170_RSP_PRETBTT = 0xc0,
+ CARL9170_RSP_TXCOMP = 0xc1,
+ CARL9170_RSP_BEACON_CONFIG = 0xc2,
+ CARL9170_RSP_ATIM = 0xc3,
+ CARL9170_RSP_WATCHDOG = 0xc6,
+ CARL9170_RSP_TEXT = 0xca,
+ CARL9170_RSP_HEXDUMP = 0xcc,
+ CARL9170_RSP_RADAR = 0xcd,
+ CARL9170_RSP_GPIO = 0xce,
+ CARL9170_RSP_BOOT = 0xcf,
+};
+
+struct carl9170_set_key_cmd {
+ __le16 user;
+ __le16 keyId;
+ __le16 type;
+ u8 macAddr[6];
+ u32 key[4];
+} __packed;
+#define CARL9170_SET_KEY_CMD_SIZE 28
+
+struct carl9170_disable_key_cmd {
+ __le16 user;
+ __le16 padding;
+} __packed;
+#define CARL9170_DISABLE_KEY_CMD_SIZE 4
+
+struct carl9170_u32_list {
+ u32 vals[0];
+} __packed;
+
+struct carl9170_reg_list {
+ __le32 regs[0];
+} __packed;
+
+struct carl9170_write_reg {
+ struct {
+ __le32 addr;
+ __le32 val;
+ } regs[0] __packed;
+} __packed;
+
+#define CARL9170FW_PHY_HT_ENABLE 0x4
+#define CARL9170FW_PHY_HT_DYN2040 0x8
+#define CARL9170FW_PHY_HT_EXT_CHAN_OFF 0x3
+#define CARL9170FW_PHY_HT_EXT_CHAN_OFF_S 2
+
+struct carl9170_rf_init {
+ __le32 freq;
+ u8 ht_settings;
+ u8 padding2[3];
+ __le32 delta_slope_coeff_exp;
+ __le32 delta_slope_coeff_man;
+ __le32 delta_slope_coeff_exp_shgi;
+ __le32 delta_slope_coeff_man_shgi;
+ __le32 finiteLoopCount;
+} __packed;
+#define CARL9170_RF_INIT_SIZE 28
+
+struct carl9170_rf_init_result {
+ __le32 ret; /* AR9170_PHY_REG_AGC_CONTROL */
+} __packed;
+#define CARL9170_RF_INIT_RESULT_SIZE 4
+
+#define CARL9170_PSM_SLEEP 0x1000
+#define CARL9170_PSM_SOFTWARE 0
+#define CARL9170_PSM_WAKE 0 /* internally used. */
+#define CARL9170_PSM_COUNTER 0xfff
+#define CARL9170_PSM_COUNTER_S 0
+
+struct carl9170_psm {
+ __le32 state;
+} __packed;
+#define CARL9170_PSM_SIZE 4
+
+struct carl9170_rx_filter_cmd {
+ __le32 rx_filter;
+} __packed;
+#define CARL9170_RX_FILTER_CMD_SIZE 4
+
+#define CARL9170_RX_FILTER_BAD 0x01
+#define CARL9170_RX_FILTER_OTHER_RA 0x02
+#define CARL9170_RX_FILTER_DECRY_FAIL 0x04
+#define CARL9170_RX_FILTER_CTL_OTHER 0x08
+#define CARL9170_RX_FILTER_CTL_PSPOLL 0x10
+#define CARL9170_RX_FILTER_CTL_BACKR 0x20
+#define CARL9170_RX_FILTER_MGMT 0x40
+#define CARL9170_RX_FILTER_DATA 0x80
+
+struct carl9170_bcn_ctrl_cmd {
+ __le32 vif_id;
+ __le32 mode;
+ __le32 bcn_addr;
+ __le32 bcn_len;
+} __packed;
+#define CARL9170_BCN_CTRL_CMD_SIZE 16
+
+#define CARL9170_BCN_CTRL_DRAIN 0
+#define CARL9170_BCN_CTRL_CAB_TRIGGER 1
+
+struct carl9170_cmd_head {
+ union {
+ struct {
+ u8 len;
+ u8 cmd;
+ u8 seq;
+ u8 ext;
+ } __packed;
+
+ u32 hdr_data;
+ } __packed;
+} __packed;
+
+struct carl9170_cmd {
+ struct carl9170_cmd_head hdr;
+ union {
+ struct carl9170_set_key_cmd setkey;
+ struct carl9170_disable_key_cmd disablekey;
+ struct carl9170_u32_list echo;
+ struct carl9170_reg_list rreg;
+ struct carl9170_write_reg wreg;
+ struct carl9170_rf_init rf_init;
+ struct carl9170_psm psm;
+ struct carl9170_bcn_ctrl_cmd bcn_ctrl;
+ struct carl9170_rx_filter_cmd rx_filter;
+ u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN];
+ } __packed;
+} __packed;
+
+#define CARL9170_TX_STATUS_QUEUE 3
+#define CARL9170_TX_STATUS_QUEUE_S 0
+#define CARL9170_TX_STATUS_RIX_S 2
+#define CARL9170_TX_STATUS_RIX (3 << CARL9170_TX_STATUS_RIX_S)
+#define CARL9170_TX_STATUS_TRIES_S 4
+#define CARL9170_TX_STATUS_TRIES (7 << CARL9170_TX_STATUS_TRIES_S)
+#define CARL9170_TX_STATUS_SUCCESS 0x80
+
+/*
+ * NOTE:
+ * Both structs [carl9170_tx_status and _carl9170_tx_status]
+ * need to be "bit for bit" in sync.
+ */
+struct carl9170_tx_status {
+ /*
+ * Beware of compiler bugs in all gcc pre 4.4!
+ */
+
+ u8 cookie;
+ u8 queue:2;
+ u8 rix:2;
+ u8 tries:3;
+ u8 success:1;
+} __packed;
+struct _carl9170_tx_status {
+ /*
+ * This version should be immune to all alignment bugs.
+ */
+
+ u8 cookie;
+ u8 info;
+} __packed;
+#define CARL9170_TX_STATUS_SIZE 2
+
+#define CARL9170_RSP_TX_STATUS_NUM (CARL9170_MAX_CMD_PAYLOAD_LEN / \
+ sizeof(struct _carl9170_tx_status))
+
+#define CARL9170_TX_MAX_RATE_TRIES 7
+
+#define CARL9170_TX_MAX_RATES 4
+#define CARL9170_TX_MAX_RETRY_RATES (CARL9170_TX_MAX_RATES - 1)
+#define CARL9170_ERR_MAGIC "ERR:"
+#define CARL9170_BUG_MAGIC "BUG:"
+
+struct carl9170_gpio {
+ __le32 gpio;
+} __packed;
+#define CARL9170_GPIO_SIZE 4
+
+struct carl9170_tsf_rsp {
+ union {
+ __le32 tsf[2];
+ __le64 tsf_64;
+ } __packed;
+} __packed;
+#define CARL9170_TSF_RSP_SIZE 8
+
+struct carl9170_rsp {
+ struct carl9170_cmd_head hdr;
+
+ union {
+ struct carl9170_rf_init_result rf_init_res;
+ struct carl9170_u32_list rreg_res;
+ struct carl9170_u32_list echo;
+ struct carl9170_tx_status tx_status[0];
+ struct _carl9170_tx_status _tx_status[0];
+ struct carl9170_gpio gpio;
+ struct carl9170_tsf_rsp tsf;
+ struct carl9170_psm psm;
+ u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN];
+ } __packed;
+} __packed;
+
+#endif /* __CARL9170_SHARED_FWCMD_H */
diff --git a/drivers/net/wireless/ath/carl9170/fwdesc.h b/drivers/net/wireless/ath/carl9170/fwdesc.h
new file mode 100644
index 000000000000..71f3821f6058
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/fwdesc.h
@@ -0,0 +1,241 @@
+/*
+ * Shared CARL9170 Header
+ *
+ * Firmware descriptor format
+ *
+ * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.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.
+ *
+ * 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, see
+ * http://www.gnu.org/licenses/.
+ */
+
+#ifndef __CARL9170_SHARED_FWDESC_H
+#define __CARL9170_SHARED_FWDESC_H
+
+/* NOTE: Don't mess with the order of the flags! */
+enum carl9170fw_feature_list {
+ /* Always set */
+ CARL9170FW_DUMMY_FEATURE,
+
+ /*
+ * Indicates that this image has special boot block which prevents
+ * legacy drivers to drive the firmware.
+ */
+ CARL9170FW_MINIBOOT,
+
+ /* usb registers are initialized by the firmware */
+ CARL9170FW_USB_INIT_FIRMWARE,
+
+ /* command traps & notifications are send through EP2 */
+ CARL9170FW_USB_RESP_EP2,
+
+ /* usb download (app -> fw) stream */
+ CARL9170FW_USB_DOWN_STREAM,
+
+ /* usb upload (fw -> app) stream */
+ CARL9170FW_USB_UP_STREAM,
+
+ /* unusable - reserved to flag non-functional debug firmwares */
+ CARL9170FW_UNUSABLE,
+
+ /* AR9170_CMD_RF_INIT, AR9170_CMD_FREQ_START, AR9170_CMD_FREQUENCY */
+ CARL9170FW_COMMAND_PHY,
+
+ /* AR9170_CMD_EKEY, AR9170_CMD_DKEY */
+ CARL9170FW_COMMAND_CAM,
+
+ /* Firmware has a software Content After Beacon Queueing mechanism */
+ CARL9170FW_WLANTX_CAB,
+
+ /* The firmware is capable of responding to incoming BAR frames */
+ CARL9170FW_HANDLE_BACK_REQ,
+
+ /* GPIO Interrupt | CARL9170_RSP_GPIO */
+ CARL9170FW_GPIO_INTERRUPT,
+
+ /* Firmware PSM support | CARL9170_CMD_PSM */
+ CARL9170FW_PSM,
+
+ /* Firmware RX filter | CARL9170_CMD_RX_FILTER */
+ CARL9170FW_RX_FILTER,
+
+ /* KEEP LAST */
+ __CARL9170FW_FEATURE_NUM
+};
+
+#define OTUS_MAGIC "OTAR"
+#define MOTD_MAGIC "MOTD"
+#define FIX_MAGIC "FIX\0"
+#define DBG_MAGIC "DBG\0"
+#define CHK_MAGIC "CHK\0"
+#define LAST_MAGIC "LAST"
+
+#define CARL9170FW_SET_DAY(d) (((d) - 1) % 31)
+#define CARL9170FW_SET_MONTH(m) ((((m) - 1) % 12) * 31)
+#define CARL9170FW_SET_YEAR(y) (((y) - 10) * 372)
+
+#define CARL9170FW_GET_DAY(d) (((d) % 31) + 1)
+#define CARL9170FW_GET_MONTH(m) ((((m) / 31) % 12) + 1)
+#define CARL9170FW_GET_YEAR(y) ((y) / 372 + 10)
+
+struct carl9170fw_desc_head {
+ u8 magic[4];
+ __le16 length;
+ u8 min_ver;
+ u8 cur_ver;
+} __packed;
+#define CARL9170FW_DESC_HEAD_SIZE \
+ (sizeof(struct carl9170fw_desc_head))
+
+#define CARL9170FW_OTUS_DESC_MIN_VER 6
+#define CARL9170FW_OTUS_DESC_CUR_VER 6
+struct carl9170fw_otus_desc {
+ struct carl9170fw_desc_head head;
+ __le32 feature_set;
+ __le32 fw_address;
+ __le32 bcn_addr;
+ __le16 bcn_len;
+ __le16 miniboot_size;
+ __le16 tx_frag_len;
+ __le16 rx_max_frame_len;
+ u8 tx_descs;
+ u8 cmd_bufs;
+ u8 api_ver;
+ u8 vif_num;
+} __packed;
+#define CARL9170FW_OTUS_DESC_SIZE \
+ (sizeof(struct carl9170fw_otus_desc))
+
+#define CARL9170FW_MOTD_STRING_LEN 24
+#define CARL9170FW_MOTD_RELEASE_LEN 20
+#define CARL9170FW_MOTD_DESC_MIN_VER 1
+#define CARL9170FW_MOTD_DESC_CUR_VER 2
+struct carl9170fw_motd_desc {
+ struct carl9170fw_desc_head head;
+ __le32 fw_year_month_day;
+ char desc[CARL9170FW_MOTD_STRING_LEN];
+ char release[CARL9170FW_MOTD_RELEASE_LEN];
+} __packed;
+#define CARL9170FW_MOTD_DESC_SIZE \
+ (sizeof(struct carl9170fw_motd_desc))
+
+#define CARL9170FW_FIX_DESC_MIN_VER 1
+#define CARL9170FW_FIX_DESC_CUR_VER 2
+struct carl9170fw_fix_entry {
+ __le32 address;
+ __le32 mask;
+ __le32 value;
+} __packed;
+
+struct carl9170fw_fix_desc {
+ struct carl9170fw_desc_head head;
+ struct carl9170fw_fix_entry data[0];
+} __packed;
+#define CARL9170FW_FIX_DESC_SIZE \
+ (sizeof(struct carl9170fw_fix_desc))
+
+#define CARL9170FW_DBG_DESC_MIN_VER 1
+#define CARL9170FW_DBG_DESC_CUR_VER 3
+struct carl9170fw_dbg_desc {
+ struct carl9170fw_desc_head head;
+
+ __le32 bogoclock_addr;
+ __le32 counter_addr;
+ __le32 rx_total_addr;
+ __le32 rx_overrun_addr;
+ __le32 rx_filter;
+
+ /* Put your debugging definitions here */
+} __packed;
+#define CARL9170FW_DBG_DESC_SIZE \
+ (sizeof(struct carl9170fw_dbg_desc))
+
+#define CARL9170FW_CHK_DESC_MIN_VER 1
+#define CARL9170FW_CHK_DESC_CUR_VER 2
+struct carl9170fw_chk_desc {
+ struct carl9170fw_desc_head head;
+ __le32 fw_crc32;
+ __le32 hdr_crc32;
+} __packed;
+#define CARL9170FW_CHK_DESC_SIZE \
+ (sizeof(struct carl9170fw_chk_desc))
+
+#define CARL9170FW_LAST_DESC_MIN_VER 1
+#define CARL9170FW_LAST_DESC_CUR_VER 2
+struct carl9170fw_last_desc {
+ struct carl9170fw_desc_head head;
+} __packed;
+#define CARL9170FW_LAST_DESC_SIZE \
+ (sizeof(struct carl9170fw_fix_desc))
+
+#define CARL9170FW_DESC_MAX_LENGTH 8192
+
+#define CARL9170FW_FILL_DESC(_magic, _length, _min_ver, _cur_ver) \
+ .head = { \
+ .magic = _magic, \
+ .length = cpu_to_le16(_length), \
+ .min_ver = _min_ver, \
+ .cur_ver = _cur_ver, \
+ }
+
+static inline void carl9170fw_fill_desc(struct carl9170fw_desc_head *head,
+ u8 magic[4], __le16 length,
+ u8 min_ver, u8 cur_ver)
+{
+ head->magic[0] = magic[0];
+ head->magic[1] = magic[1];
+ head->magic[2] = magic[2];
+ head->magic[3] = magic[3];
+
+ head->length = length;
+ head->min_ver = min_ver;
+ head->cur_ver = cur_ver;
+}
+
+#define carl9170fw_for_each_hdr(desc, fw_desc) \
+ for (desc = fw_desc; \
+ memcmp(desc->magic, LAST_MAGIC, 4) && \
+ le16_to_cpu(desc->length) >= CARL9170FW_DESC_HEAD_SIZE && \
+ le16_to_cpu(desc->length) < CARL9170FW_DESC_MAX_LENGTH; \
+ desc = (void *)((unsigned long)desc + le16_to_cpu(desc->length)))
+
+#define CHECK_HDR_VERSION(head, _min_ver) \
+ (((head)->cur_ver < _min_ver) || ((head)->min_ver > _min_ver)) \
+
+static inline bool carl9170fw_supports(__le32 list, u8 feature)
+{
+ return le32_to_cpu(list) & BIT(feature);
+}
+
+static inline bool carl9170fw_desc_cmp(const struct carl9170fw_desc_head *head,
+ const u8 descid[4], u16 min_len,
+ u8 compatible_revision)
+{
+ if (descid[0] == head->magic[0] && descid[1] == head->magic[1] &&
+ descid[2] == head->magic[2] && descid[3] == head->magic[3] &&
+ !CHECK_HDR_VERSION(head, compatible_revision) &&
+ (le16_to_cpu(head->length) >= min_len))
+ return true;
+
+ return false;
+}
+
+#define CARL9170FW_MIN_SIZE 32
+#define CARL9170FW_MAX_SIZE 16384
+
+static inline bool carl9170fw_size_check(unsigned int len)
+{
+ return (len <= CARL9170FW_MAX_SIZE && len >= CARL9170FW_MIN_SIZE);
+}
+
+#endif /* __CARL9170_SHARED_FWDESC_H */
diff --git a/drivers/net/wireless/ath/carl9170/hw.h b/drivers/net/wireless/ath/carl9170/hw.h
new file mode 100644
index 000000000000..2f471b3f05af
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/hw.h
@@ -0,0 +1,739 @@
+/*
+ * Shared Atheros AR9170 Header
+ *
+ * Register map, hardware-specific definitions
+ *
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.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.
+ *
+ * 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, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2007-2008 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 __CARL9170_SHARED_HW_H
+#define __CARL9170_SHARED_HW_H
+
+/* High Speed UART */
+#define AR9170_UART_REG_BASE 0x1c0000
+
+/* Definitions of interrupt registers */
+#define AR9170_UART_REG_RX_BUFFER (AR9170_UART_REG_BASE + 0x000)
+#define AR9170_UART_REG_TX_HOLDING (AR9170_UART_REG_BASE + 0x004)
+#define AR9170_UART_REG_FIFO_CONTROL (AR9170_UART_REG_BASE + 0x010)
+#define AR9170_UART_FIFO_CTRL_RESET_RX_FIFO 0x02
+#define AR9170_UART_FIFO_CTRL_RESET_TX_FIFO 0x04
+
+#define AR9170_UART_REG_LINE_CONTROL (AR9170_UART_REG_BASE + 0x014)
+#define AR9170_UART_REG_MODEM_CONTROL (AR9170_UART_REG_BASE + 0x018)
+#define AR9170_UART_MODEM_CTRL_DTR_BIT 0x01
+#define AR9170_UART_MODEM_CTRL_RTS_BIT 0x02
+#define AR9170_UART_MODEM_CTRL_INTERNAL_LOOP_BACK 0x10
+#define AR9170_UART_MODEM_CTRL_AUTO_RTS 0x20
+#define AR9170_UART_MODEM_CTRL_AUTO_CTR 0x40
+
+#define AR9170_UART_REG_LINE_STATUS (AR9170_UART_REG_BASE + 0x01c)
+#define AR9170_UART_LINE_STS_RX_DATA_READY 0x01
+#define AR9170_UART_LINE_STS_RX_BUFFER_OVERRUN 0x02
+#define AR9170_UART_LINE_STS_RX_BREAK_IND 0x10
+#define AR9170_UART_LINE_STS_TX_FIFO_NEAR_EMPTY 0x20
+#define AR9170_UART_LINE_STS_TRANSMITTER_EMPTY 0x40
+
+#define AR9170_UART_REG_MODEM_STATUS (AR9170_UART_REG_BASE + 0x020)
+#define AR9170_UART_MODEM_STS_CTS_CHANGE 0x01
+#define AR9170_UART_MODEM_STS_DSR_CHANGE 0x02
+#define AR9170_UART_MODEM_STS_DCD_CHANGE 0x08
+#define AR9170_UART_MODEM_STS_CTS_COMPL 0x10
+#define AR9170_UART_MODEM_STS_DSR_COMPL 0x20
+#define AR9170_UART_MODEM_STS_DCD_COMPL 0x80
+
+#define AR9170_UART_REG_SCRATCH (AR9170_UART_REG_BASE + 0x024)
+#define AR9170_UART_REG_DIVISOR_LSB (AR9170_UART_REG_BASE + 0x028)
+#define AR9170_UART_REG_DIVISOR_MSB (AR9170_UART_REG_BASE + 0x02c)
+#define AR9170_UART_REG_WORD_RX_BUFFER (AR9170_UART_REG_BASE + 0x034)
+#define AR9170_UART_REG_WORD_TX_HOLDING (AR9170_UART_REG_BASE + 0x038)
+#define AR9170_UART_REG_FIFO_COUNT (AR9170_UART_REG_BASE + 0x03c)
+#define AR9170_UART_REG_REMAINDER (AR9170_UART_REG_BASE + 0x04c)
+
+/* Timer */
+#define AR9170_TIMER_REG_BASE 0x1c1000
+
+#define AR9170_TIMER_REG_WATCH_DOG (AR9170_TIMER_REG_BASE + 0x000)
+#define AR9170_TIMER_REG_TIMER0 (AR9170_TIMER_REG_BASE + 0x010)
+#define AR9170_TIMER_REG_TIMER1 (AR9170_TIMER_REG_BASE + 0x014)
+#define AR9170_TIMER_REG_TIMER2 (AR9170_TIMER_REG_BASE + 0x018)
+#define AR9170_TIMER_REG_TIMER3 (AR9170_TIMER_REG_BASE + 0x01c)
+#define AR9170_TIMER_REG_TIMER4 (AR9170_TIMER_REG_BASE + 0x020)
+#define AR9170_TIMER_REG_CONTROL (AR9170_TIMER_REG_BASE + 0x024)
+#define AR9170_TIMER_CTRL_DISABLE_CLOCK 0x100
+
+#define AR9170_TIMER_REG_INTERRUPT (AR9170_TIMER_REG_BASE + 0x028)
+#define AR9170_TIMER_INT_TIMER0 0x001
+#define AR9170_TIMER_INT_TIMER1 0x002
+#define AR9170_TIMER_INT_TIMER2 0x004
+#define AR9170_TIMER_INT_TIMER3 0x008
+#define AR9170_TIMER_INT_TIMER4 0x010
+#define AR9170_TIMER_INT_TICK_TIMER 0x100
+
+#define AR9170_TIMER_REG_TICK_TIMER (AR9170_TIMER_REG_BASE + 0x030)
+#define AR9170_TIMER_REG_CLOCK_LOW (AR9170_TIMER_REG_BASE + 0x040)
+#define AR9170_TIMER_REG_CLOCK_HIGH (AR9170_TIMER_REG_BASE + 0x044)
+
+#define AR9170_MAC_REG_BASE 0x1c3000
+
+#define AR9170_MAC_REG_POWER_STATE_CTRL (AR9170_MAC_REG_BASE + 0x500)
+#define AR9170_MAC_POWER_STATE_CTRL_RESET 0x20
+
+#define AR9170_MAC_REG_MAC_POWER_STATE_CTRL (AR9170_MAC_REG_BASE + 0x50c)
+
+#define AR9170_MAC_REG_INT_CTRL (AR9170_MAC_REG_BASE + 0x510)
+#define AR9170_MAC_INT_TXC BIT(0)
+#define AR9170_MAC_INT_RXC BIT(1)
+#define AR9170_MAC_INT_RETRY_FAIL BIT(2)
+#define AR9170_MAC_INT_WAKEUP BIT(3)
+#define AR9170_MAC_INT_ATIM BIT(4)
+#define AR9170_MAC_INT_DTIM BIT(5)
+#define AR9170_MAC_INT_CFG_BCN BIT(6)
+#define AR9170_MAC_INT_ABORT BIT(7)
+#define AR9170_MAC_INT_QOS BIT(8)
+#define AR9170_MAC_INT_MIMO_PS BIT(9)
+#define AR9170_MAC_INT_KEY_GEN BIT(10)
+#define AR9170_MAC_INT_DECRY_NOUSER BIT(11)
+#define AR9170_MAC_INT_RADAR BIT(12)
+#define AR9170_MAC_INT_QUIET_FRAME BIT(13)
+#define AR9170_MAC_INT_PRETBTT BIT(14)
+
+#define AR9170_MAC_REG_TSF_L (AR9170_MAC_REG_BASE + 0x514)
+#define AR9170_MAC_REG_TSF_H (AR9170_MAC_REG_BASE + 0x518)
+
+#define AR9170_MAC_REG_ATIM_WINDOW (AR9170_MAC_REG_BASE + 0x51c)
+#define AR9170_MAC_ATIM_PERIOD_S 0
+#define AR9170_MAC_ATIM_PERIOD 0x0000ffff
+
+#define AR9170_MAC_REG_BCN_PERIOD (AR9170_MAC_REG_BASE + 0x520)
+#define AR9170_MAC_BCN_PERIOD_S 0
+#define AR9170_MAC_BCN_PERIOD 0x0000ffff
+#define AR9170_MAC_BCN_DTIM_S 16
+#define AR9170_MAC_BCN_DTIM 0x00ff0000
+#define AR9170_MAC_BCN_AP_MODE BIT(24)
+#define AR9170_MAC_BCN_IBSS_MODE BIT(25)
+#define AR9170_MAC_BCN_PWR_MGT BIT(26)
+#define AR9170_MAC_BCN_STA_PS BIT(27)
+
+#define AR9170_MAC_REG_PRETBTT (AR9170_MAC_REG_BASE + 0x524)
+#define AR9170_MAC_PRETBTT_S 0
+#define AR9170_MAC_PRETBTT 0x0000ffff
+#define AR9170_MAC_PRETBTT2_S 16
+#define AR9170_MAC_PRETBTT2 0xffff0000
+
+#define AR9170_MAC_REG_MAC_ADDR_L (AR9170_MAC_REG_BASE + 0x610)
+#define AR9170_MAC_REG_MAC_ADDR_H (AR9170_MAC_REG_BASE + 0x614)
+#define AR9170_MAC_REG_BSSID_L (AR9170_MAC_REG_BASE + 0x618)
+#define AR9170_MAC_REG_BSSID_H (AR9170_MAC_REG_BASE + 0x61c)
+
+#define AR9170_MAC_REG_GROUP_HASH_TBL_L (AR9170_MAC_REG_BASE + 0x624)
+#define AR9170_MAC_REG_GROUP_HASH_TBL_H (AR9170_MAC_REG_BASE + 0x628)
+
+#define AR9170_MAC_REG_RX_TIMEOUT (AR9170_MAC_REG_BASE + 0x62c)
+
+#define AR9170_MAC_REG_BASIC_RATE (AR9170_MAC_REG_BASE + 0x630)
+#define AR9170_MAC_REG_MANDATORY_RATE (AR9170_MAC_REG_BASE + 0x634)
+#define AR9170_MAC_REG_RTS_CTS_RATE (AR9170_MAC_REG_BASE + 0x638)
+#define AR9170_MAC_REG_BACKOFF_PROTECT (AR9170_MAC_REG_BASE + 0x63c)
+#define AR9170_MAC_REG_RX_THRESHOLD (AR9170_MAC_REG_BASE + 0x640)
+#define AR9170_MAC_REG_AFTER_PNP (AR9170_MAC_REG_BASE + 0x648)
+#define AR9170_MAC_REG_RX_PE_DELAY (AR9170_MAC_REG_BASE + 0x64c)
+
+#define AR9170_MAC_REG_DYNAMIC_SIFS_ACK (AR9170_MAC_REG_BASE + 0x658)
+#define AR9170_MAC_REG_SNIFFER (AR9170_MAC_REG_BASE + 0x674)
+#define AR9170_MAC_SNIFFER_ENABLE_PROMISC BIT(0)
+#define AR9170_MAC_SNIFFER_DEFAULTS 0x02000000
+#define AR9170_MAC_REG_ENCRYPTION (AR9170_MAC_REG_BASE + 0x678)
+#define AR9170_MAC_ENCRYPTION_RX_SOFTWARE BIT(3)
+#define AR9170_MAC_ENCRYPTION_DEFAULTS 0x70
+
+#define AR9170_MAC_REG_MISC_680 (AR9170_MAC_REG_BASE + 0x680)
+#define AR9170_MAC_REG_MISC_684 (AR9170_MAC_REG_BASE + 0x684)
+#define AR9170_MAC_REG_TX_UNDERRUN (AR9170_MAC_REG_BASE + 0x688)
+
+#define AR9170_MAC_REG_FRAMETYPE_FILTER (AR9170_MAC_REG_BASE + 0x68c)
+#define AR9170_MAC_FTF_ASSOC_REQ BIT(0)
+#define AR9170_MAC_FTF_ASSOC_RESP BIT(1)
+#define AR9170_MAC_FTF_REASSOC_REQ BIT(2)
+#define AR9170_MAC_FTF_REASSOC_RESP BIT(3)
+#define AR9170_MAC_FTF_PRB_REQ BIT(4)
+#define AR9170_MAC_FTF_PRB_RESP BIT(5)
+#define AR9170_MAC_FTF_BIT6 BIT(6)
+#define AR9170_MAC_FTF_BIT7 BIT(7)
+#define AR9170_MAC_FTF_BEACON BIT(8)
+#define AR9170_MAC_FTF_ATIM BIT(9)
+#define AR9170_MAC_FTF_DEASSOC BIT(10)
+#define AR9170_MAC_FTF_AUTH BIT(11)
+#define AR9170_MAC_FTF_DEAUTH BIT(12)
+#define AR9170_MAC_FTF_BIT13 BIT(13)
+#define AR9170_MAC_FTF_BIT14 BIT(14)
+#define AR9170_MAC_FTF_BIT15 BIT(15)
+#define AR9170_MAC_FTF_BAR BIT(24)
+#define AR9170_MAC_FTF_BA BIT(25)
+#define AR9170_MAC_FTF_PSPOLL BIT(26)
+#define AR9170_MAC_FTF_RTS BIT(27)
+#define AR9170_MAC_FTF_CTS BIT(28)
+#define AR9170_MAC_FTF_ACK BIT(29)
+#define AR9170_MAC_FTF_CFE BIT(30)
+#define AR9170_MAC_FTF_CFE_ACK BIT(31)
+#define AR9170_MAC_FTF_DEFAULTS 0x0500ffff
+#define AR9170_MAC_FTF_MONITOR 0xff00ffff
+
+#define AR9170_MAC_REG_ACK_EXTENSION (AR9170_MAC_REG_BASE + 0x690)
+#define AR9170_MAC_REG_ACK_TPC (AR9170_MAC_REG_BASE + 0x694)
+#define AR9170_MAC_REG_EIFS_AND_SIFS (AR9170_MAC_REG_BASE + 0x698)
+#define AR9170_MAC_REG_RX_TIMEOUT_COUNT (AR9170_MAC_REG_BASE + 0x69c)
+#define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6a0)
+#define AR9170_MAC_REG_RX_CRC32 (AR9170_MAC_REG_BASE + 0x6a4)
+#define AR9170_MAC_REG_RX_CRC16 (AR9170_MAC_REG_BASE + 0x6a8)
+#define AR9170_MAC_REG_RX_ERR_DECRYPTION_UNI (AR9170_MAC_REG_BASE + 0x6ac)
+#define AR9170_MAC_REG_RX_OVERRUN (AR9170_MAC_REG_BASE + 0x6b0)
+#define AR9170_MAC_REG_RX_ERR_DECRYPTION_MUL (AR9170_MAC_REG_BASE + 0x6bc)
+#define AR9170_MAC_REG_TX_BLOCKACKS (AR9170_MAC_REG_BASE + 0x6c0)
+#define AR9170_MAC_REG_NAV_COUNT (AR9170_MAC_REG_BASE + 0x6c4)
+#define AR9170_MAC_REG_BACKOFF_STATUS (AR9170_MAC_REG_BASE + 0x6c8)
+#define AR9170_MAC_REG_TX_RETRY (AR9170_MAC_REG_BASE + 0x6cc)
+
+#define AR9170_MAC_REG_TX_COMPLETE (AR9170_MAC_REG_BASE + 0x6d4)
+
+#define AR9170_MAC_REG_CHANNEL_BUSY (AR9170_MAC_REG_BASE + 0x6e8)
+#define AR9170_MAC_REG_EXT_BUSY (AR9170_MAC_REG_BASE + 0x6ec)
+
+#define AR9170_MAC_REG_SLOT_TIME (AR9170_MAC_REG_BASE + 0x6f0)
+#define AR9170_MAC_REG_TX_TOTAL (AR9170_MAC_REG_BASE + 0x6f4)
+#define AR9170_MAC_REG_ACK_FC (AR9170_MAC_REG_BASE + 0x6f8)
+
+#define AR9170_MAC_REG_CAM_MODE (AR9170_MAC_REG_BASE + 0x700)
+#define AR9170_MAC_CAM_IBSS 0xe0
+#define AR9170_MAC_CAM_AP 0xa1
+#define AR9170_MAC_CAM_STA 0x2
+#define AR9170_MAC_CAM_AP_WDS 0x3
+#define AR9170_MAC_CAM_DEFAULTS (0xf << 24)
+#define AR9170_MAC_CAM_HOST_PENDING 0x80000000
+
+#define AR9170_MAC_REG_CAM_ROLL_CALL_TBL_L (AR9170_MAC_REG_BASE + 0x704)
+#define AR9170_MAC_REG_CAM_ROLL_CALL_TBL_H (AR9170_MAC_REG_BASE + 0x708)
+
+#define AR9170_MAC_REG_CAM_ADDR (AR9170_MAC_REG_BASE + 0x70c)
+#define AR9170_MAC_CAM_ADDR_WRITE 0x80000000
+#define AR9170_MAC_REG_CAM_DATA0 (AR9170_MAC_REG_BASE + 0x720)
+#define AR9170_MAC_REG_CAM_DATA1 (AR9170_MAC_REG_BASE + 0x724)
+#define AR9170_MAC_REG_CAM_DATA2 (AR9170_MAC_REG_BASE + 0x728)
+#define AR9170_MAC_REG_CAM_DATA3 (AR9170_MAC_REG_BASE + 0x72c)
+
+#define AR9170_MAC_REG_CAM_DBG0 (AR9170_MAC_REG_BASE + 0x730)
+#define AR9170_MAC_REG_CAM_DBG1 (AR9170_MAC_REG_BASE + 0x734)
+#define AR9170_MAC_REG_CAM_DBG2 (AR9170_MAC_REG_BASE + 0x738)
+#define AR9170_MAC_REG_CAM_STATE (AR9170_MAC_REG_BASE + 0x73c)
+#define AR9170_MAC_CAM_STATE_READ_PENDING 0x40000000
+#define AR9170_MAC_CAM_STATE_WRITE_PENDING 0x80000000
+
+#define AR9170_MAC_REG_CAM_TXKEY (AR9170_MAC_REG_BASE + 0x740)
+#define AR9170_MAC_REG_CAM_RXKEY (AR9170_MAC_REG_BASE + 0x750)
+
+#define AR9170_MAC_REG_CAM_TX_ENC_TYPE (AR9170_MAC_REG_BASE + 0x760)
+#define AR9170_MAC_REG_CAM_RX_ENC_TYPE (AR9170_MAC_REG_BASE + 0x770)
+#define AR9170_MAC_REG_CAM_TX_SERACH_HIT (AR9170_MAC_REG_BASE + 0x780)
+#define AR9170_MAC_REG_CAM_RX_SERACH_HIT (AR9170_MAC_REG_BASE + 0x790)
+
+#define AR9170_MAC_REG_AC0_CW (AR9170_MAC_REG_BASE + 0xb00)
+#define AR9170_MAC_REG_AC1_CW (AR9170_MAC_REG_BASE + 0xb04)
+#define AR9170_MAC_REG_AC2_CW (AR9170_MAC_REG_BASE + 0xb08)
+#define AR9170_MAC_REG_AC3_CW (AR9170_MAC_REG_BASE + 0xb0c)
+#define AR9170_MAC_REG_AC4_CW (AR9170_MAC_REG_BASE + 0xb10)
+#define AR9170_MAC_REG_AC2_AC1_AC0_AIFS (AR9170_MAC_REG_BASE + 0xb14)
+#define AR9170_MAC_REG_AC4_AC3_AC2_AIFS (AR9170_MAC_REG_BASE + 0xb18)
+#define AR9170_MAC_REG_TXOP_ACK_EXTENSION (AR9170_MAC_REG_BASE + 0xb1c)
+#define AR9170_MAC_REG_TXOP_ACK_INTERVAL (AR9170_MAC_REG_BASE + 0xb20)
+#define AR9170_MAC_REG_CONTENTION_POINT (AR9170_MAC_REG_BASE + 0xb24)
+#define AR9170_MAC_REG_RETRY_MAX (AR9170_MAC_REG_BASE + 0xb28)
+#define AR9170_MAC_REG_TID_CFACK_CFEND_RATE (AR9170_MAC_REG_BASE + 0xb2c)
+#define AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND (AR9170_MAC_REG_BASE + 0xb30)
+#define AR9170_MAC_REG_TKIP_TSC (AR9170_MAC_REG_BASE + 0xb34)
+#define AR9170_MAC_REG_TXOP_DURATION (AR9170_MAC_REG_BASE + 0xb38)
+#define AR9170_MAC_REG_TX_QOS_THRESHOLD (AR9170_MAC_REG_BASE + 0xb3c)
+#define AR9170_MAC_REG_QOS_PRIORITY_VIRTUAL_CCA (AR9170_MAC_REG_BASE + 0xb40)
+#define AR9170_MAC_VIRTUAL_CCA_Q0 BIT(15)
+#define AR9170_MAC_VIRTUAL_CCA_Q1 BIT(16)
+#define AR9170_MAC_VIRTUAL_CCA_Q2 BIT(17)
+#define AR9170_MAC_VIRTUAL_CCA_Q3 BIT(18)
+#define AR9170_MAC_VIRTUAL_CCA_Q4 BIT(19)
+#define AR9170_MAC_VIRTUAL_CCA_ALL (0xf8000)
+
+#define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xb44)
+#define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xb48)
+
+#define AR9170_MAC_REG_AMPDU_COUNT (AR9170_MAC_REG_BASE + 0xb88)
+#define AR9170_MAC_REG_MPDU_COUNT (AR9170_MAC_REG_BASE + 0xb8c)
+
+#define AR9170_MAC_REG_AMPDU_FACTOR (AR9170_MAC_REG_BASE + 0xb9c)
+#define AR9170_MAC_AMPDU_FACTOR 0x7f0000
+#define AR9170_MAC_AMPDU_FACTOR_S 16
+#define AR9170_MAC_REG_AMPDU_DENSITY (AR9170_MAC_REG_BASE + 0xba0)
+#define AR9170_MAC_AMPDU_DENSITY 0x7
+#define AR9170_MAC_AMPDU_DENSITY_S 0
+
+#define AR9170_MAC_REG_FCS_SELECT (AR9170_MAC_REG_BASE + 0xbb0)
+#define AR9170_MAC_FCS_SWFCS 0x1
+#define AR9170_MAC_FCS_FIFO_PROT 0x4
+
+#define AR9170_MAC_REG_RTS_CTS_TPC (AR9170_MAC_REG_BASE + 0xbb4)
+#define AR9170_MAC_REG_CFEND_QOSNULL_TPC (AR9170_MAC_REG_BASE + 0xbb8)
+
+#define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xc00)
+#define AR9170_MAC_REG_RX_CONTROL (AR9170_MAC_REG_BASE + 0xc40)
+#define AR9170_MAC_RX_CTRL_DEAGG 0x1
+#define AR9170_MAC_RX_CTRL_SHORT_FILTER 0x2
+#define AR9170_MAC_RX_CTRL_SA_DA_SEARCH 0x20
+#define AR9170_MAC_RX_CTRL_PASS_TO_HOST BIT(28)
+#define AR9170_MAC_RX_CTRL_ACK_IN_SNIFFER BIT(30)
+
+#define AR9170_MAC_REG_RX_CONTROL_1 (AR9170_MAC_REG_BASE + 0xc44)
+
+#define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xc50)
+
+#define AR9170_MAC_REG_RX_MPDU (AR9170_MAC_REG_BASE + 0xca0)
+#define AR9170_MAC_REG_RX_DROPPED_MPDU (AR9170_MAC_REG_BASE + 0xca4)
+#define AR9170_MAC_REG_RX_DEL_MPDU (AR9170_MAC_REG_BASE + 0xca8)
+#define AR9170_MAC_REG_RX_PHY_MISC_ERROR (AR9170_MAC_REG_BASE + 0xcac)
+#define AR9170_MAC_REG_RX_PHY_XR_ERROR (AR9170_MAC_REG_BASE + 0xcb0)
+#define AR9170_MAC_REG_RX_PHY_OFDM_ERROR (AR9170_MAC_REG_BASE + 0xcb4)
+#define AR9170_MAC_REG_RX_PHY_CCK_ERROR (AR9170_MAC_REG_BASE + 0xcb8)
+#define AR9170_MAC_REG_RX_PHY_HT_ERROR (AR9170_MAC_REG_BASE + 0xcbc)
+#define AR9170_MAC_REG_RX_PHY_TOTAL (AR9170_MAC_REG_BASE + 0xcc0)
+
+#define AR9170_MAC_REG_DMA_TXQ_ADDR (AR9170_MAC_REG_BASE + 0xd00)
+#define AR9170_MAC_REG_DMA_TXQ_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd04)
+#define AR9170_MAC_REG_DMA_TXQ0_ADDR (AR9170_MAC_REG_BASE + 0xd00)
+#define AR9170_MAC_REG_DMA_TXQ0_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd04)
+#define AR9170_MAC_REG_DMA_TXQ1_ADDR (AR9170_MAC_REG_BASE + 0xd08)
+#define AR9170_MAC_REG_DMA_TXQ1_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd0c)
+#define AR9170_MAC_REG_DMA_TXQ2_ADDR (AR9170_MAC_REG_BASE + 0xd10)
+#define AR9170_MAC_REG_DMA_TXQ2_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd14)
+#define AR9170_MAC_REG_DMA_TXQ3_ADDR (AR9170_MAC_REG_BASE + 0xd18)
+#define AR9170_MAC_REG_DMA_TXQ3_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd1c)
+#define AR9170_MAC_REG_DMA_TXQ4_ADDR (AR9170_MAC_REG_BASE + 0xd20)
+#define AR9170_MAC_REG_DMA_TXQ4_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd24)
+#define AR9170_MAC_REG_DMA_RXQ_ADDR (AR9170_MAC_REG_BASE + 0xd28)
+#define AR9170_MAC_REG_DMA_RXQ_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd2c)
+
+#define AR9170_MAC_REG_DMA_TRIGGER (AR9170_MAC_REG_BASE + 0xd30)
+#define AR9170_DMA_TRIGGER_TXQ0 BIT(0)
+#define AR9170_DMA_TRIGGER_TXQ1 BIT(1)
+#define AR9170_DMA_TRIGGER_TXQ2 BIT(2)
+#define AR9170_DMA_TRIGGER_TXQ3 BIT(3)
+#define AR9170_DMA_TRIGGER_TXQ4 BIT(4)
+#define AR9170_DMA_TRIGGER_RXQ BIT(8)
+
+#define AR9170_MAC_REG_DMA_WLAN_STATUS (AR9170_MAC_REG_BASE + 0xd38)
+#define AR9170_MAC_REG_DMA_STATUS (AR9170_MAC_REG_BASE + 0xd3c)
+
+#define AR9170_MAC_REG_TXRX_MPI (AR9170_MAC_REG_BASE + 0xd7c)
+#define AR9170_MAC_TXRX_MPI_TX_MPI_MASK 0x0000000f
+#define AR9170_MAC_TXRX_MPI_TX_TO_MASK 0x0000fff0
+#define AR9170_MAC_TXRX_MPI_RX_MPI_MASK 0x000f0000
+#define AR9170_MAC_TXRX_MPI_RX_TO_MASK 0xfff00000
+
+#define AR9170_MAC_REG_BCN_ADDR (AR9170_MAC_REG_BASE + 0xd84)
+#define AR9170_MAC_REG_BCN_LENGTH (AR9170_MAC_REG_BASE + 0xd88)
+#define AR9170_MAC_BCN_LENGTH_MAX 256
+
+#define AR9170_MAC_REG_BCN_STATUS (AR9170_MAC_REG_BASE + 0xd8c)
+
+#define AR9170_MAC_REG_BCN_PLCP (AR9170_MAC_REG_BASE + 0xd90)
+#define AR9170_MAC_REG_BCN_CTRL (AR9170_MAC_REG_BASE + 0xd94)
+#define AR9170_BCN_CTRL_READY 0x01
+#define AR9170_BCN_CTRL_LOCK 0x02
+
+#define AR9170_MAC_REG_BCN_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd98)
+#define AR9170_MAC_REG_BCN_COUNT (AR9170_MAC_REG_BASE + 0xd9c)
+
+
+#define AR9170_MAC_REG_BCN_HT1 (AR9170_MAC_REG_BASE + 0xda0)
+#define AR9170_MAC_REG_BCN_HT2 (AR9170_MAC_REG_BASE + 0xda4)
+
+#define AR9170_MAC_REG_DMA_TXQX_ADDR_CURR (AR9170_MAC_REG_BASE + 0xdc0)
+
+/* Random number generator */
+#define AR9170_RAND_REG_BASE 0x1d0000
+
+#define AR9170_RAND_REG_NUM (AR9170_RAND_REG_BASE + 0x000)
+#define AR9170_RAND_REG_MODE (AR9170_RAND_REG_BASE + 0x004)
+#define AR9170_RAND_MODE_MANUAL 0x000
+#define AR9170_RAND_MODE_FREE 0x001
+
+/* GPIO */
+#define AR9170_GPIO_REG_BASE 0x1d0100
+#define AR9170_GPIO_REG_PORT_TYPE (AR9170_GPIO_REG_BASE + 0x000)
+#define AR9170_GPIO_REG_PORT_DATA (AR9170_GPIO_REG_BASE + 0x004)
+#define AR9170_GPIO_PORT_LED_0 1
+#define AR9170_GPIO_PORT_LED_1 2
+/* WPS Button GPIO for TP-Link TL-WN821N */
+#define AR9170_GPIO_PORT_WPS_BUTTON_PRESSED 4
+
+/* Memory Controller */
+#define AR9170_MC_REG_BASE 0x1d1000
+
+#define AR9170_MC_REG_FLASH_WAIT_STATE (AR9170_MC_REG_BASE + 0x000)
+#define AR9170_MC_REG_SEEPROM_WP0 (AR9170_MC_REG_BASE + 0x400)
+#define AR9170_MC_REG_SEEPROM_WP1 (AR9170_MC_REG_BASE + 0x404)
+#define AR9170_MC_REG_SEEPROM_WP2 (AR9170_MC_REG_BASE + 0x408)
+
+/* Interrupt Controller */
+#define AR9170_MAX_INT_SRC 9
+#define AR9170_INT_REG_BASE 0x1d2000
+
+#define AR9170_INT_REG_FLAG (AR9170_INT_REG_BASE + 0x000)
+#define AR9170_INT_REG_FIQ_MASK (AR9170_INT_REG_BASE + 0x004)
+#define AR9170_INT_REG_IRQ_MASK (AR9170_INT_REG_BASE + 0x008)
+/* INT_REG_FLAG, INT_REG_FIQ_MASK and INT_REG_IRQ_MASK */
+#define AR9170_INT_FLAG_WLAN 0x001
+#define AR9170_INT_FLAG_PTAB_BIT 0x002
+#define AR9170_INT_FLAG_SE_BIT 0x004
+#define AR9170_INT_FLAG_UART_BIT 0x008
+#define AR9170_INT_FLAG_TIMER_BIT 0x010
+#define AR9170_INT_FLAG_EXT_BIT 0x020
+#define AR9170_INT_FLAG_SW_BIT 0x040
+#define AR9170_INT_FLAG_USB_BIT 0x080
+#define AR9170_INT_FLAG_ETHERNET_BIT 0x100
+
+#define AR9170_INT_REG_PRIORITY1 (AR9170_INT_REG_BASE + 0x00c)
+#define AR9170_INT_REG_PRIORITY2 (AR9170_INT_REG_BASE + 0x010)
+#define AR9170_INT_REG_PRIORITY3 (AR9170_INT_REG_BASE + 0x014)
+#define AR9170_INT_REG_EXT_INT_CONTROL (AR9170_INT_REG_BASE + 0x018)
+#define AR9170_INT_REG_SW_INT_CONTROL (AR9170_INT_REG_BASE + 0x01c)
+#define AR9170_INT_SW_INT_ENABLE 0x1
+
+#define AR9170_INT_REG_FIQ_ENCODE (AR9170_INT_REG_BASE + 0x020)
+#define AR9170_INT_INT_IRQ_ENCODE (AR9170_INT_REG_BASE + 0x024)
+
+/* Power Management */
+#define AR9170_PWR_REG_BASE 0x1d4000
+
+#define AR9170_PWR_REG_POWER_STATE (AR9170_PWR_REG_BASE + 0x000)
+
+#define AR9170_PWR_REG_RESET (AR9170_PWR_REG_BASE + 0x004)
+#define AR9170_PWR_RESET_COMMIT_RESET_MASK BIT(0)
+#define AR9170_PWR_RESET_WLAN_MASK BIT(1)
+#define AR9170_PWR_RESET_DMA_MASK BIT(2)
+#define AR9170_PWR_RESET_BRIDGE_MASK BIT(3)
+#define AR9170_PWR_RESET_AHB_MASK BIT(9)
+#define AR9170_PWR_RESET_BB_WARM_RESET BIT(10)
+#define AR9170_PWR_RESET_BB_COLD_RESET BIT(11)
+#define AR9170_PWR_RESET_ADDA_CLK_COLD_RESET BIT(12)
+#define AR9170_PWR_RESET_PLL BIT(13)
+#define AR9170_PWR_RESET_USB_PLL BIT(14)
+
+#define AR9170_PWR_REG_CLOCK_SEL (AR9170_PWR_REG_BASE + 0x008)
+#define AR9170_PWR_CLK_AHB_40MHZ 0
+#define AR9170_PWR_CLK_AHB_20_22MHZ 1
+#define AR9170_PWR_CLK_AHB_40_44MHZ 2
+#define AR9170_PWR_CLK_AHB_80_88MHZ 3
+#define AR9170_PWR_CLK_DAC_160_INV_DLY 0x70
+
+#define AR9170_PWR_REG_CHIP_REVISION (AR9170_PWR_REG_BASE + 0x010)
+#define AR9170_PWR_REG_PLL_ADDAC (AR9170_PWR_REG_BASE + 0x014)
+#define AR9170_PWR_REG_WATCH_DOG_MAGIC (AR9170_PWR_REG_BASE + 0x020)
+
+/* Faraday USB Controller */
+#define AR9170_USB_REG_BASE 0x1e1000
+
+#define AR9170_USB_REG_MAIN_CTRL (AR9170_USB_REG_BASE + 0x000)
+#define AR9170_USB_MAIN_CTRL_REMOTE_WAKEUP BIT(0)
+#define AR9170_USB_MAIN_CTRL_ENABLE_GLOBAL_INT BIT(2)
+#define AR9170_USB_MAIN_CTRL_HIGHSPEED BIT(6)
+
+#define AR9170_USB_REG_DEVICE_ADDRESS (AR9170_USB_REG_BASE + 0x001)
+#define AR9170_USB_DEVICE_ADDRESS_CONFIGURE BIT(7)
+
+#define AR9170_USB_REG_TEST (AR9170_USB_REG_BASE + 0x002)
+#define AR9170_USB_REG_PHY_TEST_SELECT (AR9170_USB_REG_BASE + 0x008)
+#define AR9170_USB_REG_CX_CONFIG_STATUS (AR9170_USB_REG_BASE + 0x00b)
+#define AR9170_USB_REG_EP0_DATA (AR9170_USB_REG_BASE + 0x00c)
+#define AR9170_USB_REG_EP0_DATA1 (AR9170_USB_REG_BASE + 0x00c)
+#define AR9170_USB_REG_EP0_DATA2 (AR9170_USB_REG_BASE + 0x00d)
+
+#define AR9170_USB_REG_INTR_MASK_BYTE_0 (AR9170_USB_REG_BASE + 0x011)
+#define AR9170_USB_REG_INTR_MASK_BYTE_1 (AR9170_USB_REG_BASE + 0x012)
+#define AR9170_USB_REG_INTR_MASK_BYTE_2 (AR9170_USB_REG_BASE + 0x013)
+#define AR9170_USB_REG_INTR_MASK_BYTE_3 (AR9170_USB_REG_BASE + 0x014)
+#define AR9170_USB_REG_INTR_MASK_BYTE_4 (AR9170_USB_REG_BASE + 0x015)
+#define AR9170_USB_INTR_DISABLE_OUT_INT (BIT(7) | BIT(6))
+
+#define AR9170_USB_REG_INTR_MASK_BYTE_5 (AR9170_USB_REG_BASE + 0x016)
+#define AR9170_USB_REG_INTR_MASK_BYTE_6 (AR9170_USB_REG_BASE + 0x017)
+#define AR9170_USB_INTR_DISABLE_IN_INT BIT(6)
+
+#define AR9170_USB_REG_INTR_MASK_BYTE_7 (AR9170_USB_REG_BASE + 0x018)
+
+#define AR9170_USB_REG_INTR_GROUP (AR9170_USB_REG_BASE + 0x020)
+
+#define AR9170_USB_REG_INTR_SOURCE_0 (AR9170_USB_REG_BASE + 0x021)
+#define AR9170_USB_REG_INTR_SOURCE_1 (AR9170_USB_REG_BASE + 0x022)
+#define AR9170_USB_REG_INTR_SOURCE_2 (AR9170_USB_REG_BASE + 0x023)
+#define AR9170_USB_REG_INTR_SOURCE_3 (AR9170_USB_REG_BASE + 0x024)
+#define AR9170_USB_REG_INTR_SOURCE_4 (AR9170_USB_REG_BASE + 0x025)
+#define AR9170_USB_REG_INTR_SOURCE_5 (AR9170_USB_REG_BASE + 0x026)
+#define AR9170_USB_REG_INTR_SOURCE_6 (AR9170_USB_REG_BASE + 0x027)
+#define AR9170_USB_REG_INTR_SOURCE_7 (AR9170_USB_REG_BASE + 0x028)
+
+#define AR9170_USB_REG_EP_MAP (AR9170_USB_REG_BASE + 0x030)
+#define AR9170_USB_REG_EP1_MAP (AR9170_USB_REG_BASE + 0x030)
+#define AR9170_USB_REG_EP2_MAP (AR9170_USB_REG_BASE + 0x031)
+#define AR9170_USB_REG_EP3_MAP (AR9170_USB_REG_BASE + 0x032)
+#define AR9170_USB_REG_EP4_MAP (AR9170_USB_REG_BASE + 0x033)
+#define AR9170_USB_REG_EP5_MAP (AR9170_USB_REG_BASE + 0x034)
+#define AR9170_USB_REG_EP6_MAP (AR9170_USB_REG_BASE + 0x035)
+#define AR9170_USB_REG_EP7_MAP (AR9170_USB_REG_BASE + 0x036)
+#define AR9170_USB_REG_EP8_MAP (AR9170_USB_REG_BASE + 0x037)
+#define AR9170_USB_REG_EP9_MAP (AR9170_USB_REG_BASE + 0x038)
+#define AR9170_USB_REG_EP10_MAP (AR9170_USB_REG_BASE + 0x039)
+
+#define AR9170_USB_REG_EP_IN_MAX_SIZE_HIGH (AR9170_USB_REG_BASE + 0x03f)
+#define AR9170_USB_EP_IN_TOGGLE 0x10
+
+#define AR9170_USB_REG_EP_IN_MAX_SIZE_LOW (AR9170_USB_REG_BASE + 0x03e)
+
+#define AR9170_USB_REG_EP_OUT_MAX_SIZE_HIGH (AR9170_USB_REG_BASE + 0x05f)
+#define AR9170_USB_EP_OUT_TOGGLE 0x10
+
+#define AR9170_USB_REG_EP_OUT_MAX_SIZE_LOW (AR9170_USB_REG_BASE + 0x05e)
+
+#define AR9170_USB_REG_EP3_BYTE_COUNT_HIGH (AR9170_USB_REG_BASE + 0x0ae)
+#define AR9170_USB_REG_EP3_BYTE_COUNT_LOW (AR9170_USB_REG_BASE + 0x0be)
+#define AR9170_USB_REG_EP4_BYTE_COUNT_HIGH (AR9170_USB_REG_BASE + 0x0af)
+#define AR9170_USB_REG_EP4_BYTE_COUNT_LOW (AR9170_USB_REG_BASE + 0x0bf)
+
+#define AR9170_USB_REG_FIFO_MAP (AR9170_USB_REG_BASE + 0x080)
+#define AR9170_USB_REG_FIFO0_MAP (AR9170_USB_REG_BASE + 0x080)
+#define AR9170_USB_REG_FIFO1_MAP (AR9170_USB_REG_BASE + 0x081)
+#define AR9170_USB_REG_FIFO2_MAP (AR9170_USB_REG_BASE + 0x082)
+#define AR9170_USB_REG_FIFO3_MAP (AR9170_USB_REG_BASE + 0x083)
+#define AR9170_USB_REG_FIFO4_MAP (AR9170_USB_REG_BASE + 0x084)
+#define AR9170_USB_REG_FIFO5_MAP (AR9170_USB_REG_BASE + 0x085)
+#define AR9170_USB_REG_FIFO6_MAP (AR9170_USB_REG_BASE + 0x086)
+#define AR9170_USB_REG_FIFO7_MAP (AR9170_USB_REG_BASE + 0x087)
+#define AR9170_USB_REG_FIFO8_MAP (AR9170_USB_REG_BASE + 0x088)
+#define AR9170_USB_REG_FIFO9_MAP (AR9170_USB_REG_BASE + 0x089)
+
+#define AR9170_USB_REG_FIFO_CONFIG (AR9170_USB_REG_BASE + 0x090)
+#define AR9170_USB_REG_FIFO0_CONFIG (AR9170_USB_REG_BASE + 0x090)
+#define AR9170_USB_REG_FIFO1_CONFIG (AR9170_USB_REG_BASE + 0x091)
+#define AR9170_USB_REG_FIFO2_CONFIG (AR9170_USB_REG_BASE + 0x092)
+#define AR9170_USB_REG_FIFO3_CONFIG (AR9170_USB_REG_BASE + 0x093)
+#define AR9170_USB_REG_FIFO4_CONFIG (AR9170_USB_REG_BASE + 0x094)
+#define AR9170_USB_REG_FIFO5_CONFIG (AR9170_USB_REG_BASE + 0x095)
+#define AR9170_USB_REG_FIFO6_CONFIG (AR9170_USB_REG_BASE + 0x096)
+#define AR9170_USB_REG_FIFO7_CONFIG (AR9170_USB_REG_BASE + 0x097)
+#define AR9170_USB_REG_FIFO8_CONFIG (AR9170_USB_REG_BASE + 0x098)
+#define AR9170_USB_REG_FIFO9_CONFIG (AR9170_USB_REG_BASE + 0x099)
+
+#define AR9170_USB_REG_EP3_DATA (AR9170_USB_REG_BASE + 0x0f8)
+#define AR9170_USB_REG_EP4_DATA (AR9170_USB_REG_BASE + 0x0fc)
+
+#define AR9170_USB_REG_FIFO_SIZE (AR9170_USB_REG_BASE + 0x100)
+#define AR9170_USB_REG_DMA_CTL (AR9170_USB_REG_BASE + 0x108)
+#define AR9170_USB_DMA_CTL_ENABLE_TO_DEVICE BIT(0)
+#define AR9170_USB_DMA_CTL_ENABLE_FROM_DEVICE BIT(1)
+#define AR9170_USB_DMA_CTL_HIGH_SPEED BIT(2)
+#define AR9170_USB_DMA_CTL_UP_PACKET_MODE BIT(3)
+#define AR9170_USB_DMA_CTL_UP_STREAM_S 4
+#define AR9170_USB_DMA_CTL_UP_STREAM (BIT(4) | BIT(5))
+#define AR9170_USB_DMA_CTL_UP_STREAM_4K (0)
+#define AR9170_USB_DMA_CTL_UP_STREAM_8K BIT(4)
+#define AR9170_USB_DMA_CTL_UP_STREAM_16K BIT(5)
+#define AR9170_USB_DMA_CTL_UP_STREAM_32K (BIT(4) | BIT(5))
+#define AR9170_USB_DMA_CTL_DOWN_STREAM BIT(6)
+
+#define AR9170_USB_REG_DMA_STATUS (AR9170_USB_REG_BASE + 0x10c)
+#define AR9170_USB_DMA_STATUS_UP_IDLE BIT(8)
+#define AR9170_USB_DMA_STATUS_DN_IDLE BIT(16)
+
+#define AR9170_USB_REG_MAX_AGG_UPLOAD (AR9170_USB_REG_BASE + 0x110)
+#define AR9170_USB_REG_UPLOAD_TIME_CTL (AR9170_USB_REG_BASE + 0x114)
+#define AR9170_USB_REG_CBUS_CTRL (AR9170_USB_REG_BASE + 0x1f0)
+#define AR9170_USB_CBUS_CTRL_BUFFER_END (BIT(1))
+
+/* PCI/USB to AHB Bridge */
+#define AR9170_PTA_REG_BASE 0x1e2000
+
+#define AR9170_PTA_REG_CMD (AR9170_PTA_REG_BASE + 0x000)
+#define AR9170_PTA_REG_PARAM1 (AR9170_PTA_REG_BASE + 0x004)
+#define AR9170_PTA_REG_PARAM2 (AR9170_PTA_REG_BASE + 0x008)
+#define AR9170_PTA_REG_PARAM3 (AR9170_PTA_REG_BASE + 0x00c)
+#define AR9170_PTA_REG_RSP (AR9170_PTA_REG_BASE + 0x010)
+#define AR9170_PTA_REG_STATUS1 (AR9170_PTA_REG_BASE + 0x014)
+#define AR9170_PTA_REG_STATUS2 (AR9170_PTA_REG_BASE + 0x018)
+#define AR9170_PTA_REG_STATUS3 (AR9170_PTA_REG_BASE + 0x01c)
+#define AR9170_PTA_REG_AHB_INT_FLAG (AR9170_PTA_REG_BASE + 0x020)
+#define AR9170_PTA_REG_AHB_INT_MASK (AR9170_PTA_REG_BASE + 0x024)
+#define AR9170_PTA_REG_AHB_INT_ACK (AR9170_PTA_REG_BASE + 0x028)
+#define AR9170_PTA_REG_AHB_SCRATCH1 (AR9170_PTA_REG_BASE + 0x030)
+#define AR9170_PTA_REG_AHB_SCRATCH2 (AR9170_PTA_REG_BASE + 0x034)
+#define AR9170_PTA_REG_AHB_SCRATCH3 (AR9170_PTA_REG_BASE + 0x038)
+#define AR9170_PTA_REG_AHB_SCRATCH4 (AR9170_PTA_REG_BASE + 0x03c)
+
+#define AR9170_PTA_REG_SHARE_MEM_CTRL (AR9170_PTA_REG_BASE + 0x124)
+
+/*
+ * PCI to AHB Bridge
+ */
+
+#define AR9170_PTA_REG_INT_FLAG (AR9170_PTA_REG_BASE + 0x100)
+#define AR9170_PTA_INT_FLAG_DN 0x01
+#define AR9170_PTA_INT_FLAG_UP 0x02
+#define AR9170_PTA_INT_FLAG_CMD 0x04
+
+#define AR9170_PTA_REG_INT_MASK (AR9170_PTA_REG_BASE + 0x104)
+#define AR9170_PTA_REG_DN_DMA_ADDRL (AR9170_PTA_REG_BASE + 0x108)
+#define AR9170_PTA_REG_DN_DMA_ADDRH (AR9170_PTA_REG_BASE + 0x10c)
+#define AR9170_PTA_REG_UP_DMA_ADDRL (AR9170_PTA_REG_BASE + 0x110)
+#define AR9170_PTA_REG_UP_DMA_ADDRH (AR9170_PTA_REG_BASE + 0x114)
+#define AR9170_PTA_REG_DN_PEND_TIME (AR9170_PTA_REG_BASE + 0x118)
+#define AR9170_PTA_REG_UP_PEND_TIME (AR9170_PTA_REG_BASE + 0x11c)
+#define AR9170_PTA_REG_CONTROL (AR9170_PTA_REG_BASE + 0x120)
+#define AR9170_PTA_CTRL_4_BEAT_BURST 0x00
+#define AR9170_PTA_CTRL_8_BEAT_BURST 0x01
+#define AR9170_PTA_CTRL_16_BEAT_BURST 0x02
+#define AR9170_PTA_CTRL_LOOPBACK_MODE 0x10
+
+#define AR9170_PTA_REG_MEM_CTRL (AR9170_PTA_REG_BASE + 0x124)
+#define AR9170_PTA_REG_MEM_ADDR (AR9170_PTA_REG_BASE + 0x128)
+#define AR9170_PTA_REG_DN_DMA_TRIGGER (AR9170_PTA_REG_BASE + 0x12c)
+#define AR9170_PTA_REG_UP_DMA_TRIGGER (AR9170_PTA_REG_BASE + 0x130)
+#define AR9170_PTA_REG_DMA_STATUS (AR9170_PTA_REG_BASE + 0x134)
+#define AR9170_PTA_REG_DN_CURR_ADDRL (AR9170_PTA_REG_BASE + 0x138)
+#define AR9170_PTA_REG_DN_CURR_ADDRH (AR9170_PTA_REG_BASE + 0x13c)
+#define AR9170_PTA_REG_UP_CURR_ADDRL (AR9170_PTA_REG_BASE + 0x140)
+#define AR9170_PTA_REG_UP_CURR_ADDRH (AR9170_PTA_REG_BASE + 0x144)
+#define AR9170_PTA_REG_DMA_MODE_CTRL (AR9170_PTA_REG_BASE + 0x148)
+#define AR9170_PTA_DMA_MODE_CTRL_RESET BIT(0)
+#define AR9170_PTA_DMA_MODE_CTRL_DISABLE_USB BIT(1)
+
+/* Protocol Controller Module */
+#define AR9170_MAC_REG_PC_REG_BASE (AR9170_MAC_REG_BASE + 0xe00)
+
+
+#define AR9170_NUM_LEDS 2
+
+/* CAM */
+#define AR9170_CAM_MAX_USER 64
+#define AR9170_CAM_MAX_KEY_LENGTH 16
+
+#define AR9170_SRAM_OFFSET 0x100000
+#define AR9170_SRAM_SIZE 0x18000
+
+#define AR9170_PRAM_OFFSET 0x200000
+#define AR9170_PRAM_SIZE 0x8000
+
+enum cpu_clock {
+ AHB_STATIC_40MHZ = 0,
+ AHB_GMODE_22MHZ = 1,
+ AHB_AMODE_20MHZ = 1,
+ AHB_GMODE_44MHZ = 2,
+ AHB_AMODE_40MHZ = 2,
+ AHB_GMODE_88MHZ = 3,
+ AHB_AMODE_80MHZ = 3
+};
+
+/* USB endpoints */
+enum ar9170_usb_ep {
+ /*
+ * Control EP is always EP 0 (USB SPEC)
+ *
+ * The weird thing is: the original firmware has a few
+ * comments that suggest that the actual EP numbers
+ * are in the 1 to 10 range?!
+ */
+ AR9170_USB_EP_CTRL = 0,
+
+ AR9170_USB_EP_TX,
+ AR9170_USB_EP_RX,
+ AR9170_USB_EP_IRQ,
+ AR9170_USB_EP_CMD,
+ AR9170_USB_NUM_EXTRA_EP = 4,
+
+ __AR9170_USB_NUM_EP,
+
+ __AR9170_USB_NUM_MAX_EP = 10
+};
+
+enum ar9170_usb_fifo {
+ __AR9170_USB_NUM_MAX_FIFO = 10
+};
+
+enum ar9170_tx_queues {
+ AR9170_TXQ0 = 0,
+ AR9170_TXQ1,
+ AR9170_TXQ2,
+ AR9170_TXQ3,
+ AR9170_TXQ_SPECIAL,
+
+ /* keep last */
+ __AR9170_NUM_TX_QUEUES = 5
+};
+
+#define AR9170_TX_STREAM_TAG 0x697e
+#define AR9170_RX_STREAM_TAG 0x4e00
+#define AR9170_RX_STREAM_MAX_SIZE 0xffff
+
+struct ar9170_stream {
+ __le16 length;
+ __le16 tag;
+
+ u8 payload[0];
+};
+
+#define AR9170_MAX_ACKTABLE_ENTRIES 8
+#define AR9170_MAX_VIRTUAL_MAC 7
+
+#define AR9170_USB_EP_CTRL_MAX 64
+#define AR9170_USB_EP_TX_MAX 512
+#define AR9170_USB_EP_RX_MAX 512
+#define AR9170_USB_EP_IRQ_MAX 64
+#define AR9170_USB_EP_CMD_MAX 64
+
+/* Trigger PRETBTT interrupt 6 Kus earlier */
+#define CARL9170_PRETBTT_KUS 6
+
+#define AR5416_MAX_RATE_POWER 63
+
+#define SET_VAL(reg, value, newvalue) \
+ (value = ((value) & ~reg) | (((newvalue) << reg##_S) & reg))
+
+#define SET_CONSTVAL(reg, newvalue) \
+ (((newvalue) << reg##_S) & reg)
+
+#define MOD_VAL(reg, value, newvalue) \
+ (((value) & ~reg) | (((newvalue) << reg##_S) & reg))
+#endif /* __CARL9170_SHARED_HW_H */
diff --git a/drivers/net/wireless/ath/carl9170/led.c b/drivers/net/wireless/ath/carl9170/led.c
new file mode 100644
index 000000000000..4bb2cbd8bd9b
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/led.c
@@ -0,0 +1,190 @@
+/*
+ * Atheros CARL9170 driver
+ *
+ * LED handling
+ *
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2009, 2010, Christian Lamparer <chunkeey@googlemail.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; see the file COPYING. If not, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2007-2008 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 "carl9170.h"
+#include "cmd.h"
+
+int carl9170_led_set_state(struct ar9170 *ar, const u32 led_state)
+{
+ return carl9170_write_reg(ar, AR9170_GPIO_REG_PORT_DATA, led_state);
+}
+
+int carl9170_led_init(struct ar9170 *ar)
+{
+ int err;
+
+ /* disable LEDs */
+ /* GPIO [0/1 mode: output, 2/3: input] */
+ err = carl9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3);
+ if (err)
+ goto out;
+
+ /* GPIO 0/1 value: off */
+ err = carl9170_led_set_state(ar, 0);
+
+out:
+ return err;
+}
+
+#ifdef CONFIG_CARL9170_LEDS
+static void carl9170_led_update(struct work_struct *work)
+{
+ struct ar9170 *ar = container_of(work, struct ar9170, led_work.work);
+ int i, tmp = 300, blink_delay = 1000;
+ u32 led_val = 0;
+ bool rerun = false;
+
+ if (!IS_ACCEPTING_CMD(ar))
+ return;
+
+ mutex_lock(&ar->mutex);
+ for (i = 0; i < AR9170_NUM_LEDS; i++) {
+ if (ar->leds[i].registered) {
+ if (ar->leds[i].last_state ||
+ ar->leds[i].toggled) {
+
+ if (ar->leds[i].toggled)
+ tmp = 70 + 200 / (ar->leds[i].toggled);
+
+ if (tmp < blink_delay)
+ blink_delay = tmp;
+
+ led_val |= 1 << i;
+ ar->leds[i].toggled = 0;
+ rerun = true;
+ }
+ }
+ }
+
+ carl9170_led_set_state(ar, led_val);
+ mutex_unlock(&ar->mutex);
+
+ if (!rerun)
+ return;
+
+ ieee80211_queue_delayed_work(ar->hw,
+ &ar->led_work,
+ msecs_to_jiffies(blink_delay));
+}
+
+static void carl9170_led_set_brightness(struct led_classdev *led,
+ enum led_brightness brightness)
+{
+ struct carl9170_led *arl = container_of(led, struct carl9170_led, l);
+ struct ar9170 *ar = arl->ar;
+
+ if (!arl->registered)
+ return;
+
+ if (arl->last_state != !!brightness) {
+ arl->toggled++;
+ arl->last_state = !!brightness;
+ }
+
+ if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled))
+ ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ/10);
+}
+
+static int carl9170_led_register_led(struct ar9170 *ar, int i, char *name,
+ char *trigger)
+{
+ int err;
+
+ snprintf(ar->leds[i].name, sizeof(ar->leds[i].name),
+ "carl9170-%s::%s", wiphy_name(ar->hw->wiphy), name);
+
+ ar->leds[i].ar = ar;
+ ar->leds[i].l.name = ar->leds[i].name;
+ ar->leds[i].l.brightness_set = carl9170_led_set_brightness;
+ ar->leds[i].l.brightness = 0;
+ ar->leds[i].l.default_trigger = trigger;
+
+ err = led_classdev_register(wiphy_dev(ar->hw->wiphy),
+ &ar->leds[i].l);
+ if (err) {
+ wiphy_err(ar->hw->wiphy, "failed to register %s LED (%d).\n",
+ ar->leds[i].name, err);
+ } else {
+ ar->leds[i].registered = true;
+ }
+
+ return err;
+}
+
+void carl9170_led_unregister(struct ar9170 *ar)
+{
+ int i;
+
+ for (i = 0; i < AR9170_NUM_LEDS; i++)
+ if (ar->leds[i].registered) {
+ led_classdev_unregister(&ar->leds[i].l);
+ ar->leds[i].registered = false;
+ ar->leds[i].toggled = 0;
+ }
+
+ cancel_delayed_work_sync(&ar->led_work);
+}
+
+int carl9170_led_register(struct ar9170 *ar)
+{
+ int err;
+
+ INIT_DELAYED_WORK(&ar->led_work, carl9170_led_update);
+
+ err = carl9170_led_register_led(ar, 0, "tx",
+ ieee80211_get_tx_led_name(ar->hw));
+ if (err)
+ goto fail;
+
+ if (ar->features & CARL9170_ONE_LED)
+ return 0;
+
+ err = carl9170_led_register_led(ar, 1, "assoc",
+ ieee80211_get_assoc_led_name(ar->hw));
+ if (err)
+ goto fail;
+
+ return 0;
+
+fail:
+ carl9170_led_unregister(ar);
+ return err;
+}
+
+#endif /* CONFIG_CARL9170_LEDS */
diff --git a/drivers/net/wireless/ath/carl9170/mac.c b/drivers/net/wireless/ath/carl9170/mac.c
new file mode 100644
index 000000000000..2305bc27151c
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/mac.c
@@ -0,0 +1,604 @@
+/*
+ * Atheros CARL9170 driver
+ *
+ * MAC programming
+ *
+ * Copyright 2008, 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 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, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2007-2008 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 <asm/unaligned.h>
+
+#include "carl9170.h"
+#include "cmd.h"
+
+int carl9170_set_dyn_sifs_ack(struct ar9170 *ar)
+{
+ u32 val;
+
+ if (conf_is_ht40(&ar->hw->conf))
+ val = 0x010a;
+ else {
+ if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ)
+ val = 0x105;
+ else
+ val = 0x104;
+ }
+
+ return carl9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val);
+}
+
+int carl9170_set_rts_cts_rate(struct ar9170 *ar)
+{
+ u32 rts_rate, cts_rate;
+
+ if (conf_is_ht(&ar->hw->conf)) {
+ /* 12 mbit OFDM */
+ rts_rate = 0x1da;
+ cts_rate = 0x10a;
+ } else {
+ if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
+ /* 11 mbit CCK */
+ rts_rate = 033;
+ cts_rate = 003;
+ } else {
+ /* 6 mbit OFDM */
+ rts_rate = 0x1bb;
+ cts_rate = 0x10b;
+ }
+ }
+
+ return carl9170_write_reg(ar, AR9170_MAC_REG_RTS_CTS_RATE,
+ rts_rate | (cts_rate) << 16);
+}
+
+int carl9170_set_slot_time(struct ar9170 *ar)
+{
+ struct ieee80211_vif *vif;
+ u32 slottime = 20;
+
+ rcu_read_lock();
+ vif = carl9170_get_main_vif(ar);
+ if (!vif) {
+ rcu_read_unlock();
+ return 0;
+ }
+
+ if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) ||
+ vif->bss_conf.use_short_slot)
+ slottime = 9;
+
+ rcu_read_unlock();
+
+ return carl9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME,
+ slottime << 10);
+}
+
+int carl9170_set_mac_rates(struct ar9170 *ar)
+{
+ struct ieee80211_vif *vif;
+ u32 basic, mandatory;
+
+ rcu_read_lock();
+ vif = carl9170_get_main_vif(ar);
+
+ if (!vif) {
+ rcu_read_unlock();
+ return 0;
+ }
+
+ basic = (vif->bss_conf.basic_rates & 0xf);
+ basic |= (vif->bss_conf.basic_rates & 0xff0) << 4;
+ rcu_read_unlock();
+
+ if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ)
+ mandatory = 0xff00; /* OFDM 6/9/12/18/24/36/48/54 */
+ else
+ mandatory = 0xff0f; /* OFDM (6/9../54) + CCK (1/2/5.5/11) */
+
+ carl9170_regwrite_begin(ar);
+ carl9170_regwrite(AR9170_MAC_REG_BASIC_RATE, basic);
+ carl9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, mandatory);
+ carl9170_regwrite_finish();
+
+ return carl9170_regwrite_result();
+}
+
+int carl9170_set_qos(struct ar9170 *ar)
+{
+ carl9170_regwrite_begin(ar);
+
+ carl9170_regwrite(AR9170_MAC_REG_AC0_CW, ar->edcf[0].cw_min |
+ (ar->edcf[0].cw_max << 16));
+ carl9170_regwrite(AR9170_MAC_REG_AC1_CW, ar->edcf[1].cw_min |
+ (ar->edcf[1].cw_max << 16));
+ carl9170_regwrite(AR9170_MAC_REG_AC2_CW, ar->edcf[2].cw_min |
+ (ar->edcf[2].cw_max << 16));
+ carl9170_regwrite(AR9170_MAC_REG_AC3_CW, ar->edcf[3].cw_min |
+ (ar->edcf[3].cw_max << 16));
+ carl9170_regwrite(AR9170_MAC_REG_AC4_CW, ar->edcf[4].cw_min |
+ (ar->edcf[4].cw_max << 16));
+
+ carl9170_regwrite(AR9170_MAC_REG_AC2_AC1_AC0_AIFS,
+ ((ar->edcf[0].aifs * 9 + 10)) |
+ ((ar->edcf[1].aifs * 9 + 10) << 12) |
+ ((ar->edcf[2].aifs * 9 + 10) << 24));
+ carl9170_regwrite(AR9170_MAC_REG_AC4_AC3_AC2_AIFS,
+ ((ar->edcf[2].aifs * 9 + 10) >> 8) |
+ ((ar->edcf[3].aifs * 9 + 10) << 4) |
+ ((ar->edcf[4].aifs * 9 + 10) << 16));
+
+ carl9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP,
+ ar->edcf[0].txop | ar->edcf[1].txop << 16);
+ carl9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP,
+ ar->edcf[2].txop | ar->edcf[3].txop << 16 |
+ ar->edcf[4].txop << 24);
+
+ carl9170_regwrite_finish();
+
+ return carl9170_regwrite_result();
+}
+
+int carl9170_init_mac(struct ar9170 *ar)
+{
+ carl9170_regwrite_begin(ar);
+
+ /* switch MAC to OTUS interface */
+ carl9170_regwrite(0x1c3600, 0x3);
+
+ carl9170_regwrite(AR9170_MAC_REG_ACK_EXTENSION, 0x40);
+
+ carl9170_regwrite(AR9170_MAC_REG_RETRY_MAX, 0x0);
+
+ carl9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER,
+ AR9170_MAC_FTF_MONITOR);
+
+ /* enable MMIC */
+ carl9170_regwrite(AR9170_MAC_REG_SNIFFER,
+ AR9170_MAC_SNIFFER_DEFAULTS);
+
+ carl9170_regwrite(AR9170_MAC_REG_RX_THRESHOLD, 0xc1f80);
+
+ carl9170_regwrite(AR9170_MAC_REG_RX_PE_DELAY, 0x70);
+ carl9170_regwrite(AR9170_MAC_REG_EIFS_AND_SIFS, 0xa144000);
+ carl9170_regwrite(AR9170_MAC_REG_SLOT_TIME, 9 << 10);
+
+ /* CF-END & CF-ACK rate => 24M OFDM */
+ carl9170_regwrite(AR9170_MAC_REG_TID_CFACK_CFEND_RATE, 0x59900000);
+
+ /* NAV protects ACK only (in TXOP) */
+ carl9170_regwrite(AR9170_MAC_REG_TXOP_DURATION, 0x201);
+
+ /* Set Beacon PHY CTRL's TPC to 0x7, TA1=1 */
+ /* OTUS set AM to 0x1 */
+ carl9170_regwrite(AR9170_MAC_REG_BCN_HT1, 0x8000170);
+
+ carl9170_regwrite(AR9170_MAC_REG_BACKOFF_PROTECT, 0x105);
+
+ /* Aggregation MAX number and timeout */
+ carl9170_regwrite(AR9170_MAC_REG_AMPDU_FACTOR, 0xa);
+ carl9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, 0x140a00);
+
+ carl9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER,
+ AR9170_MAC_FTF_DEFAULTS);
+
+ carl9170_regwrite(AR9170_MAC_REG_RX_CONTROL,
+ AR9170_MAC_RX_CTRL_DEAGG |
+ AR9170_MAC_RX_CTRL_SHORT_FILTER);
+
+ /* rate sets */
+ carl9170_regwrite(AR9170_MAC_REG_BASIC_RATE, 0x150f);
+ carl9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, 0x150f);
+ carl9170_regwrite(AR9170_MAC_REG_RTS_CTS_RATE, 0x0030033);
+
+ /* MIMO response control */
+ carl9170_regwrite(AR9170_MAC_REG_ACK_TPC, 0x4003c1e);
+
+ carl9170_regwrite(AR9170_MAC_REG_AMPDU_RX_THRESH, 0xffff);
+
+ /* set PHY register read timeout (??) */
+ carl9170_regwrite(AR9170_MAC_REG_MISC_680, 0xf00008);
+
+ /* Disable Rx TimeOut, workaround for BB. */
+ carl9170_regwrite(AR9170_MAC_REG_RX_TIMEOUT, 0x0);
+
+ /* Set WLAN DMA interrupt mode: generate int per packet */
+ carl9170_regwrite(AR9170_MAC_REG_TXRX_MPI, 0x110011);
+
+ carl9170_regwrite(AR9170_MAC_REG_FCS_SELECT,
+ AR9170_MAC_FCS_FIFO_PROT);
+
+ /* Disables the CF_END frame, undocumented register */
+ carl9170_regwrite(AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND,
+ 0x141e0f48);
+
+ /* reset group hash table */
+ carl9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, 0xffffffff);
+ carl9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, 0xffffffff);
+
+ /* disable PRETBTT interrupt */
+ carl9170_regwrite(AR9170_MAC_REG_PRETBTT, 0x0);
+ carl9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, 0x0);
+
+ carl9170_regwrite_finish();
+
+ return carl9170_regwrite_result();
+}
+
+static int carl9170_set_mac_reg(struct ar9170 *ar,
+ const u32 reg, const u8 *mac)
+{
+ static const u8 zero[ETH_ALEN] = { 0 };
+
+ if (!mac)
+ mac = zero;
+
+ carl9170_regwrite_begin(ar);
+
+ carl9170_regwrite(reg, get_unaligned_le32(mac));
+ carl9170_regwrite(reg + 4, get_unaligned_le16(mac + 4));
+
+ carl9170_regwrite_finish();
+
+ return carl9170_regwrite_result();
+}
+
+int carl9170_mod_virtual_mac(struct ar9170 *ar, const unsigned int id,
+ const u8 *mac)
+{
+ if (WARN_ON(id >= ar->fw.vif_num))
+ return -EINVAL;
+
+ return carl9170_set_mac_reg(ar,
+ AR9170_MAC_REG_ACK_TABLE + (id - 1) * 8, mac);
+}
+
+int carl9170_update_multicast(struct ar9170 *ar, const u64 mc_hash)
+{
+ int err;
+
+ carl9170_regwrite_begin(ar);
+ carl9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, mc_hash >> 32);
+ carl9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, mc_hash);
+ carl9170_regwrite_finish();
+ err = carl9170_regwrite_result();
+ if (err)
+ return err;
+
+ ar->cur_mc_hash = mc_hash;
+ return 0;
+}
+
+int carl9170_set_operating_mode(struct ar9170 *ar)
+{
+ struct ieee80211_vif *vif;
+ struct ath_common *common = &ar->common;
+ u8 *mac_addr, *bssid;
+ u32 cam_mode = AR9170_MAC_CAM_DEFAULTS;
+ u32 enc_mode = AR9170_MAC_ENCRYPTION_DEFAULTS;
+ u32 rx_ctrl = AR9170_MAC_RX_CTRL_DEAGG |
+ AR9170_MAC_RX_CTRL_SHORT_FILTER;
+ u32 sniffer = AR9170_MAC_SNIFFER_DEFAULTS;
+ int err = 0;
+
+ rcu_read_lock();
+ vif = carl9170_get_main_vif(ar);
+
+ if (vif) {
+ mac_addr = common->macaddr;
+ bssid = common->curbssid;
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_ADHOC:
+ cam_mode |= AR9170_MAC_CAM_IBSS;
+ break;
+ case NL80211_IFTYPE_AP:
+ cam_mode |= AR9170_MAC_CAM_AP;
+
+ /* iwlagn 802.11n STA Workaround */
+ rx_ctrl |= AR9170_MAC_RX_CTRL_PASS_TO_HOST;
+ break;
+ case NL80211_IFTYPE_WDS:
+ cam_mode |= AR9170_MAC_CAM_AP_WDS;
+ rx_ctrl |= AR9170_MAC_RX_CTRL_PASS_TO_HOST;
+ break;
+ case NL80211_IFTYPE_STATION:
+ cam_mode |= AR9170_MAC_CAM_STA;
+ rx_ctrl |= AR9170_MAC_RX_CTRL_PASS_TO_HOST;
+ break;
+ default:
+ WARN(1, "Unsupported operation mode %x\n", vif->type);
+ err = -EOPNOTSUPP;
+ break;
+ }
+ } else {
+ mac_addr = NULL;
+ bssid = NULL;
+ }
+ rcu_read_unlock();
+
+ if (err)
+ return err;
+
+ if (ar->rx_software_decryption)
+ enc_mode |= AR9170_MAC_ENCRYPTION_RX_SOFTWARE;
+
+ if (ar->sniffer_enabled) {
+ rx_ctrl |= AR9170_MAC_RX_CTRL_ACK_IN_SNIFFER;
+ sniffer |= AR9170_MAC_SNIFFER_ENABLE_PROMISC;
+ enc_mode |= AR9170_MAC_ENCRYPTION_RX_SOFTWARE;
+ }
+
+ err = carl9170_set_mac_reg(ar, AR9170_MAC_REG_MAC_ADDR_L, mac_addr);
+ if (err)
+ return err;
+
+ err = carl9170_set_mac_reg(ar, AR9170_MAC_REG_BSSID_L, bssid);
+ if (err)
+ return err;
+
+ carl9170_regwrite_begin(ar);
+ carl9170_regwrite(AR9170_MAC_REG_SNIFFER, sniffer);
+ carl9170_regwrite(AR9170_MAC_REG_CAM_MODE, cam_mode);
+ carl9170_regwrite(AR9170_MAC_REG_ENCRYPTION, enc_mode);
+ carl9170_regwrite(AR9170_MAC_REG_RX_CONTROL, rx_ctrl);
+ carl9170_regwrite_finish();
+
+ return carl9170_regwrite_result();
+}
+
+int carl9170_set_hwretry_limit(struct ar9170 *ar, const unsigned int max_retry)
+{
+ u32 tmp = min_t(u32, 0x33333, max_retry * 0x11111);
+
+ return carl9170_write_reg(ar, AR9170_MAC_REG_RETRY_MAX, tmp);
+}
+
+int carl9170_set_beacon_timers(struct ar9170 *ar)
+{
+ struct ieee80211_vif *vif;
+ u32 v = 0;
+ u32 pretbtt = 0;
+
+ rcu_read_lock();
+ vif = carl9170_get_main_vif(ar);
+
+ if (vif) {
+ struct carl9170_vif_info *mvif;
+ mvif = (void *) vif->drv_priv;
+
+ if (mvif->enable_beacon && !WARN_ON(!ar->beacon_enabled)) {
+ ar->global_beacon_int = vif->bss_conf.beacon_int /
+ ar->beacon_enabled;
+
+ SET_VAL(AR9170_MAC_BCN_DTIM, v,
+ vif->bss_conf.dtim_period);
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_ADHOC:
+ v |= AR9170_MAC_BCN_IBSS_MODE;
+ break;
+ case NL80211_IFTYPE_AP:
+ v |= AR9170_MAC_BCN_AP_MODE;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+ } else if (vif->type == NL80211_IFTYPE_STATION) {
+ ar->global_beacon_int = vif->bss_conf.beacon_int;
+
+ SET_VAL(AR9170_MAC_BCN_DTIM, v,
+ ar->hw->conf.ps_dtim_period);
+
+ v |= AR9170_MAC_BCN_STA_PS |
+ AR9170_MAC_BCN_PWR_MGT;
+ }
+
+ if (ar->global_beacon_int) {
+ if (ar->global_beacon_int < 15) {
+ rcu_read_unlock();
+ return -ERANGE;
+ }
+
+ ar->global_pretbtt = ar->global_beacon_int -
+ CARL9170_PRETBTT_KUS;
+ } else {
+ ar->global_pretbtt = 0;
+ }
+ } else {
+ ar->global_beacon_int = 0;
+ ar->global_pretbtt = 0;
+ }
+
+ rcu_read_unlock();
+
+ SET_VAL(AR9170_MAC_BCN_PERIOD, v, ar->global_beacon_int);
+ SET_VAL(AR9170_MAC_PRETBTT, pretbtt, ar->global_pretbtt);
+ SET_VAL(AR9170_MAC_PRETBTT2, pretbtt, ar->global_pretbtt);
+
+ carl9170_regwrite_begin(ar);
+ carl9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt);
+ carl9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v);
+ carl9170_regwrite_finish();
+ return carl9170_regwrite_result();
+}
+
+int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
+{
+ struct sk_buff *skb;
+ struct carl9170_vif_info *cvif;
+ __le32 *data, *old = NULL;
+ u32 word, off, addr, len;
+ int i = 0, err = 0;
+
+ rcu_read_lock();
+ cvif = rcu_dereference(ar->beacon_iter);
+retry:
+ if (ar->vifs == 0 || !cvif)
+ goto out_unlock;
+
+ list_for_each_entry_continue_rcu(cvif, &ar->vif_list, list) {
+ if (cvif->active && cvif->enable_beacon)
+ goto found;
+ }
+
+ if (!ar->beacon_enabled || i++)
+ goto out_unlock;
+
+ goto retry;
+
+found:
+ rcu_assign_pointer(ar->beacon_iter, cvif);
+
+ skb = ieee80211_beacon_get_tim(ar->hw, carl9170_get_vif(cvif),
+ NULL, NULL);
+
+ if (!skb) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+
+ spin_lock_bh(&ar->beacon_lock);
+ data = (__le32 *)skb->data;
+ if (cvif->beacon)
+ old = (__le32 *)cvif->beacon->data;
+
+ off = cvif->id * AR9170_MAC_BCN_LENGTH_MAX;
+ addr = ar->fw.beacon_addr + off;
+ len = roundup(skb->len + FCS_LEN, 4);
+
+ if ((off + len) > ar->fw.beacon_max_len) {
+ if (net_ratelimit()) {
+ wiphy_err(ar->hw->wiphy, "beacon does not "
+ "fit into device memory!\n");
+ }
+
+ spin_unlock_bh(&ar->beacon_lock);
+ dev_kfree_skb_any(skb);
+ err = -EINVAL;
+ goto out_unlock;
+ }
+
+ if (len > AR9170_MAC_BCN_LENGTH_MAX) {
+ if (net_ratelimit()) {
+ wiphy_err(ar->hw->wiphy, "no support for beacons "
+ "bigger than %d (yours:%d).\n",
+ AR9170_MAC_BCN_LENGTH_MAX, len);
+ }
+
+ spin_unlock_bh(&ar->beacon_lock);
+ dev_kfree_skb_any(skb);
+ err = -EMSGSIZE;
+ goto out_unlock;
+ }
+
+ carl9170_async_regwrite_begin(ar);
+
+ /* XXX: use skb->cb info */
+ if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
+ carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP,
+ ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400);
+ } else {
+ carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP,
+ ((skb->len + FCS_LEN) << 16) + 0x001b);
+ }
+
+ for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) {
+ /*
+ * XXX: This accesses beyond skb data for up
+ * to the last 3 bytes!!
+ */
+
+ if (old && (data[i] == old[i]))
+ continue;
+
+ word = le32_to_cpu(data[i]);
+ carl9170_async_regwrite(addr + 4 * i, word);
+ }
+ carl9170_async_regwrite_finish();
+
+ dev_kfree_skb_any(cvif->beacon);
+ cvif->beacon = NULL;
+
+ err = carl9170_async_regwrite_result();
+ if (!err)
+ cvif->beacon = skb;
+ spin_unlock_bh(&ar->beacon_lock);
+ if (err)
+ goto out_unlock;
+
+ if (submit) {
+ err = carl9170_bcn_ctrl(ar, cvif->id,
+ CARL9170_BCN_CTRL_CAB_TRIGGER,
+ addr, skb->len + FCS_LEN);
+
+ if (err)
+ goto out_unlock;
+ }
+out_unlock:
+ rcu_read_unlock();
+ return err;
+}
+
+int carl9170_upload_key(struct ar9170 *ar, const u8 id, const u8 *mac,
+ const u8 ktype, const u8 keyidx, const u8 *keydata,
+ const int keylen)
+{
+ struct carl9170_set_key_cmd key = { };
+ static const u8 bcast[ETH_ALEN] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ mac = mac ? : bcast;
+
+ key.user = cpu_to_le16(id);
+ key.keyId = cpu_to_le16(keyidx);
+ key.type = cpu_to_le16(ktype);
+ memcpy(&key.macAddr, mac, ETH_ALEN);
+ if (keydata)
+ memcpy(&key.key, keydata, keylen);
+
+ return carl9170_exec_cmd(ar, CARL9170_CMD_EKEY,
+ sizeof(key), (u8 *)&key, 0, NULL);
+}
+
+int carl9170_disable_key(struct ar9170 *ar, const u8 id)
+{
+ struct carl9170_disable_key_cmd key = { };
+
+ key.user = cpu_to_le16(id);
+
+ return carl9170_exec_cmd(ar, CARL9170_CMD_DKEY,
+ sizeof(key), (u8 *)&key, 0, NULL);
+}
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
new file mode 100644
index 000000000000..980ae70ea424
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -0,0 +1,1891 @@
+/*
+ * Atheros CARL9170 driver
+ *
+ * mac80211 interaction code
+ *
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.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; see the file COPYING. If not, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2007-2008 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/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/random.h>
+#include <net/mac80211.h>
+#include <net/cfg80211.h>
+#include "hw.h"
+#include "carl9170.h"
+#include "cmd.h"
+
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware crypto offload.");
+
+int modparam_noht;
+module_param_named(noht, modparam_noht, int, S_IRUGO);
+MODULE_PARM_DESC(noht, "Disable MPDU aggregation.");
+
+#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \
+ .bitrate = (_bitrate), \
+ .flags = (_flags), \
+ .hw_value = (_hw_rate) | (_txpidx) << 4, \
+}
+
+struct ieee80211_rate __carl9170_ratetable[] = {
+ RATE(10, 0, 0, 0),
+ RATE(20, 1, 1, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(55, 2, 2, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(110, 3, 3, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(60, 0xb, 0, 0),
+ RATE(90, 0xf, 0, 0),
+ RATE(120, 0xa, 0, 0),
+ RATE(180, 0xe, 0, 0),
+ RATE(240, 0x9, 0, 0),
+ RATE(360, 0xd, 1, 0),
+ RATE(480, 0x8, 2, 0),
+ RATE(540, 0xc, 3, 0),
+};
+#undef RATE
+
+#define carl9170_g_ratetable (__carl9170_ratetable + 0)
+#define carl9170_g_ratetable_size 12
+#define carl9170_a_ratetable (__carl9170_ratetable + 4)
+#define carl9170_a_ratetable_size 8
+
+/*
+ * NB: The hw_value is used as an index into the carl9170_phy_freq_params
+ * array in phy.c so that we don't have to do frequency lookups!
+ */
+#define CHAN(_freq, _idx) { \
+ .center_freq = (_freq), \
+ .hw_value = (_idx), \
+ .max_power = 18, /* XXX */ \
+}
+
+static struct ieee80211_channel carl9170_2ghz_chantable[] = {
+ CHAN(2412, 0),
+ CHAN(2417, 1),
+ CHAN(2422, 2),
+ CHAN(2427, 3),
+ CHAN(2432, 4),
+ CHAN(2437, 5),
+ CHAN(2442, 6),
+ CHAN(2447, 7),
+ CHAN(2452, 8),
+ CHAN(2457, 9),
+ CHAN(2462, 10),
+ CHAN(2467, 11),
+ CHAN(2472, 12),
+ CHAN(2484, 13),
+};
+
+static struct ieee80211_channel carl9170_5ghz_chantable[] = {
+ CHAN(4920, 14),
+ CHAN(4940, 15),
+ CHAN(4960, 16),
+ CHAN(4980, 17),
+ CHAN(5040, 18),
+ CHAN(5060, 19),
+ CHAN(5080, 20),
+ CHAN(5180, 21),
+ CHAN(5200, 22),
+ CHAN(5220, 23),
+ CHAN(5240, 24),
+ CHAN(5260, 25),
+ CHAN(5280, 26),
+ CHAN(5300, 27),
+ CHAN(5320, 28),
+ CHAN(5500, 29),
+ CHAN(5520, 30),
+ CHAN(5540, 31),
+ CHAN(5560, 32),
+ CHAN(5580, 33),
+ CHAN(5600, 34),
+ CHAN(5620, 35),
+ CHAN(5640, 36),
+ CHAN(5660, 37),
+ CHAN(5680, 38),
+ CHAN(5700, 39),
+ CHAN(5745, 40),
+ CHAN(5765, 41),
+ CHAN(5785, 42),
+ CHAN(5805, 43),
+ CHAN(5825, 44),
+ CHAN(5170, 45),
+ CHAN(5190, 46),
+ CHAN(5210, 47),
+ CHAN(5230, 48),
+};
+#undef CHAN
+
+#define CARL9170_HT_CAP \
+{ \
+ .ht_supported = true, \
+ .cap = IEEE80211_HT_CAP_MAX_AMSDU | \
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
+ IEEE80211_HT_CAP_SGI_40 | \
+ IEEE80211_HT_CAP_DSSSCCK40 | \
+ IEEE80211_HT_CAP_SM_PS, \
+ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, \
+ .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
+ .mcs = { \
+ .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \
+ .rx_highest = cpu_to_le16(300), \
+ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
+ }, \
+}
+
+static struct ieee80211_supported_band carl9170_band_2GHz = {
+ .channels = carl9170_2ghz_chantable,
+ .n_channels = ARRAY_SIZE(carl9170_2ghz_chantable),
+ .bitrates = carl9170_g_ratetable,
+ .n_bitrates = carl9170_g_ratetable_size,
+ .ht_cap = CARL9170_HT_CAP,
+};
+
+static struct ieee80211_supported_band carl9170_band_5GHz = {
+ .channels = carl9170_5ghz_chantable,
+ .n_channels = ARRAY_SIZE(carl9170_5ghz_chantable),
+ .bitrates = carl9170_a_ratetable,
+ .n_bitrates = carl9170_a_ratetable_size,
+ .ht_cap = CARL9170_HT_CAP,
+};
+
+static void carl9170_ampdu_gc(struct ar9170 *ar)
+{
+ struct carl9170_sta_tid *tid_info;
+ LIST_HEAD(tid_gc);
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(tid_info, &ar->tx_ampdu_list, list) {
+ spin_lock_bh(&ar->tx_ampdu_list_lock);
+ if (tid_info->state == CARL9170_TID_STATE_SHUTDOWN) {
+ tid_info->state = CARL9170_TID_STATE_KILLED;
+ list_del_rcu(&tid_info->list);
+ ar->tx_ampdu_list_len--;
+ list_add_tail(&tid_info->tmp_list, &tid_gc);
+ }
+ spin_unlock_bh(&ar->tx_ampdu_list_lock);
+
+ }
+ rcu_assign_pointer(ar->tx_ampdu_iter, tid_info);
+ rcu_read_unlock();
+
+ synchronize_rcu();
+
+ while (!list_empty(&tid_gc)) {
+ struct sk_buff *skb;
+ tid_info = list_first_entry(&tid_gc, struct carl9170_sta_tid,
+ tmp_list);
+
+ while ((skb = __skb_dequeue(&tid_info->queue)))
+ carl9170_tx_status(ar, skb, false);
+
+ list_del_init(&tid_info->tmp_list);
+ kfree(tid_info);
+ }
+}
+
+static void carl9170_flush(struct ar9170 *ar, bool drop_queued)
+{
+ if (drop_queued) {
+ int i;
+
+ /*
+ * We can only drop frames which have not been uploaded
+ * to the device yet.
+ */
+
+ for (i = 0; i < ar->hw->queues; i++) {
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&ar->tx_pending[i]))) {
+ struct ieee80211_tx_info *info;
+
+ info = IEEE80211_SKB_CB(skb);
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
+ atomic_dec(&ar->tx_ampdu_upload);
+
+ carl9170_tx_status(ar, skb, false);
+ }
+ }
+ }
+
+ /* Wait for all other outstanding frames to timeout. */
+ if (atomic_read(&ar->tx_total_queued))
+ WARN_ON(wait_for_completion_timeout(&ar->tx_flush, HZ) == 0);
+}
+
+static void carl9170_flush_ba(struct ar9170 *ar)
+{
+ struct sk_buff_head free;
+ struct carl9170_sta_tid *tid_info;
+ struct sk_buff *skb;
+
+ __skb_queue_head_init(&free);
+
+ rcu_read_lock();
+ spin_lock_bh(&ar->tx_ampdu_list_lock);
+ list_for_each_entry_rcu(tid_info, &ar->tx_ampdu_list, list) {
+ if (tid_info->state > CARL9170_TID_STATE_SUSPEND) {
+ tid_info->state = CARL9170_TID_STATE_SUSPEND;
+
+ spin_lock(&tid_info->lock);
+ while ((skb = __skb_dequeue(&tid_info->queue)))
+ __skb_queue_tail(&free, skb);
+ spin_unlock(&tid_info->lock);
+ }
+ }
+ spin_unlock_bh(&ar->tx_ampdu_list_lock);
+ rcu_read_unlock();
+
+ while ((skb = __skb_dequeue(&free)))
+ carl9170_tx_status(ar, skb, false);
+}
+
+static void carl9170_zap_queues(struct ar9170 *ar)
+{
+ struct carl9170_vif_info *cvif;
+ unsigned int i;
+
+ carl9170_ampdu_gc(ar);
+
+ carl9170_flush_ba(ar);
+ carl9170_flush(ar, true);
+
+ for (i = 0; i < ar->hw->queues; i++) {
+ spin_lock_bh(&ar->tx_status[i].lock);
+ while (!skb_queue_empty(&ar->tx_status[i])) {
+ struct sk_buff *skb;
+
+ skb = skb_peek(&ar->tx_status[i]);
+ carl9170_tx_get_skb(skb);
+ spin_unlock_bh(&ar->tx_status[i].lock);
+ carl9170_tx_drop(ar, skb);
+ spin_lock_bh(&ar->tx_status[i].lock);
+ carl9170_tx_put_skb(skb);
+ }
+ spin_unlock_bh(&ar->tx_status[i].lock);
+ }
+
+ BUILD_BUG_ON(CARL9170_NUM_TX_LIMIT_SOFT < 1);
+ BUILD_BUG_ON(CARL9170_NUM_TX_LIMIT_HARD < CARL9170_NUM_TX_LIMIT_SOFT);
+ BUILD_BUG_ON(CARL9170_NUM_TX_LIMIT_HARD >= CARL9170_BAW_BITS);
+
+ /* reinitialize queues statistics */
+ memset(&ar->tx_stats, 0, sizeof(ar->tx_stats));
+ for (i = 0; i < ar->hw->queues; i++)
+ ar->tx_stats[i].limit = CARL9170_NUM_TX_LIMIT_HARD;
+
+ for (i = 0; i < DIV_ROUND_UP(ar->fw.mem_blocks, BITS_PER_LONG); i++)
+ ar->mem_bitmap[i] = 0;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(cvif, &ar->vif_list, list) {
+ spin_lock_bh(&ar->beacon_lock);
+ dev_kfree_skb_any(cvif->beacon);
+ cvif->beacon = NULL;
+ spin_unlock_bh(&ar->beacon_lock);
+ }
+ rcu_read_unlock();
+
+ atomic_set(&ar->tx_ampdu_upload, 0);
+ atomic_set(&ar->tx_ampdu_scheduler, 0);
+ atomic_set(&ar->tx_total_pending, 0);
+ atomic_set(&ar->tx_total_queued, 0);
+ atomic_set(&ar->mem_free_blocks, ar->fw.mem_blocks);
+}
+
+#define CARL9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \
+do { \
+ queue.aifs = ai_fs; \
+ queue.cw_min = cwmin; \
+ queue.cw_max = cwmax; \
+ queue.txop = _txop; \
+} while (0)
+
+static int carl9170_op_start(struct ieee80211_hw *hw)
+{
+ struct ar9170 *ar = hw->priv;
+ int err, i;
+
+ mutex_lock(&ar->mutex);
+
+ carl9170_zap_queues(ar);
+
+ /* reset QoS defaults */
+ CARL9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023, 0); /* BEST EFFORT */
+ CARL9170_FILL_QUEUE(ar->edcf[1], 2, 7, 15, 94); /* VIDEO */
+ CARL9170_FILL_QUEUE(ar->edcf[2], 2, 3, 7, 47); /* VOICE */
+ CARL9170_FILL_QUEUE(ar->edcf[3], 7, 15, 1023, 0); /* BACKGROUND */
+ CARL9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */
+
+ ar->current_factor = ar->current_density = -1;
+ /* "The first key is unique." */
+ ar->usedkeys = 1;
+ ar->filter_state = 0;
+ ar->ps.last_action = jiffies;
+ ar->ps.last_slept = jiffies;
+ ar->erp_mode = CARL9170_ERP_AUTO;
+ ar->rx_software_decryption = false;
+ ar->disable_offload = false;
+
+ for (i = 0; i < ar->hw->queues; i++) {
+ ar->queue_stop_timeout[i] = jiffies;
+ ar->max_queue_stop_timeout[i] = 0;
+ }
+
+ atomic_set(&ar->mem_allocs, 0);
+
+ err = carl9170_usb_open(ar);
+ if (err)
+ goto out;
+
+ err = carl9170_init_mac(ar);
+ if (err)
+ goto out;
+
+ err = carl9170_set_qos(ar);
+ if (err)
+ goto out;
+
+ if (ar->fw.rx_filter) {
+ err = carl9170_rx_filter(ar, CARL9170_RX_FILTER_OTHER_RA |
+ CARL9170_RX_FILTER_CTL_OTHER | CARL9170_RX_FILTER_BAD);
+ if (err)
+ goto out;
+ }
+
+ err = carl9170_write_reg(ar, AR9170_MAC_REG_DMA_TRIGGER,
+ AR9170_DMA_TRIGGER_RXQ);
+ if (err)
+ goto out;
+
+ /* Clear key-cache */
+ for (i = 0; i < AR9170_CAM_MAX_USER + 4; i++) {
+ err = carl9170_upload_key(ar, i, NULL, AR9170_ENC_ALG_NONE,
+ 0, NULL, 0);
+ if (err)
+ goto out;
+
+ err = carl9170_upload_key(ar, i, NULL, AR9170_ENC_ALG_NONE,
+ 1, NULL, 0);
+ if (err)
+ goto out;
+
+ if (i < AR9170_CAM_MAX_USER) {
+ err = carl9170_disable_key(ar, i);
+ if (err)
+ goto out;
+ }
+ }
+
+ carl9170_set_state_when(ar, CARL9170_IDLE, CARL9170_STARTED);
+
+ ieee80211_wake_queues(ar->hw);
+ err = 0;
+
+out:
+ mutex_unlock(&ar->mutex);
+ return err;
+}
+
+static void carl9170_cancel_worker(struct ar9170 *ar)
+{
+ cancel_delayed_work_sync(&ar->tx_janitor);
+#ifdef CONFIG_CARL9170_LEDS
+ cancel_delayed_work_sync(&ar->led_work);
+#endif /* CONFIG_CARL9170_LEDS */
+ cancel_work_sync(&ar->ps_work);
+ cancel_work_sync(&ar->ampdu_work);
+}
+
+static void carl9170_op_stop(struct ieee80211_hw *hw)
+{
+ struct ar9170 *ar = hw->priv;
+
+ carl9170_set_state_when(ar, CARL9170_STARTED, CARL9170_IDLE);
+
+ ieee80211_stop_queues(ar->hw);
+
+ mutex_lock(&ar->mutex);
+ if (IS_ACCEPTING_CMD(ar)) {
+ rcu_assign_pointer(ar->beacon_iter, NULL);
+
+ carl9170_led_set_state(ar, 0);
+
+ /* stop DMA */
+ carl9170_write_reg(ar, AR9170_MAC_REG_DMA_TRIGGER, 0);
+ carl9170_usb_stop(ar);
+ }
+
+ carl9170_zap_queues(ar);
+ mutex_unlock(&ar->mutex);
+
+ carl9170_cancel_worker(ar);
+}
+
+static void carl9170_restart_work(struct work_struct *work)
+{
+ struct ar9170 *ar = container_of(work, struct ar9170,
+ restart_work);
+ int err;
+
+ ar->usedkeys = 0;
+ ar->filter_state = 0;
+ carl9170_cancel_worker(ar);
+
+ mutex_lock(&ar->mutex);
+ err = carl9170_usb_restart(ar);
+ if (net_ratelimit()) {
+ if (err) {
+ dev_err(&ar->udev->dev, "Failed to restart device "
+ " (%d).\n", err);
+ } else {
+ dev_info(&ar->udev->dev, "device restarted "
+ "successfully.\n");
+ }
+ }
+
+ carl9170_zap_queues(ar);
+ mutex_unlock(&ar->mutex);
+ if (!err) {
+ ar->restart_counter++;
+ atomic_set(&ar->pending_restarts, 0);
+
+ ieee80211_restart_hw(ar->hw);
+ } else {
+ /*
+ * The reset was unsuccessful and the device seems to
+ * be dead. But there's still one option: a low-level
+ * usb subsystem reset...
+ */
+
+ carl9170_usb_reset(ar);
+ }
+}
+
+void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r)
+{
+ carl9170_set_state_when(ar, CARL9170_STARTED, CARL9170_IDLE);
+
+ /*
+ * Sometimes, an error can trigger several different reset events.
+ * By ignoring these *surplus* reset events, the device won't be
+ * killed again, right after it has recovered.
+ */
+ if (atomic_inc_return(&ar->pending_restarts) > 1) {
+ dev_dbg(&ar->udev->dev, "ignoring restart (%d)\n", r);
+ return;
+ }
+
+ ieee80211_stop_queues(ar->hw);
+
+ dev_err(&ar->udev->dev, "restart device (%d)\n", r);
+
+ if (!WARN_ON(r == CARL9170_RR_NO_REASON) ||
+ !WARN_ON(r >= __CARL9170_RR_LAST))
+ ar->last_reason = r;
+
+ if (!ar->registered)
+ return;
+
+ if (IS_ACCEPTING_CMD(ar) && !ar->needs_full_reset)
+ ieee80211_queue_work(ar->hw, &ar->restart_work);
+ else
+ carl9170_usb_reset(ar);
+
+ /*
+ * At this point, the device instance might have vanished/disabled.
+ * So, don't put any code which access the ar9170 struct
+ * without proper protection.
+ */
+}
+
+static int carl9170_init_interface(struct ar9170 *ar,
+ struct ieee80211_vif *vif)
+{
+ struct ath_common *common = &ar->common;
+ int err;
+
+ if (!vif) {
+ WARN_ON_ONCE(IS_STARTED(ar));
+ return 0;
+ }
+
+ memcpy(common->macaddr, vif->addr, ETH_ALEN);
+
+ if (modparam_nohwcrypt ||
+ ((vif->type != NL80211_IFTYPE_STATION) &&
+ (vif->type != NL80211_IFTYPE_AP))) {
+ ar->rx_software_decryption = true;
+ ar->disable_offload = true;
+ }
+
+ err = carl9170_set_operating_mode(ar);
+ return err;
+}
+
+static int carl9170_op_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct carl9170_vif_info *vif_priv = (void *) vif->drv_priv;
+ struct ieee80211_vif *main_vif;
+ struct ar9170 *ar = hw->priv;
+ int vif_id = -1, err = 0;
+
+ mutex_lock(&ar->mutex);
+ rcu_read_lock();
+ if (vif_priv->active) {
+ /*
+ * Skip the interface structure initialization,
+ * if the vif survived the _restart call.
+ */
+ vif_id = vif_priv->id;
+ vif_priv->enable_beacon = false;
+
+ spin_lock_bh(&ar->beacon_lock);
+ dev_kfree_skb_any(vif_priv->beacon);
+ vif_priv->beacon = NULL;
+ spin_unlock_bh(&ar->beacon_lock);
+
+ goto init;
+ }
+
+ main_vif = carl9170_get_main_vif(ar);
+
+ if (main_vif) {
+ switch (main_vif->type) {
+ case NL80211_IFTYPE_STATION:
+ if (vif->type == NL80211_IFTYPE_STATION)
+ break;
+
+ err = -EBUSY;
+ rcu_read_unlock();
+
+ goto unlock;
+
+ case NL80211_IFTYPE_AP:
+ if ((vif->type == NL80211_IFTYPE_STATION) ||
+ (vif->type == NL80211_IFTYPE_WDS) ||
+ (vif->type == NL80211_IFTYPE_AP))
+ break;
+
+ err = -EBUSY;
+ rcu_read_unlock();
+ goto unlock;
+
+ default:
+ rcu_read_unlock();
+ goto unlock;
+ }
+ }
+
+ vif_id = bitmap_find_free_region(&ar->vif_bitmap, ar->fw.vif_num, 0);
+
+ if (vif_id < 0) {
+ rcu_read_unlock();
+
+ err = -ENOSPC;
+ goto unlock;
+ }
+
+ BUG_ON(ar->vif_priv[vif_id].id != vif_id);
+
+ vif_priv->active = true;
+ vif_priv->id = vif_id;
+ vif_priv->enable_beacon = false;
+ ar->vifs++;
+ list_add_tail_rcu(&vif_priv->list, &ar->vif_list);
+ rcu_assign_pointer(ar->vif_priv[vif_id].vif, vif);
+
+init:
+ if (carl9170_get_main_vif(ar) == vif) {
+ rcu_assign_pointer(ar->beacon_iter, vif_priv);
+ rcu_read_unlock();
+
+ err = carl9170_init_interface(ar, vif);
+ if (err)
+ goto unlock;
+ } else {
+ rcu_read_unlock();
+ err = carl9170_mod_virtual_mac(ar, vif_id, vif->addr);
+
+ if (err)
+ goto unlock;
+ }
+
+unlock:
+ if (err && (vif_id != -1)) {
+ vif_priv->active = false;
+ bitmap_release_region(&ar->vif_bitmap, vif_id, 0);
+ ar->vifs--;
+ rcu_assign_pointer(ar->vif_priv[vif_id].vif, NULL);
+ list_del_rcu(&vif_priv->list);
+ mutex_unlock(&ar->mutex);
+ synchronize_rcu();
+ } else {
+ if (ar->vifs > 1)
+ ar->ps.off_override |= PS_OFF_VIF;
+
+ mutex_unlock(&ar->mutex);
+ }
+
+ return err;
+}
+
+static void carl9170_op_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct carl9170_vif_info *vif_priv = (void *) vif->drv_priv;
+ struct ieee80211_vif *main_vif;
+ struct ar9170 *ar = hw->priv;
+ unsigned int id;
+
+ mutex_lock(&ar->mutex);
+
+ if (WARN_ON_ONCE(!vif_priv->active))
+ goto unlock;
+
+ ar->vifs--;
+
+ rcu_read_lock();
+ main_vif = carl9170_get_main_vif(ar);
+
+ id = vif_priv->id;
+
+ vif_priv->active = false;
+ WARN_ON(vif_priv->enable_beacon);
+ vif_priv->enable_beacon = false;
+ list_del_rcu(&vif_priv->list);
+ rcu_assign_pointer(ar->vif_priv[id].vif, NULL);
+
+ if (vif == main_vif) {
+ rcu_read_unlock();
+
+ if (ar->vifs) {
+ WARN_ON(carl9170_init_interface(ar,
+ carl9170_get_main_vif(ar)));
+ } else {
+ carl9170_set_operating_mode(ar);
+ }
+ } else {
+ rcu_read_unlock();
+
+ WARN_ON(carl9170_mod_virtual_mac(ar, id, NULL));
+ }
+
+ carl9170_update_beacon(ar, false);
+ carl9170_flush_cab(ar, id);
+
+ spin_lock_bh(&ar->beacon_lock);
+ dev_kfree_skb_any(vif_priv->beacon);
+ vif_priv->beacon = NULL;
+ spin_unlock_bh(&ar->beacon_lock);
+
+ bitmap_release_region(&ar->vif_bitmap, id, 0);
+
+ carl9170_set_beacon_timers(ar);
+
+ if (ar->vifs == 1)
+ ar->ps.off_override &= ~PS_OFF_VIF;
+
+unlock:
+ mutex_unlock(&ar->mutex);
+
+ synchronize_rcu();
+}
+
+void carl9170_ps_check(struct ar9170 *ar)
+{
+ ieee80211_queue_work(ar->hw, &ar->ps_work);
+}
+
+/* caller must hold ar->mutex */
+static int carl9170_ps_update(struct ar9170 *ar)
+{
+ bool ps = false;
+ int err = 0;
+
+ if (!ar->ps.off_override)
+ ps = (ar->hw->conf.flags & IEEE80211_CONF_PS);
+
+ if (ps != ar->ps.state) {
+ err = carl9170_powersave(ar, ps);
+ if (err)
+ return err;
+
+ if (ar->ps.state && !ps) {
+ ar->ps.sleep_ms = jiffies_to_msecs(jiffies -
+ ar->ps.last_action);
+ }
+
+ if (ps)
+ ar->ps.last_slept = jiffies;
+
+ ar->ps.last_action = jiffies;
+ ar->ps.state = ps;
+ }
+
+ return 0;
+}
+
+static void carl9170_ps_work(struct work_struct *work)
+{
+ struct ar9170 *ar = container_of(work, struct ar9170,
+ ps_work);
+ mutex_lock(&ar->mutex);
+ if (IS_STARTED(ar))
+ WARN_ON_ONCE(carl9170_ps_update(ar) != 0);
+ mutex_unlock(&ar->mutex);
+}
+
+
+static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed)
+{
+ struct ar9170 *ar = hw->priv;
+ int err = 0;
+
+ mutex_lock(&ar->mutex);
+ if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
+ /* TODO */
+ err = 0;
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_PS) {
+ err = carl9170_ps_update(ar);
+ if (err)
+ goto out;
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_POWER) {
+ /* TODO */
+ err = 0;
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_SMPS) {
+ /* TODO */
+ err = 0;
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ /* adjust slot time for 5 GHz */
+ err = carl9170_set_slot_time(ar);
+ 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_set_dyn_sifs_ack(ar);
+ if (err)
+ goto out;
+
+ err = carl9170_set_rts_cts_rate(ar);
+ if (err)
+ goto out;
+ }
+
+out:
+ mutex_unlock(&ar->mutex);
+ return err;
+}
+
+static u64 carl9170_op_prepare_multicast(struct ieee80211_hw *hw,
+ struct netdev_hw_addr_list *mc_list)
+{
+ struct netdev_hw_addr *ha;
+ u64 mchash;
+
+ /* always get broadcast frames */
+ mchash = 1ULL << (0xff >> 2);
+
+ netdev_hw_addr_list_for_each(ha, mc_list)
+ mchash |= 1ULL << (ha->addr[5] >> 2);
+
+ return mchash;
+}
+
+static void carl9170_op_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *new_flags,
+ u64 multicast)
+{
+ struct ar9170 *ar = hw->priv;
+
+ /* mask supported flags */
+ *new_flags &= FIF_ALLMULTI | ar->rx_filter_caps;
+
+ if (!IS_ACCEPTING_CMD(ar))
+ return;
+
+ mutex_lock(&ar->mutex);
+
+ ar->filter_state = *new_flags;
+ /*
+ * We can support more by setting the sniffer bit and
+ * then checking the error flags, later.
+ */
+
+ if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI)
+ multicast = ~0ULL;
+
+ if (multicast != ar->cur_mc_hash)
+ WARN_ON(carl9170_update_multicast(ar, multicast));
+
+ if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
+ ar->sniffer_enabled = !!(*new_flags &
+ (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS));
+
+ WARN_ON(carl9170_set_operating_mode(ar));
+ }
+
+ if (ar->fw.rx_filter && changed_flags & ar->rx_filter_caps) {
+ u32 rx_filter = 0;
+
+ if (!(*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL)))
+ rx_filter |= CARL9170_RX_FILTER_BAD;
+
+ if (!(*new_flags & FIF_CONTROL))
+ rx_filter |= CARL9170_RX_FILTER_CTL_OTHER;
+
+ if (!(*new_flags & FIF_PSPOLL))
+ rx_filter |= CARL9170_RX_FILTER_CTL_PSPOLL;
+
+ if (!(*new_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))) {
+ rx_filter |= CARL9170_RX_FILTER_OTHER_RA;
+ rx_filter |= CARL9170_RX_FILTER_DECRY_FAIL;
+ }
+
+ WARN_ON(carl9170_rx_filter(ar, rx_filter));
+ }
+
+ mutex_unlock(&ar->mutex);
+}
+
+
+static void carl9170_op_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changed)
+{
+ struct ar9170 *ar = hw->priv;
+ struct ath_common *common = &ar->common;
+ int err = 0;
+ struct carl9170_vif_info *vif_priv;
+ struct ieee80211_vif *main_vif;
+
+ mutex_lock(&ar->mutex);
+ vif_priv = (void *) vif->drv_priv;
+ main_vif = carl9170_get_main_vif(ar);
+ if (WARN_ON(!main_vif))
+ goto out;
+
+ if (changed & BSS_CHANGED_BEACON_ENABLED) {
+ struct carl9170_vif_info *iter;
+ int i = 0;
+
+ vif_priv->enable_beacon = bss_conf->enable_beacon;
+ rcu_read_lock();
+ list_for_each_entry_rcu(iter, &ar->vif_list, list) {
+ if (iter->active && iter->enable_beacon)
+ i++;
+
+ }
+ rcu_read_unlock();
+
+ ar->beacon_enabled = i;
+ }
+
+ if (changed & BSS_CHANGED_BEACON) {
+ err = carl9170_update_beacon(ar, false);
+ if (err)
+ goto out;
+ }
+
+ if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON |
+ BSS_CHANGED_BEACON_INT)) {
+
+ if (main_vif != vif) {
+ bss_conf->beacon_int = main_vif->bss_conf.beacon_int;
+ bss_conf->dtim_period = main_vif->bss_conf.dtim_period;
+ }
+
+ /*
+ * Therefore a hard limit for the broadcast traffic should
+ * prevent false alarms.
+ */
+ if (vif->type != NL80211_IFTYPE_STATION &&
+ (bss_conf->beacon_int * bss_conf->dtim_period >=
+ (CARL9170_QUEUE_STUCK_TIMEOUT / 2))) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = carl9170_set_beacon_timers(ar);
+ if (err)
+ goto out;
+ }
+
+ if (changed & BSS_CHANGED_HT) {
+ /* TODO */
+ err = 0;
+ if (err)
+ goto out;
+ }
+
+ if (main_vif != vif)
+ goto out;
+
+ /*
+ * The following settings can only be changed by the
+ * master interface.
+ */
+
+ if (changed & BSS_CHANGED_BSSID) {
+ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+ err = carl9170_set_operating_mode(ar);
+ if (err)
+ goto out;
+ }
+
+ if (changed & BSS_CHANGED_ASSOC) {
+ ar->common.curaid = bss_conf->aid;
+ err = carl9170_set_beacon_timers(ar);
+ if (err)
+ goto out;
+ }
+
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ err = carl9170_set_slot_time(ar);
+ if (err)
+ goto out;
+ }
+
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ err = carl9170_set_mac_rates(ar);
+ if (err)
+ goto out;
+ }
+
+out:
+ WARN_ON_ONCE(err && IS_STARTED(ar));
+ mutex_unlock(&ar->mutex);
+}
+
+static u64 carl9170_op_get_tsf(struct ieee80211_hw *hw)
+{
+ struct ar9170 *ar = hw->priv;
+ struct carl9170_tsf_rsp tsf;
+ int err;
+
+ mutex_lock(&ar->mutex);
+ err = carl9170_exec_cmd(ar, CARL9170_CMD_READ_TSF,
+ 0, NULL, sizeof(tsf), &tsf);
+ mutex_unlock(&ar->mutex);
+ if (WARN_ON(err))
+ return 0;
+
+ return le64_to_cpu(tsf.tsf_64);
+}
+
+static int carl9170_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct ar9170 *ar = hw->priv;
+ int err = 0, i;
+ u8 ktype;
+
+ if (ar->disable_offload || !vif)
+ return -EOPNOTSUPP;
+
+ /*
+ * We have to fall back to software encryption, whenever
+ * the user choose to participates in an IBSS or is connected
+ * to more than one network.
+ *
+ * This is very unfortunate, because some machines cannot handle
+ * the high througput speed in 802.11n networks.
+ */
+
+ if (!is_main_vif(ar, vif))
+ goto err_softw;
+
+ /*
+ * While the hardware supports *catch-all* key, for offloading
+ * group-key en-/de-cryption. The way of how the hardware
+ * decides which keyId maps to which key, remains a mystery...
+ */
+ if ((vif->type != NL80211_IFTYPE_STATION &&
+ vif->type != NL80211_IFTYPE_ADHOC) &&
+ !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+ return -EOPNOTSUPP;
+
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ ktype = AR9170_ENC_ALG_WEP64;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ ktype = AR9170_ENC_ALG_WEP128;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ ktype = AR9170_ENC_ALG_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ ktype = AR9170_ENC_ALG_AESCCMP;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ mutex_lock(&ar->mutex);
+ if (cmd == SET_KEY) {
+ if (!IS_STARTED(ar)) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+ sta = NULL;
+
+ i = 64 + key->keyidx;
+ } else {
+ for (i = 0; i < 64; i++)
+ if (!(ar->usedkeys & BIT(i)))
+ break;
+ if (i == 64)
+ goto err_softw;
+ }
+
+ key->hw_key_idx = i;
+
+ err = carl9170_upload_key(ar, i, sta ? sta->addr : NULL,
+ ktype, 0, key->key,
+ min_t(u8, 16, key->keylen));
+ if (err)
+ goto out;
+
+ if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
+ err = carl9170_upload_key(ar, i, sta ? sta->addr :
+ NULL, ktype, 1,
+ key->key + 16, 16);
+ if (err)
+ goto out;
+
+ /*
+ * hardware is not capable generating MMIC
+ * of fragmented frames!
+ */
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ }
+
+ if (i < 64)
+ ar->usedkeys |= BIT(i);
+
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ } else {
+ if (!IS_STARTED(ar)) {
+ /* The device is gone... together with the key ;-) */
+ err = 0;
+ goto out;
+ }
+
+ if (key->hw_key_idx < 64) {
+ ar->usedkeys &= ~BIT(key->hw_key_idx);
+ } else {
+ err = carl9170_upload_key(ar, key->hw_key_idx, NULL,
+ AR9170_ENC_ALG_NONE, 0,
+ NULL, 0);
+ if (err)
+ goto out;
+
+ if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
+ err = carl9170_upload_key(ar, key->hw_key_idx,
+ NULL,
+ AR9170_ENC_ALG_NONE,
+ 1, NULL, 0);
+ if (err)
+ goto out;
+ }
+
+ }
+
+ err = carl9170_disable_key(ar, key->hw_key_idx);
+ if (err)
+ goto out;
+ }
+
+out:
+ mutex_unlock(&ar->mutex);
+ return err;
+
+err_softw:
+ if (!ar->rx_software_decryption) {
+ ar->rx_software_decryption = true;
+ carl9170_set_operating_mode(ar);
+ }
+ mutex_unlock(&ar->mutex);
+ return -ENOSPC;
+}
+
+static int carl9170_op_sta_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
+ unsigned int i;
+
+ if (sta->ht_cap.ht_supported) {
+ if (sta->ht_cap.ampdu_density > 6) {
+ /*
+ * HW does support 16us AMPDU density.
+ * No HT-Xmit for station.
+ */
+
+ return 0;
+ }
+
+ for (i = 0; i < CARL9170_NUM_TID; i++)
+ rcu_assign_pointer(sta_info->agg[i], NULL);
+
+ sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
+ sta_info->ht_sta = true;
+ }
+
+ return 0;
+}
+
+static int carl9170_op_sta_remove(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct ar9170 *ar = hw->priv;
+ struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
+ unsigned int i;
+ bool cleanup = false;
+
+ if (sta->ht_cap.ht_supported) {
+
+ sta_info->ht_sta = false;
+
+ rcu_read_lock();
+ for (i = 0; i < CARL9170_NUM_TID; i++) {
+ struct carl9170_sta_tid *tid_info;
+
+ tid_info = rcu_dereference(sta_info->agg[i]);
+ rcu_assign_pointer(sta_info->agg[i], NULL);
+
+ if (!tid_info)
+ continue;
+
+ spin_lock_bh(&ar->tx_ampdu_list_lock);
+ if (tid_info->state > CARL9170_TID_STATE_SHUTDOWN)
+ tid_info->state = CARL9170_TID_STATE_SHUTDOWN;
+ spin_unlock_bh(&ar->tx_ampdu_list_lock);
+ cleanup = true;
+ }
+ rcu_read_unlock();
+
+ if (cleanup)
+ carl9170_ampdu_gc(ar);
+ }
+
+ return 0;
+}
+
+static int carl9170_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
+ const struct ieee80211_tx_queue_params *param)
+{
+ struct ar9170 *ar = hw->priv;
+ int ret;
+
+ mutex_lock(&ar->mutex);
+ if (queue < ar->hw->queues) {
+ memcpy(&ar->edcf[ar9170_qmap[queue]], param, sizeof(*param));
+ ret = carl9170_set_qos(ar);
+ } else {
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&ar->mutex);
+ return ret;
+}
+
+static void carl9170_ampdu_work(struct work_struct *work)
+{
+ struct ar9170 *ar = container_of(work, struct ar9170,
+ ampdu_work);
+
+ if (!IS_STARTED(ar))
+ return;
+
+ mutex_lock(&ar->mutex);
+ carl9170_ampdu_gc(ar);
+ mutex_unlock(&ar->mutex);
+}
+
+static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta,
+ u16 tid, u16 *ssn)
+{
+ struct ar9170 *ar = hw->priv;
+ struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
+ struct carl9170_sta_tid *tid_info;
+
+ if (modparam_noht)
+ return -EOPNOTSUPP;
+
+ switch (action) {
+ case IEEE80211_AMPDU_TX_START:
+ if (!sta_info->ht_sta)
+ return -EOPNOTSUPP;
+
+ rcu_read_lock();
+ if (rcu_dereference(sta_info->agg[tid])) {
+ rcu_read_unlock();
+ return -EBUSY;
+ }
+
+ tid_info = kzalloc(sizeof(struct carl9170_sta_tid),
+ GFP_ATOMIC);
+ if (!tid_info) {
+ rcu_read_unlock();
+ return -ENOMEM;
+ }
+
+ tid_info->hsn = tid_info->bsn = tid_info->snx = (*ssn);
+ tid_info->state = CARL9170_TID_STATE_PROGRESS;
+ tid_info->tid = tid;
+ tid_info->max = sta_info->ampdu_max_len;
+
+ INIT_LIST_HEAD(&tid_info->list);
+ INIT_LIST_HEAD(&tid_info->tmp_list);
+ skb_queue_head_init(&tid_info->queue);
+ spin_lock_init(&tid_info->lock);
+
+ spin_lock_bh(&ar->tx_ampdu_list_lock);
+ ar->tx_ampdu_list_len++;
+ list_add_tail_rcu(&tid_info->list, &ar->tx_ampdu_list);
+ rcu_assign_pointer(sta_info->agg[tid], tid_info);
+ spin_unlock_bh(&ar->tx_ampdu_list_lock);
+ rcu_read_unlock();
+
+ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+
+ case IEEE80211_AMPDU_TX_STOP:
+ rcu_read_lock();
+ tid_info = rcu_dereference(sta_info->agg[tid]);
+ if (tid_info) {
+ spin_lock_bh(&ar->tx_ampdu_list_lock);
+ if (tid_info->state > CARL9170_TID_STATE_SHUTDOWN)
+ tid_info->state = CARL9170_TID_STATE_SHUTDOWN;
+ spin_unlock_bh(&ar->tx_ampdu_list_lock);
+ }
+
+ rcu_assign_pointer(sta_info->agg[tid], NULL);
+ rcu_read_unlock();
+
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ ieee80211_queue_work(ar->hw, &ar->ampdu_work);
+ break;
+
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+ rcu_read_lock();
+ tid_info = rcu_dereference(sta_info->agg[tid]);
+
+ sta_info->stats[tid].clear = true;
+
+ if (tid_info) {
+ bitmap_zero(tid_info->bitmap, CARL9170_BAW_SIZE);
+ tid_info->state = CARL9170_TID_STATE_IDLE;
+ }
+ rcu_read_unlock();
+
+ if (WARN_ON_ONCE(!tid_info))
+ return -EFAULT;
+
+ break;
+
+ case IEEE80211_AMPDU_RX_START:
+ case IEEE80211_AMPDU_RX_STOP:
+ /* Handled by hardware */
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_CARL9170_WPC
+static int carl9170_register_wps_button(struct ar9170 *ar)
+{
+ struct input_dev *input;
+ int err;
+
+ if (!(ar->features & CARL9170_WPS_BUTTON))
+ return 0;
+
+ input = input_allocate_device();
+ if (!input)
+ return -ENOMEM;
+
+ snprintf(ar->wps.name, sizeof(ar->wps.name), "%s WPS Button",
+ wiphy_name(ar->hw->wiphy));
+
+ snprintf(ar->wps.phys, sizeof(ar->wps.phys),
+ "ieee80211/%s/input0", wiphy_name(ar->hw->wiphy));
+
+ input->name = ar->wps.name;
+ input->phys = ar->wps.phys;
+ input->id.bustype = BUS_USB;
+ input->dev.parent = &ar->hw->wiphy->dev;
+
+ input_set_capability(input, EV_KEY, KEY_WPS_BUTTON);
+
+ err = input_register_device(input);
+ if (err) {
+ input_free_device(input);
+ return err;
+ }
+
+ ar->wps.pbc = input;
+ return 0;
+}
+#endif /* CONFIG_CARL9170_WPC */
+
+static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey)
+{
+ struct ar9170 *ar = hw->priv;
+ int err;
+
+ if (idx != 0)
+ return -ENOENT;
+
+ mutex_lock(&ar->mutex);
+ err = carl9170_get_noisefloor(ar);
+ mutex_unlock(&ar->mutex);
+ if (err)
+ return err;
+
+ survey->channel = ar->channel;
+ survey->filled = SURVEY_INFO_NOISE_DBM;
+ survey->noise = ar->noise[0];
+ return 0;
+}
+
+static void carl9170_op_flush(struct ieee80211_hw *hw, bool drop)
+{
+ struct ar9170 *ar = hw->priv;
+ unsigned int vid;
+
+ mutex_lock(&ar->mutex);
+ for_each_set_bit(vid, &ar->vif_bitmap, ar->fw.vif_num)
+ carl9170_flush_cab(ar, vid);
+
+ carl9170_flush(ar, drop);
+ mutex_unlock(&ar->mutex);
+}
+
+static int carl9170_op_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct ar9170 *ar = hw->priv;
+
+ memset(stats, 0, sizeof(*stats));
+ stats->dot11ACKFailureCount = ar->tx_ack_failures;
+ stats->dot11FCSErrorCount = ar->tx_fcs_errors;
+ return 0;
+}
+
+static void carl9170_op_sta_notify(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum sta_notify_cmd cmd,
+ struct ieee80211_sta *sta)
+{
+ struct ar9170 *ar = hw->priv;
+ struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
+ struct sk_buff *skb, *tmp;
+ struct sk_buff_head free;
+ int i;
+
+ switch (cmd) {
+ case STA_NOTIFY_SLEEP:
+ /*
+ * Since the peer is no longer listening, we have to return
+ * as many SKBs as possible back to the mac80211 stack.
+ * It will deal with the retry procedure, once the peer
+ * has become available again.
+ *
+ * NB: Ideally, the driver should return the all frames in
+ * the correct, ascending order. However, I think that this
+ * functionality should be implemented in the stack and not
+ * here...
+ */
+
+ __skb_queue_head_init(&free);
+
+ if (sta->ht_cap.ht_supported) {
+ rcu_read_lock();
+ for (i = 0; i < CARL9170_NUM_TID; i++) {
+ struct carl9170_sta_tid *tid_info;
+
+ tid_info = rcu_dereference(sta_info->agg[i]);
+
+ if (!tid_info)
+ continue;
+
+ spin_lock_bh(&ar->tx_ampdu_list_lock);
+ if (tid_info->state >
+ CARL9170_TID_STATE_SUSPEND)
+ tid_info->state =
+ CARL9170_TID_STATE_SUSPEND;
+ spin_unlock_bh(&ar->tx_ampdu_list_lock);
+
+ spin_lock_bh(&tid_info->lock);
+ while ((skb = __skb_dequeue(&tid_info->queue)))
+ __skb_queue_tail(&free, skb);
+ spin_unlock_bh(&tid_info->lock);
+ }
+ rcu_read_unlock();
+ }
+
+ for (i = 0; i < ar->hw->queues; i++) {
+ spin_lock_bh(&ar->tx_pending[i].lock);
+ skb_queue_walk_safe(&ar->tx_pending[i], skb, tmp) {
+ struct _carl9170_tx_superframe *super;
+ struct ieee80211_hdr *hdr;
+ struct ieee80211_tx_info *info;
+
+ super = (void *) skb->data;
+ hdr = (void *) super->frame_data;
+
+ if (compare_ether_addr(hdr->addr1, sta->addr))
+ continue;
+
+ __skb_unlink(skb, &ar->tx_pending[i]);
+
+ info = IEEE80211_SKB_CB(skb);
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
+ atomic_dec(&ar->tx_ampdu_upload);
+
+ carl9170_tx_status(ar, skb, false);
+ }
+ spin_unlock_bh(&ar->tx_pending[i].lock);
+ }
+
+ while ((skb = __skb_dequeue(&free)))
+ carl9170_tx_status(ar, skb, false);
+
+ break;
+
+ case STA_NOTIFY_AWAKE:
+ if (!sta->ht_cap.ht_supported)
+ return;
+
+ rcu_read_lock();
+ for (i = 0; i < CARL9170_NUM_TID; i++) {
+ struct carl9170_sta_tid *tid_info;
+
+ tid_info = rcu_dereference(sta_info->agg[i]);
+
+ if (!tid_info)
+ continue;
+
+ if ((tid_info->state == CARL9170_TID_STATE_SUSPEND))
+ tid_info->state = CARL9170_TID_STATE_IDLE;
+ }
+ rcu_read_unlock();
+ break;
+ }
+}
+
+static const struct ieee80211_ops carl9170_ops = {
+ .start = carl9170_op_start,
+ .stop = carl9170_op_stop,
+ .tx = carl9170_op_tx,
+ .flush = carl9170_op_flush,
+ .add_interface = carl9170_op_add_interface,
+ .remove_interface = carl9170_op_remove_interface,
+ .config = carl9170_op_config,
+ .prepare_multicast = carl9170_op_prepare_multicast,
+ .configure_filter = carl9170_op_configure_filter,
+ .conf_tx = carl9170_op_conf_tx,
+ .bss_info_changed = carl9170_op_bss_info_changed,
+ .get_tsf = carl9170_op_get_tsf,
+ .set_key = carl9170_op_set_key,
+ .sta_add = carl9170_op_sta_add,
+ .sta_remove = carl9170_op_sta_remove,
+ .sta_notify = carl9170_op_sta_notify,
+ .get_survey = carl9170_op_get_survey,
+ .get_stats = carl9170_op_get_stats,
+ .ampdu_action = carl9170_op_ampdu_action,
+};
+
+void *carl9170_alloc(size_t priv_size)
+{
+ struct ieee80211_hw *hw;
+ struct ar9170 *ar;
+ struct sk_buff *skb;
+ int i;
+
+ /*
+ * this buffer is used for rx stream reconstruction.
+ * Under heavy load this device (or the transport layer?)
+ * tends to split the streams into separate rx descriptors.
+ */
+
+ skb = __dev_alloc_skb(AR9170_RX_STREAM_MAX_SIZE, GFP_KERNEL);
+ if (!skb)
+ goto err_nomem;
+
+ hw = ieee80211_alloc_hw(priv_size, &carl9170_ops);
+ if (!hw)
+ goto err_nomem;
+
+ ar = hw->priv;
+ ar->hw = hw;
+ ar->rx_failover = skb;
+
+ memset(&ar->rx_plcp, 0, sizeof(struct ar9170_rx_head));
+ ar->rx_has_plcp = false;
+
+ /*
+ * Here's a hidden pitfall!
+ *
+ * All 4 AC queues work perfectly well under _legacy_ operation.
+ * However as soon as aggregation is enabled, the traffic flow
+ * gets very bumpy. Therefore we have to _switch_ to a
+ * software AC with a single HW queue.
+ */
+ hw->queues = __AR9170_NUM_TXQ;
+
+ mutex_init(&ar->mutex);
+ spin_lock_init(&ar->beacon_lock);
+ spin_lock_init(&ar->cmd_lock);
+ spin_lock_init(&ar->tx_stats_lock);
+ spin_lock_init(&ar->tx_ampdu_list_lock);
+ spin_lock_init(&ar->mem_lock);
+ spin_lock_init(&ar->state_lock);
+ atomic_set(&ar->pending_restarts, 0);
+ ar->vifs = 0;
+ for (i = 0; i < ar->hw->queues; i++) {
+ skb_queue_head_init(&ar->tx_status[i]);
+ skb_queue_head_init(&ar->tx_pending[i]);
+ }
+ INIT_WORK(&ar->ps_work, carl9170_ps_work);
+ INIT_WORK(&ar->restart_work, carl9170_restart_work);
+ INIT_WORK(&ar->ampdu_work, carl9170_ampdu_work);
+ INIT_DELAYED_WORK(&ar->tx_janitor, carl9170_tx_janitor);
+ INIT_LIST_HEAD(&ar->tx_ampdu_list);
+ rcu_assign_pointer(ar->tx_ampdu_iter,
+ (struct carl9170_sta_tid *) &ar->tx_ampdu_list);
+
+ bitmap_zero(&ar->vif_bitmap, ar->fw.vif_num);
+ INIT_LIST_HEAD(&ar->vif_list);
+ init_completion(&ar->tx_flush);
+
+ /*
+ * Note:
+ * IBSS/ADHOC and AP mode are only enabled, if the firmware
+ * supports these modes. The code which will add the
+ * additional interface_modes is in fw.c.
+ */
+ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
+ hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_REPORTS_TX_ACK_STATUS |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK |
+ IEEE80211_HW_SIGNAL_DBM;
+
+ if (!modparam_noht) {
+ /*
+ * see the comment above, why we allow the user
+ * to disable HT by a module parameter.
+ */
+ hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+ }
+
+ hw->extra_tx_headroom = sizeof(struct _carl9170_tx_superframe);
+ hw->sta_data_size = sizeof(struct carl9170_sta_info);
+ hw->vif_data_size = sizeof(struct carl9170_vif_info);
+
+ hw->max_rates = CARL9170_TX_MAX_RATES;
+ hw->max_rate_tries = CARL9170_TX_USER_RATE_TRIES;
+
+ for (i = 0; i < ARRAY_SIZE(ar->noise); i++)
+ ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */
+
+ hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+ return ar;
+
+err_nomem:
+ kfree_skb(skb);
+ return ERR_PTR(-ENOMEM);
+}
+
+static int carl9170_read_eeprom(struct ar9170 *ar)
+{
+#define RW 8 /* number of words to read at once */
+#define RB (sizeof(u32) * RW)
+ u8 *eeprom = (void *)&ar->eeprom;
+ __le32 offsets[RW];
+ int i, j, err;
+
+ BUILD_BUG_ON(sizeof(ar->eeprom) & 3);
+
+ BUILD_BUG_ON(RB > CARL9170_MAX_CMD_LEN - 4);
+#ifndef __CHECKER__
+ /* don't want to handle trailing remains */
+ BUILD_BUG_ON(sizeof(ar->eeprom) % RB);
+#endif
+
+ for (i = 0; i < sizeof(ar->eeprom)/RB; i++) {
+ for (j = 0; j < RW; j++)
+ offsets[j] = cpu_to_le32(AR9170_EEPROM_START +
+ RB * i + 4 * j);
+
+ err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG,
+ RB, (u8 *) &offsets,
+ RB, eeprom + RB * i);
+ if (err)
+ return err;
+ }
+
+#undef RW
+#undef RB
+ return 0;
+}
+
+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;
+
+ if (ar->eeprom.length == cpu_to_le16(0xffff))
+ return -ENODATA;
+
+ rx_streams = hweight8(ar->eeprom.rx_mask);
+ tx_streams = hweight8(ar->eeprom.tx_mask);
+
+ if (rx_streams != tx_streams) {
+ tx_params = IEEE80211_HT_MCS_TX_RX_DIFF;
+
+ WARN_ON(!(tx_streams >= 1 && tx_streams <=
+ IEEE80211_HT_MCS_TX_MAX_STREAMS));
+
+ tx_params = (tx_streams - 1) <<
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+
+ carl9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params;
+ carl9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params;
+ }
+
+ if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) {
+ ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &carl9170_band_2GHz;
+ bands++;
+ }
+ if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) {
+ ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &carl9170_band_5GHz;
+ bands++;
+ }
+
+ /*
+ * I measured this, a bandswitch takes roughly
+ * 135 ms and a frequency switch about 80.
+ *
+ * FIXME: measure these values again once EEPROM settings
+ * are used, that will influence them!
+ */
+ if (bands == 2)
+ ar->hw->channel_change_time = 135 * 1000;
+ else
+ 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;
+}
+
+static int carl9170_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct ar9170 *ar = hw->priv;
+
+ return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory);
+}
+
+int carl9170_register(struct ar9170 *ar)
+{
+ struct ath_regulatory *regulatory = &ar->common.regulatory;
+ int err = 0, i;
+
+ if (WARN_ON(ar->mem_bitmap))
+ return -EINVAL;
+
+ ar->mem_bitmap = kzalloc(roundup(ar->fw.mem_blocks, BITS_PER_LONG) *
+ sizeof(unsigned long), GFP_KERNEL);
+
+ if (!ar->mem_bitmap)
+ return -ENOMEM;
+
+ /* try to read EEPROM, init MAC addr */
+ err = carl9170_read_eeprom(ar);
+ if (err)
+ return err;
+
+ err = carl9170_fw_fix_eeprom(ar);
+ if (err)
+ return err;
+
+ err = carl9170_parse_eeprom(ar);
+ if (err)
+ return err;
+
+ err = ath_regd_init(regulatory, ar->hw->wiphy,
+ carl9170_reg_notifier);
+ if (err)
+ return err;
+
+ if (modparam_noht) {
+ carl9170_band_2GHz.ht_cap.ht_supported = false;
+ carl9170_band_5GHz.ht_cap.ht_supported = false;
+ }
+
+ for (i = 0; i < ar->fw.vif_num; i++) {
+ ar->vif_priv[i].id = i;
+ ar->vif_priv[i].vif = NULL;
+ }
+
+ err = ieee80211_register_hw(ar->hw);
+ if (err)
+ return err;
+
+ /* mac80211 interface is now registered */
+ ar->registered = true;
+
+ if (!ath_is_world_regd(regulatory))
+ regulatory_hint(ar->hw->wiphy, regulatory->alpha2);
+
+#ifdef CONFIG_CARL9170_DEBUGFS
+ carl9170_debugfs_register(ar);
+#endif /* CONFIG_CARL9170_DEBUGFS */
+
+ err = carl9170_led_init(ar);
+ if (err)
+ goto err_unreg;
+
+#ifdef CONFIG_CARL9170_LEDS
+ err = carl9170_led_register(ar);
+ if (err)
+ goto err_unreg;
+#endif /* CONFIG_CAR9L170_LEDS */
+
+#ifdef CONFIG_CARL9170_WPC
+ err = carl9170_register_wps_button(ar);
+ if (err)
+ goto err_unreg;
+#endif /* CONFIG_CARL9170_WPC */
+
+ dev_info(&ar->udev->dev, "Atheros AR9170 is registered as '%s'\n",
+ wiphy_name(ar->hw->wiphy));
+
+ return 0;
+
+err_unreg:
+ carl9170_unregister(ar);
+ return err;
+}
+
+void carl9170_unregister(struct ar9170 *ar)
+{
+ if (!ar->registered)
+ return;
+
+ ar->registered = false;
+
+#ifdef CONFIG_CARL9170_LEDS
+ carl9170_led_unregister(ar);
+#endif /* CONFIG_CARL9170_LEDS */
+
+#ifdef CONFIG_CARL9170_DEBUGFS
+ carl9170_debugfs_unregister(ar);
+#endif /* CONFIG_CARL9170_DEBUGFS */
+
+#ifdef CONFIG_CARL9170_WPC
+ if (ar->wps.pbc) {
+ input_unregister_device(ar->wps.pbc);
+ ar->wps.pbc = NULL;
+ }
+#endif /* CONFIG_CARL9170_WPC */
+
+ carl9170_cancel_worker(ar);
+ cancel_work_sync(&ar->restart_work);
+
+ ieee80211_unregister_hw(ar->hw);
+}
+
+void carl9170_free(struct ar9170 *ar)
+{
+ WARN_ON(ar->registered);
+ WARN_ON(IS_INITIALIZED(ar));
+
+ kfree_skb(ar->rx_failover);
+ ar->rx_failover = NULL;
+
+ kfree(ar->mem_bitmap);
+ ar->mem_bitmap = 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
new file mode 100644
index 000000000000..89deca37a988
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/phy.c
@@ -0,0 +1,1810 @@
+/*
+ * Atheros CARL9170 driver
+ *
+ * PHY and RF code
+ *
+ * Copyright 2008, 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 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, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2007-2008 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/bitrev.h>
+#include "carl9170.h"
+#include "cmd.h"
+#include "phy.h"
+
+static int carl9170_init_power_cal(struct ar9170 *ar)
+{
+ carl9170_regwrite_begin(ar);
+
+ carl9170_regwrite(AR9170_PHY_REG_POWER_TX_RATE_MAX, 0x7f);
+ carl9170_regwrite(AR9170_PHY_REG_POWER_TX_RATE1, 0x3f3f3f3f);
+ carl9170_regwrite(AR9170_PHY_REG_POWER_TX_RATE2, 0x3f3f3f3f);
+ carl9170_regwrite(AR9170_PHY_REG_POWER_TX_RATE3, 0x3f3f3f3f);
+ carl9170_regwrite(AR9170_PHY_REG_POWER_TX_RATE4, 0x3f3f3f3f);
+ carl9170_regwrite(AR9170_PHY_REG_POWER_TX_RATE5, 0x3f3f3f3f);
+ carl9170_regwrite(AR9170_PHY_REG_POWER_TX_RATE6, 0x3f3f3f3f);
+ carl9170_regwrite(AR9170_PHY_REG_POWER_TX_RATE7, 0x3f3f3f3f);
+ carl9170_regwrite(AR9170_PHY_REG_POWER_TX_RATE8, 0x3f3f3f3f);
+ carl9170_regwrite(AR9170_PHY_REG_POWER_TX_RATE9, 0x3f3f3f3f);
+
+ carl9170_regwrite_finish();
+ return carl9170_regwrite_result();
+}
+
+struct carl9170_phy_init {
+ u32 reg, _5ghz_20, _5ghz_40, _2ghz_40, _2ghz_20;
+};
+
+static struct carl9170_phy_init ar5416_phy_init[] = {
+ { 0x1c5800, 0x00000007, 0x00000007, 0x00000007, 0x00000007, },
+ { 0x1c5804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, },
+ { 0x1c5808, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c580c, 0xad848e19, 0xad848e19, 0xad848e19, 0xad848e19, },
+ { 0x1c5810, 0x7d14e000, 0x7d14e000, 0x7d14e000, 0x7d14e000, },
+ { 0x1c5814, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, },
+ { 0x1c5818, 0x00000090, 0x00000090, 0x00000090, 0x00000090, },
+ { 0x1c581c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, },
+ { 0x1c5824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, },
+ { 0x1c5828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, },
+ { 0x1c582c, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, },
+ { 0x1c5830, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, },
+ { 0x1c5838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, },
+ { 0x1c583c, 0x00200400, 0x00200400, 0x00200400, 0x00200400, },
+ { 0x1c5840, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e, },
+ { 0x1c5844, 0x1372161e, 0x13721c1e, 0x13721c24, 0x137216a4, },
+ { 0x1c5848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, },
+ { 0x1c584c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, },
+ { 0x1c5850, 0x6c48b4e4, 0x6d48b4e4, 0x6d48b0e4, 0x6c48b0e4, },
+ { 0x1c5854, 0x00000859, 0x00000859, 0x00000859, 0x00000859, },
+ { 0x1c5858, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, },
+ { 0x1c585c, 0x31395c5e, 0x3139605e, 0x3139605e, 0x31395c5e, },
+ { 0x1c5860, 0x0004dd10, 0x0004dd10, 0x0004dd20, 0x0004dd20, },
+ { 0x1c5864, 0x0001c600, 0x0001c600, 0x0001c600, 0x0001c600, },
+ { 0x1c5868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, },
+ { 0x1c586c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, },
+ { 0x1c5900, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5904, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5908, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c590c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, },
+ { 0x1c5918, 0x00000118, 0x00000230, 0x00000268, 0x00000134, },
+ { 0x1c591c, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff, },
+ { 0x1c5920, 0x0510081c, 0x0510081c, 0x0510001c, 0x0510001c, },
+ { 0x1c5924, 0xd0058a15, 0xd0058a15, 0xd0058a15, 0xd0058a15, },
+ { 0x1c5928, 0x00000001, 0x00000001, 0x00000001, 0x00000001, },
+ { 0x1c592c, 0x00000004, 0x00000004, 0x00000004, 0x00000004, },
+ { 0x1c5934, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
+ { 0x1c5938, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
+ { 0x1c593c, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, },
+ { 0x1c5944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, },
+ { 0x1c5948, 0x9280b212, 0x9280b212, 0x9280b212, 0x9280b212, },
+ { 0x1c594c, 0x00020028, 0x00020028, 0x00020028, 0x00020028, },
+ { 0x1c5954, 0x5d50e188, 0x5d50e188, 0x5d50e188, 0x5d50e188, },
+ { 0x1c5958, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, },
+ { 0x1c5960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, },
+ { 0x1c5964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, },
+ { 0x1c5970, 0x190fb515, 0x190fb515, 0x190fb515, 0x190fb515, },
+ { 0x1c5974, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5978, 0x00000001, 0x00000001, 0x00000001, 0x00000001, },
+ { 0x1c597c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5980, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5984, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5988, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c598c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5990, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5994, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5998, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c599c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c59a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c59a4, 0x00000007, 0x00000007, 0x00000007, 0x00000007, },
+ { 0x1c59a8, 0x001fff00, 0x001fff00, 0x001fff00, 0x001fff00, },
+ { 0x1c59ac, 0x006f00c4, 0x006f00c4, 0x006f00c4, 0x006f00c4, },
+ { 0x1c59b0, 0x03051000, 0x03051000, 0x03051000, 0x03051000, },
+ { 0x1c59b4, 0x00000820, 0x00000820, 0x00000820, 0x00000820, },
+ { 0x1c59bc, 0x00181400, 0x00181400, 0x00181400, 0x00181400, },
+ { 0x1c59c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, },
+ { 0x1c59c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, },
+ { 0x1c59c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c, },
+ { 0x1c59cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, },
+ { 0x1c59d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, },
+ { 0x1c59d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c59d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c59dc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c59e0, 0x00000200, 0x00000200, 0x00000200, 0x00000200, },
+ { 0x1c59e4, 0x64646464, 0x64646464, 0x64646464, 0x64646464, },
+ { 0x1c59e8, 0x3c787878, 0x3c787878, 0x3c787878, 0x3c787878, },
+ { 0x1c59ec, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, },
+ { 0x1c59f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c59fc, 0x00001042, 0x00001042, 0x00001042, 0x00001042, },
+ { 0x1c5a00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5a04, 0x00000040, 0x00000040, 0x00000040, 0x00000040, },
+ { 0x1c5a08, 0x00000080, 0x00000080, 0x00000080, 0x00000080, },
+ { 0x1c5a0c, 0x000001a1, 0x000001a1, 0x00000141, 0x00000141, },
+ { 0x1c5a10, 0x000001e1, 0x000001e1, 0x00000181, 0x00000181, },
+ { 0x1c5a14, 0x00000021, 0x00000021, 0x000001c1, 0x000001c1, },
+ { 0x1c5a18, 0x00000061, 0x00000061, 0x00000001, 0x00000001, },
+ { 0x1c5a1c, 0x00000168, 0x00000168, 0x00000041, 0x00000041, },
+ { 0x1c5a20, 0x000001a8, 0x000001a8, 0x000001a8, 0x000001a8, },
+ { 0x1c5a24, 0x000001e8, 0x000001e8, 0x000001e8, 0x000001e8, },
+ { 0x1c5a28, 0x00000028, 0x00000028, 0x00000028, 0x00000028, },
+ { 0x1c5a2c, 0x00000068, 0x00000068, 0x00000068, 0x00000068, },
+ { 0x1c5a30, 0x00000189, 0x00000189, 0x000000a8, 0x000000a8, },
+ { 0x1c5a34, 0x000001c9, 0x000001c9, 0x00000169, 0x00000169, },
+ { 0x1c5a38, 0x00000009, 0x00000009, 0x000001a9, 0x000001a9, },
+ { 0x1c5a3c, 0x00000049, 0x00000049, 0x000001e9, 0x000001e9, },
+ { 0x1c5a40, 0x00000089, 0x00000089, 0x00000029, 0x00000029, },
+ { 0x1c5a44, 0x00000170, 0x00000170, 0x00000069, 0x00000069, },
+ { 0x1c5a48, 0x000001b0, 0x000001b0, 0x00000190, 0x00000190, },
+ { 0x1c5a4c, 0x000001f0, 0x000001f0, 0x000001d0, 0x000001d0, },
+ { 0x1c5a50, 0x00000030, 0x00000030, 0x00000010, 0x00000010, },
+ { 0x1c5a54, 0x00000070, 0x00000070, 0x00000050, 0x00000050, },
+ { 0x1c5a58, 0x00000191, 0x00000191, 0x00000090, 0x00000090, },
+ { 0x1c5a5c, 0x000001d1, 0x000001d1, 0x00000151, 0x00000151, },
+ { 0x1c5a60, 0x00000011, 0x00000011, 0x00000191, 0x00000191, },
+ { 0x1c5a64, 0x00000051, 0x00000051, 0x000001d1, 0x000001d1, },
+ { 0x1c5a68, 0x00000091, 0x00000091, 0x00000011, 0x00000011, },
+ { 0x1c5a6c, 0x000001b8, 0x000001b8, 0x00000051, 0x00000051, },
+ { 0x1c5a70, 0x000001f8, 0x000001f8, 0x00000198, 0x00000198, },
+ { 0x1c5a74, 0x00000038, 0x00000038, 0x000001d8, 0x000001d8, },
+ { 0x1c5a78, 0x00000078, 0x00000078, 0x00000018, 0x00000018, },
+ { 0x1c5a7c, 0x00000199, 0x00000199, 0x00000058, 0x00000058, },
+ { 0x1c5a80, 0x000001d9, 0x000001d9, 0x00000098, 0x00000098, },
+ { 0x1c5a84, 0x00000019, 0x00000019, 0x00000159, 0x00000159, },
+ { 0x1c5a88, 0x00000059, 0x00000059, 0x00000199, 0x00000199, },
+ { 0x1c5a8c, 0x00000099, 0x00000099, 0x000001d9, 0x000001d9, },
+ { 0x1c5a90, 0x000000d9, 0x000000d9, 0x00000019, 0x00000019, },
+ { 0x1c5a94, 0x000000f9, 0x000000f9, 0x00000059, 0x00000059, },
+ { 0x1c5a98, 0x000000f9, 0x000000f9, 0x00000099, 0x00000099, },
+ { 0x1c5a9c, 0x000000f9, 0x000000f9, 0x000000d9, 0x000000d9, },
+ { 0x1c5aa0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5aa4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5aa8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5aac, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5ab0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5ab4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5ab8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5abc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5ac0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5ac4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5ac8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5acc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5ad0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5ad4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5ad8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5adc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5ae0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5ae4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5ae8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5aec, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5af0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5af4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5af8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5afc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
+ { 0x1c5b00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5b04, 0x00000001, 0x00000001, 0x00000001, 0x00000001, },
+ { 0x1c5b08, 0x00000002, 0x00000002, 0x00000002, 0x00000002, },
+ { 0x1c5b0c, 0x00000003, 0x00000003, 0x00000003, 0x00000003, },
+ { 0x1c5b10, 0x00000004, 0x00000004, 0x00000004, 0x00000004, },
+ { 0x1c5b14, 0x00000005, 0x00000005, 0x00000005, 0x00000005, },
+ { 0x1c5b18, 0x00000008, 0x00000008, 0x00000008, 0x00000008, },
+ { 0x1c5b1c, 0x00000009, 0x00000009, 0x00000009, 0x00000009, },
+ { 0x1c5b20, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, },
+ { 0x1c5b24, 0x0000000b, 0x0000000b, 0x0000000b, 0x0000000b, },
+ { 0x1c5b28, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, },
+ { 0x1c5b2c, 0x0000000d, 0x0000000d, 0x0000000d, 0x0000000d, },
+ { 0x1c5b30, 0x00000010, 0x00000010, 0x00000010, 0x00000010, },
+ { 0x1c5b34, 0x00000011, 0x00000011, 0x00000011, 0x00000011, },
+ { 0x1c5b38, 0x00000012, 0x00000012, 0x00000012, 0x00000012, },
+ { 0x1c5b3c, 0x00000013, 0x00000013, 0x00000013, 0x00000013, },
+ { 0x1c5b40, 0x00000014, 0x00000014, 0x00000014, 0x00000014, },
+ { 0x1c5b44, 0x00000015, 0x00000015, 0x00000015, 0x00000015, },
+ { 0x1c5b48, 0x00000018, 0x00000018, 0x00000018, 0x00000018, },
+ { 0x1c5b4c, 0x00000019, 0x00000019, 0x00000019, 0x00000019, },
+ { 0x1c5b50, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, },
+ { 0x1c5b54, 0x0000001b, 0x0000001b, 0x0000001b, 0x0000001b, },
+ { 0x1c5b58, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, },
+ { 0x1c5b5c, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, },
+ { 0x1c5b60, 0x00000020, 0x00000020, 0x00000020, 0x00000020, },
+ { 0x1c5b64, 0x00000021, 0x00000021, 0x00000021, 0x00000021, },
+ { 0x1c5b68, 0x00000022, 0x00000022, 0x00000022, 0x00000022, },
+ { 0x1c5b6c, 0x00000023, 0x00000023, 0x00000023, 0x00000023, },
+ { 0x1c5b70, 0x00000024, 0x00000024, 0x00000024, 0x00000024, },
+ { 0x1c5b74, 0x00000025, 0x00000025, 0x00000025, 0x00000025, },
+ { 0x1c5b78, 0x00000028, 0x00000028, 0x00000028, 0x00000028, },
+ { 0x1c5b7c, 0x00000029, 0x00000029, 0x00000029, 0x00000029, },
+ { 0x1c5b80, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a, },
+ { 0x1c5b84, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, },
+ { 0x1c5b88, 0x0000002c, 0x0000002c, 0x0000002c, 0x0000002c, },
+ { 0x1c5b8c, 0x0000002d, 0x0000002d, 0x0000002d, 0x0000002d, },
+ { 0x1c5b90, 0x00000030, 0x00000030, 0x00000030, 0x00000030, },
+ { 0x1c5b94, 0x00000031, 0x00000031, 0x00000031, 0x00000031, },
+ { 0x1c5b98, 0x00000032, 0x00000032, 0x00000032, 0x00000032, },
+ { 0x1c5b9c, 0x00000033, 0x00000033, 0x00000033, 0x00000033, },
+ { 0x1c5ba0, 0x00000034, 0x00000034, 0x00000034, 0x00000034, },
+ { 0x1c5ba4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5ba8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bac, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bb0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bb4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bb8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bbc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bc0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bc4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bc8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bcc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bd0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bd4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bd8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bdc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5be0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5be4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5be8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bec, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bf0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bf4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
+ { 0x1c5bf8, 0x00000010, 0x00000010, 0x00000010, 0x00000010, },
+ { 0x1c5bfc, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, },
+ { 0x1c5c00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5c0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5c14, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5c18, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5c1c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5c20, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5c24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5c28, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5c2c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5c30, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5c34, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5c38, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5c3c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5cf0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5cf4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5cf8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c5cfc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c6200, 0x00000008, 0x00000008, 0x0000000e, 0x0000000e, },
+ { 0x1c6204, 0x00000440, 0x00000440, 0x00000440, 0x00000440, },
+ { 0x1c6208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, },
+ { 0x1c620c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, },
+ { 0x1c6210, 0x40806333, 0x40806333, 0x40806333, 0x40806333, },
+ { 0x1c6214, 0x00106c10, 0x00106c10, 0x00106c10, 0x00106c10, },
+ { 0x1c6218, 0x009c4060, 0x009c4060, 0x009c4060, 0x009c4060, },
+ { 0x1c621c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, },
+ { 0x1c6220, 0x018830c6, 0x018830c6, 0x018830c6, 0x018830c6, },
+ { 0x1c6224, 0x00000400, 0x00000400, 0x00000400, 0x00000400, },
+ { 0x1c6228, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, },
+ { 0x1c622c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c6230, 0x00000108, 0x00000210, 0x00000210, 0x00000108, },
+ { 0x1c6234, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
+ { 0x1c6238, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
+ { 0x1c623c, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, },
+ { 0x1c6240, 0x38490a20, 0x38490a20, 0x38490a20, 0x38490a20, },
+ { 0x1c6244, 0x00007bb6, 0x00007bb6, 0x00007bb6, 0x00007bb6, },
+ { 0x1c6248, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, },
+ { 0x1c624c, 0x00000001, 0x00000001, 0x00000001, 0x00000001, },
+ { 0x1c6250, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, },
+ { 0x1c6254, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c6258, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, },
+ { 0x1c625c, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, },
+ { 0x1c6260, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, },
+ { 0x1c6264, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, },
+ { 0x1c6268, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c626c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, },
+ { 0x1c6274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, },
+ { 0x1c6278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, },
+ { 0x1c627c, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, },
+ { 0x1c6300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, },
+ { 0x1c6304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, },
+ { 0x1c6308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, },
+ { 0x1c630c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, },
+ { 0x1c6310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, },
+ { 0x1c6314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, },
+ { 0x1c6318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, },
+ { 0x1c631c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, },
+ { 0x1c6320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, },
+ { 0x1c6324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, },
+ { 0x1c6328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, },
+ { 0x1c632c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c6330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c6334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c6338, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c633c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c6340, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c6344, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c6348, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, },
+ { 0x1c634c, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, },
+ { 0x1c6350, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, },
+ { 0x1c6354, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, },
+ { 0x1c6358, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, },
+ { 0x1c6388, 0x08000000, 0x08000000, 0x08000000, 0x08000000, },
+ { 0x1c638c, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
+ { 0x1c6390, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
+ { 0x1c6394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, },
+ { 0x1c6398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, },
+ { 0x1c639c, 0x00000007, 0x00000007, 0x00000007, 0x00000007, },
+ { 0x1c63a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c63a4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c63a8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c63ac, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c63b0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c63b4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c63b8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c63bc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c63c0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c63c4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c63c8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c63cc, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
+ { 0x1c63d0, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
+ { 0x1c63d4, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
+ { 0x1c63d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
+ { 0x1c63dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, },
+ { 0x1c63e0, 0x000000c0, 0x000000c0, 0x000000c0, 0x000000c0, },
+ { 0x1c6848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, },
+ { 0x1c6920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, },
+ { 0x1c6960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, },
+ { 0x1c720c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, },
+ { 0x1c726c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, },
+ { 0x1c7848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, },
+ { 0x1c7920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, },
+ { 0x1c7960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, },
+ { 0x1c820c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, },
+ { 0x1c826c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, },
+/* { 0x1c8864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, }, */
+ { 0x1c8864, 0x0001c600, 0x0001c600, 0x0001c600, 0x0001c600, },
+ { 0x1c895c, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, },
+ { 0x1c8968, 0x000003ce, 0x000003ce, 0x000003ce, 0x000003ce, },
+ { 0x1c89bc, 0x00181400, 0x00181400, 0x00181400, 0x00181400, },
+ { 0x1c9270, 0x00820820, 0x00820820, 0x00820820, 0x00820820, },
+ { 0x1c935c, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, },
+ { 0x1c9360, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, },
+ { 0x1c9364, 0x17601685, 0x17601685, 0x17601685, 0x17601685, },
+ { 0x1c9368, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, },
+ { 0x1c936c, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, },
+ { 0x1c9370, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, },
+ { 0x1c9374, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, },
+ { 0x1c9378, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, },
+ { 0x1c937c, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, },
+ { 0x1c9380, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, },
+ { 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, }
+};
+
+/*
+ * look up a certain register in ar5416_phy_init[] and return the init. value
+ * for the band and bandwidth given. Return 0 if register address not found.
+ */
+static u32 carl9170_def_val(u32 reg, bool is_2ghz, bool is_40mhz)
+{
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) {
+ if (ar5416_phy_init[i].reg != reg)
+ continue;
+
+ if (is_2ghz) {
+ if (is_40mhz)
+ return ar5416_phy_init[i]._2ghz_40;
+ else
+ return ar5416_phy_init[i]._2ghz_20;
+ } else {
+ if (is_40mhz)
+ return ar5416_phy_init[i]._5ghz_40;
+ else
+ return ar5416_phy_init[i]._5ghz_20;
+ }
+ }
+ return 0;
+}
+
+/*
+ * initialize some phy regs from eeprom values in modal_header[]
+ * acc. to band and bandwith
+ */
+static int carl9170_init_phy_from_eeprom(struct ar9170 *ar,
+ bool is_2ghz, bool is_40mhz)
+{
+ static const u8 xpd2pd[16] = {
+ 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x6, 0x2,
+ 0x2, 0x3, 0x7, 0x2, 0xb, 0x2, 0x2, 0x2
+ };
+ /* pointer to the modal_header acc. to band */
+ struct ar9170_eeprom_modal *m = &ar->eeprom.modal_header[is_2ghz];
+ u32 val;
+
+ carl9170_regwrite_begin(ar);
+
+ /* ant common control (index 0) */
+ carl9170_regwrite(AR9170_PHY_REG_SWITCH_COM,
+ le32_to_cpu(m->antCtrlCommon));
+
+ /* ant control chain 0 (index 1) */
+ carl9170_regwrite(AR9170_PHY_REG_SWITCH_CHAIN_0,
+ le32_to_cpu(m->antCtrlChain[0]));
+
+ /* ant control chain 2 (index 2) */
+ carl9170_regwrite(AR9170_PHY_REG_SWITCH_CHAIN_2,
+ le32_to_cpu(m->antCtrlChain[1]));
+
+ /* SwSettle (index 3) */
+ if (!is_40mhz) {
+ val = carl9170_def_val(AR9170_PHY_REG_SETTLING,
+ is_2ghz, is_40mhz);
+ SET_VAL(AR9170_PHY_SETTLING_SWITCH, val, m->switchSettling);
+ carl9170_regwrite(AR9170_PHY_REG_SETTLING, val);
+ }
+
+ /* adcDesired, pdaDesired (index 4) */
+ val = carl9170_def_val(AR9170_PHY_REG_DESIRED_SZ, is_2ghz, is_40mhz);
+ SET_VAL(AR9170_PHY_DESIRED_SZ_PGA, val, m->pgaDesiredSize);
+ SET_VAL(AR9170_PHY_DESIRED_SZ_ADC, val, m->adcDesiredSize);
+ carl9170_regwrite(AR9170_PHY_REG_DESIRED_SZ, val);
+
+ /* TxEndToXpaOff, TxFrameToXpaOn (index 5) */
+ val = carl9170_def_val(AR9170_PHY_REG_RF_CTL4, is_2ghz, is_40mhz);
+ SET_VAL(AR9170_PHY_RF_CTL4_TX_END_XPAB_OFF, val, m->txEndToXpaOff);
+ SET_VAL(AR9170_PHY_RF_CTL4_TX_END_XPAA_OFF, val, m->txEndToXpaOff);
+ SET_VAL(AR9170_PHY_RF_CTL4_FRAME_XPAB_ON, val, m->txFrameToXpaOn);
+ SET_VAL(AR9170_PHY_RF_CTL4_FRAME_XPAA_ON, val, m->txFrameToXpaOn);
+ carl9170_regwrite(AR9170_PHY_REG_RF_CTL4, val);
+
+ /* TxEndToRxOn (index 6) */
+ val = carl9170_def_val(AR9170_PHY_REG_RF_CTL3, is_2ghz, is_40mhz);
+ SET_VAL(AR9170_PHY_RF_CTL3_TX_END_TO_A2_RX_ON, val, m->txEndToRxOn);
+ carl9170_regwrite(AR9170_PHY_REG_RF_CTL3, val);
+
+ /* thresh62 (index 7) */
+ val = carl9170_def_val(0x1c8864, is_2ghz, is_40mhz);
+ val = (val & ~0x7f000) | (m->thresh62 << 12);
+ carl9170_regwrite(0x1c8864, val);
+
+ /* tx/rx attenuation chain 0 (index 8) */
+ val = carl9170_def_val(AR9170_PHY_REG_RXGAIN, is_2ghz, is_40mhz);
+ SET_VAL(AR9170_PHY_RXGAIN_TXRX_ATTEN, val, m->txRxAttenCh[0]);
+ carl9170_regwrite(AR9170_PHY_REG_RXGAIN, val);
+
+ /* tx/rx attenuation chain 2 (index 9) */
+ val = carl9170_def_val(AR9170_PHY_REG_RXGAIN_CHAIN_2,
+ is_2ghz, is_40mhz);
+ SET_VAL(AR9170_PHY_RXGAIN_TXRX_ATTEN, val, m->txRxAttenCh[1]);
+ carl9170_regwrite(AR9170_PHY_REG_RXGAIN_CHAIN_2, val);
+
+ /* tx/rx margin chain 0 (index 10) */
+ val = carl9170_def_val(AR9170_PHY_REG_GAIN_2GHZ, is_2ghz, is_40mhz);
+ SET_VAL(AR9170_PHY_GAIN_2GHZ_RXTX_MARGIN, val, m->rxTxMarginCh[0]);
+ /* bsw margin chain 0 for 5GHz only */
+ if (!is_2ghz)
+ SET_VAL(AR9170_PHY_GAIN_2GHZ_BSW_MARGIN, val, m->bswMargin[0]);
+ carl9170_regwrite(AR9170_PHY_REG_GAIN_2GHZ, val);
+
+ /* tx/rx margin chain 2 (index 11) */
+ val = carl9170_def_val(AR9170_PHY_REG_GAIN_2GHZ_CHAIN_2,
+ is_2ghz, is_40mhz);
+ SET_VAL(AR9170_PHY_GAIN_2GHZ_RXTX_MARGIN, val, m->rxTxMarginCh[1]);
+ carl9170_regwrite(AR9170_PHY_REG_GAIN_2GHZ_CHAIN_2, val);
+
+ /* iqCall, iqCallq chain 0 (index 12) */
+ val = carl9170_def_val(AR9170_PHY_REG_TIMING_CTRL4(0),
+ is_2ghz, is_40mhz);
+ SET_VAL(AR9170_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, val, m->iqCalICh[0]);
+ SET_VAL(AR9170_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, val, m->iqCalQCh[0]);
+ carl9170_regwrite(AR9170_PHY_REG_TIMING_CTRL4(0), val);
+
+ /* iqCall, iqCallq chain 2 (index 13) */
+ val = carl9170_def_val(AR9170_PHY_REG_TIMING_CTRL4(2),
+ is_2ghz, is_40mhz);
+ SET_VAL(AR9170_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, val, m->iqCalICh[1]);
+ SET_VAL(AR9170_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, val, m->iqCalQCh[1]);
+ carl9170_regwrite(AR9170_PHY_REG_TIMING_CTRL4(2), val);
+
+ /* xpd gain mask (index 14) */
+ val = carl9170_def_val(AR9170_PHY_REG_TPCRG1, is_2ghz, is_40mhz);
+ SET_VAL(AR9170_PHY_TPCRG1_PD_GAIN_1, val,
+ xpd2pd[m->xpdGain & 0xf] & 3);
+ SET_VAL(AR9170_PHY_TPCRG1_PD_GAIN_2, val,
+ xpd2pd[m->xpdGain & 0xf] >> 2);
+ carl9170_regwrite(AR9170_PHY_REG_TPCRG1, val);
+
+ carl9170_regwrite(AR9170_PHY_REG_RX_CHAINMASK, ar->eeprom.rx_mask);
+ carl9170_regwrite(AR9170_PHY_REG_CAL_CHAINMASK, ar->eeprom.rx_mask);
+
+ carl9170_regwrite_finish();
+ return carl9170_regwrite_result();
+}
+
+static int carl9170_init_phy(struct ar9170 *ar, enum ieee80211_band band)
+{
+ int i, err;
+ u32 val;
+ bool is_2ghz = band == IEEE80211_BAND_2GHZ;
+ bool is_40mhz = conf_is_ht40(&ar->hw->conf);
+
+ carl9170_regwrite_begin(ar);
+
+ for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) {
+ if (is_40mhz) {
+ if (is_2ghz)
+ val = ar5416_phy_init[i]._2ghz_40;
+ else
+ val = ar5416_phy_init[i]._5ghz_40;
+ } else {
+ if (is_2ghz)
+ val = ar5416_phy_init[i]._2ghz_20;
+ else
+ val = ar5416_phy_init[i]._5ghz_20;
+ }
+
+ carl9170_regwrite(ar5416_phy_init[i].reg, val);
+ }
+
+ carl9170_regwrite_finish();
+ err = carl9170_regwrite_result();
+ if (err)
+ return err;
+
+ err = carl9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz);
+ if (err)
+ return err;
+
+ err = carl9170_init_power_cal(ar);
+ 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);
+
+ return err;
+}
+
+struct carl9170_rf_initvals {
+ u32 reg, _5ghz, _2ghz;
+};
+
+static struct carl9170_rf_initvals carl9170_rf_initval[] = {
+ /* bank 0 */
+ { 0x1c58b0, 0x1e5795e5, 0x1e5795e5},
+ { 0x1c58e0, 0x02008020, 0x02008020},
+ /* bank 1 */
+ { 0x1c58b0, 0x02108421, 0x02108421},
+ { 0x1c58ec, 0x00000008, 0x00000008},
+ /* bank 2 */
+ { 0x1c58b0, 0x0e73ff17, 0x0e73ff17},
+ { 0x1c58e0, 0x00000420, 0x00000420},
+ /* bank 3 */
+ { 0x1c58f0, 0x01400018, 0x01c00018},
+ /* bank 4 */
+ { 0x1c58b0, 0x000001a1, 0x000001a1},
+ { 0x1c58e8, 0x00000001, 0x00000001},
+ /* bank 5 */
+ { 0x1c58b0, 0x00000013, 0x00000013},
+ { 0x1c58e4, 0x00000002, 0x00000002},
+ /* bank 6 */
+ { 0x1c58b0, 0x00000000, 0x00000000},
+ { 0x1c58b0, 0x00000000, 0x00000000},
+ { 0x1c58b0, 0x00000000, 0x00000000},
+ { 0x1c58b0, 0x00000000, 0x00000000},
+ { 0x1c58b0, 0x00000000, 0x00000000},
+ { 0x1c58b0, 0x00004000, 0x00004000},
+ { 0x1c58b0, 0x00006c00, 0x00006c00},
+ { 0x1c58b0, 0x00002c00, 0x00002c00},
+ { 0x1c58b0, 0x00004800, 0x00004800},
+ { 0x1c58b0, 0x00004000, 0x00004000},
+ { 0x1c58b0, 0x00006000, 0x00006000},
+ { 0x1c58b0, 0x00001000, 0x00001000},
+ { 0x1c58b0, 0x00004000, 0x00004000},
+ { 0x1c58b0, 0x00007c00, 0x00007c00},
+ { 0x1c58b0, 0x00007c00, 0x00007c00},
+ { 0x1c58b0, 0x00007c00, 0x00007c00},
+ { 0x1c58b0, 0x00007c00, 0x00007c00},
+ { 0x1c58b0, 0x00007c00, 0x00007c00},
+ { 0x1c58b0, 0x00087c00, 0x00087c00},
+ { 0x1c58b0, 0x00007c00, 0x00007c00},
+ { 0x1c58b0, 0x00005400, 0x00005400},
+ { 0x1c58b0, 0x00000c00, 0x00000c00},
+ { 0x1c58b0, 0x00001800, 0x00001800},
+ { 0x1c58b0, 0x00007c00, 0x00007c00},
+ { 0x1c58b0, 0x00006c00, 0x00006c00},
+ { 0x1c58b0, 0x00006c00, 0x00006c00},
+ { 0x1c58b0, 0x00007c00, 0x00007c00},
+ { 0x1c58b0, 0x00002c00, 0x00002c00},
+ { 0x1c58b0, 0x00003c00, 0x00003c00},
+ { 0x1c58b0, 0x00003800, 0x00003800},
+ { 0x1c58b0, 0x00001c00, 0x00001c00},
+ { 0x1c58b0, 0x00000800, 0x00000800},
+ { 0x1c58b0, 0x00000408, 0x00000408},
+ { 0x1c58b0, 0x00004c15, 0x00004c15},
+ { 0x1c58b0, 0x00004188, 0x00004188},
+ { 0x1c58b0, 0x0000201e, 0x0000201e},
+ { 0x1c58b0, 0x00010408, 0x00010408},
+ { 0x1c58b0, 0x00000801, 0x00000801},
+ { 0x1c58b0, 0x00000c08, 0x00000c08},
+ { 0x1c58b0, 0x0000181e, 0x0000181e},
+ { 0x1c58b0, 0x00001016, 0x00001016},
+ { 0x1c58b0, 0x00002800, 0x00002800},
+ { 0x1c58b0, 0x00004010, 0x00004010},
+ { 0x1c58b0, 0x0000081c, 0x0000081c},
+ { 0x1c58b0, 0x00000115, 0x00000115},
+ { 0x1c58b0, 0x00000015, 0x00000015},
+ { 0x1c58b0, 0x00000066, 0x00000066},
+ { 0x1c58b0, 0x0000001c, 0x0000001c},
+ { 0x1c58b0, 0x00000000, 0x00000000},
+ { 0x1c58b0, 0x00000004, 0x00000004},
+ { 0x1c58b0, 0x00000015, 0x00000015},
+ { 0x1c58b0, 0x0000001f, 0x0000001f},
+ { 0x1c58e0, 0x00000000, 0x00000400},
+ /* bank 7 */
+ { 0x1c58b0, 0x000000a0, 0x000000a0},
+ { 0x1c58b0, 0x00000000, 0x00000000},
+ { 0x1c58b0, 0x00000040, 0x00000040},
+ { 0x1c58f0, 0x0000001c, 0x0000001c},
+};
+
+static int carl9170_init_rf_banks_0_7(struct ar9170 *ar, bool band5ghz)
+{
+ int err, i;
+
+ carl9170_regwrite_begin(ar);
+
+ for (i = 0; i < ARRAY_SIZE(carl9170_rf_initval); i++)
+ carl9170_regwrite(carl9170_rf_initval[i].reg,
+ band5ghz ? carl9170_rf_initval[i]._5ghz
+ : carl9170_rf_initval[i]._2ghz);
+
+ carl9170_regwrite_finish();
+ err = carl9170_regwrite_result();
+ if (err)
+ wiphy_err(ar->hw->wiphy, "rf init failed\n");
+
+ return err;
+}
+
+struct carl9170_phy_freq_params {
+ u8 coeff_exp;
+ u16 coeff_man;
+ u8 coeff_exp_shgi;
+ u16 coeff_man_shgi;
+};
+
+enum carl9170_bw {
+ CARL9170_BW_20,
+ CARL9170_BW_40_BELOW,
+ CARL9170_BW_40_ABOVE,
+
+ __CARL9170_NUM_BW,
+};
+
+struct carl9170_phy_freq_entry {
+ u16 freq;
+ struct carl9170_phy_freq_params params[__CARL9170_NUM_BW];
+};
+
+/* NB: must be in sync with channel tables in main! */
+static const struct carl9170_phy_freq_entry carl9170_phy_freq_params[] = {
+/*
+ * freq,
+ * 20MHz,
+ * 40MHz (below),
+ * 40Mhz (above),
+ */
+ { 2412, {
+ { 3, 21737, 3, 19563, },
+ { 3, 21827, 3, 19644, },
+ { 3, 21647, 3, 19482, },
+ } },
+ { 2417, {
+ { 3, 21692, 3, 19523, },
+ { 3, 21782, 3, 19604, },
+ { 3, 21602, 3, 19442, },
+ } },
+ { 2422, {
+ { 3, 21647, 3, 19482, },
+ { 3, 21737, 3, 19563, },
+ { 3, 21558, 3, 19402, },
+ } },
+ { 2427, {
+ { 3, 21602, 3, 19442, },
+ { 3, 21692, 3, 19523, },
+ { 3, 21514, 3, 19362, },
+ } },
+ { 2432, {
+ { 3, 21558, 3, 19402, },
+ { 3, 21647, 3, 19482, },
+ { 3, 21470, 3, 19323, },
+ } },
+ { 2437, {
+ { 3, 21514, 3, 19362, },
+ { 3, 21602, 3, 19442, },
+ { 3, 21426, 3, 19283, },
+ } },
+ { 2442, {
+ { 3, 21470, 3, 19323, },
+ { 3, 21558, 3, 19402, },
+ { 3, 21382, 3, 19244, },
+ } },
+ { 2447, {
+ { 3, 21426, 3, 19283, },
+ { 3, 21514, 3, 19362, },
+ { 3, 21339, 3, 19205, },
+ } },
+ { 2452, {
+ { 3, 21382, 3, 19244, },
+ { 3, 21470, 3, 19323, },
+ { 3, 21295, 3, 19166, },
+ } },
+ { 2457, {
+ { 3, 21339, 3, 19205, },
+ { 3, 21426, 3, 19283, },
+ { 3, 21252, 3, 19127, },
+ } },
+ { 2462, {
+ { 3, 21295, 3, 19166, },
+ { 3, 21382, 3, 19244, },
+ { 3, 21209, 3, 19088, },
+ } },
+ { 2467, {
+ { 3, 21252, 3, 19127, },
+ { 3, 21339, 3, 19205, },
+ { 3, 21166, 3, 19050, },
+ } },
+ { 2472, {
+ { 3, 21209, 3, 19088, },
+ { 3, 21295, 3, 19166, },
+ { 3, 21124, 3, 19011, },
+ } },
+ { 2484, {
+ { 3, 21107, 3, 18996, },
+ { 3, 21192, 3, 19073, },
+ { 3, 21022, 3, 18920, },
+ } },
+ { 4920, {
+ { 4, 21313, 4, 19181, },
+ { 4, 21356, 4, 19220, },
+ { 4, 21269, 4, 19142, },
+ } },
+ { 4940, {
+ { 4, 21226, 4, 19104, },
+ { 4, 21269, 4, 19142, },
+ { 4, 21183, 4, 19065, },
+ } },
+ { 4960, {
+ { 4, 21141, 4, 19027, },
+ { 4, 21183, 4, 19065, },
+ { 4, 21098, 4, 18988, },
+ } },
+ { 4980, {
+ { 4, 21056, 4, 18950, },
+ { 4, 21098, 4, 18988, },
+ { 4, 21014, 4, 18912, },
+ } },
+ { 5040, {
+ { 4, 20805, 4, 18725, },
+ { 4, 20846, 4, 18762, },
+ { 4, 20764, 4, 18687, },
+ } },
+ { 5060, {
+ { 4, 20723, 4, 18651, },
+ { 4, 20764, 4, 18687, },
+ { 4, 20682, 4, 18614, },
+ } },
+ { 5080, {
+ { 4, 20641, 4, 18577, },
+ { 4, 20682, 4, 18614, },
+ { 4, 20601, 4, 18541, },
+ } },
+ { 5180, {
+ { 4, 20243, 4, 18219, },
+ { 4, 20282, 4, 18254, },
+ { 4, 20204, 4, 18183, },
+ } },
+ { 5200, {
+ { 4, 20165, 4, 18148, },
+ { 4, 20204, 4, 18183, },
+ { 4, 20126, 4, 18114, },
+ } },
+ { 5220, {
+ { 4, 20088, 4, 18079, },
+ { 4, 20126, 4, 18114, },
+ { 4, 20049, 4, 18044, },
+ } },
+ { 5240, {
+ { 4, 20011, 4, 18010, },
+ { 4, 20049, 4, 18044, },
+ { 4, 19973, 4, 17976, },
+ } },
+ { 5260, {
+ { 4, 19935, 4, 17941, },
+ { 4, 19973, 4, 17976, },
+ { 4, 19897, 4, 17907, },
+ } },
+ { 5280, {
+ { 4, 19859, 4, 17873, },
+ { 4, 19897, 4, 17907, },
+ { 4, 19822, 4, 17840, },
+ } },
+ { 5300, {
+ { 4, 19784, 4, 17806, },
+ { 4, 19822, 4, 17840, },
+ { 4, 19747, 4, 17772, },
+ } },
+ { 5320, {
+ { 4, 19710, 4, 17739, },
+ { 4, 19747, 4, 17772, },
+ { 4, 19673, 4, 17706, },
+ } },
+ { 5500, {
+ { 4, 19065, 4, 17159, },
+ { 4, 19100, 4, 17190, },
+ { 4, 19030, 4, 17127, },
+ } },
+ { 5520, {
+ { 4, 18996, 4, 17096, },
+ { 4, 19030, 4, 17127, },
+ { 4, 18962, 4, 17065, },
+ } },
+ { 5540, {
+ { 4, 18927, 4, 17035, },
+ { 4, 18962, 4, 17065, },
+ { 4, 18893, 4, 17004, },
+ } },
+ { 5560, {
+ { 4, 18859, 4, 16973, },
+ { 4, 18893, 4, 17004, },
+ { 4, 18825, 4, 16943, },
+ } },
+ { 5580, {
+ { 4, 18792, 4, 16913, },
+ { 4, 18825, 4, 16943, },
+ { 4, 18758, 4, 16882, },
+ } },
+ { 5600, {
+ { 4, 18725, 4, 16852, },
+ { 4, 18758, 4, 16882, },
+ { 4, 18691, 4, 16822, },
+ } },
+ { 5620, {
+ { 4, 18658, 4, 16792, },
+ { 4, 18691, 4, 16822, },
+ { 4, 18625, 4, 16762, },
+ } },
+ { 5640, {
+ { 4, 18592, 4, 16733, },
+ { 4, 18625, 4, 16762, },
+ { 4, 18559, 4, 16703, },
+ } },
+ { 5660, {
+ { 4, 18526, 4, 16673, },
+ { 4, 18559, 4, 16703, },
+ { 4, 18493, 4, 16644, },
+ } },
+ { 5680, {
+ { 4, 18461, 4, 16615, },
+ { 4, 18493, 4, 16644, },
+ { 4, 18428, 4, 16586, },
+ } },
+ { 5700, {
+ { 4, 18396, 4, 16556, },
+ { 4, 18428, 4, 16586, },
+ { 4, 18364, 4, 16527, },
+ } },
+ { 5745, {
+ { 4, 18252, 4, 16427, },
+ { 4, 18284, 4, 16455, },
+ { 4, 18220, 4, 16398, },
+ } },
+ { 5765, {
+ { 4, 18189, 5, 32740, },
+ { 4, 18220, 4, 16398, },
+ { 4, 18157, 5, 32683, },
+ } },
+ { 5785, {
+ { 4, 18126, 5, 32626, },
+ { 4, 18157, 5, 32683, },
+ { 4, 18094, 5, 32570, },
+ } },
+ { 5805, {
+ { 4, 18063, 5, 32514, },
+ { 4, 18094, 5, 32570, },
+ { 4, 18032, 5, 32458, },
+ } },
+ { 5825, {
+ { 4, 18001, 5, 32402, },
+ { 4, 18032, 5, 32458, },
+ { 4, 17970, 5, 32347, },
+ } },
+ { 5170, {
+ { 4, 20282, 4, 18254, },
+ { 4, 20321, 4, 18289, },
+ { 4, 20243, 4, 18219, },
+ } },
+ { 5190, {
+ { 4, 20204, 4, 18183, },
+ { 4, 20243, 4, 18219, },
+ { 4, 20165, 4, 18148, },
+ } },
+ { 5210, {
+ { 4, 20126, 4, 18114, },
+ { 4, 20165, 4, 18148, },
+ { 4, 20088, 4, 18079, },
+ } },
+ { 5230, {
+ { 4, 20049, 4, 18044, },
+ { 4, 20088, 4, 18079, },
+ { 4, 20011, 4, 18010, },
+ } },
+};
+
+static int carl9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz,
+ u32 freq, enum carl9170_bw bw)
+{
+ int err;
+ u32 d0, d1, td0, td1, fd0, fd1;
+ u8 chansel;
+ u8 refsel0 = 1, refsel1 = 0;
+ u8 lf_synth = 0;
+
+ switch (bw) {
+ case CARL9170_BW_40_ABOVE:
+ freq += 10;
+ break;
+ case CARL9170_BW_40_BELOW:
+ freq -= 10;
+ break;
+ case CARL9170_BW_20:
+ break;
+ default:
+ BUG();
+ return -ENOSYS;
+ }
+
+ if (band5ghz) {
+ if (freq % 10) {
+ chansel = (freq - 4800) / 5;
+ } else {
+ chansel = ((freq - 4800) / 10) * 2;
+ refsel0 = 0;
+ refsel1 = 1;
+ }
+ chansel = byte_rev_table[chansel];
+ } else {
+ if (freq == 2484) {
+ chansel = 10 + (freq - 2274) / 5;
+ lf_synth = 1;
+ } else
+ chansel = 16 + (freq - 2272) / 5;
+ chansel *= 4;
+ chansel = byte_rev_table[chansel];
+ }
+
+ d1 = chansel;
+ d0 = 0x21 |
+ refsel0 << 3 |
+ refsel1 << 2 |
+ lf_synth << 1;
+ td0 = d0 & 0x1f;
+ td1 = d1 & 0x1f;
+ fd0 = td1 << 5 | td0;
+
+ td0 = (d0 >> 5) & 0x7;
+ td1 = (d1 >> 5) & 0x7;
+ fd1 = td1 << 5 | td0;
+
+ carl9170_regwrite_begin(ar);
+
+ carl9170_regwrite(0x1c58b0, fd0);
+ carl9170_regwrite(0x1c58e8, fd1);
+
+ carl9170_regwrite_finish();
+ err = carl9170_regwrite_result();
+ if (err)
+ return err;
+
+ msleep(20);
+
+ return 0;
+}
+
+static const struct carl9170_phy_freq_params *
+carl9170_get_hw_dyn_params(struct ieee80211_channel *channel,
+ enum carl9170_bw bw)
+{
+ unsigned int chanidx = 0;
+ u16 freq = 2412;
+
+ if (channel) {
+ chanidx = channel->hw_value;
+ freq = channel->center_freq;
+ }
+
+ BUG_ON(chanidx >= ARRAY_SIZE(carl9170_phy_freq_params));
+
+ BUILD_BUG_ON(__CARL9170_NUM_BW != 3);
+
+ WARN_ON(carl9170_phy_freq_params[chanidx].freq != freq);
+
+ return &carl9170_phy_freq_params[chanidx].params[bw];
+}
+
+static int carl9170_find_freq_idx(int nfreqs, u8 *freqs, u8 f)
+{
+ int idx = nfreqs - 2;
+
+ while (idx >= 0) {
+ if (f >= freqs[idx])
+ return idx;
+ idx--;
+ }
+
+ return 0;
+}
+
+static s32 carl9170_interpolate_s32(s32 x, s32 x1, s32 y1, s32 x2, s32 y2)
+{
+ /* nothing to interpolate, it's horizontal */
+ if (y2 == y1)
+ return y1;
+
+ /* check if we hit one of the edges */
+ if (x == x1)
+ return y1;
+ if (x == x2)
+ return y2;
+
+ /* x1 == x2 is bad, hopefully == x */
+ if (x2 == x1)
+ return y1;
+
+ return y1 + (((y2 - y1) * (x - x1)) / (x2 - x1));
+}
+
+static u8 carl9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2)
+{
+#define SHIFT 8
+ s32 y;
+
+ y = carl9170_interpolate_s32(x << SHIFT, x1 << SHIFT,
+ y1 << SHIFT, x2 << SHIFT, y2 << SHIFT);
+
+ /*
+ * XXX: unwrap this expression
+ * Isn't it just DIV_ROUND_UP(y, 1<<SHIFT)?
+ * Can we rely on the compiler to optimise away the div?
+ */
+ return (y >> SHIFT) + ((y & (1<<(SHIFT-1))) >> (SHIFT - 1));
+#undef SHIFT
+}
+
+static u8 carl9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (x <= x_array[i + 1])
+ break;
+ }
+
+ return carl9170_interpolate_u8(x, x_array[i], y_array[i],
+ x_array[i + 1], y_array[i + 1]);
+}
+
+static int carl9170_set_freq_cal_data(struct ar9170 *ar,
+ struct ieee80211_channel *channel)
+{
+ u8 *cal_freq_pier;
+ u8 vpds[2][AR5416_PD_GAIN_ICEPTS];
+ u8 pwrs[2][AR5416_PD_GAIN_ICEPTS];
+ int chain, idx, i;
+ u32 phy_data = 0;
+ u8 f, tmp;
+
+ switch (channel->band) {
+ case IEEE80211_BAND_2GHZ:
+ f = channel->center_freq - 2300;
+ cal_freq_pier = ar->eeprom.cal_freq_pier_2G;
+ i = AR5416_NUM_2G_CAL_PIERS - 1;
+ break;
+
+ case IEEE80211_BAND_5GHZ:
+ f = (channel->center_freq - 4800) / 5;
+ cal_freq_pier = ar->eeprom.cal_freq_pier_5G;
+ i = AR5416_NUM_5G_CAL_PIERS - 1;
+ break;
+
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ for (; i >= 0; i--) {
+ if (cal_freq_pier[i] != 0xff)
+ break;
+ }
+ if (i < 0)
+ return -EINVAL;
+
+ idx = carl9170_find_freq_idx(i, cal_freq_pier, f);
+
+ carl9170_regwrite_begin(ar);
+
+ for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) {
+ for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) {
+ struct ar9170_calibration_data_per_freq *cal_pier_data;
+ int j;
+
+ switch (channel->band) {
+ case IEEE80211_BAND_2GHZ:
+ cal_pier_data = &ar->eeprom.
+ cal_pier_data_2G[chain][idx];
+ break;
+
+ case IEEE80211_BAND_5GHZ:
+ cal_pier_data = &ar->eeprom.
+ cal_pier_data_5G[chain][idx];
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ for (j = 0; j < 2; j++) {
+ vpds[j][i] = carl9170_interpolate_u8(f,
+ cal_freq_pier[idx],
+ cal_pier_data->vpd_pdg[j][i],
+ cal_freq_pier[idx + 1],
+ cal_pier_data[1].vpd_pdg[j][i]);
+
+ pwrs[j][i] = carl9170_interpolate_u8(f,
+ cal_freq_pier[idx],
+ cal_pier_data->pwr_pdg[j][i],
+ cal_freq_pier[idx + 1],
+ cal_pier_data[1].pwr_pdg[j][i]) / 2;
+ }
+ }
+
+ for (i = 0; i < 76; i++) {
+ if (i < 25) {
+ tmp = carl9170_interpolate_val(i, &pwrs[0][0],
+ &vpds[0][0]);
+ } else {
+ tmp = carl9170_interpolate_val(i - 12,
+ &pwrs[1][0],
+ &vpds[1][0]);
+ }
+
+ phy_data |= tmp << ((i & 3) << 3);
+ if ((i & 3) == 3) {
+ carl9170_regwrite(0x1c6280 + chain * 0x1000 +
+ (i & ~3), phy_data);
+ phy_data = 0;
+ }
+ }
+
+ for (i = 19; i < 32; i++)
+ carl9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2),
+ 0x0);
+ }
+
+ carl9170_regwrite_finish();
+ return carl9170_regwrite_result();
+}
+
+static u8 carl9170_get_max_edge_power(struct ar9170 *ar,
+ u32 freq, struct ar9170_calctl_edges edges[])
+{
+ int i;
+ u8 rc = AR5416_MAX_RATE_POWER;
+ u8 f;
+ if (freq < 3000)
+ f = freq - 2300;
+ else
+ f = (freq - 4800) / 5;
+
+ for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) {
+ if (edges[i].channel == 0xff)
+ break;
+ if (f == edges[i].channel) {
+ /* exact freq match */
+ rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS;
+ break;
+ }
+ if (i > 0 && f < edges[i].channel) {
+ if (f > edges[i - 1].channel &&
+ edges[i - 1].power_flags &
+ AR9170_CALCTL_EDGE_FLAGS) {
+ /* lower channel has the inband flag set */
+ rc = edges[i - 1].power_flags &
+ ~AR9170_CALCTL_EDGE_FLAGS;
+ }
+ break;
+ }
+ }
+
+ if (i == AR5416_NUM_BAND_EDGES) {
+ if (f > edges[i - 1].channel &&
+ edges[i - 1].power_flags & AR9170_CALCTL_EDGE_FLAGS) {
+ /* lower channel has the inband flag set */
+ rc = edges[i - 1].power_flags &
+ ~AR9170_CALCTL_EDGE_FLAGS;
+ }
+ }
+ return rc;
+}
+
+static u8 carl9170_get_heavy_clip(struct ar9170 *ar, u32 freq,
+ enum carl9170_bw bw, struct ar9170_calctl_edges edges[])
+{
+ u8 f;
+ int i;
+ u8 rc = 0;
+
+ if (freq < 3000)
+ f = freq - 2300;
+ else
+ f = (freq - 4800) / 5;
+
+ if (bw == CARL9170_BW_40_BELOW || bw == CARL9170_BW_40_ABOVE)
+ rc |= 0xf0;
+
+ for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) {
+ if (edges[i].channel == 0xff)
+ break;
+ if (f == edges[i].channel) {
+ if (!(edges[i].power_flags & AR9170_CALCTL_EDGE_FLAGS))
+ rc |= 0x0f;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+/*
+ * calculate the conformance test limits and the heavy clip parameter
+ * and apply them to ar->power* (derived from otus hal/hpmain.c, line 3706)
+ */
+static void carl9170_calc_ctl(struct ar9170 *ar, u32 freq, enum carl9170_bw bw)
+{
+ u8 ctl_grp; /* CTL group */
+ u8 ctl_idx; /* CTL index */
+ int i, j;
+ struct ctl_modes {
+ u8 ctl_mode;
+ u8 max_power;
+ u8 *pwr_cal_data;
+ int pwr_cal_len;
+ } *modes;
+
+ /*
+ * order is relevant in the mode_list_*: we fall back to the
+ * lower indices if any mode is missed in the EEPROM.
+ */
+ struct ctl_modes mode_list_2ghz[] = {
+ { CTL_11B, 0, ar->power_2G_cck, 4 },
+ { CTL_11G, 0, ar->power_2G_ofdm, 4 },
+ { CTL_2GHT20, 0, ar->power_2G_ht20, 8 },
+ { CTL_2GHT40, 0, ar->power_2G_ht40, 8 },
+ };
+ struct ctl_modes mode_list_5ghz[] = {
+ { CTL_11A, 0, ar->power_5G_leg, 4 },
+ { CTL_5GHT20, 0, ar->power_5G_ht20, 8 },
+ { CTL_5GHT40, 0, ar->power_5G_ht40, 8 },
+ };
+ int nr_modes;
+
+#define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n])
+
+ ar->heavy_clip = 0;
+
+ /*
+ * TODO: investigate the differences between OTUS'
+ * hpreg.c::zfHpGetRegulatoryDomain() and
+ * ath/regd.c::ath_regd_get_band_ctl() -
+ * e.g. for FCC3_WORLD the OTUS procedure
+ * always returns CTL_FCC, while the one in ath/ delivers
+ * CTL_ETSI for 2GHz and CTL_FCC for 5GHz.
+ */
+ ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory,
+ ar->hw->conf.channel->band);
+
+ /* ctl group not found - either invalid band (NO_CTL) or ww roaming */
+ if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL)
+ ctl_grp = CTL_FCC;
+
+ if (ctl_grp != CTL_FCC)
+ /* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */
+ return;
+
+ if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
+ modes = mode_list_2ghz;
+ nr_modes = ARRAY_SIZE(mode_list_2ghz);
+ } else {
+ modes = mode_list_5ghz;
+ nr_modes = ARRAY_SIZE(mode_list_5ghz);
+ }
+
+ for (i = 0; i < nr_modes; i++) {
+ u8 c = ctl_grp | modes[i].ctl_mode;
+ for (ctl_idx = 0; ctl_idx < AR5416_NUM_CTLS; ctl_idx++)
+ if (c == ar->eeprom.ctl_index[ctl_idx])
+ break;
+ if (ctl_idx < AR5416_NUM_CTLS) {
+ int f_off = 0;
+
+ /*
+ * determine heavy clip parameter
+ * from the 11G edges array
+ */
+ if (modes[i].ctl_mode == CTL_11G) {
+ ar->heavy_clip =
+ carl9170_get_heavy_clip(ar,
+ freq, bw, EDGES(ctl_idx, 1));
+ }
+
+ /* adjust freq for 40MHz */
+ if (modes[i].ctl_mode == CTL_2GHT40 ||
+ modes[i].ctl_mode == CTL_5GHT40) {
+ if (bw == CARL9170_BW_40_BELOW)
+ f_off = -10;
+ else
+ f_off = 10;
+ }
+
+ modes[i].max_power =
+ carl9170_get_max_edge_power(ar,
+ freq+f_off, EDGES(ctl_idx, 1));
+
+ /*
+ * TODO: check if the regulatory max. power is
+ * controlled by cfg80211 for DFS.
+ * (hpmain applies it to max_power itself for DFS freq)
+ */
+
+ } else {
+ /*
+ * Workaround in otus driver, hpmain.c, line 3906:
+ * if no data for 5GHT20 are found, take the
+ * legacy 5G value. We extend this here to fallback
+ * from any other HT* or 11G, too.
+ */
+ int k = i;
+
+ modes[i].max_power = AR5416_MAX_RATE_POWER;
+ while (k-- > 0) {
+ if (modes[k].max_power !=
+ AR5416_MAX_RATE_POWER) {
+ modes[i].max_power = modes[k].max_power;
+ break;
+ }
+ }
+ }
+
+ /* apply max power to pwr_cal_data (ar->power_*) */
+ for (j = 0; j < modes[i].pwr_cal_len; j++) {
+ modes[i].pwr_cal_data[j] = min(modes[i].pwr_cal_data[j],
+ modes[i].max_power);
+ }
+ }
+
+ if (ar->heavy_clip & 0xf0) {
+ ar->power_2G_ht40[0]--;
+ ar->power_2G_ht40[1]--;
+ ar->power_2G_ht40[2]--;
+ }
+ if (ar->heavy_clip & 0xf) {
+ ar->power_2G_ht20[0]++;
+ ar->power_2G_ht20[1]++;
+ ar->power_2G_ht20[2]++;
+ }
+
+#undef EDGES
+}
+
+static int carl9170_set_power_cal(struct ar9170 *ar, u32 freq,
+ enum carl9170_bw bw)
+{
+ struct ar9170_calibration_target_power_legacy *ctpl;
+ struct ar9170_calibration_target_power_ht *ctph;
+ u8 *ctpres;
+ int ntargets;
+ int idx, i, n;
+ u8 ackpower, ackchains, f;
+ u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS];
+
+ if (freq < 3000)
+ f = freq - 2300;
+ else
+ f = (freq - 4800)/5;
+
+ /*
+ * cycle through the various modes
+ *
+ * legacy modes first: 5G, 2G CCK, 2G OFDM
+ */
+ for (i = 0; i < 3; i++) {
+ switch (i) {
+ case 0: /* 5 GHz legacy */
+ ctpl = &ar->eeprom.cal_tgt_pwr_5G[0];
+ ntargets = AR5416_NUM_5G_TARGET_PWRS;
+ ctpres = ar->power_5G_leg;
+ break;
+ case 1: /* 2.4 GHz CCK */
+ ctpl = &ar->eeprom.cal_tgt_pwr_2G_cck[0];
+ ntargets = AR5416_NUM_2G_CCK_TARGET_PWRS;
+ ctpres = ar->power_2G_cck;
+ break;
+ case 2: /* 2.4 GHz OFDM */
+ ctpl = &ar->eeprom.cal_tgt_pwr_2G_ofdm[0];
+ ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS;
+ ctpres = ar->power_2G_ofdm;
+ break;
+ default:
+ BUG();
+ }
+
+ for (n = 0; n < ntargets; n++) {
+ if (ctpl[n].freq == 0xff)
+ break;
+ pwr_freqs[n] = ctpl[n].freq;
+ }
+ ntargets = n;
+ idx = carl9170_find_freq_idx(ntargets, pwr_freqs, f);
+ for (n = 0; n < 4; n++)
+ ctpres[n] = carl9170_interpolate_u8(f,
+ ctpl[idx + 0].freq, ctpl[idx + 0].power[n],
+ ctpl[idx + 1].freq, ctpl[idx + 1].power[n]);
+ }
+
+ /* HT modes now: 5G HT20, 5G HT40, 2G CCK, 2G OFDM, 2G HT20, 2G HT40 */
+ for (i = 0; i < 4; i++) {
+ switch (i) {
+ case 0: /* 5 GHz HT 20 */
+ ctph = &ar->eeprom.cal_tgt_pwr_5G_ht20[0];
+ ntargets = AR5416_NUM_5G_TARGET_PWRS;
+ ctpres = ar->power_5G_ht20;
+ break;
+ case 1: /* 5 GHz HT 40 */
+ ctph = &ar->eeprom.cal_tgt_pwr_5G_ht40[0];
+ ntargets = AR5416_NUM_5G_TARGET_PWRS;
+ ctpres = ar->power_5G_ht40;
+ break;
+ case 2: /* 2.4 GHz HT 20 */
+ ctph = &ar->eeprom.cal_tgt_pwr_2G_ht20[0];
+ ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS;
+ ctpres = ar->power_2G_ht20;
+ break;
+ case 3: /* 2.4 GHz HT 40 */
+ ctph = &ar->eeprom.cal_tgt_pwr_2G_ht40[0];
+ ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS;
+ ctpres = ar->power_2G_ht40;
+ break;
+ default:
+ BUG();
+ }
+
+ for (n = 0; n < ntargets; n++) {
+ if (ctph[n].freq == 0xff)
+ break;
+ pwr_freqs[n] = ctph[n].freq;
+ }
+ ntargets = n;
+ idx = carl9170_find_freq_idx(ntargets, pwr_freqs, f);
+ for (n = 0; n < 8; n++)
+ ctpres[n] = carl9170_interpolate_u8(f,
+ ctph[idx + 0].freq, ctph[idx + 0].power[n],
+ ctph[idx + 1].freq, ctph[idx + 1].power[n]);
+ }
+
+ /* calc. conformance test limits and apply to ar->power*[] */
+ carl9170_calc_ctl(ar, freq, bw);
+
+ /* set ACK/CTS TX power */
+ carl9170_regwrite_begin(ar);
+
+ if (ar->eeprom.tx_mask != 1)
+ ackchains = AR9170_TX_PHY_TXCHAIN_2;
+ else
+ ackchains = AR9170_TX_PHY_TXCHAIN_1;
+
+ if (freq < 3000)
+ ackpower = ar->power_2G_ofdm[0] & 0x3f;
+ else
+ ackpower = ar->power_5G_leg[0] & 0x3f;
+
+ carl9170_regwrite(AR9170_MAC_REG_ACK_TPC,
+ 0x3c1e | ackpower << 20 | ackchains << 26);
+ carl9170_regwrite(AR9170_MAC_REG_RTS_CTS_TPC,
+ ackpower << 5 | ackchains << 11 |
+ ackpower << 21 | ackchains << 27);
+
+ carl9170_regwrite(AR9170_MAC_REG_CFEND_QOSNULL_TPC,
+ ackpower << 5 | ackchains << 11 |
+ ackpower << 21 | ackchains << 27);
+
+ carl9170_regwrite_finish();
+ return carl9170_regwrite_result();
+}
+
+/* TODO: replace this with sign_extend32(noise, 8) */
+static int carl9170_calc_noise_dbm(u32 raw_noise)
+{
+ if (raw_noise & 0x100)
+ return ~0x1ff | raw_noise;
+ else
+ return raw_noise;
+}
+
+int carl9170_get_noisefloor(struct ar9170 *ar)
+{
+ static const u32 phy_regs[] = {
+ AR9170_PHY_REG_CCA, AR9170_PHY_REG_CH2_CCA,
+ AR9170_PHY_REG_EXT_CCA, AR9170_PHY_REG_CH2_EXT_CCA };
+ u32 phy_res[ARRAY_SIZE(phy_regs)];
+ int err, i;
+
+ BUILD_BUG_ON(ARRAY_SIZE(phy_regs) != ARRAY_SIZE(ar->noise));
+
+ err = carl9170_read_mreg(ar, ARRAY_SIZE(phy_regs), phy_regs, phy_res);
+ if (err)
+ return err;
+
+ for (i = 0; i < 2; i++) {
+ ar->noise[i] = carl9170_calc_noise_dbm(
+ (phy_res[i] >> 19) & 0x1ff);
+
+ ar->noise[i + 2] = carl9170_calc_noise_dbm(
+ (phy_res[i + 2] >> 23) & 0x1ff);
+ }
+
+ return 0;
+}
+
+static enum carl9170_bw nl80211_to_carl(enum nl80211_channel_type type)
+{
+ switch (type) {
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
+ return CARL9170_BW_20;
+ case NL80211_CHAN_HT40MINUS:
+ return CARL9170_BW_40_BELOW;
+ case NL80211_CHAN_HT40PLUS:
+ return CARL9170_BW_40_ABOVE;
+ default:
+ BUG();
+ }
+}
+
+int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
+ enum nl80211_channel_type _bw,
+ enum carl9170_rf_init_mode rfi)
+{
+ const struct carl9170_phy_freq_params *freqpar;
+ struct carl9170_rf_init_result rf_res;
+ struct carl9170_rf_init rf;
+ u32 cmd, tmp, offs = 0, new_ht = 0;
+ int err;
+ enum carl9170_bw bw;
+ bool warm_reset;
+ struct ieee80211_channel *old_channel = NULL;
+
+ bw = nl80211_to_carl(_bw);
+
+ if (conf_is_ht(&ar->hw->conf))
+ new_ht |= CARL9170FW_PHY_HT_ENABLE;
+
+ if (conf_is_ht40(&ar->hw->conf))
+ new_ht |= CARL9170FW_PHY_HT_DYN2040;
+
+ /* may be NULL at first setup */
+ if (ar->channel) {
+ old_channel = ar->channel;
+ warm_reset = (old_channel->band != channel->band) ||
+ (old_channel->center_freq ==
+ channel->center_freq) ||
+ (ar->ht_settings != new_ht);
+
+ ar->channel = NULL;
+ } else {
+ warm_reset = true;
+ }
+
+ /* HW workaround */
+ if (!ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] &&
+ channel->center_freq <= 2417)
+ warm_reset = true;
+
+ if (rfi != CARL9170_RFI_NONE || warm_reset) {
+ u32 val;
+
+ if (rfi == CARL9170_RFI_COLD)
+ val = AR9170_PWR_RESET_BB_COLD_RESET;
+ else
+ val = AR9170_PWR_RESET_BB_WARM_RESET;
+
+ /* warm/cold reset BB/ADDA */
+ err = carl9170_write_reg(ar, AR9170_PWR_REG_RESET, val);
+ if (err)
+ return err;
+
+ err = carl9170_write_reg(ar, AR9170_PWR_REG_RESET, 0x0);
+ if (err)
+ return err;
+
+ err = carl9170_init_phy(ar, channel->band);
+ if (err)
+ return err;
+
+ err = carl9170_init_rf_banks_0_7(ar,
+ channel->band == IEEE80211_BAND_5GHZ);
+ if (err)
+ return err;
+
+ cmd = CARL9170_CMD_RF_INIT;
+
+ msleep(100);
+
+ err = carl9170_echo_test(ar, 0xaabbccdd);
+ if (err)
+ return err;
+ } else {
+ cmd = CARL9170_CMD_FREQUENCY;
+ }
+
+ err = carl9170_exec_cmd(ar, CARL9170_CMD_FREQ_START, 0, NULL, 0, NULL);
+ if (err)
+ return err;
+
+ err = carl9170_write_reg(ar, AR9170_PHY_REG_HEAVY_CLIP_ENABLE,
+ 0x200);
+
+ err = carl9170_init_rf_bank4_pwr(ar,
+ channel->band == IEEE80211_BAND_5GHZ,
+ channel->center_freq, bw);
+ if (err)
+ return err;
+
+ tmp = AR9170_PHY_TURBO_FC_SINGLE_HT_LTF1 |
+ AR9170_PHY_TURBO_FC_HT_EN;
+
+ switch (bw) {
+ case CARL9170_BW_20:
+ break;
+ case CARL9170_BW_40_BELOW:
+ tmp |= AR9170_PHY_TURBO_FC_DYN2040_EN |
+ AR9170_PHY_TURBO_FC_SHORT_GI_40;
+ offs = 3;
+ break;
+ case CARL9170_BW_40_ABOVE:
+ tmp |= AR9170_PHY_TURBO_FC_DYN2040_EN |
+ AR9170_PHY_TURBO_FC_SHORT_GI_40 |
+ AR9170_PHY_TURBO_FC_DYN2040_PRI_CH;
+ offs = 1;
+ break;
+ default:
+ BUG();
+ return -ENOSYS;
+ }
+
+ if (ar->eeprom.tx_mask != 1)
+ tmp |= AR9170_PHY_TURBO_FC_WALSH;
+
+ err = carl9170_write_reg(ar, AR9170_PHY_REG_TURBO, tmp);
+ if (err)
+ return err;
+
+ err = carl9170_set_freq_cal_data(ar, channel);
+ if (err)
+ return err;
+
+ err = carl9170_set_power_cal(ar, channel->center_freq, bw);
+ if (err)
+ return err;
+
+ freqpar = carl9170_get_hw_dyn_params(channel, bw);
+
+ rf.ht_settings = new_ht;
+ if (conf_is_ht40(&ar->hw->conf))
+ SET_VAL(CARL9170FW_PHY_HT_EXT_CHAN_OFF, rf.ht_settings, offs);
+
+ rf.freq = cpu_to_le32(channel->center_freq * 1000);
+ rf.delta_slope_coeff_exp = cpu_to_le32(freqpar->coeff_exp);
+ rf.delta_slope_coeff_man = cpu_to_le32(freqpar->coeff_man);
+ rf.delta_slope_coeff_exp_shgi = cpu_to_le32(freqpar->coeff_exp_shgi);
+ rf.delta_slope_coeff_man_shgi = cpu_to_le32(freqpar->coeff_man_shgi);
+
+ if (rfi != CARL9170_RFI_NONE)
+ rf.finiteLoopCount = cpu_to_le32(2000);
+ else
+ rf.finiteLoopCount = cpu_to_le32(1000);
+
+ err = carl9170_exec_cmd(ar, cmd, sizeof(rf), &rf,
+ sizeof(rf_res), &rf_res);
+ if (err)
+ return err;
+
+ err = le32_to_cpu(rf_res.ret);
+ if (err != 0) {
+ ar->chan_fail++;
+ ar->total_chan_fail++;
+
+ wiphy_err(ar->hw->wiphy, "channel change: %d -> %d "
+ "failed (%d).\n", old_channel ?
+ old_channel->center_freq : -1, channel->center_freq,
+ err);
+
+ if ((rfi == CARL9170_RFI_COLD) || (ar->chan_fail > 3)) {
+ /*
+ * We have tried very hard to change to _another_
+ * channel and we've failed to do so!
+ * Chances are that the PHY/RF is no longer
+ * operable (due to corruptions/fatal events/bugs?)
+ * and we need to reset at a higher level.
+ */
+ carl9170_restart(ar, CARL9170_RR_TOO_MANY_PHY_ERRORS);
+ return 0;
+ }
+
+ err = carl9170_set_channel(ar, channel, _bw,
+ CARL9170_RFI_COLD);
+ if (err)
+ return err;
+ } else {
+ 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);
+ if (err) {
+ if (net_ratelimit()) {
+ wiphy_err(ar->hw->wiphy, "failed to set "
+ "heavy clip\n");
+ }
+
+ return err;
+ }
+ }
+
+ /* FIXME: PSM does not work in 5GHz Band */
+ if (channel->band == IEEE80211_BAND_5GHZ)
+ ar->ps.off_override |= PS_OFF_5GHZ;
+ else
+ ar->ps.off_override &= ~PS_OFF_5GHZ;
+
+ ar->channel = channel;
+ ar->ht_settings = new_ht;
+ return 0;
+}
diff --git a/drivers/net/wireless/ath/carl9170/phy.h b/drivers/net/wireless/ath/carl9170/phy.h
new file mode 100644
index 000000000000..02c34eb4ebde
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/phy.h
@@ -0,0 +1,564 @@
+/*
+ * Shared Atheros AR9170 Header
+ *
+ * PHY register map
+ *
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __CARL9170_SHARED_PHY_H
+#define __CARL9170_SHARED_PHY_H
+
+#define AR9170_PHY_REG_BASE (0x1bc000 + 0x9800)
+#define AR9170_PHY_REG(_n) (AR9170_PHY_REG_BASE + \
+ ((_n) << 2))
+
+#define AR9170_PHY_REG_TEST (AR9170_PHY_REG_BASE + 0x0000)
+#define AR9170_PHY_TEST_AGC_CLR 0x10000000
+#define AR9170_PHY_TEST_RFSILENT_BB 0x00002000
+
+#define AR9170_PHY_REG_TURBO (AR9170_PHY_REG_BASE + 0x0004)
+#define AR9170_PHY_TURBO_FC_TURBO_MODE 0x00000001
+#define AR9170_PHY_TURBO_FC_TURBO_SHORT 0x00000002
+#define AR9170_PHY_TURBO_FC_DYN2040_EN 0x00000004
+#define AR9170_PHY_TURBO_FC_DYN2040_PRI_ONLY 0x00000008
+#define AR9170_PHY_TURBO_FC_DYN2040_PRI_CH 0x00000010
+/* For 25 MHz channel spacing -- not used but supported by hw */
+#define AR9170_PHY_TURBO_FC_DYN2040_EXT_CH 0x00000020
+#define AR9170_PHY_TURBO_FC_HT_EN 0x00000040
+#define AR9170_PHY_TURBO_FC_SHORT_GI_40 0x00000080
+#define AR9170_PHY_TURBO_FC_WALSH 0x00000100
+#define AR9170_PHY_TURBO_FC_SINGLE_HT_LTF1 0x00000200
+#define AR9170_PHY_TURBO_FC_ENABLE_DAC_FIFO 0x00000800
+
+#define AR9170_PHY_REG_TEST2 (AR9170_PHY_REG_BASE + 0x0008)
+
+#define AR9170_PHY_REG_TIMING2 (AR9170_PHY_REG_BASE + 0x0010)
+#define AR9170_PHY_TIMING2_USE_FORCE 0x00001000
+#define AR9170_PHY_TIMING2_FORCE 0x00000fff
+#define AR9170_PHY_TIMING2_FORCE_S 0
+
+#define AR9170_PHY_REG_TIMING3 (AR9170_PHY_REG_BASE + 0x0014)
+#define AR9170_PHY_TIMING3_DSC_EXP 0x0001e000
+#define AR9170_PHY_TIMING3_DSC_EXP_S 13
+#define AR9170_PHY_TIMING3_DSC_MAN 0xfffe0000
+#define AR9170_PHY_TIMING3_DSC_MAN_S 17
+
+#define AR9170_PHY_REG_CHIP_ID (AR9170_PHY_REG_BASE + 0x0018)
+#define AR9170_PHY_CHIP_ID_REV_0 0x80
+#define AR9170_PHY_CHIP_ID_REV_1 0x81
+#define AR9170_PHY_CHIP_ID_9160_REV_0 0xb0
+
+#define AR9170_PHY_REG_ACTIVE (AR9170_PHY_REG_BASE + 0x001c)
+#define AR9170_PHY_ACTIVE_EN 0x00000001
+#define AR9170_PHY_ACTIVE_DIS 0x00000000
+
+#define AR9170_PHY_REG_RF_CTL2 (AR9170_PHY_REG_BASE + 0x0024)
+#define AR9170_PHY_RF_CTL2_TX_END_DATA_START 0x000000ff
+#define AR9170_PHY_RF_CTL2_TX_END_DATA_START_S 0
+#define AR9170_PHY_RF_CTL2_TX_END_PA_ON 0x0000ff00
+#define AR9170_PHY_RF_CTL2_TX_END_PA_ON_S 8
+
+#define AR9170_PHY_REG_RF_CTL3 (AR9170_PHY_REG_BASE + 0x0028)
+#define AR9170_PHY_RF_CTL3_TX_END_TO_A2_RX_ON 0x00ff0000
+#define AR9170_PHY_RF_CTL3_TX_END_TO_A2_RX_ON_S 16
+
+#define AR9170_PHY_REG_ADC_CTL (AR9170_PHY_REG_BASE + 0x002c)
+#define AR9170_PHY_ADC_CTL_OFF_INBUFGAIN 0x00000003
+#define AR9170_PHY_ADC_CTL_OFF_INBUFGAIN_S 0
+#define AR9170_PHY_ADC_CTL_OFF_PWDDAC 0x00002000
+#define AR9170_PHY_ADC_CTL_OFF_PWDBANDGAP 0x00004000
+#define AR9170_PHY_ADC_CTL_OFF_PWDADC 0x00008000
+#define AR9170_PHY_ADC_CTL_ON_INBUFGAIN 0x00030000
+#define AR9170_PHY_ADC_CTL_ON_INBUFGAIN_S 16
+
+#define AR9170_PHY_REG_ADC_SERIAL_CTL (AR9170_PHY_REG_BASE + 0x0030)
+#define AR9170_PHY_ADC_SCTL_SEL_INTERNAL_ADDAC 0x00000000
+#define AR9170_PHY_ADC_SCTL_SEL_EXTERNAL_RADIO 0x00000001
+
+#define AR9170_PHY_REG_RF_CTL4 (AR9170_PHY_REG_BASE + 0x0034)
+#define AR9170_PHY_RF_CTL4_TX_END_XPAB_OFF 0xff000000
+#define AR9170_PHY_RF_CTL4_TX_END_XPAB_OFF_S 24
+#define AR9170_PHY_RF_CTL4_TX_END_XPAA_OFF 0x00ff0000
+#define AR9170_PHY_RF_CTL4_TX_END_XPAA_OFF_S 16
+#define AR9170_PHY_RF_CTL4_FRAME_XPAB_ON 0x0000ff00
+#define AR9170_PHY_RF_CTL4_FRAME_XPAB_ON_S 8
+#define AR9170_PHY_RF_CTL4_FRAME_XPAA_ON 0x000000ff
+#define AR9170_PHY_RF_CTL4_FRAME_XPAA_ON_S 0
+
+#define AR9170_PHY_REG_TSTDAC_CONST (AR9170_PHY_REG_BASE + 0x003c)
+
+#define AR9170_PHY_REG_SETTLING (AR9170_PHY_REG_BASE + 0x0044)
+#define AR9170_PHY_SETTLING_SWITCH 0x00003f80
+#define AR9170_PHY_SETTLING_SWITCH_S 7
+
+#define AR9170_PHY_REG_RXGAIN (AR9170_PHY_REG_BASE + 0x0048)
+#define AR9170_PHY_REG_RXGAIN_CHAIN_2 (AR9170_PHY_REG_BASE + 0x2048)
+#define AR9170_PHY_RXGAIN_TXRX_ATTEN 0x0003f000
+#define AR9170_PHY_RXGAIN_TXRX_ATTEN_S 12
+#define AR9170_PHY_RXGAIN_TXRX_RF_MAX 0x007c0000
+#define AR9170_PHY_RXGAIN_TXRX_RF_MAX_S 18
+
+#define AR9170_PHY_REG_DESIRED_SZ (AR9170_PHY_REG_BASE + 0x0050)
+#define AR9170_PHY_DESIRED_SZ_ADC 0x000000ff
+#define AR9170_PHY_DESIRED_SZ_ADC_S 0
+#define AR9170_PHY_DESIRED_SZ_PGA 0x0000ff00
+#define AR9170_PHY_DESIRED_SZ_PGA_S 8
+#define AR9170_PHY_DESIRED_SZ_TOT_DES 0x0ff00000
+#define AR9170_PHY_DESIRED_SZ_TOT_DES_S 20
+
+#define AR9170_PHY_REG_FIND_SIG (AR9170_PHY_REG_BASE + 0x0058)
+#define AR9170_PHY_FIND_SIG_FIRSTEP 0x0003f000
+#define AR9170_PHY_FIND_SIG_FIRSTEP_S 12
+#define AR9170_PHY_FIND_SIG_FIRPWR 0x03fc0000
+#define AR9170_PHY_FIND_SIG_FIRPWR_S 18
+
+#define AR9170_PHY_REG_AGC_CTL1 (AR9170_PHY_REG_BASE + 0x005c)
+#define AR9170_PHY_AGC_CTL1_COARSE_LOW 0x00007f80
+#define AR9170_PHY_AGC_CTL1_COARSE_LOW_S 7
+#define AR9170_PHY_AGC_CTL1_COARSE_HIGH 0x003f8000
+#define AR9170_PHY_AGC_CTL1_COARSE_HIGH_S 15
+
+#define AR9170_PHY_REG_AGC_CONTROL (AR9170_PHY_REG_BASE + 0x0060)
+#define AR9170_PHY_AGC_CONTROL_CAL 0x00000001
+#define AR9170_PHY_AGC_CONTROL_NF 0x00000002
+#define AR9170_PHY_AGC_CONTROL_ENABLE_NF 0x00008000
+#define AR9170_PHY_AGC_CONTROL_FLTR_CAL 0x00010000
+#define AR9170_PHY_AGC_CONTROL_NO_UPDATE_NF 0x00020000
+
+#define AR9170_PHY_REG_CCA (AR9170_PHY_REG_BASE + 0x0064)
+#define AR9170_PHY_CCA_MINCCA_PWR 0x0ff80000
+#define AR9170_PHY_CCA_MINCCA_PWR_S 19
+#define AR9170_PHY_CCA_THRESH62 0x0007f000
+#define AR9170_PHY_CCA_THRESH62_S 12
+
+#define AR9170_PHY_REG_SFCORR (AR9170_PHY_REG_BASE + 0x0068)
+#define AR9170_PHY_SFCORR_M2COUNT_THR 0x0000001f
+#define AR9170_PHY_SFCORR_M2COUNT_THR_S 0
+#define AR9170_PHY_SFCORR_M1_THRESH 0x00fe0000
+#define AR9170_PHY_SFCORR_M1_THRESH_S 17
+#define AR9170_PHY_SFCORR_M2_THRESH 0x7f000000
+#define AR9170_PHY_SFCORR_M2_THRESH_S 24
+
+#define AR9170_PHY_REG_SFCORR_LOW (AR9170_PHY_REG_BASE + 0x006c)
+#define AR9170_PHY_SFCORR_LOW_USE_SELF_CORR_LOW 0x00000001
+#define AR9170_PHY_SFCORR_LOW_M2COUNT_THR_LOW 0x00003f00
+#define AR9170_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S 8
+#define AR9170_PHY_SFCORR_LOW_M1_THRESH_LOW 0x001fc000
+#define AR9170_PHY_SFCORR_LOW_M1_THRESH_LOW_S 14
+#define AR9170_PHY_SFCORR_LOW_M2_THRESH_LOW 0x0fe00000
+#define AR9170_PHY_SFCORR_LOW_M2_THRESH_LOW_S 21
+
+#define AR9170_PHY_REG_SLEEP_CTR_CONTROL (AR9170_PHY_REG_BASE + 0x0070)
+#define AR9170_PHY_REG_SLEEP_CTR_LIMIT (AR9170_PHY_REG_BASE + 0x0074)
+#define AR9170_PHY_REG_SLEEP_SCAL (AR9170_PHY_REG_BASE + 0x0078)
+
+#define AR9170_PHY_REG_PLL_CTL (AR9170_PHY_REG_BASE + 0x007c)
+#define AR9170_PHY_PLL_CTL_40 0xaa
+#define AR9170_PHY_PLL_CTL_40_5413 0x04
+#define AR9170_PHY_PLL_CTL_44 0xab
+#define AR9170_PHY_PLL_CTL_44_2133 0xeb
+#define AR9170_PHY_PLL_CTL_40_2133 0xea
+
+#define AR9170_PHY_REG_BIN_MASK_1 (AR9170_PHY_REG_BASE + 0x0100)
+#define AR9170_PHY_REG_BIN_MASK_2 (AR9170_PHY_REG_BASE + 0x0104)
+#define AR9170_PHY_REG_BIN_MASK_3 (AR9170_PHY_REG_BASE + 0x0108)
+#define AR9170_PHY_REG_MASK_CTL (AR9170_PHY_REG_BASE + 0x010c)
+
+/* analogue power on time (100ns) */
+#define AR9170_PHY_REG_RX_DELAY (AR9170_PHY_REG_BASE + 0x0114)
+#define AR9170_PHY_REG_SEARCH_START_DELAY (AR9170_PHY_REG_BASE + 0x0118)
+#define AR9170_PHY_RX_DELAY_DELAY 0x00003fff
+
+#define AR9170_PHY_REG_TIMING_CTRL4(_i) (AR9170_PHY_REG_BASE + \
+ (0x0120 + ((_i) << 12)))
+#define AR9170_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF 0x01f
+#define AR9170_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_S 0
+#define AR9170_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF 0x7e0
+#define AR9170_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S 5
+#define AR9170_PHY_TIMING_CTRL4_IQCORR_ENABLE 0x800
+#define AR9170_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX 0xf000
+#define AR9170_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S 12
+#define AR9170_PHY_TIMING_CTRL4_DO_IQCAL 0x10000
+#define AR9170_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI 0x80000000
+#define AR9170_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER 0x40000000
+#define AR9170_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK 0x20000000
+#define AR9170_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK 0x10000000
+
+#define AR9170_PHY_REG_TIMING5 (AR9170_PHY_REG_BASE + 0x0124)
+#define AR9170_PHY_TIMING5_CYCPWR_THR1 0x000000fe
+#define AR9170_PHY_TIMING5_CYCPWR_THR1_S 1
+
+#define AR9170_PHY_REG_POWER_TX_RATE1 (AR9170_PHY_REG_BASE + 0x0134)
+#define AR9170_PHY_REG_POWER_TX_RATE2 (AR9170_PHY_REG_BASE + 0x0138)
+#define AR9170_PHY_REG_POWER_TX_RATE_MAX (AR9170_PHY_REG_BASE + 0x013c)
+#define AR9170_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040
+
+#define AR9170_PHY_REG_FRAME_CTL (AR9170_PHY_REG_BASE + 0x0144)
+#define AR9170_PHY_FRAME_CTL_TX_CLIP 0x00000038
+#define AR9170_PHY_FRAME_CTL_TX_CLIP_S 3
+
+#define AR9170_PHY_REG_SPUR_REG (AR9170_PHY_REG_BASE + 0x014c)
+#define AR9170_PHY_SPUR_REG_MASK_RATE_CNTL (0xff << 18)
+#define AR9170_PHY_SPUR_REG_MASK_RATE_CNTL_S 18
+#define AR9170_PHY_SPUR_REG_ENABLE_MASK_PPM 0x20000
+#define AR9170_PHY_SPUR_REG_MASK_RATE_SELECT (0xff << 9)
+#define AR9170_PHY_SPUR_REG_MASK_RATE_SELECT_S 9
+#define AR9170_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI 0x100
+#define AR9170_PHY_SPUR_REG_SPUR_RSSI_THRESH 0x7f
+#define AR9170_PHY_SPUR_REG_SPUR_RSSI_THRESH_S 0
+
+#define AR9170_PHY_REG_RADAR_EXT (AR9170_PHY_REG_BASE + 0x0140)
+#define AR9170_PHY_RADAR_EXT_ENA 0x00004000
+
+#define AR9170_PHY_REG_RADAR_0 (AR9170_PHY_REG_BASE + 0x0154)
+#define AR9170_PHY_RADAR_0_ENA 0x00000001
+#define AR9170_PHY_RADAR_0_FFT_ENA 0x80000000
+/* inband pulse threshold */
+#define AR9170_PHY_RADAR_0_INBAND 0x0000003e
+#define AR9170_PHY_RADAR_0_INBAND_S 1
+/* pulse RSSI threshold */
+#define AR9170_PHY_RADAR_0_PRSSI 0x00000fc0
+#define AR9170_PHY_RADAR_0_PRSSI_S 6
+/* pulse height threshold */
+#define AR9170_PHY_RADAR_0_HEIGHT 0x0003f000
+#define AR9170_PHY_RADAR_0_HEIGHT_S 12
+/* radar RSSI threshold */
+#define AR9170_PHY_RADAR_0_RRSSI 0x00fc0000
+#define AR9170_PHY_RADAR_0_RRSSI_S 18
+/* radar firepower threshold */
+#define AR9170_PHY_RADAR_0_FIRPWR 0x7f000000
+#define AR9170_PHY_RADAR_0_FIRPWR_S 24
+
+#define AR9170_PHY_REG_RADAR_1 (AR9170_PHY_REG_BASE + 0x0158)
+#define AR9170_PHY_RADAR_1_RELPWR_ENA 0x00800000
+#define AR9170_PHY_RADAR_1_USE_FIR128 0x00400000
+#define AR9170_PHY_RADAR_1_RELPWR_THRESH 0x003f0000
+#define AR9170_PHY_RADAR_1_RELPWR_THRESH_S 16
+#define AR9170_PHY_RADAR_1_BLOCK_CHECK 0x00008000
+#define AR9170_PHY_RADAR_1_MAX_RRSSI 0x00004000
+#define AR9170_PHY_RADAR_1_RELSTEP_CHECK 0x00002000
+#define AR9170_PHY_RADAR_1_RELSTEP_THRESH 0x00001f00
+#define AR9170_PHY_RADAR_1_RELSTEP_THRESH_S 8
+#define AR9170_PHY_RADAR_1_MAXLEN 0x000000ff
+#define AR9170_PHY_RADAR_1_MAXLEN_S 0
+
+#define AR9170_PHY_REG_SWITCH_CHAIN_0 (AR9170_PHY_REG_BASE + 0x0160)
+#define AR9170_PHY_REG_SWITCH_CHAIN_2 (AR9170_PHY_REG_BASE + 0x2160)
+
+#define AR9170_PHY_REG_SWITCH_COM (AR9170_PHY_REG_BASE + 0x0164)
+
+#define AR9170_PHY_REG_CCA_THRESHOLD (AR9170_PHY_REG_BASE + 0x0168)
+
+#define AR9170_PHY_REG_SIGMA_DELTA (AR9170_PHY_REG_BASE + 0x016c)
+#define AR9170_PHY_SIGMA_DELTA_ADC_SEL 0x00000003
+#define AR9170_PHY_SIGMA_DELTA_ADC_SEL_S 0
+#define AR9170_PHY_SIGMA_DELTA_FILT2 0x000000f8
+#define AR9170_PHY_SIGMA_DELTA_FILT2_S 3
+#define AR9170_PHY_SIGMA_DELTA_FILT1 0x00001f00
+#define AR9170_PHY_SIGMA_DELTA_FILT1_S 8
+#define AR9170_PHY_SIGMA_DELTA_ADC_CLIP 0x01ffe000
+#define AR9170_PHY_SIGMA_DELTA_ADC_CLIP_S 13
+
+#define AR9170_PHY_REG_RESTART (AR9170_PHY_REG_BASE + 0x0170)
+#define AR9170_PHY_RESTART_DIV_GC 0x001c0000
+#define AR9170_PHY_RESTART_DIV_GC_S 18
+
+#define AR9170_PHY_REG_RFBUS_REQ (AR9170_PHY_REG_BASE + 0x017c)
+#define AR9170_PHY_RFBUS_REQ_EN 0x00000001
+
+#define AR9170_PHY_REG_TIMING7 (AR9170_PHY_REG_BASE + 0x0180)
+#define AR9170_PHY_REG_TIMING8 (AR9170_PHY_REG_BASE + 0x0184)
+#define AR9170_PHY_TIMING8_PILOT_MASK_2 0x000fffff
+#define AR9170_PHY_TIMING8_PILOT_MASK_2_S 0
+
+#define AR9170_PHY_REG_BIN_MASK2_1 (AR9170_PHY_REG_BASE + 0x0188)
+#define AR9170_PHY_REG_BIN_MASK2_2 (AR9170_PHY_REG_BASE + 0x018c)
+#define AR9170_PHY_REG_BIN_MASK2_3 (AR9170_PHY_REG_BASE + 0x0190)
+#define AR9170_PHY_REG_BIN_MASK2_4 (AR9170_PHY_REG_BASE + 0x0194)
+#define AR9170_PHY_BIN_MASK2_4_MASK_4 0x00003fff
+#define AR9170_PHY_BIN_MASK2_4_MASK_4_S 0
+
+#define AR9170_PHY_REG_TIMING9 (AR9170_PHY_REG_BASE + 0x0198)
+#define AR9170_PHY_REG_TIMING10 (AR9170_PHY_REG_BASE + 0x019c)
+#define AR9170_PHY_TIMING10_PILOT_MASK_2 0x000fffff
+#define AR9170_PHY_TIMING10_PILOT_MASK_2_S 0
+
+#define AR9170_PHY_REG_TIMING11 (AR9170_PHY_REG_BASE + 0x01a0)
+#define AR9170_PHY_TIMING11_SPUR_DELTA_PHASE 0x000fffff
+#define AR9170_PHY_TIMING11_SPUR_DELTA_PHASE_S 0
+#define AR9170_PHY_TIMING11_SPUR_FREQ_SD 0x3ff00000
+#define AR9170_PHY_TIMING11_SPUR_FREQ_SD_S 20
+#define AR9170_PHY_TIMING11_USE_SPUR_IN_AGC 0x40000000
+#define AR9170_PHY_TIMING11_USE_SPUR_IN_SELFCOR 0x80000000
+
+#define AR9170_PHY_REG_RX_CHAINMASK (AR9170_PHY_REG_BASE + 0x01a4)
+#define AR9170_PHY_REG_NEW_ADC_DC_GAIN_CORR(_i) (AR9170_PHY_REG_BASE + \
+ 0x01b4 + ((_i) << 12))
+#define AR9170_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000
+#define AR9170_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000
+
+#define AR9170_PHY_REG_MULTICHAIN_GAIN_CTL (AR9170_PHY_REG_BASE + 0x01ac)
+#define AR9170_PHY_9285_ANT_DIV_CTL_ALL 0x7f000000
+#define AR9170_PHY_9285_ANT_DIV_CTL 0x01000000
+#define AR9170_PHY_9285_ANT_DIV_CTL_S 24
+#define AR9170_PHY_9285_ANT_DIV_ALT_LNACONF 0x06000000
+#define AR9170_PHY_9285_ANT_DIV_ALT_LNACONF_S 25
+#define AR9170_PHY_9285_ANT_DIV_MAIN_LNACONF 0x18000000
+#define AR9170_PHY_9285_ANT_DIV_MAIN_LNACONF_S 27
+#define AR9170_PHY_9285_ANT_DIV_ALT_GAINTB 0x20000000
+#define AR9170_PHY_9285_ANT_DIV_ALT_GAINTB_S 29
+#define AR9170_PHY_9285_ANT_DIV_MAIN_GAINTB 0x40000000
+#define AR9170_PHY_9285_ANT_DIV_MAIN_GAINTB_S 30
+#define AR9170_PHY_9285_ANT_DIV_LNA1 2
+#define AR9170_PHY_9285_ANT_DIV_LNA2 1
+#define AR9170_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2 3
+#define AR9170_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0
+#define AR9170_PHY_9285_ANT_DIV_GAINTB_0 0
+#define AR9170_PHY_9285_ANT_DIV_GAINTB_1 1
+
+#define AR9170_PHY_REG_EXT_CCA0 (AR9170_PHY_REG_BASE + 0x01b8)
+#define AR9170_PHY_REG_EXT_CCA0_THRESH62 0x000000ff
+#define AR9170_PHY_REG_EXT_CCA0_THRESH62_S 0
+
+#define AR9170_PHY_REG_EXT_CCA (AR9170_PHY_REG_BASE + 0x01bc)
+#define AR9170_PHY_EXT_CCA_CYCPWR_THR1 0x0000fe00
+#define AR9170_PHY_EXT_CCA_CYCPWR_THR1_S 9
+#define AR9170_PHY_EXT_CCA_THRESH62 0x007f0000
+#define AR9170_PHY_EXT_CCA_THRESH62_S 16
+#define AR9170_PHY_EXT_MINCCA_PWR 0xff800000
+#define AR9170_PHY_EXT_MINCCA_PWR_S 23
+
+#define AR9170_PHY_REG_SFCORR_EXT (AR9170_PHY_REG_BASE + 0x01c0)
+#define AR9170_PHY_SFCORR_EXT_M1_THRESH 0x0000007f
+#define AR9170_PHY_SFCORR_EXT_M1_THRESH_S 0
+#define AR9170_PHY_SFCORR_EXT_M2_THRESH 0x00003f80
+#define AR9170_PHY_SFCORR_EXT_M2_THRESH_S 7
+#define AR9170_PHY_SFCORR_EXT_M1_THRESH_LOW 0x001fc000
+#define AR9170_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14
+#define AR9170_PHY_SFCORR_EXT_M2_THRESH_LOW 0x0fe00000
+#define AR9170_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21
+#define AR9170_PHY_SFCORR_SPUR_SUBCHNL_SD_S 28
+
+#define AR9170_PHY_REG_HALFGI (AR9170_PHY_REG_BASE + 0x01d0)
+#define AR9170_PHY_HALFGI_DSC_MAN 0x0007fff0
+#define AR9170_PHY_HALFGI_DSC_MAN_S 4
+#define AR9170_PHY_HALFGI_DSC_EXP 0x0000000f
+#define AR9170_PHY_HALFGI_DSC_EXP_S 0
+
+#define AR9170_PHY_REG_CHANNEL_MASK_01_30 (AR9170_PHY_REG_BASE + 0x01d4)
+#define AR9170_PHY_REG_CHANNEL_MASK_31_60 (AR9170_PHY_REG_BASE + 0x01d8)
+
+#define AR9170_PHY_REG_CHAN_INFO_MEMORY (AR9170_PHY_REG_BASE + 0x01dc)
+#define AR9170_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK 0x0001
+
+#define AR9170_PHY_REG_HEAVY_CLIP_ENABLE (AR9170_PHY_REG_BASE + 0x01e0)
+#define AR9170_PHY_REG_HEAVY_CLIP_FACTOR_RIFS (AR9170_PHY_REG_BASE + 0x01ec)
+#define AR9170_PHY_RIFS_INIT_DELAY 0x03ff0000
+
+#define AR9170_PHY_REG_CALMODE (AR9170_PHY_REG_BASE + 0x01f0)
+#define AR9170_PHY_CALMODE_IQ 0x00000000
+#define AR9170_PHY_CALMODE_ADC_GAIN 0x00000001
+#define AR9170_PHY_CALMODE_ADC_DC_PER 0x00000002
+#define AR9170_PHY_CALMODE_ADC_DC_INIT 0x00000003
+
+#define AR9170_PHY_REG_REFCLKDLY (AR9170_PHY_REG_BASE + 0x01f4)
+#define AR9170_PHY_REG_REFCLKPD (AR9170_PHY_REG_BASE + 0x01f8)
+
+
+#define AR9170_PHY_REG_CAL_MEAS_0(_i) (AR9170_PHY_REG_BASE + \
+ 0x0410 + ((_i) << 12))
+#define AR9170_PHY_REG_CAL_MEAS_1(_i) (AR9170_PHY_REG_BASE + \
+ 0x0414 \ + ((_i) << 12))
+#define AR9170_PHY_REG_CAL_MEAS_2(_i) (AR9170_PHY_REG_BASE + \
+ 0x0418 + ((_i) << 12))
+#define AR9170_PHY_REG_CAL_MEAS_3(_i) (AR9170_PHY_REG_BASE + \
+ 0x041c + ((_i) << 12))
+
+#define AR9170_PHY_REG_CURRENT_RSSI (AR9170_PHY_REG_BASE + 0x041c)
+
+#define AR9170_PHY_REG_RFBUS_GRANT (AR9170_PHY_REG_BASE + 0x0420)
+#define AR9170_PHY_RFBUS_GRANT_EN 0x00000001
+
+#define AR9170_PHY_REG_CHAN_INFO_GAIN_DIFF (AR9170_PHY_REG_BASE + 0x04f4)
+#define AR9170_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320
+
+#define AR9170_PHY_REG_CHAN_INFO_GAIN (AR9170_PHY_REG_BASE + 0x04fc)
+
+#define AR9170_PHY_REG_MODE (AR9170_PHY_REG_BASE + 0x0a00)
+#define AR9170_PHY_MODE_ASYNCFIFO 0x80
+#define AR9170_PHY_MODE_AR2133 0x08
+#define AR9170_PHY_MODE_AR5111 0x00
+#define AR9170_PHY_MODE_AR5112 0x08
+#define AR9170_PHY_MODE_DYNAMIC 0x04
+#define AR9170_PHY_MODE_RF2GHZ 0x02
+#define AR9170_PHY_MODE_RF5GHZ 0x00
+#define AR9170_PHY_MODE_CCK 0x01
+#define AR9170_PHY_MODE_OFDM 0x00
+#define AR9170_PHY_MODE_DYN_CCK_DISABLE 0x100
+
+#define AR9170_PHY_REG_CCK_TX_CTRL (AR9170_PHY_REG_BASE + 0x0a04)
+#define AR9170_PHY_CCK_TX_CTRL_JAPAN 0x00000010
+#define AR9170_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK 0x0000000c
+#define AR9170_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK_S 2
+
+#define AR9170_PHY_REG_CCK_DETECT (AR9170_PHY_REG_BASE + 0x0a08)
+#define AR9170_PHY_CCK_DETECT_WEAK_SIG_THR_CCK 0x0000003f
+#define AR9170_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S 0
+/* [12:6] settling time for antenna switch */
+#define AR9170_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001fc0
+#define AR9170_PHY_CCK_DETECT_ANT_SWITCH_TIME_S 6
+#define AR9170_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000
+#define AR9170_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV_S 13
+
+#define AR9170_PHY_REG_GAIN_2GHZ (AR9170_PHY_REG_BASE + 0x0a0c)
+#define AR9170_PHY_REG_GAIN_2GHZ_CHAIN_2 (AR9170_PHY_REG_BASE + 0x2a0c)
+#define AR9170_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00fc0000
+#define AR9170_PHY_GAIN_2GHZ_RXTX_MARGIN_S 18
+#define AR9170_PHY_GAIN_2GHZ_BSW_MARGIN 0x00003c00
+#define AR9170_PHY_GAIN_2GHZ_BSW_MARGIN_S 10
+#define AR9170_PHY_GAIN_2GHZ_BSW_ATTEN 0x0000001f
+#define AR9170_PHY_GAIN_2GHZ_BSW_ATTEN_S 0
+#define AR9170_PHY_GAIN_2GHZ_XATTEN2_MARGIN 0x003e0000
+#define AR9170_PHY_GAIN_2GHZ_XATTEN2_MARGIN_S 17
+#define AR9170_PHY_GAIN_2GHZ_XATTEN1_MARGIN 0x0001f000
+#define AR9170_PHY_GAIN_2GHZ_XATTEN1_MARGIN_S 12
+#define AR9170_PHY_GAIN_2GHZ_XATTEN2_DB 0x00000fc0
+#define AR9170_PHY_GAIN_2GHZ_XATTEN2_DB_S 6
+#define AR9170_PHY_GAIN_2GHZ_XATTEN1_DB 0x0000003f
+#define AR9170_PHY_GAIN_2GHZ_XATTEN1_DB_S 0
+
+#define AR9170_PHY_REG_CCK_RXCTRL4 (AR9170_PHY_REG_BASE + 0x0a1c)
+#define AR9170_PHY_CCK_RXCTRL4_FREQ_EST_SHORT 0x01f80000
+#define AR9170_PHY_CCK_RXCTRL4_FREQ_EST_SHORT_S 19
+
+#define AR9170_PHY_REG_DAG_CTRLCCK (AR9170_PHY_REG_BASE + 0x0a28)
+#define AR9170_REG_DAG_CTRLCCK_EN_RSSI_THR 0x00000200
+#define AR9170_REG_DAG_CTRLCCK_RSSI_THR 0x0001fc00
+#define AR9170_REG_DAG_CTRLCCK_RSSI_THR_S 10
+
+#define AR9170_PHY_REG_FORCE_CLKEN_CCK (AR9170_PHY_REG_BASE + 0x0a2c)
+#define AR9170_FORCE_CLKEN_CCK_MRC_MUX 0x00000040
+
+#define AR9170_PHY_REG_POWER_TX_RATE3 (AR9170_PHY_REG_BASE + 0x0a34)
+#define AR9170_PHY_REG_POWER_TX_RATE4 (AR9170_PHY_REG_BASE + 0x0a38)
+
+#define AR9170_PHY_REG_SCRM_SEQ_XR (AR9170_PHY_REG_BASE + 0x0a3c)
+#define AR9170_PHY_REG_HEADER_DETECT_XR (AR9170_PHY_REG_BASE + 0x0a40)
+#define AR9170_PHY_REG_CHIRP_DETECTED_XR (AR9170_PHY_REG_BASE + 0x0a44)
+#define AR9170_PHY_REG_BLUETOOTH (AR9170_PHY_REG_BASE + 0x0a54)
+
+#define AR9170_PHY_REG_TPCRG1 (AR9170_PHY_REG_BASE + 0x0a58)
+#define AR9170_PHY_TPCRG1_NUM_PD_GAIN 0x0000c000
+#define AR9170_PHY_TPCRG1_NUM_PD_GAIN_S 14
+#define AR9170_PHY_TPCRG1_PD_GAIN_1 0x00030000
+#define AR9170_PHY_TPCRG1_PD_GAIN_1_S 16
+#define AR9170_PHY_TPCRG1_PD_GAIN_2 0x000c0000
+#define AR9170_PHY_TPCRG1_PD_GAIN_2_S 18
+#define AR9170_PHY_TPCRG1_PD_GAIN_3 0x00300000
+#define AR9170_PHY_TPCRG1_PD_GAIN_3_S 20
+#define AR9170_PHY_TPCRG1_PD_CAL_ENABLE 0x00400000
+#define AR9170_PHY_TPCRG1_PD_CAL_ENABLE_S 22
+
+#define AR9170_PHY_REG_TX_PWRCTRL4 (AR9170_PHY_REG_BASE + 0x0a64)
+#define AR9170_PHY_TX_PWRCTRL_PD_AVG_VALID 0x00000001
+#define AR9170_PHY_TX_PWRCTRL_PD_AVG_VALID_S 0
+#define AR9170_PHY_TX_PWRCTRL_PD_AVG_OUT 0x000001fe
+#define AR9170_PHY_TX_PWRCTRL_PD_AVG_OUT_S 1
+
+#define AR9170_PHY_REG_ANALOG_SWAP (AR9170_PHY_REG_BASE + 0x0a68)
+#define AR9170_PHY_ANALOG_SWAP_AB 0x0001
+#define AR9170_PHY_ANALOG_SWAP_ALT_CHAIN 0x00000040
+
+#define AR9170_PHY_REG_TPCRG5 (AR9170_PHY_REG_BASE + 0x0a6c)
+#define AR9170_PHY_TPCRG5_PD_GAIN_OVERLAP 0x0000000f
+#define AR9170_PHY_TPCRG5_PD_GAIN_OVERLAP_S 0
+#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_1 0x000003f0
+#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_1_S 4
+#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_2 0x0000fc00
+#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_2_S 10
+#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_3 0x003f0000
+#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_3_S 16
+#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_4 0x0fc00000
+#define AR9170_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S 22
+
+#define AR9170_PHY_REG_TX_PWRCTRL6_0 (AR9170_PHY_REG_BASE + 0x0a70)
+#define AR9170_PHY_REG_TX_PWRCTRL6_1 (AR9170_PHY_REG_BASE + 0x1a70)
+#define AR9170_PHY_TX_PWRCTRL_ERR_EST_MODE 0x03000000
+#define AR9170_PHY_TX_PWRCTRL_ERR_EST_MODE_S 24
+
+#define AR9170_PHY_REG_TX_PWRCTRL7 (AR9170_PHY_REG_BASE + 0x0a74)
+#define AR9170_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01f80000
+#define AR9170_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19
+
+#define AR9170_PHY_REG_TX_PWRCTRL9 (AR9170_PHY_REG_BASE + 0x0a7c)
+#define AR9170_PHY_TX_DESIRED_SCALE_CCK 0x00007c00
+#define AR9170_PHY_TX_DESIRED_SCALE_CCK_S 10
+#define AR9170_PHY_TX_PWRCTRL9_RES_DC_REMOVAL 0x80000000
+#define AR9170_PHY_TX_PWRCTRL9_RES_DC_REMOVAL_S 31
+
+#define AR9170_PHY_REG_TX_GAIN_TBL1 (AR9170_PHY_REG_BASE + 0x0b00)
+#define AR9170_PHY_TX_GAIN 0x0007f000
+#define AR9170_PHY_TX_GAIN_S 12
+
+/* Carrier leak calibration control, do it after AGC calibration */
+#define AR9170_PHY_REG_CL_CAL_CTL (AR9170_PHY_REG_BASE + 0x0b58)
+#define AR9170_PHY_CL_CAL_ENABLE 0x00000002
+#define AR9170_PHY_CL_CAL_PARALLEL_CAL_ENABLE 0x00000001
+
+#define AR9170_PHY_REG_POWER_TX_RATE5 (AR9170_PHY_REG_BASE + 0x0b8c)
+#define AR9170_PHY_REG_POWER_TX_RATE6 (AR9170_PHY_REG_BASE + 0x0b90)
+
+#define AR9170_PHY_REG_CH0_TX_PWRCTRL11 (AR9170_PHY_REG_BASE + 0x0b98)
+#define AR9170_PHY_REG_CH1_TX_PWRCTRL11 (AR9170_PHY_REG_BASE + 0x1b98)
+#define AR9170_PHY_TX_CHX_PWRCTRL_OLPC_TEMP_COMP 0x0000fc00
+#define AR9170_PHY_TX_CHX_PWRCTRL_OLPC_TEMP_COMP_S 10
+
+#define AR9170_PHY_REG_CAL_CHAINMASK (AR9170_PHY_REG_BASE + 0x0b9c)
+#define AR9170_PHY_REG_VIT_MASK2_M_46_61 (AR9170_PHY_REG_BASE + 0x0ba0)
+#define AR9170_PHY_REG_MASK2_M_31_45 (AR9170_PHY_REG_BASE + 0x0ba4)
+#define AR9170_PHY_REG_MASK2_M_16_30 (AR9170_PHY_REG_BASE + 0x0ba8)
+#define AR9170_PHY_REG_MASK2_M_00_15 (AR9170_PHY_REG_BASE + 0x0bac)
+#define AR9170_PHY_REG_PILOT_MASK_01_30 (AR9170_PHY_REG_BASE + 0x0bb0)
+#define AR9170_PHY_REG_PILOT_MASK_31_60 (AR9170_PHY_REG_BASE + 0x0bb4)
+#define AR9170_PHY_REG_MASK2_P_15_01 (AR9170_PHY_REG_BASE + 0x0bb8)
+#define AR9170_PHY_REG_MASK2_P_30_16 (AR9170_PHY_REG_BASE + 0x0bbc)
+#define AR9170_PHY_REG_MASK2_P_45_31 (AR9170_PHY_REG_BASE + 0x0bc0)
+#define AR9170_PHY_REG_MASK2_P_61_45 (AR9170_PHY_REG_BASE + 0x0bc4)
+#define AR9170_PHY_REG_POWER_TX_SUB (AR9170_PHY_REG_BASE + 0x0bc8)
+#define AR9170_PHY_REG_POWER_TX_RATE7 (AR9170_PHY_REG_BASE + 0x0bcc)
+#define AR9170_PHY_REG_POWER_TX_RATE8 (AR9170_PHY_REG_BASE + 0x0bd0)
+#define AR9170_PHY_REG_POWER_TX_RATE9 (AR9170_PHY_REG_BASE + 0x0bd4)
+#define AR9170_PHY_REG_XPA_CFG (AR9170_PHY_REG_BASE + 0x0bd8)
+#define AR9170_PHY_FORCE_XPA_CFG 0x000000001
+#define AR9170_PHY_FORCE_XPA_CFG_S 0
+
+#define AR9170_PHY_REG_CH1_CCA (AR9170_PHY_REG_BASE + 0x1064)
+#define AR9170_PHY_CH1_MINCCA_PWR 0x0ff80000
+#define AR9170_PHY_CH1_MINCCA_PWR_S 19
+
+#define AR9170_PHY_REG_CH2_CCA (AR9170_PHY_REG_BASE + 0x2064)
+#define AR9170_PHY_CH2_MINCCA_PWR 0x0ff80000
+#define AR9170_PHY_CH2_MINCCA_PWR_S 19
+
+#define AR9170_PHY_REG_CH1_EXT_CCA (AR9170_PHY_REG_BASE + 0x11bc)
+#define AR9170_PHY_CH1_EXT_MINCCA_PWR 0xff800000
+#define AR9170_PHY_CH1_EXT_MINCCA_PWR_S 23
+
+#define AR9170_PHY_REG_CH2_EXT_CCA (AR9170_PHY_REG_BASE + 0x21bc)
+#define AR9170_PHY_CH2_EXT_MINCCA_PWR 0xff800000
+#define AR9170_PHY_CH2_EXT_MINCCA_PWR_S 23
+
+#endif /* __CARL9170_SHARED_PHY_H */
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
new file mode 100644
index 000000000000..939a0e96ed1f
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -0,0 +1,938 @@
+/*
+ * Atheros CARL9170 driver
+ *
+ * 802.11 & command trap routines
+ *
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.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; see the file COPYING. If not, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2007-2008 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/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/crc32.h>
+#include <net/mac80211.h>
+#include "carl9170.h"
+#include "hw.h"
+#include "cmd.h"
+
+static void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len)
+{
+ bool restart = false;
+ enum carl9170_restart_reasons reason = CARL9170_RR_NO_REASON;
+
+ if (len > 3) {
+ if (memcmp(buf, CARL9170_ERR_MAGIC, 3) == 0) {
+ ar->fw.err_counter++;
+ if (ar->fw.err_counter > 3) {
+ restart = true;
+ reason = CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS;
+ }
+ }
+
+ if (memcmp(buf, CARL9170_BUG_MAGIC, 3) == 0) {
+ ar->fw.bug_counter++;
+ restart = true;
+ reason = CARL9170_RR_FATAL_FIRMWARE_ERROR;
+ }
+ }
+
+ wiphy_info(ar->hw->wiphy, "FW: %.*s\n", len, buf);
+
+ if (restart)
+ carl9170_restart(ar, reason);
+}
+
+static void carl9170_handle_ps(struct ar9170 *ar, struct carl9170_rsp *rsp)
+{
+ u32 ps;
+ bool new_ps;
+
+ ps = le32_to_cpu(rsp->psm.state);
+
+ new_ps = (ps & CARL9170_PSM_COUNTER) != CARL9170_PSM_WAKE;
+ if (ar->ps.state != new_ps) {
+ if (!new_ps) {
+ ar->ps.sleep_ms = jiffies_to_msecs(jiffies -
+ ar->ps.last_action);
+ }
+
+ ar->ps.last_action = jiffies;
+
+ ar->ps.state = new_ps;
+ }
+}
+
+static int carl9170_check_sequence(struct ar9170 *ar, unsigned int seq)
+{
+ if (ar->cmd_seq < -1)
+ return 0;
+
+ /*
+ * Initialize Counter
+ */
+ if (ar->cmd_seq < 0)
+ ar->cmd_seq = seq;
+
+ /*
+ * The sequence is strictly monotonic increasing and it never skips!
+ *
+ * Therefore we can safely assume that whenever we received an
+ * unexpected sequence we have lost some valuable data.
+ */
+ if (seq != ar->cmd_seq) {
+ int count;
+
+ count = (seq - ar->cmd_seq) % ar->fw.cmd_bufs;
+
+ wiphy_err(ar->hw->wiphy, "lost %d command responses/traps! "
+ "w:%d g:%d\n", count, ar->cmd_seq, seq);
+
+ carl9170_restart(ar, CARL9170_RR_LOST_RSP);
+ return -EIO;
+ }
+
+ ar->cmd_seq = (ar->cmd_seq + 1) % ar->fw.cmd_bufs;
+ return 0;
+}
+
+static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)
+{
+ /*
+ * Some commands may have a variable response length
+ * and we cannot predict the correct length in advance.
+ * So we only check if we provided enough space for the data.
+ */
+ if (unlikely(ar->readlen != (len - 4))) {
+ dev_warn(&ar->udev->dev, "received invalid command response:"
+ "got %d, instead of %d\n", len - 4, ar->readlen);
+ print_hex_dump_bytes("carl9170 cmd:", DUMP_PREFIX_OFFSET,
+ ar->cmd_buf, (ar->cmd.hdr.len + 4) & 0x3f);
+ print_hex_dump_bytes("carl9170 rsp:", DUMP_PREFIX_OFFSET,
+ buffer, len);
+ /*
+ * Do not complete. The command times out,
+ * and we get a stack trace from there.
+ */
+ carl9170_restart(ar, CARL9170_RR_INVALID_RSP);
+ }
+
+ spin_lock(&ar->cmd_lock);
+ if (ar->readbuf) {
+ if (len >= 4)
+ memcpy(ar->readbuf, buffer + 4, len - 4);
+
+ ar->readbuf = NULL;
+ }
+ complete(&ar->cmd_wait);
+ spin_unlock(&ar->cmd_lock);
+}
+
+void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
+{
+ struct carl9170_rsp *cmd = (void *) buf;
+ struct ieee80211_vif *vif;
+
+ if (carl9170_check_sequence(ar, cmd->hdr.seq))
+ return;
+
+ if ((cmd->hdr.cmd & CARL9170_RSP_FLAG) != CARL9170_RSP_FLAG) {
+ if (!(cmd->hdr.cmd & CARL9170_CMD_ASYNC_FLAG))
+ carl9170_cmd_callback(ar, len, buf);
+
+ return;
+ }
+
+ if (unlikely(cmd->hdr.len != (len - 4))) {
+ if (net_ratelimit()) {
+ wiphy_err(ar->hw->wiphy, "FW: received over-/under"
+ "sized event %x (%d, but should be %d).\n",
+ cmd->hdr.cmd, cmd->hdr.len, len - 4);
+
+ print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE,
+ buf, len);
+ }
+
+ return;
+ }
+
+ /* hardware event handlers */
+ switch (cmd->hdr.cmd) {
+ case CARL9170_RSP_PRETBTT:
+ /* pre-TBTT event */
+ rcu_read_lock();
+ vif = carl9170_get_main_vif(ar);
+
+ if (!vif) {
+ rcu_read_unlock();
+ break;
+ }
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ carl9170_handle_ps(ar, cmd);
+ break;
+
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_ADHOC:
+ carl9170_update_beacon(ar, true);
+ break;
+
+ default:
+ break;
+ }
+ rcu_read_unlock();
+
+ break;
+
+
+ case CARL9170_RSP_TXCOMP:
+ /* TX status notification */
+ carl9170_tx_process_status(ar, cmd);
+ break;
+
+ case CARL9170_RSP_BEACON_CONFIG:
+ /*
+ * (IBSS) beacon send notification
+ * bytes: 04 c2 XX YY B4 B3 B2 B1
+ *
+ * XX always 80
+ * YY always 00
+ * B1-B4 "should" be the number of send out beacons.
+ */
+ break;
+
+ case CARL9170_RSP_ATIM:
+ /* End of Atim Window */
+ break;
+
+ case CARL9170_RSP_WATCHDOG:
+ /* Watchdog Interrupt */
+ carl9170_restart(ar, CARL9170_RR_WATCHDOG);
+ break;
+
+ case CARL9170_RSP_TEXT:
+ /* firmware debug */
+ carl9170_dbg_message(ar, (char *)buf + 4, len - 4);
+ break;
+
+ case CARL9170_RSP_HEXDUMP:
+ wiphy_dbg(ar->hw->wiphy, "FW: HD %d\n", len - 4);
+ print_hex_dump_bytes("FW:", DUMP_PREFIX_NONE,
+ (char *)buf + 4, len - 4);
+ break;
+
+ case CARL9170_RSP_RADAR:
+ if (!net_ratelimit())
+ break;
+
+ wiphy_info(ar->hw->wiphy, "FW: RADAR! Please report this "
+ "incident to linux-wireless@vger.kernel.org !\n");
+ break;
+
+ case CARL9170_RSP_GPIO:
+#ifdef CONFIG_CARL9170_WPC
+ if (ar->wps.pbc) {
+ bool state = !!(cmd->gpio.gpio & cpu_to_le32(
+ AR9170_GPIO_PORT_WPS_BUTTON_PRESSED));
+
+ if (state != ar->wps.pbc_state) {
+ ar->wps.pbc_state = state;
+ input_report_key(ar->wps.pbc, KEY_WPS_BUTTON,
+ state);
+ input_sync(ar->wps.pbc);
+ }
+ }
+#endif /* CONFIG_CARL9170_WPC */
+ break;
+
+ case CARL9170_RSP_BOOT:
+ complete(&ar->fw_boot_wait);
+ break;
+
+ default:
+ wiphy_err(ar->hw->wiphy, "FW: received unhandled event %x\n",
+ cmd->hdr.cmd);
+ print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len);
+ break;
+ }
+}
+
+static int carl9170_rx_mac_status(struct ar9170 *ar,
+ struct ar9170_rx_head *head, struct ar9170_rx_macstatus *mac,
+ struct ieee80211_rx_status *status)
+{
+ struct ieee80211_channel *chan;
+ u8 error, decrypt;
+
+ BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12);
+ BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4);
+
+ error = mac->error;
+
+ if (error & AR9170_RX_ERROR_WRONG_RA) {
+ if (!ar->sniffer_enabled)
+ return -EINVAL;
+ }
+
+ if (error & AR9170_RX_ERROR_PLCP) {
+ if (!(ar->filter_state & FIF_PLCPFAIL))
+ return -EINVAL;
+
+ status->flag |= RX_FLAG_FAILED_PLCP_CRC;
+ }
+
+ if (error & AR9170_RX_ERROR_FCS) {
+ ar->tx_fcs_errors++;
+
+ if (!(ar->filter_state & FIF_FCSFAIL))
+ return -EINVAL;
+
+ status->flag |= RX_FLAG_FAILED_FCS_CRC;
+ }
+
+ decrypt = ar9170_get_decrypt_type(mac);
+ if (!(decrypt & AR9170_RX_ENC_SOFTWARE) &&
+ decrypt != AR9170_ENC_ALG_NONE) {
+ if ((decrypt == AR9170_ENC_ALG_TKIP) &&
+ (error & AR9170_RX_ERROR_MMIC))
+ status->flag |= RX_FLAG_MMIC_ERROR;
+
+ status->flag |= RX_FLAG_DECRYPTED;
+ }
+
+ if (error & AR9170_RX_ERROR_DECRYPT && !ar->sniffer_enabled)
+ return -ENODATA;
+
+ error &= ~(AR9170_RX_ERROR_MMIC |
+ AR9170_RX_ERROR_FCS |
+ AR9170_RX_ERROR_WRONG_RA |
+ AR9170_RX_ERROR_DECRYPT |
+ AR9170_RX_ERROR_PLCP);
+
+ /* drop any other error frames */
+ if (unlikely(error)) {
+ /* TODO: update netdevice's RX dropped/errors statistics */
+
+ if (net_ratelimit())
+ wiphy_dbg(ar->hw->wiphy, "received frame with "
+ "suspicious error code (%#x).\n", error);
+
+ return -EINVAL;
+ }
+
+ chan = ar->channel;
+ if (chan) {
+ status->band = chan->band;
+ status->freq = chan->center_freq;
+ }
+
+ switch (mac->status & AR9170_RX_STATUS_MODULATION) {
+ case AR9170_RX_STATUS_MODULATION_CCK:
+ if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE)
+ status->flag |= RX_FLAG_SHORTPRE;
+ switch (head->plcp[0]) {
+ case AR9170_RX_PHY_RATE_CCK_1M:
+ status->rate_idx = 0;
+ break;
+ case AR9170_RX_PHY_RATE_CCK_2M:
+ status->rate_idx = 1;
+ break;
+ case AR9170_RX_PHY_RATE_CCK_5M:
+ status->rate_idx = 2;
+ break;
+ case AR9170_RX_PHY_RATE_CCK_11M:
+ status->rate_idx = 3;
+ break;
+ default:
+ if (net_ratelimit()) {
+ wiphy_err(ar->hw->wiphy, "invalid plcp cck "
+ "rate (%x).\n", head->plcp[0]);
+ }
+
+ return -EINVAL;
+ }
+ break;
+
+ case AR9170_RX_STATUS_MODULATION_DUPOFDM:
+ case AR9170_RX_STATUS_MODULATION_OFDM:
+ switch (head->plcp[0] & 0xf) {
+ case AR9170_TXRX_PHY_RATE_OFDM_6M:
+ status->rate_idx = 0;
+ break;
+ case AR9170_TXRX_PHY_RATE_OFDM_9M:
+ status->rate_idx = 1;
+ break;
+ case AR9170_TXRX_PHY_RATE_OFDM_12M:
+ status->rate_idx = 2;
+ break;
+ case AR9170_TXRX_PHY_RATE_OFDM_18M:
+ status->rate_idx = 3;
+ break;
+ case AR9170_TXRX_PHY_RATE_OFDM_24M:
+ status->rate_idx = 4;
+ break;
+ case AR9170_TXRX_PHY_RATE_OFDM_36M:
+ status->rate_idx = 5;
+ break;
+ case AR9170_TXRX_PHY_RATE_OFDM_48M:
+ status->rate_idx = 6;
+ break;
+ case AR9170_TXRX_PHY_RATE_OFDM_54M:
+ status->rate_idx = 7;
+ break;
+ default:
+ if (net_ratelimit()) {
+ wiphy_err(ar->hw->wiphy, "invalid plcp ofdm "
+ "rate (%x).\n", head->plcp[0]);
+ }
+
+ return -EINVAL;
+ }
+ if (status->band == IEEE80211_BAND_2GHZ)
+ status->rate_idx += 4;
+ break;
+
+ case AR9170_RX_STATUS_MODULATION_HT:
+ if (head->plcp[3] & 0x80)
+ status->flag |= RX_FLAG_40MHZ;
+ if (head->plcp[6] & 0x80)
+ status->flag |= RX_FLAG_SHORT_GI;
+
+ status->rate_idx = clamp(0, 75, head->plcp[3] & 0x7f);
+ status->flag |= RX_FLAG_HT;
+ break;
+
+ default:
+ BUG();
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
+static void carl9170_rx_phy_status(struct ar9170 *ar,
+ struct ar9170_rx_phystatus *phy, struct ieee80211_rx_status *status)
+{
+ int i;
+
+ BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20);
+
+ for (i = 0; i < 3; i++)
+ if (phy->rssi[i] != 0x80)
+ status->antenna |= BIT(i);
+
+ /* post-process RSSI */
+ for (i = 0; i < 7; i++)
+ if (phy->rssi[i] & 0x80)
+ phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f;
+
+ /* TODO: we could do something with phy_errors */
+ status->signal = ar->noise[0] + phy->rssi_combined;
+}
+
+static struct sk_buff *carl9170_rx_copy_data(u8 *buf, int len)
+{
+ struct sk_buff *skb;
+ int reserved = 0;
+ struct ieee80211_hdr *hdr = (void *) buf;
+
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
+ u8 *qc = ieee80211_get_qos_ctl(hdr);
+ reserved += NET_IP_ALIGN;
+
+ if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
+ reserved += NET_IP_ALIGN;
+ }
+
+ if (ieee80211_has_a4(hdr->frame_control))
+ reserved += NET_IP_ALIGN;
+
+ reserved = 32 + (reserved & NET_IP_ALIGN);
+
+ skb = dev_alloc_skb(len + reserved);
+ if (likely(skb)) {
+ skb_reserve(skb, reserved);
+ memcpy(skb_put(skb, len), buf, len);
+ }
+
+ return skb;
+}
+
+static u8 *carl9170_find_ie(u8 *data, unsigned int len, u8 ie)
+{
+ struct ieee80211_mgmt *mgmt = (void *)data;
+ u8 *pos, *end;
+
+ pos = (u8 *)mgmt->u.beacon.variable;
+ end = data + len;
+ while (pos < end) {
+ if (pos + 2 + pos[1] > end)
+ return NULL;
+
+ if (pos[0] == ie)
+ return pos;
+
+ pos += 2 + pos[1];
+ }
+ return NULL;
+}
+
+/*
+ * NOTE:
+ *
+ * The firmware is in charge of waking up the device just before
+ * the AP is expected to transmit the next beacon.
+ *
+ * This leaves the driver with the important task of deciding when
+ * to set the PHY back to bed again.
+ */
+static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
+{
+ struct ieee80211_hdr *hdr = (void *) data;
+ struct ieee80211_tim_ie *tim_ie;
+ u8 *tim;
+ u8 tim_len;
+ bool cam;
+
+ if (likely(!(ar->hw->conf.flags & IEEE80211_CONF_PS)))
+ return;
+
+ /* check if this really is a beacon */
+ if (!ieee80211_is_beacon(hdr->frame_control))
+ return;
+
+ /* min. beacon length + FCS_LEN */
+ if (len <= 40 + FCS_LEN)
+ return;
+
+ /* and only beacons from the associated BSSID, please */
+ if (compare_ether_addr(hdr->addr3, ar->common.curbssid) ||
+ !ar->common.curaid)
+ return;
+
+ ar->ps.last_beacon = jiffies;
+
+ tim = carl9170_find_ie(data, len - FCS_LEN, WLAN_EID_TIM);
+ if (!tim)
+ return;
+
+ if (tim[1] < sizeof(*tim_ie))
+ return;
+
+ tim_len = tim[1];
+ tim_ie = (struct ieee80211_tim_ie *) &tim[2];
+
+ if (!WARN_ON_ONCE(!ar->hw->conf.ps_dtim_period))
+ ar->ps.dtim_counter = (tim_ie->dtim_count - 1) %
+ ar->hw->conf.ps_dtim_period;
+
+ /* Check whenever the PHY can be turned off again. */
+
+ /* 1. What about buffered unicast traffic for our AID? */
+ cam = ieee80211_check_tim(tim_ie, tim_len, ar->common.curaid);
+
+ /* 2. Maybe the AP wants to send multicast/broadcast data? */
+ cam = !!(tim_ie->bitmap_ctrl & 0x01);
+
+ if (!cam) {
+ /* back to low-power land. */
+ ar->ps.off_override &= ~PS_OFF_BCN;
+ carl9170_ps_check(ar);
+ } else {
+ /* force CAM */
+ ar->ps.off_override |= PS_OFF_BCN;
+ }
+}
+
+static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms)
+{
+ __le16 fc;
+
+ if ((ms & AR9170_RX_STATUS_MPDU) == AR9170_RX_STATUS_MPDU_SINGLE) {
+ /*
+ * This frame is not part of an aMPDU.
+ * Therefore it is not subjected to any
+ * of the following content restrictions.
+ */
+ return true;
+ }
+
+ /*
+ * "802.11n - 7.4a.3 A-MPDU contents" describes in which contexts
+ * certain frame types can be part of an aMPDU.
+ *
+ * In order to keep the processing cost down, I opted for a
+ * stateless filter solely based on the frame control field.
+ */
+
+ fc = ((struct ieee80211_hdr *)buf)->frame_control;
+ if (ieee80211_is_data_qos(fc) && ieee80211_is_data_present(fc))
+ return true;
+
+ if (ieee80211_is_ack(fc) || ieee80211_is_back(fc) ||
+ ieee80211_is_back_req(fc))
+ return true;
+
+ if (ieee80211_is_action(fc))
+ return true;
+
+ return false;
+}
+
+/*
+ * If the frame alignment is right (or the kernel has
+ * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there
+ * is only a single MPDU in the USB frame, then we could
+ * submit to mac80211 the SKB directly. However, since
+ * there may be multiple packets in one SKB in stream
+ * mode, and we need to observe the proper ordering,
+ * this is non-trivial.
+ */
+
+static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
+{
+ struct ar9170_rx_head *head;
+ struct ar9170_rx_macstatus *mac;
+ struct ar9170_rx_phystatus *phy = NULL;
+ struct ieee80211_rx_status status;
+ struct sk_buff *skb;
+ int mpdu_len;
+ u8 mac_status;
+
+ if (!IS_STARTED(ar))
+ return;
+
+ if (unlikely(len < sizeof(*mac)))
+ goto drop;
+
+ mpdu_len = len - sizeof(*mac);
+
+ mac = (void *)(buf + mpdu_len);
+ mac_status = mac->status;
+ switch (mac_status & AR9170_RX_STATUS_MPDU) {
+ case AR9170_RX_STATUS_MPDU_FIRST:
+ /* Aggregated MPDUs start with an PLCP header */
+ if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) {
+ head = (void *) buf;
+
+ /*
+ * The PLCP header needs to be cached for the
+ * following MIDDLE + LAST A-MPDU packets.
+ *
+ * So, if you are wondering why all frames seem
+ * to share a common RX status information,
+ * then you have the answer right here...
+ */
+ memcpy(&ar->rx_plcp, (void *) buf,
+ sizeof(struct ar9170_rx_head));
+
+ mpdu_len -= sizeof(struct ar9170_rx_head);
+ buf += sizeof(struct ar9170_rx_head);
+
+ ar->rx_has_plcp = true;
+ } else {
+ if (net_ratelimit()) {
+ wiphy_err(ar->hw->wiphy, "plcp info "
+ "is clipped.\n");
+ }
+
+ goto drop;
+ }
+ break;
+
+ case AR9170_RX_STATUS_MPDU_LAST:
+ /*
+ * The last frame of an A-MPDU has an extra tail
+ * which does contain the phy status of the whole
+ * aggregate.
+ */
+
+ if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) {
+ mpdu_len -= sizeof(struct ar9170_rx_phystatus);
+ phy = (void *)(buf + mpdu_len);
+ } else {
+ if (net_ratelimit()) {
+ wiphy_err(ar->hw->wiphy, "frame tail "
+ "is clipped.\n");
+ }
+
+ goto drop;
+ }
+
+ case AR9170_RX_STATUS_MPDU_MIDDLE:
+ /* These are just data + mac status */
+ if (unlikely(!ar->rx_has_plcp)) {
+ if (!net_ratelimit())
+ return;
+
+ wiphy_err(ar->hw->wiphy, "rx stream does not start "
+ "with a first_mpdu frame tag.\n");
+
+ goto drop;
+ }
+
+ head = &ar->rx_plcp;
+ break;
+
+ case AR9170_RX_STATUS_MPDU_SINGLE:
+ /* single mpdu has both: plcp (head) and phy status (tail) */
+ head = (void *) buf;
+
+ mpdu_len -= sizeof(struct ar9170_rx_head);
+ mpdu_len -= sizeof(struct ar9170_rx_phystatus);
+
+ buf += sizeof(struct ar9170_rx_head);
+ phy = (void *)(buf + mpdu_len);
+ break;
+
+ default:
+ BUG_ON(1);
+ break;
+ }
+
+ /* FC + DU + RA + FCS */
+ if (unlikely(mpdu_len < (2 + 2 + ETH_ALEN + FCS_LEN)))
+ goto drop;
+
+ memset(&status, 0, sizeof(status));
+ if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status)))
+ goto drop;
+
+ if (!carl9170_ampdu_check(ar, buf, mac_status))
+ goto drop;
+
+ if (phy)
+ carl9170_rx_phy_status(ar, phy, &status);
+
+ carl9170_ps_beacon(ar, buf, mpdu_len);
+
+ skb = carl9170_rx_copy_data(buf, mpdu_len);
+ if (!skb)
+ goto drop;
+
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx(ar->hw, skb);
+ return;
+
+drop:
+ ar->rx_dropped++;
+}
+
+static void carl9170_rx_untie_cmds(struct ar9170 *ar, const u8 *respbuf,
+ const unsigned int resplen)
+{
+ struct carl9170_rsp *cmd;
+ int i = 0;
+
+ while (i < resplen) {
+ cmd = (void *) &respbuf[i];
+
+ i += cmd->hdr.len + 4;
+ if (unlikely(i > resplen))
+ break;
+
+ carl9170_handle_command_response(ar, cmd, cmd->hdr.len + 4);
+ }
+
+ if (unlikely(i != resplen)) {
+ if (!net_ratelimit())
+ return;
+
+ wiphy_err(ar->hw->wiphy, "malformed firmware trap:\n");
+ print_hex_dump_bytes("rxcmd:", DUMP_PREFIX_OFFSET,
+ respbuf, resplen);
+ }
+}
+
+static void __carl9170_rx(struct ar9170 *ar, u8 *buf, unsigned int len)
+{
+ unsigned int i = 0;
+
+ /* weird thing, but this is the same in the original driver */
+ while (len > 2 && i < 12 && buf[0] == 0xff && buf[1] == 0xff) {
+ i += 2;
+ len -= 2;
+ buf += 2;
+ }
+
+ if (unlikely(len < 4))
+ return;
+
+ /* found the 6 * 0xffff marker? */
+ if (i == 12)
+ carl9170_rx_untie_cmds(ar, buf, len);
+ else
+ carl9170_handle_mpdu(ar, buf, len);
+}
+
+static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len)
+{
+ unsigned int tlen, wlen = 0, clen = 0;
+ struct ar9170_stream *rx_stream;
+ u8 *tbuf;
+
+ tbuf = buf;
+ tlen = len;
+
+ while (tlen >= 4) {
+ rx_stream = (void *) tbuf;
+ clen = le16_to_cpu(rx_stream->length);
+ wlen = ALIGN(clen, 4);
+
+ /* check if this is stream has a valid tag.*/
+ if (rx_stream->tag != cpu_to_le16(AR9170_RX_STREAM_TAG)) {
+ /*
+ * TODO: handle the highly unlikely event that the
+ * corrupted stream has the TAG at the right position.
+ */
+
+ /* check if the frame can be repaired. */
+ if (!ar->rx_failover_missing) {
+
+ /* this is not "short read". */
+ if (net_ratelimit()) {
+ wiphy_err(ar->hw->wiphy,
+ "missing tag!\n");
+ }
+
+ __carl9170_rx(ar, tbuf, tlen);
+ return;
+ }
+
+ if (ar->rx_failover_missing > tlen) {
+ if (net_ratelimit()) {
+ wiphy_err(ar->hw->wiphy,
+ "possible multi "
+ "stream corruption!\n");
+ goto err_telluser;
+ } else {
+ goto err_silent;
+ }
+ }
+
+ memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen);
+ ar->rx_failover_missing -= tlen;
+
+ if (ar->rx_failover_missing <= 0) {
+ /*
+ * nested carl9170_rx_stream call!
+ *
+ * termination is guranteed, even when the
+ * combined frame also have an element with
+ * a bad tag.
+ */
+
+ ar->rx_failover_missing = 0;
+ carl9170_rx_stream(ar, ar->rx_failover->data,
+ ar->rx_failover->len);
+
+ skb_reset_tail_pointer(ar->rx_failover);
+ skb_trim(ar->rx_failover, 0);
+ }
+
+ return;
+ }
+
+ /* check if stream is clipped */
+ if (wlen > tlen - 4) {
+ if (ar->rx_failover_missing) {
+ /* TODO: handle double stream corruption. */
+ if (net_ratelimit()) {
+ wiphy_err(ar->hw->wiphy, "double rx "
+ "stream corruption!\n");
+ goto err_telluser;
+ } else {
+ goto err_silent;
+ }
+ }
+
+ /*
+ * save incomplete data set.
+ * the firmware will resend the missing bits when
+ * the rx - descriptor comes round again.
+ */
+
+ memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen);
+ ar->rx_failover_missing = clen - tlen;
+ return;
+ }
+ __carl9170_rx(ar, rx_stream->payload, clen);
+
+ tbuf += wlen + 4;
+ tlen -= wlen + 4;
+ }
+
+ if (tlen) {
+ if (net_ratelimit()) {
+ wiphy_err(ar->hw->wiphy, "%d bytes of unprocessed "
+ "data left in rx stream!\n", tlen);
+ }
+
+ goto err_telluser;
+ }
+
+ return;
+
+err_telluser:
+ wiphy_err(ar->hw->wiphy, "damaged RX stream data [want:%d, "
+ "data:%d, rx:%d, pending:%d ]\n", clen, wlen, tlen,
+ ar->rx_failover_missing);
+
+ if (ar->rx_failover_missing)
+ print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET,
+ ar->rx_failover->data,
+ ar->rx_failover->len);
+
+ print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET,
+ buf, len);
+
+ wiphy_err(ar->hw->wiphy, "please check your hardware and cables, if "
+ "you see this message frequently.\n");
+
+err_silent:
+ if (ar->rx_failover_missing) {
+ skb_reset_tail_pointer(ar->rx_failover);
+ skb_trim(ar->rx_failover, 0);
+ ar->rx_failover_missing = 0;
+ }
+}
+
+void carl9170_rx(struct ar9170 *ar, void *buf, unsigned int len)
+{
+ if (ar->fw.rx_stream)
+ carl9170_rx_stream(ar, buf, len);
+ else
+ __carl9170_rx(ar, buf, len);
+}
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
new file mode 100644
index 000000000000..b575c865142d
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -0,0 +1,1335 @@
+/*
+ * Atheros CARL9170 driver
+ *
+ * 802.11 xmit & status routines
+ *
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.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; see the file COPYING. If not, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2007-2008 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/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+#include "carl9170.h"
+#include "hw.h"
+#include "cmd.h"
+
+static inline unsigned int __carl9170_get_queue(struct ar9170 *ar,
+ unsigned int queue)
+{
+ if (unlikely(modparam_noht)) {
+ return queue;
+ } else {
+ /*
+ * This is just another workaround, until
+ * someone figures out how to get QoS and
+ * AMPDU to play nicely together.
+ */
+
+ return 2; /* AC_BE */
+ }
+}
+
+static inline unsigned int carl9170_get_queue(struct ar9170 *ar,
+ struct sk_buff *skb)
+{
+ return __carl9170_get_queue(ar, skb_get_queue_mapping(skb));
+}
+
+static bool is_mem_full(struct ar9170 *ar)
+{
+ return (DIV_ROUND_UP(IEEE80211_MAX_FRAME_LEN, ar->fw.mem_block_size) >
+ atomic_read(&ar->mem_free_blocks));
+}
+
+static void carl9170_tx_accounting(struct ar9170 *ar, struct sk_buff *skb)
+{
+ int queue, i;
+ bool mem_full;
+
+ atomic_inc(&ar->tx_total_queued);
+
+ queue = skb_get_queue_mapping(skb);
+ spin_lock_bh(&ar->tx_stats_lock);
+
+ /*
+ * The driver has to accept the frame, regardless if the queue is
+ * full to the brim, or not. We have to do the queuing internally,
+ * since mac80211 assumes that a driver which can operate with
+ * aggregated frames does not reject frames for this reason.
+ */
+ ar->tx_stats[queue].len++;
+ ar->tx_stats[queue].count++;
+
+ mem_full = is_mem_full(ar);
+ for (i = 0; i < ar->hw->queues; i++) {
+ if (mem_full || ar->tx_stats[i].len >= ar->tx_stats[i].limit) {
+ ieee80211_stop_queue(ar->hw, i);
+ ar->queue_stop_timeout[i] = jiffies;
+ }
+ }
+
+ spin_unlock_bh(&ar->tx_stats_lock);
+}
+
+static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *txinfo;
+ int queue;
+
+ txinfo = IEEE80211_SKB_CB(skb);
+ queue = skb_get_queue_mapping(skb);
+
+ spin_lock_bh(&ar->tx_stats_lock);
+
+ ar->tx_stats[queue].len--;
+
+ if (!is_mem_full(ar)) {
+ unsigned int i;
+ for (i = 0; i < ar->hw->queues; i++) {
+ if (ar->tx_stats[i].len >= CARL9170_NUM_TX_LIMIT_SOFT)
+ continue;
+
+ if (ieee80211_queue_stopped(ar->hw, i)) {
+ unsigned long tmp;
+
+ tmp = jiffies - ar->queue_stop_timeout[i];
+ if (tmp > ar->max_queue_stop_timeout[i])
+ ar->max_queue_stop_timeout[i] = tmp;
+ }
+
+ ieee80211_wake_queue(ar->hw, i);
+ }
+ }
+
+ spin_unlock_bh(&ar->tx_stats_lock);
+ if (atomic_dec_and_test(&ar->tx_total_queued))
+ complete(&ar->tx_flush);
+}
+
+static int carl9170_alloc_dev_space(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct _carl9170_tx_superframe *super = (void *) skb->data;
+ unsigned int chunks;
+ int cookie = -1;
+
+ atomic_inc(&ar->mem_allocs);
+
+ chunks = DIV_ROUND_UP(skb->len, ar->fw.mem_block_size);
+ if (unlikely(atomic_sub_return(chunks, &ar->mem_free_blocks) < 0)) {
+ atomic_add(chunks, &ar->mem_free_blocks);
+ return -ENOSPC;
+ }
+
+ spin_lock_bh(&ar->mem_lock);
+ cookie = bitmap_find_free_region(ar->mem_bitmap, ar->fw.mem_blocks, 0);
+ spin_unlock_bh(&ar->mem_lock);
+
+ if (unlikely(cookie < 0)) {
+ atomic_add(chunks, &ar->mem_free_blocks);
+ return -ENOSPC;
+ }
+
+ super = (void *) skb->data;
+
+ /*
+ * Cookie #0 serves two special purposes:
+ * 1. The firmware might use it generate BlockACK frames
+ * in responds of an incoming BlockAckReqs.
+ *
+ * 2. Prevent double-free bugs.
+ */
+ super->s.cookie = (u8) cookie + 1;
+ return 0;
+}
+
+static void carl9170_release_dev_space(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct _carl9170_tx_superframe *super = (void *) skb->data;
+ int cookie;
+
+ /* make a local copy of the cookie */
+ cookie = super->s.cookie;
+ /* invalidate cookie */
+ super->s.cookie = 0;
+
+ /*
+ * Do a out-of-bounds check on the cookie:
+ *
+ * * cookie "0" is reserved and won't be assigned to any
+ * out-going frame. Internally however, it is used to
+ * mark no longer/un-accounted frames and serves as a
+ * cheap way of preventing frames from being freed
+ * twice by _accident_. NB: There is a tiny race...
+ *
+ * * obviously, cookie number is limited by the amount
+ * of available memory blocks, so the number can
+ * never execeed the mem_blocks count.
+ */
+ if (unlikely(WARN_ON_ONCE(cookie == 0) ||
+ WARN_ON_ONCE(cookie > ar->fw.mem_blocks)))
+ return;
+
+ atomic_add(DIV_ROUND_UP(skb->len, ar->fw.mem_block_size),
+ &ar->mem_free_blocks);
+
+ spin_lock_bh(&ar->mem_lock);
+ bitmap_release_region(ar->mem_bitmap, cookie - 1, 0);
+ spin_unlock_bh(&ar->mem_lock);
+}
+
+/* Called from any context */
+static void carl9170_tx_release(struct kref *ref)
+{
+ struct ar9170 *ar;
+ struct carl9170_tx_info *arinfo;
+ struct ieee80211_tx_info *txinfo;
+ struct sk_buff *skb;
+
+ arinfo = container_of(ref, struct carl9170_tx_info, ref);
+ txinfo = container_of((void *) arinfo, struct ieee80211_tx_info,
+ rate_driver_data);
+ skb = container_of((void *) txinfo, struct sk_buff, cb);
+
+ ar = arinfo->ar;
+ if (WARN_ON_ONCE(!ar))
+ return;
+
+ BUILD_BUG_ON(
+ offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23);
+
+ memset(&txinfo->status.ampdu_ack_len, 0,
+ sizeof(struct ieee80211_tx_info) -
+ offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
+
+ if (atomic_read(&ar->tx_total_queued))
+ ar->tx_schedule = true;
+
+ if (txinfo->flags & IEEE80211_TX_CTL_AMPDU) {
+ if (!atomic_read(&ar->tx_ampdu_upload))
+ ar->tx_ampdu_schedule = true;
+
+ if (txinfo->flags & IEEE80211_TX_STAT_AMPDU) {
+ txinfo->status.ampdu_len = txinfo->pad[0];
+ txinfo->status.ampdu_ack_len = txinfo->pad[1];
+ txinfo->pad[0] = txinfo->pad[1] = 0;
+ } else if (txinfo->flags & IEEE80211_TX_STAT_ACK) {
+ /*
+ * drop redundant tx_status reports:
+ *
+ * 1. ampdu_ack_len of the final tx_status does
+ * include the feedback of this particular frame.
+ *
+ * 2. tx_status_irqsafe only queues up to 128
+ * tx feedback reports and discards the rest.
+ *
+ * 3. minstrel_ht is picky, it only accepts
+ * reports of frames with the TX_STATUS_AMPDU flag.
+ */
+
+ dev_kfree_skb_any(skb);
+ return;
+ } else {
+ /*
+ * Frame has failed, but we want to keep it in
+ * case it was lost due to a power-state
+ * transition.
+ */
+ }
+ }
+
+ skb_pull(skb, sizeof(struct _carl9170_tx_superframe));
+ ieee80211_tx_status_irqsafe(ar->hw, skb);
+}
+
+void carl9170_tx_get_skb(struct sk_buff *skb)
+{
+ struct carl9170_tx_info *arinfo = (void *)
+ (IEEE80211_SKB_CB(skb))->rate_driver_data;
+ kref_get(&arinfo->ref);
+}
+
+int carl9170_tx_put_skb(struct sk_buff *skb)
+{
+ struct carl9170_tx_info *arinfo = (void *)
+ (IEEE80211_SKB_CB(skb))->rate_driver_data;
+
+ return kref_put(&arinfo->ref, carl9170_tx_release);
+}
+
+/* Caller must hold the tid_info->lock & rcu_read_lock */
+static void carl9170_tx_shift_bm(struct ar9170 *ar,
+ struct carl9170_sta_tid *tid_info, u16 seq)
+{
+ u16 off;
+
+ off = SEQ_DIFF(seq, tid_info->bsn);
+
+ if (WARN_ON_ONCE(off >= CARL9170_BAW_BITS))
+ return;
+
+ /*
+ * Sanity check. For each MPDU we set the bit in bitmap and
+ * clear it once we received the tx_status.
+ * But if the bit is already cleared then we've been bitten
+ * by a bug.
+ */
+ WARN_ON_ONCE(!test_and_clear_bit(off, tid_info->bitmap));
+
+ off = SEQ_DIFF(tid_info->snx, tid_info->bsn);
+ if (WARN_ON_ONCE(off >= CARL9170_BAW_BITS))
+ return;
+
+ if (!bitmap_empty(tid_info->bitmap, off))
+ off = find_first_bit(tid_info->bitmap, off);
+
+ tid_info->bsn += off;
+ tid_info->bsn &= 0x0fff;
+
+ bitmap_shift_right(tid_info->bitmap, tid_info->bitmap,
+ off, CARL9170_BAW_BITS);
+}
+
+static void carl9170_tx_status_process_ampdu(struct ar9170 *ar,
+ struct sk_buff *skb, struct ieee80211_tx_info *txinfo)
+{
+ struct _carl9170_tx_superframe *super = (void *) skb->data;
+ struct ieee80211_hdr *hdr = (void *) super->frame_data;
+ struct ieee80211_tx_info *tx_info;
+ struct carl9170_tx_info *ar_info;
+ struct carl9170_sta_info *sta_info;
+ struct ieee80211_sta *sta;
+ struct carl9170_sta_tid *tid_info;
+ struct ieee80211_vif *vif;
+ unsigned int vif_id;
+ u8 tid;
+
+ if (!(txinfo->flags & IEEE80211_TX_CTL_AMPDU) ||
+ txinfo->flags & IEEE80211_TX_CTL_INJECTED)
+ return;
+
+ tx_info = IEEE80211_SKB_CB(skb);
+ ar_info = (void *) tx_info->rate_driver_data;
+
+ vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >>
+ CARL9170_TX_SUPER_MISC_VIF_ID_S;
+
+ if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC))
+ return;
+
+ rcu_read_lock();
+ vif = rcu_dereference(ar->vif_priv[vif_id].vif);
+ if (unlikely(!vif))
+ goto out_rcu;
+
+ /*
+ * Normally we should use wrappers like ieee80211_get_DA to get
+ * the correct peer ieee80211_sta.
+ *
+ * But there is a problem with indirect traffic (broadcasts, or
+ * data which is designated for other stations) in station mode.
+ * The frame will be directed to the AP for distribution and not
+ * to the actual destination.
+ */
+ sta = ieee80211_find_sta(vif, hdr->addr1);
+ if (unlikely(!sta))
+ goto out_rcu;
+
+ tid = get_tid_h(hdr);
+
+ sta_info = (void *) sta->drv_priv;
+ tid_info = rcu_dereference(sta_info->agg[tid]);
+ if (!tid_info)
+ goto out_rcu;
+
+ spin_lock_bh(&tid_info->lock);
+ if (likely(tid_info->state >= CARL9170_TID_STATE_IDLE))
+ carl9170_tx_shift_bm(ar, tid_info, get_seq_h(hdr));
+
+ if (sta_info->stats[tid].clear) {
+ sta_info->stats[tid].clear = false;
+ sta_info->stats[tid].ampdu_len = 0;
+ sta_info->stats[tid].ampdu_ack_len = 0;
+ }
+
+ sta_info->stats[tid].ampdu_len++;
+ if (txinfo->status.rates[0].count == 1)
+ sta_info->stats[tid].ampdu_ack_len++;
+
+ if (super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_IMM_BA)) {
+ txinfo->pad[0] = sta_info->stats[tid].ampdu_len;
+ txinfo->pad[1] = sta_info->stats[tid].ampdu_ack_len;
+ txinfo->flags |= IEEE80211_TX_STAT_AMPDU;
+ sta_info->stats[tid].clear = true;
+ }
+ spin_unlock_bh(&tid_info->lock);
+
+out_rcu:
+ rcu_read_unlock();
+}
+
+void carl9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
+ const bool success)
+{
+ struct ieee80211_tx_info *txinfo;
+
+ carl9170_tx_accounting_free(ar, skb);
+
+ txinfo = IEEE80211_SKB_CB(skb);
+
+ if (success)
+ txinfo->flags |= IEEE80211_TX_STAT_ACK;
+ else
+ ar->tx_ack_failures++;
+
+ if (txinfo->flags & IEEE80211_TX_CTL_AMPDU)
+ carl9170_tx_status_process_ampdu(ar, skb, txinfo);
+
+ carl9170_tx_put_skb(skb);
+}
+
+/* This function may be called form any context */
+void carl9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
+
+ atomic_dec(&ar->tx_total_pending);
+
+ if (txinfo->flags & IEEE80211_TX_CTL_AMPDU)
+ atomic_dec(&ar->tx_ampdu_upload);
+
+ if (carl9170_tx_put_skb(skb))
+ tasklet_hi_schedule(&ar->usb_tasklet);
+}
+
+static struct sk_buff *carl9170_get_queued_skb(struct ar9170 *ar, u8 cookie,
+ struct sk_buff_head *queue)
+{
+ struct sk_buff *skb;
+
+ spin_lock_bh(&queue->lock);
+ skb_queue_walk(queue, skb) {
+ struct _carl9170_tx_superframe *txc = (void *) skb->data;
+
+ if (txc->s.cookie != cookie)
+ continue;
+
+ __skb_unlink(skb, queue);
+ spin_unlock_bh(&queue->lock);
+
+ carl9170_release_dev_space(ar, skb);
+ return skb;
+ }
+ spin_unlock_bh(&queue->lock);
+
+ return NULL;
+}
+
+static void carl9170_tx_fill_rateinfo(struct ar9170 *ar, unsigned int rix,
+ unsigned int tries, struct ieee80211_tx_info *txinfo)
+{
+ unsigned int i;
+
+ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+ if (txinfo->status.rates[i].idx < 0)
+ break;
+
+ if (i == rix) {
+ txinfo->status.rates[i].count = tries;
+ i++;
+ break;
+ }
+ }
+
+ for (; i < IEEE80211_TX_MAX_RATES; i++) {
+ txinfo->status.rates[i].idx = -1;
+ txinfo->status.rates[i].count = 0;
+ }
+}
+
+static void carl9170_check_queue_stop_timeout(struct ar9170 *ar)
+{
+ int i;
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *txinfo;
+ struct carl9170_tx_info *arinfo;
+ bool restart = false;
+
+ for (i = 0; i < ar->hw->queues; i++) {
+ spin_lock_bh(&ar->tx_status[i].lock);
+
+ skb = skb_peek(&ar->tx_status[i]);
+
+ if (!skb)
+ goto next;
+
+ txinfo = IEEE80211_SKB_CB(skb);
+ arinfo = (void *) txinfo->rate_driver_data;
+
+ if (time_is_before_jiffies(arinfo->timeout +
+ msecs_to_jiffies(CARL9170_QUEUE_STUCK_TIMEOUT)) == true)
+ restart = true;
+
+next:
+ spin_unlock_bh(&ar->tx_status[i].lock);
+ }
+
+ if (restart) {
+ /*
+ * At least one queue has been stuck for long enough.
+ * Give the device a kick and hope it gets back to
+ * work.
+ *
+ * possible reasons may include:
+ * - frames got lost/corrupted (bad connection to the device)
+ * - stalled rx processing/usb controller hiccups
+ * - firmware errors/bugs
+ * - every bug you can think of.
+ * - all bugs you can't...
+ * - ...
+ */
+ carl9170_restart(ar, CARL9170_RR_STUCK_TX);
+ }
+}
+
+void carl9170_tx_janitor(struct work_struct *work)
+{
+ struct ar9170 *ar = container_of(work, struct ar9170,
+ tx_janitor.work);
+ if (!IS_STARTED(ar))
+ return;
+
+ ar->tx_janitor_last_run = jiffies;
+
+ carl9170_check_queue_stop_timeout(ar);
+
+ if (!atomic_read(&ar->tx_total_queued))
+ return;
+
+ ieee80211_queue_delayed_work(ar->hw, &ar->tx_janitor,
+ msecs_to_jiffies(CARL9170_TX_TIMEOUT));
+}
+
+static void __carl9170_tx_process_status(struct ar9170 *ar,
+ const uint8_t cookie, const uint8_t info)
+{
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *txinfo;
+ struct carl9170_tx_info *arinfo;
+ unsigned int r, t, q;
+ bool success = true;
+
+ q = ar9170_qmap[info & CARL9170_TX_STATUS_QUEUE];
+
+ skb = carl9170_get_queued_skb(ar, cookie, &ar->tx_status[q]);
+ if (!skb) {
+ /*
+ * We have lost the race to another thread.
+ */
+
+ return ;
+ }
+
+ txinfo = IEEE80211_SKB_CB(skb);
+ arinfo = (void *) txinfo->rate_driver_data;
+
+ if (!(info & CARL9170_TX_STATUS_SUCCESS))
+ success = false;
+
+ r = (info & CARL9170_TX_STATUS_RIX) >> CARL9170_TX_STATUS_RIX_S;
+ t = (info & CARL9170_TX_STATUS_TRIES) >> CARL9170_TX_STATUS_TRIES_S;
+
+ carl9170_tx_fill_rateinfo(ar, r, t, txinfo);
+ carl9170_tx_status(ar, skb, success);
+}
+
+void carl9170_tx_process_status(struct ar9170 *ar,
+ const struct carl9170_rsp *cmd)
+{
+ unsigned int i;
+
+ for (i = 0; i < cmd->hdr.ext; i++) {
+ if (WARN_ON(i > ((cmd->hdr.len / 2) + 1))) {
+ print_hex_dump_bytes("UU:", DUMP_PREFIX_NONE,
+ (void *) cmd, cmd->hdr.len + 4);
+ break;
+ }
+
+ __carl9170_tx_process_status(ar, cmd->_tx_status[i].cookie,
+ cmd->_tx_status[i].info);
+ }
+}
+
+static __le32 carl9170_tx_physet(struct ar9170 *ar,
+ struct ieee80211_tx_info *info, struct ieee80211_tx_rate *txrate)
+{
+ struct ieee80211_rate *rate = NULL;
+ u32 power, chains;
+ __le32 tmp;
+
+ tmp = cpu_to_le32(0);
+
+ if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ tmp |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ <<
+ AR9170_TX_PHY_BW_S);
+ /* this works because 40 MHz is 2 and dup is 3 */
+ if (txrate->flags & IEEE80211_TX_RC_DUP_DATA)
+ tmp |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ_DUP <<
+ AR9170_TX_PHY_BW_S);
+
+ if (txrate->flags & IEEE80211_TX_RC_SHORT_GI)
+ tmp |= cpu_to_le32(AR9170_TX_PHY_SHORT_GI);
+
+ if (txrate->flags & IEEE80211_TX_RC_MCS) {
+ u32 r = txrate->idx;
+ u8 *txpower;
+
+ /* heavy clip control */
+ tmp |= cpu_to_le32((r & 0x7) <<
+ AR9170_TX_PHY_TX_HEAVY_CLIP_S);
+
+ if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
+ if (info->band == IEEE80211_BAND_5GHZ)
+ txpower = ar->power_5G_ht40;
+ else
+ txpower = ar->power_2G_ht40;
+ } else {
+ if (info->band == IEEE80211_BAND_5GHZ)
+ txpower = ar->power_5G_ht20;
+ else
+ txpower = ar->power_2G_ht20;
+ }
+
+ power = txpower[r & 7];
+
+ /* +1 dBm for HT40 */
+ if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ power += 2;
+
+ r <<= AR9170_TX_PHY_MCS_S;
+ BUG_ON(r & ~AR9170_TX_PHY_MCS);
+
+ tmp |= cpu_to_le32(r & AR9170_TX_PHY_MCS);
+ tmp |= cpu_to_le32(AR9170_TX_PHY_MOD_HT);
+
+ /*
+ * green field preamble does not work.
+ *
+ * if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD)
+ * tmp |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD);
+ */
+ } else {
+ u8 *txpower;
+ u32 mod;
+ u32 phyrate;
+ u8 idx = txrate->idx;
+
+ if (info->band != IEEE80211_BAND_2GHZ) {
+ idx += 4;
+ txpower = ar->power_5G_leg;
+ mod = AR9170_TX_PHY_MOD_OFDM;
+ } else {
+ if (idx < 4) {
+ txpower = ar->power_2G_cck;
+ mod = AR9170_TX_PHY_MOD_CCK;
+ } else {
+ mod = AR9170_TX_PHY_MOD_OFDM;
+ txpower = ar->power_2G_ofdm;
+ }
+ }
+
+ rate = &__carl9170_ratetable[idx];
+
+ phyrate = rate->hw_value & 0xF;
+ power = txpower[(rate->hw_value & 0x30) >> 4];
+ phyrate <<= AR9170_TX_PHY_MCS_S;
+
+ tmp |= cpu_to_le32(mod);
+ tmp |= cpu_to_le32(phyrate);
+
+ /*
+ * short preamble seems to be broken too.
+ *
+ * if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+ * tmp |= cpu_to_le32(AR9170_TX_PHY_SHORT_PREAMBLE);
+ */
+ }
+ power <<= AR9170_TX_PHY_TX_PWR_S;
+ power &= AR9170_TX_PHY_TX_PWR;
+ tmp |= cpu_to_le32(power);
+
+ /* set TX chains */
+ if (ar->eeprom.tx_mask == 1) {
+ chains = AR9170_TX_PHY_TXCHAIN_1;
+ } else {
+ chains = AR9170_TX_PHY_TXCHAIN_2;
+
+ /* >= 36M legacy OFDM - use only one chain */
+ if (rate && rate->bitrate >= 360 &&
+ !(txrate->flags & IEEE80211_TX_RC_MCS))
+ chains = AR9170_TX_PHY_TXCHAIN_1;
+ }
+ tmp |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_S);
+
+ return tmp;
+}
+
+static bool carl9170_tx_rts_check(struct ar9170 *ar,
+ struct ieee80211_tx_rate *rate,
+ bool ampdu, bool multi)
+{
+ switch (ar->erp_mode) {
+ case CARL9170_ERP_AUTO:
+ if (ampdu)
+ break;
+
+ case CARL9170_ERP_MAC80211:
+ if (!(rate->flags & IEEE80211_TX_RC_USE_RTS_CTS))
+ break;
+
+ case CARL9170_ERP_RTS:
+ if (likely(!multi))
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static bool carl9170_tx_cts_check(struct ar9170 *ar,
+ struct ieee80211_tx_rate *rate)
+{
+ switch (ar->erp_mode) {
+ case CARL9170_ERP_AUTO:
+ case CARL9170_ERP_MAC80211:
+ if (!(rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
+ break;
+
+ case CARL9170_ERP_CTS:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr;
+ struct _carl9170_tx_superframe *txc;
+ struct carl9170_vif_info *cvif;
+ struct ieee80211_tx_info *info;
+ struct ieee80211_tx_rate *txrate;
+ struct ieee80211_sta *sta;
+ struct carl9170_tx_info *arinfo;
+ unsigned int hw_queue;
+ int i;
+ __le16 mac_tmp;
+ u16 len;
+ bool ampdu, no_ack;
+
+ BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data));
+ BUILD_BUG_ON(sizeof(struct _carl9170_tx_superdesc) !=
+ CARL9170_TX_SUPERDESC_LEN);
+
+ BUILD_BUG_ON(sizeof(struct _ar9170_tx_hwdesc) !=
+ AR9170_TX_HWDESC_LEN);
+
+ BUILD_BUG_ON(IEEE80211_TX_MAX_RATES < CARL9170_TX_MAX_RATES);
+
+ BUILD_BUG_ON(AR9170_MAX_VIRTUAL_MAC >
+ ((CARL9170_TX_SUPER_MISC_VIF_ID >>
+ CARL9170_TX_SUPER_MISC_VIF_ID_S) + 1));
+
+ hw_queue = ar9170_qmap[carl9170_get_queue(ar, skb)];
+
+ hdr = (void *)skb->data;
+ info = IEEE80211_SKB_CB(skb);
+ len = skb->len;
+
+ /*
+ * Note: If the frame was sent through a monitor interface,
+ * the ieee80211_vif pointer can be NULL.
+ */
+ if (likely(info->control.vif))
+ cvif = (void *) info->control.vif->drv_priv;
+ else
+ cvif = NULL;
+
+ sta = info->control.sta;
+
+ txc = (void *)skb_push(skb, sizeof(*txc));
+ memset(txc, 0, sizeof(*txc));
+
+ SET_VAL(CARL9170_TX_SUPER_MISC_QUEUE, txc->s.misc, hw_queue);
+
+ if (likely(cvif))
+ SET_VAL(CARL9170_TX_SUPER_MISC_VIF_ID, txc->s.misc, cvif->id);
+
+ if (unlikely(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM))
+ txc->s.misc |= CARL9170_TX_SUPER_MISC_CAB;
+
+ if (unlikely(ieee80211_is_probe_resp(hdr->frame_control)))
+ txc->s.misc |= CARL9170_TX_SUPER_MISC_FILL_IN_TSF;
+
+ mac_tmp = cpu_to_le16(AR9170_TX_MAC_HW_DURATION |
+ AR9170_TX_MAC_BACKOFF);
+ mac_tmp |= cpu_to_le16((hw_queue << AR9170_TX_MAC_QOS_S) &&
+ AR9170_TX_MAC_QOS);
+
+ no_ack = !!(info->flags & IEEE80211_TX_CTL_NO_ACK);
+ if (unlikely(no_ack))
+ mac_tmp |= cpu_to_le16(AR9170_TX_MAC_NO_ACK);
+
+ if (info->control.hw_key) {
+ len += info->control.hw_key->icv_len;
+
+ switch (info->control.hw_key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ case WLAN_CIPHER_SUITE_TKIP:
+ mac_tmp |= cpu_to_le16(AR9170_TX_MAC_ENCR_RC4);
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ mac_tmp |= cpu_to_le16(AR9170_TX_MAC_ENCR_AES);
+ break;
+ default:
+ WARN_ON(1);
+ goto err_out;
+ }
+ }
+
+ ampdu = !!(info->flags & IEEE80211_TX_CTL_AMPDU);
+ if (ampdu) {
+ unsigned int density, factor;
+
+ if (unlikely(!sta || !cvif))
+ goto err_out;
+
+ factor = min_t(unsigned int, 1u,
+ info->control.sta->ht_cap.ampdu_factor);
+
+ density = info->control.sta->ht_cap.ampdu_density;
+
+ if (density) {
+ /*
+ * Watch out!
+ *
+ * Otus uses slightly different density values than
+ * those from the 802.11n spec.
+ */
+
+ density = max_t(unsigned int, density + 1, 7u);
+ }
+
+ SET_VAL(CARL9170_TX_SUPER_AMPDU_DENSITY,
+ txc->s.ampdu_settings, density);
+
+ SET_VAL(CARL9170_TX_SUPER_AMPDU_FACTOR,
+ txc->s.ampdu_settings, factor);
+
+ for (i = 0; i < CARL9170_TX_MAX_RATES; i++) {
+ txrate = &info->control.rates[i];
+ if (txrate->idx >= 0) {
+ txc->s.ri[i] =
+ CARL9170_TX_SUPER_RI_AMPDU;
+
+ if (WARN_ON(!(txrate->flags &
+ IEEE80211_TX_RC_MCS))) {
+ /*
+ * Not sure if it's even possible
+ * to aggregate non-ht rates with
+ * this HW.
+ */
+ goto err_out;
+ }
+ continue;
+ }
+
+ txrate->idx = 0;
+ txrate->count = ar->hw->max_rate_tries;
+ }
+
+ mac_tmp |= cpu_to_le16(AR9170_TX_MAC_AGGR);
+ }
+
+ /*
+ * NOTE: For the first rate, the ERP & AMPDU flags are directly
+ * taken from mac_control. For all fallback rate, the firmware
+ * updates the mac_control flags from the rate info field.
+ */
+ for (i = 1; i < CARL9170_TX_MAX_RATES; i++) {
+ txrate = &info->control.rates[i];
+ if (txrate->idx < 0)
+ break;
+
+ SET_VAL(CARL9170_TX_SUPER_RI_TRIES, txc->s.ri[i],
+ txrate->count);
+
+ if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack))
+ txc->s.ri[i] |= (AR9170_TX_MAC_PROT_RTS <<
+ CARL9170_TX_SUPER_RI_ERP_PROT_S);
+ else if (carl9170_tx_cts_check(ar, txrate))
+ txc->s.ri[i] |= (AR9170_TX_MAC_PROT_CTS <<
+ CARL9170_TX_SUPER_RI_ERP_PROT_S);
+
+ txc->s.rr[i - 1] = carl9170_tx_physet(ar, info, txrate);
+ }
+
+ txrate = &info->control.rates[0];
+ SET_VAL(CARL9170_TX_SUPER_RI_TRIES, txc->s.ri[0], txrate->count);
+
+ if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack))
+ mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS);
+ else if (carl9170_tx_cts_check(ar, txrate))
+ mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS);
+
+ txc->s.len = cpu_to_le16(skb->len);
+ txc->f.length = cpu_to_le16(len + FCS_LEN);
+ txc->f.mac_control = mac_tmp;
+ txc->f.phy_control = carl9170_tx_physet(ar, info, txrate);
+
+ arinfo = (void *)info->rate_driver_data;
+ arinfo->timeout = jiffies;
+ arinfo->ar = ar;
+ kref_init(&arinfo->ref);
+ return 0;
+
+err_out:
+ skb_pull(skb, sizeof(*txc));
+ return -EINVAL;
+}
+
+static void carl9170_set_immba(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct _carl9170_tx_superframe *super;
+
+ super = (void *) skb->data;
+ super->f.mac_control |= cpu_to_le16(AR9170_TX_MAC_IMM_BA);
+}
+
+static void carl9170_set_ampdu_params(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct _carl9170_tx_superframe *super;
+ int tmp;
+
+ super = (void *) skb->data;
+
+ tmp = (super->s.ampdu_settings & CARL9170_TX_SUPER_AMPDU_DENSITY) <<
+ CARL9170_TX_SUPER_AMPDU_DENSITY_S;
+
+ /*
+ * If you haven't noticed carl9170_tx_prepare has already filled
+ * in all ampdu spacing & factor parameters.
+ * Now it's the time to check whenever the settings have to be
+ * updated by the firmware, or if everything is still the same.
+ *
+ * There's no sane way to handle different density values with
+ * this hardware, so we may as well just do the compare in the
+ * driver.
+ */
+
+ if (tmp != ar->current_density) {
+ ar->current_density = tmp;
+ super->s.ampdu_settings |=
+ CARL9170_TX_SUPER_AMPDU_COMMIT_DENSITY;
+ }
+
+ tmp = (super->s.ampdu_settings & CARL9170_TX_SUPER_AMPDU_FACTOR) <<
+ CARL9170_TX_SUPER_AMPDU_FACTOR_S;
+
+ if (tmp != ar->current_factor) {
+ ar->current_factor = tmp;
+ super->s.ampdu_settings |=
+ CARL9170_TX_SUPER_AMPDU_COMMIT_FACTOR;
+ }
+}
+
+static bool carl9170_tx_rate_check(struct ar9170 *ar, struct sk_buff *_dest,
+ struct sk_buff *_src)
+{
+ struct _carl9170_tx_superframe *dest, *src;
+
+ dest = (void *) _dest->data;
+ src = (void *) _src->data;
+
+ /*
+ * The mac80211 rate control algorithm expects that all MPDUs in
+ * an AMPDU share the same tx vectors.
+ * This is not really obvious right now, because the hardware
+ * does the AMPDU setup according to its own rulebook.
+ * Our nicely assembled, strictly monotonic increasing mpdu
+ * chains will be broken up, mashed back together...
+ */
+
+ return (dest->f.phy_control == src->f.phy_control);
+}
+
+static void carl9170_tx_ampdu(struct ar9170 *ar)
+{
+ struct sk_buff_head agg;
+ struct carl9170_sta_tid *tid_info;
+ struct sk_buff *skb, *first;
+ unsigned int i = 0, done_ampdus = 0;
+ u16 seq, queue, tmpssn;
+
+ atomic_inc(&ar->tx_ampdu_scheduler);
+ ar->tx_ampdu_schedule = false;
+
+ if (atomic_read(&ar->tx_ampdu_upload))
+ return;
+
+ if (!ar->tx_ampdu_list_len)
+ return;
+
+ __skb_queue_head_init(&agg);
+
+ rcu_read_lock();
+ tid_info = rcu_dereference(ar->tx_ampdu_iter);
+ if (WARN_ON_ONCE(!tid_info)) {
+ rcu_read_unlock();
+ return;
+ }
+
+retry:
+ list_for_each_entry_continue_rcu(tid_info, &ar->tx_ampdu_list, list) {
+ i++;
+
+ if (tid_info->state < CARL9170_TID_STATE_PROGRESS)
+ continue;
+
+ queue = TID_TO_WME_AC(tid_info->tid);
+
+ spin_lock_bh(&tid_info->lock);
+ if (tid_info->state != CARL9170_TID_STATE_XMIT)
+ goto processed;
+
+ tid_info->counter++;
+ first = skb_peek(&tid_info->queue);
+ tmpssn = carl9170_get_seq(first);
+ seq = tid_info->snx;
+
+ if (unlikely(tmpssn != seq)) {
+ tid_info->state = CARL9170_TID_STATE_IDLE;
+
+ goto processed;
+ }
+
+ while ((skb = skb_peek(&tid_info->queue))) {
+ /* strict 0, 1, ..., n - 1, n frame sequence order */
+ if (unlikely(carl9170_get_seq(skb) != seq))
+ break;
+
+ /* don't upload more than AMPDU FACTOR allows. */
+ if (unlikely(SEQ_DIFF(tid_info->snx, tid_info->bsn) >=
+ (tid_info->max - 1)))
+ break;
+
+ if (!carl9170_tx_rate_check(ar, skb, first))
+ break;
+
+ atomic_inc(&ar->tx_ampdu_upload);
+ tid_info->snx = seq = SEQ_NEXT(seq);
+ __skb_unlink(skb, &tid_info->queue);
+
+ __skb_queue_tail(&agg, skb);
+
+ if (skb_queue_len(&agg) >= CARL9170_NUM_TX_AGG_MAX)
+ break;
+ }
+
+ if (skb_queue_empty(&tid_info->queue) ||
+ carl9170_get_seq(skb_peek(&tid_info->queue)) !=
+ tid_info->snx) {
+ /*
+ * stop TID, if A-MPDU frames are still missing,
+ * or whenever the queue is empty.
+ */
+
+ tid_info->state = CARL9170_TID_STATE_IDLE;
+ }
+ done_ampdus++;
+
+processed:
+ spin_unlock_bh(&tid_info->lock);
+
+ if (skb_queue_empty(&agg))
+ continue;
+
+ /* apply ampdu spacing & factor settings */
+ carl9170_set_ampdu_params(ar, skb_peek(&agg));
+
+ /* set aggregation push bit */
+ carl9170_set_immba(ar, skb_peek_tail(&agg));
+
+ spin_lock_bh(&ar->tx_pending[queue].lock);
+ skb_queue_splice_tail_init(&agg, &ar->tx_pending[queue]);
+ spin_unlock_bh(&ar->tx_pending[queue].lock);
+ ar->tx_schedule = true;
+ }
+ if ((done_ampdus++ == 0) && (i++ == 0))
+ goto retry;
+
+ rcu_assign_pointer(ar->tx_ampdu_iter, tid_info);
+ rcu_read_unlock();
+}
+
+static struct sk_buff *carl9170_tx_pick_skb(struct ar9170 *ar,
+ struct sk_buff_head *queue)
+{
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *info;
+ struct carl9170_tx_info *arinfo;
+
+ BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data));
+
+ spin_lock_bh(&queue->lock);
+ skb = skb_peek(queue);
+ if (unlikely(!skb))
+ goto err_unlock;
+
+ if (carl9170_alloc_dev_space(ar, skb))
+ goto err_unlock;
+
+ __skb_unlink(skb, queue);
+ spin_unlock_bh(&queue->lock);
+
+ info = IEEE80211_SKB_CB(skb);
+ arinfo = (void *) info->rate_driver_data;
+
+ arinfo->timeout = jiffies;
+
+ /*
+ * increase ref count to "2".
+ * Ref counting is the easiest way to solve the race between
+ * the the urb's completion routine: carl9170_tx_callback and
+ * wlan tx status functions: carl9170_tx_status/janitor.
+ */
+ carl9170_tx_get_skb(skb);
+
+ return skb;
+
+err_unlock:
+ spin_unlock_bh(&queue->lock);
+ return NULL;
+}
+
+void carl9170_tx_drop(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct _carl9170_tx_superframe *super;
+ uint8_t q = 0;
+
+ ar->tx_dropped++;
+
+ super = (void *)skb->data;
+ SET_VAL(CARL9170_TX_SUPER_MISC_QUEUE, q,
+ ar9170_qmap[carl9170_get_queue(ar, skb)]);
+ __carl9170_tx_process_status(ar, super->s.cookie, q);
+}
+
+static void carl9170_tx(struct ar9170 *ar)
+{
+ struct sk_buff *skb;
+ unsigned int i, q;
+ bool schedule_garbagecollector = false;
+
+ ar->tx_schedule = false;
+
+ if (unlikely(!IS_STARTED(ar)))
+ return;
+
+ carl9170_usb_handle_tx_err(ar);
+
+ for (i = 0; i < ar->hw->queues; i++) {
+ while (!skb_queue_empty(&ar->tx_pending[i])) {
+ skb = carl9170_tx_pick_skb(ar, &ar->tx_pending[i]);
+ if (unlikely(!skb))
+ break;
+
+ atomic_inc(&ar->tx_total_pending);
+
+ q = __carl9170_get_queue(ar, i);
+ /*
+ * NB: tx_status[i] vs. tx_status[q],
+ * TODO: Move into pick_skb or alloc_dev_space.
+ */
+ skb_queue_tail(&ar->tx_status[q], skb);
+
+ carl9170_usb_tx(ar, skb);
+ schedule_garbagecollector = true;
+ }
+ }
+
+ if (!schedule_garbagecollector)
+ return;
+
+ ieee80211_queue_delayed_work(ar->hw, &ar->tx_janitor,
+ msecs_to_jiffies(CARL9170_TX_TIMEOUT));
+}
+
+static bool carl9170_tx_ampdu_queue(struct ar9170 *ar,
+ struct ieee80211_sta *sta, struct sk_buff *skb)
+{
+ struct carl9170_sta_info *sta_info;
+ struct carl9170_sta_tid *agg;
+ struct sk_buff *iter;
+ unsigned int max;
+ u16 tid, seq, qseq, off;
+ bool run = false;
+
+ tid = carl9170_get_tid(skb);
+ seq = carl9170_get_seq(skb);
+ sta_info = (void *) sta->drv_priv;
+
+ rcu_read_lock();
+ agg = rcu_dereference(sta_info->agg[tid]);
+ max = sta_info->ampdu_max_len;
+
+ if (!agg)
+ goto err_unlock_rcu;
+
+ spin_lock_bh(&agg->lock);
+ if (unlikely(agg->state < CARL9170_TID_STATE_IDLE))
+ goto err_unlock;
+
+ /* check if sequence is within the BA window */
+ if (unlikely(!BAW_WITHIN(agg->bsn, CARL9170_BAW_BITS, seq)))
+ goto err_unlock;
+
+ if (WARN_ON_ONCE(!BAW_WITHIN(agg->snx, CARL9170_BAW_BITS, seq)))
+ goto err_unlock;
+
+ off = SEQ_DIFF(seq, agg->bsn);
+ if (WARN_ON_ONCE(test_and_set_bit(off, agg->bitmap)))
+ goto err_unlock;
+
+ if (likely(BAW_WITHIN(agg->hsn, CARL9170_BAW_BITS, seq))) {
+ __skb_queue_tail(&agg->queue, skb);
+ agg->hsn = seq;
+ goto queued;
+ }
+
+ skb_queue_reverse_walk(&agg->queue, iter) {
+ qseq = carl9170_get_seq(iter);
+
+ if (BAW_WITHIN(qseq, CARL9170_BAW_BITS, seq)) {
+ __skb_queue_after(&agg->queue, iter, skb);
+ goto queued;
+ }
+ }
+
+ __skb_queue_head(&agg->queue, skb);
+queued:
+
+ if (unlikely(agg->state != CARL9170_TID_STATE_XMIT)) {
+ if (agg->snx == carl9170_get_seq(skb_peek(&agg->queue))) {
+ agg->state = CARL9170_TID_STATE_XMIT;
+ run = true;
+ }
+ }
+
+ spin_unlock_bh(&agg->lock);
+ rcu_read_unlock();
+
+ return run;
+
+err_unlock:
+ spin_unlock_bh(&agg->lock);
+
+err_unlock_rcu:
+ rcu_read_unlock();
+ carl9170_tx_status(ar, skb, false);
+ ar->tx_dropped++;
+ return false;
+}
+
+int carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct ar9170 *ar = hw->priv;
+ struct ieee80211_tx_info *info;
+ struct ieee80211_sta *sta;
+ bool run;
+
+ if (unlikely(!IS_STARTED(ar)))
+ goto err_free;
+
+ info = IEEE80211_SKB_CB(skb);
+ sta = info->control.sta;
+
+ if (unlikely(carl9170_tx_prepare(ar, skb)))
+ goto err_free;
+
+ carl9170_tx_accounting(ar, skb);
+ /*
+ * from now on, one has to use carl9170_tx_status to free
+ * all ressouces which are associated with the frame.
+ */
+
+ if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+ if (WARN_ON_ONCE(!sta))
+ goto err_free;
+
+ run = carl9170_tx_ampdu_queue(ar, sta, skb);
+ if (run)
+ carl9170_tx_ampdu(ar);
+
+ } else {
+ unsigned int queue = skb_get_queue_mapping(skb);
+
+ skb_queue_tail(&ar->tx_pending[queue], skb);
+ }
+
+ carl9170_tx(ar);
+ return NETDEV_TX_OK;
+
+err_free:
+ ar->tx_dropped++;
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+}
+
+void carl9170_tx_scheduler(struct ar9170 *ar)
+{
+
+ if (ar->tx_ampdu_schedule)
+ carl9170_tx_ampdu(ar);
+
+ if (ar->tx_schedule)
+ carl9170_tx(ar);
+}
diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c
new file mode 100644
index 000000000000..d8607f4c144d
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/usb.c
@@ -0,0 +1,1149 @@
+/*
+ * Atheros CARL9170 driver
+ *
+ * USB - frontend
+ *
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.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; see the file COPYING. If not, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2007-2008 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/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/device.h>
+#include <net/mac80211.h>
+#include "carl9170.h"
+#include "cmd.h"
+#include "hw.h"
+#include "fwcmd.h"
+
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_AUTHOR("Christian Lamparter <chunkeey@googlemail.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless");
+MODULE_FIRMWARE(CARL9170FW_NAME);
+MODULE_ALIAS("ar9170usb");
+MODULE_ALIAS("arusb_lnx");
+
+/*
+ * Note:
+ *
+ * Always update our wiki's device list (located at:
+ * http://wireless.kernel.org/en/users/Drivers/ar9170/devices ),
+ * whenever you add a new device.
+ */
+static struct usb_device_id carl9170_usb_ids[] = {
+ /* Atheros 9170 */
+ { USB_DEVICE(0x0cf3, 0x9170) },
+ /* Atheros TG121N */
+ { USB_DEVICE(0x0cf3, 0x1001) },
+ /* TP-Link TL-WN821N v2 */
+ { USB_DEVICE(0x0cf3, 0x1002), .driver_info = CARL9170_WPS_BUTTON |
+ CARL9170_ONE_LED },
+ /* 3Com Dual Band 802.11n USB Adapter */
+ { USB_DEVICE(0x0cf3, 0x1010) },
+ /* H3C Dual Band 802.11n USB Adapter */
+ { USB_DEVICE(0x0cf3, 0x1011) },
+ /* Cace Airpcap NX */
+ { USB_DEVICE(0xcace, 0x0300) },
+ /* D-Link DWA 160 A1 */
+ { USB_DEVICE(0x07d1, 0x3c10) },
+ /* D-Link DWA 160 A2 */
+ { USB_DEVICE(0x07d1, 0x3a09) },
+ /* Netgear WNA1000 */
+ { USB_DEVICE(0x0846, 0x9040) },
+ /* Netgear WNDA3100 */
+ { USB_DEVICE(0x0846, 0x9010) },
+ /* Netgear WN111 v2 */
+ { USB_DEVICE(0x0846, 0x9001), .driver_info = CARL9170_ONE_LED },
+ /* Zydas ZD1221 */
+ { USB_DEVICE(0x0ace, 0x1221) },
+ /* Proxim ORiNOCO 802.11n USB */
+ { USB_DEVICE(0x1435, 0x0804) },
+ /* WNC Generic 11n USB Dongle */
+ { USB_DEVICE(0x1435, 0x0326) },
+ /* ZyXEL NWD271N */
+ { USB_DEVICE(0x0586, 0x3417) },
+ /* Z-Com UB81 BG */
+ { USB_DEVICE(0x0cde, 0x0023) },
+ /* Z-Com UB82 ABG */
+ { USB_DEVICE(0x0cde, 0x0026) },
+ /* Sphairon Homelink 1202 */
+ { USB_DEVICE(0x0cde, 0x0027) },
+ /* Arcadyan WN7512 */
+ { USB_DEVICE(0x083a, 0xf522) },
+ /* Planex GWUS300 */
+ { USB_DEVICE(0x2019, 0x5304) },
+ /* IO-Data WNGDNUS2 */
+ { USB_DEVICE(0x04bb, 0x093f) },
+ /* NEC WL300NU-G */
+ { USB_DEVICE(0x0409, 0x0249) },
+ /* AVM FRITZ!WLAN USB Stick N */
+ { USB_DEVICE(0x057c, 0x8401) },
+ /* AVM FRITZ!WLAN USB Stick N 2.4 */
+ { USB_DEVICE(0x057c, 0x8402) },
+ /* Qwest/Actiontec 802AIN Wireless N USB Network Adapter */
+ { USB_DEVICE(0x1668, 0x1200) },
+
+ /* terminate */
+ {}
+};
+MODULE_DEVICE_TABLE(usb, carl9170_usb_ids);
+
+static void carl9170_usb_submit_data_urb(struct ar9170 *ar)
+{
+ struct urb *urb;
+ int err;
+
+ if (atomic_inc_return(&ar->tx_anch_urbs) > AR9170_NUM_TX_URBS)
+ goto err_acc;
+
+ urb = usb_get_from_anchor(&ar->tx_wait);
+ if (!urb)
+ goto err_acc;
+
+ usb_anchor_urb(urb, &ar->tx_anch);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (unlikely(err)) {
+ if (net_ratelimit()) {
+ dev_err(&ar->udev->dev, "tx submit failed (%d)\n",
+ urb->status);
+ }
+
+ usb_unanchor_urb(urb);
+ usb_anchor_urb(urb, &ar->tx_err);
+ }
+
+ usb_free_urb(urb);
+
+ if (likely(err == 0))
+ return;
+
+err_acc:
+ atomic_dec(&ar->tx_anch_urbs);
+}
+
+static void carl9170_usb_tx_data_complete(struct urb *urb)
+{
+ struct ar9170 *ar = (struct ar9170 *)
+ usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
+
+ if (WARN_ON_ONCE(!ar)) {
+ dev_kfree_skb_irq(urb->context);
+ return;
+ }
+
+ atomic_dec(&ar->tx_anch_urbs);
+
+ switch (urb->status) {
+ /* everything is fine */
+ case 0:
+ carl9170_tx_callback(ar, (void *)urb->context);
+ break;
+
+ /* disconnect */
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ENODEV:
+ case -ESHUTDOWN:
+ /*
+ * Defer the frame clean-up to the tasklet worker.
+ * This is necessary, because carl9170_tx_drop
+ * does not work in an irqsave context.
+ */
+ usb_anchor_urb(urb, &ar->tx_err);
+ return;
+
+ /* a random transmission error has occurred? */
+ default:
+ if (net_ratelimit()) {
+ dev_err(&ar->udev->dev, "tx failed (%d)\n",
+ urb->status);
+ }
+
+ usb_anchor_urb(urb, &ar->tx_err);
+ break;
+ }
+
+ if (likely(IS_STARTED(ar)))
+ carl9170_usb_submit_data_urb(ar);
+}
+
+static int carl9170_usb_submit_cmd_urb(struct ar9170 *ar)
+{
+ struct urb *urb;
+ int err;
+
+ if (atomic_inc_return(&ar->tx_cmd_urbs) != 1) {
+ atomic_dec(&ar->tx_cmd_urbs);
+ return 0;
+ }
+
+ urb = usb_get_from_anchor(&ar->tx_cmd);
+ if (!urb) {
+ atomic_dec(&ar->tx_cmd_urbs);
+ return 0;
+ }
+
+ usb_anchor_urb(urb, &ar->tx_anch);
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (unlikely(err)) {
+ usb_unanchor_urb(urb);
+ atomic_dec(&ar->tx_cmd_urbs);
+ }
+ usb_free_urb(urb);
+
+ return err;
+}
+
+static void carl9170_usb_cmd_complete(struct urb *urb)
+{
+ struct ar9170 *ar = urb->context;
+ int err = 0;
+
+ if (WARN_ON_ONCE(!ar))
+ return;
+
+ atomic_dec(&ar->tx_cmd_urbs);
+
+ switch (urb->status) {
+ /* everything is fine */
+ case 0:
+ break;
+
+ /* disconnect */
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ENODEV:
+ case -ESHUTDOWN:
+ return;
+
+ default:
+ err = urb->status;
+ break;
+ }
+
+ if (!IS_INITIALIZED(ar))
+ return;
+
+ if (err)
+ dev_err(&ar->udev->dev, "submit cmd cb failed (%d).\n", err);
+
+ err = carl9170_usb_submit_cmd_urb(ar);
+ if (err)
+ dev_err(&ar->udev->dev, "submit cmd failed (%d).\n", err);
+}
+
+static void carl9170_usb_rx_irq_complete(struct urb *urb)
+{
+ struct ar9170 *ar = urb->context;
+
+ if (WARN_ON_ONCE(!ar))
+ return;
+
+ switch (urb->status) {
+ /* everything is fine */
+ case 0:
+ break;
+
+ /* disconnect */
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ENODEV:
+ case -ESHUTDOWN:
+ return;
+
+ default:
+ goto resubmit;
+ }
+
+ carl9170_handle_command_response(ar, urb->transfer_buffer,
+ urb->actual_length);
+
+resubmit:
+ usb_anchor_urb(urb, &ar->rx_anch);
+ if (unlikely(usb_submit_urb(urb, GFP_ATOMIC)))
+ usb_unanchor_urb(urb);
+}
+
+static int carl9170_usb_submit_rx_urb(struct ar9170 *ar, gfp_t gfp)
+{
+ struct urb *urb;
+ int err = 0, runs = 0;
+
+ while ((atomic_read(&ar->rx_anch_urbs) < AR9170_NUM_RX_URBS) &&
+ (runs++ < AR9170_NUM_RX_URBS)) {
+ err = -ENOSPC;
+ urb = usb_get_from_anchor(&ar->rx_pool);
+ if (urb) {
+ usb_anchor_urb(urb, &ar->rx_anch);
+ err = usb_submit_urb(urb, gfp);
+ if (unlikely(err)) {
+ usb_unanchor_urb(urb);
+ usb_anchor_urb(urb, &ar->rx_pool);
+ } else {
+ atomic_dec(&ar->rx_pool_urbs);
+ atomic_inc(&ar->rx_anch_urbs);
+ }
+ usb_free_urb(urb);
+ }
+ }
+
+ return err;
+}
+
+static void carl9170_usb_rx_work(struct ar9170 *ar)
+{
+ struct urb *urb;
+ int i;
+
+ for (i = 0; i < AR9170_NUM_RX_URBS_POOL; i++) {
+ urb = usb_get_from_anchor(&ar->rx_work);
+ if (!urb)
+ break;
+
+ atomic_dec(&ar->rx_work_urbs);
+ if (IS_INITIALIZED(ar)) {
+ carl9170_rx(ar, urb->transfer_buffer,
+ urb->actual_length);
+ }
+
+ usb_anchor_urb(urb, &ar->rx_pool);
+ atomic_inc(&ar->rx_pool_urbs);
+
+ usb_free_urb(urb);
+
+ carl9170_usb_submit_rx_urb(ar, GFP_ATOMIC);
+ }
+}
+
+void carl9170_usb_handle_tx_err(struct ar9170 *ar)
+{
+ struct urb *urb;
+
+ while ((urb = usb_get_from_anchor(&ar->tx_err))) {
+ struct sk_buff *skb = (void *)urb->context;
+
+ carl9170_tx_drop(ar, skb);
+ carl9170_tx_callback(ar, skb);
+ usb_free_urb(urb);
+ }
+}
+
+static void carl9170_usb_tasklet(unsigned long data)
+{
+ struct ar9170 *ar = (struct ar9170 *) data;
+
+ if (!IS_INITIALIZED(ar))
+ return;
+
+ carl9170_usb_rx_work(ar);
+
+ /*
+ * Strictly speaking: The tx scheduler is not part of the USB system.
+ * But the rx worker returns frames back to the mac80211-stack and
+ * this is the _perfect_ place to generate the next transmissions.
+ */
+ if (IS_STARTED(ar))
+ carl9170_tx_scheduler(ar);
+}
+
+static void carl9170_usb_rx_complete(struct urb *urb)
+{
+ struct ar9170 *ar = (struct ar9170 *)urb->context;
+ int err;
+
+ if (WARN_ON_ONCE(!ar))
+ return;
+
+ atomic_dec(&ar->rx_anch_urbs);
+
+ switch (urb->status) {
+ case 0:
+ /* rx path */
+ usb_anchor_urb(urb, &ar->rx_work);
+ atomic_inc(&ar->rx_work_urbs);
+ break;
+
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ENODEV:
+ case -ESHUTDOWN:
+ /* handle disconnect events*/
+ return;
+
+ default:
+ /* handle all other errors */
+ usb_anchor_urb(urb, &ar->rx_pool);
+ atomic_inc(&ar->rx_pool_urbs);
+ break;
+ }
+
+ err = carl9170_usb_submit_rx_urb(ar, GFP_ATOMIC);
+ if (unlikely(err)) {
+ /*
+ * usb_submit_rx_urb reported a problem.
+ * In case this is due to a rx buffer shortage,
+ * elevate the tasklet worker priority to
+ * the highest available level.
+ */
+ tasklet_hi_schedule(&ar->usb_tasklet);
+
+ if (atomic_read(&ar->rx_anch_urbs) == 0) {
+ /*
+ * The system is too slow to cope with
+ * the enormous workload. We have simply
+ * run out of active rx urbs and this
+ * unfortunatly leads to an unpredictable
+ * device.
+ */
+
+ carl9170_restart(ar, CARL9170_RR_SLOW_SYSTEM);
+ }
+ } else {
+ /*
+ * Using anything less than _high_ priority absolutely
+ * kills the rx performance my UP-System...
+ */
+ tasklet_hi_schedule(&ar->usb_tasklet);
+ }
+}
+
+static struct urb *carl9170_usb_alloc_rx_urb(struct ar9170 *ar, gfp_t gfp)
+{
+ struct urb *urb;
+ void *buf;
+
+ buf = kmalloc(ar->fw.rx_size, gfp);
+ if (!buf)
+ return NULL;
+
+ urb = usb_alloc_urb(0, gfp);
+ if (!urb) {
+ kfree(buf);
+ return NULL;
+ }
+
+ usb_fill_bulk_urb(urb, ar->udev, usb_rcvbulkpipe(ar->udev,
+ AR9170_USB_EP_RX), buf, ar->fw.rx_size,
+ carl9170_usb_rx_complete, ar);
+
+ urb->transfer_flags |= URB_FREE_BUFFER;
+
+ return urb;
+}
+
+static int carl9170_usb_send_rx_irq_urb(struct ar9170 *ar)
+{
+ struct urb *urb = NULL;
+ void *ibuf;
+ int err = -ENOMEM;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ goto out;
+
+ ibuf = kmalloc(AR9170_USB_EP_CTRL_MAX, GFP_KERNEL);
+ if (!ibuf)
+ goto out;
+
+ usb_fill_int_urb(urb, ar->udev, usb_rcvintpipe(ar->udev,
+ AR9170_USB_EP_IRQ), ibuf, AR9170_USB_EP_CTRL_MAX,
+ carl9170_usb_rx_irq_complete, ar, 1);
+
+ urb->transfer_flags |= URB_FREE_BUFFER;
+
+ usb_anchor_urb(urb, &ar->rx_anch);
+ err = usb_submit_urb(urb, GFP_KERNEL);
+ if (err)
+ usb_unanchor_urb(urb);
+
+out:
+ usb_free_urb(urb);
+ return err;
+}
+
+static int carl9170_usb_init_rx_bulk_urbs(struct ar9170 *ar)
+{
+ struct urb *urb;
+ int i, err = -EINVAL;
+
+ /*
+ * The driver actively maintains a second shadow
+ * pool for inactive, but fully-prepared rx urbs.
+ *
+ * The pool should help the driver to master huge
+ * workload spikes without running the risk of
+ * undersupplying the hardware or wasting time by
+ * processing rx data (streams) inside the urb
+ * completion (hardirq context).
+ */
+ for (i = 0; i < AR9170_NUM_RX_URBS_POOL; i++) {
+ urb = carl9170_usb_alloc_rx_urb(ar, GFP_KERNEL);
+ if (!urb) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ usb_anchor_urb(urb, &ar->rx_pool);
+ atomic_inc(&ar->rx_pool_urbs);
+ usb_free_urb(urb);
+ }
+
+ err = carl9170_usb_submit_rx_urb(ar, GFP_KERNEL);
+ if (err)
+ goto err_out;
+
+ /* the device now waiting for the firmware. */
+ carl9170_set_state_when(ar, CARL9170_STOPPED, CARL9170_IDLE);
+ return 0;
+
+err_out:
+
+ usb_scuttle_anchored_urbs(&ar->rx_pool);
+ usb_scuttle_anchored_urbs(&ar->rx_work);
+ usb_kill_anchored_urbs(&ar->rx_anch);
+ return err;
+}
+
+static int carl9170_usb_flush(struct ar9170 *ar)
+{
+ struct urb *urb;
+ int ret, err = 0;
+
+ while ((urb = usb_get_from_anchor(&ar->tx_wait))) {
+ struct sk_buff *skb = (void *)urb->context;
+ carl9170_tx_drop(ar, skb);
+ carl9170_tx_callback(ar, skb);
+ usb_free_urb(urb);
+ }
+
+ ret = usb_wait_anchor_empty_timeout(&ar->tx_cmd, HZ);
+ if (ret == 0)
+ err = -ETIMEDOUT;
+
+ /* lets wait a while until the tx - queues are dried out */
+ ret = usb_wait_anchor_empty_timeout(&ar->tx_anch, HZ);
+ if (ret == 0)
+ err = -ETIMEDOUT;
+
+ usb_kill_anchored_urbs(&ar->tx_anch);
+ carl9170_usb_handle_tx_err(ar);
+
+ return err;
+}
+
+static void carl9170_usb_cancel_urbs(struct ar9170 *ar)
+{
+ int err;
+
+ carl9170_set_state(ar, CARL9170_UNKNOWN_STATE);
+
+ err = carl9170_usb_flush(ar);
+ if (err)
+ dev_err(&ar->udev->dev, "stuck tx urbs!\n");
+
+ usb_poison_anchored_urbs(&ar->tx_anch);
+ carl9170_usb_handle_tx_err(ar);
+ usb_poison_anchored_urbs(&ar->rx_anch);
+
+ tasklet_kill(&ar->usb_tasklet);
+
+ usb_scuttle_anchored_urbs(&ar->rx_work);
+ usb_scuttle_anchored_urbs(&ar->rx_pool);
+ usb_scuttle_anchored_urbs(&ar->tx_cmd);
+}
+
+int __carl9170_exec_cmd(struct ar9170 *ar, struct carl9170_cmd *cmd,
+ const bool free_buf)
+{
+ struct urb *urb;
+ int err = 0;
+
+ if (!IS_INITIALIZED(ar)) {
+ err = -EPERM;
+ goto err_free;
+ }
+
+ if (WARN_ON(cmd->hdr.len > CARL9170_MAX_CMD_LEN - 4)) {
+ err = -EINVAL;
+ goto err_free;
+ }
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ usb_fill_int_urb(urb, ar->udev, usb_sndintpipe(ar->udev,
+ AR9170_USB_EP_CMD), cmd, cmd->hdr.len + 4,
+ carl9170_usb_cmd_complete, ar, 1);
+
+ if (free_buf)
+ urb->transfer_flags |= URB_FREE_BUFFER;
+
+ usb_anchor_urb(urb, &ar->tx_cmd);
+ usb_free_urb(urb);
+
+ return carl9170_usb_submit_cmd_urb(ar);
+
+err_free:
+ if (free_buf)
+ kfree(cmd);
+
+ return err;
+}
+
+int carl9170_exec_cmd(struct ar9170 *ar, const enum carl9170_cmd_oids cmd,
+ unsigned int plen, void *payload, unsigned int outlen, void *out)
+{
+ int err = -ENOMEM;
+
+ if (!IS_ACCEPTING_CMD(ar))
+ return -EIO;
+
+ if (!(cmd & CARL9170_CMD_ASYNC_FLAG))
+ might_sleep();
+
+ ar->cmd.hdr.len = plen;
+ ar->cmd.hdr.cmd = cmd;
+ /* writing multiple regs fills this buffer already */
+ if (plen && payload != (u8 *)(ar->cmd.data))
+ memcpy(ar->cmd.data, payload, plen);
+
+ spin_lock_bh(&ar->cmd_lock);
+ ar->readbuf = (u8 *)out;
+ ar->readlen = outlen;
+ spin_unlock_bh(&ar->cmd_lock);
+
+ err = __carl9170_exec_cmd(ar, &ar->cmd, false);
+
+ if (!(cmd & CARL9170_CMD_ASYNC_FLAG)) {
+ err = wait_for_completion_timeout(&ar->cmd_wait, HZ);
+ if (err == 0) {
+ err = -ETIMEDOUT;
+ goto err_unbuf;
+ }
+
+ if (ar->readlen != outlen) {
+ err = -EMSGSIZE;
+ goto err_unbuf;
+ }
+ }
+
+ return 0;
+
+err_unbuf:
+ /* Maybe the device was removed in the moment we were waiting? */
+ if (IS_STARTED(ar)) {
+ dev_err(&ar->udev->dev, "no command feedback "
+ "received (%d).\n", err);
+
+ /* provide some maybe useful debug information */
+ print_hex_dump_bytes("carl9170 cmd: ", DUMP_PREFIX_NONE,
+ &ar->cmd, plen + 4);
+
+ carl9170_restart(ar, CARL9170_RR_COMMAND_TIMEOUT);
+ }
+
+ /* invalidate to avoid completing the next command prematurely */
+ spin_lock_bh(&ar->cmd_lock);
+ ar->readbuf = NULL;
+ ar->readlen = 0;
+ spin_unlock_bh(&ar->cmd_lock);
+
+ return err;
+}
+
+void carl9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct urb *urb;
+ struct ar9170_stream *tx_stream;
+ void *data;
+ unsigned int len;
+
+ if (!IS_STARTED(ar))
+ goto err_drop;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb)
+ goto err_drop;
+
+ if (ar->fw.tx_stream) {
+ tx_stream = (void *) (skb->data - sizeof(*tx_stream));
+
+ len = skb->len + sizeof(*tx_stream);
+ tx_stream->length = cpu_to_le16(len);
+ tx_stream->tag = cpu_to_le16(AR9170_TX_STREAM_TAG);
+ data = tx_stream;
+ } else {
+ data = skb->data;
+ len = skb->len;
+ }
+
+ usb_fill_bulk_urb(urb, ar->udev, usb_sndbulkpipe(ar->udev,
+ AR9170_USB_EP_TX), data, len,
+ carl9170_usb_tx_data_complete, skb);
+
+ urb->transfer_flags |= URB_ZERO_PACKET;
+
+ usb_anchor_urb(urb, &ar->tx_wait);
+
+ usb_free_urb(urb);
+
+ carl9170_usb_submit_data_urb(ar);
+ return;
+
+err_drop:
+ carl9170_tx_drop(ar, skb);
+ carl9170_tx_callback(ar, skb);
+}
+
+static void carl9170_release_firmware(struct ar9170 *ar)
+{
+ if (ar->fw.fw) {
+ release_firmware(ar->fw.fw);
+ memset(&ar->fw, 0, sizeof(ar->fw));
+ }
+}
+
+void carl9170_usb_stop(struct ar9170 *ar)
+{
+ int ret;
+
+ carl9170_set_state_when(ar, CARL9170_IDLE, CARL9170_STOPPED);
+
+ ret = carl9170_usb_flush(ar);
+ if (ret)
+ dev_err(&ar->udev->dev, "kill pending tx urbs.\n");
+
+ usb_poison_anchored_urbs(&ar->tx_anch);
+ carl9170_usb_handle_tx_err(ar);
+
+ /* kill any pending command */
+ spin_lock_bh(&ar->cmd_lock);
+ ar->readlen = 0;
+ spin_unlock_bh(&ar->cmd_lock);
+ complete_all(&ar->cmd_wait);
+
+ /* This is required to prevent an early completion on _start */
+ INIT_COMPLETION(ar->cmd_wait);
+
+ /*
+ * Note:
+ * So far we freed all tx urbs, but we won't dare to touch any rx urbs.
+ * Else we would end up with a unresponsive device...
+ */
+}
+
+int carl9170_usb_open(struct ar9170 *ar)
+{
+ usb_unpoison_anchored_urbs(&ar->tx_anch);
+
+ carl9170_set_state_when(ar, CARL9170_STOPPED, CARL9170_IDLE);
+ return 0;
+}
+
+static int carl9170_usb_load_firmware(struct ar9170 *ar)
+{
+ const u8 *data;
+ u8 *buf;
+ unsigned int transfer;
+ size_t len;
+ u32 addr;
+ int err = 0;
+
+ buf = kmalloc(4096, GFP_KERNEL);
+ if (!buf) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ data = ar->fw.fw->data;
+ len = ar->fw.fw->size;
+ addr = ar->fw.address;
+
+ /* this removes the miniboot image */
+ data += ar->fw.offset;
+ len -= ar->fw.offset;
+
+ while (len) {
+ transfer = min_t(unsigned int, len, 4096u);
+ memcpy(buf, data, transfer);
+
+ err = usb_control_msg(ar->udev, usb_sndctrlpipe(ar->udev, 0),
+ 0x30 /* FW DL */, 0x40 | USB_DIR_OUT,
+ addr >> 8, 0, buf, transfer, 100);
+
+ if (err < 0) {
+ kfree(buf);
+ goto err_out;
+ }
+
+ len -= transfer;
+ data += transfer;
+ addr += transfer;
+ }
+ kfree(buf);
+
+ err = usb_control_msg(ar->udev, usb_sndctrlpipe(ar->udev, 0),
+ 0x31 /* FW DL COMPLETE */,
+ 0x40 | USB_DIR_OUT, 0, 0, NULL, 0, 200);
+
+ if (wait_for_completion_timeout(&ar->fw_boot_wait, HZ) == 0) {
+ err = -ETIMEDOUT;
+ goto err_out;
+ }
+
+ err = carl9170_echo_test(ar, 0x4a110123);
+ if (err)
+ goto err_out;
+
+ /* firmware restarts cmd counter */
+ ar->cmd_seq = -1;
+
+ return 0;
+
+err_out:
+ dev_err(&ar->udev->dev, "firmware upload failed (%d).\n", err);
+ return err;
+}
+
+int carl9170_usb_restart(struct ar9170 *ar)
+{
+ int err = 0;
+
+ if (ar->intf->condition != USB_INTERFACE_BOUND)
+ return 0;
+
+ /* Disable command response sequence counter. */
+ ar->cmd_seq = -2;
+
+ err = carl9170_reboot(ar);
+
+ carl9170_usb_stop(ar);
+
+ if (err)
+ goto err_out;
+
+ tasklet_schedule(&ar->usb_tasklet);
+
+ /* The reboot procedure can take quite a while to complete. */
+ msleep(1100);
+
+ err = carl9170_usb_open(ar);
+ if (err)
+ goto err_out;
+
+ err = carl9170_usb_load_firmware(ar);
+ if (err)
+ goto err_out;
+
+ return 0;
+
+err_out:
+ carl9170_usb_cancel_urbs(ar);
+ return err;
+}
+
+void carl9170_usb_reset(struct ar9170 *ar)
+{
+ /*
+ * This is the last resort to get the device going again
+ * without any *user replugging action*.
+ *
+ * But there is a catch: usb_reset really is like a physical
+ * *reconnect*. The mac80211 state will be lost in the process.
+ * Therefore a userspace application, which is monitoring
+ * the link must step in.
+ */
+ carl9170_usb_cancel_urbs(ar);
+
+ carl9170_usb_stop(ar);
+
+ usb_queue_reset_device(ar->intf);
+}
+
+static int carl9170_usb_init_device(struct ar9170 *ar)
+{
+ int err;
+
+ err = carl9170_usb_send_rx_irq_urb(ar);
+ if (err)
+ goto err_out;
+
+ err = carl9170_usb_init_rx_bulk_urbs(ar);
+ if (err)
+ goto err_unrx;
+
+ mutex_lock(&ar->mutex);
+ err = carl9170_usb_load_firmware(ar);
+ mutex_unlock(&ar->mutex);
+ if (err)
+ goto err_unrx;
+
+ return 0;
+
+err_unrx:
+ carl9170_usb_cancel_urbs(ar);
+
+err_out:
+ return err;
+}
+
+static void carl9170_usb_firmware_failed(struct ar9170 *ar)
+{
+ struct device *parent = ar->udev->dev.parent;
+ struct usb_device *udev;
+
+ /*
+ * Store a copy of the usb_device pointer locally.
+ * This is because device_release_driver initiates
+ * carl9170_usb_disconnect, which in turn frees our
+ * driver context (ar).
+ */
+ udev = ar->udev;
+
+ complete(&ar->fw_load_wait);
+
+ /* unbind anything failed */
+ if (parent)
+ device_lock(parent);
+
+ device_release_driver(&udev->dev);
+ if (parent)
+ device_unlock(parent);
+
+ usb_put_dev(udev);
+}
+
+static void carl9170_usb_firmware_finish(struct ar9170 *ar)
+{
+ int err;
+
+ err = carl9170_parse_firmware(ar);
+ if (err)
+ goto err_freefw;
+
+ err = carl9170_usb_init_device(ar);
+ if (err)
+ goto err_freefw;
+
+ err = carl9170_usb_open(ar);
+ if (err)
+ goto err_unrx;
+
+ err = carl9170_register(ar);
+
+ carl9170_usb_stop(ar);
+ if (err)
+ goto err_unrx;
+
+ complete(&ar->fw_load_wait);
+ usb_put_dev(ar->udev);
+ return;
+
+err_unrx:
+ carl9170_usb_cancel_urbs(ar);
+
+err_freefw:
+ carl9170_release_firmware(ar);
+ carl9170_usb_firmware_failed(ar);
+}
+
+static void carl9170_usb_firmware_step2(const struct firmware *fw,
+ void *context)
+{
+ struct ar9170 *ar = context;
+
+ if (fw) {
+ ar->fw.fw = fw;
+ carl9170_usb_firmware_finish(ar);
+ return;
+ }
+
+ dev_err(&ar->udev->dev, "firmware not found.\n");
+ carl9170_usb_firmware_failed(ar);
+}
+
+static int carl9170_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct ar9170 *ar;
+ struct usb_device *udev;
+ int err;
+
+ err = usb_reset_device(interface_to_usbdev(intf));
+ if (err)
+ return err;
+
+ ar = carl9170_alloc(sizeof(*ar));
+ if (IS_ERR(ar))
+ return PTR_ERR(ar);
+
+ udev = interface_to_usbdev(intf);
+ usb_get_dev(udev);
+ ar->udev = udev;
+ ar->intf = intf;
+ ar->features = id->driver_info;
+
+ usb_set_intfdata(intf, ar);
+ SET_IEEE80211_DEV(ar->hw, &intf->dev);
+
+ init_usb_anchor(&ar->rx_anch);
+ init_usb_anchor(&ar->rx_pool);
+ init_usb_anchor(&ar->rx_work);
+ init_usb_anchor(&ar->tx_wait);
+ init_usb_anchor(&ar->tx_anch);
+ init_usb_anchor(&ar->tx_cmd);
+ init_usb_anchor(&ar->tx_err);
+ init_completion(&ar->cmd_wait);
+ init_completion(&ar->fw_boot_wait);
+ init_completion(&ar->fw_load_wait);
+ tasklet_init(&ar->usb_tasklet, carl9170_usb_tasklet,
+ (unsigned long)ar);
+
+ atomic_set(&ar->tx_cmd_urbs, 0);
+ atomic_set(&ar->tx_anch_urbs, 0);
+ atomic_set(&ar->rx_work_urbs, 0);
+ atomic_set(&ar->rx_anch_urbs, 0);
+ atomic_set(&ar->rx_pool_urbs, 0);
+ ar->cmd_seq = -2;
+
+ usb_get_dev(ar->udev);
+
+ carl9170_set_state(ar, CARL9170_STOPPED);
+
+ return request_firmware_nowait(THIS_MODULE, 1, CARL9170FW_NAME,
+ &ar->udev->dev, GFP_KERNEL, ar, carl9170_usb_firmware_step2);
+}
+
+static void carl9170_usb_disconnect(struct usb_interface *intf)
+{
+ struct ar9170 *ar = usb_get_intfdata(intf);
+ struct usb_device *udev;
+
+ if (WARN_ON(!ar))
+ return;
+
+ udev = ar->udev;
+ wait_for_completion(&ar->fw_load_wait);
+
+ if (IS_INITIALIZED(ar)) {
+ carl9170_reboot(ar);
+ carl9170_usb_stop(ar);
+ }
+
+ carl9170_usb_cancel_urbs(ar);
+ carl9170_unregister(ar);
+
+ usb_set_intfdata(intf, NULL);
+
+ carl9170_release_firmware(ar);
+ carl9170_free(ar);
+ usb_put_dev(udev);
+}
+
+#ifdef CONFIG_PM
+static int carl9170_usb_suspend(struct usb_interface *intf,
+ pm_message_t message)
+{
+ struct ar9170 *ar = usb_get_intfdata(intf);
+
+ if (!ar)
+ return -ENODEV;
+
+ carl9170_usb_cancel_urbs(ar);
+
+ /*
+ * firmware automatically reboots for usb suspend.
+ */
+
+ return 0;
+}
+
+static int carl9170_usb_resume(struct usb_interface *intf)
+{
+ struct ar9170 *ar = usb_get_intfdata(intf);
+ int err;
+
+ if (!ar)
+ return -ENODEV;
+
+ usb_unpoison_anchored_urbs(&ar->rx_anch);
+
+ err = carl9170_usb_init_device(ar);
+ if (err)
+ goto err_unrx;
+
+ err = carl9170_usb_open(ar);
+ if (err)
+ goto err_unrx;
+
+ return 0;
+
+err_unrx:
+ carl9170_usb_cancel_urbs(ar);
+
+ return err;
+}
+#endif /* CONFIG_PM */
+
+static struct usb_driver carl9170_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = carl9170_usb_probe,
+ .disconnect = carl9170_usb_disconnect,
+ .id_table = carl9170_usb_ids,
+ .soft_unbind = 1,
+#ifdef CONFIG_PM
+ .suspend = carl9170_usb_suspend,
+ .resume = carl9170_usb_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init carl9170_usb_init(void)
+{
+ return usb_register(&carl9170_driver);
+}
+
+static void __exit carl9170_usb_exit(void)
+{
+ usb_deregister(&carl9170_driver);
+}
+
+module_init(carl9170_usb_init);
+module_exit(carl9170_usb_exit);
diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h
new file mode 100644
index 000000000000..ff53f078a0b5
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/version.h
@@ -0,0 +1,7 @@
+#ifndef __CARL9170_SHARED_VERSION_H
+#define __CARL9170_SHARED_VERSION_H
+#define CARL9170FW_VERSION_YEAR 10
+#define CARL9170FW_VERSION_MONTH 9
+#define CARL9170FW_VERSION_DAY 28
+#define CARL9170FW_VERSION_GIT "1.8.8.3"
+#endif /* __CARL9170_SHARED_VERSION_H */
diff --git a/drivers/net/wireless/ath/carl9170/wlan.h b/drivers/net/wireless/ath/carl9170/wlan.h
new file mode 100644
index 000000000000..24d63b583b6b
--- /dev/null
+++ b/drivers/net/wireless/ath/carl9170/wlan.h
@@ -0,0 +1,420 @@
+/*
+ * Shared Atheros AR9170 Header
+ *
+ * RX/TX meta descriptor format
+ *
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.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.
+ *
+ * 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, see
+ * http://www.gnu.org/licenses/.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ * Copyright (c) 2007-2008 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 __CARL9170_SHARED_WLAN_H
+#define __CARL9170_SHARED_WLAN_H
+
+#include "fwcmd.h"
+
+#define AR9170_RX_PHY_RATE_CCK_1M 0x0a
+#define AR9170_RX_PHY_RATE_CCK_2M 0x14
+#define AR9170_RX_PHY_RATE_CCK_5M 0x37
+#define AR9170_RX_PHY_RATE_CCK_11M 0x6e
+
+#define AR9170_ENC_ALG_NONE 0x0
+#define AR9170_ENC_ALG_WEP64 0x1
+#define AR9170_ENC_ALG_TKIP 0x2
+#define AR9170_ENC_ALG_AESCCMP 0x4
+#define AR9170_ENC_ALG_WEP128 0x5
+#define AR9170_ENC_ALG_WEP256 0x6
+#define AR9170_ENC_ALG_CENC 0x7
+
+#define AR9170_RX_ENC_SOFTWARE 0x8
+
+#define AR9170_RX_STATUS_MODULATION 0x03
+#define AR9170_RX_STATUS_MODULATION_S 0
+#define AR9170_RX_STATUS_MODULATION_CCK 0x00
+#define AR9170_RX_STATUS_MODULATION_OFDM 0x01
+#define AR9170_RX_STATUS_MODULATION_HT 0x02
+#define AR9170_RX_STATUS_MODULATION_DUPOFDM 0x03
+
+/* depends on modulation */
+#define AR9170_RX_STATUS_SHORT_PREAMBLE 0x08
+#define AR9170_RX_STATUS_GREENFIELD 0x08
+
+#define AR9170_RX_STATUS_MPDU 0x30
+#define AR9170_RX_STATUS_MPDU_S 4
+#define AR9170_RX_STATUS_MPDU_SINGLE 0x00
+#define AR9170_RX_STATUS_MPDU_FIRST 0x20
+#define AR9170_RX_STATUS_MPDU_MIDDLE 0x30
+#define AR9170_RX_STATUS_MPDU_LAST 0x10
+
+#define AR9170_RX_STATUS_CONT_AGGR 0x40
+#define AR9170_RX_STATUS_TOTAL_ERROR 0x80
+
+#define AR9170_RX_ERROR_RXTO 0x01
+#define AR9170_RX_ERROR_OVERRUN 0x02
+#define AR9170_RX_ERROR_DECRYPT 0x04
+#define AR9170_RX_ERROR_FCS 0x08
+#define AR9170_RX_ERROR_WRONG_RA 0x10
+#define AR9170_RX_ERROR_PLCP 0x20
+#define AR9170_RX_ERROR_MMIC 0x40
+
+/* these are either-or */
+#define AR9170_TX_MAC_PROT_RTS 0x0001
+#define AR9170_TX_MAC_PROT_CTS 0x0002
+#define AR9170_TX_MAC_PROT 0x0003
+
+#define AR9170_TX_MAC_NO_ACK 0x0004
+/* if unset, MAC will only do SIFS space before frame */
+#define AR9170_TX_MAC_BACKOFF 0x0008
+#define AR9170_TX_MAC_BURST 0x0010
+#define AR9170_TX_MAC_AGGR 0x0020
+
+/* encryption is a two-bit field */
+#define AR9170_TX_MAC_ENCR_NONE 0x0000
+#define AR9170_TX_MAC_ENCR_RC4 0x0040
+#define AR9170_TX_MAC_ENCR_CENC 0x0080
+#define AR9170_TX_MAC_ENCR_AES 0x00c0
+
+#define AR9170_TX_MAC_MMIC 0x0100
+#define AR9170_TX_MAC_HW_DURATION 0x0200
+#define AR9170_TX_MAC_QOS_S 10
+#define AR9170_TX_MAC_QOS 0x0c00
+#define AR9170_TX_MAC_DISABLE_TXOP 0x1000
+#define AR9170_TX_MAC_TXOP_RIFS 0x2000
+#define AR9170_TX_MAC_IMM_BA 0x4000
+
+/* either-or */
+#define AR9170_TX_PHY_MOD_CCK 0x00000000
+#define AR9170_TX_PHY_MOD_OFDM 0x00000001
+#define AR9170_TX_PHY_MOD_HT 0x00000002
+
+/* depends on modulation */
+#define AR9170_TX_PHY_SHORT_PREAMBLE 0x00000004
+#define AR9170_TX_PHY_GREENFIELD 0x00000004
+
+#define AR9170_TX_PHY_BW_S 3
+#define AR9170_TX_PHY_BW (3 << AR9170_TX_PHY_BW_SHIFT)
+#define AR9170_TX_PHY_BW_20MHZ 0
+#define AR9170_TX_PHY_BW_40MHZ 2
+#define AR9170_TX_PHY_BW_40MHZ_DUP 3
+
+#define AR9170_TX_PHY_TX_HEAVY_CLIP_S 6
+#define AR9170_TX_PHY_TX_HEAVY_CLIP (7 << \
+ AR9170_TX_PHY_TX_HEAVY_CLIP_S)
+
+#define AR9170_TX_PHY_TX_PWR_S 9
+#define AR9170_TX_PHY_TX_PWR (0x3f << \
+ AR9170_TX_PHY_TX_PWR_S)
+
+#define AR9170_TX_PHY_TXCHAIN_S 15
+#define AR9170_TX_PHY_TXCHAIN (7 << \
+ AR9170_TX_PHY_TXCHAIN_S)
+#define AR9170_TX_PHY_TXCHAIN_1 1
+/* use for cck, ofdm 6/9/12/18/24 and HT if capable */
+#define AR9170_TX_PHY_TXCHAIN_2 5
+
+#define AR9170_TX_PHY_MCS_S 18
+#define AR9170_TX_PHY_MCS (0x7f << \
+ AR9170_TX_PHY_MCS_S)
+
+#define AR9170_TX_PHY_RATE_CCK_1M 0x0
+#define AR9170_TX_PHY_RATE_CCK_2M 0x1
+#define AR9170_TX_PHY_RATE_CCK_5M 0x2
+#define AR9170_TX_PHY_RATE_CCK_11M 0x3
+
+/* same as AR9170_RX_PHY_RATE */
+#define AR9170_TXRX_PHY_RATE_OFDM_6M 0xb
+#define AR9170_TXRX_PHY_RATE_OFDM_9M 0xf
+#define AR9170_TXRX_PHY_RATE_OFDM_12M 0xa
+#define AR9170_TXRX_PHY_RATE_OFDM_18M 0xe
+#define AR9170_TXRX_PHY_RATE_OFDM_24M 0x9
+#define AR9170_TXRX_PHY_RATE_OFDM_36M 0xd
+#define AR9170_TXRX_PHY_RATE_OFDM_48M 0x8
+#define AR9170_TXRX_PHY_RATE_OFDM_54M 0xc
+
+#define AR9170_TXRX_PHY_RATE_HT_MCS0 0x0
+#define AR9170_TXRX_PHY_RATE_HT_MCS1 0x1
+#define AR9170_TXRX_PHY_RATE_HT_MCS2 0x2
+#define AR9170_TXRX_PHY_RATE_HT_MCS3 0x3
+#define AR9170_TXRX_PHY_RATE_HT_MCS4 0x4
+#define AR9170_TXRX_PHY_RATE_HT_MCS5 0x5
+#define AR9170_TXRX_PHY_RATE_HT_MCS6 0x6
+#define AR9170_TXRX_PHY_RATE_HT_MCS7 0x7
+#define AR9170_TXRX_PHY_RATE_HT_MCS8 0x8
+#define AR9170_TXRX_PHY_RATE_HT_MCS9 0x9
+#define AR9170_TXRX_PHY_RATE_HT_MCS10 0xa
+#define AR9170_TXRX_PHY_RATE_HT_MCS11 0xb
+#define AR9170_TXRX_PHY_RATE_HT_MCS12 0xc
+#define AR9170_TXRX_PHY_RATE_HT_MCS13 0xd
+#define AR9170_TXRX_PHY_RATE_HT_MCS14 0xe
+#define AR9170_TXRX_PHY_RATE_HT_MCS15 0xf
+
+#define AR9170_TX_PHY_SHORT_GI 0x80000000
+
+#ifdef __CARL9170FW__
+struct ar9170_tx_hw_mac_control {
+ union {
+ struct {
+ /*
+ * Beware of compiler bugs in all gcc pre 4.4!
+ */
+
+ u8 erp_prot:2;
+ u8 no_ack:1;
+ u8 backoff:1;
+ u8 burst:1;
+ u8 ampdu:1;
+
+ u8 enc_mode:2;
+
+ u8 hw_mmic:1;
+ u8 hw_duration:1;
+
+ u8 qos_queue:2;
+
+ u8 disable_txop:1;
+ u8 txop_rifs:1;
+
+ u8 ba_end:1;
+ u8 probe:1;
+ } __packed;
+
+ __le16 set;
+ } __packed;
+} __packed;
+
+struct ar9170_tx_hw_phy_control {
+ union {
+ struct {
+ /*
+ * Beware of compiler bugs in all gcc pre 4.4!
+ */
+
+ u8 modulation:2;
+ u8 preamble:1;
+ u8 bandwidth:2;
+ u8:1;
+ u8 heavy_clip:3;
+ u8 tx_power:6;
+ u8 chains:3;
+ u8 mcs:7;
+ u8:6;
+ u8 short_gi:1;
+ } __packed;
+
+ __le32 set;
+ } __packed;
+} __packed;
+
+struct ar9170_tx_rate_info {
+ u8 tries:3;
+ u8 erp_prot:2;
+ u8 ampdu:1;
+ u8 free:2; /* free for use (e.g.:RIFS/TXOP/AMPDU) */
+} __packed;
+
+struct carl9170_tx_superdesc {
+ __le16 len;
+ u8 rix;
+ u8 cnt;
+ u8 cookie;
+ u8 ampdu_density:3;
+ u8 ampdu_factor:2;
+ u8 ampdu_commit_density:1;
+ u8 ampdu_commit_factor:1;
+ u8 ampdu_unused_bit:1;
+ u8 queue:2;
+ u8 reserved:1;
+ u8 vif_id:3;
+ u8 fill_in_tsf:1;
+ u8 cab:1;
+ u8 padding2;
+ struct ar9170_tx_rate_info ri[CARL9170_TX_MAX_RATES];
+ struct ar9170_tx_hw_phy_control rr[CARL9170_TX_MAX_RETRY_RATES];
+} __packed;
+
+struct ar9170_tx_hwdesc {
+ __le16 length;
+ struct ar9170_tx_hw_mac_control mac;
+ struct ar9170_tx_hw_phy_control phy;
+} __packed;
+
+struct ar9170_tx_frame {
+ struct ar9170_tx_hwdesc hdr;
+
+ union {
+ struct ieee80211_hdr i3e;
+ u8 payload[0];
+ } data;
+} __packed;
+
+struct carl9170_tx_superframe {
+ struct carl9170_tx_superdesc s;
+ struct ar9170_tx_frame f;
+} __packed;
+
+#endif /* __CARL9170FW__ */
+
+struct _ar9170_tx_hwdesc {
+ __le16 length;
+ __le16 mac_control;
+ __le32 phy_control;
+} __packed;
+
+#define CARL9170_TX_SUPER_AMPDU_DENSITY_S 0
+#define CARL9170_TX_SUPER_AMPDU_DENSITY 0x7
+#define CARL9170_TX_SUPER_AMPDU_FACTOR 0x18
+#define CARL9170_TX_SUPER_AMPDU_FACTOR_S 3
+#define CARL9170_TX_SUPER_AMPDU_COMMIT_DENSITY 0x20
+#define CARL9170_TX_SUPER_AMPDU_COMMIT_DENSITY_S 5
+#define CARL9170_TX_SUPER_AMPDU_COMMIT_FACTOR 0x40
+#define CARL9170_TX_SUPER_AMPDU_COMMIT_FACTOR_S 6
+
+#define CARL9170_TX_SUPER_MISC_QUEUE 0x3
+#define CARL9170_TX_SUPER_MISC_QUEUE_S 0
+#define CARL9170_TX_SUPER_MISC_VIF_ID 0x38
+#define CARL9170_TX_SUPER_MISC_VIF_ID_S 3
+#define CARL9170_TX_SUPER_MISC_FILL_IN_TSF 0x40
+#define CARL9170_TX_SUPER_MISC_CAB 0x80
+
+#define CARL9170_TX_SUPER_RI_TRIES 0x7
+#define CARL9170_TX_SUPER_RI_TRIES_S 0
+#define CARL9170_TX_SUPER_RI_ERP_PROT 0x18
+#define CARL9170_TX_SUPER_RI_ERP_PROT_S 3
+#define CARL9170_TX_SUPER_RI_AMPDU 0x20
+#define CARL9170_TX_SUPER_RI_AMPDU_S 5
+
+struct _carl9170_tx_superdesc {
+ __le16 len;
+ u8 rix;
+ u8 cnt;
+ u8 cookie;
+ u8 ampdu_settings;
+ u8 misc;
+ u8 padding;
+ u8 ri[CARL9170_TX_MAX_RATES];
+ __le32 rr[CARL9170_TX_MAX_RETRY_RATES];
+} __packed;
+
+struct _carl9170_tx_superframe {
+ struct _carl9170_tx_superdesc s;
+ struct _ar9170_tx_hwdesc f;
+ u8 frame_data[0];
+} __packed;
+
+#define CARL9170_TX_SUPERDESC_LEN 24
+#define AR9170_TX_HWDESC_LEN 8
+#define CARL9170_TX_SUPERFRAME_LEN (CARL9170_TX_SUPERDESC_LEN + \
+ AR9170_TX_HWDESC_LEN)
+
+struct ar9170_rx_head {
+ u8 plcp[12];
+} __packed;
+
+#define AR9170_RX_HEAD_LEN 12
+
+struct ar9170_rx_phystatus {
+ union {
+ struct {
+ u8 rssi_ant0, rssi_ant1, rssi_ant2,
+ rssi_ant0x, rssi_ant1x, rssi_ant2x,
+ rssi_combined;
+ } __packed;
+ u8 rssi[7];
+ } __packed;
+
+ u8 evm_stream0[6], evm_stream1[6];
+ u8 phy_err;
+} __packed;
+
+#define AR9170_RX_PHYSTATUS_LEN 20
+
+struct ar9170_rx_macstatus {
+ u8 SAidx, DAidx;
+ u8 error;
+ u8 status;
+} __packed;
+
+#define AR9170_RX_MACSTATUS_LEN 4
+
+struct ar9170_rx_frame_single {
+ struct ar9170_rx_head phy_head;
+ struct ieee80211_hdr i3e;
+ struct ar9170_rx_phystatus phy_tail;
+ struct ar9170_rx_macstatus macstatus;
+} __packed;
+
+struct ar9170_rx_frame_head {
+ struct ar9170_rx_head phy_head;
+ struct ieee80211_hdr i3e;
+ struct ar9170_rx_macstatus macstatus;
+} __packed;
+
+struct ar9170_rx_frame_middle {
+ struct ieee80211_hdr i3e;
+ struct ar9170_rx_macstatus macstatus;
+} __packed;
+
+struct ar9170_rx_frame_tail {
+ struct ieee80211_hdr i3e;
+ struct ar9170_rx_phystatus phy_tail;
+ struct ar9170_rx_macstatus macstatus;
+} __packed;
+
+struct ar9170_rx_frame {
+ union {
+ struct ar9170_rx_frame_single single;
+ struct ar9170_rx_frame_head head;
+ struct ar9170_rx_frame_middle middle;
+ struct ar9170_rx_frame_tail tail;
+ } __packed;
+} __packed;
+
+static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t)
+{
+ return (t->SAidx & 0xc0) >> 4 |
+ (t->DAidx & 0xc0) >> 6;
+}
+
+enum ar9170_txq {
+ AR9170_TXQ_BE,
+
+ AR9170_TXQ_VI,
+ AR9170_TXQ_VO,
+ AR9170_TXQ_BK,
+
+ __AR9170_NUM_TXQ,
+};
+
+static const u8 ar9170_qmap[__AR9170_NUM_TXQ] = { 2, 1, 0, 3 };
+
+#define AR9170_TXQ_DEPTH 32
+
+#endif /* __CARL9170_SHARED_WLAN_H */
diff --git a/drivers/net/wireless/ath/debug.c b/drivers/net/wireless/ath/debug.c
index 53e77bd131b9..dacfb234f491 100644
--- a/drivers/net/wireless/ath/debug.c
+++ b/drivers/net/wireless/ath/debug.c
@@ -30,3 +30,32 @@ void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...)
va_end(args);
}
EXPORT_SYMBOL(ath_print);
+
+const char *ath_opmode_to_string(enum nl80211_iftype opmode)
+{
+ switch (opmode) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ return "UNSPEC";
+ case NL80211_IFTYPE_ADHOC:
+ return "ADHOC";
+ case NL80211_IFTYPE_STATION:
+ return "STATION";
+ case NL80211_IFTYPE_AP:
+ return "AP";
+ case NL80211_IFTYPE_AP_VLAN:
+ return "AP-VLAN";
+ case NL80211_IFTYPE_WDS:
+ return "WDS";
+ case NL80211_IFTYPE_MONITOR:
+ return "MONITOR";
+ case NL80211_IFTYPE_MESH_POINT:
+ return "MESH";
+ case NL80211_IFTYPE_P2P_CLIENT:
+ return "P2P-CLIENT";
+ case NL80211_IFTYPE_P2P_GO:
+ return "P2P-GO";
+ default:
+ return "UNKNOWN";
+ }
+}
+EXPORT_SYMBOL(ath_opmode_to_string);
diff --git a/drivers/net/wireless/ath/debug.h b/drivers/net/wireless/ath/debug.h
index 873bf526e11f..64e4af2c2887 100644
--- a/drivers/net/wireless/ath/debug.h
+++ b/drivers/net/wireless/ath/debug.h
@@ -36,6 +36,7 @@
* @ATH_DBG_PS: power save processing
* @ATH_DBG_HWTIMER: hardware timer handling
* @ATH_DBG_BTCOEX: bluetooth coexistance
+ * @ATH_DBG_BSTUCK: stuck beacons
* @ATH_DBG_ANY: enable all debugging
*
* The debug level is used to control the amount and type of debugging output
@@ -60,6 +61,7 @@ enum ATH_DEBUG {
ATH_DBG_HWTIMER = 0x00001000,
ATH_DBG_BTCOEX = 0x00002000,
ATH_DBG_WMI = 0x00004000,
+ ATH_DBG_BSTUCK = 0x00008000,
ATH_DBG_ANY = 0xffffffff
};
@@ -75,4 +77,14 @@ ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...)
}
#endif /* CONFIG_ATH_DEBUG */
+/** Returns string describing opmode, or NULL if unknown mode. */
+#ifdef CONFIG_ATH_DEBUG
+const char *ath_opmode_to_string(enum nl80211_iftype opmode);
+#else
+static inline const char *ath_opmode_to_string(enum nl80211_iftype opmode)
+{
+ return "UNKNOWN";
+}
+#endif
+
#endif /* ATH_DEBUG_H */
diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c
index a8f81ea09f14..183c28281385 100644
--- a/drivers/net/wireless/ath/hw.c
+++ b/drivers/net/wireless/ath/hw.c
@@ -124,3 +124,62 @@ void ath_hw_setbssidmask(struct ath_common *common)
REG_WRITE(ah, get_unaligned_le16(common->bssidmask + 4), AR_BSSMSKU);
}
EXPORT_SYMBOL(ath_hw_setbssidmask);
+
+
+/**
+ * ath_hw_cycle_counters_update - common function to update cycle counters
+ *
+ * @common: the ath_common struct for the device.
+ *
+ * This function is used to update all cycle counters in one place.
+ * It has to be called while holding common->cc_lock!
+ */
+void ath_hw_cycle_counters_update(struct ath_common *common)
+{
+ u32 cycles, busy, rx, tx;
+ void *ah = common->ah;
+
+ /* freeze */
+ REG_WRITE(ah, AR_MIBC_FMC, AR_MIBC);
+
+ /* read */
+ cycles = REG_READ(ah, AR_CCCNT);
+ busy = REG_READ(ah, AR_RCCNT);
+ rx = REG_READ(ah, AR_RFCNT);
+ tx = REG_READ(ah, AR_TFCNT);
+
+ /* clear */
+ REG_WRITE(ah, 0, AR_CCCNT);
+ REG_WRITE(ah, 0, AR_RFCNT);
+ REG_WRITE(ah, 0, AR_RCCNT);
+ REG_WRITE(ah, 0, AR_TFCNT);
+
+ /* unfreeze */
+ REG_WRITE(ah, 0, AR_MIBC);
+
+ /* update all cycle counters here */
+ common->cc_ani.cycles += cycles;
+ common->cc_ani.rx_busy += busy;
+ common->cc_ani.rx_frame += rx;
+ common->cc_ani.tx_frame += tx;
+
+ common->cc_survey.cycles += cycles;
+ common->cc_survey.rx_busy += busy;
+ common->cc_survey.rx_frame += rx;
+ common->cc_survey.tx_frame += tx;
+}
+EXPORT_SYMBOL(ath_hw_cycle_counters_update);
+
+int32_t ath_hw_get_listen_time(struct ath_common *common)
+{
+ struct ath_cycle_counters *cc = &common->cc_ani;
+ int32_t listen_time;
+
+ listen_time = (cc->cycles - cc->rx_frame - cc->tx_frame) /
+ (common->clockrate * 1000);
+
+ memset(cc, 0, sizeof(*cc));
+
+ return listen_time;
+}
+EXPORT_SYMBOL(ath_hw_get_listen_time);
diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c
new file mode 100644
index 000000000000..bd21a4d82085
--- /dev/null
+++ b/drivers/net/wireless/ath/key.c
@@ -0,0 +1,568 @@
+/*
+ * Copyright (c) 2009 Atheros Communications Inc.
+ * Copyright (c) 2010 Bruno Randolf <br1@einfach.org>
+ *
+ * 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 <asm/unaligned.h>
+#include <net/mac80211.h>
+
+#include "ath.h"
+#include "reg.h"
+#include "debug.h"
+
+#define REG_READ (common->ops->read)
+#define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg)
+
+#define IEEE80211_WEP_NKID 4 /* number of key ids */
+
+/************************/
+/* Key Cache Management */
+/************************/
+
+bool ath_hw_keyreset(struct ath_common *common, u16 entry)
+{
+ u32 keyType;
+ void *ah = common->ah;
+
+ if (entry >= common->keymax) {
+ ath_print(common, ATH_DBG_FATAL,
+ "keychache entry %u out of range\n", entry);
+ return false;
+ }
+
+ keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
+
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
+ REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
+
+ if (keyType == AR_KEYTABLE_TYPE_TKIP) {
+ u16 micentry = entry + 64;
+
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
+
+ }
+
+ return true;
+}
+EXPORT_SYMBOL(ath_hw_keyreset);
+
+bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac)
+{
+ u32 macHi, macLo;
+ u32 unicast_flag = AR_KEYTABLE_VALID;
+ void *ah = common->ah;
+
+ if (entry >= common->keymax) {
+ ath_print(common, ATH_DBG_FATAL,
+ "keychache entry %u out of range\n", entry);
+ return false;
+ }
+
+ if (mac != NULL) {
+ /*
+ * AR_KEYTABLE_VALID indicates that the address is a unicast
+ * address, which must match the transmitter address for
+ * decrypting frames.
+ * Not setting this bit allows the hardware to use the key
+ * for multicast frame decryption.
+ */
+ if (mac[0] & 0x01)
+ unicast_flag = 0;
+
+ macHi = (mac[5] << 8) | mac[4];
+ macLo = (mac[3] << 24) |
+ (mac[2] << 16) |
+ (mac[1] << 8) |
+ mac[0];
+ macLo >>= 1;
+ macLo |= (macHi & 1) << 31;
+ macHi >>= 1;
+ } else {
+ macLo = macHi = 0;
+ }
+ REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
+ REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag);
+
+ return true;
+}
+
+bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
+ const struct ath_keyval *k,
+ const u8 *mac)
+{
+ void *ah = common->ah;
+ u32 key0, key1, key2, key3, key4;
+ u32 keyType;
+
+ if (entry >= common->keymax) {
+ ath_print(common, ATH_DBG_FATAL,
+ "keycache entry %u out of range\n", entry);
+ return false;
+ }
+
+ switch (k->kv_type) {
+ case ATH_CIPHER_AES_OCB:
+ keyType = AR_KEYTABLE_TYPE_AES;
+ break;
+ case ATH_CIPHER_AES_CCM:
+ if (!(common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)) {
+ ath_print(common, ATH_DBG_ANY,
+ "AES-CCM not supported by this mac rev\n");
+ return false;
+ }
+ keyType = AR_KEYTABLE_TYPE_CCM;
+ break;
+ case ATH_CIPHER_TKIP:
+ keyType = AR_KEYTABLE_TYPE_TKIP;
+ if (entry + 64 >= common->keymax) {
+ ath_print(common, ATH_DBG_ANY,
+ "entry %u inappropriate for TKIP\n", entry);
+ return false;
+ }
+ break;
+ case ATH_CIPHER_WEP:
+ if (k->kv_len < WLAN_KEY_LEN_WEP40) {
+ ath_print(common, ATH_DBG_ANY,
+ "WEP key length %u too small\n", k->kv_len);
+ return false;
+ }
+ if (k->kv_len <= WLAN_KEY_LEN_WEP40)
+ keyType = AR_KEYTABLE_TYPE_40;
+ else if (k->kv_len <= WLAN_KEY_LEN_WEP104)
+ keyType = AR_KEYTABLE_TYPE_104;
+ else
+ keyType = AR_KEYTABLE_TYPE_128;
+ break;
+ case ATH_CIPHER_CLR:
+ keyType = AR_KEYTABLE_TYPE_CLR;
+ break;
+ default:
+ ath_print(common, ATH_DBG_FATAL,
+ "cipher %u not supported\n", k->kv_type);
+ return false;
+ }
+
+ key0 = get_unaligned_le32(k->kv_val + 0);
+ key1 = get_unaligned_le16(k->kv_val + 4);
+ key2 = get_unaligned_le32(k->kv_val + 6);
+ key3 = get_unaligned_le16(k->kv_val + 10);
+ key4 = get_unaligned_le32(k->kv_val + 12);
+ if (k->kv_len <= WLAN_KEY_LEN_WEP104)
+ key4 &= 0xff;
+
+ /*
+ * Note: Key cache registers access special memory area that requires
+ * two 32-bit writes to actually update the values in the internal
+ * memory. Consequently, the exact order and pairs used here must be
+ * maintained.
+ */
+
+ if (keyType == AR_KEYTABLE_TYPE_TKIP) {
+ u16 micentry = entry + 64;
+
+ /*
+ * Write inverted key[47:0] first to avoid Michael MIC errors
+ * on frames that could be sent or received at the same time.
+ * The correct key will be written in the end once everything
+ * else is ready.
+ */
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
+
+ /* Write key[95:48] */
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
+
+ /* Write key[127:96] and key type */
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
+ REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
+
+ /* Write MAC address for the entry */
+ (void) ath_hw_keysetmac(common, entry, mac);
+
+ if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) {
+ /*
+ * TKIP uses two key cache entries:
+ * Michael MIC TX/RX keys in the same key cache entry
+ * (idx = main index + 64):
+ * key0 [31:0] = RX key [31:0]
+ * key1 [15:0] = TX key [31:16]
+ * key1 [31:16] = reserved
+ * key2 [31:0] = RX key [63:32]
+ * key3 [15:0] = TX key [15:0]
+ * key3 [31:16] = reserved
+ * key4 [31:0] = TX key [63:32]
+ */
+ u32 mic0, mic1, mic2, mic3, mic4;
+
+ mic0 = get_unaligned_le32(k->kv_mic + 0);
+ mic2 = get_unaligned_le32(k->kv_mic + 4);
+ mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
+ mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
+ mic4 = get_unaligned_le32(k->kv_txmic + 4);
+
+ /* Write RX[31:0] and TX[31:16] */
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
+
+ /* Write RX[63:32] and TX[15:0] */
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
+
+ /* Write TX[63:32] and keyType(reserved) */
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
+ REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
+ AR_KEYTABLE_TYPE_CLR);
+
+ } else {
+ /*
+ * TKIP uses four key cache entries (two for group
+ * keys):
+ * Michael MIC TX/RX keys are in different key cache
+ * entries (idx = main index + 64 for TX and
+ * main index + 32 + 96 for RX):
+ * key0 [31:0] = TX/RX MIC key [31:0]
+ * key1 [31:0] = reserved
+ * key2 [31:0] = TX/RX MIC key [63:32]
+ * key3 [31:0] = reserved
+ * key4 [31:0] = reserved
+ *
+ * Upper layer code will call this function separately
+ * for TX and RX keys when these registers offsets are
+ * used.
+ */
+ u32 mic0, mic2;
+
+ mic0 = get_unaligned_le32(k->kv_mic + 0);
+ mic2 = get_unaligned_le32(k->kv_mic + 4);
+
+ /* Write MIC key[31:0] */
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
+
+ /* Write MIC key[63:32] */
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
+
+ /* Write TX[63:32] and keyType(reserved) */
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
+ AR_KEYTABLE_TYPE_CLR);
+ }
+
+ /* MAC address registers are reserved for the MIC entry */
+ REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
+
+ /*
+ * Write the correct (un-inverted) key[47:0] last to enable
+ * TKIP now that all other registers are set with correct
+ * values.
+ */
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
+ } else {
+ /* Write key[47:0] */
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
+
+ /* Write key[95:48] */
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
+
+ /* Write key[127:96] and key type */
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
+ REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
+
+ /* Write MAC address for the entry */
+ (void) ath_hw_keysetmac(common, entry, mac);
+ }
+
+ return true;
+}
+
+static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key,
+ struct ath_keyval *hk, const u8 *addr,
+ bool authenticator)
+{
+ const u8 *key_rxmic;
+ const u8 *key_txmic;
+
+ key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
+ key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
+
+ if (addr == NULL) {
+ /*
+ * Group key installation - only two key cache entries are used
+ * regardless of splitmic capability since group key is only
+ * used either for TX or RX.
+ */
+ if (authenticator) {
+ memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
+ memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic));
+ } else {
+ memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
+ memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));
+ }
+ return ath_hw_set_keycache_entry(common, keyix, hk, addr);
+ }
+ if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) {
+ /* TX and RX keys share the same key cache entry. */
+ memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
+ memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
+ return ath_hw_set_keycache_entry(common, keyix, hk, addr);
+ }
+
+ /* Separate key cache entries for TX and RX */
+
+ /* TX key goes at first index, RX key at +32. */
+ memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
+ if (!ath_hw_set_keycache_entry(common, keyix, hk, NULL)) {
+ /* TX MIC entry failed. No need to proceed further */
+ ath_print(common, ATH_DBG_FATAL,
+ "Setting TX MIC Key Failed\n");
+ return 0;
+ }
+
+ memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
+ /* XXX delete tx key on failure? */
+ return ath_hw_set_keycache_entry(common, keyix + 32, hk, addr);
+}
+
+static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
+{
+ int i;
+
+ for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
+ if (test_bit(i, common->keymap) ||
+ test_bit(i + 64, common->keymap))
+ continue; /* At least one part of TKIP key allocated */
+ if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) &&
+ (test_bit(i + 32, common->keymap) ||
+ test_bit(i + 64 + 32, common->keymap)))
+ continue; /* At least one part of TKIP key allocated */
+
+ /* Found a free slot for a TKIP key */
+ return i;
+ }
+ return -1;
+}
+
+static int ath_reserve_key_cache_slot(struct ath_common *common,
+ u32 cipher)
+{
+ int i;
+
+ if (cipher == WLAN_CIPHER_SUITE_TKIP)
+ return ath_reserve_key_cache_slot_tkip(common);
+
+ /* First, try to find slots that would not be available for TKIP. */
+ if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
+ for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {
+ if (!test_bit(i, common->keymap) &&
+ (test_bit(i + 32, common->keymap) ||
+ test_bit(i + 64, common->keymap) ||
+ test_bit(i + 64 + 32, common->keymap)))
+ return i;
+ if (!test_bit(i + 32, common->keymap) &&
+ (test_bit(i, common->keymap) ||
+ test_bit(i + 64, common->keymap) ||
+ test_bit(i + 64 + 32, common->keymap)))
+ return i + 32;
+ if (!test_bit(i + 64, common->keymap) &&
+ (test_bit(i , common->keymap) ||
+ test_bit(i + 32, common->keymap) ||
+ test_bit(i + 64 + 32, common->keymap)))
+ return i + 64;
+ if (!test_bit(i + 64 + 32, common->keymap) &&
+ (test_bit(i, common->keymap) ||
+ test_bit(i + 32, common->keymap) ||
+ test_bit(i + 64, common->keymap)))
+ return i + 64 + 32;
+ }
+ } else {
+ for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
+ if (!test_bit(i, common->keymap) &&
+ test_bit(i + 64, common->keymap))
+ return i;
+ if (test_bit(i, common->keymap) &&
+ !test_bit(i + 64, common->keymap))
+ return i + 64;
+ }
+ }
+
+ /* No partially used TKIP slots, pick any available slot */
+ for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) {
+ /* Do not allow slots that could be needed for TKIP group keys
+ * to be used. This limitation could be removed if we know that
+ * TKIP will not be used. */
+ if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
+ continue;
+ if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
+ if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
+ continue;
+ if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
+ continue;
+ }
+
+ if (!test_bit(i, common->keymap))
+ return i; /* Found a free slot for a key */
+ }
+
+ /* No free slot found */
+ return -1;
+}
+
+/*
+ * Configure encryption in the HW.
+ */
+int ath_key_config(struct ath_common *common,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct ath_keyval hk;
+ const u8 *mac = NULL;
+ u8 gmac[ETH_ALEN];
+ int ret = 0;
+ int idx;
+
+ memset(&hk, 0, sizeof(hk));
+
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ hk.kv_type = ATH_CIPHER_WEP;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ hk.kv_type = ATH_CIPHER_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ hk.kv_type = ATH_CIPHER_AES_CCM;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ hk.kv_len = key->keylen;
+ memcpy(hk.kv_val, key->key, key->keylen);
+
+ if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+ switch (vif->type) {
+ case NL80211_IFTYPE_AP:
+ memcpy(gmac, vif->addr, ETH_ALEN);
+ gmac[0] |= 0x01;
+ mac = gmac;
+ idx = ath_reserve_key_cache_slot(common, key->cipher);
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ if (!sta) {
+ idx = key->keyidx;
+ break;
+ }
+ memcpy(gmac, sta->addr, ETH_ALEN);
+ gmac[0] |= 0x01;
+ mac = gmac;
+ idx = ath_reserve_key_cache_slot(common, key->cipher);
+ break;
+ default:
+ idx = key->keyidx;
+ break;
+ }
+ } else if (key->keyidx) {
+ if (WARN_ON(!sta))
+ return -EOPNOTSUPP;
+ mac = sta->addr;
+
+ if (vif->type != NL80211_IFTYPE_AP) {
+ /* Only keyidx 0 should be used with unicast key, but
+ * allow this for client mode for now. */
+ idx = key->keyidx;
+ } else
+ return -EIO;
+ } else {
+ if (WARN_ON(!sta))
+ return -EOPNOTSUPP;
+ mac = sta->addr;
+
+ idx = ath_reserve_key_cache_slot(common, key->cipher);
+ }
+
+ if (idx < 0)
+ return -ENOSPC; /* no free key cache entries */
+
+ if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
+ ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
+ vif->type == NL80211_IFTYPE_AP);
+ else
+ ret = ath_hw_set_keycache_entry(common, idx, &hk, mac);
+
+ if (!ret)
+ return -EIO;
+
+ set_bit(idx, common->keymap);
+ if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
+ set_bit(idx + 64, common->keymap);
+ set_bit(idx, common->tkip_keymap);
+ set_bit(idx + 64, common->tkip_keymap);
+ if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
+ set_bit(idx + 32, common->keymap);
+ set_bit(idx + 64 + 32, common->keymap);
+ set_bit(idx + 32, common->tkip_keymap);
+ set_bit(idx + 64 + 32, common->tkip_keymap);
+ }
+ }
+
+ return idx;
+}
+EXPORT_SYMBOL(ath_key_config);
+
+/*
+ * Delete Key.
+ */
+void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key)
+{
+ ath_hw_keyreset(common, key->hw_key_idx);
+ if (key->hw_key_idx < IEEE80211_WEP_NKID)
+ return;
+
+ clear_bit(key->hw_key_idx, common->keymap);
+ if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
+ return;
+
+ clear_bit(key->hw_key_idx + 64, common->keymap);
+
+ clear_bit(key->hw_key_idx, common->tkip_keymap);
+ clear_bit(key->hw_key_idx + 64, common->tkip_keymap);
+
+ if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
+ ath_hw_keyreset(common, key->hw_key_idx + 32);
+ clear_bit(key->hw_key_idx + 32, common->keymap);
+ clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
+
+ clear_bit(key->hw_key_idx + 32, common->tkip_keymap);
+ clear_bit(key->hw_key_idx + 64 + 32, common->tkip_keymap);
+ }
+}
+EXPORT_SYMBOL(ath_key_delete);
diff --git a/drivers/net/wireless/ath/reg.h b/drivers/net/wireless/ath/reg.h
index dfe1fbec24f5..298e53f3fa48 100644
--- a/drivers/net/wireless/ath/reg.h
+++ b/drivers/net/wireless/ath/reg.h
@@ -17,6 +17,12 @@
#ifndef ATH_REGISTERS_H
#define ATH_REGISTERS_H
+#define AR_MIBC 0x0040
+#define AR_MIBC_COW 0x00000001
+#define AR_MIBC_FMC 0x00000002
+#define AR_MIBC_CMC 0x00000004
+#define AR_MIBC_MCS 0x00000008
+
/*
* BSSID mask registers. See ath_hw_set_bssid_mask()
* for detailed documentation about these registers.
@@ -24,4 +30,32 @@
#define AR_BSSMSKL 0x80e0
#define AR_BSSMSKU 0x80e4
+#define AR_TFCNT 0x80ec
+#define AR_RFCNT 0x80f0
+#define AR_RCCNT 0x80f4
+#define AR_CCCNT 0x80f8
+
+#define AR_KEYTABLE_0 0x8800
+#define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32))
+#define AR_KEY_CACHE_SIZE 128
+#define AR_RSVD_KEYTABLE_ENTRIES 4
+#define AR_KEY_TYPE 0x00000007
+#define AR_KEYTABLE_TYPE_40 0x00000000
+#define AR_KEYTABLE_TYPE_104 0x00000001
+#define AR_KEYTABLE_TYPE_128 0x00000003
+#define AR_KEYTABLE_TYPE_TKIP 0x00000004
+#define AR_KEYTABLE_TYPE_AES 0x00000005
+#define AR_KEYTABLE_TYPE_CCM 0x00000006
+#define AR_KEYTABLE_TYPE_CLR 0x00000007
+#define AR_KEYTABLE_ANT 0x00000008
+#define AR_KEYTABLE_VALID 0x00008000
+#define AR_KEYTABLE_KEY0(_n) (AR_KEYTABLE(_n) + 0)
+#define AR_KEYTABLE_KEY1(_n) (AR_KEYTABLE(_n) + 4)
+#define AR_KEYTABLE_KEY2(_n) (AR_KEYTABLE(_n) + 8)
+#define AR_KEYTABLE_KEY3(_n) (AR_KEYTABLE(_n) + 12)
+#define AR_KEYTABLE_KEY4(_n) (AR_KEYTABLE(_n) + 16)
+#define AR_KEYTABLE_TYPE(_n) (AR_KEYTABLE(_n) + 20)
+#define AR_KEYTABLE_MAC0(_n) (AR_KEYTABLE(_n) + 24)
+#define AR_KEYTABLE_MAC1(_n) (AR_KEYTABLE(_n) + 28)
+
#endif /* ATH_REGISTERS_H */
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
index 5e83b6f0a3a0..69d4af09a6cb 100644
--- a/drivers/net/wireless/b43/Makefile
+++ b/drivers/net/wireless/b43/Makefile
@@ -1,6 +1,8 @@
b43-y += main.o
b43-y += tables.o
b43-$(CONFIG_B43_NPHY) += tables_nphy.o
+b43-$(CONFIG_B43_NPHY) += radio_2055.o
+b43-$(CONFIG_B43_NPHY) += radio_2056.o
b43-y += phy_common.o
b43-y += phy_g.o
b43-y += phy_a.o
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 8674a99356af..72821c456b02 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -186,7 +186,8 @@ enum {
#define B43_SHM_SH_PHYTXNOI 0x006E /* PHY noise directly after TX (lower 8bit only) */
#define B43_SHM_SH_RFRXSP1 0x0072 /* RF RX SP Register 1 */
#define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */
-#define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5Ghz channel */
+#define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5 Ghz channel */
+#define B43_SHM_SH_CHAN_40MHZ 0x0200 /* Bit set, if 40 Mhz channel width */
#define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */
/* TSSI information */
#define B43_SHM_SH_TSSI_CCK 0x0058 /* TSSI for last 4 CCK frames (32bit) */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 20631ae2ddd7..a1186525c70d 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -2280,6 +2280,7 @@ out:
static int b43_upload_microcode(struct b43_wldev *dev)
{
+ struct wiphy *wiphy = dev->wl->hw->wiphy;
const size_t hdr_len = sizeof(struct b43_fw_header);
const __be32 *data;
unsigned int i, len;
@@ -2405,6 +2406,10 @@ static int b43_upload_microcode(struct b43_wldev *dev)
}
}
+ snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "%u.%u",
+ dev->fw.rev, dev->fw.patch);
+ wiphy->hw_version = dev->dev->id.coreid;
+
if (b43_is_old_txhdr_format(dev)) {
/* We're over the deadline, but we keep support for old fw
* until it turns out to be in major conflict with something new. */
@@ -3754,17 +3759,17 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
}
err = -EINVAL;
- switch (key->alg) {
- case ALG_WEP:
- if (key->keylen == WLAN_KEY_LEN_WEP40)
- algorithm = B43_SEC_ALGO_WEP40;
- else
- algorithm = B43_SEC_ALGO_WEP104;
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ algorithm = B43_SEC_ALGO_WEP40;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ algorithm = B43_SEC_ALGO_WEP104;
break;
- case ALG_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
algorithm = B43_SEC_ALGO_TKIP;
break;
- case ALG_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
algorithm = B43_SEC_ALGO_AES;
break;
default:
@@ -4250,6 +4255,10 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
B43_WARN_ON(dev && b43_status(dev) > B43_STAT_INITIALIZED);
if (!dev || b43_status(dev) != B43_STAT_INITIALIZED)
return;
+
+ /* Unregister HW RNG driver */
+ b43_rng_exit(dev->wl);
+
b43_set_status(dev, B43_STAT_UNINIT);
/* Stop the microcode PSM. */
@@ -4379,6 +4388,9 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
b43_set_status(dev, B43_STAT_INITIALIZED);
+ /* Register HW RNG driver */
+ b43_rng_init(dev->wl);
+
out:
return err;
@@ -4984,7 +4996,6 @@ static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
if (err)
goto err_one_core_detach;
b43_leds_register(wl->current_dev);
- b43_rng_init(wl);
}
out:
@@ -5020,7 +5031,6 @@ static void b43_remove(struct ssb_device *dev)
b43_one_core_detach(dev);
if (list_empty(&wl->devlist)) {
- b43_rng_exit(wl);
b43_leds_unregister(wl);
/* Last core on the chip unregistered.
* We can destroy common struct b43_wl.
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index 8f7d7eff2d80..7b2ea6781457 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -294,8 +294,10 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)
*/
channelcookie = new_channel;
if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
- channelcookie |= 0x100;
- //FIXME set 40Mhz flag if required
+ channelcookie |= B43_SHM_SH_CHAN_5GHZ;
+ /* FIXME: set 40Mhz flag if required */
+ if (0)
+ channelcookie |= B43_SHM_SH_CHAN_40MHZ;
savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h
index bd480b481bfc..0e6194228845 100644
--- a/drivers/net/wireless/b43/phy_common.h
+++ b/drivers/net/wireless/b43/phy_common.h
@@ -2,6 +2,7 @@
#define LINUX_B43_PHY_COMMON_H_
#include <linux/types.h>
+#include <linux/nl80211.h>
struct b43_wldev;
@@ -250,8 +251,10 @@ struct b43_phy {
* check is needed. */
unsigned long next_txpwr_check_time;
- /* current channel */
+ /* Current channel */
unsigned int channel;
+ u16 channel_freq;
+ enum nl80211_channel_type channel_type;
/* PHY TX errors counter. */
atomic_t txerr_cnt;
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index 5a725703770c..e0f2d122e124 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -29,6 +29,8 @@
#include "b43.h"
#include "phy_n.h"
#include "tables_nphy.h"
+#include "radio_2055.h"
+#include "radio_2056.h"
#include "main.h"
struct nphy_txgains {
@@ -73,21 +75,12 @@ 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 int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel);
-static inline bool b43_empty_chanspec(struct b43_chanspec *chanspec)
+static inline bool b43_channel_type_is_40mhz(
+ enum nl80211_channel_type channel_type)
{
- return !chanspec->channel && !chanspec->sideband &&
- !chanspec->b_width && !chanspec->b_freq;
-}
-
-static inline bool b43_eq_chanspecs(struct b43_chanspec *chanspec1,
- struct b43_chanspec *chanspec2)
-{
- return (chanspec1->channel == chanspec2->channel &&
- chanspec1->sideband == chanspec2->sideband &&
- chanspec1->b_width == chanspec2->b_width &&
- chanspec1->b_freq == chanspec2->b_freq);
+ return (channel_type == NL80211_CHAN_HT40MINUS ||
+ channel_type == NL80211_CHAN_HT40PLUS);
}
void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
@@ -223,7 +216,7 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
if (i)
b43err(dev->wl, "radio post init timeout\n");
b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
- nphy_channel_switch(dev, dev->phy.channel);
+ b43_switch_channel(dev, dev->phy.channel);
b43_radio_write(dev, B2055_C1_RX_BB_LPF, 0x9);
b43_radio_write(dev, B2055_C2_RX_BB_LPF, 0x9);
b43_radio_write(dev, B2055_C1_RX_BB_MIDACHP, 0x83);
@@ -782,7 +775,7 @@ static void b43_nphy_spur_workaround(struct b43_wldev *dev)
{
struct b43_phy_n *nphy = dev->phy.n;
- u8 channel = nphy->radio_chanspec.channel;
+ u8 channel = dev->phy.channel;
int tone[2] = { 57, 58 };
u32 noise[2] = { 0x3FF, 0x3FF };
@@ -856,9 +849,9 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev)
gain[0] = 6;
gain[1] = 6;
} else {
- tmp = 40370 - 315 * nphy->radio_chanspec.channel;
+ tmp = 40370 - 315 * dev->phy.channel;
gain[0] = ((tmp >> 13) + ((tmp >> 12) & 1));
- tmp = 23242 - 224 * nphy->radio_chanspec.channel;
+ tmp = 23242 - 224 * dev->phy.channel;
gain[1] = ((tmp >> 13) + ((tmp >> 12) & 1));
}
} else {
@@ -893,7 +886,7 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev)
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
-static void b43_nphy_gain_crtl_workarounds(struct b43_wldev *dev)
+static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
{
struct b43_phy_n *nphy = dev->phy.n;
u8 i, j;
@@ -1094,11 +1087,12 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);
b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);
- b43_nphy_gain_crtl_workarounds(dev);
+ b43_nphy_gain_ctrl_workarounds(dev);
if (dev->phy.rev < 2) {
if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2)
- ; /*TODO: b43_mhf(dev, 2, 0x0010, 0x0010, 3);*/
+ 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);
@@ -1182,7 +1176,7 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max,
len = bw << 1;
}
- samples = kzalloc(len * sizeof(struct b43_c32), GFP_KERNEL);
+ samples = kcalloc(len, sizeof(struct b43_c32), GFP_KERNEL);
if (!samples) {
b43err(dev->wl, "allocation for samples generation failed\n");
return 0;
@@ -2083,12 +2077,12 @@ static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev)
u16 *rssical_phy_regs = NULL;
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
- if (b43_empty_chanspec(&nphy->rssical_chanspec_2G))
+ if (!nphy->rssical_chanspec_2G.center_freq)
return;
rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_2G;
rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_2G;
} else {
- if (b43_empty_chanspec(&nphy->rssical_chanspec_5G))
+ if (!nphy->rssical_chanspec_5G.center_freq)
return;
rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_5G;
rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_5G;
@@ -2544,8 +2538,9 @@ static void b43_nphy_save_cal(struct b43_wldev *dev)
txcal_radio_regs[2] = b43_radio_read(dev, 0x8D);
txcal_radio_regs[3] = b43_radio_read(dev, 0xBC);
}
- *iqcal_chanspec = nphy->radio_chanspec;
- b43_ntab_write_bulk(dev, B43_NTAB16(15, 80), 8, table);
+ iqcal_chanspec->center_freq = dev->phy.channel_freq;
+ iqcal_chanspec->channel_type = dev->phy.channel_type;
+ b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 8, table);
if (nphy->hang_avoid)
b43_nphy_stay_in_carrier_search(dev, 0);
@@ -2565,12 +2560,12 @@ static void b43_nphy_restore_cal(struct b43_wldev *dev)
struct b43_phy_n_iq_comp *rxcal_coeffs = NULL;
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
- if (b43_empty_chanspec(&nphy->iqcal_chanspec_2G))
+ if (!nphy->iqcal_chanspec_2G.center_freq)
return;
table = nphy->cal_cache.txcal_coeffs_2G;
loft = &nphy->cal_cache.txcal_coeffs_2G[5];
} else {
- if (b43_empty_chanspec(&nphy->iqcal_chanspec_5G))
+ if (!nphy->iqcal_chanspec_5G.center_freq)
return;
table = nphy->cal_cache.txcal_coeffs_5G;
loft = &nphy->cal_cache.txcal_coeffs_5G[5];
@@ -2815,7 +2810,10 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length,
nphy->txiqlocal_bestc);
nphy->txiqlocal_coeffsvalid = true;
- nphy->txiqlocal_chanspec = nphy->radio_chanspec;
+ nphy->txiqlocal_chanspec.center_freq =
+ dev->phy.channel_freq;
+ nphy->txiqlocal_chanspec.channel_type =
+ dev->phy.channel_type;
} else {
length = 11;
if (dev->phy.rev < 3)
@@ -2851,7 +2849,8 @@ static void b43_nphy_reapply_tx_cal_coeffs(struct b43_wldev *dev)
bool equal = true;
if (!nphy->txiqlocal_coeffsvalid ||
- b43_eq_chanspecs(&nphy->txiqlocal_chanspec, &nphy->radio_chanspec))
+ nphy->txiqlocal_chanspec.center_freq != dev->phy.channel_freq ||
+ nphy->txiqlocal_chanspec.channel_type != dev->phy.channel_type)
return;
b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer);
@@ -2965,7 +2964,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
(2 - i));
}
- for (j = 0; i < 4; j++) {
+ for (j = 0; j < 4; j++) {
if (j < 3) {
cur_lna = lna[j];
cur_hpf1 = hpf1[j];
@@ -3073,6 +3072,57 @@ static int b43_nphy_cal_rx_iq(struct b43_wldev *dev,
return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug);
}
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */
+static void b43_nphy_mac_phy_clock_set(struct b43_wldev *dev, bool on)
+{
+ u32 tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+ if (on)
+ tmslow |= SSB_TMSLOW_PHYCLK;
+ else
+ tmslow &= ~SSB_TMSLOW_PHYCLK;
+ ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreSetState */
+static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_phy_n *nphy = phy->n;
+ u16 buf[16];
+
+ nphy->phyrxchain = mask;
+
+ if (0 /* FIXME clk */)
+ return;
+
+ b43_mac_suspend(dev);
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, true);
+
+ b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_RXEN,
+ (mask & 0x3) << B43_NPHY_RFSEQCA_RXEN_SHIFT);
+
+ if ((mask & 0x3) != 0x3) {
+ b43_phy_write(dev, B43_NPHY_HPANT_SWTHRES, 1);
+ if (dev->phy.rev >= 3) {
+ /* TODO */
+ }
+ } else {
+ b43_phy_write(dev, B43_NPHY_HPANT_SWTHRES, 0x1E);
+ if (dev->phy.rev >= 3) {
+ /* TODO */
+ }
+ }
+
+ b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, false);
+
+ b43_mac_enable(dev);
+}
+
/*
* Init N-PHY
* http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N
@@ -3173,7 +3223,7 @@ int b43_phy_initn(struct b43_wldev *dev)
b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA);
b43_nphy_bmac_clock_fgc(dev, 0);
- /* TODO N PHY MAC PHY Clock Set with argument 1 */
+ b43_nphy_mac_phy_clock_set(dev, true);
b43_nphy_pa_override(dev, false);
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
@@ -3199,18 +3249,16 @@ int b43_phy_initn(struct b43_wldev *dev)
}
if (nphy->phyrxchain != 3)
- ;/* TODO N PHY RX Core Set State with phyrxchain as argument */
+ b43_nphy_set_rx_core_state(dev, nphy->phyrxchain);
if (nphy->mphase_cal_phase_id > 0)
;/* TODO PHY Periodic Calibration Multi-Phase Restart */
do_rssi_cal = false;
if (phy->rev >= 3) {
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
- do_rssi_cal =
- b43_empty_chanspec(&nphy->rssical_chanspec_2G);
+ do_rssi_cal = !nphy->rssical_chanspec_2G.center_freq;
else
- do_rssi_cal =
- b43_empty_chanspec(&nphy->rssical_chanspec_5G);
+ do_rssi_cal = !nphy->rssical_chanspec_5G.center_freq;
if (do_rssi_cal)
b43_nphy_rssi_cal(dev);
@@ -3222,9 +3270,9 @@ int b43_phy_initn(struct b43_wldev *dev)
if (!((nphy->measure_hold & 0x6) != 0)) {
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
- do_cal = b43_empty_chanspec(&nphy->iqcal_chanspec_2G);
+ do_cal = !nphy->iqcal_chanspec_2G.center_freq;
else
- do_cal = b43_empty_chanspec(&nphy->iqcal_chanspec_5G);
+ do_cal = !nphy->iqcal_chanspec_5G.center_freq;
if (nphy->mute)
do_cal = false;
@@ -3272,24 +3320,25 @@ int b43_phy_initn(struct b43_wldev *dev)
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ChanspecSetup */
-static void b43_nphy_chanspec_setup(struct b43_wldev *dev,
+static void b43_nphy_channel_setup(struct b43_wldev *dev,
const struct b43_phy_n_sfo_cfg *e,
- struct b43_chanspec chanspec)
+ struct ieee80211_channel *new_channel)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = dev->phy.n;
- u16 tmp;
+ u16 old_band_5ghz;
u32 tmp32;
- tmp = b43_phy_read(dev, B43_NPHY_BANDCTL) & B43_NPHY_BANDCTL_5GHZ;
- if (chanspec.b_freq == 1 && tmp == 0) {
+ old_band_5ghz =
+ b43_phy_read(dev, B43_NPHY_BANDCTL) & B43_NPHY_BANDCTL_5GHZ;
+ if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) {
tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR);
b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4);
b43_phy_set(dev, B43_PHY_B_BBCFG, 0xC000);
b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32);
b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ);
- } else if (chanspec.b_freq == 1) {
+ } else if (new_channel->band == IEEE80211_BAND_2GHZ && old_band_5ghz) {
b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ);
tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR);
b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4);
@@ -3299,19 +3348,12 @@ static void b43_nphy_chanspec_setup(struct b43_wldev *dev,
b43_chantab_phy_upload(dev, e);
- tmp = chanspec.channel;
- if (chanspec.b_freq == 1)
- tmp |= 0x0100;
- if (chanspec.b_width == 3)
- tmp |= 0x0200;
- b43_shm_write16(dev, B43_SHM_SHARED, 0xA0, tmp);
-
- if (nphy->radio_chanspec.channel == 14) {
+ if (new_channel->hw_value == 14) {
b43_nphy_classifier(dev, 2, 0);
b43_phy_set(dev, B43_PHY_B_TEST, 0x0800);
} else {
b43_nphy_classifier(dev, 2, 2);
- if (chanspec.b_freq == 2)
+ if (new_channel->band == IEEE80211_BAND_2GHZ)
b43_phy_mask(dev, B43_PHY_B_TEST, ~0x840);
}
@@ -3334,70 +3376,62 @@ static void b43_nphy_chanspec_setup(struct b43_wldev *dev,
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetChanspec */
-static int b43_nphy_set_chanspec(struct b43_wldev *dev,
- struct b43_chanspec chanspec)
+static int b43_nphy_set_channel(struct b43_wldev *dev,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type)
{
+ struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = dev->phy.n;
const struct b43_nphy_channeltab_entry_rev2 *tabent_r2;
const struct b43_nphy_channeltab_entry_rev3 *tabent_r3;
u8 tmp;
- u8 channel = chanspec.channel;
if (dev->phy.rev >= 3) {
- /* TODO */
+ tabent_r3 = b43_nphy_get_chantabent_rev3(dev,
+ channel->center_freq);
tabent_r3 = NULL;
if (!tabent_r3)
return -ESRCH;
} else {
- tabent_r2 = b43_nphy_get_chantabent_rev2(dev, channel);
+ tabent_r2 = b43_nphy_get_chantabent_rev2(dev,
+ channel->hw_value);
if (!tabent_r2)
return -ESRCH;
}
- nphy->radio_chanspec = chanspec;
+ /* Channel is set later in common code, but we need to set it on our
+ own to let this function's subcalls work properly. */
+ phy->channel = channel->hw_value;
+ phy->channel_freq = channel->center_freq;
- if (chanspec.b_width != nphy->b_width)
- ; /* TODO: BMAC BW Set (chanspec.b_width) */
+ if (b43_channel_type_is_40mhz(phy->channel_type) !=
+ b43_channel_type_is_40mhz(channel_type))
+ ; /* TODO: BMAC BW Set (channel_type) */
- /* TODO: use defines */
- if (chanspec.b_width == 3) {
- if (chanspec.sideband == 2)
- b43_phy_set(dev, B43_NPHY_RXCTL,
- B43_NPHY_RXCTL_BSELU20);
- else
- b43_phy_mask(dev, B43_NPHY_RXCTL,
- ~B43_NPHY_RXCTL_BSELU20);
- }
+ if (channel_type == NL80211_CHAN_HT40PLUS)
+ b43_phy_set(dev, B43_NPHY_RXCTL,
+ B43_NPHY_RXCTL_BSELU20);
+ else if (channel_type == NL80211_CHAN_HT40MINUS)
+ b43_phy_mask(dev, B43_NPHY_RXCTL,
+ ~B43_NPHY_RXCTL_BSELU20);
if (dev->phy.rev >= 3) {
- tmp = (chanspec.b_freq == 1) ? 4 : 0;
+ tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 4 : 0;
b43_radio_maskset(dev, 0x08, 0xFFFB, tmp);
/* TODO: PHY Radio2056 Setup (dev, tabent_r3); */
- b43_nphy_chanspec_setup(dev, &(tabent_r3->phy_regs), chanspec);
+ b43_nphy_channel_setup(dev, &(tabent_r3->phy_regs), channel);
} else {
- tmp = (chanspec.b_freq == 1) ? 0x0020 : 0x0050;
+ tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 0x0020 : 0x0050;
b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, tmp);
b43_radio_2055_setup(dev, tabent_r2);
- b43_nphy_chanspec_setup(dev, &(tabent_r2->phy_regs), chanspec);
+ b43_nphy_channel_setup(dev, &(tabent_r2->phy_regs), channel);
}
return 0;
}
-/* Tune the hardware to a new channel */
-static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel)
-{
- struct b43_phy_n *nphy = dev->phy.n;
-
- struct b43_chanspec chanspec;
- chanspec = nphy->radio_chanspec;
- chanspec.channel = channel;
-
- return b43_nphy_set_chanspec(dev, chanspec);
-}
-
static int b43_nphy_op_allocate(struct b43_wldev *dev)
{
struct b43_phy_n *nphy;
@@ -3518,7 +3552,7 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
} else {
if (dev->phy.rev >= 3) {
b43_radio_init2056(dev);
- b43_nphy_set_chanspec(dev, nphy->radio_chanspec);
+ b43_switch_channel(dev, dev->phy.channel);
} else {
b43_radio_init2055(dev);
}
@@ -3534,6 +3568,9 @@ static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on)
static int b43_nphy_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;
@@ -3542,7 +3579,7 @@ static int b43_nphy_op_switch_channel(struct b43_wldev *dev,
return -EINVAL;
}
- return nphy_channel_switch(dev, new_channel);
+ return b43_nphy_set_channel(dev, channel, channel_type);
}
static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev)
diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h
index 8b6d570dd0aa..c144e59a708b 100644
--- a/drivers/net/wireless/b43/phy_n.h
+++ b/drivers/net/wireless/b43/phy_n.h
@@ -714,223 +714,11 @@
#define B43_PHY_B_BBCFG B43_PHY_N_BMODE(0x001) /* BB config */
#define B43_PHY_B_TEST B43_PHY_N_BMODE(0x00A)
-
-/* Broadcom 2055 radio registers */
-
-#define B2055_GEN_SPARE 0x00 /* GEN spare */
-#define B2055_SP_PINPD 0x02 /* SP PIN PD */
-#define B2055_C1_SP_RSSI 0x03 /* SP RSSI Core 1 */
-#define B2055_C1_SP_PDMISC 0x04 /* SP PD MISC Core 1 */
-#define B2055_C2_SP_RSSI 0x05 /* SP RSSI Core 2 */
-#define B2055_C2_SP_PDMISC 0x06 /* SP PD MISC Core 2 */
-#define B2055_C1_SP_RXGC1 0x07 /* SP RX GC1 Core 1 */
-#define B2055_C1_SP_RXGC2 0x08 /* SP RX GC2 Core 1 */
-#define B2055_C2_SP_RXGC1 0x09 /* SP RX GC1 Core 2 */
-#define B2055_C2_SP_RXGC2 0x0A /* SP RX GC2 Core 2 */
-#define B2055_C1_SP_LPFBWSEL 0x0B /* SP LPF BW select Core 1 */
-#define B2055_C2_SP_LPFBWSEL 0x0C /* SP LPF BW select Core 2 */
-#define B2055_C1_SP_TXGC1 0x0D /* SP TX GC1 Core 1 */
-#define B2055_C1_SP_TXGC2 0x0E /* SP TX GC2 Core 1 */
-#define B2055_C2_SP_TXGC1 0x0F /* SP TX GC1 Core 2 */
-#define B2055_C2_SP_TXGC2 0x10 /* SP TX GC2 Core 2 */
-#define B2055_MASTER1 0x11 /* Master control 1 */
-#define B2055_MASTER2 0x12 /* Master control 2 */
-#define B2055_PD_LGEN 0x13 /* PD LGEN */
-#define B2055_PD_PLLTS 0x14 /* PD PLL TS */
-#define B2055_C1_PD_LGBUF 0x15 /* PD Core 1 LGBUF */
-#define B2055_C1_PD_TX 0x16 /* PD Core 1 TX */
-#define B2055_C1_PD_RXTX 0x17 /* PD Core 1 RXTX */
-#define B2055_C1_PD_RSSIMISC 0x18 /* PD Core 1 RSSI MISC */
-#define B2055_C2_PD_LGBUF 0x19 /* PD Core 2 LGBUF */
-#define B2055_C2_PD_TX 0x1A /* PD Core 2 TX */
-#define B2055_C2_PD_RXTX 0x1B /* PD Core 2 RXTX */
-#define B2055_C2_PD_RSSIMISC 0x1C /* PD Core 2 RSSI MISC */
-#define B2055_PWRDET_LGEN 0x1D /* PWRDET LGEN */
-#define B2055_C1_PWRDET_LGBUF 0x1E /* PWRDET LGBUF Core 1 */
-#define B2055_C1_PWRDET_RXTX 0x1F /* PWRDET RXTX Core 1 */
-#define B2055_C2_PWRDET_LGBUF 0x20 /* PWRDET LGBUF Core 2 */
-#define B2055_C2_PWRDET_RXTX 0x21 /* PWRDET RXTX Core 2 */
-#define B2055_RRCCAL_CS 0x22 /* RRCCAL Control spare */
-#define B2055_RRCCAL_NOPTSEL 0x23 /* RRCCAL N OPT SEL */
-#define B2055_CAL_MISC 0x24 /* CAL MISC */
-#define B2055_CAL_COUT 0x25 /* CAL Counter out */
-#define B2055_CAL_COUT2 0x26 /* CAL Counter out 2 */
-#define B2055_CAL_CVARCTL 0x27 /* CAL CVAR Control */
-#define B2055_CAL_RVARCTL 0x28 /* CAL RVAR Control */
-#define B2055_CAL_LPOCTL 0x29 /* CAL LPO Control */
-#define B2055_CAL_TS 0x2A /* CAL TS */
-#define B2055_CAL_RCCALRTS 0x2B /* CAL RCCAL READ TS */
-#define B2055_CAL_RCALRTS 0x2C /* CAL RCAL READ TS */
-#define B2055_PADDRV 0x2D /* PAD driver */
-#define B2055_XOCTL1 0x2E /* XO Control 1 */
-#define B2055_XOCTL2 0x2F /* XO Control 2 */
-#define B2055_XOREGUL 0x30 /* XO Regulator */
-#define B2055_XOMISC 0x31 /* XO misc */
-#define B2055_PLL_LFC1 0x32 /* PLL LF C1 */
-#define B2055_PLL_CALVTH 0x33 /* PLL CAL VTH */
-#define B2055_PLL_LFC2 0x34 /* PLL LF C2 */
-#define B2055_PLL_REF 0x35 /* PLL reference */
-#define B2055_PLL_LFR1 0x36 /* PLL LF R1 */
-#define B2055_PLL_PFDCP 0x37 /* PLL PFD CP */
-#define B2055_PLL_IDAC_CPOPAMP 0x38 /* PLL IDAC CPOPAMP */
-#define B2055_PLL_CPREG 0x39 /* PLL CP Regulator */
-#define B2055_PLL_RCAL 0x3A /* PLL RCAL */
-#define B2055_RF_PLLMOD0 0x3B /* RF PLL MOD0 */
-#define B2055_RF_PLLMOD1 0x3C /* RF PLL MOD1 */
-#define B2055_RF_MMDIDAC1 0x3D /* RF MMD IDAC 1 */
-#define B2055_RF_MMDIDAC0 0x3E /* RF MMD IDAC 0 */
-#define B2055_RF_MMDSP 0x3F /* RF MMD spare */
-#define B2055_VCO_CAL1 0x40 /* VCO cal 1 */
-#define B2055_VCO_CAL2 0x41 /* VCO cal 2 */
-#define B2055_VCO_CAL3 0x42 /* VCO cal 3 */
-#define B2055_VCO_CAL4 0x43 /* VCO cal 4 */
-#define B2055_VCO_CAL5 0x44 /* VCO cal 5 */
-#define B2055_VCO_CAL6 0x45 /* VCO cal 6 */
-#define B2055_VCO_CAL7 0x46 /* VCO cal 7 */
-#define B2055_VCO_CAL8 0x47 /* VCO cal 8 */
-#define B2055_VCO_CAL9 0x48 /* VCO cal 9 */
-#define B2055_VCO_CAL10 0x49 /* VCO cal 10 */
-#define B2055_VCO_CAL11 0x4A /* VCO cal 11 */
-#define B2055_VCO_CAL12 0x4B /* VCO cal 12 */
-#define B2055_VCO_CAL13 0x4C /* VCO cal 13 */
-#define B2055_VCO_CAL14 0x4D /* VCO cal 14 */
-#define B2055_VCO_CAL15 0x4E /* VCO cal 15 */
-#define B2055_VCO_CAL16 0x4F /* VCO cal 16 */
-#define B2055_VCO_KVCO 0x50 /* VCO KVCO */
-#define B2055_VCO_CAPTAIL 0x51 /* VCO CAP TAIL */
-#define B2055_VCO_IDACVCO 0x52 /* VCO IDAC VCO */
-#define B2055_VCO_REG 0x53 /* VCO Regulator */
-#define B2055_PLL_RFVTH 0x54 /* PLL RF VTH */
-#define B2055_LGBUF_CENBUF 0x55 /* LGBUF CEN BUF */
-#define B2055_LGEN_TUNE1 0x56 /* LGEN tune 1 */
-#define B2055_LGEN_TUNE2 0x57 /* LGEN tune 2 */
-#define B2055_LGEN_IDAC1 0x58 /* LGEN IDAC 1 */
-#define B2055_LGEN_IDAC2 0x59 /* LGEN IDAC 2 */
-#define B2055_LGEN_BIASC 0x5A /* LGEN BIAS counter */
-#define B2055_LGEN_BIASIDAC 0x5B /* LGEN BIAS IDAC */
-#define B2055_LGEN_RCAL 0x5C /* LGEN RCAL */
-#define B2055_LGEN_DIV 0x5D /* LGEN div */
-#define B2055_LGEN_SPARE2 0x5E /* LGEN spare 2 */
-#define B2055_C1_LGBUF_ATUNE 0x5F /* Core 1 LGBUF A tune */
-#define B2055_C1_LGBUF_GTUNE 0x60 /* Core 1 LGBUF G tune */
-#define B2055_C1_LGBUF_DIV 0x61 /* Core 1 LGBUF div */
-#define B2055_C1_LGBUF_AIDAC 0x62 /* Core 1 LGBUF A IDAC */
-#define B2055_C1_LGBUF_GIDAC 0x63 /* Core 1 LGBUF G IDAC */
-#define B2055_C1_LGBUF_IDACFO 0x64 /* Core 1 LGBUF IDAC filter override */
-#define B2055_C1_LGBUF_SPARE 0x65 /* Core 1 LGBUF spare */
-#define B2055_C1_RX_RFSPC1 0x66 /* Core 1 RX RF SPC1 */
-#define B2055_C1_RX_RFR1 0x67 /* Core 1 RX RF reg 1 */
-#define B2055_C1_RX_RFR2 0x68 /* Core 1 RX RF reg 2 */
-#define B2055_C1_RX_RFRCAL 0x69 /* Core 1 RX RF RCAL */
-#define B2055_C1_RX_BB_BLCMP 0x6A /* Core 1 RX Baseband BUFI LPF CMP */
-#define B2055_C1_RX_BB_LPF 0x6B /* Core 1 RX Baseband LPF */
-#define B2055_C1_RX_BB_MIDACHP 0x6C /* Core 1 RX Baseband MIDAC High-pass */
-#define B2055_C1_RX_BB_VGA1IDAC 0x6D /* Core 1 RX Baseband VGA1 IDAC */
-#define B2055_C1_RX_BB_VGA2IDAC 0x6E /* Core 1 RX Baseband VGA2 IDAC */
-#define B2055_C1_RX_BB_VGA3IDAC 0x6F /* Core 1 RX Baseband VGA3 IDAC */
-#define B2055_C1_RX_BB_BUFOCTL 0x70 /* Core 1 RX Baseband BUFO Control */
-#define B2055_C1_RX_BB_RCCALCTL 0x71 /* Core 1 RX Baseband RCCAL Control */
-#define B2055_C1_RX_BB_RSSICTL1 0x72 /* Core 1 RX Baseband RSSI Control 1 */
-#define B2055_C1_RX_BB_RSSICTL2 0x73 /* Core 1 RX Baseband RSSI Control 2 */
-#define B2055_C1_RX_BB_RSSICTL3 0x74 /* Core 1 RX Baseband RSSI Control 3 */
-#define B2055_C1_RX_BB_RSSICTL4 0x75 /* Core 1 RX Baseband RSSI Control 4 */
-#define B2055_C1_RX_BB_RSSICTL5 0x76 /* Core 1 RX Baseband RSSI Control 5 */
-#define B2055_C1_RX_BB_REG 0x77 /* Core 1 RX Baseband Regulator */
-#define B2055_C1_RX_BB_SPARE1 0x78 /* Core 1 RX Baseband spare 1 */
-#define B2055_C1_RX_TXBBRCAL 0x79 /* Core 1 RX TX BB RCAL */
-#define B2055_C1_TX_RF_SPGA 0x7A /* Core 1 TX RF SGM PGA */
-#define B2055_C1_TX_RF_SPAD 0x7B /* Core 1 TX RF SGM PAD */
-#define B2055_C1_TX_RF_CNTPGA1 0x7C /* Core 1 TX RF counter PGA 1 */
-#define B2055_C1_TX_RF_CNTPAD1 0x7D /* Core 1 TX RF counter PAD 1 */
-#define B2055_C1_TX_RF_PGAIDAC 0x7E /* Core 1 TX RF PGA IDAC */
-#define B2055_C1_TX_PGAPADTN 0x7F /* Core 1 TX PGA PAD TN */
-#define B2055_C1_TX_PADIDAC1 0x80 /* Core 1 TX PAD IDAC 1 */
-#define B2055_C1_TX_PADIDAC2 0x81 /* Core 1 TX PAD IDAC 2 */
-#define B2055_C1_TX_MXBGTRIM 0x82 /* Core 1 TX MX B/G TRIM */
-#define B2055_C1_TX_RF_RCAL 0x83 /* Core 1 TX RF RCAL */
-#define B2055_C1_TX_RF_PADTSSI1 0x84 /* Core 1 TX RF PAD TSSI1 */
-#define B2055_C1_TX_RF_PADTSSI2 0x85 /* Core 1 TX RF PAD TSSI2 */
-#define B2055_C1_TX_RF_SPARE 0x86 /* Core 1 TX RF spare */
-#define B2055_C1_TX_RF_IQCAL1 0x87 /* Core 1 TX RF I/Q CAL 1 */
-#define B2055_C1_TX_RF_IQCAL2 0x88 /* Core 1 TX RF I/Q CAL 2 */
-#define B2055_C1_TXBB_RCCAL 0x89 /* Core 1 TXBB RC CAL Control */
-#define B2055_C1_TXBB_LPF1 0x8A /* Core 1 TXBB LPF 1 */
-#define B2055_C1_TX_VOSCNCL 0x8B /* Core 1 TX VOS CNCL */
-#define B2055_C1_TX_LPF_MXGMIDAC 0x8C /* Core 1 TX LPF MXGM IDAC */
-#define B2055_C1_TX_BB_MXGM 0x8D /* Core 1 TX BB MXGM */
-#define B2055_C2_LGBUF_ATUNE 0x8E /* Core 2 LGBUF A tune */
-#define B2055_C2_LGBUF_GTUNE 0x8F /* Core 2 LGBUF G tune */
-#define B2055_C2_LGBUF_DIV 0x90 /* Core 2 LGBUF div */
-#define B2055_C2_LGBUF_AIDAC 0x91 /* Core 2 LGBUF A IDAC */
-#define B2055_C2_LGBUF_GIDAC 0x92 /* Core 2 LGBUF G IDAC */
-#define B2055_C2_LGBUF_IDACFO 0x93 /* Core 2 LGBUF IDAC filter override */
-#define B2055_C2_LGBUF_SPARE 0x94 /* Core 2 LGBUF spare */
-#define B2055_C2_RX_RFSPC1 0x95 /* Core 2 RX RF SPC1 */
-#define B2055_C2_RX_RFR1 0x96 /* Core 2 RX RF reg 1 */
-#define B2055_C2_RX_RFR2 0x97 /* Core 2 RX RF reg 2 */
-#define B2055_C2_RX_RFRCAL 0x98 /* Core 2 RX RF RCAL */
-#define B2055_C2_RX_BB_BLCMP 0x99 /* Core 2 RX Baseband BUFI LPF CMP */
-#define B2055_C2_RX_BB_LPF 0x9A /* Core 2 RX Baseband LPF */
-#define B2055_C2_RX_BB_MIDACHP 0x9B /* Core 2 RX Baseband MIDAC High-pass */
-#define B2055_C2_RX_BB_VGA1IDAC 0x9C /* Core 2 RX Baseband VGA1 IDAC */
-#define B2055_C2_RX_BB_VGA2IDAC 0x9D /* Core 2 RX Baseband VGA2 IDAC */
-#define B2055_C2_RX_BB_VGA3IDAC 0x9E /* Core 2 RX Baseband VGA3 IDAC */
-#define B2055_C2_RX_BB_BUFOCTL 0x9F /* Core 2 RX Baseband BUFO Control */
-#define B2055_C2_RX_BB_RCCALCTL 0xA0 /* Core 2 RX Baseband RCCAL Control */
-#define B2055_C2_RX_BB_RSSICTL1 0xA1 /* Core 2 RX Baseband RSSI Control 1 */
-#define B2055_C2_RX_BB_RSSICTL2 0xA2 /* Core 2 RX Baseband RSSI Control 2 */
-#define B2055_C2_RX_BB_RSSICTL3 0xA3 /* Core 2 RX Baseband RSSI Control 3 */
-#define B2055_C2_RX_BB_RSSICTL4 0xA4 /* Core 2 RX Baseband RSSI Control 4 */
-#define B2055_C2_RX_BB_RSSICTL5 0xA5 /* Core 2 RX Baseband RSSI Control 5 */
-#define B2055_C2_RX_BB_REG 0xA6 /* Core 2 RX Baseband Regulator */
-#define B2055_C2_RX_BB_SPARE1 0xA7 /* Core 2 RX Baseband spare 1 */
-#define B2055_C2_RX_TXBBRCAL 0xA8 /* Core 2 RX TX BB RCAL */
-#define B2055_C2_TX_RF_SPGA 0xA9 /* Core 2 TX RF SGM PGA */
-#define B2055_C2_TX_RF_SPAD 0xAA /* Core 2 TX RF SGM PAD */
-#define B2055_C2_TX_RF_CNTPGA1 0xAB /* Core 2 TX RF counter PGA 1 */
-#define B2055_C2_TX_RF_CNTPAD1 0xAC /* Core 2 TX RF counter PAD 1 */
-#define B2055_C2_TX_RF_PGAIDAC 0xAD /* Core 2 TX RF PGA IDAC */
-#define B2055_C2_TX_PGAPADTN 0xAE /* Core 2 TX PGA PAD TN */
-#define B2055_C2_TX_PADIDAC1 0xAF /* Core 2 TX PAD IDAC 1 */
-#define B2055_C2_TX_PADIDAC2 0xB0 /* Core 2 TX PAD IDAC 2 */
-#define B2055_C2_TX_MXBGTRIM 0xB1 /* Core 2 TX MX B/G TRIM */
-#define B2055_C2_TX_RF_RCAL 0xB2 /* Core 2 TX RF RCAL */
-#define B2055_C2_TX_RF_PADTSSI1 0xB3 /* Core 2 TX RF PAD TSSI1 */
-#define B2055_C2_TX_RF_PADTSSI2 0xB4 /* Core 2 TX RF PAD TSSI2 */
-#define B2055_C2_TX_RF_SPARE 0xB5 /* Core 2 TX RF spare */
-#define B2055_C2_TX_RF_IQCAL1 0xB6 /* Core 2 TX RF I/Q CAL 1 */
-#define B2055_C2_TX_RF_IQCAL2 0xB7 /* Core 2 TX RF I/Q CAL 2 */
-#define B2055_C2_TXBB_RCCAL 0xB8 /* Core 2 TXBB RC CAL Control */
-#define B2055_C2_TXBB_LPF1 0xB9 /* Core 2 TXBB LPF 1 */
-#define B2055_C2_TX_VOSCNCL 0xBA /* Core 2 TX VOS CNCL */
-#define B2055_C2_TX_LPF_MXGMIDAC 0xBB /* Core 2 TX LPF MXGM IDAC */
-#define B2055_C2_TX_BB_MXGM 0xBC /* Core 2 TX BB MXGM */
-#define B2055_PRG_GCHP21 0xBD /* PRG GC HPVGA23 21 */
-#define B2055_PRG_GCHP22 0xBE /* PRG GC HPVGA23 22 */
-#define B2055_PRG_GCHP23 0xBF /* PRG GC HPVGA23 23 */
-#define B2055_PRG_GCHP24 0xC0 /* PRG GC HPVGA23 24 */
-#define B2055_PRG_GCHP25 0xC1 /* PRG GC HPVGA23 25 */
-#define B2055_PRG_GCHP26 0xC2 /* PRG GC HPVGA23 26 */
-#define B2055_PRG_GCHP27 0xC3 /* PRG GC HPVGA23 27 */
-#define B2055_PRG_GCHP28 0xC4 /* PRG GC HPVGA23 28 */
-#define B2055_PRG_GCHP29 0xC5 /* PRG GC HPVGA23 29 */
-#define B2055_PRG_GCHP30 0xC6 /* PRG GC HPVGA23 30 */
-#define B2055_C1_LNA_GAINBST 0xCD /* Core 1 LNA GAINBST */
-#define B2055_C1_B0NB_RSSIVCM 0xD2 /* Core 1 B0 narrow-band RSSI VCM */
-#define B2055_C1_GENSPARE2 0xD6 /* Core 1 GEN spare 2 */
-#define B2055_C2_LNA_GAINBST 0xD9 /* Core 2 LNA GAINBST */
-#define B2055_C2_B0NB_RSSIVCM 0xDE /* Core 2 B0 narrow-band RSSI VCM */
-#define B2055_C2_GENSPARE2 0xE2 /* Core 2 GEN spare 2 */
-
-
-
struct b43_wldev;
struct b43_chanspec {
- u8 channel;
- u8 sideband;
- u8 b_width;
- u8 b_freq;
+ u16 center_freq;
+ enum nl80211_channel_type channel_type;
};
struct b43_phy_n_iq_comp {
@@ -984,8 +772,6 @@ struct b43_phy_n {
u16 papd_epsilon_offset[2];
s32 preamble_override;
u32 bb_mult_save;
- u8 b_width;
- struct b43_chanspec radio_chanspec;
bool gain_boost;
bool elna_gain_config;
diff --git a/drivers/net/wireless/b43/radio_2055.c b/drivers/net/wireless/b43/radio_2055.c
new file mode 100644
index 000000000000..1b5316586cbf
--- /dev/null
+++ b/drivers/net/wireless/b43/radio_2055.c
@@ -0,0 +1,1332 @@
+/*
+
+ Broadcom B43 wireless driver
+ IEEE 802.11n PHY and radio device data tables
+
+ Copyright (c) 2008 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This 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.
+
+*/
+
+#include "b43.h"
+#include "radio_2055.h"
+#include "phy_common.h"
+
+struct b2055_inittab_entry {
+ /* Value to write if we use the 5GHz band. */
+ u16 ghz5;
+ /* Value to write if we use the 2.4GHz band. */
+ u16 ghz2;
+ /* Flags */
+ u8 flags;
+#define B2055_INITTAB_ENTRY_OK 0x01
+#define B2055_INITTAB_UPLOAD 0x02
+};
+#define UPLOAD .flags = B2055_INITTAB_ENTRY_OK | B2055_INITTAB_UPLOAD
+#define NOUPLOAD .flags = B2055_INITTAB_ENTRY_OK
+
+static const struct b2055_inittab_entry b2055_inittab [] = {
+ [B2055_SP_PINPD] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, },
+ [B2055_C1_SP_RSSI] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C1_SP_PDMISC] = { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, },
+ [B2055_C2_SP_RSSI] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C2_SP_PDMISC] = { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, },
+ [B2055_C1_SP_RXGC1] = { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, },
+ [B2055_C1_SP_RXGC2] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+ [B2055_C2_SP_RXGC1] = { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, },
+ [B2055_C2_SP_RXGC2] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+ [B2055_C1_SP_LPFBWSEL] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2055_C2_SP_LPFBWSEL] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2055_C1_SP_TXGC1] = { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, },
+ [B2055_C1_SP_TXGC2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, },
+ [B2055_C2_SP_TXGC1] = { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, },
+ [B2055_C2_SP_TXGC2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, },
+ [B2055_MASTER1] = { .ghz5 = 0x00D0, .ghz2 = 0x00D0, NOUPLOAD, },
+ [B2055_MASTER2] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2055_PD_LGEN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_PD_PLLTS] = { .ghz5 = 0x0040, .ghz2 = 0x0040, NOUPLOAD, },
+ [B2055_C1_PD_LGBUF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C1_PD_TX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C1_PD_RXTX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C1_PD_RSSIMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C2_PD_LGBUF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C2_PD_TX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C2_PD_RXTX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C2_PD_RSSIMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_PWRDET_LGEN] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, },
+ [B2055_C1_PWRDET_LGBUF] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+ [B2055_C1_PWRDET_RXTX] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, },
+ [B2055_C2_PWRDET_LGBUF] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+ [B2055_C2_PWRDET_RXTX] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, },
+ [B2055_RRCCAL_CS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_RRCCAL_NOPTSEL] = { .ghz5 = 0x002C, .ghz2 = 0x002C, NOUPLOAD, },
+ [B2055_CAL_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_CAL_COUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_CAL_COUT2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_CAL_CVARCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_CAL_RVARCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_CAL_LPOCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_CAL_TS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_CAL_RCCALRTS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_CAL_RCALRTS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_PADDRV] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, },
+ [B2055_XOCTL1] = { .ghz5 = 0x0038, .ghz2 = 0x0038, NOUPLOAD, },
+ [B2055_XOCTL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_XOREGUL] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, },
+ [B2055_XOMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_PLL_LFC1] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+ [B2055_PLL_CALVTH] = { .ghz5 = 0x0087, .ghz2 = 0x0087, NOUPLOAD, },
+ [B2055_PLL_LFC2] = { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, },
+ [B2055_PLL_REF] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+ [B2055_PLL_LFR1] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+ [B2055_PLL_PFDCP] = { .ghz5 = 0x0018, .ghz2 = 0x0018, UPLOAD, },
+ [B2055_PLL_IDAC_CPOPAMP] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2055_PLL_CPREG] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, },
+ [B2055_PLL_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2055_RF_PLLMOD0] = { .ghz5 = 0x009E, .ghz2 = 0x009E, NOUPLOAD, },
+ [B2055_RF_PLLMOD1] = { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, },
+ [B2055_RF_MMDIDAC1] = { .ghz5 = 0x00C8, .ghz2 = 0x00C8, UPLOAD, },
+ [B2055_RF_MMDIDAC0] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2055_RF_MMDSP] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_VCO_CAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_VCO_CAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_VCO_CAL3] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+ [B2055_VCO_CAL4] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2055_VCO_CAL5] = { .ghz5 = 0x0096, .ghz2 = 0x0096, NOUPLOAD, },
+ [B2055_VCO_CAL6] = { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, },
+ [B2055_VCO_CAL7] = { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, },
+ [B2055_VCO_CAL8] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+ [B2055_VCO_CAL9] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+ [B2055_VCO_CAL10] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2055_VCO_CAL11] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2055_VCO_CAL12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_VCO_CAL13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_VCO_CAL14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_VCO_CAL15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_VCO_CAL16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_VCO_KVCO] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2055_VCO_CAPTAIL] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2055_VCO_IDACVCO] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2055_VCO_REG] = { .ghz5 = 0x0084, .ghz2 = 0x0084, UPLOAD, },
+ [B2055_PLL_RFVTH] = { .ghz5 = 0x00C3, .ghz2 = 0x00C3, NOUPLOAD, },
+ [B2055_LGBUF_CENBUF] = { .ghz5 = 0x008F, .ghz2 = 0x008F, NOUPLOAD, },
+ [B2055_LGEN_TUNE1] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+ [B2055_LGEN_TUNE2] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+ [B2055_LGEN_IDAC1] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2055_LGEN_IDAC2] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2055_LGEN_BIASC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_LGEN_BIASIDAC] = { .ghz5 = 0x00CC, .ghz2 = 0x00CC, NOUPLOAD, },
+ [B2055_LGEN_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2055_LGEN_DIV] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, },
+ [B2055_LGEN_SPARE2] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, },
+ [B2055_C1_LGBUF_ATUNE] = { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, },
+ [B2055_C1_LGBUF_GTUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2055_C1_LGBUF_DIV] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2055_C1_LGBUF_AIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, },
+ [B2055_C1_LGBUF_GIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2055_C1_LGBUF_IDACFO] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C1_LGBUF_SPARE] = { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, },
+ [B2055_C1_RX_RFSPC1] = { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, },
+ [B2055_C1_RX_RFR1] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2055_C1_RX_RFR2] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
+ [B2055_C1_RX_RFRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2055_C1_RX_BB_BLCMP] = { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, },
+ [B2055_C1_RX_BB_LPF] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+ [B2055_C1_RX_BB_MIDACHP] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+ [B2055_C1_RX_BB_VGA1IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+ [B2055_C1_RX_BB_VGA2IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+ [B2055_C1_RX_BB_VGA3IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+ [B2055_C1_RX_BB_BUFOCTL] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+ [B2055_C1_RX_BB_RCCALCTL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+ [B2055_C1_RX_BB_RSSICTL1] = { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, },
+ [B2055_C1_RX_BB_RSSICTL2] = { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, },
+ [B2055_C1_RX_BB_RSSICTL3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, },
+ [B2055_C1_RX_BB_RSSICTL4] = { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, },
+ [B2055_C1_RX_BB_RSSICTL5] = { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, },
+ [B2055_C1_RX_BB_REG] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+ [B2055_C1_RX_BB_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C1_RX_TXBBRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2055_C1_TX_RF_SPGA] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2055_C1_TX_RF_SPAD] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2055_C1_TX_RF_CNTPGA1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2055_C1_TX_RF_CNTPAD1] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2055_C1_TX_RF_PGAIDAC] = { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, },
+ [B2055_C1_TX_PGAPADTN] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2055_C1_TX_PADIDAC1] = { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, },
+ [B2055_C1_TX_PADIDAC2] = { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, },
+ [B2055_C1_TX_MXBGTRIM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2055_C1_TX_RF_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2055_C1_TX_RF_PADTSSI1] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+ [B2055_C1_TX_RF_PADTSSI2] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+ [B2055_C1_TX_RF_SPARE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+ [B2055_C1_TX_RF_IQCAL1] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+ [B2055_C1_TX_RF_IQCAL2] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, },
+ [B2055_C1_TXBB_RCCAL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+ [B2055_C1_TXBB_LPF1] = { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, },
+ [B2055_C1_TX_VOSCNCL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C1_TX_LPF_MXGMIDAC] = { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, },
+ [B2055_C1_TX_BB_MXGM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C2_LGBUF_ATUNE] = { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, },
+ [B2055_C2_LGBUF_GTUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2055_C2_LGBUF_DIV] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2055_C2_LGBUF_AIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, },
+ [B2055_C2_LGBUF_GIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2055_C2_LGBUF_IDACFO] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C2_LGBUF_SPARE] = { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, },
+ [B2055_C2_RX_RFSPC1] = { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, },
+ [B2055_C2_RX_RFR1] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2055_C2_RX_RFR2] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
+ [B2055_C2_RX_RFRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2055_C2_RX_BB_BLCMP] = { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, },
+ [B2055_C2_RX_BB_LPF] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+ [B2055_C2_RX_BB_MIDACHP] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+ [B2055_C2_RX_BB_VGA1IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+ [B2055_C2_RX_BB_VGA2IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+ [B2055_C2_RX_BB_VGA3IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+ [B2055_C2_RX_BB_BUFOCTL] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+ [B2055_C2_RX_BB_RCCALCTL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+ [B2055_C2_RX_BB_RSSICTL1] = { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, },
+ [B2055_C2_RX_BB_RSSICTL2] = { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, },
+ [B2055_C2_RX_BB_RSSICTL3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, },
+ [B2055_C2_RX_BB_RSSICTL4] = { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, },
+ [B2055_C2_RX_BB_RSSICTL5] = { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, },
+ [B2055_C2_RX_BB_REG] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+ [B2055_C2_RX_BB_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C2_RX_TXBBRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2055_C2_TX_RF_SPGA] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2055_C2_TX_RF_SPAD] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+ [B2055_C2_TX_RF_CNTPGA1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+ [B2055_C2_TX_RF_CNTPAD1] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+ [B2055_C2_TX_RF_PGAIDAC] = { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, },
+ [B2055_C2_TX_PGAPADTN] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+ [B2055_C2_TX_PADIDAC1] = { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, },
+ [B2055_C2_TX_PADIDAC2] = { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, },
+ [B2055_C2_TX_MXBGTRIM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [B2055_C2_TX_RF_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+ [B2055_C2_TX_RF_PADTSSI1] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+ [B2055_C2_TX_RF_PADTSSI2] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+ [B2055_C2_TX_RF_SPARE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+ [B2055_C2_TX_RF_IQCAL1] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+ [B2055_C2_TX_RF_IQCAL2] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, },
+ [B2055_C2_TXBB_RCCAL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+ [B2055_C2_TXBB_LPF1] = { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, },
+ [B2055_C2_TX_VOSCNCL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C2_TX_LPF_MXGMIDAC] = { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, },
+ [B2055_C2_TX_BB_MXGM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_PRG_GCHP21] = { .ghz5 = 0x0071, .ghz2 = 0x0071, NOUPLOAD, },
+ [B2055_PRG_GCHP22] = { .ghz5 = 0x0072, .ghz2 = 0x0072, NOUPLOAD, },
+ [B2055_PRG_GCHP23] = { .ghz5 = 0x0073, .ghz2 = 0x0073, NOUPLOAD, },
+ [B2055_PRG_GCHP24] = { .ghz5 = 0x0074, .ghz2 = 0x0074, NOUPLOAD, },
+ [B2055_PRG_GCHP25] = { .ghz5 = 0x0075, .ghz2 = 0x0075, NOUPLOAD, },
+ [B2055_PRG_GCHP26] = { .ghz5 = 0x0076, .ghz2 = 0x0076, NOUPLOAD, },
+ [B2055_PRG_GCHP27] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+ [B2055_PRG_GCHP28] = { .ghz5 = 0x0078, .ghz2 = 0x0078, NOUPLOAD, },
+ [B2055_PRG_GCHP29] = { .ghz5 = 0x0079, .ghz2 = 0x0079, NOUPLOAD, },
+ [B2055_PRG_GCHP30] = { .ghz5 = 0x007A, .ghz2 = 0x007A, NOUPLOAD, },
+ [0xC7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xC8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xC9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xCA] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xCB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xCC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C1_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xCE] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xCF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xD0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xD1] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+ [B2055_C1_B0NB_RSSIVCM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [0xD3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xD4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xD5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C1_GENSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xD7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xD8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C2_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xDA] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xDB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xDC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xDD] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+ [B2055_C2_B0NB_RSSIVCM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+ [0xDF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xE0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [0xE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+ [B2055_C2_GENSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+#define RADIOREGS(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, \
+ r12, r13, r14, r15, r16, r17, r18, r19, r20, r21) \
+ .radio_pll_ref = r0, \
+ .radio_rf_pllmod0 = r1, \
+ .radio_rf_pllmod1 = r2, \
+ .radio_vco_captail = r3, \
+ .radio_vco_cal1 = r4, \
+ .radio_vco_cal2 = r5, \
+ .radio_pll_lfc1 = r6, \
+ .radio_pll_lfr1 = r7, \
+ .radio_pll_lfc2 = r8, \
+ .radio_lgbuf_cenbuf = r9, \
+ .radio_lgen_tune1 = r10, \
+ .radio_lgen_tune2 = r11, \
+ .radio_c1_lgbuf_atune = r12, \
+ .radio_c1_lgbuf_gtune = r13, \
+ .radio_c1_rx_rfr1 = r14, \
+ .radio_c1_tx_pgapadtn = r15, \
+ .radio_c1_tx_mxbgtrim = r16, \
+ .radio_c2_lgbuf_atune = r17, \
+ .radio_c2_lgbuf_gtune = r18, \
+ .radio_c2_rx_rfr1 = r19, \
+ .radio_c2_tx_pgapadtn = r20, \
+ .radio_c2_tx_mxbgtrim = r21
+
+#define PHYREGS(r0, r1, r2, r3, r4, r5) \
+ .phy_regs.phy_bw1a = r0, \
+ .phy_regs.phy_bw2 = r1, \
+ .phy_regs.phy_bw3 = r2, \
+ .phy_regs.phy_bw4 = r3, \
+ .phy_regs.phy_bw5 = r4, \
+ .phy_regs.phy_bw6 = r5
+
+static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] = {
+ { .channel = 184,
+ .freq = 4920, /* MHz */
+ .unk2 = 3280,
+ RADIOREGS(0x71, 0x01, 0xEC, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F,
+ 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+ PHYREGS(0xB407, 0xB007, 0xAC07, 0x1402, 0x1502, 0x1602),
+ },
+ { .channel = 186,
+ .freq = 4930, /* MHz */
+ .unk2 = 3287,
+ RADIOREGS(0x71, 0x01, 0xED, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F,
+ 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+ PHYREGS(0xB807, 0xB407, 0xB007, 0x1302, 0x1402, 0x1502),
+ },
+ { .channel = 188,
+ .freq = 4940, /* MHz */
+ .unk2 = 3293,
+ RADIOREGS(0x71, 0x01, 0xEE, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+ 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+ PHYREGS(0xBC07, 0xB807, 0xB407, 0x1202, 0x1302, 0x1402),
+ },
+ { .channel = 190,
+ .freq = 4950, /* MHz */
+ .unk2 = 3300,
+ RADIOREGS(0x71, 0x01, 0xEF, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+ 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+ PHYREGS(0xC007, 0xBC07, 0xB807, 0x1102, 0x1202, 0x1302),
+ },
+ { .channel = 192,
+ .freq = 4960, /* MHz */
+ .unk2 = 3307,
+ RADIOREGS(0x71, 0x01, 0xF0, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+ 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+ PHYREGS(0xC407, 0xC007, 0xBC07, 0x0F02, 0x1102, 0x1202),
+ },
+ { .channel = 194,
+ .freq = 4970, /* MHz */
+ .unk2 = 3313,
+ RADIOREGS(0x71, 0x01, 0xF1, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+ 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+ PHYREGS(0xC807, 0xC407, 0xC007, 0x0E02, 0x0F02, 0x1102),
+ },
+ { .channel = 196,
+ .freq = 4980, /* MHz */
+ .unk2 = 3320,
+ RADIOREGS(0x71, 0x01, 0xF2, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+ 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+ PHYREGS(0xCC07, 0xC807, 0xC407, 0x0D02, 0x0E02, 0x0F02),
+ },
+ { .channel = 198,
+ .freq = 4990, /* MHz */
+ .unk2 = 3327,
+ RADIOREGS(0x71, 0x01, 0xF3, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+ 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+ PHYREGS(0xD007, 0xCC07, 0xC807, 0x0C02, 0x0D02, 0x0E02),
+ },
+ { .channel = 200,
+ .freq = 5000, /* MHz */
+ .unk2 = 3333,
+ RADIOREGS(0x71, 0x01, 0xF4, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+ 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+ PHYREGS(0xD407, 0xD007, 0xCC07, 0x0B02, 0x0C02, 0x0D02),
+ },
+ { .channel = 202,
+ .freq = 5010, /* MHz */
+ .unk2 = 3340,
+ RADIOREGS(0x71, 0x01, 0xF5, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+ 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+ PHYREGS(0xD807, 0xD407, 0xD007, 0x0A02, 0x0B02, 0x0C02),
+ },
+ { .channel = 204,
+ .freq = 5020, /* MHz */
+ .unk2 = 3347,
+ RADIOREGS(0x71, 0x01, 0xF6, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+ 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+ PHYREGS(0xDC07, 0xD807, 0xD407, 0x0902, 0x0A02, 0x0B02),
+ },
+ { .channel = 206,
+ .freq = 5030, /* MHz */
+ .unk2 = 3353,
+ RADIOREGS(0x71, 0x01, 0xF7, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+ 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+ PHYREGS(0xE007, 0xDC07, 0xD807, 0x0802, 0x0902, 0x0A02),
+ },
+ { .channel = 208,
+ .freq = 5040, /* MHz */
+ .unk2 = 3360,
+ RADIOREGS(0x71, 0x01, 0xF8, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+ 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+ PHYREGS(0xE407, 0xE007, 0xDC07, 0x0702, 0x0802, 0x0902),
+ },
+ { .channel = 210,
+ .freq = 5050, /* MHz */
+ .unk2 = 3367,
+ RADIOREGS(0x71, 0x01, 0xF9, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+ 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+ PHYREGS(0xE807, 0xE407, 0xE007, 0x0602, 0x0702, 0x0802),
+ },
+ { .channel = 212,
+ .freq = 5060, /* MHz */
+ .unk2 = 3373,
+ RADIOREGS(0x71, 0x01, 0xFA, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F,
+ 0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E),
+ PHYREGS(0xEC07, 0xE807, 0xE407, 0x0502, 0x0602, 0x0702),
+ },
+ { .channel = 214,
+ .freq = 5070, /* MHz */
+ .unk2 = 3380,
+ RADIOREGS(0x71, 0x01, 0xFB, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F,
+ 0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E),
+ PHYREGS(0xF007, 0xEC07, 0xE807, 0x0402, 0x0502, 0x0602),
+ },
+ { .channel = 216,
+ .freq = 5080, /* MHz */
+ .unk2 = 3387,
+ RADIOREGS(0x71, 0x01, 0xFC, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
+ 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F,
+ 0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D),
+ PHYREGS(0xF407, 0xF007, 0xEC07, 0x0302, 0x0402, 0x0502),
+ },
+ { .channel = 218,
+ .freq = 5090, /* MHz */
+ .unk2 = 3393,
+ RADIOREGS(0x71, 0x01, 0xFD, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
+ 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F,
+ 0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D),
+ PHYREGS(0xF807, 0xF407, 0xF007, 0x0202, 0x0302, 0x0402),
+ },
+ { .channel = 220,
+ .freq = 5100, /* MHz */
+ .unk2 = 3400,
+ RADIOREGS(0x71, 0x01, 0xFE, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
+ 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F,
+ 0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D),
+ PHYREGS(0xFC07, 0xF807, 0xF407, 0x0102, 0x0202, 0x0302),
+ },
+ { .channel = 222,
+ .freq = 5110, /* MHz */
+ .unk2 = 3407,
+ RADIOREGS(0x71, 0x01, 0xFF, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
+ 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F,
+ 0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D),
+ PHYREGS(0x0008, 0xFC07, 0xF807, 0x0002, 0x0102, 0x0202),
+ },
+ { .channel = 224,
+ .freq = 5120, /* MHz */
+ .unk2 = 3413,
+ RADIOREGS(0x71, 0x02, 0x00, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
+ 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F,
+ 0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C),
+ PHYREGS(0x0408, 0x0008, 0xFC07, 0xFF01, 0x0002, 0x0102),
+ },
+ { .channel = 226,
+ .freq = 5130, /* MHz */
+ .unk2 = 3420,
+ RADIOREGS(0x71, 0x02, 0x01, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
+ 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F,
+ 0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C),
+ PHYREGS(0x0808, 0x0408, 0x0008, 0xFE01, 0xFF01, 0x0002),
+ },
+ { .channel = 228,
+ .freq = 5140, /* MHz */
+ .unk2 = 3427,
+ RADIOREGS(0x71, 0x02, 0x02, 0x0C, 0xC6, 0x01, 0x04, 0x0A,
+ 0x00, 0x8D, 0x99, 0x99, 0xDD, 0x00, 0x0C, 0x0E,
+ 0x8B, 0xDD, 0x00, 0x0C, 0x0E, 0x8B),
+ PHYREGS(0x0C08, 0x0808, 0x0408, 0xFD01, 0xFE01, 0xFF01),
+ },
+ { .channel = 32,
+ .freq = 5160, /* MHz */
+ .unk2 = 3440,
+ RADIOREGS(0x71, 0x02, 0x04, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
+ 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D,
+ 0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A),
+ PHYREGS(0x1408, 0x1008, 0x0C08, 0xFB01, 0xFC01, 0xFD01),
+ },
+ { .channel = 34,
+ .freq = 5170, /* MHz */
+ .unk2 = 3447,
+ RADIOREGS(0x71, 0x02, 0x05, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
+ 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D,
+ 0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A),
+ PHYREGS(0x1808, 0x1408, 0x1008, 0xFA01, 0xFB01, 0xFC01),
+ },
+ { .channel = 36,
+ .freq = 5180, /* MHz */
+ .unk2 = 3453,
+ RADIOREGS(0x71, 0x02, 0x06, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
+ 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C,
+ 0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89),
+ PHYREGS(0x1C08, 0x1808, 0x1408, 0xF901, 0xFA01, 0xFB01),
+ },
+ { .channel = 38,
+ .freq = 5190, /* MHz */
+ .unk2 = 3460,
+ RADIOREGS(0x71, 0x02, 0x07, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
+ 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C,
+ 0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89),
+ PHYREGS(0x2008, 0x1C08, 0x1808, 0xF801, 0xF901, 0xFA01),
+ },
+ { .channel = 40,
+ .freq = 5200, /* MHz */
+ .unk2 = 3467,
+ RADIOREGS(0x71, 0x02, 0x08, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B,
+ 0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89),
+ PHYREGS(0x2408, 0x2008, 0x1C08, 0xF701, 0xF801, 0xF901),
+ },
+ { .channel = 42,
+ .freq = 5210, /* MHz */
+ .unk2 = 3473,
+ RADIOREGS(0x71, 0x02, 0x09, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B,
+ 0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89),
+ PHYREGS(0x2808, 0x2408, 0x2008, 0xF601, 0xF701, 0xF801),
+ },
+ { .channel = 44,
+ .freq = 5220, /* MHz */
+ .unk2 = 3480,
+ RADIOREGS(0x71, 0x02, 0x0A, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
+ 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A,
+ 0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88),
+ PHYREGS(0x2C08, 0x2808, 0x2408, 0xF501, 0xF601, 0xF701),
+ },
+ { .channel = 46,
+ .freq = 5230, /* MHz */
+ .unk2 = 3487,
+ RADIOREGS(0x71, 0x02, 0x0B, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
+ 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A,
+ 0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88),
+ PHYREGS(0x3008, 0x2C08, 0x2808, 0xF401, 0xF501, 0xF601),
+ },
+ { .channel = 48,
+ .freq = 5240, /* MHz */
+ .unk2 = 3493,
+ RADIOREGS(0x71, 0x02, 0x0C, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
+ 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A,
+ 0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87),
+ PHYREGS(0x3408, 0x3008, 0x2C08, 0xF301, 0xF401, 0xF501),
+ },
+ { .channel = 50,
+ .freq = 5250, /* MHz */
+ .unk2 = 3500,
+ RADIOREGS(0x71, 0x02, 0x0D, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
+ 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A,
+ 0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87),
+ PHYREGS(0x3808, 0x3408, 0x3008, 0xF201, 0xF301, 0xF401),
+ },
+ { .channel = 52,
+ .freq = 5260, /* MHz */
+ .unk2 = 3507,
+ RADIOREGS(0x71, 0x02, 0x0E, 0x0A, 0x98, 0x01, 0x04, 0x0A,
+ 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09,
+ 0x87, 0xAA, 0x00, 0x08, 0x09, 0x87),
+ PHYREGS(0x3C08, 0x3808, 0x3408, 0xF101, 0xF201, 0xF301),
+ },
+ { .channel = 54,
+ .freq = 5270, /* MHz */
+ .unk2 = 3513,
+ RADIOREGS(0x71, 0x02, 0x0F, 0x0A, 0x98, 0x01, 0x04, 0x0A,
+ 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09,
+ 0x87, 0xAA, 0x00, 0x08, 0x09, 0x87),
+ PHYREGS(0x4008, 0x3C08, 0x3808, 0xF001, 0xF101, 0xF201),
+ },
+ { .channel = 56,
+ .freq = 5280, /* MHz */
+ .unk2 = 3520,
+ RADIOREGS(0x71, 0x02, 0x10, 0x09, 0x91, 0x01, 0x04, 0x0A,
+ 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08,
+ 0x86, 0x99, 0x00, 0x08, 0x08, 0x86),
+ PHYREGS(0x4408, 0x4008, 0x3C08, 0xF001, 0xF001, 0xF101),
+ },
+ { .channel = 58,
+ .freq = 5290, /* MHz */
+ .unk2 = 3527,
+ RADIOREGS(0x71, 0x02, 0x11, 0x09, 0x91, 0x01, 0x04, 0x0A,
+ 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08,
+ 0x86, 0x99, 0x00, 0x08, 0x08, 0x86),
+ PHYREGS(0x4808, 0x4408, 0x4008, 0xEF01, 0xF001, 0xF001),
+ },
+ { .channel = 60,
+ .freq = 5300, /* MHz */
+ .unk2 = 3533,
+ RADIOREGS(0x71, 0x02, 0x12, 0x09, 0x8A, 0x01, 0x04, 0x0A,
+ 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07,
+ 0x85, 0x99, 0x00, 0x08, 0x07, 0x85),
+ PHYREGS(0x4C08, 0x4808, 0x4408, 0xEE01, 0xEF01, 0xF001),
+ },
+ { .channel = 62,
+ .freq = 5310, /* MHz */
+ .unk2 = 3540,
+ RADIOREGS(0x71, 0x02, 0x13, 0x09, 0x8A, 0x01, 0x04, 0x0A,
+ 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07,
+ 0x85, 0x99, 0x00, 0x08, 0x07, 0x85),
+ PHYREGS(0x5008, 0x4C08, 0x4808, 0xED01, 0xEE01, 0xEF01),
+ },
+ { .channel = 64,
+ .freq = 5320, /* MHz */
+ .unk2 = 3547,
+ RADIOREGS(0x71, 0x02, 0x14, 0x09, 0x83, 0x01, 0x04, 0x0A,
+ 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07,
+ 0x84, 0x88, 0x00, 0x07, 0x07, 0x84),
+ PHYREGS(0x5408, 0x5008, 0x4C08, 0xEC01, 0xED01, 0xEE01),
+ },
+ { .channel = 66,
+ .freq = 5330, /* MHz */
+ .unk2 = 3553,
+ RADIOREGS(0x71, 0x02, 0x15, 0x09, 0x83, 0x01, 0x04, 0x0A,
+ 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07,
+ 0x84, 0x88, 0x00, 0x07, 0x07, 0x84),
+ PHYREGS(0x5808, 0x5408, 0x5008, 0xEB01, 0xEC01, 0xED01),
+ },
+ { .channel = 68,
+ .freq = 5340, /* MHz */
+ .unk2 = 3560,
+ RADIOREGS(0x71, 0x02, 0x16, 0x08, 0x7C, 0x01, 0x04, 0x0A,
+ 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06,
+ 0x84, 0x88, 0x00, 0x07, 0x06, 0x84),
+ PHYREGS(0x5C08, 0x5808, 0x5408, 0xEA01, 0xEB01, 0xEC01),
+ },
+ { .channel = 70,
+ .freq = 5350, /* MHz */
+ .unk2 = 3567,
+ RADIOREGS(0x71, 0x02, 0x17, 0x08, 0x7C, 0x01, 0x04, 0x0A,
+ 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06,
+ 0x84, 0x88, 0x00, 0x07, 0x06, 0x84),
+ PHYREGS(0x6008, 0x5C08, 0x5808, 0xE901, 0xEA01, 0xEB01),
+ },
+ { .channel = 72,
+ .freq = 5360, /* MHz */
+ .unk2 = 3573,
+ RADIOREGS(0x71, 0x02, 0x18, 0x08, 0x75, 0x01, 0x04, 0x0A,
+ 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05,
+ 0x83, 0x77, 0x00, 0x06, 0x05, 0x83),
+ PHYREGS(0x6408, 0x6008, 0x5C08, 0xE801, 0xE901, 0xEA01),
+ },
+ { .channel = 74,
+ .freq = 5370, /* MHz */
+ .unk2 = 3580,
+ RADIOREGS(0x71, 0x02, 0x19, 0x08, 0x75, 0x01, 0x04, 0x0A,
+ 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05,
+ 0x83, 0x77, 0x00, 0x06, 0x05, 0x83),
+ PHYREGS(0x6808, 0x6408, 0x6008, 0xE701, 0xE801, 0xE901),
+ },
+ { .channel = 76,
+ .freq = 5380, /* MHz */
+ .unk2 = 3587,
+ RADIOREGS(0x71, 0x02, 0x1A, 0x08, 0x6E, 0x01, 0x04, 0x0A,
+ 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04,
+ 0x82, 0x77, 0x00, 0x06, 0x04, 0x82),
+ PHYREGS(0x6C08, 0x6808, 0x6408, 0xE601, 0xE701, 0xE801),
+ },
+ { .channel = 78,
+ .freq = 5390, /* MHz */
+ .unk2 = 3593,
+ RADIOREGS(0x71, 0x02, 0x1B, 0x08, 0x6E, 0x01, 0x04, 0x0A,
+ 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04,
+ 0x82, 0x77, 0x00, 0x06, 0x04, 0x82),
+ PHYREGS(0x7008, 0x6C08, 0x6808, 0xE501, 0xE601, 0xE701),
+ },
+ { .channel = 80,
+ .freq = 5400, /* MHz */
+ .unk2 = 3600,
+ RADIOREGS(0x71, 0x02, 0x1C, 0x07, 0x67, 0x01, 0x04, 0x0A,
+ 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04,
+ 0x81, 0x66, 0x00, 0x05, 0x04, 0x81),
+ PHYREGS(0x7408, 0x7008, 0x6C08, 0xE501, 0xE501, 0xE601),
+ },
+ { .channel = 82,
+ .freq = 5410, /* MHz */
+ .unk2 = 3607,
+ RADIOREGS(0x71, 0x02, 0x1D, 0x07, 0x67, 0x01, 0x04, 0x0A,
+ 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04,
+ 0x81, 0x66, 0x00, 0x05, 0x04, 0x81),
+ PHYREGS(0x7808, 0x7408, 0x7008, 0xE401, 0xE501, 0xE501),
+ },
+ { .channel = 84,
+ .freq = 5420, /* MHz */
+ .unk2 = 3613,
+ RADIOREGS(0x71, 0x02, 0x1E, 0x07, 0x61, 0x01, 0x04, 0x0A,
+ 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03,
+ 0x80, 0x66, 0x00, 0x05, 0x03, 0x80),
+ PHYREGS(0x7C08, 0x7808, 0x7408, 0xE301, 0xE401, 0xE501),
+ },
+ { .channel = 86,
+ .freq = 5430, /* MHz */
+ .unk2 = 3620,
+ RADIOREGS(0x71, 0x02, 0x1F, 0x07, 0x61, 0x01, 0x04, 0x0A,
+ 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03,
+ 0x80, 0x66, 0x00, 0x05, 0x03, 0x80),
+ PHYREGS(0x8008, 0x7C08, 0x7808, 0xE201, 0xE301, 0xE401),
+ },
+ { .channel = 88,
+ .freq = 5440, /* MHz */
+ .unk2 = 3627,
+ RADIOREGS(0x71, 0x02, 0x20, 0x07, 0x5A, 0x01, 0x04, 0x0A,
+ 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02,
+ 0x80, 0x55, 0x00, 0x04, 0x02, 0x80),
+ PHYREGS(0x8408, 0x8008, 0x7C08, 0xE101, 0xE201, 0xE301),
+ },
+ { .channel = 90,
+ .freq = 5450, /* MHz */
+ .unk2 = 3633,
+ RADIOREGS(0x71, 0x02, 0x21, 0x07, 0x5A, 0x01, 0x04, 0x0A,
+ 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02,
+ 0x80, 0x55, 0x00, 0x04, 0x02, 0x80),
+ PHYREGS(0x8808, 0x8408, 0x8008, 0xE001, 0xE101, 0xE201),
+ },
+ { .channel = 92,
+ .freq = 5460, /* MHz */
+ .unk2 = 3640,
+ RADIOREGS(0x71, 0x02, 0x22, 0x06, 0x53, 0x01, 0x04, 0x0A,
+ 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01,
+ 0x80, 0x55, 0x00, 0x04, 0x01, 0x80),
+ PHYREGS(0x8C08, 0x8808, 0x8408, 0xDF01, 0xE001, 0xE101),
+ },
+ { .channel = 94,
+ .freq = 5470, /* MHz */
+ .unk2 = 3647,
+ RADIOREGS(0x71, 0x02, 0x23, 0x06, 0x53, 0x01, 0x04, 0x0A,
+ 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01,
+ 0x80, 0x55, 0x00, 0x04, 0x01, 0x80),
+ PHYREGS(0x9008, 0x8C08, 0x8808, 0xDE01, 0xDF01, 0xE001),
+ },
+ { .channel = 96,
+ .freq = 5480, /* MHz */
+ .unk2 = 3653,
+ RADIOREGS(0x71, 0x02, 0x24, 0x06, 0x4D, 0x01, 0x04, 0x0A,
+ 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00,
+ 0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+ PHYREGS(0x9408, 0x9008, 0x8C08, 0xDD01, 0xDE01, 0xDF01),
+ },
+ { .channel = 98,
+ .freq = 5490, /* MHz */
+ .unk2 = 3660,
+ RADIOREGS(0x71, 0x02, 0x25, 0x06, 0x4D, 0x01, 0x04, 0x0A,
+ 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00,
+ 0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+ PHYREGS(0x9808, 0x9408, 0x9008, 0xDD01, 0xDD01, 0xDE01),
+ },
+ { .channel = 100,
+ .freq = 5500, /* MHz */
+ .unk2 = 3667,
+ RADIOREGS(0x71, 0x02, 0x26, 0x06, 0x47, 0x01, 0x04, 0x0A,
+ 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00,
+ 0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+ PHYREGS(0x9C08, 0x9808, 0x9408, 0xDC01, 0xDD01, 0xDD01),
+ },
+ { .channel = 102,
+ .freq = 5510, /* MHz */
+ .unk2 = 3673,
+ RADIOREGS(0x71, 0x02, 0x27, 0x06, 0x47, 0x01, 0x04, 0x0A,
+ 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00,
+ 0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+ PHYREGS(0xA008, 0x9C08, 0x9808, 0xDB01, 0xDC01, 0xDD01),
+ },
+ { .channel = 104,
+ .freq = 5520, /* MHz */
+ .unk2 = 3680,
+ RADIOREGS(0x71, 0x02, 0x28, 0x05, 0x40, 0x01, 0x04, 0x0A,
+ 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+ 0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+ PHYREGS(0xA408, 0xA008, 0x9C08, 0xDA01, 0xDB01, 0xDC01),
+ },
+ { .channel = 106,
+ .freq = 5530, /* MHz */
+ .unk2 = 3687,
+ RADIOREGS(0x71, 0x02, 0x29, 0x05, 0x40, 0x01, 0x04, 0x0A,
+ 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+ 0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+ PHYREGS(0xA808, 0xA408, 0xA008, 0xD901, 0xDA01, 0xDB01),
+ },
+ { .channel = 108,
+ .freq = 5540, /* MHz */
+ .unk2 = 3693,
+ RADIOREGS(0x71, 0x02, 0x2A, 0x05, 0x3A, 0x01, 0x04, 0x0A,
+ 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+ 0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+ PHYREGS(0xAC08, 0xA808, 0xA408, 0xD801, 0xD901, 0xDA01),
+ },
+ { .channel = 110,
+ .freq = 5550, /* MHz */
+ .unk2 = 3700,
+ RADIOREGS(0x71, 0x02, 0x2B, 0x05, 0x3A, 0x01, 0x04, 0x0A,
+ 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+ 0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+ PHYREGS(0xB008, 0xAC08, 0xA808, 0xD701, 0xD801, 0xD901),
+ },
+ { .channel = 112,
+ .freq = 5560, /* MHz */
+ .unk2 = 3707,
+ RADIOREGS(0x71, 0x02, 0x2C, 0x05, 0x34, 0x01, 0x04, 0x0A,
+ 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+ 0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+ PHYREGS(0xB408, 0xB008, 0xAC08, 0xD701, 0xD701, 0xD801),
+ },
+ { .channel = 114,
+ .freq = 5570, /* MHz */
+ .unk2 = 3713,
+ RADIOREGS(0x71, 0x02, 0x2D, 0x05, 0x34, 0x01, 0x04, 0x0A,
+ 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+ 0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+ PHYREGS(0xB808, 0xB408, 0xB008, 0xD601, 0xD701, 0xD701),
+ },
+ { .channel = 116,
+ .freq = 5580, /* MHz */
+ .unk2 = 3720,
+ RADIOREGS(0x71, 0x02, 0x2E, 0x04, 0x2E, 0x01, 0x04, 0x0A,
+ 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+ 0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+ PHYREGS(0xBC08, 0xB808, 0xB408, 0xD501, 0xD601, 0xD701),
+ },
+ { .channel = 118,
+ .freq = 5590, /* MHz */
+ .unk2 = 3727,
+ RADIOREGS(0x71, 0x02, 0x2F, 0x04, 0x2E, 0x01, 0x04, 0x0A,
+ 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+ 0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+ PHYREGS(0xC008, 0xBC08, 0xB808, 0xD401, 0xD501, 0xD601),
+ },
+ { .channel = 120,
+ .freq = 5600, /* MHz */
+ .unk2 = 3733,
+ RADIOREGS(0x71, 0x02, 0x30, 0x04, 0x28, 0x01, 0x04, 0x0A,
+ 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
+ 0x80, 0x11, 0x00, 0x01, 0x00, 0x80),
+ PHYREGS(0xC408, 0xC008, 0xBC08, 0xD301, 0xD401, 0xD501),
+ },
+ { .channel = 122,
+ .freq = 5610, /* MHz */
+ .unk2 = 3740,
+ RADIOREGS(0x71, 0x02, 0x31, 0x04, 0x28, 0x01, 0x04, 0x0A,
+ 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
+ 0x80, 0x11, 0x00, 0x01, 0x00, 0x80),
+ PHYREGS(0xC808, 0xC408, 0xC008, 0xD201, 0xD301, 0xD401),
+ },
+ { .channel = 124,
+ .freq = 5620, /* MHz */
+ .unk2 = 3747,
+ RADIOREGS(0x71, 0x02, 0x32, 0x04, 0x21, 0x01, 0x04, 0x0A,
+ 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x80, 0x11, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xCC08, 0xC808, 0xC408, 0xD201, 0xD201, 0xD301),
+ },
+ { .channel = 126,
+ .freq = 5630, /* MHz */
+ .unk2 = 3753,
+ RADIOREGS(0x71, 0x02, 0x33, 0x04, 0x21, 0x01, 0x04, 0x0A,
+ 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x80, 0x11, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xD008, 0xCC08, 0xC808, 0xD101, 0xD201, 0xD201),
+ },
+ { .channel = 128,
+ .freq = 5640, /* MHz */
+ .unk2 = 3760,
+ RADIOREGS(0x71, 0x02, 0x34, 0x03, 0x1C, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xD408, 0xD008, 0xCC08, 0xD001, 0xD101, 0xD201),
+ },
+ { .channel = 130,
+ .freq = 5650, /* MHz */
+ .unk2 = 3767,
+ RADIOREGS(0x71, 0x02, 0x35, 0x03, 0x1C, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xD808, 0xD408, 0xD008, 0xCF01, 0xD001, 0xD101),
+ },
+ { .channel = 132,
+ .freq = 5660, /* MHz */
+ .unk2 = 3773,
+ RADIOREGS(0x71, 0x02, 0x36, 0x03, 0x16, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xDC08, 0xD808, 0xD408, 0xCE01, 0xCF01, 0xD001),
+ },
+ { .channel = 134,
+ .freq = 5670, /* MHz */
+ .unk2 = 3780,
+ RADIOREGS(0x71, 0x02, 0x37, 0x03, 0x16, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xE008, 0xDC08, 0xD808, 0xCE01, 0xCE01, 0xCF01),
+ },
+ { .channel = 136,
+ .freq = 5680, /* MHz */
+ .unk2 = 3787,
+ RADIOREGS(0x71, 0x02, 0x38, 0x03, 0x10, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xE408, 0xE008, 0xDC08, 0xCD01, 0xCE01, 0xCE01),
+ },
+ { .channel = 138,
+ .freq = 5690, /* MHz */
+ .unk2 = 3793,
+ RADIOREGS(0x71, 0x02, 0x39, 0x03, 0x10, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xE808, 0xE408, 0xE008, 0xCC01, 0xCD01, 0xCE01),
+ },
+ { .channel = 140,
+ .freq = 5700, /* MHz */
+ .unk2 = 3800,
+ RADIOREGS(0x71, 0x02, 0x3A, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xEC08, 0xE808, 0xE408, 0xCB01, 0xCC01, 0xCD01),
+ },
+ { .channel = 142,
+ .freq = 5710, /* MHz */
+ .unk2 = 3807,
+ RADIOREGS(0x71, 0x02, 0x3B, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xF008, 0xEC08, 0xE808, 0xCA01, 0xCB01, 0xCC01),
+ },
+ { .channel = 144,
+ .freq = 5720, /* MHz */
+ .unk2 = 3813,
+ RADIOREGS(0x71, 0x02, 0x3C, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xF408, 0xF008, 0xEC08, 0xC901, 0xCA01, 0xCB01),
+ },
+ { .channel = 145,
+ .freq = 5725, /* MHz */
+ .unk2 = 3817,
+ RADIOREGS(0x72, 0x04, 0x79, 0x02, 0x03, 0x01, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xF608, 0xF208, 0xEE08, 0xC901, 0xCA01, 0xCB01),
+ },
+ { .channel = 146,
+ .freq = 5730, /* MHz */
+ .unk2 = 3820,
+ RADIOREGS(0x71, 0x02, 0x3D, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xF808, 0xF408, 0xF008, 0xC901, 0xC901, 0xCA01),
+ },
+ { .channel = 147,
+ .freq = 5735, /* MHz */
+ .unk2 = 3823,
+ RADIOREGS(0x72, 0x04, 0x7B, 0x02, 0x03, 0x01, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xFA08, 0xF608, 0xF208, 0xC801, 0xC901, 0xCA01),
+ },
+ { .channel = 148,
+ .freq = 5740, /* MHz */
+ .unk2 = 3827,
+ RADIOREGS(0x71, 0x02, 0x3E, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xFC08, 0xF808, 0xF408, 0xC801, 0xC901, 0xC901),
+ },
+ { .channel = 149,
+ .freq = 5745, /* MHz */
+ .unk2 = 3830,
+ RADIOREGS(0x72, 0x04, 0x7D, 0x02, 0xFE, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0xFE08, 0xFA08, 0xF608, 0xC801, 0xC801, 0xC901),
+ },
+ { .channel = 150,
+ .freq = 5750, /* MHz */
+ .unk2 = 3833,
+ RADIOREGS(0x71, 0x02, 0x3F, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x0009, 0xFC08, 0xF808, 0xC701, 0xC801, 0xC901),
+ },
+ { .channel = 151,
+ .freq = 5755, /* MHz */
+ .unk2 = 3837,
+ RADIOREGS(0x72, 0x04, 0x7F, 0x02, 0xFE, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x0209, 0xFE08, 0xFA08, 0xC701, 0xC801, 0xC801),
+ },
+ { .channel = 152,
+ .freq = 5760, /* MHz */
+ .unk2 = 3840,
+ RADIOREGS(0x71, 0x02, 0x40, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x0409, 0x0009, 0xFC08, 0xC601, 0xC701, 0xC801),
+ },
+ { .channel = 153,
+ .freq = 5765, /* MHz */
+ .unk2 = 3843,
+ RADIOREGS(0x72, 0x04, 0x81, 0x02, 0xF8, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x0609, 0x0209, 0xFE08, 0xC601, 0xC701, 0xC801),
+ },
+ { .channel = 154,
+ .freq = 5770, /* MHz */
+ .unk2 = 3847,
+ RADIOREGS(0x71, 0x02, 0x41, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x0809, 0x0409, 0x0009, 0xC601, 0xC601, 0xC701),
+ },
+ { .channel = 155,
+ .freq = 5775, /* MHz */
+ .unk2 = 3850,
+ RADIOREGS(0x72, 0x04, 0x83, 0x02, 0xF8, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x0A09, 0x0609, 0x0209, 0xC501, 0xC601, 0xC701),
+ },
+ { .channel = 156,
+ .freq = 5780, /* MHz */
+ .unk2 = 3853,
+ RADIOREGS(0x71, 0x02, 0x42, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x0C09, 0x0809, 0x0409, 0xC501, 0xC601, 0xC601),
+ },
+ { .channel = 157,
+ .freq = 5785, /* MHz */
+ .unk2 = 3857,
+ RADIOREGS(0x72, 0x04, 0x85, 0x02, 0xF2, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x0E09, 0x0A09, 0x0609, 0xC401, 0xC501, 0xC601),
+ },
+ { .channel = 158,
+ .freq = 5790, /* MHz */
+ .unk2 = 3860,
+ RADIOREGS(0x71, 0x02, 0x43, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x1009, 0x0C09, 0x0809, 0xC401, 0xC501, 0xC601),
+ },
+ { .channel = 159,
+ .freq = 5795, /* MHz */
+ .unk2 = 3863,
+ RADIOREGS(0x72, 0x04, 0x87, 0x02, 0xF2, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x1209, 0x0E09, 0x0A09, 0xC401, 0xC401, 0xC501),
+ },
+ { .channel = 160,
+ .freq = 5800, /* MHz */
+ .unk2 = 3867,
+ RADIOREGS(0x71, 0x02, 0x44, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x1409, 0x1009, 0x0C09, 0xC301, 0xC401, 0xC501),
+ },
+ { .channel = 161,
+ .freq = 5805, /* MHz */
+ .unk2 = 3870,
+ RADIOREGS(0x72, 0x04, 0x89, 0x01, 0xED, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x1609, 0x1209, 0x0E09, 0xC301, 0xC401, 0xC401),
+ },
+ { .channel = 162,
+ .freq = 5810, /* MHz */
+ .unk2 = 3873,
+ RADIOREGS(0x71, 0x02, 0x45, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x1809, 0x1409, 0x1009, 0xC201, 0xC301, 0xC401),
+ },
+ { .channel = 163,
+ .freq = 5815, /* MHz */
+ .unk2 = 3877,
+ RADIOREGS(0x72, 0x04, 0x8B, 0x01, 0xED, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x1A09, 0x1609, 0x1209, 0xC201, 0xC301, 0xC401),
+ },
+ { .channel = 164,
+ .freq = 5820, /* MHz */
+ .unk2 = 3880,
+ RADIOREGS(0x71, 0x02, 0x46, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x1C09, 0x1809, 0x1409, 0xC201, 0xC201, 0xC301),
+ },
+ { .channel = 165,
+ .freq = 5825, /* MHz */
+ .unk2 = 3883,
+ RADIOREGS(0x72, 0x04, 0x8D, 0x01, 0xED, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x1E09, 0x1A09, 0x1609, 0xC101, 0xC201, 0xC301),
+ },
+ { .channel = 166,
+ .freq = 5830, /* MHz */
+ .unk2 = 3887,
+ RADIOREGS(0x71, 0x02, 0x47, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x2009, 0x1C09, 0x1809, 0xC101, 0xC201, 0xC201),
+ },
+ { .channel = 168,
+ .freq = 5840, /* MHz */
+ .unk2 = 3893,
+ RADIOREGS(0x71, 0x02, 0x48, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x2409, 0x2009, 0x1C09, 0xC001, 0xC101, 0xC201),
+ },
+ { .channel = 170,
+ .freq = 5850, /* MHz */
+ .unk2 = 3900,
+ RADIOREGS(0x71, 0x02, 0x49, 0x01, 0xE0, 0x00, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x2809, 0x2409, 0x2009, 0xBF01, 0xC001, 0xC101),
+ },
+ { .channel = 172,
+ .freq = 5860, /* MHz */
+ .unk2 = 3907,
+ RADIOREGS(0x71, 0x02, 0x4A, 0x01, 0xDE, 0x00, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x2C09, 0x2809, 0x2409, 0xBF01, 0xBF01, 0xC001),
+ },
+ { .channel = 174,
+ .freq = 5870, /* MHz */
+ .unk2 = 3913,
+ RADIOREGS(0x71, 0x02, 0x4B, 0x00, 0xDB, 0x00, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x3009, 0x2C09, 0x2809, 0xBE01, 0xBF01, 0xBF01),
+ },
+ { .channel = 176,
+ .freq = 5880, /* MHz */
+ .unk2 = 3920,
+ RADIOREGS(0x71, 0x02, 0x4C, 0x00, 0xD8, 0x00, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x3409, 0x3009, 0x2C09, 0xBD01, 0xBE01, 0xBF01),
+ },
+ { .channel = 178,
+ .freq = 5890, /* MHz */
+ .unk2 = 3927,
+ RADIOREGS(0x71, 0x02, 0x4D, 0x00, 0xD6, 0x00, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x3809, 0x3409, 0x3009, 0xBC01, 0xBD01, 0xBE01),
+ },
+ { .channel = 180,
+ .freq = 5900, /* MHz */
+ .unk2 = 3933,
+ RADIOREGS(0x71, 0x02, 0x4E, 0x00, 0xD3, 0x00, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x3C09, 0x3809, 0x3409, 0xBC01, 0xBC01, 0xBD01),
+ },
+ { .channel = 182,
+ .freq = 5910, /* MHz */
+ .unk2 = 3940,
+ RADIOREGS(0x71, 0x02, 0x4F, 0x00, 0xD6, 0x00, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+ PHYREGS(0x4009, 0x3C09, 0x3809, 0xBB01, 0xBC01, 0xBC01),
+ },
+ { .channel = 1,
+ .freq = 2412, /* MHz */
+ .unk2 = 3216,
+ RADIOREGS(0x73, 0x09, 0x6C, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0D, 0x0C,
+ 0x80, 0xFF, 0x88, 0x0D, 0x0C, 0x80),
+ PHYREGS(0xC903, 0xC503, 0xC103, 0x3A04, 0x3F04, 0x4304),
+ },
+ { .channel = 2,
+ .freq = 2417, /* MHz */
+ .unk2 = 3223,
+ RADIOREGS(0x73, 0x09, 0x71, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0B,
+ 0x80, 0xFF, 0x88, 0x0C, 0x0B, 0x80),
+ PHYREGS(0xCB03, 0xC703, 0xC303, 0x3804, 0x3D04, 0x4104),
+ },
+ { .channel = 3,
+ .freq = 2422, /* MHz */
+ .unk2 = 3229,
+ RADIOREGS(0x73, 0x09, 0x76, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A,
+ 0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80),
+ PHYREGS(0xCD03, 0xC903, 0xC503, 0x3604, 0x3A04, 0x3F04),
+ },
+ { .channel = 4,
+ .freq = 2427, /* MHz */
+ .unk2 = 3236,
+ RADIOREGS(0x73, 0x09, 0x7B, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A,
+ 0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80),
+ PHYREGS(0xCF03, 0xCB03, 0xC703, 0x3404, 0x3804, 0x3D04),
+ },
+ { .channel = 5,
+ .freq = 2432, /* MHz */
+ .unk2 = 3243,
+ RADIOREGS(0x73, 0x09, 0x80, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x09,
+ 0x80, 0xFF, 0x88, 0x0C, 0x09, 0x80),
+ PHYREGS(0xD103, 0xCD03, 0xC903, 0x3104, 0x3604, 0x3A04),
+ },
+ { .channel = 6,
+ .freq = 2437, /* MHz */
+ .unk2 = 3249,
+ RADIOREGS(0x73, 0x09, 0x85, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0B, 0x08,
+ 0x80, 0xFF, 0x88, 0x0B, 0x08, 0x80),
+ PHYREGS(0xD303, 0xCF03, 0xCB03, 0x2F04, 0x3404, 0x3804),
+ },
+ { .channel = 7,
+ .freq = 2442, /* MHz */
+ .unk2 = 3256,
+ RADIOREGS(0x73, 0x09, 0x8A, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x07,
+ 0x80, 0xFF, 0x88, 0x0A, 0x07, 0x80),
+ PHYREGS(0xD503, 0xD103, 0xCD03, 0x2D04, 0x3104, 0x3604),
+ },
+ { .channel = 8,
+ .freq = 2447, /* MHz */
+ .unk2 = 3263,
+ RADIOREGS(0x73, 0x09, 0x8F, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x06,
+ 0x80, 0xFF, 0x88, 0x0A, 0x06, 0x80),
+ PHYREGS(0xD703, 0xD303, 0xCF03, 0x2B04, 0x2F04, 0x3404),
+ },
+ { .channel = 9,
+ .freq = 2452, /* MHz */
+ .unk2 = 3269,
+ RADIOREGS(0x73, 0x09, 0x94, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x09, 0x06,
+ 0x80, 0xFF, 0x88, 0x09, 0x06, 0x80),
+ PHYREGS(0xD903, 0xD503, 0xD103, 0x2904, 0x2D04, 0x3104),
+ },
+ { .channel = 10,
+ .freq = 2457, /* MHz */
+ .unk2 = 3276,
+ RADIOREGS(0x73, 0x09, 0x99, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x05,
+ 0x80, 0xFF, 0x88, 0x08, 0x05, 0x80),
+ PHYREGS(0xDB03, 0xD703, 0xD303, 0x2704, 0x2B04, 0x2F04),
+ },
+ { .channel = 11,
+ .freq = 2462, /* MHz */
+ .unk2 = 3283,
+ RADIOREGS(0x73, 0x09, 0x9E, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x04,
+ 0x80, 0xFF, 0x88, 0x08, 0x04, 0x80),
+ PHYREGS(0xDD03, 0xD903, 0xD503, 0x2404, 0x2904, 0x2D04),
+ },
+ { .channel = 12,
+ .freq = 2467, /* MHz */
+ .unk2 = 3289,
+ RADIOREGS(0x73, 0x09, 0xA3, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x03,
+ 0x80, 0xFF, 0x88, 0x08, 0x03, 0x80),
+ PHYREGS(0xDF03, 0xDB03, 0xD703, 0x2204, 0x2704, 0x2B04),
+ },
+ { .channel = 13,
+ .freq = 2472, /* MHz */
+ .unk2 = 3296,
+ RADIOREGS(0x73, 0x09, 0xA8, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x03,
+ 0x80, 0xFF, 0x88, 0x07, 0x03, 0x80),
+ PHYREGS(0xE103, 0xDD03, 0xD903, 0x2004, 0x2404, 0x2904),
+ },
+ { .channel = 14,
+ .freq = 2484, /* MHz */
+ .unk2 = 3312,
+ RADIOREGS(0x73, 0x09, 0xB4, 0x0F, 0xFF, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x01,
+ 0x80, 0xFF, 0x88, 0x07, 0x01, 0x80),
+ PHYREGS(0xE603, 0xE203, 0xDE03, 0x1B04, 0x1F04, 0x2404),
+ },
+};
+
+void b2055_upload_inittab(struct b43_wldev *dev,
+ bool ghz5, bool ignore_uploadflag)
+{
+ const struct b2055_inittab_entry *e;
+ unsigned int i;
+ u16 value;
+
+ for (i = 0; i < ARRAY_SIZE(b2055_inittab); i++) {
+ e = &(b2055_inittab[i]);
+ if (!(e->flags & B2055_INITTAB_ENTRY_OK))
+ continue;
+ if ((e->flags & B2055_INITTAB_UPLOAD) || ignore_uploadflag) {
+ if (ghz5)
+ value = e->ghz5;
+ else
+ value = e->ghz2;
+ b43_radio_write16(dev, i, value);
+ }
+ }
+}
+
+const struct b43_nphy_channeltab_entry_rev2 *
+b43_nphy_get_chantabent_rev2(struct b43_wldev *dev, u8 channel)
+{
+ const struct b43_nphy_channeltab_entry_rev2 *e;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab_rev2); i++) {
+ e = &(b43_nphy_channeltab_rev2[i]);
+ if (e->channel == channel)
+ return e;
+ }
+
+ return NULL;
+}
diff --git a/drivers/net/wireless/b43/radio_2055.h b/drivers/net/wireless/b43/radio_2055.h
new file mode 100644
index 000000000000..d9bfa0f21b72
--- /dev/null
+++ b/drivers/net/wireless/b43/radio_2055.h
@@ -0,0 +1,254 @@
+#ifndef B43_RADIO_2055_H_
+#define B43_RADIO_2055_H_
+
+#include <linux/types.h>
+
+#include "tables_nphy.h"
+
+#define B2055_GEN_SPARE 0x00 /* GEN spare */
+#define B2055_SP_PINPD 0x02 /* SP PIN PD */
+#define B2055_C1_SP_RSSI 0x03 /* SP RSSI Core 1 */
+#define B2055_C1_SP_PDMISC 0x04 /* SP PD MISC Core 1 */
+#define B2055_C2_SP_RSSI 0x05 /* SP RSSI Core 2 */
+#define B2055_C2_SP_PDMISC 0x06 /* SP PD MISC Core 2 */
+#define B2055_C1_SP_RXGC1 0x07 /* SP RX GC1 Core 1 */
+#define B2055_C1_SP_RXGC2 0x08 /* SP RX GC2 Core 1 */
+#define B2055_C2_SP_RXGC1 0x09 /* SP RX GC1 Core 2 */
+#define B2055_C2_SP_RXGC2 0x0A /* SP RX GC2 Core 2 */
+#define B2055_C1_SP_LPFBWSEL 0x0B /* SP LPF BW select Core 1 */
+#define B2055_C2_SP_LPFBWSEL 0x0C /* SP LPF BW select Core 2 */
+#define B2055_C1_SP_TXGC1 0x0D /* SP TX GC1 Core 1 */
+#define B2055_C1_SP_TXGC2 0x0E /* SP TX GC2 Core 1 */
+#define B2055_C2_SP_TXGC1 0x0F /* SP TX GC1 Core 2 */
+#define B2055_C2_SP_TXGC2 0x10 /* SP TX GC2 Core 2 */
+#define B2055_MASTER1 0x11 /* Master control 1 */
+#define B2055_MASTER2 0x12 /* Master control 2 */
+#define B2055_PD_LGEN 0x13 /* PD LGEN */
+#define B2055_PD_PLLTS 0x14 /* PD PLL TS */
+#define B2055_C1_PD_LGBUF 0x15 /* PD Core 1 LGBUF */
+#define B2055_C1_PD_TX 0x16 /* PD Core 1 TX */
+#define B2055_C1_PD_RXTX 0x17 /* PD Core 1 RXTX */
+#define B2055_C1_PD_RSSIMISC 0x18 /* PD Core 1 RSSI MISC */
+#define B2055_C2_PD_LGBUF 0x19 /* PD Core 2 LGBUF */
+#define B2055_C2_PD_TX 0x1A /* PD Core 2 TX */
+#define B2055_C2_PD_RXTX 0x1B /* PD Core 2 RXTX */
+#define B2055_C2_PD_RSSIMISC 0x1C /* PD Core 2 RSSI MISC */
+#define B2055_PWRDET_LGEN 0x1D /* PWRDET LGEN */
+#define B2055_C1_PWRDET_LGBUF 0x1E /* PWRDET LGBUF Core 1 */
+#define B2055_C1_PWRDET_RXTX 0x1F /* PWRDET RXTX Core 1 */
+#define B2055_C2_PWRDET_LGBUF 0x20 /* PWRDET LGBUF Core 2 */
+#define B2055_C2_PWRDET_RXTX 0x21 /* PWRDET RXTX Core 2 */
+#define B2055_RRCCAL_CS 0x22 /* RRCCAL Control spare */
+#define B2055_RRCCAL_NOPTSEL 0x23 /* RRCCAL N OPT SEL */
+#define B2055_CAL_MISC 0x24 /* CAL MISC */
+#define B2055_CAL_COUT 0x25 /* CAL Counter out */
+#define B2055_CAL_COUT2 0x26 /* CAL Counter out 2 */
+#define B2055_CAL_CVARCTL 0x27 /* CAL CVAR Control */
+#define B2055_CAL_RVARCTL 0x28 /* CAL RVAR Control */
+#define B2055_CAL_LPOCTL 0x29 /* CAL LPO Control */
+#define B2055_CAL_TS 0x2A /* CAL TS */
+#define B2055_CAL_RCCALRTS 0x2B /* CAL RCCAL READ TS */
+#define B2055_CAL_RCALRTS 0x2C /* CAL RCAL READ TS */
+#define B2055_PADDRV 0x2D /* PAD driver */
+#define B2055_XOCTL1 0x2E /* XO Control 1 */
+#define B2055_XOCTL2 0x2F /* XO Control 2 */
+#define B2055_XOREGUL 0x30 /* XO Regulator */
+#define B2055_XOMISC 0x31 /* XO misc */
+#define B2055_PLL_LFC1 0x32 /* PLL LF C1 */
+#define B2055_PLL_CALVTH 0x33 /* PLL CAL VTH */
+#define B2055_PLL_LFC2 0x34 /* PLL LF C2 */
+#define B2055_PLL_REF 0x35 /* PLL reference */
+#define B2055_PLL_LFR1 0x36 /* PLL LF R1 */
+#define B2055_PLL_PFDCP 0x37 /* PLL PFD CP */
+#define B2055_PLL_IDAC_CPOPAMP 0x38 /* PLL IDAC CPOPAMP */
+#define B2055_PLL_CPREG 0x39 /* PLL CP Regulator */
+#define B2055_PLL_RCAL 0x3A /* PLL RCAL */
+#define B2055_RF_PLLMOD0 0x3B /* RF PLL MOD0 */
+#define B2055_RF_PLLMOD1 0x3C /* RF PLL MOD1 */
+#define B2055_RF_MMDIDAC1 0x3D /* RF MMD IDAC 1 */
+#define B2055_RF_MMDIDAC0 0x3E /* RF MMD IDAC 0 */
+#define B2055_RF_MMDSP 0x3F /* RF MMD spare */
+#define B2055_VCO_CAL1 0x40 /* VCO cal 1 */
+#define B2055_VCO_CAL2 0x41 /* VCO cal 2 */
+#define B2055_VCO_CAL3 0x42 /* VCO cal 3 */
+#define B2055_VCO_CAL4 0x43 /* VCO cal 4 */
+#define B2055_VCO_CAL5 0x44 /* VCO cal 5 */
+#define B2055_VCO_CAL6 0x45 /* VCO cal 6 */
+#define B2055_VCO_CAL7 0x46 /* VCO cal 7 */
+#define B2055_VCO_CAL8 0x47 /* VCO cal 8 */
+#define B2055_VCO_CAL9 0x48 /* VCO cal 9 */
+#define B2055_VCO_CAL10 0x49 /* VCO cal 10 */
+#define B2055_VCO_CAL11 0x4A /* VCO cal 11 */
+#define B2055_VCO_CAL12 0x4B /* VCO cal 12 */
+#define B2055_VCO_CAL13 0x4C /* VCO cal 13 */
+#define B2055_VCO_CAL14 0x4D /* VCO cal 14 */
+#define B2055_VCO_CAL15 0x4E /* VCO cal 15 */
+#define B2055_VCO_CAL16 0x4F /* VCO cal 16 */
+#define B2055_VCO_KVCO 0x50 /* VCO KVCO */
+#define B2055_VCO_CAPTAIL 0x51 /* VCO CAP TAIL */
+#define B2055_VCO_IDACVCO 0x52 /* VCO IDAC VCO */
+#define B2055_VCO_REG 0x53 /* VCO Regulator */
+#define B2055_PLL_RFVTH 0x54 /* PLL RF VTH */
+#define B2055_LGBUF_CENBUF 0x55 /* LGBUF CEN BUF */
+#define B2055_LGEN_TUNE1 0x56 /* LGEN tune 1 */
+#define B2055_LGEN_TUNE2 0x57 /* LGEN tune 2 */
+#define B2055_LGEN_IDAC1 0x58 /* LGEN IDAC 1 */
+#define B2055_LGEN_IDAC2 0x59 /* LGEN IDAC 2 */
+#define B2055_LGEN_BIASC 0x5A /* LGEN BIAS counter */
+#define B2055_LGEN_BIASIDAC 0x5B /* LGEN BIAS IDAC */
+#define B2055_LGEN_RCAL 0x5C /* LGEN RCAL */
+#define B2055_LGEN_DIV 0x5D /* LGEN div */
+#define B2055_LGEN_SPARE2 0x5E /* LGEN spare 2 */
+#define B2055_C1_LGBUF_ATUNE 0x5F /* Core 1 LGBUF A tune */
+#define B2055_C1_LGBUF_GTUNE 0x60 /* Core 1 LGBUF G tune */
+#define B2055_C1_LGBUF_DIV 0x61 /* Core 1 LGBUF div */
+#define B2055_C1_LGBUF_AIDAC 0x62 /* Core 1 LGBUF A IDAC */
+#define B2055_C1_LGBUF_GIDAC 0x63 /* Core 1 LGBUF G IDAC */
+#define B2055_C1_LGBUF_IDACFO 0x64 /* Core 1 LGBUF IDAC filter override */
+#define B2055_C1_LGBUF_SPARE 0x65 /* Core 1 LGBUF spare */
+#define B2055_C1_RX_RFSPC1 0x66 /* Core 1 RX RF SPC1 */
+#define B2055_C1_RX_RFR1 0x67 /* Core 1 RX RF reg 1 */
+#define B2055_C1_RX_RFR2 0x68 /* Core 1 RX RF reg 2 */
+#define B2055_C1_RX_RFRCAL 0x69 /* Core 1 RX RF RCAL */
+#define B2055_C1_RX_BB_BLCMP 0x6A /* Core 1 RX Baseband BUFI LPF CMP */
+#define B2055_C1_RX_BB_LPF 0x6B /* Core 1 RX Baseband LPF */
+#define B2055_C1_RX_BB_MIDACHP 0x6C /* Core 1 RX Baseband MIDAC High-pass */
+#define B2055_C1_RX_BB_VGA1IDAC 0x6D /* Core 1 RX Baseband VGA1 IDAC */
+#define B2055_C1_RX_BB_VGA2IDAC 0x6E /* Core 1 RX Baseband VGA2 IDAC */
+#define B2055_C1_RX_BB_VGA3IDAC 0x6F /* Core 1 RX Baseband VGA3 IDAC */
+#define B2055_C1_RX_BB_BUFOCTL 0x70 /* Core 1 RX Baseband BUFO Control */
+#define B2055_C1_RX_BB_RCCALCTL 0x71 /* Core 1 RX Baseband RCCAL Control */
+#define B2055_C1_RX_BB_RSSICTL1 0x72 /* Core 1 RX Baseband RSSI Control 1 */
+#define B2055_C1_RX_BB_RSSICTL2 0x73 /* Core 1 RX Baseband RSSI Control 2 */
+#define B2055_C1_RX_BB_RSSICTL3 0x74 /* Core 1 RX Baseband RSSI Control 3 */
+#define B2055_C1_RX_BB_RSSICTL4 0x75 /* Core 1 RX Baseband RSSI Control 4 */
+#define B2055_C1_RX_BB_RSSICTL5 0x76 /* Core 1 RX Baseband RSSI Control 5 */
+#define B2055_C1_RX_BB_REG 0x77 /* Core 1 RX Baseband Regulator */
+#define B2055_C1_RX_BB_SPARE1 0x78 /* Core 1 RX Baseband spare 1 */
+#define B2055_C1_RX_TXBBRCAL 0x79 /* Core 1 RX TX BB RCAL */
+#define B2055_C1_TX_RF_SPGA 0x7A /* Core 1 TX RF SGM PGA */
+#define B2055_C1_TX_RF_SPAD 0x7B /* Core 1 TX RF SGM PAD */
+#define B2055_C1_TX_RF_CNTPGA1 0x7C /* Core 1 TX RF counter PGA 1 */
+#define B2055_C1_TX_RF_CNTPAD1 0x7D /* Core 1 TX RF counter PAD 1 */
+#define B2055_C1_TX_RF_PGAIDAC 0x7E /* Core 1 TX RF PGA IDAC */
+#define B2055_C1_TX_PGAPADTN 0x7F /* Core 1 TX PGA PAD TN */
+#define B2055_C1_TX_PADIDAC1 0x80 /* Core 1 TX PAD IDAC 1 */
+#define B2055_C1_TX_PADIDAC2 0x81 /* Core 1 TX PAD IDAC 2 */
+#define B2055_C1_TX_MXBGTRIM 0x82 /* Core 1 TX MX B/G TRIM */
+#define B2055_C1_TX_RF_RCAL 0x83 /* Core 1 TX RF RCAL */
+#define B2055_C1_TX_RF_PADTSSI1 0x84 /* Core 1 TX RF PAD TSSI1 */
+#define B2055_C1_TX_RF_PADTSSI2 0x85 /* Core 1 TX RF PAD TSSI2 */
+#define B2055_C1_TX_RF_SPARE 0x86 /* Core 1 TX RF spare */
+#define B2055_C1_TX_RF_IQCAL1 0x87 /* Core 1 TX RF I/Q CAL 1 */
+#define B2055_C1_TX_RF_IQCAL2 0x88 /* Core 1 TX RF I/Q CAL 2 */
+#define B2055_C1_TXBB_RCCAL 0x89 /* Core 1 TXBB RC CAL Control */
+#define B2055_C1_TXBB_LPF1 0x8A /* Core 1 TXBB LPF 1 */
+#define B2055_C1_TX_VOSCNCL 0x8B /* Core 1 TX VOS CNCL */
+#define B2055_C1_TX_LPF_MXGMIDAC 0x8C /* Core 1 TX LPF MXGM IDAC */
+#define B2055_C1_TX_BB_MXGM 0x8D /* Core 1 TX BB MXGM */
+#define B2055_C2_LGBUF_ATUNE 0x8E /* Core 2 LGBUF A tune */
+#define B2055_C2_LGBUF_GTUNE 0x8F /* Core 2 LGBUF G tune */
+#define B2055_C2_LGBUF_DIV 0x90 /* Core 2 LGBUF div */
+#define B2055_C2_LGBUF_AIDAC 0x91 /* Core 2 LGBUF A IDAC */
+#define B2055_C2_LGBUF_GIDAC 0x92 /* Core 2 LGBUF G IDAC */
+#define B2055_C2_LGBUF_IDACFO 0x93 /* Core 2 LGBUF IDAC filter override */
+#define B2055_C2_LGBUF_SPARE 0x94 /* Core 2 LGBUF spare */
+#define B2055_C2_RX_RFSPC1 0x95 /* Core 2 RX RF SPC1 */
+#define B2055_C2_RX_RFR1 0x96 /* Core 2 RX RF reg 1 */
+#define B2055_C2_RX_RFR2 0x97 /* Core 2 RX RF reg 2 */
+#define B2055_C2_RX_RFRCAL 0x98 /* Core 2 RX RF RCAL */
+#define B2055_C2_RX_BB_BLCMP 0x99 /* Core 2 RX Baseband BUFI LPF CMP */
+#define B2055_C2_RX_BB_LPF 0x9A /* Core 2 RX Baseband LPF */
+#define B2055_C2_RX_BB_MIDACHP 0x9B /* Core 2 RX Baseband MIDAC High-pass */
+#define B2055_C2_RX_BB_VGA1IDAC 0x9C /* Core 2 RX Baseband VGA1 IDAC */
+#define B2055_C2_RX_BB_VGA2IDAC 0x9D /* Core 2 RX Baseband VGA2 IDAC */
+#define B2055_C2_RX_BB_VGA3IDAC 0x9E /* Core 2 RX Baseband VGA3 IDAC */
+#define B2055_C2_RX_BB_BUFOCTL 0x9F /* Core 2 RX Baseband BUFO Control */
+#define B2055_C2_RX_BB_RCCALCTL 0xA0 /* Core 2 RX Baseband RCCAL Control */
+#define B2055_C2_RX_BB_RSSICTL1 0xA1 /* Core 2 RX Baseband RSSI Control 1 */
+#define B2055_C2_RX_BB_RSSICTL2 0xA2 /* Core 2 RX Baseband RSSI Control 2 */
+#define B2055_C2_RX_BB_RSSICTL3 0xA3 /* Core 2 RX Baseband RSSI Control 3 */
+#define B2055_C2_RX_BB_RSSICTL4 0xA4 /* Core 2 RX Baseband RSSI Control 4 */
+#define B2055_C2_RX_BB_RSSICTL5 0xA5 /* Core 2 RX Baseband RSSI Control 5 */
+#define B2055_C2_RX_BB_REG 0xA6 /* Core 2 RX Baseband Regulator */
+#define B2055_C2_RX_BB_SPARE1 0xA7 /* Core 2 RX Baseband spare 1 */
+#define B2055_C2_RX_TXBBRCAL 0xA8 /* Core 2 RX TX BB RCAL */
+#define B2055_C2_TX_RF_SPGA 0xA9 /* Core 2 TX RF SGM PGA */
+#define B2055_C2_TX_RF_SPAD 0xAA /* Core 2 TX RF SGM PAD */
+#define B2055_C2_TX_RF_CNTPGA1 0xAB /* Core 2 TX RF counter PGA 1 */
+#define B2055_C2_TX_RF_CNTPAD1 0xAC /* Core 2 TX RF counter PAD 1 */
+#define B2055_C2_TX_RF_PGAIDAC 0xAD /* Core 2 TX RF PGA IDAC */
+#define B2055_C2_TX_PGAPADTN 0xAE /* Core 2 TX PGA PAD TN */
+#define B2055_C2_TX_PADIDAC1 0xAF /* Core 2 TX PAD IDAC 1 */
+#define B2055_C2_TX_PADIDAC2 0xB0 /* Core 2 TX PAD IDAC 2 */
+#define B2055_C2_TX_MXBGTRIM 0xB1 /* Core 2 TX MX B/G TRIM */
+#define B2055_C2_TX_RF_RCAL 0xB2 /* Core 2 TX RF RCAL */
+#define B2055_C2_TX_RF_PADTSSI1 0xB3 /* Core 2 TX RF PAD TSSI1 */
+#define B2055_C2_TX_RF_PADTSSI2 0xB4 /* Core 2 TX RF PAD TSSI2 */
+#define B2055_C2_TX_RF_SPARE 0xB5 /* Core 2 TX RF spare */
+#define B2055_C2_TX_RF_IQCAL1 0xB6 /* Core 2 TX RF I/Q CAL 1 */
+#define B2055_C2_TX_RF_IQCAL2 0xB7 /* Core 2 TX RF I/Q CAL 2 */
+#define B2055_C2_TXBB_RCCAL 0xB8 /* Core 2 TXBB RC CAL Control */
+#define B2055_C2_TXBB_LPF1 0xB9 /* Core 2 TXBB LPF 1 */
+#define B2055_C2_TX_VOSCNCL 0xBA /* Core 2 TX VOS CNCL */
+#define B2055_C2_TX_LPF_MXGMIDAC 0xBB /* Core 2 TX LPF MXGM IDAC */
+#define B2055_C2_TX_BB_MXGM 0xBC /* Core 2 TX BB MXGM */
+#define B2055_PRG_GCHP21 0xBD /* PRG GC HPVGA23 21 */
+#define B2055_PRG_GCHP22 0xBE /* PRG GC HPVGA23 22 */
+#define B2055_PRG_GCHP23 0xBF /* PRG GC HPVGA23 23 */
+#define B2055_PRG_GCHP24 0xC0 /* PRG GC HPVGA23 24 */
+#define B2055_PRG_GCHP25 0xC1 /* PRG GC HPVGA23 25 */
+#define B2055_PRG_GCHP26 0xC2 /* PRG GC HPVGA23 26 */
+#define B2055_PRG_GCHP27 0xC3 /* PRG GC HPVGA23 27 */
+#define B2055_PRG_GCHP28 0xC4 /* PRG GC HPVGA23 28 */
+#define B2055_PRG_GCHP29 0xC5 /* PRG GC HPVGA23 29 */
+#define B2055_PRG_GCHP30 0xC6 /* PRG GC HPVGA23 30 */
+#define B2055_C1_LNA_GAINBST 0xCD /* Core 1 LNA GAINBST */
+#define B2055_C1_B0NB_RSSIVCM 0xD2 /* Core 1 B0 narrow-band RSSI VCM */
+#define B2055_C1_GENSPARE2 0xD6 /* Core 1 GEN spare 2 */
+#define B2055_C2_LNA_GAINBST 0xD9 /* Core 2 LNA GAINBST */
+#define B2055_C2_B0NB_RSSIVCM 0xDE /* Core 2 B0 narrow-band RSSI VCM */
+#define B2055_C2_GENSPARE2 0xE2 /* Core 2 GEN spare 2 */
+
+struct b43_nphy_channeltab_entry_rev2 {
+ /* The channel number */
+ u8 channel;
+ /* The channel frequency in MHz */
+ u16 freq;
+ /* An unknown value */
+ u16 unk2;
+ /* Radio register values on channelswitch */
+ u8 radio_pll_ref;
+ u8 radio_rf_pllmod0;
+ u8 radio_rf_pllmod1;
+ u8 radio_vco_captail;
+ u8 radio_vco_cal1;
+ u8 radio_vco_cal2;
+ u8 radio_pll_lfc1;
+ u8 radio_pll_lfr1;
+ u8 radio_pll_lfc2;
+ u8 radio_lgbuf_cenbuf;
+ u8 radio_lgen_tune1;
+ u8 radio_lgen_tune2;
+ u8 radio_c1_lgbuf_atune;
+ u8 radio_c1_lgbuf_gtune;
+ u8 radio_c1_rx_rfr1;
+ u8 radio_c1_tx_pgapadtn;
+ u8 radio_c1_tx_mxbgtrim;
+ u8 radio_c2_lgbuf_atune;
+ u8 radio_c2_lgbuf_gtune;
+ u8 radio_c2_rx_rfr1;
+ u8 radio_c2_tx_pgapadtn;
+ u8 radio_c2_tx_mxbgtrim;
+ /* PHY register values on channelswitch */
+ struct b43_phy_n_sfo_cfg phy_regs;
+};
+
+/* Upload the default register value table.
+ * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz
+ * table is uploaded. If "ignore_uploadflag" is true, we upload any value
+ * and ignore the "UPLOAD" flag. */
+void b2055_upload_inittab(struct b43_wldev *dev,
+ bool ghz5, bool ignore_uploadflag);
+
+#endif /* B43_RADIO_2055_H_ */
diff --git a/drivers/net/wireless/b43/radio_2056.c b/drivers/net/wireless/b43/radio_2056.c
new file mode 100644
index 000000000000..d8563192ce56
--- /dev/null
+++ b/drivers/net/wireless/b43/radio_2056.c
@@ -0,0 +1,43 @@
+/*
+
+ Broadcom B43 wireless driver
+ IEEE 802.11n 2056 radio device data tables
+
+ 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.
+
+*/
+
+#include "b43.h"
+#include "radio_2056.h"
+#include "phy_common.h"
+
+static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev3[] = {
+};
+
+const struct b43_nphy_channeltab_entry_rev3 *
+b43_nphy_get_chantabent_rev3(struct b43_wldev *dev, u16 freq)
+{
+ const struct b43_nphy_channeltab_entry_rev3 *e;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab_rev3); i++) {
+ e = &(b43_nphy_channeltab_rev3[i]);
+ if (e->freq == freq)
+ return e;
+ }
+
+ return NULL;
+}
diff --git a/drivers/net/wireless/b43/radio_2056.h b/drivers/net/wireless/b43/radio_2056.h
new file mode 100644
index 000000000000..fda6dafecb8c
--- /dev/null
+++ b/drivers/net/wireless/b43/radio_2056.h
@@ -0,0 +1,42 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ 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
+ (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_
+
+#include <linux/types.h>
+
+#include "tables_nphy.h"
+
+struct b43_nphy_channeltab_entry_rev3 {
+ /* The channel number */
+ u8 channel;
+ /* The channel frequency in MHz */
+ u16 freq;
+ /* Radio register values on channelswitch */
+ /* TODO */
+ /* PHY register values on channelswitch */
+ struct b43_phy_n_sfo_cfg phy_regs;
+};
+
+#endif /* B43_RADIO_2056_H_ */
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
index d96e870ab8fe..d60db078eae2 100644
--- a/drivers/net/wireless/b43/tables_nphy.c
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -1,7 +1,7 @@
/*
Broadcom B43 wireless driver
- IEEE 802.11n PHY and radio device data tables
+ IEEE 802.11n PHY data tables
Copyright (c) 2008 Michael Buesch <mb@bu3sch.de>
@@ -27,1315 +27,6 @@
#include "phy_common.h"
#include "phy_n.h"
-
-struct b2055_inittab_entry {
- /* Value to write if we use the 5GHz band. */
- u16 ghz5;
- /* Value to write if we use the 2.4GHz band. */
- u16 ghz2;
- /* Flags */
- u8 flags;
-#define B2055_INITTAB_ENTRY_OK 0x01
-#define B2055_INITTAB_UPLOAD 0x02
-};
-#define UPLOAD .flags = B2055_INITTAB_ENTRY_OK | B2055_INITTAB_UPLOAD
-#define NOUPLOAD .flags = B2055_INITTAB_ENTRY_OK
-
-static const struct b2055_inittab_entry b2055_inittab [] = {
- [B2055_SP_PINPD] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, },
- [B2055_C1_SP_RSSI] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C1_SP_PDMISC] = { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, },
- [B2055_C2_SP_RSSI] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C2_SP_PDMISC] = { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, },
- [B2055_C1_SP_RXGC1] = { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, },
- [B2055_C1_SP_RXGC2] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
- [B2055_C2_SP_RXGC1] = { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, },
- [B2055_C2_SP_RXGC2] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
- [B2055_C1_SP_LPFBWSEL] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
- [B2055_C2_SP_LPFBWSEL] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
- [B2055_C1_SP_TXGC1] = { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, },
- [B2055_C1_SP_TXGC2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, },
- [B2055_C2_SP_TXGC1] = { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, },
- [B2055_C2_SP_TXGC2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, },
- [B2055_MASTER1] = { .ghz5 = 0x00D0, .ghz2 = 0x00D0, NOUPLOAD, },
- [B2055_MASTER2] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
- [B2055_PD_LGEN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_PD_PLLTS] = { .ghz5 = 0x0040, .ghz2 = 0x0040, NOUPLOAD, },
- [B2055_C1_PD_LGBUF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C1_PD_TX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C1_PD_RXTX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C1_PD_RSSIMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C2_PD_LGBUF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C2_PD_TX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C2_PD_RXTX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C2_PD_RSSIMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_PWRDET_LGEN] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, },
- [B2055_C1_PWRDET_LGBUF] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
- [B2055_C1_PWRDET_RXTX] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, },
- [B2055_C2_PWRDET_LGBUF] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
- [B2055_C2_PWRDET_RXTX] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, },
- [B2055_RRCCAL_CS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_RRCCAL_NOPTSEL] = { .ghz5 = 0x002C, .ghz2 = 0x002C, NOUPLOAD, },
- [B2055_CAL_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_CAL_COUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_CAL_COUT2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_CAL_CVARCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_CAL_RVARCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_CAL_LPOCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_CAL_TS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_CAL_RCCALRTS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_CAL_RCALRTS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_PADDRV] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, },
- [B2055_XOCTL1] = { .ghz5 = 0x0038, .ghz2 = 0x0038, NOUPLOAD, },
- [B2055_XOCTL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_XOREGUL] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, },
- [B2055_XOMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_PLL_LFC1] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
- [B2055_PLL_CALVTH] = { .ghz5 = 0x0087, .ghz2 = 0x0087, NOUPLOAD, },
- [B2055_PLL_LFC2] = { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, },
- [B2055_PLL_REF] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
- [B2055_PLL_LFR1] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
- [B2055_PLL_PFDCP] = { .ghz5 = 0x0018, .ghz2 = 0x0018, UPLOAD, },
- [B2055_PLL_IDAC_CPOPAMP] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
- [B2055_PLL_CPREG] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, },
- [B2055_PLL_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
- [B2055_RF_PLLMOD0] = { .ghz5 = 0x009E, .ghz2 = 0x009E, NOUPLOAD, },
- [B2055_RF_PLLMOD1] = { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, },
- [B2055_RF_MMDIDAC1] = { .ghz5 = 0x00C8, .ghz2 = 0x00C8, UPLOAD, },
- [B2055_RF_MMDIDAC0] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
- [B2055_RF_MMDSP] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_VCO_CAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_VCO_CAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_VCO_CAL3] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
- [B2055_VCO_CAL4] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
- [B2055_VCO_CAL5] = { .ghz5 = 0x0096, .ghz2 = 0x0096, NOUPLOAD, },
- [B2055_VCO_CAL6] = { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, },
- [B2055_VCO_CAL7] = { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, },
- [B2055_VCO_CAL8] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
- [B2055_VCO_CAL9] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
- [B2055_VCO_CAL10] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
- [B2055_VCO_CAL11] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
- [B2055_VCO_CAL12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_VCO_CAL13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_VCO_CAL14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_VCO_CAL15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_VCO_CAL16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_VCO_KVCO] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
- [B2055_VCO_CAPTAIL] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
- [B2055_VCO_IDACVCO] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
- [B2055_VCO_REG] = { .ghz5 = 0x0084, .ghz2 = 0x0084, UPLOAD, },
- [B2055_PLL_RFVTH] = { .ghz5 = 0x00C3, .ghz2 = 0x00C3, NOUPLOAD, },
- [B2055_LGBUF_CENBUF] = { .ghz5 = 0x008F, .ghz2 = 0x008F, NOUPLOAD, },
- [B2055_LGEN_TUNE1] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
- [B2055_LGEN_TUNE2] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
- [B2055_LGEN_IDAC1] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
- [B2055_LGEN_IDAC2] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
- [B2055_LGEN_BIASC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_LGEN_BIASIDAC] = { .ghz5 = 0x00CC, .ghz2 = 0x00CC, NOUPLOAD, },
- [B2055_LGEN_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
- [B2055_LGEN_DIV] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, },
- [B2055_LGEN_SPARE2] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, },
- [B2055_C1_LGBUF_ATUNE] = { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, },
- [B2055_C1_LGBUF_GTUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
- [B2055_C1_LGBUF_DIV] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
- [B2055_C1_LGBUF_AIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, },
- [B2055_C1_LGBUF_GIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
- [B2055_C1_LGBUF_IDACFO] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C1_LGBUF_SPARE] = { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, },
- [B2055_C1_RX_RFSPC1] = { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, },
- [B2055_C1_RX_RFR1] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
- [B2055_C1_RX_RFR2] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
- [B2055_C1_RX_RFRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
- [B2055_C1_RX_BB_BLCMP] = { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, },
- [B2055_C1_RX_BB_LPF] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
- [B2055_C1_RX_BB_MIDACHP] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
- [B2055_C1_RX_BB_VGA1IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
- [B2055_C1_RX_BB_VGA2IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
- [B2055_C1_RX_BB_VGA3IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
- [B2055_C1_RX_BB_BUFOCTL] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
- [B2055_C1_RX_BB_RCCALCTL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
- [B2055_C1_RX_BB_RSSICTL1] = { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, },
- [B2055_C1_RX_BB_RSSICTL2] = { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, },
- [B2055_C1_RX_BB_RSSICTL3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, },
- [B2055_C1_RX_BB_RSSICTL4] = { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, },
- [B2055_C1_RX_BB_RSSICTL5] = { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, },
- [B2055_C1_RX_BB_REG] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
- [B2055_C1_RX_BB_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C1_RX_TXBBRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
- [B2055_C1_TX_RF_SPGA] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
- [B2055_C1_TX_RF_SPAD] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
- [B2055_C1_TX_RF_CNTPGA1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
- [B2055_C1_TX_RF_CNTPAD1] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
- [B2055_C1_TX_RF_PGAIDAC] = { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, },
- [B2055_C1_TX_PGAPADTN] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
- [B2055_C1_TX_PADIDAC1] = { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, },
- [B2055_C1_TX_PADIDAC2] = { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, },
- [B2055_C1_TX_MXBGTRIM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
- [B2055_C1_TX_RF_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
- [B2055_C1_TX_RF_PADTSSI1] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
- [B2055_C1_TX_RF_PADTSSI2] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
- [B2055_C1_TX_RF_SPARE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
- [B2055_C1_TX_RF_IQCAL1] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
- [B2055_C1_TX_RF_IQCAL2] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, },
- [B2055_C1_TXBB_RCCAL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
- [B2055_C1_TXBB_LPF1] = { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, },
- [B2055_C1_TX_VOSCNCL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C1_TX_LPF_MXGMIDAC] = { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, },
- [B2055_C1_TX_BB_MXGM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C2_LGBUF_ATUNE] = { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, },
- [B2055_C2_LGBUF_GTUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
- [B2055_C2_LGBUF_DIV] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
- [B2055_C2_LGBUF_AIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, },
- [B2055_C2_LGBUF_GIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
- [B2055_C2_LGBUF_IDACFO] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C2_LGBUF_SPARE] = { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, },
- [B2055_C2_RX_RFSPC1] = { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, },
- [B2055_C2_RX_RFR1] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
- [B2055_C2_RX_RFR2] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
- [B2055_C2_RX_RFRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
- [B2055_C2_RX_BB_BLCMP] = { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, },
- [B2055_C2_RX_BB_LPF] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
- [B2055_C2_RX_BB_MIDACHP] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
- [B2055_C2_RX_BB_VGA1IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
- [B2055_C2_RX_BB_VGA2IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
- [B2055_C2_RX_BB_VGA3IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
- [B2055_C2_RX_BB_BUFOCTL] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
- [B2055_C2_RX_BB_RCCALCTL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
- [B2055_C2_RX_BB_RSSICTL1] = { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, },
- [B2055_C2_RX_BB_RSSICTL2] = { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, },
- [B2055_C2_RX_BB_RSSICTL3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, },
- [B2055_C2_RX_BB_RSSICTL4] = { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, },
- [B2055_C2_RX_BB_RSSICTL5] = { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, },
- [B2055_C2_RX_BB_REG] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
- [B2055_C2_RX_BB_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C2_RX_TXBBRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
- [B2055_C2_TX_RF_SPGA] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
- [B2055_C2_TX_RF_SPAD] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
- [B2055_C2_TX_RF_CNTPGA1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
- [B2055_C2_TX_RF_CNTPAD1] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
- [B2055_C2_TX_RF_PGAIDAC] = { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, },
- [B2055_C2_TX_PGAPADTN] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
- [B2055_C2_TX_PADIDAC1] = { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, },
- [B2055_C2_TX_PADIDAC2] = { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, },
- [B2055_C2_TX_MXBGTRIM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
- [B2055_C2_TX_RF_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
- [B2055_C2_TX_RF_PADTSSI1] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
- [B2055_C2_TX_RF_PADTSSI2] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
- [B2055_C2_TX_RF_SPARE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
- [B2055_C2_TX_RF_IQCAL1] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
- [B2055_C2_TX_RF_IQCAL2] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, },
- [B2055_C2_TXBB_RCCAL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
- [B2055_C2_TXBB_LPF1] = { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, },
- [B2055_C2_TX_VOSCNCL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C2_TX_LPF_MXGMIDAC] = { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, },
- [B2055_C2_TX_BB_MXGM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_PRG_GCHP21] = { .ghz5 = 0x0071, .ghz2 = 0x0071, NOUPLOAD, },
- [B2055_PRG_GCHP22] = { .ghz5 = 0x0072, .ghz2 = 0x0072, NOUPLOAD, },
- [B2055_PRG_GCHP23] = { .ghz5 = 0x0073, .ghz2 = 0x0073, NOUPLOAD, },
- [B2055_PRG_GCHP24] = { .ghz5 = 0x0074, .ghz2 = 0x0074, NOUPLOAD, },
- [B2055_PRG_GCHP25] = { .ghz5 = 0x0075, .ghz2 = 0x0075, NOUPLOAD, },
- [B2055_PRG_GCHP26] = { .ghz5 = 0x0076, .ghz2 = 0x0076, NOUPLOAD, },
- [B2055_PRG_GCHP27] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
- [B2055_PRG_GCHP28] = { .ghz5 = 0x0078, .ghz2 = 0x0078, NOUPLOAD, },
- [B2055_PRG_GCHP29] = { .ghz5 = 0x0079, .ghz2 = 0x0079, NOUPLOAD, },
- [B2055_PRG_GCHP30] = { .ghz5 = 0x007A, .ghz2 = 0x007A, NOUPLOAD, },
- [0xC7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xC8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xC9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xCA] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xCB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xCC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C1_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xCE] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xCF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xD0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xD1] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
- [B2055_C1_B0NB_RSSIVCM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
- [0xD3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xD4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xD5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C1_GENSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xD7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xD8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C2_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xDA] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xDB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xDC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xDD] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
- [B2055_C2_B0NB_RSSIVCM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
- [0xDF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xE0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [0xE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
- [B2055_C2_GENSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
-};
-
-
-void b2055_upload_inittab(struct b43_wldev *dev,
- bool ghz5, bool ignore_uploadflag)
-{
- const struct b2055_inittab_entry *e;
- unsigned int i;
- u16 value;
-
- for (i = 0; i < ARRAY_SIZE(b2055_inittab); i++) {
- e = &(b2055_inittab[i]);
- if (!(e->flags & B2055_INITTAB_ENTRY_OK))
- continue;
- if ((e->flags & B2055_INITTAB_UPLOAD) || ignore_uploadflag) {
- if (ghz5)
- value = e->ghz5;
- else
- value = e->ghz2;
- b43_radio_write16(dev, i, value);
- }
- }
-}
-
-
-#define RADIOREGS(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, \
- r12, r13, r14, r15, r16, r17, r18, r19, r20, r21) \
- .radio_pll_ref = r0, \
- .radio_rf_pllmod0 = r1, \
- .radio_rf_pllmod1 = r2, \
- .radio_vco_captail = r3, \
- .radio_vco_cal1 = r4, \
- .radio_vco_cal2 = r5, \
- .radio_pll_lfc1 = r6, \
- .radio_pll_lfr1 = r7, \
- .radio_pll_lfc2 = r8, \
- .radio_lgbuf_cenbuf = r9, \
- .radio_lgen_tune1 = r10, \
- .radio_lgen_tune2 = r11, \
- .radio_c1_lgbuf_atune = r12, \
- .radio_c1_lgbuf_gtune = r13, \
- .radio_c1_rx_rfr1 = r14, \
- .radio_c1_tx_pgapadtn = r15, \
- .radio_c1_tx_mxbgtrim = r16, \
- .radio_c2_lgbuf_atune = r17, \
- .radio_c2_lgbuf_gtune = r18, \
- .radio_c2_rx_rfr1 = r19, \
- .radio_c2_tx_pgapadtn = r20, \
- .radio_c2_tx_mxbgtrim = r21
-
-#define PHYREGS(r0, r1, r2, r3, r4, r5) \
- .phy_regs.phy_bw1a = r0, \
- .phy_regs.phy_bw2 = r1, \
- .phy_regs.phy_bw3 = r2, \
- .phy_regs.phy_bw4 = r3, \
- .phy_regs.phy_bw5 = r4, \
- .phy_regs.phy_bw6 = r5
-
-static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab[] = {
- { .channel = 184,
- .freq = 4920, /* MHz */
- .unk2 = 3280,
- RADIOREGS(0x71, 0x01, 0xEC, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F,
- 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xB407, 0xB007, 0xAC07, 0x1402, 0x1502, 0x1602),
- },
- { .channel = 186,
- .freq = 4930, /* MHz */
- .unk2 = 3287,
- RADIOREGS(0x71, 0x01, 0xED, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F,
- 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xB807, 0xB407, 0xB007, 0x1302, 0x1402, 0x1502),
- },
- { .channel = 188,
- .freq = 4940, /* MHz */
- .unk2 = 3293,
- RADIOREGS(0x71, 0x01, 0xEE, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
- 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xBC07, 0xB807, 0xB407, 0x1202, 0x1302, 0x1402),
- },
- { .channel = 190,
- .freq = 4950, /* MHz */
- .unk2 = 3300,
- RADIOREGS(0x71, 0x01, 0xEF, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
- 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xC007, 0xBC07, 0xB807, 0x1102, 0x1202, 0x1302),
- },
- { .channel = 192,
- .freq = 4960, /* MHz */
- .unk2 = 3307,
- RADIOREGS(0x71, 0x01, 0xF0, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
- 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xC407, 0xC007, 0xBC07, 0x0F02, 0x1102, 0x1202),
- },
- { .channel = 194,
- .freq = 4970, /* MHz */
- .unk2 = 3313,
- RADIOREGS(0x71, 0x01, 0xF1, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
- 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xC807, 0xC407, 0xC007, 0x0E02, 0x0F02, 0x1102),
- },
- { .channel = 196,
- .freq = 4980, /* MHz */
- .unk2 = 3320,
- RADIOREGS(0x71, 0x01, 0xF2, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
- 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xCC07, 0xC807, 0xC407, 0x0D02, 0x0E02, 0x0F02),
- },
- { .channel = 198,
- .freq = 4990, /* MHz */
- .unk2 = 3327,
- RADIOREGS(0x71, 0x01, 0xF3, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
- 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xD007, 0xCC07, 0xC807, 0x0C02, 0x0D02, 0x0E02),
- },
- { .channel = 200,
- .freq = 5000, /* MHz */
- .unk2 = 3333,
- RADIOREGS(0x71, 0x01, 0xF4, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
- 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xD407, 0xD007, 0xCC07, 0x0B02, 0x0C02, 0x0D02),
- },
- { .channel = 202,
- .freq = 5010, /* MHz */
- .unk2 = 3340,
- RADIOREGS(0x71, 0x01, 0xF5, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
- 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xD807, 0xD407, 0xD007, 0x0A02, 0x0B02, 0x0C02),
- },
- { .channel = 204,
- .freq = 5020, /* MHz */
- .unk2 = 3347,
- RADIOREGS(0x71, 0x01, 0xF6, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
- 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xDC07, 0xD807, 0xD407, 0x0902, 0x0A02, 0x0B02),
- },
- { .channel = 206,
- .freq = 5030, /* MHz */
- .unk2 = 3353,
- RADIOREGS(0x71, 0x01, 0xF7, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
- 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xE007, 0xDC07, 0xD807, 0x0802, 0x0902, 0x0A02),
- },
- { .channel = 208,
- .freq = 5040, /* MHz */
- .unk2 = 3360,
- RADIOREGS(0x71, 0x01, 0xF8, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
- 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xE407, 0xE007, 0xDC07, 0x0702, 0x0802, 0x0902),
- },
- { .channel = 210,
- .freq = 5050, /* MHz */
- .unk2 = 3367,
- RADIOREGS(0x71, 0x01, 0xF9, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
- 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
- PHYREGS(0xE807, 0xE407, 0xE007, 0x0602, 0x0702, 0x0802),
- },
- { .channel = 212,
- .freq = 5060, /* MHz */
- .unk2 = 3373,
- RADIOREGS(0x71, 0x01, 0xFA, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F,
- 0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E),
- PHYREGS(0xEC07, 0xE807, 0xE407, 0x0502, 0x0602, 0x0702),
- },
- { .channel = 214,
- .freq = 5070, /* MHz */
- .unk2 = 3380,
- RADIOREGS(0x71, 0x01, 0xFB, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
- 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F,
- 0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E),
- PHYREGS(0xF007, 0xEC07, 0xE807, 0x0402, 0x0502, 0x0602),
- },
- { .channel = 216,
- .freq = 5080, /* MHz */
- .unk2 = 3387,
- RADIOREGS(0x71, 0x01, 0xFC, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
- 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F,
- 0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D),
- PHYREGS(0xF407, 0xF007, 0xEC07, 0x0302, 0x0402, 0x0502),
- },
- { .channel = 218,
- .freq = 5090, /* MHz */
- .unk2 = 3393,
- RADIOREGS(0x71, 0x01, 0xFD, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
- 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F,
- 0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D),
- PHYREGS(0xF807, 0xF407, 0xF007, 0x0202, 0x0302, 0x0402),
- },
- { .channel = 220,
- .freq = 5100, /* MHz */
- .unk2 = 3400,
- RADIOREGS(0x71, 0x01, 0xFE, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
- 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F,
- 0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D),
- PHYREGS(0xFC07, 0xF807, 0xF407, 0x0102, 0x0202, 0x0302),
- },
- { .channel = 222,
- .freq = 5110, /* MHz */
- .unk2 = 3407,
- RADIOREGS(0x71, 0x01, 0xFF, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
- 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F,
- 0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D),
- PHYREGS(0x0008, 0xFC07, 0xF807, 0x0002, 0x0102, 0x0202),
- },
- { .channel = 224,
- .freq = 5120, /* MHz */
- .unk2 = 3413,
- RADIOREGS(0x71, 0x02, 0x00, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
- 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F,
- 0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C),
- PHYREGS(0x0408, 0x0008, 0xFC07, 0xFF01, 0x0002, 0x0102),
- },
- { .channel = 226,
- .freq = 5130, /* MHz */
- .unk2 = 3420,
- RADIOREGS(0x71, 0x02, 0x01, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
- 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F,
- 0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C),
- PHYREGS(0x0808, 0x0408, 0x0008, 0xFE01, 0xFF01, 0x0002),
- },
- { .channel = 228,
- .freq = 5140, /* MHz */
- .unk2 = 3427,
- RADIOREGS(0x71, 0x02, 0x02, 0x0C, 0xC6, 0x01, 0x04, 0x0A,
- 0x00, 0x8D, 0x99, 0x99, 0xDD, 0x00, 0x0C, 0x0E,
- 0x8B, 0xDD, 0x00, 0x0C, 0x0E, 0x8B),
- PHYREGS(0x0C08, 0x0808, 0x0408, 0xFD01, 0xFE01, 0xFF01),
- },
- { .channel = 32,
- .freq = 5160, /* MHz */
- .unk2 = 3440,
- RADIOREGS(0x71, 0x02, 0x04, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
- 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D,
- 0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A),
- PHYREGS(0x1408, 0x1008, 0x0C08, 0xFB01, 0xFC01, 0xFD01),
- },
- { .channel = 34,
- .freq = 5170, /* MHz */
- .unk2 = 3447,
- RADIOREGS(0x71, 0x02, 0x05, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
- 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D,
- 0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A),
- PHYREGS(0x1808, 0x1408, 0x1008, 0xFA01, 0xFB01, 0xFC01),
- },
- { .channel = 36,
- .freq = 5180, /* MHz */
- .unk2 = 3453,
- RADIOREGS(0x71, 0x02, 0x06, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
- 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C,
- 0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89),
- PHYREGS(0x1C08, 0x1808, 0x1408, 0xF901, 0xFA01, 0xFB01),
- },
- { .channel = 38,
- .freq = 5190, /* MHz */
- .unk2 = 3460,
- RADIOREGS(0x71, 0x02, 0x07, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
- 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C,
- 0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89),
- PHYREGS(0x2008, 0x1C08, 0x1808, 0xF801, 0xF901, 0xFA01),
- },
- { .channel = 40,
- .freq = 5200, /* MHz */
- .unk2 = 3467,
- RADIOREGS(0x71, 0x02, 0x08, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
- 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B,
- 0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89),
- PHYREGS(0x2408, 0x2008, 0x1C08, 0xF701, 0xF801, 0xF901),
- },
- { .channel = 42,
- .freq = 5210, /* MHz */
- .unk2 = 3473,
- RADIOREGS(0x71, 0x02, 0x09, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
- 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B,
- 0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89),
- PHYREGS(0x2808, 0x2408, 0x2008, 0xF601, 0xF701, 0xF801),
- },
- { .channel = 44,
- .freq = 5220, /* MHz */
- .unk2 = 3480,
- RADIOREGS(0x71, 0x02, 0x0A, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
- 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A,
- 0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88),
- PHYREGS(0x2C08, 0x2808, 0x2408, 0xF501, 0xF601, 0xF701),
- },
- { .channel = 46,
- .freq = 5230, /* MHz */
- .unk2 = 3487,
- RADIOREGS(0x71, 0x02, 0x0B, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
- 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A,
- 0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88),
- PHYREGS(0x3008, 0x2C08, 0x2808, 0xF401, 0xF501, 0xF601),
- },
- { .channel = 48,
- .freq = 5240, /* MHz */
- .unk2 = 3493,
- RADIOREGS(0x71, 0x02, 0x0C, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
- 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A,
- 0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87),
- PHYREGS(0x3408, 0x3008, 0x2C08, 0xF301, 0xF401, 0xF501),
- },
- { .channel = 50,
- .freq = 5250, /* MHz */
- .unk2 = 3500,
- RADIOREGS(0x71, 0x02, 0x0D, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
- 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A,
- 0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87),
- PHYREGS(0x3808, 0x3408, 0x3008, 0xF201, 0xF301, 0xF401),
- },
- { .channel = 52,
- .freq = 5260, /* MHz */
- .unk2 = 3507,
- RADIOREGS(0x71, 0x02, 0x0E, 0x0A, 0x98, 0x01, 0x04, 0x0A,
- 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09,
- 0x87, 0xAA, 0x00, 0x08, 0x09, 0x87),
- PHYREGS(0x3C08, 0x3808, 0x3408, 0xF101, 0xF201, 0xF301),
- },
- { .channel = 54,
- .freq = 5270, /* MHz */
- .unk2 = 3513,
- RADIOREGS(0x71, 0x02, 0x0F, 0x0A, 0x98, 0x01, 0x04, 0x0A,
- 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09,
- 0x87, 0xAA, 0x00, 0x08, 0x09, 0x87),
- PHYREGS(0x4008, 0x3C08, 0x3808, 0xF001, 0xF101, 0xF201),
- },
- { .channel = 56,
- .freq = 5280, /* MHz */
- .unk2 = 3520,
- RADIOREGS(0x71, 0x02, 0x10, 0x09, 0x91, 0x01, 0x04, 0x0A,
- 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08,
- 0x86, 0x99, 0x00, 0x08, 0x08, 0x86),
- PHYREGS(0x4408, 0x4008, 0x3C08, 0xF001, 0xF001, 0xF101),
- },
- { .channel = 58,
- .freq = 5290, /* MHz */
- .unk2 = 3527,
- RADIOREGS(0x71, 0x02, 0x11, 0x09, 0x91, 0x01, 0x04, 0x0A,
- 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08,
- 0x86, 0x99, 0x00, 0x08, 0x08, 0x86),
- PHYREGS(0x4808, 0x4408, 0x4008, 0xEF01, 0xF001, 0xF001),
- },
- { .channel = 60,
- .freq = 5300, /* MHz */
- .unk2 = 3533,
- RADIOREGS(0x71, 0x02, 0x12, 0x09, 0x8A, 0x01, 0x04, 0x0A,
- 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07,
- 0x85, 0x99, 0x00, 0x08, 0x07, 0x85),
- PHYREGS(0x4C08, 0x4808, 0x4408, 0xEE01, 0xEF01, 0xF001),
- },
- { .channel = 62,
- .freq = 5310, /* MHz */
- .unk2 = 3540,
- RADIOREGS(0x71, 0x02, 0x13, 0x09, 0x8A, 0x01, 0x04, 0x0A,
- 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07,
- 0x85, 0x99, 0x00, 0x08, 0x07, 0x85),
- PHYREGS(0x5008, 0x4C08, 0x4808, 0xED01, 0xEE01, 0xEF01),
- },
- { .channel = 64,
- .freq = 5320, /* MHz */
- .unk2 = 3547,
- RADIOREGS(0x71, 0x02, 0x14, 0x09, 0x83, 0x01, 0x04, 0x0A,
- 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07,
- 0x84, 0x88, 0x00, 0x07, 0x07, 0x84),
- PHYREGS(0x5408, 0x5008, 0x4C08, 0xEC01, 0xED01, 0xEE01),
- },
- { .channel = 66,
- .freq = 5330, /* MHz */
- .unk2 = 3553,
- RADIOREGS(0x71, 0x02, 0x15, 0x09, 0x83, 0x01, 0x04, 0x0A,
- 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07,
- 0x84, 0x88, 0x00, 0x07, 0x07, 0x84),
- PHYREGS(0x5808, 0x5408, 0x5008, 0xEB01, 0xEC01, 0xED01),
- },
- { .channel = 68,
- .freq = 5340, /* MHz */
- .unk2 = 3560,
- RADIOREGS(0x71, 0x02, 0x16, 0x08, 0x7C, 0x01, 0x04, 0x0A,
- 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06,
- 0x84, 0x88, 0x00, 0x07, 0x06, 0x84),
- PHYREGS(0x5C08, 0x5808, 0x5408, 0xEA01, 0xEB01, 0xEC01),
- },
- { .channel = 70,
- .freq = 5350, /* MHz */
- .unk2 = 3567,
- RADIOREGS(0x71, 0x02, 0x17, 0x08, 0x7C, 0x01, 0x04, 0x0A,
- 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06,
- 0x84, 0x88, 0x00, 0x07, 0x06, 0x84),
- PHYREGS(0x6008, 0x5C08, 0x5808, 0xE901, 0xEA01, 0xEB01),
- },
- { .channel = 72,
- .freq = 5360, /* MHz */
- .unk2 = 3573,
- RADIOREGS(0x71, 0x02, 0x18, 0x08, 0x75, 0x01, 0x04, 0x0A,
- 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05,
- 0x83, 0x77, 0x00, 0x06, 0x05, 0x83),
- PHYREGS(0x6408, 0x6008, 0x5C08, 0xE801, 0xE901, 0xEA01),
- },
- { .channel = 74,
- .freq = 5370, /* MHz */
- .unk2 = 3580,
- RADIOREGS(0x71, 0x02, 0x19, 0x08, 0x75, 0x01, 0x04, 0x0A,
- 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05,
- 0x83, 0x77, 0x00, 0x06, 0x05, 0x83),
- PHYREGS(0x6808, 0x6408, 0x6008, 0xE701, 0xE801, 0xE901),
- },
- { .channel = 76,
- .freq = 5380, /* MHz */
- .unk2 = 3587,
- RADIOREGS(0x71, 0x02, 0x1A, 0x08, 0x6E, 0x01, 0x04, 0x0A,
- 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04,
- 0x82, 0x77, 0x00, 0x06, 0x04, 0x82),
- PHYREGS(0x6C08, 0x6808, 0x6408, 0xE601, 0xE701, 0xE801),
- },
- { .channel = 78,
- .freq = 5390, /* MHz */
- .unk2 = 3593,
- RADIOREGS(0x71, 0x02, 0x1B, 0x08, 0x6E, 0x01, 0x04, 0x0A,
- 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04,
- 0x82, 0x77, 0x00, 0x06, 0x04, 0x82),
- PHYREGS(0x7008, 0x6C08, 0x6808, 0xE501, 0xE601, 0xE701),
- },
- { .channel = 80,
- .freq = 5400, /* MHz */
- .unk2 = 3600,
- RADIOREGS(0x71, 0x02, 0x1C, 0x07, 0x67, 0x01, 0x04, 0x0A,
- 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04,
- 0x81, 0x66, 0x00, 0x05, 0x04, 0x81),
- PHYREGS(0x7408, 0x7008, 0x6C08, 0xE501, 0xE501, 0xE601),
- },
- { .channel = 82,
- .freq = 5410, /* MHz */
- .unk2 = 3607,
- RADIOREGS(0x71, 0x02, 0x1D, 0x07, 0x67, 0x01, 0x04, 0x0A,
- 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04,
- 0x81, 0x66, 0x00, 0x05, 0x04, 0x81),
- PHYREGS(0x7808, 0x7408, 0x7008, 0xE401, 0xE501, 0xE501),
- },
- { .channel = 84,
- .freq = 5420, /* MHz */
- .unk2 = 3613,
- RADIOREGS(0x71, 0x02, 0x1E, 0x07, 0x61, 0x01, 0x04, 0x0A,
- 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03,
- 0x80, 0x66, 0x00, 0x05, 0x03, 0x80),
- PHYREGS(0x7C08, 0x7808, 0x7408, 0xE301, 0xE401, 0xE501),
- },
- { .channel = 86,
- .freq = 5430, /* MHz */
- .unk2 = 3620,
- RADIOREGS(0x71, 0x02, 0x1F, 0x07, 0x61, 0x01, 0x04, 0x0A,
- 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03,
- 0x80, 0x66, 0x00, 0x05, 0x03, 0x80),
- PHYREGS(0x8008, 0x7C08, 0x7808, 0xE201, 0xE301, 0xE401),
- },
- { .channel = 88,
- .freq = 5440, /* MHz */
- .unk2 = 3627,
- RADIOREGS(0x71, 0x02, 0x20, 0x07, 0x5A, 0x01, 0x04, 0x0A,
- 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02,
- 0x80, 0x55, 0x00, 0x04, 0x02, 0x80),
- PHYREGS(0x8408, 0x8008, 0x7C08, 0xE101, 0xE201, 0xE301),
- },
- { .channel = 90,
- .freq = 5450, /* MHz */
- .unk2 = 3633,
- RADIOREGS(0x71, 0x02, 0x21, 0x07, 0x5A, 0x01, 0x04, 0x0A,
- 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02,
- 0x80, 0x55, 0x00, 0x04, 0x02, 0x80),
- PHYREGS(0x8808, 0x8408, 0x8008, 0xE001, 0xE101, 0xE201),
- },
- { .channel = 92,
- .freq = 5460, /* MHz */
- .unk2 = 3640,
- RADIOREGS(0x71, 0x02, 0x22, 0x06, 0x53, 0x01, 0x04, 0x0A,
- 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01,
- 0x80, 0x55, 0x00, 0x04, 0x01, 0x80),
- PHYREGS(0x8C08, 0x8808, 0x8408, 0xDF01, 0xE001, 0xE101),
- },
- { .channel = 94,
- .freq = 5470, /* MHz */
- .unk2 = 3647,
- RADIOREGS(0x71, 0x02, 0x23, 0x06, 0x53, 0x01, 0x04, 0x0A,
- 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01,
- 0x80, 0x55, 0x00, 0x04, 0x01, 0x80),
- PHYREGS(0x9008, 0x8C08, 0x8808, 0xDE01, 0xDF01, 0xE001),
- },
- { .channel = 96,
- .freq = 5480, /* MHz */
- .unk2 = 3653,
- RADIOREGS(0x71, 0x02, 0x24, 0x06, 0x4D, 0x01, 0x04, 0x0A,
- 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00,
- 0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
- PHYREGS(0x9408, 0x9008, 0x8C08, 0xDD01, 0xDE01, 0xDF01),
- },
- { .channel = 98,
- .freq = 5490, /* MHz */
- .unk2 = 3660,
- RADIOREGS(0x71, 0x02, 0x25, 0x06, 0x4D, 0x01, 0x04, 0x0A,
- 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00,
- 0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
- PHYREGS(0x9808, 0x9408, 0x9008, 0xDD01, 0xDD01, 0xDE01),
- },
- { .channel = 100,
- .freq = 5500, /* MHz */
- .unk2 = 3667,
- RADIOREGS(0x71, 0x02, 0x26, 0x06, 0x47, 0x01, 0x04, 0x0A,
- 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00,
- 0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
- PHYREGS(0x9C08, 0x9808, 0x9408, 0xDC01, 0xDD01, 0xDD01),
- },
- { .channel = 102,
- .freq = 5510, /* MHz */
- .unk2 = 3673,
- RADIOREGS(0x71, 0x02, 0x27, 0x06, 0x47, 0x01, 0x04, 0x0A,
- 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00,
- 0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
- PHYREGS(0xA008, 0x9C08, 0x9808, 0xDB01, 0xDC01, 0xDD01),
- },
- { .channel = 104,
- .freq = 5520, /* MHz */
- .unk2 = 3680,
- RADIOREGS(0x71, 0x02, 0x28, 0x05, 0x40, 0x01, 0x04, 0x0A,
- 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
- 0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
- PHYREGS(0xA408, 0xA008, 0x9C08, 0xDA01, 0xDB01, 0xDC01),
- },
- { .channel = 106,
- .freq = 5530, /* MHz */
- .unk2 = 3687,
- RADIOREGS(0x71, 0x02, 0x29, 0x05, 0x40, 0x01, 0x04, 0x0A,
- 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
- 0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
- PHYREGS(0xA808, 0xA408, 0xA008, 0xD901, 0xDA01, 0xDB01),
- },
- { .channel = 108,
- .freq = 5540, /* MHz */
- .unk2 = 3693,
- RADIOREGS(0x71, 0x02, 0x2A, 0x05, 0x3A, 0x01, 0x04, 0x0A,
- 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
- 0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
- PHYREGS(0xAC08, 0xA808, 0xA408, 0xD801, 0xD901, 0xDA01),
- },
- { .channel = 110,
- .freq = 5550, /* MHz */
- .unk2 = 3700,
- RADIOREGS(0x71, 0x02, 0x2B, 0x05, 0x3A, 0x01, 0x04, 0x0A,
- 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
- 0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
- PHYREGS(0xB008, 0xAC08, 0xA808, 0xD701, 0xD801, 0xD901),
- },
- { .channel = 112,
- .freq = 5560, /* MHz */
- .unk2 = 3707,
- RADIOREGS(0x71, 0x02, 0x2C, 0x05, 0x34, 0x01, 0x04, 0x0A,
- 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
- 0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
- PHYREGS(0xB408, 0xB008, 0xAC08, 0xD701, 0xD701, 0xD801),
- },
- { .channel = 114,
- .freq = 5570, /* MHz */
- .unk2 = 3713,
- RADIOREGS(0x71, 0x02, 0x2D, 0x05, 0x34, 0x01, 0x04, 0x0A,
- 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
- 0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
- PHYREGS(0xB808, 0xB408, 0xB008, 0xD601, 0xD701, 0xD701),
- },
- { .channel = 116,
- .freq = 5580, /* MHz */
- .unk2 = 3720,
- RADIOREGS(0x71, 0x02, 0x2E, 0x04, 0x2E, 0x01, 0x04, 0x0A,
- 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
- 0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
- PHYREGS(0xBC08, 0xB808, 0xB408, 0xD501, 0xD601, 0xD701),
- },
- { .channel = 118,
- .freq = 5590, /* MHz */
- .unk2 = 3727,
- RADIOREGS(0x71, 0x02, 0x2F, 0x04, 0x2E, 0x01, 0x04, 0x0A,
- 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
- 0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
- PHYREGS(0xC008, 0xBC08, 0xB808, 0xD401, 0xD501, 0xD601),
- },
- { .channel = 120,
- .freq = 5600, /* MHz */
- .unk2 = 3733,
- RADIOREGS(0x71, 0x02, 0x30, 0x04, 0x28, 0x01, 0x04, 0x0A,
- 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
- 0x80, 0x11, 0x00, 0x01, 0x00, 0x80),
- PHYREGS(0xC408, 0xC008, 0xBC08, 0xD301, 0xD401, 0xD501),
- },
- { .channel = 122,
- .freq = 5610, /* MHz */
- .unk2 = 3740,
- RADIOREGS(0x71, 0x02, 0x31, 0x04, 0x28, 0x01, 0x04, 0x0A,
- 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
- 0x80, 0x11, 0x00, 0x01, 0x00, 0x80),
- PHYREGS(0xC808, 0xC408, 0xC008, 0xD201, 0xD301, 0xD401),
- },
- { .channel = 124,
- .freq = 5620, /* MHz */
- .unk2 = 3747,
- RADIOREGS(0x71, 0x02, 0x32, 0x04, 0x21, 0x01, 0x04, 0x0A,
- 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
- 0x80, 0x11, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xCC08, 0xC808, 0xC408, 0xD201, 0xD201, 0xD301),
- },
- { .channel = 126,
- .freq = 5630, /* MHz */
- .unk2 = 3753,
- RADIOREGS(0x71, 0x02, 0x33, 0x04, 0x21, 0x01, 0x04, 0x0A,
- 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
- 0x80, 0x11, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xD008, 0xCC08, 0xC808, 0xD101, 0xD201, 0xD201),
- },
- { .channel = 128,
- .freq = 5640, /* MHz */
- .unk2 = 3760,
- RADIOREGS(0x71, 0x02, 0x34, 0x03, 0x1C, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xD408, 0xD008, 0xCC08, 0xD001, 0xD101, 0xD201),
- },
- { .channel = 130,
- .freq = 5650, /* MHz */
- .unk2 = 3767,
- RADIOREGS(0x71, 0x02, 0x35, 0x03, 0x1C, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xD808, 0xD408, 0xD008, 0xCF01, 0xD001, 0xD101),
- },
- { .channel = 132,
- .freq = 5660, /* MHz */
- .unk2 = 3773,
- RADIOREGS(0x71, 0x02, 0x36, 0x03, 0x16, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xDC08, 0xD808, 0xD408, 0xCE01, 0xCF01, 0xD001),
- },
- { .channel = 134,
- .freq = 5670, /* MHz */
- .unk2 = 3780,
- RADIOREGS(0x71, 0x02, 0x37, 0x03, 0x16, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xE008, 0xDC08, 0xD808, 0xCE01, 0xCE01, 0xCF01),
- },
- { .channel = 136,
- .freq = 5680, /* MHz */
- .unk2 = 3787,
- RADIOREGS(0x71, 0x02, 0x38, 0x03, 0x10, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xE408, 0xE008, 0xDC08, 0xCD01, 0xCE01, 0xCE01),
- },
- { .channel = 138,
- .freq = 5690, /* MHz */
- .unk2 = 3793,
- RADIOREGS(0x71, 0x02, 0x39, 0x03, 0x10, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xE808, 0xE408, 0xE008, 0xCC01, 0xCD01, 0xCE01),
- },
- { .channel = 140,
- .freq = 5700, /* MHz */
- .unk2 = 3800,
- RADIOREGS(0x71, 0x02, 0x3A, 0x02, 0x0A, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xEC08, 0xE808, 0xE408, 0xCB01, 0xCC01, 0xCD01),
- },
- { .channel = 142,
- .freq = 5710, /* MHz */
- .unk2 = 3807,
- RADIOREGS(0x71, 0x02, 0x3B, 0x02, 0x0A, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xF008, 0xEC08, 0xE808, 0xCA01, 0xCB01, 0xCC01),
- },
- { .channel = 144,
- .freq = 5720, /* MHz */
- .unk2 = 3813,
- RADIOREGS(0x71, 0x02, 0x3C, 0x02, 0x0A, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xF408, 0xF008, 0xEC08, 0xC901, 0xCA01, 0xCB01),
- },
- { .channel = 145,
- .freq = 5725, /* MHz */
- .unk2 = 3817,
- RADIOREGS(0x72, 0x04, 0x79, 0x02, 0x03, 0x01, 0x03, 0x14,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xF608, 0xF208, 0xEE08, 0xC901, 0xCA01, 0xCB01),
- },
- { .channel = 146,
- .freq = 5730, /* MHz */
- .unk2 = 3820,
- RADIOREGS(0x71, 0x02, 0x3D, 0x02, 0x0A, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xF808, 0xF408, 0xF008, 0xC901, 0xC901, 0xCA01),
- },
- { .channel = 147,
- .freq = 5735, /* MHz */
- .unk2 = 3823,
- RADIOREGS(0x72, 0x04, 0x7B, 0x02, 0x03, 0x01, 0x03, 0x14,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xFA08, 0xF608, 0xF208, 0xC801, 0xC901, 0xCA01),
- },
- { .channel = 148,
- .freq = 5740, /* MHz */
- .unk2 = 3827,
- RADIOREGS(0x71, 0x02, 0x3E, 0x02, 0x0A, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xFC08, 0xF808, 0xF408, 0xC801, 0xC901, 0xC901),
- },
- { .channel = 149,
- .freq = 5745, /* MHz */
- .unk2 = 3830,
- RADIOREGS(0x72, 0x04, 0x7D, 0x02, 0xFE, 0x00, 0x03, 0x14,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0xFE08, 0xFA08, 0xF608, 0xC801, 0xC801, 0xC901),
- },
- { .channel = 150,
- .freq = 5750, /* MHz */
- .unk2 = 3833,
- RADIOREGS(0x71, 0x02, 0x3F, 0x02, 0x0A, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0009, 0xFC08, 0xF808, 0xC701, 0xC801, 0xC901),
- },
- { .channel = 151,
- .freq = 5755, /* MHz */
- .unk2 = 3837,
- RADIOREGS(0x72, 0x04, 0x7F, 0x02, 0xFE, 0x00, 0x03, 0x14,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0209, 0xFE08, 0xFA08, 0xC701, 0xC801, 0xC801),
- },
- { .channel = 152,
- .freq = 5760, /* MHz */
- .unk2 = 3840,
- RADIOREGS(0x71, 0x02, 0x40, 0x02, 0x0A, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0409, 0x0009, 0xFC08, 0xC601, 0xC701, 0xC801),
- },
- { .channel = 153,
- .freq = 5765, /* MHz */
- .unk2 = 3843,
- RADIOREGS(0x72, 0x04, 0x81, 0x02, 0xF8, 0x00, 0x03, 0x14,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0609, 0x0209, 0xFE08, 0xC601, 0xC701, 0xC801),
- },
- { .channel = 154,
- .freq = 5770, /* MHz */
- .unk2 = 3847,
- RADIOREGS(0x71, 0x02, 0x41, 0x02, 0x0A, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0809, 0x0409, 0x0009, 0xC601, 0xC601, 0xC701),
- },
- { .channel = 155,
- .freq = 5775, /* MHz */
- .unk2 = 3850,
- RADIOREGS(0x72, 0x04, 0x83, 0x02, 0xF8, 0x00, 0x03, 0x14,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0A09, 0x0609, 0x0209, 0xC501, 0xC601, 0xC701),
- },
- { .channel = 156,
- .freq = 5780, /* MHz */
- .unk2 = 3853,
- RADIOREGS(0x71, 0x02, 0x42, 0x02, 0x0A, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0C09, 0x0809, 0x0409, 0xC501, 0xC601, 0xC601),
- },
- { .channel = 157,
- .freq = 5785, /* MHz */
- .unk2 = 3857,
- RADIOREGS(0x72, 0x04, 0x85, 0x02, 0xF2, 0x00, 0x03, 0x14,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x0E09, 0x0A09, 0x0609, 0xC401, 0xC501, 0xC601),
- },
- { .channel = 158,
- .freq = 5790, /* MHz */
- .unk2 = 3860,
- RADIOREGS(0x71, 0x02, 0x43, 0x02, 0x0A, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1009, 0x0C09, 0x0809, 0xC401, 0xC501, 0xC601),
- },
- { .channel = 159,
- .freq = 5795, /* MHz */
- .unk2 = 3863,
- RADIOREGS(0x72, 0x04, 0x87, 0x02, 0xF2, 0x00, 0x03, 0x14,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1209, 0x0E09, 0x0A09, 0xC401, 0xC401, 0xC501),
- },
- { .channel = 160,
- .freq = 5800, /* MHz */
- .unk2 = 3867,
- RADIOREGS(0x71, 0x02, 0x44, 0x01, 0x0A, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1409, 0x1009, 0x0C09, 0xC301, 0xC401, 0xC501),
- },
- { .channel = 161,
- .freq = 5805, /* MHz */
- .unk2 = 3870,
- RADIOREGS(0x72, 0x04, 0x89, 0x01, 0xED, 0x00, 0x03, 0x14,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1609, 0x1209, 0x0E09, 0xC301, 0xC401, 0xC401),
- },
- { .channel = 162,
- .freq = 5810, /* MHz */
- .unk2 = 3873,
- RADIOREGS(0x71, 0x02, 0x45, 0x01, 0x0A, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1809, 0x1409, 0x1009, 0xC201, 0xC301, 0xC401),
- },
- { .channel = 163,
- .freq = 5815, /* MHz */
- .unk2 = 3877,
- RADIOREGS(0x72, 0x04, 0x8B, 0x01, 0xED, 0x00, 0x03, 0x14,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1A09, 0x1609, 0x1209, 0xC201, 0xC301, 0xC401),
- },
- { .channel = 164,
- .freq = 5820, /* MHz */
- .unk2 = 3880,
- RADIOREGS(0x71, 0x02, 0x46, 0x01, 0x0A, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1C09, 0x1809, 0x1409, 0xC201, 0xC201, 0xC301),
- },
- { .channel = 165,
- .freq = 5825, /* MHz */
- .unk2 = 3883,
- RADIOREGS(0x72, 0x04, 0x8D, 0x01, 0xED, 0x00, 0x03, 0x14,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x1E09, 0x1A09, 0x1609, 0xC101, 0xC201, 0xC301),
- },
- { .channel = 166,
- .freq = 5830, /* MHz */
- .unk2 = 3887,
- RADIOREGS(0x71, 0x02, 0x47, 0x01, 0x0A, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x2009, 0x1C09, 0x1809, 0xC101, 0xC201, 0xC201),
- },
- { .channel = 168,
- .freq = 5840, /* MHz */
- .unk2 = 3893,
- RADIOREGS(0x71, 0x02, 0x48, 0x01, 0x0A, 0x01, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x2409, 0x2009, 0x1C09, 0xC001, 0xC101, 0xC201),
- },
- { .channel = 170,
- .freq = 5850, /* MHz */
- .unk2 = 3900,
- RADIOREGS(0x71, 0x02, 0x49, 0x01, 0xE0, 0x00, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x2809, 0x2409, 0x2009, 0xBF01, 0xC001, 0xC101),
- },
- { .channel = 172,
- .freq = 5860, /* MHz */
- .unk2 = 3907,
- RADIOREGS(0x71, 0x02, 0x4A, 0x01, 0xDE, 0x00, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x2C09, 0x2809, 0x2409, 0xBF01, 0xBF01, 0xC001),
- },
- { .channel = 174,
- .freq = 5870, /* MHz */
- .unk2 = 3913,
- RADIOREGS(0x71, 0x02, 0x4B, 0x00, 0xDB, 0x00, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x3009, 0x2C09, 0x2809, 0xBE01, 0xBF01, 0xBF01),
- },
- { .channel = 176,
- .freq = 5880, /* MHz */
- .unk2 = 3920,
- RADIOREGS(0x71, 0x02, 0x4C, 0x00, 0xD8, 0x00, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x3409, 0x3009, 0x2C09, 0xBD01, 0xBE01, 0xBF01),
- },
- { .channel = 178,
- .freq = 5890, /* MHz */
- .unk2 = 3927,
- RADIOREGS(0x71, 0x02, 0x4D, 0x00, 0xD6, 0x00, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x3809, 0x3409, 0x3009, 0xBC01, 0xBD01, 0xBE01),
- },
- { .channel = 180,
- .freq = 5900, /* MHz */
- .unk2 = 3933,
- RADIOREGS(0x71, 0x02, 0x4E, 0x00, 0xD3, 0x00, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x3C09, 0x3809, 0x3409, 0xBC01, 0xBC01, 0xBD01),
- },
- { .channel = 182,
- .freq = 5910, /* MHz */
- .unk2 = 3940,
- RADIOREGS(0x71, 0x02, 0x4F, 0x00, 0xD6, 0x00, 0x04, 0x0A,
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
- PHYREGS(0x4009, 0x3C09, 0x3809, 0xBB01, 0xBC01, 0xBC01),
- },
- { .channel = 1,
- .freq = 2412, /* MHz */
- .unk2 = 3216,
- RADIOREGS(0x73, 0x09, 0x6C, 0x0F, 0x00, 0x01, 0x07, 0x15,
- 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0D, 0x0C,
- 0x80, 0xFF, 0x88, 0x0D, 0x0C, 0x80),
- PHYREGS(0xC903, 0xC503, 0xC103, 0x3A04, 0x3F04, 0x4304),
- },
- { .channel = 2,
- .freq = 2417, /* MHz */
- .unk2 = 3223,
- RADIOREGS(0x73, 0x09, 0x71, 0x0F, 0x00, 0x01, 0x07, 0x15,
- 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0B,
- 0x80, 0xFF, 0x88, 0x0C, 0x0B, 0x80),
- PHYREGS(0xCB03, 0xC703, 0xC303, 0x3804, 0x3D04, 0x4104),
- },
- { .channel = 3,
- .freq = 2422, /* MHz */
- .unk2 = 3229,
- RADIOREGS(0x73, 0x09, 0x76, 0x0F, 0x00, 0x01, 0x07, 0x15,
- 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A,
- 0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80),
- PHYREGS(0xCD03, 0xC903, 0xC503, 0x3604, 0x3A04, 0x3F04),
- },
- { .channel = 4,
- .freq = 2427, /* MHz */
- .unk2 = 3236,
- RADIOREGS(0x73, 0x09, 0x7B, 0x0F, 0x00, 0x01, 0x07, 0x15,
- 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A,
- 0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80),
- PHYREGS(0xCF03, 0xCB03, 0xC703, 0x3404, 0x3804, 0x3D04),
- },
- { .channel = 5,
- .freq = 2432, /* MHz */
- .unk2 = 3243,
- RADIOREGS(0x73, 0x09, 0x80, 0x0F, 0x00, 0x01, 0x07, 0x15,
- 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x09,
- 0x80, 0xFF, 0x88, 0x0C, 0x09, 0x80),
- PHYREGS(0xD103, 0xCD03, 0xC903, 0x3104, 0x3604, 0x3A04),
- },
- { .channel = 6,
- .freq = 2437, /* MHz */
- .unk2 = 3249,
- RADIOREGS(0x73, 0x09, 0x85, 0x0F, 0x00, 0x01, 0x07, 0x15,
- 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0B, 0x08,
- 0x80, 0xFF, 0x88, 0x0B, 0x08, 0x80),
- PHYREGS(0xD303, 0xCF03, 0xCB03, 0x2F04, 0x3404, 0x3804),
- },
- { .channel = 7,
- .freq = 2442, /* MHz */
- .unk2 = 3256,
- RADIOREGS(0x73, 0x09, 0x8A, 0x0F, 0x00, 0x01, 0x07, 0x15,
- 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x07,
- 0x80, 0xFF, 0x88, 0x0A, 0x07, 0x80),
- PHYREGS(0xD503, 0xD103, 0xCD03, 0x2D04, 0x3104, 0x3604),
- },
- { .channel = 8,
- .freq = 2447, /* MHz */
- .unk2 = 3263,
- RADIOREGS(0x73, 0x09, 0x8F, 0x0F, 0x00, 0x01, 0x07, 0x15,
- 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x06,
- 0x80, 0xFF, 0x88, 0x0A, 0x06, 0x80),
- PHYREGS(0xD703, 0xD303, 0xCF03, 0x2B04, 0x2F04, 0x3404),
- },
- { .channel = 9,
- .freq = 2452, /* MHz */
- .unk2 = 3269,
- RADIOREGS(0x73, 0x09, 0x94, 0x0F, 0x00, 0x01, 0x07, 0x15,
- 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x09, 0x06,
- 0x80, 0xFF, 0x88, 0x09, 0x06, 0x80),
- PHYREGS(0xD903, 0xD503, 0xD103, 0x2904, 0x2D04, 0x3104),
- },
- { .channel = 10,
- .freq = 2457, /* MHz */
- .unk2 = 3276,
- RADIOREGS(0x73, 0x09, 0x99, 0x0F, 0x00, 0x01, 0x07, 0x15,
- 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x05,
- 0x80, 0xFF, 0x88, 0x08, 0x05, 0x80),
- PHYREGS(0xDB03, 0xD703, 0xD303, 0x2704, 0x2B04, 0x2F04),
- },
- { .channel = 11,
- .freq = 2462, /* MHz */
- .unk2 = 3283,
- RADIOREGS(0x73, 0x09, 0x9E, 0x0F, 0x00, 0x01, 0x07, 0x15,
- 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x04,
- 0x80, 0xFF, 0x88, 0x08, 0x04, 0x80),
- PHYREGS(0xDD03, 0xD903, 0xD503, 0x2404, 0x2904, 0x2D04),
- },
- { .channel = 12,
- .freq = 2467, /* MHz */
- .unk2 = 3289,
- RADIOREGS(0x73, 0x09, 0xA3, 0x0F, 0x00, 0x01, 0x07, 0x15,
- 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x03,
- 0x80, 0xFF, 0x88, 0x08, 0x03, 0x80),
- PHYREGS(0xDF03, 0xDB03, 0xD703, 0x2204, 0x2704, 0x2B04),
- },
- { .channel = 13,
- .freq = 2472, /* MHz */
- .unk2 = 3296,
- RADIOREGS(0x73, 0x09, 0xA8, 0x0F, 0x00, 0x01, 0x07, 0x15,
- 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x03,
- 0x80, 0xFF, 0x88, 0x07, 0x03, 0x80),
- PHYREGS(0xE103, 0xDD03, 0xD903, 0x2004, 0x2404, 0x2904),
- },
- { .channel = 14,
- .freq = 2484, /* MHz */
- .unk2 = 3312,
- RADIOREGS(0x73, 0x09, 0xB4, 0x0F, 0xFF, 0x01, 0x07, 0x15,
- 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x01,
- 0x80, 0xFF, 0x88, 0x07, 0x01, 0x80),
- PHYREGS(0xE603, 0xE203, 0xDE03, 0x1B04, 0x1F04, 0x2404),
- },
-};
-
-const struct b43_nphy_channeltab_entry_rev2 *
-b43_nphy_get_chantabent_rev2(struct b43_wldev *dev, u8 channel)
-{
- const struct b43_nphy_channeltab_entry_rev2 *e;
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab); i++) {
- e = &(b43_nphy_channeltab[i]);
- if (e->channel == channel)
- return e;
- }
-
- return NULL;
-}
-
-
static const u8 b43_ntab_adjustpower0[] = {
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h
index 8fc1da9f8fe5..4ec593ba3eef 100644
--- a/drivers/net/wireless/b43/tables_nphy.h
+++ b/drivers/net/wireless/b43/tables_nphy.h
@@ -3,7 +3,6 @@
#include <linux/types.h>
-
struct b43_phy_n_sfo_cfg {
u16 phy_bw1a;
u16 phy_bw2;
@@ -13,52 +12,6 @@ struct b43_phy_n_sfo_cfg {
u16 phy_bw6;
};
-struct b43_nphy_channeltab_entry_rev2 {
- /* The channel number */
- u8 channel;
- /* The channel frequency in MHz */
- u16 freq;
- /* An unknown value */
- u16 unk2;
- /* Radio register values on channelswitch */
- u8 radio_pll_ref;
- u8 radio_rf_pllmod0;
- u8 radio_rf_pllmod1;
- u8 radio_vco_captail;
- u8 radio_vco_cal1;
- u8 radio_vco_cal2;
- u8 radio_pll_lfc1;
- u8 radio_pll_lfr1;
- u8 radio_pll_lfc2;
- u8 radio_lgbuf_cenbuf;
- u8 radio_lgen_tune1;
- u8 radio_lgen_tune2;
- u8 radio_c1_lgbuf_atune;
- u8 radio_c1_lgbuf_gtune;
- u8 radio_c1_rx_rfr1;
- u8 radio_c1_tx_pgapadtn;
- u8 radio_c1_tx_mxbgtrim;
- u8 radio_c2_lgbuf_atune;
- u8 radio_c2_lgbuf_gtune;
- u8 radio_c2_rx_rfr1;
- u8 radio_c2_tx_pgapadtn;
- u8 radio_c2_tx_mxbgtrim;
- /* PHY register values on channelswitch */
- struct b43_phy_n_sfo_cfg phy_regs;
-};
-
-struct b43_nphy_channeltab_entry_rev3 {
- /* The channel number */
- u8 channel;
- /* The channel frequency in MHz */
- u16 freq;
- /* Radio register values on channelswitch */
- /* TODO */
- /* PHY register values on channelswitch */
- struct b43_phy_n_sfo_cfg phy_regs;
-};
-
-
struct b43_wldev;
struct nphy_txiqcal_ladder {
@@ -82,18 +35,12 @@ struct nphy_rf_control_override_rev3 {
u8 val_addr1;
};
-/* Upload the default register value table.
- * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz
- * table is uploaded. If "ignore_uploadflag" is true, we upload any value
- * and ignore the "UPLOAD" flag. */
-void b2055_upload_inittab(struct b43_wldev *dev,
- bool ghz5, bool ignore_uploadflag);
-
-
-/* Get the NPHY Channel Switch Table entry for a channel number.
+/* Get the NPHY Channel Switch Table entry for a channel.
* Returns NULL on failure to find an entry. */
const struct b43_nphy_channeltab_entry_rev2 *
b43_nphy_get_chantabent_rev2(struct b43_wldev *dev, u8 channel);
+const struct b43_nphy_channeltab_entry_rev3 *
+b43_nphy_get_chantabent_rev3(struct b43_wldev *dev, u16 freq);
/* The N-PHY tables. */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 1713f5f7a58b..67f18ecdb3bf 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -1623,6 +1623,7 @@ error:
static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
{
+ struct wiphy *wiphy = dev->wl->hw->wiphy;
const size_t hdr_len = sizeof(struct b43legacy_fw_header);
const __be32 *data;
unsigned int i;
@@ -1732,6 +1733,10 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
dev->fw.rev = fwrev;
dev->fw.patch = fwpatch;
+ snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "%u.%u",
+ dev->fw.rev, dev->fw.patch);
+ wiphy->hw_version = dev->dev->id.coreid;
+
return 0;
error:
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index e9d9d622a9b0..b7cb165d612b 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -2621,7 +2621,7 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id)
iface = netdev_priv(dev);
local = iface->local;
- /* Detect early interrupt before driver is fully configued */
+ /* Detect early interrupt before driver is fully configured */
spin_lock(&local->irq_init_lock);
if (!dev->base_addr) {
if (net_ratelimit()) {
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index a85e43a8d758..6038633ef361 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -1696,7 +1696,7 @@ static int prism2_request_scan(struct net_device *dev)
hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE,
HFA384X_ROAMING_FIRMWARE);
- return 0;
+ return ret;
}
#else /* !PRISM2_NO_STATION_MODES */
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 996e9d7d7586..61915f371416 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -1921,9 +1921,9 @@ static int ipw2100_net_init(struct net_device *dev)
bg_band->band = IEEE80211_BAND_2GHZ;
bg_band->n_channels = geo->bg_channels;
- bg_band->channels =
- kzalloc(geo->bg_channels *
- sizeof(struct ieee80211_channel), GFP_KERNEL);
+ bg_band->channels = kcalloc(geo->bg_channels,
+ sizeof(struct ieee80211_channel),
+ GFP_KERNEL);
if (!bg_band->channels) {
ipw2100_down(priv);
return -ENOMEM;
@@ -3056,9 +3056,9 @@ static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
packet = list_entry(element, struct ipw2100_tx_packet, list);
- IPW_DEBUG_TX("using TBD at virt=%p, phys=%p\n",
+ IPW_DEBUG_TX("using TBD at virt=%p, phys=%04X\n",
&txq->drv[txq->next],
- (void *)(txq->nic + txq->next *
+ (u32) (txq->nic + txq->next *
sizeof(struct ipw2100_bd)));
packet->index = txq->next;
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index cb2552a6777c..8d6ed5f6f46f 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -11467,9 +11467,13 @@ static int ipw_net_init(struct net_device *dev)
bg_band->band = IEEE80211_BAND_2GHZ;
bg_band->n_channels = geo->bg_channels;
- bg_band->channels =
- kzalloc(geo->bg_channels *
- sizeof(struct ieee80211_channel), GFP_KERNEL);
+ bg_band->channels = kcalloc(geo->bg_channels,
+ sizeof(struct ieee80211_channel),
+ GFP_KERNEL);
+ if (!bg_band->channels) {
+ rc = -ENOMEM;
+ goto out;
+ }
/* translate geo->bg to bg_band.channels */
for (i = 0; i < geo->bg_channels; i++) {
bg_band->channels[i].band = IEEE80211_BAND_2GHZ;
@@ -11502,9 +11506,13 @@ static int ipw_net_init(struct net_device *dev)
a_band->band = IEEE80211_BAND_5GHZ;
a_band->n_channels = geo->a_channels;
- a_band->channels =
- kzalloc(geo->a_channels *
- sizeof(struct ieee80211_channel), GFP_KERNEL);
+ a_band->channels = kcalloc(geo->a_channels,
+ sizeof(struct ieee80211_channel),
+ GFP_KERNEL);
+ if (!a_band->channels) {
+ rc = -ENOMEM;
+ goto out;
+ }
/* translate geo->bg to a_band.channels */
for (i = 0; i < geo->a_channels; i++) {
a_band->channels[i].band = IEEE80211_BAND_2GHZ;
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index a51e4da1bdfc..b82364258dc5 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -3,6 +3,9 @@ config IWLWIFI
depends on PCI && MAC80211
select FW_LOADER
+menu "Debugging Options"
+ depends on IWLWIFI
+
config IWLWIFI_DEBUG
bool "Enable full debugging output in iwlagn and iwl3945 drivers"
depends on IWLWIFI
@@ -36,6 +39,12 @@ config IWLWIFI_DEBUGFS
is a low-impact option that allows getting insight into the
driver's state at runtime.
+config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
+ bool "Experimental uCode support"
+ 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 IWLWIFI
@@ -53,6 +62,7 @@ config IWLWIFI_DEVICE_TRACING
If unsure, say Y so we can help you better when problems
occur.
+endmenu
config IWLAGN
tristate "Intel Wireless WiFi Next Gen AGN (iwlagn)"
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 728bb858ba97..63edbe2e557f 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_IWLAGN) += iwlagn.o
iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o
iwlagn-objs += iwl-agn-ucode.o iwl-agn-hcmd.o iwl-agn-tx.o
iwlagn-objs += iwl-agn-lib.o iwl-agn-rx.o iwl-agn-calib.o
+iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o
iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o
iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 0b779a41a142..db540910b110 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -50,14 +50,20 @@
/* Highest firmware API version supported */
#define IWL1000_UCODE_API_MAX 3
+#define IWL100_UCODE_API_MAX 5
/* Lowest firmware API version supported */
#define IWL1000_UCODE_API_MIN 1
+#define IWL100_UCODE_API_MIN 5
#define IWL1000_FW_PRE "iwlwifi-1000-"
#define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode"
#define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api)
+#define IWL100_FW_PRE "iwlwifi-100-"
+#define _IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode"
+#define IWL100_MODULE_FIRMWARE(api) _IWL100_MODULE_FIRMWARE(api)
+
/*
* For 1000, use advance thermal throttling critical temperature threshold,
@@ -120,17 +126,17 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
{
if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
- priv->cfg->num_of_queues =
+ priv->cfg->base_params->num_of_queues =
priv->cfg->mod_params->num_of_queues;
- priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+ priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
priv->hw_params.scd_bc_tbls_size =
- priv->cfg->num_of_queues *
+ 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;
- priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
+ 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;
@@ -145,8 +151,7 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
- if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
- priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
+ iwl1000_set_ct_threshold(priv);
/* Set initial sensitivity parameters */
/* Set initial calibration set */
@@ -189,9 +194,7 @@ static struct iwl_lib_ops iwl1000_lib = {
.update_chain_flags = iwl_update_chain_flags,
.apm_ops = {
.init = iwl_apm_init,
- .stop = iwl_apm_stop,
.config = iwl1000_nic_config,
- .set_pwr_src = iwl_set_pwr_src,
},
.eeprom_ops = {
.regulatory_bands = {
@@ -203,7 +206,6 @@ static struct iwl_lib_ops iwl1000_lib = {
EEPROM_REG_BAND_24_HT40_CHANNELS,
EEPROM_REG_BAND_52_HT40_CHANNELS
},
- .verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
.release_semaphore = iwlcore_eeprom_release_semaphore,
.calib_version = iwlagn_eeprom_calib_version,
@@ -214,21 +216,26 @@ static struct iwl_lib_ops iwl1000_lib = {
.config_ap = iwl_config_ap,
.temp_ops = {
.temperature = iwlagn_temperature,
- .set_ct_kill = iwl1000_set_ct_threshold,
},
.manage_ibss_station = iwlagn_manage_ibss_station,
- .update_bcast_station = iwl_update_bcast_station,
+ .update_bcast_stations = iwl_update_bcast_stations,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
.general_stats_read = iwl_ucode_general_stats_read,
.bt_stats_read = iwl_ucode_bt_stats_read,
+ .reply_tx_error = iwl_reply_tx_error_read,
},
.recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
.txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
+ .tt_ops = {
+ .lower_power_detection = iwl_tt_is_low_power_state,
+ .tt_power_mode = iwl_tt_current_power_mode,
+ .ct_kill_check = iwl_check_for_ct_kill,
+ }
};
static const struct iwl_ops iwl1000_ops = {
@@ -238,29 +245,16 @@ static const struct iwl_ops iwl1000_ops = {
.led = &iwlagn_led_ops,
};
-struct iwl_cfg iwl1000_bgn_cfg = {
- .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
- .fw_name_pre = IWL1000_FW_PRE,
- .ucode_api_max = IWL1000_UCODE_API_MAX,
- .ucode_api_min = IWL1000_UCODE_API_MIN,
- .sku = IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl1000_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
+static struct iwl_base_params iwl1000_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
- .mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_AB,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.set_l0s = true,
.use_bsm = false,
.max_ll_items = OTP_MAX_LL_ITEMS_1000,
.shadow_ram_support = false,
- .ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
@@ -271,6 +265,26 @@ struct iwl_cfg iwl1000_bgn_cfg = {
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
};
+static struct iwl_ht_params iwl1000_ht_params = {
+ .ht_greenfield_support = true,
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
+};
+
+struct iwl_cfg iwl1000_bgn_cfg = {
+ .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
+ .fw_name_pre = IWL1000_FW_PRE,
+ .ucode_api_max = IWL1000_UCODE_API_MAX,
+ .ucode_api_min = IWL1000_UCODE_API_MIN,
+ .sku = IWL_SKU_G|IWL_SKU_N,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_AB,
+ .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
+ .ops = &iwl1000_ops,
+ .mod_params = &iwlagn_mod_params,
+ .base_params = &iwl1000_base_params,
+ .ht_params = &iwl1000_ht_params,
+};
struct iwl_cfg iwl1000_bg_cfg = {
.name = "Intel(R) Centrino(R) Wireless-N 1000 BG",
@@ -278,30 +292,45 @@ struct iwl_cfg iwl1000_bg_cfg = {
.ucode_api_max = IWL1000_UCODE_API_MAX,
.ucode_api_min = IWL1000_UCODE_API_MIN,
.sku = IWL_SKU_G,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_AB,
+ .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
.ops = &iwl1000_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .mod_params = &iwlagn_mod_params,
+ .base_params = &iwl1000_base_params,
+};
+
+struct iwl_cfg iwl100_bgn_cfg = {
+ .name = "Intel(R) 100 Series 1x1 BGN",
+ .fw_name_pre = IWL100_FW_PRE,
+ .ucode_api_max = IWL100_UCODE_API_MAX,
+ .ucode_api_min = IWL100_UCODE_API_MIN,
+ .sku = IWL_SKU_G|IWL_SKU_N,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_A,
.eeprom_ver = EEPROM_1000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl1000_ops,
.mod_params = &iwlagn_mod_params,
+ .base_params = &iwl1000_base_params,
+ .ht_params = &iwl1000_ht_params,
+};
+
+struct iwl_cfg iwl100_bg_cfg = {
+ .name = "Intel(R) 100 Series 1x1 BG",
+ .fw_name_pre = IWL100_FW_PRE,
+ .ucode_api_max = IWL100_UCODE_API_MAX,
+ .ucode_api_min = IWL100_UCODE_API_MIN,
+ .sku = IWL_SKU_G,
.valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_AB,
- .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
- .set_l0s = true,
- .use_bsm = false,
- .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,
- .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
- .max_event_log_size = 128,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .valid_rx_ant = ANT_A,
+ .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
+ .ops = &iwl1000_ops,
+ .mod_params = &iwlagn_mod_params,
+ .base_params = &iwl1000_base_params,
};
MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL100_MODULE_FIRMWARE(IWL100_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index 7c731a793632..65b5834da28c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -62,7 +62,7 @@
*****************************************************************************/
/*
* Please use this file (iwl-3945-hw.h) only for hardware-related definitions.
- * Please use iwl-3945-commands.h for uCode API definitions.
+ * Please use iwl-commands.h for uCode API definitions.
* Please use iwl-3945.h for driver implementation definitions.
*/
@@ -226,6 +226,7 @@ struct iwl3945_eeprom {
/* 4 DATA + 1 CMD. There are 2 HCCA queues that are not used. */
#define IWL39_NUM_QUEUES 5
+#define IWL39_CMD_QUEUE_NUM 4
#define IWL_DEFAULT_TX_RETRY 15
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index 293e1dbc166c..1f3e7e34fbc7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -343,7 +343,7 @@ void iwl3945_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 s
int i;
IWL_DEBUG_INFO(priv, "enter\n");
- if (sta_id == priv->hw_params.bcast_sta_id)
+ if (sta_id == priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id)
goto out;
psta = (struct iwl3945_sta_priv *) sta->drv_priv;
@@ -933,7 +933,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
rcu_read_lock();
- sta = ieee80211_find_sta(priv->vif,
+ sta = ieee80211_find_sta(priv->contexts[IWL_RXON_CTX_BSS].vif,
priv->stations[sta_id].sta.sta.addr);
if (!sta) {
IWL_DEBUG_RATE(priv, "Unable to find station to initialize rate scaling.\n");
@@ -950,7 +950,8 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
switch (priv->band) {
case IEEE80211_BAND_2GHZ:
/* TODO: this always does G, not a regression */
- if (priv->active_rxon.flags & RXON_FLG_TGG_PROTECT_MSK) {
+ if (priv->contexts[IWL_RXON_CTX_BSS].active.flags &
+ RXON_FLG_TGG_PROTECT_MSK) {
rs_sta->tgg = 1;
rs_sta->expected_tpt = iwl3945_expected_tpt_g_prot;
} else
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 8ccfcd08218d..176e52577673 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -87,6 +87,15 @@ const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT_3945] = {
IWL_DECLARE_RATE_INFO(54, 48, INV, 48, INV, 48, INV),/* 54mbps */
};
+static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index)
+{
+ u8 rate = iwl3945_rates[rate_index].prev_ieee;
+
+ if (rate == IWL_RATE_INVALID)
+ rate = rate_index;
+ return rate;
+}
+
/* 1 = enable the iwl3945_disable_events() function */
#define IWL_EVT_DISABLE (0)
#define IWL_EVT_DISABLE_SIZE (1532/32)
@@ -245,7 +254,7 @@ int iwl3945_rs_next_rate(struct iwl_priv *priv, int rate)
break;
case IEEE80211_BAND_2GHZ:
if (!(priv->_3945.sta_supp_rates & IWL_OFDM_RATES_MASK) &&
- iwl_is_associated(priv)) {
+ iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
if (rate == IWL_RATE_11M_INDEX)
next_rate = IWL_RATE_5M_INDEX;
}
@@ -273,7 +282,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
struct iwl_queue *q = &txq->q;
struct iwl_tx_info *tx_info;
- BUG_ON(txq_id == IWL_CMD_QUEUE_NUM);
+ BUG_ON(txq_id == IWL39_CMD_QUEUE_NUM);
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)) {
@@ -285,7 +294,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
}
if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) &&
- (txq_id != IWL_CMD_QUEUE_NUM) &&
+ (txq_id != IWL39_CMD_QUEUE_NUM) &&
priv->mac80211_registered)
iwl_wake_queue(priv, txq_id);
}
@@ -339,7 +348,7 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
IWL_DEBUG_TX_REPLY(priv, "Tx queue reclaim %d\n", index);
iwl3945_tx_queue_reclaim(priv, txq_id, index);
- if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
+ if (status & TX_ABORT_REQUIRED_MSK)
IWL_ERR(priv, "TODO: Implement Tx ABORT REQUIRED!!!\n");
}
@@ -406,7 +415,7 @@ static bool iwl3945_good_plcp_health(struct iwl_priv *priv,
unsigned int plcp_msec;
unsigned long plcp_received_jiffies;
- if (priv->cfg->plcp_delta_threshold ==
+ if (priv->cfg->base_params->plcp_delta_threshold ==
IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
return rc;
@@ -432,7 +441,7 @@ static bool iwl3945_good_plcp_health(struct iwl_priv *priv,
if ((combined_plcp_delta > 0) &&
((combined_plcp_delta * 100) / plcp_msec) >
- priv->cfg->plcp_delta_threshold) {
+ priv->cfg->base_params->plcp_delta_threshold) {
/*
* if plcp_err exceed the threshold, the following
* data is printed in csv format:
@@ -444,7 +453,7 @@ static bool iwl3945_good_plcp_health(struct iwl_priv *priv,
*/
IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
"%u, %d, %u mSecs\n",
- priv->cfg->plcp_delta_threshold,
+ priv->cfg->base_params->plcp_delta_threshold,
le32_to_cpu(current_stat.rx.ofdm.plcp_err),
combined_plcp_delta, plcp_msec);
/*
@@ -760,7 +769,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
data_retry_limit = IWL_DEFAULT_TX_RETRY;
tx_cmd->data_retry_limit = data_retry_limit;
- if (tx_id >= IWL_CMD_QUEUE_NUM)
+ if (tx_id >= IWL39_CMD_QUEUE_NUM)
rts_retry_limit = 3;
else
rts_retry_limit = 7;
@@ -807,9 +816,12 @@ static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate)
return sta_id;
}
-static int iwl3945_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
+static void iwl3945_set_pwr_vmain(struct iwl_priv *priv)
{
- if (src == IWL_PWR_SRC_VAUX) {
+/*
+ * (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,
@@ -819,16 +831,14 @@ static int iwl3945_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
CSR_GPIO_IN_VAL_VAUX_PWR_SRC,
CSR_GPIO_IN_BIT_AUX_POWER, 5000);
}
- } else {
- iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
- APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
- ~APMG_PS_CTRL_MSK_PWR_SRC);
+ */
- iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC,
- CSR_GPIO_IN_BIT_AUX_POWER, 5000); /* uS */
- }
+ iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+ ~APMG_PS_CTRL_MSK_PWR_SRC);
- return 0;
+ iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC,
+ CSR_GPIO_IN_BIT_AUX_POWER, 5000); /* uS */
}
static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
@@ -909,7 +919,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
/* Tx queue(s) */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
- slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+ slots_num = (txq_id == IWL39_CMD_QUEUE_NUM) ?
TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
txq_id);
@@ -1022,9 +1032,7 @@ int iwl3945_hw_nic_init(struct iwl_priv *priv)
priv->cfg->ops->lib->apm_ops.init(priv);
spin_unlock_irqrestore(&priv->lock, flags);
- rc = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
- if (rc)
- return rc;
+ iwl3945_set_pwr_vmain(priv);
priv->cfg->ops->lib->apm_ops.config(priv);
@@ -1072,7 +1080,7 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv)
if (priv->txq)
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num;
txq_id++)
- if (txq_id == IWL_CMD_QUEUE_NUM)
+ if (txq_id == IWL39_CMD_QUEUE_NUM)
iwl_cmd_queue_free(priv);
else
iwl_tx_queue_free(priv, txq_id);
@@ -1439,17 +1447,18 @@ static int iwl3945_send_tx_power(struct iwl_priv *priv)
int rate_idx, i;
const struct iwl_channel_info *ch_info = NULL;
struct iwl3945_txpowertable_cmd txpower = {
- .channel = priv->active_rxon.channel,
+ .channel = priv->contexts[IWL_RXON_CTX_BSS].active.channel,
};
+ u16 chan;
+
+ chan = le16_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.channel);
txpower.band = (priv->band == IEEE80211_BAND_5GHZ) ? 0 : 1;
- ch_info = iwl_get_channel_info(priv,
- priv->band,
- le16_to_cpu(priv->active_rxon.channel));
+ ch_info = iwl_get_channel_info(priv, priv->band, chan);
if (!ch_info) {
IWL_ERR(priv,
"Failed to get channel info for channel %d [%d]\n",
- le16_to_cpu(priv->active_rxon.channel), priv->band);
+ chan, priv->band);
return -EINVAL;
}
@@ -1710,7 +1719,8 @@ int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
return 0;
}
-static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
+static int iwl3945_send_rxon_assoc(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
{
int rc = 0;
struct iwl_rx_packet *pkt;
@@ -1721,8 +1731,8 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
.flags = CMD_WANT_SKB,
.data = &rxon_assoc,
};
- const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
- const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+ const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
+ const struct iwl_rxon_cmd *rxon2 = &ctx->active;
if ((rxon1->flags == rxon2->flags) &&
(rxon1->filter_flags == rxon2->filter_flags) &&
@@ -1732,10 +1742,10 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
return 0;
}
- rxon_assoc.flags = priv->staging_rxon.flags;
- rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
- rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
- rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+ rxon_assoc.flags = ctx->staging.flags;
+ rxon_assoc.filter_flags = ctx->staging.filter_flags;
+ rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
+ rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
rxon_assoc.reserved = 0;
rc = iwl_send_cmd_sync(priv, &cmd);
@@ -1761,14 +1771,13 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
* function correctly transitions out of the RXON_ASSOC_MSK state if
* a HW tune is required based on the RXON structure changes.
*/
-static int iwl3945_commit_rxon(struct iwl_priv *priv)
+int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
{
/* cast away the const for active_rxon in this function */
- struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
- struct iwl3945_rxon_cmd *staging_rxon = (void *)&priv->staging_rxon;
+ struct iwl3945_rxon_cmd *active_rxon = (void *)&ctx->active;
+ struct iwl3945_rxon_cmd *staging_rxon = (void *)&ctx->staging;
int rc = 0;
- bool new_assoc =
- !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK);
+ bool new_assoc = !!(staging_rxon->filter_flags & RXON_FILTER_ASSOC_MSK);
if (!iwl_is_alive(priv))
return -1;
@@ -1781,7 +1790,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK);
staging_rxon->flags |= iwl3945_get_antenna_flags(priv);
- rc = iwl_check_rxon_cmd(priv);
+ rc = iwl_check_rxon_cmd(priv, ctx);
if (rc) {
IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
return -EINVAL;
@@ -1790,8 +1799,9 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
/* If we don't need to send a full RXON, we can use
* iwl3945_rxon_assoc_cmd which is used to reconfigure filter
* and other flags for the current radio configuration. */
- if (!iwl_full_rxon_required(priv)) {
- rc = iwl_send_rxon_assoc(priv);
+ if (!iwl_full_rxon_required(priv, &priv->contexts[IWL_RXON_CTX_BSS])) {
+ rc = iwl_send_rxon_assoc(priv,
+ &priv->contexts[IWL_RXON_CTX_BSS]);
if (rc) {
IWL_ERR(priv, "Error setting RXON_ASSOC "
"configuration (%d).\n", rc);
@@ -1807,7 +1817,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
* an RXON_ASSOC and the new config wants the associated mask enabled,
* we must clear the associated from the active configuration
* before we apply the new config */
- if (iwl_is_associated(priv) && new_assoc) {
+ if (iwl_is_associated(priv, IWL_RXON_CTX_BSS) && new_assoc) {
IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n");
active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
@@ -1819,7 +1829,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
active_rxon->reserved5 = 0;
rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
sizeof(struct iwl3945_rxon_cmd),
- &priv->active_rxon);
+ &priv->contexts[IWL_RXON_CTX_BSS].active);
/* If the mask clearing failed then we set
* active_rxon back to what it was previously */
@@ -1829,8 +1839,9 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
"configuration (%d).\n", rc);
return rc;
}
- iwl_clear_ucode_stations(priv);
- iwl_restore_stations(priv);
+ iwl_clear_ucode_stations(priv,
+ &priv->contexts[IWL_RXON_CTX_BSS]);
+ iwl_restore_stations(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
}
IWL_DEBUG_INFO(priv, "Sending RXON\n"
@@ -1848,7 +1859,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
staging_rxon->reserved4 = 0;
staging_rxon->reserved5 = 0;
- iwl_set_rxon_hwcrypto(priv, !iwl3945_mod_params.sw_crypto);
+ iwl_set_rxon_hwcrypto(priv, ctx, !iwl3945_mod_params.sw_crypto);
/* Apply the new configuration */
rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
@@ -1862,8 +1873,9 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
if (!new_assoc) {
- iwl_clear_ucode_stations(priv);
- iwl_restore_stations(priv);
+ iwl_clear_ucode_stations(priv,
+ &priv->contexts[IWL_RXON_CTX_BSS]);
+ iwl_restore_stations(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
}
/* If we issue a new RXON command which required a tune then we must
@@ -2295,6 +2307,32 @@ static u16 iwl3945_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
return (u16)sizeof(struct iwl3945_addsta_cmd);
}
+static int iwl3945_add_bssid_station(struct iwl_priv *priv,
+ const u8 *addr, u8 *sta_id_r)
+{
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+ int ret;
+ u8 sta_id;
+ unsigned long flags;
+
+ if (sta_id_r)
+ *sta_id_r = IWL_INVALID_STATION;
+
+ ret = iwl_add_station_common(priv, ctx, addr, 0, NULL, &sta_id);
+ if (ret) {
+ IWL_ERR(priv, "Unable to add station %pM\n", addr);
+ return ret;
+ }
+
+ if (sta_id_r)
+ *sta_id_r = sta_id;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].used |= IWL_STA_LOCAL;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return 0;
+}
static int iwl3945_manage_ibss_station(struct iwl_priv *priv,
struct ieee80211_vif *vif, bool add)
{
@@ -2302,8 +2340,8 @@ static int iwl3945_manage_ibss_station(struct iwl_priv *priv,
int ret;
if (add) {
- ret = iwl_add_bssid_station(priv, vif->bss_conf.bssid, false,
- &vif_priv->ibss_bssid_sta_id);
+ ret = iwl3945_add_bssid_station(priv, vif->bss_conf.bssid,
+ &vif_priv->ibss_bssid_sta_id);
if (ret)
return ret;
@@ -2366,7 +2404,7 @@ int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
* 1M CCK rates */
if (!(priv->_3945.sta_supp_rates & IWL_OFDM_RATES_MASK) &&
- iwl_is_associated(priv)) {
+ iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
index = IWL_FIRST_CCK_RATE;
for (i = IWL_RATE_6M_INDEX_TABLE;
@@ -2414,14 +2452,16 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
}
/* Assign number of Usable TX queues */
- priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+ priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd);
priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_3K);
priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
priv->hw_params.max_stations = IWL3945_STATION_COUNT;
- priv->hw_params.bcast_sta_id = IWL3945_BROADCAST_ID;
+ priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWL3945_BROADCAST_ID;
+
+ priv->sta_key_max_num = STA_KEY_MAX_NUM;
priv->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR;
priv->hw_params.max_beacon_itrvl = IWL39_MAX_UCODE_BEACON_INTERVAL;
@@ -2439,7 +2479,8 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl_priv *priv,
tx_beacon_cmd = (struct iwl3945_tx_beacon_cmd *)&frame->u;
memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
- tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
+ tx_beacon_cmd->tx.sta_id =
+ priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id;
tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
frame_size = iwl3945_fill_beacon_frame(priv,
@@ -2663,9 +2704,7 @@ static struct iwl_lib_ops iwl3945_lib = {
.dump_nic_error_log = iwl3945_dump_nic_error_log,
.apm_ops = {
.init = iwl3945_apm_init,
- .stop = iwl_apm_stop,
.config = iwl3945_nic_config,
- .set_pwr_src = iwl3945_set_pwr_src,
},
.eeprom_ops = {
.regulatory_bands = {
@@ -2677,7 +2716,6 @@ static struct iwl_lib_ops iwl3945_lib = {
EEPROM_REGULATORY_BAND_NO_HT40,
EEPROM_REGULATORY_BAND_NO_HT40,
},
- .verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwl3945_eeprom_acquire_semaphore,
.release_semaphore = iwl3945_eeprom_release_semaphore,
.query_addr = iwlcore_eeprom_query_addr,
@@ -2703,6 +2741,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
.build_addsta_hcmd = iwl3945_build_addsta_hcmd,
.tx_cmd_protection = iwlcore_tx_cmd_protection,
.request_scan = iwl3945_request_scan,
+ .post_scan = iwl3945_post_scan,
};
static const struct iwl_ops iwl3945_ops = {
@@ -2712,22 +2751,13 @@ static const struct iwl_ops iwl3945_ops = {
.led = &iwl3945_led_ops,
};
-static struct iwl_cfg iwl3945_bg_cfg = {
- .name = "3945BG",
- .fw_name_pre = IWL3945_FW_PRE,
- .ucode_api_max = IWL3945_UCODE_API_MAX,
- .ucode_api_min = IWL3945_UCODE_API_MIN,
- .sku = IWL_SKU_G,
+static struct iwl_base_params iwl3945_base_params = {
.eeprom_size = IWL3945_EEPROM_IMG_SIZE,
- .eeprom_ver = EEPROM_3945_EEPROM_VERSION,
- .ops = &iwl3945_ops,
.num_of_queues = IWL39_NUM_QUEUES,
- .mod_params = &iwl3945_mod_params,
.pll_cfg_val = CSR39_ANA_PLL_CFG_VAL,
.set_l0s = false,
.use_bsm = true,
.use_isr_legacy = true,
- .ht_greenfield_support = false,
.led_compensation = 64,
.broken_powersave = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
@@ -2736,25 +2766,28 @@ static struct iwl_cfg iwl3945_bg_cfg = {
.tx_power_by_driver = true,
};
+static struct iwl_cfg iwl3945_bg_cfg = {
+ .name = "3945BG",
+ .fw_name_pre = IWL3945_FW_PRE,
+ .ucode_api_max = IWL3945_UCODE_API_MAX,
+ .ucode_api_min = IWL3945_UCODE_API_MIN,
+ .sku = IWL_SKU_G,
+ .eeprom_ver = EEPROM_3945_EEPROM_VERSION,
+ .ops = &iwl3945_ops,
+ .mod_params = &iwl3945_mod_params,
+ .base_params = &iwl3945_base_params,
+};
+
static struct iwl_cfg iwl3945_abg_cfg = {
.name = "3945ABG",
.fw_name_pre = IWL3945_FW_PRE,
.ucode_api_max = IWL3945_UCODE_API_MAX,
.ucode_api_min = IWL3945_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G,
- .eeprom_size = IWL3945_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_3945_EEPROM_VERSION,
.ops = &iwl3945_ops,
- .num_of_queues = IWL39_NUM_QUEUES,
.mod_params = &iwl3945_mod_params,
- .use_isr_legacy = true,
- .ht_greenfield_support = false,
- .led_compensation = 64,
- .broken_powersave = true,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
- .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
- .max_event_log_size = 512,
- .tx_power_by_driver = true,
+ .base_params = &iwl3945_base_params,
};
DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index bb2aeebf3652..09391f0ee61f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -138,8 +138,6 @@ enum iwl3945_antenna {
#define DEFAULT_SHORT_RETRY_LIMIT 7U
#define DEFAULT_LONG_RETRY_LIMIT 4U
-#include "iwl-agn-rs.h"
-
#define IWL_TX_FIFO_AC0 0
#define IWL_TX_FIFO_AC1 1
#define IWL_TX_FIFO_AC2 2
@@ -271,6 +269,9 @@ extern void iwl3945_post_associate(struct iwl_priv *priv,
extern void iwl3945_config_ap(struct iwl_priv *priv,
struct ieee80211_vif *vif);
+extern int iwl3945_commit_rxon(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx);
+
/**
* iwl3945_hw_find_station - Find station id for a given BSSID
* @bssid: MAC address of station ID to find
@@ -295,7 +296,11 @@ extern const struct iwl_channel_info *iwl3945_get_channel_info(
extern int iwl3945_rs_next_rate(struct iwl_priv *priv, int rate);
/* scanning */
-void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
+int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
+void iwl3945_post_scan(struct iwl_priv *priv);
+
+/* rates */
+extern const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT_3945];
/* Requires full declaration of iwl_priv before including */
#include "iwl-io.h"
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index d92b72909233..b207e3e9299f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -43,7 +43,7 @@
#include "iwl-core.h"
#include "iwl-io.h"
#include "iwl-helpers.h"
-#include "iwl-calib.h"
+#include "iwl-agn-calib.h"
#include "iwl-sta.h"
#include "iwl-agn-led.h"
#include "iwl-agn.h"
@@ -347,7 +347,7 @@ static void iwl4965_chain_noise_reset(struct iwl_priv *priv)
struct iwl_chain_noise_data *data = &(priv->chain_noise_data);
if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
- iwl_is_associated(priv)) {
+ iwl_is_any_associated(priv)) {
struct iwl_calib_diff_gain_cmd cmd;
/* clear data for chain noise calibration algorithm */
@@ -576,7 +576,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
/* Activate all Tx DMA/FIFO channels */
priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 6));
- iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+ iwl4965_set_wr_ptrs(priv, IWL_DEFAULT_CMD_QUEUE_NUM, 0);
/* make sure all queue are not stopped */
memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
@@ -587,6 +587,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
priv->txq_ctx_active_msk = 0;
/* Map each Tx/cmd queue to its corresponding fifo */
BUILD_BUG_ON(ARRAY_SIZE(default_queue_to_tx_fifo) != 7);
+
for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) {
int ac = default_queue_to_tx_fifo[i];
@@ -646,17 +647,17 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
{
if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
priv->cfg->mod_params->num_of_queues <= IWL49_NUM_QUEUES)
- priv->cfg->num_of_queues =
+ priv->cfg->base_params->num_of_queues =
priv->cfg->mod_params->num_of_queues;
- priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+ priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM;
priv->hw_params.scd_bc_tbls_size =
- priv->cfg->num_of_queues *
+ priv->cfg->base_params->num_of_queues *
sizeof(struct iwl4965_scd_bc_tbl);
priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
priv->hw_params.max_stations = IWL4965_STATION_COUNT;
- priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID;
+ priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWL4965_BROADCAST_ID;
priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE;
priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE;
priv->hw_params.max_bsm_size = BSM_SRAM_SIZE;
@@ -668,8 +669,8 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
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;
- if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
- priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
+
+ iwl4965_set_ct_threshold(priv);
priv->hw_params.sens = &iwl4965_sensitivity;
priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
@@ -1374,6 +1375,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv)
u8 band = 0;
bool is_ht40 = false;
u8 ctrl_chan_high = 0;
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
if (test_bit(STATUS_SCANNING, &priv->status)) {
/* If this gets hit a lot, switch it to a BUG() and catch
@@ -1385,17 +1387,16 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv)
band = priv->band == IEEE80211_BAND_2GHZ;
- is_ht40 = is_ht40_channel(priv->active_rxon.flags);
+ is_ht40 = is_ht40_channel(ctx->active.flags);
- if (is_ht40 &&
- (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
+ if (is_ht40 && (ctx->active.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
ctrl_chan_high = 1;
cmd.band = band;
- cmd.channel = priv->active_rxon.channel;
+ cmd.channel = ctx->active.channel;
ret = iwl4965_fill_txpower_tbl(priv, band,
- le16_to_cpu(priv->active_rxon.channel),
+ le16_to_cpu(ctx->active.channel),
is_ht40, ctrl_chan_high, &cmd.tx_power);
if (ret)
goto out;
@@ -1406,12 +1407,13 @@ out:
return ret;
}
-static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
+static int iwl4965_send_rxon_assoc(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
{
int ret = 0;
struct iwl4965_rxon_assoc_cmd rxon_assoc;
- const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
- const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+ const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
+ const struct iwl_rxon_cmd *rxon2 = &ctx->active;
if ((rxon1->flags == rxon2->flags) &&
(rxon1->filter_flags == rxon2->filter_flags) &&
@@ -1426,16 +1428,16 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
return 0;
}
- rxon_assoc.flags = priv->staging_rxon.flags;
- rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
- rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
- rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+ rxon_assoc.flags = ctx->staging.flags;
+ rxon_assoc.filter_flags = ctx->staging.filter_flags;
+ rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
+ rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
rxon_assoc.reserved = 0;
rxon_assoc.ofdm_ht_single_stream_basic_rates =
- priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
+ ctx->staging.ofdm_ht_single_stream_basic_rates;
rxon_assoc.ofdm_ht_dual_stream_basic_rates =
- priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
- rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
+ ctx->staging.ofdm_ht_dual_stream_basic_rates;
+ rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
sizeof(rxon_assoc), &rxon_assoc, NULL);
@@ -1448,6 +1450,7 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
struct ieee80211_channel_switch *ch_switch)
{
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
int rc;
u8 band = 0;
bool is_ht40 = false;
@@ -1458,22 +1461,22 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
u16 ch;
u32 tsf_low;
u8 switch_count;
- u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
- struct ieee80211_vif *vif = priv->vif;
+ u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
+ struct ieee80211_vif *vif = ctx->vif;
band = priv->band == IEEE80211_BAND_2GHZ;
- is_ht40 = is_ht40_channel(priv->staging_rxon.flags);
+ is_ht40 = is_ht40_channel(ctx->staging.flags);
if (is_ht40 &&
- (priv->staging_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
+ (ctx->staging.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
ctrl_chan_high = 1;
cmd.band = band;
cmd.expect_beacon = 0;
- ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
+ ch = ch_switch->channel->hw_value;
cmd.channel = cpu_to_le16(ch);
- cmd.rxon_flags = priv->staging_rxon.flags;
- cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
+ cmd.rxon_flags = ctx->staging.flags;
+ cmd.rxon_filter_flags = ctx->staging.filter_flags;
switch_count = ch_switch->count;
tsf_low = ch_switch->timestamp & 0x0ffffffff;
/*
@@ -1508,7 +1511,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
cmd.expect_beacon = is_channel_radar(ch_info);
else {
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
- priv->active_rxon.channel, ch);
+ ctx->active.channel, ch);
return -EFAULT;
}
@@ -1721,13 +1724,13 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
u16 ssn_idx, u8 tx_fifo)
{
if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
- (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
- <= txq_id)) {
+ (IWL49_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, IWL49_FIRST_AMPDU_QUEUE,
IWL49_FIRST_AMPDU_QUEUE +
- priv->cfg->num_of_ampdu_queues - 1);
+ priv->cfg->base_params->num_of_ampdu_queues - 1);
return -EINVAL;
}
@@ -1789,13 +1792,13 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
int ret;
if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
- (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
- <= txq_id)) {
+ (IWL49_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, IWL49_FIRST_AMPDU_QUEUE,
IWL49_FIRST_AMPDU_QUEUE +
- priv->cfg->num_of_ampdu_queues - 1);
+ priv->cfg->base_params->num_of_ampdu_queues - 1);
return -EINVAL;
}
@@ -2007,7 +2010,7 @@ static u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
start = IWL_STA_ID;
if (is_broadcast_ether_addr(addr))
- return priv->hw_params.bcast_sta_id;
+ return priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id;
spin_lock_irqsave(&priv->sta_lock, flags);
for (i = start; i < priv->hw_params.max_stations; i++)
@@ -2213,11 +2216,23 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
static struct iwl_hcmd_ops iwl4965_hcmd = {
.rxon_assoc = iwl4965_send_rxon_assoc,
- .commit_rxon = iwl_commit_rxon,
- .set_rxon_chain = iwl_set_rxon_chain,
+ .commit_rxon = iwlagn_commit_rxon,
+ .set_rxon_chain = iwlagn_set_rxon_chain,
.send_bt_config = iwl_send_bt_config,
};
+static void iwl4965_post_scan(struct iwl_priv *priv)
+{
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+
+ /*
+ * Since setting the RXON may have been deferred while
+ * performing the scan, fire one off if needed
+ */
+ if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
+ iwlcore_commit_rxon(priv, ctx);
+}
+
static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.get_hcmd_size = iwl4965_get_hcmd_size,
.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
@@ -2226,6 +2241,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.tx_cmd_protection = iwlcore_tx_cmd_protection,
.calc_rssi = iwl4965_calc_rssi,
.request_scan = iwlagn_request_scan,
+ .post_scan = iwl4965_post_scan,
};
static struct iwl_lib_ops iwl4965_lib = {
@@ -2250,9 +2266,7 @@ static struct iwl_lib_ops iwl4965_lib = {
.set_channel_switch = iwl4965_hw_channel_switch,
.apm_ops = {
.init = iwl_apm_init,
- .stop = iwl_apm_stop,
.config = iwl4965_nic_config,
- .set_pwr_src = iwl_set_pwr_src,
},
.eeprom_ops = {
.regulatory_bands = {
@@ -2264,7 +2278,6 @@ static struct iwl_lib_ops iwl4965_lib = {
EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS,
EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS
},
- .verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
.release_semaphore = iwlcore_eeprom_release_semaphore,
.calib_version = iwl4965_eeprom_calib_version,
@@ -2277,15 +2290,15 @@ static struct iwl_lib_ops iwl4965_lib = {
.isr = iwl_isr_legacy,
.temp_ops = {
.temperature = iwl4965_temperature_calib,
- .set_ct_kill = iwl4965_set_ct_threshold,
},
.manage_ibss_station = iwlagn_manage_ibss_station,
- .update_bcast_station = iwl_update_bcast_station,
+ .update_bcast_stations = iwl_update_bcast_stations,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
.general_stats_read = iwl_ucode_general_stats_read,
.bt_stats_read = iwl_ucode_bt_stats_read,
+ .reply_tx_error = iwl_reply_tx_error_read,
},
.recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
@@ -2298,26 +2311,14 @@ static const struct iwl_ops iwl4965_ops = {
.led = &iwlagn_led_ops,
};
-struct iwl_cfg iwl4965_agn_cfg = {
- .name = "Intel(R) Wireless WiFi Link 4965AGN",
- .fw_name_pre = IWL4965_FW_PRE,
- .ucode_api_max = IWL4965_UCODE_API_MAX,
- .ucode_api_min = IWL4965_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+static struct iwl_base_params iwl4965_base_params = {
.eeprom_size = IWL4965_EEPROM_IMG_SIZE,
- .eeprom_ver = EEPROM_4965_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION,
- .ops = &iwl4965_ops,
.num_of_queues = IWL49_NUM_QUEUES,
.num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
- .mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_ABC,
.pll_cfg_val = 0,
.set_l0s = true,
.use_bsm = true,
.use_isr_legacy = true,
- .ht_greenfield_support = false,
.broken_powersave = true,
.led_compensation = 61,
.chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
@@ -2329,6 +2330,21 @@ struct iwl_cfg iwl4965_agn_cfg = {
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
+};
+
+struct iwl_cfg iwl4965_agn_cfg = {
+ .name = "Intel(R) Wireless WiFi Link 4965AGN",
+ .fw_name_pre = IWL4965_FW_PRE,
+ .ucode_api_max = IWL4965_UCODE_API_MAX,
+ .ucode_api_min = IWL4965_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_ABC,
+ .eeprom_ver = EEPROM_4965_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION,
+ .ops = &iwl4965_ops,
+ .mod_params = &iwlagn_mod_params,
+ .base_params = &iwl4965_base_params,
/*
* Force use of chains B and C for scan RX on 5 GHz band
* because the device has off-channel reception on chain A.
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
index 146e6431ae95..3975e45e7500 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
@@ -62,7 +62,7 @@
*****************************************************************************/
/*
* Please use this file (iwl-5000-hw.h) only for hardware-related definitions.
- * Use iwl-5000-commands.h for uCode API definitions.
+ * Use iwl-commands.h for uCode API definitions.
*/
#ifndef __iwl_5000_hw_h__
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 48bdcd8d2e94..fd9fbc93ea1b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -170,17 +170,17 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
{
if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
- priv->cfg->num_of_queues =
+ priv->cfg->base_params->num_of_queues =
priv->cfg->mod_params->num_of_queues;
- priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+ priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
priv->hw_params.scd_bc_tbls_size =
- priv->cfg->num_of_queues *
+ 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;
- priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
+ 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;
@@ -195,8 +195,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
- if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
- priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
+ iwl5000_set_ct_threshold(priv);
/* Set initial sensitivity parameters */
/* Set initial calibration set */
@@ -217,17 +216,17 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
{
if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
- priv->cfg->num_of_queues =
+ priv->cfg->base_params->num_of_queues =
priv->cfg->mod_params->num_of_queues;
- priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+ priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
priv->hw_params.scd_bc_tbls_size =
- priv->cfg->num_of_queues *
+ 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;
- priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
+ 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;
@@ -242,8 +241,7 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
- if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
- priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
+ iwl5150_set_ct_threshold(priv);
/* Set initial sensitivity parameters */
/* Set initial calibration set */
@@ -275,14 +273,19 @@ static void iwl5150_temperature(struct iwl_priv *priv)
static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
struct ieee80211_channel_switch *ch_switch)
{
+ /*
+ * MULTI-FIXME
+ * See iwl_mac_channel_switch.
+ */
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
struct iwl5000_channel_switch_cmd cmd;
const struct iwl_channel_info *ch_info;
u32 switch_time_in_usec, ucode_switch_time;
u16 ch;
u32 tsf_low;
u8 switch_count;
- u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
- struct ieee80211_vif *vif = priv->vif;
+ u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
+ struct ieee80211_vif *vif = ctx->vif;
struct iwl_host_cmd hcmd = {
.id = REPLY_CHANNEL_SWITCH,
.len = sizeof(cmd),
@@ -291,12 +294,12 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
};
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
- ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
+ ch = ch_switch->channel->hw_value;
IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
- priv->active_rxon.channel, ch);
+ ctx->active.channel, ch);
cmd.channel = cpu_to_le16(ch);
- cmd.rxon_flags = priv->staging_rxon.flags;
- cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
+ cmd.rxon_flags = ctx->staging.flags;
+ cmd.rxon_filter_flags = ctx->staging.filter_flags;
switch_count = ch_switch->count;
tsf_low = ch_switch->timestamp & 0x0ffffffff;
/*
@@ -331,7 +334,7 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
cmd.expect_beacon = is_channel_radar(ch_info);
else {
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
- priv->active_rxon.channel, ch);
+ ctx->active.channel, ch);
return -EFAULT;
}
priv->switch_rxon.channel = cmd.channel;
@@ -365,9 +368,7 @@ static struct iwl_lib_ops iwl5000_lib = {
.set_channel_switch = iwl5000_hw_channel_switch,
.apm_ops = {
.init = iwl_apm_init,
- .stop = iwl_apm_stop,
.config = iwl5000_nic_config,
- .set_pwr_src = iwl_set_pwr_src,
},
.eeprom_ops = {
.regulatory_bands = {
@@ -379,7 +380,6 @@ static struct iwl_lib_ops iwl5000_lib = {
EEPROM_REG_BAND_24_HT40_CHANNELS,
EEPROM_REG_BAND_52_HT40_CHANNELS
},
- .verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
.release_semaphore = iwlcore_eeprom_release_semaphore,
.calib_version = iwlagn_eeprom_calib_version,
@@ -390,21 +390,26 @@ static struct iwl_lib_ops iwl5000_lib = {
.config_ap = iwl_config_ap,
.temp_ops = {
.temperature = iwlagn_temperature,
- .set_ct_kill = iwl5000_set_ct_threshold,
},
.manage_ibss_station = iwlagn_manage_ibss_station,
- .update_bcast_station = iwl_update_bcast_station,
+ .update_bcast_stations = iwl_update_bcast_stations,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
.general_stats_read = iwl_ucode_general_stats_read,
.bt_stats_read = iwl_ucode_bt_stats_read,
+ .reply_tx_error = iwl_reply_tx_error_read,
},
.recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
.txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
+ .tt_ops = {
+ .lower_power_detection = iwl_tt_is_low_power_state,
+ .tt_power_mode = iwl_tt_current_power_mode,
+ .ct_kill_check = iwl_check_for_ct_kill,
+ }
};
static struct iwl_lib_ops iwl5150_lib = {
@@ -431,9 +436,7 @@ static struct iwl_lib_ops iwl5150_lib = {
.set_channel_switch = iwl5000_hw_channel_switch,
.apm_ops = {
.init = iwl_apm_init,
- .stop = iwl_apm_stop,
.config = iwl5000_nic_config,
- .set_pwr_src = iwl_set_pwr_src,
},
.eeprom_ops = {
.regulatory_bands = {
@@ -445,7 +448,6 @@ static struct iwl_lib_ops iwl5150_lib = {
EEPROM_REG_BAND_24_HT40_CHANNELS,
EEPROM_REG_BAND_52_HT40_CHANNELS
},
- .verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
.release_semaphore = iwlcore_eeprom_release_semaphore,
.calib_version = iwlagn_eeprom_calib_version,
@@ -456,20 +458,26 @@ static struct iwl_lib_ops iwl5150_lib = {
.config_ap = iwl_config_ap,
.temp_ops = {
.temperature = iwl5150_temperature,
- .set_ct_kill = iwl5150_set_ct_threshold,
},
.manage_ibss_station = iwlagn_manage_ibss_station,
- .update_bcast_station = iwl_update_bcast_station,
+ .update_bcast_stations = iwl_update_bcast_stations,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
.general_stats_read = iwl_ucode_general_stats_read,
+ .bt_stats_read = iwl_ucode_bt_stats_read,
+ .reply_tx_error = iwl_reply_tx_error_read,
},
.recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
.txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
+ .tt_ops = {
+ .lower_power_detection = iwl_tt_is_low_power_state,
+ .tt_power_mode = iwl_tt_current_power_mode,
+ .ct_kill_check = iwl_check_for_ct_kill,
+ }
};
static const struct iwl_ops iwl5000_ops = {
@@ -486,27 +494,14 @@ static const struct iwl_ops iwl5150_ops = {
.led = &iwlagn_led_ops,
};
-struct iwl_cfg iwl5300_agn_cfg = {
- .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
- .fw_name_pre = IWL5000_FW_PRE,
- .ucode_api_max = IWL5000_UCODE_API_MAX,
- .ucode_api_min = IWL5000_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl5000_ops,
+static struct iwl_base_params iwl5000_base_params = {
.eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
- .mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_ABC,
- .valid_rx_ant = ANT_ABC,
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.set_l0s = true,
.use_bsm = false,
- .ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
@@ -516,6 +511,26 @@ struct iwl_cfg iwl5300_agn_cfg = {
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
};
+static struct iwl_ht_params iwl5000_ht_params = {
+ .ht_greenfield_support = true,
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
+};
+
+struct iwl_cfg iwl5300_agn_cfg = {
+ .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
+ .fw_name_pre = IWL5000_FW_PRE,
+ .ucode_api_max = IWL5000_UCODE_API_MAX,
+ .ucode_api_min = IWL5000_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+ .valid_tx_ant = ANT_ABC,
+ .valid_rx_ant = ANT_ABC,
+ .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .ops = &iwl5000_ops,
+ .mod_params = &iwlagn_mod_params,
+ .base_params = &iwl5000_base_params,
+ .ht_params = &iwl5000_ht_params,
+};
struct iwl_cfg iwl5100_bgn_cfg = {
.name = "Intel(R) WiFi Link 5100 BGN",
@@ -523,29 +538,14 @@ struct iwl_cfg iwl5100_bgn_cfg = {
.ucode_api_max = IWL5000_UCODE_API_MAX,
.ucode_api_min = IWL5000_UCODE_API_MIN,
.sku = IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl5000_ops,
- .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
+ .valid_tx_ant = ANT_B,
+ .valid_rx_ant = ANT_AB,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl5000_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_B,
- .valid_rx_ant = ANT_AB,
- .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
- .set_l0s = true,
- .use_bsm = false,
- .ht_greenfield_support = true,
- .led_compensation = 51,
- .use_rts_for_aggregation = true, /* use rts/cts protection */
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
- .chain_noise_scale = 1000,
- .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
- .max_event_log_size = 512,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl5000_base_params,
+ .ht_params = &iwl5000_ht_params,
};
struct iwl_cfg iwl5100_abg_cfg = {
@@ -554,27 +554,13 @@ struct iwl_cfg iwl5100_abg_cfg = {
.ucode_api_max = IWL5000_UCODE_API_MAX,
.ucode_api_min = IWL5000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G,
- .ops = &iwl5000_ops,
- .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
+ .valid_tx_ant = ANT_B,
+ .valid_rx_ant = ANT_AB,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl5000_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_B,
- .valid_rx_ant = ANT_AB,
- .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
- .set_l0s = true,
- .use_bsm = false,
- .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,
- .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
- .max_event_log_size = 512,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl5000_base_params,
};
struct iwl_cfg iwl5100_agn_cfg = {
@@ -583,29 +569,14 @@ struct iwl_cfg iwl5100_agn_cfg = {
.ucode_api_max = IWL5000_UCODE_API_MAX,
.ucode_api_min = IWL5000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl5000_ops,
- .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
+ .valid_tx_ant = ANT_B,
+ .valid_rx_ant = ANT_AB,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl5000_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_B,
- .valid_rx_ant = ANT_AB,
- .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
- .set_l0s = true,
- .use_bsm = false,
- .ht_greenfield_support = true,
- .led_compensation = 51,
- .use_rts_for_aggregation = true, /* use rts/cts protection */
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
- .chain_noise_scale = 1000,
- .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
- .max_event_log_size = 512,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl5000_base_params,
+ .ht_params = &iwl5000_ht_params,
};
struct iwl_cfg iwl5350_agn_cfg = {
@@ -614,29 +585,14 @@ struct iwl_cfg iwl5350_agn_cfg = {
.ucode_api_max = IWL5000_UCODE_API_MAX,
.ucode_api_min = IWL5000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl5000_ops,
- .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
+ .valid_tx_ant = ANT_ABC,
+ .valid_rx_ant = ANT_ABC,
.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl5000_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_ABC,
- .valid_rx_ant = ANT_ABC,
- .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
- .set_l0s = true,
- .use_bsm = false,
- .ht_greenfield_support = true,
- .led_compensation = 51,
- .use_rts_for_aggregation = true, /* use rts/cts protection */
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
- .chain_noise_scale = 1000,
- .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
- .max_event_log_size = 512,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl5000_base_params,
+ .ht_params = &iwl5000_ht_params,
};
struct iwl_cfg iwl5150_agn_cfg = {
@@ -645,29 +601,14 @@ struct iwl_cfg iwl5150_agn_cfg = {
.ucode_api_max = IWL5150_UCODE_API_MAX,
.ucode_api_min = IWL5150_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl5150_ops,
- .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_AB,
.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl5150_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_AB,
- .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
- .set_l0s = true,
- .use_bsm = false,
- .ht_greenfield_support = true,
- .led_compensation = 51,
- .use_rts_for_aggregation = true, /* use rts/cts protection */
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
- .chain_noise_scale = 1000,
- .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
- .max_event_log_size = 512,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl5000_base_params,
+ .ht_params = &iwl5000_ht_params,
.need_dc_calib = true,
};
@@ -677,27 +618,13 @@ struct iwl_cfg iwl5150_abg_cfg = {
.ucode_api_max = IWL5150_UCODE_API_MAX,
.ucode_api_min = IWL5150_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G,
- .ops = &iwl5150_ops,
- .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_AB,
.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl5150_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_AB,
- .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
- .set_l0s = true,
- .use_bsm = false,
- .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,
- .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
- .max_event_log_size = 512,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl5000_base_params,
.need_dc_calib = true,
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h
index ddba39999997..47891e16a758 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h
@@ -62,7 +62,7 @@
*****************************************************************************/
/*
* Please use this file (iwl-6000-hw.h) only for hardware-related definitions.
- * Use iwl-5000-commands.h for uCode API definitions.
+ * Use iwl-commands.h for uCode API definitions.
*/
#ifndef __iwl_6000_hw_h__
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index cee06b968de8..11e6532fc573 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -51,13 +51,15 @@
/* Highest firmware API version supported */
#define IWL6000_UCODE_API_MAX 4
-#define IWL6050_UCODE_API_MAX 4
-#define IWL6000G2_UCODE_API_MAX 4
+#define IWL6050_UCODE_API_MAX 5
+#define IWL6000G2_UCODE_API_MAX 5
+#define IWL130_UCODE_API_MAX 5
/* Lowest firmware API version supported */
#define IWL6000_UCODE_API_MIN 4
#define IWL6050_UCODE_API_MIN 4
#define IWL6000G2_UCODE_API_MIN 4
+#define IWL130_UCODE_API_MIN 5
#define IWL6000_FW_PRE "iwlwifi-6000-"
#define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode"
@@ -75,6 +77,9 @@
#define _IWL6000G2B_MODULE_FIRMWARE(api) IWL6000G2B_FW_PRE #api ".ucode"
#define IWL6000G2B_MODULE_FIRMWARE(api) _IWL6000G2B_MODULE_FIRMWARE(api)
+#define IWL130_FW_PRE "iwlwifi-130-"
+#define _IWL130_MODULE_FIRMWARE(api) IWL130_FW_PRE #api ".ucode"
+#define IWL130_MODULE_FIRMWARE(api) _IWL130_MODULE_FIRMWARE(api)
static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
{
@@ -83,15 +88,24 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
}
-/* Indicate calibration version to uCode. */
-static void iwl6000_set_calib_version(struct iwl_priv *priv)
+static void iwl6050_additional_nic_config(struct iwl_priv *priv)
{
- if (priv->cfg->need_dc_calib &&
- (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6))
+ /* Indicate calibration version to uCode. */
+ if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)
iwl_set_bit(priv, CSR_GP_DRIVER_REG,
CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
}
+static void iwl6050g2_additional_nic_config(struct iwl_priv *priv)
+{
+ /* Indicate calibration version to uCode. */
+ if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)
+ iwl_set_bit(priv, CSR_GP_DRIVER_REG,
+ CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
+ iwl_set_bit(priv, CSR_GP_DRIVER_REG,
+ CSR_GP_DRIVER_REG_BIT_6050_1x2);
+}
+
/* NIC configuration for 6000 series */
static void iwl6000_nic_config(struct iwl_priv *priv)
{
@@ -117,9 +131,11 @@ static void iwl6000_nic_config(struct iwl_priv *priv)
iwl_write32(priv, CSR_GP_DRIVER_REG,
CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
}
- /* else do nothing, uCode configured */
- if (priv->cfg->ops->lib->temp_ops.set_calib_version)
- priv->cfg->ops->lib->temp_ops.set_calib_version(priv);
+ /* do additional nic configuration if needed */
+ if (priv->cfg->ops->nic &&
+ priv->cfg->ops->nic->additional_nic_config) {
+ priv->cfg->ops->nic->additional_nic_config(priv);
+ }
}
static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
@@ -151,17 +167,17 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
{
if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
- priv->cfg->num_of_queues =
+ priv->cfg->base_params->num_of_queues =
priv->cfg->mod_params->num_of_queues;
- priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+ priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
priv->hw_params.scd_bc_tbls_size =
- priv->cfg->num_of_queues *
+ 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;
- priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
+ 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;
@@ -176,8 +192,7 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
- if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
- priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
+ iwl6000_set_ct_threshold(priv);
/* Set initial sensitivity parameters */
/* Set initial calibration set */
@@ -188,7 +203,9 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
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.calib_rt_cfg |= BIT(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;
@@ -198,14 +215,19 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
struct ieee80211_channel_switch *ch_switch)
{
+ /*
+ * MULTI-FIXME
+ * See iwl_mac_channel_switch.
+ */
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
struct iwl6000_channel_switch_cmd cmd;
const struct iwl_channel_info *ch_info;
u32 switch_time_in_usec, ucode_switch_time;
u16 ch;
u32 tsf_low;
u8 switch_count;
- u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
- struct ieee80211_vif *vif = priv->vif;
+ u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
+ struct ieee80211_vif *vif = ctx->vif;
struct iwl_host_cmd hcmd = {
.id = REPLY_CHANNEL_SWITCH,
.len = sizeof(cmd),
@@ -214,12 +236,12 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
};
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
- ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
+ ch = ch_switch->channel->hw_value;
IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
- priv->active_rxon.channel, ch);
+ ctx->active.channel, ch);
cmd.channel = cpu_to_le16(ch);
- cmd.rxon_flags = priv->staging_rxon.flags;
- cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
+ cmd.rxon_flags = ctx->staging.flags;
+ cmd.rxon_filter_flags = ctx->staging.filter_flags;
switch_count = ch_switch->count;
tsf_low = ch_switch->timestamp & 0x0ffffffff;
/*
@@ -254,7 +276,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
cmd.expect_beacon = is_channel_radar(ch_info);
else {
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
- priv->active_rxon.channel, ch);
+ ctx->active.channel, ch);
return -EFAULT;
}
priv->switch_rxon.channel = cmd.channel;
@@ -288,9 +310,7 @@ static struct iwl_lib_ops iwl6000_lib = {
.set_channel_switch = iwl6000_hw_channel_switch,
.apm_ops = {
.init = iwl_apm_init,
- .stop = iwl_apm_stop,
.config = iwl6000_nic_config,
- .set_pwr_src = iwl_set_pwr_src,
},
.eeprom_ops = {
.regulatory_bands = {
@@ -302,7 +322,6 @@ static struct iwl_lib_ops iwl6000_lib = {
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
EEPROM_REG_BAND_52_HT40_CHANNELS
},
- .verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
.release_semaphore = iwlcore_eeprom_release_semaphore,
.calib_version = iwlagn_eeprom_calib_version,
@@ -314,22 +333,105 @@ static struct iwl_lib_ops iwl6000_lib = {
.config_ap = iwl_config_ap,
.temp_ops = {
.temperature = iwlagn_temperature,
- .set_ct_kill = iwl6000_set_ct_threshold,
- .set_calib_version = iwl6000_set_calib_version,
},
.manage_ibss_station = iwlagn_manage_ibss_station,
- .update_bcast_station = iwl_update_bcast_station,
+ .update_bcast_stations = iwl_update_bcast_stations,
+ .debugfs_ops = {
+ .rx_stats_read = iwl_ucode_rx_stats_read,
+ .tx_stats_read = iwl_ucode_tx_stats_read,
+ .general_stats_read = iwl_ucode_general_stats_read,
+ .bt_stats_read = iwl_ucode_bt_stats_read,
+ .reply_tx_error = iwl_reply_tx_error_read,
+ },
+ .recover_from_tx_stall = iwl_bg_monitor_recover,
+ .check_plcp_health = iwl_good_plcp_health,
+ .check_ack_health = iwl_good_ack_health,
+ .txfifo_flush = iwlagn_txfifo_flush,
+ .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
+ .tt_ops = {
+ .lower_power_detection = iwl_tt_is_low_power_state,
+ .tt_power_mode = iwl_tt_current_power_mode,
+ .ct_kill_check = iwl_check_for_ct_kill,
+ }
+};
+
+static struct iwl_lib_ops iwl6000g2b_lib = {
+ .set_hw_params = iwl6000_hw_set_hw_params,
+ .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
+ .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
+ .txq_set_sched = iwlagn_txq_set_sched,
+ .txq_agg_enable = iwlagn_txq_agg_enable,
+ .txq_agg_disable = iwlagn_txq_agg_disable,
+ .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
+ .txq_free_tfd = iwl_hw_txq_free_tfd,
+ .txq_init = iwl_hw_tx_queue_init,
+ .rx_handler_setup = iwlagn_bt_rx_handler_setup,
+ .setup_deferred_work = iwlagn_bt_setup_deferred_work,
+ .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
+ .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
+ .load_ucode = iwlagn_load_ucode,
+ .dump_nic_event_log = iwl_dump_nic_event_log,
+ .dump_nic_error_log = iwl_dump_nic_error_log,
+ .dump_csr = iwl_dump_csr,
+ .dump_fh = iwl_dump_fh,
+ .init_alive_start = iwlagn_init_alive_start,
+ .alive_notify = iwlagn_alive_notify,
+ .send_tx_power = iwlagn_send_tx_power,
+ .update_chain_flags = iwl_update_chain_flags,
+ .set_channel_switch = iwl6000_hw_channel_switch,
+ .apm_ops = {
+ .init = iwl_apm_init,
+ .config = iwl6000_nic_config,
+ },
+ .eeprom_ops = {
+ .regulatory_bands = {
+ EEPROM_REG_BAND_1_CHANNELS,
+ EEPROM_REG_BAND_2_CHANNELS,
+ EEPROM_REG_BAND_3_CHANNELS,
+ EEPROM_REG_BAND_4_CHANNELS,
+ EEPROM_REG_BAND_5_CHANNELS,
+ EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
+ EEPROM_REG_BAND_52_HT40_CHANNELS
+ },
+ .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+ .release_semaphore = iwlcore_eeprom_release_semaphore,
+ .calib_version = iwlagn_eeprom_calib_version,
+ .query_addr = iwlagn_eeprom_query_addr,
+ .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
+ },
+ .post_associate = iwl_post_associate,
+ .isr = iwl_isr_ict,
+ .config_ap = iwl_config_ap,
+ .temp_ops = {
+ .temperature = iwlagn_temperature,
+ },
+ .manage_ibss_station = iwlagn_manage_ibss_station,
+ .update_bcast_stations = iwl_update_bcast_stations,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
.general_stats_read = iwl_ucode_general_stats_read,
.bt_stats_read = iwl_ucode_bt_stats_read,
+ .reply_tx_error = iwl_reply_tx_error_read,
},
.recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
.txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
+ .tt_ops = {
+ .lower_power_detection = iwl_tt_is_low_power_state,
+ .tt_power_mode = iwl_tt_current_power_mode,
+ .ct_kill_check = iwl_check_for_ct_kill,
+ }
+};
+
+static struct iwl_nic_ops iwl6050_nic_ops = {
+ .additional_nic_config = &iwl6050_additional_nic_config,
+};
+
+static struct iwl_nic_ops iwl6050g2_nic_ops = {
+ .additional_nic_config = &iwl6050g2_additional_nic_config,
};
static const struct iwl_ops iwl6000_ops = {
@@ -339,49 +441,39 @@ static const struct iwl_ops iwl6000_ops = {
.led = &iwlagn_led_ops,
};
-static void do_not_send_bt_config(struct iwl_priv *priv)
-{
-}
+static const struct iwl_ops iwl6050_ops = {
+ .lib = &iwl6000_lib,
+ .hcmd = &iwlagn_hcmd,
+ .utils = &iwlagn_hcmd_utils,
+ .led = &iwlagn_led_ops,
+ .nic = &iwl6050_nic_ops,
+};
-static struct iwl_hcmd_ops iwl6000g2b_hcmd = {
- .rxon_assoc = iwlagn_send_rxon_assoc,
- .commit_rxon = iwl_commit_rxon,
- .set_rxon_chain = iwl_set_rxon_chain,
- .set_tx_ant = iwlagn_send_tx_ant_config,
- .send_bt_config = do_not_send_bt_config,
+static const struct iwl_ops iwl6050g2_ops = {
+ .lib = &iwl6000_lib,
+ .hcmd = &iwlagn_hcmd,
+ .utils = &iwlagn_hcmd_utils,
+ .led = &iwlagn_led_ops,
+ .nic = &iwl6050g2_nic_ops,
};
static const struct iwl_ops iwl6000g2b_ops = {
- .lib = &iwl6000_lib,
- .hcmd = &iwl6000g2b_hcmd,
+ .lib = &iwl6000g2b_lib,
+ .hcmd = &iwlagn_bt_hcmd,
.utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
};
-struct iwl_cfg iwl6000g2a_2agn_cfg = {
- .name = "6000 Series 2x2 AGN Gen2a",
- .fw_name_pre = IWL6000G2A_FW_PRE,
- .ucode_api_max = IWL6000G2_UCODE_API_MAX,
- .ucode_api_min = IWL6000G2_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl6000_ops,
+static struct iwl_base_params iwl6000_base_params = {
.eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
- .mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
.pll_cfg_val = 0,
.set_l0s = true,
.use_bsm = false,
- .pa_type = IWL_PA_SYSTEM,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
- .ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true,
.adv_thermal_throttle = true,
@@ -393,29 +485,16 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = {
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
- .need_dc_calib = true,
};
-struct iwl_cfg iwl6000g2a_2abg_cfg = {
- .name = "6000 Series 2x2 ABG Gen2a",
- .fw_name_pre = IWL6000G2A_FW_PRE,
- .ucode_api_max = IWL6000G2_UCODE_API_MAX,
- .ucode_api_min = IWL6000G2_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G,
- .ops = &iwl6000_ops,
+static struct iwl_base_params iwl6050_base_params = {
.eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
- .mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
.pll_cfg_val = 0,
.set_l0s = true,
.use_bsm = false,
- .pa_type = IWL_PA_SYSTEM,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
.shadow_ram_support = true,
.led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
@@ -423,33 +502,20 @@ struct iwl_cfg iwl6000g2a_2abg_cfg = {
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
- .chain_noise_scale = 1000,
+ .chain_noise_scale = 1500,
.monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
- .max_event_log_size = 512,
+ .max_event_log_size = 1024,
+ .ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
- .need_dc_calib = true,
};
-
-struct iwl_cfg iwl6000g2a_2bg_cfg = {
- .name = "6000 Series 2x2 BG Gen2a",
- .fw_name_pre = IWL6000G2A_FW_PRE,
- .ucode_api_max = IWL6000G2_UCODE_API_MAX,
- .ucode_api_min = IWL6000G2_UCODE_API_MIN,
- .sku = IWL_SKU_G,
- .ops = &iwl6000_ops,
+static struct iwl_base_params iwl6000_coex_base_params = {
.eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
- .mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
.pll_cfg_val = 0,
.set_l0s = true,
.use_bsm = false,
- .pa_type = IWL_PA_SYSTEM,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
.led_compensation = 51,
@@ -459,11 +525,76 @@ struct iwl_cfg iwl6000g2a_2bg_cfg = {
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1000,
- .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
+ .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
.max_event_log_size = 512,
+ .ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
+};
+
+static struct iwl_ht_params iwl6000_ht_params = {
+ .ht_greenfield_support = true,
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
+};
+
+static struct iwl_bt_params iwl6000_bt_params = {
+ .bt_statistics = true,
+ /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+ .advanced_bt_coexist = true,
+ .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
+ .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
+};
+
+struct iwl_cfg iwl6000g2a_2agn_cfg = {
+ .name = "6000 Series 2x2 AGN Gen2a",
+ .fw_name_pre = IWL6000G2A_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .ops = &iwl6000_ops,
+ .mod_params = &iwlagn_mod_params,
+ .base_params = &iwl6000_base_params,
+ .ht_params = &iwl6000_ht_params,
+ .need_dc_calib = true,
+ .need_temp_offset_calib = true,
+};
+
+struct iwl_cfg iwl6000g2a_2abg_cfg = {
+ .name = "6000 Series 2x2 ABG Gen2a",
+ .fw_name_pre = IWL6000G2A_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .ops = &iwl6000_ops,
+ .mod_params = &iwlagn_mod_params,
+ .base_params = &iwl6000_base_params,
+ .need_dc_calib = true,
+ .need_temp_offset_calib = true,
+};
+
+struct iwl_cfg iwl6000g2a_2bg_cfg = {
+ .name = "6000 Series 2x2 BG Gen2a",
+ .fw_name_pre = IWL6000G2A_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_G,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .ops = &iwl6000_ops,
+ .mod_params = &iwlagn_mod_params,
+ .base_params = &iwl6000_base_params,
.need_dc_calib = true,
+ .need_temp_offset_calib = true,
};
struct iwl_cfg iwl6000g2b_2agn_cfg = {
@@ -472,36 +603,19 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = {
.ucode_api_max = IWL6000G2_UCODE_API_MAX,
.ucode_api_min = IWL6000G2_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl6000g2b_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl6000g2b_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
- .pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
- .pa_type = IWL_PA_SYSTEM,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
- .shadow_ram_support = true,
- .ht_greenfield_support = true,
- .led_compensation = 51,
- .use_rts_for_aggregation = true, /* use rts/cts protection */
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .supports_idle = true,
- .adv_thermal_throttle = true,
- .support_ct_kill_exit = true,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
- .chain_noise_scale = 1000,
- .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
- .max_event_log_size = 512,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl6000_coex_base_params,
+ .bt_params = &iwl6000_bt_params,
+ .ht_params = &iwl6000_ht_params,
.need_dc_calib = true,
- .bt_statistics = true,
+ .need_temp_offset_calib = true,
+ /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
};
struct iwl_cfg iwl6000g2b_2abg_cfg = {
@@ -510,34 +624,18 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = {
.ucode_api_max = IWL6000G2_UCODE_API_MAX,
.ucode_api_min = IWL6000G2_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G,
- .ops = &iwl6000g2b_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl6000g2b_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
- .pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
- .pa_type = IWL_PA_SYSTEM,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
- .shadow_ram_support = true,
- .led_compensation = 51,
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .supports_idle = true,
- .adv_thermal_throttle = true,
- .support_ct_kill_exit = true,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
- .chain_noise_scale = 1000,
- .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
- .max_event_log_size = 512,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl6000_coex_base_params,
+ .bt_params = &iwl6000_bt_params,
.need_dc_calib = true,
- .bt_statistics = true,
+ .need_temp_offset_calib = true,
+ /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
};
struct iwl_cfg iwl6000g2b_2bgn_cfg = {
@@ -546,36 +644,19 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = {
.ucode_api_max = IWL6000G2_UCODE_API_MAX,
.ucode_api_min = IWL6000G2_UCODE_API_MIN,
.sku = IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl6000g2b_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl6000g2b_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
- .pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
- .pa_type = IWL_PA_SYSTEM,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
- .shadow_ram_support = true,
- .ht_greenfield_support = true,
- .led_compensation = 51,
- .use_rts_for_aggregation = true, /* use rts/cts protection */
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .supports_idle = true,
- .adv_thermal_throttle = true,
- .support_ct_kill_exit = true,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
- .chain_noise_scale = 1000,
- .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
- .max_event_log_size = 512,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl6000_coex_base_params,
+ .bt_params = &iwl6000_bt_params,
+ .ht_params = &iwl6000_ht_params,
.need_dc_calib = true,
- .bt_statistics = true,
+ .need_temp_offset_calib = true,
+ /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
};
struct iwl_cfg iwl6000g2b_2bg_cfg = {
@@ -584,34 +665,18 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = {
.ucode_api_max = IWL6000G2_UCODE_API_MAX,
.ucode_api_min = IWL6000G2_UCODE_API_MIN,
.sku = IWL_SKU_G,
- .ops = &iwl6000g2b_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl6000g2b_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
- .pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
- .pa_type = IWL_PA_SYSTEM,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
- .shadow_ram_support = true,
- .led_compensation = 51,
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .supports_idle = true,
- .adv_thermal_throttle = true,
- .support_ct_kill_exit = true,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
- .chain_noise_scale = 1000,
- .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
- .max_event_log_size = 512,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl6000_coex_base_params,
+ .bt_params = &iwl6000_bt_params,
.need_dc_calib = true,
- .bt_statistics = true,
+ .need_temp_offset_calib = true,
+ /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
};
struct iwl_cfg iwl6000g2b_bgn_cfg = {
@@ -620,36 +685,19 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = {
.ucode_api_max = IWL6000G2_UCODE_API_MAX,
.ucode_api_min = IWL6000G2_UCODE_API_MIN,
.sku = IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl6000g2b_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_AB,
.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl6000g2b_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_AB,
- .pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
- .pa_type = IWL_PA_SYSTEM,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
- .shadow_ram_support = true,
- .ht_greenfield_support = true,
- .led_compensation = 51,
- .use_rts_for_aggregation = true, /* use rts/cts protection */
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .supports_idle = true,
- .adv_thermal_throttle = true,
- .support_ct_kill_exit = true,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
- .chain_noise_scale = 1000,
- .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
- .max_event_log_size = 512,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl6000_coex_base_params,
+ .bt_params = &iwl6000_bt_params,
+ .ht_params = &iwl6000_ht_params,
.need_dc_calib = true,
- .bt_statistics = true,
+ .need_temp_offset_calib = true,
+ /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
};
struct iwl_cfg iwl6000g2b_bg_cfg = {
@@ -658,34 +706,18 @@ struct iwl_cfg iwl6000g2b_bg_cfg = {
.ucode_api_max = IWL6000G2_UCODE_API_MAX,
.ucode_api_min = IWL6000G2_UCODE_API_MIN,
.sku = IWL_SKU_G,
- .ops = &iwl6000g2b_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_AB,
.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl6000g2b_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_AB,
- .pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
- .pa_type = IWL_PA_SYSTEM,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
- .shadow_ram_support = true,
- .led_compensation = 51,
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .supports_idle = true,
- .adv_thermal_throttle = true,
- .support_ct_kill_exit = true,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
- .chain_noise_scale = 1000,
- .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
- .max_event_log_size = 512,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl6000_coex_base_params,
+ .bt_params = &iwl6000_bt_params,
.need_dc_calib = true,
- .bt_statistics = true,
+ .need_temp_offset_calib = true,
+ /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
};
/*
@@ -697,35 +729,15 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
.ucode_api_max = IWL6000_UCODE_API_MAX,
.ucode_api_min = IWL6000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl6000_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .valid_tx_ant = ANT_BC,
+ .valid_rx_ant = ANT_BC,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl6000_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_BC,
- .valid_rx_ant = ANT_BC,
- .pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
+ .base_params = &iwl6000_base_params,
+ .ht_params = &iwl6000_ht_params,
.pa_type = IWL_PA_INTERNAL,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
- .shadow_ram_support = true,
- .ht_greenfield_support = true,
- .led_compensation = 51,
- .use_rts_for_aggregation = true, /* use rts/cts protection */
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .supports_idle = true,
- .adv_thermal_throttle = true,
- .support_ct_kill_exit = true,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
- .chain_noise_scale = 1000,
- .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
- .max_event_log_size = 1024,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
};
struct iwl_cfg iwl6000i_2abg_cfg = {
@@ -734,33 +746,14 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
.ucode_api_max = IWL6000_UCODE_API_MAX,
.ucode_api_min = IWL6000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G,
- .ops = &iwl6000_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .valid_tx_ant = ANT_BC,
+ .valid_rx_ant = ANT_BC,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl6000_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_BC,
- .valid_rx_ant = ANT_BC,
- .pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
+ .base_params = &iwl6000_base_params,
.pa_type = IWL_PA_INTERNAL,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
- .shadow_ram_support = true,
- .led_compensation = 51,
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .supports_idle = true,
- .adv_thermal_throttle = true,
- .support_ct_kill_exit = true,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
- .chain_noise_scale = 1000,
- .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
- .max_event_log_size = 1024,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
};
struct iwl_cfg iwl6000i_2bg_cfg = {
@@ -769,33 +762,14 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
.ucode_api_max = IWL6000_UCODE_API_MAX,
.ucode_api_min = IWL6000_UCODE_API_MIN,
.sku = IWL_SKU_G,
- .ops = &iwl6000_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .valid_tx_ant = ANT_BC,
+ .valid_rx_ant = ANT_BC,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl6000_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_BC,
- .valid_rx_ant = ANT_BC,
- .pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
+ .base_params = &iwl6000_base_params,
.pa_type = IWL_PA_INTERNAL,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
- .shadow_ram_support = true,
- .led_compensation = 51,
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .supports_idle = true,
- .adv_thermal_throttle = true,
- .support_ct_kill_exit = true,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
- .chain_noise_scale = 1000,
- .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
- .max_event_log_size = 1024,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
};
struct iwl_cfg iwl6050_2agn_cfg = {
@@ -804,35 +778,14 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl6000_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .ops = &iwl6050_ops,
.eeprom_ver = EEPROM_6050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
- .pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
- .pa_type = IWL_PA_SYSTEM,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
- .shadow_ram_support = true,
- .ht_greenfield_support = true,
- .led_compensation = 51,
- .use_rts_for_aggregation = true, /* use rts/cts protection */
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .supports_idle = true,
- .adv_thermal_throttle = true,
- .support_ct_kill_exit = true,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
- .chain_noise_scale = 1500,
- .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
- .max_event_log_size = 1024,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl6050_base_params,
+ .ht_params = &iwl6000_ht_params,
.need_dc_calib = true,
};
@@ -842,35 +795,14 @@ struct iwl_cfg iwl6050g2_bgn_cfg = {
.ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl6000_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_AB,
.eeprom_ver = EEPROM_6050G2_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6050G2_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl6050g2_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_A,
- .valid_rx_ant = ANT_AB,
- .pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
- .pa_type = IWL_PA_SYSTEM,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
- .shadow_ram_support = true,
- .ht_greenfield_support = true,
- .led_compensation = 51,
- .use_rts_for_aggregation = true, /* use rts/cts protection */
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .supports_idle = true,
- .adv_thermal_throttle = true,
- .support_ct_kill_exit = true,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
- .chain_noise_scale = 1500,
- .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
- .max_event_log_size = 1024,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl6050_base_params,
+ .ht_params = &iwl6000_ht_params,
.need_dc_calib = true,
};
@@ -880,33 +812,13 @@ struct iwl_cfg iwl6050_2abg_cfg = {
.ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G,
- .ops = &iwl6000_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
.eeprom_ver = EEPROM_6050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl6050_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_AB,
- .valid_rx_ant = ANT_AB,
- .pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
- .pa_type = IWL_PA_SYSTEM,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
- .shadow_ram_support = true,
- .led_compensation = 51,
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .supports_idle = true,
- .adv_thermal_throttle = true,
- .support_ct_kill_exit = true,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
- .chain_noise_scale = 1500,
- .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
- .max_event_log_size = 1024,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl6050_base_params,
.need_dc_calib = true,
};
@@ -916,38 +828,58 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.ucode_api_max = IWL6000_UCODE_API_MAX,
.ucode_api_min = IWL6000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl6000_ops,
- .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .valid_tx_ant = ANT_ABC,
+ .valid_rx_ant = ANT_ABC,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
- .num_of_queues = IWLAGN_NUM_QUEUES,
- .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .ops = &iwl6000_ops,
.mod_params = &iwlagn_mod_params,
- .valid_tx_ant = ANT_ABC,
- .valid_rx_ant = ANT_ABC,
- .pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
- .pa_type = IWL_PA_SYSTEM,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
- .shadow_ram_support = true,
- .ht_greenfield_support = true,
- .led_compensation = 51,
- .use_rts_for_aggregation = true, /* use rts/cts protection */
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
- .supports_idle = true,
- .adv_thermal_throttle = true,
- .support_ct_kill_exit = true,
- .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
- .chain_noise_scale = 1000,
- .monitor_recover_period = IWL_DEF_MONITORING_PERIOD,
- .max_event_log_size = 1024,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
+ .base_params = &iwl6000_base_params,
+ .ht_params = &iwl6000_ht_params,
+ .need_dc_calib = true,
+};
+
+struct iwl_cfg iwl130_bgn_cfg = {
+ .name = "Intel(R) 130 Series 1x1 BGN",
+ .fw_name_pre = IWL6000G2B_FW_PRE,
+ .ucode_api_max = IWL130_UCODE_API_MAX,
+ .ucode_api_min = IWL130_UCODE_API_MIN,
+ .sku = IWL_SKU_G|IWL_SKU_N,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_A,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .ops = &iwl6000g2b_ops,
+ .mod_params = &iwlagn_mod_params,
+ .base_params = &iwl6000_coex_base_params,
+ .bt_params = &iwl6000_bt_params,
+ .ht_params = &iwl6000_ht_params,
+ .need_dc_calib = true,
+ /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+};
+
+struct iwl_cfg iwl130_bg_cfg = {
+ .name = "Intel(R) 130 Series 1x2 BG",
+ .fw_name_pre = IWL6000G2B_FW_PRE,
+ .ucode_api_max = IWL130_UCODE_API_MAX,
+ .ucode_api_min = IWL130_UCODE_API_MIN,
+ .sku = IWL_SKU_G,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_A,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .ops = &iwl6000g2b_ops,
+ .mod_params = &iwlagn_mod_params,
+ .base_params = &iwl6000_coex_base_params,
+ .bt_params = &iwl6000_bt_params,
+ .need_dc_calib = true,
+ /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
};
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX));
MODULE_FIRMWARE(IWL6000G2A_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
MODULE_FIRMWARE(IWL6000G2B_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL130_MODULE_FIRMWARE(IWL130_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
index c4c5691032a6..e2019e756936 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
@@ -65,7 +65,7 @@
#include "iwl-dev.h"
#include "iwl-core.h"
-#include "iwl-calib.h"
+#include "iwl-agn-calib.h"
/*****************************************************************************
* INIT calibrations framework
@@ -625,13 +625,14 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp)
data = &(priv->sensitivity_data);
- if (!iwl_is_associated(priv)) {
+ if (!iwl_is_any_associated(priv)) {
IWL_DEBUG_CALIB(priv, "<< - not associated\n");
return;
}
spin_lock_irqsave(&priv->lock, flags);
- if (priv->cfg->bt_statistics) {
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->bt_statistics) {
rx_info = &(((struct iwl_bt_notif_statistics *)resp)->
rx.general.common);
ofdm = &(((struct iwl_bt_notif_statistics *)resp)->rx.ofdm);
@@ -763,6 +764,12 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
unsigned long flags;
struct statistics_rx_non_phy *rx_info;
u8 first_chain;
+ /*
+ * MULTI-FIXME:
+ * When we support multiple interfaces on different channels,
+ * this must be modified/fixed.
+ */
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
if (priv->disable_chain_noise_cal)
return;
@@ -780,7 +787,8 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
}
spin_lock_irqsave(&priv->lock, flags);
- if (priv->cfg->bt_statistics) {
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->bt_statistics) {
rx_info = &(((struct iwl_bt_notif_statistics *)stat_resp)->
rx.general.common);
} else {
@@ -793,9 +801,10 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
return;
}
- rxon_band24 = !!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK);
- rxon_chnum = le16_to_cpu(priv->staging_rxon.channel);
- if (priv->cfg->bt_statistics) {
+ rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK);
+ rxon_chnum = le16_to_cpu(ctx->staging.channel);
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->bt_statistics) {
stat_band24 = !!(((struct iwl_bt_notif_statistics *)
stat_resp)->flag &
STATISTICS_REPLY_FLG_BAND_24G_MSK);
@@ -855,16 +864,17 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
/* 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->chain_noise_num_beacons)
+ if (data->beacon_count !=
+ priv->cfg->base_params->chain_noise_num_beacons)
return;
/* Analyze signal for disconnected antenna */
- average_sig[0] =
- (data->chain_signal_a) / priv->cfg->chain_noise_num_beacons;
- average_sig[1] =
- (data->chain_signal_b) / priv->cfg->chain_noise_num_beacons;
- average_sig[2] =
- (data->chain_signal_c) / priv->cfg->chain_noise_num_beacons;
+ 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;
if (average_sig[0] >= average_sig[1]) {
max_average_sig = average_sig[0];
@@ -914,7 +924,13 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
* To be safe, simply mask out any chains that we know
* are not on the device.
*/
- active_chains &= priv->hw_params.valid_rx_ant;
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist &&
+ priv->bt_full_concurrent) {
+ /* operated as 1x1 in full concurrency mode */
+ active_chains &= first_antenna(priv->hw_params.valid_rx_ant);
+ } else
+ active_chains &= priv->hw_params.valid_rx_ant;
num_tx_chains = 0;
for (i = 0; i < NUM_RX_CHAINS; i++) {
@@ -957,12 +973,12 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
active_chains);
/* Analyze noise for rx balance */
- average_noise[0] =
- ((data->chain_noise_a) / priv->cfg->chain_noise_num_beacons);
- average_noise[1] =
- ((data->chain_noise_b) / priv->cfg->chain_noise_num_beacons);
- average_noise[2] =
- ((data->chain_noise_c) / priv->cfg->chain_noise_num_beacons);
+ 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;
for (i = 0; i < NUM_RX_CHAINS; i++) {
if (!(data->disconn_array[i]) &&
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h
index ba9523fbb300..e37ae7261630 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h
@@ -79,4 +79,8 @@ static inline void iwl_chain_noise_reset(struct iwl_priv *priv)
priv->cfg->ops->utils->chain_noise_reset(priv);
}
+int iwl_send_calib_results(struct iwl_priv *priv);
+int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len);
+void iwl_calib_free_results(struct iwl_priv *priv);
+
#endif /* __iwl_calib_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
index d706b8afbe5a..a358d4334a1a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
@@ -25,15 +25,22 @@
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*****************************************************************************/
-
+#include "iwl-agn.h"
#include "iwl-agn-debugfs.h"
+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";
+static const char *fmt_header =
+ "%-32s current cumulative delta max\n";
+
static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
{
int p = 0;
u32 flag;
- if (priv->cfg->bt_statistics)
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->bt_statistics)
flag = le32_to_cpu(priv->_agn.statistics_bt.flag);
else
flag = le32_to_cpu(priv->_agn.statistics.flag);
@@ -82,7 +89,8 @@ ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
* the last statistics notification from uCode
* might not reflect the current uCode activity
*/
- if (priv->cfg->bt_statistics) {
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->bt_statistics) {
ofdm = &priv->_agn.statistics_bt.rx.ofdm;
cck = &priv->_agn.statistics_bt.rx.cck;
general = &priv->_agn.statistics_bt.rx.general.common;
@@ -121,436 +129,380 @@ ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
}
pos += iwl_statistics_flag(priv, buf, bufsz);
- pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
- "acumulative delta max\n",
- "Statistics_Rx - OFDM:");
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "ina_cnt:", le32_to_cpu(ofdm->ina_cnt),
+ fmt_header, "Statistics_Rx - OFDM:");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "ina_cnt:",
+ le32_to_cpu(ofdm->ina_cnt),
accum_ofdm->ina_cnt,
delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "fina_cnt:",
+ fmt_table, "fina_cnt:",
le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "plcp_err:",
+ fmt_table, "plcp_err:",
le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
delta_ofdm->plcp_err, max_ofdm->plcp_err);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "crc32_err:",
+ fmt_table, "crc32_err:",
le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
delta_ofdm->crc32_err, max_ofdm->crc32_err);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "overrun_err:",
+ fmt_table, "overrun_err:",
le32_to_cpu(ofdm->overrun_err),
accum_ofdm->overrun_err, delta_ofdm->overrun_err,
max_ofdm->overrun_err);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "early_overrun_err:",
+ fmt_table, "early_overrun_err:",
le32_to_cpu(ofdm->early_overrun_err),
accum_ofdm->early_overrun_err,
delta_ofdm->early_overrun_err,
max_ofdm->early_overrun_err);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "crc32_good:", le32_to_cpu(ofdm->crc32_good),
+ fmt_table, "crc32_good:",
+ le32_to_cpu(ofdm->crc32_good),
accum_ofdm->crc32_good, delta_ofdm->crc32_good,
max_ofdm->crc32_good);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "false_alarm_cnt:",
+ fmt_table, "false_alarm_cnt:",
le32_to_cpu(ofdm->false_alarm_cnt),
accum_ofdm->false_alarm_cnt,
delta_ofdm->false_alarm_cnt,
max_ofdm->false_alarm_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "fina_sync_err_cnt:",
+ fmt_table, "fina_sync_err_cnt:",
le32_to_cpu(ofdm->fina_sync_err_cnt),
accum_ofdm->fina_sync_err_cnt,
delta_ofdm->fina_sync_err_cnt,
max_ofdm->fina_sync_err_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "sfd_timeout:",
+ fmt_table, "sfd_timeout:",
le32_to_cpu(ofdm->sfd_timeout),
accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout,
max_ofdm->sfd_timeout);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "fina_timeout:",
+ fmt_table, "fina_timeout:",
le32_to_cpu(ofdm->fina_timeout),
accum_ofdm->fina_timeout, delta_ofdm->fina_timeout,
max_ofdm->fina_timeout);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "unresponded_rts:",
+ fmt_table, "unresponded_rts:",
le32_to_cpu(ofdm->unresponded_rts),
accum_ofdm->unresponded_rts,
delta_ofdm->unresponded_rts,
max_ofdm->unresponded_rts);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "rxe_frame_lmt_ovrun:",
+ fmt_table, "rxe_frame_lmt_ovrun:",
le32_to_cpu(ofdm->rxe_frame_limit_overrun),
accum_ofdm->rxe_frame_limit_overrun,
delta_ofdm->rxe_frame_limit_overrun,
max_ofdm->rxe_frame_limit_overrun);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "sent_ack_cnt:",
+ fmt_table, "sent_ack_cnt:",
le32_to_cpu(ofdm->sent_ack_cnt),
accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt,
max_ofdm->sent_ack_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "sent_cts_cnt:",
+ fmt_table, "sent_cts_cnt:",
le32_to_cpu(ofdm->sent_cts_cnt),
accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt,
max_ofdm->sent_cts_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "sent_ba_rsp_cnt:",
+ fmt_table, "sent_ba_rsp_cnt:",
le32_to_cpu(ofdm->sent_ba_rsp_cnt),
accum_ofdm->sent_ba_rsp_cnt,
delta_ofdm->sent_ba_rsp_cnt,
max_ofdm->sent_ba_rsp_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "dsp_self_kill:",
+ fmt_table, "dsp_self_kill:",
le32_to_cpu(ofdm->dsp_self_kill),
accum_ofdm->dsp_self_kill,
delta_ofdm->dsp_self_kill,
max_ofdm->dsp_self_kill);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "mh_format_err:",
+ fmt_table, "mh_format_err:",
le32_to_cpu(ofdm->mh_format_err),
accum_ofdm->mh_format_err,
delta_ofdm->mh_format_err,
max_ofdm->mh_format_err);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "re_acq_main_rssi_sum:",
+ fmt_table, "re_acq_main_rssi_sum:",
le32_to_cpu(ofdm->re_acq_main_rssi_sum),
accum_ofdm->re_acq_main_rssi_sum,
delta_ofdm->re_acq_main_rssi_sum,
max_ofdm->re_acq_main_rssi_sum);
- pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
- "acumulative delta max\n",
- "Statistics_Rx - CCK:");
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "ina_cnt:",
+ fmt_header, "Statistics_Rx - CCK:");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "ina_cnt:",
le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
delta_cck->ina_cnt, max_cck->ina_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "fina_cnt:",
+ fmt_table, "fina_cnt:",
le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
delta_cck->fina_cnt, max_cck->fina_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "plcp_err:",
+ fmt_table, "plcp_err:",
le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
delta_cck->plcp_err, max_cck->plcp_err);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "crc32_err:",
+ fmt_table, "crc32_err:",
le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
delta_cck->crc32_err, max_cck->crc32_err);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "overrun_err:",
+ fmt_table, "overrun_err:",
le32_to_cpu(cck->overrun_err),
accum_cck->overrun_err, delta_cck->overrun_err,
max_cck->overrun_err);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "early_overrun_err:",
+ fmt_table, "early_overrun_err:",
le32_to_cpu(cck->early_overrun_err),
accum_cck->early_overrun_err,
delta_cck->early_overrun_err,
max_cck->early_overrun_err);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "crc32_good:",
+ fmt_table, "crc32_good:",
le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
delta_cck->crc32_good, max_cck->crc32_good);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "false_alarm_cnt:",
+ fmt_table, "false_alarm_cnt:",
le32_to_cpu(cck->false_alarm_cnt),
accum_cck->false_alarm_cnt,
delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "fina_sync_err_cnt:",
+ fmt_table, "fina_sync_err_cnt:",
le32_to_cpu(cck->fina_sync_err_cnt),
accum_cck->fina_sync_err_cnt,
delta_cck->fina_sync_err_cnt,
max_cck->fina_sync_err_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "sfd_timeout:",
+ fmt_table, "sfd_timeout:",
le32_to_cpu(cck->sfd_timeout),
accum_cck->sfd_timeout, delta_cck->sfd_timeout,
max_cck->sfd_timeout);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "fina_timeout:",
+ fmt_table, "fina_timeout:",
le32_to_cpu(cck->fina_timeout),
accum_cck->fina_timeout, delta_cck->fina_timeout,
max_cck->fina_timeout);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "unresponded_rts:",
+ fmt_table, "unresponded_rts:",
le32_to_cpu(cck->unresponded_rts),
accum_cck->unresponded_rts, delta_cck->unresponded_rts,
max_cck->unresponded_rts);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "rxe_frame_lmt_ovrun:",
+ fmt_table, "rxe_frame_lmt_ovrun:",
le32_to_cpu(cck->rxe_frame_limit_overrun),
accum_cck->rxe_frame_limit_overrun,
delta_cck->rxe_frame_limit_overrun,
max_cck->rxe_frame_limit_overrun);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "sent_ack_cnt:",
+ fmt_table, "sent_ack_cnt:",
le32_to_cpu(cck->sent_ack_cnt),
accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt,
max_cck->sent_ack_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "sent_cts_cnt:",
+ fmt_table, "sent_cts_cnt:",
le32_to_cpu(cck->sent_cts_cnt),
accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt,
max_cck->sent_cts_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "sent_ba_rsp_cnt:",
+ fmt_table, "sent_ba_rsp_cnt:",
le32_to_cpu(cck->sent_ba_rsp_cnt),
accum_cck->sent_ba_rsp_cnt,
delta_cck->sent_ba_rsp_cnt,
max_cck->sent_ba_rsp_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "dsp_self_kill:",
+ fmt_table, "dsp_self_kill:",
le32_to_cpu(cck->dsp_self_kill),
accum_cck->dsp_self_kill, delta_cck->dsp_self_kill,
max_cck->dsp_self_kill);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "mh_format_err:",
+ fmt_table, "mh_format_err:",
le32_to_cpu(cck->mh_format_err),
accum_cck->mh_format_err, delta_cck->mh_format_err,
max_cck->mh_format_err);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "re_acq_main_rssi_sum:",
+ fmt_table, "re_acq_main_rssi_sum:",
le32_to_cpu(cck->re_acq_main_rssi_sum),
accum_cck->re_acq_main_rssi_sum,
delta_cck->re_acq_main_rssi_sum,
max_cck->re_acq_main_rssi_sum);
- pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
- "acumulative delta max\n",
- "Statistics_Rx - GENERAL:");
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "bogus_cts:",
+ fmt_header, "Statistics_Rx - GENERAL:");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "bogus_cts:",
le32_to_cpu(general->bogus_cts),
accum_general->bogus_cts, delta_general->bogus_cts,
max_general->bogus_cts);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n", "bogus_ack:",
+ fmt_table, "bogus_ack:",
le32_to_cpu(general->bogus_ack),
accum_general->bogus_ack, delta_general->bogus_ack,
max_general->bogus_ack);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "non_bssid_frames:",
+ fmt_table, "non_bssid_frames:",
le32_to_cpu(general->non_bssid_frames),
accum_general->non_bssid_frames,
delta_general->non_bssid_frames,
max_general->non_bssid_frames);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "filtered_frames:",
+ fmt_table, "filtered_frames:",
le32_to_cpu(general->filtered_frames),
accum_general->filtered_frames,
delta_general->filtered_frames,
max_general->filtered_frames);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "non_channel_beacons:",
+ fmt_table, "non_channel_beacons:",
le32_to_cpu(general->non_channel_beacons),
accum_general->non_channel_beacons,
delta_general->non_channel_beacons,
max_general->non_channel_beacons);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "channel_beacons:",
+ fmt_table, "channel_beacons:",
le32_to_cpu(general->channel_beacons),
accum_general->channel_beacons,
delta_general->channel_beacons,
max_general->channel_beacons);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "num_missed_bcon:",
+ fmt_table, "num_missed_bcon:",
le32_to_cpu(general->num_missed_bcon),
accum_general->num_missed_bcon,
delta_general->num_missed_bcon,
max_general->num_missed_bcon);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "adc_rx_saturation_time:",
+ fmt_table, "adc_rx_saturation_time:",
le32_to_cpu(general->adc_rx_saturation_time),
accum_general->adc_rx_saturation_time,
delta_general->adc_rx_saturation_time,
max_general->adc_rx_saturation_time);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "ina_detect_search_tm:",
+ fmt_table, "ina_detect_search_tm:",
le32_to_cpu(general->ina_detection_search_time),
accum_general->ina_detection_search_time,
delta_general->ina_detection_search_time,
max_general->ina_detection_search_time);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "beacon_silence_rssi_a:",
+ fmt_table, "beacon_silence_rssi_a:",
le32_to_cpu(general->beacon_silence_rssi_a),
accum_general->beacon_silence_rssi_a,
delta_general->beacon_silence_rssi_a,
max_general->beacon_silence_rssi_a);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "beacon_silence_rssi_b:",
+ fmt_table, "beacon_silence_rssi_b:",
le32_to_cpu(general->beacon_silence_rssi_b),
accum_general->beacon_silence_rssi_b,
delta_general->beacon_silence_rssi_b,
max_general->beacon_silence_rssi_b);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "beacon_silence_rssi_c:",
+ fmt_table, "beacon_silence_rssi_c:",
le32_to_cpu(general->beacon_silence_rssi_c),
accum_general->beacon_silence_rssi_c,
delta_general->beacon_silence_rssi_c,
max_general->beacon_silence_rssi_c);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "interference_data_flag:",
+ fmt_table, "interference_data_flag:",
le32_to_cpu(general->interference_data_flag),
accum_general->interference_data_flag,
delta_general->interference_data_flag,
max_general->interference_data_flag);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "channel_load:",
+ fmt_table, "channel_load:",
le32_to_cpu(general->channel_load),
accum_general->channel_load,
delta_general->channel_load,
max_general->channel_load);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "dsp_false_alarms:",
+ fmt_table, "dsp_false_alarms:",
le32_to_cpu(general->dsp_false_alarms),
accum_general->dsp_false_alarms,
delta_general->dsp_false_alarms,
max_general->dsp_false_alarms);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "beacon_rssi_a:",
+ fmt_table, "beacon_rssi_a:",
le32_to_cpu(general->beacon_rssi_a),
accum_general->beacon_rssi_a,
delta_general->beacon_rssi_a,
max_general->beacon_rssi_a);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "beacon_rssi_b:",
+ fmt_table, "beacon_rssi_b:",
le32_to_cpu(general->beacon_rssi_b),
accum_general->beacon_rssi_b,
delta_general->beacon_rssi_b,
max_general->beacon_rssi_b);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "beacon_rssi_c:",
+ fmt_table, "beacon_rssi_c:",
le32_to_cpu(general->beacon_rssi_c),
accum_general->beacon_rssi_c,
delta_general->beacon_rssi_c,
max_general->beacon_rssi_c);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "beacon_energy_a:",
+ fmt_table, "beacon_energy_a:",
le32_to_cpu(general->beacon_energy_a),
accum_general->beacon_energy_a,
delta_general->beacon_energy_a,
max_general->beacon_energy_a);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "beacon_energy_b:",
+ fmt_table, "beacon_energy_b:",
le32_to_cpu(general->beacon_energy_b),
accum_general->beacon_energy_b,
delta_general->beacon_energy_b,
max_general->beacon_energy_b);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "beacon_energy_c:",
+ fmt_table, "beacon_energy_c:",
le32_to_cpu(general->beacon_energy_c),
accum_general->beacon_energy_c,
delta_general->beacon_energy_c,
max_general->beacon_energy_c);
- pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n");
- pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
- "acumulative delta max\n",
- "Statistics_Rx - OFDM_HT:");
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "plcp_err:",
+ fmt_header, "Statistics_Rx - OFDM_HT:");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "plcp_err:",
le32_to_cpu(ht->plcp_err), accum_ht->plcp_err,
delta_ht->plcp_err, max_ht->plcp_err);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "overrun_err:",
+ fmt_table, "overrun_err:",
le32_to_cpu(ht->overrun_err), accum_ht->overrun_err,
delta_ht->overrun_err, max_ht->overrun_err);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "early_overrun_err:",
+ fmt_table, "early_overrun_err:",
le32_to_cpu(ht->early_overrun_err),
accum_ht->early_overrun_err,
delta_ht->early_overrun_err,
max_ht->early_overrun_err);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "crc32_good:",
+ fmt_table, "crc32_good:",
le32_to_cpu(ht->crc32_good), accum_ht->crc32_good,
delta_ht->crc32_good, max_ht->crc32_good);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "crc32_err:",
+ fmt_table, "crc32_err:",
le32_to_cpu(ht->crc32_err), accum_ht->crc32_err,
delta_ht->crc32_err, max_ht->crc32_err);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "mh_format_err:",
+ fmt_table, "mh_format_err:",
le32_to_cpu(ht->mh_format_err),
accum_ht->mh_format_err,
delta_ht->mh_format_err, max_ht->mh_format_err);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "agg_crc32_good:",
+ fmt_table, "agg_crc32_good:",
le32_to_cpu(ht->agg_crc32_good),
accum_ht->agg_crc32_good,
delta_ht->agg_crc32_good, max_ht->agg_crc32_good);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "agg_mpdu_cnt:",
+ fmt_table, "agg_mpdu_cnt:",
le32_to_cpu(ht->agg_mpdu_cnt),
accum_ht->agg_mpdu_cnt,
delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "agg_cnt:",
+ fmt_table, "agg_cnt:",
le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt,
delta_ht->agg_cnt, max_ht->agg_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "unsupport_mcs:",
+ fmt_table, "unsupport_mcs:",
le32_to_cpu(ht->unsupport_mcs),
accum_ht->unsupport_mcs,
delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
@@ -584,7 +536,8 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file,
* the last statistics notification from uCode
* might not reflect the current uCode activity
*/
- if (priv->cfg->bt_statistics) {
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->bt_statistics) {
tx = &priv->_agn.statistics_bt.tx;
accum_tx = &priv->_agn.accum_statistics_bt.tx;
delta_tx = &priv->_agn.delta_statistics_bt.tx;
@@ -597,166 +550,141 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file,
}
pos += iwl_statistics_flag(priv, buf, bufsz);
- pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
- "acumulative delta max\n",
- "Statistics_Tx:");
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "preamble:",
+ fmt_header, "Statistics_Tx:");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "preamble:",
le32_to_cpu(tx->preamble_cnt),
accum_tx->preamble_cnt,
delta_tx->preamble_cnt, max_tx->preamble_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "rx_detected_cnt:",
+ fmt_table, "rx_detected_cnt:",
le32_to_cpu(tx->rx_detected_cnt),
accum_tx->rx_detected_cnt,
delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "bt_prio_defer_cnt:",
+ fmt_table, "bt_prio_defer_cnt:",
le32_to_cpu(tx->bt_prio_defer_cnt),
accum_tx->bt_prio_defer_cnt,
delta_tx->bt_prio_defer_cnt,
max_tx->bt_prio_defer_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "bt_prio_kill_cnt:",
+ fmt_table, "bt_prio_kill_cnt:",
le32_to_cpu(tx->bt_prio_kill_cnt),
accum_tx->bt_prio_kill_cnt,
delta_tx->bt_prio_kill_cnt,
max_tx->bt_prio_kill_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "few_bytes_cnt:",
+ fmt_table, "few_bytes_cnt:",
le32_to_cpu(tx->few_bytes_cnt),
accum_tx->few_bytes_cnt,
delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "cts_timeout:",
+ fmt_table, "cts_timeout:",
le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
delta_tx->cts_timeout, max_tx->cts_timeout);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "ack_timeout:",
+ fmt_table, "ack_timeout:",
le32_to_cpu(tx->ack_timeout),
accum_tx->ack_timeout,
delta_tx->ack_timeout, max_tx->ack_timeout);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "expected_ack_cnt:",
+ fmt_table, "expected_ack_cnt:",
le32_to_cpu(tx->expected_ack_cnt),
accum_tx->expected_ack_cnt,
delta_tx->expected_ack_cnt,
max_tx->expected_ack_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "actual_ack_cnt:",
+ fmt_table, "actual_ack_cnt:",
le32_to_cpu(tx->actual_ack_cnt),
accum_tx->actual_ack_cnt,
delta_tx->actual_ack_cnt,
max_tx->actual_ack_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "dump_msdu_cnt:",
+ fmt_table, "dump_msdu_cnt:",
le32_to_cpu(tx->dump_msdu_cnt),
accum_tx->dump_msdu_cnt,
delta_tx->dump_msdu_cnt,
max_tx->dump_msdu_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "abort_nxt_frame_mismatch:",
+ fmt_table, "abort_nxt_frame_mismatch:",
le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
accum_tx->burst_abort_next_frame_mismatch_cnt,
delta_tx->burst_abort_next_frame_mismatch_cnt,
max_tx->burst_abort_next_frame_mismatch_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "abort_missing_nxt_frame:",
+ fmt_table, "abort_missing_nxt_frame:",
le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
accum_tx->burst_abort_missing_next_frame_cnt,
delta_tx->burst_abort_missing_next_frame_cnt,
max_tx->burst_abort_missing_next_frame_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "cts_timeout_collision:",
+ fmt_table, "cts_timeout_collision:",
le32_to_cpu(tx->cts_timeout_collision),
accum_tx->cts_timeout_collision,
delta_tx->cts_timeout_collision,
max_tx->cts_timeout_collision);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "ack_ba_timeout_collision:",
+ fmt_table, "ack_ba_timeout_collision:",
le32_to_cpu(tx->ack_or_ba_timeout_collision),
accum_tx->ack_or_ba_timeout_collision,
delta_tx->ack_or_ba_timeout_collision,
max_tx->ack_or_ba_timeout_collision);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "agg ba_timeout:",
+ fmt_table, "agg ba_timeout:",
le32_to_cpu(tx->agg.ba_timeout),
accum_tx->agg.ba_timeout,
delta_tx->agg.ba_timeout,
max_tx->agg.ba_timeout);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "agg ba_resched_frames:",
+ fmt_table, "agg ba_resched_frames:",
le32_to_cpu(tx->agg.ba_reschedule_frames),
accum_tx->agg.ba_reschedule_frames,
delta_tx->agg.ba_reschedule_frames,
max_tx->agg.ba_reschedule_frames);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "agg scd_query_agg_frame:",
+ fmt_table, "agg scd_query_agg_frame:",
le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
accum_tx->agg.scd_query_agg_frame_cnt,
delta_tx->agg.scd_query_agg_frame_cnt,
max_tx->agg.scd_query_agg_frame_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "agg scd_query_no_agg:",
+ fmt_table, "agg scd_query_no_agg:",
le32_to_cpu(tx->agg.scd_query_no_agg),
accum_tx->agg.scd_query_no_agg,
delta_tx->agg.scd_query_no_agg,
max_tx->agg.scd_query_no_agg);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "agg scd_query_agg:",
+ fmt_table, "agg scd_query_agg:",
le32_to_cpu(tx->agg.scd_query_agg),
accum_tx->agg.scd_query_agg,
delta_tx->agg.scd_query_agg,
max_tx->agg.scd_query_agg);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "agg scd_query_mismatch:",
+ fmt_table, "agg scd_query_mismatch:",
le32_to_cpu(tx->agg.scd_query_mismatch),
accum_tx->agg.scd_query_mismatch,
delta_tx->agg.scd_query_mismatch,
max_tx->agg.scd_query_mismatch);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "agg frame_not_ready:",
+ fmt_table, "agg frame_not_ready:",
le32_to_cpu(tx->agg.frame_not_ready),
accum_tx->agg.frame_not_ready,
delta_tx->agg.frame_not_ready,
max_tx->agg.frame_not_ready);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "agg underrun:",
+ fmt_table, "agg underrun:",
le32_to_cpu(tx->agg.underrun),
accum_tx->agg.underrun,
delta_tx->agg.underrun, max_tx->agg.underrun);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "agg bt_prio_kill:",
+ fmt_table, "agg bt_prio_kill:",
le32_to_cpu(tx->agg.bt_prio_kill),
accum_tx->agg.bt_prio_kill,
delta_tx->agg.bt_prio_kill,
max_tx->agg.bt_prio_kill);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "agg rx_ba_rsp_cnt:",
+ fmt_table, "agg rx_ba_rsp_cnt:",
le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
accum_tx->agg.rx_ba_rsp_cnt,
delta_tx->agg.rx_ba_rsp_cnt,
@@ -767,15 +695,15 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file,
"tx power: (1/2 dB step)\n");
if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a)
pos += scnprintf(buf + pos, bufsz - pos,
- "\tantenna A: 0x%X\n",
+ fmt_hex, "antenna A:",
tx->tx_power.ant_a);
if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b)
pos += scnprintf(buf + pos, bufsz - pos,
- "\tantenna B: 0x%X\n",
+ fmt_hex, "antenna B:",
tx->tx_power.ant_b);
if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c)
pos += scnprintf(buf + pos, bufsz - pos,
- "\tantenna C: 0x%X\n",
+ fmt_hex, "antenna C:",
tx->tx_power.ant_c);
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
@@ -809,7 +737,8 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
* the last statistics notification from uCode
* might not reflect the current uCode activity
*/
- if (priv->cfg->bt_statistics) {
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->bt_statistics) {
general = &priv->_agn.statistics_bt.general.common;
dbg = &priv->_agn.statistics_bt.general.common.dbg;
div = &priv->_agn.statistics_bt.general.common.div;
@@ -838,84 +767,72 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
}
pos += iwl_statistics_flag(priv, buf, bufsz);
- pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
- "acumulative delta max\n",
- "Statistics_General:");
- pos += scnprintf(buf + pos, bufsz - pos, " %-30s %10u\n",
- "temperature:",
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_header, "Statistics_General:");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_value, "temperature:",
le32_to_cpu(general->temperature));
- pos += scnprintf(buf + pos, bufsz - pos, " %-30s %10u\n",
- "temperature_m:",
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_value, "temperature_m:",
le32_to_cpu(general->temperature_m));
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "burst_check:",
+ fmt_value, "ttl_timestamp:",
+ le32_to_cpu(general->ttl_timestamp));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "burst_check:",
le32_to_cpu(dbg->burst_check),
accum_dbg->burst_check,
delta_dbg->burst_check, max_dbg->burst_check);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "burst_count:",
+ fmt_table, "burst_count:",
le32_to_cpu(dbg->burst_count),
accum_dbg->burst_count,
delta_dbg->burst_count, max_dbg->burst_count);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "wait_for_silence_timeout_count:",
+ fmt_table, "wait_for_silence_timeout_count:",
le32_to_cpu(dbg->wait_for_silence_timeout_cnt),
accum_dbg->wait_for_silence_timeout_cnt,
delta_dbg->wait_for_silence_timeout_cnt,
max_dbg->wait_for_silence_timeout_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "sleep_time:",
+ fmt_table, "sleep_time:",
le32_to_cpu(general->sleep_time),
accum_general->sleep_time,
delta_general->sleep_time, max_general->sleep_time);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "slots_out:",
+ fmt_table, "slots_out:",
le32_to_cpu(general->slots_out),
accum_general->slots_out,
delta_general->slots_out, max_general->slots_out);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "slots_idle:",
+ fmt_table, "slots_idle:",
le32_to_cpu(general->slots_idle),
accum_general->slots_idle,
delta_general->slots_idle, max_general->slots_idle);
- pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp:\t\t\t%u\n",
- le32_to_cpu(general->ttl_timestamp));
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "tx_on_a:",
+ fmt_table, "tx_on_a:",
le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
delta_div->tx_on_a, max_div->tx_on_a);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "tx_on_b:",
+ fmt_table, "tx_on_b:",
le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
delta_div->tx_on_b, max_div->tx_on_b);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "exec_time:",
+ fmt_table, "exec_time:",
le32_to_cpu(div->exec_time), accum_div->exec_time,
delta_div->exec_time, max_div->exec_time);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "probe_time:",
+ fmt_table, "probe_time:",
le32_to_cpu(div->probe_time), accum_div->probe_time,
delta_div->probe_time, max_div->probe_time);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "rx_enable_counter:",
+ fmt_table, "rx_enable_counter:",
le32_to_cpu(general->rx_enable_counter),
accum_general->rx_enable_counter,
delta_general->rx_enable_counter,
max_general->rx_enable_counter);
pos += scnprintf(buf + pos, bufsz - pos,
- " %-30s %10u %10u %10u %10u\n",
- "num_of_sos_states:",
+ fmt_table, "num_of_sos_states:",
le32_to_cpu(general->num_of_sos_states),
accum_general->num_of_sos_states,
delta_general->num_of_sos_states,
@@ -1011,3 +928,147 @@ ssize_t iwl_ucode_bt_stats_read(struct file *file,
kfree(buf);
return ret;
}
+
+ssize_t iwl_reply_tx_error_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0;
+ char *buf;
+ int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) +
+ (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200;
+ ssize_t ret;
+
+ if (!iwl_is_alive(priv))
+ 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, "Statistics_TX_Error:\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY),
+ priv->_agn.reply_tx_stats.pp_delay);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES),
+ priv->_agn.reply_tx_stats.pp_few_bytes);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO),
+ priv->_agn.reply_tx_stats.pp_bt_prio);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD),
+ priv->_agn.reply_tx_stats.pp_quiet_period);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK),
+ priv->_agn.reply_tx_stats.pp_calc_ttak);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+ iwl_get_tx_fail_reason(
+ TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY),
+ priv->_agn.reply_tx_stats.int_crossed_retry);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT),
+ priv->_agn.reply_tx_stats.short_limit);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT),
+ priv->_agn.reply_tx_stats.long_limit);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN),
+ priv->_agn.reply_tx_stats.fifo_underrun);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW),
+ priv->_agn.reply_tx_stats.drain_flow);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH),
+ priv->_agn.reply_tx_stats.rfkill_flush);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE),
+ priv->_agn.reply_tx_stats.life_expire);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS),
+ priv->_agn.reply_tx_stats.dest_ps);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED),
+ priv->_agn.reply_tx_stats.host_abort);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY),
+ priv->_agn.reply_tx_stats.pp_delay);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID),
+ priv->_agn.reply_tx_stats.sta_invalid);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED),
+ priv->_agn.reply_tx_stats.frag_drop);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE),
+ priv->_agn.reply_tx_stats.tid_disable);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED),
+ priv->_agn.reply_tx_stats.fifo_flush);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+ iwl_get_tx_fail_reason(
+ TX_STATUS_FAIL_INSUFFICIENT_CF_POLL),
+ priv->_agn.reply_tx_stats.insuff_cf_poll);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX),
+ priv->_agn.reply_tx_stats.fail_hw_drop);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+ iwl_get_tx_fail_reason(
+ TX_STATUS_FAIL_NO_BEACON_ON_RADAR),
+ priv->_agn.reply_tx_stats.sta_color_mismatch);
+ pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
+ priv->_agn.reply_tx_stats.unknown);
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\nStatistics_Agg_TX_Error:\n");
+
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK),
+ priv->_agn.reply_agg_tx_stats.underrun);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK),
+ priv->_agn.reply_agg_tx_stats.bt_prio);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK),
+ priv->_agn.reply_agg_tx_stats.few_bytes);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK),
+ priv->_agn.reply_agg_tx_stats.abort);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(
+ AGG_TX_STATE_LAST_SENT_TTL_MSK),
+ priv->_agn.reply_agg_tx_stats.last_sent_ttl);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(
+ AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK),
+ priv->_agn.reply_agg_tx_stats.last_sent_try);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(
+ AGG_TX_STATE_LAST_SENT_BT_KILL_MSK),
+ priv->_agn.reply_agg_tx_stats.last_sent_bt_kill);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK),
+ priv->_agn.reply_agg_tx_stats.scd_query);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(
+ AGG_TX_STATE_TEST_BAD_CRC32_MSK),
+ priv->_agn.reply_agg_tx_stats.bad_crc32);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK),
+ priv->_agn.reply_agg_tx_stats.response);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK),
+ priv->_agn.reply_agg_tx_stats.dump_tx);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK),
+ priv->_agn.reply_agg_tx_stats.delay_tx);
+ pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
+ priv->_agn.reply_agg_tx_stats.unknown);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
index bbdce5913ac7..f2573b5486cd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
@@ -39,6 +39,8 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos);
ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos);
+ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos);
#else
static ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
@@ -60,4 +62,9 @@ static ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf,
{
return 0;
}
+static ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ return 0;
+}
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
new file mode 100644
index 000000000000..a650baba0809
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
@@ -0,0 +1,454 @@
+/******************************************************************************
+ *
+ * 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 - 2010 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 - 2010 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 BANDS ****************************
+ *
+ * The iwl_eeprom_band definitions below provide the mapping from the
+ * EEPROM contents to the specific channel number supported for each
+ * band.
+ *
+ * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3
+ * definition below maps to physical channel 42 in the 5.2GHz spectrum.
+ * The specific geography and calibration information for that channel
+ * is contained in the eeprom map itself.
+ *
+ * During init, we copy the eeprom information and channel map
+ * information into priv->channel_info_24/52 and priv->channel_map_24/52
+ *
+ * channel_map_24/52 provides the index in the channel_info array for a
+ * given channel. We have to have two separate maps as there is channel
+ * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and
+ * band_2
+ *
+ * A value of 0xff stored in the channel_map indicates that the channel
+ * is not supported by the hardware at all.
+ *
+ * A value of 0xfe in the channel_map indicates that the channel is not
+ * valid for Tx with the current hardware. This means that
+ * while the system can tune and receive on a given channel, it may not
+ * be able to associate or transmit any frames on that
+ * channel. There is no corresponding channel information for that
+ * entry.
+ *
+ *********************************************************************/
+
+/**
+ * struct iwl_txpwr_section: eeprom section information
+ * @offset: indirect address into eeprom image
+ * @count: number of "struct iwl_eeprom_enhanced_txpwr" in this section
+ * @band: band type for the section
+ * @is_common - true: common section, false: channel section
+ * @is_cck - true: cck section, false: not cck section
+ * @is_ht_40 - true: all channel in the section are HT40 channel,
+ * false: legacy or HT 20 MHz
+ * ignore if it is common section
+ * @iwl_eeprom_section_channel: channel array in the section,
+ * ignore if common section
+ */
+struct iwl_txpwr_section {
+ u32 offset;
+ u8 count;
+ enum ieee80211_band band;
+ bool is_common;
+ bool is_cck;
+ bool is_ht40;
+ u8 iwl_eeprom_section_channel[EEPROM_MAX_TXPOWER_SECTION_ELEMENTS];
+};
+
+/**
+ * section 1 - 3 are regulatory tx power apply to all channels based on
+ * modulation: CCK, OFDM
+ * Band: 2.4GHz, 5.2GHz
+ * section 4 - 10 are regulatory tx power apply to specified channels
+ * For example:
+ * 1L - Channel 1 Legacy
+ * 1HT - Channel 1 HT
+ * (1,+1) - Channel 1 HT40 "_above_"
+ *
+ * Section 1: all CCK channels
+ * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40) channels
+ * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels
+ * Section 4: 2.4 GHz 20MHz channels: 1L, 1HT, 2L, 2HT, 10L, 10HT, 11L, 11HT
+ * Section 5: 2.4 GHz 40MHz channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1)
+ * Section 6: 5.2 GHz 20MHz channels: 36L, 64L, 100L, 36HT, 64HT, 100HT
+ * Section 7: 5.2 GHz 40MHz channels: (36,+1) (60,+1) (100,+1)
+ * Section 8: 2.4 GHz channel: 13L, 13HT
+ * Section 9: 2.4 GHz channel: 140L, 140HT
+ * Section 10: 2.4 GHz 40MHz channels: (132,+1) (44,+1)
+ *
+ */
+static const struct iwl_txpwr_section enhinfo[] = {
+ { EEPROM_LB_CCK_20_COMMON, 1, IEEE80211_BAND_2GHZ, true, true, false },
+ { EEPROM_LB_OFDM_COMMON, 3, IEEE80211_BAND_2GHZ, true, false, false },
+ { EEPROM_HB_OFDM_COMMON, 3, IEEE80211_BAND_5GHZ, true, false, false },
+ { EEPROM_LB_OFDM_20_BAND, 8, IEEE80211_BAND_2GHZ,
+ false, false, false,
+ {1, 1, 2, 2, 10, 10, 11, 11 } },
+ { EEPROM_LB_OFDM_HT40_BAND, 5, IEEE80211_BAND_2GHZ,
+ false, false, true,
+ { 1, 2, 6, 7, 9 } },
+ { EEPROM_HB_OFDM_20_BAND, 6, IEEE80211_BAND_5GHZ,
+ false, false, false,
+ { 36, 64, 100, 36, 64, 100 } },
+ { EEPROM_HB_OFDM_HT40_BAND, 3, IEEE80211_BAND_5GHZ,
+ false, false, true,
+ { 36, 60, 100 } },
+ { EEPROM_LB_OFDM_20_CHANNEL_13, 2, IEEE80211_BAND_2GHZ,
+ false, false, false,
+ { 13, 13 } },
+ { EEPROM_HB_OFDM_20_CHANNEL_140, 2, IEEE80211_BAND_5GHZ,
+ false, false, false,
+ { 140, 140 } },
+ { EEPROM_HB_OFDM_HT40_BAND_1, 2, IEEE80211_BAND_5GHZ,
+ false, false, true,
+ { 132, 44 } },
+};
+
+/******************************************************************************
+ *
+ * EEPROM related functions
+ *
+******************************************************************************/
+
+/*
+ * The device's EEPROM semaphore prevents conflicts between driver and uCode
+ * when accessing the EEPROM; each access is a series of pulses to/from the
+ * EEPROM chip, not a single event, so even reads could conflict if they
+ * weren't arbitrated by the semaphore.
+ */
+int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv)
+{
+ u16 count;
+ int ret;
+
+ for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
+ /* Request semaphore */
+ iwl_set_bit(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,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+ EEPROM_SEM_TIMEOUT);
+ if (ret >= 0) {
+ IWL_DEBUG_IO(priv,
+ "Acquired semaphore after %d tries.\n",
+ count+1);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv)
+{
+ iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+
+}
+
+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 = priv->cfg->ops->lib->eeprom_ops.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;
+
+}
+
+void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac)
+{
+ const u8 *addr = priv->cfg->ops->lib->eeprom_ops.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) */
+
+ IWL_DEBUG_INFO(priv, "%d - "
+ "chain_a: %d dB chain_b: %d dB "
+ "chain_c: %d dB mimo2: %d dB mimo3: %d dB\n",
+ element,
+ enhanced_txpower[element].chain_a_max >> 1,
+ enhanced_txpower[element].chain_b_max >> 1,
+ enhanced_txpower[element].chain_c_max >> 1,
+ enhanced_txpower[element].mimo2_max >> 1,
+ enhanced_txpower[element].mimo3_max >> 1);
+ /* 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);
+}
+
+/**
+ * iwl_update_common_txpower: update channel tx power
+ * update tx power per band based on EEPROM enhanced tx power info.
+ */
+static s8 iwl_update_common_txpower(struct iwl_priv *priv,
+ struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
+ int section, int element, s8 *max_txpower_in_half_dbm)
+{
+ struct iwl_channel_info *ch_info;
+ int ch;
+ bool is_ht40 = false;
+ s8 max_txpower_avg; /* (dBm) */
+
+ /* it is common section, contain all type (Legacy, HT and HT40)
+ * based on the element in the section to determine
+ * is it HT 40 or not
+ */
+ if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX)
+ is_ht40 = true;
+ max_txpower_avg =
+ iwl_get_max_txpower_avg(priv, enhanced_txpower,
+ element, max_txpower_in_half_dbm);
+
+ ch_info = priv->channel_info;
+
+ for (ch = 0; ch < priv->channel_count; ch++) {
+ /* find matching band and update tx power if needed */
+ if ((ch_info->band == enhinfo[section].band) &&
+ (ch_info->max_power_avg < max_txpower_avg) &&
+ (!is_ht40)) {
+ /* Update regulatory-based run-time data */
+ ch_info->max_power_avg = ch_info->curr_txpow =
+ max_txpower_avg;
+ ch_info->scan_power = max_txpower_avg;
+ }
+ if ((ch_info->band == enhinfo[section].band) && is_ht40 &&
+ (ch_info->ht40_max_power_avg < max_txpower_avg)) {
+ /* Update regulatory-based run-time data */
+ ch_info->ht40_max_power_avg = max_txpower_avg;
+ }
+ ch_info++;
+ }
+ return max_txpower_avg;
+}
+
+/**
+ * iwl_update_channel_txpower: update channel tx power
+ * update channel tx power based on EEPROM enhanced tx power info.
+ */
+static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
+ struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
+ int section, int element, s8 *max_txpower_in_half_dbm)
+{
+ struct iwl_channel_info *ch_info;
+ int ch;
+ u8 channel;
+ s8 max_txpower_avg; /* (dBm) */
+
+ channel = enhinfo[section].iwl_eeprom_section_channel[element];
+ max_txpower_avg =
+ iwl_get_max_txpower_avg(priv, enhanced_txpower,
+ element, max_txpower_in_half_dbm);
+
+ ch_info = priv->channel_info;
+ for (ch = 0; ch < priv->channel_count; ch++) {
+ /* find matching channel and update tx power if needed */
+ if (ch_info->channel == channel) {
+ if ((ch_info->max_power_avg < max_txpower_avg) &&
+ (!enhinfo[section].is_ht40)) {
+ /* Update regulatory-based run-time data */
+ ch_info->max_power_avg = max_txpower_avg;
+ ch_info->curr_txpow = max_txpower_avg;
+ ch_info->scan_power = max_txpower_avg;
+ }
+ if ((enhinfo[section].is_ht40) &&
+ (ch_info->ht40_max_power_avg < max_txpower_avg)) {
+ /* Update regulatory-based run-time data */
+ ch_info->ht40_max_power_avg = max_txpower_avg;
+ }
+ break;
+ }
+ ch_info++;
+ }
+ return max_txpower_avg;
+}
+
+/**
+ * iwlcore_eeprom_enhanced_txpower: process enhanced tx power info
+ */
+void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
+{
+ int eeprom_section_count = 0;
+ int section, element;
+ struct iwl_eeprom_enhanced_txpwr *enhanced_txpower;
+ u32 offset;
+ s8 max_txpower_avg; /* (dBm) */
+ s8 max_txpower_in_half_dbm; /* (half-dBm) */
+
+ /* Loop through all the sections
+ * adjust bands and channel's max tx power
+ * Set the tx_power_user_lmt to the highest power
+ * supported by any channels and chains
+ */
+ for (section = 0; section < ARRAY_SIZE(enhinfo); section++) {
+ eeprom_section_count = enhinfo[section].count;
+ offset = enhinfo[section].offset;
+ enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *)
+ iwl_eeprom_query_addr(priv, offset);
+
+ /*
+ * check for valid entry -
+ * different version of EEPROM might contain different set
+ * of enhanced tx power table
+ * always check for valid entry before process
+ * the information
+ */
+ if (!enhanced_txpower->common || enhanced_txpower->reserved)
+ continue;
+
+ for (element = 0; element < eeprom_section_count; element++) {
+ if (enhinfo[section].is_common)
+ max_txpower_avg =
+ iwl_update_common_txpower(priv,
+ enhanced_txpower, section,
+ element,
+ &max_txpower_in_half_dbm);
+ else
+ max_txpower_avg =
+ iwl_update_channel_txpower(priv,
+ enhanced_txpower, section,
+ element,
+ &max_txpower_in_half_dbm);
+
+ /* Update the tx_power_user_lmt to the highest power
+ * supported by any channel */
+ if (max_txpower_avg > priv->tx_power_user_lmt)
+ priv->tx_power_user_lmt = max_txpower_avg;
+
+ /*
+ * Update the tx_power_lmt_in_half_dbm to
+ * the highest power supported by any channel
+ */
+ if (max_txpower_in_half_dbm >
+ priv->tx_power_lmt_in_half_dbm)
+ priv->tx_power_lmt_in_half_dbm =
+ max_txpower_in_half_dbm;
+ }
+ }
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
index 75b901b3eb1e..ffb2f4111ad0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
@@ -37,12 +37,13 @@
#include "iwl-io.h"
#include "iwl-agn.h"
-int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
+int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
{
int ret = 0;
struct iwl5000_rxon_assoc_cmd rxon_assoc;
- const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
- const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+ const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
+ const struct iwl_rxon_cmd *rxon2 = &ctx->active;
if ((rxon1->flags == rxon2->flags) &&
(rxon1->filter_flags == rxon2->filter_flags) &&
@@ -60,23 +61,23 @@ int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
return 0;
}
- rxon_assoc.flags = priv->staging_rxon.flags;
- rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
- rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
- rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+ rxon_assoc.flags = ctx->staging.flags;
+ rxon_assoc.filter_flags = ctx->staging.filter_flags;
+ rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
+ rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
rxon_assoc.reserved1 = 0;
rxon_assoc.reserved2 = 0;
rxon_assoc.reserved3 = 0;
rxon_assoc.ofdm_ht_single_stream_basic_rates =
- priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
+ ctx->staging.ofdm_ht_single_stream_basic_rates;
rxon_assoc.ofdm_ht_dual_stream_basic_rates =
- priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
- rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
+ ctx->staging.ofdm_ht_dual_stream_basic_rates;
+ rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
rxon_assoc.ofdm_ht_triple_stream_basic_rates =
- priv->staging_rxon.ofdm_ht_triple_stream_basic_rates;
- rxon_assoc.acquisition_data = priv->staging_rxon.acquisition_data;
+ ctx->staging.ofdm_ht_triple_stream_basic_rates;
+ rxon_assoc.acquisition_data = ctx->staging.acquisition_data;
- ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
+ ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd,
sizeof(rxon_assoc), &rxon_assoc, NULL);
if (ret)
return ret;
@@ -136,7 +137,7 @@ static void iwlagn_gain_computation(struct iwl_priv *priv,
continue;
}
- delta_g = (priv->cfg->chain_noise_scale *
+ delta_g = (priv->cfg->base_params->chain_noise_scale *
((s32)average_noise[default_chain] -
(s32)average_noise[i])) / 1500;
@@ -184,7 +185,7 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
int ret;
if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
- iwl_is_associated(priv)) {
+ iwl_is_any_associated(priv)) {
struct iwl_calib_chain_noise_reset_cmd cmd;
/* clear data for chain noise calibration algorithm */
@@ -221,7 +222,8 @@ static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
return;
}
- if (priv->cfg->use_rts_for_aggregation &&
+ if (priv->cfg->ht_params &&
+ priv->cfg->ht_params->use_rts_for_aggregation &&
info->flags & IEEE80211_TX_CTL_AMPDU) {
*tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
return;
@@ -235,13 +237,13 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv,
/* data from PHY/DSP regarding signal strength, etc.,
* contents are always there, not configurable by host
*/
- struct iwl5000_non_cfg_phy *ncphy =
- (struct iwl5000_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
+ struct iwlagn_non_cfg_phy *ncphy =
+ (struct iwlagn_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
u8 agc;
- val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_AGC_IDX]);
- agc = (val & IWL50_OFDM_AGC_MSK) >> IWL50_OFDM_AGC_BIT_POS;
+ val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_AGC_IDX]);
+ agc = (val & IWLAGN_OFDM_AGC_MSK) >> IWLAGN_OFDM_AGC_BIT_POS;
/* Find max rssi among 3 possible receivers.
* These values are measured by the digital signal processor (DSP).
@@ -249,11 +251,14 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv,
* if the radio's automatic gain control (AGC) is working right.
* AGC value (see below) will provide the "interesting" info.
*/
- val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_AB_IDX]);
- rssi_a = (val & IWL50_OFDM_RSSI_A_MSK) >> IWL50_OFDM_RSSI_A_BIT_POS;
- rssi_b = (val & IWL50_OFDM_RSSI_B_MSK) >> IWL50_OFDM_RSSI_B_BIT_POS;
- val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_C_IDX]);
- rssi_c = (val & IWL50_OFDM_RSSI_C_MSK) >> IWL50_OFDM_RSSI_C_BIT_POS;
+ val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_AB_IDX]);
+ rssi_a = (val & IWLAGN_OFDM_RSSI_INBAND_A_BITMSK) >>
+ IWLAGN_OFDM_RSSI_A_BIT_POS;
+ rssi_b = (val & IWLAGN_OFDM_RSSI_INBAND_B_BITMSK) >>
+ IWLAGN_OFDM_RSSI_B_BIT_POS;
+ val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_C_IDX]);
+ rssi_c = (val & IWLAGN_OFDM_RSSI_INBAND_C_BITMSK) >>
+ IWLAGN_OFDM_RSSI_C_BIT_POS;
max_rssi = max_t(u32, rssi_a, rssi_b);
max_rssi = max_t(u32, max_rssi, rssi_c);
@@ -266,12 +271,109 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv,
return max_rssi - agc - IWLAGN_RSSI_OFFSET;
}
+static int iwlagn_set_pan_params(struct iwl_priv *priv)
+{
+ struct iwl_wipan_params_cmd cmd;
+ struct iwl_rxon_context *ctx_bss, *ctx_pan;
+ int slot0 = 300, slot1 = 0;
+ int ret;
+
+ if (priv->valid_contexts == BIT(IWL_RXON_CTX_BSS))
+ return 0;
+
+ BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
+ lockdep_assert_held(&priv->mutex);
+
+ ctx_bss = &priv->contexts[IWL_RXON_CTX_BSS];
+ ctx_pan = &priv->contexts[IWL_RXON_CTX_PAN];
+
+ /*
+ * If the PAN context is inactive, then we don't need
+ * to update the PAN parameters, the last thing we'll
+ * have done before it goes inactive is making the PAN
+ * parameters be WLAN-only.
+ */
+ if (!ctx_pan->is_active)
+ return 0;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ /* only 2 slots are currently allowed */
+ cmd.num_slots = 2;
+
+ cmd.slots[0].type = 0; /* BSS */
+ cmd.slots[1].type = 1; /* PAN */
+
+ if (ctx_bss->vif && ctx_pan->vif) {
+ int bcnint = ctx_pan->vif->bss_conf.beacon_int;
+
+ /* should be set, but seems unused?? */
+ cmd.flags |= cpu_to_le16(IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE);
+
+ if (ctx_pan->vif->type == NL80211_IFTYPE_AP &&
+ bcnint &&
+ bcnint != ctx_bss->vif->bss_conf.beacon_int) {
+ IWL_ERR(priv,
+ "beacon intervals don't match (%d, %d)\n",
+ ctx_bss->vif->bss_conf.beacon_int,
+ ctx_pan->vif->bss_conf.beacon_int);
+ } else
+ bcnint = max_t(int, bcnint,
+ ctx_bss->vif->bss_conf.beacon_int);
+ if (!bcnint)
+ bcnint = DEFAULT_BEACON_INTERVAL;
+ slot0 = bcnint / 2;
+ slot1 = bcnint - slot0;
+
+ if (test_bit(STATUS_SCAN_HW, &priv->status) ||
+ (!ctx_bss->vif->bss_conf.idle &&
+ !ctx_bss->vif->bss_conf.assoc)) {
+ slot0 = bcnint * 3 - 20;
+ slot1 = 20;
+ } else if (!ctx_pan->vif->bss_conf.idle &&
+ !ctx_pan->vif->bss_conf.assoc) {
+ slot1 = bcnint * 3 - 20;
+ slot0 = 20;
+ }
+ } else if (ctx_pan->vif) {
+ slot0 = 0;
+ slot1 = max_t(int, 1, ctx_pan->vif->bss_conf.dtim_period) *
+ ctx_pan->vif->bss_conf.beacon_int;
+ slot1 = max_t(int, DEFAULT_BEACON_INTERVAL, slot1);
+
+ if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+ slot0 = slot1 * 3 - 20;
+ slot1 = 20;
+ }
+ }
+
+ cmd.slots[0].width = cpu_to_le16(slot0);
+ cmd.slots[1].width = cpu_to_le16(slot1);
+
+ ret = iwl_send_cmd_pdu(priv, REPLY_WIPAN_PARAMS, sizeof(cmd), &cmd);
+ if (ret)
+ IWL_ERR(priv, "Error setting PAN parameters (%d)\n", ret);
+
+ return ret;
+}
+
struct iwl_hcmd_ops iwlagn_hcmd = {
.rxon_assoc = iwlagn_send_rxon_assoc,
- .commit_rxon = iwl_commit_rxon,
- .set_rxon_chain = iwl_set_rxon_chain,
+ .commit_rxon = iwlagn_commit_rxon,
+ .set_rxon_chain = iwlagn_set_rxon_chain,
.set_tx_ant = iwlagn_send_tx_ant_config,
.send_bt_config = iwl_send_bt_config,
+ .set_pan_params = iwlagn_set_pan_params,
+};
+
+struct iwl_hcmd_ops iwlagn_bt_hcmd = {
+ .rxon_assoc = iwlagn_send_rxon_assoc,
+ .commit_rxon = iwlagn_commit_rxon,
+ .set_rxon_chain = iwlagn_set_rxon_chain,
+ .set_tx_ant = iwlagn_send_tx_ant_config,
+ .send_bt_config = iwlagn_send_advance_bt_config,
+ .set_pan_params = iwlagn_set_pan_params,
};
struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = {
@@ -282,4 +384,5 @@ struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = {
.tx_cmd_protection = iwlagn_tx_cmd_protection,
.calc_rssi = iwlagn_calc_rssi,
.request_scan = iwlagn_request_scan,
+ .post_scan = iwlagn_post_scan,
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c
index c92b2c0cbd91..a5dbfea1bfad 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c
@@ -59,7 +59,7 @@ void iwl_free_isr_ict(struct iwl_priv *priv)
int iwl_alloc_isr_ict(struct iwl_priv *priv)
{
- if (priv->cfg->use_isr_legacy)
+ if (priv->cfg->base_params->use_isr_legacy)
return 0;
/* allocate shrared data table */
priv->_agn.ict_tbl_vir =
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 8fd00a6e5120..b555edd53354 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -40,22 +40,195 @@
#include "iwl-agn.h"
#include "iwl-sta.h"
-static inline u32 iwlagn_get_scd_ssn(struct iwl5000_tx_resp *tx_resp)
+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->_agn.reply_tx_stats.pp_delay++;
+ break;
+ case TX_STATUS_POSTPONE_FEW_BYTES:
+ priv->_agn.reply_tx_stats.pp_few_bytes++;
+ break;
+ case TX_STATUS_POSTPONE_BT_PRIO:
+ priv->_agn.reply_tx_stats.pp_bt_prio++;
+ break;
+ case TX_STATUS_POSTPONE_QUIET_PERIOD:
+ priv->_agn.reply_tx_stats.pp_quiet_period++;
+ break;
+ case TX_STATUS_POSTPONE_CALC_TTAK:
+ priv->_agn.reply_tx_stats.pp_calc_ttak++;
+ break;
+ case TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY:
+ priv->_agn.reply_tx_stats.int_crossed_retry++;
+ break;
+ case TX_STATUS_FAIL_SHORT_LIMIT:
+ priv->_agn.reply_tx_stats.short_limit++;
+ break;
+ case TX_STATUS_FAIL_LONG_LIMIT:
+ priv->_agn.reply_tx_stats.long_limit++;
+ break;
+ case TX_STATUS_FAIL_FIFO_UNDERRUN:
+ priv->_agn.reply_tx_stats.fifo_underrun++;
+ break;
+ case TX_STATUS_FAIL_DRAIN_FLOW:
+ priv->_agn.reply_tx_stats.drain_flow++;
+ break;
+ case TX_STATUS_FAIL_RFKILL_FLUSH:
+ priv->_agn.reply_tx_stats.rfkill_flush++;
+ break;
+ case TX_STATUS_FAIL_LIFE_EXPIRE:
+ priv->_agn.reply_tx_stats.life_expire++;
+ break;
+ case TX_STATUS_FAIL_DEST_PS:
+ priv->_agn.reply_tx_stats.dest_ps++;
+ break;
+ case TX_STATUS_FAIL_HOST_ABORTED:
+ priv->_agn.reply_tx_stats.host_abort++;
+ break;
+ case TX_STATUS_FAIL_BT_RETRY:
+ priv->_agn.reply_tx_stats.bt_retry++;
+ break;
+ case TX_STATUS_FAIL_STA_INVALID:
+ priv->_agn.reply_tx_stats.sta_invalid++;
+ break;
+ case TX_STATUS_FAIL_FRAG_DROPPED:
+ priv->_agn.reply_tx_stats.frag_drop++;
+ break;
+ case TX_STATUS_FAIL_TID_DISABLE:
+ priv->_agn.reply_tx_stats.tid_disable++;
+ break;
+ case TX_STATUS_FAIL_FIFO_FLUSHED:
+ priv->_agn.reply_tx_stats.fifo_flush++;
+ break;
+ case TX_STATUS_FAIL_INSUFFICIENT_CF_POLL:
+ priv->_agn.reply_tx_stats.insuff_cf_poll++;
+ break;
+ case TX_STATUS_FAIL_PASSIVE_NO_RX:
+ priv->_agn.reply_tx_stats.fail_hw_drop++;
+ break;
+ case TX_STATUS_FAIL_NO_BEACON_ON_RADAR:
+ priv->_agn.reply_tx_stats.sta_color_mismatch++;
+ break;
+ default:
+ priv->_agn.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->_agn.reply_agg_tx_stats.underrun++;
+ break;
+ case AGG_TX_STATE_BT_PRIO_MSK:
+ priv->_agn.reply_agg_tx_stats.bt_prio++;
+ break;
+ case AGG_TX_STATE_FEW_BYTES_MSK:
+ priv->_agn.reply_agg_tx_stats.few_bytes++;
+ break;
+ case AGG_TX_STATE_ABORT_MSK:
+ priv->_agn.reply_agg_tx_stats.abort++;
+ break;
+ case AGG_TX_STATE_LAST_SENT_TTL_MSK:
+ priv->_agn.reply_agg_tx_stats.last_sent_ttl++;
+ break;
+ case AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK:
+ priv->_agn.reply_agg_tx_stats.last_sent_try++;
+ break;
+ case AGG_TX_STATE_LAST_SENT_BT_KILL_MSK:
+ priv->_agn.reply_agg_tx_stats.last_sent_bt_kill++;
+ break;
+ case AGG_TX_STATE_SCD_QUERY_MSK:
+ priv->_agn.reply_agg_tx_stats.scd_query++;
+ break;
+ case AGG_TX_STATE_TEST_BAD_CRC32_MSK:
+ priv->_agn.reply_agg_tx_stats.bad_crc32++;
+ break;
+ case AGG_TX_STATE_RESPONSE_MSK:
+ priv->_agn.reply_agg_tx_stats.response++;
+ break;
+ case AGG_TX_STATE_DUMP_TX_MSK:
+ priv->_agn.reply_agg_tx_stats.dump_tx++;
+ break;
+ case AGG_TX_STATE_DELAY_TX_MSK:
+ priv->_agn.reply_agg_tx_stats.delay_tx++;
+ break;
+ default:
+ priv->_agn.reply_agg_tx_stats.unknown++;
+ break;
+ }
+}
+
+static void iwlagn_set_tx_status(struct iwl_priv *priv,
+ struct ieee80211_tx_info *info,
+ 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);
+
+ 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 iwl5000_tx_resp *tx_resp,
+ 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_tx_info *info = NULL;
struct ieee80211_hdr *hdr = NULL;
- u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
int i, sh, idx;
u16 seq;
@@ -64,31 +237,20 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
agg->frame_count = tx_resp->frame_count;
agg->start_idx = start_idx;
- agg->rate_n_flags = rate_n_flags;
+ 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) {
/* Only one frame was attempted; no block-ack will arrive */
- status = le16_to_cpu(frame_status[0].status);
idx = start_idx;
- /* FIXME: code repetition */
IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
agg->frame_count, agg->start_idx, idx);
-
- info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb);
- info->status.rates[0].count = tx_resp->failure_frame + 1;
- info->flags &= ~IEEE80211_TX_CTL_AMPDU;
- info->flags |= iwl_tx_status_to_mac80211(status);
- iwlagn_hwrate_to_tx_control(priv, rate_n_flags, info);
-
- /* FIXME: code repetition end */
-
- IWL_DEBUG_TX_REPLY(priv, "1 Frame 0x%x failure :%d\n",
- status & 0xff, tx_resp->failure_frame);
- IWL_DEBUG_TX_REPLY(priv, "Rate Info rate_n_flags=%x\n", rate_n_flags);
-
+ iwlagn_set_tx_status(priv,
+ IEEE80211_SKB_CB(
+ priv->txq[txq_id].txb[idx].skb),
+ tx_resp, txq_id, true);
agg->wait_for_ba = 0;
} else {
/* Two or more frames were attempted; expect block-ack */
@@ -109,12 +271,20 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
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) {
@@ -220,7 +390,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
int index = SEQ_TO_INDEX(sequence);
struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct ieee80211_tx_info *info;
- struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+ struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
u32 status = le16_to_cpu(tx_resp->status.status);
int tid;
int sta_id;
@@ -238,8 +408,10 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
memset(&info->status, 0, sizeof(info->status));
- tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS;
- sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS;
+ 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);
if (txq->sched_retry) {
@@ -247,7 +419,15 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
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_WARN(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 */
@@ -274,20 +454,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
}
} else {
BUG_ON(txq_id != txq->swq_id);
-
- info->status.rates[0].count = tx_resp->failure_frame + 1;
- info->flags |= iwl_tx_status_to_mac80211(status);
- iwlagn_hwrate_to_tx_control(priv,
- le32_to_cpu(tx_resp->rate_n_flags),
- info);
-
- 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);
-
+ iwlagn_set_tx_status(priv, info, tx_resp, txq_id, false);
freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
@@ -326,7 +493,7 @@ int iwlagn_hw_valid_rtc_data_addr(u32 addr)
int iwlagn_send_tx_power(struct iwl_priv *priv)
{
- struct iwl5000_tx_power_dbm_cmd tx_power_cmd;
+ struct iwlagn_tx_power_dbm_cmd tx_power_cmd;
u8 tx_ant_cfg_cmd;
/* half dBm need to multiply */
@@ -347,8 +514,8 @@ int iwlagn_send_tx_power(struct iwl_priv *priv)
*/
tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm;
}
- tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED;
- tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO;
+ tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED;
+ tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO;
if (IWL_UCODE_API(priv->ucode_ver) == 1)
tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
@@ -425,7 +592,7 @@ const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv,
size_t offset)
{
u32 address = eeprom_indirect_address(priv, offset);
- BUG_ON(address >= priv->cfg->eeprom_size);
+ BUG_ON(address >= priv->cfg->base_params->eeprom_size);
return &priv->eeprom[address];
}
@@ -473,7 +640,7 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */
- if (!priv->cfg->use_isr_legacy)
+ if (!priv->cfg->base_params->use_isr_legacy)
rb_timeout = RX_RB_TIMEOUT;
if (priv->cfg->mod_params->amsdu_size_8K)
@@ -518,6 +685,23 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
return 0;
}
+static void iwlagn_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);
+}
+
int iwlagn_hw_nic_init(struct iwl_priv *priv)
{
unsigned long flags;
@@ -533,7 +717,7 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv)
spin_unlock_irqrestore(&priv->lock, flags);
- ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
+ iwlagn_set_pwr_vmain(priv);
priv->cfg->ops->lib->apm_ops.config(priv);
@@ -1098,7 +1282,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
if (chan->band != band)
continue;
- channel = ieee80211_frequency_to_channel(chan->center_freq);
+ channel = chan->hw_value;
scan_ch->channel = cpu_to_le16(channel);
ch_info = iwl_get_channel_info(priv, band, channel);
@@ -1147,7 +1331,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
return added;
}
-void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
+int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
{
struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_CMD,
@@ -1155,7 +1339,7 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
.flags = CMD_SIZE_HUGE,
};
struct iwl_scan_cmd *scan;
- struct ieee80211_conf *conf = NULL;
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
u32 rate_flags = 0;
u16 cmd_len;
u16 rx_chain = 0;
@@ -1167,48 +1351,12 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
int chan_mod;
u8 active_chains;
u8 scan_tx_antennas = priv->hw_params.valid_tx_ant;
+ int ret;
- conf = ieee80211_get_hw_conf(priv->hw);
-
- cancel_delayed_work(&priv->scan_check);
-
- if (!iwl_is_ready(priv)) {
- IWL_WARN(priv, "request scan called when driver not ready.\n");
- goto done;
- }
-
- /* Make sure the scan wasn't canceled before this queued work
- * was given the chance to run... */
- if (!test_bit(STATUS_SCANNING, &priv->status))
- goto done;
-
- /* This should never be called or scheduled if there is currently
- * a scan active in the hardware. */
- if (test_bit(STATUS_SCAN_HW, &priv->status)) {
- IWL_DEBUG_INFO(priv, "Multiple concurrent scan requests in parallel. "
- "Ignoring second request.\n");
- goto done;
- }
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
- IWL_DEBUG_SCAN(priv, "Aborting scan due to device shutdown\n");
- goto done;
- }
-
- if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
- IWL_DEBUG_HC(priv, "Scan request while abort pending. Queuing.\n");
- goto done;
- }
-
- if (iwl_is_rfkill(priv)) {
- IWL_DEBUG_HC(priv, "Aborting scan due to RF Kill activation\n");
- goto done;
- }
+ lockdep_assert_held(&priv->mutex);
- if (!test_bit(STATUS_READY, &priv->status)) {
- IWL_DEBUG_HC(priv, "Scan request while uninitialized. Queuing.\n");
- goto done;
- }
+ if (vif)
+ ctx = iwl_rxon_ctx_from_vif(vif);
if (!priv->scan_cmd) {
priv->scan_cmd = kmalloc(sizeof(struct iwl_scan_cmd) +
@@ -1216,7 +1364,7 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
if (!priv->scan_cmd) {
IWL_DEBUG_SCAN(priv,
"fail to allocate memory for scan\n");
- goto done;
+ return -ENOMEM;
}
}
scan = priv->scan_cmd;
@@ -1225,7 +1373,7 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
- if (iwl_is_associated(priv)) {
+ if (iwl_is_any_associated(priv)) {
u16 interval = 0;
u32 extra;
u32 suspend_time = 100;
@@ -1276,13 +1424,15 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
- scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id;
+ 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->active_rxon.flags & RXON_FLG_CHANNEL_MODE_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;
@@ -1290,35 +1440,42 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
rate = IWL_RATE_1M_PLCP;
rate_flags = RATE_MCS_CCK_MSK;
}
- scan->good_CRC_th = IWL_GOOD_CRC_TH_DISABLED;
+ /*
+ * 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;
- /*
- * 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.
- */
- scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
- IWL_GOOD_CRC_TH_NEVER;
break;
default:
- IWL_WARN(priv, "Invalid scan band count\n");
- goto done;
+ 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.
+ */
+ 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])
@@ -1327,6 +1484,14 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
if (priv->cfg->scan_tx_antennas[band])
scan_tx_antennas = priv->cfg->scan_tx_antennas[band];
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist &&
+ priv->bt_full_concurrent) {
+ /* operated as 1x1 in full concurrency mode */
+ scan_tx_antennas = first_antenna(
+ priv->cfg->scan_tx_antennas[band]);
+ }
+
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]);
@@ -1345,6 +1510,13 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
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;
@@ -1385,7 +1557,7 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
}
if (scan->channel_count == 0) {
IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
- goto done;
+ return -EIO;
}
cmd.len += le16_to_cpu(scan->tx_cmd.len) +
@@ -1393,25 +1565,39 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
cmd.data = scan;
scan->len = cpu_to_le16(cmd.len);
+ /* set scan bit here for PAN params */
set_bit(STATUS_SCAN_HW, &priv->status);
- if (iwl_send_cmd_sync(priv, &cmd))
- goto done;
- queue_delayed_work(priv->workqueue, &priv->scan_check,
- IWL_SCAN_CHECK_WATCHDOG);
-
- return;
-
- done:
- /* Cannot perform scan. Make sure we clear scanning
- * bits from status so next scan request can be performed.
- * If we don't clear scanning status bit here all next scan
- * will fail
- */
- clear_bit(STATUS_SCAN_HW, &priv->status);
- clear_bit(STATUS_SCANNING, &priv->status);
- /* inform mac80211 scan aborted */
- queue_work(priv->workqueue, &priv->abort_scan);
+ if (priv->cfg->ops->hcmd->set_pan_params) {
+ ret = priv->cfg->ops->hcmd->set_pan_params(priv);
+ if (ret)
+ return ret;
+ }
+
+ ret = iwl_send_cmd_sync(priv, &cmd);
+ if (ret) {
+ clear_bit(STATUS_SCAN_HW, &priv->status);
+ if (priv->cfg->ops->hcmd->set_pan_params)
+ priv->cfg->ops->hcmd->set_pan_params(priv);
+ }
+
+ return ret;
+}
+
+void iwlagn_post_scan(struct iwl_priv *priv)
+{
+ struct iwl_rxon_context *ctx;
+
+ /*
+ * Since setting the RXON may have been deferred while
+ * performing the scan, fire one off if needed
+ */
+ for_each_context(priv, ctx)
+ if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
+ iwlagn_commit_rxon(priv, ctx);
+
+ if (priv->cfg->ops->hcmd->set_pan_params)
+ priv->cfg->ops->hcmd->set_pan_params(priv);
}
int iwlagn_manage_ibss_station(struct iwl_priv *priv,
@@ -1420,8 +1606,9 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
if (add)
- return iwl_add_bssid_station(priv, vif->bss_conf.bssid, true,
- &vif_priv->ibss_bssid_sta_id);
+ return iwlagn_add_bssid_station(priv, vif_priv->ctx,
+ vif->bss_conf.bssid,
+ &vif_priv->ibss_bssid_sta_id);
return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
vif->bss_conf.bssid);
}
@@ -1453,7 +1640,7 @@ int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv)
/* waiting for all the tx frames complete might take a while */
for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
- if (cnt == IWL_CMD_QUEUE_NUM)
+ if (cnt == priv->cmd_queue)
continue;
txq = &priv->txq[cnt];
q = &txq->q;
@@ -1518,3 +1705,669 @@ done:
ieee80211_wake_queues(priv->hw);
mutex_unlock(&priv->mutex);
}
+
+/*
+ * BT coex
+ */
+/*
+ * Macros to access the lookup table.
+ *
+ * The lookup table has 7 inputs: bt3_prio, bt3_txrx, bt_rf_act, wifi_req,
+* wifi_prio, wifi_txrx and wifi_sh_ant_req.
+ *
+ * It has three outputs: WLAN_ACTIVE, WLAN_KILL and ANT_SWITCH
+ *
+ * The format is that "registers" 8 through 11 contain the WLAN_ACTIVE bits
+ * one after another in 32-bit registers, and "registers" 0 through 7 contain
+ * the WLAN_KILL and ANT_SWITCH bits interleaved (in that order).
+ *
+ * These macros encode that format.
+ */
+#define LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, wifi_req, wifi_prio, \
+ wifi_txrx, wifi_sh_ant_req) \
+ (bt3_prio | (bt3_txrx << 1) | (bt_rf_act << 2) | (wifi_req << 3) | \
+ (wifi_prio << 4) | (wifi_txrx << 5) | (wifi_sh_ant_req << 6))
+
+#define LUT_PTA_WLAN_ACTIVE_OP(lut, op, val) \
+ lut[8 + ((val) >> 5)] op (cpu_to_le32(BIT((val) & 0x1f)))
+#define LUT_TEST_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+ wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+ (!!(LUT_PTA_WLAN_ACTIVE_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, \
+ bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \
+ wifi_sh_ant_req))))
+#define LUT_SET_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+ wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+ LUT_PTA_WLAN_ACTIVE_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, \
+ bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \
+ wifi_sh_ant_req))
+#define LUT_CLEAR_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, \
+ wifi_req, wifi_prio, wifi_txrx, \
+ wifi_sh_ant_req) \
+ LUT_PTA_WLAN_ACTIVE_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, \
+ bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \
+ wifi_sh_ant_req))
+
+#define LUT_WLAN_KILL_OP(lut, op, val) \
+ lut[(val) >> 4] op (cpu_to_le32(BIT(((val) << 1) & 0x1e)))
+#define LUT_TEST_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+ wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+ (!!(LUT_WLAN_KILL_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+ wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))))
+#define LUT_SET_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+ wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+ LUT_WLAN_KILL_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+ wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
+#define LUT_CLEAR_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+ wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+ LUT_WLAN_KILL_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+ wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
+
+#define LUT_ANT_SWITCH_OP(lut, op, val) \
+ lut[(val) >> 4] op (cpu_to_le32(BIT((((val) << 1) & 0x1e) + 1)))
+#define LUT_TEST_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+ wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+ (!!(LUT_ANT_SWITCH_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+ wifi_req, wifi_prio, wifi_txrx, \
+ wifi_sh_ant_req))))
+#define LUT_SET_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+ wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+ LUT_ANT_SWITCH_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+ wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
+#define LUT_CLEAR_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+ wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+ LUT_ANT_SWITCH_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+ wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
+
+static const __le32 iwlagn_def_3w_lookup[12] = {
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaeaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xcc00ff28),
+ cpu_to_le32(0x0000aaaa),
+ cpu_to_le32(0xcc00aaaa),
+ cpu_to_le32(0x0000aaaa),
+ cpu_to_le32(0xc0004000),
+ cpu_to_le32(0x00004000),
+ cpu_to_le32(0xf0005000),
+ cpu_to_le32(0xf0004000),
+};
+
+static const __le32 iwlagn_concurrent_lookup[12] = {
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000),
+};
+
+void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
+{
+ struct iwlagn_bt_cmd bt_cmd = {
+ .max_kill = IWLAGN_BT_MAX_KILL_DEFAULT,
+ .bt3_timer_t7_value = IWLAGN_BT3_T7_DEFAULT,
+ .bt3_prio_sample_time = IWLAGN_BT3_PRIO_SAMPLE_DEFAULT,
+ .bt3_timer_t2_value = IWLAGN_BT3_T2_DEFAULT,
+ };
+
+ BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) !=
+ sizeof(bt_cmd.bt3_lookup_table));
+
+ if (priv->cfg->bt_params)
+ bt_cmd.prio_boost = priv->cfg->bt_params->bt_prio_boost;
+ else
+ bt_cmd.prio_boost = 0;
+ bt_cmd.kill_ack_mask = priv->kill_ack_mask;
+ bt_cmd.kill_cts_mask = priv->kill_cts_mask;
+ bt_cmd.valid = priv->bt_valid;
+ bt_cmd.tx_prio_boost = 0;
+ bt_cmd.rx_prio_boost = 0;
+
+ /*
+ * Configure BT coex mode to "no coexistence" when the
+ * user disabled BT coexistence, we have no interface
+ * (might be in monitor mode), or the interface is in
+ * IBSS mode (no proper uCode support for coex then).
+ */
+ if (!bt_coex_active || priv->iw_mode == NL80211_IFTYPE_ADHOC) {
+ bt_cmd.flags = 0;
+ } else {
+ bt_cmd.flags = IWLAGN_BT_FLAG_COEX_MODE_3W <<
+ IWLAGN_BT_FLAG_COEX_MODE_SHIFT;
+ if (priv->bt_ch_announce)
+ bt_cmd.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION;
+ IWL_DEBUG_INFO(priv, "BT coex flag: 0X%x\n", bt_cmd.flags);
+ }
+ if (priv->bt_full_concurrent)
+ memcpy(bt_cmd.bt3_lookup_table, iwlagn_concurrent_lookup,
+ sizeof(iwlagn_concurrent_lookup));
+ else
+ memcpy(bt_cmd.bt3_lookup_table, iwlagn_def_3w_lookup,
+ sizeof(iwlagn_def_3w_lookup));
+
+ IWL_DEBUG_INFO(priv, "BT coex %s in %s mode\n",
+ bt_cmd.flags ? "active" : "disabled",
+ priv->bt_full_concurrent ?
+ "full concurrency" : "3-wire");
+
+ if (iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, sizeof(bt_cmd), &bt_cmd))
+ IWL_ERR(priv, "failed to send BT Coex Config\n");
+
+ /*
+ * When we are doing a restart, need to also reconfigure BT
+ * SCO to the device. If not doing a restart, bt_sco_active
+ * will always be false, so there's no need to have an extra
+ * variable to check for it.
+ */
+ if (priv->bt_sco_active) {
+ struct iwlagn_bt_sco_cmd sco_cmd = { .flags = 0 };
+
+ if (priv->bt_sco_active)
+ sco_cmd.flags |= IWLAGN_BT_SCO_ACTIVE;
+ if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_SCO,
+ sizeof(sco_cmd), &sco_cmd))
+ IWL_ERR(priv, "failed to send BT SCO command\n");
+ }
+}
+
+static void iwlagn_bt_traffic_change_work(struct work_struct *work)
+{
+ struct iwl_priv *priv =
+ container_of(work, struct iwl_priv, bt_traffic_change_work);
+ struct iwl_rxon_context *ctx;
+ int smps_request = -1;
+
+ IWL_DEBUG_INFO(priv, "BT traffic load changes: %d\n",
+ priv->bt_traffic_load);
+
+ switch (priv->bt_traffic_load) {
+ case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+ smps_request = IEEE80211_SMPS_AUTOMATIC;
+ break;
+ case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+ smps_request = IEEE80211_SMPS_DYNAMIC;
+ break;
+ case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+ case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+ smps_request = IEEE80211_SMPS_STATIC;
+ break;
+ default:
+ IWL_ERR(priv, "Invalid BT traffic load: %d\n",
+ priv->bt_traffic_load);
+ break;
+ }
+
+ mutex_lock(&priv->mutex);
+
+ if (priv->cfg->ops->lib->update_chain_flags)
+ priv->cfg->ops->lib->update_chain_flags(priv);
+
+ if (smps_request != -1) {
+ for_each_context(priv, ctx) {
+ if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION)
+ ieee80211_request_smps(ctx->vif, smps_request);
+ }
+ }
+
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwlagn_print_uartmsg(struct iwl_priv *priv,
+ struct iwl_bt_uart_msg *uart_msg)
+{
+ IWL_DEBUG_NOTIF(priv, "Message Type = 0x%X, SSN = 0x%X, "
+ "Update Req = 0x%X",
+ (BT_UART_MSG_FRAME1MSGTYPE_MSK & uart_msg->frame1) >>
+ BT_UART_MSG_FRAME1MSGTYPE_POS,
+ (BT_UART_MSG_FRAME1SSN_MSK & uart_msg->frame1) >>
+ BT_UART_MSG_FRAME1SSN_POS,
+ (BT_UART_MSG_FRAME1UPDATEREQ_MSK & uart_msg->frame1) >>
+ BT_UART_MSG_FRAME1UPDATEREQ_POS);
+
+ IWL_DEBUG_NOTIF(priv, "Open connections = 0x%X, Traffic load = 0x%X, "
+ "Chl_SeqN = 0x%X, In band = 0x%X",
+ (BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK & uart_msg->frame2) >>
+ BT_UART_MSG_FRAME2OPENCONNECTIONS_POS,
+ (BT_UART_MSG_FRAME2TRAFFICLOAD_MSK & uart_msg->frame2) >>
+ BT_UART_MSG_FRAME2TRAFFICLOAD_POS,
+ (BT_UART_MSG_FRAME2CHLSEQN_MSK & uart_msg->frame2) >>
+ BT_UART_MSG_FRAME2CHLSEQN_POS,
+ (BT_UART_MSG_FRAME2INBAND_MSK & uart_msg->frame2) >>
+ BT_UART_MSG_FRAME2INBAND_POS);
+
+ IWL_DEBUG_NOTIF(priv, "SCO/eSCO = 0x%X, Sniff = 0x%X, A2DP = 0x%X, "
+ "ACL = 0x%X, Master = 0x%X, OBEX = 0x%X",
+ (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >>
+ BT_UART_MSG_FRAME3SCOESCO_POS,
+ (BT_UART_MSG_FRAME3SNIFF_MSK & uart_msg->frame3) >>
+ BT_UART_MSG_FRAME3SNIFF_POS,
+ (BT_UART_MSG_FRAME3A2DP_MSK & uart_msg->frame3) >>
+ BT_UART_MSG_FRAME3A2DP_POS,
+ (BT_UART_MSG_FRAME3ACL_MSK & uart_msg->frame3) >>
+ BT_UART_MSG_FRAME3ACL_POS,
+ (BT_UART_MSG_FRAME3MASTER_MSK & uart_msg->frame3) >>
+ BT_UART_MSG_FRAME3MASTER_POS,
+ (BT_UART_MSG_FRAME3OBEX_MSK & uart_msg->frame3) >>
+ BT_UART_MSG_FRAME3OBEX_POS);
+
+ IWL_DEBUG_NOTIF(priv, "Idle duration = 0x%X",
+ (BT_UART_MSG_FRAME4IDLEDURATION_MSK & uart_msg->frame4) >>
+ BT_UART_MSG_FRAME4IDLEDURATION_POS);
+
+ IWL_DEBUG_NOTIF(priv, "Tx Activity = 0x%X, Rx Activity = 0x%X, "
+ "eSCO Retransmissions = 0x%X",
+ (BT_UART_MSG_FRAME5TXACTIVITY_MSK & uart_msg->frame5) >>
+ BT_UART_MSG_FRAME5TXACTIVITY_POS,
+ (BT_UART_MSG_FRAME5RXACTIVITY_MSK & uart_msg->frame5) >>
+ BT_UART_MSG_FRAME5RXACTIVITY_POS,
+ (BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK & uart_msg->frame5) >>
+ BT_UART_MSG_FRAME5ESCORETRANSMIT_POS);
+
+ IWL_DEBUG_NOTIF(priv, "Sniff Interval = 0x%X, Discoverable = 0x%X",
+ (BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK & uart_msg->frame6) >>
+ BT_UART_MSG_FRAME6SNIFFINTERVAL_POS,
+ (BT_UART_MSG_FRAME6DISCOVERABLE_MSK & uart_msg->frame6) >>
+ BT_UART_MSG_FRAME6DISCOVERABLE_POS);
+
+ IWL_DEBUG_NOTIF(priv, "Sniff Activity = 0x%X, Inquiry/Page SR Mode = "
+ "0x%X, Connectable = 0x%X",
+ (BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK & uart_msg->frame7) >>
+ BT_UART_MSG_FRAME7SNIFFACTIVITY_POS,
+ (BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_MSK & uart_msg->frame7) >>
+ BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_POS,
+ (BT_UART_MSG_FRAME7CONNECTABLE_MSK & uart_msg->frame7) >>
+ BT_UART_MSG_FRAME7CONNECTABLE_POS);
+}
+
+static void iwlagn_set_kill_ack_msk(struct iwl_priv *priv,
+ struct iwl_bt_uart_msg *uart_msg)
+{
+ u8 kill_ack_msk;
+ __le32 bt_kill_ack_msg[2] = {
+ cpu_to_le32(0xFFFFFFF), cpu_to_le32(0xFFFFFC00) };
+
+ kill_ack_msk = (((BT_UART_MSG_FRAME3A2DP_MSK |
+ BT_UART_MSG_FRAME3SNIFF_MSK |
+ BT_UART_MSG_FRAME3SCOESCO_MSK) &
+ uart_msg->frame3) == 0) ? 1 : 0;
+ if (priv->kill_ack_mask != bt_kill_ack_msg[kill_ack_msk]) {
+ priv->bt_valid |= IWLAGN_BT_VALID_KILL_ACK_MASK;
+ priv->kill_ack_mask = bt_kill_ack_msg[kill_ack_msk];
+ /* schedule to send runtime bt_config */
+ queue_work(priv->workqueue, &priv->bt_runtime_config);
+ }
+
+}
+
+void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ unsigned long flags;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_bt_coex_profile_notif *coex = &pkt->u.bt_coex_profile_notif;
+ struct iwlagn_bt_sco_cmd sco_cmd = { .flags = 0 };
+ struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg;
+ u8 last_traffic_load;
+
+ IWL_DEBUG_NOTIF(priv, "BT Coex notification:\n");
+ IWL_DEBUG_NOTIF(priv, " status: %d\n", coex->bt_status);
+ IWL_DEBUG_NOTIF(priv, " traffic load: %d\n", coex->bt_traffic_load);
+ IWL_DEBUG_NOTIF(priv, " CI compliance: %d\n",
+ coex->bt_ci_compliance);
+ iwlagn_print_uartmsg(priv, uart_msg);
+
+ last_traffic_load = priv->notif_bt_traffic_load;
+ priv->notif_bt_traffic_load = coex->bt_traffic_load;
+ if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
+ if (priv->bt_status != coex->bt_status ||
+ last_traffic_load != coex->bt_traffic_load) {
+ if (coex->bt_status) {
+ /* BT on */
+ if (!priv->bt_ch_announce)
+ priv->bt_traffic_load =
+ IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+ else
+ priv->bt_traffic_load =
+ coex->bt_traffic_load;
+ } else {
+ /* BT off */
+ priv->bt_traffic_load =
+ IWL_BT_COEX_TRAFFIC_LOAD_NONE;
+ }
+ priv->bt_status = coex->bt_status;
+ queue_work(priv->workqueue,
+ &priv->bt_traffic_change_work);
+ }
+ if (priv->bt_sco_active !=
+ (uart_msg->frame3 & BT_UART_MSG_FRAME3SCOESCO_MSK)) {
+ priv->bt_sco_active = uart_msg->frame3 &
+ BT_UART_MSG_FRAME3SCOESCO_MSK;
+ if (priv->bt_sco_active)
+ sco_cmd.flags |= IWLAGN_BT_SCO_ACTIVE;
+ iwl_send_cmd_pdu_async(priv, REPLY_BT_COEX_SCO,
+ sizeof(sco_cmd), &sco_cmd, NULL);
+ }
+ }
+
+ iwlagn_set_kill_ack_msk(priv, uart_msg);
+
+ /* FIXME: based on notification, adjust the prio_boost */
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->bt_ci_compliance = coex->bt_ci_compliance;
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv)
+{
+ iwlagn_rx_handler_setup(priv);
+ priv->rx_handlers[REPLY_BT_COEX_PROFILE_NOTIF] =
+ iwlagn_bt_coex_profile_notif;
+}
+
+void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv)
+{
+ iwlagn_setup_deferred_work(priv);
+
+ INIT_WORK(&priv->bt_traffic_change_work,
+ iwlagn_bt_traffic_change_work);
+}
+
+void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv)
+{
+ cancel_work_sync(&priv->bt_traffic_change_work);
+}
+
+static bool is_single_rx_stream(struct iwl_priv *priv)
+{
+ return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC ||
+ priv->current_ht_config.single_chain_sufficient;
+}
+
+#define IWL_NUM_RX_CHAINS_MULTIPLE 3
+#define IWL_NUM_RX_CHAINS_SINGLE 2
+#define IWL_NUM_IDLE_CHAINS_DUAL 2
+#define IWL_NUM_IDLE_CHAINS_SINGLE 1
+
+/*
+ * Determine how many receiver/antenna chains to use.
+ *
+ * More provides better reception via diversity. Fewer saves power
+ * at the expense of throughput, but only when not in powersave to
+ * start with.
+ *
+ * MIMO (dual stream) requires at least 2, but works better with 3.
+ * This does not determine *which* chains to use, just how many.
+ */
+static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
+{
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist &&
+ (priv->bt_full_concurrent ||
+ priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
+ /*
+ * only use chain 'A' in bt high traffic load or
+ * full concurrency mode
+ */
+ return IWL_NUM_RX_CHAINS_SINGLE;
+ }
+ /* # of Rx chains to use when expecting MIMO. */
+ if (is_single_rx_stream(priv))
+ return IWL_NUM_RX_CHAINS_SINGLE;
+ else
+ return IWL_NUM_RX_CHAINS_MULTIPLE;
+}
+
+/*
+ * When we are in power saving mode, unless device support spatial
+ * multiplexing power save, use the active count for rx chain count.
+ */
+static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
+{
+ /* # Rx chains when idling, depending on SMPS mode */
+ switch (priv->current_ht_config.smps) {
+ case IEEE80211_SMPS_STATIC:
+ case IEEE80211_SMPS_DYNAMIC:
+ return IWL_NUM_IDLE_CHAINS_SINGLE;
+ case IEEE80211_SMPS_OFF:
+ return active_cnt;
+ default:
+ WARN(1, "invalid SMPS mode %d",
+ priv->current_ht_config.smps);
+ return active_cnt;
+ }
+}
+
+/* up to 4 chains */
+static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
+{
+ u8 res;
+ res = (chain_bitmap & BIT(0)) >> 0;
+ res += (chain_bitmap & BIT(1)) >> 1;
+ res += (chain_bitmap & BIT(2)) >> 2;
+ res += (chain_bitmap & BIT(3)) >> 3;
+ return res;
+}
+
+/**
+ * iwlagn_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
+ *
+ * Selects how many and which Rx receivers/antennas/chains to use.
+ * This should not be used for scan command ... it puts data in wrong place.
+ */
+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);
+ u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt;
+ u32 active_chains;
+ u16 rx_chain;
+
+ /* Tell uCode which antennas are actually connected.
+ * Before first association, we assume all antennas are connected.
+ * Just after first association, iwl_chain_noise_calibration()
+ * checks which antennas actually *are* connected. */
+ if (priv->chain_noise_data.active_chains)
+ active_chains = priv->chain_noise_data.active_chains;
+ else
+ active_chains = priv->hw_params.valid_rx_ant;
+
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist &&
+ (priv->bt_full_concurrent ||
+ priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
+ /*
+ * only use chain 'A' in bt high traffic load or
+ * full concurrency mode
+ */
+ active_chains = first_antenna(active_chains);
+ }
+
+ rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS;
+
+ /* How many receivers should we use? */
+ active_rx_cnt = iwl_get_active_rx_chain_count(priv);
+ idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
+
+
+ /* correct rx chain count according hw settings
+ * and chain noise calibration
+ */
+ valid_rx_cnt = iwl_count_chain_bitmap(active_chains);
+ if (valid_rx_cnt < active_rx_cnt)
+ active_rx_cnt = valid_rx_cnt;
+
+ if (valid_rx_cnt < idle_rx_cnt)
+ idle_rx_cnt = valid_rx_cnt;
+
+ rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
+ rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS;
+
+ ctx->staging.rx_chain = cpu_to_le16(rx_chain);
+
+ if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam)
+ ctx->staging.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
+ else
+ ctx->staging.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
+
+ IWL_DEBUG_ASSOC(priv, "rx_chain=0x%X active=%d idle=%d\n",
+ ctx->staging.rx_chain,
+ active_rx_cnt, idle_rx_cnt);
+
+ WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 ||
+ active_rx_cnt < idle_rx_cnt);
+}
+
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid)
+{
+ int i;
+ u8 ind = ant;
+
+ if (priv->band == IEEE80211_BAND_2GHZ &&
+ priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)
+ return 0;
+
+ for (i = 0; i < RATE_ANT_NUM - 1; i++) {
+ ind = (ind + 1) < RATE_ANT_NUM ? ind + 1 : 0;
+ if (valid & BIT(ind))
+ return ind;
+ }
+ 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;
+ 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
+ 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;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index a4378ba31ef6..065553629de5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -39,6 +39,7 @@
#include "iwl-dev.h"
#include "iwl-sta.h"
#include "iwl-core.h"
+#include "iwl-agn.h"
#define RS_NAME "iwl-agn-rs"
@@ -76,12 +77,81 @@ static const u8 ant_toggle_lookup[] = {
/*ANT_ABC -> */ ANT_ABC,
};
+#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \
+ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
+ IWL_RATE_SISO_##s##M_PLCP, \
+ IWL_RATE_MIMO2_##s##M_PLCP,\
+ IWL_RATE_MIMO3_##s##M_PLCP,\
+ IWL_RATE_##r##M_IEEE, \
+ IWL_RATE_##ip##M_INDEX, \
+ IWL_RATE_##in##M_INDEX, \
+ IWL_RATE_##rp##M_INDEX, \
+ IWL_RATE_##rn##M_INDEX, \
+ IWL_RATE_##pp##M_INDEX, \
+ IWL_RATE_##np##M_INDEX }
+
+/*
+ * Parameter order:
+ * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
+ *
+ * If there isn't a valid next or previous rate then INV is used which
+ * maps to IWL_RATE_INVALID
+ *
+ */
+const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
+ IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */
+ IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */
+ IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */
+ IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */
+ IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */
+ IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */
+ IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */
+ IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */
+ IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */
+ IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */
+ IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */
+ IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
+ IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
+ /* FIXME:RS: ^^ should be INV (legacy) */
+};
+
+static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
+{
+ int idx = 0;
+
+ /* HT rate format */
+ if (rate_n_flags & RATE_MCS_HT_MSK) {
+ idx = (rate_n_flags & 0xff);
+
+ if (idx >= IWL_RATE_MIMO3_6M_PLCP)
+ idx = idx - IWL_RATE_MIMO3_6M_PLCP;
+ else if (idx >= IWL_RATE_MIMO2_6M_PLCP)
+ idx = idx - IWL_RATE_MIMO2_6M_PLCP;
+
+ idx += IWL_FIRST_OFDM_RATE;
+ /* skip 9M not supported in ht*/
+ if (idx >= IWL_RATE_9M_INDEX)
+ idx += 1;
+ if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE))
+ return idx;
+
+ /* legacy rate format, search for match in table */
+ } else {
+ for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++)
+ if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
+ return idx;
+ }
+
+ return -1;
+}
+
static void rs_rate_scale_perform(struct iwl_priv *priv,
struct sk_buff *skb,
struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta);
static void rs_fill_link_cmd(struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
+static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);
#ifdef CONFIG_MAC80211_DEBUGFS
@@ -300,7 +370,19 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
struct ieee80211_sta *sta)
{
int ret = -EAGAIN;
- u32 load = rs_tl_get_load(lq_data, tid);
+ u32 load;
+
+ /*
+ * Don't create TX aggregation sessions when in high
+ * BT traffic, as they would just be disrupted by BT.
+ */
+ if (priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) {
+ IWL_ERR(priv, "BT traffic (%d), no aggregation allowed\n",
+ priv->bt_traffic_load);
+ return ret;
+ }
+
+ load = rs_tl_get_load(lq_data, tid);
if (load > IWL_AGG_LOAD_THRESHOLD) {
IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
@@ -502,6 +584,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags);
u8 mcs;
+ memset(tbl, 0, sizeof(struct iwl_scale_tbl_info));
*rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
if (*rate_idx == IWL_RATE_INVALID) {
@@ -588,11 +671,13 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
* Green-field mode is valid if the station supports it and
* there are no non-GF stations present in the BSS.
*/
-static inline u8 rs_use_green(struct ieee80211_sta *sta,
- struct iwl_ht_config *ht_conf)
+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;
+
return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
- !(ht_conf->non_GF_STA_present);
+ !(ctx->ht.non_gf_sta_present);
}
/**
@@ -744,6 +829,32 @@ static bool table_type_matches(struct iwl_scale_tbl_info *a,
(a->is_SGI == b->is_SGI);
}
+static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+ struct iwl_lq_sta *lq_sta)
+{
+ struct iwl_scale_tbl_info *tbl;
+ bool full_concurrent;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->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);
+
+ if (priv->bt_full_concurrent != full_concurrent) {
+ priv->bt_full_concurrent = full_concurrent;
+
+ /* Update uCode's rate table. */
+ tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ 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);
+ }
+}
+
/*
* mac80211 sends us Tx status
*/
@@ -763,6 +874,8 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
u32 tx_rate;
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;
IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n");
@@ -829,7 +942,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
lq_sta->missed_rate_counter++;
if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) {
lq_sta->missed_rate_counter = 0;
- iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false);
+ iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
}
/* Regardless, ignore this status info for outdated rate */
return;
@@ -848,7 +961,20 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
} else {
IWL_DEBUG_RATE(priv, "Neither active nor search matches tx rate\n");
- return;
+ tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ IWL_DEBUG_RATE(priv, "active- lq:%x, ant:%x, SGI:%d\n",
+ tmp_tbl->lq_type, tmp_tbl->ant_type, tmp_tbl->is_SGI);
+ tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+ IWL_DEBUG_RATE(priv, "search- lq:%x, ant:%x, SGI:%d\n",
+ tmp_tbl->lq_type, tmp_tbl->ant_type, tmp_tbl->is_SGI);
+ IWL_DEBUG_RATE(priv, "actual- lq:%x, ant:%x, SGI:%d\n",
+ tbl_type.lq_type, tbl_type.ant_type, tbl_type.is_SGI);
+ /*
+ * no matching table found, let's by-pass the data collection
+ * and continue to perform rate scale to find the rate table
+ */
+ rs_stay_in_table(lq_sta, true);
+ goto done;
}
/*
@@ -909,10 +1035,14 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
}
/* The last TX rate is cached in lq_sta; it's set in if/else above */
lq_sta->last_rate_n_flags = tx_rate;
-
+done:
/* See if there's a better rate or modulation mode to try. */
if (sta && sta->supp_rates[sband->band])
rs_rate_scale_perform(priv, skb, sta, lq_sta);
+
+ /* Is there a need to switch between full concurrency and 3-wire? */
+ if (priv->bt_ant_couple_ok)
+ rs_bt_update_lq(priv, ctx, lq_sta);
}
/*
@@ -1106,6 +1236,8 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
u16 rate_mask;
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;
if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
return -1;
@@ -1126,7 +1258,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
tbl->max_search = IWL_MAX_SEARCH;
rate_mask = lq_sta->active_mimo2_rate;
- if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap))
+ if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
tbl->is_ht40 = 1;
else
tbl->is_ht40 = 0;
@@ -1160,6 +1292,8 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
u16 rate_mask;
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;
if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
return -1;
@@ -1180,7 +1314,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
rate_mask = lq_sta->active_mimo3_rate;
- if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap))
+ if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
tbl->is_ht40 = 1;
else
tbl->is_ht40 = 0;
@@ -1215,6 +1349,8 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
u16 rate_mask;
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;
if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
return -1;
@@ -1227,7 +1363,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
tbl->max_search = IWL_MAX_SEARCH;
rate_mask = lq_sta->active_siso_rate;
- if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap))
+ if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
tbl->is_ht40 = 1;
else
tbl->is_ht40 = 0;
@@ -1265,18 +1401,52 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
struct iwl_rate_scale_data *window = &(tbl->win[index]);
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
- u8 start_action = tbl->action;
+ u8 start_action;
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
u8 tx_chains_num = priv->hw_params.tx_chains_num;
int ret = 0;
u8 update_search_tbl_counter = 0;
+ switch (priv->bt_traffic_load) {
+ case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+ /* nothing */
+ break;
+ case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+ /* avoid antenna B unless MIMO */
+ valid_tx_ant = first_antenna(priv->hw_params.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);
+ if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2 &&
+ tbl->action != IWL_LEGACY_SWITCH_SISO)
+ tbl->action = IWL_LEGACY_SWITCH_SISO;
+ break;
+ default:
+ IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+ break;
+ }
+
if (!iwl_ht_enabled(priv))
/* stay in Legacy */
tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
tbl->action > IWL_LEGACY_SWITCH_SISO)
tbl->action = IWL_LEGACY_SWITCH_SISO;
+
+ /* configure as 1x1 if bt full concurrency */
+ if (priv->bt_full_concurrent) {
+ if (!iwl_ht_enabled(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);
+ }
+
+ start_action = tbl->action;
for (; ;) {
lq_sta->action_counter++;
switch (tbl->action) {
@@ -1291,7 +1461,10 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
break;
/* Don't change antenna if success has been great */
- if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+ if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
+ !priv->bt_full_concurrent &&
+ priv->bt_traffic_load ==
+ IWL_BT_COEX_TRAFFIC_LOAD_NONE)
break;
/* Set up search table to try other antenna */
@@ -1403,31 +1576,64 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
- u8 start_action = tbl->action;
+ u8 start_action;
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
u8 tx_chains_num = priv->hw_params.tx_chains_num;
u8 update_search_tbl_counter = 0;
int ret;
+ switch (priv->bt_traffic_load) {
+ case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+ /* nothing */
+ break;
+ case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+ /* avoid antenna B unless MIMO */
+ valid_tx_ant = first_antenna(priv->hw_params.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);
+ if (tbl->action != IWL_SISO_SWITCH_ANTENNA1)
+ tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+ break;
+ default:
+ IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+ break;
+ }
+
if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
tbl->action > IWL_SISO_SWITCH_ANTENNA2) {
/* stay in SISO */
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
}
+
+ /* configure as 1x1 if bt full concurrency */
+ if (priv->bt_full_concurrent) {
+ valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+ if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
+ tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+ }
+
+ start_action = tbl->action;
for (;;) {
lq_sta->action_counter++;
switch (tbl->action) {
case IWL_SISO_SWITCH_ANTENNA1:
case IWL_SISO_SWITCH_ANTENNA2:
IWL_DEBUG_RATE(priv, "LQ: SISO toggle Antenna\n");
-
if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 &&
- tx_chains_num <= 1) ||
+ tx_chains_num <= 1) ||
(tbl->action == IWL_SISO_SWITCH_ANTENNA2 &&
- tx_chains_num <= 2))
+ tx_chains_num <= 2))
break;
- if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+ if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
+ !priv->bt_full_concurrent &&
+ priv->bt_traffic_load ==
+ IWL_BT_COEX_TRAFFIC_LOAD_NONE)
break;
memcpy(search_tbl, tbl, sz);
@@ -1541,18 +1747,47 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
- u8 start_action = tbl->action;
+ u8 start_action;
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
u8 tx_chains_num = priv->hw_params.tx_chains_num;
u8 update_search_tbl_counter = 0;
int ret;
+ switch (priv->bt_traffic_load) {
+ case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+ /* nothing */
+ break;
+ case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+ case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+ /* avoid antenna B and MIMO */
+ if (tbl->action != IWL_MIMO2_SWITCH_SISO_A)
+ tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+ break;
+ case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+ /* avoid antenna B unless MIMO */
+ if (tbl->action == IWL_MIMO2_SWITCH_SISO_B ||
+ tbl->action == IWL_MIMO2_SWITCH_SISO_C)
+ tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+ break;
+ default:
+ IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+ break;
+ }
+
if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
(tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
tbl->action > IWL_MIMO2_SWITCH_SISO_C)) {
/* switch in SISO */
tbl->action = IWL_MIMO2_SWITCH_SISO_A;
}
+
+ /* configure as 1x1 if bt full concurrency */
+ if (priv->bt_full_concurrent &&
+ (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
+ tbl->action > IWL_MIMO2_SWITCH_SISO_C))
+ tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+
+ start_action = tbl->action;
for (;;) {
lq_sta->action_counter++;
switch (tbl->action) {
@@ -1682,18 +1917,47 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
- u8 start_action = tbl->action;
+ u8 start_action;
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
u8 tx_chains_num = priv->hw_params.tx_chains_num;
int ret;
u8 update_search_tbl_counter = 0;
+ switch (priv->bt_traffic_load) {
+ case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+ /* nothing */
+ break;
+ case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+ case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+ /* avoid antenna B and MIMO */
+ if (tbl->action != IWL_MIMO3_SWITCH_SISO_A)
+ tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+ break;
+ case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+ /* avoid antenna B unless MIMO */
+ if (tbl->action == IWL_MIMO3_SWITCH_SISO_B ||
+ tbl->action == IWL_MIMO3_SWITCH_SISO_C)
+ tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+ break;
+ default:
+ IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+ break;
+ }
+
if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
(tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
tbl->action > IWL_MIMO3_SWITCH_SISO_C)) {
/* switch in SISO */
tbl->action = IWL_MIMO3_SWITCH_SISO_A;
}
+
+ /* configure as 1x1 if bt full concurrency */
+ if (priv->bt_full_concurrent &&
+ (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
+ tbl->action > IWL_MIMO3_SWITCH_SISO_C))
+ tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+
+ start_action = tbl->action;
for (;;) {
lq_sta->action_counter++;
switch (tbl->action) {
@@ -1820,7 +2084,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
* 2) # times calling this function
* 3) elapsed time in this mode (not used, for now)
*/
-static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
+static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
{
struct iwl_scale_tbl_info *tbl;
int i;
@@ -1851,7 +2115,8 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
* allow a new search. Also (below) reset all bitmaps and
* stats in active history.
*/
- if ((lq_sta->total_failed > lq_sta->max_failure_limit) ||
+ if (force_search ||
+ (lq_sta->total_failed > lq_sta->max_failure_limit) ||
(lq_sta->total_success > lq_sta->max_success_limit) ||
((!lq_sta->search_better_tbl) && (lq_sta->flush_timer)
&& (flush_interval_passed))) {
@@ -1900,6 +2165,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
* return rate_n_flags as used in the table
*/
static u32 rs_update_rate_tbl(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
struct iwl_lq_sta *lq_sta,
struct iwl_scale_tbl_info *tbl,
int index, u8 is_green)
@@ -1909,7 +2175,7 @@ static u32 rs_update_rate_tbl(struct iwl_priv *priv,
/* Update uCode's rate table. */
rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
rs_fill_link_cmd(priv, lq_sta, rate);
- iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false);
+ iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
return rate;
}
@@ -1948,6 +2214,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
s32 sr;
u8 tid = 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;
IWL_DEBUG_RATE(priv, "rate scale calculate new rate for skb\n");
@@ -1986,7 +2254,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
if (is_legacy(tbl->lq_type))
lq_sta->is_green = 0;
else
- lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config);
+ lq_sta->is_green = rs_use_green(sta);
is_green = lq_sta->is_green;
/* current tx rate */
@@ -2025,7 +2293,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
/* get "active" rate info */
index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
- rate = rs_update_rate_tbl(priv, lq_sta,
+ rate = rs_update_rate_tbl(priv, ctx, lq_sta,
tbl, index, is_green);
}
return;
@@ -2067,7 +2335,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
/* Should we stay with this modulation mode,
* or search for a new one? */
- rs_stay_in_table(lq_sta);
+ rs_stay_in_table(lq_sta, false);
goto out;
}
@@ -2215,6 +2483,28 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
if (iwl_tx_ant_restriction(priv) != IWL_ANT_OK_MULTI &&
(is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type)))
scale_action = -1;
+
+ if ((priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
+ (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
+ if (lq_sta->last_bt_traffic > priv->bt_traffic_load) {
+ /*
+ * don't set scale_action, don't want to scale up if
+ * the rate scale doesn't otherwise think that is a
+ * good idea.
+ */
+ } else if (lq_sta->last_bt_traffic <= priv->bt_traffic_load) {
+ scale_action = -1;
+ }
+ }
+ lq_sta->last_bt_traffic = priv->bt_traffic_load;
+
+ if ((priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
+ (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
+ /* search for a new modulation */
+ rs_stay_in_table(lq_sta, true);
+ goto lq_update;
+ }
+
switch (scale_action) {
case -1:
/* Decrease starting rate, update uCode's rate table */
@@ -2245,13 +2535,13 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
lq_update:
/* Replace uCode's rate table for the destination station. */
if (update_lq)
- rate = rs_update_rate_tbl(priv, lq_sta,
+ rate = rs_update_rate_tbl(priv, ctx, lq_sta,
tbl, index, is_green);
if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) {
/* Should we stay with this modulation mode,
* or search for a new one? */
- rs_stay_in_table(lq_sta);
+ rs_stay_in_table(lq_sta, false);
}
/*
* Search for new modulation mode if we're:
@@ -2287,7 +2577,7 @@ lq_update:
IWL_DEBUG_RATE(priv, "Switch current mcs: %X index: %d\n",
tbl->current_rate, index);
rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
- iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false);
+ iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
} else
done_search = 1;
}
@@ -2357,12 +2647,17 @@ static void rs_initialize_lq(struct iwl_priv *priv,
int rate_idx;
int i;
u32 rate;
- u8 use_green = rs_use_green(sta, &priv->current_ht_config);
+ u8 use_green = rs_use_green(sta);
u8 active_tbl = 0;
u8 valid_tx_ant;
+ struct iwl_station_priv *sta_priv;
+ struct iwl_rxon_context *ctx;
if (!sta || !lq_sta)
- goto out;
+ return;
+
+ sta_priv = (void *)sta->drv_priv;
+ ctx = sta_priv->common.ctx;
i = lq_sta->last_txrate_idx;
@@ -2394,9 +2689,7 @@ static void rs_initialize_lq(struct iwl_priv *priv,
rs_set_expected_tpt_table(lq_sta, tbl);
rs_fill_link_cmd(NULL, lq_sta, rate);
priv->stations[lq_sta->lq.sta_id].lq = &lq_sta->lq;
- iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_SYNC, true);
- out:
- return;
+ iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_SYNC, true);
}
static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
@@ -2524,7 +2817,7 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i
lq_sta->is_dup = 0;
lq_sta->max_rate_idx = -1;
lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
- lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config);
+ lq_sta->is_green = rs_use_green(sta);
lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
lq_sta->band = priv->band;
/*
@@ -2594,10 +2887,15 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
/* Interpret new_rate (rate_n_flags) */
- memset(&tbl_type, 0, sizeof(tbl_type));
rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
&tbl_type, &rate_idx);
+ if (priv && priv->bt_full_concurrent) {
+ /* 1x1 only */
+ tbl_type.ant_type =
+ first_antenna(priv->hw_params.valid_tx_ant);
+ }
+
/* How many times should we repeat the initial rate? */
if (is_legacy(tbl_type.lq_type)) {
ant_toggle_cnt = 1;
@@ -2622,9 +2920,12 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
index++;
repeat_rate--;
-
- if (priv)
- valid_tx_ant = priv->hw_params.valid_tx_ant;
+ if (priv) {
+ if (priv->bt_full_concurrent)
+ valid_tx_ant = ANT_A;
+ else
+ valid_tx_ant = priv->hw_params.valid_tx_ant;
+ }
/* Fill rest of rate table */
while (index < LINK_QUAL_MAX_RETRY_NUM) {
@@ -2639,7 +2940,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
rs_toggle_antenna(valid_tx_ant,
&new_rate, &tbl_type))
ant_toggle_cnt = 1;
-}
+ }
/* Override next rate if needed for debug purposes */
rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
@@ -2654,6 +2955,12 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type,
&rate_idx);
+ if (priv && priv->bt_full_concurrent) {
+ /* 1x1 only */
+ tbl_type.ant_type =
+ first_antenna(priv->hw_params.valid_tx_ant);
+ }
+
/* Indicate to uCode which entries might be MIMO.
* If initial rate was MIMO, this will finally end up
* as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
@@ -2694,8 +3001,21 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+
lq_cmd->agg_params.agg_time_limit =
cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
+ /*
+ * overwrite if needed, pass aggregation time limit
+ * to uCode in uSec
+ */
+ if (priv && priv->cfg->bt_params &&
+ priv->cfg->bt_params->agg_time_limit &&
+ priv->cfg->bt_params->agg_time_limit >=
+ LINK_QUAL_AGG_TIME_LIMIT_MIN &&
+ priv->cfg->bt_params->agg_time_limit <=
+ LINK_QUAL_AGG_TIME_LIMIT_MAX)
+ lq_cmd->agg_params.agg_time_limit =
+ cpu_to_le16(priv->cfg->bt_params->agg_time_limit);
}
static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
@@ -2760,6 +3080,9 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
char buf[64];
int buf_size;
u32 parsed_rate;
+ 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;
priv = lq_sta->drv;
memset(buf, 0, sizeof(buf));
@@ -2782,7 +3105,8 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
if (lq_sta->dbg_fixed_rate) {
rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
- iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC, false);
+ iwl_send_lq_cmd(lq_sta->drv, ctx, &lq_sta->lq, CMD_ASYNC,
+ false);
}
return count;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index 8292f6d48ec6..75e50d33ecb3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -299,7 +299,6 @@ enum {
#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
-extern const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT_3945];
enum iwl_table_type {
LQ_NONE,
@@ -432,6 +431,8 @@ struct iwl_lq_sta {
u32 last_rate_n_flags;
/* packets destined for this STA are aggregated */
u8 is_agg;
+ /* BT traffic this sta was last updated in */
+ u8 last_bt_traffic;
};
static inline u8 num_of_ant(u8 mask)
@@ -451,24 +452,6 @@ static inline u8 first_antenna(u8 mask)
}
-static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
-{
- u8 rate = iwl_rates[rate_index].prev_ieee;
-
- if (rate == IWL_RATE_INVALID)
- rate = rate_index;
- return rate;
-}
-
-static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index)
-{
- u8 rate = iwl3945_rates[rate_index].prev_ieee;
-
- if (rate == IWL_RATE_INVALID)
- rate = rate_index;
- return rate;
-}
-
/**
* iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info
*
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
index 9490eced1198..bbd40b7dd597 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
@@ -34,7 +34,7 @@
#include "iwl-dev.h"
#include "iwl-core.h"
-#include "iwl-calib.h"
+#include "iwl-agn-calib.h"
#include "iwl-sta.h"
#include "iwl-io.h"
#include "iwl-helpers.h"
@@ -73,7 +73,8 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
int bcn_silence_a, bcn_silence_b, bcn_silence_c;
int last_rx_noise;
- if (priv->cfg->bt_statistics)
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->bt_statistics)
rx_info = &(priv->_agn.statistics_bt.rx.general.common);
else
rx_info = &(priv->_agn.statistics.rx.general);
@@ -124,7 +125,8 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,
struct statistics_general_common *general, *accum_general;
struct statistics_tx *tx, *accum_tx;
- if (priv->cfg->bt_statistics) {
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->bt_statistics) {
prev_stats = (__le32 *)&priv->_agn.statistics_bt;
accum_stats = (u32 *)&priv->_agn.accum_statistics_bt;
size = sizeof(struct iwl_bt_notif_statistics);
@@ -183,7 +185,7 @@ bool iwl_good_plcp_health(struct iwl_priv *priv,
unsigned int plcp_msec;
unsigned long plcp_received_jiffies;
- if (priv->cfg->plcp_delta_threshold ==
+ if (priv->cfg->base_params->plcp_delta_threshold ==
IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
return rc;
@@ -205,7 +207,8 @@ bool iwl_good_plcp_health(struct iwl_priv *priv,
struct statistics_rx_phy *ofdm;
struct statistics_rx_ht_phy *ofdm_ht;
- if (priv->cfg->bt_statistics) {
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->bt_statistics) {
ofdm = &pkt->u.stats_bt.rx.ofdm;
ofdm_ht = &pkt->u.stats_bt.rx.ofdm_ht;
combined_plcp_delta =
@@ -229,7 +232,7 @@ bool iwl_good_plcp_health(struct iwl_priv *priv,
if ((combined_plcp_delta > 0) &&
((combined_plcp_delta * 100) / plcp_msec) >
- priv->cfg->plcp_delta_threshold) {
+ priv->cfg->base_params->plcp_delta_threshold) {
/*
* if plcp_err exceed the threshold,
* the following data is printed in csv format:
@@ -242,13 +245,13 @@ bool iwl_good_plcp_health(struct iwl_priv *priv,
* plcp_msec
*/
IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
- "%u, %u, %u, %u, %d, %u mSecs\n",
- priv->cfg->plcp_delta_threshold,
- le32_to_cpu(ofdm->plcp_err),
- le32_to_cpu(ofdm->plcp_err),
- le32_to_cpu(ofdm_ht->plcp_err),
- le32_to_cpu(ofdm_ht->plcp_err),
- combined_plcp_delta, plcp_msec);
+ "%u, %u, %u, %u, %d, %u mSecs\n",
+ priv->cfg->base_params->plcp_delta_threshold,
+ le32_to_cpu(ofdm->plcp_err),
+ le32_to_cpu(ofdm->plcp_err),
+ le32_to_cpu(ofdm_ht->plcp_err),
+ le32_to_cpu(ofdm_ht->plcp_err),
+ combined_plcp_delta, plcp_msec);
rc = false;
}
@@ -262,7 +265,8 @@ void iwl_rx_statistics(struct iwl_priv *priv,
int change;
struct iwl_rx_packet *pkt = rxb_addr(rxb);
- if (priv->cfg->bt_statistics) {
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->bt_statistics) {
IWL_DEBUG_RX(priv,
"Statistics notification received (%d vs %d).\n",
(int)sizeof(struct iwl_bt_notif_statistics),
@@ -300,7 +304,8 @@ void iwl_rx_statistics(struct iwl_priv *priv,
iwl_recover_from_statistics(priv, pkt);
- if (priv->cfg->bt_statistics)
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->bt_statistics)
memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt,
sizeof(priv->_agn.statistics_bt));
else
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
new file mode 100644
index 000000000000..35a30d2e0734
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
@@ -0,0 +1,716 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2010 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 "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-sta.h"
+#include "iwl-agn.h"
+
+static struct iwl_link_quality_cmd *
+iwl_sta_alloc_lq(struct iwl_priv *priv, u8 sta_id)
+{
+ 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;
+ }
+ /* 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 */
+ if (priv->band == IEEE80211_BAND_5GHZ)
+ r = IWL_RATE_6M_INDEX;
+ else
+ r = IWL_RATE_1M_INDEX;
+
+ 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_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);
+
+ link_cmd->general_params.dual_stream_ant_msk =
+ priv->hw_params.valid_tx_ant &
+ ~first_antenna(priv->hw_params.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) {
+ link_cmd->general_params.dual_stream_ant_msk =
+ priv->hw_params.valid_tx_ant;
+ }
+
+ 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;
+
+ return link_cmd;
+}
+
+/*
+ * iwlagn_add_bssid_station - Add the special IBSS BSSID station
+ *
+ * Function sleeps.
+ */
+int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+ const u8 *addr, u8 *sta_id_r)
+{
+ int ret;
+ u8 sta_id;
+ struct iwl_link_quality_cmd *link_cmd;
+ unsigned long flags;
+
+ if (sta_id_r)
+ *sta_id_r = IWL_INVALID_STATION;
+
+ ret = iwl_add_station_common(priv, ctx, addr, 0, NULL, &sta_id);
+ if (ret) {
+ IWL_ERR(priv, "Unable to add station %pM\n", addr);
+ return ret;
+ }
+
+ if (sta_id_r)
+ *sta_id_r = sta_id;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].used |= IWL_STA_LOCAL;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ /* Set up default rate scaling table in device's station table */
+ link_cmd = iwl_sta_alloc_lq(priv, sta_id);
+ if (!link_cmd) {
+ IWL_ERR(priv, "Unable to initialize rate scaling for station %pM.\n",
+ addr);
+ return -ENOMEM;
+ }
+
+ ret = iwl_send_lq_cmd(priv, ctx, link_cmd, CMD_SYNC, true);
+ if (ret)
+ IWL_ERR(priv, "Link quality command failed (%d)\n", ret);
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].lq = link_cmd;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return 0;
+}
+
+static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ bool send_if_empty)
+{
+ int i, not_empty = 0;
+ u8 buff[sizeof(struct iwl_wep_cmd) +
+ sizeof(struct iwl_wep_key) * WEP_KEYS_MAX];
+ struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff;
+ size_t cmd_size = sizeof(struct iwl_wep_cmd);
+ struct iwl_host_cmd cmd = {
+ .id = ctx->wep_key_cmd,
+ .data = wep_cmd,
+ .flags = CMD_SYNC,
+ };
+
+ might_sleep();
+
+ memset(wep_cmd, 0, cmd_size +
+ (sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));
+
+ for (i = 0; i < WEP_KEYS_MAX ; i++) {
+ wep_cmd->key[i].key_index = i;
+ if (ctx->wep_keys[i].key_size) {
+ wep_cmd->key[i].key_offset = i;
+ not_empty = 1;
+ } else {
+ wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET;
+ }
+
+ wep_cmd->key[i].key_size = ctx->wep_keys[i].key_size;
+ memcpy(&wep_cmd->key[i].key[3], ctx->wep_keys[i].key,
+ ctx->wep_keys[i].key_size);
+ }
+
+ wep_cmd->global_key_type = WEP_KEY_WEP_TYPE;
+ wep_cmd->num_keys = WEP_KEYS_MAX;
+
+ cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;
+
+ cmd.len = cmd_size;
+
+ if (not_empty || send_if_empty)
+ return iwl_send_cmd(priv, &cmd);
+ else
+ return 0;
+}
+
+int iwl_restore_default_wep_keys(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
+{
+ lockdep_assert_held(&priv->mutex);
+
+ return iwl_send_static_wepkey_cmd(priv, ctx, false);
+}
+
+int iwl_remove_default_wep_key(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct ieee80211_key_conf *keyconf)
+{
+ int ret;
+
+ lockdep_assert_held(&priv->mutex);
+
+ IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
+ keyconf->keyidx);
+
+ memset(&ctx->wep_keys[keyconf->keyidx], 0, sizeof(ctx->wep_keys[0]));
+ if (iwl_is_rfkill(priv)) {
+ 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;
+ }
+ ret = iwl_send_static_wepkey_cmd(priv, ctx, 1);
+ IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
+ keyconf->keyidx, ret);
+
+ return ret;
+}
+
+int iwl_set_default_wep_key(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct ieee80211_key_conf *keyconf)
+{
+ int ret;
+
+ lockdep_assert_held(&priv->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);
+ return -EINVAL;
+ }
+
+ keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
+ keyconf->hw_key_idx = HW_KEY_DEFAULT;
+ priv->stations[ctx->ap_sta_id].keyinfo.cipher = keyconf->cipher;
+
+ ctx->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
+ memcpy(&ctx->wep_keys[keyconf->keyidx].key, &keyconf->key,
+ keyconf->keylen);
+
+ ret = iwl_send_static_wepkey_cmd(priv, ctx, false);
+ IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n",
+ keyconf->keylen, keyconf->keyidx, ret);
+
+ return ret;
+}
+
+static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct ieee80211_key_conf *keyconf,
+ u8 sta_id)
+{
+ unsigned long flags;
+ __le16 key_flags = 0;
+ struct iwl_addsta_cmd sta_cmd;
+
+ lockdep_assert_held(&priv->mutex);
+
+ keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
+
+ key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK);
+ key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+ key_flags &= ~STA_KEY_FLG_INVALID;
+
+ if (keyconf->keylen == WEP_KEY_LEN_128)
+ key_flags |= STA_KEY_FLG_KEY_SIZE_MSK;
+
+ if (sta_id == ctx->bcast_sta_id)
+ key_flags |= STA_KEY_MULTICAST_MSK;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
+ priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
+ priv->stations[sta_id].keyinfo.keyidx = keyconf->keyidx;
+
+ memcpy(priv->stations[sta_id].keyinfo.key,
+ keyconf->key, keyconf->keylen);
+
+ memcpy(&priv->stations[sta_id].sta.key.key[3],
+ keyconf->key, keyconf->keylen);
+
+ if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
+ == STA_KEY_FLG_NO_ENC)
+ priv->stations[sta_id].sta.key.key_offset =
+ iwl_get_free_ucode_key_index(priv);
+ /* else, we are overriding an existing key => no need to allocated room
+ * in uCode. */
+
+ WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
+ "no space for a new key");
+
+ priv->stations[sta_id].sta.key.key_flags = key_flags;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ 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);
+
+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+}
+
+static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct ieee80211_key_conf *keyconf,
+ u8 sta_id)
+{
+ unsigned long flags;
+ __le16 key_flags = 0;
+ struct iwl_addsta_cmd sta_cmd;
+
+ lockdep_assert_held(&priv->mutex);
+
+ key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
+ key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+ key_flags &= ~STA_KEY_FLG_INVALID;
+
+ if (sta_id == ctx->bcast_sta_id)
+ key_flags |= STA_KEY_MULTICAST_MSK;
+
+ keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
+ priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
+
+ memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
+ keyconf->keylen);
+
+ memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
+ keyconf->keylen);
+
+ if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
+ == STA_KEY_FLG_NO_ENC)
+ priv->stations[sta_id].sta.key.key_offset =
+ iwl_get_free_ucode_key_index(priv);
+ /* else, we are overriding an existing key => no need to allocated room
+ * in uCode. */
+
+ WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
+ "no space for a new key");
+
+ priv->stations[sta_id].sta.key.key_flags = key_flags;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ 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);
+
+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+}
+
+static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct ieee80211_key_conf *keyconf,
+ u8 sta_id)
+{
+ unsigned long flags;
+ int ret = 0;
+ __le16 key_flags = 0;
+
+ key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
+ key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+ key_flags &= ~STA_KEY_FLG_INVALID;
+
+ if (sta_id == ctx->bcast_sta_id)
+ key_flags |= STA_KEY_MULTICAST_MSK;
+
+ keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
+ priv->stations[sta_id].keyinfo.keylen = 16;
+
+ if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
+ == STA_KEY_FLG_NO_ENC)
+ priv->stations[sta_id].sta.key.key_offset =
+ iwl_get_free_ucode_key_index(priv);
+ /* else, we are overriding an existing key => no need to allocated room
+ * in uCode. */
+
+ WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
+ "no space for a new key");
+
+ priv->stations[sta_id].sta.key.key_flags = key_flags;
+
+
+ /* This copy is acutally not needed: we get the key with each TX */
+ memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
+
+ memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16);
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return ret;
+}
+
+void iwl_update_tkip_key(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct ieee80211_key_conf *keyconf,
+ struct ieee80211_sta *sta, u32 iv32, u16 *phase1key)
+{
+ u8 sta_id;
+ unsigned long flags;
+ int i;
+
+ if (iwl_scan_cancel(priv)) {
+ /* cancel scan failed, just live w/ bad key and rely
+ briefly on SW decryption */
+ return;
+ }
+
+ sta_id = iwl_sta_id_or_broadcast(priv, ctx, sta);
+ if (sta_id == IWL_INVALID_STATION)
+ return;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
+
+ for (i = 0; i < 5; i++)
+ priv->stations[sta_id].sta.key.tkip_rx_ttak[i] =
+ cpu_to_le16(phase1key[i]);
+
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ 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);
+
+}
+
+int iwl_remove_dynamic_key(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct ieee80211_key_conf *keyconf,
+ u8 sta_id)
+{
+ unsigned long flags;
+ u16 key_flags;
+ u8 keyidx;
+ struct iwl_addsta_cmd sta_cmd;
+
+ lockdep_assert_held(&priv->mutex);
+
+ ctx->key_mapping_keys--;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags);
+ keyidx = (key_flags >> STA_KEY_FLG_KEYID_POS) & 0x3;
+
+ IWL_DEBUG_WEP(priv, "Remove dynamic key: idx=%d sta=%d\n",
+ keyconf->keyidx, sta_id);
+
+ if (keyconf->keyidx != keyidx) {
+ /* We need to remove a key with index different that the one
+ * in the uCode. This means that the key we need to remove has
+ * been replaced by another one with different index.
+ * Don't do anything and return ok
+ */
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+ }
+
+ if (priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET) {
+ IWL_WARN(priv, "Removing wrong key %d 0x%x\n",
+ keyconf->keyidx, key_flags);
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+ }
+
+ if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset,
+ &priv->ucode_key_table))
+ IWL_ERR(priv, "index %d not used in uCode key table.\n",
+ priv->stations[sta_id].sta.key.key_offset);
+ memset(&priv->stations[sta_id].keyinfo, 0,
+ sizeof(struct iwl_hw_key));
+ memset(&priv->stations[sta_id].sta.key, 0,
+ sizeof(struct iwl4965_keyinfo));
+ priv->stations[sta_id].sta.key.key_flags =
+ STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID;
+ priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled.\n");
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+ }
+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+}
+
+int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+ struct ieee80211_key_conf *keyconf, u8 sta_id)
+{
+ int ret;
+
+ lockdep_assert_held(&priv->mutex);
+
+ ctx->key_mapping_keys++;
+ keyconf->hw_key_idx = HW_KEY_DYNAMIC;
+
+ switch (keyconf->cipher) {
+ case WLAN_CIPHER_SUITE_CCMP:
+ ret = iwl_set_ccmp_dynamic_key_info(priv, ctx, keyconf, sta_id);
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ ret = iwl_set_tkip_dynamic_key_info(priv, ctx, keyconf, sta_id);
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ ret = iwl_set_wep_dynamic_key_info(priv, ctx, keyconf, sta_id);
+ break;
+ default:
+ IWL_ERR(priv,
+ "Unknown alg: %s cipher = %x\n", __func__,
+ keyconf->cipher);
+ ret = -EINVAL;
+ }
+
+ IWL_DEBUG_WEP(priv, "Set dynamic key: cipher=%x len=%d idx=%d sta=%d ret=%d\n",
+ keyconf->cipher, keyconf->keylen, keyconf->keyidx,
+ sta_id, ret);
+
+ return ret;
+}
+
+/**
+ * iwlagn_alloc_bcast_station - add broadcast station into driver's station table.
+ *
+ * This adds the broadcast station into the driver's station table
+ * and marks it driver active, so that it will be restored to the
+ * device at the next best time.
+ */
+int iwlagn_alloc_bcast_station(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
+{
+ struct iwl_link_quality_cmd *link_cmd;
+ unsigned long flags;
+ u8 sta_id;
+
+ spin_lock_irqsave(&priv->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);
+
+ 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);
+
+ link_cmd = iwl_sta_alloc_lq(priv, sta_id);
+ if (!link_cmd) {
+ IWL_ERR(priv,
+ "Unable to initialize rate scaling for bcast station.\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].lq = link_cmd;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return 0;
+}
+
+/**
+ * iwl_update_bcast_station - update broadcast station's LQ command
+ *
+ * Only used by iwlagn. Placed here to have all bcast station management
+ * code together.
+ */
+static int iwl_update_bcast_station(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
+{
+ unsigned long flags;
+ struct iwl_link_quality_cmd *link_cmd;
+ u8 sta_id = ctx->bcast_sta_id;
+
+ link_cmd = iwl_sta_alloc_lq(priv, sta_id);
+ if (!link_cmd) {
+ IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&priv->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);
+
+ return 0;
+}
+
+int iwl_update_bcast_stations(struct iwl_priv *priv)
+{
+ struct iwl_rxon_context *ctx;
+ int ret = 0;
+
+ for_each_context(priv, ctx) {
+ ret = iwl_update_bcast_station(priv, ctx);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
+ */
+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);
+
+ /* Remove "disable" flag, to enable Tx for this TID */
+ spin_lock_irqsave(&priv->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);
+
+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+}
+
+int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
+ int tid, u16 ssn)
+{
+ unsigned long flags;
+ int sta_id;
+ struct iwl_addsta_cmd sta_cmd;
+
+ lockdep_assert_held(&priv->mutex);
+
+ sta_id = iwl_sta_id(sta);
+ if (sta_id == IWL_INVALID_STATION)
+ return -ENXIO;
+
+ spin_lock_irqsave(&priv->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);
+
+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+}
+
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
+ int tid)
+{
+ unsigned long flags;
+ int sta_id;
+ struct iwl_addsta_cmd sta_cmd;
+
+ lockdep_assert_held(&priv->mutex);
+
+ sta_id = iwl_sta_id(sta);
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
+ return -ENXIO;
+ }
+
+ spin_lock_irqsave(&priv->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);
+
+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+}
+
+void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->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);
+
+}
+
+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);
+ priv->stations[sta_id].sta.station_flags |= STA_FLG_PWR_SAVE_MSK;
+ priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
+ priv->stations[sta_id].sta.sta.modify_mask =
+ STA_MODIFY_SLEEP_TX_COUNT_MSK;
+ priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt);
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
new file mode 100644
index 000000000000..e3a8216a033c
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
@@ -0,0 +1,699 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <net/mac80211.h>
+
+#include "iwl-eeprom.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-commands.h"
+#include "iwl-debug.h"
+#include "iwl-agn-tt.h"
+
+/* default Thermal Throttling transaction table
+ * Current state | Throttling Down | Throttling Up
+ *=============================================================================
+ * Condition Nxt State Condition Nxt State Condition Nxt State
+ *-----------------------------------------------------------------------------
+ * IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A
+ * IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0
+ * IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1
+ * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
+ *=============================================================================
+ */
+static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
+ {IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
+ {IWL_TI_1, 105, CT_KILL_THRESHOLD - 1},
+ {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
+};
+static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
+ {IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
+ {IWL_TI_2, 110, CT_KILL_THRESHOLD - 1},
+ {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
+};
+static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
+ {IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
+ {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX},
+ {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
+};
+static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
+ {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
+ {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
+ {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+};
+
+/* Advance Thermal Throttling default restriction table */
+static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
+ {IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true },
+ {IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true },
+ {IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false },
+ {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false }
+};
+
+bool iwl_tt_is_low_power_state(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+ if (tt->state >= IWL_TI_1)
+ return true;
+ return false;
+}
+
+u8 iwl_tt_current_power_mode(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+ return tt->tt_power_mode;
+}
+
+bool iwl_ht_enabled(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ struct iwl_tt_restriction *restriction;
+
+ if (!priv->thermal_throttle.advanced_tt)
+ return true;
+ restriction = tt->restriction + tt->state;
+ return restriction->is_ht;
+}
+
+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;
+ else
+ within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
+ CT_KILL_THRESHOLD) ? true : false;
+ return within_margin;
+}
+
+bool iwl_check_for_ct_kill(struct iwl_priv *priv)
+{
+ bool is_ct_kill = false;
+
+ if (iwl_within_ct_kill_margin(priv)) {
+ iwl_tt_enter_ct_kill(priv);
+ is_ct_kill = true;
+ }
+ return is_ct_kill;
+}
+
+enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ struct iwl_tt_restriction *restriction;
+
+ if (!priv->thermal_throttle.advanced_tt)
+ return IWL_ANT_OK_MULTI;
+ restriction = tt->restriction + tt->state;
+ return restriction->tx_stream;
+}
+
+enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ struct iwl_tt_restriction *restriction;
+
+ if (!priv->thermal_throttle.advanced_tt)
+ return IWL_ANT_OK_MULTI;
+ restriction = tt->restriction + tt->state;
+ return restriction->rx_stream;
+}
+
+#define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */
+#define CT_KILL_WAITING_DURATION (300) /* 300ms duration */
+
+/*
+ * toggle the bit to wake up uCode and check the temperature
+ * if the temperature is below CT, uCode will stay awake and send card
+ * state notification with CT_KILL bit clear to inform Thermal Throttling
+ * Management to change state. Otherwise, uCode will go back to sleep
+ * without doing anything, driver should continue the 5 seconds timer
+ * to wake up uCode for temperature check until temperature drop below CT
+ */
+static void iwl_tt_check_exit_ct_kill(unsigned long data)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)data;
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ unsigned long flags;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if (tt->state == IWL_TI_CT_KILL) {
+ if (priv->thermal_throttle.ct_kill_toggle) {
+ iwl_write32(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,
+ 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);
+
+ /* Reschedule the ct_kill timer to occur in
+ * CT_KILL_EXIT_DURATION seconds to ensure we get a
+ * thermal update */
+ IWL_DEBUG_POWER(priv, "schedule ct_kill exit timer\n");
+ mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
+ jiffies + CT_KILL_EXIT_DURATION * HZ);
+ }
+}
+
+static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
+ bool stop)
+{
+ if (stop) {
+ IWL_DEBUG_POWER(priv, "Stop all queues\n");
+ if (priv->mac80211_registered)
+ ieee80211_stop_queues(priv->hw);
+ IWL_DEBUG_POWER(priv,
+ "Schedule 5 seconds CT_KILL Timer\n");
+ mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
+ jiffies + CT_KILL_EXIT_DURATION * HZ);
+ } else {
+ IWL_DEBUG_POWER(priv, "Wake all queues\n");
+ if (priv->mac80211_registered)
+ ieee80211_wake_queues(priv->hw);
+ }
+}
+
+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))
+ return;
+
+ /* temperature timer expired, ready to go into CT_KILL state */
+ if (tt->state != IWL_TI_CT_KILL) {
+ IWL_DEBUG_POWER(priv, "entering CT_KILL state when "
+ "temperature timer expired\n");
+ tt->state = IWL_TI_CT_KILL;
+ set_bit(STATUS_CT_KILL, &priv->status);
+ iwl_perform_ct_kill_task(priv, true);
+ }
+}
+
+static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
+{
+ IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n");
+ /* make request to retrieve statistics information */
+ iwl_send_statistics_request(priv, CMD_SYNC, false);
+ /* Reschedule the ct_kill wait timer */
+ mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
+ jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
+}
+
+#define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY)
+#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100)
+#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90)
+
+/*
+ * Legacy thermal throttling
+ * 1) Avoid NIC destruction due to high temperatures
+ * Chip will identify dangerously high temperatures that can
+ * harm the device and will power down
+ * 2) Avoid the NIC power down due to high temperature
+ * Throttle early enough to lower the power consumption before
+ * drastic steps are needed
+ */
+static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
+{
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ enum iwl_tt_state old_state;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if ((tt->tt_previous_temp) &&
+ (temp > tt->tt_previous_temp) &&
+ ((temp - tt->tt_previous_temp) >
+ IWL_TT_INCREASE_MARGIN)) {
+ IWL_DEBUG_POWER(priv,
+ "Temperature increase %d degree Celsius\n",
+ (temp - tt->tt_previous_temp));
+ }
+#endif
+ old_state = tt->state;
+ /* in Celsius */
+ if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
+ tt->state = IWL_TI_CT_KILL;
+ else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
+ tt->state = IWL_TI_2;
+ else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
+ tt->state = IWL_TI_1;
+ else
+ tt->state = IWL_TI_0;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ tt->tt_previous_temp = temp;
+#endif
+ /* stop ct_kill_waiting_tm timer */
+ del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
+ if (tt->state != old_state) {
+ switch (tt->state) {
+ case IWL_TI_0:
+ /*
+ * When the system is ready to go back to IWL_TI_0
+ * we only have to call iwl_power_update_mode() to
+ * do so.
+ */
+ break;
+ case IWL_TI_1:
+ tt->tt_power_mode = IWL_POWER_INDEX_3;
+ break;
+ case IWL_TI_2:
+ tt->tt_power_mode = IWL_POWER_INDEX_4;
+ break;
+ default:
+ tt->tt_power_mode = IWL_POWER_INDEX_5;
+ break;
+ }
+ mutex_lock(&priv->mutex);
+ if (old_state == IWL_TI_CT_KILL)
+ clear_bit(STATUS_CT_KILL, &priv->status);
+ if (tt->state != IWL_TI_CT_KILL &&
+ iwl_power_update_mode(priv, true)) {
+ /* TT state not updated
+ * try again during next temperature read
+ */
+ if (old_state == IWL_TI_CT_KILL)
+ set_bit(STATUS_CT_KILL, &priv->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);
+ iwl_perform_ct_kill_task(priv, true);
+ } else {
+ iwl_prepare_ct_kill_task(priv);
+ tt->state = old_state;
+ }
+ } else if (old_state == IWL_TI_CT_KILL &&
+ tt->state != IWL_TI_CT_KILL)
+ iwl_perform_ct_kill_task(priv, false);
+ IWL_DEBUG_POWER(priv, "Temperature state changed %u\n",
+ tt->state);
+ IWL_DEBUG_POWER(priv, "Power Index change to %u\n",
+ tt->tt_power_mode);
+ }
+ mutex_unlock(&priv->mutex);
+ }
+}
+
+/*
+ * Advance thermal throttling
+ * 1) Avoid NIC destruction due to high temperatures
+ * Chip will identify dangerously high temperatures that can
+ * harm the device and will power down
+ * 2) Avoid the NIC power down due to high temperature
+ * Throttle early enough to lower the power consumption before
+ * drastic steps are needed
+ * Actions include relaxing the power down sleep thresholds and
+ * decreasing the number of TX streams
+ * 3) Avoid throughput performance impact as much as possible
+ *
+ *=============================================================================
+ * Condition Nxt State Condition Nxt State Condition Nxt State
+ *-----------------------------------------------------------------------------
+ * IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A
+ * IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0
+ * IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1
+ * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
+ *=============================================================================
+ */
+static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
+{
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ int i;
+ bool changed = false;
+ enum iwl_tt_state old_state;
+ struct iwl_tt_trans *transaction;
+
+ old_state = tt->state;
+ for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
+ /* based on the current TT state,
+ * find the curresponding transaction table
+ * each table has (IWL_TI_STATE_MAX - 1) entries
+ * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
+ * will advance to the correct table.
+ * then based on the current temperature
+ * find the next state need to transaction to
+ * go through all the possible (IWL_TI_STATE_MAX - 1) entries
+ * in the current table to see if transaction is needed
+ */
+ transaction = tt->transaction +
+ ((old_state * (IWL_TI_STATE_MAX - 1)) + i);
+ if (temp >= transaction->tt_low &&
+ temp <= transaction->tt_high) {
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if ((tt->tt_previous_temp) &&
+ (temp > tt->tt_previous_temp) &&
+ ((temp - tt->tt_previous_temp) >
+ IWL_TT_INCREASE_MARGIN)) {
+ IWL_DEBUG_POWER(priv,
+ "Temperature increase %d "
+ "degree Celsius\n",
+ (temp - tt->tt_previous_temp));
+ }
+ tt->tt_previous_temp = temp;
+#endif
+ if (old_state !=
+ transaction->next_state) {
+ changed = true;
+ tt->state =
+ transaction->next_state;
+ }
+ break;
+ }
+ }
+ /* stop ct_kill_waiting_tm timer */
+ del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
+ if (changed) {
+ if (tt->state >= IWL_TI_1) {
+ /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
+ tt->tt_power_mode = IWL_POWER_INDEX_5;
+
+ if (!iwl_ht_enabled(priv)) {
+ struct iwl_rxon_context *ctx;
+
+ for_each_context(priv, ctx) {
+ struct iwl_rxon_cmd *rxon;
+
+ rxon = &ctx->staging;
+
+ /* disable HT */
+ rxon->flags &= ~(
+ RXON_FLG_CHANNEL_MODE_MSK |
+ RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
+ RXON_FLG_HT40_PROT_MSK |
+ RXON_FLG_HT_PROT_MSK);
+ }
+ } else {
+ /* check HT capability and set
+ * according to the system HT capability
+ * in case get disabled before */
+ iwl_set_rxon_ht(priv, &priv->current_ht_config);
+ }
+
+ } else {
+ /*
+ * restore system power setting -- it will be
+ * recalculated automatically.
+ */
+
+ /* check HT capability and set
+ * according to the system HT capability
+ * in case get disabled before */
+ iwl_set_rxon_ht(priv, &priv->current_ht_config);
+ }
+ mutex_lock(&priv->mutex);
+ if (old_state == IWL_TI_CT_KILL)
+ clear_bit(STATUS_CT_KILL, &priv->status);
+ if (tt->state != IWL_TI_CT_KILL &&
+ iwl_power_update_mode(priv, true)) {
+ /* TT state not updated
+ * try again during next temperature read
+ */
+ 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);
+ tt->state = old_state;
+ } else {
+ IWL_DEBUG_POWER(priv,
+ "Thermal Throttling to new state: %u\n",
+ tt->state);
+ if (old_state != IWL_TI_CT_KILL &&
+ tt->state == IWL_TI_CT_KILL) {
+ if (force) {
+ IWL_DEBUG_POWER(priv,
+ "Enter IWL_TI_CT_KILL\n");
+ set_bit(STATUS_CT_KILL, &priv->status);
+ iwl_perform_ct_kill_task(priv, true);
+ } else {
+ iwl_prepare_ct_kill_task(priv);
+ tt->state = old_state;
+ }
+ } else if (old_state == IWL_TI_CT_KILL &&
+ tt->state != IWL_TI_CT_KILL) {
+ IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n");
+ iwl_perform_ct_kill_task(priv, false);
+ }
+ }
+ mutex_unlock(&priv->mutex);
+ }
+}
+
+/* Card State Notification indicated reach critical temperature
+ * if PSP not enable, no Thermal Throttling function will be performed
+ * just set the GP1 bit to acknowledge the event
+ * otherwise, go into IWL_TI_CT_KILL state
+ * since Card State Notification will not provide any temperature reading
+ * for Legacy mode
+ * so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
+ * for advance mode
+ * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
+ */
+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))
+ return;
+
+ if (!iwl_is_ready(priv))
+ return;
+
+ if (tt->state != IWL_TI_CT_KILL) {
+ IWL_ERR(priv, "Device reached critical temperature "
+ "- ucode going to sleep!\n");
+ if (!priv->thermal_throttle.advanced_tt)
+ iwl_legacy_tt_handler(priv,
+ IWL_MINIMAL_POWER_THRESHOLD,
+ true);
+ else
+ iwl_advance_tt_handler(priv,
+ CT_KILL_THRESHOLD + 1, true);
+ }
+}
+
+/* Card State Notification indicated out of critical temperature
+ * since Card State Notification will not provide any temperature reading
+ * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
+ * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
+ */
+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))
+ return;
+
+ if (!iwl_is_ready(priv))
+ return;
+
+ /* stop ct_kill_exit_tm timer */
+ del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
+
+ if (tt->state == IWL_TI_CT_KILL) {
+ IWL_ERR(priv,
+ "Device temperature below critical"
+ "- ucode awake!\n");
+ /*
+ * exit from CT_KILL state
+ * reset the current temperature reading
+ */
+ priv->temperature = 0;
+ if (!priv->thermal_throttle.advanced_tt)
+ iwl_legacy_tt_handler(priv,
+ IWL_REDUCED_PERFORMANCE_THRESHOLD_2,
+ true);
+ else
+ iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
+ true);
+ }
+}
+
+void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
+{
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ IWL_DEBUG_POWER(priv, "Queueing critical temperature enter.\n");
+ queue_work(priv->workqueue, &priv->ct_enter);
+}
+
+void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
+{
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ IWL_DEBUG_POWER(priv, "Queueing critical temperature exit.\n");
+ queue_work(priv->workqueue, &priv->ct_exit);
+}
+
+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))
+ 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
+ iwl_advance_tt_handler(priv, temp, false);
+}
+
+void iwl_tt_handler(struct iwl_priv *priv)
+{
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ IWL_DEBUG_POWER(priv, "Queueing thermal throttling work.\n");
+ queue_work(priv->workqueue, &priv->tt_work);
+}
+
+/* Thermal throttling initialization
+ * For advance thermal throttling:
+ * Initialize Thermal Index and temperature threshold table
+ * Initialize thermal throttling restriction table
+ */
+void iwl_tt_initialize(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+ int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
+ struct iwl_tt_trans *transaction;
+
+ IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling\n");
+
+ memset(tt, 0, sizeof(struct iwl_tt_mgmt));
+
+ tt->state = IWL_TI_0;
+ init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
+ priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
+ priv->thermal_throttle.ct_kill_exit_tm.function =
+ iwl_tt_check_exit_ct_kill;
+ init_timer(&priv->thermal_throttle.ct_kill_waiting_tm);
+ priv->thermal_throttle.ct_kill_waiting_tm.data =
+ (unsigned long)priv;
+ priv->thermal_throttle.ct_kill_waiting_tm.function =
+ iwl_tt_ready_for_ct_kill;
+ /* setup deferred ct kill work */
+ INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
+ INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
+ INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
+
+ if (priv->cfg->base_params->adv_thermal_throttle) {
+ IWL_DEBUG_POWER(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);
+ if (!tt->restriction || !tt->transaction) {
+ IWL_ERR(priv, "Fallback to Legacy Throttling\n");
+ priv->thermal_throttle.advanced_tt = false;
+ kfree(tt->restriction);
+ tt->restriction = NULL;
+ kfree(tt->transaction);
+ tt->transaction = NULL;
+ } else {
+ transaction = tt->transaction +
+ (IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
+ memcpy(transaction, &tt_range_0[0], size);
+ transaction = tt->transaction +
+ (IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
+ memcpy(transaction, &tt_range_1[0], size);
+ transaction = tt->transaction +
+ (IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
+ memcpy(transaction, &tt_range_2[0], size);
+ transaction = tt->transaction +
+ (IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
+ memcpy(transaction, &tt_range_3[0], size);
+ size = sizeof(struct iwl_tt_restriction) *
+ IWL_TI_STATE_MAX;
+ memcpy(tt->restriction,
+ &restriction_range[0], size);
+ priv->thermal_throttle.advanced_tt = true;
+ }
+ } else {
+ IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n");
+ priv->thermal_throttle.advanced_tt = false;
+ }
+}
+
+/* cleanup thermal throttling management related memory and timer */
+void iwl_tt_exit(struct iwl_priv *priv)
+{
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+ /* stop ct_kill_exit_tm timer if activated */
+ del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
+ /* stop ct_kill_waiting_tm timer if activated */
+ del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
+ cancel_work_sync(&priv->tt_work);
+ cancel_work_sync(&priv->ct_enter);
+ cancel_work_sync(&priv->ct_exit);
+
+ if (priv->thermal_throttle.advanced_tt) {
+ /* free advance thermal throttling memory */
+ kfree(tt->restriction);
+ tt->restriction = NULL;
+ kfree(tt->transaction);
+ tt->transaction = NULL;
+ }
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h
new file mode 100644
index 000000000000..d55060427cac
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h
@@ -0,0 +1,129 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2010 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_tt_setting_h__
+#define __iwl_tt_setting_h__
+
+#include "iwl-commands.h"
+
+#define IWL_ABSOLUTE_ZERO 0
+#define IWL_ABSOLUTE_MAX 0xFFFFFFFF
+#define IWL_TT_INCREASE_MARGIN 5
+#define IWL_TT_CT_KILL_MARGIN 3
+
+enum iwl_antenna_ok {
+ IWL_ANT_OK_NONE,
+ IWL_ANT_OK_SINGLE,
+ IWL_ANT_OK_MULTI,
+};
+
+/* Thermal Throttling State Machine states */
+enum iwl_tt_state {
+ IWL_TI_0, /* normal temperature, system power state */
+ IWL_TI_1, /* high temperature detect, low power state */
+ IWL_TI_2, /* higher temperature detected, lower power state */
+ IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */
+ IWL_TI_STATE_MAX
+};
+
+/**
+ * struct iwl_tt_restriction - Thermal Throttling restriction table
+ * @tx_stream: number of tx stream allowed
+ * @is_ht: ht enable/disable
+ * @rx_stream: number of rx stream allowed
+ *
+ * This table is used by advance thermal throttling management
+ * based on the current thermal throttling state, and determines
+ * the number of tx/rx streams and the status of HT operation.
+ */
+struct iwl_tt_restriction {
+ enum iwl_antenna_ok tx_stream;
+ enum iwl_antenna_ok rx_stream;
+ bool is_ht;
+};
+
+/**
+ * struct iwl_tt_trans - Thermal Throttling transaction table
+ * @next_state: next thermal throttling mode
+ * @tt_low: low temperature threshold to change state
+ * @tt_high: high temperature threshold to change state
+ *
+ * This is used by the advanced thermal throttling algorithm
+ * to determine the next thermal state to go based on the
+ * current temperature.
+ */
+struct iwl_tt_trans {
+ enum iwl_tt_state next_state;
+ u32 tt_low;
+ u32 tt_high;
+};
+
+/**
+ * struct iwl_tt_mgnt - Thermal Throttling Management structure
+ * @advanced_tt: advanced thermal throttle required
+ * @state: current Thermal Throttling state
+ * @tt_power_mode: Thermal Throttling power mode index
+ * being used to set power level when
+ * when thermal throttling state != IWL_TI_0
+ * the tt_power_mode should set to different
+ * power mode based on the current tt state
+ * @tt_previous_temperature: last measured temperature
+ * @iwl_tt_restriction: ptr to restriction tbl, used by advance
+ * thermal throttling to determine how many tx/rx streams
+ * should be used in tt state; and can HT be enabled or not
+ * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling
+ * state transaction
+ * @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature
+ * @ct_kill_exit_tm: timer to exit thermal kill
+ */
+struct iwl_tt_mgmt {
+ enum iwl_tt_state state;
+ bool advanced_tt;
+ u8 tt_power_mode;
+ bool ct_kill_toggle;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ s32 tt_previous_temp;
+#endif
+ struct iwl_tt_restriction *restriction;
+ struct iwl_tt_trans *transaction;
+ struct timer_list ct_kill_exit_tm;
+ struct timer_list ct_kill_waiting_tm;
+};
+
+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);
+void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
+void iwl_tt_handler(struct iwl_priv *priv);
+void iwl_tt_initialize(struct iwl_priv *priv);
+void iwl_tt_exit(struct iwl_priv *priv);
+
+#endif /* __iwl_tt_setting_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 69155aa448fb..2b078a995729 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -71,18 +71,6 @@ static const u8 tid_to_ac[] = {
2, 3, 3, 2, 1, 1, 0, 0
};
-static const u8 ac_to_fifo[] = {
- IWL_TX_FIFO_VO,
- IWL_TX_FIFO_VI,
- IWL_TX_FIFO_BE,
- IWL_TX_FIFO_BK,
-};
-
-static inline int get_fifo_from_ac(u8 ac)
-{
- return ac_to_fifo[ac];
-}
-
static inline int get_ac_from_tid(u16 tid)
{
if (likely(tid < ARRAY_SIZE(tid_to_ac)))
@@ -92,10 +80,10 @@ static inline int get_ac_from_tid(u16 tid)
return -EINVAL;
}
-static inline int get_fifo_from_tid(u16 tid)
+static inline int get_fifo_from_tid(struct iwl_rxon_context *ctx, u16 tid)
{
if (likely(tid < ARRAY_SIZE(tid_to_ac)))
- return get_fifo_from_ac(tid_to_ac[tid]);
+ return ctx->ac_to_fifo[tid_to_ac[tid]];
/* no support for TIDs 8-15 yet */
return -EINVAL;
@@ -118,7 +106,7 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
- if (txq_id != IWL_CMD_QUEUE_NUM) {
+ if (txq_id != priv->cmd_queue) {
sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
@@ -155,7 +143,7 @@ void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
- if (txq_id != IWL_CMD_QUEUE_NUM)
+ if (txq_id != priv->cmd_queue)
sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id;
bc_ent = cpu_to_le16(1 | (sta_id << 12));
@@ -236,13 +224,13 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
int ret;
if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
- (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
- <= 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->num_of_ampdu_queues - 1);
+ priv->cfg->base_params->num_of_ampdu_queues - 1);
return -EINVAL;
}
@@ -298,13 +286,13 @@ int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
u16 ssn_idx, u8 tx_fifo)
{
if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
- (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
- <= txq_id)) {
+ (IWLAGN_FIRST_AMPDU_QUEUE +
+ priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) {
IWL_ERR(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->num_of_ampdu_queues - 1);
+ priv->cfg->base_params->num_of_ampdu_queues - 1);
return -EINVAL;
}
@@ -333,19 +321,15 @@ void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask)
iwl_write_prph(priv, IWLAGN_SCD_TXFACT, mask);
}
-static inline int get_queue_from_ac(u16 ac)
-{
- return ac;
-}
-
/*
* handle build REPLY_TX command notification.
*/
static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
- 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 std_id)
{
__le16 fc = hdr->frame_control;
__le32 tx_flags = tx_cmd->tx_flags;
@@ -365,6 +349,13 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
if (ieee80211_is_back_req(fc))
tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
+ else if (info->band == IEEE80211_BAND_2GHZ &&
+ priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist &&
+ (ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) ||
+ ieee80211_is_reassoc_req(fc) ||
+ skb->protocol == cpu_to_be16(ETH_P_PAE)))
+ tx_flags |= TX_CMD_FLG_IGNORE_BT;
tx_cmd->sta_id = std_id;
@@ -454,7 +445,14 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
rate_flags |= RATE_MCS_CCK_MSK;
/* Set up antennas */
- priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist &&
+ 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));
+ } else
+ priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
priv->hw_params.valid_tx_ant);
rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
@@ -470,8 +468,8 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
{
struct ieee80211_key_conf *keyconf = info->control.hw_key;
- switch (keyconf->alg) {
- case ALG_CCMP:
+ switch (keyconf->cipher) {
+ case WLAN_CIPHER_SUITE_CCMP:
tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
if (info->flags & IEEE80211_TX_CTL_AMPDU)
@@ -479,20 +477,20 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
break;
- case ALG_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
ieee80211_get_tkip_key(keyconf, skb_frag,
IEEE80211_TKIP_P2_KEY, tx_cmd->key);
IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
break;
- case ALG_WEP:
+ case WLAN_CIPHER_SUITE_WEP104:
+ tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
+ /* fall through */
+ case WLAN_CIPHER_SUITE_WEP40:
tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
(keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
- if (keyconf->keylen == WEP_KEY_LEN_128)
- tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
-
memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
@@ -500,7 +498,7 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
break;
default:
- IWL_ERR(priv, "Unknown encode alg %d\n", keyconf->alg);
+ IWL_ERR(priv, "Unknown encode cipher %x\n", keyconf->cipher);
break;
}
}
@@ -519,6 +517,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
struct iwl_device_cmd *out_cmd;
struct iwl_cmd_meta *out_meta;
struct iwl_tx_cmd *tx_cmd;
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
int swq_id, txq_id;
dma_addr_t phys_addr;
dma_addr_t txcmd_phys;
@@ -533,6 +532,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
u8 *qc = NULL;
unsigned long flags;
+ if (info->control.vif)
+ ctx = iwl_rxon_ctx_from_vif(info->control.vif);
+
spin_lock_irqsave(&priv->lock, flags);
if (iwl_is_rfkill(priv)) {
IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
@@ -553,7 +555,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr_len = ieee80211_hdrlen(fc);
/* Find index into station table for destination station */
- sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
+ sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);
@@ -565,8 +567,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (sta)
sta_priv = (void *)sta->drv_priv;
- if (sta_priv && sta_id != priv->hw_params.bcast_sta_id &&
- sta_priv->asleep) {
+ if (sta_priv && sta_priv->asleep) {
WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE));
/*
* This sends an asynchronous command to the device,
@@ -580,7 +581,20 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
}
- txq_id = get_queue_from_ac(skb_get_queue_mapping(skb));
+ /*
+ * 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)];
/* irqs already disabled/saved above when locking priv->lock */
spin_lock(&priv->sta_lock);
@@ -625,6 +639,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* 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_cmd = txq->cmd[q->write_ptr];
@@ -655,7 +670,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
iwlagn_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id);
/* TODO need this for burst mode later on */
- iwlagn_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
+ iwlagn_tx_cmd_build_basic(priv, skb, tx_cmd, info, hdr, sta_id);
iwl_dbg_log_tx_data_frame(priv, len, hdr);
iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc);
@@ -813,7 +828,7 @@ void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv)
/* Tx queues */
if (priv->txq) {
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
- if (txq_id == IWL_CMD_QUEUE_NUM)
+ if (txq_id == priv->cmd_queue)
iwl_cmd_queue_free(priv);
else
iwl_tx_queue_free(priv, txq_id);
@@ -870,9 +885,9 @@ int iwlagn_txq_ctx_alloc(struct iwl_priv *priv)
spin_unlock_irqrestore(&priv->lock, flags);
- /* Alloc and init all Tx queues, including the command queue (#4) */
+ /* 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 == IWL_CMD_QUEUE_NUM) ?
+ slots_num = (txq_id == priv->cmd_queue) ?
TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
txq_id);
@@ -910,7 +925,7 @@ void iwlagn_txq_ctx_reset(struct iwl_priv *priv)
/* Alloc and init all Tx queues, including the command queue (#4) */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
- slots_num = txq_id == IWL_CMD_QUEUE_NUM ?
+ slots_num = txq_id == priv->cmd_queue ?
TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id);
}
@@ -968,7 +983,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
unsigned long flags;
struct iwl_tid_data *tid_data;
- tx_fifo = get_fifo_from_tid(tid);
+ tx_fifo = get_fifo_from_tid(iwl_rxon_ctx_from_vif(vif), tid);
if (unlikely(tx_fifo < 0))
return tx_fifo;
@@ -1024,12 +1039,12 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid)
{
- int tx_fifo_id, txq_id, sta_id, ssn = -1;
+ 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(tid);
+ tx_fifo_id = get_fifo_from_tid(iwl_rxon_ctx_from_vif(vif), tid);
if (unlikely(tx_fifo_id < 0))
return tx_fifo_id;
@@ -1042,21 +1057,26 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
spin_lock_irqsave(&priv->sta_lock, flags);
- if (priv->stations[sta_id].tid[tid].agg.state ==
- IWL_EMPTYING_HW_QUEUE_ADDBA) {
- IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
- ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
- priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
- return 0;
- }
-
- if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
- IWL_WARN(priv, "Stopping AGG while state not ON or starting\n");
-
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;
@@ -1070,6 +1090,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
}
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 */
@@ -1098,6 +1119,9 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
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);
@@ -1108,12 +1132,12 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
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(tid);
+ int tx_fifo = get_fifo_from_tid(ctx, tid);
IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n");
priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
ssn, tx_fifo);
tid_data->agg.state = IWL_AGG_OFF;
- ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, addr, tid);
+ ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid);
}
break;
case IWL_EMPTYING_HW_QUEUE_ADDBA:
@@ -1121,7 +1145,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
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(priv->vif, addr, tid);
+ ieee80211_start_tx_ba_cb_irqsafe(ctx->vif, addr, tid);
}
break;
}
@@ -1129,14 +1153,14 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
return 0;
}
-static void iwlagn_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
+static void iwlagn_tx_status(struct iwl_priv *priv, struct iwl_tx_info *tx_info)
{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx_info->skb->data;
struct ieee80211_sta *sta;
struct iwl_station_priv *sta_priv;
rcu_read_lock();
- sta = ieee80211_find_sta(priv->vif, hdr->addr1);
+ sta = ieee80211_find_sta(tx_info->ctx->vif, hdr->addr1);
if (sta) {
sta_priv = (void *)sta->drv_priv;
/* avoid atomic ops if this isn't a client */
@@ -1146,7 +1170,7 @@ static void iwlagn_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
}
rcu_read_unlock();
- ieee80211_tx_status_irqsafe(priv->hw, skb);
+ ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb);
}
int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
@@ -1169,7 +1193,7 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
tx_info = &txq->txb[txq->q.read_ptr];
- iwlagn_tx_status(priv, tx_info->skb);
+ iwlagn_tx_status(priv, tx_info);
hdr = (struct ieee80211_hdr *)tx_info->skb->data;
if (hdr && ieee80211_is_data_qos(hdr->frame_control))
@@ -1203,7 +1227,8 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
struct ieee80211_tx_info *info;
if (unlikely(!agg->wait_for_ba)) {
- IWL_ERR(priv, "Received BA when not expected\n");
+ if (unlikely(ba_resp->bitmap))
+ IWL_ERR(priv, "Received BA when not expected\n");
return -EINVAL;
}
@@ -1367,3 +1392,43 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
spin_unlock_irqrestore(&priv->sta_lock, flags);
}
+
+#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
+
+ 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);
+ }
+
+ return "UNKNOWN";
+
+#undef TX_STATUS_FAIL
+#undef TX_STATUS_POSTPONE
+}
+#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 6f77441cb65a..703621107dac 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -38,6 +38,7 @@
#include "iwl-helpers.h"
#include "iwl-agn-hw.h"
#include "iwl-agn.h"
+#include "iwl-agn-calib.h"
static const s8 iwlagn_default_queue_to_tx_fifo[] = {
IWL_TX_FIFO_VO,
@@ -52,6 +53,19 @@ static const s8 iwlagn_default_queue_to_tx_fifo[] = {
IWL_TX_FIFO_UNUSED,
};
+static const s8 iwlagn_ipan_queue_to_tx_fifo[] = {
+ IWL_TX_FIFO_VO,
+ IWL_TX_FIFO_VI,
+ IWL_TX_FIFO_BE,
+ IWL_TX_FIFO_BK,
+ IWL_TX_FIFO_BK_IPAN,
+ IWL_TX_FIFO_BE_IPAN,
+ IWL_TX_FIFO_VI_IPAN,
+ IWL_TX_FIFO_VO_IPAN,
+ IWL_TX_FIFO_BE_IPAN,
+ IWLAGN_CMD_FIFO_NUM,
+};
+
static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
{COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
0, COEX_UNASSOC_IDLE_FLAGS},
@@ -201,6 +215,25 @@ static int iwlagn_set_Xtal_calib(struct iwl_priv *priv)
(u8 *)&cmd, sizeof(cmd));
}
+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_5000_TEMPERATURE);
+ cmd.hdr.op_code = IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD;
+ cmd.hdr.first_group = 0;
+ cmd.hdr.groups_num = 1;
+ cmd.hdr.data_valid = 1;
+ cmd.radio_sensor_offset = le16_to_cpu(offset_calib[1]);
+ if (!(cmd.radio_sensor_offset))
+ cmd.radio_sensor_offset = DEFAULT_RADIO_SENSOR_OFFSET;
+ cmd.reserved = 0;
+ IWL_DEBUG_CALIB(priv, "Radio sensor offset: %d\n",
+ cmd.radio_sensor_offset);
+ 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;
@@ -294,7 +327,27 @@ void iwlagn_init_alive_start(struct iwl_priv *priv)
goto restart;
}
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist) {
+ /*
+ * Tell uCode we are ready to perform calibration
+ * need to perform this before any calibration
+ * no need to close the envlope since we are going
+ * to load the runtime uCode later.
+ */
+ iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
+ BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+
+ }
iwlagn_send_calib_cfg(priv);
+
+ /**
+ * temperature offset calibration is only needed for runtime ucode,
+ * so prepare the value now.
+ */
+ if (priv->cfg->need_temp_offset_calib)
+ iwlagn_set_temperature_offset_calib(priv);
+
return;
restart:
@@ -306,7 +359,7 @@ static int iwlagn_send_wimax_coex(struct iwl_priv *priv)
{
struct iwl_wimax_coex_cmd coex_cmd;
- if (priv->cfg->support_wimax_coexist) {
+ if (priv->cfg->base_params->support_wimax_coexist) {
/* UnMask wake up src at associated sleep */
coex_cmd.flags = COEX_FLAGS_ASSOC_WA_UNMASK_MSK;
@@ -329,8 +382,54 @@ static int iwlagn_send_wimax_coex(struct iwl_priv *priv)
sizeof(coex_cmd), &coex_cmd);
}
+static const u8 iwlagn_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
+ ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+ (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+ ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+ (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+ ((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+ (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+ ((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+ (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+ ((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+ (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+ ((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+ (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+ ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+ (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+ ((BT_COEX_PRIO_TBL_PRIO_COEX_OFF << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+ (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+ ((BT_COEX_PRIO_TBL_PRIO_COEX_ON << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+ (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+ 0, 0, 0, 0, 0, 0, 0
+};
+
+void iwlagn_send_prio_tbl(struct iwl_priv *priv)
+{
+ struct iwl_bt_coex_prio_table_cmd prio_tbl_cmd;
+
+ memcpy(prio_tbl_cmd.prio_tbl, iwlagn_bt_prio_tbl,
+ sizeof(iwlagn_bt_prio_tbl));
+ if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PRIO_TABLE,
+ sizeof(prio_tbl_cmd), &prio_tbl_cmd))
+ IWL_ERR(priv, "failed to send BT prio tbl command\n");
+}
+
+void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
+{
+ struct iwl_bt_coex_prot_env_cmd env_cmd;
+
+ env_cmd.action = action;
+ env_cmd.type = type;
+ if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV,
+ sizeof(env_cmd), &env_cmd))
+ IWL_ERR(priv, "failed to send BT env command\n");
+}
+
+
int iwlagn_alive_notify(struct iwl_priv *priv)
{
+ const s8 *queues;
u32 a;
unsigned long flags;
int i, chan;
@@ -365,7 +464,7 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
iwl_write_prph(priv, IWLAGN_SCD_QUEUECHAIN_SEL,
- IWLAGN_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num));
+ IWLAGN_SCD_QUEUECHAIN_SEL_ALL(priv));
iwl_write_prph(priv, IWLAGN_SCD_AGGR_SEL, 0);
/* initiate the queues */
@@ -391,7 +490,13 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
/* Activate all Tx DMA/FIFO channels */
priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
- iwlagn_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+ /* map queues to FIFOs */
+ if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
+ queues = iwlagn_ipan_queue_to_tx_fifo;
+ else
+ queues = iwlagn_default_queue_to_tx_fifo;
+
+ iwlagn_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));
@@ -400,11 +505,12 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
/* reset to 0 to enable all the queue first */
priv->txq_ctx_active_msk = 0;
- /* map qos queues to fifos one-to-one */
+
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 < ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo); i++) {
- int ac = iwlagn_default_queue_to_tx_fifo[i];
+ for (i = 0; i < 10; i++) {
+ int ac = queues[i];
iwl_txq_ctx_activate(priv, i);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 10d7b9b7f064..c2636a7ab9ee 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -33,6 +33,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/pci-aspm.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
@@ -56,7 +57,7 @@
#include "iwl-io.h"
#include "iwl-helpers.h"
#include "iwl-sta.h"
-#include "iwl-calib.h"
+#include "iwl-agn-calib.h"
#include "iwl-agn.h"
@@ -86,29 +87,36 @@ MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL");
MODULE_ALIAS("iwl4965");
+static int iwlagn_ant_coupling;
+static bool iwlagn_bt_ch_announce = 1;
+
/**
- * iwl_commit_rxon - commit staging_rxon to hardware
+ * iwlagn_commit_rxon - commit staging_rxon to hardware
*
* The RXON command in staging_rxon is committed to the hardware and
* the active_rxon structure is updated with the new data. This
* function correctly transitions out of the RXON_ASSOC_MSK state if
* a HW tune is required based on the RXON structure changes.
*/
-int iwl_commit_rxon(struct iwl_priv *priv)
+int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
{
/* cast away the const for active_rxon in this function */
- struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+ struct iwl_rxon_cmd *active_rxon = (void *)&ctx->active;
int ret;
bool new_assoc =
- !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK);
+ !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
+ bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK);
if (!iwl_is_alive(priv))
return -EBUSY;
+ if (!ctx->is_active)
+ return 0;
+
/* always get timestamp with Rx frame */
- priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
+ ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
- ret = iwl_check_rxon_cmd(priv);
+ ret = iwl_check_rxon_cmd(priv, ctx);
if (ret) {
IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
return -EINVAL;
@@ -119,7 +127,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
* abort any previous channel switch if still in process
*/
if (priv->switch_rxon.switch_in_progress &&
- (priv->switch_rxon.channel != priv->staging_rxon.channel)) {
+ (priv->switch_rxon.channel != ctx->staging.channel)) {
IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
le16_to_cpu(priv->switch_rxon.channel));
iwl_chswitch_done(priv, false);
@@ -128,15 +136,15 @@ int iwl_commit_rxon(struct iwl_priv *priv)
/* If we don't need to send a full RXON, we can use
* iwl_rxon_assoc_cmd which is used to reconfigure filter
* and other flags for the current radio configuration. */
- if (!iwl_full_rxon_required(priv)) {
- ret = iwl_send_rxon_assoc(priv);
+ if (!iwl_full_rxon_required(priv, ctx)) {
+ ret = iwl_send_rxon_assoc(priv, ctx);
if (ret) {
IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
return ret;
}
- memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
- iwl_print_rx_config_cmd(priv);
+ memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
+ iwl_print_rx_config_cmd(priv, ctx);
return 0;
}
@@ -144,13 +152,13 @@ int iwl_commit_rxon(struct iwl_priv *priv)
* an RXON_ASSOC and the new config wants the associated mask enabled,
* we must clear the associated from the active configuration
* before we apply the new config */
- if (iwl_is_associated(priv) && new_assoc) {
+ if (iwl_is_associated_ctx(ctx) && new_assoc) {
IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n");
active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- ret = iwl_send_cmd_pdu(priv, REPLY_RXON,
- sizeof(struct iwl_rxon_cmd),
- &priv->active_rxon);
+ ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+ sizeof(struct iwl_rxon_cmd),
+ active_rxon);
/* If the mask clearing failed then we set
* active_rxon back to what it was previously */
@@ -159,9 +167,9 @@ int iwl_commit_rxon(struct iwl_priv *priv)
IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret);
return ret;
}
- iwl_clear_ucode_stations(priv);
- iwl_restore_stations(priv);
- ret = iwl_restore_default_wep_keys(priv);
+ iwl_clear_ucode_stations(priv, ctx);
+ iwl_restore_stations(priv, ctx);
+ ret = iwl_restore_default_wep_keys(priv, ctx);
if (ret) {
IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
return ret;
@@ -173,47 +181,65 @@ int iwl_commit_rxon(struct iwl_priv *priv)
"* channel = %d\n"
"* bssid = %pM\n",
(new_assoc ? "" : "out"),
- le16_to_cpu(priv->staging_rxon.channel),
- priv->staging_rxon.bssid_addr);
+ le16_to_cpu(ctx->staging.channel),
+ ctx->staging.bssid_addr);
+
+ iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto);
- iwl_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto);
+ if (!old_assoc) {
+ /*
+ * First of all, before setting associated, we need to
+ * send RXON timing so the device knows about the DTIM
+ * period and other timing values
+ */
+ ret = iwl_send_rxon_timing(priv, ctx);
+ if (ret) {
+ IWL_ERR(priv, "Error setting RXON timing!\n");
+ return ret;
+ }
+ }
+
+ if (priv->cfg->ops->hcmd->set_pan_params) {
+ ret = priv->cfg->ops->hcmd->set_pan_params(priv);
+ if (ret)
+ return ret;
+ }
/* Apply the new configuration
* RXON unassoc clears the station table in uCode so restoration of
* stations is needed after it (the RXON command) completes
*/
if (!new_assoc) {
- ret = iwl_send_cmd_pdu(priv, REPLY_RXON,
- sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
+ ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+ sizeof(struct iwl_rxon_cmd), &ctx->staging);
if (ret) {
IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
return ret;
}
IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON.\n");
- memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
- iwl_clear_ucode_stations(priv);
- iwl_restore_stations(priv);
- ret = iwl_restore_default_wep_keys(priv);
+ memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
+ iwl_clear_ucode_stations(priv, ctx);
+ iwl_restore_stations(priv, ctx);
+ ret = iwl_restore_default_wep_keys(priv, ctx);
if (ret) {
IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
return ret;
}
}
-
- priv->start_calib = 0;
if (new_assoc) {
+ priv->start_calib = 0;
/* Apply the new configuration
* RXON assoc doesn't clear the station table in uCode,
*/
- ret = iwl_send_cmd_pdu(priv, REPLY_RXON,
- sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
+ ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+ sizeof(struct iwl_rxon_cmd), &ctx->staging);
if (ret) {
IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
return ret;
}
- memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+ memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
}
- iwl_print_rx_config_cmd(priv);
+ iwl_print_rx_config_cmd(priv, ctx);
iwl_init_sensitivity(priv);
@@ -230,10 +256,14 @@ int iwl_commit_rxon(struct iwl_priv *priv)
void iwl_update_chain_flags(struct iwl_priv *priv)
{
+ struct iwl_rxon_context *ctx;
- if (priv->cfg->ops->hcmd->set_rxon_chain)
- priv->cfg->ops->hcmd->set_rxon_chain(priv);
- iwlcore_commit_rxon(priv);
+ if (priv->cfg->ops->hcmd->set_rxon_chain) {
+ for_each_context(priv, ctx) {
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+ iwlcore_commit_rxon(priv, ctx);
+ }
+ }
}
static void iwl_clear_free_frames(struct iwl_priv *priv)
@@ -284,24 +314,26 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
}
static u32 iwl_fill_beacon_frame(struct iwl_priv *priv,
- struct ieee80211_hdr *hdr,
- int left)
+ struct ieee80211_hdr *hdr,
+ int left)
{
- if (!priv->ibss_beacon)
+ lockdep_assert_held(&priv->mutex);
+
+ if (!priv->beacon_skb)
return 0;
- if (priv->ibss_beacon->len > left)
+ if (priv->beacon_skb->len > left)
return 0;
- memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len);
+ memcpy(hdr, priv->beacon_skb->data, priv->beacon_skb->len);
- return priv->ibss_beacon->len;
+ return priv->beacon_skb->len;
}
/* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */
static void iwl_set_beacon_tim(struct iwl_priv *priv,
- struct iwl_tx_beacon_cmd *tx_beacon_cmd,
- u8 *beacon, u32 frame_size)
+ struct iwl_tx_beacon_cmd *tx_beacon_cmd,
+ u8 *beacon, u32 frame_size)
{
u16 tim_idx;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon;
@@ -337,6 +369,13 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
* beacon contents.
*/
+ lockdep_assert_held(&priv->mutex);
+
+ if (!priv->beacon_ctx) {
+ IWL_ERR(priv, "trying to build beacon w/o beacon context!\n");
+ return 0;
+ }
+
/* Initialize memory */
tx_beacon_cmd = &frame->u.beacon;
memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
@@ -346,20 +385,22 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
sizeof(frame->u) - sizeof(*tx_beacon_cmd));
if (WARN_ON_ONCE(frame_size > MAX_MPDU_SIZE))
return 0;
+ if (!frame_size)
+ return 0;
/* Set up TX command fields */
tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
- tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
+ tx_beacon_cmd->tx.sta_id = priv->beacon_ctx->bcast_sta_id;
tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK;
/* Set up TX beacon command fields */
iwl_set_beacon_tim(priv, tx_beacon_cmd, (u8 *)tx_beacon_cmd->frame,
- frame_size);
+ frame_size);
/* Set up packet rate and flags */
- rate = iwl_rate_get_lowest_plcp(priv);
+ rate = iwl_rate_get_lowest_plcp(priv, priv->beacon_ctx);
priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
priv->hw_params.valid_tx_ant);
rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
@@ -592,23 +633,83 @@ static void iwl_bg_beacon_update(struct work_struct *work)
container_of(work, struct iwl_priv, beacon_update);
struct sk_buff *beacon;
- /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
- beacon = ieee80211_beacon_get(priv->hw, priv->vif);
+ mutex_lock(&priv->mutex);
+ if (!priv->beacon_ctx) {
+ IWL_ERR(priv, "updating beacon w/o beacon context!\n");
+ goto out;
+ }
+
+ if (priv->beacon_ctx->vif->type != NL80211_IFTYPE_AP) {
+ /*
+ * The ucode will send beacon notifications even in
+ * IBSS mode, but we don't want to process them. But
+ * we need to defer the type check to here due to
+ * requiring locking around the beacon_ctx access.
+ */
+ goto out;
+ }
+ /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
+ beacon = ieee80211_beacon_get(priv->hw, priv->beacon_ctx->vif);
if (!beacon) {
- IWL_ERR(priv, "update beacon failed\n");
- return;
+ IWL_ERR(priv, "update beacon failed -- keeping old\n");
+ goto out;
}
- mutex_lock(&priv->mutex);
/* new beacon skb is allocated every time; dispose previous.*/
- if (priv->ibss_beacon)
- dev_kfree_skb(priv->ibss_beacon);
+ dev_kfree_skb(priv->beacon_skb);
- priv->ibss_beacon = beacon;
- mutex_unlock(&priv->mutex);
+ priv->beacon_skb = beacon;
iwl_send_beacon_cmd(priv);
+ out:
+ mutex_unlock(&priv->mutex);
+}
+
+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))
+ return;
+
+ /* dont send host command if rf-kill is on */
+ if (!iwl_is_ready_rf(priv))
+ return;
+ priv->cfg->ops->hcmd->send_bt_config(priv);
+}
+
+static void iwl_bg_bt_full_concurrency(struct work_struct *work)
+{
+ struct iwl_priv *priv =
+ container_of(work, struct iwl_priv, bt_full_concurrency);
+ struct iwl_rxon_context *ctx;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ /* dont send host command if rf-kill is on */
+ if (!iwl_is_ready_rf(priv))
+ return;
+
+ IWL_DEBUG_INFO(priv, "BT coex in %s mode\n",
+ priv->bt_full_concurrent ?
+ "full concurrency" : "3-wire");
+
+ /*
+ * LQ & RXON updated cmds must be sent before BT Config cmd
+ * to avoid 3-wire collisions
+ */
+ mutex_lock(&priv->mutex);
+ for_each_context(priv, ctx) {
+ if (priv->cfg->ops->hcmd->set_rxon_chain)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+ iwlcore_commit_rxon(priv, ctx);
+ }
+ mutex_unlock(&priv->mutex);
+
+ priv->cfg->ops->hcmd->send_bt_config(priv);
}
/**
@@ -763,10 +864,10 @@ static void iwl_bg_ucode_trace(unsigned long data)
static void iwl_rx_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
-#ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl4965_beacon_notif *beacon =
(struct iwl4965_beacon_notif *)pkt->u.raw;
+#ifdef CONFIG_IWLWIFI_DEBUG
u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
IWL_DEBUG_RX(priv, "beacon status %x retries %d iss %d "
@@ -778,8 +879,9 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
le32_to_cpu(beacon->low_tsf), rate);
#endif
- if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
- (!test_bit(STATUS_EXIT_PENDING, &priv->status)))
+ 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);
}
@@ -836,22 +938,6 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
wake_up_interruptible(&priv->wait_command_queue);
}
-int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
-{
- if (src == IWL_PWR_SRC_VAUX) {
- 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);
- } else {
- iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
- APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
- ~APMG_PS_CTRL_MSK_PWR_SRC);
- }
-
- return 0;
-}
-
static void iwl_bg_tx_flush(struct work_struct *work)
{
struct iwl_priv *priv =
@@ -1181,7 +1267,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
IWL_ERR(priv, "Microcode SW error detected. "
" Restarting 0x%X.\n", inta);
priv->isr_stats.sw++;
- priv->isr_stats.sw_err = inta;
iwl_irq_handle_error(priv);
handled |= CSR_INT_BIT_SW_ERR;
}
@@ -1362,7 +1447,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
IWL_ERR(priv, "Microcode SW error detected. "
" Restarting 0x%X.\n", inta);
priv->isr_stats.sw++;
- priv->isr_stats.sw_err = inta;
iwl_irq_handle_error(priv);
handled |= CSR_INT_BIT_SW_ERR;
}
@@ -1650,30 +1734,44 @@ static void iwl_nic_start(struct iwl_priv *priv)
struct iwlagn_ucode_capabilities {
u32 max_probe_length;
u32 standard_phy_calibration_size;
+ bool pan;
};
static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
static int iwl_mac_setup_register(struct iwl_priv *priv,
struct iwlagn_ucode_capabilities *capa);
+#define UCODE_EXPERIMENTAL_INDEX 100
+#define UCODE_EXPERIMENTAL_TAG "exp"
+
static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
{
const char *name_pre = priv->cfg->fw_name_pre;
+ char tag[8];
- if (first)
+ if (first) {
+#ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
+ priv->fw_index = UCODE_EXPERIMENTAL_INDEX;
+ strcpy(tag, UCODE_EXPERIMENTAL_TAG);
+ } else if (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) {
+#endif
priv->fw_index = priv->cfg->ucode_api_max;
- else
+ sprintf(tag, "%d", priv->fw_index);
+ } else {
priv->fw_index--;
+ sprintf(tag, "%d", priv->fw_index);
+ }
if (priv->fw_index < priv->cfg->ucode_api_min) {
IWL_ERR(priv, "no suitable firmware found!\n");
return -ENOENT;
}
- sprintf(priv->firmware_name, "%s%d%s",
- name_pre, priv->fw_index, ".ucode");
+ sprintf(priv->firmware_name, "%s%s%s", name_pre, tag, ".ucode");
- IWL_DEBUG_INFO(priv, "attempting to load firmware '%s'\n",
+ IWL_DEBUG_INFO(priv, "attempting to load firmware %s'%s'\n",
+ (priv->fw_index == UCODE_EXPERIMENTAL_INDEX)
+ ? "EXPERIMENTAL " : "",
priv->firmware_name);
return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name,
@@ -1874,6 +1972,11 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
capa->max_probe_length =
le32_to_cpup((__le32 *)tlv_data);
break;
+ case IWL_UCODE_TLV_PAN:
+ if (tlv_len)
+ goto invalid_tlv_len;
+ capa->pan = true;
+ break;
case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
if (tlv_len != sizeof(u32))
goto invalid_tlv_len;
@@ -1962,14 +2065,16 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
struct iwlagn_ucode_capabilities ucode_capa = {
.max_probe_length = 200,
.standard_phy_calibration_size =
- IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE,
+ IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE,
};
memset(&pieces, 0, sizeof(pieces));
if (!ucode_raw) {
- IWL_ERR(priv, "request for firmware file '%s' failed.\n",
- priv->firmware_name);
+ if (priv->fw_index <= priv->cfg->ucode_api_max)
+ IWL_ERR(priv,
+ "request for firmware file '%s' failed.\n",
+ priv->firmware_name);
goto try_again;
}
@@ -2002,21 +2107,28 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
* firmware filename ... but we don't check for that and only rely
* on the API version read from firmware header from here on forward
*/
- if (api_ver < api_min || api_ver > api_max) {
- IWL_ERR(priv, "Driver unable to support your firmware API. "
- "Driver supports v%u, firmware is v%u.\n",
- api_max, api_ver);
- goto try_again;
- }
+ /* no api version check required for experimental uCode */
+ if (priv->fw_index != UCODE_EXPERIMENTAL_INDEX) {
+ if (api_ver < api_min || api_ver > api_max) {
+ IWL_ERR(priv,
+ "Driver unable to support your firmware API. "
+ "Driver supports v%u, firmware is v%u.\n",
+ api_max, api_ver);
+ goto try_again;
+ }
- if (api_ver != api_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_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 (build)
- sprintf(buildstr, " build %u", build);
+ sprintf(buildstr, " build %u%s", build,
+ (priv->fw_index == UCODE_EXPERIMENTAL_INDEX)
+ ? " (EXP)" : "");
else
buildstr[0] = '\0';
@@ -2136,15 +2248,23 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
if (pieces.init_evtlog_size)
priv->_agn.init_evtlog_size = (pieces.init_evtlog_size - 16)/12;
else
- priv->_agn.init_evtlog_size = priv->cfg->max_event_log_size;
+ priv->_agn.init_evtlog_size =
+ priv->cfg->base_params->max_event_log_size;
priv->_agn.init_errlog_ptr = pieces.init_errlog_ptr;
priv->_agn.inst_evtlog_ptr = pieces.inst_evtlog_ptr;
if (pieces.inst_evtlog_size)
priv->_agn.inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12;
else
- priv->_agn.inst_evtlog_size = priv->cfg->max_event_log_size;
+ priv->_agn.inst_evtlog_size =
+ priv->cfg->base_params->max_event_log_size;
priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr;
+ if (ucode_capa.pan) {
+ priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
+ priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
+ } else
+ priv->sta_key_max_num = STA_KEY_MAX_NUM;
+
/* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */
@@ -2341,6 +2461,7 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
}
desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
+ priv->isr_stats.err_code = desc;
pc = iwl_read_targ_mem(priv, base + 2 * sizeof(u32));
blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
@@ -2543,6 +2664,9 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
return pos;
}
+ /* enable/disable bt channel announcement */
+ 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)
@@ -2589,6 +2713,69 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
return pos;
}
+static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
+{
+ struct iwl_ct_kill_config cmd;
+ struct iwl_ct_kill_throttling_config adv_cmd;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+ spin_unlock_irqrestore(&priv->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);
+ adv_cmd.critical_temperature_exit =
+ cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
+
+ ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
+ 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);
+ } else {
+ cmd.critical_temperature_R =
+ cpu_to_le32(priv->hw_params.ct_kill_threshold);
+
+ ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
+ 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);
+ }
+}
+
+static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
+{
+ struct iwl_calib_cfg_cmd calib_cfg_cmd;
+ struct iwl_host_cmd cmd = {
+ .id = CALIBRATION_CFG_CMD,
+ .len = sizeof(struct iwl_calib_cfg_cmd),
+ .data = &calib_cfg_cmd,
+ };
+
+ 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.start = cpu_to_le32(cfg);
+
+ return iwl_send_cmd(priv, &cmd);
+}
+
+
/**
* iwl_alive_start - called after REPLY_ALIVE notification received
* from protocol/runtime uCode (initialization uCode's
@@ -2597,6 +2784,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
static void iwl_alive_start(struct iwl_priv *priv)
{
int ret = 0;
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
@@ -2624,6 +2812,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
goto restart;
}
+
/* After the ALIVE response, we can send host commands to the uCode */
set_bit(STATUS_ALIVE, &priv->status);
@@ -2631,12 +2820,33 @@ static void iwl_alive_start(struct iwl_priv *priv)
/* Enable timer to monitor the driver queues */
mod_timer(&priv->monitor_recover,
jiffies +
- msecs_to_jiffies(priv->cfg->monitor_recover_period));
+ msecs_to_jiffies(
+ priv->cfg->base_params->monitor_recover_period));
}
if (iwl_is_rfkill(priv))
return;
+ /* download priority table before any calibration request */
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist) {
+ /* Configure Bluetooth device coexistence support */
+ priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
+ priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
+ priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
+ priv->cfg->ops->hcmd->send_bt_config(priv);
+ priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS;
+ iwlagn_send_prio_tbl(priv);
+
+ /* FIXME: w/a to force change uCode BT state machine */
+ iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
+ BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+ iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
+ BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+ }
+ if (priv->hw_params.calib_rt_cfg)
+ iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg);
+
ieee80211_wake_queues(priv->hw);
priv->active_rate = IWL_RATES_MASK;
@@ -2645,27 +2855,32 @@ static void iwl_alive_start(struct iwl_priv *priv)
if (priv->cfg->ops->hcmd->set_tx_ant)
priv->cfg->ops->hcmd->set_tx_ant(priv, priv->cfg->valid_tx_ant);
- if (iwl_is_associated(priv)) {
+ if (iwl_is_associated_ctx(ctx)) {
struct iwl_rxon_cmd *active_rxon =
- (struct iwl_rxon_cmd *)&priv->active_rxon;
+ (struct iwl_rxon_cmd *)&ctx->active;
/* apply any changes in staging */
- priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+ ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
} else {
+ struct iwl_rxon_context *tmp;
/* Initialize our rx_config data */
- iwl_connection_init_rx_config(priv, NULL);
+ for_each_context(priv, tmp)
+ iwl_connection_init_rx_config(priv, tmp);
if (priv->cfg->ops->hcmd->set_rxon_chain)
- priv->cfg->ops->hcmd->set_rxon_chain(priv);
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
}
- /* Configure Bluetooth device coexistence support */
- priv->cfg->ops->hcmd->send_bt_config(priv);
+ if (priv->cfg->bt_params &&
+ !priv->cfg->bt_params->advanced_bt_coexist) {
+ /* Configure Bluetooth device coexistence support */
+ priv->cfg->ops->hcmd->send_bt_config(priv);
+ }
iwl_reset_run_time_calib(priv);
/* Configure the adapter for unassociated operation */
- iwlcore_commit_rxon(priv);
+ iwlcore_commit_rxon(priv, ctx);
/* At this point, the NIC is initialized and operational */
iwl_rf_kill_ct_config(priv);
@@ -2695,13 +2910,30 @@ static void __iwl_down(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
- if (!exit_pending)
- set_bit(STATUS_EXIT_PENDING, &priv->status);
+ iwl_scan_cancel_timeout(priv, 200);
- iwl_clear_ucode_stations(priv);
- iwl_dealloc_bcast_station(priv);
+ exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
+
+ /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
+ * to prevent rearm timer */
+ if (priv->cfg->ops->lib->recover_from_tx_stall)
+ del_timer_sync(&priv->monitor_recover);
+
+ iwl_clear_ucode_stations(priv, NULL);
+ iwl_dealloc_bcast_stations(priv);
iwl_clear_driver_stations(priv);
+ /* reset BT coex data */
+ priv->bt_status = 0;
+ if (priv->cfg->bt_params)
+ priv->bt_traffic_load =
+ priv->cfg->bt_params->bt_init_traffic_load;
+ else
+ priv->bt_traffic_load = 0;
+ priv->bt_sco_active = false;
+ priv->bt_full_concurrent = false;
+ priv->bt_ci_compliance = 0;
+
/* Unblock any waiting calls */
wake_up_interruptible_all(&priv->wait_command_queue);
@@ -2759,14 +2991,13 @@ static void __iwl_down(struct iwl_priv *priv)
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 */
- priv->cfg->ops->lib->apm_ops.stop(priv);
+ iwl_apm_stop(priv);
exit:
memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
- if (priv->ibss_beacon)
- dev_kfree_skb(priv->ibss_beacon);
- priv->ibss_beacon = NULL;
+ dev_kfree_skb(priv->beacon_skb);
+ priv->beacon_skb = NULL;
/* clear out any free frames */
iwl_clear_free_frames(priv);
@@ -2834,6 +3065,7 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
static int __iwl_up(struct iwl_priv *priv)
{
+ struct iwl_rxon_context *ctx;
int i;
int ret;
@@ -2847,9 +3079,13 @@ static int __iwl_up(struct iwl_priv *priv)
return -EIO;
}
- ret = iwl_alloc_bcast_station(priv, true);
- if (ret)
- return ret;
+ for_each_context(priv, ctx) {
+ ret = iwlagn_alloc_bcast_station(priv, ctx);
+ if (ret) {
+ iwl_dealloc_bcast_stations(priv);
+ return ret;
+ }
+ }
iwl_prepare_card_hw(priv);
@@ -2874,6 +3110,12 @@ static int __iwl_up(struct iwl_priv *priv)
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+ /* must be initialised before iwl_hw_nic_init */
+ 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;
+
ret = iwlagn_hw_nic_init(priv);
if (ret) {
IWL_ERR(priv, "Unable to init nic\n");
@@ -2980,7 +3222,8 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
}
if (priv->start_calib) {
- if (priv->cfg->bt_statistics) {
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->bt_statistics) {
iwl_chain_noise_calibration(priv,
(void *)&priv->_agn.statistics_bt);
iwl_sensitivity_calibration(priv,
@@ -3004,11 +3247,42 @@ static void iwl_bg_restart(struct work_struct *data)
return;
if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
+ struct iwl_rxon_context *ctx;
+ bool bt_sco, bt_full_concurrent;
+ u8 bt_ci_compliance;
+ u8 bt_load;
+ u8 bt_status;
+
mutex_lock(&priv->mutex);
- priv->vif = NULL;
+ for_each_context(priv, ctx)
+ ctx->vif = NULL;
priv->is_open = 0;
+
+ /*
+ * __iwl_down() will clear the BT status variables,
+ * which is correct, but when we restart we really
+ * want to keep them so restore them afterwards.
+ *
+ * The restart process will later pick them up and
+ * re-configure the hw when we reconfigure the BT
+ * command.
+ */
+ bt_sco = priv->bt_sco_active;
+ bt_full_concurrent = priv->bt_full_concurrent;
+ bt_ci_compliance = priv->bt_ci_compliance;
+ bt_load = priv->bt_traffic_load;
+ bt_status = priv->bt_status;
+
+ __iwl_down(priv);
+
+ priv->bt_sco_active = bt_sco;
+ priv->bt_full_concurrent = bt_full_concurrent;
+ priv->bt_ci_compliance = bt_ci_compliance;
+ priv->bt_traffic_load = bt_load;
+ priv->bt_status = bt_status;
+
mutex_unlock(&priv->mutex);
- iwl_down(priv);
+ iwl_cancel_deferred_work(priv);
ieee80211_restart_hw(priv->hw);
} else {
iwl_down(priv);
@@ -3039,12 +3313,15 @@ static void iwl_bg_rx_replenish(struct work_struct *data)
void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
{
+ struct iwl_rxon_context *ctx;
struct ieee80211_conf *conf = NULL;
int ret = 0;
if (!vif || !priv->is_open)
return;
+ ctx = iwl_rxon_ctx_from_vif(vif);
+
if (vif->type == NL80211_IFTYPE_AP) {
IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__);
return;
@@ -3057,44 +3334,42 @@ void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
conf = ieee80211_get_hw_conf(priv->hw);
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwlcore_commit_rxon(priv);
+ ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwlcore_commit_rxon(priv, ctx);
- iwl_setup_rxon_timing(priv, vif);
- ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
- sizeof(priv->rxon_timing), &priv->rxon_timing);
+ ret = iwl_send_rxon_timing(priv, ctx);
if (ret)
- IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
+ IWL_WARN(priv, "RXON timing - "
"Attempting to continue.\n");
- priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+ ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
iwl_set_rxon_ht(priv, &priv->current_ht_config);
if (priv->cfg->ops->hcmd->set_rxon_chain)
- priv->cfg->ops->hcmd->set_rxon_chain(priv);
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
- priv->staging_rxon.assoc_id = cpu_to_le16(vif->bss_conf.aid);
+ ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
vif->bss_conf.aid, vif->bss_conf.beacon_int);
if (vif->bss_conf.use_short_preamble)
- priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+ ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
else
- priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+ ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
- if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+ if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
if (vif->bss_conf.use_short_slot)
- priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
else
- priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+ ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
}
- iwlcore_commit_rxon(priv);
+ iwlcore_commit_rxon(priv, ctx);
IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
- vif->bss_conf.aid, priv->active_rxon.bssid_addr);
+ vif->bss_conf.aid, ctx->active.bssid_addr);
switch (vif->type) {
case NL80211_IFTYPE_STATION:
@@ -3137,14 +3412,17 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
{
int ret;
struct ieee80211_hw *hw = priv->hw;
+ struct iwl_rxon_context *ctx;
+
hw->rate_control_algorithm = "iwl-agn-rs";
/* Tell mac80211 our characteristics */
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_AMPDU_AGGREGATION |
+ IEEE80211_HW_NEED_DTIM_PERIOD |
IEEE80211_HW_SPECTRUM_MGMT;
- if (!priv->cfg->broken_powersave)
+ if (!priv->cfg->base_params->broken_powersave)
hw->flags |= IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
@@ -3155,9 +3433,10 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
hw->sta_data_size = sizeof(struct iwl_station_priv);
hw->vif_data_size = sizeof(struct iwl_vif_priv);
- hw->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC);
+ for_each_context(priv, ctx) {
+ hw->wiphy->interface_modes |= ctx->interface_modes;
+ hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
+ }
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_DISABLE_BEACON_HINTS;
@@ -3247,15 +3526,6 @@ static void iwl_mac_stop(struct ieee80211_hw *hw)
priv->is_open = 0;
- if (iwl_is_ready_rf(priv) || test_bit(STATUS_SCAN_HW, &priv->status)) {
- /* stop mac, cancel any scan request and clear
- * RXON_FILTER_ASSOC_MSK BIT
- */
- mutex_lock(&priv->mutex);
- iwl_scan_cancel_timeout(priv, 100);
- mutex_unlock(&priv->mutex);
- }
-
iwl_down(priv);
flush_workqueue(priv->workqueue);
@@ -3285,24 +3555,25 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
{
+ struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
int ret = 0;
+ lockdep_assert_held(&priv->mutex);
+
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
/* The following should be done only at AP bring up */
- if (!iwl_is_associated(priv)) {
+ if (!iwl_is_associated_ctx(ctx)) {
/* RXON - unassoc (to set timing command) */
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwlcore_commit_rxon(priv);
+ ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwlcore_commit_rxon(priv, ctx);
/* RXON Timing */
- iwl_setup_rxon_timing(priv, vif);
- ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
- sizeof(priv->rxon_timing), &priv->rxon_timing);
+ ret = iwl_send_rxon_timing(priv, ctx);
if (ret)
- IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
+ IWL_WARN(priv, "RXON timing failed - "
"Attempting to continue.\n");
/* AP has all antennas */
@@ -3310,28 +3581,30 @@ void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
priv->hw_params.valid_rx_ant;
iwl_set_rxon_ht(priv, &priv->current_ht_config);
if (priv->cfg->ops->hcmd->set_rxon_chain)
- priv->cfg->ops->hcmd->set_rxon_chain(priv);
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
- priv->staging_rxon.assoc_id = 0;
+ ctx->staging.assoc_id = 0;
if (vif->bss_conf.use_short_preamble)
- priv->staging_rxon.flags |=
+ ctx->staging.flags |=
RXON_FLG_SHORT_PREAMBLE_MSK;
else
- priv->staging_rxon.flags &=
+ ctx->staging.flags &=
~RXON_FLG_SHORT_PREAMBLE_MSK;
- if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+ if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
if (vif->bss_conf.use_short_slot)
- priv->staging_rxon.flags |=
+ ctx->staging.flags |=
RXON_FLG_SHORT_SLOT_MSK;
else
- priv->staging_rxon.flags &=
+ ctx->staging.flags &=
~RXON_FLG_SHORT_SLOT_MSK;
}
+ /* need to send beacon cmd before committing assoc RXON! */
+ iwl_send_beacon_cmd(priv);
/* restore RXON assoc */
- priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
- iwlcore_commit_rxon(priv);
+ ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+ iwlcore_commit_rxon(priv, ctx);
}
iwl_send_beacon_cmd(priv);
@@ -3348,9 +3621,11 @@ static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
{
struct iwl_priv *priv = hw->priv;
+ struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+
IWL_DEBUG_MAC80211(priv, "enter\n");
- iwl_update_tkip_key(priv, keyconf, sta,
+ iwl_update_tkip_key(priv, vif_priv->ctx, keyconf, sta,
iv32, phase1key);
IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -3362,6 +3637,8 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_key_conf *key)
{
struct iwl_priv *priv = hw->priv;
+ struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+ struct iwl_rxon_context *ctx = vif_priv->ctx;
int ret;
u8 sta_id;
bool is_default_wep_key = false;
@@ -3373,7 +3650,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return -EOPNOTSUPP;
}
- sta_id = iwl_sta_id_or_broadcast(priv, sta);
+ sta_id = iwl_sta_id_or_broadcast(priv, vif_priv->ctx, sta);
if (sta_id == IWL_INVALID_STATION)
return -EINVAL;
@@ -3386,9 +3663,11 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* in 1X mode.
* In legacy wep mode, we use another host command to the uCode.
*/
- if (key->alg == ALG_WEP && !sta && vif->type != NL80211_IFTYPE_AP) {
+ if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+ key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
+ !sta) {
if (cmd == SET_KEY)
- is_default_wep_key = !priv->key_mapping_key;
+ is_default_wep_key = !ctx->key_mapping_keys;
else
is_default_wep_key =
(key->hw_key_idx == HW_KEY_DEFAULT);
@@ -3397,17 +3676,18 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
switch (cmd) {
case SET_KEY:
if (is_default_wep_key)
- ret = iwl_set_default_wep_key(priv, key);
+ ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key);
else
- ret = iwl_set_dynamic_key(priv, key, sta_id);
+ ret = iwl_set_dynamic_key(priv, vif_priv->ctx,
+ key, sta_id);
IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
break;
case DISABLE_KEY:
if (is_default_wep_key)
- ret = iwl_remove_default_wep_key(priv, key);
+ ret = iwl_remove_default_wep_key(priv, ctx, key);
else
- ret = iwl_remove_dynamic_key(priv, key, sta_id);
+ ret = iwl_remove_dynamic_key(priv, ctx, key, sta_id);
IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
break;
@@ -3467,7 +3747,8 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
}
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
ret = 0;
- if (priv->cfg->use_rts_for_aggregation) {
+ if (priv->cfg->ht_params &&
+ priv->cfg->ht_params->use_rts_for_aggregation) {
struct iwl_station_priv *sta_priv =
(void *) sta->drv_priv;
/*
@@ -3476,12 +3757,13 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
sta_priv->lq_sta.lq.general_params.flags &=
~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
- iwl_send_lq_cmd(priv, &sta_priv->lq_sta.lq,
- CMD_ASYNC, false);
+ iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
+ &sta_priv->lq_sta.lq, CMD_ASYNC, false);
}
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
- if (priv->cfg->use_rts_for_aggregation) {
+ if (priv->cfg->ht_params &&
+ priv->cfg->ht_params->use_rts_for_aggregation) {
struct iwl_station_priv *sta_priv =
(void *) sta->drv_priv;
@@ -3492,8 +3774,8 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
sta_priv->lq_sta.lq.general_params.flags |=
LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
- iwl_send_lq_cmd(priv, &sta_priv->lq_sta.lq,
- CMD_ASYNC, false);
+ iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
+ &sta_priv->lq_sta.lq, CMD_ASYNC, false);
}
ret = 0;
break;
@@ -3539,6 +3821,7 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
{
struct iwl_priv *priv = hw->priv;
struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+ struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
bool is_ap = vif->type == NL80211_IFTYPE_STATION;
int ret;
u8 sta_id;
@@ -3554,8 +3837,8 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
if (vif->type == NL80211_IFTYPE_AP)
sta_priv->client = true;
- ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap,
- &sta_id);
+ ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr,
+ is_ap, sta, &sta_id);
if (ret) {
IWL_ERR(priv, "Unable to add station %pM (%d)\n",
sta->addr, ret);
@@ -3581,7 +3864,17 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
struct iwl_priv *priv = hw->priv;
const struct iwl_channel_info *ch_info;
struct ieee80211_conf *conf = &hw->conf;
+ struct ieee80211_channel *channel = ch_switch->channel;
struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+ /*
+ * MULTI-FIXME
+ * When we add support for multiple interfaces, we need to
+ * revisit this. The channel switch command in the device
+ * only affects the BSS context, but what does that really
+ * mean? And what if we get a CSA on the second interface?
+ * This needs a lot of work.
+ */
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
u16 ch;
unsigned long flags = 0;
@@ -3594,7 +3887,7 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
test_bit(STATUS_SCANNING, &priv->status))
goto out_exit;
- if (!iwl_is_associated(priv))
+ if (!iwl_is_associated_ctx(ctx))
goto out_exit;
/* channel switch in progress */
@@ -3604,11 +3897,10 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
mutex_lock(&priv->mutex);
if (priv->cfg->ops->lib->set_channel_switch) {
- ch = ieee80211_frequency_to_channel(
- ch_switch->channel->center_freq);
- if (le16_to_cpu(priv->active_rxon.channel) != ch) {
+ ch = channel->hw_value;
+ if (le16_to_cpu(ctx->active.channel) != ch) {
ch_info = iwl_get_channel_info(priv,
- conf->channel->band,
+ channel->band,
ch);
if (!is_channel_valid(ch_info)) {
IWL_DEBUG_MAC80211(priv, "invalid channel\n");
@@ -3619,34 +3911,31 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
priv->current_ht_config.smps = conf->smps_mode;
/* Configure HT40 channels */
- ht_conf->is_ht = conf_is_ht(conf);
- if (ht_conf->is_ht) {
+ ctx->ht.enabled = conf_is_ht(conf);
+ if (ctx->ht.enabled) {
if (conf_is_ht40_minus(conf)) {
- ht_conf->extension_chan_offset =
+ ctx->ht.extension_chan_offset =
IEEE80211_HT_PARAM_CHA_SEC_BELOW;
- ht_conf->is_40mhz = true;
+ ctx->ht.is_40mhz = true;
} else if (conf_is_ht40_plus(conf)) {
- ht_conf->extension_chan_offset =
+ ctx->ht.extension_chan_offset =
IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
- ht_conf->is_40mhz = true;
+ ctx->ht.is_40mhz = true;
} else {
- ht_conf->extension_chan_offset =
+ ctx->ht.extension_chan_offset =
IEEE80211_HT_PARAM_CHA_SEC_NONE;
- ht_conf->is_40mhz = false;
+ ctx->ht.is_40mhz = false;
}
} else
- ht_conf->is_40mhz = false;
+ ctx->ht.is_40mhz = false;
- /* if we are switching from ht to 2.4 clear flags
- * from any ht related info since 2.4 does not
- * support ht */
- if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
- priv->staging_rxon.flags = 0;
+ if ((le16_to_cpu(ctx->staging.channel) != ch))
+ ctx->staging.flags = 0;
- iwl_set_rxon_channel(priv, conf->channel);
+ iwl_set_rxon_channel(priv, channel, ctx);
iwl_set_rxon_ht(priv, ht_conf);
- iwl_set_flags_for_band(priv, conf->channel->band,
- priv->vif);
+ iwl_set_flags_for_band(priv, ctx, channel->band,
+ ctx->vif);
spin_unlock_irqrestore(&priv->lock, flags);
iwl_set_rate(priv);
@@ -3663,7 +3952,7 @@ out:
mutex_unlock(&priv->mutex);
out_exit:
if (!priv->switch_rxon.switch_in_progress)
- ieee80211_chswitch_done(priv->vif, false);
+ ieee80211_chswitch_done(ctx->vif, false);
IWL_DEBUG_MAC80211(priv, "leave\n");
}
@@ -3674,6 +3963,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
{
struct iwl_priv *priv = hw->priv;
__le32 filter_or = 0, filter_nand = 0;
+ struct iwl_rxon_context *ctx;
#define CHK(test, flag) do { \
if (*total_flags & (test)) \
@@ -3693,10 +3983,11 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
mutex_lock(&priv->mutex);
- priv->staging_rxon.filter_flags &= ~filter_nand;
- priv->staging_rxon.filter_flags |= filter_or;
-
- iwlcore_commit_rxon(priv);
+ for_each_context(priv, ctx) {
+ ctx->staging.filter_flags &= ~filter_nand;
+ ctx->staging.filter_flags |= filter_or;
+ iwlcore_commit_rxon(priv, ctx);
+ }
mutex_unlock(&priv->mutex);
@@ -3765,6 +4056,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
+ INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
+ INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
@@ -3788,7 +4081,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
priv->cfg->ops->lib->recover_from_tx_stall;
}
- if (!priv->cfg->use_isr_legacy)
+ if (!priv->cfg->base_params->use_isr_legacy)
tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
iwl_irq_tasklet, (unsigned long)priv);
else
@@ -3802,15 +4095,17 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
priv->cfg->ops->lib->cancel_deferred_work(priv);
cancel_delayed_work_sync(&priv->init_alive_start);
- cancel_delayed_work(&priv->scan_check);
- cancel_work_sync(&priv->start_internal_scan);
cancel_delayed_work(&priv->alive_start);
cancel_work_sync(&priv->run_time_calib_work);
cancel_work_sync(&priv->beacon_update);
+
+ iwl_cancel_scan_deferred_work(priv);
+
+ cancel_work_sync(&priv->bt_full_concurrency);
+ cancel_work_sync(&priv->bt_runtime_config);
+
del_timer_sync(&priv->statistics_periodic);
del_timer_sync(&priv->ucode_trace);
- if (priv->cfg->ops->lib->recover_from_tx_stall)
- del_timer_sync(&priv->monitor_recover);
}
static void iwl_init_hw_rates(struct iwl_priv *priv,
@@ -3838,8 +4133,6 @@ static int iwl_init_drv(struct iwl_priv *priv)
{
int ret;
- priv->ibss_beacon = NULL;
-
spin_lock_init(&priv->sta_lock);
spin_lock_init(&priv->hcmd_lock);
@@ -3865,10 +4158,23 @@ static int iwl_init_drv(struct iwl_priv *priv)
/* Choose which receivers/antennas to use */
if (priv->cfg->ops->hcmd->set_rxon_chain)
- priv->cfg->ops->hcmd->set_rxon_chain(priv);
+ priv->cfg->ops->hcmd->set_rxon_chain(priv,
+ &priv->contexts[IWL_RXON_CTX_BSS]);
iwl_init_scan_params(priv);
+ /* init bt coex */
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist) {
+ priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
+ priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
+ priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
+ priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
+ priv->bt_duration = BT_DURATION_LIMIT_DEF;
+ priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
+ priv->dynamic_agg_thresh = BT_AGG_THRESHOLD_DEF;
+ }
+
/* Set the tx_power_user_lmt to the lowest power level
* this value will get overwritten by channel max power avg
* from eeprom */
@@ -3923,11 +4229,60 @@ static struct ieee80211_ops iwl_hw_ops = {
.sta_remove = iwl_mac_sta_remove,
.channel_switch = iwl_mac_channel_switch,
.flush = iwl_mac_flush,
+ .tx_last_beacon = iwl_mac_tx_last_beacon,
+};
+
+static void iwl_hw_detect(struct iwl_priv *priv)
+{
+ priv->hw_rev = _iwl_read32(priv, CSR_HW_REV);
+ priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG);
+ pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id);
+ IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id);
+}
+
+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 (priv->cfg->mod_params->amsdu_size_8K)
+ priv->hw_params.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;
+
+ if (priv->cfg->mod_params->disable_11n)
+ priv->cfg->sku &= ~IWL_SKU_N;
+
+ /* Device-specific setup */
+ return priv->cfg->ops->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,
};
static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- int err = 0;
+ int err = 0, i;
struct iwl_priv *priv;
struct ieee80211_hw *hw;
struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
@@ -3941,9 +4296,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan. */
if (cfg->mod_params->disable_hw_scan) {
- if (iwl_debug_level & IWL_DL_INFO)
- dev_printk(KERN_DEBUG, &(pdev->dev),
- "Disabling hw_scan\n");
+ dev_printk(KERN_DEBUG, &(pdev->dev),
+ "sw scan support is deprecated\n");
iwl_hw_ops.hw_scan = NULL;
}
@@ -3955,6 +4309,53 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
priv = hw->priv;
/* At this point both hw and priv are allocated. */
+ /*
+ * 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].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);
+ 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);
+
SET_IEEE80211_DEV(hw, &pdev->dev);
IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
@@ -3962,12 +4363,23 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
priv->pci_dev = pdev;
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;
+
+ /* enable/disable bt channel announcement */
+ priv->bt_ch_announce = iwlagn_bt_ch_announce;
+
if (iwl_alloc_traffic_mem(priv))
IWL_ERR(priv, "Not enough memory to generate traffic log\n");
/**************************
* 2. Initializing PCI bus
**************************/
+ pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
+ PCIE_LINK_STATE_CLKPM);
+
if (pci_enable_device(pdev)) {
err = -ENODEV;
goto out_ieee80211_free_hw;
@@ -4190,7 +4602,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
* paths to avoid running iwl_down() at all before leaving driver.
* This (inexpensive) call *makes sure* device is reset.
*/
- priv->cfg->ops->lib->apm_ops.stop(priv);
+ iwl_apm_stop(priv);
iwl_tt_exit(priv);
@@ -4233,8 +4645,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
iwl_free_isr_ict(priv);
- if (priv->ibss_beacon)
- dev_kfree_skb(priv->ibss_beacon);
+ dev_kfree_skb(priv->beacon_skb);
ieee80211_free_hw(priv->hw);
}
@@ -4398,6 +4809,22 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x0083, 0x1326, iwl1000_bg_cfg)},
{IWL_PCI_DEVICE(0x0084, 0x1216, iwl1000_bg_cfg)},
{IWL_PCI_DEVICE(0x0084, 0x1316, iwl1000_bg_cfg)},
+
+/* 100 Series WiFi */
+ {IWL_PCI_DEVICE(0x08AE, 0x1005, iwl100_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x08AF, 0x1015, iwl100_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x08AE, 0x1025, iwl100_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x08AE, 0x1007, iwl100_bg_cfg)},
+ {IWL_PCI_DEVICE(0x08AE, 0x1017, iwl100_bg_cfg)},
+
+/* 130 Series WiFi */
+ {IWL_PCI_DEVICE(0x0896, 0x5005, iwl130_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0896, 0x5007, iwl130_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0897, 0x5015, iwl130_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0897, 0x5017, iwl130_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0896, 0x5025, iwl130_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0896, 0x5027, iwl130_bg_cfg)},
+
#endif /* CONFIG_IWL5000 */
{0}
@@ -4486,9 +4913,18 @@ 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(
disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO);
-MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+MODULE_PARM_DESC(disable_hw_scan,
+ "disable hardware scanning (default 0) (deprecated)");
module_param_named(ucode_alternative, iwlagn_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_PARM_DESC(antenna_coupling,
+ "specify antenna coupling in dB (defualt: 0 dB)");
+
+module_param_named(bt_ch_announce, iwlagn_bt_ch_announce, bool, S_IRUGO);
+MODULE_PARM_DESC(bt_ch_announce,
+ "Enable BT channel announcement mode (default: enable)");
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index cc6464dc72e5..f525d55f2c0f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -92,9 +92,14 @@ extern struct iwl_cfg iwl6050_2abg_cfg;
extern struct iwl_cfg iwl6050g2_bgn_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_mod_params iwlagn_mod_params;
extern struct iwl_hcmd_ops iwlagn_hcmd;
+extern struct iwl_hcmd_ops iwlagn_bt_hcmd;
extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils;
int iwl_reset_ict(struct iwl_priv *priv);
@@ -124,6 +129,10 @@ void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask);
void iwl_free_tfds_in_queue(struct iwl_priv *priv,
int sta_id, int tid, int freed);
+/* RXON */
+int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+
/* uCode */
int iwlagn_load_ucode(struct iwl_priv *priv);
void iwlagn_rx_calib_result(struct iwl_priv *priv,
@@ -133,6 +142,8 @@ void iwlagn_rx_calib_complete(struct iwl_priv *priv,
void iwlagn_init_alive_start(struct iwl_priv *priv);
int iwlagn_alive_notify(struct iwl_priv *priv);
int iwl_verify_ucode(struct iwl_priv *priv);
+void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
+void iwlagn_send_prio_tbl(struct iwl_priv *priv);
/* lib */
void iwl_check_abort_status(struct iwl_priv *priv,
@@ -151,6 +162,8 @@ int iwlagn_hw_nic_init(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);
+void iwl_dump_csr(struct iwl_priv *priv);
+int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display);
/* rx */
void iwlagn_rx_queue_restock(struct iwl_priv *priv);
@@ -164,8 +177,15 @@ void iwlagn_rx_reply_rx(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
+void iwl_rx_handle(struct iwl_priv *priv);
/* tx */
+void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq,
+ dma_addr_t addr, u16 len, u8 reset, u8 pad);
+int iwl_hw_tx_queue_init(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq);
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);
@@ -205,6 +225,8 @@ static inline bool iwl_is_tx_success(u32 status)
(status == TX_STATUS_DIRECT_DONE);
}
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
+
/* rx */
void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
@@ -216,14 +238,84 @@ void iwl_reply_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
/* scan */
-void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
+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);
/* hcmd */
-int iwlagn_send_rxon_assoc(struct iwl_priv *priv);
+int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx);
int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant);
+/* 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);
+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);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+const char *iwl_get_tx_fail_reason(u32 status);
+const char *iwl_get_agg_tx_fail_reason(u16 status);
+#else
+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_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,
+ const u8 *addr, u8 *sta_id_r);
+int iwl_remove_default_wep_key(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct ieee80211_key_conf *key);
+int iwl_set_default_wep_key(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct ieee80211_key_conf *key);
+int iwl_restore_default_wep_keys(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx);
+int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+ struct ieee80211_key_conf *key, u8 sta_id);
+int iwl_remove_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+ struct ieee80211_key_conf *key, u8 sta_id);
+void iwl_update_tkip_key(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct ieee80211_key_conf *keyconf,
+ struct ieee80211_sta *sta, u32 iv32, u16 *phase1key);
+int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
+int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
+ int tid, u16 ssn);
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
+ int tid);
+void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id);
+void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
+int iwl_update_bcast_stations(struct iwl_priv *priv);
+
+/* rate */
+static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
+{
+ return BIT(ant_idx) << RATE_MCS_ANT_POS;
+}
+
+static inline u8 iwl_hw_get_rate(__le32 rate_n_flags)
+{
+ return le32_to_cpu(rate_n_flags) & 0xFF;
+}
+
+static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
+{
+ return cpu_to_le32(flags|(u32)rate);
+}
+
+/* eeprom */
+void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv);
+void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac);
+int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv);
+void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv);
+
#endif /* __iwl_agn_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 60725a5c1b69..424801abc80e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -62,7 +62,7 @@
*****************************************************************************/
/*
* Please use this file (iwl-commands.h) only for uCode API definitions.
- * Please use iwl-4965-hw.h for hardware-related definitions.
+ * Please use iwl-xxxx-hw.h for hardware-related definitions.
* Please use iwl-dev.h for driver implementation definitions.
*/
@@ -173,6 +173,23 @@ enum {
REPLY_RX_MPDU_CMD = 0xc1,
REPLY_RX = 0xc3,
REPLY_COMPRESSED_BA = 0xc5,
+
+ /* BT Coex */
+ REPLY_BT_COEX_PRIO_TABLE = 0xcc,
+ REPLY_BT_COEX_PROT_ENV = 0xcd,
+ REPLY_BT_COEX_PROFILE_NOTIF = 0xce,
+ REPLY_BT_COEX_SCO = 0xcf,
+
+ /* PAN commands */
+ REPLY_WIPAN_PARAMS = 0xb2,
+ REPLY_WIPAN_RXON = 0xb3, /* use REPLY_RXON structure */
+ REPLY_WIPAN_RXON_TIMING = 0xb4, /* use REPLY_RXON_TIMING structure */
+ REPLY_WIPAN_RXON_ASSOC = 0xb6, /* use REPLY_RXON_ASSOC structure */
+ REPLY_WIPAN_QOS_PARAM = 0xb7, /* use REPLY_QOS_PARAM structure */
+ REPLY_WIPAN_WEPKEY = 0xb8, /* use REPLY_WEPKEY structure */
+ REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9,
+ REPLY_WIPAN_NOA_NOTIFICATION = 0xbc,
+
REPLY_MAX = 0xff
};
@@ -403,12 +420,12 @@ struct iwl4965_tx_power_db {
/**
* Command REPLY_TX_POWER_DBM_CMD = 0x98
- * struct iwl5000_tx_power_dbm_cmd
+ * struct iwlagn_tx_power_dbm_cmd
*/
-#define IWL50_TX_POWER_AUTO 0x7f
-#define IWL50_TX_POWER_NO_CLOSED (0x1 << 6)
+#define IWLAGN_TX_POWER_AUTO 0x7f
+#define IWLAGN_TX_POWER_NO_CLOSED (0x1 << 6)
-struct iwl5000_tx_power_dbm_cmd {
+struct iwlagn_tx_power_dbm_cmd {
s8 global_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */
u8 flags;
s8 srv_chan_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */
@@ -600,6 +617,9 @@ enum {
RXON_DEV_TYPE_ESS = 3,
RXON_DEV_TYPE_IBSS = 4,
RXON_DEV_TYPE_SNIFFER = 6,
+ RXON_DEV_TYPE_CP = 7,
+ RXON_DEV_TYPE_2STA = 8,
+ RXON_DEV_TYPE_P2P = 9,
};
@@ -816,7 +836,8 @@ struct iwl_rxon_time_cmd {
__le16 atim_window;
__le32 beacon_init_val;
__le16 listen_interval;
- __le16 reserved;
+ u8 dtim_period;
+ u8 delta_cp_bss_tbtts;
} __packed;
/*
@@ -953,11 +974,13 @@ struct iwl_qosparam_cmd {
/* Special, dedicated locations within device's station table */
#define IWL_AP_ID 0
+#define IWL_AP_ID_PAN 1
#define IWL_STA_ID 2
#define IWL3945_BROADCAST_ID 24
#define IWL3945_STATION_COUNT 25
#define IWL4965_BROADCAST_ID 31
#define IWL4965_STATION_COUNT 32
+#define IWLAGN_PAN_BCAST_ID 14
#define IWLAGN_BROADCAST_ID 15
#define IWLAGN_STATION_COUNT 16
@@ -966,6 +989,7 @@ struct iwl_qosparam_cmd {
#define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2)
#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8)
+#define STA_FLG_PAN_STATION cpu_to_le32(1 << 13)
#define STA_FLG_RTS_MIMO_PROT_MSK cpu_to_le32(1 << 17)
#define STA_FLG_AGG_MPDU_8US_MSK cpu_to_le32(1 << 18)
#define STA_FLG_MAX_AGG_SIZE_POS (19)
@@ -994,6 +1018,7 @@ struct iwl_qosparam_cmd {
#define STA_KEY_FLG_KEY_SIZE_MSK cpu_to_le16(0x1000)
#define STA_KEY_MULTICAST_MSK cpu_to_le16(0x4000)
#define STA_KEY_MAX_NUM 8
+#define STA_KEY_MAX_NUM_PAN 16
/* Flags indicate whether to modify vs. don't change various station params */
#define STA_MODIFY_KEY_MASK 0x01
@@ -1017,7 +1042,7 @@ struct iwl4965_keyinfo {
u8 key[16]; /* 16-byte unicast decryption key */
} __packed;
-/* 5000 */
+/* agn */
struct iwl_keyinfo {
__le16 key_flags;
u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */
@@ -1056,7 +1081,8 @@ struct sta_id_modify {
*
* The device contains an internal table of per-station information,
* with info on security keys, aggregation parameters, and Tx rates for
- * initial Tx attempt and any retries (4965 uses REPLY_TX_LINK_QUALITY_CMD,
+ * initial Tx attempt and any retries (agn devices uses
+ * REPLY_TX_LINK_QUALITY_CMD,
* 3945 uses REPLY_RATE_SCALE to set up rate tables).
*
* REPLY_ADD_STA sets up the table entry for one station, either creating
@@ -1142,7 +1168,7 @@ struct iwl4965_addsta_cmd {
__le16 reserved2;
} __packed;
-/* 5000 */
+/* agn */
struct iwl_addsta_cmd {
u8 mode; /* 1: modify existing, 0: add new station */
u8 reserved[3];
@@ -1367,21 +1393,24 @@ struct iwl4965_rx_non_cfg_phy {
} __packed;
-#define IWL50_RX_RES_PHY_CNT 8
-#define IWL50_RX_RES_AGC_IDX 1
-#define IWL50_RX_RES_RSSI_AB_IDX 2
-#define IWL50_RX_RES_RSSI_C_IDX 3
-#define IWL50_OFDM_AGC_MSK 0xfe00
-#define IWL50_OFDM_AGC_BIT_POS 9
-#define IWL50_OFDM_RSSI_A_MSK 0x00ff
-#define IWL50_OFDM_RSSI_A_BIT_POS 0
-#define IWL50_OFDM_RSSI_B_MSK 0xff0000
-#define IWL50_OFDM_RSSI_B_BIT_POS 16
-#define IWL50_OFDM_RSSI_C_MSK 0x00ff
-#define IWL50_OFDM_RSSI_C_BIT_POS 0
+#define IWLAGN_RX_RES_PHY_CNT 8
+#define IWLAGN_RX_RES_AGC_IDX 1
+#define IWLAGN_RX_RES_RSSI_AB_IDX 2
+#define IWLAGN_RX_RES_RSSI_C_IDX 3
+#define IWLAGN_OFDM_AGC_MSK 0xfe00
+#define IWLAGN_OFDM_AGC_BIT_POS 9
+#define IWLAGN_OFDM_RSSI_INBAND_A_BITMSK 0x00ff
+#define IWLAGN_OFDM_RSSI_ALLBAND_A_BITMSK 0xff00
+#define IWLAGN_OFDM_RSSI_A_BIT_POS 0
+#define IWLAGN_OFDM_RSSI_INBAND_B_BITMSK 0xff0000
+#define IWLAGN_OFDM_RSSI_ALLBAND_B_BITMSK 0xff000000
+#define IWLAGN_OFDM_RSSI_B_BIT_POS 16
+#define IWLAGN_OFDM_RSSI_INBAND_C_BITMSK 0x00ff
+#define IWLAGN_OFDM_RSSI_ALLBAND_C_BITMSK 0xff00
+#define IWLAGN_OFDM_RSSI_C_BIT_POS 0
-struct iwl5000_non_cfg_phy {
- __le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* up to 8 phy entries */
+struct iwlagn_non_cfg_phy {
+ __le32 non_cfg_phy[IWLAGN_RX_RES_PHY_CNT]; /* up to 8 phy entries */
} __packed;
@@ -1401,7 +1430,7 @@ struct iwl_rx_phy_res {
u8 non_cfg_phy_buf[32]; /* for various implementations of non_cfg_phy */
__le32 rate_n_flags; /* RATE_MCS_* */
__le16 byte_count; /* frame's byte-count */
- __le16 reserved3;
+ __le16 frame_time; /* frame's time on the air */
} __packed;
struct iwl_rx_mpdu_res_start {
@@ -1424,12 +1453,12 @@ struct iwl_rx_mpdu_res_start {
* uCode handles all timing and protocol related to control frames
* (RTS/CTS/ACK), based on flags in the Tx command. uCode and Tx scheduler
* handle reception of block-acks; uCode updates the host driver via
- * REPLY_COMPRESSED_BA (4965).
+ * REPLY_COMPRESSED_BA.
*
* uCode handles retrying Tx when an ACK is expected but not received.
* This includes trying lower data rates than the one requested in the Tx
* command, as set up by the REPLY_RATE_SCALE (for 3945) or
- * REPLY_TX_LINK_QUALITY_CMD (4965).
+ * REPLY_TX_LINK_QUALITY_CMD (agn).
*
* Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD.
* This command must be executed after every RXON command, before Tx can occur.
@@ -1465,7 +1494,7 @@ struct iwl_rx_mpdu_res_start {
* Set this for unicast frames, but not broadcast/multicast. */
#define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3)
-/* For 4965:
+/* For agn devices:
* 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
* Tx command's initial_rate_index indicates first rate to try;
* uCode walks through table for additional Tx attempts.
@@ -1484,7 +1513,7 @@ struct iwl_rx_mpdu_res_start {
*/
#define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7)
-/* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
+/* Tx antenna selection field; used only for 3945, reserved (0) for agn devices.
* Set field to "0" to allow 3945 uCode to select antenna (normal usage). */
#define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00)
#define TX_CMD_FLG_ANT_A_MSK cpu_to_le32(1 << 8)
@@ -1791,13 +1820,8 @@ enum {
TX_STATUS_FAIL_TID_DISABLE = 0x8d,
TX_STATUS_FAIL_FIFO_FLUSHED = 0x8e,
TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
- /* uCode drop due to FW drop request */
- TX_STATUS_FAIL_FW_DROP = 0x90,
- /*
- * uCode drop due to station color mismatch
- * between tx command and station table
- */
- TX_STATUS_FAIL_STA_COLOR_MISMATCH_DROP = 0x91,
+ TX_STATUS_FAIL_PASSIVE_NO_RX = 0x90,
+ TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
};
#define TX_PACKET_MODE_REGULAR 0x0000
@@ -1839,6 +1863,9 @@ enum {
AGG_TX_STATE_DELAY_TX_MSK = 0x400
};
+#define AGG_TX_STATUS_MSK 0x00000fff /* bits 0:11 */
+#define AGG_TX_TRY_MSK 0x0000f000 /* bits 12:15 */
+
#define AGG_TX_STATE_LAST_SENT_MSK (AGG_TX_STATE_LAST_SENT_TTL_MSK | \
AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
@@ -1867,9 +1894,10 @@ enum {
* frame in this new agg block failed in previous agg block(s).
*
* Note that, for aggregation, ACK (block-ack) status is not delivered here;
- * block-ack has not been received by the time the 4965 records this status.
+ * block-ack has not been received by the time the agn device records
+ * this status.
* This status relates to reasons the tx might have been blocked or aborted
- * within the sending station (this 4965), rather than whether it was
+ * within the sending station (this agn device), rather than whether it was
* received successfully by the destination station.
*/
struct agg_tx_status {
@@ -1931,12 +1959,12 @@ struct iwl4965_tx_resp {
#define IWL50_TX_RES_INV_RATE_INDEX_MSK 0x80
/* refer to ra_tid */
-#define IWL50_TX_RES_TID_POS 0
-#define IWL50_TX_RES_TID_MSK 0x0f
-#define IWL50_TX_RES_RA_POS 4
-#define IWL50_TX_RES_RA_MSK 0xf0
+#define IWLAGN_TX_RES_TID_POS 0
+#define IWLAGN_TX_RES_TID_MSK 0x0f
+#define IWLAGN_TX_RES_RA_POS 4
+#define IWLAGN_TX_RES_RA_MSK 0xf0
-struct iwl5000_tx_resp {
+struct iwlagn_tx_resp {
u8 frame_count; /* 1 no aggregation, >1 aggregation */
u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */
u8 failure_rts; /* # failures due to unsuccessful RTS */
@@ -2092,8 +2120,8 @@ struct iwl_link_qual_general_params {
} __packed;
#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */
-#define LINK_QUAL_AGG_TIME_LIMIT_MAX (65535)
-#define LINK_QUAL_AGG_TIME_LIMIT_MIN (0)
+#define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000)
+#define LINK_QUAL_AGG_TIME_LIMIT_MIN (100)
#define LINK_QUAL_AGG_DISABLE_START_DEF (3)
#define LINK_QUAL_AGG_DISABLE_START_MAX (255)
@@ -2110,8 +2138,10 @@ struct iwl_link_qual_general_params {
*/
struct iwl_link_qual_agg_params {
- /* Maximum number of uSec in aggregation.
- * Driver should set this to 4000 (4 milliseconds). */
+ /*
+ *Maximum number of uSec in aggregation.
+ * default set to 4000 (4 milliseconds) if not configured in .cfg
+ */
__le16 agg_time_limit;
/*
@@ -2135,14 +2165,16 @@ struct iwl_link_qual_agg_params {
/*
* REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
*
- * For 4965 only; 3945 uses REPLY_RATE_SCALE.
+ * For agn devices only; 3945 uses REPLY_RATE_SCALE.
*
- * Each station in the 4965's internal station table has its own table of 16
+ * Each station in the agn device's internal station table has its own table
+ * of 16
* Tx rates and modulation modes (e.g. legacy/SISO/MIMO) for retrying Tx when
* an ACK is not received. This command replaces the entire table for
* one station.
*
- * NOTE: Station must already be in 4965's station table. Use REPLY_ADD_STA.
+ * NOTE: Station must already be in agn device's station table.
+ * Use REPLY_ADD_STA.
*
* The rate scaling procedures described below work well. Of course, other
* procedures are possible, and may work better for particular environments.
@@ -2179,12 +2211,12 @@ struct iwl_link_qual_agg_params {
*
* ACCUMULATING HISTORY
*
- * The rate scaling algorithm for 4965, as implemented in Linux driver, uses
- * two sets of frame Tx success history: One for the current/active modulation
- * mode, and one for a speculative/search mode that is being attempted. If the
- * speculative mode turns out to be more effective (i.e. actual transfer
- * rate is better), then the driver continues to use the speculative mode
- * as the new current active mode.
+ * The rate scaling algorithm for agn devices, as implemented in Linux driver,
+ * uses two sets of frame Tx success history: One for the current/active
+ * modulation mode, and one for a speculative/search mode that is being
+ * attempted. If the speculative mode turns out to be more effective (i.e.
+ * actual transfer rate is better), then the driver continues to use the
+ * speculative mode as the new current active mode.
*
* Each history set contains, separately for each possible rate, data for a
* sliding window of the 62 most recent tx attempts at that rate. The data
@@ -2195,12 +2227,12 @@ struct iwl_link_qual_agg_params {
* The driver uses the bit map to remove successes from the success sum, as
* the oldest tx attempts fall out of the window.
*
- * When the 4965 makes multiple tx attempts for a given frame, each attempt
- * might be at a different rate, and have different modulation characteristics
- * (e.g. antenna, fat channel, short guard interval), as set up in the rate
- * scaling table in the Link Quality command. The driver must determine
- * which rate table entry was used for each tx attempt, to determine which
- * rate-specific history to update, and record only those attempts that
+ * When the agn device makes multiple tx attempts for a given frame, each
+ * attempt might be at a different rate, and have different modulation
+ * characteristics (e.g. antenna, fat channel, short guard interval), as set
+ * up in the rate scaling table in the Link Quality command. The driver must
+ * determine which rate table entry was used for each tx attempt, to determine
+ * which rate-specific history to update, and record only those attempts that
* match the modulation characteristics of the history set.
*
* When using block-ack (aggregation), all frames are transmitted at the same
@@ -2330,7 +2362,7 @@ struct iwl_link_quality_cmd {
/*
* Rate info; when using rate-scaling, Tx command's initial_rate_index
* specifies 1st Tx rate attempted, via index into this table.
- * 4965 works its way through table when retrying Tx.
+ * agn devices works its way through table when retrying Tx.
*/
struct {
__le32 rate_n_flags; /* RATE_MCS_*, IWL_RATE_* */
@@ -2363,10 +2395,26 @@ struct iwl_link_quality_cmd {
#define BT_MAX_KILL_DEF (0x5)
#define BT_MAX_KILL_MAX (0xFF)
+#define BT_DURATION_LIMIT_DEF 625
+#define BT_DURATION_LIMIT_MAX 1250
+#define BT_DURATION_LIMIT_MIN 625
+
+#define BT_ON_THRESHOLD_DEF 4
+#define BT_ON_THRESHOLD_MAX 1000
+#define BT_ON_THRESHOLD_MIN 1
+
+#define BT_FRAG_THRESHOLD_DEF 0
+#define BT_FRAG_THRESHOLD_MAX 0
+#define BT_FRAG_THRESHOLD_MIN 0
+
+#define BT_AGG_THRESHOLD_DEF 0
+#define BT_AGG_THRESHOLD_MAX 0
+#define BT_AGG_THRESHOLD_MIN 0
+
/*
* REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
*
- * 3945 and 4965 support hardware handshake with Bluetooth device on
+ * 3945 and agn devices support hardware handshake with Bluetooth device on
* same platform. Bluetooth device alerts wireless device when it will Tx;
* wireless device can delay or kill its own Tx to accommodate.
*/
@@ -2379,6 +2427,79 @@ struct iwl_bt_cmd {
__le32 kill_cts_mask;
} __packed;
+#define IWLAGN_BT_FLAG_CHANNEL_INHIBITION BIT(0)
+
+#define IWLAGN_BT_FLAG_COEX_MODE_MASK (BIT(3)|BIT(4)|BIT(5))
+#define IWLAGN_BT_FLAG_COEX_MODE_SHIFT 3
+#define IWLAGN_BT_FLAG_COEX_MODE_DISABLED 0
+#define IWLAGN_BT_FLAG_COEX_MODE_LEGACY_2W 1
+#define IWLAGN_BT_FLAG_COEX_MODE_3W 2
+#define IWLAGN_BT_FLAG_COEX_MODE_4W 3
+
+#define IWLAGN_BT_FLAG_UCODE_DEFAULT BIT(6)
+#define IWLAGN_BT_FLAG_NOCOEX_NOTIF BIT(7)
+
+#define IWLAGN_BT_PRIO_BOOST_MAX 0xFF
+#define IWLAGN_BT_PRIO_BOOST_MIN 0x00
+#define IWLAGN_BT_PRIO_BOOST_DEFAULT 0xF0
+
+#define IWLAGN_BT_MAX_KILL_DEFAULT 5
+
+#define IWLAGN_BT3_T7_DEFAULT 1
+
+#define IWLAGN_BT_KILL_ACK_MASK_DEFAULT cpu_to_le32(0xffffffff)
+#define IWLAGN_BT_KILL_CTS_MASK_DEFAULT cpu_to_le32(0xffffffff)
+
+#define IWLAGN_BT3_PRIO_SAMPLE_DEFAULT 2
+
+#define IWLAGN_BT3_T2_DEFAULT 0xc
+
+#define IWLAGN_BT_VALID_ENABLE_FLAGS cpu_to_le16(BIT(0))
+#define IWLAGN_BT_VALID_BOOST cpu_to_le16(BIT(1))
+#define IWLAGN_BT_VALID_MAX_KILL cpu_to_le16(BIT(2))
+#define IWLAGN_BT_VALID_3W_TIMERS cpu_to_le16(BIT(3))
+#define IWLAGN_BT_VALID_KILL_ACK_MASK cpu_to_le16(BIT(4))
+#define IWLAGN_BT_VALID_KILL_CTS_MASK cpu_to_le16(BIT(5))
+#define IWLAGN_BT_VALID_BT4_TIMES cpu_to_le16(BIT(6))
+#define IWLAGN_BT_VALID_3W_LUT cpu_to_le16(BIT(7))
+
+#define IWLAGN_BT_ALL_VALID_MSK (IWLAGN_BT_VALID_ENABLE_FLAGS | \
+ IWLAGN_BT_VALID_BOOST | \
+ IWLAGN_BT_VALID_MAX_KILL | \
+ IWLAGN_BT_VALID_3W_TIMERS | \
+ IWLAGN_BT_VALID_KILL_ACK_MASK | \
+ IWLAGN_BT_VALID_KILL_CTS_MASK | \
+ IWLAGN_BT_VALID_BT4_TIMES | \
+ IWLAGN_BT_VALID_3W_LUT)
+
+struct iwlagn_bt_cmd {
+ u8 flags;
+ u8 ledtime; /* unused */
+ u8 max_kill;
+ u8 bt3_timer_t7_value;
+ __le32 kill_ack_mask;
+ __le32 kill_cts_mask;
+ u8 bt3_prio_sample_time;
+ u8 bt3_timer_t2_value;
+ __le16 bt4_reaction_time; /* unused */
+ __le32 bt3_lookup_table[12];
+ __le16 bt4_decision_time; /* unused */
+ __le16 valid;
+ u8 prio_boost;
+ /*
+ * set IWLAGN_BT_VALID_BOOST to "1" in "valid" bitmask
+ * if configure the following patterns
+ */
+ u8 tx_prio_boost; /* SW boost of WiFi tx priority */
+ __le16 rx_prio_boost; /* SW boost of WiFi rx priority */
+};
+
+#define IWLAGN_BT_SCO_ACTIVE cpu_to_le32(BIT(0))
+
+struct iwlagn_bt_sco_cmd {
+ __le32 flags;
+};
+
/******************************************************************************
* (6)
* Spectrum Management (802.11h) Commands, Responses, Notifications:
@@ -2567,7 +2688,7 @@ struct iwl_powertable_cmd {
/*
* PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
- * 3945 and 4965 identical.
+ * all devices identical.
*/
struct iwl_sleep_notification {
u8 pm_sleep_mode;
@@ -2578,7 +2699,7 @@ struct iwl_sleep_notification {
__le32 bcon_timer;
} __packed;
-/* Sleep states. 3945 and 4965 identical. */
+/* Sleep states. all devices identical. */
enum {
IWL_PM_NO_SLEEP = 0,
IWL_PM_SLP_MAC = 1,
@@ -2887,6 +3008,12 @@ struct iwl_scanstart_notification {
#define SCAN_OWNER_STATUS 0x1;
#define MEASURE_OWNER_STATUS 0x2;
+#define IWL_PROBE_STATUS_OK 0
+#define IWL_PROBE_STATUS_TX_FAILED BIT(0)
+/* error statuses combined with TX_FAILED */
+#define IWL_PROBE_STATUS_FAIL_TTL BIT(1)
+#define IWL_PROBE_STATUS_FAIL_BT BIT(2)
+
#define NUMBER_OF_STATISTICS 1 /* first __le32 is good CRC */
/*
* SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
@@ -2894,7 +3021,8 @@ struct iwl_scanstart_notification {
struct iwl_scanresults_notification {
u8 channel;
u8 band;
- u8 reserved[2];
+ u8 probe_status;
+ u8 num_probe_not_sent; /* not enough time to send */
__le32 tsf_low;
__le32 tsf_high;
__le32 statistics[NUMBER_OF_STATISTICS];
@@ -2906,7 +3034,7 @@ struct iwl_scanresults_notification {
struct iwl_scancomplete_notification {
u8 scanned_channels;
u8 status;
- u8 reserved;
+ u8 bt_status; /* BT On/Off status */
u8 last_channel;
__le32 tsf_low;
__le32 tsf_high;
@@ -2919,6 +3047,11 @@ struct iwl_scancomplete_notification {
*
*****************************************************************************/
+enum iwl_ibss_manager {
+ IWL_NOT_IBSS_MANAGER = 0,
+ IWL_IBSS_MANAGER = 1,
+};
+
/*
* BEACON_NOTIFICATION = 0x90 (notification only, not a command)
*/
@@ -3260,7 +3393,7 @@ struct statistics_general_bt {
/*
* REPLY_STATISTICS_CMD = 0x9c,
- * 3945 and 4965 identical.
+ * all devices identical.
*
* This command triggers an immediate response containing uCode statistics.
* The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
@@ -3598,7 +3731,7 @@ struct iwl_enhance_sensitivity_cmd {
/**
* REPLY_PHY_CALIBRATION_CMD = 0xb0 (command, has simple generic response)
*
- * This command sets the relative gains of 4965's 3 radio receiver chains.
+ * This command sets the relative gains of agn device's 3 radio receiver chains.
*
* After the first association, driver should accumulate signal and noise
* statistics from the STATISTICS_NOTIFICATIONs that follow the first 20
@@ -3651,7 +3784,8 @@ struct iwl_enhance_sensitivity_cmd {
*/
/* Phy calibration command for series */
-
+/* The default calibrate table size if not specified by firmware */
+#define IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE 18
enum {
IWL_PHY_CALIBRATE_DIFF_GAIN_CMD = 7,
IWL_PHY_CALIBRATE_DC_CMD = 8,
@@ -3660,13 +3794,29 @@ enum {
IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15,
IWL_PHY_CALIBRATE_BASE_BAND_CMD = 16,
IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17,
- IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE = 18,
+ IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD = 18,
+ IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE = 19,
};
#define IWL_MAX_PHY_CALIBRATE_TBL_SIZE (253)
#define IWL_CALIB_INIT_CFG_ALL cpu_to_le32(0xffffffff)
+/* This enum defines the bitmap of various calibrations to enable in both
+ * init ucode and runtime ucode through CALIBRATION_CFG_CMD.
+ */
+enum iwl_ucode_calib_cfg {
+ IWL_CALIB_CFG_RX_BB_IDX,
+ IWL_CALIB_CFG_DC_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_TEMPERATURE_IDX,
+ IWL_CALIB_CFG_PAPD_IDX,
+};
+
+
struct iwl_calib_cfg_elmnt_s {
__le32 is_enable;
__le32 start;
@@ -3715,6 +3865,13 @@ struct iwl_calib_xtal_freq_cmd {
u8 pad[2];
} __packed;
+#define DEFAULT_RADIO_SENSOR_OFFSET 2700
+struct iwl_calib_temperature_offset_cmd {
+ struct iwl_calib_hdr hdr;
+ s16 radio_sensor_offset;
+ s16 reserved;
+} __packed;
+
/* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
struct iwl_calib_chain_noise_reset_cmd {
struct iwl_calib_hdr hdr;
@@ -3955,6 +4112,201 @@ struct iwl_coex_event_resp {
/******************************************************************************
+ * Bluetooth Coexistence commands
+ *
+ *****************************************************************************/
+
+/*
+ * BT Status notification
+ * REPLY_BT_COEX_PROFILE_NOTIF = 0xce
+ */
+enum iwl_bt_coex_profile_traffic_load {
+ IWL_BT_COEX_TRAFFIC_LOAD_NONE = 0,
+ IWL_BT_COEX_TRAFFIC_LOAD_LOW = 1,
+ IWL_BT_COEX_TRAFFIC_LOAD_HIGH = 2,
+ IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS = 3,
+/*
+ * There are no more even though below is a u8, the
+ * indication from the BT device only has two bits.
+ */
+};
+
+#define BT_UART_MSG_FRAME1MSGTYPE_POS (0)
+#define BT_UART_MSG_FRAME1MSGTYPE_MSK \
+ (0x7 << BT_UART_MSG_FRAME1MSGTYPE_POS)
+#define BT_UART_MSG_FRAME1SSN_POS (3)
+#define BT_UART_MSG_FRAME1SSN_MSK \
+ (0x3 << BT_UART_MSG_FRAME1SSN_POS)
+#define BT_UART_MSG_FRAME1UPDATEREQ_POS (5)
+#define BT_UART_MSG_FRAME1UPDATEREQ_MSK \
+ (0x1 << BT_UART_MSG_FRAME1UPDATEREQ_POS)
+#define BT_UART_MSG_FRAME1RESERVED_POS (6)
+#define BT_UART_MSG_FRAME1RESERVED_MSK \
+ (0x3 << BT_UART_MSG_FRAME1RESERVED_POS)
+
+#define BT_UART_MSG_FRAME2OPENCONNECTIONS_POS (0)
+#define BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK \
+ (0x3 << BT_UART_MSG_FRAME2OPENCONNECTIONS_POS)
+#define BT_UART_MSG_FRAME2TRAFFICLOAD_POS (2)
+#define BT_UART_MSG_FRAME2TRAFFICLOAD_MSK \
+ (0x3 << BT_UART_MSG_FRAME2TRAFFICLOAD_POS)
+#define BT_UART_MSG_FRAME2CHLSEQN_POS (4)
+#define BT_UART_MSG_FRAME2CHLSEQN_MSK \
+ (0x1 << BT_UART_MSG_FRAME2CHLSEQN_POS)
+#define BT_UART_MSG_FRAME2INBAND_POS (5)
+#define BT_UART_MSG_FRAME2INBAND_MSK \
+ (0x1 << BT_UART_MSG_FRAME2INBAND_POS)
+#define BT_UART_MSG_FRAME2RESERVED_POS (6)
+#define BT_UART_MSG_FRAME2RESERVED_MSK \
+ (0x3 << BT_UART_MSG_FRAME2RESERVED_POS)
+
+#define BT_UART_MSG_FRAME3SCOESCO_POS (0)
+#define BT_UART_MSG_FRAME3SCOESCO_MSK \
+ (0x1 << BT_UART_MSG_FRAME3SCOESCO_POS)
+#define BT_UART_MSG_FRAME3SNIFF_POS (1)
+#define BT_UART_MSG_FRAME3SNIFF_MSK \
+ (0x1 << BT_UART_MSG_FRAME3SNIFF_POS)
+#define BT_UART_MSG_FRAME3A2DP_POS (2)
+#define BT_UART_MSG_FRAME3A2DP_MSK \
+ (0x1 << BT_UART_MSG_FRAME3A2DP_POS)
+#define BT_UART_MSG_FRAME3ACL_POS (3)
+#define BT_UART_MSG_FRAME3ACL_MSK \
+ (0x1 << BT_UART_MSG_FRAME3ACL_POS)
+#define BT_UART_MSG_FRAME3MASTER_POS (4)
+#define BT_UART_MSG_FRAME3MASTER_MSK \
+ (0x1 << BT_UART_MSG_FRAME3MASTER_POS)
+#define BT_UART_MSG_FRAME3OBEX_POS (5)
+#define BT_UART_MSG_FRAME3OBEX_MSK \
+ (0x1 << BT_UART_MSG_FRAME3OBEX_POS)
+#define BT_UART_MSG_FRAME3RESERVED_POS (6)
+#define BT_UART_MSG_FRAME3RESERVED_MSK \
+ (0x3 << BT_UART_MSG_FRAME3RESERVED_POS)
+
+#define BT_UART_MSG_FRAME4IDLEDURATION_POS (0)
+#define BT_UART_MSG_FRAME4IDLEDURATION_MSK \
+ (0x3F << BT_UART_MSG_FRAME4IDLEDURATION_POS)
+#define BT_UART_MSG_FRAME4RESERVED_POS (6)
+#define BT_UART_MSG_FRAME4RESERVED_MSK \
+ (0x3 << BT_UART_MSG_FRAME4RESERVED_POS)
+
+#define BT_UART_MSG_FRAME5TXACTIVITY_POS (0)
+#define BT_UART_MSG_FRAME5TXACTIVITY_MSK \
+ (0x3 << BT_UART_MSG_FRAME5TXACTIVITY_POS)
+#define BT_UART_MSG_FRAME5RXACTIVITY_POS (2)
+#define BT_UART_MSG_FRAME5RXACTIVITY_MSK \
+ (0x3 << BT_UART_MSG_FRAME5RXACTIVITY_POS)
+#define BT_UART_MSG_FRAME5ESCORETRANSMIT_POS (4)
+#define BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK \
+ (0x3 << BT_UART_MSG_FRAME5ESCORETRANSMIT_POS)
+#define BT_UART_MSG_FRAME5RESERVED_POS (6)
+#define BT_UART_MSG_FRAME5RESERVED_MSK \
+ (0x3 << BT_UART_MSG_FRAME5RESERVED_POS)
+
+#define BT_UART_MSG_FRAME6SNIFFINTERVAL_POS (0)
+#define BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK \
+ (0x1F << BT_UART_MSG_FRAME6SNIFFINTERVAL_POS)
+#define BT_UART_MSG_FRAME6DISCOVERABLE_POS (5)
+#define BT_UART_MSG_FRAME6DISCOVERABLE_MSK \
+ (0x1 << BT_UART_MSG_FRAME6DISCOVERABLE_POS)
+#define BT_UART_MSG_FRAME6RESERVED_POS (6)
+#define BT_UART_MSG_FRAME6RESERVED_MSK \
+ (0x3 << BT_UART_MSG_FRAME6RESERVED_POS)
+
+#define BT_UART_MSG_FRAME7SNIFFACTIVITY_POS (0)
+#define BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK \
+ (0x7 << BT_UART_MSG_FRAME7SNIFFACTIVITY_POS)
+#define BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_POS (3)
+#define BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_MSK \
+ (0x3 << BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_POS)
+#define BT_UART_MSG_FRAME7CONNECTABLE_POS (5)
+#define BT_UART_MSG_FRAME7CONNECTABLE_MSK \
+ (0x1 << BT_UART_MSG_FRAME7CONNECTABLE_POS)
+#define BT_UART_MSG_FRAME7RESERVED_POS (6)
+#define BT_UART_MSG_FRAME7RESERVED_MSK \
+ (0x3 << BT_UART_MSG_FRAME7RESERVED_POS)
+
+
+struct iwl_bt_uart_msg {
+ u8 header;
+ u8 frame1;
+ u8 frame2;
+ u8 frame3;
+ u8 frame4;
+ u8 frame5;
+ u8 frame6;
+ u8 frame7;
+} __attribute__((packed));
+
+struct iwl_bt_coex_profile_notif {
+ struct iwl_bt_uart_msg last_bt_uart_msg;
+ u8 bt_status; /* 0 - off, 1 - on */
+ u8 bt_traffic_load; /* 0 .. 3? */
+ u8 bt_ci_compliance; /* 0 - not complied, 1 - complied */
+ u8 reserved;
+} __attribute__((packed));
+
+#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS 0
+#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_MSK 0x1
+#define IWL_BT_COEX_PRIO_TBL_PRIO_POS 1
+#define IWL_BT_COEX_PRIO_TBL_PRIO_MASK 0x0e
+#define IWL_BT_COEX_PRIO_TBL_RESERVED_POS 4
+#define IWL_BT_COEX_PRIO_TBL_RESERVED_MASK 0xf0
+#define IWL_BT_COEX_PRIO_TBL_PRIO_SHIFT 1
+
+/*
+ * BT Coexistence Priority table
+ * REPLY_BT_COEX_PRIO_TABLE = 0xcc
+ */
+enum bt_coex_prio_table_events {
+ BT_COEX_PRIO_TBL_EVT_INIT_CALIB1 = 0,
+ BT_COEX_PRIO_TBL_EVT_INIT_CALIB2 = 1,
+ BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1 = 2,
+ BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2 = 3, /* DC calib */
+ BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1 = 4,
+ BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2 = 5,
+ BT_COEX_PRIO_TBL_EVT_DTIM = 6,
+ BT_COEX_PRIO_TBL_EVT_SCAN52 = 7,
+ BT_COEX_PRIO_TBL_EVT_SCAN24 = 8,
+ BT_COEX_PRIO_TBL_EVT_RESERVED0 = 9,
+ BT_COEX_PRIO_TBL_EVT_RESERVED1 = 10,
+ BT_COEX_PRIO_TBL_EVT_RESERVED2 = 11,
+ BT_COEX_PRIO_TBL_EVT_RESERVED3 = 12,
+ BT_COEX_PRIO_TBL_EVT_RESERVED4 = 13,
+ BT_COEX_PRIO_TBL_EVT_RESERVED5 = 14,
+ BT_COEX_PRIO_TBL_EVT_RESERVED6 = 15,
+ /* BT_COEX_PRIO_TBL_EVT_MAX should always be last */
+ BT_COEX_PRIO_TBL_EVT_MAX,
+};
+
+enum bt_coex_prio_table_priorities {
+ BT_COEX_PRIO_TBL_DISABLED = 0,
+ BT_COEX_PRIO_TBL_PRIO_LOW = 1,
+ BT_COEX_PRIO_TBL_PRIO_HIGH = 2,
+ BT_COEX_PRIO_TBL_PRIO_BYPASS = 3,
+ BT_COEX_PRIO_TBL_PRIO_COEX_OFF = 4,
+ BT_COEX_PRIO_TBL_PRIO_COEX_ON = 5,
+ BT_COEX_PRIO_TBL_PRIO_RSRVD1 = 6,
+ BT_COEX_PRIO_TBL_PRIO_RSRVD2 = 7,
+ BT_COEX_PRIO_TBL_MAX,
+};
+
+struct iwl_bt_coex_prio_table_cmd {
+ u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
+} __attribute__((packed));
+
+#define IWL_BT_COEX_ENV_CLOSE 0
+#define IWL_BT_COEX_ENV_OPEN 1
+/*
+ * BT Protection Envelope
+ * REPLY_BT_COEX_PROT_ENV = 0xcd
+ */
+struct iwl_bt_coex_prot_env_cmd {
+ u8 action; /* 0 = closed, 1 = open */
+ u8 type; /* 0 .. 15 */
+ u8 reserved[2];
+} __attribute__((packed));
+
+/******************************************************************************
* (13)
* Union of all expected notifications/responses:
*
@@ -3993,6 +4345,7 @@ struct iwl_rx_packet {
struct iwl_missed_beacon_notif missed_beacon;
struct iwl_coex_medium_notification coex_medium_notif;
struct iwl_coex_event_resp coex_event;
+ struct iwl_bt_coex_profile_notif bt_coex_profile_notif;
__le32 status;
u8 raw[0];
} u;
@@ -4000,4 +4353,94 @@ struct iwl_rx_packet {
int iwl_agn_check_rxon_cmd(struct iwl_priv *priv);
+/*
+ * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification)
+ */
+
+/**
+ * struct iwl_wipan_slot
+ * @width: Time in TU
+ * @type:
+ * 0 - BSS
+ * 1 - PAN
+ */
+struct iwl_wipan_slot {
+ __le16 width;
+ u8 type;
+ u8 reserved;
+} __packed;
+
+#define IWL_WIPAN_PARAMS_FLG_LEAVE_CHANNEL_CTS BIT(1) /* reserved */
+#define IWL_WIPAN_PARAMS_FLG_LEAVE_CHANNEL_QUIET BIT(2) /* reserved */
+#define IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE BIT(3) /* reserved */
+#define IWL_WIPAN_PARAMS_FLG_FILTER_BEACON_NOTIF BIT(4)
+#define IWL_WIPAN_PARAMS_FLG_FULL_SLOTTED_MODE BIT(5)
+
+/**
+ * struct iwl_wipan_params_cmd
+ * @flags:
+ * bit0: reserved
+ * bit1: CP leave channel with CTS
+ * bit2: CP leave channel qith Quiet
+ * bit3: slotted mode
+ * 1 - work in slotted mode
+ * 0 - work in non slotted mode
+ * bit4: filter beacon notification
+ * bit5: full tx slotted mode. if this flag is set,
+ * uCode will perform leaving channel methods in context switch
+ * also when working in same channel mode
+ * @num_slots: 1 - 10
+ */
+struct iwl_wipan_params_cmd {
+ __le16 flags;
+ u8 reserved;
+ u8 num_slots;
+ struct iwl_wipan_slot slots[10];
+} __packed;
+
+/*
+ * REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9
+ *
+ * TODO: Figure out what this is used for,
+ * it can only switch between 2.4 GHz
+ * channels!!
+ */
+
+struct iwl_wipan_p2p_channel_switch_cmd {
+ __le16 channel;
+ __le16 reserved;
+};
+
+/*
+ * REPLY_WIPAN_NOA_NOTIFICATION = 0xbc
+ *
+ * This is used by the device to notify us of the
+ * NoA schedule it determined so we can forward it
+ * to userspace for inclusion in probe responses.
+ *
+ * In beacons, the NoA schedule is simply appended
+ * to the frame we give the device.
+ */
+
+struct iwl_wipan_noa_descriptor {
+ u8 count;
+ __le32 duration;
+ __le32 interval;
+ __le32 starttime;
+} __packed;
+
+struct iwl_wipan_noa_attribute {
+ u8 id;
+ __le16 length;
+ u8 index;
+ u8 ct_window;
+ struct iwl_wipan_noa_descriptor descr0, descr1;
+ u8 reserved;
+} __packed;
+
+struct iwl_wipan_noa_notification {
+ u32 noa_active;
+ struct iwl_wipan_noa_attribute noa_attribute;
+} __packed;
+
#endif /* __iwl_commands_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index e23c4060a0f0..25fb3912342c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -64,97 +64,14 @@ MODULE_LICENSE("GPL");
*
* default: bt_coex_active = true (BT_COEX_ENABLE)
*/
-static bool bt_coex_active = true;
+bool bt_coex_active = true;
+EXPORT_SYMBOL_GPL(bt_coex_active);
module_param(bt_coex_active, bool, S_IRUGO);
MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist");
-#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \
- [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
- IWL_RATE_SISO_##s##M_PLCP, \
- IWL_RATE_MIMO2_##s##M_PLCP,\
- IWL_RATE_MIMO3_##s##M_PLCP,\
- IWL_RATE_##r##M_IEEE, \
- IWL_RATE_##ip##M_INDEX, \
- IWL_RATE_##in##M_INDEX, \
- IWL_RATE_##rp##M_INDEX, \
- IWL_RATE_##rn##M_INDEX, \
- IWL_RATE_##pp##M_INDEX, \
- IWL_RATE_##np##M_INDEX }
-
u32 iwl_debug_level;
EXPORT_SYMBOL(iwl_debug_level);
-/*
- * Parameter order:
- * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
- *
- * If there isn't a valid next or previous rate then INV is used which
- * maps to IWL_RATE_INVALID
- *
- */
-const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
- IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */
- IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */
- IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */
- IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */
- IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */
- IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */
- IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */
- IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */
- IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */
- IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */
- IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */
- IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
- IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
- /* FIXME:RS: ^^ should be INV (legacy) */
-};
-EXPORT_SYMBOL(iwl_rates);
-
-int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
-{
- int idx = 0;
-
- /* HT rate format */
- if (rate_n_flags & RATE_MCS_HT_MSK) {
- idx = (rate_n_flags & 0xff);
-
- if (idx >= IWL_RATE_MIMO3_6M_PLCP)
- idx = idx - IWL_RATE_MIMO3_6M_PLCP;
- else if (idx >= IWL_RATE_MIMO2_6M_PLCP)
- idx = idx - IWL_RATE_MIMO2_6M_PLCP;
-
- idx += IWL_FIRST_OFDM_RATE;
- /* skip 9M not supported in ht*/
- if (idx >= IWL_RATE_9M_INDEX)
- idx += 1;
- if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE))
- return idx;
-
- /* legacy rate format, search for match in table */
- } else {
- for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++)
- if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
- return idx;
- }
-
- return -1;
-}
-EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx);
-
-u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid)
-{
- int i;
- u8 ind = ant;
-
- for (i = 0; i < RATE_ANT_NUM - 1; i++) {
- ind = (ind + 1) < RATE_ANT_NUM ? ind + 1 : 0;
- if (valid & BIT(ind))
- return ind;
- }
- return ant;
-}
-EXPORT_SYMBOL(iwl_toggle_tx_ant);
-
const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
EXPORT_SYMBOL(iwl_bcast_addr);
@@ -183,38 +100,33 @@ out:
}
EXPORT_SYMBOL(iwl_alloc_all);
-void iwl_hw_detect(struct iwl_priv *priv)
-{
- priv->hw_rev = _iwl_read32(priv, CSR_HW_REV);
- priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG);
- pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id);
-}
-EXPORT_SYMBOL(iwl_hw_detect);
-
/*
* QoS support
*/
-static void iwl_update_qos(struct iwl_priv *priv)
+static void iwl_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
{
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
- priv->qos_data.def_qos_parm.qos_flags = 0;
+ if (!ctx->is_active)
+ return;
+
+ ctx->qos_data.def_qos_parm.qos_flags = 0;
- if (priv->qos_data.qos_active)
- priv->qos_data.def_qos_parm.qos_flags |=
+ if (ctx->qos_data.qos_active)
+ ctx->qos_data.def_qos_parm.qos_flags |=
QOS_PARAM_FLG_UPDATE_EDCA_MSK;
- if (priv->current_ht_config.is_ht)
- priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
+ if (ctx->ht.enabled)
+ ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
- priv->qos_data.qos_active,
- priv->qos_data.def_qos_parm.qos_flags);
+ ctx->qos_data.qos_active,
+ ctx->qos_data.def_qos_parm.qos_flags);
- iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
+ iwl_send_cmd_pdu_async(priv, ctx->qos_cmd,
sizeof(struct iwl_qosparam_cmd),
- &priv->qos_data.def_qos_parm, NULL);
+ &ctx->qos_data.def_qos_parm, NULL);
}
#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
@@ -232,7 +144,8 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
ht_info->ht_supported = true;
- if (priv->cfg->ht_greenfield_support)
+ if (priv->cfg->ht_params &&
+ priv->cfg->ht_params->ht_greenfield_support)
ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
max_bit_rate = MAX_BIT_RATE_20_MHZ;
@@ -247,7 +160,11 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
+ if (priv->cfg->bt_params && priv->cfg->bt_params->ampdu_factor)
+ ht_info->ampdu_factor = priv->cfg->bt_params->ampdu_factor;
ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
+ if (priv->cfg->bt_params && priv->cfg->bt_params->ampdu_density)
+ ht_info->ampdu_density = priv->cfg->bt_params->ampdu_density;
ht_info->mcs.rx_mask[0] = 0xFF;
if (rx_chains_num >= 2)
@@ -434,21 +351,15 @@ void iwlcore_tx_cmd_protection(struct iwl_priv *priv,
EXPORT_SYMBOL(iwlcore_tx_cmd_protection);
-static bool is_single_rx_stream(struct iwl_priv *priv)
-{
- return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC ||
- priv->current_ht_config.single_chain_sufficient;
-}
-
-static u8 iwl_is_channel_extension(struct iwl_priv *priv,
- enum ieee80211_band band,
- u16 channel, u8 extension_chan_offset)
+static bool iwl_is_channel_extension(struct iwl_priv *priv,
+ enum ieee80211_band band,
+ u16 channel, u8 extension_chan_offset)
{
const struct iwl_channel_info *ch_info;
ch_info = iwl_get_channel_info(priv, band, channel);
if (!is_channel_valid(ch_info))
- return 0;
+ return false;
if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
return !(ch_info->ht40_extension_channel &
@@ -457,38 +368,59 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv,
return !(ch_info->ht40_extension_channel &
IEEE80211_CHAN_NO_HT40MINUS);
- return 0;
+ return false;
}
-u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
- struct ieee80211_sta_ht_cap *sta_ht_inf)
+bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct ieee80211_sta_ht_cap *ht_cap)
{
- struct iwl_ht_config *ht_conf = &priv->current_ht_config;
-
- if (!ht_conf->is_ht || !ht_conf->is_40mhz)
- return 0;
+ if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
+ return false;
- /* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
+ /*
+ * We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
* the bit will not set if it is pure 40MHz case
*/
- if (sta_ht_inf) {
- if (!sta_ht_inf->ht_supported)
- return 0;
- }
+ if (ht_cap && !ht_cap->ht_supported)
+ return false;
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (priv->disable_ht40)
- return 0;
+ return false;
#endif
+
return iwl_is_channel_extension(priv, priv->band,
- le16_to_cpu(priv->staging_rxon.channel),
- ht_conf->extension_chan_offset);
+ le16_to_cpu(ctx->staging.channel),
+ ctx->ht.extension_chan_offset);
}
EXPORT_SYMBOL(iwl_is_ht40_tx_allowed);
static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
{
- u16 new_val = 0;
- u16 beacon_factor = 0;
+ u16 new_val;
+ u16 beacon_factor;
+
+ /*
+ * If mac80211 hasn't given us a beacon interval, program
+ * the default into the device (not checking this here
+ * would cause the adjustment below to return the maximum
+ * value, which may break PAN.)
+ */
+ if (!beacon_val)
+ return DEFAULT_BEACON_INTERVAL;
+
+ /*
+ * If the beacon interval we obtained from the peer
+ * is too large, we'll have to wake up more often
+ * (and in IBSS case, we'll beacon too much)
+ *
+ * For example, if max_beacon_val is 4096, and the
+ * requested beacon interval is 7000, we'll have to
+ * use 3500 to be able to wake up on the beacons.
+ *
+ * This could badly influence beacon detection stats.
+ */
beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val;
new_val = beacon_val / beacon_factor;
@@ -499,51 +431,76 @@ static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
return new_val;
}
-void iwl_setup_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif)
+int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
{
u64 tsf;
s32 interval_tm, rem;
- unsigned long flags;
struct ieee80211_conf *conf = NULL;
u16 beacon_int;
+ struct ieee80211_vif *vif = ctx->vif;
conf = ieee80211_get_hw_conf(priv->hw);
- spin_lock_irqsave(&priv->lock, flags);
- priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
- priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
+ lockdep_assert_held(&priv->mutex);
- beacon_int = vif->bss_conf.beacon_int;
+ memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd));
- if (vif->type == NL80211_IFTYPE_ADHOC) {
- /* TODO: we need to get atim_window from upper stack
- * for now we set to 0 */
- priv->rxon_timing.atim_window = 0;
- } else {
- priv->rxon_timing.atim_window = 0;
- }
+ ctx->timing.timestamp = cpu_to_le64(priv->timestamp);
+ ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval);
- beacon_int = iwl_adjust_beacon_interval(beacon_int,
+ beacon_int = vif ? vif->bss_conf.beacon_int : 0;
+
+ /*
+ * TODO: For IBSS we need to get atim_window from mac80211,
+ * for now just always use 0
+ */
+ ctx->timing.atim_window = 0;
+
+ if (ctx->ctxid == IWL_RXON_CTX_PAN &&
+ (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION) &&
+ iwl_is_associated(priv, IWL_RXON_CTX_BSS) &&
+ priv->contexts[IWL_RXON_CTX_BSS].vif &&
+ priv->contexts[IWL_RXON_CTX_BSS].vif->bss_conf.beacon_int) {
+ ctx->timing.beacon_interval =
+ priv->contexts[IWL_RXON_CTX_BSS].timing.beacon_interval;
+ beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
+ } else if (ctx->ctxid == IWL_RXON_CTX_BSS &&
+ iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
+ priv->contexts[IWL_RXON_CTX_PAN].vif &&
+ priv->contexts[IWL_RXON_CTX_PAN].vif->bss_conf.beacon_int &&
+ (!iwl_is_associated_ctx(ctx) || !ctx->vif ||
+ !ctx->vif->bss_conf.beacon_int)) {
+ ctx->timing.beacon_interval =
+ priv->contexts[IWL_RXON_CTX_PAN].timing.beacon_interval;
+ 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);
- priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
+ ctx->timing.beacon_interval = cpu_to_le16(beacon_int);
+ }
tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
interval_tm = beacon_int * TIME_UNIT;
rem = do_div(tsf, interval_tm);
- priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+ ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+
+ ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1;
- spin_unlock_irqrestore(&priv->lock, flags);
IWL_DEBUG_ASSOC(priv,
"beacon interval %d beacon timer %d beacon tim %d\n",
- le16_to_cpu(priv->rxon_timing.beacon_interval),
- le32_to_cpu(priv->rxon_timing.beacon_init_val),
- le16_to_cpu(priv->rxon_timing.atim_window));
+ le16_to_cpu(ctx->timing.beacon_interval),
+ le32_to_cpu(ctx->timing.beacon_init_val),
+ le16_to_cpu(ctx->timing.atim_window));
+
+ return iwl_send_cmd_pdu(priv, ctx->rxon_timing_cmd,
+ sizeof(ctx->timing), &ctx->timing);
}
-EXPORT_SYMBOL(iwl_setup_rxon_timing);
+EXPORT_SYMBOL(iwl_send_rxon_timing);
-void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+ int hw_decrypt)
{
- struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+ struct iwl_rxon_cmd *rxon = &ctx->staging;
if (hw_decrypt)
rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
@@ -553,76 +510,74 @@ void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
}
EXPORT_SYMBOL(iwl_set_rxon_hwcrypto);
-/**
- * iwl_check_rxon_cmd - validate RXON structure is valid
- *
- * NOTE: This is really only useful during development and can eventually
- * be #ifdef'd out once the driver is stable and folks aren't actively
- * making changes
- */
-int iwl_check_rxon_cmd(struct iwl_priv *priv)
+/* validate RXON structure is valid */
+int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
{
- int error = 0;
- int counter = 1;
- struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+ struct iwl_rxon_cmd *rxon = &ctx->staging;
+ bool error = false;
if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
- error |= le32_to_cpu(rxon->flags &
- (RXON_FLG_TGJ_NARROW_BAND_MSK |
- RXON_FLG_RADAR_DETECT_MSK));
- if (error)
- IWL_WARN(priv, "check 24G fields %d | %d\n",
- counter++, error);
+ if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) {
+ IWL_WARN(priv, "check 2.4G: wrong narrow\n");
+ error = true;
+ }
+ if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) {
+ IWL_WARN(priv, "check 2.4G: wrong radar\n");
+ error = true;
+ }
} else {
- error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ?
- 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK);
- if (error)
- IWL_WARN(priv, "check 52 fields %d | %d\n",
- counter++, error);
- error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK);
- if (error)
- IWL_WARN(priv, "check 52 CCK %d | %d\n",
- counter++, error);
- }
- error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;
- if (error)
- IWL_WARN(priv, "check mac addr %d | %d\n", counter++, error);
+ if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) {
+ IWL_WARN(priv, "check 5.2G: not short slot!\n");
+ error = true;
+ }
+ if (rxon->flags & RXON_FLG_CCK_MSK) {
+ IWL_WARN(priv, "check 5.2G: CCK!\n");
+ error = true;
+ }
+ }
+ if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) {
+ IWL_WARN(priv, "mac/bssid mcast!\n");
+ error = true;
+ }
/* make sure basic rates 6Mbps and 1Mbps are supported */
- error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&
- ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));
- if (error)
- IWL_WARN(priv, "check basic rate %d | %d\n", counter++, error);
+ if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 &&
+ (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) {
+ IWL_WARN(priv, "neither 1 nor 6 are basic\n");
+ error = true;
+ }
- error |= (le16_to_cpu(rxon->assoc_id) > 2007);
- if (error)
- IWL_WARN(priv, "check assoc id %d | %d\n", counter++, error);
+ if (le16_to_cpu(rxon->assoc_id) > 2007) {
+ IWL_WARN(priv, "aid > 2007\n");
+ error = true;
+ }
- error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
- == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));
- if (error)
- IWL_WARN(priv, "check CCK and short slot %d | %d\n",
- counter++, error);
+ if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
+ == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) {
+ IWL_WARN(priv, "CCK and short slot\n");
+ error = true;
+ }
- error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
- == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));
- if (error)
- IWL_WARN(priv, "check CCK & auto detect %d | %d\n",
- counter++, error);
+ if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
+ == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) {
+ IWL_WARN(priv, "CCK and auto detect");
+ error = true;
+ }
- error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
- RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK);
- if (error)
- IWL_WARN(priv, "check TGG and auto detect %d | %d\n",
- counter++, error);
+ if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
+ RXON_FLG_TGG_PROTECT_MSK)) ==
+ RXON_FLG_TGG_PROTECT_MSK) {
+ IWL_WARN(priv, "TGg but no auto-detect\n");
+ error = true;
+ }
if (error)
IWL_WARN(priv, "Tuning to channel %d\n",
le16_to_cpu(rxon->channel));
if (error) {
- IWL_ERR(priv, "Not a valid iwl_rxon_assoc_cmd field values\n");
- return -1;
+ IWL_ERR(priv, "Invalid RXON\n");
+ return -EINVAL;
}
return 0;
}
@@ -636,66 +591,83 @@ EXPORT_SYMBOL(iwl_check_rxon_cmd);
* or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
* a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
*/
-int iwl_full_rxon_required(struct iwl_priv *priv)
+int iwl_full_rxon_required(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
{
+ const struct iwl_rxon_cmd *staging = &ctx->staging;
+ const struct iwl_rxon_cmd *active = &ctx->active;
+
+#define CHK(cond) \
+ if ((cond)) { \
+ IWL_DEBUG_INFO(priv, "need full RXON - " #cond "\n"); \
+ return 1; \
+ }
+
+#define CHK_NEQ(c1, c2) \
+ if ((c1) != (c2)) { \
+ IWL_DEBUG_INFO(priv, "need full RXON - " \
+ #c1 " != " #c2 " - %d != %d\n", \
+ (c1), (c2)); \
+ return 1; \
+ }
/* These items are only settable from the full RXON command */
- if (!(iwl_is_associated(priv)) ||
- compare_ether_addr(priv->staging_rxon.bssid_addr,
- priv->active_rxon.bssid_addr) ||
- compare_ether_addr(priv->staging_rxon.node_addr,
- priv->active_rxon.node_addr) ||
- compare_ether_addr(priv->staging_rxon.wlap_bssid_addr,
- priv->active_rxon.wlap_bssid_addr) ||
- (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) ||
- (priv->staging_rxon.channel != priv->active_rxon.channel) ||
- (priv->staging_rxon.air_propagation !=
- priv->active_rxon.air_propagation) ||
- (priv->staging_rxon.ofdm_ht_single_stream_basic_rates !=
- priv->active_rxon.ofdm_ht_single_stream_basic_rates) ||
- (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates !=
- priv->active_rxon.ofdm_ht_dual_stream_basic_rates) ||
- (priv->staging_rxon.ofdm_ht_triple_stream_basic_rates !=
- priv->active_rxon.ofdm_ht_triple_stream_basic_rates) ||
- (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
- return 1;
+ CHK(!iwl_is_associated_ctx(ctx));
+ CHK(compare_ether_addr(staging->bssid_addr, active->bssid_addr));
+ CHK(compare_ether_addr(staging->node_addr, active->node_addr));
+ CHK(compare_ether_addr(staging->wlap_bssid_addr,
+ active->wlap_bssid_addr));
+ CHK_NEQ(staging->dev_type, active->dev_type);
+ CHK_NEQ(staging->channel, active->channel);
+ CHK_NEQ(staging->air_propagation, active->air_propagation);
+ CHK_NEQ(staging->ofdm_ht_single_stream_basic_rates,
+ active->ofdm_ht_single_stream_basic_rates);
+ CHK_NEQ(staging->ofdm_ht_dual_stream_basic_rates,
+ active->ofdm_ht_dual_stream_basic_rates);
+ CHK_NEQ(staging->ofdm_ht_triple_stream_basic_rates,
+ active->ofdm_ht_triple_stream_basic_rates);
+ CHK_NEQ(staging->assoc_id, active->assoc_id);
/* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
* be updated with the RXON_ASSOC command -- however only some
* flag transitions are allowed using RXON_ASSOC */
/* Check if we are not switching bands */
- if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) !=
- (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK))
- return 1;
+ CHK_NEQ(staging->flags & RXON_FLG_BAND_24G_MSK,
+ active->flags & RXON_FLG_BAND_24G_MSK);
/* Check if we are switching association toggle */
- if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) !=
- (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK))
- return 1;
+ CHK_NEQ(staging->filter_flags & RXON_FILTER_ASSOC_MSK,
+ active->filter_flags & RXON_FILTER_ASSOC_MSK);
+
+#undef CHK
+#undef CHK_NEQ
return 0;
}
EXPORT_SYMBOL(iwl_full_rxon_required);
-u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv)
+u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
{
/*
* Assign the lowest rate -- should really get this from
* the beacon skb from mac80211.
*/
- if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
+ if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK)
return IWL_RATE_1M_PLCP;
else
return IWL_RATE_6M_PLCP;
}
EXPORT_SYMBOL(iwl_rate_get_lowest_plcp);
-void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
+static void _iwl_set_rxon_ht(struct iwl_priv *priv,
+ struct iwl_ht_config *ht_conf,
+ struct iwl_rxon_context *ctx)
{
- struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+ struct iwl_rxon_cmd *rxon = &ctx->staging;
- if (!ht_conf->is_ht) {
+ if (!ctx->ht.enabled) {
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
RXON_FLG_HT40_PROT_MSK |
@@ -703,22 +675,22 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
return;
}
- /* FIXME: if the definition of ht_protection changed, the "translation"
+ /* FIXME: if the definition of ht.protection changed, the "translation"
* will be needed for rxon->flags
*/
- rxon->flags |= cpu_to_le32(ht_conf->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS);
+ rxon->flags |= cpu_to_le32(ctx->ht.protection << RXON_FLG_HT_OPERATING_MODE_POS);
/* Set up channel bandwidth:
* 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
/* clear the HT channel mode before set the mode */
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
- if (iwl_is_ht40_tx_allowed(priv, NULL)) {
+ if (iwl_is_ht40_tx_allowed(priv, ctx, NULL)) {
/* pure ht40 */
- if (ht_conf->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
+ if (ctx->ht.protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
/* Note: control channel is opposite of extension channel */
- switch (ht_conf->extension_chan_offset) {
+ switch (ctx->ht.extension_chan_offset) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
rxon->flags &= ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
break;
@@ -728,7 +700,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
}
} else {
/* Note: control channel is opposite of extension channel */
- switch (ht_conf->extension_chan_offset) {
+ switch (ctx->ht.extension_chan_offset) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
@@ -749,162 +721,58 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
}
if (priv->cfg->ops->hcmd->set_rxon_chain)
- priv->cfg->ops->hcmd->set_rxon_chain(priv);
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X "
"extension channel offset 0x%x\n",
- le32_to_cpu(rxon->flags), ht_conf->ht_protection,
- ht_conf->extension_chan_offset);
-}
-EXPORT_SYMBOL(iwl_set_rxon_ht);
-
-#define IWL_NUM_RX_CHAINS_MULTIPLE 3
-#define IWL_NUM_RX_CHAINS_SINGLE 2
-#define IWL_NUM_IDLE_CHAINS_DUAL 2
-#define IWL_NUM_IDLE_CHAINS_SINGLE 1
-
-/*
- * Determine how many receiver/antenna chains to use.
- *
- * More provides better reception via diversity. Fewer saves power
- * at the expense of throughput, but only when not in powersave to
- * start with.
- *
- * MIMO (dual stream) requires at least 2, but works better with 3.
- * This does not determine *which* chains to use, just how many.
- */
-static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
-{
- /* # of Rx chains to use when expecting MIMO. */
- if (is_single_rx_stream(priv))
- return IWL_NUM_RX_CHAINS_SINGLE;
- else
- return IWL_NUM_RX_CHAINS_MULTIPLE;
-}
-
-/*
- * When we are in power saving mode, unless device support spatial
- * multiplexing power save, use the active count for rx chain count.
- */
-static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
-{
- /* # Rx chains when idling, depending on SMPS mode */
- switch (priv->current_ht_config.smps) {
- case IEEE80211_SMPS_STATIC:
- case IEEE80211_SMPS_DYNAMIC:
- return IWL_NUM_IDLE_CHAINS_SINGLE;
- case IEEE80211_SMPS_OFF:
- return active_cnt;
- default:
- WARN(1, "invalid SMPS mode %d",
- priv->current_ht_config.smps);
- return active_cnt;
- }
+ le32_to_cpu(rxon->flags), ctx->ht.protection,
+ ctx->ht.extension_chan_offset);
}
-/* up to 4 chains */
-static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
+void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
{
- u8 res;
- res = (chain_bitmap & BIT(0)) >> 0;
- res += (chain_bitmap & BIT(1)) >> 1;
- res += (chain_bitmap & BIT(2)) >> 2;
- res += (chain_bitmap & BIT(3)) >> 3;
- return res;
-}
-
-/**
- * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
- *
- * Selects how many and which Rx receivers/antennas/chains to use.
- * This should not be used for scan command ... it puts data in wrong place.
- */
-void iwl_set_rxon_chain(struct iwl_priv *priv)
-{
- bool is_single = is_single_rx_stream(priv);
- bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
- u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt;
- u32 active_chains;
- u16 rx_chain;
-
- /* Tell uCode which antennas are actually connected.
- * Before first association, we assume all antennas are connected.
- * Just after first association, iwl_chain_noise_calibration()
- * checks which antennas actually *are* connected. */
- if (priv->chain_noise_data.active_chains)
- active_chains = priv->chain_noise_data.active_chains;
- else
- active_chains = priv->hw_params.valid_rx_ant;
-
- rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS;
-
- /* How many receivers should we use? */
- active_rx_cnt = iwl_get_active_rx_chain_count(priv);
- idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
-
-
- /* correct rx chain count according hw settings
- * and chain noise calibration
- */
- valid_rx_cnt = iwl_count_chain_bitmap(active_chains);
- if (valid_rx_cnt < active_rx_cnt)
- active_rx_cnt = valid_rx_cnt;
-
- if (valid_rx_cnt < idle_rx_cnt)
- idle_rx_cnt = valid_rx_cnt;
-
- rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
- rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS;
-
- priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain);
-
- if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam)
- priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
- else
- priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
+ struct iwl_rxon_context *ctx;
- IWL_DEBUG_ASSOC(priv, "rx_chain=0x%X active=%d idle=%d\n",
- priv->staging_rxon.rx_chain,
- active_rx_cnt, idle_rx_cnt);
-
- WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 ||
- active_rx_cnt < idle_rx_cnt);
+ for_each_context(priv, ctx)
+ _iwl_set_rxon_ht(priv, ht_conf, ctx);
}
-EXPORT_SYMBOL(iwl_set_rxon_chain);
+EXPORT_SYMBOL(iwl_set_rxon_ht);
-/* Return valid channel */
+/* Return valid, unused, channel for a passive scan to reset the RF */
u8 iwl_get_single_channel_number(struct iwl_priv *priv,
- enum ieee80211_band band)
+ enum ieee80211_band band)
{
const struct iwl_channel_info *ch_info;
int i;
u8 channel = 0;
+ u8 min, max;
+ struct iwl_rxon_context *ctx;
- /* only scan single channel, good enough to reset the RF */
- /* pick the first valid not in-use channel */
if (band == IEEE80211_BAND_5GHZ) {
- for (i = 14; i < priv->channel_count; i++) {
- if (priv->channel_info[i].channel !=
- le16_to_cpu(priv->staging_rxon.channel)) {
- channel = priv->channel_info[i].channel;
- ch_info = iwl_get_channel_info(priv,
- band, channel);
- if (is_channel_valid(ch_info))
- break;
- }
- }
+ min = 14;
+ max = priv->channel_count;
} else {
- for (i = 0; i < 14; i++) {
- if (priv->channel_info[i].channel !=
- le16_to_cpu(priv->staging_rxon.channel)) {
- channel =
- priv->channel_info[i].channel;
- ch_info = iwl_get_channel_info(priv,
- band, channel);
- if (is_channel_valid(ch_info))
- break;
- }
+ min = 0;
+ max = 14;
+ }
+
+ for (i = min; i < max; i++) {
+ bool busy = false;
+
+ for_each_context(priv, ctx) {
+ busy = priv->channel_info[i].channel ==
+ le16_to_cpu(ctx->staging.channel);
+ if (busy)
+ break;
}
+
+ if (busy)
+ continue;
+
+ channel = priv->channel_info[i].channel;
+ ch_info = iwl_get_channel_info(priv, band, channel);
+ if (is_channel_valid(ch_info))
+ break;
}
return channel;
@@ -912,35 +780,27 @@ u8 iwl_get_single_channel_number(struct iwl_priv *priv,
EXPORT_SYMBOL(iwl_get_single_channel_number);
/**
- * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
- * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
- * @channel: Any channel valid for the requested phymode
+ * iwl_set_rxon_channel - Set the band and channel values in staging RXON
+ * @ch: requested channel as a pointer to struct ieee80211_channel
- * In addition to setting the staging RXON, priv->phymode is also set.
- *
* NOTE: Does not commit to the hardware; it sets appropriate bit fields
- * in the staging RXON flag structure based on the phymode
+ * in the staging RXON flag structure based on the ch->band
*/
-int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch)
+int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
+ struct iwl_rxon_context *ctx)
{
enum ieee80211_band band = ch->band;
- u16 channel = ieee80211_frequency_to_channel(ch->center_freq);
+ u16 channel = ch->hw_value;
- if (!iwl_get_channel_info(priv, band, channel)) {
- IWL_DEBUG_INFO(priv, "Could not set channel to %d [%d]\n",
- channel, band);
- return -EINVAL;
- }
-
- if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
+ if ((le16_to_cpu(ctx->staging.channel) == channel) &&
(priv->band == band))
return 0;
- priv->staging_rxon.channel = cpu_to_le16(channel);
+ ctx->staging.channel = cpu_to_le16(channel);
if (band == IEEE80211_BAND_5GHZ)
- priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
+ ctx->staging.flags &= ~RXON_FLG_BAND_24G_MSK;
else
- priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+ ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
priv->band = band;
@@ -951,24 +811,25 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch)
EXPORT_SYMBOL(iwl_set_rxon_channel);
void iwl_set_flags_for_band(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
enum ieee80211_band band,
struct ieee80211_vif *vif)
{
if (band == IEEE80211_BAND_5GHZ) {
- priv->staging_rxon.flags &=
+ ctx->staging.flags &=
~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
| RXON_FLG_CCK_MSK);
- priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
} else {
/* Copied from iwl_post_associate() */
if (vif && vif->bss_conf.use_short_slot)
- priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
else
- priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+ ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
- priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
- priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
- priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
+ ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
+ ctx->staging.flags |= RXON_FLG_AUTO_DETECT_MSK;
+ ctx->staging.flags &= ~RXON_FLG_CCK_MSK;
}
}
EXPORT_SYMBOL(iwl_set_flags_for_band);
@@ -977,35 +838,34 @@ EXPORT_SYMBOL(iwl_set_flags_for_band);
* initialize rxon structure with default values from eeprom
*/
void iwl_connection_init_rx_config(struct iwl_priv *priv,
- struct ieee80211_vif *vif)
+ struct iwl_rxon_context *ctx)
{
const struct iwl_channel_info *ch_info;
- enum nl80211_iftype type = NL80211_IFTYPE_STATION;
- if (vif)
- type = vif->type;
+ memset(&ctx->staging, 0, sizeof(ctx->staging));
- memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
-
- switch (type) {
+ if (!ctx->vif) {
+ ctx->staging.dev_type = ctx->unused_devtype;
+ } else switch (ctx->vif->type) {
case NL80211_IFTYPE_AP:
- priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
+ ctx->staging.dev_type = ctx->ap_devtype;
break;
case NL80211_IFTYPE_STATION:
- priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
- priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
+ ctx->staging.dev_type = ctx->station_devtype;
+ ctx->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
break;
case NL80211_IFTYPE_ADHOC:
- priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
- priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
- priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
+ ctx->staging.dev_type = ctx->ibss_devtype;
+ ctx->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
+ ctx->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
RXON_FILTER_ACCEPT_GRP_MSK;
break;
default:
- IWL_ERR(priv, "Unsupported interface type %d\n", type);
+ IWL_ERR(priv, "Unsupported interface type %d\n",
+ ctx->vif->type);
break;
}
@@ -1013,37 +873,36 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv,
/* TODO: Figure out when short_preamble would be set and cache from
* that */
if (!hw_to_local(priv->hw)->short_preamble)
- priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+ ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
else
- priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+ ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
#endif
ch_info = iwl_get_channel_info(priv, priv->band,
- le16_to_cpu(priv->active_rxon.channel));
+ le16_to_cpu(ctx->active.channel));
if (!ch_info)
ch_info = &priv->channel_info[0];
- priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
+ ctx->staging.channel = cpu_to_le16(ch_info->channel);
priv->band = ch_info->band;
- iwl_set_flags_for_band(priv, priv->band, vif);
+ iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif);
- priv->staging_rxon.ofdm_basic_rates =
+ ctx->staging.ofdm_basic_rates =
(IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
- priv->staging_rxon.cck_basic_rates =
+ ctx->staging.cck_basic_rates =
(IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
/* clear both MIX and PURE40 mode flag */
- priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
+ ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
RXON_FLG_CHANNEL_MODE_PURE_40);
+ if (ctx->vif)
+ memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN);
- if (vif)
- memcpy(priv->staging_rxon.node_addr, vif->addr, ETH_ALEN);
-
- priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
- priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
- priv->staging_rxon.ofdm_ht_triple_stream_basic_rates = 0xff;
+ ctx->staging.ofdm_ht_single_stream_basic_rates = 0xff;
+ ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff;
+ ctx->staging.ofdm_ht_triple_stream_basic_rates = 0xff;
}
EXPORT_SYMBOL(iwl_connection_init_rx_config);
@@ -1051,6 +910,7 @@ void iwl_set_rate(struct iwl_priv *priv)
{
const struct ieee80211_supported_band *hw = NULL;
struct ieee80211_rate *rate;
+ struct iwl_rxon_context *ctx;
int i;
hw = iwl_get_hw_mode(priv, priv->band);
@@ -1069,21 +929,29 @@ void iwl_set_rate(struct iwl_priv *priv)
IWL_DEBUG_RATE(priv, "Set active_rate = %0x\n", priv->active_rate);
- priv->staging_rxon.cck_basic_rates =
- (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+ for_each_context(priv, ctx) {
+ ctx->staging.cck_basic_rates =
+ (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
- priv->staging_rxon.ofdm_basic_rates =
- (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+ ctx->staging.ofdm_basic_rates =
+ (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+ }
}
EXPORT_SYMBOL(iwl_set_rate);
void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
{
+ /*
+ * MULTI-FIXME
+ * See iwl_mac_channel_switch.
+ */
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
if (priv->switch_rxon.switch_in_progress) {
- ieee80211_chswitch_done(priv->vif, is_success);
+ ieee80211_chswitch_done(ctx->vif, is_success);
mutex_lock(&priv->mutex);
priv->switch_rxon.switch_in_progress = false;
mutex_unlock(&priv->mutex);
@@ -1094,14 +962,19 @@ EXPORT_SYMBOL(iwl_chswitch_done);
void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
+ /*
+ * MULTI-FIXME
+ * See iwl_mac_channel_switch.
+ */
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+ struct iwl_rxon_cmd *rxon = (void *)&ctx->active;
if (priv->switch_rxon.switch_in_progress) {
if (!le32_to_cpu(csa->status) &&
(csa->channel == priv->switch_rxon.channel)) {
rxon->channel = csa->channel;
- priv->staging_rxon.channel = csa->channel;
+ ctx->staging.channel = csa->channel;
IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
le16_to_cpu(csa->channel));
iwl_chswitch_done(priv, true);
@@ -1115,9 +988,10 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
EXPORT_SYMBOL(iwl_rx_csa);
#ifdef CONFIG_IWLWIFI_DEBUG
-void iwl_print_rx_config_cmd(struct iwl_priv *priv)
+void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
{
- struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+ struct iwl_rxon_cmd *rxon = &ctx->staging;
IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
@@ -1157,7 +1031,8 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
priv->cfg->ops->lib->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);
+ iwl_print_rx_config_cmd(priv,
+ &priv->contexts[IWL_RXON_CTX_BSS]);
#endif
wake_up_interruptible(&priv->wait_command_queue);
@@ -1261,7 +1136,7 @@ int iwl_apm_init(struct iwl_priv *priv)
* If not (unlikely), enable L0S, so there is at least some
* power savings, even without L1.
*/
- if (priv->cfg->set_l0s) {
+ if (priv->cfg->base_params->set_l0s) {
lctl = iwl_pcie_link_ctl(priv);
if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
PCI_CFG_LINK_CTRL_VAL_L1_EN) {
@@ -1278,8 +1153,9 @@ int iwl_apm_init(struct iwl_priv *priv)
}
/* Configure analog phase-lock-loop before activating to D0A */
- if (priv->cfg->pll_cfg_val)
- iwl_set_bit(priv, CSR_ANA_PLL_CFG, priv->cfg->pll_cfg_val);
+ if (priv->cfg->base_params->pll_cfg_val)
+ iwl_set_bit(priv, CSR_ANA_PLL_CFG,
+ priv->cfg->base_params->pll_cfg_val);
/*
* Set "initialization complete" bit to move adapter from
@@ -1310,7 +1186,7 @@ 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.
*/
- if (priv->cfg->use_bsm)
+ if (priv->cfg->base_params->use_bsm)
iwl_write_prph(priv, APMG_CLK_EN_REG,
APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT);
else
@@ -1328,25 +1204,6 @@ out:
EXPORT_SYMBOL(iwl_apm_init);
-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 (priv->cfg->mod_params->amsdu_size_8K)
- priv->hw_params.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;
-
- if (priv->cfg->mod_params->disable_11n)
- priv->cfg->sku &= ~IWL_SKU_N;
-
- /* Device-specific setup */
- return priv->cfg->ops->lib->set_hw_params(priv);
-}
-EXPORT_SYMBOL(iwl_set_hw_params);
-
int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
{
int ret = 0;
@@ -1496,76 +1353,6 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
}
EXPORT_SYMBOL(iwl_send_statistics_request);
-void iwl_rf_kill_ct_config(struct iwl_priv *priv)
-{
- struct iwl_ct_kill_config cmd;
- struct iwl_ct_kill_throttling_config adv_cmd;
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&priv->lock, flags);
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
- CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
- spin_unlock_irqrestore(&priv->lock, flags);
- priv->thermal_throttle.ct_kill_toggle = false;
-
- if (priv->cfg->support_ct_kill_exit) {
- adv_cmd.critical_temperature_enter =
- cpu_to_le32(priv->hw_params.ct_kill_threshold);
- adv_cmd.critical_temperature_exit =
- cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
-
- ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
- 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);
- } else {
- cmd.critical_temperature_R =
- cpu_to_le32(priv->hw_params.ct_kill_threshold);
-
- ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
- 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);
- }
-}
-EXPORT_SYMBOL(iwl_rf_kill_ct_config);
-
-
-/*
- * CARD_STATE_CMD
- *
- * Use: Sets the device's internal card state to enable, disable, or halt
- *
- * When in the 'enable' state the card operates as normal.
- * When in the 'disable' state, the card enters into a low power mode.
- * When in the 'halt' state, the card is shut down and must be fully
- * restarted to come back on.
- */
-int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
-{
- struct iwl_host_cmd cmd = {
- .id = REPLY_CARD_STATE_CMD,
- .len = sizeof(u32),
- .data = &flags,
- .flags = meta_flag,
- };
-
- return iwl_send_cmd(priv, &cmd);
-}
-
void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
@@ -1614,6 +1401,7 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct iwl_priv *priv = hw->priv;
+ struct iwl_rxon_context *ctx;
unsigned long flags;
int q;
@@ -1633,13 +1421,21 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
spin_lock_irqsave(&priv->lock, flags);
- priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min);
- priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
- priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
- priv->qos_data.def_qos_parm.ac[q].edca_txop =
- cpu_to_le16((params->txop * 32));
+ /*
+ * MULTI-FIXME
+ * This may need to be done per interface in nl80211/cfg80211/mac80211.
+ */
+ for_each_context(priv, ctx) {
+ ctx->qos_data.def_qos_parm.ac[q].cw_min =
+ cpu_to_le16(params->cw_min);
+ ctx->qos_data.def_qos_parm.ac[q].cw_max =
+ cpu_to_le16(params->cw_max);
+ ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+ ctx->qos_data.def_qos_parm.ac[q].edca_txop =
+ cpu_to_le16((params->txop * 32));
- priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+ ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+ }
spin_unlock_irqrestore(&priv->lock, flags);
@@ -1648,21 +1444,30 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
}
EXPORT_SYMBOL(iwl_mac_conf_tx);
+int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ return priv->ibss_manager == IWL_IBSS_MANAGER;
+}
+EXPORT_SYMBOL_GPL(iwl_mac_tx_last_beacon);
+
static void iwl_ht_conf(struct iwl_priv *priv,
struct ieee80211_vif *vif)
{
struct iwl_ht_config *ht_conf = &priv->current_ht_config;
struct ieee80211_sta *sta;
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
IWL_DEBUG_MAC80211(priv, "enter:\n");
- if (!ht_conf->is_ht)
+ if (!ctx->ht.enabled)
return;
- ht_conf->ht_protection =
+ ctx->ht.protection =
bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
- ht_conf->non_GF_STA_present =
+ ctx->ht.non_gf_sta_present =
!!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
ht_conf->single_chain_sufficient = false;
@@ -1706,49 +1511,63 @@ static void iwl_ht_conf(struct iwl_priv *priv,
IWL_DEBUG_MAC80211(priv, "leave\n");
}
-static inline void iwl_set_no_assoc(struct iwl_priv *priv)
+static inline void iwl_set_no_assoc(struct iwl_priv *priv,
+ struct ieee80211_vif *vif)
{
+ struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
iwl_led_disassociate(priv);
/*
* inform the ucode that there is no longer an
* association and that no more packets should be
* sent
*/
- priv->staging_rxon.filter_flags &=
- ~RXON_FILTER_ASSOC_MSK;
- priv->staging_rxon.assoc_id = 0;
- iwlcore_commit_rxon(priv);
+ ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ ctx->staging.assoc_id = 0;
+ iwlcore_commit_rxon(priv, ctx);
}
-static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
+static void iwlcore_beacon_update(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
struct iwl_priv *priv = hw->priv;
unsigned long flags;
__le64 timestamp;
+ struct sk_buff *skb = ieee80211_beacon_get(hw, vif);
- IWL_DEBUG_MAC80211(priv, "enter\n");
+ if (!skb)
+ return;
- if (!iwl_is_ready_rf(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
- return -EIO;
+ IWL_DEBUG_ASSOC(priv, "enter\n");
+
+ lockdep_assert_held(&priv->mutex);
+
+ if (!priv->beacon_ctx) {
+ IWL_ERR(priv, "update beacon but no beacon context!\n");
+ dev_kfree_skb(skb);
+ return;
}
spin_lock_irqsave(&priv->lock, flags);
- if (priv->ibss_beacon)
- dev_kfree_skb(priv->ibss_beacon);
+ if (priv->beacon_skb)
+ dev_kfree_skb(priv->beacon_skb);
- priv->ibss_beacon = skb;
+ priv->beacon_skb = skb;
timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
priv->timestamp = le64_to_cpu(timestamp);
- IWL_DEBUG_MAC80211(priv, "leave\n");
+ IWL_DEBUG_ASSOC(priv, "leave\n");
+
spin_unlock_irqrestore(&priv->lock, flags);
- priv->cfg->ops->lib->post_associate(priv, priv->vif);
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
+ return;
+ }
- return 0;
+ priv->cfg->ops->lib->post_associate(priv, priv->beacon_ctx->vif);
}
void iwl_bss_info_changed(struct ieee80211_hw *hw,
@@ -1757,6 +1576,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
u32 changes)
{
struct iwl_priv *priv = hw->priv;
+ struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
int ret;
IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes);
@@ -1770,20 +1590,31 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
- priv->qos_data.qos_active = bss_conf->qos;
- iwl_update_qos(priv);
+ ctx->qos_data.qos_active = bss_conf->qos;
+ iwl_update_qos(priv, ctx);
spin_unlock_irqrestore(&priv->lock, flags);
}
- if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) {
- dev_kfree_skb(priv->ibss_beacon);
- priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
+ if (changes & BSS_CHANGED_BEACON_ENABLED) {
+ /*
+ * the add_interface code must make sure we only ever
+ * have a single interface that could be beaconing at
+ * any time.
+ */
+ if (vif->bss_conf.enable_beacon)
+ priv->beacon_ctx = ctx;
+ else
+ priv->beacon_ctx = NULL;
}
- if (changes & BSS_CHANGED_BEACON_INT) {
- /* TODO: in AP mode, do something to make this take effect */
+ if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) {
+ dev_kfree_skb(priv->beacon_skb);
+ priv->beacon_skb = ieee80211_beacon_get(hw, vif);
}
+ if (changes & BSS_CHANGED_BEACON_INT && vif->type == NL80211_IFTYPE_AP)
+ iwl_send_rxon_timing(priv, ctx);
+
if (changes & BSS_CHANGED_BSSID) {
IWL_DEBUG_MAC80211(priv, "BSSID %pM\n", bss_conf->bssid);
@@ -1801,13 +1632,13 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
/* mac80211 only sets assoc when in STATION mode */
if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) {
- memcpy(priv->staging_rxon.bssid_addr,
+ memcpy(ctx->staging.bssid_addr,
bss_conf->bssid, ETH_ALEN);
/* currently needed in a few places */
memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
} else {
- priv->staging_rxon.filter_flags &=
+ ctx->staging.filter_flags &=
~RXON_FILTER_ASSOC_MSK;
}
@@ -1818,33 +1649,28 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
* mac80211 decides to do both changes at once because
* it will invoke post_associate.
*/
- if (vif->type == NL80211_IFTYPE_ADHOC &&
- changes & BSS_CHANGED_BEACON) {
- struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
-
- if (beacon)
- iwl_mac_beacon_update(hw, beacon);
- }
+ if (vif->type == NL80211_IFTYPE_ADHOC && changes & BSS_CHANGED_BEACON)
+ iwlcore_beacon_update(hw, vif);
if (changes & BSS_CHANGED_ERP_PREAMBLE) {
IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n",
bss_conf->use_short_preamble);
if (bss_conf->use_short_preamble)
- priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+ ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
else
- priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+ ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
}
if (changes & BSS_CHANGED_ERP_CTS_PROT) {
IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot);
if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
- priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
+ ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
else
- priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+ ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
if (bss_conf->use_cts_prot)
- priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
+ ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
else
- priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
+ ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
}
if (changes & BSS_CHANGED_BASIC_RATES) {
@@ -1854,12 +1680,12 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
* like this here:
*
if (A-band)
- priv->staging_rxon.ofdm_basic_rates =
+ ctx->staging.ofdm_basic_rates =
bss_conf->basic_rates;
else
- priv->staging_rxon.ofdm_basic_rates =
+ ctx->staging.ofdm_basic_rates =
bss_conf->basic_rates >> 4;
- priv->staging_rxon.cck_basic_rates =
+ ctx->staging.cck_basic_rates =
bss_conf->basic_rates & 0xF;
*/
}
@@ -1868,7 +1694,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
iwl_ht_conf(priv, vif);
if (priv->cfg->ops->hcmd->set_rxon_chain)
- priv->cfg->ops->hcmd->set_rxon_chain(priv);
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
}
if (changes & BSS_CHANGED_ASSOC) {
@@ -1881,29 +1707,30 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
if (!iwl_is_rfkill(priv))
priv->cfg->ops->lib->post_associate(priv, vif);
} else
- iwl_set_no_assoc(priv);
+ iwl_set_no_assoc(priv, vif);
}
- if (changes && iwl_is_associated(priv) && bss_conf->aid) {
+ if (changes && iwl_is_associated_ctx(ctx) && bss_conf->aid) {
IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n",
changes);
- ret = iwl_send_rxon_assoc(priv);
+ ret = iwl_send_rxon_assoc(priv, ctx);
if (!ret) {
/* Sync active_rxon with latest change. */
- memcpy((void *)&priv->active_rxon,
- &priv->staging_rxon,
+ memcpy((void *)&ctx->active,
+ &ctx->staging,
sizeof(struct iwl_rxon_cmd));
}
}
if (changes & BSS_CHANGED_BEACON_ENABLED) {
if (vif->bss_conf.enable_beacon) {
- memcpy(priv->staging_rxon.bssid_addr,
+ memcpy(ctx->staging.bssid_addr,
bss_conf->bssid, ETH_ALEN);
memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
+ iwl_led_associate(priv);
iwlcore_config_ap(priv, vif);
} else
- iwl_set_no_assoc(priv);
+ iwl_set_no_assoc(priv, vif);
}
if (changes & BSS_CHANGED_IBSS) {
@@ -1915,6 +1742,12 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
bss_conf->bssid);
}
+ if (changes & BSS_CHANGED_IDLE &&
+ priv->cfg->ops->hcmd->set_pan_params) {
+ if (priv->cfg->ops->hcmd->set_pan_params(priv))
+ IWL_ERR(priv, "failed to update PAN params\n");
+ }
+
mutex_unlock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -1923,17 +1756,21 @@ EXPORT_SYMBOL(iwl_bss_info_changed);
static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif)
{
- iwl_connection_init_rx_config(priv, vif);
+ struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
+ iwl_connection_init_rx_config(priv, ctx);
if (priv->cfg->ops->hcmd->set_rxon_chain)
- priv->cfg->ops->hcmd->set_rxon_chain(priv);
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
- return iwlcore_commit_rxon(priv);
+ return iwlcore_commit_rxon(priv, ctx);
}
int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct iwl_priv *priv = hw->priv;
+ struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+ struct iwl_rxon_context *tmp, *ctx = NULL;
int err = 0;
IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
@@ -1941,28 +1778,72 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
mutex_lock(&priv->mutex);
- if (WARN_ON(!iwl_is_ready_rf(priv))) {
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_WARN(priv, "Try to add interface when device not ready\n");
err = -EINVAL;
goto out;
}
- if (priv->vif) {
- IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n");
+ for_each_context(priv, tmp) {
+ u32 possible_modes =
+ tmp->interface_modes | tmp->exclusive_interface_modes;
+
+ if (tmp->vif) {
+ /* check if this busy context is exclusive */
+ if (tmp->exclusive_interface_modes &
+ BIT(tmp->vif->type)) {
+ err = -EINVAL;
+ goto out;
+ }
+ continue;
+ }
+
+ if (!(possible_modes & BIT(vif->type)))
+ continue;
+
+ /* have maybe usable context w/o interface */
+ ctx = tmp;
+ break;
+ }
+
+ if (!ctx) {
err = -EOPNOTSUPP;
goto out;
}
- priv->vif = vif;
+ vif_priv->ctx = ctx;
+ ctx->vif = vif;
+ /*
+ * This variable will be correct only when there's just
+ * a single context, but all code using it is for hardware
+ * that supports only one context.
+ */
priv->iw_mode = vif->type;
+ ctx->is_active = true;
+
err = iwl_set_mode(priv, vif);
- if (err)
+ if (err) {
+ if (!ctx->always_active)
+ ctx->is_active = false;
goto out_err;
+ }
+
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist &&
+ vif->type == NL80211_IFTYPE_ADHOC) {
+ /*
+ * pretend to have high BT traffic as long as we
+ * are operating in IBSS mode, as this will cause
+ * the rate scaling etc. to behave as intended.
+ */
+ priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+ }
goto out;
out_err:
- priv->vif = NULL;
+ ctx->vif = NULL;
priv->iw_mode = NL80211_IFTYPE_STATION;
out:
mutex_unlock(&priv->mutex);
@@ -1976,30 +1857,36 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct iwl_priv *priv = hw->priv;
- bool scan_completed = false;
+ struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
IWL_DEBUG_MAC80211(priv, "enter\n");
mutex_lock(&priv->mutex);
- if (iwl_is_ready_rf(priv)) {
- iwl_scan_cancel_timeout(priv, 100);
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwlcore_commit_rxon(priv);
- }
- if (priv->vif == vif) {
- priv->vif = NULL;
- if (priv->scan_vif == vif) {
- scan_completed = true;
- priv->scan_vif = NULL;
- priv->scan_request = NULL;
- }
- memset(priv->bssid, 0, ETH_ALEN);
+ WARN_ON(ctx->vif != vif);
+ ctx->vif = NULL;
+
+ if (priv->scan_vif == vif) {
+ iwl_scan_cancel_timeout(priv, 200);
+ iwl_force_scan_end(priv);
}
- mutex_unlock(&priv->mutex);
+ iwl_set_mode(priv, vif);
- if (scan_completed)
- ieee80211_scan_completed(priv->hw, true);
+ if (!ctx->always_active)
+ ctx->is_active = false;
+
+ /*
+ * When removing the IBSS interface, overwrite the
+ * BT traffic load with the stored one from the last
+ * notification, if any. If this is a device that
+ * doesn't implement this, this has no effect since
+ * both values are the same and zero.
+ */
+ if (vif->type == NL80211_IFTYPE_ADHOC)
+ priv->bt_traffic_load = priv->notif_bt_traffic_load;
+
+ memset(priv->bssid, 0, ETH_ALEN);
+ mutex_unlock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -2014,7 +1901,9 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
struct iwl_priv *priv = hw->priv;
const struct iwl_channel_info *ch_info;
struct ieee80211_conf *conf = &hw->conf;
+ struct ieee80211_channel *channel = conf->channel;
struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+ struct iwl_rxon_context *ctx;
unsigned long flags = 0;
int ret = 0;
u16 ch;
@@ -2023,7 +1912,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n",
- conf->channel->hw_value, changed);
+ channel->hw_value, changed);
if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
test_bit(STATUS_SCANNING, &priv->status))) {
@@ -2044,7 +1933,8 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
* configured.
*/
if (priv->cfg->ops->hcmd->set_rxon_chain)
- priv->cfg->ops->hcmd->set_rxon_chain(priv);
+ for_each_context(priv, ctx)
+ priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
}
/* during scanning mac80211 will delay channel setting until
@@ -2054,8 +1944,8 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
if (scan_active)
goto set_ch_out;
- ch = ieee80211_frequency_to_channel(conf->channel->center_freq);
- ch_info = iwl_get_channel_info(priv, conf->channel->band, ch);
+ ch = channel->hw_value;
+ ch_info = iwl_get_channel_info(priv, channel->band, ch);
if (!is_channel_valid(ch_info)) {
IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
ret = -EINVAL;
@@ -2064,42 +1954,49 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
spin_lock_irqsave(&priv->lock, flags);
- /* Configure HT40 channels */
- ht_conf->is_ht = conf_is_ht(conf);
- if (ht_conf->is_ht) {
- if (conf_is_ht40_minus(conf)) {
- ht_conf->extension_chan_offset =
- IEEE80211_HT_PARAM_CHA_SEC_BELOW;
- ht_conf->is_40mhz = true;
- } else if (conf_is_ht40_plus(conf)) {
- ht_conf->extension_chan_offset =
- IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
- ht_conf->is_40mhz = true;
- } else {
- ht_conf->extension_chan_offset =
- IEEE80211_HT_PARAM_CHA_SEC_NONE;
- ht_conf->is_40mhz = false;
- }
- } else
- ht_conf->is_40mhz = false;
- /* Default to no protection. Protection mode will later be set
- * from BSS config in iwl_ht_conf */
- ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
+ for_each_context(priv, ctx) {
+ /* Configure HT40 channels */
+ ctx->ht.enabled = conf_is_ht(conf);
+ if (ctx->ht.enabled) {
+ if (conf_is_ht40_minus(conf)) {
+ ctx->ht.extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ ctx->ht.is_40mhz = true;
+ } else if (conf_is_ht40_plus(conf)) {
+ ctx->ht.extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ ctx->ht.is_40mhz = true;
+ } else {
+ ctx->ht.extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ ctx->ht.is_40mhz = false;
+ }
+ } else
+ ctx->ht.is_40mhz = false;
- /* if we are switching from ht to 2.4 clear flags
- * from any ht related info since 2.4 does not
- * support ht */
- if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
- priv->staging_rxon.flags = 0;
+ /*
+ * Default to no protection. Protection mode will
+ * later be set from BSS config in iwl_ht_conf
+ */
+ ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
- iwl_set_rxon_channel(priv, conf->channel);
- iwl_set_rxon_ht(priv, ht_conf);
+ /* if we are switching from ht to 2.4 clear flags
+ * from any ht related info since 2.4 does not
+ * support ht */
+ if ((le16_to_cpu(ctx->staging.channel) != ch))
+ ctx->staging.flags = 0;
+
+ iwl_set_rxon_channel(priv, channel, ctx);
+ iwl_set_rxon_ht(priv, ht_conf);
+
+ iwl_set_flags_for_band(priv, ctx, channel->band,
+ ctx->vif);
+ }
- iwl_set_flags_for_band(priv, conf->channel->band, priv->vif);
spin_unlock_irqrestore(&priv->lock, flags);
- if (priv->cfg->ops->lib->update_bcast_station)
- ret = priv->cfg->ops->lib->update_bcast_station(priv);
+ if (priv->cfg->ops->lib->update_bcast_stations)
+ ret = priv->cfg->ops->lib->update_bcast_stations(priv);
set_ch_out:
/* The list of supported rates and rate mask can be different
@@ -2130,12 +2027,13 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
if (scan_active)
goto out;
- if (memcmp(&priv->active_rxon,
- &priv->staging_rxon, sizeof(priv->staging_rxon)))
- iwlcore_commit_rxon(priv);
- else
- IWL_DEBUG_INFO(priv, "Not re-sending same RXON configuration.\n");
-
+ for_each_context(priv, ctx) {
+ if (memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)))
+ iwlcore_commit_rxon(priv, ctx);
+ else
+ IWL_DEBUG_INFO(priv,
+ "Not re-sending same RXON configuration.\n");
+ }
out:
IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -2148,6 +2046,8 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
unsigned long flags;
+ /* IBSS can only be the IWL_RXON_CTX_BSS context */
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
mutex_lock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "enter\n");
@@ -2159,15 +2059,16 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
spin_lock_irqsave(&priv->lock, flags);
/* new association get rid of ibss beacon skb */
- if (priv->ibss_beacon)
- dev_kfree_skb(priv->ibss_beacon);
+ if (priv->beacon_skb)
+ dev_kfree_skb(priv->beacon_skb);
- priv->ibss_beacon = NULL;
+ priv->beacon_skb = NULL;
priv->timestamp = 0;
spin_unlock_irqrestore(&priv->lock, flags);
+ iwl_scan_cancel_timeout(priv, 100);
if (!iwl_is_ready_rf(priv)) {
IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
mutex_unlock(&priv->mutex);
@@ -2177,9 +2078,8 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
/* we are restarting association process
* clear RXON_FILTER_ASSOC_MSK bit
*/
- iwl_scan_cancel_timeout(priv, 100);
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwlcore_commit_rxon(priv);
+ ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwlcore_commit_rxon(priv, ctx);
iwl_set_rate(priv);
@@ -2193,7 +2093,8 @@ int iwl_alloc_txq_mem(struct iwl_priv *priv)
{
if (!priv->txq)
priv->txq = kzalloc(
- sizeof(struct iwl_tx_queue) * priv->cfg->num_of_queues,
+ 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");
@@ -2449,146 +2350,12 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
EXPORT_SYMBOL(iwl_update_stats);
#endif
-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;
- 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]));
- }
-}
-EXPORT_SYMBOL(iwl_dump_csr);
-
-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
- 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;
-}
-EXPORT_SYMBOL(iwl_dump_fh);
-
static void iwl_force_rf_reset(struct iwl_priv *priv)
{
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
- if (!iwl_is_associated(priv)) {
+ if (!iwl_is_any_associated(priv)) {
IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
return;
}
@@ -2613,11 +2380,6 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return -EINVAL;
- if (test_bit(STATUS_SCANNING, &priv->status)) {
- IWL_DEBUG_INFO(priv, "scan in progress.\n");
- return -EINVAL;
- }
-
if (mode >= IWL_MAX_FORCE_RESET) {
IWL_DEBUG_INFO(priv, "invalid reset request.\n");
return -EINVAL;
@@ -2668,7 +2430,6 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
}
return 0;
}
-EXPORT_SYMBOL(iwl_force_reset);
/**
* iwl_bg_monitor_recover - Timer callback to check for stuck queue and recover
@@ -2704,29 +2465,31 @@ static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt)
txq = &priv->txq[cnt];
q = &txq->q;
/* queue is empty, skip */
- if (q->read_ptr != q->write_ptr) {
- if (q->read_ptr == q->last_read_ptr) {
- /* a queue has not been read from last time */
- if (q->repeat_same_read_ptr > MAX_REPEAT) {
- IWL_ERR(priv,
- "queue %d stuck %d time. Fw reload.\n",
- q->id, q->repeat_same_read_ptr);
- q->repeat_same_read_ptr = 0;
- iwl_force_reset(priv, IWL_FW_RESET, false);
- } else {
- q->repeat_same_read_ptr++;
- IWL_DEBUG_RADIO(priv,
- "queue %d, not read %d time\n",
- q->id,
- q->repeat_same_read_ptr);
- mod_timer(&priv->monitor_recover, jiffies +
- msecs_to_jiffies(IWL_ONE_HUNDRED_MSECS));
- }
- return 1;
- } else {
- q->last_read_ptr = q->read_ptr;
+ if (q->read_ptr == q->write_ptr)
+ return 0;
+
+ if (q->read_ptr == q->last_read_ptr) {
+ /* a queue has not been read from last time */
+ if (q->repeat_same_read_ptr > MAX_REPEAT) {
+ IWL_ERR(priv,
+ "queue %d stuck %d time. Fw reload.\n",
+ q->id, q->repeat_same_read_ptr);
q->repeat_same_read_ptr = 0;
+ iwl_force_reset(priv, IWL_FW_RESET, false);
+ } else {
+ q->repeat_same_read_ptr++;
+ IWL_DEBUG_RADIO(priv,
+ "queue %d, not read %d time\n",
+ q->id,
+ q->repeat_same_read_ptr);
+ mod_timer(&priv->monitor_recover,
+ jiffies + msecs_to_jiffies(
+ IWL_ONE_HUNDRED_MSECS));
+ return 1;
}
+ } else {
+ q->last_read_ptr = q->read_ptr;
+ q->repeat_same_read_ptr = 0;
}
return 0;
}
@@ -2740,25 +2503,27 @@ void iwl_bg_monitor_recover(unsigned long data)
return;
/* monitor and check for stuck cmd queue */
- if (iwl_check_stuck_queue(priv, IWL_CMD_QUEUE_NUM))
+ if (iwl_check_stuck_queue(priv, priv->cmd_queue))
return;
/* monitor and check for other stuck queues */
- if (iwl_is_associated(priv)) {
+ if (iwl_is_any_associated(priv)) {
for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
/* skip as we already checked the command queue */
- if (cnt == IWL_CMD_QUEUE_NUM)
+ if (cnt == priv->cmd_queue)
continue;
if (iwl_check_stuck_queue(priv, cnt))
return;
}
}
- /*
- * Reschedule the timer to occur in
- * priv->cfg->monitor_recover_period
- */
- mod_timer(&priv->monitor_recover,
- jiffies + msecs_to_jiffies(priv->cfg->monitor_recover_period));
+ if (priv->cfg->base_params->monitor_recover_period) {
+ /*
+ * Reschedule the timer to occur in
+ * priv->cfg->base_params->monitor_recover_period
+ */
+ mod_timer(&priv->monitor_recover, jiffies + msecs_to_jiffies(
+ priv->cfg->base_params->monitor_recover_period));
+ }
}
EXPORT_SYMBOL(iwl_bg_monitor_recover);
@@ -2830,7 +2595,7 @@ int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
* it will not call apm_ops.stop() to stop the DMA operation.
* Calling apm_ops.stop here to make sure we stop the DMA.
*/
- priv->cfg->ops->lib->apm_ops.stop(priv);
+ iwl_apm_stop(priv);
pci_save_state(pdev);
pci_disable_device(pdev);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 5e6ee3da6bbf..64527def059f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -88,11 +88,13 @@ struct iwl_cmd;
#define IWL_CMD(x) case x: return #x
struct iwl_hcmd_ops {
- int (*rxon_assoc)(struct iwl_priv *priv);
- int (*commit_rxon)(struct iwl_priv *priv);
- void (*set_rxon_chain)(struct iwl_priv *priv);
+ int (*rxon_assoc)(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+ int (*commit_rxon)(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+ void (*set_rxon_chain)(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx);
int (*set_tx_ant)(struct iwl_priv *priv, u8 valid_tx_ant);
void (*send_bt_config)(struct iwl_priv *priv);
+ int (*set_pan_params)(struct iwl_priv *priv);
};
struct iwl_hcmd_utils_ops {
@@ -109,14 +111,13 @@ struct iwl_hcmd_utils_ops {
__le16 fc, __le32 *tx_flags);
int (*calc_rssi)(struct iwl_priv *priv,
struct iwl_rx_phy_res *rx_resp);
- void (*request_scan)(struct iwl_priv *priv, struct ieee80211_vif *vif);
+ int (*request_scan)(struct iwl_priv *priv, struct ieee80211_vif *vif);
+ void (*post_scan)(struct iwl_priv *priv);
};
struct iwl_apm_ops {
int (*init)(struct iwl_priv *priv);
- void (*stop)(struct iwl_priv *priv);
void (*config)(struct iwl_priv *priv);
- int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src);
};
struct iwl_debugfs_ops {
@@ -128,12 +129,18 @@ struct iwl_debugfs_ops {
size_t count, loff_t *ppos);
ssize_t (*bt_stats_read)(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos);
+ ssize_t (*reply_tx_error)(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos);
};
struct iwl_temp_ops {
void (*temperature)(struct iwl_priv *priv);
- void (*set_ct_kill)(struct iwl_priv *priv);
- void (*set_calib_version)(struct iwl_priv *priv);
+};
+
+struct iwl_tt_ops {
+ bool (*lower_power_detection)(struct iwl_priv *priv);
+ u8 (*tt_power_mode)(struct iwl_priv *priv);
+ bool (*ct_kill_check)(struct iwl_priv *priv);
};
struct iwl_lib_ops {
@@ -199,7 +206,7 @@ struct iwl_lib_ops {
/* station management */
int (*manage_ibss_station)(struct iwl_priv *priv,
struct ieee80211_vif *vif, bool add);
- int (*update_bcast_station)(struct iwl_priv *priv);
+ int (*update_bcast_stations)(struct iwl_priv *priv);
/* recover from tx queue stall */
void (*recover_from_tx_stall)(unsigned long data);
/* check for plcp health */
@@ -212,6 +219,9 @@ struct iwl_lib_ops {
void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
struct iwl_debugfs_ops debugfs_ops;
+
+ /* thermal throttling */
+ struct iwl_tt_ops tt_ops;
};
struct iwl_led_ops {
@@ -220,11 +230,17 @@ struct iwl_led_ops {
int (*off)(struct iwl_priv *priv);
};
+/* NIC specific ops */
+struct iwl_nic_ops {
+ void (*additional_nic_config)(struct iwl_priv *priv);
+};
+
struct iwl_ops {
const struct iwl_lib_ops *lib;
const struct iwl_hcmd_ops *hcmd;
const struct iwl_hcmd_utils_ops *utils;
const struct iwl_led_ops *led;
+ const struct iwl_nic_ops *nic;
};
struct iwl_mod_params {
@@ -237,20 +253,12 @@ struct iwl_mod_params {
int restart_fw; /* def: 1 = restart firmware */
};
-/**
- * struct iwl_cfg
- * @fw_name_pre: Firmware filename prefix. The api version and extension
- * (.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_min: Lowest version of uCode API supported by driver.
- * @pa_type: used by 6000 series only to identify the type of Power Amplifier
+/*
* @max_ll_items: max number of OTP blocks
* @shadow_ram_support: shadow support for OTP memory
* @led_compensation: compensate on the led on/off time per HW according
* to the deviation to achieve the desired led frequency.
* The detail algorithm is described in iwl-led.c
- * @use_rts_for_aggregation: use rts/cts protection for HT traffic
* @chain_noise_num_beacons: number of beacons used to compute chain noise
* @adv_thermal_throttle: support advance thermal throttle
* @support_ct_kill_exit: support ct kill exit condition
@@ -268,6 +276,73 @@ struct iwl_mod_params {
* sensitivity calibration operation
* @chain_noise_calib_by_driver: driver has the capability to perform
* chain noise calibration operation
+*/
+struct iwl_base_params {
+ int eeprom_size;
+ int num_of_queues; /* def: HW dependent */
+ int num_of_ampdu_queues;/* def: HW dependent */
+ /* for iwl_apm_init() */
+ u32 pll_cfg_val;
+ bool set_l0s;
+ bool use_bsm;
+
+ bool use_isr_legacy;
+ const u16 max_ll_items;
+ const bool shadow_ram_support;
+ u16 led_compensation;
+ const bool broken_powersave;
+ int chain_noise_num_beacons;
+ const bool supports_idle;
+ bool adv_thermal_throttle;
+ bool support_ct_kill_exit;
+ const bool support_wimax_coexist;
+ u8 plcp_delta_threshold;
+ s32 chain_noise_scale;
+ /* timer period for monitor the driver queues */
+ u32 monitor_recover_period;
+ bool temperature_kelvin;
+ u32 max_event_log_size;
+ const bool tx_power_by_driver;
+ const bool ucode_tracing;
+ const bool sensitivity_calib_by_driver;
+ const bool chain_noise_calib_by_driver;
+};
+/*
+ * @advanced_bt_coexist: support advanced bt coexist
+ * @bt_init_traffic_load: specify initial bt traffic load
+ * @bt_prio_boost: default bt priority boost value
+ * @bt_statistics: use BT version of statistics notification
+ * @agg_time_limit: maximum number of uSec in aggregation
+ * @ampdu_factor: Maximum A-MPDU length factor
+ * @ampdu_density: Minimum A-MPDU spacing
+*/
+struct iwl_bt_params {
+ bool advanced_bt_coexist;
+ u8 bt_init_traffic_load;
+ u8 bt_prio_boost;
+ const bool bt_statistics;
+ u16 agg_time_limit;
+ u8 ampdu_factor;
+ u8 ampdu_density;
+};
+/*
+ * @use_rts_for_aggregation: use rts/cts protection for HT traffic
+*/
+struct iwl_ht_params {
+ const bool ht_greenfield_support; /* if used set to true */
+ bool use_rts_for_aggregation;
+};
+
+/**
+ * struct iwl_cfg
+ * @fw_name_pre: Firmware filename prefix. The api version and extension
+ * (.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_min: Lowest version of uCode API supported by driver.
+ * @pa_type: used by 6000 series only to identify the type of Power Amplifier
+ * @need_dc_calib: need to perform init dc calibration
+ * @need_temp_offset_calib: need to perform temperature offset calibration
* @scan_antennas: available antenna for scan operation
*
* We enable the driver to be backward compatible wrt API version. The
@@ -279,9 +354,9 @@ struct iwl_mod_params {
*
* For example,
* if (IWL_UCODE_API(priv->ucode_ver) >= 2) {
- * Driver interacts with Firmware API version >= 2.
+ * Driver interacts with Firmware API version >= 2.
* } else {
- * Driver interacts with Firmware API version 1.
+ * Driver interacts with Firmware API version 1.
* }
*
* The ideal usage of this infrastructure is to treat a new ucode API
@@ -292,53 +367,29 @@ struct iwl_mod_params {
*
*/
struct iwl_cfg {
+ /* params specific to an individual device within a device family */
const char *name;
const char *fw_name_pre;
const unsigned int ucode_api_max;
const unsigned int ucode_api_min;
+ u8 valid_tx_ant;
+ u8 valid_rx_ant;
unsigned int sku;
- int eeprom_size;
u16 eeprom_ver;
u16 eeprom_calib_ver;
- int num_of_queues; /* def: HW dependent */
- int num_of_ampdu_queues;/* def: HW dependent */
const struct iwl_ops *ops;
+ /* module based parameters which can be set from modprobe cmd */
const struct iwl_mod_params *mod_params;
- u8 valid_tx_ant;
- u8 valid_rx_ant;
-
- /* for iwl_apm_init() */
- u32 pll_cfg_val;
- bool set_l0s;
- bool use_bsm;
-
- bool use_isr_legacy;
- enum iwl_pa_type pa_type;
- const u16 max_ll_items;
- const bool shadow_ram_support;
- const bool ht_greenfield_support;
- u16 led_compensation;
- const bool broken_powersave;
- bool use_rts_for_aggregation;
- int chain_noise_num_beacons;
- const bool supports_idle;
- bool adv_thermal_throttle;
- bool support_ct_kill_exit;
- const bool support_wimax_coexist;
- u8 plcp_delta_threshold;
- s32 chain_noise_scale;
- /* timer period for monitor the driver queues */
- u32 monitor_recover_period;
- bool temperature_kelvin;
- u32 max_event_log_size;
- const bool tx_power_by_driver;
- const bool ucode_tracing;
- const bool sensitivity_calib_by_driver;
- const bool chain_noise_calib_by_driver;
+ /* params not likely to change within a device family */
+ struct iwl_base_params *base_params;
+ /* params likely to change within a device family */
+ struct iwl_ht_params *ht_params;
+ struct iwl_bt_params *bt_params;
+ enum iwl_pa_type pa_type; /* if used set to IWL_PA_SYSTEM */
+ const bool need_dc_calib; /* if used set to true */
+ const bool need_temp_offset_calib; /* if used set to true */
u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
u8 scan_tx_antennas[IEEE80211_NUM_BANDS];
- const bool need_dc_calib;
- const bool bt_statistics;
};
/***************************
@@ -347,38 +398,38 @@ struct iwl_cfg {
struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
struct ieee80211_ops *hw_ops);
-void iwl_hw_detect(struct iwl_priv *priv);
-void iwl_activate_qos(struct iwl_priv *priv);
int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params);
-void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt);
-int iwl_check_rxon_cmd(struct iwl_priv *priv);
-int iwl_full_rxon_required(struct iwl_priv *priv);
-void iwl_set_rxon_chain(struct iwl_priv *priv);
-int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
+int iwl_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);
+int iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
+ struct iwl_rxon_context *ctx);
void iwl_set_flags_for_band(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
enum ieee80211_band band,
struct ieee80211_vif *vif);
u8 iwl_get_single_channel_number(struct iwl_priv *priv,
enum ieee80211_band band);
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
-u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
- struct ieee80211_sta_ht_cap *sta_ht_inf);
+bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct ieee80211_sta_ht_cap *ht_cap);
void iwl_connection_init_rx_config(struct iwl_priv *priv,
- struct ieee80211_vif *vif);
+ struct iwl_rxon_context *ctx);
void iwl_set_rate(struct iwl_priv *priv);
int iwl_set_decrypted_flag(struct iwl_priv *priv,
struct ieee80211_hdr *hdr,
u32 decrypt_res,
struct ieee80211_rx_status *stats);
void iwl_irq_handle_error(struct iwl_priv *priv);
-int iwl_set_hw_params(struct iwl_priv *priv);
void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif);
void iwl_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changes);
-int iwl_commit_rxon(struct iwl_priv *priv);
int iwl_mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
void iwl_mac_remove_interface(struct ieee80211_hw *hw,
@@ -455,7 +506,6 @@ void iwl_rx_reply_error(struct iwl_priv *priv,
******************************************************/
void iwl_cmd_queue_free(struct iwl_priv *priv);
int iwl_rx_queue_alloc(struct iwl_priv *priv);
-void iwl_rx_handle(struct iwl_priv *priv);
void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
struct iwl_rx_queue *q);
int iwl_rx_queue_space(const struct iwl_rx_queue *q);
@@ -473,12 +523,6 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
/*****************************************************
* TX
******************************************************/
-void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
-int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
- struct iwl_tx_queue *txq,
- dma_addr_t addr, u16 len, u8 reset, u8 pad);
-int iwl_hw_tx_queue_init(struct iwl_priv *priv,
- struct iwl_tx_queue *txq);
void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
int slots_num, u32 txq_id);
@@ -494,29 +538,8 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force);
* Rate
******************************************************************************/
-int iwl_hwrate_to_plcp_idx(u32 rate_n_flags);
-
-u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv);
-
-u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
-
-static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
-{
- return BIT(ant_idx) << RATE_MCS_ANT_POS;
-}
-
-static inline u8 iwl_hw_get_rate(__le32 rate_n_flags)
-{
- return le32_to_cpu(rate_n_flags) & 0xFF;
-}
-static inline u32 iwl_hw_get_rate_n_flags(__le32 rate_n_flags)
-{
- return le32_to_cpu(rate_n_flags) & 0x1FFFF;
-}
-static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
-{
- return cpu_to_le32(flags|(u32)rate);
-}
+u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx);
/*******************************************************************************
* Scanning
@@ -524,10 +547,10 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
void iwl_init_scan_params(struct iwl_priv *priv);
int iwl_scan_cancel(struct iwl_priv *priv);
int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
+void iwl_force_scan_end(struct iwl_priv *priv);
int iwl_mac_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_scan_request *req);
-void iwl_bg_start_internal_scan(struct work_struct *work);
void iwl_internal_short_hw_scan(struct iwl_priv *priv);
int iwl_force_reset(struct iwl_priv *priv, int mode, bool external);
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
@@ -539,10 +562,8 @@ u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
enum ieee80211_band band,
struct ieee80211_vif *vif);
-void iwl_bg_scan_check(struct work_struct *data);
-void iwl_bg_abort_scan(struct work_struct *work);
-void iwl_bg_scan_completed(struct work_struct *work);
void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
+void iwl_cancel_scan_deferred_work(struct iwl_priv *priv);
/* For faster active scanning, scan will move to the next channel if fewer than
* PLCP_QUIET_THRESH packets are heard on this channel within
@@ -555,13 +576,6 @@ void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
#define IWL_SCAN_CHECK_WATCHDOG (HZ * 7)
-/*******************************************************************************
- * Calibrations - implemented in iwl-calib.c
- ******************************************************************************/
-int iwl_send_calib_results(struct iwl_priv *priv);
-int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len);
-void iwl_calib_free_results(struct iwl_priv *priv);
-
/*****************************************************
* S e n d i n g H o s t C o m m a n d s *
*****************************************************/
@@ -580,8 +594,6 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
-int iwl_send_card_state(struct iwl_priv *priv, u32 flags,
- u8 meta_flag);
/*****************************************************
* PCI *
@@ -613,12 +625,12 @@ int iwl_pci_resume(struct pci_dev *pdev);
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);
+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)
+static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
{
}
#endif
@@ -695,23 +707,22 @@ static inline int iwl_is_ready_rf(struct iwl_priv *priv)
return iwl_is_ready(priv);
}
-extern void iwl_rf_kill_ct_config(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);
-extern int iwl_send_lq_cmd(struct iwl_priv *priv,
- struct iwl_link_quality_cmd *lq, u8 flags, bool init);
void iwl_apm_stop(struct iwl_priv *priv);
int iwl_apm_init(struct iwl_priv *priv);
-void iwl_setup_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif);
-static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
+int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+static inline int iwl_send_rxon_assoc(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
{
- return priv->cfg->ops->hcmd->rxon_assoc(priv);
+ return priv->cfg->ops->hcmd->rxon_assoc(priv, ctx);
}
-static inline int iwlcore_commit_rxon(struct iwl_priv *priv)
+static inline int iwlcore_commit_rxon(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
{
- return priv->cfg->ops->hcmd->commit_rxon(priv);
+ return priv->cfg->ops->hcmd->commit_rxon(priv, ctx);
}
static inline void iwlcore_config_ap(struct iwl_priv *priv,
struct ieee80211_vif *vif)
@@ -723,4 +734,8 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
{
return priv->hw->wiphy->bands[band];
}
+
+extern bool bt_coex_active;
+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 ecf98e7ac4ed..2aa15ab13892 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -371,7 +371,8 @@
#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_3x3_HYB (0x00000000)
#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB (0x00000001)
#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002)
-#define CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6 (0x00000004)
+#define CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6 (0x00000004)
+#define CSR_GP_DRIVER_REG_BIT_6050_1x2 (0x00000008)
/* GIO Chicken Bits (PCI Express bus link power management) */
#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index a32d5d337649..8fdd4efdb1d3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -39,7 +39,6 @@
#include "iwl-debug.h"
#include "iwl-core.h"
#include "iwl-io.h"
-#include "iwl-calib.h"
/* create and remove of files */
#define DEBUGFS_ADD_FILE(name, parent, mode) do { \
@@ -359,7 +358,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
const u8 *ptr;
char *buf;
u16 eeprom_ver;
- size_t eeprom_len = priv->cfg->eeprom_size;
+ size_t eeprom_len = priv->cfg->base_params->eeprom_size;
buf_size = 4 * eeprom_len + 256;
if (eeprom_len % 16) {
@@ -470,8 +469,7 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
for (i = 0; i < supp_band->n_channels; i++)
pos += scnprintf(buf + pos, bufsz - pos,
"%d: %ddBm: BSS%s%s, %s.\n",
- ieee80211_frequency_to_channel(
- channels[i].center_freq),
+ channels[i].hw_value,
channels[i].max_power,
channels[i].flags & IEEE80211_CHAN_RADAR ?
" (IEEE 802.11h required)" : "",
@@ -494,8 +492,7 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
for (i = 0; i < supp_band->n_channels; i++)
pos += scnprintf(buf + pos, bufsz - pos,
"%d: %ddBm: BSS%s%s, %s.\n",
- ieee80211_frequency_to_channel(
- channels[i].center_freq),
+ channels[i].hw_value,
channels[i].max_power,
channels[i].flags & IEEE80211_CHAN_RADAR ?
" (IEEE 802.11h required)" : "",
@@ -580,10 +577,10 @@ static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
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 > 0) {
+ if (priv->isr_stats.sw || priv->isr_stats.hw) {
pos += scnprintf(buf + pos, bufsz - pos,
"\tLast Restarting Code: 0x%X\n",
- priv->isr_stats.sw_err);
+ priv->isr_stats.err_code);
}
#ifdef CONFIG_IWLWIFI_DEBUG
pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
@@ -648,19 +645,25 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = file->private_data;
+ struct iwl_rxon_context *ctx;
int pos = 0, i;
- char buf[256];
+ char buf[256 * NUM_IWL_RXON_CTX];
const size_t bufsz = sizeof(buf);
- for (i = 0; i < AC_NUM; i++) {
- pos += scnprintf(buf + pos, bufsz - pos,
- "\tcw_min\tcw_max\taifsn\ttxop\n");
- pos += scnprintf(buf + pos, bufsz - pos,
+ for_each_context(priv, ctx) {
+ pos += scnprintf(buf + pos, bufsz - pos, "context %d:\n",
+ ctx->ctxid);
+ for (i = 0; i < AC_NUM; i++) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tcw_min\tcw_max\taifsn\ttxop\n");
+ pos += scnprintf(buf + pos, bufsz - pos,
"AC[%d]\t%u\t%u\t%u\t%u\n", i,
- priv->qos_data.def_qos_parm.ac[i].cw_min,
- priv->qos_data.def_qos_parm.ac[i].cw_max,
- priv->qos_data.def_qos_parm.ac[i].aifsn,
- priv->qos_data.def_qos_parm.ac[i].edca_txop);
+ ctx->qos_data.def_qos_parm.ac[i].cw_min,
+ ctx->qos_data.def_qos_parm.ac[i].cw_max,
+ ctx->qos_data.def_qos_parm.ac[i].aifsn,
+ ctx->qos_data.def_qos_parm.ac[i].edca_txop);
+ }
+ pos += scnprintf(buf + pos, bufsz - pos, "\n");
}
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
@@ -735,7 +738,7 @@ static ssize_t iwl_dbgfs_disable_ht40_write(struct file *file,
return -EFAULT;
if (sscanf(buf, "%d", &ht40) != 1)
return -EFAULT;
- if (!iwl_is_associated(priv))
+ if (!iwl_is_any_associated(priv))
priv->disable_ht40 = ht40 ? true : false;
else {
IWL_ERR(priv, "Sta associated with AP - "
@@ -871,7 +874,7 @@ static ssize_t iwl_dbgfs_traffic_log_read(struct file *file,
struct iwl_rx_queue *rxq = &priv->rxq;
char *buf;
int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
- (priv->cfg->num_of_queues * 32 * 8) + 400;
+ (priv->cfg->base_params->num_of_queues * 32 * 8) + 400;
const u8 *ptr;
ssize_t ret;
@@ -970,7 +973,8 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
int pos = 0;
int cnt;
int ret;
- const size_t bufsz = sizeof(char) * 64 * priv->cfg->num_of_queues;
+ const size_t bufsz = sizeof(char) * 64 *
+ priv->cfg->base_params->num_of_queues;
if (!priv->txq) {
IWL_ERR(priv, "txq not ready\n");
@@ -1324,7 +1328,8 @@ static ssize_t iwl_dbgfs_rxon_flags_read(struct file *file,
int len = 0;
char buf[20];
- len = sprintf(buf, "0x%04X\n", le32_to_cpu(priv->active_rxon.flags));
+ len = sprintf(buf, "0x%04X\n",
+ le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.flags));
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -1337,7 +1342,7 @@ static ssize_t iwl_dbgfs_rxon_filter_flags_read(struct file *file,
char buf[20];
len = sprintf(buf, "0x%04X\n",
- le32_to_cpu(priv->active_rxon.filter_flags));
+ le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags));
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -1413,7 +1418,7 @@ static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
const size_t bufsz = sizeof(buf);
pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
- priv->cfg->plcp_delta_threshold);
+ priv->cfg->base_params->plcp_delta_threshold);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
@@ -1435,10 +1440,10 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
return -EINVAL;
if ((plcp < IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
(plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
- priv->cfg->plcp_delta_threshold =
+ priv->cfg->base_params->plcp_delta_threshold =
IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE;
else
- priv->cfg->plcp_delta_threshold = plcp;
+ priv->cfg->base_params->plcp_delta_threshold = plcp;
return count;
}
@@ -1532,6 +1537,135 @@ static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file,
user_buf, count, ppos);
}
+static ssize_t iwl_dbgfs_monitor_period_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 period;
+
+ 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", &period) != 1)
+ return -EINVAL;
+ if (period < 0 || period > IWL_MAX_MONITORING_PERIOD)
+ priv->cfg->base_params->monitor_recover_period =
+ IWL_DEF_MONITORING_PERIOD;
+ else
+ priv->cfg->base_params->monitor_recover_period = period;
+
+ if (priv->cfg->base_params->monitor_recover_period)
+ mod_timer(&priv->monitor_recover, jiffies + msecs_to_jiffies(
+ priv->cfg->base_params->monitor_recover_period));
+ else
+ del_timer_sync(&priv->monitor_recover);
+ return count;
+}
+
+static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0;
+ char buf[200];
+ const size_t bufsz = sizeof(buf);
+ ssize_t ret;
+
+ pos += scnprintf(buf + pos, bufsz - pos, "BT in %s mode\n",
+ priv->bt_full_concurrent ? "full concurrency" : "3-wire");
+ pos += scnprintf(buf + pos, bufsz - pos, "BT status: %s, "
+ "last traffic notif: %d\n",
+ priv->bt_status ? "On" : "Off", priv->notif_bt_traffic_load);
+ pos += scnprintf(buf + pos, bufsz - pos, "ch_announcement: %d, "
+ "sco_active: %d, kill_ack_mask: %x, "
+ "kill_cts_mask: %x\n",
+ priv->bt_ch_announce, priv->bt_sco_active,
+ priv->kill_ack_mask, priv->kill_cts_mask);
+
+ pos += scnprintf(buf + pos, bufsz - pos, "bluetooth traffic load: ");
+ switch (priv->bt_traffic_load) {
+ case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+ pos += scnprintf(buf + pos, bufsz - pos, "Continuous\n");
+ break;
+ case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+ pos += scnprintf(buf + pos, bufsz - pos, "High\n");
+ break;
+ case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+ pos += scnprintf(buf + pos, bufsz - pos, "Low\n");
+ break;
+ case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+ default:
+ pos += scnprintf(buf + pos, bufsz - pos, "None\n");
+ break;
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_protection_mode_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+
+ int pos = 0;
+ char buf[40];
+ const size_t bufsz = sizeof(buf);
+
+ if (priv->cfg->ht_params)
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "use %s for aggregation\n",
+ (priv->cfg->ht_params->use_rts_for_aggregation) ?
+ "rts/cts" : "cts-to-self");
+ else
+ pos += scnprintf(buf + pos, bufsz - pos, "N/A");
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_protection_mode_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 rts;
+
+ if (!priv->cfg->ht_params)
+ return -EINVAL;
+
+ 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", &rts) != 1)
+ return -EINVAL;
+ if (rts)
+ priv->cfg->ht_params->use_rts_for_aggregation = true;
+ else
+ priv->cfg->ht_params->use_rts_for_aggregation = false;
+ return count;
+}
+
+static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+
+ if (priv->cfg->ops->lib->debugfs_ops.reply_tx_error)
+ return priv->cfg->ops->lib->debugfs_ops.reply_tx_error(
+ file, user_buf, count, ppos);
+ else
+ return -ENODATA;
+}
DEBUGFS_READ_FILE_OPS(rx_statistics);
DEBUGFS_READ_FILE_OPS(tx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -1555,6 +1689,10 @@ DEBUGFS_READ_FILE_OPS(rxon_flags);
DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
DEBUGFS_WRITE_FILE_OPS(txfifo_flush);
DEBUGFS_READ_FILE_OPS(ucode_bt_stats);
+DEBUGFS_WRITE_FILE_OPS(monitor_period);
+DEBUGFS_READ_FILE_OPS(bt_traffic);
+DEBUGFS_READ_WRITE_FILE_OPS(protection_mode);
+DEBUGFS_READ_FILE_OPS(reply_tx_error);
/*
* Create the debugfs files and directories
@@ -1590,7 +1728,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
DEBUGFS_ADD_FILE(led, dir_data, S_IRUSR);
- if (!priv->cfg->broken_powersave) {
+ if (!priv->cfg->base_params->broken_powersave) {
DEBUGFS_ADD_FILE(sleep_level_override, dir_data,
S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
@@ -1615,24 +1753,29 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
if (priv->cfg->ops->lib->dev_txfifo_flush)
DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
+ DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR);
- if (priv->cfg->sensitivity_calib_by_driver)
+ if (priv->cfg->base_params->sensitivity_calib_by_driver)
DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
- if (priv->cfg->chain_noise_calib_by_driver)
+ if (priv->cfg->base_params->chain_noise_calib_by_driver)
DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
- if (priv->cfg->ucode_tracing)
+ if (priv->cfg->base_params->ucode_tracing)
DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
- if (priv->cfg->bt_statistics)
+ if (priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics)
DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
- if (priv->cfg->sensitivity_calib_by_driver)
+ DEBUGFS_ADD_FILE(monitor_period, dir_debug, S_IWUSR);
+ if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist)
+ DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
+ if (priv->cfg->base_params->sensitivity_calib_by_driver)
DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
&priv->disable_sens_cal);
- if (priv->cfg->chain_noise_calib_by_driver)
+ if (priv->cfg->base_params->chain_noise_calib_by_driver)
DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
&priv->disable_chain_noise_cal);
- if (priv->cfg->tx_power_by_driver)
+ if (priv->cfg->base_params->tx_power_by_driver)
DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf,
&priv->disable_tx_power_cal);
return 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 2e97cd2fa98a..70e07fa48405 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -47,6 +47,7 @@
#include "iwl-led.h"
#include "iwl-power.h"
#include "iwl-agn-rs.h"
+#include "iwl-agn-tt.h"
struct iwl_tx_queue;
@@ -143,6 +144,7 @@ struct iwl_queue {
/* One for each TFD */
struct iwl_tx_info {
struct sk_buff *skb;
+ struct iwl_rxon_context *ctx;
};
/**
@@ -252,10 +254,14 @@ struct iwl_channel_info {
struct iwl3945_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
};
-#define IWL_TX_FIFO_BK 0
+#define IWL_TX_FIFO_BK 0 /* shared */
#define IWL_TX_FIFO_BE 1
-#define IWL_TX_FIFO_VI 2
+#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.
@@ -264,18 +270,17 @@ struct iwl_channel_info {
#define IWL_MIN_NUM_QUEUES 10
/*
- * Queue #4 is the command queue for 3945/4965/5x00/1000/6x00,
- * the driver maps it into the appropriate device FIFO for the
- * uCode.
+ * Command queue depends on iPAN support.
*/
-#define IWL_CMD_QUEUE_NUM 4
+#define IWL_DEFAULT_CMD_QUEUE_NUM 4
+#define IWL_IPAN_CMD_QUEUE_NUM 9
-/* Power management (not Tx power) structures */
-
-enum iwl_pwr_src {
- IWL_PWR_SRC_VMAIN,
- IWL_PWR_SRC_VAUX,
-};
+/*
+ * 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
@@ -420,7 +425,7 @@ struct iwl_tid_data {
};
struct iwl_hw_key {
- enum ieee80211_key_alg alg;
+ u32 cipher;
int keylen;
u8 keyidx;
u8 key[32];
@@ -434,7 +439,13 @@ union iwl_ht_rate_supp {
};
};
-#define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3)
+#define CFG_HT_RX_AMPDU_FACTOR_8K (0x0)
+#define CFG_HT_RX_AMPDU_FACTOR_16K (0x1)
+#define CFG_HT_RX_AMPDU_FACTOR_32K (0x2)
+#define CFG_HT_RX_AMPDU_FACTOR_64K (0x3)
+#define CFG_HT_RX_AMPDU_FACTOR_DEF CFG_HT_RX_AMPDU_FACTOR_64K
+#define CFG_HT_RX_AMPDU_FACTOR_MAX CFG_HT_RX_AMPDU_FACTOR_64K
+#define CFG_HT_RX_AMPDU_FACTOR_MIN CFG_HT_RX_AMPDU_FACTOR_8K
/*
* Maximal MPDU density for TX aggregation
@@ -443,19 +454,17 @@ union iwl_ht_rate_supp {
* 6 - 8us density
* 7 - 16us density
*/
+#define CFG_HT_MPDU_DENSITY_2USEC (0x4)
#define CFG_HT_MPDU_DENSITY_4USEC (0x5)
+#define CFG_HT_MPDU_DENSITY_8USEC (0x6)
+#define CFG_HT_MPDU_DENSITY_16USEC (0x7)
#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC
+#define CFG_HT_MPDU_DENSITY_MAX CFG_HT_MPDU_DENSITY_16USEC
+#define CFG_HT_MPDU_DENSITY_MIN (0x1)
struct iwl_ht_config {
- /* self configuration data */
- bool is_ht;
- bool is_40mhz;
bool single_chain_sufficient;
enum ieee80211_smps_mode smps; /* current smps mode */
- /* BSS related data */
- u8 extension_chan_offset;
- u8 ht_protection;
- u8 non_GF_STA_present;
};
/* QoS structures */
@@ -473,12 +482,13 @@ struct iwl_qos_info {
struct iwl_station_entry {
struct iwl_addsta_cmd sta;
struct iwl_tid_data tid[MAX_TID_COUNT];
- u8 used;
+ u8 used, ctxid;
struct iwl_hw_key keyinfo;
struct iwl_link_quality_cmd *lq;
};
struct iwl_station_priv_common {
+ struct iwl_rxon_context *ctx;
u8 sta_id;
};
@@ -507,6 +517,7 @@ struct iwl_station_priv {
* space for us to put data into.
*/
struct iwl_vif_priv {
+ struct iwl_rxon_context *ctx;
u8 ibss_bssid_sta_id;
};
@@ -564,6 +575,7 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_INIT_DATA = 4,
IWL_UCODE_TLV_BOOT = 5,
IWL_UCODE_TLV_PROBE_MAX_LEN = 6, /* a u32 value */
+ IWL_UCODE_TLV_PAN = 7,
IWL_UCODE_TLV_RUNT_EVTLOG_PTR = 8,
IWL_UCODE_TLV_RUNT_EVTLOG_SIZE = 9,
IWL_UCODE_TLV_RUNT_ERRLOG_PTR = 10,
@@ -658,7 +670,6 @@ struct iwl_sensitivity_ranges {
* @rx_page_order: Rx buffer page order
* @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR
* @max_stations:
- * @bcast_sta_id:
* @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
@@ -666,6 +677,7 @@ struct iwl_sensitivity_ranges {
* @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 {
@@ -682,7 +694,6 @@ struct iwl_hw_params {
u32 rx_page_order;
u32 rx_wrt_ptr_reg;
u8 max_stations;
- u8 bcast_sta_id;
u8 ht40_channel;
u8 max_beacon_itrvl; /* in 1024 ms */
u32 max_inst_size;
@@ -693,6 +704,7 @@ struct iwl_hw_params {
/* 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;
};
@@ -713,7 +725,6 @@ struct iwl_hw_params {
*
****************************************************************************/
extern void iwl_update_chain_flags(struct iwl_priv *priv);
-extern int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
extern const u8 iwl_bcast_addr[ETH_ALEN];
extern int iwl_rxq_stop(struct iwl_priv *priv);
extern void iwl_txq_ctx_stop(struct iwl_priv *priv);
@@ -824,6 +835,7 @@ enum iwl_calib {
IWL_CALIB_TX_IQ,
IWL_CALIB_TX_IQ_PERD,
IWL_CALIB_BASE_BAND,
+ IWL_CALIB_TEMP_OFFSET,
IWL_CALIB_MAX
};
@@ -928,7 +940,7 @@ enum iwl_pa_type {
struct isr_statistics {
u32 hw;
u32 sw;
- u32 sw_err;
+ u32 err_code;
u32 sch;
u32 alive;
u32 rfkill;
@@ -940,6 +952,50 @@ struct isr_statistics {
u32 unhandled;
};
+/* reply_tx_statistics (for _agn devices) */
+struct reply_tx_error_statistics {
+ u32 pp_delay;
+ u32 pp_few_bytes;
+ u32 pp_bt_prio;
+ u32 pp_quiet_period;
+ u32 pp_calc_ttak;
+ u32 int_crossed_retry;
+ u32 short_limit;
+ u32 long_limit;
+ u32 fifo_underrun;
+ u32 drain_flow;
+ u32 rfkill_flush;
+ u32 life_expire;
+ u32 dest_ps;
+ u32 host_abort;
+ u32 bt_retry;
+ u32 sta_invalid;
+ u32 frag_drop;
+ u32 tid_disable;
+ u32 fifo_flush;
+ u32 insuff_cf_poll;
+ u32 fail_hw_drop;
+ u32 sta_color_mismatch;
+ u32 unknown;
+};
+
+/* reply_agg_tx_statistics (for _agn devices) */
+struct reply_agg_tx_error_statistics {
+ u32 underrun;
+ u32 bt_prio;
+ u32 few_bytes;
+ u32 abort;
+ u32 last_sent_ttl;
+ u32 last_sent_try;
+ u32 last_sent_bt_kill;
+ u32 scd_query;
+ u32 bad_crc32;
+ u32 response;
+ u32 dump_tx;
+ u32 delay_tx;
+ u32 unknown;
+};
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
/* management statistics */
enum iwl_mgmt_stats {
@@ -1052,7 +1108,10 @@ struct iwl_event_log {
#define IWL_DEF_MONITORING_PERIOD (1000)
#define IWL_LONG_MONITORING_PERIOD (5000)
#define IWL_ONE_HUNDRED_MSECS (100)
-#define IWL_SIXTY_SECS (60000)
+#define IWL_MAX_MONITORING_PERIOD (60000)
+
+/* BT Antenna Coupling Threshold (dB) */
+#define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35)
enum iwl_reset {
IWL_RF_RESET = 0,
@@ -1082,6 +1141,64 @@ struct iwl_force_reset {
*/
#define IWLAGN_EXT_BEACON_TIME_POS 22
+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
+ * we already removed the vif for type setting.
+ */
+ bool always_active, is_active;
+
+ enum iwl_rxon_context_id ctxid;
+
+ u32 interface_modes, exclusive_interface_modes;
+ u8 unused_devtype, ap_devtype, ibss_devtype, station_devtype;
+
+ /*
+ * We declare this const so it can only be
+ * changed via explicit cast within the
+ * routines that actually update the physical
+ * hardware.
+ */
+ const struct iwl_rxon_cmd active;
+ struct iwl_rxon_cmd staging;
+
+ struct iwl_rxon_time_cmd timing;
+
+ struct iwl_qos_info qos_data;
+
+ u8 bcast_sta_id, ap_sta_id;
+
+ u8 rxon_cmd, rxon_assoc_cmd, rxon_timing_cmd;
+ u8 qos_cmd;
+ u8 wep_key_cmd;
+
+ struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
+ u8 key_mapping_keys;
+
+ __le32 station_flags;
+
+ struct {
+ bool non_gf_sta_present;
+ u8 protection;
+ bool enabled, is_40mhz;
+ u8 extension_chan_offset;
+ } ht;
+};
+
struct iwl_priv {
/* ieee device used by generic ieee processing code */
@@ -1110,6 +1227,9 @@ struct iwl_priv {
u32 ucode_beacon_time;
int missed_beacon_threshold;
+ /* track IBSS manager (last beacon) status */
+ u32 ibss_manager;
+
/* storing the jiffies when the plcp error rate is received */
unsigned long plcp_jiffies;
@@ -1155,6 +1275,15 @@ struct iwl_priv {
u32 hw_wa_rev;
u8 rev_id;
+ /* microcode/device supports multiple contexts */
+ u8 valid_contexts;
+
+ /* command queue number */
+ u8 cmd_queue;
+
+ /* max number of station keys */
+ u8 sta_key_max_num;
+
/* EEPROM MAC addresses */
struct mac_address addresses[2];
@@ -1172,15 +1301,7 @@ struct iwl_priv {
u8 ucode_write_complete; /* the image write is complete */
char firmware_name[25];
-
- struct iwl_rxon_time_cmd rxon_timing;
-
- /* We declare this const so it can only be
- * changed via explicit cast within the
- * routines that actually update the physical
- * hardware */
- const struct iwl_rxon_cmd active_rxon;
- struct iwl_rxon_cmd staging_rxon;
+ struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
struct iwl_switch_rxon switch_rxon;
@@ -1242,8 +1363,6 @@ struct iwl_priv {
spinlock_t sta_lock;
int num_stations;
struct iwl_station_entry stations[IWL_STATION_COUNT];
- struct iwl_wep_key wep_keys[WEP_KEYS_MAX]; /* protected by mutex */
- u8 key_mapping_key;
unsigned long ucode_key_table;
/* queue refcounts */
@@ -1264,11 +1383,8 @@ struct iwl_priv {
enum nl80211_iftype iw_mode;
- struct sk_buff *ibss_beacon;
-
/* Last Rx'd beacon timestamp */
u64 timestamp;
- struct ieee80211_vif *vif;
union {
#if defined(CONFIG_IWL3945) || defined(CONFIG_IWL3945_MODULE)
@@ -1336,6 +1452,9 @@ struct iwl_priv {
struct iwl_notif_statistics statistics;
struct iwl_bt_notif_statistics statistics_bt;
+ /* counts reply_tx error */
+ struct reply_tx_error_statistics reply_tx_stats;
+ struct reply_agg_tx_error_statistics reply_agg_tx_stats;
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct iwl_notif_statistics accum_statistics;
struct iwl_notif_statistics delta_statistics;
@@ -1348,24 +1467,45 @@ struct iwl_priv {
#endif
};
+ /* bt coex */
+ u8 bt_status;
+ u8 bt_traffic_load, notif_bt_traffic_load;
+ bool bt_ch_announce;
+ bool bt_sco_active;
+ bool bt_full_concurrent;
+ bool bt_ant_couple_ok;
+ __le32 kill_ack_mask;
+ __le32 kill_cts_mask;
+ __le16 bt_valid;
+ u16 bt_on_thresh;
+ u16 bt_duration;
+ u16 dynamic_frag_thresh;
+ u16 dynamic_agg_thresh;
+ u8 bt_ci_compliance;
+ struct work_struct bt_traffic_change_work;
+
struct iwl_hw_params hw_params;
u32 inta_mask;
- struct iwl_qos_info qos_data;
-
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;
+ struct iwl_rxon_context *beacon_ctx;
+ struct sk_buff *beacon_skb;
+
struct work_struct tt_work;
struct work_struct ct_enter;
struct work_struct ct_exit;
struct work_struct start_internal_scan;
struct work_struct tx_flush;
+ struct work_struct bt_full_concurrency;
+ struct work_struct bt_runtime_config;
struct tasklet_struct irq_tasklet;
@@ -1419,7 +1559,6 @@ static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id)
}
#ifdef CONFIG_IWLWIFI_DEBUG
-const char *iwl_get_tx_fail_reason(u32 status);
/*
* iwl_get_debug_level: Return active debug level for device
*
@@ -1435,8 +1574,6 @@ static inline u32 iwl_get_debug_level(struct iwl_priv *priv)
return iwl_debug_level;
}
#else
-static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; }
-
static inline u32 iwl_get_debug_level(struct iwl_priv *priv)
{
return iwl_debug_level;
@@ -1453,10 +1590,34 @@ static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv,
return NULL;
}
+static inline struct iwl_rxon_context *
+iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif)
+{
+ struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+
+ return vif_priv->ctx;
+}
+
+#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))
+
+static inline int iwl_is_associated(struct iwl_priv *priv,
+ enum iwl_rxon_context_id ctxid)
+{
+ return (priv->contexts[ctxid].active.filter_flags &
+ RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+}
+
+static inline int iwl_is_any_associated(struct iwl_priv *priv)
+{
+ return iwl_is_associated(priv, IWL_RXON_CTX_BSS);
+}
-static inline int iwl_is_associated(struct iwl_priv *priv)
+static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx)
{
- return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+ return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
}
static inline int is_channel_valid(const struct iwl_channel_info *ch_info)
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index a45d02e555cf..87cd10ff285d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -136,85 +136,13 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */
36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
};
-/**
- * struct iwl_txpwr_section: eeprom section information
- * @offset: indirect address into eeprom image
- * @count: number of "struct iwl_eeprom_enhanced_txpwr" in this section
- * @band: band type for the section
- * @is_common - true: common section, false: channel section
- * @is_cck - true: cck section, false: not cck section
- * @is_ht_40 - true: all channel in the section are HT40 channel,
- * false: legacy or HT 20 MHz
- * ignore if it is common section
- * @iwl_eeprom_section_channel: channel array in the section,
- * ignore if common section
- */
-struct iwl_txpwr_section {
- u32 offset;
- u8 count;
- enum ieee80211_band band;
- bool is_common;
- bool is_cck;
- bool is_ht40;
- u8 iwl_eeprom_section_channel[EEPROM_MAX_TXPOWER_SECTION_ELEMENTS];
-};
-
-/**
- * section 1 - 3 are regulatory tx power apply to all channels based on
- * modulation: CCK, OFDM
- * Band: 2.4GHz, 5.2GHz
- * section 4 - 10 are regulatory tx power apply to specified channels
- * For example:
- * 1L - Channel 1 Legacy
- * 1HT - Channel 1 HT
- * (1,+1) - Channel 1 HT40 "_above_"
- *
- * Section 1: all CCK channels
- * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40) channels
- * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels
- * Section 4: 2.4 GHz 20MHz channels: 1L, 1HT, 2L, 2HT, 10L, 10HT, 11L, 11HT
- * Section 5: 2.4 GHz 40MHz channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1)
- * Section 6: 5.2 GHz 20MHz channels: 36L, 64L, 100L, 36HT, 64HT, 100HT
- * Section 7: 5.2 GHz 40MHz channels: (36,+1) (60,+1) (100,+1)
- * Section 8: 2.4 GHz channel: 13L, 13HT
- * Section 9: 2.4 GHz channel: 140L, 140HT
- * Section 10: 2.4 GHz 40MHz channels: (132,+1) (44,+1)
- *
- */
-static const struct iwl_txpwr_section enhinfo[] = {
- { EEPROM_LB_CCK_20_COMMON, 1, IEEE80211_BAND_2GHZ, true, true, false },
- { EEPROM_LB_OFDM_COMMON, 3, IEEE80211_BAND_2GHZ, true, false, false },
- { EEPROM_HB_OFDM_COMMON, 3, IEEE80211_BAND_5GHZ, true, false, false },
- { EEPROM_LB_OFDM_20_BAND, 8, IEEE80211_BAND_2GHZ,
- false, false, false,
- {1, 1, 2, 2, 10, 10, 11, 11 } },
- { EEPROM_LB_OFDM_HT40_BAND, 5, IEEE80211_BAND_2GHZ,
- false, false, true,
- { 1, 2, 6, 7, 9 } },
- { EEPROM_HB_OFDM_20_BAND, 6, IEEE80211_BAND_5GHZ,
- false, false, false,
- { 36, 64, 100, 36, 64, 100 } },
- { EEPROM_HB_OFDM_HT40_BAND, 3, IEEE80211_BAND_5GHZ,
- false, false, true,
- { 36, 60, 100 } },
- { EEPROM_LB_OFDM_20_CHANNEL_13, 2, IEEE80211_BAND_2GHZ,
- false, false, false,
- { 13, 13 } },
- { EEPROM_HB_OFDM_20_CHANNEL_140, 2, IEEE80211_BAND_5GHZ,
- false, false, false,
- { 140, 140 } },
- { EEPROM_HB_OFDM_HT40_BAND_1, 2, IEEE80211_BAND_5GHZ,
- false, false, true,
- { 132, 44 } },
-};
-
/******************************************************************************
*
* EEPROM related functions
*
******************************************************************************/
-int iwlcore_eeprom_verify_signature(struct iwl_priv *priv)
+static int iwl_eeprom_verify_signature(struct iwl_priv *priv)
{
u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
int ret = 0;
@@ -246,7 +174,6 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv)
}
return ret;
}
-EXPORT_SYMBOL(iwlcore_eeprom_verify_signature);
static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode)
{
@@ -290,49 +217,9 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv)
return nvm_type;
}
-/*
- * The device's EEPROM semaphore prevents conflicts between driver and uCode
- * when accessing the EEPROM; each access is a series of pulses to/from the
- * EEPROM chip, not a single event, so even reads could conflict if they
- * weren't arbitrated by the semaphore.
- */
-int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv)
-{
- u16 count;
- int ret;
-
- for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
- /* Request semaphore */
- iwl_set_bit(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,
- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
- EEPROM_SEM_TIMEOUT);
- if (ret >= 0) {
- IWL_DEBUG_IO(priv, "Acquired semaphore after %d tries.\n",
- count+1);
- return ret;
- }
- }
-
- return ret;
-}
-EXPORT_SYMBOL(iwlcore_eeprom_acquire_semaphore);
-
-void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv)
-{
- iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
-
-}
-EXPORT_SYMBOL(iwlcore_eeprom_release_semaphore);
-
const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
{
- BUG_ON(offset >= priv->cfg->eeprom_size);
+ BUG_ON(offset >= priv->cfg->base_params->eeprom_size);
return &priv->eeprom[offset];
}
EXPORT_SYMBOL(iwlcore_eeprom_query_addr);
@@ -364,7 +251,7 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
* CSR auto clock gate disable bit -
* this is only applicable for HW with OTP shadow RAM
*/
- if (priv->cfg->shadow_ram_support)
+ if (priv->cfg->base_params->shadow_ram_support)
iwl_set_bit(priv, CSR_DBG_LINK_PWR_MGMT_REG,
CSR_RESET_LINK_PWR_MGMT_DISABLED);
}
@@ -484,13 +371,27 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
}
/* more in the link list, continue */
usedblocks++;
- } while (usedblocks <= priv->cfg->max_ll_items);
+ } while (usedblocks <= priv->cfg->base_params->max_ll_items);
/* OTP has no valid blocks */
IWL_DEBUG_INFO(priv, "OTP has no valid blocks\n");
return -EINVAL;
}
+const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
+{
+ return priv->cfg->ops->lib->eeprom_ops.query_addr(priv, offset);
+}
+EXPORT_SYMBOL(iwl_eeprom_query_addr);
+
+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);
+}
+EXPORT_SYMBOL(iwl_eeprom_query16);
+
/**
* iwl_eeprom_init - read EEPROM contents
*
@@ -512,8 +413,8 @@ int iwl_eeprom_init(struct iwl_priv *priv)
if (priv->nvm_device_type == -ENOENT)
return -ENOENT;
/* allocate eeprom */
- IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size);
- sz = priv->cfg->eeprom_size;
+ sz = priv->cfg->base_params->eeprom_size;
+ IWL_DEBUG_INFO(priv, "NVM size = %d\n", sz);
priv->eeprom = kzalloc(sz, GFP_KERNEL);
if (!priv->eeprom) {
ret = -ENOMEM;
@@ -523,7 +424,7 @@ int iwl_eeprom_init(struct iwl_priv *priv)
priv->cfg->ops->lib->apm_ops.init(priv);
- ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv);
+ ret = iwl_eeprom_verify_signature(priv);
if (ret < 0) {
IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
ret = -ENOENT;
@@ -554,7 +455,7 @@ int iwl_eeprom_init(struct iwl_priv *priv)
CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
/* traversing the linked list if no shadow ram supported */
- if (!priv->cfg->shadow_ram_support) {
+ if (!priv->cfg->base_params->shadow_ram_support) {
if (iwl_find_otp_image(priv, &validblockaddr)) {
ret = -ENOENT;
goto done;
@@ -604,7 +505,7 @@ err:
if (ret)
iwl_eeprom_free(priv);
/* Reset chip to save power until we load uCode during "up". */
- priv->cfg->ops->lib->apm_ops.stop(priv);
+ iwl_apm_stop(priv);
alloc_err:
return ret;
}
@@ -617,53 +518,6 @@ void iwl_eeprom_free(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_eeprom_free);
-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 = priv->cfg->ops->lib->eeprom_ops.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;
-
-}
-EXPORT_SYMBOL(iwl_eeprom_check_version);
-
-const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
-{
- return priv->cfg->ops->lib->eeprom_ops.query_addr(priv, offset);
-}
-EXPORT_SYMBOL(iwl_eeprom_query_addr);
-
-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);
-}
-EXPORT_SYMBOL(iwl_eeprom_query16);
-
-void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac)
-{
- const u8 *addr = priv->cfg->ops->lib->eeprom_ops.query_addr(priv,
- EEPROM_MAC_ADDRESS);
- memcpy(mac, addr, ETH_ALEN);
-}
-EXPORT_SYMBOL(iwl_eeprom_get_mac);
-
static void iwl_init_band_reference(const struct iwl_priv *priv,
int eep_band, int *eeprom_ch_count,
const struct iwl_eeprom_channel **eeprom_ch_info,
@@ -722,7 +576,6 @@ static void iwl_init_band_reference(const struct iwl_priv *priv,
#define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \
? # x " " : "")
-
/**
* iwl_mod_ht40_chan_info - Copy ht40 channel info into driver's priv.
*
@@ -766,205 +619,6 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv,
return 0;
}
-/**
- * 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) */
-
- IWL_DEBUG_INFO(priv, "%d - "
- "chain_a: %d dB chain_b: %d dB "
- "chain_c: %d dB mimo2: %d dB mimo3: %d dB\n",
- element,
- enhanced_txpower[element].chain_a_max >> 1,
- enhanced_txpower[element].chain_b_max >> 1,
- enhanced_txpower[element].chain_c_max >> 1,
- enhanced_txpower[element].mimo2_max >> 1,
- enhanced_txpower[element].mimo3_max >> 1);
- /* 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);
-}
-
-/**
- * iwl_update_common_txpower: update channel tx power
- * update tx power per band based on EEPROM enhanced tx power info.
- */
-static s8 iwl_update_common_txpower(struct iwl_priv *priv,
- struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
- int section, int element, s8 *max_txpower_in_half_dbm)
-{
- struct iwl_channel_info *ch_info;
- int ch;
- bool is_ht40 = false;
- s8 max_txpower_avg; /* (dBm) */
-
- /* it is common section, contain all type (Legacy, HT and HT40)
- * based on the element in the section to determine
- * is it HT 40 or not
- */
- if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX)
- is_ht40 = true;
- max_txpower_avg =
- iwl_get_max_txpower_avg(priv, enhanced_txpower,
- element, max_txpower_in_half_dbm);
-
- ch_info = priv->channel_info;
-
- for (ch = 0; ch < priv->channel_count; ch++) {
- /* find matching band and update tx power if needed */
- if ((ch_info->band == enhinfo[section].band) &&
- (ch_info->max_power_avg < max_txpower_avg) &&
- (!is_ht40)) {
- /* Update regulatory-based run-time data */
- ch_info->max_power_avg = ch_info->curr_txpow =
- max_txpower_avg;
- ch_info->scan_power = max_txpower_avg;
- }
- if ((ch_info->band == enhinfo[section].band) && is_ht40 &&
- (ch_info->ht40_max_power_avg < max_txpower_avg)) {
- /* Update regulatory-based run-time data */
- ch_info->ht40_max_power_avg = max_txpower_avg;
- }
- ch_info++;
- }
- return max_txpower_avg;
-}
-
-/**
- * iwl_update_channel_txpower: update channel tx power
- * update channel tx power based on EEPROM enhanced tx power info.
- */
-static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
- struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
- int section, int element, s8 *max_txpower_in_half_dbm)
-{
- struct iwl_channel_info *ch_info;
- int ch;
- u8 channel;
- s8 max_txpower_avg; /* (dBm) */
-
- channel = enhinfo[section].iwl_eeprom_section_channel[element];
- max_txpower_avg =
- iwl_get_max_txpower_avg(priv, enhanced_txpower,
- element, max_txpower_in_half_dbm);
-
- ch_info = priv->channel_info;
- for (ch = 0; ch < priv->channel_count; ch++) {
- /* find matching channel and update tx power if needed */
- if (ch_info->channel == channel) {
- if ((ch_info->max_power_avg < max_txpower_avg) &&
- (!enhinfo[section].is_ht40)) {
- /* Update regulatory-based run-time data */
- ch_info->max_power_avg = max_txpower_avg;
- ch_info->curr_txpow = max_txpower_avg;
- ch_info->scan_power = max_txpower_avg;
- }
- if ((enhinfo[section].is_ht40) &&
- (ch_info->ht40_max_power_avg < max_txpower_avg)) {
- /* Update regulatory-based run-time data */
- ch_info->ht40_max_power_avg = max_txpower_avg;
- }
- break;
- }
- ch_info++;
- }
- return max_txpower_avg;
-}
-
-/**
- * iwlcore_eeprom_enhanced_txpower: process enhanced tx power info
- */
-void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
-{
- int eeprom_section_count = 0;
- int section, element;
- struct iwl_eeprom_enhanced_txpwr *enhanced_txpower;
- u32 offset;
- s8 max_txpower_avg; /* (dBm) */
- s8 max_txpower_in_half_dbm; /* (half-dBm) */
-
- /* Loop through all the sections
- * adjust bands and channel's max tx power
- * Set the tx_power_user_lmt to the highest power
- * supported by any channels and chains
- */
- for (section = 0; section < ARRAY_SIZE(enhinfo); section++) {
- eeprom_section_count = enhinfo[section].count;
- offset = enhinfo[section].offset;
- enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *)
- iwl_eeprom_query_addr(priv, offset);
-
- /*
- * check for valid entry -
- * different version of EEPROM might contain different set
- * of enhanced tx power table
- * always check for valid entry before process
- * the information
- */
- if (!enhanced_txpower->common || enhanced_txpower->reserved)
- continue;
-
- for (element = 0; element < eeprom_section_count; element++) {
- if (enhinfo[section].is_common)
- max_txpower_avg =
- iwl_update_common_txpower(priv,
- enhanced_txpower, section,
- element,
- &max_txpower_in_half_dbm);
- else
- max_txpower_avg =
- iwl_update_channel_txpower(priv,
- enhanced_txpower, section,
- element,
- &max_txpower_in_half_dbm);
-
- /* Update the tx_power_user_lmt to the highest power
- * supported by any channel */
- if (max_txpower_avg > priv->tx_power_user_lmt)
- priv->tx_power_user_lmt = max_txpower_avg;
-
- /*
- * Update the tx_power_lmt_in_half_dbm to
- * the highest power supported by any channel
- */
- if (max_txpower_in_half_dbm >
- priv->tx_power_lmt_in_half_dbm)
- priv->tx_power_lmt_in_half_dbm =
- max_txpower_in_half_dbm;
- }
- }
-}
-EXPORT_SYMBOL(iwlcore_eeprom_enhanced_txpower);
-
#define CHECK_AND_PRINT_I(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
? # x " " : "")
@@ -1162,4 +816,3 @@ const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
return NULL;
}
EXPORT_SYMBOL(iwl_get_channel_info);
-
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index a4772aff51fe..d9b590625ae4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -493,7 +493,6 @@ struct iwl_eeprom_calib_info {
struct iwl_eeprom_ops {
const u32 regulatory_bands[7];
- int (*verify_signature) (struct iwl_priv *priv);
int (*acquire_semaphore) (struct iwl_priv *priv);
void (*release_semaphore) (struct iwl_priv *priv);
u16 (*calib_version) (struct iwl_priv *priv);
@@ -502,18 +501,13 @@ struct iwl_eeprom_ops {
};
-void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac);
int iwl_eeprom_init(struct iwl_priv *priv);
void iwl_eeprom_free(struct iwl_priv *priv);
int iwl_eeprom_check_version(struct iwl_priv *priv);
const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset);
-u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset);
-
int iwlcore_eeprom_verify_signature(struct iwl_priv *priv);
-int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv);
-void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv);
+u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset);
const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset);
-void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv);
int iwl_init_channel_map(struct iwl_priv *priv);
void iwl_free_channel_map(struct iwl_priv *priv);
const struct iwl_channel_info *iwl_get_channel_info(
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 258d059ef41f..c373b53babea 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -97,6 +97,17 @@ const char *get_cmd_string(u8 cmd)
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);
default:
return "UNKNOWN";
@@ -229,7 +240,7 @@ cancel:
* in later, it will possibly set an invalid
* address (cmd->meta.source).
*/
- priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_idx].flags &=
+ priv->txq[priv->cmd_queue].meta[cmd_idx].flags &=
~CMD_WANT_SKB;
}
fail:
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index 621abe3c5afc..1aaef70deaec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -44,11 +44,6 @@ static inline struct ieee80211_conf *ieee80211_get_hw_conf(
return &hw->conf;
}
-static inline int iwl_check_bits(unsigned long field, unsigned long mask)
-{
- return ((field & mask) == mask) ? 1 : 0;
-}
-
static inline unsigned long elapsed_jiffies(unsigned long start,
unsigned long end)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index db5bfcb036ca..86c2b6fed0c6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -108,13 +108,13 @@ static int iwl_led_pattern(struct iwl_priv *priv, unsigned int idx)
BUG_ON(idx > IWL_MAX_BLINK_TBL);
IWL_DEBUG_LED(priv, "Led blink time compensation= %u\n",
- priv->cfg->led_compensation);
+ priv->cfg->base_params->led_compensation);
led_cmd.on =
iwl_blink_compensation(priv, blink_tbl[idx].on_time,
- priv->cfg->led_compensation);
+ priv->cfg->base_params->led_compensation);
led_cmd.off =
iwl_blink_compensation(priv, blink_tbl[idx].off_time,
- priv->cfg->led_compensation);
+ priv->cfg->base_params->led_compensation);
return priv->cfg->ops->led->cmd(priv, &led_cmd);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index cda6a94d6cc9..49d7788937a9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -192,47 +192,6 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
}
-/* default Thermal Throttling transaction table
- * Current state | Throttling Down | Throttling Up
- *=============================================================================
- * Condition Nxt State Condition Nxt State Condition Nxt State
- *-----------------------------------------------------------------------------
- * IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A
- * IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0
- * IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1
- * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
- *=============================================================================
- */
-static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
- {IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
- {IWL_TI_1, 105, CT_KILL_THRESHOLD - 1},
- {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
-};
-static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
- {IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
- {IWL_TI_2, 110, CT_KILL_THRESHOLD - 1},
- {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
-};
-static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
- {IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
- {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX},
- {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
-};
-static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
- {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
- {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
- {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
-};
-
-/* Advance Thermal Throttling default restriction table */
-static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
- {IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true },
- {IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true },
- {IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false },
- {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false }
-};
-
-
static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv,
struct iwl_powertable_cmd *cmd)
{
@@ -308,7 +267,6 @@ static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
int iwl_power_update_mode(struct iwl_priv *priv, bool force)
{
int ret = 0;
- struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
bool update_chains;
struct iwl_powertable_cmd cmd;
@@ -320,14 +278,18 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
dtimper = priv->hw->conf.ps_dtim_period ?: 1;
- if (priv->cfg->broken_powersave)
+ if (priv->cfg->base_params->broken_powersave)
iwl_power_sleep_cam_cmd(priv, &cmd);
- else if (priv->cfg->supports_idle &&
+ else if (priv->cfg->base_params->supports_idle &&
priv->hw->conf.flags & IEEE80211_CONF_IDLE)
iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20);
- else if (tt->state >= IWL_TI_1)
- iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper);
- else if (!enabled)
+ else if (priv->cfg->ops->lib->tt_ops.lower_power_detection &&
+ priv->cfg->ops->lib->tt_ops.tt_power_mode &&
+ priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) {
+ /* in thermal throttling low power state */
+ iwl_static_sleep_cmd(priv, &cmd,
+ priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper);
+ } else if (!enabled)
iwl_power_sleep_cam_cmd(priv, &cmd);
else if (priv->power_data.debug_sleep_level_override >= 0)
iwl_static_sleep_cmd(priv, &cmd,
@@ -367,592 +329,6 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
}
EXPORT_SYMBOL(iwl_power_update_mode);
-bool iwl_ht_enabled(struct iwl_priv *priv)
-{
- struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
- struct iwl_tt_restriction *restriction;
-
- if (!priv->thermal_throttle.advanced_tt)
- return true;
- restriction = tt->restriction + tt->state;
- return restriction->is_ht;
-}
-EXPORT_SYMBOL(iwl_ht_enabled);
-
-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->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;
- else
- within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
- CT_KILL_THRESHOLD) ? true : false;
- return within_margin;
-}
-
-enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
-{
- struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
- struct iwl_tt_restriction *restriction;
-
- if (!priv->thermal_throttle.advanced_tt)
- return IWL_ANT_OK_MULTI;
- restriction = tt->restriction + tt->state;
- return restriction->tx_stream;
-}
-EXPORT_SYMBOL(iwl_tx_ant_restriction);
-
-enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
-{
- struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
- struct iwl_tt_restriction *restriction;
-
- if (!priv->thermal_throttle.advanced_tt)
- return IWL_ANT_OK_MULTI;
- restriction = tt->restriction + tt->state;
- return restriction->rx_stream;
-}
-
-#define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */
-#define CT_KILL_WAITING_DURATION (300) /* 300ms duration */
-
-/*
- * toggle the bit to wake up uCode and check the temperature
- * if the temperature is below CT, uCode will stay awake and send card
- * state notification with CT_KILL bit clear to inform Thermal Throttling
- * Management to change state. Otherwise, uCode will go back to sleep
- * without doing anything, driver should continue the 5 seconds timer
- * to wake up uCode for temperature check until temperature drop below CT
- */
-static void iwl_tt_check_exit_ct_kill(unsigned long data)
-{
- struct iwl_priv *priv = (struct iwl_priv *)data;
- struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
- unsigned long flags;
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- if (tt->state == IWL_TI_CT_KILL) {
- if (priv->thermal_throttle.ct_kill_toggle) {
- iwl_write32(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,
- 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);
-
- /* Reschedule the ct_kill timer to occur in
- * CT_KILL_EXIT_DURATION seconds to ensure we get a
- * thermal update */
- IWL_DEBUG_POWER(priv, "schedule ct_kill exit timer\n");
- mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies +
- CT_KILL_EXIT_DURATION * HZ);
- }
-}
-
-static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
- bool stop)
-{
- if (stop) {
- IWL_DEBUG_POWER(priv, "Stop all queues\n");
- if (priv->mac80211_registered)
- ieee80211_stop_queues(priv->hw);
- IWL_DEBUG_POWER(priv,
- "Schedule 5 seconds CT_KILL Timer\n");
- mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies +
- CT_KILL_EXIT_DURATION * HZ);
- } else {
- IWL_DEBUG_POWER(priv, "Wake all queues\n");
- if (priv->mac80211_registered)
- ieee80211_wake_queues(priv->hw);
- }
-}
-
-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))
- return;
-
- /* temperature timer expired, ready to go into CT_KILL state */
- if (tt->state != IWL_TI_CT_KILL) {
- IWL_DEBUG_POWER(priv, "entering CT_KILL state when temperature timer expired\n");
- tt->state = IWL_TI_CT_KILL;
- set_bit(STATUS_CT_KILL, &priv->status);
- iwl_perform_ct_kill_task(priv, true);
- }
-}
-
-static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
-{
- IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n");
- /* make request to retrieve statistics information */
- iwl_send_statistics_request(priv, CMD_SYNC, false);
- /* Reschedule the ct_kill wait timer */
- mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
- jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
-}
-
-#define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY)
-#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100)
-#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90)
-
-/*
- * Legacy thermal throttling
- * 1) Avoid NIC destruction due to high temperatures
- * Chip will identify dangerously high temperatures that can
- * harm the device and will power down
- * 2) Avoid the NIC power down due to high temperature
- * Throttle early enough to lower the power consumption before
- * drastic steps are needed
- */
-static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
-{
- struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
- enum iwl_tt_state old_state;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- if ((tt->tt_previous_temp) &&
- (temp > tt->tt_previous_temp) &&
- ((temp - tt->tt_previous_temp) >
- IWL_TT_INCREASE_MARGIN)) {
- IWL_DEBUG_POWER(priv,
- "Temperature increase %d degree Celsius\n",
- (temp - tt->tt_previous_temp));
- }
-#endif
- old_state = tt->state;
- /* in Celsius */
- if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
- tt->state = IWL_TI_CT_KILL;
- else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
- tt->state = IWL_TI_2;
- else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
- tt->state = IWL_TI_1;
- else
- tt->state = IWL_TI_0;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- tt->tt_previous_temp = temp;
-#endif
- /* stop ct_kill_waiting_tm timer */
- del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
- if (tt->state != old_state) {
- switch (tt->state) {
- case IWL_TI_0:
- /*
- * When the system is ready to go back to IWL_TI_0
- * we only have to call iwl_power_update_mode() to
- * do so.
- */
- break;
- case IWL_TI_1:
- tt->tt_power_mode = IWL_POWER_INDEX_3;
- break;
- case IWL_TI_2:
- tt->tt_power_mode = IWL_POWER_INDEX_4;
- break;
- default:
- tt->tt_power_mode = IWL_POWER_INDEX_5;
- break;
- }
- mutex_lock(&priv->mutex);
- if (old_state == IWL_TI_CT_KILL)
- clear_bit(STATUS_CT_KILL, &priv->status);
- if (tt->state != IWL_TI_CT_KILL &&
- iwl_power_update_mode(priv, true)) {
- /* TT state not updated
- * try again during next temperature read
- */
- if (old_state == IWL_TI_CT_KILL)
- set_bit(STATUS_CT_KILL, &priv->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);
- iwl_perform_ct_kill_task(priv, true);
- } else {
- iwl_prepare_ct_kill_task(priv);
- tt->state = old_state;
- }
- } else if (old_state == IWL_TI_CT_KILL &&
- tt->state != IWL_TI_CT_KILL)
- iwl_perform_ct_kill_task(priv, false);
- IWL_DEBUG_POWER(priv, "Temperature state changed %u\n",
- tt->state);
- IWL_DEBUG_POWER(priv, "Power Index change to %u\n",
- tt->tt_power_mode);
- }
- mutex_unlock(&priv->mutex);
- }
-}
-
-/*
- * Advance thermal throttling
- * 1) Avoid NIC destruction due to high temperatures
- * Chip will identify dangerously high temperatures that can
- * harm the device and will power down
- * 2) Avoid the NIC power down due to high temperature
- * Throttle early enough to lower the power consumption before
- * drastic steps are needed
- * Actions include relaxing the power down sleep thresholds and
- * decreasing the number of TX streams
- * 3) Avoid throughput performance impact as much as possible
- *
- *=============================================================================
- * Condition Nxt State Condition Nxt State Condition Nxt State
- *-----------------------------------------------------------------------------
- * IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A
- * IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0
- * IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1
- * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
- *=============================================================================
- */
-static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
-{
- struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
- int i;
- bool changed = false;
- enum iwl_tt_state old_state;
- struct iwl_tt_trans *transaction;
-
- old_state = tt->state;
- for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
- /* based on the current TT state,
- * find the curresponding transaction table
- * each table has (IWL_TI_STATE_MAX - 1) entries
- * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
- * will advance to the correct table.
- * then based on the current temperature
- * find the next state need to transaction to
- * go through all the possible (IWL_TI_STATE_MAX - 1) entries
- * in the current table to see if transaction is needed
- */
- transaction = tt->transaction +
- ((old_state * (IWL_TI_STATE_MAX - 1)) + i);
- if (temp >= transaction->tt_low &&
- temp <= transaction->tt_high) {
-#ifdef CONFIG_IWLWIFI_DEBUG
- if ((tt->tt_previous_temp) &&
- (temp > tt->tt_previous_temp) &&
- ((temp - tt->tt_previous_temp) >
- IWL_TT_INCREASE_MARGIN)) {
- IWL_DEBUG_POWER(priv,
- "Temperature increase %d "
- "degree Celsius\n",
- (temp - tt->tt_previous_temp));
- }
- tt->tt_previous_temp = temp;
-#endif
- if (old_state !=
- transaction->next_state) {
- changed = true;
- tt->state =
- transaction->next_state;
- }
- break;
- }
- }
- /* stop ct_kill_waiting_tm timer */
- del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
- if (changed) {
- struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
-
- if (tt->state >= IWL_TI_1) {
- /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
- tt->tt_power_mode = IWL_POWER_INDEX_5;
- if (!iwl_ht_enabled(priv))
- /* disable HT */
- rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
- RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
- RXON_FLG_HT40_PROT_MSK |
- RXON_FLG_HT_PROT_MSK);
- else {
- /* check HT capability and set
- * according to the system HT capability
- * in case get disabled before */
- iwl_set_rxon_ht(priv, &priv->current_ht_config);
- }
-
- } else {
- /*
- * restore system power setting -- it will be
- * recalculated automatically.
- */
-
- /* check HT capability and set
- * according to the system HT capability
- * in case get disabled before */
- iwl_set_rxon_ht(priv, &priv->current_ht_config);
- }
- mutex_lock(&priv->mutex);
- if (old_state == IWL_TI_CT_KILL)
- clear_bit(STATUS_CT_KILL, &priv->status);
- if (tt->state != IWL_TI_CT_KILL &&
- iwl_power_update_mode(priv, true)) {
- /* TT state not updated
- * try again during next temperature read
- */
- 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);
- tt->state = old_state;
- } else {
- IWL_DEBUG_POWER(priv,
- "Thermal Throttling to new state: %u\n",
- tt->state);
- if (old_state != IWL_TI_CT_KILL &&
- tt->state == IWL_TI_CT_KILL) {
- if (force) {
- IWL_DEBUG_POWER(priv,
- "Enter IWL_TI_CT_KILL\n");
- set_bit(STATUS_CT_KILL, &priv->status);
- iwl_perform_ct_kill_task(priv, true);
- } else {
- iwl_prepare_ct_kill_task(priv);
- tt->state = old_state;
- }
- } else if (old_state == IWL_TI_CT_KILL &&
- tt->state != IWL_TI_CT_KILL) {
- IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n");
- iwl_perform_ct_kill_task(priv, false);
- }
- }
- mutex_unlock(&priv->mutex);
- }
-}
-
-/* Card State Notification indicated reach critical temperature
- * if PSP not enable, no Thermal Throttling function will be performed
- * just set the GP1 bit to acknowledge the event
- * otherwise, go into IWL_TI_CT_KILL state
- * since Card State Notification will not provide any temperature reading
- * for Legacy mode
- * so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
- * for advance mode
- * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
- */
-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))
- return;
-
- if (!iwl_is_ready(priv))
- return;
-
- if (tt->state != IWL_TI_CT_KILL) {
- IWL_ERR(priv, "Device reached critical temperature "
- "- ucode going to sleep!\n");
- if (!priv->thermal_throttle.advanced_tt)
- iwl_legacy_tt_handler(priv,
- IWL_MINIMAL_POWER_THRESHOLD,
- true);
- else
- iwl_advance_tt_handler(priv,
- CT_KILL_THRESHOLD + 1, true);
- }
-}
-
-/* Card State Notification indicated out of critical temperature
- * since Card State Notification will not provide any temperature reading
- * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
- * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
- */
-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))
- return;
-
- if (!iwl_is_ready(priv))
- return;
-
- /* stop ct_kill_exit_tm timer */
- del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
-
- if (tt->state == IWL_TI_CT_KILL) {
- IWL_ERR(priv,
- "Device temperature below critical"
- "- ucode awake!\n");
- /*
- * exit from CT_KILL state
- * reset the current temperature reading
- */
- priv->temperature = 0;
- if (!priv->thermal_throttle.advanced_tt)
- iwl_legacy_tt_handler(priv,
- IWL_REDUCED_PERFORMANCE_THRESHOLD_2,
- true);
- else
- iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
- true);
- }
-}
-
-void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
-{
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- IWL_DEBUG_POWER(priv, "Queueing critical temperature enter.\n");
- queue_work(priv->workqueue, &priv->ct_enter);
-}
-EXPORT_SYMBOL(iwl_tt_enter_ct_kill);
-
-void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
-{
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- IWL_DEBUG_POWER(priv, "Queueing critical temperature exit.\n");
- queue_work(priv->workqueue, &priv->ct_exit);
-}
-EXPORT_SYMBOL(iwl_tt_exit_ct_kill);
-
-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))
- return;
-
- if (priv->cfg->temperature_kelvin)
- temp = KELVIN_TO_CELSIUS(priv->temperature);
-
- if (!priv->thermal_throttle.advanced_tt)
- iwl_legacy_tt_handler(priv, temp, false);
- else
- iwl_advance_tt_handler(priv, temp, false);
-}
-
-void iwl_tt_handler(struct iwl_priv *priv)
-{
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- IWL_DEBUG_POWER(priv, "Queueing thermal throttling work.\n");
- queue_work(priv->workqueue, &priv->tt_work);
-}
-EXPORT_SYMBOL(iwl_tt_handler);
-
-/* Thermal throttling initialization
- * For advance thermal throttling:
- * Initialize Thermal Index and temperature threshold table
- * Initialize thermal throttling restriction table
- */
-void iwl_tt_initialize(struct iwl_priv *priv)
-{
- struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
- int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
- struct iwl_tt_trans *transaction;
-
- IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling\n");
-
- memset(tt, 0, sizeof(struct iwl_tt_mgmt));
-
- tt->state = IWL_TI_0;
- init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
- priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
- priv->thermal_throttle.ct_kill_exit_tm.function =
- iwl_tt_check_exit_ct_kill;
- init_timer(&priv->thermal_throttle.ct_kill_waiting_tm);
- priv->thermal_throttle.ct_kill_waiting_tm.data = (unsigned long)priv;
- priv->thermal_throttle.ct_kill_waiting_tm.function =
- iwl_tt_ready_for_ct_kill;
- /* setup deferred ct kill work */
- INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
- INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
- INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
-
- if (priv->cfg->adv_thermal_throttle) {
- IWL_DEBUG_POWER(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);
- if (!tt->restriction || !tt->transaction) {
- IWL_ERR(priv, "Fallback to Legacy Throttling\n");
- priv->thermal_throttle.advanced_tt = false;
- kfree(tt->restriction);
- tt->restriction = NULL;
- kfree(tt->transaction);
- tt->transaction = NULL;
- } else {
- transaction = tt->transaction +
- (IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
- memcpy(transaction, &tt_range_0[0], size);
- transaction = tt->transaction +
- (IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
- memcpy(transaction, &tt_range_1[0], size);
- transaction = tt->transaction +
- (IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
- memcpy(transaction, &tt_range_2[0], size);
- transaction = tt->transaction +
- (IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
- memcpy(transaction, &tt_range_3[0], size);
- size = sizeof(struct iwl_tt_restriction) *
- IWL_TI_STATE_MAX;
- memcpy(tt->restriction,
- &restriction_range[0], size);
- priv->thermal_throttle.advanced_tt = true;
- }
- } else {
- IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n");
- priv->thermal_throttle.advanced_tt = false;
- }
-}
-EXPORT_SYMBOL(iwl_tt_initialize);
-
-/* cleanup thermal throttling management related memory and timer */
-void iwl_tt_exit(struct iwl_priv *priv)
-{
- struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
- /* stop ct_kill_exit_tm timer if activated */
- del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
- /* stop ct_kill_waiting_tm timer if activated */
- del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
- cancel_work_sync(&priv->tt_work);
- cancel_work_sync(&priv->ct_enter);
- cancel_work_sync(&priv->ct_exit);
-
- if (priv->thermal_throttle.advanced_tt) {
- /* free advance thermal throttling memory */
- kfree(tt->restriction);
- tt->restriction = NULL;
- kfree(tt->transaction);
- tt->transaction = NULL;
- }
-}
-EXPORT_SYMBOL(iwl_tt_exit);
-
/* initialize to default */
void iwl_power_initialize(struct iwl_priv *priv)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index 5db91c10dcc8..df81565a7cc4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -30,90 +30,6 @@
#include "iwl-commands.h"
-#define IWL_ABSOLUTE_ZERO 0
-#define IWL_ABSOLUTE_MAX 0xFFFFFFFF
-#define IWL_TT_INCREASE_MARGIN 5
-#define IWL_TT_CT_KILL_MARGIN 3
-
-enum iwl_antenna_ok {
- IWL_ANT_OK_NONE,
- IWL_ANT_OK_SINGLE,
- IWL_ANT_OK_MULTI,
-};
-
-/* Thermal Throttling State Machine states */
-enum iwl_tt_state {
- IWL_TI_0, /* normal temperature, system power state */
- IWL_TI_1, /* high temperature detect, low power state */
- IWL_TI_2, /* higher temperature detected, lower power state */
- IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */
- IWL_TI_STATE_MAX
-};
-
-/**
- * struct iwl_tt_restriction - Thermal Throttling restriction table
- * @tx_stream: number of tx stream allowed
- * @is_ht: ht enable/disable
- * @rx_stream: number of rx stream allowed
- *
- * This table is used by advance thermal throttling management
- * based on the current thermal throttling state, and determines
- * the number of tx/rx streams and the status of HT operation.
- */
-struct iwl_tt_restriction {
- enum iwl_antenna_ok tx_stream;
- enum iwl_antenna_ok rx_stream;
- bool is_ht;
-};
-
-/**
- * struct iwl_tt_trans - Thermal Throttling transaction table
- * @next_state: next thermal throttling mode
- * @tt_low: low temperature threshold to change state
- * @tt_high: high temperature threshold to change state
- *
- * This is used by the advanced thermal throttling algorithm
- * to determine the next thermal state to go based on the
- * current temperature.
- */
-struct iwl_tt_trans {
- enum iwl_tt_state next_state;
- u32 tt_low;
- u32 tt_high;
-};
-
-/**
- * struct iwl_tt_mgnt - Thermal Throttling Management structure
- * @advanced_tt: advanced thermal throttle required
- * @state: current Thermal Throttling state
- * @tt_power_mode: Thermal Throttling power mode index
- * being used to set power level when
- * when thermal throttling state != IWL_TI_0
- * the tt_power_mode should set to different
- * power mode based on the current tt state
- * @tt_previous_temperature: last measured temperature
- * @iwl_tt_restriction: ptr to restriction tbl, used by advance
- * thermal throttling to determine how many tx/rx streams
- * should be used in tt state; and can HT be enabled or not
- * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling
- * state transaction
- * @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature
- * @ct_kill_exit_tm: timer to exit thermal kill
- */
-struct iwl_tt_mgmt {
- enum iwl_tt_state state;
- bool advanced_tt;
- u8 tt_power_mode;
- bool ct_kill_toggle;
-#ifdef CONFIG_IWLWIFI_DEBUG
- s32 tt_previous_temp;
-#endif
- struct iwl_tt_restriction *restriction;
- struct iwl_tt_trans *transaction;
- struct timer_list ct_kill_exit_tm;
- struct timer_list ct_kill_waiting_tm;
-};
-
enum iwl_power_level {
IWL_POWER_INDEX_1,
IWL_POWER_INDEX_2,
@@ -130,15 +46,6 @@ struct iwl_power_mgr {
};
int iwl_power_update_mode(struct iwl_priv *priv, bool force);
-bool iwl_ht_enabled(struct iwl_priv *priv);
-bool iwl_within_ct_kill_margin(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);
-void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
-void iwl_tt_handler(struct iwl_priv *priv);
-void iwl_tt_initialize(struct iwl_priv *priv);
-void iwl_tt_exit(struct iwl_priv *priv);
void iwl_power_initialize(struct iwl_priv *priv);
extern bool no_sleep_autoadjust;
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index b1f101caf19d..5469655646ae 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -306,7 +306,7 @@
* at a time, until receiving ACK from receiving station, or reaching
* retry limit and giving up.
*
- * The command queue (#4) must use this mode!
+ * The command queue (#4/#9) must use this mode!
* This mode does not require use of the Byte Count table in host DRAM.
*
* Driver controls scheduler operation via 3 means:
@@ -322,7 +322,7 @@
* (1024 bytes for each queue).
*
* After receiving "Alive" response from uCode, driver must initialize
- * the scheduler (especially for queue #4, the command queue, otherwise
+ * the scheduler (especially for queue #4/#9, the command queue, otherwise
* the driver can't issue commands!):
*/
@@ -555,8 +555,9 @@
#define IWLAGN_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
((IWLAGN_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffc)
-#define IWLAGN_SCD_QUEUECHAIN_SEL_ALL(x) (((1<<(x)) - 1) &\
- (~(1<<IWL_CMD_QUEUE_NUM)))
+#define IWLAGN_SCD_QUEUECHAIN_SEL_ALL(priv) \
+ (((1<<(priv)->hw_params.max_txq_num) - 1) &\
+ (~(1<<(priv)->cmd_queue)))
#define IWLAGN_SCD_BASE (PRPH_BASE + 0xa02c00)
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 79773e353baa..f436270ca39a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -36,7 +36,6 @@
#include "iwl-core.h"
#include "iwl-sta.h"
#include "iwl-io.h"
-#include "iwl-calib.h"
#include "iwl-helpers.h"
/************************** RX-FUNCTIONS ****************************/
/*
@@ -228,7 +227,7 @@ void iwl_recover_from_statistics(struct iwl_priv *priv,
{
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
- if (iwl_is_associated(priv)) {
+ if (iwl_is_any_associated(priv)) {
if (priv->cfg->ops->lib->check_ack_health) {
if (!priv->cfg->ops->lib->check_ack_health(
priv, pkt)) {
@@ -266,7 +265,12 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv,
{
u16 fc = le16_to_cpu(hdr->frame_control);
- if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK)
+ /*
+ * All contexts have the same setting here due to it being
+ * a module parameter, so OK to check any context.
+ */
+ if (priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags &
+ RXON_FILTER_DIS_DECRYPT_MSK)
return 0;
if (!(fc & IEEE80211_FCTL_PROTECTED))
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index a4b3663a262f..67da31295781 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -54,100 +54,133 @@
#define IWL_PASSIVE_DWELL_BASE (100)
#define IWL_CHANNEL_TUNE_TIME 5
+static int iwl_send_scan_abort(struct iwl_priv *priv)
+{
+ int ret;
+ struct iwl_rx_packet *pkt;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_SCAN_ABORT_CMD,
+ .flags = CMD_WANT_SKB,
+ };
+ /* 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))
+ return -EIO;
-/**
- * iwl_scan_cancel - Cancel any currently executing HW scan
- *
- * NOTE: priv->mutex is not required before calling this function
- */
-int iwl_scan_cancel(struct iwl_priv *priv)
+ ret = iwl_send_cmd_sync(priv, &cmd);
+ if (ret)
+ return ret;
+
+ pkt = (struct iwl_rx_packet *)cmd.reply_page;
+ if (pkt->u.status != CAN_ABORT_STATUS) {
+ /* The scan abort will return 1 for success or
+ * 2 for "failure". A failure condition can be
+ * due to simply not being in an active scan which
+ * can occur if we send the scan abort before we
+ * the microcode has notified us that a scan is
+ * completed. */
+ IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n", pkt->u.status);
+ ret = -EIO;
+ }
+
+ iwl_free_pages(priv, cmd.reply_page);
+ return ret;
+}
+
+static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
{
- if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
- clear_bit(STATUS_SCANNING, &priv->status);
- return 0;
+ /* check if scan was requested from mac80211 */
+ if (priv->scan_request) {
+ IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n");
+ ieee80211_scan_completed(priv->hw, aborted);
}
- if (test_bit(STATUS_SCANNING, &priv->status)) {
- if (!test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) {
- IWL_DEBUG_SCAN(priv, "Queuing scan abort.\n");
- queue_work(priv->workqueue, &priv->abort_scan);
+ priv->is_internal_short_scan = false;
+ priv->scan_vif = NULL;
+ priv->scan_request = NULL;
+}
- } else
- IWL_DEBUG_SCAN(priv, "Scan abort already in progress.\n");
+void iwl_force_scan_end(struct iwl_priv *priv)
+{
+ lockdep_assert_held(&priv->mutex);
- return test_bit(STATUS_SCANNING, &priv->status);
+ if (!test_bit(STATUS_SCANNING, &priv->status)) {
+ IWL_DEBUG_SCAN(priv, "Forcing scan end while not scanning\n");
+ return;
}
+ IWL_DEBUG_SCAN(priv, "Forcing scan end\n");
+ clear_bit(STATUS_SCANNING, &priv->status);
+ clear_bit(STATUS_SCAN_HW, &priv->status);
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ iwl_complete_scan(priv, true);
+}
+
+static void iwl_do_scan_abort(struct iwl_priv *priv)
+{
+ int ret;
+
+ lockdep_assert_held(&priv->mutex);
+
+ if (!test_bit(STATUS_SCANNING, &priv->status)) {
+ IWL_DEBUG_SCAN(priv, "Not performing scan to abort\n");
+ return;
+ }
+
+ if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_SCAN(priv, "Scan abort in progress\n");
+ return;
+ }
+
+ ret = iwl_send_scan_abort(priv);
+ if (ret) {
+ IWL_DEBUG_SCAN(priv, "Send scan abort failed %d\n", ret);
+ iwl_force_scan_end(priv);
+ } else
+ IWL_DEBUG_SCAN(priv, "Sucessfully send scan abort\n");
+}
+
+/**
+ * iwl_scan_cancel - Cancel any currently executing HW scan
+ */
+int iwl_scan_cancel(struct iwl_priv *priv)
+{
+ IWL_DEBUG_SCAN(priv, "Queuing abort scan\n");
+ queue_work(priv->workqueue, &priv->abort_scan);
return 0;
}
EXPORT_SYMBOL(iwl_scan_cancel);
+
/**
* iwl_scan_cancel_timeout - Cancel any currently executing HW scan
* @ms: amount of time to wait (in milliseconds) for scan to abort
*
- * NOTE: priv->mutex must be held before calling this function
*/
int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
{
- unsigned long now = jiffies;
- int ret;
-
- ret = iwl_scan_cancel(priv);
- if (ret && ms) {
- mutex_unlock(&priv->mutex);
- while (!time_after(jiffies, now + msecs_to_jiffies(ms)) &&
- test_bit(STATUS_SCANNING, &priv->status))
- msleep(1);
- mutex_lock(&priv->mutex);
-
- return test_bit(STATUS_SCANNING, &priv->status);
- }
+ unsigned long timeout = jiffies + msecs_to_jiffies(ms);
- return ret;
-}
-EXPORT_SYMBOL(iwl_scan_cancel_timeout);
+ lockdep_assert_held(&priv->mutex);
-static int iwl_send_scan_abort(struct iwl_priv *priv)
-{
- int ret = 0;
- struct iwl_rx_packet *pkt;
- struct iwl_host_cmd cmd = {
- .id = REPLY_SCAN_ABORT_CMD,
- .flags = CMD_WANT_SKB,
- };
+ IWL_DEBUG_SCAN(priv, "Scan cancel timeout\n");
- /* If there isn't a scan actively going on in the hardware
- * then we are in between scan bands and not actually
- * actively scanning, so don't send the abort command */
- if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
- clear_bit(STATUS_SCAN_ABORTING, &priv->status);
- return 0;
- }
+ iwl_do_scan_abort(priv);
- ret = iwl_send_cmd_sync(priv, &cmd);
- if (ret) {
- clear_bit(STATUS_SCAN_ABORTING, &priv->status);
- return ret;
- }
-
- pkt = (struct iwl_rx_packet *)cmd.reply_page;
- if (pkt->u.status != CAN_ABORT_STATUS) {
- /* The scan abort will return 1 for success or
- * 2 for "failure". A failure condition can be
- * due to simply not being in an active scan which
- * can occur if we send the scan abort before we
- * the microcode has notified us that a scan is
- * completed. */
- IWL_DEBUG_INFO(priv, "SCAN_ABORT returned %d.\n", pkt->u.status);
- clear_bit(STATUS_SCAN_ABORTING, &priv->status);
- clear_bit(STATUS_SCAN_HW, &priv->status);
+ while (time_before_eq(jiffies, timeout)) {
+ if (!test_bit(STATUS_SCAN_HW, &priv->status))
+ break;
+ msleep(20);
}
- iwl_free_pages(priv, cmd.reply_page);
-
- return ret;
+ return test_bit(STATUS_SCAN_HW, &priv->status);
}
+EXPORT_SYMBOL(iwl_scan_cancel_timeout);
/* Service response to REPLY_SCAN_CMD (0x80) */
static void iwl_rx_reply_scan(struct iwl_priv *priv,
@@ -158,7 +191,7 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv,
struct iwl_scanreq_notification *notif =
(struct iwl_scanreq_notification *)pkt->u.raw;
- IWL_DEBUG_RX(priv, "Scan request status = 0x%x\n", notif->status);
+ IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status);
#endif
}
@@ -206,7 +239,6 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
-#ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
@@ -214,29 +246,38 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
scan_notif->scanned_channels,
scan_notif->tsf_low,
scan_notif->tsf_high, scan_notif->status);
-#endif
/* The HW is no longer scanning */
clear_bit(STATUS_SCAN_HW, &priv->status);
- IWL_DEBUG_INFO(priv, "Scan on %sGHz took %dms\n",
+ IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n",
(priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
jiffies_to_msecs(elapsed_jiffies
(priv->scan_start, jiffies)));
- /*
- * If a request to abort was given, or the scan did not succeed
- * then we reset the scan state machine and terminate,
- * re-queuing another scan if one has been requested
- */
- if (test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status))
- IWL_DEBUG_INFO(priv, "Aborted scan completed.\n");
-
- IWL_DEBUG_INFO(priv, "Setting scan to off\n");
-
- clear_bit(STATUS_SCANNING, &priv->status);
-
queue_work(priv->workqueue, &priv->scan_completed);
+
+ if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
+ priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist &&
+ priv->bt_status != scan_notif->bt_status) {
+ if (scan_notif->bt_status) {
+ /* BT on */
+ if (!priv->bt_ch_announce)
+ priv->bt_traffic_load =
+ IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+ /*
+ * otherwise, no traffic load information provided
+ * no changes made
+ */
+ } else {
+ /* BT off */
+ priv->bt_traffic_load =
+ IWL_BT_COEX_TRAFFIC_LOAD_NONE;
+ }
+ priv->bt_status = scan_notif->bt_status;
+ queue_work(priv->workqueue, &priv->bt_traffic_change_work);
+ }
}
void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
@@ -268,18 +309,28 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
enum ieee80211_band band,
struct ieee80211_vif *vif)
{
+ struct iwl_rxon_context *ctx;
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_associated(priv)) {
- /* If we're associated, we clamp the maximum passive
- * dwell time to be 98% of the beacon interval (minus
- * 2 * channel tune time) */
- passive = vif ? vif->bss_conf.beacon_int : 0;
- if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
- passive = IWL_PASSIVE_DWELL_BASE;
- passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+ if (iwl_is_any_associated(priv)) {
+ /*
+ * If we're associated, we clamp the maximum passive
+ * dwell time to be 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->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);
+ }
}
return passive;
@@ -296,19 +347,53 @@ void iwl_init_scan_params(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_init_scan_params);
-static int iwl_scan_initiate(struct iwl_priv *priv, struct ieee80211_vif *vif)
+static int __must_check iwl_scan_initiate(struct iwl_priv *priv,
+ struct ieee80211_vif *vif,
+ bool internal,
+ enum ieee80211_band band)
{
+ int ret;
+
lockdep_assert_held(&priv->mutex);
- IWL_DEBUG_INFO(priv, "Starting scan...\n");
+ if (WARN_ON(!priv->cfg->ops->utils->request_scan))
+ return -EOPNOTSUPP;
+
+ cancel_delayed_work(&priv->scan_check);
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_WARN(priv, "Request scan called when driver not ready.\n");
+ return -EIO;
+ }
+
+ if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+ IWL_DEBUG_SCAN(priv,
+ "Multiple concurrent scan requests in parallel.\n");
+ return -EBUSY;
+ }
+
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_SCAN(priv, "Scan request while abort pending.\n");
+ return -EBUSY;
+ }
+
+ IWL_DEBUG_SCAN(priv, "Starting %sscan...\n",
+ internal ? "internal short " : "");
+
set_bit(STATUS_SCANNING, &priv->status);
- priv->is_internal_short_scan = false;
+ priv->is_internal_short_scan = internal;
priv->scan_start = jiffies;
+ priv->scan_band = band;
- if (WARN_ON(!priv->cfg->ops->utils->request_scan))
- return -EOPNOTSUPP;
+ ret = priv->cfg->ops->utils->request_scan(priv, vif);
+ if (ret) {
+ clear_bit(STATUS_SCANNING, &priv->status);
+ priv->is_internal_short_scan = false;
+ return ret;
+ }
- priv->cfg->ops->utils->request_scan(priv, vif);
+ queue_delayed_work(priv->workqueue, &priv->scan_check,
+ IWL_SCAN_CHECK_WATCHDOG);
return 0;
}
@@ -327,12 +412,6 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
mutex_lock(&priv->mutex);
- if (!iwl_is_ready_rf(priv)) {
- ret = -EIO;
- IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n");
- goto out_unlock;
- }
-
if (test_bit(STATUS_SCANNING, &priv->status) &&
!priv->is_internal_short_scan) {
IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
@@ -340,14 +419,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
goto out_unlock;
}
- if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
- IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
- ret = -EAGAIN;
- goto out_unlock;
- }
-
/* mac80211 will only ask for one band at a time */
- priv->scan_band = req->channels[0]->band;
priv->scan_request = req;
priv->scan_vif = vif;
@@ -355,10 +427,12 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
* If an internal scan is in progress, just set
* up the scan_request as per above.
*/
- if (priv->is_internal_short_scan)
+ if (priv->is_internal_short_scan) {
+ IWL_DEBUG_SCAN(priv, "SCAN request during internal scan\n");
ret = 0;
- else
- ret = iwl_scan_initiate(priv, vif);
+ } else
+ ret = iwl_scan_initiate(priv, vif, false,
+ req->channels[0]->band);
IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -378,11 +452,13 @@ void iwl_internal_short_hw_scan(struct iwl_priv *priv)
queue_work(priv->workqueue, &priv->start_internal_scan);
}
-void iwl_bg_start_internal_scan(struct work_struct *work)
+static void iwl_bg_start_internal_scan(struct work_struct *work)
{
struct iwl_priv *priv =
container_of(work, struct iwl_priv, start_internal_scan);
+ IWL_DEBUG_SCAN(priv, "Start internal scan\n");
+
mutex_lock(&priv->mutex);
if (priv->is_internal_short_scan == true) {
@@ -390,56 +466,31 @@ void iwl_bg_start_internal_scan(struct work_struct *work)
goto unlock;
}
- if (!iwl_is_ready_rf(priv)) {
- IWL_DEBUG_SCAN(priv, "not ready or exit pending\n");
- goto unlock;
- }
-
if (test_bit(STATUS_SCANNING, &priv->status)) {
IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
goto unlock;
}
- if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
- IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
- goto unlock;
- }
-
- priv->scan_band = priv->band;
-
- IWL_DEBUG_SCAN(priv, "Start internal short scan...\n");
- set_bit(STATUS_SCANNING, &priv->status);
- priv->is_internal_short_scan = true;
-
- if (WARN_ON(!priv->cfg->ops->utils->request_scan))
- goto unlock;
-
- priv->cfg->ops->utils->request_scan(priv, NULL);
+ if (iwl_scan_initiate(priv, NULL, true, priv->band))
+ IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n");
unlock:
mutex_unlock(&priv->mutex);
}
-EXPORT_SYMBOL(iwl_bg_start_internal_scan);
-void iwl_bg_scan_check(struct work_struct *data)
+static void iwl_bg_scan_check(struct work_struct *data)
{
struct iwl_priv *priv =
container_of(data, struct iwl_priv, scan_check.work);
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
+ IWL_DEBUG_SCAN(priv, "Scan check work\n");
+ /* 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);
- if (test_bit(STATUS_SCANNING, &priv->status) &&
- !test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
- IWL_DEBUG_SCAN(priv, "Scan completion watchdog (%dms)\n",
- jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
-
- if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
- iwl_send_scan_abort(priv);
- }
+ iwl_force_scan_end(priv);
mutex_unlock(&priv->mutex);
}
-EXPORT_SYMBOL(iwl_bg_scan_check);
/**
* iwl_fill_probe_req - fill in all required fields and IE for probe request
@@ -489,73 +540,78 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
}
EXPORT_SYMBOL(iwl_fill_probe_req);
-void iwl_bg_abort_scan(struct work_struct *work)
+static void iwl_bg_abort_scan(struct work_struct *work)
{
struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
- if (!test_bit(STATUS_READY, &priv->status) ||
- !test_bit(STATUS_GEO_CONFIGURED, &priv->status))
- return;
-
- cancel_delayed_work(&priv->scan_check);
+ IWL_DEBUG_SCAN(priv, "Abort scan work\n");
+ /* We keep scan_check work queued in case when firmware will not
+ * report back scan completed notification */
mutex_lock(&priv->mutex);
- if (test_bit(STATUS_SCAN_ABORTING, &priv->status))
- iwl_send_scan_abort(priv);
+ iwl_scan_cancel_timeout(priv, 200);
mutex_unlock(&priv->mutex);
}
-EXPORT_SYMBOL(iwl_bg_abort_scan);
-void iwl_bg_scan_completed(struct work_struct *work)
+static void iwl_bg_scan_completed(struct work_struct *work)
{
struct iwl_priv *priv =
container_of(work, struct iwl_priv, scan_completed);
- bool internal = false;
+ bool aborted;
- IWL_DEBUG_SCAN(priv, "SCAN complete scan\n");
+ IWL_DEBUG_SCAN(priv, "Completed %sscan.\n",
+ priv->is_internal_short_scan ? "internal short " : "");
cancel_delayed_work(&priv->scan_check);
mutex_lock(&priv->mutex);
- if (priv->is_internal_short_scan) {
- priv->is_internal_short_scan = false;
- IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
- internal = true;
- } else {
- priv->scan_request = NULL;
- priv->scan_vif = NULL;
+
+ 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 (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ if (priv->is_internal_short_scan && !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, false,
+ 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);
- if (internal && priv->scan_request)
- iwl_scan_initiate(priv, priv->scan_vif);
+out_settings:
+ /* Can we still talk to firmware ? */
+ if (!iwl_is_ready_rf(priv))
+ goto out;
/* Since setting the TXPOWER may have been deferred while
* performing the scan, fire one off */
iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
- /*
- * Since setting the RXON may have been deferred while
- * performing the scan, fire one off if needed
- */
- if (memcmp(&priv->active_rxon,
- &priv->staging_rxon, sizeof(priv->staging_rxon)))
- iwlcore_commit_rxon(priv);
+ priv->cfg->ops->utils->post_scan(priv);
out:
mutex_unlock(&priv->mutex);
-
- /*
- * Do not hold mutex here since this will cause mac80211 to call
- * into driver again into functions that will attempt to take
- * mutex.
- */
- if (!internal)
- ieee80211_scan_completed(priv->hw, false);
}
-EXPORT_SYMBOL(iwl_bg_scan_completed);
void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
{
@@ -566,3 +622,16 @@ void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_setup_scan_deferred_work);
+void iwl_cancel_scan_deferred_work(struct iwl_priv *priv)
+{
+ cancel_work_sync(&priv->start_internal_scan);
+ cancel_work_sync(&priv->abort_scan);
+ cancel_work_sync(&priv->scan_completed);
+
+ if (cancel_delayed_work_sync(&priv->scan_check)) {
+ mutex_lock(&priv->mutex);
+ iwl_force_scan_end(priv);
+ mutex_unlock(&priv->mutex);
+ }
+}
+EXPORT_SYMBOL(iwl_cancel_scan_deferred_work);
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 7e0829be5e78..7c7f7dcb1b1e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -172,12 +172,14 @@ int iwl_send_add_sta(struct iwl_priv *priv,
EXPORT_SYMBOL(iwl_send_add_sta);
static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
- struct ieee80211_sta_ht_cap *sta_ht_inf)
+ 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_ht_inf || !sta_ht_inf->ht_supported)
+ if (!sta || !sta_ht_inf->ht_supported)
goto done;
mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
@@ -211,7 +213,7 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
sta_flags |= cpu_to_le32(
(u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
- if (iwl_is_ht40_tx_allowed(priv, sta_ht_inf))
+ 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;
@@ -226,9 +228,8 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
*
* should be called with sta_lock held
*/
-static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr,
- bool is_ap,
- struct ieee80211_sta_ht_cap *ht_info)
+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;
@@ -236,9 +237,9 @@ static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr,
u16 rate;
if (is_ap)
- sta_id = IWL_AP_ID;
+ sta_id = ctx->ap_sta_id;
else if (is_broadcast_ether_addr(addr))
- sta_id = priv->hw_params.bcast_sta_id;
+ 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,
@@ -289,14 +290,22 @@ static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr,
memcpy(station->sta.sta.addr, addr, ETH_ALEN);
station->sta.mode = 0;
station->sta.sta.sta_id = sta_id;
- station->sta.station_flags = 0;
+ 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 ht_info, and mac80211
+ * STA and broadcast STA) pass in a NULL sta, and mac80211
* doesn't allow HT IBSS.
*/
- iwl_set_ht_add_station(priv, sta_id, ht_info);
+ iwl_set_ht_add_station(priv, sta_id, sta, ctx);
/* 3945 only */
rate = (priv->band == IEEE80211_BAND_5GHZ) ?
@@ -307,16 +316,16 @@ static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr,
return sta_id;
}
+EXPORT_SYMBOL_GPL(iwl_prep_station);
#define STA_WAIT_TIMEOUT (HZ/2)
/**
* iwl_add_station_common -
*/
-int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
- bool is_ap,
- struct ieee80211_sta_ht_cap *ht_info,
- u8 *sta_id_r)
+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;
@@ -325,7 +334,7 @@ int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
*sta_id_r = 0;
spin_lock_irqsave(&priv->sta_lock, flags_spin);
- sta_id = iwl_prep_station(priv, addr, is_ap, ht_info);
+ 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);
@@ -372,111 +381,6 @@ int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
}
EXPORT_SYMBOL(iwl_add_station_common);
-static struct iwl_link_quality_cmd *iwl_sta_alloc_lq(struct iwl_priv *priv,
- u8 sta_id)
-{
- int i, r;
- struct iwl_link_quality_cmd *link_cmd;
- u32 rate_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;
- }
- /* 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 */
- if (priv->band == IEEE80211_BAND_5GHZ)
- r = IWL_RATE_6M_INDEX;
- else
- r = IWL_RATE_1M_INDEX;
-
- for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
- rate_flags = 0;
- 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_MCS_ANT_POS;
-
- link_cmd->rs_table[i].rate_n_flags =
- iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
- r = iwl_get_prev_ieee_rate(r);
- }
-
- link_cmd->general_params.single_stream_ant_msk =
- first_antenna(priv->hw_params.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);
- 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) {
- link_cmd->general_params.dual_stream_ant_msk =
- priv->hw_params.valid_tx_ant;
- }
-
- 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;
-
- return link_cmd;
-}
-
-/*
- * iwl_add_bssid_station - Add the special IBSS BSSID station
- *
- * Function sleeps.
- */
-int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs,
- u8 *sta_id_r)
-{
- int ret;
- u8 sta_id;
- struct iwl_link_quality_cmd *link_cmd;
- unsigned long flags;
-
- if (sta_id_r)
- *sta_id_r = IWL_INVALID_STATION;
-
- ret = iwl_add_station_common(priv, addr, 0, NULL, &sta_id);
- if (ret) {
- IWL_ERR(priv, "Unable to add station %pM\n", addr);
- return ret;
- }
-
- if (sta_id_r)
- *sta_id_r = sta_id;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- priv->stations[sta_id].used |= IWL_STA_LOCAL;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- if (init_rs) {
- /* Set up default rate scaling table in device's station table */
- link_cmd = iwl_sta_alloc_lq(priv, sta_id);
- if (!link_cmd) {
- IWL_ERR(priv, "Unable to initialize rate scaling for station %pM.\n",
- addr);
- return -ENOMEM;
- }
-
- ret = iwl_send_lq_cmd(priv, link_cmd, CMD_SYNC, true);
- if (ret)
- IWL_ERR(priv, "Link quality command failed (%d)\n", ret);
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- priv->stations[sta_id].lq = link_cmd;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(iwl_add_bssid_station);
-
/**
* iwl_sta_ucode_deactivate - deactivate ucode status for a station
*
@@ -616,7 +520,8 @@ EXPORT_SYMBOL_GPL(iwl_remove_station);
* other than explicit station management would cause this in
* the ucode, e.g. unassociated RXON.
*/
-void iwl_clear_ucode_stations(struct iwl_priv *priv)
+void iwl_clear_ucode_stations(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
{
int i;
unsigned long flags_spin;
@@ -626,6 +531,9 @@ void iwl_clear_ucode_stations(struct iwl_priv *priv)
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;
@@ -647,7 +555,7 @@ EXPORT_SYMBOL(iwl_clear_ucode_stations);
*
* Function sleeps.
*/
-void iwl_restore_stations(struct iwl_priv *priv)
+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;
@@ -665,6 +573,8 @@ void iwl_restore_stations(struct iwl_priv *priv)
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",
@@ -700,7 +610,7 @@ void iwl_restore_stations(struct iwl_priv *priv)
* current LQ command
*/
if (send_lq)
- iwl_send_lq_cmd(priv, &lq, CMD_SYNC, true);
+ 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;
}
@@ -718,7 +628,7 @@ int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
{
int i;
- for (i = 0; i < STA_KEY_MAX_NUM; i++)
+ for (i = 0; i < priv->sta_key_max_num; i++)
if (!test_and_set_bit(i, &priv->ucode_key_table))
return i;
@@ -726,393 +636,25 @@ int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_get_free_ucode_key_index);
-static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
-{
- int i, not_empty = 0;
- u8 buff[sizeof(struct iwl_wep_cmd) +
- sizeof(struct iwl_wep_key) * WEP_KEYS_MAX];
- struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff;
- size_t cmd_size = sizeof(struct iwl_wep_cmd);
- struct iwl_host_cmd cmd = {
- .id = REPLY_WEPKEY,
- .data = wep_cmd,
- .flags = CMD_SYNC,
- };
-
- might_sleep();
-
- memset(wep_cmd, 0, cmd_size +
- (sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));
-
- for (i = 0; i < WEP_KEYS_MAX ; i++) {
- wep_cmd->key[i].key_index = i;
- if (priv->wep_keys[i].key_size) {
- wep_cmd->key[i].key_offset = i;
- not_empty = 1;
- } else {
- wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET;
- }
-
- wep_cmd->key[i].key_size = priv->wep_keys[i].key_size;
- memcpy(&wep_cmd->key[i].key[3], priv->wep_keys[i].key,
- priv->wep_keys[i].key_size);
- }
-
- wep_cmd->global_key_type = WEP_KEY_WEP_TYPE;
- wep_cmd->num_keys = WEP_KEYS_MAX;
-
- cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;
-
- cmd.len = cmd_size;
-
- if (not_empty || send_if_empty)
- return iwl_send_cmd(priv, &cmd);
- else
- return 0;
-}
-
-int iwl_restore_default_wep_keys(struct iwl_priv *priv)
-{
- lockdep_assert_held(&priv->mutex);
-
- return iwl_send_static_wepkey_cmd(priv, 0);
-}
-EXPORT_SYMBOL(iwl_restore_default_wep_keys);
-
-int iwl_remove_default_wep_key(struct iwl_priv *priv,
- struct ieee80211_key_conf *keyconf)
-{
- int ret;
-
- lockdep_assert_held(&priv->mutex);
-
- IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
- keyconf->keyidx);
-
- memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
- if (iwl_is_rfkill(priv)) {
- IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n");
- /* but keys in device are clear anyway so return success */
- return 0;
- }
- ret = iwl_send_static_wepkey_cmd(priv, 1);
- IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
- keyconf->keyidx, ret);
-
- return ret;
-}
-EXPORT_SYMBOL(iwl_remove_default_wep_key);
-
-int iwl_set_default_wep_key(struct iwl_priv *priv,
- struct ieee80211_key_conf *keyconf)
+void iwl_dealloc_bcast_stations(struct iwl_priv *priv)
{
- int ret;
-
- lockdep_assert_held(&priv->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);
- return -EINVAL;
- }
-
- keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
- keyconf->hw_key_idx = HW_KEY_DEFAULT;
- priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;
-
- priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
- memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key,
- keyconf->keylen);
-
- ret = iwl_send_static_wepkey_cmd(priv, 0);
- IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n",
- keyconf->keylen, keyconf->keyidx, ret);
-
- return ret;
-}
-EXPORT_SYMBOL(iwl_set_default_wep_key);
-
-static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
- struct ieee80211_key_conf *keyconf,
- u8 sta_id)
-{
- unsigned long flags;
- __le16 key_flags = 0;
- struct iwl_addsta_cmd sta_cmd;
-
- lockdep_assert_held(&priv->mutex);
-
- keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
-
- key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK);
- key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
- key_flags &= ~STA_KEY_FLG_INVALID;
-
- if (keyconf->keylen == WEP_KEY_LEN_128)
- key_flags |= STA_KEY_FLG_KEY_SIZE_MSK;
-
- if (sta_id == priv->hw_params.bcast_sta_id)
- key_flags |= STA_KEY_MULTICAST_MSK;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
-
- priv->stations[sta_id].keyinfo.alg = keyconf->alg;
- priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
- priv->stations[sta_id].keyinfo.keyidx = keyconf->keyidx;
-
- memcpy(priv->stations[sta_id].keyinfo.key,
- keyconf->key, keyconf->keylen);
-
- memcpy(&priv->stations[sta_id].sta.key.key[3],
- keyconf->key, keyconf->keylen);
-
- if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
- == STA_KEY_FLG_NO_ENC)
- priv->stations[sta_id].sta.key.key_offset =
- iwl_get_free_ucode_key_index(priv);
- /* else, we are overriding an existing key => no need to allocated room
- * in uCode. */
-
- WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
- "no space for a new key");
-
- priv->stations[sta_id].sta.key.key_flags = key_flags;
- priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
- 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);
-
- return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-}
-
-static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
- struct ieee80211_key_conf *keyconf,
- u8 sta_id)
-{
- unsigned long flags;
- __le16 key_flags = 0;
- struct iwl_addsta_cmd sta_cmd;
-
- lockdep_assert_held(&priv->mutex);
-
- key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
- key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
- key_flags &= ~STA_KEY_FLG_INVALID;
-
- if (sta_id == priv->hw_params.bcast_sta_id)
- key_flags |= STA_KEY_MULTICAST_MSK;
-
- keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- priv->stations[sta_id].keyinfo.alg = keyconf->alg;
- priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
-
- memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
- keyconf->keylen);
-
- memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
- keyconf->keylen);
-
- if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
- == STA_KEY_FLG_NO_ENC)
- priv->stations[sta_id].sta.key.key_offset =
- iwl_get_free_ucode_key_index(priv);
- /* else, we are overriding an existing key => no need to allocated room
- * in uCode. */
-
- WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
- "no space for a new key");
-
- priv->stations[sta_id].sta.key.key_flags = key_flags;
- priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
- 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);
-
- return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-}
-
-static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
- struct ieee80211_key_conf *keyconf,
- u8 sta_id)
-{
- unsigned long flags;
- int ret = 0;
- __le16 key_flags = 0;
-
- key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
- key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
- key_flags &= ~STA_KEY_FLG_INVALID;
-
- if (sta_id == priv->hw_params.bcast_sta_id)
- key_flags |= STA_KEY_MULTICAST_MSK;
-
- keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
-
- priv->stations[sta_id].keyinfo.alg = keyconf->alg;
- priv->stations[sta_id].keyinfo.keylen = 16;
-
- if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
- == STA_KEY_FLG_NO_ENC)
- priv->stations[sta_id].sta.key.key_offset =
- iwl_get_free_ucode_key_index(priv);
- /* else, we are overriding an existing key => no need to allocated room
- * in uCode. */
-
- WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
- "no space for a new key");
-
- priv->stations[sta_id].sta.key.key_flags = key_flags;
-
-
- /* This copy is acutally not needed: we get the key with each TX */
- memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
-
- memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16);
-
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- return ret;
-}
-
-void iwl_update_tkip_key(struct iwl_priv *priv,
- struct ieee80211_key_conf *keyconf,
- struct ieee80211_sta *sta, u32 iv32, u16 *phase1key)
-{
- u8 sta_id;
unsigned long flags;
int i;
- if (iwl_scan_cancel(priv)) {
- /* cancel scan failed, just live w/ bad key and rely
- briefly on SW decryption */
- return;
- }
-
- sta_id = iwl_sta_id_or_broadcast(priv, sta);
- if (sta_id == IWL_INVALID_STATION)
- return;
-
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[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
-
- for (i = 0; i < 5; i++)
- priv->stations[sta_id].sta.key.tkip_rx_ttak[i] =
- cpu_to_le16(phase1key[i]);
-
- priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
- 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);
-
-}
-EXPORT_SYMBOL(iwl_update_tkip_key);
-
-int iwl_remove_dynamic_key(struct iwl_priv *priv,
- struct ieee80211_key_conf *keyconf,
- u8 sta_id)
-{
- unsigned long flags;
- u16 key_flags;
- u8 keyidx;
- struct iwl_addsta_cmd sta_cmd;
-
- lockdep_assert_held(&priv->mutex);
-
- priv->key_mapping_key--;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags);
- keyidx = (key_flags >> STA_KEY_FLG_KEYID_POS) & 0x3;
-
- IWL_DEBUG_WEP(priv, "Remove dynamic key: idx=%d sta=%d\n",
- keyconf->keyidx, sta_id);
-
- if (keyconf->keyidx != keyidx) {
- /* We need to remove a key with index different that the one
- * in the uCode. This means that the key we need to remove has
- * been replaced by another one with different index.
- * Don't do anything and return ok
- */
- spin_unlock_irqrestore(&priv->sta_lock, flags);
- return 0;
- }
-
- if (priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET) {
- IWL_WARN(priv, "Removing wrong key %d 0x%x\n",
- keyconf->keyidx, key_flags);
- spin_unlock_irqrestore(&priv->sta_lock, flags);
- return 0;
- }
-
- if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset,
- &priv->ucode_key_table))
- IWL_ERR(priv, "index %d not used in uCode key table.\n",
- priv->stations[sta_id].sta.key.key_offset);
- memset(&priv->stations[sta_id].keyinfo, 0,
- sizeof(struct iwl_hw_key));
- memset(&priv->stations[sta_id].sta.key, 0,
- sizeof(struct iwl4965_keyinfo));
- priv->stations[sta_id].sta.key.key_flags =
- STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID;
- priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET;
- priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
- priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-
- if (iwl_is_rfkill(priv)) {
- IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled.\n");
- spin_unlock_irqrestore(&priv->sta_lock, flags);
- return 0;
+ priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
+ priv->num_stations--;
+ BUG_ON(priv->num_stations < 0);
+ kfree(priv->stations[i].lq);
+ priv->stations[i].lq = NULL;
}
- memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-}
-EXPORT_SYMBOL(iwl_remove_dynamic_key);
-
-int iwl_set_dynamic_key(struct iwl_priv *priv,
- struct ieee80211_key_conf *keyconf, u8 sta_id)
-{
- int ret;
-
- lockdep_assert_held(&priv->mutex);
-
- priv->key_mapping_key++;
- keyconf->hw_key_idx = HW_KEY_DYNAMIC;
-
- switch (keyconf->alg) {
- case ALG_CCMP:
- ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
- break;
- case ALG_TKIP:
- ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
- break;
- case ALG_WEP:
- ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id);
- break;
- default:
- IWL_ERR(priv,
- "Unknown alg: %s alg = %d\n", __func__, keyconf->alg);
- ret = -EINVAL;
- }
-
- IWL_DEBUG_WEP(priv, "Set dynamic key: alg= %d len=%d idx=%d sta=%d ret=%d\n",
- keyconf->alg, keyconf->keylen, keyconf->keyidx,
- sta_id, ret);
-
- return ret;
}
-EXPORT_SYMBOL(iwl_set_dynamic_key);
+EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_stations);
#ifdef CONFIG_IWLWIFI_DEBUG
static void iwl_dump_lq_cmd(struct iwl_priv *priv,
@@ -1147,16 +689,16 @@ static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
* 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;
- struct iwl_ht_config *ht_conf = &priv->current_ht_config;
- if (ht_conf->is_ht)
+ if (ctx->ht.enabled)
return true;
IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n",
- priv->active_rxon.channel);
+ 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,
@@ -1178,7 +720,7 @@ static bool is_lq_table_valid(struct iwl_priv *priv,
* this case to clear the state indicating that station creation is in
* progress.
*/
-int iwl_send_lq_cmd(struct iwl_priv *priv,
+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;
@@ -1197,7 +739,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
iwl_dump_lq_cmd(priv, lq);
BUG_ON(init && (cmd.flags & CMD_ASYNC));
- if (is_lq_table_valid(priv, lq))
+ if (is_lq_table_valid(priv, ctx, lq))
ret = iwl_send_cmd(priv, &cmd);
else
ret = -EINVAL;
@@ -1216,207 +758,6 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
}
EXPORT_SYMBOL(iwl_send_lq_cmd);
-/**
- * iwl_alloc_bcast_station - add broadcast station into driver's station table.
- *
- * This adds the broadcast station into the driver's station table
- * and marks it driver active, so that it will be restored to the
- * device at the next best time.
- */
-int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq)
-{
- struct iwl_link_quality_cmd *link_cmd;
- unsigned long flags;
- u8 sta_id;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- sta_id = iwl_prep_station(priv, 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);
-
- 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);
-
- if (init_lq) {
- link_cmd = iwl_sta_alloc_lq(priv, sta_id);
- if (!link_cmd) {
- IWL_ERR(priv,
- "Unable to initialize rate scaling for bcast station.\n");
- return -ENOMEM;
- }
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- priv->stations[sta_id].lq = link_cmd;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(iwl_alloc_bcast_station);
-
-/**
- * iwl_update_bcast_station - update broadcast station's LQ command
- *
- * Only used by iwlagn. Placed here to have all bcast station management
- * code together.
- */
-int iwl_update_bcast_station(struct iwl_priv *priv)
-{
- unsigned long flags;
- struct iwl_link_quality_cmd *link_cmd;
- u8 sta_id = priv->hw_params.bcast_sta_id;
-
- link_cmd = iwl_sta_alloc_lq(priv, sta_id);
- if (!link_cmd) {
- IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n");
- return -ENOMEM;
- }
-
- spin_lock_irqsave(&priv->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);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(iwl_update_bcast_station);
-
-void iwl_dealloc_bcast_station(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--;
- BUG_ON(priv->num_stations < 0);
- kfree(priv->stations[i].lq);
- priv->stations[i].lq = NULL;
- }
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-}
-EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_station);
-
-/**
- * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
- */
-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);
-
- /* Remove "disable" flag, to enable Tx for this TID */
- spin_lock_irqsave(&priv->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);
-
- return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-}
-EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid);
-
-int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
- int tid, u16 ssn)
-{
- unsigned long flags;
- int sta_id;
- struct iwl_addsta_cmd sta_cmd;
-
- lockdep_assert_held(&priv->mutex);
-
- sta_id = iwl_sta_id(sta);
- if (sta_id == IWL_INVALID_STATION)
- return -ENXIO;
-
- spin_lock_irqsave(&priv->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);
-
- return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-}
-EXPORT_SYMBOL(iwl_sta_rx_agg_start);
-
-int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
- int tid)
-{
- unsigned long flags;
- int sta_id;
- struct iwl_addsta_cmd sta_cmd;
-
- lockdep_assert_held(&priv->mutex);
-
- sta_id = iwl_sta_id(sta);
- if (sta_id == IWL_INVALID_STATION) {
- IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
- return -ENXIO;
- }
-
- spin_lock_irqsave(&priv->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);
-
- return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-}
-EXPORT_SYMBOL(iwl_sta_rx_agg_stop);
-
-void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->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);
-
-}
-EXPORT_SYMBOL(iwl_sta_modify_ps_wake);
-
-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);
- priv->stations[sta_id].sta.station_flags |= STA_FLG_PWR_SAVE_MSK;
- priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
- priv->stations[sta_id].sta.sta.modify_mask =
- STA_MODIFY_SLEEP_TX_COUNT_MSK;
- priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt);
- priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
-}
-EXPORT_SYMBOL(iwl_sta_modify_sleep_tx_count);
-
int iwl_mac_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index d38a350ba0bd..06475872eee4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -43,44 +43,26 @@
#define IWL_STA_BCAST BIT(4) /* this station is the special bcast station */
-int iwl_remove_default_wep_key(struct iwl_priv *priv,
- struct ieee80211_key_conf *key);
-int iwl_set_default_wep_key(struct iwl_priv *priv,
- struct ieee80211_key_conf *key);
-int iwl_restore_default_wep_keys(struct iwl_priv *priv);
-int iwl_set_dynamic_key(struct iwl_priv *priv,
- struct ieee80211_key_conf *key, u8 sta_id);
-int iwl_remove_dynamic_key(struct iwl_priv *priv,
- struct ieee80211_key_conf *key, u8 sta_id);
-void iwl_update_tkip_key(struct iwl_priv *priv,
- struct ieee80211_key_conf *keyconf,
- struct ieee80211_sta *sta, u32 iv32, u16 *phase1key);
-
-void iwl_restore_stations(struct iwl_priv *priv);
-void iwl_clear_ucode_stations(struct iwl_priv *priv);
-int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq);
-void iwl_dealloc_bcast_station(struct iwl_priv *priv);
-int iwl_update_bcast_station(struct iwl_priv *priv);
+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_index(struct iwl_priv *priv);
int iwl_send_add_sta(struct iwl_priv *priv,
struct iwl_addsta_cmd *sta, u8 flags);
-int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs,
- u8 *sta_id_r);
-int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
- bool is_ap,
- struct ieee80211_sta_ht_cap *ht_info,
- u8 *sta_id_r);
+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);
-int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
-int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
- int tid, u16 ssn);
-int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
- int tid);
-void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id);
-void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
+
+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);
/**
* iwl_clear_driver_stations - clear knowledge of all stations from driver
@@ -94,20 +76,25 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
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;
- /*
- * 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.
- */
priv->ucode_key_table = 0;
- priv->key_mapping_key = 0;
- memset(priv->wep_keys, 0, sizeof(priv->wep_keys));
+
+ 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);
}
@@ -123,6 +110,7 @@ static inline int iwl_sta_id(struct ieee80211_sta *sta)
/**
* 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
@@ -131,12 +119,13 @@ static inline int iwl_sta_id(struct ieee80211_sta *sta)
* 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 priv->hw_params.bcast_sta_id;
+ return context->bcast_sta_id;
sta_id = iwl_sta_id(sta);
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index a81989c06983..7261ee49f282 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -134,7 +134,7 @@ EXPORT_SYMBOL(iwl_tx_queue_free);
*/
void iwl_cmd_queue_free(struct iwl_priv *priv)
{
- struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+ struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
struct iwl_queue *q = &txq->q;
struct device *dev = &priv->pci_dev->dev;
int i;
@@ -271,7 +271,7 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv,
/* Driver private data, only for Tx (not command) queues,
* not shared with device. */
- if (id != IWL_CMD_QUEUE_NUM) {
+ if (id != priv->cmd_queue) {
txq->txb = kzalloc(sizeof(txq->txb[0]) *
TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
if (!txq->txb) {
@@ -314,13 +314,13 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
/*
* Alloc buffer array for commands (Tx or other types of commands).
- * For the command queue (#4), allocate command space + one big
+ * For the command queue (#4/#9), allocate command space + one big
* command for scan, since scan command is very huge; the system will
* not have two scans at the same time, so only one is needed.
* For normal Tx queues (all other queues), no super-size command
* space is needed.
*/
- if (txq_id == IWL_CMD_QUEUE_NUM)
+ if (txq_id == priv->cmd_queue)
actual_slots++;
txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * actual_slots,
@@ -355,7 +355,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
* need an swq_id so don't set one to catch errors, all others can
* be set up to the identity mapping.
*/
- if (txq_id != IWL_CMD_QUEUE_NUM)
+ if (txq_id != priv->cmd_queue)
txq->swq_id = txq_id;
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
@@ -385,7 +385,7 @@ void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
{
int actual_slots = slots_num;
- if (txq_id == IWL_CMD_QUEUE_NUM)
+ if (txq_id == priv->cmd_queue)
actual_slots++;
memset(txq->meta, 0, sizeof(struct iwl_cmd_meta) * actual_slots);
@@ -413,7 +413,7 @@ EXPORT_SYMBOL(iwl_tx_queue_reset);
*/
int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
{
- struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+ struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
struct iwl_queue *q = &txq->q;
struct iwl_device_cmd *out_cmd;
struct iwl_cmd_meta *out_meta;
@@ -422,6 +422,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
int len;
u32 idx;
u16 fix_size;
+ bool is_ct_kill = false;
cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len);
fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
@@ -443,9 +444,11 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
IWL_ERR(priv, "No space in command queue\n");
- if (iwl_within_ct_kill_margin(priv))
- iwl_tt_enter_ct_kill(priv);
- else {
+ if (priv->cfg->ops->lib->tt_ops.ct_kill_check) {
+ is_ct_kill =
+ priv->cfg->ops->lib->tt_ops.ct_kill_check(priv);
+ }
+ if (!is_ct_kill) {
IWL_ERR(priv, "Restarting adapter due to queue full\n");
queue_work(priv->workqueue, &priv->restart);
}
@@ -480,7 +483,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
* information */
out_cmd->hdr.flags = 0;
- out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
+ out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(priv->cmd_queue) |
INDEX_TO_SEQ(q->write_ptr));
if (cmd->flags & CMD_SIZE_HUGE)
out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
@@ -497,15 +500,15 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
get_cmd_string(out_cmd->hdr.cmd),
out_cmd->hdr.cmd,
le16_to_cpu(out_cmd->hdr.sequence), fix_size,
- q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
- break;
+ q->write_ptr, idx, priv->cmd_queue);
+ break;
default:
IWL_DEBUG_HC(priv, "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), fix_size,
- q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
+ q->write_ptr, idx, priv->cmd_queue);
}
#endif
txq->need_update = 1;
@@ -584,16 +587,16 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
struct iwl_device_cmd *cmd;
struct iwl_cmd_meta *meta;
- struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+ struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
/* If a Tx command is being handled and it isn't in the actual
* command queue then there a command routing bug has been introduced
* in the queue management code. */
- if (WARN(txq_id != IWL_CMD_QUEUE_NUM,
- "wrong command queue %d, sequence 0x%X readp=%d writep=%d\n",
- txq_id, sequence,
- priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr,
- priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) {
+ if (WARN(txq_id != priv->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);
return;
}
@@ -633,41 +636,3 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
meta->flags = 0;
}
EXPORT_SYMBOL(iwl_tx_cmd_complete);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x
-#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x
-
-const char *iwl_get_tx_fail_reason(u32 status)
-{
- 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(FW_DROP);
- TX_STATUS_FAIL(STA_COLOR_MISMATCH_DROP);
- }
-
- return "UNKNOWN";
-}
-EXPORT_SYMBOL(iwl_get_tx_fail_reason);
-#endif /* CONFIG_IWLWIFI_DEBUG */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index d31661c1ce77..8f8c4b73f8b9 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -33,6 +33,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/pci-aspm.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
@@ -143,7 +144,7 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
- if (sta_id == priv->hw_params.bcast_sta_id)
+ if (sta_id == priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id)
key_flags |= STA_KEY_MULTICAST_MSK;
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
@@ -151,7 +152,7 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
key_flags &= ~STA_KEY_FLG_INVALID;
spin_lock_irqsave(&priv->sta_lock, flags);
- priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+ priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
keyconf->keylen);
@@ -222,23 +223,25 @@ static int iwl3945_set_dynamic_key(struct iwl_priv *priv,
keyconf->hw_key_idx = HW_KEY_DYNAMIC;
- switch (keyconf->alg) {
- case ALG_CCMP:
+ switch (keyconf->cipher) {
+ case WLAN_CIPHER_SUITE_CCMP:
ret = iwl3945_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
break;
- case ALG_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
ret = iwl3945_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
break;
- case ALG_WEP:
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
ret = iwl3945_set_wep_dynamic_key_info(priv, keyconf, sta_id);
break;
default:
- IWL_ERR(priv, "Unknown alg: %s alg = %d\n", __func__, keyconf->alg);
+ IWL_ERR(priv, "Unknown alg: %s alg=%x\n", __func__,
+ keyconf->cipher);
ret = -EINVAL;
}
- IWL_DEBUG_WEP(priv, "Set dynamic key: alg= %d len=%d idx=%d sta=%d ret=%d\n",
- keyconf->alg, keyconf->keylen, keyconf->keyidx,
+ IWL_DEBUG_WEP(priv, "Set dynamic key: alg=%x len=%d idx=%d sta=%d ret=%d\n",
+ keyconf->cipher, keyconf->keylen, keyconf->keyidx,
sta_id, ret);
return ret;
@@ -254,10 +257,11 @@ static int iwl3945_remove_static_key(struct iwl_priv *priv)
static int iwl3945_set_static_key(struct iwl_priv *priv,
struct ieee80211_key_conf *key)
{
- if (key->alg == ALG_WEP)
+ if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+ key->cipher == WLAN_CIPHER_SUITE_WEP104)
return -EOPNOTSUPP;
- IWL_ERR(priv, "Static key invalid: alg %d\n", key->alg);
+ IWL_ERR(priv, "Static key invalid: cipher %x\n", key->cipher);
return -EINVAL;
}
@@ -313,15 +317,15 @@ unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,
int left)
{
- if (!iwl_is_associated(priv) || !priv->ibss_beacon)
+ if (!iwl_is_associated(priv, IWL_RXON_CTX_BSS) || !priv->beacon_skb)
return 0;
- if (priv->ibss_beacon->len > left)
+ if (priv->beacon_skb->len > left)
return 0;
- memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len);
+ memcpy(hdr, priv->beacon_skb->data, priv->beacon_skb->len);
- return priv->ibss_beacon->len;
+ return priv->beacon_skb->len;
}
static int iwl3945_send_beacon_cmd(struct iwl_priv *priv)
@@ -339,7 +343,8 @@ static int iwl3945_send_beacon_cmd(struct iwl_priv *priv)
return -ENOMEM;
}
- rate = iwl_rate_get_lowest_plcp(priv);
+ rate = iwl_rate_get_lowest_plcp(priv,
+ &priv->contexts[IWL_RXON_CTX_BSS]);
frame_size = iwl3945_hw_get_beacon_cmd(priv, frame, rate);
@@ -369,23 +374,25 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
- switch (keyinfo->alg) {
- case ALG_CCMP:
+ tx_cmd->sec_ctl = 0;
+
+ switch (keyinfo->cipher) {
+ case WLAN_CIPHER_SUITE_CCMP:
tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen);
IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
break;
- case ALG_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
break;
- case ALG_WEP:
- tx_cmd->sec_ctl = TX_CMD_SEC_WEP |
+ case WLAN_CIPHER_SUITE_WEP104:
+ tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
+ /* fall through */
+ case WLAN_CIPHER_SUITE_WEP40:
+ tx_cmd->sec_ctl |= TX_CMD_SEC_WEP |
(info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
- if (keyinfo->keylen == 13)
- tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
-
memcpy(&tx_cmd->key[3], keyinfo->key, keyinfo->keylen);
IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
@@ -393,7 +400,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
break;
default:
- IWL_ERR(priv, "Unknown encode alg %d\n", keyinfo->alg);
+ IWL_ERR(priv, "Unknown encode cipher %x\n", keyinfo->cipher);
break;
}
}
@@ -506,7 +513,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr_len = ieee80211_hdrlen(fc);
/* Find index into station table for destination station */
- sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
+ sta_id = iwl_sta_id_or_broadcast(
+ priv, &priv->contexts[IWL_RXON_CTX_BSS],
+ info->control.sta);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);
@@ -536,6 +545,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* 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 = &priv->contexts[IWL_RXON_CTX_BSS];
/* Init first empty entry in queue's array of Tx/cmd buffers */
out_cmd = txq->cmd[idx];
@@ -677,11 +687,12 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
int rc;
int spectrum_resp_status;
int duration = le16_to_cpu(params->duration);
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
- if (iwl_is_associated(priv))
+ if (iwl_is_associated(priv, IWL_RXON_CTX_BSS))
add_time = iwl_usecs_to_beacons(priv,
le64_to_cpu(params->start_time) - priv->_3945.last_tsf,
- le16_to_cpu(priv->rxon_timing.beacon_interval));
+ le16_to_cpu(ctx->timing.beacon_interval));
memset(&spectrum, 0, sizeof(spectrum));
@@ -692,18 +703,18 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
cmd.len = sizeof(spectrum);
spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
- if (iwl_is_associated(priv))
+ if (iwl_is_associated(priv, IWL_RXON_CTX_BSS))
spectrum.start_time =
iwl_add_beacon_time(priv,
priv->_3945.last_beacon_time, add_time,
- le16_to_cpu(priv->rxon_timing.beacon_interval));
+ le16_to_cpu(ctx->timing.beacon_interval));
else
spectrum.start_time = 0;
spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
spectrum.channels[0].channel = params->channel;
spectrum.channels[0].type = type;
- if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
+ if (ctx->active.flags & RXON_FLG_BAND_24G_MSK)
spectrum.flags |= RXON_FLG_BAND_24G_MSK |
RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
@@ -792,7 +803,8 @@ static void iwl3945_bg_beacon_update(struct work_struct *work)
struct sk_buff *beacon;
/* Pull updated AP beacon from mac80211. will fail if not in AP mode */
- beacon = ieee80211_beacon_get(priv->hw, priv->vif);
+ beacon = ieee80211_beacon_get(priv->hw,
+ priv->contexts[IWL_RXON_CTX_BSS].vif);
if (!beacon) {
IWL_ERR(priv, "update beacon failed\n");
@@ -801,10 +813,10 @@ static void iwl3945_bg_beacon_update(struct work_struct *work)
mutex_lock(&priv->mutex);
/* new beacon skb is allocated every time; dispose previous.*/
- if (priv->ibss_beacon)
- dev_kfree_skb(priv->ibss_beacon);
+ if (priv->beacon_skb)
+ dev_kfree_skb(priv->beacon_skb);
- priv->ibss_beacon = beacon;
+ priv->beacon_skb = beacon;
mutex_unlock(&priv->mutex);
iwl3945_send_beacon_cmd(priv);
@@ -813,9 +825,9 @@ static void iwl3945_bg_beacon_update(struct work_struct *work)
static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
-#ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status);
+#ifdef CONFIG_IWLWIFI_DEBUG
u8 rate = beacon->beacon_notify_hdr.rate;
IWL_DEBUG_RX(priv, "beacon status %x retries %d iss %d "
@@ -827,6 +839,8 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
le32_to_cpu(beacon->low_tsf), rate);
#endif
+ priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
+
if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
(!test_bit(STATUS_EXIT_PENDING, &priv->status)))
queue_work(priv->workqueue, &priv->beacon_update);
@@ -1567,16 +1581,16 @@ int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
- if (capacity > priv->cfg->max_event_log_size) {
+ if (capacity > priv->cfg->base_params->max_event_log_size) {
IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
- capacity, priv->cfg->max_event_log_size);
- capacity = priv->cfg->max_event_log_size;
+ capacity, priv->cfg->base_params->max_event_log_size);
+ capacity = priv->cfg->base_params->max_event_log_size;
}
- if (next_entry > priv->cfg->max_event_log_size) {
+ if (next_entry > priv->cfg->base_params->max_event_log_size) {
IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
- next_entry, priv->cfg->max_event_log_size);
- next_entry = priv->cfg->max_event_log_size;
+ next_entry, priv->cfg->base_params->max_event_log_size);
+ next_entry = priv->cfg->base_params->max_event_log_size;
}
size = num_wraps ? capacity : next_entry;
@@ -1716,7 +1730,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
IWL_ERR(priv, "Microcode SW error detected. "
"Restarting 0x%X.\n", inta);
priv->isr_stats.sw++;
- priv->isr_stats.sw_err = inta;
iwl_irq_handle_error(priv);
handled |= CSR_INT_BIT_SW_ERR;
}
@@ -2460,6 +2473,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
{
int thermal_spin = 0;
u32 rfkill;
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
@@ -2505,7 +2519,8 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
/* Enable timer to monitor the driver queues */
mod_timer(&priv->monitor_recover,
jiffies +
- msecs_to_jiffies(priv->cfg->monitor_recover_period));
+ msecs_to_jiffies(
+ priv->cfg->base_params->monitor_recover_period));
}
if (iwl_is_rfkill(priv))
@@ -2517,22 +2532,22 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
iwl_power_update_mode(priv, true);
- if (iwl_is_associated(priv)) {
+ if (iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
struct iwl3945_rxon_cmd *active_rxon =
- (struct iwl3945_rxon_cmd *)(&priv->active_rxon);
+ (struct iwl3945_rxon_cmd *)(&ctx->active);
- priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+ ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
} else {
/* Initialize our rx_config data */
- iwl_connection_init_rx_config(priv, NULL);
+ iwl_connection_init_rx_config(priv, ctx);
}
/* Configure Bluetooth device coexistence support */
priv->cfg->ops->hcmd->send_bt_config(priv);
/* Configure the adapter for unassociated operation */
- iwlcore_commit_rxon(priv);
+ iwl3945_commit_rxon(priv, ctx);
iwl3945_reg_txpower_periodic(priv);
@@ -2553,19 +2568,22 @@ static void iwl3945_cancel_deferred_work(struct iwl_priv *priv);
static void __iwl3945_down(struct iwl_priv *priv)
{
unsigned long flags;
- int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
- struct ieee80211_conf *conf = NULL;
+ int exit_pending;
IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
- conf = ieee80211_get_hw_conf(priv->hw);
+ iwl_scan_cancel_timeout(priv, 200);
- if (!exit_pending)
- set_bit(STATUS_EXIT_PENDING, &priv->status);
+ exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
+
+ /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
+ * to prevent rearm timer */
+ if (priv->cfg->ops->lib->recover_from_tx_stall)
+ del_timer_sync(&priv->monitor_recover);
/* Station information will now be cleared in device */
- iwl_clear_ucode_stations(priv);
- iwl_dealloc_bcast_station(priv);
+ iwl_clear_ucode_stations(priv, NULL);
+ iwl_dealloc_bcast_stations(priv);
iwl_clear_driver_stations(priv);
/* Unblock any waiting calls */
@@ -2619,14 +2637,14 @@ static void __iwl3945_down(struct iwl_priv *priv)
udelay(5);
/* Stop the device, and put it in low power state */
- priv->cfg->ops->lib->apm_ops.stop(priv);
+ iwl_apm_stop(priv);
exit:
memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
- if (priv->ibss_beacon)
- dev_kfree_skb(priv->ibss_beacon);
- priv->ibss_beacon = NULL;
+ if (priv->beacon_skb)
+ dev_kfree_skb(priv->beacon_skb);
+ priv->beacon_skb = NULL;
/* clear out any free frames */
iwl3945_clear_free_frames(priv);
@@ -2643,11 +2661,33 @@ static void iwl3945_down(struct iwl_priv *priv)
#define MAX_HW_RESTARTS 5
+static int iwl3945_alloc_bcast_station(struct iwl_priv *priv)
+{
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+ unsigned long flags;
+ u8 sta_id;
+
+ spin_lock_irqsave(&priv->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);
+
+ 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);
+
+ return 0;
+}
+
static int __iwl3945_up(struct iwl_priv *priv)
{
int rc, i;
- rc = iwl_alloc_bcast_station(priv, false);
+ rc = iwl3945_alloc_bcast_station(priv);
if (rc)
return rc;
@@ -2799,7 +2839,7 @@ static void iwl3945_rfkill_poll(struct work_struct *data)
}
-void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
+int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
{
struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_CMD,
@@ -2807,61 +2847,19 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
.flags = CMD_SIZE_HUGE,
};
struct iwl3945_scan_cmd *scan;
- struct ieee80211_conf *conf = NULL;
u8 n_probes = 0;
enum ieee80211_band band;
bool is_active = false;
+ int ret;
- conf = ieee80211_get_hw_conf(priv->hw);
-
- cancel_delayed_work(&priv->scan_check);
-
- if (!iwl_is_ready(priv)) {
- IWL_WARN(priv, "request scan called when driver not ready.\n");
- goto done;
- }
-
- /* Make sure the scan wasn't canceled before this queued work
- * was given the chance to run... */
- if (!test_bit(STATUS_SCANNING, &priv->status))
- goto done;
-
- /* This should never be called or scheduled if there is currently
- * a scan active in the hardware. */
- if (test_bit(STATUS_SCAN_HW, &priv->status)) {
- IWL_DEBUG_INFO(priv, "Multiple concurrent scan requests "
- "Ignoring second request.\n");
- goto done;
- }
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
- IWL_DEBUG_SCAN(priv, "Aborting scan due to device shutdown\n");
- goto done;
- }
-
- if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
- IWL_DEBUG_HC(priv,
- "Scan request while abort pending. Queuing.\n");
- goto done;
- }
-
- if (iwl_is_rfkill(priv)) {
- IWL_DEBUG_HC(priv, "Aborting scan due to RF Kill activation\n");
- goto done;
- }
-
- if (!test_bit(STATUS_READY, &priv->status)) {
- IWL_DEBUG_HC(priv,
- "Scan request while uninitialized. Queuing.\n");
- goto done;
- }
+ lockdep_assert_held(&priv->mutex);
if (!priv->scan_cmd) {
priv->scan_cmd = kmalloc(sizeof(struct iwl3945_scan_cmd) +
IWL_MAX_SCAN_SIZE, GFP_KERNEL);
if (!priv->scan_cmd) {
IWL_DEBUG_SCAN(priv, "Fail to allocate scan memory\n");
- goto done;
+ return -ENOMEM;
}
}
scan = priv->scan_cmd;
@@ -2870,7 +2868,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
- if (iwl_is_associated(priv)) {
+ if (iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
u16 interval = 0;
u32 extra;
u32 suspend_time = 100;
@@ -2931,7 +2929,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
/* We don't build a direct scan probe request; the uCode will do
* that based on the direct_mask added to each channel entry */
scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
- scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id;
+ scan->tx_cmd.sta_id = priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id;
scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
/* flags + rate selection */
@@ -2940,25 +2938,25 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
case IEEE80211_BAND_2GHZ:
scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
scan->tx_cmd.rate = IWL_RATE_1M_PLCP;
- scan->good_CRC_th = 0;
band = IEEE80211_BAND_2GHZ;
break;
case IEEE80211_BAND_5GHZ:
scan->tx_cmd.rate = IWL_RATE_6M_PLCP;
- /*
- * If active scaning is requested but a certain channel
- * is marked passive, we can do active scanning if we
- * detect transmissions.
- */
- scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
- IWL_GOOD_CRC_TH_DISABLED;
band = IEEE80211_BAND_5GHZ;
break;
default:
IWL_WARN(priv, "Invalid scan band\n");
- goto done;
+ return -EIO;
}
+ /*
+ * If active scaning is requested but a certain channel
+ * is marked passive, we can do active scanning if we
+ * detect transmissions.
+ */
+ scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+ IWL_GOOD_CRC_TH_DISABLED;
+
if (!priv->is_internal_short_scan) {
scan->tx_cmd.len = cpu_to_le16(
iwl_fill_probe_req(priv,
@@ -2991,7 +2989,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
if (scan->channel_count == 0) {
IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
- goto done;
+ return -EIO;
}
cmd.len += le16_to_cpu(scan->tx_cmd.len) +
@@ -3000,25 +2998,22 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
scan->len = cpu_to_le16(cmd.len);
set_bit(STATUS_SCAN_HW, &priv->status);
- if (iwl_send_cmd_sync(priv, &cmd))
- goto done;
-
- queue_delayed_work(priv->workqueue, &priv->scan_check,
- IWL_SCAN_CHECK_WATCHDOG);
+ ret = iwl_send_cmd_sync(priv, &cmd);
+ if (ret)
+ clear_bit(STATUS_SCAN_HW, &priv->status);
+ return ret;
+}
- return;
+void iwl3945_post_scan(struct iwl_priv *priv)
+{
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
- done:
- /* can not perform scan make sure we clear scanning
- * bits from status so next scan request can be performed.
- * if we dont clear scanning status bit here all next scan
- * will fail
- */
- clear_bit(STATUS_SCAN_HW, &priv->status);
- clear_bit(STATUS_SCANNING, &priv->status);
-
- /* inform mac80211 scan aborted */
- queue_work(priv->workqueue, &priv->abort_scan);
+ /*
+ * Since setting the RXON may have been deferred while
+ * performing the scan, fire one off if needed
+ */
+ if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
+ iwl3945_commit_rxon(priv, ctx);
}
static void iwl3945_bg_restart(struct work_struct *data)
@@ -3029,8 +3024,10 @@ static void iwl3945_bg_restart(struct work_struct *data)
return;
if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
+ struct iwl_rxon_context *ctx;
mutex_lock(&priv->mutex);
- priv->vif = NULL;
+ for_each_context(priv, ctx)
+ ctx->vif = NULL;
priv->is_open = 0;
mutex_unlock(&priv->mutex);
iwl3945_down(priv);
@@ -3064,6 +3061,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
{
int rc = 0;
struct ieee80211_conf *conf = NULL;
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
if (!vif || !priv->is_open)
return;
@@ -3074,7 +3072,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
}
IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
- vif->bss_conf.aid, priv->active_rxon.bssid_addr);
+ vif->bss_conf.aid, ctx->active.bssid_addr);
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
@@ -3083,37 +3081,34 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
conf = ieee80211_get_hw_conf(priv->hw);
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwlcore_commit_rxon(priv);
+ ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl3945_commit_rxon(priv, ctx);
- memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
- iwl_setup_rxon_timing(priv, vif);
- rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
- sizeof(priv->rxon_timing), &priv->rxon_timing);
+ rc = iwl_send_rxon_timing(priv, ctx);
if (rc)
IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
"Attempting to continue.\n");
- priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+ ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
- priv->staging_rxon.assoc_id = cpu_to_le16(vif->bss_conf.aid);
+ ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
vif->bss_conf.aid, vif->bss_conf.beacon_int);
if (vif->bss_conf.use_short_preamble)
- priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+ ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
else
- priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+ ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
- if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+ if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
if (vif->bss_conf.use_short_slot)
- priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
else
- priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+ ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
}
- iwlcore_commit_rxon(priv);
+ iwl3945_commit_rxon(priv, ctx);
switch (vif->type) {
case NL80211_IFTYPE_STATION:
@@ -3212,15 +3207,6 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw)
priv->is_open = 0;
- if (iwl_is_ready_rf(priv)) {
- /* stop mac, cancel any scan request and clear
- * RXON_FILTER_ASSOC_MSK BIT
- */
- mutex_lock(&priv->mutex);
- iwl_scan_cancel_timeout(priv, 100);
- mutex_unlock(&priv->mutex);
- }
-
iwl3945_down(priv);
flush_workqueue(priv->workqueue);
@@ -3250,48 +3236,45 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
{
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
int rc = 0;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
/* The following should be done only at AP bring up */
- if (!(iwl_is_associated(priv))) {
+ if (!(iwl_is_associated(priv, IWL_RXON_CTX_BSS))) {
/* RXON - unassoc (to set timing command) */
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwlcore_commit_rxon(priv);
+ ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl3945_commit_rxon(priv, ctx);
/* RXON Timing */
- memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
- iwl_setup_rxon_timing(priv, vif);
- rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
- sizeof(priv->rxon_timing),
- &priv->rxon_timing);
+ rc = iwl_send_rxon_timing(priv, ctx);
if (rc)
IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
"Attempting to continue.\n");
- priv->staging_rxon.assoc_id = 0;
+ ctx->staging.assoc_id = 0;
if (vif->bss_conf.use_short_preamble)
- priv->staging_rxon.flags |=
+ ctx->staging.flags |=
RXON_FLG_SHORT_PREAMBLE_MSK;
else
- priv->staging_rxon.flags &=
+ ctx->staging.flags &=
~RXON_FLG_SHORT_PREAMBLE_MSK;
- if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+ if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
if (vif->bss_conf.use_short_slot)
- priv->staging_rxon.flags |=
+ ctx->staging.flags |=
RXON_FLG_SHORT_SLOT_MSK;
else
- priv->staging_rxon.flags &=
+ ctx->staging.flags &=
~RXON_FLG_SHORT_SLOT_MSK;
}
/* restore RXON assoc */
- priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
- iwlcore_commit_rxon(priv);
+ ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+ iwl3945_commit_rxon(priv, ctx);
}
iwl3945_send_beacon_cmd(priv);
@@ -3317,10 +3300,11 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return -EOPNOTSUPP;
}
- static_key = !iwl_is_associated(priv);
+ static_key = !iwl_is_associated(priv, IWL_RXON_CTX_BSS);
if (!static_key) {
- sta_id = iwl_sta_id_or_broadcast(priv, sta);
+ sta_id = iwl_sta_id_or_broadcast(
+ priv, &priv->contexts[IWL_RXON_CTX_BSS], sta);
if (sta_id == IWL_INVALID_STATION)
return -EINVAL;
}
@@ -3371,8 +3355,8 @@ static int iwl3945_mac_sta_add(struct ieee80211_hw *hw,
sta_priv->common.sta_id = IWL_INVALID_STATION;
- ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap,
- &sta_id);
+ ret = iwl_add_station_common(priv, &priv->contexts[IWL_RXON_CTX_BSS],
+ sta->addr, is_ap, sta, &sta_id);
if (ret) {
IWL_ERR(priv, "Unable to add station %pM (%d)\n",
sta->addr, ret);
@@ -3399,6 +3383,7 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,
{
struct iwl_priv *priv = hw->priv;
__le32 filter_or = 0, filter_nand = 0;
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
#define CHK(test, flag) do { \
if (*total_flags & (test)) \
@@ -3418,8 +3403,8 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,
mutex_lock(&priv->mutex);
- priv->staging_rxon.filter_flags &= ~filter_nand;
- priv->staging_rxon.filter_flags |= filter_or;
+ ctx->staging.filter_flags &= ~filter_nand;
+ ctx->staging.filter_flags |= filter_or;
/*
* Committing directly here breaks for some reason,
@@ -3533,8 +3518,9 @@ static ssize_t show_flags(struct device *d,
struct device_attribute *attr, char *buf)
{
struct iwl_priv *priv = dev_get_drvdata(d);
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
- return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
+ return sprintf(buf, "0x%04X\n", ctx->active.flags);
}
static ssize_t store_flags(struct device *d,
@@ -3543,17 +3529,18 @@ static ssize_t store_flags(struct device *d,
{
struct iwl_priv *priv = dev_get_drvdata(d);
u32 flags = simple_strtoul(buf, NULL, 0);
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
mutex_lock(&priv->mutex);
- if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
+ if (le32_to_cpu(ctx->staging.flags) != flags) {
/* Cancel any currently running scans... */
if (iwl_scan_cancel_timeout(priv, 100))
IWL_WARN(priv, "Could not cancel scan.\n");
else {
IWL_DEBUG_INFO(priv, "Committing rxon.flags = 0x%04X\n",
flags);
- priv->staging_rxon.flags = cpu_to_le32(flags);
- iwlcore_commit_rxon(priv);
+ ctx->staging.flags = cpu_to_le32(flags);
+ iwl3945_commit_rxon(priv, ctx);
}
}
mutex_unlock(&priv->mutex);
@@ -3567,9 +3554,10 @@ static ssize_t show_filter_flags(struct device *d,
struct device_attribute *attr, char *buf)
{
struct iwl_priv *priv = dev_get_drvdata(d);
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
return sprintf(buf, "0x%04X\n",
- le32_to_cpu(priv->active_rxon.filter_flags));
+ le32_to_cpu(ctx->active.filter_flags));
}
static ssize_t store_filter_flags(struct device *d,
@@ -3577,19 +3565,20 @@ static ssize_t store_filter_flags(struct device *d,
const char *buf, size_t count)
{
struct iwl_priv *priv = dev_get_drvdata(d);
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
u32 filter_flags = simple_strtoul(buf, NULL, 0);
mutex_lock(&priv->mutex);
- if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
+ if (le32_to_cpu(ctx->staging.filter_flags) != filter_flags) {
/* Cancel any currently running scans... */
if (iwl_scan_cancel_timeout(priv, 100))
IWL_WARN(priv, "Could not cancel scan.\n");
else {
IWL_DEBUG_INFO(priv, "Committing rxon.filter_flags = "
"0x%04X\n", filter_flags);
- priv->staging_rxon.filter_flags =
+ ctx->staging.filter_flags =
cpu_to_le32(filter_flags);
- iwlcore_commit_rxon(priv);
+ iwl3945_commit_rxon(priv, ctx);
}
}
mutex_unlock(&priv->mutex);
@@ -3637,8 +3626,9 @@ static ssize_t store_measurement(struct device *d,
const char *buf, size_t count)
{
struct iwl_priv *priv = dev_get_drvdata(d);
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
struct ieee80211_measurement_params params = {
- .channel = le16_to_cpu(priv->active_rxon.channel),
+ .channel = le16_to_cpu(ctx->active.channel),
.start_time = cpu_to_le64(priv->_3945.last_tsf),
.duration = cpu_to_le16(1),
};
@@ -3785,10 +3775,8 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv)
INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
INIT_DELAYED_WORK(&priv->_3945.rfkill_poll, iwl3945_rfkill_poll);
- INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
- INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
- INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);
- INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
+
+ iwl_setup_scan_deferred_work(priv);
iwl3945_hw_setup_deferred_work(priv);
@@ -3808,12 +3796,10 @@ static void iwl3945_cancel_deferred_work(struct iwl_priv *priv)
iwl3945_hw_cancel_deferred_work(priv);
cancel_delayed_work_sync(&priv->init_alive_start);
- cancel_delayed_work(&priv->scan_check);
cancel_delayed_work(&priv->alive_start);
- cancel_work_sync(&priv->start_internal_scan);
cancel_work_sync(&priv->beacon_update);
- if (priv->cfg->ops->lib->recover_from_tx_stall)
- del_timer_sync(&priv->monitor_recover);
+
+ iwl_cancel_scan_deferred_work(priv);
}
static struct attribute *iwl3945_sysfs_entries[] = {
@@ -3853,6 +3839,7 @@ static struct ieee80211_ops iwl3945_hw_ops = {
.hw_scan = iwl_mac_hw_scan,
.sta_add = iwl3945_mac_sta_add,
.sta_remove = iwl_mac_sta_remove,
+ .tx_last_beacon = iwl_mac_tx_last_beacon,
};
static int iwl3945_init_drv(struct iwl_priv *priv)
@@ -3861,7 +3848,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
struct iwl3945_eeprom *eeprom = (struct iwl3945_eeprom *)priv->eeprom;
priv->retry_rate = 1;
- priv->ibss_beacon = NULL;
+ priv->beacon_skb = NULL;
spin_lock_init(&priv->sta_lock);
spin_lock_init(&priv->hcmd_lock);
@@ -3928,13 +3915,12 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SPECTRUM_MGMT;
- if (!priv->cfg->broken_powersave)
+ if (!priv->cfg->base_params->broken_powersave)
hw->flags |= IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
hw->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC);
+ priv->contexts[IWL_RXON_CTX_BSS].interface_modes;
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_DISABLE_BEACON_HINTS;
@@ -3966,7 +3952,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- int err = 0;
+ int err = 0, i;
struct iwl_priv *priv;
struct ieee80211_hw *hw;
struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
@@ -3988,12 +3974,33 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv = hw->priv;
SET_IEEE80211_DEV(hw, &pdev->dev);
+ priv->cmd_queue = IWL39_CMD_QUEUE_NUM;
+
+ /* 3945 has only one valid context */
+ 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].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].interface_modes =
+ BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC);
+ 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;
+
/*
* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan.
*/
if (iwl3945_mod_params.disable_hw_scan) {
- IWL_DEBUG_INFO(priv, "Disabling hw_scan\n");
+ IWL_ERR(priv, "sw scan support is deprecated\n");
iwl3945_hw_ops.hw_scan = NULL;
}
@@ -4009,6 +4016,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
/***************************
* 2. Initializing PCI bus
* *************************/
+ pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
+ PCIE_LINK_STATE_CLKPM);
+
if (pci_enable_device(pdev)) {
err = -ENODEV;
goto out_ieee80211_free_hw;
@@ -4120,7 +4130,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
}
iwl_set_rxon_channel(priv,
- &priv->bands[IEEE80211_BAND_2GHZ].channels[5]);
+ &priv->bands[IEEE80211_BAND_2GHZ].channels[5],
+ &priv->contexts[IWL_RXON_CTX_BSS]);
iwl3945_setup_deferred_work(priv);
iwl3945_setup_rx_handlers(priv);
iwl_power_initialize(priv);
@@ -4201,7 +4212,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
* paths to avoid running iwl_down() at all before leaving driver.
* This (inexpensive) call *makes sure* device is reset.
*/
- priv->cfg->ops->lib->apm_ops.stop(priv);
+ iwl_apm_stop(priv);
/* make sure we flush any pending irq or
* tasklet for the driver
@@ -4245,8 +4256,8 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
iwl_free_channel_map(priv);
iwlcore_free_geos(priv);
kfree(priv->scan_cmd);
- if (priv->ibss_beacon)
- dev_kfree_skb(priv->ibss_beacon);
+ if (priv->beacon_skb)
+ dev_kfree_skb(priv->beacon_skb);
ieee80211_free_hw(priv->hw);
}
@@ -4314,7 +4325,8 @@ MODULE_PARM_DESC(debug, "debug output mask");
#endif
module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan,
int, S_IRUGO);
-MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+MODULE_PARM_DESC(disable_hw_scan,
+ "disable hardware scanning (default 0) (deprecated)");
module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, S_IRUGO);
MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error");
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index 60619678f4ec..c6c0eff9b5ed 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -161,7 +161,7 @@ static int iwm_key_init(struct iwm_key *key, u8 key_index,
}
static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_index, const u8 *mac_addr,
+ u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
@@ -181,7 +181,8 @@ static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
}
static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_index, const u8 *mac_addr, void *cookie,
+ u8 key_index, bool pairwise, const u8 *mac_addr,
+ void *cookie,
void (*callback)(void *cookie,
struct key_params*))
{
@@ -206,7 +207,7 @@ static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_index, const u8 *mac_addr)
+ u8 key_index, bool pairwise, const u8 *mac_addr)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
struct iwm_key *key = &iwm->keys[key_index];
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index c02fcedea9fa..a944893ae3ca 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -1195,11 +1195,8 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
"oid is 0x%x\n", hdr->oid);
- if (hdr->oid <= WIFI_IF_NTFY_MAX) {
- set_bit(hdr->oid, &iwm->wifi_ntfy[0]);
- wake_up_interruptible(&iwm->wifi_ntfy_queue);
- } else
- return -EINVAL;
+ set_bit(hdr->oid, &iwm->wifi_ntfy[0]);
+ wake_up_interruptible(&iwm->wifi_ntfy_queue);
switch (hdr->oid) {
case UMAC_WIFI_IF_CMD_SET_PROFILE:
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 3e82f1627209..5046a0005034 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -10,6 +10,7 @@
#include <linux/wait.h>
#include <linux/slab.h>
#include <linux/sched.h>
+#include <linux/wait.h>
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
#include <asm/unaligned.h>
@@ -480,7 +481,6 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
int bsssize;
const u8 *pos;
- u16 nr_sets;
const u8 *tsfdesc;
int tsfsize;
int i;
@@ -489,12 +489,11 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
lbs_deb_enter(LBS_DEB_CFG80211);
bsssize = get_unaligned_le16(&scanresp->bssdescriptsize);
- nr_sets = le16_to_cpu(scanresp->nr_sets);
lbs_deb_scan("scan response: %d BSSs (%d bytes); resp size %d bytes\n",
- nr_sets, bsssize, le16_to_cpu(resp->size));
+ scanresp->nr_sets, bsssize, le16_to_cpu(resp->size));
- if (nr_sets == 0) {
+ if (scanresp->nr_sets == 0) {
ret = 0;
goto done;
}
@@ -526,20 +525,31 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
pos = scanresp->bssdesc_and_tlvbuffer;
+ lbs_deb_hex(LBS_DEB_SCAN, "SCAN_RSP", scanresp->bssdesc_and_tlvbuffer,
+ scanresp->bssdescriptsize);
+
tsfdesc = pos + bsssize;
tsfsize = 4 + 8 * scanresp->nr_sets;
+ lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TSF", (u8 *) tsfdesc, tsfsize);
/* Validity check: we expect a Marvell-Local TLV */
i = get_unaligned_le16(tsfdesc);
tsfdesc += 2;
- if (i != TLV_TYPE_TSFTIMESTAMP)
+ if (i != TLV_TYPE_TSFTIMESTAMP) {
+ lbs_deb_scan("scan response: invalid TSF Timestamp %d\n", i);
goto done;
+ }
+
/* Validity check: the TLV holds TSF values with 8 bytes each, so
* the size in the TLV must match the nr_sets value */
i = get_unaligned_le16(tsfdesc);
tsfdesc += 2;
- if (i / 8 != scanresp->nr_sets)
+ if (i / 8 != scanresp->nr_sets) {
+ lbs_deb_scan("scan response: invalid number of TSF timestamp "
+ "sets (expected %d got %d)\n", scanresp->nr_sets,
+ i / 8);
goto done;
+ }
for (i = 0; i < scanresp->nr_sets; i++) {
const u8 *bssid;
@@ -581,8 +591,11 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
id = *pos++;
elen = *pos++;
left -= 2;
- if (elen > left || elen == 0)
+ if (elen > left || elen == 0) {
+ lbs_deb_scan("scan response: invalid IE fmt\n");
goto done;
+ }
+
if (id == WLAN_EID_DS_PARAMS)
chan_no = *pos;
if (id == WLAN_EID_SSID) {
@@ -613,7 +626,9 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
capa, intvl, ie, ielen,
LBS_SCAN_RSSI_TO_MBM(rssi),
GFP_KERNEL);
- }
+ } else
+ lbs_deb_scan("scan response: missing BSS channel IE\n");
+
tsfdesc += 8;
}
ret = 0;
@@ -1103,7 +1118,7 @@ static int lbs_associate(struct lbs_private *priv,
lbs_deb_hex(LBS_DEB_ASSOC, "Common Rates", tmp, pos - tmp);
/* add auth type TLV */
- if (priv->fwrelease >= 0x09000000)
+ if (MRVL_FW_MAJOR_REV(priv->fwrelease) >= 9)
pos += lbs_add_auth_type_tlv(pos, sme->auth_type);
/* add WPA/WPA2 TLV */
@@ -1114,6 +1129,9 @@ static int lbs_associate(struct lbs_private *priv,
(u16)(pos - (u8 *) &cmd->iebuf);
cmd->hdr.size = cpu_to_le16(len);
+ lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_CMD", (u8 *) cmd,
+ le16_to_cpu(cmd->hdr.size));
+
/* store for later use */
memcpy(priv->assoc_bss, bss->bssid, ETH_ALEN);
@@ -1121,14 +1139,28 @@ static int lbs_associate(struct lbs_private *priv,
if (ret)
goto done;
-
/* generate connect message to cfg80211 */
resp = (void *) cmd; /* recast for easier field access */
status = le16_to_cpu(resp->statuscode);
- /* Convert statis code of old firmware */
- if (priv->fwrelease < 0x09000000)
+ /* Older FW versions map the IEEE 802.11 Status Code in the association
+ * response to the following values returned in resp->statuscode:
+ *
+ * IEEE Status Code Marvell Status Code
+ * 0 -> 0x0000 ASSOC_RESULT_SUCCESS
+ * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
+ * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
+ * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
+ * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
+ * others -> 0x0003 ASSOC_RESULT_REFUSED
+ *
+ * Other response codes:
+ * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
+ * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
+ * association response from the AP)
+ */
+ if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) {
switch (status) {
case 0:
break;
@@ -1150,11 +1182,16 @@ static int lbs_associate(struct lbs_private *priv,
break;
default:
lbs_deb_assoc("association failure %d\n", status);
- status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ /* v5 OLPC firmware does return the AP status code if
+ * it's not one of the values above. Let that through.
+ */
+ break;
+ }
}
- lbs_deb_assoc("status %d, capability 0x%04x\n", status,
- le16_to_cpu(resp->capability));
+ lbs_deb_assoc("status %d, statuscode 0x%04x, capability 0x%04x, "
+ "aid 0x%04x\n", status, le16_to_cpu(resp->statuscode),
+ le16_to_cpu(resp->capability), le16_to_cpu(resp->aid));
resp_ie_len = le16_to_cpu(resp->hdr.size)
- sizeof(resp->hdr)
@@ -1174,7 +1211,6 @@ static int lbs_associate(struct lbs_private *priv,
netif_tx_wake_all_queues(priv->dev);
}
-
done:
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
return ret;
@@ -1404,7 +1440,7 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy,
static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
- u8 idx, const u8 *mac_addr,
+ u8 idx, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
struct lbs_private *priv = wiphy_priv(wiphy);
@@ -1464,7 +1500,7 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev,
- u8 key_index, const u8 *mac_addr)
+ u8 key_index, bool pairwise, const u8 *mac_addr)
{
lbs_deb_enter(LBS_DEB_CFG80211);
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 1d141fefd767..2ae752d10065 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -8,7 +8,14 @@
#define _LBS_DECL_H_
#include <linux/netdevice.h>
+#include <linux/firmware.h>
+/* Should be terminated by a NULL entry */
+struct lbs_fw_table {
+ int model;
+ const char *helper;
+ const char *fwname;
+};
struct lbs_private;
struct sk_buff;
@@ -53,4 +60,10 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
u32 lbs_fw_index_to_data_rate(u8 index);
u8 lbs_data_rate_to_fw_index(u32 rate);
+int lbs_get_firmware(struct device *dev, const char *user_helper,
+ const char *user_mainfw, u32 card_model,
+ const struct lbs_fw_table *fw_table,
+ const struct firmware **helper,
+ const struct firmware **mainfw);
+
#endif
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index ff1280f41336..fc8121190d38 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -47,7 +47,6 @@
MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("libertas_cs_helper.fw");
@@ -60,9 +59,34 @@ struct if_cs_card {
struct lbs_private *priv;
void __iomem *iobase;
bool align_regs;
+ u32 model;
};
+enum {
+ MODEL_UNKNOWN = 0x00,
+ MODEL_8305 = 0x01,
+ MODEL_8381 = 0x02,
+ MODEL_8385 = 0x03
+};
+
+static const struct lbs_fw_table fw_table[] = {
+ { MODEL_8305, "libertas/cf8305.bin", NULL },
+ { MODEL_8305, "libertas_cs_helper.fw", NULL },
+ { MODEL_8381, "libertas/cf8381_helper.bin", "libertas/cf8381.bin" },
+ { MODEL_8381, "libertas_cs_helper.fw", "libertas_cs.fw" },
+ { MODEL_8385, "libertas/cf8385_helper.bin", "libertas/cf8385.bin" },
+ { MODEL_8385, "libertas_cs_helper.fw", "libertas_cs.fw" },
+ { 0, NULL, NULL }
+};
+MODULE_FIRMWARE("libertas/cf8305.bin");
+MODULE_FIRMWARE("libertas/cf8381_helper.bin");
+MODULE_FIRMWARE("libertas/cf8381.bin");
+MODULE_FIRMWARE("libertas/cf8385_helper.bin");
+MODULE_FIRMWARE("libertas/cf8385.bin");
+MODULE_FIRMWARE("libertas_cs_helper.fw");
+MODULE_FIRMWARE("libertas_cs.fw");
+
/********************************************************************/
/* Hardware access */
@@ -288,22 +312,19 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
#define CF8385_MANFID 0x02df
#define CF8385_CARDID 0x8103
-static inline int if_cs_hw_is_cf8305(struct pcmcia_device *p_dev)
-{
- return (p_dev->manf_id == CF8305_MANFID &&
- p_dev->card_id == CF8305_CARDID);
-}
-
-static inline int if_cs_hw_is_cf8381(struct pcmcia_device *p_dev)
-{
- return (p_dev->manf_id == CF8381_MANFID &&
- p_dev->card_id == CF8381_CARDID);
-}
-
-static inline int if_cs_hw_is_cf8385(struct pcmcia_device *p_dev)
+/* FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when
+ * that gets fixed. Currently there's no way to access it from the probe hook.
+ */
+static inline u32 get_model(u16 manf_id, u16 card_id)
{
- return (p_dev->manf_id == CF8385_MANFID &&
- p_dev->card_id == CF8385_CARDID);
+ /* NOTE: keep in sync with if_cs_ids */
+ if (manf_id == CF8305_MANFID && card_id == CF8305_CARDID)
+ return MODEL_8305;
+ else if (manf_id == CF8381_MANFID && card_id == CF8381_CARDID)
+ return MODEL_8381;
+ else if (manf_id == CF8385_MANFID && card_id == CF8385_CARDID)
+ return MODEL_8385;
+ return MODEL_UNKNOWN;
}
/********************************************************************/
@@ -557,12 +578,11 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
*
* Return 0 on success
*/
-static int if_cs_prog_helper(struct if_cs_card *card)
+static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
{
int ret = 0;
int sent = 0;
u8 scratch;
- const struct firmware *fw;
lbs_deb_enter(LBS_DEB_CS);
@@ -588,14 +608,6 @@ static int if_cs_prog_helper(struct if_cs_card *card)
goto done;
}
- /* TODO: make firmware file configurable */
- ret = request_firmware(&fw, "libertas_cs_helper.fw",
- &card->p_dev->dev);
- if (ret) {
- lbs_pr_err("can't load helper firmware\n");
- ret = -ENODEV;
- goto done;
- }
lbs_deb_cs("helper size %td\n", fw->size);
/* "Set the 5 bytes of the helper image to 0" */
@@ -634,7 +646,7 @@ static int if_cs_prog_helper(struct if_cs_card *card)
if (ret < 0) {
lbs_pr_err("can't download helper at 0x%x, ret %d\n",
sent, ret);
- goto err_release;
+ goto done;
}
if (count == 0)
@@ -643,17 +655,14 @@ static int if_cs_prog_helper(struct if_cs_card *card)
sent += count;
}
-err_release:
- release_firmware(fw);
done:
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
return ret;
}
-static int if_cs_prog_real(struct if_cs_card *card)
+static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
{
- const struct firmware *fw;
int ret = 0;
int retry = 0;
int len = 0;
@@ -661,21 +670,13 @@ static int if_cs_prog_real(struct if_cs_card *card)
lbs_deb_enter(LBS_DEB_CS);
- /* TODO: make firmware file configurable */
- ret = request_firmware(&fw, "libertas_cs.fw",
- &card->p_dev->dev);
- if (ret) {
- lbs_pr_err("can't load firmware\n");
- ret = -ENODEV;
- goto done;
- }
lbs_deb_cs("fw size %td\n", fw->size);
ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW,
IF_CS_SQ_HELPER_OK);
if (ret < 0) {
lbs_pr_err("helper firmware doesn't answer\n");
- goto err_release;
+ goto done;
}
for (sent = 0; sent < fw->size; sent += len) {
@@ -690,7 +691,7 @@ static int if_cs_prog_real(struct if_cs_card *card)
if (retry > 20) {
lbs_pr_err("could not download firmware\n");
ret = -ENODEV;
- goto err_release;
+ goto done;
}
if (retry) {
sent -= len;
@@ -709,7 +710,7 @@ static int if_cs_prog_real(struct if_cs_card *card)
IF_CS_BIT_COMMAND);
if (ret < 0) {
lbs_pr_err("can't download firmware at 0x%x\n", sent);
- goto err_release;
+ goto done;
}
}
@@ -717,9 +718,6 @@ static int if_cs_prog_real(struct if_cs_card *card)
if (ret < 0)
lbs_pr_err("firmware download failed\n");
-err_release:
- release_firmware(fw);
-
done:
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
return ret;
@@ -795,6 +793,8 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
unsigned int prod_id;
struct lbs_private *priv;
struct if_cs_card *card;
+ const struct firmware *helper = NULL;
+ const struct firmware *mainfw = NULL;
lbs_deb_enter(LBS_DEB_CS);
@@ -845,34 +845,47 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
*/
card->align_regs = 0;
+ card->model = get_model(p_dev->manf_id, p_dev->card_id);
+ if (card->model == MODEL_UNKNOWN) {
+ lbs_pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
+ p_dev->manf_id, p_dev->card_id);
+ goto out2;
+ }
+
/* Check if we have a current silicon */
prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID);
- if (if_cs_hw_is_cf8305(p_dev)) {
+ if (card->model == MODEL_8305) {
card->align_regs = 1;
if (prod_id < IF_CS_CF8305_B1_REV) {
- lbs_pr_err("old chips like 8305 rev B3 "
- "aren't supported\n");
+ lbs_pr_err("8305 rev B0 and older are not supported\n");
ret = -ENODEV;
goto out2;
}
}
- if (if_cs_hw_is_cf8381(p_dev) && prod_id < IF_CS_CF8381_B3_REV) {
- lbs_pr_err("old chips like 8381 rev B3 aren't supported\n");
+ if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) {
+ lbs_pr_err("8381 rev B2 and older are not supported\n");
ret = -ENODEV;
goto out2;
}
- if (if_cs_hw_is_cf8385(p_dev) && prod_id < IF_CS_CF8385_B1_REV) {
- lbs_pr_err("old chips like 8385 rev B1 aren't supported\n");
+ if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) {
+ lbs_pr_err("8385 rev B0 and older are not supported\n");
ret = -ENODEV;
goto out2;
}
+ ret = lbs_get_firmware(&p_dev->dev, NULL, NULL, card->model,
+ &fw_table[0], &helper, &mainfw);
+ if (ret) {
+ lbs_pr_err("failed to find firmware (%d)\n", ret);
+ goto out2;
+ }
+
/* Load the firmware early, before calling into libertas.ko */
- ret = if_cs_prog_helper(card);
- if (ret == 0 && !if_cs_hw_is_cf8305(p_dev))
- ret = if_cs_prog_real(card);
+ ret = if_cs_prog_helper(card, helper);
+ if (ret == 0 && (card->model != MODEL_8305))
+ ret = if_cs_prog_real(card, mainfw);
if (ret)
goto out2;
@@ -921,6 +934,11 @@ out2:
out1:
pcmcia_disable_device(p_dev);
out:
+ if (helper)
+ release_firmware(helper);
+ if (mainfw)
+ release_firmware(mainfw);
+
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
return ret;
}
@@ -951,6 +969,7 @@ static struct pcmcia_device_id if_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
+ /* NOTE: keep in sync with get_model() */
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 87b634978b35..296fd00a5129 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -76,36 +76,32 @@ static const struct sdio_device_id if_sdio_ids[] = {
MODULE_DEVICE_TABLE(sdio, if_sdio_ids);
-struct if_sdio_model {
- int model;
- const char *helper;
- const char *firmware;
-};
-
-static struct if_sdio_model if_sdio_models[] = {
- {
- /* 8385 */
- .model = IF_SDIO_MODEL_8385,
- .helper = "sd8385_helper.bin",
- .firmware = "sd8385.bin",
- },
- {
- /* 8686 */
- .model = IF_SDIO_MODEL_8686,
- .helper = "sd8686_helper.bin",
- .firmware = "sd8686.bin",
- },
- {
- /* 8688 */
- .model = IF_SDIO_MODEL_8688,
- .helper = "sd8688_helper.bin",
- .firmware = "sd8688.bin",
- },
+#define MODEL_8385 0x04
+#define MODEL_8686 0x0b
+#define MODEL_8688 0x10
+
+static const struct lbs_fw_table fw_table[] = {
+ { MODEL_8385, "libertas/sd8385_helper.bin", "libertas/sd8385.bin" },
+ { MODEL_8385, "sd8385_helper.bin", "sd8385.bin" },
+ { MODEL_8686, "libertas/sd8686_v9_helper.bin", "libertas/sd8686_v9.bin" },
+ { MODEL_8686, "libertas/sd8686_v8_helper.bin", "libertas/sd8686_v8.bin" },
+ { MODEL_8686, "sd8686_helper.bin", "sd8686.bin" },
+ { MODEL_8688, "libertas/sd8688_helper.bin", "libertas/sd8688.bin" },
+ { MODEL_8688, "sd8688_helper.bin", "sd8688.bin" },
+ { 0, NULL, NULL }
};
+MODULE_FIRMWARE("libertas/sd8385_helper.bin");
+MODULE_FIRMWARE("libertas/sd8385.bin");
MODULE_FIRMWARE("sd8385_helper.bin");
MODULE_FIRMWARE("sd8385.bin");
+MODULE_FIRMWARE("libertas/sd8686_v9_helper.bin");
+MODULE_FIRMWARE("libertas/sd8686_v9.bin");
+MODULE_FIRMWARE("libertas/sd8686_v8_helper.bin");
+MODULE_FIRMWARE("libertas/sd8686_v8.bin");
MODULE_FIRMWARE("sd8686_helper.bin");
MODULE_FIRMWARE("sd8686.bin");
+MODULE_FIRMWARE("libertas/sd8688_helper.bin");
+MODULE_FIRMWARE("libertas/sd8688.bin");
MODULE_FIRMWARE("sd8688_helper.bin");
MODULE_FIRMWARE("sd8688.bin");
@@ -187,11 +183,11 @@ static u16 if_sdio_read_rx_len(struct if_sdio_card *card, int *err)
u16 rx_len;
switch (card->model) {
- case IF_SDIO_MODEL_8385:
- case IF_SDIO_MODEL_8686:
+ case MODEL_8385:
+ case MODEL_8686:
rx_len = if_sdio_read_scratch(card, &ret);
break;
- case IF_SDIO_MODEL_8688:
+ case MODEL_8688:
default: /* for newer chipsets */
rx_len = sdio_readb(card->func, IF_SDIO_RX_LEN, &ret);
if (!ret)
@@ -288,7 +284,7 @@ static int if_sdio_handle_event(struct if_sdio_card *card,
lbs_deb_enter(LBS_DEB_SDIO);
- if (card->model == IF_SDIO_MODEL_8385) {
+ if (card->model == MODEL_8385) {
event = sdio_readb(card->func, IF_SDIO_EVENT, &ret);
if (ret)
goto out;
@@ -466,10 +462,10 @@ static void if_sdio_host_to_card_worker(struct work_struct *work)
#define FW_DL_READY_STATUS (IF_SDIO_IO_RDY | IF_SDIO_DL_RDY)
-static int if_sdio_prog_helper(struct if_sdio_card *card)
+static int if_sdio_prog_helper(struct if_sdio_card *card,
+ const struct firmware *fw)
{
int ret;
- const struct firmware *fw;
unsigned long timeout;
u8 *chunk_buffer;
u32 chunk_size;
@@ -478,16 +474,10 @@ static int if_sdio_prog_helper(struct if_sdio_card *card)
lbs_deb_enter(LBS_DEB_SDIO);
- ret = request_firmware(&fw, card->helper, &card->func->dev);
- if (ret) {
- lbs_pr_err("can't load helper firmware\n");
- goto out;
- }
-
chunk_buffer = kzalloc(64, GFP_KERNEL);
if (!chunk_buffer) {
ret = -ENOMEM;
- goto release_fw;
+ goto out;
}
sdio_claim_host(card->func);
@@ -562,22 +552,19 @@ static int if_sdio_prog_helper(struct if_sdio_card *card)
release:
sdio_release_host(card->func);
kfree(chunk_buffer);
-release_fw:
- release_firmware(fw);
out:
if (ret)
lbs_pr_err("failed to load helper firmware\n");
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-
return ret;
}
-static int if_sdio_prog_real(struct if_sdio_card *card)
+static int if_sdio_prog_real(struct if_sdio_card *card,
+ const struct firmware *fw)
{
int ret;
- const struct firmware *fw;
unsigned long timeout;
u8 *chunk_buffer;
u32 chunk_size;
@@ -586,16 +573,10 @@ static int if_sdio_prog_real(struct if_sdio_card *card)
lbs_deb_enter(LBS_DEB_SDIO);
- ret = request_firmware(&fw, card->firmware, &card->func->dev);
- if (ret) {
- lbs_pr_err("can't load firmware\n");
- goto out;
- }
-
chunk_buffer = kzalloc(512, GFP_KERNEL);
if (!chunk_buffer) {
ret = -ENOMEM;
- goto release_fw;
+ goto out;
}
sdio_claim_host(card->func);
@@ -685,15 +666,12 @@ static int if_sdio_prog_real(struct if_sdio_card *card)
release:
sdio_release_host(card->func);
kfree(chunk_buffer);
-release_fw:
- release_firmware(fw);
out:
if (ret)
lbs_pr_err("failed to load firmware\n");
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-
return ret;
}
@@ -701,6 +679,8 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
{
int ret;
u16 scratch;
+ const struct firmware *helper = NULL;
+ const struct firmware *mainfw = NULL;
lbs_deb_enter(LBS_DEB_SDIO);
@@ -718,11 +698,18 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
goto success;
}
- ret = if_sdio_prog_helper(card);
+ ret = lbs_get_firmware(&card->func->dev, lbs_helper_name, lbs_fw_name,
+ card->model, &fw_table[0], &helper, &mainfw);
+ if (ret) {
+ lbs_pr_err("failed to find firmware (%d)\n", ret);
+ goto out;
+ }
+
+ ret = if_sdio_prog_helper(card, helper);
if (ret)
goto out;
- ret = if_sdio_prog_real(card);
+ ret = if_sdio_prog_real(card, mainfw);
if (ret)
goto out;
@@ -733,8 +720,12 @@ success:
ret = 0;
out:
- lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+ if (helper)
+ release_firmware(helper);
+ if (mainfw)
+ release_firmware(mainfw);
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
return ret;
}
@@ -938,7 +929,7 @@ static int if_sdio_probe(struct sdio_func *func,
"ID: %x", &model) == 1)
break;
if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {
- model = IF_SDIO_MODEL_8385;
+ model = MODEL_8385;
break;
}
}
@@ -956,13 +947,13 @@ static int if_sdio_probe(struct sdio_func *func,
card->model = model;
switch (card->model) {
- case IF_SDIO_MODEL_8385:
+ case MODEL_8385:
card->scratch_reg = IF_SDIO_SCRATCH_OLD;
break;
- case IF_SDIO_MODEL_8686:
+ case MODEL_8686:
card->scratch_reg = IF_SDIO_SCRATCH;
break;
- case IF_SDIO_MODEL_8688:
+ case MODEL_8688:
default: /* for newer chipsets */
card->scratch_reg = IF_SDIO_FW_STATUS;
break;
@@ -972,49 +963,17 @@ static int if_sdio_probe(struct sdio_func *func,
card->workqueue = create_workqueue("libertas_sdio");
INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
- for (i = 0;i < ARRAY_SIZE(if_sdio_models);i++) {
- if (card->model == if_sdio_models[i].model)
+ /* Check if we support this card */
+ for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
+ if (card->model == fw_table[i].model)
break;
}
-
- if (i == ARRAY_SIZE(if_sdio_models)) {
+ if (i == ARRAY_SIZE(fw_table)) {
lbs_pr_err("unknown card model 0x%x\n", card->model);
ret = -ENODEV;
goto free;
}
- card->helper = if_sdio_models[i].helper;
- card->firmware = if_sdio_models[i].firmware;
-
- kparam_block_sysfs_write(helper_name);
- if (lbs_helper_name) {
- char *helper = kstrdup(lbs_helper_name, GFP_KERNEL);
- if (!helper) {
- kparam_unblock_sysfs_write(helper_name);
- ret = -ENOMEM;
- goto free;
- }
- lbs_deb_sdio("overriding helper firmware: %s\n",
- lbs_helper_name);
- card->helper = helper;
- card->helper_allocated = true;
- }
- kparam_unblock_sysfs_write(helper_name);
-
- kparam_block_sysfs_write(fw_name);
- if (lbs_fw_name) {
- char *fw_name = kstrdup(lbs_fw_name, GFP_KERNEL);
- if (!fw_name) {
- kparam_unblock_sysfs_write(fw_name);
- ret = -ENOMEM;
- goto free;
- }
- lbs_deb_sdio("overriding firmware: %s\n", lbs_fw_name);
- card->firmware = fw_name;
- card->firmware_allocated = true;
- }
- kparam_unblock_sysfs_write(fw_name);
-
sdio_claim_host(func);
ret = sdio_enable_func(func);
@@ -1028,7 +987,7 @@ static int if_sdio_probe(struct sdio_func *func,
/* 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 == IF_SDIO_MODEL_8686) &&
+ if ((card->model == MODEL_8686) &&
(host->caps & MMC_CAP_SDIO_IRQ) &&
(host->ios.bus_width == MMC_BUS_WIDTH_1)) {
u8 reg;
@@ -1091,8 +1050,8 @@ static int if_sdio_probe(struct sdio_func *func,
* Get rx_unit if the chip is SD8688 or newer.
* SD8385 & SD8686 do not have rx_unit.
*/
- if ((card->model != IF_SDIO_MODEL_8385)
- && (card->model != IF_SDIO_MODEL_8686))
+ if ((card->model != MODEL_8385)
+ && (card->model != MODEL_8686))
card->rx_unit = if_sdio_read_rx_unit(card);
else
card->rx_unit = 0;
@@ -1108,7 +1067,7 @@ static int if_sdio_probe(struct sdio_func *func,
/*
* FUNC_INIT is required for SD8688 WLAN/BT multiple functions
*/
- if (card->model == IF_SDIO_MODEL_8688) {
+ if (card->model == MODEL_8688) {
struct cmd_header cmd;
memset(&cmd, 0, sizeof(cmd));
@@ -1165,7 +1124,7 @@ static void if_sdio_remove(struct sdio_func *func)
card = sdio_get_drvdata(func);
- if (user_rmmod && (card->model == IF_SDIO_MODEL_8688)) {
+ if (user_rmmod && (card->model == MODEL_8688)) {
/*
* FUNC_SHUTDOWN is required for SD8688 WLAN/BT
* multiple functions
diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h
index 12179c1dc9c9..62fda3592f67 100644
--- a/drivers/net/wireless/libertas/if_sdio.h
+++ b/drivers/net/wireless/libertas/if_sdio.h
@@ -12,10 +12,6 @@
#ifndef _LBS_IF_SDIO_H
#define _LBS_IF_SDIO_H
-#define IF_SDIO_MODEL_8385 0x04
-#define IF_SDIO_MODEL_8686 0x0b
-#define IF_SDIO_MODEL_8688 0x10
-
#define IF_SDIO_IOPORT 0x00
#define IF_SDIO_H_INT_MASK 0x04
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index fe3f08028eb3..79bcb4e5d2ca 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -39,9 +39,6 @@ struct if_spi_card {
struct lbs_private *priv;
struct libertas_spi_platform_data *pdata;
- char helper_fw_name[IF_SPI_FW_NAME_MAX];
- char main_fw_name[IF_SPI_FW_NAME_MAX];
-
/* The card ID and card revision, as reported by the hardware. */
u16 card_id;
u8 card_rev;
@@ -70,10 +67,28 @@ static void free_if_spi_card(struct if_spi_card *card)
kfree(card);
}
-static struct chip_ident chip_id_to_device_name[] = {
- { .chip_id = 0x04, .name = 8385 },
- { .chip_id = 0x0b, .name = 8686 },
+#define MODEL_8385 0x04
+#define MODEL_8686 0x0b
+#define MODEL_8688 0x10
+
+static const struct lbs_fw_table fw_table[] = {
+ { MODEL_8385, "libertas/gspi8385_helper.bin", "libertas/gspi8385.bin" },
+ { MODEL_8385, "libertas/gspi8385_hlp.bin", "libertas/gspi8385.bin" },
+ { MODEL_8686, "libertas/gspi8686_v9_helper.bin", "libertas/gspi8686_v9.bin" },
+ { MODEL_8686, "libertas/gspi8686_hlp.bin", "libertas/gspi8686.bin" },
+ { MODEL_8688, "libertas/gspi8688_helper.bin", "libertas/gspi8688.bin" },
+ { 0, NULL, NULL }
};
+MODULE_FIRMWARE("libertas/gspi8385_helper.bin");
+MODULE_FIRMWARE("libertas/gspi8385_hlp.bin");
+MODULE_FIRMWARE("libertas/gspi8385.bin");
+MODULE_FIRMWARE("libertas/gspi8686_v9_helper.bin");
+MODULE_FIRMWARE("libertas/gspi8686_v9.bin");
+MODULE_FIRMWARE("libertas/gspi8686_hlp.bin");
+MODULE_FIRMWARE("libertas/gspi8686.bin");
+MODULE_FIRMWARE("libertas/gspi8688_helper.bin");
+MODULE_FIRMWARE("libertas/gspi8688.bin");
+
/*
* SPI Interface Unit Routines
@@ -399,26 +414,20 @@ static int spu_init(struct if_spi_card *card, int use_dummy_writes)
* Firmware Loading
*/
-static int if_spi_prog_helper_firmware(struct if_spi_card *card)
+static int if_spi_prog_helper_firmware(struct if_spi_card *card,
+ const struct firmware *firmware)
{
int err = 0;
- const struct firmware *firmware = NULL;
int bytes_remaining;
const u8 *fw;
u8 temp[HELPER_FW_LOAD_CHUNK_SZ];
- struct spi_device *spi = card->spi;
lbs_deb_enter(LBS_DEB_SPI);
err = spu_set_interrupt_mode(card, 1, 0);
if (err)
goto out;
- /* Get helper firmware image */
- err = request_firmware(&firmware, card->helper_fw_name, &spi->dev);
- if (err) {
- lbs_pr_err("request_firmware failed with err = %d\n", err);
- goto out;
- }
+
bytes_remaining = firmware->size;
fw = firmware->data;
@@ -429,13 +438,13 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card)
err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG,
HELPER_FW_LOAD_CHUNK_SZ);
if (err)
- goto release_firmware;
+ goto out;
err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
IF_SPI_HIST_CMD_DOWNLOAD_RDY,
IF_SPI_HIST_CMD_DOWNLOAD_RDY);
if (err)
- goto release_firmware;
+ goto out;
/* Feed the data into the command read/write port reg
* in chunks of 64 bytes */
@@ -446,16 +455,16 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card)
err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG,
temp, HELPER_FW_LOAD_CHUNK_SZ);
if (err)
- goto release_firmware;
+ goto out;
/* Interrupt the boot code */
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
if (err)
- goto release_firmware;
+ goto out;
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
IF_SPI_CIC_CMD_DOWNLOAD_OVER);
if (err)
- goto release_firmware;
+ goto out;
bytes_remaining -= HELPER_FW_LOAD_CHUNK_SZ;
fw += HELPER_FW_LOAD_CHUNK_SZ;
}
@@ -465,18 +474,16 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card)
* bootloader. This completes the helper download. */
err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK);
if (err)
- goto release_firmware;
+ goto out;
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
if (err)
- goto release_firmware;
+ goto out;
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
IF_SPI_CIC_CMD_DOWNLOAD_OVER);
- goto release_firmware;
+ goto out;
lbs_deb_spi("waiting for helper to boot...\n");
-release_firmware:
- release_firmware(firmware);
out:
if (err)
lbs_pr_err("failed to load helper firmware (err=%d)\n", err);
@@ -523,13 +530,12 @@ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
return len;
}
-static int if_spi_prog_main_firmware(struct if_spi_card *card)
+static int if_spi_prog_main_firmware(struct if_spi_card *card,
+ const struct firmware *firmware)
{
int len, prev_len;
int bytes, crc_err = 0, err = 0;
- const struct firmware *firmware = NULL;
const u8 *fw;
- struct spi_device *spi = card->spi;
u16 num_crc_errs;
lbs_deb_enter(LBS_DEB_SPI);
@@ -538,19 +544,11 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card)
if (err)
goto out;
- /* Get firmware image */
- err = request_firmware(&firmware, card->main_fw_name, &spi->dev);
- if (err) {
- lbs_pr_err("%s: can't get firmware '%s' from kernel. "
- "err = %d\n", __func__, card->main_fw_name, err);
- goto out;
- }
-
err = spu_wait_for_u16(card, IF_SPI_SCRATCH_1_REG, 0, 0);
if (err) {
lbs_pr_err("%s: timed out waiting for initial "
"scratch reg = 0\n", __func__);
- goto release_firmware;
+ goto out;
}
num_crc_errs = 0;
@@ -560,7 +558,7 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card)
while ((len = if_spi_prog_main_firmware_check_len(card, &crc_err))) {
if (len < 0) {
err = len;
- goto release_firmware;
+ goto out;
}
if (bytes < 0) {
/* If there are no more bytes left, we would normally
@@ -575,7 +573,7 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card)
lbs_pr_err("Too many CRC errors encountered "
"in firmware load.\n");
err = -EIO;
- goto release_firmware;
+ goto out;
}
} else {
/* Previous transfer succeeded. Advance counters. */
@@ -590,15 +588,15 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card)
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
if (err)
- goto release_firmware;
+ goto out;
err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG,
card->cmd_buffer, len);
if (err)
- goto release_firmware;
+ goto out;
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG ,
IF_SPI_CIC_CMD_DOWNLOAD_OVER);
if (err)
- goto release_firmware;
+ goto out;
prev_len = len;
}
if (bytes > prev_len) {
@@ -611,12 +609,9 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card)
SUCCESSFUL_FW_DOWNLOAD_MAGIC);
if (err) {
lbs_pr_err("failed to confirm the firmware download\n");
- goto release_firmware;
+ goto out;
}
-release_firmware:
- release_firmware(firmware);
-
out:
if (err)
lbs_pr_err("failed to load firmware (err=%d)\n", err);
@@ -800,14 +795,16 @@ static int lbs_spi_thread(void *data)
goto err;
}
- if (hiStatus & IF_SPI_HIST_CMD_UPLOAD_RDY)
+ if (hiStatus & IF_SPI_HIST_CMD_UPLOAD_RDY) {
err = if_spi_c2h_cmd(card);
if (err)
goto err;
- if (hiStatus & IF_SPI_HIST_RX_UPLOAD_RDY)
+ }
+ if (hiStatus & IF_SPI_HIST_RX_UPLOAD_RDY) {
err = if_spi_c2h_data(card);
if (err)
goto err;
+ }
/* workaround: in PS mode, the card does not set the Command
* Download Ready bit, but it sets TX Download Ready. */
@@ -886,37 +883,16 @@ static irqreturn_t if_spi_host_interrupt(int irq, void *dev_id)
* SPI callbacks
*/
-static int if_spi_calculate_fw_names(u16 card_id,
- char *helper_fw, char *main_fw)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(chip_id_to_device_name); ++i) {
- if (card_id == chip_id_to_device_name[i].chip_id)
- break;
- }
- if (i == ARRAY_SIZE(chip_id_to_device_name)) {
- lbs_pr_err("Unsupported chip_id: 0x%02x\n", card_id);
- return -EAFNOSUPPORT;
- }
- snprintf(helper_fw, IF_SPI_FW_NAME_MAX, "libertas/gspi%d_hlp.bin",
- chip_id_to_device_name[i].name);
- snprintf(main_fw, IF_SPI_FW_NAME_MAX, "libertas/gspi%d.bin",
- chip_id_to_device_name[i].name);
- return 0;
-}
-MODULE_FIRMWARE("libertas/gspi8385_hlp.bin");
-MODULE_FIRMWARE("libertas/gspi8385.bin");
-MODULE_FIRMWARE("libertas/gspi8686_hlp.bin");
-MODULE_FIRMWARE("libertas/gspi8686.bin");
-
static int __devinit if_spi_probe(struct spi_device *spi)
{
struct if_spi_card *card;
struct lbs_private *priv = NULL;
struct libertas_spi_platform_data *pdata = spi->dev.platform_data;
- int err = 0;
+ int err = 0, i;
u32 scratch;
struct sched_param param = { .sched_priority = 1 };
+ const struct firmware *helper = NULL;
+ const struct firmware *mainfw = NULL;
lbs_deb_enter(LBS_DEB_SPI);
@@ -961,10 +937,25 @@ static int __devinit if_spi_probe(struct spi_device *spi)
lbs_deb_spi("Firmware is already loaded for "
"Marvell WLAN 802.11 adapter\n");
else {
- err = if_spi_calculate_fw_names(card->card_id,
- card->helper_fw_name, card->main_fw_name);
- if (err)
+ /* Check if we support this card */
+ for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
+ if (card->card_id == fw_table[i].model)
+ break;
+ }
+ if (i == ARRAY_SIZE(fw_table)) {
+ lbs_pr_err("Unsupported chip_id: 0x%02x\n",
+ card->card_id);
+ err = -ENODEV;
goto free_card;
+ }
+
+ err = lbs_get_firmware(&card->spi->dev, NULL, NULL,
+ card->card_id, &fw_table[0], &helper,
+ &mainfw);
+ if (err) {
+ lbs_pr_err("failed to find firmware (%d)\n", err);
+ goto free_card;
+ }
lbs_deb_spi("Initializing FW for Marvell WLAN 802.11 adapter "
"(chip_id = 0x%04x, chip_rev = 0x%02x) "
@@ -973,10 +964,10 @@ static int __devinit if_spi_probe(struct spi_device *spi)
card->card_id, card->card_rev,
spi->master->bus_num, spi->chip_select,
spi->max_speed_hz);
- err = if_spi_prog_helper_firmware(card);
+ err = if_spi_prog_helper_firmware(card, helper);
if (err)
goto free_card;
- err = if_spi_prog_main_firmware(card);
+ err = if_spi_prog_main_firmware(card, mainfw);
if (err)
goto free_card;
lbs_deb_spi("loaded FW for Marvell WLAN 802.11 adapter\n");
@@ -1044,6 +1035,11 @@ remove_card:
free_card:
free_if_spi_card(card);
out:
+ if (helper)
+ release_firmware(helper);
+ if (mainfw)
+ release_firmware(mainfw);
+
lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err);
return err;
}
diff --git a/drivers/net/wireless/libertas/if_spi.h b/drivers/net/wireless/libertas/if_spi.h
index f87eec410848..8b1417d3b71b 100644
--- a/drivers/net/wireless/libertas/if_spi.h
+++ b/drivers/net/wireless/libertas/if_spi.h
@@ -25,11 +25,6 @@
#define IF_SPI_FW_NAME_MAX 30
-struct chip_ident {
- u16 chip_id;
- u16 name;
-};
-
#define MAX_MAIN_FW_LOAD_CRC_ERR 10
/* Chunk size when loading the helper firmware */
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 3ff61063671a..efaf85032208 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -26,15 +26,25 @@
#define MESSAGE_HEADER_LEN 4
-static char *lbs_fw_name = "usb8388.bin";
+static char *lbs_fw_name = NULL;
module_param_named(fw_name, lbs_fw_name, charp, 0644);
+MODULE_FIRMWARE("libertas/usb8388_v9.bin");
+MODULE_FIRMWARE("libertas/usb8388_v5.bin");
+MODULE_FIRMWARE("libertas/usb8388.bin");
+MODULE_FIRMWARE("libertas/usb8682.bin");
MODULE_FIRMWARE("usb8388.bin");
+enum {
+ MODEL_UNKNOWN = 0x0,
+ MODEL_8388 = 0x1,
+ MODEL_8682 = 0x2
+};
+
static struct usb_device_id if_usb_table[] = {
/* Enter the device signature inside */
- { USB_DEVICE(0x1286, 0x2001) },
- { USB_DEVICE(0x05a3, 0x8388) },
+ { USB_DEVICE(0x1286, 0x2001), .driver_info = MODEL_8388 },
+ { USB_DEVICE(0x05a3, 0x8388), .driver_info = MODEL_8388 },
{} /* Terminating entry */
};
@@ -66,6 +76,8 @@ static ssize_t if_usb_firmware_set(struct device *dev,
struct if_usb_card *cardp = priv->card;
int ret;
+ BUG_ON(buf == NULL);
+
ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_FW);
if (ret == 0)
return count;
@@ -91,6 +103,8 @@ static ssize_t if_usb_boot2_set(struct device *dev,
struct if_usb_card *cardp = priv->card;
int ret;
+ BUG_ON(buf == NULL);
+
ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_BOOT2);
if (ret == 0)
return count;
@@ -244,6 +258,7 @@ static int if_usb_probe(struct usb_interface *intf,
init_waitqueue_head(&cardp->fw_wq);
cardp->udev = udev;
+ cardp->model = (uint32_t) id->driver_info;
iface_desc = intf->cur_altsetting;
lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
@@ -472,11 +487,12 @@ static int if_usb_reset_device(struct if_usb_card *cardp)
*/
static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb)
{
- int ret = -1;
+ int ret;
/* check if device is removed */
if (cardp->surprise_removed) {
lbs_deb_usbd(&cardp->udev->dev, "Device removed\n");
+ ret = -ENODEV;
goto tx_ret;
}
@@ -489,7 +505,6 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb
if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) {
lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
- ret = -1;
} else {
lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n");
ret = 0;
@@ -924,6 +939,38 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp,
return ret;
}
+/* table of firmware file names */
+static const struct {
+ u32 model;
+ const char *fwname;
+} fw_table[] = {
+ { MODEL_8388, "libertas/usb8388_v9.bin" },
+ { MODEL_8388, "libertas/usb8388_v5.bin" },
+ { MODEL_8388, "libertas/usb8388.bin" },
+ { MODEL_8388, "usb8388.bin" },
+ { MODEL_8682, "libertas/usb8682.bin" }
+};
+
+static int get_fw(struct if_usb_card *cardp, const char *fwname)
+{
+ int i;
+
+ /* Try user-specified firmware first */
+ if (fwname)
+ return request_firmware(&cardp->fw, fwname, &cardp->udev->dev);
+
+ /* Otherwise search for firmware to use */
+ for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
+ if (fw_table[i].model != cardp->model)
+ continue;
+ if (request_firmware(&cardp->fw, fw_table[i].fwname,
+ &cardp->udev->dev) == 0)
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
static int __if_usb_prog_firmware(struct if_usb_card *cardp,
const char *fwname, int cmd)
{
@@ -933,10 +980,9 @@ static int __if_usb_prog_firmware(struct if_usb_card *cardp,
lbs_deb_enter(LBS_DEB_USB);
- ret = request_firmware(&cardp->fw, fwname, &cardp->udev->dev);
- if (ret < 0) {
- lbs_pr_err("request_firmware() failed with %#x\n", ret);
- lbs_pr_err("firmware %s not found\n", fwname);
+ ret = get_fw(cardp, fwname);
+ if (ret) {
+ lbs_pr_err("failed to find firmware (%d)\n", ret);
goto done;
}
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
index 5ba0aee0eb2f..d819e7e3c9aa 100644
--- a/drivers/net/wireless/libertas/if_usb.h
+++ b/drivers/net/wireless/libertas/if_usb.h
@@ -43,6 +43,7 @@ struct bootcmdresp
/** USB card description structure*/
struct if_usb_card {
struct usb_device *udev;
+ uint32_t model; /* MODEL_* */
struct urb *rx_urb, *tx_urb;
struct lbs_private *priv;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 24958a86747b..47ce5a6ba120 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -1047,6 +1047,111 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
}
EXPORT_SYMBOL_GPL(lbs_notify_command_response);
+/**
+ * @brief Retrieves two-stage firmware
+ *
+ * @param dev A pointer to device structure
+ * @param user_helper User-defined helper firmware file
+ * @param user_mainfw User-defined main firmware file
+ * @param card_model Bus-specific card model ID used to filter firmware table
+ * elements
+ * @param fw_table Table of firmware file names and device model numbers
+ * terminated by an entry with a NULL helper name
+ * @param helper On success, the helper firmware; caller must free
+ * @param mainfw On success, the main firmware; caller must free
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int lbs_get_firmware(struct device *dev, const char *user_helper,
+ const char *user_mainfw, u32 card_model,
+ const struct lbs_fw_table *fw_table,
+ const struct firmware **helper,
+ const struct firmware **mainfw)
+{
+ const struct lbs_fw_table *iter;
+ int ret;
+
+ BUG_ON(helper == NULL);
+ BUG_ON(mainfw == NULL);
+
+ /* Try user-specified firmware first */
+ if (user_helper) {
+ ret = request_firmware(helper, user_helper, dev);
+ if (ret) {
+ lbs_pr_err("couldn't find helper firmware %s",
+ user_helper);
+ goto fail;
+ }
+ }
+ if (user_mainfw) {
+ ret = request_firmware(mainfw, user_mainfw, dev);
+ if (ret) {
+ lbs_pr_err("couldn't find main firmware %s",
+ user_mainfw);
+ goto fail;
+ }
+ }
+
+ if (*helper && *mainfw)
+ return 0;
+
+ /* Otherwise search for firmware to use. If neither the helper or
+ * the main firmware were specified by the user, then we need to
+ * make sure that found helper & main are from the same entry in
+ * fw_table.
+ */
+ iter = fw_table;
+ while (iter && iter->helper) {
+ if (iter->model != card_model)
+ goto next;
+
+ if (*helper == NULL) {
+ ret = request_firmware(helper, iter->helper, dev);
+ if (ret)
+ goto next;
+
+ /* If the device has one-stage firmware (ie cf8305) and
+ * we've got it then we don't need to bother with the
+ * main firmware.
+ */
+ if (iter->fwname == NULL)
+ return 0;
+ }
+
+ if (*mainfw == NULL) {
+ ret = request_firmware(mainfw, iter->fwname, dev);
+ if (ret && !user_helper) {
+ /* Clear the helper if it wasn't user-specified
+ * and the main firmware load failed, to ensure
+ * we don't have mismatched firmware pairs.
+ */
+ release_firmware(*helper);
+ *helper = NULL;
+ }
+ }
+
+ if (*helper && *mainfw)
+ return 0;
+
+ next:
+ iter++;
+ }
+
+ fail:
+ /* Failed */
+ if (*helper) {
+ release_firmware(*helper);
+ *helper = NULL;
+ }
+ if (*mainfw) {
+ release_firmware(*mainfw);
+ *mainfw = NULL;
+ }
+
+ return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(lbs_get_firmware);
+
static int __init lbs_init_module(void)
{
lbs_deb_enter(LBS_DEB_MAIN);
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index 194762ab0142..acf3bf63ee33 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -574,7 +574,7 @@ int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted)
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_SET_INVERT);
- cmd.id = !!inverted;
+ cmd.id = cpu_to_le32(!!inverted);
ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c
index 41a4f214ade1..ba7d96584cb6 100644
--- a/drivers/net/wireless/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/libertas_tf/if_usb.c
@@ -54,7 +54,7 @@ static int if_usb_reset_device(struct if_usb_card *cardp);
/**
* if_usb_wrike_bulk_callback - call back to handle URB status
*
- * @param urb pointer to urb structure
+ * @param urb pointer to urb structure
*/
static void if_usb_write_bulk_callback(struct urb *urb)
{
@@ -178,16 +178,19 @@ static int if_usb_probe(struct usb_interface *intf,
le16_to_cpu(endpoint->wMaxPacketSize);
cardp->ep_in = usb_endpoint_num(endpoint);
- lbtf_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
- lbtf_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
+ lbtf_deb_usbd(&udev->dev, "in_endpoint = %d\n",
+ cardp->ep_in);
+ lbtf_deb_usbd(&udev->dev, "Bulk in size is %d\n",
+ cardp->ep_in_size);
} else if (usb_endpoint_is_bulk_out(endpoint)) {
cardp->ep_out_size =
le16_to_cpu(endpoint->wMaxPacketSize);
cardp->ep_out = usb_endpoint_num(endpoint);
- lbtf_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
+ lbtf_deb_usbd(&udev->dev, "out_endpoint = %d\n",
+ cardp->ep_out);
lbtf_deb_usbd(&udev->dev, "Bulk out size is %d\n",
- cardp->ep_out_size);
+ cardp->ep_out_size);
}
}
if (!cardp->ep_out_size || !cardp->ep_in_size) {
@@ -318,10 +321,12 @@ static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
lbtf_deb_usb2(&cardp->udev->dev, "There are data to follow\n");
- lbtf_deb_usb2(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n",
- cardp->fwseqnum, cardp->totalbytes);
+ lbtf_deb_usb2(&cardp->udev->dev,
+ "seqnum = %d totalbytes = %d\n",
+ cardp->fwseqnum, cardp->totalbytes);
} else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
- lbtf_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n");
+ lbtf_deb_usb2(&cardp->udev->dev,
+ "Host has finished FW downloading\n");
lbtf_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n");
/* Host has finished FW downloading
@@ -367,7 +372,7 @@ EXPORT_SYMBOL_GPL(if_usb_reset_device);
/**
* usb_tx_block - transfer data to the device
*
- * @priv pointer to struct lbtf_private
+ * @priv pointer to struct lbtf_private
* @payload pointer to payload data
* @nb data length
* @data non-zero for data, zero for commands
@@ -400,7 +405,8 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
urb->transfer_flags |= URB_ZERO_PACKET;
if (usb_submit_urb(urb, GFP_ATOMIC)) {
- lbtf_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
+ lbtf_deb_usbd(&cardp->udev->dev,
+ "usb_submit_urb failed: %d\n", ret);
goto tx_ret;
}
@@ -438,10 +444,12 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
- lbtf_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
+ lbtf_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n",
+ cardp->rx_urb);
ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC);
if (ret) {
- lbtf_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
+ lbtf_deb_usbd(&cardp->udev->dev,
+ "Submit Rx URB failed: %d\n", ret);
kfree_skb(skb);
cardp->rx_skb = NULL;
lbtf_deb_leave(LBTF_DEB_USB);
@@ -522,14 +530,14 @@ static void if_usb_receive_fwload(struct urb *urb)
}
} else if (bcmdresp.cmd != BOOT_CMD_FW_BY_USB) {
pr_info("boot cmd response cmd_tag error (%d)\n",
- bcmdresp.cmd);
+ bcmdresp.cmd);
} else if (bcmdresp.result != BOOT_CMD_RESP_OK) {
pr_info("boot cmd response result error (%d)\n",
- bcmdresp.result);
+ bcmdresp.result);
} else {
cardp->bootcmdresp = 1;
lbtf_deb_usbd(&cardp->udev->dev,
- "Received valid boot command response\n");
+ "Received valid boot command response\n");
}
kfree_skb(skb);
@@ -541,19 +549,23 @@ static void if_usb_receive_fwload(struct urb *urb)
syncfwheader = kmemdup(skb->data, sizeof(struct fwsyncheader),
GFP_ATOMIC);
if (!syncfwheader) {
- lbtf_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
+ lbtf_deb_usbd(&cardp->udev->dev,
+ "Failure to allocate syncfwheader\n");
kfree_skb(skb);
lbtf_deb_leave(LBTF_DEB_USB);
return;
}
if (!syncfwheader->cmd) {
- lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
- lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
- le32_to_cpu(syncfwheader->seqnum));
+ lbtf_deb_usb2(&cardp->udev->dev,
+ "FW received Blk with correct CRC\n");
+ lbtf_deb_usb2(&cardp->udev->dev,
+ "FW received Blk seqnum = %d\n",
+ le32_to_cpu(syncfwheader->seqnum));
cardp->CRC_OK = 1;
} else {
- lbtf_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n");
+ lbtf_deb_usbd(&cardp->udev->dev,
+ "FW received Blk with CRC error\n");
cardp->CRC_OK = 0;
}
@@ -666,7 +678,8 @@ static void if_usb_receive(struct urb *urb)
{
/* Event cause handling */
u32 event_cause = le32_to_cpu(pkt[1]);
- lbtf_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n", event_cause);
+ lbtf_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n",
+ event_cause);
/* Icky undocumented magic special case */
if (event_cause & 0xffff0000) {
@@ -689,7 +702,7 @@ static void if_usb_receive(struct urb *urb)
}
default:
lbtf_deb_usbd(&cardp->udev->dev,
- "libertastf: unknown command type 0x%X\n", recvtype);
+ "libertastf: unknown command type 0x%X\n", recvtype);
kfree_skb(skb);
break;
}
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 86fa8abdd66f..7eaaa3bab547 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -9,7 +9,8 @@
/*
* TODO:
- * - IBSS mode simulation (Beacon transmission with competition for "air time")
+ * - Add TSF sync and fix IBSS beacon transmission by adding
+ * competition for "air time" at TBTT
* - RX filtering based on filter configuration (data->rx_filter)
*/
@@ -594,17 +595,34 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
wiphy_debug(hw->wiphy, "%s (type=%d mac_addr=%pM)\n",
- __func__, vif->type, vif->addr);
+ __func__, ieee80211_vif_type_p2p(vif),
+ vif->addr);
hwsim_set_magic(vif);
return 0;
}
+static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum nl80211_iftype newtype,
+ bool newp2p)
+{
+ newtype = ieee80211_iftype_p2p(newtype, newp2p);
+ wiphy_debug(hw->wiphy,
+ "%s (old type=%d, new type=%d, mac_addr=%pM)\n",
+ __func__, ieee80211_vif_type_p2p(vif),
+ newtype, vif->addr);
+ hwsim_check_magic(vif);
+
+ return 0;
+}
+
static void mac80211_hwsim_remove_interface(
struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
wiphy_debug(hw->wiphy, "%s (type=%d mac_addr=%pM)\n",
- __func__, vif->type, vif->addr);
+ __func__, ieee80211_vif_type_p2p(vif),
+ vif->addr);
hwsim_check_magic(vif);
hwsim_clear_magic(vif);
}
@@ -620,7 +638,8 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
hwsim_check_magic(vif);
if (vif->type != NL80211_IFTYPE_AP &&
- vif->type != NL80211_IFTYPE_MESH_POINT)
+ vif->type != NL80211_IFTYPE_MESH_POINT &&
+ vif->type != NL80211_IFTYPE_ADHOC)
return;
skb = ieee80211_beacon_get(hw, vif);
@@ -1025,6 +1044,7 @@ static struct ieee80211_ops mac80211_hwsim_ops =
.start = mac80211_hwsim_start,
.stop = mac80211_hwsim_stop,
.add_interface = mac80211_hwsim_add_interface,
+ .change_interface = mac80211_hwsim_change_interface,
.remove_interface = mac80211_hwsim_remove_interface,
.config = mac80211_hwsim_config,
.configure_filter = mac80211_hwsim_configure_filter,
@@ -1295,6 +1315,9 @@ static int __init init_mac80211_hwsim(void)
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT);
hw->flags = IEEE80211_HW_MFP_CAPABLE |
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c
index 077baa86756b..b4772c1c6135 100644
--- a/drivers/net/wireless/orinoco/hw.c
+++ b/drivers/net/wireless/orinoco/hw.c
@@ -762,14 +762,17 @@ int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate)
case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
for (i = 0; i < BITRATE_TABLE_SIZE; i++)
- if (bitrate_table[i].intersil_txratectrl == val)
+ if (bitrate_table[i].intersil_txratectrl == val) {
+ *bitrate = bitrate_table[i].bitrate * 100000;
break;
+ }
- if (i >= BITRATE_TABLE_SIZE)
+ if (i >= BITRATE_TABLE_SIZE) {
printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n",
priv->ndev->name, val);
+ err = -EIO;
+ }
- *bitrate = bitrate_table[i].bitrate * 100000;
break;
default:
BUG();
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index cf7be1eb6124..93505f93bf97 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -589,8 +589,15 @@ static int orinoco_ioctl_getrate(struct net_device *dev,
/* If the interface is running we try to find more about the
current mode */
- if (netif_running(dev))
- err = orinoco_hw_get_act_bitrate(priv, &bitrate);
+ if (netif_running(dev)) {
+ int act_bitrate;
+ int lerr;
+
+ /* Ignore errors if we can't get the actual bitrate */
+ lerr = orinoco_hw_get_act_bitrate(priv, &act_bitrate);
+ if (!lerr)
+ bitrate = act_bitrate;
+ }
orinoco_unlock(priv, &flags);
diff --git a/drivers/net/wireless/p54/Kconfig b/drivers/net/wireless/p54/Kconfig
index b0342a520bf1..25f965ffc889 100644
--- a/drivers/net/wireless/p54/Kconfig
+++ b/drivers/net/wireless/p54/Kconfig
@@ -2,13 +2,14 @@ config P54_COMMON
tristate "Softmac Prism54 support"
depends on MAC80211 && EXPERIMENTAL
select FW_LOADER
+ select CRC_CCITT
---help---
This is common code for isl38xx/stlc45xx based modules.
This module does nothing by itself - the USB/PCI/SPI front-ends
also need to be enabled in order to support any devices.
These devices require softmac firmware which can be found at
- http://prism54.org/
+ <http://wireless.kernel.org/en/users/Drivers/p54>
If you choose to build a module, it'll be called p54common.
@@ -20,7 +21,7 @@ config P54_USB
This driver is for USB isl38xx based wireless cards.
These devices require softmac firmware which can be found at
- http://prism54.org/
+ <http://wireless.kernel.org/en/users/Drivers/p54>
If you choose to build a module, it'll be called p54usb.
@@ -34,7 +35,7 @@ config P54_PCI
supported by the fullmac driver/firmware.
This driver requires softmac firmware which can be found at
- http://prism54.org/
+ <http://wireless.kernel.org/en/users/Drivers/p54>
If you choose to build a module, it'll be called p54pci.
@@ -48,6 +49,23 @@ config P54_SPI
If you choose to build a module, it'll be called p54spi.
+config P54_SPI_DEFAULT_EEPROM
+ bool "Include fallback EEPROM blob"
+ depends on P54_SPI
+ default n
+ ---help---
+ Unlike the PCI or USB devices, the SPI variants don't have
+ a dedicated EEPROM chip to store all device specific values
+ for calibration, country and interface settings.
+
+ The driver will try to load the image "3826.eeprom", if the
+ file is put at the right place. (usually /lib/firmware.)
+
+ Only if this request fails, this option will provide a
+ backup set of generic values to get the device working.
+
+ Enabling this option adds about 4k to p54spi.
+
config P54_LEDS
bool
depends on P54_COMMON && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = P54_COMMON)
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
index 78347041ec40..35b09aa0529b 100644
--- a/drivers/net/wireless/p54/eeprom.c
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -23,6 +23,7 @@
#include <linux/slab.h>
#include <net/mac80211.h>
+#include <linux/crc-ccitt.h>
#include "p54.h"
#include "eeprom.h"
@@ -260,8 +261,10 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
list->max_entries = max_channel_num;
list->channels = kzalloc(sizeof(struct p54_channel_entry) *
max_channel_num, GFP_KERNEL);
- if (!list->channels)
+ if (!list->channels) {
+ ret = -ENOMEM;
goto free;
+ }
for (i = 0; i < max_channel_num; i++) {
if (i < priv->iq_autocal_len) {
@@ -540,6 +543,7 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
int err;
u8 *end = (u8 *)eeprom + len;
u16 synth = 0;
+ u16 crc16 = ~0;
wrap = (struct eeprom_pda_wrap *) eeprom;
entry = (void *)wrap->data + le16_to_cpu(wrap->len);
@@ -655,16 +659,29 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
}
break;
case PDR_END:
- /* make it overrun */
- entry_len = len;
+ crc16 = ~crc_ccitt(crc16, (u8 *) entry, sizeof(*entry));
+ if (crc16 != le16_to_cpup((__le16 *)entry->data)) {
+ wiphy_err(dev->wiphy, "eeprom failed checksum "
+ "test!\n");
+ err = -ENOMSG;
+ goto err;
+ } else {
+ goto good_eeprom;
+ }
break;
default:
break;
}
- entry = (void *)entry + (entry_len + 1)*2;
+ crc16 = crc_ccitt(crc16, (u8 *)entry, (entry_len + 1) * 2);
+ entry = (void *)entry + (entry_len + 1) * 2;
}
+ wiphy_err(dev->wiphy, "unexpected end of eeprom data.\n");
+ err = -ENODATA;
+ goto err;
+
+good_eeprom:
if (!synth || !priv->iq_autocal || !priv->output_limit ||
!priv->curve_data) {
wiphy_err(dev->wiphy,
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index 15b20c29a604..92b9b1f05fd5 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -123,10 +123,14 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
bootrec = (struct bootrec *)&bootrec->data[len];
}
- if (fw_version)
+ if (fw_version) {
wiphy_info(priv->hw->wiphy,
"FW rev %s - Softmac protocol %x.%x\n",
fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
+ snprintf(dev->wiphy->fw_version, sizeof(dev->wiphy->fw_version),
+ "%s - %x.%x", fw_version,
+ priv->fw_var >> 8, priv->fw_var & 0xff);
+ }
if (priv->fw_var < 0x500)
wiphy_info(priv->hw->wiphy,
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index 47db439b63bf..622d27b6d8f2 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -429,8 +429,8 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
mutex_lock(&priv->conf_mutex);
if (cmd == SET_KEY) {
- switch (key->alg) {
- case ALG_TKIP:
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_TKIP:
if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
BR_DESC_PRIV_CAP_TKIP))) {
ret = -EOPNOTSUPP;
@@ -439,7 +439,8 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
algo = P54_CRYPTO_TKIPMICHAEL;
break;
- case ALG_WEP:
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
ret = -EOPNOTSUPP;
goto out_unlock;
@@ -447,7 +448,7 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
algo = P54_CRYPTO_WEP;
break;
- case ALG_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
ret = -EOPNOTSUPP;
goto out_unlock;
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index 087bf0698a5a..18d24b7b1e34 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -32,11 +32,14 @@
#include <linux/slab.h>
#include "p54spi.h"
-#include "p54spi_eeprom.h"
#include "p54.h"
#include "lmac.h"
+#ifdef CONFIG_P54_SPI_DEFAULT_EEPROM
+#include "p54spi_eeprom.h"
+#endif /* CONFIG_P54_SPI_DEFAULT_EEPROM */
+
MODULE_FIRMWARE("3826.arm");
MODULE_ALIAS("stlc45xx");
@@ -195,9 +198,13 @@ static int p54spi_request_eeprom(struct ieee80211_hw *dev)
ret = request_firmware(&eeprom, "3826.eeprom", &priv->spi->dev);
if (ret < 0) {
+#ifdef CONFIG_P54_SPI_DEFAULT_EEPROM
dev_info(&priv->spi->dev, "loading default eeprom...\n");
ret = p54_parse_eeprom(dev, (void *) p54spi_eeprom,
sizeof(p54spi_eeprom));
+#else
+ dev_err(&priv->spi->dev, "Failed to request user eeprom\n");
+#endif /* CONFIG_P54_SPI_DEFAULT_EEPROM */
} else {
dev_info(&priv->spi->dev, "loading user eeprom...\n");
ret = p54_parse_eeprom(dev, (void *) eeprom->data,
diff --git a/drivers/net/wireless/p54/p54spi_eeprom.h b/drivers/net/wireless/p54/p54spi_eeprom.h
index 1ea1050911d9..d592cbd34d78 100644
--- a/drivers/net/wireless/p54/p54spi_eeprom.h
+++ b/drivers/net/wireless/p54/p54spi_eeprom.h
@@ -671,7 +671,7 @@ static unsigned char p54spi_eeprom[] = {
0xa8, 0x09, 0x25, 0x00, 0xf5, 0xff, 0xf9, 0xff, 0x00, 0x01,
0x02, 0x00, 0x00, 0x00, /* PDR_END */
- 0xa8, 0xf5 /* bogus data */
+ 0x67, 0x99,
};
#endif /* P54SPI_EEPROM_H */
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index ad595958b7df..d5bc21e5a02c 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -33,8 +33,17 @@ MODULE_ALIAS("prism54usb");
MODULE_FIRMWARE("isl3886usb");
MODULE_FIRMWARE("isl3887usb");
+/*
+ * Note:
+ *
+ * Always update our wiki's device list (located at:
+ * http://wireless.kernel.org/en/users/Drivers/p54/devices ),
+ * whenever you add a new device.
+ */
+
static struct usb_device_id p54u_table[] __devinitdata = {
/* Version 1 devices (pci chip + net2280) */
+ {USB_DEVICE(0x045e, 0x00c2)}, /* Microsoft MN-710 */
{USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
{USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */
{USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
@@ -47,7 +56,9 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
{USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
{USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
+ {USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */
{USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
+ {USB_DEVICE(0x1630, 0x0005)}, /* 2Wire 802.11g USB (v1) / Z-Com */
{USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
{USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
{USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
@@ -60,6 +71,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
{USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
{USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
+ {USB_DEVICE(0x06a9, 0x000e)}, /* Westell 802.11g USB (A90-211WG-01) */
{USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
{USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
{USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
@@ -80,6 +92,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
{USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
{USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
+ {USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */
{USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
{USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */
{USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
@@ -930,8 +943,8 @@ static int __devinit p54u_probe(struct usb_interface *intf,
#ifdef CONFIG_PM
/* ISL3887 needs a full reset on resume */
udev->reset_resume = 1;
+#endif /* CONFIG_PM */
err = p54u_device_reset(dev);
-#endif
priv->hw_type = P54U_3887;
dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index 0e937dc0c9c4..76b2318a7dc7 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -275,15 +275,15 @@ static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
{
int band = priv->hw->conf.channel->band;
- if (priv->rxhw != 5)
+ if (priv->rxhw != 5) {
return ((rssi * priv->rssical_db[band].mul) / 64 +
priv->rssical_db[band].add) / 4;
- else
+ } else {
/*
* TODO: find the correct formula
*/
- return ((rssi * priv->rssical_db[band].mul) / 64 +
- priv->rssical_db[band].add) / 4;
+ return rssi / 2 - 110;
+ }
}
/*
@@ -683,14 +683,15 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
}
}
-static u8 p54_convert_algo(enum ieee80211_key_alg alg)
+static u8 p54_convert_algo(u32 cipher)
{
- switch (alg) {
- case ALG_WEP:
+ switch (cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
return P54_CRYPTO_WEP;
- case ALG_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
return P54_CRYPTO_TKIPMICHAEL;
- case ALG_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
return P54_CRYPTO_AESCCMP;
default:
return 0;
@@ -731,7 +732,7 @@ int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)
if (info->control.hw_key) {
crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
- if (info->control.hw_key->alg == ALG_TKIP) {
+ if (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
u8 *iv = (u8 *)(skb->data + crypt_offset);
/*
* The firmware excepts that the IV has to have
@@ -827,10 +828,10 @@ int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)
hdr->tries = ridx;
txhdr->rts_rate_idx = 0;
if (info->control.hw_key) {
- txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
+ txhdr->key_type = p54_convert_algo(info->control.hw_key->cipher);
txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
- if (info->control.hw_key->alg == ALG_TKIP) {
+ if (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
/* reserve space for the MIC key */
len += 8;
memcpy(skb_put(skb, 8), &(info->control.hw_key->key
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 77cd65db8500..d97a2caf582b 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -3234,7 +3234,7 @@ prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
switch (cmd) {
case PRISM54_HOSTAPD:
if (!capable(CAP_NET_ADMIN))
- return -EPERM;
+ return -EPERM;
ret = prism54_hostapd(ndev, &wrq->u.data);
return ret;
}
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index dc14420a9adc..b5e64d71b7a6 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -38,7 +38,7 @@ module_param(init_pcitm, int, 0);
/* In this order: vendor, device, subvendor, subdevice, class, class_mask,
* driver_data
* If you have an update for this please contact prism54-devel@prism54.org
- * The latest list can be found at http://prism54.org/supported_cards.php */
+ * The latest list can be found at http://wireless.kernel.org/en/users/Drivers/p54 */
static DEFINE_PCI_DEVICE_TABLE(prism54_id_tbl) = {
/* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
{
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 46da03753fd5..97007d9e2c1f 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -43,7 +43,6 @@
#include <linux/if_arp.h>
#include <linux/ioport.h>
#include <linux/skbuff.h>
-#include <linux/ethtool.h>
#include <linux/ieee80211.h>
#include <pcmcia/cistpl.h>
@@ -79,8 +78,6 @@ static int ray_dev_config(struct net_device *dev, struct ifmap *map);
static struct net_device_stats *ray_get_stats(struct net_device *dev);
static int ray_dev_init(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-
static int ray_open(struct net_device *dev);
static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb,
struct net_device *dev);
@@ -189,7 +186,7 @@ module_param(bc, int, 0);
module_param(phy_addr, charp, 0);
module_param(ray_mem_speed, int, 0);
-static UCHAR b5_default_startup_parms[] = {
+static const UCHAR b5_default_startup_parms[] = {
0, 0, /* Adhoc station */
'L', 'I', 'N', 'U', 'X', 0, 0, 0, /* 32 char ESSID */
0, 0, 0, 0, 0, 0, 0, 0,
@@ -224,7 +221,7 @@ static UCHAR b5_default_startup_parms[] = {
2, 0, 0, 0, 0, 0, 0, 0 /* basic rate set */
};
-static UCHAR b4_default_startup_parms[] = {
+static const UCHAR b4_default_startup_parms[] = {
0, 0, /* Adhoc station */
'L', 'I', 'N', 'U', 'X', 0, 0, 0, /* 32 char ESSID */
0, 0, 0, 0, 0, 0, 0, 0,
@@ -256,9 +253,9 @@ static UCHAR b4_default_startup_parms[] = {
};
/*===========================================================================*/
-static unsigned char eth2_llc[] = { 0xaa, 0xaa, 3, 0, 0, 0 };
+static const u8 eth2_llc[] = { 0xaa, 0xaa, 3, 0, 0, 0 };
-static char hop_pattern_length[] = { 1,
+static const char hop_pattern_length[] = { 1,
USA_HOP_MOD, EUROPE_HOP_MOD,
JAPAN_HOP_MOD, KOREA_HOP_MOD,
SPAIN_HOP_MOD, FRANCE_HOP_MOD,
@@ -266,7 +263,7 @@ static char hop_pattern_length[] = { 1,
JAPAN_TEST_HOP_MOD
};
-static char rcsid[] =
+static const char rcsid[] =
"Raylink/WebGear wireless LAN - Corey <Thomas corey@world.std.com>";
static const struct net_device_ops ray_netdev_ops = {
@@ -316,7 +313,6 @@ static int ray_probe(struct pcmcia_device *p_dev)
/* Raylink entries in the device structure */
dev->netdev_ops = &ray_netdev_ops;
- SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
dev->wireless_handlers = &ray_handler_def;
#ifdef WIRELESS_SPY
local->wireless_data.spy_data = &local->spy_data;
@@ -575,7 +571,7 @@ static int dl_startup_params(struct net_device *dev)
/* Start kernel timer to wait for dl startup to complete. */
local->timer.expires = jiffies + HZ / 2;
local->timer.data = (long)local;
- local->timer.function = &verify_dl_startup;
+ local->timer.function = verify_dl_startup;
add_timer(&local->timer);
dev_dbg(&link->dev,
"ray_cs dl_startup_params started timer for verify_dl_startup\n");
@@ -1025,18 +1021,6 @@ AP to AP 1 1 dest AP src AP dest source
}
} /* end encapsulate_frame */
-/*===========================================================================*/
-
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, "ray_cs");
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
-};
-
/*====================================================================*/
/*------------------------------------------------------------------*/
@@ -1960,12 +1944,12 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id)
dev_dbg(&link->dev,
"ray_cs interrupt network \"%s\" start failed\n",
local->sparm.b4.a_current_ess_id);
- local->timer.function = &start_net;
+ local->timer.function = start_net;
} else {
dev_dbg(&link->dev,
"ray_cs interrupt network \"%s\" join failed\n",
local->sparm.b4.a_current_ess_id);
- local->timer.function = &join_net;
+ local->timer.function = join_net;
}
add_timer(&local->timer);
}
@@ -2433,9 +2417,9 @@ static void authenticate(ray_dev_t *local)
del_timer(&local->timer);
if (build_auth_frame(local, local->bss_id, OPEN_AUTH_REQUEST)) {
- local->timer.function = &join_net;
+ local->timer.function = join_net;
} else {
- local->timer.function = &authenticate_timeout;
+ local->timer.function = authenticate_timeout;
}
local->timer.expires = jiffies + HZ * 2;
local->timer.data = (long)local;
@@ -2520,7 +2504,7 @@ static void associate(ray_dev_t *local)
del_timer(&local->timer);
local->timer.expires = jiffies + HZ * 2;
local->timer.data = (long)local;
- local->timer.function = &join_net;
+ local->timer.function = join_net;
add_timer(&local->timer);
local->card_status = CARD_ASSOC_FAILED;
return;
@@ -2554,7 +2538,7 @@ static void clear_interrupt(ray_dev_t *local)
#ifdef CONFIG_PROC_FS
#define MAXDATA (PAGE_SIZE - 80)
-static char *card_status[] = {
+static const char *card_status[] = {
"Card inserted - uninitialized", /* 0 */
"Card not downloaded", /* 1 */
"Waiting for download parameters", /* 2 */
@@ -2571,8 +2555,8 @@ static char *card_status[] = {
"Association failed" /* 16 */
};
-static char *nettype[] = { "Adhoc", "Infra " };
-static char *framing[] = { "Encapsulation", "Translation" }
+static const char *nettype[] = { "Adhoc", "Infra " };
+static const char *framing[] = { "Encapsulation", "Translation" }
;
/*===========================================================================*/
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 719573bbbf81..71b5971da597 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -540,11 +540,11 @@ static int rndis_set_channel(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan, enum nl80211_channel_type channel_type);
static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
- u8 key_index, const u8 *mac_addr,
- struct key_params *params);
+ u8 key_index, bool pairwise, const u8 *mac_addr,
+ struct key_params *params);
static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
- u8 key_index, const u8 *mac_addr);
+ u8 key_index, bool pairwise, const u8 *mac_addr);
static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index);
@@ -2308,8 +2308,8 @@ static int rndis_set_channel(struct wiphy *wiphy, struct net_device *netdev,
}
static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
- u8 key_index, const u8 *mac_addr,
- struct key_params *params)
+ u8 key_index, bool pairwise, const u8 *mac_addr,
+ struct key_params *params)
{
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;
@@ -2344,7 +2344,7 @@ static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
}
static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
- u8 key_index, const u8 *mac_addr)
+ u8 key_index, bool pairwise, const u8 *mac_addr)
{
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 5063e01410e5..4f420a9ec5dc 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -321,7 +321,8 @@ static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev,
}
static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev,
- struct rt2x00lib_erp *erp)
+ struct rt2x00lib_erp *erp,
+ u32 changed)
{
int preamble_mask;
u32 reg;
@@ -329,59 +330,72 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev,
/*
* When short preamble is enabled, we should set bit 0x08
*/
- preamble_mask = erp->short_preamble << 3;
-
- rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
- rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, 0x1ff);
- rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME, 0x13a);
- rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
- rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
-
- rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
- rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00);
- rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10));
- rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
-
- rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
- rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
- rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20));
- rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
-
- rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
- rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
- rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55));
- rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
-
- rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
- rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
- rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 110));
- rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
-
- rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+ preamble_mask = erp->short_preamble << 3;
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, 0x1ff);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME, 0x13a);
+ rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
+ rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00);
+ rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH,
+ GET_DURATION(ACK_SIZE, 10));
+ rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
+ rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH,
+ GET_DURATION(ACK_SIZE, 20));
+ rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
+ rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH,
+ GET_DURATION(ACK_SIZE, 55));
+ rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
+ rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH,
+ GET_DURATION(ACK_SIZE, 110));
+ rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+ }
- rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
- rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
- rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+ if (changed & BSS_CHANGED_BASIC_RATES)
+ rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
- rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
- rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL, erp->beacon_int * 16);
- rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION, erp->beacon_int * 16);
- rt2x00pci_register_write(rt2x00dev, CSR12, reg);
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
- rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
- rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
- rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
- rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+ rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+ rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
+ rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
+ rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+ rt2x00_set_field32(&reg, CSR19_DIFS, erp->difs);
+ rt2x00_set_field32(&reg, CSR19_EIFS, erp->eifs);
+ rt2x00pci_register_write(rt2x00dev, CSR19, reg);
+ }
- rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
- rt2x00_set_field32(&reg, CSR19_DIFS, erp->difs);
- rt2x00_set_field32(&reg, CSR19_EIFS, erp->eifs);
- rt2x00pci_register_write(rt2x00dev, CSR19, reg);
+ if (changed & BSS_CHANGED_BEACON_INT) {
+ rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
+ rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL,
+ erp->beacon_int * 16);
+ rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION,
+ erp->beacon_int * 16);
+ rt2x00pci_register_write(rt2x00dev, CSR12, reg);
+ }
}
static void rt2400pci_config_ant(struct rt2x00_dev *rt2x00dev,
@@ -1007,12 +1021,11 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* TX descriptor initialization
*/
-static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb,
+static void rt2400pci_write_tx_desc(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
__le32 *txd = entry_priv->desc;
u32 word;
@@ -1091,12 +1104,12 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
- rt2x00queue_map_txskb(rt2x00dev, entry->skb);
+ rt2x00queue_map_txskb(entry);
/*
* Write the TX descriptor for the beacon.
*/
- rt2400pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+ rt2400pci_write_tx_desc(entry, txdesc);
/*
* Dump beacon to userspace through debugfs.
@@ -1112,24 +1125,24 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
}
-static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
- const enum data_queue_qid queue)
+static void rt2400pci_kick_tx_queue(struct data_queue *queue)
{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
u32 reg;
rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
- rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
- rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue == QID_AC_BK));
- rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue == QID_ATIM));
+ rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE));
+ rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK));
+ rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM));
rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
}
-static void rt2400pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
- const enum data_queue_qid qid)
+static void rt2400pci_kill_tx_queue(struct data_queue *queue)
{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
u32 reg;
- if (qid == QID_BEACON) {
+ if (queue->qid == QID_BEACON) {
rt2x00pci_register_write(rt2x00dev, CSR14, 0);
} else {
rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
@@ -1481,15 +1494,17 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Create channel information array
*/
- info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+ info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
spec->channels_info = info;
tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
- for (i = 0; i < 14; i++)
- info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+ for (i = 0; i < 14; i++) {
+ info[i].max_power = TXPOWER_FROM_DEV(MAX_TXPOWER);
+ info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+ }
return 0;
}
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index c2a555d5376b..97feb7aef809 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -327,7 +327,8 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev,
}
static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev,
- struct rt2x00lib_erp *erp)
+ struct rt2x00lib_erp *erp,
+ u32 changed)
{
int preamble_mask;
u32 reg;
@@ -335,59 +336,73 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev,
/*
* When short preamble is enabled, we should set bit 0x08
*/
- preamble_mask = erp->short_preamble << 3;
-
- rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
- rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, 0x162);
- rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME, 0xa2);
- rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
- rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
-
- rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
- rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00);
- rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10));
- rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
-
- rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
- rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
- rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20));
- rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
-
- rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
- rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
- rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55));
- rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
-
- rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
- rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
- rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 110));
- rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
-
- rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+ preamble_mask = erp->short_preamble << 3;
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, 0x162);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME, 0xa2);
+ rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
+ rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00);
+ rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH,
+ GET_DURATION(ACK_SIZE, 10));
+ rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
+ rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH,
+ GET_DURATION(ACK_SIZE, 20));
+ rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
+ rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH,
+ GET_DURATION(ACK_SIZE, 55));
+ rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
+ rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH,
+ GET_DURATION(ACK_SIZE, 110));
+ rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+ }
- rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
- rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
- rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+ if (changed & BSS_CHANGED_BASIC_RATES)
+ rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
- rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
- rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL, erp->beacon_int * 16);
- rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION, erp->beacon_int * 16);
- rt2x00pci_register_write(rt2x00dev, CSR12, reg);
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
- rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
- rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
- rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
- rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+ rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+ rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
+ rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
+ rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+ rt2x00_set_field32(&reg, CSR19_DIFS, erp->difs);
+ rt2x00_set_field32(&reg, CSR19_EIFS, erp->eifs);
+ rt2x00pci_register_write(rt2x00dev, CSR19, reg);
+ }
+
+ if (changed & BSS_CHANGED_BEACON_INT) {
+ rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
+ rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL,
+ erp->beacon_int * 16);
+ rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION,
+ erp->beacon_int * 16);
+ rt2x00pci_register_write(rt2x00dev, CSR12, reg);
+ }
- rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
- rt2x00_set_field32(&reg, CSR19_DIFS, erp->difs);
- rt2x00_set_field32(&reg, CSR19_EIFS, erp->eifs);
- rt2x00pci_register_write(rt2x00dev, CSR19, reg);
}
static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev,
@@ -1161,12 +1176,11 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* TX descriptor initialization
*/
-static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb,
+static void rt2500pci_write_tx_desc(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
__le32 *txd = entry_priv->desc;
u32 word;
@@ -1244,12 +1258,12 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
- rt2x00queue_map_txskb(rt2x00dev, entry->skb);
+ rt2x00queue_map_txskb(entry);
/*
* Write the TX descriptor for the beacon.
*/
- rt2500pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+ rt2500pci_write_tx_desc(entry, txdesc);
/*
* Dump beacon to userspace through debugfs.
@@ -1265,24 +1279,24 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
}
-static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
- const enum data_queue_qid queue)
+static void rt2500pci_kick_tx_queue(struct data_queue *queue)
{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
u32 reg;
rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
- rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
- rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue == QID_AC_BK));
- rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue == QID_ATIM));
+ rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE));
+ rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK));
+ rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM));
rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
}
-static void rt2500pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
- const enum data_queue_qid qid)
+static void rt2500pci_kill_tx_queue(struct data_queue *queue)
{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
u32 reg;
- if (qid == QID_BEACON) {
+ if (queue->qid == QID_BEACON) {
rt2x00pci_register_write(rt2x00dev, CSR14, 0);
} else {
rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
@@ -1795,19 +1809,23 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Create channel information array
*/
- info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+ info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
spec->channels_info = info;
tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
- for (i = 0; i < 14; i++)
- info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+ for (i = 0; i < 14; i++) {
+ info[i].max_power = MAX_TXPOWER;
+ info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+ }
if (spec->num_channels > 14) {
- for (i = 14; i < spec->num_channels; i++)
- info[i].tx_power1 = DEFAULT_TXPOWER;
+ for (i = 14; i < spec->num_channels; i++) {
+ info[i].max_power = MAX_TXPOWER;
+ info[i].default_power1 = DEFAULT_TXPOWER;
+ }
}
return 0;
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index cdaf93f48263..93e44c7f3a74 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -355,7 +355,9 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
* it is known that not work at least on some hardware.
* SW crypto will be used in that case.
*/
- if (key->alg == ALG_WEP && key->keyidx != 0)
+ if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+ key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
+ key->keyidx != 0)
return -EOPNOTSUPP;
/*
@@ -492,24 +494,34 @@ static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev,
}
static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev,
- struct rt2x00lib_erp *erp)
+ struct rt2x00lib_erp *erp,
+ u32 changed)
{
u16 reg;
- rt2500usb_register_read(rt2x00dev, TXRX_CSR10, &reg);
- rt2x00_set_field16(&reg, TXRX_CSR10_AUTORESPOND_PREAMBLE,
- !!erp->short_preamble);
- rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg);
+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR10, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR10_AUTORESPOND_PREAMBLE,
+ !!erp->short_preamble);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg);
+ }
- rt2500usb_register_write(rt2x00dev, TXRX_CSR11, erp->basic_rates);
+ if (changed & BSS_CHANGED_BASIC_RATES)
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR11,
+ erp->basic_rates);
- rt2500usb_register_read(rt2x00dev, TXRX_CSR18, &reg);
- rt2x00_set_field16(&reg, TXRX_CSR18_INTERVAL, erp->beacon_int * 4);
- rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
+ if (changed & BSS_CHANGED_BEACON_INT) {
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR18, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR18_INTERVAL,
+ erp->beacon_int * 4);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
+ }
- rt2500usb_register_write(rt2x00dev, MAC_CSR10, erp->slot_time);
- rt2500usb_register_write(rt2x00dev, MAC_CSR11, erp->sifs);
- rt2500usb_register_write(rt2x00dev, MAC_CSR12, erp->eifs);
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ rt2500usb_register_write(rt2x00dev, MAC_CSR10, erp->slot_time);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR11, erp->sifs);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR12, erp->eifs);
+ }
}
static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev,
@@ -1039,12 +1051,11 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* TX descriptor initialization
*/
-static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb,
+static void rt2500usb_write_tx_desc(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txd = (__le32 *) skb->data;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ __le32 *txd = (__le32 *) entry->skb->data;
u32 word;
/*
@@ -1127,7 +1138,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
/*
* Write the TX descriptor for the beacon.
*/
- rt2500usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+ rt2500usb_write_tx_desc(entry, txdesc);
/*
* Dump beacon to userspace through debugfs.
@@ -1195,6 +1206,14 @@ static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
return length;
}
+static void rt2500usb_kill_tx_queue(struct data_queue *queue)
+{
+ if (queue->qid == QID_BEACON)
+ rt2500usb_register_write(queue->rt2x00dev, TXRX_CSR19, 0);
+
+ rt2x00usb_kill_tx_queue(queue);
+}
+
/*
* RX control handlers
*/
@@ -1655,10 +1674,15 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all hw fields.
+ *
+ * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING unless we are
+ * capable of sending the buffered frames out after the DTIM
+ * transmission using rt2x00lib_beacondone. This will send out
+ * multicast and broadcast traffic immediately instead of buffering it
+ * infinitly and thus dropping it after some time.
*/
rt2x00dev->hw->flags =
IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK;
@@ -1698,19 +1722,23 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Create channel information array
*/
- info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+ info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
spec->channels_info = info;
tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
- for (i = 0; i < 14; i++)
- info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+ for (i = 0; i < 14; i++) {
+ info[i].max_power = MAX_TXPOWER;
+ info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+ }
if (spec->num_channels > 14) {
- for (i = 14; i < spec->num_channels; i++)
- info[i].tx_power1 = DEFAULT_TXPOWER;
+ for (i = 14; i < spec->num_channels; i++) {
+ info[i].max_power = MAX_TXPOWER;
+ info[i].default_power1 = DEFAULT_TXPOWER;
+ }
}
return 0;
@@ -1789,7 +1817,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.write_beacon = rt2500usb_write_beacon,
.get_tx_data_len = rt2500usb_get_tx_data_len,
.kick_tx_queue = rt2x00usb_kick_tx_queue,
- .kill_tx_queue = rt2x00usb_kill_tx_queue,
+ .kill_tx_queue = rt2500usb_kill_tx_queue,
.fill_rxdone = rt2500usb_fill_rxdone,
.config_shared_key = rt2500usb_config_key,
.config_pairwise_key = rt2500usb_config_key,
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index ed4ebcdde7c9..eb8b6cab9925 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -1,5 +1,6 @@
/*
- Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
@@ -639,6 +640,18 @@
#define LED_CFG_LED_POLAR FIELD32(0x40000000)
/*
+ * AMPDU_BA_WINSIZE: Force BlockAck window size
+ * FORCE_WINSIZE_ENABLE:
+ * 0: Disable forcing of BlockAck window size
+ * 1: Enable forcing of BlockAck window size, overwrites values BlockAck
+ * window size values in the TXWI
+ * FORCE_WINSIZE: BlockAck window size
+ */
+#define AMPDU_BA_WINSIZE 0x1040
+#define AMPDU_BA_WINSIZE_FORCE_WINSIZE_ENABLE FIELD32(0x00000020)
+#define AMPDU_BA_WINSIZE_FORCE_WINSIZE FIELD32(0x0000001f)
+
+/*
* XIFS_TIME_CFG: MAC timing
* CCKM_SIFS_TIME: unit 1us. Applied after CCK RX/TX
* OFDM_SIFS_TIME: unit 1us. Applied after OFDM RX/TX
@@ -698,8 +711,14 @@
/*
* TBTT_SYNC_CFG:
+ * BCN_AIFSN: Beacon AIFSN after TBTT interrupt in slots
+ * BCN_CWMIN: Beacon CWMin after TBTT interrupt in slots
*/
#define TBTT_SYNC_CFG 0x1118
+#define TBTT_SYNC_CFG_TBTT_ADJUST FIELD32(0x000000ff)
+#define TBTT_SYNC_CFG_BCN_EXP_WIN FIELD32(0x0000ff00)
+#define TBTT_SYNC_CFG_BCN_AIFSN FIELD32(0x000f0000)
+#define TBTT_SYNC_CFG_BCN_CWMIN FIELD32(0x00f00000)
/*
* TSF_TIMER_DW0: Local lsb TSF timer, read-only
@@ -735,16 +754,21 @@
#define INT_TIMER_EN_GP_TIMER FIELD32(0x00000002)
/*
- * CH_IDLE_STA: channel idle time
+ * CH_IDLE_STA: channel idle time (in us)
*/
#define CH_IDLE_STA 0x1130
/*
- * CH_BUSY_STA: channel busy time
+ * CH_BUSY_STA: channel busy time on primary channel (in us)
*/
#define CH_BUSY_STA 0x1134
/*
+ * CH_BUSY_STA_SEC: channel busy time on secondary channel in HT40 mode (in us)
+ */
+#define CH_BUSY_STA_SEC 0x1138
+
+/*
* MAC_STATUS_CFG:
* BBP_RF_BUSY: When set to 0, BBP and RF are stable.
* if 1 or higher one of the 2 registers is busy.
@@ -1318,11 +1342,34 @@
#define TX_STA_CNT2_TX_UNDER_FLOW_COUNT FIELD32(0xffff0000)
/*
- * TX_STA_FIFO: TX Result for specific PID status fifo register
+ * TX_STA_FIFO: TX Result for specific PID status fifo register.
+ *
+ * This register is implemented as FIFO with 16 entries in the HW. Each
+ * register read fetches the next tx result. If the FIFO is full because
+ * it wasn't read fast enough after the according interrupt (TX_FIFO_STATUS)
+ * triggered, the hw seems to simply drop further tx results.
+ *
+ * VALID: 1: this tx result is valid
+ * 0: no valid tx result -> driver should stop reading
+ * PID_TYPE: The PID latched from the PID field in the TXWI, can be used
+ * to match a frame with its tx result (even though the PID is
+ * only 4 bits wide).
+ * PID_QUEUE: Part of PID_TYPE, this is the queue index number (0-3)
+ * PID_ENTRY: Part of PID_TYPE, this is the queue entry index number (1-3)
+ * This identification number is calculated by ((idx % 3) + 1).
+ * TX_SUCCESS: Indicates tx success (1) or failure (0)
+ * TX_AGGRE: Indicates if the frame was part of an aggregate (1) or not (0)
+ * TX_ACK_REQUIRED: Indicates if the frame needed to get ack'ed (1) or not (0)
+ * WCID: The wireless client ID.
+ * MCS: The tx rate used during the last transmission of this frame, be it
+ * successful or not.
+ * PHYMODE: The phymode used for the transmission.
*/
#define TX_STA_FIFO 0x1718
#define TX_STA_FIFO_VALID FIELD32(0x00000001)
#define TX_STA_FIFO_PID_TYPE FIELD32(0x0000001e)
+#define TX_STA_FIFO_PID_QUEUE FIELD32(0x00000006)
+#define TX_STA_FIFO_PID_ENTRY FIELD32(0x00000018)
#define TX_STA_FIFO_TX_SUCCESS FIELD32(0x00000020)
#define TX_STA_FIFO_TX_AGGRE FIELD32(0x00000040)
#define TX_STA_FIFO_TX_ACK_REQUIRED FIELD32(0x00000080)
@@ -1405,6 +1452,24 @@
/*
* Security key table memory.
+ *
+ * The pairwise key table shares some memory with the beacon frame
+ * buffers 6 and 7. That basically means that when beacon 6 & 7
+ * are used we should only use the reduced pairwise key table which
+ * has a maximum of 222 entries.
+ *
+ * ---------------------------------------------
+ * |0x4000 | Pairwise Key | Reduced Pairwise |
+ * | | Table | Key Table |
+ * | | Size: 256 * 32 | Size: 222 * 32 |
+ * |0x5BC0 | |-------------------
+ * | | | Beacon 6 |
+ * |0x5DC0 | |-------------------
+ * | | | Beacon 7 |
+ * |0x5FC0 | |-------------------
+ * |0x5FFF | |
+ * --------------------------
+ *
* MAC_WCID_BASE: 8-bytes (use only 6 bytes) * 256 entry
* PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry
* MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry
@@ -1554,7 +1619,8 @@ struct mac_iveiv_entry {
* 2. Extract memory from FCE table for BCN 4~5
* 3. Extract memory from Pair-wise key table for BCN 6~7
* It occupied those memory of wcid 238~253 for BCN 6
- * and wcid 222~237 for BCN 7
+ * and wcid 222~237 for BCN 7 (see Security key table memory
+ * for more info).
*
* IMPORTANT NOTE: Not sure why legacy driver does this,
* but HW_BEACON_BASE7 is 0x0200 bytes below HW_BEACON_BASE6.
@@ -1841,6 +1907,13 @@ struct mac_iveiv_entry {
#define EEPROM_RSSI_A2_LNA_A2 FIELD16(0xff00)
/*
+ * EEPROM Maximum TX power values
+ */
+#define EEPROM_MAX_TX_POWER 0x0027
+#define EEPROM_MAX_TX_POWER_24GHZ FIELD16(0x00ff)
+#define EEPROM_MAX_TX_POWER_5GHZ FIELD16(0xff00)
+
+/*
* EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power.
* This is delta in 40MHZ.
* VALUE: Tx Power dalta value (MAX=4)
@@ -1926,8 +1999,17 @@ struct mac_iveiv_entry {
* FRAG: 1 To inform TKIP engine this is a fragment.
* MIMO_PS: The remote peer is in dynamic MIMO-PS mode
* TX_OP: 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs
- * BW: Channel bandwidth 20MHz or 40 MHz
+ * BW: Channel bandwidth 0:20MHz, 1:40 MHz (for legacy rates this will
+ * duplicate the frame to both channels).
* STBC: 1: STBC support MCS =0-7, 2,3 : RESERVED
+ * AMPDU: 1: this frame is eligible for AMPDU aggregation, the hw will
+ * aggregate consecutive frames with the same RA and QoS TID. If
+ * a frame A with the same RA and QoS TID but AMPDU=0 is queued
+ * directly after a frame B with AMPDU=1, frame A might still
+ * get aggregated into the AMPDU started by frame B. So, setting
+ * AMPDU to 0 does _not_ necessarily mean the frame is sent as
+ * MPDU, it can still end up in an AMPDU if the previous frame
+ * was tagged as AMPDU.
*/
#define TXWI_W0_FRAG FIELD32(0x00000001)
#define TXWI_W0_MIMO_PS FIELD32(0x00000002)
@@ -1945,6 +2027,19 @@ struct mac_iveiv_entry {
/*
* Word1
+ * ACK: 0: No Ack needed, 1: Ack needed
+ * NSEQ: 0: Don't assign hw sequence number, 1: Assign hw sequence number
+ * BW_WIN_SIZE: BA windows size of the recipient
+ * WIRELESS_CLI_ID: Client ID for WCID table access
+ * MPDU_TOTAL_BYTE_COUNT: Length of 802.11 frame
+ * PACKETID: Will be latched into the TX_STA_FIFO register once the according
+ * frame was processed. If multiple frames are aggregated together
+ * (AMPDU==1) the reported tx status will always contain the packet
+ * id of the first frame. 0: Don't report tx status for this frame.
+ * PACKETID_QUEUE: Part of PACKETID, This is the queue index (0-3)
+ * PACKETID_ENTRY: Part of PACKETID, THis is the queue entry index (1-3)
+ * This identification number is calculated by ((idx % 3) + 1).
+ * The (+1) is required to prevent PACKETID to become 0.
*/
#define TXWI_W1_ACK FIELD32(0x00000001)
#define TXWI_W1_NSEQ FIELD32(0x00000002)
@@ -1952,6 +2047,8 @@ struct mac_iveiv_entry {
#define TXWI_W1_WIRELESS_CLI_ID FIELD32(0x0000ff00)
#define TXWI_W1_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000)
#define TXWI_W1_PACKETID FIELD32(0xf0000000)
+#define TXWI_W1_PACKETID_QUEUE FIELD32(0x30000000)
+#define TXWI_W1_PACKETID_ENTRY FIELD32(0xc0000000)
/*
* Word2
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index b66e0fd8f0fa..5f00e00789d8 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -1,4 +1,5 @@
/*
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Copyright (C) 2009 Gertjan van Wingerde <gwingerde@gmail.com>
@@ -254,6 +255,23 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
}
EXPORT_SYMBOL_GPL(rt2800_mcu_request);
+int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i = 0;
+ u32 reg;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
+ if (reg && reg != ~0)
+ return 0;
+ msleep(1);
+ }
+
+ ERROR(rt2x00dev, "Unstable hardware.\n");
+ return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(rt2800_wait_csr_ready);
+
int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
{
unsigned int i;
@@ -367,19 +385,16 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
u32 reg;
/*
- * Wait for stable hardware.
+ * If driver doesn't wake up firmware here,
+ * rt2800_load_firmware will hang forever when interface is up again.
*/
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
- if (reg && reg != ~0)
- break;
- msleep(1);
- }
+ rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000);
- if (i == REGISTER_BUSY_COUNT) {
- ERROR(rt2x00dev, "Unstable hardware.\n");
+ /*
+ * Wait for stable hardware.
+ */
+ if (rt2800_wait_csr_ready(rt2x00dev))
return -EBUSY;
- }
if (rt2x00_is_pci(rt2x00dev))
rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002);
@@ -427,8 +442,10 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
}
EXPORT_SYMBOL_GPL(rt2800_load_firmware);
-void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
+void rt2800_write_tx_data(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
{
+ __le32 *txwi = rt2800_drv_get_txwi(entry);
u32 word;
/*
@@ -437,7 +454,8 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
rt2x00_desc_read(txwi, 0, &word);
rt2x00_set_field32(&word, TXWI_W0_FRAG,
test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
- rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0);
+ rt2x00_set_field32(&word, TXWI_W0_MIMO_PS,
+ test_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
rt2x00_set_field32(&word, TXWI_W0_TS,
test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
@@ -465,7 +483,8 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
txdesc->key_idx : 0xff);
rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
txdesc->length);
- rt2x00_set_field32(&word, TXWI_W1_PACKETID, txdesc->queue + 1);
+ rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, txdesc->qid);
+ rt2x00_set_field32(&word, TXWI_W1_PACKETID_ENTRY, (entry->entry_idx % 3) + 1);
rt2x00_desc_write(txwi, 1, word);
/*
@@ -478,9 +497,9 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
_rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
_rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
}
-EXPORT_SYMBOL_GPL(rt2800_write_txwi);
+EXPORT_SYMBOL_GPL(rt2800_write_tx_data);
-static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2)
+static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, u32 rxwi_w2)
{
int rssi0 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI0);
int rssi1 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI1);
@@ -490,7 +509,7 @@ static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2)
u8 offset1;
u8 offset2;
- if (rt2x00dev->rx_status.band == IEEE80211_BAND_2GHZ) {
+ if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom);
offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0);
offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1);
@@ -569,6 +588,181 @@ void rt2800_process_rxwi(struct queue_entry *entry,
}
EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
+static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg)
+{
+ __le32 *txwi;
+ u32 word;
+ int wcid, ack, pid;
+ int tx_wcid, tx_ack, tx_pid;
+
+ 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);
+
+ /*
+ * This frames has returned with an IO error,
+ * so the status report is not intended for this
+ * frame.
+ */
+ if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) {
+ rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
+ return false;
+ }
+
+ /*
+ * Validate if this TX status report is intended for
+ * this entry by comparing the WCID/ACK/PID fields.
+ */
+ txwi = rt2800_drv_get_txwi(entry);
+
+ rt2x00_desc_read(txwi, 1, &word);
+ tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
+ tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK);
+ tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID);
+
+ if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) {
+ WARNING(entry->queue->rt2x00dev,
+ "TX status report missed for queue %d entry %d\n",
+ entry->queue->qid, entry->entry_idx);
+ rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
+ return false;
+ }
+
+ return true;
+}
+
+void rt2800_txdone_entry(struct queue_entry *entry, u32 status)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ struct txdone_entry_desc txdesc;
+ 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);
+ ampdu = rt2x00_get_field32(word, TXWI_W0_AMPDU);
+
+ real_mcs = rt2x00_get_field32(status, TX_STA_FIFO_MCS);
+ aggr = rt2x00_get_field32(status, TX_STA_FIFO_TX_AGGRE);
+
+ /*
+ * If a frame was meant to be sent as a single non-aggregated MPDU
+ * but ended up in an aggregate the used tx rate doesn't correlate
+ * with the one specified in the TXWI as the whole aggregate is sent
+ * with the same rate.
+ *
+ * For example: two frames are sent to rt2x00, the first one sets
+ * AMPDU=1 and requests MCS7 whereas the second frame sets AMDPU=0
+ * and requests MCS15. If the hw aggregates both frames into one
+ * AMDPU the tx status for both frames will contain MCS7 although
+ * the frame was sent successfully.
+ *
+ * Hence, replace the requested rate with the real tx rate to not
+ * confuse the rate control algortihm by providing clearly wrong
+ * data.
+ */
+ if (aggr == 1 && ampdu == 0 && real_mcs != mcs) {
+ skbdesc->tx_rate_idx = real_mcs;
+ mcs = real_mcs;
+ }
+
+ /*
+ * Ralink has a retry mechanism using a global fallback
+ * table. We setup this fallback table to try the immediate
+ * lower rate for all rates. In the TX_STA_FIFO, the MCS field
+ * always contains the MCS used for the last transmission, be
+ * it successful or not.
+ */
+ if (rt2x00_get_field32(status, TX_STA_FIFO_TX_SUCCESS)) {
+ /*
+ * Transmission succeeded. The number of retries is
+ * mcs - real_mcs
+ */
+ __set_bit(TXDONE_SUCCESS, &txdesc.flags);
+ txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0);
+ } else {
+ /*
+ * Transmission failed. The number of retries is
+ * always 7 in this case (for a total number of 8
+ * frames sent).
+ */
+ __set_bit(TXDONE_FAILURE, &txdesc.flags);
+ txdesc.retry = rt2x00dev->long_retry;
+ }
+
+ /*
+ * the frame was retried at least once
+ * -> hw used fallback rates
+ */
+ if (txdesc.retry)
+ __set_bit(TXDONE_FALLBACK, &txdesc.flags);
+
+ rt2x00lib_txdone(entry, &txdesc);
+}
+EXPORT_SYMBOL_GPL(rt2800_txdone_entry);
+
+void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+ struct queue_entry *entry;
+ u32 reg;
+ u8 pid;
+ int i;
+
+ /*
+ * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO
+ * at most X times and also stop processing once the TX_STA_FIFO_VALID
+ * flag is not set anymore.
+ *
+ * The legacy drivers use X=TX_RING_SIZE but state in a comment
+ * that the TX_STA_FIFO stack has a size of 16. We stick to our
+ * tx ring size for now.
+ */
+ for (i = 0; i < TX_ENTRIES; i++) {
+ rt2800_register_read(rt2x00dev, TX_STA_FIFO, &reg);
+ if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
+ break;
+
+ /*
+ * Skip this entry when it contains an invalid
+ * queue identication number.
+ */
+ pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
+ if (pid >= QID_RX)
+ continue;
+
+ queue = rt2x00queue_get_queue(rt2x00dev, pid);
+ if (unlikely(!queue))
+ continue;
+
+ /*
+ * Inside each queue, we process each entry in a chronological
+ * order. We first check that the queue is not empty.
+ */
+ entry = NULL;
+ while (!rt2x00queue_empty(queue)) {
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+ if (rt2800_txdone_entry_check(entry, reg))
+ break;
+ }
+
+ if (!entry || rt2x00queue_empty(queue))
+ break;
+
+ rt2800_txdone_entry(entry, reg);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2800_txdone);
+
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
@@ -600,7 +794,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
/*
* Add the TXWI for the beacon to the skb.
*/
- rt2800_write_txwi((__le32 *)entry->skb->data, txdesc);
+ rt2800_write_tx_data(entry, txdesc);
/*
* Dump beacon to userspace through debugfs.
@@ -871,8 +1065,12 @@ int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
* 1 pairwise key is possible per AID, this means that the AID
* equals our hw_key_idx. Make sure the WCID starts _after_ the
* last possible shared key entry.
+ *
+ * Since parts of the pairwise key table might be shared with
+ * the beacon frame buffers 6 & 7 we should only write into the
+ * first 222 entries.
*/
- if (crypto->aid > (256 - 32))
+ if (crypto->aid > (222 - 32))
return -ENOSPC;
key->hw_key_idx = 32 + crypto->aid;
@@ -975,19 +1173,23 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
}
if (flags & CONFIG_UPDATE_MAC) {
- reg = le32_to_cpu(conf->mac[1]);
- rt2x00_set_field32(&reg, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff);
- conf->mac[1] = cpu_to_le32(reg);
+ if (!is_zero_ether_addr((const u8 *)conf->mac)) {
+ reg = le32_to_cpu(conf->mac[1]);
+ rt2x00_set_field32(&reg, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff);
+ conf->mac[1] = cpu_to_le32(reg);
+ }
rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0,
conf->mac, sizeof(conf->mac));
}
if (flags & CONFIG_UPDATE_BSSID) {
- reg = le32_to_cpu(conf->bssid[1]);
- rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 3);
- rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 7);
- conf->bssid[1] = cpu_to_le32(reg);
+ if (!is_zero_ether_addr((const u8 *)conf->bssid)) {
+ reg = le32_to_cpu(conf->bssid[1]);
+ rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 3);
+ rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 7);
+ conf->bssid[1] = cpu_to_le32(reg);
+ }
rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0,
conf->bssid, sizeof(conf->bssid));
@@ -995,38 +1197,149 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
}
EXPORT_SYMBOL_GPL(rt2800_config_intf);
-void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp)
+static void rt2800_config_ht_opmode(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_erp *erp)
{
+ bool any_sta_nongf = !!(erp->ht_opmode &
+ IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+ u8 protection = erp->ht_opmode & IEEE80211_HT_OP_MODE_PROTECTION;
+ u8 mm20_mode, mm40_mode, gf20_mode, gf40_mode;
+ u16 mm20_rate, mm40_rate, gf20_rate, gf40_rate;
u32 reg;
- rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, &reg);
- rt2x00_set_field32(&reg, AUTO_RSP_CFG_BAC_ACK_POLICY,
- !!erp->short_preamble);
- rt2x00_set_field32(&reg, AUTO_RSP_CFG_AR_PREAMBLE,
- !!erp->short_preamble);
- rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg);
+ /* default protection rate for HT20: OFDM 24M */
+ mm20_rate = gf20_rate = 0x4004;
- rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, &reg);
- rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_CTRL,
- erp->cts_protection ? 2 : 0);
- rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
+ /* default protection rate for HT40: duplicate OFDM 24M */
+ mm40_rate = gf40_rate = 0x4084;
- rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE,
- erp->basic_rates);
- rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003);
+ switch (protection) {
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
+ /*
+ * All STAs in this BSS are HT20/40 but there might be
+ * STAs not supporting greenfield mode.
+ * => Disable protection for HT transmissions.
+ */
+ mm20_mode = mm40_mode = gf20_mode = gf40_mode = 0;
- rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, &reg);
- rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time);
- rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg);
+ break;
+ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
+ /*
+ * All STAs in this BSS are HT20 or HT20/40 but there
+ * might be STAs not supporting greenfield mode.
+ * => Protect all HT40 transmissions.
+ */
+ mm20_mode = gf20_mode = 0;
+ mm40_mode = gf40_mode = 2;
- rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, &reg);
- rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, erp->eifs);
- rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg);
+ break;
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
+ /*
+ * Nonmember protection:
+ * According to 802.11n we _should_ protect all
+ * HT transmissions (but we don't have to).
+ *
+ * But if cts_protection is enabled we _shall_ protect
+ * all HT transmissions using a CCK rate.
+ *
+ * And if any station is non GF we _shall_ protect
+ * GF transmissions.
+ *
+ * We decide to protect everything
+ * -> fall through to mixed mode.
+ */
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
+ /*
+ * Legacy STAs are present
+ * => Protect all HT transmissions.
+ */
+ mm20_mode = mm40_mode = gf20_mode = gf40_mode = 2;
- rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL,
- erp->beacon_int * 16);
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ /*
+ * If erp protection is needed we have to protect HT
+ * transmissions with CCK 11M long preamble.
+ */
+ if (erp->cts_protection) {
+ /* don't duplicate RTS/CTS in CCK mode */
+ mm20_rate = mm40_rate = 0x0003;
+ gf20_rate = gf40_rate = 0x0003;
+ }
+ break;
+ };
+
+ /* check for STAs not supporting greenfield mode */
+ if (any_sta_nongf)
+ gf20_mode = gf40_mode = 2;
+
+ /* Update HT protection config */
+ rt2800_register_read(rt2x00dev, MM20_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_PROTECT_RATE, mm20_rate);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_PROTECT_CTRL, mm20_mode);
+ rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg);
+
+ rt2800_register_read(rt2x00dev, MM40_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_RATE, mm40_rate);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_CTRL, mm40_mode);
+ rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg);
+
+ rt2800_register_read(rt2x00dev, GF20_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_PROTECT_RATE, gf20_rate);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_PROTECT_CTRL, gf20_mode);
+ rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg);
+
+ rt2800_register_read(rt2x00dev, GF40_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_PROTECT_RATE, gf40_rate);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_PROTECT_CTRL, gf40_mode);
+ rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg);
+}
+
+void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp,
+ u32 changed)
+{
+ u32 reg;
+
+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+ rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, &reg);
+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_BAC_ACK_POLICY,
+ !!erp->short_preamble);
+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_AR_PREAMBLE,
+ !!erp->short_preamble);
+ rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg);
+ }
+
+ if (changed & BSS_CHANGED_ERP_CTS_PROT) {
+ rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_CTRL,
+ erp->cts_protection ? 2 : 0);
+ rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
+ }
+
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE,
+ erp->basic_rates);
+ rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003);
+ }
+
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, &reg);
+ rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_SLOT_TIME,
+ erp->slot_time);
+ rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg);
+
+ rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, erp->eifs);
+ rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg);
+ }
+
+ if (changed & BSS_CHANGED_BEACON_INT) {
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL,
+ erp->beacon_int * 16);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ }
+
+ if (changed & BSS_CHANGED_HT)
+ rt2800_config_ht_opmode(rt2x00dev, erp);
}
EXPORT_SYMBOL_GPL(rt2800_config_erp);
@@ -1120,27 +1433,23 @@ static void rt2800_config_channel_rf2xxx(struct rt2x00_dev *rt2x00dev,
* double meaning, and we should set a 7DBm boost flag.
*/
rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST,
- (info->tx_power1 >= 0));
+ (info->default_power1 >= 0));
- if (info->tx_power1 < 0)
- info->tx_power1 += 7;
+ if (info->default_power1 < 0)
+ info->default_power1 += 7;
- rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A,
- TXPOWER_A_TO_DEV(info->tx_power1));
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, info->default_power1);
rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST,
- (info->tx_power2 >= 0));
+ (info->default_power2 >= 0));
- if (info->tx_power2 < 0)
- info->tx_power2 += 7;
+ if (info->default_power2 < 0)
+ info->default_power2 += 7;
- rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A,
- TXPOWER_A_TO_DEV(info->tx_power2));
+ rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, info->default_power2);
} else {
- rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G,
- TXPOWER_G_TO_DEV(info->tx_power1));
- rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G,
- TXPOWER_G_TO_DEV(info->tx_power2));
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, info->default_power1);
+ rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, info->default_power2);
}
rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf));
@@ -1180,13 +1489,11 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev,
rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER,
- TXPOWER_G_TO_DEV(info->tx_power1));
+ rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, info->default_power1);
rt2800_rfcsr_write(rt2x00dev, 12, rfcsr);
rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER,
- TXPOWER_G_TO_DEV(info->tx_power2));
+ rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, info->default_power2);
rt2800_rfcsr_write(rt2x00dev, 13, rfcsr);
rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr);
@@ -1210,10 +1517,19 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
unsigned int tx_pin;
u8 bbp;
+ if (rf->channel <= 14) {
+ info->default_power1 = TXPOWER_G_TO_DEV(info->default_power1);
+ info->default_power2 = TXPOWER_G_TO_DEV(info->default_power2);
+ } else {
+ info->default_power1 = TXPOWER_A_TO_DEV(info->default_power1);
+ info->default_power2 = TXPOWER_A_TO_DEV(info->default_power2);
+ }
+
if (rt2x00_rf(rt2x00dev, RF2020) ||
rt2x00_rf(rt2x00dev, RF3020) ||
rt2x00_rf(rt2x00dev, RF3021) ||
- rt2x00_rf(rt2x00dev, RF3022))
+ rt2x00_rf(rt2x00dev, RF3022) ||
+ rt2x00_rf(rt2x00dev, RF3052))
rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info);
else
rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info);
@@ -1536,7 +1852,7 @@ EXPORT_SYMBOL_GPL(rt2800_link_tuner);
/*
* Initialization functions.
*/
-int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
+static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
u16 eeprom;
@@ -1728,8 +2044,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_read(rt2x00dev, MM40_PROT_CFG, &reg);
rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_RATE, 0x4084);
- rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_CTRL,
- !rt2x00_is_usb(rt2x00dev));
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_CTRL, 0);
rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_NAV, 1);
rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_CCK, 1);
rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
@@ -1886,6 +2201,14 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, LG_FBK_CFG1, reg);
/*
+ * Do not force the BA window size, we use the TXWI to set it
+ */
+ rt2800_register_read(rt2x00dev, AMPDU_BA_WINSIZE, &reg);
+ rt2x00_set_field32(&reg, AMPDU_BA_WINSIZE_FORCE_WINSIZE_ENABLE, 0);
+ rt2x00_set_field32(&reg, AMPDU_BA_WINSIZE_FORCE_WINSIZE, 0);
+ rt2800_register_write(rt2x00dev, AMPDU_BA_WINSIZE, reg);
+
+ /*
* We must clear the error counters.
* These registers are cleared on read,
* so we may pass a useless variable to store the value.
@@ -1906,7 +2229,6 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
return 0;
}
-EXPORT_SYMBOL_GPL(rt2800_init_registers);
static int rt2800_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev)
{
@@ -1949,7 +2271,7 @@ static int rt2800_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
return -EACCES;
}
-int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
+static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
{
unsigned int i;
u16 eeprom;
@@ -2044,7 +2366,6 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
return 0;
}
-EXPORT_SYMBOL_GPL(rt2800_init_bbp);
static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev,
bool bw40, u8 rfcsr24, u8 filter_target)
@@ -2106,7 +2427,7 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev,
return rfcsr24;
}
-int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
+static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
{
u8 rfcsr;
u8 bbp;
@@ -2360,7 +2681,100 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
return 0;
}
-EXPORT_SYMBOL_GPL(rt2800_init_rfcsr);
+
+int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u16 word;
+
+ /*
+ * Initialize all registers.
+ */
+ if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
+ rt2800_init_registers(rt2x00dev) ||
+ rt2800_init_bbp(rt2x00dev) ||
+ rt2800_init_rfcsr(rt2x00dev)))
+ return -EIO;
+
+ /*
+ * Send signal to firmware during boot time.
+ */
+ rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
+
+ if (rt2x00_is_usb(rt2x00dev) &&
+ (rt2x00_rt(rt2x00dev, RT3070) ||
+ rt2x00_rt(rt2x00dev, RT3071) ||
+ rt2x00_rt(rt2x00dev, RT3572))) {
+ udelay(200);
+ rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0);
+ udelay(10);
+ }
+
+ /*
+ * Enable RX.
+ */
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+ udelay(50);
+
+ rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 2);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
+ rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+ /*
+ * Initialize LED control
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word);
+ rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff,
+ word & 0xff, (word >> 8) & 0xff);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word);
+ rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff,
+ word & 0xff, (word >> 8) & 0xff);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word);
+ rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff,
+ word & 0xff, (word >> 8) & 0xff);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2800_enable_radio);
+
+void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
+ rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+ /* Wait for DMA, ignore error */
+ rt2800_wait_wpdma_ready(rt2x00dev);
+
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 0);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+ rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0);
+ rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
+}
+EXPORT_SYMBOL_GPL(rt2800_disable_radio);
int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev)
{
@@ -2516,6 +2930,13 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
default_lna_gain);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_MAX_TX_POWER, &word);
+ if (rt2x00_get_field16(word, EEPROM_MAX_TX_POWER_24GHZ) == 0xff)
+ rt2x00_set_field16(&word, EEPROM_MAX_TX_POWER_24GHZ, MAX_G_TXPOWER);
+ if (rt2x00_get_field16(word, EEPROM_MAX_TX_POWER_5GHZ) == 0xff)
+ rt2x00_set_field16(&word, EEPROM_MAX_TX_POWER_5GHZ, MAX_A_TXPOWER);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_MAX_TX_POWER, word);
+
return 0;
}
EXPORT_SYMBOL_GPL(rt2800_validate_eeprom);
@@ -2755,9 +3176,10 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
struct channel_info *info;
- char *tx_power1;
- char *tx_power2;
+ char *default_power1;
+ char *default_power2;
unsigned int i;
+ unsigned short max_power;
u16 eeprom;
/*
@@ -2770,11 +3192,20 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
* Initialize all hw fields.
*/
rt2x00dev->hw->flags =
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_AMPDU_AGGREGATION;
+ /*
+ * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices
+ * unless we are capable of sending the buffered frames out after the
+ * DTIM transmission using rt2x00lib_beacondone. This will send out
+ * multicast and broadcast traffic immediately instead of buffering it
+ * infinitly and thus dropping it after some time.
+ */
+ if (!rt2x00_is_usb(rt2x00dev))
+ rt2x00dev->hw->flags |=
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@@ -2785,12 +3216,13 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
* As rt2800 has a global fallback table we cannot specify
* more then one tx rate per frame but since the hw will
* try several rates (based on the fallback table) we should
- * still initialize max_rates to the maximum number of rates
+ * initialize max_report_rates to the maximum number of rates
* we are going to try. Otherwise mac80211 will truncate our
* reported tx rates and the rc algortihm will end up with
* incorrect data.
*/
- rt2x00dev->hw->max_rates = 7;
+ rt2x00dev->hw->max_rates = 1;
+ rt2x00dev->hw->max_report_rates = 7;
rt2x00dev->hw->max_rate_tries = 1;
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
@@ -2865,27 +3297,32 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Create channel information array
*/
- info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+ info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
spec->channels_info = info;
- tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
- tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_MAX_TX_POWER, &eeprom);
+ max_power = rt2x00_get_field16(eeprom, EEPROM_MAX_TX_POWER_24GHZ);
+ default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
+ default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
for (i = 0; i < 14; i++) {
- info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]);
- info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]);
+ info[i].max_power = max_power;
+ info[i].default_power1 = TXPOWER_G_FROM_DEV(default_power1[i]);
+ info[i].default_power2 = TXPOWER_G_FROM_DEV(default_power2[i]);
}
if (spec->num_channels > 14) {
- tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1);
- tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2);
+ max_power = rt2x00_get_field16(eeprom, EEPROM_MAX_TX_POWER_5GHZ);
+ default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1);
+ default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2);
for (i = 14; i < spec->num_channels; i++) {
- info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]);
- info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]);
+ info[i].max_power = max_power;
+ info[i].default_power1 = TXPOWER_A_FROM_DEV(default_power1[i]);
+ info[i].default_power2 = TXPOWER_A_FROM_DEV(default_power2[i]);
}
}
@@ -3042,8 +3479,12 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
switch (action) {
case IEEE80211_AMPDU_RX_START:
case IEEE80211_AMPDU_RX_STOP:
- /* we don't support RX aggregation yet */
- ret = -ENOTSUPP;
+ /*
+ * The hw itself takes care of setting up BlockAck mechanisms.
+ * So, we only have to allow mac80211 to nagotiate a BlockAck
+ * agreement. Once that is done, the hw will BlockAck incoming
+ * AMPDUs without further setup.
+ */
break;
case IEEE80211_AMPDU_TX_START:
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 091641e3c5e2..81cbc92e7857 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -1,4 +1,6 @@
/*
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+ Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Bartlomiej Zolnierkiewicz
This program is free software; you can redistribute it and/or modify
@@ -44,6 +46,7 @@ struct rt2800_ops {
int (*drv_write_firmware)(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len);
int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
+ __le32 *(*drv_get_txwi)(struct queue_entry *entry);
};
static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev,
@@ -126,18 +129,32 @@ static inline int rt2800_drv_init_registers(struct rt2x00_dev *rt2x00dev)
return rt2800ops->drv_init_registers(rt2x00dev);
}
+static inline __le32 *rt2800_drv_get_txwi(struct queue_entry *entry)
+{
+ const struct rt2800_ops *rt2800ops = entry->queue->rt2x00dev->ops->drv;
+
+ return rt2800ops->drv_get_txwi(entry);
+}
+
void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
const u8 command, const u8 token,
const u8 arg0, const u8 arg1);
+int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev);
+int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev);
+
int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len);
int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len);
-void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc);
+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(struct rt2x00_dev *rt2x00dev);
+void rt2800_txdone_entry(struct queue_entry *entry, u32 status);
+
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
extern const struct rt2x00debug rt2800_rt2x00debug;
@@ -153,7 +170,8 @@ 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,
struct rt2x00intf_conf *conf, const unsigned int flags);
-void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp);
+void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp,
+ u32 changed);
void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant);
void rt2800_config(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_conf *libconf,
@@ -163,10 +181,8 @@ void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual);
void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
const u32 count);
-int rt2800_init_registers(struct rt2x00_dev *rt2x00dev);
-int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev);
-int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev);
-int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev);
+int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
+void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev);
void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 39b3846fa340..b26739535986 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2009 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
@@ -196,8 +196,6 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000);
-
/*
* enable Host program ram write selection
*/
@@ -243,6 +241,7 @@ static void rt2800pci_clear_entry(struct queue_entry *entry)
{
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
u32 word;
if (entry->queue->qid == QID_RX) {
@@ -253,6 +252,13 @@ static void rt2800pci_clear_entry(struct queue_entry *entry)
rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, RXD_W1_DMA_DONE, 0);
rt2x00_desc_write(entry_priv->desc, 1, word);
+
+ /*
+ * Set RX IDX in register to inform hardware that we have
+ * handled this entry and it is available for reuse again.
+ */
+ rt2800_register_write(rt2x00dev, RX_CRX_IDX,
+ entry->entry_idx);
} else {
rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 1);
@@ -344,24 +350,24 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
}
rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
- rt2x00_set_field32(&reg, INT_MASK_CSR_RXDELAYINT, mask);
- rt2x00_set_field32(&reg, INT_MASK_CSR_TXDELAYINT, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_RXDELAYINT, 0);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_TXDELAYINT, 0);
rt2x00_set_field32(&reg, INT_MASK_CSR_RX_DONE, mask);
- rt2x00_set_field32(&reg, INT_MASK_CSR_AC0_DMA_DONE, mask);
- rt2x00_set_field32(&reg, INT_MASK_CSR_AC1_DMA_DONE, mask);
- rt2x00_set_field32(&reg, INT_MASK_CSR_AC2_DMA_DONE, mask);
- rt2x00_set_field32(&reg, INT_MASK_CSR_AC3_DMA_DONE, mask);
- rt2x00_set_field32(&reg, INT_MASK_CSR_HCCA_DMA_DONE, mask);
- rt2x00_set_field32(&reg, INT_MASK_CSR_MGMT_DMA_DONE, mask);
- rt2x00_set_field32(&reg, INT_MASK_CSR_MCU_COMMAND, mask);
- rt2x00_set_field32(&reg, INT_MASK_CSR_RXTX_COHERENT, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_AC0_DMA_DONE, 0);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_AC1_DMA_DONE, 0);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_AC2_DMA_DONE, 0);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_AC3_DMA_DONE, 0);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_HCCA_DMA_DONE, 0);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_MGMT_DMA_DONE, 0);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_MCU_COMMAND, 0);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_RXTX_COHERENT, 0);
rt2x00_set_field32(&reg, INT_MASK_CSR_TBTT, mask);
rt2x00_set_field32(&reg, INT_MASK_CSR_PRE_TBTT, mask);
rt2x00_set_field32(&reg, INT_MASK_CSR_TX_FIFO_STATUS, mask);
rt2x00_set_field32(&reg, INT_MASK_CSR_AUTO_WAKEUP, mask);
- rt2x00_set_field32(&reg, INT_MASK_CSR_GPTIMER, mask);
- rt2x00_set_field32(&reg, INT_MASK_CSR_RX_COHERENT, mask);
- rt2x00_set_field32(&reg, INT_MASK_CSR_TX_COHERENT, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_GPTIMER, 0);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_RX_COHERENT, 0);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_TX_COHERENT, 0);
rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
}
@@ -399,78 +405,18 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
{
- u32 reg;
- u16 word;
-
- /*
- * Initialize all registers.
- */
if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
- rt2800pci_init_queues(rt2x00dev) ||
- rt2800_init_registers(rt2x00dev) ||
- rt2800_wait_wpdma_ready(rt2x00dev) ||
- rt2800_init_bbp(rt2x00dev) ||
- rt2800_init_rfcsr(rt2x00dev)))
+ rt2800pci_init_queues(rt2x00dev)))
return -EIO;
- /*
- * Send signal to firmware during boot time.
- */
- rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
-
- /*
- * Enable RX.
- */
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-
- rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 2);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
- rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-
- /*
- * Initialize LED control
- */
- rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word);
- rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff,
- word & 0xff, (word >> 8) & 0xff);
-
- rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word);
- rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff,
- word & 0xff, (word >> 8) & 0xff);
-
- rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word);
- rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff,
- word & 0xff, (word >> 8) & 0xff);
-
- return 0;
+ return rt2800_enable_radio(rt2x00dev);
}
static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
- rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
- rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0);
- rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0);
- rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
+ rt2800_disable_radio(rt2x00dev);
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001280);
@@ -486,9 +432,6 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
-
- /* Wait for DMA, ignore error */
- rt2800_wait_wpdma_ready(rt2x00dev);
}
static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
@@ -566,21 +509,16 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* TX descriptor initialization
*/
-static void rt2800pci_write_tx_data(struct queue_entry* entry,
- struct txentry_desc *txdesc)
+static __le32 *rt2800pci_get_txwi(struct queue_entry *entry)
{
- __le32 *txwi = (__le32 *) entry->skb->data;
-
- rt2800_write_txwi(txwi, txdesc);
+ return (__le32 *) entry->skb->data;
}
-
-static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb,
+static void rt2800pci_write_tx_desc(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
__le32 *txd = entry_priv->desc;
u32 word;
@@ -600,7 +538,7 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_desc_write(txd, 0, word);
rt2x00_desc_read(txd, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_SD_LEN1, skb->len);
+ 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));
rt2x00_set_field32(&word, TXD_W1_BURST,
@@ -631,41 +569,35 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* TX data initialization
*/
-static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
- const enum data_queue_qid queue_idx)
+static void rt2800pci_kick_tx_queue(struct data_queue *queue)
{
- struct data_queue *queue;
- unsigned int idx, qidx = 0;
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
+ unsigned int qidx;
- if (queue_idx > QID_HCCA && queue_idx != QID_MGMT)
- return;
-
- queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
- idx = queue->index[Q_INDEX];
-
- if (queue_idx == QID_MGMT)
+ if (queue->qid == QID_MGMT)
qidx = 5;
else
- qidx = queue_idx;
+ qidx = queue->qid;
- rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx);
+ rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), entry->entry_idx);
}
-static void rt2800pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
- const enum data_queue_qid qid)
+static void rt2800pci_kill_tx_queue(struct data_queue *queue)
{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
u32 reg;
- if (qid == QID_BEACON) {
+ if (queue->qid == QID_BEACON) {
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, 0);
return;
}
rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, (qid == QID_AC_BE));
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, (qid == QID_AC_BK));
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, (qid == QID_AC_VI));
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, (qid == QID_AC_VO));
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, (queue->qid == QID_AC_BE));
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, (queue->qid == QID_AC_BK));
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, (queue->qid == QID_AC_VI));
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, (queue->qid == QID_AC_VO));
rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
}
@@ -675,7 +607,6 @@ static void rt2800pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
static void rt2800pci_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
- struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
__le32 *rxd = entry_priv->desc;
u32 word;
@@ -717,127 +648,74 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
* Process the RXWI structure that is at the start of the buffer.
*/
rt2800_process_rxwi(entry, rxdesc);
-
- /*
- * Set RX IDX in register to inform hardware that we have handled
- * this entry and it is available for reuse again.
- */
- rt2800_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx);
}
/*
* Interrupt functions.
*/
+static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev)
+{
+ struct ieee80211_conf conf = { .flags = 0 };
+ struct rt2x00lib_conf libconf = { .conf = &conf };
+
+ rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
+}
+
static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
struct queue_entry *entry;
- __le32 *txwi;
- struct txdone_entry_desc txdesc;
- u32 word;
- u32 reg;
- int wcid, ack, pid, tx_wcid, tx_ack, tx_pid;
- u16 mcs, real_mcs;
- int i;
-
- /*
- * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO
- * at most X times and also stop processing once the TX_STA_FIFO_VALID
- * flag is not set anymore.
- *
- * The legacy drivers use X=TX_RING_SIZE but state in a comment
- * that the TX_STA_FIFO stack has a size of 16. We stick to our
- * tx ring size for now.
- */
- for (i = 0; i < TX_ENTRIES; i++) {
- rt2800_register_read(rt2x00dev, TX_STA_FIFO, &reg);
- if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
+ u32 status;
+ u8 qid;
+
+ while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) {
+ /* Now remove the tx status from the FIFO */
+ if (kfifo_out(&rt2x00dev->txstatus_fifo, &status,
+ sizeof(status)) != sizeof(status)) {
+ WARN_ON(1);
break;
+ }
- 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);
-
- /*
- * Skip this entry when it contains an invalid
- * queue identication number.
- */
- if (pid <= 0 || pid > QID_RX)
- continue;
-
- queue = rt2x00queue_get_queue(rt2x00dev, pid - 1);
- if (unlikely(!queue))
- continue;
-
- /*
- * Inside each queue, we process each entry in a chronological
- * order. We first check that the queue is not empty.
- */
- if (rt2x00queue_empty(queue))
- continue;
- entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-
- /* Check if we got a match by looking at WCID/ACK/PID
- * fields */
- txwi = (__le32 *) entry->skb->data;
-
- rt2x00_desc_read(txwi, 1, &word);
- tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
- tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK);
- tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID);
-
- if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid))
- WARNING(rt2x00dev, "invalid TX_STA_FIFO content\n");
-
- /*
- * Obtain the status about this packet.
- */
- txdesc.flags = 0;
- rt2x00_desc_read(txwi, 0, &word);
- mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
- real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
-
- /*
- * Ralink has a retry mechanism using a global fallback
- * table. We setup this fallback table to try the immediate
- * lower rate for all rates. In the TX_STA_FIFO, the MCS field
- * always contains the MCS used for the last transmission, be
- * it successful or not.
- */
- if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS)) {
+ qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE);
+ if (qid >= QID_RX) {
/*
- * Transmission succeeded. The number of retries is
- * mcs - real_mcs
+ * Unknown queue, this shouldn't happen. Just drop
+ * this tx status.
*/
- __set_bit(TXDONE_SUCCESS, &txdesc.flags);
- txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0);
- } else {
+ WARNING(rt2x00dev, "Got TX status report with "
+ "unexpected pid %u, dropping", qid);
+ break;
+ }
+
+ queue = rt2x00queue_get_queue(rt2x00dev, qid);
+ if (unlikely(queue == NULL)) {
/*
- * Transmission failed. The number of retries is
- * always 7 in this case (for a total number of 8
- * frames sent).
+ * The queue is NULL, this shouldn't happen. Stop
+ * processing here and drop the tx status
*/
- __set_bit(TXDONE_FAILURE, &txdesc.flags);
- txdesc.retry = 7;
+ WARNING(rt2x00dev, "Got TX status for an unavailable "
+ "queue %u, dropping", qid);
+ break;
}
- /*
- * the frame was retried at least once
- * -> hw used fallback rates
- */
- if (txdesc.retry)
- __set_bit(TXDONE_FALLBACK, &txdesc.flags);
+ if (rt2x00queue_empty(queue)) {
+ /*
+ * The queue is empty. Stop processing here
+ * and drop the tx status.
+ */
+ WARNING(rt2x00dev, "Got TX status for an empty "
+ "queue %u, dropping", qid);
+ break;
+ }
- rt2x00lib_txdone(entry, &txdesc);
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+ rt2800_txdone_entry(entry, status);
}
}
-static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev)
+static void rt2800pci_txstatus_tasklet(unsigned long data)
{
- struct ieee80211_conf conf = { .flags = 0 };
- struct rt2x00lib_conf libconf = { .conf = &conf };
-
- rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
+ rt2800pci_txdone((struct rt2x00_dev *)data);
}
static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
@@ -864,13 +742,7 @@ static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
rt2x00pci_rxdone(rt2x00dev);
/*
- * 4 - Tx done interrupt.
- */
- if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
- rt2800pci_txdone(rt2x00dev);
-
- /*
- * 5 - Auto wakeup interrupt.
+ * 4 - Auto wakeup interrupt.
*/
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
rt2800pci_wakeup(rt2x00dev);
@@ -882,10 +754,58 @@ static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
return IRQ_HANDLED;
}
+static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
+{
+ u32 status;
+ int i;
+
+ /*
+ * The TX_FIFO_STATUS interrupt needs special care. We should
+ * read TX_STA_FIFO but we should do it immediately as otherwise
+ * the register can overflow and we would lose status reports.
+ *
+ * Hence, read the TX_STA_FIFO register and copy all tx status
+ * reports into a kernel FIFO which is handled in the txstatus
+ * tasklet. We use a tasklet to process the tx status reports
+ * because we can schedule the tasklet multiple times (when the
+ * interrupt fires again during tx status processing).
+ *
+ * Furthermore we don't disable the TX_FIFO_STATUS
+ * interrupt here but leave it enabled so that the TX_STA_FIFO
+ * can also be read while the interrupt thread gets executed.
+ *
+ * Since we have only one producer and one consumer we don't
+ * need to lock the kfifo.
+ */
+ for (i = 0; i < TX_ENTRIES; i++) {
+ rt2800_register_read(rt2x00dev, TX_STA_FIFO, &status);
+
+ if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
+ break;
+
+ if (kfifo_is_full(&rt2x00dev->txstatus_fifo)) {
+ WARNING(rt2x00dev, "TX status FIFO overrun,"
+ " drop tx status report.\n");
+ break;
+ }
+
+ if (kfifo_in(&rt2x00dev->txstatus_fifo, &status,
+ sizeof(status)) != sizeof(status)) {
+ WARNING(rt2x00dev, "TX status FIFO overrun,"
+ "drop tx status report.\n");
+ break;
+ }
+ }
+
+ /* Schedule the tasklet for processing the tx status. */
+ tasklet_schedule(&rt2x00dev->txstatus_tasklet);
+}
+
static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
u32 reg;
+ irqreturn_t ret = IRQ_HANDLED;
/* Read status and ACK all interrupts */
rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
@@ -897,15 +817,38 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return IRQ_HANDLED;
- /* Store irqvalue for use in the interrupt thread. */
- rt2x00dev->irqvalue[0] = reg;
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
+ rt2800pci_txstatus_interrupt(rt2x00dev);
- /* Disable interrupts, will be enabled again in the interrupt thread. */
- rt2x00dev->ops->lib->set_device_state(rt2x00dev,
- STATE_RADIO_IRQ_OFF_ISR);
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT) ||
+ rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT) ||
+ rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE) ||
+ rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) {
+ /*
+ * All other interrupts are handled in the interrupt thread.
+ * Store irqvalue for use in the interrupt thread.
+ */
+ rt2x00dev->irqvalue[0] = reg;
+
+ /*
+ * Disable interrupts, will be enabled again in the
+ * interrupt thread.
+ */
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+ STATE_RADIO_IRQ_OFF_ISR);
+
+ /*
+ * Leave the TX_FIFO_STATUS interrupt enabled to not lose any
+ * tx status reports.
+ */
+ rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_TX_FIFO_STATUS, 1);
+ rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
+ ret = IRQ_WAKE_THREAD;
+ }
- return IRQ_WAKE_THREAD;
+ return ret;
}
/*
@@ -968,6 +911,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags);
if (!modparam_nohwcrypt)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
@@ -1011,11 +955,13 @@ static const struct rt2800_ops rt2800pci_rt2800_ops = {
.regbusy_read = rt2x00pci_regbusy_read,
.drv_write_firmware = rt2800pci_write_firmware,
.drv_init_registers = rt2800pci_init_registers,
+ .drv_get_txwi = rt2800pci_get_txwi,
};
static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.irq_handler = rt2800pci_interrupt,
.irq_handler_thread = rt2800pci_interrupt_thread,
+ .txstatus_tasklet = rt2800pci_txstatus_tasklet,
.probe_hw = rt2800pci_probe_hw,
.get_firmware_name = rt2800pci_get_firmware_name,
.check_firmware = rt2800_check_firmware,
@@ -1030,7 +976,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
.write_tx_desc = rt2800pci_write_tx_desc,
- .write_tx_data = rt2800pci_write_tx_data,
+ .write_tx_data = rt2800_write_tx_data,
.write_beacon = rt2800_write_beacon,
.kick_tx_queue = rt2800pci_kick_tx_queue,
.kill_tx_queue = rt2800pci_kill_tx_queue,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 5a2dfe87c6b6..3dff56ec195a 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -1,5 +1,6 @@
/*
- Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+ Copyright (C) 2009 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
@@ -100,19 +101,6 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
msleep(10);
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
- /*
- * Send signal to firmware during boot time.
- */
- rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
-
- if (rt2x00_rt(rt2x00dev, RT3070) ||
- rt2x00_rt(rt2x00dev, RT3071) ||
- rt2x00_rt(rt2x00dev, RT3572)) {
- udelay(200);
- rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0);
- udelay(10);
- }
-
return 0;
}
@@ -134,26 +122,18 @@ static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
- int i;
/*
* Wait until BBP and RF are ready.
*/
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
- if (reg && reg != ~0)
- break;
- msleep(1);
- }
-
- if (i == REGISTER_BUSY_COUNT) {
- ERROR(rt2x00dev, "Unstable hardware.\n");
+ if (rt2800_wait_csr_ready(rt2x00dev))
return -EBUSY;
- }
rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000);
+ rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+
rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
@@ -172,30 +152,10 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
- u16 word;
- /*
- * Initialize all registers.
- */
- if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
- rt2800_init_registers(rt2x00dev) ||
- rt2800_init_bbp(rt2x00dev) ||
- rt2800_init_rfcsr(rt2x00dev)))
+ if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev)))
return -EIO;
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-
- udelay(50);
-
- rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1);
- rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-
-
rt2800_register_read(rt2x00dev, USB_DMA_CFG, &reg);
rt2x00_set_field32(&reg, USB_DMA_CFG_PHY_CLEAR, 0);
rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_EN, 0);
@@ -210,45 +170,12 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, USB_DMA_CFG_TX_BULK_EN, 1);
rt2800_register_write(rt2x00dev, USB_DMA_CFG, reg);
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-
- /*
- * Initialize LED control
- */
- rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word);
- rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff,
- word & 0xff, (word >> 8) & 0xff);
-
- rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word);
- rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff,
- word & 0xff, (word >> 8) & 0xff);
-
- rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word);
- rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff,
- word & 0xff, (word >> 8) & 0xff);
-
- return 0;
+ return rt2800_enable_radio(rt2x00dev);
}
static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev)
{
- u32 reg;
-
- rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
- rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0);
- rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0);
- rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
-
- /* Wait for DMA, ignore error */
- rt2800_wait_wpdma_ready(rt2x00dev);
-
+ rt2800_disable_radio(rt2x00dev);
rt2x00usb_disable_radio(rt2x00dev);
}
@@ -320,21 +247,19 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* TX descriptor initialization
*/
-static void rt2800usb_write_tx_data(struct queue_entry* entry,
- struct txentry_desc *txdesc)
+static __le32 *rt2800usb_get_txwi(struct queue_entry *entry)
{
- __le32 *txwi = (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE);
-
- rt2800_write_txwi(txwi, txdesc);
+ if (entry->queue->qid == QID_BEACON)
+ return (__le32 *) (entry->skb->data);
+ else
+ return (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE);
}
-
-static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb,
+static void rt2800usb_write_tx_desc(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txi = (__le32 *) skb->data;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ __le32 *txi = (__le32 *) entry->skb->data;
u32 word;
/*
@@ -342,7 +267,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
*/
rt2x00_desc_read(txi, 0, &word);
rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN,
- skb->len - TXINFO_DESC_SIZE);
+ entry->skb->len - TXINFO_DESC_SIZE);
rt2x00_set_field32(&word, TXINFO_W0_WIV,
!test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2);
@@ -379,6 +304,46 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
}
/*
+ * TX control handlers
+ */
+static void rt2800usb_work_txdone(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, txdone_work);
+ struct data_queue *queue;
+ struct queue_entry *entry;
+
+ rt2800_txdone(rt2x00dev);
+
+ /*
+ * Process any trailing TX status reports for IO failures,
+ * we loop until we find the first non-IO error entry. This
+ * can either be a frame which is free, is being uploaded,
+ * or has completed the upload but didn't have an entry
+ * in the TX_STAT_FIFO register yet.
+ */
+ tx_queue_for_each(rt2x00dev, queue) {
+ while (!rt2x00queue_empty(queue)) {
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+ break;
+
+ rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
+ }
+ }
+}
+
+static void rt2800usb_kill_tx_queue(struct data_queue *queue)
+{
+ if (queue->qid == QID_BEACON)
+ rt2x00usb_register_write(queue->rt2x00dev, BCN_TIME_CFG, 0);
+
+ rt2x00usb_kill_tx_queue(queue);
+}
+
+/*
* RX control handlers
*/
static void rt2800usb_fill_rxdone(struct queue_entry *entry,
@@ -514,6 +479,11 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
*/
rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+ /*
+ * Overwrite TX done handler
+ */
+ PREPARE_WORK(&rt2x00dev->txdone_work, rt2800usb_work_txdone);
+
return 0;
}
@@ -549,6 +519,7 @@ static const struct rt2800_ops rt2800usb_rt2800_ops = {
.regbusy_read = rt2x00usb_regbusy_read,
.drv_write_firmware = rt2800usb_write_firmware,
.drv_init_registers = rt2800usb_init_registers,
+ .drv_get_txwi = rt2800usb_get_txwi,
};
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
@@ -566,11 +537,11 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.link_tuner = rt2800_link_tuner,
.watchdog = rt2x00usb_watchdog,
.write_tx_desc = rt2800usb_write_tx_desc,
- .write_tx_data = rt2800usb_write_tx_data,
+ .write_tx_data = rt2800_write_tx_data,
.write_beacon = rt2800_write_beacon,
.get_tx_data_len = rt2800usb_get_tx_data_len,
.kick_tx_queue = rt2x00usb_kick_tx_queue,
- .kill_tx_queue = rt2x00usb_kill_tx_queue,
+ .kill_tx_queue = rt2800usb_kill_tx_queue,
.fill_rxdone = rt2800usb_fill_rxdone,
.config_shared_key = rt2800_config_shared_key,
.config_pairwise_key = rt2800_config_pairwise_key,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index c21af38cc5af..94fe589acfaa 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -1,5 +1,6 @@
/*
- Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+ Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
<http://rt2x00.serialmonkey.com>
@@ -35,6 +36,7 @@
#include <linux/mutex.h>
#include <linux/etherdevice.h>
#include <linux/input-polldev.h>
+#include <linux/kfifo.h>
#include <net/mac80211.h>
@@ -212,8 +214,9 @@ struct channel_info {
unsigned int flags;
#define GEOGRAPHY_ALLOWED 0x00000001
- short tx_power1;
- short tx_power2;
+ short max_power;
+ short default_power1;
+ short default_power2;
};
/*
@@ -335,6 +338,11 @@ struct link {
/*
* Work structure for scheduling periodic watchdog monitoring.
+ * This work must be scheduled on the kernel workqueue, while
+ * all other work structures must be queued on the mac80211
+ * workqueue. This guarantees that the watchdog can schedule
+ * other work structures and wait for their completion in order
+ * to bring the device/driver back into the desired state.
*/
struct delayed_work watchdog_work;
};
@@ -455,6 +463,7 @@ struct rt2x00lib_erp {
short eifs;
u16 beacon_int;
+ u16 ht_opmode;
};
/*
@@ -520,6 +529,11 @@ struct rt2x00lib_ops {
irq_handler_t irq_handler_thread;
/*
+ * TX status tasklet handler.
+ */
+ void (*txstatus_tasklet) (unsigned long data);
+
+ /*
* Device init handlers.
*/
int (*probe_hw) (struct rt2x00_dev *rt2x00dev);
@@ -558,18 +572,15 @@ struct rt2x00lib_ops {
/*
* TX control handlers
*/
- void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb,
+ void (*write_tx_desc) (struct queue_entry *entry,
struct txentry_desc *txdesc);
void (*write_tx_data) (struct queue_entry *entry,
struct txentry_desc *txdesc);
void (*write_beacon) (struct queue_entry *entry,
struct txentry_desc *txdesc);
int (*get_tx_data_len) (struct queue_entry *entry);
- void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
- const enum data_queue_qid queue);
- void (*kill_tx_queue) (struct rt2x00_dev *rt2x00dev,
- const enum data_queue_qid queue);
+ void (*kick_tx_queue) (struct data_queue *queue);
+ void (*kill_tx_queue) (struct data_queue *queue);
/*
* RX control handlers
@@ -597,7 +608,8 @@ struct rt2x00lib_ops {
#define CONFIG_UPDATE_BSSID ( 1 << 3 )
void (*config_erp) (struct rt2x00_dev *rt2x00dev,
- struct rt2x00lib_erp *erp);
+ struct rt2x00lib_erp *erp,
+ u32 changed);
void (*config_ant) (struct rt2x00_dev *rt2x00dev,
struct antenna_setup *ant);
void (*config) (struct rt2x00_dev *rt2x00dev,
@@ -651,6 +663,7 @@ enum rt2x00_flags {
DRIVER_REQUIRE_DMA,
DRIVER_REQUIRE_COPY_IV,
DRIVER_REQUIRE_L2PAD,
+ DRIVER_REQUIRE_TXSTATUS_FIFO,
/*
* Driver features
@@ -698,6 +711,7 @@ struct rt2x00_dev {
struct ieee80211_hw *hw;
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
enum ieee80211_band curr_band;
+ int curr_freq;
/*
* If enabled, the debugfs interface structures
@@ -850,11 +864,6 @@ struct rt2x00_dev {
struct ieee80211_low_level_stats low_level_stats;
/*
- * RX configuration information.
- */
- struct ieee80211_rx_status rx_status;
-
- /*
* Scheduled work.
* NOTE: intf_work will use ieee80211_iterate_active_interfaces()
* which means it cannot be placed on the hw->workqueue
@@ -862,6 +871,12 @@ struct rt2x00_dev {
*/
struct work_struct intf_work;
+ /**
+ * Scheduled work for TX/RX done handling (USB devices)
+ */
+ struct work_struct rxdone_work;
+ struct work_struct txdone_work;
+
/*
* Data queue arrays for RX, TX and Beacon.
* The Beacon array also contains the Atim queue
@@ -882,6 +897,16 @@ struct rt2x00_dev {
* and interrupt thread routine.
*/
u32 irqvalue[2];
+
+ /*
+ * FIFO for storing tx status reports between isr and tasklet.
+ */
+ struct kfifo txstatus_fifo;
+
+ /*
+ * Tasklet for processing tx status reports (rt2800pci).
+ */
+ struct tasklet_struct txstatus_tasklet;
};
/*
@@ -1016,17 +1041,15 @@ static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev)
/**
* rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
- * @skb: The skb to map.
+ * @entry: Pointer to &struct queue_entry
*/
-void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
+void rt2x00queue_map_txskb(struct queue_entry *entry);
/**
* rt2x00queue_unmap_skb - Unmap a skb from DMA.
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
- * @skb: The skb to unmap.
+ * @entry: Pointer to &struct queue_entry
*/
-void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
+void rt2x00queue_unmap_skb(struct queue_entry *entry);
/**
* rt2x00queue_get_queue - Convert queue index to queue pointer
@@ -1069,10 +1092,11 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
*/
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_dmadone(struct queue_entry *entry);
void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc);
-void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry);
+void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status);
+void rt2x00lib_rxdone(struct queue_entry *entry);
/*
* mac80211 handlers.
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 953dc4f2c6af..54ffb5aeb34e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -81,7 +81,8 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
- struct ieee80211_bss_conf *bss_conf)
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changed)
{
struct rt2x00lib_erp erp;
@@ -102,7 +103,10 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
/* Update global beacon interval time, this is needed for PS support */
rt2x00dev->beacon_int = bss_conf->beacon_int;
- rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp);
+ if (changed & BSS_CHANGED_HT)
+ erp.ht_opmode = bss_conf->ht_operation_mode;
+
+ rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp, changed);
}
static inline
@@ -126,25 +130,17 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
* ANTENNA_SW_DIVERSITY state to the driver.
* If that happens, fallback to hardware defaults,
* or our own default.
- * If diversity handling is active for a particular antenna,
- * we shouldn't overwrite that antenna.
- * The calls to rt2x00lib_config_antenna_check()
- * might have caused that we restore back to the already
- * active setting. If that has happened we can quit.
*/
if (!(ant->flags & ANTENNA_RX_DIVERSITY))
config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx);
- else
+ else if(config.rx == ANTENNA_SW_DIVERSITY)
config.rx = active->rx;
if (!(ant->flags & ANTENNA_TX_DIVERSITY))
config.tx = rt2x00lib_config_antenna_check(config.tx, def->tx);
- else
+ else if (config.tx == ANTENNA_SW_DIVERSITY)
config.tx = active->tx;
- if (config.rx == active->rx && config.tx == active->tx)
- return;
-
/*
* Antenna setup changes require the RX to be disabled,
* else the changes will be ignored by the device.
@@ -209,10 +205,8 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
rt2x00link_reset_tuner(rt2x00dev, false);
rt2x00dev->curr_band = conf->channel->band;
+ rt2x00dev->curr_freq = conf->channel->center_freq;
rt2x00dev->tx_power = conf->power_level;
rt2x00dev->short_retry = conf->short_frame_max_tx_count;
rt2x00dev->long_retry = conf->long_frame_max_tx_count;
-
- rt2x00dev->rx_status.band = conf->channel->band;
- rt2x00dev->rx_status.freq = conf->channel->center_freq;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
index 583dacd8d241..5e9074bf2b8e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00crypto.c
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -31,15 +31,14 @@
enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
{
- switch (key->alg) {
- case ALG_WEP:
- if (key->keylen == WLAN_KEY_LEN_WEP40)
- return CIPHER_WEP64;
- else
- return CIPHER_WEP128;
- case ALG_TKIP:
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ return CIPHER_WEP64;
+ case WLAN_CIPHER_SUITE_WEP104:
+ return CIPHER_WEP128;
+ case WLAN_CIPHER_SUITE_TKIP:
return CIPHER_TKIP;
- case ALG_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
return CIPHER_AES;
default:
return CIPHER_NONE;
@@ -95,7 +94,7 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
overhead += key->iv_len;
if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
- if (key->alg == ALG_TKIP)
+ if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
overhead += 8;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index cea81e4c5c82..fcdb6b0dc40f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -334,12 +334,12 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file,
if (*offset)
return 0;
- data = kzalloc(lines * MAX_LINE_LENGTH, GFP_KERNEL);
+ data = kcalloc(lines, MAX_LINE_LENGTH, GFP_KERNEL);
if (!data)
return -ENOMEM;
temp = data +
- sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdone\tcrypto\n");
+ sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdma done\tdone\n");
queue_for_each(intf->rt2x00dev, queue) {
spin_lock_irqsave(&queue->lock, irqflags);
@@ -347,8 +347,8 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file,
temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid,
queue->count, queue->limit, queue->length,
queue->index[Q_INDEX],
- queue->index[Q_INDEX_DONE],
- queue->index[Q_INDEX_CRYPTO]);
+ queue->index[Q_INDEX_DMA_DONE],
+ queue->index[Q_INDEX_DONE]);
spin_unlock_irqrestore(&queue->lock, irqflags);
}
@@ -382,7 +382,7 @@ static ssize_t rt2x00debug_read_crypto_stats(struct file *file,
loff_t *offset)
{
struct rt2x00debug_intf *intf = file->private_data;
- char *name[] = { "WEP64", "WEP128", "TKIP", "AES" };
+ static const char * const name[] = { "WEP64", "WEP128", "TKIP", "AES" };
char *data;
char *temp;
size_t size;
@@ -484,6 +484,9 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \
if (index >= debug->__name.word_count) \
return -EINVAL; \
\
+ if (length > sizeof(line)) \
+ return -EINVAL; \
+ \
if (copy_from_user(line, buf, length)) \
return -EFAULT; \
\
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 585e8166f22a..5ba79b935f09 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -1,5 +1,6 @@
/*
- Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+ Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@@ -250,6 +251,13 @@ void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);
+void rt2x00lib_dmadone(struct queue_entry *entry)
+{
+ clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+ rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_dmadone);
+
void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc)
{
@@ -266,7 +274,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
/*
* Unmap the skb.
*/
- rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
+ rt2x00queue_unmap_skb(entry);
/*
* Remove the extra tx headroom from the skb.
@@ -383,15 +391,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* send the status report back.
*/
if (!(skbdesc_flags & SKBDESC_NOT_MAC80211))
- /*
- * Only PCI and SOC devices process the tx status in process
- * context. Hence use ieee80211_tx_status for PCI and SOC
- * devices and stick to ieee80211_tx_status_irqsafe for USB.
- */
- if (rt2x00_is_usb(rt2x00dev))
- ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
- else
- ieee80211_tx_status(rt2x00dev->hw, entry->skb);
+ ieee80211_tx_status(rt2x00dev->hw, entry->skb);
else
dev_kfree_skb_any(entry->skb);
@@ -403,7 +403,6 @@ void rt2x00lib_txdone(struct queue_entry *entry,
rt2x00dev->ops->lib->clear_entry(entry);
- clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
/*
@@ -416,65 +415,89 @@ void rt2x00lib_txdone(struct queue_entry *entry,
}
EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
+void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status)
+{
+ struct txdone_entry_desc txdesc;
+
+ txdesc.flags = 0;
+ __set_bit(status, &txdesc.flags);
+ txdesc.retry = 0;
+
+ rt2x00lib_txdone(entry, &txdesc);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo);
+
static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc)
{
struct ieee80211_supported_band *sband;
const struct rt2x00_rate *rate;
unsigned int i;
- int signal;
- int type;
+ int signal = rxdesc->signal;
+ int type = (rxdesc->dev_flags & RXDONE_SIGNAL_MASK);
- /*
- * For non-HT rates the MCS value needs to contain the
- * actually used rate modulation (CCK or OFDM).
- */
- if (rxdesc->dev_flags & RXDONE_SIGNAL_MCS)
- signal = RATE_MCS(rxdesc->rate_mode, rxdesc->signal);
- else
- signal = rxdesc->signal;
-
- type = (rxdesc->dev_flags & RXDONE_SIGNAL_MASK);
-
- sband = &rt2x00dev->bands[rt2x00dev->curr_band];
- for (i = 0; i < sband->n_bitrates; i++) {
- rate = rt2x00_get_rate(sband->bitrates[i].hw_value);
-
- if (((type == RXDONE_SIGNAL_PLCP) &&
- (rate->plcp == signal)) ||
- ((type == RXDONE_SIGNAL_BITRATE) &&
- (rate->bitrate == signal)) ||
- ((type == RXDONE_SIGNAL_MCS) &&
- (rate->mcs == signal))) {
- return i;
+ switch (rxdesc->rate_mode) {
+ case RATE_MODE_CCK:
+ case RATE_MODE_OFDM:
+ /*
+ * For non-HT rates the MCS value needs to contain the
+ * actually used rate modulation (CCK or OFDM).
+ */
+ if (rxdesc->dev_flags & RXDONE_SIGNAL_MCS)
+ signal = RATE_MCS(rxdesc->rate_mode, signal);
+
+ sband = &rt2x00dev->bands[rt2x00dev->curr_band];
+ for (i = 0; i < sband->n_bitrates; i++) {
+ rate = rt2x00_get_rate(sband->bitrates[i].hw_value);
+ if (((type == RXDONE_SIGNAL_PLCP) &&
+ (rate->plcp == signal)) ||
+ ((type == RXDONE_SIGNAL_BITRATE) &&
+ (rate->bitrate == signal)) ||
+ ((type == RXDONE_SIGNAL_MCS) &&
+ (rate->mcs == signal))) {
+ return i;
+ }
}
+ break;
+ case RATE_MODE_HT_MIX:
+ case RATE_MODE_HT_GREENFIELD:
+ if (signal >= 0 && signal <= 76)
+ return signal;
+ break;
+ default:
+ break;
}
WARNING(rt2x00dev, "Frame received with unrecognized signal, "
- "signal=0x%.4x, type=%d.\n", signal, type);
+ "mode=0x%.4x, signal=0x%.4x, type=%d.\n",
+ rxdesc->rate_mode, signal, type);
return 0;
}
-void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry)
+void rt2x00lib_rxdone(struct queue_entry *entry)
{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct rxdone_entry_desc rxdesc;
struct sk_buff *skb;
- struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
+ struct ieee80211_rx_status *rx_status;
unsigned int header_length;
int rate_idx;
+
+ if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+ goto submit_entry;
+
/*
* Allocate a new sk_buffer. If no new buffer available, drop the
* received frame and reuse the existing buffer.
*/
- skb = rt2x00queue_alloc_rxskb(rt2x00dev, entry);
+ skb = rt2x00queue_alloc_rxskb(entry);
if (!skb)
- return;
+ goto submit_entry;
/*
* Unmap the skb.
*/
- rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
+ rt2x00queue_unmap_skb(entry);
/*
* Extract the RXD details.
@@ -509,57 +532,44 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
skb_trim(entry->skb, rxdesc.size);
/*
- * Check if the frame was received using HT. In that case,
- * the rate is the MCS index and should be passed to mac80211
- * directly. Otherwise we need to translate the signal to
- * the correct bitrate index.
+ * Translate the signal to the correct bitrate index.
*/
- if (rxdesc.rate_mode == RATE_MODE_CCK ||
- rxdesc.rate_mode == RATE_MODE_OFDM) {
- rate_idx = rt2x00lib_rxdone_read_signal(rt2x00dev, &rxdesc);
- } else {
+ rate_idx = rt2x00lib_rxdone_read_signal(rt2x00dev, &rxdesc);
+ if (rxdesc.rate_mode == RATE_MODE_HT_MIX ||
+ rxdesc.rate_mode == RATE_MODE_HT_GREENFIELD)
rxdesc.flags |= RX_FLAG_HT;
- rate_idx = rxdesc.signal;
- }
/*
* Update extra components
*/
rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc);
rt2x00debug_update_crypto(rt2x00dev, &rxdesc);
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
+ /*
+ * Initialize RX status information, and send frame
+ * to mac80211.
+ */
+ rx_status = IEEE80211_SKB_RXCB(entry->skb);
rx_status->mactime = rxdesc.timestamp;
+ rx_status->band = rt2x00dev->curr_band;
+ rx_status->freq = rt2x00dev->curr_freq;
rx_status->rate_idx = rate_idx;
rx_status->signal = rxdesc.rssi;
rx_status->flag = rxdesc.flags;
rx_status->antenna = rt2x00dev->link.ant.active.rx;
- /*
- * Send frame to mac80211 & debugfs.
- * mac80211 will clean up the skb structure.
- */
- rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
- memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status));
-
- /*
- * Currently only PCI and SOC devices handle rx interrupts in process
- * context. Hence, use ieee80211_rx_irqsafe for USB and ieee80211_rx_ni
- * for PCI and SOC devices.
- */
- if (rt2x00_is_usb(rt2x00dev))
- ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
- else
- ieee80211_rx_ni(rt2x00dev->hw, entry->skb);
+ ieee80211_rx_ni(rt2x00dev->hw, entry->skb);
/*
* Replace the skb with the freshly allocated one.
*/
entry->skb = skb;
- entry->flags = 0;
+submit_entry:
rt2x00dev->ops->lib->clear_entry(entry);
-
rt2x00queue_index_inc(entry->queue, Q_INDEX);
+ rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
}
EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
@@ -710,7 +720,7 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
for (i = 0; i < spec->num_channels; i++) {
rt2x00lib_channel(&channels[i],
spec->channels[i].channel,
- spec->channels_info[i].tx_power1, i);
+ spec->channels_info[i].max_power, i);
}
/*
@@ -806,6 +816,30 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE;
/*
+ * Allocate tx status FIFO for driver use.
+ */
+ if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags) &&
+ rt2x00dev->ops->lib->txstatus_tasklet) {
+ /*
+ * Allocate txstatus fifo and tasklet, we use a size of 512
+ * for the kfifo which is big enough to store 512/4=128 tx
+ * status reports. In the worst case (tx status for all tx
+ * queues gets reported before we've got a chance to handle
+ * them) 24*4=384 tx status reports need to be cached.
+ */
+ status = kfifo_alloc(&rt2x00dev->txstatus_fifo, 512,
+ GFP_KERNEL);
+ if (status)
+ return status;
+
+ /* tasklet for processing the tx status reports. */
+ tasklet_init(&rt2x00dev->txstatus_tasklet,
+ rt2x00dev->ops->lib->txstatus_tasklet,
+ (unsigned long)rt2x00dev);
+
+ }
+
+ /*
* Register HW.
*/
status = ieee80211_register_hw(rt2x00dev->hw);
@@ -902,10 +936,8 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
/* Enable the radio */
retval = rt2x00lib_enable_radio(rt2x00dev);
- if (retval) {
- rt2x00queue_uninitialize(rt2x00dev);
+ if (retval)
return retval;
- }
set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags);
@@ -1017,6 +1049,18 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
* Stop all work.
*/
cancel_work_sync(&rt2x00dev->intf_work);
+ cancel_work_sync(&rt2x00dev->rxdone_work);
+ cancel_work_sync(&rt2x00dev->txdone_work);
+
+ /*
+ * Free the tx status fifo.
+ */
+ kfifo_free(&rt2x00dev->txstatus_fifo);
+
+ /*
+ * Kill the tx status tasklet.
+ */
+ tasklet_kill(&rt2x00dev->txstatus_tasklet);
/*
* Uninitialize device.
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c
index b818a43c4672..f0e1eb72befc 100644
--- a/drivers/net/wireless/rt2x00/rt2x00firmware.c
+++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c
@@ -63,6 +63,9 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n",
fw->data[fw->size - 4], fw->data[fw->size - 3]);
+ snprintf(rt2x00dev->hw->wiphy->fw_version,
+ sizeof(rt2x00dev->hw->wiphy->fw_version), "%d.%d",
+ fw->data[fw->size - 4], fw->data[fw->size - 3]);
retval = rt2x00dev->ops->lib->check_firmware(rt2x00dev, fw->data, fw->size);
switch (retval) {
diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c
index c004cd3a8847..c637bcaec5f8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00ht.c
+++ b/drivers/net/wireless/rt2x00/rt2x00ht.c
@@ -54,6 +54,17 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
*/
if (txrate->flags & IEEE80211_TX_RC_MCS) {
txdesc->mcs = txrate->idx;
+
+ /*
+ * MIMO PS should be set to 1 for STA's using dynamic SM PS
+ * when using more then one tx stream (>MCS7).
+ */
+ if (tx_info->control.sta && txdesc->mcs > 7 &&
+ ((tx_info->control.sta->ht_cap.cap &
+ IEEE80211_HT_CAP_SM_PS) >>
+ IEEE80211_HT_CAP_SM_PS_SHIFT) ==
+ WLAN_HT_CAP_SM_PS_DYNAMIC)
+ __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags);
} else {
txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs);
if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
@@ -62,9 +73,11 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
/*
- * Convert flags
+ * This frame is eligible for an AMPDU, however, don't aggregate
+ * frames that are intended to probe a specific tx rate.
*/
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU &&
+ !(tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE))
__set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags);
/*
@@ -74,7 +87,13 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
txdesc->rate_mode = RATE_MODE_HT_MIX;
if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD)
txdesc->rate_mode = RATE_MODE_HT_GREENFIELD;
- if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+
+ /*
+ * Set 40Mhz mode if necessary (for legacy rates this will
+ * duplicate the frame to both channels).
+ */
+ if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH ||
+ txrate->flags & IEEE80211_TX_RC_DUP_DATA)
__set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags);
if (txrate->flags & IEEE80211_TX_RC_SHORT_GI)
__set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags);
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index dc5c6574aaf4..619da23b7b56 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -86,7 +86,8 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
const u8 *mac, const u8 *bssid);
void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
- struct ieee80211_bss_conf *conf);
+ struct ieee80211_bss_conf *conf,
+ u32 changed);
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
struct antenna_setup ant);
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
@@ -99,18 +100,15 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
/**
* rt2x00queue_alloc_rxskb - allocate a skb for RX purposes.
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
- * @queue: The queue for which the skb will be applicable.
+ * @entry: The entry for which the skb will be applicable.
*/
-struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry);
+struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry);
/**
* rt2x00queue_free_skb - free a skb
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
- * @skb: The skb to free.
+ * @entry: The entry for which the skb will be applicable.
*/
-void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
+void rt2x00queue_free_skb(struct queue_entry *entry);
/**
* rt2x00queue_align_frame - Align 802.11 frame to 4-byte boundary
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index 666cef3f8472..b971d8798ebf 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -188,7 +188,6 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
- unsigned int flags = ant->flags;
/*
* Determine if software diversity is enabled for
@@ -196,13 +195,13 @@ static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
* Always perform this check since within the link
* tuner interval the configuration might have changed.
*/
- flags &= ~ANTENNA_RX_DIVERSITY;
- flags &= ~ANTENNA_TX_DIVERSITY;
+ ant->flags &= ~ANTENNA_RX_DIVERSITY;
+ ant->flags &= ~ANTENNA_TX_DIVERSITY;
if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
- flags |= ANTENNA_RX_DIVERSITY;
+ ant->flags |= ANTENNA_RX_DIVERSITY;
if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
- flags |= ANTENNA_TX_DIVERSITY;
+ ant->flags |= ANTENNA_TX_DIVERSITY;
if (!(ant->flags & ANTENNA_RX_DIVERSITY) &&
!(ant->flags & ANTENNA_TX_DIVERSITY)) {
@@ -210,9 +209,6 @@ static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
return true;
}
- /* Update flags */
- ant->flags = flags;
-
/*
* If we have only sampled the data over the last period
* we should now harvest the data. Otherwise just evaluate
@@ -240,6 +236,12 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
/*
+ * No need to update the stats for !=STA interfaces
+ */
+ if (!rt2x00dev->intf_sta_count)
+ return;
+
+ /*
* Frame was received successfully since non-succesfull
* frames would have been dropped by the hardware.
*/
@@ -415,8 +417,7 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev)
!test_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags))
return;
- ieee80211_queue_delayed_work(rt2x00dev->hw,
- &link->watchdog_work, WATCHDOG_INTERVAL);
+ schedule_delayed_work(&link->watchdog_work, WATCHDOG_INTERVAL);
}
void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
@@ -440,8 +441,7 @@ static void rt2x00link_watchdog(struct work_struct *work)
rt2x00dev->ops->lib->watchdog(rt2x00dev);
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
- ieee80211_queue_delayed_work(rt2x00dev->hw,
- &link->watchdog_work, WATCHDOG_INTERVAL);
+ schedule_delayed_work(&link->watchdog_work, WATCHDOG_INTERVAL);
}
void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 235e037e6509..c3c206a97d54 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -669,8 +669,10 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
* When the erp information has changed, we should perform
* additional configuration steps. For all other changes we are done.
*/
- if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT))
- rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
+ if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE |
+ BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BASIC_RATES |
+ BSS_CHANGED_BEACON_INT | BSS_CHANGED_HT))
+ rt2x00lib_config_erp(rt2x00dev, intf, bss_conf, changes);
}
EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 63c2cc408e15..2449d785cf8d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -84,7 +84,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
/*
* Send the frame to rt2x00lib for further processing.
*/
- rt2x00lib_rxdone(rt2x00dev, entry);
+ rt2x00lib_rxdone(entry);
}
}
EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index a3401d301058..e360d287defb 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -1,5 +1,6 @@
/*
- Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+ Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
<http://rt2x00.serialmonkey.com>
@@ -32,9 +33,9 @@
#include "rt2x00.h"
#include "rt2x00lib.h"
-struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry)
+struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry)
{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct sk_buff *skb;
struct skb_frame_desc *skbdesc;
unsigned int frame_size;
@@ -96,41 +97,42 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
return skb;
}
-void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
+void rt2x00queue_map_txskb(struct queue_entry *entry)
{
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+ struct device *dev = entry->queue->rt2x00dev->dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
skbdesc->skb_dma =
- dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE);
+ dma_map_single(dev, entry->skb->data, entry->skb->len, DMA_TO_DEVICE);
skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
}
EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
-void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
+void rt2x00queue_unmap_skb(struct queue_entry *entry)
{
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+ struct device *dev = entry->queue->rt2x00dev->dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
if (skbdesc->flags & SKBDESC_DMA_MAPPED_RX) {
- dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
+ dma_unmap_single(dev, skbdesc->skb_dma, entry->skb->len,
DMA_FROM_DEVICE);
skbdesc->flags &= ~SKBDESC_DMA_MAPPED_RX;
- }
-
- if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
- dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
+ } else if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
+ dma_unmap_single(dev, skbdesc->skb_dma, entry->skb->len,
DMA_TO_DEVICE);
skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX;
}
}
EXPORT_SYMBOL_GPL(rt2x00queue_unmap_skb);
-void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
+void rt2x00queue_free_skb(struct queue_entry *entry)
{
- if (!skb)
+ if (!entry->skb)
return;
- rt2x00queue_unmap_skb(rt2x00dev, skb);
- dev_kfree_skb_any(skb);
+ rt2x00queue_unmap_skb(entry);
+ dev_kfree_skb_any(entry->skb);
+ entry->skb = NULL;
}
void rt2x00queue_align_frame(struct sk_buff *skb)
@@ -311,7 +313,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
/*
* Initialize information from queue
*/
- txdesc->queue = entry->queue->qid;
+ txdesc->qid = entry->queue->qid;
txdesc->cw_min = entry->queue->cw_min;
txdesc->cw_max = entry->queue->cw_max;
txdesc->aifs = entry->queue->aifs;
@@ -439,7 +441,7 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry,
* Map the skb to DMA.
*/
if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))
- rt2x00queue_map_txskb(rt2x00dev, entry->skb);
+ rt2x00queue_map_txskb(entry);
return 0;
}
@@ -448,15 +450,14 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct data_queue *queue = entry->queue;
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc);
+ queue->rt2x00dev->ops->lib->write_tx_desc(entry, txdesc);
/*
* All processing on the frame has been completed, this means
* it is now ready to be dumped to userspace through debugfs.
*/
- rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
+ rt2x00debug_dump_frame(queue->rt2x00dev, DUMP_FRAME_TX, entry->skb);
}
static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
@@ -476,7 +477,7 @@ static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
*/
if (rt2x00queue_threshold(queue) ||
!test_bit(ENTRY_TXD_BURST, &txdesc->flags))
- rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid);
+ rt2x00dev->ops->lib->kick_tx_queue(queue);
}
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
@@ -491,7 +492,8 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
if (unlikely(rt2x00queue_full(queue)))
return -ENOBUFS;
- if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) {
+ if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA,
+ &entry->flags))) {
ERROR(queue->rt2x00dev,
"Arrived at non-free entry in the non-full queue %d.\n"
"Please file bug report to %s.\n",
@@ -586,11 +588,10 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
/*
* Clean up the beacon skb.
*/
- rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb);
- intf->beacon->skb = NULL;
+ rt2x00queue_free_skb(intf->beacon);
if (!enable_beacon) {
- rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_BEACON);
+ rt2x00dev->ops->lib->kill_tx_queue(intf->beacon->queue);
mutex_unlock(&intf->beacon_skb_mutex);
return 0;
}
@@ -625,6 +626,51 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
return 0;
}
+void rt2x00queue_for_each_entry(struct data_queue *queue,
+ enum queue_index start,
+ enum queue_index end,
+ void (*fn)(struct queue_entry *entry))
+{
+ unsigned long irqflags;
+ unsigned int index_start;
+ unsigned int index_end;
+ unsigned int i;
+
+ if (unlikely(start >= Q_INDEX_MAX || end >= Q_INDEX_MAX)) {
+ ERROR(queue->rt2x00dev,
+ "Entry requested from invalid index range (%d - %d)\n",
+ start, end);
+ return;
+ }
+
+ /*
+ * Only protect the range we are going to loop over,
+ * if during our loop a extra entry is set to pending
+ * it should not be kicked during this run, since it
+ * is part of another TX operation.
+ */
+ spin_lock_irqsave(&queue->lock, irqflags);
+ index_start = queue->index[start];
+ index_end = queue->index[end];
+ spin_unlock_irqrestore(&queue->lock, irqflags);
+
+ /*
+ * Start from the TX done pointer, this guarentees that we will
+ * send out all frames in the correct order.
+ */
+ if (index_start < index_end) {
+ for (i = index_start; i < index_end; i++)
+ fn(&queue->entries[i]);
+ } else {
+ for (i = index_start; i < queue->limit; i++)
+ fn(&queue->entries[i]);
+
+ for (i = 0; i < index_end; i++)
+ fn(&queue->entries[i]);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_for_each_entry);
+
struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue)
{
@@ -686,13 +732,13 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
if (queue->index[index] >= queue->limit)
queue->index[index] = 0;
+ queue->last_action[index] = jiffies;
+
if (index == Q_INDEX) {
queue->length++;
- queue->last_index = jiffies;
} else if (index == Q_INDEX_DONE) {
queue->length--;
queue->count++;
- queue->last_index_done = jiffies;
}
spin_unlock_irqrestore(&queue->lock, irqflags);
@@ -701,14 +747,17 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
static void rt2x00queue_reset(struct data_queue *queue)
{
unsigned long irqflags;
+ unsigned int i;
spin_lock_irqsave(&queue->lock, irqflags);
queue->count = 0;
queue->length = 0;
- queue->last_index = jiffies;
- queue->last_index_done = jiffies;
- memset(queue->index, 0, sizeof(queue->index));
+
+ for (i = 0; i < Q_INDEX_MAX; i++) {
+ queue->index[i] = 0;
+ queue->last_action[i] = jiffies;
+ }
spin_unlock_irqrestore(&queue->lock, irqflags);
}
@@ -718,7 +767,7 @@ void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev)
struct data_queue *queue;
txall_queue_for_each(rt2x00dev, queue)
- rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, queue->qid);
+ rt2x00dev->ops->lib->kill_tx_queue(queue);
}
void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
@@ -730,9 +779,9 @@ void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
rt2x00queue_reset(queue);
for (i = 0; i < queue->limit; i++) {
- queue->entries[i].flags = 0;
-
rt2x00dev->ops->lib->clear_entry(&queue->entries[i]);
+ if (queue->qid == QID_RX)
+ rt2x00queue_index_inc(queue, Q_INDEX);
}
}
}
@@ -755,7 +804,7 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue,
* Allocate all queue entries.
*/
entry_size = sizeof(*entries) + qdesc->priv_size;
- entries = kzalloc(queue->limit * entry_size, GFP_KERNEL);
+ entries = kcalloc(queue->limit, entry_size, GFP_KERNEL);
if (!entries)
return -ENOMEM;
@@ -780,8 +829,7 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue,
return 0;
}
-static void rt2x00queue_free_skbs(struct rt2x00_dev *rt2x00dev,
- struct data_queue *queue)
+static void rt2x00queue_free_skbs(struct data_queue *queue)
{
unsigned int i;
@@ -789,19 +837,17 @@ static void rt2x00queue_free_skbs(struct rt2x00_dev *rt2x00dev,
return;
for (i = 0; i < queue->limit; i++) {
- if (queue->entries[i].skb)
- rt2x00queue_free_skb(rt2x00dev, queue->entries[i].skb);
+ rt2x00queue_free_skb(&queue->entries[i]);
}
}
-static int rt2x00queue_alloc_rxskbs(struct rt2x00_dev *rt2x00dev,
- struct data_queue *queue)
+static int rt2x00queue_alloc_rxskbs(struct data_queue *queue)
{
unsigned int i;
struct sk_buff *skb;
for (i = 0; i < queue->limit; i++) {
- skb = rt2x00queue_alloc_rxskb(rt2x00dev, &queue->entries[i]);
+ skb = rt2x00queue_alloc_rxskb(&queue->entries[i]);
if (!skb)
return -ENOMEM;
queue->entries[i].skb = skb;
@@ -836,7 +882,7 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
goto exit;
}
- status = rt2x00queue_alloc_rxskbs(rt2x00dev, rt2x00dev->rx);
+ status = rt2x00queue_alloc_rxskbs(rt2x00dev->rx);
if (status)
goto exit;
@@ -854,7 +900,7 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
- rt2x00queue_free_skbs(rt2x00dev, rt2x00dev->rx);
+ rt2x00queue_free_skbs(rt2x00dev->rx);
queue_for_each(rt2x00dev, queue) {
kfree(queue->entries);
@@ -891,7 +937,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
*/
rt2x00dev->data_queues = 2 + rt2x00dev->ops->tx_queues + req_atim;
- queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL);
+ queue = kcalloc(rt2x00dev->data_queues, sizeof(*queue), GFP_KERNEL);
if (!queue) {
ERROR(rt2x00dev, "Queue allocation failed.\n");
return -ENOMEM;
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 191e7775a9c0..d81d85f34866 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@@ -268,6 +268,7 @@ struct txdone_entry_desc {
* @ENTRY_TXD_HT_AMPDU: This frame is part of an AMPDU.
* @ENTRY_TXD_HT_BW_40: Use 40MHz Bandwidth.
* @ENTRY_TXD_HT_SHORT_GI: Use short GI.
+ * @ENTRY_TXD_HT_MIMO_PS: The receiving STA is in dynamic SM PS mode.
*/
enum txentry_desc_flags {
ENTRY_TXD_RTS_FRAME,
@@ -286,6 +287,7 @@ enum txentry_desc_flags {
ENTRY_TXD_HT_AMPDU,
ENTRY_TXD_HT_BW_40,
ENTRY_TXD_HT_SHORT_GI,
+ ENTRY_TXD_HT_MIMO_PS,
};
/**
@@ -294,7 +296,7 @@ enum txentry_desc_flags {
* Summary of information for the frame descriptor before sending a TX frame.
*
* @flags: Descriptor flags (See &enum queue_entry_flags).
- * @queue: Queue identification (See &enum data_queue_qid).
+ * @qid: Queue identification (See &enum data_queue_qid).
* @length: Length of the entire frame.
* @header_length: Length of 802.11 header.
* @length_high: PLCP length high word.
@@ -320,7 +322,7 @@ enum txentry_desc_flags {
struct txentry_desc {
unsigned long flags;
- enum data_queue_qid queue;
+ enum data_queue_qid qid;
u16 length;
u16 header_length;
@@ -358,17 +360,17 @@ struct txentry_desc {
* @ENTRY_OWNER_DEVICE_DATA: This entry is owned by the device for data
* transfer (either TX or RX depending on the queue). The entry should
* only be touched after the device has signaled it is done with it.
- * @ENTRY_OWNER_DEVICE_CRYPTO: This entry is owned by the device for data
- * encryption or decryption. The entry should only be touched after
- * the device has signaled it is done with it.
* @ENTRY_DATA_PENDING: This entry contains a valid frame and is waiting
* for the signal to start sending.
+ * @ENTRY_DATA_IO_FAILED: Hardware indicated that an IO error occured
+ * while transfering the data to the hardware. No TX status report will
+ * be expected from the hardware.
*/
enum queue_entry_flags {
ENTRY_BCN_ASSIGNED,
ENTRY_OWNER_DEVICE_DATA,
- ENTRY_OWNER_DEVICE_CRYPTO,
ENTRY_DATA_PENDING,
+ ENTRY_DATA_IO_FAILED
};
/**
@@ -399,18 +401,18 @@ struct queue_entry {
*
* @Q_INDEX: Index pointer to the current entry in the queue, if this entry is
* owned by the hardware then the queue is considered to be full.
+ * @Q_INDEX_DMA_DONE: Index pointer for the next entry which will have been
+ * transfered to the hardware.
* @Q_INDEX_DONE: Index pointer to the next entry which will be completed by
* the hardware and for which we need to run the txdone handler. If this
* entry is not owned by the hardware the queue is considered to be empty.
- * @Q_INDEX_CRYPTO: Index pointer to the next entry which encryption/decription
- * will be completed by the hardware next.
* @Q_INDEX_MAX: Keep last, used in &struct data_queue to determine the size
* of the index array.
*/
enum queue_index {
Q_INDEX,
+ Q_INDEX_DMA_DONE,
Q_INDEX_DONE,
- Q_INDEX_CRYPTO,
Q_INDEX_MAX,
};
@@ -446,13 +448,12 @@ struct data_queue {
enum data_queue_qid qid;
spinlock_t lock;
- unsigned long last_index;
- unsigned long last_index_done;
unsigned int count;
unsigned short limit;
unsigned short threshold;
unsigned short length;
unsigned short index[Q_INDEX_MAX];
+ unsigned long last_action[Q_INDEX_MAX];
unsigned short txop;
unsigned short aifs;
@@ -565,6 +566,22 @@ struct data_queue_desc {
queue_loop(__entry, (__dev)->tx, queue_end(__dev))
/**
+ * rt2x00queue_for_each_entry - Loop through all entries in the queue
+ * @queue: Pointer to @data_queue
+ * @start: &enum queue_index Pointer to start index
+ * @end: &enum queue_index Pointer to end index
+ * @fn: The function to call for each &struct queue_entry
+ *
+ * This will walk through all entries in the queue, in chronological
+ * order. This means it will start at the current @start pointer
+ * and will walk through the queue until it reaches the @end pointer.
+ */
+void rt2x00queue_for_each_entry(struct data_queue *queue,
+ enum queue_index start,
+ enum queue_index end,
+ void (*fn)(struct queue_entry *entry));
+
+/**
* rt2x00queue_empty - Check if the queue is empty.
* @queue: Queue to check if empty.
*/
@@ -601,12 +618,23 @@ static inline int rt2x00queue_threshold(struct data_queue *queue)
}
/**
- * rt2x00queue_timeout - Check if a timeout occured for this queue
+ * rt2x00queue_timeout - Check if a timeout occured for STATUS reorts
* @queue: Queue to check.
*/
static inline int rt2x00queue_timeout(struct data_queue *queue)
{
- return time_after(queue->last_index, queue->last_index_done + (HZ / 10));
+ return time_after(queue->last_action[Q_INDEX_DMA_DONE],
+ queue->last_action[Q_INDEX_DONE] + (HZ / 10));
+}
+
+/**
+ * rt2x00queue_timeout - Check if a timeout occured for DMA transfers
+ * @queue: Queue to check.
+ */
+static inline int rt2x00queue_dma_timeout(struct data_queue *queue)
+{
+ return time_after(queue->last_action[Q_INDEX],
+ queue->last_action[Q_INDEX_DMA_DONE] + (HZ / 10));
}
/**
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index ff3a36622d1b..b3317df7a7d4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -1,5 +1,6 @@
/*
- Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+ Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@@ -167,137 +168,137 @@ EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read);
/*
* TX data handlers.
*/
-static void rt2x00usb_interrupt_txdone(struct urb *urb)
+static void rt2x00usb_work_txdone_entry(struct queue_entry *entry)
{
- struct queue_entry *entry = (struct queue_entry *)urb->context;
- struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct txdone_entry_desc txdesc;
-
- if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
- !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
- return;
-
/*
- * Obtain the status about this packet.
- * Note that when the status is 0 it does not mean the
+ * If the transfer to hardware succeeded, it does not mean the
* frame was send out correctly. It only means the frame
* was succesfully pushed to the hardware, we have no
* way to determine the transmission status right now.
* (Only indirectly by looking at the failed TX counters
* in the register).
*/
- txdesc.flags = 0;
- if (!urb->status)
- __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
+ if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+ rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
else
- __set_bit(TXDONE_FAILURE, &txdesc.flags);
- txdesc.retry = 0;
-
- rt2x00lib_txdone(entry, &txdesc);
+ rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
}
-static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
+static void rt2x00usb_work_txdone(struct work_struct *work)
{
- struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
- struct queue_entry_priv_usb *entry_priv = entry->priv_data;
- u32 length;
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, txdone_work);
+ struct data_queue *queue;
+ struct queue_entry *entry;
- if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) {
- /*
- * USB devices cannot blindly pass the skb->len as the
- * length of the data to usb_fill_bulk_urb. Pass the skb
- * to the driver to determine what the length should be.
- */
- length = rt2x00dev->ops->lib->get_tx_data_len(entry);
+ tx_queue_for_each(rt2x00dev, queue) {
+ while (!rt2x00queue_empty(queue)) {
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
- usb_fill_bulk_urb(entry_priv->urb, usb_dev,
- usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
- entry->skb->data, length,
- rt2x00usb_interrupt_txdone, entry);
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ break;
- usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+ rt2x00usb_work_txdone_entry(entry);
+ }
}
}
-void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
- const enum data_queue_qid qid)
+static void rt2x00usb_interrupt_txdone(struct urb *urb)
{
- struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid);
- unsigned long irqflags;
- unsigned int index;
- unsigned int index_done;
- unsigned int i;
+ 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))
+ return;
/*
- * Only protect the range we are going to loop over,
- * if during our loop a extra entry is set to pending
- * it should not be kicked during this run, since it
- * is part of another TX operation.
+ * Report the frame as DMA done
*/
- spin_lock_irqsave(&queue->lock, irqflags);
- index = queue->index[Q_INDEX];
- index_done = queue->index[Q_INDEX_DONE];
- spin_unlock_irqrestore(&queue->lock, irqflags);
+ rt2x00lib_dmadone(entry);
/*
- * Start from the TX done pointer, this guarentees that we will
- * send out all frames in the correct order.
+ * Check if the frame was correctly uploaded
*/
- if (index_done < index) {
- for (i = index_done; i < index; i++)
- rt2x00usb_kick_tx_entry(&queue->entries[i]);
- } else {
- for (i = index_done; i < queue->limit; i++)
- rt2x00usb_kick_tx_entry(&queue->entries[i]);
+ if (urb->status)
+ set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
- for (i = 0; i < index; i++)
- rt2x00usb_kick_tx_entry(&queue->entries[i]);
- }
+ /*
+ * Schedule the delayed work for reading the TX status
+ * from the device.
+ */
+ if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+ test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
}
-EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue);
-void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
- const enum data_queue_qid qid)
+static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
{
- struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid);
- struct queue_entry_priv_usb *entry_priv;
- struct queue_entry_priv_usb_bcn *bcn_priv;
- unsigned int i;
- bool kill_guard;
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
+ struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+ u32 length;
+
+ if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
+ return;
/*
- * When killing the beacon queue, we must also kill
- * the beacon guard byte.
+ * USB devices cannot blindly pass the skb->len as the
+ * length of the data to usb_fill_bulk_urb. Pass the skb
+ * to the driver to determine what the length should be.
*/
- kill_guard =
- (qid == QID_BEACON) &&
- (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags));
+ length = rt2x00dev->ops->lib->get_tx_data_len(entry);
+
+ usb_fill_bulk_urb(entry_priv->urb, usb_dev,
+ usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
+ entry->skb->data, length,
+ rt2x00usb_interrupt_txdone, entry);
+
+ if (usb_submit_urb(entry_priv->urb, GFP_ATOMIC)) {
+ set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
+ rt2x00lib_dmadone(entry);
+ }
+}
+
+void rt2x00usb_kick_tx_queue(struct data_queue *queue)
+{
+ rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+ rt2x00usb_kick_tx_entry);
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue);
+
+static void rt2x00usb_kill_tx_entry(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+ struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
+
+ if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ return;
+
+ usb_kill_urb(entry_priv->urb);
/*
- * Cancel all entries.
+ * Kill guardian urb (if required by driver).
*/
- for (i = 0; i < queue->limit; i++) {
- entry_priv = queue->entries[i].priv_data;
- usb_kill_urb(entry_priv->urb);
+ if ((entry->queue->qid == QID_BEACON) &&
+ (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)))
+ usb_kill_urb(bcn_priv->guardian_urb);
+}
- /*
- * Kill guardian urb (if required by driver).
- */
- if (kill_guard) {
- bcn_priv = queue->entries[i].priv_data;
- usb_kill_urb(bcn_priv->guardian_urb);
- }
- }
+void rt2x00usb_kill_tx_queue(struct data_queue *queue)
+{
+ rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+ rt2x00usb_kill_tx_entry);
}
EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);
-static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
+static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
{
- struct queue_entry_priv_usb *entry_priv;
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
unsigned short threshold = queue->threshold;
- WARNING(queue->rt2x00dev, "TX queue %d timed out, invoke reset", queue->qid);
+ WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
+ " invoke forced forced reset", queue->qid);
/*
* Temporarily disable the TX queue, this will force mac80211
@@ -307,20 +308,33 @@ static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
* queue from being enabled during the txdone handler.
*/
queue->threshold = queue->limit;
- ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid);
+ ieee80211_stop_queue(rt2x00dev->hw, queue->qid);
/*
- * Reset all currently uploaded TX frames.
+ * Kill all entries in the queue, afterwards we need to
+ * wait a bit for all URBs to be cancelled.
*/
- while (!rt2x00queue_empty(queue)) {
- entry_priv = rt2x00queue_get_entry(queue, Q_INDEX_DONE)->priv_data;
- usb_kill_urb(entry_priv->urb);
+ rt2x00usb_kill_tx_queue(queue);
- /*
- * We need a short delay here to wait for
- * the URB to be canceled and invoked the tx_done handler.
- */
- udelay(200);
+ /*
+ * In case that a driver has overriden the txdone_work
+ * function, we invoke the TX done through there.
+ */
+ rt2x00dev->txdone_work.func(&rt2x00dev->txdone_work);
+
+ /*
+ * Security measure: if the driver did override the
+ * txdone_work function, and the hardware did arrive
+ * in a state which causes it to malfunction, it is
+ * possible that the driver couldn't handle the txdone
+ * event correctly. So after giving the driver the
+ * chance to cleanup, we now force a cleanup of any
+ * leftovers.
+ */
+ if (!rt2x00queue_empty(queue)) {
+ WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
+ " status handling failed, invoke hard reset", queue->qid);
+ rt2x00usb_work_txdone(&rt2x00dev->txdone_work);
}
/*
@@ -328,7 +342,15 @@ static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
* queue again.
*/
queue->threshold = threshold;
- ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid);
+ ieee80211_wake_queue(rt2x00dev->hw, queue->qid);
+}
+
+static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
+{
+ WARNING(queue->rt2x00dev, "TX queue %d status timed out,"
+ " invoke forced tx handler", queue->qid);
+
+ ieee80211_queue_work(queue->rt2x00dev->hw, &queue->rt2x00dev->txdone_work);
}
void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
@@ -336,8 +358,12 @@ void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
struct data_queue *queue;
tx_queue_for_each(rt2x00dev, queue) {
- if (rt2x00queue_timeout(queue))
- rt2x00usb_watchdog_reset_tx(queue);
+ if (!rt2x00queue_empty(queue)) {
+ if (rt2x00queue_dma_timeout(queue))
+ rt2x00usb_watchdog_tx_dma(queue);
+ if (rt2x00queue_timeout(queue))
+ rt2x00usb_watchdog_tx_status(queue);
+ }
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
@@ -345,38 +371,62 @@ EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
/*
* RX data handlers.
*/
+static void rt2x00usb_work_rxdone(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, rxdone_work);
+ struct queue_entry *entry;
+ struct skb_frame_desc *skbdesc;
+ u8 rxd[32];
+
+ while (!rt2x00queue_empty(rt2x00dev->rx)) {
+ entry = rt2x00queue_get_entry(rt2x00dev->rx, Q_INDEX_DONE);
+
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ break;
+
+ /*
+ * Fill in desc fields of the skb descriptor
+ */
+ skbdesc = get_skb_frame_desc(entry->skb);
+ skbdesc->desc = rxd;
+ skbdesc->desc_len = entry->queue->desc_size;
+
+ /*
+ * Send the frame to rt2x00lib for further processing.
+ */
+ rt2x00lib_rxdone(entry);
+ }
+}
+
static void rt2x00usb_interrupt_rxdone(struct urb *urb)
{
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- u8 rxd[32];
- if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
- !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
/*
- * Check if the received data is simply too small
- * to be actually valid, or if the urb is signaling
- * a problem.
+ * Report the frame as DMA done
*/
- if (urb->actual_length < entry->queue->desc_size || urb->status) {
- set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
- usb_submit_urb(urb, GFP_ATOMIC);
- return;
- }
+ rt2x00lib_dmadone(entry);
/*
- * Fill in desc fields of the skb descriptor
+ * Check if the received data is simply too small
+ * to be actually valid, or if the urb is signaling
+ * a problem.
*/
- skbdesc->desc = rxd;
- skbdesc->desc_len = entry->queue->desc_size;
+ if (urb->actual_length < entry->queue->desc_size || urb->status)
+ set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
/*
- * Send the frame to rt2x00lib for further processing.
+ * Schedule the delayed work for reading the RX status
+ * from the device.
*/
- rt2x00lib_rxdone(rt2x00dev, entry);
+ if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+ test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
}
/*
@@ -391,7 +441,7 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
* The USB version of kill_tx_queue also works
* on the RX queue.
*/
- rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_RX);
+ rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev->rx);
}
EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
@@ -405,6 +455,8 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
int pipe;
+ entry->flags = 0;
+
if (entry->queue->qid == QID_RX) {
pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint);
usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe,
@@ -412,9 +464,10 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
rt2x00usb_interrupt_rxdone, entry);
set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
- usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
- } else {
- entry->flags = 0;
+ if (usb_submit_urb(entry_priv->urb, GFP_ATOMIC)) {
+ set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
+ rt2x00lib_dmadone(entry);
+ }
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
@@ -489,9 +542,9 @@ static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev)
return 0;
}
-static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
- struct data_queue *queue)
+static int rt2x00usb_alloc_entries(struct data_queue *queue)
{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
struct queue_entry_priv_usb *entry_priv;
struct queue_entry_priv_usb_bcn *bcn_priv;
unsigned int i;
@@ -508,7 +561,7 @@ static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
* no guardian byte was required for the beacon,
* then we are done.
*/
- if (rt2x00dev->bcn != queue ||
+ if (queue->qid != QID_BEACON ||
!test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
return 0;
@@ -522,9 +575,9 @@ static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
return 0;
}
-static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
- struct data_queue *queue)
+static void rt2x00usb_free_entries(struct data_queue *queue)
{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
struct queue_entry_priv_usb *entry_priv;
struct queue_entry_priv_usb_bcn *bcn_priv;
unsigned int i;
@@ -543,7 +596,7 @@ static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
* no guardian byte was required for the beacon,
* then we are done.
*/
- if (rt2x00dev->bcn != queue ||
+ if (queue->qid != QID_BEACON ||
!test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
return;
@@ -570,7 +623,7 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
* Allocate DMA
*/
queue_for_each(rt2x00dev, queue) {
- status = rt2x00usb_alloc_urb(rt2x00dev, queue);
+ status = rt2x00usb_alloc_entries(queue);
if (status)
goto exit;
}
@@ -589,7 +642,7 @@ void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev)
struct data_queue *queue;
queue_for_each(rt2x00dev, queue)
- rt2x00usb_free_urb(rt2x00dev, queue);
+ rt2x00usb_free_entries(queue);
}
EXPORT_SYMBOL_GPL(rt2x00usb_uninitialize);
@@ -659,6 +712,9 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);
+ INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone);
+ INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone);
+
retval = rt2x00usb_alloc_reg(rt2x00dev);
if (retval)
goto exit_free_device;
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index d3d3ddc40875..c2d997f67b3e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -379,25 +379,21 @@ struct queue_entry_priv_usb_bcn {
/**
* rt2x00usb_kick_tx_queue - Kick data queue
- * @rt2x00dev: Pointer to &struct rt2x00_dev
- * @qid: Data queue to kick
+ * @queue: Data queue to kick
*
* This will walk through all entries of the queue and push all pending
* frames to the hardware as a single burst.
*/
-void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
- const enum data_queue_qid qid);
+void rt2x00usb_kick_tx_queue(struct data_queue *queue);
/**
* rt2x00usb_kill_tx_queue - Kill data queue
- * @rt2x00dev: Pointer to &struct rt2x00_dev
- * @qid: Data queue to kill
+ * @queue: Data queue to kill
*
* This will walk through all entries of the queue and kill all
* previously kicked frames before they can be send.
*/
-void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
- const enum data_queue_qid qid);
+void rt2x00usb_kill_tx_queue(struct data_queue *queue);
/**
* rt2x00usb_watchdog - Watchdog for USB communication
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index e539c6cb636f..af548c87f108 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -594,7 +594,8 @@ static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev,
}
static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev,
- struct rt2x00lib_erp *erp)
+ struct rt2x00lib_erp *erp,
+ u32 changed)
{
u32 reg;
@@ -603,28 +604,36 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
- rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
- !!erp->short_preamble);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
+ !!erp->short_preamble);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+ }
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
+ if (changed & BSS_CHANGED_BASIC_RATES)
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR5,
+ erp->basic_rates);
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
- erp->beacon_int * 16);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ if (changed & BSS_CHANGED_BEACON_INT) {
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
+ erp->beacon_int * 16);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ }
- rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
- rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
- rt2x00pci_register_read(rt2x00dev, MAC_CSR8, &reg);
- rt2x00_set_field32(&reg, MAC_CSR8_SIFS, erp->sifs);
- rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
- rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg);
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR8, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS, erp->sifs);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+ rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg);
+ }
}
static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
@@ -1050,7 +1059,7 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev,
/*
* Determine r17 bounds.
*/
- if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
+ if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
low_bound = 0x28;
up_bound = 0x48;
if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
@@ -1645,6 +1654,7 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
rt2x00_set_field32(&reg, INT_MASK_CSR_TXDONE, mask);
rt2x00_set_field32(&reg, INT_MASK_CSR_RXDONE, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_BEACON_DONE, mask);
rt2x00_set_field32(&reg, INT_MASK_CSR_ENABLE_MITIGATION, mask);
rt2x00_set_field32(&reg, INT_MASK_CSR_MITIGATION_PERIOD, 0xff);
rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
@@ -1658,6 +1668,7 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_5, mask);
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_6, mask);
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_7, mask);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_TWAKEUP, mask);
rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
}
@@ -1766,12 +1777,11 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* TX descriptor initialization
*/
-static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb,
+static void rt61pci_write_tx_desc(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
__le32 *txd = entry_priv->desc;
u32 word;
@@ -1779,7 +1789,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
* Start writing the descriptor words.
*/
rt2x00_desc_read(txd, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue);
+ rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->qid);
rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
@@ -1802,15 +1812,15 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
}
rt2x00_desc_read(txd, 5, &word);
- rt2x00_set_field32(&word, TXD_W5_PID_TYPE, skbdesc->entry->queue->qid);
+ rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid);
rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE,
skbdesc->entry->entry_idx);
rt2x00_set_field32(&word, TXD_W5_TX_POWER,
- TXPOWER_TO_DEV(rt2x00dev->tx_power));
+ TXPOWER_TO_DEV(entry->queue->rt2x00dev->tx_power));
rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
rt2x00_desc_write(txd, 5, word);
- if (txdesc->queue != QID_BEACON) {
+ if (txdesc->qid != QID_BEACON) {
rt2x00_desc_read(txd, 6, &word);
rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
skbdesc->skb_dma);
@@ -1857,7 +1867,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
*/
skbdesc->desc = txd;
skbdesc->desc_len =
- (txdesc->queue == QID_BEACON) ? TXINFO_SIZE : TXD_DESC_SIZE;
+ (txdesc->qid == QID_BEACON) ? TXINFO_SIZE : TXD_DESC_SIZE;
}
/*
@@ -1882,7 +1892,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
/*
* Write the TX descriptor for the beacon.
*/
- rt61pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+ rt61pci_write_tx_desc(entry, txdesc);
/*
* Dump beacon to userspace through debugfs.
@@ -1918,34 +1928,34 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
entry->skb = NULL;
}
-static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
- const enum data_queue_qid queue)
+static void rt61pci_kick_tx_queue(struct data_queue *queue)
{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
u32 reg;
rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
- rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, (queue == QID_AC_BE));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, (queue == QID_AC_BK));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, (queue == QID_AC_VI));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, (queue == QID_AC_VO));
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, (queue->qid == QID_AC_BE));
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, (queue->qid == QID_AC_BK));
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, (queue->qid == QID_AC_VI));
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, (queue->qid == QID_AC_VO));
rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
}
-static void rt61pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
- const enum data_queue_qid qid)
+static void rt61pci_kill_tx_queue(struct data_queue *queue)
{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
u32 reg;
- if (qid == QID_BEACON) {
+ if (queue->qid == QID_BEACON) {
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0);
return;
}
rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, (qid == QID_AC_BE));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, (qid == QID_AC_BK));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, (qid == QID_AC_VI));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, (qid == QID_AC_VO));
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, (queue->qid == QID_AC_BE));
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, (queue->qid == QID_AC_BK));
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, (queue->qid == QID_AC_VI));
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, (queue->qid == QID_AC_VO));
rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
}
@@ -1972,7 +1982,7 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
return 0;
}
- if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
+ if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
if (lna == 3 || lna == 2)
offset += 10;
}
@@ -2107,11 +2117,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
"TX status report missed for entry %d\n",
entry_done->entry_idx);
- txdesc.flags = 0;
- __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
- txdesc.retry = 0;
-
- rt2x00lib_txdone(entry_done, &txdesc);
+ rt2x00lib_txdone_noinfo(entry_done, TXDONE_UNKNOWN);
entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
}
@@ -2624,12 +2630,13 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
* As rt61 has a global fallback table we cannot specify
* more then one tx rate per frame but since the hw will
* try several rates (based on the fallback table) we should
- * still initialize max_rates to the maximum number of rates
+ * initialize max_report_rates to the maximum number of rates
* we are going to try. Otherwise mac80211 will truncate our
* reported tx rates and the rc algortihm will end up with
* incorrect data.
*/
- rt2x00dev->hw->max_rates = 7;
+ rt2x00dev->hw->max_rates = 1;
+ rt2x00dev->hw->max_report_rates = 7;
rt2x00dev->hw->max_rate_tries = 1;
/*
@@ -2654,20 +2661,24 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Create channel information array
*/
- info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+ info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
spec->channels_info = info;
tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
- for (i = 0; i < 14; i++)
- info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+ for (i = 0; i < 14; i++) {
+ info[i].max_power = MAX_TXPOWER;
+ info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+ }
if (spec->num_channels > 14) {
tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
- for (i = 14; i < spec->num_channels; i++)
- info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+ for (i = 14; i < spec->num_channels; i++) {
+ info[i].max_power = MAX_TXPOWER;
+ info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+ }
}
return 0;
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index aa9de18fd410..9be8089317e4 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -545,7 +545,8 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
}
static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev,
- struct rt2x00lib_erp *erp)
+ struct rt2x00lib_erp *erp,
+ u32 changed)
{
u32 reg;
@@ -554,28 +555,36 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
- rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
- rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
- !!erp->short_preamble);
- rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
+ !!erp->short_preamble);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+ }
- rt2x00usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
+ if (changed & BSS_CHANGED_BASIC_RATES)
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR5,
+ erp->basic_rates);
- rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
- erp->beacon_int * 16);
- rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ if (changed & BSS_CHANGED_BEACON_INT) {
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
+ erp->beacon_int * 16);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ }
- rt2x00usb_register_read(rt2x00dev, MAC_CSR9, &reg);
- rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
- rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg);
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg);
- rt2x00usb_register_read(rt2x00dev, MAC_CSR8, &reg);
- rt2x00_set_field32(&reg, MAC_CSR8_SIFS, erp->sifs);
- rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
- rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs);
- rt2x00usb_register_write(rt2x00dev, MAC_CSR8, reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR8, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS, erp->sifs);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+ rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR8, reg);
+ }
}
static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
@@ -929,7 +938,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev,
/*
* Determine r17 bounds.
*/
- if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
+ if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
low_bound = 0x28;
up_bound = 0x48;
@@ -1426,12 +1435,11 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* TX descriptor initialization
*/
-static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb,
+static void rt73usb_write_tx_desc(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txd = (__le32 *) skb->data;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ __le32 *txd = (__le32 *) entry->skb->data;
u32 word;
/*
@@ -1464,7 +1472,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_desc_write(txd, 0, word);
rt2x00_desc_read(txd, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue);
+ rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->qid);
rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
@@ -1487,7 +1495,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_desc_read(txd, 5, &word);
rt2x00_set_field32(&word, TXD_W5_TX_POWER,
- TXPOWER_TO_DEV(rt2x00dev->tx_power));
+ TXPOWER_TO_DEV(entry->queue->rt2x00dev->tx_power));
rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
rt2x00_desc_write(txd, 5, word);
@@ -1526,7 +1534,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
/*
* Write the TX descriptor for the beacon.
*/
- rt73usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+ rt73usb_write_tx_desc(entry, txdesc);
/*
* Dump beacon to userspace through debugfs.
@@ -1574,6 +1582,14 @@ static int rt73usb_get_tx_data_len(struct queue_entry *entry)
return length;
}
+static void rt73usb_kill_tx_queue(struct data_queue *queue)
+{
+ if (queue->qid == QID_BEACON)
+ rt2x00usb_register_write(queue->rt2x00dev, TXRX_CSR9, 0);
+
+ rt2x00usb_kill_tx_queue(queue);
+}
+
/*
* RX control handlers
*/
@@ -1597,7 +1613,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
return 0;
}
- if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
+ if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
if (lna == 3 || lna == 2)
offset += 10;
@@ -2047,9 +2063,14 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all hw fields.
+ *
+ * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING unless we are
+ * capable of sending the buffered frames out after the DTIM
+ * transmission using rt2x00lib_beacondone. This will send out
+ * multicast and broadcast traffic immediately instead of buffering it
+ * infinitly and thus dropping it after some time.
*/
rt2x00dev->hw->flags =
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK;
@@ -2084,20 +2105,24 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Create channel information array
*/
- info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+ info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
spec->channels_info = info;
tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
- for (i = 0; i < 14; i++)
- info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+ for (i = 0; i < 14; i++) {
+ info[i].max_power = MAX_TXPOWER;
+ info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+ }
if (spec->num_channels > 14) {
tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
- for (i = 14; i < spec->num_channels; i++)
- info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+ for (i = 14; i < spec->num_channels; i++) {
+ info[i].max_power = MAX_TXPOWER;
+ info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+ }
}
return 0;
@@ -2259,7 +2284,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.write_beacon = rt73usb_write_beacon,
.get_tx_data_len = rt73usb_get_tx_data_len,
.kick_tx_queue = rt2x00usb_kick_tx_queue,
- .kill_tx_queue = rt2x00usb_kill_tx_queue,
+ .kill_tx_queue = rt73usb_kill_tx_queue,
.fill_rxdone = rt73usb_fill_rxdone,
.config_shared_key = rt73usb_config_shared_key,
.config_pairwise_key = rt73usb_config_pairwise_key,
@@ -2345,6 +2370,7 @@ static struct usb_device_id rt73usb_device_table[] = {
{ USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0411, 0x0137), USB_DEVICE_DATA(&rt73usb_ops) },
/* CEIVA */
{ USB_DEVICE(0x178d, 0x02be), USB_DEVICE_DATA(&rt73usb_ops) },
/* CNet */
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
index 30107ce78dfb..707c688da618 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -783,6 +783,7 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
struct rtl8180_priv *priv = dev->priv;
struct rtl8180_vif *vif_priv;
int i;
+ u8 reg;
vif_priv = (struct rtl8180_vif *)&vif->drv_priv;
@@ -791,12 +792,14 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
rtl818x_iowrite8(priv, &priv->map->BSSID[i],
info->bssid[i]);
- if (is_valid_ether_addr(info->bssid))
- rtl818x_iowrite8(priv, &priv->map->MSR,
- RTL818X_MSR_INFRA);
- else
- rtl818x_iowrite8(priv, &priv->map->MSR,
- RTL818X_MSR_NO_LINK);
+ if (is_valid_ether_addr(info->bssid)) {
+ if (vif->type == NL80211_IFTYPE_ADHOC)
+ reg = RTL818X_MSR_ADHOC;
+ else
+ reg = RTL818X_MSR_INFRA;
+ } else
+ reg = RTL818X_MSR_NO_LINK;
+ rtl818x_iowrite8(priv, &priv->map->MSR, reg);
}
if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp)
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index 98e0351c1dd6..38fa8244cc96 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -1176,13 +1176,12 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
else
reg = 0;
- if (is_valid_ether_addr(info->bssid)) {
+ if (is_valid_ether_addr(info->bssid))
reg |= RTL818X_MSR_INFRA;
- rtl818x_iowrite8(priv, &priv->map->MSR, reg);
- } else {
+ else
reg |= RTL818X_MSR_NO_LINK;
- rtl818x_iowrite8(priv, &priv->map->MSR, reg);
- }
+
+ rtl818x_iowrite8(priv, &priv->map->MSR, reg);
mutex_unlock(&priv->conf_mutex);
}
diff --git a/drivers/net/wireless/wl1251/Kconfig b/drivers/net/wireless/wl1251/Kconfig
new file mode 100644
index 000000000000..1fb65849414f
--- /dev/null
+++ b/drivers/net/wireless/wl1251/Kconfig
@@ -0,0 +1,33 @@
+menuconfig WL1251
+ tristate "TI wl1251 driver support"
+ depends on MAC80211 && EXPERIMENTAL && GENERIC_HARDIRQS
+ select FW_LOADER
+ select CRC7
+ ---help---
+ This will enable TI wl1251 driver support. The drivers make
+ use of the mac80211 stack.
+
+ If you choose to build a module, it'll be called wl1251. Say
+ N if unsure.
+
+config WL1251_SPI
+ tristate "TI wl1251 SPI support"
+ depends on WL1251 && SPI_MASTER
+ ---help---
+ This module adds support for the SPI interface of adapters using
+ TI wl1251 chipset. Select this if your platform is using
+ the SPI bus.
+
+ If you choose to build a module, it'll be called wl1251_spi.
+ Say N if unsure.
+
+config WL1251_SDIO
+ tristate "TI wl1251 SDIO support"
+ depends on WL1251 && MMC
+ ---help---
+ This module adds support for the SDIO interface of adapters using
+ TI wl1251 chipset. Select this if your platform is using
+ the SDIO bus.
+
+ If you choose to build a module, it'll be called
+ wl1251_sdio. Say N if unsure.
diff --git a/drivers/net/wireless/wl1251/Makefile b/drivers/net/wireless/wl1251/Makefile
new file mode 100644
index 000000000000..58b4f935a3f6
--- /dev/null
+++ b/drivers/net/wireless/wl1251/Makefile
@@ -0,0 +1,8 @@
+wl1251-objs = main.o event.o tx.o rx.o ps.o cmd.o \
+ acx.o boot.o init.o debugfs.o io.o
+wl1251_spi-objs += spi.o
+wl1251_sdio-objs += sdio.o
+
+obj-$(CONFIG_WL1251) += wl1251.o
+obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o
+obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl1251/acx.c
index 91891f928070..64a0214cfb29 100644
--- a/drivers/net/wireless/wl12xx/wl1251_acx.c
+++ b/drivers/net/wireless/wl1251/acx.c
@@ -1,13 +1,13 @@
-#include "wl1251_acx.h"
+#include "acx.h"
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/crc7.h>
#include "wl1251.h"
-#include "wl1251_reg.h"
-#include "wl1251_cmd.h"
-#include "wl1251_ps.h"
+#include "reg.h"
+#include "cmd.h"
+#include "ps.h"
int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod,
u8 mgt_rate, u8 mgt_mod)
@@ -380,7 +380,7 @@ int wl1251_acx_pd_threshold(struct wl1251 *wl)
out:
kfree(pd);
- return 0;
+ return ret;
}
int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time)
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl1251/acx.h
index 842df310d92a..e54b21a4f8b1 100644
--- a/drivers/net/wireless/wl12xx/wl1251_acx.h
+++ b/drivers/net/wireless/wl1251/acx.h
@@ -4,8 +4,6 @@
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -26,7 +24,7 @@
#define __WL1251_ACX_H__
#include "wl1251.h"
-#include "wl1251_cmd.h"
+#include "cmd.h"
/* Target's information element */
struct acx_header {
@@ -37,7 +35,7 @@ struct acx_header {
/* payload length (not including headers */
u16 len;
-};
+} __packed;
struct acx_error_counter {
struct acx_header header;
@@ -459,8 +457,8 @@ struct acx_beacon_filter_ie_table {
struct acx_header header;
u8 num_ie;
- u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
u8 pad[3];
+ u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
} __packed;
#define SYNCH_FAIL_DEFAULT_THRESHOLD 10 /* number of beacons */
@@ -471,7 +469,7 @@ struct acx_conn_monit_params {
u32 synch_fail_thold; /* number of beacons missed */
u32 bss_lose_timeout; /* number of TU's from synch fail */
-};
+} __packed;
enum {
SG_ENABLE = 0,
@@ -1056,7 +1054,7 @@ struct acx_rate_class {
u8 long_retry_limit;
u8 aflags;
u8 reserved;
-};
+} __packed;
struct acx_rate_policy {
struct acx_header header;
diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl1251/boot.c
index 65e0416be5b6..61572dfa1f60 100644
--- a/drivers/net/wireless/wl12xx/wl1251_boot.c
+++ b/drivers/net/wireless/wl1251/boot.c
@@ -3,8 +3,6 @@
*
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -24,12 +22,12 @@
#include <linux/gpio.h>
#include <linux/slab.h>
-#include "wl1251_reg.h"
-#include "wl1251_boot.h"
-#include "wl1251_io.h"
-#include "wl1251_spi.h"
-#include "wl1251_event.h"
-#include "wl1251_acx.h"
+#include "reg.h"
+#include "boot.h"
+#include "io.h"
+#include "spi.h"
+#include "event.h"
+#include "acx.h"
void wl1251_boot_target_enable_interrupts(struct wl1251 *wl)
{
@@ -302,7 +300,7 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
ROAMING_TRIGGER_LOW_RSSI_EVENT_ID |
ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID |
REGAINED_BSS_EVENT_ID | BT_PTA_SENSE_EVENT_ID |
- BT_PTA_PREDICTION_EVENT_ID;
+ BT_PTA_PREDICTION_EVENT_ID | JOIN_EVENT_COMPLETE_ID;
ret = wl1251_event_unmask(wl);
if (ret < 0) {
diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.h b/drivers/net/wireless/wl1251/boot.h
index 90063697e8f2..7661bc5e4662 100644
--- a/drivers/net/wireless/wl12xx/wl1251_boot.h
+++ b/drivers/net/wireless/wl1251/boot.h
@@ -3,8 +3,6 @@
*
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl1251/cmd.c
index ce3722f4c3e3..0ade4bd617c0 100644
--- a/drivers/net/wireless/wl12xx/wl1251_cmd.c
+++ b/drivers/net/wireless/wl1251/cmd.c
@@ -1,14 +1,14 @@
-#include "wl1251_cmd.h"
+#include "cmd.h"
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/crc7.h>
#include "wl1251.h"
-#include "wl1251_reg.h"
-#include "wl1251_io.h"
-#include "wl1251_ps.h"
-#include "wl1251_acx.h"
+#include "reg.h"
+#include "io.h"
+#include "ps.h"
+#include "acx.h"
/**
* send command to firmware
@@ -200,7 +200,7 @@ int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity,
out:
kfree(vbm);
- return 0;
+ return ret;
}
int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable)
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl1251/cmd.h
index a9e4991369be..e5c74c631374 100644
--- a/drivers/net/wireless/wl12xx/wl1251_cmd.h
+++ b/drivers/net/wireless/wl1251/cmd.h
@@ -4,8 +4,6 @@
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -111,7 +109,7 @@ struct wl1251_cmd_header {
struct wl1251_command {
struct wl1251_cmd_header header;
u8 parameters[MAX_CMD_PARAMS];
-};
+} __packed;
enum {
CMD_MAILBOX_IDLE = 0,
@@ -164,7 +162,7 @@ struct cmd_read_write_memory {
of this field is the Host in WRITE command or the Wilink in READ
command. */
u8 value[MAX_READ_SIZE];
-};
+} __packed;
#define CMDMBOX_HEADER_LEN 4
#define CMDMBOX_INFO_ELEM_HEADER_LEN 4
@@ -339,7 +337,7 @@ struct wl1251_cmd_trigger_scan_to {
struct wl1251_cmd_header header;
u32 timeout;
-};
+} __packed;
/* HW encryption keys */
#define NUM_ACCESS_CATEGORIES_COPY 4
diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl1251/debugfs.c
index fa620a5e5303..6c274007d200 100644
--- a/drivers/net/wireless/wl12xx/wl1251_debugfs.c
+++ b/drivers/net/wireless/wl1251/debugfs.c
@@ -3,8 +3,6 @@
*
* Copyright (C) 2009 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -21,14 +19,14 @@
*
*/
-#include "wl1251_debugfs.h"
+#include "debugfs.h"
#include <linux/skbuff.h>
#include <linux/slab.h>
#include "wl1251.h"
-#include "wl1251_acx.h"
-#include "wl1251_ps.h"
+#include "acx.h"
+#include "ps.h"
/* ms */
#define WL1251_DEBUGFS_STATS_LIFETIME 1000
diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.h b/drivers/net/wireless/wl1251/debugfs.h
index 6dc3d080853c..b3417c02a218 100644
--- a/drivers/net/wireless/wl12xx/wl1251_debugfs.h
+++ b/drivers/net/wireless/wl1251/debugfs.h
@@ -3,8 +3,6 @@
*
* Copyright (C) 2009 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl1251/event.c
index 020d764f9c13..712372e50a87 100644
--- a/drivers/net/wireless/wl12xx/wl1251_event.c
+++ b/drivers/net/wireless/wl1251/event.c
@@ -4,8 +4,6 @@
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -23,10 +21,10 @@
*/
#include "wl1251.h"
-#include "wl1251_reg.h"
-#include "wl1251_io.h"
-#include "wl1251_event.h"
-#include "wl1251_ps.h"
+#include "reg.h"
+#include "io.h"
+#include "event.h"
+#include "ps.h"
static int wl1251_event_scan_complete(struct wl1251 *wl,
struct event_mailbox *mbox)
@@ -36,9 +34,7 @@ static int wl1251_event_scan_complete(struct wl1251 *wl,
mbox->scheduled_scan_channels);
if (wl->scanning) {
- mutex_unlock(&wl->mutex);
ieee80211_scan_completed(wl->hw, false);
- mutex_lock(&wl->mutex);
wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed");
wl->scanning = false;
}
@@ -97,6 +93,35 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
return 0;
}
+/*
+ * Poll the mailbox event field until any of the bits in the mask is set or a
+ * timeout occurs (WL1251_EVENT_TIMEOUT in msecs)
+ */
+int wl1251_event_wait(struct wl1251 *wl, u32 mask, int timeout_ms)
+{
+ u32 events_vector, event;
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(timeout_ms);
+
+ do {
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+
+ msleep(1);
+
+ /* read from both event fields */
+ wl1251_mem_read(wl, wl->mbox_ptr[0], &events_vector,
+ sizeof(events_vector));
+ event = events_vector & mask;
+ wl1251_mem_read(wl, wl->mbox_ptr[1], &events_vector,
+ sizeof(events_vector));
+ event |= events_vector & mask;
+ } while (!event);
+
+ return 0;
+}
+
int wl1251_event_unmask(struct wl1251 *wl)
{
int ret;
diff --git a/drivers/net/wireless/wl12xx/wl1251_event.h b/drivers/net/wireless/wl1251/event.h
index f48a2b66bc5a..30eb5d150bf7 100644
--- a/drivers/net/wireless/wl12xx/wl1251_event.h
+++ b/drivers/net/wireless/wl1251/event.h
@@ -4,8 +4,6 @@
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -117,5 +115,6 @@ struct event_mailbox {
int wl1251_event_unmask(struct wl1251 *wl);
void wl1251_event_mbox_config(struct wl1251 *wl);
int wl1251_event_handle(struct wl1251 *wl, u8 mbox);
+int wl1251_event_wait(struct wl1251 *wl, u32 mask, int timeout_ms);
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl1251/init.c
index b538bdd7b320..89b43d35473c 100644
--- a/drivers/net/wireless/wl12xx/wl1251_init.c
+++ b/drivers/net/wireless/wl1251/init.c
@@ -3,8 +3,6 @@
*
* Copyright (C) 2009 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -25,11 +23,11 @@
#include <linux/module.h>
#include <linux/slab.h>
-#include "wl1251_init.h"
+#include "init.h"
#include "wl12xx_80211.h"
-#include "wl1251_acx.h"
-#include "wl1251_cmd.h"
-#include "wl1251_reg.h"
+#include "acx.h"
+#include "cmd.h"
+#include "reg.h"
int wl1251_hw_init_hwenc_config(struct wl1251 *wl)
{
diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl1251/init.h
index 269cefb3e7d4..543f17582ead 100644
--- a/drivers/net/wireless/wl12xx/wl1251_init.h
+++ b/drivers/net/wireless/wl1251/init.h
@@ -3,8 +3,6 @@
*
* Copyright (C) 2009 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl1251/io.c
index f1c232e0887f..cdcadbf6ac2c 100644
--- a/drivers/net/wireless/wl12xx/wl1251_io.c
+++ b/drivers/net/wireless/wl1251/io.c
@@ -3,8 +3,6 @@
*
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -22,8 +20,8 @@
*/
#include "wl1251.h"
-#include "wl1251_reg.h"
-#include "wl1251_io.h"
+#include "reg.h"
+#include "io.h"
/* FIXME: this is static data nowadays and the table can be removed */
static enum wl12xx_acx_int_reg wl1251_io_reg_table[ACX_REG_TABLE_LEN] = {
diff --git a/drivers/net/wireless/wl12xx/wl1251_io.h b/drivers/net/wireless/wl1251/io.h
index c545e9d5f512..c545e9d5f512 100644
--- a/drivers/net/wireless/wl12xx/wl1251_io.h
+++ b/drivers/net/wireless/wl1251/io.h
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl1251/main.c
index 861a5f33761e..7a8762553cdc 100644
--- a/drivers/net/wireless/wl12xx/wl1251_main.c
+++ b/drivers/net/wireless/wl1251/main.c
@@ -3,8 +3,6 @@
*
* Copyright (C) 2008-2009 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -33,16 +31,16 @@
#include "wl1251.h"
#include "wl12xx_80211.h"
-#include "wl1251_reg.h"
-#include "wl1251_io.h"
-#include "wl1251_cmd.h"
-#include "wl1251_event.h"
-#include "wl1251_tx.h"
-#include "wl1251_rx.h"
-#include "wl1251_ps.h"
-#include "wl1251_init.h"
-#include "wl1251_debugfs.h"
-#include "wl1251_boot.h"
+#include "reg.h"
+#include "io.h"
+#include "cmd.h"
+#include "event.h"
+#include "tx.h"
+#include "rx.h"
+#include "ps.h"
+#include "init.h"
+#include "debugfs.h"
+#include "boot.h"
void wl1251_enable_interrupts(struct wl1251 *wl)
{
@@ -293,14 +291,14 @@ static void wl1251_irq_work(struct work_struct *work)
wl1251_tx_complete(wl);
}
- if (intr & (WL1251_ACX_INTR_EVENT_A |
- WL1251_ACX_INTR_EVENT_B)) {
- wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)",
- intr);
- if (intr & WL1251_ACX_INTR_EVENT_A)
- wl1251_event_handle(wl, 0);
- else
- wl1251_event_handle(wl, 1);
+ if (intr & WL1251_ACX_INTR_EVENT_A) {
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT_A");
+ wl1251_event_handle(wl, 0);
+ }
+
+ if (intr & WL1251_ACX_INTR_EVENT_B) {
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT_B");
+ wl1251_event_handle(wl, 1);
}
if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
@@ -339,11 +337,9 @@ static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel,
if (ret < 0)
goto out;
- /*
- * FIXME: we should wait for JOIN_EVENT_COMPLETE_ID but to simplify
- * locking we just sleep instead, for now
- */
- msleep(10);
+ ret = wl1251_event_wait(wl, JOIN_EVENT_COMPLETE_ID, 100);
+ if (ret < 0)
+ wl1251_warning("join timeout");
out:
return ret;
@@ -379,6 +375,7 @@ out:
static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct wl1251 *wl = hw->priv;
+ unsigned long flags;
skb_queue_tail(&wl->tx_queue, skb);
@@ -393,16 +390,13 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* The workqueue is slow to process the tx_queue and we need stop
* the queue here, otherwise the queue will get too long.
*/
- if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) {
+ if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_HIGH_WATERMARK) {
wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues");
- ieee80211_stop_queues(wl->hw);
- /*
- * FIXME: this is racy, the variable is not properly
- * protected. Maybe fix this by removing the stupid
- * variable altogether and checking the real queue state?
- */
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ ieee80211_stop_queues(wl->hw);
wl->tx_queue_stopped = true;
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
}
return NETDEV_TX_OK;
@@ -471,9 +465,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
WARN_ON(wl->state != WL1251_STATE_ON);
if (wl->scanning) {
- mutex_unlock(&wl->mutex);
ieee80211_scan_completed(wl->hw, true);
- mutex_lock(&wl->mutex);
wl->scanning = false;
}
@@ -725,8 +717,9 @@ static int wl1251_set_key_type(struct wl1251 *wl,
struct ieee80211_key_conf *mac80211_key,
const u8 *addr)
{
- switch (mac80211_key->alg) {
- case ALG_WEP:
+ switch (mac80211_key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
if (is_broadcast_ether_addr(addr))
key->key_type = KEY_WEP_DEFAULT;
else
@@ -734,7 +727,7 @@ static int wl1251_set_key_type(struct wl1251 *wl,
mac80211_key->hw_key_idx = mac80211_key->keyidx;
break;
- case ALG_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
if (is_broadcast_ether_addr(addr))
key->key_type = KEY_TKIP_MIC_GROUP;
else
@@ -742,7 +735,7 @@ static int wl1251_set_key_type(struct wl1251 *wl,
mac80211_key->hw_key_idx = mac80211_key->keyidx;
break;
- case ALG_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
if (is_broadcast_ether_addr(addr))
key->key_type = KEY_AES_GROUP;
else
@@ -750,7 +743,7 @@ static int wl1251_set_key_type(struct wl1251 *wl,
mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
break;
default:
- wl1251_error("Unknown key algo 0x%x", mac80211_key->alg);
+ wl1251_error("Unknown key cipher 0x%x", mac80211_key->cipher);
return -EOPNOTSUPP;
}
@@ -783,7 +776,7 @@ static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
wl1251_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
wl1251_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
wl1251_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
- key->alg, key->keyidx, key->keylen, key->flags);
+ key->cipher, key->keyidx, key->keylen, key->flags);
wl1251_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen);
if (is_zero_ether_addr(addr)) {
@@ -1438,5 +1431,5 @@ EXPORT_SYMBOL_GPL(wl1251_free_hw);
MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core");
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
+MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
MODULE_FIRMWARE(WL1251_FW_NAME);
diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl1251/ps.c
index b55cb2bd459a..5ed47c8373d2 100644
--- a/drivers/net/wireless/wl12xx/wl1251_ps.c
+++ b/drivers/net/wireless/wl1251/ps.c
@@ -3,8 +3,6 @@
*
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -21,10 +19,10 @@
*
*/
-#include "wl1251_reg.h"
-#include "wl1251_ps.h"
-#include "wl1251_cmd.h"
-#include "wl1251_io.h"
+#include "reg.h"
+#include "ps.h"
+#include "cmd.h"
+#include "io.h"
/* in ms */
#define WL1251_WAKEUP_TIMEOUT 100
diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.h b/drivers/net/wireless/wl1251/ps.h
index c688ac57aee4..55c3dda75e69 100644
--- a/drivers/net/wireless/wl12xx/wl1251_ps.h
+++ b/drivers/net/wireless/wl1251/ps.h
@@ -1,14 +1,9 @@
-#ifndef __WL1251_PS_H__
-#define __WL1251_PS_H__
-
/*
* This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -25,8 +20,11 @@
*
*/
+#ifndef __WL1251_PS_H__
+#define __WL1251_PS_H__
+
#include "wl1251.h"
-#include "wl1251_acx.h"
+#include "acx.h"
int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode);
void wl1251_ps_elp_sleep(struct wl1251 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl1251/reg.h
index d16edd9bf06c..a5809019c5c1 100644
--- a/drivers/net/wireless/wl12xx/wl1251_reg.h
+++ b/drivers/net/wireless/wl1251/reg.h
@@ -4,8 +4,6 @@
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl1251/rx.c
index 1b6294b3b996..efa53607d5c9 100644
--- a/drivers/net/wireless/wl12xx/wl1251_rx.c
+++ b/drivers/net/wireless/wl1251/rx.c
@@ -4,8 +4,6 @@
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -27,11 +25,11 @@
#include <net/mac80211.h>
#include "wl1251.h"
-#include "wl1251_reg.h"
-#include "wl1251_io.h"
-#include "wl1251_rx.h"
-#include "wl1251_cmd.h"
-#include "wl1251_acx.h"
+#include "reg.h"
+#include "io.h"
+#include "rx.h"
+#include "cmd.h"
+#include "acx.h"
static void wl1251_rx_header(struct wl1251 *wl,
struct wl1251_rx_descriptor *desc)
diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.h b/drivers/net/wireless/wl1251/rx.h
index da4e53406a0e..4448f635a4d8 100644
--- a/drivers/net/wireless/wl12xx/wl1251_rx.h
+++ b/drivers/net/wireless/wl1251/rx.h
@@ -4,8 +4,6 @@
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl1251/sdio.c
index b901b6135654..74ba9ced5393 100644
--- a/drivers/net/wireless/wl12xx/wl1251_sdio.c
+++ b/drivers/net/wireless/wl1251/sdio.c
@@ -24,7 +24,7 @@
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/platform_device.h>
-#include <linux/spi/wl12xx.h>
+#include <linux/wl12xx.h>
#include <linux/irq.h>
#include "wl1251.h"
@@ -339,4 +339,4 @@ module_init(wl1251_sdio_init);
module_exit(wl1251_sdio_exit);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
+MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl1251/spi.c
index 27fdfaaeb074..88fa8e69d0d1 100644
--- a/drivers/net/wireless/wl12xx/wl1251_spi.c
+++ b/drivers/net/wireless/wl1251/spi.c
@@ -3,8 +3,6 @@
*
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -26,11 +24,11 @@
#include <linux/slab.h>
#include <linux/crc7.h>
#include <linux/spi/spi.h>
-#include <linux/spi/wl12xx.h>
+#include <linux/wl12xx.h>
#include "wl1251.h"
-#include "wl1251_reg.h"
-#include "wl1251_spi.h"
+#include "reg.h"
+#include "spi.h"
static irqreturn_t wl1251_irq(int irq, void *cookie)
{
@@ -344,5 +342,5 @@ module_init(wl1251_spi_init);
module_exit(wl1251_spi_exit);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
+MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
MODULE_ALIAS("spi:wl1251");
diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl1251/spi.h
index 2e273a97e7f3..16d506955cc0 100644
--- a/drivers/net/wireless/wl12xx/wl1251_spi.h
+++ b/drivers/net/wireless/wl1251/spi.h
@@ -4,8 +4,6 @@
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -25,9 +23,9 @@
#ifndef __WL1251_SPI_H__
#define __WL1251_SPI_H__
-#include "wl1251_cmd.h"
-#include "wl1251_acx.h"
-#include "wl1251_reg.h"
+#include "cmd.h"
+#include "acx.h"
+#include "reg.h"
#define WSPI_CMD_READ 0x40000000
#define WSPI_CMD_WRITE 0x00000000
diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl1251/tx.c
index a38ec199187a..554b4f9a3d3e 100644
--- a/drivers/net/wireless/wl12xx/wl1251_tx.c
+++ b/drivers/net/wireless/wl1251/tx.c
@@ -4,8 +4,6 @@
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -26,10 +24,10 @@
#include <linux/module.h>
#include "wl1251.h"
-#include "wl1251_reg.h"
-#include "wl1251_tx.h"
-#include "wl1251_ps.h"
-#include "wl1251_io.h"
+#include "reg.h"
+#include "tx.h"
+#include "ps.h"
+#include "io.h"
static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count)
{
@@ -189,7 +187,7 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
tx_hdr = (struct tx_double_buffer_desc *) skb->data;
if (control->control.hw_key &&
- control->control.hw_key->alg == ALG_TKIP) {
+ control->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
int hdrlen;
__le16 fc;
u16 length;
@@ -322,11 +320,6 @@ void wl1251_tx_work(struct work_struct *work)
ret = wl1251_tx_frame(wl, skb);
if (ret == -EBUSY) {
- /* firmware buffer is full, stop queues */
- wl1251_debug(DEBUG_TX, "tx_work: fw buffer full, "
- "stop queues");
- ieee80211_stop_queues(wl->hw);
- wl->tx_queue_stopped = true;
skb_queue_head(&wl->tx_queue, skb);
goto out;
} else if (ret < 0) {
@@ -399,7 +392,7 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl,
*/
frame = skb_pull(skb, sizeof(struct tx_double_buffer_desc));
if (info->control.hw_key &&
- info->control.hw_key->alg == ALG_TKIP) {
+ info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
memmove(frame + WL1251_TKIP_IV_SPACE, frame, hdrlen);
skb_pull(skb, WL1251_TKIP_IV_SPACE);
@@ -449,6 +442,7 @@ void wl1251_tx_complete(struct wl1251 *wl)
{
int i, result_index, num_complete = 0;
struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr;
+ unsigned long flags;
if (unlikely(wl->state != WL1251_STATE_ON))
return;
@@ -477,6 +471,20 @@ void wl1251_tx_complete(struct wl1251 *wl)
}
}
+ if (wl->tx_queue_stopped
+ &&
+ skb_queue_len(&wl->tx_queue) <= WL1251_TX_QUEUE_LOW_WATERMARK){
+
+ /* firmware buffer has space, restart queues */
+ wl1251_debug(DEBUG_TX, "tx_complete: waking queues");
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ ieee80211_wake_queues(wl->hw);
+ wl->tx_queue_stopped = false;
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+ ieee80211_queue_work(wl->hw, &wl->tx_work);
+
+ }
+
/* Every completed frame needs to be acknowledged */
if (num_complete) {
/*
diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl1251/tx.h
index f40eeb37f5aa..81338d39b43e 100644
--- a/drivers/net/wireless/wl12xx/wl1251_tx.h
+++ b/drivers/net/wireless/wl1251/tx.h
@@ -4,8 +4,6 @@
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -26,7 +24,7 @@
#define __WL1251_TX_H__
#include <linux/bitops.h>
-#include "wl1251_acx.h"
+#include "acx.h"
/*
*
diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h
index 6b942a28e6a5..e113d4c1fb35 100644
--- a/drivers/net/wireless/wl12xx/wl1251.h
+++ b/drivers/net/wireless/wl1251/wl1251.h
@@ -4,8 +4,6 @@
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008-2009 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -274,6 +272,8 @@ struct wl1251 {
int irq;
bool use_eeprom;
+ spinlock_t wl_lock;
+
enum wl1251_state state;
struct mutex mutex;
@@ -401,7 +401,8 @@ void wl1251_disable_interrupts(struct wl1251 *wl);
#define WL1251_DEFAULT_POWER_LEVEL 20
-#define WL1251_TX_QUEUE_MAX_LENGTH 20
+#define WL1251_TX_QUEUE_LOW_WATERMARK 10
+#define WL1251_TX_QUEUE_HIGH_WATERMARK 25
#define WL1251_DEFAULT_BEACON_INT 100
#define WL1251_DEFAULT_DTIM_PERIOD 1
diff --git a/drivers/net/wireless/wl1251/wl12xx_80211.h b/drivers/net/wireless/wl1251/wl12xx_80211.h
new file mode 100644
index 000000000000..184628027213
--- /dev/null
+++ b/drivers/net/wireless/wl1251/wl12xx_80211.h
@@ -0,0 +1,156 @@
+#ifndef __WL12XX_80211_H__
+#define __WL12XX_80211_H__
+
+#include <linux/if_ether.h> /* ETH_ALEN */
+
+/* RATES */
+#define IEEE80211_CCK_RATE_1MB 0x02
+#define IEEE80211_CCK_RATE_2MB 0x04
+#define IEEE80211_CCK_RATE_5MB 0x0B
+#define IEEE80211_CCK_RATE_11MB 0x16
+#define IEEE80211_OFDM_RATE_6MB 0x0C
+#define IEEE80211_OFDM_RATE_9MB 0x12
+#define IEEE80211_OFDM_RATE_12MB 0x18
+#define IEEE80211_OFDM_RATE_18MB 0x24
+#define IEEE80211_OFDM_RATE_24MB 0x30
+#define IEEE80211_OFDM_RATE_36MB 0x48
+#define IEEE80211_OFDM_RATE_48MB 0x60
+#define IEEE80211_OFDM_RATE_54MB 0x6C
+#define IEEE80211_BASIC_RATE_MASK 0x80
+
+#define IEEE80211_CCK_RATE_1MB_MASK (1<<0)
+#define IEEE80211_CCK_RATE_2MB_MASK (1<<1)
+#define IEEE80211_CCK_RATE_5MB_MASK (1<<2)
+#define IEEE80211_CCK_RATE_11MB_MASK (1<<3)
+#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4)
+#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5)
+#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6)
+#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7)
+#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8)
+#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9)
+#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10)
+#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11)
+
+#define IEEE80211_CCK_RATES_MASK 0x0000000F
+#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \
+ IEEE80211_CCK_RATE_2MB_MASK)
+#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \
+ IEEE80211_CCK_RATE_5MB_MASK | \
+ IEEE80211_CCK_RATE_11MB_MASK)
+
+#define IEEE80211_OFDM_RATES_MASK 0x00000FF0
+#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \
+ IEEE80211_OFDM_RATE_12MB_MASK | \
+ IEEE80211_OFDM_RATE_24MB_MASK)
+#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \
+ IEEE80211_OFDM_RATE_9MB_MASK | \
+ IEEE80211_OFDM_RATE_18MB_MASK | \
+ IEEE80211_OFDM_RATE_36MB_MASK | \
+ IEEE80211_OFDM_RATE_48MB_MASK | \
+ IEEE80211_OFDM_RATE_54MB_MASK)
+#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \
+ IEEE80211_CCK_DEFAULT_RATES_MASK)
+
+
+/* This really should be 8, but not for our firmware */
+#define MAX_SUPPORTED_RATES 32
+#define COUNTRY_STRING_LEN 3
+#define MAX_COUNTRY_TRIPLETS 32
+
+/* Headers */
+struct ieee80211_header {
+ __le16 frame_ctl;
+ __le16 duration_id;
+ u8 da[ETH_ALEN];
+ u8 sa[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ __le16 seq_ctl;
+ u8 payload[0];
+} __packed;
+
+struct wl12xx_ie_header {
+ u8 id;
+ u8 len;
+} __packed;
+
+/* IEs */
+
+struct wl12xx_ie_ssid {
+ struct wl12xx_ie_header header;
+ char ssid[IW_ESSID_MAX_SIZE];
+} __packed;
+
+struct wl12xx_ie_rates {
+ struct wl12xx_ie_header header;
+ u8 rates[MAX_SUPPORTED_RATES];
+} __packed;
+
+struct wl12xx_ie_ds_params {
+ struct wl12xx_ie_header header;
+ u8 channel;
+} __packed;
+
+struct country_triplet {
+ u8 channel;
+ u8 num_channels;
+ u8 max_tx_power;
+} __packed;
+
+struct wl12xx_ie_country {
+ struct wl12xx_ie_header header;
+ u8 country_string[COUNTRY_STRING_LEN];
+ struct country_triplet triplets[MAX_COUNTRY_TRIPLETS];
+} __packed;
+
+
+/* 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;
+
+struct wl12xx_ps_poll_template {
+ __le16 fc;
+ __le16 aid;
+ u8 bssid[ETH_ALEN];
+ u8 ta[ETH_ALEN];
+} __packed;
+
+struct wl12xx_qos_null_data_template {
+ struct ieee80211_header header;
+ __le16 qos_ctl;
+} __packed;
+
+struct wl12xx_probe_req_template {
+ struct ieee80211_header header;
+ struct wl12xx_ie_ssid ssid;
+ struct wl12xx_ie_rates rates;
+ struct wl12xx_ie_rates ext_rates;
+} __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;
+
+#endif
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index 2f98058be451..b447559f1db5 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -5,40 +5,6 @@ menuconfig WL12XX
This will enable TI wl12xx driver support. The drivers make
use of the mac80211 stack.
-config WL1251
- tristate "TI wl1251 support"
- depends on WL12XX && GENERIC_HARDIRQS
- select FW_LOADER
- select CRC7
- ---help---
- This module adds support for wireless adapters based on
- TI wl1251 chipset.
-
- If you choose to build a module, it'll be called wl1251. Say
- N if unsure.
-
-config WL1251_SPI
- tristate "TI wl1251 SPI support"
- depends on WL1251 && SPI_MASTER
- ---help---
- This module adds support for the SPI interface of adapters using
- TI wl1251 chipset. Select this if your platform is using
- the SPI bus.
-
- If you choose to build a module, it'll be called wl1251_spi.
- Say N if unsure.
-
-config WL1251_SDIO
- tristate "TI wl1251 SDIO support"
- depends on WL1251 && MMC
- ---help---
- This module adds support for the SDIO interface of adapters using
- TI wl1251 chipset. Select this if your platform is using
- the SDIO bus.
-
- If you choose to build a module, it'll be called
- wl1251_sdio. Say N if unsure.
-
config WL1271
tristate "TI wl1271 support"
depends on WL12XX && GENERIC_HARDIRQS
@@ -74,4 +40,7 @@ config WL1271_SDIO
If you choose to build a module, it'll be called
wl1271_sdio. Say N if unsure.
-
+config WL12XX_PLATFORM_DATA
+ bool
+ depends on WL1271_SDIO != n
+ default y
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index 078b4398ac1f..3a807444b2af 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -1,12 +1,3 @@
-wl1251-objs = wl1251_main.o wl1251_event.o \
- wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \
- wl1251_acx.o wl1251_boot.o wl1251_init.o \
- wl1251_debugfs.o wl1251_io.o
-
-obj-$(CONFIG_WL1251) += wl1251.o
-obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o
-obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o
-
wl1271-objs = wl1271_main.o wl1271_cmd.o wl1271_io.o \
wl1271_event.o wl1271_tx.o wl1271_rx.o \
wl1271_ps.o wl1271_acx.o wl1271_boot.o \
@@ -16,3 +7,6 @@ wl1271-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o
obj-$(CONFIG_WL1271) += wl1271.o
obj-$(CONFIG_WL1271_SPI) += wl1271_spi.o
obj-$(CONFIG_WL1271_SDIO) += wl1271_sdio.o
+
+# small builtin driver bit
+obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index dd3cee6ea5bb..8a4cd763e5a2 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -117,10 +117,7 @@ enum {
#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
-/*
- * Enable/disable 802.11a support for WL1273
- */
-#undef WL1271_80211A_ENABLED
+#define WL1271_CIPHER_SUITE_GEM 0x00147201
#define WL1271_BUSY_WORD_CNT 1
#define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32))
@@ -133,6 +130,8 @@ enum {
#define ACX_TX_DESCRIPTORS 32
+#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
+
enum wl1271_state {
WL1271_STATE_OFF,
WL1271_STATE_ON,
@@ -301,6 +300,7 @@ struct wl1271_rx_mem_pool_addr {
struct wl1271_scan {
struct cfg80211_scan_request *req;
bool *scanned_ch;
+ bool failed;
u8 state;
u8 ssid[IW_ESSID_MAX_SIZE+1];
size_t ssid_len;
@@ -313,7 +313,7 @@ struct wl1271_if_operations {
bool fixed);
void (*reset)(struct wl1271 *wl);
void (*init)(struct wl1271 *wl);
- void (*power)(struct wl1271 *wl, bool enable);
+ int (*power)(struct wl1271 *wl, bool enable);
struct device* (*dev)(struct wl1271 *wl);
void (*enable_irq)(struct wl1271 *wl);
void (*disable_irq)(struct wl1271 *wl);
@@ -330,6 +330,7 @@ struct wl1271 {
void (*set_power)(bool enable);
int irq;
+ int ref_clock;
spinlock_t wl_lock;
@@ -349,6 +350,7 @@ struct wl1271 {
#define WL1271_FLAG_IDLE (10)
#define WL1271_FLAG_IDLE_REQUESTED (11)
#define WL1271_FLAG_PSPOLL_FAILURE (12)
+#define WL1271_FLAG_STA_STATE_SENT (13)
unsigned long flags;
struct wl1271_partition_set part;
@@ -361,6 +363,7 @@ struct wl1271 {
u8 *fw;
size_t fw_len;
struct wl1271_nvs_file *nvs;
+ size_t nvs_len;
s8 hw_pg_ver;
@@ -407,9 +410,15 @@ struct wl1271 {
/* Rx memory pool address */
struct wl1271_rx_mem_pool_addr rx_mem_pool_addr;
+ /* Intermediate buffer, used for packet aggregation */
+ u8 *aggr_buf;
+
/* The target interrupt mask */
struct work_struct irq_work;
+ /* Hardware recovery work */
+ struct work_struct recovery_work;
+
/* The mbox event mask */
u32 event_mask;
@@ -418,6 +427,7 @@ struct wl1271 {
/* Are we currently scanning */
struct wl1271_scan scan;
+ struct delayed_work scan_complete_work;
/* Our association ID */
u16 aid;
@@ -474,6 +484,8 @@ struct wl1271 {
bool sg_enabled;
+ bool enable_11a;
+
struct list_head list;
/* Most recently reported noise in dBm */
@@ -497,14 +509,4 @@ int wl1271_plt_stop(struct wl1271 *wl);
#define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */
#define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */
-static inline bool wl1271_11a_enabled(void)
-{
- /* FIXME: this could be determined based on the NVS-INI file */
-#ifdef WL1271_80211A_ENABLED
- return true;
-#else
- return false;
-#endif
-}
-
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c
index bb245f05af49..618993405262 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.c
@@ -86,40 +86,6 @@ out:
return ret;
}
-int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len)
-{
- struct acx_revision *rev;
- int ret;
-
- wl1271_debug(DEBUG_ACX, "acx fw rev");
-
- rev = kzalloc(sizeof(*rev), GFP_KERNEL);
- if (!rev) {
- ret = -ENOMEM;
- goto out;
- }
-
- ret = wl1271_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev));
- if (ret < 0) {
- wl1271_warning("ACX_FW_REV interrogate failed");
- goto out;
- }
-
- /* be careful with the buffer sizes */
- strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version)));
-
- /*
- * if the firmware version string is exactly
- * sizeof(rev->fw_version) long or fw_len is less than
- * sizeof(rev->fw_version) it won't be null terminated
- */
- buf[min(len, sizeof(rev->fw_version)) - 1] = '\0';
-
-out:
- kfree(rev);
- return ret;
-}
-
int wl1271_acx_tx_power(struct wl1271 *wl, int power)
{
struct acx_current_tx_power *acx;
@@ -269,7 +235,7 @@ int wl1271_acx_pd_threshold(struct wl1271 *wl)
out:
kfree(pd);
- return 0;
+ return ret;
}
int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time)
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h
index 4235bc56f750..ebb341d36e8c 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.h
@@ -100,35 +100,6 @@ struct acx_error_counter {
__le32 seq_num_miss;
} __packed;
-struct acx_revision {
- struct acx_header header;
-
- /*
- * The WiLink firmware version, an ASCII string x.x.x.x,
- * that uniquely identifies the current firmware.
- * The left most digit is incremented each time a
- * significant change is made to the firmware, such as
- * code redesign or new platform support.
- * The second digit is incremented when major enhancements
- * are added or major fixes are made.
- * The third digit is incremented for each GA release.
- * The fourth digit is incremented for each build.
- * The first two digits identify a firmware release version,
- * in other words, a unique set of features.
- * The first three digits identify a GA release.
- */
- char fw_version[20];
-
- /*
- * This 4 byte field specifies the WiLink hardware version.
- * bits 0 - 15: Reserved.
- * bits 16 - 23: Version ID - The WiLink version ID
- * (1 = first spin, 2 = second spin, and so on).
- * bits 24 - 31: Chip ID - The WiLink chip ID.
- */
- __le32 hw_version;
-} __packed;
-
enum wl1271_psm_mode {
/* Active mode */
WL1271_PSM_CAM = 0,
@@ -1060,7 +1031,6 @@ enum {
ACX_PEER_HT_CAP = 0x0057,
ACX_HT_BSS_OPERATION = 0x0058,
ACX_COEX_ACTIVITY = 0x0059,
- ACX_SET_SMART_REFLEX_DEBUG = 0x005A,
ACX_SET_DCO_ITRIM_PARAMS = 0x0061,
DOT11_RX_MSDU_LIFE_TIME = 0x1004,
DOT11_CUR_TX_PWR = 0x100D,
@@ -1077,7 +1047,6 @@ enum {
int wl1271_acx_wake_up_conditions(struct wl1271 *wl);
int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth);
-int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len);
int wl1271_acx_tx_power(struct wl1271 *wl, int power);
int wl1271_acx_feature_cfg(struct wl1271 *wl);
int wl1271_acx_mem_map(struct wl1271 *wl,
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c
index f36430b0336d..b91021242098 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.c
+++ b/drivers/net/wireless/wl12xx/wl1271_boot.c
@@ -225,6 +225,28 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
if (wl->nvs == NULL)
return -ENODEV;
+ /*
+ * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
+ * configurations) can be removed when those NVS files stop floating
+ * around.
+ */
+ if (wl->nvs_len == sizeof(struct wl1271_nvs_file) ||
+ wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) {
+ if (wl->nvs->general_params.dual_mode_select)
+ wl->enable_11a = true;
+ }
+
+ if (wl->nvs_len != sizeof(struct wl1271_nvs_file) &&
+ (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
+ wl->enable_11a)) {
+ wl1271_error("nvs size is not as expected: %zu != %zu",
+ wl->nvs_len, sizeof(struct wl1271_nvs_file));
+ kfree(wl->nvs);
+ wl->nvs = NULL;
+ wl->nvs_len = 0;
+ return -EILSEQ;
+ }
+
/* only the first part of the NVS needs to be uploaded */
nvs_len = sizeof(wl->nvs->nvs);
nvs_ptr = (u8 *)wl->nvs->nvs;
@@ -251,8 +273,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
burst_len = nvs_ptr[0];
dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
- /* FIXME: Due to our new wl1271_translate_reg_addr function,
- we need to add the REGISTER_BASE to the destination */
+ /*
+ * Due to our new wl1271_translate_reg_addr function,
+ * we need to add the REGISTER_BASE to the destination
+ */
dest_addr += REGISTERS_BASE;
/* We move our pointer to the data */
@@ -274,31 +298,21 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
/*
* We've reached the first zero length, the first NVS table
- * is 7 bytes further.
+ * is located at an aligned offset which is at least 7 bytes further.
*/
- nvs_ptr += 7;
+ nvs_ptr = (u8 *)wl->nvs->nvs +
+ ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4);
nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs;
- nvs_len = ALIGN(nvs_len, 4);
- /* FIXME: The driver sets the partition here, but this is not needed,
- since it sets to the same one as currently in use */
/* Now we must set the partition correctly */
wl1271_set_partition(wl, &part_table[PART_WORK]);
/* Copy the NVS tables to a new block to ensure alignment */
- /* FIXME: We jump 3 more bytes before uploading the NVS. It seems
- that our NVS files have three extra zeros here. I'm not sure whether
- the problem is in our NVS generation or we should really jumpt these
- 3 bytes here */
- nvs_ptr += 3;
-
- nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); if
- (!nvs_aligned) return -ENOMEM;
+ nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
+ if (!nvs_aligned)
+ return -ENOMEM;
/* And finally we upload the NVS tables */
- /* FIXME: In wl1271, we upload everything at once.
- No endianness handling needed here?! The ref driver doesn't do
- anything about it at this point */
wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
kfree(nvs_aligned);
@@ -457,17 +471,20 @@ int wl1271_boot(struct wl1271 *wl)
{
int ret = 0;
u32 tmp, clk, pause;
+ int ref_clock = wl->ref_clock;
wl1271_boot_hw_version(wl);
- if (REF_CLOCK == 0 || REF_CLOCK == 2 || REF_CLOCK == 4)
+ if (ref_clock == 0 || ref_clock == 2 || ref_clock == 4)
/* ref clk: 19.2/38.4/38.4-XTAL */
clk = 0x3;
- else if (REF_CLOCK == 1 || REF_CLOCK == 3)
+ else if (ref_clock == 1 || ref_clock == 3)
/* ref clk: 26/52 */
clk = 0x5;
+ else
+ return -EINVAL;
- if (REF_CLOCK != 0) {
+ if (ref_clock != 0) {
u16 val;
/* Set clock type (open drain) */
val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
@@ -493,10 +510,7 @@ int wl1271_boot(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
- pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be
- * WU_COUNTER_PAUSE_VAL instead of
- * 0x3ff (magic number ). How does
- * this work?! */
+ pause &= ~(WU_COUNTER_PAUSE_VAL);
pause |= WU_COUNTER_PAUSE_VAL;
wl1271_write32(wl, WU_COUNTER_PAUSE, pause);
@@ -516,7 +530,7 @@ int wl1271_boot(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
/* 2 */
- clk |= (REF_CLOCK << 1) << 4;
+ clk |= (ref_clock << 1) << 4;
wl1271_write32(wl, DRPW_SCRATCH_START, clk);
wl1271_set_partition(wl, &part_table[PART_WORK]);
@@ -550,7 +564,6 @@ int wl1271_boot(struct wl1271 *wl)
if (ret < 0)
goto out;
- /* FIXME: Need to check whether this is really what we want */
wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_ALL_EVENTS_VECTOR);
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.h b/drivers/net/wireless/wl12xx/wl1271_boot.h
index f829699d597e..f73b0b15a280 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.h
+++ b/drivers/net/wireless/wl12xx/wl1271_boot.h
@@ -46,7 +46,6 @@ struct wl1271_static_data {
/* delay between retries */
#define INIT_LOOP_DELAY 50
-#define REF_CLOCK 2
#define WU_COUNTER_PAUSE_VAL 0x3FF
#define WELP_ARM_COMMAND_VAL 0x4
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index ce503ddd5a41..5d3e8485ea4e 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -94,6 +94,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
status = le16_to_cpu(cmd->status);
if (status != CMD_STATUS_SUCCESS) {
wl1271_error("command execute failure %d", status);
+ ieee80211_queue_work(wl->hw, &wl->recovery_work);
ret = -EIO;
}
@@ -107,6 +108,8 @@ out:
int wl1271_cmd_general_parms(struct wl1271 *wl)
{
struct wl1271_general_parms_cmd *gen_parms;
+ struct wl1271_ini_general_params *gp = &wl->nvs->general_params;
+ bool answer = false;
int ret;
if (!wl->nvs)
@@ -118,13 +121,24 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
- memcpy(&gen_parms->general_params, &wl->nvs->general_params,
- sizeof(struct wl1271_ini_general_params));
+ memcpy(&gen_parms->general_params, gp, sizeof(*gp));
- ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
- if (ret < 0)
+ if (gp->tx_bip_fem_auto_detect)
+ answer = true;
+
+ ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
+ if (ret < 0) {
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
+ goto out;
+ }
+
+ gp->tx_bip_fem_manufacturer =
+ gen_parms->general_params.tx_bip_fem_manufacturer;
+
+ wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
+ answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
+out:
kfree(gen_parms);
return ret;
}
@@ -170,6 +184,39 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
return ret;
}
+int wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
+{
+ struct wl1271_ext_radio_parms_cmd *ext_radio_parms;
+ struct conf_rf_settings *rf = &wl->conf.rf;
+ int ret;
+
+ if (!wl->nvs)
+ return -ENODEV;
+
+ ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL);
+ if (!ext_radio_parms)
+ return -ENOMEM;
+
+ ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM;
+
+ memcpy(ext_radio_parms->tx_per_channel_power_compensation_2,
+ rf->tx_per_channel_power_compensation_2,
+ CONF_TX_PWR_COMPENSATION_LEN_2);
+ memcpy(ext_radio_parms->tx_per_channel_power_compensation_5,
+ rf->tx_per_channel_power_compensation_5,
+ CONF_TX_PWR_COMPENSATION_LEN_5);
+
+ wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ",
+ ext_radio_parms, sizeof(*ext_radio_parms));
+
+ ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0);
+ if (ret < 0)
+ wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed");
+
+ kfree(ext_radio_parms);
+ return ret;
+}
+
/*
* Poll the mailbox event field until any of the bits in the mask is set or a
* timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
@@ -182,8 +229,10 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
do {
- if (time_after(jiffies, timeout))
+ if (time_after(jiffies, timeout)) {
+ ieee80211_queue_work(wl->hw, &wl->recovery_work);
return -ETIMEDOUT;
+ }
msleep(1);
@@ -390,18 +439,11 @@ out:
return ret;
}
-int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send)
+int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send)
{
struct wl1271_cmd_ps_params *ps_params = NULL;
int ret = 0;
- /* FIXME: this should be in ps.c */
- ret = wl1271_acx_wake_up_conditions(wl);
- if (ret < 0) {
- wl1271_error("couldn't set wake up conditions");
- goto out;
- }
-
wl1271_debug(DEBUG_CMD, "cmd set ps mode");
ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
@@ -412,9 +454,9 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send)
ps_params->ps_mode = ps_mode;
ps_params->send_null_data = send;
- ps_params->retries = 5;
- ps_params->hang_over_period = 1;
- ps_params->null_data_rate = cpu_to_le32(wl->basic_rate_set);
+ ps_params->retries = wl->conf.conn.psm_entry_nullfunc_retries;
+ ps_params->hang_over_period = wl->conf.conn.psm_entry_hangover_period;
+ ps_params->null_data_rate = cpu_to_le32(rates);
ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
sizeof(*ps_params), 0);
@@ -428,41 +470,6 @@ out:
return ret;
}
-int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
- size_t len)
-{
- struct cmd_read_write_memory *cmd;
- int ret = 0;
-
- wl1271_debug(DEBUG_CMD, "cmd read memory");
-
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd) {
- ret = -ENOMEM;
- goto out;
- }
-
- WARN_ON(len > MAX_READ_SIZE);
- len = min_t(size_t, len, MAX_READ_SIZE);
-
- cmd->addr = cpu_to_le32(addr);
- cmd->size = cpu_to_le32(len);
-
- ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd),
- sizeof(*cmd));
- if (ret < 0) {
- wl1271_error("read memory command failed: %d", ret);
- goto out;
- }
-
- /* the read command got in */
- memcpy(answer, cmd->value, len);
-
-out:
- kfree(cmd);
- return ret;
-}
-
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
void *buf, size_t buf_len, int index, u32 rates)
{
@@ -523,7 +530,7 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl)
}
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0,
- WL1271_RATE_AUTOMATIC);
+ wl->basic_rate);
out:
dev_kfree_skb(skb);
@@ -546,7 +553,7 @@ int wl1271_cmd_build_klv_null_data(struct wl1271 *wl)
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV,
skb->data, skb->len,
CMD_TEMPL_KLV_IDX_NULL_DATA,
- WL1271_RATE_AUTOMATIC);
+ wl->basic_rate);
out:
dev_kfree_skb(skb);
@@ -623,7 +630,7 @@ int wl1271_build_qos_null_data(struct wl1271 *wl)
return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template,
sizeof(template), 0,
- WL1271_RATE_AUTOMATIC);
+ wl->basic_rate);
}
int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
@@ -746,3 +753,31 @@ out_free:
out:
return ret;
}
+
+int wl1271_cmd_set_sta_state(struct wl1271 *wl)
+{
+ struct wl1271_cmd_set_sta_state *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd set sta state");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->state = WL1271_CMD_STA_STATE_CONNECTED;
+
+ ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send set STA state command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h
index af577ee8eb02..a0caf4fc37b1 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h
@@ -33,12 +33,13 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
size_t res_len);
int wl1271_cmd_general_parms(struct wl1271 *wl);
int wl1271_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 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);
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
-int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send);
+int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send);
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
size_t len);
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
@@ -55,6 +56,7 @@ int wl1271_cmd_set_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_disconnect(struct wl1271 *wl);
+int wl1271_cmd_set_sta_state(struct wl1271 *wl);
enum wl1271_commands {
CMD_INTERROGATE = 1, /*use this to read information elements*/
@@ -160,41 +162,6 @@ enum {
MAX_COMMAND_STATUS = 0xff
};
-
-/*
- * CMD_READ_MEMORY
- *
- * The host issues this command to read the WiLink device memory/registers.
- *
- * Note: The Base Band address has special handling (16 bits registers and
- * addresses). For more information, see the hardware specification.
- */
-/*
- * CMD_WRITE_MEMORY
- *
- * The host issues this command to write the WiLink device memory/registers.
- *
- * The Base Band address has special handling (16 bits registers and
- * addresses). For more information, see the hardware specification.
- */
-#define MAX_READ_SIZE 256
-
-struct cmd_read_write_memory {
- struct wl1271_cmd_header header;
-
- /* The address of the memory to read from or write to.*/
- __le32 addr;
-
- /* The amount of data in bytes to read from or write to the WiLink
- * device.*/
- __le32 size;
-
- /* The actual value read from or written to the Wilink. The source
- of this field is the Host in WRITE command or the Wilink in READ
- command. */
- u8 value[MAX_READ_SIZE];
-} __packed;
-
#define CMDMBOX_HEADER_LEN 4
#define CMDMBOX_INFO_ELEM_HEADER_LEN 4
@@ -313,7 +280,7 @@ enum wl1271_cmd_key_type {
KEY_WEP = 1,
KEY_TKIP = 2,
KEY_AES = 3,
- KEY_GEM = 4
+ KEY_GEM = 4,
};
/* FIXME: Add description for key-types */
@@ -358,13 +325,14 @@ enum wl1271_channel_tune_bands {
WL1271_CHANNEL_TUNE_BAND_4_9
};
-#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0
+#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0
-#define TEST_CMD_P2G_CAL 0x02
-#define TEST_CMD_CHANNEL_TUNE 0x0d
-#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d
-#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19
-#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E
+#define TEST_CMD_P2G_CAL 0x02
+#define TEST_CMD_CHANNEL_TUNE 0x0d
+#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d
+#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19
+#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E
+#define TEST_CMD_INI_FILE_RF_EXTENDED_PARAM 0x26
struct wl1271_general_parms_cmd {
struct wl1271_cmd_header header;
@@ -397,6 +365,16 @@ struct wl1271_radio_parms_cmd {
u8 padding3[2];
} __packed;
+struct wl1271_ext_radio_parms_cmd {
+ struct wl1271_cmd_header header;
+
+ struct wl1271_cmd_test_header test;
+
+ u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2];
+ u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5];
+ u8 padding[3];
+} __packed;
+
struct wl1271_cmd_cal_channel_tune {
struct wl1271_cmd_header header;
@@ -469,4 +447,13 @@ struct wl1271_cmd_disconnect {
u8 padding;
} __packed;
+#define WL1271_CMD_STA_STATE_CONNECTED 1
+
+struct wl1271_cmd_set_sta_state {
+ struct wl1271_cmd_header header;
+
+ u8 state;
+ u8 padding[3];
+} __packed;
+
#endif /* __WL1271_CMD_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h
index 0435ffda8f73..5f78a6cb1433 100644
--- a/drivers/net/wireless/wl12xx/wl1271_conf.h
+++ b/drivers/net/wireless/wl12xx/wl1271_conf.h
@@ -595,7 +595,7 @@ struct conf_tx_ac_category {
u16 tx_op_limit;
};
-#define CONF_TX_MAX_TID_COUNT 7
+#define CONF_TX_MAX_TID_COUNT 8
enum {
CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/
@@ -912,6 +912,22 @@ struct conf_conn_settings {
u8 psm_entry_retries;
/*
+ * Specifies the maximum number of times to try transmit the PSM entry
+ * null-func frame for each PSM entry attempt
+ *
+ * Range 0 - 255
+ */
+ 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.
@@ -1016,6 +1032,64 @@ struct conf_roam_trigger_settings {
u8 avg_weight_snr_data;
};
+struct conf_scan_settings {
+ /*
+ * The minimum time to wait on each channel for active scans
+ *
+ * Range: 0 - 65536 tu
+ */
+ u16 min_dwell_time_active;
+
+ /*
+ * The maximum time to wait on each channel for active scans
+ *
+ * Range: 0 - 65536 tu
+ */
+ u16 max_dwell_time_active;
+
+ /*
+ * The maximum time to wait on each channel for passive scans
+ *
+ * Range: 0 - 65536 tu
+ */
+ u16 min_dwell_time_passive;
+
+ /*
+ * The maximum time to wait on each channel for passive scans
+ *
+ * Range: 0 - 65536 tu
+ */
+ u16 max_dwell_time_passive;
+
+ /*
+ * Number of probe requests to transmit on each active scan channel
+ *
+ * Range: u8
+ */
+ u16 num_probe_reqs;
+
+};
+
+/* these are number of channels on the band divided by two, rounded up */
+#define CONF_TX_PWR_COMPENSATION_LEN_2 7
+#define CONF_TX_PWR_COMPENSATION_LEN_5 18
+
+struct conf_rf_settings {
+ /*
+ * Per channel power compensation for 2.4GHz
+ *
+ * Range: s8
+ */
+ u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2];
+
+ /*
+ * Per channel power compensation for 5GHz
+ *
+ * Range: s8
+ */
+ u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5];
+};
+
struct conf_drv_settings {
struct conf_sg_settings sg;
struct conf_rx_settings rx;
@@ -1024,6 +1098,8 @@ struct conf_drv_settings {
struct conf_itrim_settings itrim;
struct conf_pm_config_settings pm_config;
struct conf_roam_trigger_settings roam_trigger;
+ struct conf_scan_settings scan;
+ struct conf_rf_settings rf;
};
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c
index 25ce2cd5e3f3..7b3f50382963 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.c
+++ b/drivers/net/wireless/wl12xx/wl1271_event.c
@@ -41,6 +41,9 @@ void wl1271_pspoll_work(struct work_struct *work)
mutex_lock(&wl->mutex);
+ if (unlikely(wl->state == WL1271_STATE_OFF))
+ goto out;
+
if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags))
goto out;
@@ -52,7 +55,7 @@ void wl1271_pspoll_work(struct work_struct *work)
* delivery failure occurred, and no-one changed state since, so
* we should go back to powersave.
*/
- wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, true);
+ wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true);
out:
mutex_unlock(&wl->mutex);
@@ -70,7 +73,8 @@ static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl)
/* force active mode receive data from the AP */
if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
- ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, true);
+ ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
+ wl->basic_rate, true);
if (ret < 0)
return;
set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
@@ -91,6 +95,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
bool *beacon_loss)
{
int ret = 0;
+ u32 total_retries = wl->conf.conn.psm_entry_retries;
wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status);
@@ -104,10 +109,10 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
break;
}
- if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) {
+ if (wl->psm_entry_retry < total_retries) {
wl->psm_entry_retry++;
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
- true);
+ wl->basic_rate, true);
} else {
wl1271_info("No ack to nullfunc from AP.");
wl->psm_entry_retry = 0;
@@ -143,7 +148,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
/* make sure the firmware goes to active mode - the frame to
be sent next will indicate to the AP, that we are active. */
ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
- false);
+ wl->basic_rate, false);
break;
case EVENT_EXIT_POWER_SAVE_SUCCESS:
default:
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c
index 4447af1557f5..8044bba70ee7 100644
--- a/drivers/net/wireless/wl12xx/wl1271_init.c
+++ b/drivers/net/wireless/wl12xx/wl1271_init.c
@@ -53,6 +53,7 @@ static int wl1271_init_hwenc_config(struct wl1271 *wl)
int wl1271_init_templates_config(struct wl1271 *wl)
{
int ret, i;
+ size_t size;
/* send empty templates for fw memory reservation */
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
@@ -61,14 +62,12 @@ int wl1271_init_templates_config(struct wl1271 *wl)
if (ret < 0)
return ret;
- if (wl1271_11a_enabled()) {
- size_t size = sizeof(struct wl12xx_probe_req_template);
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
- NULL, size, 0,
- WL1271_RATE_AUTOMATIC);
- if (ret < 0)
- return ret;
- }
+ size = sizeof(struct wl12xx_probe_req_template);
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
+ NULL, size, 0,
+ WL1271_RATE_AUTOMATIC);
+ if (ret < 0)
+ return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
sizeof(struct wl12xx_null_data_template),
@@ -223,6 +222,10 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
+ ret = wl1271_cmd_ext_radio_parms(wl);
+ if (ret < 0)
+ return ret;
+
/* Template settings */
ret = wl1271_init_templates_config(wl);
if (ret < 0)
@@ -291,8 +294,16 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
- /* Default TID configuration */
+ /* Default TID/AC configuration */
+ BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
+ conf_ac = &wl->conf.tx.ac_conf[i];
+ ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
+ conf_ac->cw_max, conf_ac->aifsn,
+ conf_ac->tx_op_limit);
+ if (ret < 0)
+ goto out_free_memmap;
+
conf_tid = &wl->conf.tx.tid_conf[i];
ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
conf_tid->channel_type,
@@ -305,16 +316,6 @@ int wl1271_hw_init(struct wl1271 *wl)
goto out_free_memmap;
}
- /* Default AC configuration */
- for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
- conf_ac = &wl->conf.tx.ac_conf[i];
- ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
- conf_ac->cw_max, conf_ac->aifsn,
- conf_ac->tx_op_limit);
- if (ret < 0)
- goto out_free_memmap;
- }
-
/* Configure TX rate classes */
ret = wl1271_acx_rate_policies(wl);
if (ret < 0)
diff --git a/drivers/net/wireless/wl12xx/wl1271_io.h b/drivers/net/wireless/wl12xx/wl1271_io.h
index bc806c74c63a..c1f92e65ded0 100644
--- a/drivers/net/wireless/wl12xx/wl1271_io.h
+++ b/drivers/net/wireless/wl12xx/wl1271_io.h
@@ -144,10 +144,13 @@ static inline void wl1271_power_off(struct wl1271 *wl)
clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
}
-static inline void wl1271_power_on(struct wl1271 *wl)
+static inline int wl1271_power_on(struct wl1271 *wl)
{
- wl->if_ops->power(wl, true);
- set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+ int ret = wl->if_ops->power(wl, true);
+ if (ret == 0)
+ set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+
+ return ret;
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 9d68f0012f05..48a4b9961ae6 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -124,28 +124,28 @@ static struct conf_drv_settings default_conf = {
},
.ac_conf_count = 4,
.ac_conf = {
- [0] = {
+ [CONF_TX_AC_BE] = {
.ac = CONF_TX_AC_BE,
.cw_min = 15,
.cw_max = 63,
.aifsn = 3,
.tx_op_limit = 0,
},
- [1] = {
+ [CONF_TX_AC_BK] = {
.ac = CONF_TX_AC_BK,
.cw_min = 15,
.cw_max = 63,
.aifsn = 7,
.tx_op_limit = 0,
},
- [2] = {
+ [CONF_TX_AC_VI] = {
.ac = CONF_TX_AC_VI,
.cw_min = 15,
.cw_max = 63,
.aifsn = CONF_TX_AIFS_PIFS,
.tx_op_limit = 3008,
},
- [3] = {
+ [CONF_TX_AC_VO] = {
.ac = CONF_TX_AC_VO,
.cw_min = 15,
.cw_max = 63,
@@ -153,64 +153,40 @@ static struct conf_drv_settings default_conf = {
.tx_op_limit = 1504,
},
},
- .tid_conf_count = 7,
+ .tid_conf_count = 4,
.tid_conf = {
- [0] = {
- .queue_id = 0,
- .channel_type = CONF_CHANNEL_TYPE_DCF,
- .tsid = CONF_TX_AC_BE,
- .ps_scheme = CONF_PS_SCHEME_LEGACY,
- .ack_policy = CONF_ACK_POLICY_LEGACY,
- .apsd_conf = {0, 0},
- },
- [1] = {
- .queue_id = 1,
- .channel_type = CONF_CHANNEL_TYPE_DCF,
+ [CONF_TX_AC_BE] = {
+ .queue_id = CONF_TX_AC_BE,
+ .channel_type = CONF_CHANNEL_TYPE_EDCF,
.tsid = CONF_TX_AC_BE,
.ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0},
},
- [2] = {
- .queue_id = 2,
- .channel_type = CONF_CHANNEL_TYPE_DCF,
- .tsid = CONF_TX_AC_BE,
+ [CONF_TX_AC_BK] = {
+ .queue_id = CONF_TX_AC_BK,
+ .channel_type = CONF_CHANNEL_TYPE_EDCF,
+ .tsid = CONF_TX_AC_BK,
.ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0},
},
- [3] = {
- .queue_id = 3,
- .channel_type = CONF_CHANNEL_TYPE_DCF,
- .tsid = CONF_TX_AC_BE,
- .ps_scheme = CONF_PS_SCHEME_LEGACY,
- .ack_policy = CONF_ACK_POLICY_LEGACY,
- .apsd_conf = {0, 0},
- },
- [4] = {
- .queue_id = 4,
- .channel_type = CONF_CHANNEL_TYPE_DCF,
- .tsid = CONF_TX_AC_BE,
+ [CONF_TX_AC_VI] = {
+ .queue_id = CONF_TX_AC_VI,
+ .channel_type = CONF_CHANNEL_TYPE_EDCF,
+ .tsid = CONF_TX_AC_VI,
.ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0},
},
- [5] = {
- .queue_id = 5,
- .channel_type = CONF_CHANNEL_TYPE_DCF,
- .tsid = CONF_TX_AC_BE,
+ [CONF_TX_AC_VO] = {
+ .queue_id = CONF_TX_AC_VO,
+ .channel_type = CONF_CHANNEL_TYPE_EDCF,
+ .tsid = CONF_TX_AC_VO,
.ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0},
},
- [6] = {
- .queue_id = 6,
- .channel_type = CONF_CHANNEL_TYPE_DCF,
- .tsid = CONF_TX_AC_BE,
- .ps_scheme = CONF_PS_SCHEME_LEGACY,
- .ack_policy = CONF_ACK_POLICY_LEGACY,
- .apsd_conf = {0, 0},
- }
},
.frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
.tx_compl_timeout = 700,
@@ -238,7 +214,9 @@ static struct conf_drv_settings default_conf = {
.ps_poll_recovery_period = 700,
.bet_enable = CONF_BET_MODE_ENABLE,
.bet_max_consecutive = 10,
- .psm_entry_retries = 3,
+ .psm_entry_retries = 5,
+ .psm_entry_nullfunc_retries = 3,
+ .psm_entry_hangover_period = 1,
.keep_alive_interval = 55000,
.max_listen_interval = 20,
},
@@ -251,15 +229,34 @@ static struct conf_drv_settings default_conf = {
.host_fast_wakeup_support = false
},
.roam_trigger = {
- /* FIXME: due to firmware bug, must use value 1 for now */
.trigger_pacing = 1,
.avg_weight_rssi_beacon = 20,
.avg_weight_rssi_data = 10,
.avg_weight_snr_beacon = 20,
.avg_weight_snr_data = 10
- }
+ },
+ .scan = {
+ .min_dwell_time_active = 7500,
+ .max_dwell_time_active = 30000,
+ .min_dwell_time_passive = 30000,
+ .max_dwell_time_passive = 60000,
+ .num_probe_reqs = 2,
+ },
+ .rf = {
+ .tx_per_channel_power_compensation_2 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ .tx_per_channel_power_compensation_5 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ },
};
+static void __wl1271_op_remove_interface(struct wl1271 *wl);
+
+
static void wl1271_device_release(struct device *dev)
{
@@ -277,6 +274,67 @@ static struct platform_device wl1271_device = {
static LIST_HEAD(wl_list);
+static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
+ void *arg)
+{
+ struct net_device *dev = arg;
+ struct wireless_dev *wdev;
+ struct wiphy *wiphy;
+ struct ieee80211_hw *hw;
+ struct wl1271 *wl;
+ struct wl1271 *wl_temp;
+ int ret = 0;
+
+ /* Check that this notification is for us. */
+ if (what != NETDEV_CHANGE)
+ return NOTIFY_DONE;
+
+ wdev = dev->ieee80211_ptr;
+ if (wdev == NULL)
+ return NOTIFY_DONE;
+
+ wiphy = wdev->wiphy;
+ if (wiphy == NULL)
+ return NOTIFY_DONE;
+
+ hw = wiphy_priv(wiphy);
+ if (hw == NULL)
+ return NOTIFY_DONE;
+
+ wl_temp = hw->priv;
+ list_for_each_entry(wl, &wl_list, list) {
+ if (wl == wl_temp)
+ break;
+ }
+ if (wl != wl_temp)
+ return NOTIFY_DONE;
+
+ mutex_lock(&wl->mutex);
+
+ if (wl->state == WL1271_STATE_OFF)
+ goto out;
+
+ if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+
+ if ((dev->operstate == IF_OPER_UP) &&
+ !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
+ wl1271_cmd_set_sta_state(wl);
+ wl1271_info("Association completed.");
+ }
+
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return NOTIFY_OK;
+}
+
static void wl1271_conf_init(struct wl1271 *wl)
{
@@ -309,6 +367,10 @@ static int wl1271_plt_init(struct wl1271 *wl)
if (ret < 0)
return ret;
+ ret = wl1271_cmd_ext_radio_parms(wl);
+ if (ret < 0)
+ return ret;
+
ret = wl1271_init_templates_config(wl);
if (ret < 0)
return ret;
@@ -346,8 +408,16 @@ static int wl1271_plt_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
- /* Default TID configuration */
+ /* Default TID/AC configuration */
+ BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
+ conf_ac = &wl->conf.tx.ac_conf[i];
+ ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
+ conf_ac->cw_max, conf_ac->aifsn,
+ conf_ac->tx_op_limit);
+ if (ret < 0)
+ goto out_free_memmap;
+
conf_tid = &wl->conf.tx.tid_conf[i];
ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
conf_tid->channel_type,
@@ -360,16 +430,6 @@ static int wl1271_plt_init(struct wl1271 *wl)
goto out_free_memmap;
}
- /* Default AC configuration */
- for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
- conf_ac = &wl->conf.tx.ac_conf[i];
- ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
- conf_ac->cw_max, conf_ac->aifsn,
- conf_ac->tx_op_limit);
- if (ret < 0)
- goto out_free_memmap;
- }
-
/* Enable data path */
ret = wl1271_cmd_data_path(wl, 1);
if (ret < 0)
@@ -562,20 +622,6 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
return ret;
}
- /*
- * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
- * configurations) can be removed when those NVS files stop floating
- * around.
- */
- if (fw->size != sizeof(struct wl1271_nvs_file) &&
- (fw->size != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
- wl1271_11a_enabled())) {
- wl1271_error("nvs size is not as expected: %zu != %zu",
- fw->size, sizeof(struct wl1271_nvs_file));
- ret = -EILSEQ;
- goto out;
- }
-
wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
if (!wl->nvs) {
@@ -584,12 +630,37 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
goto out;
}
+ wl->nvs_len = fw->size;
+
out:
release_firmware(fw);
return ret;
}
+static void wl1271_recovery_work(struct work_struct *work)
+{
+ struct wl1271 *wl =
+ container_of(work, struct wl1271, recovery_work);
+
+ mutex_lock(&wl->mutex);
+
+ if (wl->state != WL1271_STATE_ON)
+ goto out;
+
+ wl1271_info("Hardware recovery in progress.");
+
+ if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+ ieee80211_connection_loss(wl->vif);
+
+ /* reboot the chipset */
+ __wl1271_op_remove_interface(wl);
+ ieee80211_restart_hw(wl->hw);
+
+out:
+ mutex_unlock(&wl->mutex);
+}
+
static void wl1271_fw_wakeup(struct wl1271 *wl)
{
u32 elp_reg;
@@ -610,8 +681,6 @@ static int wl1271_setup(struct wl1271 *wl)
return -ENOMEM;
}
- INIT_WORK(&wl->irq_work, wl1271_irq_work);
- INIT_WORK(&wl->tx_work, wl1271_tx_work);
return 0;
}
@@ -621,7 +690,9 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
int ret = 0;
msleep(WL1271_PRE_POWER_ON_SLEEP);
- wl1271_power_on(wl);
+ ret = wl1271_power_on(wl);
+ if (ret < 0)
+ goto out;
msleep(WL1271_POWER_ON_SLEEP);
wl1271_io_reset(wl);
wl1271_io_init(wl);
@@ -766,10 +837,12 @@ int wl1271_plt_stop(struct wl1271 *wl)
out:
mutex_unlock(&wl->mutex);
+ cancel_work_sync(&wl->irq_work);
+ cancel_work_sync(&wl->recovery_work);
+
return ret;
}
-
static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct wl1271 *wl = hw->priv;
@@ -812,6 +885,10 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_OK;
}
+static struct notifier_block wl1271_dev_notifier = {
+ .notifier_call = wl1271_dev_notify,
+};
+
static int wl1271_op_start(struct ieee80211_hw *hw)
{
wl1271_debug(DEBUG_MAC80211, "mac80211 start");
@@ -928,13 +1005,10 @@ out:
return ret;
}
-static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+static void __wl1271_op_remove_interface(struct wl1271 *wl)
{
- struct wl1271 *wl = hw->priv;
int i;
- mutex_lock(&wl->mutex);
wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
wl1271_info("down");
@@ -948,12 +1022,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
ieee80211_enable_dyn_ps(wl->vif);
if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
- mutex_unlock(&wl->mutex);
- ieee80211_scan_completed(wl->hw, true);
- mutex_lock(&wl->mutex);
wl->scan.state = WL1271_SCAN_STATE_IDLE;
kfree(wl->scan.scanned_ch);
wl->scan.scanned_ch = NULL;
+ ieee80211_scan_completed(wl->hw, true);
}
wl->state = WL1271_STATE_OFF;
@@ -962,9 +1034,11 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
mutex_unlock(&wl->mutex);
+ cancel_delayed_work_sync(&wl->scan_complete_work);
cancel_work_sync(&wl->irq_work);
cancel_work_sync(&wl->tx_work);
cancel_delayed_work_sync(&wl->pspoll_work);
+ cancel_delayed_work_sync(&wl->elp_work);
mutex_lock(&wl->mutex);
@@ -1006,8 +1080,19 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
wl->tx_res_if = NULL;
kfree(wl->target_mem_map);
wl->target_mem_map = NULL;
+}
+static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct wl1271 *wl = hw->priv;
+
+ mutex_lock(&wl->mutex);
+ WARN_ON(wl->vif != vif);
+ __wl1271_op_remove_interface(wl);
mutex_unlock(&wl->mutex);
+
+ cancel_work_sync(&wl->recovery_work);
}
static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
@@ -1289,7 +1374,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
wl1271_debug(DEBUG_PSM, "psm enabled");
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
- true);
+ wl->basic_rate, true);
}
} else if (!(conf->flags & IEEE80211_CONF_PS) &&
test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
@@ -1299,7 +1384,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
if (test_bit(WL1271_FLAG_PSM, &wl->flags))
ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
- true);
+ wl->basic_rate, true);
}
if (conf->power_level != wl->power_level) {
@@ -1439,7 +1524,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
- key_conf->alg, key_conf->keyidx,
+ key_conf->cipher, key_conf->keyidx,
key_conf->keylen, key_conf->flags);
wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
@@ -1455,28 +1540,34 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (ret < 0)
goto out_unlock;
- switch (key_conf->alg) {
- case ALG_WEP:
+ switch (key_conf->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
key_type = KEY_WEP;
key_conf->hw_key_idx = key_conf->keyidx;
break;
- case ALG_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
key_type = KEY_TKIP;
key_conf->hw_key_idx = key_conf->keyidx;
tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
break;
- case ALG_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
key_type = KEY_AES;
key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
break;
+ case WL1271_CIPHER_SUITE_GEM:
+ key_type = KEY_GEM;
+ tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
+ tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
+ break;
default:
- wl1271_error("Unknown key algo 0x%x", key_conf->alg);
+ wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
ret = -EOPNOTSUPP;
goto out_sleep;
@@ -1558,10 +1649,7 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- if (wl1271_11a_enabled())
- ret = wl1271_scan(hw->priv, ssid, len, req);
- else
- ret = wl1271_scan(hw->priv, ssid, len, req);
+ ret = wl1271_scan(hw->priv, ssid, len, req);
wl1271_ps_elp_sleep(wl);
@@ -1633,7 +1721,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- if ((changed && BSS_CHANGED_BEACON_INT) &&
+ if ((changed & BSS_CHANGED_BEACON_INT) &&
(wl->bss_type == BSS_TYPE_IBSS)) {
wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
bss_conf->beacon_int);
@@ -1642,7 +1730,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
do_join = true;
}
- if ((changed && BSS_CHANGED_BEACON) &&
+ if ((changed & BSS_CHANGED_BEACON) &&
(wl->bss_type == BSS_TYPE_IBSS)) {
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
@@ -1776,12 +1864,15 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
mode = STATION_POWER_SAVE_MODE;
- ret = wl1271_ps_set_mode(wl, mode, true);
+ ret = wl1271_ps_set_mode(wl, mode,
+ wl->basic_rate,
+ true);
if (ret < 0)
goto out_sleep;
}
} else {
/* use defaults when not associated */
+ clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
wl->aid = 0;
@@ -1993,21 +2084,24 @@ static struct ieee80211_rate wl1271_rates[] = {
.hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
};
-/* can't be const, mac80211 writes to this */
+/*
+ * Can't be const, mac80211 writes to this. The order of the channels here
+ * is designed to improve scanning.
+ */
static struct ieee80211_channel wl1271_channels[] = {
{ .hw_value = 1, .center_freq = 2412, .max_power = 25 },
- { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
- { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
- { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
{ .hw_value = 5, .center_freq = 2432, .max_power = 25 },
- { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
- { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
- { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
{ .hw_value = 9, .center_freq = 2452, .max_power = 25 },
- { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
- { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
- { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
{ .hw_value = 13, .center_freq = 2472, .max_power = 25 },
+ { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
+ { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
+ { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
+ { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
+ { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
+ { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
+ { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
+ { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
+ { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
};
/* mapping to indexes for wl1271_rates */
@@ -2076,49 +2170,52 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = {
.hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
};
-/* 5 GHz band channels for WL1273 */
+/*
+ * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
+ * The order of the channels here is designed to improve scanning.
+ */
static struct ieee80211_channel wl1271_channels_5ghz[] = {
{ .hw_value = 183, .center_freq = 4915},
- { .hw_value = 184, .center_freq = 4920},
- { .hw_value = 185, .center_freq = 4925},
- { .hw_value = 187, .center_freq = 4935},
{ .hw_value = 188, .center_freq = 4940},
- { .hw_value = 189, .center_freq = 4945},
- { .hw_value = 192, .center_freq = 4960},
- { .hw_value = 196, .center_freq = 4980},
- { .hw_value = 7, .center_freq = 5035},
{ .hw_value = 8, .center_freq = 5040},
- { .hw_value = 9, .center_freq = 5045},
- { .hw_value = 11, .center_freq = 5055},
- { .hw_value = 12, .center_freq = 5060},
- { .hw_value = 16, .center_freq = 5080},
{ .hw_value = 34, .center_freq = 5170},
- { .hw_value = 36, .center_freq = 5180},
- { .hw_value = 38, .center_freq = 5190},
- { .hw_value = 40, .center_freq = 5200},
- { .hw_value = 42, .center_freq = 5210},
{ .hw_value = 44, .center_freq = 5220},
- { .hw_value = 46, .center_freq = 5230},
- { .hw_value = 48, .center_freq = 5240},
- { .hw_value = 52, .center_freq = 5260},
- { .hw_value = 56, .center_freq = 5280},
{ .hw_value = 60, .center_freq = 5300},
- { .hw_value = 64, .center_freq = 5320},
- { .hw_value = 100, .center_freq = 5500},
- { .hw_value = 104, .center_freq = 5520},
- { .hw_value = 108, .center_freq = 5540},
{ .hw_value = 112, .center_freq = 5560},
- { .hw_value = 116, .center_freq = 5580},
- { .hw_value = 120, .center_freq = 5600},
- { .hw_value = 124, .center_freq = 5620},
- { .hw_value = 128, .center_freq = 5640},
{ .hw_value = 132, .center_freq = 5660},
+ { .hw_value = 157, .center_freq = 5785},
+ { .hw_value = 184, .center_freq = 4920},
+ { .hw_value = 189, .center_freq = 4945},
+ { .hw_value = 9, .center_freq = 5045},
+ { .hw_value = 36, .center_freq = 5180},
+ { .hw_value = 46, .center_freq = 5230},
+ { .hw_value = 64, .center_freq = 5320},
+ { .hw_value = 116, .center_freq = 5580},
{ .hw_value = 136, .center_freq = 5680},
+ { .hw_value = 192, .center_freq = 4960},
+ { .hw_value = 11, .center_freq = 5055},
+ { .hw_value = 38, .center_freq = 5190},
+ { .hw_value = 48, .center_freq = 5240},
+ { .hw_value = 100, .center_freq = 5500},
+ { .hw_value = 120, .center_freq = 5600},
{ .hw_value = 140, .center_freq = 5700},
+ { .hw_value = 185, .center_freq = 4925},
+ { .hw_value = 196, .center_freq = 4980},
+ { .hw_value = 12, .center_freq = 5060},
+ { .hw_value = 40, .center_freq = 5200},
+ { .hw_value = 52, .center_freq = 5260},
+ { .hw_value = 104, .center_freq = 5520},
+ { .hw_value = 124, .center_freq = 5620},
{ .hw_value = 149, .center_freq = 5745},
- { .hw_value = 153, .center_freq = 5765},
- { .hw_value = 157, .center_freq = 5785},
{ .hw_value = 161, .center_freq = 5805},
+ { .hw_value = 187, .center_freq = 4935},
+ { .hw_value = 7, .center_freq = 5035},
+ { .hw_value = 16, .center_freq = 5080},
+ { .hw_value = 42, .center_freq = 5210},
+ { .hw_value = 56, .center_freq = 5280},
+ { .hw_value = 108, .center_freq = 5540},
+ { .hw_value = 128, .center_freq = 5640},
+ { .hw_value = 153, .center_freq = 5765},
{ .hw_value = 165, .center_freq = 5825},
};
@@ -2211,8 +2308,7 @@ static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len;
- /* FIXME: what's the maximum length of buf? page size?*/
- len = 500;
+ len = PAGE_SIZE;
mutex_lock(&wl->mutex);
len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
@@ -2273,8 +2369,7 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len;
- /* FIXME: what's the maximum length of buf? page size?*/
- len = 500;
+ len = PAGE_SIZE;
mutex_lock(&wl->mutex);
if (wl->hw_pg_ver >= 0)
@@ -2306,6 +2401,8 @@ int wl1271_register_hw(struct wl1271 *wl)
wl->mac80211_registered = true;
+ register_netdevice_notifier(&wl1271_dev_notifier);
+
wl1271_notice("loaded");
return 0;
@@ -2314,6 +2411,7 @@ EXPORT_SYMBOL_GPL(wl1271_register_hw);
void wl1271_unregister_hw(struct wl1271 *wl)
{
+ unregister_netdevice_notifier(&wl1271_dev_notifier);
ieee80211_unregister_hw(wl->hw);
wl->mac80211_registered = false;
@@ -2322,6 +2420,14 @@ EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
int wl1271_init_ieee80211(struct wl1271 *wl)
{
+ static const u32 cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+ WL1271_CIPHER_SUITE_GEM,
+ };
+
/* The tx descriptor buffer and the TKIP space. */
wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
sizeof(struct wl1271_tx_hw_descr);
@@ -2339,13 +2445,14 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_CONNECTION_MONITOR |
IEEE80211_HW_SUPPORTS_CQM_RSSI;
+ 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);
wl->hw->wiphy->max_scan_ssids = 1;
wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
-
- if (wl1271_11a_enabled())
- wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
+ wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
wl->hw->queues = 4;
wl->hw->max_rates = 1;
@@ -2364,6 +2471,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
struct platform_device *plat_dev = NULL;
struct wl1271 *wl;
int i, ret;
+ unsigned int order;
hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
if (!hw) {
@@ -2391,6 +2499,10 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
+ INIT_WORK(&wl->irq_work, wl1271_irq_work);
+ INIT_WORK(&wl->tx_work, wl1271_tx_work);
+ INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
+ INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
wl->channel = WL1271_DEFAULT_CHANNEL;
wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
wl->default_key = 0;
@@ -2422,11 +2534,18 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl1271_debugfs_init(wl);
+ order = get_order(WL1271_AGGR_BUFFER_SIZE);
+ wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
+ if (!wl->aggr_buf) {
+ ret = -ENOMEM;
+ goto err_hw;
+ }
+
/* Register platform device */
ret = platform_device_register(wl->plat_dev);
if (ret) {
wl1271_error("couldn't register platform device");
- goto err_hw;
+ goto err_aggr;
}
dev_set_drvdata(&wl->plat_dev->dev, wl);
@@ -2452,6 +2571,9 @@ err_bt_coex_state:
err_platform:
platform_device_unregister(wl->plat_dev);
+err_aggr:
+ free_pages((unsigned long)wl->aggr_buf, order);
+
err_hw:
wl1271_debugfs_exit(wl);
kfree(plat_dev);
@@ -2468,6 +2590,8 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
int wl1271_free_hw(struct wl1271 *wl)
{
platform_device_unregister(wl->plat_dev);
+ free_pages((unsigned long)wl->aggr_buf,
+ get_order(WL1271_AGGR_BUFFER_SIZE));
kfree(wl->plat_dev);
wl1271_debugfs_exit(wl);
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c
index a5e60e0403e5..e3c332e2f97c 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.c
+++ b/drivers/net/wireless/wl12xx/wl1271_ps.c
@@ -39,6 +39,9 @@ void wl1271_elp_work(struct work_struct *work)
mutex_lock(&wl->mutex);
+ if (unlikely(wl->state == WL1271_STATE_OFF))
+ goto out;
+
if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) ||
(!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
!test_bit(WL1271_FLAG_IDLE, &wl->flags)))
@@ -61,7 +64,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
test_bit(WL1271_FLAG_IDLE, &wl->flags)) {
cancel_delayed_work(&wl->elp_work);
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
- msecs_to_jiffies(ELP_ENTRY_DELAY));
+ msecs_to_jiffies(ELP_ENTRY_DELAY));
}
}
@@ -96,6 +99,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
&compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT));
if (ret == 0) {
wl1271_error("ELP wakeup timeout!");
+ ieee80211_queue_work(wl->hw, &wl->recovery_work);
ret = -ETIMEDOUT;
goto err;
} else if (ret < 0) {
@@ -121,7 +125,7 @@ out:
}
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
- bool send)
+ u32 rates, bool send)
{
int ret;
@@ -129,7 +133,14 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
case STATION_POWER_SAVE_MODE:
wl1271_debug(DEBUG_PSM, "entering psm");
- ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, send);
+ ret = wl1271_acx_wake_up_conditions(wl);
+ if (ret < 0) {
+ wl1271_error("couldn't set wake up conditions");
+ return ret;
+ }
+
+ ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE,
+ rates, send);
if (ret < 0)
return ret;
@@ -152,7 +163,8 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
if (ret < 0)
return ret;
- ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE, send);
+ ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE,
+ rates, send);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.h b/drivers/net/wireless/wl12xx/wl1271_ps.h
index 940276f517a4..6ba7b032736f 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.h
+++ b/drivers/net/wireless/wl12xx/wl1271_ps.h
@@ -28,7 +28,7 @@
#include "wl1271_acx.h"
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
- bool send);
+ u32 rates, bool send);
void wl1271_ps_elp_sleep(struct wl1271 *wl);
int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake);
void wl1271_elp_work(struct work_struct *work);
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c
index 019aa79cd9df..bea133b6e489 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_rx.c
@@ -74,9 +74,8 @@ static void wl1271_rx_status(struct wl1271 *wl,
}
}
-static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
+static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
{
- struct ieee80211_rx_status rx_status;
struct wl1271_rx_descriptor *desc;
struct sk_buff *skb;
u16 *fc;
@@ -88,16 +87,16 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
* workaround this by not retrieving them at all.
*/
if (unlikely(wl->state == WL1271_STATE_PLT))
- return;
+ return -EINVAL;
skb = __dev_alloc_skb(length, GFP_KERNEL);
if (!skb) {
wl1271_error("Couldn't allocate RX frame");
- return;
+ return -ENOMEM;
}
buf = skb_put(skb, length);
- wl1271_read(wl, WL1271_SLV_MEM_DATA, buf, length, true);
+ memcpy(buf, data, length);
/* the data read starts with the descriptor */
desc = (struct wl1271_rx_descriptor *) buf;
@@ -109,15 +108,16 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
beacon = 1;
- wl1271_rx_status(wl, desc, &rx_status, beacon);
+ wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
beacon ? "beacon" : "");
skb_trim(skb, skb->len - desc->pad_len);
- memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
ieee80211_rx_ni(wl->hw, skb);
+
+ return 0;
}
void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
@@ -126,31 +126,60 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
u32 buf_size;
u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
+ u32 rx_counter;
u32 mem_block;
+ u32 pkt_length;
+ u32 pkt_offset;
while (drv_rx_counter != fw_rx_counter) {
- mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter);
- buf_size = wl1271_rx_get_buf_size(status, drv_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);
+ if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE)
+ break;
+ buf_size += pkt_length;
+ rx_counter++;
+ rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
+ }
if (buf_size == 0) {
wl1271_warning("received empty data");
break;
}
+ /*
+ * Choose the block we want to read
+ * 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, drv_rx_counter);
wl->rx_mem_pool_addr.addr = (mem_block << 8) +
le32_to_cpu(wl_mem_map->packet_memory_pool_start);
wl->rx_mem_pool_addr.addr_extra =
wl->rx_mem_pool_addr.addr + 4;
-
- /* Choose the block we want to read */
wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr,
- sizeof(wl->rx_mem_pool_addr), false);
-
- wl1271_rx_handle_data(wl, buf_size);
-
- wl->rx_counter++;
- drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
+ sizeof(wl->rx_mem_pool_addr), false);
+
+ /* Read all available packets at once */
+ wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
+ buf_size, true);
+
+ /* Split data into separate packets */
+ pkt_offset = 0;
+ while (pkt_offset < buf_size) {
+ pkt_length = wl1271_rx_get_buf_size(status,
+ drv_rx_counter);
+ if (wl1271_rx_handle_data(wl,
+ wl->aggr_buf + pkt_offset,
+ pkt_length) < 0)
+ break;
+ wl->rx_counter++;
+ drv_rx_counter++;
+ drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
+ pkt_offset += pkt_length;
+ }
}
-
- wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
+ wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS,
+ cpu_to_le32(wl->rx_counter));
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c
index fec43eed8c55..909bb47995b6 100644
--- a/drivers/net/wireless/wl12xx/wl1271_scan.c
+++ b/drivers/net/wireless/wl12xx/wl1271_scan.c
@@ -28,11 +28,43 @@
#include "wl1271_scan.h"
#include "wl1271_acx.h"
+void wl1271_scan_complete_work(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct wl1271 *wl;
+
+ dwork = container_of(work, struct delayed_work, work);
+ wl = container_of(dwork, struct wl1271, scan_complete_work);
+
+ wl1271_debug(DEBUG_SCAN, "Scanning complete");
+
+ mutex_lock(&wl->mutex);
+
+ if (wl->scan.state == WL1271_SCAN_STATE_IDLE) {
+ mutex_unlock(&wl->mutex);
+ return;
+ }
+
+ wl->scan.state = WL1271_SCAN_STATE_IDLE;
+ kfree(wl->scan.scanned_ch);
+ wl->scan.scanned_ch = NULL;
+ mutex_unlock(&wl->mutex);
+
+ ieee80211_scan_completed(wl->hw, false);
+
+ if (wl->scan.failed) {
+ wl1271_info("Scan completed due to error.");
+ ieee80211_queue_work(wl->hw, &wl->recovery_work);
+ }
+}
+
+
static int wl1271_get_scan_channels(struct wl1271 *wl,
struct cfg80211_scan_request *req,
struct basic_scan_channel_params *channels,
enum ieee80211_band band, bool passive)
{
+ struct conf_scan_settings *c = &wl->conf.scan;
int i, j;
u32 flags;
@@ -60,10 +92,17 @@ static int wl1271_get_scan_channels(struct wl1271 *wl,
wl1271_debug(DEBUG_SCAN, "beacon_found %d",
req->channels[i]->beacon_found);
- channels[j].min_duration =
- cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
- channels[j].max_duration =
- cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
+ if (!passive) {
+ channels[j].min_duration =
+ cpu_to_le32(c->min_dwell_time_active);
+ channels[j].max_duration =
+ cpu_to_le32(c->max_dwell_time_active);
+ } else {
+ channels[j].min_duration =
+ cpu_to_le32(c->min_dwell_time_passive);
+ channels[j].max_duration =
+ cpu_to_le32(c->max_dwell_time_passive);
+ }
channels[j].early_termination = 0;
channels[j].tx_power_att = req->channels[i]->max_power;
channels[j].channel = req->channels[i]->hw_value;
@@ -100,8 +139,11 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
/* We always use high priority scans */
scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH;
- if(passive)
+
+ /* No SSIDs means that we have a forced passive scan */
+ if (passive || wl->scan.req->n_ssids == 0)
scan_options |= WL1271_SCAN_OPT_PASSIVE;
+
cmd->params.scan_options = cpu_to_le16(scan_options);
cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
@@ -117,7 +159,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
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 = WL1271_SCAN_PROBE_REQS;
+ 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;
cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
@@ -165,7 +207,7 @@ out:
void wl1271_scan_stm(struct wl1271 *wl)
{
- int ret;
+ int ret = 0;
switch (wl->scan.state) {
case WL1271_SCAN_STATE_IDLE:
@@ -185,7 +227,7 @@ void wl1271_scan_stm(struct wl1271 *wl)
ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true,
wl->conf.tx.basic_rate);
if (ret == WL1271_NOTHING_TO_SCAN) {
- if (wl1271_11a_enabled())
+ if (wl->enable_11a)
wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
else
wl->scan.state = WL1271_SCAN_STATE_DONE;
@@ -215,20 +257,22 @@ void wl1271_scan_stm(struct wl1271 *wl)
break;
case WL1271_SCAN_STATE_DONE:
- mutex_unlock(&wl->mutex);
- ieee80211_scan_completed(wl->hw, false);
- mutex_lock(&wl->mutex);
-
- kfree(wl->scan.scanned_ch);
- wl->scan.scanned_ch = NULL;
-
- wl->scan.state = WL1271_SCAN_STATE_IDLE;
+ wl->scan.failed = false;
+ cancel_delayed_work(&wl->scan_complete_work);
+ ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+ msecs_to_jiffies(0));
break;
default:
wl1271_error("invalid scan state");
break;
}
+
+ if (ret < 0) {
+ cancel_delayed_work(&wl->scan_complete_work);
+ ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+ msecs_to_jiffies(0));
+ }
}
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
@@ -248,9 +292,14 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
wl->scan.req = req;
- wl->scan.scanned_ch = kzalloc(req->n_channels *
+ wl->scan.scanned_ch = kcalloc(req->n_channels,
sizeof(*wl->scan.scanned_ch),
GFP_KERNEL);
+ /* we assume failure so that timeout scenarios are handled correctly */
+ wl->scan.failed = true;
+ ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+ msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
+
wl1271_scan_stm(wl);
return 0;
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.h b/drivers/net/wireless/wl12xx/wl1271_scan.h
index f1815700f5f9..6d57127b5e6b 100644
--- a/drivers/net/wireless/wl12xx/wl1271_scan.h
+++ b/drivers/net/wireless/wl12xx/wl1271_scan.h
@@ -32,6 +32,7 @@ int wl1271_scan_build_probe_req(struct wl1271 *wl,
const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len, u8 band);
void wl1271_scan_stm(struct wl1271 *wl);
+void wl1271_scan_complete_work(struct work_struct *work);
#define WL1271_SCAN_MAX_CHANNELS 24
#define WL1271_SCAN_DEFAULT_TAG 1
@@ -39,11 +40,10 @@ void wl1271_scan_stm(struct wl1271 *wl);
#define WL1271_SCAN_OPT_ACTIVE 0
#define WL1271_SCAN_OPT_PASSIVE 1
#define WL1271_SCAN_OPT_PRIORITY_HIGH 4
-#define WL1271_SCAN_CHAN_MIN_DURATION 30000 /* TU */
-#define WL1271_SCAN_CHAN_MAX_DURATION 60000 /* TU */
#define WL1271_SCAN_BAND_2_4_GHZ 0
#define WL1271_SCAN_BAND_5_GHZ 1
-#define WL1271_SCAN_PROBE_REQS 3
+
+#define WL1271_SCAN_TIMEOUT 10000 /* msec */
enum {
WL1271_SCAN_STATE_IDLE,
diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c
index 7059b5cccf0f..784ef3432641 100644
--- a/drivers/net/wireless/wl12xx/wl1271_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c
@@ -29,14 +29,13 @@
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/card.h>
#include <linux/gpio.h>
+#include <linux/wl12xx.h>
+#include <linux/pm_runtime.h>
#include "wl1271.h"
#include "wl12xx_80211.h"
#include "wl1271_io.h"
-
-#define RX71_WL1271_IRQ_GPIO 42
-
#ifndef SDIO_VENDOR_ID_TI
#define SDIO_VENDOR_ID_TI 0x0097
#endif
@@ -107,6 +106,8 @@ static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
int ret;
struct sdio_func *func = wl_to_func(wl);
+ sdio_claim_host(func);
+
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x",
@@ -122,9 +123,10 @@ static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
}
+ sdio_release_host(func);
+
if (ret)
wl1271_error("sdio read failed (%d)", ret);
-
}
static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
@@ -133,6 +135,8 @@ static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
int ret;
struct sdio_func *func = wl_to_func(wl);
+ sdio_claim_host(func);
+
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x",
@@ -147,26 +151,49 @@ static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
else
ret = sdio_memcpy_toio(func, addr, buf, len);
}
+
+ sdio_release_host(func);
+
if (ret)
wl1271_error("sdio write failed (%d)", ret);
+}
+static int wl1271_sdio_power_on(struct wl1271 *wl)
+{
+ struct sdio_func *func = wl_to_func(wl);
+ int ret;
+
+ /* Power up the card */
+ ret = pm_runtime_get_sync(&func->dev);
+ if (ret < 0)
+ goto out;
+
+ sdio_claim_host(func);
+ sdio_enable_func(func);
+ sdio_release_host(func);
+
+out:
+ return ret;
}
-static void wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
+static int wl1271_sdio_power_off(struct wl1271 *wl)
{
struct sdio_func *func = wl_to_func(wl);
- /* Let the SDIO stack handle wlan_enable control, so we
- * keep host claimed while wlan is in use to keep wl1271
- * alive.
- */
- if (enable) {
- sdio_claim_host(func);
- sdio_enable_func(func);
- } else {
- sdio_disable_func(func);
- sdio_release_host(func);
- }
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+
+ /* Power down the card */
+ return pm_runtime_put_sync(&func->dev);
+}
+
+static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
+{
+ if (enable)
+ return wl1271_sdio_power_on(wl);
+ else
+ return wl1271_sdio_power_off(wl);
}
static struct wl1271_if_operations sdio_ops = {
@@ -184,6 +211,7 @@ static int __devinit wl1271_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
struct ieee80211_hw *hw;
+ const struct wl12xx_platform_data *wlan_data;
struct wl1271 *wl;
int ret;
@@ -203,13 +231,16 @@ static int __devinit wl1271_probe(struct sdio_func *func,
/* Grab access to FN0 for ELP reg. */
func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
- wl->irq = gpio_to_irq(RX71_WL1271_IRQ_GPIO);
- if (wl->irq < 0) {
- ret = wl->irq;
- wl1271_error("could not get irq!");
+ wlan_data = wl12xx_get_platform_data();
+ if (IS_ERR(wlan_data)) {
+ ret = PTR_ERR(wlan_data);
+ wl1271_error("missing wlan platform data: %d", ret);
goto out_free;
}
+ wl->irq = wlan_data->irq;
+ wl->ref_clock = wlan_data->board_ref_clock;
+
ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
if (ret < 0) {
wl1271_error("request_irq() failed: %d", ret);
@@ -230,6 +261,9 @@ static int __devinit wl1271_probe(struct sdio_func *func,
sdio_set_drvdata(func, wl);
+ /* Tell PM core that we don't need the card to be powered now */
+ pm_runtime_put_noidle(&func->dev);
+
wl1271_notice("initialized");
return 0;
@@ -248,17 +282,39 @@ static void __devexit wl1271_remove(struct sdio_func *func)
{
struct wl1271 *wl = sdio_get_drvdata(func);
- free_irq(wl->irq, wl);
+ /* Undo decrement done above in wl1271_probe */
+ pm_runtime_get_noresume(&func->dev);
wl1271_unregister_hw(wl);
+ free_irq(wl->irq, wl);
wl1271_free_hw(wl);
}
+static int wl1271_suspend(struct device *dev)
+{
+ /* Tell MMC/SDIO core it's OK to power down the card
+ * (if it isn't already), but not to remove it completely */
+ return 0;
+}
+
+static int wl1271_resume(struct device *dev)
+{
+ return 0;
+}
+
+static const struct dev_pm_ops wl1271_sdio_pm_ops = {
+ .suspend = wl1271_suspend,
+ .resume = wl1271_resume,
+};
+
static struct sdio_driver wl1271_sdio_driver = {
.name = "wl1271_sdio",
.id_table = wl1271_devices,
.probe = wl1271_probe,
.remove = __devexit_p(wl1271_remove),
+ .drv = {
+ .pm = &wl1271_sdio_pm_ops,
+ },
};
static int __init wl1271_init(void)
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index 4cb99c541e2a..ef801680773f 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -25,7 +25,7 @@
#include <linux/module.h>
#include <linux/crc7.h>
#include <linux/spi/spi.h>
-#include <linux/spi/wl12xx.h>
+#include <linux/wl12xx.h>
#include <linux/slab.h>
#include "wl1271.h"
@@ -63,6 +63,11 @@
((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32))
#define HW_ACCESS_WSPI_INIT_CMD_MASK 0
+/* HW limitation: maximum possible chunk size is 4095 bytes */
+#define WSPI_MAX_CHUNK_SIZE 4092
+
+#define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE)
+
static inline struct spi_device *wl_to_spi(struct wl1271 *wl)
{
return wl->if_priv;
@@ -202,90 +207,117 @@ static int wl1271_spi_read_busy(struct wl1271 *wl)
static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed)
{
- struct spi_transfer t[3];
+ struct spi_transfer t[2];
struct spi_message m;
u32 *busy_buf;
u32 *cmd;
+ u32 chunk_len;
- cmd = &wl->buffer_cmd;
- busy_buf = wl->buffer_busyword;
+ while (len > 0) {
+ chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
- *cmd = 0;
- *cmd |= WSPI_CMD_READ;
- *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
- *cmd |= addr & WSPI_CMD_BYTE_ADDR;
+ cmd = &wl->buffer_cmd;
+ busy_buf = wl->buffer_busyword;
- if (fixed)
- *cmd |= WSPI_CMD_FIXED;
+ *cmd = 0;
+ *cmd |= WSPI_CMD_READ;
+ *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) &
+ WSPI_CMD_BYTE_LENGTH;
+ *cmd |= addr & WSPI_CMD_BYTE_ADDR;
- spi_message_init(&m);
- memset(t, 0, sizeof(t));
+ if (fixed)
+ *cmd |= WSPI_CMD_FIXED;
- t[0].tx_buf = cmd;
- t[0].len = 4;
- t[0].cs_change = true;
- spi_message_add_tail(&t[0], &m);
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
- /* Busy and non busy words read */
- t[1].rx_buf = busy_buf;
- t[1].len = WL1271_BUSY_WORD_LEN;
- t[1].cs_change = true;
- spi_message_add_tail(&t[1], &m);
+ t[0].tx_buf = cmd;
+ t[0].len = 4;
+ t[0].cs_change = true;
+ spi_message_add_tail(&t[0], &m);
- spi_sync(wl_to_spi(wl), &m);
+ /* Busy and non busy words read */
+ t[1].rx_buf = busy_buf;
+ t[1].len = WL1271_BUSY_WORD_LEN;
+ t[1].cs_change = true;
+ spi_message_add_tail(&t[1], &m);
- if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) &&
- wl1271_spi_read_busy(wl)) {
- memset(buf, 0, len);
- return;
- }
+ spi_sync(wl_to_spi(wl), &m);
- spi_message_init(&m);
- memset(t, 0, sizeof(t));
+ if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) &&
+ wl1271_spi_read_busy(wl)) {
+ memset(buf, 0, chunk_len);
+ return;
+ }
- t[0].rx_buf = buf;
- t[0].len = len;
- t[0].cs_change = true;
- spi_message_add_tail(&t[0], &m);
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
- spi_sync(wl_to_spi(wl), &m);
+ t[0].rx_buf = buf;
+ t[0].len = chunk_len;
+ t[0].cs_change = true;
+ spi_message_add_tail(&t[0], &m);
- wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
- wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
+ spi_sync(wl_to_spi(wl), &m);
+
+ wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
+ wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, chunk_len);
+
+ if (!fixed)
+ addr += chunk_len;
+ buf += chunk_len;
+ len -= chunk_len;
+ }
}
static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed)
{
- struct spi_transfer t[2];
+ struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
struct spi_message m;
+ u32 commands[WSPI_MAX_NUM_OF_CHUNKS];
u32 *cmd;
+ u32 chunk_len;
+ int i;
- cmd = &wl->buffer_cmd;
-
- *cmd = 0;
- *cmd |= WSPI_CMD_WRITE;
- *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
- *cmd |= addr & WSPI_CMD_BYTE_ADDR;
-
- if (fixed)
- *cmd |= WSPI_CMD_FIXED;
+ WARN_ON(len > WL1271_AGGR_BUFFER_SIZE);
spi_message_init(&m);
memset(t, 0, sizeof(t));
- t[0].tx_buf = cmd;
- t[0].len = sizeof(*cmd);
- spi_message_add_tail(&t[0], &m);
+ cmd = &commands[0];
+ i = 0;
+ while (len > 0) {
+ chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
- t[1].tx_buf = buf;
- t[1].len = len;
- spi_message_add_tail(&t[1], &m);
+ *cmd = 0;
+ *cmd |= WSPI_CMD_WRITE;
+ *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) &
+ WSPI_CMD_BYTE_LENGTH;
+ *cmd |= addr & WSPI_CMD_BYTE_ADDR;
- spi_sync(wl_to_spi(wl), &m);
+ if (fixed)
+ *cmd |= WSPI_CMD_FIXED;
+
+ t[i].tx_buf = cmd;
+ t[i].len = sizeof(*cmd);
+ spi_message_add_tail(&t[i++], &m);
+
+ t[i].tx_buf = buf;
+ t[i].len = chunk_len;
+ spi_message_add_tail(&t[i++], &m);
- wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
- wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
+ wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
+ wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, chunk_len);
+
+ if (!fixed)
+ addr += chunk_len;
+ buf += chunk_len;
+ len -= chunk_len;
+ cmd++;
+ }
+
+ spi_sync(wl_to_spi(wl), &m);
}
static irqreturn_t wl1271_irq(int irq, void *cookie)
@@ -312,10 +344,12 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
return IRQ_HANDLED;
}
-static void wl1271_spi_set_power(struct wl1271 *wl, bool enable)
+static int wl1271_spi_set_power(struct wl1271 *wl, bool enable)
{
if (wl->set_power)
wl->set_power(enable);
+
+ return 0;
}
static struct wl1271_if_operations spi_ops = {
@@ -370,6 +404,8 @@ static int __devinit wl1271_probe(struct spi_device *spi)
goto out_free;
}
+ wl->ref_clock = pdata->board_ref_clock;
+
wl->irq = spi->irq;
if (wl->irq < 0) {
wl1271_error("irq missing in platform data");
@@ -412,9 +448,8 @@ static int __devexit wl1271_remove(struct spi_device *spi)
{
struct wl1271 *wl = dev_get_drvdata(&spi->dev);
- free_irq(wl->irq, wl);
-
wl1271_unregister_hw(wl);
+ free_irq(wl->irq, wl);
wl1271_free_hw(wl);
return 0;
diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/wl1271_testmode.c
index 6e0952f79e9a..a3aa84386c88 100644
--- a/drivers/net/wireless/wl12xx/wl1271_testmode.c
+++ b/drivers/net/wireless/wl12xx/wl1271_testmode.c
@@ -199,19 +199,6 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
len = nla_len(tb[WL1271_TM_ATTR_DATA]);
- /*
- * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
- * configurations) can be removed when those NVS files stop floating
- * around.
- */
- if (len != sizeof(struct wl1271_nvs_file) &&
- (len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
- wl1271_11a_enabled())) {
- wl1271_error("nvs size is not as expected: %zu != %zu",
- len, sizeof(struct wl1271_nvs_file));
- return -EMSGSIZE;
- }
-
mutex_lock(&wl->mutex);
kfree(wl->nvs);
@@ -224,6 +211,7 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
}
memcpy(wl->nvs, buf, len);
+ wl->nvs_len = len;
wl1271_debug(DEBUG_TESTMODE, "testmode pushed nvs");
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index c592cc2e9fe8..e3dc13c4d01a 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -43,13 +43,17 @@ static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb)
return -EBUSY;
}
-static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
+static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
+ u32 buf_offset)
{
struct wl1271_tx_hw_descr *desc;
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
u32 total_blocks;
int id, ret = -EBUSY;
+ if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
+ return -EBUSY;
+
/* allocate free identifier for the packet */
id = wl1271_tx_id(wl, skb);
if (id < 0)
@@ -82,7 +86,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
return ret;
}
-static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
+static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
u32 extra, struct ieee80211_tx_info *control)
{
struct timespec ts;
@@ -110,9 +114,9 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
/* configure the tx attributes */
tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
- /* queue */
+ /* queue (we use same identifiers for tid's and ac's */
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
- desc->tid = wl1271_tx_ac_to_tid(ac);
+ desc->tid = ac;
desc->aid = TX_HW_DEFAULT_AID;
desc->reserved = 0;
@@ -133,59 +137,17 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
desc->tx_attr = cpu_to_le16(tx_attr);
wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad);
- return 0;
-}
-
-static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb,
- struct ieee80211_tx_info *control)
-{
-
- struct wl1271_tx_hw_descr *desc;
- int len;
-
- /* FIXME: This is a workaround for getting non-aligned packets.
- This happens at least with EAPOL packets from the user space.
- Our DMA requires packets to be aligned on a 4-byte boundary.
- */
- if (unlikely((long)skb->data & 0x03)) {
- int offset = (4 - (long)skb->data) & 0x03;
- wl1271_debug(DEBUG_TX, "skb offset %d", offset);
-
- /* check whether the current skb can be used */
- if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) {
- unsigned char *src = skb->data;
-
- /* align the buffer on a 4-byte boundary */
- skb_reserve(skb, offset);
- memmove(skb->data, src, skb->len);
- } else {
- wl1271_info("No handler, fixme!");
- return -EINVAL;
- }
- }
-
- len = WL1271_TX_ALIGN(skb->len);
-
- /* perform a fixed address block write with the packet */
- wl1271_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
-
- /* write packet new counter into the write access register */
- wl->tx_packets_count++;
-
- desc = (struct wl1271_tx_hw_descr *) skb->data;
- wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)",
- desc->id, skb, len, desc->length);
-
- return 0;
}
/* caller must hold wl->mutex */
-static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
+static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
+ u32 buf_offset)
{
struct ieee80211_tx_info *info;
u32 extra = 0;
int ret = 0;
u8 idx;
+ u32 total_len;
if (!skb)
return -EINVAL;
@@ -193,7 +155,7 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
info = IEEE80211_SKB_CB(skb);
if (info->control.hw_key &&
- info->control.hw_key->alg == ALG_TKIP)
+ info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP)
extra = WL1271_TKIP_IV_SPACE;
if (info->control.hw_key) {
@@ -208,19 +170,22 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
}
}
- ret = wl1271_tx_allocate(wl, skb, extra);
+ ret = wl1271_tx_allocate(wl, skb, extra, buf_offset);
if (ret < 0)
return ret;
- ret = wl1271_tx_fill_hdr(wl, skb, extra, info);
- if (ret < 0)
- return ret;
+ wl1271_tx_fill_hdr(wl, skb, extra, info);
- ret = wl1271_tx_send_packet(wl, skb, info);
- if (ret < 0)
- return ret;
+ /*
+ * The length of each packet is stored in terms of words. Thus, we must
+ * pad the skb data to make sure its length is aligned.
+ * The number of padding bytes is computed and set in wl1271_tx_fill_hdr
+ */
+ total_len = WL1271_TX_ALIGN(skb->len);
+ memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len);
+ memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);
- return ret;
+ return total_len;
}
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
@@ -245,7 +210,7 @@ void wl1271_tx_work(struct work_struct *work)
struct sk_buff *skb;
bool woken_up = false;
u32 sta_rates = 0;
- u32 prev_tx_packets_count;
+ u32 buf_offset;
int ret;
/* check if the rates supported by the AP have changed */
@@ -262,14 +227,15 @@ void wl1271_tx_work(struct work_struct *work)
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;
- prev_tx_packets_count = wl->tx_packets_count;
-
/* if rates have changed, re-configure the rate policy */
if (unlikely(sta_rates)) {
wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates);
wl1271_acx_rate_policies(wl);
}
+ /* Prepare the transfer buffer, by aggregating all
+ * available packets */
+ buf_offset = 0;
while ((skb = skb_dequeue(&wl->tx_queue))) {
if (!woken_up) {
ret = wl1271_ps_elp_wakeup(wl, false);
@@ -278,21 +244,30 @@ void wl1271_tx_work(struct work_struct *work)
woken_up = true;
}
- ret = wl1271_tx_frame(wl, skb);
+ ret = wl1271_prepare_tx_frame(wl, skb, buf_offset);
if (ret == -EBUSY) {
- /* firmware buffer is full, lets stop transmitting. */
+ /*
+ * Either the firmware buffer is full, or the
+ * aggregation buffer is.
+ * Queue back last skb, and stop aggregating.
+ */
skb_queue_head(&wl->tx_queue, skb);
goto out_ack;
} else if (ret < 0) {
dev_kfree_skb(skb);
goto out_ack;
}
+ buf_offset += ret;
+ wl->tx_packets_count++;
}
out_ack:
- /* interrupt the firmware with the new packets */
- if (prev_tx_packets_count != wl->tx_packets_count)
+ if (buf_offset) {
+ wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
+ buf_offset, true);
+ /* interrupt the firmware with the new packets */
wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
+ }
out:
if (woken_up)
@@ -347,7 +322,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
/* remove TKIP header space if present */
if (info->control.hw_key &&
- info->control.hw_key->alg == ALG_TKIP) {
+ info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen);
skb_pull(skb, WL1271_TKIP_IV_SPACE);
@@ -422,8 +397,6 @@ void wl1271_tx_reset(struct wl1271 *wl)
struct sk_buff *skb;
/* TX failure */
-/* control->flags = 0; FIXME */
-
while ((skb = skb_dequeue(&wl->tx_queue))) {
wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
ieee80211_tx_status(wl->hw, skb);
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h
index 48bf92621c03..d12a129ad11c 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.h
@@ -139,23 +139,6 @@ static inline int wl1271_tx_get_queue(int queue)
}
}
-/* wl1271 tx descriptor needs the tid and we need to convert it from ac */
-static inline int wl1271_tx_ac_to_tid(int ac)
-{
- switch (ac) {
- case 0:
- return 0;
- case 1:
- return 2;
- case 2:
- return 4;
- case 3:
- return 6;
- default:
- return 0;
- }
-}
-
void wl1271_tx_work(struct work_struct *work);
void wl1271_tx_complete(struct wl1271 *wl);
void wl1271_tx_reset(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl12xx_platform_data.c b/drivers/net/wireless/wl12xx/wl12xx_platform_data.c
new file mode 100644
index 000000000000..973b11060a8f
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl12xx_platform_data.c
@@ -0,0 +1,28 @@
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/wl12xx.h>
+
+static const struct wl12xx_platform_data *platform_data;
+
+int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
+{
+ if (platform_data)
+ return -EBUSY;
+ if (!data)
+ return -EINVAL;
+
+ platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL);
+ if (!platform_data)
+ return -ENOMEM;
+
+ return 0;
+}
+
+const struct wl12xx_platform_data *wl12xx_get_platform_data(void)
+{
+ if (!platform_data)
+ return ERR_PTR(-ENODEV);
+
+ return platform_data;
+}
+EXPORT_SYMBOL(wl12xx_get_platform_data);
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index ca3f8961fa27..ee82df62e646 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -29,7 +29,6 @@
#include <linux/delay.h>
#include <linux/types.h>
-#include <linux/ethtool.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/in.h>
@@ -1403,15 +1402,6 @@ static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
return wstats;
}
-static void wl3501_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
- strlcpy(info->driver, "wl3501_cs", sizeof(info->driver));
-}
-
-static const struct ethtool_ops ops = {
- .get_drvinfo = wl3501_get_drvinfo
-};
-
/**
* wl3501_detach - deletes a driver "instance"
* @link - FILL_IN
@@ -1887,7 +1877,6 @@ static int wl3501_probe(struct pcmcia_device *p_dev)
this->p_dev = p_dev;
dev->wireless_data = &this->wireless_data;
dev->wireless_handlers = &wl3501_handler_def;
- SET_ETHTOOL_OPS(dev, &ops);
netif_stop_queue(dev);
p_dev->priv = dev;
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index b2af3c549bb3..87a95bcfee57 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -973,6 +973,7 @@ static void dump_fw_registers(struct zd_chip *chip)
static int print_fw_version(struct zd_chip *chip)
{
+ struct wiphy *wiphy = zd_chip_to_mac(chip)->hw->wiphy;
int r;
u16 version;
@@ -982,6 +983,10 @@ static int print_fw_version(struct zd_chip *chip)
return r;
dev_info(zd_chip_dev(chip),"firmware version %04hx\n", version);
+
+ snprintf(wiphy->fw_version, sizeof(wiphy->fw_version),
+ "%04hx", version);
+
return 0;
}
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index b50fedcef8ac..630fb8664768 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -135,7 +135,7 @@ static void skb_entry_set_link(union skb_entry *list, unsigned short id)
static int skb_entry_is_link(const union skb_entry *list)
{
BUILD_BUG_ON(sizeof(list->skb) != sizeof(list->link));
- return ((unsigned long)list->skb < PAGE_OFFSET);
+ return (unsigned long)list->skb < PAGE_OFFSET;
}
/*
@@ -203,8 +203,8 @@ static void rx_refill_timeout(unsigned long data)
static int netfront_tx_slot_available(struct netfront_info *np)
{
- return ((np->tx.req_prod_pvt - np->tx.rsp_cons) <
- (TX_MAX_TARGET - MAX_SKB_FRAGS - 2));
+ return (np->tx.req_prod_pvt - np->tx.rsp_cons) <
+ (TX_MAX_TARGET - MAX_SKB_FRAGS - 2);
}
static void xennet_maybe_wake_tx(struct net_device *dev)
@@ -1395,7 +1395,7 @@ static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
}
/* Common code used when first setting up, and when resuming. */
-static int talk_to_backend(struct xenbus_device *dev,
+static int talk_to_netback(struct xenbus_device *dev,
struct netfront_info *info)
{
const char *message;
@@ -1545,7 +1545,7 @@ static int xennet_connect(struct net_device *dev)
return -ENODEV;
}
- err = talk_to_backend(np->xbdev, np);
+ err = talk_to_netback(np->xbdev, np);
if (err)
return err;
@@ -1599,7 +1599,7 @@ static int xennet_connect(struct net_device *dev)
/**
* Callback received when the backend's state changes.
*/
-static void backend_changed(struct xenbus_device *dev,
+static void netback_changed(struct xenbus_device *dev,
enum xenbus_state backend_state)
{
struct netfront_info *np = dev_get_drvdata(&dev->dev);
@@ -1801,7 +1801,7 @@ static struct xenbus_driver netfront_driver = {
.probe = netfront_probe,
.remove = __devexit_p(xennet_remove),
.resume = netfront_resume,
- .otherend_changed = backend_changed,
+ .otherend_changed = netback_changed,
};
static int __init netif_init(void)
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index ecbbb688eba0..14f0955eca68 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -430,8 +430,8 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
}
/* Get the protocol type of the ethernet frame that arrived */
- proto_type = ((in_be32(addr + XEL_HEADER_OFFSET +
- XEL_RXBUFF_OFFSET) >> XEL_HEADER_SHIFT) &
+ proto_type = ((ntohl(in_be32(addr + XEL_HEADER_OFFSET +
+ XEL_RXBUFF_OFFSET)) >> XEL_HEADER_SHIFT) &
XEL_RPLR_LENGTH_MASK);
/* Check if received ethernet frame is a raw ethernet frame
@@ -439,9 +439,9 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
if (proto_type > (ETH_FRAME_LEN + ETH_FCS_LEN)) {
if (proto_type == ETH_P_IP) {
- length = ((in_be32(addr +
+ length = ((ntohl(in_be32(addr +
XEL_HEADER_IP_LENGTH_OFFSET +
- XEL_RXBUFF_OFFSET) >>
+ XEL_RXBUFF_OFFSET)) >>
XEL_HEADER_SHIFT) &
XEL_RPLR_LENGTH_MASK);
length += ETH_HLEN + ETH_FCS_LEN;
@@ -641,7 +641,7 @@ static void xemaclite_rx_handler(struct net_device *dev)
skb_put(skb, len); /* Tell the skb how much data we got */
skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_NONE;
+ skb_checksum_none_assert(skb);
dev->stats.rx_packets++;
dev->stats.rx_bytes += len;
@@ -1269,6 +1269,16 @@ static int __devexit xemaclite_of_remove(struct platform_device *of_dev)
return 0;
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void
+xemaclite_poll_controller(struct net_device *ndev)
+{
+ disable_irq(ndev->irq);
+ xemaclite_interrupt(ndev->irq, ndev);
+ enable_irq(ndev->irq);
+}
+#endif
+
static struct net_device_ops xemaclite_netdev_ops = {
.ndo_open = xemaclite_open,
.ndo_stop = xemaclite_close,
@@ -1276,6 +1286,9 @@ static struct net_device_ops xemaclite_netdev_ops = {
.ndo_set_mac_address = xemaclite_set_mac_address,
.ndo_tx_timeout = xemaclite_tx_timeout,
.ndo_get_stats = xemaclite_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = xemaclite_poll_controller,
+#endif
};
/* Match table for OF platform binding */
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 4eb67aed68dd..cd1b3dcd61db 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -646,7 +646,7 @@ static int yellowfin_open(struct net_device *dev)
init_timer(&yp->timer);
yp->timer.expires = jiffies + 3*HZ;
yp->timer.data = (unsigned long)dev;
- yp->timer.function = &yellowfin_timer; /* timer handler */
+ yp->timer.function = yellowfin_timer; /* timer handler */
add_timer(&yp->timer);
return 0;
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 6acbff389ab6..aa675ebd8eb3 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -4,7 +4,7 @@ config DTC
config OF
bool
-menu "Flattened Device Tree and Open Firmware support"
+menu "Device Tree and Open Firmware support"
depends on OF
config PROC_DEVICETREE
@@ -19,6 +19,9 @@ config OF_FLATTREE
bool
select DTC
+config OF_PROMTREE
+ bool
+
config OF_DYNAMIC
def_bool y
depends on PPC_OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 0052c405463a..7888155bea08 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -1,5 +1,6 @@
obj-y = base.o
obj-$(CONFIG_OF_FLATTREE) += fdt.o
+obj-$(CONFIG_OF_PROMTREE) += pdt.o
obj-$(CONFIG_OF_ADDRESS) += address.o
obj-$(CONFIG_OF_IRQ) += irq.o
obj-$(CONFIG_OF_DEVICE) += device.o platform.o
diff --git a/drivers/of/address.c b/drivers/of/address.c
index fcadb726d4f9..3a1c7e70b192 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -163,7 +163,7 @@ static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
unsigned int *flags)
{
- const u32 *prop;
+ const __be32 *prop;
unsigned int psize;
struct device_node *parent;
struct of_bus *bus;
diff --git a/drivers/of/base.c b/drivers/of/base.c
index aa805250de76..710b53bfac6d 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -33,7 +33,7 @@ DEFINE_RWLOCK(devtree_lock);
int of_n_addr_cells(struct device_node *np)
{
- const int *ip;
+ const __be32 *ip;
do {
if (np->parent)
@@ -49,7 +49,7 @@ EXPORT_SYMBOL(of_n_addr_cells);
int of_n_size_cells(struct device_node *np)
{
- const int *ip;
+ const __be32 *ip;
do {
if (np->parent)
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 92de0eb74aea..45d86530799f 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -81,29 +81,10 @@ struct device_attribute of_platform_device_attrs[] = {
__ATTR_NULL
};
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
- struct platform_device *ofdev;
-
- ofdev = to_platform_device(dev);
- of_node_put(ofdev->dev.of_node);
- kfree(ofdev);
-}
-EXPORT_SYMBOL(of_release_dev);
-
-int of_device_register(struct platform_device *ofdev)
+int of_device_add(struct platform_device *ofdev)
{
BUG_ON(ofdev->dev.of_node == NULL);
- device_initialize(&ofdev->dev);
-
/* name and id have to be set so that the platform bus doesn't get
* confused on matching */
ofdev->name = dev_name(&ofdev->dev);
@@ -117,6 +98,12 @@ int of_device_register(struct platform_device *ofdev)
return device_add(&ofdev->dev);
}
+
+int of_device_register(struct platform_device *pdev)
+{
+ device_initialize(&pdev->dev);
+ return of_device_add(pdev);
+}
EXPORT_SYMBOL(of_device_register);
void of_device_unregister(struct platform_device *ofdev)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 65da5aec7552..c1360e02f921 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -533,8 +533,6 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
#endif /* CONFIG_CMDLINE */
- early_init_dt_scan_chosen_arch(node);
-
pr_debug("Command line is: %s\n", cmd_line);
/* break now */
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 6e595e5a3977..75b0d3cb7676 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -24,6 +24,11 @@
#include <linux/of_irq.h>
#include <linux/string.h>
+/* For archs that don't support NO_IRQ (such as x86), provide a dummy value */
+#ifndef NO_IRQ
+#define NO_IRQ 0
+#endif
+
/**
* irq_of_parse_and_map - Parse and map an interrupt into linux virq space
* @device: Device node of the device whose interrupt is to be mapped
@@ -347,3 +352,37 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
return irq;
}
EXPORT_SYMBOL_GPL(of_irq_to_resource);
+
+/**
+ * of_irq_count - Count the number of IRQs a node uses
+ * @dev: pointer to device tree node
+ */
+int of_irq_count(struct device_node *dev)
+{
+ int nr = 0;
+
+ while (of_irq_to_resource(dev, nr, NULL) != NO_IRQ)
+ nr++;
+
+ return nr;
+}
+
+/**
+ * of_irq_to_resource_table - Fill in resource table with node's IRQ info
+ * @dev: pointer to device tree node
+ * @res: array of resources to fill in
+ * @nr_irqs: the number of IRQs (and upper bound for num of @res elements)
+ *
+ * Returns the size of the filled in table (up to @nr_irqs).
+ */
+int of_irq_to_resource_table(struct device_node *dev, struct resource *res,
+ int nr_irqs)
+{
+ int i;
+
+ for (i = 0; i < nr_irqs; i++, res++)
+ if (of_irq_to_resource(dev, i, res) == NO_IRQ)
+ break;
+
+ return i;
+}
diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c
index 0a694debd226..c85d3c7421fc 100644
--- a/drivers/of/of_i2c.c
+++ b/drivers/of/of_i2c.c
@@ -12,6 +12,7 @@
*/
#include <linux/i2c.h>
+#include <linux/irq.h>
#include <linux/of.h>
#include <linux/of_i2c.h>
#include <linux/of_irq.h>
diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c
new file mode 100644
index 000000000000..28295d0a50f6
--- /dev/null
+++ b/drivers/of/pdt.c
@@ -0,0 +1,276 @@
+/* pdt.c: OF PROM device tree support code.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ * {engebret|bergner}@us.ibm.com
+ *
+ * Adapted for sparc by David S. Miller davem@davemloft.net
+ * Adapted for multiple architectures by Andres Salomon <dilinger@queued.net>
+ *
+ * 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/module.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_pdt.h>
+#include <asm/prom.h>
+
+static struct of_pdt_ops *of_pdt_prom_ops __initdata;
+
+void __initdata (*of_pdt_build_more)(struct device_node *dp,
+ struct device_node ***nextp);
+
+#if defined(CONFIG_SPARC)
+unsigned int of_pdt_unique_id __initdata;
+
+#define of_pdt_incr_unique_id(p) do { \
+ (p)->unique_id = of_pdt_unique_id++; \
+} while (0)
+
+static inline const char *of_pdt_node_name(struct device_node *dp)
+{
+ return dp->path_component_name;
+}
+
+#else
+
+static inline void of_pdt_incr_unique_id(void *p) { }
+static inline void irq_trans_init(struct device_node *dp) { }
+
+static inline const char *of_pdt_node_name(struct device_node *dp)
+{
+ return dp->name;
+}
+
+#endif /* !CONFIG_SPARC */
+
+static struct property * __init of_pdt_build_one_prop(phandle node, char *prev,
+ char *special_name,
+ void *special_val,
+ int special_len)
+{
+ static struct property *tmp = NULL;
+ struct property *p;
+ int err;
+
+ if (tmp) {
+ p = tmp;
+ memset(p, 0, sizeof(*p) + 32);
+ tmp = NULL;
+ } else {
+ p = prom_early_alloc(sizeof(struct property) + 32);
+ of_pdt_incr_unique_id(p);
+ }
+
+ p->name = (char *) (p + 1);
+ if (special_name) {
+ strcpy(p->name, special_name);
+ p->length = special_len;
+ p->value = prom_early_alloc(special_len);
+ memcpy(p->value, special_val, special_len);
+ } else {
+ err = of_pdt_prom_ops->nextprop(node, prev, p->name);
+ if (err) {
+ tmp = p;
+ return NULL;
+ }
+ p->length = of_pdt_prom_ops->getproplen(node, p->name);
+ if (p->length <= 0) {
+ p->length = 0;
+ } else {
+ int len;
+
+ p->value = prom_early_alloc(p->length + 1);
+ len = of_pdt_prom_ops->getproperty(node, p->name,
+ p->value, p->length);
+ if (len <= 0)
+ p->length = 0;
+ ((unsigned char *)p->value)[p->length] = '\0';
+ }
+ }
+ return p;
+}
+
+static struct property * __init of_pdt_build_prop_list(phandle node)
+{
+ struct property *head, *tail;
+
+ head = tail = of_pdt_build_one_prop(node, NULL,
+ ".node", &node, sizeof(node));
+
+ tail->next = of_pdt_build_one_prop(node, NULL, NULL, NULL, 0);
+ tail = tail->next;
+ while(tail) {
+ tail->next = of_pdt_build_one_prop(node, tail->name,
+ NULL, NULL, 0);
+ tail = tail->next;
+ }
+
+ return head;
+}
+
+static char * __init of_pdt_get_one_property(phandle node, const char *name)
+{
+ char *buf = "<NULL>";
+ int len;
+
+ len = of_pdt_prom_ops->getproplen(node, name);
+ if (len > 0) {
+ buf = prom_early_alloc(len);
+ len = of_pdt_prom_ops->getproperty(node, name, buf, len);
+ }
+
+ return buf;
+}
+
+static char * __init of_pdt_try_pkg2path(phandle node)
+{
+ char *res, *buf = NULL;
+ int len;
+
+ if (!of_pdt_prom_ops->pkg2path)
+ return NULL;
+
+ if (of_pdt_prom_ops->pkg2path(node, buf, 0, &len))
+ return NULL;
+ buf = prom_early_alloc(len + 1);
+ if (of_pdt_prom_ops->pkg2path(node, buf, len, &len)) {
+ pr_err("%s: package-to-path failed\n", __func__);
+ return NULL;
+ }
+
+ res = strrchr(buf, '/');
+ if (!res) {
+ pr_err("%s: couldn't find / in %s\n", __func__, buf);
+ return NULL;
+ }
+ return res+1;
+}
+
+/*
+ * When fetching the node's name, first try using package-to-path; if
+ * that fails (either because the arch hasn't supplied a PROM callback,
+ * or some other random failure), fall back to just looking at the node's
+ * 'name' property.
+ */
+static char * __init of_pdt_build_name(phandle node)
+{
+ char *buf;
+
+ buf = of_pdt_try_pkg2path(node);
+ if (!buf)
+ buf = of_pdt_get_one_property(node, "name");
+
+ return buf;
+}
+
+static struct device_node * __init of_pdt_create_node(phandle node,
+ struct device_node *parent)
+{
+ struct device_node *dp;
+
+ if (!node)
+ return NULL;
+
+ dp = prom_early_alloc(sizeof(*dp));
+ of_pdt_incr_unique_id(dp);
+ dp->parent = parent;
+
+ kref_init(&dp->kref);
+
+ dp->name = of_pdt_build_name(node);
+ dp->type = of_pdt_get_one_property(node, "device_type");
+ dp->phandle = node;
+
+ dp->properties = of_pdt_build_prop_list(node);
+
+ irq_trans_init(dp);
+
+ return dp;
+}
+
+static char * __init of_pdt_build_full_name(struct device_node *dp)
+{
+ int len, ourlen, plen;
+ char *n;
+
+ plen = strlen(dp->parent->full_name);
+ ourlen = strlen(of_pdt_node_name(dp));
+ len = ourlen + plen + 2;
+
+ n = prom_early_alloc(len);
+ strcpy(n, dp->parent->full_name);
+ if (!of_node_is_root(dp->parent)) {
+ strcpy(n + plen, "/");
+ plen++;
+ }
+ strcpy(n + plen, of_pdt_node_name(dp));
+
+ return n;
+}
+
+static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
+ phandle node,
+ struct device_node ***nextp)
+{
+ struct device_node *ret = NULL, *prev_sibling = NULL;
+ struct device_node *dp;
+
+ while (1) {
+ dp = of_pdt_create_node(node, parent);
+ if (!dp)
+ break;
+
+ if (prev_sibling)
+ prev_sibling->sibling = dp;
+
+ if (!ret)
+ ret = dp;
+ prev_sibling = dp;
+
+ *(*nextp) = dp;
+ *nextp = &dp->allnext;
+
+#if defined(CONFIG_SPARC)
+ dp->path_component_name = build_path_component(dp);
+#endif
+ dp->full_name = of_pdt_build_full_name(dp);
+
+ dp->child = of_pdt_build_tree(dp,
+ of_pdt_prom_ops->getchild(node), nextp);
+
+ if (of_pdt_build_more)
+ of_pdt_build_more(dp, nextp);
+
+ node = of_pdt_prom_ops->getsibling(node);
+ }
+
+ return ret;
+}
+
+void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
+{
+ struct device_node **nextp;
+
+ BUG_ON(!ops);
+ of_pdt_prom_ops = ops;
+
+ allnodes = of_pdt_create_node(root_node, NULL);
+#if defined(CONFIG_SPARC)
+ allnodes->path_component_name = "";
+#endif
+ allnodes->full_name = "/";
+
+ nextp = &allnodes->allnext;
+ allnodes->child = of_pdt_build_tree(allnodes,
+ of_pdt_prom_ops->getchild(allnodes->phandle), &nextp);
+}
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index bb72223c22ae..5b4a07f1220e 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -584,34 +584,33 @@ struct platform_device *of_device_alloc(struct device_node *np,
struct device *parent)
{
struct platform_device *dev;
- int rc, i, num_reg = 0, num_irq = 0;
+ int rc, i, num_reg = 0, num_irq;
struct resource *res, temp_res;
- /* First count how many resources are needed */
- while (of_address_to_resource(np, num_reg, &temp_res) == 0)
- num_reg++;
- while (of_irq_to_resource(np, num_irq, &temp_res) != NO_IRQ)
- num_irq++;
-
- /* Allocate memory for both the struct device and the resource table */
- dev = kzalloc(sizeof(*dev) + (sizeof(*res) * (num_reg + num_irq)),
- GFP_KERNEL);
+ dev = platform_device_alloc("", -1);
if (!dev)
return NULL;
- res = (struct resource *) &dev[1];
+
+ /* count the io and irq resources */
+ while (of_address_to_resource(np, num_reg, &temp_res) == 0)
+ num_reg++;
+ num_irq = of_irq_count(np);
/* Populate the resource table */
if (num_irq || num_reg) {
+ res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
+ if (!res) {
+ platform_device_put(dev);
+ return NULL;
+ }
+
dev->num_resources = num_reg + num_irq;
dev->resource = res;
for (i = 0; i < num_reg; i++, res++) {
rc = of_address_to_resource(np, i, res);
WARN_ON(rc);
}
- for (i = 0; i < num_irq; i++, res++) {
- rc = of_irq_to_resource(np, i, res);
- WARN_ON(rc == NO_IRQ);
- }
+ WARN_ON(of_irq_to_resource_table(np, res, num_irq) != num_irq);
}
dev->dev.of_node = of_node_get(np);
@@ -619,7 +618,6 @@ struct platform_device *of_device_alloc(struct device_node *np,
dev->dev.dma_mask = &dev->archdata.dma_mask;
#endif
dev->dev.parent = parent;
- dev->dev.release = of_release_dev;
if (bus_id)
dev_set_name(&dev->dev, "%s", bus_id);
@@ -657,8 +655,8 @@ struct platform_device *of_platform_device_create(struct device_node *np,
* to do such, possibly using a device notifier
*/
- if (of_device_register(dev) != 0) {
- of_device_free(dev);
+ if (of_device_add(dev) != 0) {
+ platform_device_put(dev);
return NULL;
}
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
index 95f711b251ad..449de59bf35b 100644
--- a/drivers/oprofile/oprofilefs.c
+++ b/drivers/oprofile/oprofilefs.c
@@ -28,6 +28,7 @@ static struct inode *oprofilefs_get_inode(struct super_block *sb, int mode)
struct inode *inode = new_inode(sb);
if (inode) {
+ inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
}
diff --git a/drivers/parisc/README.dino b/drivers/parisc/README.dino
index 097324f34bbe..1627426996c1 100644
--- a/drivers/parisc/README.dino
+++ b/drivers/parisc/README.dino
@@ -10,8 +10,7 @@
** PCI bus. HP-supplied graphics cards that utilize the PCI bus are
** not affected."
**
-** REVISIT: "go/pci_defect" link below is stale.
-** HP Internal can use <http://hpfcdma.fc.hp.com:80/Dino/>
+** http://h20000.www2.hp.com/bizsupport/TechSupport/Home.jsp?locale=en_US&prodTypeId=12454&prodSeriesId=44443
**
** Product First Good Serial Number
** C200/C240 (US) US67350000
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index c542c7bb7454..d9f51485beee 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -296,10 +296,9 @@ static struct pci_port_ops dino_port_ops = {
.outl = dino_out32
};
-static void dino_disable_irq(unsigned int irq)
+static void dino_mask_irq(unsigned int irq)
{
- struct irq_desc *desc = irq_to_desc(irq);
- struct dino_device *dino_dev = desc->chip_data;
+ struct dino_device *dino_dev = get_irq_chip_data(irq);
int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, irq);
@@ -309,10 +308,9 @@ static void dino_disable_irq(unsigned int irq)
__raw_writel(dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR);
}
-static void dino_enable_irq(unsigned int irq)
+static void dino_unmask_irq(unsigned int irq)
{
- struct irq_desc *desc = irq_to_desc(irq);
- struct dino_device *dino_dev = desc->chip_data;
+ struct dino_device *dino_dev = get_irq_chip_data(irq);
int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
u32 tmp;
@@ -347,20 +345,11 @@ static void dino_enable_irq(unsigned int irq)
}
}
-static unsigned int dino_startup_irq(unsigned int irq)
-{
- dino_enable_irq(irq);
- return 0;
-}
-
static struct irq_chip dino_interrupt_type = {
- .name = "GSC-PCI",
- .startup = dino_startup_irq,
- .shutdown = dino_disable_irq,
- .enable = dino_enable_irq,
- .disable = dino_disable_irq,
- .ack = no_ack_irq,
- .end = no_end_irq,
+ .name = "GSC-PCI",
+ .unmask = dino_unmask_irq,
+ .mask = dino_mask_irq,
+ .ack = no_ack_irq,
};
@@ -391,7 +380,7 @@ ilr_again:
int irq = dino_dev->global_irq[local_irq];
DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n",
__func__, irq, intr_dev, mask);
- __do_IRQ(irq);
+ generic_handle_irq(irq);
mask &= ~(1 << local_irq);
} while (mask);
diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c
index 46f503fb7fc5..1211974f55aa 100644
--- a/drivers/parisc/eisa.c
+++ b/drivers/parisc/eisa.c
@@ -144,7 +144,7 @@ static unsigned int eisa_irq_level __read_mostly; /* default to edge triggered *
/* called by free irq */
-static void eisa_disable_irq(unsigned int irq)
+static void eisa_mask_irq(unsigned int irq)
{
unsigned long flags;
@@ -164,7 +164,7 @@ static void eisa_disable_irq(unsigned int irq)
}
/* called by request irq */
-static void eisa_enable_irq(unsigned int irq)
+static void eisa_unmask_irq(unsigned int irq)
{
unsigned long flags;
EISA_DBG("enable irq %d\n", irq);
@@ -182,20 +182,11 @@ static void eisa_enable_irq(unsigned int irq)
EISA_DBG("pic1 mask %02x\n", eisa_in8(0xa1));
}
-static unsigned int eisa_startup_irq(unsigned int irq)
-{
- eisa_enable_irq(irq);
- return 0;
-}
-
static struct irq_chip eisa_interrupt_type = {
- .name = "EISA",
- .startup = eisa_startup_irq,
- .shutdown = eisa_disable_irq,
- .enable = eisa_enable_irq,
- .disable = eisa_disable_irq,
- .ack = no_ack_irq,
- .end = no_end_irq,
+ .name = "EISA",
+ .unmask = eisa_unmask_irq,
+ .mask = eisa_mask_irq,
+ .ack = no_ack_irq,
};
static irqreturn_t eisa_irq(int wax_irq, void *intr_dev)
@@ -233,7 +224,7 @@ static irqreturn_t eisa_irq(int wax_irq, void *intr_dev)
}
spin_unlock_irqrestore(&eisa_irq_lock, flags);
- __do_IRQ(irq);
+ generic_handle_irq(irq);
spin_lock_irqsave(&eisa_irq_lock, flags);
/* unmask */
@@ -346,10 +337,10 @@ static int __init eisa_probe(struct parisc_device *dev)
}
/* Reserve IRQ2 */
- irq_to_desc(2)->action = &irq2_action;
-
+ setup_irq(2, &irq2_action);
for (i = 0; i < 16; i++) {
- irq_to_desc(i)->chip = &eisa_interrupt_type;
+ set_irq_chip_and_handler(i, &eisa_interrupt_type,
+ handle_level_irq);
}
EISA_bus = 1;
diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c
index 20a1bce1a031..e605298e3aee 100644
--- a/drivers/parisc/gsc.c
+++ b/drivers/parisc/gsc.c
@@ -86,7 +86,7 @@ irqreturn_t gsc_asic_intr(int gsc_asic_irq, void *dev)
do {
int local_irq = __ffs(irr);
unsigned int irq = gsc_asic->global_irq[local_irq];
- __do_IRQ(irq);
+ generic_handle_irq(irq);
irr &= ~(1 << local_irq);
} while (irr);
@@ -105,10 +105,9 @@ int gsc_find_local_irq(unsigned int irq, int *global_irqs, int limit)
return NO_IRQ;
}
-static void gsc_asic_disable_irq(unsigned int irq)
+static void gsc_asic_mask_irq(unsigned int irq)
{
- struct irq_desc *desc = irq_to_desc(irq);
- struct gsc_asic *irq_dev = desc->chip_data;
+ struct gsc_asic *irq_dev = get_irq_chip_data(irq);
int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
u32 imr;
@@ -121,10 +120,9 @@ static void gsc_asic_disable_irq(unsigned int irq)
gsc_writel(imr, irq_dev->hpa + OFFSET_IMR);
}
-static void gsc_asic_enable_irq(unsigned int irq)
+static void gsc_asic_unmask_irq(unsigned int irq)
{
- struct irq_desc *desc = irq_to_desc(irq);
- struct gsc_asic *irq_dev = desc->chip_data;
+ struct gsc_asic *irq_dev = get_irq_chip_data(irq);
int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
u32 imr;
@@ -141,33 +139,23 @@ static void gsc_asic_enable_irq(unsigned int irq)
*/
}
-static unsigned int gsc_asic_startup_irq(unsigned int irq)
-{
- gsc_asic_enable_irq(irq);
- return 0;
-}
-
static struct irq_chip gsc_asic_interrupt_type = {
- .name = "GSC-ASIC",
- .startup = gsc_asic_startup_irq,
- .shutdown = gsc_asic_disable_irq,
- .enable = gsc_asic_enable_irq,
- .disable = gsc_asic_disable_irq,
- .ack = no_ack_irq,
- .end = no_end_irq,
+ .name = "GSC-ASIC",
+ .unmask = gsc_asic_unmask_irq,
+ .mask = gsc_asic_mask_irq,
+ .ack = no_ack_irq,
};
int gsc_assign_irq(struct irq_chip *type, void *data)
{
static int irq = GSC_IRQ_BASE;
- struct irq_desc *desc;
if (irq > GSC_IRQ_MAX)
return NO_IRQ;
- desc = irq_to_desc(irq);
- desc->chip = type;
- desc->chip_data = data;
+ set_irq_chip_and_handler(irq, type, handle_level_irq);
+ set_irq_chip_data(irq, data);
+
return irq++;
}
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index c76836727cae..a3120a09c43d 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -615,17 +615,10 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
}
-static struct vector_info *iosapic_get_vector(unsigned int irq)
-{
- struct irq_desc *desc = irq_to_desc(irq);
-
- return desc->chip_data;
-}
-
-static void iosapic_disable_irq(unsigned int irq)
+static void iosapic_mask_irq(unsigned int irq)
{
unsigned long flags;
- struct vector_info *vi = iosapic_get_vector(irq);
+ struct vector_info *vi = get_irq_chip_data(irq);
u32 d0, d1;
spin_lock_irqsave(&iosapic_lock, flags);
@@ -635,9 +628,9 @@ static void iosapic_disable_irq(unsigned int irq)
spin_unlock_irqrestore(&iosapic_lock, flags);
}
-static void iosapic_enable_irq(unsigned int irq)
+static void iosapic_unmask_irq(unsigned int irq)
{
- struct vector_info *vi = iosapic_get_vector(irq);
+ struct vector_info *vi = get_irq_chip_data(irq);
u32 d0, d1;
/* data is initialized by fixup_irq */
@@ -676,36 +669,14 @@ printk("\n");
DBG(KERN_DEBUG "enable_irq(%d): eoi(%p, 0x%x)\n", irq,
vi->eoi_addr, vi->eoi_data);
iosapic_eoi(vi->eoi_addr, vi->eoi_data);
-}
-
-/*
- * PARISC only supports PCI devices below I/O SAPIC.
- * PCI only supports level triggered in order to share IRQ lines.
- * ergo I/O SAPIC must always issue EOI on parisc.
- *
- * i386/ia64 support ISA devices and have to deal with
- * edge-triggered interrupts too.
- */
-static void iosapic_end_irq(unsigned int irq)
-{
- struct vector_info *vi = iosapic_get_vector(irq);
- DBG(KERN_DEBUG "end_irq(%d): eoi(%p, 0x%x)\n", irq,
- vi->eoi_addr, vi->eoi_data);
- iosapic_eoi(vi->eoi_addr, vi->eoi_data);
- cpu_end_irq(irq);
-}
-
-static unsigned int iosapic_startup_irq(unsigned int irq)
-{
- iosapic_enable_irq(irq);
- return 0;
+ cpu_eoi_irq(irq);
}
#ifdef CONFIG_SMP
static int iosapic_set_affinity_irq(unsigned int irq,
const struct cpumask *dest)
{
- struct vector_info *vi = iosapic_get_vector(irq);
+ struct vector_info *vi = get_irq_chip_data(irq);
u32 d0, d1, dummy_d0;
unsigned long flags;
int dest_cpu;
@@ -730,13 +701,10 @@ static int iosapic_set_affinity_irq(unsigned int irq,
#endif
static struct irq_chip iosapic_interrupt_type = {
- .name = "IO-SAPIC-level",
- .startup = iosapic_startup_irq,
- .shutdown = iosapic_disable_irq,
- .enable = iosapic_enable_irq,
- .disable = iosapic_disable_irq,
- .ack = cpu_ack_irq,
- .end = iosapic_end_irq,
+ .name = "IO-SAPIC-level",
+ .unmask = iosapic_unmask_irq,
+ .mask = iosapic_mask_irq,
+ .ack = cpu_ack_irq,
#ifdef CONFIG_SMP
.set_affinity = iosapic_set_affinity_irq,
#endif
@@ -891,8 +859,8 @@ void *iosapic_register(unsigned long hpa)
isi->isi_version = iosapic_rd_version(isi);
isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1;
- vip = isi->isi_vector = (struct vector_info *)
- kzalloc(sizeof(struct vector_info) * isi->isi_num_vectors, GFP_KERNEL);
+ vip = isi->isi_vector = kcalloc(isi->isi_num_vectors,
+ sizeof(struct vector_info), GFP_KERNEL);
if (vip == NULL) {
kfree(isi);
return NULL;
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index c5c14dd3734f..2350e8a86eef 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -346,8 +346,8 @@ static __inline__ int led_get_net_activity(void)
#ifndef CONFIG_NET
return 0;
#else
- static unsigned long rx_total_last, tx_total_last;
- unsigned long rx_total, tx_total;
+ static u64 rx_total_last, tx_total_last;
+ u64 rx_total, tx_total;
struct net_device *dev;
int retval;
@@ -356,7 +356,7 @@ static __inline__ int led_get_net_activity(void)
/* we are running as a workqueue task, so we can use an RCU lookup */
rcu_read_lock();
for_each_netdev_rcu(&init_net, dev) {
- const struct net_device_stats *stats;
+ const struct rtnl_link_stats64 *stats;
struct rtnl_link_stats64 temp;
struct in_device *in_dev = __in_dev_get_rcu(dev);
if (!in_dev || !in_dev->ifa_list)
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index f7806d81f1e0..0846dafdfff1 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -139,7 +139,7 @@ superio_interrupt(int parent_irq, void *devp)
}
/* Call the appropriate device's interrupt */
- __do_IRQ(local_irq);
+ generic_handle_irq(local_irq);
/* set EOI - forces a new interrupt if a lower priority device
* still needs service.
@@ -286,7 +286,7 @@ superio_init(struct pci_dev *pcidev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_LIO, superio_init);
-static void superio_disable_irq(unsigned int irq)
+static void superio_mask_irq(unsigned int irq)
{
u8 r8;
@@ -303,7 +303,7 @@ static void superio_disable_irq(unsigned int irq)
outb (r8,IC_PIC1+1);
}
-static void superio_enable_irq(unsigned int irq)
+static void superio_unmask_irq(unsigned int irq)
{
u8 r8;
@@ -319,20 +319,11 @@ static void superio_enable_irq(unsigned int irq)
outb (r8,IC_PIC1+1);
}
-static unsigned int superio_startup_irq(unsigned int irq)
-{
- superio_enable_irq(irq);
- return 0;
-}
-
static struct irq_chip superio_interrupt_type = {
- .name = SUPERIO,
- .startup = superio_startup_irq,
- .shutdown = superio_disable_irq,
- .enable = superio_enable_irq,
- .disable = superio_disable_irq,
+ .name = SUPERIO,
+ .unmask = superio_unmask_irq,
+ .mask = superio_mask_irq,
.ack = no_ack_irq,
- .end = no_end_irq,
};
#ifdef DEBUG_SUPERIO_INIT
@@ -363,9 +354,7 @@ int superio_fixup_irq(struct pci_dev *pcidev)
#endif
for (i = 0; i < 16; i++) {
- struct irq_desc *desc = irq_to_desc(i);
-
- desc->chip = &superio_interrupt_type;
+ set_irq_chip_and_handler(i, &superio_interrupt_type, handle_level_irq);
}
/*
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 0950fa40684f..8d62fb76cd41 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -2599,7 +2599,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq,
printk(KERN_INFO "parport_pc: ITE8873 found (1S)\n");
return 0;
case 0x8:
- DPRINTK(KERN_DEBUG "parport_pc: ITE8874 found (2S)\n");
+ printk(KERN_INFO "parport_pc: ITE8874 found (2S)\n");
return 0;
default:
printk(KERN_INFO "parport_pc: unknown ITE887x\n");
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 01f0306525a5..895136f13edc 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -212,8 +212,6 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,
#endif /* HAVE_PCI_MMAP */
int ret = 0;
- lock_kernel();
-
switch (cmd) {
case PCIIOC_CONTROLLER:
ret = pci_domain_nr(dev->bus);
@@ -242,7 +240,6 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,
break;
};
- unlock_kernel();
return ret;
}
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 857ae01734a6..cc96c7142dac 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -226,6 +226,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quir
* VIA Apollo KT133 needs PCI latency patch
* Made according to a windows driver based patch by George E. Breese
* see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm
+ * and http://www.georgebreese.com/net/software/#PCI
* Also see http://www.au-ja.org/review-kt133a-1-en.phtml for
* the info on which Mr Breese based his work.
*
@@ -1016,7 +1017,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge)
/*
* Common misconfiguration of the MediaGX/Geode PCI master that will
* reduce PCI bandwidth from 70MB/s to 25MB/s. See the GXM/GXLV/GX1
- * datasheets found at http://www.national.com/ds/GX for info on what
+ * datasheets found at http://www.national.com/analog for info on what
* these bits do. <christer@weinigel.se>
*/
static void quirk_mediagx_master(struct pci_dev *dev)
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 408dbaa080a1..9dc565c615bd 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -1072,7 +1072,7 @@ static void yenta_config_init(struct yenta_socket *socket)
* invisible during PCI scans because of a misconfigured subordinate number
* of the parent brige - some BIOSes seem to be too lazy to set it right.
* Does the fixup carefully by checking how far it can go without conflicts.
- * See http\://bugzilla.kernel.org/show_bug.cgi?id=2944 for more information.
+ * See http://bugzilla.kernel.org/show_bug.cgi?id=2944 for more information.
*/
static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
{
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index cff7cc2c1f02..faec777b1ed4 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -92,6 +92,7 @@ config DELL_WMI
tristate "Dell WMI extras"
depends on ACPI_WMI
depends on INPUT
+ select INPUT_SPARSEKMAP
---help---
Say Y here if you want to support WMI-based hotkeys on Dell laptops.
@@ -140,6 +141,7 @@ config HP_WMI
depends on ACPI_WMI
depends on INPUT
depends on RFKILL || RFKILL = n
+ select INPUT_SPARSEKMAP
help
Say Y here if you want to support WMI-based hotkeys on HP laptops and
to read data from WMI such as docking or ambient light sensor state.
@@ -171,6 +173,7 @@ config PANASONIC_LAPTOP
tristate "Panasonic Laptop Extras"
depends on INPUT && ACPI
depends on BACKLIGHT_CLASS_DEVICE
+ select INPUT_SPARSEKMAP
---help---
This driver adds support for access to backlight control and hotkeys
on Panasonic Let's Note laptops.
@@ -219,8 +222,8 @@ config SONYPI_COMPAT
---help---
Build the sonypi driver compatibility code into the sony-laptop driver.
-config IDEAPAD_ACPI
- tristate "Lenovo IdeaPad ACPI Laptop Extras"
+config IDEAPAD_LAPTOP
+ tristate "Lenovo IdeaPad Laptop Extras"
depends on ACPI
depends on RFKILL
help
@@ -365,6 +368,26 @@ config THINKPAD_ACPI_HOTKEY_POLL
If you are not sure, say Y here. The driver enables polling only if
it is strictly necessary to do so.
+config SENSORS_HDAPS
+ tristate "Thinkpad Hard Drive Active Protection System (hdaps)"
+ depends on INPUT && X86
+ select INPUT_POLLDEV
+ default n
+ help
+ This driver provides support for the IBM Hard Drive Active Protection
+ System (hdaps), which provides an accelerometer and other misc. data.
+ ThinkPads starting with the R50, T41, and X40 are supported. The
+ accelerometer data is readable via sysfs.
+
+ This driver also provides an absolute input class device, allowing
+ the laptop to act as a pinball machine-esque joystick.
+
+ If your ThinkPad is not recognized by the driver, please update to latest
+ BIOS. This is especially the case for some R52 ThinkPads.
+
+ Say Y here if you have an applicable laptop and want to experience
+ the awesome power of hdaps.
+
config INTEL_MENLOW
tristate "Thermal Management driver for Intel menlow platform"
depends on ACPI_THERMAL
@@ -478,6 +501,7 @@ config TOPSTAR_LAPTOP
tristate "Topstar Laptop Extras"
depends on ACPI
depends on INPUT
+ select INPUT_SPARSEKMAP
---help---
This driver adds support for hotkeys found on Topstar laptops.
@@ -492,6 +516,7 @@ config ACPI_TOSHIBA
depends on INPUT
depends on RFKILL || RFKILL = n
select INPUT_POLLDEV
+ select INPUT_SPARSEKMAP
---help---
This driver adds support for access to certain system settings
on "legacy free" Toshiba laptops. These laptops can be recognized by
@@ -590,4 +615,28 @@ config INTEL_IPS
functionality. If in doubt, say Y here; it will only load on
supported platforms.
+config IBM_RTL
+ tristate "Device driver to enable PRTL support"
+ depends on X86 && PCI
+ ---help---
+ Enable support for IBM Premium Real Time Mode (PRTM).
+ This module will allow you the enter and exit PRTM in the BIOS via
+ sysfs on platforms that support this feature. System in PRTM will
+ not receive CPU-generated SMIs for recoverable errors. Use of this
+ feature without proper support may void your hardware warranty.
+
+ If the proper BIOS support is found the driver will load and create
+ /sys/devices/system/ibm_rtl/. The "state" variable will indicate
+ whether or not the BIOS is in PRTM.
+ state = 0 (BIOS SMIs on)
+ state = 1 (BIOS SMIs off)
+
+config XO1_RFKILL
+ tristate "OLPC XO-1 software RF kill switch"
+ depends on OLPC
+ depends on RFKILL
+ ---help---
+ Support for enabling/disabling the WLAN interface on the OLPC XO-1
+ laptop.
+
endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 85fb2b84f57e..9950ccc940b5 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -15,8 +15,9 @@ obj-$(CONFIG_ACERHDF) += acerhdf.o
obj-$(CONFIG_HP_WMI) += hp-wmi.o
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
-obj-$(CONFIG_IDEAPAD_ACPI) += ideapad_acpi.o
+obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
+obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
@@ -30,4 +31,5 @@ obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o
obj-$(CONFIG_INTEL_IPS) += intel_ips.o
obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o
-
+obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o
+obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 2badee2fdeed..c8c65375bfe2 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -1314,7 +1314,7 @@ static int __init acer_wmi_init(void)
AMW0_find_mailled();
if (!interface) {
- printk(ACER_ERR "No or unsupported WMI interface, unable to "
+ printk(ACER_INFO "No or unsupported WMI interface, unable to "
"load\n");
return -ENODEV;
}
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index b756e07d41b4..60a5a5c6b50a 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -236,7 +236,6 @@ struct asus_laptop {
u8 light_level; /* light sensor level */
u8 light_switch; /* light sensor switch value */
u16 event_count[128]; /* count for each event TODO make this better */
- u16 *keycode_map;
};
static const struct key_entry asus_keymap[] = {
@@ -278,6 +277,7 @@ static const struct key_entry asus_keymap[] = {
{KE_KEY, 0x99, { KEY_PHONE } },
{KE_KEY, 0xc4, { KEY_KBDILLUMUP } },
{KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } },
+ {KE_KEY, 0xb5, { KEY_CALC } },
{KE_END, 0},
};
@@ -639,29 +639,29 @@ static int asus_backlight_notify(struct asus_laptop *asus)
static int asus_backlight_init(struct asus_laptop *asus)
{
struct backlight_device *bd;
- struct device *dev = &asus->platform_device->dev;
struct backlight_properties props;
- if (!acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) &&
- !acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) &&
- lcd_switch_handle) {
- memset(&props, 0, sizeof(struct backlight_properties));
- props.max_brightness = 15;
-
- bd = backlight_device_register(ASUS_LAPTOP_FILE, dev,
- asus, &asusbl_ops, &props);
- if (IS_ERR(bd)) {
- pr_err("Could not register asus backlight device\n");
- asus->backlight_device = NULL;
- return PTR_ERR(bd);
- }
+ if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) ||
+ acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) ||
+ !lcd_switch_handle)
+ return 0;
- asus->backlight_device = bd;
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.max_brightness = 15;
- bd->props.power = FB_BLANK_UNBLANK;
- bd->props.brightness = asus_read_brightness(bd);
- backlight_update_status(bd);
+ bd = backlight_device_register(ASUS_LAPTOP_FILE,
+ &asus->platform_device->dev, asus,
+ &asusbl_ops, &props);
+ if (IS_ERR(bd)) {
+ pr_err("Could not register asus backlight device\n");
+ asus->backlight_device = NULL;
+ return PTR_ERR(bd);
}
+
+ asus->backlight_device = bd;
+ bd->props.brightness = asus_read_brightness(bd);
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
return 0;
}
@@ -1065,9 +1065,9 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
*/
static int asus_gps_rfkill_set(void *data, bool blocked)
{
- acpi_handle handle = data;
+ struct asus_laptop *asus = data;
- return asus_gps_switch(handle, !blocked);
+ return asus_gps_switch(asus, !blocked);
}
static const struct rfkill_ops asus_gps_rfkill_ops = {
@@ -1094,7 +1094,7 @@ static int asus_rfkill_init(struct asus_laptop *asus)
asus->gps_rfkill = rfkill_alloc("asus-gps", &asus->platform_device->dev,
RFKILL_TYPE_GPS,
- &asus_gps_rfkill_ops, NULL);
+ &asus_gps_rfkill_ops, asus);
if (!asus->gps_rfkill)
return -EINVAL;
@@ -1130,7 +1130,6 @@ static int asus_input_init(struct asus_laptop *asus)
input->phys = ASUS_LAPTOP_FILE "/input0";
input->id.bustype = BUS_HOST;
input->dev.parent = &asus->platform_device->dev;
- input_set_drvdata(input, asus);
error = sparse_keymap_setup(input, asus_keymap, NULL);
if (error) {
@@ -1159,6 +1158,7 @@ static void asus_input_exit(struct asus_laptop *asus)
sparse_keymap_free(asus->inputdev);
input_unregister_device(asus->inputdev);
}
+ asus->inputdev = NULL;
}
/*
@@ -1200,111 +1200,100 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
static DEVICE_ATTR(infos, S_IRUGO, show_infos, NULL);
static DEVICE_ATTR(wlan, S_IRUGO | S_IWUSR, show_wlan, store_wlan);
-static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR, show_bluetooth,
- store_bluetooth);
+static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR,
+ show_bluetooth, store_bluetooth);
static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp);
static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw);
static DEVICE_ATTR(gps, S_IRUGO | S_IWUSR, show_gps, store_gps);
-static void asus_sysfs_exit(struct asus_laptop *asus)
-{
- struct platform_device *device = asus->platform_device;
-
- device_remove_file(&device->dev, &dev_attr_infos);
- device_remove_file(&device->dev, &dev_attr_wlan);
- device_remove_file(&device->dev, &dev_attr_bluetooth);
- device_remove_file(&device->dev, &dev_attr_display);
- device_remove_file(&device->dev, &dev_attr_ledd);
- device_remove_file(&device->dev, &dev_attr_ls_switch);
- device_remove_file(&device->dev, &dev_attr_ls_level);
- device_remove_file(&device->dev, &dev_attr_gps);
-}
+static struct attribute *asus_attributes[] = {
+ &dev_attr_infos.attr,
+ &dev_attr_wlan.attr,
+ &dev_attr_bluetooth.attr,
+ &dev_attr_display.attr,
+ &dev_attr_ledd.attr,
+ &dev_attr_ls_level.attr,
+ &dev_attr_ls_switch.attr,
+ &dev_attr_gps.attr,
+ NULL
+};
-static int asus_sysfs_init(struct asus_laptop *asus)
+static mode_t asus_sysfs_is_visible(struct kobject *kobj,
+ struct attribute *attr,
+ int idx)
{
- struct platform_device *device = asus->platform_device;
- int err;
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct asus_laptop *asus = platform_get_drvdata(pdev);
+ acpi_handle handle = asus->handle;
+ bool supported;
- err = device_create_file(&device->dev, &dev_attr_infos);
- if (err)
- return err;
+ if (attr == &dev_attr_wlan.attr) {
+ supported = !acpi_check_handle(handle, METHOD_WLAN, NULL);
- if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL)) {
- err = device_create_file(&device->dev, &dev_attr_wlan);
- if (err)
- return err;
- }
+ } else if (attr == &dev_attr_bluetooth.attr) {
+ supported = !acpi_check_handle(handle, METHOD_BLUETOOTH, NULL);
- if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL)) {
- err = device_create_file(&device->dev, &dev_attr_bluetooth);
- if (err)
- return err;
- }
+ } else if (attr == &dev_attr_display.attr) {
+ supported = !acpi_check_handle(handle, METHOD_SWITCH_DISPLAY, NULL);
- if (!acpi_check_handle(asus->handle, METHOD_SWITCH_DISPLAY, NULL)) {
- err = device_create_file(&device->dev, &dev_attr_display);
- if (err)
- return err;
- }
+ } else if (attr == &dev_attr_ledd.attr) {
+ supported = !acpi_check_handle(handle, METHOD_LEDD, NULL);
- if (!acpi_check_handle(asus->handle, METHOD_LEDD, NULL)) {
- err = device_create_file(&device->dev, &dev_attr_ledd);
- if (err)
- return err;
- }
-
- if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) &&
- !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) {
- err = device_create_file(&device->dev, &dev_attr_ls_switch);
- if (err)
- return err;
- err = device_create_file(&device->dev, &dev_attr_ls_level);
- if (err)
- return err;
- }
+ } else if (attr == &dev_attr_ls_switch.attr ||
+ attr == &dev_attr_ls_level.attr) {
+ supported = !acpi_check_handle(handle, METHOD_ALS_CONTROL, NULL) &&
+ !acpi_check_handle(handle, METHOD_ALS_LEVEL, NULL);
- if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) &&
- !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) &&
- !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) {
- err = device_create_file(&device->dev, &dev_attr_gps);
- if (err)
- return err;
+ } else if (attr == &dev_attr_gps.attr) {
+ supported = !acpi_check_handle(handle, METHOD_GPS_ON, NULL) &&
+ !acpi_check_handle(handle, METHOD_GPS_OFF, NULL) &&
+ !acpi_check_handle(handle, METHOD_GPS_STATUS, NULL);
+ } else {
+ supported = true;
}
- return err;
+ return supported ? attr->mode : 0;
}
+
+static const struct attribute_group asus_attr_group = {
+ .is_visible = asus_sysfs_is_visible,
+ .attrs = asus_attributes,
+};
+
static int asus_platform_init(struct asus_laptop *asus)
{
- int err;
+ int result;
asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1);
if (!asus->platform_device)
return -ENOMEM;
platform_set_drvdata(asus->platform_device, asus);
- err = platform_device_add(asus->platform_device);
- if (err)
+ result = platform_device_add(asus->platform_device);
+ if (result)
goto fail_platform_device;
- err = asus_sysfs_init(asus);
- if (err)
+ result = sysfs_create_group(&asus->platform_device->dev.kobj,
+ &asus_attr_group);
+ if (result)
goto fail_sysfs;
+
return 0;
fail_sysfs:
- asus_sysfs_exit(asus);
platform_device_del(asus->platform_device);
fail_platform_device:
platform_device_put(asus->platform_device);
- return err;
+ return result;
}
static void asus_platform_exit(struct asus_laptop *asus)
{
- asus_sysfs_exit(asus);
+ sysfs_remove_group(&asus->platform_device->dev.kobj, &asus_attr_group);
platform_device_unregister(asus->platform_device);
}
@@ -1428,8 +1417,6 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
return AE_OK;
}
-static bool asus_device_present;
-
static int __devinit asus_acpi_init(struct asus_laptop *asus)
{
int result = 0;
@@ -1474,6 +1461,8 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
return result;
}
+static bool asus_device_present;
+
static int __devinit asus_acpi_add(struct acpi_device *device)
{
struct asus_laptop *asus;
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index 4413975912e0..cf8a89a0d8f5 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -25,6 +25,8 @@
#include <linux/mm.h>
#include <linux/i8042.h>
#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include "../../firmware/dcdbas.h"
#define BRIGHTNESS_TOKEN 0x7d
@@ -325,6 +327,75 @@ static const struct rfkill_ops dell_rfkill_ops = {
.query = dell_rfkill_query,
};
+static struct dentry *dell_laptop_dir;
+
+static int dell_debugfs_show(struct seq_file *s, void *data)
+{
+ int status;
+
+ get_buffer();
+ dell_send_request(buffer, 17, 11);
+ status = buffer->output[1];
+ release_buffer();
+
+ seq_printf(s, "status:\t0x%X\n", status);
+ seq_printf(s, "Bit 0 : Hardware switch supported: %lu\n",
+ status & BIT(0));
+ seq_printf(s, "Bit 1 : Wifi locator supported: %lu\n",
+ (status & BIT(1)) >> 1);
+ seq_printf(s, "Bit 2 : Wifi is supported: %lu\n",
+ (status & BIT(2)) >> 2);
+ seq_printf(s, "Bit 3 : Bluetooth is supported: %lu\n",
+ (status & BIT(3)) >> 3);
+ seq_printf(s, "Bit 4 : WWAN is supported: %lu\n",
+ (status & BIT(4)) >> 4);
+ seq_printf(s, "Bit 5 : Wireless keyboard supported: %lu\n",
+ (status & BIT(5)) >> 5);
+ seq_printf(s, "Bit 8 : Wifi is installed: %lu\n",
+ (status & BIT(8)) >> 8);
+ seq_printf(s, "Bit 9 : Bluetooth is installed: %lu\n",
+ (status & BIT(9)) >> 9);
+ seq_printf(s, "Bit 10: WWAN is installed: %lu\n",
+ (status & BIT(10)) >> 10);
+ seq_printf(s, "Bit 16: Hardware switch is on: %lu\n",
+ (status & BIT(16)) >> 16);
+ seq_printf(s, "Bit 17: Wifi is blocked: %lu\n",
+ (status & BIT(17)) >> 17);
+ seq_printf(s, "Bit 18: Bluetooth is blocked: %lu\n",
+ (status & BIT(18)) >> 18);
+ seq_printf(s, "Bit 19: WWAN is blocked: %lu\n",
+ (status & BIT(19)) >> 19);
+
+ seq_printf(s, "\nhwswitch_state:\t0x%X\n", hwswitch_state);
+ seq_printf(s, "Bit 0 : Wifi controlled by switch: %lu\n",
+ hwswitch_state & BIT(0));
+ seq_printf(s, "Bit 1 : Bluetooth controlled by switch: %lu\n",
+ (hwswitch_state & BIT(1)) >> 1);
+ seq_printf(s, "Bit 2 : WWAN controlled by switch: %lu\n",
+ (hwswitch_state & BIT(2)) >> 2);
+ seq_printf(s, "Bit 7 : Wireless switch config locked: %lu\n",
+ (hwswitch_state & BIT(7)) >> 7);
+ seq_printf(s, "Bit 8 : Wifi locator enabled: %lu\n",
+ (hwswitch_state & BIT(8)) >> 8);
+ seq_printf(s, "Bit 15: Wifi locator setting locked: %lu\n",
+ (hwswitch_state & BIT(15)) >> 15);
+
+ return 0;
+}
+
+static int dell_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dell_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations dell_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = dell_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static void dell_update_rfkill(struct work_struct *ignored)
{
if (wifi_rfkill)
@@ -556,6 +627,11 @@ static int __init dell_init(void)
goto fail_filter;
}
+ dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL);
+ if (dell_laptop_dir != NULL)
+ debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL,
+ &dell_debugfs_fops);
+
#ifdef CONFIG_ACPI
/* In the event of an ACPI backlight being available, don't
* register the platform controller.
@@ -615,6 +691,7 @@ fail_platform_driver:
static void __exit dell_exit(void)
{
+ debugfs_remove_recursive(dell_laptop_dir);
i8042_remove_filter(dell_laptop_i8042_filter);
cancel_delayed_work_sync(&dell_rfkill_work);
backlight_device_unregister(dell_backlight_device);
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 08fb70f6d9bf..77f1d55414c6 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -29,6 +29,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
#include <acpi/acpi_drivers.h>
#include <linux/acpi.h>
#include <linux/string.h>
@@ -44,78 +45,70 @@ static int acpi_video;
MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
-struct key_entry {
- char type; /* See KE_* below */
- u16 code;
- u16 keycode;
-};
-
-enum { KE_KEY, KE_SW, KE_IGNORE, KE_END };
-
/*
* Certain keys are flagged as KE_IGNORE. All of these are either
* notifications (rather than requests for change) or are also sent
* via the keyboard controller so should not be sent again.
*/
-static struct key_entry dell_legacy_wmi_keymap[] = {
- {KE_KEY, 0xe045, KEY_PROG1},
- {KE_KEY, 0xe009, KEY_EJECTCD},
+static const struct key_entry dell_wmi_legacy_keymap[] __initconst = {
+ { KE_KEY, 0xe045, { KEY_PROG1 } },
+ { KE_KEY, 0xe009, { KEY_EJECTCD } },
/* These also contain the brightness level at offset 6 */
- {KE_KEY, 0xe006, KEY_BRIGHTNESSUP},
- {KE_KEY, 0xe005, KEY_BRIGHTNESSDOWN},
+ { KE_KEY, 0xe006, { KEY_BRIGHTNESSUP } },
+ { KE_KEY, 0xe005, { KEY_BRIGHTNESSDOWN } },
/* Battery health status button */
- {KE_KEY, 0xe007, KEY_BATTERY},
+ { KE_KEY, 0xe007, { KEY_BATTERY } },
/* This is actually for all radios. Although physically a
* switch, the notification does not provide an indication of
* state and so it should be reported as a key */
- {KE_KEY, 0xe008, KEY_WLAN},
+ { KE_KEY, 0xe008, { KEY_WLAN } },
/* The next device is at offset 6, the active devices are at
offset 8 and the attached devices at offset 10 */
- {KE_KEY, 0xe00b, KEY_SWITCHVIDEOMODE},
+ { KE_KEY, 0xe00b, { KEY_SWITCHVIDEOMODE } },
- {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE},
+ { KE_IGNORE, 0xe00c, { KEY_KBDILLUMTOGGLE } },
/* BIOS error detected */
- {KE_IGNORE, 0xe00d, KEY_RESERVED},
+ { KE_IGNORE, 0xe00d, { KEY_RESERVED } },
/* Wifi Catcher */
- {KE_KEY, 0xe011, KEY_PROG2},
+ { KE_KEY, 0xe011, {KEY_PROG2 } },
/* Ambient light sensor toggle */
- {KE_IGNORE, 0xe013, KEY_RESERVED},
-
- {KE_IGNORE, 0xe020, KEY_MUTE},
- {KE_IGNORE, 0xe02e, KEY_VOLUMEDOWN},
- {KE_IGNORE, 0xe030, KEY_VOLUMEUP},
- {KE_IGNORE, 0xe033, KEY_KBDILLUMUP},
- {KE_IGNORE, 0xe034, KEY_KBDILLUMDOWN},
- {KE_IGNORE, 0xe03a, KEY_CAPSLOCK},
- {KE_IGNORE, 0xe045, KEY_NUMLOCK},
- {KE_IGNORE, 0xe046, KEY_SCROLLLOCK},
- {KE_END, 0}
+ { KE_IGNORE, 0xe013, { KEY_RESERVED } },
+
+ { KE_IGNORE, 0xe020, { KEY_MUTE } },
+ { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } },
+ { KE_IGNORE, 0xe030, { KEY_VOLUMEUP } },
+ { KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } },
+ { KE_IGNORE, 0xe034, { KEY_KBDILLUMDOWN } },
+ { KE_IGNORE, 0xe03a, { KEY_CAPSLOCK } },
+ { KE_IGNORE, 0xe045, { KEY_NUMLOCK } },
+ { KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } },
+ { KE_END, 0 }
};
static bool dell_new_hk_type;
-struct dell_new_keymap_entry {
+struct dell_bios_keymap_entry {
u16 scancode;
u16 keycode;
};
-struct dell_hotkey_table {
+struct dell_bios_hotkey_table {
struct dmi_header header;
- struct dell_new_keymap_entry keymap[];
+ struct dell_bios_keymap_entry keymap[];
};
-static struct key_entry *dell_new_wmi_keymap;
+static const struct dell_bios_hotkey_table *dell_bios_hotkey_table;
-static u16 bios_to_linux_keycode[256] = {
+static const u16 bios_to_linux_keycode[256] __initconst = {
KEY_MEDIA, KEY_NEXTSONG, KEY_PLAYPAUSE, KEY_PREVIOUSSONG,
KEY_STOPCD, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
@@ -138,68 +131,11 @@ static u16 bios_to_linux_keycode[256] = {
KEY_PROG3
};
-
-static struct key_entry *dell_wmi_keymap = dell_legacy_wmi_keymap;
-
static struct input_dev *dell_wmi_input_dev;
-static struct key_entry *dell_wmi_get_entry_by_scancode(unsigned int code)
-{
- struct key_entry *key;
-
- for (key = dell_wmi_keymap; key->type != KE_END; key++)
- if (code == key->code)
- return key;
-
- return NULL;
-}
-
-static struct key_entry *dell_wmi_get_entry_by_keycode(unsigned int keycode)
-{
- struct key_entry *key;
-
- for (key = dell_wmi_keymap; key->type != KE_END; key++)
- if (key->type == KE_KEY && keycode == key->keycode)
- return key;
-
- return NULL;
-}
-
-static int dell_wmi_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
-{
- struct key_entry *key = dell_wmi_get_entry_by_scancode(scancode);
-
- if (key && key->type == KE_KEY) {
- *keycode = key->keycode;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int dell_wmi_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
-{
- struct key_entry *key;
- unsigned int old_keycode;
-
- key = dell_wmi_get_entry_by_scancode(scancode);
- if (key && key->type == KE_KEY) {
- old_keycode = key->keycode;
- key->keycode = keycode;
- set_bit(keycode, dev->keybit);
- if (!dell_wmi_get_entry_by_keycode(old_keycode))
- clear_bit(old_keycode, dev->keybit);
- return 0;
- }
- return -EINVAL;
-}
-
static void dell_wmi_notify(u32 value, void *context)
{
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
- static struct key_entry *key;
union acpi_object *obj;
acpi_status status;
@@ -212,8 +148,10 @@ static void dell_wmi_notify(u32 value, void *context)
obj = (union acpi_object *)response.pointer;
if (obj && obj->type == ACPI_TYPE_BUFFER) {
+ const struct key_entry *key;
int reported_key;
u16 *buffer_entry = (u16 *)obj->buffer.pointer;
+
if (dell_new_hk_type && (buffer_entry[1] != 0x10)) {
printk(KERN_INFO "dell-wmi: Received unknown WMI event"
" (0x%x)\n", buffer_entry[1]);
@@ -226,8 +164,8 @@ static void dell_wmi_notify(u32 value, void *context)
else
reported_key = (int)buffer_entry[1] & 0xffff;
- key = dell_wmi_get_entry_by_scancode(reported_key);
-
+ key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev,
+ reported_key);
if (!key) {
printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n",
reported_key);
@@ -237,92 +175,98 @@ static void dell_wmi_notify(u32 value, void *context)
* come via ACPI */
;
} else {
- input_report_key(dell_wmi_input_dev, key->keycode, 1);
- input_sync(dell_wmi_input_dev);
- input_report_key(dell_wmi_input_dev, key->keycode, 0);
- input_sync(dell_wmi_input_dev);
+ sparse_keymap_report_entry(dell_wmi_input_dev, key,
+ 1, true);
}
}
kfree(obj);
}
-
-static void setup_new_hk_map(const struct dmi_header *dm)
+static const struct key_entry * __init dell_wmi_prepare_new_keymap(void)
{
-
+ int hotkey_num = (dell_bios_hotkey_table->header.length - 4) /
+ sizeof(struct dell_bios_keymap_entry);
+ struct key_entry *keymap;
int i;
- int hotkey_num = (dm->length-4)/sizeof(struct dell_new_keymap_entry);
- struct dell_hotkey_table *table =
- container_of(dm, struct dell_hotkey_table, header);
- dell_new_wmi_keymap = kzalloc((hotkey_num+1) *
- sizeof(struct key_entry), GFP_KERNEL);
+ keymap = kcalloc(hotkey_num + 1, sizeof(struct key_entry), GFP_KERNEL);
+ if (!keymap)
+ return NULL;
for (i = 0; i < hotkey_num; i++) {
- dell_new_wmi_keymap[i].type = KE_KEY;
- dell_new_wmi_keymap[i].code = table->keymap[i].scancode;
- dell_new_wmi_keymap[i].keycode =
- (table->keymap[i].keycode > 255) ? 0 :
- bios_to_linux_keycode[table->keymap[i].keycode];
+ const struct dell_bios_keymap_entry *bios_entry =
+ &dell_bios_hotkey_table->keymap[i];
+ keymap[i].type = KE_KEY;
+ keymap[i].code = bios_entry->scancode;
+ keymap[i].keycode = bios_entry->keycode < 256 ?
+ bios_to_linux_keycode[bios_entry->keycode] :
+ KEY_RESERVED;
}
- dell_new_wmi_keymap[i].type = KE_END;
- dell_new_wmi_keymap[i].code = 0;
- dell_new_wmi_keymap[i].keycode = 0;
-
- dell_wmi_keymap = dell_new_wmi_keymap;
+ keymap[hotkey_num].type = KE_END;
+ return keymap;
}
-
-static void find_hk_type(const struct dmi_header *dm, void *dummy)
-{
-
- if ((dm->type == 0xb2) && (dm->length > 6)) {
- dell_new_hk_type = true;
- setup_new_hk_map(dm);
- }
-
-}
-
-
static int __init dell_wmi_input_setup(void)
{
- struct key_entry *key;
int err;
dell_wmi_input_dev = input_allocate_device();
-
if (!dell_wmi_input_dev)
return -ENOMEM;
dell_wmi_input_dev->name = "Dell WMI hotkeys";
dell_wmi_input_dev->phys = "wmi/input0";
dell_wmi_input_dev->id.bustype = BUS_HOST;
- dell_wmi_input_dev->getkeycode = dell_wmi_getkeycode;
- dell_wmi_input_dev->setkeycode = dell_wmi_setkeycode;
-
- for (key = dell_wmi_keymap; key->type != KE_END; key++) {
- switch (key->type) {
- case KE_KEY:
- set_bit(EV_KEY, dell_wmi_input_dev->evbit);
- set_bit(key->keycode, dell_wmi_input_dev->keybit);
- break;
- case KE_SW:
- set_bit(EV_SW, dell_wmi_input_dev->evbit);
- set_bit(key->keycode, dell_wmi_input_dev->swbit);
- break;
+
+ if (dell_new_hk_type) {
+ const struct key_entry *keymap = dell_wmi_prepare_new_keymap();
+ if (!keymap) {
+ err = -ENOMEM;
+ goto err_free_dev;
}
- }
- err = input_register_device(dell_wmi_input_dev);
+ err = sparse_keymap_setup(dell_wmi_input_dev, keymap, NULL);
- if (err) {
- input_free_device(dell_wmi_input_dev);
- return err;
+ /*
+ * Sparse keymap library makes a copy of keymap so we
+ * don't need the original one that was allocated.
+ */
+ kfree(keymap);
+ } else {
+ err = sparse_keymap_setup(dell_wmi_input_dev,
+ dell_wmi_legacy_keymap, NULL);
}
+ if (err)
+ goto err_free_dev;
+
+ err = input_register_device(dell_wmi_input_dev);
+ if (err)
+ goto err_free_keymap;
return 0;
+
+ err_free_keymap:
+ sparse_keymap_free(dell_wmi_input_dev);
+ err_free_dev:
+ input_free_device(dell_wmi_input_dev);
+ return err;
+}
+
+static void dell_wmi_input_destroy(void)
+{
+ sparse_keymap_free(dell_wmi_input_dev);
+ input_unregister_device(dell_wmi_input_dev);
+}
+
+static void __init find_hk_type(const struct dmi_header *dm, void *dummy)
+{
+ if (dm->type == 0xb2 && dm->length > 6) {
+ dell_new_hk_type = true;
+ dell_bios_hotkey_table =
+ container_of(dm, struct dell_bios_hotkey_table, header);
+ }
}
static int __init dell_wmi_init(void)
@@ -339,18 +283,13 @@ static int __init dell_wmi_init(void)
acpi_video = acpi_video_backlight_support();
err = dell_wmi_input_setup();
- if (err) {
- if (dell_new_hk_type)
- kfree(dell_wmi_keymap);
+ if (err)
return err;
- }
status = wmi_install_notify_handler(DELL_EVENT_GUID,
dell_wmi_notify, NULL);
if (ACPI_FAILURE(status)) {
- input_unregister_device(dell_wmi_input_dev);
- if (dell_new_hk_type)
- kfree(dell_wmi_keymap);
+ dell_wmi_input_destroy();
printk(KERN_ERR
"dell-wmi: Unable to register notify handler - %d\n",
status);
@@ -359,14 +298,11 @@ static int __init dell_wmi_init(void)
return 0;
}
+module_init(dell_wmi_init);
static void __exit dell_wmi_exit(void)
{
wmi_remove_notify_handler(DELL_EVENT_GUID);
- input_unregister_device(dell_wmi_input_dev);
- if (dell_new_hk_type)
- kfree(dell_wmi_keymap);
+ dell_wmi_input_destroy();
}
-
-module_init(dell_wmi_init);
module_exit(dell_wmi_exit);
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 6b8e06206c46..b2edfdcdcb84 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -165,6 +165,7 @@ struct eeepc_laptop {
u16 event_count[128]; /* count for each event */
struct platform_device *platform_device;
+ struct acpi_device *device; /* the device we are in */
struct device *hwmon_device;
struct backlight_device *backlight_device;
@@ -1193,9 +1194,9 @@ static int eeepc_input_init(struct eeepc_laptop *eeepc)
eeepc->inputdev = input;
return 0;
- err_free_keymap:
+err_free_keymap:
sparse_keymap_free(input);
- err_free_dev:
+err_free_dev:
input_free_device(input);
return error;
}
@@ -1206,6 +1207,7 @@ static void eeepc_input_exit(struct eeepc_laptop *eeepc)
sparse_keymap_free(eeepc->inputdev);
input_unregister_device(eeepc->inputdev);
}
+ eeepc->inputdev = NULL;
}
/*
@@ -1326,16 +1328,15 @@ static void cmsg_quirks(struct eeepc_laptop *eeepc)
cmsg_quirk(eeepc, CM_ASL_TPD, "TPD");
}
-static int eeepc_acpi_init(struct eeepc_laptop *eeepc,
- struct acpi_device *device)
+static int __devinit eeepc_acpi_init(struct eeepc_laptop *eeepc)
{
unsigned int init_flags;
int result;
- result = acpi_bus_get_status(device);
+ result = acpi_bus_get_status(eeepc->device);
if (result)
return result;
- if (!device->status.present) {
+ if (!eeepc->device->status.present) {
pr_err("Hotkey device not present, aborting\n");
return -ENODEV;
}
@@ -1384,12 +1385,13 @@ static int __devinit eeepc_acpi_add(struct acpi_device *device)
strcpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME);
strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS);
device->driver_data = eeepc;
+ eeepc->device = device;
eeepc->hotplug_disabled = hotplug_disabled;
eeepc_dmi_check(eeepc);
- result = eeepc_acpi_init(eeepc, device);
+ result = eeepc_acpi_init(eeepc);
if (result)
goto fail_platform;
eeepc_enable_camera(eeepc);
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
index 9dc50fbf3d0b..462ceab93f87 100644
--- a/drivers/platform/x86/eeepc-wmi.c
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -57,6 +57,7 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID);
#define EEEPC_WMI_METHODID_DEVS 0x53564544
#define EEEPC_WMI_METHODID_DSTS 0x53544344
+#define EEEPC_WMI_METHODID_CFVS 0x53564643
#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012
@@ -69,6 +70,11 @@ static const struct key_entry eeepc_wmi_keymap[] = {
{ KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } },
{ KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } },
{ KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
+ { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */
+ { KE_KEY, 0xe1, { KEY_F14 } },
+ { KE_KEY, 0xe9, { KEY_DISPLAY_OFF } },
+ { KE_KEY, 0xe0, { KEY_PROG1 } },
+ { KE_KEY, 0x5c, { KEY_F15 } },
{ KE_END, 0},
};
@@ -292,6 +298,49 @@ static void eeepc_wmi_notify(u32 value, void *context)
kfree(obj);
}
+static int store_cpufv(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+ struct acpi_buffer input = { (acpi_size)sizeof(value), &value };
+ acpi_status status;
+
+ if (!count || sscanf(buf, "%i", &value) != 1)
+ return -EINVAL;
+ if (value < 0 || value > 2)
+ return -EINVAL;
+
+ status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
+ 1, EEEPC_WMI_METHODID_CFVS, &input, NULL);
+
+ if (ACPI_FAILURE(status))
+ return -EIO;
+ else
+ return count;
+}
+
+static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv);
+
+static void eeepc_wmi_sysfs_exit(struct platform_device *device)
+{
+ device_remove_file(&device->dev, &dev_attr_cpufv);
+}
+
+static int eeepc_wmi_sysfs_init(struct platform_device *device)
+{
+ int retval = -ENOMEM;
+
+ retval = device_create_file(&device->dev, &dev_attr_cpufv);
+ if (retval)
+ goto error_sysfs;
+
+ return 0;
+
+error_sysfs:
+ eeepc_wmi_sysfs_exit(platform_device);
+ return retval;
+}
+
static int __devinit eeepc_wmi_platform_probe(struct platform_device *device)
{
struct eeepc_wmi *eeepc;
@@ -387,8 +436,14 @@ static int __init eeepc_wmi_init(void)
goto del_dev;
}
+ err = eeepc_wmi_sysfs_init(platform_device);
+ if (err)
+ goto del_sysfs;
+
return 0;
+del_sysfs:
+ eeepc_wmi_sysfs_exit(platform_device);
del_dev:
platform_device_del(platform_device);
put_dev:
@@ -403,6 +458,7 @@ static void __exit eeepc_wmi_exit(void)
{
struct eeepc_wmi *eeepc;
+ eeepc_wmi_sysfs_exit(platform_device);
eeepc = platform_get_drvdata(platform_device);
platform_driver_unregister(&platform_driver);
platform_device_unregister(platform_device);
diff --git a/drivers/hwmon/hdaps.c b/drivers/platform/x86/hdaps.c
index bfd42f18924b..067bf36d32f3 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/platform/x86/hdaps.c
@@ -1,5 +1,5 @@
/*
- * drivers/hwmon/hdaps.c - driver for IBM's Hard Drive Active Protection System
+ * hdaps.c - driver for IBM's Hard Drive Active Protection System
*
* Copyright (C) 2005 Robert Love <rml@novell.com>
* Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com>
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index c1741142a4cb..1dac659b5e0c 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -29,6 +29,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/rfkill.h>
@@ -88,24 +89,16 @@ struct bios_return {
u32 value;
};
-struct key_entry {
- char type; /* See KE_* below */
- u16 code;
- u16 keycode;
-};
-
-enum { KE_KEY, KE_END };
-
-static struct key_entry hp_wmi_keymap[] = {
- {KE_KEY, 0x02, KEY_BRIGHTNESSUP},
- {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
- {KE_KEY, 0x20e6, KEY_PROG1},
- {KE_KEY, 0x20e8, KEY_MEDIA},
- {KE_KEY, 0x2142, KEY_MEDIA},
- {KE_KEY, 0x213b, KEY_INFO},
- {KE_KEY, 0x2169, KEY_DIRECTION},
- {KE_KEY, 0x231b, KEY_HELP},
- {KE_END, 0}
+static const struct key_entry hp_wmi_keymap[] = {
+ { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } },
+ { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } },
+ { KE_KEY, 0x20e6, { KEY_PROG1 } },
+ { KE_KEY, 0x20e8, { KEY_MEDIA } },
+ { KE_KEY, 0x2142, { KEY_MEDIA } },
+ { KE_KEY, 0x213b, { KEY_INFO } },
+ { KE_KEY, 0x2169, { KEY_DIRECTION } },
+ { KE_KEY, 0x231b, { KEY_HELP } },
+ { KE_END, 0 }
};
static struct input_dev *hp_wmi_input_dev;
@@ -347,64 +340,9 @@ static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
-static struct key_entry *hp_wmi_get_entry_by_scancode(unsigned int code)
-{
- struct key_entry *key;
-
- for (key = hp_wmi_keymap; key->type != KE_END; key++)
- if (code == key->code)
- return key;
-
- return NULL;
-}
-
-static struct key_entry *hp_wmi_get_entry_by_keycode(unsigned int keycode)
-{
- struct key_entry *key;
-
- for (key = hp_wmi_keymap; key->type != KE_END; key++)
- if (key->type == KE_KEY && keycode == key->keycode)
- return key;
-
- return NULL;
-}
-
-static int hp_wmi_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
-{
- struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode);
-
- if (key && key->type == KE_KEY) {
- *keycode = key->keycode;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int hp_wmi_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
-{
- struct key_entry *key;
- unsigned int old_keycode;
-
- key = hp_wmi_get_entry_by_scancode(scancode);
- if (key && key->type == KE_KEY) {
- old_keycode = key->keycode;
- key->keycode = keycode;
- set_bit(keycode, dev->keybit);
- if (!hp_wmi_get_entry_by_keycode(old_keycode))
- clear_bit(old_keycode, dev->keybit);
- return 0;
- }
-
- return -EINVAL;
-}
-
static void hp_wmi_notify(u32 value, void *context)
{
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
- static struct key_entry *key;
union acpi_object *obj;
u32 event_id, event_data;
int key_code = 0, ret;
@@ -465,19 +403,9 @@ static void hp_wmi_notify(u32 value, void *context)
sizeof(key_code));
if (ret)
break;
- key = hp_wmi_get_entry_by_scancode(key_code);
- if (key) {
- switch (key->type) {
- case KE_KEY:
- input_report_key(hp_wmi_input_dev,
- key->keycode, 1);
- input_sync(hp_wmi_input_dev);
- input_report_key(hp_wmi_input_dev,
- key->keycode, 0);
- input_sync(hp_wmi_input_dev);
- break;
- }
- } else
+
+ if (!sparse_keymap_report_event(hp_wmi_input_dev,
+ key_code, 1, true))
printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n",
key_code);
break;
@@ -510,7 +438,7 @@ static void hp_wmi_notify(u32 value, void *context)
static int __init hp_wmi_input_setup(void)
{
- struct key_entry *key;
+ acpi_status status;
int err;
hp_wmi_input_dev = input_allocate_device();
@@ -520,21 +448,14 @@ static int __init hp_wmi_input_setup(void)
hp_wmi_input_dev->name = "HP WMI hotkeys";
hp_wmi_input_dev->phys = "wmi/input0";
hp_wmi_input_dev->id.bustype = BUS_HOST;
- hp_wmi_input_dev->getkeycode = hp_wmi_getkeycode;
- hp_wmi_input_dev->setkeycode = hp_wmi_setkeycode;
-
- for (key = hp_wmi_keymap; key->type != KE_END; key++) {
- switch (key->type) {
- case KE_KEY:
- set_bit(EV_KEY, hp_wmi_input_dev->evbit);
- set_bit(key->keycode, hp_wmi_input_dev->keybit);
- break;
- }
- }
- set_bit(EV_SW, hp_wmi_input_dev->evbit);
- set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
- set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
+ __set_bit(EV_SW, hp_wmi_input_dev->evbit);
+ __set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
+ __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
+
+ err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
+ if (err)
+ goto err_free_dev;
/* Set initial hardware state */
input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
@@ -542,14 +463,32 @@ static int __init hp_wmi_input_setup(void)
hp_wmi_tablet_state());
input_sync(hp_wmi_input_dev);
- err = input_register_device(hp_wmi_input_dev);
-
- if (err) {
- input_free_device(hp_wmi_input_dev);
- return err;
+ status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
+ if (ACPI_FAILURE(status)) {
+ err = -EIO;
+ goto err_free_keymap;
}
+ err = input_register_device(hp_wmi_input_dev);
+ if (err)
+ goto err_uninstall_notifier;
+
return 0;
+
+ err_uninstall_notifier:
+ wmi_remove_notify_handler(HPWMI_EVENT_GUID);
+ err_free_keymap:
+ sparse_keymap_free(hp_wmi_input_dev);
+ err_free_dev:
+ input_free_device(hp_wmi_input_dev);
+ return err;
+}
+
+static void hp_wmi_input_destroy(void)
+{
+ wmi_remove_notify_handler(HPWMI_EVENT_GUID);
+ sparse_keymap_free(hp_wmi_input_dev);
+ input_unregister_device(hp_wmi_input_dev);
}
static void cleanup_sysfs(struct platform_device *device)
@@ -704,15 +643,9 @@ static int __init hp_wmi_init(void)
int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
if (event_capable) {
- err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
- hp_wmi_notify, NULL);
- if (ACPI_FAILURE(err))
- return -EINVAL;
err = hp_wmi_input_setup();
- if (err) {
- wmi_remove_notify_handler(HPWMI_EVENT_GUID);
+ if (err)
return err;
- }
}
if (bios_capable) {
@@ -739,20 +672,17 @@ err_device_add:
err_device_alloc:
platform_driver_unregister(&hp_wmi_driver);
err_driver_reg:
- if (wmi_has_guid(HPWMI_EVENT_GUID)) {
- input_unregister_device(hp_wmi_input_dev);
- wmi_remove_notify_handler(HPWMI_EVENT_GUID);
- }
+ if (event_capable)
+ hp_wmi_input_destroy();
return err;
}
static void __exit hp_wmi_exit(void)
{
- if (wmi_has_guid(HPWMI_EVENT_GUID)) {
- wmi_remove_notify_handler(HPWMI_EVENT_GUID);
- input_unregister_device(hp_wmi_input_dev);
- }
+ if (wmi_has_guid(HPWMI_EVENT_GUID))
+ hp_wmi_input_destroy();
+
if (hp_wmi_platform_dev) {
platform_device_unregister(hp_wmi_platform_dev);
platform_driver_unregister(&hp_wmi_driver);
diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c
new file mode 100644
index 000000000000..3c2c6b91ecb3
--- /dev/null
+++ b/drivers/platform/x86/ibm_rtl.c
@@ -0,0 +1,341 @@
+/*
+ * IBM Real-Time Linux driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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.
+ *
+ * Copyright (C) IBM Corporation, 2010
+ *
+ * Author: Keith Mannthey <kmannth@us.ibm.com>
+ * Vernon Mauery <vernux@us.ibm.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+#include <linux/dmi.h>
+#include <linux/mutex.h>
+#include <asm/bios_ebda.h>
+
+static bool force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
+
+static bool debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Show debug output");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Keith Mannthey <kmmanth@us.ibm.com>");
+MODULE_AUTHOR("Vernon Mauery <vernux@us.ibm.com>");
+
+#define RTL_ADDR_TYPE_IO 1
+#define RTL_ADDR_TYPE_MMIO 2
+
+#define RTL_CMD_ENTER_PRTM 1
+#define RTL_CMD_EXIT_PRTM 2
+
+/* The RTL table as presented by the EBDA: */
+struct ibm_rtl_table {
+ char signature[5]; /* signature should be "_RTL_" */
+ u8 version;
+ u8 rt_status;
+ u8 command;
+ u8 command_status;
+ u8 cmd_address_type;
+ u8 cmd_granularity;
+ u8 cmd_offset;
+ u16 reserve1;
+ u32 cmd_port_address; /* platform dependent address */
+ u32 cmd_port_value; /* platform dependent value */
+} __attribute__((packed));
+
+/* to locate "_RTL_" signature do a masked 5-byte integer compare */
+#define RTL_SIGNATURE 0x0000005f4c54525fULL
+#define RTL_MASK 0x000000ffffffffffULL
+
+#define RTL_DEBUG(A, ...) do { \
+ if (debug) \
+ pr_info("ibm-rtl: " A, ##__VA_ARGS__ ); \
+} while (0)
+
+static DEFINE_MUTEX(rtl_lock);
+static struct ibm_rtl_table __iomem *rtl_table;
+static void __iomem *ebda_map;
+static void __iomem *rtl_cmd_addr;
+static u8 rtl_cmd_type;
+static u8 rtl_cmd_width;
+
+static void __iomem *rtl_port_map(phys_addr_t addr, unsigned long len)
+{
+ if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ return ioremap(addr, len);
+ return ioport_map(addr, len);
+}
+
+static void rtl_port_unmap(void __iomem *addr)
+{
+ if (addr && rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ iounmap(addr);
+ else
+ ioport_unmap(addr);
+}
+
+static int ibm_rtl_write(u8 value)
+{
+ int ret = 0, count = 0;
+ static u32 cmd_port_val;
+
+ RTL_DEBUG("%s(%d)\n", __FUNCTION__, value);
+
+ value = value == 1 ? RTL_CMD_ENTER_PRTM : RTL_CMD_EXIT_PRTM;
+
+ mutex_lock(&rtl_lock);
+
+ if (ioread8(&rtl_table->rt_status) != value) {
+ iowrite8(value, &rtl_table->command);
+
+ switch (rtl_cmd_width) {
+ case 8:
+ cmd_port_val = ioread8(&rtl_table->cmd_port_value);
+ RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ iowrite8((u8)cmd_port_val, rtl_cmd_addr);
+ break;
+ case 16:
+ cmd_port_val = ioread16(&rtl_table->cmd_port_value);
+ RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ iowrite16((u16)cmd_port_val, rtl_cmd_addr);
+ break;
+ case 32:
+ cmd_port_val = ioread32(&rtl_table->cmd_port_value);
+ RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ iowrite32(cmd_port_val, rtl_cmd_addr);
+ break;
+ }
+
+ while (ioread8(&rtl_table->command)) {
+ msleep(10);
+ if (count++ > 500) {
+ pr_err("ibm-rtl: Hardware not responding to "
+ "mode switch request\n");
+ ret = -EIO;
+ break;
+ }
+
+ }
+
+ if (ioread8(&rtl_table->command_status)) {
+ RTL_DEBUG("command_status reports failed command\n");
+ ret = -EIO;
+ }
+ }
+
+ mutex_unlock(&rtl_lock);
+ return ret;
+}
+
+static ssize_t rtl_show_version(struct sysdev_class * dev,
+ struct sysdev_class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", (int)ioread8(&rtl_table->version));
+}
+
+static ssize_t rtl_show_state(struct sysdev_class *dev,
+ struct sysdev_class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", ioread8(&rtl_table->rt_status));
+}
+
+static ssize_t rtl_set_state(struct sysdev_class *dev,
+ struct sysdev_class_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ ssize_t ret;
+
+ if (count < 1 || count > 2)
+ return -EINVAL;
+
+ switch (buf[0]) {
+ case '0':
+ ret = ibm_rtl_write(0);
+ break;
+ case '1':
+ ret = ibm_rtl_write(1);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if (ret >= 0)
+ ret = count;
+
+ return ret;
+}
+
+static struct sysdev_class class_rtl = {
+ .name = "ibm_rtl",
+};
+
+static SYSDEV_CLASS_ATTR(version, S_IRUGO, rtl_show_version, NULL);
+static SYSDEV_CLASS_ATTR(state, 0600, rtl_show_state, rtl_set_state);
+
+static struct sysdev_class_attribute *rtl_attributes[] = {
+ &attr_version,
+ &attr_state,
+ NULL
+};
+
+
+static int rtl_setup_sysfs(void) {
+ int ret, i;
+ ret = sysdev_class_register(&class_rtl);
+
+ if (!ret) {
+ for (i = 0; rtl_attributes[i]; i ++)
+ sysdev_class_create_file(&class_rtl, rtl_attributes[i]);
+ }
+ return ret;
+}
+
+static void rtl_teardown_sysfs(void) {
+ int i;
+ for (i = 0; rtl_attributes[i]; i ++)
+ sysdev_class_remove_file(&class_rtl, rtl_attributes[i]);
+ sysdev_class_unregister(&class_rtl);
+}
+
+static int dmi_check_cb(const struct dmi_system_id *id)
+{
+ RTL_DEBUG("found IBM server '%s'\n", id->ident);
+ return 0;
+}
+
+#define ibm_dmi_entry(NAME, TYPE) \
+{ \
+ .ident = NAME, \
+ .matches = { \
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \
+ DMI_MATCH(DMI_PRODUCT_NAME, TYPE), \
+ }, \
+ .callback = dmi_check_cb \
+}
+
+static struct dmi_system_id __initdata ibm_rtl_dmi_table[] = {
+ ibm_dmi_entry("BladeCenter LS21", "7971"),
+ ibm_dmi_entry("BladeCenter LS22", "7901"),
+ ibm_dmi_entry("BladeCenter HS21 XM", "7995"),
+ ibm_dmi_entry("BladeCenter HS22", "7870"),
+ ibm_dmi_entry("BladeCenter HS22V", "7871"),
+ ibm_dmi_entry("System x3550 M2", "7946"),
+ ibm_dmi_entry("System x3650 M2", "7947"),
+ ibm_dmi_entry("System x3550 M3", "7944"),
+ ibm_dmi_entry("System x3650 M3", "7945"),
+ { }
+};
+
+static int __init ibm_rtl_init(void) {
+ unsigned long ebda_addr, ebda_size;
+ unsigned int ebda_kb;
+ int ret = -ENODEV, i;
+
+ if (force)
+ pr_warning("ibm-rtl: module loaded by force\n");
+ /* first ensure that we are running on IBM HW */
+ else if (!dmi_check_system(ibm_rtl_dmi_table))
+ return -ENODEV;
+
+ /* Get the address for the Extended BIOS Data Area */
+ ebda_addr = get_bios_ebda();
+ if (!ebda_addr) {
+ RTL_DEBUG("no BIOS EBDA found\n");
+ return -ENODEV;
+ }
+
+ ebda_map = ioremap(ebda_addr, 4);
+ if (!ebda_map)
+ return -ENOMEM;
+
+ /* First word in the EDBA is the Size in KB */
+ ebda_kb = ioread16(ebda_map);
+ RTL_DEBUG("EBDA is %d kB\n", ebda_kb);
+
+ if (ebda_kb == 0)
+ goto out;
+
+ iounmap(ebda_map);
+ ebda_size = ebda_kb*1024;
+
+ /* Remap the whole table */
+ ebda_map = ioremap(ebda_addr, ebda_size);
+ if (!ebda_map)
+ return -ENOMEM;
+
+ /* search for the _RTL_ signature at the start of the table */
+ for (i = 0 ; i < ebda_size/sizeof(unsigned int); i++) {
+ struct ibm_rtl_table __iomem * tmp;
+ tmp = (struct ibm_rtl_table __iomem *) (ebda_map+i);
+ if ((readq(&tmp->signature) & RTL_MASK) == RTL_SIGNATURE) {
+ phys_addr_t addr;
+ unsigned int plen;
+ RTL_DEBUG("found RTL_SIGNATURE at %#llx\n", (u64)tmp);
+ rtl_table = tmp;
+ /* The address, value, width and offset are platform
+ * dependent and found in the ibm_rtl_table */
+ rtl_cmd_width = ioread8(&rtl_table->cmd_granularity);
+ rtl_cmd_type = ioread8(&rtl_table->cmd_address_type);
+ RTL_DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n",
+ rtl_cmd_width, rtl_cmd_type);
+ addr = ioread32(&rtl_table->cmd_port_address);
+ RTL_DEBUG("addr = %#llx\n", addr);
+ plen = rtl_cmd_width/sizeof(char);
+ rtl_cmd_addr = rtl_port_map(addr, plen);
+ RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr);
+ if (!rtl_cmd_addr) {
+ ret = -ENOMEM;
+ break;
+ }
+ ret = rtl_setup_sysfs();
+ break;
+ }
+ }
+
+out:
+ if (ret) {
+ iounmap(ebda_map);
+ rtl_port_unmap(rtl_cmd_addr);
+ }
+
+ return ret;
+}
+
+static void __exit ibm_rtl_exit(void)
+{
+ if (rtl_table) {
+ RTL_DEBUG("cleaning up");
+ /* do not leave the machine in SMI-free mode */
+ ibm_rtl_write(0);
+ /* unmap, unlink and remove all traces */
+ rtl_teardown_sysfs();
+ iounmap(ebda_map);
+ rtl_port_unmap(rtl_cmd_addr);
+ }
+}
+
+module_init(ibm_rtl_init);
+module_exit(ibm_rtl_exit);
diff --git a/drivers/platform/x86/ideapad_acpi.c b/drivers/platform/x86/ideapad-laptop.c
index 798496353e8c..5ff12205aa6b 100644
--- a/drivers/platform/x86/ideapad_acpi.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -35,112 +35,162 @@
#define IDEAPAD_DEV_KILLSW 4
struct ideapad_private {
+ acpi_handle handle;
struct rfkill *rfk[5];
-};
+} *ideapad_priv;
static struct {
char *name;
+ int cfgbit;
+ int opcode;
int type;
} ideapad_rfk_data[] = {
- /* camera has no rfkill */
- { "ideapad_wlan", RFKILL_TYPE_WLAN },
- { "ideapad_bluetooth", RFKILL_TYPE_BLUETOOTH },
- { "ideapad_3g", RFKILL_TYPE_WWAN },
- { "ideapad_killsw", RFKILL_TYPE_WLAN }
+ { "ideapad_camera", 19, 0x1E, NUM_RFKILL_TYPES },
+ { "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN },
+ { "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH },
+ { "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN },
+ { "ideapad_killsw", 0, 0, RFKILL_TYPE_WLAN }
};
-static int ideapad_dev_exists(int device)
-{
- acpi_status status;
- union acpi_object in_param;
- struct acpi_object_list input = { 1, &in_param };
- struct acpi_buffer output;
- union acpi_object out_obj;
+static bool no_bt_rfkill;
+module_param(no_bt_rfkill, bool, 0444);
+MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
- output.length = sizeof(out_obj);
- output.pointer = &out_obj;
+/*
+ * ACPI Helpers
+ */
+#define IDEAPAD_EC_TIMEOUT (100) /* in ms */
- in_param.type = ACPI_TYPE_INTEGER;
- in_param.integer.value = device + 1;
+static int read_method_int(acpi_handle handle, const char *method, int *val)
+{
+ acpi_status status;
+ unsigned long long result;
- status = acpi_evaluate_object(NULL, "\\_SB_.DECN", &input, &output);
+ status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING "IdeaPAD \\_SB_.DECN method failed %d. Is this an IdeaPAD?\n", status);
- return -ENODEV;
- }
- if (out_obj.type != ACPI_TYPE_INTEGER) {
- printk(KERN_WARNING "IdeaPAD \\_SB_.DECN method returned unexpected type\n");
- return -ENODEV;
+ *val = -1;
+ return -1;
+ } else {
+ *val = result;
+ return 0;
}
- return out_obj.integer.value;
}
-static int ideapad_dev_get_state(int device)
+static int method_vpcr(acpi_handle handle, int cmd, int *ret)
{
acpi_status status;
- union acpi_object in_param;
- struct acpi_object_list input = { 1, &in_param };
- struct acpi_buffer output;
- union acpi_object out_obj;
+ unsigned long long result;
+ struct acpi_object_list params;
+ union acpi_object in_obj;
- output.length = sizeof(out_obj);
- output.pointer = &out_obj;
+ params.count = 1;
+ params.pointer = &in_obj;
+ in_obj.type = ACPI_TYPE_INTEGER;
+ in_obj.integer.value = cmd;
- in_param.type = ACPI_TYPE_INTEGER;
- in_param.integer.value = device + 1;
+ status = acpi_evaluate_integer(handle, "VPCR", &params, &result);
- status = acpi_evaluate_object(NULL, "\\_SB_.GECN", &input, &output);
if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING "IdeaPAD \\_SB_.GECN method failed %d\n", status);
- return -ENODEV;
- }
- if (out_obj.type != ACPI_TYPE_INTEGER) {
- printk(KERN_WARNING "IdeaPAD \\_SB_.GECN method returned unexpected type\n");
- return -ENODEV;
+ *ret = -1;
+ return -1;
+ } else {
+ *ret = result;
+ return 0;
}
- return out_obj.integer.value;
}
-static int ideapad_dev_set_state(int device, int state)
+static int method_vpcw(acpi_handle handle, int cmd, int data)
{
+ struct acpi_object_list params;
+ union acpi_object in_obj[2];
acpi_status status;
- union acpi_object in_params[2];
- struct acpi_object_list input = { 2, in_params };
- in_params[0].type = ACPI_TYPE_INTEGER;
- in_params[0].integer.value = device + 1;
- in_params[1].type = ACPI_TYPE_INTEGER;
- in_params[1].integer.value = state;
+ params.count = 2;
+ params.pointer = in_obj;
+ in_obj[0].type = ACPI_TYPE_INTEGER;
+ in_obj[0].integer.value = cmd;
+ in_obj[1].type = ACPI_TYPE_INTEGER;
+ in_obj[1].integer.value = data;
- status = acpi_evaluate_object(NULL, "\\_SB_.SECN", &input, NULL);
- if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING "IdeaPAD \\_SB_.SECN method failed %d\n", status);
- return -ENODEV;
- }
+ status = acpi_evaluate_object(handle, "VPCW", &params, NULL);
+ if (status != AE_OK)
+ return -1;
return 0;
}
+
+static int read_ec_data(acpi_handle handle, int cmd, unsigned long *data)
+{
+ int val;
+ unsigned long int end_jiffies;
+
+ if (method_vpcw(handle, 1, cmd))
+ return -1;
+
+ for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
+ time_before(jiffies, end_jiffies);) {
+ schedule();
+ if (method_vpcr(handle, 1, &val))
+ return -1;
+ if (val == 0) {
+ if (method_vpcr(handle, 0, &val))
+ return -1;
+ *data = val;
+ return 0;
+ }
+ }
+ pr_err("timeout in read_ec_cmd\n");
+ return -1;
+}
+
+static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
+{
+ int val;
+ unsigned long int end_jiffies;
+
+ if (method_vpcw(handle, 0, data))
+ return -1;
+ if (method_vpcw(handle, 1, cmd))
+ return -1;
+
+ for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
+ time_before(jiffies, end_jiffies);) {
+ schedule();
+ if (method_vpcr(handle, 1, &val))
+ return -1;
+ if (val == 0)
+ return 0;
+ }
+ pr_err("timeout in write_ec_cmd\n");
+ return -1;
+}
+/* the above is ACPI helpers */
+
static ssize_t show_ideapad_cam(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- int state = ideapad_dev_get_state(IDEAPAD_DEV_CAMERA);
- if (state < 0)
- return state;
+ struct ideapad_private *priv = dev_get_drvdata(dev);
+ acpi_handle handle = priv->handle;
+ unsigned long result;
- return sprintf(buf, "%d\n", state);
+ if (read_ec_data(handle, 0x1D, &result))
+ return sprintf(buf, "-1\n");
+ return sprintf(buf, "%lu\n", result);
}
static ssize_t store_ideapad_cam(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
+ struct ideapad_private *priv = dev_get_drvdata(dev);
+ acpi_handle handle = priv->handle;
int ret, state;
if (!count)
return 0;
if (sscanf(buf, "%i", &state) != 1)
return -EINVAL;
- ret = ideapad_dev_set_state(IDEAPAD_DEV_CAMERA, !!state);
+ ret = write_ec_cmd(handle, 0x1E, state);
if (ret < 0)
return ret;
return count;
@@ -154,7 +204,10 @@ static int ideapad_rfk_set(void *data, bool blocked)
if (device == IDEAPAD_DEV_KILLSW)
return -EINVAL;
- return ideapad_dev_set_state(device, !blocked);
+
+ return write_ec_cmd(ideapad_priv->handle,
+ ideapad_rfk_data[device].opcode,
+ !blocked);
}
static struct rfkill_ops ideapad_rfk_ops = {
@@ -164,32 +217,47 @@ static struct rfkill_ops ideapad_rfk_ops = {
static void ideapad_sync_rfk_state(struct acpi_device *adevice)
{
struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
- int hw_blocked = !ideapad_dev_get_state(IDEAPAD_DEV_KILLSW);
+ acpi_handle handle = priv->handle;
+ unsigned long hw_blocked;
int i;
- rfkill_set_hw_state(priv->rfk[IDEAPAD_DEV_KILLSW], hw_blocked);
- for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++)
- if (priv->rfk[i])
- rfkill_set_hw_state(priv->rfk[i], hw_blocked);
- if (hw_blocked)
+ if (read_ec_data(handle, 0x23, &hw_blocked))
return;
+ hw_blocked = !hw_blocked;
- for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++)
+ for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++)
if (priv->rfk[i])
- rfkill_set_sw_state(priv->rfk[i], !ideapad_dev_get_state(i));
+ rfkill_set_hw_state(priv->rfk[i], hw_blocked);
}
static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
{
struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
int ret;
+ unsigned long sw_blocked;
+
+ if (no_bt_rfkill &&
+ (ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH)) {
+ /* Force to enable bluetooth when no_bt_rfkill=1 */
+ write_ec_cmd(ideapad_priv->handle,
+ ideapad_rfk_data[dev].opcode, 1);
+ return 0;
+ }
- priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev-1].name, &adevice->dev,
- ideapad_rfk_data[dev-1].type, &ideapad_rfk_ops,
+ priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev].name, &adevice->dev,
+ ideapad_rfk_data[dev].type, &ideapad_rfk_ops,
(void *)(long)dev);
if (!priv->rfk[dev])
return -ENOMEM;
+ if (read_ec_data(ideapad_priv->handle, ideapad_rfk_data[dev].opcode-1,
+ &sw_blocked)) {
+ rfkill_init_sw_state(priv->rfk[dev], 0);
+ } else {
+ sw_blocked = !sw_blocked;
+ rfkill_init_sw_state(priv->rfk[dev], sw_blocked);
+ }
+
ret = rfkill_register(priv->rfk[dev]);
if (ret) {
rfkill_destroy(priv->rfk[dev]);
@@ -217,14 +285,18 @@ MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
static int ideapad_acpi_add(struct acpi_device *adevice)
{
- int i;
+ int i, cfg;
int devs_present[5];
struct ideapad_private *priv;
+ if (read_method_int(adevice->handle, "_CFG", &cfg))
+ return -ENODEV;
+
for (i = IDEAPAD_DEV_CAMERA; i < IDEAPAD_DEV_KILLSW; i++) {
- devs_present[i] = ideapad_dev_exists(i);
- if (devs_present[i] < 0)
- return devs_present[i];
+ if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg))
+ devs_present[i] = 1;
+ else
+ devs_present[i] = 0;
}
/* The hardware switch is always present */
@@ -242,7 +314,9 @@ static int ideapad_acpi_add(struct acpi_device *adevice)
}
}
+ priv->handle = adevice->handle;
dev_set_drvdata(&adevice->dev, priv);
+ ideapad_priv = priv;
for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) {
if (!devs_present[i])
continue;
@@ -270,7 +344,21 @@ static int ideapad_acpi_remove(struct acpi_device *adevice, int type)
static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
{
- ideapad_sync_rfk_state(adevice);
+ acpi_handle handle = adevice->handle;
+ unsigned long vpc1, vpc2, vpc_bit;
+
+ if (read_ec_data(handle, 0x10, &vpc1))
+ return;
+ if (read_ec_data(handle, 0x1A, &vpc2))
+ return;
+
+ vpc1 = (vpc2 << 8) | vpc1;
+ for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) {
+ if (test_bit(vpc_bit, &vpc1)) {
+ if (vpc_bit == 9)
+ ideapad_sync_rfk_state(adevice);
+ }
+ }
}
static struct acpi_driver ideapad_acpi_driver = {
diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c
index 5cdcff653918..e61db9dfebef 100644
--- a/drivers/platform/x86/intel_pmic_gpio.c
+++ b/drivers/platform/x86/intel_pmic_gpio.c
@@ -29,7 +29,6 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/gpio.h>
-#include <linux/interrupt.h>
#include <asm/intel_scu_ipc.h>
#include <linux/device.h>
#include <linux/intel_pmic_gpio.h>
@@ -142,16 +141,16 @@ static int pmic_gpio_direction_output(struct gpio_chip *chip,
if (offset < 8)/* it is GPIO */
rc = intel_scu_ipc_update_register(GPIO0 + offset,
- GPIO_DRV | GPIO_DOU | GPIO_DIR,
- GPIO_DRV | (value ? GPIO_DOU : 0));
+ GPIO_DRV | (value ? GPIO_DOU : 0),
+ GPIO_DRV | GPIO_DOU | GPIO_DIR);
else if (offset < 16)/* it is GPOSW */
rc = intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8,
- GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV,
- GPOSW_DRV | (value ? GPOSW_DOU : 0));
+ GPOSW_DRV | (value ? GPOSW_DOU : 0),
+ GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV);
else if (offset > 15 && offset < 24)/* it is GPO */
rc = intel_scu_ipc_update_register(GPO,
- 1 << (offset - 16),
- value ? 1 << (offset - 16) : 0);
+ value ? 1 << (offset - 16) : 0,
+ 1 << (offset - 16));
else {
printk(KERN_ERR
"%s: invalid PMIC GPIO pin %d!\n", __func__, offset);
@@ -179,16 +178,16 @@ static void pmic_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
if (offset < 8)/* it is GPIO */
intel_scu_ipc_update_register(GPIO0 + offset,
- GPIO_DRV | GPIO_DOU,
- GPIO_DRV | (value ? GPIO_DOU : 0));
+ GPIO_DRV | (value ? GPIO_DOU : 0),
+ GPIO_DRV | GPIO_DOU);
else if (offset < 16)/* it is GPOSW */
intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8,
- GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV,
- GPOSW_DRV | (value ? GPOSW_DOU : 0));
+ GPOSW_DRV | (value ? GPOSW_DOU : 0),
+ GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV);
else if (offset > 15 && offset < 24) /* it is GPO */
intel_scu_ipc_update_register(GPO,
- 1 << (offset - 16),
- value ? 1 << (offset - 16) : 0);
+ value ? 1 << (offset - 16) : 0,
+ 1 << (offset - 16));
}
static int pmic_irq_type(unsigned irq, unsigned type)
@@ -197,7 +196,7 @@ static int pmic_irq_type(unsigned irq, unsigned type)
u32 gpio = irq - pg->irq_base;
unsigned long flags;
- if (gpio > pg->chip.ngpio)
+ if (gpio >= pg->chip.ngpio)
return -EINVAL;
spin_lock_irqsave(&pg->irqtypes.lock, flags);
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index 6abe18e638e9..41a9e34899ac 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -23,6 +23,7 @@
#include <linux/pm.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/sfi.h>
#include <asm/mrst.h>
#include <asm/intel_scu_ipc.h>
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index ec01c3d8fc5a..cc1e0ba104d7 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -128,6 +128,7 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
#ifndef ACPI_HOTKEY_COMPONENT
@@ -200,30 +201,29 @@ static struct acpi_driver acpi_pcc_driver = {
},
};
-#define KEYMAP_SIZE 11
-static const unsigned int initial_keymap[KEYMAP_SIZE] = {
- /* 0 */ KEY_RESERVED,
- /* 1 */ KEY_BRIGHTNESSDOWN,
- /* 2 */ KEY_BRIGHTNESSUP,
- /* 3 */ KEY_DISPLAYTOGGLE,
- /* 4 */ KEY_MUTE,
- /* 5 */ KEY_VOLUMEDOWN,
- /* 6 */ KEY_VOLUMEUP,
- /* 7 */ KEY_SLEEP,
- /* 8 */ KEY_PROG1, /* Change CPU boost */
- /* 9 */ KEY_BATTERY,
- /* 10 */ KEY_SUSPEND,
+static const struct key_entry panasonic_keymap[] = {
+ { KE_KEY, 0, { KEY_RESERVED } },
+ { KE_KEY, 1, { KEY_BRIGHTNESSDOWN } },
+ { KE_KEY, 2, { KEY_BRIGHTNESSUP } },
+ { KE_KEY, 3, { KEY_DISPLAYTOGGLE } },
+ { KE_KEY, 4, { KEY_MUTE } },
+ { KE_KEY, 5, { KEY_VOLUMEDOWN } },
+ { KE_KEY, 6, { KEY_VOLUMEUP } },
+ { KE_KEY, 7, { KEY_SLEEP } },
+ { KE_KEY, 8, { KEY_PROG1 } }, /* Change CPU boost */
+ { KE_KEY, 9, { KEY_BATTERY } },
+ { KE_KEY, 10, { KEY_SUSPEND } },
+ { KE_END, 0 }
};
struct pcc_acpi {
acpi_handle handle;
unsigned long num_sifr;
int sticky_mode;
- u32 *sinf;
+ u32 *sinf;
struct acpi_device *device;
struct input_dev *input_dev;
struct backlight_device *backlight;
- unsigned int keymap[KEYMAP_SIZE];
};
struct pcc_keyinput {
@@ -267,7 +267,7 @@ static inline int acpi_pcc_get_sqty(struct acpi_device *device)
}
}
-static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf)
+static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc)
{
acpi_status status;
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
@@ -285,6 +285,7 @@ static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf)
hkey = buffer.pointer;
if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid HKEY.SINF\n"));
+ status = AE_ERROR;
goto end;
}
@@ -298,12 +299,12 @@ static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf)
for (i = 0; i < hkey->package.count; i++) {
union acpi_object *element = &(hkey->package.elements[i]);
if (likely(element->type == ACPI_TYPE_INTEGER)) {
- sinf[i] = element->integer.value;
+ pcc->sinf[i] = element->integer.value;
} else
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Invalid HKEY.SINF data\n"));
}
- sinf[hkey->package.count] = -1;
+ pcc->sinf[hkey->package.count] = -1;
end:
kfree(buffer.pointer);
@@ -321,7 +322,7 @@ static int bl_get(struct backlight_device *bd)
{
struct pcc_acpi *pcc = bl_get_data(bd);
- if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return pcc->sinf[SINF_AC_CUR_BRIGHT];
@@ -333,7 +334,7 @@ static int bl_set_status(struct backlight_device *bd)
int bright = bd->props.brightness;
int rc;
- if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT])
@@ -367,7 +368,7 @@ static ssize_t show_numbatt(struct device *dev, struct device_attribute *attr,
struct acpi_device *acpi = to_acpi_device(dev);
struct pcc_acpi *pcc = acpi_driver_data(acpi);
- if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]);
@@ -379,7 +380,7 @@ static ssize_t show_lcdtype(struct device *dev, struct device_attribute *attr,
struct acpi_device *acpi = to_acpi_device(dev);
struct pcc_acpi *pcc = acpi_driver_data(acpi);
- if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_LCD_TYPE]);
@@ -391,7 +392,7 @@ static ssize_t show_mute(struct device *dev, struct device_attribute *attr,
struct acpi_device *acpi = to_acpi_device(dev);
struct pcc_acpi *pcc = acpi_driver_data(acpi);
- if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_MUTE]);
@@ -403,7 +404,7 @@ static ssize_t show_sticky(struct device *dev, struct device_attribute *attr,
struct acpi_device *acpi = to_acpi_device(dev);
struct pcc_acpi *pcc = acpi_driver_data(acpi);
- if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_STICKY_KEY]);
@@ -446,56 +447,10 @@ static struct attribute_group pcc_attr_group = {
/* hotkey input device driver */
-static int pcc_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
-{
- struct pcc_acpi *pcc = input_get_drvdata(dev);
-
- if (scancode >= ARRAY_SIZE(pcc->keymap))
- return -EINVAL;
-
- *keycode = pcc->keymap[scancode];
-
- return 0;
-}
-
-static int keymap_get_by_keycode(struct pcc_acpi *pcc, unsigned int keycode)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++) {
- if (pcc->keymap[i] == keycode)
- return i+1;
- }
-
- return 0;
-}
-
-static int pcc_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
-{
- struct pcc_acpi *pcc = input_get_drvdata(dev);
- int oldkeycode;
-
- if (scancode >= ARRAY_SIZE(pcc->keymap))
- return -EINVAL;
-
- oldkeycode = pcc->keymap[scancode];
- pcc->keymap[scancode] = keycode;
-
- set_bit(keycode, dev->keybit);
-
- if (!keymap_get_by_keycode(pcc, oldkeycode))
- clear_bit(oldkeycode, dev->keybit);
-
- return 0;
-}
-
static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
{
struct input_dev *hotk_input_dev = pcc->input_dev;
int rc;
- int key_code, hkey_num;
unsigned long long result;
rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY,
@@ -508,25 +463,10 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result);
- hkey_num = result & 0xf;
-
- if (hkey_num < 0 || hkey_num >= ARRAY_SIZE(pcc->keymap)) {
+ if (!sparse_keymap_report_event(hotk_input_dev,
+ result & 0xf, result & 0x80, false))
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "hotkey number out of range: %d\n",
- hkey_num));
- return;
- }
-
- key_code = pcc->keymap[hkey_num];
-
- if (key_code != KEY_RESERVED) {
- int pushed = (result & 0x80) ? TRUE : FALSE;
-
- input_report_key(hotk_input_dev, key_code, pushed);
- input_sync(hotk_input_dev);
- }
-
- return;
+ "Unknown hotkey event: %d\n", result));
}
static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event)
@@ -545,40 +485,55 @@ static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event)
static int acpi_pcc_init_input(struct pcc_acpi *pcc)
{
- int i, rc;
+ struct input_dev *input_dev;
+ int error;
- pcc->input_dev = input_allocate_device();
- if (!pcc->input_dev) {
+ input_dev = input_allocate_device();
+ if (!input_dev) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Couldn't allocate input device for hotkey"));
return -ENOMEM;
}
- pcc->input_dev->evbit[0] = BIT(EV_KEY);
-
- pcc->input_dev->name = ACPI_PCC_DRIVER_NAME;
- pcc->input_dev->phys = ACPI_PCC_INPUT_PHYS;
- pcc->input_dev->id.bustype = BUS_HOST;
- pcc->input_dev->id.vendor = 0x0001;
- pcc->input_dev->id.product = 0x0001;
- pcc->input_dev->id.version = 0x0100;
- pcc->input_dev->getkeycode = pcc_getkeycode;
- pcc->input_dev->setkeycode = pcc_setkeycode;
+ input_dev->name = ACPI_PCC_DRIVER_NAME;
+ input_dev->phys = ACPI_PCC_INPUT_PHYS;
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->id.vendor = 0x0001;
+ input_dev->id.product = 0x0001;
+ input_dev->id.version = 0x0100;
- /* load initial keymap */
- memcpy(pcc->keymap, initial_keymap, sizeof(pcc->keymap));
+ error = sparse_keymap_setup(input_dev, panasonic_keymap, NULL);
+ if (error) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to setup input device keymap\n"));
+ goto err_free_dev;
+ }
- for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++)
- __set_bit(pcc->keymap[i], pcc->input_dev->keybit);
- __clear_bit(KEY_RESERVED, pcc->input_dev->keybit);
+ error = input_register_device(input_dev);
+ if (error) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to register input device\n"));
+ goto err_free_keymap;
+ }
- input_set_drvdata(pcc->input_dev, pcc);
+ pcc->input_dev = input_dev;
+ return 0;
- rc = input_register_device(pcc->input_dev);
- if (rc < 0)
- input_free_device(pcc->input_dev);
+ err_free_keymap:
+ sparse_keymap_free(input_dev);
+ err_free_dev:
+ input_free_device(input_dev);
+ return error;
+}
- return rc;
+static void acpi_pcc_destroy_input(struct pcc_acpi *pcc)
+{
+ sparse_keymap_free(pcc->input_dev);
+ input_unregister_device(pcc->input_dev);
+ /*
+ * No need to input_free_device() since core input API refcounts
+ * and free()s the device.
+ */
}
/* kernel module interface */
@@ -636,12 +591,13 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error installing keyinput handler\n"));
- goto out_hotkey;
+ goto out_sinf;
}
- if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) {
+ if (!acpi_pcc_retrieve_biosdata(pcc)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Couldn't retrieve BIOS data\n"));
+ result = -EIO;
goto out_input;
}
/* initialize backlight */
@@ -651,7 +607,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
&pcc_backlight_ops, &props);
if (IS_ERR(pcc->backlight)) {
result = PTR_ERR(pcc->backlight);
- goto out_sinf;
+ goto out_input;
}
/* read the initial brightness setting from the hardware */
@@ -669,12 +625,10 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
out_backlight:
backlight_device_unregister(pcc->backlight);
+out_input:
+ acpi_pcc_destroy_input(pcc);
out_sinf:
kfree(pcc->sinf);
-out_input:
- input_unregister_device(pcc->input_dev);
- /* no need to input_free_device() since core input API refcount and
- * free()s the device */
out_hotkey:
kfree(pcc);
@@ -709,9 +663,7 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type)
backlight_device_unregister(pcc->backlight);
- input_unregister_device(pcc->input_dev);
- /* no need to input_free_device() since core input API refcount and
- * free()s the device */
+ acpi_pcc_destroy_input(pcc);
kfree(pcc->sinf);
kfree(pcc);
diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c
index ff4b476f1950..1d07d6d09f27 100644
--- a/drivers/platform/x86/topstar-laptop.c
+++ b/drivers/platform/x86/topstar-laptop.c
@@ -19,6 +19,7 @@
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
#define ACPI_TOPSTAR_CLASS "topstar"
@@ -26,52 +27,37 @@ struct topstar_hkey {
struct input_dev *inputdev;
};
-struct tps_key_entry {
- u8 code;
- u16 keycode;
-};
-
-static struct tps_key_entry topstar_keymap[] = {
- { 0x80, KEY_BRIGHTNESSUP },
- { 0x81, KEY_BRIGHTNESSDOWN },
- { 0x83, KEY_VOLUMEUP },
- { 0x84, KEY_VOLUMEDOWN },
- { 0x85, KEY_MUTE },
- { 0x86, KEY_SWITCHVIDEOMODE },
- { 0x87, KEY_F13 }, /* touchpad enable/disable key */
- { 0x88, KEY_WLAN },
- { 0x8a, KEY_WWW },
- { 0x8b, KEY_MAIL },
- { 0x8c, KEY_MEDIA },
- { 0x96, KEY_F14 }, /* G key? */
- { }
-};
-
-static struct tps_key_entry *tps_get_key_by_scancode(unsigned int code)
-{
- struct tps_key_entry *key;
-
- for (key = topstar_keymap; key->code; key++)
- if (code == key->code)
- return key;
+static const struct key_entry topstar_keymap[] = {
+ { KE_KEY, 0x80, { KEY_BRIGHTNESSUP } },
+ { KE_KEY, 0x81, { KEY_BRIGHTNESSDOWN } },
+ { KE_KEY, 0x83, { KEY_VOLUMEUP } },
+ { KE_KEY, 0x84, { KEY_VOLUMEDOWN } },
+ { KE_KEY, 0x85, { KEY_MUTE } },
+ { KE_KEY, 0x86, { KEY_SWITCHVIDEOMODE } },
+ { KE_KEY, 0x87, { KEY_F13 } }, /* touchpad enable/disable key */
+ { KE_KEY, 0x88, { KEY_WLAN } },
+ { KE_KEY, 0x8a, { KEY_WWW } },
+ { KE_KEY, 0x8b, { KEY_MAIL } },
+ { KE_KEY, 0x8c, { KEY_MEDIA } },
- return NULL;
-}
-
-static struct tps_key_entry *tps_get_key_by_keycode(unsigned int code)
-{
- struct tps_key_entry *key;
+ /* Known non hotkey events don't handled or that we don't care yet */
+ { KE_IGNORE, 0x8e, },
+ { KE_IGNORE, 0x8f, },
+ { KE_IGNORE, 0x90, },
- for (key = topstar_keymap; key->code; key++)
- if (code == key->keycode)
- return key;
+ /*
+ * 'G key' generate two event codes, convert to only
+ * one event/key code for now, consider replacing by
+ * a switch (3G switch - SW_3G?)
+ */
+ { KE_KEY, 0x96, { KEY_F14 } },
+ { KE_KEY, 0x97, { KEY_F14 } },
- return NULL;
-}
+ { KE_END, 0 }
+};
static void acpi_topstar_notify(struct acpi_device *device, u32 event)
{
- struct tps_key_entry *key;
static bool dup_evnt[2];
bool *dup;
struct topstar_hkey *hkey = acpi_driver_data(device);
@@ -86,27 +72,8 @@ static void acpi_topstar_notify(struct acpi_device *device, u32 event)
*dup = true;
}
- /*
- * 'G key' generate two event codes, convert to only
- * one event/key code for now (3G switch?)
- */
- if (event == 0x97)
- event = 0x96;
-
- key = tps_get_key_by_scancode(event);
- if (key) {
- input_report_key(hkey->inputdev, key->keycode, 1);
- input_sync(hkey->inputdev);
- input_report_key(hkey->inputdev, key->keycode, 0);
- input_sync(hkey->inputdev);
- return;
- }
-
- /* Known non hotkey events don't handled or that we don't care yet */
- if (event == 0x8e || event == 0x8f || event == 0x90)
- return;
-
- pr_info("unknown event = 0x%02x\n", event);
+ if (!sparse_keymap_report_event(hkey->inputdev, event, 1, true))
+ pr_info("unknown event = 0x%02x\n", event);
}
static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state)
@@ -127,62 +94,41 @@ static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state)
return 0;
}
-static int topstar_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
-{
- struct tps_key_entry *key = tps_get_key_by_scancode(scancode);
-
- if (!key)
- return -EINVAL;
-
- *keycode = key->keycode;
- return 0;
-}
-
-static int topstar_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
-{
- struct tps_key_entry *key;
- int old_keycode;
-
- key = tps_get_key_by_scancode(scancode);
-
- if (!key)
- return -EINVAL;
-
- old_keycode = key->keycode;
- key->keycode = keycode;
- set_bit(keycode, dev->keybit);
- if (!tps_get_key_by_keycode(old_keycode))
- clear_bit(old_keycode, dev->keybit);
- return 0;
-}
-
static int acpi_topstar_init_hkey(struct topstar_hkey *hkey)
{
- struct tps_key_entry *key;
+ struct input_dev *input;
+ int error;
- hkey->inputdev = input_allocate_device();
- if (!hkey->inputdev) {
+ input = input_allocate_device();
+ if (!input) {
pr_err("Unable to allocate input device\n");
- return -ENODEV;
+ return -ENOMEM;
}
- hkey->inputdev->name = "Topstar Laptop extra buttons";
- hkey->inputdev->phys = "topstar/input0";
- hkey->inputdev->id.bustype = BUS_HOST;
- hkey->inputdev->getkeycode = topstar_getkeycode;
- hkey->inputdev->setkeycode = topstar_setkeycode;
- for (key = topstar_keymap; key->code; key++) {
- set_bit(EV_KEY, hkey->inputdev->evbit);
- set_bit(key->keycode, hkey->inputdev->keybit);
+
+ input->name = "Topstar Laptop extra buttons";
+ input->phys = "topstar/input0";
+ input->id.bustype = BUS_HOST;
+
+ error = sparse_keymap_setup(input, topstar_keymap, NULL);
+ if (error) {
+ pr_err("Unable to setup input device keymap\n");
+ goto err_free_dev;
}
- if (input_register_device(hkey->inputdev)) {
+
+ error = input_register_device(input);
+ if (error) {
pr_err("Unable to register input device\n");
- input_free_device(hkey->inputdev);
- return -ENODEV;
+ goto err_free_keymap;
}
+ hkey->inputdev = input;
return 0;
+
+ err_free_keymap:
+ sparse_keymap_free(input);
+ err_free_dev:
+ input_free_device(input);
+ return error;
}
static int acpi_topstar_add(struct acpi_device *device)
@@ -216,6 +162,7 @@ static int acpi_topstar_remove(struct acpi_device *device, int type)
acpi_topstar_fncx_switch(device, false);
+ sparse_keymap_free(tps_hkey->inputdev);
input_unregister_device(tps_hkey->inputdev);
kfree(tps_hkey);
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 7d67a45bb2b0..06f304f46e02 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -48,6 +48,7 @@
#include <linux/platform_device.h>
#include <linux/rfkill.h>
#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
#include <linux/leds.h>
#include <linux/slab.h>
@@ -121,36 +122,28 @@ static const struct acpi_device_id toshiba_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
-struct key_entry {
- char type;
- u16 code;
- u16 keycode;
-};
-
-enum {KE_KEY, KE_END};
-
-static struct key_entry toshiba_acpi_keymap[] = {
- {KE_KEY, 0x101, KEY_MUTE},
- {KE_KEY, 0x102, KEY_ZOOMOUT},
- {KE_KEY, 0x103, KEY_ZOOMIN},
- {KE_KEY, 0x13b, KEY_COFFEE},
- {KE_KEY, 0x13c, KEY_BATTERY},
- {KE_KEY, 0x13d, KEY_SLEEP},
- {KE_KEY, 0x13e, KEY_SUSPEND},
- {KE_KEY, 0x13f, KEY_SWITCHVIDEOMODE},
- {KE_KEY, 0x140, KEY_BRIGHTNESSDOWN},
- {KE_KEY, 0x141, KEY_BRIGHTNESSUP},
- {KE_KEY, 0x142, KEY_WLAN},
- {KE_KEY, 0x143, KEY_PROG1},
- {KE_KEY, 0xb05, KEY_PROG2},
- {KE_KEY, 0xb06, KEY_WWW},
- {KE_KEY, 0xb07, KEY_MAIL},
- {KE_KEY, 0xb30, KEY_STOP},
- {KE_KEY, 0xb31, KEY_PREVIOUSSONG},
- {KE_KEY, 0xb32, KEY_NEXTSONG},
- {KE_KEY, 0xb33, KEY_PLAYPAUSE},
- {KE_KEY, 0xb5a, KEY_MEDIA},
- {KE_END, 0, 0},
+static const struct key_entry toshiba_acpi_keymap[] __initconst = {
+ { KE_KEY, 0x101, { KEY_MUTE } },
+ { KE_KEY, 0x102, { KEY_ZOOMOUT } },
+ { KE_KEY, 0x103, { KEY_ZOOMIN } },
+ { KE_KEY, 0x13b, { KEY_COFFEE } },
+ { KE_KEY, 0x13c, { KEY_BATTERY } },
+ { KE_KEY, 0x13d, { KEY_SLEEP } },
+ { KE_KEY, 0x13e, { KEY_SUSPEND } },
+ { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } },
+ { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
+ { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
+ { KE_KEY, 0x142, { KEY_WLAN } },
+ { KE_KEY, 0x143, { KEY_PROG1 } },
+ { KE_KEY, 0xb05, { KEY_PROG2 } },
+ { KE_KEY, 0xb06, { KEY_WWW } },
+ { KE_KEY, 0xb07, { KEY_MAIL } },
+ { KE_KEY, 0xb30, { KEY_STOP } },
+ { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } },
+ { KE_KEY, 0xb32, { KEY_NEXTSONG } },
+ { KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
+ { KE_KEY, 0xb5a, { KEY_MEDIA } },
+ { KE_END, 0 },
};
/* utility
@@ -852,64 +845,9 @@ static struct backlight_ops toshiba_backlight_data = {
.update_status = set_lcd_status,
};
-static struct key_entry *toshiba_acpi_get_entry_by_scancode(unsigned int code)
-{
- struct key_entry *key;
-
- for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
- if (code == key->code)
- return key;
-
- return NULL;
-}
-
-static struct key_entry *toshiba_acpi_get_entry_by_keycode(unsigned int code)
-{
- struct key_entry *key;
-
- for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
- if (code == key->keycode && key->type == KE_KEY)
- return key;
-
- return NULL;
-}
-
-static int toshiba_acpi_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
-{
- struct key_entry *key = toshiba_acpi_get_entry_by_scancode(scancode);
-
- if (key && key->type == KE_KEY) {
- *keycode = key->keycode;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int toshiba_acpi_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
-{
- struct key_entry *key;
- unsigned int old_keycode;
-
- key = toshiba_acpi_get_entry_by_scancode(scancode);
- if (key && key->type == KE_KEY) {
- old_keycode = key->keycode;
- key->keycode = keycode;
- set_bit(keycode, dev->keybit);
- if (!toshiba_acpi_get_entry_by_keycode(old_keycode))
- clear_bit(old_keycode, dev->keybit);
- return 0;
- }
-
- return -EINVAL;
-}
-
static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
{
u32 hci_result, value;
- struct key_entry *key;
if (event != 0x80)
return;
@@ -922,19 +860,11 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
if (value & 0x80)
continue;
- key = toshiba_acpi_get_entry_by_scancode
- (value);
- if (!key) {
+ if (!sparse_keymap_report_event(toshiba_acpi.hotkey_dev,
+ value, 1, true)) {
printk(MY_INFO "Unknown key %x\n",
value);
- continue;
}
- input_report_key(toshiba_acpi.hotkey_dev,
- key->keycode, 1);
- input_sync(toshiba_acpi.hotkey_dev);
- input_report_key(toshiba_acpi.hotkey_dev,
- key->keycode, 0);
- input_sync(toshiba_acpi.hotkey_dev);
} else if (hci_result == HCI_NOT_SUPPORTED) {
/* This is a workaround for an unresolved issue on
* some machines where system events sporadically
@@ -945,34 +875,17 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
} while (hci_result != HCI_EMPTY);
}
-static int toshiba_acpi_setup_keyboard(char *device)
+static int __init toshiba_acpi_setup_keyboard(char *device)
{
acpi_status status;
- acpi_handle handle;
- int result;
- const struct key_entry *key;
+ int error;
- status = acpi_get_handle(NULL, device, &handle);
+ status = acpi_get_handle(NULL, device, &toshiba_acpi.handle);
if (ACPI_FAILURE(status)) {
printk(MY_INFO "Unable to get notification device\n");
return -ENODEV;
}
- toshiba_acpi.handle = handle;
-
- status = acpi_evaluate_object(handle, "ENAB", NULL, NULL);
- if (ACPI_FAILURE(status)) {
- printk(MY_INFO "Unable to enable hotkeys\n");
- return -ENODEV;
- }
-
- status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY,
- toshiba_acpi_notify, NULL);
- if (ACPI_FAILURE(status)) {
- printk(MY_INFO "Unable to install hotkey notification\n");
- return -ENODEV;
- }
-
toshiba_acpi.hotkey_dev = input_allocate_device();
if (!toshiba_acpi.hotkey_dev) {
printk(MY_INFO "Unable to register input device\n");
@@ -982,27 +895,54 @@ static int toshiba_acpi_setup_keyboard(char *device)
toshiba_acpi.hotkey_dev->name = "Toshiba input device";
toshiba_acpi.hotkey_dev->phys = device;
toshiba_acpi.hotkey_dev->id.bustype = BUS_HOST;
- toshiba_acpi.hotkey_dev->getkeycode = toshiba_acpi_getkeycode;
- toshiba_acpi.hotkey_dev->setkeycode = toshiba_acpi_setkeycode;
- for (key = toshiba_acpi_keymap; key->type != KE_END; key++) {
- set_bit(EV_KEY, toshiba_acpi.hotkey_dev->evbit);
- set_bit(key->keycode, toshiba_acpi.hotkey_dev->keybit);
+ error = sparse_keymap_setup(toshiba_acpi.hotkey_dev,
+ toshiba_acpi_keymap, NULL);
+ if (error)
+ goto err_free_dev;
+
+ status = acpi_install_notify_handler(toshiba_acpi.handle,
+ ACPI_DEVICE_NOTIFY, toshiba_acpi_notify, NULL);
+ if (ACPI_FAILURE(status)) {
+ printk(MY_INFO "Unable to install hotkey notification\n");
+ error = -ENODEV;
+ goto err_free_keymap;
+ }
+
+ status = acpi_evaluate_object(toshiba_acpi.handle, "ENAB", NULL, NULL);
+ if (ACPI_FAILURE(status)) {
+ printk(MY_INFO "Unable to enable hotkeys\n");
+ error = -ENODEV;
+ goto err_remove_notify;
}
- result = input_register_device(toshiba_acpi.hotkey_dev);
- if (result) {
+ error = input_register_device(toshiba_acpi.hotkey_dev);
+ if (error) {
printk(MY_INFO "Unable to register input device\n");
- return result;
+ goto err_remove_notify;
}
return 0;
+
+ err_remove_notify:
+ acpi_remove_notify_handler(toshiba_acpi.handle,
+ ACPI_DEVICE_NOTIFY, toshiba_acpi_notify);
+ err_free_keymap:
+ sparse_keymap_free(toshiba_acpi.hotkey_dev);
+ err_free_dev:
+ input_free_device(toshiba_acpi.hotkey_dev);
+ toshiba_acpi.hotkey_dev = NULL;
+ return error;
}
static void toshiba_acpi_exit(void)
{
- if (toshiba_acpi.hotkey_dev)
+ if (toshiba_acpi.hotkey_dev) {
+ acpi_remove_notify_handler(toshiba_acpi.handle,
+ ACPI_DEVICE_NOTIFY, toshiba_acpi_notify);
+ sparse_keymap_free(toshiba_acpi.hotkey_dev);
input_unregister_device(toshiba_acpi.hotkey_dev);
+ }
if (toshiba_acpi.bt_rfk) {
rfkill_unregister(toshiba_acpi.bt_rfk);
@@ -1017,9 +957,6 @@ static void toshiba_acpi_exit(void)
if (toshiba_proc_dir)
remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
- acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY,
- toshiba_acpi_notify);
-
if (toshiba_acpi.illumination_installed)
led_classdev_unregister(&toshiba_led);
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index b2978a04317f..104b77c87ef5 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -27,6 +27,8 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -44,9 +46,8 @@ MODULE_LICENSE("GPL");
#define ACPI_WMI_CLASS "wmi"
-#define PREFIX "ACPI: WMI: "
-
static DEFINE_MUTEX(wmi_data_lock);
+static LIST_HEAD(wmi_block_list);
struct guid_block {
char guid[16];
@@ -67,10 +68,9 @@ struct wmi_block {
acpi_handle handle;
wmi_notify_handler handler;
void *handler_data;
- struct device *dev;
+ struct device dev;
};
-static struct wmi_block wmi_blocks;
/*
* If the GUID data block is marked as expensive, we must enable and
@@ -110,7 +110,7 @@ static struct acpi_driver acpi_wmi_driver = {
.add = acpi_wmi_add,
.remove = acpi_wmi_remove,
.notify = acpi_wmi_notify,
- },
+ },
};
/*
@@ -128,30 +128,18 @@ static struct acpi_driver acpi_wmi_driver = {
*/
static int wmi_parse_hexbyte(const u8 *src)
{
- unsigned int x; /* For correct wrapping */
int h;
+ int value;
/* high part */
- x = src[0];
- if (x - '0' <= '9' - '0') {
- h = x - '0';
- } else if (x - 'a' <= 'f' - 'a') {
- h = x - 'a' + 10;
- } else if (x - 'A' <= 'F' - 'A') {
- h = x - 'A' + 10;
- } else {
+ h = value = hex_to_bin(src[0]);
+ if (value < 0)
return -1;
- }
- h <<= 4;
/* low part */
- x = src[1];
- if (x - '0' <= '9' - '0')
- return h | (x - '0');
- if (x - 'a' <= 'f' - 'a')
- return h | (x - 'a' + 10);
- if (x - 'A' <= 'F' - 'A')
- return h | (x - 'A' + 10);
+ value = hex_to_bin(src[1]);
+ if (value >= 0)
+ return (h << 4) | value;
return -1;
}
@@ -232,7 +220,7 @@ static int wmi_gtoa(const char *in, char *out)
for (i = 10; i <= 15; i++)
out += sprintf(out, "%02X", in[i] & 0xFF);
- out = '\0';
+ *out = '\0';
return 0;
}
@@ -246,7 +234,7 @@ static bool find_guid(const char *guid_string, struct wmi_block **out)
wmi_parse_guid(guid_string, tmp);
wmi_swap_bytes(tmp, guid_input);
- list_for_each(p, &wmi_blocks.list) {
+ list_for_each(p, &wmi_block_list) {
wblock = list_entry(p, struct wmi_block, list);
block = &wblock->gblock;
@@ -487,30 +475,29 @@ const struct acpi_buffer *in)
}
EXPORT_SYMBOL_GPL(wmi_set_block);
-static void wmi_dump_wdg(struct guid_block *g)
+static void wmi_dump_wdg(const struct guid_block *g)
{
char guid_string[37];
wmi_gtoa(g->guid, guid_string);
- printk(KERN_INFO PREFIX "%s:\n", guid_string);
- printk(KERN_INFO PREFIX "\tobject_id: %c%c\n",
- g->object_id[0], g->object_id[1]);
- printk(KERN_INFO PREFIX "\tnotify_id: %02X\n", g->notify_id);
- printk(KERN_INFO PREFIX "\treserved: %02X\n", g->reserved);
- printk(KERN_INFO PREFIX "\tinstance_count: %d\n", g->instance_count);
- printk(KERN_INFO PREFIX "\tflags: %#x", g->flags);
+
+ pr_info("%s:\n", guid_string);
+ pr_info("\tobject_id: %c%c\n", g->object_id[0], g->object_id[1]);
+ pr_info("\tnotify_id: %02X\n", g->notify_id);
+ pr_info("\treserved: %02X\n", g->reserved);
+ pr_info("\tinstance_count: %d\n", g->instance_count);
+ pr_info("\tflags: %#x ", g->flags);
if (g->flags) {
- printk(" ");
if (g->flags & ACPI_WMI_EXPENSIVE)
- printk("ACPI_WMI_EXPENSIVE ");
+ pr_cont("ACPI_WMI_EXPENSIVE ");
if (g->flags & ACPI_WMI_METHOD)
- printk("ACPI_WMI_METHOD ");
+ pr_cont("ACPI_WMI_METHOD ");
if (g->flags & ACPI_WMI_STRING)
- printk("ACPI_WMI_STRING ");
+ pr_cont("ACPI_WMI_STRING ");
if (g->flags & ACPI_WMI_EVENT)
- printk("ACPI_WMI_EVENT ");
+ pr_cont("ACPI_WMI_EVENT ");
}
- printk("\n");
+ pr_cont("\n");
}
@@ -522,7 +509,7 @@ static void wmi_notify_debug(u32 value, void *context)
status = wmi_get_event_data(value, &response);
if (status != AE_OK) {
- printk(KERN_INFO "wmi: bad event status 0x%x\n", status);
+ pr_info("bad event status 0x%x\n", status);
return;
}
@@ -531,22 +518,22 @@ static void wmi_notify_debug(u32 value, void *context)
if (!obj)
return;
- printk(KERN_INFO PREFIX "DEBUG Event ");
+ pr_info("DEBUG Event ");
switch(obj->type) {
case ACPI_TYPE_BUFFER:
- printk("BUFFER_TYPE - length %d\n", obj->buffer.length);
+ pr_cont("BUFFER_TYPE - length %d\n", obj->buffer.length);
break;
case ACPI_TYPE_STRING:
- printk("STRING_TYPE - %s\n", obj->string.pointer);
+ pr_cont("STRING_TYPE - %s\n", obj->string.pointer);
break;
case ACPI_TYPE_INTEGER:
- printk("INTEGER_TYPE - %llu\n", obj->integer.value);
+ pr_cont("INTEGER_TYPE - %llu\n", obj->integer.value);
break;
case ACPI_TYPE_PACKAGE:
- printk("PACKAGE_TYPE - %d elements\n", obj->package.count);
+ pr_cont("PACKAGE_TYPE - %d elements\n", obj->package.count);
break;
default:
- printk("object type 0x%X\n", obj->type);
+ pr_cont("object type 0x%X\n", obj->type);
}
kfree(obj);
}
@@ -633,7 +620,7 @@ acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
params[0].type = ACPI_TYPE_INTEGER;
params[0].integer.value = event;
- list_for_each(p, &wmi_blocks.list) {
+ list_for_each(p, &wmi_block_list) {
wblock = list_entry(p, struct wmi_block, list);
gblock = &wblock->gblock;
@@ -662,7 +649,7 @@ EXPORT_SYMBOL_GPL(wmi_has_guid);
/*
* sysfs interface
*/
-static ssize_t show_modalias(struct device *dev, struct device_attribute *attr,
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
char guid_string[37];
@@ -676,7 +663,11 @@ static ssize_t show_modalias(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "wmi:%s\n", guid_string);
}
-static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
+
+static struct device_attribute wmi_dev_attrs[] = {
+ __ATTR_RO(modalias),
+ __ATTR_NULL
+};
static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
{
@@ -702,108 +693,71 @@ static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
static void wmi_dev_free(struct device *dev)
{
- kfree(dev);
+ struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev);
+
+ kfree(wmi_block);
}
static struct class wmi_class = {
.name = "wmi",
.dev_release = wmi_dev_free,
.dev_uevent = wmi_dev_uevent,
+ .dev_attrs = wmi_dev_attrs,
};
-static int wmi_create_devs(void)
+static struct wmi_block *wmi_create_device(const struct guid_block *gblock,
+ acpi_handle handle)
{
- int result;
- char guid_string[37];
- struct guid_block *gblock;
struct wmi_block *wblock;
- struct list_head *p;
- struct device *guid_dev;
-
- /* Create devices for all the GUIDs */
- list_for_each(p, &wmi_blocks.list) {
- wblock = list_entry(p, struct wmi_block, list);
-
- guid_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
- if (!guid_dev)
- return -ENOMEM;
-
- wblock->dev = guid_dev;
-
- guid_dev->class = &wmi_class;
- dev_set_drvdata(guid_dev, wblock);
-
- gblock = &wblock->gblock;
-
- wmi_gtoa(gblock->guid, guid_string);
- dev_set_name(guid_dev, guid_string);
-
- result = device_register(guid_dev);
- if (result)
- return result;
+ int error;
+ char guid_string[37];
- result = device_create_file(guid_dev, &dev_attr_modalias);
- if (result)
- return result;
+ wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
+ if (!wblock) {
+ error = -ENOMEM;
+ goto err_out;
}
- return 0;
-}
+ wblock->handle = handle;
+ wblock->gblock = *gblock;
-static void wmi_remove_devs(void)
-{
- struct guid_block *gblock;
- struct wmi_block *wblock;
- struct list_head *p;
- struct device *guid_dev;
+ wblock->dev.class = &wmi_class;
- /* Delete devices for all the GUIDs */
- list_for_each(p, &wmi_blocks.list) {
- wblock = list_entry(p, struct wmi_block, list);
+ wmi_gtoa(gblock->guid, guid_string);
+ dev_set_name(&wblock->dev, guid_string);
- guid_dev = wblock->dev;
- gblock = &wblock->gblock;
+ dev_set_drvdata(&wblock->dev, wblock);
- device_remove_file(guid_dev, &dev_attr_modalias);
+ error = device_register(&wblock->dev);
+ if (error)
+ goto err_free;
- device_unregister(guid_dev);
- }
-}
+ list_add_tail(&wblock->list, &wmi_block_list);
+ return wblock;
-static void wmi_class_exit(void)
-{
- wmi_remove_devs();
- class_unregister(&wmi_class);
+err_free:
+ kfree(wblock);
+err_out:
+ return ERR_PTR(error);
}
-static int wmi_class_init(void)
+static void wmi_free_devices(void)
{
- int ret;
-
- ret = class_register(&wmi_class);
- if (ret)
- return ret;
+ struct wmi_block *wblock, *next;
- ret = wmi_create_devs();
- if (ret)
- wmi_class_exit();
-
- return ret;
+ /* Delete devices for all the GUIDs */
+ list_for_each_entry_safe(wblock, next, &wmi_block_list, list)
+ device_unregister(&wblock->dev);
}
static bool guid_already_parsed(const char *guid_string)
{
- struct guid_block *gblock;
struct wmi_block *wblock;
- struct list_head *p;
- list_for_each(p, &wmi_blocks.list) {
- wblock = list_entry(p, struct wmi_block, list);
- gblock = &wblock->gblock;
-
- if (strncmp(gblock->guid, guid_string, 16) == 0)
+ list_for_each_entry(wblock, &wmi_block_list, list)
+ if (strncmp(wblock->gblock.guid, guid_string, 16) == 0)
return true;
- }
+
return false;
}
@@ -814,30 +768,29 @@ static acpi_status parse_wdg(acpi_handle handle)
{
struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
union acpi_object *obj;
- struct guid_block *gblock;
+ const struct guid_block *gblock;
struct wmi_block *wblock;
char guid_string[37];
acpi_status status;
+ int retval;
u32 i, total;
status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
-
if (ACPI_FAILURE(status))
- return status;
+ return -ENXIO;
obj = (union acpi_object *) out.pointer;
+ if (!obj)
+ return -ENXIO;
- if (obj->type != ACPI_TYPE_BUFFER)
- return AE_ERROR;
-
- total = obj->buffer.length / sizeof(struct guid_block);
-
- gblock = kmemdup(obj->buffer.pointer, obj->buffer.length, GFP_KERNEL);
- if (!gblock) {
- status = AE_NO_MEMORY;
+ if (obj->type != ACPI_TYPE_BUFFER) {
+ retval = -ENXIO;
goto out_free_pointer;
}
+ gblock = (const struct guid_block *)obj->buffer.pointer;
+ total = obj->buffer.length / sizeof(struct guid_block);
+
for (i = 0; i < total; i++) {
/*
Some WMI devices, like those for nVidia hooks, have a
@@ -848,34 +801,32 @@ static acpi_status parse_wdg(acpi_handle handle)
*/
if (guid_already_parsed(gblock[i].guid) == true) {
wmi_gtoa(gblock[i].guid, guid_string);
- printk(KERN_INFO PREFIX "Skipping duplicate GUID %s\n",
- guid_string);
+ pr_info("Skipping duplicate GUID %s\n", guid_string);
continue;
}
+
if (debug_dump_wdg)
wmi_dump_wdg(&gblock[i]);
- wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
- if (!wblock) {
- status = AE_NO_MEMORY;
- goto out_free_gblock;
+ wblock = wmi_create_device(&gblock[i], handle);
+ if (IS_ERR(wblock)) {
+ retval = PTR_ERR(wblock);
+ wmi_free_devices();
+ break;
}
- wblock->gblock = gblock[i];
- wblock->handle = handle;
if (debug_event) {
wblock->handler = wmi_notify_debug;
- status = wmi_method_enable(wblock, 1);
+ wmi_method_enable(wblock, 1);
}
- list_add_tail(&wblock->list, &wmi_blocks.list);
}
-out_free_gblock:
- kfree(gblock);
+ retval = 0;
+
out_free_pointer:
kfree(out.pointer);
- return status;
+ return retval;
}
/*
@@ -929,7 +880,7 @@ static void acpi_wmi_notify(struct acpi_device *device, u32 event)
struct list_head *p;
char guid_string[37];
- list_for_each(p, &wmi_blocks.list) {
+ list_for_each(p, &wmi_block_list) {
wblock = list_entry(p, struct wmi_block, list);
block = &wblock->gblock;
@@ -939,8 +890,7 @@ static void acpi_wmi_notify(struct acpi_device *device, u32 event)
wblock->handler(event, wblock->handler_data);
if (debug_event) {
wmi_gtoa(wblock->gblock.guid, guid_string);
- printk(KERN_INFO PREFIX "DEBUG Event GUID:"
- " %s\n", guid_string);
+ pr_info("DEBUG Event GUID: %s\n", guid_string);
}
acpi_bus_generate_netlink_event(
@@ -955,6 +905,7 @@ static int acpi_wmi_remove(struct acpi_device *device, int type)
{
acpi_remove_address_space_handler(device->handle,
ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
+ wmi_free_devices();
return 0;
}
@@ -962,68 +913,57 @@ static int acpi_wmi_remove(struct acpi_device *device, int type)
static int acpi_wmi_add(struct acpi_device *device)
{
acpi_status status;
- int result = 0;
+ int error;
status = acpi_install_address_space_handler(device->handle,
ACPI_ADR_SPACE_EC,
&acpi_wmi_ec_space_handler,
NULL, NULL);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- status = parse_wdg(device->handle);
if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Error installing EC region handler\n");
+ pr_err("Error installing EC region handler\n");
return -ENODEV;
}
- return result;
+ error = parse_wdg(device->handle);
+ if (error) {
+ acpi_remove_address_space_handler(device->handle,
+ ACPI_ADR_SPACE_EC,
+ &acpi_wmi_ec_space_handler);
+ pr_err("Failed to parse WDG method\n");
+ return error;
+ }
+
+ return 0;
}
static int __init acpi_wmi_init(void)
{
- int result;
-
- INIT_LIST_HEAD(&wmi_blocks.list);
+ int error;
if (acpi_disabled)
return -ENODEV;
- result = acpi_bus_register_driver(&acpi_wmi_driver);
+ error = class_register(&wmi_class);
+ if (error)
+ return error;
- if (result < 0) {
- printk(KERN_INFO PREFIX "Error loading mapper\n");
- return -ENODEV;
+ error = acpi_bus_register_driver(&acpi_wmi_driver);
+ if (error) {
+ pr_err("Error loading mapper\n");
+ class_unregister(&wmi_class);
+ return error;
}
- result = wmi_class_init();
- if (result) {
- acpi_bus_unregister_driver(&acpi_wmi_driver);
- return result;
- }
-
- printk(KERN_INFO PREFIX "Mapper loaded\n");
-
- return result;
+ pr_info("Mapper loaded\n");
+ return 0;
}
static void __exit acpi_wmi_exit(void)
{
- struct list_head *p, *tmp;
- struct wmi_block *wblock;
-
- wmi_class_exit();
-
acpi_bus_unregister_driver(&acpi_wmi_driver);
+ class_unregister(&wmi_class);
- list_for_each_safe(p, tmp, &wmi_blocks.list) {
- wblock = list_entry(p, struct wmi_block, list);
-
- list_del(p);
- kfree(wblock);
- }
-
- printk(KERN_INFO PREFIX "Mapper unloaded\n");
+ pr_info("Mapper unloaded\n");
}
subsys_initcall(acpi_wmi_init);
diff --git a/drivers/platform/x86/xo1-rfkill.c b/drivers/platform/x86/xo1-rfkill.c
new file mode 100644
index 000000000000..e549eeeda121
--- /dev/null
+++ b/drivers/platform/x86/xo1-rfkill.c
@@ -0,0 +1,85 @@
+/*
+ * Support for rfkill through the OLPC XO-1 laptop embedded controller
+ *
+ * Copyright (C) 2010 One Laptop per Child
+ *
+ * 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/platform_device.h>
+#include <linux/rfkill.h>
+
+#include <asm/olpc.h>
+
+static int rfkill_set_block(void *data, bool blocked)
+{
+ unsigned char cmd;
+ if (blocked)
+ cmd = EC_WLAN_ENTER_RESET;
+ else
+ cmd = EC_WLAN_LEAVE_RESET;
+
+ return olpc_ec_cmd(cmd, NULL, 0, NULL, 0);
+}
+
+static const struct rfkill_ops rfkill_ops = {
+ .set_block = rfkill_set_block,
+};
+
+static int __devinit xo1_rfkill_probe(struct platform_device *pdev)
+{
+ struct rfkill *rfk;
+ int r;
+
+ rfk = rfkill_alloc(pdev->name, &pdev->dev, RFKILL_TYPE_WLAN,
+ &rfkill_ops, NULL);
+ if (!rfk)
+ return -ENOMEM;
+
+ r = rfkill_register(rfk);
+ if (r) {
+ rfkill_destroy(rfk);
+ return r;
+ }
+
+ platform_set_drvdata(pdev, rfk);
+ return 0;
+}
+
+static int __devexit xo1_rfkill_remove(struct platform_device *pdev)
+{
+ struct rfkill *rfk = platform_get_drvdata(pdev);
+ rfkill_unregister(rfk);
+ rfkill_destroy(rfk);
+ return 0;
+}
+
+static struct platform_driver xo1_rfkill_driver = {
+ .driver = {
+ .name = "xo1-rfkill",
+ .owner = THIS_MODULE,
+ },
+ .probe = xo1_rfkill_probe,
+ .remove = __devexit_p(xo1_rfkill_remove),
+};
+
+static int __init xo1_rfkill_init(void)
+{
+ return platform_driver_register(&xo1_rfkill_driver);
+}
+
+static void __exit xo1_rfkill_exit(void)
+{
+ platform_driver_unregister(&xo1_rfkill_driver);
+}
+
+MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:xo1-rfkill");
+
+module_init(xo1_rfkill_init);
+module_exit(xo1_rfkill_exit);
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h
index 0bab84ebb15d..19bc73695475 100644
--- a/drivers/pnp/base.h
+++ b/drivers/pnp/base.h
@@ -12,11 +12,12 @@ void pnp_unregister_protocol(struct pnp_protocol *protocol);
#define PNP_EISA_ID_MASK 0x7fffffff
void pnp_eisa_id_to_string(u32 id, char *str);
-struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *, int id, char *pnpid);
+struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *, int id,
+ const char *pnpid);
struct pnp_card *pnp_alloc_card(struct pnp_protocol *, int id, char *pnpid);
int pnp_add_device(struct pnp_dev *dev);
-struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id);
+struct pnp_id *pnp_add_id(struct pnp_dev *dev, const char *id);
int pnp_add_card(struct pnp_card *card);
void pnp_remove_card(struct pnp_card *card);
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index 88b3cde52596..0f34d962fd3c 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -124,7 +124,8 @@ static void pnp_release_device(struct device *dmdev)
kfree(dev);
}
-struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid)
+struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id,
+ const char *pnpid)
{
struct pnp_dev *dev;
struct pnp_id *dev_id;
@@ -194,8 +195,9 @@ int pnp_add_device(struct pnp_dev *dev)
for (id = dev->id; id; id = id->next)
len += scnprintf(buf + len, sizeof(buf) - len, " %s", id->id);
- pnp_dbg(&dev->dev, "%s device, IDs%s (%s)\n",
- dev->protocol->name, buf, dev->active ? "active" : "disabled");
+ dev_printk(KERN_DEBUG, &dev->dev, "%s device, IDs%s (%s)\n",
+ dev->protocol->name, buf,
+ dev->active ? "active" : "disabled");
return 0;
}
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index cd11b113494f..d1dbb9df53fa 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -236,7 +236,7 @@ void pnp_unregister_driver(struct pnp_driver *drv)
* @dev: pointer to the desired device
* @id: pointer to an EISA id string
*/
-struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id)
+struct pnp_id *pnp_add_id(struct pnp_dev *dev, const char *id)
{
struct pnp_id *dev_id, *ptr;
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index dc4e32e031e9..2d73dfcecdbb 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -28,7 +28,7 @@
#include "../base.h"
#include "pnpacpi.h"
-static int num = 0;
+static int num;
/* We need only to blacklist devices that have already an acpi driver that
* can't use pnp layer. We don't need to blacklist device that are directly
@@ -59,7 +59,7 @@ static inline int __init is_exclusive_device(struct acpi_device *dev)
#define TEST_ALPHA(c) \
if (!('@' <= (c) || (c) <= 'Z')) \
return 0
-static int __init ispnpidacpi(char *id)
+static int __init ispnpidacpi(const char *id)
{
TEST_ALPHA(id[0]);
TEST_ALPHA(id[1]);
@@ -180,11 +180,24 @@ struct pnp_protocol pnpacpi_protocol = {
};
EXPORT_SYMBOL(pnpacpi_protocol);
+static char *pnpacpi_get_id(struct acpi_device *device)
+{
+ struct acpi_hardware_id *id;
+
+ list_for_each_entry(id, &device->pnp.ids, list) {
+ if (ispnpidacpi(id->id))
+ return id->id;
+ }
+
+ return NULL;
+}
+
static int __init pnpacpi_add_device(struct acpi_device *device)
{
acpi_handle temp = NULL;
acpi_status status;
struct pnp_dev *dev;
+ char *pnpid;
struct acpi_hardware_id *id;
/*
@@ -192,11 +205,17 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
* driver should not be loaded.
*/
status = acpi_get_handle(device->handle, "_CRS", &temp);
- if (ACPI_FAILURE(status) || !ispnpidacpi(acpi_device_hid(device)) ||
- is_exclusive_device(device) || (!device->status.present))
+ if (ACPI_FAILURE(status))
+ return 0;
+
+ pnpid = pnpacpi_get_id(device);
+ if (!pnpid)
+ return 0;
+
+ if (is_exclusive_device(device) || !device->status.present)
return 0;
- dev = pnp_alloc_dev(&pnpacpi_protocol, num, acpi_device_hid(device));
+ dev = pnp_alloc_dev(&pnpacpi_protocol, num, pnpid);
if (!dev)
return -ENOMEM;
@@ -227,7 +246,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
pnpacpi_parse_resource_option_data(dev);
list_for_each_entry(id, &device->pnp.ids, list) {
- if (!strcmp(id->id, acpi_device_hid(device)))
+ if (!strcmp(id->id, pnpid))
continue;
if (!ispnpidacpi(id->id))
continue;
diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c
index 2d8ac43f78e8..bc89f392a629 100644
--- a/drivers/pnp/pnpbios/proc.c
+++ b/drivers/pnp/pnpbios/proc.c
@@ -11,7 +11,6 @@
*
* The .../escd file is utilized by the lsescd utility written by
* Gunther Mayer.
- * http://home.t-online.de/home/gunther.mayer/lsescd
*
* The .../legacy_device_resources file is not used yet.
*
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index e3446ab8b563..a925e6b63d72 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -523,7 +523,7 @@ struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
res->start = irq;
res->end = irq;
- pnp_dbg(&dev->dev, " add %pr\n", res);
+ dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
return pnp_res;
}
@@ -544,7 +544,7 @@ struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
res->start = dma;
res->end = dma;
- pnp_dbg(&dev->dev, " add %pr\n", res);
+ dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
return pnp_res;
}
@@ -568,7 +568,7 @@ struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
res->start = start;
res->end = end;
- pnp_dbg(&dev->dev, " add %pr\n", res);
+ dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
return pnp_res;
}
@@ -592,7 +592,7 @@ struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
res->start = start;
res->end = end;
- pnp_dbg(&dev->dev, " add %pr\n", res);
+ dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
return pnp_res;
}
@@ -616,7 +616,7 @@ struct pnp_resource *pnp_add_bus_resource(struct pnp_dev *dev,
res->start = start;
res->end = end;
- pnp_dbg(&dev->dev, " add %pr\n", res);
+ dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
return pnp_res;
}
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 07343568a12e..ec444774b9ee 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -64,8 +64,7 @@ config TEST_POWER
config BATTERY_DS2760
tristate "DS2760 battery driver (HP iPAQ & others)"
- select W1
- select W1_SLAVE_DS2760
+ depends on W1 && W1_SLAVE_DS2760
help
Say Y here to enable support for batteries with ds2760 chip.
@@ -109,6 +108,13 @@ config BATTERY_WM97XX
help
Say Y to enable support for battery measured by WM97xx aux port.
+config BATTERY_BQ20Z75
+ tristate "TI BQ20z75 gas gauge"
+ depends on I2C
+ help
+ Say Y to include support for TI BQ20z75 SBS-compliant
+ gas gauge and protection IC.
+
config BATTERY_BQ27x00
tristate "BQ27x00 battery driver"
depends on I2C
@@ -166,4 +172,18 @@ config BATTERY_INTEL_MID
Say Y here to enable the battery driver on Intel MID
platforms.
+config CHARGER_ISP1704
+ tristate "ISP1704 USB Charger Detection"
+ depends on USB_OTG_UTILS
+ help
+ Say Y to enable support for USB Charger Detection with
+ ISP1707/ISP1704 USB transceivers.
+
+config CHARGER_TWL4030
+ tristate "OMAP TWL4030 BCI charger driver"
+ depends on TWL4030_CORE
+ depends on BROKEN
+ help
+ Say Y here to enable support for TWL4030 Battery Charge Interface.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 10143aaf4ee3..c75772eb157c 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -1,16 +1,8 @@
-power_supply-objs := power_supply_core.o
+ccflags-$(CONFIG_POWER_SUPPLY_DEBUG) := -DDEBUG
-ifeq ($(CONFIG_SYSFS),y)
-power_supply-objs += power_supply_sysfs.o
-endif
-
-ifeq ($(CONFIG_LEDS_TRIGGERS),y)
-power_supply-objs += power_supply_leds.o
-endif
-
-ifeq ($(CONFIG_POWER_SUPPLY_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+power_supply-y := power_supply_core.o
+power_supply-$(CONFIG_SYSFS) += power_supply_sysfs.o
+power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o
obj-$(CONFIG_POWER_SUPPLY) += power_supply.o
@@ -29,6 +21,7 @@ obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o
obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
+obj-$(CONFIG_BATTERY_BQ20Z75) += bq20z75.o
obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
@@ -37,3 +30,5 @@ obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
+obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
+obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
diff --git a/drivers/power/bq20z75.c b/drivers/power/bq20z75.c
new file mode 100644
index 000000000000..492da27e1a47
--- /dev/null
+++ b/drivers/power/bq20z75.c
@@ -0,0 +1,493 @@
+/*
+ * Gas Gauge driver for TI's BQ20Z75
+ *
+ * Copyright (c) 2010, NVIDIA 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; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+enum {
+ REG_MANUFACTURER_DATA,
+ REG_TEMPERATURE,
+ REG_VOLTAGE,
+ REG_CURRENT,
+ REG_CAPACITY,
+ REG_TIME_TO_EMPTY,
+ REG_TIME_TO_FULL,
+ REG_STATUS,
+ REG_CYCLE_COUNT,
+ REG_SERIAL_NUMBER,
+ REG_REMAINING_CAPACITY,
+ REG_FULL_CHARGE_CAPACITY,
+ REG_DESIGN_CAPACITY,
+ REG_DESIGN_VOLTAGE,
+};
+
+/* manufacturer access defines */
+#define MANUFACTURER_ACCESS_STATUS 0x0006
+#define MANUFACTURER_ACCESS_SLEEP 0x0011
+
+/* battery status value bits */
+#define BATTERY_DISCHARGING 0x40
+#define BATTERY_FULL_CHARGED 0x20
+#define BATTERY_FULL_DISCHARGED 0x10
+
+#define BQ20Z75_DATA(_psp, _addr, _min_value, _max_value) { \
+ .psp = _psp, \
+ .addr = _addr, \
+ .min_value = _min_value, \
+ .max_value = _max_value, \
+}
+
+static const struct bq20z75_device_data {
+ enum power_supply_property psp;
+ u8 addr;
+ int min_value;
+ int max_value;
+} bq20z75_data[] = {
+ [REG_MANUFACTURER_DATA] =
+ BQ20Z75_DATA(POWER_SUPPLY_PROP_PRESENT, 0x00, 0, 65535),
+ [REG_TEMPERATURE] =
+ BQ20Z75_DATA(POWER_SUPPLY_PROP_TEMP, 0x08, 0, 65535),
+ [REG_VOLTAGE] =
+ BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_NOW, 0x09, 0, 20000),
+ [REG_CURRENT] =
+ BQ20Z75_DATA(POWER_SUPPLY_PROP_CURRENT_NOW, 0x0A, -32768,
+ 32767),
+ [REG_CAPACITY] =
+ BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100),
+ [REG_REMAINING_CAPACITY] =
+ BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535),
+ [REG_FULL_CHARGE_CAPACITY] =
+ BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535),
+ [REG_TIME_TO_EMPTY] =
+ BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0,
+ 65535),
+ [REG_TIME_TO_FULL] =
+ BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, 0x13, 0,
+ 65535),
+ [REG_STATUS] =
+ BQ20Z75_DATA(POWER_SUPPLY_PROP_STATUS, 0x16, 0, 65535),
+ [REG_CYCLE_COUNT] =
+ BQ20Z75_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535),
+ [REG_DESIGN_CAPACITY] =
+ BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0,
+ 65535),
+ [REG_DESIGN_VOLTAGE] =
+ BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0,
+ 65535),
+ [REG_SERIAL_NUMBER] =
+ BQ20Z75_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER, 0x1C, 0, 65535),
+};
+
+static enum power_supply_property bq20z75_properties[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_CYCLE_COUNT,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
+ POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
+ POWER_SUPPLY_PROP_SERIAL_NUMBER,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ POWER_SUPPLY_PROP_ENERGY_NOW,
+ POWER_SUPPLY_PROP_ENERGY_FULL,
+ POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
+};
+
+struct bq20z75_info {
+ struct i2c_client *client;
+ struct power_supply power_supply;
+};
+
+static int bq20z75_read_word_data(struct i2c_client *client, u8 address)
+{
+ s32 ret;
+
+ ret = i2c_smbus_read_word_data(client, address);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "%s: i2c read at address 0x%x failed\n",
+ __func__, address);
+ return ret;
+ }
+ return le16_to_cpu(ret);
+}
+
+static int bq20z75_write_word_data(struct i2c_client *client, u8 address,
+ u16 value)
+{
+ s32 ret;
+
+ ret = i2c_smbus_write_word_data(client, address, le16_to_cpu(value));
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "%s: i2c write to address 0x%x failed\n",
+ __func__, address);
+ return ret;
+ }
+ return 0;
+}
+
+static int bq20z75_get_battery_presence_and_health(
+ struct i2c_client *client, enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ s32 ret;
+
+ /* Write to ManufacturerAccess with
+ * ManufacturerAccess command and then
+ * read the status */
+ ret = bq20z75_write_word_data(client,
+ bq20z75_data[REG_MANUFACTURER_DATA].addr,
+ MANUFACTURER_ACCESS_STATUS);
+ if (ret < 0)
+ return ret;
+
+
+ ret = bq20z75_read_word_data(client,
+ bq20z75_data[REG_MANUFACTURER_DATA].addr);
+ if (ret < 0)
+ return ret;
+
+ if (ret < bq20z75_data[REG_MANUFACTURER_DATA].min_value ||
+ ret > bq20z75_data[REG_MANUFACTURER_DATA].max_value) {
+ val->intval = 0;
+ return 0;
+ }
+
+ /* Mask the upper nibble of 2nd byte and
+ * lower byte of response then
+ * shift the result by 8 to get status*/
+ ret &= 0x0F00;
+ ret >>= 8;
+ if (psp == POWER_SUPPLY_PROP_PRESENT) {
+ if (ret == 0x0F)
+ /* battery removed */
+ val->intval = 0;
+ else
+ val->intval = 1;
+ } else if (psp == POWER_SUPPLY_PROP_HEALTH) {
+ if (ret == 0x09)
+ val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+ else if (ret == 0x0B)
+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+ else if (ret == 0x0C)
+ val->intval = POWER_SUPPLY_HEALTH_DEAD;
+ else
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ }
+
+ return 0;
+}
+
+static int bq20z75_get_battery_property(struct i2c_client *client,
+ int reg_offset, enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ s32 ret;
+
+ ret = bq20z75_read_word_data(client,
+ bq20z75_data[reg_offset].addr);
+ if (ret < 0)
+ return ret;
+
+ /* returned values are 16 bit */
+ if (bq20z75_data[reg_offset].min_value < 0)
+ ret = (s16)ret;
+
+ if (ret >= bq20z75_data[reg_offset].min_value &&
+ ret <= bq20z75_data[reg_offset].max_value) {
+ val->intval = ret;
+ if (psp == POWER_SUPPLY_PROP_STATUS) {
+ if (ret & BATTERY_FULL_CHARGED)
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ else if (ret & BATTERY_FULL_DISCHARGED)
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ else if (ret & BATTERY_DISCHARGING)
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ else
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ }
+ } else {
+ if (psp == POWER_SUPPLY_PROP_STATUS)
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+ else
+ val->intval = 0;
+ }
+
+ return 0;
+}
+
+static void bq20z75_unit_adjustment(struct i2c_client *client,
+ enum power_supply_property psp, union power_supply_propval *val)
+{
+#define BASE_UNIT_CONVERSION 1000
+#define BATTERY_MODE_CAP_MULT_WATT (10 * BASE_UNIT_CONVERSION)
+#define TIME_UNIT_CONVERSION 600
+#define TEMP_KELVIN_TO_CELCIUS 2731
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ENERGY_NOW:
+ case POWER_SUPPLY_PROP_ENERGY_FULL:
+ case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+ val->intval *= BATTERY_MODE_CAP_MULT_WATT;
+ break;
+
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval *= BASE_UNIT_CONVERSION;
+ break;
+
+ case POWER_SUPPLY_PROP_TEMP:
+ /* bq20z75 provides battery tempreture in 0.1°K
+ * so convert it to 0.1°C */
+ val->intval -= TEMP_KELVIN_TO_CELCIUS;
+ val->intval *= 10;
+ break;
+
+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
+ case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
+ val->intval *= TIME_UNIT_CONVERSION;
+ break;
+
+ default:
+ dev_dbg(&client->dev,
+ "%s: no need for unit conversion %d\n", __func__, psp);
+ }
+}
+
+static int bq20z75_get_battery_capacity(struct i2c_client *client,
+ int reg_offset, enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ s32 ret;
+
+ ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr);
+ if (ret < 0)
+ return ret;
+
+ if (psp == POWER_SUPPLY_PROP_CAPACITY) {
+ /* bq20z75 spec says that this can be >100 %
+ * even if max value is 100 % */
+ val->intval = min(ret, 100);
+ } else
+ val->intval = ret;
+
+ return 0;
+}
+
+static char bq20z75_serial[5];
+static int bq20z75_get_battery_serial_number(struct i2c_client *client,
+ union power_supply_propval *val)
+{
+ int ret;
+
+ ret = bq20z75_read_word_data(client,
+ bq20z75_data[REG_SERIAL_NUMBER].addr);
+ if (ret < 0)
+ return ret;
+
+ ret = sprintf(bq20z75_serial, "%04x", ret);
+ val->strval = bq20z75_serial;
+
+ return 0;
+}
+
+static int bq20z75_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ int count;
+ int ret;
+ struct bq20z75_info *bq20z75_device = container_of(psy,
+ struct bq20z75_info, power_supply);
+ struct i2c_client *client = bq20z75_device->client;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_PRESENT:
+ case POWER_SUPPLY_PROP_HEALTH:
+ ret = bq20z75_get_battery_presence_and_health(client, psp, val);
+ if (ret)
+ return ret;
+ break;
+
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+ break;
+
+ case POWER_SUPPLY_PROP_ENERGY_NOW:
+ case POWER_SUPPLY_PROP_ENERGY_FULL:
+ case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+ case POWER_SUPPLY_PROP_CAPACITY:
+ for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) {
+ if (psp == bq20z75_data[count].psp)
+ break;
+ }
+
+ ret = bq20z75_get_battery_capacity(client, count, psp, val);
+ if (ret)
+ return ret;
+
+ break;
+
+ case POWER_SUPPLY_PROP_SERIAL_NUMBER:
+ ret = bq20z75_get_battery_serial_number(client, val);
+ if (ret)
+ return ret;
+ break;
+
+ case POWER_SUPPLY_PROP_STATUS:
+ case POWER_SUPPLY_PROP_CYCLE_COUNT:
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ case POWER_SUPPLY_PROP_TEMP:
+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
+ case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) {
+ if (psp == bq20z75_data[count].psp)
+ break;
+ }
+
+ ret = bq20z75_get_battery_property(client, count, psp, val);
+ if (ret)
+ return ret;
+
+ break;
+
+ default:
+ dev_err(&client->dev,
+ "%s: INVALID property\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Convert units to match requirements for power supply class */
+ bq20z75_unit_adjustment(client, psp, val);
+
+ dev_dbg(&client->dev,
+ "%s: property = %d, value = %d\n", __func__, psp, val->intval);
+
+ return 0;
+}
+
+static int bq20z75_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct bq20z75_info *bq20z75_device;
+ int rc;
+
+ bq20z75_device = kzalloc(sizeof(struct bq20z75_info), GFP_KERNEL);
+ if (!bq20z75_device)
+ return -ENOMEM;
+
+ bq20z75_device->client = client;
+ bq20z75_device->power_supply.name = "battery";
+ bq20z75_device->power_supply.type = POWER_SUPPLY_TYPE_BATTERY;
+ bq20z75_device->power_supply.properties = bq20z75_properties;
+ bq20z75_device->power_supply.num_properties =
+ ARRAY_SIZE(bq20z75_properties);
+ bq20z75_device->power_supply.get_property = bq20z75_get_property;
+
+ i2c_set_clientdata(client, bq20z75_device);
+
+ rc = power_supply_register(&client->dev, &bq20z75_device->power_supply);
+ if (rc) {
+ dev_err(&client->dev,
+ "%s: Failed to register power supply\n", __func__);
+ kfree(bq20z75_device);
+ return rc;
+ }
+
+ dev_info(&client->dev,
+ "%s: battery gas gauge device registered\n", client->name);
+
+ return 0;
+}
+
+static int bq20z75_remove(struct i2c_client *client)
+{
+ struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
+
+ power_supply_unregister(&bq20z75_device->power_supply);
+ kfree(bq20z75_device);
+ bq20z75_device = NULL;
+
+ return 0;
+}
+
+#if defined CONFIG_PM
+static int bq20z75_suspend(struct i2c_client *client,
+ pm_message_t state)
+{
+ s32 ret;
+
+ /* write to manufacturer access with sleep command */
+ ret = bq20z75_write_word_data(client,
+ bq20z75_data[REG_MANUFACTURER_DATA].addr,
+ MANUFACTURER_ACCESS_SLEEP);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+#else
+#define bq20z75_suspend NULL
+#endif
+/* any smbus transaction will wake up bq20z75 */
+#define bq20z75_resume NULL
+
+static const struct i2c_device_id bq20z75_id[] = {
+ { "bq20z75", 0 },
+ {}
+};
+
+static struct i2c_driver bq20z75_battery_driver = {
+ .probe = bq20z75_probe,
+ .remove = bq20z75_remove,
+ .suspend = bq20z75_suspend,
+ .resume = bq20z75_resume,
+ .id_table = bq20z75_id,
+ .driver = {
+ .name = "bq20z75-battery",
+ },
+};
+
+static int __init bq20z75_battery_init(void)
+{
+ return i2c_add_driver(&bq20z75_battery_driver);
+}
+module_init(bq20z75_battery_init);
+
+static void __exit bq20z75_battery_exit(void)
+{
+ i2c_del_driver(&bq20z75_battery_driver);
+}
+module_exit(bq20z75_battery_exit);
+
+MODULE_DESCRIPTION("BQ20z75 battery monitor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index 3ec9c6a8896b..eff0273d4030 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -418,6 +418,7 @@ static int bq27x00_battery_remove(struct i2c_client *client)
power_supply_unregister(&di->bat);
+ kfree(di->bus);
kfree(di->bat.name);
mutex_lock(&battery_mutex);
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c
index 4d3b27228a2e..b3c01c16a164 100644
--- a/drivers/power/ds2760_battery.c
+++ b/drivers/power/ds2760_battery.c
@@ -586,6 +586,7 @@ static int ds2760_battery_remove(struct platform_device *pdev)
&di->set_charged_work);
destroy_workqueue(di->monitor_wqueue);
power_supply_unregister(&di->bat);
+ kfree(di);
return 0;
}
diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c
index 84d3c43cf2bc..6957e8af6449 100644
--- a/drivers/power/ds2782_battery.c
+++ b/drivers/power/ds2782_battery.c
@@ -44,8 +44,8 @@ struct ds278x_info;
struct ds278x_battery_ops {
int (*get_battery_current)(struct ds278x_info *info, int *current_uA);
- int (*get_battery_voltage)(struct ds278x_info *info, int *voltage_uA);
- int (*get_battery_capacity)(struct ds278x_info *info, int *capacity_uA);
+ int (*get_battery_voltage)(struct ds278x_info *info, int *voltage_uV);
+ int (*get_battery_capacity)(struct ds278x_info *info, int *capacity);
};
#define to_ds278x_info(x) container_of(x, struct ds278x_info, battery)
@@ -137,7 +137,7 @@ static int ds2782_get_current(struct ds278x_info *info, int *current_uA)
return 0;
}
-static int ds2782_get_voltage(struct ds278x_info *info, int *voltage_uA)
+static int ds2782_get_voltage(struct ds278x_info *info, int *voltage_uV)
{
s16 raw;
int err;
@@ -149,7 +149,7 @@ static int ds2782_get_voltage(struct ds278x_info *info, int *voltage_uA)
err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw);
if (err)
return err;
- *voltage_uA = (raw / 32) * 4800;
+ *voltage_uV = (raw / 32) * 4800;
return 0;
}
@@ -177,7 +177,7 @@ static int ds2786_get_current(struct ds278x_info *info, int *current_uA)
return 0;
}
-static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uA)
+static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uV)
{
s16 raw;
int err;
@@ -189,7 +189,7 @@ static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uA)
err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw);
if (err)
return err;
- *voltage_uA = (raw / 8) * 1220;
+ *voltage_uV = (raw / 8) * 1220;
return 0;
}
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c
new file mode 100644
index 000000000000..72512185f3e2
--- /dev/null
+++ b/drivers/power/isp1704_charger.c
@@ -0,0 +1,369 @@
+/*
+ * ISP1704 USB Charger Detection driver
+ *
+ * Copyright (C) 2010 Nokia 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; 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/module.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/delay.h>
+
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* Vendor specific Power Control register */
+#define ISP1704_PWR_CTRL 0x3d
+#define ISP1704_PWR_CTRL_SWCTRL (1 << 0)
+#define ISP1704_PWR_CTRL_DET_COMP (1 << 1)
+#define ISP1704_PWR_CTRL_BVALID_RISE (1 << 2)
+#define ISP1704_PWR_CTRL_BVALID_FALL (1 << 3)
+#define ISP1704_PWR_CTRL_DP_WKPU_EN (1 << 4)
+#define ISP1704_PWR_CTRL_VDAT_DET (1 << 5)
+#define ISP1704_PWR_CTRL_DPVSRC_EN (1 << 6)
+#define ISP1704_PWR_CTRL_HWDETECT (1 << 7)
+
+#define NXP_VENDOR_ID 0x04cc
+
+static u16 isp170x_id[] = {
+ 0x1704,
+ 0x1707,
+};
+
+struct isp1704_charger {
+ struct device *dev;
+ struct power_supply psy;
+ struct otg_transceiver *otg;
+ struct notifier_block nb;
+ struct work_struct work;
+
+ char model[7];
+ unsigned present:1;
+};
+
+/*
+ * ISP1704 detects PS/2 adapters as charger. To make sure the detected charger
+ * is actually a dedicated charger, the following steps need to be taken.
+ */
+static inline int isp1704_charger_verify(struct isp1704_charger *isp)
+{
+ int ret = 0;
+ u8 r;
+
+ /* Reset the transceiver */
+ r = otg_io_read(isp->otg, ULPI_FUNC_CTRL);
+ r |= ULPI_FUNC_CTRL_RESET;
+ otg_io_write(isp->otg, ULPI_FUNC_CTRL, r);
+ usleep_range(1000, 2000);
+
+ /* Set normal mode */
+ r &= ~(ULPI_FUNC_CTRL_RESET | ULPI_FUNC_CTRL_OPMODE_MASK);
+ otg_io_write(isp->otg, ULPI_FUNC_CTRL, r);
+
+ /* Clear the DP and DM pull-down bits */
+ r = ULPI_OTG_CTRL_DP_PULLDOWN | ULPI_OTG_CTRL_DM_PULLDOWN;
+ otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), r);
+
+ /* Enable strong pull-up on DP (1.5K) and reset */
+ r = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET;
+ otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), r);
+ usleep_range(1000, 2000);
+
+ /* Read the line state */
+ if (!otg_io_read(isp->otg, ULPI_DEBUG)) {
+ /* Disable strong pull-up on DP (1.5K) */
+ otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
+ ULPI_FUNC_CTRL_TERMSELECT);
+ return 1;
+ }
+
+ /* Is it a charger or PS/2 connection */
+
+ /* Enable weak pull-up resistor on DP */
+ otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL),
+ ISP1704_PWR_CTRL_DP_WKPU_EN);
+
+ /* Disable strong pull-up on DP (1.5K) */
+ otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
+ ULPI_FUNC_CTRL_TERMSELECT);
+
+ /* Enable weak pull-down resistor on DM */
+ otg_io_write(isp->otg, ULPI_SET(ULPI_OTG_CTRL),
+ ULPI_OTG_CTRL_DM_PULLDOWN);
+
+ /* It's a charger if the line states are clear */
+ if (!(otg_io_read(isp->otg, ULPI_DEBUG)))
+ ret = 1;
+
+ /* Disable weak pull-up resistor on DP */
+ otg_io_write(isp->otg, ULPI_CLR(ISP1704_PWR_CTRL),
+ ISP1704_PWR_CTRL_DP_WKPU_EN);
+
+ return ret;
+}
+
+static inline int isp1704_charger_detect(struct isp1704_charger *isp)
+{
+ unsigned long timeout;
+ u8 r;
+ int ret = 0;
+
+ /* set SW control bit in PWR_CTRL register */
+ otg_io_write(isp->otg, ISP1704_PWR_CTRL,
+ ISP1704_PWR_CTRL_SWCTRL);
+
+ /* enable manual charger detection */
+ r = (ISP1704_PWR_CTRL_SWCTRL | ISP1704_PWR_CTRL_DPVSRC_EN);
+ otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), r);
+ usleep_range(1000, 2000);
+
+ timeout = jiffies + msecs_to_jiffies(300);
+ do {
+ /* Check if there is a charger */
+ if (otg_io_read(isp->otg, ISP1704_PWR_CTRL)
+ & ISP1704_PWR_CTRL_VDAT_DET) {
+ ret = isp1704_charger_verify(isp);
+ break;
+ }
+ } while (!time_after(jiffies, timeout));
+
+ return ret;
+}
+
+static void isp1704_charger_work(struct work_struct *data)
+{
+ int detect;
+ struct isp1704_charger *isp =
+ container_of(data, struct isp1704_charger, work);
+
+ /*
+ * FIXME Only supporting dedicated chargers even though isp1704 can
+ * detect HUB and HOST chargers. If the device has already been
+ * enumerated, the detection will break the connection.
+ */
+ if (isp->otg->state != OTG_STATE_B_IDLE)
+ return;
+
+ /* disable data pullups */
+ if (isp->otg->gadget)
+ usb_gadget_disconnect(isp->otg->gadget);
+
+ /* detect charger */
+ detect = isp1704_charger_detect(isp);
+ if (detect) {
+ isp->present = detect;
+ power_supply_changed(&isp->psy);
+ }
+
+ /* enable data pullups */
+ if (isp->otg->gadget)
+ usb_gadget_connect(isp->otg->gadget);
+}
+
+static int isp1704_notifier_call(struct notifier_block *nb,
+ unsigned long event, void *unused)
+{
+ struct isp1704_charger *isp =
+ container_of(nb, struct isp1704_charger, nb);
+
+ switch (event) {
+ case USB_EVENT_VBUS:
+ schedule_work(&isp->work);
+ break;
+ case USB_EVENT_NONE:
+ if (isp->present) {
+ isp->present = 0;
+ power_supply_changed(&isp->psy);
+ }
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ return NOTIFY_OK;
+}
+
+static int isp1704_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct isp1704_charger *isp =
+ container_of(psy, struct isp1704_charger, psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = isp->present;
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = isp->model;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = "NXP";
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static enum power_supply_property power_props[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static inline int isp1704_test_ulpi(struct isp1704_charger *isp)
+{
+ int vendor;
+ int product;
+ int i;
+ int ret = -ENODEV;
+
+ /* Test ULPI interface */
+ ret = otg_io_write(isp->otg, ULPI_SCRATCH, 0xaa);
+ if (ret < 0)
+ return ret;
+
+ ret = otg_io_read(isp->otg, ULPI_SCRATCH);
+ if (ret < 0)
+ return ret;
+
+ if (ret != 0xaa)
+ return -ENODEV;
+
+ /* Verify the product and vendor id matches */
+ vendor = otg_io_read(isp->otg, ULPI_VENDOR_ID_LOW);
+ vendor |= otg_io_read(isp->otg, ULPI_VENDOR_ID_HIGH) << 8;
+ if (vendor != NXP_VENDOR_ID)
+ return -ENODEV;
+
+ product = otg_io_read(isp->otg, ULPI_PRODUCT_ID_LOW);
+ product |= otg_io_read(isp->otg, ULPI_PRODUCT_ID_HIGH) << 8;
+
+ for (i = 0; i < ARRAY_SIZE(isp170x_id); i++) {
+ if (product == isp170x_id[i]) {
+ sprintf(isp->model, "isp%x", product);
+ return product;
+ }
+ }
+
+ dev_err(isp->dev, "product id %x not matching known ids", product);
+
+ return -ENODEV;
+}
+
+static int __devinit isp1704_charger_probe(struct platform_device *pdev)
+{
+ struct isp1704_charger *isp;
+ int ret = -ENODEV;
+
+ isp = kzalloc(sizeof *isp, GFP_KERNEL);
+ if (!isp)
+ return -ENOMEM;
+
+ isp->otg = otg_get_transceiver();
+ if (!isp->otg)
+ goto fail0;
+
+ ret = isp1704_test_ulpi(isp);
+ if (ret < 0)
+ goto fail1;
+
+ isp->dev = &pdev->dev;
+ platform_set_drvdata(pdev, isp);
+
+ isp->psy.name = "isp1704";
+ isp->psy.type = POWER_SUPPLY_TYPE_USB;
+ isp->psy.properties = power_props;
+ isp->psy.num_properties = ARRAY_SIZE(power_props);
+ isp->psy.get_property = isp1704_charger_get_property;
+
+ ret = power_supply_register(isp->dev, &isp->psy);
+ if (ret)
+ goto fail1;
+
+ /*
+ * REVISIT: using work in order to allow the otg notifications to be
+ * made atomically in the future.
+ */
+ INIT_WORK(&isp->work, isp1704_charger_work);
+
+ isp->nb.notifier_call = isp1704_notifier_call;
+
+ ret = otg_register_notifier(isp->otg, &isp->nb);
+ if (ret)
+ goto fail2;
+
+ dev_info(isp->dev, "registered with product id %s\n", isp->model);
+
+ return 0;
+fail2:
+ power_supply_unregister(&isp->psy);
+fail1:
+ otg_put_transceiver(isp->otg);
+fail0:
+ kfree(isp);
+
+ dev_err(&pdev->dev, "failed to register isp1704 with error %d\n", ret);
+
+ return ret;
+}
+
+static int __devexit isp1704_charger_remove(struct platform_device *pdev)
+{
+ struct isp1704_charger *isp = platform_get_drvdata(pdev);
+
+ otg_unregister_notifier(isp->otg, &isp->nb);
+ power_supply_unregister(&isp->psy);
+ otg_put_transceiver(isp->otg);
+ kfree(isp);
+
+ return 0;
+}
+
+static struct platform_driver isp1704_charger_driver = {
+ .driver = {
+ .name = "isp1704_charger",
+ },
+ .probe = isp1704_charger_probe,
+ .remove = __devexit_p(isp1704_charger_remove),
+};
+
+static int __init isp1704_charger_init(void)
+{
+ return platform_driver_register(&isp1704_charger_driver);
+}
+module_init(isp1704_charger_init);
+
+static void __exit isp1704_charger_exit(void)
+{
+ platform_driver_unregister(&isp1704_charger_driver);
+}
+module_exit(isp1704_charger_exit);
+
+MODULE_ALIAS("platform:isp1704_charger");
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("ISP170x USB Charger driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c
index 20c4b952e9bd..a8108a73593e 100644
--- a/drivers/power/jz4740-battery.c
+++ b/drivers/power/jz4740-battery.c
@@ -383,6 +383,7 @@ static int __devexit jz_battery_remove(struct platform_device *pdev)
iounmap(jz_battery->base);
release_mem_region(jz_battery->mem->start, resource_size(jz_battery->mem));
+ kfree(jz_battery);
return 0;
}
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
index aafc1c506eda..5bc1dcf7785e 100644
--- a/drivers/power/olpc_battery.c
+++ b/drivers/power/olpc_battery.c
@@ -271,14 +271,14 @@ static int olpc_bat_get_property(struct power_supply *psy,
if (ret)
return ret;
- val->intval = (int)be16_to_cpu(ec_word) * 9760L / 32;
+ val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32;
break;
case POWER_SUPPLY_PROP_CURRENT_AVG:
ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2);
if (ret)
return ret;
- val->intval = (int)be16_to_cpu(ec_word) * 15625L / 120;
+ val->intval = (s16)be16_to_cpu(ec_word) * 15625L / 120;
break;
case POWER_SUPPLY_PROP_CAPACITY:
ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1);
@@ -299,7 +299,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
if (ret)
return ret;
- val->intval = (int)be16_to_cpu(ec_word) * 100 / 256;
+ val->intval = (s16)be16_to_cpu(ec_word) * 100 / 256;
break;
case POWER_SUPPLY_PROP_TEMP_AMBIENT:
ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
@@ -313,7 +313,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
if (ret)
return ret;
- val->intval = (int)be16_to_cpu(ec_word) * 6250 / 15;
+ val->intval = (s16)be16_to_cpu(ec_word) * 6250 / 15;
break;
case POWER_SUPPLY_PROP_SERIAL_NUMBER:
ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8);
diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c
index 066f994e6fe5..4fa52e1781a2 100644
--- a/drivers/power/pcf50633-charger.c
+++ b/drivers/power/pcf50633-charger.c
@@ -456,6 +456,7 @@ static int __devexit pcf50633_mbc_remove(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
pcf50633_free_irq(mbc->pcf, mbc_irq_handlers[i]);
+ sysfs_remove_group(&pdev->dev.kobj, &mbc_attr_group);
power_supply_unregister(&mbc->usb);
power_supply_unregister(&mbc->adapter);
power_supply_unregister(&mbc->ac);
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 9d30eeb8c810..cd1f90754a3a 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -42,7 +42,8 @@ static ssize_t power_supply_show_property(struct device *dev,
struct device_attribute *attr,
char *buf) {
static char *type_text[] = {
- "Battery", "UPS", "Mains", "USB"
+ "Battery", "UPS", "Mains", "USB",
+ "USB_DCP", "USB_CDP", "USB_ACA"
};
static char *status_text[] = {
"Unknown", "Charging", "Discharging", "Not charging", "Full"
@@ -138,6 +139,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(voltage_min_design),
POWER_SUPPLY_ATTR(voltage_now),
POWER_SUPPLY_ATTR(voltage_avg),
+ POWER_SUPPLY_ATTR(current_max),
POWER_SUPPLY_ATTR(current_now),
POWER_SUPPLY_ATTR(current_avg),
POWER_SUPPLY_ATTR(power_now),
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
new file mode 100644
index 000000000000..ff1f42398a2e
--- /dev/null
+++ b/drivers/power/twl4030_charger.c
@@ -0,0 +1,565 @@
+/*
+ * TWL4030/TPS65950 BCI (Battery Charger Interface) driver
+ *
+ * Copyright (C) 2010 Gražvydas Ignotas <notasas@gmail.com>
+ *
+ * based on twl4030_bci_battery.c by TI
+ * Copyright (C) 2008 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/i2c/twl.h>
+#include <linux/power_supply.h>
+#include <linux/notifier.h>
+#include <linux/usb/otg.h>
+
+#define TWL4030_BCIMSTATEC 0x02
+#define TWL4030_BCIICHG 0x08
+#define TWL4030_BCIVAC 0x0a
+#define TWL4030_BCIVBUS 0x0c
+#define TWL4030_BCIMFSTS4 0x10
+#define TWL4030_BCICTL1 0x23
+
+#define TWL4030_BCIAUTOWEN BIT(5)
+#define TWL4030_CONFIG_DONE BIT(4)
+#define TWL4030_BCIAUTOUSB BIT(1)
+#define TWL4030_BCIAUTOAC BIT(0)
+#define TWL4030_CGAIN BIT(5)
+#define TWL4030_USBFASTMCHG BIT(2)
+#define TWL4030_STS_VBUS BIT(7)
+#define TWL4030_STS_USB_ID BIT(2)
+
+/* BCI interrupts */
+#define TWL4030_WOVF BIT(0) /* Watchdog overflow */
+#define TWL4030_TMOVF BIT(1) /* Timer overflow */
+#define TWL4030_ICHGHIGH BIT(2) /* Battery charge current high */
+#define TWL4030_ICHGLOW BIT(3) /* Battery cc. low / FSM state change */
+#define TWL4030_ICHGEOC BIT(4) /* Battery current end-of-charge */
+#define TWL4030_TBATOR2 BIT(5) /* Battery temperature out of range 2 */
+#define TWL4030_TBATOR1 BIT(6) /* Battery temperature out of range 1 */
+#define TWL4030_BATSTS BIT(7) /* Battery status */
+
+#define TWL4030_VBATLVL BIT(0) /* VBAT level */
+#define TWL4030_VBATOV BIT(1) /* VBAT overvoltage */
+#define TWL4030_VBUSOV BIT(2) /* VBUS overvoltage */
+#define TWL4030_ACCHGOV BIT(3) /* Ac charger overvoltage */
+
+#define TWL4030_MSTATEC_USB BIT(4)
+#define TWL4030_MSTATEC_AC BIT(5)
+#define TWL4030_MSTATEC_MASK 0x0f
+#define TWL4030_MSTATEC_QUICK1 0x02
+#define TWL4030_MSTATEC_QUICK7 0x07
+#define TWL4030_MSTATEC_COMPLETE1 0x0b
+#define TWL4030_MSTATEC_COMPLETE4 0x0e
+
+static bool allow_usb;
+module_param(allow_usb, bool, 1);
+MODULE_PARM_DESC(allow_usb, "Allow USB charge drawing default current");
+
+struct twl4030_bci {
+ struct device *dev;
+ struct power_supply ac;
+ struct power_supply usb;
+ struct otg_transceiver *transceiver;
+ struct notifier_block otg_nb;
+ int irq_chg;
+ int irq_bci;
+};
+
+/*
+ * clear and set bits on an given register on a given module
+ */
+static int twl4030_clear_set(u8 mod_no, u8 clear, u8 set, u8 reg)
+{
+ u8 val = 0;
+ int ret;
+
+ ret = twl_i2c_read_u8(mod_no, &val, reg);
+ if (ret)
+ return ret;
+
+ val &= ~clear;
+ val |= set;
+
+ return twl_i2c_write_u8(mod_no, val, reg);
+}
+
+static int twl4030_bci_read(u8 reg, u8 *val)
+{
+ return twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, val, reg);
+}
+
+static int twl4030_clear_set_boot_bci(u8 clear, u8 set)
+{
+ return twl4030_clear_set(TWL4030_MODULE_PM_MASTER, 0,
+ TWL4030_CONFIG_DONE | TWL4030_BCIAUTOWEN | set,
+ TWL4030_PM_MASTER_BOOT_BCI);
+}
+
+static int twl4030bci_read_adc_val(u8 reg)
+{
+ int ret, temp;
+ u8 val;
+
+ /* read MSB */
+ ret = twl4030_bci_read(reg + 1, &val);
+ if (ret)
+ return ret;
+
+ temp = (int)(val & 0x03) << 8;
+
+ /* read LSB */
+ ret = twl4030_bci_read(reg, &val);
+ if (ret)
+ return ret;
+
+ return temp | val;
+}
+
+/*
+ * Check if VBUS power is present
+ */
+static int twl4030_bci_have_vbus(struct twl4030_bci *bci)
+{
+ int ret;
+ u8 hwsts;
+
+ ret = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &hwsts,
+ TWL4030_PM_MASTER_STS_HW_CONDITIONS);
+ if (ret < 0)
+ return 0;
+
+ dev_dbg(bci->dev, "check_vbus: HW_CONDITIONS %02x\n", hwsts);
+
+ /* in case we also have STS_USB_ID, VBUS is driven by TWL itself */
+ if ((hwsts & TWL4030_STS_VBUS) && !(hwsts & TWL4030_STS_USB_ID))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Enable/Disable USB Charge funtionality.
+ */
+static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
+{
+ int ret;
+
+ if (enable) {
+ /* Check for USB charger conneted */
+ if (!twl4030_bci_have_vbus(bci))
+ return -ENODEV;
+
+ /*
+ * Until we can find out what current the device can provide,
+ * require a module param to enable USB charging.
+ */
+ if (!allow_usb) {
+ dev_warn(bci->dev, "USB charging is disabled.\n");
+ return -EACCES;
+ }
+
+ /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
+ ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
+ if (ret < 0)
+ return ret;
+
+ /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
+ ret = twl4030_clear_set(TWL4030_MODULE_MAIN_CHARGE, 0,
+ TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4);
+ } else {
+ ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0);
+ }
+
+ return ret;
+}
+
+/*
+ * Enable/Disable AC Charge funtionality.
+ */
+static int twl4030_charger_enable_ac(bool enable)
+{
+ int ret;
+
+ if (enable)
+ ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOAC);
+ else
+ ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC, 0);
+
+ return ret;
+}
+
+/*
+ * TWL4030 CHG_PRES (AC charger presence) events
+ */
+static irqreturn_t twl4030_charger_interrupt(int irq, void *arg)
+{
+ struct twl4030_bci *bci = arg;
+
+ dev_dbg(bci->dev, "CHG_PRES irq\n");
+ power_supply_changed(&bci->ac);
+ power_supply_changed(&bci->usb);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * TWL4030 BCI monitoring events
+ */
+static irqreturn_t twl4030_bci_interrupt(int irq, void *arg)
+{
+ struct twl4030_bci *bci = arg;
+ u8 irqs1, irqs2;
+ int ret;
+
+ ret = twl_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &irqs1,
+ TWL4030_INTERRUPTS_BCIISR1A);
+ if (ret < 0)
+ return IRQ_HANDLED;
+
+ ret = twl_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &irqs2,
+ TWL4030_INTERRUPTS_BCIISR2A);
+ if (ret < 0)
+ return IRQ_HANDLED;
+
+ dev_dbg(bci->dev, "BCI irq %02x %02x\n", irqs2, irqs1);
+
+ if (irqs1 & (TWL4030_ICHGLOW | TWL4030_ICHGEOC)) {
+ /* charger state change, inform the core */
+ power_supply_changed(&bci->ac);
+ power_supply_changed(&bci->usb);
+ }
+
+ /* various monitoring events, for now we just log them here */
+ if (irqs1 & (TWL4030_TBATOR2 | TWL4030_TBATOR1))
+ dev_warn(bci->dev, "battery temperature out of range\n");
+
+ if (irqs1 & TWL4030_BATSTS)
+ dev_crit(bci->dev, "battery disconnected\n");
+
+ if (irqs2 & TWL4030_VBATOV)
+ dev_crit(bci->dev, "VBAT overvoltage\n");
+
+ if (irqs2 & TWL4030_VBUSOV)
+ dev_crit(bci->dev, "VBUS overvoltage\n");
+
+ if (irqs2 & TWL4030_ACCHGOV)
+ dev_crit(bci->dev, "Ac charger overvoltage\n");
+
+ return IRQ_HANDLED;
+}
+
+static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val,
+ void *priv)
+{
+ struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb);
+
+ dev_dbg(bci->dev, "OTG notify %lu\n", val);
+
+ switch (val) {
+ case USB_EVENT_VBUS:
+ case USB_EVENT_CHARGER:
+ twl4030_charger_enable_usb(bci, true);
+ break;
+ case USB_EVENT_NONE:
+ twl4030_charger_enable_usb(bci, false);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+/*
+ * TI provided formulas:
+ * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85
+ * CGAIN == 1: ICHG = (BCIICHG * 3.4) / (2^10 - 1) - 1.7
+ * Here we use integer approximation of:
+ * CGAIN == 0: val * 1.6618 - 0.85
+ * CGAIN == 1: (val * 1.6618 - 0.85) * 2
+ */
+static int twl4030_charger_get_current(void)
+{
+ int curr;
+ int ret;
+ u8 bcictl1;
+
+ curr = twl4030bci_read_adc_val(TWL4030_BCIICHG);
+ if (curr < 0)
+ return curr;
+
+ ret = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1);
+ if (ret)
+ return ret;
+
+ ret = (curr * 16618 - 850 * 10000) / 10;
+ if (bcictl1 & TWL4030_CGAIN)
+ ret *= 2;
+
+ return ret;
+}
+
+/*
+ * Returns the main charge FSM state
+ * Or < 0 on failure.
+ */
+static int twl4030bci_state(struct twl4030_bci *bci)
+{
+ int ret;
+ u8 state;
+
+ ret = twl4030_bci_read(TWL4030_BCIMSTATEC, &state);
+ if (ret) {
+ pr_err("twl4030_bci: error reading BCIMSTATEC\n");
+ return ret;
+ }
+
+ dev_dbg(bci->dev, "state: %02x\n", state);
+
+ return state;
+}
+
+static int twl4030_bci_state_to_status(int state)
+{
+ state &= TWL4030_MSTATEC_MASK;
+ if (TWL4030_MSTATEC_QUICK1 <= state && state <= TWL4030_MSTATEC_QUICK7)
+ return POWER_SUPPLY_STATUS_CHARGING;
+ else if (TWL4030_MSTATEC_COMPLETE1 <= state &&
+ state <= TWL4030_MSTATEC_COMPLETE4)
+ return POWER_SUPPLY_STATUS_FULL;
+ else
+ return POWER_SUPPLY_STATUS_NOT_CHARGING;
+}
+
+static int twl4030_bci_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct twl4030_bci *bci = dev_get_drvdata(psy->dev->parent);
+ int is_charging;
+ int state;
+ int ret;
+
+ state = twl4030bci_state(bci);
+ if (state < 0)
+ return state;
+
+ if (psy->type == POWER_SUPPLY_TYPE_USB)
+ is_charging = state & TWL4030_MSTATEC_USB;
+ else
+ is_charging = state & TWL4030_MSTATEC_AC;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ if (is_charging)
+ val->intval = twl4030_bci_state_to_status(state);
+ else
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ /* charging must be active for meaningful result */
+ if (!is_charging)
+ return -ENODATA;
+ if (psy->type == POWER_SUPPLY_TYPE_USB) {
+ ret = twl4030bci_read_adc_val(TWL4030_BCIVBUS);
+ if (ret < 0)
+ return ret;
+ /* BCIVBUS uses ADCIN8, 7/1023 V/step */
+ val->intval = ret * 6843;
+ } else {
+ ret = twl4030bci_read_adc_val(TWL4030_BCIVAC);
+ if (ret < 0)
+ return ret;
+ /* BCIVAC uses ADCIN11, 10/1023 V/step */
+ val->intval = ret * 9775;
+ }
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ if (!is_charging)
+ return -ENODATA;
+ /* current measurement is shared between AC and USB */
+ ret = twl4030_charger_get_current();
+ if (ret < 0)
+ return ret;
+ val->intval = ret;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = is_charging &&
+ twl4030_bci_state_to_status(state) !=
+ POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static enum power_supply_property twl4030_charger_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+};
+
+static int __init twl4030_bci_probe(struct platform_device *pdev)
+{
+ struct twl4030_bci *bci;
+ int ret;
+ int reg;
+
+ bci = kzalloc(sizeof(*bci), GFP_KERNEL);
+ if (bci == NULL)
+ return -ENOMEM;
+
+ bci->dev = &pdev->dev;
+ bci->irq_chg = platform_get_irq(pdev, 0);
+ bci->irq_bci = platform_get_irq(pdev, 1);
+
+ platform_set_drvdata(pdev, bci);
+
+ bci->ac.name = "twl4030_ac";
+ bci->ac.type = POWER_SUPPLY_TYPE_MAINS;
+ bci->ac.properties = twl4030_charger_props;
+ bci->ac.num_properties = ARRAY_SIZE(twl4030_charger_props);
+ bci->ac.get_property = twl4030_bci_get_property;
+
+ ret = power_supply_register(&pdev->dev, &bci->ac);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register ac: %d\n", ret);
+ goto fail_register_ac;
+ }
+
+ bci->usb.name = "twl4030_usb";
+ bci->usb.type = POWER_SUPPLY_TYPE_USB;
+ bci->usb.properties = twl4030_charger_props;
+ bci->usb.num_properties = ARRAY_SIZE(twl4030_charger_props);
+ bci->usb.get_property = twl4030_bci_get_property;
+
+ ret = power_supply_register(&pdev->dev, &bci->usb);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register usb: %d\n", ret);
+ goto fail_register_usb;
+ }
+
+ ret = request_threaded_irq(bci->irq_chg, NULL,
+ twl4030_charger_interrupt, 0, pdev->name, bci);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "could not request irq %d, status %d\n",
+ bci->irq_chg, ret);
+ goto fail_chg_irq;
+ }
+
+ ret = request_threaded_irq(bci->irq_bci, NULL,
+ twl4030_bci_interrupt, 0, pdev->name, bci);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "could not request irq %d, status %d\n",
+ bci->irq_bci, ret);
+ goto fail_bci_irq;
+ }
+
+ bci->transceiver = otg_get_transceiver();
+ if (bci->transceiver != NULL) {
+ bci->otg_nb.notifier_call = twl4030_bci_usb_ncb;
+ otg_register_notifier(bci->transceiver, &bci->otg_nb);
+ }
+
+ /* Enable interrupts now. */
+ reg = ~(TWL4030_ICHGLOW | TWL4030_ICHGEOC | TWL4030_TBATOR2 |
+ TWL4030_TBATOR1 | TWL4030_BATSTS);
+ ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
+ TWL4030_INTERRUPTS_BCIIMR1A);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to unmask interrupts: %d\n", ret);
+ goto fail_unmask_interrupts;
+ }
+
+ reg = ~(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV);
+ ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
+ TWL4030_INTERRUPTS_BCIIMR2A);
+ if (ret < 0)
+ dev_warn(&pdev->dev, "failed to unmask interrupts: %d\n", ret);
+
+ twl4030_charger_enable_ac(true);
+ twl4030_charger_enable_usb(bci, true);
+
+ return 0;
+
+fail_unmask_interrupts:
+ if (bci->transceiver != NULL) {
+ otg_unregister_notifier(bci->transceiver, &bci->otg_nb);
+ otg_put_transceiver(bci->transceiver);
+ }
+ free_irq(bci->irq_bci, bci);
+fail_bci_irq:
+ free_irq(bci->irq_chg, bci);
+fail_chg_irq:
+ power_supply_unregister(&bci->usb);
+fail_register_usb:
+ power_supply_unregister(&bci->ac);
+fail_register_ac:
+ platform_set_drvdata(pdev, NULL);
+ kfree(bci);
+
+ return ret;
+}
+
+static int __exit twl4030_bci_remove(struct platform_device *pdev)
+{
+ struct twl4030_bci *bci = platform_get_drvdata(pdev);
+
+ twl4030_charger_enable_ac(false);
+ twl4030_charger_enable_usb(bci, false);
+
+ /* mask interrupts */
+ twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
+ TWL4030_INTERRUPTS_BCIIMR1A);
+ twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
+ TWL4030_INTERRUPTS_BCIIMR2A);
+
+ if (bci->transceiver != NULL) {
+ otg_unregister_notifier(bci->transceiver, &bci->otg_nb);
+ otg_put_transceiver(bci->transceiver);
+ }
+ free_irq(bci->irq_bci, bci);
+ free_irq(bci->irq_chg, bci);
+ power_supply_unregister(&bci->usb);
+ power_supply_unregister(&bci->ac);
+ platform_set_drvdata(pdev, NULL);
+ kfree(bci);
+
+ return 0;
+}
+
+static struct platform_driver twl4030_bci_driver = {
+ .driver = {
+ .name = "twl4030_bci",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(twl4030_bci_remove),
+};
+
+static int __init twl4030_bci_init(void)
+{
+ return platform_driver_probe(&twl4030_bci_driver, twl4030_bci_probe);
+}
+module_init(twl4030_bci_init);
+
+static void __exit twl4030_bci_exit(void)
+{
+ platform_driver_unregister(&twl4030_bci_driver);
+}
+module_exit(twl4030_bci_exit);
+
+MODULE_AUTHOR("Gražydas Ignotas");
+MODULE_DESCRIPTION("TWL4030 Battery Charger Interface driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:twl4030_bci");
diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c
index fbcc36dae470..ddf8cf5f3204 100644
--- a/drivers/power/wm831x_power.c
+++ b/drivers/power/wm831x_power.c
@@ -267,7 +267,6 @@ static void wm831x_config_battery(struct wm831x *wm831x)
ret = wm831x_set_bits(wm831x, WM831X_CHARGER_CONTROL_1,
WM831X_CHG_ENA_MASK |
WM831X_CHG_FAST_MASK |
- WM831X_CHG_ITERM_MASK |
WM831X_CHG_ITERM_MASK,
reg1);
if (ret != 0)
@@ -612,6 +611,7 @@ static __devexit int wm831x_power_remove(struct platform_device *pdev)
power_supply_unregister(&wm831x_power->battery);
power_supply_unregister(&wm831x_power->wall);
power_supply_unregister(&wm831x_power->usb);
+ kfree(wm831x_power);
return 0;
}
diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c
index 3222fa3c808c..0f4a53bdaa3c 100644
--- a/drivers/rapidio/rio-driver.c
+++ b/drivers/rapidio/rio-driver.c
@@ -192,7 +192,7 @@ static int rio_match_bus(struct device *dev, struct device_driver *drv)
out:return 0;
}
-static struct device rio_bus = {
+struct device rio_bus = {
.init_name = "rapidio",
};
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 8070e074c739..1eb82c4c712e 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -48,7 +48,7 @@ DEFINE_SPINLOCK(rio_global_list_lock);
static int next_destid = 0;
static int next_switchid = 0;
static int next_net = 0;
-static int next_comptag;
+static int next_comptag = 1;
static struct timer_list rio_enum_timer =
TIMER_INITIALIZER(rio_enum_timeout, 0, 0);
@@ -121,27 +121,6 @@ static int rio_clear_locks(struct rio_mport *port)
u32 result;
int ret = 0;
- /* Assign component tag to all devices */
- next_comptag = 1;
- rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR, next_comptag++);
-
- list_for_each_entry(rdev, &rio_devices, global_list) {
- /* Mark device as discovered */
- rio_read_config_32(rdev,
- rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
- &result);
- rio_write_config_32(rdev,
- rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
- result | RIO_PORT_GEN_DISCOVERED);
-
- rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR, next_comptag);
- rdev->comp_tag = next_comptag++;
- if (next_comptag >= 0x10000) {
- pr_err("RIO: Component Tag Counter Overflow\n");
- break;
- }
- }
-
/* Release host device id locks */
rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR,
port->host_deviceid);
@@ -162,6 +141,15 @@ static int rio_clear_locks(struct rio_mport *port)
rdev->vid, rdev->did);
ret = -EINVAL;
}
+
+ /* Mark device as discovered and enable master */
+ rio_read_config_32(rdev,
+ rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
+ &result);
+ result |= RIO_PORT_GEN_DISCOVERED | RIO_PORT_GEN_MASTER;
+ rio_write_config_32(rdev,
+ rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
+ result);
}
return ret;
@@ -420,11 +408,27 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
hopcount, RIO_EFB_ERR_MGMNT);
}
+ if (rdev->pef & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) {
+ rio_mport_read_config_32(port, destid, hopcount,
+ RIO_SWP_INFO_CAR, &rdev->swpinfo);
+ }
+
rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR,
&rdev->src_ops);
rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR,
&rdev->dst_ops);
+ if (do_enum) {
+ /* Assign component tag to device */
+ if (next_comptag >= 0x10000) {
+ pr_err("RIO: Component Tag Counter Overflow\n");
+ goto cleanup;
+ }
+ rio_mport_write_config_32(port, destid, hopcount,
+ RIO_COMPONENT_TAG_CSR, next_comptag);
+ rdev->comp_tag = next_comptag++;
+ }
+
if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) {
if (do_enum) {
rio_set_device_id(port, destid, hopcount, next_destid);
@@ -439,9 +443,10 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
/* If a PE has both switch and other functions, show it as a switch */
if (rio_is_switch(rdev)) {
- rio_mport_read_config_32(port, destid, hopcount,
- RIO_SWP_INFO_CAR, &rdev->swpinfo);
- rswitch = kzalloc(sizeof(struct rio_switch), GFP_KERNEL);
+ rswitch = kzalloc(sizeof(*rswitch) +
+ RIO_GET_TOTAL_PORTS(rdev->swpinfo) *
+ sizeof(rswitch->nextdev[0]),
+ GFP_KERNEL);
if (!rswitch)
goto cleanup;
rswitch->switchid = next_switchid;
@@ -458,6 +463,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
rdid++)
rswitch->route_table[rdid] = RIO_INVALID_ROUTE;
rdev->rswitch = rswitch;
+ rswitch->rdev = rdev;
dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id,
rdev->rswitch->switchid);
rio_switch_init(rdev, do_enum);
@@ -478,6 +484,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
}
rdev->dev.bus = &rio_bus_type;
+ rdev->dev.parent = &rio_bus;
device_initialize(&rdev->dev);
rdev->dev.release = rio_release_dev;
@@ -718,86 +725,53 @@ static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount)
}
/**
- * rio_get_swpinfo_inport- Gets the ingress port number
- * @mport: Master port to send transaction
- * @destid: Destination ID associated with the switch
- * @hopcount: Number of hops to the device
- *
- * Returns port number being used to access the switch device.
- */
-static u8
-rio_get_swpinfo_inport(struct rio_mport *mport, u16 destid, u8 hopcount)
-{
- u32 result;
-
- rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR,
- &result);
-
- return (u8) (result & 0xff);
-}
-
-/**
- * rio_get_swpinfo_tports- Gets total number of ports on the switch
- * @mport: Master port to send transaction
- * @destid: Destination ID associated with the switch
- * @hopcount: Number of hops to the device
- *
- * Returns total numbers of ports implemented by the switch device.
- */
-static u8 rio_get_swpinfo_tports(struct rio_mport *mport, u16 destid,
- u8 hopcount)
-{
- u32 result;
-
- rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR,
- &result);
-
- return RIO_GET_TOTAL_PORTS(result);
-}
-
-/**
- * rio_net_add_mport- Add a master port to a RIO network
- * @net: RIO network
- * @port: Master port to add
- *
- * Adds a master port to the network list of associated master
- * ports..
- */
-static void rio_net_add_mport(struct rio_net *net, struct rio_mport *port)
-{
- spin_lock(&rio_global_list_lock);
- list_add_tail(&port->nnode, &net->mports);
- spin_unlock(&rio_global_list_lock);
-}
-
-/**
* rio_enum_peer- Recursively enumerate a RIO network through a master port
* @net: RIO network being enumerated
* @port: Master port to send transactions
* @hopcount: Number of hops into the network
+ * @prev: Previous RIO device connected to the enumerated one
+ * @prev_port: Port on previous RIO device
*
* Recursively enumerates a RIO network. Transactions are sent via the
* master port passed in @port.
*/
static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
- u8 hopcount)
+ u8 hopcount, struct rio_dev *prev, int prev_port)
{
int port_num;
- int num_ports;
int cur_destid;
int sw_destid;
int sw_inport;
struct rio_dev *rdev;
u16 destid;
+ u32 regval;
int tmp;
+ if (rio_mport_chk_dev_access(port,
+ RIO_ANY_DESTID(port->sys_size), hopcount)) {
+ pr_debug("RIO: device access check failed\n");
+ return -1;
+ }
+
if (rio_get_host_deviceid_lock(port, hopcount) == port->host_deviceid) {
pr_debug("RIO: PE already discovered by this host\n");
/*
* Already discovered by this host. Add it as another
- * master port for the current network.
+ * link to the existing device.
*/
- rio_net_add_mport(net, port);
+ rio_mport_read_config_32(port, RIO_ANY_DESTID(port->sys_size),
+ hopcount, RIO_COMPONENT_TAG_CSR, &regval);
+
+ if (regval) {
+ rdev = rio_get_comptag((regval & 0xffff), NULL);
+
+ if (rdev && prev && rio_is_switch(prev)) {
+ pr_debug("RIO: redundant path to %s\n",
+ rio_name(rdev));
+ prev->rswitch->nextdev[prev_port] = rdev;
+ }
+ }
+
return 0;
}
@@ -828,13 +802,15 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
if (rdev) {
/* Add device to the global and bus/net specific list. */
list_add_tail(&rdev->net_list, &net->devices);
+ rdev->prev = prev;
+ if (prev && rio_is_switch(prev))
+ prev->rswitch->nextdev[prev_port] = rdev;
} else
return -1;
if (rio_is_switch(rdev)) {
next_switchid++;
- sw_inport = rio_get_swpinfo_inport(port,
- RIO_ANY_DESTID(port->sys_size), hopcount);
+ sw_inport = RIO_GET_PORT_NUM(rdev->swpinfo);
rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
port->host_deviceid, sw_inport, 0);
rdev->rswitch->route_table[port->host_deviceid] = sw_inport;
@@ -847,14 +823,14 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
rdev->rswitch->route_table[destid] = sw_inport;
}
- num_ports =
- rio_get_swpinfo_tports(port, RIO_ANY_DESTID(port->sys_size),
- hopcount);
pr_debug(
"RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",
- rio_name(rdev), rdev->vid, rdev->did, num_ports);
+ rio_name(rdev), rdev->vid, rdev->did,
+ RIO_GET_TOTAL_PORTS(rdev->swpinfo));
sw_destid = next_destid;
- for (port_num = 0; port_num < num_ports; port_num++) {
+ for (port_num = 0;
+ port_num < RIO_GET_TOTAL_PORTS(rdev->swpinfo);
+ port_num++) {
/*Enable Input Output Port (transmitter reviever)*/
rio_enable_rx_tx_port(port, 0,
RIO_ANY_DESTID(port->sys_size),
@@ -879,7 +855,8 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
RIO_ANY_DESTID(port->sys_size),
port_num, 0);
- if (rio_enum_peer(net, port, hopcount + 1) < 0)
+ if (rio_enum_peer(net, port, hopcount + 1,
+ rdev, port_num) < 0)
return -1;
/* Update routing tables */
@@ -945,10 +922,11 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
*/
static int rio_enum_complete(struct rio_mport *port)
{
- u32 tag_csr;
+ u32 regval;
- rio_local_read_config_32(port, RIO_COMPONENT_TAG_CSR, &tag_csr);
- return (tag_csr & 0xffff) ? 1 : 0;
+ rio_local_read_config_32(port, port->phys_efptr + RIO_PORT_GEN_CTL_CSR,
+ &regval);
+ return (regval & RIO_PORT_GEN_MASTER) ? 1 : 0;
}
/**
@@ -966,7 +944,6 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
u8 hopcount)
{
u8 port_num, route_port;
- int num_ports;
struct rio_dev *rdev;
u16 ndestid;
@@ -983,13 +960,14 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
/* Associated destid is how we accessed this switch */
rdev->rswitch->destid = destid;
- num_ports = rio_get_swpinfo_tports(port, destid, hopcount);
pr_debug(
"RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",
- rio_name(rdev), rdev->vid, rdev->did, num_ports);
- for (port_num = 0; port_num < num_ports; port_num++) {
- if (rio_get_swpinfo_inport(port, destid, hopcount) ==
- port_num)
+ rio_name(rdev), rdev->vid, rdev->did,
+ RIO_GET_TOTAL_PORTS(rdev->swpinfo));
+ for (port_num = 0;
+ port_num < RIO_GET_TOTAL_PORTS(rdev->swpinfo);
+ port_num++) {
+ if (RIO_GET_PORT_NUM(rdev->swpinfo) == port_num)
continue;
if (rio_sport_is_active
@@ -1011,6 +989,8 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
break;
}
+ if (ndestid == RIO_ANY_DESTID(port->sys_size))
+ continue;
rio_unlock_device(port, destid, hopcount);
if (rio_disc_peer
(net, port, ndestid, hopcount + 1) < 0)
@@ -1108,8 +1088,7 @@ static void rio_update_route_tables(struct rio_mport *port)
if (rswitch->destid == destid)
continue;
- sport = rio_get_swpinfo_inport(port,
- rswitch->destid, rswitch->hopcount);
+ sport = RIO_GET_PORT_NUM(rswitch->rdev->swpinfo);
if (rswitch->add_entry) {
rio_route_add_entry(port, rswitch,
@@ -1184,7 +1163,11 @@ int __devinit rio_enum_mport(struct rio_mport *mport)
/* Enable Input Output Port (transmitter reviever) */
rio_enable_rx_tx_port(mport, 1, 0, 0, 0);
- if (rio_enum_peer(net, mport, 0) < 0) {
+ /* Set component tag for host */
+ rio_local_write_config_32(mport, RIO_COMPONENT_TAG_CSR,
+ next_comptag++);
+
+ if (rio_enum_peer(net, mport, 0, NULL, 0) < 0) {
/* A higher priority host won enumeration, bail. */
printk(KERN_INFO
"RIO: master port %d device has lost enumeration to a remote host\n",
diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c
index 00b475658356..137ed93ee33f 100644
--- a/drivers/rapidio/rio-sysfs.c
+++ b/drivers/rapidio/rio-sysfs.c
@@ -40,9 +40,6 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch
char *str = buf;
int i;
- if (!rdev->rswitch)
- goto out;
-
for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
i++) {
if (rdev->rswitch->route_table[i] == RIO_INVALID_ROUTE)
@@ -52,7 +49,6 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch
rdev->rswitch->route_table[i]);
}
- out:
return (str - buf);
}
@@ -63,10 +59,11 @@ struct device_attribute rio_dev_attrs[] = {
__ATTR_RO(asm_did),
__ATTR_RO(asm_vid),
__ATTR_RO(asm_rev),
- __ATTR_RO(routes),
__ATTR_NULL,
};
+static DEVICE_ATTR(routes, S_IRUGO, routes_show, NULL);
+
static ssize_t
rio_read_config(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
@@ -218,7 +215,17 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev)
{
int err = 0;
- err = sysfs_create_bin_file(&rdev->dev.kobj, &rio_config_attr);
+ err = device_create_bin_file(&rdev->dev, &rio_config_attr);
+
+ if (!err && rdev->rswitch) {
+ err = device_create_file(&rdev->dev, &dev_attr_routes);
+ if (!err && rdev->rswitch->sw_sysfs)
+ err = rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_CREATE);
+ }
+
+ if (err)
+ pr_warning("RIO: Failed to create attribute file(s) for %s\n",
+ rio_name(rdev));
return err;
}
@@ -231,5 +238,10 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev)
*/
void rio_remove_sysfs_dev_files(struct rio_dev *rdev)
{
- sysfs_remove_bin_file(&rdev->dev.kobj, &rio_config_attr);
+ device_remove_bin_file(&rdev->dev, &rio_config_attr);
+ if (rdev->rswitch) {
+ device_remove_file(&rdev->dev, &dev_attr_routes);
+ if (rdev->rswitch->sw_sysfs)
+ rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE);
+ }
}
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index 74e9d22d95fb..68cf0c99138a 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -443,7 +443,7 @@ rio_mport_get_physefb(struct rio_mport *port, int local,
* @from is not %NULL, searches continue from next device on the global
* list.
*/
-static struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from)
+struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from)
{
struct list_head *n;
struct rio_dev *rdev;
@@ -495,6 +495,232 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
}
/**
+ * rio_chk_dev_route - Validate route to the specified device.
+ * @rdev: RIO device failed to respond
+ * @nrdev: Last active device on the route to rdev
+ * @npnum: nrdev's port number on the route to rdev
+ *
+ * Follows a route to the specified RIO device to determine the last available
+ * device (and corresponding RIO port) on the route.
+ */
+static int
+rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum)
+{
+ u32 result;
+ int p_port, dstid, rc = -EIO;
+ struct rio_dev *prev = NULL;
+
+ /* Find switch with failed RIO link */
+ while (rdev->prev && (rdev->prev->pef & RIO_PEF_SWITCH)) {
+ if (!rio_read_config_32(rdev->prev, RIO_DEV_ID_CAR, &result)) {
+ prev = rdev->prev;
+ break;
+ }
+ rdev = rdev->prev;
+ }
+
+ if (prev == NULL)
+ goto err_out;
+
+ dstid = (rdev->pef & RIO_PEF_SWITCH) ?
+ rdev->rswitch->destid : rdev->destid;
+ p_port = prev->rswitch->route_table[dstid];
+
+ if (p_port != RIO_INVALID_ROUTE) {
+ pr_debug("RIO: link failed on [%s]-P%d\n",
+ rio_name(prev), p_port);
+ *nrdev = prev;
+ *npnum = p_port;
+ rc = 0;
+ } else
+ pr_debug("RIO: failed to trace route to %s\n", rio_name(rdev));
+err_out:
+ return rc;
+}
+
+/**
+ * rio_mport_chk_dev_access - Validate access to the specified device.
+ * @mport: Master port to send transactions
+ * @destid: Device destination ID in network
+ * @hopcount: Number of hops into the network
+ */
+int
+rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount)
+{
+ int i = 0;
+ u32 tmp;
+
+ while (rio_mport_read_config_32(mport, destid, hopcount,
+ RIO_DEV_ID_CAR, &tmp)) {
+ i++;
+ if (i == RIO_MAX_CHK_RETRY)
+ return -EIO;
+ mdelay(1);
+ }
+
+ return 0;
+}
+
+/**
+ * rio_chk_dev_access - Validate access to the specified device.
+ * @rdev: Pointer to RIO device control structure
+ */
+static int rio_chk_dev_access(struct rio_dev *rdev)
+{
+ u8 hopcount = 0xff;
+ u16 destid = rdev->destid;
+
+ if (rdev->rswitch) {
+ destid = rdev->rswitch->destid;
+ hopcount = rdev->rswitch->hopcount;
+ }
+
+ return rio_mport_chk_dev_access(rdev->net->hport, destid, hopcount);
+}
+
+/**
+ * rio_get_input_status - Sends a Link-Request/Input-Status control symbol and
+ * returns link-response (if requested).
+ * @rdev: RIO devive to issue Input-status command
+ * @pnum: Device port number to issue the command
+ * @lnkresp: Response from a link partner
+ */
+static int
+rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp)
+{
+ struct rio_mport *mport = rdev->net->hport;
+ u16 destid = rdev->rswitch->destid;
+ u8 hopcount = rdev->rswitch->hopcount;
+ u32 regval;
+ int checkcount;
+
+ if (lnkresp) {
+ /* Read from link maintenance response register
+ * to clear valid bit */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum),
+ &regval);
+ udelay(50);
+ }
+
+ /* Issue Input-status command */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(pnum),
+ RIO_MNT_REQ_CMD_IS);
+
+ /* Exit if the response is not expected */
+ if (lnkresp == NULL)
+ return 0;
+
+ checkcount = 3;
+ while (checkcount--) {
+ udelay(50);
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum),
+ &regval);
+ if (regval & RIO_PORT_N_MNT_RSP_RVAL) {
+ *lnkresp = regval;
+ return 0;
+ }
+ }
+
+ return -EIO;
+}
+
+/**
+ * rio_clr_err_stopped - Clears port Error-stopped states.
+ * @rdev: Pointer to RIO device control structure
+ * @pnum: Switch port number to clear errors
+ * @err_status: port error status (if 0 reads register from device)
+ */
+static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status)
+{
+ struct rio_mport *mport = rdev->net->hport;
+ u16 destid = rdev->rswitch->destid;
+ u8 hopcount = rdev->rswitch->hopcount;
+ struct rio_dev *nextdev = rdev->rswitch->nextdev[pnum];
+ u32 regval;
+ u32 far_ackid, far_linkstat, near_ackid;
+
+ if (err_status == 0)
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
+ &err_status);
+
+ if (err_status & RIO_PORT_N_ERR_STS_PW_OUT_ES) {
+ pr_debug("RIO_EM: servicing Output Error-Stopped state\n");
+ /*
+ * Send a Link-Request/Input-Status control symbol
+ */
+ if (rio_get_input_status(rdev, pnum, &regval)) {
+ pr_debug("RIO_EM: Input-status response timeout\n");
+ goto rd_err;
+ }
+
+ pr_debug("RIO_EM: SP%d Input-status response=0x%08x\n",
+ pnum, regval);
+ far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5;
+ far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT;
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum),
+ &regval);
+ pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval);
+ near_ackid = (regval & RIO_PORT_N_ACK_INBOUND) >> 24;
+ pr_debug("RIO_EM: SP%d far_ackID=0x%02x far_linkstat=0x%02x" \
+ " near_ackID=0x%02x\n",
+ pnum, far_ackid, far_linkstat, near_ackid);
+
+ /*
+ * If required, synchronize ackIDs of near and
+ * far sides.
+ */
+ if ((far_ackid != ((regval & RIO_PORT_N_ACK_OUTSTAND) >> 8)) ||
+ (far_ackid != (regval & RIO_PORT_N_ACK_OUTBOUND))) {
+ /* Align near outstanding/outbound ackIDs with
+ * far inbound.
+ */
+ rio_mport_write_config_32(mport, destid,
+ hopcount, rdev->phys_efptr +
+ RIO_PORT_N_ACK_STS_CSR(pnum),
+ (near_ackid << 24) |
+ (far_ackid << 8) | far_ackid);
+ /* Align far outstanding/outbound ackIDs with
+ * near inbound.
+ */
+ far_ackid++;
+ if (nextdev)
+ rio_write_config_32(nextdev,
+ nextdev->phys_efptr +
+ RIO_PORT_N_ACK_STS_CSR(RIO_GET_PORT_NUM(nextdev->swpinfo)),
+ (far_ackid << 24) |
+ (near_ackid << 8) | near_ackid);
+ else
+ pr_debug("RIO_EM: Invalid nextdev pointer (NULL)\n");
+ }
+rd_err:
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
+ &err_status);
+ pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status);
+ }
+
+ if ((err_status & RIO_PORT_N_ERR_STS_PW_INP_ES) && nextdev) {
+ pr_debug("RIO_EM: servicing Input Error-Stopped state\n");
+ rio_get_input_status(nextdev,
+ RIO_GET_PORT_NUM(nextdev->swpinfo), NULL);
+ udelay(50);
+
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
+ &err_status);
+ pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status);
+ }
+
+ return (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
+ RIO_PORT_N_ERR_STS_PW_INP_ES)) ? 1 : 0;
+}
+
+/**
* rio_inb_pwrite_handler - process inbound port-write message
* @pw_msg: pointer to inbound port-write message
*
@@ -507,13 +733,13 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
struct rio_mport *mport;
u8 hopcount;
u16 destid;
- u32 err_status;
+ u32 err_status, em_perrdet, em_ltlerrdet;
int rc, portnum;
rdev = rio_get_comptag(pw_msg->em.comptag, NULL);
if (rdev == NULL) {
- /* Someting bad here (probably enumeration error) */
- pr_err("RIO: %s No matching device for CTag 0x%08x\n",
+ /* Device removed or enumeration error */
+ pr_debug("RIO: %s No matching device for CTag 0x%08x\n",
__func__, pw_msg->em.comptag);
return -EIO;
}
@@ -524,12 +750,11 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
{
u32 i;
for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) {
- pr_debug("0x%02x: %08x %08x %08x %08x",
+ pr_debug("0x%02x: %08x %08x %08x %08x\n",
i*4, pw_msg->raw[i], pw_msg->raw[i + 1],
pw_msg->raw[i + 2], pw_msg->raw[i + 3]);
i += 4;
}
- pr_debug("\n");
}
#endif
@@ -545,6 +770,26 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
return 0;
}
+ portnum = pw_msg->em.is_port & 0xFF;
+
+ /* Check if device and route to it are functional:
+ * Sometimes devices may send PW message(s) just before being
+ * powered down (or link being lost).
+ */
+ if (rio_chk_dev_access(rdev)) {
+ pr_debug("RIO: device access failed - get link partner\n");
+ /* Scan route to the device and identify failed link.
+ * This will replace device and port reported in PW message.
+ * PW message should not be used after this point.
+ */
+ if (rio_chk_dev_route(rdev, &rdev, &portnum)) {
+ pr_err("RIO: Route trace for %s failed\n",
+ rio_name(rdev));
+ return -EIO;
+ }
+ pw_msg = NULL;
+ }
+
/* For End-point devices processing stops here */
if (!(rdev->pef & RIO_PEF_SWITCH))
return 0;
@@ -562,9 +807,6 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
/*
* Process the port-write notification from switch
*/
-
- portnum = pw_msg->em.is_port & 0xFF;
-
if (rdev->rswitch->em_handle)
rdev->rswitch->em_handle(rdev, portnum);
@@ -573,29 +815,28 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
&err_status);
pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status);
- if (pw_msg->em.errdetect) {
- pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n",
- portnum, pw_msg->em.errdetect);
- /* Clear EM Port N Error Detect CSR */
- rio_mport_write_config_32(mport, destid, hopcount,
- rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0);
- }
+ if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) {
- if (pw_msg->em.ltlerrdet) {
- pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n",
- pw_msg->em.ltlerrdet);
- /* Clear EM L/T Layer Error Detect CSR */
- rio_mport_write_config_32(mport, destid, hopcount,
- rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0);
- }
+ if (!(rdev->rswitch->port_ok & (1 << portnum))) {
+ rdev->rswitch->port_ok |= (1 << portnum);
+ rio_set_port_lockout(rdev, portnum, 0);
+ /* Schedule Insertion Service */
+ pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n",
+ rio_name(rdev), portnum);
+ }
- /* Clear Port Errors */
- rio_mport_write_config_32(mport, destid, hopcount,
- rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
- err_status & RIO_PORT_N_ERR_STS_CLR_MASK);
+ /* Clear error-stopped states (if reported).
+ * Depending on the link partner state, two attempts
+ * may be needed for successful recovery.
+ */
+ if (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
+ RIO_PORT_N_ERR_STS_PW_INP_ES)) {
+ if (rio_clr_err_stopped(rdev, portnum, err_status))
+ rio_clr_err_stopped(rdev, portnum, 0);
+ }
+ } else { /* if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) */
- if (rdev->rswitch->port_ok & (1 << portnum)) {
- if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) {
+ if (rdev->rswitch->port_ok & (1 << portnum)) {
rdev->rswitch->port_ok &= ~(1 << portnum);
rio_set_port_lockout(rdev, portnum, 1);
@@ -608,21 +849,32 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n",
rio_name(rdev), portnum);
}
- } else {
- if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) {
- rdev->rswitch->port_ok |= (1 << portnum);
- rio_set_port_lockout(rdev, portnum, 0);
+ }
- /* Schedule Insertion Service */
- pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n",
- rio_name(rdev), portnum);
- }
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet);
+ if (em_perrdet) {
+ pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n",
+ portnum, em_perrdet);
+ /* Clear EM Port N Error Detect CSR */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0);
+ }
+
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet);
+ if (em_ltlerrdet) {
+ pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n",
+ em_ltlerrdet);
+ /* Clear EM L/T Layer Error Detect CSR */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0);
}
- /* Clear Port-Write Pending bit */
+ /* Clear remaining error bits and Port-Write Pending bit */
rio_mport_write_config_32(mport, destid, hopcount,
rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
- RIO_PORT_N_ERR_STS_PW_PEND);
+ err_status);
return 0;
}
diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h
index f27b7a9c47d2..b1af414f15e6 100644
--- a/drivers/rapidio/rio.h
+++ b/drivers/rapidio/rio.h
@@ -14,6 +14,8 @@
#include <linux/list.h>
#include <linux/rio.h>
+#define RIO_MAX_CHK_RETRY 3
+
/* Functions internal to the RIO core code */
extern u32 rio_mport_get_feature(struct rio_mport *mport, int local, u16 destid,
@@ -22,6 +24,8 @@ extern u32 rio_mport_get_physefb(struct rio_mport *port, int local,
u16 destid, u8 hopcount);
extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
u8 hopcount, u32 from);
+extern int rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid,
+ u8 hopcount);
extern int rio_create_sysfs_dev_files(struct rio_dev *rdev);
extern int rio_enum_mport(struct rio_mport *mport);
extern int rio_disc_mport(struct rio_mport *mport);
@@ -34,6 +38,7 @@ extern int rio_std_route_get_entry(struct rio_mport *mport, u16 destid,
extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid,
u8 hopcount, u16 table);
extern int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock);
+extern struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from);
/* Structures internal to the RIO core code */
extern struct device_attribute rio_dev_attrs[];
diff --git a/drivers/rapidio/switches/Kconfig b/drivers/rapidio/switches/Kconfig
index 2b4e9b2b6631..f47fee5d4563 100644
--- a/drivers/rapidio/switches/Kconfig
+++ b/drivers/rapidio/switches/Kconfig
@@ -20,6 +20,13 @@ config RAPIDIO_TSI568
---help---
Includes support for IDT Tsi568 serial RapidIO switch.
+config RAPIDIO_CPS_GEN2
+ bool "IDT CPS Gen.2 SRIO switch support"
+ depends on RAPIDIO
+ default n
+ ---help---
+ Includes support for ITD CPS Gen.2 serial RapidIO switches.
+
config RAPIDIO_TSI500
bool "Tsi500 Parallel RapidIO switch support"
depends on RAPIDIO
diff --git a/drivers/rapidio/switches/Makefile b/drivers/rapidio/switches/Makefile
index fe4adc3e8d5f..48d67a6b98c8 100644
--- a/drivers/rapidio/switches/Makefile
+++ b/drivers/rapidio/switches/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_RAPIDIO_TSI57X) += tsi57x.o
obj-$(CONFIG_RAPIDIO_CPS_XX) += idtcps.o
obj-$(CONFIG_RAPIDIO_TSI568) += tsi568.o
obj-$(CONFIG_RAPIDIO_TSI500) += tsi500.o
+obj-$(CONFIG_RAPIDIO_CPS_GEN2) += idt_gen2.o
ifeq ($(CONFIG_RAPIDIO_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c
new file mode 100644
index 000000000000..0bb871cb5c40
--- /dev/null
+++ b/drivers/rapidio/switches/idt_gen2.c
@@ -0,0 +1,447 @@
+/*
+ * IDT CPS Gen.2 Serial RapidIO switch family support
+ *
+ * Copyright 2010 Integrated Device Technology, Inc.
+ * Alexandre Bounine <alexandre.bounine@idt.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/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+#include <linux/delay.h>
+#include "../rio.h"
+
+#define LOCAL_RTE_CONF_DESTID_SEL 0x010070
+#define LOCAL_RTE_CONF_DESTID_SEL_PSEL 0x0000001f
+
+#define IDT_LT_ERR_REPORT_EN 0x03100c
+
+#define IDT_PORT_ERR_REPORT_EN(n) (0x031044 + (n)*0x40)
+#define IDT_PORT_ERR_REPORT_EN_BC 0x03ff04
+
+#define IDT_PORT_ISERR_REPORT_EN(n) (0x03104C + (n)*0x40)
+#define IDT_PORT_ISERR_REPORT_EN_BC 0x03ff0c
+#define IDT_PORT_INIT_TX_ACQUIRED 0x00000020
+
+#define IDT_LANE_ERR_REPORT_EN(n) (0x038010 + (n)*0x100)
+#define IDT_LANE_ERR_REPORT_EN_BC 0x03ff10
+
+#define IDT_DEV_CTRL_1 0xf2000c
+#define IDT_DEV_CTRL_1_GENPW 0x02000000
+#define IDT_DEV_CTRL_1_PRSTBEH 0x00000001
+
+#define IDT_CFGBLK_ERR_CAPTURE_EN 0x020008
+#define IDT_CFGBLK_ERR_REPORT 0xf20014
+#define IDT_CFGBLK_ERR_REPORT_GENPW 0x00000002
+
+#define IDT_AUX_PORT_ERR_CAP_EN 0x020000
+#define IDT_AUX_ERR_REPORT_EN 0xf20018
+#define IDT_AUX_PORT_ERR_LOG_I2C 0x00000002
+#define IDT_AUX_PORT_ERR_LOG_JTAG 0x00000001
+
+#define IDT_ISLTL_ADDRESS_CAP 0x021014
+
+#define IDT_RIO_DOMAIN 0xf20020
+#define IDT_RIO_DOMAIN_MASK 0x000000ff
+
+#define IDT_PW_INFO_CSR 0xf20024
+
+#define IDT_SOFT_RESET 0xf20040
+#define IDT_SOFT_RESET_REQ 0x00030097
+
+#define IDT_I2C_MCTRL 0xf20050
+#define IDT_I2C_MCTRL_GENPW 0x04000000
+
+#define IDT_JTAG_CTRL 0xf2005c
+#define IDT_JTAG_CTRL_GENPW 0x00000002
+
+#define IDT_LANE_CTRL(n) (0xff8000 + (n)*0x100)
+#define IDT_LANE_CTRL_BC 0xffff00
+#define IDT_LANE_CTRL_GENPW 0x00200000
+#define IDT_LANE_DFE_1_BC 0xffff18
+#define IDT_LANE_DFE_2_BC 0xffff1c
+
+#define IDT_PORT_OPS(n) (0xf40004 + (n)*0x100)
+#define IDT_PORT_OPS_GENPW 0x08000000
+#define IDT_PORT_OPS_PL_ELOG 0x00000040
+#define IDT_PORT_OPS_LL_ELOG 0x00000020
+#define IDT_PORT_OPS_LT_ELOG 0x00000010
+#define IDT_PORT_OPS_BC 0xf4ff04
+
+#define IDT_PORT_ISERR_DET(n) (0xf40008 + (n)*0x100)
+
+#define IDT_ERR_CAP 0xfd0000
+#define IDT_ERR_CAP_LOG_OVERWR 0x00000004
+
+#define IDT_ERR_RD 0xfd0004
+
+#define IDT_DEFAULT_ROUTE 0xde
+#define IDT_NO_ROUTE 0xdf
+
+static int
+idtg2_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+ u16 table, u16 route_destid, u8 route_port)
+{
+ /*
+ * Select routing table to update
+ */
+ if (table == RIO_GLOBAL_TABLE)
+ table = 0;
+ else
+ table++;
+
+ rio_mport_write_config_32(mport, destid, hopcount,
+ LOCAL_RTE_CONF_DESTID_SEL, table);
+
+ /*
+ * Program destination port for the specified destID
+ */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ RIO_STD_RTE_CONF_DESTID_SEL_CSR,
+ (u32)route_destid);
+
+ rio_mport_write_config_32(mport, destid, hopcount,
+ RIO_STD_RTE_CONF_PORT_SEL_CSR,
+ (u32)route_port);
+ udelay(10);
+
+ return 0;
+}
+
+static int
+idtg2_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+ u16 table, u16 route_destid, u8 *route_port)
+{
+ u32 result;
+
+ /*
+ * Select routing table to read
+ */
+ if (table == RIO_GLOBAL_TABLE)
+ table = 0;
+ else
+ table++;
+
+ rio_mport_write_config_32(mport, destid, hopcount,
+ LOCAL_RTE_CONF_DESTID_SEL, table);
+
+ rio_mport_write_config_32(mport, destid, hopcount,
+ RIO_STD_RTE_CONF_DESTID_SEL_CSR,
+ route_destid);
+
+ rio_mport_read_config_32(mport, destid, hopcount,
+ RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
+
+ if (IDT_DEFAULT_ROUTE == (u8)result || IDT_NO_ROUTE == (u8)result)
+ *route_port = RIO_INVALID_ROUTE;
+ else
+ *route_port = (u8)result;
+
+ return 0;
+}
+
+static int
+idtg2_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+ u16 table)
+{
+ u32 i;
+
+ /*
+ * Select routing table to read
+ */
+ if (table == RIO_GLOBAL_TABLE)
+ table = 0;
+ else
+ table++;
+
+ rio_mport_write_config_32(mport, destid, hopcount,
+ LOCAL_RTE_CONF_DESTID_SEL, table);
+
+ for (i = RIO_STD_RTE_CONF_EXTCFGEN;
+ i <= (RIO_STD_RTE_CONF_EXTCFGEN | 0xff);) {
+ rio_mport_write_config_32(mport, destid, hopcount,
+ RIO_STD_RTE_CONF_DESTID_SEL_CSR, i);
+ rio_mport_write_config_32(mport, destid, hopcount,
+ RIO_STD_RTE_CONF_PORT_SEL_CSR,
+ (IDT_DEFAULT_ROUTE << 24) | (IDT_DEFAULT_ROUTE << 16) |
+ (IDT_DEFAULT_ROUTE << 8) | IDT_DEFAULT_ROUTE);
+ i += 4;
+ }
+
+ return 0;
+}
+
+
+static int
+idtg2_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
+ u8 sw_domain)
+{
+ /*
+ * Switch domain configuration operates only at global level
+ */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_RIO_DOMAIN, (u32)sw_domain);
+ return 0;
+}
+
+static int
+idtg2_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
+ u8 *sw_domain)
+{
+ u32 regval;
+
+ /*
+ * Switch domain configuration operates only at global level
+ */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_RIO_DOMAIN, &regval);
+
+ *sw_domain = (u8)(regval & 0xff);
+
+ return 0;
+}
+
+static int
+idtg2_em_init(struct rio_dev *rdev)
+{
+ struct rio_mport *mport = rdev->net->hport;
+ u16 destid = rdev->rswitch->destid;
+ u8 hopcount = rdev->rswitch->hopcount;
+ u32 regval;
+ int i, tmp;
+
+ /*
+ * This routine performs device-specific initialization only.
+ * All standard EM configuration should be performed at upper level.
+ */
+
+ pr_debug("RIO: %s [%d:%d]\n", __func__, destid, hopcount);
+
+ /* Set Port-Write info CSR: PRIO=3 and CRF=1 */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_PW_INFO_CSR, 0x0000e000);
+
+ /*
+ * Configure LT LAYER error reporting.
+ */
+
+ /* Enable standard (RIO.p8) error reporting */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_LT_ERR_REPORT_EN,
+ REM_LTL_ERR_ILLTRAN | REM_LTL_ERR_UNSOLR |
+ REM_LTL_ERR_UNSUPTR);
+
+ /* Use Port-Writes for LT layer error reporting.
+ * Enable per-port reset
+ */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_DEV_CTRL_1, &regval);
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_DEV_CTRL_1,
+ regval | IDT_DEV_CTRL_1_GENPW | IDT_DEV_CTRL_1_PRSTBEH);
+
+ /*
+ * Configure PORT error reporting.
+ */
+
+ /* Report all RIO.p8 errors supported by device */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_PORT_ERR_REPORT_EN_BC, 0x807e8037);
+
+ /* Configure reporting of implementation specific errors/events */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_PORT_ISERR_REPORT_EN_BC, IDT_PORT_INIT_TX_ACQUIRED);
+
+ /* Use Port-Writes for port error reporting and enable error logging */
+ tmp = RIO_GET_TOTAL_PORTS(rdev->swpinfo);
+ for (i = 0; i < tmp; i++) {
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_PORT_OPS(i), &regval);
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_PORT_OPS(i), regval | IDT_PORT_OPS_GENPW |
+ IDT_PORT_OPS_PL_ELOG |
+ IDT_PORT_OPS_LL_ELOG |
+ IDT_PORT_OPS_LT_ELOG);
+ }
+ /* Overwrite error log if full */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_ERR_CAP, IDT_ERR_CAP_LOG_OVERWR);
+
+ /*
+ * Configure LANE error reporting.
+ */
+
+ /* Disable line error reporting */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_LANE_ERR_REPORT_EN_BC, 0);
+
+ /* Use Port-Writes for lane error reporting (when enabled)
+ * (do per-lane update because lanes may have different configuration)
+ */
+ tmp = (rdev->did == RIO_DID_IDTCPS1848) ? 48 : 16;
+ for (i = 0; i < tmp; i++) {
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_LANE_CTRL(i), &regval);
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_LANE_CTRL(i), regval | IDT_LANE_CTRL_GENPW);
+ }
+
+ /*
+ * Configure AUX error reporting.
+ */
+
+ /* Disable JTAG and I2C Error capture */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_AUX_PORT_ERR_CAP_EN, 0);
+
+ /* Disable JTAG and I2C Error reporting/logging */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_AUX_ERR_REPORT_EN, 0);
+
+ /* Disable Port-Write notification from JTAG */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_JTAG_CTRL, 0);
+
+ /* Disable Port-Write notification from I2C */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_I2C_MCTRL, &regval);
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_I2C_MCTRL,
+ regval & ~IDT_I2C_MCTRL_GENPW);
+
+ /*
+ * Configure CFG_BLK error reporting.
+ */
+
+ /* Disable Configuration Block error capture */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_CFGBLK_ERR_CAPTURE_EN, 0);
+
+ /* Disable Port-Writes for Configuration Block error reporting */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_CFGBLK_ERR_REPORT, &regval);
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_CFGBLK_ERR_REPORT,
+ regval & ~IDT_CFGBLK_ERR_REPORT_GENPW);
+
+ /* set TVAL = ~50us */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8);
+
+ return 0;
+}
+
+static int
+idtg2_em_handler(struct rio_dev *rdev, u8 portnum)
+{
+ struct rio_mport *mport = rdev->net->hport;
+ u16 destid = rdev->rswitch->destid;
+ u8 hopcount = rdev->rswitch->hopcount;
+ u32 regval, em_perrdet, em_ltlerrdet;
+
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet);
+ if (em_ltlerrdet) {
+ /* Service Logical/Transport Layer Error(s) */
+ if (em_ltlerrdet & REM_LTL_ERR_IMPSPEC) {
+ /* Implementation specific error reported */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_ISLTL_ADDRESS_CAP, &regval);
+
+ pr_debug("RIO: %s Implementation Specific LTL errors" \
+ " 0x%x @(0x%x)\n",
+ rio_name(rdev), em_ltlerrdet, regval);
+
+ /* Clear implementation specific address capture CSR */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_ISLTL_ADDRESS_CAP, 0);
+
+ }
+ }
+
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet);
+ if (em_perrdet) {
+ /* Service Port-Level Error(s) */
+ if (em_perrdet & REM_PED_IMPL_SPEC) {
+ /* Implementation Specific port error reported */
+
+ /* Get IS errors reported */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_PORT_ISERR_DET(portnum), &regval);
+
+ pr_debug("RIO: %s Implementation Specific Port" \
+ " errors 0x%x\n", rio_name(rdev), regval);
+
+ /* Clear all implementation specific events */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_PORT_ISERR_DET(portnum), 0);
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t
+idtg2_show_errlog(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct rio_dev *rdev = to_rio_dev(dev);
+ struct rio_mport *mport = rdev->net->hport;
+ u16 destid = rdev->rswitch->destid;
+ u8 hopcount = rdev->rswitch->hopcount;
+ ssize_t len = 0;
+ u32 regval;
+
+ while (!rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_ERR_RD, &regval)) {
+ if (!regval) /* 0 = end of log */
+ break;
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "%08x\n", regval);
+ if (len >= (PAGE_SIZE - 10))
+ break;
+ }
+
+ return len;
+}
+
+static DEVICE_ATTR(errlog, S_IRUGO, idtg2_show_errlog, NULL);
+
+static int idtg2_sysfs(struct rio_dev *rdev, int create)
+{
+ struct device *dev = &rdev->dev;
+ int err = 0;
+
+ if (create == RIO_SW_SYSFS_CREATE) {
+ /* Initialize sysfs entries */
+ err = device_create_file(dev, &dev_attr_errlog);
+ if (err)
+ dev_err(dev, "Unable create sysfs errlog file\n");
+ } else
+ device_remove_file(dev, &dev_attr_errlog);
+
+ return err;
+}
+
+static int idtg2_switch_init(struct rio_dev *rdev, int do_enum)
+{
+ pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+ rdev->rswitch->add_entry = idtg2_route_add_entry;
+ rdev->rswitch->get_entry = idtg2_route_get_entry;
+ rdev->rswitch->clr_table = idtg2_route_clr_table;
+ rdev->rswitch->set_domain = idtg2_set_domain;
+ rdev->rswitch->get_domain = idtg2_get_domain;
+ rdev->rswitch->em_init = idtg2_em_init;
+ rdev->rswitch->em_handle = idtg2_em_handler;
+ rdev->rswitch->sw_sysfs = idtg2_sysfs;
+
+ return 0;
+}
+
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1848, idtg2_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1616, idtg2_switch_init);
diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c
index 2c790c144f89..fc9f6374f759 100644
--- a/drivers/rapidio/switches/idtcps.c
+++ b/drivers/rapidio/switches/idtcps.c
@@ -117,6 +117,10 @@ idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
{
+ struct rio_mport *mport = rdev->net->hport;
+ u16 destid = rdev->rswitch->destid;
+ u8 hopcount = rdev->rswitch->hopcount;
+
pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
rdev->rswitch->add_entry = idtcps_route_add_entry;
rdev->rswitch->get_entry = idtcps_route_get_entry;
@@ -126,6 +130,12 @@ static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
rdev->rswitch->em_init = NULL;
rdev->rswitch->em_handle = NULL;
+ if (do_enum) {
+ /* set TVAL = ~50us */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8);
+ }
+
return 0;
}
diff --git a/drivers/rapidio/switches/tsi568.c b/drivers/rapidio/switches/tsi568.c
index f7fd7898606e..b9a389b9f812 100644
--- a/drivers/rapidio/switches/tsi568.c
+++ b/drivers/rapidio/switches/tsi568.c
@@ -29,7 +29,7 @@
#define SPP_ROUTE_CFG_DESTID(n) (0x11070 + 0x100*n)
#define SPP_ROUTE_CFG_PORT(n) (0x11074 + 0x100*n)
-#define TSI568_SP_MODE_BC 0x10004
+#define TSI568_SP_MODE(n) (0x11004 + 0x100*n)
#define TSI568_SP_MODE_PW_DIS 0x08000000
static int
@@ -117,14 +117,19 @@ tsi568_em_init(struct rio_dev *rdev)
u16 destid = rdev->rswitch->destid;
u8 hopcount = rdev->rswitch->hopcount;
u32 regval;
+ int portnum;
pr_debug("TSI568 %s [%d:%d]\n", __func__, destid, hopcount);
/* Make sure that Port-Writes are disabled (for all ports) */
- rio_mport_read_config_32(mport, destid, hopcount,
- TSI568_SP_MODE_BC, &regval);
- rio_mport_write_config_32(mport, destid, hopcount,
- TSI568_SP_MODE_BC, regval | TSI568_SP_MODE_PW_DIS);
+ for (portnum = 0;
+ portnum < RIO_GET_TOTAL_PORTS(rdev->swpinfo); portnum++) {
+ rio_mport_read_config_32(mport, destid, hopcount,
+ TSI568_SP_MODE(portnum), &regval);
+ rio_mport_write_config_32(mport, destid, hopcount,
+ TSI568_SP_MODE(portnum),
+ regval | TSI568_SP_MODE_PW_DIS);
+ }
return 0;
}
diff --git a/drivers/rapidio/switches/tsi57x.c b/drivers/rapidio/switches/tsi57x.c
index d34df722d95f..2003fb63c404 100644
--- a/drivers/rapidio/switches/tsi57x.c
+++ b/drivers/rapidio/switches/tsi57x.c
@@ -166,7 +166,8 @@ tsi57x_em_init(struct rio_dev *rdev)
pr_debug("TSI578 %s [%d:%d]\n", __func__, destid, hopcount);
- for (portnum = 0; portnum < 16; portnum++) {
+ for (portnum = 0;
+ portnum < RIO_GET_TOTAL_PORTS(rdev->swpinfo); portnum++) {
/* Make sure that Port-Writes are enabled (for all ports) */
rio_mport_read_config_32(mport, destid, hopcount,
TSI578_SP_MODE(portnum), &regval);
@@ -205,6 +206,10 @@ tsi57x_em_init(struct rio_dev *rdev)
portnum++;
}
+ /* set TVAL = ~50us */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x9a << 8);
+
return 0;
}
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 48ca7132cc05..6a77437d4f5a 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -171,7 +171,8 @@ config RTC_DRV_DS3232
depends on RTC_CLASS && I2C
help
If you say yes here you get support for Dallas Semiconductor
- DS3232 real-time clock chips.
+ DS3232 real-time clock chips. If an interrupt is associated
+ with the device, the alarm functionality is supported.
This driver can also be built as a module. If so, the module
will be called rtc-ds3232.
@@ -765,15 +766,15 @@ config RTC_DRV_AT32AP700X
AT32AP700x family processors.
config RTC_DRV_AT91RM9200
- tristate "AT91RM9200 or AT91SAM9RL"
- depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL
+ tristate "AT91RM9200 or some AT91SAM9 RTC"
+ depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
help
Driver for the internal RTC (Realtime Clock) module found on
- Atmel AT91RM9200's and AT91SAM9RL chips. On SAM9RL chips
+ Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips
this is powered by the backup power supply.
config RTC_DRV_AT91SAM9
- tristate "AT91SAM9x/AT91CAP9"
+ tristate "AT91SAM9x/AT91CAP9 RTT as RTC"
depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40)
help
RTC driver for the Atmel AT91SAM9x and AT91CAP9 internal RTT
@@ -781,8 +782,8 @@ config RTC_DRV_AT91SAM9
supply (such as a small coin cell battery), but do not need to
be used as RTCs.
- (On AT91SAM9rl chips you probably want to use the dedicated RTC
- module and leave the RTT available for other uses.)
+ (On AT91SAM9rl and AT91SAM9G45 chips you probably want to use the
+ dedicated RTC module and leave the RTT available for other uses.)
config RTC_DRV_AT91SAM9_RTT
int
@@ -952,4 +953,13 @@ config RTC_DRV_JZ4740
This driver can also be buillt as a module. If so, the module
will be called rtc-jz4740.
+config RTC_DRV_LPC32XX
+ depends on ARCH_LPC32XX
+ tristate "NXP LPC32XX RTC"
+ help
+ This enables support for the NXP RTC in the LPC32XX
+
+ This driver can also be buillt as a module. If so, the module
+ will be called rtc-lpc32xx.
+
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 0f207b3b5833..7a7cb3228a1d 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o
obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
+obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 565562ba6ac9..e6539cbabb35 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -158,8 +158,10 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
rtc_dev_prepare(rtc);
err = device_register(&rtc->dev);
- if (err)
+ if (err) {
+ put_device(&rtc->dev);
goto exit_kfree;
+ }
rtc_dev_add_device(rtc);
rtc_sysfs_add_device(rtc);
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c
index d4fb82d85e9b..b4b6087f2234 100644
--- a/drivers/rtc/rtc-bfin.c
+++ b/drivers/rtc/rtc-bfin.c
@@ -2,7 +2,7 @@
* Blackfin On-Chip Real Time Clock Driver
* Supports BF51x/BF52x/BF53[123]/BF53[467]/BF54x
*
- * Copyright 2004-2009 Analog Devices Inc.
+ * Copyright 2004-2010 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
@@ -183,29 +183,33 @@ static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id)
struct bfin_rtc *rtc = dev_get_drvdata(dev);
unsigned long events = 0;
bool write_complete = false;
- u16 rtc_istat, rtc_ictl;
+ u16 rtc_istat, rtc_istat_clear, rtc_ictl, bits;
dev_dbg_stamp(dev);
rtc_istat = bfin_read_RTC_ISTAT();
rtc_ictl = bfin_read_RTC_ICTL();
+ rtc_istat_clear = 0;
- if (rtc_istat & RTC_ISTAT_WRITE_COMPLETE) {
- bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE);
+ bits = RTC_ISTAT_WRITE_COMPLETE;
+ if (rtc_istat & bits) {
+ rtc_istat_clear |= bits;
write_complete = true;
complete(&bfin_write_complete);
}
- if (rtc_ictl & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
- if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
- bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY);
+ bits = (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY);
+ if (rtc_ictl & bits) {
+ if (rtc_istat & bits) {
+ rtc_istat_clear |= bits;
events |= RTC_AF | RTC_IRQF;
}
}
- if (rtc_ictl & RTC_ISTAT_SEC) {
- if (rtc_istat & RTC_ISTAT_SEC) {
- bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
+ bits = RTC_ISTAT_SEC;
+ if (rtc_ictl & bits) {
+ if (rtc_istat & bits) {
+ rtc_istat_clear |= bits;
events |= RTC_UF | RTC_IRQF;
}
}
@@ -213,9 +217,10 @@ static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id)
if (events)
rtc_update_irq(rtc->rtc_dev, 1, events);
- if (write_complete || events)
+ if (write_complete || events) {
+ bfin_write_RTC_ISTAT(rtc_istat_clear);
return IRQ_HANDLED;
- else
+ } else
return IRQ_NONE;
}
@@ -422,9 +427,13 @@ static int __devexit bfin_rtc_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{
- if (device_may_wakeup(&pdev->dev)) {
+ struct device *dev = &pdev->dev;
+
+ dev_dbg_stamp(dev);
+
+ if (device_may_wakeup(dev)) {
enable_irq_wake(IRQ_RTC);
- bfin_rtc_sync_pending(&pdev->dev);
+ bfin_rtc_sync_pending(dev);
} else
bfin_rtc_int_clear(0);
@@ -433,7 +442,11 @@ static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state)
static int bfin_rtc_resume(struct platform_device *pdev)
{
- if (device_may_wakeup(&pdev->dev))
+ struct device *dev = &pdev->dev;
+
+ dev_dbg_stamp(dev);
+
+ if (device_may_wakeup(dev))
disable_irq_wake(IRQ_RTC);
/*
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c
index 9de8516e3531..57063552d3b7 100644
--- a/drivers/rtc/rtc-ds3232.c
+++ b/drivers/rtc/rtc-ds3232.c
@@ -2,6 +2,7 @@
* RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C
*
* Copyright (C) 2009-2010 Freescale Semiconductor.
+ * Author: Jack Lan <jack.lan@freescale.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
@@ -175,6 +176,182 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time)
DS3232_REG_SECONDS, 7, buf);
}
+/*
+ * DS3232 has two alarm, we only use alarm1
+ * According to linux specification, only support one-shot alarm
+ * no periodic alarm mode
+ */
+static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds3232 *ds3232 = i2c_get_clientdata(client);
+ int control, stat;
+ int ret;
+ u8 buf[4];
+
+ mutex_lock(&ds3232->mutex);
+
+ ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
+ if (ret < 0)
+ goto out;
+ stat = ret;
+ ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
+ if (ret < 0)
+ goto out;
+ control = ret;
+ ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
+ if (ret < 0)
+ goto out;
+
+ alarm->time.tm_sec = bcd2bin(buf[0] & 0x7F);
+ alarm->time.tm_min = bcd2bin(buf[1] & 0x7F);
+ alarm->time.tm_hour = bcd2bin(buf[2] & 0x7F);
+ alarm->time.tm_mday = bcd2bin(buf[3] & 0x7F);
+
+ alarm->time.tm_mon = -1;
+ alarm->time.tm_year = -1;
+ alarm->time.tm_wday = -1;
+ alarm->time.tm_yday = -1;
+ alarm->time.tm_isdst = -1;
+
+ alarm->enabled = !!(control & DS3232_REG_CR_A1IE);
+ alarm->pending = !!(stat & DS3232_REG_SR_A1F);
+
+ ret = 0;
+out:
+ mutex_unlock(&ds3232->mutex);
+ return ret;
+}
+
+/*
+ * linux rtc-module does not support wday alarm
+ * and only 24h time mode supported indeed
+ */
+static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds3232 *ds3232 = i2c_get_clientdata(client);
+ int control, stat;
+ int ret;
+ u8 buf[4];
+
+ if (client->irq <= 0)
+ return -EINVAL;
+
+ mutex_lock(&ds3232->mutex);
+
+ buf[0] = bin2bcd(alarm->time.tm_sec);
+ buf[1] = bin2bcd(alarm->time.tm_min);
+ buf[2] = bin2bcd(alarm->time.tm_hour);
+ buf[3] = bin2bcd(alarm->time.tm_mday);
+
+ /* clear alarm interrupt enable bit */
+ ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
+ if (ret < 0)
+ goto out;
+ control = ret;
+ control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE);
+ ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
+ if (ret < 0)
+ goto out;
+
+ /* clear any pending alarm flag */
+ ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR);
+ if (ret < 0)
+ goto out;
+ stat = ret;
+ stat &= ~(DS3232_REG_SR_A1F | DS3232_REG_SR_A2F);
+ ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
+ if (ret < 0)
+ goto out;
+
+ ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
+
+ if (alarm->enabled) {
+ control |= DS3232_REG_CR_A1IE;
+ ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
+ }
+out:
+ mutex_unlock(&ds3232->mutex);
+ return ret;
+}
+
+static void ds3232_update_alarm(struct i2c_client *client)
+{
+ struct ds3232 *ds3232 = i2c_get_clientdata(client);
+ int control;
+ int ret;
+ u8 buf[4];
+
+ mutex_lock(&ds3232->mutex);
+
+ ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
+ if (ret < 0)
+ goto unlock;
+
+ buf[0] = bcd2bin(buf[0]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
+ 0x80 : buf[0];
+ buf[1] = bcd2bin(buf[1]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
+ 0x80 : buf[1];
+ buf[2] = bcd2bin(buf[2]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
+ 0x80 : buf[2];
+ buf[3] = bcd2bin(buf[3]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
+ 0x80 : buf[3];
+
+ ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf);
+ if (ret < 0)
+ goto unlock;
+
+ control = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
+ if (control < 0)
+ goto unlock;
+
+ if (ds3232->rtc->irq_data & (RTC_AF | RTC_UF))
+ /* enable alarm1 interrupt */
+ control |= DS3232_REG_CR_A1IE;
+ else
+ /* disable alarm1 interrupt */
+ control &= ~(DS3232_REG_CR_A1IE);
+ i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
+
+unlock:
+ mutex_unlock(&ds3232->mutex);
+}
+
+static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds3232 *ds3232 = i2c_get_clientdata(client);
+
+ if (client->irq <= 0)
+ return -EINVAL;
+
+ if (enabled)
+ ds3232->rtc->irq_data |= RTC_AF;
+ else
+ ds3232->rtc->irq_data &= ~RTC_AF;
+
+ ds3232_update_alarm(client);
+ return 0;
+}
+
+static int ds3232_update_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds3232 *ds3232 = i2c_get_clientdata(client);
+
+ if (client->irq <= 0)
+ return -EINVAL;
+
+ if (enabled)
+ ds3232->rtc->irq_data |= RTC_UF;
+ else
+ ds3232->rtc->irq_data &= ~RTC_UF;
+
+ ds3232_update_alarm(client);
+ return 0;
+}
+
static irqreturn_t ds3232_irq(int irq, void *dev_id)
{
struct i2c_client *client = dev_id;
@@ -222,6 +399,10 @@ unlock:
static const struct rtc_class_ops ds3232_rtc_ops = {
.read_time = ds3232_read_time,
.set_time = ds3232_set_time,
+ .read_alarm = ds3232_read_alarm,
+ .set_alarm = ds3232_set_alarm,
+ .alarm_irq_enable = ds3232_alarm_irq_enable,
+ .update_irq_enable = ds3232_update_irq_enable,
};
static int __devinit ds3232_probe(struct i2c_client *client,
diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c
index 2619d57b91d7..2e16f72c9056 100644
--- a/drivers/rtc/rtc-jz4740.c
+++ b/drivers/rtc/rtc-jz4740.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * Copyright (C) 2010, Paul Cercueil <paul@crapouillou.net>
* JZ4740 SoC RTC driver
*
* This program is free software; you can redistribute it and/or modify it
@@ -161,7 +162,8 @@ static int jz4740_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC_ALARM, secs);
if (!ret)
- ret = jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_AE, alrm->enabled);
+ ret = jz4740_rtc_ctrl_set_bits(rtc,
+ JZ_RTC_CTRL_AE | JZ_RTC_CTRL_AF_IRQ, alrm->enabled);
return ret;
}
@@ -258,6 +260,8 @@ static int __devinit jz4740_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, rtc);
+ device_init_wakeup(&pdev->dev, 1);
+
rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &jz4740_rtc_ops,
THIS_MODULE);
if (IS_ERR(rtc->rtc)) {
@@ -318,12 +322,43 @@ static int __devexit jz4740_rtc_remove(struct platform_device *pdev)
return 0;
}
+
+#ifdef CONFIG_PM
+static int jz4740_rtc_suspend(struct device *dev)
+{
+ struct jz4740_rtc *rtc = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(rtc->irq);
+ return 0;
+}
+
+static int jz4740_rtc_resume(struct device *dev)
+{
+ struct jz4740_rtc *rtc = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(rtc->irq);
+ return 0;
+}
+
+static const struct dev_pm_ops jz4740_pm_ops = {
+ .suspend = jz4740_rtc_suspend,
+ .resume = jz4740_rtc_resume,
+};
+#define JZ4740_RTC_PM_OPS (&jz4740_pm_ops)
+
+#else
+#define JZ4740_RTC_PM_OPS NULL
+#endif /* CONFIG_PM */
+
struct platform_driver jz4740_rtc_driver = {
- .probe = jz4740_rtc_probe,
- .remove = __devexit_p(jz4740_rtc_remove),
- .driver = {
- .name = "jz4740-rtc",
+ .probe = jz4740_rtc_probe,
+ .remove = __devexit_p(jz4740_rtc_remove),
+ .driver = {
+ .name = "jz4740-rtc",
.owner = THIS_MODULE,
+ .pm = JZ4740_RTC_PM_OPS,
},
};
diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c
new file mode 100644
index 000000000000..ec8701ce99f9
--- /dev/null
+++ b/drivers/rtc/rtc-lpc32xx.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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.
+ *
+ * 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/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+/*
+ * Clock and Power control register offsets
+ */
+#define LPC32XX_RTC_UCOUNT 0x00
+#define LPC32XX_RTC_DCOUNT 0x04
+#define LPC32XX_RTC_MATCH0 0x08
+#define LPC32XX_RTC_MATCH1 0x0C
+#define LPC32XX_RTC_CTRL 0x10
+#define LPC32XX_RTC_INTSTAT 0x14
+#define LPC32XX_RTC_KEY 0x18
+#define LPC32XX_RTC_SRAM 0x80
+
+#define LPC32XX_RTC_CTRL_MATCH0 (1 << 0)
+#define LPC32XX_RTC_CTRL_MATCH1 (1 << 1)
+#define LPC32XX_RTC_CTRL_ONSW_MATCH0 (1 << 2)
+#define LPC32XX_RTC_CTRL_ONSW_MATCH1 (1 << 3)
+#define LPC32XX_RTC_CTRL_SW_RESET (1 << 4)
+#define LPC32XX_RTC_CTRL_CNTR_DIS (1 << 6)
+#define LPC32XX_RTC_CTRL_ONSW_FORCE_HI (1 << 7)
+
+#define LPC32XX_RTC_INTSTAT_MATCH0 (1 << 0)
+#define LPC32XX_RTC_INTSTAT_MATCH1 (1 << 1)
+#define LPC32XX_RTC_INTSTAT_ONSW (1 << 2)
+
+#define LPC32XX_RTC_KEY_ONSW_LOADVAL 0xB5C13F27
+
+#define RTC_NAME "rtc-lpc32xx"
+
+#define rtc_readl(dev, reg) \
+ __raw_readl((dev)->rtc_base + (reg))
+#define rtc_writel(dev, reg, val) \
+ __raw_writel((val), (dev)->rtc_base + (reg))
+
+struct lpc32xx_rtc {
+ void __iomem *rtc_base;
+ int irq;
+ unsigned char alarm_enabled;
+ struct rtc_device *rtc;
+ spinlock_t lock;
+};
+
+static int lpc32xx_rtc_read_time(struct device *dev, struct rtc_time *time)
+{
+ unsigned long elapsed_sec;
+ struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
+
+ elapsed_sec = rtc_readl(rtc, LPC32XX_RTC_UCOUNT);
+ rtc_time_to_tm(elapsed_sec, time);
+
+ return rtc_valid_tm(time);
+}
+
+static int lpc32xx_rtc_set_mmss(struct device *dev, unsigned long secs)
+{
+ struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
+ u32 tmp;
+
+ spin_lock_irq(&rtc->lock);
+
+ /* RTC must be disabled during count update */
+ tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
+ rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp | LPC32XX_RTC_CTRL_CNTR_DIS);
+ rtc_writel(rtc, LPC32XX_RTC_UCOUNT, secs);
+ rtc_writel(rtc, LPC32XX_RTC_DCOUNT, 0xFFFFFFFF - secs);
+ rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp &= ~LPC32XX_RTC_CTRL_CNTR_DIS);
+
+ spin_unlock_irq(&rtc->lock);
+
+ return 0;
+}
+
+static int lpc32xx_rtc_read_alarm(struct device *dev,
+ struct rtc_wkalrm *wkalrm)
+{
+ struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
+
+ rtc_time_to_tm(rtc_readl(rtc, LPC32XX_RTC_MATCH0), &wkalrm->time);
+ wkalrm->enabled = rtc->alarm_enabled;
+ wkalrm->pending = !!(rtc_readl(rtc, LPC32XX_RTC_INTSTAT) &
+ LPC32XX_RTC_INTSTAT_MATCH0);
+
+ return rtc_valid_tm(&wkalrm->time);
+}
+
+static int lpc32xx_rtc_set_alarm(struct device *dev,
+ struct rtc_wkalrm *wkalrm)
+{
+ struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
+ unsigned long alarmsecs;
+ u32 tmp;
+ int ret;
+
+ ret = rtc_tm_to_time(&wkalrm->time, &alarmsecs);
+ if (ret < 0) {
+ dev_warn(dev, "Failed to convert time: %d\n", ret);
+ return ret;
+ }
+
+ spin_lock_irq(&rtc->lock);
+
+ /* Disable alarm during update */
+ tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
+ rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp & ~LPC32XX_RTC_CTRL_MATCH0);
+
+ rtc_writel(rtc, LPC32XX_RTC_MATCH0, alarmsecs);
+
+ rtc->alarm_enabled = wkalrm->enabled;
+ if (wkalrm->enabled) {
+ rtc_writel(rtc, LPC32XX_RTC_INTSTAT,
+ LPC32XX_RTC_INTSTAT_MATCH0);
+ rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp |
+ LPC32XX_RTC_CTRL_MATCH0);
+ }
+
+ spin_unlock_irq(&rtc->lock);
+
+ return 0;
+}
+
+static int lpc32xx_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
+ u32 tmp;
+
+ spin_lock_irq(&rtc->lock);
+ tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
+
+ if (enabled) {
+ rtc->alarm_enabled = 1;
+ tmp |= LPC32XX_RTC_CTRL_MATCH0;
+ } else {
+ rtc->alarm_enabled = 0;
+ tmp &= ~LPC32XX_RTC_CTRL_MATCH0;
+ }
+
+ rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp);
+ spin_unlock_irq(&rtc->lock);
+
+ return 0;
+}
+
+static irqreturn_t lpc32xx_rtc_alarm_interrupt(int irq, void *dev)
+{
+ struct lpc32xx_rtc *rtc = dev;
+
+ spin_lock(&rtc->lock);
+
+ /* Disable alarm interrupt */
+ rtc_writel(rtc, LPC32XX_RTC_CTRL,
+ rtc_readl(rtc, LPC32XX_RTC_CTRL) &
+ ~LPC32XX_RTC_CTRL_MATCH0);
+ rtc->alarm_enabled = 0;
+
+ /*
+ * Write a large value to the match value so the RTC won't
+ * keep firing the match status
+ */
+ rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF);
+ rtc_writel(rtc, LPC32XX_RTC_INTSTAT, LPC32XX_RTC_INTSTAT_MATCH0);
+
+ spin_unlock(&rtc->lock);
+
+ rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
+
+ return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops lpc32xx_rtc_ops = {
+ .read_time = lpc32xx_rtc_read_time,
+ .set_mmss = lpc32xx_rtc_set_mmss,
+ .read_alarm = lpc32xx_rtc_read_alarm,
+ .set_alarm = lpc32xx_rtc_set_alarm,
+ .alarm_irq_enable = lpc32xx_rtc_alarm_irq_enable,
+};
+
+static int __devinit lpc32xx_rtc_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct lpc32xx_rtc *rtc;
+ resource_size_t size;
+ int rtcirq;
+ u32 tmp;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Can't get memory resource\n");
+ return -ENOENT;
+ }
+
+ rtcirq = platform_get_irq(pdev, 0);
+ if (rtcirq < 0 || rtcirq >= NR_IRQS) {
+ dev_warn(&pdev->dev, "Can't get interrupt resource\n");
+ rtcirq = -1;
+ }
+
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+ if (unlikely(!rtc)) {
+ dev_err(&pdev->dev, "Can't allocate memory\n");
+ return -ENOMEM;
+ }
+ rtc->irq = rtcirq;
+
+ size = resource_size(res);
+
+ if (!devm_request_mem_region(&pdev->dev, res->start, size,
+ pdev->name)) {
+ dev_err(&pdev->dev, "RTC registers are not free\n");
+ return -EBUSY;
+ }
+
+ rtc->rtc_base = devm_ioremap(&pdev->dev, res->start, size);
+ if (!rtc->rtc_base) {
+ dev_err(&pdev->dev, "Can't map memory\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&rtc->lock);
+
+ /*
+ * The RTC is on a seperate power domain and can keep it's state
+ * across a chip power cycle. If the RTC has never been previously
+ * setup, then set it up now for the first time.
+ */
+ tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
+ if (rtc_readl(rtc, LPC32XX_RTC_KEY) != LPC32XX_RTC_KEY_ONSW_LOADVAL) {
+ tmp &= ~(LPC32XX_RTC_CTRL_SW_RESET |
+ LPC32XX_RTC_CTRL_CNTR_DIS |
+ LPC32XX_RTC_CTRL_MATCH0 |
+ LPC32XX_RTC_CTRL_MATCH1 |
+ LPC32XX_RTC_CTRL_ONSW_MATCH0 |
+ LPC32XX_RTC_CTRL_ONSW_MATCH1 |
+ LPC32XX_RTC_CTRL_ONSW_FORCE_HI);
+ rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp);
+
+ /* Clear latched interrupt states */
+ rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF);
+ rtc_writel(rtc, LPC32XX_RTC_INTSTAT,
+ LPC32XX_RTC_INTSTAT_MATCH0 |
+ LPC32XX_RTC_INTSTAT_MATCH1 |
+ LPC32XX_RTC_INTSTAT_ONSW);
+
+ /* Write key value to RTC so it won't reload on reset */
+ rtc_writel(rtc, LPC32XX_RTC_KEY,
+ LPC32XX_RTC_KEY_ONSW_LOADVAL);
+ } else {
+ rtc_writel(rtc, LPC32XX_RTC_CTRL,
+ tmp & ~LPC32XX_RTC_CTRL_MATCH0);
+ }
+
+ platform_set_drvdata(pdev, rtc);
+
+ rtc->rtc = rtc_device_register(RTC_NAME, &pdev->dev, &lpc32xx_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc->rtc)) {
+ dev_err(&pdev->dev, "Can't get RTC\n");
+ platform_set_drvdata(pdev, NULL);
+ return PTR_ERR(rtc->rtc);
+ }
+
+ /*
+ * IRQ is enabled after device registration in case alarm IRQ
+ * is pending upon suspend exit.
+ */
+ if (rtc->irq >= 0) {
+ if (devm_request_irq(&pdev->dev, rtc->irq,
+ lpc32xx_rtc_alarm_interrupt,
+ IRQF_DISABLED, pdev->name, rtc) < 0) {
+ dev_warn(&pdev->dev, "Can't request interrupt.\n");
+ rtc->irq = -1;
+ } else {
+ device_init_wakeup(&pdev->dev, 1);
+ }
+ }
+
+ return 0;
+}
+
+static int __devexit lpc32xx_rtc_remove(struct platform_device *pdev)
+{
+ struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
+
+ if (rtc->irq >= 0)
+ device_init_wakeup(&pdev->dev, 0);
+
+ platform_set_drvdata(pdev, NULL);
+ rtc_device_unregister(rtc->rtc);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int lpc32xx_rtc_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
+
+ if (rtc->irq >= 0) {
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(rtc->irq);
+ else
+ disable_irq_wake(rtc->irq);
+ }
+
+ return 0;
+}
+
+static int lpc32xx_rtc_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
+
+ if (rtc->irq >= 0 && device_may_wakeup(&pdev->dev))
+ disable_irq_wake(rtc->irq);
+
+ return 0;
+}
+
+/* Unconditionally disable the alarm */
+static int lpc32xx_rtc_freeze(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
+
+ spin_lock_irq(&rtc->lock);
+
+ rtc_writel(rtc, LPC32XX_RTC_CTRL,
+ rtc_readl(rtc, LPC32XX_RTC_CTRL) &
+ ~LPC32XX_RTC_CTRL_MATCH0);
+
+ spin_unlock_irq(&rtc->lock);
+
+ return 0;
+}
+
+static int lpc32xx_rtc_thaw(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
+
+ if (rtc->alarm_enabled) {
+ spin_lock_irq(&rtc->lock);
+
+ rtc_writel(rtc, LPC32XX_RTC_CTRL,
+ rtc_readl(rtc, LPC32XX_RTC_CTRL) |
+ LPC32XX_RTC_CTRL_MATCH0);
+
+ spin_unlock_irq(&rtc->lock);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops lpc32xx_rtc_pm_ops = {
+ .suspend = lpc32xx_rtc_suspend,
+ .resume = lpc32xx_rtc_resume,
+ .freeze = lpc32xx_rtc_freeze,
+ .thaw = lpc32xx_rtc_thaw,
+ .restore = lpc32xx_rtc_resume
+};
+
+#define LPC32XX_RTC_PM_OPS (&lpc32xx_rtc_pm_ops)
+#else
+#define LPC32XX_RTC_PM_OPS NULL
+#endif
+
+static struct platform_driver lpc32xx_rtc_driver = {
+ .probe = lpc32xx_rtc_probe,
+ .remove = __devexit_p(lpc32xx_rtc_remove),
+ .driver = {
+ .name = RTC_NAME,
+ .owner = THIS_MODULE,
+ .pm = LPC32XX_RTC_PM_OPS
+ },
+};
+
+static int __init lpc32xx_rtc_init(void)
+{
+ return platform_driver_register(&lpc32xx_rtc_driver);
+}
+module_init(lpc32xx_rtc_init);
+
+static void __exit lpc32xx_rtc_exit(void)
+{
+ platform_driver_unregister(&lpc32xx_rtc_driver);
+}
+module_exit(lpc32xx_rtc_exit);
+
+MODULE_AUTHOR("Kevin Wells <wellsk40@gmail.com");
+MODULE_DESCRIPTION("RTC driver for the LPC32xx SoC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rtc-lpc32xx");
diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c
index 62de66af0a68..ddb0857e15a4 100644
--- a/drivers/rtc/rtc-nuc900.c
+++ b/drivers/rtc/rtc-nuc900.c
@@ -274,7 +274,7 @@ static int __devinit nuc900_rtc_probe(struct platform_device *pdev)
nuc900_rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev,
&nuc900_rtc_ops, THIS_MODULE);
if (IS_ERR(nuc900_rtc->rtcdev)) {
- dev_err(&pdev->dev, "rtc device register faild\n");
+ dev_err(&pdev->dev, "rtc device register failed\n");
err = PTR_ERR(nuc900_rtc->rtcdev);
goto fail3;
}
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 64d9727b7229..73377b0d65da 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -34,7 +34,8 @@
* Board-specific wiring options include using split power mode with
* RTC_OFF_NOFF used as the reset signal (so the RTC won't be reset),
* and wiring RTC_WAKE_INT (so the RTC alarm can wake the system from
- * low power modes). See the BOARD-SPECIFIC CUSTOMIZATION comment.
+ * low power modes) for OMAP1 boards (OMAP-L138 has this built into
+ * the SoC). See the BOARD-SPECIFIC CUSTOMIZATION comment.
*/
#define OMAP_RTC_BASE 0xfffb4800
@@ -401,16 +402,17 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
/* BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE:
*
- * - Boards wired so that RTC_WAKE_INT does something, and muxed
- * right (W13_1610_RTC_WAKE_INT is the default after chip reset),
- * should initialize the device wakeup flag appropriately.
+ * - Device wake-up capability setting should come through chip
+ * init logic. OMAP1 boards should initialize the "wakeup capable"
+ * flag in the platform device if the board is wired right for
+ * being woken up by RTC alarm. For OMAP-L138, this capability
+ * is built into the SoC by the "Deep Sleep" capability.
*
* - Boards wired so RTC_ON_nOFF is used as the reset signal,
* rather than nPWRON_RESET, should forcibly enable split
* power mode. (Some chip errata report that RTC_CTRL_SPLIT
* is write-only, and always reads as zero...)
*/
- device_init_wakeup(&pdev->dev, 0);
if (new_ctrl & (u8) OMAP_RTC_CTRL_SPLIT)
pr_info("%s: split power mode\n", pdev->name);
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index f57a87f4ae96..cf953ecbfca9 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -100,7 +100,7 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)
spin_lock_irq(&s3c_rtc_pie_lock);
if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
- tmp = readb(s3c_rtc_base + S3C2410_RTCCON);
+ tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
tmp &= ~S3C64XX_RTCCON_TICEN;
if (enabled)
@@ -171,8 +171,8 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
goto retry_get_time;
}
- pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n",
- rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
+ 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);
@@ -185,7 +185,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
rtc_tm->tm_year += 100;
rtc_tm->tm_mon -= 1;
- return 0;
+ return rtc_valid_tm(rtc_tm);
}
static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
@@ -193,8 +193,8 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
void __iomem *base = s3c_rtc_base;
int year = tm->tm_year - 100;
- pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n",
- tm->tm_year, tm->tm_mon, tm->tm_mday,
+ pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n",
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
/* we get around y2k by simply not supporting it */
@@ -231,9 +231,9 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
- pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n",
+ pr_debug("read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n",
alm_en,
- alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
+ 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
@@ -242,34 +242,34 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
if (alm_en & S3C2410_RTCALM_SECEN)
alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
else
- alm_tm->tm_sec = 0xff;
+ alm_tm->tm_sec = -1;
if (alm_en & S3C2410_RTCALM_MINEN)
alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
else
- alm_tm->tm_min = 0xff;
+ alm_tm->tm_min = -1;
if (alm_en & S3C2410_RTCALM_HOUREN)
alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
else
- alm_tm->tm_hour = 0xff;
+ alm_tm->tm_hour = -1;
if (alm_en & S3C2410_RTCALM_DAYEN)
alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
else
- alm_tm->tm_mday = 0xff;
+ alm_tm->tm_mday = -1;
if (alm_en & S3C2410_RTCALM_MONEN) {
alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
alm_tm->tm_mon -= 1;
} else {
- alm_tm->tm_mon = 0xff;
+ alm_tm->tm_mon = -1;
}
if (alm_en & S3C2410_RTCALM_YEAREN)
alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
else
- alm_tm->tm_year = 0xffff;
+ alm_tm->tm_year = -1;
return 0;
}
@@ -280,10 +280,10 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
void __iomem *base = s3c_rtc_base;
unsigned int alrm_en;
- pr_debug("s3c_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n",
+ pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
alrm->enabled,
- tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff,
- tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec);
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
@@ -318,7 +318,7 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
unsigned int ticnt;
if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
- ticnt = readb(s3c_rtc_base + S3C2410_RTCCON);
+ ticnt = readw(s3c_rtc_base + S3C2410_RTCCON);
ticnt &= S3C64XX_RTCCON_TICEN;
} else {
ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
@@ -379,7 +379,8 @@ static const struct rtc_class_ops s3c_rtcops = {
.set_alarm = s3c_rtc_setalarm,
.irq_set_freq = s3c_rtc_setfreq,
.irq_set_state = s3c_rtc_setpie,
- .proc = s3c_rtc_proc,
+ .proc = s3c_rtc_proc,
+ .alarm_irq_enable = s3c_rtc_setaie,
};
static void s3c_rtc_enable(struct platform_device *pdev, int en)
@@ -391,11 +392,11 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
return;
if (!en) {
- tmp = readb(base + S3C2410_RTCCON);
+ tmp = readw(base + S3C2410_RTCCON);
if (s3c_rtc_cpu_type == TYPE_S3C64XX)
tmp &= ~S3C64XX_RTCCON_TICEN;
tmp &= ~S3C2410_RTCCON_RTCEN;
- writeb(tmp, base + S3C2410_RTCCON);
+ writew(tmp, base + S3C2410_RTCCON);
if (s3c_rtc_cpu_type == TYPE_S3C2410) {
tmp = readb(base + S3C2410_TICNT);
@@ -405,25 +406,28 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
} else {
/* re-enable the device, and check it is ok */
- if ((readb(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){
+ if ((readw(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0) {
dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
- tmp = readb(base + S3C2410_RTCCON);
- writeb(tmp|S3C2410_RTCCON_RTCEN, base+S3C2410_RTCCON);
+ tmp = readw(base + S3C2410_RTCCON);
+ writew(tmp | S3C2410_RTCCON_RTCEN,
+ base + S3C2410_RTCCON);
}
- if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){
+ if ((readw(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)) {
dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n");
- tmp = readb(base + S3C2410_RTCCON);
- writeb(tmp& ~S3C2410_RTCCON_CNTSEL, base+S3C2410_RTCCON);
+ tmp = readw(base + S3C2410_RTCCON);
+ writew(tmp & ~S3C2410_RTCCON_CNTSEL,
+ base + S3C2410_RTCCON);
}
- if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){
+ if ((readw(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)) {
dev_info(&pdev->dev, "removing RTCCON_CLKRST\n");
- tmp = readb(base + S3C2410_RTCCON);
- writeb(tmp & ~S3C2410_RTCCON_CLKRST, base+S3C2410_RTCCON);
+ tmp = readw(base + S3C2410_RTCCON);
+ writew(tmp & ~S3C2410_RTCCON_CLKRST,
+ base + S3C2410_RTCCON);
}
}
}
@@ -452,8 +456,8 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev)
static int __devinit s3c_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
+ struct rtc_time rtc_tm;
struct resource *res;
- unsigned int tmp, i;
int ret;
pr_debug("%s: probe=%p\n", __func__, pdev);
@@ -514,8 +518,8 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
s3c_rtc_enable(pdev, 1);
- pr_debug("s3c2410_rtc: RTCCON=%02x\n",
- readb(s3c_rtc_base + S3C2410_RTCCON));
+ pr_debug("s3c2410_rtc: RTCCON=%02x\n",
+ readw(s3c_rtc_base + S3C2410_RTCCON));
device_init_wakeup(&pdev->dev, 1);
@@ -534,11 +538,19 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
/* Check RTC Time */
- for (i = S3C2410_RTCSEC; i <= S3C2410_RTCYEAR; i += 0x4) {
- tmp = readb(s3c_rtc_base + i);
+ s3c_rtc_gettime(NULL, &rtc_tm);
+
+ if (rtc_valid_tm(&rtc_tm)) {
+ rtc_tm.tm_year = 100;
+ rtc_tm.tm_mon = 0;
+ rtc_tm.tm_mday = 1;
+ rtc_tm.tm_hour = 0;
+ rtc_tm.tm_min = 0;
+ rtc_tm.tm_sec = 0;
+
+ s3c_rtc_settime(NULL, &rtc_tm);
- if ((tmp & 0xf) > 0x9 || ((tmp >> 4) & 0xf) > 0x9)
- writeb(0, s3c_rtc_base + i);
+ dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n");
}
if (s3c_rtc_cpu_type == TYPE_S3C64XX)
@@ -578,7 +590,7 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
/* save TICNT for anyone using periodic interrupts */
ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
- ticnt_en_save = readb(s3c_rtc_base + S3C2410_RTCCON);
+ ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON);
ticnt_en_save &= S3C64XX_RTCCON_TICEN;
}
s3c_rtc_enable(pdev, 0);
@@ -596,8 +608,8 @@ static int s3c_rtc_resume(struct platform_device *pdev)
s3c_rtc_enable(pdev, 1);
writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
- tmp = readb(s3c_rtc_base + S3C2410_RTCCON);
- writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
+ tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
+ writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
}
if (device_may_wakeup(&pdev->dev))
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index aa95f1001761..fb613d70c2cb 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -1099,16 +1099,30 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
cqr = (struct dasd_ccw_req *) intparm;
if (!cqr || ((scsw_cc(&irb->scsw) == 1) &&
(scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) &&
- (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))) {
+ ((scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND) ||
+ (scsw_stctl(&irb->scsw) == (SCSW_STCTL_STATUS_PEND |
+ SCSW_STCTL_ALERT_STATUS))))) {
if (cqr && cqr->status == DASD_CQR_IN_IO)
cqr->status = DASD_CQR_QUEUED;
+ if (cqr)
+ memcpy(&cqr->irb, irb, sizeof(*irb));
device = dasd_device_from_cdev_locked(cdev);
- if (!IS_ERR(device)) {
- dasd_device_clear_timer(device);
- device->discipline->handle_unsolicited_interrupt(device,
- irb);
+ if (IS_ERR(device))
+ return;
+ /* ignore unsolicited interrupts for DIAG discipline */
+ if (device->discipline == dasd_diag_discipline_pointer) {
dasd_put_device(device);
+ return;
}
+ device->discipline->dump_sense_dbf(device, irb,
+ "unsolicited");
+ if ((device->features & DASD_FEATURE_ERPLOG))
+ device->discipline->dump_sense(device, cqr,
+ irb);
+ dasd_device_clear_timer(device);
+ device->discipline->handle_unsolicited_interrupt(device,
+ irb);
+ dasd_put_device(device);
return;
}
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 85bfd8794856..968c76cf7127 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -221,6 +221,7 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
ccw->cmd_code = CCW_CMD_DCTL;
ccw->count = 4;
ccw->cda = (__u32)(addr_t) DCTL_data;
+ dctl_cqr->flags = erp->flags;
dctl_cqr->function = dasd_3990_erp_DCTL;
dctl_cqr->refers = erp;
dctl_cqr->startdev = device;
@@ -1710,6 +1711,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
ccw->cda = cpa;
/* fill erp related fields */
+ erp->flags = default_erp->flags;
erp->function = dasd_3990_erp_action_1B_32;
erp->refers = default_erp->refers;
erp->startdev = device;
@@ -2197,7 +2199,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
/*
*****************************************************************************
- * main ERP control fuctions (24 and 32 byte sense)
+ * main ERP control functions (24 and 32 byte sense)
*****************************************************************************
*/
@@ -2354,6 +2356,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr)
ccw->cda = (long)(cqr->cpaddr);
}
+ erp->flags = cqr->flags;
erp->function = dasd_3990_erp_add_erp;
erp->refers = cqr;
erp->startdev = device;
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 2b3bc3ec0541..266b34b55403 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -228,25 +228,22 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr)
}
/* Handle external interruption. */
-static void
-dasd_ext_handler(__u16 code)
+static void dasd_ext_handler(unsigned int ext_int_code,
+ unsigned int param32, unsigned long param64)
{
struct dasd_ccw_req *cqr, *next;
struct dasd_device *device;
unsigned long long expires;
unsigned long flags;
- u8 int_code, status;
addr_t ip;
int rc;
- int_code = *((u8 *) DASD_DIAG_LC_INT_CODE);
- status = *((u8 *) DASD_DIAG_LC_INT_STATUS);
- switch (int_code) {
+ switch (ext_int_code >> 24) {
case DASD_DIAG_CODE_31BIT:
- ip = (addr_t) *((u32 *) DASD_DIAG_LC_INT_PARM_31BIT);
+ ip = (addr_t) param32;
break;
case DASD_DIAG_CODE_64BIT:
- ip = (addr_t) *((u64 *) DASD_DIAG_LC_INT_PARM_64BIT);
+ ip = (addr_t) param64;
break;
default:
return;
@@ -281,7 +278,7 @@ dasd_ext_handler(__u16 code)
cqr->stopclk = get_clock();
expires = 0;
- if (status == 0) {
+ if ((ext_int_code & 0xff0000) == 0) {
cqr->status = DASD_CQR_SUCCESS;
/* Start first request on queue if possible -> fast_io. */
if (!list_empty(&device->ccw_queue)) {
@@ -296,8 +293,8 @@ dasd_ext_handler(__u16 code)
} else {
cqr->status = DASD_CQR_QUEUED;
DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for "
- "request %p was %d (%d retries left)", cqr, status,
- cqr->retries);
+ "request %p was %d (%d retries left)", cqr,
+ (ext_int_code >> 16) & 0xff, cqr->retries);
dasd_diag_erp(device);
}
diff --git a/drivers/s390/block/dasd_diag.h b/drivers/s390/block/dasd_diag.h
index b8c78267ff3e..4f71fbe60c82 100644
--- a/drivers/s390/block/dasd_diag.h
+++ b/drivers/s390/block/dasd_diag.h
@@ -18,10 +18,6 @@
#define DEV_CLASS_FBA 0x01
#define DEV_CLASS_ECKD 0x04
-#define DASD_DIAG_LC_INT_CODE 132
-#define DASD_DIAG_LC_INT_STATUS 133
-#define DASD_DIAG_LC_INT_PARM_31BIT 128
-#define DASD_DIAG_LC_INT_PARM_64BIT 4536
#define DASD_DIAG_CODE_31BIT 0x03
#define DASD_DIAG_CODE_64BIT 0x07
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 66360c24bd48..50cf96389d2c 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1190,7 +1190,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
goto out_err2;
}
/*
- * dasd_eckd_vaildate_server is done on the first device that
+ * dasd_eckd_validate_server is done on the first device that
* is found for an LCU. All later other devices have to wait
* for it, so they will read the correct feature codes.
*/
@@ -1216,7 +1216,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
"Read device characteristic failed, rc=%d", rc);
goto out_err3;
}
- /* find the vaild cylinder size */
+ /* find the valid cylinder size */
if (private->rdc_data.no_cyl == LV_COMPAT_CYL &&
private->rdc_data.long_no_cyl)
private->real_cyl = private->rdc_data.long_no_cyl;
@@ -1776,13 +1776,13 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
}
/* summary unit check */
- if ((scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) &&
- (irb->ecw[7] == 0x0D)) {
+ sense = dasd_get_sense(irb);
+ if (sense && (sense[7] == 0x0D) &&
+ (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) {
dasd_alias_handle_summary_unit_check(device, irb);
return;
}
- sense = dasd_get_sense(irb);
/* service information message SIM */
if (sense && !(sense[27] & DASD_SENSE_BIT_0) &&
((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) {
@@ -1791,26 +1791,15 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
return;
}
- if ((scsw_cc(&irb->scsw) == 1) &&
- (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) &&
- (scsw_actl(&irb->scsw) & SCSW_ACTL_START_PEND) &&
- (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND)) {
+ if ((scsw_cc(&irb->scsw) == 1) && !sense &&
+ (scsw_fctl(&irb->scsw) == SCSW_FCTL_START_FUNC) &&
+ (scsw_actl(&irb->scsw) == SCSW_ACTL_START_PEND) &&
+ (scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND)) {
/* fake irb do nothing, they are handled elsewhere */
dasd_schedule_device_bh(device);
return;
}
- if (!sense) {
- /* just report other unsolicited interrupts */
- DBF_DEV_EVENT(DBF_ERR, device, "%s",
- "unsolicited interrupt received");
- } else {
- DBF_DEV_EVENT(DBF_ERR, device, "%s",
- "unsolicited interrupt received "
- "(sense available)");
- device->discipline->dump_sense_dbf(device, irb, "unsolicited");
- }
-
dasd_schedule_device_bh(device);
return;
};
@@ -3093,19 +3082,19 @@ dasd_eckd_dump_sense_dbf(struct dasd_device *device, struct irb *irb,
char *reason)
{
u64 *sense;
+ u64 *stat;
sense = (u64 *) dasd_get_sense(irb);
+ stat = (u64 *) &irb->scsw;
if (sense) {
- DBF_DEV_EVENT(DBF_EMERG, device,
- "%s: %s %02x%02x%02x %016llx %016llx %016llx "
- "%016llx", reason,
- scsw_is_tm(&irb->scsw) ? "t" : "c",
- scsw_cc(&irb->scsw), scsw_cstat(&irb->scsw),
- scsw_dstat(&irb->scsw), sense[0], sense[1],
- sense[2], sense[3]);
+ DBF_DEV_EVENT(DBF_EMERG, device, "%s: %016llx %08x : "
+ "%016llx %016llx %016llx %016llx",
+ reason, *stat, *((u32 *) (stat + 1)),
+ sense[0], sense[1], sense[2], sense[3]);
} else {
- DBF_DEV_EVENT(DBF_EMERG, device, "%s",
- "SORRY - NO VALID SENSE AVAILABLE\n");
+ DBF_DEV_EVENT(DBF_EMERG, device, "%s: %016llx %08x : %s",
+ reason, *stat, *((u32 *) (stat + 1)),
+ "NO VALID SENSE");
}
}
@@ -3131,9 +3120,12 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
" I/O status report for device %s:\n",
dev_name(&device->cdev->dev));
len += sprintf(page + len, KERN_ERR PRINTK_HEADER
- " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d\n",
- req, scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw),
- scsw_cc(&irb->scsw), req ? req->intrc : 0);
+ " in req: %p CC:%02X FC:%02X AC:%02X SC:%02X DS:%02X "
+ "CS:%02X RC:%d\n",
+ req, scsw_cc(&irb->scsw), scsw_fctl(&irb->scsw),
+ scsw_actl(&irb->scsw), scsw_stctl(&irb->scsw),
+ scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw),
+ req ? req->intrc : 0);
len += sprintf(page + len, KERN_ERR PRINTK_HEADER
" device %s: Failing CCW: %p\n",
dev_name(&device->cdev->dev),
@@ -3234,11 +3226,13 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
" I/O status report for device %s:\n",
dev_name(&device->cdev->dev));
len += sprintf(page + len, KERN_ERR PRINTK_HEADER
- " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d "
- "fcxs: 0x%02X schxs: 0x%02X\n", req,
- scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw),
- scsw_cc(&irb->scsw), req->intrc,
- irb->scsw.tm.fcxs, irb->scsw.tm.schxs);
+ " in req: %p CC:%02X FC:%02X AC:%02X SC:%02X DS:%02X "
+ "CS:%02X fcxs:%02X schxs:%02X RC:%d\n",
+ req, scsw_cc(&irb->scsw), scsw_fctl(&irb->scsw),
+ scsw_actl(&irb->scsw), scsw_stctl(&irb->scsw),
+ scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw),
+ irb->scsw.tm.fcxs, irb->scsw.tm.schxs,
+ req ? req->intrc : 0);
len += sprintf(page + len, KERN_ERR PRINTK_HEADER
" device %s: Failing TCW: %p\n",
dev_name(&device->cdev->dev),
@@ -3246,7 +3240,7 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
tsb = NULL;
sense = NULL;
- if (irb->scsw.tm.tcw && (irb->scsw.tm.fcxs == 0x01))
+ if (irb->scsw.tm.tcw && (irb->scsw.tm.fcxs & 0x01))
tsb = tcw_get_tsb(
(struct tcw *)(unsigned long)irb->scsw.tm.tcw);
@@ -3344,7 +3338,7 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
static void dasd_eckd_dump_sense(struct dasd_device *device,
struct dasd_ccw_req *req, struct irb *irb)
{
- if (req && scsw_is_tm(&req->irb.scsw))
+ if (scsw_is_tm(&irb->scsw))
dasd_eckd_dump_sense_tcw(device, req, irb);
else
dasd_eckd_dump_sense_ccw(device, req, irb);
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index 2eb025592809..c4a6a31bd9cd 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -251,7 +251,6 @@ static ssize_t dasd_stats_proc_write(struct file *file,
buffer = dasd_get_user_string(user_buf, user_len);
if (IS_ERR(buffer))
return PTR_ERR(buffer);
- DBF_EVENT(DBF_DEBUG, "/proc/dasd/statictics: '%s'\n", buffer);
/* check for valid verbs */
str = skip_spaces(buffer);
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 5707a80b96b6..35cc4686b99b 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -395,16 +395,16 @@ __sclp_find_req(u32 sccb)
/* Handler for external interruption. Perform request post-processing.
* Prepare read event data request if necessary. Start processing of next
* request on queue. */
-static void
-sclp_interrupt_handler(__u16 code)
+static void sclp_interrupt_handler(unsigned int ext_int_code,
+ unsigned int param32, unsigned long param64)
{
struct sclp_req *req;
u32 finished_sccb;
u32 evbuf_pending;
spin_lock(&sclp_lock);
- finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
- evbuf_pending = S390_lowcore.ext_params & 0x3;
+ finished_sccb = param32 & 0xfffffff8;
+ evbuf_pending = param32 & 0x3;
if (finished_sccb) {
del_timer(&sclp_request_timer);
sclp_running_state = sclp_running_state_reset_pending;
@@ -819,12 +819,12 @@ EXPORT_SYMBOL(sclp_reactivate);
/* Handler for external interruption used during initialization. Modify
* request state to done. */
-static void
-sclp_check_handler(__u16 code)
+static void sclp_check_handler(unsigned int ext_int_code,
+ unsigned int param32, unsigned long param64)
{
u32 finished_sccb;
- finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
+ finished_sccb = param32 & 0xfffffff8;
/* Is this the interrupt we are waiting for? */
if (finished_sccb == 0)
return;
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index fc993acf99b6..deff2c3361e4 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -31,7 +31,7 @@ debug_info_t *TAPE_DBF_AREA = NULL;
EXPORT_SYMBOL(TAPE_DBF_AREA);
/*******************************************************************
- * Error Recovery fuctions:
+ * Error Recovery functions:
* - Read Opposite: implemented
* - Read Device (buffered) log: BRA
* - Read Library log: BRA
@@ -798,7 +798,7 @@ tape_3590_done(struct tape_device *device, struct tape_request *request)
}
/*
- * This fuction is called, when error recovery was successfull
+ * This function is called, when error recovery was successful
*/
static inline int
tape_3590_erp_succeded(struct tape_device *device, struct tape_request *request)
@@ -809,7 +809,7 @@ tape_3590_erp_succeded(struct tape_device *device, struct tape_request *request)
}
/*
- * This fuction is called, when error recovery was not successfull
+ * This function is called, when error recovery was not successful
*/
static inline int
tape_3590_erp_failed(struct tape_device *device, struct tape_request *request,
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
index 0e7cb1a84151..31a3ccbb6495 100644
--- a/drivers/s390/char/vmcp.c
+++ b/drivers/s390/char/vmcp.c
@@ -47,7 +47,7 @@ static int vmcp_release(struct inode *inode, struct file *file)
{
struct vmcp_session *session;
- session = (struct vmcp_session *)file->private_data;
+ session = file->private_data;
file->private_data = NULL;
free_pages((unsigned long)session->response, get_order(session->bufsize));
kfree(session);
@@ -94,7 +94,7 @@ vmcp_write(struct file *file, const char __user *buff, size_t count,
return -EFAULT;
}
cmd[count] = '\0';
- session = (struct vmcp_session *)file->private_data;
+ session = file->private_data;
if (mutex_lock_interruptible(&session->mutex)) {
kfree(cmd);
return -ERESTARTSYS;
@@ -136,7 +136,7 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int __user *argp;
int temp;
- session = (struct vmcp_session *)file->private_data;
+ session = file->private_data;
if (is_compat_task())
argp = compat_ptr(arg);
else
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index 0d6dc4b92cc2..9f661426e4a1 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -215,7 +215,7 @@ static void vmlogrdr_iucv_message_pending(struct iucv_path *path,
static int vmlogrdr_get_recording_class_AB(void)
{
- char cp_command[]="QUERY COMMAND RECORDING ";
+ static const char cp_command[] = "QUERY COMMAND RECORDING ";
char cp_response[80];
char *tail;
int len,i;
@@ -638,7 +638,7 @@ static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver,
char *buf)
{
- char cp_command[] = "QUERY RECORDING ";
+ static const char cp_command[] = "QUERY RECORDING ";
int len;
cpcmd(cp_command, buf, 4096, NULL);
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index 13cb60162e42..76058a5166ed 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -79,17 +79,15 @@ static int pure_hex(char **cp, unsigned int *val, int min_digit,
int max_digit, int max_val)
{
int diff;
- unsigned int value;
diff = 0;
*val = 0;
- while (isxdigit(**cp) && (diff <= max_digit)) {
+ while (diff <= max_digit) {
+ int value = hex_to_bin(**cp);
- if (isdigit(**cp))
- value = **cp - '0';
- else
- value = tolower(**cp) - 'a' + 10;
+ if (value < 0)
+ break;
*val = *val * 16 + value;
(*cp)++;
diff++;
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index 6c9fa15aac7b..2d32233943a9 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -1,7 +1,7 @@
/*
* drivers/s390/cio/chp.c
*
- * Copyright IBM Corp. 1999,2007
+ * Copyright IBM Corp. 1999,2010
* Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
* Arnd Bergmann (arndb@de.ibm.com)
* Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
@@ -54,12 +54,6 @@ static struct work_struct cfg_work;
/* Wait queue for configure completion events. */
static wait_queue_head_t cfg_wait_queue;
-/* Return channel_path struct for given chpid. */
-static inline struct channel_path *chpid_to_chp(struct chp_id chpid)
-{
- return channel_subsystems[chpid.cssid]->chps[chpid.id];
-}
-
/* Set vary state for given chpid. */
static void set_chp_logically_online(struct chp_id chpid, int onoff)
{
@@ -241,11 +235,13 @@ static ssize_t chp_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct channel_path *chp = to_channelpath(dev);
+ int status;
- if (!chp)
- return 0;
- return (chp_get_status(chp->chpid) ? sprintf(buf, "online\n") :
- sprintf(buf, "offline\n"));
+ mutex_lock(&chp->lock);
+ status = chp->state;
+ mutex_unlock(&chp->lock);
+
+ return status ? sprintf(buf, "online\n") : sprintf(buf, "offline\n");
}
static ssize_t chp_status_write(struct device *dev,
@@ -261,15 +257,18 @@ static ssize_t chp_status_write(struct device *dev,
if (!num_args)
return count;
- if (!strnicmp(cmd, "on", 2) || !strcmp(cmd, "1"))
+ if (!strnicmp(cmd, "on", 2) || !strcmp(cmd, "1")) {
+ mutex_lock(&cp->lock);
error = s390_vary_chpid(cp->chpid, 1);
- else if (!strnicmp(cmd, "off", 3) || !strcmp(cmd, "0"))
+ mutex_unlock(&cp->lock);
+ } else if (!strnicmp(cmd, "off", 3) || !strcmp(cmd, "0")) {
+ mutex_lock(&cp->lock);
error = s390_vary_chpid(cp->chpid, 0);
- else
+ mutex_unlock(&cp->lock);
+ } else
error = -EINVAL;
return error < 0 ? error : count;
-
}
static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write);
@@ -315,10 +314,12 @@ static ssize_t chp_type_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct channel_path *chp = to_channelpath(dev);
+ u8 type;
- if (!chp)
- return 0;
- return sprintf(buf, "%x\n", chp->desc.desc);
+ mutex_lock(&chp->lock);
+ type = chp->desc.desc;
+ mutex_unlock(&chp->lock);
+ return sprintf(buf, "%x\n", type);
}
static DEVICE_ATTR(type, 0444, chp_type_show, NULL);
@@ -395,6 +396,7 @@ int chp_new(struct chp_id chpid)
chp->state = 1;
chp->dev.parent = &channel_subsystems[chpid.cssid]->device;
chp->dev.release = chp_release;
+ mutex_init(&chp->lock);
/* Obtain channel path description and fill it in. */
ret = chsc_determine_base_channel_path_desc(chpid, &chp->desc);
@@ -464,7 +466,10 @@ void *chp_get_chp_desc(struct chp_id chpid)
desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL);
if (!desc)
return NULL;
+
+ mutex_lock(&chp->lock);
memcpy(desc, &chp->desc, sizeof(struct channel_path_desc));
+ mutex_unlock(&chp->lock);
return desc;
}
diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h
index 26c3d2246176..12b4903d6fe3 100644
--- a/drivers/s390/cio/chp.h
+++ b/drivers/s390/cio/chp.h
@@ -1,7 +1,7 @@
/*
* drivers/s390/cio/chp.h
*
- * Copyright IBM Corp. 2007
+ * Copyright IBM Corp. 2007,2010
* Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
*/
@@ -10,6 +10,7 @@
#include <linux/types.h>
#include <linux/device.h>
+#include <linux/mutex.h>
#include <asm/chpid.h>
#include "chsc.h"
#include "css.h"
@@ -40,16 +41,23 @@ static inline int chp_test_bit(u8 *bitmap, int num)
struct channel_path {
+ struct device dev;
struct chp_id chpid;
+ struct mutex lock; /* Serialize access to below members. */
int state;
struct channel_path_desc desc;
/* Channel-measurement related stuff: */
int cmg;
int shared;
void *cmg_chars;
- struct device dev;
};
+/* Return channel_path struct for given chpid. */
+static inline struct channel_path *chpid_to_chp(struct chp_id chpid)
+{
+ return channel_subsystems[chpid.cssid]->chps[chpid.id];
+}
+
int chp_get_status(struct chp_id chpid);
u8 chp_get_sch_opm(struct subchannel *sch);
int chp_is_registered(struct chp_id chpid);
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 4cbb1a6ca33c..1aaddea673e0 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -2,7 +2,7 @@
* drivers/s390/cio/chsc.c
* S/390 common I/O routines -- channel subsystem call
*
- * Copyright IBM Corp. 1999,2008
+ * Copyright IBM Corp. 1999,2010
* Author(s): Ingo Adlung (adlung@de.ibm.com)
* Cornelia Huck (cornelia.huck@de.ibm.com)
* Arnd Bergmann (arndb@de.ibm.com)
@@ -29,8 +29,8 @@
#include "chsc.h"
static void *sei_page;
-static DEFINE_SPINLOCK(siosl_lock);
-static DEFINE_SPINLOCK(sda_lock);
+static void *chsc_page;
+static DEFINE_SPINLOCK(chsc_page_lock);
/**
* chsc_error_from_response() - convert a chsc response to an error
@@ -85,17 +85,15 @@ struct chsc_ssd_area {
int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
{
- unsigned long page;
struct chsc_ssd_area *ssd_area;
int ccode;
int ret;
int i;
int mask;
- page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!page)
- return -ENOMEM;
- ssd_area = (struct chsc_ssd_area *) page;
+ spin_lock_irq(&chsc_page_lock);
+ memset(chsc_page, 0, PAGE_SIZE);
+ ssd_area = chsc_page;
ssd_area->request.length = 0x0010;
ssd_area->request.code = 0x0004;
ssd_area->ssid = schid.ssid;
@@ -106,25 +104,25 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
/* Check response. */
if (ccode > 0) {
ret = (ccode == 3) ? -ENODEV : -EBUSY;
- goto out_free;
+ goto out;
}
ret = chsc_error_from_response(ssd_area->response.code);
if (ret != 0) {
CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n",
schid.ssid, schid.sch_no,
ssd_area->response.code);
- goto out_free;
+ goto out;
}
if (!ssd_area->sch_valid) {
ret = -ENODEV;
- goto out_free;
+ goto out;
}
/* Copy data */
ret = 0;
memset(ssd, 0, sizeof(struct chsc_ssd_info));
if ((ssd_area->st != SUBCHANNEL_TYPE_IO) &&
(ssd_area->st != SUBCHANNEL_TYPE_MSG))
- goto out_free;
+ goto out;
ssd->path_mask = ssd_area->path_mask;
ssd->fla_valid_mask = ssd_area->fla_valid_mask;
for (i = 0; i < 8; i++) {
@@ -136,8 +134,8 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
if (ssd_area->fla_valid_mask & mask)
ssd->fla[i] = ssd_area->fla[i];
}
-out_free:
- free_page(page);
+out:
+ spin_unlock_irq(&chsc_page_lock);
return ret;
}
@@ -497,6 +495,7 @@ __s390_vary_chpid_on(struct subchannel_id schid, void *data)
*/
int chsc_chp_vary(struct chp_id chpid, int on)
{
+ struct channel_path *chp = chpid_to_chp(chpid);
struct chp_link link;
memset(&link, 0, sizeof(struct chp_link));
@@ -506,11 +505,12 @@ int chsc_chp_vary(struct chp_id chpid, int on)
/*
* Redo PathVerification on the devices the chpid connects to
*/
-
- if (on)
+ if (on) {
+ /* Try to update the channel path descritor. */
+ chsc_determine_base_channel_path_desc(chpid, &chp->desc);
for_each_subchannel_staged(s390_subchannel_vary_chpid_on,
__s390_vary_chpid_on, &link);
- else
+ } else
for_each_subchannel_staged(s390_subchannel_vary_chpid_off,
NULL, &link);
@@ -552,7 +552,7 @@ cleanup:
return ret;
}
-int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
+int __chsc_do_secm(struct channel_subsystem *css, int enable)
{
struct {
struct chsc_header request;
@@ -573,7 +573,9 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
} __attribute__ ((packed)) *secm_area;
int ret, ccode;
- secm_area = page;
+ spin_lock_irq(&chsc_page_lock);
+ memset(chsc_page, 0, PAGE_SIZE);
+ secm_area = chsc_page;
secm_area->request.length = 0x0050;
secm_area->request.code = 0x0016;
@@ -584,8 +586,10 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
secm_area->operation_code = enable ? 0 : 1;
ccode = chsc(secm_area);
- if (ccode > 0)
- return (ccode == 3) ? -ENODEV : -EBUSY;
+ if (ccode > 0) {
+ ret = (ccode == 3) ? -ENODEV : -EBUSY;
+ goto out;
+ }
switch (secm_area->response.code) {
case 0x0102:
@@ -598,37 +602,32 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
if (ret != 0)
CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n",
secm_area->response.code);
+out:
+ spin_unlock_irq(&chsc_page_lock);
return ret;
}
int
chsc_secm(struct channel_subsystem *css, int enable)
{
- void *secm_area;
int ret;
- secm_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!secm_area)
- return -ENOMEM;
-
if (enable && !css->cm_enabled) {
css->cub_addr1 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
css->cub_addr2 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!css->cub_addr1 || !css->cub_addr2) {
free_page((unsigned long)css->cub_addr1);
free_page((unsigned long)css->cub_addr2);
- free_page((unsigned long)secm_area);
return -ENOMEM;
}
}
- ret = __chsc_do_secm(css, enable, secm_area);
+ ret = __chsc_do_secm(css, enable);
if (!ret) {
css->cm_enabled = enable;
if (css->cm_enabled) {
ret = chsc_add_cmg_attr(css);
if (ret) {
- memset(secm_area, 0, PAGE_SIZE);
- __chsc_do_secm(css, 0, secm_area);
+ __chsc_do_secm(css, 0);
css->cm_enabled = 0;
}
} else
@@ -638,44 +637,24 @@ chsc_secm(struct channel_subsystem *css, int enable)
free_page((unsigned long)css->cub_addr1);
free_page((unsigned long)css->cub_addr2);
}
- free_page((unsigned long)secm_area);
return ret;
}
int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,
- int c, int m,
- struct chsc_response_struct *resp)
+ int c, int m, void *page)
{
+ struct chsc_scpd *scpd_area;
int ccode, ret;
- struct {
- struct chsc_header request;
- u32 : 2;
- u32 m : 1;
- u32 c : 1;
- u32 fmt : 4;
- u32 cssid : 8;
- u32 : 4;
- u32 rfmt : 4;
- u32 first_chpid : 8;
- u32 : 24;
- u32 last_chpid : 8;
- u32 zeroes1;
- struct chsc_header response;
- u8 data[PAGE_SIZE - 20];
- } __attribute__ ((packed)) *scpd_area;
-
if ((rfmt == 1) && !css_general_characteristics.fcs)
return -EINVAL;
if ((rfmt == 2) && !css_general_characteristics.cib)
return -EINVAL;
- scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!scpd_area)
- return -ENOMEM;
+ memset(page, 0, PAGE_SIZE);
+ scpd_area = page;
scpd_area->request.length = 0x0010;
scpd_area->request.code = 0x0002;
-
scpd_area->cssid = chpid.cssid;
scpd_area->first_chpid = chpid.id;
scpd_area->last_chpid = chpid.id;
@@ -685,20 +664,13 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,
scpd_area->rfmt = rfmt;
ccode = chsc(scpd_area);
- if (ccode > 0) {
- ret = (ccode == 3) ? -ENODEV : -EBUSY;
- goto out;
- }
+ if (ccode > 0)
+ return (ccode == 3) ? -ENODEV : -EBUSY;
ret = chsc_error_from_response(scpd_area->response.code);
- if (ret == 0)
- /* Success. */
- memcpy(resp, &scpd_area->response, scpd_area->response.length);
- else
+ if (ret)
CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n",
scpd_area->response.code);
-out:
- free_page((unsigned long)scpd_area);
return ret;
}
EXPORT_SYMBOL_GPL(chsc_determine_channel_path_desc);
@@ -707,17 +679,19 @@ int chsc_determine_base_channel_path_desc(struct chp_id chpid,
struct channel_path_desc *desc)
{
struct chsc_response_struct *chsc_resp;
+ struct chsc_scpd *scpd_area;
+ unsigned long flags;
int ret;
- chsc_resp = kzalloc(sizeof(*chsc_resp), GFP_KERNEL);
- if (!chsc_resp)
- return -ENOMEM;
- ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, chsc_resp);
+ spin_lock_irqsave(&chsc_page_lock, flags);
+ scpd_area = chsc_page;
+ ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, scpd_area);
if (ret)
- goto out_free;
+ goto out;
+ chsc_resp = (void *)&scpd_area->response;
memcpy(desc, &chsc_resp->data, sizeof(*desc));
-out_free:
- kfree(chsc_resp);
+out:
+ spin_unlock_irqrestore(&chsc_page_lock, flags);
return ret;
}
@@ -725,33 +699,22 @@ static void
chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
struct cmg_chars *chars)
{
- switch (chp->cmg) {
- case 2:
- case 3:
- chp->cmg_chars = kmalloc(sizeof(struct cmg_chars),
- GFP_KERNEL);
- if (chp->cmg_chars) {
- int i, mask;
- struct cmg_chars *cmg_chars;
-
- cmg_chars = chp->cmg_chars;
- for (i = 0; i < NR_MEASUREMENT_CHARS; i++) {
- mask = 0x80 >> (i + 3);
- if (cmcv & mask)
- cmg_chars->values[i] = chars->values[i];
- else
- cmg_chars->values[i] = 0;
- }
- }
- break;
- default:
- /* No cmg-dependent data. */
- break;
+ struct cmg_chars *cmg_chars;
+ int i, mask;
+
+ cmg_chars = chp->cmg_chars;
+ for (i = 0; i < NR_MEASUREMENT_CHARS; i++) {
+ mask = 0x80 >> (i + 3);
+ if (cmcv & mask)
+ cmg_chars->values[i] = chars->values[i];
+ else
+ cmg_chars->values[i] = 0;
}
}
int chsc_get_channel_measurement_chars(struct channel_path *chp)
{
+ struct cmg_chars *cmg_chars;
int ccode, ret;
struct {
@@ -775,13 +738,16 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
u32 data[NR_MEASUREMENT_CHARS];
} __attribute__ ((packed)) *scmc_area;
- scmc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!scmc_area)
+ chp->cmg_chars = NULL;
+ cmg_chars = kmalloc(sizeof(*cmg_chars), GFP_KERNEL);
+ if (!cmg_chars)
return -ENOMEM;
+ spin_lock_irq(&chsc_page_lock);
+ memset(chsc_page, 0, PAGE_SIZE);
+ scmc_area = chsc_page;
scmc_area->request.length = 0x0010;
scmc_area->request.code = 0x0022;
-
scmc_area->first_chpid = chp->chpid.id;
scmc_area->last_chpid = chp->chpid.id;
@@ -792,53 +758,65 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
}
ret = chsc_error_from_response(scmc_area->response.code);
- if (ret == 0) {
- /* Success. */
- if (!scmc_area->not_valid) {
- chp->cmg = scmc_area->cmg;
- chp->shared = scmc_area->shared;
- chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
- (struct cmg_chars *)
- &scmc_area->data);
- } else {
- chp->cmg = -1;
- chp->shared = -1;
- }
- } else {
+ if (ret) {
CIO_CRW_EVENT(2, "chsc: scmc failed (rc=%04x)\n",
scmc_area->response.code);
+ goto out;
+ }
+ if (scmc_area->not_valid) {
+ chp->cmg = -1;
+ chp->shared = -1;
+ goto out;
}
+ chp->cmg = scmc_area->cmg;
+ chp->shared = scmc_area->shared;
+ if (chp->cmg != 2 && chp->cmg != 3) {
+ /* No cmg-dependent data. */
+ goto out;
+ }
+ chp->cmg_chars = cmg_chars;
+ chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
+ (struct cmg_chars *) &scmc_area->data);
out:
- free_page((unsigned long)scmc_area);
+ spin_unlock_irq(&chsc_page_lock);
+ if (!chp->cmg_chars)
+ kfree(cmg_chars);
+
return ret;
}
-int __init chsc_alloc_sei_area(void)
+int __init chsc_init(void)
{
int ret;
sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!sei_page) {
- CIO_MSG_EVENT(0, "Can't allocate page for processing of "
- "chsc machine checks!\n");
- return -ENOMEM;
+ chsc_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!sei_page || !chsc_page) {
+ ret = -ENOMEM;
+ goto out_err;
}
ret = crw_register_handler(CRW_RSC_CSS, chsc_process_crw);
if (ret)
- kfree(sei_page);
+ goto out_err;
+ return ret;
+out_err:
+ free_page((unsigned long)chsc_page);
+ free_page((unsigned long)sei_page);
return ret;
}
-void __init chsc_free_sei_area(void)
+void __init chsc_init_cleanup(void)
{
crw_unregister_handler(CRW_RSC_CSS);
- kfree(sei_page);
+ free_page((unsigned long)chsc_page);
+ free_page((unsigned long)sei_page);
}
int chsc_enable_facility(int operation_code)
{
+ unsigned long flags;
int ret;
- static struct {
+ struct {
struct chsc_header request;
u8 reserved1:4;
u8 format:4;
@@ -851,32 +829,33 @@ int chsc_enable_facility(int operation_code)
u32 reserved5:4;
u32 format2:4;
u32 reserved6:24;
- } __attribute__ ((packed, aligned(4096))) sda_area;
+ } __attribute__ ((packed)) *sda_area;
- spin_lock(&sda_lock);
- memset(&sda_area, 0, sizeof(sda_area));
- sda_area.request.length = 0x0400;
- sda_area.request.code = 0x0031;
- sda_area.operation_code = operation_code;
+ spin_lock_irqsave(&chsc_page_lock, flags);
+ memset(chsc_page, 0, PAGE_SIZE);
+ sda_area = chsc_page;
+ sda_area->request.length = 0x0400;
+ sda_area->request.code = 0x0031;
+ sda_area->operation_code = operation_code;
- ret = chsc(&sda_area);
+ ret = chsc(sda_area);
if (ret > 0) {
ret = (ret == 3) ? -ENODEV : -EBUSY;
goto out;
}
- switch (sda_area.response.code) {
+ switch (sda_area->response.code) {
case 0x0101:
ret = -EOPNOTSUPP;
break;
default:
- ret = chsc_error_from_response(sda_area.response.code);
+ ret = chsc_error_from_response(sda_area->response.code);
}
if (ret != 0)
CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n",
- operation_code, sda_area.response.code);
- out:
- spin_unlock(&sda_lock);
+ operation_code, sda_area->response.code);
+out:
+ spin_unlock_irqrestore(&chsc_page_lock, flags);
return ret;
}
@@ -895,13 +874,12 @@ chsc_determine_css_characteristics(void)
struct chsc_header response;
u32 reserved4;
u32 general_char[510];
- u32 chsc_char[518];
+ u32 chsc_char[508];
} __attribute__ ((packed)) *scsc_area;
- scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!scsc_area)
- return -ENOMEM;
-
+ spin_lock_irq(&chsc_page_lock);
+ memset(chsc_page, 0, PAGE_SIZE);
+ scsc_area = chsc_page;
scsc_area->request.length = 0x0010;
scsc_area->request.code = 0x0010;
@@ -921,7 +899,7 @@ chsc_determine_css_characteristics(void)
CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n",
scsc_area->response.code);
exit:
- free_page ((unsigned long) scsc_area);
+ spin_unlock_irq(&chsc_page_lock);
return result;
}
@@ -976,29 +954,29 @@ int chsc_sstpi(void *page, void *result, size_t size)
return (rr->response.code == 0x0001) ? 0 : -EIO;
}
-static struct {
- struct chsc_header request;
- u32 word1;
- struct subchannel_id sid;
- u32 word3;
- struct chsc_header response;
- u32 word[11];
-} __attribute__ ((packed)) siosl_area __attribute__ ((__aligned__(PAGE_SIZE)));
-
int chsc_siosl(struct subchannel_id schid)
{
+ struct {
+ struct chsc_header request;
+ u32 word1;
+ struct subchannel_id sid;
+ u32 word3;
+ struct chsc_header response;
+ u32 word[11];
+ } __attribute__ ((packed)) *siosl_area;
unsigned long flags;
int ccode;
int rc;
- spin_lock_irqsave(&siosl_lock, flags);
- memset(&siosl_area, 0, sizeof(siosl_area));
- siosl_area.request.length = 0x0010;
- siosl_area.request.code = 0x0046;
- siosl_area.word1 = 0x80000000;
- siosl_area.sid = schid;
+ spin_lock_irqsave(&chsc_page_lock, flags);
+ memset(chsc_page, 0, PAGE_SIZE);
+ siosl_area = chsc_page;
+ siosl_area->request.length = 0x0010;
+ siosl_area->request.code = 0x0046;
+ siosl_area->word1 = 0x80000000;
+ siosl_area->sid = schid;
- ccode = chsc(&siosl_area);
+ ccode = chsc(siosl_area);
if (ccode > 0) {
if (ccode == 3)
rc = -ENODEV;
@@ -1008,17 +986,16 @@ int chsc_siosl(struct subchannel_id schid)
schid.ssid, schid.sch_no, ccode);
goto out;
}
- rc = chsc_error_from_response(siosl_area.response.code);
+ rc = chsc_error_from_response(siosl_area->response.code);
if (rc)
CIO_MSG_EVENT(2, "chsc: siosl failed for 0.%x.%04x (rc=%04x)\n",
schid.ssid, schid.sch_no,
- siosl_area.response.code);
+ siosl_area->response.code);
else
CIO_MSG_EVENT(4, "chsc: siosl succeeded for 0.%x.%04x\n",
schid.ssid, schid.sch_no);
out:
- spin_unlock_irqrestore(&siosl_lock, flags);
-
+ spin_unlock_irqrestore(&chsc_page_lock, flags);
return rc;
}
EXPORT_SYMBOL_GPL(chsc_siosl);
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index 5453013f094b..6693f5e3176f 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -57,21 +57,39 @@ struct chsc_ssd_info {
struct chp_id chpid[8];
u16 fla[8];
};
+
+struct chsc_scpd {
+ struct chsc_header request;
+ u32:2;
+ u32 m:1;
+ u32 c:1;
+ u32 fmt:4;
+ u32 cssid:8;
+ u32:4;
+ u32 rfmt:4;
+ u32 first_chpid:8;
+ u32:24;
+ u32 last_chpid:8;
+ u32 zeroes1;
+ struct chsc_header response;
+ u8 data[PAGE_SIZE - 20];
+} __attribute__ ((packed));
+
+
extern int chsc_get_ssd_info(struct subchannel_id schid,
struct chsc_ssd_info *ssd);
extern int chsc_determine_css_characteristics(void);
-extern int chsc_alloc_sei_area(void);
-extern void chsc_free_sei_area(void);
+extern int chsc_init(void);
+extern void chsc_init_cleanup(void);
extern int chsc_enable_facility(int);
struct channel_subsystem;
extern int chsc_secm(struct channel_subsystem *, int);
-int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page);
+int __chsc_do_secm(struct channel_subsystem *css, int enable);
int chsc_chp_vary(struct chp_id chpid, int on);
int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,
- int c, int m,
- struct chsc_response_struct *resp);
+ int c, int m, void *page);
int chsc_determine_base_channel_path_desc(struct chp_id chpid,
struct channel_path_desc *desc);
void chsc_chp_online(struct chp_id chpid);
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index f2b77e7bfc6f..3c3f3ffe2179 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -688,25 +688,31 @@ out_free:
static int chsc_ioctl_chpd(void __user *user_chpd)
{
+ struct chsc_scpd *scpd_area;
struct chsc_cpd_info *chpd;
int ret;
chpd = kzalloc(sizeof(*chpd), GFP_KERNEL);
- if (!chpd)
- return -ENOMEM;
+ scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!scpd_area || !chpd) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
if (copy_from_user(chpd, user_chpd, sizeof(*chpd))) {
ret = -EFAULT;
goto out_free;
}
ret = chsc_determine_channel_path_desc(chpd->chpid, chpd->fmt,
chpd->rfmt, chpd->c, chpd->m,
- &chpd->chpdb);
+ scpd_area);
if (ret)
goto out_free;
+ memcpy(&chpd->chpdb, &scpd_area->response, scpd_area->response.length);
if (copy_to_user(user_chpd, chpd, sizeof(*chpd)))
ret = -EFAULT;
out_free:
kfree(chpd);
+ free_page((unsigned long)scpd_area);
return ret;
}
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index ca8e1c240c3c..a5050e217150 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -1,7 +1,7 @@
/*
* driver for channel subsystem
*
- * Copyright IBM Corp. 2002, 2009
+ * Copyright IBM Corp. 2002, 2010
*
* Author(s): Arnd Bergmann (arndb@de.ibm.com)
* Cornelia Huck (cornelia.huck@de.ibm.com)
@@ -577,7 +577,7 @@ static int __unset_registered(struct device *dev, void *data)
return 0;
}
-void css_schedule_eval_all_unreg(void)
+static void css_schedule_eval_all_unreg(void)
{
unsigned long flags;
struct idset *unreg_set;
@@ -790,7 +790,6 @@ static struct notifier_block css_reboot_notifier = {
static int css_power_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
- void *secm_area;
int ret, i;
switch (event) {
@@ -806,15 +805,8 @@ static int css_power_event(struct notifier_block *this, unsigned long event,
mutex_unlock(&css->mutex);
continue;
}
- secm_area = (void *)get_zeroed_page(GFP_KERNEL |
- GFP_DMA);
- if (secm_area) {
- if (__chsc_do_secm(css, 0, secm_area))
- ret = NOTIFY_BAD;
- free_page((unsigned long)secm_area);
- } else
+ if (__chsc_do_secm(css, 0))
ret = NOTIFY_BAD;
-
mutex_unlock(&css->mutex);
}
break;
@@ -830,15 +822,8 @@ static int css_power_event(struct notifier_block *this, unsigned long event,
mutex_unlock(&css->mutex);
continue;
}
- secm_area = (void *)get_zeroed_page(GFP_KERNEL |
- GFP_DMA);
- if (secm_area) {
- if (__chsc_do_secm(css, 1, secm_area))
- ret = NOTIFY_BAD;
- free_page((unsigned long)secm_area);
- } else
+ if (__chsc_do_secm(css, 1))
ret = NOTIFY_BAD;
-
mutex_unlock(&css->mutex);
}
/* search for subchannels, which appeared during hibernation */
@@ -863,14 +848,11 @@ static int __init css_bus_init(void)
{
int ret, i;
- ret = chsc_determine_css_characteristics();
- if (ret == -ENOMEM)
- goto out;
-
- ret = chsc_alloc_sei_area();
+ ret = chsc_init();
if (ret)
- goto out;
+ return ret;
+ chsc_determine_css_characteristics();
/* Try to enable MSS. */
ret = chsc_enable_facility(CHSC_SDA_OC_MSS);
if (ret)
@@ -956,9 +938,9 @@ out_unregister:
}
bus_unregister(&css_bus_type);
out:
- crw_unregister_handler(CRW_RSC_CSS);
- chsc_free_sei_area();
+ crw_unregister_handler(CRW_RSC_SCH);
idset_free(slow_subchannel_set);
+ chsc_init_cleanup();
pr_alert("The CSS device driver initialization failed with "
"errno=%d\n", ret);
return ret;
@@ -978,9 +960,9 @@ static void __init css_bus_cleanup(void)
device_unregister(&css->device);
}
bus_unregister(&css_bus_type);
- crw_unregister_handler(CRW_RSC_CSS);
- chsc_free_sei_area();
+ crw_unregister_handler(CRW_RSC_SCH);
idset_free(slow_subchannel_set);
+ chsc_init_cleanup();
isc_unregister(IO_SCH_ISC);
}
@@ -1048,7 +1030,16 @@ subsys_initcall_sync(channel_subsystem_init_sync);
void channel_subsystem_reinit(void)
{
+ struct channel_path *chp;
+ struct chp_id chpid;
+
chsc_enable_facility(CHSC_SDA_OC_MSS);
+ chp_id_for_each(&chpid) {
+ chp = chpid_to_chp(chpid);
+ if (!chp)
+ continue;
+ chsc_determine_base_channel_path_desc(chpid, &chp->desc);
+ }
}
#ifdef CONFIG_PROC_FS
@@ -1200,6 +1191,7 @@ static int css_pm_restore(struct device *dev)
struct subchannel *sch = to_subchannel(dev);
struct css_driver *drv;
+ css_update_ssd_info(sch);
if (!sch->dev.driver)
return 0;
drv = to_cssdriver(sch->dev.driver);
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 51bd3687d163..2ff8a22d4257 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1147,6 +1147,7 @@ err:
static int io_subchannel_chp_event(struct subchannel *sch,
struct chp_link *link, int event)
{
+ struct ccw_device *cdev = sch_get_cdev(sch);
int mask;
mask = chp_ssd_get_mask(&sch->ssd_info, link);
@@ -1156,22 +1157,30 @@ static int io_subchannel_chp_event(struct subchannel *sch,
case CHP_VARY_OFF:
sch->opm &= ~mask;
sch->lpm &= ~mask;
+ if (cdev)
+ cdev->private->path_gone_mask |= mask;
io_subchannel_terminate_path(sch, mask);
break;
case CHP_VARY_ON:
sch->opm |= mask;
sch->lpm |= mask;
+ if (cdev)
+ cdev->private->path_new_mask |= mask;
io_subchannel_verify(sch);
break;
case CHP_OFFLINE:
if (cio_update_schib(sch))
return -ENODEV;
+ if (cdev)
+ cdev->private->path_gone_mask |= mask;
io_subchannel_terminate_path(sch, mask);
break;
case CHP_ONLINE:
if (cio_update_schib(sch))
return -ENODEV;
sch->lpm |= mask & sch->opm;
+ if (cdev)
+ cdev->private->path_new_mask |= mask;
io_subchannel_verify(sch);
break;
}
@@ -1196,6 +1205,7 @@ static void io_subchannel_quiesce(struct subchannel *sch)
cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-EIO));
while (ret == -EBUSY) {
cdev->private->state = DEV_STATE_QUIESCE;
+ cdev->private->iretry = 255;
ret = ccw_device_cancel_halt_clear(cdev);
if (ret == -EBUSY) {
ccw_device_set_timeout(cdev, HZ/10);
@@ -1468,9 +1478,13 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
goto out;
break;
case IO_SCH_UNREG_ATTACH:
+ if (cdev->private->flags.resuming) {
+ /* Device will be handled later. */
+ rc = 0;
+ goto out;
+ }
/* Unregister ccw device. */
- if (!cdev->private->flags.resuming)
- ccw_device_unregister(cdev);
+ ccw_device_unregister(cdev);
break;
default:
break;
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index c9b852647f01..a845695ac314 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -174,7 +174,10 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
ret = cio_clear (sch);
return (ret == 0) ? -EBUSY : ret;
}
- panic("Can't stop i/o on subchannel.\n");
+ /* Function was unsuccessful */
+ CIO_MSG_EVENT(0, "0.%x.%04x: could not stop I/O\n",
+ cdev->private->dev_id.ssid, cdev->private->dev_id.devno);
+ return -EIO;
}
void ccw_device_update_sense_data(struct ccw_device *cdev)
@@ -349,9 +352,13 @@ out:
static void ccw_device_oper_notify(struct ccw_device *cdev)
{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+
if (ccw_device_notify(cdev, CIO_OPER) == NOTIFY_OK) {
/* Reenable channel measurements, if needed. */
ccw_device_sched_todo(cdev, CDEV_TODO_ENABLE_CMF);
+ /* Save indication for new paths. */
+ cdev->private->path_new_mask = sch->vpm;
return;
}
/* Driver doesn't want device back. */
@@ -462,6 +469,32 @@ static void ccw_device_request_event(struct ccw_device *cdev, enum dev_event e)
}
}
+static void ccw_device_report_path_events(struct ccw_device *cdev)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ int path_event[8];
+ int chp, mask;
+
+ for (chp = 0, mask = 0x80; chp < 8; chp++, mask >>= 1) {
+ path_event[chp] = PE_NONE;
+ if (mask & cdev->private->path_gone_mask & ~(sch->vpm))
+ path_event[chp] |= PE_PATH_GONE;
+ if (mask & cdev->private->path_new_mask & sch->vpm)
+ path_event[chp] |= PE_PATH_AVAILABLE;
+ if (mask & cdev->private->pgid_reset_mask & sch->vpm)
+ path_event[chp] |= PE_PATHGROUP_ESTABLISHED;
+ }
+ if (cdev->online && cdev->drv->path_event)
+ cdev->drv->path_event(cdev, path_event);
+}
+
+static void ccw_device_reset_path_events(struct ccw_device *cdev)
+{
+ cdev->private->path_gone_mask = 0;
+ cdev->private->path_new_mask = 0;
+ cdev->private->pgid_reset_mask = 0;
+}
+
void
ccw_device_verify_done(struct ccw_device *cdev, int err)
{
@@ -498,6 +531,7 @@ callback:
&cdev->private->irb);
memset(&cdev->private->irb, 0, sizeof(struct irb));
}
+ ccw_device_report_path_events(cdev);
break;
case -ETIME:
case -EUSERS:
@@ -516,6 +550,7 @@ callback:
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
break;
}
+ ccw_device_reset_path_events(cdev);
}
/*
@@ -734,13 +769,14 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
int ret;
ccw_device_set_timeout(cdev, 0);
+ cdev->private->iretry = 255;
ret = ccw_device_cancel_halt_clear(cdev);
if (ret == -EBUSY) {
ccw_device_set_timeout(cdev, 3*HZ);
cdev->private->state = DEV_STATE_TIMEOUT_KILL;
return;
}
- if (ret == -ENODEV)
+ if (ret)
dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
else if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
@@ -837,6 +873,7 @@ void ccw_device_kill_io(struct ccw_device *cdev)
{
int ret;
+ cdev->private->iretry = 255;
ret = ccw_device_cancel_halt_clear(cdev);
if (ret == -EBUSY) {
ccw_device_set_timeout(cdev, 3*HZ);
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index 82a5ad0d63f6..07a4fd29f096 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -213,6 +213,17 @@ static void spid_start(struct ccw_device *cdev)
spid_do(cdev);
}
+static int pgid_is_reset(struct pgid *p)
+{
+ char *c;
+
+ for (c = (char *)p + 1; c < (char *)(p + 1); c++) {
+ if (*c != 0)
+ return 0;
+ }
+ return 1;
+}
+
static int pgid_cmp(struct pgid *p1, struct pgid *p2)
{
return memcmp((char *) p1 + 1, (char *) p2 + 1,
@@ -223,7 +234,7 @@ static int pgid_cmp(struct pgid *p1, struct pgid *p2)
* Determine pathgroup state from PGID data.
*/
static void pgid_analyze(struct ccw_device *cdev, struct pgid **p,
- int *mismatch, int *reserved, int *reset)
+ int *mismatch, int *reserved, u8 *reset)
{
struct pgid *pgid = &cdev->private->pgid[0];
struct pgid *first = NULL;
@@ -238,9 +249,8 @@ static void pgid_analyze(struct ccw_device *cdev, struct pgid **p,
continue;
if (pgid->inf.ps.state2 == SNID_STATE2_RESVD_ELSE)
*reserved = 1;
- if (pgid->inf.ps.state1 == SNID_STATE1_RESET) {
- /* A PGID was reset. */
- *reset = 1;
+ if (pgid_is_reset(pgid)) {
+ *reset |= lpm;
continue;
}
if (!first) {
@@ -307,7 +317,7 @@ static void snid_done(struct ccw_device *cdev, int rc)
struct pgid *pgid;
int mismatch = 0;
int reserved = 0;
- int reset = 0;
+ u8 reset = 0;
u8 donepm;
if (rc)
@@ -321,11 +331,12 @@ static void snid_done(struct ccw_device *cdev, int rc)
donepm = pgid_to_donepm(cdev);
sch->vpm = donepm & sch->opm;
cdev->private->pgid_todo_mask &= ~donepm;
+ cdev->private->pgid_reset_mask |= reset;
pgid_fill(cdev, pgid);
}
out:
CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x vpm=%02x "
- "todo=%02x mism=%d rsvd=%d reset=%d\n", id->ssid,
+ "todo=%02x mism=%d rsvd=%d reset=%02x\n", id->ssid,
id->devno, rc, cdev->private->pgid_valid_mask, sch->vpm,
cdev->private->pgid_todo_mask, mismatch, reserved, reset);
switch (rc) {
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
index 469ef93f2302..d024d2c21897 100644
--- a/drivers/s390/cio/io_sch.h
+++ b/drivers/s390/cio/io_sch.h
@@ -151,8 +151,11 @@ struct ccw_device_private {
struct subchannel_id schid; /* subchannel number */
struct ccw_request req; /* internal I/O request */
int iretry;
- u8 pgid_valid_mask; /* mask of valid PGIDs */
- u8 pgid_todo_mask; /* mask of PGIDs to be adjusted */
+ u8 pgid_valid_mask; /* mask of valid PGIDs */
+ u8 pgid_todo_mask; /* mask of PGIDs to be adjusted */
+ u8 pgid_reset_mask; /* mask of PGIDs which were reset */
+ u8 path_gone_mask; /* mask of paths, that became unavailable */
+ u8 path_new_mask; /* mask of paths, that became available */
struct {
unsigned int fast:1; /* post with "channel end" */
unsigned int repall:1; /* report every interrupt status */
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index f0037eefd44e..0f4ef8769a3d 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -208,6 +208,7 @@ struct qdio_dev_perf_stat {
unsigned int eqbs_partial;
unsigned int sqbs;
unsigned int sqbs_partial;
+ unsigned int int_discarded;
} ____cacheline_aligned;
struct qdio_queue_perf_stat {
@@ -222,6 +223,10 @@ struct qdio_queue_perf_stat {
unsigned int nr_sbal_total;
};
+enum qdio_queue_irq_states {
+ QDIO_QUEUE_IRQS_DISABLED,
+};
+
struct qdio_input_q {
/* input buffer acknowledgement flag */
int polling;
@@ -231,6 +236,10 @@ struct qdio_input_q {
int ack_count;
/* last time of noticing incoming data */
u64 timestamp;
+ /* upper-layer polling flag */
+ unsigned long queue_irq_state;
+ /* callback to start upper-layer polling */
+ void (*queue_start_poll) (struct ccw_device *, int, unsigned long);
};
struct qdio_output_q {
@@ -399,6 +408,26 @@ static inline int multicast_outbound(struct qdio_q *q)
#define sub_buf(bufnr, dec) \
((bufnr - dec) & QDIO_MAX_BUFFERS_MASK)
+#define queue_irqs_enabled(q) \
+ (test_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state) == 0)
+#define queue_irqs_disabled(q) \
+ (test_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state) != 0)
+
+#define TIQDIO_SHARED_IND 63
+
+/* device state change indicators */
+struct indicator_t {
+ u32 ind; /* u32 because of compare-and-swap performance */
+ atomic_t count; /* use count, 0 or 1 for non-shared indicators */
+};
+
+extern struct indicator_t *q_indicators;
+
+static inline int shared_ind(struct qdio_irq *irq_ptr)
+{
+ return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind;
+}
+
/* prototypes for thin interrupt */
void qdio_setup_thinint(struct qdio_irq *irq_ptr);
int qdio_establish_thinint(struct qdio_irq *irq_ptr);
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index 6ce83f56d537..28868e7471a5 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -56,9 +56,16 @@ static int qstat_show(struct seq_file *m, void *v)
seq_printf(m, "DSCI: %d nr_used: %d\n",
*(u32 *)q->irq_ptr->dsci, atomic_read(&q->nr_buf_used));
- seq_printf(m, "ftc: %d last_move: %d\n", q->first_to_check, q->last_move);
- seq_printf(m, "polling: %d ack start: %d ack count: %d\n",
- q->u.in.polling, q->u.in.ack_start, q->u.in.ack_count);
+ seq_printf(m, "ftc: %d last_move: %d\n",
+ q->first_to_check, q->last_move);
+ if (q->is_input_q) {
+ seq_printf(m, "polling: %d ack start: %d ack count: %d\n",
+ q->u.in.polling, q->u.in.ack_start,
+ q->u.in.ack_count);
+ seq_printf(m, "IRQs disabled: %u\n",
+ test_bit(QDIO_QUEUE_IRQS_DISABLED,
+ &q->u.in.queue_irq_state));
+ }
seq_printf(m, "SBAL states:\n");
seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
@@ -113,22 +120,6 @@ static int qstat_show(struct seq_file *m, void *v)
return 0;
}
-static ssize_t qstat_seq_write(struct file *file, const char __user *buf,
- size_t count, loff_t *off)
-{
- struct seq_file *seq = file->private_data;
- struct qdio_q *q = seq->private;
-
- if (!q)
- return 0;
- if (q->is_input_q)
- xchg(q->irq_ptr->dsci, 1);
- local_bh_disable();
- tasklet_schedule(&q->tasklet);
- local_bh_enable();
- return count;
-}
-
static int qstat_seq_open(struct inode *inode, struct file *filp)
{
return single_open(filp, qstat_show,
@@ -139,7 +130,6 @@ static const struct file_operations debugfs_fops = {
.owner = THIS_MODULE,
.open = qstat_seq_open,
.read = seq_read,
- .write = qstat_seq_write,
.llseek = seq_lseek,
.release = single_release,
};
@@ -166,7 +156,8 @@ static char *qperf_names[] = {
"QEBSM eqbs",
"QEBSM eqbs partial",
"QEBSM sqbs",
- "QEBSM sqbs partial"
+ "QEBSM sqbs partial",
+ "Discarded interrupts"
};
static int qperf_show(struct seq_file *m, void *v)
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 00520f9a7a8e..5fcfa7f9e9ef 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -884,8 +884,19 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr)
if (unlikely(irq_ptr->state == QDIO_IRQ_STATE_STOPPED))
return;
- for_each_input_queue(irq_ptr, q, i)
- tasklet_schedule(&q->tasklet);
+ for_each_input_queue(irq_ptr, q, i) {
+ 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;
+ }
+ q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr,
+ q->irq_ptr->int_parm);
+ } else
+ tasklet_schedule(&q->tasklet);
+ }
if (!(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED))
return;
@@ -1519,6 +1530,129 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
}
EXPORT_SYMBOL_GPL(do_QDIO);
+/**
+ * qdio_start_irq - process input buffers
+ * @cdev: associated ccw_device for the qdio subchannel
+ * @nr: input queue number
+ *
+ * Return codes
+ * 0 - success
+ * 1 - irqs not started since new data is available
+ */
+int qdio_start_irq(struct ccw_device *cdev, int nr)
+{
+ struct qdio_q *q;
+ struct qdio_irq *irq_ptr = cdev->private->qdio_data;
+
+ if (!irq_ptr)
+ return -ENODEV;
+ q = irq_ptr->input_qs[nr];
+
+ WARN_ON(queue_irqs_enabled(q));
+
+ if (!shared_ind(q->irq_ptr))
+ xchg(q->irq_ptr->dsci, 0);
+
+ qdio_stop_polling(q);
+ clear_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state);
+
+ /*
+ * We need to check again to not lose initiative after
+ * resetting the ACK state.
+ */
+ if (!shared_ind(q->irq_ptr) && *q->irq_ptr->dsci)
+ goto rescan;
+ if (!qdio_inbound_q_done(q))
+ goto rescan;
+ return 0;
+
+rescan:
+ if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED,
+ &q->u.in.queue_irq_state))
+ return 0;
+ else
+ return 1;
+
+}
+EXPORT_SYMBOL(qdio_start_irq);
+
+/**
+ * qdio_get_next_buffers - process input buffers
+ * @cdev: associated ccw_device for the qdio subchannel
+ * @nr: input queue number
+ * @bufnr: first filled buffer number
+ * @error: buffers are in error state
+ *
+ * Return codes
+ * < 0 - error
+ * = 0 - no new buffers found
+ * > 0 - number of processed buffers
+ */
+int qdio_get_next_buffers(struct ccw_device *cdev, int nr, int *bufnr,
+ int *error)
+{
+ struct qdio_q *q;
+ int start, end;
+ struct qdio_irq *irq_ptr = cdev->private->qdio_data;
+
+ if (!irq_ptr)
+ return -ENODEV;
+ q = irq_ptr->input_qs[nr];
+ WARN_ON(queue_irqs_enabled(q));
+
+ qdio_sync_after_thinint(q);
+
+ /*
+ * The interrupt could be caused by a PCI request. Check the
+ * PCI capable outbound queues.
+ */
+ qdio_check_outbound_after_thinint(q);
+
+ if (!qdio_inbound_q_moved(q))
+ return 0;
+
+ /* Note: upper-layer MUST stop processing immediately here ... */
+ if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE))
+ return -EIO;
+
+ start = q->first_to_kick;
+ end = q->first_to_check;
+ *bufnr = start;
+ *error = q->qdio_error;
+
+ /* for the next time */
+ q->first_to_kick = end;
+ q->qdio_error = 0;
+ return sub_buf(end, start);
+}
+EXPORT_SYMBOL(qdio_get_next_buffers);
+
+/**
+ * qdio_stop_irq - disable interrupt processing for the device
+ * @cdev: associated ccw_device for the qdio subchannel
+ * @nr: input queue number
+ *
+ * Return codes
+ * 0 - interrupts were already disabled
+ * 1 - interrupts successfully disabled
+ */
+int qdio_stop_irq(struct ccw_device *cdev, int nr)
+{
+ struct qdio_q *q;
+ struct qdio_irq *irq_ptr = cdev->private->qdio_data;
+
+ if (!irq_ptr)
+ return -ENODEV;
+ q = irq_ptr->input_qs[nr];
+
+ if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED,
+ &q->u.in.queue_irq_state))
+ return 0;
+ else
+ return 1;
+}
+EXPORT_SYMBOL(qdio_stop_irq);
+
static int __init init_QDIO(void)
{
int rc;
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index 34c7e4046df4..a13cf7ec64b2 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -161,6 +161,7 @@ static void setup_queues(struct qdio_irq *irq_ptr,
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;
setup_storage_lists(q, irq_ptr, input_sbal_array, i);
input_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c
index 8daf1b99f153..752dbee06af5 100644
--- a/drivers/s390/cio/qdio_thinint.c
+++ b/drivers/s390/cio/qdio_thinint.c
@@ -25,24 +25,20 @@
*/
#define TIQDIO_NR_NONSHARED_IND 63
#define TIQDIO_NR_INDICATORS (TIQDIO_NR_NONSHARED_IND + 1)
-#define TIQDIO_SHARED_IND 63
/* list of thin interrupt input queues */
static LIST_HEAD(tiq_list);
DEFINE_MUTEX(tiq_list_lock);
/* adapter local summary indicator */
-static unsigned char *tiqdio_alsi;
+static u8 *tiqdio_alsi;
-/* device state change indicators */
-struct indicator_t {
- u32 ind; /* u32 because of compare-and-swap performance */
- atomic_t count; /* use count, 0 or 1 for non-shared indicators */
-};
-static struct indicator_t *q_indicators;
+struct indicator_t *q_indicators;
static int css_qdio_omit_svs;
+static u64 last_ai_time;
+
static inline unsigned long do_clear_global_summary(void)
{
register unsigned long __fn asm("1") = 3;
@@ -116,59 +112,73 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
}
}
-static inline int shared_ind(struct qdio_irq *irq_ptr)
+static inline int shared_ind_used(void)
{
- return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind;
+ return atomic_read(&q_indicators[TIQDIO_SHARED_IND].count);
}
/**
* tiqdio_thinint_handler - thin interrupt handler for qdio
- * @ind: pointer to adapter local summary indicator
- * @drv_data: NULL
+ * @alsi: pointer to adapter local summary indicator
+ * @data: NULL
*/
-static void tiqdio_thinint_handler(void *ind, void *drv_data)
+static void tiqdio_thinint_handler(void *alsi, void *data)
{
struct qdio_q *q;
+ last_ai_time = S390_lowcore.int_clock;
+
/*
* SVS only when needed: issue SVS to benefit from iqdio interrupt
- * avoidance (SVS clears adapter interrupt suppression overwrite)
+ * avoidance (SVS clears adapter interrupt suppression overwrite).
*/
if (!css_qdio_omit_svs)
do_clear_global_summary();
- /*
- * reset local summary indicator (tiqdio_alsi) to stop adapter
- * interrupts for now
- */
- xchg((u8 *)ind, 0);
+ /* reset local summary indicator */
+ if (shared_ind_used())
+ xchg(tiqdio_alsi, 0);
/* protect tiq_list entries, only changed in activate or shutdown */
rcu_read_lock();
/* check for work on all inbound thinint queues */
- list_for_each_entry_rcu(q, &tiq_list, entry)
+ list_for_each_entry_rcu(q, &tiq_list, entry) {
+
/* only process queues from changed sets */
- if (*q->irq_ptr->dsci) {
- qperf_inc(q, adapter_int);
+ if (!*q->irq_ptr->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;
+ }
+
+ /* 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))
xchg(q->irq_ptr->dsci, 0);
/*
- * don't call inbound processing directly since
- * that could starve other thinint queues
+ * 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();
/*
- * if we used the shared indicator clear it now after all queues
- * were processed
+ * If the shared indicator was used clear it now after all queues
+ * were processed.
*/
- if (atomic_read(&q_indicators[TIQDIO_SHARED_IND].count)) {
+ if (shared_ind_used()) {
xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0);
/* prevent racing */
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 91c6028d7b74..8fd8c62455e9 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -154,14 +154,7 @@ static inline int ap_instructions_available(void)
*/
static int ap_interrupts_available(void)
{
- unsigned long long facility_bits[2];
-
- if (stfle(facility_bits, 2) <= 1)
- return 0;
- if (!(facility_bits[0] & (1ULL << 61)) ||
- !(facility_bits[1] & (1ULL << 62)))
- return 0;
- return 1;
+ return test_facility(1) && test_facility(2);
}
/**
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index 4e298bc8949d..375aeeaf9ea5 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -32,6 +32,7 @@
* The pointer to our (page) of device descriptions.
*/
static void *kvm_devices;
+struct work_struct hotplug_work;
struct kvm_device {
struct virtio_device vdev;
@@ -328,33 +329,85 @@ static void scan_devices(void)
}
/*
+ * match for a kvm device with a specific desc pointer
+ */
+static int match_desc(struct device *dev, void *data)
+{
+ if ((ulong)to_kvmdev(dev_to_virtio(dev))->desc == (ulong)data)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * hotplug_device tries to find changes in the device page.
+ */
+static void hotplug_devices(struct work_struct *dummy)
+{
+ unsigned int i;
+ struct kvm_device_desc *d;
+ struct device *dev;
+
+ for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
+ d = kvm_devices + i;
+
+ /* end of list */
+ if (d->type == 0)
+ break;
+
+ /* device already exists */
+ dev = device_find_child(kvm_root, d, match_desc);
+ if (dev) {
+ /* XXX check for hotplug remove */
+ put_device(dev);
+ continue;
+ }
+
+ /* new device */
+ printk(KERN_INFO "Adding new virtio device %p\n", d);
+ add_kvm_device(d, i);
+ }
+}
+
+/*
* we emulate the request_irq behaviour on top of s390 extints
*/
-static void kvm_extint_handler(u16 code)
+static void kvm_extint_handler(unsigned int ext_int_code,
+ unsigned int param32, unsigned long param64)
{
struct virtqueue *vq;
u16 subcode;
- int config_changed;
+ u32 param;
- subcode = S390_lowcore.cpu_addr;
+ subcode = ext_int_code >> 16;
if ((subcode & 0xff00) != VIRTIO_SUBCODE_64)
return;
/* The LSB might be overloaded, we have to mask it */
- vq = (struct virtqueue *)(S390_lowcore.ext_params2 & ~1UL);
+ vq = (struct virtqueue *)(param64 & ~1UL);
- /* We use the LSB of extparam, to decide, if this interrupt is a config
- * change or a "standard" interrupt */
- config_changed = S390_lowcore.ext_params & 1;
+ /* We use ext_params to decide what this interrupt means */
+ param = param32 & VIRTIO_PARAM_MASK;
- if (config_changed) {
+ switch (param) {
+ case VIRTIO_PARAM_CONFIG_CHANGED:
+ {
struct virtio_driver *drv;
drv = container_of(vq->vdev->dev.driver,
struct virtio_driver, driver);
if (drv->config_changed)
drv->config_changed(vq->vdev);
- } else
+
+ break;
+ }
+ case VIRTIO_PARAM_DEV_ADD:
+ schedule_work(&hotplug_work);
+ break;
+ case VIRTIO_PARAM_VRING_INTERRUPT:
+ default:
vring_interrupt(0, vq);
+ break;
+ }
}
/*
@@ -383,6 +436,8 @@ static int __init kvm_devices_init(void)
kvm_devices = (void *) real_memory_size;
+ INIT_WORK(&hotplug_work, hotplug_devices);
+
ctl_set_bit(0, 9);
register_external_interrupt(0x2603, kvm_extint_handler);
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index 977bb4d4ed15..456b18743397 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -100,6 +100,6 @@ config QETH_IPV6
config CCWGROUP
tristate
- default (LCS || CTCM || QETH)
+ default (LCS || CTCM || QETH || CLAW)
endmenu
diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c
index 2861e78773cb..b64881f33f23 100644
--- a/drivers/s390/net/ctcm_mpc.c
+++ b/drivers/s390/net/ctcm_mpc.c
@@ -540,7 +540,7 @@ void ctc_mpc_dealloc_ch(int port_num)
CTCM_DBF_TEXT_(MPC_SETUP, CTC_DBF_DEBUG,
"%s: %s: refcount = %d\n",
- CTCM_FUNTAIL, dev->name, atomic_read(&dev->refcnt));
+ CTCM_FUNTAIL, dev->name, netdev_refcnt_read(dev));
fsm_deltimer(&priv->restart_timer);
grp->channels_terminating = 0;
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index d1257768be90..6be43eb126b4 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -676,6 +676,7 @@ enum qeth_discipline_id {
};
struct qeth_discipline {
+ void (*start_poll)(struct ccw_device *, int, unsigned long);
qdio_handler_t *input_handler;
qdio_handler_t *output_handler;
int (*recover)(void *ptr);
@@ -702,6 +703,16 @@ struct qeth_skb_data {
#define QETH_SKB_MAGIC 0x71657468
#define QETH_SIGA_CC2_RETRIES 3
+struct qeth_rx {
+ int b_count;
+ int b_index;
+ struct qdio_buffer_element *b_element;
+ int e_offset;
+ int qdio_err;
+};
+
+#define QETH_NAPI_WEIGHT 128
+
struct qeth_card {
struct list_head list;
enum qeth_card_states state;
@@ -749,6 +760,8 @@ struct qeth_card {
debug_info_t *debug;
struct mutex conf_mutex;
struct mutex discipline_mutex;
+ struct napi_struct napi;
+ struct qeth_rx rx;
};
struct qeth_card_list_struct {
@@ -831,6 +844,10 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *,
struct 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);
+void qeth_qdio_input_handler(struct ccw_device *,
+ unsigned int, unsigned int, int,
+ int, unsigned long);
void qeth_qdio_output_handler(struct ccw_device *, unsigned int,
int, int, int, unsigned long);
void qeth_clear_ipacmd_list(struct qeth_card *);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 3a5a18a0fc28..764267062601 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -2911,6 +2911,27 @@ static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue)
}
}
+void qeth_qdio_start_poll(struct ccw_device *ccwdev, int queue,
+ unsigned long card_ptr)
+{
+ struct qeth_card *card = (struct qeth_card *)card_ptr;
+
+ if (card->dev)
+ napi_schedule(&card->napi);
+}
+EXPORT_SYMBOL_GPL(qeth_qdio_start_poll);
+
+void qeth_qdio_input_handler(struct ccw_device *ccwdev, unsigned int qdio_err,
+ unsigned int queue, int first_element, int count,
+ unsigned long card_ptr)
+{
+ struct qeth_card *card = (struct qeth_card *)card_ptr;
+
+ if (qdio_err)
+ qeth_schedule_recovery(card);
+}
+EXPORT_SYMBOL_GPL(qeth_qdio_input_handler);
+
void qeth_qdio_output_handler(struct ccw_device *ccwdev,
unsigned int qdio_error, int __queue, int first_element,
int count, unsigned long card_ptr)
@@ -3843,6 +3864,7 @@ static int qeth_qdio_establish(struct qeth_card *card)
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.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;
@@ -4513,8 +4535,8 @@ static struct {
/* 20 */{"queue 1 buffer usage"},
{"queue 2 buffer usage"},
{"queue 3 buffer usage"},
- {"rx handler time"},
- {"rx handler count"},
+ {"rx poll time"},
+ {"rx poll count"},
{"rx do_QDIO time"},
{"rx do_QDIO count"},
{"tx handler time"},
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 830d63524d61..847e8797073c 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -310,6 +310,8 @@ static void qeth_l2_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
struct qeth_vlan_vid *id;
QETH_CARD_TEXT_(card, 4, "aid:%d", vid);
+ if (!vid)
+ return;
if (card->info.type == QETH_CARD_TYPE_OSM) {
QETH_CARD_TEXT(card, 3, "aidOSM");
return;
@@ -407,29 +409,25 @@ static int qeth_l2_stop_card(struct qeth_card *card, int recovery_mode)
return rc;
}
-static void qeth_l2_process_inbound_buffer(struct qeth_card *card,
- struct qeth_qdio_buffer *buf, int index)
+static int qeth_l2_process_inbound_buffer(struct qeth_card *card,
+ int budget, int *done)
{
- struct qdio_buffer_element *element;
+ int work_done = 0;
struct sk_buff *skb;
struct qeth_hdr *hdr;
- int offset;
unsigned int len;
- /* get first element of current buffer */
- element = (struct qdio_buffer_element *)&buf->buffer->element[0];
- offset = 0;
- if (card->options.performance_stats)
- card->perf_stats.bufs_rec++;
- while ((skb = qeth_core_get_next_skb(card, buf->buffer, &element,
- &offset, &hdr))) {
- skb->dev = card->dev;
- /* is device UP ? */
- if (!(card->dev->flags & IFF_UP)) {
- dev_kfree_skb_any(skb);
- continue;
+ *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->rx.b_element, &card->rx.e_offset, &hdr);
+ if (!skb) {
+ *done = 1;
+ break;
}
-
+ skb->dev = card->dev;
switch (hdr->hdr.l2.id) {
case QETH_HEADER_TYPE_LAYER2:
skb->pkt_type = PACKET_HOST;
@@ -441,7 +439,7 @@ static void qeth_l2_process_inbound_buffer(struct qeth_card *card,
if (skb->protocol == htons(ETH_P_802_2))
*((__u32 *)skb->cb) = ++card->seqno.pkt_seqno;
len = skb->len;
- netif_rx(skb);
+ netif_receive_skb(skb);
break;
case QETH_HEADER_TYPE_OSN:
if (card->info.type == QETH_CARD_TYPE_OSN) {
@@ -459,9 +457,87 @@ static void qeth_l2_process_inbound_buffer(struct qeth_card *card,
QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN);
continue;
}
+ work_done++;
+ budget--;
card->stats.rx_packets++;
card->stats.rx_bytes += len;
}
+ return work_done;
+}
+
+static int qeth_l2_poll(struct napi_struct *napi, int budget)
+{
+ struct qeth_card *card = container_of(napi, struct qeth_card, napi);
+ int work_done = 0;
+ struct qeth_qdio_buffer *buffer;
+ int done;
+ int new_budget = budget;
+
+ if (card->options.performance_stats) {
+ card->perf_stats.inbound_cnt++;
+ card->perf_stats.inbound_start_time = qeth_get_micros();
+ }
+
+ while (1) {
+ if (!card->rx.b_count) {
+ card->rx.qdio_err = 0;
+ card->rx.b_count = qdio_get_next_buffers(
+ card->data.ccwdev, 0, &card->rx.b_index,
+ &card->rx.qdio_err);
+ if (card->rx.b_count <= 0) {
+ card->rx.b_count = 0;
+ break;
+ }
+ card->rx.b_element =
+ &card->qdio.in_q->bufs[card->rx.b_index]
+ .buffer->element[0];
+ card->rx.e_offset = 0;
+ }
+
+ while (card->rx.b_count) {
+ buffer = &card->qdio.in_q->bufs[card->rx.b_index];
+ if (!(card->rx.qdio_err &&
+ qeth_check_qdio_errors(card, buffer->buffer,
+ card->rx.qdio_err, "qinerr")))
+ work_done += qeth_l2_process_inbound_buffer(
+ card, new_budget, &done);
+ else
+ done = 1;
+
+ if (done) {
+ if (card->options.performance_stats)
+ card->perf_stats.bufs_rec++;
+ qeth_put_buffer_pool_entry(card,
+ buffer->pool_entry);
+ qeth_queue_input_buffer(card, card->rx.b_index);
+ card->rx.b_count--;
+ if (card->rx.b_count) {
+ card->rx.b_index =
+ (card->rx.b_index + 1) %
+ QDIO_MAX_BUFFERS_PER_Q;
+ card->rx.b_element =
+ &card->qdio.in_q
+ ->bufs[card->rx.b_index]
+ .buffer->element[0];
+ card->rx.e_offset = 0;
+ }
+ }
+
+ if (work_done >= budget)
+ goto out;
+ else
+ new_budget = budget - work_done;
+ }
+ }
+
+ napi_complete(napi);
+ if (qdio_start_irq(card->data.ccwdev, 0))
+ napi_schedule(&card->napi);
+out:
+ if (card->options.performance_stats)
+ card->perf_stats.inbound_time += qeth_get_micros() -
+ card->perf_stats.inbound_start_time;
+ return work_done;
}
static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac,
@@ -755,49 +831,10 @@ tx_drop:
return NETDEV_TX_OK;
}
-static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev,
- unsigned int qdio_err, unsigned int queue,
- int first_element, int count, unsigned long card_ptr)
-{
- struct net_device *net_dev;
- struct qeth_card *card;
- struct qeth_qdio_buffer *buffer;
- int index;
- int i;
-
- card = (struct qeth_card *) card_ptr;
- net_dev = card->dev;
- if (card->options.performance_stats) {
- card->perf_stats.inbound_cnt++;
- card->perf_stats.inbound_start_time = qeth_get_micros();
- }
- if (qdio_err & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) {
- QETH_CARD_TEXT(card, 1, "qdinchk");
- QETH_CARD_TEXT_(card, 1, "%04X%04X", first_element,
- count);
- QETH_CARD_TEXT_(card, 1, "%04X", queue);
- qeth_schedule_recovery(card);
- return;
- }
- for (i = first_element; i < (first_element + count); ++i) {
- index = i % QDIO_MAX_BUFFERS_PER_Q;
- buffer = &card->qdio.in_q->bufs[index];
- if (!(qdio_err &&
- qeth_check_qdio_errors(card, buffer->buffer, qdio_err,
- "qinerr")))
- qeth_l2_process_inbound_buffer(card, buffer, index);
- /* clear buffer and give back to hardware */
- qeth_put_buffer_pool_entry(card, buffer->pool_entry);
- qeth_queue_input_buffer(card, index);
- }
- if (card->options.performance_stats)
- card->perf_stats.inbound_time += qeth_get_micros() -
- card->perf_stats.inbound_start_time;
-}
-
static int qeth_l2_open(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
+ int rc = 0;
QETH_CARD_TEXT(card, 4, "qethopen");
if (card->state != CARD_STATE_SOFTSETUP)
@@ -814,18 +851,24 @@ static int qeth_l2_open(struct net_device *dev)
if (!card->lan_online && netif_carrier_ok(dev))
netif_carrier_off(dev);
- return 0;
+ if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) {
+ napi_enable(&card->napi);
+ napi_schedule(&card->napi);
+ } else
+ rc = -EIO;
+ return rc;
}
-
static int qeth_l2_stop(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
QETH_CARD_TEXT(card, 4, "qethstop");
netif_tx_disable(dev);
- if (card->state == CARD_STATE_UP)
+ if (card->state == CARD_STATE_UP) {
card->state = CARD_STATE_SOFTSETUP;
+ napi_disable(&card->napi);
+ }
return 0;
}
@@ -836,8 +879,9 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
INIT_LIST_HEAD(&card->vid_list);
INIT_LIST_HEAD(&card->mc_list);
card->options.layer2 = 1;
+ card->discipline.start_poll = qeth_qdio_start_poll;
card->discipline.input_handler = (qdio_handler_t *)
- qeth_l2_qdio_input_handler;
+ qeth_qdio_input_handler;
card->discipline.output_handler = (qdio_handler_t *)
qeth_qdio_output_handler;
card->discipline.recover = qeth_l2_recover;
@@ -923,6 +967,7 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
card->info.broadcast_capable = 1;
qeth_l2_request_initial_mac(card);
SET_NETDEV_DEV(card->dev, &card->gdev->dev);
+ netif_napi_add(card->dev, &card->napi, qeth_l2_poll, QETH_NAPI_WEIGHT);
return register_netdev(card->dev);
}
@@ -955,6 +1000,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
qeth_l2_send_setmac(card, &card->dev->dev_addr[0]);
card->state = CARD_STATE_HARDSETUP;
+ memset(&card->rx, 0, sizeof(struct qeth_rx));
qeth_print_status_message(card);
/* softsetup */
@@ -1086,9 +1132,6 @@ static int qeth_l2_recover(void *ptr)
card->use_hard_stop = 1;
__qeth_l2_set_offline(card->gdev, 1);
rc = __qeth_l2_set_online(card->gdev, 1);
- /* don't run another scheduled recovery */
- qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
- qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
if (!rc)
dev_info(&card->gdev->dev,
"Device successfully recovered!\n");
@@ -1099,6 +1142,8 @@ static int qeth_l2_recover(void *ptr)
dev_warn(&card->gdev->dev, "The qeth device driver "
"failed to recover an error on the device\n");
}
+ qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
+ qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
return 0;
}
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index e22ae248f613..74d1401a5d5e 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -103,12 +103,7 @@ int qeth_l3_string_to_ipaddr4(const char *buf, __u8 *addr)
void qeth_l3_ipaddr6_to_string(const __u8 *addr, char *buf)
{
- sprintf(buf, "%02x%02x:%02x%02x:%02x%02x:%02x%02x"
- ":%02x%02x:%02x%02x:%02x%02x:%02x%02x",
- addr[0], addr[1], addr[2], addr[3],
- addr[4], addr[5], addr[6], addr[7],
- addr[8], addr[9], addr[10], addr[11],
- addr[12], addr[13], addr[14], addr[15]);
+ sprintf(buf, "%pI6", addr);
}
int qeth_l3_string_to_ipaddr6(const char *buf, __u8 *addr)
@@ -1825,7 +1820,7 @@ static void qeth_l3_add_vlan_mc(struct qeth_card *card)
return;
vg = card->vlangrp;
- for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ for (i = 0; i < VLAN_N_VID; i++) {
struct net_device *netdev = vlan_group_get_device(vg, i);
if (netdev == NULL ||
!(netdev->flags & IFF_UP))
@@ -1888,7 +1883,7 @@ static void qeth_l3_add_vlan_mc6(struct qeth_card *card)
return;
vg = card->vlangrp;
- for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ for (i = 0; i < VLAN_N_VID; i++) {
struct net_device *netdev = vlan_group_get_device(vg, i);
if (netdev == NULL ||
!(netdev->flags & IFF_UP))
@@ -2018,13 +2013,14 @@ static void qeth_l3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
qeth_l3_set_multicast_list(card->dev);
}
-static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card,
- struct sk_buff *skb, struct qeth_hdr *hdr)
+static inline int qeth_l3_rebuild_skb(struct qeth_card *card,
+ struct sk_buff *skb, struct qeth_hdr *hdr,
+ unsigned short *vlan_id)
{
- unsigned short vlan_id = 0;
__be16 prot;
struct iphdr *ip_hdr;
unsigned char tg_addr[MAX_ADDR_LEN];
+ int is_vlan = 0;
if (!(hdr->hdr.l3.flags & QETH_HDR_PASSTHRU)) {
prot = htons((hdr->hdr.l3.flags & QETH_HDR_IPV6)? ETH_P_IPV6 :
@@ -2087,8 +2083,9 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card,
if (hdr->hdr.l3.ext_flags &
(QETH_HDR_EXT_VLAN_FRAME | QETH_HDR_EXT_INCLUDE_VLAN_TAG)) {
- vlan_id = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME)?
+ *vlan_id = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME) ?
hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]);
+ is_vlan = 1;
}
switch (card->options.checksum_type) {
@@ -2109,54 +2106,44 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card,
skb->ip_summed = CHECKSUM_NONE;
}
- return vlan_id;
+ return is_vlan;
}
-static void qeth_l3_process_inbound_buffer(struct qeth_card *card,
- struct qeth_qdio_buffer *buf, int index)
+static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
+ int budget, int *done)
{
- struct qdio_buffer_element *element;
+ int work_done = 0;
struct sk_buff *skb;
struct qeth_hdr *hdr;
- int offset;
__u16 vlan_tag = 0;
+ int is_vlan;
unsigned int len;
- /* get first element of current buffer */
- element = (struct qdio_buffer_element *)&buf->buffer->element[0];
- offset = 0;
- if (card->options.performance_stats)
- card->perf_stats.bufs_rec++;
- while ((skb = qeth_core_get_next_skb(card, buf->buffer, &element,
- &offset, &hdr))) {
- skb->dev = card->dev;
- /* is device UP ? */
- if (!(card->dev->flags & IFF_UP)) {
- dev_kfree_skb_any(skb);
- continue;
- }
+ *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->rx.b_element, &card->rx.e_offset, &hdr);
+ if (!skb) {
+ *done = 1;
+ break;
+ }
+ skb->dev = card->dev;
switch (hdr->hdr.l3.id) {
case QETH_HEADER_TYPE_LAYER3:
- vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr);
+ is_vlan = qeth_l3_rebuild_skb(card, skb, hdr,
+ &vlan_tag);
len = skb->len;
- if (vlan_tag && !card->options.sniffer)
- if (card->vlangrp)
- vlan_hwaccel_rx(skb, card->vlangrp,
- vlan_tag);
- else {
- dev_kfree_skb_any(skb);
- continue;
- }
+ if (is_vlan && !card->options.sniffer)
+ vlan_gro_receive(&card->napi, card->vlangrp,
+ vlan_tag, skb);
else
- netif_rx(skb);
+ napi_gro_receive(&card->napi, skb);
break;
case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */
skb->pkt_type = PACKET_HOST;
skb->protocol = eth_type_trans(skb, skb->dev);
- if (card->options.checksum_type == NO_CHECKSUMMING)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- else
- skb->ip_summed = CHECKSUM_NONE;
len = skb->len;
netif_receive_skb(skb);
break;
@@ -2166,10 +2153,87 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card,
QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN);
continue;
}
-
+ work_done++;
+ budget--;
card->stats.rx_packets++;
card->stats.rx_bytes += len;
}
+ return work_done;
+}
+
+static int qeth_l3_poll(struct napi_struct *napi, int budget)
+{
+ struct qeth_card *card = container_of(napi, struct qeth_card, napi);
+ int work_done = 0;
+ struct qeth_qdio_buffer *buffer;
+ int done;
+ int new_budget = budget;
+
+ if (card->options.performance_stats) {
+ card->perf_stats.inbound_cnt++;
+ card->perf_stats.inbound_start_time = qeth_get_micros();
+ }
+
+ while (1) {
+ if (!card->rx.b_count) {
+ card->rx.qdio_err = 0;
+ card->rx.b_count = qdio_get_next_buffers(
+ card->data.ccwdev, 0, &card->rx.b_index,
+ &card->rx.qdio_err);
+ if (card->rx.b_count <= 0) {
+ card->rx.b_count = 0;
+ break;
+ }
+ card->rx.b_element =
+ &card->qdio.in_q->bufs[card->rx.b_index]
+ .buffer->element[0];
+ card->rx.e_offset = 0;
+ }
+
+ while (card->rx.b_count) {
+ buffer = &card->qdio.in_q->bufs[card->rx.b_index];
+ if (!(card->rx.qdio_err &&
+ qeth_check_qdio_errors(card, buffer->buffer,
+ card->rx.qdio_err, "qinerr")))
+ work_done += qeth_l3_process_inbound_buffer(
+ card, new_budget, &done);
+ else
+ done = 1;
+
+ if (done) {
+ if (card->options.performance_stats)
+ card->perf_stats.bufs_rec++;
+ qeth_put_buffer_pool_entry(card,
+ buffer->pool_entry);
+ qeth_queue_input_buffer(card, card->rx.b_index);
+ card->rx.b_count--;
+ if (card->rx.b_count) {
+ card->rx.b_index =
+ (card->rx.b_index + 1) %
+ QDIO_MAX_BUFFERS_PER_Q;
+ card->rx.b_element =
+ &card->qdio.in_q
+ ->bufs[card->rx.b_index]
+ .buffer->element[0];
+ card->rx.e_offset = 0;
+ }
+ }
+
+ if (work_done >= budget)
+ goto out;
+ else
+ new_budget = budget - work_done;
+ }
+ }
+
+ napi_complete(napi);
+ if (qdio_start_irq(card->data.ccwdev, 0))
+ napi_schedule(&card->napi);
+out:
+ if (card->options.performance_stats)
+ card->perf_stats.inbound_time += qeth_get_micros() -
+ card->perf_stats.inbound_start_time;
+ return work_done;
}
static int qeth_l3_verify_vlan_dev(struct net_device *dev,
@@ -2183,7 +2247,7 @@ static int qeth_l3_verify_vlan_dev(struct net_device *dev,
if (!vg)
return rc;
- for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ for (i = 0; i < VLAN_N_VID; i++) {
if (vlan_group_get_device(vg, i) == dev) {
rc = QETH_VLAN_CARD;
break;
@@ -3103,6 +3167,7 @@ tx_drop:
static int qeth_l3_open(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
+ int rc = 0;
QETH_CARD_TEXT(card, 4, "qethopen");
if (card->state != CARD_STATE_SOFTSETUP)
@@ -3113,7 +3178,12 @@ static int qeth_l3_open(struct net_device *dev)
if (!card->lan_online && netif_carrier_ok(dev))
netif_carrier_off(dev);
- return 0;
+ if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) {
+ napi_enable(&card->napi);
+ napi_schedule(&card->napi);
+ } else
+ rc = -EIO;
+ return rc;
}
static int qeth_l3_stop(struct net_device *dev)
@@ -3122,8 +3192,10 @@ static int qeth_l3_stop(struct net_device *dev)
QETH_CARD_TEXT(card, 4, "qethstop");
netif_tx_disable(dev);
- if (card->state == CARD_STATE_UP)
+ if (card->state == CARD_STATE_UP) {
card->state = CARD_STATE_SOFTSETUP;
+ napi_disable(&card->napi);
+ }
return 0;
}
@@ -3293,57 +3365,19 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
card->dev->gso_max_size = 15 * PAGE_SIZE;
SET_NETDEV_DEV(card->dev, &card->gdev->dev);
+ netif_napi_add(card->dev, &card->napi, qeth_l3_poll, QETH_NAPI_WEIGHT);
return register_netdev(card->dev);
}
-static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev,
- unsigned int qdio_err, unsigned int queue, int first_element,
- int count, unsigned long card_ptr)
-{
- struct net_device *net_dev;
- struct qeth_card *card;
- struct qeth_qdio_buffer *buffer;
- int index;
- int i;
-
- card = (struct qeth_card *) card_ptr;
- net_dev = card->dev;
- if (card->options.performance_stats) {
- card->perf_stats.inbound_cnt++;
- card->perf_stats.inbound_start_time = qeth_get_micros();
- }
- if (qdio_err & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) {
- QETH_CARD_TEXT(card, 1, "qdinchk");
- QETH_CARD_TEXT_(card, 1, "%04X%04X",
- first_element, count);
- QETH_CARD_TEXT_(card, 1, "%04X", queue);
- qeth_schedule_recovery(card);
- return;
- }
- for (i = first_element; i < (first_element + count); ++i) {
- index = i % QDIO_MAX_BUFFERS_PER_Q;
- buffer = &card->qdio.in_q->bufs[index];
- if (!(qdio_err &&
- qeth_check_qdio_errors(card, buffer->buffer,
- qdio_err, "qinerr")))
- qeth_l3_process_inbound_buffer(card, buffer, index);
- /* clear buffer and give back to hardware */
- qeth_put_buffer_pool_entry(card, buffer->pool_entry);
- qeth_queue_input_buffer(card, index);
- }
- if (card->options.performance_stats)
- card->perf_stats.inbound_time += qeth_get_micros() -
- card->perf_stats.inbound_start_time;
-}
-
static int qeth_l3_probe_device(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
qeth_l3_create_device_attributes(&gdev->dev);
card->options.layer2 = 0;
+ card->discipline.start_poll = qeth_qdio_start_poll;
card->discipline.input_handler = (qdio_handler_t *)
- qeth_l3_qdio_input_handler;
+ qeth_qdio_input_handler;
card->discipline.output_handler = (qdio_handler_t *)
qeth_qdio_output_handler;
card->discipline.recover = qeth_l3_recover;
@@ -3402,6 +3436,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
}
card->state = CARD_STATE_HARDSETUP;
+ memset(&card->rx, 0, sizeof(struct qeth_rx));
qeth_print_status_message(card);
/* softsetup */
@@ -3538,9 +3573,6 @@ static int qeth_l3_recover(void *ptr)
card->use_hard_stop = 1;
__qeth_l3_set_offline(card->gdev, 1);
rc = __qeth_l3_set_online(card->gdev, 1);
- /* don't run another scheduled recovery */
- qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
- qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
if (!rc)
dev_info(&card->gdev->dev,
"Device successfully recovered!\n");
@@ -3551,6 +3583,8 @@ static int qeth_l3_recover(void *ptr)
dev_warn(&card->gdev->dev, "The qeth device driver "
"failed to recover an error on the device\n");
}
+ qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
+ qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
return 0;
}
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index 60e6e5714eb9..a0554beb4179 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -279,16 +279,12 @@ int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
struct zfcp_qdio *qdio)
{
-
+ memset(id, 0, sizeof(*id));
id->cdev = qdio->adapter->ccw_device;
id->q_format = QDIO_ZFCP_QFMT;
memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8);
ASCEBC(id->adapter_name, 8);
id->qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV;
- id->qib_param_field_format = 0;
- id->qib_param_field = NULL;
- id->input_slib_elements = NULL;
- id->output_slib_elements = NULL;
id->no_input_qs = 1;
id->no_output_qs = 1;
id->input_handler = zfcp_qdio_int_resp;
diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
index 13f48e28a1e1..a624f5af4320 100644
--- a/drivers/sbus/char/jsflash.c
+++ b/drivers/sbus/char/jsflash.c
@@ -461,7 +461,7 @@ static int jsflash_init(void)
{
int rc;
struct jsflash *jsf;
- int node;
+ phandle node;
char banner[128];
struct linux_prom_registers reg0;
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 2e9632e2c98b..8616496ffc02 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -116,7 +116,7 @@ config CHR_DEV_OSST
<http://www.tldp.org/docs.html#howto> and
<file:Documentation/scsi/osst.txt> in the kernel source.
More info on the OnStream driver may be found on
- <http://linux1.onstream.nl/test/>
+ <http://sourceforge.net/projects/osst/>
Please also have a look at the standard st docu, as most of it
applies to osst as well.
@@ -156,9 +156,9 @@ config CHR_DEV_SG
directly, so you need some additional software which knows how to
talk to these devices using the SCSI protocol:
- For scanners, look at SANE (<http://www.mostang.com/sane/>). For CD
+ For scanners, look at SANE (<http://www.sane-project.org/>). For CD
writer software look at Cdrtools
- (<http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/cdrecord.html>)
+ (<http://cdrecord.berlios.de/private/cdrecord.html>)
and for burning a "disk at once": CDRDAO
(<http://cdrdao.sourceforge.net/>). Cdparanoia is a high
quality digital reader of audio CDs (<http://www.xiph.org/paranoia/>).
@@ -951,6 +951,7 @@ config SCSI_IPS
---help---
This is support for the IBM ServeRAID hardware RAID controllers.
See <http://www.developer.ibm.com/welcome/netfinity/serveraid.html>
+ and <http://www-947.ibm.com/support/entry/portal/docdisplay?brand=5000008&lndocid=SERV-RAID>
for more information. If this driver does not work correctly
without modification please contact the author by email at
<ipslinux@adaptec.com>.
@@ -1610,7 +1611,7 @@ config SCSI_DEBUG
host adapter with one dummy SCSI disk. Each dummy disk uses kernel
RAM as storage (i.e. it is a ramdisk). To save space when multiple
dummy disks are simulated, they share the same kernel RAM for
- their storage. See <http://www.torque.net/sg/sdebug.html> for more
+ their storage. See <http://sg.danny.cz/sg/sdebug26.html> for more
information. This driver is primarily of use to those testing the
SCSI and block subsystems. If unsure, say N.
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index dae46d779c7b..29c0ed1cf507 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -771,7 +771,7 @@ static long aac_compat_cfg_ioctl(struct file *file, unsigned cmd, unsigned long
{
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
- return aac_compat_do_ioctl((struct aac_dev *)file->private_data, cmd, arg);
+ return aac_compat_do_ioctl(file->private_data, cmd, arg);
}
#endif
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
index 2fceb19eb27b..1b6f86b2482d 100644
--- a/drivers/scsi/bnx2i/57xx_iscsi_constants.h
+++ b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
@@ -120,6 +120,8 @@
/* additional LOM specific iSCSI license not installed */
#define ISCSI_KCQE_COMPLETION_STATUS_LOM_ISCSI_NOT_ENABLED (0x51)
+#define ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY (0x80)
+
/* SQ/RQ/CQ DB structure sizes */
#define ISCSI_SQ_DB_SIZE (16)
#define ISCSI_RQ_DB_SIZE (16)
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index b6345d91bb66..a44b1b33fa18 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -58,6 +58,8 @@
#define MAX_PAGES_PER_CTRL_STRUCT_POOL 8
#define BNX2I_RESERVED_SLOW_PATH_CMD_SLOTS 4
+#define BNX2I_5771X_DBELL_PAGE_SIZE 128
+
/* 5706/08 hardware has limit on maximum buffer size per BD it can handle */
#define MAX_BD_LENGTH 65535
#define BD_SPLIT_SIZE 32768
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index 90cef716b796..8d9dbb33972f 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -2406,7 +2406,8 @@ int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)
if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
reg_base = pci_resource_start(ep->hba->pcidev,
BNX2X_DOORBELL_PCI_BAR);
- reg_off = PAGE_SIZE * (cid_num & 0x1FFFF) + DPM_TRIGER_TYPE;
+ reg_off = BNX2I_5771X_DBELL_PAGE_SIZE * (cid_num & 0x1FFFF) +
+ DPM_TRIGER_TYPE;
ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off, 4);
goto arm_cq;
}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index c3d7174e3469..a345dde16c86 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -5509,7 +5509,7 @@ lpfc_get_rec_conf23(uint8_t *buff, uint32_t size, uint8_t rec_type)
* @buff: Buffer containing config region 23 data.
* @size: Size of the data buffer.
*
- * This fuction parse the FCoE config parameters in config region 23 and
+ * This function parses the FCoE config parameters in config region 23 and
* populate driver data structure with the parameters.
*/
void
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 5428d53f5a13..909ed9ed24c0 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -212,7 +212,7 @@ static void sg_put_dev(Sg_device *sdp);
static int sg_allow_access(struct file *filp, unsigned char *cmd)
{
- struct sg_fd *sfp = (struct sg_fd *)filp->private_data;
+ struct sg_fd *sfp = filp->private_data;
if (sfp->parentdp->device->type == TYPE_SCANNER)
return 0;
diff --git a/drivers/serial/68328serial.h b/drivers/serial/68328serial.h
index 58aa2154655b..664ceb0a158c 100644
--- a/drivers/serial/68328serial.h
+++ b/drivers/serial/68328serial.h
@@ -181,13 +181,8 @@ struct m68k_serial {
/*
* Define the number of ports supported and their irqs.
*/
-#ifndef CONFIG_68328_SERIAL_UART2
#define NR_PORTS 1
#define UART_IRQ_DEFNS {UART_IRQ_NUM}
-#else
-#define NR_PORTS 2
-#define UART_IRQ_DEFNS {UART1_IRQ_NUM, UART2_IRQ_NUM}
-#endif
#endif /* __KERNEL__ */
#endif /* !(_MC683XX_SERIAL_H) */
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 167c4a6ccbc3..4d8e14b7aa93 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -919,7 +919,7 @@ static int broken_efr(struct uart_8250_port *up)
/*
* Exar ST16C2550 "A2" devices incorrectly detect as
* having an EFR, and report an ID of 0x0201. See
- * http://www.exar.com/info.php?pdf=dan180_oct2004.pdf
+ * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html
*/
if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16)
return 1;
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 927816484397..aff9dcd051c6 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1410,6 +1410,33 @@ config SERIAL_OF_PLATFORM
Currently, only 8250 compatible ports are supported, but
others can easily be added.
+config SERIAL_OMAP
+ tristate "OMAP serial port support"
+ depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4
+ select SERIAL_CORE
+ help
+ If you have a machine based on an Texas Instruments OMAP CPU you
+ can enable its onboard serial ports by enabling this option.
+
+ By enabling this option you take advantage of dma feature available
+ with the omap-serial driver. DMA support can be enabled from platform
+ data.
+
+config SERIAL_OMAP_CONSOLE
+ bool "Console on OMAP serial port"
+ depends on SERIAL_OMAP
+ select SERIAL_CORE_CONSOLE
+ help
+ Select this option if you would like to use omap serial port as
+ console.
+
+ 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=ttyOx". (Try "man bootparam" or see the documentation of
+ your boot loader about how to pass options to the kernel at
+ boot time.)
+
config SERIAL_OF_PLATFORM_NWPSERIAL
tristate "NWP serial port driver"
depends on PPC_OF && PPC_DCR
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 1ca4fd599ffe..c5705765454f 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -88,3 +88,4 @@ obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o
obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
+obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c
index 6f1b51e231e4..e95c524d9d18 100644
--- a/drivers/serial/bfin_sport_uart.c
+++ b/drivers/serial/bfin_sport_uart.c
@@ -10,7 +10,7 @@
/*
* This driver and the hardware supported are in term of EE-191 of ADI.
- * http://www.analog.com/UploadedFiles/Application_Notes/399447663EE191.pdf
+ * http://www.analog.com/static/imported-files/application_notes/EE191.pdf
* This application note describe how to implement a UART on a Sharc DSP,
* but this driver is implemented on Blackfin Processor.
* Transmit Frame Sync is not used by this driver to transfer data out.
diff --git a/drivers/serial/bfin_sport_uart.h b/drivers/serial/bfin_sport_uart.h
index 9ce253e381d2..6d06ce1d5675 100644
--- a/drivers/serial/bfin_sport_uart.h
+++ b/drivers/serial/bfin_sport_uart.h
@@ -10,7 +10,7 @@
/*
* This driver and the hardware supported are in term of EE-191 of ADI.
- * http://www.analog.com/UploadedFiles/Application_Notes/399447663EE191.pdf
+ * http://www.analog.com/static/imported-files/application_notes/EE191.pdf
* This application note describe how to implement a UART on a Sharc DSP,
* but this driver is implemented on Blackfin Processor.
* Transmit Frame Sync is not used by this driver to transfer data out.
diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c
index 2af8fd113123..17849dcb9adc 100644
--- a/drivers/serial/of_serial.c
+++ b/drivers/serial/of_serial.c
@@ -31,8 +31,8 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
{
struct resource resource;
struct device_node *np = ofdev->dev.of_node;
- const unsigned int *clk, *spd;
- const u32 *prop;
+ const __be32 *clk, *spd;
+ const __be32 *prop;
int ret, prop_size;
memset(port, 0, sizeof *port);
@@ -55,23 +55,23 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
/* Check for shifted address mapping */
prop = of_get_property(np, "reg-offset", &prop_size);
if (prop && (prop_size == sizeof(u32)))
- port->mapbase += *prop;
+ port->mapbase += be32_to_cpup(prop);
/* Check for registers offset within the devices address range */
prop = of_get_property(np, "reg-shift", &prop_size);
if (prop && (prop_size == sizeof(u32)))
- port->regshift = *prop;
+ port->regshift = be32_to_cpup(prop);
port->irq = irq_of_parse_and_map(np, 0);
port->iotype = UPIO_MEM;
port->type = type;
- port->uartclk = *clk;
+ port->uartclk = be32_to_cpup(clk);
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
| UPF_FIXED_PORT | UPF_FIXED_TYPE;
port->dev = &ofdev->dev;
/* If current-speed was set, then try not to change it. */
if (spd)
- port->custom_divisor = *clk / (16 * (*spd));
+ port->custom_divisor = be32_to_cpup(clk) / (16 * (be32_to_cpup(spd)));
return 0;
}
diff --git a/drivers/serial/omap-serial.c b/drivers/serial/omap-serial.c
new file mode 100644
index 000000000000..14365f72b664
--- /dev/null
+++ b/drivers/serial/omap-serial.c
@@ -0,0 +1,1333 @@
+/*
+ * Driver for OMAP-UART controller.
+ * Based on drivers/serial/8250.c
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * Authors:
+ * Govindraj R <govindraj.raja@ti.com>
+ * Thara Gopinath <thara@ti.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.
+ *
+ * Note: This driver is made seperate from 8250 driver as we cannot
+ * over load 8250 driver with omap platform specific configuration for
+ * features like DMA, it makes easier to implement features like DMA and
+ * hardware flow control and software flow control configuration with
+ * this driver as required for the omap-platform.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/serial_core.h>
+#include <linux/irq.h>
+
+#include <plat/dma.h>
+#include <plat/dmtimer.h>
+#include <plat/omap-serial.h>
+
+static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
+
+/* Forward declaration of functions */
+static void uart_tx_dma_callback(int lch, u16 ch_status, void *data);
+static void serial_omap_rx_timeout(unsigned long uart_no);
+static int serial_omap_start_rxdma(struct uart_omap_port *up);
+
+static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
+{
+ offset <<= up->port.regshift;
+ return readw(up->port.membase + offset);
+}
+
+static inline void serial_out(struct uart_omap_port *up, int offset, int value)
+{
+ offset <<= up->port.regshift;
+ writew(value, up->port.membase + offset);
+}
+
+static inline void serial_omap_clear_fifos(struct uart_omap_port *up)
+{
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+ serial_out(up, UART_FCR, 0);
+}
+
+/*
+ * serial_omap_get_divisor - calculate divisor value
+ * @port: uart port info
+ * @baud: baudrate for which divisor needs to be calculated.
+ *
+ * We have written our own function to get the divisor so as to support
+ * 13x mode. 3Mbps Baudrate as an different divisor.
+ * Reference OMAP TRM Chapter 17:
+ * Table 17-1. UART Mode Baud Rates, Divisor Values, and Error Rates
+ * referring to oversampling - divisor value
+ * baudrate 460,800 to 3,686,400 all have divisor 13
+ * except 3,000,000 which has divisor value 16
+ */
+static unsigned int
+serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
+{
+ unsigned int divisor;
+
+ if (baud > OMAP_MODE13X_SPEED && baud != 3000000)
+ divisor = 13;
+ else
+ divisor = 16;
+ return port->uartclk/(baud * divisor);
+}
+
+static void serial_omap_stop_rxdma(struct uart_omap_port *up)
+{
+ if (up->uart_dma.rx_dma_used) {
+ del_timer(&up->uart_dma.rx_timer);
+ omap_stop_dma(up->uart_dma.rx_dma_channel);
+ omap_free_dma(up->uart_dma.rx_dma_channel);
+ up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
+ up->uart_dma.rx_dma_used = false;
+ }
+}
+
+static void serial_omap_enable_ms(struct uart_port *port)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+ dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->pdev->id);
+ up->ier |= UART_IER_MSI;
+ serial_out(up, UART_IER, up->ier);
+}
+
+static void serial_omap_stop_tx(struct uart_port *port)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+ if (up->use_dma &&
+ up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) {
+ /*
+ * Check if dma is still active. If yes do nothing,
+ * return. Else stop dma
+ */
+ if (omap_get_dma_active_status(up->uart_dma.tx_dma_channel))
+ return;
+ omap_stop_dma(up->uart_dma.tx_dma_channel);
+ omap_free_dma(up->uart_dma.tx_dma_channel);
+ up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
+ }
+
+ if (up->ier & UART_IER_THRI) {
+ up->ier &= ~UART_IER_THRI;
+ serial_out(up, UART_IER, up->ier);
+ }
+}
+
+static void serial_omap_stop_rx(struct uart_port *port)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+ if (up->use_dma)
+ serial_omap_stop_rxdma(up);
+ up->ier &= ~UART_IER_RLSI;
+ up->port.read_status_mask &= ~UART_LSR_DR;
+ serial_out(up, UART_IER, up->ier);
+}
+
+static inline void receive_chars(struct uart_omap_port *up, int *status)
+{
+ struct tty_struct *tty = up->port.state->port.tty;
+ unsigned int flag;
+ unsigned char ch, lsr = *status;
+ int max_count = 256;
+
+ do {
+ if (likely(lsr & UART_LSR_DR))
+ ch = serial_in(up, UART_RX);
+ flag = TTY_NORMAL;
+ up->port.icount.rx++;
+
+ if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
+ /*
+ * For statistics only
+ */
+ if (lsr & UART_LSR_BI) {
+ lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+ up->port.icount.brk++;
+ /*
+ * We do the SysRQ and SAK checking
+ * here because otherwise the break
+ * may get masked by ignore_status_mask
+ * or read_status_mask.
+ */
+ if (uart_handle_break(&up->port))
+ goto ignore_char;
+ } else if (lsr & UART_LSR_PE) {
+ up->port.icount.parity++;
+ } else if (lsr & UART_LSR_FE) {
+ up->port.icount.frame++;
+ }
+
+ if (lsr & UART_LSR_OE)
+ up->port.icount.overrun++;
+
+ /*
+ * Mask off conditions which should be ignored.
+ */
+ lsr &= up->port.read_status_mask;
+
+#ifdef CONFIG_SERIAL_OMAP_CONSOLE
+ if (up->port.line == up->port.cons->index) {
+ /* Recover the break flag from console xmit */
+ lsr |= up->lsr_break_flag;
+ up->lsr_break_flag = 0;
+ }
+#endif
+ if (lsr & UART_LSR_BI)
+ flag = TTY_BREAK;
+ else if (lsr & UART_LSR_PE)
+ flag = TTY_PARITY;
+ else if (lsr & UART_LSR_FE)
+ flag = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(&up->port, ch))
+ goto ignore_char;
+ uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
+ignore_char:
+ lsr = serial_in(up, UART_LSR);
+ } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
+ spin_unlock(&up->port.lock);
+ tty_flip_buffer_push(tty);
+ spin_lock(&up->port.lock);
+}
+
+static void transmit_chars(struct uart_omap_port *up)
+{
+ struct circ_buf *xmit = &up->port.state->xmit;
+ int count;
+
+ if (up->port.x_char) {
+ serial_out(up, UART_TX, up->port.x_char);
+ up->port.icount.tx++;
+ up->port.x_char = 0;
+ return;
+ }
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+ serial_omap_stop_tx(&up->port);
+ return;
+ }
+ count = up->port.fifosize / 4;
+ do {
+ serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ up->port.icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ } while (--count > 0);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&up->port);
+
+ if (uart_circ_empty(xmit))
+ serial_omap_stop_tx(&up->port);
+}
+
+static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
+{
+ if (!(up->ier & UART_IER_THRI)) {
+ up->ier |= UART_IER_THRI;
+ serial_out(up, UART_IER, up->ier);
+ }
+}
+
+static void serial_omap_start_tx(struct uart_port *port)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct circ_buf *xmit;
+ unsigned int start;
+ int ret = 0;
+
+ if (!up->use_dma) {
+ serial_omap_enable_ier_thri(up);
+ return;
+ }
+
+ if (up->uart_dma.tx_dma_used)
+ return;
+
+ xmit = &up->port.state->xmit;
+
+ if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) {
+ ret = omap_request_dma(up->uart_dma.uart_dma_tx,
+ "UART Tx DMA",
+ (void *)uart_tx_dma_callback, up,
+ &(up->uart_dma.tx_dma_channel));
+
+ if (ret < 0) {
+ serial_omap_enable_ier_thri(up);
+ return;
+ }
+ }
+ spin_lock(&(up->uart_dma.tx_lock));
+ up->uart_dma.tx_dma_used = true;
+ spin_unlock(&(up->uart_dma.tx_lock));
+
+ start = up->uart_dma.tx_buf_dma_phys +
+ (xmit->tail & (UART_XMIT_SIZE - 1));
+
+ up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
+ /*
+ * It is a circular buffer. See if the buffer has wounded back.
+ * If yes it will have to be transferred in two separate dma
+ * transfers
+ */
+ if (start + up->uart_dma.tx_buf_size >=
+ up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
+ up->uart_dma.tx_buf_size =
+ (up->uart_dma.tx_buf_dma_phys +
+ UART_XMIT_SIZE) - start;
+
+ omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
+ OMAP_DMA_AMODE_CONSTANT,
+ up->uart_dma.uart_base, 0, 0);
+ omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
+ OMAP_DMA_AMODE_POST_INC, start, 0, 0);
+ omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
+ OMAP_DMA_DATA_TYPE_S8,
+ up->uart_dma.tx_buf_size, 1,
+ OMAP_DMA_SYNC_ELEMENT,
+ up->uart_dma.uart_dma_tx, 0);
+ /* FIXME: Cache maintenance needed here? */
+ omap_start_dma(up->uart_dma.tx_dma_channel);
+}
+
+static unsigned int check_modem_status(struct uart_omap_port *up)
+{
+ unsigned int status;
+
+ status = serial_in(up, UART_MSR);
+ status |= up->msr_saved_flags;
+ up->msr_saved_flags = 0;
+ if ((status & UART_MSR_ANY_DELTA) == 0)
+ return status;
+
+ if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
+ up->port.state != NULL) {
+ if (status & UART_MSR_TERI)
+ up->port.icount.rng++;
+ if (status & UART_MSR_DDSR)
+ up->port.icount.dsr++;
+ if (status & UART_MSR_DDCD)
+ uart_handle_dcd_change
+ (&up->port, status & UART_MSR_DCD);
+ if (status & UART_MSR_DCTS)
+ uart_handle_cts_change
+ (&up->port, status & UART_MSR_CTS);
+ wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+ }
+
+ return status;
+}
+
+/**
+ * serial_omap_irq() - This handles the interrupt from one port
+ * @irq: uart port irq number
+ * @dev_id: uart port info
+ */
+static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
+{
+ struct uart_omap_port *up = dev_id;
+ unsigned int iir, lsr;
+ unsigned long flags;
+
+ iir = serial_in(up, UART_IIR);
+ if (iir & UART_IIR_NO_INT)
+ return IRQ_NONE;
+
+ spin_lock_irqsave(&up->port.lock, flags);
+ lsr = serial_in(up, UART_LSR);
+ if (iir & UART_IIR_RLSI) {
+ if (!up->use_dma) {
+ if (lsr & UART_LSR_DR)
+ receive_chars(up, &lsr);
+ } else {
+ up->ier &= ~(UART_IER_RDI | UART_IER_RLSI);
+ serial_out(up, UART_IER, up->ier);
+ if ((serial_omap_start_rxdma(up) != 0) &&
+ (lsr & UART_LSR_DR))
+ receive_chars(up, &lsr);
+ }
+ }
+
+ check_modem_status(up);
+ if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI))
+ transmit_chars(up);
+
+ spin_unlock_irqrestore(&up->port.lock, flags);
+ up->port_activity = jiffies;
+ return IRQ_HANDLED;
+}
+
+static unsigned int serial_omap_tx_empty(struct uart_port *port)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+ unsigned long flags = 0;
+ unsigned int ret = 0;
+
+ dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id);
+ spin_lock_irqsave(&up->port.lock, flags);
+ ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
+ return ret;
+}
+
+static unsigned int serial_omap_get_mctrl(struct uart_port *port)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+ unsigned char status;
+ unsigned int ret = 0;
+
+ status = check_modem_status(up);
+ dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id);
+
+ if (status & UART_MSR_DCD)
+ ret |= TIOCM_CAR;
+ if (status & UART_MSR_RI)
+ ret |= TIOCM_RNG;
+ if (status & UART_MSR_DSR)
+ ret |= TIOCM_DSR;
+ if (status & UART_MSR_CTS)
+ ret |= TIOCM_CTS;
+ return ret;
+}
+
+static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+ unsigned char mcr = 0;
+
+ dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->pdev->id);
+ if (mctrl & TIOCM_RTS)
+ mcr |= UART_MCR_RTS;
+ if (mctrl & TIOCM_DTR)
+ mcr |= UART_MCR_DTR;
+ if (mctrl & TIOCM_OUT1)
+ mcr |= UART_MCR_OUT1;
+ if (mctrl & TIOCM_OUT2)
+ mcr |= UART_MCR_OUT2;
+ if (mctrl & TIOCM_LOOP)
+ mcr |= UART_MCR_LOOP;
+
+ mcr |= up->mcr;
+ serial_out(up, UART_MCR, mcr);
+}
+
+static void serial_omap_break_ctl(struct uart_port *port, int break_state)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+ unsigned long flags = 0;
+
+ dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id);
+ spin_lock_irqsave(&up->port.lock, flags);
+ if (break_state == -1)
+ up->lcr |= UART_LCR_SBC;
+ else
+ up->lcr &= ~UART_LCR_SBC;
+ serial_out(up, UART_LCR, up->lcr);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static int serial_omap_startup(struct uart_port *port)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+ unsigned long flags = 0;
+ int retval;
+
+ /*
+ * Allocate the IRQ
+ */
+ retval = request_irq(up->port.irq, serial_omap_irq, up->port.irqflags,
+ up->name, up);
+ if (retval)
+ return retval;
+
+ dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id);
+
+ /*
+ * Clear the FIFO buffers and disable them.
+ * (they will be reenabled in set_termios())
+ */
+ serial_omap_clear_fifos(up);
+ /* For Hardware flow control */
+ serial_out(up, UART_MCR, UART_MCR_RTS);
+
+ /*
+ * Clear the interrupt registers.
+ */
+ (void) serial_in(up, UART_LSR);
+ if (serial_in(up, UART_LSR) & UART_LSR_DR)
+ (void) serial_in(up, UART_RX);
+ (void) serial_in(up, UART_IIR);
+ (void) serial_in(up, UART_MSR);
+
+ /*
+ * Now, initialize the UART
+ */
+ serial_out(up, UART_LCR, UART_LCR_WLEN8);
+ spin_lock_irqsave(&up->port.lock, flags);
+ /*
+ * Most PC uarts need OUT2 raised to enable interrupts.
+ */
+ up->port.mctrl |= TIOCM_OUT2;
+ serial_omap_set_mctrl(&up->port, up->port.mctrl);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
+ up->msr_saved_flags = 0;
+ if (up->use_dma) {
+ free_page((unsigned long)up->port.state->xmit.buf);
+ up->port.state->xmit.buf = dma_alloc_coherent(NULL,
+ UART_XMIT_SIZE,
+ (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys),
+ 0);
+ init_timer(&(up->uart_dma.rx_timer));
+ up->uart_dma.rx_timer.function = serial_omap_rx_timeout;
+ up->uart_dma.rx_timer.data = up->pdev->id;
+ /* Currently the buffer size is 4KB. Can increase it */
+ up->uart_dma.rx_buf = dma_alloc_coherent(NULL,
+ up->uart_dma.rx_buf_size,
+ (dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0);
+ }
+ /*
+ * Finally, enable interrupts. Note: Modem status interrupts
+ * are set via set_termios(), which will be occurring imminently
+ * anyway, so we don't enable them here.
+ */
+ up->ier = UART_IER_RLSI | UART_IER_RDI;
+ serial_out(up, UART_IER, up->ier);
+
+ up->port_activity = jiffies;
+ return 0;
+}
+
+static void serial_omap_shutdown(struct uart_port *port)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+ unsigned long flags = 0;
+
+ dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id);
+ /*
+ * Disable interrupts from this port
+ */
+ up->ier = 0;
+ serial_out(up, UART_IER, 0);
+
+ spin_lock_irqsave(&up->port.lock, flags);
+ up->port.mctrl &= ~TIOCM_OUT2;
+ serial_omap_set_mctrl(&up->port, up->port.mctrl);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
+ /*
+ * Disable break condition and FIFOs
+ */
+ serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
+ serial_omap_clear_fifos(up);
+
+ /*
+ * Read data port to reset things, and then free the irq
+ */
+ if (serial_in(up, UART_LSR) & UART_LSR_DR)
+ (void) serial_in(up, UART_RX);
+ if (up->use_dma) {
+ dma_free_coherent(up->port.dev,
+ UART_XMIT_SIZE, up->port.state->xmit.buf,
+ up->uart_dma.tx_buf_dma_phys);
+ up->port.state->xmit.buf = NULL;
+ serial_omap_stop_rx(port);
+ dma_free_coherent(up->port.dev,
+ up->uart_dma.rx_buf_size, up->uart_dma.rx_buf,
+ up->uart_dma.rx_buf_dma_phys);
+ up->uart_dma.rx_buf = NULL;
+ }
+ free_irq(up->port.irq, up);
+}
+
+static inline void
+serial_omap_configure_xonxoff
+ (struct uart_omap_port *up, struct ktermios *termios)
+{
+ unsigned char efr = 0;
+
+ up->lcr = serial_in(up, UART_LCR);
+ serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+ up->efr = serial_in(up, UART_EFR);
+ serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB);
+
+ serial_out(up, UART_XON1, termios->c_cc[VSTART]);
+ serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
+
+ /* clear SW control mode bits */
+ efr = up->efr;
+ efr &= OMAP_UART_SW_CLR;
+
+ /*
+ * IXON Flag:
+ * Enable XON/XOFF flow control on output.
+ * Transmit XON1, XOFF1
+ */
+ if (termios->c_iflag & IXON)
+ efr |= OMAP_UART_SW_TX;
+
+ /*
+ * IXOFF Flag:
+ * Enable XON/XOFF flow control on input.
+ * Receiver compares XON1, XOFF1.
+ */
+ if (termios->c_iflag & IXOFF)
+ efr |= OMAP_UART_SW_RX;
+
+ serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+ serial_out(up, UART_LCR, UART_LCR_DLAB);
+
+ up->mcr = serial_in(up, UART_MCR);
+
+ /*
+ * IXANY Flag:
+ * Enable any character to restart output.
+ * Operation resumes after receiving any
+ * character after recognition of the XOFF character
+ */
+ if (termios->c_iflag & IXANY)
+ up->mcr |= UART_MCR_XONANY;
+
+ serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+ serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+ serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
+ /* Enable special char function UARTi.EFR_REG[5] and
+ * load the new software flow control mode IXON or IXOFF
+ * and restore the UARTi.EFR_REG[4] ENHANCED_EN value.
+ */
+ serial_out(up, UART_EFR, efr | UART_EFR_SCD);
+ serial_out(up, UART_LCR, UART_LCR_DLAB);
+
+ serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR);
+ serial_out(up, UART_LCR, up->lcr);
+}
+
+static void
+serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+ unsigned char cval = 0;
+ unsigned char efr = 0;
+ unsigned long flags = 0;
+ unsigned int baud, quot;
+
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ cval = UART_LCR_WLEN5;
+ break;
+ case CS6:
+ cval = UART_LCR_WLEN6;
+ break;
+ case CS7:
+ cval = UART_LCR_WLEN7;
+ break;
+ default:
+ case CS8:
+ cval = UART_LCR_WLEN8;
+ break;
+ }
+
+ if (termios->c_cflag & CSTOPB)
+ cval |= UART_LCR_STOP;
+ if (termios->c_cflag & PARENB)
+ cval |= UART_LCR_PARITY;
+ if (!(termios->c_cflag & PARODD))
+ cval |= UART_LCR_EPAR;
+
+ /*
+ * Ask the core to calculate the divisor for us.
+ */
+
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13);
+ quot = serial_omap_get_divisor(port, baud);
+
+ up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 |
+ UART_FCR_ENABLE_FIFO;
+ if (up->use_dma)
+ up->fcr |= UART_FCR_DMA_SELECT;
+
+ /*
+ * Ok, we're now changing the port state. Do it with
+ * interrupts disabled.
+ */
+ spin_lock_irqsave(&up->port.lock, flags);
+
+ /*
+ * Update the per-port timeout.
+ */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+ if (termios->c_iflag & INPCK)
+ up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ up->port.read_status_mask |= UART_LSR_BI;
+
+ /*
+ * Characters to ignore
+ */
+ up->port.ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+ if (termios->c_iflag & IGNBRK) {
+ up->port.ignore_status_mask |= UART_LSR_BI;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ up->port.ignore_status_mask |= UART_LSR_OE;
+ }
+
+ /*
+ * ignore all characters if CREAD is not set
+ */
+ if ((termios->c_cflag & CREAD) == 0)
+ up->port.ignore_status_mask |= UART_LSR_DR;
+
+ /*
+ * Modem status interrupts
+ */
+ up->ier &= ~UART_IER_MSI;
+ if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+ up->ier |= UART_IER_MSI;
+ serial_out(up, UART_IER, up->ier);
+ serial_out(up, UART_LCR, cval); /* reset DLAB */
+
+ /* FIFOs and DMA Settings */
+
+ /* FCR can be changed only when the
+ * baud clock is not running
+ * DLL_REG and DLH_REG set to 0.
+ */
+ serial_out(up, UART_LCR, UART_LCR_DLAB);
+ serial_out(up, UART_DLL, 0);
+ serial_out(up, UART_DLM, 0);
+ serial_out(up, UART_LCR, 0);
+
+ serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+
+ up->efr = serial_in(up, UART_EFR);
+ serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+ serial_out(up, UART_LCR, UART_LCR_DLAB);
+ up->mcr = serial_in(up, UART_MCR);
+ serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+ /* FIFO ENABLE, DMA MODE */
+ serial_out(up, UART_FCR, up->fcr);
+ serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+
+ if (up->use_dma) {
+ serial_out(up, UART_TI752_TLR, 0);
+ serial_out(up, UART_OMAP_SCR,
+ (UART_FCR_TRIGGER_4 | UART_FCR_TRIGGER_8));
+ }
+
+ serial_out(up, UART_EFR, up->efr);
+ serial_out(up, UART_LCR, UART_LCR_DLAB);
+ serial_out(up, UART_MCR, up->mcr);
+
+ /* Protocol, Baud Rate, and Interrupt Settings */
+
+ serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_DISABLE);
+ serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+
+ up->efr = serial_in(up, UART_EFR);
+ serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+ serial_out(up, UART_LCR, 0);
+ serial_out(up, UART_IER, 0);
+ serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+
+ serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
+ serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
+
+ serial_out(up, UART_LCR, 0);
+ serial_out(up, UART_IER, up->ier);
+ serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+
+ serial_out(up, UART_EFR, up->efr);
+ serial_out(up, UART_LCR, cval);
+
+ if (baud > 230400 && baud != 3000000)
+ serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_MODE13X);
+ else
+ serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_MODE16X);
+
+ /* Hardware Flow Control Configuration */
+
+ if (termios->c_cflag & CRTSCTS) {
+ efr |= (UART_EFR_CTS | UART_EFR_RTS);
+ serial_out(up, UART_LCR, UART_LCR_DLAB);
+
+ up->mcr = serial_in(up, UART_MCR);
+ serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+
+ serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+ up->efr = serial_in(up, UART_EFR);
+ serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+ serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
+ serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */
+ serial_out(up, UART_LCR, UART_LCR_DLAB);
+ serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS);
+ serial_out(up, UART_LCR, cval);
+ }
+
+ 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);
+
+ spin_unlock_irqrestore(&up->port.lock, flags);
+ dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id);
+}
+
+static void
+serial_omap_pm(struct uart_port *port, unsigned int state,
+ unsigned int oldstate)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+ unsigned char efr;
+
+ dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id);
+ serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+ efr = serial_in(up, UART_EFR);
+ serial_out(up, UART_EFR, efr | UART_EFR_ECB);
+ serial_out(up, UART_LCR, 0);
+
+ serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
+ serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+ serial_out(up, UART_EFR, efr);
+ serial_out(up, UART_LCR, 0);
+ /* Enable module level wake up */
+ serial_out(up, UART_OMAP_WER,
+ (state != 0) ? OMAP_UART_WER_MOD_WKUP : 0);
+}
+
+static void serial_omap_release_port(struct uart_port *port)
+{
+ dev_dbg(port->dev, "serial_omap_release_port+\n");
+}
+
+static int serial_omap_request_port(struct uart_port *port)
+{
+ dev_dbg(port->dev, "serial_omap_request_port+\n");
+ return 0;
+}
+
+static void serial_omap_config_port(struct uart_port *port, int flags)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+ dev_dbg(up->port.dev, "serial_omap_config_port+%d\n",
+ up->pdev->id);
+ up->port.type = PORT_OMAP;
+}
+
+static int
+serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ /* we don't want the core code to modify any port params */
+ dev_dbg(port->dev, "serial_omap_verify_port+\n");
+ return -EINVAL;
+}
+
+static const char *
+serial_omap_type(struct uart_port *port)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+ dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->pdev->id);
+ return up->name;
+}
+
+#ifdef CONFIG_SERIAL_OMAP_CONSOLE
+
+static struct uart_omap_port *serial_omap_console_ports[4];
+
+static struct uart_driver serial_omap_reg;
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+static inline void wait_for_xmitr(struct uart_omap_port *up)
+{
+ unsigned int status, tmout = 10000;
+
+ /* Wait up to 10ms for the character(s) to be sent. */
+ do {
+ status = serial_in(up, UART_LSR);
+
+ if (status & UART_LSR_BI)
+ up->lsr_break_flag = UART_LSR_BI;
+
+ if (--tmout == 0)
+ break;
+ udelay(1);
+ } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+ /* Wait up to 1s for flow control if necessary */
+ if (up->port.flags & UPF_CONS_FLOW) {
+ tmout = 1000000;
+ for (tmout = 1000000; tmout; tmout--) {
+ unsigned int msr = serial_in(up, UART_MSR);
+
+ up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
+ if (msr & UART_MSR_CTS)
+ break;
+
+ udelay(1);
+ }
+ }
+}
+
+static void serial_omap_console_putchar(struct uart_port *port, int ch)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+ wait_for_xmitr(up);
+ serial_out(up, UART_TX, ch);
+}
+
+static void
+serial_omap_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_omap_port *up = serial_omap_console_ports[co->index];
+ unsigned long flags;
+ unsigned int ier;
+ int locked = 1;
+
+ local_irq_save(flags);
+ if (up->port.sysrq)
+ locked = 0;
+ else if (oops_in_progress)
+ locked = spin_trylock(&up->port.lock);
+ else
+ spin_lock(&up->port.lock);
+
+ /*
+ * First save the IER then disable the interrupts
+ */
+ ier = serial_in(up, UART_IER);
+ serial_out(up, UART_IER, 0);
+
+ uart_console_write(&up->port, s, count, serial_omap_console_putchar);
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore the IER
+ */
+ wait_for_xmitr(up);
+ serial_out(up, UART_IER, ier);
+ /*
+ * The receive handling will happen properly because the
+ * receive ready bit will still be set; it is not cleared
+ * on read. However, modem control will not, we must
+ * call it if we have saved something in the saved flags
+ * while processing with interrupts off.
+ */
+ if (up->msr_saved_flags)
+ check_modem_status(up);
+
+ if (locked)
+ spin_unlock(&up->port.lock);
+ local_irq_restore(flags);
+}
+
+static int __init
+serial_omap_console_setup(struct console *co, char *options)
+{
+ struct uart_omap_port *up;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (serial_omap_console_ports[co->index] == NULL)
+ return -ENODEV;
+ up = serial_omap_console_ports[co->index];
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(&up->port, co, baud, parity, bits, flow);
+}
+
+static struct console serial_omap_console = {
+ .name = OMAP_SERIAL_NAME,
+ .write = serial_omap_console_write,
+ .device = uart_console_device,
+ .setup = serial_omap_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &serial_omap_reg,
+};
+
+static void serial_omap_add_console_port(struct uart_omap_port *up)
+{
+ serial_omap_console_ports[up->pdev->id] = up;
+}
+
+#define OMAP_CONSOLE (&serial_omap_console)
+
+#else
+
+#define OMAP_CONSOLE NULL
+
+static inline void serial_omap_add_console_port(struct uart_omap_port *up)
+{}
+
+#endif
+
+static struct uart_ops serial_omap_pops = {
+ .tx_empty = serial_omap_tx_empty,
+ .set_mctrl = serial_omap_set_mctrl,
+ .get_mctrl = serial_omap_get_mctrl,
+ .stop_tx = serial_omap_stop_tx,
+ .start_tx = serial_omap_start_tx,
+ .stop_rx = serial_omap_stop_rx,
+ .enable_ms = serial_omap_enable_ms,
+ .break_ctl = serial_omap_break_ctl,
+ .startup = serial_omap_startup,
+ .shutdown = serial_omap_shutdown,
+ .set_termios = serial_omap_set_termios,
+ .pm = serial_omap_pm,
+ .type = serial_omap_type,
+ .release_port = serial_omap_release_port,
+ .request_port = serial_omap_request_port,
+ .config_port = serial_omap_config_port,
+ .verify_port = serial_omap_verify_port,
+};
+
+static struct uart_driver serial_omap_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "OMAP-SERIAL",
+ .dev_name = OMAP_SERIAL_NAME,
+ .nr = OMAP_MAX_HSUART_PORTS,
+ .cons = OMAP_CONSOLE,
+};
+
+static int
+serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct uart_omap_port *up = platform_get_drvdata(pdev);
+
+ if (up)
+ uart_suspend_port(&serial_omap_reg, &up->port);
+ return 0;
+}
+
+static int serial_omap_resume(struct platform_device *dev)
+{
+ struct uart_omap_port *up = platform_get_drvdata(dev);
+
+ if (up)
+ uart_resume_port(&serial_omap_reg, &up->port);
+ return 0;
+}
+
+static void serial_omap_rx_timeout(unsigned long uart_no)
+{
+ struct uart_omap_port *up = ui[uart_no];
+ unsigned int curr_dma_pos, curr_transmitted_size;
+ int ret = 0;
+
+ curr_dma_pos = omap_get_dma_dst_pos(up->uart_dma.rx_dma_channel);
+ if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) ||
+ (curr_dma_pos == 0)) {
+ if (jiffies_to_msecs(jiffies - up->port_activity) <
+ RX_TIMEOUT) {
+ mod_timer(&up->uart_dma.rx_timer, jiffies +
+ usecs_to_jiffies(up->uart_dma.rx_timeout));
+ } else {
+ serial_omap_stop_rxdma(up);
+ up->ier |= (UART_IER_RDI | UART_IER_RLSI);
+ serial_out(up, UART_IER, up->ier);
+ }
+ return;
+ }
+
+ curr_transmitted_size = curr_dma_pos -
+ up->uart_dma.prev_rx_dma_pos;
+ up->port.icount.rx += curr_transmitted_size;
+ tty_insert_flip_string(up->port.state->port.tty,
+ up->uart_dma.rx_buf +
+ (up->uart_dma.prev_rx_dma_pos -
+ up->uart_dma.rx_buf_dma_phys),
+ curr_transmitted_size);
+ tty_flip_buffer_push(up->port.state->port.tty);
+ up->uart_dma.prev_rx_dma_pos = curr_dma_pos;
+ if (up->uart_dma.rx_buf_size +
+ up->uart_dma.rx_buf_dma_phys == curr_dma_pos) {
+ ret = serial_omap_start_rxdma(up);
+ if (ret < 0) {
+ serial_omap_stop_rxdma(up);
+ up->ier |= (UART_IER_RDI | UART_IER_RLSI);
+ serial_out(up, UART_IER, up->ier);
+ }
+ } else {
+ mod_timer(&up->uart_dma.rx_timer, jiffies +
+ usecs_to_jiffies(up->uart_dma.rx_timeout));
+ }
+ up->port_activity = jiffies;
+}
+
+static void uart_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+ return;
+}
+
+static int serial_omap_start_rxdma(struct uart_omap_port *up)
+{
+ int ret = 0;
+
+ if (up->uart_dma.rx_dma_channel == -1) {
+ ret = omap_request_dma(up->uart_dma.uart_dma_rx,
+ "UART Rx DMA",
+ (void *)uart_rx_dma_callback, up,
+ &(up->uart_dma.rx_dma_channel));
+ if (ret < 0)
+ return ret;
+
+ omap_set_dma_src_params(up->uart_dma.rx_dma_channel, 0,
+ OMAP_DMA_AMODE_CONSTANT,
+ up->uart_dma.uart_base, 0, 0);
+ omap_set_dma_dest_params(up->uart_dma.rx_dma_channel, 0,
+ OMAP_DMA_AMODE_POST_INC,
+ up->uart_dma.rx_buf_dma_phys, 0, 0);
+ omap_set_dma_transfer_params(up->uart_dma.rx_dma_channel,
+ OMAP_DMA_DATA_TYPE_S8,
+ up->uart_dma.rx_buf_size, 1,
+ OMAP_DMA_SYNC_ELEMENT,
+ up->uart_dma.uart_dma_rx, 0);
+ }
+ up->uart_dma.prev_rx_dma_pos = up->uart_dma.rx_buf_dma_phys;
+ /* FIXME: Cache maintenance needed here? */
+ omap_start_dma(up->uart_dma.rx_dma_channel);
+ mod_timer(&up->uart_dma.rx_timer, jiffies +
+ usecs_to_jiffies(up->uart_dma.rx_timeout));
+ up->uart_dma.rx_dma_used = true;
+ return ret;
+}
+
+static void serial_omap_continue_tx(struct uart_omap_port *up)
+{
+ struct circ_buf *xmit = &up->port.state->xmit;
+ unsigned int start = up->uart_dma.tx_buf_dma_phys
+ + (xmit->tail & (UART_XMIT_SIZE - 1));
+
+ if (uart_circ_empty(xmit))
+ return;
+
+ up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
+ /*
+ * It is a circular buffer. See if the buffer has wounded back.
+ * If yes it will have to be transferred in two separate dma
+ * transfers
+ */
+ if (start + up->uart_dma.tx_buf_size >=
+ up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
+ up->uart_dma.tx_buf_size =
+ (up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start;
+ omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
+ OMAP_DMA_AMODE_CONSTANT,
+ up->uart_dma.uart_base, 0, 0);
+ omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
+ OMAP_DMA_AMODE_POST_INC, start, 0, 0);
+ omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
+ OMAP_DMA_DATA_TYPE_S8,
+ up->uart_dma.tx_buf_size, 1,
+ OMAP_DMA_SYNC_ELEMENT,
+ up->uart_dma.uart_dma_tx, 0);
+ /* FIXME: Cache maintenance needed here? */
+ omap_start_dma(up->uart_dma.tx_dma_channel);
+}
+
+static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)data;
+ struct circ_buf *xmit = &up->port.state->xmit;
+
+ xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \
+ (UART_XMIT_SIZE - 1);
+ up->port.icount.tx += up->uart_dma.tx_buf_size;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&up->port);
+
+ if (uart_circ_empty(xmit)) {
+ spin_lock(&(up->uart_dma.tx_lock));
+ serial_omap_stop_tx(&up->port);
+ up->uart_dma.tx_dma_used = false;
+ spin_unlock(&(up->uart_dma.tx_lock));
+ } else {
+ omap_stop_dma(up->uart_dma.tx_dma_channel);
+ serial_omap_continue_tx(up);
+ }
+ up->port_activity = jiffies;
+ return;
+}
+
+static int serial_omap_probe(struct platform_device *pdev)
+{
+ struct uart_omap_port *up;
+ struct resource *mem, *irq, *dma_tx, *dma_rx;
+ struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
+ int ret = -ENOSPC;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -ENODEV;
+ }
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return -ENODEV;
+ }
+
+ if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,
+ pdev->dev.driver->name)) {
+ dev_err(&pdev->dev, "memory region already claimed\n");
+ return -EBUSY;
+ }
+
+ dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+ if (!dma_rx) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+ if (!dma_tx) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ up = kzalloc(sizeof(*up), GFP_KERNEL);
+ if (up == NULL) {
+ ret = -ENOMEM;
+ goto do_release_region;
+ }
+ sprintf(up->name, "OMAP UART%d", pdev->id);
+ up->pdev = pdev;
+ up->port.dev = &pdev->dev;
+ up->port.type = PORT_OMAP;
+ up->port.iotype = UPIO_MEM;
+ up->port.irq = irq->start;
+
+ up->port.regshift = 2;
+ up->port.fifosize = 64;
+ up->port.ops = &serial_omap_pops;
+ up->port.line = pdev->id;
+
+ up->port.membase = omap_up_info->membase;
+ up->port.mapbase = omap_up_info->mapbase;
+ up->port.flags = omap_up_info->flags;
+ up->port.irqflags = omap_up_info->irqflags;
+ up->port.uartclk = omap_up_info->uartclk;
+ up->uart_dma.uart_base = mem->start;
+
+ if (omap_up_info->dma_enabled) {
+ up->uart_dma.uart_dma_tx = dma_tx->start;
+ up->uart_dma.uart_dma_rx = dma_rx->start;
+ up->use_dma = 1;
+ up->uart_dma.rx_buf_size = 4096;
+ up->uart_dma.rx_timeout = 2;
+ spin_lock_init(&(up->uart_dma.tx_lock));
+ spin_lock_init(&(up->uart_dma.rx_lock));
+ up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
+ up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
+ }
+
+ ui[pdev->id] = up;
+ serial_omap_add_console_port(up);
+
+ ret = uart_add_one_port(&serial_omap_reg, &up->port);
+ if (ret != 0)
+ goto do_release_region;
+
+ platform_set_drvdata(pdev, up);
+ return 0;
+err:
+ dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
+ pdev->id, __func__, ret);
+do_release_region:
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+ return ret;
+}
+
+static int serial_omap_remove(struct platform_device *dev)
+{
+ struct uart_omap_port *up = platform_get_drvdata(dev);
+
+ platform_set_drvdata(dev, NULL);
+ if (up) {
+ uart_remove_one_port(&serial_omap_reg, &up->port);
+ kfree(up);
+ }
+ return 0;
+}
+
+static struct platform_driver serial_omap_driver = {
+ .probe = serial_omap_probe,
+ .remove = serial_omap_remove,
+
+ .suspend = serial_omap_suspend,
+ .resume = serial_omap_resume,
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init serial_omap_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&serial_omap_reg);
+ if (ret != 0)
+ return ret;
+ ret = platform_driver_register(&serial_omap_driver);
+ if (ret != 0)
+ uart_unregister_driver(&serial_omap_reg);
+ return ret;
+}
+
+static void __exit serial_omap_exit(void)
+{
+ platform_driver_unregister(&serial_omap_driver);
+ uart_unregister_driver(&serial_omap_reg);
+}
+
+module_init(serial_omap_init);
+module_exit(serial_omap_exit);
+
+MODULE_DESCRIPTION("OMAP High Speed UART driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments Inc");
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index 9b52f77a9305..d2352ac437c5 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -140,7 +140,15 @@
# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
# define SCSPTR1 0xffe10024 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* Overrun error bit */
-# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+
+#if defined(CONFIG_SH_SH2007)
+/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=0 */
+# define SCSCR_INIT(port) 0x38
+#else
+/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=1 */
+# define SCSCR_INIT(port) 0x3a
+#endif
+
#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
defined(CONFIG_CPU_SUBTYPE_SH7786)
# define SCSPTR0 0xffea0024 /* 16 bit SCIF */
@@ -616,9 +624,10 @@ static inline int sci_rxd_in(struct uart_port *port)
* -- Mitch Davis - 15 Jul 2000
*/
-#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \
- defined(CONFIG_CPU_SUBTYPE_SH7785) || \
- defined(CONFIG_CPU_SUBTYPE_SH7786)
+#if (defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7786)) && \
+ !defined(CONFIG_SH_SH2007)
#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index c4bf54bb3fc7..d2fce865b731 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -44,7 +44,7 @@ MODULE_DEVICE_TABLE(of, ulite_of_match);
* Register definitions
*
* For register details see datasheet:
- * http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
+ * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf
*/
#define ULITE_RX 0x00
diff --git a/drivers/sh/Kconfig b/drivers/sh/Kconfig
index a54de0b9b3df..f168a6159961 100644
--- a/drivers/sh/Kconfig
+++ b/drivers/sh/Kconfig
@@ -1,24 +1,5 @@
-config INTC_USERIMASK
- bool "Userspace interrupt masking support"
- depends on ARCH_SHMOBILE || (SUPERH && CPU_SH4A)
- help
- This enables support for hardware-assisted userspace hardirq
- masking.
+menu "SuperH / SH-Mobile Driver Options"
- SH-4A and newer interrupt blocks all support a special shadowed
- page with all non-masking registers obscured when mapped in to
- userspace. This is primarily for use by userspace device
- drivers that are using special priority levels.
+source "drivers/sh/intc/Kconfig"
- If in doubt, say N.
-
-config INTC_BALANCING
- bool "Hardware IRQ balancing support"
- depends on SMP && SUPERH && CPU_SUBTYPE_SH7786
- help
- This enables support for IRQ auto-distribution mode on SH-X3
- SMP parts. All of the balancing and CPU wakeup decisions are
- taken care of automatically by hardware for distributed
- vectors.
-
- If in doubt, say N.
+endmenu
diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile
index 08fc653a825c..24e6cec0ae8d 100644
--- a/drivers/sh/Makefile
+++ b/drivers/sh/Makefile
@@ -1,10 +1,9 @@
#
# Makefile for the SuperH specific drivers.
#
-obj-y := clk.o intc.o
+obj-y := intc/
-obj-$(CONFIG_SUPERHYWAY) += superhyway/
+obj-$(CONFIG_HAVE_CLK) += clk/
obj-$(CONFIG_MAPLE) += maple/
-
+obj-$(CONFIG_SUPERHYWAY) += superhyway/
obj-$(CONFIG_GENERIC_GPIO) += pfc.o
-obj-$(CONFIG_SH_CLK_CPG) += clk-cpg.o
diff --git a/drivers/sh/clk/Makefile b/drivers/sh/clk/Makefile
new file mode 100644
index 000000000000..5d15ebfaa074
--- /dev/null
+++ b/drivers/sh/clk/Makefile
@@ -0,0 +1,3 @@
+obj-y := core.o
+
+obj-$(CONFIG_SH_CLK_CPG) += cpg.o
diff --git a/drivers/sh/clk.c b/drivers/sh/clk/core.c
index 5d84adac9ec4..fd0d1b98901c 100644
--- a/drivers/sh/clk.c
+++ b/drivers/sh/clk/core.c
@@ -1,7 +1,7 @@
/*
- * drivers/sh/clk.c - SuperH clock framework
+ * SuperH clock framework
*
- * Copyright (C) 2005 - 2009 Paul Mundt
+ * Copyright (C) 2005 - 2010 Paul Mundt
*
* This clock framework is derived from the OMAP version by:
*
@@ -14,6 +14,8 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+#define pr_fmt(fmt) "clock: " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -23,7 +25,7 @@
#include <linux/sysdev.h>
#include <linux/seq_file.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
+#include <linux/io.h>
#include <linux/debugfs.h>
#include <linux/cpufreq.h>
#include <linux/clk.h>
@@ -43,6 +45,8 @@ void clk_rate_table_build(struct clk *clk,
unsigned long freq;
int i;
+ clk->nr_freqs = nr_freqs;
+
for (i = 0; i < nr_freqs; i++) {
div = 1;
mult = 1;
@@ -67,29 +71,39 @@ void clk_rate_table_build(struct clk *clk,
freq_table[i].frequency = CPUFREQ_TABLE_END;
}
-long clk_rate_table_round(struct clk *clk,
- struct cpufreq_frequency_table *freq_table,
- unsigned long rate)
+struct clk_rate_round_data;
+
+struct clk_rate_round_data {
+ unsigned long rate;
+ unsigned int min, max;
+ long (*func)(unsigned int, struct clk_rate_round_data *);
+ void *arg;
+};
+
+#define for_each_frequency(pos, r, freq) \
+ for (pos = r->min, freq = r->func(pos, r); \
+ pos <= r->max; pos++, freq = r->func(pos, r)) \
+ if (unlikely(freq == 0)) \
+ ; \
+ else
+
+static long clk_rate_round_helper(struct clk_rate_round_data *rounder)
{
unsigned long rate_error, rate_error_prev = ~0UL;
- unsigned long rate_best_fit = rate;
- unsigned long highest, lowest;
+ unsigned long rate_best_fit = rounder->rate;
+ unsigned long highest, lowest, freq;
int i;
- highest = lowest = 0;
-
- for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
- unsigned long freq = freq_table[i].frequency;
-
- if (freq == CPUFREQ_ENTRY_INVALID)
- continue;
+ highest = 0;
+ lowest = ~0UL;
+ for_each_frequency(i, rounder, freq) {
if (freq > highest)
highest = freq;
if (freq < lowest)
lowest = freq;
- rate_error = abs(freq - rate);
+ rate_error = abs(freq - rounder->rate);
if (rate_error < rate_error_prev) {
rate_best_fit = freq;
rate_error_prev = rate_error;
@@ -99,14 +113,64 @@ long clk_rate_table_round(struct clk *clk,
break;
}
- if (rate >= highest)
+ if (rounder->rate >= highest)
rate_best_fit = highest;
- if (rate <= lowest)
+ if (rounder->rate <= lowest)
rate_best_fit = lowest;
return rate_best_fit;
}
+static long clk_rate_table_iter(unsigned int pos,
+ struct clk_rate_round_data *rounder)
+{
+ struct cpufreq_frequency_table *freq_table = rounder->arg;
+ unsigned long freq = freq_table[pos].frequency;
+
+ if (freq == CPUFREQ_ENTRY_INVALID)
+ freq = 0;
+
+ return freq;
+}
+
+long clk_rate_table_round(struct clk *clk,
+ struct cpufreq_frequency_table *freq_table,
+ unsigned long rate)
+{
+ struct clk_rate_round_data table_round = {
+ .min = 0,
+ .max = clk->nr_freqs - 1,
+ .func = clk_rate_table_iter,
+ .arg = freq_table,
+ .rate = rate,
+ };
+
+ if (clk->nr_freqs < 1)
+ return 0;
+
+ return clk_rate_round_helper(&table_round);
+}
+
+static long clk_rate_div_range_iter(unsigned int pos,
+ struct clk_rate_round_data *rounder)
+{
+ return clk_get_rate(rounder->arg) / pos;
+}
+
+long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,
+ unsigned int div_max, unsigned long rate)
+{
+ struct clk_rate_round_data div_range_round = {
+ .min = div_min,
+ .max = div_max,
+ .func = clk_rate_div_range_iter,
+ .arg = clk_get_parent(clk),
+ .rate = rate,
+ };
+
+ return clk_rate_round_helper(&div_range_round);
+}
+
int clk_rate_table_find(struct clk *clk,
struct cpufreq_frequency_table *freq_table,
unsigned long rate)
@@ -160,8 +224,8 @@ void propagate_rate(struct clk *tclk)
static void __clk_disable(struct clk *clk)
{
- if (WARN(!clk->usecount, "Trying to disable clock %s with 0 usecount\n",
- clk->name))
+ if (WARN(!clk->usecount, "Trying to disable clock %p with 0 usecount\n",
+ clk))
return;
if (!(--clk->usecount)) {
@@ -248,8 +312,88 @@ void recalculate_root_clocks(void)
}
}
+static struct clk_mapping dummy_mapping;
+
+static struct clk *lookup_root_clock(struct clk *clk)
+{
+ while (clk->parent)
+ clk = clk->parent;
+
+ return clk;
+}
+
+static int clk_establish_mapping(struct clk *clk)
+{
+ struct clk_mapping *mapping = clk->mapping;
+
+ /*
+ * Propagate mappings.
+ */
+ if (!mapping) {
+ struct clk *clkp;
+
+ /*
+ * dummy mapping for root clocks with no specified ranges
+ */
+ if (!clk->parent) {
+ clk->mapping = &dummy_mapping;
+ return 0;
+ }
+
+ /*
+ * If we're on a child clock and it provides no mapping of its
+ * own, inherit the mapping from its root clock.
+ */
+ clkp = lookup_root_clock(clk);
+ mapping = clkp->mapping;
+ BUG_ON(!mapping);
+ }
+
+ /*
+ * Establish initial mapping.
+ */
+ if (!mapping->base && mapping->phys) {
+ kref_init(&mapping->ref);
+
+ mapping->base = ioremap_nocache(mapping->phys, mapping->len);
+ if (unlikely(!mapping->base))
+ return -ENXIO;
+ } else if (mapping->base) {
+ /*
+ * Bump the refcount for an existing mapping
+ */
+ kref_get(&mapping->ref);
+ }
+
+ clk->mapping = mapping;
+ return 0;
+}
+
+static void clk_destroy_mapping(struct kref *kref)
+{
+ struct clk_mapping *mapping;
+
+ mapping = container_of(kref, struct clk_mapping, ref);
+
+ iounmap(mapping->base);
+}
+
+static void clk_teardown_mapping(struct clk *clk)
+{
+ struct clk_mapping *mapping = clk->mapping;
+
+ /* Nothing to do */
+ if (mapping == &dummy_mapping)
+ return;
+
+ kref_put(&mapping->ref, clk_destroy_mapping);
+ clk->mapping = NULL;
+}
+
int clk_register(struct clk *clk)
{
+ int ret;
+
if (clk == NULL || IS_ERR(clk))
return -EINVAL;
@@ -264,6 +408,10 @@ int clk_register(struct clk *clk)
INIT_LIST_HEAD(&clk->children);
clk->usecount = 0;
+ ret = clk_establish_mapping(clk);
+ if (unlikely(ret))
+ goto out_unlock;
+
if (clk->parent)
list_add(&clk->sibling, &clk->parent->children);
else
@@ -272,9 +420,11 @@ int clk_register(struct clk *clk)
list_add(&clk->node, &clock_list);
if (clk->ops && clk->ops->init)
clk->ops->init(clk);
+
+out_unlock:
mutex_unlock(&clock_list_sem);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(clk_register);
@@ -283,6 +433,7 @@ void clk_unregister(struct clk *clk)
mutex_lock(&clock_list_sem);
list_del(&clk->sibling);
list_del(&clk->node);
+ clk_teardown_mapping(clk);
mutex_unlock(&clock_list_sem);
}
EXPORT_SYMBOL_GPL(clk_unregister);
@@ -354,10 +505,10 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
ret = clk_reparent(clk, parent);
if (ret == 0) {
- pr_debug("clock: set parent of %s to %s (new rate %ld)\n",
- clk->name, clk->parent->name, clk->rate);
if (clk->ops->recalc)
clk->rate = clk->ops->recalc(clk);
+ pr_debug("set parent of %p to %p (new rate %ld)\n",
+ clk, clk->parent, clk->rate);
propagate_rate(clk);
}
} else
@@ -469,9 +620,7 @@ static int clk_debugfs_register_one(struct clk *c)
char s[255];
char *p = s;
- p += sprintf(p, "%s", c->name);
- if (c->id >= 0)
- sprintf(p, ":%d", c->id);
+ p += sprintf(p, "%p", c);
d = debugfs_create_dir(s, pa ? pa->dentry : clk_debugfs_root);
if (!d)
return -ENOMEM;
@@ -513,7 +662,7 @@ static int clk_debugfs_register(struct clk *c)
return err;
}
- if (!c->dentry && c->name) {
+ if (!c->dentry) {
err = clk_debugfs_register_one(c);
if (err)
return err;
diff --git a/drivers/sh/clk-cpg.c b/drivers/sh/clk/cpg.c
index 8c024b984ed8..3aea5f0ceb09 100644
--- a/drivers/sh/clk-cpg.c
+++ b/drivers/sh/clk/cpg.c
@@ -1,3 +1,12 @@
+/*
+ * Helper routines for SuperH Clock Pulse Generator blocks (CPG).
+ *
+ * Copyright (C) 2010 Magnus Damm
+ *
+ * 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/clk.h>
#include <linux/compiler.h>
#include <linux/slab.h>
@@ -180,7 +189,6 @@ static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
clkp = clks + k;
clkp->ops = ops;
- clkp->id = -1;
clkp->freq_table = freq_table + (k * freq_table_size);
clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
@@ -319,7 +327,6 @@ static int __init sh_clk_div4_register_ops(struct clk *clks, int nr,
clkp = clks + k;
clkp->ops = ops;
- clkp->id = -1;
clkp->priv = table;
clkp->freq_table = freq_table + (k * freq_table_size);
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
deleted file mode 100644
index e91a23e5ffd8..000000000000
--- a/drivers/sh/intc.c
+++ /dev/null
@@ -1,1390 +0,0 @@
-/*
- * Shared interrupt handling code for IPR and INTC2 types of IRQs.
- *
- * Copyright (C) 2007, 2008 Magnus Damm
- * Copyright (C) 2009, 2010 Paul Mundt
- *
- * Based on intc2.c and ipr.c
- *
- * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi
- * Copyright (C) 2000 Kazumoto Kojima
- * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
- * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
- * Copyright (C) 2005, 2006 Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/sh_intc.h>
-#include <linux/sysdev.h>
-#include <linux/list.h>
-#include <linux/topology.h>
-#include <linux/bitmap.h>
-#include <linux/cpumask.h>
-#include <asm/sizes.h>
-
-#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
- ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
- ((addr_e) << 16) | ((addr_d << 24)))
-
-#define _INTC_SHIFT(h) (h & 0x1f)
-#define _INTC_WIDTH(h) ((h >> 5) & 0xf)
-#define _INTC_FN(h) ((h >> 9) & 0xf)
-#define _INTC_MODE(h) ((h >> 13) & 0x7)
-#define _INTC_ADDR_E(h) ((h >> 16) & 0xff)
-#define _INTC_ADDR_D(h) ((h >> 24) & 0xff)
-
-struct intc_handle_int {
- unsigned int irq;
- unsigned long handle;
-};
-
-struct intc_window {
- phys_addr_t phys;
- void __iomem *virt;
- unsigned long size;
-};
-
-struct intc_desc_int {
- struct list_head list;
- struct sys_device sysdev;
- pm_message_t state;
- unsigned long *reg;
-#ifdef CONFIG_SMP
- unsigned long *smp;
-#endif
- unsigned int nr_reg;
- struct intc_handle_int *prio;
- unsigned int nr_prio;
- struct intc_handle_int *sense;
- unsigned int nr_sense;
- struct intc_window *window;
- unsigned int nr_windows;
- struct irq_chip chip;
-};
-
-static LIST_HEAD(intc_list);
-
-/*
- * The intc_irq_map provides a global map of bound IRQ vectors for a
- * given platform. Allocation of IRQs are either static through the CPU
- * vector map, or dynamic in the case of board mux vectors or MSI.
- *
- * As this is a central point for all IRQ controllers on the system,
- * each of the available sources are mapped out here. This combined with
- * sparseirq makes it quite trivial to keep the vector map tightly packed
- * when dynamically creating IRQs, as well as tying in to otherwise
- * unused irq_desc positions in the sparse array.
- */
-static DECLARE_BITMAP(intc_irq_map, NR_IRQS);
-static DEFINE_SPINLOCK(vector_lock);
-
-#ifdef CONFIG_SMP
-#define IS_SMP(x) x.smp
-#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
-#define SMP_NR(d, x) ((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1)
-#else
-#define IS_SMP(x) 0
-#define INTC_REG(d, x, c) (d->reg[(x)])
-#define SMP_NR(d, x) 1
-#endif
-
-static unsigned int intc_prio_level[NR_IRQS]; /* for now */
-static unsigned int default_prio_level = 2; /* 2 - 16 */
-static unsigned long ack_handle[NR_IRQS];
-#ifdef CONFIG_INTC_BALANCING
-static unsigned long dist_handle[NR_IRQS];
-#endif
-
-static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
-{
- struct irq_chip *chip = get_irq_chip(irq);
- return container_of(chip, struct intc_desc_int, chip);
-}
-
-static unsigned long intc_phys_to_virt(struct intc_desc_int *d,
- unsigned long address)
-{
- struct intc_window *window;
- int k;
-
- /* scan through physical windows and convert address */
- for (k = 0; k < d->nr_windows; k++) {
- window = d->window + k;
-
- if (address < window->phys)
- continue;
-
- if (address >= (window->phys + window->size))
- continue;
-
- address -= window->phys;
- address += (unsigned long)window->virt;
-
- return address;
- }
-
- /* no windows defined, register must be 1:1 mapped virt:phys */
- return address;
-}
-
-static unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
-{
- unsigned int k;
-
- address = intc_phys_to_virt(d, address);
-
- for (k = 0; k < d->nr_reg; k++) {
- if (d->reg[k] == address)
- return k;
- }
-
- BUG();
- return 0;
-}
-
-static inline unsigned int set_field(unsigned int value,
- unsigned int field_value,
- unsigned int handle)
-{
- unsigned int width = _INTC_WIDTH(handle);
- unsigned int shift = _INTC_SHIFT(handle);
-
- value &= ~(((1 << width) - 1) << shift);
- value |= field_value << shift;
- return value;
-}
-
-static void write_8(unsigned long addr, unsigned long h, unsigned long data)
-{
- __raw_writeb(set_field(0, data, h), addr);
- (void)__raw_readb(addr); /* Defeat write posting */
-}
-
-static void write_16(unsigned long addr, unsigned long h, unsigned long data)
-{
- __raw_writew(set_field(0, data, h), addr);
- (void)__raw_readw(addr); /* Defeat write posting */
-}
-
-static void write_32(unsigned long addr, unsigned long h, unsigned long data)
-{
- __raw_writel(set_field(0, data, h), addr);
- (void)__raw_readl(addr); /* Defeat write posting */
-}
-
-static void modify_8(unsigned long addr, unsigned long h, unsigned long data)
-{
- unsigned long flags;
- local_irq_save(flags);
- __raw_writeb(set_field(__raw_readb(addr), data, h), addr);
- (void)__raw_readb(addr); /* Defeat write posting */
- local_irq_restore(flags);
-}
-
-static void modify_16(unsigned long addr, unsigned long h, unsigned long data)
-{
- unsigned long flags;
- local_irq_save(flags);
- __raw_writew(set_field(__raw_readw(addr), data, h), addr);
- (void)__raw_readw(addr); /* Defeat write posting */
- local_irq_restore(flags);
-}
-
-static void modify_32(unsigned long addr, unsigned long h, unsigned long data)
-{
- unsigned long flags;
- local_irq_save(flags);
- __raw_writel(set_field(__raw_readl(addr), data, h), addr);
- (void)__raw_readl(addr); /* Defeat write posting */
- local_irq_restore(flags);
-}
-
-enum { REG_FN_ERR = 0, REG_FN_WRITE_BASE = 1, REG_FN_MODIFY_BASE = 5 };
-
-static void (*intc_reg_fns[])(unsigned long addr,
- unsigned long h,
- unsigned long data) = {
- [REG_FN_WRITE_BASE + 0] = write_8,
- [REG_FN_WRITE_BASE + 1] = write_16,
- [REG_FN_WRITE_BASE + 3] = write_32,
- [REG_FN_MODIFY_BASE + 0] = modify_8,
- [REG_FN_MODIFY_BASE + 1] = modify_16,
- [REG_FN_MODIFY_BASE + 3] = modify_32,
-};
-
-enum { MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */
- MODE_MASK_REG, /* Bit(s) set -> interrupt disabled */
- MODE_DUAL_REG, /* Two registers, set bit to enable / disable */
- MODE_PRIO_REG, /* Priority value written to enable interrupt */
- MODE_PCLR_REG, /* Above plus all bits set to disable interrupt */
-};
-
-static void intc_mode_field(unsigned long addr,
- unsigned long handle,
- void (*fn)(unsigned long,
- unsigned long,
- unsigned long),
- unsigned int irq)
-{
- fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
-}
-
-static void intc_mode_zero(unsigned long addr,
- unsigned long handle,
- void (*fn)(unsigned long,
- unsigned long,
- unsigned long),
- unsigned int irq)
-{
- fn(addr, handle, 0);
-}
-
-static void intc_mode_prio(unsigned long addr,
- unsigned long handle,
- void (*fn)(unsigned long,
- unsigned long,
- unsigned long),
- unsigned int irq)
-{
- fn(addr, handle, intc_prio_level[irq]);
-}
-
-static void (*intc_enable_fns[])(unsigned long addr,
- unsigned long handle,
- void (*fn)(unsigned long,
- unsigned long,
- unsigned long),
- unsigned int irq) = {
- [MODE_ENABLE_REG] = intc_mode_field,
- [MODE_MASK_REG] = intc_mode_zero,
- [MODE_DUAL_REG] = intc_mode_field,
- [MODE_PRIO_REG] = intc_mode_prio,
- [MODE_PCLR_REG] = intc_mode_prio,
-};
-
-static void (*intc_disable_fns[])(unsigned long addr,
- unsigned long handle,
- void (*fn)(unsigned long,
- unsigned long,
- unsigned long),
- unsigned int irq) = {
- [MODE_ENABLE_REG] = intc_mode_zero,
- [MODE_MASK_REG] = intc_mode_field,
- [MODE_DUAL_REG] = intc_mode_field,
- [MODE_PRIO_REG] = intc_mode_zero,
- [MODE_PCLR_REG] = intc_mode_field,
-};
-
-#ifdef CONFIG_INTC_BALANCING
-static inline void intc_balancing_enable(unsigned int irq)
-{
- struct intc_desc_int *d = get_intc_desc(irq);
- unsigned long handle = dist_handle[irq];
- unsigned long addr;
-
- if (irq_balancing_disabled(irq) || !handle)
- return;
-
- addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
- intc_reg_fns[_INTC_FN(handle)](addr, handle, 1);
-}
-
-static inline void intc_balancing_disable(unsigned int irq)
-{
- struct intc_desc_int *d = get_intc_desc(irq);
- unsigned long handle = dist_handle[irq];
- unsigned long addr;
-
- if (irq_balancing_disabled(irq) || !handle)
- return;
-
- addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
- intc_reg_fns[_INTC_FN(handle)](addr, handle, 0);
-}
-
-static unsigned int intc_dist_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id)
-{
- struct intc_mask_reg *mr = desc->hw.mask_regs;
- unsigned int i, j, fn, mode;
- unsigned long reg_e, reg_d;
-
- for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) {
- mr = desc->hw.mask_regs + i;
-
- /*
- * Skip this entry if there's no auto-distribution
- * register associated with it.
- */
- if (!mr->dist_reg)
- continue;
-
- for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
- if (mr->enum_ids[j] != enum_id)
- continue;
-
- fn = REG_FN_MODIFY_BASE;
- mode = MODE_ENABLE_REG;
- reg_e = mr->dist_reg;
- reg_d = mr->dist_reg;
-
- fn += (mr->reg_width >> 3) - 1;
- return _INTC_MK(fn, mode,
- intc_get_reg(d, reg_e),
- intc_get_reg(d, reg_d),
- 1,
- (mr->reg_width - 1) - j);
- }
- }
-
- /*
- * It's possible we've gotten here with no distribution options
- * available for the IRQ in question, so we just skip over those.
- */
- return 0;
-}
-#else
-static inline void intc_balancing_enable(unsigned int irq)
-{
-}
-
-static inline void intc_balancing_disable(unsigned int irq)
-{
-}
-#endif
-
-static inline void _intc_enable(unsigned int irq, unsigned long handle)
-{
- struct intc_desc_int *d = get_intc_desc(irq);
- unsigned long addr;
- unsigned int cpu;
-
- for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
-#ifdef CONFIG_SMP
- if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
- continue;
-#endif
- addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
- intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
- [_INTC_FN(handle)], irq);
- }
-
- intc_balancing_enable(irq);
-}
-
-static void intc_enable(unsigned int irq)
-{
- _intc_enable(irq, (unsigned long)get_irq_chip_data(irq));
-}
-
-static void intc_disable(unsigned int irq)
-{
- struct intc_desc_int *d = get_intc_desc(irq);
- unsigned long handle = (unsigned long)get_irq_chip_data(irq);
- unsigned long addr;
- unsigned int cpu;
-
- intc_balancing_disable(irq);
-
- for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
-#ifdef CONFIG_SMP
- if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
- continue;
-#endif
- addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
- intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
- [_INTC_FN(handle)], irq);
- }
-}
-
-static void (*intc_enable_noprio_fns[])(unsigned long addr,
- unsigned long handle,
- void (*fn)(unsigned long,
- unsigned long,
- unsigned long),
- unsigned int irq) = {
- [MODE_ENABLE_REG] = intc_mode_field,
- [MODE_MASK_REG] = intc_mode_zero,
- [MODE_DUAL_REG] = intc_mode_field,
- [MODE_PRIO_REG] = intc_mode_field,
- [MODE_PCLR_REG] = intc_mode_field,
-};
-
-static void intc_enable_disable(struct intc_desc_int *d,
- unsigned long handle, int do_enable)
-{
- unsigned long addr;
- unsigned int cpu;
- void (*fn)(unsigned long, unsigned long,
- void (*)(unsigned long, unsigned long, unsigned long),
- unsigned int);
-
- if (do_enable) {
- for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
- addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
- fn = intc_enable_noprio_fns[_INTC_MODE(handle)];
- fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
- }
- } else {
- for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
- addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
- fn = intc_disable_fns[_INTC_MODE(handle)];
- fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
- }
- }
-}
-
-static int intc_set_wake(unsigned int irq, unsigned int on)
-{
- return 0; /* allow wakeup, but setup hardware in intc_suspend() */
-}
-
-#ifdef CONFIG_SMP
-/*
- * This is held with the irq desc lock held, so we don't require any
- * additional locking here at the intc desc level. The affinity mask is
- * later tested in the enable/disable paths.
- */
-static int intc_set_affinity(unsigned int irq, const struct cpumask *cpumask)
-{
- if (!cpumask_intersects(cpumask, cpu_online_mask))
- return -1;
-
- cpumask_copy(irq_to_desc(irq)->affinity, cpumask);
-
- return 0;
-}
-#endif
-
-static void intc_mask_ack(unsigned int irq)
-{
- struct intc_desc_int *d = get_intc_desc(irq);
- unsigned long handle = ack_handle[irq];
- unsigned long addr;
-
- intc_disable(irq);
-
- /* read register and write zero only to the associated bit */
- if (handle) {
- addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
- switch (_INTC_FN(handle)) {
- case REG_FN_MODIFY_BASE + 0: /* 8bit */
- __raw_readb(addr);
- __raw_writeb(0xff ^ set_field(0, 1, handle), addr);
- break;
- case REG_FN_MODIFY_BASE + 1: /* 16bit */
- __raw_readw(addr);
- __raw_writew(0xffff ^ set_field(0, 1, handle), addr);
- break;
- case REG_FN_MODIFY_BASE + 3: /* 32bit */
- __raw_readl(addr);
- __raw_writel(0xffffffff ^ set_field(0, 1, handle), addr);
- break;
- default:
- BUG();
- break;
- }
- }
-}
-
-static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
- unsigned int nr_hp,
- unsigned int irq)
-{
- int i;
-
- /*
- * this doesn't scale well, but...
- *
- * this function should only be used for cerain uncommon
- * operations such as intc_set_priority() and intc_set_sense()
- * and in those rare cases performance doesn't matter that much.
- * keeping the memory footprint low is more important.
- *
- * one rather simple way to speed this up and still keep the
- * memory footprint down is to make sure the array is sorted
- * and then perform a bisect to lookup the irq.
- */
- for (i = 0; i < nr_hp; i++) {
- if ((hp + i)->irq != irq)
- continue;
-
- return hp + i;
- }
-
- return NULL;
-}
-
-int intc_set_priority(unsigned int irq, unsigned int prio)
-{
- struct intc_desc_int *d = get_intc_desc(irq);
- struct intc_handle_int *ihp;
-
- if (!intc_prio_level[irq] || prio <= 1)
- return -EINVAL;
-
- ihp = intc_find_irq(d->prio, d->nr_prio, irq);
- if (ihp) {
- if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
- return -EINVAL;
-
- intc_prio_level[irq] = prio;
-
- /*
- * only set secondary masking method directly
- * primary masking method is using intc_prio_level[irq]
- * priority level will be set during next enable()
- */
- if (_INTC_FN(ihp->handle) != REG_FN_ERR)
- _intc_enable(irq, ihp->handle);
- }
- return 0;
-}
-
-#define VALID(x) (x | 0x80)
-
-static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
- [IRQ_TYPE_EDGE_FALLING] = VALID(0),
- [IRQ_TYPE_EDGE_RISING] = VALID(1),
- [IRQ_TYPE_LEVEL_LOW] = VALID(2),
- /* SH7706, SH7707 and SH7709 do not support high level triggered */
-#if !defined(CONFIG_CPU_SUBTYPE_SH7706) && \
- !defined(CONFIG_CPU_SUBTYPE_SH7707) && \
- !defined(CONFIG_CPU_SUBTYPE_SH7709)
- [IRQ_TYPE_LEVEL_HIGH] = VALID(3),
-#endif
-};
-
-static int intc_set_sense(unsigned int irq, unsigned int type)
-{
- struct intc_desc_int *d = get_intc_desc(irq);
- unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
- struct intc_handle_int *ihp;
- unsigned long addr;
-
- if (!value)
- return -EINVAL;
-
- ihp = intc_find_irq(d->sense, d->nr_sense, irq);
- if (ihp) {
- addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
- intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
- }
- return 0;
-}
-
-static intc_enum __init intc_grp_id(struct intc_desc *desc,
- intc_enum enum_id)
-{
- struct intc_group *g = desc->hw.groups;
- unsigned int i, j;
-
- for (i = 0; g && enum_id && i < desc->hw.nr_groups; i++) {
- g = desc->hw.groups + i;
-
- for (j = 0; g->enum_ids[j]; j++) {
- if (g->enum_ids[j] != enum_id)
- continue;
-
- return g->enum_id;
- }
- }
-
- return 0;
-}
-
-static unsigned int __init _intc_mask_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id,
- unsigned int *reg_idx,
- unsigned int *fld_idx)
-{
- struct intc_mask_reg *mr = desc->hw.mask_regs;
- unsigned int fn, mode;
- unsigned long reg_e, reg_d;
-
- while (mr && enum_id && *reg_idx < desc->hw.nr_mask_regs) {
- mr = desc->hw.mask_regs + *reg_idx;
-
- for (; *fld_idx < ARRAY_SIZE(mr->enum_ids); (*fld_idx)++) {
- if (mr->enum_ids[*fld_idx] != enum_id)
- continue;
-
- if (mr->set_reg && mr->clr_reg) {
- fn = REG_FN_WRITE_BASE;
- mode = MODE_DUAL_REG;
- reg_e = mr->clr_reg;
- reg_d = mr->set_reg;
- } else {
- fn = REG_FN_MODIFY_BASE;
- if (mr->set_reg) {
- mode = MODE_ENABLE_REG;
- reg_e = mr->set_reg;
- reg_d = mr->set_reg;
- } else {
- mode = MODE_MASK_REG;
- reg_e = mr->clr_reg;
- reg_d = mr->clr_reg;
- }
- }
-
- fn += (mr->reg_width >> 3) - 1;
- return _INTC_MK(fn, mode,
- intc_get_reg(d, reg_e),
- intc_get_reg(d, reg_d),
- 1,
- (mr->reg_width - 1) - *fld_idx);
- }
-
- *fld_idx = 0;
- (*reg_idx)++;
- }
-
- return 0;
-}
-
-static unsigned int __init intc_mask_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id, int do_grps)
-{
- unsigned int i = 0;
- unsigned int j = 0;
- unsigned int ret;
-
- ret = _intc_mask_data(desc, d, enum_id, &i, &j);
- if (ret)
- return ret;
-
- if (do_grps)
- return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0);
-
- return 0;
-}
-
-static unsigned int __init _intc_prio_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id,
- unsigned int *reg_idx,
- unsigned int *fld_idx)
-{
- struct intc_prio_reg *pr = desc->hw.prio_regs;
- unsigned int fn, n, mode, bit;
- unsigned long reg_e, reg_d;
-
- while (pr && enum_id && *reg_idx < desc->hw.nr_prio_regs) {
- pr = desc->hw.prio_regs + *reg_idx;
-
- for (; *fld_idx < ARRAY_SIZE(pr->enum_ids); (*fld_idx)++) {
- if (pr->enum_ids[*fld_idx] != enum_id)
- continue;
-
- if (pr->set_reg && pr->clr_reg) {
- fn = REG_FN_WRITE_BASE;
- mode = MODE_PCLR_REG;
- reg_e = pr->set_reg;
- reg_d = pr->clr_reg;
- } else {
- fn = REG_FN_MODIFY_BASE;
- mode = MODE_PRIO_REG;
- if (!pr->set_reg)
- BUG();
- reg_e = pr->set_reg;
- reg_d = pr->set_reg;
- }
-
- fn += (pr->reg_width >> 3) - 1;
- n = *fld_idx + 1;
-
- BUG_ON(n * pr->field_width > pr->reg_width);
-
- bit = pr->reg_width - (n * pr->field_width);
-
- return _INTC_MK(fn, mode,
- intc_get_reg(d, reg_e),
- intc_get_reg(d, reg_d),
- pr->field_width, bit);
- }
-
- *fld_idx = 0;
- (*reg_idx)++;
- }
-
- return 0;
-}
-
-static unsigned int __init intc_prio_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id, int do_grps)
-{
- unsigned int i = 0;
- unsigned int j = 0;
- unsigned int ret;
-
- ret = _intc_prio_data(desc, d, enum_id, &i, &j);
- if (ret)
- return ret;
-
- if (do_grps)
- return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0);
-
- return 0;
-}
-
-static void __init intc_enable_disable_enum(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id, int enable)
-{
- unsigned int i, j, data;
-
- /* go through and enable/disable all mask bits */
- i = j = 0;
- do {
- data = _intc_mask_data(desc, d, enum_id, &i, &j);
- if (data)
- intc_enable_disable(d, data, enable);
- j++;
- } while (data);
-
- /* go through and enable/disable all priority fields */
- i = j = 0;
- do {
- data = _intc_prio_data(desc, d, enum_id, &i, &j);
- if (data)
- intc_enable_disable(d, data, enable);
-
- j++;
- } while (data);
-}
-
-static unsigned int __init intc_ack_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id)
-{
- struct intc_mask_reg *mr = desc->hw.ack_regs;
- unsigned int i, j, fn, mode;
- unsigned long reg_e, reg_d;
-
- for (i = 0; mr && enum_id && i < desc->hw.nr_ack_regs; i++) {
- mr = desc->hw.ack_regs + i;
-
- for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
- if (mr->enum_ids[j] != enum_id)
- continue;
-
- fn = REG_FN_MODIFY_BASE;
- mode = MODE_ENABLE_REG;
- reg_e = mr->set_reg;
- reg_d = mr->set_reg;
-
- fn += (mr->reg_width >> 3) - 1;
- return _INTC_MK(fn, mode,
- intc_get_reg(d, reg_e),
- intc_get_reg(d, reg_d),
- 1,
- (mr->reg_width - 1) - j);
- }
- }
-
- return 0;
-}
-
-static unsigned int __init intc_sense_data(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id)
-{
- struct intc_sense_reg *sr = desc->hw.sense_regs;
- unsigned int i, j, fn, bit;
-
- for (i = 0; sr && enum_id && i < desc->hw.nr_sense_regs; i++) {
- sr = desc->hw.sense_regs + i;
-
- for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
- if (sr->enum_ids[j] != enum_id)
- continue;
-
- fn = REG_FN_MODIFY_BASE;
- fn += (sr->reg_width >> 3) - 1;
-
- BUG_ON((j + 1) * sr->field_width > sr->reg_width);
-
- bit = sr->reg_width - ((j + 1) * sr->field_width);
-
- return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg),
- 0, sr->field_width, bit);
- }
- }
-
- return 0;
-}
-
-static void __init intc_register_irq(struct intc_desc *desc,
- struct intc_desc_int *d,
- intc_enum enum_id,
- unsigned int irq)
-{
- struct intc_handle_int *hp;
- unsigned int data[2], primary;
-
- /*
- * Register the IRQ position with the global IRQ map
- */
- set_bit(irq, intc_irq_map);
-
- /*
- * Prefer single interrupt source bitmap over other combinations:
- *
- * 1. bitmap, single interrupt source
- * 2. priority, single interrupt source
- * 3. bitmap, multiple interrupt sources (groups)
- * 4. priority, multiple interrupt sources (groups)
- */
- data[0] = intc_mask_data(desc, d, enum_id, 0);
- data[1] = intc_prio_data(desc, d, enum_id, 0);
-
- primary = 0;
- if (!data[0] && data[1])
- primary = 1;
-
- if (!data[0] && !data[1])
- pr_warning("missing unique irq mask for irq %d (vect 0x%04x)\n",
- irq, irq2evt(irq));
-
- data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1);
- data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1);
-
- if (!data[primary])
- primary ^= 1;
-
- BUG_ON(!data[primary]); /* must have primary masking method */
-
- disable_irq_nosync(irq);
- set_irq_chip_and_handler_name(irq, &d->chip,
- handle_level_irq, "level");
- set_irq_chip_data(irq, (void *)data[primary]);
-
- /*
- * set priority level
- * - this needs to be at least 2 for 5-bit priorities on 7780
- */
- intc_prio_level[irq] = default_prio_level;
-
- /* enable secondary masking method if present */
- if (data[!primary])
- _intc_enable(irq, data[!primary]);
-
- /* add irq to d->prio list if priority is available */
- if (data[1]) {
- hp = d->prio + d->nr_prio;
- hp->irq = irq;
- hp->handle = data[1];
-
- if (primary) {
- /*
- * only secondary priority should access registers, so
- * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
- */
- hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
- hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
- }
- d->nr_prio++;
- }
-
- /* add irq to d->sense list if sense is available */
- data[0] = intc_sense_data(desc, d, enum_id);
- if (data[0]) {
- (d->sense + d->nr_sense)->irq = irq;
- (d->sense + d->nr_sense)->handle = data[0];
- d->nr_sense++;
- }
-
- /* irq should be disabled by default */
- d->chip.mask(irq);
-
- if (desc->hw.ack_regs)
- ack_handle[irq] = intc_ack_data(desc, d, enum_id);
-
-#ifdef CONFIG_INTC_BALANCING
- if (desc->hw.mask_regs)
- dist_handle[irq] = intc_dist_data(desc, d, enum_id);
-#endif
-
-#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */
-#endif
-}
-
-static unsigned int __init save_reg(struct intc_desc_int *d,
- unsigned int cnt,
- unsigned long value,
- unsigned int smp)
-{
- if (value) {
- value = intc_phys_to_virt(d, value);
-
- d->reg[cnt] = value;
-#ifdef CONFIG_SMP
- d->smp[cnt] = smp;
-#endif
- return 1;
- }
-
- return 0;
-}
-
-static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc)
-{
- generic_handle_irq((unsigned int)get_irq_data(irq));
-}
-
-int __init register_intc_controller(struct intc_desc *desc)
-{
- unsigned int i, k, smp;
- struct intc_hw_desc *hw = &desc->hw;
- struct intc_desc_int *d;
- struct resource *res;
-
- pr_info("Registered controller '%s' with %u IRQs\n",
- desc->name, hw->nr_vectors);
-
- d = kzalloc(sizeof(*d), GFP_NOWAIT);
- if (!d)
- goto err0;
-
- INIT_LIST_HEAD(&d->list);
- list_add(&d->list, &intc_list);
-
- if (desc->num_resources) {
- d->nr_windows = desc->num_resources;
- d->window = kzalloc(d->nr_windows * sizeof(*d->window),
- GFP_NOWAIT);
- if (!d->window)
- goto err1;
-
- for (k = 0; k < d->nr_windows; k++) {
- res = desc->resource + k;
- WARN_ON(resource_type(res) != IORESOURCE_MEM);
- d->window[k].phys = res->start;
- d->window[k].size = resource_size(res);
- d->window[k].virt = ioremap_nocache(res->start,
- resource_size(res));
- if (!d->window[k].virt)
- goto err2;
- }
- }
-
- d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
-#ifdef CONFIG_INTC_BALANCING
- if (d->nr_reg)
- d->nr_reg += hw->nr_mask_regs;
-#endif
- d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
- d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
- d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0;
-
- d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
- if (!d->reg)
- goto err2;
-
-#ifdef CONFIG_SMP
- d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
- if (!d->smp)
- goto err3;
-#endif
- k = 0;
-
- if (hw->mask_regs) {
- for (i = 0; i < hw->nr_mask_regs; i++) {
- smp = IS_SMP(hw->mask_regs[i]);
- k += save_reg(d, k, hw->mask_regs[i].set_reg, smp);
- k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp);
-#ifdef CONFIG_INTC_BALANCING
- k += save_reg(d, k, hw->mask_regs[i].dist_reg, 0);
-#endif
- }
- }
-
- if (hw->prio_regs) {
- d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio),
- GFP_NOWAIT);
- if (!d->prio)
- goto err4;
-
- for (i = 0; i < hw->nr_prio_regs; i++) {
- smp = IS_SMP(hw->prio_regs[i]);
- k += save_reg(d, k, hw->prio_regs[i].set_reg, smp);
- k += save_reg(d, k, hw->prio_regs[i].clr_reg, smp);
- }
- }
-
- if (hw->sense_regs) {
- d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense),
- GFP_NOWAIT);
- if (!d->sense)
- goto err5;
-
- for (i = 0; i < hw->nr_sense_regs; i++)
- k += save_reg(d, k, hw->sense_regs[i].reg, 0);
- }
-
- d->chip.name = desc->name;
- d->chip.mask = intc_disable;
- d->chip.unmask = intc_enable;
- d->chip.mask_ack = intc_disable;
- d->chip.enable = intc_enable;
- d->chip.disable = intc_disable;
- d->chip.shutdown = intc_disable;
- d->chip.set_type = intc_set_sense;
- d->chip.set_wake = intc_set_wake;
-#ifdef CONFIG_SMP
- d->chip.set_affinity = intc_set_affinity;
-#endif
-
- if (hw->ack_regs) {
- for (i = 0; i < hw->nr_ack_regs; i++)
- k += save_reg(d, k, hw->ack_regs[i].set_reg, 0);
-
- d->chip.mask_ack = intc_mask_ack;
- }
-
- /* disable bits matching force_disable before registering irqs */
- if (desc->force_disable)
- intc_enable_disable_enum(desc, d, desc->force_disable, 0);
-
- /* disable bits matching force_enable before registering irqs */
- if (desc->force_enable)
- intc_enable_disable_enum(desc, d, desc->force_enable, 0);
-
- BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
-
- /* register the vectors one by one */
- for (i = 0; i < hw->nr_vectors; i++) {
- struct intc_vect *vect = hw->vectors + i;
- unsigned int irq = evt2irq(vect->vect);
- struct irq_desc *irq_desc;
-
- if (!vect->enum_id)
- continue;
-
- irq_desc = irq_to_desc_alloc_node(irq, numa_node_id());
- if (unlikely(!irq_desc)) {
- pr_err("can't get irq_desc for %d\n", irq);
- continue;
- }
-
- intc_register_irq(desc, d, vect->enum_id, irq);
-
- for (k = i + 1; k < hw->nr_vectors; k++) {
- struct intc_vect *vect2 = hw->vectors + k;
- unsigned int irq2 = evt2irq(vect2->vect);
-
- if (vect->enum_id != vect2->enum_id)
- continue;
-
- /*
- * In the case of multi-evt handling and sparse
- * IRQ support, each vector still needs to have
- * its own backing irq_desc.
- */
- irq_desc = irq_to_desc_alloc_node(irq2, numa_node_id());
- if (unlikely(!irq_desc)) {
- pr_err("can't get irq_desc for %d\n", irq2);
- continue;
- }
-
- vect2->enum_id = 0;
-
- /* redirect this interrupts to the first one */
- set_irq_chip(irq2, &dummy_irq_chip);
- set_irq_chained_handler(irq2, intc_redirect_irq);
- set_irq_data(irq2, (void *)irq);
- }
- }
-
- /* enable bits matching force_enable after registering irqs */
- if (desc->force_enable)
- intc_enable_disable_enum(desc, d, desc->force_enable, 1);
-
- return 0;
-err5:
- kfree(d->prio);
-err4:
-#ifdef CONFIG_SMP
- kfree(d->smp);
-err3:
-#endif
- kfree(d->reg);
-err2:
- for (k = 0; k < d->nr_windows; k++)
- if (d->window[k].virt)
- iounmap(d->window[k].virt);
-
- kfree(d->window);
-err1:
- kfree(d);
-err0:
- pr_err("unable to allocate INTC memory\n");
-
- return -ENOMEM;
-}
-
-#ifdef CONFIG_INTC_USERIMASK
-static void __iomem *uimask;
-
-int register_intc_userimask(unsigned long addr)
-{
- if (unlikely(uimask))
- return -EBUSY;
-
- uimask = ioremap_nocache(addr, SZ_4K);
- if (unlikely(!uimask))
- return -ENOMEM;
-
- pr_info("userimask support registered for levels 0 -> %d\n",
- default_prio_level - 1);
-
- return 0;
-}
-
-static ssize_t
-show_intc_userimask(struct sysdev_class *cls,
- struct sysdev_class_attribute *attr, char *buf)
-{
- return sprintf(buf, "%d\n", (__raw_readl(uimask) >> 4) & 0xf);
-}
-
-static ssize_t
-store_intc_userimask(struct sysdev_class *cls,
- struct sysdev_class_attribute *attr,
- const char *buf, size_t count)
-{
- unsigned long level;
-
- level = simple_strtoul(buf, NULL, 10);
-
- /*
- * Minimal acceptable IRQ levels are in the 2 - 16 range, but
- * these are chomped so as to not interfere with normal IRQs.
- *
- * Level 1 is a special case on some CPUs in that it's not
- * directly settable, but given that USERIMASK cuts off below a
- * certain level, we don't care about this limitation here.
- * Level 0 on the other hand equates to user masking disabled.
- *
- * We use default_prio_level as a cut off so that only special
- * case opt-in IRQs can be mangled.
- */
- if (level >= default_prio_level)
- return -EINVAL;
-
- __raw_writel(0xa5 << 24 | level << 4, uimask);
-
- return count;
-}
-
-static SYSDEV_CLASS_ATTR(userimask, S_IRUSR | S_IWUSR,
- show_intc_userimask, store_intc_userimask);
-#endif
-
-static ssize_t
-show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf)
-{
- struct intc_desc_int *d;
-
- d = container_of(dev, struct intc_desc_int, sysdev);
-
- return sprintf(buf, "%s\n", d->chip.name);
-}
-
-static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL);
-
-static int intc_suspend(struct sys_device *dev, pm_message_t state)
-{
- struct intc_desc_int *d;
- struct irq_desc *desc;
- int irq;
-
- /* get intc controller associated with this sysdev */
- d = container_of(dev, struct intc_desc_int, sysdev);
-
- switch (state.event) {
- case PM_EVENT_ON:
- if (d->state.event != PM_EVENT_FREEZE)
- break;
- for_each_irq_desc(irq, desc) {
- if (desc->handle_irq == intc_redirect_irq)
- continue;
- if (desc->chip != &d->chip)
- continue;
- if (desc->status & IRQ_DISABLED)
- intc_disable(irq);
- else
- intc_enable(irq);
- }
- break;
- case PM_EVENT_FREEZE:
- /* nothing has to be done */
- break;
- case PM_EVENT_SUSPEND:
- /* enable wakeup irqs belonging to this intc controller */
- for_each_irq_desc(irq, desc) {
- if ((desc->status & IRQ_WAKEUP) && (desc->chip == &d->chip))
- intc_enable(irq);
- }
- break;
- }
- d->state = state;
-
- return 0;
-}
-
-static int intc_resume(struct sys_device *dev)
-{
- return intc_suspend(dev, PMSG_ON);
-}
-
-static struct sysdev_class intc_sysdev_class = {
- .name = "intc",
- .suspend = intc_suspend,
- .resume = intc_resume,
-};
-
-/* register this intc as sysdev to allow suspend/resume */
-static int __init register_intc_sysdevs(void)
-{
- struct intc_desc_int *d;
- int error;
- int id = 0;
-
- error = sysdev_class_register(&intc_sysdev_class);
-#ifdef CONFIG_INTC_USERIMASK
- if (!error && uimask)
- error = sysdev_class_create_file(&intc_sysdev_class,
- &attr_userimask);
-#endif
- if (!error) {
- list_for_each_entry(d, &intc_list, list) {
- d->sysdev.id = id;
- d->sysdev.cls = &intc_sysdev_class;
- error = sysdev_register(&d->sysdev);
- if (error == 0)
- error = sysdev_create_file(&d->sysdev,
- &attr_name);
- if (error)
- break;
-
- id++;
- }
- }
-
- if (error)
- pr_err("sysdev registration error\n");
-
- return error;
-}
-device_initcall(register_intc_sysdevs);
-
-/*
- * Dynamic IRQ allocation and deallocation
- */
-unsigned int create_irq_nr(unsigned int irq_want, int node)
-{
- unsigned int irq = 0, new;
- unsigned long flags;
- struct irq_desc *desc;
-
- spin_lock_irqsave(&vector_lock, flags);
-
- /*
- * First try the wanted IRQ
- */
- if (test_and_set_bit(irq_want, intc_irq_map) == 0) {
- new = irq_want;
- } else {
- /* .. then fall back to scanning. */
- new = find_first_zero_bit(intc_irq_map, nr_irqs);
- if (unlikely(new == nr_irqs))
- goto out_unlock;
-
- __set_bit(new, intc_irq_map);
- }
-
- desc = irq_to_desc_alloc_node(new, node);
- if (unlikely(!desc)) {
- pr_err("can't get irq_desc for %d\n", new);
- goto out_unlock;
- }
-
- desc = move_irq_desc(desc, node);
- irq = new;
-
-out_unlock:
- spin_unlock_irqrestore(&vector_lock, flags);
-
- if (irq > 0) {
- dynamic_irq_init(irq);
-#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */
-#endif
- }
-
- return irq;
-}
-
-int create_irq(void)
-{
- int nid = cpu_to_node(smp_processor_id());
- int irq;
-
- irq = create_irq_nr(NR_IRQS_LEGACY, nid);
- if (irq == 0)
- irq = -1;
-
- return irq;
-}
-
-void destroy_irq(unsigned int irq)
-{
- unsigned long flags;
-
- dynamic_irq_cleanup(irq);
-
- spin_lock_irqsave(&vector_lock, flags);
- __clear_bit(irq, intc_irq_map);
- spin_unlock_irqrestore(&vector_lock, flags);
-}
-
-int reserve_irq_vector(unsigned int irq)
-{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&vector_lock, flags);
- if (test_and_set_bit(irq, intc_irq_map))
- ret = -EBUSY;
- spin_unlock_irqrestore(&vector_lock, flags);
-
- return ret;
-}
-
-void reserve_irq_legacy(void)
-{
- unsigned long flags;
- int i, j;
-
- spin_lock_irqsave(&vector_lock, flags);
- j = find_first_bit(intc_irq_map, nr_irqs);
- for (i = 0; i < j; i++)
- __set_bit(i, intc_irq_map);
- spin_unlock_irqrestore(&vector_lock, flags);
-}
diff --git a/drivers/sh/intc/Kconfig b/drivers/sh/intc/Kconfig
new file mode 100644
index 000000000000..c88cbccc62b0
--- /dev/null
+++ b/drivers/sh/intc/Kconfig
@@ -0,0 +1,35 @@
+comment "Interrupt controller options"
+
+config INTC_USERIMASK
+ bool "Userspace interrupt masking support"
+ depends on ARCH_SHMOBILE || (SUPERH && CPU_SH4A)
+ help
+ This enables support for hardware-assisted userspace hardirq
+ masking.
+
+ SH-4A and newer interrupt blocks all support a special shadowed
+ page with all non-masking registers obscured when mapped in to
+ userspace. This is primarily for use by userspace device
+ drivers that are using special priority levels.
+
+ If in doubt, say N.
+
+config INTC_BALANCING
+ bool "Hardware IRQ balancing support"
+ depends on SMP && SUPERH && CPU_SHX3
+ help
+ This enables support for IRQ auto-distribution mode on SH-X3
+ SMP parts. All of the balancing and CPU wakeup decisions are
+ taken care of automatically by hardware for distributed
+ vectors.
+
+ If in doubt, say N.
+
+config INTC_MAPPING_DEBUG
+ bool "Expose IRQ to per-controller id mapping via debugfs"
+ depends on DEBUG_FS
+ help
+ This will create a debugfs entry for showing the relationship
+ between system IRQs and the per-controller id tables.
+
+ If in doubt, say N.
diff --git a/drivers/sh/intc/Makefile b/drivers/sh/intc/Makefile
new file mode 100644
index 000000000000..bb5df868d77a
--- /dev/null
+++ b/drivers/sh/intc/Makefile
@@ -0,0 +1,5 @@
+obj-y := access.o chip.o core.o dynamic.o handle.o virq.o
+
+obj-$(CONFIG_INTC_BALANCING) += balancing.o
+obj-$(CONFIG_INTC_USERIMASK) += userimask.o
+obj-$(CONFIG_INTC_MAPPING_DEBUG) += virq-debugfs.o
diff --git a/drivers/sh/intc/access.c b/drivers/sh/intc/access.c
new file mode 100644
index 000000000000..f892ae1d212a
--- /dev/null
+++ b/drivers/sh/intc/access.c
@@ -0,0 +1,237 @@
+/*
+ * Common INTC2 register accessors
+ *
+ * Copyright (C) 2007, 2008 Magnus Damm
+ * Copyright (C) 2009, 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/io.h>
+#include "internals.h"
+
+unsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address)
+{
+ struct intc_window *window;
+ int k;
+
+ /* scan through physical windows and convert address */
+ for (k = 0; k < d->nr_windows; k++) {
+ window = d->window + k;
+
+ if (address < window->phys)
+ continue;
+
+ if (address >= (window->phys + window->size))
+ continue;
+
+ address -= window->phys;
+ address += (unsigned long)window->virt;
+
+ return address;
+ }
+
+ /* no windows defined, register must be 1:1 mapped virt:phys */
+ return address;
+}
+
+unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
+{
+ unsigned int k;
+
+ address = intc_phys_to_virt(d, address);
+
+ for (k = 0; k < d->nr_reg; k++) {
+ if (d->reg[k] == address)
+ return k;
+ }
+
+ BUG();
+ return 0;
+}
+
+unsigned int intc_set_field_from_handle(unsigned int value,
+ unsigned int field_value,
+ unsigned int handle)
+{
+ unsigned int width = _INTC_WIDTH(handle);
+ unsigned int shift = _INTC_SHIFT(handle);
+
+ value &= ~(((1 << width) - 1) << shift);
+ value |= field_value << shift;
+ return value;
+}
+
+unsigned long intc_get_field_from_handle(unsigned int value, unsigned int handle)
+{
+ unsigned int width = _INTC_WIDTH(handle);
+ unsigned int shift = _INTC_SHIFT(handle);
+ unsigned int mask = ((1 << width) - 1) << shift;
+
+ return (value & mask) >> shift;
+}
+
+static unsigned long test_8(unsigned long addr, unsigned long h,
+ unsigned long ignore)
+{
+ return intc_get_field_from_handle(__raw_readb(addr), h);
+}
+
+static unsigned long test_16(unsigned long addr, unsigned long h,
+ unsigned long ignore)
+{
+ return intc_get_field_from_handle(__raw_readw(addr), h);
+}
+
+static unsigned long test_32(unsigned long addr, unsigned long h,
+ unsigned long ignore)
+{
+ return intc_get_field_from_handle(__raw_readl(addr), h);
+}
+
+static unsigned long write_8(unsigned long addr, unsigned long h,
+ unsigned long data)
+{
+ __raw_writeb(intc_set_field_from_handle(0, data, h), addr);
+ (void)__raw_readb(addr); /* Defeat write posting */
+ return 0;
+}
+
+static unsigned long write_16(unsigned long addr, unsigned long h,
+ unsigned long data)
+{
+ __raw_writew(intc_set_field_from_handle(0, data, h), addr);
+ (void)__raw_readw(addr); /* Defeat write posting */
+ return 0;
+}
+
+static unsigned long write_32(unsigned long addr, unsigned long h,
+ unsigned long data)
+{
+ __raw_writel(intc_set_field_from_handle(0, data, h), addr);
+ (void)__raw_readl(addr); /* Defeat write posting */
+ return 0;
+}
+
+static unsigned long modify_8(unsigned long addr, unsigned long h,
+ unsigned long data)
+{
+ unsigned long flags;
+ unsigned int value;
+ local_irq_save(flags);
+ value = intc_set_field_from_handle(__raw_readb(addr), data, h);
+ __raw_writeb(value, addr);
+ (void)__raw_readb(addr); /* Defeat write posting */
+ local_irq_restore(flags);
+ return 0;
+}
+
+static unsigned long modify_16(unsigned long addr, unsigned long h,
+ unsigned long data)
+{
+ unsigned long flags;
+ unsigned int value;
+ local_irq_save(flags);
+ value = intc_set_field_from_handle(__raw_readw(addr), data, h);
+ __raw_writew(value, addr);
+ (void)__raw_readw(addr); /* Defeat write posting */
+ local_irq_restore(flags);
+ return 0;
+}
+
+static unsigned long modify_32(unsigned long addr, unsigned long h,
+ unsigned long data)
+{
+ unsigned long flags;
+ unsigned int value;
+ local_irq_save(flags);
+ value = intc_set_field_from_handle(__raw_readl(addr), data, h);
+ __raw_writel(value, addr);
+ (void)__raw_readl(addr); /* Defeat write posting */
+ local_irq_restore(flags);
+ return 0;
+}
+
+static unsigned long intc_mode_field(unsigned long addr,
+ unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq)
+{
+ return fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
+}
+
+static unsigned long intc_mode_zero(unsigned long addr,
+ unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq)
+{
+ return fn(addr, handle, 0);
+}
+
+static unsigned long intc_mode_prio(unsigned long addr,
+ unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq)
+{
+ return fn(addr, handle, intc_get_prio_level(irq));
+}
+
+unsigned long (*intc_reg_fns[])(unsigned long addr,
+ unsigned long h,
+ unsigned long data) = {
+ [REG_FN_TEST_BASE + 0] = test_8,
+ [REG_FN_TEST_BASE + 1] = test_16,
+ [REG_FN_TEST_BASE + 3] = test_32,
+ [REG_FN_WRITE_BASE + 0] = write_8,
+ [REG_FN_WRITE_BASE + 1] = write_16,
+ [REG_FN_WRITE_BASE + 3] = write_32,
+ [REG_FN_MODIFY_BASE + 0] = modify_8,
+ [REG_FN_MODIFY_BASE + 1] = modify_16,
+ [REG_FN_MODIFY_BASE + 3] = modify_32,
+};
+
+unsigned long (*intc_enable_fns[])(unsigned long addr,
+ unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq) = {
+ [MODE_ENABLE_REG] = intc_mode_field,
+ [MODE_MASK_REG] = intc_mode_zero,
+ [MODE_DUAL_REG] = intc_mode_field,
+ [MODE_PRIO_REG] = intc_mode_prio,
+ [MODE_PCLR_REG] = intc_mode_prio,
+};
+
+unsigned long (*intc_disable_fns[])(unsigned long addr,
+ unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq) = {
+ [MODE_ENABLE_REG] = intc_mode_zero,
+ [MODE_MASK_REG] = intc_mode_field,
+ [MODE_DUAL_REG] = intc_mode_field,
+ [MODE_PRIO_REG] = intc_mode_zero,
+ [MODE_PCLR_REG] = intc_mode_field,
+};
+
+unsigned long (*intc_enable_noprio_fns[])(unsigned long addr,
+ unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long,
+ unsigned long),
+ unsigned int irq) = {
+ [MODE_ENABLE_REG] = intc_mode_field,
+ [MODE_MASK_REG] = intc_mode_zero,
+ [MODE_DUAL_REG] = intc_mode_field,
+ [MODE_PRIO_REG] = intc_mode_field,
+ [MODE_PCLR_REG] = intc_mode_field,
+};
diff --git a/drivers/sh/intc/balancing.c b/drivers/sh/intc/balancing.c
new file mode 100644
index 000000000000..cec7a96f2c09
--- /dev/null
+++ b/drivers/sh/intc/balancing.c
@@ -0,0 +1,97 @@
+/*
+ * Support for hardware-managed IRQ auto-distribution.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include "internals.h"
+
+static unsigned long dist_handle[NR_IRQS];
+
+void intc_balancing_enable(unsigned int irq)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long handle = dist_handle[irq];
+ unsigned long addr;
+
+ if (irq_balancing_disabled(irq) || !handle)
+ return;
+
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
+ intc_reg_fns[_INTC_FN(handle)](addr, handle, 1);
+}
+
+void intc_balancing_disable(unsigned int irq)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long handle = dist_handle[irq];
+ unsigned long addr;
+
+ if (irq_balancing_disabled(irq) || !handle)
+ return;
+
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
+ intc_reg_fns[_INTC_FN(handle)](addr, handle, 0);
+}
+
+static unsigned int intc_dist_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id)
+{
+ struct intc_mask_reg *mr = desc->hw.mask_regs;
+ unsigned int i, j, fn, mode;
+ unsigned long reg_e, reg_d;
+
+ for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) {
+ mr = desc->hw.mask_regs + i;
+
+ /*
+ * Skip this entry if there's no auto-distribution
+ * register associated with it.
+ */
+ if (!mr->dist_reg)
+ continue;
+
+ for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
+ if (mr->enum_ids[j] != enum_id)
+ continue;
+
+ fn = REG_FN_MODIFY_BASE;
+ mode = MODE_ENABLE_REG;
+ reg_e = mr->dist_reg;
+ reg_d = mr->dist_reg;
+
+ fn += (mr->reg_width >> 3) - 1;
+ return _INTC_MK(fn, mode,
+ intc_get_reg(d, reg_e),
+ intc_get_reg(d, reg_d),
+ 1,
+ (mr->reg_width - 1) - j);
+ }
+ }
+
+ /*
+ * It's possible we've gotten here with no distribution options
+ * available for the IRQ in question, so we just skip over those.
+ */
+ return 0;
+}
+
+void intc_set_dist_handle(unsigned int irq, struct intc_desc *desc,
+ struct intc_desc_int *d, intc_enum id)
+{
+ unsigned long flags;
+
+ /*
+ * Nothing to do for this IRQ.
+ */
+ if (!desc->hw.mask_regs)
+ return;
+
+ raw_spin_lock_irqsave(&intc_big_lock, flags);
+ dist_handle[irq] = intc_dist_data(desc, d, id);
+ raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+}
diff --git a/drivers/sh/intc/chip.c b/drivers/sh/intc/chip.c
new file mode 100644
index 000000000000..35c03706cc21
--- /dev/null
+++ b/drivers/sh/intc/chip.c
@@ -0,0 +1,215 @@
+/*
+ * IRQ chip definitions for INTC IRQs.
+ *
+ * Copyright (C) 2007, 2008 Magnus Damm
+ * Copyright (C) 2009, 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/cpumask.h>
+#include <linux/io.h>
+#include "internals.h"
+
+void _intc_enable(unsigned int irq, unsigned long handle)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long addr;
+ unsigned int cpu;
+
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
+#ifdef CONFIG_SMP
+ if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
+ continue;
+#endif
+ addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
+ intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
+ [_INTC_FN(handle)], irq);
+ }
+
+ intc_balancing_enable(irq);
+}
+
+static void intc_enable(unsigned int irq)
+{
+ _intc_enable(irq, (unsigned long)get_irq_chip_data(irq));
+}
+
+static void intc_disable(unsigned int irq)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long handle = (unsigned long)get_irq_chip_data(irq);
+ unsigned long addr;
+ unsigned int cpu;
+
+ intc_balancing_disable(irq);
+
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
+#ifdef CONFIG_SMP
+ if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
+ continue;
+#endif
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
+ intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
+ [_INTC_FN(handle)], irq);
+ }
+}
+
+static int intc_set_wake(unsigned int irq, unsigned int on)
+{
+ return 0; /* allow wakeup, but setup hardware in intc_suspend() */
+}
+
+#ifdef CONFIG_SMP
+/*
+ * This is held with the irq desc lock held, so we don't require any
+ * additional locking here at the intc desc level. The affinity mask is
+ * later tested in the enable/disable paths.
+ */
+static int intc_set_affinity(unsigned int irq, const struct cpumask *cpumask)
+{
+ if (!cpumask_intersects(cpumask, cpu_online_mask))
+ return -1;
+
+ cpumask_copy(irq_to_desc(irq)->affinity, cpumask);
+
+ return 0;
+}
+#endif
+
+static void intc_mask_ack(unsigned int irq)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long handle = intc_get_ack_handle(irq);
+ unsigned long addr;
+
+ intc_disable(irq);
+
+ /* read register and write zero only to the associated bit */
+ if (handle) {
+ unsigned int value;
+
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
+ value = intc_set_field_from_handle(0, 1, handle);
+
+ switch (_INTC_FN(handle)) {
+ case REG_FN_MODIFY_BASE + 0: /* 8bit */
+ __raw_readb(addr);
+ __raw_writeb(0xff ^ value, addr);
+ break;
+ case REG_FN_MODIFY_BASE + 1: /* 16bit */
+ __raw_readw(addr);
+ __raw_writew(0xffff ^ value, addr);
+ break;
+ case REG_FN_MODIFY_BASE + 3: /* 32bit */
+ __raw_readl(addr);
+ __raw_writel(0xffffffff ^ value, addr);
+ break;
+ default:
+ BUG();
+ break;
+ }
+ }
+}
+
+static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
+ unsigned int nr_hp,
+ unsigned int irq)
+{
+ int i;
+
+ /*
+ * this doesn't scale well, but...
+ *
+ * this function should only be used for cerain uncommon
+ * operations such as intc_set_priority() and intc_set_type()
+ * and in those rare cases performance doesn't matter that much.
+ * keeping the memory footprint low is more important.
+ *
+ * one rather simple way to speed this up and still keep the
+ * memory footprint down is to make sure the array is sorted
+ * and then perform a bisect to lookup the irq.
+ */
+ for (i = 0; i < nr_hp; i++) {
+ if ((hp + i)->irq != irq)
+ continue;
+
+ return hp + i;
+ }
+
+ return NULL;
+}
+
+int intc_set_priority(unsigned int irq, unsigned int prio)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ struct intc_handle_int *ihp;
+
+ if (!intc_get_prio_level(irq) || prio <= 1)
+ return -EINVAL;
+
+ ihp = intc_find_irq(d->prio, d->nr_prio, irq);
+ if (ihp) {
+ if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
+ return -EINVAL;
+
+ intc_set_prio_level(irq, prio);
+
+ /*
+ * only set secondary masking method directly
+ * primary masking method is using intc_prio_level[irq]
+ * priority level will be set during next enable()
+ */
+ if (_INTC_FN(ihp->handle) != REG_FN_ERR)
+ _intc_enable(irq, ihp->handle);
+ }
+ return 0;
+}
+
+#define VALID(x) (x | 0x80)
+
+static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
+ [IRQ_TYPE_EDGE_FALLING] = VALID(0),
+ [IRQ_TYPE_EDGE_RISING] = VALID(1),
+ [IRQ_TYPE_LEVEL_LOW] = VALID(2),
+ /* SH7706, SH7707 and SH7709 do not support high level triggered */
+#if !defined(CONFIG_CPU_SUBTYPE_SH7706) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7707) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7709)
+ [IRQ_TYPE_LEVEL_HIGH] = VALID(3),
+#endif
+};
+
+static int intc_set_type(unsigned int irq, unsigned int type)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
+ struct intc_handle_int *ihp;
+ unsigned long addr;
+
+ if (!value)
+ return -EINVAL;
+
+ ihp = intc_find_irq(d->sense, d->nr_sense, irq);
+ if (ihp) {
+ addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
+ intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
+ }
+
+ return 0;
+}
+
+struct irq_chip intc_irq_chip = {
+ .mask = intc_disable,
+ .unmask = intc_enable,
+ .mask_ack = intc_mask_ack,
+ .enable = intc_enable,
+ .disable = intc_disable,
+ .shutdown = intc_disable,
+ .set_type = intc_set_type,
+ .set_wake = intc_set_wake,
+#ifdef CONFIG_SMP
+ .set_affinity = intc_set_affinity,
+#endif
+};
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c
new file mode 100644
index 000000000000..306ed287077a
--- /dev/null
+++ b/drivers/sh/intc/core.c
@@ -0,0 +1,469 @@
+/*
+ * Shared interrupt handling code for IPR and INTC2 types of IRQs.
+ *
+ * Copyright (C) 2007, 2008 Magnus Damm
+ * Copyright (C) 2009, 2010 Paul Mundt
+ *
+ * Based on intc2.c and ipr.c
+ *
+ * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi
+ * Copyright (C) 2000 Kazumoto Kojima
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ * Copyright (C) 2005, 2006 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "intc: " fmt
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/sh_intc.h>
+#include <linux/sysdev.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/radix-tree.h>
+#include "internals.h"
+
+LIST_HEAD(intc_list);
+DEFINE_RAW_SPINLOCK(intc_big_lock);
+unsigned int nr_intc_controllers;
+
+/*
+ * Default priority level
+ * - this needs to be at least 2 for 5-bit priorities on 7780
+ */
+static unsigned int default_prio_level = 2; /* 2 - 16 */
+static unsigned int intc_prio_level[NR_IRQS]; /* for now */
+
+unsigned int intc_get_dfl_prio_level(void)
+{
+ return default_prio_level;
+}
+
+unsigned int intc_get_prio_level(unsigned int irq)
+{
+ return intc_prio_level[irq];
+}
+
+void intc_set_prio_level(unsigned int irq, unsigned int level)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&intc_big_lock, flags);
+ intc_prio_level[irq] = level;
+ raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+}
+
+static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc)
+{
+ generic_handle_irq((unsigned int)get_irq_data(irq));
+}
+
+static void __init intc_register_irq(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id,
+ unsigned int irq)
+{
+ struct intc_handle_int *hp;
+ unsigned int data[2], primary;
+ unsigned long flags;
+
+ /*
+ * Register the IRQ position with the global IRQ map, then insert
+ * it in to the radix tree.
+ */
+ reserve_irq_vector(irq);
+
+ raw_spin_lock_irqsave(&intc_big_lock, flags);
+ radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq));
+ raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+
+ /*
+ * Prefer single interrupt source bitmap over other combinations:
+ *
+ * 1. bitmap, single interrupt source
+ * 2. priority, single interrupt source
+ * 3. bitmap, multiple interrupt sources (groups)
+ * 4. priority, multiple interrupt sources (groups)
+ */
+ data[0] = intc_get_mask_handle(desc, d, enum_id, 0);
+ data[1] = intc_get_prio_handle(desc, d, enum_id, 0);
+
+ primary = 0;
+ if (!data[0] && data[1])
+ primary = 1;
+
+ if (!data[0] && !data[1])
+ pr_warning("missing unique irq mask for irq %d (vect 0x%04x)\n",
+ irq, irq2evt(irq));
+
+ data[0] = data[0] ? data[0] : intc_get_mask_handle(desc, d, enum_id, 1);
+ data[1] = data[1] ? data[1] : intc_get_prio_handle(desc, d, enum_id, 1);
+
+ if (!data[primary])
+ primary ^= 1;
+
+ BUG_ON(!data[primary]); /* must have primary masking method */
+
+ disable_irq_nosync(irq);
+ set_irq_chip_and_handler_name(irq, &d->chip,
+ handle_level_irq, "level");
+ set_irq_chip_data(irq, (void *)data[primary]);
+
+ /*
+ * set priority level
+ */
+ intc_set_prio_level(irq, intc_get_dfl_prio_level());
+
+ /* enable secondary masking method if present */
+ if (data[!primary])
+ _intc_enable(irq, data[!primary]);
+
+ /* add irq to d->prio list if priority is available */
+ if (data[1]) {
+ hp = d->prio + d->nr_prio;
+ hp->irq = irq;
+ hp->handle = data[1];
+
+ if (primary) {
+ /*
+ * only secondary priority should access registers, so
+ * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
+ */
+ hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
+ hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
+ }
+ d->nr_prio++;
+ }
+
+ /* add irq to d->sense list if sense is available */
+ data[0] = intc_get_sense_handle(desc, d, enum_id);
+ if (data[0]) {
+ (d->sense + d->nr_sense)->irq = irq;
+ (d->sense + d->nr_sense)->handle = data[0];
+ d->nr_sense++;
+ }
+
+ /* irq should be disabled by default */
+ d->chip.mask(irq);
+
+ intc_set_ack_handle(irq, desc, d, enum_id);
+ intc_set_dist_handle(irq, desc, d, enum_id);
+
+ activate_irq(irq);
+}
+
+static unsigned int __init save_reg(struct intc_desc_int *d,
+ unsigned int cnt,
+ unsigned long value,
+ unsigned int smp)
+{
+ if (value) {
+ value = intc_phys_to_virt(d, value);
+
+ d->reg[cnt] = value;
+#ifdef CONFIG_SMP
+ d->smp[cnt] = smp;
+#endif
+ return 1;
+ }
+
+ return 0;
+}
+
+int __init register_intc_controller(struct intc_desc *desc)
+{
+ unsigned int i, k, smp;
+ struct intc_hw_desc *hw = &desc->hw;
+ struct intc_desc_int *d;
+ struct resource *res;
+
+ pr_info("Registered controller '%s' with %u IRQs\n",
+ desc->name, hw->nr_vectors);
+
+ d = kzalloc(sizeof(*d), GFP_NOWAIT);
+ if (!d)
+ goto err0;
+
+ INIT_LIST_HEAD(&d->list);
+ list_add_tail(&d->list, &intc_list);
+
+ raw_spin_lock_init(&d->lock);
+
+ d->index = nr_intc_controllers;
+
+ if (desc->num_resources) {
+ d->nr_windows = desc->num_resources;
+ d->window = kzalloc(d->nr_windows * sizeof(*d->window),
+ GFP_NOWAIT);
+ if (!d->window)
+ goto err1;
+
+ for (k = 0; k < d->nr_windows; k++) {
+ res = desc->resource + k;
+ WARN_ON(resource_type(res) != IORESOURCE_MEM);
+ d->window[k].phys = res->start;
+ d->window[k].size = resource_size(res);
+ d->window[k].virt = ioremap_nocache(res->start,
+ resource_size(res));
+ if (!d->window[k].virt)
+ goto err2;
+ }
+ }
+
+ d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
+#ifdef CONFIG_INTC_BALANCING
+ if (d->nr_reg)
+ d->nr_reg += hw->nr_mask_regs;
+#endif
+ d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
+ d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
+ d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0;
+ d->nr_reg += hw->subgroups ? hw->nr_subgroups : 0;
+
+ d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
+ if (!d->reg)
+ goto err2;
+
+#ifdef CONFIG_SMP
+ d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
+ if (!d->smp)
+ goto err3;
+#endif
+ k = 0;
+
+ if (hw->mask_regs) {
+ for (i = 0; i < hw->nr_mask_regs; i++) {
+ smp = IS_SMP(hw->mask_regs[i]);
+ k += save_reg(d, k, hw->mask_regs[i].set_reg, smp);
+ k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp);
+#ifdef CONFIG_INTC_BALANCING
+ k += save_reg(d, k, hw->mask_regs[i].dist_reg, 0);
+#endif
+ }
+ }
+
+ if (hw->prio_regs) {
+ d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio),
+ GFP_NOWAIT);
+ if (!d->prio)
+ goto err4;
+
+ for (i = 0; i < hw->nr_prio_regs; i++) {
+ smp = IS_SMP(hw->prio_regs[i]);
+ k += save_reg(d, k, hw->prio_regs[i].set_reg, smp);
+ k += save_reg(d, k, hw->prio_regs[i].clr_reg, smp);
+ }
+ }
+
+ if (hw->sense_regs) {
+ d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense),
+ GFP_NOWAIT);
+ if (!d->sense)
+ goto err5;
+
+ for (i = 0; i < hw->nr_sense_regs; i++)
+ k += save_reg(d, k, hw->sense_regs[i].reg, 0);
+ }
+
+ if (hw->subgroups)
+ for (i = 0; i < hw->nr_subgroups; i++)
+ if (hw->subgroups[i].reg)
+ k+= save_reg(d, k, hw->subgroups[i].reg, 0);
+
+ memcpy(&d->chip, &intc_irq_chip, sizeof(struct irq_chip));
+ d->chip.name = desc->name;
+
+ if (hw->ack_regs)
+ for (i = 0; i < hw->nr_ack_regs; i++)
+ k += save_reg(d, k, hw->ack_regs[i].set_reg, 0);
+ else
+ d->chip.mask_ack = d->chip.disable;
+
+ /* disable bits matching force_disable before registering irqs */
+ if (desc->force_disable)
+ intc_enable_disable_enum(desc, d, desc->force_disable, 0);
+
+ /* disable bits matching force_enable before registering irqs */
+ if (desc->force_enable)
+ intc_enable_disable_enum(desc, d, desc->force_enable, 0);
+
+ BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
+
+ /* register the vectors one by one */
+ for (i = 0; i < hw->nr_vectors; i++) {
+ struct intc_vect *vect = hw->vectors + i;
+ unsigned int irq = evt2irq(vect->vect);
+ struct irq_desc *irq_desc;
+
+ if (!vect->enum_id)
+ continue;
+
+ irq_desc = irq_to_desc_alloc_node(irq, numa_node_id());
+ if (unlikely(!irq_desc)) {
+ pr_err("can't get irq_desc for %d\n", irq);
+ continue;
+ }
+
+ intc_irq_xlate_set(irq, vect->enum_id, d);
+ intc_register_irq(desc, d, vect->enum_id, irq);
+
+ for (k = i + 1; k < hw->nr_vectors; k++) {
+ struct intc_vect *vect2 = hw->vectors + k;
+ unsigned int irq2 = evt2irq(vect2->vect);
+
+ if (vect->enum_id != vect2->enum_id)
+ continue;
+
+ /*
+ * In the case of multi-evt handling and sparse
+ * IRQ support, each vector still needs to have
+ * its own backing irq_desc.
+ */
+ irq_desc = irq_to_desc_alloc_node(irq2, numa_node_id());
+ if (unlikely(!irq_desc)) {
+ pr_err("can't get irq_desc for %d\n", irq2);
+ continue;
+ }
+
+ vect2->enum_id = 0;
+
+ /* redirect this interrupts to the first one */
+ set_irq_chip(irq2, &dummy_irq_chip);
+ set_irq_chained_handler(irq2, intc_redirect_irq);
+ set_irq_data(irq2, (void *)irq);
+ }
+ }
+
+ intc_subgroup_init(desc, d);
+
+ /* enable bits matching force_enable after registering irqs */
+ if (desc->force_enable)
+ intc_enable_disable_enum(desc, d, desc->force_enable, 1);
+
+ nr_intc_controllers++;
+
+ return 0;
+err5:
+ kfree(d->prio);
+err4:
+#ifdef CONFIG_SMP
+ kfree(d->smp);
+err3:
+#endif
+ kfree(d->reg);
+err2:
+ for (k = 0; k < d->nr_windows; k++)
+ if (d->window[k].virt)
+ iounmap(d->window[k].virt);
+
+ kfree(d->window);
+err1:
+ kfree(d);
+err0:
+ pr_err("unable to allocate INTC memory\n");
+
+ return -ENOMEM;
+}
+
+static ssize_t
+show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf)
+{
+ struct intc_desc_int *d;
+
+ d = container_of(dev, struct intc_desc_int, sysdev);
+
+ return sprintf(buf, "%s\n", d->chip.name);
+}
+
+static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL);
+
+static int intc_suspend(struct sys_device *dev, pm_message_t state)
+{
+ struct intc_desc_int *d;
+ struct irq_desc *desc;
+ int irq;
+
+ /* get intc controller associated with this sysdev */
+ d = container_of(dev, struct intc_desc_int, sysdev);
+
+ switch (state.event) {
+ case PM_EVENT_ON:
+ if (d->state.event != PM_EVENT_FREEZE)
+ break;
+
+ for_each_irq_desc(irq, desc) {
+ /*
+ * This will catch the redirect and VIRQ cases
+ * due to the dummy_irq_chip being inserted.
+ */
+ if (desc->chip != &d->chip)
+ continue;
+ if (desc->status & IRQ_DISABLED)
+ desc->chip->disable(irq);
+ else
+ desc->chip->enable(irq);
+ }
+ break;
+ case PM_EVENT_FREEZE:
+ /* nothing has to be done */
+ break;
+ case PM_EVENT_SUSPEND:
+ /* enable wakeup irqs belonging to this intc controller */
+ for_each_irq_desc(irq, desc) {
+ if (desc->chip != &d->chip)
+ continue;
+ if ((desc->status & IRQ_WAKEUP))
+ desc->chip->enable(irq);
+ }
+ break;
+ }
+
+ d->state = state;
+
+ return 0;
+}
+
+static int intc_resume(struct sys_device *dev)
+{
+ return intc_suspend(dev, PMSG_ON);
+}
+
+struct sysdev_class intc_sysdev_class = {
+ .name = "intc",
+ .suspend = intc_suspend,
+ .resume = intc_resume,
+};
+
+/* register this intc as sysdev to allow suspend/resume */
+static int __init register_intc_sysdevs(void)
+{
+ struct intc_desc_int *d;
+ int error;
+
+ error = sysdev_class_register(&intc_sysdev_class);
+ if (!error) {
+ list_for_each_entry(d, &intc_list, list) {
+ d->sysdev.id = d->index;
+ d->sysdev.cls = &intc_sysdev_class;
+ error = sysdev_register(&d->sysdev);
+ if (error == 0)
+ error = sysdev_create_file(&d->sysdev,
+ &attr_name);
+ if (error)
+ break;
+ }
+ }
+
+ if (error)
+ pr_err("sysdev registration error\n");
+
+ return error;
+}
+device_initcall(register_intc_sysdevs);
diff --git a/drivers/sh/intc/dynamic.c b/drivers/sh/intc/dynamic.c
new file mode 100644
index 000000000000..6caecdffe201
--- /dev/null
+++ b/drivers/sh/intc/dynamic.c
@@ -0,0 +1,135 @@
+/*
+ * Dynamic IRQ management
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * Modelled after arch/x86/kernel/apic/io_apic.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.
+ */
+#define pr_fmt(fmt) "intc: " fmt
+
+#include <linux/irq.h>
+#include <linux/bitmap.h>
+#include <linux/spinlock.h>
+#include "internals.h" /* only for activate_irq() damage.. */
+
+/*
+ * The intc_irq_map provides a global map of bound IRQ vectors for a
+ * given platform. Allocation of IRQs are either static through the CPU
+ * vector map, or dynamic in the case of board mux vectors or MSI.
+ *
+ * As this is a central point for all IRQ controllers on the system,
+ * each of the available sources are mapped out here. This combined with
+ * sparseirq makes it quite trivial to keep the vector map tightly packed
+ * when dynamically creating IRQs, as well as tying in to otherwise
+ * unused irq_desc positions in the sparse array.
+ */
+static DECLARE_BITMAP(intc_irq_map, NR_IRQS);
+static DEFINE_RAW_SPINLOCK(vector_lock);
+
+/*
+ * Dynamic IRQ allocation and deallocation
+ */
+unsigned int create_irq_nr(unsigned int irq_want, int node)
+{
+ unsigned int irq = 0, new;
+ unsigned long flags;
+ struct irq_desc *desc;
+
+ raw_spin_lock_irqsave(&vector_lock, flags);
+
+ /*
+ * First try the wanted IRQ
+ */
+ if (test_and_set_bit(irq_want, intc_irq_map) == 0) {
+ new = irq_want;
+ } else {
+ /* .. then fall back to scanning. */
+ new = find_first_zero_bit(intc_irq_map, nr_irqs);
+ if (unlikely(new == nr_irqs))
+ goto out_unlock;
+
+ __set_bit(new, intc_irq_map);
+ }
+
+ desc = irq_to_desc_alloc_node(new, node);
+ if (unlikely(!desc)) {
+ pr_err("can't get irq_desc for %d\n", new);
+ goto out_unlock;
+ }
+
+ desc = move_irq_desc(desc, node);
+ irq = new;
+
+out_unlock:
+ raw_spin_unlock_irqrestore(&vector_lock, flags);
+
+ if (irq > 0) {
+ dynamic_irq_init(irq);
+ activate_irq(irq);
+ }
+
+ return irq;
+}
+
+int create_irq(void)
+{
+ int nid = cpu_to_node(smp_processor_id());
+ int irq;
+
+ irq = create_irq_nr(NR_IRQS_LEGACY, nid);
+ if (irq == 0)
+ irq = -1;
+
+ return irq;
+}
+
+void destroy_irq(unsigned int irq)
+{
+ unsigned long flags;
+
+ dynamic_irq_cleanup(irq);
+
+ raw_spin_lock_irqsave(&vector_lock, flags);
+ __clear_bit(irq, intc_irq_map);
+ raw_spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+int reserve_irq_vector(unsigned int irq)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ raw_spin_lock_irqsave(&vector_lock, flags);
+ if (test_and_set_bit(irq, intc_irq_map))
+ ret = -EBUSY;
+ raw_spin_unlock_irqrestore(&vector_lock, flags);
+
+ return ret;
+}
+
+void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs)
+{
+ unsigned long flags;
+ int i;
+
+ raw_spin_lock_irqsave(&vector_lock, flags);
+ for (i = 0; i < nr_vecs; i++)
+ __set_bit(evt2irq(vectors[i].vect), intc_irq_map);
+ raw_spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+void reserve_irq_legacy(void)
+{
+ unsigned long flags;
+ int i, j;
+
+ raw_spin_lock_irqsave(&vector_lock, flags);
+ j = find_first_bit(intc_irq_map, nr_irqs);
+ for (i = 0; i < j; i++)
+ __set_bit(i, intc_irq_map);
+ raw_spin_unlock_irqrestore(&vector_lock, flags);
+}
diff --git a/drivers/sh/intc/handle.c b/drivers/sh/intc/handle.c
new file mode 100644
index 000000000000..057ce56829bf
--- /dev/null
+++ b/drivers/sh/intc/handle.c
@@ -0,0 +1,307 @@
+/*
+ * Shared interrupt handling code for IPR and INTC2 types of IRQs.
+ *
+ * Copyright (C) 2007, 2008 Magnus Damm
+ * Copyright (C) 2009, 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+#include "internals.h"
+
+static unsigned long ack_handle[NR_IRQS];
+
+static intc_enum __init intc_grp_id(struct intc_desc *desc,
+ intc_enum enum_id)
+{
+ struct intc_group *g = desc->hw.groups;
+ unsigned int i, j;
+
+ for (i = 0; g && enum_id && i < desc->hw.nr_groups; i++) {
+ g = desc->hw.groups + i;
+
+ for (j = 0; g->enum_ids[j]; j++) {
+ if (g->enum_ids[j] != enum_id)
+ continue;
+
+ return g->enum_id;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned int __init _intc_mask_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id,
+ unsigned int *reg_idx,
+ unsigned int *fld_idx)
+{
+ struct intc_mask_reg *mr = desc->hw.mask_regs;
+ unsigned int fn, mode;
+ unsigned long reg_e, reg_d;
+
+ while (mr && enum_id && *reg_idx < desc->hw.nr_mask_regs) {
+ mr = desc->hw.mask_regs + *reg_idx;
+
+ for (; *fld_idx < ARRAY_SIZE(mr->enum_ids); (*fld_idx)++) {
+ if (mr->enum_ids[*fld_idx] != enum_id)
+ continue;
+
+ if (mr->set_reg && mr->clr_reg) {
+ fn = REG_FN_WRITE_BASE;
+ mode = MODE_DUAL_REG;
+ reg_e = mr->clr_reg;
+ reg_d = mr->set_reg;
+ } else {
+ fn = REG_FN_MODIFY_BASE;
+ if (mr->set_reg) {
+ mode = MODE_ENABLE_REG;
+ reg_e = mr->set_reg;
+ reg_d = mr->set_reg;
+ } else {
+ mode = MODE_MASK_REG;
+ reg_e = mr->clr_reg;
+ reg_d = mr->clr_reg;
+ }
+ }
+
+ fn += (mr->reg_width >> 3) - 1;
+ return _INTC_MK(fn, mode,
+ intc_get_reg(d, reg_e),
+ intc_get_reg(d, reg_d),
+ 1,
+ (mr->reg_width - 1) - *fld_idx);
+ }
+
+ *fld_idx = 0;
+ (*reg_idx)++;
+ }
+
+ return 0;
+}
+
+unsigned int __init
+intc_get_mask_handle(struct intc_desc *desc, struct intc_desc_int *d,
+ intc_enum enum_id, int do_grps)
+{
+ unsigned int i = 0;
+ unsigned int j = 0;
+ unsigned int ret;
+
+ ret = _intc_mask_data(desc, d, enum_id, &i, &j);
+ if (ret)
+ return ret;
+
+ if (do_grps)
+ return intc_get_mask_handle(desc, d, intc_grp_id(desc, enum_id), 0);
+
+ return 0;
+}
+
+static unsigned int __init _intc_prio_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id,
+ unsigned int *reg_idx,
+ unsigned int *fld_idx)
+{
+ struct intc_prio_reg *pr = desc->hw.prio_regs;
+ unsigned int fn, n, mode, bit;
+ unsigned long reg_e, reg_d;
+
+ while (pr && enum_id && *reg_idx < desc->hw.nr_prio_regs) {
+ pr = desc->hw.prio_regs + *reg_idx;
+
+ for (; *fld_idx < ARRAY_SIZE(pr->enum_ids); (*fld_idx)++) {
+ if (pr->enum_ids[*fld_idx] != enum_id)
+ continue;
+
+ if (pr->set_reg && pr->clr_reg) {
+ fn = REG_FN_WRITE_BASE;
+ mode = MODE_PCLR_REG;
+ reg_e = pr->set_reg;
+ reg_d = pr->clr_reg;
+ } else {
+ fn = REG_FN_MODIFY_BASE;
+ mode = MODE_PRIO_REG;
+ if (!pr->set_reg)
+ BUG();
+ reg_e = pr->set_reg;
+ reg_d = pr->set_reg;
+ }
+
+ fn += (pr->reg_width >> 3) - 1;
+ n = *fld_idx + 1;
+
+ BUG_ON(n * pr->field_width > pr->reg_width);
+
+ bit = pr->reg_width - (n * pr->field_width);
+
+ return _INTC_MK(fn, mode,
+ intc_get_reg(d, reg_e),
+ intc_get_reg(d, reg_d),
+ pr->field_width, bit);
+ }
+
+ *fld_idx = 0;
+ (*reg_idx)++;
+ }
+
+ return 0;
+}
+
+unsigned int __init
+intc_get_prio_handle(struct intc_desc *desc, struct intc_desc_int *d,
+ intc_enum enum_id, int do_grps)
+{
+ unsigned int i = 0;
+ unsigned int j = 0;
+ unsigned int ret;
+
+ ret = _intc_prio_data(desc, d, enum_id, &i, &j);
+ if (ret)
+ return ret;
+
+ if (do_grps)
+ return intc_get_prio_handle(desc, d, intc_grp_id(desc, enum_id), 0);
+
+ return 0;
+}
+
+static unsigned int __init intc_ack_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id)
+{
+ struct intc_mask_reg *mr = desc->hw.ack_regs;
+ unsigned int i, j, fn, mode;
+ unsigned long reg_e, reg_d;
+
+ for (i = 0; mr && enum_id && i < desc->hw.nr_ack_regs; i++) {
+ mr = desc->hw.ack_regs + i;
+
+ for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
+ if (mr->enum_ids[j] != enum_id)
+ continue;
+
+ fn = REG_FN_MODIFY_BASE;
+ mode = MODE_ENABLE_REG;
+ reg_e = mr->set_reg;
+ reg_d = mr->set_reg;
+
+ fn += (mr->reg_width >> 3) - 1;
+ return _INTC_MK(fn, mode,
+ intc_get_reg(d, reg_e),
+ intc_get_reg(d, reg_d),
+ 1,
+ (mr->reg_width - 1) - j);
+ }
+ }
+
+ return 0;
+}
+
+static void intc_enable_disable(struct intc_desc_int *d,
+ unsigned long handle, int do_enable)
+{
+ unsigned long addr;
+ unsigned int cpu;
+ unsigned long (*fn)(unsigned long, unsigned long,
+ unsigned long (*)(unsigned long, unsigned long,
+ unsigned long),
+ unsigned int);
+
+ if (do_enable) {
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
+ addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
+ fn = intc_enable_noprio_fns[_INTC_MODE(handle)];
+ fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
+ }
+ } else {
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
+ fn = intc_disable_fns[_INTC_MODE(handle)];
+ fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
+ }
+ }
+}
+
+void __init intc_enable_disable_enum(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id, int enable)
+{
+ unsigned int i, j, data;
+
+ /* go through and enable/disable all mask bits */
+ i = j = 0;
+ do {
+ data = _intc_mask_data(desc, d, enum_id, &i, &j);
+ if (data)
+ intc_enable_disable(d, data, enable);
+ j++;
+ } while (data);
+
+ /* go through and enable/disable all priority fields */
+ i = j = 0;
+ do {
+ data = _intc_prio_data(desc, d, enum_id, &i, &j);
+ if (data)
+ intc_enable_disable(d, data, enable);
+
+ j++;
+ } while (data);
+}
+
+unsigned int __init
+intc_get_sense_handle(struct intc_desc *desc, struct intc_desc_int *d,
+ intc_enum enum_id)
+{
+ struct intc_sense_reg *sr = desc->hw.sense_regs;
+ unsigned int i, j, fn, bit;
+
+ for (i = 0; sr && enum_id && i < desc->hw.nr_sense_regs; i++) {
+ sr = desc->hw.sense_regs + i;
+
+ for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
+ if (sr->enum_ids[j] != enum_id)
+ continue;
+
+ fn = REG_FN_MODIFY_BASE;
+ fn += (sr->reg_width >> 3) - 1;
+
+ BUG_ON((j + 1) * sr->field_width > sr->reg_width);
+
+ bit = sr->reg_width - ((j + 1) * sr->field_width);
+
+ return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg),
+ 0, sr->field_width, bit);
+ }
+ }
+
+ return 0;
+}
+
+
+void intc_set_ack_handle(unsigned int irq, struct intc_desc *desc,
+ struct intc_desc_int *d, intc_enum id)
+{
+ unsigned long flags;
+
+ /*
+ * Nothing to do for this IRQ.
+ */
+ if (!desc->hw.ack_regs)
+ return;
+
+ raw_spin_lock_irqsave(&intc_big_lock, flags);
+ ack_handle[irq] = intc_ack_data(desc, d, id);
+ raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+}
+
+unsigned long intc_get_ack_handle(unsigned int irq)
+{
+ return ack_handle[irq];
+}
diff --git a/drivers/sh/intc/internals.h b/drivers/sh/intc/internals.h
new file mode 100644
index 000000000000..d49482c623fa
--- /dev/null
+++ b/drivers/sh/intc/internals.h
@@ -0,0 +1,186 @@
+#include <linux/sh_intc.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/radix-tree.h>
+#include <linux/sysdev.h>
+
+#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
+ ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
+ ((addr_e) << 16) | ((addr_d << 24)))
+
+#define _INTC_SHIFT(h) (h & 0x1f)
+#define _INTC_WIDTH(h) ((h >> 5) & 0xf)
+#define _INTC_FN(h) ((h >> 9) & 0xf)
+#define _INTC_MODE(h) ((h >> 13) & 0x7)
+#define _INTC_ADDR_E(h) ((h >> 16) & 0xff)
+#define _INTC_ADDR_D(h) ((h >> 24) & 0xff)
+
+#ifdef CONFIG_SMP
+#define IS_SMP(x) (x.smp)
+#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
+#define SMP_NR(d, x) ((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1)
+#else
+#define IS_SMP(x) 0
+#define INTC_REG(d, x, c) (d->reg[(x)])
+#define SMP_NR(d, x) 1
+#endif
+
+struct intc_handle_int {
+ unsigned int irq;
+ unsigned long handle;
+};
+
+struct intc_window {
+ phys_addr_t phys;
+ void __iomem *virt;
+ unsigned long size;
+};
+
+struct intc_map_entry {
+ intc_enum enum_id;
+ struct intc_desc_int *desc;
+};
+
+struct intc_subgroup_entry {
+ unsigned int pirq;
+ intc_enum enum_id;
+ unsigned long handle;
+};
+
+struct intc_desc_int {
+ struct list_head list;
+ struct sys_device sysdev;
+ struct radix_tree_root tree;
+ pm_message_t state;
+ raw_spinlock_t lock;
+ unsigned int index;
+ unsigned long *reg;
+#ifdef CONFIG_SMP
+ unsigned long *smp;
+#endif
+ unsigned int nr_reg;
+ struct intc_handle_int *prio;
+ unsigned int nr_prio;
+ struct intc_handle_int *sense;
+ unsigned int nr_sense;
+ struct intc_window *window;
+ unsigned int nr_windows;
+ struct irq_chip chip;
+};
+
+
+enum {
+ REG_FN_ERR = 0,
+ REG_FN_TEST_BASE = 1,
+ REG_FN_WRITE_BASE = 5,
+ REG_FN_MODIFY_BASE = 9
+};
+
+enum { MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */
+ MODE_MASK_REG, /* Bit(s) set -> interrupt disabled */
+ MODE_DUAL_REG, /* Two registers, set bit to enable / disable */
+ MODE_PRIO_REG, /* Priority value written to enable interrupt */
+ MODE_PCLR_REG, /* Above plus all bits set to disable interrupt */
+};
+
+static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
+{
+ struct irq_chip *chip = get_irq_chip(irq);
+
+ return container_of(chip, struct intc_desc_int, chip);
+}
+
+/*
+ * Grumble.
+ */
+static inline void activate_irq(int irq)
+{
+#ifdef CONFIG_ARM
+ /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
+ * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE.
+ */
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ /* same effect on other architectures */
+ set_irq_noprobe(irq);
+#endif
+}
+
+/* access.c */
+extern unsigned long
+(*intc_reg_fns[])(unsigned long addr, unsigned long h, unsigned long data);
+
+extern unsigned long
+(*intc_enable_fns[])(unsigned long addr, unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long, unsigned long),
+ unsigned int irq);
+extern unsigned long
+(*intc_disable_fns[])(unsigned long addr, unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long, unsigned long),
+ unsigned int irq);
+extern unsigned long
+(*intc_enable_noprio_fns[])(unsigned long addr, unsigned long handle,
+ unsigned long (*fn)(unsigned long,
+ unsigned long, unsigned long),
+ unsigned int irq);
+
+unsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address);
+unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address);
+unsigned int intc_set_field_from_handle(unsigned int value,
+ unsigned int field_value,
+ unsigned int handle);
+unsigned long intc_get_field_from_handle(unsigned int value,
+ unsigned int handle);
+
+/* balancing.c */
+#ifdef CONFIG_INTC_BALANCING
+void intc_balancing_enable(unsigned int irq);
+void intc_balancing_disable(unsigned int irq);
+void intc_set_dist_handle(unsigned int irq, struct intc_desc *desc,
+ struct intc_desc_int *d, intc_enum id);
+#else
+static inline void intc_balancing_enable(unsigned int irq) { }
+static inline void intc_balancing_disable(unsigned int irq) { }
+static inline void
+intc_set_dist_handle(unsigned int irq, struct intc_desc *desc,
+ struct intc_desc_int *d, intc_enum id) { }
+#endif
+
+/* chip.c */
+extern struct irq_chip intc_irq_chip;
+void _intc_enable(unsigned int irq, unsigned long handle);
+
+/* core.c */
+extern struct list_head intc_list;
+extern raw_spinlock_t intc_big_lock;
+extern unsigned int nr_intc_controllers;
+extern struct sysdev_class intc_sysdev_class;
+
+unsigned int intc_get_dfl_prio_level(void);
+unsigned int intc_get_prio_level(unsigned int irq);
+void intc_set_prio_level(unsigned int irq, unsigned int level);
+
+/* handle.c */
+unsigned int intc_get_mask_handle(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id, int do_grps);
+unsigned int intc_get_prio_handle(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id, int do_grps);
+unsigned int intc_get_sense_handle(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id);
+void intc_set_ack_handle(unsigned int irq, struct intc_desc *desc,
+ struct intc_desc_int *d, intc_enum id);
+unsigned long intc_get_ack_handle(unsigned int irq);
+void intc_enable_disable_enum(struct intc_desc *desc, struct intc_desc_int *d,
+ intc_enum enum_id, int enable);
+
+/* virq.c */
+void intc_subgroup_init(struct intc_desc *desc, struct intc_desc_int *d);
+void intc_irq_xlate_set(unsigned int irq, intc_enum id, struct intc_desc_int *d);
+struct intc_map_entry *intc_irq_xlate_get(unsigned int irq);
diff --git a/drivers/sh/intc/userimask.c b/drivers/sh/intc/userimask.c
new file mode 100644
index 000000000000..e32304b66cf1
--- /dev/null
+++ b/drivers/sh/intc/userimask.c
@@ -0,0 +1,83 @@
+/*
+ * Support for hardware-assisted userspace interrupt masking.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "intc: " fmt
+
+#include <linux/errno.h>
+#include <linux/sysdev.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/sizes.h>
+#include "internals.h"
+
+static void __iomem *uimask;
+
+static ssize_t
+show_intc_userimask(struct sysdev_class *cls,
+ struct sysdev_class_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", (__raw_readl(uimask) >> 4) & 0xf);
+}
+
+static ssize_t
+store_intc_userimask(struct sysdev_class *cls,
+ struct sysdev_class_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long level;
+
+ level = simple_strtoul(buf, NULL, 10);
+
+ /*
+ * Minimal acceptable IRQ levels are in the 2 - 16 range, but
+ * these are chomped so as to not interfere with normal IRQs.
+ *
+ * Level 1 is a special case on some CPUs in that it's not
+ * directly settable, but given that USERIMASK cuts off below a
+ * certain level, we don't care about this limitation here.
+ * Level 0 on the other hand equates to user masking disabled.
+ *
+ * We use the default priority level as a cut off so that only
+ * special case opt-in IRQs can be mangled.
+ */
+ if (level >= intc_get_dfl_prio_level())
+ return -EINVAL;
+
+ __raw_writel(0xa5 << 24 | level << 4, uimask);
+
+ return count;
+}
+
+static SYSDEV_CLASS_ATTR(userimask, S_IRUSR | S_IWUSR,
+ show_intc_userimask, store_intc_userimask);
+
+
+static int __init userimask_sysdev_init(void)
+{
+ if (unlikely(!uimask))
+ return -ENXIO;
+
+ return sysdev_class_create_file(&intc_sysdev_class, &attr_userimask);
+}
+late_initcall(userimask_sysdev_init);
+
+int register_intc_userimask(unsigned long addr)
+{
+ if (unlikely(uimask))
+ return -EBUSY;
+
+ uimask = ioremap_nocache(addr, SZ_4K);
+ if (unlikely(!uimask))
+ return -ENOMEM;
+
+ pr_info("userimask support registered for levels 0 -> %d\n",
+ intc_get_dfl_prio_level() - 1);
+
+ return 0;
+}
diff --git a/drivers/sh/intc/virq-debugfs.c b/drivers/sh/intc/virq-debugfs.c
new file mode 100644
index 000000000000..9e62ba9311f0
--- /dev/null
+++ b/drivers/sh/intc/virq-debugfs.c
@@ -0,0 +1,64 @@
+/*
+ * Support for virtual IRQ subgroups debugfs mapping.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * Modelled after arch/powerpc/kernel/irq.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/seq_file.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/debugfs.h>
+#include "internals.h"
+
+static int intc_irq_xlate_debug(struct seq_file *m, void *priv)
+{
+ int i;
+
+ seq_printf(m, "%-5s %-7s %-15s\n", "irq", "enum", "chip name");
+
+ for (i = 1; i < nr_irqs; i++) {
+ struct intc_map_entry *entry = intc_irq_xlate_get(i);
+ struct intc_desc_int *desc = entry->desc;
+
+ if (!desc)
+ continue;
+
+ seq_printf(m, "%5d ", i);
+ seq_printf(m, "0x%05x ", entry->enum_id);
+ seq_printf(m, "%-15s\n", desc->chip.name);
+ }
+
+ return 0;
+}
+
+static int intc_irq_xlate_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, intc_irq_xlate_debug, inode->i_private);
+}
+
+static const struct file_operations intc_irq_xlate_fops = {
+ .open = intc_irq_xlate_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init intc_irq_xlate_init(void)
+{
+ /*
+ * XXX.. use arch_debugfs_dir here when all of the intc users are
+ * converted.
+ */
+ if (debugfs_create_file("intc_irq_xlate", S_IRUGO, NULL, NULL,
+ &intc_irq_xlate_fops) == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+fs_initcall(intc_irq_xlate_init);
diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c
new file mode 100644
index 000000000000..643dfd4d2057
--- /dev/null
+++ b/drivers/sh/intc/virq.c
@@ -0,0 +1,255 @@
+/*
+ * Support for virtual IRQ subgroups.
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "intc: " fmt
+
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/radix-tree.h>
+#include <linux/spinlock.h>
+#include "internals.h"
+
+static struct intc_map_entry intc_irq_xlate[NR_IRQS];
+
+struct intc_virq_list {
+ unsigned int irq;
+ struct intc_virq_list *next;
+};
+
+#define for_each_virq(entry, head) \
+ for (entry = head; entry; entry = entry->next)
+
+/*
+ * Tags for the radix tree
+ */
+#define INTC_TAG_VIRQ_NEEDS_ALLOC 0
+
+void intc_irq_xlate_set(unsigned int irq, intc_enum id, struct intc_desc_int *d)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&intc_big_lock, flags);
+ intc_irq_xlate[irq].enum_id = id;
+ intc_irq_xlate[irq].desc = d;
+ raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+}
+
+struct intc_map_entry *intc_irq_xlate_get(unsigned int irq)
+{
+ return intc_irq_xlate + irq;
+}
+
+int intc_irq_lookup(const char *chipname, intc_enum enum_id)
+{
+ struct intc_map_entry *ptr;
+ struct intc_desc_int *d;
+ int irq = -1;
+
+ list_for_each_entry(d, &intc_list, list) {
+ int tagged;
+
+ if (strcmp(d->chip.name, chipname) != 0)
+ continue;
+
+ /*
+ * Catch early lookups for subgroup VIRQs that have not
+ * yet been allocated an IRQ. This already includes a
+ * fast-path out if the tree is untagged, so there is no
+ * need to explicitly test the root tree.
+ */
+ tagged = radix_tree_tag_get(&d->tree, enum_id,
+ INTC_TAG_VIRQ_NEEDS_ALLOC);
+ if (unlikely(tagged))
+ break;
+
+ ptr = radix_tree_lookup(&d->tree, enum_id);
+ if (ptr) {
+ irq = ptr - intc_irq_xlate;
+ break;
+ }
+ }
+
+ return irq;
+}
+EXPORT_SYMBOL_GPL(intc_irq_lookup);
+
+static int add_virq_to_pirq(unsigned int irq, unsigned int virq)
+{
+ struct intc_virq_list **last, *entry;
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ /* scan for duplicates */
+ last = (struct intc_virq_list **)&desc->handler_data;
+ for_each_virq(entry, desc->handler_data) {
+ if (entry->irq == virq)
+ return 0;
+ last = &entry->next;
+ }
+
+ entry = kzalloc(sizeof(struct intc_virq_list), GFP_ATOMIC);
+ if (!entry) {
+ pr_err("can't allocate VIRQ mapping for %d\n", virq);
+ return -ENOMEM;
+ }
+
+ entry->irq = virq;
+
+ *last = entry;
+
+ return 0;
+}
+
+static void intc_virq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct intc_virq_list *entry, *vlist = get_irq_data(irq);
+ struct intc_desc_int *d = get_intc_desc(irq);
+
+ desc->chip->mask_ack(irq);
+
+ for_each_virq(entry, vlist) {
+ unsigned long addr, handle;
+
+ handle = (unsigned long)get_irq_data(entry->irq);
+ addr = INTC_REG(d, _INTC_ADDR_E(handle), 0);
+
+ if (intc_reg_fns[_INTC_FN(handle)](addr, handle, 0))
+ generic_handle_irq(entry->irq);
+ }
+
+ desc->chip->unmask(irq);
+}
+
+static unsigned long __init intc_subgroup_data(struct intc_subgroup *subgroup,
+ struct intc_desc_int *d,
+ unsigned int index)
+{
+ unsigned int fn = REG_FN_TEST_BASE + (subgroup->reg_width >> 3) - 1;
+
+ return _INTC_MK(fn, MODE_ENABLE_REG, intc_get_reg(d, subgroup->reg),
+ 0, 1, (subgroup->reg_width - 1) - index);
+}
+
+static void __init intc_subgroup_init_one(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ struct intc_subgroup *subgroup)
+{
+ struct intc_map_entry *mapped;
+ unsigned int pirq;
+ unsigned long flags;
+ int i;
+
+ mapped = radix_tree_lookup(&d->tree, subgroup->parent_id);
+ if (!mapped) {
+ WARN_ON(1);
+ return;
+ }
+
+ pirq = mapped - intc_irq_xlate;
+
+ raw_spin_lock_irqsave(&d->lock, flags);
+
+ for (i = 0; i < ARRAY_SIZE(subgroup->enum_ids); i++) {
+ struct intc_subgroup_entry *entry;
+ int err;
+
+ if (!subgroup->enum_ids[i])
+ continue;
+
+ entry = kmalloc(sizeof(*entry), GFP_NOWAIT);
+ if (!entry)
+ break;
+
+ entry->pirq = pirq;
+ entry->enum_id = subgroup->enum_ids[i];
+ entry->handle = intc_subgroup_data(subgroup, d, i);
+
+ err = radix_tree_insert(&d->tree, entry->enum_id, entry);
+ if (unlikely(err < 0))
+ break;
+
+ radix_tree_tag_set(&d->tree, entry->enum_id,
+ INTC_TAG_VIRQ_NEEDS_ALLOC);
+ }
+
+ raw_spin_unlock_irqrestore(&d->lock, flags);
+}
+
+void __init intc_subgroup_init(struct intc_desc *desc, struct intc_desc_int *d)
+{
+ int i;
+
+ if (!desc->hw.subgroups)
+ return;
+
+ for (i = 0; i < desc->hw.nr_subgroups; i++)
+ intc_subgroup_init_one(desc, d, desc->hw.subgroups + i);
+}
+
+static void __init intc_subgroup_map(struct intc_desc_int *d)
+{
+ struct intc_subgroup_entry *entries[32];
+ unsigned long flags;
+ unsigned int nr_found;
+ int i;
+
+ raw_spin_lock_irqsave(&d->lock, flags);
+
+restart:
+ nr_found = radix_tree_gang_lookup_tag_slot(&d->tree,
+ (void ***)entries, 0, ARRAY_SIZE(entries),
+ INTC_TAG_VIRQ_NEEDS_ALLOC);
+
+ for (i = 0; i < nr_found; i++) {
+ struct intc_subgroup_entry *entry;
+ int irq;
+
+ entry = radix_tree_deref_slot((void **)entries[i]);
+ if (unlikely(!entry))
+ continue;
+ if (unlikely(entry == RADIX_TREE_RETRY))
+ goto restart;
+
+ irq = create_irq();
+ if (unlikely(irq < 0)) {
+ pr_err("no more free IRQs, bailing..\n");
+ break;
+ }
+
+ pr_info("Setting up a chained VIRQ from %d -> %d\n",
+ irq, entry->pirq);
+
+ intc_irq_xlate_set(irq, entry->enum_id, d);
+
+ set_irq_chip_and_handler_name(irq, get_irq_chip(entry->pirq),
+ handle_simple_irq, "virq");
+ set_irq_chip_data(irq, get_irq_chip_data(entry->pirq));
+
+ set_irq_data(irq, (void *)entry->handle);
+
+ set_irq_chained_handler(entry->pirq, intc_virq_handler);
+ add_virq_to_pirq(entry->pirq, irq);
+
+ radix_tree_tag_clear(&d->tree, entry->enum_id,
+ INTC_TAG_VIRQ_NEEDS_ALLOC);
+ radix_tree_replace_slot((void **)entries[i],
+ &intc_irq_xlate[irq]);
+ }
+
+ raw_spin_unlock_irqrestore(&d->lock, flags);
+}
+
+void __init intc_finalize(void)
+{
+ struct intc_desc_int *d;
+
+ list_for_each_entry(d, &intc_list, list)
+ if (radix_tree_tagged(&d->tree, INTC_TAG_VIRQ_NEEDS_ALLOC))
+ intc_subgroup_map(d);
+}
diff --git a/drivers/sh/pfc.c b/drivers/sh/pfc.c
index cf0303acab8e..75934e3ea34e 100644
--- a/drivers/sh/pfc.c
+++ b/drivers/sh/pfc.c
@@ -7,6 +7,8 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -559,10 +561,8 @@ static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio)
struct pinmux_data_reg *dr = NULL;
int bit = 0;
- if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) {
- BUG();
- return 0;
- }
+ if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
+ return -EINVAL;
return gpio_read_reg(dr->reg, dr->reg_width, 1, bit);
}
@@ -581,7 +581,7 @@ int register_pinmux(struct pinmux_info *pip)
{
struct gpio_chip *chip = &pip->chip;
- pr_info("sh pinmux: %s handling gpio %d -> %d\n",
+ pr_info("%s handling gpio %d -> %d\n",
pip->name, pip->first_gpio, pip->last_gpio);
setup_data_regs(pip);
@@ -602,3 +602,10 @@ int register_pinmux(struct pinmux_info *pip)
return gpiochip_add(chip);
}
+
+int unregister_pinmux(struct pinmux_info *pip)
+{
+ pr_info("%s deregistering\n", pip->name);
+
+ return gpiochip_remove(&pip->chip);
+}
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 4b9eec68fad6..78f9fd02c1b2 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -329,6 +329,13 @@ config SPI_STMP3XXX
help
SPI driver for Freescale STMP37xx/378x SoC SSP interface
+config SPI_TEGRA
+ tristate "Nvidia Tegra SPI controller"
+ depends on ARCH_TEGRA
+ select TEGRA_SYSTEM_DMA
+ help
+ SPI driver for NVidia Tegra SoCs
+
config SPI_TOPCLIFF_PCH
tristate "Topcliff PCH SPI Controller"
depends on PCI
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 557aaadf56b2..8bc1a5abac1f 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_SPI_PPC4xx) += spi_ppc4xx.o
obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx_hw.o
obj-$(CONFIG_SPI_S3C64XX) += spi_s3c64xx.o
+obj-$(CONFIG_SPI_TEGRA) += spi_tegra.o
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi_topcliff_pch.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
diff --git a/drivers/spi/spi_tegra.c b/drivers/spi/spi_tegra.c
new file mode 100644
index 000000000000..bb7df02a5472
--- /dev/null
+++ b/drivers/spi/spi_tegra.c
@@ -0,0 +1,618 @@
+/*
+ * Driver for Nvidia TEGRA spi controller.
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ * Erik Gilling <konkers@android.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/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <linux/spi/spi.h>
+
+#include <mach/dma.h>
+
+#define SLINK_COMMAND 0x000
+#define SLINK_BIT_LENGTH(x) (((x) & 0x1f) << 0)
+#define SLINK_WORD_SIZE(x) (((x) & 0x1f) << 5)
+#define SLINK_BOTH_EN (1 << 10)
+#define SLINK_CS_SW (1 << 11)
+#define SLINK_CS_VALUE (1 << 12)
+#define SLINK_CS_POLARITY (1 << 13)
+#define SLINK_IDLE_SDA_DRIVE_LOW (0 << 16)
+#define SLINK_IDLE_SDA_DRIVE_HIGH (1 << 16)
+#define SLINK_IDLE_SDA_PULL_LOW (2 << 16)
+#define SLINK_IDLE_SDA_PULL_HIGH (3 << 16)
+#define SLINK_IDLE_SDA_MASK (3 << 16)
+#define SLINK_CS_POLARITY1 (1 << 20)
+#define SLINK_CK_SDA (1 << 21)
+#define SLINK_CS_POLARITY2 (1 << 22)
+#define SLINK_CS_POLARITY3 (1 << 23)
+#define SLINK_IDLE_SCLK_DRIVE_LOW (0 << 24)
+#define SLINK_IDLE_SCLK_DRIVE_HIGH (1 << 24)
+#define SLINK_IDLE_SCLK_PULL_LOW (2 << 24)
+#define SLINK_IDLE_SCLK_PULL_HIGH (3 << 24)
+#define SLINK_IDLE_SCLK_MASK (3 << 24)
+#define SLINK_M_S (1 << 28)
+#define SLINK_WAIT (1 << 29)
+#define SLINK_GO (1 << 30)
+#define SLINK_ENB (1 << 31)
+
+#define SLINK_COMMAND2 0x004
+#define SLINK_LSBFE (1 << 0)
+#define SLINK_SSOE (1 << 1)
+#define SLINK_SPIE (1 << 4)
+#define SLINK_BIDIROE (1 << 6)
+#define SLINK_MODFEN (1 << 7)
+#define SLINK_INT_SIZE(x) (((x) & 0x1f) << 8)
+#define SLINK_CS_ACTIVE_BETWEEN (1 << 17)
+#define SLINK_SS_EN_CS(x) (((x) & 0x3) << 18)
+#define SLINK_SS_SETUP(x) (((x) & 0x3) << 20)
+#define SLINK_FIFO_REFILLS_0 (0 << 22)
+#define SLINK_FIFO_REFILLS_1 (1 << 22)
+#define SLINK_FIFO_REFILLS_2 (2 << 22)
+#define SLINK_FIFO_REFILLS_3 (3 << 22)
+#define SLINK_FIFO_REFILLS_MASK (3 << 22)
+#define SLINK_WAIT_PACK_INT(x) (((x) & 0x7) << 26)
+#define SLINK_SPC0 (1 << 29)
+#define SLINK_TXEN (1 << 30)
+#define SLINK_RXEN (1 << 31)
+
+#define SLINK_STATUS 0x008
+#define SLINK_COUNT(val) (((val) >> 0) & 0x1f)
+#define SLINK_WORD(val) (((val) >> 5) & 0x1f)
+#define SLINK_BLK_CNT(val) (((val) >> 0) & 0xffff)
+#define SLINK_MODF (1 << 16)
+#define SLINK_RX_UNF (1 << 18)
+#define SLINK_TX_OVF (1 << 19)
+#define SLINK_TX_FULL (1 << 20)
+#define SLINK_TX_EMPTY (1 << 21)
+#define SLINK_RX_FULL (1 << 22)
+#define SLINK_RX_EMPTY (1 << 23)
+#define SLINK_TX_UNF (1 << 24)
+#define SLINK_RX_OVF (1 << 25)
+#define SLINK_TX_FLUSH (1 << 26)
+#define SLINK_RX_FLUSH (1 << 27)
+#define SLINK_SCLK (1 << 28)
+#define SLINK_ERR (1 << 29)
+#define SLINK_RDY (1 << 30)
+#define SLINK_BSY (1 << 31)
+
+#define SLINK_MAS_DATA 0x010
+#define SLINK_SLAVE_DATA 0x014
+
+#define SLINK_DMA_CTL 0x018
+#define SLINK_DMA_BLOCK_SIZE(x) (((x) & 0xffff) << 0)
+#define SLINK_TX_TRIG_1 (0 << 16)
+#define SLINK_TX_TRIG_4 (1 << 16)
+#define SLINK_TX_TRIG_8 (2 << 16)
+#define SLINK_TX_TRIG_16 (3 << 16)
+#define SLINK_TX_TRIG_MASK (3 << 16)
+#define SLINK_RX_TRIG_1 (0 << 18)
+#define SLINK_RX_TRIG_4 (1 << 18)
+#define SLINK_RX_TRIG_8 (2 << 18)
+#define SLINK_RX_TRIG_16 (3 << 18)
+#define SLINK_RX_TRIG_MASK (3 << 18)
+#define SLINK_PACKED (1 << 20)
+#define SLINK_PACK_SIZE_4 (0 << 21)
+#define SLINK_PACK_SIZE_8 (1 << 21)
+#define SLINK_PACK_SIZE_16 (2 << 21)
+#define SLINK_PACK_SIZE_32 (3 << 21)
+#define SLINK_PACK_SIZE_MASK (3 << 21)
+#define SLINK_IE_TXC (1 << 26)
+#define SLINK_IE_RXC (1 << 27)
+#define SLINK_DMA_EN (1 << 31)
+
+#define SLINK_STATUS2 0x01c
+#define SLINK_TX_FIFO_EMPTY_COUNT(val) (((val) & 0x3f) >> 0)
+#define SLINK_RX_FIFO_FULL_COUNT(val) (((val) & 0x3f) >> 16)
+
+#define SLINK_TX_FIFO 0x100
+#define SLINK_RX_FIFO 0x180
+
+static const unsigned long spi_tegra_req_sels[] = {
+ TEGRA_DMA_REQ_SEL_SL2B1,
+ TEGRA_DMA_REQ_SEL_SL2B2,
+ TEGRA_DMA_REQ_SEL_SL2B3,
+ TEGRA_DMA_REQ_SEL_SL2B4,
+};
+
+#define BB_LEN 32
+
+struct spi_tegra_data {
+ struct spi_master *master;
+ struct platform_device *pdev;
+ spinlock_t lock;
+
+ struct clk *clk;
+ void __iomem *base;
+ unsigned long phys;
+
+ u32 cur_speed;
+
+ struct list_head queue;
+ struct spi_transfer *cur;
+ unsigned cur_pos;
+ unsigned cur_len;
+ unsigned cur_bytes_per_word;
+
+ /* The tegra spi controller has a bug which causes the first word
+ * in PIO transactions to be garbage. Since packed DMA transactions
+ * require transfers to be 4 byte aligned we need a bounce buffer
+ * for the generic case.
+ */
+ struct tegra_dma_req rx_dma_req;
+ struct tegra_dma_channel *rx_dma;
+ u32 *rx_bb;
+ dma_addr_t rx_bb_phys;
+};
+
+
+static inline unsigned long spi_tegra_readl(struct spi_tegra_data *tspi,
+ unsigned long reg)
+{
+ return readl(tspi->base + reg);
+}
+
+static inline void spi_tegra_writel(struct spi_tegra_data *tspi,
+ unsigned long val,
+ unsigned long reg)
+{
+ writel(val, tspi->base + reg);
+}
+
+static void spi_tegra_go(struct spi_tegra_data *tspi)
+{
+ unsigned long val;
+
+ wmb();
+
+ val = spi_tegra_readl(tspi, SLINK_DMA_CTL);
+ val &= ~SLINK_DMA_BLOCK_SIZE(~0) & ~SLINK_DMA_EN;
+ val |= SLINK_DMA_BLOCK_SIZE(tspi->rx_dma_req.size / 4 - 1);
+ spi_tegra_writel(tspi, val, SLINK_DMA_CTL);
+
+ tegra_dma_enqueue_req(tspi->rx_dma, &tspi->rx_dma_req);
+
+ val |= SLINK_DMA_EN;
+ spi_tegra_writel(tspi, val, SLINK_DMA_CTL);
+}
+
+static unsigned spi_tegra_fill_tx_fifo(struct spi_tegra_data *tspi,
+ struct spi_transfer *t)
+{
+ unsigned len = min(t->len - tspi->cur_pos, BB_LEN *
+ tspi->cur_bytes_per_word);
+ u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_pos;
+ int i, j;
+ unsigned long val;
+
+ val = spi_tegra_readl(tspi, SLINK_COMMAND);
+ val &= ~SLINK_WORD_SIZE(~0);
+ val |= SLINK_WORD_SIZE(len / tspi->cur_bytes_per_word - 1);
+ spi_tegra_writel(tspi, val, SLINK_COMMAND);
+
+ for (i = 0; i < len; i += tspi->cur_bytes_per_word) {
+ val = 0;
+ for (j = 0; j < tspi->cur_bytes_per_word; j++)
+ val |= tx_buf[i + j] << j * 8;
+
+ spi_tegra_writel(tspi, val, SLINK_TX_FIFO);
+ }
+
+ tspi->rx_dma_req.size = len / tspi->cur_bytes_per_word * 4;
+
+ return len;
+}
+
+static unsigned spi_tegra_drain_rx_fifo(struct spi_tegra_data *tspi,
+ struct spi_transfer *t)
+{
+ unsigned len = tspi->cur_len;
+ u8 *rx_buf = (u8 *)t->rx_buf + tspi->cur_pos;
+ int i, j;
+ unsigned long val;
+
+ for (i = 0; i < len; i += tspi->cur_bytes_per_word) {
+ val = tspi->rx_bb[i / tspi->cur_bytes_per_word];
+ for (j = 0; j < tspi->cur_bytes_per_word; j++)
+ rx_buf[i + j] = (val >> (j * 8)) & 0xff;
+ }
+
+ return len;
+}
+
+static void spi_tegra_start_transfer(struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct spi_tegra_data *tspi = spi_master_get_devdata(spi->master);
+ u32 speed;
+ u8 bits_per_word;
+ unsigned long val;
+
+ speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
+ bits_per_word = t->bits_per_word ? t->bits_per_word :
+ spi->bits_per_word;
+
+ tspi->cur_bytes_per_word = (bits_per_word - 1) / 8 + 1;
+
+ if (speed != tspi->cur_speed)
+ clk_set_rate(tspi->clk, speed);
+
+ if (tspi->cur_speed == 0)
+ clk_enable(tspi->clk);
+
+ tspi->cur_speed = speed;
+
+ val = spi_tegra_readl(tspi, SLINK_COMMAND2);
+ val &= ~SLINK_SS_EN_CS(~0) | SLINK_RXEN | SLINK_TXEN;
+ if (t->rx_buf)
+ val |= SLINK_RXEN;
+ if (t->tx_buf)
+ val |= SLINK_TXEN;
+ val |= SLINK_SS_EN_CS(spi->chip_select);
+ val |= SLINK_SPIE;
+ spi_tegra_writel(tspi, val, SLINK_COMMAND2);
+
+ val = spi_tegra_readl(tspi, SLINK_COMMAND);
+ val &= ~SLINK_BIT_LENGTH(~0);
+ val |= SLINK_BIT_LENGTH(bits_per_word - 1);
+
+ /* FIXME: should probably control CS manually so that we can be sure
+ * it does not go low between transfer and to support delay_usecs
+ * correctly.
+ */
+ val &= ~SLINK_IDLE_SCLK_MASK & ~SLINK_CK_SDA & ~SLINK_CS_SW;
+
+ if (spi->mode & SPI_CPHA)
+ val |= SLINK_CK_SDA;
+
+ if (spi->mode & SPI_CPOL)
+ val |= SLINK_IDLE_SCLK_DRIVE_HIGH;
+ else
+ val |= SLINK_IDLE_SCLK_DRIVE_LOW;
+
+ val |= SLINK_M_S;
+
+ spi_tegra_writel(tspi, val, SLINK_COMMAND);
+
+ spi_tegra_writel(tspi, SLINK_RX_FLUSH | SLINK_TX_FLUSH, SLINK_STATUS);
+
+ tspi->cur = t;
+ tspi->cur_pos = 0;
+ tspi->cur_len = spi_tegra_fill_tx_fifo(tspi, t);
+
+ spi_tegra_go(tspi);
+}
+
+static void spi_tegra_start_message(struct spi_device *spi,
+ struct spi_message *m)
+{
+ struct spi_transfer *t;
+
+ m->actual_length = 0;
+ m->status = 0;
+
+ t = list_first_entry(&m->transfers, struct spi_transfer, transfer_list);
+ spi_tegra_start_transfer(spi, t);
+}
+
+static void tegra_spi_rx_dma_complete(struct tegra_dma_req *req)
+{
+ struct spi_tegra_data *tspi = req->dev;
+ unsigned long flags;
+ struct spi_message *m;
+ struct spi_device *spi;
+ int timeout = 0;
+ unsigned long val;
+
+ /* the SPI controller may come back with both the BSY and RDY bits
+ * set. In this case we need to wait for the BSY bit to clear so
+ * that we are sure the DMA is finished. 1000 reads was empirically
+ * determined to be long enough.
+ */
+ while (timeout++ < 1000) {
+ if (!(spi_tegra_readl(tspi, SLINK_STATUS) & SLINK_BSY))
+ break;
+ }
+
+ spin_lock_irqsave(&tspi->lock, flags);
+
+ val = spi_tegra_readl(tspi, SLINK_STATUS);
+ val |= SLINK_RDY;
+ spi_tegra_writel(tspi, val, SLINK_STATUS);
+
+ m = list_first_entry(&tspi->queue, struct spi_message, queue);
+
+ if (timeout >= 1000)
+ m->status = -EIO;
+
+ spi = m->state;
+
+ tspi->cur_pos += spi_tegra_drain_rx_fifo(tspi, tspi->cur);
+ m->actual_length += tspi->cur_pos;
+
+ if (tspi->cur_pos < tspi->cur->len) {
+ tspi->cur_len = spi_tegra_fill_tx_fifo(tspi, tspi->cur);
+ spi_tegra_go(tspi);
+ } else if (!list_is_last(&tspi->cur->transfer_list,
+ &m->transfers)) {
+ tspi->cur = list_first_entry(&tspi->cur->transfer_list,
+ struct spi_transfer,
+ transfer_list);
+ spi_tegra_start_transfer(spi, tspi->cur);
+ } else {
+ list_del(&m->queue);
+
+ m->complete(m->context);
+
+ if (!list_empty(&tspi->queue)) {
+ m = list_first_entry(&tspi->queue, struct spi_message,
+ queue);
+ spi = m->state;
+ spi_tegra_start_message(spi, m);
+ } else {
+ clk_disable(tspi->clk);
+ tspi->cur_speed = 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&tspi->lock, flags);
+}
+
+static int spi_tegra_setup(struct spi_device *spi)
+{
+ struct spi_tegra_data *tspi = spi_master_get_devdata(spi->master);
+ unsigned long cs_bit;
+ unsigned long val;
+ unsigned long flags;
+
+ dev_dbg(&spi->dev, "setup %d bpw, %scpol, %scpha, %dHz\n",
+ spi->bits_per_word,
+ spi->mode & SPI_CPOL ? "" : "~",
+ spi->mode & SPI_CPHA ? "" : "~",
+ spi->max_speed_hz);
+
+
+ switch (spi->chip_select) {
+ case 0:
+ cs_bit = SLINK_CS_POLARITY;
+ break;
+
+ case 1:
+ cs_bit = SLINK_CS_POLARITY1;
+ break;
+
+ case 2:
+ cs_bit = SLINK_CS_POLARITY2;
+ break;
+
+ case 4:
+ cs_bit = SLINK_CS_POLARITY3;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&tspi->lock, flags);
+
+ val = spi_tegra_readl(tspi, SLINK_COMMAND);
+ if (spi->mode & SPI_CS_HIGH)
+ val |= cs_bit;
+ else
+ val &= ~cs_bit;
+ spi_tegra_writel(tspi, val, SLINK_COMMAND);
+
+ spin_unlock_irqrestore(&tspi->lock, flags);
+
+ return 0;
+}
+
+static int spi_tegra_transfer(struct spi_device *spi, struct spi_message *m)
+{
+ struct spi_tegra_data *tspi = spi_master_get_devdata(spi->master);
+ struct spi_transfer *t;
+ unsigned long flags;
+ int was_empty;
+
+ if (list_empty(&m->transfers) || !m->complete)
+ return -EINVAL;
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (t->bits_per_word < 0 || t->bits_per_word > 32)
+ return -EINVAL;
+
+ if (t->len == 0)
+ return -EINVAL;
+
+ if (!t->rx_buf && !t->tx_buf)
+ return -EINVAL;
+ }
+
+ m->state = spi;
+
+ spin_lock_irqsave(&tspi->lock, flags);
+ was_empty = list_empty(&tspi->queue);
+ list_add_tail(&m->queue, &tspi->queue);
+
+ if (was_empty)
+ spi_tegra_start_message(spi, m);
+
+ spin_unlock_irqrestore(&tspi->lock, flags);
+
+ return 0;
+}
+
+static int __init spi_tegra_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct spi_tegra_data *tspi;
+ struct resource *r;
+ int ret;
+
+ master = spi_alloc_master(&pdev->dev, sizeof *tspi);
+ if (master == NULL) {
+ dev_err(&pdev->dev, "master allocation failed\n");
+ return -ENOMEM;
+ }
+
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
+ master->bus_num = pdev->id;
+
+ master->setup = spi_tegra_setup;
+ master->transfer = spi_tegra_transfer;
+ master->num_chipselect = 4;
+
+ dev_set_drvdata(&pdev->dev, master);
+ tspi = spi_master_get_devdata(master);
+ tspi->master = master;
+ tspi->pdev = pdev;
+ spin_lock_init(&tspi->lock);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ ret = -ENODEV;
+ goto err0;
+ }
+
+ if (!request_mem_region(r->start, (r->end - r->start) + 1,
+ dev_name(&pdev->dev))) {
+ ret = -EBUSY;
+ goto err0;
+ }
+
+ tspi->phys = r->start;
+ tspi->base = ioremap(r->start, r->end - r->start + 1);
+ if (!tspi->base) {
+ dev_err(&pdev->dev, "can't ioremap iomem\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ tspi->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR_OR_NULL(tspi->clk)) {
+ dev_err(&pdev->dev, "can not get clock\n");
+ ret = PTR_ERR(tspi->clk);
+ goto err2;
+ }
+
+ INIT_LIST_HEAD(&tspi->queue);
+
+ tspi->rx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT);
+ if (!tspi->rx_dma) {
+ dev_err(&pdev->dev, "can not allocate rx dma channel\n");
+ ret = -ENODEV;
+ goto err3;
+ }
+
+ tspi->rx_bb = dma_alloc_coherent(&pdev->dev, sizeof(u32) * BB_LEN,
+ &tspi->rx_bb_phys, GFP_KERNEL);
+ if (!tspi->rx_bb) {
+ dev_err(&pdev->dev, "can not allocate rx bounce buffer\n");
+ ret = -ENOMEM;
+ goto err4;
+ }
+
+ tspi->rx_dma_req.complete = tegra_spi_rx_dma_complete;
+ tspi->rx_dma_req.to_memory = 1;
+ tspi->rx_dma_req.dest_addr = tspi->rx_bb_phys;
+ tspi->rx_dma_req.dest_bus_width = 32;
+ tspi->rx_dma_req.source_addr = tspi->phys + SLINK_RX_FIFO;
+ tspi->rx_dma_req.source_bus_width = 32;
+ tspi->rx_dma_req.source_wrap = 4;
+ tspi->rx_dma_req.req_sel = spi_tegra_req_sels[pdev->id];
+ tspi->rx_dma_req.dev = tspi;
+
+ ret = spi_register_master(master);
+
+ if (ret < 0)
+ goto err5;
+
+ return ret;
+
+err5:
+ dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN,
+ tspi->rx_bb, tspi->rx_bb_phys);
+err4:
+ tegra_dma_free_channel(tspi->rx_dma);
+err3:
+ clk_put(tspi->clk);
+err2:
+ iounmap(tspi->base);
+err1:
+ release_mem_region(r->start, (r->end - r->start) + 1);
+err0:
+ spi_master_put(master);
+ return ret;
+}
+
+static int __devexit spi_tegra_remove(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct spi_tegra_data *tspi;
+ struct resource *r;
+
+ master = dev_get_drvdata(&pdev->dev);
+ tspi = spi_master_get_devdata(master);
+
+ tegra_dma_free_channel(tspi->rx_dma);
+
+ dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN,
+ tspi->rx_bb, tspi->rx_bb_phys);
+
+ clk_put(tspi->clk);
+ iounmap(tspi->base);
+
+ spi_master_put(master);
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(r->start, (r->end - r->start) + 1);
+
+ return 0;
+}
+
+MODULE_ALIAS("platform:spi_tegra");
+
+static struct platform_driver spi_tegra_driver = {
+ .driver = {
+ .name = "spi_tegra",
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(spi_tegra_remove),
+};
+
+static int __init spi_tegra_init(void)
+{
+ return platform_driver_probe(&spi_tegra_driver, spi_tegra_probe);
+}
+module_init(spi_tegra_init);
+
+static void __exit spi_tegra_exit(void)
+{
+ platform_driver_unregister(&spi_tegra_driver);
+}
+module_exit(spi_tegra_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 335311a98fdc..8e03e7600239 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -139,8 +139,6 @@ source "drivers/staging/adis16255/Kconfig"
source "drivers/staging/xgifb/Kconfig"
-source "drivers/staging/mrst-touchscreen/Kconfig"
-
source "drivers/staging/msm/Kconfig"
source "drivers/staging/lirc/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index e3f1e1b6095e..0e7d7559d379 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -51,7 +51,6 @@ obj-$(CONFIG_CXT1E1) += cxt1e1/
obj-$(CONFIG_TI_ST) += ti-st/
obj-$(CONFIG_ADIS16255) += adis16255/
obj-$(CONFIG_FB_XGI) += xgifb/
-obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH) += mrst-touchscreen/
obj-$(CONFIG_MSM_STAGING) += msm/
obj-$(CONFIG_EASYCAP) += easycap/
obj-$(CONFIG_SOLO6X10) += solo6x10/
diff --git a/drivers/staging/asus_oled/README b/drivers/staging/asus_oled/README
index 96b9717f168f..0d82a6d5fa58 100644
--- a/drivers/staging/asus_oled/README
+++ b/drivers/staging/asus_oled/README
@@ -2,7 +2,7 @@
Driver for Asus OLED display present in some Asus laptops.
The code of this driver is based on 'asusoled' program taken from
- https://launchpad.net/asusoled/. I just wanted to have a simple
+ <http://lapsus.berlios.de/asus_oled.html>. I just wanted to have a simple
kernel driver for controlling this device, but I didn't know how
to do that. Now I know ;) Also, that program can not be used
with usbhid loaded, which means no USB mouse/keyboard while
diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c
index 5b279fb30f3f..8c95d8c2a4f4 100644
--- a/drivers/staging/asus_oled/asus_oled.c
+++ b/drivers/staging/asus_oled/asus_oled.c
@@ -24,7 +24,7 @@
*
*
* Asus OLED support is based on asusoled program taken from
- * https://launchpad.net/asusoled/.
+ * <http://lapsus.berlios.de/asus_oled.html>.
*
*
*/
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index ced346a7cae3..78b1410ba4f6 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdas.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdas.c
@@ -37,7 +37,7 @@ Configuration Options:
Developed from cb_pcidas and skel by Richard Bytheway (mocelet@sucs.org).
Only supports DIO, AO and simple AI in it's present form.
No interrupts, multi channel or FIFO AI, although the card looks like it could support this.
-See http://www.measurementcomputing.com/PDFManuals/pcim-das1602_16.pdf for more details.
+See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details.
*/
#include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c
index 6af6c8323d56..82be77daa7d7 100644
--- a/drivers/staging/comedi/drivers/daqboard2000.c
+++ b/drivers/staging/comedi/drivers/daqboard2000.c
@@ -50,8 +50,8 @@ Configuration options:
With some help from our swedish distributor, we got the Windows sourcecode
for the card, and here are the findings so far.
- 1. A good document that describes the PCI interface chip is found at:
- http://plx.plxtech.com/download/9080/databook/9080db-106.pdf
+ 1. A good document that describes the PCI interface chip is 9080db-106.pdf
+ available from http://www.plxtech.com/products/io/pci9080
2. The initialization done so far is:
a. program the FPGA (windows code sans a lot of error messages)
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index 3acf7e62bec4..1411dd8f4e7c 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -37,7 +37,7 @@ boards has not
yet been added to the driver, mainly due to the fact that
I don't know the device id numbers. If you have one
of these boards,
-please file a bug report at https://bugs.comedi.org/
+please file a bug report at http://comedi.org/
so I can get the necessary information from you.
The 1200 series boards have onboard calibration dacs for correcting
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index bd16f913af23..986ef6712989 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -34,7 +34,7 @@
340747b.pdf AT-MIO E series Register Level Programmer Manual
341079b.pdf PCI E Series RLPM
340934b.pdf DAQ-STC reference manual
- 67xx and 611x registers (from http://www.ni.com/pdf/daq/us)
+ 67xx and 611x registers (from ftp://ftp.ni.com/support/daq/mhddk/documentation/)
release_ni611x.pdf
release_ni67xx.pdf
Other possibly relevant info:
diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h
index 485d63f99293..0d254a1b78a7 100644
--- a/drivers/staging/comedi/drivers/plx9080.h
+++ b/drivers/staging/comedi/drivers/plx9080.h
@@ -13,7 +13,7 @@
*
********************************************************************
*
- * Copyright (C) 1999 RG Studio s.c., http://www.rgstudio.com.pl/
+ * Copyright (C) 1999 RG Studio s.c.
* Written by Krzysztof Halasa <khc@rgstudio.com.pl>
*
* Portions (C) SBE Inc., used by permission.
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 0367d2b9e2fa..a49a7c566d37 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -59,7 +59,7 @@ Configuration options:
Data sheet: http://www.rtdusa.com/pdf/dm7520.pdf
Example source: http://www.rtdusa.com/examples/dm/dm7520.zip
Call them and ask for the register level manual.
- PCI chip: http://www.plxtech.com/products/toolbox/9080.htm
+ PCI chip: http://www.plxtech.com/products/io/pci9080
Notes:
This board is memory mapped. There is some IO stuff, but it isn't needed.
diff --git a/drivers/staging/mrst-touchscreen/Kconfig b/drivers/staging/mrst-touchscreen/Kconfig
deleted file mode 100644
index c2af49217084..000000000000
--- a/drivers/staging/mrst-touchscreen/Kconfig
+++ /dev/null
@@ -1,7 +0,0 @@
-config TOUCHSCREEN_INTEL_MID
- tristate "Intel MID platform resistive touchscreen"
- depends on INTEL_SCU_IPC
- default y
- help
- Say Y here if you have a Intel MID based touchscreen
- If unsure, say N.
diff --git a/drivers/staging/mrst-touchscreen/Makefile b/drivers/staging/mrst-touchscreen/Makefile
deleted file mode 100644
index 2d638b0d70bf..000000000000
--- a/drivers/staging/mrst-touchscreen/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) := intel_mid_touch.o
-
-
diff --git a/drivers/staging/mrst-touchscreen/TODO b/drivers/staging/mrst-touchscreen/TODO
deleted file mode 100644
index 7157028d634a..000000000000
--- a/drivers/staging/mrst-touchscreen/TODO
+++ /dev/null
@@ -1,2 +0,0 @@
-- Move the driver to not think it is SPI (requires fixing some of the SFI
- and firmware side)
diff --git a/drivers/staging/mrst-touchscreen/intel-mid-touch.c b/drivers/staging/mrst-touchscreen/intel-mid-touch.c
deleted file mode 100644
index abba22f921be..000000000000
--- a/drivers/staging/mrst-touchscreen/intel-mid-touch.c
+++ /dev/null
@@ -1,864 +0,0 @@
-/*
- * intel_mid_touch.c - Intel MID Resistive Touch Screen Driver
- *
- * Copyright (C) 2008 Intel Corp
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * 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; ifnot, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * Questions/Comments/Bug fixes to Sreedhara (sreedhara.ds@intel.com)
- * Ramesh Agarwal (ramesh.agarwal@intel.com)
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * TODO:
- * kill off mrstouch_debug eventually
- * review conversion of r/m/w sequences
- * Replace interrupt mutex abuse
- * Kill of mrstouchdevp pointer
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/param.h>
-#include <linux/spi/spi.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
-#include <linux/kthread.h>
-#include <asm/intel_scu_ipc.h>
-
-
-#if defined(MRSTOUCH_DEBUG)
-#define mrstouch_debug(fmt, args...)\
- do { \
- printk(KERN_DEBUG "\n[MRSTOUCH(%d)] - ", __LINE__); \
- printk(KERN_DEBUG fmt, ##args); \
- } while (0);
-#else
-#define mrstouch_debug(fmt, args...)
-#endif
-
-/* PMIC Interrupt registers */
-#define PMIC_REG_ID1 0x00 /*PMIC ID1 register */
-
-/* PMIC Interrupt registers */
-#define PMIC_REG_INT 0x04 /*PMIC interrupt register */
-#define PMIC_REG_MINT 0x05 /*PMIC interrupt mask register */
-
-/* ADC Interrupt registers */
-#define PMIC_REG_ADCINT 0x5F /*ADC interrupt register */
-#define PMIC_REG_MADCINT 0x60 /*ADC interrupt mask register */
-
-/* ADC Control registers */
-#define PMIC_REG_ADCCNTL1 0x61 /*ADC control register */
-
-/* ADC Channel Selection registers */
-#define PMICADDR0 0xA4
-#define END_OF_CHANNEL 0x1F
-
-/* ADC Result register */
-#define PMIC_REG_ADCSNS0H 0x64
-
-/* ADC channels for touch screen */
-#define MRST_TS_CHAN10 0xA /* Touch screen X+ connection */
-#define MRST_TS_CHAN11 0xB /* Touch screen X- connection */
-#define MRST_TS_CHAN12 0xC /* Touch screen Y+ connection */
-#define MRST_TS_CHAN13 0xD /* Touch screen Y- connection */
-
-/* Touch screen coordinate constants */
-#define TOUCH_PRESSURE 50
-#define TOUCH_PRESSURE_FS 100
-
-#define XMOVE_LIMIT 5
-#define YMOVE_LIMIT 5
-#define XYMOVE_CNT 3
-
-#define MAX_10BIT ((1<<10)-1)
-
-/* Touch screen channel BIAS constants */
-#define XBIAS 0x20
-#define YBIAS 0x40
-#define ZBIAS 0x80
-
-/* Touch screen coordinates */
-#define MIN_X 10
-#define MAX_X 1024
-#define MIN_Y 10
-#define MAX_Y 1024
-#define WAIT_ADC_COMPLETION 10
-
-/* PMIC ADC round robin delays */
-#define ADC_LOOP_DELAY0 0x0 /* Continuous loop */
-#define ADC_LOOP_DELAY1 0x1 /* 4.5 ms approximate */
-
-/* PMIC Vendor Identifiers */
-#define PMIC_VENDOR_FS 0 /* PMIC vendor FreeScale */
-#define PMIC_VENDOR_MAXIM 1 /* PMIC vendor MAXIM */
-#define PMIC_VENDOR_NEC 2 /* PMIC vendor NEC */
-#define MRSTOUCH_MAX_CHANNELS 32 /* Maximum ADC channels */
-
-/* Touch screen device structure */
-struct mrstouch_dev {
- struct spi_device *spi; /* SPI device associated with touch screen */
- struct input_dev *input; /* input device for touchscreen*/
- char phys[32]; /* Device name */
- struct task_struct *pendet_thrd; /* PENDET interrupt handler */
- struct mutex lock; /* Sync between interrupt and PENDET handler */
- bool busy; /* Busy flag */
- u16 asr; /* Address selection register */
- int irq; /* Touch screen IRQ # */
- uint vendor; /* PMIC vendor */
- uint rev; /* PMIC revision */
- bool suspended; /* Device suspended status */
- bool disabled; /* Device disabled status */
- u16 x; /* X coordinate */
- u16 y; /* Y coordinate */
- bool pendown; /* PEN position */
-} ;
-
-
-/* Global Pointer to Touch screen device */
-static struct mrstouch_dev *mrstouchdevp;
-
-/* Utility to read PMIC ID */
-static int mrstouch_pmic_id(uint *vendor, uint *rev)
-{
- int err;
- u8 r;
-
- err = intel_scu_ipc_ioread8(PMIC_REG_ID1, &r);
- if (err)
- return err;
-
- *vendor = r & 0x7;
- *rev = (r >> 3) & 0x7;
-
- return 0;
-}
-
-/*
- * Parse ADC channels to find end of the channel configured by other ADC user
- * NEC and MAXIM requires 4 channels and FreeScale needs 18 channels
- */
-static int mrstouch_chan_parse(struct mrstouch_dev *tsdev)
-{
- int err, i, j, found;
- u32 r32;
-
- found = -1;
-
- for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) {
- if (found >= 0)
- break;
-
- err = intel_scu_ipc_ioread32(PMICADDR0, &r32);
- if (err)
- return err;
-
- for (j = 0; j < 32; j+= 8) {
- if (((r32 >> j) & 0xFF) == END_OF_CHANNEL) {
- found = i;
- break;
- }
- }
- }
- if (found < 0)
- return 0;
-
- if (tsdev->vendor == PMIC_VENDOR_FS) {
- if (found && found > (MRSTOUCH_MAX_CHANNELS - 18))
- return -ENOSPC;
- } else {
- if (found && found > (MRSTOUCH_MAX_CHANNELS - 4))
- return -ENOSPC;
- }
- return found;
-}
-
-/* Utility to enable/disable pendet.
- * pendet set to true enables PENDET interrupt
- * pendet set to false disables PENDET interrupt
- * Also clears RND mask bit
-*/
-static int pendet_enable(struct mrstouch_dev *tsdev, bool pendet)
-{
- u16 reg;
- u8 r;
- u8 pendet_enabled = 0;
- int retry = 0;
- int err;
-
- err = intel_scu_ipc_ioread16(PMIC_REG_MADCINT, &reg);
- if (err)
- return err;
-
- if (pendet) {
- reg &= ~0x0005;
- reg |= 0x2000; /* Enable pendet */
- } else
- reg &= 0xDFFF; /* Disable pendet */
-
- /* Set MADCINT and update ADCCNTL1 (next reg byte) */
- err = intel_scu_ipc_iowrite16(PMIC_REG_MADCINT, reg);
- if (!pendet || err)
- return err;
-
- /*
- * Sometimes even after the register write succeeds
- * the PMIC register value is not updated. Retry few iterations
- * to enable pendet.
- */
-
- err = intel_scu_ipc_ioread8(PMIC_REG_ADCCNTL1, &r);
- pendet_enabled = (r >> 5) & 0x01;
-
- retry = 0;
- while (!err && !pendet_enabled) {
- retry++;
- msleep(10);
- err = intel_scu_ipc_iowrite8(PMIC_REG_ADCCNTL1, reg >> 8);
- if (err)
- break;
- err = intel_scu_ipc_ioread8(PMIC_REG_ADCCNTL1, &r);
- if (err == 0)
- pendet_enabled = (r >> 5) & 0x01;
- if (retry >= 10) {
- dev_err(&tsdev->spi->dev, "Touch screen disabled.\n");
- return -EIO;
- }
- }
- return 0;
-}
-
-/* To read PMIC ADC touch screen result
- * Reads ADC storage registers for higher 7 and lower 3 bits
- * converts the two readings to single value and turns off gain bit
- */
-static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm)
-{
- int err;
- u16 result;
- u32 res;
-
- result = PMIC_REG_ADCSNS0H + offset;
-
- if (chan == MRST_TS_CHAN12)
- result += 4;
-
- err = intel_scu_ipc_ioread32(result, &res);
- if (err)
- return err;
-
- /* Mash the bits up */
-
- *vp = (res & 0xFF) << 3; /* Highest 7 bits */
- *vp |= (res >> 8) & 0x07; /* Lower 3 bits */
- *vp &= 0x3FF;
-
- res >>= 16;
-
- *vm = (res & 0xFF) << 3; /* Highest 7 bits */
- *vm |= (res >> 8) & 0x07; /* Lower 3 bits */
- *vm &= 0x3FF;
-
- return 0;
-}
-
-/* To configure touch screen channels
- * Writes touch screen channels to ADC address selection registers
- */
-static int mrstouch_ts_chan_set(uint offset)
-{
- int count;
- u16 chan;
- u16 reg[5];
- u8 data[5];
-
- chan = PMICADDR0 + offset;
- for (count = 0; count <= 3; count++) {
- reg[count] = chan++;
- data[count] = MRST_TS_CHAN10 + count;
- }
- reg[count] = chan;
- data[count] = END_OF_CHANNEL;
-
- return intel_scu_ipc_writev(reg, data, 5);
-}
-
-/* Initialize ADC */
-static int mrstouch_adc_init(struct mrstouch_dev *tsdev)
-{
- int err, start;
- u8 ra, rm;
-
- err = mrstouch_pmic_id(&tsdev->vendor, &tsdev->rev);
- if (err) {
- dev_err(&tsdev->spi->dev, "Unable to read PMIC id\n");
- return err;
- }
-
- start = mrstouch_chan_parse(tsdev);
- if (start < 0) {
- dev_err(&tsdev->spi->dev, "Unable to parse channels\n");
- return start;
- }
-
- tsdev->asr = start;
-
- mrstouch_debug("Channel offset(%d): 0x%X\n", tsdev->asr, tsdev->vendor);
-
- /* ADC power on, start, enable PENDET and set loop delay
- * ADC loop delay is set to 4.5 ms approximately
- * Loop delay more than this results in jitter in adc readings
- * Setting loop delay to 0 (continous loop) in MAXIM stops PENDET
- * interrupt generation sometimes.
- */
-
- if (tsdev->vendor == PMIC_VENDOR_FS) {
- ra = 0xE0 | ADC_LOOP_DELAY0;
- rm = 0x5;
- } else {
- /* NEC and MAXIm not consistent with loop delay 0 */
- ra = 0xE0 | ADC_LOOP_DELAY1;
- rm = 0x0;
-
- /* configure touch screen channels */
- err = mrstouch_ts_chan_set(tsdev->asr);
- if (err)
- return err;
- }
- err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, ra, 0xE7);
- if (err == 0)
- err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, rm, 0x03);
- return err;
-}
-
-/* Reports x,y coordinates to event subsystem */
-static void mrstouch_report_xy(struct mrstouch_dev *tsdev, u16 x, u16 y, u16 z)
-{
- int xdiff, ydiff;
-
- if (tsdev->pendown && z <= TOUCH_PRESSURE) {
- /* Pen removed, report button release */
- mrstouch_debug("BTN REL(%d)", z);
- input_report_key(tsdev->input, BTN_TOUCH, 0);
- tsdev->pendown = false;
- }
-
- xdiff = abs(x - tsdev->x);
- ydiff = abs(y - tsdev->y);
-
- /*
- if x and y values changes for XYMOVE_CNT readings it is considered
- as stylus is moving. This is required to differentiate between stylus
- movement and jitter
- */
- if (x < MIN_X || x > MAX_X || y < MIN_Y || y > MAX_Y) {
- /* Spurious values, release button if touched and return */
- if (tsdev->pendown) {
- mrstouch_debug("BTN REL(%d)", z);
- input_report_key(tsdev->input, BTN_TOUCH, 0);
- tsdev->pendown = false;
- }
- return;
- } else if (xdiff >= XMOVE_LIMIT || ydiff >= YMOVE_LIMIT) {
- tsdev->x = x;
- tsdev->y = y;
-
- input_report_abs(tsdev->input, ABS_X, x);
- input_report_abs(tsdev->input, ABS_Y, y);
- input_sync(tsdev->input);
- }
-
-
- if (!tsdev->pendown && z > TOUCH_PRESSURE) {
- /* Pen touched, report button touch */
- mrstouch_debug("BTN TCH(%d, %d, %d)", x, y, z);
- input_report_key(tsdev->input, BTN_TOUCH, 1);
- tsdev->pendown = true;
- }
-}
-
-
-/* Utility to start ADC, used by freescale handler */
-static int pendet_mask(void)
-{
- return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x02, 0x02);
-}
-
-/* Utility to stop ADC, used by freescale handler */
-static int pendet_umask(void)
-{
- return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x00, 0x02);
-}
-
-/* Utility to read ADC, used by freescale handler */
-static int mrstouch_pmic_fs_adc_read(struct mrstouch_dev *tsdev)
-{
- int err;
- u16 x, y, z, result;
- u16 reg[4];
- u8 data[4];
-
- result = PMIC_REG_ADCSNS0H + tsdev->asr;
-
- reg[0] = result + 4;
- reg[1] = result + 5;
- reg[2] = result + 16;
- reg[3] = result + 17;
-
- err = intel_scu_ipc_readv(reg, data, 4);
- if (err)
- goto ipc_error;
-
- x = data[0] << 3; /* Higher 7 bits */
- x |= data[1] & 0x7; /* Lower 3 bits */
- x &= 0x3FF;
-
- y = data[2] << 3; /* Higher 7 bits */
- y |= data[3] & 0x7; /* Lower 3 bits */
- y &= 0x3FF;
-
- /* Read Z value */
- reg[0] = result + 28;
- reg[1] = result + 29;
-
- err = intel_scu_ipc_readv(reg, data, 4);
- if (err)
- goto ipc_error;
-
- z = data[0] << 3; /* Higher 7 bits */
- z |= data[1] & 0x7; /* Lower 3 bits */
- z &= 0x3FF;
-
-#if defined(MRSTOUCH_PRINT_XYZP)
- mrstouch_debug("X: %d, Y: %d, Z: %d", x, y, z);
-#endif
-
- if (z >= TOUCH_PRESSURE_FS) {
- mrstouch_report_xy(tsdev, x, y, TOUCH_PRESSURE - 1); /* Pen Removed */
- return TOUCH_PRESSURE - 1;
- } else {
- mrstouch_report_xy(tsdev, x, y, TOUCH_PRESSURE + 1); /* Pen Touched */
- return TOUCH_PRESSURE + 1;
- }
-
- return 0;
-
-ipc_error:
- dev_err(&tsdev->spi->dev, "ipc error during fs_adc read\n");
- return err;
-}
-
-/* To handle free scale pmic pendet interrupt */
-static int pmic0_pendet(void *dev_id)
-{
- int err, count;
- u16 chan;
- unsigned int touched;
- struct mrstouch_dev *tsdev = (struct mrstouch_dev *)dev_id;
- u16 reg[5];
- u8 data[5];
-
- chan = PMICADDR0 + tsdev->asr;
-
- /* Set X BIAS */
- for (count = 0; count <= 3; count++) {
- reg[count] = chan++;
- data[count] = 0x2A;
- }
- reg[count] = chan++; /* Dummy */
- data[count] = 0;
-
- err = intel_scu_ipc_writev(reg, data, 5);
- if (err)
- goto ipc_error;
-
- msleep(WAIT_ADC_COMPLETION);
-
- /* Set Y BIAS */
- for (count = 0; count <= 3; count++) {
- reg[count] = chan++;
- data[count] = 0x4A;
- }
- reg[count] = chan++; /* Dummy */
- data[count] = 0;
-
- err = intel_scu_ipc_writev(reg, data, 5);
- if (err)
- goto ipc_error;
-
- msleep(WAIT_ADC_COMPLETION);
-
- /* Set Z BIAS */
- err = intel_scu_ipc_iowrite32(chan + 2, 0x8A8A8A8A);
- if (err)
- goto ipc_error;
-
- msleep(WAIT_ADC_COMPLETION);
-
- /*Read touch screen channels till pen removed
- * Freescale reports constant value of z for all points
- * z is high when screen is not touched and low when touched
- * Map high z value to not touched and low z value to pen touched
- */
- touched = mrstouch_pmic_fs_adc_read(tsdev);
- while (touched > TOUCH_PRESSURE) {
- touched = mrstouch_pmic_fs_adc_read(tsdev);
- msleep(WAIT_ADC_COMPLETION);
- }
-
- /* Clear all TS channels */
- chan = PMICADDR0 + tsdev->asr;
- for (count = 0; count <= 4; count++) {
- reg[count] = chan++;
- data[count] = 0;
- }
- err = intel_scu_ipc_writev(reg, data, 5);
- if (err)
- goto ipc_error;
-
- for (count = 0; count <= 4; count++) {
- reg[count] = chan++;
- data[count] = 0;
- }
- err = intel_scu_ipc_writev(reg, data, 5);
- if (err)
- goto ipc_error;
-
- err = intel_scu_ipc_iowrite32(chan + 2, 0x00000000);
- if (err)
- goto ipc_error;
-
- return 0;
-
-ipc_error:
- dev_err(&tsdev->spi->dev, "ipc error during pendet\n");
- return err;
-}
-
-
-/* To enable X, Y and Z bias values
- * Enables YPYM for X channels and XPXM for Y channels
- */
-static int mrstouch_ts_bias_set(uint offset, uint bias)
-{
- int count;
- u16 chan, start;
- u16 reg[4];
- u8 data[4];
-
- chan = PMICADDR0 + offset;
- start = MRST_TS_CHAN10;
-
- for (count = 0; count <= 3; count++) {
- reg[count] = chan++;
- data[count] = bias | (start + count);
- }
- return intel_scu_ipc_writev(reg, data, 4);
-}
-
-/* To read touch screen channel values */
-static int mrstouch_adc_read(struct mrstouch_dev *tsdev)
-{
- int err;
- u16 xp, xm, yp, ym, zp, zm;
-
- /* configure Y bias for X channels */
- err = mrstouch_ts_bias_set(tsdev->asr, YBIAS);
- if (err)
- goto ipc_error;
-
- msleep(WAIT_ADC_COMPLETION);
-
- /* read x+ and x- channels */
- err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &xp, &xm);
- if (err)
- goto ipc_error;
-
- /* configure x bias for y channels */
- err = mrstouch_ts_bias_set(tsdev->asr, XBIAS);
- if (err)
- goto ipc_error;
-
- msleep(WAIT_ADC_COMPLETION);
-
- /* read y+ and y- channels */
- err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN12, &yp, &ym);
- if (err)
- goto ipc_error;
-
- /* configure z bias for x and y channels */
- err = mrstouch_ts_bias_set(tsdev->asr, ZBIAS);
- if (err)
- goto ipc_error;
-
- msleep(WAIT_ADC_COMPLETION);
-
- /* read z+ and z- channels */
- err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &zp, &zm);
- if (err)
- goto ipc_error;
-
-#if defined(MRSTOUCH_PRINT_XYZP)
- printk(KERN_INFO "X+: %d, Y+: %d, Z+: %d\n", xp, yp, zp);
-#endif
-
-#if defined(MRSTOUCH_PRINT_XYZM)
- printk(KERN_INFO "X-: %d, Y-: %d, Z-: %d\n", xm, ym, zm);
-#endif
-
- mrstouch_report_xy(tsdev, xp, yp, zp); /* report x and y to eventX */
-
- return zp;
-
-ipc_error:
- dev_err(&tsdev->spi->dev, "ipc error during adc read\n");
- return err;
-}
-
-/* PENDET interrupt handler function for NEC and MAXIM */
-static void pmic12_pendet(void *data)
-{
- unsigned int touched;
- struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data;
-
- /* read touch screen channels till pen removed */
- do {
- touched = mrstouch_adc_read(tsdev);
- } while (touched > TOUCH_PRESSURE);
-}
-
-/* Handler to process PENDET interrupt */
-int mrstouch_pendet(void *data)
-{
- struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data;
- while (1) {
- /* Wait for PENDET interrupt */
- if (mutex_lock_interruptible(&tsdev->lock)) {
- msleep(WAIT_ADC_COMPLETION);
- continue;
- }
-
- if (tsdev->busy)
- return 0;
-
- tsdev->busy = true;
-
- if (tsdev->vendor == PMIC_VENDOR_NEC ||
- tsdev->vendor == PMIC_VENDOR_MAXIM) {
- /* PENDET must be disabled in NEC before reading ADC */
- pendet_enable(tsdev,false); /* Disbale PENDET */
- pmic12_pendet(tsdev);
- pendet_enable(tsdev, true); /*Enable PENDET */
- } else if (tsdev->vendor == PMIC_VENDOR_FS) {
- pendet_umask(); /* Stop ADC */
- pmic0_pendet(tsdev);
- pendet_mask(); /* Stop ADC */
- } else
- dev_err(&tsdev->spi->dev, "Unsupported touchscreen: %d\n",
- tsdev->vendor);
-
- tsdev->busy = false;
-
- }
- return 0;
-}
-
-/* PENDET interrupt handler */
-static irqreturn_t pendet_intr_handler(int irq, void *handle)
-{
- struct mrstouch_dev *tsdev = (struct mrstouch_dev *)handle;
-
- mutex_unlock(&tsdev->lock);
- return IRQ_HANDLED;
-}
-
-/* Intializes input device and registers with input subsystem */
-static int ts_input_dev_init(struct mrstouch_dev *tsdev, struct spi_device *spi)
-{
- int err = 0;
-
- mrstouch_debug("%s", __func__);
-
- tsdev->input = input_allocate_device();
- if (!tsdev->input) {
- dev_err(&tsdev->spi->dev, "Unable to allocate input device.\n");
- return -EINVAL;
- }
-
- tsdev->input->name = "mrst_touchscreen";
- snprintf(tsdev->phys, sizeof(tsdev->phys),
- "%s/input0", dev_name(&spi->dev));
- tsdev->input->phys = tsdev->phys;
- tsdev->input->dev.parent = &spi->dev;
-
- tsdev->input->id.vendor = tsdev->vendor;
- tsdev->input->id.version = tsdev->rev;
-
- tsdev->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- tsdev->input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-
- input_set_abs_params(tsdev->input, ABS_X, MIN_X, MIN_Y, 0, 0);
- input_set_abs_params(tsdev->input, ABS_Y, MIN_X, MIN_Y, 0, 0);
-
- err = input_register_device(tsdev->input);
- if (err) {
- dev_err(&tsdev->spi->dev, "unable to register input device\n");
- input_free_device(tsdev->input);
- return err;
- }
-
- mrstouch_debug("%s", "mrstouch initialized");
-
- return 0;
-
-}
-
-/* Probe function for touch screen driver */
-static int __devinit mrstouch_probe(struct spi_device *mrstouch_spi)
-{
- int err;
- unsigned int myirq;
- struct mrstouch_dev *tsdev;
-
- mrstouch_debug("%s(%p)", __func__, mrstouch_spi);
-
- mrstouchdevp = NULL;
- myirq = mrstouch_spi->irq;
-
- if (!mrstouch_spi->irq) {
- dev_err(&mrstouch_spi->dev, "no interrupt assigned\n");
- return -EINVAL;
- }
-
- tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL);
- if (!tsdev) {
- dev_err(&mrstouch_spi->dev, "unable to allocate memory\n");
- return -ENOMEM;
- }
-
- tsdev->irq = myirq;
- mrstouchdevp = tsdev;
-
- err = mrstouch_adc_init(tsdev);
- if (err) {
- dev_err(&mrstouch_spi->dev, "ADC init failed\n");
- goto mrstouch_err_free_mem;
- }
-
- dev_set_drvdata(&mrstouch_spi->dev, tsdev);
- tsdev->spi = mrstouch_spi;
-
- err = ts_input_dev_init(tsdev, mrstouch_spi);
- if (err) {
- dev_err(&tsdev->spi->dev, "ts_input_dev_init failed");
- goto mrstouch_err_free_mem;
- }
-
- mutex_init(&tsdev->lock);
- mutex_lock(&tsdev->lock)
-
- mrstouch_debug("Requesting IRQ-%d", myirq);
- err = request_irq(myirq, pendet_intr_handler,
- 0, "mrstouch", tsdev);
- if (err) {
- dev_err(&tsdev->spi->dev, "unable to allocate irq\n");
- goto mrstouch_err_free_mem;
- }
-
- tsdev->pendet_thrd = kthread_run(mrstouch_pendet,
- (void *)tsdev, "pendet handler");
- if (IS_ERR(tsdev->pendet_thrd)) {
- dev_err(&tsdev->spi->dev, "kthread_run failed\n");
- err = PTR_ERR(tsdev->pendet_thrd);
- goto mrstouch_err_free_mem;
- }
- mrstouch_debug("%s", "Driver initialized");
- return 0;
-
-mrstouch_err_free_mem:
- kfree(tsdev);
- return err;
-}
-
-static int mrstouch_suspend(struct spi_device *spi, pm_message_t msg)
-{
- mrstouch_debug("%s", __func__);
- mrstouchdevp->suspended = 1;
- return 0;
-}
-
-static int mrstouch_resume(struct spi_device *spi)
-{
- mrstouch_debug("%s", __func__);
- mrstouchdevp->suspended = 0;
- return 0;
-}
-
-static int mrstouch_remove(struct spi_device *spi)
-{
- mrstouch_debug("%s", __func__);
- free_irq(mrstouchdevp->irq, mrstouchdevp);
- input_unregister_device(mrstouchdevp->input);
- input_free_device(mrstouchdevp->input);
- if (mrstouchdevp->pendet_thrd)
- kthread_stop(mrstouchdevp->pendet_thrd);
- kfree(mrstouchdevp);
- return 0;
-}
-
-static struct spi_driver mrstouch_driver = {
- .driver = {
- .name = "pmic_touch",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
- .probe = mrstouch_probe,
- .suspend = mrstouch_suspend,
- .resume = mrstouch_resume,
- .remove = mrstouch_remove,
-};
-
-static int __init mrstouch_module_init(void)
-{
- int err;
-
- mrstouch_debug("%s", __func__);
- err = spi_register_driver(&mrstouch_driver);
- if (err) {
- mrstouch_debug("%s(%d)", "SPI PENDET failed", err);
- return -1;
- }
-
- return 0;
-}
-
-static void __exit mrstouch_module_exit(void)
-{
- mrstouch_debug("%s", __func__);
- spi_unregister_driver(&mrstouch_driver);
- return;
-}
-
-module_init(mrstouch_module_init);
-module_exit(mrstouch_module_exit);
-
-MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com");
-MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c
index 97dae297ca3c..c62d30017c07 100644
--- a/drivers/staging/pohmelfs/inode.c
+++ b/drivers/staging/pohmelfs/inode.c
@@ -882,12 +882,8 @@ static struct inode *pohmelfs_alloc_inode(struct super_block *sb)
static int pohmelfs_fsync(struct file *file, int datasync)
{
struct inode *inode = file->f_mapping->host;
- struct writeback_control wbc = {
- .sync_mode = WB_SYNC_ALL,
- .nr_to_write = 0, /* sys_fsync did this */
- };
- return sync_inode(inode, &wbc);
+ return sync_inode_metadata(inode, 1);
}
ssize_t pohmelfs_write(struct file *file, const char __user *buf,
diff --git a/drivers/staging/quickstart/quickstart.c b/drivers/staging/quickstart/quickstart.c
index 66122479d529..ba8f670ec0a7 100644
--- a/drivers/staging/quickstart/quickstart.c
+++ b/drivers/staging/quickstart/quickstart.c
@@ -5,8 +5,7 @@
* Copyright (C) 2007-2010 Angelo Arrifano <miknix@gmail.com>
*
* Information gathered from disassebled dsdt and from here:
- * "http://download.microsoft.com/download/9/c/5/
- * 9c5b2167-8017-4bae-9fde-d599bac8184a/DirAppLaunch_Vista.doc"
+ * <http://www.microsoft.com/whdc/system/platform/firmware/DirAppLaunch.mspx>
*
* 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/staging/xgifb/TODO b/drivers/staging/xgifb/TODO
index 7d71019b84c2..c85ff5e9e700 100644
--- a/drivers/staging/xgifb/TODO
+++ b/drivers/staging/xgifb/TODO
@@ -12,4 +12,4 @@ TODO:
- get rid of non-linux related stuff
Please send patches to:
-Arnaud Patard <apatard@mandriva.com>
+Arnaud Patard <arnaud.patard@rtp-net.org>
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 1da73ecd9799..bb440792a1b7 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -17,9 +17,9 @@ config UIO_CIF
depends on PCI
help
Driver for Hilscher CIF DeviceNet and Profibus cards. This
- driver requires a userspace component that handles all of the
- heavy lifting and can be found at:
- http://www.osadl.org/projects/downloads/UIO/user/cif-*
+ driver requires a userspace component called cif that handles
+ all of the heavy lifting and can be found at:
+ <http://www.osadl.org/projects/downloads/UIO/user/>
To compile this driver as a module, choose M here: the module
will be called uio_cif.
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 5af23cc5ea9f..f383cb42b1d7 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -1344,8 +1344,24 @@ static struct usbatm_driver cxacru_driver = {
.tx_padding = 11,
};
-static int cxacru_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+static int cxacru_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
{
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ char buf[15];
+
+ /* Avoid ADSL routers (cx82310_eth).
+ * Abort if bDeviceClass is 0xff and iProduct is "USB NET CARD".
+ */
+ if (usb_dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC
+ && usb_string(usb_dev, usb_dev->descriptor.iProduct,
+ buf, sizeof(buf)) > 0) {
+ if (!strcmp(buf, "USB NET CARD")) {
+ dev_info(&intf->dev, "ignoring cx82310_eth device\n");
+ return -ENODEV;
+ }
+ }
+
return usbatm_usb_probe(intf, id, &cxacru_driver);
}
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 095fa5366690..e2f63c0ea09d 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -276,6 +276,7 @@ static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t de
struct inode *inode = new_inode(sb);
if (inode) {
+ inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 387e503b9d14..bdec36acd0fa 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -1266,7 +1266,6 @@ write_in:
csr |= AT91_UDP_TXPKTRDY;
__raw_writel(csr, creg);
udc->req_pending = 0;
- return;
}
static void handle_ep0(struct at91_udc *udc)
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c
index 1f48ceb55a77..00975ed903d1 100644
--- a/drivers/usb/gadget/f_audio.c
+++ b/drivers/usb/gadget/f_audio.c
@@ -317,8 +317,6 @@ static void f_audio_playback_work(struct work_struct *data)
u_audio_playback(&audio->card, play_buf->buf, play_buf->actual);
f_audio_buffer_free(play_buf);
-
- return;
}
static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req)
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index e4f595055208..f276e9594f00 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -980,6 +980,7 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
if (likely(inode)) {
struct timespec current_time = CURRENT_TIME;
+ inode->i_ino = get_next_ino();
inode->i_mode = perms->mode;
inode->i_uid = perms->uid;
inode->i_gid = perms->gid;
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
index 2b98bd26364b..4f891eddd060 100644
--- a/drivers/usb/gadget/f_hid.c
+++ b/drivers/usb/gadget/f_hid.c
@@ -318,8 +318,6 @@ static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req)
spin_unlock(&hidg->spinlock);
wake_up(&hidg->read_queue);
-
- return;
}
static int hidg_setup(struct usb_function *f,
@@ -413,8 +411,6 @@ static void hidg_disable(struct usb_function *f)
usb_ep_disable(hidg->in_ep);
hidg->in_ep->driver_data = NULL;
-
- return;
}
static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index c16b402a876b..4c55eda4bd20 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -287,8 +287,6 @@ static void dr_controller_run(struct fsl_udc *udc)
temp = fsl_readl(&dr_regs->usbcmd);
temp |= USB_CMD_RUN_STOP;
fsl_writel(temp, &dr_regs->usbcmd);
-
- return;
}
static void dr_controller_stop(struct fsl_udc *udc)
@@ -308,8 +306,6 @@ static void dr_controller_stop(struct fsl_udc *udc)
tmp = fsl_readl(&dr_regs->usbcmd);
tmp &= ~USB_CMD_RUN_STOP;
fsl_writel(tmp, &dr_regs->usbcmd);
-
- return;
}
static void dr_ep_setup(unsigned char ep_num, unsigned char dir,
@@ -416,8 +412,6 @@ static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num,
p_QH->max_pkt_length = cpu_to_le32(tmp);
p_QH->next_dtd_ptr = 1;
p_QH->size_ioc_int_sts = 0;
-
- return;
}
/* Setup qh structure and ep register for ep0. */
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index d1d72d946b04..ba145e7fbe03 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -1991,6 +1991,7 @@ gadgetfs_make_inode (struct super_block *sb,
struct inode *inode = new_inode (sb);
if (inode) {
+ inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_uid = default_uid;
inode->i_gid = default_gid;
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 61d3ca6619bb..cb5cd422f3f5 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -54,7 +54,6 @@
#include <plat/dma.h>
#include <plat/usb.h>
-#include <plat/control.h>
#include "omap_udc.h"
@@ -2309,21 +2308,12 @@ static char *trx_mode(unsigned m, int enabled)
static int proc_otg_show(struct seq_file *s)
{
u32 tmp;
- u32 trans;
- char *ctrl_name;
+ u32 trans = 0;
+ char *ctrl_name = "(UNKNOWN)";
+ /* XXX This needs major revision for OMAP2+ */
tmp = omap_readl(OTG_REV);
- if (cpu_is_omap24xx()) {
- /*
- * REVISIT: Not clear how this works on OMAP2. trans
- * is ANDed to produce bits 7 and 8, which might make
- * sense for USB_TRANSCEIVER_CTRL on OMAP1,
- * but with CONTROL_DEVCONF, these bits have something to
- * do with the frame adjustment counter and McBSP2.
- */
- ctrl_name = "control_devconf";
- trans = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
- } else {
+ if (cpu_class_is_omap1()) {
ctrl_name = "tranceiver_ctrl";
trans = omap_readw(USB_TRANSCEIVER_CTRL);
}
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 027d66f81620..2efd6732d130 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -1394,8 +1394,6 @@ static void pxa_ep_fifo_flush(struct usb_ep *_ep)
}
spin_unlock_irqrestore(&ep->lock, flags);
-
- return;
}
/**
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 5b314041dfa9..d3cdffea9c8a 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -918,8 +918,6 @@ void rndis_deregister(int configNr)
if (configNr >= RNDIS_MAX_CONFIGS) return;
rndis_per_dev_params[configNr].used = 0;
-
- return;
}
int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter)
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 15fe3ecd203b..2adae8e39bba 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1095,7 +1095,6 @@ nogood:
ep->hcpriv = NULL;
done:
spin_unlock_irqrestore (&ehci->lock, flags);
- return;
}
static void
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
index 1dfb2c8f7707..e49b75a78000 100644
--- a/drivers/usb/host/imx21-hcd.c
+++ b/drivers/usb/host/imx21-hcd.c
@@ -27,8 +27,8 @@
* * 32 transfer descriptors (called ETDs)
* * 4Kb of Data memory
*
- * The data memory is shared between the host and fuction controlers
- * (but this driver only supports the host controler)
+ * The data memory is shared between the host and function controllers
+ * (but this driver only supports the host controller)
*
* So setting up a transfer involves:
* * Allocating a ETD
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 3b5785032a10..f3713f43f3fe 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -370,7 +370,6 @@ sanitize:
}
ep->hcpriv = NULL;
spin_unlock_irqrestore (&ohci->lock, flags);
- return;
}
static int ohci_get_frame (struct usb_hcd *hcd)
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index d32c3eae99cb..32149be4ad8e 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -544,8 +544,6 @@ static void oxu_buf_free(struct oxu_hcd *oxu, struct ehci_qtd *qtd)
qtd->buffer = NULL;
spin_unlock(&oxu->mem_lock);
-
- return;
}
static inline void ehci_qtd_init(struct ehci_qtd *qtd, dma_addr_t dma)
@@ -571,8 +569,6 @@ static inline void oxu_qtd_free(struct oxu_hcd *oxu, struct ehci_qtd *qtd)
oxu->qtd_used[index] = 0;
spin_unlock(&oxu->mem_lock);
-
- return;
}
static struct ehci_qtd *ehci_qtd_alloc(struct oxu_hcd *oxu)
@@ -615,8 +611,6 @@ static void oxu_qh_free(struct oxu_hcd *oxu, struct ehci_qh *qh)
oxu->qh_used[index] = 0;
spin_unlock(&oxu->mem_lock);
-
- return;
}
static void qh_destroy(struct kref *kref)
@@ -693,8 +687,6 @@ static void oxu_murb_free(struct oxu_hcd *oxu, struct oxu_murb *murb)
oxu->murb_used[index] = 0;
spin_unlock(&oxu->mem_lock);
-
- return;
}
static struct oxu_murb *oxu_murb_alloc(struct oxu_hcd *oxu)
@@ -3070,7 +3062,6 @@ nogood:
ep->hcpriv = NULL;
done:
spin_unlock_irqrestore(&oxu->lock, flags);
- return;
}
static int oxu_get_frame(struct usb_hcd *hcd)
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 464ed977b45d..4c502c890ebd 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -342,8 +342,6 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
writel(0x3f, op_reg_base + EHCI_USBSTS);
iounmap(base);
-
- return;
}
/*
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 77be3c24a427..3076b1cc05df 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -2397,7 +2397,7 @@ static const struct dev_pm_ops r8a66597_dev_pm_ops = {
#define R8A66597_DEV_PM_OPS NULL
#endif
-static int __init_or_module r8a66597_remove(struct platform_device *pdev)
+static int __devexit r8a66597_remove(struct platform_device *pdev)
{
struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
@@ -2542,7 +2542,7 @@ clean_up:
static struct platform_driver r8a66597_driver = {
.probe = r8a66597_probe,
- .remove = r8a66597_remove,
+ .remove = __devexit_p(r8a66597_remove),
.driver = {
.name = (char *) hcd_name,
.owner = THIS_MODULE,
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 5b31bae92dbc..fab764946c74 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -316,7 +316,6 @@ static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring,
} else if (queue_delayed_work(workqueue, &ring->scheduler, 0))
return;
kref_put(&u132->kref, u132_hcd_delete);
- return;
}
static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring,
@@ -324,7 +323,6 @@ static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring,
{
kref_get(&u132->kref);
u132_ring_requeue_work(u132, ring, delta);
- return;
}
static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring)
@@ -543,7 +541,6 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
mutex_unlock(&u132->scheduler_lock);
u132_endp_put_kref(u132, endp);
usb_hcd_giveback_urb(hcd, urb, status);
- return;
}
static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp,
@@ -574,8 +571,8 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
endp->active = 0;
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
kfree(urbq);
- } usb_hcd_giveback_urb(hcd, urb, status);
- return;
+ }
+ usb_hcd_giveback_urb(hcd, urb, status);
}
static inline int edset_input(struct u132 *u132, struct u132_ring *ring,
@@ -3085,7 +3082,6 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
u132->endp[endps] = NULL;
mutex_unlock(&u132->sw_lock);
- return;
}
static int __devinit u132_probe(struct platform_device *pdev)
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 3a6bcd5fee09..5a47805d9580 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -398,7 +398,6 @@ void mts_int_submit_urb (struct urb* transfer,
context->srb->result = DID_ERROR << 16;
mts_transfer_cleanup(transfer);
}
- return;
}
@@ -409,7 +408,6 @@ static void mts_transfer_cleanup( struct urb *transfer )
if ( likely(context->final_callback != NULL) )
context->final_callback(context->srb);
-
}
static void mts_transfer_done( struct urb *transfer )
@@ -420,8 +418,6 @@ static void mts_transfer_done( struct urb *transfer )
context->srb->result |= (unsigned)(*context->scsi_status)<<1;
mts_transfer_cleanup(transfer);
-
- return;
}
@@ -452,8 +448,6 @@ static void mts_data_done( struct urb* transfer )
}
mts_get_status(transfer);
-
- return;
}
@@ -496,8 +490,6 @@ static void mts_command_done( struct urb *transfer )
mts_get_status(transfer);
}
}
-
- return;
}
static void mts_do_sg (struct urb* transfer)
@@ -522,7 +514,6 @@ static void mts_do_sg (struct urb* transfer)
sg[context->fragment].length,
context->fragment + 1 == scsi_sg_count(context->srb) ?
mts_data_done : mts_do_sg);
- return;
}
static const u8 mts_read_image_sig[] = { 0x28, 00, 00, 00 };
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index c8eec9c2d89e..7839c98fa742 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -456,7 +456,6 @@ static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi)
static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi)
{
ftdi_command_queue_work(ftdi, 0);
- return;
}
static void ftdi_elan_command_work(struct work_struct *work)
@@ -483,7 +482,6 @@ static void ftdi_elan_command_work(struct work_struct *work)
static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi)
{
ftdi_respond_queue_work(ftdi, 0);
- return;
}
static void ftdi_elan_respond_work(struct work_struct *work)
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index 812dc288bb8c..10405119985c 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -90,7 +90,6 @@ static void mon_bus_submit(struct mon_bus *mbus, struct urb *urb)
r->rnf_submit(r->r_data, urb);
}
spin_unlock_irqrestore(&mbus->lock, flags);
- return;
}
static void mon_submit(struct usb_bus *ubus, struct urb *urb)
@@ -117,7 +116,6 @@ static void mon_bus_submit_error(struct mon_bus *mbus, struct urb *urb, int erro
r->rnf_error(r->r_data, urb, error);
}
spin_unlock_irqrestore(&mbus->lock, flags);
- return;
}
static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 95058109f9fa..c2b29761fa98 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -176,7 +176,7 @@ config USB_SERIAL_VISOR
help
Say Y here if you want to connect to your HandSpring Visor, Palm
m500 or m505 through its USB docking station. See
- <http://usbvisor.sourceforge.net/> for more information on using this
+ <http://usbvisor.sourceforge.net/index.php3> for more information on using this
driver.
To compile this driver as a module, choose M here: the
@@ -289,7 +289,7 @@ config USB_SERIAL_KEYSPAN
and was developed with their support. You must also include
firmware to support your particular device(s).
- See <http://misc.nu/hugh/keyspan.html> for more information.
+ See <http://blemings.org/hugh/keyspan.html> for more information.
To compile this driver as a module, choose M here: the
module will be called keyspan.
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index f5d06746cc3b..2edf238b00b9 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -1320,8 +1320,6 @@ continue_read:
cypress_set_dead(port);
}
}
-
- return;
} /* cypress_read_int_callback */
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 37b57c785cc7..89a9a5847803 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -2108,7 +2108,6 @@ static void ftdi_set_termios(struct tty_struct *tty,
}
}
- return;
}
static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index cf1aea1b9ee7..7dfe02f1fb6a 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -46,7 +46,7 @@
#define FTDI_USINT_RS232_PID 0xb812 /* Navigator RS232 and CONFIG lines */
/* OOCDlink by Joern Kaipf <joernk@web.de>
- * (http://www.joernonline.de/dw/doku.php?id=start&idx=projects:oocdlink) */
+ * (http://www.joernonline.de/) */
#define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */
/* Luminary Micro Stellaris Boards, VID = FTDI_VID */
@@ -336,7 +336,7 @@
#define FTDI_PIEGROUP_PID 0xF208 /* Product Id */
/* ACT Solutions HomePro ZWave interface
- (http://www.act-solutions.com/HomePro.htm) */
+ (http://www.act-solutions.com/HomePro-Product-Matrix.html) */
#define FTDI_ACTZWAVE_PID 0xF2D0
/*
@@ -367,7 +367,7 @@
#define FTDI_SUUNTO_SPORTS_PID 0xF680 /* Suunto Sports instrument */
/* USB-UIRT - An infrared receiver and transmitter using the 8U232AM chip */
-/* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */
+/* http://www.usbuirt.com/ */
#define FTDI_USB_UIRT_PID 0xF850 /* Product Id */
/* CCS Inc. ICDU/ICDU40 product ID -
@@ -396,7 +396,7 @@
*/
#define FTDI_HE_TIRA1_PID 0xFA78 /* Tira-1 IR transceiver */
-/* Inside Accesso contactless reader (http://www.insidefr.com) */
+/* Inside Accesso contactless reader (http://www.insidecontactless.com/) */
#define INSIDE_ACCESSO 0xFAD0
/*
@@ -635,14 +635,14 @@
/*
* JETI SPECTROMETER SPECBOS 1201
- * http://www.jeti.com/products/sys/scb/scb1201.php
+ * http://www.jeti.com/cms/index.php/instruments/other-instruments/specbos-2101
*/
#define JETI_VID 0x0c6c
#define JETI_SPC1201_PID 0x04b2
/*
* FTDI USB UART chips used in construction projects from the
- * Elektor Electronics magazine (http://elektor-electronics.co.uk)
+ * Elektor Electronics magazine (http://www.elektor.com/)
*/
#define ELEKTOR_VID 0x0C7D
#define ELEKTOR_FT323R_PID 0x0005 /* RFID-Reader, issue 09-2006 */
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index a42b29a695b2..26710b189918 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1264,7 +1264,6 @@ static void garmin_read_bulk_callback(struct urb *urb)
garmin_data_p->flags &= ~FLAGS_BULK_IN_ACTIVE;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
}
- return;
}
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index a0ab78ada25e..cd769ef24f8a 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -1467,8 +1467,6 @@ static void edge_throttle(struct tty_struct *tty)
if (status != 0)
return;
}
-
- return;
}
@@ -1775,8 +1773,6 @@ static void edge_break(struct tty_struct *tty, int break_state)
dbg("%s - error sending break set/clear command.",
__func__);
}
-
- return;
}
@@ -2047,7 +2043,6 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
dbg("%s - Unrecognized IOSP status code %u", __func__, code);
break;
}
- return;
}
@@ -2100,8 +2095,6 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr)
/* Save the new modem status */
edge_port->shadowMSR = newMsr & 0xf0;
-
- return;
}
@@ -2148,8 +2141,6 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData,
icount->parity++;
if (newLsr & LSR_FRM_ERR)
icount->frame++;
-
- return;
}
@@ -2725,7 +2716,6 @@ static void change_port_settings(struct tty_struct *tty,
baud = tty_termios_baud_rate(old_termios);
tty_encode_baud_rate(tty, baud, baud);
}
- return;
}
@@ -2927,7 +2917,6 @@ static void load_application_firmware(struct edgeport_serial *edge_serial)
0x40, 0x4000, 0x0001, NULL, 0, 3000);
release_firmware(fw);
- return;
}
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 4dad27a0f22a..22506b095c4f 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -1571,8 +1571,6 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
}
}
tty_kref_put(tty);
-
- return;
}
static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
@@ -2424,7 +2422,6 @@ static void change_port_settings(struct tty_struct *tty,
dbg("%s - error %d when trying to write config to device",
__func__, status);
kfree(config);
- return;
}
static void edge_set_termios(struct tty_struct *tty,
@@ -2445,7 +2442,6 @@ static void edge_set_termios(struct tty_struct *tty,
return;
/* change the port settings to the new ones specified */
change_port_settings(tty, edge_port, old_termios);
- return;
}
static int edge_tiocmset(struct tty_struct *tty, struct file *file,
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index efc72113216b..12ed594f5f80 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -807,7 +807,6 @@ static void read_rxcmd_callback(struct urb *urb)
iuu_uart_read_callback, port);
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
dbg("%s - submit result = %d", __func__, result);
- return;
}
static int iuu_uart_on(struct usb_serial_port *port)
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 297163c3c610..0791778a66f3 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -9,7 +9,7 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
- See http://misc.nu/hugh/keyspan.html for more information.
+ See http://blemings.org/hugh/keyspan.html for more information.
Code in this driver inspired by and in a number of places taken
from Brian Warner's original Keyspan-PDA driver.
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index bf3297ddd186..2d8baf6ac472 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -9,7 +9,7 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
- See http://misc.nu/hugh/keyspan.html for more information.
+ See http://blemings.org/hugh/keyspan.html for more information.
Code in this driver inspired by and in a number of places taken
from Brian Warner's original Keyspan-PDA driver.
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 185fe9a7d4e0..a10dd5676ccc 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -292,7 +292,6 @@ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty)
port->interrupt_in_urb->dev = port->serial->dev;
if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
dbg(" usb_submit_urb(read urb) failed");
- return;
}
diff --git a/drivers/usb/serial/mct_u232.h b/drivers/usb/serial/mct_u232.h
index 3a3f5e6b8f96..d325bb8cb583 100644
--- a/drivers/usb/serial/mct_u232.h
+++ b/drivers/usb/serial/mct_u232.h
@@ -10,10 +10,9 @@
*
* This driver is for the device MCT USB-RS232 Converter (25 pin, Model No.
* U232-P25) from Magic Control Technology Corp. (there is also a 9 pin
- * Model No. U232-P9). See http://www.mct.com.tw/p_u232.html for further
- * information. The properties of this device are listed at the end of this
- * file. This device is available from various distributors. I know Hana,
- * http://www.hana.de and D-Link, http://www.dlink.com/products/usb/dsbs25.
+ * Model No. U232-P9). See http://www.mct.com.tw/products/product_us232.html
+ * for further information. The properties of this device are listed at the end
+ * of this file. This device was used in the Dlink DSB-S25.
*
* All of the information about the device was acquired by using SniffUSB
* on Windows98. The technical details of the reverse engineering are
@@ -458,7 +457,7 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial,
* embedded UART. Exhaustive documentation for these is available at:
*
* http://www.semiconductors.philips.com/pip/p87c52ubaa
- * http://www.semiconductors.philips.com/pip/pdiusbd12
+ * http://www.nxp.com/acrobat_download/various/PDIUSBD12_PROGRAMMING_GUIDE.pdf
*
* Thanks to Julian Highfield for the pointer to the Philips database.
*
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index fd0b6414f459..7d3bc9a3e2b6 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -827,7 +827,6 @@ exit:
dev_err(&urb->dev->dev,
"%s - Error %d submitting control urb\n",
__func__, result);
- return;
}
/*
@@ -907,7 +906,6 @@ exit:
dev_err(&urb->dev->dev,
"%s - Error %d submitting control urb\n",
__func__, result);
- return;
}
/*
@@ -1227,8 +1225,6 @@ static void mos7720_break(struct tty_struct *tty, int break_state)
mos7720_port->shadowLCR = data;
write_mos_reg(serial, port->number - port->serial->minor,
LCR, mos7720_port->shadowLCR);
-
- return;
}
/*
@@ -1746,7 +1742,6 @@ static void change_port_settings(struct tty_struct *tty,
dbg("usb_submit_urb(read bulk) failed, status = %d",
status);
}
- return;
}
/*
@@ -1803,7 +1798,6 @@ static void mos7720_set_termios(struct tty_struct *tty,
dbg("usb_submit_urb(read bulk) failed, status = %d",
status);
}
- return;
}
/*
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 93dad5853cd5..5627993f9e41 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1367,8 +1367,6 @@ static void mos7840_break(struct tty_struct *tty, int break_state)
mos7840_port->shadowLCR);
mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER,
mos7840_port->shadowLCR);
-
- return;
}
/*****************************************************************************
@@ -1599,8 +1597,6 @@ static void mos7840_throttle(struct tty_struct *tty)
if (status < 0)
return;
}
-
- return;
}
/*****************************************************************************
@@ -2075,8 +2071,6 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
mos7840_port->delta_msr_cond = 1;
dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x",
mos7840_port->shadowLCR);
-
- return;
}
/*****************************************************************************
@@ -2145,7 +2139,6 @@ static void mos7840_set_termios(struct tty_struct *tty,
mos7840_port->read_urb_busy = false;
}
}
- return;
}
/*****************************************************************************
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 89c724c0ac0a..60f38d5e64fc 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -246,8 +246,6 @@ static void omninet_read_bulk_callback(struct urb *urb)
dev_err(&port->dev,
"%s - failed resubmitting read urb, error %d\n",
__func__, result);
-
- return;
}
static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index d47b56e9e8ce..7481ff8a49e4 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -620,8 +620,6 @@ static void sierra_indat_callback(struct urb *urb)
dev_err(&port->dev, "resubmit read urb failed."
"(%d)\n", err);
}
-
- return;
}
static void sierra_instat_callback(struct urb *urb)
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index 329d311a35d9..765aa983bf58 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -441,7 +441,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
spcp8x5_set_workMode(serial->dev, 0x000a,
SET_WORKING_MODE_U2C, priv->type);
}
- return;
}
/* open the serial port. do some usb system call. set termios and get the line
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 0c70b4a621bb..fbc946797801 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -234,7 +234,6 @@ static void usb_wwan_indat_callback(struct urb *urb)
}
}
- return;
}
static void usb_wwan_outdat_callback(struct urb *urb)
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 12ed8209ca72..3f9ac88d588c 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -655,8 +655,6 @@ static void whiteheat_release(struct usb_serial *serial)
}
kfree(info);
}
-
- return;
}
static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -955,8 +953,6 @@ static void whiteheat_throttle(struct tty_struct *tty)
spin_lock_irq(&info->lock);
info->flags |= THROTTLED;
spin_unlock_irq(&info->lock);
-
- return;
}
@@ -975,8 +971,6 @@ static void whiteheat_unthrottle(struct tty_struct *tty)
if (actually_throttled)
rx_data_softint(&info->rx_work);
-
- return;
}
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index f2767cf2e229..49a489e03716 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -36,7 +36,7 @@ config USB_STORAGE_DATAFAB
depends on USB_STORAGE
help
Support for certain Datafab CompactFlash readers.
- Datafab has a web page at <http://www.datafabusa.com/>.
+ Datafab has a web page at <http://www.datafab.com/>.
If this driver is compiled as a module, it will be named ums-datafab.
diff --git a/drivers/uwb/Kconfig b/drivers/uwb/Kconfig
index bac8e7a6f17b..d100f54ed650 100644
--- a/drivers/uwb/Kconfig
+++ b/drivers/uwb/Kconfig
@@ -12,8 +12,7 @@ menuconfig UWB
technology using a wide spectrum (3.1-10.6GHz). It is
optimized for in-room use (480Mbps at 2 meters, 110Mbps at
10m). It serves as the transport layer for other protocols,
- such as Wireless USB (WUSB), IP (WLP) and upcoming
- Bluetooth and 1394
+ such as Wireless USB (WUSB).
The topology is peer to peer; however, higher level
protocols (such as WUSB) might impose a master/slave
@@ -58,13 +57,6 @@ config UWB_WHCI
To compile this driver select Y (built in) or M (module). It
is safe to select any even if you do not have the hardware.
-config UWB_WLP
- tristate "Support WiMedia Link Protocol (Ethernet/IP over UWB)"
- depends on UWB && NET
- help
- This is a common library for drivers that implement
- networking over UWB.
-
config UWB_I1480U
tristate "Support for Intel Wireless UWB Link 1480 HWA"
depends on UWB_HWA
@@ -77,14 +69,4 @@ config UWB_I1480U
To compile this driver select Y (built in) or M (module). It
is safe to select any even if you do not have the hardware.
-config UWB_I1480U_WLP
- tristate "Support for Intel Wireless UWB Link 1480 HWA's WLP interface"
- depends on UWB_I1480U && UWB_WLP && NET
- help
- This driver enables WLP support for the i1480 when connected via
- USB. WLP is the WiMedia Link Protocol, or IP over UWB.
-
- To compile this driver select Y (built in) or M (module). It
- is safe to select any even if you don't have the hardware.
-
endif # UWB
diff --git a/drivers/uwb/Makefile b/drivers/uwb/Makefile
index 2f98d080fe78..d47dd6e2942c 100644
--- a/drivers/uwb/Makefile
+++ b/drivers/uwb/Makefile
@@ -1,5 +1,4 @@
obj-$(CONFIG_UWB) += uwb.o
-obj-$(CONFIG_UWB_WLP) += wlp/
obj-$(CONFIG_UWB_WHCI) += umc.o whci.o whc-rc.o
obj-$(CONFIG_UWB_HWA) += hwa-rc.o
obj-$(CONFIG_UWB_I1480U) += i1480/
diff --git a/drivers/uwb/i1480/Makefile b/drivers/uwb/i1480/Makefile
index 212bbc7d4c32..d69da1684cfb 100644
--- a/drivers/uwb/i1480/Makefile
+++ b/drivers/uwb/i1480/Makefile
@@ -1,2 +1 @@
obj-$(CONFIG_UWB_I1480U) += dfu/ i1480-est.o
-obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp/
diff --git a/drivers/uwb/i1480/i1480-wlp.h b/drivers/uwb/i1480/i1480-wlp.h
deleted file mode 100644
index 18a8b0e4567b..000000000000
--- a/drivers/uwb/i1480/i1480-wlp.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Intel 1480 Wireless UWB Link
- * WLP specific definitions
- *
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- */
-
-#ifndef __i1480_wlp_h__
-#define __i1480_wlp_h__
-
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/uwb.h>
-#include <linux/if_ether.h>
-#include <asm/byteorder.h>
-
-/* New simplified header format? */
-#undef WLP_HDR_FMT_2 /* FIXME: rename */
-
-/**
- * Values of the Delivery ID & Type field when PCA or DRP
- *
- * The Delivery ID & Type field in the WLP TX header indicates whether
- * the frame is PCA or DRP. This is done based on the high level bit of
- * this field.
- * We use this constant to test if the traffic is PCA or DRP as follows:
- * if (wlp_tx_hdr_delivery_id_type(wlp_tx_hdr) & WLP_DRP)
- * this is DRP traffic
- * else
- * this is PCA traffic
- */
-enum deliver_id_type_bit {
- WLP_DRP = 8,
-};
-
-/**
- * WLP TX header
- *
- * Indicates UWB/WLP-specific transmission parameters for a network
- * packet.
- */
-struct wlp_tx_hdr {
- /* dword 0 */
- struct uwb_dev_addr dstaddr;
- u8 key_index;
- u8 mac_params;
- /* dword 1 */
- u8 phy_params;
-#ifndef WLP_HDR_FMT_2
- u8 reserved;
- __le16 oui01; /* FIXME: not so sure if __le16 or u8[2] */
- /* dword 2 */
- u8 oui2; /* if all LE, it could be merged */
- __le16 prid;
-#endif
-} __attribute__((packed));
-
-static inline int wlp_tx_hdr_delivery_id_type(const struct wlp_tx_hdr *hdr)
-{
- return hdr->mac_params & 0x0f;
-}
-
-static inline int wlp_tx_hdr_ack_policy(const struct wlp_tx_hdr *hdr)
-{
- return (hdr->mac_params >> 4) & 0x07;
-}
-
-static inline int wlp_tx_hdr_rts_cts(const struct wlp_tx_hdr *hdr)
-{
- return (hdr->mac_params >> 7) & 0x01;
-}
-
-static inline void wlp_tx_hdr_set_delivery_id_type(struct wlp_tx_hdr *hdr, int id)
-{
- hdr->mac_params = (hdr->mac_params & ~0x0f) | id;
-}
-
-static inline void wlp_tx_hdr_set_ack_policy(struct wlp_tx_hdr *hdr,
- enum uwb_ack_pol policy)
-{
- hdr->mac_params = (hdr->mac_params & ~0x70) | (policy << 4);
-}
-
-static inline void wlp_tx_hdr_set_rts_cts(struct wlp_tx_hdr *hdr, int rts_cts)
-{
- hdr->mac_params = (hdr->mac_params & ~0x80) | (rts_cts << 7);
-}
-
-static inline enum uwb_phy_rate wlp_tx_hdr_phy_rate(const struct wlp_tx_hdr *hdr)
-{
- return hdr->phy_params & 0x0f;
-}
-
-static inline int wlp_tx_hdr_tx_power(const struct wlp_tx_hdr *hdr)
-{
- return (hdr->phy_params >> 4) & 0x0f;
-}
-
-static inline void wlp_tx_hdr_set_phy_rate(struct wlp_tx_hdr *hdr, enum uwb_phy_rate rate)
-{
- hdr->phy_params = (hdr->phy_params & ~0x0f) | rate;
-}
-
-static inline void wlp_tx_hdr_set_tx_power(struct wlp_tx_hdr *hdr, int pwr)
-{
- hdr->phy_params = (hdr->phy_params & ~0xf0) | (pwr << 4);
-}
-
-
-/**
- * WLP RX header
- *
- * Provides UWB/WLP-specific transmission data for a received
- * network packet.
- */
-struct wlp_rx_hdr {
- /* dword 0 */
- struct uwb_dev_addr dstaddr;
- struct uwb_dev_addr srcaddr;
- /* dword 1 */
- u8 LQI;
- s8 RSSI;
- u8 reserved3;
-#ifndef WLP_HDR_FMT_2
- u8 oui0;
- /* dword 2 */
- __le16 oui12;
- __le16 prid;
-#endif
-} __attribute__((packed));
-
-
-/** User configurable options for WLP */
-struct wlp_options {
- struct mutex mutex; /* access to user configurable options*/
- struct wlp_tx_hdr def_tx_hdr; /* default tx hdr */
- u8 pca_base_priority;
- u8 bw_alloc; /*index into bw_allocs[] for PCA/DRP reservations*/
-};
-
-
-static inline
-void wlp_options_init(struct wlp_options *options)
-{
- mutex_init(&options->mutex);
- wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, UWB_ACK_INM);
- wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, 1);
- /* FIXME: default to phy caps */
- wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, UWB_PHY_RATE_480);
-#ifndef WLP_HDR_FMT_2
- options->def_tx_hdr.prid = cpu_to_le16(0x0000);
-#endif
-}
-
-
-/* sysfs helpers */
-
-extern ssize_t uwb_pca_base_priority_store(struct wlp_options *,
- const char *, size_t);
-extern ssize_t uwb_pca_base_priority_show(const struct wlp_options *, char *);
-extern ssize_t uwb_bw_alloc_store(struct wlp_options *, const char *, size_t);
-extern ssize_t uwb_bw_alloc_show(const struct wlp_options *, char *);
-extern ssize_t uwb_ack_policy_store(struct wlp_options *,
- const char *, size_t);
-extern ssize_t uwb_ack_policy_show(const struct wlp_options *, char *);
-extern ssize_t uwb_rts_cts_store(struct wlp_options *, const char *, size_t);
-extern ssize_t uwb_rts_cts_show(const struct wlp_options *, char *);
-extern ssize_t uwb_phy_rate_store(struct wlp_options *, const char *, size_t);
-extern ssize_t uwb_phy_rate_show(const struct wlp_options *, char *);
-
-
-/** Simple bandwidth allocation (temporary and too simple) */
-struct wlp_bw_allocs {
- const char *name;
- struct {
- u8 mask, stream;
- } tx, rx;
-};
-
-
-#endif /* #ifndef __i1480_wlp_h__ */
diff --git a/drivers/uwb/i1480/i1480u-wlp/Makefile b/drivers/uwb/i1480/i1480u-wlp/Makefile
deleted file mode 100644
index fe6709b8e68b..000000000000
--- a/drivers/uwb/i1480/i1480u-wlp/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp.o
-
-i1480u-wlp-objs := \
- lc.o \
- netdev.o \
- rx.o \
- sysfs.o \
- tx.o
diff --git a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h
deleted file mode 100644
index 2e31f536a347..000000000000
--- a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Intel 1480 Wireless UWB Link USB
- * Header formats, constants, general internal interfaces
- *
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * This is not an standard interface.
- *
- * FIXME: docs
- *
- * i1480u-wlp is pretty simple: two endpoints, one for tx, one for
- * rx. rx is polled. Network packets (ethernet, whatever) are wrapped
- * in i1480 TX or RX headers (for sending over the air), and these
- * packets are wrapped in UNTD headers (for sending to the WLP UWB
- * controller).
- *
- * UNTD packets (UNTD hdr + i1480 hdr + network packet) packets
- * cannot be bigger than i1480u_MAX_FRG_SIZE. When this happens, the
- * i1480 packet is broken in chunks/packets:
- *
- * UNTD-1st.hdr + i1480.hdr + payload
- * UNTD-next.hdr + payload
- * ...
- * UNTD-last.hdr + payload
- *
- * so that each packet is smaller or equal than i1480u_MAX_FRG_SIZE.
- *
- * All HW structures and bitmaps are little endian, so we need to play
- * ugly tricks when defining bitfields. Hoping for the day GCC
- * implements __attribute__((endian(1234))).
- *
- * FIXME: ROADMAP to the whole implementation
- */
-
-#ifndef __i1480u_wlp_h__
-#define __i1480u_wlp_h__
-
-#include <linux/usb.h>
-#include <linux/netdevice.h>
-#include <linux/uwb.h> /* struct uwb_rc, struct uwb_notifs_handler */
-#include <linux/wlp.h>
-#include "../i1480-wlp.h"
-
-#undef i1480u_FLOW_CONTROL /* Enable flow control code */
-
-/**
- * Basic flow control
- */
-enum {
- i1480u_TX_INFLIGHT_MAX = 1000,
- i1480u_TX_INFLIGHT_THRESHOLD = 100,
-};
-
-/** Maximum size of a transaction that we can tx/rx */
-enum {
- /* Maximum packet size computed as follows: max UNTD header (8) +
- * i1480 RX header (8) + max Ethernet header and payload (4096) +
- * Padding added by skb_reserve (2) to make post Ethernet payload
- * start on 16 byte boundary*/
- i1480u_MAX_RX_PKT_SIZE = 4114,
- i1480u_MAX_FRG_SIZE = 512,
- i1480u_RX_BUFS = 9,
-};
-
-
-/**
- * UNTD packet type
- *
- * We need to fragment any payload whose UNTD packet is going to be
- * bigger than i1480u_MAX_FRG_SIZE.
- */
-enum i1480u_pkt_type {
- i1480u_PKT_FRAG_1ST = 0x1,
- i1480u_PKT_FRAG_NXT = 0x0,
- i1480u_PKT_FRAG_LST = 0x2,
- i1480u_PKT_FRAG_CMP = 0x3
-};
-enum {
- i1480u_PKT_NONE = 0x4,
-};
-
-/** USB Network Transfer Descriptor - common */
-struct untd_hdr {
- u8 type;
- __le16 len;
-} __attribute__((packed));
-
-static inline enum i1480u_pkt_type untd_hdr_type(const struct untd_hdr *hdr)
-{
- return hdr->type & 0x03;
-}
-
-static inline int untd_hdr_rx_tx(const struct untd_hdr *hdr)
-{
- return (hdr->type >> 2) & 0x01;
-}
-
-static inline void untd_hdr_set_type(struct untd_hdr *hdr, enum i1480u_pkt_type type)
-{
- hdr->type = (hdr->type & ~0x03) | type;
-}
-
-static inline void untd_hdr_set_rx_tx(struct untd_hdr *hdr, int rx_tx)
-{
- hdr->type = (hdr->type & ~0x04) | (rx_tx << 2);
-}
-
-
-/**
- * USB Network Transfer Descriptor - Complete Packet
- *
- * This is for a packet that is smaller (header + payload) than
- * i1480u_MAX_FRG_SIZE.
- *
- * @hdr.total_len is the size of the payload; the payload doesn't
- * count this header nor the padding, but includes the size of i1480
- * header.
- */
-struct untd_hdr_cmp {
- struct untd_hdr hdr;
- u8 padding;
-} __attribute__((packed));
-
-
-/**
- * USB Network Transfer Descriptor - First fragment
- *
- * @hdr.len is the size of the *whole packet* (excluding UNTD
- * headers); @fragment_len is the size of the payload (excluding UNTD
- * headers, but including i1480 headers).
- */
-struct untd_hdr_1st {
- struct untd_hdr hdr;
- __le16 fragment_len;
- u8 padding[3];
-} __attribute__((packed));
-
-
-/**
- * USB Network Transfer Descriptor - Next / Last [Rest]
- *
- * @hdr.len is the size of the payload, not including headrs.
- */
-struct untd_hdr_rst {
- struct untd_hdr hdr;
- u8 padding;
-} __attribute__((packed));
-
-
-/**
- * Transmission context
- *
- * Wraps all the stuff needed to track a pending/active tx
- * operation.
- */
-struct i1480u_tx {
- struct list_head list_node;
- struct i1480u *i1480u;
- struct urb *urb;
-
- struct sk_buff *skb;
- struct wlp_tx_hdr *wlp_tx_hdr;
-
- void *buf; /* if NULL, no new buf was used */
- size_t buf_size;
-};
-
-/**
- * Basic flow control
- *
- * We maintain a basic flow control counter. "count" how many TX URBs are
- * outstanding. Only allow "max"
- * TX URBs to be outstanding. If this value is reached the queue will be
- * stopped. The queue will be restarted when there are
- * "threshold" URBs outstanding.
- * Maintain a counter of how many time the TX queue needed to be restarted
- * due to the "max" being exceeded and the "threshold" reached again. The
- * timestamp "restart_ts" is to keep track from when the counter was last
- * queried (see sysfs handling of file wlp_tx_inflight).
- */
-struct i1480u_tx_inflight {
- atomic_t count;
- unsigned long max;
- unsigned long threshold;
- unsigned long restart_ts;
- atomic_t restart_count;
-};
-
-/**
- * Instance of a i1480u WLP interface
- *
- * Keeps references to the USB device that wraps it, as well as it's
- * interface and associated UWB host controller. As well, it also
- * keeps a link to the netdevice for integration into the networking
- * stack.
- * We maintian separate error history for the tx and rx endpoints because
- * the implementation does not rely on locking - having one shared
- * structure between endpoints may cause problems. Adding locking to the
- * implementation will have higher cost than adding a separate structure.
- */
-struct i1480u {
- struct usb_device *usb_dev;
- struct usb_interface *usb_iface;
- struct net_device *net_dev;
-
- spinlock_t lock;
-
- /* RX context handling */
- struct sk_buff *rx_skb;
- struct uwb_dev_addr rx_srcaddr;
- size_t rx_untd_pkt_size;
- struct i1480u_rx_buf {
- struct i1480u *i1480u; /* back pointer */
- struct urb *urb;
- struct sk_buff *data; /* i1480u_MAX_RX_PKT_SIZE each */
- } rx_buf[i1480u_RX_BUFS]; /* N bufs */
-
- spinlock_t tx_list_lock; /* TX context */
- struct list_head tx_list;
- u8 tx_stream;
-
- struct stats lqe_stats, rssi_stats; /* radio statistics */
-
- /* Options we can set from sysfs */
- struct wlp_options options;
- struct uwb_notifs_handler uwb_notifs_handler;
- struct edc tx_errors;
- struct edc rx_errors;
- struct wlp wlp;
-#ifdef i1480u_FLOW_CONTROL
- struct urb *notif_urb;
- struct edc notif_edc; /* error density counter */
- u8 notif_buffer[1];
-#endif
- struct i1480u_tx_inflight tx_inflight;
-};
-
-/* Internal interfaces */
-extern void i1480u_rx_cb(struct urb *urb);
-extern int i1480u_rx_setup(struct i1480u *);
-extern void i1480u_rx_release(struct i1480u *);
-extern void i1480u_tx_release(struct i1480u *);
-extern int i1480u_xmit_frame(struct wlp *, struct sk_buff *,
- struct uwb_dev_addr *);
-extern void i1480u_stop_queue(struct wlp *);
-extern void i1480u_start_queue(struct wlp *);
-extern int i1480u_sysfs_setup(struct i1480u *);
-extern void i1480u_sysfs_release(struct i1480u *);
-
-/* netdev interface */
-extern int i1480u_open(struct net_device *);
-extern int i1480u_stop(struct net_device *);
-extern netdev_tx_t i1480u_hard_start_xmit(struct sk_buff *,
- struct net_device *);
-extern void i1480u_tx_timeout(struct net_device *);
-extern int i1480u_set_config(struct net_device *, struct ifmap *);
-extern int i1480u_change_mtu(struct net_device *, int);
-extern void i1480u_uwb_notifs_cb(void *, struct uwb_dev *, enum uwb_notifs);
-
-/* bandwidth allocation callback */
-extern void i1480u_bw_alloc_cb(struct uwb_rsv *);
-
-/* Sys FS */
-extern struct attribute_group i1480u_wlp_attr_group;
-
-#endif /* #ifndef __i1480u_wlp_h__ */
diff --git a/drivers/uwb/i1480/i1480u-wlp/lc.c b/drivers/uwb/i1480/i1480u-wlp/lc.c
deleted file mode 100644
index def778cf2216..000000000000
--- a/drivers/uwb/i1480/i1480u-wlp/lc.c
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * WUSB Wire Adapter: WLP interface
- * Driver for the Linux Network stack.
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- *
- * This implements a very simple network driver for the WLP USB
- * device that is associated to a UWB (Ultra Wide Band) host.
- *
- * This is seen as an interface of a composite device. Once the UWB
- * host has an association to another WLP capable device, the
- * networking interface (aka WLP) can start to send packets back and
- * forth.
- *
- * Limitations:
- *
- * - Hand cranked; can't ifup the interface until there is an association
- *
- * - BW allocation very simplistic [see i1480u_mas_set() and callees].
- *
- *
- * ROADMAP:
- *
- * ENTRY POINTS (driver model):
- *
- * i1480u_driver_{exit,init}(): initialization of the driver.
- *
- * i1480u_probe(): called by the driver code when a device
- * matching 'i1480u_id_table' is connected.
- *
- * This allocs a netdev instance, inits with
- * i1480u_add(), then registers_netdev().
- * i1480u_init()
- * i1480u_add()
- *
- * i1480u_disconnect(): device has been disconnected/module
- * is being removed.
- * i1480u_rm()
- */
-#include <linux/gfp.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-
-#include "i1480u-wlp.h"
-
-
-
-static inline
-void i1480u_init(struct i1480u *i1480u)
-{
- /* nothing so far... doesn't it suck? */
- spin_lock_init(&i1480u->lock);
- INIT_LIST_HEAD(&i1480u->tx_list);
- spin_lock_init(&i1480u->tx_list_lock);
- wlp_options_init(&i1480u->options);
- edc_init(&i1480u->tx_errors);
- edc_init(&i1480u->rx_errors);
-#ifdef i1480u_FLOW_CONTROL
- edc_init(&i1480u->notif_edc);
-#endif
- stats_init(&i1480u->lqe_stats);
- stats_init(&i1480u->rssi_stats);
- wlp_init(&i1480u->wlp);
-}
-
-/**
- * Fill WLP device information structure
- *
- * The structure will contain a few character arrays, each ending with a
- * null terminated string. Each string has to fit (excluding terminating
- * character) into a specified range obtained from the WLP substack.
- *
- * It is still not clear exactly how this device information should be
- * obtained. Until we find out we use the USB device descriptor as backup, some
- * information elements have intuitive mappings, other not.
- */
-static
-void i1480u_fill_device_info(struct wlp *wlp, struct wlp_device_info *dev_info)
-{
- struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
- struct usb_device *usb_dev = i1480u->usb_dev;
- /* Treat device name and model name the same */
- if (usb_dev->descriptor.iProduct) {
- usb_string(usb_dev, usb_dev->descriptor.iProduct,
- dev_info->name, sizeof(dev_info->name));
- usb_string(usb_dev, usb_dev->descriptor.iProduct,
- dev_info->model_name, sizeof(dev_info->model_name));
- }
- if (usb_dev->descriptor.iManufacturer)
- usb_string(usb_dev, usb_dev->descriptor.iManufacturer,
- dev_info->manufacturer,
- sizeof(dev_info->manufacturer));
- scnprintf(dev_info->model_nr, sizeof(dev_info->model_nr), "%04x",
- __le16_to_cpu(usb_dev->descriptor.bcdDevice));
- if (usb_dev->descriptor.iSerialNumber)
- usb_string(usb_dev, usb_dev->descriptor.iSerialNumber,
- dev_info->serial, sizeof(dev_info->serial));
- /* FIXME: where should we obtain category? */
- dev_info->prim_dev_type.category = cpu_to_le16(WLP_DEV_CAT_OTHER);
- /* FIXME: Complete OUI and OUIsubdiv attributes */
-}
-
-#ifdef i1480u_FLOW_CONTROL
-/**
- * Callback for the notification endpoint
- *
- * This mostly controls the xon/xoff protocol. In case of hard error,
- * we stop the queue. If not, we always retry.
- */
-static
-void i1480u_notif_cb(struct urb *urb, struct pt_regs *regs)
-{
- struct i1480u *i1480u = urb->context;
- struct usb_interface *usb_iface = i1480u->usb_iface;
- struct device *dev = &usb_iface->dev;
- int result;
-
- switch (urb->status) {
- case 0: /* Got valid data, do xon/xoff */
- switch (i1480u->notif_buffer[0]) {
- case 'N':
- dev_err(dev, "XOFF STOPPING queue at %lu\n", jiffies);
- netif_stop_queue(i1480u->net_dev);
- break;
- case 'A':
- dev_err(dev, "XON STARTING queue at %lu\n", jiffies);
- netif_start_queue(i1480u->net_dev);
- break;
- default:
- dev_err(dev, "NEP: unknown data 0x%02hhx\n",
- i1480u->notif_buffer[0]);
- }
- break;
- case -ECONNRESET: /* Controlled situation ... */
- case -ENOENT: /* we killed the URB... */
- dev_err(dev, "NEP: URB reset/noent %d\n", urb->status);
- goto error;
- case -ESHUTDOWN: /* going away! */
- dev_err(dev, "NEP: URB down %d\n", urb->status);
- goto error;
- default: /* Retry unless it gets ugly */
- if (edc_inc(&i1480u->notif_edc, EDC_MAX_ERRORS,
- EDC_ERROR_TIMEFRAME)) {
- dev_err(dev, "NEP: URB max acceptable errors "
- "exceeded; resetting device\n");
- goto error_reset;
- }
- dev_err(dev, "NEP: URB error %d\n", urb->status);
- break;
- }
- result = usb_submit_urb(urb, GFP_ATOMIC);
- if (result < 0) {
- dev_err(dev, "NEP: Can't resubmit URB: %d; resetting device\n",
- result);
- goto error_reset;
- }
- return;
-
-error_reset:
- wlp_reset_all(&i1480-wlp);
-error:
- netif_stop_queue(i1480u->net_dev);
- return;
-}
-#endif
-
-static const struct net_device_ops i1480u_netdev_ops = {
- .ndo_open = i1480u_open,
- .ndo_stop = i1480u_stop,
- .ndo_start_xmit = i1480u_hard_start_xmit,
- .ndo_tx_timeout = i1480u_tx_timeout,
- .ndo_set_config = i1480u_set_config,
- .ndo_change_mtu = i1480u_change_mtu,
-};
-
-static
-int i1480u_add(struct i1480u *i1480u, struct usb_interface *iface)
-{
- int result = -ENODEV;
- struct wlp *wlp = &i1480u->wlp;
- struct usb_device *usb_dev = interface_to_usbdev(iface);
- struct net_device *net_dev = i1480u->net_dev;
- struct uwb_rc *rc;
- struct uwb_dev *uwb_dev;
-#ifdef i1480u_FLOW_CONTROL
- struct usb_endpoint_descriptor *epd;
-#endif
-
- i1480u->usb_dev = usb_get_dev(usb_dev);
- i1480u->usb_iface = iface;
- rc = uwb_rc_get_by_grandpa(&i1480u->usb_dev->dev);
- if (rc == NULL) {
- dev_err(&iface->dev, "Cannot get associated UWB Radio "
- "Controller\n");
- goto out;
- }
- wlp->xmit_frame = i1480u_xmit_frame;
- wlp->fill_device_info = i1480u_fill_device_info;
- wlp->stop_queue = i1480u_stop_queue;
- wlp->start_queue = i1480u_start_queue;
- result = wlp_setup(wlp, rc, net_dev);
- if (result < 0) {
- dev_err(&iface->dev, "Cannot setup WLP\n");
- goto error_wlp_setup;
- }
- result = 0;
- ether_setup(net_dev); /* make it an etherdevice */
- uwb_dev = &rc->uwb_dev;
- /* FIXME: hookup address change notifications? */
-
- memcpy(net_dev->dev_addr, uwb_dev->mac_addr.data,
- sizeof(net_dev->dev_addr));
-
- net_dev->hard_header_len = sizeof(struct untd_hdr_cmp)
- + sizeof(struct wlp_tx_hdr)
- + WLP_DATA_HLEN
- + ETH_HLEN;
- net_dev->mtu = 3500;
- net_dev->tx_queue_len = 20; /* FIXME: maybe use 1000? */
-
-/* net_dev->flags &= ~IFF_BROADCAST; FIXME: BUG in firmware */
- /* FIXME: multicast disabled */
- net_dev->flags &= ~IFF_MULTICAST;
- net_dev->features &= ~NETIF_F_SG;
- net_dev->features &= ~NETIF_F_FRAGLIST;
- /* All NETIF_F_*_CSUM disabled */
- net_dev->features |= NETIF_F_HIGHDMA;
- net_dev->watchdog_timeo = 5*HZ; /* FIXME: a better default? */
-
- net_dev->netdev_ops = &i1480u_netdev_ops;
-
-#ifdef i1480u_FLOW_CONTROL
- /* Notification endpoint setup (submitted when we open the device) */
- i1480u->notif_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (i1480u->notif_urb == NULL) {
- dev_err(&iface->dev, "Unable to allocate notification URB\n");
- result = -ENOMEM;
- goto error_urb_alloc;
- }
- epd = &iface->cur_altsetting->endpoint[0].desc;
- usb_fill_int_urb(i1480u->notif_urb, usb_dev,
- usb_rcvintpipe(usb_dev, epd->bEndpointAddress),
- i1480u->notif_buffer, sizeof(i1480u->notif_buffer),
- i1480u_notif_cb, i1480u, epd->bInterval);
-
-#endif
-
- i1480u->tx_inflight.max = i1480u_TX_INFLIGHT_MAX;
- i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD;
- i1480u->tx_inflight.restart_ts = jiffies;
- usb_set_intfdata(iface, i1480u);
- return result;
-
-#ifdef i1480u_FLOW_CONTROL
-error_urb_alloc:
-#endif
- wlp_remove(wlp);
-error_wlp_setup:
- uwb_rc_put(rc);
-out:
- usb_put_dev(i1480u->usb_dev);
- return result;
-}
-
-static void i1480u_rm(struct i1480u *i1480u)
-{
- struct uwb_rc *rc = i1480u->wlp.rc;
- usb_set_intfdata(i1480u->usb_iface, NULL);
-#ifdef i1480u_FLOW_CONTROL
- usb_kill_urb(i1480u->notif_urb);
- usb_free_urb(i1480u->notif_urb);
-#endif
- wlp_remove(&i1480u->wlp);
- uwb_rc_put(rc);
- usb_put_dev(i1480u->usb_dev);
-}
-
-/** Just setup @net_dev's i1480u private data */
-static void i1480u_netdev_setup(struct net_device *net_dev)
-{
- struct i1480u *i1480u = netdev_priv(net_dev);
- /* Initialize @i1480u */
- memset(i1480u, 0, sizeof(*i1480u));
- i1480u_init(i1480u);
-}
-
-/**
- * Probe a i1480u interface and register it
- *
- * @iface: USB interface to link to
- * @id: USB class/subclass/protocol id
- * @returns: 0 if ok, < 0 errno code on error.
- *
- * Does basic housekeeping stuff and then allocs a netdev with space
- * for the i1480u data. Initializes, registers in i1480u, registers in
- * netdev, ready to go.
- */
-static int i1480u_probe(struct usb_interface *iface,
- const struct usb_device_id *id)
-{
- int result;
- struct net_device *net_dev;
- struct device *dev = &iface->dev;
- struct i1480u *i1480u;
-
- /* Allocate instance [calls i1480u_netdev_setup() on it] */
- result = -ENOMEM;
- net_dev = alloc_netdev(sizeof(*i1480u), "wlp%d", i1480u_netdev_setup);
- if (net_dev == NULL) {
- dev_err(dev, "no memory for network device instance\n");
- goto error_alloc_netdev;
- }
- SET_NETDEV_DEV(net_dev, dev);
- i1480u = netdev_priv(net_dev);
- i1480u->net_dev = net_dev;
- result = i1480u_add(i1480u, iface); /* Now setup all the wlp stuff */
- if (result < 0) {
- dev_err(dev, "cannot add i1480u device: %d\n", result);
- goto error_i1480u_add;
- }
- result = register_netdev(net_dev); /* Okey dokey, bring it up */
- if (result < 0) {
- dev_err(dev, "cannot register network device: %d\n", result);
- goto error_register_netdev;
- }
- i1480u_sysfs_setup(i1480u);
- if (result < 0)
- goto error_sysfs_init;
- return 0;
-
-error_sysfs_init:
- unregister_netdev(net_dev);
-error_register_netdev:
- i1480u_rm(i1480u);
-error_i1480u_add:
- free_netdev(net_dev);
-error_alloc_netdev:
- return result;
-}
-
-
-/**
- * Disconect a i1480u from the system.
- *
- * i1480u_stop() has been called before, so al the rx and tx contexts
- * have been taken down already. Make sure the queue is stopped,
- * unregister netdev and i1480u, free and kill.
- */
-static void i1480u_disconnect(struct usb_interface *iface)
-{
- struct i1480u *i1480u;
- struct net_device *net_dev;
-
- i1480u = usb_get_intfdata(iface);
- net_dev = i1480u->net_dev;
- netif_stop_queue(net_dev);
-#ifdef i1480u_FLOW_CONTROL
- usb_kill_urb(i1480u->notif_urb);
-#endif
- i1480u_sysfs_release(i1480u);
- unregister_netdev(net_dev);
- i1480u_rm(i1480u);
- free_netdev(net_dev);
-}
-
-static struct usb_device_id i1480u_id_table[] = {
- {
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE \
- | USB_DEVICE_ID_MATCH_DEV_INFO \
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x8086,
- .idProduct = 0x0c3b,
- .bDeviceClass = 0xef,
- .bDeviceSubClass = 0x02,
- .bDeviceProtocol = 0x02,
- .bInterfaceClass = 0xff,
- .bInterfaceSubClass = 0xff,
- .bInterfaceProtocol = 0xff,
- },
- {},
-};
-MODULE_DEVICE_TABLE(usb, i1480u_id_table);
-
-static struct usb_driver i1480u_driver = {
- .name = KBUILD_MODNAME,
- .probe = i1480u_probe,
- .disconnect = i1480u_disconnect,
- .id_table = i1480u_id_table,
-};
-
-static int __init i1480u_driver_init(void)
-{
- return usb_register(&i1480u_driver);
-}
-module_init(i1480u_driver_init);
-
-
-static void __exit i1480u_driver_exit(void)
-{
- usb_deregister(&i1480u_driver);
-}
-module_exit(i1480u_driver_exit);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("i1480 Wireless UWB Link WLP networking for USB");
-MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/i1480/i1480u-wlp/netdev.c b/drivers/uwb/i1480/i1480u-wlp/netdev.c
deleted file mode 100644
index f98f6ce8b9e7..000000000000
--- a/drivers/uwb/i1480/i1480u-wlp/netdev.c
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * WUSB Wire Adapter: WLP interface
- * Driver for the Linux Network stack.
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- *
- * Implementation of the netdevice linkage (except tx and rx related stuff).
- *
- * ROADMAP:
- *
- * ENTRY POINTS (Net device):
- *
- * i1480u_open(): Called when we ifconfig up the interface;
- * associates to a UWB host controller, reserves
- * bandwidth (MAS), sets up RX USB URB and starts
- * the queue.
- *
- * i1480u_stop(): Called when we ifconfig down a interface;
- * reverses _open().
- *
- * i1480u_set_config():
- */
-
-#include <linux/slab.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-
-#include "i1480u-wlp.h"
-
-struct i1480u_cmd_set_ip_mas {
- struct uwb_rccb rccb;
- struct uwb_dev_addr addr;
- u8 stream;
- u8 owner;
- u8 type; /* enum uwb_drp_type */
- u8 baMAS[32];
-} __attribute__((packed));
-
-
-static
-int i1480u_set_ip_mas(
- struct uwb_rc *rc,
- const struct uwb_dev_addr *dstaddr,
- u8 stream, u8 owner, u8 type, unsigned long *mas)
-{
-
- int result;
- struct i1480u_cmd_set_ip_mas *cmd;
- struct uwb_rc_evt_confirm reply;
-
- result = -ENOMEM;
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (cmd == NULL)
- goto error_kzalloc;
- cmd->rccb.bCommandType = 0xfd;
- cmd->rccb.wCommand = cpu_to_le16(0x000e);
- cmd->addr = *dstaddr;
- cmd->stream = stream;
- cmd->owner = owner;
- cmd->type = type;
- if (mas == NULL)
- memset(cmd->baMAS, 0x00, sizeof(cmd->baMAS));
- else
- memcpy(cmd->baMAS, mas, sizeof(cmd->baMAS));
- reply.rceb.bEventType = 0xfd;
- reply.rceb.wEvent = cpu_to_le16(0x000e);
- result = uwb_rc_cmd(rc, "SET-IP-MAS", &cmd->rccb, sizeof(*cmd),
- &reply.rceb, sizeof(reply));
- if (result < 0)
- goto error_cmd;
- if (reply.bResultCode != UWB_RC_RES_FAIL) {
- dev_err(&rc->uwb_dev.dev,
- "SET-IP-MAS: command execution failed: %d\n",
- reply.bResultCode);
- result = -EIO;
- }
-error_cmd:
- kfree(cmd);
-error_kzalloc:
- return result;
-}
-
-/*
- * Inform a WLP interface of a MAS reservation
- *
- * @rc is assumed refcnted.
- */
-/* FIXME: detect if remote device is WLP capable? */
-static int i1480u_mas_set_dev(struct uwb_dev *uwb_dev, struct uwb_rc *rc,
- u8 stream, u8 owner, u8 type, unsigned long *mas)
-{
- int result = 0;
- struct device *dev = &rc->uwb_dev.dev;
-
- result = i1480u_set_ip_mas(rc, &uwb_dev->dev_addr, stream, owner,
- type, mas);
- if (result < 0) {
- char rcaddrbuf[UWB_ADDR_STRSIZE], devaddrbuf[UWB_ADDR_STRSIZE];
- uwb_dev_addr_print(rcaddrbuf, sizeof(rcaddrbuf),
- &rc->uwb_dev.dev_addr);
- uwb_dev_addr_print(devaddrbuf, sizeof(devaddrbuf),
- &uwb_dev->dev_addr);
- dev_err(dev, "Set IP MAS (%s to %s) failed: %d\n",
- rcaddrbuf, devaddrbuf, result);
- }
- return result;
-}
-
-/**
- * Called by bandwidth allocator when change occurs in reservation.
- *
- * @rsv: The reservation that is being established, modified, or
- * terminated.
- *
- * When a reservation is established, modified, or terminated the upper layer
- * (WLP here) needs set/update the currently available Media Access Slots
- * that can be use for IP traffic.
- *
- * Our action taken during failure depends on how the reservation is being
- * changed:
- * - if reservation is being established we do nothing if we cannot set the
- * new MAS to be used
- * - if reservation is being terminated we revert back to PCA whether the
- * SET IP MAS command succeeds or not.
- */
-void i1480u_bw_alloc_cb(struct uwb_rsv *rsv)
-{
- int result = 0;
- struct i1480u *i1480u = rsv->pal_priv;
- struct device *dev = &i1480u->usb_iface->dev;
- struct uwb_dev *target_dev = rsv->target.dev;
- struct uwb_rc *rc = i1480u->wlp.rc;
- u8 stream = rsv->stream;
- int type = rsv->type;
- int is_owner = rsv->owner == &rc->uwb_dev;
- unsigned long *bmp = rsv->mas.bm;
-
- dev_err(dev, "WLP callback called - sending set ip mas\n");
- /*user cannot change options while setting configuration*/
- mutex_lock(&i1480u->options.mutex);
- switch (rsv->state) {
- case UWB_RSV_STATE_T_ACCEPTED:
- case UWB_RSV_STATE_O_ESTABLISHED:
- result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner,
- type, bmp);
- if (result < 0) {
- dev_err(dev, "MAS reservation failed: %d\n", result);
- goto out;
- }
- if (is_owner) {
- wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr,
- WLP_DRP | stream);
- wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 0);
- }
- break;
- case UWB_RSV_STATE_NONE:
- /* revert back to PCA */
- result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner,
- type, bmp);
- if (result < 0)
- dev_err(dev, "MAS reservation failed: %d\n", result);
- /* Revert to PCA even though SET IP MAS failed. */
- wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr,
- i1480u->options.pca_base_priority);
- wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 1);
- break;
- default:
- dev_err(dev, "unexpected WLP reservation state: %s (%d).\n",
- uwb_rsv_state_str(rsv->state), rsv->state);
- break;
- }
-out:
- mutex_unlock(&i1480u->options.mutex);
- return;
-}
-
-/**
- *
- * Called on 'ifconfig up'
- */
-int i1480u_open(struct net_device *net_dev)
-{
- int result;
- struct i1480u *i1480u = netdev_priv(net_dev);
- struct wlp *wlp = &i1480u->wlp;
- struct uwb_rc *rc;
- struct device *dev = &i1480u->usb_iface->dev;
-
- rc = wlp->rc;
- result = i1480u_rx_setup(i1480u); /* Alloc RX stuff */
- if (result < 0)
- goto error_rx_setup;
-
- result = uwb_radio_start(&wlp->pal);
- if (result < 0)
- goto error_radio_start;
-
- netif_wake_queue(net_dev);
-#ifdef i1480u_FLOW_CONTROL
- result = usb_submit_urb(i1480u->notif_urb, GFP_KERNEL);
- if (result < 0) {
- dev_err(dev, "Can't submit notification URB: %d\n", result);
- goto error_notif_urb_submit;
- }
-#endif
- /* Interface is up with an address, now we can create WSS */
- result = wlp_wss_setup(net_dev, &wlp->wss);
- if (result < 0) {
- dev_err(dev, "Can't create WSS: %d. \n", result);
- goto error_wss_setup;
- }
- return 0;
-error_wss_setup:
-#ifdef i1480u_FLOW_CONTROL
- usb_kill_urb(i1480u->notif_urb);
-error_notif_urb_submit:
-#endif
- uwb_radio_stop(&wlp->pal);
-error_radio_start:
- netif_stop_queue(net_dev);
- i1480u_rx_release(i1480u);
-error_rx_setup:
- return result;
-}
-
-
-/**
- * Called on 'ifconfig down'
- */
-int i1480u_stop(struct net_device *net_dev)
-{
- struct i1480u *i1480u = netdev_priv(net_dev);
- struct wlp *wlp = &i1480u->wlp;
-
- BUG_ON(wlp->rc == NULL);
- wlp_wss_remove(&wlp->wss);
- netif_carrier_off(net_dev);
-#ifdef i1480u_FLOW_CONTROL
- usb_kill_urb(i1480u->notif_urb);
-#endif
- netif_stop_queue(net_dev);
- uwb_radio_stop(&wlp->pal);
- i1480u_rx_release(i1480u);
- i1480u_tx_release(i1480u);
- return 0;
-}
-
-/**
- *
- * Change the interface config--we probably don't have to do anything.
- */
-int i1480u_set_config(struct net_device *net_dev, struct ifmap *map)
-{
- int result;
- struct i1480u *i1480u = netdev_priv(net_dev);
- BUG_ON(i1480u->wlp.rc == NULL);
- result = 0;
- return result;
-}
-
-/**
- * Change the MTU of the interface
- */
-int i1480u_change_mtu(struct net_device *net_dev, int mtu)
-{
- static union {
- struct wlp_tx_hdr tx;
- struct wlp_rx_hdr rx;
- } i1480u_all_hdrs;
-
- if (mtu < ETH_HLEN) /* We encap eth frames */
- return -ERANGE;
- if (mtu > 4000 - sizeof(i1480u_all_hdrs))
- return -ERANGE;
- net_dev->mtu = mtu;
- return 0;
-}
-
-/**
- * Stop the network queue
- *
- * Enable WLP substack to stop network queue. We also set the flow control
- * threshold at this time to prevent the flow control from restarting the
- * queue.
- *
- * we are loosing the current threshold value here ... FIXME?
- */
-void i1480u_stop_queue(struct wlp *wlp)
-{
- struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
- struct net_device *net_dev = i1480u->net_dev;
- i1480u->tx_inflight.threshold = 0;
- netif_stop_queue(net_dev);
-}
-
-/**
- * Start the network queue
- *
- * Enable WLP substack to start network queue. Also re-enable the flow
- * control to manage the queue again.
- *
- * We re-enable the flow control by storing the default threshold in the
- * flow control threshold. This means that if the user modified the
- * threshold before the queue was stopped and restarted that information
- * will be lost. FIXME?
- */
-void i1480u_start_queue(struct wlp *wlp)
-{
- struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
- struct net_device *net_dev = i1480u->net_dev;
- i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD;
- netif_start_queue(net_dev);
-}
diff --git a/drivers/uwb/i1480/i1480u-wlp/rx.c b/drivers/uwb/i1480/i1480u-wlp/rx.c
deleted file mode 100644
index d4e51e108aa4..000000000000
--- a/drivers/uwb/i1480/i1480u-wlp/rx.c
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * WUSB Wire Adapter: WLP interface
- * Driver for the Linux Network stack.
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * i1480u's RX handling is simple. i1480u will send the received
- * network packets broken up in fragments; 1 to N fragments make a
- * packet, we assemble them together and deliver the packet with netif_rx().
- *
- * Beacuse each USB transfer is a *single* fragment (except when the
- * transfer contains a first fragment), each URB called thus
- * back contains one or two fragments. So we queue N URBs, each with its own
- * fragment buffer. When a URB is done, we process it (adding to the
- * current skb from the fragment buffer until complete). Once
- * processed, we requeue the URB. There is always a bunch of URBs
- * ready to take data, so the intergap should be minimal.
- *
- * An URB's transfer buffer is the data field of a socket buffer. This
- * reduces copying as data can be passed directly to network layer. If a
- * complete packet or 1st fragment is received the URB's transfer buffer is
- * taken away from it and used to send data to the network layer. In this
- * case a new transfer buffer is allocated to the URB before being requeued.
- * If a "NEXT" or "LAST" fragment is received, the fragment contents is
- * appended to the RX packet under construction and the transfer buffer
- * is reused. To be able to use this buffer to assemble complete packets
- * we set each buffer's size to that of the MAX ethernet packet that can
- * be received. There is thus room for improvement in memory usage.
- *
- * When the max tx fragment size increases, we should be able to read
- * data into the skbs directly with very simple code.
- *
- * ROADMAP:
- *
- * ENTRY POINTS:
- *
- * i1480u_rx_setup(): setup RX context [from i1480u_open()]
- *
- * i1480u_rx_release(): release RX context [from i1480u_stop()]
- *
- * i1480u_rx_cb(): called when the RX USB URB receives a
- * packet. It removes the header and pushes it up
- * the Linux netdev stack with netif_rx().
- *
- * i1480u_rx_buffer()
- * i1480u_drop() and i1480u_fix()
- * i1480u_skb_deliver
- *
- */
-
-#include <linux/gfp.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include "i1480u-wlp.h"
-
-/*
- * Setup the RX context
- *
- * Each URB is provided with a transfer_buffer that is the data field
- * of a new socket buffer.
- */
-int i1480u_rx_setup(struct i1480u *i1480u)
-{
- int result, cnt;
- struct device *dev = &i1480u->usb_iface->dev;
- struct net_device *net_dev = i1480u->net_dev;
- struct usb_endpoint_descriptor *epd;
- struct sk_buff *skb;
-
- /* Alloc RX stuff */
- i1480u->rx_skb = NULL; /* not in process of receiving packet */
- result = -ENOMEM;
- epd = &i1480u->usb_iface->cur_altsetting->endpoint[1].desc;
- for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) {
- struct i1480u_rx_buf *rx_buf = &i1480u->rx_buf[cnt];
- rx_buf->i1480u = i1480u;
- skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE);
- if (!skb) {
- dev_err(dev,
- "RX: cannot allocate RX buffer %d\n", cnt);
- result = -ENOMEM;
- goto error;
- }
- skb->dev = net_dev;
- skb->ip_summed = CHECKSUM_NONE;
- skb_reserve(skb, 2);
- rx_buf->data = skb;
- rx_buf->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (unlikely(rx_buf->urb == NULL)) {
- dev_err(dev, "RX: cannot allocate URB %d\n", cnt);
- result = -ENOMEM;
- goto error;
- }
- usb_fill_bulk_urb(rx_buf->urb, i1480u->usb_dev,
- usb_rcvbulkpipe(i1480u->usb_dev, epd->bEndpointAddress),
- rx_buf->data->data, i1480u_MAX_RX_PKT_SIZE - 2,
- i1480u_rx_cb, rx_buf);
- result = usb_submit_urb(rx_buf->urb, GFP_NOIO);
- if (unlikely(result < 0)) {
- dev_err(dev, "RX: cannot submit URB %d: %d\n",
- cnt, result);
- goto error;
- }
- }
- return 0;
-
-error:
- i1480u_rx_release(i1480u);
- return result;
-}
-
-
-/* Release resources associated to the rx context */
-void i1480u_rx_release(struct i1480u *i1480u)
-{
- int cnt;
- for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) {
- if (i1480u->rx_buf[cnt].data)
- dev_kfree_skb(i1480u->rx_buf[cnt].data);
- if (i1480u->rx_buf[cnt].urb) {
- usb_kill_urb(i1480u->rx_buf[cnt].urb);
- usb_free_urb(i1480u->rx_buf[cnt].urb);
- }
- }
- if (i1480u->rx_skb != NULL)
- dev_kfree_skb(i1480u->rx_skb);
-}
-
-static
-void i1480u_rx_unlink_urbs(struct i1480u *i1480u)
-{
- int cnt;
- for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) {
- if (i1480u->rx_buf[cnt].urb)
- usb_unlink_urb(i1480u->rx_buf[cnt].urb);
- }
-}
-
-/* Fix an out-of-sequence packet */
-#define i1480u_fix(i1480u, msg...) \
-do { \
- if (printk_ratelimit()) \
- dev_err(&i1480u->usb_iface->dev, msg); \
- dev_kfree_skb_irq(i1480u->rx_skb); \
- i1480u->rx_skb = NULL; \
- i1480u->rx_untd_pkt_size = 0; \
-} while (0)
-
-
-/* Drop an out-of-sequence packet */
-#define i1480u_drop(i1480u, msg...) \
-do { \
- if (printk_ratelimit()) \
- dev_err(&i1480u->usb_iface->dev, msg); \
- i1480u->net_dev->stats.rx_dropped++; \
-} while (0)
-
-
-
-
-/* Finalizes setting up the SKB and delivers it
- *
- * We first pass the incoming frame to WLP substack for verification. It
- * may also be a WLP association frame in which case WLP will take over the
- * processing. If WLP does not take it over it will still verify it, if the
- * frame is invalid the skb will be freed by WLP and we will not continue
- * parsing.
- * */
-static
-void i1480u_skb_deliver(struct i1480u *i1480u)
-{
- int should_parse;
- struct net_device *net_dev = i1480u->net_dev;
- struct device *dev = &i1480u->usb_iface->dev;
-
- should_parse = wlp_receive_frame(dev, &i1480u->wlp, i1480u->rx_skb,
- &i1480u->rx_srcaddr);
- if (!should_parse)
- goto out;
- i1480u->rx_skb->protocol = eth_type_trans(i1480u->rx_skb, net_dev);
- net_dev->stats.rx_packets++;
- net_dev->stats.rx_bytes += i1480u->rx_untd_pkt_size;
-
- netif_rx(i1480u->rx_skb); /* deliver */
-out:
- i1480u->rx_skb = NULL;
- i1480u->rx_untd_pkt_size = 0;
-}
-
-
-/*
- * Process a buffer of data received from the USB RX endpoint
- *
- * First fragment arrives with next or last fragment. All other fragments
- * arrive alone.
- *
- * /me hates long functions.
- */
-static
-void i1480u_rx_buffer(struct i1480u_rx_buf *rx_buf)
-{
- unsigned pkt_completed = 0; /* !0 when we got all pkt fragments */
- size_t untd_hdr_size, untd_frg_size;
- size_t i1480u_hdr_size;
- struct wlp_rx_hdr *i1480u_hdr = NULL;
-
- struct i1480u *i1480u = rx_buf->i1480u;
- struct sk_buff *skb = rx_buf->data;
- int size_left = rx_buf->urb->actual_length;
- void *ptr = rx_buf->urb->transfer_buffer; /* also rx_buf->data->data */
- struct untd_hdr *untd_hdr;
-
- struct net_device *net_dev = i1480u->net_dev;
- struct device *dev = &i1480u->usb_iface->dev;
- struct sk_buff *new_skb;
-
-#if 0
- dev_fnstart(dev,
- "(i1480u %p ptr %p size_left %zu)\n", i1480u, ptr, size_left);
- dev_err(dev, "RX packet, %zu bytes\n", size_left);
- dump_bytes(dev, ptr, size_left);
-#endif
- i1480u_hdr_size = sizeof(struct wlp_rx_hdr);
-
- while (size_left > 0) {
- if (pkt_completed) {
- i1480u_drop(i1480u, "RX: fragment follows completed"
- "packet in same buffer. Dropping\n");
- break;
- }
- untd_hdr = ptr;
- if (size_left < sizeof(*untd_hdr)) { /* Check the UNTD header */
- i1480u_drop(i1480u, "RX: short UNTD header! Dropping\n");
- goto out;
- }
- if (unlikely(untd_hdr_rx_tx(untd_hdr) == 0)) { /* Paranoia: TX set? */
- i1480u_drop(i1480u, "RX: TX bit set! Dropping\n");
- goto out;
- }
- switch (untd_hdr_type(untd_hdr)) { /* Check the UNTD header type */
- case i1480u_PKT_FRAG_1ST: {
- struct untd_hdr_1st *untd_hdr_1st = (void *) untd_hdr;
- dev_dbg(dev, "1st fragment\n");
- untd_hdr_size = sizeof(struct untd_hdr_1st);
- if (i1480u->rx_skb != NULL)
- i1480u_fix(i1480u, "RX: 1st fragment out of "
- "sequence! Fixing\n");
- if (size_left < untd_hdr_size + i1480u_hdr_size) {
- i1480u_drop(i1480u, "RX: short 1st fragment! "
- "Dropping\n");
- goto out;
- }
- i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len)
- - i1480u_hdr_size;
- untd_frg_size = le16_to_cpu(untd_hdr_1st->fragment_len);
- if (size_left < untd_hdr_size + untd_frg_size) {
- i1480u_drop(i1480u,
- "RX: short payload! Dropping\n");
- goto out;
- }
- i1480u->rx_skb = skb;
- i1480u_hdr = (void *) untd_hdr_1st + untd_hdr_size;
- i1480u->rx_srcaddr = i1480u_hdr->srcaddr;
- skb_put(i1480u->rx_skb, untd_hdr_size + untd_frg_size);
- skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size);
- stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7);
- stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18);
- rx_buf->data = NULL; /* need to create new buffer */
- break;
- }
- case i1480u_PKT_FRAG_NXT: {
- dev_dbg(dev, "nxt fragment\n");
- untd_hdr_size = sizeof(struct untd_hdr_rst);
- if (i1480u->rx_skb == NULL) {
- i1480u_drop(i1480u, "RX: next fragment out of "
- "sequence! Dropping\n");
- goto out;
- }
- if (size_left < untd_hdr_size) {
- i1480u_drop(i1480u, "RX: short NXT fragment! "
- "Dropping\n");
- goto out;
- }
- untd_frg_size = le16_to_cpu(untd_hdr->len);
- if (size_left < untd_hdr_size + untd_frg_size) {
- i1480u_drop(i1480u,
- "RX: short payload! Dropping\n");
- goto out;
- }
- memmove(skb_put(i1480u->rx_skb, untd_frg_size),
- ptr + untd_hdr_size, untd_frg_size);
- break;
- }
- case i1480u_PKT_FRAG_LST: {
- dev_dbg(dev, "Lst fragment\n");
- untd_hdr_size = sizeof(struct untd_hdr_rst);
- if (i1480u->rx_skb == NULL) {
- i1480u_drop(i1480u, "RX: last fragment out of "
- "sequence! Dropping\n");
- goto out;
- }
- if (size_left < untd_hdr_size) {
- i1480u_drop(i1480u, "RX: short LST fragment! "
- "Dropping\n");
- goto out;
- }
- untd_frg_size = le16_to_cpu(untd_hdr->len);
- if (size_left < untd_frg_size + untd_hdr_size) {
- i1480u_drop(i1480u,
- "RX: short payload! Dropping\n");
- goto out;
- }
- memmove(skb_put(i1480u->rx_skb, untd_frg_size),
- ptr + untd_hdr_size, untd_frg_size);
- pkt_completed = 1;
- break;
- }
- case i1480u_PKT_FRAG_CMP: {
- dev_dbg(dev, "cmp fragment\n");
- untd_hdr_size = sizeof(struct untd_hdr_cmp);
- if (i1480u->rx_skb != NULL)
- i1480u_fix(i1480u, "RX: fix out-of-sequence CMP"
- " fragment!\n");
- if (size_left < untd_hdr_size + i1480u_hdr_size) {
- i1480u_drop(i1480u, "RX: short CMP fragment! "
- "Dropping\n");
- goto out;
- }
- i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len);
- untd_frg_size = i1480u->rx_untd_pkt_size;
- if (size_left < i1480u->rx_untd_pkt_size + untd_hdr_size) {
- i1480u_drop(i1480u,
- "RX: short payload! Dropping\n");
- goto out;
- }
- i1480u->rx_skb = skb;
- i1480u_hdr = (void *) untd_hdr + untd_hdr_size;
- i1480u->rx_srcaddr = i1480u_hdr->srcaddr;
- stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7);
- stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18);
- skb_put(i1480u->rx_skb, untd_hdr_size + i1480u->rx_untd_pkt_size);
- skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size);
- rx_buf->data = NULL; /* for hand off skb to network stack */
- pkt_completed = 1;
- i1480u->rx_untd_pkt_size -= i1480u_hdr_size; /* accurate stat */
- break;
- }
- default:
- i1480u_drop(i1480u, "RX: unknown packet type %u! "
- "Dropping\n", untd_hdr_type(untd_hdr));
- goto out;
- }
- size_left -= untd_hdr_size + untd_frg_size;
- if (size_left > 0)
- ptr += untd_hdr_size + untd_frg_size;
- }
- if (pkt_completed)
- i1480u_skb_deliver(i1480u);
-out:
- /* recreate needed RX buffers*/
- if (rx_buf->data == NULL) {
- /* buffer is being used to receive packet, create new */
- new_skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE);
- if (!new_skb) {
- if (printk_ratelimit())
- dev_err(dev,
- "RX: cannot allocate RX buffer\n");
- } else {
- new_skb->dev = net_dev;
- new_skb->ip_summed = CHECKSUM_NONE;
- skb_reserve(new_skb, 2);
- rx_buf->data = new_skb;
- }
- }
- return;
-}
-
-
-/*
- * Called when an RX URB has finished receiving or has found some kind
- * of error condition.
- *
- * LIMITATIONS:
- *
- * - We read USB-transfers, each transfer contains a SINGLE fragment
- * (can contain a complete packet, or a 1st, next, or last fragment
- * of a packet).
- * Looks like a transfer can contain more than one fragment (07/18/06)
- *
- * - Each transfer buffer is the size of the maximum packet size (minus
- * headroom), i1480u_MAX_PKT_SIZE - 2
- *
- * - We always read the full USB-transfer, no partials.
- *
- * - Each transfer is read directly into a skb. This skb will be used to
- * send data to the upper layers if it is the first fragment or a complete
- * packet. In the other cases the data will be copied from the skb to
- * another skb that is being prepared for the upper layers from a prev
- * first fragment.
- *
- * It is simply too much of a pain. Gosh, there should be a unified
- * SG infrastructure for *everything* [so that I could declare a SG
- * buffer, pass it to USB for receiving, append some space to it if
- * I wish, receive more until I have the whole chunk, adapt
- * pointers on each fragment to remove hardware headers and then
- * attach that to an skbuff and netif_rx()].
- */
-void i1480u_rx_cb(struct urb *urb)
-{
- int result;
- int do_parse_buffer = 1;
- struct i1480u_rx_buf *rx_buf = urb->context;
- struct i1480u *i1480u = rx_buf->i1480u;
- struct device *dev = &i1480u->usb_iface->dev;
- unsigned long flags;
- u8 rx_buf_idx = rx_buf - i1480u->rx_buf;
-
- switch (urb->status) {
- case 0:
- break;
- case -ECONNRESET: /* Not an error, but a controlled situation; */
- case -ENOENT: /* (we killed the URB)...so, no broadcast */
- case -ESHUTDOWN: /* going away! */
- dev_err(dev, "RX URB[%u]: goind down %d\n",
- rx_buf_idx, urb->status);
- goto error;
- default:
- dev_err(dev, "RX URB[%u]: unknown status %d\n",
- rx_buf_idx, urb->status);
- if (edc_inc(&i1480u->rx_errors, EDC_MAX_ERRORS,
- EDC_ERROR_TIMEFRAME)) {
- dev_err(dev, "RX: max acceptable errors exceeded,"
- " resetting device.\n");
- i1480u_rx_unlink_urbs(i1480u);
- wlp_reset_all(&i1480u->wlp);
- goto error;
- }
- do_parse_buffer = 0;
- break;
- }
- spin_lock_irqsave(&i1480u->lock, flags);
- /* chew the data fragments, extract network packets */
- if (do_parse_buffer) {
- i1480u_rx_buffer(rx_buf);
- if (rx_buf->data) {
- rx_buf->urb->transfer_buffer = rx_buf->data->data;
- result = usb_submit_urb(rx_buf->urb, GFP_ATOMIC);
- if (result < 0) {
- dev_err(dev, "RX URB[%u]: cannot submit %d\n",
- rx_buf_idx, result);
- }
- }
- }
- spin_unlock_irqrestore(&i1480u->lock, flags);
-error:
- return;
-}
-
diff --git a/drivers/uwb/i1480/i1480u-wlp/sysfs.c b/drivers/uwb/i1480/i1480u-wlp/sysfs.c
deleted file mode 100644
index 4ffaf546cc6c..000000000000
--- a/drivers/uwb/i1480/i1480u-wlp/sysfs.c
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * WUSB Wire Adapter: WLP interface
- * Sysfs interfaces
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- */
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/device.h>
-
-#include "i1480u-wlp.h"
-
-
-/**
- *
- * @dev: Class device from the net_device; assumed refcnted.
- *
- * Yes, I don't lock--we assume it is refcounted and I am getting a
- * single byte value that is kind of atomic to read.
- */
-ssize_t uwb_phy_rate_show(const struct wlp_options *options, char *buf)
-{
- return sprintf(buf, "%u\n",
- wlp_tx_hdr_phy_rate(&options->def_tx_hdr));
-}
-EXPORT_SYMBOL_GPL(uwb_phy_rate_show);
-
-
-ssize_t uwb_phy_rate_store(struct wlp_options *options,
- const char *buf, size_t size)
-{
- ssize_t result;
- unsigned rate;
-
- result = sscanf(buf, "%u\n", &rate);
- if (result != 1) {
- result = -EINVAL;
- goto out;
- }
- result = -EINVAL;
- if (rate >= UWB_PHY_RATE_INVALID)
- goto out;
- wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, rate);
- result = 0;
-out:
- return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(uwb_phy_rate_store);
-
-
-ssize_t uwb_rts_cts_show(const struct wlp_options *options, char *buf)
-{
- return sprintf(buf, "%u\n",
- wlp_tx_hdr_rts_cts(&options->def_tx_hdr));
-}
-EXPORT_SYMBOL_GPL(uwb_rts_cts_show);
-
-
-ssize_t uwb_rts_cts_store(struct wlp_options *options,
- const char *buf, size_t size)
-{
- ssize_t result;
- unsigned value;
-
- result = sscanf(buf, "%u\n", &value);
- if (result != 1) {
- result = -EINVAL;
- goto out;
- }
- result = -EINVAL;
- wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, !!value);
- result = 0;
-out:
- return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(uwb_rts_cts_store);
-
-
-ssize_t uwb_ack_policy_show(const struct wlp_options *options, char *buf)
-{
- return sprintf(buf, "%u\n",
- wlp_tx_hdr_ack_policy(&options->def_tx_hdr));
-}
-EXPORT_SYMBOL_GPL(uwb_ack_policy_show);
-
-
-ssize_t uwb_ack_policy_store(struct wlp_options *options,
- const char *buf, size_t size)
-{
- ssize_t result;
- unsigned value;
-
- result = sscanf(buf, "%u\n", &value);
- if (result != 1 || value > UWB_ACK_B_REQ) {
- result = -EINVAL;
- goto out;
- }
- wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, value);
- result = 0;
-out:
- return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(uwb_ack_policy_store);
-
-
-/**
- * Show the PCA base priority.
- *
- * We can access without locking, as the value is (for now) orthogonal
- * to other values.
- */
-ssize_t uwb_pca_base_priority_show(const struct wlp_options *options,
- char *buf)
-{
- return sprintf(buf, "%u\n",
- options->pca_base_priority);
-}
-EXPORT_SYMBOL_GPL(uwb_pca_base_priority_show);
-
-
-/**
- * Set the PCA base priority.
- *
- * We can access without locking, as the value is (for now) orthogonal
- * to other values.
- */
-ssize_t uwb_pca_base_priority_store(struct wlp_options *options,
- const char *buf, size_t size)
-{
- ssize_t result = -EINVAL;
- u8 pca_base_priority;
-
- result = sscanf(buf, "%hhu\n", &pca_base_priority);
- if (result != 1) {
- result = -EINVAL;
- goto out;
- }
- result = -EINVAL;
- if (pca_base_priority >= 8)
- goto out;
- options->pca_base_priority = pca_base_priority;
- /* Update TX header if we are currently using PCA. */
- if (result >= 0 && (wlp_tx_hdr_delivery_id_type(&options->def_tx_hdr) & WLP_DRP) == 0)
- wlp_tx_hdr_set_delivery_id_type(&options->def_tx_hdr, options->pca_base_priority);
- result = 0;
-out:
- return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(uwb_pca_base_priority_store);
-
-/**
- * Show current inflight values
- *
- * Will print the current MAX and THRESHOLD values for the basic flow
- * control. In addition it will report how many times the TX queue needed
- * to be restarted since the last time this query was made.
- */
-static ssize_t wlp_tx_inflight_show(struct i1480u_tx_inflight *inflight,
- char *buf)
-{
- ssize_t result;
- unsigned long sec_elapsed = (jiffies - inflight->restart_ts)/HZ;
- unsigned long restart_count = atomic_read(&inflight->restart_count);
-
- result = scnprintf(buf, PAGE_SIZE, "%lu %lu %d %lu %lu %lu\n"
- "#read: threshold max inflight_count restarts "
- "seconds restarts/sec\n"
- "#write: threshold max\n",
- inflight->threshold, inflight->max,
- atomic_read(&inflight->count),
- restart_count, sec_elapsed,
- sec_elapsed == 0 ? 0 : restart_count/sec_elapsed);
- inflight->restart_ts = jiffies;
- atomic_set(&inflight->restart_count, 0);
- return result;
-}
-
-static
-ssize_t wlp_tx_inflight_store(struct i1480u_tx_inflight *inflight,
- const char *buf, size_t size)
-{
- unsigned long in_threshold, in_max;
- ssize_t result;
- result = sscanf(buf, "%lu %lu", &in_threshold, &in_max);
- if (result != 2)
- return -EINVAL;
- if (in_max <= in_threshold)
- return -EINVAL;
- inflight->max = in_max;
- inflight->threshold = in_threshold;
- return size;
-}
-/*
- * Glue (or function adaptors) for accesing info on sysfs
- *
- * [we need this indirection because the PCI driver does almost the
- * same]
- *
- * Linux 2.6.21 changed how 'struct netdevice' does attributes (from
- * having a 'struct class_dev' to having a 'struct device'). That is
- * quite of a pain.
- *
- * So we try to abstract that here. i1480u_SHOW() and i1480u_STORE()
- * create adaptors for extracting the 'struct i1480u' from a 'struct
- * dev' and calling a function for doing a sysfs operation (as we have
- * them factorized already). i1480u_ATTR creates the attribute file
- * (CLASS_DEVICE_ATTR or DEVICE_ATTR) and i1480u_ATTR_NAME produces a
- * class_device_attr_NAME or device_attr_NAME (for group registration).
- */
-
-#define i1480u_SHOW(name, fn, param) \
-static ssize_t i1480u_show_##name(struct device *dev, \
- struct device_attribute *attr,\
- char *buf) \
-{ \
- struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \
- return fn(&i1480u->param, buf); \
-}
-
-#define i1480u_STORE(name, fn, param) \
-static ssize_t i1480u_store_##name(struct device *dev, \
- struct device_attribute *attr,\
- const char *buf, size_t size)\
-{ \
- struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \
- return fn(&i1480u->param, buf, size); \
-}
-
-#define i1480u_ATTR(name, perm) static DEVICE_ATTR(name, perm, \
- i1480u_show_##name,\
- i1480u_store_##name)
-
-#define i1480u_ATTR_SHOW(name) static DEVICE_ATTR(name, \
- S_IRUGO, \
- i1480u_show_##name, NULL)
-
-#define i1480u_ATTR_NAME(a) (dev_attr_##a)
-
-
-/*
- * Sysfs adaptors
- */
-i1480u_SHOW(uwb_phy_rate, uwb_phy_rate_show, options);
-i1480u_STORE(uwb_phy_rate, uwb_phy_rate_store, options);
-i1480u_ATTR(uwb_phy_rate, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(uwb_rts_cts, uwb_rts_cts_show, options);
-i1480u_STORE(uwb_rts_cts, uwb_rts_cts_store, options);
-i1480u_ATTR(uwb_rts_cts, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(uwb_ack_policy, uwb_ack_policy_show, options);
-i1480u_STORE(uwb_ack_policy, uwb_ack_policy_store, options);
-i1480u_ATTR(uwb_ack_policy, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(uwb_pca_base_priority, uwb_pca_base_priority_show, options);
-i1480u_STORE(uwb_pca_base_priority, uwb_pca_base_priority_store, options);
-i1480u_ATTR(uwb_pca_base_priority, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_eda, wlp_eda_show, wlp);
-i1480u_STORE(wlp_eda, wlp_eda_store, wlp);
-i1480u_ATTR(wlp_eda, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_uuid, wlp_uuid_show, wlp);
-i1480u_STORE(wlp_uuid, wlp_uuid_store, wlp);
-i1480u_ATTR(wlp_uuid, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_name, wlp_dev_name_show, wlp);
-i1480u_STORE(wlp_dev_name, wlp_dev_name_store, wlp);
-i1480u_ATTR(wlp_dev_name, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_manufacturer, wlp_dev_manufacturer_show, wlp);
-i1480u_STORE(wlp_dev_manufacturer, wlp_dev_manufacturer_store, wlp);
-i1480u_ATTR(wlp_dev_manufacturer, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_model_name, wlp_dev_model_name_show, wlp);
-i1480u_STORE(wlp_dev_model_name, wlp_dev_model_name_store, wlp);
-i1480u_ATTR(wlp_dev_model_name, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_model_nr, wlp_dev_model_nr_show, wlp);
-i1480u_STORE(wlp_dev_model_nr, wlp_dev_model_nr_store, wlp);
-i1480u_ATTR(wlp_dev_model_nr, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_serial, wlp_dev_serial_show, wlp);
-i1480u_STORE(wlp_dev_serial, wlp_dev_serial_store, wlp);
-i1480u_ATTR(wlp_dev_serial, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_prim_category, wlp_dev_prim_category_show, wlp);
-i1480u_STORE(wlp_dev_prim_category, wlp_dev_prim_category_store, wlp);
-i1480u_ATTR(wlp_dev_prim_category, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_prim_OUI, wlp_dev_prim_OUI_show, wlp);
-i1480u_STORE(wlp_dev_prim_OUI, wlp_dev_prim_OUI_store, wlp);
-i1480u_ATTR(wlp_dev_prim_OUI, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_show, wlp);
-i1480u_STORE(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_store, wlp);
-i1480u_ATTR(wlp_dev_prim_OUI_sub, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_dev_prim_subcat, wlp_dev_prim_subcat_show, wlp);
-i1480u_STORE(wlp_dev_prim_subcat, wlp_dev_prim_subcat_store, wlp);
-i1480u_ATTR(wlp_dev_prim_subcat, S_IRUGO | S_IWUSR);
-
-i1480u_SHOW(wlp_neighborhood, wlp_neighborhood_show, wlp);
-i1480u_ATTR_SHOW(wlp_neighborhood);
-
-i1480u_SHOW(wss_activate, wlp_wss_activate_show, wlp.wss);
-i1480u_STORE(wss_activate, wlp_wss_activate_store, wlp.wss);
-i1480u_ATTR(wss_activate, S_IRUGO | S_IWUSR);
-
-/*
- * Show the (min, max, avg) Line Quality Estimate (LQE, in dB) as over
- * the last 256 received WLP frames (ECMA-368 13.3).
- *
- * [the -7dB that have to be substracted from the LQI to make the LQE
- * are already taken into account].
- */
-i1480u_SHOW(wlp_lqe, stats_show, lqe_stats);
-i1480u_STORE(wlp_lqe, stats_store, lqe_stats);
-i1480u_ATTR(wlp_lqe, S_IRUGO | S_IWUSR);
-
-/*
- * Show the Receive Signal Strength Indicator averaged over all the
- * received WLP frames (ECMA-368 13.3). Still is not clear what
- * this value is, but is kind of a percentage of the signal strength
- * at the antenna.
- */
-i1480u_SHOW(wlp_rssi, stats_show, rssi_stats);
-i1480u_STORE(wlp_rssi, stats_store, rssi_stats);
-i1480u_ATTR(wlp_rssi, S_IRUGO | S_IWUSR);
-
-/**
- * We maintain a basic flow control counter. "count" how many TX URBs are
- * outstanding. Only allow "max"
- * TX URBs to be outstanding. If this value is reached the queue will be
- * stopped. The queue will be restarted when there are
- * "threshold" URBs outstanding.
- */
-i1480u_SHOW(wlp_tx_inflight, wlp_tx_inflight_show, tx_inflight);
-i1480u_STORE(wlp_tx_inflight, wlp_tx_inflight_store, tx_inflight);
-i1480u_ATTR(wlp_tx_inflight, S_IRUGO | S_IWUSR);
-
-static struct attribute *i1480u_attrs[] = {
- &i1480u_ATTR_NAME(uwb_phy_rate).attr,
- &i1480u_ATTR_NAME(uwb_rts_cts).attr,
- &i1480u_ATTR_NAME(uwb_ack_policy).attr,
- &i1480u_ATTR_NAME(uwb_pca_base_priority).attr,
- &i1480u_ATTR_NAME(wlp_lqe).attr,
- &i1480u_ATTR_NAME(wlp_rssi).attr,
- &i1480u_ATTR_NAME(wlp_eda).attr,
- &i1480u_ATTR_NAME(wlp_uuid).attr,
- &i1480u_ATTR_NAME(wlp_dev_name).attr,
- &i1480u_ATTR_NAME(wlp_dev_manufacturer).attr,
- &i1480u_ATTR_NAME(wlp_dev_model_name).attr,
- &i1480u_ATTR_NAME(wlp_dev_model_nr).attr,
- &i1480u_ATTR_NAME(wlp_dev_serial).attr,
- &i1480u_ATTR_NAME(wlp_dev_prim_category).attr,
- &i1480u_ATTR_NAME(wlp_dev_prim_OUI).attr,
- &i1480u_ATTR_NAME(wlp_dev_prim_OUI_sub).attr,
- &i1480u_ATTR_NAME(wlp_dev_prim_subcat).attr,
- &i1480u_ATTR_NAME(wlp_neighborhood).attr,
- &i1480u_ATTR_NAME(wss_activate).attr,
- &i1480u_ATTR_NAME(wlp_tx_inflight).attr,
- NULL,
-};
-
-static struct attribute_group i1480u_attr_group = {
- .name = NULL, /* we want them in the same directory */
- .attrs = i1480u_attrs,
-};
-
-int i1480u_sysfs_setup(struct i1480u *i1480u)
-{
- int result;
- struct device *dev = &i1480u->usb_iface->dev;
- result = sysfs_create_group(&i1480u->net_dev->dev.kobj,
- &i1480u_attr_group);
- if (result < 0)
- dev_err(dev, "cannot initialize sysfs attributes: %d\n",
- result);
- return result;
-}
-
-
-void i1480u_sysfs_release(struct i1480u *i1480u)
-{
- sysfs_remove_group(&i1480u->net_dev->dev.kobj,
- &i1480u_attr_group);
-}
diff --git a/drivers/uwb/i1480/i1480u-wlp/tx.c b/drivers/uwb/i1480/i1480u-wlp/tx.c
deleted file mode 100644
index 3c117a364564..000000000000
--- a/drivers/uwb/i1480/i1480u-wlp/tx.c
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- * WUSB Wire Adapter: WLP interface
- * Deal with TX (massaging data to transmit, handling it)
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * Transmission engine. Get an skb, create from that a WLP transmit
- * context, add a WLP TX header (which we keep prefilled in the
- * device's instance), fill out the target-specific fields and
- * fire it.
- *
- * ROADMAP:
- *
- * Entry points:
- *
- * i1480u_tx_release(): called by i1480u_disconnect() to release
- * pending tx contexts.
- *
- * i1480u_tx_cb(): callback for TX contexts (USB URBs)
- * i1480u_tx_destroy():
- *
- * i1480u_tx_timeout(): called for timeout handling from the
- * network stack.
- *
- * i1480u_hard_start_xmit(): called for transmitting an skb from
- * the network stack. Will interact with WLP
- * substack to verify and prepare frame.
- * i1480u_xmit_frame(): actual transmission on hardware
- *
- * i1480u_tx_create() Creates TX context
- * i1480u_tx_create_1() For packets in 1 fragment
- * i1480u_tx_create_n() For packets in >1 fragments
- *
- * TODO:
- *
- * - FIXME: rewrite using usb_sg_*(), add asynch support to
- * usb_sg_*(). It might not make too much sense as most of
- * the times the MTU will be smaller than one page...
- */
-
-#include <linux/slab.h>
-#include "i1480u-wlp.h"
-
-enum {
- /* This is only for Next and Last TX packets */
- i1480u_MAX_PL_SIZE = i1480u_MAX_FRG_SIZE
- - sizeof(struct untd_hdr_rst),
-};
-
-/* Free resources allocated to a i1480u tx context. */
-static
-void i1480u_tx_free(struct i1480u_tx *wtx)
-{
- kfree(wtx->buf);
- if (wtx->skb)
- dev_kfree_skb_irq(wtx->skb);
- usb_free_urb(wtx->urb);
- kfree(wtx);
-}
-
-static
-void i1480u_tx_destroy(struct i1480u *i1480u, struct i1480u_tx *wtx)
-{
- unsigned long flags;
- spin_lock_irqsave(&i1480u->tx_list_lock, flags); /* not active any more */
- list_del(&wtx->list_node);
- i1480u_tx_free(wtx);
- spin_unlock_irqrestore(&i1480u->tx_list_lock, flags);
-}
-
-static
-void i1480u_tx_unlink_urbs(struct i1480u *i1480u)
-{
- unsigned long flags;
- struct i1480u_tx *wtx, *next;
-
- spin_lock_irqsave(&i1480u->tx_list_lock, flags);
- list_for_each_entry_safe(wtx, next, &i1480u->tx_list, list_node) {
- usb_unlink_urb(wtx->urb);
- }
- spin_unlock_irqrestore(&i1480u->tx_list_lock, flags);
-}
-
-
-/*
- * Callback for a completed tx USB URB.
- *
- * TODO:
- *
- * - FIXME: recover errors more gracefully
- * - FIXME: handle NAKs (I dont think they come here) for flow ctl
- */
-static
-void i1480u_tx_cb(struct urb *urb)
-{
- struct i1480u_tx *wtx = urb->context;
- struct i1480u *i1480u = wtx->i1480u;
- struct net_device *net_dev = i1480u->net_dev;
- struct device *dev = &i1480u->usb_iface->dev;
- unsigned long flags;
-
- switch (urb->status) {
- case 0:
- spin_lock_irqsave(&i1480u->lock, flags);
- net_dev->stats.tx_packets++;
- net_dev->stats.tx_bytes += urb->actual_length;
- spin_unlock_irqrestore(&i1480u->lock, flags);
- break;
- case -ECONNRESET: /* Not an error, but a controlled situation; */
- case -ENOENT: /* (we killed the URB)...so, no broadcast */
- dev_dbg(dev, "notif endp: reset/noent %d\n", urb->status);
- netif_stop_queue(net_dev);
- break;
- case -ESHUTDOWN: /* going away! */
- dev_dbg(dev, "notif endp: down %d\n", urb->status);
- netif_stop_queue(net_dev);
- break;
- default:
- dev_err(dev, "TX: unknown URB status %d\n", urb->status);
- if (edc_inc(&i1480u->tx_errors, EDC_MAX_ERRORS,
- EDC_ERROR_TIMEFRAME)) {
- dev_err(dev, "TX: max acceptable errors exceeded."
- "Reset device.\n");
- netif_stop_queue(net_dev);
- i1480u_tx_unlink_urbs(i1480u);
- wlp_reset_all(&i1480u->wlp);
- }
- break;
- }
- i1480u_tx_destroy(i1480u, wtx);
- if (atomic_dec_return(&i1480u->tx_inflight.count)
- <= i1480u->tx_inflight.threshold
- && netif_queue_stopped(net_dev)
- && i1480u->tx_inflight.threshold != 0) {
- netif_start_queue(net_dev);
- atomic_inc(&i1480u->tx_inflight.restart_count);
- }
- return;
-}
-
-
-/*
- * Given a buffer that doesn't fit in a single fragment, create an
- * scatter/gather structure for delivery to the USB pipe.
- *
- * Implements functionality of i1480u_tx_create().
- *
- * @wtx: tx descriptor
- * @skb: skb to send
- * @gfp_mask: gfp allocation mask
- * @returns: Pointer to @wtx if ok, NULL on error.
- *
- * Sorry, TOO LONG a function, but breaking it up is kind of hard
- *
- * This will break the buffer in chunks smaller than
- * i1480u_MAX_FRG_SIZE (including the header) and add proper headers
- * to each:
- *
- * 1st header \
- * i1480 tx header | fragment 1
- * fragment data /
- * nxt header \ fragment 2
- * fragment data /
- * ..
- * ..
- * last header \ fragment 3
- * last fragment data /
- *
- * This does not fill the i1480 TX header, it is left up to the
- * caller to do that; you can get it from @wtx->wlp_tx_hdr.
- *
- * This function consumes the skb unless there is an error.
- */
-static
-int i1480u_tx_create_n(struct i1480u_tx *wtx, struct sk_buff *skb,
- gfp_t gfp_mask)
-{
- int result;
- void *pl;
- size_t pl_size;
-
- void *pl_itr, *buf_itr;
- size_t pl_size_left, frgs, pl_size_1st, frg_pl_size = 0;
- struct untd_hdr_1st *untd_hdr_1st;
- struct wlp_tx_hdr *wlp_tx_hdr;
- struct untd_hdr_rst *untd_hdr_rst;
-
- wtx->skb = NULL;
- pl = skb->data;
- pl_itr = pl;
- pl_size = skb->len;
- pl_size_left = pl_size; /* payload size */
- /* First fragment; fits as much as i1480u_MAX_FRG_SIZE minus
- * the headers */
- pl_size_1st = i1480u_MAX_FRG_SIZE
- - sizeof(struct untd_hdr_1st) - sizeof(struct wlp_tx_hdr);
- BUG_ON(pl_size_1st > pl_size);
- pl_size_left -= pl_size_1st;
- /* The rest have an smaller header (no i1480 TX header). We
- * need to break up the payload in blocks smaller than
- * i1480u_MAX_PL_SIZE (payload excluding header). */
- frgs = (pl_size_left + i1480u_MAX_PL_SIZE - 1) / i1480u_MAX_PL_SIZE;
- /* Allocate space for the new buffer. In this new buffer we'll
- * place the headers followed by the data fragment, headers,
- * data fragments, etc..
- */
- result = -ENOMEM;
- wtx->buf_size = sizeof(*untd_hdr_1st)
- + sizeof(*wlp_tx_hdr)
- + frgs * sizeof(*untd_hdr_rst)
- + pl_size;
- wtx->buf = kmalloc(wtx->buf_size, gfp_mask);
- if (wtx->buf == NULL)
- goto error_buf_alloc;
-
- buf_itr = wtx->buf; /* We got the space, let's fill it up */
- /* Fill 1st fragment */
- untd_hdr_1st = buf_itr;
- buf_itr += sizeof(*untd_hdr_1st);
- untd_hdr_set_type(&untd_hdr_1st->hdr, i1480u_PKT_FRAG_1ST);
- untd_hdr_set_rx_tx(&untd_hdr_1st->hdr, 0);
- untd_hdr_1st->hdr.len = cpu_to_le16(pl_size + sizeof(*wlp_tx_hdr));
- untd_hdr_1st->fragment_len =
- cpu_to_le16(pl_size_1st + sizeof(*wlp_tx_hdr));
- memset(untd_hdr_1st->padding, 0, sizeof(untd_hdr_1st->padding));
- /* Set up i1480 header info */
- wlp_tx_hdr = wtx->wlp_tx_hdr = buf_itr;
- buf_itr += sizeof(*wlp_tx_hdr);
- /* Copy the first fragment */
- memcpy(buf_itr, pl_itr, pl_size_1st);
- pl_itr += pl_size_1st;
- buf_itr += pl_size_1st;
-
- /* Now do each remaining fragment */
- result = -EINVAL;
- while (pl_size_left > 0) {
- if (buf_itr + sizeof(*untd_hdr_rst) - wtx->buf
- > wtx->buf_size) {
- printk(KERN_ERR "BUG: no space for header\n");
- goto error_bug;
- }
- untd_hdr_rst = buf_itr;
- buf_itr += sizeof(*untd_hdr_rst);
- if (pl_size_left > i1480u_MAX_PL_SIZE) {
- frg_pl_size = i1480u_MAX_PL_SIZE;
- untd_hdr_set_type(&untd_hdr_rst->hdr, i1480u_PKT_FRAG_NXT);
- } else {
- frg_pl_size = pl_size_left;
- untd_hdr_set_type(&untd_hdr_rst->hdr, i1480u_PKT_FRAG_LST);
- }
- untd_hdr_set_rx_tx(&untd_hdr_rst->hdr, 0);
- untd_hdr_rst->hdr.len = cpu_to_le16(frg_pl_size);
- untd_hdr_rst->padding = 0;
- if (buf_itr + frg_pl_size - wtx->buf
- > wtx->buf_size) {
- printk(KERN_ERR "BUG: no space for payload\n");
- goto error_bug;
- }
- memcpy(buf_itr, pl_itr, frg_pl_size);
- buf_itr += frg_pl_size;
- pl_itr += frg_pl_size;
- pl_size_left -= frg_pl_size;
- }
- dev_kfree_skb_irq(skb);
- return 0;
-
-error_bug:
- printk(KERN_ERR
- "BUG: skb %u bytes\n"
- "BUG: frg_pl_size %zd i1480u_MAX_FRG_SIZE %u\n"
- "BUG: buf_itr %zu buf_size %zu pl_size_left %zu\n",
- skb->len,
- frg_pl_size, i1480u_MAX_FRG_SIZE,
- buf_itr - wtx->buf, wtx->buf_size, pl_size_left);
-
- kfree(wtx->buf);
-error_buf_alloc:
- return result;
-}
-
-
-/*
- * Given a buffer that fits in a single fragment, fill out a @wtx
- * struct for transmitting it down the USB pipe.
- *
- * Uses the fact that we have space reserved in front of the skbuff
- * for hardware headers :]
- *
- * This does not fill the i1480 TX header, it is left up to the
- * caller to do that; you can get it from @wtx->wlp_tx_hdr.
- *
- * @pl: pointer to payload data
- * @pl_size: size of the payuload
- *
- * This function does not consume the @skb.
- */
-static
-int i1480u_tx_create_1(struct i1480u_tx *wtx, struct sk_buff *skb,
- gfp_t gfp_mask)
-{
- struct untd_hdr_cmp *untd_hdr_cmp;
- struct wlp_tx_hdr *wlp_tx_hdr;
-
- wtx->buf = NULL;
- wtx->skb = skb;
- BUG_ON(skb_headroom(skb) < sizeof(*wlp_tx_hdr));
- wlp_tx_hdr = (void *) __skb_push(skb, sizeof(*wlp_tx_hdr));
- wtx->wlp_tx_hdr = wlp_tx_hdr;
- BUG_ON(skb_headroom(skb) < sizeof(*untd_hdr_cmp));
- untd_hdr_cmp = (void *) __skb_push(skb, sizeof(*untd_hdr_cmp));
-
- untd_hdr_set_type(&untd_hdr_cmp->hdr, i1480u_PKT_FRAG_CMP);
- untd_hdr_set_rx_tx(&untd_hdr_cmp->hdr, 0);
- untd_hdr_cmp->hdr.len = cpu_to_le16(skb->len - sizeof(*untd_hdr_cmp));
- untd_hdr_cmp->padding = 0;
- return 0;
-}
-
-
-/*
- * Given a skb to transmit, massage it to become palatable for the TX pipe
- *
- * This will break the buffer in chunks smaller than
- * i1480u_MAX_FRG_SIZE and add proper headers to each.
- *
- * 1st header \
- * i1480 tx header | fragment 1
- * fragment data /
- * nxt header \ fragment 2
- * fragment data /
- * ..
- * ..
- * last header \ fragment 3
- * last fragment data /
- *
- * Each fragment will be always smaller or equal to i1480u_MAX_FRG_SIZE.
- *
- * If the first fragment is smaller than i1480u_MAX_FRG_SIZE, then the
- * following is composed:
- *
- * complete header \
- * i1480 tx header | single fragment
- * packet data /
- *
- * We were going to use s/g support, but because the interface is
- * synch and at the end there is plenty of overhead to do it, it
- * didn't seem that worth for data that is going to be smaller than
- * one page.
- */
-static
-struct i1480u_tx *i1480u_tx_create(struct i1480u *i1480u,
- struct sk_buff *skb, gfp_t gfp_mask)
-{
- int result;
- struct usb_endpoint_descriptor *epd;
- int usb_pipe;
- unsigned long flags;
-
- struct i1480u_tx *wtx;
- const size_t pl_max_size =
- i1480u_MAX_FRG_SIZE - sizeof(struct untd_hdr_cmp)
- - sizeof(struct wlp_tx_hdr);
-
- wtx = kmalloc(sizeof(*wtx), gfp_mask);
- if (wtx == NULL)
- goto error_wtx_alloc;
- wtx->urb = usb_alloc_urb(0, gfp_mask);
- if (wtx->urb == NULL)
- goto error_urb_alloc;
- epd = &i1480u->usb_iface->cur_altsetting->endpoint[2].desc;
- usb_pipe = usb_sndbulkpipe(i1480u->usb_dev, epd->bEndpointAddress);
- /* Fits in a single complete packet or need to split? */
- if (skb->len > pl_max_size) {
- result = i1480u_tx_create_n(wtx, skb, gfp_mask);
- if (result < 0)
- goto error_create;
- usb_fill_bulk_urb(wtx->urb, i1480u->usb_dev, usb_pipe,
- wtx->buf, wtx->buf_size, i1480u_tx_cb, wtx);
- } else {
- result = i1480u_tx_create_1(wtx, skb, gfp_mask);
- if (result < 0)
- goto error_create;
- usb_fill_bulk_urb(wtx->urb, i1480u->usb_dev, usb_pipe,
- skb->data, skb->len, i1480u_tx_cb, wtx);
- }
- spin_lock_irqsave(&i1480u->tx_list_lock, flags);
- list_add(&wtx->list_node, &i1480u->tx_list);
- spin_unlock_irqrestore(&i1480u->tx_list_lock, flags);
- return wtx;
-
-error_create:
- kfree(wtx->urb);
-error_urb_alloc:
- kfree(wtx);
-error_wtx_alloc:
- return NULL;
-}
-
-/*
- * Actual fragmentation and transmission of frame
- *
- * @wlp: WLP substack data structure
- * @skb: To be transmitted
- * @dst: Device address of destination
- * @returns: 0 on success, <0 on failure
- *
- * This function can also be called directly (not just from
- * hard_start_xmit), so we also check here if the interface is up before
- * taking sending anything.
- */
-int i1480u_xmit_frame(struct wlp *wlp, struct sk_buff *skb,
- struct uwb_dev_addr *dst)
-{
- int result = -ENXIO;
- struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
- struct device *dev = &i1480u->usb_iface->dev;
- struct net_device *net_dev = i1480u->net_dev;
- struct i1480u_tx *wtx;
- struct wlp_tx_hdr *wlp_tx_hdr;
- static unsigned char dev_bcast[2] = { 0xff, 0xff };
-
- BUG_ON(i1480u->wlp.rc == NULL);
- if ((net_dev->flags & IFF_UP) == 0)
- goto out;
- result = -EBUSY;
- if (atomic_read(&i1480u->tx_inflight.count) >= i1480u->tx_inflight.max) {
- netif_stop_queue(net_dev);
- goto error_max_inflight;
- }
- result = -ENOMEM;
- wtx = i1480u_tx_create(i1480u, skb, GFP_ATOMIC);
- if (unlikely(wtx == NULL)) {
- if (printk_ratelimit())
- dev_err(dev, "TX: no memory for WLP TX URB,"
- "dropping packet (in flight %d)\n",
- atomic_read(&i1480u->tx_inflight.count));
- netif_stop_queue(net_dev);
- goto error_wtx_alloc;
- }
- wtx->i1480u = i1480u;
- /* Fill out the i1480 header; @i1480u->def_tx_hdr read without
- * locking. We do so because they are kind of orthogonal to
- * each other (and thus not changed in an atomic batch).
- * The ETH header is right after the WLP TX header. */
- wlp_tx_hdr = wtx->wlp_tx_hdr;
- *wlp_tx_hdr = i1480u->options.def_tx_hdr;
- wlp_tx_hdr->dstaddr = *dst;
- if (!memcmp(&wlp_tx_hdr->dstaddr, dev_bcast, sizeof(dev_bcast))
- && (wlp_tx_hdr_delivery_id_type(wlp_tx_hdr) & WLP_DRP)) {
- /*Broadcast message directed to DRP host. Send as best effort
- * on PCA. */
- wlp_tx_hdr_set_delivery_id_type(wlp_tx_hdr, i1480u->options.pca_base_priority);
- }
-
- result = usb_submit_urb(wtx->urb, GFP_ATOMIC); /* Go baby */
- if (result < 0) {
- dev_err(dev, "TX: cannot submit URB: %d\n", result);
- /* We leave the freeing of skb to calling function */
- wtx->skb = NULL;
- goto error_tx_urb_submit;
- }
- atomic_inc(&i1480u->tx_inflight.count);
- net_dev->trans_start = jiffies;
- return result;
-
-error_tx_urb_submit:
- i1480u_tx_destroy(i1480u, wtx);
-error_wtx_alloc:
-error_max_inflight:
-out:
- return result;
-}
-
-
-/*
- * Transmit an skb Called when an skbuf has to be transmitted
- *
- * The skb is first passed to WLP substack to ensure this is a valid
- * frame. If valid the device address of destination will be filled and
- * the WLP header prepended to the skb. If this step fails we fake sending
- * the frame, if we return an error the network stack will just keep trying.
- *
- * Broadcast frames inside a WSS needs to be treated special as multicast is
- * not supported. A broadcast frame is sent as unicast to each member of the
- * WSS - this is done by the WLP substack when it finds a broadcast frame.
- * So, we test if the WLP substack took over the skb and only transmit it
- * if it has not (been taken over).
- *
- * @net_dev->xmit_lock is held
- */
-netdev_tx_t i1480u_hard_start_xmit(struct sk_buff *skb,
- struct net_device *net_dev)
-{
- int result;
- struct i1480u *i1480u = netdev_priv(net_dev);
- struct device *dev = &i1480u->usb_iface->dev;
- struct uwb_dev_addr dst;
-
- if ((net_dev->flags & IFF_UP) == 0)
- goto error;
- result = wlp_prepare_tx_frame(dev, &i1480u->wlp, skb, &dst);
- if (result < 0) {
- dev_err(dev, "WLP verification of TX frame failed (%d). "
- "Dropping packet.\n", result);
- goto error;
- } else if (result == 1) {
- /* trans_start time will be set when WLP actually transmits
- * the frame */
- goto out;
- }
- result = i1480u_xmit_frame(&i1480u->wlp, skb, &dst);
- if (result < 0) {
- dev_err(dev, "Frame TX failed (%d).\n", result);
- goto error;
- }
- return NETDEV_TX_OK;
-error:
- dev_kfree_skb_any(skb);
- net_dev->stats.tx_dropped++;
-out:
- return NETDEV_TX_OK;
-}
-
-
-/*
- * Called when a pkt transmission doesn't complete in a reasonable period
- * Device reset may sleep - do it outside of interrupt context (delayed)
- */
-void i1480u_tx_timeout(struct net_device *net_dev)
-{
- struct i1480u *i1480u = netdev_priv(net_dev);
-
- wlp_reset_all(&i1480u->wlp);
-}
-
-
-void i1480u_tx_release(struct i1480u *i1480u)
-{
- unsigned long flags;
- struct i1480u_tx *wtx, *next;
- int count = 0, empty;
-
- spin_lock_irqsave(&i1480u->tx_list_lock, flags);
- list_for_each_entry_safe(wtx, next, &i1480u->tx_list, list_node) {
- count++;
- usb_unlink_urb(wtx->urb);
- }
- spin_unlock_irqrestore(&i1480u->tx_list_lock, flags);
- count = count*10; /* i1480ut 200ms per unlinked urb (intervals of 20ms) */
- /*
- * We don't like this sollution too much (dirty as it is), but
- * it is cheaper than putting a refcount on each i1480u_tx and
- * i1480uting for all of them to go away...
- *
- * Called when no more packets can be added to tx_list
- * so can i1480ut for it to be empty.
- */
- while (1) {
- spin_lock_irqsave(&i1480u->tx_list_lock, flags);
- empty = list_empty(&i1480u->tx_list);
- spin_unlock_irqrestore(&i1480u->tx_list_lock, flags);
- if (empty)
- break;
- count--;
- BUG_ON(count == 0);
- msleep(20);
- }
-}
diff --git a/drivers/uwb/wlp/Makefile b/drivers/uwb/wlp/Makefile
deleted file mode 100644
index c72c11db5b1b..000000000000
--- a/drivers/uwb/wlp/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-obj-$(CONFIG_UWB_WLP) := wlp.o
-
-wlp-objs := \
- driver.o \
- eda.o \
- messages.o \
- sysfs.o \
- txrx.o \
- wlp-lc.o \
- wss-lc.o
diff --git a/drivers/uwb/wlp/driver.c b/drivers/uwb/wlp/driver.c
deleted file mode 100644
index cb8d699b6a67..000000000000
--- a/drivers/uwb/wlp/driver.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- *
- * Copyright (C) 2007 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * Life cycle of WLP substack
- *
- * FIXME: Docs
- */
-
-#include <linux/module.h>
-
-static int __init wlp_subsys_init(void)
-{
- return 0;
-}
-module_init(wlp_subsys_init);
-
-static void __exit wlp_subsys_exit(void)
-{
- return;
-}
-module_exit(wlp_subsys_exit);
-
-MODULE_AUTHOR("Reinette Chatre <reinette.chatre@intel.com>");
-MODULE_DESCRIPTION("WiMedia Logical Link Control Protocol (WLP)");
-MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/wlp/eda.c b/drivers/uwb/wlp/eda.c
deleted file mode 100644
index 086fc0cf9401..000000000000
--- a/drivers/uwb/wlp/eda.c
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * WUSB Wire Adapter: WLP interface
- * Ethernet to device address cache
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * We need to be able to map ethernet addresses to device addresses
- * and back because there is not explicit relationship between the eth
- * addresses used in the ETH frames and the device addresses (no, it
- * would not have been simpler to force as ETH address the MBOA MAC
- * address...no, not at all :).
- *
- * A device has one MBOA MAC address and one device address. It is possible
- * for a device to have more than one virtual MAC address (although a
- * virtual address can be the same as the MBOA MAC address). The device
- * address is guaranteed to be unique among the devices in the extended
- * beacon group (see ECMA 17.1.1). We thus use the device address as index
- * to this cache. We do allow searching based on virtual address as this
- * is how Ethernet frames will be addressed.
- *
- * We need to support virtual EUI-48. Although, right now the virtual
- * EUI-48 will always be the same as the MAC SAP address. The EDA cache
- * entry thus contains a MAC SAP address as well as the virtual address
- * (used to map the network stack address to a neighbor). When we move
- * to support more than one virtual MAC on a host then this organization
- * will have to change. Perhaps a neighbor has a list of WSSs, each with a
- * tag and virtual EUI-48.
- *
- * On data transmission
- * it is used to determine if the neighbor is connected and what WSS it
- * belongs to. With this we know what tag to add to the WLP frame. Storing
- * the WSS in the EDA cache may be overkill because we only support one
- * WSS. Hopefully we will support more than one WSS at some point.
- * On data reception it is used to determine the WSS based on
- * the tag and address of the transmitting neighbor.
- */
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/wlp.h>
-#include "wlp-internal.h"
-
-
-/* FIXME: cache is not purged, only on device close */
-
-/* FIXME: does not scale, change to dynamic array */
-
-/*
- * Initialize the EDA cache
- *
- * @returns 0 if ok, < 0 errno code on error
- *
- * Call when the interface is being brought up
- *
- * NOTE: Keep it as a separate function as the implementation will
- * change and be more complex.
- */
-void wlp_eda_init(struct wlp_eda *eda)
-{
- INIT_LIST_HEAD(&eda->cache);
- spin_lock_init(&eda->lock);
-}
-
-/*
- * Release the EDA cache
- *
- * @returns 0 if ok, < 0 errno code on error
- *
- * Called when the interface is brought down
- */
-void wlp_eda_release(struct wlp_eda *eda)
-{
- unsigned long flags;
- struct wlp_eda_node *itr, *next;
-
- spin_lock_irqsave(&eda->lock, flags);
- list_for_each_entry_safe(itr, next, &eda->cache, list_node) {
- list_del(&itr->list_node);
- kfree(itr);
- }
- spin_unlock_irqrestore(&eda->lock, flags);
-}
-
-/*
- * Add an address mapping
- *
- * @returns 0 if ok, < 0 errno code on error
- *
- * An address mapping is initially created when the neighbor device is seen
- * for the first time (it is "onair"). At this time the neighbor is not
- * connected or associated with a WSS so we only populate the Ethernet and
- * Device address fields.
- *
- */
-int wlp_eda_create_node(struct wlp_eda *eda,
- const unsigned char eth_addr[ETH_ALEN],
- const struct uwb_dev_addr *dev_addr)
-{
- int result = 0;
- struct wlp_eda_node *itr;
- unsigned long flags;
-
- BUG_ON(dev_addr == NULL || eth_addr == NULL);
- spin_lock_irqsave(&eda->lock, flags);
- list_for_each_entry(itr, &eda->cache, list_node) {
- if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
- printk(KERN_ERR "EDA cache already contains entry "
- "for neighbor %02x:%02x\n",
- dev_addr->data[1], dev_addr->data[0]);
- result = -EEXIST;
- goto out_unlock;
- }
- }
- itr = kzalloc(sizeof(*itr), GFP_ATOMIC);
- if (itr != NULL) {
- memcpy(itr->eth_addr, eth_addr, sizeof(itr->eth_addr));
- itr->dev_addr = *dev_addr;
- list_add(&itr->list_node, &eda->cache);
- } else
- result = -ENOMEM;
-out_unlock:
- spin_unlock_irqrestore(&eda->lock, flags);
- return result;
-}
-
-/*
- * Remove entry from EDA cache
- *
- * This is done when the device goes off air.
- */
-void wlp_eda_rm_node(struct wlp_eda *eda, const struct uwb_dev_addr *dev_addr)
-{
- struct wlp_eda_node *itr, *next;
- unsigned long flags;
-
- spin_lock_irqsave(&eda->lock, flags);
- list_for_each_entry_safe(itr, next, &eda->cache, list_node) {
- if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
- list_del(&itr->list_node);
- kfree(itr);
- break;
- }
- }
- spin_unlock_irqrestore(&eda->lock, flags);
-}
-
-/*
- * Update an address mapping
- *
- * @returns 0 if ok, < 0 errno code on error
- */
-int wlp_eda_update_node(struct wlp_eda *eda,
- const struct uwb_dev_addr *dev_addr,
- struct wlp_wss *wss,
- const unsigned char virt_addr[ETH_ALEN],
- const u8 tag, const enum wlp_wss_connect state)
-{
- int result = -ENOENT;
- struct wlp_eda_node *itr;
- unsigned long flags;
-
- spin_lock_irqsave(&eda->lock, flags);
- list_for_each_entry(itr, &eda->cache, list_node) {
- if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
- /* Found it, update it */
- itr->wss = wss;
- memcpy(itr->virt_addr, virt_addr,
- sizeof(itr->virt_addr));
- itr->tag = tag;
- itr->state = state;
- result = 0;
- goto out_unlock;
- }
- }
- /* Not found */
-out_unlock:
- spin_unlock_irqrestore(&eda->lock, flags);
- return result;
-}
-
-/*
- * Update only state field of an address mapping
- *
- * @returns 0 if ok, < 0 errno code on error
- */
-int wlp_eda_update_node_state(struct wlp_eda *eda,
- const struct uwb_dev_addr *dev_addr,
- const enum wlp_wss_connect state)
-{
- int result = -ENOENT;
- struct wlp_eda_node *itr;
- unsigned long flags;
-
- spin_lock_irqsave(&eda->lock, flags);
- list_for_each_entry(itr, &eda->cache, list_node) {
- if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
- /* Found it, update it */
- itr->state = state;
- result = 0;
- goto out_unlock;
- }
- }
- /* Not found */
-out_unlock:
- spin_unlock_irqrestore(&eda->lock, flags);
- return result;
-}
-
-/*
- * Return contents of EDA cache entry
- *
- * @dev_addr: index to EDA cache
- * @eda_entry: pointer to where contents of EDA cache will be copied
- */
-int wlp_copy_eda_node(struct wlp_eda *eda, struct uwb_dev_addr *dev_addr,
- struct wlp_eda_node *eda_entry)
-{
- int result = -ENOENT;
- struct wlp_eda_node *itr;
- unsigned long flags;
-
- spin_lock_irqsave(&eda->lock, flags);
- list_for_each_entry(itr, &eda->cache, list_node) {
- if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
- *eda_entry = *itr;
- result = 0;
- goto out_unlock;
- }
- }
- /* Not found */
-out_unlock:
- spin_unlock_irqrestore(&eda->lock, flags);
- return result;
-}
-
-/*
- * Execute function for every element in the cache
- *
- * @function: function to execute on element of cache (must be atomic)
- * @priv: private data of function
- * @returns: result of first function that failed, or last function
- * executed if no function failed.
- *
- * Stop executing when function returns error for any element in cache.
- *
- * IMPORTANT: We are using a spinlock here: the function executed on each
- * element has to be atomic.
- */
-int wlp_eda_for_each(struct wlp_eda *eda, wlp_eda_for_each_f function,
- void *priv)
-{
- int result = 0;
- struct wlp *wlp = container_of(eda, struct wlp, eda);
- struct wlp_eda_node *entry;
- unsigned long flags;
-
- spin_lock_irqsave(&eda->lock, flags);
- list_for_each_entry(entry, &eda->cache, list_node) {
- result = (*function)(wlp, entry, priv);
- if (result < 0)
- break;
- }
- spin_unlock_irqrestore(&eda->lock, flags);
- return result;
-}
-
-/*
- * Execute function for single element in the cache (return dev addr)
- *
- * @virt_addr: index into EDA cache used to determine which element to
- * execute the function on
- * @dev_addr: device address of element in cache will be returned using
- * @dev_addr
- * @function: function to execute on element of cache (must be atomic)
- * @priv: private data of function
- * @returns: result of function
- *
- * IMPORTANT: We are using a spinlock here: the function executed on the
- * element has to be atomic.
- */
-int wlp_eda_for_virtual(struct wlp_eda *eda,
- const unsigned char virt_addr[ETH_ALEN],
- struct uwb_dev_addr *dev_addr,
- wlp_eda_for_each_f function,
- void *priv)
-{
- int result = 0;
- struct wlp *wlp = container_of(eda, struct wlp, eda);
- struct wlp_eda_node *itr;
- unsigned long flags;
- int found = 0;
-
- spin_lock_irqsave(&eda->lock, flags);
- list_for_each_entry(itr, &eda->cache, list_node) {
- if (!memcmp(itr->virt_addr, virt_addr,
- sizeof(itr->virt_addr))) {
- result = (*function)(wlp, itr, priv);
- *dev_addr = itr->dev_addr;
- found = 1;
- break;
- }
- }
- if (!found)
- result = -ENODEV;
- spin_unlock_irqrestore(&eda->lock, flags);
- return result;
-}
-
-static const char *__wlp_wss_connect_state[] = { "WLP_WSS_UNCONNECTED",
- "WLP_WSS_CONNECTED",
- "WLP_WSS_CONNECT_FAILED",
-};
-
-static const char *wlp_wss_connect_state_str(unsigned id)
-{
- if (id >= ARRAY_SIZE(__wlp_wss_connect_state))
- return "unknown WSS connection state";
- return __wlp_wss_connect_state[id];
-}
-
-/*
- * View EDA cache from user space
- *
- * A debugging feature to give user visibility into the EDA cache. Also
- * used to display members of WSS to user (called from wlp_wss_members_show())
- */
-ssize_t wlp_eda_show(struct wlp *wlp, char *buf)
-{
- ssize_t result = 0;
- struct wlp_eda_node *entry;
- unsigned long flags;
- struct wlp_eda *eda = &wlp->eda;
- spin_lock_irqsave(&eda->lock, flags);
- result = scnprintf(buf, PAGE_SIZE, "#eth_addr dev_addr wss_ptr "
- "tag state virt_addr\n");
- list_for_each_entry(entry, &eda->cache, list_node) {
- result += scnprintf(buf + result, PAGE_SIZE - result,
- "%pM %02x:%02x %p 0x%02x %s %pM\n",
- entry->eth_addr,
- entry->dev_addr.data[1],
- entry->dev_addr.data[0], entry->wss,
- entry->tag,
- wlp_wss_connect_state_str(entry->state),
- entry->virt_addr);
- if (result >= PAGE_SIZE)
- break;
- }
- spin_unlock_irqrestore(&eda->lock, flags);
- return result;
-}
-EXPORT_SYMBOL_GPL(wlp_eda_show);
-
-/*
- * Add new EDA cache entry based on user input in sysfs
- *
- * Should only be used for debugging.
- *
- * The WSS is assumed to be the only WSS supported. This needs to be
- * redesigned when we support more than one WSS.
- */
-ssize_t wlp_eda_store(struct wlp *wlp, const char *buf, size_t size)
-{
- ssize_t result;
- struct wlp_eda *eda = &wlp->eda;
- u8 eth_addr[6];
- struct uwb_dev_addr dev_addr;
- u8 tag;
- unsigned state;
-
- result = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx "
- "%02hhx:%02hhx %02hhx %u\n",
- &eth_addr[0], &eth_addr[1],
- &eth_addr[2], &eth_addr[3],
- &eth_addr[4], &eth_addr[5],
- &dev_addr.data[1], &dev_addr.data[0], &tag, &state);
- switch (result) {
- case 6: /* no dev addr specified -- remove entry NOT IMPLEMENTED */
- /*result = wlp_eda_rm(eda, eth_addr, &dev_addr);*/
- result = -ENOSYS;
- break;
- case 10:
- state = state >= 1 ? 1 : 0;
- result = wlp_eda_create_node(eda, eth_addr, &dev_addr);
- if (result < 0 && result != -EEXIST)
- goto error;
- /* Set virtual addr to be same as MAC */
- result = wlp_eda_update_node(eda, &dev_addr, &wlp->wss,
- eth_addr, tag, state);
- if (result < 0)
- goto error;
- break;
- default: /* bad format */
- result = -EINVAL;
- }
-error:
- return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(wlp_eda_store);
diff --git a/drivers/uwb/wlp/messages.c b/drivers/uwb/wlp/messages.c
deleted file mode 100644
index 3a8e033dce21..000000000000
--- a/drivers/uwb/wlp/messages.c
+++ /dev/null
@@ -1,1798 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- * Message construction and parsing
- *
- * Copyright (C) 2007 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- */
-
-#include <linux/wlp.h>
-#include <linux/slab.h>
-
-#include "wlp-internal.h"
-
-static
-const char *__wlp_assoc_frame[] = {
- [WLP_ASSOC_D1] = "WLP_ASSOC_D1",
- [WLP_ASSOC_D2] = "WLP_ASSOC_D2",
- [WLP_ASSOC_M1] = "WLP_ASSOC_M1",
- [WLP_ASSOC_M2] = "WLP_ASSOC_M2",
- [WLP_ASSOC_M3] = "WLP_ASSOC_M3",
- [WLP_ASSOC_M4] = "WLP_ASSOC_M4",
- [WLP_ASSOC_M5] = "WLP_ASSOC_M5",
- [WLP_ASSOC_M6] = "WLP_ASSOC_M6",
- [WLP_ASSOC_M7] = "WLP_ASSOC_M7",
- [WLP_ASSOC_M8] = "WLP_ASSOC_M8",
- [WLP_ASSOC_F0] = "WLP_ASSOC_F0",
- [WLP_ASSOC_E1] = "WLP_ASSOC_E1",
- [WLP_ASSOC_E2] = "WLP_ASSOC_E2",
- [WLP_ASSOC_C1] = "WLP_ASSOC_C1",
- [WLP_ASSOC_C2] = "WLP_ASSOC_C2",
- [WLP_ASSOC_C3] = "WLP_ASSOC_C3",
- [WLP_ASSOC_C4] = "WLP_ASSOC_C4",
-};
-
-static const char *wlp_assoc_frame_str(unsigned id)
-{
- if (id >= ARRAY_SIZE(__wlp_assoc_frame))
- return "unknown association frame";
- return __wlp_assoc_frame[id];
-}
-
-static const char *__wlp_assc_error[] = {
- "none",
- "Authenticator Failure",
- "Rogue activity suspected",
- "Device busy",
- "Setup Locked",
- "Registrar not ready",
- "Invalid WSS selection",
- "Message timeout",
- "Enrollment session timeout",
- "Device password invalid",
- "Unsupported version",
- "Internal error",
- "Undefined error",
- "Numeric comparison failure",
- "Waiting for user input",
-};
-
-static const char *wlp_assc_error_str(unsigned id)
-{
- if (id >= ARRAY_SIZE(__wlp_assc_error))
- return "unknown WLP association error";
- return __wlp_assc_error[id];
-}
-
-static inline void wlp_set_attr_hdr(struct wlp_attr_hdr *hdr, unsigned type,
- size_t len)
-{
- hdr->type = cpu_to_le16(type);
- hdr->length = cpu_to_le16(len);
-}
-
-/*
- * Populate fields of a constant sized attribute
- *
- * @returns: total size of attribute including size of new value
- *
- * We have two instances of this function (wlp_pset and wlp_set): one takes
- * the value as a parameter, the other takes a pointer to the value as
- * parameter. They thus only differ in how the value is assigned to the
- * attribute.
- *
- * We use sizeof(*attr) - sizeof(struct wlp_attr_hdr) instead of
- * sizeof(type) to be able to use this same code for the structures that
- * contain 8bit enum values and be able to deal with pointer types.
- */
-#define wlp_set(type, type_code, name) \
-static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \
-{ \
- wlp_set_attr_hdr(&attr->hdr, type_code, \
- sizeof(*attr) - sizeof(struct wlp_attr_hdr)); \
- attr->name = value; \
- return sizeof(*attr); \
-}
-
-#define wlp_pset(type, type_code, name) \
-static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \
-{ \
- wlp_set_attr_hdr(&attr->hdr, type_code, \
- sizeof(*attr) - sizeof(struct wlp_attr_hdr)); \
- attr->name = *value; \
- return sizeof(*attr); \
-}
-
-/**
- * Populate fields of a variable attribute
- *
- * @returns: total size of attribute including size of new value
- *
- * Provided with a pointer to the memory area reserved for the
- * attribute structure, the field is populated with the value. The
- * reserved memory has to contain enough space for the value.
- */
-#define wlp_vset(type, type_code, name) \
-static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value, \
- size_t len) \
-{ \
- wlp_set_attr_hdr(&attr->hdr, type_code, len); \
- memcpy(attr->name, value, len); \
- return sizeof(*attr) + len; \
-}
-
-wlp_vset(char *, WLP_ATTR_DEV_NAME, dev_name)
-wlp_vset(char *, WLP_ATTR_MANUF, manufacturer)
-wlp_set(enum wlp_assoc_type, WLP_ATTR_MSG_TYPE, msg_type)
-wlp_vset(char *, WLP_ATTR_MODEL_NAME, model_name)
-wlp_vset(char *, WLP_ATTR_MODEL_NR, model_nr)
-wlp_vset(char *, WLP_ATTR_SERIAL, serial)
-wlp_vset(char *, WLP_ATTR_WSS_NAME, wss_name)
-wlp_pset(struct wlp_uuid *, WLP_ATTR_UUID_E, uuid_e)
-wlp_pset(struct wlp_uuid *, WLP_ATTR_UUID_R, uuid_r)
-wlp_pset(struct wlp_uuid *, WLP_ATTR_WSSID, wssid)
-wlp_pset(struct wlp_dev_type *, WLP_ATTR_PRI_DEV_TYPE, prim_dev_type)
-/*wlp_pset(struct wlp_dev_type *, WLP_ATTR_SEC_DEV_TYPE, sec_dev_type)*/
-wlp_set(u8, WLP_ATTR_WLP_VER, version)
-wlp_set(enum wlp_assc_error, WLP_ATTR_WLP_ASSC_ERR, wlp_assc_err)
-wlp_set(enum wlp_wss_sel_mthd, WLP_ATTR_WSS_SEL_MTHD, wss_sel_mthd)
-wlp_set(u8, WLP_ATTR_ACC_ENRL, accept_enrl)
-wlp_set(u8, WLP_ATTR_WSS_SEC_STAT, wss_sec_status)
-wlp_pset(struct uwb_mac_addr *, WLP_ATTR_WSS_BCAST, wss_bcast)
-wlp_pset(struct wlp_nonce *, WLP_ATTR_ENRL_NONCE, enonce)
-wlp_pset(struct wlp_nonce *, WLP_ATTR_REG_NONCE, rnonce)
-wlp_set(u8, WLP_ATTR_WSS_TAG, wss_tag)
-wlp_pset(struct uwb_mac_addr *, WLP_ATTR_WSS_VIRT, wss_virt)
-
-/**
- * Fill in the WSS information attributes
- *
- * We currently only support one WSS, and this is assumed in this function
- * that can populate only one WSS information attribute.
- */
-static size_t wlp_set_wss_info(struct wlp_attr_wss_info *attr,
- struct wlp_wss *wss)
-{
- size_t datalen;
- void *ptr = attr->wss_info;
- size_t used = sizeof(*attr);
-
- datalen = sizeof(struct wlp_wss_info) + strlen(wss->name);
- wlp_set_attr_hdr(&attr->hdr, WLP_ATTR_WSS_INFO, datalen);
- used = wlp_set_wssid(ptr, &wss->wssid);
- used += wlp_set_wss_name(ptr + used, wss->name, strlen(wss->name));
- used += wlp_set_accept_enrl(ptr + used, wss->accept_enroll);
- used += wlp_set_wss_sec_status(ptr + used, wss->secure_status);
- used += wlp_set_wss_bcast(ptr + used, &wss->bcast);
- return sizeof(*attr) + used;
-}
-
-/**
- * Verify attribute header
- *
- * @hdr: Pointer to attribute header that will be verified.
- * @type: Expected attribute type.
- * @len: Expected length of attribute value (excluding header).
- *
- * Most attribute values have a known length even when they do have a
- * length field. This knowledge can be used via this function to verify
- * that the length field matches the expected value.
- */
-static int wlp_check_attr_hdr(struct wlp *wlp, struct wlp_attr_hdr *hdr,
- enum wlp_attr_type type, unsigned len)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
-
- if (le16_to_cpu(hdr->type) != type) {
- dev_err(dev, "WLP: unexpected header type. Expected "
- "%u, got %u.\n", type, le16_to_cpu(hdr->type));
- return -EINVAL;
- }
- if (le16_to_cpu(hdr->length) != len) {
- dev_err(dev, "WLP: unexpected length in header. Expected "
- "%u, got %u.\n", len, le16_to_cpu(hdr->length));
- return -EINVAL;
- }
- return 0;
-}
-
-/**
- * Check if header of WSS information attribute valid
- *
- * @returns: length of WSS attributes (value of length attribute field) if
- * valid WSS information attribute found
- * -ENODATA if no WSS information attribute found
- * -EIO other error occured
- *
- * The WSS information attribute is optional. The function will be provided
- * with a pointer to data that could _potentially_ be a WSS information
- * attribute. If a valid WSS information attribute is found it will return
- * 0, if no WSS information attribute is found it will return -ENODATA, and
- * another error will be returned if it is a WSS information attribute, but
- * some parsing failure occured.
- */
-static int wlp_check_wss_info_attr_hdr(struct wlp *wlp,
- struct wlp_attr_hdr *hdr, size_t buflen)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- size_t len;
- int result = 0;
-
- if (buflen < sizeof(*hdr)) {
- dev_err(dev, "WLP: Not enough space in buffer to parse"
- " WSS information attribute header.\n");
- result = -EIO;
- goto out;
- }
- if (le16_to_cpu(hdr->type) != WLP_ATTR_WSS_INFO) {
- /* WSS information is optional */
- result = -ENODATA;
- goto out;
- }
- len = le16_to_cpu(hdr->length);
- if (buflen < sizeof(*hdr) + len) {
- dev_err(dev, "WLP: Not enough space in buffer to parse "
- "variable data. Got %d, expected %d.\n",
- (int)buflen, (int)(sizeof(*hdr) + len));
- result = -EIO;
- goto out;
- }
- result = len;
-out:
- return result;
-}
-
-
-static ssize_t wlp_get_attribute(struct wlp *wlp, u16 type_code,
- struct wlp_attr_hdr *attr_hdr, void *value, ssize_t value_len,
- ssize_t buflen)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- ssize_t attr_len = sizeof(*attr_hdr) + value_len;
- if (buflen < 0)
- return -EINVAL;
- if (buflen < attr_len) {
- dev_err(dev, "WLP: Not enough space in buffer to parse"
- " attribute field. Need %d, received %zu\n",
- (int)attr_len, buflen);
- return -EIO;
- }
- if (wlp_check_attr_hdr(wlp, attr_hdr, type_code, value_len) < 0) {
- dev_err(dev, "WLP: Header verification failed. \n");
- return -EINVAL;
- }
- memcpy(value, (void *)attr_hdr + sizeof(*attr_hdr), value_len);
- return attr_len;
-}
-
-static ssize_t wlp_vget_attribute(struct wlp *wlp, u16 type_code,
- struct wlp_attr_hdr *attr_hdr, void *value, ssize_t max_value_len,
- ssize_t buflen)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- size_t len;
- if (buflen < 0)
- return -EINVAL;
- if (buflen < sizeof(*attr_hdr)) {
- dev_err(dev, "WLP: Not enough space in buffer to parse"
- " header.\n");
- return -EIO;
- }
- if (le16_to_cpu(attr_hdr->type) != type_code) {
- dev_err(dev, "WLP: Unexpected attribute type. Got %u, "
- "expected %u.\n", le16_to_cpu(attr_hdr->type),
- type_code);
- return -EINVAL;
- }
- len = le16_to_cpu(attr_hdr->length);
- if (len > max_value_len) {
- dev_err(dev, "WLP: Attribute larger than maximum "
- "allowed. Received %zu, max is %d.\n", len,
- (int)max_value_len);
- return -EFBIG;
- }
- if (buflen < sizeof(*attr_hdr) + len) {
- dev_err(dev, "WLP: Not enough space in buffer to parse "
- "variable data.\n");
- return -EIO;
- }
- memcpy(value, (void *)attr_hdr + sizeof(*attr_hdr), len);
- return sizeof(*attr_hdr) + len;
-}
-
-/**
- * Get value of attribute from fixed size attribute field.
- *
- * @attr: Pointer to attribute field.
- * @value: Pointer to variable in which attribute value will be placed.
- * @buflen: Size of buffer in which attribute field (including header)
- * can be found.
- * @returns: Amount of given buffer consumed by parsing for this attribute.
- *
- * The size and type of the value is known by the type of the attribute.
- */
-#define wlp_get(type, type_code, name) \
-ssize_t wlp_get_##name(struct wlp *wlp, struct wlp_attr_##name *attr, \
- type *value, ssize_t buflen) \
-{ \
- return wlp_get_attribute(wlp, (type_code), &attr->hdr, \
- value, sizeof(*value), buflen); \
-}
-
-#define wlp_get_sparse(type, type_code, name) \
- static wlp_get(type, type_code, name)
-
-/**
- * Get value of attribute from variable sized attribute field.
- *
- * @max: The maximum size of this attribute. This value is dictated by
- * the maximum value from the WLP specification.
- *
- * @attr: Pointer to attribute field.
- * @value: Pointer to variable that will contain the value. The memory
- * must already have been allocated for this value.
- * @buflen: Size of buffer in which attribute field (including header)
- * can be found.
- * @returns: Amount of given bufferconsumed by parsing for this attribute.
- */
-#define wlp_vget(type_val, type_code, name, max) \
-static ssize_t wlp_get_##name(struct wlp *wlp, \
- struct wlp_attr_##name *attr, \
- type_val *value, ssize_t buflen) \
-{ \
- return wlp_vget_attribute(wlp, (type_code), &attr->hdr, \
- value, (max), buflen); \
-}
-
-wlp_get(u8, WLP_ATTR_WLP_VER, version)
-wlp_get_sparse(enum wlp_wss_sel_mthd, WLP_ATTR_WSS_SEL_MTHD, wss_sel_mthd)
-wlp_get_sparse(struct wlp_dev_type, WLP_ATTR_PRI_DEV_TYPE, prim_dev_type)
-wlp_get_sparse(enum wlp_assc_error, WLP_ATTR_WLP_ASSC_ERR, wlp_assc_err)
-wlp_get_sparse(struct wlp_uuid, WLP_ATTR_UUID_E, uuid_e)
-wlp_get_sparse(struct wlp_uuid, WLP_ATTR_UUID_R, uuid_r)
-wlp_get(struct wlp_uuid, WLP_ATTR_WSSID, wssid)
-wlp_get_sparse(u8, WLP_ATTR_ACC_ENRL, accept_enrl)
-wlp_get_sparse(u8, WLP_ATTR_WSS_SEC_STAT, wss_sec_status)
-wlp_get_sparse(struct uwb_mac_addr, WLP_ATTR_WSS_BCAST, wss_bcast)
-wlp_get_sparse(u8, WLP_ATTR_WSS_TAG, wss_tag)
-wlp_get_sparse(struct uwb_mac_addr, WLP_ATTR_WSS_VIRT, wss_virt)
-wlp_get_sparse(struct wlp_nonce, WLP_ATTR_ENRL_NONCE, enonce)
-wlp_get_sparse(struct wlp_nonce, WLP_ATTR_REG_NONCE, rnonce)
-
-/* The buffers for the device info attributes can be found in the
- * wlp_device_info struct. These buffers contain one byte more than the
- * max allowed by the spec - this is done to be able to add the
- * terminating \0 for user display. This terminating byte is not required
- * in the actual attribute field (because it has a length field) so the
- * maximum allowed for this value is one less than its size in the
- * structure.
- */
-wlp_vget(char, WLP_ATTR_WSS_NAME, wss_name,
- FIELD_SIZEOF(struct wlp_wss, name) - 1)
-wlp_vget(char, WLP_ATTR_DEV_NAME, dev_name,
- FIELD_SIZEOF(struct wlp_device_info, name) - 1)
-wlp_vget(char, WLP_ATTR_MANUF, manufacturer,
- FIELD_SIZEOF(struct wlp_device_info, manufacturer) - 1)
-wlp_vget(char, WLP_ATTR_MODEL_NAME, model_name,
- FIELD_SIZEOF(struct wlp_device_info, model_name) - 1)
-wlp_vget(char, WLP_ATTR_MODEL_NR, model_nr,
- FIELD_SIZEOF(struct wlp_device_info, model_nr) - 1)
-wlp_vget(char, WLP_ATTR_SERIAL, serial,
- FIELD_SIZEOF(struct wlp_device_info, serial) - 1)
-
-/**
- * Retrieve WSS Name, Accept enroll, Secure status, Broadcast from WSS info
- *
- * @attr: pointer to WSS name attribute in WSS information attribute field
- * @info: structure that will be populated with data from WSS information
- * field (WSS name, Accept enroll, secure status, broadcast address)
- * @buflen: size of buffer
- *
- * Although the WSSID attribute forms part of the WSS info attribute it is
- * retrieved separately and stored in a different location.
- */
-static ssize_t wlp_get_wss_info_attrs(struct wlp *wlp,
- struct wlp_attr_hdr *attr,
- struct wlp_wss_tmp_info *info,
- ssize_t buflen)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- void *ptr = attr;
- size_t used = 0;
- ssize_t result = -EINVAL;
-
- result = wlp_get_wss_name(wlp, ptr, info->name, buflen);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain WSS name from "
- "WSS info in D2 message.\n");
- goto error_parse;
- }
- used += result;
-
- result = wlp_get_accept_enrl(wlp, ptr + used, &info->accept_enroll,
- buflen - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain accepting "
- "enrollment from WSS info in D2 message.\n");
- goto error_parse;
- }
- if (info->accept_enroll != 0 && info->accept_enroll != 1) {
- dev_err(dev, "WLP: invalid value for accepting "
- "enrollment in D2 message.\n");
- result = -EINVAL;
- goto error_parse;
- }
- used += result;
-
- result = wlp_get_wss_sec_status(wlp, ptr + used, &info->sec_status,
- buflen - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain secure "
- "status from WSS info in D2 message.\n");
- goto error_parse;
- }
- if (info->sec_status != 0 && info->sec_status != 1) {
- dev_err(dev, "WLP: invalid value for secure "
- "status in D2 message.\n");
- result = -EINVAL;
- goto error_parse;
- }
- used += result;
-
- result = wlp_get_wss_bcast(wlp, ptr + used, &info->bcast,
- buflen - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain broadcast "
- "address from WSS info in D2 message.\n");
- goto error_parse;
- }
- used += result;
- result = used;
-error_parse:
- return result;
-}
-
-/**
- * Create a new WSSID entry for the neighbor, allocate temporary storage
- *
- * Each neighbor can have many WSS active. We maintain a list of WSSIDs
- * advertised by neighbor. During discovery we also cache information about
- * these WSS in temporary storage.
- *
- * The temporary storage will be removed after it has been used (eg.
- * displayed to user), the wssid element will be removed from the list when
- * the neighbor is rediscovered or when it disappears.
- */
-static struct wlp_wssid_e *wlp_create_wssid_e(struct wlp *wlp,
- struct wlp_neighbor_e *neighbor)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct wlp_wssid_e *wssid_e;
-
- wssid_e = kzalloc(sizeof(*wssid_e), GFP_KERNEL);
- if (wssid_e == NULL) {
- dev_err(dev, "WLP: unable to allocate memory "
- "for WSS information.\n");
- goto error_alloc;
- }
- wssid_e->info = kzalloc(sizeof(struct wlp_wss_tmp_info), GFP_KERNEL);
- if (wssid_e->info == NULL) {
- dev_err(dev, "WLP: unable to allocate memory "
- "for temporary WSS information.\n");
- kfree(wssid_e);
- wssid_e = NULL;
- goto error_alloc;
- }
- list_add(&wssid_e->node, &neighbor->wssid);
-error_alloc:
- return wssid_e;
-}
-
-/**
- * Parse WSS information attribute
- *
- * @attr: pointer to WSS information attribute header
- * @buflen: size of buffer in which WSS information attribute appears
- * @wssid: will place wssid from WSS info attribute in this location
- * @wss_info: will place other information from WSS information attribute
- * in this location
- *
- * memory for @wssid and @wss_info must be allocated when calling this
- */
-static ssize_t wlp_get_wss_info(struct wlp *wlp, struct wlp_attr_wss_info *attr,
- size_t buflen, struct wlp_uuid *wssid,
- struct wlp_wss_tmp_info *wss_info)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- ssize_t result;
- size_t len;
- size_t used = 0;
- void *ptr;
-
- result = wlp_check_wss_info_attr_hdr(wlp, (struct wlp_attr_hdr *)attr,
- buflen);
- if (result < 0)
- goto out;
- len = result;
- used = sizeof(*attr);
- ptr = attr;
-
- result = wlp_get_wssid(wlp, ptr + used, wssid, buflen - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain WSSID from WSS info.\n");
- goto out;
- }
- used += result;
- result = wlp_get_wss_info_attrs(wlp, ptr + used, wss_info,
- buflen - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain WSS information "
- "from WSS information attributes. \n");
- goto out;
- }
- used += result;
- if (len + sizeof(*attr) != used) {
- dev_err(dev, "WLP: Amount of data parsed does not "
- "match length field. Parsed %zu, length "
- "field %zu. \n", used, len);
- result = -EINVAL;
- goto out;
- }
- result = used;
-out:
- return result;
-}
-
-/**
- * Retrieve WSS info from association frame
- *
- * @attr: pointer to WSS information attribute
- * @neighbor: ptr to neighbor being discovered, NULL if enrollment in
- * progress
- * @wss: ptr to WSS being enrolled in, NULL if discovery in progress
- * @buflen: size of buffer in which WSS information appears
- *
- * The WSS information attribute appears in the D2 association message.
- * This message is used in two ways: to discover all neighbors or to enroll
- * into a WSS activated by a neighbor. During discovery we only want to
- * store the WSS info in a cache, to be deleted right after it has been
- * used (eg. displayed to the user). During enrollment we store the WSS
- * information for the lifetime of enrollment.
- *
- * During discovery we are interested in all WSS information, during
- * enrollment we are only interested in the WSS being enrolled in. Even so,
- * when in enrollment we keep parsing the message after finding the WSS of
- * interest, this simplifies the calling routine in that it can be sure
- * that all WSS information attributes have been parsed out of the message.
- *
- * Association frame is process with nbmutex held. The list access is safe.
- */
-static ssize_t wlp_get_all_wss_info(struct wlp *wlp,
- struct wlp_attr_wss_info *attr,
- struct wlp_neighbor_e *neighbor,
- struct wlp_wss *wss, ssize_t buflen)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- size_t used = 0;
- ssize_t result = -EINVAL;
- struct wlp_attr_wss_info *cur;
- struct wlp_uuid wssid;
- struct wlp_wss_tmp_info wss_info;
- unsigned enroll; /* 0 - discovery to cache, 1 - enrollment */
- struct wlp_wssid_e *wssid_e;
- char buf[WLP_WSS_UUID_STRSIZE];
-
- if (buflen < 0)
- goto out;
-
- if (neighbor != NULL && wss == NULL)
- enroll = 0; /* discovery */
- else if (wss != NULL && neighbor == NULL)
- enroll = 1; /* enrollment */
- else
- goto out;
-
- cur = attr;
- while (buflen - used > 0) {
- memset(&wss_info, 0, sizeof(wss_info));
- cur = (void *)cur + used;
- result = wlp_get_wss_info(wlp, cur, buflen - used, &wssid,
- &wss_info);
- if (result == -ENODATA) {
- result = used;
- goto out;
- } else if (result < 0) {
- dev_err(dev, "WLP: Unable to parse WSS information "
- "from WSS information attribute. \n");
- result = -EINVAL;
- goto error_parse;
- }
- if (enroll && !memcmp(&wssid, &wss->wssid, sizeof(wssid))) {
- if (wss_info.accept_enroll != 1) {
- dev_err(dev, "WLP: Requested WSS does "
- "not accept enrollment.\n");
- result = -EINVAL;
- goto out;
- }
- memcpy(wss->name, wss_info.name, sizeof(wss->name));
- wss->bcast = wss_info.bcast;
- wss->secure_status = wss_info.sec_status;
- wss->accept_enroll = wss_info.accept_enroll;
- wss->state = WLP_WSS_STATE_PART_ENROLLED;
- wlp_wss_uuid_print(buf, sizeof(buf), &wssid);
- dev_dbg(dev, "WLP: Found WSS %s. Enrolling.\n", buf);
- } else {
- wssid_e = wlp_create_wssid_e(wlp, neighbor);
- if (wssid_e == NULL) {
- dev_err(dev, "WLP: Cannot create new WSSID "
- "entry for neighbor %02x:%02x.\n",
- neighbor->uwb_dev->dev_addr.data[1],
- neighbor->uwb_dev->dev_addr.data[0]);
- result = -ENOMEM;
- goto out;
- }
- wssid_e->wssid = wssid;
- *wssid_e->info = wss_info;
- }
- used += result;
- }
- result = used;
-error_parse:
- if (result < 0 && !enroll) /* this was a discovery */
- wlp_remove_neighbor_tmp_info(neighbor);
-out:
- return result;
-
-}
-
-/**
- * Parse WSS information attributes into cache for discovery
- *
- * @attr: the first WSS information attribute in message
- * @neighbor: the neighbor whose cache will be populated
- * @buflen: size of the input buffer
- */
-static ssize_t wlp_get_wss_info_to_cache(struct wlp *wlp,
- struct wlp_attr_wss_info *attr,
- struct wlp_neighbor_e *neighbor,
- ssize_t buflen)
-{
- return wlp_get_all_wss_info(wlp, attr, neighbor, NULL, buflen);
-}
-
-/**
- * Parse WSS information attributes into WSS struct for enrollment
- *
- * @attr: the first WSS information attribute in message
- * @wss: the WSS that will be enrolled
- * @buflen: size of the input buffer
- */
-static ssize_t wlp_get_wss_info_to_enroll(struct wlp *wlp,
- struct wlp_attr_wss_info *attr,
- struct wlp_wss *wss, ssize_t buflen)
-{
- return wlp_get_all_wss_info(wlp, attr, NULL, wss, buflen);
-}
-
-/**
- * Construct a D1 association frame
- *
- * We use the radio control functions to determine the values of the device
- * properties. These are of variable length and the total space needed is
- * tallied first before we start constructing the message. The radio
- * control functions return strings that are terminated with \0. This
- * character should not be included in the message (there is a length field
- * accompanying it in the attribute).
- */
-static int wlp_build_assoc_d1(struct wlp *wlp, struct wlp_wss *wss,
- struct sk_buff **skb)
-{
-
- struct device *dev = &wlp->rc->uwb_dev.dev;
- int result = 0;
- struct wlp_device_info *info;
- size_t used = 0;
- struct wlp_frame_assoc *_d1;
- struct sk_buff *_skb;
- void *d1_itr;
-
- if (wlp->dev_info == NULL) {
- result = __wlp_setup_device_info(wlp);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to setup device "
- "information for D1 message.\n");
- goto error;
- }
- }
- info = wlp->dev_info;
- _skb = dev_alloc_skb(sizeof(*_d1)
- + sizeof(struct wlp_attr_uuid_e)
- + sizeof(struct wlp_attr_wss_sel_mthd)
- + sizeof(struct wlp_attr_dev_name)
- + strlen(info->name)
- + sizeof(struct wlp_attr_manufacturer)
- + strlen(info->manufacturer)
- + sizeof(struct wlp_attr_model_name)
- + strlen(info->model_name)
- + sizeof(struct wlp_attr_model_nr)
- + strlen(info->model_nr)
- + sizeof(struct wlp_attr_serial)
- + strlen(info->serial)
- + sizeof(struct wlp_attr_prim_dev_type)
- + sizeof(struct wlp_attr_wlp_assc_err));
- if (_skb == NULL) {
- dev_err(dev, "WLP: Cannot allocate memory for association "
- "message.\n");
- result = -ENOMEM;
- goto error;
- }
- _d1 = (void *) _skb->data;
- _d1->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
- _d1->hdr.type = WLP_FRAME_ASSOCIATION;
- _d1->type = WLP_ASSOC_D1;
-
- wlp_set_version(&_d1->version, WLP_VERSION);
- wlp_set_msg_type(&_d1->msg_type, WLP_ASSOC_D1);
- d1_itr = _d1->attr;
- used = wlp_set_uuid_e(d1_itr, &wlp->uuid);
- used += wlp_set_wss_sel_mthd(d1_itr + used, WLP_WSS_REG_SELECT);
- used += wlp_set_dev_name(d1_itr + used, info->name,
- strlen(info->name));
- used += wlp_set_manufacturer(d1_itr + used, info->manufacturer,
- strlen(info->manufacturer));
- used += wlp_set_model_name(d1_itr + used, info->model_name,
- strlen(info->model_name));
- used += wlp_set_model_nr(d1_itr + used, info->model_nr,
- strlen(info->model_nr));
- used += wlp_set_serial(d1_itr + used, info->serial,
- strlen(info->serial));
- used += wlp_set_prim_dev_type(d1_itr + used, &info->prim_dev_type);
- used += wlp_set_wlp_assc_err(d1_itr + used, WLP_ASSOC_ERROR_NONE);
- skb_put(_skb, sizeof(*_d1) + used);
- *skb = _skb;
-error:
- return result;
-}
-
-/**
- * Construct a D2 association frame
- *
- * We use the radio control functions to determine the values of the device
- * properties. These are of variable length and the total space needed is
- * tallied first before we start constructing the message. The radio
- * control functions return strings that are terminated with \0. This
- * character should not be included in the message (there is a length field
- * accompanying it in the attribute).
- */
-static
-int wlp_build_assoc_d2(struct wlp *wlp, struct wlp_wss *wss,
- struct sk_buff **skb, struct wlp_uuid *uuid_e)
-{
-
- struct device *dev = &wlp->rc->uwb_dev.dev;
- int result = 0;
- struct wlp_device_info *info;
- size_t used = 0;
- struct wlp_frame_assoc *_d2;
- struct sk_buff *_skb;
- void *d2_itr;
- size_t mem_needed;
-
- if (wlp->dev_info == NULL) {
- result = __wlp_setup_device_info(wlp);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to setup device "
- "information for D2 message.\n");
- goto error;
- }
- }
- info = wlp->dev_info;
- mem_needed = sizeof(*_d2)
- + sizeof(struct wlp_attr_uuid_e)
- + sizeof(struct wlp_attr_uuid_r)
- + sizeof(struct wlp_attr_dev_name)
- + strlen(info->name)
- + sizeof(struct wlp_attr_manufacturer)
- + strlen(info->manufacturer)
- + sizeof(struct wlp_attr_model_name)
- + strlen(info->model_name)
- + sizeof(struct wlp_attr_model_nr)
- + strlen(info->model_nr)
- + sizeof(struct wlp_attr_serial)
- + strlen(info->serial)
- + sizeof(struct wlp_attr_prim_dev_type)
- + sizeof(struct wlp_attr_wlp_assc_err);
- if (wlp->wss.state >= WLP_WSS_STATE_ACTIVE)
- mem_needed += sizeof(struct wlp_attr_wss_info)
- + sizeof(struct wlp_wss_info)
- + strlen(wlp->wss.name);
- _skb = dev_alloc_skb(mem_needed);
- if (_skb == NULL) {
- dev_err(dev, "WLP: Cannot allocate memory for association "
- "message.\n");
- result = -ENOMEM;
- goto error;
- }
- _d2 = (void *) _skb->data;
- _d2->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
- _d2->hdr.type = WLP_FRAME_ASSOCIATION;
- _d2->type = WLP_ASSOC_D2;
-
- wlp_set_version(&_d2->version, WLP_VERSION);
- wlp_set_msg_type(&_d2->msg_type, WLP_ASSOC_D2);
- d2_itr = _d2->attr;
- used = wlp_set_uuid_e(d2_itr, uuid_e);
- used += wlp_set_uuid_r(d2_itr + used, &wlp->uuid);
- if (wlp->wss.state >= WLP_WSS_STATE_ACTIVE)
- used += wlp_set_wss_info(d2_itr + used, &wlp->wss);
- used += wlp_set_dev_name(d2_itr + used, info->name,
- strlen(info->name));
- used += wlp_set_manufacturer(d2_itr + used, info->manufacturer,
- strlen(info->manufacturer));
- used += wlp_set_model_name(d2_itr + used, info->model_name,
- strlen(info->model_name));
- used += wlp_set_model_nr(d2_itr + used, info->model_nr,
- strlen(info->model_nr));
- used += wlp_set_serial(d2_itr + used, info->serial,
- strlen(info->serial));
- used += wlp_set_prim_dev_type(d2_itr + used, &info->prim_dev_type);
- used += wlp_set_wlp_assc_err(d2_itr + used, WLP_ASSOC_ERROR_NONE);
- skb_put(_skb, sizeof(*_d2) + used);
- *skb = _skb;
-error:
- return result;
-}
-
-/**
- * Allocate memory for and populate fields of F0 association frame
- *
- * Currently (while focusing on unsecure enrollment) we ignore the
- * nonce's that could be placed in the message. Only the error field is
- * populated by the value provided by the caller.
- */
-static
-int wlp_build_assoc_f0(struct wlp *wlp, struct sk_buff **skb,
- enum wlp_assc_error error)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- int result = -ENOMEM;
- struct {
- struct wlp_frame_assoc f0_hdr;
- struct wlp_attr_enonce enonce;
- struct wlp_attr_rnonce rnonce;
- struct wlp_attr_wlp_assc_err assc_err;
- } *f0;
- struct sk_buff *_skb;
- struct wlp_nonce tmp;
-
- _skb = dev_alloc_skb(sizeof(*f0));
- if (_skb == NULL) {
- dev_err(dev, "WLP: Unable to allocate memory for F0 "
- "association frame. \n");
- goto error_alloc;
- }
- f0 = (void *) _skb->data;
- f0->f0_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
- f0->f0_hdr.hdr.type = WLP_FRAME_ASSOCIATION;
- f0->f0_hdr.type = WLP_ASSOC_F0;
- wlp_set_version(&f0->f0_hdr.version, WLP_VERSION);
- wlp_set_msg_type(&f0->f0_hdr.msg_type, WLP_ASSOC_F0);
- memset(&tmp, 0, sizeof(tmp));
- wlp_set_enonce(&f0->enonce, &tmp);
- wlp_set_rnonce(&f0->rnonce, &tmp);
- wlp_set_wlp_assc_err(&f0->assc_err, error);
- skb_put(_skb, sizeof(*f0));
- *skb = _skb;
- result = 0;
-error_alloc:
- return result;
-}
-
-/**
- * Parse F0 frame
- *
- * We just retrieve the values and print it as an error to the user.
- * Calling function already knows an error occured (F0 indicates error), so
- * we just parse the content as debug for higher layers.
- */
-int wlp_parse_f0(struct wlp *wlp, struct sk_buff *skb)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct wlp_frame_assoc *f0 = (void *) skb->data;
- void *ptr = skb->data;
- size_t len = skb->len;
- size_t used;
- ssize_t result;
- struct wlp_nonce enonce, rnonce;
- enum wlp_assc_error assc_err;
- char enonce_buf[WLP_WSS_NONCE_STRSIZE];
- char rnonce_buf[WLP_WSS_NONCE_STRSIZE];
-
- used = sizeof(*f0);
- result = wlp_get_enonce(wlp, ptr + used, &enonce, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain Enrollee nonce "
- "attribute from F0 message.\n");
- goto error_parse;
- }
- used += result;
- result = wlp_get_rnonce(wlp, ptr + used, &rnonce, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain Registrar nonce "
- "attribute from F0 message.\n");
- goto error_parse;
- }
- used += result;
- result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain WLP Association error "
- "attribute from F0 message.\n");
- goto error_parse;
- }
- wlp_wss_nonce_print(enonce_buf, sizeof(enonce_buf), &enonce);
- wlp_wss_nonce_print(rnonce_buf, sizeof(rnonce_buf), &rnonce);
- dev_err(dev, "WLP: Received F0 error frame from neighbor. Enrollee "
- "nonce: %s, Registrar nonce: %s, WLP Association error: %s.\n",
- enonce_buf, rnonce_buf, wlp_assc_error_str(assc_err));
- result = 0;
-error_parse:
- return result;
-}
-
-/**
- * Retrieve variable device information from association message
- *
- * The device information parsed is not required in any message. This
- * routine will thus not fail if an attribute is not present.
- * The attributes are expected in a certain order, even if all are not
- * present. The "attribute type" value is used to ensure the attributes
- * are parsed in the correct order.
- *
- * If an error is encountered during parsing the function will return an
- * error code, when this happens the given device_info structure may be
- * partially filled.
- */
-static
-int wlp_get_variable_info(struct wlp *wlp, void *data,
- struct wlp_device_info *dev_info, ssize_t len)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- size_t used = 0;
- struct wlp_attr_hdr *hdr;
- ssize_t result = 0;
- unsigned last = 0;
-
- while (len - used > 0) {
- if (len - used < sizeof(*hdr)) {
- dev_err(dev, "WLP: Partial data in frame, cannot "
- "parse. \n");
- goto error_parse;
- }
- hdr = data + used;
- switch (le16_to_cpu(hdr->type)) {
- case WLP_ATTR_MANUF:
- if (last >= WLP_ATTR_MANUF) {
- dev_err(dev, "WLP: Incorrect order of "
- "attribute values in D1 msg.\n");
- goto error_parse;
- }
- result = wlp_get_manufacturer(wlp, data + used,
- dev_info->manufacturer,
- len - used);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to obtain "
- "Manufacturer attribute from D1 "
- "message.\n");
- goto error_parse;
- }
- last = WLP_ATTR_MANUF;
- used += result;
- break;
- case WLP_ATTR_MODEL_NAME:
- if (last >= WLP_ATTR_MODEL_NAME) {
- dev_err(dev, "WLP: Incorrect order of "
- "attribute values in D1 msg.\n");
- goto error_parse;
- }
- result = wlp_get_model_name(wlp, data + used,
- dev_info->model_name,
- len - used);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to obtain Model "
- "name attribute from D1 message.\n");
- goto error_parse;
- }
- last = WLP_ATTR_MODEL_NAME;
- used += result;
- break;
- case WLP_ATTR_MODEL_NR:
- if (last >= WLP_ATTR_MODEL_NR) {
- dev_err(dev, "WLP: Incorrect order of "
- "attribute values in D1 msg.\n");
- goto error_parse;
- }
- result = wlp_get_model_nr(wlp, data + used,
- dev_info->model_nr,
- len - used);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to obtain Model "
- "number attribute from D1 message.\n");
- goto error_parse;
- }
- last = WLP_ATTR_MODEL_NR;
- used += result;
- break;
- case WLP_ATTR_SERIAL:
- if (last >= WLP_ATTR_SERIAL) {
- dev_err(dev, "WLP: Incorrect order of "
- "attribute values in D1 msg.\n");
- goto error_parse;
- }
- result = wlp_get_serial(wlp, data + used,
- dev_info->serial, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to obtain Serial "
- "number attribute from D1 message.\n");
- goto error_parse;
- }
- last = WLP_ATTR_SERIAL;
- used += result;
- break;
- case WLP_ATTR_PRI_DEV_TYPE:
- if (last >= WLP_ATTR_PRI_DEV_TYPE) {
- dev_err(dev, "WLP: Incorrect order of "
- "attribute values in D1 msg.\n");
- goto error_parse;
- }
- result = wlp_get_prim_dev_type(wlp, data + used,
- &dev_info->prim_dev_type,
- len - used);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to obtain Primary "
- "device type attribute from D1 "
- "message.\n");
- goto error_parse;
- }
- dev_info->prim_dev_type.category =
- le16_to_cpu(dev_info->prim_dev_type.category);
- dev_info->prim_dev_type.subID =
- le16_to_cpu(dev_info->prim_dev_type.subID);
- last = WLP_ATTR_PRI_DEV_TYPE;
- used += result;
- break;
- default:
- /* This is not variable device information. */
- goto out;
- break;
- }
- }
-out:
- return used;
-error_parse:
- return -EINVAL;
-}
-
-/**
- * Parse incoming D1 frame, populate attribute values
- *
- * Caller provides pointers to memory already allocated for attributes
- * expected in the D1 frame. These variables will be populated.
- */
-static
-int wlp_parse_d1_frame(struct wlp *wlp, struct sk_buff *skb,
- struct wlp_uuid *uuid_e,
- enum wlp_wss_sel_mthd *sel_mthd,
- struct wlp_device_info *dev_info,
- enum wlp_assc_error *assc_err)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct wlp_frame_assoc *d1 = (void *) skb->data;
- void *ptr = skb->data;
- size_t len = skb->len;
- size_t used;
- ssize_t result;
-
- used = sizeof(*d1);
- result = wlp_get_uuid_e(wlp, ptr + used, uuid_e, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain UUID-E attribute from D1 "
- "message.\n");
- goto error_parse;
- }
- used += result;
- result = wlp_get_wss_sel_mthd(wlp, ptr + used, sel_mthd, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain WSS selection method "
- "from D1 message.\n");
- goto error_parse;
- }
- used += result;
- result = wlp_get_dev_name(wlp, ptr + used, dev_info->name,
- len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain Device Name from D1 "
- "message.\n");
- goto error_parse;
- }
- used += result;
- result = wlp_get_variable_info(wlp, ptr + used, dev_info, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain Device Information from "
- "D1 message.\n");
- goto error_parse;
- }
- used += result;
- result = wlp_get_wlp_assc_err(wlp, ptr + used, assc_err, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain WLP Association Error "
- "Information from D1 message.\n");
- goto error_parse;
- }
- result = 0;
-error_parse:
- return result;
-}
-/**
- * Handle incoming D1 frame
- *
- * The frame has already been verified to contain an Association header with
- * the correct version number. Parse the incoming frame, construct and send
- * a D2 frame in response.
- *
- * It is not clear what to do with most fields in the incoming D1 frame. We
- * retrieve and discard the information here for now.
- */
-void wlp_handle_d1_frame(struct work_struct *ws)
-{
- struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws,
- struct wlp_assoc_frame_ctx,
- ws);
- struct wlp *wlp = frame_ctx->wlp;
- struct wlp_wss *wss = &wlp->wss;
- struct sk_buff *skb = frame_ctx->skb;
- struct uwb_dev_addr *src = &frame_ctx->src;
- int result;
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct wlp_uuid uuid_e;
- enum wlp_wss_sel_mthd sel_mthd = 0;
- struct wlp_device_info dev_info;
- enum wlp_assc_error assc_err;
- struct sk_buff *resp = NULL;
-
- /* Parse D1 frame */
- mutex_lock(&wss->mutex);
- mutex_lock(&wlp->mutex); /* to access wlp->uuid */
- memset(&dev_info, 0, sizeof(dev_info));
- result = wlp_parse_d1_frame(wlp, skb, &uuid_e, &sel_mthd, &dev_info,
- &assc_err);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to parse incoming D1 frame.\n");
- kfree_skb(skb);
- goto out;
- }
-
- kfree_skb(skb);
- if (!wlp_uuid_is_set(&wlp->uuid)) {
- dev_err(dev, "WLP: UUID is not set. Set via sysfs to "
- "proceed. Respong to D1 message with error F0.\n");
- result = wlp_build_assoc_f0(wlp, &resp,
- WLP_ASSOC_ERROR_NOT_READY);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to construct F0 message.\n");
- goto out;
- }
- } else {
- /* Construct D2 frame */
- result = wlp_build_assoc_d2(wlp, wss, &resp, &uuid_e);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to construct D2 message.\n");
- goto out;
- }
- }
- /* Send D2 frame */
- BUG_ON(wlp->xmit_frame == NULL);
- result = wlp->xmit_frame(wlp, resp, src);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to transmit D2 association "
- "message: %d\n", result);
- if (result == -ENXIO)
- dev_err(dev, "WLP: Is network interface up? \n");
- /* We could try again ... */
- dev_kfree_skb_any(resp); /* we need to free if tx fails */
- }
-out:
- kfree(frame_ctx);
- mutex_unlock(&wlp->mutex);
- mutex_unlock(&wss->mutex);
-}
-
-/**
- * Parse incoming D2 frame, create and populate temporary cache
- *
- * @skb: socket buffer in which D2 frame can be found
- * @neighbor: the neighbor that sent the D2 frame
- *
- * Will allocate memory for temporary storage of information learned during
- * discovery.
- */
-int wlp_parse_d2_frame_to_cache(struct wlp *wlp, struct sk_buff *skb,
- struct wlp_neighbor_e *neighbor)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct wlp_frame_assoc *d2 = (void *) skb->data;
- void *ptr = skb->data;
- size_t len = skb->len;
- size_t used;
- ssize_t result;
- struct wlp_uuid uuid_e;
- struct wlp_device_info *nb_info;
- enum wlp_assc_error assc_err;
-
- used = sizeof(*d2);
- result = wlp_get_uuid_e(wlp, ptr + used, &uuid_e, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain UUID-E attribute from D2 "
- "message.\n");
- goto error_parse;
- }
- if (memcmp(&uuid_e, &wlp->uuid, sizeof(uuid_e))) {
- dev_err(dev, "WLP: UUID-E in incoming D2 does not match "
- "local UUID sent in D1. \n");
- goto error_parse;
- }
- used += result;
- result = wlp_get_uuid_r(wlp, ptr + used, &neighbor->uuid, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain UUID-R attribute from D2 "
- "message.\n");
- goto error_parse;
- }
- used += result;
- result = wlp_get_wss_info_to_cache(wlp, ptr + used, neighbor,
- len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain WSS information "
- "from D2 message.\n");
- goto error_parse;
- }
- used += result;
- neighbor->info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL);
- if (neighbor->info == NULL) {
- dev_err(dev, "WLP: cannot allocate memory to store device "
- "info.\n");
- result = -ENOMEM;
- goto error_parse;
- }
- nb_info = neighbor->info;
- result = wlp_get_dev_name(wlp, ptr + used, nb_info->name,
- len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain Device Name from D2 "
- "message.\n");
- goto error_parse;
- }
- used += result;
- result = wlp_get_variable_info(wlp, ptr + used, nb_info, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain Device Information from "
- "D2 message.\n");
- goto error_parse;
- }
- used += result;
- result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain WLP Association Error "
- "Information from D2 message.\n");
- goto error_parse;
- }
- if (assc_err != WLP_ASSOC_ERROR_NONE) {
- dev_err(dev, "WLP: neighbor device returned association "
- "error %d\n", assc_err);
- result = -EINVAL;
- goto error_parse;
- }
- result = 0;
-error_parse:
- if (result < 0)
- wlp_remove_neighbor_tmp_info(neighbor);
- return result;
-}
-
-/**
- * Parse incoming D2 frame, populate attribute values of WSS bein enrolled in
- *
- * @wss: our WSS that will be enrolled
- * @skb: socket buffer in which D2 frame can be found
- * @neighbor: the neighbor that sent the D2 frame
- * @wssid: the wssid of the WSS in which we want to enroll
- *
- * Forms part of enrollment sequence. We are trying to enroll in WSS with
- * @wssid by using @neighbor as registrar. A D1 message was sent to
- * @neighbor and now we need to parse the D2 response. The neighbor's
- * response is searched for the requested WSS and if found (and it accepts
- * enrollment), we store the information.
- */
-int wlp_parse_d2_frame_to_enroll(struct wlp_wss *wss, struct sk_buff *skb,
- struct wlp_neighbor_e *neighbor,
- struct wlp_uuid *wssid)
-{
- struct wlp *wlp = container_of(wss, struct wlp, wss);
- struct device *dev = &wlp->rc->uwb_dev.dev;
- void *ptr = skb->data;
- size_t len = skb->len;
- size_t used;
- ssize_t result;
- struct wlp_uuid uuid_e;
- struct wlp_uuid uuid_r;
- struct wlp_device_info nb_info;
- enum wlp_assc_error assc_err;
- char uuid_bufA[WLP_WSS_UUID_STRSIZE];
- char uuid_bufB[WLP_WSS_UUID_STRSIZE];
-
- used = sizeof(struct wlp_frame_assoc);
- result = wlp_get_uuid_e(wlp, ptr + used, &uuid_e, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain UUID-E attribute from D2 "
- "message.\n");
- goto error_parse;
- }
- if (memcmp(&uuid_e, &wlp->uuid, sizeof(uuid_e))) {
- dev_err(dev, "WLP: UUID-E in incoming D2 does not match "
- "local UUID sent in D1. \n");
- goto error_parse;
- }
- used += result;
- result = wlp_get_uuid_r(wlp, ptr + used, &uuid_r, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain UUID-R attribute from D2 "
- "message.\n");
- goto error_parse;
- }
- if (memcmp(&uuid_r, &neighbor->uuid, sizeof(uuid_r))) {
- wlp_wss_uuid_print(uuid_bufA, sizeof(uuid_bufA),
- &neighbor->uuid);
- wlp_wss_uuid_print(uuid_bufB, sizeof(uuid_bufB), &uuid_r);
- dev_err(dev, "WLP: UUID of neighbor does not match UUID "
- "learned during discovery. Originally discovered: %s, "
- "now from D2 message: %s\n", uuid_bufA, uuid_bufB);
- result = -EINVAL;
- goto error_parse;
- }
- used += result;
- wss->wssid = *wssid;
- result = wlp_get_wss_info_to_enroll(wlp, ptr + used, wss, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain WSS information "
- "from D2 message.\n");
- goto error_parse;
- }
- if (wss->state != WLP_WSS_STATE_PART_ENROLLED) {
- dev_err(dev, "WLP: D2 message did not contain information "
- "for successful enrollment. \n");
- result = -EINVAL;
- goto error_parse;
- }
- used += result;
- /* Place device information on stack to continue parsing of message */
- result = wlp_get_dev_name(wlp, ptr + used, nb_info.name,
- len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain Device Name from D2 "
- "message.\n");
- goto error_parse;
- }
- used += result;
- result = wlp_get_variable_info(wlp, ptr + used, &nb_info, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain Device Information from "
- "D2 message.\n");
- goto error_parse;
- }
- used += result;
- result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain WLP Association Error "
- "Information from D2 message.\n");
- goto error_parse;
- }
- if (assc_err != WLP_ASSOC_ERROR_NONE) {
- dev_err(dev, "WLP: neighbor device returned association "
- "error %d\n", assc_err);
- if (wss->state == WLP_WSS_STATE_PART_ENROLLED) {
- dev_err(dev, "WLP: Enrolled in WSS (should not "
- "happen according to spec). Undoing. \n");
- wlp_wss_reset(wss);
- }
- result = -EINVAL;
- goto error_parse;
- }
- result = 0;
-error_parse:
- return result;
-}
-
-/**
- * Parse C3/C4 frame into provided variables
- *
- * @wssid: will point to copy of wssid retrieved from C3/C4 frame
- * @tag: will point to copy of tag retrieved from C3/C4 frame
- * @virt_addr: will point to copy of virtual address retrieved from C3/C4
- * frame.
- *
- * Calling function has to allocate memory for these values.
- *
- * skb contains a valid C3/C4 frame, return the individual fields of this
- * frame in the provided variables.
- */
-int wlp_parse_c3c4_frame(struct wlp *wlp, struct sk_buff *skb,
- struct wlp_uuid *wssid, u8 *tag,
- struct uwb_mac_addr *virt_addr)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- int result;
- void *ptr = skb->data;
- size_t len = skb->len;
- size_t used;
- struct wlp_frame_assoc *assoc = ptr;
-
- used = sizeof(*assoc);
- result = wlp_get_wssid(wlp, ptr + used, wssid, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain WSSID attribute from "
- "%s message.\n", wlp_assoc_frame_str(assoc->type));
- goto error_parse;
- }
- used += result;
- result = wlp_get_wss_tag(wlp, ptr + used, tag, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain WSS tag attribute from "
- "%s message.\n", wlp_assoc_frame_str(assoc->type));
- goto error_parse;
- }
- used += result;
- result = wlp_get_wss_virt(wlp, ptr + used, virt_addr, len - used);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain WSS virtual address "
- "attribute from %s message.\n",
- wlp_assoc_frame_str(assoc->type));
- goto error_parse;
- }
-error_parse:
- return result;
-}
-
-/**
- * Allocate memory for and populate fields of C1 or C2 association frame
- *
- * The C1 and C2 association frames appear identical - except for the type.
- */
-static
-int wlp_build_assoc_c1c2(struct wlp *wlp, struct wlp_wss *wss,
- struct sk_buff **skb, enum wlp_assoc_type type)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- int result = -ENOMEM;
- struct {
- struct wlp_frame_assoc c_hdr;
- struct wlp_attr_wssid wssid;
- } *c;
- struct sk_buff *_skb;
-
- _skb = dev_alloc_skb(sizeof(*c));
- if (_skb == NULL) {
- dev_err(dev, "WLP: Unable to allocate memory for C1/C2 "
- "association frame. \n");
- goto error_alloc;
- }
- c = (void *) _skb->data;
- c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
- c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION;
- c->c_hdr.type = type;
- wlp_set_version(&c->c_hdr.version, WLP_VERSION);
- wlp_set_msg_type(&c->c_hdr.msg_type, type);
- wlp_set_wssid(&c->wssid, &wss->wssid);
- skb_put(_skb, sizeof(*c));
- *skb = _skb;
- result = 0;
-error_alloc:
- return result;
-}
-
-
-static
-int wlp_build_assoc_c1(struct wlp *wlp, struct wlp_wss *wss,
- struct sk_buff **skb)
-{
- return wlp_build_assoc_c1c2(wlp, wss, skb, WLP_ASSOC_C1);
-}
-
-static
-int wlp_build_assoc_c2(struct wlp *wlp, struct wlp_wss *wss,
- struct sk_buff **skb)
-{
- return wlp_build_assoc_c1c2(wlp, wss, skb, WLP_ASSOC_C2);
-}
-
-
-/**
- * Allocate memory for and populate fields of C3 or C4 association frame
- *
- * The C3 and C4 association frames appear identical - except for the type.
- */
-static
-int wlp_build_assoc_c3c4(struct wlp *wlp, struct wlp_wss *wss,
- struct sk_buff **skb, enum wlp_assoc_type type)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- int result = -ENOMEM;
- struct {
- struct wlp_frame_assoc c_hdr;
- struct wlp_attr_wssid wssid;
- struct wlp_attr_wss_tag wss_tag;
- struct wlp_attr_wss_virt wss_virt;
- } *c;
- struct sk_buff *_skb;
-
- _skb = dev_alloc_skb(sizeof(*c));
- if (_skb == NULL) {
- dev_err(dev, "WLP: Unable to allocate memory for C3/C4 "
- "association frame. \n");
- goto error_alloc;
- }
- c = (void *) _skb->data;
- c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
- c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION;
- c->c_hdr.type = type;
- wlp_set_version(&c->c_hdr.version, WLP_VERSION);
- wlp_set_msg_type(&c->c_hdr.msg_type, type);
- wlp_set_wssid(&c->wssid, &wss->wssid);
- wlp_set_wss_tag(&c->wss_tag, wss->tag);
- wlp_set_wss_virt(&c->wss_virt, &wss->virtual_addr);
- skb_put(_skb, sizeof(*c));
- *skb = _skb;
- result = 0;
-error_alloc:
- return result;
-}
-
-static
-int wlp_build_assoc_c3(struct wlp *wlp, struct wlp_wss *wss,
- struct sk_buff **skb)
-{
- return wlp_build_assoc_c3c4(wlp, wss, skb, WLP_ASSOC_C3);
-}
-
-static
-int wlp_build_assoc_c4(struct wlp *wlp, struct wlp_wss *wss,
- struct sk_buff **skb)
-{
- return wlp_build_assoc_c3c4(wlp, wss, skb, WLP_ASSOC_C4);
-}
-
-
-#define wlp_send_assoc(type, id) \
-static int wlp_send_assoc_##type(struct wlp *wlp, struct wlp_wss *wss, \
- struct uwb_dev_addr *dev_addr) \
-{ \
- struct device *dev = &wlp->rc->uwb_dev.dev; \
- int result; \
- struct sk_buff *skb = NULL; \
- \
- /* Build the frame */ \
- result = wlp_build_assoc_##type(wlp, wss, &skb); \
- if (result < 0) { \
- dev_err(dev, "WLP: Unable to construct %s association " \
- "frame: %d\n", wlp_assoc_frame_str(id), result);\
- goto error_build_assoc; \
- } \
- /* Send the frame */ \
- BUG_ON(wlp->xmit_frame == NULL); \
- result = wlp->xmit_frame(wlp, skb, dev_addr); \
- if (result < 0) { \
- dev_err(dev, "WLP: Unable to transmit %s association " \
- "message: %d\n", wlp_assoc_frame_str(id), \
- result); \
- if (result == -ENXIO) \
- dev_err(dev, "WLP: Is network interface " \
- "up? \n"); \
- goto error_xmit; \
- } \
- return 0; \
-error_xmit: \
- /* We could try again ... */ \
- dev_kfree_skb_any(skb);/*we need to free if tx fails*/ \
-error_build_assoc: \
- return result; \
-}
-
-wlp_send_assoc(d1, WLP_ASSOC_D1)
-wlp_send_assoc(c1, WLP_ASSOC_C1)
-wlp_send_assoc(c3, WLP_ASSOC_C3)
-
-int wlp_send_assoc_frame(struct wlp *wlp, struct wlp_wss *wss,
- struct uwb_dev_addr *dev_addr,
- enum wlp_assoc_type type)
-{
- int result = 0;
- struct device *dev = &wlp->rc->uwb_dev.dev;
- switch (type) {
- case WLP_ASSOC_D1:
- result = wlp_send_assoc_d1(wlp, wss, dev_addr);
- break;
- case WLP_ASSOC_C1:
- result = wlp_send_assoc_c1(wlp, wss, dev_addr);
- break;
- case WLP_ASSOC_C3:
- result = wlp_send_assoc_c3(wlp, wss, dev_addr);
- break;
- default:
- dev_err(dev, "WLP: Received request to send unknown "
- "association message.\n");
- result = -EINVAL;
- break;
- }
- return result;
-}
-
-/**
- * Handle incoming C1 frame
- *
- * The frame has already been verified to contain an Association header with
- * the correct version number. Parse the incoming frame, construct and send
- * a C2 frame in response.
- */
-void wlp_handle_c1_frame(struct work_struct *ws)
-{
- struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws,
- struct wlp_assoc_frame_ctx,
- ws);
- struct wlp *wlp = frame_ctx->wlp;
- struct wlp_wss *wss = &wlp->wss;
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct wlp_frame_assoc *c1 = (void *) frame_ctx->skb->data;
- unsigned int len = frame_ctx->skb->len;
- struct uwb_dev_addr *src = &frame_ctx->src;
- int result;
- struct wlp_uuid wssid;
- struct sk_buff *resp = NULL;
-
- /* Parse C1 frame */
- mutex_lock(&wss->mutex);
- result = wlp_get_wssid(wlp, (void *)c1 + sizeof(*c1), &wssid,
- len - sizeof(*c1));
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain WSSID from C1 frame.\n");
- goto out;
- }
- if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))
- && wss->state == WLP_WSS_STATE_ACTIVE) {
- /* Construct C2 frame */
- result = wlp_build_assoc_c2(wlp, wss, &resp);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to construct C2 message.\n");
- goto out;
- }
- } else {
- /* Construct F0 frame */
- result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to construct F0 message.\n");
- goto out;
- }
- }
- /* Send C2 frame */
- BUG_ON(wlp->xmit_frame == NULL);
- result = wlp->xmit_frame(wlp, resp, src);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to transmit response association "
- "message: %d\n", result);
- if (result == -ENXIO)
- dev_err(dev, "WLP: Is network interface up? \n");
- /* We could try again ... */
- dev_kfree_skb_any(resp); /* we need to free if tx fails */
- }
-out:
- kfree_skb(frame_ctx->skb);
- kfree(frame_ctx);
- mutex_unlock(&wss->mutex);
-}
-
-/**
- * Handle incoming C3 frame
- *
- * The frame has already been verified to contain an Association header with
- * the correct version number. Parse the incoming frame, construct and send
- * a C4 frame in response. If the C3 frame identifies a WSS that is locally
- * active then we connect to this neighbor (add it to our EDA cache).
- */
-void wlp_handle_c3_frame(struct work_struct *ws)
-{
- struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws,
- struct wlp_assoc_frame_ctx,
- ws);
- struct wlp *wlp = frame_ctx->wlp;
- struct wlp_wss *wss = &wlp->wss;
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct sk_buff *skb = frame_ctx->skb;
- struct uwb_dev_addr *src = &frame_ctx->src;
- int result;
- struct sk_buff *resp = NULL;
- struct wlp_uuid wssid;
- u8 tag;
- struct uwb_mac_addr virt_addr;
-
- /* Parse C3 frame */
- mutex_lock(&wss->mutex);
- result = wlp_parse_c3c4_frame(wlp, skb, &wssid, &tag, &virt_addr);
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain values from C3 frame.\n");
- goto out;
- }
- if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))
- && wss->state >= WLP_WSS_STATE_ACTIVE) {
- result = wlp_eda_update_node(&wlp->eda, src, wss,
- (void *) virt_addr.data, tag,
- WLP_WSS_CONNECTED);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to update EDA cache "
- "with new connected neighbor information.\n");
- result = wlp_build_assoc_f0(wlp, &resp,
- WLP_ASSOC_ERROR_INT);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to construct F0 "
- "message.\n");
- goto out;
- }
- } else {
- wss->state = WLP_WSS_STATE_CONNECTED;
- /* Construct C4 frame */
- result = wlp_build_assoc_c4(wlp, wss, &resp);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to construct C4 "
- "message.\n");
- goto out;
- }
- }
- } else {
- /* Construct F0 frame */
- result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to construct F0 message.\n");
- goto out;
- }
- }
- /* Send C4 frame */
- BUG_ON(wlp->xmit_frame == NULL);
- result = wlp->xmit_frame(wlp, resp, src);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to transmit response association "
- "message: %d\n", result);
- if (result == -ENXIO)
- dev_err(dev, "WLP: Is network interface up? \n");
- /* We could try again ... */
- dev_kfree_skb_any(resp); /* we need to free if tx fails */
- }
-out:
- kfree_skb(frame_ctx->skb);
- kfree(frame_ctx);
- mutex_unlock(&wss->mutex);
-}
-
-
diff --git a/drivers/uwb/wlp/sysfs.c b/drivers/uwb/wlp/sysfs.c
deleted file mode 100644
index 6627c94cc854..000000000000
--- a/drivers/uwb/wlp/sysfs.c
+++ /dev/null
@@ -1,708 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- * sysfs functions
- *
- * Copyright (C) 2007 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: Docs
- *
- */
-#include <linux/wlp.h>
-
-#include "wlp-internal.h"
-
-static
-size_t wlp_wss_wssid_e_print(char *buf, size_t bufsize,
- struct wlp_wssid_e *wssid_e)
-{
- size_t used = 0;
- used += scnprintf(buf, bufsize, " WSS: ");
- used += wlp_wss_uuid_print(buf + used, bufsize - used,
- &wssid_e->wssid);
-
- if (wssid_e->info != NULL) {
- used += scnprintf(buf + used, bufsize - used, " ");
- used += uwb_mac_addr_print(buf + used, bufsize - used,
- &wssid_e->info->bcast);
- used += scnprintf(buf + used, bufsize - used, " %u %u %s\n",
- wssid_e->info->accept_enroll,
- wssid_e->info->sec_status,
- wssid_e->info->name);
- }
- return used;
-}
-
-/**
- * Print out information learned from neighbor discovery
- *
- * Some fields being printed may not be included in the device discovery
- * information (it is not mandatory). We are thus careful how the
- * information is printed to ensure it is clear to the user what field is
- * being referenced.
- * The information being printed is for one time use - temporary storage is
- * cleaned after it is printed.
- *
- * Ideally sysfs output should be on one line. The information printed here
- * contain a few strings so it will be hard to parse if they are all
- * printed on the same line - without agreeing on a standard field
- * separator.
- */
-static
-ssize_t wlp_wss_neighborhood_print_remove(struct wlp *wlp, char *buf,
- size_t bufsize)
-{
- size_t used = 0;
- struct wlp_neighbor_e *neighb;
- struct wlp_wssid_e *wssid_e;
-
- mutex_lock(&wlp->nbmutex);
- used = scnprintf(buf, bufsize, "#Neighbor information\n"
- "#uuid dev_addr\n"
- "# Device Name:\n# Model Name:\n# Manufacturer:\n"
- "# Model Nr:\n# Serial:\n"
- "# Pri Dev type: CategoryID OUI OUISubdiv "
- "SubcategoryID\n"
- "# WSS: WSSID WSS_name accept_enroll sec_status "
- "bcast\n"
- "# WSS: WSSID WSS_name accept_enroll sec_status "
- "bcast\n\n");
- list_for_each_entry(neighb, &wlp->neighbors, node) {
- if (bufsize - used <= 0)
- goto out;
- used += wlp_wss_uuid_print(buf + used, bufsize - used,
- &neighb->uuid);
- buf[used++] = ' ';
- used += uwb_dev_addr_print(buf + used, bufsize - used,
- &neighb->uwb_dev->dev_addr);
- if (neighb->info != NULL)
- used += scnprintf(buf + used, bufsize - used,
- "\n Device Name: %s\n"
- " Model Name: %s\n"
- " Manufacturer:%s \n"
- " Model Nr: %s\n"
- " Serial: %s\n"
- " Pri Dev type: "
- "%u %02x:%02x:%02x %u %u\n",
- neighb->info->name,
- neighb->info->model_name,
- neighb->info->manufacturer,
- neighb->info->model_nr,
- neighb->info->serial,
- neighb->info->prim_dev_type.category,
- neighb->info->prim_dev_type.OUI[0],
- neighb->info->prim_dev_type.OUI[1],
- neighb->info->prim_dev_type.OUI[2],
- neighb->info->prim_dev_type.OUIsubdiv,
- neighb->info->prim_dev_type.subID);
- list_for_each_entry(wssid_e, &neighb->wssid, node) {
- used += wlp_wss_wssid_e_print(buf + used,
- bufsize - used,
- wssid_e);
- }
- buf[used++] = '\n';
- wlp_remove_neighbor_tmp_info(neighb);
- }
-
-
-out:
- mutex_unlock(&wlp->nbmutex);
- return used;
-}
-
-
-/**
- * Show properties of all WSS in neighborhood.
- *
- * Will trigger a complete discovery of WSS activated by this device and
- * its neighbors.
- */
-ssize_t wlp_neighborhood_show(struct wlp *wlp, char *buf)
-{
- wlp_discover(wlp);
- return wlp_wss_neighborhood_print_remove(wlp, buf, PAGE_SIZE);
-}
-EXPORT_SYMBOL_GPL(wlp_neighborhood_show);
-
-static
-ssize_t __wlp_wss_properties_show(struct wlp_wss *wss, char *buf,
- size_t bufsize)
-{
- ssize_t result;
-
- result = wlp_wss_uuid_print(buf, bufsize, &wss->wssid);
- result += scnprintf(buf + result, bufsize - result, " ");
- result += uwb_mac_addr_print(buf + result, bufsize - result,
- &wss->bcast);
- result += scnprintf(buf + result, bufsize - result,
- " 0x%02x %u ", wss->hash, wss->secure_status);
- result += wlp_wss_key_print(buf + result, bufsize - result,
- wss->master_key);
- result += scnprintf(buf + result, bufsize - result, " 0x%02x ",
- wss->tag);
- result += uwb_mac_addr_print(buf + result, bufsize - result,
- &wss->virtual_addr);
- result += scnprintf(buf + result, bufsize - result, " %s", wss->name);
- result += scnprintf(buf + result, bufsize - result,
- "\n\n#WSSID\n#WSS broadcast address\n"
- "#WSS hash\n#WSS secure status\n"
- "#WSS master key\n#WSS local tag\n"
- "#WSS local virtual EUI-48\n#WSS name\n");
- return result;
-}
-
-/**
- * Show which WSS is activated.
- */
-ssize_t wlp_wss_activate_show(struct wlp_wss *wss, char *buf)
-{
- int result = 0;
-
- if (mutex_lock_interruptible(&wss->mutex))
- goto out;
- if (wss->state >= WLP_WSS_STATE_ACTIVE)
- result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE);
- else
- result = scnprintf(buf, PAGE_SIZE, "No local WSS active.\n");
- result += scnprintf(buf + result, PAGE_SIZE - result,
- "\n\n"
- "# echo WSSID SECURE_STATUS ACCEPT_ENROLLMENT "
- "NAME #create new WSS\n"
- "# echo WSSID [DEV ADDR] #enroll in and activate "
- "existing WSS, can request registrar\n"
- "#\n"
- "# WSSID is a 16 byte hex array. Eg. 12 A3 3B ... \n"
- "# SECURE_STATUS 0 - unsecure, 1 - secure (default)\n"
- "# ACCEPT_ENROLLMENT 0 - no, 1 - yes (default)\n"
- "# NAME is the text string identifying the WSS\n"
- "# DEV ADDR is the device address of neighbor "
- "that should be registrar. Eg. 32:AB\n");
-
- mutex_unlock(&wss->mutex);
-out:
- return result;
-
-}
-EXPORT_SYMBOL_GPL(wlp_wss_activate_show);
-
-/**
- * Create/activate a new WSS or enroll/activate in neighboring WSS
- *
- * The user can provide the WSSID of a WSS in which it wants to enroll.
- * Only the WSSID is necessary if the WSS have been discovered before. If
- * the WSS has not been discovered before, or the user wants to use a
- * particular neighbor as its registrar, then the user can also provide a
- * device address or the neighbor that will be used as registrar.
- *
- * A new WSS is created when the user provides a WSSID, secure status, and
- * WSS name.
- */
-ssize_t wlp_wss_activate_store(struct wlp_wss *wss,
- const char *buf, size_t size)
-{
- ssize_t result = -EINVAL;
- struct wlp_uuid wssid;
- struct uwb_dev_addr dev;
- struct uwb_dev_addr bcast = {.data = {0xff, 0xff} };
- char name[65];
- unsigned sec_status, accept;
- memset(name, 0, sizeof(name));
- result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
- "%02hhx %02hhx %02hhx %02hhx "
- "%02hhx %02hhx %02hhx %02hhx "
- "%02hhx %02hhx %02hhx %02hhx "
- "%02hhx:%02hhx",
- &wssid.data[0] , &wssid.data[1],
- &wssid.data[2] , &wssid.data[3],
- &wssid.data[4] , &wssid.data[5],
- &wssid.data[6] , &wssid.data[7],
- &wssid.data[8] , &wssid.data[9],
- &wssid.data[10], &wssid.data[11],
- &wssid.data[12], &wssid.data[13],
- &wssid.data[14], &wssid.data[15],
- &dev.data[1], &dev.data[0]);
- if (result == 16 || result == 17) {
- result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
- "%02hhx %02hhx %02hhx %02hhx "
- "%02hhx %02hhx %02hhx %02hhx "
- "%02hhx %02hhx %02hhx %02hhx "
- "%u %u %64c",
- &wssid.data[0] , &wssid.data[1],
- &wssid.data[2] , &wssid.data[3],
- &wssid.data[4] , &wssid.data[5],
- &wssid.data[6] , &wssid.data[7],
- &wssid.data[8] , &wssid.data[9],
- &wssid.data[10], &wssid.data[11],
- &wssid.data[12], &wssid.data[13],
- &wssid.data[14], &wssid.data[15],
- &sec_status, &accept, name);
- if (result == 16)
- result = wlp_wss_enroll_activate(wss, &wssid, &bcast);
- else if (result == 19) {
- sec_status = sec_status == 0 ? 0 : 1;
- accept = accept == 0 ? 0 : 1;
- /* We read name using %c, so the newline needs to be
- * removed */
- if (strlen(name) != sizeof(name) - 1)
- name[strlen(name) - 1] = '\0';
- result = wlp_wss_create_activate(wss, &wssid, name,
- sec_status, accept);
- } else
- result = -EINVAL;
- } else if (result == 18)
- result = wlp_wss_enroll_activate(wss, &wssid, &dev);
- else
- result = -EINVAL;
- return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(wlp_wss_activate_store);
-
-/**
- * Show the UUID of this host
- */
-ssize_t wlp_uuid_show(struct wlp *wlp, char *buf)
-{
- ssize_t result = 0;
-
- mutex_lock(&wlp->mutex);
- result = wlp_wss_uuid_print(buf, PAGE_SIZE, &wlp->uuid);
- buf[result++] = '\n';
- mutex_unlock(&wlp->mutex);
- return result;
-}
-EXPORT_SYMBOL_GPL(wlp_uuid_show);
-
-/**
- * Store a new UUID for this host
- *
- * According to the spec this should be encoded as an octet string in the
- * order the octets are shown in string representation in RFC 4122 (WLP
- * 0.99 [Table 6])
- *
- * We do not check value provided by user.
- */
-ssize_t wlp_uuid_store(struct wlp *wlp, const char *buf, size_t size)
-{
- ssize_t result;
- struct wlp_uuid uuid;
-
- mutex_lock(&wlp->mutex);
- result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
- "%02hhx %02hhx %02hhx %02hhx "
- "%02hhx %02hhx %02hhx %02hhx "
- "%02hhx %02hhx %02hhx %02hhx ",
- &uuid.data[0] , &uuid.data[1],
- &uuid.data[2] , &uuid.data[3],
- &uuid.data[4] , &uuid.data[5],
- &uuid.data[6] , &uuid.data[7],
- &uuid.data[8] , &uuid.data[9],
- &uuid.data[10], &uuid.data[11],
- &uuid.data[12], &uuid.data[13],
- &uuid.data[14], &uuid.data[15]);
- if (result != 16) {
- result = -EINVAL;
- goto error;
- }
- wlp->uuid = uuid;
-error:
- mutex_unlock(&wlp->mutex);
- return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(wlp_uuid_store);
-
-/**
- * Show contents of members of device information structure
- */
-#define wlp_dev_info_show(type) \
-ssize_t wlp_dev_##type##_show(struct wlp *wlp, char *buf) \
-{ \
- ssize_t result = 0; \
- mutex_lock(&wlp->mutex); \
- if (wlp->dev_info == NULL) { \
- result = __wlp_setup_device_info(wlp); \
- if (result < 0) \
- goto out; \
- } \
- result = scnprintf(buf, PAGE_SIZE, "%s\n", wlp->dev_info->type);\
-out: \
- mutex_unlock(&wlp->mutex); \
- return result; \
-} \
-EXPORT_SYMBOL_GPL(wlp_dev_##type##_show);
-
-wlp_dev_info_show(name)
-wlp_dev_info_show(model_name)
-wlp_dev_info_show(model_nr)
-wlp_dev_info_show(manufacturer)
-wlp_dev_info_show(serial)
-
-/**
- * Store contents of members of device information structure
- */
-#define wlp_dev_info_store(type, len) \
-ssize_t wlp_dev_##type##_store(struct wlp *wlp, const char *buf, size_t size)\
-{ \
- ssize_t result; \
- char format[10]; \
- mutex_lock(&wlp->mutex); \
- if (wlp->dev_info == NULL) { \
- result = __wlp_alloc_device_info(wlp); \
- if (result < 0) \
- goto out; \
- } \
- memset(wlp->dev_info->type, 0, sizeof(wlp->dev_info->type)); \
- sprintf(format, "%%%uc", len); \
- result = sscanf(buf, format, wlp->dev_info->type); \
-out: \
- mutex_unlock(&wlp->mutex); \
- return result < 0 ? result : size; \
-} \
-EXPORT_SYMBOL_GPL(wlp_dev_##type##_store);
-
-wlp_dev_info_store(name, 32)
-wlp_dev_info_store(manufacturer, 64)
-wlp_dev_info_store(model_name, 32)
-wlp_dev_info_store(model_nr, 32)
-wlp_dev_info_store(serial, 32)
-
-static
-const char *__wlp_dev_category[] = {
- [WLP_DEV_CAT_COMPUTER] = "Computer",
- [WLP_DEV_CAT_INPUT] = "Input device",
- [WLP_DEV_CAT_PRINT_SCAN_FAX_COPIER] = "Printer, scanner, FAX, or "
- "Copier",
- [WLP_DEV_CAT_CAMERA] = "Camera",
- [WLP_DEV_CAT_STORAGE] = "Storage Network",
- [WLP_DEV_CAT_INFRASTRUCTURE] = "Infrastructure",
- [WLP_DEV_CAT_DISPLAY] = "Display",
- [WLP_DEV_CAT_MULTIM] = "Multimedia device",
- [WLP_DEV_CAT_GAMING] = "Gaming device",
- [WLP_DEV_CAT_TELEPHONE] = "Telephone",
- [WLP_DEV_CAT_OTHER] = "Other",
-};
-
-static
-const char *wlp_dev_category_str(unsigned cat)
-{
- if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE)
- || cat == WLP_DEV_CAT_OTHER)
- return __wlp_dev_category[cat];
- return "unknown category";
-}
-
-ssize_t wlp_dev_prim_category_show(struct wlp *wlp, char *buf)
-{
- ssize_t result = 0;
- mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
- result = __wlp_setup_device_info(wlp);
- if (result < 0)
- goto out;
- }
- result = scnprintf(buf, PAGE_SIZE, "%s\n",
- wlp_dev_category_str(wlp->dev_info->prim_dev_type.category));
-out:
- mutex_unlock(&wlp->mutex);
- return result;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_category_show);
-
-ssize_t wlp_dev_prim_category_store(struct wlp *wlp, const char *buf,
- size_t size)
-{
- ssize_t result;
- u16 cat;
- mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
- result = __wlp_alloc_device_info(wlp);
- if (result < 0)
- goto out;
- }
- result = sscanf(buf, "%hu", &cat);
- if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE)
- || cat == WLP_DEV_CAT_OTHER)
- wlp->dev_info->prim_dev_type.category = cat;
- else
- result = -EINVAL;
-out:
- mutex_unlock(&wlp->mutex);
- return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_category_store);
-
-ssize_t wlp_dev_prim_OUI_show(struct wlp *wlp, char *buf)
-{
- ssize_t result = 0;
- mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
- result = __wlp_setup_device_info(wlp);
- if (result < 0)
- goto out;
- }
- result = scnprintf(buf, PAGE_SIZE, "%02x:%02x:%02x\n",
- wlp->dev_info->prim_dev_type.OUI[0],
- wlp->dev_info->prim_dev_type.OUI[1],
- wlp->dev_info->prim_dev_type.OUI[2]);
-out:
- mutex_unlock(&wlp->mutex);
- return result;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_show);
-
-ssize_t wlp_dev_prim_OUI_store(struct wlp *wlp, const char *buf, size_t size)
-{
- ssize_t result;
- u8 OUI[3];
- mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
- result = __wlp_alloc_device_info(wlp);
- if (result < 0)
- goto out;
- }
- result = sscanf(buf, "%hhx:%hhx:%hhx",
- &OUI[0], &OUI[1], &OUI[2]);
- if (result != 3) {
- result = -EINVAL;
- goto out;
- } else
- memcpy(wlp->dev_info->prim_dev_type.OUI, OUI, sizeof(OUI));
-out:
- mutex_unlock(&wlp->mutex);
- return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_store);
-
-
-ssize_t wlp_dev_prim_OUI_sub_show(struct wlp *wlp, char *buf)
-{
- ssize_t result = 0;
- mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
- result = __wlp_setup_device_info(wlp);
- if (result < 0)
- goto out;
- }
- result = scnprintf(buf, PAGE_SIZE, "%u\n",
- wlp->dev_info->prim_dev_type.OUIsubdiv);
-out:
- mutex_unlock(&wlp->mutex);
- return result;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_show);
-
-ssize_t wlp_dev_prim_OUI_sub_store(struct wlp *wlp, const char *buf,
- size_t size)
-{
- ssize_t result;
- unsigned sub;
- u8 max_sub = ~0;
- mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
- result = __wlp_alloc_device_info(wlp);
- if (result < 0)
- goto out;
- }
- result = sscanf(buf, "%u", &sub);
- if (sub <= max_sub)
- wlp->dev_info->prim_dev_type.OUIsubdiv = sub;
- else
- result = -EINVAL;
-out:
- mutex_unlock(&wlp->mutex);
- return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_store);
-
-ssize_t wlp_dev_prim_subcat_show(struct wlp *wlp, char *buf)
-{
- ssize_t result = 0;
- mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
- result = __wlp_setup_device_info(wlp);
- if (result < 0)
- goto out;
- }
- result = scnprintf(buf, PAGE_SIZE, "%u\n",
- wlp->dev_info->prim_dev_type.subID);
-out:
- mutex_unlock(&wlp->mutex);
- return result;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_show);
-
-ssize_t wlp_dev_prim_subcat_store(struct wlp *wlp, const char *buf,
- size_t size)
-{
- ssize_t result;
- unsigned sub;
- __le16 max_sub = ~0;
- mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
- result = __wlp_alloc_device_info(wlp);
- if (result < 0)
- goto out;
- }
- result = sscanf(buf, "%u", &sub);
- if (sub <= max_sub)
- wlp->dev_info->prim_dev_type.subID = sub;
- else
- result = -EINVAL;
-out:
- mutex_unlock(&wlp->mutex);
- return result < 0 ? result : size;
-}
-EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_store);
-
-/**
- * Subsystem implementation for interaction with individual WSS via sysfs
- *
- * Followed instructions for subsystem in Documentation/filesystems/sysfs.txt
- */
-
-#define kobj_to_wlp_wss(obj) container_of(obj, struct wlp_wss, kobj)
-#define attr_to_wlp_wss_attr(_attr) \
- container_of(_attr, struct wlp_wss_attribute, attr)
-
-/**
- * Sysfs subsystem: forward read calls
- *
- * Sysfs operation for forwarding read call to the show method of the
- * attribute owner
- */
-static
-ssize_t wlp_wss_attr_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
-{
- struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr);
- struct wlp_wss *wss = kobj_to_wlp_wss(kobj);
- ssize_t ret = -EIO;
-
- if (wss_attr->show)
- ret = wss_attr->show(wss, buf);
- return ret;
-}
-/**
- * Sysfs subsystem: forward write calls
- *
- * Sysfs operation for forwarding write call to the store method of the
- * attribute owner
- */
-static
-ssize_t wlp_wss_attr_store(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr);
- struct wlp_wss *wss = kobj_to_wlp_wss(kobj);
- ssize_t ret = -EIO;
-
- if (wss_attr->store)
- ret = wss_attr->store(wss, buf, count);
- return ret;
-}
-
-static const struct sysfs_ops wss_sysfs_ops = {
- .show = wlp_wss_attr_show,
- .store = wlp_wss_attr_store,
-};
-
-struct kobj_type wss_ktype = {
- .release = wlp_wss_release,
- .sysfs_ops = &wss_sysfs_ops,
-};
-
-
-/**
- * Sysfs files for individual WSS
- */
-
-/**
- * Print static properties of this WSS
- *
- * The name of a WSS may not be null teminated. It's max size is 64 bytes
- * so we copy it to a larger array just to make sure we print sane data.
- */
-static ssize_t wlp_wss_properties_show(struct wlp_wss *wss, char *buf)
-{
- int result = 0;
-
- if (mutex_lock_interruptible(&wss->mutex))
- goto out;
- result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE);
- mutex_unlock(&wss->mutex);
-out:
- return result;
-}
-WSS_ATTR(properties, S_IRUGO, wlp_wss_properties_show, NULL);
-
-/**
- * Print all connected members of this WSS
- * The EDA cache contains all members of WSS neighborhood.
- */
-static ssize_t wlp_wss_members_show(struct wlp_wss *wss, char *buf)
-{
- struct wlp *wlp = container_of(wss, struct wlp, wss);
- return wlp_eda_show(wlp, buf);
-}
-WSS_ATTR(members, S_IRUGO, wlp_wss_members_show, NULL);
-
-static
-const char *__wlp_strstate[] = {
- "none",
- "partially enrolled",
- "enrolled",
- "active",
- "connected",
-};
-
-static const char *wlp_wss_strstate(unsigned state)
-{
- if (state >= ARRAY_SIZE(__wlp_strstate))
- return "unknown state";
- return __wlp_strstate[state];
-}
-
-/*
- * Print current state of this WSS
- */
-static ssize_t wlp_wss_state_show(struct wlp_wss *wss, char *buf)
-{
- int result = 0;
-
- if (mutex_lock_interruptible(&wss->mutex))
- goto out;
- result = scnprintf(buf, PAGE_SIZE, "%s\n",
- wlp_wss_strstate(wss->state));
- mutex_unlock(&wss->mutex);
-out:
- return result;
-}
-WSS_ATTR(state, S_IRUGO, wlp_wss_state_show, NULL);
-
-
-static
-struct attribute *wss_attrs[] = {
- &wss_attr_properties.attr,
- &wss_attr_members.attr,
- &wss_attr_state.attr,
- NULL,
-};
-
-struct attribute_group wss_attr_group = {
- .name = NULL, /* we want them in the same directory */
- .attrs = wss_attrs,
-};
diff --git a/drivers/uwb/wlp/txrx.c b/drivers/uwb/wlp/txrx.c
deleted file mode 100644
index 05dde44b3592..000000000000
--- a/drivers/uwb/wlp/txrx.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- * Message exchange infrastructure
- *
- * Copyright (C) 2007 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: Docs
- *
- */
-
-#include <linux/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/wlp.h>
-
-#include "wlp-internal.h"
-
-/*
- * Direct incoming association msg to correct parsing routine
- *
- * We only expect D1, E1, C1, C3 messages as new. All other incoming
- * association messages should form part of an established session that is
- * handled elsewhere.
- * The handling of these messages often require calling sleeping functions
- * - this cannot be done in interrupt context. We use the kernel's
- * workqueue to handle these messages.
- */
-static
-void wlp_direct_assoc_frame(struct wlp *wlp, struct sk_buff *skb,
- struct uwb_dev_addr *src)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct wlp_frame_assoc *assoc = (void *) skb->data;
- struct wlp_assoc_frame_ctx *frame_ctx;
-
- frame_ctx = kmalloc(sizeof(*frame_ctx), GFP_ATOMIC);
- if (frame_ctx == NULL) {
- dev_err(dev, "WLP: Unable to allocate memory for association "
- "frame handling.\n");
- kfree_skb(skb);
- return;
- }
- frame_ctx->wlp = wlp;
- frame_ctx->skb = skb;
- frame_ctx->src = *src;
- switch (assoc->type) {
- case WLP_ASSOC_D1:
- INIT_WORK(&frame_ctx->ws, wlp_handle_d1_frame);
- schedule_work(&frame_ctx->ws);
- break;
- case WLP_ASSOC_E1:
- kfree_skb(skb); /* Temporary until we handle it */
- kfree(frame_ctx); /* Temporary until we handle it */
- break;
- case WLP_ASSOC_C1:
- INIT_WORK(&frame_ctx->ws, wlp_handle_c1_frame);
- schedule_work(&frame_ctx->ws);
- break;
- case WLP_ASSOC_C3:
- INIT_WORK(&frame_ctx->ws, wlp_handle_c3_frame);
- schedule_work(&frame_ctx->ws);
- break;
- default:
- dev_err(dev, "Received unexpected association frame. "
- "Type = %d \n", assoc->type);
- kfree_skb(skb);
- kfree(frame_ctx);
- break;
- }
-}
-
-/*
- * Process incoming association frame
- *
- * Although it could be possible to deal with some incoming association
- * messages without creating a new session we are keeping things simple. We
- * do not accept new association messages if there is a session in progress
- * and the messages do not belong to that session.
- *
- * If an association message arrives that causes the creation of a session
- * (WLP_ASSOC_E1) while we are in the process of creating a session then we
- * rely on the neighbor mutex to protect the data. That is, the new session
- * will not be started until the previous is completed.
- */
-static
-void wlp_receive_assoc_frame(struct wlp *wlp, struct sk_buff *skb,
- struct uwb_dev_addr *src)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct wlp_frame_assoc *assoc = (void *) skb->data;
- struct wlp_session *session = wlp->session;
- u8 version;
-
- if (wlp_get_version(wlp, &assoc->version, &version,
- sizeof(assoc->version)) < 0)
- goto error;
- if (version != WLP_VERSION) {
- dev_err(dev, "Unsupported WLP version in association "
- "message.\n");
- goto error;
- }
- if (session != NULL) {
- /* Function that created this session is still holding the
- * &wlp->mutex to protect this session. */
- if (assoc->type == session->exp_message ||
- assoc->type == WLP_ASSOC_F0) {
- if (!memcmp(&session->neighbor_addr, src,
- sizeof(*src))) {
- session->data = skb;
- (session->cb)(wlp);
- } else {
- dev_err(dev, "Received expected message from "
- "unexpected source. Expected message "
- "%d or F0 from %02x:%02x, but received "
- "it from %02x:%02x. Dropping.\n",
- session->exp_message,
- session->neighbor_addr.data[1],
- session->neighbor_addr.data[0],
- src->data[1], src->data[0]);
- goto error;
- }
- } else {
- dev_err(dev, "Association already in progress. "
- "Dropping.\n");
- goto error;
- }
- } else {
- wlp_direct_assoc_frame(wlp, skb, src);
- }
- return;
-error:
- kfree_skb(skb);
-}
-
-/*
- * Verify incoming frame is from connected neighbor, prep to pass to WLP client
- *
- * Verification proceeds according to WLP 0.99 [7.3.1]. The source address
- * is used to determine which neighbor is sending the frame and the WSS tag
- * is used to know to which WSS the frame belongs (we only support one WSS
- * so this test is straight forward).
- * With the WSS found we need to ensure that we are connected before
- * allowing the exchange of data frames.
- */
-static
-int wlp_verify_prep_rx_frame(struct wlp *wlp, struct sk_buff *skb,
- struct uwb_dev_addr *src)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- int result = -EINVAL;
- struct wlp_eda_node eda_entry;
- struct wlp_frame_std_abbrv_hdr *hdr = (void *) skb->data;
-
- /*verify*/
- result = wlp_copy_eda_node(&wlp->eda, src, &eda_entry);
- if (result < 0) {
- if (printk_ratelimit())
- dev_err(dev, "WLP: Incoming frame is from unknown "
- "neighbor %02x:%02x.\n", src->data[1],
- src->data[0]);
- goto out;
- }
- if (hdr->tag != eda_entry.tag) {
- if (printk_ratelimit())
- dev_err(dev, "WLP: Tag of incoming frame from "
- "%02x:%02x does not match expected tag. "
- "Received 0x%02x, expected 0x%02x. \n",
- src->data[1], src->data[0], hdr->tag,
- eda_entry.tag);
- result = -EINVAL;
- goto out;
- }
- if (eda_entry.state != WLP_WSS_CONNECTED) {
- if (printk_ratelimit())
- dev_err(dev, "WLP: Incoming frame from "
- "%02x:%02x does is not from connected WSS.\n",
- src->data[1], src->data[0]);
- result = -EINVAL;
- goto out;
- }
- /*prep*/
- skb_pull(skb, sizeof(*hdr));
-out:
- return result;
-}
-
-/*
- * Receive a WLP frame from device
- *
- * @returns: 1 if calling function should free the skb
- * 0 if it successfully handled skb and freed it
- * 0 if error occured, will free skb in this case
- */
-int wlp_receive_frame(struct device *dev, struct wlp *wlp, struct sk_buff *skb,
- struct uwb_dev_addr *src)
-{
- unsigned len = skb->len;
- void *ptr = skb->data;
- struct wlp_frame_hdr *hdr;
- int result = 0;
-
- if (len < sizeof(*hdr)) {
- dev_err(dev, "Not enough data to parse WLP header.\n");
- result = -EINVAL;
- goto out;
- }
- hdr = ptr;
- if (le16_to_cpu(hdr->mux_hdr) != WLP_PROTOCOL_ID) {
- dev_err(dev, "Not a WLP frame type.\n");
- result = -EINVAL;
- goto out;
- }
- switch (hdr->type) {
- case WLP_FRAME_STANDARD:
- if (len < sizeof(struct wlp_frame_std_abbrv_hdr)) {
- dev_err(dev, "Not enough data to parse Standard "
- "WLP header.\n");
- goto out;
- }
- result = wlp_verify_prep_rx_frame(wlp, skb, src);
- if (result < 0) {
- if (printk_ratelimit())
- dev_err(dev, "WLP: Verification of frame "
- "from neighbor %02x:%02x failed.\n",
- src->data[1], src->data[0]);
- goto out;
- }
- result = 1;
- break;
- case WLP_FRAME_ABBREVIATED:
- dev_err(dev, "Abbreviated frame received. FIXME?\n");
- kfree_skb(skb);
- break;
- case WLP_FRAME_CONTROL:
- dev_err(dev, "Control frame received. FIXME?\n");
- kfree_skb(skb);
- break;
- case WLP_FRAME_ASSOCIATION:
- if (len < sizeof(struct wlp_frame_assoc)) {
- dev_err(dev, "Not enough data to parse Association "
- "WLP header.\n");
- goto out;
- }
- wlp_receive_assoc_frame(wlp, skb, src);
- break;
- default:
- dev_err(dev, "Invalid frame received.\n");
- result = -EINVAL;
- break;
- }
-out:
- if (result < 0) {
- kfree_skb(skb);
- result = 0;
- }
- return result;
-}
-EXPORT_SYMBOL_GPL(wlp_receive_frame);
-
-
-/*
- * Verify frame from network stack, prepare for further transmission
- *
- * @skb: the socket buffer that needs to be prepared for transmission (it
- * is in need of a WLP header). If this is a broadcast frame we take
- * over the entire transmission.
- * If it is a unicast the WSS connection should already be established
- * and transmission will be done by the calling function.
- * @dst: On return this will contain the device address to which the
- * frame is destined.
- * @returns: 0 on success no tx : WLP header successfully applied to skb buffer,
- * calling function can proceed with tx
- * 1 on success with tx : WLP will take over transmission of this
- * frame
- * <0 on error
- *
- * The network stack (WLP client) is attempting to transmit a frame. We can
- * only transmit data if a local WSS is at least active (connection will be
- * done here if this is a broadcast frame and neighbor also has the WSS
- * active).
- *
- * The frame can be either broadcast or unicast. Broadcast in a WSS is
- * supported via multicast, but we don't support multicast yet (until
- * devices start to support MAB IEs). If a broadcast frame needs to be
- * transmitted it is treated as a unicast frame to each neighbor. In this
- * case the WLP takes over transmission of the skb and returns 1
- * to the caller to indicate so. Also, in this case, if a neighbor has the
- * same WSS activated but is not connected then the WSS connection will be
- * done at this time. The neighbor's virtual address will be learned at
- * this time.
- *
- * The destination address in a unicast frame is the virtual address of the
- * neighbor. This address only becomes known when a WSS connection is
- * established. We thus rely on a broadcast frame to trigger the setup of
- * WSS connections to all neighbors before we are able to send unicast
- * frames to them. This seems reasonable as IP would usually use ARP first
- * before any unicast frames are sent.
- *
- * If we are already connected to the neighbor (neighbor's virtual address
- * is known) we just prepare the WLP header and the caller will continue to
- * send the frame.
- *
- * A failure in this function usually indicates something that cannot be
- * fixed automatically. So, if this function fails (@return < 0) the calling
- * function should not retry to send the frame as it will very likely keep
- * failing.
- *
- */
-int wlp_prepare_tx_frame(struct device *dev, struct wlp *wlp,
- struct sk_buff *skb, struct uwb_dev_addr *dst)
-{
- int result = -EINVAL;
- struct ethhdr *eth_hdr = (void *) skb->data;
-
- if (is_multicast_ether_addr(eth_hdr->h_dest)) {
- result = wlp_eda_for_each(&wlp->eda, wlp_wss_send_copy, skb);
- if (result < 0) {
- if (printk_ratelimit())
- dev_err(dev, "Unable to handle broadcast "
- "frame from WLP client.\n");
- goto out;
- }
- dev_kfree_skb_irq(skb);
- result = 1;
- /* Frame will be transmitted by WLP. */
- } else {
- result = wlp_eda_for_virtual(&wlp->eda, eth_hdr->h_dest, dst,
- wlp_wss_prep_hdr, skb);
- if (unlikely(result < 0)) {
- if (printk_ratelimit())
- dev_err(dev, "Unable to prepare "
- "skb for transmission. \n");
- goto out;
- }
- }
-out:
- return result;
-}
-EXPORT_SYMBOL_GPL(wlp_prepare_tx_frame);
diff --git a/drivers/uwb/wlp/wlp-internal.h b/drivers/uwb/wlp/wlp-internal.h
deleted file mode 100644
index 3e8d5de7c5b9..000000000000
--- a/drivers/uwb/wlp/wlp-internal.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- * Internal API
- *
- * Copyright (C) 2007 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-
-#ifndef __WLP_INTERNAL_H__
-#define __WLP_INTERNAL_H__
-
-/**
- * State of WSS connection
- *
- * A device needs to connect to a neighbor in an activated WSS before data
- * can be transmitted. The spec also distinguishes between a new connection
- * attempt and a connection attempt after previous connection attempts. The
- * state WLP_WSS_CONNECT_FAILED is used for this scenario. See WLP 0.99
- * [7.2.6]
- */
-enum wlp_wss_connect {
- WLP_WSS_UNCONNECTED = 0,
- WLP_WSS_CONNECTED,
- WLP_WSS_CONNECT_FAILED,
-};
-
-extern struct kobj_type wss_ktype;
-extern struct attribute_group wss_attr_group;
-
-/* This should be changed to a dynamic array where entries are sorted
- * by eth_addr and search is done in a binary form
- *
- * Although thinking twice about it: this technologie's maximum reach
- * is 10 meters...unless you want to pack too much stuff in around
- * your radio controller/WLP device, the list will probably not be
- * too big.
- *
- * In any case, there is probably some data structure in the kernel
- * than we could reused for that already.
- *
- * The below structure is really just good while we support one WSS per
- * host.
- */
-struct wlp_eda_node {
- struct list_head list_node;
- unsigned char eth_addr[ETH_ALEN];
- struct uwb_dev_addr dev_addr;
- struct wlp_wss *wss;
- unsigned char virt_addr[ETH_ALEN];
- u8 tag;
- enum wlp_wss_connect state;
-};
-
-typedef int (*wlp_eda_for_each_f)(struct wlp *, struct wlp_eda_node *, void *);
-
-extern void wlp_eda_init(struct wlp_eda *);
-extern void wlp_eda_release(struct wlp_eda *);
-extern int wlp_eda_create_node(struct wlp_eda *,
- const unsigned char eth_addr[ETH_ALEN],
- const struct uwb_dev_addr *);
-extern void wlp_eda_rm_node(struct wlp_eda *, const struct uwb_dev_addr *);
-extern int wlp_eda_update_node(struct wlp_eda *,
- const struct uwb_dev_addr *,
- struct wlp_wss *,
- const unsigned char virt_addr[ETH_ALEN],
- const u8, const enum wlp_wss_connect);
-extern int wlp_eda_update_node_state(struct wlp_eda *,
- const struct uwb_dev_addr *,
- const enum wlp_wss_connect);
-
-extern int wlp_copy_eda_node(struct wlp_eda *, struct uwb_dev_addr *,
- struct wlp_eda_node *);
-extern int wlp_eda_for_each(struct wlp_eda *, wlp_eda_for_each_f , void *);
-extern int wlp_eda_for_virtual(struct wlp_eda *,
- const unsigned char eth_addr[ETH_ALEN],
- struct uwb_dev_addr *,
- wlp_eda_for_each_f , void *);
-
-
-extern void wlp_remove_neighbor_tmp_info(struct wlp_neighbor_e *);
-
-extern size_t wlp_wss_key_print(char *, size_t, u8 *);
-
-/* Function called when no more references to WSS exists */
-extern void wlp_wss_release(struct kobject *);
-
-extern void wlp_wss_reset(struct wlp_wss *);
-extern int wlp_wss_create_activate(struct wlp_wss *, struct wlp_uuid *,
- char *, unsigned, unsigned);
-extern int wlp_wss_enroll_activate(struct wlp_wss *, struct wlp_uuid *,
- struct uwb_dev_addr *);
-extern ssize_t wlp_discover(struct wlp *);
-
-extern int wlp_enroll_neighbor(struct wlp *, struct wlp_neighbor_e *,
- struct wlp_wss *, struct wlp_uuid *);
-extern int wlp_wss_is_active(struct wlp *, struct wlp_wss *,
- struct uwb_dev_addr *);
-
-struct wlp_assoc_conn_ctx {
- struct work_struct ws;
- struct wlp *wlp;
- struct sk_buff *skb;
- struct wlp_eda_node eda_entry;
-};
-
-
-extern int wlp_wss_connect_prep(struct wlp *, struct wlp_eda_node *, void *);
-extern int wlp_wss_send_copy(struct wlp *, struct wlp_eda_node *, void *);
-
-
-/* Message handling */
-struct wlp_assoc_frame_ctx {
- struct work_struct ws;
- struct wlp *wlp;
- struct sk_buff *skb;
- struct uwb_dev_addr src;
-};
-
-extern int wlp_wss_prep_hdr(struct wlp *, struct wlp_eda_node *, void *);
-extern void wlp_handle_d1_frame(struct work_struct *);
-extern int wlp_parse_d2_frame_to_cache(struct wlp *, struct sk_buff *,
- struct wlp_neighbor_e *);
-extern int wlp_parse_d2_frame_to_enroll(struct wlp_wss *, struct sk_buff *,
- struct wlp_neighbor_e *,
- struct wlp_uuid *);
-extern void wlp_handle_c1_frame(struct work_struct *);
-extern void wlp_handle_c3_frame(struct work_struct *);
-extern int wlp_parse_c3c4_frame(struct wlp *, struct sk_buff *,
- struct wlp_uuid *, u8 *,
- struct uwb_mac_addr *);
-extern int wlp_parse_f0(struct wlp *, struct sk_buff *);
-extern int wlp_send_assoc_frame(struct wlp *, struct wlp_wss *,
- struct uwb_dev_addr *, enum wlp_assoc_type);
-extern ssize_t wlp_get_version(struct wlp *, struct wlp_attr_version *,
- u8 *, ssize_t);
-extern ssize_t wlp_get_wssid(struct wlp *, struct wlp_attr_wssid *,
- struct wlp_uuid *, ssize_t);
-extern int __wlp_alloc_device_info(struct wlp *);
-extern int __wlp_setup_device_info(struct wlp *);
-
-extern struct wlp_wss_attribute wss_attribute_properties;
-extern struct wlp_wss_attribute wss_attribute_members;
-extern struct wlp_wss_attribute wss_attribute_state;
-
-static inline
-size_t wlp_wss_uuid_print(char *buf, size_t bufsize, struct wlp_uuid *uuid)
-{
- size_t result;
-
- result = scnprintf(buf, bufsize,
- "%02x:%02x:%02x:%02x:%02x:%02x:"
- "%02x:%02x:%02x:%02x:%02x:%02x:"
- "%02x:%02x:%02x:%02x",
- uuid->data[0], uuid->data[1],
- uuid->data[2], uuid->data[3],
- uuid->data[4], uuid->data[5],
- uuid->data[6], uuid->data[7],
- uuid->data[8], uuid->data[9],
- uuid->data[10], uuid->data[11],
- uuid->data[12], uuid->data[13],
- uuid->data[14], uuid->data[15]);
- return result;
-}
-
-/**
- * FIXME: How should a nonce be displayed?
- */
-static inline
-size_t wlp_wss_nonce_print(char *buf, size_t bufsize, struct wlp_nonce *nonce)
-{
- size_t result;
-
- result = scnprintf(buf, bufsize,
- "%02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x",
- nonce->data[0], nonce->data[1],
- nonce->data[2], nonce->data[3],
- nonce->data[4], nonce->data[5],
- nonce->data[6], nonce->data[7],
- nonce->data[8], nonce->data[9],
- nonce->data[10], nonce->data[11],
- nonce->data[12], nonce->data[13],
- nonce->data[14], nonce->data[15]);
- return result;
-}
-
-
-static inline
-void wlp_session_cb(struct wlp *wlp)
-{
- struct completion *completion = wlp->session->cb_priv;
- complete(completion);
-}
-
-static inline
-int wlp_uuid_is_set(struct wlp_uuid *uuid)
-{
- struct wlp_uuid zero_uuid = { .data = { 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00} };
-
- if (!memcmp(uuid, &zero_uuid, sizeof(*uuid)))
- return 0;
- return 1;
-}
-
-#endif /* __WLP_INTERNAL_H__ */
diff --git a/drivers/uwb/wlp/wlp-lc.c b/drivers/uwb/wlp/wlp-lc.c
deleted file mode 100644
index 7f6a630bf26c..000000000000
--- a/drivers/uwb/wlp/wlp-lc.c
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- */
-#include <linux/wlp.h>
-#include <linux/slab.h>
-
-#include "wlp-internal.h"
-
-static
-void wlp_neighbor_init(struct wlp_neighbor_e *neighbor)
-{
- INIT_LIST_HEAD(&neighbor->wssid);
-}
-
-/**
- * Create area for device information storage
- *
- * wlp->mutex must be held
- */
-int __wlp_alloc_device_info(struct wlp *wlp)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- BUG_ON(wlp->dev_info != NULL);
- wlp->dev_info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL);
- if (wlp->dev_info == NULL) {
- dev_err(dev, "WLP: Unable to allocate memory for "
- "device information.\n");
- return -ENOMEM;
- }
- return 0;
-}
-
-
-/**
- * Fill in device information using function provided by driver
- *
- * wlp->mutex must be held
- */
-static
-void __wlp_fill_device_info(struct wlp *wlp)
-{
- wlp->fill_device_info(wlp, wlp->dev_info);
-}
-
-/**
- * Setup device information
- *
- * Allocate area for device information and populate it.
- *
- * wlp->mutex must be held
- */
-int __wlp_setup_device_info(struct wlp *wlp)
-{
- int result;
- struct device *dev = &wlp->rc->uwb_dev.dev;
-
- result = __wlp_alloc_device_info(wlp);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to allocate area for "
- "device information.\n");
- return result;
- }
- __wlp_fill_device_info(wlp);
- return 0;
-}
-
-/**
- * Remove information about neighbor stored temporarily
- *
- * Information learned during discovey should only be stored when the
- * device enrolls in the neighbor's WSS. We do need to store this
- * information temporarily in order to present it to the user.
- *
- * We are only interested in keeping neighbor WSS information if that
- * neighbor is accepting enrollment.
- *
- * should be called with wlp->nbmutex held
- */
-void wlp_remove_neighbor_tmp_info(struct wlp_neighbor_e *neighbor)
-{
- struct wlp_wssid_e *wssid_e, *next;
- u8 keep;
- if (!list_empty(&neighbor->wssid)) {
- list_for_each_entry_safe(wssid_e, next, &neighbor->wssid,
- node) {
- if (wssid_e->info != NULL) {
- keep = wssid_e->info->accept_enroll;
- kfree(wssid_e->info);
- wssid_e->info = NULL;
- if (!keep) {
- list_del(&wssid_e->node);
- kfree(wssid_e);
- }
- }
- }
- }
- if (neighbor->info != NULL) {
- kfree(neighbor->info);
- neighbor->info = NULL;
- }
-}
-
-/*
- * Populate WLP neighborhood cache with neighbor information
- *
- * A new neighbor is found. If it is discoverable then we add it to the
- * neighborhood cache.
- *
- */
-static
-int wlp_add_neighbor(struct wlp *wlp, struct uwb_dev *dev)
-{
- int result = 0;
- int discoverable;
- struct wlp_neighbor_e *neighbor;
-
- /*
- * FIXME:
- * Use contents of WLP IE found in beacon cache to determine if
- * neighbor is discoverable.
- * The device does not support WLP IE yet so this still needs to be
- * done. Until then we assume all devices are discoverable.
- */
- discoverable = 1; /* will be changed when FIXME disappears */
- if (discoverable) {
- /* Add neighbor to cache for discovery */
- neighbor = kzalloc(sizeof(*neighbor), GFP_KERNEL);
- if (neighbor == NULL) {
- dev_err(&dev->dev, "Unable to create memory for "
- "new neighbor. \n");
- result = -ENOMEM;
- goto error_no_mem;
- }
- wlp_neighbor_init(neighbor);
- uwb_dev_get(dev);
- neighbor->uwb_dev = dev;
- list_add(&neighbor->node, &wlp->neighbors);
- }
-error_no_mem:
- return result;
-}
-
-/**
- * Remove one neighbor from cache
- */
-static
-void __wlp_neighbor_release(struct wlp_neighbor_e *neighbor)
-{
- struct wlp_wssid_e *wssid_e, *next_wssid_e;
-
- list_for_each_entry_safe(wssid_e, next_wssid_e,
- &neighbor->wssid, node) {
- list_del(&wssid_e->node);
- kfree(wssid_e);
- }
- uwb_dev_put(neighbor->uwb_dev);
- list_del(&neighbor->node);
- kfree(neighbor);
-}
-
-/**
- * Clear entire neighborhood cache.
- */
-static
-void __wlp_neighbors_release(struct wlp *wlp)
-{
- struct wlp_neighbor_e *neighbor, *next;
- if (list_empty(&wlp->neighbors))
- return;
- list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) {
- __wlp_neighbor_release(neighbor);
- }
-}
-
-static
-void wlp_neighbors_release(struct wlp *wlp)
-{
- mutex_lock(&wlp->nbmutex);
- __wlp_neighbors_release(wlp);
- mutex_unlock(&wlp->nbmutex);
-}
-
-
-
-/**
- * Send D1 message to neighbor, receive D2 message
- *
- * @neighbor: neighbor to which D1 message will be sent
- * @wss: if not NULL, it is an enrollment request for this WSS
- * @wssid: if wss not NULL, this is the wssid of the WSS in which we
- * want to enroll
- *
- * A D1/D2 exchange is done for one of two reasons: discovery or
- * enrollment. If done for discovery the D1 message is sent to the neighbor
- * and the contents of the D2 response is stored in a temporary cache.
- * If done for enrollment the @wss and @wssid are provided also. In this
- * case the D1 message is sent to the neighbor, the D2 response is parsed
- * for enrollment of the WSS with wssid.
- *
- * &wss->mutex is held
- */
-static
-int wlp_d1d2_exchange(struct wlp *wlp, struct wlp_neighbor_e *neighbor,
- struct wlp_wss *wss, struct wlp_uuid *wssid)
-{
- int result;
- struct device *dev = &wlp->rc->uwb_dev.dev;
- DECLARE_COMPLETION_ONSTACK(completion);
- struct wlp_session session;
- struct sk_buff *skb;
- struct wlp_frame_assoc *resp;
- struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr;
-
- mutex_lock(&wlp->mutex);
- if (!wlp_uuid_is_set(&wlp->uuid)) {
- dev_err(dev, "WLP: UUID is not set. Set via sysfs to "
- "proceed.\n");
- result = -ENXIO;
- goto out;
- }
- /* Send D1 association frame */
- result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_D1);
- if (result < 0) {
- dev_err(dev, "Unable to send D1 frame to neighbor "
- "%02x:%02x (%d)\n", dev_addr->data[1],
- dev_addr->data[0], result);
- goto out;
- }
- /* Create session, wait for response */
- session.exp_message = WLP_ASSOC_D2;
- session.cb = wlp_session_cb;
- session.cb_priv = &completion;
- session.neighbor_addr = *dev_addr;
- BUG_ON(wlp->session != NULL);
- wlp->session = &session;
- /* Wait for D2/F0 frame */
- result = wait_for_completion_interruptible_timeout(&completion,
- WLP_PER_MSG_TIMEOUT * HZ);
- if (result == 0) {
- result = -ETIMEDOUT;
- dev_err(dev, "Timeout while sending D1 to neighbor "
- "%02x:%02x.\n", dev_addr->data[1],
- dev_addr->data[0]);
- goto error_session;
- }
- if (result < 0) {
- dev_err(dev, "Unable to discover/enroll neighbor %02x:%02x.\n",
- dev_addr->data[1], dev_addr->data[0]);
- goto error_session;
- }
- /* Parse message in session->data: it will be either D2 or F0 */
- skb = session.data;
- resp = (void *) skb->data;
-
- if (resp->type == WLP_ASSOC_F0) {
- result = wlp_parse_f0(wlp, skb);
- if (result < 0)
- dev_err(dev, "WLP: Unable to parse F0 from neighbor "
- "%02x:%02x.\n", dev_addr->data[1],
- dev_addr->data[0]);
- result = -EINVAL;
- goto error_resp_parse;
- }
- if (wss == NULL) {
- /* Discovery */
- result = wlp_parse_d2_frame_to_cache(wlp, skb, neighbor);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to parse D2 message from "
- "neighbor %02x:%02x for discovery.\n",
- dev_addr->data[1], dev_addr->data[0]);
- goto error_resp_parse;
- }
- } else {
- /* Enrollment */
- result = wlp_parse_d2_frame_to_enroll(wss, skb, neighbor,
- wssid);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to parse D2 message from "
- "neighbor %02x:%02x for enrollment.\n",
- dev_addr->data[1], dev_addr->data[0]);
- goto error_resp_parse;
- }
- }
-error_resp_parse:
- kfree_skb(skb);
-error_session:
- wlp->session = NULL;
-out:
- mutex_unlock(&wlp->mutex);
- return result;
-}
-
-/**
- * Enroll into WSS of provided WSSID by using neighbor as registrar
- *
- * &wss->mutex is held
- */
-int wlp_enroll_neighbor(struct wlp *wlp, struct wlp_neighbor_e *neighbor,
- struct wlp_wss *wss, struct wlp_uuid *wssid)
-{
- int result = 0;
- struct device *dev = &wlp->rc->uwb_dev.dev;
- char buf[WLP_WSS_UUID_STRSIZE];
- struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr;
-
- wlp_wss_uuid_print(buf, sizeof(buf), wssid);
-
- result = wlp_d1d2_exchange(wlp, neighbor, wss, wssid);
- if (result < 0) {
- dev_err(dev, "WLP: D1/D2 message exchange for enrollment "
- "failed. result = %d \n", result);
- goto out;
- }
- if (wss->state != WLP_WSS_STATE_PART_ENROLLED) {
- dev_err(dev, "WLP: Unable to enroll into WSS %s using "
- "neighbor %02x:%02x. \n", buf,
- dev_addr->data[1], dev_addr->data[0]);
- result = -EINVAL;
- goto out;
- }
- if (wss->secure_status == WLP_WSS_SECURE) {
- dev_err(dev, "FIXME: need to complete secure enrollment.\n");
- result = -EINVAL;
- goto error;
- } else {
- wss->state = WLP_WSS_STATE_ENROLLED;
- dev_dbg(dev, "WLP: Success Enrollment into unsecure WSS "
- "%s using neighbor %02x:%02x. \n",
- buf, dev_addr->data[1], dev_addr->data[0]);
- }
-out:
- return result;
-error:
- wlp_wss_reset(wss);
- return result;
-}
-
-/**
- * Discover WSS information of neighbor's active WSS
- */
-static
-int wlp_discover_neighbor(struct wlp *wlp,
- struct wlp_neighbor_e *neighbor)
-{
- return wlp_d1d2_exchange(wlp, neighbor, NULL, NULL);
-}
-
-
-/**
- * Each neighbor in the neighborhood cache is discoverable. Discover it.
- *
- * Discovery is done through sending of D1 association frame and parsing
- * the D2 association frame response. Only wssid from D2 will be included
- * in neighbor cache, rest is just displayed to user and forgotten.
- *
- * The discovery is not done in parallel. This is simple and enables us to
- * maintain only one association context.
- *
- * The discovery of one neighbor does not affect the other, but if the
- * discovery of a neighbor fails it is removed from the neighborhood cache.
- */
-static
-int wlp_discover_all_neighbors(struct wlp *wlp)
-{
- int result = 0;
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct wlp_neighbor_e *neighbor, *next;
-
- list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) {
- result = wlp_discover_neighbor(wlp, neighbor);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to discover neighbor "
- "%02x:%02x, removing from neighborhood. \n",
- neighbor->uwb_dev->dev_addr.data[1],
- neighbor->uwb_dev->dev_addr.data[0]);
- __wlp_neighbor_release(neighbor);
- }
- }
- return result;
-}
-
-static int wlp_add_neighbor_helper(struct device *dev, void *priv)
-{
- struct wlp *wlp = priv;
- struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-
- return wlp_add_neighbor(wlp, uwb_dev);
-}
-
-/**
- * Discover WLP neighborhood
- *
- * Will send D1 association frame to all devices in beacon group that have
- * discoverable bit set in WLP IE. D2 frames will be received, information
- * displayed to user in @buf. Partial information (from D2 association
- * frame) will be cached to assist with future association
- * requests.
- *
- * The discovery of the WLP neighborhood is triggered by the user. This
- * should occur infrequently and we thus free current cache and re-allocate
- * memory if needed.
- *
- * If one neighbor fails during initial discovery (determining if it is a
- * neighbor or not), we fail all - note that interaction with neighbor has
- * not occured at this point so if a failure occurs we know something went wrong
- * locally. We thus undo everything.
- */
-ssize_t wlp_discover(struct wlp *wlp)
-{
- int result = 0;
- struct device *dev = &wlp->rc->uwb_dev.dev;
-
- mutex_lock(&wlp->nbmutex);
- /* Clear current neighborhood cache. */
- __wlp_neighbors_release(wlp);
- /* Determine which devices in neighborhood. Repopulate cache. */
- result = uwb_dev_for_each(wlp->rc, wlp_add_neighbor_helper, wlp);
- if (result < 0) {
- /* May have partial neighbor information, release all. */
- __wlp_neighbors_release(wlp);
- goto error_dev_for_each;
- }
- /* Discover the properties of devices in neighborhood. */
- result = wlp_discover_all_neighbors(wlp);
- /* In case of failure we still print our partial results. */
- if (result < 0) {
- dev_err(dev, "Unable to fully discover neighborhood. \n");
- result = 0;
- }
-error_dev_for_each:
- mutex_unlock(&wlp->nbmutex);
- return result;
-}
-
-/**
- * Handle events from UWB stack
- *
- * We handle events conservatively. If a neighbor goes off the air we
- * remove it from the neighborhood. If an association process is in
- * progress this function will block waiting for the nbmutex to become
- * free. The association process will thus be allowed to complete before it
- * is removed.
- */
-static
-void wlp_uwb_notifs_cb(void *_wlp, struct uwb_dev *uwb_dev,
- enum uwb_notifs event)
-{
- struct wlp *wlp = _wlp;
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct wlp_neighbor_e *neighbor, *next;
- int result;
- switch (event) {
- case UWB_NOTIF_ONAIR:
- result = wlp_eda_create_node(&wlp->eda,
- uwb_dev->mac_addr.data,
- &uwb_dev->dev_addr);
- if (result < 0)
- dev_err(dev, "WLP: Unable to add new neighbor "
- "%02x:%02x to EDA cache.\n",
- uwb_dev->dev_addr.data[1],
- uwb_dev->dev_addr.data[0]);
- break;
- case UWB_NOTIF_OFFAIR:
- wlp_eda_rm_node(&wlp->eda, &uwb_dev->dev_addr);
- mutex_lock(&wlp->nbmutex);
- list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) {
- if (neighbor->uwb_dev == uwb_dev)
- __wlp_neighbor_release(neighbor);
- }
- mutex_unlock(&wlp->nbmutex);
- break;
- default:
- dev_err(dev, "don't know how to handle event %d from uwb\n",
- event);
- }
-}
-
-static void wlp_channel_changed(struct uwb_pal *pal, int channel)
-{
- struct wlp *wlp = container_of(pal, struct wlp, pal);
-
- if (channel < 0)
- netif_carrier_off(wlp->ndev);
- else
- netif_carrier_on(wlp->ndev);
-}
-
-int wlp_setup(struct wlp *wlp, struct uwb_rc *rc, struct net_device *ndev)
-{
- int result;
-
- BUG_ON(wlp->fill_device_info == NULL);
- BUG_ON(wlp->xmit_frame == NULL);
- BUG_ON(wlp->stop_queue == NULL);
- BUG_ON(wlp->start_queue == NULL);
-
- wlp->rc = rc;
- wlp->ndev = ndev;
- wlp_eda_init(&wlp->eda);/* Set up address cache */
- wlp->uwb_notifs_handler.cb = wlp_uwb_notifs_cb;
- wlp->uwb_notifs_handler.data = wlp;
- uwb_notifs_register(rc, &wlp->uwb_notifs_handler);
-
- uwb_pal_init(&wlp->pal);
- wlp->pal.rc = rc;
- wlp->pal.channel_changed = wlp_channel_changed;
- result = uwb_pal_register(&wlp->pal);
- if (result < 0)
- uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler);
-
- return result;
-}
-EXPORT_SYMBOL_GPL(wlp_setup);
-
-void wlp_remove(struct wlp *wlp)
-{
- wlp_neighbors_release(wlp);
- uwb_pal_unregister(&wlp->pal);
- uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler);
- wlp_eda_release(&wlp->eda);
- mutex_lock(&wlp->mutex);
- if (wlp->dev_info != NULL)
- kfree(wlp->dev_info);
- mutex_unlock(&wlp->mutex);
- wlp->rc = NULL;
-}
-EXPORT_SYMBOL_GPL(wlp_remove);
-
-/**
- * wlp_reset_all - reset the WLP hardware
- * @wlp: the WLP device to reset.
- *
- * This schedules a full hardware reset of the WLP device. The radio
- * controller and any other PALs will also be reset.
- */
-void wlp_reset_all(struct wlp *wlp)
-{
- uwb_rc_reset_all(wlp->rc);
-}
-EXPORT_SYMBOL_GPL(wlp_reset_all);
diff --git a/drivers/uwb/wlp/wss-lc.c b/drivers/uwb/wlp/wss-lc.c
deleted file mode 100644
index 67872c83b679..000000000000
--- a/drivers/uwb/wlp/wss-lc.c
+++ /dev/null
@@ -1,959 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- *
- * Copyright (C) 2007 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * Implementation of the WLP association protocol.
- *
- * FIXME: Docs
- *
- * A UWB network interface will configure a WSS through wlp_wss_setup() after
- * the interface has been assigned a MAC address, typically after
- * "ifconfig" has been called. When the interface goes down it should call
- * wlp_wss_remove().
- *
- * When the WSS is ready for use the user interacts via sysfs to create,
- * discover, and activate WSS.
- *
- * wlp_wss_enroll_activate()
- *
- * wlp_wss_create_activate()
- * wlp_wss_set_wssid_hash()
- * wlp_wss_comp_wssid_hash()
- * wlp_wss_sel_bcast_addr()
- * wlp_wss_sysfs_add()
- *
- * Called when no more references to WSS exist:
- * wlp_wss_release()
- * wlp_wss_reset()
- */
-#include <linux/etherdevice.h> /* for is_valid_ether_addr */
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/wlp.h>
-
-#include "wlp-internal.h"
-
-size_t wlp_wss_key_print(char *buf, size_t bufsize, u8 *key)
-{
- size_t result;
-
- result = scnprintf(buf, bufsize,
- "%02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x",
- key[0], key[1], key[2], key[3],
- key[4], key[5], key[6], key[7],
- key[8], key[9], key[10], key[11],
- key[12], key[13], key[14], key[15]);
- return result;
-}
-
-/**
- * Compute WSSID hash
- * WLP Draft 0.99 [7.2.1]
- *
- * The WSSID hash for a WSSID is the result of an octet-wise exclusive-OR
- * of all octets in the WSSID.
- */
-static
-u8 wlp_wss_comp_wssid_hash(struct wlp_uuid *wssid)
-{
- return wssid->data[0] ^ wssid->data[1] ^ wssid->data[2]
- ^ wssid->data[3] ^ wssid->data[4] ^ wssid->data[5]
- ^ wssid->data[6] ^ wssid->data[7] ^ wssid->data[8]
- ^ wssid->data[9] ^ wssid->data[10] ^ wssid->data[11]
- ^ wssid->data[12] ^ wssid->data[13] ^ wssid->data[14]
- ^ wssid->data[15];
-}
-
-/**
- * Select a multicast EUI-48 for the WSS broadcast address.
- * WLP Draft 0.99 [7.2.1]
- *
- * Selected based on the WiMedia Alliance OUI, 00-13-88, within the WLP
- * range, [01-13-88-00-01-00, 01-13-88-00-01-FF] inclusive.
- *
- * This address is currently hardcoded.
- * FIXME?
- */
-static
-struct uwb_mac_addr wlp_wss_sel_bcast_addr(struct wlp_wss *wss)
-{
- struct uwb_mac_addr bcast = {
- .data = { 0x01, 0x13, 0x88, 0x00, 0x01, 0x00 }
- };
- return bcast;
-}
-
-/**
- * Clear the contents of the WSS structure - all except kobj, mutex, virtual
- *
- * We do not want to reinitialize - the internal kobj should not change as
- * it still points to the parent received during setup. The mutex should
- * remain also. We thus just reset values individually.
- * The virutal address assigned to WSS will remain the same for the
- * lifetime of the WSS. We only reset the fields that can change during its
- * lifetime.
- */
-void wlp_wss_reset(struct wlp_wss *wss)
-{
- memset(&wss->wssid, 0, sizeof(wss->wssid));
- wss->hash = 0;
- memset(&wss->name[0], 0, sizeof(wss->name));
- memset(&wss->bcast, 0, sizeof(wss->bcast));
- wss->secure_status = WLP_WSS_UNSECURE;
- memset(&wss->master_key[0], 0, sizeof(wss->master_key));
- wss->tag = 0;
- wss->state = WLP_WSS_STATE_NONE;
-}
-
-/**
- * Create sysfs infrastructure for WSS
- *
- * The WSS is configured to have the interface as parent (see wlp_wss_setup())
- * a new sysfs directory that includes wssid as its name is created in the
- * interface's sysfs directory. The group of files interacting with WSS are
- * created also.
- */
-static
-int wlp_wss_sysfs_add(struct wlp_wss *wss, char *wssid_str)
-{
- struct wlp *wlp = container_of(wss, struct wlp, wss);
- struct device *dev = &wlp->rc->uwb_dev.dev;
- int result;
-
- result = kobject_set_name(&wss->kobj, "wss-%s", wssid_str);
- if (result < 0)
- return result;
- wss->kobj.ktype = &wss_ktype;
- result = kobject_init_and_add(&wss->kobj,
- &wss_ktype, wss->kobj.parent, "wlp");
- if (result < 0) {
- dev_err(dev, "WLP: Cannot register WSS kobject.\n");
- goto error_kobject_register;
- }
- result = sysfs_create_group(&wss->kobj, &wss_attr_group);
- if (result < 0) {
- dev_err(dev, "WLP: Cannot register WSS attributes: %d\n",
- result);
- goto error_sysfs_create_group;
- }
- return 0;
-error_sysfs_create_group:
-
- kobject_put(&wss->kobj); /* will free name if needed */
- return result;
-error_kobject_register:
- kfree(wss->kobj.name);
- wss->kobj.name = NULL;
- wss->kobj.ktype = NULL;
- return result;
-}
-
-
-/**
- * Release WSS
- *
- * No more references exist to this WSS. We should undo everything that was
- * done in wlp_wss_create_activate() except removing the group. The group
- * is not removed because an object can be unregistered before the group is
- * created. We also undo any additional operations on the WSS after this
- * (addition of members).
- *
- * If memory was allocated for the kobject's name then it will
- * be freed by the kobject system during this time.
- *
- * The EDA cache is removed and reinitialized when the WSS is removed. We
- * thus loose knowledge of members of this WSS at that time and need not do
- * it here.
- */
-void wlp_wss_release(struct kobject *kobj)
-{
- struct wlp_wss *wss = container_of(kobj, struct wlp_wss, kobj);
-
- wlp_wss_reset(wss);
-}
-
-/**
- * Enroll into a WSS using provided neighbor as registrar
- *
- * First search the neighborhood information to learn which neighbor is
- * referred to, next proceed with enrollment.
- *
- * &wss->mutex is held
- */
-static
-int wlp_wss_enroll_target(struct wlp_wss *wss, struct wlp_uuid *wssid,
- struct uwb_dev_addr *dest)
-{
- struct wlp *wlp = container_of(wss, struct wlp, wss);
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct wlp_neighbor_e *neighbor;
- int result = -ENXIO;
- struct uwb_dev_addr *dev_addr;
-
- mutex_lock(&wlp->nbmutex);
- list_for_each_entry(neighbor, &wlp->neighbors, node) {
- dev_addr = &neighbor->uwb_dev->dev_addr;
- if (!memcmp(dest, dev_addr, sizeof(*dest))) {
- result = wlp_enroll_neighbor(wlp, neighbor, wss, wssid);
- break;
- }
- }
- if (result == -ENXIO)
- dev_err(dev, "WLP: Cannot find neighbor %02x:%02x. \n",
- dest->data[1], dest->data[0]);
- mutex_unlock(&wlp->nbmutex);
- return result;
-}
-
-/**
- * Enroll into a WSS previously discovered
- *
- * User provides WSSID of WSS, search for neighbor that has this WSS
- * activated and attempt to enroll.
- *
- * &wss->mutex is held
- */
-static
-int wlp_wss_enroll_discovered(struct wlp_wss *wss, struct wlp_uuid *wssid)
-{
- struct wlp *wlp = container_of(wss, struct wlp, wss);
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct wlp_neighbor_e *neighbor;
- struct wlp_wssid_e *wssid_e;
- char buf[WLP_WSS_UUID_STRSIZE];
- int result = -ENXIO;
-
-
- mutex_lock(&wlp->nbmutex);
- list_for_each_entry(neighbor, &wlp->neighbors, node) {
- list_for_each_entry(wssid_e, &neighbor->wssid, node) {
- if (!memcmp(wssid, &wssid_e->wssid, sizeof(*wssid))) {
- result = wlp_enroll_neighbor(wlp, neighbor,
- wss, wssid);
- if (result == 0) /* enrollment success */
- goto out;
- break;
- }
- }
- }
-out:
- if (result == -ENXIO) {
- wlp_wss_uuid_print(buf, sizeof(buf), wssid);
- dev_err(dev, "WLP: Cannot find WSSID %s in cache. \n", buf);
- }
- mutex_unlock(&wlp->nbmutex);
- return result;
-}
-
-/**
- * Enroll into WSS with provided WSSID, registrar may be provided
- *
- * @wss: out WSS that will be enrolled
- * @wssid: wssid of neighboring WSS that we want to enroll in
- * @devaddr: registrar can be specified, will be broadcast (ff:ff) if any
- * neighbor can be used as registrar.
- *
- * &wss->mutex is held
- */
-static
-int wlp_wss_enroll(struct wlp_wss *wss, struct wlp_uuid *wssid,
- struct uwb_dev_addr *devaddr)
-{
- int result;
- struct wlp *wlp = container_of(wss, struct wlp, wss);
- struct device *dev = &wlp->rc->uwb_dev.dev;
- char buf[WLP_WSS_UUID_STRSIZE];
- struct uwb_dev_addr bcast = {.data = {0xff, 0xff} };
-
- wlp_wss_uuid_print(buf, sizeof(buf), wssid);
-
- if (wss->state != WLP_WSS_STATE_NONE) {
- dev_err(dev, "WLP: Already enrolled in WSS %s.\n", buf);
- result = -EEXIST;
- goto error;
- }
- if (!memcmp(&bcast, devaddr, sizeof(bcast)))
- result = wlp_wss_enroll_discovered(wss, wssid);
- else
- result = wlp_wss_enroll_target(wss, wssid, devaddr);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to enroll into WSS %s, result %d \n",
- buf, result);
- goto error;
- }
- dev_dbg(dev, "Successfully enrolled into WSS %s \n", buf);
- result = wlp_wss_sysfs_add(wss, buf);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to set up sysfs for WSS kobject.\n");
- wlp_wss_reset(wss);
- }
-error:
- return result;
-
-}
-
-/**
- * Activate given WSS
- *
- * Prior to activation a WSS must be enrolled. To activate a WSS a device
- * includes the WSS hash in the WLP IE in its beacon in each superframe.
- * WLP 0.99 [7.2.5].
- *
- * The WSS tag is also computed at this time. We only support one activated
- * WSS so we can use the hash as a tag - there will never be a conflict.
- *
- * We currently only support one activated WSS so only one WSS hash is
- * included in the WLP IE.
- */
-static
-int wlp_wss_activate(struct wlp_wss *wss)
-{
- struct wlp *wlp = container_of(wss, struct wlp, wss);
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct uwb_rc *uwb_rc = wlp->rc;
- int result;
- struct {
- struct wlp_ie wlp_ie;
- u8 hash; /* only include one hash */
- } ie_data;
-
- BUG_ON(wss->state != WLP_WSS_STATE_ENROLLED);
- wss->hash = wlp_wss_comp_wssid_hash(&wss->wssid);
- wss->tag = wss->hash;
- memset(&ie_data, 0, sizeof(ie_data));
- ie_data.wlp_ie.hdr.element_id = UWB_IE_WLP;
- ie_data.wlp_ie.hdr.length = sizeof(ie_data) - sizeof(struct uwb_ie_hdr);
- wlp_ie_set_hash_length(&ie_data.wlp_ie, sizeof(ie_data.hash));
- ie_data.hash = wss->hash;
- result = uwb_rc_ie_add(uwb_rc, &ie_data.wlp_ie.hdr,
- sizeof(ie_data));
- if (result < 0) {
- dev_err(dev, "WLP: Unable to add WLP IE to beacon. "
- "result = %d.\n", result);
- goto error_wlp_ie;
- }
- wss->state = WLP_WSS_STATE_ACTIVE;
- result = 0;
-error_wlp_ie:
- return result;
-}
-
-/**
- * Enroll in and activate WSS identified by provided WSSID
- *
- * The neighborhood cache should contain a list of all neighbors and the
- * WSS they have activated. Based on that cache we search which neighbor we
- * can perform the association process with. The user also has option to
- * specify which neighbor it prefers as registrar.
- * Successful enrollment is followed by activation.
- * Successful activation will create the sysfs directory containing
- * specific information regarding this WSS.
- */
-int wlp_wss_enroll_activate(struct wlp_wss *wss, struct wlp_uuid *wssid,
- struct uwb_dev_addr *devaddr)
-{
- struct wlp *wlp = container_of(wss, struct wlp, wss);
- struct device *dev = &wlp->rc->uwb_dev.dev;
- int result = 0;
- char buf[WLP_WSS_UUID_STRSIZE];
-
- mutex_lock(&wss->mutex);
- result = wlp_wss_enroll(wss, wssid, devaddr);
- if (result < 0) {
- wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid);
- dev_err(dev, "WLP: Enrollment into WSS %s failed.\n", buf);
- goto error_enroll;
- }
- result = wlp_wss_activate(wss);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to activate WSS. Undoing enrollment "
- "result = %d \n", result);
- /* Undo enrollment */
- wlp_wss_reset(wss);
- goto error_activate;
- }
-error_activate:
-error_enroll:
- mutex_unlock(&wss->mutex);
- return result;
-}
-
-/**
- * Create, enroll, and activate a new WSS
- *
- * @wssid: new wssid provided by user
- * @name: WSS name requested by used.
- * @sec_status: security status requested by user
- *
- * A user requested the creation of a new WSS. All operations are done
- * locally. The new WSS will be stored locally, the hash will be included
- * in the WLP IE, and the sysfs infrastructure for this WSS will be
- * created.
- */
-int wlp_wss_create_activate(struct wlp_wss *wss, struct wlp_uuid *wssid,
- char *name, unsigned sec_status, unsigned accept)
-{
- struct wlp *wlp = container_of(wss, struct wlp, wss);
- struct device *dev = &wlp->rc->uwb_dev.dev;
- int result = 0;
- char buf[WLP_WSS_UUID_STRSIZE];
-
- result = wlp_wss_uuid_print(buf, sizeof(buf), wssid);
-
- if (!mutex_trylock(&wss->mutex)) {
- dev_err(dev, "WLP: WLP association session in progress.\n");
- return -EBUSY;
- }
- if (wss->state != WLP_WSS_STATE_NONE) {
- dev_err(dev, "WLP: WSS already exists. Not creating new.\n");
- result = -EEXIST;
- goto out;
- }
- if (wss->kobj.parent == NULL) {
- dev_err(dev, "WLP: WSS parent not ready. Is network interface "
- "up?\n");
- result = -ENXIO;
- goto out;
- }
- if (sec_status == WLP_WSS_SECURE) {
- dev_err(dev, "WLP: FIXME Creation of secure WSS not "
- "supported yet.\n");
- result = -EINVAL;
- goto out;
- }
- wss->wssid = *wssid;
- memcpy(wss->name, name, sizeof(wss->name));
- wss->bcast = wlp_wss_sel_bcast_addr(wss);
- wss->secure_status = sec_status;
- wss->accept_enroll = accept;
- /*wss->virtual_addr is initialized in call to wlp_wss_setup*/
- /* sysfs infrastructure */
- result = wlp_wss_sysfs_add(wss, buf);
- if (result < 0) {
- dev_err(dev, "Cannot set up sysfs for WSS kobject.\n");
- wlp_wss_reset(wss);
- goto out;
- } else
- result = 0;
- wss->state = WLP_WSS_STATE_ENROLLED;
- result = wlp_wss_activate(wss);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to activate WSS. Undoing "
- "enrollment\n");
- wlp_wss_reset(wss);
- goto out;
- }
- result = 0;
-out:
- mutex_unlock(&wss->mutex);
- return result;
-}
-
-/**
- * Determine if neighbor has WSS activated
- *
- * @returns: 1 if neighbor has WSS activated, zero otherwise
- *
- * This can be done in two ways:
- * - send a C1 frame, parse C2/F0 response
- * - examine the WLP IE sent by the neighbor
- *
- * The WLP IE is not fully supported in hardware so we use the C1/C2 frame
- * exchange to determine if a WSS is activated. Using the WLP IE should be
- * faster and should be used when it becomes possible.
- */
-int wlp_wss_is_active(struct wlp *wlp, struct wlp_wss *wss,
- struct uwb_dev_addr *dev_addr)
-{
- int result = 0;
- struct device *dev = &wlp->rc->uwb_dev.dev;
- DECLARE_COMPLETION_ONSTACK(completion);
- struct wlp_session session;
- struct sk_buff *skb;
- struct wlp_frame_assoc *resp;
- struct wlp_uuid wssid;
-
- mutex_lock(&wlp->mutex);
- /* Send C1 association frame */
- result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_C1);
- if (result < 0) {
- dev_err(dev, "Unable to send C1 frame to neighbor "
- "%02x:%02x (%d)\n", dev_addr->data[1],
- dev_addr->data[0], result);
- result = 0;
- goto out;
- }
- /* Create session, wait for response */
- session.exp_message = WLP_ASSOC_C2;
- session.cb = wlp_session_cb;
- session.cb_priv = &completion;
- session.neighbor_addr = *dev_addr;
- BUG_ON(wlp->session != NULL);
- wlp->session = &session;
- /* Wait for C2/F0 frame */
- result = wait_for_completion_interruptible_timeout(&completion,
- WLP_PER_MSG_TIMEOUT * HZ);
- if (result == 0) {
- dev_err(dev, "Timeout while sending C1 to neighbor "
- "%02x:%02x.\n", dev_addr->data[1],
- dev_addr->data[0]);
- goto out;
- }
- if (result < 0) {
- dev_err(dev, "Unable to send C1 to neighbor %02x:%02x.\n",
- dev_addr->data[1], dev_addr->data[0]);
- result = 0;
- goto out;
- }
- /* Parse message in session->data: it will be either C2 or F0 */
- skb = session.data;
- resp = (void *) skb->data;
- if (resp->type == WLP_ASSOC_F0) {
- result = wlp_parse_f0(wlp, skb);
- if (result < 0)
- dev_err(dev, "WLP: unable to parse incoming F0 "
- "frame from neighbor %02x:%02x.\n",
- dev_addr->data[1], dev_addr->data[0]);
- result = 0;
- goto error_resp_parse;
- }
- /* WLP version and message type fields have already been parsed */
- result = wlp_get_wssid(wlp, (void *)resp + sizeof(*resp), &wssid,
- skb->len - sizeof(*resp));
- if (result < 0) {
- dev_err(dev, "WLP: unable to obtain WSSID from C2 frame.\n");
- result = 0;
- goto error_resp_parse;
- }
- if (!memcmp(&wssid, &wss->wssid, sizeof(wssid)))
- result = 1;
- else {
- dev_err(dev, "WLP: Received a C2 frame without matching "
- "WSSID.\n");
- result = 0;
- }
-error_resp_parse:
- kfree_skb(skb);
-out:
- wlp->session = NULL;
- mutex_unlock(&wlp->mutex);
- return result;
-}
-
-/**
- * Activate connection with neighbor by updating EDA cache
- *
- * @wss: local WSS to which neighbor wants to connect
- * @dev_addr: neighbor's address
- * @wssid: neighbor's WSSID - must be same as our WSS's WSSID
- * @tag: neighbor's WSS tag used to identify frames transmitted by it
- * @virt_addr: neighbor's virtual EUI-48
- */
-static
-int wlp_wss_activate_connection(struct wlp *wlp, struct wlp_wss *wss,
- struct uwb_dev_addr *dev_addr,
- struct wlp_uuid *wssid, u8 *tag,
- struct uwb_mac_addr *virt_addr)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- int result = 0;
-
- if (!memcmp(wssid, &wss->wssid, sizeof(*wssid))) {
- /* Update EDA cache */
- result = wlp_eda_update_node(&wlp->eda, dev_addr, wss,
- (void *) virt_addr->data, *tag,
- WLP_WSS_CONNECTED);
- if (result < 0)
- dev_err(dev, "WLP: Unable to update EDA cache "
- "with new connected neighbor information.\n");
- } else {
- dev_err(dev, "WLP: Neighbor does not have matching WSSID.\n");
- result = -EINVAL;
- }
- return result;
-}
-
-/**
- * Connect to WSS neighbor
- *
- * Use C3/C4 exchange to determine if neighbor has WSS activated and
- * retrieve the WSS tag and virtual EUI-48 of the neighbor.
- */
-static
-int wlp_wss_connect_neighbor(struct wlp *wlp, struct wlp_wss *wss,
- struct uwb_dev_addr *dev_addr)
-{
- int result;
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct wlp_uuid wssid;
- u8 tag;
- struct uwb_mac_addr virt_addr;
- DECLARE_COMPLETION_ONSTACK(completion);
- struct wlp_session session;
- struct wlp_frame_assoc *resp;
- struct sk_buff *skb;
-
- mutex_lock(&wlp->mutex);
- /* Send C3 association frame */
- result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_C3);
- if (result < 0) {
- dev_err(dev, "Unable to send C3 frame to neighbor "
- "%02x:%02x (%d)\n", dev_addr->data[1],
- dev_addr->data[0], result);
- goto out;
- }
- /* Create session, wait for response */
- session.exp_message = WLP_ASSOC_C4;
- session.cb = wlp_session_cb;
- session.cb_priv = &completion;
- session.neighbor_addr = *dev_addr;
- BUG_ON(wlp->session != NULL);
- wlp->session = &session;
- /* Wait for C4/F0 frame */
- result = wait_for_completion_interruptible_timeout(&completion,
- WLP_PER_MSG_TIMEOUT * HZ);
- if (result == 0) {
- dev_err(dev, "Timeout while sending C3 to neighbor "
- "%02x:%02x.\n", dev_addr->data[1],
- dev_addr->data[0]);
- result = -ETIMEDOUT;
- goto out;
- }
- if (result < 0) {
- dev_err(dev, "Unable to send C3 to neighbor %02x:%02x.\n",
- dev_addr->data[1], dev_addr->data[0]);
- goto out;
- }
- /* Parse message in session->data: it will be either C4 or F0 */
- skb = session.data;
- resp = (void *) skb->data;
- if (resp->type == WLP_ASSOC_F0) {
- result = wlp_parse_f0(wlp, skb);
- if (result < 0)
- dev_err(dev, "WLP: unable to parse incoming F0 "
- "frame from neighbor %02x:%02x.\n",
- dev_addr->data[1], dev_addr->data[0]);
- result = -EINVAL;
- goto error_resp_parse;
- }
- result = wlp_parse_c3c4_frame(wlp, skb, &wssid, &tag, &virt_addr);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to parse C4 frame from neighbor.\n");
- goto error_resp_parse;
- }
- result = wlp_wss_activate_connection(wlp, wss, dev_addr, &wssid, &tag,
- &virt_addr);
- if (result < 0) {
- dev_err(dev, "WLP: Unable to activate connection to "
- "neighbor %02x:%02x.\n", dev_addr->data[1],
- dev_addr->data[0]);
- goto error_resp_parse;
- }
-error_resp_parse:
- kfree_skb(skb);
-out:
- /* Record that we unsuccessfully tried to connect to this neighbor */
- if (result < 0)
- wlp_eda_update_node_state(&wlp->eda, dev_addr,
- WLP_WSS_CONNECT_FAILED);
- wlp->session = NULL;
- mutex_unlock(&wlp->mutex);
- return result;
-}
-
-/**
- * Connect to neighbor with common WSS, send pending frame
- *
- * This function is scheduled when a frame is destined to a neighbor with
- * which we do not have a connection. A copy of the EDA cache entry is
- * provided - not the actual cache entry (because it is protected by a
- * spinlock).
- *
- * First determine if neighbor has the same WSS activated, connect if it
- * does. The C3/C4 exchange is dual purpose to determine if neighbor has
- * WSS activated and proceed with the connection.
- *
- * The frame that triggered the connection setup is sent after connection
- * setup.
- *
- * network queue is stopped - we need to restart when done
- *
- */
-static
-void wlp_wss_connect_send(struct work_struct *ws)
-{
- struct wlp_assoc_conn_ctx *conn_ctx = container_of(ws,
- struct wlp_assoc_conn_ctx,
- ws);
- struct wlp *wlp = conn_ctx->wlp;
- struct sk_buff *skb = conn_ctx->skb;
- struct wlp_eda_node *eda_entry = &conn_ctx->eda_entry;
- struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr;
- struct wlp_wss *wss = &wlp->wss;
- int result;
- struct device *dev = &wlp->rc->uwb_dev.dev;
-
- mutex_lock(&wss->mutex);
- if (wss->state < WLP_WSS_STATE_ACTIVE) {
- if (printk_ratelimit())
- dev_err(dev, "WLP: Attempting to connect with "
- "WSS that is not active or connected.\n");
- dev_kfree_skb(skb);
- goto out;
- }
- /* Establish connection - send C3 rcv C4 */
- result = wlp_wss_connect_neighbor(wlp, wss, dev_addr);
- if (result < 0) {
- if (printk_ratelimit())
- dev_err(dev, "WLP: Unable to establish connection "
- "with neighbor %02x:%02x.\n",
- dev_addr->data[1], dev_addr->data[0]);
- dev_kfree_skb(skb);
- goto out;
- }
- /* EDA entry changed, update the local copy being used */
- result = wlp_copy_eda_node(&wlp->eda, dev_addr, eda_entry);
- if (result < 0) {
- if (printk_ratelimit())
- dev_err(dev, "WLP: Cannot find EDA entry for "
- "neighbor %02x:%02x \n",
- dev_addr->data[1], dev_addr->data[0]);
- }
- result = wlp_wss_prep_hdr(wlp, eda_entry, skb);
- if (result < 0) {
- if (printk_ratelimit())
- dev_err(dev, "WLP: Unable to prepare frame header for "
- "transmission (neighbor %02x:%02x). \n",
- dev_addr->data[1], dev_addr->data[0]);
- dev_kfree_skb(skb);
- goto out;
- }
- BUG_ON(wlp->xmit_frame == NULL);
- result = wlp->xmit_frame(wlp, skb, dev_addr);
- if (result < 0) {
- if (printk_ratelimit())
- dev_err(dev, "WLP: Unable to transmit frame: %d\n",
- result);
- if (result == -ENXIO)
- dev_err(dev, "WLP: Is network interface up? \n");
- /* We could try again ... */
- dev_kfree_skb(skb);/*we need to free if tx fails */
- }
-out:
- kfree(conn_ctx);
- BUG_ON(wlp->start_queue == NULL);
- wlp->start_queue(wlp);
- mutex_unlock(&wss->mutex);
-}
-
-/**
- * Add WLP header to outgoing skb
- *
- * @eda_entry: pointer to neighbor's entry in the EDA cache
- * @_skb: skb containing data destined to the neighbor
- */
-int wlp_wss_prep_hdr(struct wlp *wlp, struct wlp_eda_node *eda_entry,
- void *_skb)
-{
- struct device *dev = &wlp->rc->uwb_dev.dev;
- int result = 0;
- unsigned char *eth_addr = eda_entry->eth_addr;
- struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr;
- struct sk_buff *skb = _skb;
- struct wlp_frame_std_abbrv_hdr *std_hdr;
-
- if (eda_entry->state == WLP_WSS_CONNECTED) {
- /* Add WLP header */
- BUG_ON(skb_headroom(skb) < sizeof(*std_hdr));
- std_hdr = (void *) __skb_push(skb, sizeof(*std_hdr));
- std_hdr->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
- std_hdr->hdr.type = WLP_FRAME_STANDARD;
- std_hdr->tag = eda_entry->wss->tag;
- } else {
- if (printk_ratelimit())
- dev_err(dev, "WLP: Destination neighbor (Ethernet: "
- "%pM, Dev: %02x:%02x) is not connected.\n",
- eth_addr, dev_addr->data[1], dev_addr->data[0]);
- result = -EINVAL;
- }
- return result;
-}
-
-
-/**
- * Prepare skb for neighbor: connect if not already and prep WLP header
- *
- * This function is called in interrupt context, but it needs to sleep. We
- * temporarily stop the net queue to establish the WLP connection.
- * Setup of the WLP connection and restart of queue is scheduled
- * on the default work queue.
- *
- * run with eda->lock held (spinlock)
- */
-int wlp_wss_connect_prep(struct wlp *wlp, struct wlp_eda_node *eda_entry,
- void *_skb)
-{
- int result = 0;
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct sk_buff *skb = _skb;
- struct wlp_assoc_conn_ctx *conn_ctx;
-
- if (eda_entry->state == WLP_WSS_UNCONNECTED) {
- /* We don't want any more packets while we set up connection */
- BUG_ON(wlp->stop_queue == NULL);
- wlp->stop_queue(wlp);
- conn_ctx = kmalloc(sizeof(*conn_ctx), GFP_ATOMIC);
- if (conn_ctx == NULL) {
- if (printk_ratelimit())
- dev_err(dev, "WLP: Unable to allocate memory "
- "for connection handling.\n");
- result = -ENOMEM;
- goto out;
- }
- conn_ctx->wlp = wlp;
- conn_ctx->skb = skb;
- conn_ctx->eda_entry = *eda_entry;
- INIT_WORK(&conn_ctx->ws, wlp_wss_connect_send);
- schedule_work(&conn_ctx->ws);
- result = 1;
- } else if (eda_entry->state == WLP_WSS_CONNECT_FAILED) {
- /* Previous connection attempts failed, don't retry - see
- * conditions for connection in WLP 0.99 [7.6.2] */
- if (printk_ratelimit())
- dev_err(dev, "Could not connect to neighbor "
- "previously. Not retrying. \n");
- result = -ENONET;
- goto out;
- } else /* eda_entry->state == WLP_WSS_CONNECTED */
- result = wlp_wss_prep_hdr(wlp, eda_entry, skb);
-out:
- return result;
-}
-
-/**
- * Emulate broadcast: copy skb, send copy to neighbor (connect if not already)
- *
- * We need to copy skbs in the case where we emulate broadcast through
- * unicast. We copy instead of clone because we are modifying the data of
- * the frame after copying ... clones share data so we cannot emulate
- * broadcast using clones.
- *
- * run with eda->lock held (spinlock)
- */
-int wlp_wss_send_copy(struct wlp *wlp, struct wlp_eda_node *eda_entry,
- void *_skb)
-{
- int result = -ENOMEM;
- struct device *dev = &wlp->rc->uwb_dev.dev;
- struct sk_buff *skb = _skb;
- struct sk_buff *copy;
- struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr;
-
- copy = skb_copy(skb, GFP_ATOMIC);
- if (copy == NULL) {
- if (printk_ratelimit())
- dev_err(dev, "WLP: Unable to copy skb for "
- "transmission.\n");
- goto out;
- }
- result = wlp_wss_connect_prep(wlp, eda_entry, copy);
- if (result < 0) {
- if (printk_ratelimit())
- dev_err(dev, "WLP: Unable to connect/send skb "
- "to neighbor.\n");
- dev_kfree_skb_irq(copy);
- goto out;
- } else if (result == 1)
- /* Frame will be transmitted separately */
- goto out;
- BUG_ON(wlp->xmit_frame == NULL);
- result = wlp->xmit_frame(wlp, copy, dev_addr);
- if (result < 0) {
- if (printk_ratelimit())
- dev_err(dev, "WLP: Unable to transmit frame: %d\n",
- result);
- if ((result == -ENXIO) && printk_ratelimit())
- dev_err(dev, "WLP: Is network interface up? \n");
- /* We could try again ... */
- dev_kfree_skb_irq(copy);/*we need to free if tx fails */
- }
-out:
- return result;
-}
-
-
-/**
- * Setup WSS
- *
- * Should be called by network driver after the interface has been given a
- * MAC address.
- */
-int wlp_wss_setup(struct net_device *net_dev, struct wlp_wss *wss)
-{
- struct wlp *wlp = container_of(wss, struct wlp, wss);
- struct device *dev = &wlp->rc->uwb_dev.dev;
- int result = 0;
-
- mutex_lock(&wss->mutex);
- wss->kobj.parent = &net_dev->dev.kobj;
- if (!is_valid_ether_addr(net_dev->dev_addr)) {
- dev_err(dev, "WLP: Invalid MAC address. Cannot use for"
- "virtual.\n");
- result = -EINVAL;
- goto out;
- }
- memcpy(wss->virtual_addr.data, net_dev->dev_addr,
- sizeof(wss->virtual_addr.data));
-out:
- mutex_unlock(&wss->mutex);
- return result;
-}
-EXPORT_SYMBOL_GPL(wlp_wss_setup);
-
-/**
- * Remove WSS
- *
- * Called by client that configured WSS through wlp_wss_setup(). This
- * function is called when client no longer needs WSS, eg. client shuts
- * down.
- *
- * We remove the WLP IE from the beacon before initiating local cleanup.
- */
-void wlp_wss_remove(struct wlp_wss *wss)
-{
- struct wlp *wlp = container_of(wss, struct wlp, wss);
-
- mutex_lock(&wss->mutex);
- if (wss->state == WLP_WSS_STATE_ACTIVE)
- uwb_rc_ie_rm(wlp->rc, UWB_IE_WLP);
- if (wss->state != WLP_WSS_STATE_NONE) {
- sysfs_remove_group(&wss->kobj, &wss_attr_group);
- kobject_put(&wss->kobj);
- }
- wss->kobj.parent = NULL;
- memset(&wss->virtual_addr, 0, sizeof(wss->virtual_addr));
- /* Cleanup EDA cache */
- wlp_eda_release(&wlp->eda);
- wlp_eda_init(&wlp->eda);
- mutex_unlock(&wss->mutex);
-}
-EXPORT_SYMBOL_GPL(wlp_wss_remove);
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 861af4a8b79c..4b4da5b86ff9 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -246,7 +246,7 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
int r, nlogs = 0;
while (datalen > 0) {
- if (unlikely(seg >= VHOST_NET_MAX_SG)) {
+ if (unlikely(seg >= UIO_MAXIOV)) {
r = -ENOBUFS;
goto err;
}
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 8b5a1b33d0fe..94701ff3a23a 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -212,6 +212,45 @@ static int vhost_worker(void *data)
}
}
+/* Helper to allocate iovec buffers for all vqs. */
+static long vhost_dev_alloc_iovecs(struct vhost_dev *dev)
+{
+ int i;
+ for (i = 0; i < dev->nvqs; ++i) {
+ dev->vqs[i].indirect = kmalloc(sizeof *dev->vqs[i].indirect *
+ UIO_MAXIOV, GFP_KERNEL);
+ dev->vqs[i].log = kmalloc(sizeof *dev->vqs[i].log * UIO_MAXIOV,
+ GFP_KERNEL);
+ dev->vqs[i].heads = kmalloc(sizeof *dev->vqs[i].heads *
+ UIO_MAXIOV, GFP_KERNEL);
+
+ if (!dev->vqs[i].indirect || !dev->vqs[i].log ||
+ !dev->vqs[i].heads)
+ goto err_nomem;
+ }
+ return 0;
+err_nomem:
+ for (; i >= 0; --i) {
+ kfree(dev->vqs[i].indirect);
+ kfree(dev->vqs[i].log);
+ kfree(dev->vqs[i].heads);
+ }
+ return -ENOMEM;
+}
+
+static void vhost_dev_free_iovecs(struct vhost_dev *dev)
+{
+ int i;
+ for (i = 0; i < dev->nvqs; ++i) {
+ kfree(dev->vqs[i].indirect);
+ dev->vqs[i].indirect = NULL;
+ kfree(dev->vqs[i].log);
+ dev->vqs[i].log = NULL;
+ kfree(dev->vqs[i].heads);
+ dev->vqs[i].heads = NULL;
+ }
+}
+
long vhost_dev_init(struct vhost_dev *dev,
struct vhost_virtqueue *vqs, int nvqs)
{
@@ -229,6 +268,9 @@ long vhost_dev_init(struct vhost_dev *dev,
dev->worker = NULL;
for (i = 0; i < dev->nvqs; ++i) {
+ dev->vqs[i].log = NULL;
+ dev->vqs[i].indirect = NULL;
+ dev->vqs[i].heads = NULL;
dev->vqs[i].dev = dev;
mutex_init(&dev->vqs[i].mutex);
vhost_vq_reset(dev, dev->vqs + i);
@@ -295,6 +337,10 @@ static long vhost_dev_set_owner(struct vhost_dev *dev)
if (err)
goto err_cgroup;
+ err = vhost_dev_alloc_iovecs(dev);
+ if (err)
+ goto err_cgroup;
+
return 0;
err_cgroup:
kthread_stop(worker);
@@ -345,6 +391,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
fput(dev->vqs[i].call);
vhost_vq_reset(dev, dev->vqs + i);
}
+ vhost_dev_free_iovecs(dev);
if (dev->log_ctx)
eventfd_ctx_put(dev->log_ctx);
dev->log_ctx = NULL;
@@ -372,7 +419,7 @@ static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz)
/* Make sure 64 bit math will not overflow. */
if (a > ULONG_MAX - (unsigned long)log_base ||
a + (unsigned long)log_base > ULONG_MAX)
- return -EFAULT;
+ return 0;
return access_ok(VERIFY_WRITE, log_base + a,
(sz + VHOST_PAGE_SIZE * 8 - 1) / VHOST_PAGE_SIZE / 8);
@@ -957,7 +1004,7 @@ static int get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,
}
ret = translate_desc(dev, indirect->addr, indirect->len, vq->indirect,
- ARRAY_SIZE(vq->indirect));
+ UIO_MAXIOV);
if (unlikely(ret < 0)) {
vq_err(vq, "Translation failure %d in indirect.\n", ret);
return ret;
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index af3c11ded5fd..073d06ae091f 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -15,11 +15,6 @@
struct vhost_device;
-enum {
- /* Enough place for all fragments, head, and virtio net header. */
- VHOST_NET_MAX_SG = MAX_SKB_FRAGS + 2,
-};
-
struct vhost_work;
typedef void (*vhost_work_fn_t)(struct vhost_work *work);
@@ -93,12 +88,15 @@ struct vhost_virtqueue {
bool log_used;
u64 log_addr;
- struct iovec indirect[VHOST_NET_MAX_SG];
- struct iovec iov[VHOST_NET_MAX_SG];
- struct iovec hdr[VHOST_NET_MAX_SG];
+ struct iovec iov[UIO_MAXIOV];
+ /* hdr is used to store the virtio header.
+ * Since each iovec has >= 1 byte length, we never need more than
+ * header length entries to store the header. */
+ struct iovec hdr[sizeof(struct virtio_net_hdr_mrg_rxbuf)];
+ struct iovec *indirect;
size_t vhost_hlen;
size_t sock_hlen;
- struct vring_used_elem heads[VHOST_NET_MAX_SG];
+ struct vring_used_elem *heads;
/* We use a kind of RCU to access private pointer.
* All readers access it from worker, which makes it possible to
* flush the vhost_work instead of synchronize_rcu. Therefore readers do
@@ -109,7 +107,7 @@ struct vhost_virtqueue {
void __rcu *private_data;
/* Log write descriptors */
void __user *log_base;
- struct vhost_log log[VHOST_NET_MAX_SG];
+ struct vhost_log *log;
};
struct vhost_dev {
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 8b31fdfefc98..27c1fb4b1e0d 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -17,6 +17,8 @@ source "drivers/gpu/vga/Kconfig"
source "drivers/gpu/drm/Kconfig"
+source "drivers/gpu/stub/Kconfig"
+
config VGASTATE
tristate
default n
@@ -49,7 +51,7 @@ menuconfig FB
You need an utility program called fbset to make full use of frame
buffer devices. Please read <file:Documentation/fb/framebuffer.txt>
and the Framebuffer-HOWTO at
- <http://www.munted.org.uk/programming/Framebuffer-HOWTO-1.2.html> for more
+ <http://www.munted.org.uk/programming/Framebuffer-HOWTO-1.3.html> for more
information.
Say Y here and to the driver for your graphics board below if you
@@ -955,7 +957,7 @@ config FB_EPSON1355
Build in support for the SED1355 Epson Research Embedded RAMDAC
LCD/CRT Controller (since redesignated as the S1D13505) as a
framebuffer. Product specs at
- <http://www.erd.epson.com/vdc/html/products.htm>.
+ <http://vdc.epson.com/>.
config FB_S1D13XXX
tristate "Epson S1D13XXX framebuffer support"
@@ -966,7 +968,7 @@ config FB_S1D13XXX
help
Support for S1D13XXX framebuffer device family (currently only
working with S1D13806). Product specs at
- <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm>
+ <http://vdc.epson.com/>
config FB_ATMEL
tristate "AT91/AT32 LCD Controller support"
@@ -1323,7 +1325,7 @@ config FB_RADEON
don't need to choose this to run the Radeon in plain VGA mode.
There is a product page at
- http://apps.ati.com/ATIcompare/
+ http://products.amd.com/en-us/GraphicCardResult.aspx
config FB_RADEON_I2C
bool "DDC/I2C for ATI Radeon support"
@@ -1395,7 +1397,7 @@ config FB_ATY_CT
Say Y here to support use of ATI's 64-bit Rage boards (or other
boards based on the Mach64 CT, VT, GT, and LT chipsets) as a
framebuffer device. The ATI product support page for these boards
- is at <http://support.ati.com/products/pc/mach64/>.
+ is at <http://support.ati.com/products/pc/mach64/mach64.html>.
config FB_ATY_GENERIC_LCD
bool "Mach64 generic LCD support (EXPERIMENTAL)"
@@ -1919,6 +1921,9 @@ config FB_SH_MOBILE_HDMI
tristate "SuperH Mobile HDMI controller support"
depends on FB_SH_MOBILE_LCDC
select FB_MODE_HELPERS
+ select SOUND
+ select SND
+ select SND_SOC
---help---
Driver for the on-chip SH-Mobile HDMI controller.
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
index f3d7440f0072..3ec4923c2d84 100644
--- a/drivers/video/arcfb.c
+++ b/drivers/video/arcfb.c
@@ -2,7 +2,6 @@
* linux/drivers/video/arcfb.c -- FB driver for Arc monochrome LCD board
*
* Copyright (C) 2005, Jaya Kumar <jayalk@intworks.biz>
- * http://www.intworks.biz/arclcd
*
* 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
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index f8d69ad36830..5bf91236c701 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2970,7 +2970,8 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
struct atyfb_par *par = info->par;
struct device_node *dp;
char prop[128];
- int node, len, i, j, ret;
+ phandle node;
+ int len, i, j, ret;
u32 mem, chip_id;
/*
diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c
index 359fc64e761a..78d1f4cd1fe0 100644
--- a/drivers/video/aty/radeon_i2c.c
+++ b/drivers/video/aty/radeon_i2c.c
@@ -7,7 +7,6 @@
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
#include <asm/io.h>
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
index e77e8e4280fb..4ea187d93768 100644
--- a/drivers/video/au1200fb.c
+++ b/drivers/video/au1200fb.c
@@ -1079,7 +1079,7 @@ static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
* clock can only be obtain by dividing this value by an even integer.
* Fallback to a slower pixel clock if necessary. */
pixclock = max((u32)(PICOS2KHZ(var->pixclock) * 1000), fbi->monspecs.dclkmin);
- pixclock = min(pixclock, min(fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2));
+ pixclock = min3(pixclock, fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2);
if (AU1200_LCD_MAX_CLK % pixclock) {
int diff = AU1200_LCD_MAX_CLK % pixclock;
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index b020ba7f1cf2..e7d0f525041e 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -241,12 +241,12 @@ static int request_ports(struct bfin_bf54xfb_info *fbi)
u16 disp = fbi->mach_info->disp;
if (gpio_request(disp, DRIVER_NAME)) {
- printk(KERN_ERR "Requesting GPIO %d faild\n", disp);
+ printk(KERN_ERR "Requesting GPIO %d failed\n", disp);
return -EFAULT;
}
if (peripheral_request_list(eppi_req_18, DRIVER_NAME)) {
- printk(KERN_ERR "Requesting Peripherals faild\n");
+ printk(KERN_ERR "Requesting Peripherals failed\n");
gpio_free(disp);
return -EFAULT;
}
@@ -256,7 +256,7 @@ static int request_ports(struct bfin_bf54xfb_info *fbi)
u16 eppi_req_24[] = EPPI0_24;
if (peripheral_request_list(eppi_req_24, DRIVER_NAME)) {
- printk(KERN_ERR "Requesting Peripherals faild\n");
+ printk(KERN_ERR "Requesting Peripherals failed\n");
peripheral_free_list(eppi_req_18);
gpio_free(disp);
return -EFAULT;
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c
index 7a50272eaab9..3cf77676947c 100644
--- a/drivers/video/bfin-t350mcqb-fb.c
+++ b/drivers/video/bfin-t350mcqb-fb.c
@@ -192,7 +192,7 @@ static int bfin_t350mcqb_request_ports(int action)
{
if (action) {
if (peripheral_request_list(ppi0_req_8, DRIVER_NAME)) {
- printk(KERN_ERR "Requesting Peripherals faild\n");
+ printk(KERN_ERR "Requesting Peripherals failed\n");
return -EFAULT;
}
} else
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
index db9713b49ce9..a268cbf1cbea 100644
--- a/drivers/video/epson1355fb.c
+++ b/drivers/video/epson1355fb.c
@@ -4,7 +4,7 @@
* Epson Research S1D13505 Embedded RAMDAC LCD/CRT Controller
* (previously known as SED1355)
*
- * Cf. http://www.erd.epson.com/vdc/html/S1D13505.html
+ * Cf. http://vdc.epson.com/
*
*
* Copyright (C) Hewlett-Packard Company. All rights reserved.
diff --git a/drivers/video/fbcvt.c b/drivers/video/fbcvt.c
index 7293eaccd81b..7cb715dfc0e1 100644
--- a/drivers/video/fbcvt.c
+++ b/drivers/video/fbcvt.c
@@ -5,7 +5,7 @@
*
* Based from the VESA(TM) Coordinated Video Timing Generator by
* Graham Loveridge April 9, 2003 available at
- * http://www.vesa.org/public/CVT/CVTd6r1.xls
+ * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls
*
* 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
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 42e303ff862a..0e6aa3d96a42 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -697,9 +697,9 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
- u32 *buffer, *dst;
- u32 __iomem *src;
- int c, i, cnt = 0, err = 0;
+ u8 *buffer, *dst;
+ u8 __iomem *src;
+ int c, cnt = 0, err = 0;
unsigned long total_size;
if (!info || ! info->screen_base)
@@ -730,7 +730,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
if (!buffer)
return -ENOMEM;
- src = (u32 __iomem *) (info->screen_base + p);
+ src = (u8 __iomem *) (info->screen_base + p);
if (info->fbops->fb_sync)
info->fbops->fb_sync(info);
@@ -738,17 +738,9 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
while (count) {
c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
dst = buffer;
- for (i = c >> 2; i--; )
- *dst++ = fb_readl(src++);
- if (c & 3) {
- u8 *dst8 = (u8 *) dst;
- u8 __iomem *src8 = (u8 __iomem *) src;
-
- for (i = c & 3; i--;)
- *dst8++ = fb_readb(src8++);
-
- src = (u32 __iomem *) src8;
- }
+ fb_memcpy_fromfb(dst, src, c);
+ dst += c;
+ src += c;
if (copy_to_user(buf, buffer, c)) {
err = -EFAULT;
@@ -772,9 +764,9 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
- u32 *buffer, *src;
- u32 __iomem *dst;
- int c, i, cnt = 0, err = 0;
+ u8 *buffer, *src;
+ u8 __iomem *dst;
+ int c, cnt = 0, err = 0;
unsigned long total_size;
if (!info || !info->screen_base)
@@ -811,7 +803,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
if (!buffer)
return -ENOMEM;
- dst = (u32 __iomem *) (info->screen_base + p);
+ dst = (u8 __iomem *) (info->screen_base + p);
if (info->fbops->fb_sync)
info->fbops->fb_sync(info);
@@ -825,19 +817,9 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
break;
}
- for (i = c >> 2; i--; )
- fb_writel(*src++, dst++);
-
- if (c & 3) {
- u8 *src8 = (u8 *) src;
- u8 __iomem *dst8 = (u8 __iomem *) dst;
-
- for (i = c & 3; i--; )
- fb_writeb(*src8++, dst8++);
-
- dst = (u32 __iomem *) dst8;
- }
-
+ fb_memcpy_tofb(dst, src, c);
+ dst += c;
+ src += c;
*ppos += c;
buf += c;
cnt += c;
@@ -877,13 +859,13 @@ fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
if ((err = info->fbops->fb_pan_display(var, info)))
return err;
- info->var.xoffset = var->xoffset;
- info->var.yoffset = var->yoffset;
- if (var->vmode & FB_VMODE_YWRAP)
- info->var.vmode |= FB_VMODE_YWRAP;
- else
- info->var.vmode &= ~FB_VMODE_YWRAP;
- return 0;
+ info->var.xoffset = var->xoffset;
+ info->var.yoffset = var->yoffset;
+ if (var->vmode & FB_VMODE_YWRAP)
+ info->var.vmode |= FB_VMODE_YWRAP;
+ else
+ info->var.vmode &= ~FB_VMODE_YWRAP;
+ return 0;
}
static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c
index ca3355e430bf..933899dca33a 100644
--- a/drivers/video/gbefb.c
+++ b/drivers/video/gbefb.c
@@ -1143,8 +1143,10 @@ static int __devinit gbefb_probe(struct platform_device *p_dev)
return -ENOMEM;
#ifndef MODULE
- if (fb_get_options("gbefb", &options))
- return -ENODEV;
+ if (fb_get_options("gbefb", &options)) {
+ ret = -ENODEV;
+ goto out_release_framebuffer;
+ }
gbefb_setup(options);
#endif
diff --git a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h
index 328ae6c673ec..f37de60ecc59 100644
--- a/drivers/video/i810/i810.h
+++ b/drivers/video/i810/i810.h
@@ -17,7 +17,6 @@
#include <linux/agp_backend.h>
#include <linux/fb.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
#include <video/vga.h>
diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c
index 487f2be47460..3300bd31d9d7 100644
--- a/drivers/video/intelfb/intelfb_i2c.c
+++ b/drivers/video/intelfb/intelfb_i2c.c
@@ -32,7 +32,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <linux/fb.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
#include <asm/io.h>
diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c
index f9fa0fd00292..1717623aabc0 100644
--- a/drivers/video/matrox/matroxfb_DAC1064.c
+++ b/drivers/video/matrox/matroxfb_DAC1064.c
@@ -869,12 +869,9 @@ static int MGAG100_preinit(struct matrox_fb_info *minfo)
minfo->capable.plnwt = minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG100
? minfo->devflags.sgram : 1;
-#ifdef CONFIG_FB_MATROX_G
if (minfo->devflags.g450dac) {
minfo->outputs[0].output = &g450out;
- } else
-#endif
- {
+ } else {
minfo->outputs[0].output = &m1064;
}
minfo->outputs[0].src = minfo->outputs[0].default_src;
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
index 1e3e8f19783e..31b8f67477b7 100644
--- a/drivers/video/matrox/matroxfb_maven.c
+++ b/drivers/video/matrox/matroxfb_maven.c
@@ -280,7 +280,7 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
return fxtal * (*feed) / (*in) * ctl->den;
}
-static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl,
+static int matroxfb_mavenclock(const struct matrox_pll_ctl *ctl,
unsigned int htotal, unsigned int vtotal,
unsigned int* in, unsigned int* feed, unsigned int* post,
unsigned int* htotal2) {
diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c
index 9b3d6e4584cc..63ed3b72b01c 100644
--- a/drivers/video/metronomefb.c
+++ b/drivers/video/metronomefb.c
@@ -10,7 +10,7 @@
* Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
*
* This work was made possible by help and equipment support from E-Ink
- * Corporation. http://support.eink.com/community
+ * Corporation. http://www.eink.com/
*
* This driver is written to be used with the Metronome display controller.
* It is intended to be architecture independent. A board specific driver
diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c
index 2ffb34af4c59..87785c215a52 100644
--- a/drivers/video/omap/blizzard.c
+++ b/drivers/video/omap/blizzard.c
@@ -1590,7 +1590,7 @@ static int blizzard_init(struct omapfb_device *fbdev, int ext_mode,
blizzard.auto_update_window.width = fbdev->panel->x_res;
blizzard.auto_update_window.height = fbdev->panel->y_res;
blizzard.auto_update_window.out_x = 0;
- blizzard.auto_update_window.out_x = 0;
+ blizzard.auto_update_window.out_y = 0;
blizzard.auto_update_window.out_width = fbdev->panel->x_res;
blizzard.auto_update_window.out_height = fbdev->panel->y_res;
blizzard.auto_update_window.format = 0;
diff --git a/drivers/video/omap/lcd_omap3beagle.c b/drivers/video/omap/lcd_omap3beagle.c
index ca75cc2a87a5..d7c6c3e0afc6 100644
--- a/drivers/video/omap/lcd_omap3beagle.c
+++ b/drivers/video/omap/lcd_omap3beagle.c
@@ -25,8 +25,6 @@
#include <linux/gpio.h>
#include <linux/i2c/twl.h>
-#include <plat/mux.h>
-#include <plat/mux.h>
#include <asm/mach-types.h>
#include "omapfb.h"
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
index 881c9f77c75a..12327bbfdbbb 100644
--- a/drivers/video/omap2/displays/Kconfig
+++ b/drivers/video/omap2/displays/Kconfig
@@ -40,7 +40,7 @@ config PANEL_TPO_TD043MTEA1
config PANEL_ACX565AKM
tristate "ACX565AKM Panel"
- depends on OMAP2_DSS_SDI
+ depends on OMAP2_DSS_SDI && SPI
select BACKLIGHT_CLASS_DEVICE
help
This is the LCD panel used on Nokia N900
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
index 07fbb8a733bb..e77310653207 100644
--- a/drivers/video/omap2/displays/panel-acx565akm.c
+++ b/drivers/video/omap2/displays/panel-acx565akm.c
@@ -587,6 +587,9 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev)
dev_dbg(&dssdev->dev, "%s\n", __func__);
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+ return 0;
+
mutex_lock(&md->mutex);
r = omapdss_sdi_display_enable(dssdev);
@@ -644,6 +647,9 @@ static void acx_panel_power_off(struct omap_dss_device *dssdev)
dev_dbg(&dssdev->dev, "%s\n", __func__);
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ return;
+
mutex_lock(&md->mutex);
if (!md->enabled) {
diff --git a/drivers/video/omap2/displays/panel-generic.c b/drivers/video/omap2/displays/panel-generic.c
index 300eff5de1b4..395a68de3990 100644
--- a/drivers/video/omap2/displays/panel-generic.c
+++ b/drivers/video/omap2/displays/panel-generic.c
@@ -39,6 +39,9 @@ static int generic_panel_power_on(struct omap_dss_device *dssdev)
{
int r;
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+ return 0;
+
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
@@ -58,6 +61,9 @@ err0:
static void generic_panel_power_off(struct omap_dss_device *dssdev)
{
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ return;
+
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
diff --git a/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c b/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c
index 10267461991c..0c6896cea2d0 100644
--- a/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c
+++ b/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c
@@ -43,6 +43,9 @@ static int sharp_lq_panel_power_on(struct omap_dss_device *dssdev)
{
int r;
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+ return 0;
+
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
@@ -65,6 +68,9 @@ err0:
static void sharp_lq_panel_power_off(struct omap_dss_device *dssdev)
{
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ return;
+
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
index 7d9eb2b1f5af..9a138f650e05 100644
--- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
+++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
@@ -135,6 +135,9 @@ static int sharp_ls_power_on(struct omap_dss_device *dssdev)
{
int r = 0;
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+ return 0;
+
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
@@ -157,6 +160,9 @@ err0:
static void sharp_ls_power_off(struct omap_dss_device *dssdev)
{
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ return;
+
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
diff --git a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c
index e320e67d06f3..526e906c8a6c 100644
--- a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c
+++ b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c
@@ -46,6 +46,9 @@ static int toppoly_tdo_panel_power_on(struct omap_dss_device *dssdev)
{
int r;
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+ return 0;
+
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
@@ -65,6 +68,9 @@ err0:
static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev)
{
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ return;
+
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
index e866e76b13d0..dbe9d43b4850 100644
--- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
+++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
@@ -269,6 +269,9 @@ static int tpo_td043_power_on(struct omap_dss_device *dssdev)
int nreset_gpio = dssdev->reset_gpio;
int r;
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+ return 0;
+
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
@@ -308,6 +311,9 @@ static void tpo_td043_power_off(struct omap_dss_device *dssdev)
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
int nreset_gpio = dssdev->reset_gpio;
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ return;
+
tpo_td043_write(tpo_td043->spi, 3,
TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
index d71b5d9d71b1..7db17b5e570c 100644
--- a/drivers/video/omap2/dss/Makefile
+++ b/drivers/video/omap2/dss/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
-omapdss-y := core.o dss.o dispc.o display.o manager.o overlay.o
+omapdss-y := core.o dss.o dss_features.o dispc.o display.o manager.o overlay.o
omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index b3a498f22d36..8e89f6049280 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -37,6 +37,7 @@
#include <plat/clock.h>
#include "dss.h"
+#include "dss_features.h"
static struct {
struct platform_device *pdev;
@@ -502,6 +503,8 @@ static int omap_dss_probe(struct platform_device *pdev)
core.pdev = pdev;
+ dss_features_init();
+
dss_init_overlay_managers(pdev);
dss_init_overlays(pdev);
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 5ecdc0004094..fa40fa59a9ac 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -39,6 +39,7 @@
#include <plat/display.h>
#include "dss.h"
+#include "dss_features.h"
/* DISPC */
#define DISPC_BASE 0x48050400
@@ -139,6 +140,22 @@ struct omap_dispc_isr_data {
u32 mask;
};
+struct dispc_h_coef {
+ s8 hc4;
+ s8 hc3;
+ u8 hc2;
+ s8 hc1;
+ s8 hc0;
+};
+
+struct dispc_v_coef {
+ s8 vc22;
+ s8 vc2;
+ u8 vc1;
+ s8 vc0;
+ s8 vc00;
+};
+
#define REG_GET(idx, start, end) \
FLD_GET(dispc_read_reg(idx), start, end)
@@ -564,106 +581,77 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
int vscaleup, int five_taps)
{
/* Coefficients for horizontal up-sampling */
- static const u32 coef_hup[8] = {
- 0x00800000,
- 0x0D7CF800,
- 0x1E70F5FF,
- 0x335FF5FE,
- 0xF74949F7,
- 0xF55F33FB,
- 0xF5701EFE,
- 0xF87C0DFF,
+ static const struct dispc_h_coef coef_hup[8] = {
+ { 0, 0, 128, 0, 0 },
+ { -1, 13, 124, -8, 0 },
+ { -2, 30, 112, -11, -1 },
+ { -5, 51, 95, -11, -2 },
+ { 0, -9, 73, 73, -9 },
+ { -2, -11, 95, 51, -5 },
+ { -1, -11, 112, 30, -2 },
+ { 0, -8, 124, 13, -1 },
};
- /* Coefficients for horizontal down-sampling */
- static const u32 coef_hdown[8] = {
- 0x24382400,
- 0x28371FFE,
- 0x2C361BFB,
- 0x303516F9,
- 0x11343311,
- 0x1635300C,
- 0x1B362C08,
- 0x1F372804,
+ /* Coefficients for vertical up-sampling */
+ static const struct dispc_v_coef coef_vup_3tap[8] = {
+ { 0, 0, 128, 0, 0 },
+ { 0, 3, 123, 2, 0 },
+ { 0, 12, 111, 5, 0 },
+ { 0, 32, 89, 7, 0 },
+ { 0, 0, 64, 64, 0 },
+ { 0, 7, 89, 32, 0 },
+ { 0, 5, 111, 12, 0 },
+ { 0, 2, 123, 3, 0 },
};
- /* Coefficients for horizontal and vertical up-sampling */
- static const u32 coef_hvup[2][8] = {
- {
- 0x00800000,
- 0x037B02FF,
- 0x0C6F05FE,
- 0x205907FB,
- 0x00404000,
- 0x075920FE,
- 0x056F0CFF,
- 0x027B0300,
- },
- {
- 0x00800000,
- 0x0D7CF8FF,
- 0x1E70F5FE,
- 0x335FF5FB,
- 0xF7404000,
- 0xF55F33FE,
- 0xF5701EFF,
- 0xF87C0D00,
- },
+ static const struct dispc_v_coef coef_vup_5tap[8] = {
+ { 0, 0, 128, 0, 0 },
+ { -1, 13, 124, -8, 0 },
+ { -2, 30, 112, -11, -1 },
+ { -5, 51, 95, -11, -2 },
+ { 0, -9, 73, 73, -9 },
+ { -2, -11, 95, 51, -5 },
+ { -1, -11, 112, 30, -2 },
+ { 0, -8, 124, 13, -1 },
};
- /* Coefficients for horizontal and vertical down-sampling */
- static const u32 coef_hvdown[2][8] = {
- {
- 0x24382400,
- 0x28391F04,
- 0x2D381B08,
- 0x3237170C,
- 0x123737F7,
- 0x173732F9,
- 0x1B382DFB,
- 0x1F3928FE,
- },
- {
- 0x24382400,
- 0x28371F04,
- 0x2C361B08,
- 0x3035160C,
- 0x113433F7,
- 0x163530F9,
- 0x1B362CFB,
- 0x1F3728FE,
- },
+ /* Coefficients for horizontal down-sampling */
+ static const struct dispc_h_coef coef_hdown[8] = {
+ { 0, 36, 56, 36, 0 },
+ { 4, 40, 55, 31, -2 },
+ { 8, 44, 54, 27, -5 },
+ { 12, 48, 53, 22, -7 },
+ { -9, 17, 52, 51, 17 },
+ { -7, 22, 53, 48, 12 },
+ { -5, 27, 54, 44, 8 },
+ { -2, 31, 55, 40, 4 },
};
- /* Coefficients for vertical up-sampling */
- static const u32 coef_vup[8] = {
- 0x00000000,
- 0x0000FF00,
- 0x0000FEFF,
- 0x0000FBFE,
- 0x000000F7,
- 0x0000FEFB,
- 0x0000FFFE,
- 0x000000FF,
+ /* Coefficients for vertical down-sampling */
+ static const struct dispc_v_coef coef_vdown_3tap[8] = {
+ { 0, 36, 56, 36, 0 },
+ { 0, 40, 57, 31, 0 },
+ { 0, 45, 56, 27, 0 },
+ { 0, 50, 55, 23, 0 },
+ { 0, 18, 55, 55, 0 },
+ { 0, 23, 55, 50, 0 },
+ { 0, 27, 56, 45, 0 },
+ { 0, 31, 57, 40, 0 },
};
-
- /* Coefficients for vertical down-sampling */
- static const u32 coef_vdown[8] = {
- 0x00000000,
- 0x000004FE,
- 0x000008FB,
- 0x00000CF9,
- 0x0000F711,
- 0x0000F90C,
- 0x0000FB08,
- 0x0000FE04,
+ static const struct dispc_v_coef coef_vdown_5tap[8] = {
+ { 0, 36, 56, 36, 0 },
+ { 4, 40, 55, 31, -2 },
+ { 8, 44, 54, 27, -5 },
+ { 12, 48, 53, 22, -7 },
+ { -9, 17, 52, 51, 17 },
+ { -7, 22, 53, 48, 12 },
+ { -5, 27, 54, 44, 8 },
+ { -2, 31, 55, 40, 4 },
};
- const u32 *h_coef;
- const u32 *hv_coef;
- const u32 *hv_coef_mod;
- const u32 *v_coef;
+ const struct dispc_h_coef *h_coef;
+ const struct dispc_v_coef *v_coef;
int i;
if (hscaleup)
@@ -671,47 +659,34 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
else
h_coef = coef_hdown;
- if (vscaleup) {
- hv_coef = coef_hvup[five_taps];
- v_coef = coef_vup;
-
- if (hscaleup)
- hv_coef_mod = NULL;
- else
- hv_coef_mod = coef_hvdown[five_taps];
- } else {
- hv_coef = coef_hvdown[five_taps];
- v_coef = coef_vdown;
-
- if (hscaleup)
- hv_coef_mod = coef_hvup[five_taps];
- else
- hv_coef_mod = NULL;
- }
+ if (vscaleup)
+ v_coef = five_taps ? coef_vup_5tap : coef_vup_3tap;
+ else
+ v_coef = five_taps ? coef_vdown_5tap : coef_vdown_3tap;
for (i = 0; i < 8; i++) {
u32 h, hv;
- h = h_coef[i];
-
- hv = hv_coef[i];
-
- if (hv_coef_mod) {
- hv &= 0xffffff00;
- hv |= (hv_coef_mod[i] & 0xff);
- }
+ h = FLD_VAL(h_coef[i].hc0, 7, 0)
+ | FLD_VAL(h_coef[i].hc1, 15, 8)
+ | FLD_VAL(h_coef[i].hc2, 23, 16)
+ | FLD_VAL(h_coef[i].hc3, 31, 24);
+ hv = FLD_VAL(h_coef[i].hc4, 7, 0)
+ | FLD_VAL(v_coef[i].vc0, 15, 8)
+ | FLD_VAL(v_coef[i].vc1, 23, 16)
+ | FLD_VAL(v_coef[i].vc2, 31, 24);
_dispc_write_firh_reg(plane, i, h);
_dispc_write_firhv_reg(plane, i, hv);
}
- if (!five_taps)
- return;
-
- for (i = 0; i < 8; i++) {
- u32 v;
- v = v_coef[i];
- _dispc_write_firv_reg(plane, i, v);
+ if (five_taps) {
+ for (i = 0; i < 8; i++) {
+ u32 v;
+ v = FLD_VAL(v_coef[i].vc00, 7, 0)
+ | FLD_VAL(v_coef[i].vc22, 15, 8);
+ _dispc_write_firv_reg(plane, i, v);
+ }
}
}
@@ -800,12 +775,12 @@ static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
{
-
- BUG_ON(plane == OMAP_DSS_VIDEO1);
-
- if (cpu_is_omap24xx())
+ if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
return;
+ BUG_ON(!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
+ plane == OMAP_DSS_VIDEO1);
+
if (plane == OMAP_DSS_GFX)
REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
else if (plane == OMAP_DSS_VIDEO2)
@@ -975,17 +950,14 @@ static void dispc_read_plane_fifo_sizes(void)
DISPC_VID_FIFO_SIZE_STATUS(1) };
u32 size;
int plane;
+ u8 start, end;
enable_clocks(1);
- for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
- if (cpu_is_omap24xx())
- size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 8, 0);
- else if (cpu_is_omap34xx())
- size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 10, 0);
- else
- BUG();
+ dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
+ for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
+ size = FLD_GET(dispc_read_reg(fsz_reg[plane]), start, end);
dispc.fifo_size[plane] = size;
}
@@ -1002,6 +974,8 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
const struct dispc_reg ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
DISPC_VID_FIFO_THRESHOLD(0),
DISPC_VID_FIFO_THRESHOLD(1) };
+ u8 hi_start, hi_end, lo_start, lo_end;
+
enable_clocks(1);
DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
@@ -1010,12 +984,12 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
REG_GET(ftrs_reg[plane], 27, 16),
low, high);
- if (cpu_is_omap24xx())
- dispc_write_reg(ftrs_reg[plane],
- FLD_VAL(high, 24, 16) | FLD_VAL(low, 8, 0));
- else
- dispc_write_reg(ftrs_reg[plane],
- FLD_VAL(high, 27, 16) | FLD_VAL(low, 11, 0));
+ dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
+ dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
+
+ dispc_write_reg(ftrs_reg[plane],
+ FLD_VAL(high, hi_start, hi_end) |
+ FLD_VAL(low, lo_start, lo_end));
enable_clocks(0);
}
@@ -1035,13 +1009,16 @@ static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc)
u32 val;
const struct dispc_reg fir_reg[] = { DISPC_VID_FIR(0),
DISPC_VID_FIR(1) };
+ u8 hinc_start, hinc_end, vinc_start, vinc_end;
BUG_ON(plane == OMAP_DSS_GFX);
- if (cpu_is_omap24xx())
- val = FLD_VAL(vinc, 27, 16) | FLD_VAL(hinc, 11, 0);
- else
- val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
+ dss_feat_get_reg_field(FEAT_REG_FIRHINC, &hinc_start, &hinc_end);
+ dss_feat_get_reg_field(FEAT_REG_FIRVINC, &vinc_start, &vinc_end);
+
+ val = FLD_VAL(vinc, vinc_start, vinc_end) |
+ FLD_VAL(hinc, hinc_start, hinc_end);
+
dispc_write_reg(fir_reg[plane-1], val);
}
@@ -1567,6 +1544,8 @@ static int _dispc_setup_plane(enum omap_plane plane,
case OMAP_DSS_COLOR_ARGB16:
case OMAP_DSS_COLOR_ARGB32:
case OMAP_DSS_COLOR_RGBA32:
+ if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
+ return -EINVAL;
case OMAP_DSS_COLOR_RGBX32:
if (cpu_is_omap24xx())
return -EINVAL;
@@ -1607,9 +1586,10 @@ static int _dispc_setup_plane(enum omap_plane plane,
case OMAP_DSS_COLOR_ARGB16:
case OMAP_DSS_COLOR_ARGB32:
case OMAP_DSS_COLOR_RGBA32:
- if (cpu_is_omap24xx())
+ if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
return -EINVAL;
- if (plane == OMAP_DSS_VIDEO1)
+ if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
+ plane == OMAP_DSS_VIDEO1)
return -EINVAL;
break;
@@ -2002,7 +1982,7 @@ void dispc_enable_trans_key(enum omap_channel ch, bool enable)
}
void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
{
- if (cpu_is_omap24xx())
+ if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
return;
enable_clocks(1);
@@ -2016,7 +1996,7 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch)
{
bool enabled;
- if (cpu_is_omap24xx())
+ if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
return false;
enable_clocks(1);
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index b3fa3a7db911..aa4f7a5fae29 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -3274,7 +3274,6 @@ int dsi_init(struct platform_device *pdev)
dsi.vdds_dsi_reg = dss_get_vdds_dsi();
if (IS_ERR(dsi.vdds_dsi_reg)) {
- iounmap(dsi.base);
DSSERR("can't get VDDS_DSI regulator\n");
r = PTR_ERR(dsi.vdds_dsi_reg);
goto err2;
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
new file mode 100644
index 000000000000..867f68de125f
--- /dev/null
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -0,0 +1,191 @@
+/*
+ * linux/drivers/video/omap2/dss/dss_features.c
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Archit Taneja <archit@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include <plat/display.h>
+#include <plat/cpu.h>
+
+#include "dss_features.h"
+
+/* Defines a generic omap register field */
+struct dss_reg_field {
+ enum dss_feat_reg_field id;
+ u8 start, end;
+};
+
+struct omap_dss_features {
+ const struct dss_reg_field *reg_fields;
+ const int num_reg_fields;
+
+ const u32 has_feature;
+
+ const int num_mgrs;
+ const int num_ovls;
+ const enum omap_display_type *supported_displays;
+ const enum omap_color_mode *supported_color_modes;
+};
+
+/* This struct is assigned to one of the below during initialization */
+static struct omap_dss_features *omap_current_dss_features;
+
+static const struct dss_reg_field omap2_dss_reg_fields[] = {
+ { FEAT_REG_FIRHINC, 11, 0 },
+ { FEAT_REG_FIRVINC, 27, 16 },
+ { FEAT_REG_FIFOLOWTHRESHOLD, 8, 0 },
+ { FEAT_REG_FIFOHIGHTHRESHOLD, 24, 16 },
+ { FEAT_REG_FIFOSIZE, 8, 0 },
+};
+
+static const struct dss_reg_field omap3_dss_reg_fields[] = {
+ { FEAT_REG_FIRHINC, 12, 0 },
+ { FEAT_REG_FIRVINC, 28, 16 },
+ { FEAT_REG_FIFOLOWTHRESHOLD, 11, 0 },
+ { FEAT_REG_FIFOHIGHTHRESHOLD, 27, 16 },
+ { FEAT_REG_FIFOSIZE, 10, 0 },
+};
+
+static const enum omap_display_type omap2_dss_supported_displays[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+ OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DISPLAY_TYPE_VENC,
+};
+
+static const enum omap_display_type omap3_dss_supported_displays[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+ OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DISPLAY_TYPE_VENC,
+};
+
+static const enum omap_color_mode omap2_dss_supported_color_modes[] = {
+ /* OMAP_DSS_GFX */
+ OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
+ OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
+ OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
+ OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P,
+
+ /* OMAP_DSS_VIDEO1 */
+ OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+ OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
+ OMAP_DSS_COLOR_UYVY,
+
+ /* OMAP_DSS_VIDEO2 */
+ OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+ OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
+ OMAP_DSS_COLOR_UYVY,
+};
+
+static const enum omap_color_mode omap3_dss_supported_color_modes[] = {
+ /* OMAP_DSS_GFX */
+ OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
+ OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
+ OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
+ OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+ OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
+ OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
+
+ /* OMAP_DSS_VIDEO1 */
+ OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P |
+ OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
+ OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY,
+
+ /* OMAP_DSS_VIDEO2 */
+ OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
+ OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+ OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
+ OMAP_DSS_COLOR_UYVY | OMAP_DSS_COLOR_ARGB32 |
+ OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
+};
+
+/* OMAP2 DSS Features */
+static struct omap_dss_features omap2_dss_features = {
+ .reg_fields = omap2_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields),
+
+ .num_mgrs = 2,
+ .num_ovls = 3,
+ .supported_displays = omap2_dss_supported_displays,
+ .supported_color_modes = omap2_dss_supported_color_modes,
+};
+
+/* OMAP3 DSS Features */
+static struct omap_dss_features omap3_dss_features = {
+ .reg_fields = omap3_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
+
+ .has_feature = FEAT_GLOBAL_ALPHA,
+
+ .num_mgrs = 2,
+ .num_ovls = 3,
+ .supported_displays = omap3_dss_supported_displays,
+ .supported_color_modes = omap3_dss_supported_color_modes,
+};
+
+/* Functions returning values related to a DSS feature */
+int dss_feat_get_num_mgrs(void)
+{
+ return omap_current_dss_features->num_mgrs;
+}
+
+int dss_feat_get_num_ovls(void)
+{
+ return omap_current_dss_features->num_ovls;
+}
+
+enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel)
+{
+ return omap_current_dss_features->supported_displays[channel];
+}
+
+enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane)
+{
+ return omap_current_dss_features->supported_color_modes[plane];
+}
+
+/* DSS has_feature check */
+bool dss_has_feature(enum dss_feat_id id)
+{
+ return omap_current_dss_features->has_feature & id;
+}
+
+void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end)
+{
+ if (id >= omap_current_dss_features->num_reg_fields)
+ BUG();
+
+ *start = omap_current_dss_features->reg_fields[id].start;
+ *end = omap_current_dss_features->reg_fields[id].end;
+}
+
+void dss_features_init(void)
+{
+ if (cpu_is_omap24xx())
+ omap_current_dss_features = &omap2_dss_features;
+ else
+ omap_current_dss_features = &omap3_dss_features;
+}
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
new file mode 100644
index 000000000000..cb231eaa9b31
--- /dev/null
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -0,0 +1,50 @@
+/*
+ * linux/drivers/video/omap2/dss/dss_features.h
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Archit Taneja <archit@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OMAP2_DSS_FEATURES_H
+#define __OMAP2_DSS_FEATURES_H
+
+#define MAX_DSS_MANAGERS 2
+#define MAX_DSS_OVERLAYS 3
+
+/* DSS has feature id */
+enum dss_feat_id {
+ FEAT_GLOBAL_ALPHA = 1 << 0,
+ FEAT_GLOBAL_ALPHA_VID1 = 1 << 1,
+};
+
+/* DSS register field id */
+enum dss_feat_reg_field {
+ FEAT_REG_FIRHINC,
+ FEAT_REG_FIRVINC,
+ FEAT_REG_FIFOHIGHTHRESHOLD,
+ FEAT_REG_FIFOLOWTHRESHOLD,
+ FEAT_REG_FIFOSIZE,
+};
+
+/* DSS Feature Functions */
+int dss_feat_get_num_mgrs(void);
+int dss_feat_get_num_ovls(void);
+enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
+enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
+
+bool dss_has_feature(enum dss_feat_id id);
+void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
+void dss_features_init(void);
+#endif
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index 6a649ab5539e..545e9b9a4d92 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -33,6 +33,7 @@
#include <plat/cpu.h>
#include "dss.h"
+#include "dss_features.h"
static int num_managers;
static struct list_head manager_list;
@@ -448,8 +449,8 @@ struct manager_cache_data {
static struct {
spinlock_t lock;
- struct overlay_cache_data overlay_cache[3];
- struct manager_cache_data manager_cache[2];
+ struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS];
+ struct manager_cache_data manager_cache[MAX_DSS_MANAGERS];
bool irq_enabled;
} dss_cache;
@@ -882,12 +883,12 @@ static int configure_dispc(void)
{
struct overlay_cache_data *oc;
struct manager_cache_data *mc;
- const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
- const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
+ const int num_ovls = dss_feat_get_num_ovls();
+ const int num_mgrs = dss_feat_get_num_mgrs();
int i;
int r;
- bool mgr_busy[2];
- bool mgr_go[2];
+ bool mgr_busy[MAX_DSS_MANAGERS];
+ bool mgr_go[MAX_DSS_MANAGERS];
bool busy;
r = 0;
@@ -989,7 +990,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
{
struct overlay_cache_data *oc;
struct manager_cache_data *mc;
- const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
+ const int num_ovls = dss_feat_get_num_ovls();
struct omap_overlay_manager *mgr;
int i;
u16 x, y, w, h;
@@ -1121,8 +1122,8 @@ void dss_start_update(struct omap_dss_device *dssdev)
{
struct manager_cache_data *mc;
struct overlay_cache_data *oc;
- const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
- const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
+ const int num_ovls = dss_feat_get_num_ovls();
+ const int num_mgrs = dss_feat_get_num_mgrs();
struct omap_overlay_manager *mgr;
int i;
@@ -1151,10 +1152,10 @@ static void dss_apply_irq_handler(void *data, u32 mask)
{
struct manager_cache_data *mc;
struct overlay_cache_data *oc;
- const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
- const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
+ const int num_ovls = dss_feat_get_num_ovls();
+ const int num_mgrs = dss_feat_get_num_mgrs();
int i, r;
- bool mgr_busy[2];
+ bool mgr_busy[MAX_DSS_MANAGERS];
mgr_busy[0] = dispc_go_busy(0);
mgr_busy[1] = dispc_go_busy(1);
@@ -1461,7 +1462,7 @@ int dss_init_overlay_managers(struct platform_device *pdev)
num_managers = 0;
- for (i = 0; i < 2; ++i) {
+ for (i = 0; i < dss_feat_get_num_mgrs(); ++i) {
struct omap_overlay_manager *mgr;
mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
@@ -1471,14 +1472,10 @@ int dss_init_overlay_managers(struct platform_device *pdev)
case 0:
mgr->name = "lcd";
mgr->id = OMAP_DSS_CHANNEL_LCD;
- mgr->supported_displays =
- OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
- OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI;
break;
case 1:
mgr->name = "tv";
mgr->id = OMAP_DSS_CHANNEL_DIGIT;
- mgr->supported_displays = OMAP_DISPLAY_TYPE_VENC;
break;
}
@@ -1494,6 +1491,8 @@ int dss_init_overlay_managers(struct platform_device *pdev)
mgr->disable = &dss_mgr_disable;
mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC;
+ mgr->supported_displays =
+ dss_feat_get_supported_displays(mgr->id);
dss_overlay_setup_dispc_manager(mgr);
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
index 244dca81a399..75642c22cac7 100644
--- a/drivers/video/omap2/dss/overlay.c
+++ b/drivers/video/omap2/dss/overlay.c
@@ -35,6 +35,7 @@
#include <plat/cpu.h>
#include "dss.h"
+#include "dss_features.h"
static int num_overlays;
static struct list_head overlay_list;
@@ -237,7 +238,8 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
/* Video1 plane does not support global alpha
* to always make it 255 completely opaque
*/
- if (ovl->id == OMAP_DSS_VIDEO1)
+ if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
+ ovl->id == OMAP_DSS_VIDEO1)
info.global_alpha = 255;
else
info.global_alpha = simple_strtoul(buf, NULL, 10);
@@ -510,11 +512,11 @@ static void omap_dss_add_overlay(struct omap_overlay *overlay)
list_add_tail(&overlay->list, &overlay_list);
}
-static struct omap_overlay *dispc_overlays[3];
+static struct omap_overlay *dispc_overlays[MAX_DSS_OVERLAYS];
void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr)
{
- mgr->num_overlays = 3;
+ mgr->num_overlays = dss_feat_get_num_ovls();
mgr->overlays = dispc_overlays;
}
@@ -535,7 +537,7 @@ void dss_init_overlays(struct platform_device *pdev)
num_overlays = 0;
- for (i = 0; i < 3; ++i) {
+ for (i = 0; i < dss_feat_get_num_ovls(); ++i) {
struct omap_overlay *ovl;
ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
@@ -545,18 +547,12 @@ void dss_init_overlays(struct platform_device *pdev)
case 0:
ovl->name = "gfx";
ovl->id = OMAP_DSS_GFX;
- ovl->supported_modes = cpu_is_omap34xx() ?
- OMAP_DSS_COLOR_GFX_OMAP3 :
- OMAP_DSS_COLOR_GFX_OMAP2;
ovl->caps = OMAP_DSS_OVL_CAP_DISPC;
ovl->info.global_alpha = 255;
break;
case 1:
ovl->name = "vid1";
ovl->id = OMAP_DSS_VIDEO1;
- ovl->supported_modes = cpu_is_omap34xx() ?
- OMAP_DSS_COLOR_VID1_OMAP3 :
- OMAP_DSS_COLOR_VID_OMAP2;
ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
OMAP_DSS_OVL_CAP_DISPC;
ovl->info.global_alpha = 255;
@@ -564,9 +560,6 @@ void dss_init_overlays(struct platform_device *pdev)
case 2:
ovl->name = "vid2";
ovl->id = OMAP_DSS_VIDEO2;
- ovl->supported_modes = cpu_is_omap34xx() ?
- OMAP_DSS_COLOR_VID2_OMAP3 :
- OMAP_DSS_COLOR_VID_OMAP2;
ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
OMAP_DSS_OVL_CAP_DISPC;
ovl->info.global_alpha = 255;
@@ -579,6 +572,9 @@ void dss_init_overlays(struct platform_device *pdev)
ovl->get_overlay_info = &dss_ovl_get_overlay_info;
ovl->wait_for_go = &dss_ovl_wait_for_go;
+ ovl->supported_modes =
+ dss_feat_get_supported_color_modes(ovl->id);
+
omap_dss_add_overlay(ovl);
r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
@@ -651,7 +647,7 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
}
if (mgr) {
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < dss_feat_get_num_ovls(); i++) {
struct omap_overlay *ovl;
ovl = omap_dss_get_overlay(i);
if (!ovl->manager || force) {
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
index 43496d6c377f..65149b22cf37 100644
--- a/drivers/video/omap2/omapfb/Kconfig
+++ b/drivers/video/omap2/omapfb/Kconfig
@@ -3,7 +3,7 @@ menuconfig FB_OMAP2
depends on FB && OMAP2_DSS
select OMAP2_VRAM
- select OMAP2_VRFB
+ select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 04034d410d6d..6a704f176c22 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -714,10 +714,10 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
var->pixclock = timings.pixel_clock != 0 ?
KHZ2PICOS(timings.pixel_clock) :
0;
- var->left_margin = timings.hfp;
- var->right_margin = timings.hbp;
- var->upper_margin = timings.vfp;
- var->lower_margin = timings.vbp;
+ var->left_margin = timings.hbp;
+ var->right_margin = timings.hfp;
+ var->upper_margin = timings.vbp;
+ var->lower_margin = timings.vfp;
var->hsync_len = timings.hsw;
var->vsync_len = timings.vsw;
} else {
@@ -2059,10 +2059,10 @@ static int omapfb_mode_to_timings(const char *mode_str,
if (r != 0) {
timings->pixel_clock = PICOS2KHZ(var.pixclock);
- timings->hfp = var.left_margin;
- timings->hbp = var.right_margin;
- timings->vfp = var.upper_margin;
- timings->vbp = var.lower_margin;
+ timings->hbp = var.left_margin;
+ timings->hfp = var.right_margin;
+ timings->vbp = var.upper_margin;
+ timings->vfp = var.lower_margin;
timings->hsw = var.hsync_len;
timings->vsw = var.vsync_len;
timings->x_res = var.xres;
@@ -2198,6 +2198,16 @@ static int omapfb_probe(struct platform_device *pdev)
goto err0;
}
+ /* TODO : Replace cpu check with omap_has_vrfb once HAS_FEATURE
+ * available for OMAP2 and OMAP3
+ */
+ if (def_vrfb && !cpu_is_omap24xx() && !cpu_is_omap34xx()) {
+ def_vrfb = 0;
+ dev_warn(&pdev->dev, "VRFB is not supported on this hardware, "
+ "ignoring the module parameter vrfb=y\n");
+ }
+
+
mutex_init(&fbdev->mtx);
fbdev->dev = &pdev->dev;
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c
index ed371c868b3a..b16e6138fdd4 100644
--- a/drivers/video/savage/savagefb-i2c.c
+++ b/drivers/video/savage/savagefb-i2c.c
@@ -181,6 +181,15 @@ void savagefb_create_i2c_busses(struct fb_info *info)
par->chan.algo.getscl = prosavage_gpio_getscl;
break;
case FB_ACCEL_SAVAGE4:
+ par->chan.reg = CR_SERIAL1;
+ if (par->pcidev->revision > 1 && !(VGArCR(0xa6, par) & 0x40))
+ par->chan.reg = CR_SERIAL2;
+ par->chan.ioaddr = par->mmio.vbase;
+ par->chan.algo.setsda = prosavage_gpio_setsda;
+ par->chan.algo.setscl = prosavage_gpio_setscl;
+ par->chan.algo.getsda = prosavage_gpio_getsda;
+ par->chan.algo.getscl = prosavage_gpio_getscl;
+ break;
case FB_ACCEL_SAVAGE2000:
par->chan.reg = 0xff20;
par->chan.ioaddr = par->mmio.vbase;
diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h
index 8bfdfc3c5234..e4c3f214eb8e 100644
--- a/drivers/video/savage/savagefb.h
+++ b/drivers/video/savage/savagefb.h
@@ -13,7 +13,6 @@
#define __SAVAGEFB_H__
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
#include <linux/mutex.h>
#include <video/vga.h>
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index 2fde08cc66bf..ef989d94511c 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -22,6 +22,8 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/workqueue.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
#include <video/sh_mobile_hdmi.h>
#include <video/sh_mobile_lcdc.h>
@@ -222,6 +224,58 @@ static u8 hdmi_read(struct sh_hdmi *hdmi, u8 reg)
return ioread8(hdmi->base + reg);
}
+/*
+ * HDMI sound
+ */
+static unsigned int sh_hdmi_snd_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
+
+ return hdmi_read(hdmi, reg);
+}
+
+static int sh_hdmi_snd_write(struct snd_soc_codec *codec,
+ unsigned int reg,
+ unsigned int value)
+{
+ struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
+
+ hdmi_write(hdmi, value, reg);
+ return 0;
+}
+
+static struct snd_soc_dai_driver sh_hdmi_dai = {
+ .name = "sh_mobile_hdmi-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+};
+
+static int sh_hdmi_snd_probe(struct snd_soc_codec *codec)
+{
+ dev_info(codec->dev, "SH Mobile HDMI Audio Codec");
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = {
+ .probe = sh_hdmi_snd_probe,
+ .read = sh_hdmi_snd_read,
+ .write = sh_hdmi_snd_write,
+};
+
+/*
+ * HDMI video
+ */
+
/* External video parameter settings */
static void hdmi_external_video_param(struct sh_hdmi *hdmi)
{
@@ -318,6 +372,9 @@ static void sh_hdmi_video_config(struct sh_hdmi *hdmi)
*/
static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
{
+ u8 data;
+ struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
+
/*
* [7:4] L/R data swap control
* [3:0] appropriate N[19:16]
@@ -335,7 +392,23 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
* [6:5] set required down sampling rate if required
* [4:3] set required audio source
*/
- hdmi_write(hdmi, 0x00, HDMI_AUDIO_SETTING_1);
+ switch (pdata->flags & HDMI_SND_SRC_MASK) {
+ default:
+ /* fall through */
+ case HDMI_SND_SRC_I2S:
+ data = 0x0 << 3;
+ break;
+ case HDMI_SND_SRC_SPDIF:
+ data = 0x1 << 3;
+ break;
+ case HDMI_SND_SRC_DSD:
+ data = 0x2 << 3;
+ break;
+ case HDMI_SND_SRC_HBR:
+ data = 0x3 << 3;
+ break;
+ }
+ hdmi_write(hdmi, data, HDMI_AUDIO_SETTING_1);
/* [3:0] set sending channel number for channel status */
hdmi_write(hdmi, 0x40, HDMI_AUDIO_SETTING_2);
@@ -891,6 +964,11 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ ret = snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1);
+ if (ret < 0)
+ goto esndreg;
+
hdmi->dev = &pdev->dev;
hdmi->hdmi_clk = clk_get(&pdev->dev, "ick");
@@ -976,6 +1054,8 @@ eclkenable:
erate:
clk_put(hdmi->hdmi_clk);
egetclk:
+ snd_soc_unregister_codec(&pdev->dev);
+esndreg:
kfree(hdmi);
return ret;
@@ -988,6 +1068,8 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
int irq = platform_get_irq(pdev, 0);
+ snd_soc_unregister_codec(&pdev->dev);
+
pdata->lcd_chan->board_cfg.display_on = NULL;
pdata->lcd_chan->board_cfg.display_off = NULL;
pdata->lcd_chan->board_cfg.board_data = NULL;
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index d72075a9f01c..7a1419279c8f 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1243,8 +1243,10 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
if (priv->ch[i].sglist)
vfree(priv->ch[i].sglist);
- dma_free_coherent(&pdev->dev, info->fix.smem_len,
- info->screen_base, priv->ch[i].dma_handle);
+ if (info->screen_base)
+ dma_free_coherent(&pdev->dev, info->fix.smem_len,
+ info->screen_base,
+ priv->ch[i].dma_handle);
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
}
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 090aa1a9be6e..6a069d047914 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -253,7 +253,7 @@ static int __init vesafb_probe(struct platform_device *dev)
size_vmode = vesafb_defined.yres * vesafb_fix.line_length;
/* size_total -- all video memory we have. Used for mtrr
- * entries, ressource allocation and bounds
+ * entries, resource allocation and bounds
* checking. */
size_total = screen_info.lfb_size * 65536;
if (vram_total)
diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile
index d496adb0f832..96f01ee2a412 100644
--- a/drivers/video/via/Makefile
+++ b/drivers/video/via/Makefile
@@ -5,5 +5,5 @@
obj-$(CONFIG_FB_VIA) += viafb.o
viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o \
- via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o \
+ via_utility.o vt1636.o global.o tblDPASetting.o viamode.o \
via-core.o via-gpio.o via_modesetting.o
diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c
index e44893ea590d..3c969cdef0af 100644
--- a/drivers/video/via/accel.c
+++ b/drivers/video/via/accel.c
@@ -283,11 +283,12 @@ static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
writel(tmp, engine + 0x1C);
}
- if (op != VIA_BITBLT_COLOR)
+ if (op == VIA_BITBLT_FILL) {
+ writel(fg_color, engine + 0x58);
+ } else if (op == VIA_BITBLT_MONO) {
writel(fg_color, engine + 0x4C);
-
- if (op == VIA_BITBLT_MONO)
writel(bg_color, engine + 0x50);
+ }
if (op == VIA_BITBLT_FILL)
ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001;
@@ -314,13 +315,11 @@ static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
return 0;
}
-int viafb_init_engine(struct fb_info *info)
+int viafb_setup_engine(struct fb_info *info)
{
struct viafb_par *viapar = info->par;
void __iomem *engine;
- int highest_reg, i;
- u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high,
- vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name;
+ u32 chip_name = viapar->shared->chip_info.gfx_chip_name;
engine = viapar->shared->vdev->engine_mmio;
if (!engine) {
@@ -329,18 +328,6 @@ int viafb_init_engine(struct fb_info *info)
return -ENOMEM;
}
- /* Initialize registers to reset the 2D engine */
- switch (viapar->shared->chip_info.twod_engine) {
- case VIA_2D_ENG_M1:
- highest_reg = 0x5c;
- break;
- default:
- highest_reg = 0x40;
- break;
- }
- for (i = 0; i <= highest_reg; i += 4)
- writel(0x0, engine + i);
-
switch (chip_name) {
case UNICHROME_CLE266:
case UNICHROME_K400:
@@ -356,6 +343,7 @@ int viafb_init_engine(struct fb_info *info)
break;
case UNICHROME_VX800:
case UNICHROME_VX855:
+ case UNICHROME_VX900:
viapar->shared->hw_bitblt = hw_bitblt_2;
break;
default:
@@ -386,12 +374,36 @@ int viafb_init_engine(struct fb_info *info)
viapar->shared->vdev->camera_fbmem_offset = viapar->fbmem_free;
#endif
+ viafb_reset_engine(viapar);
+ return 0;
+}
+
+void viafb_reset_engine(struct viafb_par *viapar)
+{
+ void __iomem *engine = viapar->shared->vdev->engine_mmio;
+ int highest_reg, i;
+ u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high,
+ vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name;
+
+ /* Initialize registers to reset the 2D engine */
+ switch (viapar->shared->chip_info.twod_engine) {
+ case VIA_2D_ENG_M1:
+ highest_reg = 0x5c;
+ break;
+ default:
+ highest_reg = 0x40;
+ break;
+ }
+ for (i = 0; i <= highest_reg; i += 4)
+ writel(0x0, engine + i);
+
/* Init AGP and VQ regs */
switch (chip_name) {
case UNICHROME_K8M890:
case UNICHROME_P4M900:
case UNICHROME_VX800:
case UNICHROME_VX855:
+ case UNICHROME_VX900:
writel(0x00100000, engine + VIA_REG_CR_TRANSET);
writel(0x680A0000, engine + VIA_REG_CR_TRANSPACE);
writel(0x02000000, engine + VIA_REG_CR_TRANSPACE);
@@ -428,6 +440,7 @@ int viafb_init_engine(struct fb_info *info)
case UNICHROME_P4M900:
case UNICHROME_VX800:
case UNICHROME_VX855:
+ case UNICHROME_VX900:
vq_start_low |= 0x20000000;
vq_end_low |= 0x20000000;
vq_high |= 0x20000000;
@@ -473,7 +486,7 @@ int viafb_init_engine(struct fb_info *info)
writel(0x0, engine + VIA_REG_CURSOR_ORG);
writel(0x0, engine + VIA_REG_CURSOR_BG);
writel(0x0, engine + VIA_REG_CURSOR_FG);
- return 0;
+ return;
}
void viafb_show_hw_cursor(struct fb_info *info, int Status)
diff --git a/drivers/video/via/accel.h b/drivers/video/via/accel.h
index 2c122d292365..79d5e10cc835 100644
--- a/drivers/video/via/accel.h
+++ b/drivers/video/via/accel.h
@@ -203,7 +203,8 @@
#define VIA_BITBLT_MONO 2
#define VIA_BITBLT_FILL 3
-int viafb_init_engine(struct fb_info *info);
+int viafb_setup_engine(struct fb_info *info);
+void viafb_reset_engine(struct viafb_par *viapar);
void viafb_show_hw_cursor(struct fb_info *info, int Status);
void viafb_wait_engine_idle(struct fb_info *info);
diff --git a/drivers/video/via/chip.h b/drivers/video/via/chip.h
index ef1f3de2e052..48f1342897bd 100644
--- a/drivers/video/via/chip.h
+++ b/drivers/video/via/chip.h
@@ -71,6 +71,9 @@
#define UNICHROME_VX855 12
#define UNICHROME_VX855_DID 0x5122
+#define UNICHROME_VX900 13
+#define UNICHROME_VX900_DID 0x7122
+
/**************************************************/
/* Definition TMDS Trasmitter Information */
/**************************************************/
diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c
index 39b040bb3817..84e21b39dd0b 100644
--- a/drivers/video/via/dvi.c
+++ b/drivers/video/via/dvi.c
@@ -25,10 +25,12 @@
static void tmds_register_write(int index, u8 data);
static int tmds_register_read(int index);
static int tmds_register_read_bytes(int index, u8 *buff, int buff_len);
-static void dvi_get_panel_size_from_DDCv1(struct tmds_chip_information
- *tmds_chip, struct tmds_setting_information *tmds_setting);
-static void dvi_get_panel_size_from_DDCv2(struct tmds_chip_information
- *tmds_chip, struct tmds_setting_information *tmds_setting);
+static void __devinit dvi_get_panel_size_from_DDCv1(
+ struct tmds_chip_information *tmds_chip,
+ struct tmds_setting_information *tmds_setting);
+static void __devinit dvi_get_panel_size_from_DDCv2(
+ struct tmds_chip_information *tmds_chip,
+ struct tmds_setting_information *tmds_setting);
static int viafb_dvi_query_EDID(void);
static int check_tmds_chip(int device_id_subaddr, int device_id)
@@ -39,7 +41,7 @@ static int check_tmds_chip(int device_id_subaddr, int device_id)
return FAIL;
}
-void viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
+void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
struct tmds_setting_information *tmds_setting)
{
DEBUG_MSG(KERN_INFO "viafb_init_dvi_size()\n");
@@ -60,7 +62,7 @@ void viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
return;
}
-int viafb_tmds_trasmitter_identify(void)
+int __devinit viafb_tmds_trasmitter_identify(void)
{
unsigned char sr2a = 0, sr1e = 0, sr3e = 0;
@@ -208,8 +210,6 @@ void viafb_dvi_set_mode(struct VideoModeTable *mode, int mode_bpp,
}
}
viafb_fill_crtc_timing(pDviTiming, mode, mode_bpp / 8, set_iga);
- viafb_set_output_path(DEVICE_DVI, set_iga,
- viaparinfo->chip_info->tmds_chip_info.output_interface);
}
/* Sense DVI Connector */
@@ -313,8 +313,9 @@ static int viafb_dvi_query_EDID(void)
}
/* Get Panel Size Using EDID1 Table */
-static void dvi_get_panel_size_from_DDCv1(struct tmds_chip_information
- *tmds_chip, struct tmds_setting_information *tmds_setting)
+static void __devinit dvi_get_panel_size_from_DDCv1(
+ struct tmds_chip_information *tmds_chip,
+ struct tmds_setting_information *tmds_setting)
{
int i, max_h = 0, tmp, restore;
unsigned char rData;
@@ -418,8 +419,9 @@ static void dvi_get_panel_size_from_DDCv1(struct tmds_chip_information
}
/* Get Panel Size Using EDID2 Table */
-static void dvi_get_panel_size_from_DDCv2(struct tmds_chip_information
- *tmds_chip, struct tmds_setting_information *tmds_setting)
+static void __devinit dvi_get_panel_size_from_DDCv2(
+ struct tmds_chip_information *tmds_chip,
+ struct tmds_setting_information *tmds_setting)
{
int restore;
unsigned char R_Buffer[2];
@@ -468,64 +470,107 @@ static void dvi_get_panel_size_from_DDCv2(struct tmds_chip_information
void viafb_dvi_disable(void)
{
if (viaparinfo->chip_info->
- tmds_chip_info.output_interface == INTERFACE_DVP0)
- viafb_write_reg(SR1E, VIASR,
- viafb_read_reg(VIASR, SR1E) & (~0xC0));
-
- if (viaparinfo->chip_info->
- tmds_chip_info.output_interface == INTERFACE_DVP1)
- viafb_write_reg(SR1E, VIASR,
- viafb_read_reg(VIASR, SR1E) & (~0x30));
-
- if (viaparinfo->chip_info->
- tmds_chip_info.output_interface == INTERFACE_DFP_HIGH)
- viafb_write_reg(SR2A, VIASR,
- viafb_read_reg(VIASR, SR2A) & (~0x0C));
-
- if (viaparinfo->chip_info->
- tmds_chip_info.output_interface == INTERFACE_DFP_LOW)
- viafb_write_reg(SR2A, VIASR,
- viafb_read_reg(VIASR, SR2A) & (~0x03));
-
- if (viaparinfo->chip_info->
tmds_chip_info.output_interface == INTERFACE_TMDS)
/* Turn off TMDS power. */
viafb_write_reg(CRD2, VIACR,
viafb_read_reg(VIACR, CRD2) | 0x08);
}
+static void dvi_patch_skew_dvp0(void)
+{
+ /* Reset data driving first: */
+ viafb_write_reg_mask(SR1B, VIASR, 0, BIT1);
+ viafb_write_reg_mask(SR2A, VIASR, 0, BIT4);
+
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_P4M890:
+ {
+ if ((viaparinfo->tmds_setting_info->h_active == 1600) &&
+ (viaparinfo->tmds_setting_info->v_active ==
+ 1200))
+ viafb_write_reg_mask(CR96, VIACR, 0x03,
+ BIT0 + BIT1 + BIT2);
+ else
+ viafb_write_reg_mask(CR96, VIACR, 0x07,
+ BIT0 + BIT1 + BIT2);
+ break;
+ }
+
+ case UNICHROME_P4M900:
+ {
+ viafb_write_reg_mask(CR96, VIACR, 0x07,
+ BIT0 + BIT1 + BIT2 + BIT3);
+ viafb_write_reg_mask(SR1B, VIASR, 0x02, BIT1);
+ viafb_write_reg_mask(SR2A, VIASR, 0x10, BIT4);
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+}
+
+static void dvi_patch_skew_dvp_low(void)
+{
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_K8M890:
+ {
+ viafb_write_reg_mask(CR99, VIACR, 0x03, BIT0 + BIT1);
+ break;
+ }
+
+ case UNICHROME_P4M900:
+ {
+ viafb_write_reg_mask(CR99, VIACR, 0x08,
+ BIT0 + BIT1 + BIT2 + BIT3);
+ break;
+ }
+
+ case UNICHROME_P4M890:
+ {
+ viafb_write_reg_mask(CR99, VIACR, 0x0F,
+ BIT0 + BIT1 + BIT2 + BIT3);
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+}
+
/* If Enable DVI, turn off pad */
void viafb_dvi_enable(void)
{
u8 data;
- if (viaparinfo->chip_info->
- tmds_chip_info.output_interface == INTERFACE_DVP0) {
- viafb_write_reg(SR1E, VIASR,
- viafb_read_reg(VIASR, SR1E) | 0xC0);
+ switch (viaparinfo->chip_info->tmds_chip_info.output_interface) {
+ case INTERFACE_DVP0:
+ viafb_write_reg_mask(CR6B, VIACR, 0x01, BIT0);
+ viafb_write_reg_mask(CR6C, VIACR, 0x21, BIT0 + BIT5);
+ dvi_patch_skew_dvp0();
if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
tmds_register_write(0x88, 0x3b);
else
/*clear CR91[5] to direct on display period
in the secondary diplay path */
- viafb_write_reg(CR91, VIACR,
- viafb_read_reg(VIACR, CR91) & 0xDF);
- }
+ via_write_reg_mask(VIACR, 0x91, 0x00, 0x20);
+ break;
- if (viaparinfo->chip_info->
- tmds_chip_info.output_interface == INTERFACE_DVP1) {
- viafb_write_reg(SR1E, VIASR,
- viafb_read_reg(VIASR, SR1E) | 0x30);
+ case INTERFACE_DVP1:
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
+ viafb_write_reg_mask(CR93, VIACR, 0x21, BIT0 + BIT5);
/*fix dvi cann't be enabled with MB VT5718C4 - Al Zhang */
- if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
tmds_register_write(0x88, 0x3b);
- } else {
+ else
/*clear CR91[5] to direct on display period
in the secondary diplay path */
- viafb_write_reg(CR91, VIACR,
- viafb_read_reg(VIACR, CR91) & 0xDF);
- }
+ via_write_reg_mask(VIACR, 0x91, 0x00, 0x20);
/*fix DVI cannot enable on EPIA-M board */
if (viafb_platform_epia_dvi == 1) {
@@ -537,36 +582,40 @@ void viafb_dvi_enable(void)
else
data = 0x37;
viafb_i2c_writebyte(viaparinfo->chip_info->
- tmds_chip_info.i2c_port,
- viaparinfo->chip_info->
- tmds_chip_info.tmds_chip_slave_addr,
- 0x08, data);
+ tmds_chip_info.i2c_port,
+ viaparinfo->chip_info->
+ tmds_chip_info.tmds_chip_slave_addr,
+ 0x08, data);
}
}
- }
+ break;
- if (viaparinfo->chip_info->
- tmds_chip_info.output_interface == INTERFACE_DFP_HIGH) {
- viafb_write_reg(SR2A, VIASR,
- viafb_read_reg(VIASR, SR2A) | 0x0C);
- viafb_write_reg(CR91, VIACR,
- viafb_read_reg(VIACR, CR91) & 0xDF);
- }
+ case INTERFACE_DFP_HIGH:
+ if (viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266)
+ via_write_reg_mask(VIACR, CR97, 0x03, 0x03);
- if (viaparinfo->chip_info->
- tmds_chip_info.output_interface == INTERFACE_DFP_LOW) {
- viafb_write_reg(SR2A, VIASR,
- viafb_read_reg(VIASR, SR2A) | 0x03);
- viafb_write_reg(CR91, VIACR,
- viafb_read_reg(VIACR, CR91) & 0xDF);
- }
- if (viaparinfo->chip_info->
- tmds_chip_info.output_interface == INTERFACE_TMDS) {
+ via_write_reg_mask(VIACR, 0x91, 0x00, 0x20);
+ break;
+
+ case INTERFACE_DFP_LOW:
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
+ break;
+
+ dvi_patch_skew_dvp_low();
+ via_write_reg_mask(VIACR, 0x91, 0x00, 0x20);
+ break;
+
+ case INTERFACE_TMDS:
/* Turn on Display period in the panel path. */
viafb_write_reg_mask(CR91, VIACR, 0, BIT7);
/* Turn on TMDS power. */
viafb_write_reg_mask(CRD2, VIACR, 0, BIT3);
+ break;
}
-}
+ if (viaparinfo->tmds_setting_info->iga_path == IGA2) {
+ /* Disable LCD Scaling */
+ viafb_write_reg_mask(CR79, VIACR, 0x00, BIT0);
+ }
+}
diff --git a/drivers/video/via/dvi.h b/drivers/video/via/dvi.h
index 0dffcfd395f3..2c525c0c1adb 100644
--- a/drivers/video/via/dvi.h
+++ b/drivers/video/via/dvi.h
@@ -56,8 +56,8 @@
int viafb_dvi_sense(void);
void viafb_dvi_disable(void);
void viafb_dvi_enable(void);
-int viafb_tmds_trasmitter_identify(void);
-void viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
+int __devinit viafb_tmds_trasmitter_identify(void);
+void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
struct tmds_setting_information *tmds_setting);
void viafb_dvi_set_mode(struct VideoModeTable *videoMode, int mode_bpp,
int set_iga);
diff --git a/drivers/video/via/global.h b/drivers/video/via/global.h
index 28221a062dda..38ef5ac66953 100644
--- a/drivers/video/via/global.h
+++ b/drivers/video/via/global.h
@@ -48,7 +48,6 @@
#include "via_utility.h"
#include "vt1636.h"
#include "tblDPASetting.h"
-#include "tbl1636.h"
/* External struct*/
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index 7dcb4d5bb9c3..36d73f940d8b 100644
--- a/drivers/video/via/hw.c
+++ b/drivers/video/via/hw.c
@@ -718,16 +718,20 @@ static struct rgbLUT palLUT_table[] = {
0x00}
};
-static void set_crt_output_path(int set_iga);
-static void dvi_patch_skew_dvp0(void);
-static void dvi_patch_skew_dvp1(void);
-static void dvi_patch_skew_dvp_low(void);
-static void set_dvi_output_path(int set_iga, int output_interface);
-static void set_lcd_output_path(int set_iga, int output_interface);
+static struct via_device_mapping device_mapping[] = {
+ {VIA_LDVP0, "LDVP0"},
+ {VIA_LDVP1, "LDVP1"},
+ {VIA_DVP0, "DVP0"},
+ {VIA_CRT, "CRT"},
+ {VIA_DVP1, "DVP1"},
+ {VIA_LVDS1, "LVDS1"},
+ {VIA_LVDS2, "LVDS2"}
+};
+
static void load_fix_bit_crtc_reg(void);
-static void init_gfx_chip_info(int chip_type);
-static void init_tmds_chip_info(void);
-static void init_lvds_chip_info(void);
+static void __devinit init_gfx_chip_info(int chip_type);
+static void __devinit init_tmds_chip_info(void);
+static void __devinit init_lvds_chip_info(void);
static void device_screen_off(void);
static void device_screen_on(void);
static void set_display_channel(void);
@@ -755,6 +759,66 @@ void write_dac_reg(u8 index, u8 r, u8 g, u8 b)
outb(b, LUT_DATA);
}
+static u32 get_dvi_devices(int output_interface)
+{
+ switch (output_interface) {
+ case INTERFACE_DVP0:
+ return VIA_DVP0 | VIA_LDVP0;
+
+ case INTERFACE_DVP1:
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
+ return VIA_LDVP1;
+ else
+ return VIA_DVP1;
+
+ case INTERFACE_DFP_HIGH:
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
+ return 0;
+ else
+ return VIA_LVDS2 | VIA_DVP0;
+
+ case INTERFACE_DFP_LOW:
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
+ return 0;
+ else
+ return VIA_DVP1 | VIA_LVDS1;
+
+ case INTERFACE_TMDS:
+ return VIA_LVDS1;
+ }
+
+ return 0;
+}
+
+static u32 get_lcd_devices(int output_interface)
+{
+ switch (output_interface) {
+ case INTERFACE_DVP0:
+ return VIA_DVP0;
+
+ case INTERFACE_DVP1:
+ return VIA_DVP1;
+
+ case INTERFACE_DFP_HIGH:
+ return VIA_LVDS2 | VIA_DVP0;
+
+ case INTERFACE_DFP_LOW:
+ return VIA_LVDS1 | VIA_DVP1;
+
+ case INTERFACE_DFP:
+ return VIA_LVDS1 | VIA_LVDS2;
+
+ case INTERFACE_LVDS0:
+ case INTERFACE_LVDS0LVDS1:
+ return VIA_LVDS1;
+
+ case INTERFACE_LVDS1:
+ return VIA_LVDS2;
+ }
+
+ return 0;
+}
+
/*Set IGA path for each device*/
void viafb_set_iga_path(void)
{
@@ -821,6 +885,48 @@ void viafb_set_iga_path(void)
viaparinfo->tmds_setting_info->iga_path = IGA1;
}
}
+
+ viaparinfo->shared->iga1_devices = 0;
+ viaparinfo->shared->iga2_devices = 0;
+ if (viafb_CRT_ON) {
+ if (viaparinfo->crt_setting_info->iga_path == IGA1)
+ viaparinfo->shared->iga1_devices |= VIA_CRT;
+ else
+ viaparinfo->shared->iga2_devices |= VIA_CRT;
+ }
+
+ if (viafb_DVI_ON) {
+ if (viaparinfo->tmds_setting_info->iga_path == IGA1)
+ viaparinfo->shared->iga1_devices |= get_dvi_devices(
+ viaparinfo->chip_info->
+ tmds_chip_info.output_interface);
+ else
+ viaparinfo->shared->iga2_devices |= get_dvi_devices(
+ viaparinfo->chip_info->
+ tmds_chip_info.output_interface);
+ }
+
+ if (viafb_LCD_ON) {
+ if (viaparinfo->lvds_setting_info->iga_path == IGA1)
+ viaparinfo->shared->iga1_devices |= get_lcd_devices(
+ viaparinfo->chip_info->
+ lvds_chip_info.output_interface);
+ else
+ viaparinfo->shared->iga2_devices |= get_lcd_devices(
+ viaparinfo->chip_info->
+ lvds_chip_info.output_interface);
+ }
+
+ if (viafb_LCD2_ON) {
+ if (viaparinfo->lvds_setting_info2->iga_path == IGA1)
+ viaparinfo->shared->iga1_devices |= get_lcd_devices(
+ viaparinfo->chip_info->
+ lvds_chip_info2.output_interface);
+ else
+ viaparinfo->shared->iga2_devices |= get_lcd_devices(
+ viaparinfo->chip_info->
+ lvds_chip_info2.output_interface);
+ }
}
static void set_color_register(u8 index, u8 red, u8 green, u8 blue)
@@ -844,295 +950,266 @@ void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue)
set_color_register(index, red, green, blue);
}
-void viafb_set_output_path(int device, int set_iga, int output_interface)
+static void set_source_common(u8 index, u8 offset, u8 iga)
{
- switch (device) {
- case DEVICE_CRT:
- set_crt_output_path(set_iga);
- break;
- case DEVICE_DVI:
- set_dvi_output_path(set_iga, output_interface);
+ u8 value, mask = 1 << offset;
+
+ switch (iga) {
+ case IGA1:
+ value = 0x00;
break;
- case DEVICE_LCD:
- set_lcd_output_path(set_iga, output_interface);
+ case IGA2:
+ value = mask;
break;
+ default:
+ printk(KERN_WARNING "viafb: Unsupported source: %d\n", iga);
+ return;
}
+
+ via_write_reg_mask(VIACR, index, value, mask);
}
-static void set_crt_output_path(int set_iga)
+static void set_crt_source(u8 iga)
{
- viafb_write_reg_mask(CR36, VIACR, 0x00, BIT4 + BIT5);
+ u8 value;
- switch (set_iga) {
+ switch (iga) {
case IGA1:
- viafb_write_reg_mask(SR16, VIASR, 0x00, BIT6);
+ value = 0x00;
break;
case IGA2:
- viafb_write_reg_mask(CR6A, VIACR, 0xC0, BIT6 + BIT7);
- viafb_write_reg_mask(SR16, VIASR, 0x40, BIT6);
+ value = 0x40;
break;
+ default:
+ printk(KERN_WARNING "viafb: Unsupported source: %d\n", iga);
+ return;
}
+
+ via_write_reg_mask(VIASR, 0x16, value, 0x40);
}
-static void dvi_patch_skew_dvp0(void)
+static inline void set_ldvp0_source(u8 iga)
{
- /* Reset data driving first: */
- viafb_write_reg_mask(SR1B, VIASR, 0, BIT1);
- viafb_write_reg_mask(SR2A, VIASR, 0, BIT4);
-
- switch (viaparinfo->chip_info->gfx_chip_name) {
- case UNICHROME_P4M890:
- {
- if ((viaparinfo->tmds_setting_info->h_active == 1600) &&
- (viaparinfo->tmds_setting_info->v_active ==
- 1200))
- viafb_write_reg_mask(CR96, VIACR, 0x03,
- BIT0 + BIT1 + BIT2);
- else
- viafb_write_reg_mask(CR96, VIACR, 0x07,
- BIT0 + BIT1 + BIT2);
- break;
- }
+ set_source_common(0x6C, 7, iga);
+}
- case UNICHROME_P4M900:
- {
- viafb_write_reg_mask(CR96, VIACR, 0x07,
- BIT0 + BIT1 + BIT2 + BIT3);
- viafb_write_reg_mask(SR1B, VIASR, 0x02, BIT1);
- viafb_write_reg_mask(SR2A, VIASR, 0x10, BIT4);
- break;
- }
+static inline void set_ldvp1_source(u8 iga)
+{
+ set_source_common(0x93, 7, iga);
+}
- default:
- {
- break;
- }
- }
+static inline void set_dvp0_source(u8 iga)
+{
+ set_source_common(0x96, 4, iga);
}
-static void dvi_patch_skew_dvp1(void)
+static inline void set_dvp1_source(u8 iga)
{
- switch (viaparinfo->chip_info->gfx_chip_name) {
- case UNICHROME_CX700:
- {
- break;
- }
+ set_source_common(0x9B, 4, iga);
+}
- default:
- {
- break;
- }
- }
+static inline void set_lvds1_source(u8 iga)
+{
+ set_source_common(0x99, 4, iga);
}
-static void dvi_patch_skew_dvp_low(void)
+static inline void set_lvds2_source(u8 iga)
{
- switch (viaparinfo->chip_info->gfx_chip_name) {
- case UNICHROME_K8M890:
- {
- viafb_write_reg_mask(CR99, VIACR, 0x03, BIT0 + BIT1);
- break;
- }
+ set_source_common(0x97, 4, iga);
+}
- case UNICHROME_P4M900:
- {
- viafb_write_reg_mask(CR99, VIACR, 0x08,
- BIT0 + BIT1 + BIT2 + BIT3);
- break;
- }
+void via_set_source(u32 devices, u8 iga)
+{
+ if (devices & VIA_LDVP0)
+ set_ldvp0_source(iga);
+ if (devices & VIA_LDVP1)
+ set_ldvp1_source(iga);
+ if (devices & VIA_DVP0)
+ set_dvp0_source(iga);
+ if (devices & VIA_CRT)
+ set_crt_source(iga);
+ if (devices & VIA_DVP1)
+ set_dvp1_source(iga);
+ if (devices & VIA_LVDS1)
+ set_lvds1_source(iga);
+ if (devices & VIA_LVDS2)
+ set_lvds2_source(iga);
+}
- case UNICHROME_P4M890:
- {
- viafb_write_reg_mask(CR99, VIACR, 0x0F,
- BIT0 + BIT1 + BIT2 + BIT3);
- break;
- }
+static void set_crt_state(u8 state)
+{
+ u8 value;
+ switch (state) {
+ case VIA_STATE_ON:
+ value = 0x00;
+ break;
+ case VIA_STATE_STANDBY:
+ value = 0x10;
+ break;
+ case VIA_STATE_SUSPEND:
+ value = 0x20;
+ break;
+ case VIA_STATE_OFF:
+ value = 0x30;
+ break;
default:
- {
- break;
- }
+ return;
}
+
+ via_write_reg_mask(VIACR, 0x36, value, 0x30);
}
-static void set_dvi_output_path(int set_iga, int output_interface)
+static void set_dvp0_state(u8 state)
{
- switch (output_interface) {
- case INTERFACE_DVP0:
- viafb_write_reg_mask(CR6B, VIACR, 0x01, BIT0);
-
- if (set_iga == IGA1) {
- viafb_write_reg_mask(CR96, VIACR, 0x00, BIT4);
- viafb_write_reg_mask(CR6C, VIACR, 0x21, BIT0 +
- BIT5 + BIT7);
- } else {
- viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4);
- viafb_write_reg_mask(CR6C, VIACR, 0xA1, BIT0 +
- BIT5 + BIT7);
- }
-
- viafb_write_reg_mask(SR1E, VIASR, 0xC0, BIT7 + BIT6);
+ u8 value;
- dvi_patch_skew_dvp0();
+ switch (state) {
+ case VIA_STATE_ON:
+ value = 0xC0;
break;
+ case VIA_STATE_OFF:
+ value = 0x00;
+ break;
+ default:
+ return;
+ }
- case INTERFACE_DVP1:
- if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
- if (set_iga == IGA1)
- viafb_write_reg_mask(CR93, VIACR, 0x21,
- BIT0 + BIT5 + BIT7);
- else
- viafb_write_reg_mask(CR93, VIACR, 0xA1,
- BIT0 + BIT5 + BIT7);
- } else {
- if (set_iga == IGA1)
- viafb_write_reg_mask(CR9B, VIACR, 0x00, BIT4);
- else
- viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4);
- }
+ via_write_reg_mask(VIASR, 0x1E, value, 0xC0);
+}
+
+static void set_dvp1_state(u8 state)
+{
+ u8 value;
- viafb_write_reg_mask(SR1E, VIASR, 0x30, BIT4 + BIT5);
- dvi_patch_skew_dvp1();
+ switch (state) {
+ case VIA_STATE_ON:
+ value = 0x30;
break;
- case INTERFACE_DFP_HIGH:
- if (viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266) {
- if (set_iga == IGA1) {
- viafb_write_reg_mask(CR96, VIACR, 0x00, BIT4);
- viafb_write_reg_mask(CR97, VIACR, 0x03,
- BIT0 + BIT1 + BIT4);
- } else {
- viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4);
- viafb_write_reg_mask(CR97, VIACR, 0x13,
- BIT0 + BIT1 + BIT4);
- }
- }
- viafb_write_reg_mask(SR2A, VIASR, 0x0C, BIT2 + BIT3);
+ case VIA_STATE_OFF:
+ value = 0x00;
break;
+ default:
+ return;
+ }
- case INTERFACE_DFP_LOW:
- if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
- break;
+ via_write_reg_mask(VIASR, 0x1E, value, 0x30);
+}
- if (set_iga == IGA1) {
- viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4);
- viafb_write_reg_mask(CR9B, VIACR, 0x00, BIT4);
- } else {
- viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4);
- viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4);
- }
+static void set_lvds1_state(u8 state)
+{
+ u8 value;
- viafb_write_reg_mask(SR2A, VIASR, 0x03, BIT0 + BIT1);
- dvi_patch_skew_dvp_low();
+ switch (state) {
+ case VIA_STATE_ON:
+ value = 0x03;
break;
-
- case INTERFACE_TMDS:
- if (set_iga == IGA1)
- viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4);
- else
- viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4);
+ case VIA_STATE_OFF:
+ value = 0x00;
break;
+ default:
+ return;
}
- if (set_iga == IGA2) {
- enable_second_display_channel();
- /* Disable LCD Scaling */
- viafb_write_reg_mask(CR79, VIACR, 0x00, BIT0);
- }
+ via_write_reg_mask(VIASR, 0x2A, value, 0x03);
}
-static void set_lcd_output_path(int set_iga, int output_interface)
+static void set_lvds2_state(u8 state)
{
- DEBUG_MSG(KERN_INFO
- "set_lcd_output_path, iga:%d,out_interface:%d\n",
- set_iga, output_interface);
- switch (set_iga) {
- case IGA1:
- viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3);
- viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
+ u8 value;
- disable_second_display_channel();
+ switch (state) {
+ case VIA_STATE_ON:
+ value = 0x0C;
break;
-
- case IGA2:
- viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3);
- viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
-
- enable_second_display_channel();
+ case VIA_STATE_OFF:
+ value = 0x00;
break;
+ default:
+ return;
}
- switch (output_interface) {
- case INTERFACE_DVP0:
- if (set_iga == IGA1) {
- viafb_write_reg_mask(CR96, VIACR, 0x00, BIT4);
- } else {
- viafb_write_reg(CR91, VIACR, 0x00);
- viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4);
- }
- break;
-
- case INTERFACE_DVP1:
- if (set_iga == IGA1)
- viafb_write_reg_mask(CR9B, VIACR, 0x00, BIT4);
- else {
- viafb_write_reg(CR91, VIACR, 0x00);
- viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4);
- }
- break;
+ via_write_reg_mask(VIASR, 0x2A, value, 0x0C);
+}
- case INTERFACE_DFP_HIGH:
- if (set_iga == IGA1)
- viafb_write_reg_mask(CR97, VIACR, 0x00, BIT4);
- else {
- viafb_write_reg(CR91, VIACR, 0x00);
- viafb_write_reg_mask(CR97, VIACR, 0x10, BIT4);
- viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4);
- }
- break;
+void via_set_state(u32 devices, u8 state)
+{
+ /*
+ TODO: Can we enable/disable these devices? How?
+ if (devices & VIA_LDVP0)
+ if (devices & VIA_LDVP1)
+ */
+ if (devices & VIA_DVP0)
+ set_dvp0_state(state);
+ if (devices & VIA_CRT)
+ set_crt_state(state);
+ if (devices & VIA_DVP1)
+ set_dvp1_state(state);
+ if (devices & VIA_LVDS1)
+ set_lvds1_state(state);
+ if (devices & VIA_LVDS2)
+ set_lvds2_state(state);
+}
- case INTERFACE_DFP_LOW:
- if (set_iga == IGA1)
- viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4);
- else {
- viafb_write_reg(CR91, VIACR, 0x00);
- viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4);
- viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4);
- }
+void via_set_sync_polarity(u32 devices, u8 polarity)
+{
+ if (polarity & ~(VIA_HSYNC_NEGATIVE | VIA_VSYNC_NEGATIVE)) {
+ printk(KERN_WARNING "viafb: Unsupported polarity: %d\n",
+ polarity);
+ return;
+ }
- break;
+ if (devices & VIA_CRT)
+ via_write_misc_reg_mask(polarity << 6, 0xC0);
+ if (devices & VIA_DVP1)
+ via_write_reg_mask(VIACR, 0x9B, polarity << 5, 0x60);
+ if (devices & VIA_LVDS1)
+ via_write_reg_mask(VIACR, 0x99, polarity << 5, 0x60);
+ if (devices & VIA_LVDS2)
+ via_write_reg_mask(VIACR, 0x97, polarity << 5, 0x60);
+}
- case INTERFACE_DFP:
- if ((UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name)
- || (UNICHROME_P4M890 ==
- viaparinfo->chip_info->gfx_chip_name))
- viafb_write_reg_mask(CR97, VIACR, 0x84,
- BIT7 + BIT2 + BIT1 + BIT0);
- if (set_iga == IGA1) {
- viafb_write_reg_mask(CR97, VIACR, 0x00, BIT4);
- viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4);
- } else {
- viafb_write_reg(CR91, VIACR, 0x00);
- viafb_write_reg_mask(CR97, VIACR, 0x10, BIT4);
- viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4);
+u32 via_parse_odev(char *input, char **end)
+{
+ char *ptr = input;
+ u32 odev = 0;
+ bool next = true;
+ int i, len;
+
+ while (next) {
+ next = false;
+ for (i = 0; i < ARRAY_SIZE(device_mapping); i++) {
+ len = strlen(device_mapping[i].name);
+ if (!strncmp(ptr, device_mapping[i].name, len)) {
+ odev |= device_mapping[i].device;
+ ptr += len;
+ if (*ptr == ',') {
+ ptr++;
+ next = true;
+ }
+ }
}
- break;
+ }
- case INTERFACE_LVDS0:
- case INTERFACE_LVDS0LVDS1:
- if (set_iga == IGA1)
- viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4);
- else
- viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4);
+ *end = ptr;
+ return odev;
+}
- break;
+void via_odev_to_seq(struct seq_file *m, u32 odev)
+{
+ int i, count = 0;
- case INTERFACE_LVDS1:
- if (set_iga == IGA1)
- viafb_write_reg_mask(CR97, VIACR, 0x00, BIT4);
- else
- viafb_write_reg_mask(CR97, VIACR, 0x10, BIT4);
- break;
+ for (i = 0; i < ARRAY_SIZE(device_mapping); i++) {
+ if (odev & device_mapping[i].device) {
+ if (count > 0)
+ seq_putc(m, ',');
+
+ seq_puts(m, device_mapping[i].name);
+ count++;
+ }
}
+
+ seq_putc(m, '\n');
}
static void load_fix_bit_crtc_reg(void)
@@ -1352,6 +1429,15 @@ void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active)
VX855_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
}
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX900) {
+ iga1_fifo_max_depth = VX900_IGA1_FIFO_MAX_DEPTH;
+ iga1_fifo_threshold = VX900_IGA1_FIFO_THRESHOLD;
+ iga1_fifo_high_threshold =
+ VX900_IGA1_FIFO_HIGH_THRESHOLD;
+ iga1_display_queue_expire_num =
+ VX900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
/* Set Display FIFO Depath Select */
reg_value = IGA1_FIFO_DEPTH_SELECT_FORMULA(iga1_fifo_max_depth);
viafb_load_reg_num =
@@ -1492,6 +1578,15 @@ void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active)
VX855_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
}
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX900) {
+ iga2_fifo_max_depth = VX900_IGA2_FIFO_MAX_DEPTH;
+ iga2_fifo_threshold = VX900_IGA2_FIFO_THRESHOLD;
+ iga2_fifo_high_threshold =
+ VX900_IGA2_FIFO_HIGH_THRESHOLD;
+ iga2_display_queue_expire_num =
+ VX900_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) {
/* Set Display FIFO Depath Select */
reg_value =
@@ -1612,6 +1707,7 @@ u32 viafb_get_clk_value(int clk)
break;
case UNICHROME_VX855:
+ case UNICHROME_VX900:
value = vx855_encode_pll(pll_value[i].vx855_pll);
break;
}
@@ -1645,6 +1741,7 @@ void viafb_set_vclock(u32 clk, int set_iga)
case UNICHROME_P4M900:
case UNICHROME_VX800:
case UNICHROME_VX855:
+ case UNICHROME_VX900:
via_write_reg(VIASR, SR44, (clk & 0x0000FF));
via_write_reg(VIASR, SR45, (clk & 0x00FF00) >> 8);
via_write_reg(VIASR, SR46, (clk & 0xFF0000) >> 16);
@@ -1671,6 +1768,7 @@ void viafb_set_vclock(u32 clk, int set_iga)
case UNICHROME_P4M900:
case UNICHROME_VX800:
case UNICHROME_VX855:
+ case UNICHROME_VX900:
via_write_reg(VIASR, SR4A, (clk & 0x0000FF));
via_write_reg(VIASR, SR4B, (clk & 0x00FF00) >> 8);
via_write_reg(VIASR, SR4C, (clk & 0xFF0000) >> 16);
@@ -1688,8 +1786,8 @@ void viafb_set_vclock(u32 clk, int set_iga)
}
if (set_iga == IGA2) {
- viafb_write_reg_mask(SR40, VIASR, 0x01, BIT0);
- viafb_write_reg_mask(SR40, VIASR, 0x00, BIT0);
+ viafb_write_reg_mask(SR40, VIASR, 0x04, BIT2);
+ viafb_write_reg_mask(SR40, VIASR, 0x00, BIT2);
}
/* Fire! */
@@ -1937,7 +2035,6 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
int index = 0;
int h_addr, v_addr;
u32 pll_D_N;
- u8 polarity = 0;
for (i = 0; i < video_mode->mode_array; i++) {
index = i;
@@ -1964,14 +2061,6 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
h_addr = crt_reg.hor_addr;
v_addr = crt_reg.ver_addr;
-
- /* update polarity for CRT timing */
- if (crt_table[index].h_sync_polarity == NEGATIVE)
- polarity |= BIT6;
- if (crt_table[index].v_sync_polarity == NEGATIVE)
- polarity |= BIT7;
- via_write_misc_reg_mask(polarity, BIT6 | BIT7);
-
if (set_iga == IGA1) {
viafb_unlock_crt();
viafb_write_reg(CR09, VIACR, 0x00); /*initial CR09=0 */
@@ -2004,7 +2093,7 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
}
-void viafb_init_chip_info(int chip_type)
+void __devinit viafb_init_chip_info(int chip_type)
{
init_gfx_chip_info(chip_type);
init_tmds_chip_info();
@@ -2071,7 +2160,7 @@ void viafb_update_device_setting(int hres, int vres,
}
}
-static void init_gfx_chip_info(int chip_type)
+static void __devinit init_gfx_chip_info(int chip_type)
{
u8 tmp;
@@ -2111,6 +2200,7 @@ static void init_gfx_chip_info(int chip_type)
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_VX800:
case UNICHROME_VX855:
+ case UNICHROME_VX900:
viaparinfo->chip_info->twod_engine = VIA_2D_ENG_M1;
break;
case UNICHROME_K8M890:
@@ -2123,7 +2213,7 @@ static void init_gfx_chip_info(int chip_type)
}
}
-static void init_tmds_chip_info(void)
+static void __devinit init_tmds_chip_info(void)
{
viafb_tmds_trasmitter_identify();
@@ -2168,7 +2258,7 @@ static void init_tmds_chip_info(void)
&viaparinfo->shared->tmds_setting_info);
}
-static void init_lvds_chip_info(void)
+static void __devinit init_lvds_chip_info(void)
{
viafb_lvds_trasmitter_identify();
viafb_init_lcd_size();
@@ -2202,7 +2292,7 @@ static void init_lvds_chip_info(void)
viaparinfo->chip_info->lvds_chip_info.output_interface);
}
-void viafb_init_dac(int set_iga)
+void __devinit viafb_init_dac(int set_iga)
{
int i;
u8 tmp;
@@ -2275,11 +2365,24 @@ static void set_display_channel(void)
}
}
+static u8 get_sync(struct fb_info *info)
+{
+ u8 polarity = 0;
+
+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+ polarity |= VIA_HSYNC_NEGATIVE;
+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+ polarity |= VIA_VSYNC_NEGATIVE;
+ return polarity;
+}
+
int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
struct VideoModeTable *vmode_tbl1, int video_bpp1)
{
int i, j;
int port;
+ u32 devices = viaparinfo->shared->iga1_devices
+ | viaparinfo->shared->iga2_devices;
u8 value, index, mask;
struct crt_mode_table *crt_timing;
struct crt_mode_table *crt_timing1 = NULL;
@@ -2322,11 +2425,13 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
break;
case UNICHROME_VX855:
+ case UNICHROME_VX900:
viafb_write_regx(VX855_ModeXregs, NUM_TOTAL_VX855_ModeXregs);
break;
}
device_off();
+ via_set_state(devices, VIA_STATE_OFF);
/* Fill VPIT Parameters */
/* Write Misc Register */
@@ -2337,7 +2442,6 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
via_write_reg(VIASR, i, VPIT.SR[i - 1]);
viafb_write_reg_mask(0x15, VIASR, 0xA2, 0xA2);
- viafb_set_iga_path();
/* Write CRTC */
viafb_fill_crtc_timing(crt_timing, vmode_tbl, video_bpp / 8, IGA1);
@@ -2377,6 +2481,13 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
via_set_primary_color_depth(viaparinfo->depth);
via_set_secondary_color_depth(viafb_dual_fb ? viaparinfo1->depth
: viaparinfo->depth);
+ via_set_source(viaparinfo->shared->iga1_devices, IGA1);
+ via_set_source(viaparinfo->shared->iga2_devices, IGA2);
+ if (viaparinfo->shared->iga2_devices)
+ enable_second_display_channel();
+ else
+ disable_second_display_channel();
+
/* Update Refresh Rate Setting */
/* Clear On Screen */
@@ -2394,8 +2505,6 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
viaparinfo->crt_setting_info->iga_path);
}
- set_crt_output_path(viaparinfo->crt_setting_info->iga_path);
-
/* Patch if set_hres is not 8 alignment (1366) to viafb_setmode
to 8 alignment (1368),there is several pixels (2 pixels)
on right side of screen. */
@@ -2482,10 +2591,16 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
viafb_DeviceStatus = CRT_Device;
}
device_on();
+ if (!viafb_dual_fb)
+ via_set_sync_polarity(devices, get_sync(viafbinfo));
+ else {
+ via_set_sync_polarity(viaparinfo->shared->iga1_devices,
+ get_sync(viafbinfo));
+ via_set_sync_polarity(viaparinfo->shared->iga2_devices,
+ get_sync(viafbinfo1));
+ }
- if (viafb_SAMM_ON == 1)
- viafb_write_reg_mask(CR6A, VIACR, 0xC0, BIT6 + BIT7);
-
+ via_set_state(devices, VIA_STATE_ON);
device_screen_on();
return 1;
}
@@ -2526,31 +2641,18 @@ int viafb_get_refresh(int hres, int vres, u32 long_refresh)
static void device_off(void)
{
- viafb_crt_disable();
viafb_dvi_disable();
viafb_lcd_disable();
}
static void device_on(void)
{
- if (viafb_CRT_ON == 1)
- viafb_crt_enable();
if (viafb_DVI_ON == 1)
viafb_dvi_enable();
if (viafb_LCD_ON == 1)
viafb_lcd_enable();
}
-void viafb_crt_disable(void)
-{
- viafb_write_reg_mask(CR36, VIACR, BIT5 + BIT4, BIT5 + BIT4);
-}
-
-void viafb_crt_enable(void)
-{
- viafb_write_reg_mask(CR36, VIACR, 0x0, BIT5 + BIT4);
-}
-
static void enable_second_display_channel(void)
{
/* to enable second display channel. */
@@ -2567,7 +2669,6 @@ static void disable_second_display_channel(void)
viafb_write_reg_mask(CR6A, VIACR, BIT6, BIT6);
}
-
void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
*p_gfx_dpa_setting)
{
@@ -2652,4 +2753,9 @@ void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
crt_reg.ver_total - (crt_reg.ver_sync_start + crt_reg.ver_sync_end);
var->lower_margin = crt_reg.ver_sync_start - crt_reg.ver_addr;
var->vsync_len = crt_reg.ver_sync_end;
+ var->sync = 0;
+ if (crt_timing[index].h_sync_polarity == POSITIVE)
+ var->sync |= FB_SYNC_HOR_HIGH_ACT;
+ if (crt_timing[index].v_sync_polarity == POSITIVE)
+ var->sync |= FB_SYNC_VERT_HIGH_ACT;
}
diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h
index c44399895294..668d534542ef 100644
--- a/drivers/video/via/hw.h
+++ b/drivers/video/via/hw.h
@@ -22,6 +22,8 @@
#ifndef __HW_H__
#define __HW_H__
+#include <linux/seq_file.h>
+
#include "viamode.h"
#include "global.h"
#include "via_modesetting.h"
@@ -30,6 +32,25 @@
#define viafb_write_reg(i, p, d) via_write_reg(p, i, d)
#define viafb_write_reg_mask(i, p, d, m) via_write_reg_mask(p, i, d, m)
+/* VIA output devices */
+#define VIA_LDVP0 0x00000001
+#define VIA_LDVP1 0x00000002
+#define VIA_DVP0 0x00000004
+#define VIA_CRT 0x00000010
+#define VIA_DVP1 0x00000020
+#define VIA_LVDS1 0x00000040
+#define VIA_LVDS2 0x00000080
+
+/* VIA output device power states */
+#define VIA_STATE_ON 0
+#define VIA_STATE_STANDBY 1
+#define VIA_STATE_SUSPEND 2
+#define VIA_STATE_OFF 3
+
+/* VIA output device sync polarity */
+#define VIA_HSYNC_NEGATIVE 0x01
+#define VIA_VSYNC_NEGATIVE 0x02
+
/***************************************************
* Definition IGA1 Design Method of CRTC Registers *
****************************************************/
@@ -341,6 +362,17 @@ is reserved, so it may have problem to set 1600x1200 on IGA2. */
#define VX855_IGA2_FIFO_HIGH_THRESHOLD 160
#define VX855_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 320
+/* For VT3410 */
+#define VX900_IGA1_FIFO_MAX_DEPTH 400
+#define VX900_IGA1_FIFO_THRESHOLD 320
+#define VX900_IGA1_FIFO_HIGH_THRESHOLD 320
+#define VX900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 160
+
+#define VX900_IGA2_FIFO_MAX_DEPTH 192
+#define VX900_IGA2_FIFO_THRESHOLD 160
+#define VX900_IGA2_FIFO_HIGH_THRESHOLD 160
+#define VX900_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 320
+
#define IGA1_FIFO_DEPTH_SELECT_REG_NUM 1
#define IGA1_FIFO_THRESHOLD_REG_NUM 2
#define IGA1_FIFO_HIGH_THRESHOLD_REG_NUM 2
@@ -858,6 +890,8 @@ struct iga2_crtc_timing {
#define VX800_FUNCTION3 0x3353
/* VT3409 chipset*/
#define VX855_FUNCTION3 0x3409
+/* VT3410 chipset*/
+#define VX900_FUNCTION3 0x3410
#define NUM_TOTAL_PLL_TABLE ARRAY_SIZE(pll_value)
@@ -873,6 +907,11 @@ struct pci_device_id_info {
u32 chip_index;
};
+struct via_device_mapping {
+ u32 device;
+ const char *name;
+};
+
extern unsigned int viafb_second_virtual_xres;
extern int viafb_SAMM_ON;
extern int viafb_dual_fb;
@@ -881,9 +920,6 @@ extern int viafb_LCD_ON;
extern int viafb_DVI_ON;
extern int viafb_hotplug;
-void viafb_set_output_path(int device, int set_iga,
- int output_interface);
-
void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
struct VideoModeTable *video_mode, int bpp_byte, int set_iga);
@@ -891,8 +927,11 @@ void viafb_set_vclock(u32 CLK, int set_iga);
void viafb_load_reg(int timing_value, int viafb_load_reg_num,
struct io_register *reg,
int io_type);
-void viafb_crt_disable(void);
-void viafb_crt_enable(void);
+void via_set_source(u32 devices, u8 iga);
+void via_set_state(u32 devices, u8 state);
+void via_set_sync_polarity(u32 devices, u8 polarity);
+u32 via_parse_odev(char *input, char **end);
+void via_odev_to_seq(struct seq_file *m, u32 odev);
void init_ad9389(void);
/* Access I/O Function */
void viafb_lock_crt(void);
@@ -908,8 +947,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
struct VideoModeTable *vmode_tbl1, int video_bpp1);
void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
struct VideoModeTable *vmode_tbl);
-void viafb_init_chip_info(int chip_type);
-void viafb_init_dac(int set_iga);
+void __devinit viafb_init_chip_info(int chip_type);
+void __devinit viafb_init_dac(int set_iga);
int viafb_get_pixclock(int hres, int vres, int vmode_refresh);
int viafb_get_refresh(int hres, int vres, u32 float_refresh);
void viafb_update_device_setting(int hres, int vres, int bpp,
diff --git a/drivers/video/via/ioctl.c b/drivers/video/via/ioctl.c
index 4d553d0b8d7a..ea1c51428823 100644
--- a/drivers/video/via/ioctl.c
+++ b/drivers/video/via/ioctl.c
@@ -94,6 +94,7 @@ int viafb_ioctl_hotplug(int hres, int vres, int bpp)
viafb_CRT_ON = 0;
viafb_LCD_ON = 0;
viafb_DeviceStatus = DVI_Device;
+ viafb_set_iga_path();
return viafb_DeviceStatus;
}
status = 1;
@@ -107,6 +108,7 @@ int viafb_ioctl_hotplug(int hres, int vres, int bpp)
viafb_LCD_ON = 0;
viafb_DeviceStatus = CRT_Device;
+ viafb_set_iga_path();
return viafb_DeviceStatus;
}
diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c
index fc25ae30c5f6..3425c3969806 100644
--- a/drivers/video/via/lcd.c
+++ b/drivers/video/via/lcd.c
@@ -21,10 +21,16 @@
#include <linux/via-core.h>
#include <linux/via_i2c.h>
#include "global.h"
-#include "lcdtbl.h"
#define viafb_compact_res(x, y) (((x)<<16)|(y))
+/* CLE266 Software Power Sequence */
+/* {Mask}, {Data}, {Delay} */
+int PowerSequenceOn[3][3] = { {0x10, 0x08, 0x06}, {0x10, 0x08, 0x06},
+ {0x19, 0x1FE, 0x01} };
+int PowerSequenceOff[3][3] = { {0x06, 0x08, 0x10}, {0x00, 0x00, 0x00},
+ {0xD2, 0x19, 0x01} };
+
static struct _lcd_scaling_factor lcd_scaling_factor = {
/* LCD Horizontal Scaling Factor Register */
{LCD_HOR_SCALING_FACTOR_REG_NUM,
@@ -42,7 +48,7 @@ static struct _lcd_scaling_factor lcd_scaling_factor_CLE = {
static int check_lvds_chip(int device_id_subaddr, int device_id);
static bool lvds_identify_integratedlvds(void);
-static void fp_id_to_vindex(int panel_id);
+static void __devinit fp_id_to_vindex(int panel_id);
static int lvds_register_read(int index);
static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
int panel_vres);
@@ -84,7 +90,7 @@ static int check_lvds_chip(int device_id_subaddr, int device_id)
return FAIL;
}
-void viafb_init_lcd_size(void)
+void __devinit viafb_init_lcd_size(void)
{
DEBUG_MSG(KERN_INFO "viafb_init_lcd_size()\n");
@@ -144,7 +150,7 @@ static bool lvds_identify_integratedlvds(void)
return true;
}
-int viafb_lvds_trasmitter_identify(void)
+int __devinit viafb_lvds_trasmitter_identify(void)
{
if (viafb_lvds_identify_vt1636(VIA_PORT_31)) {
viaparinfo->chip_info->lvds_chip_info.i2c_port = VIA_PORT_31;
@@ -185,7 +191,7 @@ int viafb_lvds_trasmitter_identify(void)
return FAIL;
}
-static void fp_id_to_vindex(int panel_id)
+static void __devinit fp_id_to_vindex(int panel_id)
{
DEBUG_MSG(KERN_INFO "fp_get_panel_id()\n");
@@ -436,6 +442,7 @@ static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
case UNICHROME_CN750:
case UNICHROME_VX800:
case UNICHROME_VX855:
+ case UNICHROME_VX900:
reg_value =
K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres);
/* Horizontal scaling enabled */
@@ -479,6 +486,7 @@ static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
case UNICHROME_CN750:
case UNICHROME_VX800:
case UNICHROME_VX855:
+ case UNICHROME_VX900:
reg_value =
K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres);
/* Vertical scaling enabled */
@@ -655,9 +663,6 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
pll_D_N = viafb_get_clk_value(panel_crt_table[0].clk);
DEBUG_MSG(KERN_INFO "PLL=0x%x", pll_D_N);
viafb_set_vclock(pll_D_N, set_iga);
-
- viafb_set_output_path(DEVICE_LCD, set_iga,
- plvds_chip_info->output_interface);
lcd_patch_skew(plvds_setting_info, plvds_chip_info);
/* If K8M800, enable LCD Prefetch Mode. */
@@ -700,9 +705,6 @@ static void integrated_lvds_disable(struct lvds_setting_information
viafb_write_reg_mask(CR91, VIACR, 0xC0, BIT6 + BIT7);
}
- /* Turn DFP High/Low Pad off. */
- viafb_write_reg_mask(SR2A, VIASR, 0, BIT0 + BIT1 + BIT2 + BIT3);
-
/* Power off LVDS channel. */
switch (plvds_chip_info->output_interface) {
case INTERFACE_LVDS0:
@@ -758,9 +760,6 @@ static void integrated_lvds_enable(struct lvds_setting_information
break;
}
- /* Turn DFP High/Low pad on. */
- viafb_write_reg_mask(SR2A, VIASR, 0x0F, BIT0 + BIT1 + BIT2 + BIT3);
-
/* Power on LVDS channel. */
switch (plvds_chip_info->output_interface) {
case INTERFACE_LVDS0:
@@ -809,29 +808,48 @@ void viafb_lcd_disable(void)
viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info,
&viaparinfo->chip_info->lvds_chip_info);
} else {
- /* DFP-HL pad off */
- viafb_write_reg_mask(SR2A, VIASR, 0x00, 0x0F);
/* Backlight off */
viafb_write_reg_mask(SR3D, VIASR, 0x00, 0x20);
/* 24 bit DI data paht off */
viafb_write_reg_mask(CR91, VIACR, 0x80, 0x80);
- /* Simultaneout disabled */
- viafb_write_reg_mask(CR6B, VIACR, 0x00, 0x08);
}
/* Disable expansion bit */
viafb_write_reg_mask(CR79, VIACR, 0x00, 0x01);
- /* CRT path set to IGA1 */
- viafb_write_reg_mask(SR16, VIASR, 0x00, 0x40);
/* Simultaneout disabled */
viafb_write_reg_mask(CR6B, VIACR, 0x00, 0x08);
- /* IGA2 path disabled */
- viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x80);
+}
+static void set_lcd_output_path(int set_iga, int output_interface)
+{
+ switch (output_interface) {
+ case INTERFACE_DFP:
+ if ((UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name)
+ || (UNICHROME_P4M890 ==
+ viaparinfo->chip_info->gfx_chip_name))
+ viafb_write_reg_mask(CR97, VIACR, 0x84,
+ BIT7 + BIT2 + BIT1 + BIT0);
+ case INTERFACE_DVP0:
+ case INTERFACE_DVP1:
+ case INTERFACE_DFP_HIGH:
+ case INTERFACE_DFP_LOW:
+ if (set_iga == IGA2)
+ viafb_write_reg(CR91, VIACR, 0x00);
+ break;
+ }
}
void viafb_lcd_enable(void)
{
+ viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3);
+ viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
+ set_lcd_output_path(viaparinfo->lvds_setting_info->iga_path,
+ viaparinfo->chip_info->lvds_chip_info.output_interface);
+ if (viafb_LCD2_ON)
+ set_lcd_output_path(viaparinfo->lvds_setting_info2->iga_path,
+ viaparinfo->chip_info->
+ lvds_chip_info2.output_interface);
+
if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
/* DI1 pad on */
viafb_write_reg_mask(SR1E, VIASR, 0x30, 0x30);
@@ -855,39 +873,13 @@ void viafb_lcd_enable(void)
viafb_enable_lvds_vt1636(viaparinfo->lvds_setting_info,
&viaparinfo->chip_info->lvds_chip_info);
} else {
- /* DFP-HL pad on */
- viafb_write_reg_mask(SR2A, VIASR, 0x0F, 0x0F);
/* Backlight on */
viafb_write_reg_mask(SR3D, VIASR, 0x20, 0x20);
/* 24 bit DI data paht on */
viafb_write_reg_mask(CR91, VIACR, 0x00, 0x80);
-
- /* Set data source selection bit by iga path */
- if (viaparinfo->lvds_setting_info->iga_path == IGA1) {
- /* DFP-H set to IGA1 */
- viafb_write_reg_mask(CR97, VIACR, 0x00, 0x10);
- /* DFP-L set to IGA1 */
- viafb_write_reg_mask(CR99, VIACR, 0x00, 0x10);
- } else {
- /* DFP-H set to IGA2 */
- viafb_write_reg_mask(CR97, VIACR, 0x10, 0x10);
- /* DFP-L set to IGA2 */
- viafb_write_reg_mask(CR99, VIACR, 0x10, 0x10);
- }
/* LCD enabled */
viafb_write_reg_mask(CR6A, VIACR, 0x48, 0x48);
}
-
- if (viaparinfo->lvds_setting_info->iga_path == IGA1) {
- /* CRT path set to IGA2 */
- viafb_write_reg_mask(SR16, VIASR, 0x40, 0x40);
- /* IGA2 path disabled */
- viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x80);
- /* IGA2 path enabled */
- } else { /* IGA2 */
- viafb_write_reg_mask(CR6A, VIACR, 0x80, 0x80);
- }
-
}
static void lcd_powersequence_off(void)
@@ -993,7 +985,7 @@ static void check_diport_of_integrated_lvds(
plvds_chip_info->output_interface);
}
-void viafb_init_lvds_output_interface(struct lvds_chip_information
+void __devinit viafb_init_lvds_output_interface(struct lvds_chip_information
*plvds_chip_info,
struct lvds_setting_information
*plvds_setting_info)
diff --git a/drivers/video/via/lcd.h b/drivers/video/via/lcd.h
index b348efc360b8..c7909fe29550 100644
--- a/drivers/video/via/lcd.h
+++ b/drivers/video/via/lcd.h
@@ -71,15 +71,15 @@ void viafb_enable_lvds_vt1636(struct lvds_setting_information
struct lvds_chip_information *plvds_chip_info);
void viafb_lcd_disable(void);
void viafb_lcd_enable(void);
-void viafb_init_lcd_size(void);
-void viafb_init_lvds_output_interface(struct lvds_chip_information
+void __devinit viafb_init_lcd_size(void);
+void __devinit viafb_init_lvds_output_interface(struct lvds_chip_information
*plvds_chip_info,
struct lvds_setting_information
*plvds_setting_info);
void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
struct lvds_setting_information *plvds_setting_info,
struct lvds_chip_information *plvds_chip_info);
-int viafb_lvds_trasmitter_identify(void);
+int __devinit viafb_lvds_trasmitter_identify(void);
void viafb_init_lvds_output_interface(struct lvds_chip_information
*plvds_chip_info,
struct lvds_setting_information
diff --git a/drivers/video/via/lcdtbl.h b/drivers/video/via/lcdtbl.h
deleted file mode 100644
index 6f3dd800be59..000000000000
--- a/drivers/video/via/lcdtbl.h
+++ /dev/null
@@ -1,591 +0,0 @@
-/*
- * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2008 S3 Graphics, Inc. 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, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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 __LCDTBL_H__
-#define __LCDTBL_H__
-
-#include "share.h"
-
-/* CLE266 Software Power Sequence */
-/* {Mask}, {Data}, {Delay} */
-int PowerSequenceOn[3][3] =
- { {0x10, 0x08, 0x06}, {0x10, 0x08, 0x06}, {0x19, 0x1FE, 0x01} };
-int PowerSequenceOff[3][3] =
- { {0x06, 0x08, 0x10}, {0x00, 0x00, 0x00}, {0xD2, 0x19, 0x01} };
-
-/* ++++++ P880 ++++++ */
-/* Panel 1600x1200 */
-struct io_reg P880_LCD_RES_6X4_16X12[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x73}, {VIACR, CR55, 0x0F, 0x08},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x73}, {VIACR, CR54, 0x38, 0x00},
- {VIACR, CR5D, 0x40, 0x40},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x5A}, {VIACR, CR71, 0x08, 0x00},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x5E},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xD6}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR44, 0xFF, 0x7D}, {VIASR, SR45, 0xFF, 0x8C},
- {VIASR, SR46, 0xFF, 0x02}
-
-};
-
-#define NUM_TOTAL_P880_LCD_RES_6X4_16X12 ARRAY_SIZE(P880_LCD_RES_6X4_16X12)
-
-struct io_reg P880_LCD_RES_7X4_16X12[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x67}, {VIACR, CR55, 0x0F, 0x08},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x67}, {VIACR, CR54, 0x38, 0x00},
- {VIACR, CR5D, 0x40, 0x40},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x74}, {VIACR, CR71, 0x08, 0x00},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x78},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xF5}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR44, 0xFF, 0x78}, {VIASR, SR45, 0xFF, 0x8C},
- {VIASR, SR46, 0xFF, 0x01}
-
-};
-
-#define NUM_TOTAL_P880_LCD_RES_7X4_16X12 ARRAY_SIZE(P880_LCD_RES_7X4_16X12)
-
-struct io_reg P880_LCD_RES_8X6_16X12[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00},
- {VIACR, CR5D, 0x40, 0x40},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x00},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x83},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xE1}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR44, 0xFF, 0x6D}, {VIASR, SR45, 0xFF, 0x88},
- {VIASR, SR46, 0xFF, 0x03}
-
-};
-
-#define NUM_TOTAL_P880_LCD_RES_8X6_16X12 ARRAY_SIZE(P880_LCD_RES_8X6_16X12)
-
-struct io_reg P880_LCD_RES_10X7_16X12[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00},
- {VIACR, CR5D, 0x40, 0x40},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0xAB}, {VIACR, CR71, 0x08, 0x00},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0xAF},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xF0}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR44, 0xFF, 0x92}, {VIASR, SR45, 0xFF, 0x88},
- {VIASR, SR46, 0xFF, 0x03}
-
-};
-
-#define NUM_TOTAL_P880_LCD_RES_10X7_16X12 ARRAY_SIZE(P880_LCD_RES_10X7_16X12)
-
-struct io_reg P880_LCD_RES_12X10_16X12[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x7D}, {VIACR, CR55, 0x0F, 0x08},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x7D}, {VIACR, CR54, 0x38, 0x00},
- {VIACR, CR5D, 0x40, 0x40},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0xD0}, {VIACR, CR71, 0x08, 0x00},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0xD4},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xFA}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR44, 0xFF, 0xF6}, {VIASR, SR45, 0xFF, 0x88},
- {VIASR, SR46, 0xFF, 0x05}
-
-};
-
-#define NUM_TOTAL_P880_LCD_RES_12X10_16X12 ARRAY_SIZE(P880_LCD_RES_12X10_16X12)
-
-/* Panel 1400x1050 */
-struct io_reg P880_LCD_RES_6X4_14X10[] = {
- /* 640x480 */
- /* IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
- /* IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
- {VIACR, CR5D, 0x40, 0x24},
- /* IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x44},
- /* IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x63},
- /* IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xB4}, {VIACR, CR67, 0x03, 0x00},
- /* VCLK */
- {VIASR, SR44, 0xFF, 0xC6}, {VIASR, SR45, 0xFF, 0x8C},
- {VIASR, SR46, 0xFF, 0x05}
-};
-
-#define NUM_TOTAL_P880_LCD_RES_6X4_14X10 ARRAY_SIZE(P880_LCD_RES_6X4_14X10)
-
-struct io_reg P880_LCD_RES_8X6_14X10[] = {
- /* 800x600 */
- /* IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
- /* IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
- {VIACR, CR5D, 0x40, 0x24},
- /* IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x44},
- /* IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x83},
- /* IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x00},
- /* VCLK */
- {VIASR, SR44, 0xFF, 0x06}, {VIASR, SR45, 0xFF, 0x8D},
- {VIASR, SR46, 0xFF, 0x05}
-};
-
-#define NUM_TOTAL_P880_LCD_RES_8X6_14X10 ARRAY_SIZE(P880_LCD_RES_8X6_14X10)
-
-/* ++++++ K400 ++++++ */
-/* Panel 1600x1200 */
-struct io_reg K400_LCD_RES_6X4_16X12[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x73}, {VIACR, CR55, 0x0F, 0x08},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x73}, {VIACR, CR54, 0x38, 0x00},
- {VIACR, CR5D, 0x40, 0x40},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x5A}, {VIACR, CR71, 0x08, 0x00},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x5E},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xDA}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR46, 0xFF, 0xC4}, {VIASR, SR47, 0xFF, 0x7F}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_6X4_16X12 ARRAY_SIZE(K400_LCD_RES_6X4_16X12)
-
-struct io_reg K400_LCD_RES_7X4_16X12[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x67}, {VIACR, CR55, 0x0F, 0x08},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x67}, {VIACR, CR54, 0x38, 0x00},
- {VIACR, CR5D, 0x40, 0x40},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x74}, {VIACR, CR71, 0x08, 0x00},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x78},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xF5}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR46, 0xFF, 0x46}, {VIASR, SR47, 0xFF, 0x3D}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_7X4_16X12 ARRAY_SIZE(K400_LCD_RES_7X4_16X12)
-
-struct io_reg K400_LCD_RES_8X6_16X12[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00},
- {VIACR, CR5D, 0x40, 0x40},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x00},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x83},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xE1}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR46, 0xFF, 0x85}, {VIASR, SR47, 0xFF, 0x6F}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_8X6_16X12 ARRAY_SIZE(K400_LCD_RES_8X6_16X12)
-
-struct io_reg K400_LCD_RES_10X7_16X12[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00},
- {VIACR, CR5D, 0x40, 0x40},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0xAB}, {VIACR, CR71, 0x08, 0x00},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0xAF},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xF0}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR46, 0xFF, 0x45}, {VIASR, SR47, 0xFF, 0x4A}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_10X7_16X12 ARRAY_SIZE(K400_LCD_RES_10X7_16X12)
-
-struct io_reg K400_LCD_RES_12X10_16X12[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x7D}, {VIACR, CR55, 0x0F, 0x08},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x7D}, {VIACR, CR54, 0x38, 0x00},
- {VIACR, CR5D, 0x40, 0x40},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0xD0}, {VIACR, CR71, 0x08, 0x00},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0xD4},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xFA}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR46, 0xFF, 0x47}, {VIASR, SR47, 0xFF, 0x7C}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_12X10_16X12 ARRAY_SIZE(K400_LCD_RES_12X10_16X12)
-
-/* Panel 1400x1050 */
-struct io_reg K400_LCD_RES_6X4_14X10[] = {
- /* 640x400 */
- /* IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
- /* IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
- {VIACR, CR5D, 0x40, 0x24},
- /* IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x44},
- /* IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x63},
- /* IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xB4}, {VIACR, CR67, 0x03, 0x00},
- /* VCLK */
- {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x19}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_6X4_14X10 ARRAY_SIZE(K400_LCD_RES_6X4_14X10)
-
-struct io_reg K400_LCD_RES_8X6_14X10[] = {
- /* 800x600 */
- /* IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
- /* IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
- {VIACR, CR5D, 0x40, 0x24},
- /* IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x44},
- /* IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x83},
- /* IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x00},
- /* VCLK */
- {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x21}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_8X6_14X10 ARRAY_SIZE(K400_LCD_RES_8X6_14X10)
-
-struct io_reg K400_LCD_RES_10X7_14X10[] = {
- /* 1024x768 */
- /* IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
- /* IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
- {VIACR, CR5D, 0x40, 0x24},
- /* IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0xA3}, {VIACR, CR71, 0x08, 0x44},
- /* IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0xA7},
- /* IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xC3}, {VIACR, CR67, 0x03, 0x04},
- /* VCLK */
- {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x1E}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_10X7_14X10 ARRAY_SIZE(K400_LCD_RES_10X7_14X10)
-
-struct io_reg K400_LCD_RES_12X10_14X10[] = {
- /* 1280x768, 1280x960, 1280x1024 */
- /* IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x97}, {VIACR, CR55, 0x0F, 0x56},
- /* IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x97}, {VIACR, CR54, 0x38, 0x75},
- {VIACR, CR5D, 0x40, 0x24},
- /* IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0xCE}, {VIACR, CR71, 0x08, 0x44},
- /* IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0xD2},
- /* IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xC9}, {VIACR, CR67, 0x03, 0x04},
- /* VCLK */
- {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0x79}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_12X10_14X10 ARRAY_SIZE(K400_LCD_RES_12X10_14X10)
-
-/* ++++++ K400 ++++++ */
-/* Panel 1366x768 */
-struct io_reg K400_LCD_RES_6X4_1366X7[] = {
- /* 640x400 */
- /* IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x47}, {VIACR, CR55, 0x0F, 0x35},
- /* IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x47}, {VIACR, CR54, 0x38, 0x2B},
- {VIACR, CR5D, 0x40, 0x13},
- /* IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x60}, {VIACR, CR71, 0x08, 0x23},
- /* IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x64},
- /* IGA2 Offset */
- {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00},
- /* VCLK */
- {VIASR, SR46, 0xFF, 0x87}, {VIASR, SR47, 0xFF, 0x4C}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_6X4_1366X7 ARRAY_SIZE(K400_LCD_RES_6X4_1366X7)
-
-struct io_reg K400_LCD_RES_7X4_1366X7[] = {
- /* IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x3B}, {VIACR, CR55, 0x0F, 0x35},
- /* IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x3B}, {VIACR, CR54, 0x38, 0x2B},
- {VIACR, CR5D, 0x40, 0x13},
- /* IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x71}, {VIACR, CR71, 0x08, 0x23},
- /* IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x75},
- /* IGA2 Offset */
- {VIACR, CR66, 0xFF, 0x96}, {VIACR, CR67, 0x03, 0x00},
- /* VCLK */
- {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x10}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_7X4_1366X7 ARRAY_SIZE(K400_LCD_RES_7X4_1366X7)
-
-struct io_reg K400_LCD_RES_8X6_1366X7[] = {
- /* 800x600 */
- /* IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x37}, {VIACR, CR55, 0x0F, 0x35},
- /* IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x37}, {VIACR, CR54, 0x38, 0x2B},
- {VIACR, CR5D, 0x40, 0x13},
- /* IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x7E}, {VIACR, CR71, 0x08, 0x23},
- /* IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x82},
- /* IGA2 Offset */
- {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00},
- /* VCLK */
- {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0xB9}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_8X6_1366X7 ARRAY_SIZE(K400_LCD_RES_8X6_1366X7)
-
-struct io_reg K400_LCD_RES_10X7_1366X7[] = {
- /* 1024x768 */
- /* IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
- /* IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
- {VIACR, CR5D, 0x40, 0x24},
- /* IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0xA3}, {VIACR, CR71, 0x08, 0x44},
- /* IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0xA7},
- /* IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xC3}, {VIACR, CR67, 0x03, 0x04},
- /* VCLK */
- {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x1E}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_10X7_1366X7 ARRAY_SIZE(K400_LCD_RES_10X7_1366X7)
-
-struct io_reg K400_LCD_RES_12X10_1366X7[] = {
- /* 1280x768, 1280x960, 1280x1024 */
- /* IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x97}, {VIACR, CR55, 0x0F, 0x56},
- /* IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x97}, {VIACR, CR54, 0x38, 0x75},
- {VIACR, CR5D, 0x40, 0x24},
- /* IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0xCE}, {VIACR, CR71, 0x08, 0x44},
- /* IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0xD2},
- /* IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xC9}, {VIACR, CR67, 0x03, 0x04},
- /* VCLK */
- {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0x79}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_12X10_1366X7\
- ARRAY_SIZE(K400_LCD_RES_12X10_1366X7)
-
-/* ++++++ K400 ++++++ */
-/* Panel 1280x1024 */
-struct io_reg K400_LCD_RES_6X4_12X10[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74},
- {VIACR, CR5D, 0x40, 0x1C},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x34},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x63},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xAA}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x19}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_6X4_12X10 ARRAY_SIZE(K400_LCD_RES_6X4_12X10)
-
-struct io_reg K400_LCD_RES_7X4_12X10[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74},
- {VIACR, CR5D, 0x40, 0x1C},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x68}, {VIACR, CR71, 0x08, 0x34},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x6C},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xA8}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR46, 0xFF, 0x87}, {VIASR, SR47, 0xFF, 0xED}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_7X4_12X10 ARRAY_SIZE(K400_LCD_RES_7X4_12X10)
-
-struct io_reg K400_LCD_RES_8X6_12X10[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74},
- {VIACR, CR5D, 0x40, 0x1C},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x34},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x83},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x21}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_8X6_12X10 ARRAY_SIZE(K400_LCD_RES_8X6_12X10)
-
-struct io_reg K400_LCD_RES_10X7_12X10[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74},
- {VIACR, CR5D, 0x40, 0x1C},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0xA3}, {VIACR, CR71, 0x08, 0x34},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0xA7},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x04},
- /*VCLK*/ {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x1E}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_10X7_12X10 ARRAY_SIZE(K400_LCD_RES_10X7_12X10)
-
-/* ++++++ K400 ++++++ */
-/* Panel 1024x768 */
-struct io_reg K400_LCD_RES_6X4_10X7[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x47}, {VIACR, CR55, 0x0F, 0x35},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x47}, {VIACR, CR54, 0x38, 0x2B},
- {VIACR, CR5D, 0x40, 0x13},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x60}, {VIACR, CR71, 0x08, 0x23},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x64},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR46, 0xFF, 0x87}, {VIASR, SR47, 0xFF, 0x4C}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_6X4_10X7 ARRAY_SIZE(K400_LCD_RES_6X4_10X7)
-
-struct io_reg K400_LCD_RES_7X4_10X7[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x3B}, {VIACR, CR55, 0x0F, 0x35},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x3B}, {VIACR, CR54, 0x38, 0x2B},
- {VIACR, CR5D, 0x40, 0x13},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x71}, {VIACR, CR71, 0x08, 0x23},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x75},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0x96}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x10}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_7X4_10X7 ARRAY_SIZE(K400_LCD_RES_7X4_10X7)
-
-struct io_reg K400_LCD_RES_8X6_10X7[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x37}, {VIACR, CR55, 0x0F, 0x35},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x37}, {VIACR, CR54, 0x38, 0x2B},
- {VIACR, CR5D, 0x40, 0x13},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x7E}, {VIACR, CR71, 0x08, 0x23},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x82},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0xB9}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_8X6_10X7 ARRAY_SIZE(K400_LCD_RES_8X6_10X7)
-
-/* ++++++ K400 ++++++ */
-/* Panel 800x600 */
-struct io_reg K400_LCD_RES_6X4_8X6[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x1A}, {VIACR, CR55, 0x0F, 0x34},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x1A}, {VIACR, CR54, 0x38, 0xE3},
- {VIACR, CR5D, 0x40, 0x12},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x22},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x63},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0x6E}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR46, 0xFF, 0x86}, {VIASR, SR47, 0xFF, 0xB3}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_6X4_8X6 ARRAY_SIZE(K400_LCD_RES_6X4_8X6)
-
-struct io_reg K400_LCD_RES_7X4_8X6[] = {
- /*IGA2 Horizontal Total */
- {VIACR, CR50, 0xFF, 0x1F}, {VIACR, CR55, 0x0F, 0x34},
- /*IGA2 Horizontal Blank End */
- {VIACR, CR53, 0xFF, 0x1F}, {VIACR, CR54, 0x38, 0xE3},
- {VIACR, CR5D, 0x40, 0x12},
- /*IGA2 Horizontal Total Shadow */
- {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x22},
- /*IGA2 Horizontal Blank End Shadow */
- {VIACR, CR6E, 0xFF, 0x83},
- /*IGA2 Offset */
- {VIACR, CR66, 0xFF, 0x78}, {VIACR, CR67, 0x03, 0x00},
- /*VCLK*/ {VIASR, SR46, 0xFF, 0xC4}, {VIASR, SR47, 0xFF, 0x59}
-};
-
-#define NUM_TOTAL_K400_LCD_RES_7X4_8X6 ARRAY_SIZE(K400_LCD_RES_7X4_8X6)
-
-#endif /* __LCDTBL_H__ */
diff --git a/drivers/video/via/tbl1636.c b/drivers/video/via/tbl1636.c
deleted file mode 100644
index 2d8453429d4a..000000000000
--- a/drivers/video/via/tbl1636.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2008 S3 Graphics, Inc. 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, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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 "global.h"
-struct IODATA COMMON_INIT_TBL_VT1636[] = {
-/* Index, Mask, Value */
- /* Set panel power sequence timing */
- {0x10, 0xC0, 0x00},
- /* T1: VDD on - Data on. Each increment is 1 ms. (50ms = 031h) */
- {0x0B, 0xFF, 0x40},
- /* T2: Data on - Backlight on. Each increment is 2 ms. (210ms = 068h) */
- {0x0C, 0xFF, 0x31},
- /* T3: Backlight off -Data off. Each increment is 2 ms. (210ms = 068h)*/
- {0x0D, 0xFF, 0x31},
- /* T4: Data off - VDD off. Each increment is 1 ms. (50ms = 031h) */
- {0x0E, 0xFF, 0x68},
- /* T5: VDD off - VDD on. Each increment is 100 ms. (500ms = 04h) */
- {0x0F, 0xFF, 0x68},
- /* LVDS output power up */
- {0x09, 0xA0, 0xA0},
- /* turn on back light */
- {0x10, 0x33, 0x13}
-};
-
-struct IODATA DUAL_CHANNEL_ENABLE_TBL_VT1636[] = {
-/* Index, Mask, Value */
- {0x08, 0xF0, 0xE0} /* Input Data Mode Select */
-};
-
-struct IODATA SINGLE_CHANNEL_ENABLE_TBL_VT1636[] = {
-/* Index, Mask, Value */
- {0x08, 0xF0, 0x00} /* Input Data Mode Select */
-};
-
-struct IODATA DITHERING_ENABLE_TBL_VT1636[] = {
-/* Index, Mask, Value */
- {0x0A, 0x70, 0x50}
-};
-
-struct IODATA DITHERING_DISABLE_TBL_VT1636[] = {
-/* Index, Mask, Value */
- {0x0A, 0x70, 0x00}
-};
-
-struct IODATA VDD_ON_TBL_VT1636[] = {
-/* Index, Mask, Value */
- {0x10, 0x20, 0x20}
-};
-
-struct IODATA VDD_OFF_TBL_VT1636[] = {
-/* Index, Mask, Value */
- {0x10, 0x20, 0x00}
-};
diff --git a/drivers/video/via/tbl1636.h b/drivers/video/via/tbl1636.h
deleted file mode 100644
index d906055f1511..000000000000
--- a/drivers/video/via/tbl1636.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2008 S3 Graphics, Inc. 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, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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 _TBL1636_H_
-#define _TBL1636_H_
-#include "hw.h"
-
-extern struct IODATA COMMON_INIT_TBL_VT1636[8];
-extern struct IODATA DUAL_CHANNEL_ENABLE_TBL_VT1636[1];
-extern struct IODATA SINGLE_CHANNEL_ENABLE_TBL_VT1636[1];
-extern struct IODATA DITHERING_ENABLE_TBL_VT1636[1];
-extern struct IODATA DITHERING_DISABLE_TBL_VT1636[1];
-extern struct IODATA VDD_ON_TBL_VT1636[1];
-extern struct IODATA VDD_OFF_TBL_VT1636[1];
-
-#endif /* _VIA_TBL1636_H_ */
diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
index 66f403033111..31e30338e893 100644
--- a/drivers/video/via/via-core.c
+++ b/drivers/video/via/via-core.c
@@ -20,7 +20,7 @@
* The default port config.
*/
static struct via_port_cfg adap_configs[] = {
- [VIA_PORT_26] = { VIA_PORT_I2C, VIA_MODE_OFF, VIASR, 0x26 },
+ [VIA_PORT_26] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x26 },
[VIA_PORT_31] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x31 },
[VIA_PORT_25] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x25 },
[VIA_PORT_2C] = { VIA_PORT_GPIO, VIA_MODE_I2C, VIASR, 0x2c },
@@ -333,7 +333,7 @@ EXPORT_SYMBOL_GPL(viafb_dma_copy_out_sg);
static u16 via_function3[] = {
CLE266_FUNCTION3, KM400_FUNCTION3, CN400_FUNCTION3, CN700_FUNCTION3,
CX700_FUNCTION3, KM800_FUNCTION3, KM890_FUNCTION3, P4M890_FUNCTION3,
- P4M900_FUNCTION3, VX800_FUNCTION3, VX855_FUNCTION3,
+ P4M900_FUNCTION3, VX800_FUNCTION3, VX855_FUNCTION3, VX900_FUNCTION3,
};
/* Get the BIOS-configured framebuffer size from PCI configuration space
@@ -370,6 +370,7 @@ static int viafb_get_fb_size_from_pci(int chip_type)
case P4M900_FUNCTION3:
case VX800_FUNCTION3:
case VX855_FUNCTION3:
+ case VX900_FUNCTION3:
/*case CN750_FUNCTION3: */
offset = 0xA0;
break;
@@ -474,7 +475,10 @@ static int __devinit via_pci_setup_mmio(struct viafb_dev *vdev)
* Eventually we want to move away from mapping this
* entire region.
*/
- vdev->fbmem_start = pci_resource_start(vdev->pdev, 0);
+ if (vdev->chip_type == UNICHROME_VX900)
+ vdev->fbmem_start = pci_resource_start(vdev->pdev, 2);
+ else
+ vdev->fbmem_start = pci_resource_start(vdev->pdev, 0);
ret = vdev->fbmem_len = viafb_get_fb_size_from_pci(vdev->chip_type);
if (ret < 0)
goto out_unmap;
@@ -635,6 +639,8 @@ static struct pci_device_id via_pci_table[] __devinitdata = {
.driver_data = UNICHROME_VX800 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX855_DID),
.driver_data = UNICHROME_VX855 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX900_DID),
+ .driver_data = UNICHROME_VX900 },
{ }
};
MODULE_DEVICE_TABLE(pci, via_pci_table);
@@ -644,6 +650,10 @@ static struct pci_driver via_driver = {
.id_table = via_pci_table,
.probe = via_pci_probe,
.remove = __devexit_p(via_pci_remove),
+#ifdef CONFIG_PM
+ .suspend = viafb_suspend,
+ .resume = viafb_resume,
+#endif
};
static int __init via_core_init(void)
diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c
index da9e4ca94b17..3844b558b7bd 100644
--- a/drivers/video/via/via_i2c.c
+++ b/drivers/video/via/via_i2c.c
@@ -114,6 +114,7 @@ static void via_i2c_setsda(void *data, int state)
int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata)
{
+ int ret;
u8 mm1[] = {0x00};
struct i2c_msg msgs[2];
@@ -126,11 +127,18 @@ int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata)
mm1[0] = index;
msgs[0].len = 1; msgs[1].len = 1;
msgs[0].buf = mm1; msgs[1].buf = pdata;
- return i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
+ ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
+ if (ret == 2)
+ ret = 0;
+ else if (ret >= 0)
+ ret = -EIO;
+
+ return ret;
}
int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data)
{
+ int ret;
u8 msg[2] = { index, data };
struct i2c_msg msgs;
@@ -140,11 +148,18 @@ int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data)
msgs.addr = slave_addr / 2;
msgs.len = 2;
msgs.buf = msg;
- return i2c_transfer(&via_i2c_par[adap].adapter, &msgs, 1);
+ ret = i2c_transfer(&via_i2c_par[adap].adapter, &msgs, 1);
+ if (ret == 1)
+ ret = 0;
+ else if (ret >= 0)
+ ret = -EIO;
+
+ return ret;
}
int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len)
{
+ int ret;
u8 mm1[] = {0x00};
struct i2c_msg msgs[2];
@@ -156,7 +171,13 @@ int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len
mm1[0] = index;
msgs[0].len = 1; msgs[1].len = buff_len;
msgs[0].buf = mm1; msgs[1].buf = buff;
- return i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
+ ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
+ if (ret == 2)
+ ret = 0;
+ else if (ret >= 0)
+ ret = -EIO;
+
+ return ret;
}
/*
@@ -181,8 +202,8 @@ static int create_i2c_bus(struct i2c_adapter *adapter,
algo->setscl = via_i2c_setscl;
algo->getsda = via_i2c_getsda;
algo->getscl = via_i2c_getscl;
- algo->udelay = 40;
- algo->timeout = 20;
+ algo->udelay = 10;
+ algo->timeout = 2;
algo->data = adap_cfg;
sprintf(adapter->name, "viafb i2c io_port idx 0x%02x",
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index bdd0e4130f4e..d298cfccd6fc 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -56,6 +56,32 @@ static int viafb_pan_display(struct fb_var_screeninfo *var,
static struct fb_ops viafb_ops;
+/* supported output devices on each IGP
+ * only CX700, VX800, VX855, VX900 were documented
+ * VIA_CRT should be everywhere
+ * VIA_6C can be onle pre-CX700 (probably only on CLE266) as 6C is used for PLL
+ * source selection on CX700 and later
+ * K400 seems to support VIA_96, VIA_DVP1, VIA_LVDS{1,2} as in viamode.c
+ */
+static const u32 supported_odev_map[] = {
+ [UNICHROME_CLE266] = VIA_CRT | VIA_LDVP0 | VIA_LDVP1,
+ [UNICHROME_K400] = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1
+ | VIA_LVDS2,
+ [UNICHROME_K800] = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1
+ | VIA_LVDS2,
+ [UNICHROME_PM800] = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1
+ | VIA_LVDS2,
+ [UNICHROME_CN700] = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1
+ | VIA_LVDS2,
+ [UNICHROME_CX700] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+ [UNICHROME_CN750] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+ [UNICHROME_K8M890] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+ [UNICHROME_P4M890] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+ [UNICHROME_P4M900] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+ [UNICHROME_VX800] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+ [UNICHROME_VX855] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+ [UNICHROME_VX900] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+};
static void viafb_fill_var_color_info(struct fb_var_screeninfo *var, u8 depth)
{
@@ -332,22 +358,22 @@ static int viafb_blank(int blank_mode, struct fb_info *info)
case FB_BLANK_UNBLANK:
/* Screen: On, HSync: On, VSync: On */
/* control CRT monitor power management */
- viafb_write_reg_mask(CR36, VIACR, 0x00, BIT4 + BIT5);
+ via_set_state(VIA_CRT, VIA_STATE_ON);
break;
case FB_BLANK_HSYNC_SUSPEND:
/* Screen: Off, HSync: Off, VSync: On */
/* control CRT monitor power management */
- viafb_write_reg_mask(CR36, VIACR, 0x10, BIT4 + BIT5);
+ via_set_state(VIA_CRT, VIA_STATE_STANDBY);
break;
case FB_BLANK_VSYNC_SUSPEND:
/* Screen: Off, HSync: On, VSync: Off */
/* control CRT monitor power management */
- viafb_write_reg_mask(CR36, VIACR, 0x20, BIT4 + BIT5);
+ via_set_state(VIA_CRT, VIA_STATE_SUSPEND);
break;
case FB_BLANK_POWERDOWN:
/* Screen: Off, HSync: Off, VSync: Off */
/* control CRT monitor power management */
- viafb_write_reg_mask(CR36, VIACR, 0x30, BIT4 + BIT5);
+ via_set_state(VIA_CRT, VIA_STATE_OFF);
break;
}
@@ -457,7 +483,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
if (copy_from_user(&gpu32, argp, sizeof(gpu32)))
return -EFAULT;
if (gpu32 & CRT_Device)
- viafb_crt_enable();
+ via_set_state(VIA_CRT, VIA_STATE_ON);
if (gpu32 & DVI_Device)
viafb_dvi_enable();
if (gpu32 & LCD_Device)
@@ -467,7 +493,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
if (copy_from_user(&gpu32, argp, sizeof(gpu32)))
return -EFAULT;
if (gpu32 & CRT_Device)
- viafb_crt_disable();
+ via_set_state(VIA_CRT, VIA_STATE_OFF);
if (gpu32 & DVI_Device)
viafb_dvi_disable();
if (gpu32 & LCD_Device)
@@ -787,7 +813,8 @@ static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
bg_color = cursor->image.bg_color;
if (chip_name == UNICHROME_CX700 ||
chip_name == UNICHROME_VX800 ||
- chip_name == UNICHROME_VX855) {
+ chip_name == UNICHROME_VX855 ||
+ chip_name == UNICHROME_VX900) {
fg_color =
((info->cmap.red[fg_color] & 0xFFC0) << 14) |
((info->cmap.green[fg_color] & 0xFFC0) << 4) |
@@ -961,7 +988,7 @@ static void retrieve_device_setting(struct viafb_ioctl_setting
setting_info->lcd_attributes.lcd_mode = viafb_lcd_mode;
}
-static int parse_active_dev(void)
+static int __init parse_active_dev(void)
{
viafb_CRT_ON = STATE_OFF;
viafb_DVI_ON = STATE_OFF;
@@ -1031,7 +1058,7 @@ static int parse_active_dev(void)
return 0;
}
-static int parse_port(char *opt_str, int *output_interface)
+static int __devinit parse_port(char *opt_str, int *output_interface)
{
if (!strncmp(opt_str, "DVP0", 4))
*output_interface = INTERFACE_DVP0;
@@ -1048,7 +1075,7 @@ static int parse_port(char *opt_str, int *output_interface)
return 0;
}
-static void parse_lcd_port(void)
+static void __devinit parse_lcd_port(void)
{
parse_port(viafb_lcd_port, &viaparinfo->chip_info->lvds_chip_info.
output_interface);
@@ -1061,7 +1088,7 @@ static void parse_lcd_port(void)
output_interface);
}
-static void parse_dvi_port(void)
+static void __devinit parse_dvi_port(void)
{
parse_port(viafb_dvi_port, &viaparinfo->chip_info->tmds_chip_info.
output_interface);
@@ -1431,38 +1458,196 @@ static const struct file_operations viafb_vt1636_proc_fops = {
.write = viafb_vt1636_proc_write,
};
-static void viafb_init_proc(struct proc_dir_entry **viafb_entry)
+#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
+
+static int viafb_sup_odev_proc_show(struct seq_file *m, void *v)
{
- *viafb_entry = proc_mkdir("viafb", NULL);
- if (*viafb_entry) {
- proc_create("dvp0", 0, *viafb_entry, &viafb_dvp0_proc_fops);
- proc_create("dvp1", 0, *viafb_entry, &viafb_dvp1_proc_fops);
- proc_create("dfph", 0, *viafb_entry, &viafb_dfph_proc_fops);
- proc_create("dfpl", 0, *viafb_entry, &viafb_dfpl_proc_fops);
- if (VT1636_LVDS == viaparinfo->chip_info->lvds_chip_info.
- lvds_chip_name || VT1636_LVDS ==
- viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
- proc_create("vt1636", 0, *viafb_entry, &viafb_vt1636_proc_fops);
- }
+ via_odev_to_seq(m, supported_odev_map[
+ viaparinfo->shared->chip_info.gfx_chip_name]);
+ return 0;
+}
+
+static int viafb_sup_odev_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, viafb_sup_odev_proc_show, NULL);
+}
+
+static const struct file_operations viafb_sup_odev_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = viafb_sup_odev_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static ssize_t odev_update(const char __user *buffer, size_t count, u32 *odev)
+{
+ char buf[64], *ptr = buf;
+ u32 devices;
+ bool add, sub;
+
+ if (count < 1 || count > 63)
+ return -EINVAL;
+ if (copy_from_user(&buf[0], buffer, count))
+ return -EFAULT;
+ buf[count] = '\0';
+ add = buf[0] == '+';
+ sub = buf[0] == '-';
+ if (add || sub)
+ ptr++;
+ devices = via_parse_odev(ptr, &ptr);
+ if (*ptr == '\n')
+ ptr++;
+ if (*ptr != 0)
+ return -EINVAL;
+ if (add)
+ *odev |= devices;
+ else if (sub)
+ *odev &= ~devices;
+ else
+ *odev = devices;
+ return count;
+}
+
+static int viafb_iga1_odev_proc_show(struct seq_file *m, void *v)
+{
+ via_odev_to_seq(m, viaparinfo->shared->iga1_devices);
+ return 0;
+}
+
+static int viafb_iga1_odev_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, viafb_iga1_odev_proc_show, NULL);
+}
+
+static ssize_t viafb_iga1_odev_proc_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *pos)
+{
+ u32 dev_on, dev_off, dev_old, dev_new;
+ ssize_t res;
+
+ dev_old = dev_new = viaparinfo->shared->iga1_devices;
+ res = odev_update(buffer, count, &dev_new);
+ if (res != count)
+ return res;
+ dev_off = dev_old & ~dev_new;
+ dev_on = dev_new & ~dev_old;
+ viaparinfo->shared->iga1_devices = dev_new;
+ viaparinfo->shared->iga2_devices &= ~dev_new;
+ via_set_state(dev_off, VIA_STATE_OFF);
+ via_set_source(dev_new, IGA1);
+ via_set_state(dev_on, VIA_STATE_ON);
+ return res;
+}
+
+static const struct file_operations viafb_iga1_odev_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = viafb_iga1_odev_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = viafb_iga1_odev_proc_write,
+};
+
+static int viafb_iga2_odev_proc_show(struct seq_file *m, void *v)
+{
+ via_odev_to_seq(m, viaparinfo->shared->iga2_devices);
+ return 0;
+}
+static int viafb_iga2_odev_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, viafb_iga2_odev_proc_show, NULL);
+}
+
+static ssize_t viafb_iga2_odev_proc_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *pos)
+{
+ u32 dev_on, dev_off, dev_old, dev_new;
+ ssize_t res;
+
+ dev_old = dev_new = viaparinfo->shared->iga2_devices;
+ res = odev_update(buffer, count, &dev_new);
+ if (res != count)
+ return res;
+ dev_off = dev_old & ~dev_new;
+ dev_on = dev_new & ~dev_old;
+ viaparinfo->shared->iga2_devices = dev_new;
+ viaparinfo->shared->iga1_devices &= ~dev_new;
+ via_set_state(dev_off, VIA_STATE_OFF);
+ via_set_source(dev_new, IGA2);
+ via_set_state(dev_on, VIA_STATE_ON);
+ return res;
+}
+
+static const struct file_operations viafb_iga2_odev_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = viafb_iga2_odev_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = viafb_iga2_odev_proc_write,
+};
+
+#define IS_VT1636(lvds_chip) ((lvds_chip).lvds_chip_name == VT1636_LVDS)
+static void viafb_init_proc(struct viafb_shared *shared)
+{
+ struct proc_dir_entry *iga1_entry, *iga2_entry,
+ *viafb_entry = proc_mkdir("viafb", NULL);
+
+ shared->proc_entry = viafb_entry;
+ if (viafb_entry) {
+#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
+ proc_create("dvp0", 0, viafb_entry, &viafb_dvp0_proc_fops);
+ proc_create("dvp1", 0, viafb_entry, &viafb_dvp1_proc_fops);
+ proc_create("dfph", 0, viafb_entry, &viafb_dfph_proc_fops);
+ proc_create("dfpl", 0, viafb_entry, &viafb_dfpl_proc_fops);
+ if (IS_VT1636(shared->chip_info.lvds_chip_info)
+ || IS_VT1636(shared->chip_info.lvds_chip_info2))
+ proc_create("vt1636", 0, viafb_entry,
+ &viafb_vt1636_proc_fops);
+#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
+
+ proc_create("supported_output_devices", 0, viafb_entry,
+ &viafb_sup_odev_proc_fops);
+ iga1_entry = proc_mkdir("iga1", viafb_entry);
+ shared->iga1_proc_entry = iga1_entry;
+ proc_create("output_devices", 0, iga1_entry,
+ &viafb_iga1_odev_proc_fops);
+ iga2_entry = proc_mkdir("iga2", viafb_entry);
+ shared->iga2_proc_entry = iga2_entry;
+ proc_create("output_devices", 0, iga2_entry,
+ &viafb_iga2_odev_proc_fops);
}
}
-static void viafb_remove_proc(struct proc_dir_entry *viafb_entry)
+static void viafb_remove_proc(struct viafb_shared *shared)
{
- struct chip_information *chip_info = &viaparinfo->shared->chip_info;
+ struct proc_dir_entry *viafb_entry = shared->proc_entry,
+ *iga1_entry = shared->iga1_proc_entry,
+ *iga2_entry = shared->iga2_proc_entry;
+ if (!viafb_entry)
+ return;
+
+ remove_proc_entry("output_devices", iga2_entry);
+ remove_proc_entry("iga2", viafb_entry);
+ remove_proc_entry("output_devices", iga1_entry);
+ remove_proc_entry("iga1", viafb_entry);
+ remove_proc_entry("supported_output_devices", viafb_entry);
+
+#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
remove_proc_entry("dvp0", viafb_entry);/* parent dir */
remove_proc_entry("dvp1", viafb_entry);
remove_proc_entry("dfph", viafb_entry);
remove_proc_entry("dfpl", viafb_entry);
- if (chip_info->lvds_chip_info.lvds_chip_name == VT1636_LVDS
- || chip_info->lvds_chip_info2.lvds_chip_name == VT1636_LVDS)
+ if (IS_VT1636(shared->chip_info.lvds_chip_info)
+ || IS_VT1636(shared->chip_info.lvds_chip_info2))
remove_proc_entry("vt1636", viafb_entry);
+#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
remove_proc_entry("viafb", NULL);
}
-
-#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
+#undef IS_VT1636
static int parse_mode(const char *str, u32 *xres, u32 *yres)
{
@@ -1486,6 +1671,47 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres)
}
+#ifdef CONFIG_PM
+int viafb_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ if (state.event == PM_EVENT_SUSPEND) {
+ acquire_console_sem();
+ fb_set_suspend(viafbinfo, 1);
+
+ viafb_sync(viafbinfo);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ release_console_sem();
+ }
+
+ return 0;
+}
+
+int viafb_resume(struct pci_dev *pdev)
+{
+ acquire_console_sem();
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ if (pci_enable_device(pdev))
+ goto fail;
+ pci_set_master(pdev);
+ if (viaparinfo->shared->vdev->engine_mmio)
+ viafb_reset_engine(viaparinfo);
+ viafb_set_par(viafbinfo);
+ if (viafb_dual_fb)
+ viafb_set_par(viafbinfo1);
+ fb_set_suspend(viafbinfo, 0);
+
+fail:
+ release_console_sem();
+ return 0;
+}
+
+#endif
+
+
int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
{
u32 default_xres, default_yres;
@@ -1544,7 +1770,7 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
viafbinfo->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
viafbinfo->pseudo_palette = pseudo_pal;
- if (viafb_accel && !viafb_init_engine(viafbinfo)) {
+ if (viafb_accel && !viafb_setup_engine(viafbinfo)) {
viafbinfo->flags |= FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_IMAGEBLIT;
default_var.accel_flags = FB_ACCELF_TEXT;
@@ -1671,9 +1897,7 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
viafbinfo->node, viafbinfo->fix.id, default_var.xres,
default_var.yres, default_var.bits_per_pixel);
-#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
- viafb_init_proc(&viaparinfo->shared->proc_entry);
-#endif
+ viafb_init_proc(viaparinfo->shared);
viafb_init_dac(IGA2);
return 0;
@@ -1700,9 +1924,7 @@ void __devexit via_fb_pci_remove(struct pci_dev *pdev)
unregister_framebuffer(viafbinfo);
if (viafb_dual_fb)
unregister_framebuffer(viafbinfo1);
-#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
- viafb_remove_proc(viaparinfo->shared->proc_entry);
-#endif
+ viafb_remove_proc(viaparinfo->shared);
framebuffer_release(viafbinfo);
if (viafb_dual_fb)
framebuffer_release(viafbinfo1);
diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h
index 52a35fabba91..4960e3da6645 100644
--- a/drivers/video/via/viafbdev.h
+++ b/drivers/video/via/viafbdev.h
@@ -40,7 +40,12 @@
#define VIAFB_NUM_I2C 5
struct viafb_shared {
+ u32 iga1_devices;
+ u32 iga2_devices;
+
struct proc_dir_entry *proc_entry; /*viafb proc entry */
+ struct proc_dir_entry *iga1_proc_entry;
+ struct proc_dir_entry *iga2_proc_entry;
struct viafb_dev *vdev; /* Global dev info */
/* All the information will be needed to set engine */
@@ -103,4 +108,6 @@ void via_fb_pci_remove(struct pci_dev *pdev);
/* Temporary */
int viafb_init(void);
void viafb_exit(void);
+int viafb_suspend(struct pci_dev *pdev, pm_message_t state);
+int viafb_resume(struct pci_dev *pdev);
#endif /* __VIAFBDEV_H__ */
diff --git a/drivers/video/via/vt1636.c b/drivers/video/via/vt1636.c
index d65bf1aee87c..60e4192c2b34 100644
--- a/drivers/video/via/vt1636.c
+++ b/drivers/video/via/vt1636.c
@@ -23,6 +23,34 @@
#include <linux/via_i2c.h>
#include "global.h"
+static const struct IODATA common_init_data[] = {
+/* Index, Mask, Value */
+ /* Set panel power sequence timing */
+ {0x10, 0xC0, 0x00},
+ /* T1: VDD on - Data on. Each increment is 1 ms. (50ms = 031h) */
+ {0x0B, 0xFF, 0x40},
+ /* T2: Data on - Backlight on. Each increment is 2 ms. (210ms = 068h) */
+ {0x0C, 0xFF, 0x31},
+ /* T3: Backlight off -Data off. Each increment is 2 ms. (210ms = 068h)*/
+ {0x0D, 0xFF, 0x31},
+ /* T4: Data off - VDD off. Each increment is 1 ms. (50ms = 031h) */
+ {0x0E, 0xFF, 0x68},
+ /* T5: VDD off - VDD on. Each increment is 100 ms. (500ms = 04h) */
+ {0x0F, 0xFF, 0x68},
+ /* LVDS output power up */
+ {0x09, 0xA0, 0xA0},
+ /* turn on back light */
+ {0x10, 0x33, 0x13}
+};
+
+/* Index, Mask, Value */
+static const struct IODATA dual_channel_enable_data = {0x08, 0xF0, 0xE0};
+static const struct IODATA single_channel_enable_data = {0x08, 0xF0, 0x00};
+static const struct IODATA dithering_enable_data = {0x0A, 0x70, 0x50};
+static const struct IODATA dithering_disable_data = {0x0A, 0x70, 0x00};
+static const struct IODATA vdd_on_data = {0x10, 0x20, 0x20};
+static const struct IODATA vdd_off_data = {0x10, 0x20, 0x00};
+
u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
*plvds_setting_info, struct lvds_chip_information *plvds_chip_info,
u8 index)
@@ -55,108 +83,41 @@ void viafb_init_lvds_vt1636(struct lvds_setting_information
int reg_num, i;
/* Common settings: */
- reg_num = ARRAY_SIZE(COMMON_INIT_TBL_VT1636);
-
- for (i = 0; i < reg_num; i++) {
+ reg_num = ARRAY_SIZE(common_init_data);
+ for (i = 0; i < reg_num; i++)
viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
- plvds_chip_info,
- COMMON_INIT_TBL_VT1636[i]);
- }
+ plvds_chip_info, common_init_data[i]);
/* Input Data Mode Select */
- if (plvds_setting_info->device_lcd_dualedge) {
+ if (plvds_setting_info->device_lcd_dualedge)
viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
- plvds_chip_info,
- DUAL_CHANNEL_ENABLE_TBL_VT1636[0]);
- } else {
+ plvds_chip_info, dual_channel_enable_data);
+ else
viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
- plvds_chip_info,
- SINGLE_CHANNEL_ENABLE_TBL_VT1636[0]);
- }
+ plvds_chip_info, single_channel_enable_data);
- if (plvds_setting_info->LCDDithering) {
+ if (plvds_setting_info->LCDDithering)
viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
- plvds_chip_info,
- DITHERING_ENABLE_TBL_VT1636[0]);
- } else {
+ plvds_chip_info, dithering_enable_data);
+ else
viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
- plvds_chip_info,
- DITHERING_DISABLE_TBL_VT1636[0]);
- }
+ plvds_chip_info, dithering_disable_data);
}
void viafb_enable_lvds_vt1636(struct lvds_setting_information
*plvds_setting_info,
struct lvds_chip_information *plvds_chip_info)
{
-
viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info,
- VDD_ON_TBL_VT1636[0]);
-
- /* Pad on: */
- switch (plvds_chip_info->output_interface) {
- case INTERFACE_DVP0:
- {
- viafb_write_reg_mask(SR1E, VIASR, 0xC0, 0xC0);
- break;
- }
-
- case INTERFACE_DVP1:
- {
- viafb_write_reg_mask(SR1E, VIASR, 0x30, 0x30);
- break;
- }
-
- case INTERFACE_DFP_LOW:
- {
- viafb_write_reg_mask(SR2A, VIASR, 0x03, 0x03);
- break;
- }
-
- case INTERFACE_DFP_HIGH:
- {
- viafb_write_reg_mask(SR2A, VIASR, 0x03, 0x0C);
- break;
- }
-
- }
+ vdd_on_data);
}
void viafb_disable_lvds_vt1636(struct lvds_setting_information
*plvds_setting_info,
struct lvds_chip_information *plvds_chip_info)
{
-
viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info,
- VDD_OFF_TBL_VT1636[0]);
-
- /* Pad off: */
- switch (plvds_chip_info->output_interface) {
- case INTERFACE_DVP0:
- {
- viafb_write_reg_mask(SR1E, VIASR, 0x00, 0xC0);
- break;
- }
-
- case INTERFACE_DVP1:
- {
- viafb_write_reg_mask(SR1E, VIASR, 0x00, 0x30);
- break;
- }
-
- case INTERFACE_DFP_LOW:
- {
- viafb_write_reg_mask(SR2A, VIASR, 0x00, 0x03);
- break;
- }
-
- case INTERFACE_DFP_HIGH:
- {
- viafb_write_reg_mask(SR2A, VIASR, 0x00, 0x0C);
- break;
- }
-
- }
+ vdd_off_data);
}
bool viafb_lvds_identify_vt1636(u8 i2c_adapter)
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index 0c9ce88e95e8..68bd23476c64 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -32,10 +32,14 @@
#include <linux/dma-mapping.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
+#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/xilinxfb.h>
#include <linux/slab.h>
+
+#ifdef CONFIG_PPC_DCR
#include <asm/dcr.h>
+#endif
#define DRIVER_NAME "xilinxfb"
@@ -123,10 +127,10 @@ struct xilinxfb_drvdata {
registers */
void __iomem *regs; /* virt. address of the control
registers */
-
+#ifdef CONFIG_PPC_DCR
dcr_host_t dcr_host;
unsigned int dcr_len;
-
+#endif
void *fb_virt; /* virt. address of the frame buffer */
dma_addr_t fb_phys; /* phys. address of the frame buffer */
int fb_alloced; /* Flag, was the fb memory alloced? */
@@ -152,9 +156,10 @@ static void xilinx_fb_out_be32(struct xilinxfb_drvdata *drvdata, u32 offset,
{
if (drvdata->flags & PLB_ACCESS_FLAG)
out_be32(drvdata->regs + (offset << 2), val);
+#ifdef CONFIG_PPC_DCR
else
dcr_write(drvdata->dcr_host, offset, val);
-
+#endif
}
static int
@@ -383,8 +388,11 @@ static int xilinxfb_release(struct device *dev)
if (drvdata->flags & PLB_ACCESS_FLAG) {
iounmap(drvdata->regs);
release_mem_region(drvdata->regs_phys, 8);
- } else
+ }
+#ifdef CONFIG_PPC_DCR
+ else
dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
+#endif
kfree(drvdata);
dev_set_drvdata(dev, NULL);
@@ -404,7 +412,7 @@ xilinxfb_of_probe(struct platform_device *op, const struct of_device_id *match)
u32 tft_access;
struct xilinxfb_platform_data pdata;
struct resource res;
- int size, rc, start;
+ int size, rc;
struct xilinxfb_drvdata *drvdata;
/* Copy with the default pdata (not a ptr reference!) */
@@ -437,7 +445,10 @@ xilinxfb_of_probe(struct platform_device *op, const struct of_device_id *match)
dev_err(&op->dev, "invalid address\n");
goto err;
}
- } else {
+ }
+#ifdef CONFIG_PPC_DCR
+ else {
+ int start;
res.start = 0;
start = dcr_resource_start(op->dev.of_node, 0);
drvdata->dcr_len = dcr_resource_len(op->dev.of_node, 0);
@@ -447,6 +458,7 @@ xilinxfb_of_probe(struct platform_device *op, const struct of_device_id *match)
goto err;
}
}
+#endif
prop = of_get_property(op->dev.of_node, "phys-size", &size);
if ((prop) && (size >= sizeof(u32)*2)) {
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 2839e281cd65..b7b5014ff714 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -517,10 +517,10 @@ static W1_MASTER_ATTR_RO(max_slave_count, S_IRUGO);
static W1_MASTER_ATTR_RO(attempts, S_IRUGO);
static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
static W1_MASTER_ATTR_RO(pointer, S_IRUGO);
-static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUGO);
-static W1_MASTER_ATTR_RW(pullup, S_IRUGO | S_IWUGO);
-static W1_MASTER_ATTR_RW(add, S_IRUGO | S_IWUGO);
-static W1_MASTER_ATTR_RW(remove, S_IRUGO | S_IWUGO);
+static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUSR | S_IWGRP);
+static W1_MASTER_ATTR_RW(pullup, S_IRUGO | S_IWUSR | S_IWGRP);
+static W1_MASTER_ATTR_RW(add, S_IRUGO | S_IWUSR | S_IWGRP);
+static W1_MASTER_ATTR_RW(remove, S_IRUGO | S_IWUSR | S_IWGRP);
static struct attribute *w1_master_default_attrs[] = {
&w1_master_attribute_name.attr,
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 81e3d6100894..3dd4971160ef 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -38,11 +38,11 @@
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/moduleparam.h>
-#include <linux/clk.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
+#include <linux/pm_runtime.h>
#include <mach/hardware.h>
#include <plat/prcm.h>
@@ -61,8 +61,6 @@ struct omap_wdt_dev {
void __iomem *base; /* physical */
struct device *dev;
int omap_wdt_users;
- struct clk *ick;
- struct clk *fck;
struct resource *mem;
struct miscdevice omap_wdt_miscdev;
};
@@ -146,8 +144,7 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
return -EBUSY;
- clk_enable(wdev->ick); /* Enable the interface clock */
- clk_enable(wdev->fck); /* Enable the functional clock */
+ pm_runtime_get_sync(wdev->dev);
/* initialize prescaler */
while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
@@ -177,8 +174,7 @@ static int omap_wdt_release(struct inode *inode, struct file *file)
omap_wdt_disable(wdev);
- clk_disable(wdev->ick);
- clk_disable(wdev->fck);
+ pm_runtime_put_sync(wdev->dev);
#else
printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
#endif
@@ -293,19 +289,7 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev)
wdev->omap_wdt_users = 0;
wdev->mem = mem;
-
- wdev->ick = clk_get(&pdev->dev, "ick");
- if (IS_ERR(wdev->ick)) {
- ret = PTR_ERR(wdev->ick);
- wdev->ick = NULL;
- goto err_clk;
- }
- wdev->fck = clk_get(&pdev->dev, "fck");
- if (IS_ERR(wdev->fck)) {
- ret = PTR_ERR(wdev->fck);
- wdev->fck = NULL;
- goto err_clk;
- }
+ wdev->dev = &pdev->dev;
wdev->base = ioremap(res->start, resource_size(res));
if (!wdev->base) {
@@ -315,8 +299,8 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, wdev);
- clk_enable(wdev->ick);
- clk_enable(wdev->fck);
+ pm_runtime_enable(wdev->dev);
+ pm_runtime_get_sync(wdev->dev);
omap_wdt_disable(wdev);
omap_wdt_adjust_timeout(timer_margin);
@@ -334,11 +318,7 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev)
__raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
timer_margin);
- /* autogate OCP interface clock */
- __raw_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG);
-
- clk_disable(wdev->ick);
- clk_disable(wdev->fck);
+ pm_runtime_put_sync(wdev->dev);
omap_wdt_dev = pdev;
@@ -350,12 +330,6 @@ err_misc:
err_ioremap:
wdev->base = NULL;
-
-err_clk:
- if (wdev->ick)
- clk_put(wdev->ick);
- if (wdev->fck)
- clk_put(wdev->fck);
kfree(wdev);
err_kzalloc:
@@ -387,8 +361,6 @@ static int __devexit omap_wdt_remove(struct platform_device *pdev)
release_mem_region(res->start, resource_size(res));
platform_set_drvdata(pdev, NULL);
- clk_put(wdev->ick);
- clk_put(wdev->fck);
iounmap(wdev->base);
kfree(wdev);
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 7d24b0d94ed4..347f17edad77 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -261,7 +261,7 @@ static void init_evtchn_cpu_bindings(void)
}
#endif
- memset(cpu_evtchn_mask(0), ~0, sizeof(cpu_evtchn_mask(0)));
+ memset(cpu_evtchn_mask(0), ~0, sizeof(struct cpu_evtchn_s));
}
static inline void clear_evtchn(int port)
@@ -377,7 +377,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
irq = find_unbound_irq();
set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
- handle_edge_irq, "event");
+ handle_fasteoi_irq, "event");
evtchn_to_irq[evtchn] = irq;
irq_info[irq] = mk_evtchn_info(evtchn);
@@ -435,6 +435,11 @@ static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
irq = per_cpu(virq_to_irq, cpu)[virq];
if (irq == -1) {
+ irq = find_unbound_irq();
+
+ set_irq_chip_and_handler_name(irq, &xen_percpu_chip,
+ handle_percpu_irq, "virq");
+
bind_virq.virq = virq;
bind_virq.vcpu = cpu;
if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
@@ -442,11 +447,6 @@ static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
BUG();
evtchn = bind_virq.port;
- irq = find_unbound_irq();
-
- set_irq_chip_and_handler_name(irq, &xen_percpu_chip,
- handle_percpu_irq, "virq");
-
evtchn_to_irq[evtchn] = irq;
irq_info[irq] = mk_virq_info(evtchn, virq);
@@ -578,41 +578,75 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
{
struct shared_info *sh = HYPERVISOR_shared_info;
int cpu = smp_processor_id();
+ unsigned long *cpu_evtchn = cpu_evtchn_mask(cpu);
int i;
unsigned long flags;
static DEFINE_SPINLOCK(debug_lock);
+ struct vcpu_info *v;
spin_lock_irqsave(&debug_lock, flags);
- printk("vcpu %d\n ", cpu);
+ printk("\nvcpu %d\n ", cpu);
for_each_online_cpu(i) {
- struct vcpu_info *v = per_cpu(xen_vcpu, i);
- printk("%d: masked=%d pending=%d event_sel %08lx\n ", i,
- (get_irq_regs() && i == cpu) ? xen_irqs_disabled(get_irq_regs()) : v->evtchn_upcall_mask,
- v->evtchn_upcall_pending,
- v->evtchn_pending_sel);
+ int pending;
+ v = per_cpu(xen_vcpu, i);
+ pending = (get_irq_regs() && i == cpu)
+ ? xen_irqs_disabled(get_irq_regs())
+ : v->evtchn_upcall_mask;
+ printk("%d: masked=%d pending=%d event_sel %0*lx\n ", i,
+ pending, v->evtchn_upcall_pending,
+ (int)(sizeof(v->evtchn_pending_sel)*2),
+ v->evtchn_pending_sel);
+ }
+ v = per_cpu(xen_vcpu, cpu);
+
+ printk("\npending:\n ");
+ for (i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--)
+ printk("%0*lx%s", (int)sizeof(sh->evtchn_pending[0])*2,
+ sh->evtchn_pending[i],
+ i % 8 == 0 ? "\n " : " ");
+ printk("\nglobal mask:\n ");
+ for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
+ printk("%0*lx%s",
+ (int)(sizeof(sh->evtchn_mask[0])*2),
+ sh->evtchn_mask[i],
+ i % 8 == 0 ? "\n " : " ");
+
+ printk("\nglobally unmasked:\n ");
+ for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
+ printk("%0*lx%s", (int)(sizeof(sh->evtchn_mask[0])*2),
+ sh->evtchn_pending[i] & ~sh->evtchn_mask[i],
+ i % 8 == 0 ? "\n " : " ");
+
+ printk("\nlocal cpu%d mask:\n ", cpu);
+ for (i = (NR_EVENT_CHANNELS/BITS_PER_LONG)-1; i >= 0; i--)
+ printk("%0*lx%s", (int)(sizeof(cpu_evtchn[0])*2),
+ cpu_evtchn[i],
+ i % 8 == 0 ? "\n " : " ");
+
+ printk("\nlocally unmasked:\n ");
+ for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) {
+ unsigned long pending = sh->evtchn_pending[i]
+ & ~sh->evtchn_mask[i]
+ & cpu_evtchn[i];
+ printk("%0*lx%s", (int)(sizeof(sh->evtchn_mask[0])*2),
+ pending, i % 8 == 0 ? "\n " : " ");
}
- printk("pending:\n ");
- for(i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--)
- printk("%08lx%s", sh->evtchn_pending[i],
- i % 8 == 0 ? "\n " : " ");
- printk("\nmasks:\n ");
- for(i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
- printk("%08lx%s", sh->evtchn_mask[i],
- i % 8 == 0 ? "\n " : " ");
-
- printk("\nunmasked:\n ");
- for(i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
- printk("%08lx%s", sh->evtchn_pending[i] & ~sh->evtchn_mask[i],
- i % 8 == 0 ? "\n " : " ");
printk("\npending list:\n");
- for(i = 0; i < NR_EVENT_CHANNELS; i++) {
+ for (i = 0; i < NR_EVENT_CHANNELS; i++) {
if (sync_test_bit(i, sh->evtchn_pending)) {
- printk(" %d: event %d -> irq %d\n",
+ int word_idx = i / BITS_PER_LONG;
+ printk(" %d: event %d -> irq %d%s%s%s\n",
cpu_from_evtchn(i), i,
- evtchn_to_irq[i]);
+ evtchn_to_irq[i],
+ sync_test_bit(word_idx, &v->evtchn_pending_sel)
+ ? "" : " l2-clear",
+ !sync_test_bit(i, sh->evtchn_mask)
+ ? "" : " globally-masked",
+ sync_test_bit(i, cpu_evtchn)
+ ? "" : " locally-masked");
}
}
@@ -663,6 +697,9 @@ static void __xen_evtchn_do_upcall(void)
int irq = evtchn_to_irq[port];
struct irq_desc *desc;
+ mask_evtchn(port);
+ clear_evtchn(port);
+
if (irq != -1) {
desc = irq_to_desc(irq);
if (desc)
@@ -800,10 +837,10 @@ static void ack_dynirq(unsigned int irq)
{
int evtchn = evtchn_from_irq(irq);
- move_native_irq(irq);
+ move_masked_irq(irq);
if (VALID_EVTCHN(evtchn))
- clear_evtchn(evtchn);
+ unmask_evtchn(evtchn);
}
static int retrigger_dynirq(unsigned int irq)
@@ -959,7 +996,7 @@ static struct irq_chip xen_dynamic_chip __read_mostly = {
.mask = disable_dynirq,
.unmask = enable_dynirq,
- .ack = ack_dynirq,
+ .eoi = ack_dynirq,
.set_affinity = set_affinity_irq,
.retrigger = retrigger_dynirq,
};
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index d409495876f1..132939f36020 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -64,9 +64,11 @@
int xen_store_evtchn;
-EXPORT_SYMBOL(xen_store_evtchn);
+EXPORT_SYMBOL_GPL(xen_store_evtchn);
struct xenstore_domain_interface *xen_store_interface;
+EXPORT_SYMBOL_GPL(xen_store_interface);
+
static unsigned long xen_store_mfn;
static BLOCKING_NOTIFIER_HEAD(xenstore_chain);
diff --git a/drivers/xen/xenfs/Makefile b/drivers/xen/xenfs/Makefile
index 25275c3bbdff..4fde9440fe1f 100644
--- a/drivers/xen/xenfs/Makefile
+++ b/drivers/xen/xenfs/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_XENFS) += xenfs.o
-xenfs-objs = super.o xenbus.o \ No newline at end of file
+xenfs-y = super.o xenbus.o privcmd.o
+xenfs-$(CONFIG_XEN_DOM0) += xenstored.o
diff --git a/drivers/xen/xenfs/privcmd.c b/drivers/xen/xenfs/privcmd.c
new file mode 100644
index 000000000000..f80be7f6eb95
--- /dev/null
+++ b/drivers/xen/xenfs/privcmd.c
@@ -0,0 +1,404 @@
+/******************************************************************************
+ * privcmd.c
+ *
+ * Interface to privileged domain-0 commands.
+ *
+ * Copyright (c) 2002-2004, K A Fraser, B Dragovic
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/uaccess.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/tlb.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/xen.h>
+#include <xen/privcmd.h>
+#include <xen/interface/xen.h>
+#include <xen/features.h>
+#include <xen/page.h>
+#include <xen/xen-ops.h>
+
+#ifndef HAVE_ARCH_PRIVCMD_MMAP
+static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma);
+#endif
+
+static long privcmd_ioctl_hypercall(void __user *udata)
+{
+ struct privcmd_hypercall hypercall;
+ long ret;
+
+ if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
+ return -EFAULT;
+
+ ret = privcmd_call(hypercall.op,
+ hypercall.arg[0], hypercall.arg[1],
+ hypercall.arg[2], hypercall.arg[3],
+ hypercall.arg[4]);
+
+ return ret;
+}
+
+static void free_page_list(struct list_head *pages)
+{
+ struct page *p, *n;
+
+ list_for_each_entry_safe(p, n, pages, lru)
+ __free_page(p);
+
+ INIT_LIST_HEAD(pages);
+}
+
+/*
+ * Given an array of items in userspace, return a list of pages
+ * containing the data. If copying fails, either because of memory
+ * allocation failure or a problem reading user memory, return an
+ * error code; its up to the caller to dispose of any partial list.
+ */
+static int gather_array(struct list_head *pagelist,
+ unsigned nelem, size_t size,
+ void __user *data)
+{
+ unsigned pageidx;
+ void *pagedata;
+ int ret;
+
+ if (size > PAGE_SIZE)
+ return 0;
+
+ pageidx = PAGE_SIZE;
+ pagedata = NULL; /* quiet, gcc */
+ while (nelem--) {
+ if (pageidx > PAGE_SIZE-size) {
+ struct page *page = alloc_page(GFP_KERNEL);
+
+ ret = -ENOMEM;
+ if (page == NULL)
+ goto fail;
+
+ pagedata = page_address(page);
+
+ list_add_tail(&page->lru, pagelist);
+ pageidx = 0;
+ }
+
+ ret = -EFAULT;
+ if (copy_from_user(pagedata + pageidx, data, size))
+ goto fail;
+
+ data += size;
+ pageidx += size;
+ }
+
+ ret = 0;
+
+fail:
+ return ret;
+}
+
+/*
+ * Call function "fn" on each element of the array fragmented
+ * over a list of pages.
+ */
+static int traverse_pages(unsigned nelem, size_t size,
+ struct list_head *pos,
+ int (*fn)(void *data, void *state),
+ void *state)
+{
+ void *pagedata;
+ unsigned pageidx;
+ int ret = 0;
+
+ BUG_ON(size > PAGE_SIZE);
+
+ pageidx = PAGE_SIZE;
+ pagedata = NULL; /* hush, gcc */
+
+ while (nelem--) {
+ if (pageidx > PAGE_SIZE-size) {
+ struct page *page;
+ pos = pos->next;
+ page = list_entry(pos, struct page, lru);
+ pagedata = page_address(page);
+ pageidx = 0;
+ }
+
+ ret = (*fn)(pagedata + pageidx, state);
+ if (ret)
+ break;
+ pageidx += size;
+ }
+
+ return ret;
+}
+
+struct mmap_mfn_state {
+ unsigned long va;
+ struct vm_area_struct *vma;
+ domid_t domain;
+};
+
+static int mmap_mfn_range(void *data, void *state)
+{
+ struct privcmd_mmap_entry *msg = data;
+ struct mmap_mfn_state *st = state;
+ struct vm_area_struct *vma = st->vma;
+ int rc;
+
+ /* Do not allow range to wrap the address space. */
+ if ((msg->npages > (LONG_MAX >> PAGE_SHIFT)) ||
+ ((unsigned long)(msg->npages << PAGE_SHIFT) >= -st->va))
+ return -EINVAL;
+
+ /* Range chunks must be contiguous in va space. */
+ if ((msg->va != st->va) ||
+ ((msg->va+(msg->npages<<PAGE_SHIFT)) > vma->vm_end))
+ return -EINVAL;
+
+ rc = xen_remap_domain_mfn_range(vma,
+ msg->va & PAGE_MASK,
+ msg->mfn, msg->npages,
+ vma->vm_page_prot,
+ st->domain);
+ if (rc < 0)
+ return rc;
+
+ st->va += msg->npages << PAGE_SHIFT;
+
+ return 0;
+}
+
+static long privcmd_ioctl_mmap(void __user *udata)
+{
+ struct privcmd_mmap mmapcmd;
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ int rc;
+ LIST_HEAD(pagelist);
+ struct mmap_mfn_state state;
+
+ if (!xen_initial_domain())
+ return -EPERM;
+
+ if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
+ return -EFAULT;
+
+ rc = gather_array(&pagelist,
+ mmapcmd.num, sizeof(struct privcmd_mmap_entry),
+ mmapcmd.entry);
+
+ if (rc || list_empty(&pagelist))
+ goto out;
+
+ down_write(&mm->mmap_sem);
+
+ {
+ struct page *page = list_first_entry(&pagelist,
+ struct page, lru);
+ struct privcmd_mmap_entry *msg = page_address(page);
+
+ vma = find_vma(mm, msg->va);
+ rc = -EINVAL;
+
+ if (!vma || (msg->va != vma->vm_start) ||
+ !privcmd_enforce_singleshot_mapping(vma))
+ goto out_up;
+ }
+
+ state.va = vma->vm_start;
+ state.vma = vma;
+ state.domain = mmapcmd.dom;
+
+ rc = traverse_pages(mmapcmd.num, sizeof(struct privcmd_mmap_entry),
+ &pagelist,
+ mmap_mfn_range, &state);
+
+
+out_up:
+ up_write(&mm->mmap_sem);
+
+out:
+ free_page_list(&pagelist);
+
+ return rc;
+}
+
+struct mmap_batch_state {
+ domid_t domain;
+ unsigned long va;
+ struct vm_area_struct *vma;
+ int err;
+
+ xen_pfn_t __user *user;
+};
+
+static int mmap_batch_fn(void *data, void *state)
+{
+ xen_pfn_t *mfnp = data;
+ struct mmap_batch_state *st = state;
+
+ if (xen_remap_domain_mfn_range(st->vma, st->va & PAGE_MASK, *mfnp, 1,
+ st->vma->vm_page_prot, st->domain) < 0) {
+ *mfnp |= 0xf0000000U;
+ st->err++;
+ }
+ st->va += PAGE_SIZE;
+
+ return 0;
+}
+
+static int mmap_return_errors(void *data, void *state)
+{
+ xen_pfn_t *mfnp = data;
+ struct mmap_batch_state *st = state;
+
+ put_user(*mfnp, st->user++);
+
+ return 0;
+}
+
+static struct vm_operations_struct privcmd_vm_ops;
+
+static long privcmd_ioctl_mmap_batch(void __user *udata)
+{
+ int ret;
+ struct privcmd_mmapbatch m;
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ unsigned long nr_pages;
+ LIST_HEAD(pagelist);
+ struct mmap_batch_state state;
+
+ if (!xen_initial_domain())
+ return -EPERM;
+
+ if (copy_from_user(&m, udata, sizeof(m)))
+ return -EFAULT;
+
+ nr_pages = m.num;
+ if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
+ return -EINVAL;
+
+ ret = gather_array(&pagelist, m.num, sizeof(xen_pfn_t),
+ m.arr);
+
+ if (ret || list_empty(&pagelist))
+ goto out;
+
+ down_write(&mm->mmap_sem);
+
+ vma = find_vma(mm, m.addr);
+ ret = -EINVAL;
+ if (!vma ||
+ vma->vm_ops != &privcmd_vm_ops ||
+ (m.addr != vma->vm_start) ||
+ ((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) ||
+ !privcmd_enforce_singleshot_mapping(vma)) {
+ up_write(&mm->mmap_sem);
+ goto out;
+ }
+
+ state.domain = m.dom;
+ state.vma = vma;
+ state.va = m.addr;
+ state.err = 0;
+
+ ret = traverse_pages(m.num, sizeof(xen_pfn_t),
+ &pagelist, mmap_batch_fn, &state);
+
+ up_write(&mm->mmap_sem);
+
+ if (state.err > 0) {
+ ret = 0;
+
+ state.user = m.arr;
+ traverse_pages(m.num, sizeof(xen_pfn_t),
+ &pagelist,
+ mmap_return_errors, &state);
+ }
+
+out:
+ free_page_list(&pagelist);
+
+ return ret;
+}
+
+static long privcmd_ioctl(struct file *file,
+ unsigned int cmd, unsigned long data)
+{
+ int ret = -ENOSYS;
+ void __user *udata = (void __user *) data;
+
+ switch (cmd) {
+ case IOCTL_PRIVCMD_HYPERCALL:
+ ret = privcmd_ioctl_hypercall(udata);
+ break;
+
+ case IOCTL_PRIVCMD_MMAP:
+ ret = privcmd_ioctl_mmap(udata);
+ break;
+
+ case IOCTL_PRIVCMD_MMAPBATCH:
+ ret = privcmd_ioctl_mmap_batch(udata);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+#ifndef HAVE_ARCH_PRIVCMD_MMAP
+static int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n",
+ vma, vma->vm_start, vma->vm_end,
+ vmf->pgoff, vmf->virtual_address);
+
+ return VM_FAULT_SIGBUS;
+}
+
+static struct vm_operations_struct privcmd_vm_ops = {
+ .fault = privcmd_fault
+};
+
+static int privcmd_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ /* Unsupported for auto-translate guests. */
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return -ENOSYS;
+
+ /* DONTCOPY is essential for Xen as copy_page_range is broken. */
+ vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
+ vma->vm_ops = &privcmd_vm_ops;
+ vma->vm_private_data = NULL;
+
+ return 0;
+}
+
+static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
+{
+ return (xchg(&vma->vm_private_data, (void *)1) == NULL);
+}
+#endif
+
+const struct file_operations privcmd_file_ops = {
+ .unlocked_ioctl = privcmd_ioctl,
+ .mmap = privcmd_mmap,
+};
diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c
index bd96340063c1..d6662b789b6b 100644
--- a/drivers/xen/xenfs/super.c
+++ b/drivers/xen/xenfs/super.c
@@ -12,6 +12,8 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/magic.h>
+#include <linux/mm.h>
+#include <linux/backing-dev.h>
#include <xen/xen.h>
@@ -22,6 +24,62 @@
MODULE_DESCRIPTION("Xen filesystem");
MODULE_LICENSE("GPL");
+static int xenfs_set_page_dirty(struct page *page)
+{
+ return !TestSetPageDirty(page);
+}
+
+static const struct address_space_operations xenfs_aops = {
+ .set_page_dirty = xenfs_set_page_dirty,
+};
+
+static struct backing_dev_info xenfs_backing_dev_info = {
+ .ra_pages = 0, /* No readahead */
+ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
+};
+
+static struct inode *xenfs_make_inode(struct super_block *sb, int mode)
+{
+ struct inode *ret = new_inode(sb);
+
+ if (ret) {
+ ret->i_mode = mode;
+ ret->i_mapping->a_ops = &xenfs_aops;
+ ret->i_mapping->backing_dev_info = &xenfs_backing_dev_info;
+ ret->i_uid = ret->i_gid = 0;
+ ret->i_blocks = 0;
+ ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
+ }
+ return ret;
+}
+
+static struct dentry *xenfs_create_file(struct super_block *sb,
+ struct dentry *parent,
+ const char *name,
+ const struct file_operations *fops,
+ void *data,
+ int mode)
+{
+ struct dentry *dentry;
+ struct inode *inode;
+
+ dentry = d_alloc_name(parent, name);
+ if (!dentry)
+ return NULL;
+
+ inode = xenfs_make_inode(sb, S_IFREG | mode);
+ if (!inode) {
+ dput(dentry);
+ return NULL;
+ }
+
+ inode->i_fop = fops;
+ inode->i_private = data;
+
+ d_add(dentry, inode);
+ return dentry;
+}
+
static ssize_t capabilities_read(struct file *file, char __user *buf,
size_t size, loff_t *off)
{
@@ -44,10 +102,23 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
[1] = {},
{ "xenbus", &xenbus_file_ops, S_IRUSR|S_IWUSR },
{ "capabilities", &capabilities_file_ops, S_IRUGO },
+ { "privcmd", &privcmd_file_ops, S_IRUSR|S_IWUSR },
{""},
};
+ int rc;
- return simple_fill_super(sb, XENFS_SUPER_MAGIC, xenfs_files);
+ rc = simple_fill_super(sb, XENFS_SUPER_MAGIC, xenfs_files);
+ if (rc < 0)
+ return rc;
+
+ if (xen_initial_domain()) {
+ xenfs_create_file(sb, sb->s_root, "xsd_kva",
+ &xsd_kva_file_ops, NULL, S_IRUSR|S_IWUSR);
+ xenfs_create_file(sb, sb->s_root, "xsd_port",
+ &xsd_port_file_ops, NULL, S_IRUSR|S_IWUSR);
+ }
+
+ return rc;
}
static int xenfs_get_sb(struct file_system_type *fs_type,
@@ -66,11 +137,25 @@ static struct file_system_type xenfs_type = {
static int __init xenfs_init(void)
{
- if (xen_domain())
- return register_filesystem(&xenfs_type);
+ int err;
+ if (!xen_domain()) {
+ printk(KERN_INFO "xenfs: not registering filesystem on non-xen platform\n");
+ return 0;
+ }
+
+ err = register_filesystem(&xenfs_type);
+ if (err) {
+ printk(KERN_ERR "xenfs: Unable to register filesystem!\n");
+ goto out;
+ }
+
+ err = bdi_init(&xenfs_backing_dev_info);
+ if (err)
+ unregister_filesystem(&xenfs_type);
+
+ out:
- printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n");
- return 0;
+ return err;
}
static void __exit xenfs_exit(void)
diff --git a/drivers/xen/xenfs/xenfs.h b/drivers/xen/xenfs/xenfs.h
index 51f08b2d0bf1..b68aa6200003 100644
--- a/drivers/xen/xenfs/xenfs.h
+++ b/drivers/xen/xenfs/xenfs.h
@@ -2,5 +2,8 @@
#define _XENFS_XENBUS_H
extern const struct file_operations xenbus_file_ops;
+extern const struct file_operations privcmd_file_ops;
+extern const struct file_operations xsd_kva_file_ops;
+extern const struct file_operations xsd_port_file_ops;
#endif /* _XENFS_XENBUS_H */
diff --git a/drivers/xen/xenfs/xenstored.c b/drivers/xen/xenfs/xenstored.c
new file mode 100644
index 000000000000..fef20dbc6a5c
--- /dev/null
+++ b/drivers/xen/xenfs/xenstored.c
@@ -0,0 +1,68 @@
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+
+#include <xen/page.h>
+
+#include "xenfs.h"
+#include "../xenbus/xenbus_comms.h"
+
+static ssize_t xsd_read(struct file *file, char __user *buf,
+ size_t size, loff_t *off)
+{
+ const char *str = (const char *)file->private_data;
+ return simple_read_from_buffer(buf, size, off, str, strlen(str));
+}
+
+static int xsd_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+static int xsd_kva_open(struct inode *inode, struct file *file)
+{
+ file->private_data = (void *)kasprintf(GFP_KERNEL, "0x%p",
+ xen_store_interface);
+ if (!file->private_data)
+ return -ENOMEM;
+ return 0;
+}
+
+static int xsd_kva_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ size_t size = vma->vm_end - vma->vm_start;
+
+ if ((size > PAGE_SIZE) || (vma->vm_pgoff != 0))
+ return -EINVAL;
+
+ if (remap_pfn_range(vma, vma->vm_start,
+ virt_to_pfn(xen_store_interface),
+ size, vma->vm_page_prot))
+ return -EAGAIN;
+
+ return 0;
+}
+
+const struct file_operations xsd_kva_file_ops = {
+ .open = xsd_kva_open,
+ .mmap = xsd_kva_mmap,
+ .read = xsd_read,
+ .release = xsd_release,
+};
+
+static int xsd_port_open(struct inode *inode, struct file *file)
+{
+ file->private_data = (void *)kasprintf(GFP_KERNEL, "%d",
+ xen_store_evtchn);
+ if (!file->private_data)
+ return -ENOMEM;
+ return 0;
+}
+
+const struct file_operations xsd_port_file_ops = {
+ .open = xsd_port_open,
+ .read = xsd_read,
+ .release = xsd_release,
+};
diff --git a/firmware/Makefile b/firmware/Makefile
index 9c2d19452d0b..74d47cd0886c 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -32,12 +32,14 @@ fw-shipped-$(CONFIG_ADAPTEC_STARFIRE) += adaptec/starfire_rx.bin \
adaptec/starfire_tx.bin
fw-shipped-$(CONFIG_ATARI_DSP56K) += dsp56k/bootstrap.bin
fw-shipped-$(CONFIG_ATM_AMBASSADOR) += atmsar11.fw
-fw-shipped-$(CONFIG_BNX2X) += bnx2x-e1-5.2.13.0.fw bnx2x-e1h-5.2.13.0.fw
-fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-5.0.0.j15.fw \
- bnx2/bnx2-rv2p-09-5.0.0.j10.fw \
- bnx2/bnx2-rv2p-09ax-5.0.0.j10.fw \
- bnx2/bnx2-mips-06-5.0.0.j6.fw \
- bnx2/bnx2-rv2p-06-5.0.0.j3.fw
+fw-shipped-$(CONFIG_BNX2X) += bnx2x/bnx2x-e1-6.0.34.0.fw \
+ bnx2x/bnx2x-e1h-6.0.34.0.fw \
+ bnx2x/bnx2x-e2-6.0.34.0.fw
+fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-6.0.17.fw \
+ bnx2/bnx2-rv2p-09-6.0.17.fw \
+ bnx2/bnx2-rv2p-09ax-6.0.17.fw \
+ bnx2/bnx2-mips-06-6.0.15.fw \
+ bnx2/bnx2-rv2p-06-6.0.15.fw
fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin
fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin
fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \
diff --git a/firmware/WHENCE b/firmware/WHENCE
index ae5f8a47f292..f22c4dfd0733 100644
--- a/firmware/WHENCE
+++ b/firmware/WHENCE
@@ -679,8 +679,8 @@ Found in hex form in kernel source.
Driver: bnx2x: Broadcom Everest
-File: bnx2x-e1-5.2.13.0.fw
-File: bnx2x-e1h-5.2.13.0.fw
+File: bnx2x/bnx2x-e1-5.2.13.0.fw
+File: bnx2x/bnx2x-e1h-5.2.13.0.fw
License:
Copyright (c) 2007-2010 Broadcom Corporation
@@ -699,15 +699,16 @@ Found in hex form in kernel source.
Driver: BNX2 - Broadcom NetXtremeII
-File: bnx2/bnx2-mips-06-4.6.16.fw
-File: bnx2/bnx2-rv2p-06-4.6.16.fw
-File: bnx2/bnx2-mips-09-4.6.17.fw
-File: bnx2/bnx2-rv2p-09-4.6.15.fw
+File: bnx2/bnx2-mips-06-6.0.15.fw
+File: bnx2/bnx2-rv2p-06-6.0.15.fw
+File: bnx2/bnx2-mips-09-6.0.17.fw
+File: bnx2/bnx2-rv2p-09-6.0.17.fw
+File: bnx2/bnx2-rv2p-09ax-6.0.17.fw
Licence:
This file contains firmware data derived from proprietary unpublished
- source code, Copyright (c) 2004 - 2009 Broadcom Corporation.
+ source code, Copyright (c) 2004 - 2010 Broadcom Corporation.
Permission is hereby granted for the distribution of this firmware data
in hexadecimal or equivalent format, provided this copyright notice is
diff --git a/firmware/bnx2/bnx2-mips-06-5.0.0.j6.fw.ihex b/firmware/bnx2/bnx2-mips-06-5.0.0.j6.fw.ihex
deleted file mode 100644
index 8d379bffbfef..000000000000
--- a/firmware/bnx2/bnx2-mips-06-5.0.0.j6.fw.ihex
+++ /dev/null
@@ -1,5908 +0,0 @@
-:10000000080001100800000000004CC8000000C8F3
-:1000100000000000000000000000000008004CC8C4
-:100020000000001400004D90080000880800000047
-:10003000000058C400004DA408005A40000000848D
-:100040000000A668080058C4000001540000A6EC97
-:10005000080031D808000000000075340000A840F6
-:1000600000000000000000000000000008007534DF
-:100070000000002400011D7408000488080004002A
-:100080000000175C00011D98000000000000000047
-:100090000000000000000000000000000000000060
-:1000A000080000A80800000000003B38000134F4FC
-:1000B0000000000000000000000000000000000040
-:0800C000000000000000000038
-:0800C8000A00004400000000E2
-:1000D000000000000000000D636F6D352E302E30E3
-:1000E0006A36000005000002000000000000000366
-:1000F00000000014000000320000000300000000B7
-:1001000000000000000000000000000000000000EF
-:1001100000000010000001360000EA600000000549
-:1001200000000000000000000000000000000008C7
-:1001300000000000000000000000000000000000BF
-:1001400000000000000000000000000000000000AF
-:10015000000000000000000000000000000000009F
-:10016000000000020000000000000000000000008D
-:10017000000000000000000000000000000000007F
-:10018000000000000000000000000010000000005F
-:10019000000000000000000000000000000000005F
-:1001A000000000000000000000000000000000004F
-:1001B000000000000000000000000000000000003F
-:1001C000000000000000000000000000000000002F
-:1001D000000000000000000000000000100000030C
-:1001E000000000000000000D0000000D3C020800AF
-:1001F00024424D003C03080024634DFCAC40000049
-:100200000043202B1480FFFD244200043C1D080005
-:1002100037BD7FFC03A0F0213C1008002610011020
-:100220003C1C0800279C4D000E000214000000003A
-:100230000000000D27BDFFE8AFBF0014AFB00010F5
-:100240009742010830437000240220001062000B26
-:10025000286220011440002F0000102124024000D9
-:1002600010620025000000002402600010620026D9
-:10027000000010210A0000948FBF001427500100D5
-:10028000920200091040001A240300013C020800F9
-:100290008C42002010400016000018210E00052B93
-:1002A00000000000960300083C06080094C64DBEFE
-:1002B0008E0400188F8200209605000C00031C009D
-:1002C00000661825AC440000AC450004240400017D
-:1002D000AC400008AC40000CAC400010AC40001436
-:1002E000AC4000180E000550AC43001C0000182163
-:1002F0000A000093006010210E0003BD0000000002
-:100300000A000093000010210E000F810000000081
-:10031000000010218FBF00148FB0001003E0000810
-:1003200027BD001827BDFFE0AFB00010AFBF001819
-:10033000AFB10014275001009203000B2402001AF1
-:10034000961100081462005B00002821322200018F
-:1003500010400008000000008E0200009603001408
-:10036000000211C200021040005A10210A0000DBF6
-:10037000A44300803C0208008C420020104000286A
-:10038000000000000E00052B00000000974201084D
-:100390009743010C8F8500203042003E3063FFFF01
-:1003A0000002140000431025ACA200008F4201009F
-:1003B0003C06080094C64DBEACA20004974301164B
-:1003C0009744010E3C02200000031C003084FFFF14
-:1003D00000641825ACA3000800C230259742011024
-:1003E0009743011224040001000214003063FFFF50
-:1003F00000431025ACA2000C974201143042FFFFCD
-:10040000ACA200108F420118ACA200149342010B61
-:10041000304200FFACA200180E000550ACA6001C34
-:100420003C0208008C420040244200013C010800CC
-:10043000AC2200403C0308008C63004432220002DE
-:1004400032240004246300013C010800AC23004472
-:10045000108000180002282B8F4202B804430008C5
-:100460008E0200203C0208008C4200602442000101
-:100470003C010800AC2200600A0000FB24050001DA
-:100480009603001600002821AF4202808E0200046D
-:10049000A7430284AF4202883C021000AF4202B878
-:1004A0003C0208008C42005C244200013C01080030
-:1004B000AC22005C8FBF00188FB100148FB0001009
-:1004C00000A0102103E0000827BD002027BDFFE0A9
-:1004D000AFB00010AFBF0018AFB10014275001003B
-:1004E0009203000B24020003961100081462006DB1
-:1004F000000020213222000110400008000000000E
-:100500008E02000096030014000211C20002104087
-:10051000005A10210A000142A44300803C02080056
-:100520008C42002010400025000000000E00052B2A
-:1005300000000000974201089743010C8F850020BE
-:100540003042003E3063FFFF0002140000431025DC
-:10055000ACA200008F4201003C06080094C64DBECC
-:10056000ACA20004974301169744010E3C02200000
-:1005700000031C003084FFFF00641825ACA30008B2
-:1005800000C2302597420110974301122404000154
-:10059000000214003063FFFF00431025ACA2000CE2
-:1005A000974201143042FFFFACA20010ACA000142F
-:1005B000ACA000180E000550ACA6001C3C020800C0
-:1005C0008C420040244200013C010800AC22004063
-:1005D0003C0208008C420044322300042442000103
-:1005E0003C010800AC2200441060001A32220002D4
-:1005F0008F4202B8044300088E0200203C0208002B
-:100600008C420060244200013C010800AC220060E2
-:100610000A0001772404000196030016000020213F
-:10062000AF4202808E020004A7430284AF420288D8
-:100630003C021000AF4202B83C0208008C42005C51
-:10064000244200013C010800AC22005C0A00017851
-:100650008FBF001810400013000020218F430104B9
-:100660003C026020AC4300148C420004240301FED1
-:10067000304203FF1443000B000020218F42010091
-:10068000000211C02442FFFC2C420008104000026E
-:100690002403000200031F403C026000AC436914C5
-:1006A000000020218FBF00188FB100148FB0001000
-:1006B0000080102103E0000827BD00208F430100C7
-:1006C0002402010050620003000311C20000000D6B
-:1006D000000311C200021040005A1021A440008003
-:1006E00003E00008000010219362000003E000080E
-:1006F000AF80000003E000080000102103E00008C4
-:1007000000001021240201001482000800000000F3
-:100710003C0208008C4200FC244200013C0108001D
-:10072000AC2200FC0A00019F30A200203C0208001D
-:100730008C420084244200013C010800AC22008469
-:1007400030A200201040000830A300103C02080036
-:100750008C420108244200013C010800AC2201083F
-:1007600003E0000800000000106000080000000026
-:100770003C0208008C420104244200013C010800B4
-:10078000AC22010403E00008000000003C02080065
-:100790008C420100244200013C010800AC2201000F
-:1007A00003E000080000000027BDFFE8AFBF001015
-:1007B0002744010094830008306200041040001BAD
-:1007C000306600028F4202B804410008240500018F
-:1007D0003C0208008C420060244200013C010800F9
-:1007E000AC2200600A0001EB8FBF00108C82002059
-:1007F0009483001600002821AF4202808C820004FE
-:10080000A7430284AF4202883C021000AF4202B804
-:100810003C0208008C42005C244200013C010800BC
-:10082000AC22005C0A0001EB8FBF001010C0000674
-:10083000006028218F4401000E00018F000000009D
-:100840000A0001EA240500018F8200088F43010499
-:1008500050430007000028218F4401000E00018F43
-:10086000000000008F420104AF8200080000282130
-:100870008FBF001000A0102103E0000827BD001862
-:100880003C0208008C420088274301009465000C5C
-:10089000244200013C010800AC2200888C6400184E
-:1008A0000345102190454000AF4400388C62001C85
-:1008B0002403FFF800052E000043102434420004F6
-:1008C000AF42003C3C020005AF4200300000000097
-:1008D0000000000000000000AF450404000000001C
-:1008E00000000000000000003C020006344200014D
-:1008F000AF420030000000000000000000000000D7
-:100900008F420000304200101040FFFD0000102117
-:1009100003E000080000000027BDFFE0AFB20018B0
-:100920003C036010AFBF001CAFB10014AFB00010AB
-:100930008C6450002402FF7F3C1A80000082202437
-:100940003484380C24020037AC6450003C12080098
-:1009500026524D38AF42000824020C80AF420024DA
-:100960003C1B80083C06080024C6062C02401021CF
-:100970002404001C2484FFFFAC4600000481FFFD1A
-:10098000244200043C0208002442016C3C0108009F
-:10099000AC224D403C020800244204043C01080003
-:1009A000AC224D443C020800244207B83C01080038
-:1009B000AC224D883C0208002442025C3C03080043
-:1009C000246306343C040800248406E03C05080047
-:1009D00024A53B503C010800AC224DA03C0208007D
-:1009E000244205F43C010800AC264D843C0108007B
-:1009F000AC254D943C010800AC234D9C3C01080003
-:100A0000AC244DA43C010800AC224DA83C010800D8
-:100A1000AC234D3C3C010800AC204D483C01080093
-:100A2000AC204D4C3C010800AC204D503C0108006E
-:100A3000AC204D543C010800AC204D583C0108004E
-:100A4000AC204D5C3C010800AC204D603C0108002E
-:100A5000AC244D643C010800AC204D683C0108000A
-:100A6000AC204D6C3C010800AC204D703C010800EE
-:100A7000AC204D743C010800AC204D783C010800CE
-:100A8000AC264D7C3C010800AC264D803C010800A2
-:100A9000AC204D8C3C010800AC254D903C01080079
-:100AA000AC234D980E0006BB000000003C02800005
-:100AB000344200708C420000AF8200143C030800F6
-:100AC0008C6300208F820004104300043C028000ED
-:100AD0000E0004F3AF8300043C0280003446007033
-:100AE0003C0308008C6300A03C0208008C4200A478
-:100AF000104300048F8400143C010800AC2300A4C0
-:100B0000A743009E8CCA00003C0308008C6300BC15
-:100B10003C0208008C4200B80144202300641821E4
-:100B2000000040210064202B0048102100441021C7
-:100B30003C010800AC2300BC3C010800AC2200B81A
-:100B40008F510000322200071040FFDCAF8A0014F2
-:100B50008CC600003C0508008CA500BC3C040800C5
-:100B60008C8400B800CA302300A628210000102180
-:100B700000A6302B00822021008620213227000190
-:100B80003C010800AC2500BC3C010800AC2400B8C6
-:100B900010E0001F322200028F420100AF4200200D
-:100BA0008F420104AF4200A89342010B0E0001885E
-:100BB000305000FF2E02001D544000040010108031
-:100BC0000E00018B0A0002C5000000000052102137
-:100BD0008C4200000040F8090000000010400005B1
-:100BE0003C0240008F4301043C026020AC430014EF
-:100BF0003C024000AF4201383C0208008C42003405
-:100C0000244200013C010800AC22003432220002E0
-:100C10001040000E322200048F4201400E00018875
-:100C2000AF4200200E00034B000000003C024000D9
-:100C3000AF4201783C0208008C4200382442000197
-:100C40003C010800AC220038322200041040FF981A
-:100C50003C0280008F4201800E000188AF420020DC
-:100C60008F43018024020F00146200050000000081
-:100C70008F420188A742009C0A0002FA3C02400011
-:100C80009362000024030050304200FF1443000828
-:100C90003C0240000E00032D000000005440000400
-:100CA0003C0240000E000E0D000000003C0240001F
-:100CB000AF4201B83C0208008C42003C24420001D3
-:100CC0003C010800AC22003C0A00027A3C02800091
-:100CD0003C0290003442000100822025AF440020F5
-:100CE0008F4200200440FFFE0000000003E00008E7
-:100CF000000000003C0280003442000100822025F8
-:100D000003E00008AF44002027BDFFE0AFB10014AE
-:100D1000AFB0001000808821AFBF00180E000302A2
-:100D200030B000FF9362007D022020210202802566
-:100D3000A370007D8F7000743C0280000E00030BD6
-:100D400002028024160000098FBF00188F4201F8AC
-:100D50000440FFFE24020002AF5101C0A34201C4BF
-:100D60003C021000AF4201F88FBF00188FB1001491
-:100D70008FB0001003E0000827BD002027BDFFE86A
-:100D8000AFBF0010974201843042020010400005BE
-:100D9000000020210E001042000000000A00034164
-:100DA000240400018F420188044000098FBF001015
-:100DB0008F4201883C03FF00004310243C030400E1
-:100DC00014430003240400019362003E8FBF00100F
-:100DD0000080102103E0000827BD00182402000154
-:100DE000A3600022A76200168F4401400A0003108E
-:100DF0002405000127BDFFE8AFBF0014AFB000100D
-:100E000093620000304400FF3883002038820030B5
-:100E10000003182B0002102B00621824106000033E
-:100E200024020050148200628FBF001493420148D4
-:100E3000304200FF2443FFFF2C6200051040005C9D
-:100E40008FBF0014000310803C03080024634CC8CB
-:100E5000004310218C420000004000080000000008
-:100E60000E0003028F4401408F70000C8F4201443A
-:100E70001602000224020001AF62000C0E00030BF8
-:100E80008F4401408F420144145000048FBF00146E
-:100E90008FB000100A000FB827BD00188F62000C39
-:100EA0000A0003B300000000976200108F43014462
-:100EB0003042FFFF1462000900000000240200011C
-:100EC000A76200108F420140AF4202003C021000B6
-:100ED000AF4202380A0003BA8FBF001497620010B5
-:100EE0000A0003B3000000000E0003028F4401401B
-:100EF000976200128F4301443050FFFF1603000237
-:100F000024020001A76200120E00030B8F4401406F
-:100F10008F420144160200048FBF00148FB00010EE
-:100F20000A00034527BD0018976200120A0003B3A8
-:100F300000000000976200148F4301443042FFFF1D
-:100F4000146200068FBF0014240200018FB000104D
-:100F5000A76200140A0012E227BD0018976200146D
-:100F60000A0003B300000000976200168F4301449B
-:100F70003042FFFF14620006240200018FBF0014FC
-:100F80008FB00010A76200160A000BAA27BD001838
-:100F900097620016144000068FBF00143C02080040
-:100FA0008C420070244200013C010800AC22007019
-:100FB0008FB0001003E0000827BD001827BDFFE830
-:100FC000AFBF0014AFB000108F500100936200005B
-:100FD00093430109304400FF2402001F106200A562
-:100FE0002862002010400018240200382862000AFD
-:100FF0001040000C2402000B286200081040002C56
-:1010000000000000046000E528620002144000288F
-:1010100024020006106200268FBF00140A0004B7E5
-:101020008FB000101062005E2862000B144000DCDC
-:101030008FBF00142402000E106200738FB00010E6
-:101040000A0004B700000000106200C028620039E6
-:101050001040000A2402008024020036106200CAF8
-:1010600028620037104000B424020035106200C12D
-:101070008FBF00140A0004B78FB000101062002B5D
-:101080002862008110400006240200C824020039B2
-:10109000106200B48FBF00140A0004B78FB00010B4
-:1010A000106200998FBF00140A0004B78FB00010BF
-:1010B0003C0208008C420020104000B98FBF001491
-:1010C0000E00052B000000008F4201008F830020DE
-:1010D0009745010C97460108AC6200008F4201045D
-:1010E0003C04080094844DBE00052C00AC62000452
-:1010F0008F4201180006340000C43025AC6200089D
-:101100008F42011C24040001AC62000C9342010ACE
-:1011100000A22825AC650010AC600014AC6000187B
-:10112000AC66001C0A00048D8FBF00143C0208004E
-:101130008C4200201040009A8FBF00140E00052B37
-:1011400000000000974401083C03080094634DBE72
-:101150009745010C000422029746010E8F82002061
-:10116000000426000083202500052C003C0300809D
-:1011700000A6282500832025AC400000AC400004D8
-:10118000AC400008AC40000CAC450010AC40001472
-:10119000AC400018AC44001C0A00048C240400017C
-:1011A0009742010C144000150000000093620005F6
-:1011B0003042001014400011000000000E00030235
-:1011C0000200202193620005020020213442001019
-:1011D0000E00030BA36200059362000024030020AD
-:1011E000304200FF1043006D020020218FBF001429
-:1011F0008FB000100A00105827BD00180000000D25
-:101200000A0004B68FBF00143C0208008C42002084
-:10121000104000638FBF00140E00052B000000007B
-:101220008F4201048F8300209744010C3C05080085
-:1012300094A54DBEAC6200009762002C000424000F
-:101240003042FFFF008220253C02400E00A22825EC
-:10125000AC640004AC600008AC60000CAC60001032
-:10126000AC600014AC600018AC65001C0A00048C73
-:10127000240400010E00030202002021A7600008E0
-:101280000E00030B02002021020020210E0003109B
-:10129000240500013C0208008C4200201040004060
-:1012A0008FBF00140E00052B000000009742010CB8
-:1012B0008F8300203C05080094A54DBE0002140059
-:1012C000AC700000AC620004AC6000088F64004C9D
-:1012D0003C02401F00A22825AC64000C8F62005025
-:1012E00024040001AC6200108F620054AC62001450
-:1012F000AC600018AC65001C8FBF00148FB00010EC
-:101300000A00055027BD0018240200205082002545
-:101310008FB000100E000FA202002021104000200C
-:101320008FBF0014020020218FB000100000282180
-:101330000A00031027BD0018020020218FBF0014EF
-:101340008FB000100A00061827BD00189745010C41
-:10135000020020218FBF00148FB000100A00063851
-:1013600027BD0018020020218FB000100A00065D82
-:1013700027BD00189345010D020020218FB00010F9
-:101380000A0006A727BD0018020020218FBF001405
-:101390008FB000100A00068327BD00188FBF00140D
-:1013A0008FB0001003E0000827BD00188F420278BC
-:1013B0000440FFFE2402000234840080AF44024057
-:1013C000A34202443C02100003E00008AF4202784E
-:1013D0003C04080094844DCA3C0208008C424DD461
-:1013E0003083FFFF000318C000431021AF42003CD0
-:1013F0003C0208008C424DD0AF4200383C02005005
-:1014000034420008AF42003000000000000000003D
-:10141000000000008F420000304200201040FFFD1D
-:10142000000000008F4204003C010800AC224DC0C7
-:101430008F4204043C010800AC224DC43C02002051
-:10144000AF420030000000003C02080094424DC84A
-:101450003C03080094634DCC3C05080094A54DCE98
-:1014600024840001004310213083FFFF3C01080069
-:10147000A4224DC83C010800A4244DCA14650003F1
-:10148000000000003C010800A4204DCA03E0000851
-:10149000000000003C05000A27BDFFE803452821A5
-:1014A0003C04080024844DB0AFBF00100E0005B509
-:1014B0002406000A3C02080094424DB23C03080096
-:1014C00094634DCE3042000F2442000300431804C1
-:1014D00024027FFF0043102B10400002AF83001C4A
-:1014E0000000000D0E0004C2000000003C020800D5
-:1014F00094424DBA8FBF001027BD001803E00008CA
-:10150000A74200A23C02000A0342102194430006B5
-:101510003C02080094424DBA3C010800A4234DB699
-:10152000004310238F83001C0002140000021403E8
-:101530000043102B03E000083842000127BDFFE8FC
-:10154000AFBF00103C02000A034210219442000683
-:101550003C010800A4224DB60E00050F000000005B
-:101560005440FFF93C02000A8FBF001003E000085E
-:1015700027BD001827BDFFE8AFBF00100E00050F04
-:101580000000000010400003000000000E00051DD8
-:10159000000000003C0208008C424DC08FBF0010CC
-:1015A00027430400AF4200383C0208008C424DC47F
-:1015B00027BD0018AF830020AF42003C3C0200056D
-:1015C000AF42003003E00008AF8000188F8200189F
-:1015D0003C0300060002114000431025AF420030DA
-:1015E0000000000000000000000000008F4200002A
-:1015F000304200101040FFFD27420400AF8200205F
-:1016000003E00008AF8000183C0608008CC64DC4FB
-:101610008F8500188F8300203C02080094424DBA49
-:1016200027BDFFE024A5000124630020244200011F
-:1016300024C70020AFB10014AFB00010AFBF001836
-:10164000AF850018AF8300203C010800A4224DBAEA
-:10165000309000FF3C010800AC274DC404C10008D5
-:101660000000882104E00006000000003C020800A1
-:101670008C424DC0244200013C010800AC224DC008
-:101680003C02080094424DBA3C03080094634DC8E4
-:101690000010202B004310262C420001004410258E
-:1016A000144000048F830018240200101462000FFD
-:1016B000000000000E000541241100013C03080059
-:1016C00094634DBA3C02080094424DC81462000372
-:1016D000000000000E0004C200000000160000031D
-:1016E000000000000E00052B000000003C03080075
-:1016F00094634DBE3C02080094424DBC246300013B
-:101700003064FFFF3C010800A4234DBE1482000397
-:10171000000000003C010800A4204DBE120000069D
-:10172000000000003C02080094424DBAA74200A20B
-:101730000A0005A3022010210E00050F0000000082
-:1017400010400004022010210E00051D00000000C2
-:10175000022010218FBF00188FB100148FB000102D
-:1017600003E0000827BD00203084FFFF30A5FFFF05
-:1017700000001821108000070000000030820001E6
-:101780001040000200042042006518210A0005AB49
-:101790000005284003E000080060102110C000068A
-:1017A00024C6FFFF8CA2000024A50004AC82000028
-:1017B0000A0005B52484000403E0000800000000CE
-:1017C00010A0000824A3FFFFAC860000000000006A
-:1017D000000000002402FFFF2463FFFF1462FFFAF1
-:1017E0002484000403E0000800000000240200013B
-:1017F000AF62000CA7620010A7620012A76200147B
-:1018000003E00008A76200163082007F0342102127
-:101810003C08000E004818213C0208008C420020C1
-:1018200027BDFFD82407FF80AFB3001CAFB200185C
-:10183000AFB10014AFB00010AFBF00200080802116
-:1018400030B100FF0087202430D200FF1040002F6D
-:1018500000009821AF44002C906200002403005047
-:10186000304200FF1443000E000000003C0208005C
-:101870008C4200E00202102100471024AF42002CED
-:101880003C0208008C4200E0020210213042007F3E
-:101890000342102100481021944200D43053FFFF2E
-:1018A0000E00052B000000003C02080094424DBED3
-:1018B0008F8300200011340000C2302500122C005C
-:1018C0003C02400000C2302534A50001AC7000008D
-:1018D0008FBF0020AC6000048FB20018AC7300080A
-:1018E0008FB10014AC60000C8FB3001CAC6500100D
-:1018F0008FB00010AC60001424040001AC6000182C
-:1019000027BD00280A000550AC66001C8FBF0020D0
-:101910008FB3001C8FB200188FB100148FB000106D
-:1019200003E0000827BD00289343010F24020010A4
-:101930001062000E2865001110A00007240200129A
-:10194000240200082405003A10620006000030213D
-:1019500003E0000800000000240500351462FFFCCD
-:10196000000030210A0005D0000000008F42007402
-:1019700024420FA003E00008AF62000C27BDFFE87F
-:10198000AFBF00100E000310240500018FBF001030
-:1019900024020001A762001227BD001824020001E2
-:1019A00003E00008A360002227BDFFE0AFB10014F0
-:1019B000AFB00010AFBF001830B1FFFF0E00030240
-:1019C000008080219362003F24030004304200FF26
-:1019D0001443000C02002021122000082402000AF7
-:1019E0000E0005C900000000936200052403FFFEFD
-:1019F00000431024A362000524020012A362003FEA
-:101A0000020020210E00030BA360008116200003BA
-:101A1000020020210E00062D0000000002002021FF
-:101A2000322600FF8FBF00188FB100148FB0001056
-:101A3000240500380A0005D027BD002027BDFFE09F
-:101A4000AFBF001CAFB20018AFB10014AFB00010B0
-:101A50000E000302008080210E0005C90000000076
-:101A60009362003F24120018305100FF123200032D
-:101A70000200202124020012A362003F93620005AD
-:101A80002403FFFE004310240E00030BA362000595
-:101A9000020020212405002016320007000030211A
-:101AA0008FBF001C8FB200188FB100148FB00010D0
-:101AB0000A00031027BD00208FBF001C8FB2001842
-:101AC0008FB100148FB00010240500390A0005D032
-:101AD00027BD002027BDFFE8AFB00010AFBF001446
-:101AE0009742010C2405003600808021144000102C
-:101AF000304600FF0E000302000000002402001226
-:101B0000A362003F93620005344200100E0005C935
-:101B1000A36200050E00030B020020210200202119
-:101B20000E000310240500200A00069C000000009F
-:101B30000E0005D0000000000E000302020020216C
-:101B4000936200232403FF9F0200202100431024FE
-:101B50008FBF00148FB00010A36200230A00030B94
-:101B600027BD001827BDFFE0AFBF0018AFB10014BC
-:101B7000AFB0001030B100FF0E00030200808021E2
-:101B8000240200120E0005C9A362003F0E00030BE1
-:101B90000200202102002021022030218FBF0018E6
-:101BA0008FB100148FB00010240500350A0005D055
-:101BB00027BD0020A380002C03E00008A380002D97
-:101BC0008F4202780440FFFE8F820034AF42024011
-:101BD00024020002A34202443C02100003E0000879
-:101BE000AF4202783C0360008C625400304200082F
-:101BF0001440FFFD000000008C625408AF82000C0E
-:101C000024020052AC605408AC645430AC625434CA
-:101C10002402000803E00008AC6254003C026000AB
-:101C20008C42540030420008104000053C03600024
-:101C30008C625400304200081440FFFD0000000098
-:101C40008F83000C3C02600003E00008AC435408A2
-:101C500090A3000024020005008040213063003F73
-:101C600000004821146200050000502190A2001CD1
-:101C700094A3001E304900FF306AFFFFAD00000C46
-:101C8000AD000010AD000024950200148D05001C6D
-:101C90008D0400183042FFFF00491023000211009C
-:101CA000000237C3004038210086202300A2102BF9
-:101CB0000082202300A72823AD05001CAD040018D6
-:101CC000A5090014A5090020A50A001603E00008D4
-:101CD000A50A00228F4201F80440FFFE2402000200
-:101CE000AF4401C0A34201C43C02100003E000085D
-:101CF000AF4201F83C0208008C4200B427BDFFE867
-:101D0000AFBF001424420001AFB000103C01080036
-:101D1000AC2200B48F4300243C02001F30AA00FF15
-:101D20003442FF8030D800FF006280240080F82118
-:101D300030EF00FF1158003B01405821240CFF8078
-:101D40003C19000A3163007F000310C000031940F2
-:101D5000006218213C0208008C4200DC256800016A
-:101D6000310D007F03E21021004310213043007F3A
-:101D700003431821004C102400794821AF4200246D
-:101D80008D220024016C1824006C7026AD22000CFA
-:101D90008D220024310800FFAD220010952200148E
-:101DA000952300208D27001C3042FFFF3063FFFF8A
-:101DB0008D2600180043102300021100000227C3E3
-:101DC0000040282100C4302300E2102B00C2302341
-:101DD00000E53823AD27001CAD2600189522002011
-:101DE000A522001495220022154B000AA5220016F8
-:101DF0008D2300248D2200082546000131450080F6
-:101E00001462000430C4007F108F000238AA0080E2
-:101E100000C0502151AF000131C800FF1518FFC9A3
-:101E2000010058218F8400343082007F0342182142
-:101E30003C02000A006218212402FF800082202454
-:101E4000AF440024A06A0079A06A00838C6200502D
-:101E50008F840034AC6200708C6500743C027FFF9C
-:101E60003442FFFF00A228240E000703AC65007473
-:101E7000AF5000248FBF00148FB0001003E00008A3
-:101E800027BD001827BDFFC0AFBE0038AFB7003474
-:101E9000AFB5002CAFB20020AFB1001CAFB000183E
-:101EA000AFBF003CAFB60030AFB40028AFB30024E2
-:101EB0008F4500248F4600288F43002C3C02001FD2
-:101EC0003442FF800062182400C230240080A82120
-:101ED000AFA3001400A2F0240E0006C7AFA60010A6
-:101EE0003C0208008C4200E02410FF80036088213F
-:101EF00002A2102100501024AF4200243C0208002E
-:101F00008C4200E002A210213042007F03421821DF
-:101F10003C02000A00629021924200D29363008446
-:101F2000305700FF306300FF2402000110620034CC
-:101F30000360202124020002146200360000000029
-:101F40000E0012AE024028219223008392220083C9
-:101F50003063007F3042007F000210C00003194050
-:101F6000006218213C0208008C4200DC02A2102111
-:101F70000043382100F01024AF4200289225007859
-:101F80009224008330E2007F034218213C02000CBF
-:101F900014850007006280212402FFFFA24200F1A5
-:101FA0002402FFFFA64200F20A0007BF2402FFFF3F
-:101FB00096020020A24200F196020022A64200F200
-:101FC0008E020024AE4200F492220083A24200F06E
-:101FD0008E4200C8AE4200FC8E4200C4AE4200F801
-:101FE0008E220050AE4201008E4200CCAE4201046F
-:101FF000922200853042003F0A00081A3442004015
-:102000000E0012D102402821922200850A00081AEF
-:102010003042003F936200852403FFDF3042003FDF
-:10202000A36200859362008500431024A3620085AB
-:102030009363008393620078307400FF304200FFA6
-:1020400010540036240AFF803C0C000C3283007FC1
-:10205000000310C000031940006218213C02080070
-:102060008C4200DC268800013109007F02A2102189
-:102070000043382130E2007F0342182100EA102497
-:10208000AF420028006C80218E020024028A1824AE
-:10209000006A5826AE02000C8E020024310800FFB0
-:1020A000AE02001096020014960300208E07001C5A
-:1020B0003042FFFF3063FFFF8E06001800431023FD
-:1020C00000021100000227C30040282100C4302371
-:1020D00000E2102B00C2302300E53823AE07001CBD
-:1020E000AE06001896020020A602001496020022F6
-:1020F000A602001692220079304200FF1054000719
-:102100000000000051370001316800FF9222007882
-:10211000304200FF1448FFCD0100A021922200832D
-:10212000A22200798E2200500A00087AAE220070A6
-:10213000A22200858E22004C2405FF80AE42010CB5
-:102140009222008534420020A2220085924200D1D2
-:102150003C0308008C6300DC305400FF3C020800A4
-:102160008C4200E400143140001420C002A3182166
-:1021700000C4202102A21021006438210046102151
-:102180000045182400E52824AF450028AF43002C63
-:102190003042007F924400D030E3007F0342282188
-:1021A000034318213C02000C006280213C02000E17
-:1021B000309600FF00A298211296002A000000002D
-:1021C0008E02000C02002021026028211040002510
-:1021D000261000280E0006E2000000009262000DAA
-:1021E00026830001307400FF3042007FA262000DA0
-:1021F0002404FF801697FFF0267300203C0208009D
-:102200008C4200DC0000A02102A210210044102416
-:10221000AF4200283C0208008C4200E43C03080066
-:102220008C6300DC02A2102100441024AF42002C79
-:102230003C0208008C4200E402A318213063007FB6
-:1022400002A210213042007F0342202103431821C3
-:102250003C02000C006280213C02000E0A00083C97
-:10226000008298218E4200D8AE2200508E4200D8C3
-:10227000AE22007092250083924600D19223008303
-:10228000924400D12402FF8000A228243063007F02
-:10229000308400FF00A628250064182A1060000280
-:1022A00030A500FF38A50080A2250083A225007973
-:1022B0000E0006D5000000009222007E02A0202120
-:1022C000A222007A8E2300743C027FFF3442FFFF7B
-:1022D000006218240E000703AE2300748FA20010C2
-:1022E000AF5E00248FBF003CAF4200288FBE003895
-:1022F0008FA200148FB700348FB600308FB5002C3A
-:102300008FB400288FB300248FB200208FB1001C3F
-:102310008FB0001827BD004003E00008AF42002C3A
-:1023200090A2000024420001A0A200003C0308008B
-:102330008C6300F4304200FF1443000F0080302112
-:10234000A0A000003C0208008C4200E48F8400340E
-:10235000008220213082007F034218213C02000CC1
-:10236000006218212402FF8000822024ACC30000F8
-:1023700003E00008AF4400288C82000024420020C3
-:1023800003E00008AC82000094C200003C08080092
-:10239000950800CA30E7FFFF0080482101021021A4
-:1023A000A4C2000094C200003042FFFF00E2102BE4
-:1023B00054400001A4C7000094A200003C030800A0
-:1023C0008C6300CC24420001A4A2000094A200006F
-:1023D0003042FFFF544300078F8600280107102B6F
-:1023E000A4A000005440000101003821A4C700004F
-:1023F0008F8600288CC4001CAF44003C94A20000CF
-:102400008F43003C3042FFFF000210C000621821E1
-:10241000AF43003C8F42003C008220231880000420
-:10242000000000008CC200180A0008DB24420001F2
-:102430008CC20018AF4200383C02005034420010F9
-:10244000AF4200300000000000000000000000006B
-:102450008F420000304200201040FFFD00000000CD
-:102460008F420404AD2200048F420400AD2200001C
-:102470003C020020AF42003003E0000800000000F2
-:1024800027BDFFE0AFB20018AFB10014AFB000102D
-:10249000AFBF001C94C2000000C080213C120800A5
-:1024A000965200C624420001A602000096030000D6
-:1024B00094E2000000E03021144300058FB10030A9
-:1024C0000E0008B0024038210A00090D000000008B
-:1024D0008C8300048C8200042442004004610007C5
-:1024E000AC8200048C820004044000040000000060
-:1024F0008C82000024420001AC82000096020000A1
-:102500003042FFFF50520001A6000000962200005A
-:1025100024420001A62200008F820028962300009A
-:1025200094420016144300048FBF001C24020001D3
-:10253000A62200008FBF001C8FB200188FB10014BC
-:102540008FB0001003E0000827BD00208F8900280D
-:1025500027BDFFE0AFBF00188D22002827480400E8
-:1025600030E700FFAF4200388D22002CAF880030EA
-:10257000AF42003C3C020005AF42003000000000CA
-:10258000000000000000000000000000000000004B
-:10259000000000008C82000C8C82000CAD02000058
-:1025A0008C820010AD0200048C820018AD0200087D
-:1025B0008C82001CAD02000C8CA20014AD02001035
-:1025C0008C820020AD02001490820005304200FF92
-:1025D00000021200AD0200188CA20018AD02001C0F
-:1025E0008CA2000CAD0200208CA20010AD020024D1
-:1025F0008CA2001CAD0200288CA20020AD02002C91
-:10260000AD060030AD000034978300263402FFFF92
-:1026100014620002006020213404FFFF10E000116A
-:10262000AD040038952300369524003624020001BD
-:102630003063FFFF000318C2006918219065004055
-:10264000308400070082100400451025A06200407D
-:102650008F820028944200563042FFFF0A0009741E
-:10266000AD02003C9523003695240036240200017B
-:102670003063FFFF000318C2006918219065004015
-:102680003084000700821004000210270045102447
-:10269000A0620040AD00003C00000000000000000F
-:1026A000000000003C02000634420040AF4200300F
-:1026B0000000000000000000000000008F42000049
-:1026C000304200101040FFFD8F860028AF88003098
-:1026D00024C2005624C7003C24C4002824C500326C
-:1026E00024C600360E0008EEAFA200108FBF0018FF
-:1026F00003E0000827BD00208F8300243C0608006B
-:102700008CC600E88F82003430633FFF00031980DD
-:1027100000461021004310212403FF803046007F33
-:1027200000431024AF420028034618213C02000C4D
-:102730000062302190C2000D30A500FF000038215A
-:1027400034420010A0C2000D8F8900288F8A002417
-:1027500095230036000A138230480003240200014A
-:10276000A4C3000E1102000B290200021040000554
-:10277000240200021100000C240300010A0009B821
-:102780000000182111020006000000000A0009B82C
-:10279000000018218CC2002C0A0009B82443000153
-:1027A0008CC20014244300018CC200180043102B7B
-:1027B00050400009240700012402002714A200034E
-:1027C000000000000A0009C4240700019522003E11
-:1027D00024420001A522003E000A13823043000378
-:1027E0002C620002104000090080282114600004BF
-:1027F0000000000094C200360A0009D43046FFFFF2
-:102800008CC600380A0009D400802821000030213D
-:102810003C04080024844DD80A000921000000006F
-:10282000274901008D22000C95230006012020215C
-:10283000000216023046003F3063FFFF24020027EB
-:1028400000C0282128C7002810C2000EAF83002432
-:1028500010E00008240200312402002110C2000907
-:102860002402002510C200079382002D0A0009F3FC
-:102870000000000010C200059382002D0A0009F339
-:10288000000000000A00098C000000000A0006BEDB
-:102890000000000095230006912400058D25000C02
-:1028A0008D2600108D2700188D28001C8D290020F2
-:1028B000244200013C010800A4234DDE3C01080035
-:1028C000A0244DDD3C010800AC254DE43C0108008E
-:1028D000AC264DE83C010800AC274DF03C01080057
-:1028E000AC284DF43C010800AC294DF803E0000889
-:1028F000A382002D8F87002827BDFFC0AFB300340F
-:10290000AFB20030AFB1002CAFB00028AFBF00387D
-:102910003C0208008C4200D094E3003030B0FFFF4E
-:10292000005010073045FFFF3063FFFF00C09821C3
-:10293000A7A200103C110800963100C614A300069F
-:102940003092FFFF8CE2002424420030AF42003C72
-:102950000A000A2C8CE2002094E200323042FFFF91
-:1029600054A2000827A400188CE2002C2442003056
-:10297000AF42003C8CE20028AF4200380A000A3A1D
-:102980008F84002827A5001027A6002002203821C8
-:102990000E0008B0A7A000208FA20018244200302B
-:1029A000AF4200388FA2001CAF42003C8F84002849
-:1029B0003C020005AF4200309482003427430400FB
-:1029C0003042FFFF0202102B14400007AF8300309B
-:1029D0009482005494830034020210210043102397
-:1029E0000A000A4E3043FFFF94830054948200345F
-:1029F0000223182100501023006218233063FFFFC8
-:102A0000948200163042FFFF1443000300000000D0
-:102A10000A000A5C24030001948200163042FFFF82
-:102A20000043102B104000058F8200309482001666
-:102A3000006210233043FFFF8F820030AC53000050
-:102A4000AC400004AC520008AC43000C3C02000651
-:102A500034420010AF4200300000000000000000CF
-:102A6000000000008F420000304200101040FFFDC7
-:102A7000001018C20064182190650040320400075D
-:102A8000240200018FBF00388FB300348FB20030B2
-:102A90008FB1002C8FB00028008210040045102553
-:102AA00027BD004003E00008A062004027BDFFA84A
-:102AB000AFB60050AFB5004CAFB40048AFB3004460
-:102AC000AFB1003CAFBF0054AFB20040AFB0003870
-:102AD0008C9000003C0208008C4200E88F86003495
-:102AE000960300022413FF8000C2302130633FFFB1
-:102AF0000003198000C3382100F3102490B20000B5
-:102B0000AF42002C9203000230E2007F03423021EA
-:102B10003C02000E00C28821306300C02402004045
-:102B20000080A82100A0B021146200260000A0218E
-:102B30008E3400388E220018144000022402000156
-:102B4000AE2200189202000D304200201440001501
-:102B50008F8200343C0308008C6300DC001238C014
-:102B6000001231400043102100C7302100463821B7
-:102B700030E300073C02008030E6007800C23025D8
-:102B80000343182100F31024AF4208002463090016
-:102B9000AF4608108E2200188C63000800431021F5
-:102BA000AE2200188E22002C8E2300182442000131
-:102BB0000062182B1060003D000000000A000B109E
-:102BC00000000000920300022402FFC00043102412
-:102BD000304200FF1440000524020001AE2200181C
-:102BE000962200360A000AF93054FFFF8E220014A4
-:102BF00024420001AE2200189202000000021600DA
-:102C000000021603044100290000000096020002A1
-:102C100027A4001000802821A7A200169602000217
-:102C200024070001000030213042FFFFAF82002462
-:102C30000E000921AFA0001C960300023C0408000E
-:102C40008C8400E88F82003430633FFF00031980DA
-:102C500000441021004310213043007F3C05000C4C
-:102C60000053102403431821AF42002800651821A7
-:102C70009062000D001221403042007FA062000DE2
-:102C80003C0308008C6300E48F8200340043102171
-:102C90000044382130E2007F03421021004510211A
-:102CA00000F31824AF430028AEA200009222000DCA
-:102CB000304200101040001302A020218F83002812
-:102CC0008EA40000028030219462003E2442FFFF67
-:102CD000A462003E948400029625000E3084FFFF1B
-:102CE0000E000A0B30A5FFFF8F82002894430034AA
-:102CF0009622000E1443000302A0202124020001AA
-:102D0000A382002C02C028210E00089600000000BB
-:102D10008FBF00548FB600508FB5004C8FB4004861
-:102D20008FB300448FB200408FB1003C8FB00038A9
-:102D300003E0000827BD00588F82002827BDFFD080
-:102D4000AFB40028AFB20020AFBF002CAFB3002457
-:102D5000AFB1001CAFB00018904400D0904300D138
-:102D60000000A021309200FFA3A30010306300FFF9
-:102D70008C5100D88C5300DC1072002B240200010F
-:102D80003C0308008C6300E493A400108F8200349D
-:102D90002406FF800004214000431021004410213C
-:102DA0003043007F00461024AF420028034318211F
-:102DB0003C02000C006218218C62000427A400145D
-:102DC00027A5001002228021027010230440001564
-:102DD000AFA300149062000D00C21024304200FF27
-:102DE00014400007020088219062000D3442004028
-:102DF0000E000896A062000D0A000B5593A2001069
-:102E00000E000A79241400018F830028AC7000D8CA
-:102E100093A20010A06200D193A200101452FFD818
-:102E20000000000024020001168200048FBF002C65
-:102E30000E0006BE000000008FBF002C8FB40028DB
-:102E40008FB300248FB200208FB1001C8FB0001808
-:102E500003E0000827BD003027BDFFD8AFB3001C3A
-:102E6000AFB20018AFB10014AFB00010AFBF002078
-:102E70000080982100E0802130B1FFFF0E00052B7B
-:102E800030D200FF00000000000000000000000041
-:102E90008F820020AC510000AC520004AC530008FB
-:102EA000AC40000CAC400010AC400014AC4000182A
-:102EB0003C03080094634DBE02038025AC50001C07
-:102EC00000000000000000000000000024040001D9
-:102ED0008FBF00208FB3001C8FB200188FB1001479
-:102EE0008FB000100A00055027BD002827BDFFE85D
-:102EF000AFB00010AFBF001430A5FFFF30C600FF19
-:102F00000080802124020C80AF42002400000000D9
-:102F100000000000000000000000000000000000B1
-:102F20000E000B64000000003C040800248400E054
-:102F30008C8200002403FF808FBF00140202102146
-:102F400000431024AF4200248C8200003C03000A9E
-:102F5000020280213210007F035010218FB0001038
-:102F60000043102127BD001803E00008AF820028AD
-:102F700027BDFFE8AFBF00108F4401403C030800AD
-:102F80008C6300E02402FF80AF84003400831821AA
-:102F900000621024AF4200243C020008034240219A
-:102FA000950500023063007F3C02000A03431821AC
-:102FB0000062182130A5FFFF3402FFFF000030211E
-:102FC0003C07602010A20006AF8300282402FFFF08
-:102FD000A5020002946500D40E000B8930A5FFFF06
-:102FE0008FBF001024020C8027BD001803E00008EA
-:102FF000AF4200243C020008034240219502000237
-:103000003C0A0800954A00C63046FFFF14C000077E
-:103010003402FFFF8F8200288F8400343C07602039
-:10302000944500D40A000BF230A5FFFF10C2002423
-:103030008F87002894E2005494E400163045FFFF87
-:1030400000A6102300A6182B3089FFFF1060000493
-:103050003044FFFF00C51023012210233044FFFF3E
-:10306000008A102B1040000C012A102324020001BA
-:10307000A50200162402FFFFA502000294E500D479
-:103080008F8400340000302130A5FFFF3C07602012
-:103090000A000B89000000000044102A10400008BC
-:1030A00000000000950200163042000110400004AC
-:1030B000000000009742007E24420014A502001682
-:1030C00003E00008000000008F84002827BDFFE017
-:1030D000AFBF0018948200349483003E1060001A41
-:1030E0003048FFFF9383002C240200011462002764
-:1030F0008FBF00188F820028000818C2310800070F
-:10310000006218212447003A244900542444002036
-:10311000244500302446003490620040304200FFD5
-:103120000102100730420001104000168FBF001846
-:103130000E0008EEAFA900108F82002894420034E0
-:103140000A000C0B3048FFFF948300369482003451
-:103150001043000E8FBF001894820036A482003402
-:1031600094820056A48200548C82002CAC820024ED
-:1031700094820032A48200309482003CA482003AFF
-:103180008FBF00180A000BCB27BD002003E000080A
-:1031900027BD002027BDFFE8AFBF00108F4A010008
-:1031A0003C0508008CA500E03C02080090424DE47C
-:1031B0003C0C0800958C4DDE01452821304B003F2A
-:1031C00030A2007F03424021396900323C02000AEC
-:1031D0003963003F2C630001010240212D290001C9
-:1031E0002402FF8000A2282401234825AF8A00344E
-:1031F00000801821AF4500240000302100802821E4
-:1032000024070001AF8800283C04080024844DD81E
-:10321000AF8C002415200007A380002D240200207D
-:103220005562000F006020213402FFFF5582000C20
-:10323000006020212402002015620005000000002B
-:103240008C6300142402FFFF1062000700000000DE
-:103250000E000921000000000A000C6800000000B8
-:103260000E00098C016028210E000C0000000000F7
-:103270008FBF001024020C8027BD001803E0000857
-:10328000AF4200243C0208008C4200E027BDFFA0B2
-:10329000AFB1003C008210212411FF80AFBE005866
-:1032A000AFB70054AFB20040AFB00038AFBF005C62
-:1032B000AFB60050AFB5004CAFB40048AFB3004458
-:1032C000005110248F4800248F4900288F47002880
-:1032D000AF4200243C0208008C4200E000809021B4
-:1032E00024060006008210213042007F034218218C
-:1032F0003C02000A006280213C02001F3442FF8031
-:1033000000E2382427A40010260500F00122F02452
-:103310000102B8240E0005B5AFA700308FA2001837
-:10332000AE0200C48FA2001CAE0200C88FA200240F
-:10333000AE0200CC93A40010920300D12402FF80BF
-:103340000082102400431025304900FF3083007FA5
-:103350003122007F0062102A10400004000310C0D8
-:1033600001311026304900FF000310C0000319404E
-:10337000006218213C0208008C4200DC920400D25A
-:10338000024210210043102100511024AF420028B6
-:1033900093A300103063007F000310C000031940A6
-:1033A000006218213C0208008C4200DC024210211D
-:1033B000004310213042007F034218213C02000CE0
-:1033C000006240218FA300142402FFFF106200302E
-:1033D000309500FF93A2001195030014304400FFC4
-:1033E0003063FFFF0064182B1060000D0000000028
-:1033F000950400148D07001C8D0600183084FFFF13
-:1034000000442023000421000000102100E43821A2
-:1034100000E4202B00C230210A000CE200C430215D
-:10342000950400148D07001C8D0600183084FFFFE2
-:1034300000822023000421000000102100801821B8
-:1034400000C2302300E4202B00C4302300E33823E3
-:10345000AD07001CAD06001893A20011A5020014D0
-:1034600097A20012A50200168FA20014AD02001050
-:103470008FA20014AD02000C93A20011A50200203F
-:1034800097A20012A50200228FA20014AD02002410
-:103490002406FF80024610243256007FAF420024EB
-:1034A000035618213C02000A006280218E02004C63
-:1034B0008FA200203124007F000428C0AE020050FB
-:1034C0008FA200200004214000852821AE02007058
-:1034D00093A2001001208821A202008393A2001071
-:1034E000A2020079920200853042003FA2020085CC
-:1034F0003C0208008C4200DC0242102100451021F1
-:1035000000461024AF42002C3C0208008C4200E42C
-:103510003C0308008C6300DC0242102100441021AF
-:1035200000461024AF4200283C0208008C4200E410
-:103530000243182100651821024210210044102185
-:103540003042007F3063007F93A5001003422021AA
-:10355000034318213C02000E006240213C02000C93
-:1035600010B1008C008248213233007F16600019B0
-:103570002404FF803C0208008C4200DC024210213F
-:1035800000441024AF42002C3C0208008C4200E4AE
-:103590003C0308008C6300DC02421021004410242C
-:1035A000AF4200283C0208008C4200E4024318218C
-:1035B0003063007F024210213042007F034220210D
-:1035C000034318213C02000E006240213C02000C23
-:1035D000008248219124000D2414FF800000102156
-:1035E00000942025A124000D9504000295050014E7
-:1035F0008D07001C3084FFFF30A5FFFF8D060018EB
-:10360000008520230004210000E4382100C230217D
-:1036100000E4202B00C43021AD07001CAD060018CB
-:1036200095020002A5020014A50000168D020008F4
-:10363000AD0200108D020008AD02000C95020002E0
-:10364000A5020020A50000228D020008AD02002482
-:103650009122000D3042004010400042262200011D
-:103660003C0208008C4200E0A3B300283C10000A92
-:103670000242102100541024AF4200243C020800F2
-:103680008C4200E0A380002C27A4002C02421021D1
-:103690003042007F03421821007018218C6200D84C
-:1036A0008D26000427A50028AFA9002C0046102174
-:1036B000AC6200D80E000A79AF83002893A30028DB
-:1036C0008F8200280E0006BEA04300D10E000C0021
-:1036D0000000000002541024AF4200243C02080005
-:1036E0008C4200DC00132940001320C000A42021DC
-:1036F000024210210044102100541024AF42002C3B
-:103700003C0208008C4200E43C0308008C6300DCAF
-:10371000035630210242102100451021005410248C
-:10372000AF4200283C0208008C4200E4024318210A
-:103730000064182102421021004510213042007F10
-:103740003063007F03422021034318213C02000E16
-:10375000006240213C02000C00D080210082482100
-:10376000262200013043007F14750005304400FF1D
-:103770002403FF800223102400431026304400FF5E
-:1037800093A2001000808821250800281444FF76A9
-:103790002529002093A400108FA300142402FFFF0A
-:1037A0001062000A308900FF248200012483000196
-:1037B0003042007F14550005306900FF2403FF806C
-:1037C0000083102400431026304900FF9202007845
-:1037D000305300FF11330032012088213C020800E1
-:1037E0008C4200DC3225007F000520C00005294006
-:1037F00000A42021024210212406FF800044102151
-:1038000000461024AF42002C3C0308008C6300DC0F
-:103810003C0208008C4200E40243182102421021BD
-:103820000045102100641821004610243063007FF9
-:10383000AF420028034318213C02000E00624021E1
-:103840003C0208008C4200E48D06000C010020219F
-:1038500002421021004510213042007F034218210E
-:103860003C02000C0062482110C0000D01202821FC
-:103870000E0006E2000000002402FF80022218244D
-:1038800026240001006228263082007F14550002A1
-:10389000308300FF30A300FF1473FFD00060882145
-:1038A0008E0300743C027FFF3442FFFF0062182445
-:1038B000AE0300740E00070302402021AF5700241E
-:1038C0008FA20030AF5E00288FBF005C8FBE005813
-:1038D0008FB700548FB600508FB5004C8FB400489E
-:1038E0008FB300448FB200408FB1003C8FB00038DE
-:1038F00027BD006003E00008AF42002C27BDFFD8C1
-:10390000AFB1001CAFBF0020AFB000182751018835
-:10391000922200032408FF803C03000A3047007F06
-:10392000A3A700108F4601803C0208008C4200E0F3
-:10393000AF86003400C2282100A81024AF42002422
-:103940009224000030A2007F034210210043102186
-:10395000AF8200283084007F2402000214820025F8
-:10396000000719403C0208008C4200E400C210210C
-:103970000043282130A2007F0342182100A8102410
-:10398000AF4200283C02000C006218219062000D3A
-:10399000AFA3001400481025A062000D8FA30014EF
-:1039A0009062000D304200405040006A8FBF0020FE
-:1039B0008F860028A380002C27A400148CC200D876
-:1039C0008C63000427A50010004310210E000A7923
-:1039D000ACC200D893A300108F8200280E0006BE50
-:1039E000A04300D10E000C00000000000A000EA34E
-:1039F0008FBF00200E0006C700C020210E0006D594
-:103A0000000000003C0200080342802192230001D4
-:103A10009202007B1443004F8FBF002092220000CF
-:103A20003044007F24020004108200172882000521
-:103A30001040000624020005240200031082000743
-:103A40008FB1001C0A000EA40000000010820012BA
-:103A50008FBF00200A000EA48FB1001C92050083C6
-:103A6000920600788E0700748F84003430A500FF22
-:103A700000073E0230C600FF0E00070B30E7007F54
-:103A80000A000EA38FBF00200E000C6F8F8400343D
-:103A90000A000EA38FBF002024020C80AF42002436
-:103AA0009202003E30420040104000200000000022
-:103AB0009202003E000216000002160304410006B6
-:103AC000000000008F8400340E00063824050093A7
-:103AD0000A000EA38FBF00209202003F24030018AB
-:103AE000304200FF1443000C8F8400342405003959
-:103AF0000E0005D0000030210E0003028F84003438
-:103B000024020012A202003F0E00030B8F84003437
-:103B10000A000EA38FBF0020240500360E0005D03A
-:103B2000000030210A000EA38FBF00200E00030208
-:103B30008F8400349202000534420020A202000566
-:103B40000E00030B8F8400340E0010588F84003455
-:103B50008FBF00208FB1001C8FB0001824020C8092
-:103B600027BD002803E00008AF42002427BDFFE87E
-:103B7000AFB00010AFBF00142743010094620008EB
-:103B8000000214000002140304410002000080211E
-:103B90002410000194620008304200801040001A96
-:103BA00002001021946200083042200010400016EC
-:103BB000020010218C6300183C021C2D344219EDC8
-:103BC000240600061062000F3C0760213C0208003A
-:103BD0008C4200D4104000078F8200288F83002879
-:103BE000906200623042000F34420040A0620062E6
-:103BF0008F8200288F840034944500D40E000B89F6
-:103C000030A5FFFF020010218FBF00148FB00010FD
-:103C100003E0000827BD001827BDFFE0AFB1001486
-:103C2000AFB00010A380002CAFBF00188F4501007B
-:103C30003C0308008C6300E02402FF80AF85003461
-:103C400000A318213064007F03442021006218245F
-:103C50003C02000A00822021AF43002427500100CB
-:103C60008E0200148C8300DCAF84002800431023F4
-:103C700018400004000088218E0200140E000B1C66
-:103C8000AC8200DC9202000B24030002304200FFF1
-:103C90001443002F0000000096020008304300FF8C
-:103CA0002402008214620005240200840E0009D65A
-:103CB000000000000A000F2F00000000146200093D
-:103CC000240200818F8200288F8400343C07602109
-:103CD000944500D49206000530A5FFFF0A000F1E90
-:103CE00030C600FF14620027000000009202000AA4
-:103CF000304300FF3062002010400004306200407A
-:103D00008F8400340A000F1A24060040104000047B
-:103D1000000316008F8400340A000F1A24060041A5
-:103D200000021603044100178F8400342406004269
-:103D30008F8200283C076019944500D430A5FFFF0E
-:103D40000E000B89000000000A000F2F0000000089
-:103D50009202000B24030016304200FF10430006BD
-:103D6000000000009202000B24030017304200FF05
-:103D700014430004000000000E000EA90000000023
-:103D8000004088210E000C00000000009202000A92
-:103D9000304200081040000624020C808F85002865
-:103DA0003C0400080E0012860344202124020C80EB
-:103DB000AF4200248FBF0018022010218FB00010E6
-:103DC0008FB1001403E0000827BD002027BDFFE8E5
-:103DD000AFBF0014AFB000108F5000243C030800A8
-:103DE0008C6300E08F4501002402FF8000A31821AE
-:103DF0003064007F03442021006218243C02000A42
-:103E000000822021AF850034AF43002490820062FD
-:103E1000AF8400283042000F34420050A08200627C
-:103E20003C02001F3442FF800E0006BE02028024C6
-:103E3000AF5000248FBF00148FB0001003E00008C3
-:103E400027BD00183C0208008C4200201040001DD5
-:103E50002745010090A300093C02000803422021ED
-:103E600024020018546200033C0200080A000F708C
-:103E700024020008034220212402001614620005D7
-:103E80002402001724020012A082003F0A000F7AC9
-:103E900094A700085462000694A7000893620005E6
-:103EA0002403FFFE00431024A362000594A700082A
-:103EB00090A6001B8CA4000094A500060A000B64C9
-:103EC00000073C0003E00008000000002744010058
-:103ED00094820008304500FF38A3008238A2008495
-:103EE0002C6300012C4200010062182510600006BE
-:103EF000240200839382002D1040000D000000007A
-:103F00000A000C330000000014A2000524A2FF8068
-:103F10008F4301043C02602003E00008AC4300141E
-:103F2000304200FF2C420002104000032402002215
-:103F30000A000ED40000000014A2000300000000DC
-:103F40000A000F41000000000A000F5F000000009F
-:103F50009363007E9362007A1443000900002021DD
-:103F60009362000024030050304200FF1443000419
-:103F7000240400019362007E24420001A362007EBB
-:103F800003E00008008010218F4201F80440FFFE8A
-:103F900024020002AF4401C0A34201C43C0210004D
-:103FA00003E00008AF4201F827BDFFE8AFBF0010F3
-:103FB0009362003F2403000A304200FF144300468E
-:103FC000000000008F6300548F62004C1062007D7F
-:103FD000036030219362000024030050304200FF50
-:103FE0001443002F000000008F4401403C020800F1
-:103FF0008C4200E02403FF80008210210043102443
-:10400000AF4200243C0208008C4200E08F6500545F
-:104010003C03000A008220213084007F03441021E9
-:1040200000431021AC4501089762003C8F63004CAF
-:104030003042FFFF0002104000621821AF63005CB5
-:104040008F6300548F64004C9762003C0064182317
-:104050003042FFFF00031843000210400043102AC3
-:1040600010400006000000008F6200548F63004C77
-:10407000004310230A000FF0000210439762003C37
-:104080003042FFFF00021040ACC200642402000175
-:10409000A0C0007CA0C2008424020C80AF42002497
-:1040A0000E000FA28F440140104000478FBF001048
-:1040B0008F4301408F4201F80440FFFE24020002BA
-:1040C000AF4301C0A34201C43C021000AF4201F85B
-:1040D0000A0010408FBF00109362003F24030010BD
-:1040E000304200FF14430004000000008F440140F0
-:1040F0000A00102C000028219362003F24030016C0
-:10410000304200FF1443000424020014A362003F65
-:104110000A00103A000000008F62004C8F630050CC
-:1041200000431023044100288FBF001093620081D8
-:1041300024420001A3620081936200812C420004AA
-:1041400014400010000000009362003F24030004AC
-:10415000304200FF14430006000000008F4401407D
-:104160008FBF0010240500930A00063827BD0018F1
-:104170008F440140240500938FBF00100A0006A75A
-:1041800027BD00188F4401400E000302000000000C
-:104190008F6200542442FFFFAF6200548F620050D0
-:1041A0002442FFFFAF6200500E00030B8F4401401A
-:1041B0008F4401408FBF0010240500040A00031043
-:1041C00027BD00188FBF001003E0000827BD0018AE
-:1041D0008F4201889363007E00021402304400FF86
-:1041E000306300FF1464000D000000009362008043
-:1041F000304200FF1044000900000000A36400806A
-:104200009362000024030050304200FF1443000476
-:10421000000000000A00076F8F440180A364008043
-:1042200003E000080000000027BDFFE8AFB0001069
-:10423000AFBF001493620005240300303042003009
-:1042400014430089008080213C0208008C42002039
-:1042500010400080020020210E00052B000000000D
-:104260008F850020ACB000009362003E9363003F56
-:10427000304200FF00021200306300FF00431025AF
-:10428000ACA2000493620082000216000002160332
-:1042900004410005000000003C0308008C63004856
-:1042A0000A00107E000000009362003E3042004091
-:1042B000144000030000182193620081304300FF86
-:1042C0009362008200031E00304200FF00021400CF
-:1042D00000621825ACA300088F620040ACA2000C5D
-:1042E0008F620048ACA200108F62004CACA2001498
-:1042F0008F6200508F63004C004310230441000381
-:10430000000000000A0010928F62004C8F62005083
-:10431000ACA200183C02080094424DBE3C03C00B06
-:1043200000002021004310250E000550ACA2001C07
-:104330008F6200548F840020AC8200008F6200588E
-:10434000AC8200048F62005CAC8200088F62006067
-:104350008F43007400431021AC82000C8F62006414
-:10436000AC820010976300689762006A00031C002B
-:104370003042FFFF00621825AC8300149362008274
-:1043800024030080304200FF1443000300000000BB
-:104390000A0010C6AC8000188F63000C24020001D4
-:1043A0001062000E2402FFFF9362003E3042004084
-:1043B0001440000A2402FFFF8F63000C8F42007438
-:1043C000006218233C02080000621024144000021E
-:1043D000000028210060282100051043AC8200184D
-:1043E0003C02080094424DBE3C03C00C000020215A
-:1043F000004310258F8300200E000550AC62001C86
-:104400008F6200188F8300203C05080094A54DBEE4
-:1044100024040001AC620000AC6000048F66006CF4
-:104420003C02400D00A22825AC6600088F6200DC2B
-:10443000AC62000CAC600010936200050002160034
-:10444000AC620014AC6000180E000550AC65001C96
-:10445000020020218FBF00148FB00010A360000560
-:104460000A0004B927BD00188FBF00148FB00010D8
-:1044700003E0000827BD00189742007C30C600FF0B
-:10448000A08600843047FFFF2402000514C2000B01
-:1044900024E3465090A201122C420007104000076E
-:1044A00024E30A0090A30112240200140062100405
-:1044B00000E210210A0010FE3047FFFF3067FFFFC7
-:1044C00003E00008A4870014AC87004C8CA201080C
-:1044D0000080402100A0482100E2102330C600FFE8
-:1044E0001840000393AA001324E2FFFCACA20108C9
-:1044F00030C2000110400008000000008D02005092
-:1045000000E2102304410013240600058D0200542C
-:1045100010E20010000000008D02005414E2001AA6
-:10452000000000003C0208008C4200D8304200200D
-:104530001040000A240200019103007891020083D8
-:10454000144300062402000101002021012028213B
-:10455000240600040A0010EC00000000A100008402
-:1045600011400009A50200148F4301008F4201F899
-:104570000440FFFE24020002AF4301C0A34201C475
-:104580003C021000AF4201F803E000080000000008
-:1045900027BDFFE88FA90028AFBF00100080402191
-:1045A00000E918231860007330C600FFA080007C6B
-:1045B000A08000818CA2010800E210230440004D7D
-:1045C000000000008C8200509483003C8C840064C6
-:1045D000004748233063FFFF012318210083202B6D
-:1045E00010800004000000008D0200640A00114FDA
-:1045F00000E210219502003C3042FFFF0122102111
-:1046000000E21021AD02005C9502003C8D03005CCD
-:104610003042FFFF0002104000E210210043102B47
-:1046200010400003000000000A00115E8D02005CD3
-:104630009502003C3042FFFF0002104000E21021D2
-:10464000AD02005CA1000084AD07004C8CA2010803
-:1046500000E210231840000224E2FFFCACA2010893
-:1046600030C200011040000A000000008D0200501E
-:1046700000E2102304410004010020218D020054B7
-:1046800014E20003000000000A0011802406000567
-:104690008D02005414E200478FBF00103C02080056
-:1046A0008C4200D8304200201040000A2402000151
-:1046B0009103007891020083144300062402000154
-:1046C00001002021240600048FBF00100A0010EC16
-:1046D00027BD0018A1000084A50200148F4301002B
-:1046E0008F4201F80440FFFE240200020A0011A5D7
-:1046F000000000008C82005C004910230043102B56
-:1047000054400001AC87005C9502003C3042FFFF42
-:104710000062102B14400007240200029502003CA6
-:104720008D03005C3042FFFF00621821AD03005C86
-:1047300024020002AD07004CA10200840E000FA26B
-:104740008F4401001040001B8FBF00108F430100F9
-:104750008F4201F80440FFFE24020002AF4301C073
-:10476000A34201C43C021000AF4201F80A0011BB91
-:104770008FBF001030C200101040000E8FBF00101D
-:104780008C83005C9482003C006918233042FFFF58
-:10479000006218213C023FFF3444FFFF0083102BCE
-:1047A000544000010080182101231021AD02005C5B
-:1047B0008FBF001003E0000827BD001827BDFFE8E9
-:1047C0008FAA0028AFBF00100080402100EA4823D4
-:1047D0001920002130C600FF8C83005C8C820064AD
-:1047E000006A18230043102B504000100069182164
-:1047F00094A2011001221021A4A2011094A2011080
-:104800003042FFFF0043102B1440000A3C023FFFE0
-:1048100094A2011000431023A4A201109482003C32
-:104820003042FFFF0A0011DA00621821A4A0011033
-:104830003C023FFF3444FFFF0083102B5440000133
-:104840000080182100671021AD02005CA100007CEF
-:104850000A001222A100008130C200101040003C6A
-:10486000000000008C820050004A102318400038DD
-:10487000000000009082007C24420001A082007CA5
-:104880009082007C3C0308008C630024304200FFCF
-:104890000043102B1440005C8FBF00108CA2010855
-:1048A00000E2102318400058000000008C830054E0
-:1048B0009482003C006A18233042FFFF0003184333
-:1048C000000210400043102A1040000500000000C4
-:1048D0008C820054004A10230A001209000210437F
-:1048E0009482003C3042FFFF00021040AD020064A1
-:1048F0009502003C8D0400649503003C3042FFFFAC
-:1049000000021040008220213063FFFF0083182145
-:1049100001431021AD02005C8D020054ACA20108DD
-:1049200024020002A10200840E000FA28F440100A5
-:10493000104000358FBF00108F4301008F4201F8F7
-:104940000440FFFE240200020A00124B0000000097
-:10495000AD07004C8CA2010800E2102318400002B1
-:1049600024E2FFFCACA2010830C200011040000AA2
-:10497000000000008D02005000E2102304410004FA
-:10498000010020218D02005414E200030000000009
-:104990000A001242240600058D02005414E2001A97
-:1049A0008FBF00103C0208008C4200D8304200202B
-:1049B0001040000A24020001910300789102008354
-:1049C00014430006240200010100202124060004F3
-:1049D0008FBF00100A0010EC27BD0018A100008452
-:1049E000A50200148F4301008F4201F80440FFFE2E
-:1049F00024020002AF4301C0A34201C43C021000E4
-:104A0000AF4201F88FBF001003E0000827BD001877
-:104A10008FAA00108C8200500080402130C600FF19
-:104A2000004A102300A048211840000700E0182188
-:104A300024020001A0800084A0A00112A48200141E
-:104A40000A0011BDAFAA0010A0800081AD07004C84
-:104A50008CA2010800E210231840000224E2FFFCAF
-:104A6000ACA2010830C200011040000800000000A4
-:104A70008D0200500062102304410013240600053B
-:104A80008D02005410620010000000008D020054DE
-:104A900014620011000000003C0208008C4200D8A3
-:104AA000304200201040000A2402000191030078E7
-:104AB000910200831443000624020001010020211A
-:104AC00001202821240600040A0010EC0000000048
-:104AD000A1000084A502001403E00008000000000B
-:104AE00027BDFFE0AFBF0018274201009046000A33
-:104AF0008C4800148C8B004C9082008430C900FFDD
-:104B000001681823304A00FF1C60001A2D46000679
-:104B1000240200010142100410C0001630430003BB
-:104B2000012030210100382114600007304C000CB6
-:104B300015800009304200301440000B8FBF001870
-:104B40000A0012AC000000000E0011BDAFAB001057
-:104B50000A0012AC8FBF00180E001132AFAB00106C
-:104B60000A0012AC8FBF0018AFAB00100E0012523B
-:104B7000AFAA00148FBF001803E0000827BD002073
-:104B800024020003A08200848C82005403E0000809
-:104B9000ACA201083C020008034218219062008187
-:104BA000240600433C07601924420001A0620081F2
-:104BB000906300813C0208008C4200C0306300FF1B
-:104BC000146200102403FF803C0208008C4200E0C5
-:104BD0000082102100431024AF4200243C02080050
-:104BE0008C4200E03C03000A008210213042007F2A
-:104BF0000342102100431021944500D40A000B8980
-:104C000030A5FFFF03E000080000000027BDFFE023
-:104C1000AFBF0018AFB10014AFB000108F420180D9
-:104C20000080802100A088210E0012B300402021C6
-:104C3000A20000848E0200548FBF00188FB00010B5
-:104C4000AE2201088FB1001403E0000827BD002048
-:104C500027BDFFE03C020008AFB00010AFBF001856
-:104C6000AFB10014034280218F51014092030084B0
-:104C70008E0400508E02004C14820040306600FF0B
-:104C80003C0208008C4200E02403FF800222102135
-:104C900000431024AF4200243C0208008C4200E094
-:104CA0009744007C92050081022210213042007F4F
-:104CB000034218213C02000A0062182114A0000BD4
-:104CC0003084FFFF2402000554C20014248205DC56
-:104CD0009062011224420001A062011224020C80A1
-:104CE000AF4200240A00130B24020005A060011249
-:104CF0002402000514C20009248205DC920200810E
-:104D00002C4200075040000524820A0092030081D3
-:104D10002402001400621004008210213044FFFFBE
-:104D2000A60400140E0012B3022020219602003CBB
-:104D30008E03004C022020213042FFFF0002104071
-:104D4000006218210E000302AE03005C9202007D97
-:104D500002202021344200400E00030BA202007DFD
-:104D60008F4201F80440FFFE24020002AF5101C04F
-:104D7000A34201C43C021000AF4201F88FBF0018EB
-:104D80008FB100148FB0001003E0000827BD002091
-:104D900008000D9808000DE008000E2008000E6CB9
-:044DA00008000EA059
-:0C4DA4000A0000220000000000000000D7
-:104DB0000000000D6370352E302E306A3600000082
-:104DC00005000004000000000000000000000000DA
-:104DD00000000000000000000000000000000000D3
-:104DE00000000000000000000000000000000020A3
-:104DF00000000000000000000000000000000000B3
-:104E000000000000000000000000000000000000A2
-:104E10000000000000000000000000000000000191
-:104E20000000002B00000000000000000000000057
-:104E300010000003000000000000000D0000000D45
-:104E40003C02080024425AC43C03080024636190D9
-:104E5000AC4000000043202B1480FFFD24420004DE
-:104E60003C1D080037BD7FFC03A0F0213C1008006A
-:104E7000261000883C1C0800279C5AC40E0001A67E
-:104E8000000000000000000D27BDFFE83C0960188D
-:104E9000AFBF00108D2C5000240DFF7F240800317F
-:104EA000018D5824356A380C24070C003C1A800008
-:104EB000AD2A50003C04800AAF4800083C1B800823
-:104EC000AF4700240E000935AF8400100E0008F82B
-:104ED000000000000E000845000000000E0012DC7B
-:104EE000000000003C0460168C8500003C06FFFFBB
-:104EF0003C02535300A618241062004734867C00FD
-:104F000094C201F2A780002C10400003A78000CCBF
-:104F100038581E1EA798002C94C201F810400004B7
-:104F2000978300CC38591E1EA79900CC978300CCDC
-:104F30002C7F006753E00001240300669784002C57
-:104F40002C82040114400002006028212404040083
-:104F50003C0760008CE904382403103C3128FFFF33
-:104F60001103001F30B9FFFF57200010A38000CEAF
-:104F700024020050A38200CE939F00CE53E0000F86
-:104F8000A78500CCA78000CC978500CC8FBF0010F0
-:104F9000A780002CA7800034A78000E63C01080011
-:104FA000AC25008003E0000827BD0018939F00CEC9
-:104FB00057E0FFF5A78000CCA78500CC978500CCF3
-:104FC0008FBF0010A784002CA7800034A78000E6C4
-:104FD0003C010800AC25008003E0000827BD001854
-:104FE000A38000CE8CCB003C316A00011140000E42
-:104FF0000000000030A7FFFF10E0FFDE2402005099
-:105000008CCC00C83186000114C0FFDC939F00CE19
-:105010000A000074240200518C8F00043C0E6000D2
-:105020000A00005701EE30218CEF0808240D5708C4
-:10503000000F740211CD000430B8FFFF2405006694
-:105040000A000075240404001700FFCC939F00CED3
-:105050000A000074240200508F8600103089FFFF80
-:10506000000939408CC300103C08005000E820259E
-:10507000AF4300388CC5001427420400AF82001CE7
-:10508000AF45003CAF4400300000000000000000CD
-:105090000000000000000000000000000000000010
-:1050A00000000000000000008F4B0000316A00206B
-:1050B0001140FFFD0000000003E0000800000000B8
-:1050C0008F840010948A001A8C8700243149FFFFD6
-:1050D000000940C000E83021AF46003C8C85002428
-:1050E0008F43003C00A3102318400029000000005B
-:1050F0008C8B0020256200013C0D005035AC00086F
-:10510000AF420038AF4C003000000000000000004B
-:10511000000000000000000000000000000000008F
-:1051200000000000000000008F4F000031EE002062
-:1051300011C0FFFD000000008F4A04003C08002061
-:10514000AC8A00108F490404AC890014AF480030C9
-:1051500000000000948600189487001C00C71821E6
-:10516000A48300189485001A24A20001A482001AC6
-:105170009498001A9499001E133800030000000050
-:1051800003E000080000000003E00008A480001A0B
-:105190008C8200200A0000D63C0D00500A0000C797
-:1051A000000000003C0308008C6300208F82001880
-:1051B00027BDFFE810620008AFBF00100E0000FE20
-:1051C000AF8300183C0308008C6300202404000116
-:1051D000106400048F8900108FBF001003E00008E6
-:1051E00027BD00188FBF00103C076012A520000AE1
-:1051F0009528000A34E5001027BD00183106FFFF8E
-:1052000003E00008ACA600903C0208008C4200209D
-:1052100027BDFFC8AFBF0034AFBE0030AFB7002C12
-:10522000AFB60028AFB50024AFB40020AFB3001C68
-:10523000AFB20018AFB1001410400050AFB0001072
-:105240008F840010948600069483000A00C32823EC
-:1052500030B6FFFF12C0004A8FBF00349489001897
-:10526000948A000A012A40233102FFFF02C2382B30
-:1052700014E0000202C02021004020212C8C0005F7
-:10528000158000020080A021241400040E0000AD4F
-:10529000028020218F87001002809821AF800014A7
-:1052A00094ED000A028088211280004E31B2FFFF87
-:1052B0003C1770003C1540003C1E60008F8F001CA6
-:1052C0008DEE000001D718245075005002202021D7
-:1052D00002A3802B160000353C18200050780047B0
-:1052E00002202021241000018F8300141460003953
-:1052F000029158230230F8230250C82133F1FFFFF6
-:105300001620FFEE3332FFFF8F8700103C11002084
-:10531000AF5100300000000094E6000A3C1E60120D
-:1053200037D5001002662821A4E5000A94E2000A9D
-:1053300094F2000A94F400183057FFFF1292003BD9
-:10534000AEB700908CED00148CE400100013714097
-:1053500001AE4021000E5FC3010E502B008B48218F
-:10536000012A1821ACE80014ACE3001002D3382362
-:1053700030F6FFFF16C0FFB98F8400108FBF0034D6
-:105380008FBE00308FB7002C8FB600288FB5002459
-:105390008FB400208FB3001C8FB200188FB100149F
-:1053A0008FB0001003E0000827BD0038107E001BFE
-:1053B000000000001477FFCC241000010E00162717
-:1053C000000000008F8300141060FFCB0230F82330
-:1053D000029158238F870010017020210A0001914B
-:1053E0003093FFFF8F8300141460FFCB3C1100202B
-:1053F000AF5100300A00015D000000000E00079E62
-:10540000024028210A000151004080210E00034B78
-:10541000024028210A000151004080210E0014EFB3
-:10542000022020210A000151004080210E0000C707
-:10543000000000000A00017302D3382327BDFFE8F3
-:10544000AFB00010AFBF00140E0000390000000024
-:105450003C028000345000700A0001B48E06000047
-:105460008F4F000039EE000131C2000110400024CE
-:105470008F8600A88E0700003C0C08008D8C003C35
-:105480003C0908008D29003800E66823018D282199
-:105490000000502100AD302B012A402101062021BF
-:1054A0003C010800AC25003CAF8700A83C01080087
-:1054B000AC2400380E000100000000003C0308008E
-:1054C0008C6300701060FFE6006020213C0508003E
-:1054D0008CA500683C0608008CC6006C0E0015B652
-:1054E000000000003C010800AC2000708F4F00005D
-:1054F00039EE000131C200011440FFDE8F8600A8A2
-:105500008E0A00008F8B00A83C0508008CA5003C8B
-:105510003C0408008C840038014B482300A9382142
-:105520000082182100E9402B006810213C0108008E
-:10553000AC27003C3C010800AC2200388F5F010022
-:105540002419FF0024180C0003F9202410980012DD
-:10555000AF840000AF440020936D0000240C0020B5
-:1055600031A600FF10CC0012240E005010CE000413
-:105570003C194000AF5901380A0001AD000000009D
-:105580000E001252000000003C194000AF590138D3
-:105590000A0001AD000000000E000119000000002B
-:1055A0003C194000AF5901380A0001AD000000006D
-:1055B0008F58010000802821330F00FF01E02021D7
-:1055C0000E0002F8AF8F00043C194000AF590138BB
-:1055D0000A0001AD0000000000A4102B240300010C
-:1055E00010400009000030210005284000A4102BC5
-:1055F00004A00003000318405440FFFC00052840AD
-:105600005060000A0004182B0085382B54E0000479
-:105610000003184200C330250085202300031842F0
-:105620001460FFF9000528420004182B03E000086D
-:1056300000C310213084FFFF30A5FFFF8F4201B867
-:105640000440FFFE3C074080008730253C031000EB
-:10565000AF400180AF450184AF46018803E00008F8
-:10566000AF4301B83084FFFF8F4201B80440FFFE12
-:105670003C0740388CA60000008728253C0310001A
-:10568000AF460180AF45018803E00008AF4301B891
-:105690008F8300388F8600301066000B0080402119
-:1056A0003C07080024E75C38000328C000A710214D
-:1056B0008C44000024630001108800053063000F53
-:1056C0005466FFFA000328C003E000080000102120
-:1056D0003C07080024E75C3C00A7302103E00008F9
-:1056E0008CC200003C03900034620001008220253F
-:1056F000AF4400208F45002004A0FFFE0000000002
-:1057000003E00008000000003C0380003462000158
-:105710000082202503E00008AF44002027BDFFE001
-:10572000AFB100143091FFFFAFB00010AFBF001851
-:105730001220001500A080218CA5000010A00013ED
-:10574000240400020E000C7C24060140AE00000080
-:105750008F4201B80440000D000028213C064000A3
-:10576000022620258FBF00188FB100148FB00010C3
-:105770003C03100027BD0020AF450180AF440188E5
-:1057800003E00008AF4301B88CA500008F4201B8C8
-:105790000440FFFE3C064000022620258FBF001873
-:1057A0008FB100148FB000103C03100027BD002003
-:1057B000AF450180AF44018803E00008AF4301B862
-:1057C0003086FFFF8F4201B80440FFFE3C094006CF
-:1057D0008CA8000000C93825AF4801808CA40004C3
-:1057E0003C031000AF440184AF47018803E0000888
-:1057F000AF4301B827BDFFE0AFB00010AFBF001846
-:10580000AFB100149363003E008080210080282106
-:1058100030620040000020211040000F8E11000077
-:105820000E0008710220202193670000240400501C
-:1058300030E500FF50A400128E0F0000022020214E
-:105840008FBF00188FB100148FB00010A762013C09
-:105850000A00093127BD00200E0002870000000069
-:105860000E000871022020219367000024040050DC
-:1058700030E500FF14A4FFF2022020218E0F00006B
-:105880003C1008008E1000503C0D000C240BFF80D3
-:1058900001F05021314E007F01DA6021018D40215D
-:1058A000014B4824AF490028022020218FBF001857
-:1058B0008FB100148FB00010A50200D627BD0020C4
-:1058C0000A000931AF8800D027BDFFE0AFBF001844
-:1058D000AFB10014AFB000109366000100808021CA
-:1058E0000E00025030D1000493640005001029C25C
-:1058F000A765000034830040A36300050E00025931
-:10590000020020210E0009330200202124020001A0
-:10591000AF62000C02002821A762001024040002DC
-:10592000A762001224060140A76200140E000C7C3E
-:10593000A76200161620000F8FBF0018978C003446
-:105940003C0B08008D6B00782588FFFF3109FFFFB5
-:10595000256A0001012A382B10E00006A7880034D0
-:105960003C0F6006240E001635ED0010ADAE005061
-:105970008FBF00188FB100148FB0001003E0000833
-:1059800027BD002027BDFFE0AFB10014AFBF001856
-:10599000AFB0001000A088211080000A3C03600016
-:1059A0002402008010820012000000000000000DA0
-:1059B0008FBF00188FB100148FB0001003E00008F3
-:1059C00027BD00208C682BF80500FFFE00000000BA
-:1059D000AC712BC08FBF00188FB100148FB00010B6
-:1059E0003C09100027BD002003E00008AC692BF83B
-:1059F0000E00025000A02021936500050220202106
-:105A00000E00025930B000FF2403003E1603FFE7EA
-:105A1000000000008F4401780480FFFE2407000787
-:105A20003C061000AF51014002202021A347014451
-:105A30008FBF00188FB100148FB00010AF460178EF
-:105A40000A0002C927BD002027BDFFE8AFBF001430
-:105A5000AFB000108F500020000000000E0009338E
-:105A6000AF440020AF5000208FBF00148FB0001053
-:105A700003E0000827BD00183084FFFF8F4201B803
-:105A80000440FFFE3C074035008730253C031000F2
-:105A9000AF450180AF400184AF46018803E00008B4
-:105AA000AF4301B83084FFFF8F4201B80440FFFECE
-:105AB0003C074036008730253C031000AF4501808D
-:105AC000AF400184AF46018803E00008AF4301B84E
-:105AD00027BDFFD0AFB3001C3093FFFFAFB500244C
-:105AE000AFB20018AFBF0028AFB40020AFB10014B0
-:105AF000AFB0001030B5FFFF12600027000090210A
-:105B00008F90001C8E0300003C06800024020040A1
-:105B100000033E0200032C0230E4007F006688246C
-:105B20001482001D30A500FF8F8300282C68000A16
-:105B3000510000108F910014000358803C0C0800A5
-:105B4000258C58C4016C50218D49000001200008AB
-:105B50000000000002B218213065FFFF0E00022491
-:105B600024040084162000028F90001CAF800028BF
-:105B70008F910014260C0020264B0001018080210B
-:105B80003172FFFF16200004AF8C001C0253282B3B
-:105B900014A0FFDC00000000024010218FBF00288D
-:105BA0008FB500248FB400208FB3001C8FB2001873
-:105BB0008FB100148FB0001003E0000827BD003043
-:105BC000240D003414AD00F600000000920B000E0E
-:105BD000240A16803C07000CA36B00219203000DE1
-:105BE0000347F8213C066000A363002096110012D1
-:105BF0003C057FFF34ACFFFFA771003C960200100C
-:105C0000240B00053054FFFFAF7400848E19001C74
-:105C1000AF4A00288FF800008CCF44480319702643
-:105C200001EE3021AF66004C8F69004C24CD00019D
-:105C30003C197F00AF6900508F640050AF6400547E
-:105C4000AF660070AF6D00588F6800582404005094
-:105C5000AF68005CA3600023AF6C0064A36B0037E7
-:105C60008E030014AF6300488F710048AF710024A9
-:105C70008E020018AF62006C9214000CA374003600
-:105C8000936A003E355F0020A37F003E8F7800744A
-:105C90000319782435EE4000AF6E0074936900005C
-:105CA000313000FF1204022C2418FF803C0408004D
-:105CB00024845CB80E000294000000002406000456
-:105CC000240700013C0408008C845CB8A366007DB6
-:105CD000A36700058F4A01780540FFFE24020002F9
-:105CE000AF440140A34201448F90001C3C141000BB
-:105CF000AF5401780A000373AF8000282CAD003741
-:105D000051A0FF9C8F9100140005A0803C18080052
-:105D1000271858EC029878218DEE000001C0000889
-:105D2000000000002406000614A600110000000078
-:105D30003C1F08008FFF5CB824040005AF5F002003
-:105D40008E190018AF7900188F78004CAF78001CBE
-:105D50008F6F0050122000C2AF6F00700A000373F3
-:105D6000AF840028240A000710AA00842403000638
-:105D70003C05080024A55CB80E00025E24040081E6
-:105D80008F90001C0011102B0A000373AF820028B3
-:105D90002402000414A2FFF6240A00503C09080063
-:105DA0008D295CB8AF4900208E040008AF64004024
-:105DB0008E060008AF6600448E07000CAF670048EF
-:105DC0008E0D0010AF6D004C8E080010AF6800847F
-:105DD0008E050014AF6500508E0C0018AF6C005497
-:105DE0008E0B001CAF6B005893740000328300FFD1
-:105DF000106A01EE000000008F6700488F660040C7
-:105E000000E6682305A000042404008C1620FFDEB1
-:105E100024020003240400823C05080024A55CB889
-:105E20000E000287000000008F90001C000010216F
-:105E30000A000373AF8200282404000514A4FFCCD9
-:105E4000240520003C1F08008FFF5CB8AF5F0020D6
-:105E50008E190004AF79005C921800082410000825
-:105E6000A37800218F8F001C91EE0009A36E002003
-:105E70008F86001C90C9000A312400FF109000108A
-:105E8000288A00091540006C24020002240C00201E
-:105E9000108C000B340580002885002114A0000818
-:105EA0002405400024080040108800053C0500013E
-:105EB000240D0080108D00023C05000224054000E6
-:105EC0008F6E00743C0FFF0001CF48240125802510
-:105ED000AF70007490C4000BA36400818F84001C19
-:105EE0009487000C10E0019400000000948E000CD8
-:105EF000241FFFBF24060004A76E003C9089000EFB
-:105F0000A369003E8F90001C9204000FA364003F21
-:105F10008F94001C8E8D00108F47007401A74023C2
-:105F2000AF6800608E850014AF650064968C001821
-:105F3000A76C0068968B001AA76B006A8E83001C02
-:105F4000AF63006C96820002A762013E928A000E47
-:105F5000A36A003E9379003E033FC02412200167EC
-:105F6000A378003E8F90001C0A000373AF860028C0
-:105F70002414002214B4FF7E240300073C0208000E
-:105F80008C425CB81220000CAF4200200A00037360
-:105F9000AF830028240C003310AC00142405002823
-:105FA0003C05080024A55CB80E00023024040081E2
-:105FB0000A0003F88F90001C3C04080024845CB89D
-:105FC0000E00029400000000936B000024110050AA
-:105FD000316300FF10710151000000008F90001C20
-:105FE000000018210A000373AF8300283C08080052
-:105FF0008D085CB824040081AF480020A3650034FC
-:106000003C05080024A55CB80E000230000000002A
-:106010008F90001C240200090A000373AF8200283D
-:1060200002B288213225FFFF0E00022424040084DE
-:106030000A0003738F90001C1082FFA12405040046
-:10604000288300031060016F240B00042414000156
-:106050005494FF9B240540000A00044724050100D6
-:106060003C04080024845CB88F62004C0E0002944B
-:106070008F6300508F90001C000020210A000373E2
-:10608000AF8400288E1000042404008AAF50002042
-:10609000936E000531C900021520015E020028211F
-:1060A0009378002302002821330F002015E00159C6
-:1060B0002404008D9362003F24190012305F00FF1A
-:1060C00013F90154240400810E0002500200202123
-:1060D00093740023240A0004020020213683004226
-:1060E000A36300230E000259A36A007D8F4B017841
-:1060F0000560FFFE24050002AF500140A3450144A6
-:106100008F90001C3C0C1000AF4C01780A0003F982
-:106110000011102B8E1000042404008AAF500020C0
-:10612000936D000531A80002150000160200282119
-:106130009364003F2407000402002821308600FFFA
-:1061400010C70010240400810E000250020020211C
-:10615000937F002324180012240FFFFE37F900203C
-:10616000A3790023A378003F936E0005020020214D
-:1061700001CF48240E000259A3690005020028211E
-:10618000000020210E000340000000000A0003F878
-:106190008F90001C8E0500043C0F0008034F402127
-:1061A000AF450020910E00002406005031C900FFC9
-:1061B00011260176240400888F5901B80720FFFEBC
-:1061C0003C0C400E008C58253C031000AF4501806C
-:1061D000AF400184AF4B0188AF4301B8910200008A
-:1061E000240AFF8024040004004AF825A11F0000AF
-:1061F0000E000C7C240600300A0003F88F90001C6F
-:106200008E0F00043C14080026945CB83C01080082
-:10621000AC2F5CB8AF4F0020920E000331C90004D0
-:10622000112000022402001224020006A362003F93
-:106230009203001B240AFFC03062003F004AF82589
-:10624000A37F003E92190003333800011700011CA0
-:10625000000000008E020008AE8200083C02080028
-:106260008C425CC01040011B00000000000221C2F3
-:10627000A76400088E0D000C240B000124140014E8
-:10628000AF6D002C8E080010AF6800309605001628
-:10629000A7650038960C0014A76C003AAF6B000C91
-:1062A000A76B0010A76B0012A76B0014A76B00165A
-:1062B00012200146A37400349206000330C7000286
-:1062C0002CF00001260200088F90001C0A000373C6
-:1062D000AF8200288E14000424030081AF540020F4
-:1062E000936800233105001010A001070000000092
-:1062F0008F4401B80480FFFE3C06401F0011382B7C
-:10630000006610253C111000AF540180AF870028B3
-:10631000AF400184AF420188AF5101B80A00037455
-:106320008F9100148E0600043C19000803592021A7
-:10633000AF4600208E07000890980000240F005000
-:10634000331400FF128F0102240500888F4401B826
-:106350000480FFFE3C0D40090011602B00AD1025AC
-:106360003C111000AF460180AF8C0028AF4701847C
-:10637000AF420188AF5101B80A0003748F91001435
-:106380008E04001C0E00023B00000000104000E8DC
-:10639000004048218F90001C240500898F4D01B8D2
-:1063A00005A0FFFE00000000AF4901808E0F001C19
-:1063B0003C1440010011702B00B448253C11100022
-:1063C000AF4F0184AF8E0028AF490188AF5101B8AB
-:1063D0000A0003748F910014961900023C140800FF
-:1063E00026945CB8333800041300008E3C02600031
-:1063F0008E1F001C3C010800AC3F5CB8AF5F002062
-:10640000920C0010240B0014318400FF148B00B890
-:106410000000000096090002312D000115A0014E78
-:10642000000000008E020004AE8200083C0E08004E
-:106430008DCE5CC011C00144000000008F69007463
-:106440003C0E800024040001012E6825AF6D00740D
-:10645000A3600005AF64000C3C0C08008D8C5CC090
-:106460008F88001CA7640010000C59C2A76400129A
-:10647000A7640014A7640016A76B00088D0300082A
-:1064800024040002AF63002C8D0A000CAF6A0030B8
-:1064900091070010A36700348F82001C9045001103
-:1064A000A36500358F86001C90D00012A3700036C3
-:1064B0008F9F001C93F90013A37900378F90001C65
-:1064C00096180014A778003896140016A774003A9E
-:1064D0008E0F0018AF6F00245620FDA5AF84002852
-:1064E0003C05080024A55CB80E00025E00002021D7
-:1064F0008F90001C0A0004B6000020213C05080013
-:1065000024A55CB80E000287240400828F90001C32
-:10651000000030210A000373AF8600283C04080005
-:106520008C845CB80E001574000000008F90001C75
-:106530000A000490000018213C05080024A55CB85E
-:106540000E0002872404008B8F90001C0011302B5A
-:106550000A000373AF8600283C1908008F395CB825
-:106560003C1F08008FFF005024CCFFFE033F782122
-:1065700001F87024AF4E00283C0408008C845CB8FD
-:106580003C0908008D2900500089682131A8007F4E
-:10659000011A282100A78021AE0600D8AF9000D0B4
-:1065A000AE0000DC0A0003C2AE0C0108AF6000843C
-:1065B0003C0508008CA55CB83C0808008D0800501C
-:1065C000240CFF803C02000C00A8A021028C58245F
-:1065D000AF4B00288E1F00143283007F007A5021B9
-:1065E00001427021ADDF00D88E190014AF8E00D0AB
-:1065F000ADD900DC8E180010270FFFFE0A0004152D
-:10660000ADCF0108548BFE2E240540000A0004473C
-:10661000240510000E000335000000000A0003F8F6
-:106620008F90001C8C46442C3C056C6234B0797011
-:106630003C010800AC205CB814D00008240400021F
-:1066400097880034978A002C02802821010A382B71
-:1066500010E0001124040092240400020E000C9AA1
-:10666000240501403C010800AC225CB8AF42002088
-:106670003C0308008C635CB81060000524040083B0
-:106680000E0008650000000010400009240400838B
-:106690003C05080024A55CB80E00025E0000000066
-:1066A0008F90001C0011202B0A000373AF84002878
-:1066B0000E000869000000000A0005978F90001C7A
-:1066C0008E0400080E00023B000000000A00052EA8
-:1066D000AE8200083C05080024A55CB80E0002301C
-:1066E000240400878F90001C0A00054A0011102B1B
-:1066F0000E00086D000000003C05080024A55CB8F1
-:106700000A00063D2404008B0E0002500280202166
-:106710009370002302802021360D00100E000259D4
-:10672000A36D00238F90001C0A0005530000182160
-:10673000240400040E000C9A240500301440002AA2
-:10674000004048218F90001C0A00057E240500832C
-:106750009205000C30BF000113E0000300000000B0
-:106760009602000EA482002C920A000C314800020E
-:106770001100FEF600002821960B00128E03001473
-:10678000A48B001A0A00056AAC83001C8F830038B2
-:106790008F8700301067FE88000020213C09080028
-:1067A00025295C3C000320C0008930218CD40000E6
-:1067B0001285005E247800013303000F5467FFFA4E
-:1067C000000320C00A000505000020213C05080048
-:1067D00024A55CB80E000287240400828F90001C60
-:1067E0000A00054A000010213C0B0008034B202141
-:1067F00024030050240A0001AF420020A0830000BF
-:10680000A08A00018F88001C91070004A08700184F
-:106810008F82001C90450005A08500198F86001C02
-:1068200090DF0006A09F001A8F99001C9338000784
-:10683000A098001B8F94001C928F0008A08F001C52
-:106840008F90001C920E0009A08E001D8F8D001CE1
-:1068500091AC000AA08C001E8F8B001C3C0C080021
-:10686000258C5C3C9163000B3C0B0800256B5C386D
-:10687000A083001F8F8A001C9148000CA088002074
-:106880008F87001C90E5000DA08500218F82001CE1
-:10689000240546469046000EA08600228F9F001CCD
-:1068A00093F9000FA09900238F98001C93140010F7
-:1068B000A09400248F8F001C91F00011A09000255F
-:1068C0008F90001C8F8E00308F990038960D001429
-:1068D000000E18C025C80001A48D0028960A0016D5
-:1068E000006C3021006BF821A48A002A960700185A
-:1068F0003108000FA487002CA485002E8E02001CF6
-:10690000ACC90000AF88003011190003AFE20000ED
-:106910000A00057E00002821250C00013184000FAB
-:10692000000028210A00057EAF8400383C070800DB
-:1069300024E75C380087802100002021ACC00000E3
-:106940000A000505AE0000003C05080024A55CB85F
-:106950000A00063D240400878E0400040E00023B5A
-:10696000000000000A0005A2AE8200083084FFFF8C
-:1069700030C600FF8F4201B80440FFFE000644000D
-:10698000010430253C07200000C720253C031000EF
-:10699000AF400180AF450184AF44018803E00008A7
-:1069A000AF4301B827BDFFE8AFB00010AFBF001480
-:1069B0003C076000240600021080000600A0802131
-:1069C0000010102B8FBF00148FB0001003E00008E0
-:1069D00027BD00183C09600EAD2000348CE5201C5A
-:1069E0008F82001C2408FFFC00A81824ACE3201CA4
-:1069F0000E0006F28C45000C0010102B8FBF001407
-:106A00008FB0001003E0000827BD00183C02600EA4
-:106A10003447010024090018274A04000000000040
-:106A200000000000000000003C06005034C30200DB
-:106A3000AF440038AF45003CAF430030014018215F
-:106A40008F4B0000316800201100FFFD2406007FFD
-:106A50002408FFFF8C6C000024C6FFFF24630004A1
-:106A6000ACEC000014C8FFFB24E7000400000000A9
-:106A700000000000000000003C0F0020AF4F00307D
-:106A80000000000024AD020001A5702B2529FFFFA6
-:106A9000008E20211520FFE101A0282103E000083D
-:106AA0000000000027BDFFE0AFB10014AFBF001829
-:106AB000AFB000103C05600E8CA20034008088212D
-:106AC000144000063C0460008C87201C2408FFFC56
-:106AD00000E8302434C30001AC83201C8F8B001CE1
-:106AE00024090001ACA90034956900028D650014E9
-:106AF0008D70000C2D2400818D6700048D660008C8
-:106B0000108000078D6A00102D2C00041580000EE7
-:106B100030CE0007312D000311A0000B0000000053
-:106B20002404008B020028210E0006F22406000334
-:106B30000011102B8FBF00188FB100148FB0001000
-:106B400003E0000827BD002015C0FFF62404008BD9
-:106B50003C030020AF43003000000000240200018D
-:106B6000AF820014000000000000000000000000E0
-:106B70003C1F0150013FC825253800033C0F600E23
-:106B8000AF47003800181882AF46003C35E8003C9B
-:106B9000AF590030274704008F44000030860020A2
-:106BA00010C0FFFD00000000106000082466FFFF19
-:106BB0002403FFFF8CEB000024C6FFFF24E7000442
-:106BC000AD0B000014C3FFFB250800043C08600E59
-:106BD000AD090038000000000000000000000000C7
-:106BE0003C070020AF470030000000000E00071AED
-:106BF0000140202102002821000020210E0006F281
-:106C0000240600030011102B8FBF00188FB1001451
-:106C10008FB0001003E0000827BD002027BDFFD87B
-:106C2000AFB200183092FFFFAFB10014AFBF002029
-:106C3000AFB3001CAFB000101240002C0000882140
-:106C40000A0007B22413000150B300408CE5000C89
-:106C50000000000D263900013331FFFF24F8002029
-:106C60000232382B10E00021AF98001C8F820014F4
-:106C70001440001E8F87001C3C0670003C0320005F
-:106C80008CE400000086282414A300188F85003CA3
-:106C9000000444023C0980000089802414A0FFEA1B
-:106CA000310600FF240A000210CA002E28CB000380
-:106CB00011600016240C000314D3FFE726390001ED
-:106CC000020028210E000700240400018F87001C09
-:106CD000AF82003C263900013331FFFF24F8002049
-:106CE0000232382B14E0FFE1AF98001C0220102183
-:106CF0008FBF00208FB3001C8FB200188FB100141B
-:106D00008FB0001003E0000827BD002810CC001A47
-:106D1000240D000414CDFFD026390001308EFFFF72
-:106D2000000E19C08F4401B80480FFFE3C0F100014
-:106D30003C102004AF430180AF400184AF50018874
-:106D4000AF4F01B80A0007AD263900010E0006F268
-:106D5000240400841600FFBF8F87001C0A0007ACC4
-:106D6000AF80003C020028210E0007000000202117
-:106D70000A0007CB8F87001C0E000740020020216D
-:106D80008F87001C0A0007CCAF82003C3082FFFFD7
-:106D90001440000300001821000424022403001002
-:106DA000308500FF14A000053087000F246600081E
-:106DB0000004220230C300FF3087000F14E00005FA
-:106DC000308900032468000400042102310300FF1D
-:106DD0003089000315200005388B0001246A000269
-:106DE00000042082314300FF388B00013164000130
-:106DF00010800002246C0001318300FF03E00008D2
-:106E000000601021308BFFFF000B394230E600FF9D
-:106E10003C09080025295BB8000640800109602173
-:106E20008D8700003164001F240A0001008A1804C5
-:106E300030A500FF00E3202514A000020003102766
-:106E400000E22024240F000100CF70040109682112
-:106E5000000E282714800005ADA400008F86000CCA
-:106E600000A6102403E00008AF82000C8F88000CFD
-:106E700001C8102503E00008AF82000C3C06001F8B
-:106E80003C0360003084FFFF34C5FF8024020020F3
-:106E9000AC602008AC60200CAC602010AC65201405
-:106EA000AC642018AC62200000000000000000006C
-:106EB00003E000080000000027BDFFE82402FFFFF8
-:106EC000AFBF0010AF82000C000020213C0608007C
-:106ED00024C65BB82405FFFF24890001000440801C
-:106EE0003124FFFF010618212C87002014E0FFFA4F
-:106EF000AC6500000E0008360000202124020001CD
-:106F00003C04600024050020AC822018AC852000E1
-:106F1000000000000000000000000000244A000102
-:106F20003142FFFF2C46040014C0FFF78FBF001052
-:106F300003E0000827BD00188F8300082C620400BE
-:106F400003E00008384200018F830008246200013A
-:106F500003E00008AF8200088F8300082462FFFF6F
-:106F600003E00008AF82000827BDFFE0AFB10014C6
-:106F7000AFBF0018AFB000108F6B00303C06600050
-:106F800000808821ACCB20088F6A002C3C02800056
-:106F900024030008ACCA200C9769003A97680038AF
-:106FA00000092C003107FFFF00A72025ACC42010EA
-:106FB000ACC22014ACC320000000000000000000A0
-:106FC000000000003C0360008C6D200031AC000824
-:106FD0001580FFF9000000008C6E201405C0002011
-:106FE000000000000E0007FA8F84000C00024080B1
-:106FF0003C09080025295BB8010938218CE4000010
-:107000000E0007FA00028140020220213090FFFFAB
-:10701000020020210E000818000028213C0C8000EE
-:10702000022C58253210FFFF3C116000240A00207A
-:10703000AE2B2014AE302018AE2A20000000000035
-:107040000000000000000000020010218FBF0018A7
-:107050008FB100148FB0001003E0000827BD00209E
-:107060008C6620143C02001F3443FF803C1FFFE865
-:1070700000C3C02437F9080003198021001079C229
-:107080003C0C8000022C582531F0FFFF3C116000C1
-:10709000240A0020AE2B2014AE302018AE2A200087
-:1070A00000000000000000000000000002001021AD
-:1070B0008FBF00188FB100148FB0001003E00008DC
-:1070C00027BD002027BDFFE8AFB000103402FFFF4E
-:1070D0003090FFFFAFBF0014120200060200202113
-:1070E0000E00083600000000020020210E000818E3
-:1070F000240500018F8400088FBF00148FB000109A
-:107100002483FFFF27BD001803E00008AF830008B9
-:10711000000439C230E6003F00043B42000718403B
-:10712000240210002CC4002024C8FFE0AF42002C31
-:10713000246300011480000330A900FF00071840F9
-:10714000310600FF0003608024080001019A5821E5
-:107150003C0A000E00C82804016A382111200005ED
-:10716000000530278CE900000125302503E00008E8
-:10717000ACE600008CEE000001C6682403E00008C5
-:10718000ACED000027BDFFE8AFBF0014AFB00010AA
-:107190003C0460008C8508083403F00030A2F00045
-:1071A00050430006240200018C8708083404E000E4
-:1071B00030E6F00010C4001E24020002AF8200403E
-:1071C0003C1060003C0A0200AE0A081424091000BA
-:1071D0003C08000E8E03440003482021AF49002CD8
-:1071E000240501200E000CE0000030218F830040B8
-:1071F000106000043C021691240B0001106B000E7D
-:107200003C023D6C344F0090AE0F44088FBF001419
-:107210008FB000103C0C6000240E10003C0D0200EA
-:1072200027BD0018AD8E442003E00008AD8D081086
-:107230000A000907AF8000403C0218DA344F009082
-:10724000AE0F44088FBF00148FB000103C0C6000DC
-:10725000240E10003C0D020027BD0018AD8E442006
-:1072600003E00008AD8D08100A0008DB24050001CA
-:107270000A0008DB000028213C08080025085FC43C
-:107280002404FFFF010018212402001E2442FFFFF6
-:10729000AC6400000441FFFD246300043C070800C7
-:1072A00024E760408CE5FFFC2404001C2406000158
-:1072B000308A001F01464804248400010009102779
-:1072C0002C8300201460FFFA00A22824ACE5FFFC08
-:1072D0003C05666634A4616E3C06080024C6610065
-:1072E000AF840058AF88009C2404FFFF00C0182121
-:1072F0002402001F2442FFFFAC6400000441FFFD94
-:10730000246300043C0766663C05080024A560C0B1
-:10731000AF86004834E6616EAF8600982404FFFF14
-:1073200000A018212402000F2442FFFFAC640000DB
-:107330000441FFFD246300043C0B66663C06080024
-:1073400024C660403568616EAF8500A4AF880070C8
-:107350002404FFFF00C018212402001F2442FFFF65
-:10736000AC6400000441FFFD246300043C0D66662C
-:107370003C0A0800254A618035AC616EAF860090FA
-:10738000AF8C005C2404FFFF01401821240200039D
-:107390002442FFFFAC6400000441FFFD24630004AD
-:1073A0003C090800252961908D27FFFC2404000674
-:1073B000240500013099001F0325C0042484000126
-:1073C000001878272C8E002015C0FFFA00EF382413
-:1073D000AD27FFFC3C09666624030400240403DC9B
-:1073E00024050200240600663522616E3C08080070
-:1073F00025085CC4AF820074AF830044AF83006C87
-:10740000AF830050AF830084AF8A008CAF840064E8
-:10741000AF85004CAF860054AF840078AF85006024
-:10742000AF86008001001821240200022442FFFFE1
-:10743000AC6000000441FFFD246300042404000349
-:107440002403000C3C0A0800254A5CD0AF8A00687F
-:107450000A0009AE2405FFFF0004188024840001FF
-:10746000006858212C8700C014E0FFFBAD650000C8
-:107470003C0E666635CD616E240C17A024081800FA
-:10748000AF8D0088AF8C009403E00008AF88007CCB
-:107490002484007F000421C200004021000030212C
-:1074A00000003821000028210A0009C5AF8400A08F
-:1074B0001060000624E7000100C4302124A500016B
-:1074C0002CC20BF51440FFFA2CA300663C090800FF
-:1074D0002529618001201821240200032442FFFF96
-:1074E000AC6000000441FFFD2463000410E0001ABA
-:1074F00024E3FFFF0003294210A0000A000020211E
-:107500002406FFFF3C0308002463618024840001FB
-:107510000085502BAC660000250800011540FFFBDC
-:107520002463000430E2001F104000080008688057
-:10753000240C0001004C38040008588001692821FF
-:1075400024E6FFFF03E00008ACA6000001A94021EB
-:107550002409FFFFAD09000003E00008000000005F
-:10756000AF4400283C04000C03442021000528827D
-:107570000A000CE000003021000421803C03600080
-:10758000AC6410080000000000052980AC65100CF8
-:107590000000000003E000088C62100C27BDFFE82B
-:1075A0000080282124040038AFBF00140E0009F524
-:1075B000AFB0001024040E00AF4400283C10000CB3
-:1075C00003502021240500100E000CE000003021A3
-:1075D00003501021AC400000AC40000424040038EB
-:1075E0008FBF00148FB0001024053FFF27BD001887
-:1075F0000A0009F58C430000000421803C03600070
-:10760000AC641008000000008C62100C03E000085D
-:107610000002118227BDFFC8AFB400208F9400681C
-:10762000AFBE0030AFB7002CAFB600280000B821C5
-:107630000080B021241E00C0AFBF0034AFB50024CD
-:10764000AFB3001CAFB20018AFB10014AFB0001060
-:107650000A000A32AFA5003C504000018F94006838
-:1076600027DEFFFF13C00028269400048E9200003E
-:107670003C03080024635FC01240FFF70283102B15
-:107680003C04080024845CC4028410230002A8C0C7
-:10769000000098210A000A412411000100118840CD
-:1076A000122000260000000002B38021025128248D
-:1076B0000200202110A0FFF9267300010E0009FE30
-:1076C000000000000016684032EC000101AC2021EF
-:1076D0000E0009F5020028218F89009426F7000189
-:1076E0008FA6003C3AEB0001316A00012528FFFF1C
-:1076F0000011382702CAB021AF88009416E6FFE7D0
-:1077000002479024AE92000002E010218FBF0034A7
-:107710008FBE00308FB7002C8FB600288FB50024A5
-:107720008FB400208FB3001C8FB200188FB10014EB
-:107730008FB0001003E0000827BD00383C0E0800A1
-:1077400025CE5FC0028E102B0A000A2DAE920000DB
-:1077500027BDFFD8AFB10014AFB00010AFBF0020FD
-:10776000AFB3001CAFB2001800A0882110A0001F0A
-:10777000000480403C13080026735CC40A000A7AA7
-:107780002412000112200019261000010E000A1513
-:1077900002002021000231422444FFA0000618808C
-:1077A0003045001F2C8217A1007318212631FFFFDE
-:1077B0001040FFF400B230048C6900000200202168
-:1077C00024053FFF012640241500FFEE0126382541
-:1077D0000E0009F5AC6700008F8A009426100001A6
-:1077E000254700011620FFE9AF8700948FBF0020D6
-:1077F0008FB3001C8FB200188FB100148FB000102F
-:1078000003E0000827BD00288F85009C00805821D8
-:107810000000402100004821240A001F3C0C080001
-:10782000258C603C3C0D080025AD5FC48CA6000093
-:1078300050C000140000402100AD1023000238C0E9
-:10784000240300010A000AB30000202115000003F0
-:1078500000E41021244820240000482125290001AB
-:10786000512B00132506DFDC106000062484000184
-:1078700000C3702415C0FFF5000318400A000AB1C8
-:107880000000402110AC002624A300040060282141
-:10789000254AFFFF1540FFE5AF85009C512B0004F2
-:1078A0002506DFDC0000402103E000080100102174
-:1078B0000006614230C5001F000C50803C070800E4
-:1078C00024E75FC424040001014730211120000F88
-:1078D00000A420043C05080024A560401480000595
-:1078E0002529FFFF24C6000410C500110000000078
-:1078F000240400018CCF00000004C02700042040B5
-:1079000001F868241520FFF5ACCD00008F990078B0
-:1079100001001021032B482303E00008AF89007801
-:107920003C05080024A55FC40A000ABB00004021F2
-:107930003C06080024C65FC40A000AD424040001DF
-:10794000308800FF240200021102000A2403000311
-:107950001103005C8F8900A4240400041104005F5B
-:1079600024050005110500670000182103E0000848
-:10797000006010218F8900483C0C0800258C6100B4
-:107980003C04080024846180240300201060000F60
-:1079900000005821240D0002240E00033C0F0800B3
-:1079A00025EF61008D27000014E0000B30F9FFFF88
-:1079B000252900040124C02B530000010180482127
-:1079C0002463FFFF5460FFF88D2700000160182139
-:1079D00003E0000800601021132000323C0500FF86
-:1079E00030E200FF004030211040004200005021F2
-:1079F00024050001000020210005C84000A6C02485
-:107A000017000003332500FF14A0FFFB24840001AE
-:107A1000012CC023001828C000AA6021008C50212E
-:107A20003144001F240C0001008C180400031027AF
-:107A300000E23024110D0041AD260000110E004C73
-:107A4000000A1840110D00368F87006C510E005649
-:107A50008F8C0060240D0004110D005A8F8E00845D
-:107A6000240E0005150EFFDA01601821240B1430D6
-:107A700011400006000018218F8400A0246300013B
-:107A8000006A402B1500FFFD016458218F8A008099
-:107A9000AF89008C016018212549FFFF0A000B0BFC
-:107AA000AF89008000E52024000736021080FFD057
-:107AB000240A001800075402314600FF0A000B1385
-:107AC000240A00103C0C0800258C60C03C0408000F
-:107AD000248461000A000AFA240300103C0C080008
-:107AE000258C60403C040800248460C00A000AF928
-:107AF0008F89009000071A02306600FF0A000B13FE
-:107B0000240A00088F89008C3C0C0800258C6180B9
-:107B10003C040800248461900A000AFA240300044B
-:107B2000000A4080250B003024E6FFFF0160182189
-:107B3000AF8900480A000B0BAF86006C000AC982AF
-:107B4000001978803C07080024E760C001E7202185
-:107B5000000A18428C8F00003079001F032C380473
-:107B60000007C02701F860240A000B28AC8C000035
-:107B7000000331420006288000AF28213062001F38
-:107B80008CB8000024630001004CC80400032142AB
-:107B9000001938270004108003073024004F2021EB
-:107BA0000A000B6CACA60000000A68C025AB0032CE
-:107BB000258AFFFF01601821AF8900A40A000B0B82
-:107BC000AF8A0060254B1030AF890090016018210A
-:107BD00025C9FFFF0A000B0BAF8900843086000720
-:107BE0002CC2000610400014000000000006408077
-:107BF0003C030800246359C8010338218CE40000C9
-:107C000000800008000000002409000310A9000EF5
-:107C100000000000240A000510AA000B000000006C
-:107C2000240B000110AB0008000000008F8C00A0A6
-:107C300010AC00050000000003E000080000102167
-:107C40000A000A9900A020210A000AE700C02021AA
-:107C500027BDFFE8308400FF240300021083000BDF
-:107C6000AFBF0010240600031086003A2408000469
-:107C700010880068240E0005108E007F2CAF143091
-:107C80008FBF001003E0000827BD00182CA20030B1
-:107C90001440FFFC8FBF001024A5FFD0000531C2A7
-:107CA000000668803C07080024E7610001A7302136
-:107CB0008CC900000005288230AC001F240B000195
-:107CC000018B50048F840048012A4025ACC8000075
-:107CD0008C83000050600001AF8600488F98006CD4
-:107CE00030AE000124A6FFFF270F000115C00002DF
-:107CF000AF8F006C24A600010006414200082080DE
-:107D0000008718218C79000030C2001F2406000172
-:107D10000046F804033F382410E0FFDA8FBF00105C
-:107D20000005C182001870803C0F080025EF60C07C
-:107D300001CF48218D2B00000005684231A5001FAE
-:107D400000A66004016C502527BD001803E0000860
-:107D5000AD2A00002CA7003014E0FFCA8FBF00102E
-:107D600030B900071723FFC724A8FFCE00086A0216
-:107D7000000D60803C0B0800256B60C0018B30213A
-:107D80008CC40000000828C230AA001F240800018B
-:107D9000014848048F8200A400891825ACC3000064
-:107DA0008C5F000053E00001AF8600A40005704026
-:107DB000000E7942000F28803C04080024846100F2
-:107DC00000A418218C6B000025DF000131CD001FBD
-:107DD000001F514201A86004016C4825000A108070
-:107DE000AC690000004428218CA600008F98006038
-:107DF00033F9001F8FBF00100328380400C778250F
-:107E0000270E000127BD0018ACAF000003E00008FA
-:107E1000AF8E006024A5EFD02CB804001300FF99AA
-:107E20008FBF001000053142000658803C0A080050
-:107E3000254A6040016A30218CC4000030A3001F35
-:107E400024090001006910048F9900900082F82530
-:107E5000ACDF00008F27000050E00001AF860090EB
-:107E60008F8D00848FBF001027BD001825AC000146
-:107E700003E00008AF8C008415E0FF828FBF001084
-:107E80008F8600A0000610400046F821001F210048
-:107E900003E4C8210019384024F8143000B8402BFE
-:107EA0001100FF788FBF001024A4EBD00E00020D4C
-:107EB00000C0282100027942000F70803C0D0800AC
-:107EC00025AD618001CD20218C8B0000304C001F3E
-:107ED00024060001018618048F89008C0163502557
-:107EE000AC8A00008D25000050A00001AF84008CFA
-:107EF0008F9800808FBF001027BD00182708000151
-:107F000003E00008AF88008030A5000724030003C9
-:107F100010A3001028A20004144000082407000247
-:107F20002403000410A300152408000510A8000F66
-:107F30008F8500A003E000080000000014A7FFFDEB
-:107F40000080282114C3FFFB240400020A000BABAD
-:107F500000000000240900050080282110C9FFFB53
-:107F60002404000303E000080000000014C5FFF132
-:107F7000008028210A000BAB24040005240A00011C
-:107F80000080282110CAFFF12404000403E0000847
-:107F90000000000027BDFFE0AFB00010000581C267
-:107FA0002603FFD024C5003F2C6223D024C6007FC7
-:107FB000AFB20018AFB10014AFBF001C309100FF8A
-:107FC000000691C20005298202002021104000080D
-:107FD0002403FFFF0E000A6B0000000002002021B6
-:107FE000022028210E000C590240302100001821E7
-:107FF0008FBF001C8FB200188FB100148FB000101B
-:108000000060102103E0000827BD002027BDFFD835
-:1080100024A2007FAFB3001CAFB20018000299C2C7
-:10802000309200FF24A3003F02402021026028215B
-:10803000AFB10014AFB00010AFBF00200E000B8E28
-:108040000003898200408021004020210220282155
-:1080500014400009000018218FBF00208FB3001CBE
-:108060008FB200188FB100148FB000100060102183
-:1080700003E0000827BD00280E000A1C00000000D5
-:1080800000402821020020211051FFF3001019C0E8
-:108090000E000A6B0000000002002021024028218F
-:1080A0000E000C59026030218FBF00208FB3001CDE
-:1080B0008FB200188FB100148FB00010000018218B
-:1080C0000060102103E0000827BD00283084FFFF76
-:1080D00030A5FFFF1080000700001821308200014A
-:1080E0001040000200042042006518211480FFFBAC
-:1080F0000005284003E000080060102110C00007C0
-:10810000000000008CA2000024C6FFFF24A500048C
-:10811000AC82000014C0FFFB2484000403E00008CC
-:108120000000000010A0000824A3FFFFAC860000A0
-:1081300000000000000000002402FFFF2463FFFF96
-:108140001462FFFA2484000403E000080000000029
-:1081500030A5FFFF8F4201B80440FFFE3C076015C9
-:1081600000A730253C031000AF440180AF400184DC
-:10817000AF46018803E00008AF4301B88F8500D007
-:108180002C864000008018218CA700840087102BCB
-:1081900014400010000000008CA800842D06400050
-:1081A00050C0000F240340008CAA0084008A482B92
-:1081B000512000018CA3008400035A42000B208050
-:1081C0003C05080024A55A400085182103E000085A
-:1081D0008C62000014C0FFF4000000002403400083
-:1081E00000035A42000B20803C05080024A55A4099
-:1081F0000085182103E000088C6200008F8300D006
-:10820000906600D024C50001A06500D08F8500D005
-:10821000906400D090A200D210440017000000002B
-:10822000936C00788F8B00BC318A00FFA16A000C30
-:1082300025490001938700C4312200FF3048007FA8
-:108240001107000B00026827A36200788F4E0178A7
-:1082500005C0FFFE8F9900B0241800023C0F1000EB
-:10826000AF590140A358014403E00008AF4F017823
-:108270000A000D2931A20080A0A000D00A000D1F25
-:108280000000000027BDFFD8AFB200188F9200B8E1
-:10829000AFBF0020AFB3001CAFB00010AFB10014EF
-:1082A0008F9300B48E5900283C1000803C0EFFEFE5
-:1082B000AE7900008E580024A260000A35CDFFFF81
-:1082C000AE7800049251002C3C0BFF9F356AFFFFF3
-:1082D000A271000C8E6F000C3C080040A271000BD4
-:1082E00001F06025018D4824012A382400E830255A
-:1082F000AE66000C8E450004AE6000183C0400FF22
-:10830000AE6500148E43002C3482FFFFA660000887
-:108310000062F824AE7F00108E5900088F9000B0E4
-:10832000964E0012AE7900208E51000C31D83FFFDE
-:1083300000187980AE7100248E4D001401F0602188
-:1083400031CB0001AE6D00288E4A0018000C41C2EE
-:10835000000B4B80AE6A002C8E46001C01093821B0
-:10836000A667001CAE660030964500028E440020D1
-:10837000A665001EAE6400349243003330620004F0
-:1083800054400005924600008F8300D08C7F007C13
-:10839000AE7F0030924600008F8500BCA0A6000092
-:1083A000924400333082000250400007924E000198
-:1083B0008F8700BC240AFF8090E90000012A402535
-:1083C000A0E80000924E00018F8D00BC2409FFBF81
-:1083D0002404FFDFA1AE00018F8A00BC914C000D88
-:1083E000318B007FA14B000D8F8600BC90C8000D23
-:1083F00001093824A0C7000D8F9100BC8E650014C0
-:108400009223000D2CA200010002F9400064C82450
-:10841000033FC025A238000D8F8800BC9650001283
-:108420008F8700D0A51000028E45000490ED00BC9F
-:1084300030AF0003000F702331CC000300AC1021DB
-:1084400031AB0002156000022444003424440030A3
-:1084500090F100BC00B18024320F000415E000024E
-:1084600024830004008018218F8900AC240A0002B4
-:10847000AD030004A12A00009248003F8F8700ACA2
-:10848000A0E800018F9100AC9246003F8E440004AA
-:10849000A62600029765003C0E000CF630B0FFFFE8
-:1084A00000021380005020253C0342000083F82581
-:1084B000AE3F00048F8500AC8E590038ACB900186F
-:1084C0008E580034ACB8001CACA0000CACA000105E
-:1084D000A4A00014A4A00016A4A00020A4A0002220
-:1084E000ACA000248E620014504000012402000160
-:1084F0008FBF00208FB3001C8FB200188FB1001403
-:108500008FB00010ACA200080A000D1627BD00288D
-:108510008F8600D027BDFFD0AFBF002CAFB600289C
-:10852000AFB50024AFB40020AFB3001CAFB2001849
-:10853000AFB10014AFB0001094C300E094C200E2E9
-:10854000104300412405FFFF3C16000E90C400D0EC
-:1085500090C800D1309200FF310400FF0244382B54
-:1085600010E0004426490001108900378F9800B0C0
-:108570003C0508008CA5005C2414FF8000B8602135
-:1085800001946824AF4D002C94CA00E2318B007F27
-:10859000017A482131447FFF013640210004104018
-:1085A0000048A82196A700003C1F08008FFF005834
-:1085B00030F53FFF0015198003E3C8210319882116
-:1085C0003233007F027A782102348024AF50002CAD
-:1085D00001F69821926E000D31C5000410A00048EC
-:1085E0000000000094C300E294C300E294D800E2CB
-:1085F00024048000307F7FFF27F9000133317FFFA3
-:108600000304802402117825A4CF00E294CE00E276
-:108610003C1208008E52006031D47FFF129200DFBE
-:10862000000000008E720018000028212646FFFF7F
-:10863000AE66002C8F8600D094C800E094C900E29A
-:108640001528FFC2000000008FBF002C8FB6002845
-:108650008FB500248FB400208FB3001C8FB2001898
-:108660008FB100148FB0001000A0102103E00008AB
-:1086700027BD003090CD00D2264A000131AC00FF6A
-:10868000008C5821116AFFF08F9800B03C0508005B
-:108690008CA5005C2414FF8000B86021019468243C
-:1086A000AF4D002C94CA00E2318B007F017A482143
-:1086B00031447FFF01364021000410400048A821CA
-:1086C00096A700003C1F08008FFF005830F53FFFC1
-:1086D0000015198003E3C821031988213233007F74
-:1086E000027A782102348024AF50002C01F69821C0
-:1086F000926E000D31C5000414A0FFBA0000000006
-:108700008E6600100012C0C08E6E003000129140C4
-:1087100002587821036F582100CE6823256C008809
-:1087200024020002AE6D0010AF8C00ACA162008884
-:10873000976A003C8E6400308F9100AC0E000CF6FE
-:108740003150FFFF00022380009048253C03420087
-:1087500001234025AE2800048E6700048F8C00ACF6
-:108760008E7F0000240D0008AD87001CAD9F00180F
-:10877000AD80000CAD8000109265000A30B900FF9A
-:10878000A5990014967800083C05000CA5980016E1
-:108790009271000A322F00FFA58F0020967000080A
-:1087A00024110005A5900022AD800024926E000BDC
-:1087B0002410C00031C600FFA5860002A18D000173
-:1087C0008E6B00308F8200AC8F8800B0AC4B0008FD
-:1087D0003C0A08008D4A0054014820210094482496
-:1087E000AF4900283C0308008C630054006838211E
-:1087F00030FF007F03FAC8210325C02102587821E9
-:10880000AF8F00BCAF9800C0A1F100008F8B00BCFF
-:108810002403FFBF2405FFDF956E000201D0A024D2
-:1088200002959025A57200029166000230CD003FAE
-:1088300035AC0040A16C00028F8800BC8F8200D054
-:108840003C0C7FFFAD0000048C4A007C358BFFFFA1
-:108850003C028000AD0A00089104000D3089007FC1
-:10886000A109000D8F9F00BC93F5000D02A33824D1
-:10887000A3E7000D8F9100BC9239000D0325C024A1
-:10888000A238000D8E6F00348F8D00BCADAF00108C
-:108890008E6E002C8E70003001D0A023ADB4001479
-:1088A00091B200183246007FA1A600188F8700BC45
-:1088B0008E6A00308CE40018014B4824008240246A
-:1088C0000109A825ACF500189263000AA0E3001C7A
-:1088D000967F00088F8500BC8F9900D0A4BF001E32
-:1088E0008E7000308E6400300E00020D8F250084E3
-:1088F0008F8500D0000289400002C10090AE00BC0C
-:10890000023878210040302131D400021280000367
-:10891000020F80210002A8800215802190B200BCC5
-:1089200032540004128000020006C880021980211F
-:108930008E6F00308F8B00BC2406800031EE000368
-:10894000000E682331AC0003020C1021AD6200045C
-:1089500094A400E294AA00E294A300E231507FFFC5
-:108960002604000130897FFF006640240109882524
-:10897000A4B100E294A700E23C1308008E730060EB
-:1089800030FF7FFF13F30012000000000E000D16F1
-:10899000000000000A000E240000282194CD00E20F
-:1089A00001A46024A4CC00E290CB00E290C200E2DB
-:1089B000316A00FF000A49C200092027000441C0B3
-:1089C0003055007F02A838250A000E20A0C700E21B
-:1089D00094B100E202263824A4A700E290BF00E28E
-:1089E00090B400E233F300FF0013C9C200199027CE
-:1089F0003298007F0012A9C0031530250E000D1615
-:108A0000A0A600E20A000E24000028213084FFFF07
-:108A100030A5FFFFAF440018AF45001C03E000087D
-:108A20008F42001427BDFFB0AFB000288F9000D058
-:108A3000AFB40038AFBF004CAFBE0048AFB7004482
-:108A4000AFB60040AFB5003CAFB30034AFB20030BA
-:108A5000AFB1002CA7A00014920600D1920500D05F
-:108A60003094FFFF30C400FF30A300FF0064102BE0
-:108A7000A7A0001E10400071AFA00010920900D006
-:108A80000014982B312800FF0088382324F2FFFFC0
-:108A90000012882B0233782451E000758FB2001049
-:108AA00096180012961900100014F4000319B82348
-:108AB0000017B400001614030282A82A16A00002B0
-:108AC000001E2403004020210244F82B13E0000282
-:108AD00000801821024018210003340000061C0306
-:108AE0003065FFFF2CA200091440000200609821AD
-:108AF000241300088E090008001359808E08000C0A
-:108B00003164FFFF3C0A0010008A3825274A040020
-:108B1000AF490038AF8A00B8AF48003CAF470030DB
-:108B20000000000000000000000000000000000045
-:108B30000000000000000000000000000000000035
-:108B40008F4D000031AC00201180FFFD0013702A12
-:108B500001D110240000A821104001C00000000035
-:108B60008F9800B03C0B08008D6B00542411FF80DF
-:108B7000921E00D00178202100911024921900D07B
-:108B8000AF4200288D4500103C0608008CC60058F6
-:108B90003C1708008EF7005430A73FFF00071980EC
-:108BA00000C34021030820210091F824920B00D03B
-:108BB000AF5F002C9148000033D600FF332F00FF39
-:108BC00002F8702100166140000F68C031C9007FB3
-:108BD000018D3821013A2821316300FF3086007F62
-:108BE0003C02000C00A2B021000389400367C821A9
-:108BF00000DAF8213108003F3C1E000E0236B82191
-:108C00002738008803FE88212D0F0008AF9800AC9C
-:108C1000AF9700BCAF9600C011E0018FAF9100B4D8
-:108C2000000868803C0E080025CE59E001AE6021A6
-:108C30008D8900000120000800000000920E00D283
-:108C4000920D00D00014982B31CA00FF31AC00FF08
-:108C5000008C5823014B20212492FFFF0012882B07
-:108C60000233782415E0FF8E000000008FB2001060
-:108C70008FBF004C8FBE00483A4200018FB70044BE
-:108C80008FB600408FB5003C8FB400388FB30034EE
-:108C90008FB200308FB1002C8FB0002803E00008A5
-:108CA00027BD0050915800013317002012E0020444
-:108CB00024160001921F00BC0000B02133F900010E
-:108CC0001320000D241E00018D4800148E03008423
-:108CD0000103B02B16C00002010030218E06008473
-:108CE0008E05006400C5382B14E0000200C020216E
-:108CF0008E0400640080B0218D4200148E0B00644D
-:108D0000004B302B14C00002004020218E04006470
-:108D10000096B82356E00001241E0002025E202BBC
-:108D200014800148000018218D5900388E2F000C46
-:108D30003C180080AE3900008D5000343C0EFF9F7F
-:108D400001F86025AE3000049149003F35CDFFFFAA
-:108D5000018D20243C0A00203C0BFFEFA229000BD0
-:108D6000008A38253562FFFF00E228243C0600080F
-:108D70008F8700B800A6C825AE39000C8CE300141C
-:108D8000AE2000183C08FFFBAE2300148CF800183E
-:108D9000351FFFFF033F7024AE38001C8CEF000826
-:108DA00002D78021AE2F00248CED000CAE30002CB9
-:108DB000AE2E000CAE2D0020AE200028A6200038DC
-:108DC000A620003A8CEC001401964823013750236A
-:108DD00011400011AE2A001090EE003D8E2C0004D0
-:108DE0008E240000000E6900018D28210000502112
-:108DF00000AD302B008A582101661021AE250004F9
-:108E0000AE22000090E3003DA223000A8F8800B844
-:108E1000951F0006A63F00088F8B00AC24060002B9
-:108E200002C02021A16600009765003C8F9000AC35
-:108E300030A2FFFF0E000CF6AFA200208FA300208F
-:108E4000000243808F8500B80103C8253C1F420003
-:108E5000033FC025AE1800048F8400AC8CAF0038EF
-:108E6000AC8F00188CB00034AC90001CAC80000CAF
-:108E7000AC800010A4800014A4800016A480002000
-:108E8000A4800022AC80002490A7003FA4870002A9
-:108E900012C00210240D000152E0000290A2003D19
-:108EA00090A2003E244A0001A08A00018F8400ACF9
-:108EB000AC9600088F8300D024070034906F00BC6C
-:108EC00031EE000251C00001240700308F8200B84B
-:108ED0008F9900BC906800BC905F000024100004D3
-:108EE00032CF0003A33F00008F9800B88F8C00BCE6
-:108EF000020F7023930D00012405C00031CA000346
-:108F0000A18D00018F9000BC8F8900B800F6382138
-:108F1000960400029526001200EA382100855824A4
-:108F200030C33FFF01631025A6020002921F00021A
-:108F30003108000433F9003F37380040A21800021E
-:108F400012C000028F8500BC00E838218F8600D057
-:108F5000ACA70004241FFFBF8CC3007C2ECB0001F4
-:108F6000240FFFDFACA3000890A8000D000B6940A0
-:108F70003102007FA0A2000D8F9000BC9219000D5D
-:108F8000033FC024A218000D8F8A00BC914E000D33
-:108F900001CF6024018D4825A149000D8F8600B8BE
-:108FA0008F8B00BC8CC70020AD6700108CC50024DF
-:108FB000AD6500148CC40028AD6400188CC3002C6F
-:108FC0000E000D16AD63001C2408000257C8009C5B
-:108FD0008F9000D08F8F00D08F8A00C002E02021B8
-:108FE00091E800D091EB00D091E700D0311000FF64
-:108FF000316E00FF00106940000E28C001A5182145
-:1090000030E900FF0363C8210009314000CAF8219C
-:1090100027220088AF8200ACAF9F00BCA33E00882F
-:109020000E000CF68F9000AC8FB800200002638019
-:109030003C0F4200019840258F8C00B8010F582545
-:10904000AE0B00048D8400388F8B00AC000028210B
-:1090500000053900AD6400188D8E00343C0F7FFF91
-:1090600035E8FFFFAD6E001C9183003E8D69001C4A
-:109070008D6600180003510000036F02012AC02111
-:1090800000ED1025030AF82B00C2C821033F802100
-:10909000AD78001CAD700018AD60000CAD60001024
-:1090A0009184003E241F00052410C000A564001414
-:1090B000958E000402E8402402E02021A56E0016EF
-:1090C0009185003EA5650020958D0004A56D0022C8
-:1090D000AD6000249187003FA56700029183003EA8
-:1090E0009189003D0123502325460001A16600011E
-:1090F0008F8200AC8F9900BCAC570008A33F0000E2
-:109100008F8A00BC8F9800B8954F0002970E00120E
-:109110002418FFBF020F682431C53FFF01A5382581
-:10912000A5470002914C00022405FFDF3189003F72
-:1091300035230040A14300028F9900BC8F8600D0E8
-:109140002409FFFFAF2000048CCB007C2403FF80A8
-:10915000AF2B00089322000D3C0B8000305F007F96
-:10916000A33F000D8F8E00BC91D0000D0218782413
-:10917000A1CF000D8F8C00BC918D000D01A538246E
-:10918000A187000D8F8600BCACC90010ACD60014BE
-:1091900090CA00180143B025A0D600188F8F00BCDC
-:1091A0008F9800B88DE20018004BF82403E8C8251A
-:1091B000ADF900189310003EA1F0001C8F8E00B88E
-:1091C0008F8D00BC8F8700D095C50004A5A5001E1B
-:1091D0000E00020D8CE500848F8700D000026140F4
-:1091E0000002210090EA00BC0184482100402821AF
-:1091F0003156000212C0000302E930210002B080A3
-:1092000000D6302190EC00BC3184000410800003B3
-:1092100032EA00030005C08000D830212409000490
-:109220008F9700BC012A1023305F000300DFC821A4
-:10923000AEF900040E000D16A62500388F9000D060
-:1092400003C01821146000020060B02100009021CA
-:1092500056C000868F9700B80012882B9609001020
-:10926000029550233C14002002A91021A6020010F0
-:10927000AF5400303154FFFF00000000961300107F
-:10928000961F001213F30011000000008E17000C4F
-:109290008E0C00080015C98002F94021001927C36F
-:1092A0000119B02B0184782101F65821AE08000C79
-:1092B000AE0B00080014A82B023580241200FE6BB0
-:1092C0008F9000D00A000F3F00000000960B0014A2
-:1092D0008E0500043163FFFF000370C000AE38212B
-:1092E000AF47003C8E0600048F4D003C00CDF023BC
-:1092F0001BC00036000000008E080000250200019F
-:109300003C16001036CF0008AF420038AF4F003097
-:10931000000000000000000000000000000000004D
-:10932000000000000000000000000000000000003D
-:109330008F440000308C00201180FFFD00000000F1
-:109340008F5904003C170020AE1900088F55040403
-:10935000AE15000CAF570030000000003C060800BE
-:109360008CC600442418000110D800D3000000006F
-:10937000960700123C0508008CA5004000A7682154
-:10938000A60D0012961E001427C90001A60900149C
-:10939000960200143044FFFF5486FFC70014A82B28
-:1093A00030A5FFFF0E000F1AA60000143C030800B2
-:1093B0008C630024960500120043702300AE302316
-:1093C000A60600120A0011450014A82B8E02000008
-:1093D0000A0011583C16001091560001241000019B
-:1093E0000016784215F0001C97A8001E8D5F00142F
-:1093F0002411C00033FE3FFF0111C8243C180800AF
-:109400008F180060033EB82532E53FFF00B8502BAF
-:1094100011400011A7B7001E3C1008008E10005824
-:109420008F8F00B000057180240CFF80020F68212F
-:1094300001AE48213124007F012C5824009A2821B4
-:109440003C02000EAF4B002C00A2302190C7000D53
-:1094500034E30004A0C3000D0E000D38000000002E
-:109460008F9000D0240300018F9700B826B9000127
-:109470000019AC00024390230015AC0326F800400D
-:1094800002B3202A0012882B240C00010300502173
-:1094900000911024AF9800B80A000F6DAFAC001017
-:1094A000955600128F8400B032C5FFFF0E000CEB02
-:1094B000A7B600148F9000D00A0011B10000182147
-:1094C0008D590038A620000824040003AE3900009E
-:1094D0008D570034A220000A8F9800B8AE370004E0
-:1094E0003C0F0080930C003FA224000C8E28000C3F
-:1094F0003C0BFF9FA22C000B010F1825356EFFFFC0
-:109500003C05FFEF8F9700B8006E682434A7FFFF7B
-:1095100001A73024AE26000C8EFE001496FF001228
-:109520008F8200B0AE3E00108EF00014AE20001806
-:10953000AE200020AE300014AE2000248EE90018CA
-:1095400033F03FFF00105180AE2900288EF900084B
-:109550000142C02133EC0001AE3900308EEB000C2B
-:109560008F8500AC001879C2000C238001E44021F3
-:10957000240E0002A628001CA6200036AE2B002CCC
-:10958000A0AE00009767003C8F8A00AC3C0342000D
-:1095900030EDFFFF01A33025AD4600048F9E00B8DB
-:1095A000240200012408C0008FD1003824060034B2
-:1095B000AD5100188FC90034AD49001CAD40000CFE
-:1095C000AD400010A5400014A5400016A5400020A5
-:1095D000A5400022AD400024A5560002A142000192
-:1095E0008F9F00AC8F9900B88F9800BCAFF6000831
-:1095F00093370000A31700008F8C00B88F8F00BC3A
-:1096000091840001A1E400018F8D00BC95AB0002A4
-:109610000168702401D02825A5A5000291A70002A9
-:1096200030E3003FA1A300028F8300D08F8400BCF1
-:10963000907100BC323E000253C00001240600308D
-:10964000AC8600048C6F007C2403FFBFAC8F000845
-:109650009088000D310B007FA08B000D8F8700BC20
-:1096600090EE000D01C32824A0E5000D8F9E00BCE4
-:1096700093CD000D35A60020A3C6000D8F8A00B83B
-:109680008F9100BC8D500020AE3000108D49002419
-:10969000AE2900148D420028AE2200188D5F002CE8
-:1096A000AE3F001C0E000D16000000008F9000D091
-:1096B0000A00112B02C01821960A00123C1F080054
-:1096C0008FFF002403EA9821A61300120A00114517
-:1096D0000014A82BA08D00018F8900AC240C000180
-:1096E000AD2C00080A0010458F8300D027BDFFE095
-:1096F0003C1808008F180050AFB00010AFBF001822
-:10970000AFB10014AF8400B09371007403047821EA
-:109710002410FF8031EE007F3225007F01F05824B5
-:1097200001DA68213C0C000AA38500C401AC2821A1
-:10973000AF4B002494A900109768000690A6006221
-:1097400000803821240200300109202330C300F0BA
-:10975000AF8500D0106200193090FFFF90AE00621C
-:10976000240DFFF0240A005001AE6024318B00FF6D
-:10977000116A002F0000000016000007241F0C00D3
-:10978000AF5F00248FB100148FBF00188FB000109E
-:1097900003E0000827BD00200E000F20020020215A
-:1097A000241F0C00AF5F00248FB100148FBF00187E
-:1097B0008FB0001003E0000827BD002094A200E055
-:1097C00094A400E290BF0113008218263079FFFFB5
-:1097D00033E700C014E000092F3100011600003803
-:1097E000000000005620FFE6241F0C000E000DDBD9
-:1097F000000000000A001277241F0C001620FFDE74
-:10980000000000000E000DDB000000001440FFDC33
-:10981000241F0C00160000228F8300D090690113D2
-:109820003122003FA06201130A001277241F0C00AE
-:1098300094AF00D48F8600D400E0282124040005D2
-:109840000E000C7C31F0FFFF1440000524030003E0
-:10985000979100E6000018212625FFFFA78500E666
-:109860008F5801B80700FFFE3C196013AF4001801C
-:10987000241F0C00AF500184007938253C101000E3
-:10988000AF4701888FB10014AF5001B8AF5F00241B
-:109890008FB000108FBF001803E0000827BD002024
-:1098A0000E000F20020020215040FFB5241F0C00A5
-:1098B0008F8300D0906901130A0012A03122003F6B
-:1098C0000E000F20020020211440FFAD241F0C00C9
-:1098D000122000078F8300D0906801133106003FEB
-:1098E00034C20040A06201130A001277241F0C004A
-:1098F0000E000DDB000000005040FFA1241F0C00F3
-:109900008F8300D0906801133106003F0A0012D007
-:1099100034C20040AF9B00C803E00008AF8000ECF9
-:109920003089FFFF000940422D02004100092980D3
-:10993000144000020009504024080040000879400B
-:109940000008C0C001F85821256701A800EF702168
-:1099500025CC007F240DFF80018D18240065302167
-:1099600000CA282125640088240A00883C010800D8
-:10997000AC2A004C3C010800AC240050AF8500D458
-:109980003C010800AC2900603C010800AC280064E0
-:109990003C010800AC2700543C010800AC230058EF
-:1099A0003C010800AC26005C03E000080000000059
-:1099B000308300FF30C6FFFF30E400FF8F4201B864
-:1099C0000440FFFE00034C00012438253C086000E1
-:1099D00000E820253C031000AF450180AF4601841C
-:1099E000AF44018803E00008AF4301B88F86001C34
-:1099F0003C096012352700108CCB00043C0C600E33
-:109A000035850010316A00062D480001ACE800C41D
-:109A10008CC40004ACA431808CC2000894C3000242
-:109A2000ACA2318403E00008A78300E43C030800F3
-:109A30008C6300508F8400E88F86001C2402FF8016
-:109A40000064C0210302C824AF5900288CCD000453
-:109A50003305007F00BA78213C0E000C01EE28216E
-:109A6000ACAD00588CC80008AF8500D03C07601230
-:109A7000ACA8005C8CCC001034E80010ACAC000C3E
-:109A80008CCB000CACAB000894AA00143C0208007C
-:109A90008C42004425490001A4A9001494A4001498
-:109AA0003083FFFF106200178F8400D03C0A08004B
-:109AB0008D4A0040A4AA00128CCE0018AC8E00245F
-:109AC0008CCD0014AC8D00208CC70018AC87002C06
-:109AD0008CCC001424060001AC8C00288D0B00BC3B
-:109AE0005166001A8D0200B48D0200B8A482003ABB
-:109AF000948F003AA48F003C948800D403E00008BF
-:109B00003102FFFF3C0908008D290024A4A00014A5
-:109B10008F8400D0A4A900128CCE0018AC8E002433
-:109B20008CCD0014AC8D00208CC70018AC87002CA5
-:109B30008CCC001424060001AC8C00288D0B00BCDA
-:109B40005566FFEA8D0200B88D0200B4A482003A87
-:109B5000948F003AA48F003C948800D403E000085E
-:109B60003102FFFF8F86001C3C0C08008D8C0050DA
-:109B7000240BFF808CCD00083C03000C000D51C06D
-:109B8000018A4021010B4824AF8A00E8AF49002830
-:109B900090C700073105007F00BA1021004328213B
-:109BA00030E400041080002FAF8500D090CF000774
-:109BB00031EE000811C0003C000000008CD9000C00
-:109BC0008CC400140324C02B1300002600000000E6
-:109BD0008CC2000CACA200648CCD00182402FFF8EB
-:109BE000ACAD00688CCC0010ACAC00808CCB000C11
-:109BF000ACAB00848CCA001CACAA007C90A900BC51
-:109C000001224024A0A800BC90C3000730670008D0
-:109C100010E000048F8500D090AF00BC35EE00014D
-:109C2000A0AE00BC90D90007333800011300000F2C
-:109C30008F8400D024070020908200BC34490002A9
-:109C4000A08900BC8F8400D090880062310300F0AE
-:109C500014670006240A0034AC8A00C00A0013B25C
-:109C6000000000000A00138C8CC2001490CB000787
-:109C70003166000210C0000500000000908D00BC9D
-:109C800035AC0004A08C00BC8F8400D090980113E8
-:109C9000330F003FA08F01138F8E00D095C500D4E5
-:109CA00003E0000830A2FFFFACA000640A00138D9F
-:109CB0000000000027BDFFD8AFB000108F90001C3F
-:109CC000AFBF0024AFB40020AFB20018AFB1001492
-:109CD000AFB3001C9613000E3C07600A3C146006EC
-:109CE0003264FFFF369300100E0012DF34F40410CC
-:109CF0008F8400D43C11600E0E0009BB3631001079
-:109D0000920E00153C0708008CE700603C126012C0
-:109D100031CD000FA38D00F08E0E00048E0D0008D3
-:109D200096080012961F00109619001A9618001E29
-:109D3000960F001C310CFFFF33EBFFFF332AFFFFB0
-:109D40003309FFFF31E6FFFF3C010800AC2B004068
-:109D50003C010800AC2C00243C010800AC2A004463
-:109D6000AE293178AE26317C92020015960300169A
-:109D700036520010304400FF3065FFFF3C060800FB
-:109D80008CC60064AE243188AE4500B4920800143D
-:109D900096190018241F0001011FC004332FFFFF74
-:109DA0003C0508008CA50058AE5800B8AE4F00BC6A
-:109DB000920C0014AF8E00D8AF8D00DC318B00FF09
-:109DC000AE4B00C0920A0015AE670048AE66004C6C
-:109DD000314900FFAE4900C8AE65007C3C03080075
-:109DE0008C6300503C0408008C84004C3C08080044
-:109DF0008D0800543C0208008C42005C8FBF002498
-:109E0000AE6300808FB00010AE8300748FB3001C6F
-:109E1000AE22319CAE4200DCAE2731A0AE2631A48A
-:109E2000AE24318CAE233190AE283194AE253198DA
-:109E3000AE870050AE860054AE8500708FB100141E
-:109E4000AE4700E0AE4600E4AE4400CCAE4300D0E6
-:109E5000AE4800D4AE4500D88FB400208FB20018B1
-:109E600003E0000827BD002827BDFFE0AFB10014C4
-:109E7000AFBF0018241100010E000865AFB000103C
-:109E800010510005978400E6978300CC0083102BC7
-:109E9000144000088F8500D4240700028FBF0018EB
-:109EA0008FB100148FB0001000E0102103E0000813
-:109EB00027BD00200E000C9A24040005AF8200E8A4
-:109EC0001040FFF6240700020E0008698F90001C66
-:109ED000979F00E68F9900E88F8D00C827EF00015B
-:109EE000240E0050AF590020A78F00E6A1AE00005D
-:109EF0003C0C08008D8C00648F8600C8240A80000A
-:109F0000000C5E00ACCB0074A4C0000694C9000A2B
-:109F1000241FFF803C0D000C012AC024A4D8000A95
-:109F200090C8000A24182000011F1825A0C3000AA9
-:109F30008F8700C8A0E000788F8500C80000382116
-:109F4000A0A000833C0208008C4200508F8400E8EF
-:109F50000044782101FFC824AF590028960B000265
-:109F600031EE007F01DA6021018D3021A4CB00D4D5
-:109F7000960A0002AF8600D03C0E00042549240159
-:109F8000A4C900E68E080004ACC800048E030008D3
-:109F9000ACC30000A4C00010A4C00014A0C000D036
-:109FA0008F8500D02403FFBFA0A000D13C0408008F
-:109FB0008C8400648F8200D0A04400D28E1F000CDD
-:109FC0008F8A00D0978F00E4AD5F001C8E190010BF
-:109FD00024100030AD590018A5400030A5510054A0
-:109FE000A5510056A54F0016AD4E0068AD58008033
-:109FF000AD580084914D006231AC000F358B0010DC
-:10A00000A14B00628F8600D090C900633128007F89
-:10A01000A0C800638F8400D02406FFFF90850063F2
-:10A0200000A31024A08200638F9100D000E01021D3
-:10A03000923F00BC37F90001A23900BC8F8A00D0E2
-:10A04000938F00F0AD580064AD5000C0914E00D326
-:10A05000000F690031CC000F018D5825A14B00D3B2
-:10A060008F8500D08F8900DCACA900E88F8800D8EC
-:10A070008FBF00188FB100148FB0001027BD0020D3
-:10A08000ACA800ECA4A600D6A4A000E0A4A000E226
-:10A0900003E000080000000027BDFFE0AFB00010A3
-:10A0A0008F90001CAFB10014AFBF00188E190004D0
-:10A0B0003C1808008F180050240FFF80001989C039
-:10A0C0000238702131CD007F01CF602401BA5021C8
-:10A0D0003C0B000CAF4C0028014B4021950900D4EB
-:10A0E000950400D68E0700043131FFFFAF8800D001
-:10A0F0000E000933000721C08E0600048F8300C8BC
-:10A10000000629C0AF4500209064003E3082004028
-:10A11000144000068F8400D0341FFFFF948300D6C4
-:10A120003062FFFF145F000400000000948400D63A
-:10A130000E0008C83084FFFF8E0500040220302185
-:10A140008FBF00188FB100148FB0001024040022BC
-:10A1500000003821000529C00A00130327BD002094
-:10A1600027BDFFE0AFB100143091FFFFAFB000108A
-:10A17000AFBF00181220001D000080218F86001C38
-:10A180008CC500002403000600053F0200051402F0
-:10A1900030E4000714830015304500FF2CA80006AA
-:10A1A0001100004D000558803C0C0800258C5A0019
-:10A1B000016C50218D4900000120000800000000C2
-:10A1C0008F8E00EC240D000111CD0059000000001D
-:10A1D000260B00013170FFFF24CA00200211202B42
-:10A1E000014030211480FFE6AF8A001C02001021DC
-:10A1F0008FBF00188FB100148FB0001003E000086B
-:10A2000027BD0020938700CE14E0003824040014FA
-:10A210000E0013C4000000008F86001C2402000101
-:10A220000A00150BAF8200EC8F8900EC24080002B5
-:10A230001128003B240400130000282100003021D5
-:10A24000240700010E001303000000000A00150B94
-:10A250008F86001C8F8700EC2405000214E5FFF6B2
-:10A26000240400120E001370000000008F8500E827
-:10A2700000403021240400120E0013030000382196
-:10A280000A00150B8F86001C8F8300EC241F00032F
-:10A29000147FFFD0260B00010E00132200000000E7
-:10A2A0008F8500E8004030212402000224040010C1
-:10A2B00000003821AF8200EC0E0013030000000004
-:10A2C0000A00150B8F86001C8F8F00EC24060002FD
-:10A2D00011E6000B000000002404001000002821FB
-:10A2E000000030210A001528240700010000282161
-:10A2F0000E001303000030210A00150B8F86001C8E
-:10A300000E00143100000000144000128F99001C50
-:10A310008F86001C240200030A00150BAF8200EC9C
-:10A320000E0014BD000000000A00150B8F86001CF3
-:10A330000E00131200000000240200022404001486
-:10A340000000282100003021000038210A001545B6
-:10A35000AF8200EC0040382124040010973800023E
-:10A36000000028210E0013033306FFFF0A00150B1F
-:10A370008F86001C8F8400C83C077FFF34E6FFFFF8
-:10A380008C8500742402000100A61824AC8300749C
-:10A3900003E00008A082000510A000362CA2008077
-:10A3A000274A04003C0B00052409008010400007E8
-:10A3B0002408008030A6000F00C540212D03008135
-:10A3C0001460000200A0482124080080AF4B003038
-:10A3D0000000000000000000000000001100000963
-:10A3E00000003821014030218C8D000024E700045A
-:10A3F00000E8602BACCD0000248400041580FFFA37
-:10A4000024C600040000000000000000000000005E
-:10A410003C0E0006010E3825AF470030000000005A
-:10A4200000000000000000008F4F000031E8001025
-:10A430001100FFFD000000008F42003C8F43003CF4
-:10A440000049C8210323C02B1300000400000000B2
-:10A450008F4C003825860001AF4600388F47003CFE
-:10A4600000A9282300E96821AF4D003C14A0FFCECD
-:10A470002CA2008003E000080000000027BDFFD0F0
-:10A480003C020002AFB100143C11000CAF45003893
-:10A49000AFB3001CAF46003C00809821AF420030B3
-:10A4A00024050088AF44002803512021AFBF0028B5
-:10A4B000AFB50024AFB40020AFB200180E00157D78
-:10A4C000AFB000103C1F08008FFF004C3C18080084
-:10A4D0008F1800642410FF8003F3A82132B9007F95
-:10A4E00002B078240018A0C0033A702100189140EF
-:10A4F00001D12021AF4F00280E00157D02542821E4
-:10A500003C0D08008DAD00502405012001B35821F9
-:10A51000316C007F01705024019A482101312021C3
-:10A520000E00157DAF4A00283C0808008D08005435
-:10A530003C0508008CA500640113382130E6007F3B
-:10A5400000F0182400DA202100912021AF430028D8
-:10A550000E00157D000529403C0208008C42005881
-:10A560003C1008008E1000601200001C005388216F
-:10A570002415FF800A0016003C14000C3226007FD0
-:10A580000235182400DA202102402821AF43002898
-:10A59000009420210E00157D2610FFC01200000F30
-:10A5A000023288212E05004110A0FFF42412100071
-:10A5B0003226007F001091800235182400DA202115
-:10A5C00002402821AF430028009420210E00157D71
-:10A5D000000080211600FFF3023288213C0B0800A6
-:10A5E0008D6B005C240AFF8024050002017340216A
-:10A5F000010A4824AF4900283C0408009484006202
-:10A600003110007F021A88213C07000C0E000CCA92
-:10A610000227982100402821026020218FBF0028B6
-:10A620008FB500248FB400208FB3001C8FB20018A8
-:10A630008FB100148FB000100A00157D27BD0030C7
-:10A640008F83001C8C620004104000030000000097
-:10A6500003E00008000000008C6400108C65000816
-:08A660000A0015B68C66000C1F
-:08A66800000000000000001BCF
-:10A670000000000F0000000A0000000800000006B3
-:10A6800000000005000000050000000400000004B8
-:10A6900000000003000000030000000300000003AE
-:10A6A00000000003000000020000000200000002A1
-:10A6B0000000000200000002000000020000000292
-:10A6C0000000000200000002000000020000000282
-:10A6D0000000000200000002000000020000000272
-:0CA6E0000000000100000001000000016B
-:04A6EC0008000F58FB
-:10A6F00008000DB008000FEC0800109408000F804F
-:10A7000008000FC0080011CC08000DCC080011F0A3
-:10A7100008000E1C08001634080015DC08000DCCDB
-:10A7200008000DCC08000DCC0800127C0800127C3B
-:10A7300008000DCC08000DCC0800158008000DCCD9
-:10A7400008000DCC08000DCC08000DCC080013F05B
-:10A7500008000DCC08000DCC08000DCC08000DCC75
-:10A7600008000DCC08000DCC08000DCC08000DCC65
-:10A7700008000DCC08000DCC08000DCC08000DCC55
-:10A7800008000DCC08000DCC08000FE008000DCC2F
-:10A7900008000DCC0800153008000DCC08000DCCC9
-:10A7A00008000DCC08000DCC08000DCC08000DCC25
-:10A7B00008000DCC08000DCC08000DCC08000DCC15
-:10A7C00008000DCC08000DCC08000DCC08000DCC05
-:10A7D00008000DCC08000DCC08000DCC0800145C5E
-:10A7E00008000DCC08000DCC08001370080012E022
-:10A7F00008002E9408002E9C08002E6408002E707D
-:10A8000008002E7C08002E88080046B408003F008F
-:10A8100008004634080046B4080046B4080044B4B2
-:10A82000080046B4080046FC08005524080054E41B
-:10A83000080054B008005484080054600800541CF8
-:10A840000A000C7600000000000000000000000D6F
-:10A85000727870352E302E306A3600000500000305
-:10A8600000000000000000010000000000000000E7
-:10A8700000000000000000000000000000000000D8
-:10A8800000000000000000000000000000000000C8
-:10A8900000000000000000000000000000000000B8
-:10A8A00000000000000000000000000000000000A8
-:10A8B0000000000000000000000000000000000098
-:10A8C0000000000000000000000000000000000088
-:10A8D0000000000000000000000000000000000078
-:10A8E0000000000000000000000000000000000068
-:10A8F0000000000000000000000000000000000058
-:10A900000000000000000000000000000000000047
-:10A910000000000000000000000000000000000037
-:10A920000000000000000000000000000000000027
-:10A930000000000000000000000000000000000017
-:10A940000000000000000000000000000000000007
-:10A9500000000000000000000000000000000000F7
-:10A9600000000000000000000000000000000000E7
-:10A9700000000000000000000000000000000000D7
-:10A9800000000000000000000000000000000000C7
-:10A9900000000000000000000000000000000000B7
-:10A9A00000000000000000000000000000000000A7
-:10A9B0000000000000000000000000000000000097
-:10A9C0000000000000000000000000000000000087
-:10A9D0000000000000000000000000000000000077
-:10A9E0000000000000000000000000000000000067
-:10A9F0000000000000000000000000000000000057
-:10AA00000000000000000000000000000000000046
-:10AA10000000000000000000000000000000000036
-:10AA20000000000000000000000000000000000026
-:10AA30000000000000000000000000000000000016
-:10AA40000000000000000000000000000000000006
-:10AA500000000000000000000000000000000000F6
-:10AA600000000000000000000000000000000000E6
-:10AA700000000000000000000000000000000000D6
-:10AA800000000000000000000000000000000000C6
-:10AA900000000000000000000000000000000000B6
-:10AAA00000000000000000000000000000000000A6
-:10AAB0000000000000000000000000000000000096
-:10AAC0000000000000000000000000000000000086
-:10AAD0000000000000000000000000000000000076
-:10AAE0000000000000000000000000000000000066
-:10AAF0000000000000000000000000000000000056
-:10AB00000000000000000000000000000000000045
-:10AB10000000000000000000000000000000000035
-:10AB20000000000000000000000000000000000025
-:10AB30000000000000000000000000000000000015
-:10AB40000000000000000000000000000000000005
-:10AB500000000000000000000000000000000000F5
-:10AB600000000000000000000000000000000000E5
-:10AB700000000000000000000000000000000000D5
-:10AB800000000000000000000000000000000000C5
-:10AB900000000000000000000000000000000000B5
-:10ABA00000000000000000000000000000000000A5
-:10ABB0000000000000000000000000000000000095
-:10ABC0000000000000000000000000000000000085
-:10ABD0000000000000000000000000000000000075
-:10ABE0000000000000000000000000000000000065
-:10ABF0000000000000000000000000000000000055
-:10AC00000000000000000000000000000000000044
-:10AC10000000000000000000000000000000000034
-:10AC20000000000000000000000000000000000024
-:10AC30000000000000000000000000000000000014
-:10AC40000000000000000000000000000000000004
-:10AC500000000000000000000000000000000000F4
-:10AC600000000000000000000000000000000000E4
-:10AC700000000000000000000000000000000000D4
-:10AC800000000000000000000000000000000000C4
-:10AC900000000000000000000000000000000000B4
-:10ACA00000000000000000000000000000000000A4
-:10ACB0000000000000000000000000000000000094
-:10ACC0000000000000000000000000000000000084
-:10ACD0000000000000000000000000000000000074
-:10ACE0000000000000000000000000000000000064
-:10ACF0000000000000000000000000000000000054
-:10AD00000000000000000000000000000000000043
-:10AD10000000000000000000000000000000000033
-:10AD20000000000000000000000000000000000023
-:10AD30000000000000000000000000000000000013
-:10AD40000000000000000000000000000000000003
-:10AD500000000000000000000000000000000000F3
-:10AD600000000000000000000000000000000000E3
-:10AD700000000000000000000000000000000000D3
-:10AD800000000000000000000000000000000000C3
-:10AD900000000000000000000000000000000000B3
-:10ADA00000000000000000000000000000000000A3
-:10ADB0000000000000000000000000000000000093
-:10ADC0000000000000000000000000000000000083
-:10ADD0000000000000000000000000000000000073
-:10ADE0000000000000000000000000000000000063
-:10ADF0000000000000000000000000000000000053
-:10AE00000000000000000000000000000000000042
-:10AE10000000000000000000000000000000000032
-:10AE20000000000000000000000000000000000022
-:10AE30000000000000000000000000000000000012
-:10AE40000000000000000000000000000000000002
-:10AE500000000000000000000000000000000000F2
-:10AE600000000000000000000000000000000000E2
-:10AE700000000000000000000000000000000000D2
-:10AE800000000000000000000000000000000000C2
-:10AE900000000000000000000000000000000000B2
-:10AEA00000000000000000000000000000000000A2
-:10AEB0000000000000000000000000000000000092
-:10AEC0000000000000000000000000000000000082
-:10AED0000000000000000000000000000000000072
-:10AEE0000000000000000000000000000000000062
-:10AEF0000000000000000000000000000000000052
-:10AF00000000000000000000000000000000000041
-:10AF10000000000000000000000000000000000031
-:10AF20000000000000000000000000000000000021
-:10AF30000000000000000000000000000000000011
-:10AF40000000000000000000000000000000000001
-:10AF500000000000000000000000000000000000F1
-:10AF600000000000000000000000000000000000E1
-:10AF700000000000000000000000000000000000D1
-:10AF800000000000000000000000000000000000C1
-:10AF900000000000000000000000000000000000B1
-:10AFA00000000000000000000000000000000000A1
-:10AFB0000000000000000000000000000000000091
-:10AFC0000000000000000000000000000000000081
-:10AFD0000000000000000000000000000000000071
-:10AFE0000000000000000000000000000000000061
-:10AFF0000000000000000000000000000000000051
-:10B000000000000000000000000000000000000040
-:10B010000000000000000000000000000000000030
-:10B020000000000000000000000000000000000020
-:10B030000000000000000000000000000000000010
-:10B040000000000000000000000000000000000000
-:10B0500000000000000000000000000000000000F0
-:10B0600000000000000000000000000000000000E0
-:10B0700000000000000000000000000000000000D0
-:10B0800000000000000000000000000000000000C0
-:10B0900000000000000000000000000000000000B0
-:10B0A00000000000000000000000000000000000A0
-:10B0B0000000000000000000000000000000000090
-:10B0C0000000000000000000000000000000000080
-:10B0D0000000000000000000000000000000000070
-:10B0E0000000000000000000000000000000000060
-:10B0F0000000000000000000000000000000000050
-:10B10000000000000000000000000000000000003F
-:10B11000000000000000000000000000000000002F
-:10B12000000000000000000000000000000000001F
-:10B13000000000000000000000000000000000000F
-:10B1400000000000000000000000000000000000FF
-:10B1500000000000000000000000000000000000EF
-:10B1600000000000000000000000000000000000DF
-:10B1700000000000000000000000000000000000CF
-:10B1800000000000000000000000000000000000BF
-:10B1900000000000000000000000000000000000AF
-:10B1A000000000000000000000000000000000009F
-:10B1B000000000000000000000000000000000008F
-:10B1C000000000000000000000000000000000007F
-:10B1D000000000000000000000000000000000006F
-:10B1E000000000000000000000000000000000005F
-:10B1F000000000000000000000000000000000004F
-:10B20000000000000000000000000000000000003E
-:10B21000000000000000000000000000000000002E
-:10B22000000000000000000000000000000000001E
-:10B23000000000000000000000000000000000000E
-:10B2400000000000000000000000000000000000FE
-:10B2500000000000000000000000000000000000EE
-:10B2600000000000000000000000000000000000DE
-:10B2700000000000000000000000000000000000CE
-:10B2800000000000000000000000000000000000BE
-:10B2900000000000000000000000000000000000AE
-:10B2A000000000000000000000000000000000009E
-:10B2B000000000000000000000000000000000008E
-:10B2C000000000000000000000000000000000007E
-:10B2D000000000000000000000000000000000006E
-:10B2E000000000000000000000000000000000005E
-:10B2F000000000000000000000000000000000004E
-:10B30000000000000000000000000000000000003D
-:10B31000000000000000000000000000000000002D
-:10B32000000000000000000000000000000000001D
-:10B33000000000000000000000000000000000000D
-:10B3400000000000000000000000000000000000FD
-:10B3500000000000000000000000000000000000ED
-:10B3600000000000000000000000000000000000DD
-:10B3700000000000000000000000000000000000CD
-:10B3800000000000000000000000000000000000BD
-:10B3900000000000000000000000000000000000AD
-:10B3A000000000000000000000000000000000009D
-:10B3B000000000000000000000000000000000008D
-:10B3C000000000000000000000000000000000007D
-:10B3D000000000000000000000000000000000006D
-:10B3E000000000000000000000000000000000005D
-:10B3F000000000000000000000000000000000004D
-:10B40000000000000000000000000000000000003C
-:10B41000000000000000000000000000000000002C
-:10B42000000000000000000000000000000000001C
-:10B43000000000000000000000000000000000000C
-:10B4400000000000000000000000000000000000FC
-:10B4500000000000000000000000000000000000EC
-:10B4600000000000000000000000000000000000DC
-:10B4700000000000000000000000000000000000CC
-:10B4800000000000000000000000000000000000BC
-:10B4900000000000000000000000000000000000AC
-:10B4A000000000000000000000000000000000009C
-:10B4B000000000000000000000000000000000008C
-:10B4C000000000000000000000000000000000007C
-:10B4D000000000000000000000000000000000006C
-:10B4E000000000000000000000000000000000005C
-:10B4F000000000000000000000000000000000004C
-:10B50000000000000000000000000000000000003B
-:10B51000000000000000000000000000000000002B
-:10B52000000000000000000000000000000000001B
-:10B53000000000000000000000000000000000000B
-:10B5400000000000000000000000000000000000FB
-:10B5500000000000000000000000000000000000EB
-:10B5600000000000000000000000000000000000DB
-:10B5700000000000000000000000000000000000CB
-:10B5800000000000000000000000000000000000BB
-:10B5900000000000000000000000000000000000AB
-:10B5A000000000000000000000000000000000009B
-:10B5B000000000000000000000000000000000008B
-:10B5C000000000000000000000000000000000007B
-:10B5D000000000000000000000000000000000006B
-:10B5E000000000000000000000000000000000005B
-:10B5F000000000000000000000000000000000004B
-:10B60000000000000000000000000000000000003A
-:10B61000000000000000000000000000000000002A
-:10B62000000000000000000000000000000000001A
-:10B63000000000000000000000000000000000000A
-:10B6400000000000000000000000000000000000FA
-:10B6500000000000000000000000000000000000EA
-:10B6600000000000000000000000000000000000DA
-:10B6700000000000000000000000000000000000CA
-:10B6800000000000000000000000000000000000BA
-:10B6900000000000000000000000000000000000AA
-:10B6A000000000000000000000000000000000009A
-:10B6B000000000000000000000000000000000008A
-:10B6C000000000000000000000000000000000007A
-:10B6D000000000000000000000000000000000006A
-:10B6E000000000000000000000000000000000005A
-:10B6F000000000000000000000000000000000004A
-:10B700000000000000000000000000000000000039
-:10B710000000000000000000000000000000000029
-:10B720000000000000000000000000000000000019
-:10B730000000000000000000000000000000000009
-:10B7400000000000000000000000000000000000F9
-:10B7500000000000000000000000000000000000E9
-:10B7600000000000000000000000000000000000D9
-:10B7700000000000000000000000000000000000C9
-:10B7800000000000000000000000000000000000B9
-:10B7900000000000000000000000000000000000A9
-:10B7A0000000000000000000000000000000000099
-:10B7B0000000000000000000000000000000000089
-:10B7C0000000000000000000000000000000000079
-:10B7D0000000000000000000000000000000000069
-:10B7E0000000000000000000000000000000000059
-:10B7F0000000000000000000000000000000000049
-:10B800000000000000000000000000000000000038
-:10B810000000000000000000000000000000000028
-:10B820000000000000000000000000000000000018
-:10B830000000000000000000000000000000000008
-:10B8400000000000000000000000000000000000F8
-:10B8500000000000000000000000000000000000E8
-:10B8600000000000000000000000000000000000D8
-:10B8700000000000000000000000000000000000C8
-:10B8800000000000000000000000000000000000B8
-:10B8900000000000000000000000000000000000A8
-:10B8A0000000000000000000000000000000000098
-:10B8B0000000000000000000000000000000000088
-:10B8C0000000000000000000000000000000000078
-:10B8D0000000000000000000000000000000000068
-:10B8E0000000000000000000000000000000000058
-:10B8F0000000000000000000000000000000000048
-:10B900000000000000000000000000000000000037
-:10B910000000000000000000000000000000000027
-:10B920000000000000000000000000000000000017
-:10B930000000000000000000000000000000000007
-:10B9400000000000000000000000000000000000F7
-:10B9500000000000000000000000000000000000E7
-:10B9600000000000000000000000000000000000D7
-:10B9700000000000000000000000000000000000C7
-:10B9800000000000000000000000000000000000B7
-:10B9900000000000000000000000000000000000A7
-:10B9A0000000000000000000000000000000000097
-:10B9B0000000000000000000000000000000000087
-:10B9C0000000000000000000000000000000000077
-:10B9D0000000000000000000000000000000000067
-:10B9E0000000000000000000000000000000000057
-:10B9F0000000000000000000000000000000000047
-:10BA00000000000000000000000000000000000036
-:10BA10000000000000000000000000000000000026
-:10BA20000000000000000000000000000000000016
-:10BA30000000000000000000000000000000000006
-:10BA400000000000000000000000000000000000F6
-:10BA500000000000000000000000000000000000E6
-:10BA600000000000000000000000000000000000D6
-:10BA700000000000000000000000000000000000C6
-:10BA800000000000000000000000000000000000B6
-:10BA900000000000000000000000000000000000A6
-:10BAA0000000000000000000000000000000000096
-:10BAB0000000000000000000000000000000000086
-:10BAC0000000000000000000000000000000000076
-:10BAD0000000000000000000000000000000000066
-:10BAE0000000000000000000000000000000000056
-:10BAF0000000000000000000000000000000000046
-:10BB00000000000000000000000000000000000035
-:10BB10000000000000000000000000000000000025
-:10BB20000000000000000000000000000000000015
-:10BB30000000000000000000000000000000000005
-:10BB400000000000000000000000000000000000F5
-:10BB500000000000000000000000000000000000E5
-:10BB600000000000000000000000000000000000D5
-:10BB700000000000000000000000000000000000C5
-:10BB800000000000000000000000000000000000B5
-:10BB900000000000000000000000000000000000A5
-:10BBA0000000000000000000000000000000000095
-:10BBB0000000000000000000000000000000000085
-:10BBC0000000000000000000000000000000000075
-:10BBD0000000000000000000000000000000000065
-:10BBE0000000000000000000000000000000000055
-:10BBF0000000000000000000000000000000000045
-:10BC00000000000000000000000000000000000034
-:10BC10000000000000000000000000000000000024
-:10BC20000000000000000000000000000000000014
-:10BC30000000000000000000000000000000000004
-:10BC400000000000000000000000000000000000F4
-:10BC500000000000000000000000000000000000E4
-:10BC600000000000000000000000000000000000D4
-:10BC700000000000000000000000000000000000C4
-:10BC800000000000000000000000000000000000B4
-:10BC900000000000000000000000000000000000A4
-:10BCA0000000000000000000000000000000000094
-:10BCB0000000000000000000000000000000000084
-:10BCC0000000000000000000000000000000000074
-:10BCD0000000000000000000000000000000000064
-:10BCE0000000000000000000000000000000000054
-:10BCF0000000000000000000000000000000000044
-:10BD00000000000000000000000000000000000033
-:10BD10000000000000000000000000000000000023
-:10BD20000000000000000000000000000000000013
-:10BD30000000000000000000000000000000000003
-:10BD400000000000000000000000000000000000F3
-:10BD500000000000000000000000000000000000E3
-:10BD600000000000000000000000000000000000D3
-:10BD700000000000000000000000000000000000C3
-:10BD800000000000000000000000000000000000B3
-:10BD900000000000000000000000000000000000A3
-:10BDA0000000000000000000000000000000000093
-:10BDB0000000000000000000000000000000000083
-:10BDC0000000000000000000000000000000000073
-:10BDD0000000000000000000000000000000000063
-:10BDE0000000000000000000000000000000000053
-:10BDF0000000000000000000000000000000000043
-:10BE00000000000000000000000000000000000032
-:10BE10000000000000000000000000000000000022
-:10BE20000000000000000000000000000000000012
-:10BE30000000000000000000000000000000000002
-:10BE400000000000000000000000000000000000F2
-:10BE500000000000000000000000000000000000E2
-:10BE600000000000000000000000000000000000D2
-:10BE700000000000000000000000000000000000C2
-:10BE800000000000000000000000000000000000B2
-:10BE900000000000000000000000000000000000A2
-:10BEA0000000000000000000000000000000000092
-:10BEB0000000000000000000000000000000000082
-:10BEC0000000000000000000000000000000000072
-:10BED0000000000000000000000000000000000062
-:10BEE0000000000000000000000000000000000052
-:10BEF0000000000000000000000000000000000042
-:10BF00000000000000000000000000000000000031
-:10BF10000000000000000000000000000000000021
-:10BF20000000000000000000000000000000000011
-:10BF30000000000000000000000000000000000001
-:10BF400000000000000000000000000000000000F1
-:10BF500000000000000000000000000000000000E1
-:10BF600000000000000000000000000000000000D1
-:10BF700000000000000000000000000000000000C1
-:10BF800000000000000000000000000000000000B1
-:10BF900000000000000000000000000000000000A1
-:10BFA0000000000000000000000000000000000091
-:10BFB0000000000000000000000000000000000081
-:10BFC0000000000000000000000000000000000071
-:10BFD0000000000000000000000000000000000061
-:10BFE0000000000000000000000000000000000051
-:10BFF0000000000000000000000000000000000041
-:10C000000000000000000000000000000000000030
-:10C010000000000000000000000000000000000020
-:10C020000000000000000000000000000000000010
-:10C030000000000000000000000000000000000000
-:10C0400000000000000000000000000000000000F0
-:10C0500000000000000000000000000000000000E0
-:10C0600000000000000000000000000000000000D0
-:10C0700000000000000000000000000000000000C0
-:10C0800000000000000000000000000000000000B0
-:10C0900000000000000000000000000000000000A0
-:10C0A0000000000000000000000000000000000090
-:10C0B0000000000000000000000000000000000080
-:10C0C0000000000000000000000000000000000070
-:10C0D0000000000000000000000000000000000060
-:10C0E0000000000000000000000000000000000050
-:10C0F0000000000000000000000000000000000040
-:10C10000000000000000000000000000000000002F
-:10C11000000000000000000000000000000000001F
-:10C12000000000000000000000000000000000000F
-:10C1300000000000000000000000000000000000FF
-:10C1400000000000000000000000000000000000EF
-:10C1500000000000000000000000000000000000DF
-:10C1600000000000000000000000000000000000CF
-:10C1700000000000000000000000000000000000BF
-:10C1800000000000000000000000000000000000AF
-:10C19000000000000000000000000000000000009F
-:10C1A000000000000000000000000000000000008F
-:10C1B000000000000000000000000000000000007F
-:10C1C000000000000000000000000000000000006F
-:10C1D000000000000000000000000000000000005F
-:10C1E000000000000000000000000000000000004F
-:10C1F000000000000000000000000000000000003F
-:10C20000000000000000000000000000000000002E
-:10C21000000000000000000000000000000000001E
-:10C22000000000000000000000000000000000000E
-:10C2300000000000000000000000000000000000FE
-:10C2400000000000000000000000000000000000EE
-:10C2500000000000000000000000000000000000DE
-:10C2600000000000000000000000000000000000CE
-:10C2700000000000000000000000000000000000BE
-:10C2800000000000000000000000000000000000AE
-:10C29000000000000000000000000000000000009E
-:10C2A000000000000000000000000000000000008E
-:10C2B000000000000000000000000000000000007E
-:10C2C000000000000000000000000000000000006E
-:10C2D000000000000000000000000000000000005E
-:10C2E000000000000000000000000000000000004E
-:10C2F000000000000000000000000000000000003E
-:10C30000000000000000000000000000000000002D
-:10C31000000000000000000000000000000000001D
-:10C32000000000000000000000000000000000000D
-:10C3300000000000000000000000000000000000FD
-:10C3400000000000000000000000000000000000ED
-:10C3500000000000000000000000000000000000DD
-:10C3600000000000000000000000000000000000CD
-:10C3700000000000000000000000000000000000BD
-:10C3800000000000000000000000000000000000AD
-:10C39000000000000000000000000000000000009D
-:10C3A000000000000000000000000000000000008D
-:10C3B000000000000000000000000000000000007D
-:10C3C000000000000000000000000000000000006D
-:10C3D000000000000000000000000000000000005D
-:10C3E000000000000000000000000000000000004D
-:10C3F000000000000000000000000000000000003D
-:10C40000000000000000000000000000000000002C
-:10C41000000000000000000000000000000000001C
-:10C42000000000000000000000000000000000000C
-:10C4300000000000000000000000000000000000FC
-:10C4400000000000000000000000000000000000EC
-:10C4500000000000000000000000000000000000DC
-:10C4600000000000000000000000000000000000CC
-:10C4700000000000000000000000000000000000BC
-:10C4800000000000000000000000000000000000AC
-:10C49000000000000000000000000000000000009C
-:10C4A000000000000000000000000000000000008C
-:10C4B000000000000000000000000000000000007C
-:10C4C000000000000000000000000000000000006C
-:10C4D000000000000000000000000000000000005C
-:10C4E000000000000000000000000000000000004C
-:10C4F000000000000000000000000000000000003C
-:10C50000000000000000000000000000000000002B
-:10C51000000000000000000000000000000000001B
-:10C52000000000000000000000000000000000000B
-:10C5300000000000000000000000000000000000FB
-:10C5400000000000000000000000000000000000EB
-:10C5500000000000000000000000000000000000DB
-:10C5600000000000000000000000000000000000CB
-:10C5700000000000000000000000000000000000BB
-:10C5800000000000000000000000000000000000AB
-:10C59000000000000000000000000000000000009B
-:10C5A000000000000000000000000000000000008B
-:10C5B000000000000000000000000000000000007B
-:10C5C000000000000000000000000000000000006B
-:10C5D000000000000000000000000000000000005B
-:10C5E000000000000000000000000000000000004B
-:10C5F000000000000000000000000000000000003B
-:10C60000000000000000000000000000000000002A
-:10C61000000000000000000000000000000000001A
-:10C62000000000000000000000000000000000000A
-:10C6300000000000000000000000000000000000FA
-:10C6400000000000000000000000000000000000EA
-:10C6500000000000000000000000000000000000DA
-:10C6600000000000000000000000000000000000CA
-:10C6700000000000000000000000000000000000BA
-:10C6800000000000000000000000000000000000AA
-:10C69000000000000000000000000000000000009A
-:10C6A000000000000000000000000000000000008A
-:10C6B000000000000000000000000000000000007A
-:10C6C000000000000000000000000000000000006A
-:10C6D000000000000000000000000000000000005A
-:10C6E000000000000000000000000000000000004A
-:10C6F000000000000000000000000000000000003A
-:10C700000000000000000000000000000000000029
-:10C710000000000000000000000000000000000019
-:10C720000000000000000000000000000000000009
-:10C7300000000000000000000000000000000000F9
-:10C7400000000000000000000000000000000000E9
-:10C7500000000000000000000000000000000000D9
-:10C7600000000000000000000000000000000000C9
-:10C7700000000000000000000000000000000000B9
-:10C7800000000000000000000000000000000000A9
-:10C790000000000000000000000000000000000099
-:10C7A0000000000000000000000000000000000089
-:10C7B0000000000000000000000000000000000079
-:10C7C0000000000000000000000000000000000069
-:10C7D0000000000000000000000000000000000059
-:10C7E0000000000000000000000000000000000049
-:10C7F0000000000000000000000000000000000039
-:10C800000000000000000000000000000000000028
-:10C810000000000000000000000000000000000018
-:10C820000000000000000000000000000000000008
-:10C8300000000000000000000000000000000000F8
-:10C8400000000000000000000000000000000000E8
-:10C8500000000000000000000000000000000000D8
-:10C8600000000000000000000000000000000000C8
-:10C8700000000000000000000000000000000000B8
-:10C8800000000000000000000000000000000000A8
-:10C890000000000000000000000000000000000098
-:10C8A0000000000000000000000000000000000088
-:10C8B0000000000000000000000000000000000078
-:10C8C0000000000000000000000000000000000068
-:10C8D0000000000000000000000000000000000058
-:10C8E0000000000000000000000000000000000048
-:10C8F0000000000000000000000000000000000038
-:10C900000000000000000000000000000000000027
-:10C910000000000000000000000000000000000017
-:10C920000000000000000000000000000000000007
-:10C9300000000000000000000000000000000000F7
-:10C9400000000000000000000000000000000000E7
-:10C9500000000000000000000000000000000000D7
-:10C9600000000000000000000000000000000000C7
-:10C9700000000000000000000000000000000000B7
-:10C9800000000000000000000000000000000000A7
-:10C990000000000000000000000000000000000097
-:10C9A0000000000000000000000000000000000087
-:10C9B0000000000000000000000000000000000077
-:10C9C0000000000000000000000000000000000067
-:10C9D0000000000000000000000000000000000057
-:10C9E0000000000000000000000000000000000047
-:10C9F0000000000000000000000000000000000037
-:10CA00000000000000000000000000000000000026
-:10CA10000000000000000000000000000000000016
-:10CA20000000000000000000000000000000000006
-:10CA300000000000000000000000000000000000F6
-:10CA400000000000000000000000000000000000E6
-:10CA500000000000000000000000000000000000D6
-:10CA600000000000000000000000000000000000C6
-:10CA700000000000000000000000000000000000B6
-:10CA800000000000000000000000000000000000A6
-:10CA90000000000000000000000000000000000096
-:10CAA0000000000000000000000000000000000086
-:10CAB0000000000000000000000000000000000076
-:10CAC0000000000000000000000000000000000066
-:10CAD0000000000000000000000000000000000056
-:10CAE0000000000000000000000000000000000046
-:10CAF0000000000000000000000000000000000036
-:10CB00000000000000000000000000000000000025
-:10CB10000000000000000000000000000000000015
-:10CB20000000000000000000000000000000000005
-:10CB300000000000000000000000000000000000F5
-:10CB400000000000000000000000000000000000E5
-:10CB500000000000000000000000000000000000D5
-:10CB600000000000000000000000000000000000C5
-:10CB700000000000000000000000000000000000B5
-:10CB800000000000000000000000000000000000A5
-:10CB90000000000000000000000000000000000095
-:10CBA0000000000000000000000000000000000085
-:10CBB0000000000000000000000000000000000075
-:10CBC0000000000000000000000000000000000065
-:10CBD0000000000000000000000000000000000055
-:10CBE0000000000000000000000000000000000045
-:10CBF0000000000000000000000000000000000035
-:10CC00000000000000000000000000000000000024
-:10CC10000000000000000000000000000000000014
-:10CC20000000000000000000000000000000000004
-:10CC300000000000000000000000000000000000F4
-:10CC400000000000000000000000000000000000E4
-:10CC500000000000000000000000000000000000D4
-:10CC600000000000000000000000000000000000C4
-:10CC700000000000000000000000000000000000B4
-:10CC800000000000000000000000000000000000A4
-:10CC90000000000000000000000000000000000094
-:10CCA0000000000000000000000000000000000084
-:10CCB0000000000000000000000000000000000074
-:10CCC0000000000000000000000000000000000064
-:10CCD0000000000000000000000000000000000054
-:10CCE0000000000000000000000000000000000044
-:10CCF0000000000000000000000000000000000034
-:10CD00000000000000000000000000000000000023
-:10CD10000000000000000000000000000000000013
-:10CD20000000000000000000000000000000000003
-:10CD300000000000000000000000000000000000F3
-:10CD400000000000000000000000000000000000E3
-:10CD500000000000000000000000000000000000D3
-:10CD600000000000000000000000000000000000C3
-:10CD700000000000000000000000000000000000B3
-:10CD800000000000000000000000000000000000A3
-:10CD90000000000000000000000000000000000093
-:10CDA0000000000000000000000000000000000083
-:10CDB0000000000000000000000000000000000073
-:10CDC0000000000000000000000000000000000063
-:10CDD0000000000000000000000000000000000053
-:10CDE0000000000000000000000000000000000043
-:10CDF0000000000000000000000000000000000033
-:10CE00000000000000000000000000000000000022
-:10CE10000000000000000000000000000000000012
-:10CE20000000000000000000000000000000000002
-:10CE300000000000000000000000000000000000F2
-:10CE400000000000000000000000000000000000E2
-:10CE500000000000000000000000000000000000D2
-:10CE600000000000000000000000000000000000C2
-:10CE700000000000000000000000000000000000B2
-:10CE800000000000000000000000000000000000A2
-:10CE90000000000000000000000000000000000092
-:10CEA0000000000000000000000000000000000082
-:10CEB0000000000000000000000000000000000072
-:10CEC0000000000000000000000000000000000062
-:10CED0000000000000000000000000000000000052
-:10CEE0000000000000000000000000000000000042
-:10CEF0000000000000000000000000000000000032
-:10CF00000000000000000000000000000000000021
-:10CF10000000000000000000000000000000000011
-:10CF20000000000000000000000000000000000001
-:10CF300000000000000000000000000000000000F1
-:10CF400000000000000000000000000000000000E1
-:10CF500000000000000000000000000000000000D1
-:10CF600000000000000000000000000000000000C1
-:10CF700000000000000000000000000000000000B1
-:10CF800000000000000000000000000000000000A1
-:10CF90000000000000000000000000000000000091
-:10CFA0000000000000000000000000000000000081
-:10CFB0000000000000000000000000000000000071
-:10CFC0000000000000000000000000000000000061
-:10CFD0000000000000000000000000000000000051
-:10CFE0000000000000000000000000000000000041
-:10CFF0000000000000000000000000000000000031
-:10D000000000000000000000000000000000000020
-:10D010000000000000000000000000000000000010
-:10D020000000000000000000000000000000000000
-:10D0300000000000000000000000000000000000F0
-:10D0400000000000000000000000000000000000E0
-:10D0500000000000000000000000000000000000D0
-:10D0600000000000000000000000000000000000C0
-:10D0700000000000000000000000000000000000B0
-:10D0800000000000000000000000000000000000A0
-:10D090000000000000000000000000000000000090
-:10D0A0000000000000000000000000000000000080
-:10D0B0000000000000000000000000000000000070
-:10D0C0000000000000000000000000000000000060
-:10D0D0000000000000000000000000000000000050
-:10D0E0000000000000000000000000000000000040
-:10D0F0000000000000000000000000000000000030
-:10D10000000000000000000000000000000000001F
-:10D11000000000000000000000000000000000000F
-:10D1200000000000000000000000000000000000FF
-:10D1300000000000000000000000000000000000EF
-:10D1400000000000000000000000000000000000DF
-:10D1500000000000000000000000000000000000CF
-:10D1600000000000000000000000000000000000BF
-:10D1700000000000000000000000000000000000AF
-:10D18000000000000000000000000000000000009F
-:10D19000000000000000000000000000000000008F
-:10D1A000000000000000000000000000000000007F
-:10D1B000000000000000000000000000000000006F
-:10D1C000000000000000000000000000000000005F
-:10D1D000000000000000000000000000000000004F
-:10D1E000000000000000000000000000000000003F
-:10D1F000000000000000000000000000000000002F
-:10D20000000000000000000000000000000000001E
-:10D21000000000000000000000000000000000000E
-:10D2200000000000000000000000000000000000FE
-:10D2300000000000000000000000000000000000EE
-:10D2400000000000000000000000000000000000DE
-:10D2500000000000000000000000000000000000CE
-:10D2600000000000000000000000000000000000BE
-:10D2700000000000000000000000000000000000AE
-:10D28000000000000000000000000000000000009E
-:10D29000000000000000000000000000000000008E
-:10D2A000000000000000000000000000000000007E
-:10D2B000000000000000000000000000000000006E
-:10D2C000000000000000000000000000000000005E
-:10D2D000000000000000000000000000000000004E
-:10D2E000000000000000000000000000000000003E
-:10D2F000000000000000000000000000000000002E
-:10D30000000000000000000000000000000000001D
-:10D31000000000000000000000000000000000000D
-:10D3200000000000000000000000000000000000FD
-:10D3300000000000000000000000000000000000ED
-:10D3400000000000000000000000000000000000DD
-:10D3500000000000000000000000000000000000CD
-:10D3600000000000000000000000000000000000BD
-:10D3700000000000000000000000000000000000AD
-:10D38000000000000000000000000000000000009D
-:10D39000000000000000000000000000000000008D
-:10D3A000000000000000000000000000000000007D
-:10D3B000000000000000000000000000000000006D
-:10D3C000000000000000000000000000000000005D
-:10D3D000000000000000000000000000000000004D
-:10D3E000000000000000000000000000000000003D
-:10D3F000000000000000000000000000000000002D
-:10D40000000000000000000000000000000000001C
-:10D41000000000000000000000000000000000000C
-:10D4200000000000000000000000000000000000FC
-:10D4300000000000000000000000000000000000EC
-:10D4400000000000000000000000000000000000DC
-:10D4500000000000000000000000000000000000CC
-:10D4600000000000000000000000000000000000BC
-:10D4700000000000000000000000000000000000AC
-:10D48000000000000000000000000000000000009C
-:10D49000000000000000000000000000000000008C
-:10D4A000000000000000000000000000000000007C
-:10D4B000000000000000000000000000000000006C
-:10D4C000000000000000000000000000000000005C
-:10D4D000000000000000000000000000000000004C
-:10D4E000000000000000000000000000000000003C
-:10D4F000000000000000000000000000000000002C
-:10D50000000000000000000000000000000000001B
-:10D51000000000000000000000000000000000000B
-:10D5200000000000000000000000000000000000FB
-:10D5300000000000000000000000000000000000EB
-:10D5400000000000000000000000000000000000DB
-:10D5500000000000000000000000000000000000CB
-:10D5600000000000000000000000000000000000BB
-:10D5700000000000000000000000000000000000AB
-:10D58000000000000000000000000000000000009B
-:10D59000000000000000000000000000000000008B
-:10D5A000000000000000000000000000000000007B
-:10D5B000000000000000000000000000000000006B
-:10D5C000000000000000000000000000000000005B
-:10D5D000000000000000000000000000000000004B
-:10D5E000000000000000000000000000000000003B
-:10D5F000000000000000000000000000000000002B
-:10D60000000000000000000000000000000000001A
-:10D61000000000000000000000000000000000000A
-:10D6200000000000000000000000000000000000FA
-:10D6300000000000000000000000000000000000EA
-:10D6400000000000000000000000000000000000DA
-:10D6500000000000000000000000000000000000CA
-:10D6600000000000000000000000000000000000BA
-:10D6700000000000000000000000000000000000AA
-:10D68000000000000000000000000000000000009A
-:10D69000000000000000000000000000000000008A
-:10D6A000000000000000000000000000000000007A
-:10D6B000000000000000000000000000000000006A
-:10D6C000000000000000000000000000000000005A
-:10D6D000000000000000000000000000000000004A
-:10D6E000000000000000000000000000000000003A
-:10D6F000000000000000000000000000000000002A
-:10D700000000000000000000000000000000000019
-:10D710000000000000000000000000000000000009
-:10D7200000000000000000000000000000000000F9
-:10D7300000000000000000000000000000000000E9
-:10D7400000000000000000000000000000000000D9
-:10D7500000000000000000000000000000000000C9
-:10D7600000000000000000000000000000000000B9
-:10D7700000000000000000000000000000000000A9
-:10D780000000000000000000000000000000000099
-:10D790000000000000000000000000000000000089
-:10D7A0000000000000000000000000000000000079
-:10D7B0000000000000000000000000000000000069
-:10D7C0000000000000000000000000000000000059
-:10D7D0000000000000000000000000000000000049
-:10D7E0000000000000000000000000000000000039
-:10D7F0000000000000000000000000000000000029
-:10D800000000000000000000000000000000000018
-:10D810000000000000000000000000000000000008
-:10D8200000000000000000000000000000000000F8
-:10D8300000000000000000000000000000000000E8
-:10D8400000000000000000000000000000000000D8
-:10D8500000000000000000000000000000000000C8
-:10D8600000000000000000000000000000000000B8
-:10D8700000000000000000000000000000000000A8
-:10D880000000000000000000000000000000000098
-:10D890000000000000000000000000000000000088
-:10D8A0000000000000000000000000000000000078
-:10D8B0000000000000000000000000000000000068
-:10D8C0000000000000000000000000000000000058
-:10D8D0000000000000000000000000000000000048
-:10D8E0000000000000000000000000000000000038
-:10D8F0000000000000000000000000000000000028
-:10D900000000000000000000000000000000000017
-:10D910000000000000000000000000000000000007
-:10D9200000000000000000000000000000000000F7
-:10D9300000000000000000000000000000000000E7
-:10D9400000000000000000000000000000000000D7
-:10D9500000000000000000000000000000000000C7
-:10D9600000000000000000000000000000000000B7
-:10D9700000000000000000000000000000000000A7
-:10D980000000000000000000000000000000000097
-:10D990000000000000000000000000000000000087
-:10D9A0000000000000000000000000000000000077
-:10D9B0000000000000000000000000000000000067
-:10D9C0000000000000000000000000000000000057
-:10D9D0000000000000000000000000000000000047
-:10D9E0000000000000000000000000000000000037
-:10D9F0000000000000000000000000000000000027
-:10DA00000000000000000000000000000000000016
-:10DA100000000000000000000000000010000003F3
-:10DA2000000000000000000D0000000D3C02080096
-:10DA3000244275803C03080024637A28AC4000002F
-:10DA40000043202B1480FFFD244200043C1D0800ED
-:10DA500037BD7FFC03A0F0213C100800261031D810
-:10DA60003C1C0800279C75800E0010EF0000000091
-:10DA70000000000D30A5FFFF30C600FF27430180E6
-:10DA80008F4201B80440FFFE24020002AC64000093
-:10DA9000A4650008A066000AA062000B3C0210000A
-:10DAA000AC67001803E00008AF4201B83C03600017
-:10DAB0008C624FF80440FFFE3C020200AC644FC091
-:10DAC000AC624FC43C02100003E00008AC624FF8A7
-:10DAD0009482000C2486001400A038210002130256
-:10DAE000000210800082402100C8102B1040005717
-:10DAF0000000000090C300002C620009504000515B
-:10DB000090C20001000310803C03080024637534B8
-:10DB1000004310218C42000000400008000000007B
-:10DB200090C300012402000A1462003A00000000C1
-:10DB3000010610232C42000A1440003624C60002BD
-:10DB40008CE2000034420100ACE2000090C2000010
-:10DB500090C3000190C4000290C5000300031C00A4
-:10DB60000002160000431025000422000044102586
-:10DB70000045102524C60004ACE2000490C2000059
-:10DB800090C3000190C4000290C50003000216007B
-:10DB900000031C000043102500042200004410254F
-:10DBA0000045102524C600040A000CAAACE20008B7
-:10DBB00090C30001240200041462001624C600026F
-:10DBC00090C2000090C400018CE30000000212002B
-:10DBD000004410253463000424C60002ACE2000CAB
-:10DBE0000A000CAAACE3000090C300012402000369
-:10DBF0001462000824C600028CE2000090C30000FA
-:10DC000024C6000134420008A0E300100A000CAA58
-:10DC1000ACE2000003E000082402000190C3000110
-:10DC2000240200021062000224C40002010020212C
-:10DC30000A000CAA008030210A000CAA24C60001A8
-:10DC400090C200010A000CAA00C2302103E00008C3
-:10DC50000000102127BDFFE8AFBF0014AFB00010D7
-:10DC60000E00130E00808021936200052403FFFE46
-:10DC700002002021004310248FBF00148FB0001039
-:10DC8000A36200050A00131727BD001827BDFFE88F
-:10DC9000AFB00010AFBF00140E000F0E0080802147
-:10DCA0009362000024030050304200FF144300043C
-:10DCB00024020100AF4201800A000D22020020214F
-:10DCC000AF400180020020218FBF00148FB00010F0
-:10DCD0000A000FAD27BD001827BDFF80AFBE00783A
-:10DCE000AFB70074AFB30064AFBF007CAFB60070D5
-:10DCF000AFB5006CAFB40068AFB20060AFB1005C0C
-:10DD0000AFB000588F5001289363003F9362000525
-:10DD10000000F021307300FF0002102730420001A4
-:10DD20000000B82114400066AFA0005093420116D5
-:10DD300093430112304200FF306300FF0342202171
-:10DD400003431021244540008F82001C104000181E
-:10DD5000249140008F4201043C0300010043102441
-:10DD600010400013000000008CA3000C8F620030F4
-:10DD7000146201B5240200018CA300108F62002CF4
-:10DD8000146201B1240200019762003A94834000BA
-:10DD90003042FFFF146201AC240200019762003898
-:10DDA000962300023042FFFF146201A72402000103
-:10DDB00093620000304300FF24020020106200053F
-:10DDC0002402005010620006000000000A000D6CE2
-:10DDD000000000000000000D0A000D75AFA000302B
-:10DDE0003C1E080027DE75E80A000D75AFA0003064
-:10DDF0003C0208008C4200DC244200013C01080087
-:10DE0000AC2200DC0E0013D8000000000A000F0353
-:10DE10008FBF007C8F4201043C0300209234000D30
-:10DE2000004310240002202B00042140AFA4003046
-:10DE30008F4301043C020040006218241460000279
-:10DE4000348700400080382132820020AFA70030A4
-:10DE50001440000234E6008000E0302110C0000BC6
-:10DE6000AFA6003093C500088F67004C0200202148
-:10DE700000052B0034A5008130A5F0810E000C8D2B
-:10DE800030C600FF0A000F00000000009362003E51
-:10DE9000304200401040000E24020004566200068A
-:10DEA00024020012020020210E0014E6022030217C
-:10DEB0000A000F038FBF007C1662000500000000FF
-:10DEC0000E000D13000020210A000F038FBF007CFD
-:10DED0009743011A9624000E9362003532850004A0
-:10DEE0003076FFFF00442004AFA400548E320004BB
-:10DEF00010A000158E3500089362003E30420040AD
-:10DF000010400007000000000E00142802402021ED
-:10DF10001040000D000000000A000F00000000008B
-:10DF20008F620044024210230440014500000000BB
-:10DF30008F6200480242102304410141240400166C
-:10DF40000A000E038FC200048F62004802421023B1
-:10DF500004400008000000003C0208008C42310030
-:10DF6000244200013C010800AC2231000A000EF5F9
-:10DF7000000000008F620040024210231840000998
-:10DF80002402000C3C0208008C423100329400FC58
-:10DF90000000B021244200013C010800AC22310005
-:10DFA0002402000CAFA200308F62004000522023F8
-:10DFB0001880000D02C4102A144001160000000051
-:10DFC0001496000602C410233A8200013042000178
-:10DFD000144001100000000002C4102302449021EC
-:10DFE0000A000DEB3056FFFF0000202132820002B4
-:10DFF0001040001A328200109362003E304200400E
-:10E00000504000118FC200040E00130E02002021A8
-:10E0100024020018A362003F936200052403FFFE60
-:10E0200002002021004310240E001317A3620005F4
-:10E0300024040039000028210E00141124060018C1
-:10E040000A000F0224020001240400170040F8090E
-:10E05000000000000A000F0224020001104000F836
-:10E06000000000008F63004C8F62005402A2102356
-:10E070001C4000F302A31023044200010060A82109
-:10E08000AFA40018AFB20010AFB600149342012045
-:10E090008F6500409763003C304200FF034210212F
-:10E0A000004410218FA400543063FFFF244240003D
-:10E0B0000083182B8FA40030AFA20020AFA500284A
-:10E0C00000832025AFA40030AFA50024AFA0002C12
-:10E0D000AFB500349362003E30420008504000115A
-:10E0E0008FC200000220202127A500380E000CA4BA
-:10E0F000AFA000385440000B8FC200008FA2003840
-:10E1000030420100504000078FC200008FA3003C46
-:10E110008F6200600062102304430001AF6300605F
-:10E120008FC200000040F80927A400108FA2003021
-:10E130003042000254400001329400FE9362003EDF
-:10E1400030420040104000378FA300148F6200540B
-:10E1500016A2001A3282000124020014126200107A
-:10E160002A62001510400006240200162402000C4A
-:10E1700012620007328200010A000E5F00000000F8
-:10E1800012620005328200010A000E5F00000000EA
-:10E190000A000E5A2417000E0A000E5A2417001007
-:10E1A0000A000E5E24170012936200232403FFBDB1
-:10E1B00000431024A36200233282000110400019A2
-:10E1C0008FA300142402000C1262000E2A62000DBC
-:10E1D000104000062402000E2402000A126200070A
-:10E1E0008FA200240A000E77244200011262000868
-:10E1F0008FA200240A000E77244200010A000E7547
-:10E20000241700082402000E16E20002241700164C
-:10E21000241700108FA2002424420001AFA2002482
-:10E220008FA300148FA200248F730040004310219D
-:10E23000AF6200408FA20054936400368F630040A9
-:10E2400002A288213402FFFF00821004006218211C
-:10E25000AF6300488FA6003030C200081040000EA7
-:10E26000000000008F6200581622000430C600FF34
-:10E270009742011A5040000134C6001093C50008AF
-:10E280008FA700340200202100052B0034A5008058
-:10E290000E000C8D30A5F0808F62004000531023DB
-:10E2A000184000178FA200183C0208008C423198D9
-:10E2B00030420010104000092402000197620068FB
-:10E2C0001440000624020001A76200689742007A09
-:10E2D0002442000A0A000EBBA7620012A7620012C5
-:10E2E0000E00130E020020219362007D2403000122
-:10E2F00002002021344200010A000EB9AFA30050F1
-:10E300001840000A000000000E00130E0200202139
-:10E310009362007D2403000102002021AFA300507E
-:10E32000344200040E001317A362007D9362003E86
-:10E33000304200401440000C328200011040000ABC
-:10E34000000000008F6300408FC200042404001806
-:10E35000246300010040F809AF6300408FA2003041
-:10E360000A000F02304200048F6200581051001062
-:10E37000000000008F620018024210231C400008B9
-:10E38000240400018F6200181642000900000000FA
-:10E390008F62001C02A21023044000050000000050
-:10E3A000AF710058AFA40050AF720018AF75001CD9
-:10E3B00012E0000B8FA200500E00130E020020216D
-:10E3C000A377003F0E0013170200202102E0302146
-:10E3D000240400370E001411000028218FA20050E1
-:10E3E00010400003000000000E000C9B02002021E2
-:10E3F00012C00005000018218FA200303042000436
-:10E400005040001100601021240300010A000F0297
-:10E41000006010210E00130E020020219362007D87
-:10E4200002002021344200040E001317A362007D75
-:10E430000E000C9B020020210A000F0224020001A2
-:10E44000AF400044240200018FBF007C8FBE0078E3
-:10E450008FB700748FB600708FB5006C8FB40068F2
-:10E460008FB300648FB200608FB1005C8FB0005832
-:10E4700003E0000827BD00808F4201B80440FFFE82
-:10E4800024020800AF4201B803E0000800000000C9
-:10E4900030A5FFFF30C6FFFF8F4201B80440FFFEEA
-:10E4A0003C020008AF44018003421021AF44002029
-:10E4B000944200483044FFFF1080001924020003FA
-:10E4C00024A200120082102B104000152402000329
-:10E4D000934201202403001AA343018B304200FF22
-:10E4E0002447FFFE8F8200000087182B386300014D
-:10E4F0000002138200431024104000058F830004A3
-:10E5000034620001A74701940A000F39AF8200046A
-:10E510002402FFFE006210240A000F39AF820004BB
-:10E52000A342018B24020002A742018C8F820000CB
-:10E530008F840004A745018EA74201908F82000CB2
-:10E5400030838000AF4201A8A74601881060000E0A
-:10E550008F82000493420116304200FC24420004E2
-:10E56000005A10218C4240003042FFFF1440000648
-:10E570008F8200043C02FFFF34427FFF00821024A0
-:10E58000AF8200048F8200042403BFFF978400023F
-:10E5900000431024A74201A69742010C0002140078
-:10E5A00000441025AF4201AC3C021000AF4201B85C
-:10E5B00003E00008000000008F4700709342011242
-:10E5C0008F83000027BDFFF0304200FF0002288249
-:10E5D00030620100000030211040004324A40003F9
-:10E5E00030624000104000103062200000041080B3
-:10E5F000005A10218C43400024A400040004108021
-:10E60000AFA30000005A10218C424000AFA20004CA
-:10E6100093420116304200FC005A10218C42400007
-:10E620000A000F86AFA200081040002F0000302122
-:10E6300000041080005A10218C43400024A40004E0
-:10E6400000041080AFA30000005A10218C4240004B
-:10E65000AFA00008AFA200048FA80008000030217E
-:10E6600000002021240A00083C0908002529010097
-:10E6700003A41021148A000300042A001100000AD8
-:10E680000000000090420000248400012C83000C54
-:10E6900000A2102100021080004910218C420000CD
-:10E6A0001460FFF300C230263C0408008C8431045F
-:10E6B0008F4200702C83002010600009004738232F
-:10E6C0003C0308002463310800041080004310213B
-:10E6D00024830001AC4700003C010800AC23310456
-:10E6E000AF86000C2406000100C0102103E00008E2
-:10E6F00027BD00103C0208008C42003827BDFFD027
-:10E70000AFB60028AFB40020AFB20018AFBF002CE6
-:10E71000AFB50024AFB3001CAFB10014AFB0001010
-:10E72000000090213C16080026D600381440000254
-:10E730002454FFFF0000A0219742010E8F840000A7
-:10E740003042FFFF308340001060000A2453000471
-:10E750003C020020008210245040000730828000DC
-:10E760008F8200042403BFFF008318240A000FD700
-:10E7700034421000308280001040000A3C02002029
-:10E7800000821024104000078F8200043C03FFFF2A
-:10E7900034637FFF0083182434428000AF8200047A
-:10E7A000AF8300000E000F5E000000001440000761
-:10E7B000000000009743011E9742011C3063FFFFD9
-:10E7C0000002140000621825AF83000C9742010C70
-:10E7D0008F4340003046FFFF3402FFFF1462000306
-:10E7E000000000000A000FEF241200208F424000BA
-:10E7F0003042010054400001241200108F840000B8
-:10E800003082100050400014365200013082002047
-:10E810001440000B3C021000008210245040000EF7
-:10E82000365200013C030E003C020DFF0083182409
-:10E830003442FFFF0043102B5040000736520001C6
-:10E840003C0208008C42002C244200013C010800DC
-:10E85000AC22002C365200053C0508008CA5003483
-:10E8600054A000408F8400008F8200105440003D6F
-:10E870008F8400008F8200043042400054400039F1
-:10E880008F8400003C021F01008210243C03100012
-:10E89000144300348F84000030C202001440003260
-:10E8A0003C0200013265FFFF364600028F4201B88C
-:10E8B0000440FFFE3C020008AF40018003421021EB
-:10E8C000944200483043FFFF10600019AF830008F6
-:10E8D00024A200120062102B104000162402000334
-:10E8E000934201202403001AA343018B304200FF0E
-:10E8F0002443FFFE8F820000304240001040000899
-:10E900008F8200048F8200080043102B1440000403
-:10E910008F820004A74301940A00103A3442000198
-:10E920002403FFFE004310240A00103EAF820004BF
-:10E9300024020003A342018B8F8300042402BFFF43
-:10E940000062182424020002A742018C8F8200007A
-:10E95000A745018EA7460188A74301A60A0010D942
-:10E96000A74201903C020001008210241040000BDD
-:10E970003C0210003C0208008C4200D89745010E72
-:10E98000240400802442000130A5FFFF3C01080060
-:10E99000AC2200D80A0010E22406000300821024F2
-:10E9A00010400041000000003C0208008C42003092
-:10E9B0001040000C8F8200043042400010400009DB
-:10E9C0003C030F00008318243C0201000043102B7D
-:10E9D00014400004364600023265FFFF0A0010E2D0
-:10E9E0002404008010A0000D308201001040000BB4
-:10E9F0003C020F00008210243C0302001043000779
-:10EA00008F82000C00541024005610219042000404
-:10EA1000244200040A001097000221C000000000F8
-:10EA20008F8600003C0508008CA500D00006160269
-:10EA30003050000F38A200012C4200012E03000CC0
-:10EA40000043102414400015001021C02602FFFCD2
-:10EA50002C420004544000110000202138A2000282
-:10EA60002C42000100431024104000030006124213
-:10EA70000A001097000020210010182B00431024DA
-:10EA800050400006001021C0000020213265FFFF29
-:10EA90000E000F143246FFFB001021C03265FFFF4D
-:10EAA0000A0010E2364600028F4240003C11080086
-:10EAB0008E310024304201001040003E322200011D
-:10EAC0000220802110A00014325500043082010081
-:10EAD00010400012240200013C020F0000821024AA
-:10EAE0003C0302001043000C8F82000C02403021D6
-:10EAF0003265FFFF0054102400561021904400049A
-:10EB00003252FFFB248400040E000F14000421C0C5
-:10EB10002402FFFE022280242402000116020007C4
-:10EB2000320200013242000450400001365200021D
-:10EB30003265FFFF0A0010E102403021104000075B
-:10EB40003202000402403021000020210E000F1488
-:10EB50003265FFFF3252FFFB320200041040000713
-:10EB60008F82000030420800104000043265FFFF31
-:10EB7000024030210E000F142404010016A00015DD
-:10EB80008FBF002C274301808F4201B80440FFFE55
-:10EB900024022000A462000824020002A062000BEC
-:10EBA000A46000103C021000AF4201B80A0010E55A
-:10EBB0008FBF002C104000078FBF002C3265FFFF75
-:10EBC00036460002000020210E000F140000000055
-:10EBD0008FBF002C8FB600288FB500248FB4002083
-:10EBE0008FB3001C8FB200188FB100148FB00010CB
-:10EBF0000000102103E0000827BD003027BDFFC83A
-:10EC0000AFB000103C04600CAFBF0030AFB7002CB9
-:10EC1000AFB60028AFB50024AFB40020AFB3001CDE
-:10EC2000AFB20018AFB100148C8250002403FF7FF4
-:10EC30003C1A8000004310243442380CAC8250004F
-:10EC4000240200033C106000AF4200088E02080856
-:10EC50003C1B80083C010800AC2000203042FFF043
-:10EC6000384200102C4200010E001C46AF82001CEE
-:10EC70003C04FFFF3C020400348308063442000CCD
-:10EC8000AE021948AE03194C3C0560168E0219807D
-:10EC90008CA300003442020000641824AE021980E4
-:10ECA0003C0253531462000334A47C008CA2000481
-:10ECB000005020218C82007C8C830078AF82001869
-:10ECC000AF8300143C028000344200708C4300008B
-:10ECD00000403821AF830020006030218CE8000024
-:10ECE0003C0508008CA500FC3C0408008C8400F85E
-:10ECF000010630230000102100A6282100A6302B99
-:10ED000000822021008620213C010800AC2500FC67
-:10ED10003C010800AC2400F88F56000032C200030A
-:10ED20001040FFEE010030218CE600003C05080099
-:10ED30008CA500FC3C0408008C8400F800C830233B
-:10ED400000A628210000102100A6302B00822021DF
-:10ED50000086202132C700013C010800AC2500FCE0
-:10ED6000AF8800203C010800AC2400F810E0016BE3
-:10ED700032C200028F4301283C02000803421021E6
-:10ED8000AF4300208F4301048F44010094420048A8
-:10ED9000AF830000AF8400043042FFFF0E000F0E6F
-:10EDA000AF8200083C0208008C4200C010400008FE
-:10EDB0008F8400003C0208008C4200C42442000101
-:10EDC0003C010800AC2200C40A0012AF00000000A1
-:10EDD0003C02001000821024144001358F8300048F
-:10EDE0003C0208008C4200203C0308008C63003881
-:10EDF00000009021244200013C010800AC220020C8
-:10EE00003C17080026F70038146000022474FFFF46
-:10EE10000000A0219742010E308340003042FFFFE6
-:10EE20001060000A245300043C02002000821024D9
-:10EE300050400007308280008F8200042403BFFF0F
-:10EE4000008318240A00118D3442100030828000A3
-:10EE50001040000A3C0200200082102410400007ED
-:10EE60008F8200043C03FFFF34637FFF008318247C
-:10EE700034428000AF820004AF8300000E000F5EBA
-:10EE80000000000014400007000000009743011E2E
-:10EE90009742011C3063FFFF000214000062182536
-:10EEA000AF83000C9742010C8F4340003046FFFFB8
-:10EEB0003402FFFF14620003000000000A0011A5E5
-:10EEC000241200208F4240003042010054400001D3
-:10EED000241200108F840000308210005040001473
-:10EEE00036520001308200201440000B3C0210001A
-:10EEF000008210245040000E365200013C030E00E8
-:10EF00003C020DFF008318243442FFFF0043102B06
-:10EF100050400007365200013C0208008C42002C91
-:10EF2000244200013C010800AC22002C36520005AE
-:10EF30003C0508008CA5003454A000408F840000DC
-:10EF40008F8200105440003D8F8400008F820004A7
-:10EF500030424000544000398F8400003C021F01C1
-:10EF6000008210243C031000144300348F840000FE
-:10EF700030C20200144000323C0200013265FFFF43
-:10EF8000364600028F4201B80440FFFE3C020008F2
-:10EF9000AF40018003421021944200483043FFFFFC
-:10EFA00010600019AF83000824A200120062102B29
-:10EFB0001040001624020003934201202403001A8B
-:10EFC000A343018B304200FF2443FFFE8F820000E9
-:10EFD00030424000104000088F8200048F820008F9
-:10EFE0000043102B144000048F820004A7430194B7
-:10EFF0000A0011F0344200012403FFFE00431024F4
-:10F000000A0011F4AF82000424020003A342018B22
-:10F010008F8300042402BFFF006218242402000230
-:10F02000A742018C8F820000A745018EA746018868
-:10F03000A74301A60A00128FA74201903C020001DB
-:10F04000008210245040000B3C0210003C020800DB
-:10F050008C4200D89745010E240400802442000110
-:10F0600030A5FFFF3C010800AC2200D80A0012982E
-:10F07000240600030082102410400041000000001C
-:10F080003C0208008C4200301040000C8F820004CB
-:10F0900030424000104000093C030F000083182458
-:10F0A0003C0201000043102B1440000436460002CD
-:10F0B0003265FFFF0A0012982404008010A0000DA2
-:10F0C000308201001040000B3C020F00008210242F
-:10F0D0003C030200104300078F82000C00541024F0
-:10F0E0000057102190420004244200040A00124DEF
-:10F0F000000221C0000000008F8600003C050800CF
-:10F100008CA500D0000616023050000F38A2000176
-:10F110002C4200012E03000C004310241440001563
-:10F12000001021C02602FFFC2C42000454400011B4
-:10F130000000202138A200022C42000100431024CC
-:10F1400050400003000612420A00124D0000202128
-:10F150000010182B0043102450400006001021C05E
-:10F16000000020213265FFFF0E000F143246FFFB26
-:10F17000001021C03265FFFF0A00129836460002D7
-:10F180008F4240003C1108008E31002430420100C3
-:10F190001040003E322200010220802110A0001405
-:10F1A0003255000430820100104000122402000198
-:10F1B0003C020F00008210243C0302001043000CAC
-:10F1C0008F82000C024030213265FFFF0054102472
-:10F1D00000571021904400043252FFFB24840004A5
-:10F1E0000E000F14000421C02402FFFE022280241E
-:10F1F000240200011602000732020001324200041C
-:10F2000050400001365200023265FFFF0A0012979B
-:10F210000240302110400007320200040240302139
-:10F22000000020210E000F143265FFFF3252FFFB59
-:10F2300032020004104000078F82000030420800B4
-:10F24000104000043265FFFF024030210E000F1411
-:10F250002404010016A0002E3C0240002743018038
-:10F260008F4201B80440FFFE24022000A46200087F
-:10F2700024020002A062000BA46000103C021000F7
-:10F28000AF4201B80A0012B43C02400050400020D6
-:10F290003C0240003265FFFF36460002000020219C
-:10F2A0000E000F14000000000A0012B43C024000DF
-:10F2B0002402BFFF0062102410400008000000007C
-:10F2C000240287FF00621024144000083C02006002
-:10F2D0000082102410400005000000000E000D26E2
-:10F2E000000000000A0012AD000000000E0012F83D
-:10F2F00000000000104000063C0240008F43012443
-:10F300003C026020AC430014000000003C024000BE
-:10F31000AF4201380000000032C200021040FE6A15
-:10F320003C0280008F4201403C044000AF4200207C
-:10F330008F4301483C027000006218241064002DC5
-:10F34000000000000083102B144000063C02600007
-:10F350003C022000106200073C0240000A0012F448
-:10F360000000000010620027000000000A0012F4F4
-:10F370003C0240008F4201482403000400021402B2
-:10F38000304200FF1443000B274401808F430140AB
-:10F390008F4201B80440FFFE2402001CAC83000031
-:10F3A000A082000B3C021000AF4201B80A0012F428
-:10F3B0003C0240008F4201B80440FFFE0000000004
-:10F3C0008F42014800021402A482000824020002B5
-:10F3D000A082000B8F420148A48200108F4201449A
-:10F3E000AC8200243C021000AF4201B80A0012F4C3
-:10F3F0003C0240000E00131C000000000A0012F442
-:10F400003C0240000E001C53000000003C02400083
-:10F41000AF420178000000000A0011223C02800087
-:10F420008F4201003042003E1440001124020001CE
-:10F43000AF4000488F420100304207C01040000535
-:10F4400000000000AF40004CAF40005003E0000857
-:10F4500024020001AF400054AF4000408F42010041
-:10F460003042380054400001AF4000442402000103
-:10F4700003E00008000000003C029000344200015C
-:10F4800000822025AF4400208F4200200440FFFE70
-:10F490000000000003E00008000000003C028000C3
-:10F4A000344200010082202503E00008AF44002020
-:10F4B00027BDFFE0AFB20018AFBF001CAFB1001412
-:10F4C000AFB000108F5001408F5101483C028000C6
-:10F4D0000011940202222024324300FF2402000E75
-:10F4E0001062008A2862000F104000122862003764
-:10F4F000240200061062003B28620007104000074B
-:10F50000240200091060001A240200011062002584
-:10F51000000000000A0013D1000000001062007B10
-:10F520002402000B1062005B3222FFFF0A0013D19D
-:10F530000000000010400008240200382862003556
-:10F54000104000802402001F1062007E00000000B6
-:10F550000A0013D1000000001062007A240200802B
-:10F5600010620042000000000A0013D100000000F9
-:10F570008F4201B80440FFFE24020001AF50018019
-:10F58000AF400184A7520188A342018A24020002ED
-:10F59000A342018BA75101908F4201440A0013CC72
-:10F5A000AF4201A41080000A240200023C010800BE
-:10F5B000A02275D83C010800AC3075E08F420144B0
-:10F5C0003C010800AC2275DC0A0013D38FBF001C7D
-:10F5D0008F4201B80440FFFE240200020A0013B665
-:10F5E000000000008F4201B80440FFFE0000000050
-:10F5F000AF5001803C020800904275D810400003D3
-:10F60000000018213C0308008C6375E0AF430184BF
-:10F61000A75201883C020800904275D800001821CA
-:10F6200034420001A342018A24020002A342018B5A
-:10F63000A75101908F420144AF4201A43C0208004F
-:10F64000904275D8104000033C0210003C030800B3
-:10F650008C6375DCAF4301A8AF4201B83C010800E0
-:10F66000A02075D80A0013D38FBF001C8F4201B8A9
-:10F670000440FFFE24020002A342018BA75201882E
-:10F68000A75101908F420144A74201920A0013CE74
-:10F690003C0210001440001D0000000093620005B1
-:10F6A0003042000414400037000000000E00130E2A
-:10F6B0000200202193620005020020213442000450
-:10F6C0000E001317A3620005936200053042000488
-:10F6D00014400002000000000000000D93620000D2
-:10F6E00024030020304200FF144300080000000003
-:10F6F0008F4201B80440FFFE24020005AF50018094
-:10F70000A342018B3C021000AF4201B88F4201B806
-:10F710000440FFFE24020002AF400180AF5001848C
-:10F72000A7520188A342018AA342018BA7510190ED
-:10F73000AF4001A48F420144AF4201A80A0013CE9A
-:10F740003C0210008F4201B80440FFFE2402000179
-:10F75000AF500180AF400184A7520188A342018AC3
-:10F7600024020002A342018BA7510190AF4001A4E3
-:10F77000AF4001A83C021000AF4201B80A0013D309
-:10F780008FBF001C0000000D8FBF001C8FB200183F
-:10F790008FB100148FB0001003E0000827BD0020D7
-:10F7A00027BDFFE8AFBF00100E000F0E00000000E5
-:10F7B000AF4001808FBF0010000020210A000FAD74
-:10F7C00027BD00183084FFFF30A5FFFF000018217F
-:10F7D000108000070000000030820001104000028D
-:10F7E00000042042006518210A0013E400052840A7
-:10F7F00003E000080060102110C0000624C6FFFFCF
-:10F800008CA2000024A50004AC8200000A0013EEC4
-:10F810002484000403E000080000000010A0000899
-:10F8200024A3FFFFAC8600000000000000000000E1
-:10F830002402FFFF2463FFFF1462FFFA2484000404
-:10F8400003E000080000000027BDFFE8AFBF001480
-:10F85000AFB000100E00130E008080219362007D77
-:10F8600002002021344200200E001317A362007D05
-:10F87000020020218FBF00148FB000100A000C9BE3
-:10F8800027BD0018308300FF30A500FF30C600FF01
-:10F89000274701808F4201B80440FFFE00000000AE
-:10F8A0008F42012834634000ACE2000024020001D2
-:10F8B000ACE00004A4E30008A0E2000A2402000275
-:10F8C000A0E2000B3C021000A4E50010ACE0002414
-:10F8D000ACE00028A4E6001203E00008AF4201B843
-:10F8E00027BDFFE8AFBF00109362003F2403001262
-:10F8F000304200FF1043000D008030218F62004431
-:10F90000008210230440000A8FBF00108F6200485D
-:10F91000240400390000282100C2102304410004FF
-:10F92000240600120E001411000000008FBF00100A
-:10F930002402000103E0000827BD001827BDFFC80E
-:10F94000AFB1002C00A08821AFB2003027A5001075
-:10F950000080902102202021AFBF0034AFB00028EA
-:10F960000E000CA4AFA0001010400009024020219E
-:10F970008E220008AF6200840E001402AF600040C7
-:10F98000240400382405008D0A0014DD240600122A
-:10F990009362003E304200081040000F8FA200101A
-:10F9A00030420100104000078FA300148F620060F6
-:10F9B0000062102304430008AF6300600A0014666D
-:10F9C00000000000AF6000609362003E2403FFF778
-:10F9D00000431024A362003E9362003E30420008C0
-:10F9E000144000022406000300003021936200341A
-:10F9F000936300378F640084304200FF306300FF60
-:10FA000000661821000318800043282100A4202B41
-:10FA10001080000B000000009763003C8F620084A0
-:10FA20003063FFFF004510230062182B14600004B0
-:10FA3000000000008F6200840A00148200458023C9
-:10FA40009762003C3050FFFF8FA30010306200042B
-:10FA500010400004000628808FA2001C0A00148AAF
-:10FA60000202102B2E02021850400003240202183A
-:10FA70000A00149302051023306300041060000391
-:10FA8000004510238FA2001C004510230040802158
-:10FA90002C42008054400001241000800E00130E00
-:10FAA0000240202124020001AF62000C9362003E5C
-:10FAB000001020403042007FA362003E8E220004EE
-:10FAC00024420001AF620040A770003C8F620050EA
-:10FAD0009623000E00431021AF6200588F62005041
-:10FAE00000441021AF62005C8E220004AF62001857
-:10FAF0008E220008AF62001C8FA200103042000866
-:10FB00005440000A93A20020A3600036936200369E
-:10FB10002403FFDFA36200359362003E00431024FC
-:10FB2000A362003E0A0014BD8E220008A3620035C5
-:10FB30008E220008AF62004C8F6200248F63004069
-:10FB400000431021AF62004893620000240300507C
-:10FB5000304200FF144300122403FF803C020800DF
-:10FB60008C4231A00242102100431024AF420028F1
-:10FB70003C0208008C4231A08E2400083C03000C9B
-:10FB8000024210213042007F034210210043102125
-:10FB9000AC4400D88E230008AF820028AC4300DCC0
-:10FBA0000E001317024020212404003800002821F1
-:10FBB0002406000A0E001411000000008FBF00345C
-:10FBC0008FB200308FB1002C8FB0002824020001CA
-:10FBD00003E0000827BD003827BDFFE8AFBF0010D5
-:10FBE00090C7000D00C0282130E6001010C0000AA8
-:10FBF00030E200058CA300088F62005410620006FA
-:10FC000030E20005144000178FBF001000002021D3
-:10FC10000A000D1327BD00181040000D30E300123C
-:10FC200010C000108FBF00108CA300088F6200541A
-:10FC30001462000D24020001240400382405008D04
-:10FC40000E001411240600120A0015098FBF0010BF
-:10FC500024020012146200038FBF00100A00143F38
-:10FC600027BD00182402000103E0000827BD00188A
-:10FC700027BDFFF827420180AFA20000308A00FFB5
-:10FC80008F4201B80440FFFE000000008F460128AB
-:10FC90003C0208008C4231A02403FF80AF86005054
-:10FCA00000C2102100431024AF4200243C0208008F
-:10FCB0008C4231A08FA900008FA8000000C2102143
-:10FCC0003042007F034218213C02000A00621821E2
-:10FCD000946400D48FA700008FA5000024020002C6
-:10FCE000AF830028A0A2000B8FA300003542600064
-:10FCF0003084FFFFA4E200083C021000AD260000A3
-:10FD0000AD040004AC60002427BD0008AF4201B878
-:10FD100003E00008240200018C8200048F83002885
-:10FD200000451023AC820004906200633042007FE3
-:10FD3000A06200638C820020938300308F850028AE
-:10FD400034420002AF830044A7800042AC8200200E
-:10FD5000A4A000E490A200632403FFBF004310248A
-:10FD600003E00008A0A20063274301808F4201B88E
-:10FD70000440FFFE8F820050AC6200008F420124DD
-:10FD8000AC62000424026083A46200082402000222
-:10FD9000A062000B3C02100003E00008AF4201B873
-:10FDA0008F880044938200308F8300283C0708002E
-:10FDB00024E779F400481023304200FF304900FC6A
-:10FDC000246500888F860048304A0003112000090E
-:10FDD00000002021248200048CA30000304400FF96
-:10FDE0000089102AACE3000024A500041440FFF9A8
-:10FDF00024E70004114000090000202124820001B2
-:10FE000090A30000304400FF008A102BA0E3000004
-:10FE100024A500011440FFF924E7000130C20003CB
-:10FE2000144000048F850044310200031040000D8F
-:10FE30000000000010A00009000020212482000121
-:10FE400090C30000304400FF0085102BA0E30000A9
-:10FE500024C600011440FFF924E7000103E0000874
-:10FE6000000000001100FFFD00002021248200049A
-:10FE70008CC30000304400FF0088102BACE300006E
-:10FE800024C600041440FFF924E7000403E000083E
-:10FE9000000000008F8300449382003030C600FFD2
-:10FEA00030A500FF00431023304300FF8F8200285D
-:10FEB000008038210043102114C00002244800882B
-:10FEC0000083382130E200031440000530A2000313
-:10FED00014400003306200031040000D00000000D9
-:10FEE00010A00009000020212482000190E30000FE
-:10FEF000304400FF0085102BA103000024E700011F
-:10FF00001440FFF92508000103E00008000000008C
-:10FF100010A0FFFD00002021248200048CE30000DB
-:10FF2000304400FF0085102BAD03000024E70004DF
-:10FF30001440FFF92508000403E000080000000059
-:10FF400027BDFFF82402FFFFAFA200000080382188
-:10FF50002405002F3C090800252975F4240800FF1A
-:10FF60002406FFFF90E2000024A3FFFF0006220208
-:10FF700000C21026304200FF00021080004910210C
-:10FF80008C420000306500FF24E7000114A8FFF553
-:10FF90000082302600061027AFA20004AFA20000A6
-:10FFA0000000282127A6000400C510239044000368
-:10FFB00024A2000100BD1821304500FF2CA200043E
-:10FFC0001440FFF9A06400008FA2000003E00008C5
-:10FFD00027BD00080080482130AAFFFF30C600FF7F
-:10FFE00030E7FFFF274801808F4201B80440FFFE41
-:10FFF0008F820050AD0200008F420124AD02000448
-:020000040001F9
-:100000008D220020A5070008A102000A2402001684
-:10001000A102000B934301208D2200088D240004CF
-:10002000306300FF004310219783004200441021F9
-:100030008D250024004310233C0308008C6331A06D
-:100040008F840028A502000C246300E82402FFFF2F
-:10005000A50A000EA5030010A5060012AD050018A4
-:10006000AD020024948201142403FFF73042FFFF05
-:10007000AD0200288C820118AD02002C3C02100059
-:10008000AD000030AF4201B88D22002000431024A3
-:1000900003E00008AD2200208F82002830E7FFFF38
-:1000A00000804821904200D330A5FFFF30C600FFFA
-:1000B0000002110030420F0000E23825274801807D
-:1000C0008F4201B80440FFFE8F820050AD02000055
-:1000D0008F420124AD0200048D220020A5070008F4
-:1000E000A102000A24020017A102000B9343012081
-:1000F0008D2200088D240004306300FF004310218E
-:1001000097830042004410218F840028004310236D
-:100110003C0308008C6331A0A502000CA505000E6D
-:10012000246300E8A5030010A5060012AD0000142A
-:100130008D220024AD0200188C82005CAD02001CF0
-:100140008C820058AD0200202402FFFFAD02002483
-:10015000948200E63042FFFFAD02002894820060E6
-:10016000948300BE30427FFF3063FFFF0002120025
-:1001700000431021AD02002C3C021000AD00003005
-:10018000AF4201B8948200BE2403FFF700A2102101
-:10019000A48200BE8D2200200043102403E000084A
-:1001A000AD220020274301808F4201B80440FFFEAA
-:1001B00024020018AC640000A062000B8F820028AB
-:1001C000944200E6A46200103C021000AC600030D3
-:1001D00003E00008AF4201B8274301808F4201B815
-:1001E0000440FFFE8F82002C9442001C3042FFFF2F
-:1001F000000211C0AC62000024020019A062000BD2
-:100200003C021000AC60003003E00008AF4201B8CF
-:100210008F87003430C300FF8F4201B80440FFFED7
-:100220008F82005034636000ACA200009382004CC7
-:10023000A0A200058CE20010A4A20006A4A300085E
-:100240008C8200202403FFF7A0A2000A24020002EF
-:10025000A0A2000B8CE20000ACA200108CE2000413
-:10026000ACA200148CE2001CACA200248CE20020A2
-:10027000ACA200288CE2002CACA2002C8C820024C2
-:10028000ACA200183C021000AF4201B88C820020E2
-:100290000043102403E00008AC8200209382004C4D
-:1002A0002403000127BDFFE8004330042C42002056
-:1002B000AFB00010AFBF00142410FFFE10400005C7
-:1002C000274501803C0208008C4231900A0016A8A4
-:1002D000004610243C0208008C4231940046102451
-:1002E00014400007240600848F8300282410FFFF99
-:1002F000906200623042000F34420040A06200620F
-:100300000E00167400000000020010218FBF0014C0
-:100310008FB0001003E0000827BD00188F83002C69
-:1003200027BDFFE0AFB20018AFB10014AFB00010AE
-:10033000AFBF001C9062000D00A0902130D100FFE3
-:100340003042007FA062000D8F8500288E43001888
-:10035000008080218CA2007C146200052402000E23
-:1003600090A20063344200200A0016D1A0A20063CC
-:100370000E001697A382004C2403FFFF1043004792
-:100380002404FFFF52200045000020218E4300007E
-:100390003C02001000621024504000043C0200089F
-:1003A000020020210A0016E0240200150062102439
-:1003B000504000098E450000020020212402001454
-:1003C0000E001697A382004C2403FFFF1043003356
-:1003D0002404FFFF8E4500003C02000200A210240E
-:1003E000104000163C0200048F86002C8CC20014C2
-:1003F0008CC300108CC40014004310230044102B45
-:1004000050400005020020218E43002C8CC20010B9
-:1004100010620003020020210A00171124020012BA
-:100420003C02000400A210245040001C00002021C7
-:10043000020020210A0017112402001300A2102438
-:10044000104000068F83002C8C6200105040001377
-:10045000000020210A00170B020020218C620010EE
-:10046000504000048E42002C020020210A00171187
-:100470002402001150400009000020210200202128
-:10048000240200170E001697A382004C2403FFFFDE
-:10049000104300022404FFFF000020218FBF001C36
-:1004A0008FB200188FB100148FB00010008010219F
-:1004B00003E0000827BD00209383003027BDFFE044
-:1004C00024020034AFB20018AFB10014AFBF001C5B
-:1004D000AFB00010008088211462000C00A09021B1
-:1004E0008F8400340E0015C08C900030120200077B
-:1004F00024020005022020210E001697A382004C42
-:100500002403FFFF104300602404FFFF9242000415
-:10051000104000098F820028022020212402000CB4
-:100520000E001697A382004C2403FFFF10430056D1
-:100530002404FFFF8F820028A38000248E43000440
-:100540008C4400803C0200FF3442FFFF006218240C
-:100550000083202B10800008AF83003C0220202164
-:10056000240200190E001697A382004C2403FFFFFB
-:10057000104300452404FFFF978200428F87004408
-:100580008F85003C0047202310A0003AA78400423A
-:100590008F86002830A200030002102390C300BC05
-:1005A0003050000300B02821000318823071000190
-:1005B0000011108000A228213C0308008C6331A0A8
-:1005C0008F8200503084FFFF0085202B00431021D4
-:1005D00010800010244200888F8400341082000DA7
-:1005E0003C033F018E420000004310243C032500E1
-:1005F0001443000630E500FF8C820000ACC2008886
-:100600008C8200100A001775ACC200980E00159578
-:1006100000003021938200248F8500288F830048BA
-:10062000020238218F820044A387002494A400E4AE
-:10063000006218218F82003C34841000AF83004890
-:1006400000503021A4A400E41220000EAF86004424
-:1006500024E20004A382002494A200E424C3000442
-:10066000AF83004434422000A4A200E40A001792A1
-:10067000000020218F820048AF80004400471021F5
-:10068000AF820048000020218FBF001C8FB20018ED
-:100690008FB100148FB000100080102103E000081B
-:1006A00027BD00208F86002827BDFFE8AFBF0014BC
-:1006B000AFB0001090C2006330420020104000082C
-:1006C00030A500FF8CC2007C2403FFDF2442000120
-:1006D000ACC2007C90C2006300431024A0C200633F
-:1006E00010A000238F8300282750018002002821BA
-:1006F0000E001674240600828F8200289042006348
-:100700003042004050400019A380004C8F830034D9
-:100710008F4201B80440FFFE8F820050AE020000FD
-:1007200024026082A602000824020002A202000B3A
-:100730008C620008AE0200108C62000CAE02001445
-:100740008C620014AE0200188C620018AE02002405
-:100750008C620024AE0200288C620028AE02002CBD
-:100760003C021000AF4201B8A380004C8F830028E8
-:100770008FBF00148FB000109062006327BD001877
-:100780003042007FA0620063978200428F8600445F
-:100790008F8500289383003000461023A7820042F3
-:1007A000A4A000E490A400638F820048AF830044BB
-:1007B0002403FFBF0046102100832024AF8200489D
-:1007C000A0A400638F820028A04000BD8F82002873
-:1007D00003E00008A44000BE8F8A002827BDFFE088
-:1007E000AFB10014AFB000108F880044AFBF001845
-:1007F00093890024954200E430D100FF0109182BB1
-:100800000080802130AC00FF3047FFFF00005821FE
-:1008100014600003310600FF012030210109582334
-:10082000978300420068102B144000320000000043
-:1008300014680007240200018E0200202403FFFB3D
-:1008400034E7800000431024AE020020240200019F
-:1008500034E70880158200053165FFFF0E0015E5BD
-:10086000020020210A001827020020210E0016167F
-:10087000020020210E0016598F8400508F8400281A
-:100880009482006024420001A4820060948200608F
-:100890003C0308008C63318830427FFF5443000FD3
-:1008A0000200202194820060240380000043102471
-:1008B000A48200609082006090830060304200FF5C
-:1008C000000211C200021027000211C03063007F35
-:1008D00000621825A0830060020020210220282148
-:1008E0008FBF00188FB100148FB000100A00179945
-:1008F00027BD0020914200632403FF8000431025A0
-:10090000A1420063978200423048FFFF110000209F
-:10091000938300248F840028004B1023304600FF6F
-:10092000948300E42402EFFF0168282B006218245E
-:10093000A48300E414A000038E02002001005821CB
-:10094000000030212403FFFB34E780000043102423
-:10095000AE02002024020001158200053165FFFF70
-:100960000E0015E5020020210A00184F978300426F
-:100970000E00161602002021978300428F82004449
-:10098000A780004200431023AF82004493830024D9
-:100990008F8200288FBF00188FB100148FB0001015
-:1009A00027BD002003E00008A04300BD8F8200287F
-:1009B00090430088904500BD244900883063003F83
-:1009C0002463FFE024020001006238042C6300204D
-:1009D00030E80019A385002410600010AF890034AE
-:1009E0003C0280003442000224050001240600017C
-:1009F0001500000800E218240000282114600005FA
-:100A000030E200201040000524050001912600017D
-:100A100030C600010A0017E60000000003E00008ED
-:100A20000000000027BDFFD8AFB000108F90003449
-:100A3000AFB40020AFB10014AFBF0024AFB3001CAF
-:100A4000AFB200188E0500103C0208008C4231B095
-:100A50008F86003830A33FFF0062182B8CD3001420
-:100A6000008088218CD20020106000780000A02136
-:100A700090C3000D2402FF8000431024304200FF89
-:100A800050400073022020210005138230420003F1
-:100A90005440006F0220202194C3001C8F82002844
-:100AA0008E050028A44301148CC200100262182392
-:100AB000146500072402001F8F82003C0062102191
-:100AC0000262102B104000088F83002C24020018B3
-:100AD0000E001697A382004C2403FFFF1043006F03
-:100AE0002404FFFF8F83002C8F84003C8C62001055
-:100AF0000244902100441023AC6200108F82002831
-:100B0000AC7200208C4200680052102B104000098B
-:100B10008F830038022020212402001D0E0016972A
-:100B2000A382004C2403FFFF1043005C2404FFFF5A
-:100B30008F8300388E0200248C630024104300074A
-:100B4000022020212402001C0E001697A382004CD4
-:100B50002403FFFF104300512404FFFF8F84002C67
-:100B60008C82002424420001AC8200241253000431
-:100B70008F8200288C4200685642000E8E020000D0
-:100B80008E0200003C030080004310241440000D3E
-:100B90002402001A022020210E001697A382004C86
-:100BA0002403FFFF1043003D2404FFFF0A0018E365
-:100BB0008E0200143C0300800043102450400003C8
-:100BC0008E020014AC8000208E0200142412FFFF5D
-:100BD000105200062402001B022020210E0016974E
-:100BE000A382004C1052002D2404FFFF8E0300004E
-:100BF0003C020001006210241040001F3C020080F3
-:100C00000062102414400008022020212402001A4F
-:100C10000E001697A382004C2403FFFF1043001F11
-:100C20002404FFFF02202021020028210E0016B715
-:100C3000240600012403FFFF2404FFFF1443000ED9
-:100C4000241400010A0019188FBF0024022020215B
-:100C50002402000D8FBF00248FB400208FB3001C2E
-:100C60008FB200188FB100148FB0001027BD00287C
-:100C70000A001697A382004C8F83002C02202021AB
-:100C800002803021946200362405000124420001D4
-:100C90000E0017E6A4620036000020218FBF00245A
-:100CA0008FB400208FB3001C8FB200188FB10014D6
-:100CB0008FB000100080102103E0000827BD00283D
-:100CC0008F83002827BDFFD8AFB40020AFB3001C2E
-:100CD000AFB20018AFB10014AFB00010AFBF002426
-:100CE000906200638F9100342412FFFF3442004071
-:100CF00092250000A06200638E22001000809821DF
-:100D000030B0003F105200060360A0212402000D05
-:100D10000E001697A382004C105200522404FFFFCD
-:100D20008F8300288E2200188C63007C10430007FC
-:100D3000026020212402000E0E001697A382004CB0
-:100D40002403FFFF104300472404FFFF2404002076
-:100D5000120400048F830028906200633442002054
-:100D6000A06200638F85003C10A0001E0000000000
-:100D7000560400048F820028026020210A001962B4
-:100D80002402000A9683000A2404FFFD94420060B6
-:100D90003042FFFF104300348FBF00243C020800A4
-:100DA0008C42318C0045102B14400006026020213B
-:100DB000000028210E0017E6240600010A00198908
-:100DC000000020212402002D0E001697A382004C63
-:100DD0002403FFFF104300232404FFFF0A001989A6
-:100DE00000002021160400058F8400288E230014A3
-:100DF0002402FFFF506200180260202194820060EC
-:100E000024420001A4820060948200603C03080038
-:100E10008C63318830427FFF5443000F02602021F1
-:100E2000948200602403800000431024A4820060A8
-:100E30009082006090830060304200FF000211C287
-:100E400000021027000211C03063007F00621825E5
-:100E5000A0830060026020210E0017992405000184
-:100E6000000020218FBF00248FB400208FB3001C0E
-:100E70008FB200188FB100148FB0001000801021C5
-:100E800003E0000827BD00288F83002827BDFFE866
-:100E9000AFB00010AFBF0014906200638F870034C2
-:100EA00000808021344200408CE60010A062006384
-:100EB0003C0308008C6331B030C23FFF0043102B6D
-:100EC0001040004E8F8500382402FF8090A3000D53
-:100ED00000431024304200FF50400049020020210E
-:100EE0000006138230480003240200025502004429
-:100EF0000200202194A2001C8F85002824030023D7
-:100F0000A4A201148CE60000000616023042003F45
-:100F1000104300103C0300838CE300188CA2007C7B
-:100F2000106200062402000E0E001697A382004CE9
-:100F30002403FFFF104300382404FFFF8F830028A1
-:100F40009062006334420020A06200630A0019CE60
-:100F50008F83002C00C31024144300078F83002CC0
-:100F600090A200623042000F34420020A0A2006232
-:100F7000A38800408F83002C9062000D3042007FD8
-:100F8000A062000D8F83003C106000180200202139
-:100F90008F8400388C8200100043102B1040000911
-:100FA00024020018020020210E001697A382004C94
-:100FB0002403FFFF104300182404FFFF0A0019F662
-:100FC000000020218C820010240500010200202155
-:100FD000004310238F83002C240600010E0017E627
-:100FE000AC6200100A0019F6000020210E001799CB
-:100FF000240500010A0019F600002021020020212A
-:101000002402000D8FBF00148FB0001027BD001800
-:101010000A001697A382004C8FBF00148FB00010F7
-:101020000080102103E0000827BD001827BDFFD86D
-:10103000AFB000108F900034AFB3001CAFBF0020E2
-:10104000AFB20018AFB100148E1200103C030800BC
-:101050008C6331B032423FFF0043102B1040007CC4
-:10106000008098218F8500382402FF8090A3000D16
-:1010700000431024304200FF5040007602602021DF
-:101080000012138230420003240300015443007114
-:101090000260202190A2000D30420008544000035D
-:1010A0008F82003C0A001A262402002450400003CC
-:1010B0008E03000C0A001A26240200278CA20020AE
-:1010C00014620005240200208E0300088CA2002474
-:1010D00010620008240200200E001697A382004C24
-:1010E0002403FFFF1043006A2404FFFF0A001A5183
-:1010F0008F84002C8E0200142411FFFF1451000372
-:101100008F8700280A001A4C240200258E0300183D
-:101110008CE2007C146200162402000E8E03002470
-:101120008CA2002814620012240200218E060028DE
-:101130008CA2002C14C2000E2402001F8E03002C6F
-:101140001060000B240200238CE200680043102B87
-:1011500014400007240200268CA200140066182107
-:101160000043102B504000078F84002C24020022E3
-:101170000E001697A382004C105100452404FFFF77
-:101180008F84002C2403FFF79082000D004310246D
-:10119000A082000D8F8600283C0308008C6331ACD0
-:1011A0008F82005094C400E08F85002C00431021F2
-:1011B00030847FFF00042040004410213043007F32
-:1011C000034320213C03000E008320212403FF80E1
-:1011D00000431024AF42002CA49200008CA20028EF
-:1011E00024420001ACA200288CA2002C8E03002C0B
-:1011F00000431021ACA2002C8E02002CACA20030C7
-:101200008E020014ACA2003494A2003A24420001E1
-:10121000A4A2003A94C600E03C0208008C4231B01F
-:1012200024C4000130837FFF14620013008030214A
-:10123000240280000082302430C2FFFF000213C26B
-:10124000304200FF000210270A001A8E000233C04D
-:10125000026020212402000D8FBF00208FB3001CEC
-:101260008FB200188FB100148FB0001027BD002876
-:101270000A001697A382004C8F820028026020216A
-:10128000240500010E001799A44600E0000020216B
-:101290008FBF00208FB3001C8FB200188FB10014D5
-:1012A0008FB000100080102103E0000827BD002847
-:1012B00027BDFFE0AFB100148F910034AFB0001034
-:1012C000AFBF00188E2600103C0308008C6331B0BD
-:1012D00030C23FFF0043102B1040005E0080802191
-:1012E0008F8500382402FF8090A3000D0043102456
-:1012F000304200FF50400058020020218F82003C05
-:1013000010400008000613828F8200289763000AAD
-:101310002404FFFD944200603042FFFF104300555B
-:1013200000061382304200031440000E000000004B
-:1013300092220002104000058E2300245060001508
-:10134000922300030A001AC7020020218CA2002465
-:101350005062001092230003020020210A001ACFDD
-:101360002402000F90A2000D3042000854400009F2
-:101370009223000302002021240200100E00169781
-:10138000A382004C2403FFFF1043003A2404FFFF14
-:1013900092230003240200025462000C92220003F4
-:1013A0008F82003C54400009922200030200202159
-:1013B0002402002C0E001697A382004C2403FFFF8A
-:1013C0001043002C2404FFFF922200030220282156
-:1013D00002002021384600102CC600012C420001DA
-:1013E0000E0016B7004630252411FFFF10510021D2
-:1013F0002404FFFF8F83003C1060001202002021B4
-:101400003C0208008C42318C0043102B1440000633
-:1014100000000000000028210E0017E6240600014D
-:101420000A001B0D000020212402002D0E0016973B
-:10143000A382004C1051000F2404FFFF0A001B0D73
-:10144000000020210E001799240500010A001B0D41
-:1014500000002021020020212402000D8FBF00186F
-:101460008FB100148FB0001027BD00200A0016971E
-:10147000A382004C8FBF00188FB100148FB00010F2
-:101480000080102103E0000827BD00209383004066
-:1014900027BDFFE024020002AFB10014AFB000107E
-:1014A00000808821AFBF0018000080211062008CEE
-:1014B0002404FFFD978500428F83004430A2FFFF84
-:1014C0000043102B5440007D8F8400480E001558B7
-:1014D000000000003C020800244279F40220202190
-:1014E000004028210E00171EAF8200342409FFFFA0
-:1014F0001049007B2404FFFF3C0808008D087A0493
-:101500003C0208008C4231B03C030800906379F43F
-:1015100031043FFF0082102B1040001B3067003F5A
-:101520003C0208008C4231A88F83005000042180C7
-:1015300000621821006418213062007F03422821D4
-:101540003C02000C00A228213C0200803442000131
-:101550003066007800C230252402FF80006210242B
-:10156000AF42002830640007AF4208048F82002891
-:101570000344202124840940AF460814AF85002C81
-:10158000AF840038AC430118938300402402000369
-:101590001462003B240200012402002610E2003DF8
-:1015A00028E2002710400013240200322402002207
-:1015B00010E2003828E20023104000082402002432
-:1015C0002402002010E200242402002110E2001E68
-:1015D000022020210A001B8C2402000B10E2002DA7
-:1015E0002402002510E20010022020210A001B8C9A
-:1015F0002402000B10E2001A28E20033104000061B
-:101600002402003F2402003110E2000B02202021BE
-:101610000A001B8C2402000B10E200110220202182
-:101620000A001B8C2402000B0E00187902202021D6
-:101630000A001BA7004080210E0019FB0220202178
-:101640000A001BA7004080210E001A9C02202021C6
-:101650000A001BA7004080211509000E00000000B1
-:101660000E001920022020210A001BA70040802123
-:101670000E001697A382004C0A001BA70040802191
-:1016800014620017020020212402002314E2000546
-:101690002402000B0E001992022020210A001BA731
-:1016A0000040802102202021A382004C0E001697CA
-:1016B0002410FFFF0A001BA80200202130A500FF14
-:1016C0000E00159524060001978300428F82004486
-:1016D000A780004200431023AF8200440200202173
-:1016E0008FBF00188FB100148FB000100080102140
-:1016F00003E0000827BD002027BDFFE0AFB10014C4
-:10170000AFBF0018AFB000108F4601283C0308009F
-:101710008C6331A02402FF80AF86005000C31821E3
-:101720003065007F03452821006218243C02000A2E
-:10173000AF43002400A2282190A2006200808821EB
-:10174000AF850028304200FF00021102A382004052
-:1017500090A200BC30420002144000022403003476
-:10176000240300308F820028A3830030938300403D
-:101770008C4200C0A380004CAF82004424020004CD
-:10178000106200308F8400448E2400045080002DAD
-:101790008F8400448E2200103083FFFFA784004214
-:1017A0001060001FAF8200488F8300282405FF804F
-:1017B000022020219062006300A21024304200FF2A
-:1017C0001440000D000000000E001B139790004213
-:1017D00010400010004018212402FFFD5462001147
-:1017E0008E230020020028210E0015360220202121
-:1017F0000A001BF98E2300209062006300A21024CF
-:10180000304200FF10400003022020210E00185B30
-:1018100000000000978200421440FFE48F830028FC
-:101820008E23002030620004104000068F840044A4
-:101830002402FFFB006210240E00154AAE22002095
-:101840008F8400448F8300288FBF00188FB100144D
-:101850008FB000102402000127BD002003E0000823
-:10186000AC6400C030A500FF2403000124A90001DE
-:101870000069102B1040000C00004021240A0001D8
-:1018800000A31023004A38042463000130820001C1
-:101890000069302B1040000200042042010740255F
-:1018A00054C0FFF800A3102303E00008010010213A
-:1018B00027BDFFE03C021EDCAFB20018AFB1001440
-:1018C000AFBF001CAFB0001034526F410000882140
-:1018D000240500080E001C09022020210011808030
-:1018E0003C07080024E775F40002160002071821DF
-:1018F000AC6200000000282124A200013045FFFF57
-:101900008C6200002CA60008044100020002204066
-:101910000092202614C0FFF8AC640000020780216A
-:101920008E0400000E001C0924050020262300015F
-:101930003071FFFF2E2301001460FFE5AE020000AE
-:101940008FBF001C8FB200188FB100148FB0001031
-:1019500003E0000827BD00203C02080024426EB8C6
-:101960003C010800AC2275E83C02080024425430D7
-:101970003C010800AC2275EC240200063C01080082
-:10198000A02275F00A001C1C0000000027BDFFD833
-:10199000AFB3001CAFB20018AFBF0020AFB100144E
-:1019A000AFB000108F5101408F48014800089402E9
-:1019B000324300FF311300FF8F4201B80440FFFEA5
-:1019C00027500180AE1100008F420144AE02000496
-:1019D00024020002A6120008A202000B2402001436
-:1019E000AE13002410620025286200151040000884
-:1019F000240200152402001010620030240200129C
-:101A0000106200098FBF00200A001D468FB3001C22
-:101A10001062007024020022106200378FBF002085
-:101A20000A001D468FB3001C3C0208008C4231A006
-:101A30002403FF800222102100431024AF4200241F
-:101A40003C0208008C4231A0022210213042007F6B
-:101A5000034218213C02000A00621821166000BCF3
-:101A6000AF830028906200623042000F34420030A1
-:101A7000A06200620A001D458FBF00203C04600088
-:101A80008C832C083C02F0033442FFFF00621824D0
-:101A9000AC832C083C0208008C4231A08C832C08BB
-:101AA0002442007400021082000214800062182593
-:101AB000AC832C080A001D458FBF00203C020800A3
-:101AC0008C4231A02403FF80022210210043102405
-:101AD000AF4200243C0208008C4231A03C03000AC3
-:101AE000022210213042007F0342102100431021C6
-:101AF0000A001D44AF8200283C0208008C4231A03D
-:101B00002405FF800222102100451024AF4200244A
-:101B10003C0208008C4231A0022210213042007F9A
-:101B2000034218213C02000A0062182190620063FF
-:101B300000A21024304200FF10400085AF8300282F
-:101B400024620088944300123C0208008C4231A8B1
-:101B500030633FFF0003198002221021004310214F
-:101B60003043007F03432021004510243C03000C38
-:101B700000832021AF4200289082000D00A2102493
-:101B8000304200FF10400072AF84002C9082000DA4
-:101B9000304200101440006F8FBF00200E00166608
-:101BA000000000008F4201B80440FFFE000000006A
-:101BB000AE1100008F420144AE0200042402000274
-:101BC000A6120008A202000BAE1300240A001D4555
-:101BD0008FBF00202406FF8002261024AF42002081
-:101BE0003C0208008C4231A031043FFF00042180F8
-:101BF0000222102100461024AF4200243C030800BA
-:101C00008C6331A83C0208008C4231A03227007F4F
-:101C10000223182102221021006418213042007F83
-:101C20003064007F034228213C02000A0066182429
-:101C300000A22821034420213C02000C0082202124
-:101C4000AF4300283C02000803471821006290219E
-:101C5000AF850028AF84002C0E001666010080219D
-:101C60008F4201B80440FFFE8F82002C8F84002831
-:101C7000274501809042000DACB10000A4B00006E1
-:101C8000000216000002160300021027000237C2ED
-:101C900014C00016248200889442001232033FFFD1
-:101CA00030423FFF1443001224026082908300639D
-:101CB0002402FF8000431024304200FF5040000CFB
-:101CC00024026082908200623042000F3442004061
-:101CD000A082006224026084A4A200082402000DF5
-:101CE000A0A200050A001D2F3C02270024026082EA
-:101CF000A4A20008A0A000053C02270000061C00CA
-:101D00000062182524020002A0A2000BACA3001060
-:101D1000ACA00014ACA00024ACA00028ACA0002C07
-:101D20008E42004C8F84002CACA200189083000DD2
-:101D30002402FF8000431024304200FF10400005C1
-:101D40008FBF00209082000D3042007FA082000DE6
-:101D50008FBF00208FB3001C8FB200188FB100140A
-:101D60008FB000103C02100027BD002803E00008DF
-:041D7000AF4201B8C5
-:0C1D7400080033F8080033F80800337052
-:101D8000080033A8080033DC0800340008003400E1
-:081D900008003400080032E0F5
-:081D98000A0001220000000016
-:101DA000000000000000000D747061352E302E30F0
-:101DB0006A3600000500000100000000000000007D
-:101DC0000000000000000000000000000000000013
-:101DD0000000000000000000000000000000000003
-:101DE00000000000000000000000000000000000F3
-:101DF00000000000000000000000000000000000E3
-:101E000000000000000000000000000000000000D2
-:101E100000000000000000000000000000000000C2
-:101E20000000000010000003000000000000000D92
-:101E30000000000D3C02080024421B803C03080007
-:101E400024632014AC4000000043202B1480FFFDCD
-:101E5000244200043C1D080037BD2FFC03A0F021E4
-:101E60003C100800261004883C1C0800279C1B809E
-:101E70000E00015A000000000000000D3084FFFF3A
-:101E8000308200078F85001810400002248300076D
-:101E90003064FFF80085302130C41FFF034418214F
-:101EA000247B4000AF85001CAF84001803E00008CD
-:101EB000AF4400843084FFFF308200078F8500200C
-:101EC0008F86002810400002248300073064FFF84A
-:101ED000008520210086182B14600002AF850024A5
-:101EE000008620230344282134068000AF8400208C
-:101EF000AF44008000A6202103E00008AF84003832
-:101F000027BDFFD8AFB3001CAFB20018AFB00010B0
-:101F1000AFBF0024AFB40020AFB100143C0860088C
-:101F20008D1450002418FF7F3C1A800002989824DA
-:101F30003672380CAD1250008F5100083C07601CFF
-:101F40003C08600036300001AF500008AF80001838
-:101F5000AF400080AF4000848CE600088D0F080879
-:101F60003C0760168CEC000031EEFFF039CA00101F
-:101F70003C0DFFFF340B80003C030080034B4821E5
-:101F80002D440001018D28243C0253533C010800DC
-:101F9000AC230420AF890038AF860028AF8400103E
-:101FA000275B400014A2000334E37C008CF900049A
-:101FB000032818218C7F007C8C6500783C0280000F
-:101FC00034520070AF85003CAF9F00403C130800C6
-:101FD00026731BC40240A0218E4800008F460000DB
-:101FE00038C300013064000110800017AF8800344E
-:101FF000028048218D2D00003C1908008F39045CB7
-:102000003C1108008E31045801A8F823033F7821C1
-:10201000000040210228382101FF802B00F07021B0
-:102020003C010800AC2F045C3C010800AC2E0458B5
-:102030008F4C0000398B0001316A00011540FFED23
-:1020400001A04021AF8D00348E4E00003C0C0800F2
-:102050008D8C045C3C0A08008D4A045801C8682332
-:10206000018D28210000582100AD302B014B20218B
-:10207000008610213C010800AC25045C3C010800EE
-:10208000AC2204588F4501088F44010030A920007C
-:10209000AF850000AF84000C1120000A00A03021A1
-:1020A0003C0708008CE7042C24EF00013C010800E9
-:1020B000AC2F042C3C104000AF5001380A000190B6
-:1020C0000000000030B002001600001424110F00C0
-:1020D0001091001224070D001087023330B0000663
-:1020E0005200FFF53C104000936D0000240C0010DE
-:1020F00031A600F010CC0269240E007010CE02DD73
-:102100008F8B001425670001AF8700143C1040003E
-:10211000AF5001380A000190000000009748010408
-:102120001100FFE53C10400030B84000170000A24D
-:10213000000000008F5901780720FFFE8F870038CC
-:1021400024090008240508008CE30008AF45017845
-:10215000A7490140A7400142974201048F86000031
-:102160003049FFFF30DF000113E002D5012040219C
-:102170002524FFFE240A0002A74A01463088FFFFFB
-:10218000A74401483C0B08008D6B043C156002C459
-:102190008F8F000C30C3002014600002240400095B
-:1021A0002404000130CD0C00240C040051AC0001CB
-:1021B00034840004A744014A3C0508008CA504208F
-:1021C0003C0200483C19000100A2F82530D800026A
-:1021D00003F9282513000004000018213C04010025
-:1021E00000A428252403000130CA00045140000542
-:1021F000AF8300083C06001000A628252403000138
-:10220000AF830008AF451000000000000000000090
-:1022100000000000000000008F8300081060002311
-:10222000000000008F4B10000561FFFE0000000061
-:102230001060001E000000008F4D10003C030020C5
-:1022400001A36024118000198F8F000031EE00027D
-:1022500011C0001600000000975010141600001363
-:10226000000000009745100830BFFFFF27F8000668
-:102270000018C8820019308000C7282133110001DE
-:1022800033030003122003208CA200000000000D85
-:1022900000C7F821AFE200003C1908008F39043074
-:1022A000272600013C010800AC2604308F6A00009C
-:1022B0003405FFFFAF8A00048CE200001045029A4B
-:1022C000000020218CE5000030BF010013E0027EF9
-:1022D000010020213C0708008CE704743C10080032
-:1022E0008E10044C00E858213C1808008F18047028
-:1022F0000168882B3C0808008D08044800007821FC
-:1023000002046021030F18210184702B010F682142
-:102310000071502101AE10213C010800AC2C044C8E
-:102320003C010800AC2204483C010800AC2B0474BA
-:102330003C010800AC2A04708F8D00180120302168
-:102340003129000725AE000831C21FFF034260217A
-:10235000AF8D001CAF820018259B4000AF42008467
-:10236000112000038F90002024C800073106FFF8D9
-:102370008F84002800D0282100A4782B15E00002CB
-:10238000AF90002400A428230345202134038000BB
-:10239000008310213C061000AF850020AF8200387A
-:1023A000AF450080AF4601788F8B00142567000190
-:1023B0000A0001DDAF8700148F6200088F670000FC
-:1023C000241100300007C602330300F0107100A290
-:1023D000241900401479FF4B8F8B00148F4A017829
-:1023E0000540FFFE30A7020014E000030005128242
-:1023F0000000000D0005128230500003001049005B
-:1024000001307021000E688001B06021000C5880FE
-:10241000017380218E0800001500000200000000FA
-:102420000000000D8F6F000405E202B19203000668
-:1024300092070005920F00043C020001000728806B
-:1024400000B060218D8900182771000825EE000575
-:1024500001226821000E3082AD8D0018022020215B
-:102460000E00058026050014920B00068F7F0004E5
-:102470003C087FFF000B2080009130218CC30004BA
-:10248000350AFFFF03EAC8240079C021ACD8000454
-:102490009207000592090004960D000800072880A5
-:1024A00000B1F8218FEF0000974201043C07FFFFC5
-:1024B00001E75024304EFFFF01C96021018D5823F0
-:1024C0003168FFFF01482025AFE4000092030007B8
-:1024D00024190001107902692406000310660279AC
-:1024E000000000008E190010241F000AA75F0140A1
-:1024F000A7590142920300048F86000024070001BF
-:10250000A7430144A74001469758010430D1000277
-:102510003C050041A758014800001821A747014A7F
-:102520001220000330CA00043C05014124030001CD
-:1025300051400005AF8300083C08001000A8282582
-:1025400024030001AF830008AF4510000000000025
-:102550000000000000000000000000008F8B000859
-:1025600011600004000000008F4410000481FFFE91
-:10257000000000008F6A0000920700043C0508007C
-:102580008CA50444AF8A0004975F01043C0F080047
-:102590008DEF044030E300FF33F9FFFF0079C021E5
-:1025A00000B868210000102124E6000A30C8FFFFAF
-:1025B00001B8482B01E2702101C9602131100007E8
-:1025C0003C010800AC2D04443C010800AC2C044044
-:1025D000120000038F8D0018250B00073168FFF8EB
-:1025E000010D702131CC1FFFAF8D001CAF8C001886
-:1025F000AF4C008497440104034C80213084FFFFDA
-:102600003088000711000003261B400024890007C2
-:102610003124FFF88F8200208F850028008220213E
-:102620000085782B15E00002AF820024008520236E
-:102630000344882134058000022510213C06100047
-:10264000AF840020AF820038AF440080AF460178ED
-:102650000A0002858F8B00148F5F017807E0FFFE70
-:1026600030AA020015400003000542820000000D60
-:1026700000054282310200030002710001C268219C
-:10268000000D6080018248210009288000B380216C
-:102690008E0B000011600002000000000000000D21
-:1026A0008F6F000C05E001F38F87003824190001BB
-:1026B000AE1900008CE30008A20000078F78000428
-:1026C00000181C02306600FF24D100050011308282
-:1026D0002CC4004114800002A20300040000000D7D
-:1026E0008F6B00043C0EFFFF00E028213164FFFFE8
-:1026F000248F000B000F4082000810800047482103
-:102700008D2D000026040014A60B000801AE6024E5
-:102710000E000580AD2C00008F5F01083C0A100000
-:1027200003EA382410E001A30000000097460104EA
-:102730009203000724D1FFEC346500023224FFFF2E
-:10274000A2050007960600082CC7001354E00005F8
-:1027500092030007920A0007355F0001A21F0007DD
-:1027600092030007240B0001106B01BA2409000337
-:10277000106901CD8F88003830CFFFFF25E40002BB
-:102780000004C883333F00FF001F2880A219000502
-:1027900000A858218D780000975101043C03FFFFE9
-:1027A000030360243222FFFF004F702325CDFFFE7C
-:1027B000018D4825AD690000920600053C02FFF638
-:1027C000344EFFFF30CA00FF000A388000F020219D
-:1027D000909900143C1FFF7F37E7FFFF3323000F62
-:1027E0000066782131F800FF0018288000B08821A9
-:1027F0008E2D002000A86021A20F000601AE482403
-:10280000AE0D000CAD89000C920B00068E04000C7E
-:102810000127F824000B50800150C821972600267C
-:102820000148C02100874024AF260024AE08000CD8
-:10283000AF3F0020AF0600108F860000240C001070
-:1028400024090002A74C0140A7400142A7400144CF
-:10285000A7490146974B01042407000130C8000234
-:10286000256AFFFEA74A01483C050009A747014A1F
-:1028700011000003000018213C0501092403000198
-:1028800030CD000451A00005AF8300083C060010C5
-:1028900000A6282524030001AF830008AF451000DF
-:1028A0000000000000000000000000000000000028
-:1028B0009218000427110002322F0007000F102386
-:1028C000304E0007AE0E00108F900008120000047A
-:1028D000000000008F4310000461FFFE00000000B4
-:1028E0008F7800008F8F00183C1008008E10044471
-:1028F000AF9800049751010425E6001030CA1FFF6D
-:102900003222FFFFAF8F001CAF8A0018AF4A00844D
-:102910002449FFFE3C0B08008D6B0440974E0104D8
-:1029200001206821000967C3020D282131C9FFFF7A
-:1029300000AD402B016C382100E82021034AF8212A
-:10294000313900073C010800AC2504443C01080073
-:10295000AC2404401320000327FB4000252300077C
-:102960003069FFF88F9F00208F840028013F3821B5
-:1029700000E4C82B17200002AF9F002400E4382396
-:102980000347202134058000008510213C061000FB
-:10299000AF870020AF820038AF470080AF46017894
-:1029A0000A0002858F8B0014975801041300FDC2A2
-:1029B0003C1040008F4301780460FFFE30B94000B6
-:1029C000132000033C0400080000000D3C04000834
-:1029D000AF44014024080800AF4801788F8B000005
-:1029E000974A0104317F000113E000E93146FFFFFF
-:1029F00024D0FFFE240C0002A74C0146A75001483A
-:102A00008F8F00182405000DA745014A8F71000023
-:102A100025E2000830491FFF0349702130CD00072F
-:102A2000AF910004AF8F001CAF89001800C038219F
-:102A3000AF49008411A0000325DB400024C6000735
-:102A400030C7FFF88F9800208F84002800F83021CD
-:102A500000C4382B14E00002AF98002400C43023D7
-:102A60008F8A001403465821340880000168F82139
-:102A7000255900013C0310003C104000AF860020A7
-:102A8000AF9F0038AF460080AF430178AF99001484
-:102A9000AF5001380A000190000000008F6900006B
-:102AA000974401043127FFFF3088FFFF8F4F0178E3
-:102AB00005E0FFFE30FF0007001F182330780007F5
-:102AC00024E6FFFE2419000AA7590140A758014235
-:102AD000A7460144A7400146A74801488F42010884
-:102AE00030510020162000022403000924030001B5
-:102AF00030AA0002A743014A3C04004111400003F0
-:102B0000000018213C0401412403000130AB000403
-:102B100051600005AF8300083C05001000852025AA
-:102B200024030001AF830008AF4410000000000040
-:102B30000000000000000000000000008F9000086E
-:102B400012000004000000008F4C10000581FFFE01
-:102B5000000000008F780000276200088F8D003C85
-:102B6000AF980004944600089451000A944F000C5A
-:102B700030CEFFFF0011240031E9FFFF11CD00A28C
-:102B8000008920253C0308008C6304443C1808009D
-:102B90008F18044000E85021255FFFFE007F782158
-:102BA0000000102101FF302B03028821022648215A
-:102BB0003C010800AC2F04443C010800AC2904404F
-:102BC00024EB00083162FFFF3047000710E00003EC
-:102BD0008F850018245000073202FFF83106FFFFEE
-:102BE00030C800070045702131CD1FFF034D602123
-:102BF000AF85001CAF8D0018259B4000AF4D0084B1
-:102C0000110000038F8F002024C400073086FFF8D6
-:102C10008F84002800CF282100A4482B1520000213
-:102C2000AF8F002400A42823AF850020AF4500808B
-:102C30003C1108008E3104340345C0213402800069
-:102C40000302302112200005AF860038938300175D
-:102C50002419000E1079000D241F043F3C0A1000B7
-:102C6000AF4A01788F8B0014256700010A0001DD4F
-:102C7000AF8700140E0005A63C1040008F8B001497
-:102C8000256700010A0001DEAF8700143C0A10002E
-:102C9000A75F0148AF4A01780A0004B48F8B001483
-:102CA000240E0F0011EE003D30D10020162000024E
-:102CB00024030009240300010A000208A743014A73
-:102CC0000A0001FBA740014694E5000894E2000ACF
-:102CD00094EB000C8F86003C0002FC00316AFFFF81
-:102CE00030B9FFFF1326003703EA20253C05080012
-:102CF0008CA504443C1F08008FFF044000005021B5
-:102D000000A8382100E8302B03EAC8210326C0219F
-:102D10003C010800AC2704443C010800AC380440E6
-:102D20000A0002698F8D00183C1908008F39047C55
-:102D30003C0308008C6304543C0608008CC60478ED
-:102D40003C0F08008DEF04500328382100686821EB
-:102D500000E8C02B00C4882101A8402B01E47021A9
-:102D60000238582101C860213C010800AC2D0454F0
-:102D70003C010800AC2C04503C010800AC27047C4A
-:102D80003C010800AC2B04780A0002698F8D001802
-:102D9000A74001460A00041B8F8F001830D0002086
-:102DA0001600FFC52403000D240300050A000208D5
-:102DB000A743014A975901042738FFF00A00036B23
-:102DC0003304FFFF8F8C0040148CFFC8000080216B
-:102DD0003C1108008E31046C3C0408008C840468AB
-:102DE0000228702101C8782B00904021010F682132
-:102DF0003C010800AC2E046C3C010800AC2D0468BA
-:102E00000A0002698F8D00188F9900401499FF5DA8
-:102E1000000060213C0508008CA5046C3C100800F3
-:102E20008E10046800E82021248EFFFE00AEF821F9
-:102E300003EE582B020C5021014B18213C010800D5
-:102E4000AC3F046C3C010800AC2304680A00048B0E
-:102E500024EB00088F8800383C02FFFF8D0E000C29
-:102E600001C2682401A46025AD0C000C0A0003799E
-:102E700030CFFFFF0A0003A9AE000000974B01040A
-:102E8000920400048E2A000C01644021251FFFF2E9
-:102E90000147182433F9FFFF0079C025AE38000C34
-:102EA0000A0002D48E1900103C03FFFF8D110010A0
-:102EB0000223282400A47825AD0F00100A0003790E
-:102EC00030CFFFFF97450104920600048E2F0010BB
-:102ED00000A610212449FFEE01E76824312EFFFFF0
-:102EE00001AE6025AE2C00100A0002D48E1900102D
-:102EF0008E06000CAE0000000003C0800310882185
-:102F00000A0002A6AE2600201460000D3050FFFF1C
-:102F10003C04FFFF0044602401846826000D582B08
-:102F2000000C502B014B1024104000020000000048
-:102F30000000000D8CA300000A00023E0064102572
-:102F40003A11FFFF0011782B0010702B01CF2024C5
-:102F500010800002000000000000000D8CB800008E
-:102F60000A00023E3702FFFF3084FFFF30A5FFFF5B
-:102F7000108000070000182130820001104000027C
-:102F800000042042006518211480FFFB0005284042
-:102F900003E000080060102110C0000700000000DE
-:102FA0008CA2000024C6FFFF24A50004AC82000010
-:102FB00014C0FFFB2484000403E0000800000000AC
-:102FC00010A0000824A3FFFFAC8600000000000052
-:102FD000000000002402FFFF2463FFFF1462FFFAD9
-:102FE0002484000403E0000800000000308EFFFF8E
-:102FF00030D8FFFF00057C0001F8602539CDFFFFC8
-:1030000001AC5021014C582B014B482100094402CE
-:103010003127FFFF00E830210006240230C5FFFF02
-:1030200000A418213862FFFF03E000083042FFFFD0
-:103030003C0C08008D8C0484240BFF8027BDFFD03E
-:1030400001845021014B4824AF4900203C0808006E
-:103050008D080484AFB20020AFB00018AFBF0028C5
-:10306000AFB30024AFB1001C936600040104382103
-:1030700030E4007F009A10213C03000800439021B7
-:1030800030C50020036080213C080111277B000827
-:1030900014A00002264600702646006C921300041D
-:1030A00097510104920F00043267000F322EFFFF88
-:1030B00031ED004001C7282311A000050000482180
-:1030C000925900BC33380004170000900000000043
-:1030D000924300BC307F000413E0000F00000000AA
-:1030E00010A0000D00000000960E0002240AFF80D0
-:1030F00000A7602125CDFFFEA74D1016920B0004FE
-:10310000014B2024308200FF10400085010C402537
-:103110003C0F0400010F40258F5301780660FFFE2D
-:103120002404000AA7440140960D0002240400096B
-:1031300031AC0007000C5823316A0007A74A01424E
-:10314000960200022443FFFEA7430144A740014624
-:10315000975F0104A75F01488F59010833380020A9
-:103160005300000124040001920F000431EE00100E
-:1031700015C000023483001000801821A743014AC3
-:10318000000000000000000000000000000000003F
-:10319000AF48100000000000000000000000000028
-:1031A000000000008F5110000621FFFE3113FFFFC9
-:1031B00012600003000000008F481018ACC8000027
-:1031C00096030006307FFFFF27F90002001998825E
-:1031D00000138880023B30218CD800001520005756
-:1031E00000183402920300042405FF8000A3F82491
-:1031F00033F100FF1220002C00000000924700BCB9
-:1032000030F200021240002800000000974B100C22
-:103210002562FFFEA7421016000000003C0A0400D1
-:1032200035490030AF4910000000000000000000E8
-:1032300000000000000000008F4C10000581FFFE20
-:10324000000000009749100C8F51101C00C0202175
-:103250003127FFFF24F2003000121882000328807B
-:1032600000BBF8213226FFFFAFF100000E000595EC
-:1032700000112C020013C880033B98218E780000B7
-:1032800000027400AFB800108FA80010310FFFFFCC
-:10329000AFAF00108FA4001001C46825AFAD0010BF
-:1032A0008FA60010AE66000097730008976D000AA5
-:1032B0009766000C8F8A003C000D5C0030CCFFFF4D
-:1032C0003262FFFF104A0036016C2025960600028C
-:1032D0003C10100024D300080E0001393264FFFFB7
-:1032E000974C01040E0001473184FFFFAF50017875
-:1032F0008FBF00288FB300248FB200208FB1001C35
-:103300008FB0001803E0000827BD003010A0FF7048
-:103310000000000024A5FFFC0A0005CE24090004DB
-:103320008CD10000AF5110188F5301780660FF7ADE
-:103330002404000A0A0005E30000000000A7C821D9
-:103340008F8800388F4E101C0019C08200187880BA
-:1033500001E82021AC8E0000000E2C0200C02021CC
-:103360000E00059531C6FFFF023B28218CAD000001
-:103370000002540000403021AFAD00108FAC0010AF
-:10338000318BFFFFAFAB00108FA200100142482528
-:10339000AFA900108FA700100A000613ACA7000009
-:1033A0008F8F0040148FFFC9000000009742010476
-:1033B000960B00023C0508008CA5046C3049FFFF09
-:1033C000316AFFFF3C1108008E310468012A382160
-:1033D00024F2FFFE00B240210012FFC30112C82BED
-:1033E000023FC021031920213C010800AC28046CD5
-:1033F0003C010800AC2404680A00064D00000000EF
-:1034000000A4102B104000092403000100052840EF
-:1034100000A4102B04A00003000318405440FFFC3C
-:103420000005284010600007000000000085302BD8
-:1034300014C0000200031842008520231460FFFB23
-:103440000005284203E00008008010218F85002C31
-:1034500027BDFFE8000530272CC300012CA4000283
-:103460000083102510400003AFBF00102405007F2B
-:10347000AF85002C0005282730A5FFFF0E0005743E
-:10348000240426F58F830030240402BD004030213F
-:103490000083382B10E000092405000100042040BF
-:1034A0000083102B04800003000528405440FFFCDB
-:1034B0000004204010A0000800C350210064402BED
-:1034C00015000002000528420064182314A0FFFB29
-:1034D0000004204200C350218FBF0010000A4C029C
-:1034E000312200FF27BD0018AF8A002C03E000083E
-:0434F000AF89003070
-:0C34F4000A00002A000000000000000098
-:103500000000000D747870352E302E306A360000C1
-:10351000050000000000000A000001360000EA601B
-:10352000000000000000000000000000000000009B
-:10353000000000000000000000000000000000008B
-:10354000000000000000000000000000000000007B
-:103550000000000000000016000000000000000055
-:10356000000000000000000000000000000000005B
-:10357000000000000000000000000000000000004B
-:1035800000000000000000000000000000001388A0
-:1035900000000000000005DC00000000000000004A
-:1035A00010000003000000000000000D0000000DEE
-:1035B0003C02080024423B603C03080024633D14A5
-:1035C000AC4000000043202B1480FFFD2442000487
-:1035D0003C1D080037BD7FFC03A0F0213C10080013
-:1035E000261000A83C1C0800279C3B600E0002BA75
-:1035F000000000000000000D8F8300383C088000B0
-:10360000350700708CE50000008330253C029000F7
-:1036100000C22025AF850030AF4400208F49002034
-:103620000520FFFE3C038000346200708C450000E2
-:103630008F8600303C1908008F39007C3C0E080052
-:103640008DCE007800A62023032458210000782185
-:103650000164682B01CF6021018D50213C010800DD
-:10366000AC2B007C3C010800AC2A007803E0000889
-:10367000000000000A000041240400018F8400388B
-:103680003C05800034A200010082182503E00008F8
-:10369000AF43002003E00008000010213084FFFF4A
-:1036A00030A5FFFF108000070000182130820001C4
-:1036B0001040000200042042006518211480FFFB26
-:1036C0000005284003E000080060102110C000073A
-:1036D000000000008CA2000024C6FFFF24A5000407
-:1036E000AC82000014C0FFFB2484000403E0000847
-:1036F0000000000010A0000824A3FFFFAC8600001B
-:1037000000000000000000002402FFFF2463FFFF10
-:103710001462FFFA2484000403E0000800000000A3
-:10372000308AFFFF93A80013A74A014497490E1659
-:1037300030C600FF3C021000A7490146AF450148D2
-:10374000A3460152A748015AAF4701608FA4001851
-:103750008FA30014A7440158AF43015403E00008AD
-:10376000AF42017803E00008000000003C03800045
-:10377000346200708C4900008F88000024840007A8
-:1037800027BDFFF83084FFF8AF890030974D008ADD
-:1037900031ACFFFFAFAC00008FAB000001685023DD
-:1037A0002547FFFF30E61FFF00C4282B14A0FFF7BA
-:1037B0003C0C8000358B00708D6A00003C070800CF
-:1037C0008CE700843C0608008CC60080000810824C
-:1037D000014918230002788000E3702100002021B5
-:1037E00001C3C82B00C4C02101FA4021031948219C
-:1037F0002502400027BD00083C010800AC2E0084D3
-:103800003C010800AC29008003E000080000000033
-:103810008F8200002486000730C5FFF800A218211F
-:1038200030641FFF03E00008AF8400008F8700387A
-:103830008F8A004027BDFFB88F860044AFB6004096
-:10384000AFBF0044AFB5003CAFB40038AFB30034F5
-:10385000AFB20030AFB1002CAFB000288F450104EB
-:103860008D4900ACAF4700808CC8002000A93823E8
-:103870000000B021AF480E108F440E100000482108
-:10388000AF440E148CC20024AF420E188F430E18A2
-:10389000AF430E1C10E001252D230001936B00089F
-:1038A000116000D400000000976E001031CDFFFFC2
-:1038B00000ED602B158000CF000000009770001015
-:1038C000320FFFFFAF4F0E008F5200003251000841
-:1038D0001220FFFD0000000097540E088F460E04D2
-:1038E0003285FFFF30B3000112600132000000009A
-:1038F0000000000D30B8A04024150040131500C092
-:1039000030A9A0001120012D00000000937F0008C5
-:1039100013E000080000000097630010306BFFFF09
-:1039200000CB402B1100000330AC0040118001237C
-:1039300000000000A785003CAF86003493660008B5
-:1039400000E02821AFA7002014C0012427B30020E5
-:10395000AF60000C9782003C3047400014E000024A
-:10396000240300162403000E24194007A363000A51
-:10397000AF790014938A003E8F7400143158000709
-:103980000018AA4002959025AF7200149784003C5D
-:103990008F7000143091001002117825AF6F001461
-:1039A000978E003C31CD000811A00147000028216E
-:1039B0008F6700143C0210003C0C810000E22825B7
-:1039C000AF65001497460E0A2408000E3405FFFC6C
-:1039D00030C3FFFF006C5825AF6B0004A3680002E2
-:1039E000937F000A27E90004A369000A9786003C38
-:1039F0009363000A30CC1F00000C598301634021FF
-:103A0000251F0028A37F000997490E0CA769001005
-:103A100093790009272A0002315800070018A823CB
-:103A200032B10007A371000B937400099764001072
-:103A30008F910034978F003C329200FF0244802126
-:103A40000205702131ED004011A0000531C4FFFFD7
-:103A50000091282B3C12800010A000140000A0212F
-:103A60000224382B14E0011B8FA500208F4D0E146B
-:103A7000AF4D0E108F420E1CAF420E18AF440E0019
-:103A80008F4F000031EE000811C0FFFD0000000064
-:103A900097540E080080882100009021A794003CD4
-:103AA0008F500E0424140001AF900034976400106E
-:103AB0003095FFFF8E6800000111F82317E0000920
-:103AC000AE7F00008F6500148F8B004434A6004049
-:103AD000AF6600148F4C0E10AD6C00208F430E1893
-:103AE000AD6300249367000814E000D200000000DA
-:103AF0000E00009E240400108F8900483C0832000C
-:103B000000402821312600FF0006FC0003E8502574
-:103B100025390001AF990048AC4A000093780009AC
-:103B20009370000A330400FF00047400320F00FF9A
-:103B300001CF6825AC4D00048F820048064000EAA2
-:103B4000ACA20008ACA0000C9783003C306B0008CE
-:103B5000156000022628000626280002974E0E1443
-:103B60008F450E1C8F670004936D000231C4FFFF68
-:103B700031A200FFAFA200108F6C0014AFA8001894
-:103B80000E00008BAFAC0014240400100E0000C720
-:103B9000000000008E7200001640000500000000CA
-:103BA0008F6400142405FFBF00859824AF730014B0
-:103BB0008F79000C03353821AF67000C937500082E
-:103BC00016A000080000000012800006000000009F
-:103BD0008F7F00143C0BEFFF3568FFFE03E848249D
-:103BE000AF690014A37400088FA500200A000246E4
-:103BF00002202021AF470E000A0000F5000000005F
-:103C00008F5901780720FFFE241F08008F840000D1
-:103C1000AF5F0178974B008A316AFFFF0144482368
-:103C20002528FFFF31021FFF2C4300081460FFF915
-:103C3000000000008F8E00488F8D003800C04821A2
-:103C40000344202125C60001240C0F00AF86004844
-:103C500000E938232486400031CA00FF11AC00057A
-:103C6000240800019391003E3230000700107A4092
-:103C700035E80001000AAC003C18010002B8A0259C
-:103C8000AC9440008F93004830B2003630A4000856
-:103C9000ACD300041080009701123025974E0E0A15
-:103CA0008F8D00003C02810031CCFFFF25AB000866
-:103CB000018240253C03100031651FFF25390006B5
-:103CC000241F000EAF48016000C33025A75F015AD2
-:103CD000AF850000A759015814E0000A8F930038FF
-:103CE00024120F00527200022416000134C6004054
-:103CF0008F580E108F940044AE9800208F550E18E8
-:103D0000AE9500248F450E14AF4501448F590E1C0B
-:103D1000AF590148A34A01523C0A1000AF46015472
-:103D2000AF4A017814E0FEDD2D2300010076A025C6
-:103D3000128000178FBF00448F84003824160F00B4
-:103D400010960084000000008F45017804A0FFFE5B
-:103D500024150F001095006E000000008F470E1410
-:103D6000240202403C1F1000AF4701448F440E1C48
-:103D7000AF440148A3400152A740015AAF4001603F
-:103D8000A7400158AF420154AF5F01788FBF004494
-:103D90008FB600408FB5003C8FB400388FB300342D
-:103DA0008FB200308FB1002C8FB0002803E00008E4
-:103DB00027BD004814C0FED030B8A0408F420E147A
-:103DC0008F84004400004821AC8200208F510E1CDB
-:103DD000AC9100240A00020E2D2300018F910034C3
-:103DE000978A003C3C1280000220A82131580040F4
-:103DF0001700FF300000A021976900108F92003457
-:103E00003139FFFF133200350000202100804821A6
-:103E10001480FEA000A038218F420E148F8400442D
-:103E2000AC8200208F510E1CAC9100240A00020EBF
-:103E30002D230001936A00099378000B315000FF95
-:103E4000330F00FF020F702125C2000A3050FFFF20
-:103E50000E00009E020020218F8600483C1F41007A
-:103E600024CD0001AF8D0048936C000930C600FFDF
-:103E700000064400318300FF246B0002010B48253B
-:103E8000013FC825AC5900008F67000C97440E1401
-:103E900000F22825AC4500048F450E1C8F670004F6
-:103EA000936A00023084FFFF315800FFAFB8001062
-:103EB0008F6F0014AFB100180E00008BAFAF00146D
-:103EC0000A0001A602002021AF6000040A00013EA2
-:103ED000A36000020A000246000020210000902199
-:103EE0000A000170241400013C1280000A000195B0
-:103EF000ACB2000C8F91000025240002A7440158A9
-:103F000026300008320F1FFF0A0001F9AF8F0000B2
-:103F1000AF40014C1120002C000000008F590E1002
-:103F2000AF5901448F430E18240200403C1F10007B
-:103F3000AF430148A3400152A740015AAF4001607E
-:103F4000A7400158AF420154AF5F01780A00022731
-:103F50008FBF0044112000060000000097460E08A5
-:103F600030CC004015800002000000000000000D71
-:103F70008F4D017805A0FFFE0000000097530E1042
-:103F80003C120500240E2000326AFFFF0152C025BA
-:103F9000AF58014C8F4F0E143C021000AF4F01443C
-:103FA0008F500E1CAF500148A34001528F8400383F
-:103FB000A740015AAF400160A7400158AF4E0154DD
-:103FC0000A000215AF4201788F490E14AF4901442F
-:103FD0008F430E1C0A00028E240200403C0E20FF7C
-:103FE00027BDFFE03C1A80003C0F800835CDFFFD67
-:103FF000AFBF001CAFB20018AFB10014AFB00010DB
-:10400000AF8F0040AF4D0E00000000000000000028
-:104010000000000000000000000000003C0C00FF59
-:10402000358BFFFDAF4B0E003C0660048CC9500081
-:10403000240AFF7F3C116000012A40243507380C18
-:10404000ACC750008E24043824050009AF45000891
-:104050003083FFFF38622F712450C0B3AF80004817
-:104060000E000068AF80000052000001AE20442C1A
-:104070000E0004353C1180000E000EA83630007092
-:104080008F8A00403C12080026523BC8020088215B
-:104090008E0800008F5F00003BF9000133380001FB
-:1040A00013000017AF880030022048218D27000040
-:1040B0003C0F08008DEF006C3C0C08008D8C0068F4
-:1040C00000E8C02301F828210000682100B8302B47
-:1040D000018D5821016640213C010800AC25006C8F
-:1040E0003C010800AC2800688F44000038830001C0
-:1040F000306200011440FFED00E04021AF87003046
-:104100008E0C00003C0508008CA5006C3C040800E7
-:104110008C8400680188302300A63821000010211B
-:1041200000E6402B008218210068F8213C010800BD
-:10413000AC27006C3C010800AC3F00688F490100CF
-:1041400025590088AF990044AF890038AF49002055
-:104150008E070000AF8700308F4D017805A0FFFE6D
-:10416000000000008E0600003C0B08008D6B007400
-:104170003C0408008C84007000C728230165F821E6
-:104180000000102103E5402B0082382100E8C821FF
-:10419000240908003C010800AC3F00743C01080001
-:1041A000AC390070AF49017893580108A398003EDC
-:1041B000938F003E31EE000115C000158F8300384B
-:1041C000240E0D00106E0019240F0F00106F001D3B
-:1041D000000000009159000024180050332900FF0E
-:1041E000113800043C1F4000AF5F01380A0002E7AD
-:1041F000000000000E0008EE000000008F8A004062
-:104200003C1F4000AF5F01380A0002E700000000D9
-:10421000938D003E31AC0006000C51000E0000CE24
-:104220000152D8210A0003438F8A00403C1B08003A
-:10423000277B3C480E0000CE000000000A0003432C
-:104240008F8A00403C1B0800277B3C680E0000CE94
-:10425000000000000A0003438F8A004090AA00017A
-:104260008FAB00108CAC00103C0300FF8D68000485
-:10427000AD6C00208CAD001400E060213462FFFFC3
-:10428000AD6D00248CA700183C09FF000109C02473
-:10429000AD6700288CAE001C0182C8240319782564
-:1042A000AD6F0004AD6E002C8CAD0008314A00FFEC
-:1042B000AD6D001C94A900023128FFFFAD6800100D
-:1042C00090A70000A5600002A1600004A1670000A3
-:1042D00090A30002306200FF000219821060000506
-:1042E000240500011065000E0000000003E0000836
-:1042F000A16A00018CD80028354A0080AD780018EA
-:104300008CCF0014AD6F00148CCE0030AD6E000861
-:104310008CC4002CA16A000103E00008AD64000C0D
-:104320008CCD001CAD6D00188CC90014AD69001453
-:104330008CC80024AD6800088CC70020AD67000C55
-:104340008CC200148C8300640043C82B1320000728
-:10435000000000008CC20014144CFFE400000000B8
-:10436000354A008003E00008A16A00018C820064E5
-:104370000A0003990000000090AA000027BDFFF882
-:104380008FA9001CA3AA00008FAE00003C0FFF8085
-:104390008FA8001835E2FFFF8CCD002C01C26024ED
-:1043A000AFAC0000A120000400E06021A7A0000243
-:1043B0008FB800008D2700040188182100A0582123
-:1043C00000C05021006D28263C06FF7F3C0F00FFF7
-:1043D0002CAD000135EEFFFF34D9FFFF3C02FF009A
-:1043E00003193024000D1DC0010EC82400E2C024B2
-:1043F00000C3702503197825AD2E0000AD2F0004F1
-:104400008D450024AFAE0000AD2500088D4D002085
-:104410002405FFFFAD2D000C956800023107FFFF5A
-:10442000AD2700109166001830C200FF000219C2CB
-:10443000506000018D450034AD2500148D670008E3
-:1044400027BD0008AD27001C8C8B00CCAD2C0028AC
-:10445000AD20002CAD2B0024AD20001803E0000897
-:10446000AD20002027BDFFE0AFB20018AFB10014AF
-:10447000AFB00010AFBF001C9098000000C08821B2
-:104480003C0D00FF330F007FA0CF0000908E000195
-:1044900035ACFFFF3C0AFF00A0CE000194A6001E31
-:1044A000A22000048CAB00148E29000400A08021FF
-:1044B000016C2824012A4024008090210105202538
-:1044C000A6260002AE2400042605002026240008AB
-:1044D0000E00007624060002924700002605002800
-:1044E0002624001400071E000003160324060004FF
-:1044F000044000032403FFFF965900023323FFFF0B
-:104500000E000076AE230010262400248FBF001C6E
-:104510008FB200188FB100148FB000102405000373
-:10452000000030210A00008027BD002027BDFFD8F1
-:10453000AFB1001CAFB00018AFBF002090A80000C2
-:10454000240200018FB0003C3103003F008088212D
-:10455000106200148FAA0038240B0005506B00165F
-:10456000AFAA001000A0202100C028210E0003DC0B
-:1045700002003021922400BC30830002106000034E
-:1045800026060030ACC0000024C600048FBF002007
-:104590008FB1001C8FB0001800C0102103E000088C
-:1045A00027BD0028014038210E00035AAFB000108B
-:1045B0000A000420000000000E0003A1AFB00014A8
-:1045C0000A000420000000003C02000A03421821F7
-:1045D0003C04080024843CAC2405001A000030216F
-:1045E0000A000080AF8300543C03800034620070F6
-:1045F0008C48000000A0582100C04821308A00FFEC
-:10460000AF8800308F4401780480FFFE3C0C8000AE
-:10461000358600708CC500003C0308008C63007474
-:104620003C1808008F18007000A82023006468213F
-:104630000000C82101A4782B0319702101CF60214B
-:104640003C010800AC2D00743C010800AC2C00704B
-:104650008F480E14AF480144AF47014CA34A0152A2
-:10466000A74B01589346010830C5000854A000012B
-:1046700035291000934B090024070050316A00FFD0
-:1046800011470007000000008F450E1CAF45014890
-:10469000AF4901543C09100003E00008AF4901781C
-:1046A000934D010831A8000811000010000000001F
-:1046B000934F010831EE001051C000013529000868
-:1046C0003C04080090843D10A34401508F4309A48A
-:1046D000AF4301488F4209A0AF420144AF490154A2
-:1046E0003C09100003E00008AF4901783C190800BC
-:1046F0008F393CCC333800085700FFF135290008CA
-:104700000A0004730000000024070040AF470814AB
-:10471000AF4008108F4209448F4309508F44095419
-:104720008F45095C8F46094CAF820064AF8300500F
-:10473000AF84004CAF85005C03E00008AF860060EA
-:104740009346010930C5007F000518C000052140CF
-:104750000083102103E00008244200883C0A08007E
-:10476000914A3CD13C09080095293CCA3C051100FE
-:10477000000A3C002528000200E8302500C5182565
-:1047800024820008AC83000003E00008AC80000431
-:104790008F4A002C974E09083C0F000E034F38211A
-:1047A00031CDFFFF000D41C0AF48002C97430908F1
-:1047B00094EC001A0080402124020001318BFFFF9D
-:1047C000AC8B00008CE9001C00A0582100C06021C7
-:1047D000AC8900048CE40020AD04000890E30019CB
-:1047E00030630003106200400000000028650002F2
-:1047F00014A00073240600021066004E00000000A2
-:104800002418000310780057000000003C0908003D
-:1048100095293CC093450934934609213C0E080074
-:1048200095CE3CC630A200FF0002C88294E5002A63
-:1048300030C400FF978700580019C60000041C0010
-:10484000312FFFFF0303102501CF6821004DC8253C
-:1048500000A720213C0640000326C02500044C0090
-:10486000AD090004AD180000934F09203C03000679
-:1048700025090014000F760001C36825AD0D00085E
-:104880008F42092C24E5000130A67FFFAD02000C09
-:104890008F59093025020028A7860058AD1900104D
-:1048A0008F440938AD040014AD2B00048F58094023
-:1048B000AD380008934F09373C0D080091AD3CD04E
-:1048C000AD20001031EE00FF01CC1821000367007D
-:1048D000000D4400018858253567FFFFAD27000C07
-:1048E00003E00008AF4A002C3C09080095293CC0B1
-:1048F0003C05080094A53CCA3C0F080095EF3CBC61
-:1049000094E400243126FFFF00A6702101CF682324
-:1049100000041C0025A2FFF20062C825241808002C
-:10492000AD19000CAD180014AD0000100A0004C849
-:104930002508001894E6002494E500283C090800A6
-:1049400095293CC000067C000005740035ED81000F
-:1049500035C40800AD0D000CAD0400100A0004C8F9
-:10496000250800143C09080095293CC03C020800B9
-:1049700094423CCA3C06080094C63CBC94E4002423
-:104980003125FFFF94F800280045C821032678232D
-:1049900000181C0000046C0025EEFFEE006EC82518
-:1049A00035A2810024180800AD02000CAD190010DA
-:1049B000AD180018AD0000140A0004C82508001C3A
-:1049C0001460FF920000000094E300243C090800FA
-:1049D00095293CC00003140034590800AD19000C9F
-:1049E0000A0004C82508001003E00008240201F4AE
-:1049F00027BDFFE8AFB00010AFBF00140E0000608D
-:104A00000080802124050040AF4508148F830050AA
-:104A10008F84004C8F85005C007018210064102387
-:104A200018400004AF830050AF6300548F660054F9
-:104A3000AF86004C1200000C000000008F44007490
-:104A4000936800813409FA002D07000710E0000583
-:104A500000891021936C0081240B01F4018B500418
-:104A600001441021AF62000C8F4E095C01C5682320
-:104A700019A000048FBF00148F4F095CAF8F005C3A
-:104A80008FBF00148FB000100A00006227BD00180D
-:104A90008F8400648F8300508F82004CAF64004489
-:104AA000AF63005003E00008AF6200543C03800095
-:104AB000346200708C43000027BDFFF8308700FF90
-:104AC00030A900FF30C800FFAF8300308F44017869
-:104AD0000480FFFE3C028000345900708F380000D3
-:104AE000A3A700033C0708008CE700748FAC00000C
-:104AF0003C0608008CC60070030378233C0E7FFF41
-:104B000000EFC82135CDFFFF00005021018D282482
-:104B100000CA1821000847C0032F202B00A8102529
-:104B20000064C021AFA200003C010800AC39007451
-:104B30003C010800AC380070934F010AA3A00002AA
-:104B40003C0E80FFA3AF00018FAC0000312B007F33
-:104B500035CDFFFF018D4824000B5600012A40256A
-:104B6000240730002406FF803C05100027BD000804
-:104B7000AF48014CAF470154A7400158A34601522A
-:104B800003E00008AF45017827BDFFE8AFBF001480
-:104B9000AFB000108F6500743C068000309000FFBD
-:104BA00000A620250E000060AF640074936300052A
-:104BB000346200080E000062A3620005020020219A
-:104BC0008FBF00148FB000102405000524060001DB
-:104BD0000A00056E27BD001827BDFFE03C038000DA
-:104BE000AFB00010AFBF0018AFB100143462007056
-:104BF0008C470000309000FF30A800FFAF870030E6
-:104C00008F4401780480FFFE3C188000371100704B
-:104C10008E2F00003C0D08008DAD00743C0A08008A
-:104C20008D4A007001E7702301AE28210000582151
-:104C300000AE302B014B4821012638213C010800F1
-:104C4000AC250074000088213C010800AC270070EE
-:104C50001100000F000000008F6200742619FFFF92
-:104C60003208007F0002FE0233E5007F15000006D7
-:104C7000332200FF2407FF800207202624A3FFFF22
-:104C800000838025320200FF00408021241110089B
-:104C90000E000060000000008F4908183125000454
-:104CA00014A0FFFD3218007F001878C00018714072
-:104CB00001CF682125AC0088AF4C0818274A09802D
-:104CC0008D4B0020AF4B01448D460024AF46014878
-:104CD000A35001500E000062A7400158022010218D
-:104CE0008FBF00188FB100148FB0001003E00008D0
-:104CF00027BD002027BDFFE8308400FFAFBF0010B4
-:104D00000E0005B930A500FF8F8300508FBF001043
-:104D1000344500402404FF903C02100027BD0018D9
-:104D2000AF43014CA3440152AF45015403E00008D6
-:104D3000AF4201789343093E306200081040000DF5
-:104D40003C0901013528080AAC8800008F4700742F
-:104D5000AC8700043C06080090C63CD030C500106B
-:104D600050A00006AC8000088F6A0060AC8A000882
-:104D70002484000C03E00008008010210A000620B3
-:104D80002484000C27BDFFE8AFBF0014AFB00010B3
-:104D90009346093F00A05021000528800085382354
-:104DA00030C200FF240300063C09080095293CC6D8
-:104DB00024E8FFD82405000410430037240600022D
-:104DC0009750093C3C0F020400063400320EFFFFEE
-:104DD00001CF6825AC8D0000934C093E318B00203B
-:104DE0001160000800000000934309363C020103F3
-:104DF000345F0300307900FF033FC025240500081D
-:104E0000AC98000493430934935909210005F882B2
-:104E1000306200FF0002C082332F00FF00186E00D6
-:104E2000000F740001AE6025018920253C09400077
-:104E300000898025ACF0FFD8934309378F4F09488C
-:104E40008F580940306200FF004AC821033F70219B
-:104E500001F86023000E6F0001A650253185FFFF89
-:104E6000001F58800145482501683821AD09002000
-:104E70000E00006024F00028240400040E000062EC
-:104E8000A364003F020010218FBF00148FB00010F8
-:104E900003E0000827BD00180A00063324060012AC
-:104EA00027BDFFD024090010AFB60028AFB50024FD
-:104EB000AFB40020AFB10014AFB000103C01080047
-:104EC000A0293CD0AFBF002CAFB3001CAFB200187C
-:104ED00097480908309500FF3C02000E3107FFFF9C
-:104EE000000731C0AF46002C974409089344010BDA
-:104EF00030B400FF03428021308300300000B02135
-:104F00001060010700008821240C00043C01080007
-:104F1000A02C3CD0934B093E000B5600000A2E03F8
-:104F200004A0014B00000000AF400048934F010B6C
-:104F300031EE002011C00006000000009358093E29
-:104F400000189E00001396030640016B000000004D
-:104F50009344010B30830040106000038F93005096
-:104F60008F8200502453FFFF9347093E30E600082C
-:104F700014C0000224120003000090219619002C96
-:104F800093580934934F0937A7990058330C00FF01
-:104F900031EE00FF024E6821000D5880016C502157
-:104FA000015140213C010800A4283CC6920500188C
-:104FB00030A900FF010918213C010800A4233CC8C6
-:104FC00092110018162000032467000A0000000D4B
-:104FD0002467000A30F0FFFF3C010800A4233CCA0C
-:104FE0003C010800A4203CC03C010800A4203CBCBB
-:104FF0000E00009E020020210E00049A0040202195
-:105000008F4B002C974A09083C0C000E034C3821AA
-:105010003145FFFF000549C0AF49002C97430908FF
-:1050200094F1001A00404021241F00013226FFFFA6
-:10503000AC4600008CE2001CAD0200048CE40020B1
-:10504000AD04000890E3001930630003107F00D620
-:10505000286D000215A0011C240E0002106E010E26
-:10506000240F0003106F00E3000000003C0908005B
-:1050700095293CC0934E0934935109213C0A0800FC
-:10508000954A3CC631CD00FF94F9002A000D1882E4
-:1050900097870058322C00FF00032E00000C2400DC
-:1050A0003126FFFF3142FFFF00A4F82500464821CA
-:1050B00003E97825032770213C18400001F8682592
-:1050C000000E8C00AD0D0000AD110004934C0920C2
-:1050D0003C03000625110014000C2E0000A310252F
-:1050E000AD0200088F49092C24E40001309F7FFFA6
-:1050F000AD09000C8F46093025090028A79F0058EC
-:10510000AD0600108F59093801203021AD19001467
-:10511000AE3300048F580940AE380008934F09376A
-:105120003C0C0800918C3CD0AE20001031EE00FF0A
-:1051300001D26821000D2F00000C1C0000A31025D7
-:105140003447FFFFAE27000CAF4B002C934B093EBA
-:10515000317300081260000D3C0F010135E7080AA9
-:10516000AD0700288F4B0074AD2B00043C130800E2
-:1051700092733CD03268001051000003AD2000084B
-:105180008F780060AD3800082526000C12C000386A
-:1051900000000000935F093F241600062407000466
-:1051A00033F900FF133600D2240800029743093C6C
-:1051B0003C0C02043064FFFF008C2825ACC50000C5
-:1051C0009342093E304900201120000800000000F1
-:1051D000934B09363C130103366E0300316D00FF1B
-:1051E00001AE8825ACD10004240700089349093496
-:1051F00093590921314BFFFF313F00FF001FB0825F
-:10520000333800FF0016560000187C00014F982527
-:1052100000122880026B68253C0E400000C5502318
-:1052200001AE8825AD51FFD8934309378F5F0948F8
-:105230008F490940306C00FF019210210007208245
-:105240000044C82103E978230019C7000008B4000E
-:105250000316402531E7FFFF010730250E000060EF
-:10526000AD46FFF8241200040E000062A372003F56
-:105270000E0000C7020020213C12080092523CD0D0
-:10528000325000031200000F02A020218F82005034
-:1052900024470001AF870050AF6700508F6800546B
-:1052A0000107302318C0000200E020218F64005461
-:1052B000AF6400548F4C0074258401F4AF64000C7B
-:1052C00002A0202102802821A76000680E0005B9F5
-:1052D0003C1410008F8D005034550006AF4D014C2A
-:1052E0008F9100488FBF002C8FB600282623000125
-:1052F000AF8300488FB3001CA35101528FB2001836
-:10530000AF5501548FB10014AF5401788FB500240C
-:105310008FB400208FB0001003E0000827BD0030DC
-:105320009358093E00189E00001396030642005150
-:105330002411000293440923308300021060FEFB15
-:105340008F8600608F82005014C2FEF800000000BB
-:105350000E000060000000009369003F2407001663
-:10536000312800FF1107000C240500083C0C080040
-:10537000918C3CD0358B00013C010800A02B3CD027
-:10538000936A003F314300FF10650065240D000A59
-:10539000106D005E2402000C0E0000620000000090
-:1053A0000A00068E000000003C09080095293CC058
-:1053B0003C04080094843CCA3C1F080097FF3CBC96
-:1053C00094F800243123FFFF0083C821033F782392
-:1053D00000186C0025EEFFF201AE6025240A0800DB
-:1053E000AD0C000CAD0A0014AD0000100A0006E080
-:1053F000250800183C09080095293CC03C1F0800FE
-:1054000097FF3CCA3C19080097393CBC94EF002434
-:105410003124FFFF94EE002803E4C0210319682320
-:10542000000F2C00000E540025ACFFEE014C882527
-:1054300034A2810024060800AD02000CAD1100105A
-:10544000AD060018AD0000140A0006E02508001C97
-:105450008F6E00848F4D094011A0FEB3AF8E0050B7
-:10546000240F00143C010800A02F3CD00A00068D38
-:10547000000000003C010800A0313CD0935F093ED1
-:105480002416000133F900201720FEA8241100087B
-:105490000A00068E2411000494E5002494F10028EB
-:1054A0003C09080095293CC0000514000011340097
-:1054B0003444810034C30800AD04000CAD03001077
-:1054C0000A0006E0250800141460FEE80000000051
-:1054D00094FF00243C09080095293CC0001FCC0023
-:1054E00037380800AD18000C0A0006E02508001047
-:1054F0000A00072E240800128F7F004CAF7F005453
-:105500008F7900540A000697AF790050A362003FDC
-:105510000E000062000000000A00068E000000007D
-:10552000240200140A000807A362003F27BDFFE819
-:10553000308400FFAFBF00100E0005B930A500FF9A
-:105540009378007E9379007F936E00809368007A51
-:10555000332F00FF00186600000F6C0031CB00FFF6
-:10556000018D4825000B52008FBF0010012A3825FD
-:10557000310600FF3444700000E628252402FF8134
-:105580003C03100027BD0018AF45014CAF44015447
-:10559000A342015203E00008AF43017827BDFFD8C2
-:1055A000AFB20018AFB10014AFB00010AFBF002011
-:1055B000AFB3001C93420109308600FF30B000FFFA
-:1055C000000618C232040002307100011480000588
-:1055D000305200FF9367000530E5000810A0000D71
-:1055E00030C80010024020210E0005A5022028210D
-:1055F000240400018FBF00208FB3001C8FB200185D
-:105600008FB100148FB000100080102103E000085B
-:1056100027BD002815000032000000009343010957
-:10562000000028213062007F000220C00002F94003
-:1056300003E4982126790088033B98218E78002482
-:105640008E6F0008130F0046000000008F64008476
-:10565000241800020004FD8233F900031338007C93
-:105660000000000093660083934A0109514600043C
-:105670003205007C10A00060000000003205007CB4
-:1056800014A000530240202116200006320400011D
-:105690008E7F00248F59010417F9FFD600002021C6
-:1056A000320400011080000A024020218F4209408C
-:1056B0008F93006410530006000000000E00066B7C
-:1056C000022028218F430940AF630044024020217B
-:1056D0000E000600022028210A00084024040001D0
-:1056E0003C0908008D290064252600013C010800C2
-:1056F000AC26006416000012000000008F6D0084CC
-:105700003C0E00C001AE602415800005024020213F
-:105710000E00080E022028210A000840240400017F
-:10572000240500040E00056E24060001024020211D
-:105730000E00080E022028210A000840240400015F
-:105740000E00004124040001936B007D020B5025E4
-:105750000E000062A36A007D0A0008838F6D00843A
-:105760008F6600748F4801048E67002400064E0285
-:105770001507FFB63126007F936B00832644000196
-:10578000308A007F11460043316300FF5464FFB04C
-:105790008F6400842645000130B1007F30A200FFF5
-:1057A0001226000424050001004090210A0008563A
-:1057B00024110001240FFF80024F702401CF902696
-:1057C000324200FF004090210A00085624110001D7
-:1057D0000E00066B02202821321800301300FFAAA9
-:1057E00032100082024020210E0005A5022028214F
-:1057F0000A000840240400018F6E00743C0F8000F2
-:105800002405000301CF9025AF72007493710083CB
-:10581000240600010E00056E322400FF0E00004138
-:1058200024040001936D007D020D60250E000062CE
-:10583000A36C007D3C0B08008D6B005425700001AB
-:105840003C010800AC3000540A0008402404000168
-:105850008F6800743C098000240500040109382584
-:10586000AF67007493630083240600010E00056E89
-:10587000306400FF0E000041240400019362007DAB
-:10588000020298250E000062A373007D0A00084002
-:1058900024040001324D008039AC0080546CFF6C50
-:1058A0008F6400840A0008A92645000127BDFFC8AF
-:1058B0003C0A0008AFBF0030AFB5002CAFB40028E1
-:1058C000AFB30024AFB20020AFB1001CAFB00018DE
-:1058D000034AD82124090040AF490814AF400810FA
-:1058E0008F4209448F4309508F4609548F47095C02
-:1058F0008F48094C934401089345010BAF82006423
-:10590000308400FF30A500FFAF830050AF86004C0D
-:10591000AF87005C0E00082AAF8800601440017455
-:105920008FBF0030A7600068934D0900240B005022
-:105930003C15080026B53C8831AC00FF3C1208003D
-:1059400026523C98118B0003000000000000A821A3
-:1059500000009021935101098F9F005024040010F2
-:10596000322E007F000E68C0000E6140018D28219C
-:1059700024B40088AF5408188F4901048F4A09A441
-:105980003C0B000E034BC021012A10233C010800F0
-:10599000AC223CAC8F4309583C010800A0243CD009
-:1059A00097470908007F30233C010800AC263CB033
-:1059B00030E8FFFF0008C9C03C010800AC3F3CD400
-:1059C000AF59002C974209089710002C8EB10000A7
-:1059D000930F001803749821A7900058AF930044C8
-:1059E0000220F80931F000FF304E000215C001A975
-:1059F000304F000111E0015D000000009343093EBB
-:105A00003066000814C00002241400030000A02126
-:105A10008F5809A4241300013C010800AC383CD87D
-:105A2000934F09349351093731EC00FF322E00FFB8
-:105A3000028E6821000D288000AC502101505821B1
-:105A40003C010800A42B3CC83C010800A42A3CC629
-:105A500093490934312200FF0202202124900010D2
-:105A60003C010800A4303CC4240700068F9F00506E
-:105A70003C010800AC273CCC8F88005C8F5909584A
-:105A800000008021011F282304A00151033F20238F
-:105A90000480014F00A4302B10C001510000000011
-:105AA0003C010800AC253CB08E4200000040F809E3
-:105AB0000000000030430002146000F10040882123
-:105AC00030440001548000108E4200043C0908005C
-:105AD0008D293CB43C0AC000012A8025AF500E003D
-:105AE0008F45000030AB00081160FFFD0000000092
-:105AF000974D0E0824100001A78D003C8F4C0E041A
-:105B0000AF8C00348E4200040040F8090000000011
-:105B100002228825322E000215C0016F000000000D
-:105B20003C09080095293CBC3C06080094C63CC8CA
-:105B30003C04080094843CBE3C1808008F183CB418
-:105B4000012658213C0F08008DEF3CD83C1F08006F
-:105B500097FF3CD2016418218F4D09400309C821E9
-:105B6000246E0002033F282101F860213C01080057
-:105B7000A42B3CCAAF8D00643C010800AC2C3CD87F
-:105B80003C010800A4253CC00E00009E31C4FFFF6C
-:105B90008F870048004020213C010800A0273CD10D
-:105BA0008E42000824E80001AF8800480040F80950
-:105BB000000000008F4B002C974909083C0A000E9A
-:105BC000034A38213124FFFF000419C08F8A005096
-:105BD000AF43002C9743090894E6001A0040402187
-:105BE00030DFFFFFAC5F00008CF9001CAC590004F3
-:105BF0008CF80020AC58000890EF001931E3000346
-:105C0000107300FB0000000028620002144001171E
-:105C10002405000210650109240C0003106C00BC6F
-:105C2000000000003C09080095293CC0935F09343E
-:105C3000934C09213C0D080095AD3CC633F900FF9B
-:105C400094E5002A0019C082318F00FF978C00581C
-:105C500000181600000F74003124FFFF004E382595
-:105C600001A4302100E6F82500ACC8213C03400027
-:105C700003E3C02500194C00AD180000AD09000475
-:105C8000934F09203C0E000625090014000F6E00FA
-:105C900001AE2825AD0500088F46092C258200019C
-:105CA00030477FFFAD06000C8F440930A7870058AE
-:105CB00025060028AD0400108F43093800C02021BC
-:105CC000AD030014AD2A00048F5F0940AD3F00080A
-:105CD000935909373C0E080091CE3CD0AD200010FE
-:105CE000333800FF03147821000F6700000E6C00AA
-:105CF000018D282534A2FFFFAD22000CAF4B002CF4
-:105D00009347093E30EA00085140000F8E58000CBE
-:105D10003C0301013469080AAD0900288F4A007468
-:105D2000ACCA00043C0B0800916B3CD031680010F9
-:105D300051000003ACC000088F650060ACC50008CE
-:105D400024C4000C8E58000C0300F8090000000069
-:105D50003C0F080095EF3CCA3C02080094423CBE50
-:105D600001E2702125C400020E0000C73084FFFF4D
-:105D70003C0608008CC63CAC3C0D08008DAD3CB424
-:105D800000CD38233C010800AC273CAC14E00006F1
-:105D9000000000003C1908008F393CCC372C004033
-:105DA0003C010800AC2C3CCC120000858F8B0044D9
-:105DB0008F480E108F900044AE0800208F5F0E18A1
-:105DC000AE1F00243C10080096103CC00E0000607E
-:105DD0000000000024050040AF4508148F830050E8
-:105DE0008F89004C0070182100695023194000046D
-:105DF000AF830050AF6300548F670054AF87004CEF
-:105E00001200000C000000008F440074936D0081AC
-:105E1000340EFA002DA6000710C00005008E1821D0
-:105E200093780081240201F40302780401E418212C
-:105E3000AF63000C8F4C095C8F99005C01992023A3
-:105E400018800003000000008F50095CAF90005CD8
-:105E50000E000062000000008F8B00508E48001082
-:105E60003C010800AC2B3CD40100F8090000000004
-:105E70003C1F08008FFF3CAC17E0FEFC2407000627
-:105E80008F450024974209088F8A00648F94005040
-:105E90003C0F001F978700588F8300548F93004C4E
-:105EA000304DFFFF35EEFF8000AE4824000D31C0BD
-:105EB00032320010AF460024A467002CAF49002402
-:105EC000AF6A0044AF740050AF7300545640007E78
-:105ED0008EB8000432240040548000328EB1000895
-:105EE0008EAC000C0180F809000000008FBF00306C
-:105EF0008FB5002C8FB400288FB300248FB2002000
-:105F00008FB1001C8FB0001803E0000827BD0038D7
-:105F10003C09080095293CC03C04080094843CCA14
-:105F20003C1F080097FF3CBC94F800243123FFFF7E
-:105F300094EF00280083C821033F702300182C0031
-:105F4000000F640025CDFFEE018D302534A28100C5
-:105F500024030800AD02000CAD060010AD030018CC
-:105F6000AD0000140A0009CE2508001C9347010962
-:105F70008F8800380007FE0003E8C825AF5900806D
-:105F80008F5809A08F5309A4AFB80010AF580E1452
-:105F90008FB40010AF540E10AF530E1C0A0009420C
-:105FA000AF530E180220F809000000008EAC000C60
-:105FB0000180F809000000000A000A7F8FBF00304E
-:105FC000A5600020A57300220A000A34AD730024E6
-:105FD0003C010800AC203CB00A00096E8E42000073
-:105FE0003C010800AC243CB00A00096E8E4200005F
-:105FF0003C09080095293CC03C1F080097FF3CCA9B
-:106000003C19080097393CBC94EF00243124FFFF71
-:1060100003E4C02103197023000F640025CDFFF2B3
-:10602000018D2825AC45000C24020800AD020014A7
-:10603000AD0000100A0009CE2508001894E60024DF
-:1060400094E300283C09080095293CC00006240080
-:106050000003FC003499810037F80800AD19000CEA
-:10606000AD1800100A0009CE250800141460FEEDDA
-:106070000000000094EF00243C09080095293CC072
-:10608000000F740035CD0800AD0D000C0A0009CEDC
-:106090002508001093520109000028210E00060077
-:1060A000324400FF8FBF00308FB5002C8FB4002822
-:1060B0008FB300248FB200208FB1001C8FB0001866
-:1060C00003E0000827BD00380300F80900000000C5
-:1060D0000A000A79322400401200FF690000000023
-:1060E0008F540E148F920044AE5400208F530E1C18
-:1060F0000A000A63AE5300248F82001C00804021F6
-:106100003C0401009047008530E300201060000946
-:10611000000000003C0708008CE73CD48F83001887
-:1061200000E32023048000089389000414E30003A3
-:106130000100202103E00008008010213C04010040
-:1061400003E00008008010211120000B00673823B5
-:106150008F8C002024090034918B00BC316A00022E
-:10616000514000012409003000E9682B15A0FFF11F
-:106170000100202100E938232419FFFC00B9C024C4
-:1061800000F9782400F8702B15C0FFEA01E82021FF
-:1061900030C200030002182314C00012306900034B
-:1061A0000000302100A9702101C6682100ED602B9C
-:1061B0001180FFE03C0401002D2F00010006482B58
-:1061C0000105382101E9302414C0FFDA24E4FFFC82
-:1061D0002419FFFC00B9C0240308202103E00008B3
-:1061E000008010218F8B002024060004916A00BCDF
-:1061F000314400041480FFEC00A970210A000B2D2B
-:106200000000302127BDFFE8AFBF00108F4601001E
-:10621000934A01093C1F08008FFF00902407FF806C
-:10622000314F00FF31E8007F0008614003E6C821DC
-:10623000032CC02127090120012770243C010800FC
-:10624000A02F3D10AF4E080C3C0D08008DAD009006
-:106250003C0400803482000301A65821016C1821FF
-:106260002465012030AA007801424025AF48081C6F
-:106270003C1F08008FFF00908F88004003E6C0217C
-:106280003319000703074824033A7821AF4900284F
-:1062900025E909C0952E00023C0D08008DAD008C4B
-:1062A0003C0A08008D4A009031CC3FFF01A618211E
-:1062B000000C5980006B282100A72024AF44002C3B
-:1062C000952200023C1F08008FFF008C910700857B
-:1062D00030593FFF03E678210019C1800146702143
-:1062E00001F8682131CC007F31AB007F019A282171
-:1062F000017A50213C03000C3C04000E00A328212D
-:106300000144102130E6002027470980AF82002C8D
-:10631000AF88001CAF890024AF85002010C00006A4
-:10632000AF8700288D0200508CA4010C004430235C
-:1063300018C0007700000000910C0085240DFFDFDD
-:10634000018D3824A10700858F8B001C8F890024C4
-:106350008F8700288D65004CAF850018912F000DA8
-:1063600031EE002011C000170000000024090001D8
-:10637000A3890004AF80000C8CE400248F85000CFE
-:10638000240A0008AF800008AF8000103C0108001C
-:10639000A42A3CBE3C010800A4203CD20E000B0104
-:1063A000000030218F8500248FBF0010AF820014C1
-:1063B00090A8000D27BD00180008394203E000082E
-:1063C00030E20001913F00022418000133F900FF80
-:1063D0000019218210980039240800021088005BFF
-:1063E0008F86002C8CE5002414A0001B8F9F0020BA
-:1063F00091220000240A00053046003F10CA0047E1
-:10640000240400018F860008A3840004AF860010D6
-:10641000AF86000C8CE400248F85000C240A000851
-:106420003C010800A42A3CBE3C010800A4203CD248
-:106430000E000B01000000008F8500248FBF0010AC
-:10644000AF82001490A8000D27BD00180008394243
-:1064500003E0000830E200018CF800088CF9002409
-:106460008FEE00C4A38000048CE40024AF8E000CE7
-:106470008F85000C8F86000803197823240A0008F2
-:10648000AF8F00103C010800A42A3CBE3C0108006C
-:10649000A4203CD20E000B01000000008F850024D8
-:1064A0008FBF0010AF82001490A8000D27BD001808
-:1064B0000008394203E0000830E2000191230000A7
-:1064C0003062003F104400278F8500208CE40024B8
-:1064D00014800021000000008D2E00183C187FFF62
-:1064E0008F850020370FFFFF01CF1824AF830008EE
-:1064F0008F9F00088CA8008403E8C82B1720000297
-:1065000003E020218CA400840A000BBCAF840008A7
-:106510008CA3010C0A000B9AAF8300188D2C001875
-:106520008F8600083C0D7FFF8F89002035A3FFFF79
-:106530000183582424040001AF8B0010AD2000CC4F
-:10654000A38400040A000BC8AF86000C8CCA001498
-:106550000A000BBCAF8A00088CA300C80A000BFF1E
-:10656000AF8300088F84002C8CAC00648C8D0014E9
-:10657000018D582B11600004000000008CA2006403
-:106580000A000BFFAF8200088C8200140A000BFF88
-:10659000AF8200088F85000C27BDFFE0AFBF001859
-:1065A000AFB1001414A00007AFB000108F86002414
-:1065B0002402000590C400003083003F106200B642
-:1065C0008F8400208F91000800A080218F8C0028EC
-:1065D0003C0508008CA53CB08D8B000431663FFF64
-:1065E00000C5502B5540000100C02821938D0004A8
-:1065F00011A0007300B0F82B8F9800202404003401
-:10660000930F00BC31EE000251C0000124040030A1
-:1066100000A4C82B172000D10000000000A42823EC
-:1066200000B0F82B3C010800A4243CBC17E0006833
-:10663000020020213C0308008C633CAC0083102B3B
-:1066400054400001008018218F8800243C0108007C
-:10665000AC233CB4000048219104000D308300209D
-:10666000506000018F490E188F8300140123382BCE
-:1066700010E00059000000003C0408008C843CB489
-:1066800000895821006B502B114000560090602B60
-:106690000069302300C020213C010800AC263CB436
-:1066A00012000003241FFFFC1090008A3227000311
-:1066B000009FC8243C010800AC393CB43C010800F0
-:1066C000A4203CD28F84000C120400078F8300208A
-:1066D000AF910008020020218C7100CCAF90000C1B
-:1066E00026300001AC7000CC3C0208008C423CB467
-:1066F0008F8A0010240700180082202301422823DB
-:10670000AF84000C10800002AF8500102407001039
-:106710008F86001C3C010800A0273CD024070040C5
-:1067200090CC0085318B00C0116700408F8D001424
-:1067300014A0001500002021934A01098F4209741A
-:10674000314500FF0002260224A300013090007FA3
-:106750003071007F1230007A2407FF80A0C30083CD
-:106760003C0908008D293CCC8F880024240D0002B0
-:10677000352C00083C010800A02D3D113C0108000B
-:10678000AC2C3CCC24040010910E000D31C600202E
-:1067900010C0000500801821240800013C010800F9
-:1067A000AC283CB4348300018FBF00188FB10014B3
-:1067B0008FB000100060102103E0000827BD00200A
-:1067C0003C010800A4203CBC13E0FF9A02002021F9
-:1067D0000A000C5000A020213C0408008C843CB42A
-:1067E0000090602B1180FFAE000000003C0F0800FD
-:1067F00095EF3CBC01E4702101C6682B11A0000795
-:106800002C8200043C1F60008FF954043338003F91
-:106810001700FFE5240300422C8200041040FFA073
-:10682000240300420A000CAE8FBF0018152DFFC0D4
-:10683000000000008CDF00743C0380002405FF8012
-:1068400003E3C825ACD9007490D80085240E000459
-:1068500024040010330F003F01E54025A0C8008547
-:106860008F8800243C010800A02E3D112403000164
-:106870009106000D30C90020152000030000000023
-:106880003C0308008C633CB43C010800AC233CACE6
-:106890000A000CA5000000008F8700108C8800847F
-:1068A00000E8282B14A0000200E088218C910084CD
-:1068B00024090001A38900048F440E180220282116
-:1068C0000E000B0102203021022080210A000C362C
-:1068D000AF82001400071823306600033C01080053
-:1068E000A4263CD2122000058F8C0020918B00BC86
-:1068F000316A00041540001524CD00043C0F080047
-:1069000095EF3CD201E4702100AE302B50C0FF6EF9
-:106910008F84000C2C85000514A0FFA324030042E3
-:106920003098000317000002009818232483FFFC0E
-:106930003C010800AC233CB40A000C7200000000CB
-:1069400000A758240A000C9A016718263C01080089
-:10695000A42D3CD20A000D02000000003C010800FA
-:10696000AC203CB40A000CAD240300428F8300101D
-:1069700014600007000010218F8800242405000502
-:106980009106000030C400FF1085000300000000E5
-:1069900003E0000800000000910A0018314900FFE0
-:1069A000000939C214E0FFFA8F85001C3C0408007E
-:1069B00094843CBC3C0308008C633CD43C19080024
-:1069C0008F393CB43C0F080095EF3CD20064C021E5
-:1069D0008CAD00540319702101CF6021018D582323
-:1069E0001960001D00000000910E001C8F8C002C0F
-:1069F000974B0E1031CD00FF8D850004016D3023C3
-:106A00008D88000030CEFFFF000E510000AAC82183
-:106A10000000382101072021032A182B0083C02100
-:106A2000AD990004AD980000918F000A01CF682154
-:106A3000A18D000A8F88002C974B0E12A50B000821
-:106A4000950A003825490001A50900389107000D75
-:106A500034E60008A106000D03E000080000000075
-:106A600027BDFFE0938700048F8F00248FAD0014B3
-:106A70003C0E7FFF8F89000C35C8FFFFAFBF001CA5
-:106A8000AFB0001801A8182491EA000D000717C044
-:106A90003C1FBFFF006258252D2E00018F9000186B
-:106AA00037F9FFFF3C1808008F183CD43C0F080052
-:106AB00095EF3CCA01796824000E47803C07EFFF40
-:106AC0003C05F0FF01A818253149002034E2FFFF02
-:106AD00034ACFFFF0310582327A500102406000242
-:106AE00025EA00020062182400808021152000029F
-:106AF000000040218F480E1CA7AA00120560003735
-:106B00002407000030FF00FF001FCF008F8B001C08
-:106B100000793825AFA70014916F00853C08080064
-:106B200091083CD13C18DFFF31EE00C0370AFFFF6F
-:106B3000000E182B3C1F080097FF3CC400EA682495
-:106B4000A3A800110003174001A248258FB9001027
-:106B5000AFA900143C0A0800914A3CD3A7BF001615
-:106B60008FA80014032CC0243C0B01003C0F0FFF26
-:106B7000030B18253147000335EEFFFF010C682495
-:106B800000071600006EF8243C09700001A2C82519
-:106B900003E95825AFB90014AFAB00100E00007622
-:106BA000A3A000158F8C0024260200089186000DFA
-:106BB00030C40020108000068FBF001C3C05080078
-:106BC00094A53CC024B0FFFF3C010800A4303CC0A9
-:106BD0008FB0001803E0000827BD00208F98001434
-:106BE0000118502B5540FFC7240700010A000D85EE
-:106BF00030FF00FF9382000427BDFFE0AFBF001805
-:106C00001040000F008050218F880024240B0005C5
-:106C10008F890008910700008F840020010028213F
-:106C200030E3003F8F86002C106B000800003821F5
-:106C3000AFA900100E00040EAFAA0014A380000438
-:106C40008FBF001803E0000827BD00208D19001831
-:106C50003C0F08008DEF3CB48F9800103C027FFF82
-:106C60008D080014345FFFFF033F682401F8702192
-:106C700001AE602301883821AFA900100E00040E78
-:106C8000AFAA00140A000DD3A38000048F8700244C
-:106C90003C05080094A53CD23C0208008C423CCC48
-:106CA00090E6000D0005240030C300201060002C89
-:106CB000004440258F85001C00006021240B00014A
-:106CC00090A3008500004821240A00013C0F8000A9
-:106CD00035EE00708DC70000AF8700308F58017807
-:106CE0000700FFFE3C038000347900708F380000FD
-:106CF0003C0508008CA500743C0D08008DAD0070AB
-:106D00000307782300AF38210000102100EF302B5B
-:106D100001A22021008618213C010800AC27007444
-:106D20003C010800AC230070AF4B01483C1908003F
-:106D30008F393CD4A7490144A74A0146AF59014CB9
-:106D40003C0B0800916B3CD1A34B0152AF4801545E
-:106D50003C081000A74C015803E00008AF48017838
-:106D60008F4B0E1C3C0A08008D4A3CB497490E1606
-:106D7000974D0E1401456021312AFFFF0A000DF6E0
-:106D800031A9FFFF8F8300249064000D3082002022
-:106D900010400029000000000000482100005021A0
-:106DA000000040213C07800034EB00708D6700003C
-:106DB000AF8700308F4C01780580FFFE3C0D8000CE
-:106DC00035AC00708D8B00003C0508008CA500746C
-:106DD0003C0408008C8400700167302300A67821F1
-:106DE0000000102101E6C82B0082C0210319702188
-:106DF0003C010800AC2F00743C010800AC2E007070
-:106E0000AF4901483C0D08008DAD3CD4A748014472
-:106E100024090040A74A01463C081000240AFF91BB
-:106E2000AF4D014CA34A0152AF490154A74001584C
-:106E300003E00008AF4801788F490E1897460E12FC
-:106E400097450E1030CAFFFF0A000E2C30A8FFFF36
-:106E50008F83002427BDFFF89064000D308200204E
-:106E60001040003A00000000240B000100004821FF
-:106E7000240A00013C088000350700708CE3000004
-:106E8000AF8300308F4C01780580FFFE3C0E800000
-:106E90003C04080090843D1035C700708CEC000065
-:106EA0003C0508008CA50074A3A400033C1908004D
-:106EB0008F3900708FAD00000183302300A6382188
-:106EC000000010210322782100E6C02B01F8602188
-:106ED00001AE4025AFA800003C010800AC270074BB
-:106EE0003C010800AC2C00709346010A3C040800E9
-:106EF00090843D11A3A00002A3A600018FA300006F
-:106F00003C0580FF3099007F34A2FFFF00627824A7
-:106F10000019C60001F87025240D3000AF4E014C59
-:106F200027BD0008AF4D0154A7400158AF4B0148A1
-:106F3000A7490144A74A01463C091000240AFF80E2
-:106F4000A34A015203E00008AF4901788F4B0E18A5
-:106F500097460E1297450E1030CAFFFF0A000E60CA
-:106F600030A9FFFF8F85001C2402008090A40085BB
-:106F7000308300C0106200058F8600208F880008D3
-:106F80008F87000CACC800C8ACC700C403E0000881
-:106F9000000000003C0A0800254A38903C0908001F
-:106FA0002529395C3C08080025082D103C070800FD
-:106FB00024E73A703C06080024C637003C05080068
-:106FC00024A534783C040800248430A03C03080045
-:106FD000246337983C0208002442356C3C010800C9
-:106FE000AC2A3C903C010800AC293C8C3C010800D8
-:106FF000AC283C883C010800AC273C943C010800CC
-:10700000AC263CA43C010800AC253C9C3C0108009B
-:10701000AC243C983C010800AC233CA83C0108008F
-:0C702000AC223CA003E0000800000000CF
-:00000001FF
-/*
- * This file contains firmware data derived from proprietary unpublished
- * source code, Copyright (c) 2004 - 2009 Broadcom Corporation.
- *
- * Permission is hereby granted for the distribution of this firmware data
- * in hexadecimal or equivalent format, provided this copyright notice is
- * accompanying it.
- */
diff --git a/firmware/bnx2/bnx2-mips-06-6.0.15.fw.ihex b/firmware/bnx2/bnx2-mips-06-6.0.15.fw.ihex
new file mode 100644
index 000000000000..e9bbdc3b0397
--- /dev/null
+++ b/firmware/bnx2/bnx2-mips-06-6.0.15.fw.ihex
@@ -0,0 +1,5815 @@
+:10000000080001180800000000004A68000000C84D
+:1000100000000000000000000000000008004A6826
+:100020000000001400004B30080000A00800000091
+:100030000000568800004B4408005800000000846F
+:100040000000A1CC08005688000001580000A25012
+:100050000800321008000000000072D00000A3A8C1
+:10006000000000000000000000000000080072D046
+:100070000000002400011678080004900800040025
+:10008000000017D40001169C0000000000000000D2
+:100090000000000000000000000000000000000060
+:1000A000080000A80800000000003BFC00012E70C2
+:1000B0000000000000000000000000000000000040
+:0800C000000000000000000038
+:0800C8000A00004600000000E0
+:1000D000000000000000000D636F6D362E302E31E1
+:1000E0003500000006000F020000000000000003C1
+:1000F000000000C800000032000000030000000003
+:1001000000000000000000000000000000000000EF
+:1001100000000010000001360000EA600000000549
+:1001200000000000000000000000000000000008C7
+:1001300000000000000000000000000000000000BF
+:1001400000000000000000000000000000000000AF
+:10015000000000000000000000000000000000009F
+:10016000000000020000000000000000000000008D
+:10017000000000000000000000000000000000007F
+:10018000000000000000000000000010000000005F
+:10019000000000000000000000000000000000005F
+:1001A000000000000000000000000000000000004F
+:1001B000000000000000000000000000000000003F
+:1001C000000000000000000000000000000000002F
+:1001D000000000000000000000000000000000001F
+:1001E0000000000010000003000000000000000DEF
+:1001F0000000000D3C02080024424AA03C03080015
+:1002000024634B9CAC4000000043202B1480FFFD76
+:10021000244200043C1D080037BD7FFC03A0F021F0
+:100220003C100800261001183C1C0800279C4AA01E
+:100230000E000168000000000000000D27470100CB
+:1002400090E3000B2402001A94E5000814620028D1
+:10025000000020218CE200003C0308008C63004475
+:1002600094E60014000211C20002104030A4000203
+:10027000005A10212463000130A50004A446008028
+:100280003C010800AC23004410A000190004202BFE
+:100290008F4202B804410008240400013C02080017
+:1002A0008C420060244200013C010800AC22006046
+:1002B00003E00008008010218CE2002094E3001687
+:1002C00000002021AF4202808CE20004A743028498
+:1002D000AF4202883C021000AF4202B83C02080064
+:1002E0008C42005C244200013C010800AC22005C0E
+:1002F00003E00008008010212747010090E3000B75
+:100300002402000394E50008146200280000202164
+:100310008CE200003C0308008C63004494E6001467
+:10032000000211C20002104030A40002005A102145
+:100330002463000130A50004A44600803C010800AD
+:10034000AC23004410A000190004202B8F4202B8F7
+:1003500004410008240400013C0208008C420060B3
+:10036000244200013C010800AC22006003E00008C8
+:10037000008010218CE2002094E300160000202170
+:10038000AF4202808CE20004A7430284AF4202889D
+:100390003C021000AF4202B83C0208008C42005CF4
+:1003A000244200013C010800AC22005C03E000088C
+:1003B000008010218F4301002402010050620003DD
+:1003C000000311C20000000D000311C20002104022
+:1003D000005A1021A440008003E000080000102112
+:1003E0009362000003E00008AF80000003E0000813
+:1003F0000000102103E00008000010212402010089
+:1004000014820008000000003C0208008C4200FC3E
+:10041000244200013C010800AC2200FC0A0000DD7F
+:1004200030A200203C0208008C42008424420001DB
+:100430003C010800AC22008430A2002010400008DB
+:1004400030A300103C0208008C4201082442000145
+:100450003C010800AC22010803E000080000000095
+:1004600010600008000000003C0208008C420104FB
+:10047000244200013C010800AC22010403E0000812
+:10048000000000003C0208008C42010024420001F0
+:100490003C010800AC22010003E00008000000005D
+:1004A00027BDFFE8AFBF0010274401009483000878
+:1004B000306200041040001B306600028F4202B818
+:1004C00004410008240500013C0208008C42006041
+:1004D000244200013C010800AC2200600A0001290E
+:1004E0008FBF00108C82002094830016000028210A
+:1004F000AF4202808C820004A7430284AF4202888C
+:100500003C021000AF4202B83C0208008C42005C82
+:10051000244200013C010800AC22005C0A000129D1
+:100520008FBF001010C00006006028218F4401001A
+:100530000E0000CD000000000A0001282405000183
+:100540008F8200088F4301045043000700002821D8
+:100550008F4401000E0000CD000000008F42010416
+:10056000AF820008000028218FBF001000A01021DA
+:1005700003E0000827BD001827BDFFE8AFBF001447
+:10058000AFB00010974201083043700024022000F1
+:100590001062000B286220011440002F000010217F
+:1005A00024024000106200250000000024026000C8
+:1005B00010620026000010210A0001658FBF0014A0
+:1005C00027500100920200091040001A2403000184
+:1005D0003C0208008C420020104000160000182148
+:1005E0000E00049300000000960300083C0608007B
+:1005F00094C64B5E8E0400188F8200209605000C76
+:1006000000031C0000661825AC440000AC45000443
+:1006100024040001AC400008AC40000CAC400010C9
+:10062000AC400014AC4000180E0004B8AC43001CF1
+:10063000000018210A000164006010210E0003254B
+:10064000000000000A000164000010210E000EE905
+:1006500000000000000010218FBF00148FB00010B8
+:1006600003E0000827BD001827BDFFE0AFB2001867
+:100670003C036010AFBF001CAFB10014AFB000105E
+:100680008C6450002402FF7F3C1A800000822024EA
+:100690003484380C24020037AC6450003C1208004B
+:1006A00026524AD8AF42000824020C80AF420024F0
+:1006B0003C1B80083C06080024C60324024010218D
+:1006C0002404001D2484FFFFAC4600000481FFFDCC
+:1006D000244200043C020800244204B03C0108000B
+:1006E000AC224AE03C020800244202303C010800EF
+:1006F000AC224AE43C020800244201743C03080096
+:100700002463032C3C040800248403D83C0508001F
+:1007100024A538F03C010800AC224B403C02080004
+:10072000244202EC3C010800AC264B243C010800AA
+:10073000AC254B343C010800AC234B3C3C01080089
+:10074000AC244B443C010800AC224B483C0108005F
+:10075000AC234ADC3C010800AC204AE83C0108001C
+:10076000AC204AEC3C010800AC204AF03C010800F7
+:10077000AC204AF43C010800AC204AF83C010800D7
+:10078000AC204AFC3C010800AC204B003C010800B6
+:10079000AC244B043C010800AC204B083C01080091
+:1007A000AC204B0C3C010800AC204B103C01080075
+:1007B000AC204B143C010800AC204B183C01080055
+:1007C000AC264B1C3C010800AC264B203C01080029
+:1007D000AC254B303C010800AC234B380E000623FF
+:1007E000000000003C028000344200708C42000097
+:1007F000AF8200143C0308008C6300208F82000449
+:10080000104300043C0280000E00045BAF83000430
+:100810003C028000344600703C0308008C6300A05A
+:100820003C0208008C4200A4104300048F84001492
+:100830003C010800AC2300A4A743009E8CCA000022
+:100840003C0308008C6300BC3C0208008C4200B8EA
+:100850000144202300641821000040210064202B63
+:1008600000481021004410213C010800AC2300BCCA
+:100870003C010800AC2200B88F5100003222000772
+:100880001040FFDCAF8A00148CC600003C05080055
+:100890008CA500BC3C0408008C8400B800CA30233E
+:1008A00000A628210000102100A6302B0082202164
+:1008B00000862021322700013C010800AC2500BC45
+:1008C0003C010800AC2400B810E0001F32220002F6
+:1008D0008F420100AF4200208F420104AF4200A8C6
+:1008E0009342010B0E0000C6305000FF2E02001E86
+:1008F00054400004001010800E0000C90A000213CA
+:1009000000000000005210218C4200000040F80955
+:1009100000000000104000053C0240008F4301042D
+:100920003C026020AC4300143C024000AF4201385E
+:100930003C0208008C420034244200013C010800C3
+:10094000AC220034322200021040000E3222000499
+:100950008F4201400E0000C6AF4200200E000295FB
+:10096000000000003C024000AF4201783C02080059
+:100970008C420038244200013C010800AC220038BF
+:10098000322200041040FF983C0280008F42018018
+:100990000E0000C6AF4200208F43018024020F00EA
+:1009A00014620005000000008F420188A742009CED
+:1009B0000A0002483C0240009362000024030050F9
+:1009C000304200FF144300083C0240000E00027B4E
+:1009D00000000000544000043C0240000E000D7571
+:1009E000000000003C024000AF4201B83C02080099
+:1009F0008C42003C244200013C010800AC22003C37
+:100A00000A0001C83C0280003C0290003442000110
+:100A100000822025AF4400208F4200200440FFFECA
+:100A20000000000003E00008000000003C0280001D
+:100A3000344200010082202503E00008AF4400207A
+:100A400027BDFFE0AFB10014AFB0001000808821D7
+:100A5000AFBF00180E00025030B000FF9362007D5F
+:100A60000220202102028025A370007D8F70007477
+:100A70003C0280000E000259020280241600000988
+:100A80008FBF00188F4201F80440FFFE24020002CD
+:100A9000AF5101C0A34201C43C021000AF4201F8B3
+:100AA0008FBF00188FB100148FB0001003E0000852
+:100AB00027BD002027BDFFE8AFBF0010974201848B
+:100AC0008F440188304202001040000500002821B8
+:100AD0000E000FAA000000000A00028D240500018C
+:100AE0003C02FF0004800005008218243C02040040
+:100AF000506200019362003E240500018FBF001088
+:100B000000A0102103E0000827BD0018A360002208
+:100B10008F4401400A00025E2405000127BDFFE862
+:100B2000AFBF0014AFB0001093620000304400FF6C
+:100B300038830020388200300003182B0002102B6D
+:100B40000062182410600003240200501482008008
+:100B50008FBF001493620005304200011040007CFA
+:100B60008FBF0014934201482443FFFF2C6200050D
+:100B7000104000788FB00010000310803C03080084
+:100B800024634A68004310218C42000000400008A2
+:100B9000000000000E0002508F4401408F70000CD6
+:100BA0008F4201441602000224020001AF62000CD1
+:100BB0000E0002598F4401408F420144145000043A
+:100BC0008FBF00148FB000100A000F2027BD00183F
+:100BD0008F62000C0A0003040000000097620010FE
+:100BE0008F4301443042FFFF1462001A00000000EE
+:100BF00024020001A76200108F4202380443001053
+:100C00008F4201403C02003F3446F0003C0560004A
+:100C10003C04FFC08CA22BBC0044182400461024C6
+:100C20000002130200031D82106200390000000060
+:100C30008F4202380440FFF7000000008F4201405D
+:100C4000AF4202003C021000AF4202380A00032209
+:100C50008FBF0014976200100A0003040000000018
+:100C60000E0002508F440140976200128F430144EE
+:100C70003050FFFF1603000224020001A762001299
+:100C80000E0002598F4401408F42014416020004B5
+:100C90008FBF00148FB000100A00029127BD00180A
+:100CA000976200120A00030400000000976200141B
+:100CB0008F4301443042FFFF14620006240200010A
+:100CC0008FBF00148FB00010A76200140A00124AF0
+:100CD00027BD0018976200141440001D8FBF001438
+:100CE0000A00031C00000000976200168F430144B5
+:100CF0003042FFFF1462000B240200018FBF00147A
+:100D00008FB00010A76200160A000B1227BD001852
+:100D10009742007824420004A76200100A000322D0
+:100D20008FBF001497620016240300013042FFFFBA
+:100D3000144300078FBF00143C0208008C4200706F
+:100D4000244200013C010800AC2200708FBF001457
+:100D50008FB0001003E0000827BD001827BDFFE892
+:100D6000AFBF0014AFB000108F50010093620000BD
+:100D700093430109304400FF2402001F106200A5C4
+:100D80002862002010400018240200382862000A5F
+:100D90001040000C2402000B286200081040002CB8
+:100DA00000000000046000E52862000214400028F2
+:100DB00024020006106200268FBF00140A00041FE0
+:100DC0008FB000101062005E2862000B144000DC3F
+:100DD0008FBF00142402000E106200738FB0001049
+:100DE0000A00041F00000000106200C028620039E1
+:100DF0001040000A2402008024020036106200CA5B
+:100E000028620037104000B424020035106200C18F
+:100E10008FBF00140A00041F8FB000101062002B57
+:100E20002862008110400006240200C82402003914
+:100E3000106200B48FBF00140A00041F8FB00010AE
+:100E4000106200998FBF00140A00041F8FB00010B9
+:100E50003C0208008C420020104000B98FBF0014F3
+:100E60000E000493000000008F4201008F830020D9
+:100E70009745010C97460108AC6200008F420104BF
+:100E80003C04080094844B5E00052C00AC62000416
+:100E90008F4201180006340000C43025AC620008FF
+:100EA0008F42011C24040001AC62000C9342010A31
+:100EB00000A22825AC650010AC600014AC600018DE
+:100EC000AC66001C0A0003F58FBF00143C0208004A
+:100ED0008C4200201040009A8FBF00140E00049333
+:100EE00000000000974401083C03080094634B5E37
+:100EF0009745010C000422029746010E8F820020C4
+:100F0000000426000083202500052C003C030080FF
+:100F100000A6282500832025AC400000AC4000043A
+:100F2000AC400008AC40000CAC450010AC400014D4
+:100F3000AC400018AC44001C0A0003F42404000177
+:100F40009742010C14400015000000009362000558
+:100F50003042001014400011000000000E0002504A
+:100F6000020020219362000502002021344200107B
+:100F70000E000259A36200059362000024030020C2
+:100F8000304200FF1043006D020020218FBF00148B
+:100F90008FB000100A000FC027BD00180000000D20
+:100FA0000A00041E8FBF00143C0208008C4200207F
+:100FB000104000638FBF00140E0004930000000077
+:100FC0008F4201048F8300209744010C3C050800E8
+:100FD00094A54B5EAC6200009762002C00042400D4
+:100FE0003042FFFF008220253C02400E00A228254F
+:100FF000AC640004AC600008AC60000CAC60001095
+:10100000AC600014AC600018AC65001C0A0003F46E
+:10101000240400010E00025002002021A7600008F5
+:101020000E00025902002021020020210E00025E63
+:10103000240500013C0208008C42002010400040C2
+:101040008FBF00140E000493000000009742010CB3
+:101050008F8300203C05080094A54B5E000214001D
+:10106000AC700000AC620004AC6000088F64004CFF
+:101070003C02401F00A22825AC64000C8F62005087
+:1010800024040001AC6200108F620054AC620014B2
+:10109000AC600018AC65001C8FBF00148FB000104E
+:1010A0000A0004B827BD0018240200205082002541
+:1010B0008FB000100E000F0A020020211040002007
+:1010C0008FBF0014020020218FB0001000002821E3
+:1010D0000A00025E27BD0018020020218FBF001405
+:1010E0008FB000100A00058027BD00189745010C3D
+:1010F000020020218FBF00148FB000100A0005A04D
+:1011000027BD0018020020218FB000100A0005C57D
+:1011100027BD00189345010D020020218FB000105B
+:101120000A00060F27BD0018020020218FBF0014FF
+:101130008FB000100A0005EB27BD00188FBF001408
+:101140008FB0001003E0000827BD00188F4202781E
+:101150000440FFFE2402000234840080AF440240B9
+:10116000A34202443C02100003E00008AF420278B0
+:101170003C04080094844B6A3C0208008C424B7487
+:101180003083FFFF000318C000431021AF42003C32
+:101190003C0208008C424B70AF4200383C020050C9
+:1011A00034420008AF4200300000000000000000A0
+:1011B000000000008F420000304200201040FFFD80
+:1011C000000000008F4204003C010800AC224B608C
+:1011D0008F4204043C010800AC224B643C02002016
+:1011E000AF420030000000003C02080094424B680F
+:1011F0003C03080094634B6C3C05080094A54B6EBF
+:1012000024840001004310213083FFFF3C010800CB
+:10121000A4224B683C010800A4244B6A1465000317
+:10122000000000003C010800A4204B6A03E0000815
+:10123000000000003C05000A27BDFFE80345282107
+:101240003C04080024844B50AFBF00100E00051D65
+:101250002406000A3C02080094424B523C0308005A
+:1012600094634B6E3042000F244200030043180485
+:1012700024027FFF0043102B10400002AF83001CAC
+:101280000000000D0E00042A000000003C020800CF
+:1012900094424B5A8FBF001027BD001803E000088E
+:1012A000A74200A23C02000A034210219443000618
+:1012B0003C02080094424B5A3C010800A4234B56C0
+:1012C000004310238F83001C00021400000214034B
+:1012D0000043102B03E000083842000127BDFFE85F
+:1012E000AFBF00103C02000A0342102194420006E6
+:1012F0003C010800A4224B560E00047700000000B9
+:101300005440FFF93C02000A8FBF001003E00008C0
+:1013100027BD001827BDFFE8AFBF00100E000477FF
+:101320000000000010400003000000000E000485D3
+:10133000000000003C0208008C424B608FBF001090
+:1013400027430400AF4200383C0208008C424B6443
+:1013500027BD0018AF830020AF42003C3C020005CF
+:10136000AF42003003E00008AF8000188F82001801
+:101370003C0300060002114000431025AF4200303C
+:101380000000000000000000000000008F4200008C
+:10139000304200101040FFFD27420400AF820020C1
+:1013A00003E00008AF8000183C0608008CC64B64C0
+:1013B0008F8500188F8300203C02080094424B5A0E
+:1013C00027BDFFE024A50001246300202442000182
+:1013D00024C70020AFB10014AFB00010AFBF001899
+:1013E000AF850018AF8300203C010800A4224B5AAF
+:1013F000309000FF3C010800AC274B6404C100089A
+:101400000000882104E00006000000003C02080003
+:101410008C424B60244200013C010800AC224B602E
+:101420003C02080094424B5A3C03080094634B680A
+:101430000010202B004310262C42000100441025F0
+:10144000144000048F830018240200101462000F5F
+:10145000000000000E0004A9241100013C03080054
+:1014600094634B5A3C02080094424B681462000398
+:10147000000000000E00042A000000001600000317
+:10148000000000000E000493000000003C03080070
+:1014900094634B5E3C02080094424B5C2463000161
+:1014A0003064FFFF3C010800A4234B5E148200035C
+:1014B000000000003C010800A4204B5E1200000662
+:1014C000000000003C02080094424B5AA74200A2D0
+:1014D0000A00050B022010210E0004770000000016
+:1014E00010400004022010210E00048500000000BE
+:1014F000022010218FBF00188FB100148FB0001090
+:1015000003E0000827BD00203084FFFF30A5FFFF67
+:101510000000182110800007000000003082000148
+:101520001040000200042042006518210A00051343
+:101530000005284003E000080060102110C00006EC
+:1015400024C6FFFF8CA2000024A50004AC8200008A
+:101550000A00051D2484000403E0000800000000C8
+:1015600010A0000824A3FFFFAC86000000000000CC
+:10157000000000002402FFFF2463FFFF1462FFFA53
+:101580002484000403E0000800000000240200019D
+:10159000AF62000CA7620010A7620012A7620014DD
+:1015A00003E00008A76200163082007F034210218A
+:1015B0003C08000E004818213C0208008C42002024
+:1015C00027BDFFD82407FF80AFB3001CAFB20018BF
+:1015D000AFB10014AFB00010AFBF00200080802179
+:1015E00030B100FF0087202430D200FF1040002FD0
+:1015F00000009821AF44002C9062000024030050AA
+:10160000304200FF1443000E000000003C020800BE
+:101610008C4200E00202102100471024AF42002C4F
+:101620003C0208008C4200E0020210213042007FA0
+:101630000342102100481021944200D43053FFFF90
+:101640000E000493000000003C02080094424B5E30
+:101650008F8300200011340000C2302500122C00BE
+:101660003C02400000C2302534A50001AC700000EF
+:101670008FBF0020AC6000048FB20018AC7300086C
+:101680008FB10014AC60000C8FB3001CAC6500106F
+:101690008FB00010AC60001424040001AC6000188E
+:1016A00027BD00280A0004B8AC66001C8FBF0020CC
+:1016B0008FB3001C8FB200188FB100148FB00010D0
+:1016C00003E0000827BD00289343010F2402001007
+:1016D0001062000E2865001110A0000724020012FD
+:1016E000240200082405003A1062000600003021A0
+:1016F00003E0000800000000240500351462FFFC30
+:10170000000030210A000538000000008F420074FC
+:1017100024420FA003E00008AF62000C27BDFFE8E1
+:10172000AFBF00100E00025E240500018FBF001045
+:1017300024020001A762001227BD00182402000144
+:1017400003E00008A360002227BDFFE0AFB1001452
+:10175000AFB00010AFBF001830B1FFFF0E00025055
+:10176000008080219362003F24030004304200FF88
+:101770001443000C02002021122000082402000A59
+:101780000E00053100000000936200052403FFFEF7
+:1017900000431024A362000524020012A362003F4C
+:1017A000020020210E000259A360008116200003D0
+:1017B000020020210E0005950000000002002021FB
+:1017C000322600FF8FBF00188FB100148FB00010B9
+:1017D000240500380A00053827BD002027BDFFE09A
+:1017E000AFBF001CAFB20018AFB10014AFB0001013
+:1017F0000E000250008080210E0005310000000024
+:101800009362003F24120018305100FF123200038F
+:101810000200202124020012A362003F936200050F
+:101820002403FFFE004310240E000259A3620005AA
+:10183000020020212405002016320007000030217C
+:101840008FBF001C8FB200188FB100148FB0001032
+:101850000A00025E27BD00208FBF001C8FB2001857
+:101860008FB100148FB00010240500390A0005382C
+:1018700027BD002027BDFFE8AFB00010AFBF0014A8
+:101880009742010C2405003600808021144000108E
+:10189000304600FF0E00025000000000240200123B
+:1018A000A362003F93620005344200100E00053130
+:1018B000A36200050E00025902002021020020212F
+:1018C0000E00025E240500200A000604000000004D
+:1018D0000E000538000000000E000250020020211A
+:1018E000936200232403FF9F020020210043102461
+:1018F0008FBF00148FB00010A36200230A000259AA
+:1019000027BD001827BDFFE0AFBF0018AFB100141E
+:10191000AFB0001030B100FF0E00025000808021F7
+:10192000240200120E000531A362003F0E0002598E
+:101930000200202102002021022030218FBF001848
+:101940008FB100148FB00010240500350A0005384F
+:1019500027BD0020A380002C03E00008A380002DF9
+:101960008F4202780440FFFE8F820034AF42024073
+:1019700024020002A34202443C02100003E00008DB
+:10198000AF4202783C0360008C6254003042000891
+:101990001440FFFD000000008C625408AF82000C70
+:1019A00024020052AC605408AC645430AC6254342D
+:1019B0002402000803E00008AC6254003C0260000E
+:1019C0008C42540030420008104000053C03600087
+:1019D0008C625400304200081440FFFD00000000FB
+:1019E0008F83000C3C02600003E00008AC43540805
+:1019F00090A3000024020005008040213063003FD6
+:101A000000004821146200050000502190A2001C33
+:101A100094A3001E304900FF306AFFFFAD00000CA8
+:101A2000AD000010AD000024950200148D05001CCF
+:101A30008D0400183042FFFF0049102300021100FE
+:101A4000000237C3004038210086202300A2102B5B
+:101A50000082202300A72823AD05001CAD04001838
+:101A6000A5090014A5090020A50A001603E0000836
+:101A7000A50A00228F4201F80440FFFE2402000262
+:101A8000AF4401C0A34201C43C02100003E00008BF
+:101A9000AF4201F83C0208008C4200B427BDFFE8C9
+:101AA000AFBF001424420001AFB000103C01080099
+:101AB000AC2200B48F4300243C02001F30AA00FF78
+:101AC0003442FF8030D800FF006280240080F8217B
+:101AD00030EF00FF1158003B01405821240CFF80DB
+:101AE0003C19000A3163007F000310C00003194055
+:101AF000006218213C0208008C4200DC25680001CD
+:101B0000310D007F03E21021004310213043007F9C
+:101B100003431821004C102400794821AF420024CF
+:101B20008D220024016C1824006C7026AD22000C5C
+:101B30008D220024310800FFAD22001095220014F0
+:101B4000952300208D27001C3042FFFF3063FFFFEC
+:101B50008D2600180043102300021100000227C345
+:101B60000040282100C4302300E2102B00C23023A3
+:101B700000E53823AD27001CAD2600189522002073
+:101B8000A522001495220022154B000AA52200165A
+:101B90008D2300248D220008254600013145008058
+:101BA0001462000430C4007F108F000238AA008045
+:101BB00000C0502151AF000131C800FF1518FFC906
+:101BC000010058218F8400343082007F03421821A5
+:101BD0003C02000A006218212402FF8000822024B7
+:101BE000AF440024A06A0079A06A00838C62005090
+:101BF0008F840034AC6200708C6500743C027FFFFF
+:101C00003442FFFF00A228240E00066BAC6500746E
+:101C1000AF5000248FBF00148FB0001003E0000805
+:101C200027BD001827BDFFC0AFBE0038AFB70034D6
+:101C3000AFB5002CAFB20020AFB1001CAFB00018A0
+:101C4000AFBF003CAFB60030AFB40028AFB3002444
+:101C50008F4500248F4600288F43002C3C02001F34
+:101C60003442FF800062182400C230240080A82182
+:101C7000AFA3001400A2F0240E00062FAFA60010A0
+:101C80003C0208008C4200E02410FF8003608821A1
+:101C900002A2102100501024AF4200243C02080090
+:101CA0008C4200E002A210213042007F0342182142
+:101CB0003C02000A00629021924200D293630084A9
+:101CC000305700FF306300FF24020001106200342F
+:101CD000036020212402000214620036000000008C
+:101CE0000E001216024028219223008392220083C4
+:101CF0003063007F3042007F000210C000031940B3
+:101D0000006218213C0208008C4200DC02A2102173
+:101D10000043382100F01024AF42002892250078BB
+:101D20009224008330E2007F034218213C02000C21
+:101D300014850007006280212402FFFFA24200F107
+:101D40002402FFFFA64200F20A0007272402FFFF39
+:101D500096020020A24200F196020022A64200F262
+:101D60008E020024AE4200F492220083A24200F0D0
+:101D70008E4200C8AE4200FC8E4200C4AE4200F863
+:101D80008E220050AE4201008E4200CCAE420104D1
+:101D9000922200853042003F0A0007823442004010
+:101DA0000E00123902402821922200850A00078283
+:101DB0003042003F936200852403FFDF3042003F42
+:101DC000A36200859362008500431024A36200850E
+:101DD0009363008393620078307400FF304200FF09
+:101DE00010540036240AFF803C0C000C3283007F24
+:101DF000000310C000031940006218213C020800D3
+:101E00008C4200DC268800013109007F02A21021EB
+:101E10000043382130E2007F0342182100EA1024F9
+:101E2000AF420028006C80218E020024028A182410
+:101E3000006A5826AE02000C8E020024310800FF12
+:101E4000AE02001096020014960300208E07001CBC
+:101E50003042FFFF3063FFFF8E060018004310235F
+:101E600000021100000227C30040282100C43023D3
+:101E700000E2102B00C2302300E53823AE07001C1F
+:101E8000AE06001896020020A60200149602002258
+:101E9000A602001692220079304200FF105400077B
+:101EA0000000000051370001316800FF92220078E5
+:101EB000304200FF1448FFCD0100A0219222008390
+:101EC000A22200798E2200500A0007E2AE220070A2
+:101ED000A22200858E22004C2405FF80AE42010C18
+:101EE0009222008534420020A2220085924200D135
+:101EF0003C0308008C6300DC305400FF3C02080007
+:101F00008C4200E400143140001420C002A31821C8
+:101F100000C4202102A210210064382100461021B3
+:101F20000045182400E52824AF450028AF43002CC5
+:101F30003042007F924400D030E3007F03422821EA
+:101F4000034318213C02000C006280213C02000E79
+:101F5000309600FF00A298211296002A000000008F
+:101F60008E02000C02002021026028211040002572
+:101F7000261000280E00064A000000009262000DA4
+:101F800026830001307400FF3042007FA262000D02
+:101F90002404FF801697FFF0267300203C020800FF
+:101FA0008C4200DC0000A02102A210210044102479
+:101FB000AF4200283C0208008C4200E43C030800C9
+:101FC0008C6300DC02A2102100441024AF42002CDC
+:101FD0003C0208008C4200E402A318213063007F19
+:101FE00002A210213042007F034220210343182126
+:101FF0003C02000C006280213C02000E0A0007A493
+:10200000008298218E4200D8AE2200508E4200D825
+:10201000AE22007092250083924600D19223008365
+:10202000924400D12402FF8000A228243063007F64
+:10203000308400FF00A628250064182A10600002E2
+:1020400030A500FF38A50080A2250083A2250079D5
+:102050000E00063D000000009222007E02A020211A
+:10206000A222007A8E2300743C027FFF3442FFFFDD
+:10207000006218240E00066BAE2300748FA20010BD
+:10208000AF5E00248FBF003CAF4200288FBE0038F7
+:102090008FA200148FB700348FB600308FB5002C9C
+:1020A0008FB400288FB300248FB200208FB1001CA2
+:1020B0008FB0001827BD004003E00008AF42002C9D
+:1020C00090A2000024420001A0A200003C030800EE
+:1020D0008C6300F4304200FF1443000F0080302175
+:1020E000A0A000003C0208008C4200E48F84003471
+:1020F000008220213082007F034218213C02000C24
+:10210000006218212402FF8000822024ACC300005A
+:1021100003E00008AF4400288C8200002442002025
+:1021200003E00008AC82000094C200003C080800F4
+:10213000950800CA30E7FFFF008048210102102106
+:10214000A4C2000094C200003042FFFF00E2102B46
+:1021500054400001A4C7000094A200003C03080002
+:102160008C6300CC24420001A4A2000094A20000D1
+:102170003042FFFF544300078F8600280107102BD1
+:10218000A4A000005440000101003821A4C70000B1
+:102190008F8600288CC4001CAF44003C94A2000031
+:1021A0008F43003C3042FFFF000210C00062182144
+:1021B000AF43003C8F42003C008220231880000483
+:1021C000000000008CC200180A00084324420001ED
+:1021D0008CC20018AF4200383C020050344200105C
+:1021E000AF420030000000000000000000000000CE
+:1021F0008F420000304200201040FFFD0000000030
+:102200008F420404AD2200048F420400AD2200007E
+:102210003C020020AF42003003E000080000000054
+:1022200027BDFFE0AFB20018AFB10014AFB000108F
+:10223000AFBF001C94C2000000C080213C12080007
+:10224000965200C624420001A60200009603000038
+:1022500094E2000000E03021144300058FB100300B
+:102260000E000818024038210A000875000000001E
+:102270008C8300048C820004244200400461000727
+:10228000AC8200048C8200040440000400000000C2
+:102290008C82000024420001AC8200009602000003
+:1022A0003042FFFF50520001A600000096220000BD
+:1022B00024420001A62200008F82002896230000FD
+:1022C00094420016144300048FBF001C2402000136
+:1022D000A62200008FBF001C8FB200188FB100141F
+:1022E0008FB0001003E0000827BD00208F89002870
+:1022F00027BDFFE0AFBF00188D220028274804004B
+:1023000030E700FFAF4200388D22002CAF8800304C
+:10231000AF42003C3C020005AF420030000000002C
+:1023200000000000000000000000000000000000AD
+:10233000000000008C82000C8C82000CAD020000BA
+:102340008C820010AD0200048C820018AD020008DF
+:102350008C82001CAD02000C8CA20014AD02001097
+:102360008C820020AD02001490820005304200FFF4
+:1023700000021200AD0200188CA20018AD02001C71
+:102380008CA2000CAD0200208CA20010AD02002433
+:102390008CA2001CAD0200288CA20020AD02002CF3
+:1023A000AD060030AD000034978300263402FFFFF5
+:1023B00014620002006020213404FFFF10E00011CD
+:1023C000AD04003895230036952400362402000120
+:1023D0003063FFFF000318C20069182190650040B8
+:1023E000308400070082100400451025A0620040E0
+:1023F0008F820028944200563042FFFF0A0008DC1A
+:10240000AD02003C952300369524003624020001DD
+:102410003063FFFF000318C2006918219065004077
+:1024200030840007008210040002102700451024A9
+:10243000A0620040AD00003C000000000000000071
+:10244000000000003C02000634420040AF42003071
+:102450000000000000000000000000008F420000AB
+:10246000304200101040FFFD8F860028AF880030FA
+:1024700024C2005624C7003C24C4002824C50032CE
+:1024800024C600360E000856AFA200108FBF0018F9
+:1024900003E0000827BD00208F8300243C060800CD
+:1024A0008CC600E88F82003430633FFF0003198040
+:1024B00000461021004310212403FF803046007F96
+:1024C00000431024AF420028034618213C02000CB0
+:1024D0000062302190C2000D30A500FF00003821BD
+:1024E00034420010A0C2000D8F8900288F8A00247A
+:1024F00095230036000A13823048000324020001AD
+:10250000A4C3000E1102000B2902000210400005B6
+:10251000240200021100000C240300010A0009201B
+:102520000000182111020006000000000A00092026
+:10253000000018218CC2002C0A000920244300014D
+:102540008CC20014244300018CC200180043102BDD
+:1025500050400009240700012402002714A20003B0
+:10256000000000000A00092C240700019522003E0B
+:1025700024420001A522003E000A138230430003DA
+:102580002C62000210400009008028211460000421
+:102590000000000094C200360A00093C3046FFFFEC
+:1025A0008CC600380A00093C008028210000302138
+:1025B0003C04080024844B780A00088900000000CD
+:1025C000274901008D22000C9523000601202021BF
+:1025D000000216023046003F3063FFFF240200274E
+:1025E00000C0282128C7002810C2000EAF83002495
+:1025F00010E00008240200312402002110C200096A
+:102600002402002510C200079382002D0A00095BF6
+:102610000000000010C200059382002D0A00095B33
+:10262000000000000A0008F4000000000A0006266E
+:102630000000000095230006912400058D25000C64
+:102640008D2600108D2700188D28001C8D29002054
+:10265000244200013C010800A4234B7E3C010800F9
+:10266000A0244B7D3C010800AC254B843C010800B4
+:10267000AC264B883C010800AC274B903C0108007D
+:10268000AC284B943C010800AC294B9803E00008AF
+:10269000A382002D8F87002827BDFFC0AFB3003471
+:1026A000AFB20030AFB1002CAFB00028AFBF0038E0
+:1026B0003C0208008C4200D094E3003030B0FFFFB1
+:1026C000005010073045FFFF3063FFFF00C0982126
+:1026D000A7A200103C110800963100C614A3000602
+:1026E0003092FFFF8CE2002424420030AF42003CD5
+:1026F0000A0009948CE2002094E200323042FFFF8D
+:1027000054A2000827A400188CE2002C24420030B8
+:10271000AF42003C8CE20028AF4200380A0009A218
+:102720008F84002827A5001027A60020022038212A
+:102730000E000818A7A000208FA200182442003025
+:10274000AF4200388FA2001CAF42003C8F840028AB
+:102750003C020005AF42003094820034274304005D
+:102760003042FFFF0202102B14400007AF830030FD
+:1027700094820054948300340202102100431023F9
+:102780000A0009B63043FFFF94830054948200345A
+:102790000223182100501023006218233063FFFF2A
+:1027A000948200163042FFFF144300030000000033
+:1027B0000A0009C424030001948200163042FFFF7E
+:1027C0000043102B104000058F82003094820016C9
+:1027D000006210233043FFFF8F820030AC530000B3
+:1027E000AC400004AC520008AC43000C3C020006B4
+:1027F00034420010AF420030000000000000000032
+:10280000000000008F420000304200101040FFFD29
+:10281000001018C2006418219065004032040007BF
+:10282000240200018FBF00388FB300348FB2003014
+:102830008FB1002C8FB000280082100400451025B5
+:1028400027BD004003E00008A062004027BDFFA8AC
+:10285000AFB60050AFB5004CAFB40048AFB30044C2
+:10286000AFB1003CAFBF0054AFB20040AFB00038D2
+:102870008C9000003C0208008C4200E88F860034F7
+:10288000960300022413FF8000C2302130633FFF13
+:102890000003198000C3382100F3102490B2000017
+:1028A000AF42002C9203000230E2007F034230214D
+:1028B0003C02000E00C28821306300C024020040A8
+:1028C0000080A82100A0B021146200260000A021F1
+:1028D0008E3400388E2200181440000224020001B9
+:1028E000AE2200189202000D304200201440001564
+:1028F0008F8200343C0308008C6300DC001238C077
+:10290000001231400043102100C730210046382119
+:1029100030E300073C02008030E6007800C230253A
+:102920000343182100F31024AF4208002463090078
+:10293000AF4608108E2200188C6300080043102157
+:10294000AE2200188E22002C8E2300182442000193
+:102950000062182B1060003D000000000A000A7899
+:1029600000000000920300022402FFC00043102474
+:10297000304200FF1440000524020001AE2200187E
+:10298000962200360A000A613054FFFF8E2200149E
+:1029900024420001AE22001892020000000216003C
+:1029A0000002160304410029000000009602000204
+:1029B00027A4001000802821A7A20016960200027A
+:1029C00024070001000030213042FFFFAF820024C5
+:1029D0000E000889AFA0001C960300023C0408000A
+:1029E0008C8400E88F82003430633FFF000319803D
+:1029F00000441021004310213043007F3C05000CAF
+:102A00000053102403431821AF4200280065182109
+:102A10009062000D001221403042007FA062000D44
+:102A20003C0308008C6300E48F82003400431021D3
+:102A30000044382130E2007F03421021004510217C
+:102A400000F31824AF430028AEA200009222000D2C
+:102A5000304200101040001302A020218F83002874
+:102A60008EA40000028030219462003E2442FFFFC9
+:102A7000A462003E948400029625000E3084FFFF7D
+:102A80000E00097330A5FFFF8F82002894430034A5
+:102A90009622000E1443000302A02021240200010C
+:102AA000A382002C02C028210E0007FE00000000B7
+:102AB0008FBF00548FB600508FB5004C8FB40048C4
+:102AC0008FB300448FB200408FB1003C8FB000380C
+:102AD00003E0000827BD00588F82002827BDFFD0E3
+:102AE000AFB40028AFB20020AFBF002CAFB30024BA
+:102AF000AFB1001CAFB00018904400D0904300D19B
+:102B00000000A021309200FFA3A30010306300FF5B
+:102B10008C5100D88C5300DC1072002B2402000171
+:102B20003C0308008C6300E493A400108F820034FF
+:102B30002406FF800004214000431021004410219E
+:102B40003043007F00461024AF4200280343182181
+:102B50003C02000C006218218C62000427A40014BF
+:102B600027A50010022280210270102304400015C6
+:102B7000AFA300149062000D00C21024304200FF89
+:102B800014400007020088219062000D344200408A
+:102B90000E0007FEA062000D0A000ABD93A20010FD
+:102BA0000E0009E1241400018F830028AC7000D8C6
+:102BB00093A20010A06200D193A200101452FFD87B
+:102BC0000000000024020001168200048FBF002CC8
+:102BD0000E000626000000008FBF002C8FB40028D6
+:102BE0008FB300248FB200208FB1001C8FB000186B
+:102BF00003E0000827BD003027BDFFD8AFB3001C9D
+:102C0000AFB20018AFB10014AFB00010AFBF0020DA
+:102C10000080982100E0802130B1FFFF0E00049376
+:102C200030D200FF000000000000000000000000A3
+:102C30008F820020AC510000AC520004AC5300085D
+:102C4000AC40000CAC400010AC400014AC4000188C
+:102C50003C03080094634B5E02038025AC50001CCB
+:102C6000000000000000000000000000240400013B
+:102C70008FBF00208FB3001C8FB200188FB10014DB
+:102C80008FB000100A0004B827BD002827BDFFE858
+:102C9000AFB00010AFBF001430A5FFFF30C600FF7B
+:102CA0000080802124020C80AF420024000000003C
+:102CB0000000000000000000000000000000000014
+:102CC0000E000ACC000000003C040800248400E050
+:102CD0008C8200002403FF808FBF001402021021A9
+:102CE00000431024AF4200248C8200003C03000A01
+:102CF000020280213210007F035010218FB000109B
+:102D00000043102127BD001803E00008AF8200280F
+:102D100027BDFFE8AFBF00108F4401403C0308000F
+:102D20008C6300E02402FF80AF840034008318210C
+:102D300000621024AF4200243C02000803424021FC
+:102D4000950500023063007F3C02000A034318210E
+:102D50000062182130A5FFFF3402FFFF0000302180
+:102D60003C07602010A20006AF8300282402FFFF6A
+:102D7000A5020002946500D40E000AF130A5FFFF01
+:102D80008FBF001024020C8027BD001803E000084C
+:102D9000AF4200243C020008034240219502000299
+:102DA0003C0A0800954A00C63046FFFF14C00007E1
+:102DB0003402FFFF8F8200288F8400343C0760209C
+:102DC000944500D40A000B5A30A5FFFF10C200241E
+:102DD0008F87002894E2005494E400163045FFFFEA
+:102DE00000A6102300A6182B3089FFFF10600004F6
+:102DF0003044FFFF00C51023012210233044FFFFA1
+:102E0000008A102B1040000C012A1023240200011C
+:102E1000A50200162402FFFFA502000294E500D4DB
+:102E20008F8400340000302130A5FFFF3C07602074
+:102E30000A000AF1000000000044102A10400008B7
+:102E4000000000009502001630420001104000040E
+:102E5000000000009742007E24420014A5020016E4
+:102E600003E00008000000008F84002827BDFFE079
+:102E7000AFBF0018948200349483003E1060001AA3
+:102E80003048FFFF9383002C2402000114620027C6
+:102E90008FBF00188F820028000818C23108000771
+:102EA000006218212447003A244900542444002099
+:102EB000244500302446003490620040304200FF38
+:102EC0000102100730420001104000168FBF0018A9
+:102ED0000E000856AFA900108F82002894420034DB
+:102EE0000A000B733048FFFF94830036948200344D
+:102EF0001043000E8FBF001894820036A482003465
+:102F000094820056A48200548C82002CAC8200244F
+:102F100094820032A48200309482003CA482003A61
+:102F20008FBF00180A000B3327BD002003E0000804
+:102F300027BD002027BDFFE8AFBF00108F4A01006A
+:102F40003C0508008CA500E03C02080090424B8440
+:102F50003C0C0800958C4B7E01452821304B003FEE
+:102F600030A2007F03424021396900323C02000A4E
+:102F70003963003F2C630001010240212D2900012B
+:102F80002402FF8000A2282401234825AF8A0034B0
+:102F900000801821AF450024000030210080282146
+:102FA00024070001AF8800283C04080024844B78E3
+:102FB000AF8C002415200007A380002D24020020E0
+:102FC0005562000F006020213402FFFF5582000C83
+:102FD000006020212402002015620005000000008E
+:102FE0008C6300142402FFFF106200070000000041
+:102FF0000E000889000000000A000BD0000000004D
+:103000000E0008F4016028210E000B68000000008B
+:103010008FBF001024020C8027BD001803E00008B9
+:10302000AF4200243C0208008C4200E027BDFFA014
+:10303000AFB1003C008210212411FF80AFBE0058C8
+:10304000AFB70054AFB20040AFB00038AFBF005CC4
+:10305000AFB60050AFB5004CAFB40048AFB30044BA
+:10306000005110248F4800248F4900288F470028E2
+:10307000AF4200243C0208008C4200E00080902116
+:1030800024060006008210213042007F03421821EE
+:103090003C02000A006280213C02001F3442FF8093
+:1030A00000E2382427A40010260500F00122F024B5
+:1030B0000102B8240E00051DAFA700308FA2001832
+:1030C000AE0200C48FA2001CAE0200C88FA2002472
+:1030D000AE0200CC93A40010920300D12402FF8022
+:1030E0000082102400431025304900FF3083007F08
+:1030F0003122007F0062102A10400004000310C03B
+:1031000001311026304900FF000310C000031940B0
+:10311000006218213C0208008C4200DC920400D2BC
+:10312000024210210043102100511024AF42002818
+:1031300093A300103063007F000310C00003194008
+:10314000006218213C0208008C4200DC024210217F
+:10315000004310213042007F034218213C02000C42
+:10316000006240218FA300142402FFFF1062003090
+:10317000309500FF93A2001195030014304400FF26
+:103180003063FFFF0064182B1060000D000000008A
+:10319000950400148D07001C8D0600183084FFFF75
+:1031A00000442023000421000000102100E4382105
+:1031B00000E4202B00C230210A000C4A00C4302158
+:1031C000950400148D07001C8D0600183084FFFF45
+:1031D000008220230004210000001021008018211B
+:1031E00000C2302300E4202B00C4302300E3382346
+:1031F000AD07001CAD06001893A20011A502001433
+:1032000097A20012A50200168FA20014AD020010B2
+:103210008FA20014AD02000C93A20011A5020020A1
+:1032200097A20012A50200228FA20014AD02002472
+:103230002406FF80024610243256007FAF4200244D
+:10324000035618213C02000A006280218E02004CC5
+:103250008FA200203124007F000428C0AE0200505D
+:103260008FA200200004214000852821AE020070BA
+:1032700093A2001001208821A202008393A20010D3
+:10328000A2020079920200853042003FA20200852E
+:103290003C0208008C4200DC024210210045102153
+:1032A00000461024AF42002C3C0208008C4200E48F
+:1032B0003C0308008C6300DC024210210044102112
+:1032C00000461024AF4200283C0208008C4200E473
+:1032D00002431821006518210242102100441021E8
+:1032E0003042007F3063007F93A50010034220210D
+:1032F000034318213C02000E006240213C02000CF6
+:1033000010B1008C008248213233007F1660001912
+:103310002404FF803C0208008C4200DC02421021A1
+:1033200000441024AF42002C3C0208008C4200E410
+:103330003C0308008C6300DC02421021004410248E
+:10334000AF4200283C0208008C4200E402431821EE
+:103350003063007F024210213042007F034220216F
+:10336000034318213C02000E006240213C02000C85
+:10337000008248219124000D2414FF8000001021B8
+:1033800000942025A124000D950400029505001449
+:103390008D07001C3084FFFF30A5FFFF8D0600184D
+:1033A000008520230004210000E4382100C23021E0
+:1033B00000E4202B00C43021AD07001CAD0600182E
+:1033C00095020002A5020014A50000168D02000857
+:1033D000AD0200108D020008AD02000C9502000243
+:1033E000A5020020A50000228D020008AD020024E5
+:1033F0009122000D30420040104000422622000180
+:103400003C0208008C4200E0A3B300283C10000AF4
+:103410000242102100541024AF4200243C02080054
+:103420008C4200E0A380002C27A4002C0242102133
+:103430003042007F03421821007018218C6200D8AE
+:103440008D26000427A50028AFA9002C00461021D6
+:10345000AC6200D80E0009E1AF83002893A30028D6
+:103460008F8200280E000626A04300D10E000B68B4
+:103470000000000002541024AF4200243C02080067
+:103480008C4200DC00132940001320C000A420213E
+:10349000024210210044102100541024AF42002C9D
+:1034A0003C0208008C4200E43C0308008C6300DC12
+:1034B00003563021024210210045102100541024EF
+:1034C000AF4200283C0208008C4200E4024318216D
+:1034D0000064182102421021004510213042007F73
+:1034E0003063007F03422021034318213C02000E79
+:1034F000006240213C02000C00D080210082482163
+:10350000262200013043007F14750005304400FF7F
+:103510002403FF800223102400431026304400FFC0
+:1035200093A2001000808821250800281444FF760B
+:103530002529002093A400108FA300142402FFFF6C
+:103540001062000A308900FF2482000124830001F8
+:103550003042007F14550005306900FF2403FF80CE
+:103560000083102400431026304900FF92020078A7
+:10357000305300FF11330032012088213C02080043
+:103580008C4200DC3225007F000520C00005294068
+:1035900000A42021024210212406FF8000441021B3
+:1035A00000461024AF42002C3C0308008C6300DC72
+:1035B0003C0208008C4200E4024318210242102120
+:1035C0000045102100641821004610243063007F5C
+:1035D000AF420028034318213C02000E0062402144
+:1035E0003C0208008C4200E48D06000C0100202102
+:1035F00002421021004510213042007F0342182171
+:103600003C02000C0062482110C0000D012028215E
+:103610000E00064A000000002402FF800222182447
+:1036200026240001006228263082007F1455000203
+:10363000308300FF30A300FF1473FFD000608821A7
+:103640008E0300743C027FFF3442FFFF00621824A7
+:10365000AE0300740E00066B02402021AF57002419
+:103660008FA20030AF5E00288FBF005C8FBE005875
+:103670008FB700548FB600508FB5004C8FB4004800
+:103680008FB300448FB200408FB1003C8FB0003840
+:1036900027BD006003E00008AF42002C27BDFFD823
+:1036A000AFB1001CAFBF0020AFB000182751018898
+:1036B000922200032408FF803C03000A3047007F69
+:1036C000A3A700108F4601803C0208008C4200E056
+:1036D000AF86003400C2282100A81024AF42002485
+:1036E0009224000030A2007F0342102100431021E9
+:1036F000AF8200283084007F24020002148200255B
+:10370000000719403C0208008C4200E400C210216E
+:103710000043282130A2007F0342182100A8102472
+:10372000AF4200283C02000C006218219062000D9C
+:10373000AFA3001400481025A062000D8FA3001451
+:103740009062000D304200405040006A8FBF002060
+:103750008F860028A380002C27A400148CC200D8D8
+:103760008C63000427A50010004310210E0009E11E
+:10377000ACC200D893A300108F8200280E0006264A
+:10378000A04300D10E000B68000000000A000E0BE1
+:103790008FBF00200E00062F00C020210E00063D26
+:1037A000000000003C020008034280219223000137
+:1037B0009202007B1443004F8FBF00209222000032
+:1037C0003044007F24020004108200172882000584
+:1037D00010400006240200052402000310820007A6
+:1037E0008FB1001C0A000E0C0000000010820012B5
+:1037F0008FBF00200A000E0C8FB1001C92050083C1
+:10380000920600788E0700748F84003430A500FF84
+:1038100000073E0230C600FF0E00067330E7007F4F
+:103820000A000E0B8FBF00200E000BD78F840034D0
+:103830000A000E0B8FBF002024020C80AF42002430
+:103840009202003E30420040104000200000000084
+:103850009202003E00021600000216030441000618
+:10386000000000008F8400340E0005A024050093A2
+:103870000A000E0B8FBF00209202003F24030018A5
+:10388000304200FF1443000C8F84003424050039BB
+:103890000E000538000030210E0002508F840034E5
+:1038A00024020012A202003F0E0002598F8400344D
+:1038B0000A000E0B8FBF0020240500360E000538CD
+:1038C000000030210A000E0B8FBF00200E000250B6
+:1038D0008F8400349202000534420020A2020005C9
+:1038E0000E0002598F8400340E000FC08F84003404
+:1038F0008FBF00208FB1001C8FB0001824020C80F5
+:1039000027BD002803E00008AF42002427BDFFE8E0
+:10391000AFB00010AFBF001427430100946200084D
+:103920000002140000021403044100020000802180
+:103930002410000194620008304200801040001AF8
+:10394000020010219462000830422000104000164E
+:10395000020010218C6300183C021C2D344219ED2A
+:10396000240600061062000F3C0760213C0208009C
+:103970008C4200D4104000078F8200288F830028DB
+:10398000906200623042000F34420040A062006248
+:103990008F8200288F840034944500D40E000AF1F1
+:1039A00030A5FFFF020010218FBF00148FB0001060
+:1039B00003E0000827BD001827BDFFE0AFB10014E9
+:1039C000AFB00010A380002CAFBF00188F450100DE
+:1039D0003C0308008C6300E02402FF80AF850034C4
+:1039E00000A318213064007F0344202100621824C2
+:1039F0003C02000A00822021AF430024275001002E
+:103A00008E0200148C8300DCAF8400280043102356
+:103A100018400004000088218E0200140E000A8461
+:103A2000AC8200DC9202000B24030002304200FF53
+:103A30001443002F0000000096020008304300FFEE
+:103A40002402008214620005240200840E00093E54
+:103A5000000000000A000E97000000001462000938
+:103A6000240200818F8200288F8400343C0760216B
+:103A7000944500D49206000530A5FFFF0A000E868B
+:103A800030C600FF14620027000000009202000A06
+:103A9000304300FF306200201040000430620040DC
+:103AA0008F8400340A000E82240600401040000477
+:103AB000000316008F8400340A000E8224060041A1
+:103AC00000021603044100178F84003424060042CC
+:103AD0008F8200283C076019944500D430A5FFFF71
+:103AE0000E000AF1000000000A000E97000000001E
+:103AF0009202000B24030016304200FF1043000620
+:103B0000000000009202000B24030017304200FF67
+:103B100014430004000000000E000E11000000001D
+:103B2000004088210E000B68000000009202000A8D
+:103B3000304200081040000624020C808F850028C7
+:103B40003C0400080E0011EE0344202124020C80E6
+:103B5000AF4200248FBF0018022010218FB0001048
+:103B60008FB1001403E0000827BD002027BDFFE847
+:103B7000AFBF0014AFB000108F5000243C0308000A
+:103B80008C6300E08F4501002402FF8000A3182110
+:103B90003064007F03442021006218243C02000AA4
+:103BA00000822021AF850034AF4300249082006260
+:103BB000AF8400283042000F34420050A0820062DF
+:103BC0003C02001F3442FF800E00062602028024C1
+:103BD000AF5000248FBF00148FB0001003E0000826
+:103BE00027BD00183C0208008C4200201040001D38
+:103BF0002745010090A300093C0200080342202150
+:103C000024020018546200033C0200080A000ED887
+:103C10002402000803422021240200161462000539
+:103C20002402001724020012A082003F0A000EE2C4
+:103C300094A700085462000694A700089362000548
+:103C40002403FFFE00431024A362000594A700088C
+:103C500090A6001B8CA4000094A500060A000ACCC4
+:103C600000073C0003E000080000000027440100BA
+:103C700094820008304500FF38A3008238A20084F7
+:103C80002C6300012C420001006218251060000620
+:103C9000240200839382002D1040000D00000000DC
+:103CA0000A000B9B0000000014A2000524A2FF8064
+:103CB0008F4301043C02602003E00008AC43001481
+:103CC000304200FF2C420002104000032402002278
+:103CD0000A000E3C0000000014A2000300000000D7
+:103CE0000A000EA9000000000A000EC70000000034
+:103CF0009363007E9362007A144300090000202140
+:103D00009362000024030050304200FF144300047B
+:103D1000240400019362007E24420001A362007E1D
+:103D200003E00008008010218F4201F80440FFFEEC
+:103D300024020002AF4401C0A34201C43C021000AF
+:103D400003E00008AF4201F827BDFFE8AFBF001055
+:103D50009362003F2403000A304200FF14430046F0
+:103D6000000000008F6300548F62004C1062007DE1
+:103D7000036030219362000024030050304200FFB2
+:103D80001443002F000000008F4401403C02080053
+:103D90008C4200E02403FF800082102100431024A5
+:103DA000AF4200243C0208008C4200E08F650054C2
+:103DB0003C03000A008220213084007F034410214C
+:103DC00000431021AC4501089762003C8F63004C12
+:103DD0003042FFFF0002104000621821AF63005C18
+:103DE0008F6300548F64004C9762003C006418237A
+:103DF0003042FFFF00031843000210400043102A26
+:103E000010400006000000008F6200548F63004CD9
+:103E1000004310230A000F58000210439762003C31
+:103E20003042FFFF00021040ACC2006424020001D7
+:103E3000A0C0007CA0C2008424020C80AF420024F9
+:103E40000E000F0A8F440140104000478FBF001042
+:103E50008F4301408F4201F80440FFFE240200021C
+:103E6000AF4301C0A34201C43C021000AF4201F8BD
+:103E70000A000FA88FBF00109362003F24030010B8
+:103E8000304200FF14430004000000008F44014052
+:103E90000A000F94000028219362003F24030016BB
+:103EA000304200FF1443000424020014A362003FC8
+:103EB0000A000FA2000000008F62004C8F630050C8
+:103EC00000431023044100288FBF0010936200813B
+:103ED00024420001A3620081936200812C4200040D
+:103EE00014400010000000009362003F240300040F
+:103EF000304200FF14430006000000008F440140E0
+:103F00008FBF0010240500930A0005A027BD0018EC
+:103F10008F440140240500938FBF00100A00060F54
+:103F200027BD00188F4401400E0002500000000021
+:103F30008F6200542442FFFFAF6200548F62005032
+:103F40002442FFFFAF6200500E0002598F4401402F
+:103F50008F4401408FBF0010240500040A00025E58
+:103F600027BD00188FBF001003E0000827BD001810
+:103F70008F4201889363007E00021402304400FFE8
+:103F8000306300FF1464000D0000000093620080A5
+:103F9000304200FF1044000900000000A3640080CC
+:103FA0009362000024030050304200FF14430004D9
+:103FB000000000000A0006D78F440180A36400803F
+:103FC00003E000080000000027BDFFE8AFB00010CC
+:103FD000AFBF00149362000524030030304200306C
+:103FE00014430089008080213C0208008C4200209C
+:103FF00010400080020020210E0004930000000009
+:104000008F850020ACB000009362003E9363003FB8
+:10401000304200FF00021200306300FF0043102511
+:10402000ACA2000493620082000216000002160394
+:1040300004410005000000003C0308008C630048B8
+:104040000A000FE6000000009362003E304200408C
+:10405000144000030000182193620081304300FFE8
+:104060009362008200031E00304200FF0002140031
+:1040700000621825ACA300088F620040ACA2000CBF
+:104080008F620048ACA200108F62004CACA20014FA
+:104090008F6200508F63004C0043102304410003E3
+:1040A000000000000A000FFA8F62004C8F6200507F
+:1040B000ACA200183C02080094424B5E3C03C00BCB
+:1040C00000002021004310250E0004B8ACA2001C03
+:1040D0008F6200548F840020AC8200008F620058F1
+:1040E000AC8200048F62005CAC8200088F620060CA
+:1040F0008F43007400431021AC82000C8F62006477
+:10410000AC820010976300689762006A00031C008D
+:104110003042FFFF00621825AC83001493620082D6
+:1041200024030080304200FF14430003000000001D
+:104130000A00102EAC8000188F63000C24020001CE
+:104140001062000E2402FFFF9362003E30420040E6
+:104150001440000A2402FFFF8F63000C8F4200749A
+:10416000006218233C020800006210241440000280
+:10417000000028210060282100051043AC820018AF
+:104180003C02080094424B5E3C03C00C000020211E
+:10419000004310258F8300200E0004B8AC62001C81
+:1041A0008F6200188F8300203C05080094A54B5EA9
+:1041B00024040001AC620000AC6000048F66006C57
+:1041C0003C02400D00A22825AC6600088F6200DC8E
+:1041D000AC62000CAC600010936200050002160097
+:1041E000AC620014AC6000180E0004B8AC65001C92
+:1041F000020020218FBF00148FB00010A3600005C3
+:104200000A00042127BD00188FBF00148FB00010D2
+:1042100003E0000827BD00189742007C30C600FF6D
+:10422000A08600843047FFFF2402000514C2000B63
+:1042300024E3465090A201122C42000710400007D0
+:1042400024E30A0090A30112240200140062100467
+:1042500000E210210A0010663047FFFF3067FFFFC1
+:1042600003E00008A4870014AC87004C8CA201086E
+:104270000080402100A0482100E2102330C600FF4A
+:104280001840000393AA001324E2FFFCACA201082B
+:1042900030C2000110400008000000008D020050F4
+:1042A00000E2102304410013240600058D0200548F
+:1042B00010E20010000000008D02005414E2001A09
+:1042C000000000003C0208008C4200D83042002070
+:1042D0001040000A2402000191030078910200833B
+:1042E000144300062402000101002021012028219E
+:1042F000240600040A00105400000000A1000084FD
+:1043000011400009A50200148F4301008F4201F8FB
+:104310000440FFFE24020002AF4301C0A34201C4D7
+:104320003C021000AF4201F803E00008000000006A
+:1043300027BDFFE88FA90028AFBF001000804021F3
+:1043400000E918231860007330C600FFA080007CCD
+:10435000A08000818CA2010800E210230440004DDF
+:10436000000000008C8200509483003C8C84006428
+:10437000004748233063FFFF012318210083202BCF
+:1043800010800004000000008D0200640A0010B7D5
+:1043900000E210219502003C3042FFFF0122102173
+:1043A00000E21021AD02005C9502003C8D03005C30
+:1043B0003042FFFF0002104000E210210043102BAA
+:1043C00010400003000000000A0010C68D02005CCF
+:1043D0009502003C3042FFFF0002104000E2102135
+:1043E000AD02005CA1000084AD07004C8CA2010866
+:1043F00000E210231840000224E2FFFCACA20108F6
+:1044000030C200011040000A000000008D02005080
+:1044100000E2102304410004010020218D02005419
+:1044200014E20003000000000A0010E82406000562
+:104430008D02005414E200478FBF00103C020800B8
+:104440008C4200D8304200201040000A24020001B3
+:1044500091030078910200831443000624020001B6
+:1044600001002021240600048FBF00100A00105410
+:1044700027BD0018A1000084A50200148F4301008D
+:104480008F4201F80440FFFE240200020A00110DD1
+:10449000000000008C82005C004910230043102BB8
+:1044A00054400001AC87005C9502003C3042FFFFA5
+:1044B0000062102B14400007240200029502003C09
+:1044C0008D03005C3042FFFF00621821AD03005CE9
+:1044D00024020002AD07004CA10200840E000F0A66
+:1044E0008F4401001040001B8FBF00108F4301005C
+:1044F0008F4201F80440FFFE24020002AF4301C0D6
+:10450000A34201C43C021000AF4201F80A0011238B
+:104510008FBF001030C200101040000E8FBF00107F
+:104520008C83005C9482003C006918233042FFFFBA
+:10453000006218213C023FFF3444FFFF0083102B30
+:10454000544000010080182101231021AD02005CBD
+:104550008FBF001003E0000827BD001827BDFFE84B
+:104560008FAA0028AFBF00100080402100EA482336
+:104570001920002130C600FF8C83005C8C8200640F
+:10458000006A18230043102B5040001000691821C6
+:1045900094A2011001221021A4A2011094A20110E2
+:1045A0003042FFFF0043102B1440000A3C023FFF43
+:1045B00094A2011000431023A4A201109482003C95
+:1045C0003042FFFF0A00114200621821A4A001102E
+:1045D0003C023FFF3444FFFF0083102B5440000196
+:1045E0000080182100671021AD02005CA100007C52
+:1045F0000A00118AA100008130C200101040003C66
+:10460000000000008C820050004A1023184000383F
+:10461000000000009082007C24420001A082007C07
+:104620009082007C3C0308008C630024304200FF31
+:104630000043102B1440005C8FBF00108CA20108B7
+:1046400000E2102318400058000000008C83005442
+:104650009482003C006A18233042FFFF0003184395
+:10466000000210400043102A104000050000000026
+:104670008C820054004A10230A001171000210437A
+:104680009482003C3042FFFF00021040AD02006403
+:104690009502003C8D0400649503003C3042FFFF0E
+:1046A00000021040008220213063FFFF00831821A8
+:1046B00001431021AD02005C8D020054ACA2010840
+:1046C00024020002A10200840E000F0A8F440100A0
+:1046D000104000358FBF00108F4301008F4201F85A
+:1046E0000440FFFE240200020A0011B30000000093
+:1046F000AD07004C8CA2010800E210231840000214
+:1047000024E2FFFCACA2010830C200011040000A04
+:10471000000000008D02005000E21023044100045C
+:10472000010020218D02005414E20003000000006B
+:104730000A0011AA240600058D02005414E2001A92
+:104740008FBF00103C0208008C4200D8304200208D
+:104750001040000A240200019103007891020083B6
+:104760001443000624020001010020212406000455
+:104770008FBF00100A00105427BD0018A10000844C
+:10478000A50200148F4301008F4201F80440FFFE90
+:1047900024020002AF4301C0A34201C43C02100046
+:1047A000AF4201F88FBF001003E0000827BD0018DA
+:1047B0008FAA00108C8200500080402130C600FF7C
+:1047C000004A102300A048211840000700E01821EB
+:1047D00024020001A0800084A0A00112A482001481
+:1047E0000A001125AFAA0010A0800081AD07004C7F
+:1047F0008CA2010800E210231840000224E2FFFC12
+:10480000ACA2010830C20001104000080000000006
+:104810008D0200500062102304410013240600059D
+:104820008D02005410620010000000008D02005440
+:1048300014620011000000003C0208008C4200D805
+:10484000304200201040000A240200019103007849
+:10485000910200831443000624020001010020217C
+:1048600001202821240600040A0010540000000042
+:10487000A1000084A502001403E00008000000006D
+:1048800027BDFFE0AFBF0018274201009046000A95
+:104890008C4800148C8B004C9082008430C900FF3F
+:1048A00001681823304A00FF1C60001A2D460006DC
+:1048B000240200010142100410C00016304300031E
+:1048C000012030210100382114600007304C000C19
+:1048D00015800009304200301440000B8FBF0018D3
+:1048E0000A001214000000000E001125AFAB0010EA
+:1048F0000A0012148FBF00180E00109AAFAB001000
+:104900000A0012148FBF0018AFAB00100E0011BACE
+:10491000AFAA00148FBF001803E0000827BD0020D5
+:1049200024020003A08200848C82005403E000086B
+:10493000ACA201083C0200080342182190620081E9
+:10494000240600433C07601924420001A062008154
+:10495000906300813C0208008C4200C0306300FF7D
+:10496000146200102403FF803C0208008C4200E027
+:104970000082102100431024AF4200243C020800B2
+:104980008C4200E03C03000A008210213042007F8C
+:104990000342102100431021944500D40A000AF17B
+:1049A00030A5FFFF03E000080000000027BDFFE086
+:1049B000AFBF0018AFB10014AFB000108F4201803C
+:1049C0000080802100A088210E00121B00402021C1
+:1049D000A20000848E0200548FBF00188FB0001018
+:1049E000AE2201088FB1001403E0000827BD0020AB
+:1049F00027BDFFE03C020008AFB00010AFBF0018B9
+:104A0000AFB10014034280218F5101409203008412
+:104A10008E0400508E02004C14820040306600FF6D
+:104A20003C0208008C4200E02403FF800222102197
+:104A300000431024AF4200243C0208008C4200E0F6
+:104A40009744007C92050081022210213042007FB1
+:104A5000034218213C02000A0062182114A0000B36
+:104A60003084FFFF2402000554C20014248205DCB8
+:104A70009062011224420001A062011224020C8003
+:104A8000AF4200240A00127324020005A060011244
+:104A90002402000514C20009248205DC9202008170
+:104AA0002C4200075040000524820A009203008136
+:104AB0002402001400621004008210213044FFFF21
+:104AC000A60400140E00121B022020219602003CB6
+:104AD0008E03004C022020213042FFFF00021040D4
+:104AE000006218210E000250AE03005C9202007DAD
+:104AF00002202021344200400E000259A202007D13
+:104B00008F4201F80440FFFE24020002AF5101C0B1
+:104B1000A34201C43C021000AF4201F88FBF00184D
+:104B20008FB100148FB0001003E0000827BD0020F3
+:104B300008000ACC08000B1408000B9808000BE4CE
+:044B400008000C203D
+:0C4B44000A000028000000000000000033
+:104B50000000000D6370362E302E3135000000004D
+:104B600006000F040000000000000000000000002C
+:104B70000000000000000000000000000000000035
+:104B80000000000000000000000000000000002005
+:104B90000000000000000000000000000000000015
+:104BA0000000000000000000000000000000000005
+:104BB00000000000000000000000000000000001F4
+:104BC0000000002B000000000000000400030D4066
+:104BD00000000000000000000000000000000000D5
+:104BE00000000000000000001000000300000000B2
+:104BF0000000000D0000000D3C0208002442588413
+:104C00003C03080024635F50AC4000000043202BAD
+:104C10001480FFFD244200043C1D080037BD7FFCCA
+:104C200003A0F0213C100800261000A03C1C080046
+:104C3000279C58840E0001AC000000000000000D0D
+:104C400027BDFFE83C096018AFBF00108D2C500055
+:104C5000240DFF7F24080031018D5824356A380C5B
+:104C600024070C003C1A8000AD2A50003C04800A46
+:104C7000AF4800083C1B8008AF4700240E00091510
+:104C8000AF8400100E0008D8000000000E000825B8
+:104C9000000000000E001252000000003C046016EC
+:104CA0008C8500003C06FFFF3C02535300A61824ED
+:104CB0001062004734867C0094C201F2A780002C69
+:104CC00010400003A78000CC38581E1EA798002C67
+:104CD00094C201F810400004978300CC38591E1E7E
+:104CE000A79900CC978300CC2C7F006753E000018C
+:104CF000240300669784002C2C82040114400002D7
+:104D000000602821240404003C0760008CE904387A
+:104D10002403103C3128FFFF1103001F30B9FFFFAF
+:104D200057200010A38000CE24020050A38200CEA2
+:104D3000939F00CE53E0000FA78500CCA78000CC46
+:104D4000978500CC8FBF0010A780002CA78000346F
+:104D5000A78000E63C010800AC25008003E00008C5
+:104D600027BD0018939F00CE57E0FFF5A78000CC29
+:104D7000A78500CC978500CC8FBF0010A784002C9E
+:104D8000A7800034A78000E63C010800AC25008025
+:104D900003E0000827BD0018A38000CE8CCB003CA8
+:104DA000316A00011140000E0000000030A7FFFF33
+:104DB00010E0FFDE240200508CCC00C831860001D8
+:104DC00014C0FFDC939F00CE0A00007A2402005139
+:104DD0008C8F00043C0E60000A00005D01EE302163
+:104DE0008CEF0808240D5708000F740211CD000441
+:104DF00030B8FFFF240500660A00007B240404008D
+:104E00001700FFCC939F00CE0A00007A24020050C6
+:104E10008F8600103089FFFF000939408CC30010D5
+:104E20003C08005000E82025AF4300388CC5001432
+:104E300027420400AF82001CAF45003CAF44003065
+:104E40000000000000000000000000000000000062
+:104E50000000000000000000000000000000000052
+:104E60008F4B0000316A00201140FFFD0000000060
+:104E700003E00008000000008F840010948A001AEC
+:104E80008C8700243149FFFF000940C000E8302131
+:104E9000AF46003C8C8500248F43003C00A31023C8
+:104EA00018400029000000008C8B002025620001C2
+:104EB0003C0D005035AC0008AF420038AF4C00301C
+:104EC00000000000000000000000000000000000E2
+:104ED00000000000000000000000000000000000D2
+:104EE0008F4F000031EE002011C0FFFD00000000D8
+:104EF0008F4A04003C080020AC8A00108F4904044B
+:104F0000AC890014AF4800300000000094860018FF
+:104F10009487001C00C71821A48300189485001AE8
+:104F200024A20001A482001A9498001A9499001EE9
+:104F3000133800030000000003E000080000000038
+:104F400003E00008A480001A8C8200200A0000DC24
+:104F50003C0D00500A0000CD000000003C0308009A
+:104F60008C6300208F82001827BDFFE810620008C4
+:104F7000AFBF00100E000104AF8300183C0308000F
+:104F80008C63002024040001106400048F89001049
+:104F90008FBF001003E0000827BD00188FBF00106E
+:104FA0003C076012A520000A9528000A34E500108D
+:104FB00027BD00183106FFFF03E00008ACA60090F3
+:104FC0003C0208008C42002027BDFFC8AFBF003460
+:104FD000AFBE0030AFB7002CAFB60028AFB500248D
+:104FE000AFB40020AFB3001CAFB20018AFB10014D3
+:104FF00010400050AFB000108F840010948600065F
+:105000009483000A00C3282330B6FFFF12C0004A71
+:105010008FBF003494890018948A000A012A402323
+:105020003102FFFF02C2382B14E0000202C020212F
+:10503000004020212C8C0005158000020080A0215A
+:10504000241400040E0000B3028020218F8700107A
+:1050500002809821AF80001494ED000A028088211C
+:105060001280004E31B2FFFF3C1770003C1540002B
+:105070003C1E60008F8F001C8DEE000001D71824AD
+:10508000507500500220202102A3802B160000350D
+:105090003C182000507800470220202124100001F5
+:1050A0008F83001414600039029158230230F823D2
+:1050B0000250C82133F1FFFF1620FFEE3332FFFF0D
+:1050C0008F8700103C110020AF510030000000001D
+:1050D00094E6000A3C1E601237D5001002662821B3
+:1050E000A4E5000A94E2000A94F2000A94F400187D
+:1050F0003057FFFF1292003BAEB700908CED0014CA
+:105100008CE400100013714001AE4021000E5FC31B
+:10511000010E502B008B4821012A1821ACE8001405
+:10512000ACE3001002D3382330F6FFFF16C0FFB9FE
+:105130008F8400108FBF00348FBE00308FB7002CDB
+:105140008FB600288FB500248FB400208FB3001CC9
+:105150008FB200188FB100148FB0001003E0000868
+:1051600027BD0038107E001B000000001477FFCC24
+:10517000241000010E001598000000008F83001419
+:105180001060FFCB0230F823029158238F87001064
+:10519000017020210A0001973093FFFF8F830014D4
+:1051A0001460FFCB3C110020AF5100300A000163B6
+:1051B000000000000E00077D024028210A00015770
+:1051C000004080210E00033A024028210A000157C6
+:1051D000004080210E001460022020210A000157A7
+:1051E000004080210E0000CD000000000A0001797F
+:1051F00002D3382327BDFFE8AFB00010AFBF0014C3
+:105200000E00003F000000003C028000345000709F
+:105210000A0001BA8E0600008F4F000039EE00012F
+:1052200031C20001104000248F8600A88E070000C4
+:105230003C0C08008D8C003C3C0908008D2900388E
+:1052400000E66823018D28210000502100AD302B9D
+:10525000012A4021010620213C010800AC25003C28
+:10526000AF8700A83C010800AC2400380E000106FE
+:10527000000000003C0308008C6300701060FFE633
+:10528000006020213C0508008CA500683C06080051
+:105290008CC6006C0E001527000000003C010800C1
+:1052A000AC2000708F4F000039EE000131C20001C8
+:1052B0001440FFDE8F8600A88E0A00008F8B00A8A6
+:1052C0003C0508008CA5003C3C0408008C84003898
+:1052D000014B482300A938210082182100E9402B06
+:1052E000006810213C010800AC27003C3C0108008C
+:1052F000AC2200388F5F01002419FF0024180C0035
+:1053000003F9202410980012AF840000AF4400205D
+:10531000936D0000240C002031A600FF10CC001279
+:10532000240E005010CE00043C194000AF59013843
+:105330000A0001B3000000000E0011C800000000C8
+:105340003C194000AF5901380A0001B300000000C9
+:105350000E00011F000000003C194000AF59013849
+:105360000A0001B3000000008F58010000802821CE
+:10537000330F00FF01E020210E0002F1AF8F000487
+:105380003C194000AF5901380A0001B30000000089
+:1053900000A4102B2403000110400009000030215C
+:1053A0000005284000A4102B04A0000300031840AF
+:1053B0005440FFFC000528405060000A0004182BF0
+:1053C0000085382B54E000040003184200C3302548
+:1053D00000852023000318421460FFF900052842CD
+:1053E0000004182B03E0000800C310218F4201B80D
+:1053F0000440FFFE00000000AF4401803C031000A9
+:1054000024040040AF450184A3440188A3460189D8
+:10541000A747018A03E00008AF4301B83084FFFFCB
+:105420000080382130A5FFFF000020210A00022A59
+:10543000240600803087FFFF8CA40000240600387B
+:105440000A00022A000028218F8300388F8600304E
+:105450001066000B008040213C07080024E759F843
+:10546000000328C000A710218C4400002463000121
+:10547000108800053063000F5466FFFA000328C04F
+:1054800003E00008000010213C07080024E759FC55
+:1054900000A7302103E000088CC200003C0390000C
+:1054A0003462000100822025AF4400208F45002097
+:1054B00004A0FFFE0000000003E000080000000060
+:1054C0003C038000346200010082202503E00008D4
+:1054D000AF44002027BDFFE0AFB100143091FFFFC3
+:1054E000AFB00010AFBF00181220001300A0802141
+:1054F0008CA2000024040002240601401040000F8A
+:10550000004028210E000C5C00000000000010216B
+:10551000AE000000022038218FBF00188FB10014A8
+:105520008FB0001000402021000028210000302111
+:105530000A00022A27BD00208CA200000220382188
+:105540008FBF00188FB100148FB0001000402021D1
+:1055500000002821000030210A00022A27BD002077
+:1055600000A010213087FFFF8CA500048C440000B0
+:105570000A00022A2406000627BDFFE0AFB0001093
+:10558000AFBF0018AFB100149363003E00808021CC
+:105590000080282130620040000020211040000FD0
+:1055A0008E1100000E000851022020219367000098
+:1055B0002404005030E500FF50A400128E0F0000BC
+:1055C000022020218FBF00188FB100148FB000106F
+:1055D000A762013C0A00091127BD00200E000287C6
+:1055E000000000000E0008510220202193670000F7
+:1055F0002404005030E500FF14A4FFF20220202113
+:105600008E0F00003C1008008E1000503C0D000C66
+:10561000240BFF8001F05021314E007F01DA602120
+:10562000018D4021014B4824AF4900280220202150
+:105630008FBF00188FB100148FB00010A50200D6E4
+:1056400027BD00200A000911AF8800D027BDFFE068
+:10565000AFBF0018AFB10014AFB0001093660001E7
+:10566000008080210E00025630D1000493640005B2
+:10567000001029C2A765000034830040A363000521
+:105680000E00025F020020210E00091302002021FB
+:1056900024020001AF62000C02002821A762001062
+:1056A00024040002A762001224060140A76200142D
+:1056B0000E000C5CA76200161620000F8FBF0018AA
+:1056C000978C00343C0B08008D6B00782588FFFF19
+:1056D0003109FFFF256A0001012A382B10E000067E
+:1056E000A78800343C0F6006240E001635ED00102C
+:1056F000ADAE00508FBF00188FB100148FB00010F6
+:1057000003E0000827BD002027BDFFE0AFB1001473
+:10571000AFBF0018AFB0001000A088211080000AB1
+:105720003C03600024020080108200120000000090
+:105730000000000D8FBF00188FB100148FB0001053
+:1057400003E0000827BD00208C682BF80500FFFE51
+:1057500000000000AC712BC08FBF00188FB1001487
+:105760008FB000103C09100027BD002003E00008A6
+:10577000AC692BF80E00025600A0202193650005AD
+:10578000022020210E00025F30B000FF2403003E03
+:105790001603FFE7000000008F4401780480FFFE3D
+:1057A000240700073C061000AF51014002202021D1
+:1057B000A34701448FBF00188FB100148FB00010B1
+:1057C000AF4601780A0002C227BD002027BDFFE8CE
+:1057D000AFBF0014AFB000108F50002000000000D9
+:1057E0000E000913AF440020AF5000208FBF0014FB
+:1057F0008FB0001003E0000827BD00183084FFFFC1
+:10580000008038212406003500A020210A00022A49
+:10581000000028213084FFFF008038212406003654
+:1058200000A020210A00022A0000282127BDFFD065
+:10583000AFB3001C3093FFFFAFB50024AFB2001828
+:10584000AFBF0028AFB40020AFB10014AFB000105C
+:1058500030B5FFFF12600027000090218F90001CE0
+:105860008E0300003C0680002402004000033E023C
+:1058700000032C0230E4007F006688241482001D9F
+:1058800030A500FF8F8300282C68000A510000100B
+:105890008F910014000358803C0C0800258C56881A
+:1058A000016C50218D49000001200008000000001B
+:1058B00002B210213045FFFF0E000236240400849E
+:1058C000162000028F90001CAF8000288F910014DA
+:1058D000260C002026430001018080213072FFFF4A
+:1058E00016200004AF8C001C0253502B1540FFDC27
+:1058F00000000000024010218FBF00288FB5002457
+:105900008FB400208FB3001C8FB200188FB1001429
+:105910008FB0001003E0000827BD0030240E0034D3
+:1059200014AE00F9000000009203000E241F168040
+:105930003C07000CA36300219202000D0347C8211D
+:105940003C066000A3620020961100123C0A7FFF13
+:10595000354CFFFFA771003C960B00102403000597
+:105960003168FFFFAF6800848E05001CAF5F002820
+:105970008F3800008CC4444803057826008F3021FE
+:10598000AF66004C8F69004C24CE00013C057F00BF
+:10599000AF6900508F740050AF740054AF66007050
+:1059A000AF6E00588F6D005824140050AF6D005C2E
+:1059B000A3600023AF6C0064A36300378E02001461
+:1059C000AF6200488F710048AF7100248E0B001841
+:1059D000AF6B006C9208000CA3680036937F003E0A
+:1059E00037F90020A379003E8F78007403058024E6
+:1059F000360F4000AF6F007493640000308900FFE1
+:105A0000513402452404FF803C04080024845A7861
+:105A10000E00028D000000003C1008008E105A7825
+:105A20000E00025602002021240600042407000173
+:105A3000A366007D020020210E00025FA36700051F
+:105A40008F5F017807E0FFFE240B0002AF5001409A
+:105A5000A34B01448F90001C3C081000AF48017814
+:105A60000A000362AF8000282CAD003751A0FF98D8
+:105A70008F9100140005A0803C180800271856B02C
+:105A8000029878218DEE000001C00008000000009F
+:105A90002418000614B80011000000003C0808009B
+:105AA0008D085A7824040005AF4800208E1F001886
+:105AB000AF7F00188F79004CAF79001C8F650050C4
+:105AC000122000C0AF6500700A000362AF84002896
+:105AD0002406000710A60083240300063C050800E6
+:105AE00024A55A780E000264240400818F90001CC3
+:105AF0000011102B0A000362AF8200282407000463
+:105B000014A7FFF6240500503C1808008F185A7897
+:105B1000AF5800208E0F0008AF6F00408E090008BC
+:105B2000AF6900448E14000CAF7400488E0E001054
+:105B3000AF6E004C8E0D0010AF6D00848E0A001405
+:105B4000AF6A00508E0C0018AF6C00548E04001C1D
+:105B5000AF64005893630000306B00FF116501D8FB
+:105B6000000000008F7400488F6900400289702394
+:105B700005C000042404008C1620FFDE240200036C
+:105B8000240400823C05080024A55A780E000287F0
+:105B9000000000008F90001C000010210A0003622A
+:105BA000AF820028240F000514AFFFCC240520008D
+:105BB0003C0708008CE75A78AF4700208E060004A7
+:105BC000AF66005C9208000824100008A36800215A
+:105BD0008F9F001C93F90009A37900208F86001C79
+:105BE00090D8000A330400FF10900011000000005C
+:105BF0002885000914A0006924020002240A00205C
+:105C0000108A000B34058000288D002115A00008A3
+:105C100024054000240E0040108E00053C050001C4
+:105C200024140080109400023C050002240540006A
+:105C30008F7800743C19FF00031980240205782531
+:105C4000AF6F007490C4000BA36400818F84001CAC
+:105C50009489000C11200192000000009490000C27
+:105C60002406FFBF24050004A770003C908F000E9F
+:105C7000A36F003E8F84001C9089000FA369003F32
+:105C80008F8B001C8D6E00108F54007401D468231C
+:105C9000AF6D00608D6A0014AF6A0064956C0018E7
+:105CA000A76C00689563001AA763006A8D62001CE8
+:105CB000AF62006C9167000EA367003E9368003EE0
+:105CC0000106F8241220014BA37F003E8F90001C98
+:105CD0000A000362AF8500282407002214A7FF7F73
+:105CE000240300073C0B08008D6B5A781220000C2F
+:105CF000AF4B00200A000362AF830028240C00335E
+:105D000010AC0014240A00283C05080024A55A7889
+:105D10000E00023C240400810A0003EB8F90001C5B
+:105D20003C04080024845A780E00028D0000000014
+:105D30009363000024110050306200FF10510135C0
+:105D4000000000008F90001C000018210A00036270
+:105D5000AF8300283C0D08008DAD5A7824040081E3
+:105D6000AF4D00203C05080024A55A780E00023CE7
+:105D7000A36A00348F90001C240200090A00036209
+:105D8000AF82002802B288213225FFFF0E000236C2
+:105D9000240400840A0003628F90001C1082FFA478
+:105DA00024050400288B000311600170240C0004FA
+:105DB000240300015483FF9E240540000A00043B95
+:105DC000240501003C04080024845A788F62004CAA
+:105DD0000E00028D8F6300508F90001C0000202168
+:105DE0000A000362AF8400288E1000042404008A95
+:105DF000AF50002093790005333800021700015F8F
+:105E0000020028219368002302002821311F00206E
+:105E100017E0015A2404008D9367003F2406001206
+:105E200030E200FF10460155240400810E000256A6
+:105E30000200202193630023240500040200202196
+:105E4000346B0042A36B00230E00025FA365007D4C
+:105E50008F4401780480FFFE240A0002AF50014005
+:105E6000A34A01448F90001C3C0C1000AF4C0178F9
+:105E70000A0003EC0011102B8E1000042404008A89
+:105E8000AF500020936E000531CD000215A0001622
+:105E900002002821936F003F2414000402002821EF
+:105EA00031E900FF11340010240400810E00025675
+:105EB000020020219362002324080012241FFFFE09
+:105EC00034460020A3660023A368003F93790005B1
+:105ED00002002021033FC0240E00025FA3780005CA
+:105EE00002002821000020210E00033400000000E1
+:105EF0000A0003EB8F90001C8E1000043C03000886
+:105F00000343A021AF500020928B000024050050D5
+:105F1000316400FF10850161240700880200202100
+:105F2000000028210E00022A2406000E928D000097
+:105F3000240EFF800200282101AE8025A2900000DF
+:105F4000240400040E000C5C240600300A0003EB5D
+:105F50008F90001C8E0800043C14080026945A7888
+:105F60003C010800AC285A78AF480020921F00037B
+:105F700033F9000413200002240200122402000658
+:105F8000A362003F920B001B2404FFC03165003F59
+:105F900000A43825A367003E9206000330C200012A
+:105FA00014400132000000008E020008AE8200089A
+:105FB0003C0208008C425A8010400131000249C264
+:105FC000A76900088E14000C240C0001240300149F
+:105FD000AF74002C8E0E0010AF6E0030960D0016C0
+:105FE000A76D0038960A0014A76A003AAF6C000C3F
+:105FF000A76C0010A76C0012A76C0014A76C001609
+:1060000012200136A3630034920F000331F0000226
+:106010002E1100018F90001C262200080A00036246
+:10602000AF8200288E0400043C0E0008034E30218D
+:10603000AF4400208E05000890CD0000240C0050D5
+:1060400031AA00FF114C00862407008824060009AD
+:106050000E00022A000000000A0003EB8F90001CD3
+:106060008E04001C0E00024100000000104000F4ED
+:10607000004050218F89001C240700890140202105
+:106080008D25001C240600010E00022A00000000DD
+:106090000A0003EB8F90001C960D00023C140800D0
+:1060A00026945A7831AA0004514000B83C10600090
+:1060B0008E0E001C3C010800AC2E5A78AF4E00201A
+:1060C000920700102408001430E200FF144800D6A4
+:1060D00000000000960B00023163000114600165AE
+:1060E000000000008E020004AE8200083C1408008C
+:1060F0008E945A801280015B000000008F7400743F
+:106100003C0380002404000102835825AF6B007417
+:10611000A3600005AF64000C3C0708008CE75A80C0
+:106120008F86001CA7640010000711C2A76400122C
+:10613000A7640014A7640016A76200088CC80008B2
+:1061400024040002AF68002C8CC5000CAF65003041
+:1061500090DF0010A37F00348F99001C9330001152
+:10616000A37000358F98001C930F0012A36F0036A8
+:106170008F89001C912E0013A36E00378F90001C96
+:10618000960D0014A76D0038960A0016A76A003A0B
+:106190008E0C0018AF6C00245620FDCCAF84002874
+:1061A0003C05080024A55A780E0002640000202156
+:1061B0008F90001C0A0004A7000020218E1000040C
+:1061C00024070081AF500020936900233134001070
+:1061D000128000170000000002002021000028218A
+:1061E0002406001F0E00022A000000000A0003EB34
+:1061F0008F90001C3C05080024A55A780E000287E9
+:10620000240400828F90001C000028210A000362F1
+:10621000AF8500283C0408008C845A780E0014E5F1
+:10622000000000008F90001C0A000482000018216A
+:106230000E00025602002021937800230200202144
+:10624000370F00100E00025FA36F002300003821FB
+:1062500002002021000028210A0005A82406001FB2
+:10626000920F000C31E90001112000030000000032
+:106270009618000EA4D8002C921F000C33F90002CF
+:1062800013200005000038218E0200149608001229
+:10629000ACC2001CA4C8001A0A0005432406000969
+:1062A0003C05080024A55A780E0002872404008BC0
+:1062B0008F90001C0011282B0A000362AF85002874
+:1062C000AF6000843C0A08008D4A5A783C0D0800F3
+:1062D0008DAD0050240CFF803C02000C014D1821B4
+:1062E000006C2024AF4400288E070014306B007F20
+:1062F000017A282100A2C821AF2700D88E060014F9
+:10630000AF9900D0AF2600DC8E080010251FFFFEDD
+:106310000A000408AF3F01083C0508008CA55A7824
+:106320003C1908008F39005024CCFFFE00B9C02171
+:1063300003047824AF4F00283C1408008E945A7848
+:106340003C0908008D2900500289702131CD007F61
+:1063500001BA502101478021AE0600D8AF9000D08D
+:10636000AE0000DC0A0003B1AE0C0108548CFE3014
+:10637000240540000A00043B240510000E00032EF3
+:10638000000000000A0003EB8F90001C8E0F442CCD
+:106390003C186C62370979703C010800AC205A78CF
+:1063A00015E9000824050140979F00349786002CCA
+:1063B0000280282103E6C82B132000112404009238
+:1063C000240501400E000C7A240400023C01080060
+:1063D000AC225A78AF4200203C0508008CA55A78C0
+:1063E00010A00005240400830E00084500000000F2
+:1063F00010400009240400833C05080024A55A78B5
+:106400000E000264000000008F90001C0011202B81
+:106410000A000362AF8400280E0008490000000053
+:106420000A00055F8F90001C0E00084D0000000060
+:106430003C05080024A55A780A00062F2404008B86
+:10644000240400040E000C7A240500301440002AB5
+:10645000004050218F89001C240700830140202127
+:106460008D25001C0A000551240600018E04000839
+:106470000E000241000000000A00051BAE82000869
+:106480003C05080024A55A780E00023C240400872D
+:106490008F90001C0A0005360011102B8F830038E6
+:1064A0008F8600301066FE9D000038213C070800F2
+:1064B00024E759FC000320C0008728218CAC000091
+:1064C00011900061246A00013143000F5466FFFA05
+:1064D000000320C00A0004F6000038213C05080033
+:1064E00024A55A780E000287240400828F90001C95
+:1064F0000A000536000010213C0B0008034B202148
+:106500002403005024070001AF420020A0830000B4
+:10651000A08700018F82001C90480004A08800180A
+:106520008F85001C90A60005A08600198F9F001C77
+:1065300093F90006A099001A8F90001C921800078A
+:10654000A098001B8F94001C928F0008A08F001C45
+:106550008F89001C912E0009A08E001D8F8D001CBC
+:1065600091AC000AA08C001E8F8B001C3C0C080014
+:10657000258C59FC9163000B3C0B0800256B59F8E6
+:10658000A083001F8F87001C90E8000CA0880020CB
+:106590008F82001C9045000D24024646A0850021F4
+:1065A0008F86001C90DF000EA09F00228F99001C98
+:1065B0009330000FA09000238F98001C93140010BC
+:1065C000A09400248F8F001C91E90011A089002560
+:1065D0008F89001C8F8E00308F900038952D00140D
+:1065E000000E18C025C80001A48D002895270016AC
+:1065F000006C3021006BC821A487002A9525001863
+:106600003108000FA485002CA482002E8D3F001CB1
+:10661000ACCA0000AF88003011100006AF3F000088
+:10662000000038218D25001C014020210A00055161
+:1066300024060001250C00013184000F00003821E0
+:106640000A0006B8AF8400383C07080024E759F870
+:106650000087302100003821ACA000000A0004F6B9
+:10666000ACC000003C05080024A55A780A00062F9B
+:10667000240400878E0400040E0002410000000084
+:106680000A00056AAE8200083084FFFF30C600FFB2
+:106690008F4201B80440FFFE00064400010430258B
+:1066A0003C07200000C720253C031000AF400180BC
+:1066B000AF450184AF44018803E00008AF4301B84F
+:1066C00027BDFFE8AFB00010AFBF00143C0760006B
+:1066D000240600021080000600A080210010102B6C
+:1066E0008FBF00148FB0001003E0000827BD001812
+:1066F0003C09600EAD2000348CE5201C8F82001C0C
+:106700002408FFFC00A81824ACE3201C0E0006D1CE
+:106710008C45000C0010102B8FBF00148FB00010A0
+:1067200003E0000827BD00183C02600E344701005A
+:1067300024090018274A040000000000000000009F
+:10674000000000003C06005034C30200AF44003893
+:10675000AF45003CAF430030014018218F4B000093
+:10676000316800201100FFFD2406007F2408FFFF90
+:106770008C6C000024C6FFFF24630004ACEC000016
+:1067800014C8FFFB24E70004000000000000000024
+:10679000000000003C0F0020AF4F00300000000060
+:1067A00024AD020001A5702B2529FFFF008E2021BA
+:1067B0001520FFE101A0282103E0000800000000EF
+:1067C00027BDFFE0AFB10014AFBF0018AFB000109D
+:1067D0003C05600E8CA20034008088211440000625
+:1067E0003C0460008C87201C2408FFFC00E8302457
+:1067F00034C30001AC83201C8F8B001C24090001D2
+:10680000ACA90034956900028D6500148D70000CF0
+:106810002D2400818D6700048D660008108000071C
+:106820008D6A00102D2C00041580000E30CE00075C
+:10683000312D000311A0000B000000002404008B88
+:10684000020028210E0006D1240600030011102B9F
+:106850008FBF00188FB100148FB0001003E0000844
+:1068600027BD002015C0FFF62404008B3C03002048
+:10687000AF4300300000000024020001AF8200148A
+:106880000000000000000000000000003C1F01505C
+:10689000013FC825253800033C0F600EAF47003884
+:1068A00000181882AF46003C35E8003CAF59003074
+:1068B000274704008F4400003086002010C0FFFDF1
+:1068C00000000000106000082466FFFF2403FFFFA3
+:1068D0008CEB000024C6FFFF24E70004AD0B000092
+:1068E00014C3FFFB250800043C08600EAD09003806
+:1068F0000000000000000000000000003C07002035
+:10690000AF470030000000000E0006F901402021D2
+:1069100002002821000020210E0006D124060003D9
+:106920000011102B8FBF00188FB100148FB0001012
+:1069300003E0000827BD002027BDFFE0AFB200182C
+:106940003092FFFFAFB10014AFBF001CAFB000101A
+:106950001640000D000088210A0007AA022010211D
+:1069600024050001508500278CE5000C0000000D77
+:10697000262300013071FFFF24E200200232382B71
+:1069800010E00019AF82001C8F8200141440001622
+:106990008F87001C3C0670003C0320008CE5000043
+:1069A00000A62024148300108F84003C00054402BC
+:1069B0003C09800000A980241480FFE9310600FF13
+:1069C0002CCA00095140FFEB262300010006688015
+:1069D0003C0E080025CE578C01AE60218D8B000047
+:1069E0000160000800000000022010218FBF001C81
+:1069F0008FB200188FB100148FB0001003E00008B0
+:106A000027BD00200E0006D1240400841600FFD804
+:106A10008F87001C0A00078BAF80003C90EF0002BC
+:106A200000002021240600090E0006D1000F2E00D0
+:106A30008F87001C0010102B0A00078BAF82003CD0
+:106A4000020028210E0006DF240400018F87001CAD
+:106A50000A00078BAF82003C020028210E0006DFEF
+:106A6000000020210A0007C38F87001C0E00071FAB
+:106A7000020020210A0007C38F87001C30B0FFFFEF
+:106A8000001019C08F5801B80700FFFE3C1F2004FA
+:106A90003C191000AF430180AF400184AF5F018813
+:106AA000AF5901B80A00078C262300013082FFFF8E
+:106AB00014400003000018210004240224030010E5
+:106AC000308500FF14A000053087000F2466000801
+:106AD0000004220230C300FF3087000F14E00005DD
+:106AE000308900032468000400042102310300FF00
+:106AF0003089000315200005388B0001246A00024C
+:106B000000042082314300FF388B00013164000112
+:106B100010800002246C0001318300FF03E00008B4
+:106B200000601021308BFFFF000B394230E600FF80
+:106B30003C09080025295978000640800109602198
+:106B40008D8700003164001F240A0001008A1804A8
+:106B500030A500FF00E3202514A000020003102749
+:106B600000E22024240F000100CF700401096821F5
+:106B7000000E282714800005ADA400008F86000CAD
+:106B800000A6102403E00008AF82000C8F88000CE0
+:106B900001C8102503E00008AF82000C3C06001F6E
+:106BA0003C0360003084FFFF34C5FF8024020020D6
+:106BB000AC602008AC60200CAC602010AC652014E8
+:106BC000AC642018AC62200000000000000000004F
+:106BD00003E000080000000027BDFFE82402FFFFDB
+:106BE000AFBF0010AF82000C000020213C0608005F
+:106BF00024C659782405FFFF248900010004408041
+:106C00003124FFFF010618212C87002014E0FFFA31
+:106C1000AC6500000E0008160000202124020001CF
+:106C20003C04600024050020AC822018AC852000C4
+:106C3000000000000000000000000000244A0001E5
+:106C40003142FFFF2C46040014C0FFF78FBF001035
+:106C500003E0000827BD00188F8300082C620400A1
+:106C600003E00008384200018F830008246200011D
+:106C700003E00008AF8200088F8300082462FFFF52
+:106C800003E00008AF82000827BDFFE0AFB10014A9
+:106C9000AFBF0018AFB000108F6B00303C06600033
+:106CA00000808821ACCB20088F6A002C3C02800039
+:106CB00024030008ACCA200C9769003A9768003892
+:106CC00000092C003107FFFF00A72025ACC42010CD
+:106CD000ACC22014ACC32000000000000000000083
+:106CE000000000003C0360008C6D200031AC000807
+:106CF0001580FFF9000000008C6E201405C00020F4
+:106D0000000000000E0007DA8F84000C00024080B3
+:106D10003C09080025295978010938218CE4000034
+:106D20000E0007DA00028140020220213090FFFFAE
+:106D3000020020210E0007F8000028213C0C8000F2
+:106D4000022C58253210FFFF3C116000240A00205D
+:106D5000AE2B2014AE302018AE2A20000000000018
+:106D60000000000000000000020010218FBF00188A
+:106D70008FB100148FB0001003E0000827BD002081
+:106D80008C6620143C02001F3443FF803C1FFFE848
+:106D900000C3C02437F9080003198021001079C20C
+:106DA0003C0C8000022C582531F0FFFF3C116000A4
+:106DB000240A0020AE2B2014AE302018AE2A20006A
+:106DC0000000000000000000000000000200102190
+:106DD0008FBF00188FB100148FB0001003E00008BF
+:106DE00027BD002027BDFFE8AFB000103402FFFF31
+:106DF0003090FFFFAFBF00141202000602002021F6
+:106E00000E00081600000000020020210E0007F806
+:106E1000240500018F8400088FBF00148FB000107C
+:106E20002483FFFF27BD001803E00008AF8300089C
+:106E3000000439C230E6003F00043B42000718401E
+:106E4000240210002CC4002024C8FFE0AF42002C14
+:106E5000246300011480000330A900FF00071840DC
+:106E6000310600FF0003608024080001019A5821C8
+:106E70003C0A000E00C82804016A382111200005D0
+:106E8000000530278CE900000125302503E00008CB
+:106E9000ACE600008CEE000001C6682403E00008A8
+:106EA000ACED000027BDFFE8AFBF0014AFB000108D
+:106EB0003C0460008C8508083403F00030A2F00028
+:106EC00050430006240200018C8708083404E000C7
+:106ED00030E6F00010C4001E24020002AF82004021
+:106EE0003C1060003C0A0200AE0A0814240910009D
+:106EF0003C08000E8E03440003482021AF49002CBB
+:106F0000240501200E000CC0000030218F830040BA
+:106F1000106000043C021691240B0001106B000E5F
+:106F20003C023D2C344F0090AE0F44088FBF00143C
+:106F30008FB000103C0C6000240E10003C0D0200CD
+:106F400027BD0018AD8E442003E00008AD8D081069
+:106F50000A0008E7AF8000403C0218DA344F009086
+:106F6000AE0F44088FBF00148FB000103C0C6000BF
+:106F7000240E10003C0D020027BD0018AD8E4420E9
+:106F800003E00008AD8D08100A0008BB24050001CD
+:106F90000A0008BB000028213C08080025085D8481
+:106FA0002404FFFF010018212402001E2442FFFFD9
+:106FB000AC6400000441FFFD246300043C070800AA
+:106FC00024E75E008CE5FFFC2404001C240600017D
+:106FD000308A001F0146480424840001000910275C
+:106FE0002C8300201460FFFA00A22824ACE5FFFCEB
+:106FF0003C05666634A4616E3C06080024C65EC08B
+:10700000AF840058AF88009C2404FFFF00C0182103
+:107010002402001F2442FFFFAC6400000441FFFD76
+:10702000246300043C0766663C05080024A55E80D6
+:10703000AF86004834E6616EAF8600982404FFFFF7
+:1070400000A018212402000F2442FFFFAC640000BE
+:107050000441FFFD246300043C0B66663C06080007
+:1070600024C65E003568616EAF8500A4AF880070ED
+:107070002404FFFF00C018212402001F2442FFFF48
+:10708000AC6400000441FFFD246300043C0D66660F
+:107090003C0A0800254A5F4035AC616EAF8600901F
+:1070A000AF8C005C2404FFFF014018212402000380
+:1070B0002442FFFFAC6400000441FFFD2463000490
+:1070C0003C09080025295F508D27FFFC2404000699
+:1070D000240500013099001F0325C0042484000109
+:1070E000001878272C8E002015C0FFFA00EF3824F6
+:1070F000AD27FFFC3C09666624030400240403DC7E
+:1071000024050200240600663522616E3C08080052
+:1071100025085A84AF820074AF830044AF83006CAB
+:10712000AF830050AF830084AF8A008CAF840064CB
+:10713000AF85004CAF860054AF840078AF85006007
+:10714000AF86008001001821240200022442FFFFC4
+:10715000AC6000000441FFFD24630004240400032C
+:107160002403000C3C0A0800254A5A90AF8A0068A4
+:107170000A00098E2405FFFF000418802484000102
+:10718000006858212C8700C014E0FFFBAD650000AB
+:107190003C0E666635CD616E240C17A024081800DD
+:1071A000AF8D0088AF8C009403E00008AF88007CAE
+:1071B0002484007F000421C200004021000030210F
+:1071C00000003821000028210A0009A5AF8400A092
+:1071D0001060000624E7000100C4302124A500014E
+:1071E0002CC20BF51440FFFA2CA300663C090800E2
+:1071F00025295F4001201821240200032442FFFFBB
+:10720000AC6000000441FFFD2463000410E0001A9C
+:1072100024E3FFFF0003294210A0000A0000202100
+:107220002406FFFF3C03080024635F402484000120
+:107230000085502BAC660000250800011540FFFBBF
+:107240002463000430E2001F10400008000868803A
+:10725000240C0001004C38040008588001692821E2
+:1072600024E6FFFF03E00008ACA6000001A94021CE
+:107270002409FFFFAD09000003E000080000000042
+:10728000AF4400283C04000C034420210005288260
+:107290000A000CC000003021000421803C03600083
+:1072A000AC6410080000000000052980AC65100CDB
+:1072B0000000000003E000088C62100C27BDFFE80E
+:1072C0000080282124040038AFBF00140E0009D527
+:1072D000AFB0001024040E00AF4400283C10000C96
+:1072E00003502021240500100E000CC000003021A6
+:1072F00003501021AC400000AC40000424040038CE
+:107300008FBF00148FB0001024053FFF27BD001869
+:107310000A0009D58C430000000421803C03600072
+:10732000AC641008000000008C62100C03E0000840
+:107330000002118227BDFFC8AFB400208F940068FF
+:10734000AFBE0030AFB7002CAFB600280000B821A8
+:107350000080B021241E00C0AFBF0034AFB50024B0
+:10736000AFB3001CAFB20018AFB10014AFB0001043
+:107370000A000A12AFA5003C504000018F9400683B
+:1073800027DEFFFF13C00028269400048E92000021
+:107390003C03080024635D801240FFF70283102B3A
+:1073A0003C04080024845A84028410230002A8C0EC
+:1073B000000098210A000A212411000100118840D0
+:1073C000122000260000000002B380210251282470
+:1073D0000200202110A0FFF9267300010E0009DE33
+:1073E000000000000016684032EC000101AC2021D2
+:1073F0000E0009D5020028218F89009426F700018C
+:107400008FA6003C3AEB0001316A00012528FFFFFE
+:107410000011382702CAB021AF88009416E6FFE7B2
+:1074200002479024AE92000002E010218FBF00348A
+:107430008FBE00308FB7002C8FB600288FB5002488
+:107440008FB400208FB3001C8FB200188FB10014CE
+:107450008FB0001003E0000827BD00383C0E080084
+:1074600025CE5D80028E102B0A000A0DAE92000020
+:1074700027BDFFD8AFB10014AFB00010AFBF0020E0
+:10748000AFB3001CAFB2001800A0882110A0001FED
+:10749000000480403C13080026735A840A000A5AEC
+:1074A0002412000112200019261000010E0009F517
+:1074B00002002021000231422444FFA0000618806F
+:1074C0003045001F2C8217A1007318212631FFFFC1
+:1074D0001040FFF400B230048C690000020020214B
+:1074E00024053FFF012640241500FFEE0126382524
+:1074F0000E0009D5AC6700008F8A009426100001A9
+:10750000254700011620FFE9AF8700948FBF0020B8
+:107510008FB3001C8FB200188FB100148FB0001011
+:1075200003E0000827BD00288F85009C00805821BB
+:107530000000402100004821240A001F3C0C0800E4
+:10754000258C5DFC3C0D080025AD5D848CA60000FB
+:1075500050C000140000402100AD1023000238C0CC
+:10756000240300010A000A930000202115000003F3
+:1075700000E410212448202400004821252900018E
+:10758000512B00132506DFDC106000062484000167
+:1075900000C3702415C0FFF5000318400A000A91CB
+:1075A0000000402110AC002624A300040060282124
+:1075B000254AFFFF1540FFE5AF85009C512B0004D5
+:1075C0002506DFDC0000402103E000080100102157
+:1075D0000006614230C5001F000C50803C070800C7
+:1075E00024E75D8424040001014730211120000FAD
+:1075F00000A420043C05080024A55E0014800005BA
+:107600002529FFFF24C6000410C50011000000005A
+:10761000240400018CCF00000004C0270004204097
+:1076200001F868241520FFF5ACCD00008F99007893
+:1076300001001021032B482303E00008AF890078E4
+:107640003C05080024A55D840A000A9B0000402137
+:107650003C06080024C65D840A000AB42404000124
+:10766000308800FF240200021102000A24030003F4
+:107670001103005C8F8900A4240400041104005F3E
+:1076800024050005110500670000182103E000082B
+:10769000006010218F8900483C0C0800258C5EC0DA
+:1076A0003C04080024845F40240300201060000F85
+:1076B00000005821240D0002240E00033C0F080096
+:1076C00025EF5EC08D27000014E0000B30F9FFFFAE
+:1076D000252900040124C02B53000001018048210A
+:1076E0002463FFFF5460FFF88D270000016018211C
+:1076F00003E0000800601021132000323C0500FF69
+:1077000030E200FF004030211040004200005021D4
+:1077100024050001000020210005C84000A6C02467
+:1077200017000003332500FF14A0FFFB2484000191
+:10773000012CC023001828C000AA6021008C502111
+:107740003144001F240C0001008C18040003102792
+:1077500000E23024110D0041AD260000110E004C56
+:10776000000A1840110D00368F87006C510E00562C
+:107770008F8C0060240D0004110D005A8F8E008440
+:10778000240E0005150EFFDA01601821240B1430B9
+:1077900011400006000018218F8400A0246300011E
+:1077A000006A402B1500FFFD016458218F8A00807C
+:1077B000AF89008C016018212549FFFF0A000AEB00
+:1077C000AF89008000E52024000736021080FFD03A
+:1077D000240A001800075402314600FF0A000AF389
+:1077E000240A00103C0C0800258C5E803C04080034
+:1077F00024845EC00A000ADA240300103C0C08004E
+:10780000258C5E003C04080024845E800A000AD9AE
+:107810008F89009000071A02306600FF0A000AF301
+:10782000240A00088F89008C3C0C0800258C5F40DE
+:107830003C04080024845F500A000ADA2403000490
+:10784000000A4080250B003024E6FFFF016018216C
+:10785000AF8900480A000AEBAF86006C000AC982B3
+:10786000001978803C07080024E75E8001E72021AA
+:10787000000A18428C8F00003079001F032C380456
+:107880000007C02701F860240A000B08AC8C000038
+:10789000000331420006288000AF28213062001F1B
+:1078A0008CB8000024630001004CC804000321428E
+:1078B000001938270004108003073024004F2021CE
+:1078C0000A000B4CACA60000000A68C025AB0032D1
+:1078D000258AFFFF01601821AF8900A40A000AEB86
+:1078E000AF8A0060254B1030AF89009001601821ED
+:1078F00025C9FFFF0A000AEBAF8900843086000724
+:107900002CC2000610400014000000000006408059
+:107910003C030800246357B0010338218CE40000C5
+:1079200000800008000000002409000310A9000ED8
+:1079300000000000240A000510AA000B000000004F
+:10794000240B000110AB0008000000008F8C00A089
+:1079500010AC00050000000003E00008000010214A
+:107960000A000A7900A020210A000AC700C02021CD
+:1079700027BDFFE8308400FF240300021083000BC2
+:10798000AFBF0010240600031086003A240800044C
+:1079900010880068240E0005108E007F2CAF143074
+:1079A0008FBF001003E0000827BD00182CA2003094
+:1079B0001440FFFC8FBF001024A5FFD0000531C28A
+:1079C000000668803C07080024E75EC001A730215C
+:1079D0008CC900000005288230AC001F240B000178
+:1079E000018B50048F840048012A4025ACC8000058
+:1079F0008C83000050600001AF8600488F98006CB7
+:107A000030AE000124A6FFFF270F000115C00002C1
+:107A1000AF8F006C24A600010006414200082080C0
+:107A2000008718218C79000030C2001F2406000155
+:107A30000046F804033F382410E0FFDA8FBF00103F
+:107A40000005C182001870803C0F080025EF5E80A1
+:107A500001CF48218D2B00000005684231A5001F91
+:107A600000A66004016C502527BD001803E0000843
+:107A7000AD2A00002CA7003014E0FFCA8FBF001011
+:107A800030B900071723FFC724A8FFCE00086A02F9
+:107A9000000D60803C0B0800256B5E80018B30215F
+:107AA0008CC40000000828C230AA001F240800016E
+:107AB000014848048F8200A400891825ACC3000047
+:107AC0008C5F000053E00001AF8600A40005704009
+:107AD000000E7942000F28803C04080024845EC018
+:107AE00000A418218C6B000025DF000131CD001FA0
+:107AF000001F514201A86004016C4825000A108053
+:107B0000AC690000004428218CA600008F9800601A
+:107B100033F9001F8FBF00100328380400C77825F1
+:107B2000270E000127BD0018ACAF000003E00008DD
+:107B3000AF8E006024A5EFD02CB804001300FF998D
+:107B40008FBF001000053142000658803C0A080033
+:107B5000254A5E00016A30218CC4000030A3001F5A
+:107B600024090001006910048F9900900082F82513
+:107B7000ACDF00008F27000050E00001AF860090CE
+:107B80008F8D00848FBF001027BD001825AC000129
+:107B900003E00008AF8C008415E0FF828FBF001067
+:107BA0008F8600A0000610400046F821001F21002B
+:107BB00003E4C8210019384024F8143000B8402BE1
+:107BC0001100FF788FBF001024A4EBD00E00021329
+:107BD00000C0282100027942000F70803C0D08008F
+:107BE00025AD5F4001CD20218C8B0000304C001F63
+:107BF00024060001018618048F89008C016350253A
+:107C0000AC8A00008D25000050A00001AF84008CDC
+:107C10008F9800808FBF001027BD00182708000133
+:107C200003E00008AF88008030A5000724030003AC
+:107C300010A3001028A2000414400008240700022A
+:107C40002403000410A300152408000510A8000F49
+:107C50008F8500A003E000080000000014A7FFFDCE
+:107C60000080282114C3FFFB240400020A000B8BB0
+:107C700000000000240900050080282110C9FFFB36
+:107C80002404000303E000080000000014C5FFF115
+:107C9000008028210A000B8B24040005240A00011F
+:107CA0000080282110CAFFF12404000403E000082A
+:107CB0000000000027BDFFE0AFB00010000581C24A
+:107CC0002603FFD024C5003F2C6223D024C6007FAA
+:107CD000AFB20018AFB10014AFBF001C309100FF6D
+:107CE000000691C2000529820200202110400008F0
+:107CF0002403FFFF0E000A4B0000000002002021B9
+:107D0000022028210E000C390240302100001821E9
+:107D10008FBF001C8FB200188FB100148FB00010FD
+:107D20000060102103E0000827BD002027BDFFD818
+:107D300024A2007FAFB3001CAFB20018000299C2AA
+:107D4000309200FF24A3003F02402021026028213E
+:107D5000AFB10014AFB00010AFBF00200E000B6E2B
+:107D60000003898200408021004020210220282138
+:107D700014400009000018218FBF00208FB3001CA1
+:107D80008FB200188FB100148FB000100060102166
+:107D900003E0000827BD00280E0009FC00000000D9
+:107DA00000402821020020211051FFF3001019C0CB
+:107DB0000E000A4B00000000020020210240282192
+:107DC0000E000C39026030218FBF00208FB3001CE1
+:107DD0008FB200188FB100148FB00010000018216E
+:107DE0000060102103E0000827BD00283084FFFF59
+:107DF00030A5FFFF1080000700001821308200012D
+:107E00001040000200042042006518211480FFFB8E
+:107E10000005284003E000080060102110C00007A2
+:107E2000000000008CA2000024C6FFFF24A500046F
+:107E3000AC82000014C0FFFB2484000403E00008AF
+:107E40000000000010A0000824A3FFFFAC86000083
+:107E500000000000000000002402FFFF2463FFFF79
+:107E60001462FFFA2484000403E00008000000000C
+:107E700030A5FFFF8F4201B80440FFFE3C076015AC
+:107E800000A730253C031000AF440180AF400184BF
+:107E9000AF46018803E00008AF4301B88F8500D0EA
+:107EA0002C864000008018218CA700840087102BAE
+:107EB00014400010000000008CA800842D06400033
+:107EC00050C0000F240340008CAA0084008A482B75
+:107ED000512000018CA3008400035A42000B208033
+:107EE0003C05080024A558000085182103E000087F
+:107EF0008C62000014C0FFF4000000002403400066
+:107F000000035A42000B20803C05080024A55800BD
+:107F10000085182103E000088C6200008F8300D0E8
+:107F2000906600D024C50001A06500D08F8500D0E8
+:107F3000906400D090A200D210440017000000000E
+:107F4000936C00788F8B00BC318A00FFA16A000C13
+:107F500025490001938700C4312200FF3048007F8B
+:107F60001107000B00026827A36200788F4E01788A
+:107F700005C0FFFE8F9900B0241800023C0F1000CE
+:107F8000AF590140A358014403E00008AF4F017806
+:107F90000A000D0931A20080A0A000D00A000CFF49
+:107FA000000000008F8700D027BDFFC8AFBF0030A2
+:107FB000AFB7002CAFB60028AFB50024AFB4002097
+:107FC000AFB3001CAFB20018AFB10014AFB00010D7
+:107FD00094E300E094E200E2104300D72405FFFFA1
+:107FE0003C047FFF3497FFFF2415FF800A000DF04B
+:107FF0003C16000E108A00D18FBF00308F9100B068
+:108000003C1808008F18005C001230C0001291402C
+:108010000311702101D57824AF4F002C94EC00E2BD
+:1080200031CD007F01BA5821318A7FFF0176482186
+:10803000000A804002091021945300003C08080007
+:108040008D0800580246C02132733FFF001319808B
+:10805000010320210224282130BF007F03FAC82118
+:1080600000B5A024AF54002C0336A0218E87001049
+:108070008E8F003003785821256D008800EF702323
+:10808000240C0002AE8E0010AF8D00ACA16C0088F5
+:10809000976A003C8E8400308F9100AC0E000CD6A5
+:1080A0003150FFFF00024B80020940253C02420094
+:1080B00001022025AE2400048E8300048F8D00ACC5
+:1080C0008E860000240E0008ADA3001CADA600188B
+:1080D000ADA0000CADA00010929F000A33F900FF84
+:1080E000A5B90014968500083C1F000CA5A5001634
+:1080F0009298000A331100FFA5B100209690000865
+:1081000024180005A5B00022ADA00024928F000B1A
+:108110002410C00031E700FFA5A70002A1AE0001B6
+:108120008E8C00308F8B00AC8F8400B0AD6C00085B
+:108130003C0A08008D4A005401444821013540247E
+:10814000AF4800283C0208008C4200540044302113
+:1081500030C3007F007AC821033F282102458821CF
+:10816000AF9100BCAF8500C0A23800008F8A00BC70
+:108170002403FFBF2418FFDF954F000201F03824CD
+:1081800000F37025A54E0002914D000231AC003F76
+:10819000358B0040A14B00028F8600BC8F8900D038
+:1081A000ACC000048D28007C3C098000ACC80008ED
+:1081B00090C4000D3082007FA0C2000D8F8500BCEE
+:1081C00090BF000D03E3C824A0B9000D8F9100BC3F
+:1081D0009233000D02789024A232000D8E9000346C
+:1081E0008F8B00BCAD7000108E87002C8E8F0030FE
+:1081F00000EF7023AD6E0014916D001831AC007F5C
+:10820000A16C00188F9F00BC8E8A00308FE8001888
+:10821000015720240109302400C41025AFE20018C2
+:108220009283000AA3E3001C969900088F8500BC86
+:108230008F9800D0A4B9001E8E9000308E8400303C
+:108240000E0002138F0500848F8500D0000291403C
+:108250000002990090AF00BC0253882100403021F9
+:1082600031E7000210E0000302118021000290803B
+:108270000212802190B900BC3327000410E00002F4
+:108280000006F880021F80218E9800308F8B00BC82
+:1082900024068000330F0003000F702331CD00034C
+:1082A000020D6021AD6C000494A400E294AA00E2E7
+:1082B00094B000E231497FFF2522000130537FFF57
+:1082C0000206182400734025A4A800E294A400E24A
+:1082D0003C1408008E94006030917FFF123400221D
+:1082E000000000000E000CF6000000008F8700D098
+:1082F0000000282194F300E094F000E21213000F34
+:108300008FBF003090E900D090E800D1313200FFFB
+:10831000310400FF0244302B14C0FF36264A00010E
+:1083200090EE00D2264B000131CD00FF008D602180
+:10833000158BFF338F9100B08FBF00308FB7002CAB
+:108340008FB600288FB500248FB400208FB3001C97
+:108350008FB200188FB100148FB0001000A0102150
+:1083600003E0000827BD003894A300E20066402423
+:10837000A4A800E290A400E290B900E2309100FFCE
+:108380000011A1C20014F827001F39C03332007F4A
+:10839000024730250A000DE8A0A600E23084FFFF66
+:1083A00030A5FFFFAF440018AF45001C03E00008F4
+:1083B0008F42001427BDFFB8AFB000208F9000D0CF
+:1083C0003084FFFFAFA40010AFBF0044AFBE004039
+:1083D000AFB7003CAFB60038AFB50034AFB4003033
+:1083E000AFB3002CAFB20028AFB10024A7A0001893
+:1083F000920600D1920500D030C400FF30A300FFE8
+:108400000064102B10400122AFA00014920900D08C
+:108410008FB50010312800FF0088382324F4FFFFB7
+:108420000014882B0015982B02339024524001260B
+:108430008FB40014961E0012961F00108FB7001004
+:1084400003DFC823001714000019C400000224032E
+:108450000018140302E2B02A52C00001004020219B
+:108460000284282B10A0000200801821028018210D
+:1084700000033C0000071C033064FFFF2C8600094A
+:1084800014C000020060B821241700088E0A0008FA
+:10849000001769808E09000C31ABFFFF3C0C001007
+:1084A000016C402527520400AF4A0038AF9200B853
+:1084B000AF49003CAF480030000000000000000061
+:1084C00000000000000000000000000000000000AC
+:1084D00000000000000000008F4F000031EE00207F
+:1084E00011C0FFFD0017982A027110240A000E83A4
+:1084F0000000B02155E001019258000131130080C5
+:10850000126001CF012020219655001232A5FFFFF5
+:108510000E000CCBA7B500188F9000D00291A023BD
+:1085200026CD00018F9100B8000DB4000016B403F1
+:108530002638004002D7582A0014882B2405000151
+:108540000300902101711024AF9800B8AFA500146A
+:10855000104001BC8F8900B03C0C08008D8C005489
+:10856000240BFF80921E00D001895021014B28244A
+:10857000921900D0AF4500288E4700103C08080033
+:108580008D0800583C1808008F18005430E33FFF56
+:108590000003218001043021012658212402FF809C
+:1085A0000162F824920C00D0AF5F002C92480000CA
+:1085B00033D100FF333500FF0309982100117140CA
+:1085C000001578C0326D007F01CF382101BA282113
+:1085D000318300FF3164007F3C0A000C00AA88212F
+:1085E0000367F02100033140009A10213108003F59
+:1085F0003C1F000E00D1C021005F982127D90088C0
+:108600002D150008AF9100C0AF9900ACAF9800BC29
+:10861000AF9300B412A0018A00008821240E00014B
+:10862000010E4004310D005D11A0FFB2310F0002B8
+:108630008E4A00283C0300803C04FFEFAE6A000035
+:108640008E450024A260000A3488FFFFAE65000456
+:108650009247002C3C1FFF9F37FEFFFFA267000CD4
+:108660008E62000C3C180040A267000B00433025CE
+:1086700000C8C824033E88240238A825AE75000C23
+:108680008E490004AE6000183C0F00FFAE69001474
+:108690008E4D002C35EEFFFF8F8B00B001AE6024B5
+:1086A000AE6C00108E470008A660000896450012C8
+:1086B000AE6700208E42000C30B03FFF00105180AA
+:1086C000AE6200248E5E0014014B182130A400011C
+:1086D000AE7E00288E590018000331C2000443808A
+:1086E000AE79002C8E51001C00C8F821A67F001C1A
+:1086F000AE710030965800028E550020A678001EFC
+:10870000AE75003492490033313000045600000544
+:10871000925000008F8C00D08D8B007CAE6B0030AF
+:10872000925000008F8F00BCA1F00000924E0033E9
+:1087300031CD000251A00007925E00018F8900BC7C
+:108740002418FF80913100000311A825A1350000F5
+:10875000925E00018F9900BC2409FFBF240BFFDF4C
+:10876000A33E00018F9500BC92B8000D3311007F2D
+:10877000A2B1000D8F8E00BC91D0000D02097824AB
+:10878000A1CF000D8F8800BC8E6D0014910A000DE2
+:108790002DAC0001000C2940014B382400E51825C0
+:1087A000A103000D964200128F8800BC8F8700D075
+:1087B000A50200028E45000490FF00BC30A4000317
+:1087C0000004302330DE000300BE102133F9000224
+:1087D00017200002244400342444003090E200BCFE
+:1087E00000A2302430DF000417E0000224830004DC
+:1087F000008018218F8F00AC24090002AD03000413
+:10880000A1E90000924E003F8F8D00ACA1AE0001A7
+:108810008F9500AC924C003F8E440004A6AC000241
+:10882000976B003C0E000CD63170FFFF00025380A6
+:10883000020A38253C05420000E51825AEA30004D5
+:108840008F8600AC8E480038ACC800188E440034C7
+:10885000ACC4001CACC0000CACC00010A4C0001420
+:10886000A4C00016A4C00020A4C00022ACC00024F4
+:108870008E6400145080000124040001ACC4000880
+:108880000E000CF6241100010A000E768F9000D025
+:10889000920F00D2920E00D08FB5001031EB00FF86
+:1088A00031CD00FF008D6023016C50212554FFFF66
+:1088B0000014882B0015982B023390241640FEDDFF
+:1088C000000000008FB400148FBF00448FBE004032
+:1088D0003A8200018FB7003C8FB600388FB5003464
+:1088E0008FB400308FB3002C8FB200288FB10024DA
+:1088F0008FB0002003E0000827BD0048331100209E
+:10890000122000EF24150001921E00BC241F00015C
+:108910000000A82133D900011320000DAFBF001CB7
+:108920008E4400148E0800840088102B144000022E
+:10893000008030218E0600848E03006400C3A82BC3
+:1089400016A0000200C020218E0400640080A8212F
+:108950008E4700148E05006400E5302B14C0000221
+:1089600000E020218E0400640095F02313C0000471
+:108970008FAC001C240A0002AFAA001C8FAC001CA4
+:10898000028C582B156000A8000018218E4F00386B
+:108990008E6D000C3C0E0080AE6F00008E4A0034DD
+:1089A0003C10FF9F01AE5825AE6A00049246003F7E
+:1089B000360CFFFF016C38243C0500203C03FFEF20
+:1089C000A266000B00E510253468FFFF8F8700B812
+:1089D0000048F8243C04000803E4C825AE79000CE4
+:1089E0008CF80014AE60001802BE7821AE78001436
+:1089F0008CF10018AE71001C8CE90008AE690024EF
+:108A00008CEE000CAE6F002CAE600028AE6E002025
+:108A1000A6600038A660003A8CED001401B58023F2
+:108A2000021E902312400011AE72001090EA003D29
+:108A30008E6500048E640000000A310000A6C82183
+:108A4000000010210326402B0082F82103E8C021FA
+:108A5000AE790004AE78000090F1003DA271000AEA
+:108A60008F8900B895320006A67200088F9800AC76
+:108A70002419000202A02021A31900009769003CDC
+:108A80008F9200AC0E000CD63131FFFF00027B80CC
+:108A90008F8500B8022F68253C0E420001AE80256C
+:108AA000AE5000048F8400AC8CAC0038AC8C001845
+:108AB0008CAB0034AC8B001CAC80000CAC80001084
+:108AC000A4800014A4800016A4800020A4800022AA
+:108AD000AC80002490A7003FA487000212A00135BB
+:108AE0002403000153C0000290A2003D90A2003E6A
+:108AF00024480001A08800018F9F00ACAFF500085A
+:108B00008F8300D024070034906600BC30C500027B
+:108B100050A00001240700308F9200B88F8A00BC5B
+:108B2000906D00BC924B00002412C00032A50003DF
+:108B3000A14B00008F8600B88F8800BC240200047F
+:108B400090C400010045182330790003A1040001FE
+:108B50008F8A00BC8F9F00B800F53821955800021D
+:108B600097E9001200F9382103128824312F3FFFC2
+:108B7000022F7025A54E00029150000231A800047A
+:108B8000320C003F358B0040A14B000212A00002C6
+:108B90008F8500BC00E838218F8E00D0ACA7000480
+:108BA000240BFFBF8DCD007C2EA400012403FFDF2A
+:108BB000ACAD000890B0000D00044140320C007FC5
+:108BC000A0AC000D8F8600BC90CA000D014B102494
+:108BD000A0C2000D8F8700BC90E5000D00A3F82413
+:108BE00003E8C825A0F9000D8F9100B88F8D00BC57
+:108BF0008E380020ADB800108E290024ADA90014D5
+:108C00008E2F0028ADAF00188E2E002C0E000CF613
+:108C1000ADAE001C8FB0001C240C0002120C00EE44
+:108C20008F9000D08FA3001C006088211460000288
+:108C30000060A8210000A02156A0FE390291A023C7
+:108C40000014882B8FA90010960700103C1E0020EE
+:108C50000136402302C750213112FFFFA60A00103F
+:108C6000AFB20010AF5E0030000000009617001099
+:108C7000961300121277008F000000008E05000C82
+:108C80008E0B00080016698000AD7021000DC7C36F
+:108C900001CDA82B0178782101F56021AE0E000CE2
+:108CA000AE0C00088FB300100013B82B02378024DD
+:108CB0001200FF048F9000D00A000E3C000000005C
+:108CC0008E4D0038A6600008240B0003AE6D000036
+:108CD0008E500034A260000A8F9800B8AE70000475
+:108CE0003C0500809311003FA26B000C8E6F000CBE
+:108CF0003C0EFF9FA271000B01E5102535CCFFFF54
+:108D00003C03FFEF8F9200B8004C30243464FFFF27
+:108D100000C4F824AE7F000C8E590014964800124F
+:108D20008F8A00B0AE7900108E490014AE60001832
+:108D3000AE600020AE690014AE6000248E470018BB
+:108D400031093FFF0009F180AE6700288E4D000811
+:108D500003CA802131180001AE6D00308E4F000C27
+:108D60008F8C00AC001089C200185B80022B282178
+:108D7000240E0002A665001CA6600036AE6F002C13
+:108D8000A18E00009763003C8F8A00AC3C04420037
+:108D90003062FFFF00443025AD4600048F9F00B8CD
+:108DA000240700012411C0008FF30038240600348A
+:108DB000AD5300188FF90034AD59001CAD40000CC4
+:108DC000AD400010A5400014A5400016A5400020AD
+:108DD000A5400022AD400024A5550002A147000196
+:108DE0008F9E00AC8F8800B88F9200BCAFD5000872
+:108DF000910D0000A24D00008F9000B88F8B00BC39
+:108E000092180001A17800018F8400BC94850002B3
+:108E100000B1782401E97025A48E0002908C000234
+:108E20003183003FA08300028F8300D08F8400BC79
+:108E3000906200BC305300025260000124060030F2
+:108E4000AC8600048C6F007C2403FFBF02A0882145
+:108E5000AC8F0008908E000D31CC007FA08C000DEF
+:108E60008F8600BC90C2000D00432024A0C4000DDA
+:108E70008F8900BC913F000D37F90020A139000D0A
+:108E80008F8800B88F9300BC8D070020AE6700105C
+:108E90008D0A0024AE6A00148D1E0028AE7E0018D4
+:108EA0008D12002C0E000CF6AE72001C0A00103D54
+:108EB0008F9000D0960E00148E03000431CCFFFF7B
+:108EC000000C10C000622021AF44003C8E1F000443
+:108ED0008F46003C03E6C8231B20003C0000000036
+:108EE0008E0F000025E200013C05001034B500089B
+:108EF000AF420038AF550030000000000000000015
+:108F00000000000000000000000000000000000061
+:108F100000000000000000008F580000330B00200C
+:108F20001160FFFD000000008F5304003C0D002085
+:108F3000AE1300088F570404AE17000CAF4D00307D
+:108F4000000000003C0608008CC600442416000106
+:108F500010D600BD00000000961F00123C0508005E
+:108F60008CA5004000BFC821A61900129609001464
+:108F700025270001A6070014960A00143144FFFFBC
+:108F80005486FF498FB30010A60000140E000E1681
+:108F900030A5FFFF3C0408008C84002496030012D7
+:108FA0000044102300623023A60600120A00105964
+:108FB0008FB30010A08300018F8200AC2404000155
+:108FC000AC4400080A000FF08F8300D08E0200002E
+:108FD0000A0010EA3C0500108F8200C08FA7001C19
+:108FE000921800D0920B00D0920E00D0331100FFE7
+:108FF000316900FF00117940000928C001E56021B6
+:1090000031C300FF036C50210003314000C2C8216E
+:10901000255F0088AF9F00ACAF9900BCA1470088D6
+:109020009768003C03C020218F9100AC0E000CD645
+:109030003110FFFF00026B80020DC0253C0442008E
+:109040008F8D00B803045825AE2B00048DA900387D
+:109050008F8B00AC0000882100118100AD690018E1
+:109060008DAF00343C087FFF3504FFFFAD6F001C5F
+:1090700091AC003E8D65001C8D660018000C190037
+:10908000000C770200A33821020E102500E3F82B14
+:1090900000C2C821033F5021AD67001CAD6A001813
+:1090A000AD60000CAD60001091B8003E24050005D5
+:1090B00003C45024A578001495A9000403C02021FE
+:1090C000A569001691AF003EA56F002095B1000480
+:1090D000A5710022AD60002491AE003FA56E000294
+:1090E00091B0003E91AC003D01901023244300015B
+:1090F000A16300018F8600AC8F9F00BCACDE00082E
+:10910000A3E500008F9000BC8F9900B82405FFBF35
+:1091100096070002973800120247782433093FFF70
+:1091200001E98825A6110002921200022418FFDF2F
+:10913000324E003F35CD0040A20D00028F8600BCAC
+:109140008F8C00D02412FFFFACC000048D8B007CFC
+:109150003C0C8000ACCB000890C2000D3043007F77
+:10916000A0C3000D8F8700BC90FF000D03E5C8244D
+:10917000A0F9000D8F9100BC9229000D01387824D0
+:10918000A22F000D8F9000BCAE120010AE1500147F
+:10919000920E00182415FF8002AE6825A20D00185B
+:1091A0008F8500BC8F8300B88CAB0018016C102435
+:1091B000004A3025ACA600189068003EA0A8001C0C
+:1091C0008F9F00B88F8700BC8F9800D097F900045C
+:1091D000A4F9001E0E0002138F0500848F8600D0B4
+:1091E000000279400002490090D200BC01E98821C8
+:1091F000004028213255000212A0000303D1202193
+:109200000002A8800095202190CD00BC31B200045E
+:109210001240000333DF0003000540800088202156
+:10922000240600048F9E00BC00DFC8233327000300
+:1092300000875021AFCA00040E000CF6A665003866
+:109240000A0010388F9000D0961E00123C080800CB
+:109250008D080024011E9021A61200120A00105948
+:109260008FB3001027BDFFE03C1808008F18005096
+:10927000AFB00010AFBF0018AFB10014AF8400B0A2
+:1092800093710074030478212410FF8031EE007F75
+:109290003225007F01F0582401DA68213C0C000AD5
+:1092A000A38500C401AC2821AF4B002494A9001071
+:1092B0009768000690A600620080382124020030E2
+:1092C0000109202330C300F0AF8500D010620019DF
+:1092D0003090FFFF90AE0062240DFFF0240A005092
+:1092E00001AE6024318B00FF116A002F00000000E6
+:1092F00016000007241F0C00AF5F00248FB100147C
+:109300008FBF00188FB0001003E0000827BD0020B9
+:109310000E000E1C02002021241F0C00AF5F002451
+:109320008FB100148FBF00188FB0001003E0000849
+:1093300027BD002094A200E094A400E290BF011396
+:10934000008218263079FFFF33E700C014E00009DF
+:109350002F31000116000038000000005620FFE603
+:10936000241F0C000E000D18000000000A0011ED73
+:10937000241F0C001620FFDE000000000E000D1858
+:10938000000000001440FFDC241F0C001600002227
+:109390008F8300D0906901133122003FA062011336
+:1093A0000A0011ED241F0C0094AF00D48F8600D466
+:1093B00000E02821240400050E000C5C31F0FFFFC2
+:1093C0001440000524030003979100E600001821D3
+:1093D0002625FFFFA78500E68F5801B80700FFFE8E
+:1093E0003C196013AF400180241F0C00AF50018472
+:1093F000007938253C101000AF4701888FB1001468
+:10940000AF5001B8AF5F00248FB000108FBF0018BD
+:1094100003E0000827BD00200E000E1C02002021E2
+:109420005040FFB5241F0C008F8300D090690113BA
+:109430000A0012163122003F0E000E1C02002021ED
+:109440001440FFAD241F0C00122000078F8300D0B2
+:10945000906801133106003F34C20040A06201133E
+:109460000A0011ED241F0C000E000D180000000072
+:109470005040FFA1241F0C008F8300D0906801137F
+:109480003106003F0A00124634C20040AF9B00C8BC
+:1094900003E00008AF8000EC3089FFFF0009404284
+:1094A0002D020041000929801440000200095040AB
+:1094B00024080040000879400008C0C001F8582185
+:1094C000256701A800EF702125CC007F240DFF80C7
+:1094D000018D18240065302100CA282125640088E8
+:1094E000240A00883C010800AC2A004C3C0108001A
+:1094F000AC240050AF8500D43C010800AC290060CA
+:109500003C010800AC2800643C010800AC27005472
+:109510003C010800AC2300583C010800AC26005C6C
+:1095200003E0000800000000308300FF30C6FFFFAA
+:1095300030E400FF8F4201B80440FFFE00034C00FE
+:10954000012438253C08600000E820253C03100079
+:10955000AF450180AF460184AF44018803E00008B5
+:10956000AF4301B88F86001C3C09601235270010FC
+:109570008CCB00043C0C600E35850010316A00066F
+:109580002D480001ACE800C48CC40004ACA43180B8
+:109590008CC2000894C30002ACA2318403E000082E
+:1095A000A78300E43C0308008C6300508F8400E82C
+:1095B0008F86001C2402FF800064C0210302C8249F
+:1095C000AF5900288CCD00043305007F00BA782104
+:1095D0003C0E000C01EE2821ACAD00588CC80008F0
+:1095E000AF8500D03C076012ACA8005C8CCC0010AA
+:1095F00034E80010ACAC000C8CCB000CACAB000819
+:1096000094AA00143C0208008C4200442549000141
+:10961000A4A9001494A400143083FFFF1062001763
+:109620008F8400D03C0A08008D4A0040A4AA001292
+:109630008CCE0018AC8E00248CCD0014AC8D002094
+:109640008CC70018AC87002C8CCC001424060001B9
+:10965000AC8C00288D0B00BC5166001A8D0200B442
+:109660008D0200B8A482003A948F003AA48F003C87
+:10967000948800D403E000083102FFFF3C09080091
+:109680008D290024A4A000148F8400D0A4A9001266
+:109690008CCE0018AC8E00248CCD0014AC8D002034
+:1096A0008CC70018AC87002C8CCC00142406000159
+:1096B000AC8C00288D0B00BC5566FFEA8D0200B80B
+:1096C0008D0200B4A482003A948F003AA48F003C2B
+:1096D000948800D403E000083102FFFF8F86001C4D
+:1096E0003C0C08008D8C0050240BFF808CCD0008B2
+:1096F0003C03000C000D51C0018A4021010B48249D
+:10970000AF8A00E8AF49002890C700073105007F05
+:1097100000BA10210043282130E4000410800039F1
+:10972000AF8500D090CF000731EE000811C000389F
+:10973000000000008CD9000C8CC400140324C02B42
+:1097400013000030000000008CC2000CACA20064CA
+:109750008CCD00182402FFF8ACAD00688CCC001052
+:10976000ACAC00808CCB000CACAB00848CCA001C71
+:10977000ACAA007C90A900BC01224024A0A800BC97
+:1097800090C300073067000810E000048F8500D008
+:1097900090AF00BC35EE0001A0AE00BC90D9000730
+:1097A00033380001130000088F8300D08F8700D06A
+:1097B0002404003490E800BC35030002A0E300BCA0
+:1097C0008F8300D0AC6400C090C90007312600022E
+:1097D00010C0000500000000906A00BC3542000483
+:1097E000A06200BC8F8300D09065011330AD003FB4
+:1097F000A06D01138F8C00D0958B00D403E000087E
+:109800003162FFFF8CC200140A0013020000000046
+:109810000A001303ACA0006427BDFFD8AFB000104E
+:109820008F90001CAFBF0024AFB40020AFB200186F
+:10983000AFB10014AFB3001C9613000E3C07600AD2
+:109840003C1460063264FFFF369300100E00125580
+:1098500034F404108F8400D43C11600E0E00099B78
+:1098600036310010920E00153C0708008CE70060AE
+:109870003C12601231CD000FA38D00F08E0E00045B
+:109880008E0D000896080012961F00109619001AF7
+:109890009618001E960F001C310CFFFF33EBFFFFE4
+:1098A000332AFFFF3309FFFF31E6FFFF3C010800C9
+:1098B000AC2B00403C010800AC2C00243C0108000B
+:1098C000AC2A0044AE293178AE26317C92020015D4
+:1098D0009603001636520010304400FF3065FFFF3B
+:1098E0003C0608008CC60064AE243188AE4500B446
+:1098F0009208001496190018241F0001011FC004CB
+:10990000332FFFFF3C0508008CA50058AE5800B867
+:10991000AE4F00BC920C0014AF8E00D8AF8D00DCAF
+:10992000318B00FFAE4B00C0920A0015AE670048B5
+:10993000AE66004C314900FFAE4900C8AE65007C00
+:109940003C0308008C6300503C0408008C84004CED
+:109950003C0808008D0800543C0208008C42005C62
+:109960008FBF0024AE6300808FB00010AE83007400
+:109970008FB3001CAE22319CAE4200DCAE2731A07A
+:10998000AE2631A4AE24318CAE233190AE28319472
+:10999000AE253198AE870050AE860054AE8500707B
+:1099A0008FB10014AE4700E0AE4600E4AE4400CCF8
+:1099B000AE4300D0AE4800D4AE4500D88FB40020EE
+:1099C0008FB2001803E0000827BD002827BDFFE084
+:1099D000AFB10014AFBF0018241100010E000845FC
+:1099E000AFB0001010510005978400E6978300CCBB
+:1099F0000083102B144000088F8500D42407000238
+:109A00008FBF00188FB100148FB0001000E010213C
+:109A100003E0000827BD00200E000C7A2404000596
+:109A2000AF8200E81040FFF6240700020E0008494C
+:109A30008F90001C979F00E68F9900E88F8D00C8DB
+:109A400027EF0001240E0050AF590020A78F00E639
+:109A5000A1AE00003C0C08008D8C00648F8600C80D
+:109A6000240A8000000C5E00ACCB0074A4C0000689
+:109A700094C9000A241FFF803C0D000C012AC02459
+:109A8000A4D8000A90C8000A24182000011F182535
+:109A9000A0C3000A8F8700C8A0E000788F8500C8A7
+:109AA00000003821A0A000833C0208008C42005036
+:109AB0008F8400E80044782101FFC824AF590028B2
+:109AC000960B000231EE007F01DA6021018D30211A
+:109AD000A4CB00D4960A0002AF8600D03C0E00044E
+:109AE00025492401A4C900E68E080004ACC800047E
+:109AF0008E030008ACC30000A4C00010A4C0001472
+:109B0000A0C000D08F8500D02403FFBFA0A000D14B
+:109B10003C0408008C8400648F8200D0A04400D2F2
+:109B20008E1F000C8F8A00D0978F00E4AD5F001C61
+:109B30008E19001024100030AD590018A5400030D7
+:109B4000A5510054A5510056A54F0016AD4E006812
+:109B5000AD580080AD580084914D006231AC000FCB
+:109B6000358B0010A14B00628F8600D090C9006336
+:109B70003128007FA0C800638F8400D02406FFFF37
+:109B80009085006300A31024A08200638F9100D011
+:109B900000E01021923F00BC37F90001A23900BC5F
+:109BA0008F8A00D0938F00F0AD580064AD5000C094
+:109BB000914E00D3000F690031CC000F018D582564
+:109BC000A14B00D38F8500D08F8900DCACA900E8C1
+:109BD0008F8800D88FBF00188FB100148FB000108D
+:109BE00027BD0020ACA800ECA4A600D6A4A000E0ED
+:109BF000A4A000E203E000080000000027BDFFE091
+:109C0000AFB000108F90001CAFB10014AFBF0018B0
+:109C10008E1900043C1808008F180050240FFF8094
+:109C2000001989C00238702131CD007F01CF602436
+:109C300001BA50213C0B000CAF4C0028014B4021D5
+:109C4000950900D4950400D68E0700043131FFFF3A
+:109C5000AF8800D00E000913000721C08E06000453
+:109C60008F8300C8000629C0AF4500209064003EE5
+:109C700030820040144000068F8400D0341FFFFF64
+:109C8000948300D63062FFFF145F000400000000E0
+:109C9000948400D60E0008A83084FFFF8E050004CF
+:109CA000022030218FBF00188FB100148FB0001038
+:109CB0002404002200003821000529C00A0012797E
+:109CC00027BD002027BDFFE0AFB100143091FFFF9A
+:109CD000AFB00010AFBF00181220001D000080219F
+:109CE0008F86001C8CC500002403000600053F027F
+:109CF0000005140230E4000714830015304500FF0E
+:109D00002CA800061100004D000558803C0C0800EE
+:109D1000258C57C8016C50218D4900000120000896
+:109D2000000000008F8E00EC240D000111CD0059C1
+:109D300000000000260B00013170FFFF24CA002044
+:109D40000211202B014030211480FFE6AF8A001C55
+:109D5000020010218FBF00188FB100148FB00010C7
+:109D600003E0000827BD0020938700CE14E00038F0
+:109D7000240400140E001335000000008F86001C20
+:109D8000240200010A00147CAF8200EC8F8900ECF1
+:109D9000240800021128003B24040013000028219D
+:109DA00000003021240700010E001279000000009D
+:109DB0000A00147C8F86001C8F8700EC24050002AB
+:109DC00014E5FFF6240400120E0012E60000000065
+:109DD0008F8500E800403021240400120E00127923
+:109DE000000038210A00147C8F86001C8F8300EC51
+:109DF000241F0003147FFFD0260B00010E001298D1
+:109E0000000000008F8500E800403021240200029D
+:109E10002404001000003821AF8200EC0E001279FB
+:109E2000000000000A00147C8F86001C8F8F00EC5D
+:109E30002406000211E6000B0000000024040010BC
+:109E400000002821000030210A0014992407000195
+:109E5000000028210E001279000030210A00147C35
+:109E60008F86001C0E0013A2000000001440001298
+:109E70008F99001C8F86001C240200030A00147CAA
+:109E8000AF8200EC0E00142E000000000A00147CCB
+:109E90008F86001C0E0012880000000024020002C1
+:109EA0002404001400002821000030210000382183
+:109EB0000A0014B6AF8200EC0040382124040010E0
+:109EC00097380002000028210E0012793306FFFFA8
+:109ED0000A00147C8F86001C8F8400C83C077FFF1B
+:109EE00034E6FFFF8C8500742402000100A61824CC
+:109EF000AC83007403E00008A082000510A00036C7
+:109F00002CA20080274A04003C0B00052409008095
+:109F1000104000072408008030A6000F00C5402133
+:109F20002D0300811460000200A048212408008055
+:109F3000AF4B0030000000000000000000000000F7
+:109F40001100000900003821014030218C8D0000F3
+:109F500024E7000400E8602BACCD0000248400045A
+:109F60001580FFFA24C60004000000000000000075
+:109F7000000000003C0E0006010E3825AF470030FF
+:109F80000000000000000000000000008F4F0000F3
+:109F900031E800101100FFFD000000008F42003C7E
+:109FA0008F43003C0049C8210323C02B1300000449
+:109FB000000000008F4C003825860001AF460038B5
+:109FC0008F47003C00A9282300E96821AF4D003CE1
+:109FD00014A0FFCE2CA2008003E0000800000000C7
+:109FE00027BDFFD03C020002AFB100143C11000CB1
+:109FF000AF450038AFB3001CAF46003C008098214D
+:10A00000AF42003024050088AF44002803512021CE
+:10A01000AFBF0028AFB50024AFB40020AFB2001826
+:10A020000E0014EEAFB000103C1F08008FFF004C74
+:10A030003C1808008F1800642410FF8003F3A82147
+:10A0400032B9007F02B078240018A0C0033A702112
+:10A050000018914001D12021AF4F00280E0014EECE
+:10A06000025428213C0D08008DAD0050240501202C
+:10A0700001B35821316C007F01705024019A4821AE
+:10A08000013120210E0014EEAF4A00283C080800E0
+:10A090008D0800543C0508008CA50064011338218C
+:10A0A00030E6007F00F0182400DA20210091202102
+:10A0B000AF4300280E0014EE000529403C020800C2
+:10A0C0008C4200583C1008008E1000601200001CEA
+:10A0D000005388212415FF800A0015713C14000CE0
+:10A0E0003226007F0235182400DA20210240282180
+:10A0F000AF430028009420210E0014EE2610FFC06C
+:10A100001200000F023288212E05004110A0FFF43A
+:10A11000241210003226007F00109180023518248E
+:10A1200000DA202102402821AF430028009420219A
+:10A130000E0014EE000080211600FFF30232882189
+:10A140003C0B08008D6B005C240AFF802405000294
+:10A1500001734021010A4824AF4900283C0408004B
+:10A16000948400623110007F021A88213C07000CA1
+:10A170000E000CAA0227982100402821026020210D
+:10A180008FBF00288FB500248FB400208FB3001C30
+:10A190008FB200188FB100148FB000100A0014EEB7
+:10A1A00027BD00308F83001C8C6200041040000328
+:10A1B0000000000003E00008000000008C640010B4
+:0CA1C0008C6500080A0015278C66000C56
+:04A1CC00000000008F
+:10A1D0000000001B0000000F0000000A0000000843
+:10A1E000000000060000000500000005000000045B
+:10A1F0000000000400000003000000030000000352
+:10A200000000000300000003000000020000000244
+:10A210000000000200000002000000020000000236
+:10A220000000000200000002000000020000000226
+:10A230000000000200000002000000020000000216
+:10A240000000000200000001000000010000000109
+:10A2500008000F2408000D6C08000FB808001060FB
+:10A2600008000F4C08000F8C0800119408000D889E
+:10A27000080011B808000DD8080015540800151C76
+:10A2800008000D8808000D8808000D88080012409D
+:10A290000800124008000D8808000D88080014E02E
+:10A2A00008000D8808000D8808000D8808000D883A
+:10A2B000080013B408000D8808000D8808000D88F8
+:10A2C00008000D8808000D8808000D8808000D881A
+:10A2D00008000D8808000D8808000D8808000D880A
+:10A2E00008000D8808000D8808000D8808000FACD4
+:10A2F00008000D8808000D880800167808000D88F1
+:10A3000008000D8808000D8808000D8808000D88D9
+:10A3100008000D8808000D8808000D8808000D88C9
+:10A3200008000D8808000D8808000D8808000D88B9
+:10A3300008000D8808000D8808000D8808000D88A9
+:10A340000800141008000D8808000D880800133458
+:10A35000080012A408001E2C08001EFC08001F1490
+:10A3600008001F2808001F3808001E2C08001E2C9B
+:10A3700008001E2C08001ED808002E1408002E1CF1
+:10A3800008002DE408002DF008002DFC08002E0820
+:10A39000080052E8080052A8080052740800524809
+:08A3A00008005224080051E0FE
+:08A3A8000A000C840000000013
+:10A3B000000000000000000D727870362E302E3143
+:10A3C0003500000006000F0300000000000000013F
+:10A3D000000000000000000000000000000000007D
+:10A3E000000000000000000000000000000000006D
+:10A3F000000000000000000000000000000000005D
+:10A40000000000000000000000000000000000004C
+:10A41000000000000000000000000000000000003C
+:10A42000000000000000000000000000000000002C
+:10A43000000000000000000000000000000000001C
+:10A44000000000000000000000000000000000000C
+:10A4500000000000000000000000000000000000FC
+:10A4600000000000000000000000000000000000EC
+:10A4700000000000000000000000000000000000DC
+:10A4800000000000000000000000000000000000CC
+:10A4900000000000000000000000000000000000BC
+:10A4A00000000000000000000000000000000000AC
+:10A4B000000000000000000000000000000000009C
+:10A4C000000000000000000000000000000000008C
+:10A4D000000000000000000000000000000000007C
+:10A4E000000000000000000000000000000000006C
+:10A4F000000000000000000000000000000000005C
+:10A50000000000000000000000000000000000004B
+:10A51000000000000000000000000000000000003B
+:10A52000000000000000000000000000000000002B
+:10A53000000000000000000000000000000000001B
+:10A54000000000000000000000000000000000000B
+:10A5500000000000000000000000000000000000FB
+:10A5600000000000000000000000000000000000EB
+:10A5700000000000000000000000000000000000DB
+:10A5800000000000000000000000000000000000CB
+:10A5900000000000000000000000000000000000BB
+:10A5A00000000000000000000000000000000000AB
+:10A5B000000000000000000000000000000000009B
+:10A5C000000000000000000000000000000000008B
+:10A5D000000000000000000000000000000000007B
+:10A5E000000000000000000000000000000000006B
+:10A5F000000000000000000000000000000000005B
+:10A60000000000000000000000000000000000004A
+:10A61000000000000000000000000000000000003A
+:10A62000000000000000000000000000000000002A
+:10A63000000000000000000000000000000000001A
+:10A64000000000000000000000000000000000000A
+:10A6500000000000000000000000000000000000FA
+:10A6600000000000000000000000000000000000EA
+:10A6700000000000000000000000000000000000DA
+:10A6800000000000000000000000000000000000CA
+:10A6900000000000000000000000000000000000BA
+:10A6A00000000000000000000000000000000000AA
+:10A6B000000000000000000000000000000000009A
+:10A6C000000000000000000000000000000000008A
+:10A6D000000000000000000000000000000000007A
+:10A6E000000000000000000000000000000000006A
+:10A6F000000000000000000000000000000000005A
+:10A700000000000000000000000000000000000049
+:10A710000000000000000000000000000000000039
+:10A720000000000000000000000000000000000029
+:10A730000000000000000000000000000000000019
+:10A740000000000000000000000000000000000009
+:10A7500000000000000000000000000000000000F9
+:10A7600000000000000000000000000000000000E9
+:10A7700000000000000000000000000000000000D9
+:10A7800000000000000000000000000000000000C9
+:10A7900000000000000000000000000000000000B9
+:10A7A00000000000000000000000000000000000A9
+:10A7B0000000000000000000000000000000000099
+:10A7C0000000000000000000000000000000000089
+:10A7D0000000000000000000000000000000000079
+:10A7E0000000000000000000000000000000000069
+:10A7F0000000000000000000000000000000000059
+:10A800000000000000000000000000000000000048
+:10A810000000000000000000000000000000000038
+:10A820000000000000000000000000000000000028
+:10A830000000000000000000000000000000000018
+:10A840000000000000000000000000000000000008
+:10A8500000000000000000000000000000000000F8
+:10A8600000000000000000000000000000000000E8
+:10A8700000000000000000000000000000000000D8
+:10A8800000000000000000000000000000000000C8
+:10A8900000000000000000000000000000000000B8
+:10A8A00000000000000000000000000000000000A8
+:10A8B0000000000000000000000000000000000098
+:10A8C0000000000000000000000000000000000088
+:10A8D0000000000000000000000000000000000078
+:10A8E0000000000000000000000000000000000068
+:10A8F0000000000000000000000000000000000058
+:10A900000000000000000000000000000000000047
+:10A910000000000000000000000000000000000037
+:10A920000000000000000000000000000000000027
+:10A930000000000000000000000000000000000017
+:10A940000000000000000000000000000000000007
+:10A9500000000000000000000000000000000000F7
+:10A9600000000000000000000000000000000000E7
+:10A9700000000000000000000000000000000000D7
+:10A9800000000000000000000000000000000000C7
+:10A9900000000000000000000000000000000000B7
+:10A9A00000000000000000000000000000000000A7
+:10A9B0000000000000000000000000000000000097
+:10A9C0000000000000000000000000000000000087
+:10A9D0000000000000000000000000000000000077
+:10A9E0000000000000000000000000000000000067
+:10A9F0000000000000000000000000000000000057
+:10AA00000000000000000000000000000000000046
+:10AA10000000000000000000000000000000000036
+:10AA20000000000000000000000000000000000026
+:10AA30000000000000000000000000000000000016
+:10AA40000000000000000000000000000000000006
+:10AA500000000000000000000000000000000000F6
+:10AA600000000000000000000000000000000000E6
+:10AA700000000000000000000000000000000000D6
+:10AA800000000000000000000000000000000000C6
+:10AA900000000000000000000000000000000000B6
+:10AAA00000000000000000000000000000000000A6
+:10AAB0000000000000000000000000000000000096
+:10AAC0000000000000000000000000000000000086
+:10AAD0000000000000000000000000000000000076
+:10AAE0000000000000000000000000000000000066
+:10AAF0000000000000000000000000000000000056
+:10AB00000000000000000000000000000000000045
+:10AB10000000000000000000000000000000000035
+:10AB20000000000000000000000000000000000025
+:10AB30000000000000000000000000000000000015
+:10AB40000000000000000000000000000000000005
+:10AB500000000000000000000000000000000000F5
+:10AB600000000000000000000000000000000000E5
+:10AB700000000000000000000000000000000000D5
+:10AB800000000000000000000000000000000000C5
+:10AB900000000000000000000000000000000000B5
+:10ABA00000000000000000000000000000000000A5
+:10ABB0000000000000000000000000000000000095
+:10ABC0000000000000000000000000000000000085
+:10ABD0000000000000000000000000000000000075
+:10ABE0000000000000000000000000000000000065
+:10ABF0000000000000000000000000000000000055
+:10AC00000000000000000000000000000000000044
+:10AC10000000000000000000000000000000000034
+:10AC20000000000000000000000000000000000024
+:10AC30000000000000000000000000000000000014
+:10AC40000000000000000000000000000000000004
+:10AC500000000000000000000000000000000000F4
+:10AC600000000000000000000000000000000000E4
+:10AC700000000000000000000000000000000000D4
+:10AC800000000000000000000000000000000000C4
+:10AC900000000000000000000000000000000000B4
+:10ACA00000000000000000000000000000000000A4
+:10ACB0000000000000000000000000000000000094
+:10ACC0000000000000000000000000000000000084
+:10ACD0000000000000000000000000000000000074
+:10ACE0000000000000000000000000000000000064
+:10ACF0000000000000000000000000000000000054
+:10AD00000000000000000000000000000000000043
+:10AD10000000000000000000000000000000000033
+:10AD20000000000000000000000000000000000023
+:10AD30000000000000000000000000000000000013
+:10AD40000000000000000000000000000000000003
+:10AD500000000000000000000000000000000000F3
+:10AD600000000000000000000000000000000000E3
+:10AD700000000000000000000000000000000000D3
+:10AD800000000000000000000000000000000000C3
+:10AD900000000000000000000000000000000000B3
+:10ADA00000000000000000000000000000000000A3
+:10ADB0000000000000000000000000000000000093
+:10ADC0000000000000000000000000000000000083
+:10ADD0000000000000000000000000000000000073
+:10ADE0000000000000000000000000000000000063
+:10ADF0000000000000000000000000000000000053
+:10AE00000000000000000000000000000000000042
+:10AE10000000000000000000000000000000000032
+:10AE20000000000000000000000000000000000022
+:10AE30000000000000000000000000000000000012
+:10AE40000000000000000000000000000000000002
+:10AE500000000000000000000000000000000000F2
+:10AE600000000000000000000000000000000000E2
+:10AE700000000000000000000000000000000000D2
+:10AE800000000000000000000000000000000000C2
+:10AE900000000000000000000000000000000000B2
+:10AEA00000000000000000000000000000000000A2
+:10AEB0000000000000000000000000000000000092
+:10AEC0000000000000000000000000000000000082
+:10AED0000000000000000000000000000000000072
+:10AEE0000000000000000000000000000000000062
+:10AEF0000000000000000000000000000000000052
+:10AF00000000000000000000000000000000000041
+:10AF10000000000000000000000000000000000031
+:10AF20000000000000000000000000000000000021
+:10AF30000000000000000000000000000000000011
+:10AF40000000000000000000000000000000000001
+:10AF500000000000000000000000000000000000F1
+:10AF600000000000000000000000000000000000E1
+:10AF700000000000000000000000000000000000D1
+:10AF800000000000000000000000000000000000C1
+:10AF900000000000000000000000000000000000B1
+:10AFA00000000000000000000000000000000000A1
+:10AFB0000000000000000000000000000000000091
+:10AFC0000000000000000000000000000000000081
+:10AFD0000000000000000000000000000000000071
+:10AFE0000000000000000000000000000000000061
+:10AFF0000000000000000000000000000000000051
+:10B000000000000000000000000000000000000040
+:10B010000000000000000000000000000000000030
+:10B020000000000000000000000000000000000020
+:10B030000000000000000000000000000000000010
+:10B040000000000000000000000000000000000000
+:10B0500000000000000000000000000000000000F0
+:10B0600000000000000000000000000000000000E0
+:10B0700000000000000000000000000000000000D0
+:10B0800000000000000000000000000000000000C0
+:10B0900000000000000000000000000000000000B0
+:10B0A00000000000000000000000000000000000A0
+:10B0B0000000000000000000000000000000000090
+:10B0C0000000000000000000000000000000000080
+:10B0D0000000000000000000000000000000000070
+:10B0E0000000000000000000000000000000000060
+:10B0F0000000000000000000000000000000000050
+:10B10000000000000000000000000000000000003F
+:10B11000000000000000000000000000000000002F
+:10B12000000000000000000000000000000000001F
+:10B13000000000000000000000000000000000000F
+:10B1400000000000000000000000000000000000FF
+:10B1500000000000000000000000000000000000EF
+:10B1600000000000000000000000000000000000DF
+:10B1700000000000000000000000000000000000CF
+:10B1800000000000000000000000000000000000BF
+:10B1900000000000000000000000000000000000AF
+:10B1A000000000000000000000000000000000009F
+:10B1B000000000000000000000000000000000008F
+:10B1C000000000000000000000000000000000007F
+:10B1D000000000000000000000000000000000006F
+:10B1E000000000000000000000000000000000005F
+:10B1F000000000000000000000000000000000004F
+:10B20000000000000000000000000000000000003E
+:10B21000000000000000000000000000000000002E
+:10B22000000000000000000000000000000000001E
+:10B23000000000000000000000000000000000000E
+:10B2400000000000000000000000000000000000FE
+:10B2500000000000000000000000000000000000EE
+:10B2600000000000000000000000000000000000DE
+:10B2700000000000000000000000000000000000CE
+:10B2800000000000000000000000000000000000BE
+:10B2900000000000000000000000000000000000AE
+:10B2A000000000000000000000000000000000009E
+:10B2B000000000000000000000000000000000008E
+:10B2C000000000000000000000000000000000007E
+:10B2D000000000000000000000000000000000006E
+:10B2E000000000000000000000000000000000005E
+:10B2F000000000000000000000000000000000004E
+:10B30000000000000000000000000000000000003D
+:10B31000000000000000000000000000000000002D
+:10B32000000000000000000000000000000000001D
+:10B33000000000000000000000000000000000000D
+:10B3400000000000000000000000000000000000FD
+:10B3500000000000000000000000000000000000ED
+:10B3600000000000000000000000000000000000DD
+:10B3700000000000000000000000000000000000CD
+:10B3800000000000000000000000000000000000BD
+:10B3900000000000000000000000000000000000AD
+:10B3A000000000000000000000000000000000009D
+:10B3B000000000000000000000000000000000008D
+:10B3C000000000000000000000000000000000007D
+:10B3D000000000000000000000000000000000006D
+:10B3E000000000000000000000000000000000005D
+:10B3F000000000000000000000000000000000004D
+:10B40000000000000000000000000000000000003C
+:10B41000000000000000000000000000000000002C
+:10B42000000000000000000000000000000000001C
+:10B43000000000000000000000000000000000000C
+:10B4400000000000000000000000000000000000FC
+:10B4500000000000000000000000000000000000EC
+:10B4600000000000000000000000000000000000DC
+:10B4700000000000000000000000000000000000CC
+:10B4800000000000000000000000000000000000BC
+:10B4900000000000000000000000000000000000AC
+:10B4A000000000000000000000000000000000009C
+:10B4B000000000000000000000000000000000008C
+:10B4C000000000000000000000000000000000007C
+:10B4D000000000000000000000000000000000006C
+:10B4E000000000000000000000000000000000005C
+:10B4F000000000000000000000000000000000004C
+:10B50000000000000000000000000000000000003B
+:10B51000000000000000000000000000000000002B
+:10B52000000000000000000000000000000000001B
+:10B53000000000000000000000000000000000000B
+:10B5400000000000000000000000000000000000FB
+:10B5500000000000000000000000000000000000EB
+:10B5600000000000000000000000000000000000DB
+:10B5700000000000000000000000000000000000CB
+:10B5800000000000000000000000000000000000BB
+:10B5900000000000000000000000000000000000AB
+:10B5A000000000000000000000000000000000009B
+:10B5B000000000000000000000000000000000008B
+:10B5C000000000000000000000000000000000007B
+:10B5D000000000000000000000000000000000006B
+:10B5E000000000000000000000000000000000005B
+:10B5F000000000000000000000000000000000004B
+:10B60000000000000000000000000000000000003A
+:10B61000000000000000000000000000000000002A
+:10B62000000000000000000000000000000000001A
+:10B63000000000000000000000000000000000000A
+:10B6400000000000000000000000000000000000FA
+:10B6500000000000000000000000000000000000EA
+:10B6600000000000000000000000000000000000DA
+:10B6700000000000000000000000000000000000CA
+:10B6800000000000000000000000000000000000BA
+:10B6900000000000000000000000000000000000AA
+:10B6A000000000000000000000000000000000009A
+:10B6B000000000000000000000000000000000008A
+:10B6C000000000000000000000000000000000007A
+:10B6D000000000000000000000000000000000006A
+:10B6E000000000000000000000000000000000005A
+:10B6F000000000000000000000000000000000004A
+:10B700000000000000000000000000000000000039
+:10B710000000000000000000000000000000000029
+:10B720000000000000000000000000000000000019
+:10B730000000000000000000000000000000000009
+:10B7400000000000000000000000000000000000F9
+:10B7500000000000000000000000000000000000E9
+:10B7600000000000000000000000000000000000D9
+:10B7700000000000000000000000000000000000C9
+:10B7800000000000000000000000000000000000B9
+:10B7900000000000000000000000000000000000A9
+:10B7A0000000000000000000000000000000000099
+:10B7B0000000000000000000000000000000000089
+:10B7C0000000000000000000000000000000000079
+:10B7D0000000000000000000000000000000000069
+:10B7E0000000000000000000000000000000000059
+:10B7F0000000000000000000000000000000000049
+:10B800000000000000000000000000000000000038
+:10B810000000000000000000000000000000000028
+:10B820000000000000000000000000000000000018
+:10B830000000000000000000000000000000000008
+:10B8400000000000000000000000000000000000F8
+:10B8500000000000000000000000000000000000E8
+:10B8600000000000000000000000000000000000D8
+:10B8700000000000000000000000000000000000C8
+:10B8800000000000000000000000000000000000B8
+:10B8900000000000000000000000000000000000A8
+:10B8A0000000000000000000000000000000000098
+:10B8B0000000000000000000000000000000000088
+:10B8C0000000000000000000000000000000000078
+:10B8D0000000000000000000000000000000000068
+:10B8E0000000000000000000000000000000000058
+:10B8F0000000000000000000000000000000000048
+:10B900000000000000000000000000000000000037
+:10B910000000000000000000000000000000000027
+:10B920000000000000000000000000000000000017
+:10B930000000000000000000000000000000000007
+:10B9400000000000000000000000000000000000F7
+:10B9500000000000000000000000000000000000E7
+:10B9600000000000000000000000000000000000D7
+:10B9700000000000000000000000000000000000C7
+:10B9800000000000000000000000000000000000B7
+:10B9900000000000000000000000000000000000A7
+:10B9A0000000000000000000000000000000000097
+:10B9B0000000000000000000000000000000000087
+:10B9C0000000000000000000000000000000000077
+:10B9D0000000000000000000000000000000000067
+:10B9E0000000000000000000000000000000000057
+:10B9F0000000000000000000000000000000000047
+:10BA00000000000000000000000000000000000036
+:10BA10000000000000000000000000000000000026
+:10BA20000000000000000000000000000000000016
+:10BA30000000000000000000000000000000000006
+:10BA400000000000000000000000000000000000F6
+:10BA500000000000000000000000000000000000E6
+:10BA600000000000000000000000000000000000D6
+:10BA700000000000000000000000000000000000C6
+:10BA800000000000000000000000000000000000B6
+:10BA900000000000000000000000000000000000A6
+:10BAA0000000000000000000000000000000000096
+:10BAB0000000000000000000000000000000000086
+:10BAC0000000000000000000000000000000000076
+:10BAD0000000000000000000000000000000000066
+:10BAE0000000000000000000000000000000000056
+:10BAF0000000000000000000000000000000000046
+:10BB00000000000000000000000000000000000035
+:10BB10000000000000000000000000000000000025
+:10BB20000000000000000000000000000000000015
+:10BB30000000000000000000000000000000000005
+:10BB400000000000000000000000000000000000F5
+:10BB500000000000000000000000000000000000E5
+:10BB600000000000000000000000000000000000D5
+:10BB700000000000000000000000000000000000C5
+:10BB800000000000000000000000000000000000B5
+:10BB900000000000000000000000000000000000A5
+:10BBA0000000000000000000000000000000000095
+:10BBB0000000000000000000000000000000000085
+:10BBC0000000000000000000000000000000000075
+:10BBD0000000000000000000000000000000000065
+:10BBE0000000000000000000000000000000000055
+:10BBF0000000000000000000000000000000000045
+:10BC00000000000000000000000000000000000034
+:10BC10000000000000000000000000000000000024
+:10BC20000000000000000000000000000000000014
+:10BC30000000000000000000000000000000000004
+:10BC400000000000000000000000000000000000F4
+:10BC500000000000000000000000000000000000E4
+:10BC600000000000000000000000000000000000D4
+:10BC700000000000000000000000000000000000C4
+:10BC800000000000000000000000000000000000B4
+:10BC900000000000000000000000000000000000A4
+:10BCA0000000000000000000000000000000000094
+:10BCB0000000000000000000000000000000000084
+:10BCC0000000000000000000000000000000000074
+:10BCD0000000000000000000000000000000000064
+:10BCE0000000000000000000000000000000000054
+:10BCF0000000000000000000000000000000000044
+:10BD00000000000000000000000000000000000033
+:10BD10000000000000000000000000000000000023
+:10BD20000000000000000000000000000000000013
+:10BD30000000000000000000000000000000000003
+:10BD400000000000000000000000000000000000F3
+:10BD500000000000000000000000000000000000E3
+:10BD600000000000000000000000000000000000D3
+:10BD700000000000000000000000000000000000C3
+:10BD800000000000000000000000000000000000B3
+:10BD900000000000000000000000000000000000A3
+:10BDA0000000000000000000000000000000000093
+:10BDB0000000000000000000000000000000000083
+:10BDC0000000000000000000000000000000000073
+:10BDD0000000000000000000000000000000000063
+:10BDE0000000000000000000000000000000000053
+:10BDF0000000000000000000000000000000000043
+:10BE00000000000000000000000000000000000032
+:10BE10000000000000000000000000000000000022
+:10BE20000000000000000000000000000000000012
+:10BE30000000000000000000000000000000000002
+:10BE400000000000000000000000000000000000F2
+:10BE500000000000000000000000000000000000E2
+:10BE600000000000000000000000000000000000D2
+:10BE700000000000000000000000000000000000C2
+:10BE800000000000000000000000000000000000B2
+:10BE900000000000000000000000000000000000A2
+:10BEA0000000000000000000000000000000000092
+:10BEB0000000000000000000000000000000000082
+:10BEC0000000000000000000000000000000000072
+:10BED0000000000000000000000000000000000062
+:10BEE0000000000000000000000000000000000052
+:10BEF0000000000000000000000000000000000042
+:10BF00000000000000000000000000000000000031
+:10BF10000000000000000000000000000000000021
+:10BF20000000000000000000000000000000000011
+:10BF30000000000000000000000000000000000001
+:10BF400000000000000000000000000000000000F1
+:10BF500000000000000000000000000000000000E1
+:10BF600000000000000000000000000000000000D1
+:10BF700000000000000000000000000000000000C1
+:10BF800000000000000000000000000000000000B1
+:10BF900000000000000000000000000000000000A1
+:10BFA0000000000000000000000000000000000091
+:10BFB0000000000000000000000000000000000081
+:10BFC0000000000000000000000000000000000071
+:10BFD0000000000000000000000000000000000061
+:10BFE0000000000000000000000000000000000051
+:10BFF0000000000000000000000000000000000041
+:10C000000000000000000000000000000000000030
+:10C010000000000000000000000000000000000020
+:10C020000000000000000000000000000000000010
+:10C030000000000000000000000000000000000000
+:10C0400000000000000000000000000000000000F0
+:10C0500000000000000000000000000000000000E0
+:10C0600000000000000000000000000000000000D0
+:10C0700000000000000000000000000000000000C0
+:10C0800000000000000000000000000000000000B0
+:10C0900000000000000000000000000000000000A0
+:10C0A0000000000000000000000000000000000090
+:10C0B0000000000000000000000000000000000080
+:10C0C0000000000000000000000000000000000070
+:10C0D0000000000000000000000000000000000060
+:10C0E0000000000000000000000000000000000050
+:10C0F0000000000000000000000000000000000040
+:10C10000000000000000000000000000000000002F
+:10C11000000000000000000000000000000000001F
+:10C12000000000000000000000000000000000000F
+:10C1300000000000000000000000000000000000FF
+:10C1400000000000000000000000000000000000EF
+:10C1500000000000000000000000000000000000DF
+:10C1600000000000000000000000000000000000CF
+:10C1700000000000000000000000000000000000BF
+:10C1800000000000000000000000000000000000AF
+:10C19000000000000000000000000000000000009F
+:10C1A000000000000000000000000000000000008F
+:10C1B000000000000000000000000000000000007F
+:10C1C000000000000000000000000000000000006F
+:10C1D000000000000000000000000000000000005F
+:10C1E000000000000000000000000000000000004F
+:10C1F000000000000000000000000000000000003F
+:10C20000000000000000000000000000000000002E
+:10C21000000000000000000000000000000000001E
+:10C22000000000000000000000000000000000000E
+:10C2300000000000000000000000000000000000FE
+:10C2400000000000000000000000000000000000EE
+:10C2500000000000000000000000000000000000DE
+:10C2600000000000000000000000000000000000CE
+:10C2700000000000000000000000000000000000BE
+:10C2800000000000000000000000000000000000AE
+:10C29000000000000000000000000000000000009E
+:10C2A000000000000000000000000000000000008E
+:10C2B000000000000000000000000000000000007E
+:10C2C000000000000000000000000000000000006E
+:10C2D000000000000000000000000000000000005E
+:10C2E000000000000000000000000000000000004E
+:10C2F000000000000000000000000000000000003E
+:10C30000000000000000000000000000000000002D
+:10C31000000000000000000000000000000000001D
+:10C32000000000000000000000000000000000000D
+:10C3300000000000000000000000000000000000FD
+:10C3400000000000000000000000000000000000ED
+:10C3500000000000000000000000000000000000DD
+:10C3600000000000000000000000000000000000CD
+:10C3700000000000000000000000000000000000BD
+:10C3800000000000000000000000000000000000AD
+:10C39000000000000000000000000000000000009D
+:10C3A000000000000000000000000000000000008D
+:10C3B000000000000000000000000000000000007D
+:10C3C000000000000000000000000000000000006D
+:10C3D000000000000000000000000000000000005D
+:10C3E000000000000000000000000000000000004D
+:10C3F000000000000000000000000000000000003D
+:10C40000000000000000000000000000000000002C
+:10C41000000000000000000000000000000000001C
+:10C42000000000000000000000000000000000000C
+:10C4300000000000000000000000000000000000FC
+:10C4400000000000000000000000000000000000EC
+:10C4500000000000000000000000000000000000DC
+:10C4600000000000000000000000000000000000CC
+:10C4700000000000000000000000000000000000BC
+:10C4800000000000000000000000000000000000AC
+:10C49000000000000000000000000000000000009C
+:10C4A000000000000000000000000000000000008C
+:10C4B000000000000000000000000000000000007C
+:10C4C000000000000000000000000000000000006C
+:10C4D000000000000000000000000000000000005C
+:10C4E000000000000000000000000000000000004C
+:10C4F000000000000000000000000000000000003C
+:10C50000000000000000000000000000000000002B
+:10C51000000000000000000000000000000000001B
+:10C52000000000000000000000000000000000000B
+:10C5300000000000000000000000000000000000FB
+:10C5400000000000000000000000000000000000EB
+:10C5500000000000000000000000000000000000DB
+:10C5600000000000000000000000000000000000CB
+:10C5700000000000000000000000000000000000BB
+:10C5800000000000000000000000000000000000AB
+:10C59000000000000000000000000000000000009B
+:10C5A000000000000000000000000000000000008B
+:10C5B000000000000000000000000000000000007B
+:10C5C000000000000000000000000000000000006B
+:10C5D000000000000000000000000000000000005B
+:10C5E000000000000000000000000000000000004B
+:10C5F000000000000000000000000000000000003B
+:10C60000000000000000000000000000000000002A
+:10C61000000000000000000000000000000000001A
+:10C62000000000000000000000000000000000000A
+:10C6300000000000000000000000000000000000FA
+:10C6400000000000000000000000000000000000EA
+:10C6500000000000000000000000000000000000DA
+:10C6600000000000000000000000000000000000CA
+:10C6700000000000000000000000000000000000BA
+:10C6800000000000000000000000000000000000AA
+:10C69000000000000000000000000000000000009A
+:10C6A000000000000000000000000000000000008A
+:10C6B000000000000000000000000000000000007A
+:10C6C000000000000000000000000000000000006A
+:10C6D000000000000000000000000000000000005A
+:10C6E000000000000000000000000000000000004A
+:10C6F000000000000000000000000000000000003A
+:10C700000000000000000000000000000000000029
+:10C710000000000000000000000000000000000019
+:10C720000000000000000000000000000000000009
+:10C7300000000000000000000000000000000000F9
+:10C7400000000000000000000000000000000000E9
+:10C7500000000000000000000000000000000000D9
+:10C7600000000000000000000000000000000000C9
+:10C7700000000000000000000000000000000000B9
+:10C7800000000000000000000000000000000000A9
+:10C790000000000000000000000000000000000099
+:10C7A0000000000000000000000000000000000089
+:10C7B0000000000000000000000000000000000079
+:10C7C0000000000000000000000000000000000069
+:10C7D0000000000000000000000000000000000059
+:10C7E0000000000000000000000000000000000049
+:10C7F0000000000000000000000000000000000039
+:10C800000000000000000000000000000000000028
+:10C810000000000000000000000000000000000018
+:10C820000000000000000000000000000000000008
+:10C8300000000000000000000000000000000000F8
+:10C8400000000000000000000000000000000000E8
+:10C8500000000000000000000000000000000000D8
+:10C8600000000000000000000000000000000000C8
+:10C8700000000000000000000000000000000000B8
+:10C8800000000000000000000000000000000000A8
+:10C890000000000000000000000000000000000098
+:10C8A0000000000000000000000000000000000088
+:10C8B0000000000000000000000000000000000078
+:10C8C0000000000000000000000000000000000068
+:10C8D0000000000000000000000000000000000058
+:10C8E0000000000000000000000000000000000048
+:10C8F0000000000000000000000000000000000038
+:10C900000000000000000000000000000000000027
+:10C910000000000000000000000000000000000017
+:10C920000000000000000000000000000000000007
+:10C9300000000000000000000000000000000000F7
+:10C9400000000000000000000000000000000000E7
+:10C9500000000000000000000000000000000000D7
+:10C9600000000000000000000000000000000000C7
+:10C9700000000000000000000000000000000000B7
+:10C9800000000000000000000000000000000000A7
+:10C990000000000000000000000000000000000097
+:10C9A0000000000000000000000000000000000087
+:10C9B0000000000000000000000000000000000077
+:10C9C0000000000000000000000000000000000067
+:10C9D0000000000000000000000000000000000057
+:10C9E0000000000000000000000000000000000047
+:10C9F0000000000000000000000000000000000037
+:10CA00000000000000000000000000000000000026
+:10CA10000000000000000000000000000000000016
+:10CA20000000000000000000000000000000000006
+:10CA300000000000000000000000000000000000F6
+:10CA400000000000000000000000000000000000E6
+:10CA500000000000000000000000000000000000D6
+:10CA600000000000000000000000000000000000C6
+:10CA700000000000000000000000000000000000B6
+:10CA800000000000000000000000000000000000A6
+:10CA90000000000000000000000000000000000096
+:10CAA0000000000000000000000000000000000086
+:10CAB0000000000000000000000000000000000076
+:10CAC0000000000000000000000000000000000066
+:10CAD0000000000000000000000000000000000056
+:10CAE0000000000000000000000000000000000046
+:10CAF0000000000000000000000000000000000036
+:10CB00000000000000000000000000000000000025
+:10CB10000000000000000000000000000000000015
+:10CB20000000000000000000000000000000000005
+:10CB300000000000000000000000000000000000F5
+:10CB400000000000000000000000000000000000E5
+:10CB500000000000000000000000000000000000D5
+:10CB600000000000000000000000000000000000C5
+:10CB700000000000000000000000000000000000B5
+:10CB800000000000000000000000000000000000A5
+:10CB90000000000000000000000000000000000095
+:10CBA0000000000000000000000000000000000085
+:10CBB0000000000000000000000000000000000075
+:10CBC0000000000000000000000000000000000065
+:10CBD0000000000000000000000000000000000055
+:10CBE0000000000000000000000000000000000045
+:10CBF0000000000000000000000000000000000035
+:10CC00000000000000000000000000000000000024
+:10CC10000000000000000000000000000000000014
+:10CC20000000000000000000000000000000000004
+:10CC300000000000000000000000000000000000F4
+:10CC400000000000000000000000000000000000E4
+:10CC500000000000000000000000000000000000D4
+:10CC600000000000000000000000000000000000C4
+:10CC700000000000000000000000000000000000B4
+:10CC800000000000000000000000000000000000A4
+:10CC90000000000000000000000000000000000094
+:10CCA0000000000000000000000000000000000084
+:10CCB0000000000000000000000000000000000074
+:10CCC0000000000000000000000000000000000064
+:10CCD0000000000000000000000000000000000054
+:10CCE0000000000000000000000000000000000044
+:10CCF0000000000000000000000000000000000034
+:10CD00000000000000000000000000000000000023
+:10CD10000000000000000000000000000000000013
+:10CD20000000000000000000000000000000000003
+:10CD300000000000000000000000000000000000F3
+:10CD400000000000000000000000000000000000E3
+:10CD500000000000000000000000000000000000D3
+:10CD600000000000000000000000000000000000C3
+:10CD700000000000000000000000000000000000B3
+:10CD800000000000000000000000000000000000A3
+:10CD90000000000000000000000000000000000093
+:10CDA0000000000000000000000000000000000083
+:10CDB0000000000000000000000000000000000073
+:10CDC0000000000000000000000000000000000063
+:10CDD0000000000000000000000000000000000053
+:10CDE0000000000000000000000000000000000043
+:10CDF0000000000000000000000000000000000033
+:10CE00000000000000000000000000000000000022
+:10CE10000000000000000000000000000000000012
+:10CE20000000000000000000000000000000000002
+:10CE300000000000000000000000000000000000F2
+:10CE400000000000000000000000000000000000E2
+:10CE500000000000000000000000000000000000D2
+:10CE600000000000000000000000000000000000C2
+:10CE700000000000000000000000000000000000B2
+:10CE800000000000000000000000000000000000A2
+:10CE90000000000000000000000000000000000092
+:10CEA0000000000000000000000000000000000082
+:10CEB0000000000000000000000000000000000072
+:10CEC0000000000000000000000000000000000062
+:10CED0000000000000000000000000000000000052
+:10CEE0000000000000000000000000000000000042
+:10CEF0000000000000000000000000000000000032
+:10CF00000000000000000000000000000000000021
+:10CF10000000000000000000000000000000000011
+:10CF20000000000000000000000000000000000001
+:10CF300000000000000000000000000000000000F1
+:10CF400000000000000000000000000000000000E1
+:10CF500000000000000000000000000000000000D1
+:10CF600000000000000000000000000000000000C1
+:10CF700000000000000000000000000000000000B1
+:10CF800000000000000000000000000000000000A1
+:10CF90000000000000000000000000000000000091
+:10CFA0000000000000000000000000000000000081
+:10CFB0000000000000000000000000000000000071
+:10CFC0000000000000000000000000000000000061
+:10CFD0000000000000000000000000000000000051
+:10CFE0000000000000000000000000000000000041
+:10CFF0000000000000000000000000000000000031
+:10D000000000000000000000000000000000000020
+:10D010000000000000000000000000000000000010
+:10D020000000000000000000000000000000000000
+:10D0300000000000000000000000000000000000F0
+:10D0400000000000000000000000000000000000E0
+:10D0500000000000000000000000000000000000D0
+:10D0600000000000000000000000000000000000C0
+:10D0700000000000000000000000000000000000B0
+:10D0800000000000000000000000000000000000A0
+:10D090000000000000000000000000000000000090
+:10D0A0000000000000000000000000000000000080
+:10D0B0000000000000000000000000000000000070
+:10D0C0000000000000000000000000000000000060
+:10D0D0000000000000000000000000000000000050
+:10D0E0000000000000000000000000000000000040
+:10D0F0000000000000000000000000000000000030
+:10D10000000000000000000000000000000000001F
+:10D11000000000000000000000000000000000000F
+:10D1200000000000000000000000000000000000FF
+:10D1300000000000000000000000000000000000EF
+:10D1400000000000000000000000000000000000DF
+:10D1500000000000000000000000000000000000CF
+:10D1600000000000000000000000000000000000BF
+:10D1700000000000000000000000000000000000AF
+:10D18000000000000000000000000000000000009F
+:10D19000000000000000000000000000000000008F
+:10D1A000000000000000000000000000000000007F
+:10D1B000000000000000000000000000000000006F
+:10D1C000000000000000000000000000000000005F
+:10D1D000000000000000000000000000000000004F
+:10D1E000000000000000000000000000000000003F
+:10D1F000000000000000000000000000000000002F
+:10D20000000000000000000000000000000000001E
+:10D21000000000000000000000000000000000000E
+:10D2200000000000000000000000000000000000FE
+:10D2300000000000000000000000000000000000EE
+:10D2400000000000000000000000000000000000DE
+:10D2500000000000000000000000000000000000CE
+:10D2600000000000000000000000000000000000BE
+:10D2700000000000000000000000000000000000AE
+:10D28000000000000000000000000000000000009E
+:10D29000000000000000000000000000000000008E
+:10D2A000000000000000000000000000000000007E
+:10D2B000000000000000000000000000000000006E
+:10D2C000000000000000000000000000000000005E
+:10D2D000000000000000000000000000000000004E
+:10D2E000000000000000000000000000000000003E
+:10D2F000000000000000000000000000000000002E
+:10D30000000000000000000000000000000000001D
+:10D31000000000000000000000000000000000000D
+:10D3200000000000000000000000000000000000FD
+:10D3300000000000000000000000000000000000ED
+:10D3400000000000000000000000000000000000DD
+:10D3500000000000000000000000000000000000CD
+:10D3600000000000000000000000000000000000BD
+:10D3700000000000000000000000000000000000AD
+:10D38000000000000000000000000000000000009D
+:10D39000000000000000000000000000000000008D
+:10D3A000000000000000000000000000000000007D
+:10D3B000000000000000000000000000000000006D
+:10D3C000000000000000000000000000000000005D
+:10D3D000000000000000000000000000000000004D
+:10D3E000000000000000000000000000000000003D
+:10D3F000000000000000000000000000000000002D
+:10D40000000000000000000000000000000000001C
+:10D41000000000000000000000000000000000000C
+:10D4200000000000000000000000000000000000FC
+:10D4300000000000000000000000000000000000EC
+:10D4400000000000000000000000000000000000DC
+:10D4500000000000000000000000000000000000CC
+:10D4600000000000000000000000000000000000BC
+:10D4700000000000000000000000000000000000AC
+:10D48000000000000000000000000000000000009C
+:10D49000000000000000000000000000000000008C
+:10D4A000000000000000000000000000000000007C
+:10D4B000000000000000000000000000000000006C
+:10D4C000000000000000000000000000000000005C
+:10D4D000000000000000000000000000000000004C
+:10D4E000000000000000000000000000000000003C
+:10D4F000000000000000000000000000000000002C
+:10D50000000000000000000000000000000000001B
+:10D51000000000000000000000000000000000000B
+:10D5200000000000000000000000000000000000FB
+:10D5300000000000000000000000000000000000EB
+:10D5400000000000000000000000000000000000DB
+:10D5500000000000000000000000000000000000CB
+:10D5600000000000000000000000000000000000BB
+:10D5700000000000000000000000000000000000AB
+:10D58000000000000000000000000080000000001B
+:10D59000000000000000000000000000000000008B
+:10D5A0000000000000000000000000000000000A71
+:10D5B0000000000000000000000000001000000358
+:10D5C000000000000000000D0000000D3C020800FB
+:10D5D000244273203C030800246377ACAC40000075
+:10D5E0000043202B1480FFFD244200043C1D080052
+:10D5F00037BD7FFC03A0F0213C100800261032103C
+:10D600003C1C0800279C73200E0010FE0000000048
+:10D610000000000D30A5FFFF30C600FF274301804A
+:10D620008F4201B80440FFFE24020002AC640000F7
+:10D63000A4650008A066000AA062000B3C0210006E
+:10D64000AC67001803E00008AF4201B83C0360007B
+:10D650008C624FF80440FFFE3C020200AC644FC0F5
+:10D66000AC624FC43C02100003E00008AC624FF80B
+:10D670009482000C2486001400A0382100021302BA
+:10D68000000210800082402100C8102B104000577B
+:10D690000000000090C300002C62000950400051BF
+:10D6A00090C20001000310803C030800246372D084
+:10D6B000004310218C4200000040000800000000E0
+:10D6C00090C300012402000A1462003A0000000026
+:10D6D000010610232C42000A1440003624C6000222
+:10D6E0008CE2000034420100ACE2000090C2000075
+:10D6F00090C3000190C4000290C5000300031C0009
+:10D7000000021600004310250004220000441025EA
+:10D710000045102524C60004ACE2000490C20000BD
+:10D7200090C3000190C4000290C5000300021600DF
+:10D7300000031C00004310250004220000441025B3
+:10D740000045102524C600040A000CB8ACE200080D
+:10D7500090C30001240200041462001624C60002D3
+:10D7600090C2000090C400018CE30000000212008F
+:10D77000004410253463000424C60002ACE2000C0F
+:10D780000A000CB8ACE3000090C3000124020003BF
+:10D790001462000824C600028CE2000090C300005E
+:10D7A00024C6000134420008A0E300100A000CB8AF
+:10D7B000ACE2000003E000082402000190C3000175
+:10D7C000240200021062000224C400020100202191
+:10D7D0000A000CB8008030210A000CB824C60001F1
+:10D7E00090C200010A000CB800C2302103E000081A
+:10D7F0000000102127BDFFE8AFBF0014AFB000103C
+:10D800000E00130200808021936200052403FFFEB6
+:10D8100002002021004310248FBF00148FB000109D
+:10D82000A36200050A00130B27BD001827BDFFE8FF
+:10D83000AFB00010AFBF00140E000F3C008080217D
+:10D840009362000024030050304200FF14430004A0
+:10D8500024020100AF4201800A000D3002002021A5
+:10D86000AF400180020020218FBF00148FB0001054
+:10D870000A000FE727BD001827BDFF80AFBE007864
+:10D88000AFB70074AFB20060AFBF007CAFB600703E
+:10D89000AFB5006CAFB40068AFB30064AFB1005C6B
+:10D8A000AFB000588F5001283C0208008C4231A0D4
+:10D8B0002403FF809365003F0202102100431024DF
+:10D8C000AF4200243C0208008C4231A09364000562
+:10D8D00030B200FF020210213042007F03421821C3
+:10D8E000000420273C02000A006218213084000155
+:10D8F000AF8300140000F0210000B8211480005311
+:10D90000AFA0005093430116934401128F450104C8
+:10D91000306300FF3C020001308400FF00A2282495
+:10D92000034310210344182124564000246740007B
+:10D9300014A001CD2402000193620000304300FFD7
+:10D94000240200201062000524020050106200062C
+:10D95000000000000A000D74000000000000000D2F
+:10D960000A000D7DAFA000303C1E080027DE736C5E
+:10D970000A000D7DAFA000303C0208008C4200DCA4
+:10D98000244200013C010800AC2200DC0E00139F81
+:10D99000000000000A000F318FBF007C8F4201049D
+:10D9A0003C03002092D3000D004310240002202BE2
+:10D9B00000042140AFA400308F4301043C0200402A
+:10D9C0000062182414600002348500400080282181
+:10D9D00032620020AFA500301440000234A600805F
+:10D9E00000A0302110C0000BAFA6003093C5000886
+:10D9F0008F67004C0200202100052B0034A5008118
+:10DA000030A5F0810E000C9B30C600FF0A000F2EDF
+:10DA1000000000009362003E304200401040000FC2
+:10DA200024020004564200072402001202002021B2
+:10DA300000E028210E0013F702C030210A000F3148
+:10DA40008FBF007C16420005000000000E000D2173
+:10DA5000000020210A000F318FBF007C9743011A7C
+:10DA600096C4000E93620035326500043075FFFFE6
+:10DA700000442004AFA400548ED1000410A000156F
+:10DA80008ED400089362003E3042004010400007F0
+:10DA9000000000000E0013E0022020211040000DC5
+:10DAA000000000000A000F2E000000008F620044FA
+:10DAB000022210230440016A000000008F62004827
+:10DAC0000222102304410166240400160A000E21DC
+:10DAD0008FC200048F620048022210230440000815
+:10DAE000000000003C0208008C423100244200018A
+:10DAF0003C010800AC2231000A000F2300000000A6
+:10DB00008F62004002221023184000128F840014FC
+:10DB10003C0208008C423100327300FC0000A82156
+:10DB2000244200013C010800AC2231008F63004018
+:10DB30009482011C022318233042FFFF0043102A65
+:10DB4000504000102402000C8F6200400A000DF2C9
+:10DB5000022210239483011C9762003C0043102B87
+:10DB600010400006000000009482011C00551023A4
+:10DB7000A482011C0A000DF72402000CA480011CE1
+:10DB80002402000CAFA200308F620040005120231D
+:10DB90001880000D02A4102A144001260000000085
+:10DBA0001495000602A410233A62000130420001DD
+:10DBB000144001200000000002A410230224882148
+:10DBC0000A000E093055FFFF0000202132620002DA
+:10DBD0001040001A326200109362003E3042004052
+:10DBE000504000118FC200040E00130202002021D9
+:10DBF00024020018A362003F936200052403FFFE85
+:10DC000002002021004310240E00130BA362000524
+:10DC100024040039000028210E0013C9240600182E
+:10DC20000A000F3024020001240400170040F80904
+:10DC3000000000000A000F3024020001104001081B
+:10DC4000000000008F63004C8F620054028210239A
+:10DC50001C40010302831023044200010060A02144
+:10DC6000AFA40018AFB10010AFB50014934201206B
+:10DC70008F6500409763003C304200FF0342102153
+:10DC8000004410218FA400543063FFFF2442400061
+:10DC90000083182B8FA40030AFA20020AFA500286E
+:10DCA00000832025AFA40030AFA50024AFA0002C36
+:10DCB000AFB400349362003E30420008504000117F
+:10DCC0008FC2000002C0202127A500380E000CB230
+:10DCD000AFA000385440000B8FC200008FA2003864
+:10DCE00030420100504000078FC200008FA3003C6B
+:10DCF0008F6200600062102304430001AF63006084
+:10DD00008FC200000040F80927A400108FA2003045
+:10DD10003042000254400001327300FE9362003E24
+:10DD200030420040104000378FA200248F62005420
+:10DD30001682001A326200012402001412420010FE
+:10DD40002A42001510400006240200162402000C8E
+:10DD500012420007326200010A000E7D000000003E
+:10DD600012420005326200010A000E7D0000000030
+:10DD70000A000E782417000E0A000E7824170010EF
+:10DD80000A000E7C24170012936200232403FFBDB7
+:10DD900000431024A36200233262000110400019E6
+:10DDA0008FA200242402000C1242000E2A42000D11
+:10DDB000104000062402000E2402000A124200074E
+:10DDC0008FA200240A000E9524420001124200088E
+:10DDD0008FA200240A000E95244200010A000E932F
+:10DDE000241700082402000E16E200022417001671
+:10DDF000241700108FA2002424420001AFA20024A7
+:10DE00008FA200248FA300148F76004000431021BE
+:10DE1000AF6200408F8200149442011C1040000940
+:10DE2000000000008F6200488F6400409763003C50
+:10DE3000004410233063FFFF0043102A1040000805
+:10DE40008FA20054936400368F6300403402FFFCBD
+:10DE50000082100400621821AF6300488FA20054B2
+:10DE60008FA600300282902130C200081040000EC0
+:10DE7000000000008F6200581642000430C600FF08
+:10DE80009742011A5040000134C6001093C50008A3
+:10DE90008FA700340200202100052B0034A500804C
+:10DEA0000E000C9B30A5F0808F62004000561023BE
+:10DEB0001840001B8FA200183C0208008C423198C9
+:10DEC000304200101040000D2402000197620068EB
+:10DED0001440000A240200018F8200149442011CA5
+:10DEE0001440000624020001A76200689742007AED
+:10DEF000244200640A000EE9A7620012A762001221
+:10DF00000E001302020020219362007D2403000111
+:10DF100002002021344200010A000EE7AFA30050A6
+:10DF20001840000A000000000E0013020200202129
+:10DF30009362007D2403000102002021AFA3005062
+:10DF4000344200040E00130BA362007D9362003E76
+:10DF5000304200401440000C326200011040000AC0
+:10DF6000000000008F6300408FC2000424040018EA
+:10DF7000246300010040F809AF6300408FA2003025
+:10DF80000A000F30304200048F6200581052001017
+:10DF9000000000008F620018022210231C400008BD
+:10DFA000240400018F6200181622000900000000FE
+:10DFB0008F62001C02821023044000050000000054
+:10DFC000AF720058AFA40050AF710018AF74001CBE
+:10DFD00012E0000B8FA200500E001302020020215D
+:10DFE000A377003F0E00130B0200202102E0302136
+:10DFF000240400370E0013C9000028218FA200500E
+:10E0000010400003000000000E000CA902002021B7
+:10E0100012A00005000018218FA200303042000439
+:10E020005040001100601021240300010A000F304D
+:10E03000006010210E001302020020219362007D77
+:10E0400002002021344200040E00130BA362007D65
+:10E050000E000CA9020020210A000F30240200014A
+:10E06000AF400044240200018FBF007C8FBE0078C7
+:10E070008FB700748FB600708FB5006C8FB40068D6
+:10E080008FB300648FB200608FB1005C8FB0005816
+:10E0900003E0000827BD00808F4201B80440FFFE66
+:10E0A00024020800AF4201B803E0000800000000AD
+:10E0B0003C02000803421021944200483084FFFFD4
+:10E0C000248400123045FFFF10A0001700A4102B7D
+:10E0D0001040001624020003934201202403001A7A
+:10E0E000A343018B304200FF2446FFFE8F820000D5
+:10E0F00000A6182B3863000100021382004310248D
+:10E10000104000058F84000434820001A74601946A
+:10E1100003E00008AF8200042402FFFE0082102406
+:10E1200003E00008AF8200042402000303E00008BB
+:10E13000A342018B27BDFFE0AFB10014AFB00010C8
+:10E14000AFBF001830B0FFFF30D1FFFF8F4201B8E2
+:10E150000440FFFE00000000AF440180AF440020F7
+:10E160000E000F42020020218F8300008F840004E4
+:10E17000A750019AA750018EA74301908F830008F2
+:10E1800030828000AF4301A8A75101881040000EE3
+:10E190008F82000493420116304200FC24420004A6
+:10E1A000005A10218C4240003042FFFF144000060C
+:10E1B0008F8200043C02FFFF34427FFF0082102464
+:10E1C000AF8200048F8200042403BFFF00431024A9
+:10E1D000A74201A69743010C8F42010400031C00D3
+:10E1E0003042FFFF00621825AF4301AC3C02100033
+:10E1F000AF4201B88FBF00188FB100148FB000106C
+:10E2000003E0000827BD00208F47007093420112F1
+:10E210008F83000027BDFFF0304200FF00022882FC
+:10E2200030620100000030211040004324A40003AC
+:10E230003062400010400010306220000004108066
+:10E24000005A10218C43400024A4000400041080D4
+:10E25000AFA30000005A10218C424000AFA200047E
+:10E2600093420116304200FC005A10218C424000BB
+:10E270000A000FC0AFA200081040002F000030219C
+:10E2800000041080005A10218C43400024A4000494
+:10E2900000041080AFA30000005A10218C424000FF
+:10E2A000AFA00008AFA200048FA800080000302132
+:10E2B00000002021240A00083C090800252901004B
+:10E2C00003A41021148A000300042A001100000A8C
+:10E2D0000000000090420000248400012C83000C08
+:10E2E00000A2102100021080004910218C42000081
+:10E2F0001460FFF300C230263C0408008C84310413
+:10E300008F4200702C8300201060000900473823E2
+:10E310003C030800246331080004108000431021EE
+:10E3200024830001AC4700003C010800AC23310409
+:10E33000AF8600082406000100C0102103E0000899
+:10E3400027BD00103C0208008C42003827BDFFD0DA
+:10E35000AFB50024AFB40020AFB10014AFBF0028A8
+:10E36000AFB3001CAFB20018AFB00010000088219E
+:10E370003C15080026B50038144000022454FFFF65
+:10E380000000A0219742010E8F8400003042FFFF61
+:10E39000308340001060000A245200043C02002038
+:10E3A0000082102450400007308280008F820004D9
+:10E3B0002403BFFF008318240A0010103442100009
+:10E3C000308280001040000A3C02002000821024AD
+:10E3D000104000078F8200043C03FFFF34637FFF7F
+:10E3E0000083182434428000AF820004AF83000011
+:10E3F0000E000F980000000014400007000000000D
+:10E400009743011E9742011C3063FFFF0002140076
+:10E4100000621825AF8300089742010C8F4340002B
+:10E420003045FFFF3402FFFF1462000300000000CC
+:10E430000A001028241100208F42400030420100C1
+:10E4400054400001241100108F840000308210001D
+:10E450005040001436310001308200201440000B7F
+:10E460003C021000008210245040000E36310001A2
+:10E470003C030E003C020DFF008318243442FFFFD2
+:10E480000043102B50400007363100013C020800C9
+:10E490008C42002C244200013C010800AC22002CDC
+:10E4A000363100053C0608008CC6003454C00023F9
+:10E4B0008F8500008F820004304240005440001FCE
+:10E4C0008F8500003C021F01008210243C031000D5
+:10E4D0005443001A8F85000030A202001440001738
+:10E4E0008F8500003250FFFF363100028F4201B8A5
+:10E4F0000440FFFE00000000AF4001800200202128
+:10E500000E000F42AF4000208F8300042402BFFFA3
+:10E51000A750019A006218248F820000A750018E34
+:10E52000A7510188A74301A6A74201903C02100011
+:10E53000AF4201B80A0010F5000010213C021000A3
+:10E5400000A210241040003A0000000010C0000F8C
+:10E550000000000030A201001040000C3C0302004B
+:10E560003C020F0000A2102410430008000000002D
+:10E570008F8200080054102400551021904200049E
+:10E58000244200040A00109F000221C00000000085
+:10E59000000516023050000F3A0300022E4203EF2E
+:10E5A000384200012C6300010062182414600073DB
+:10E5B000240200013C0308008C6300D02E06000CEE
+:10E5C000386200012C42000100461024144000155E
+:10E5D000001021C02602FFFC2C4200045440001110
+:10E5E00000002021386200022C4200010046102465
+:10E5F00010400003000512420A00109F0000202175
+:10E600000010182B0043102450400006001021C0B9
+:10E61000000020213245FFFF0E000F633226FFFB72
+:10E62000001021C03245FFFF0A0010F2362600021A
+:10E630008F4240003C0308008C63002430420100FC
+:10E640001040004630620001322200043070000D9C
+:10E65000144000022413000424130002000512C217
+:10E66000384200012E4303EF3042000138630001BD
+:10E6700000431025104000033231FFFB2402FFFB52
+:10E680000202802410C000183202000130A20100F2
+:10E6900010400015320200013C020F0000A21024BD
+:10E6A0003C0302001043000F8F8200082403FFFE8A
+:10E6B00002038024005410240055102190420004CD
+:10E6C000023330252442000412000002000221C05F
+:10E6D0003226FFFF0E000F633245FFFF12000027B6
+:10E6E00000001021320200011040000D320200042F
+:10E6F0002402000112020002023330253226FFFFFD
+:10E70000000020210E000F633245FFFF2402FFFEB0
+:10E7100002028024120000190000102132020004BD
+:10E72000104000162402000124020004120200021C
+:10E73000023330253226FFFF3245FFFF0E000F6304
+:10E74000240401002402FFFB020280241200000BBB
+:10E75000000010210A0010F52402000110400007FB
+:10E76000000010213245FFFF362600020000202164
+:10E770000E000F6300000000000010218FBF002872
+:10E780008FB500248FB400208FB3001C8FB2001807
+:10E790008FB100148FB0001003E0000827BD0030D7
+:10E7A00027BDFFD0AFB000103C04600CAFBF002C01
+:10E7B000AFB60028AFB50024AFB40020AFB3001C43
+:10E7C000AFB20018AFB100148C8250002403FF7F59
+:10E7D0003C1A8000004310243442380CAC825000B4
+:10E7E000240200033C106000AF4200088E020808BB
+:10E7F0003C1B80083C010800AC2000203042FFF0A8
+:10E80000384200102C4200010E001B85AF82001818
+:10E810003C04FFFF3C020400348308063442000C31
+:10E82000AE021948AE03194C3C0560168E021980E1
+:10E830008CA300003442020000641824AE02198048
+:10E840003C0253531462000334A47C008CA20004E5
+:10E85000005020218C82007C8C830078AF820010D5
+:10E86000AF83000C8F55000032A200031040FFFD63
+:10E8700032A200011040013D32A200028F42012865
+:10E88000AF4200208F4201048F430100AF8200009D
+:10E890000E000F3CAF8300043C0208008C4200C015
+:10E8A000104000088F8400003C0208008C4200C425
+:10E8B000244200013C010800AC2200C40A00126995
+:10E8C000000000003C020010008210241440010CE3
+:10E8D0008F8300043C0208008C4200203C030800A7
+:10E8E0008C63003800008821244200013C010800AC
+:10E8F000AC2200203C16080026D600381460000226
+:10E900002474FFFF0000A0219742010E30834000D5
+:10E910003042FFFF1060000A245200043C02002035
+:10E920000082102450400007308280008F82000453
+:10E930002403BFFF008318240A0011703442100022
+:10E94000308280001040000A3C0200200082102427
+:10E95000104000078F8200043C03FFFF34637FFFF9
+:10E960000083182434428000AF820004AF8300008B
+:10E970000E000F9800000000144000070000000087
+:10E980009743011E9742011C3063FFFF00021400F1
+:10E9900000621825AF8300089742010C8F434000A6
+:10E9A0003045FFFF3402FFFF146200030000000047
+:10E9B0000A001188241100208F42400030420100DB
+:10E9C00054400001241100108F8400003082100098
+:10E9D0005040001436310001308200201440000BFA
+:10E9E0003C021000008210245040000E363100011D
+:10E9F0003C030E003C020DFF008318243442FFFF4D
+:10EA00000043102B50400007363100013C02080043
+:10EA10008C42002C244200013C010800AC22002C56
+:10EA2000363100053C0608008CC6003454C0002373
+:10EA30008F8500008F820004304240005440001F48
+:10EA40008F8500003C021F01008210243C0310004F
+:10EA50005443001A8F85000030A2020014400017B2
+:10EA60008F8500003250FFFF363100028F4201B81F
+:10EA70000440FFFE00000000AF40018002002021A2
+:10EA80000E000F42AF4000208F8300042402BFFF1E
+:10EA9000A750019A006218248F820000A750018EAF
+:10EAA000A7510188A74301A6A74201903C0210008C
+:10EAB000AF4201B80A001267000010213C021000AA
+:10EAC00000A210241040003A0000000010C0000F07
+:10EAD0000000000030A201001040000C3C030200C6
+:10EAE0003C020F0000A210241043000800000000A8
+:10EAF0008F82000800541024005610219042000418
+:10EB0000244200040A0011FF000221C0000000009E
+:10EB1000000516023050000F3A0300022E4203EFA8
+:10EB2000384200012C630001006218241460008543
+:10EB3000240200013C0308008C6300D02E06000C68
+:10EB4000386200012C4200010046102414400015D8
+:10EB5000001021C02602FFFC2C420004544000118A
+:10EB600000002021386200022C42000100461024DF
+:10EB700050400003000512420A0011FF000020214E
+:10EB80000010182B0043102450400006001021C034
+:10EB9000000020213245FFFF0E000F633226FFFBED
+:10EBA000001021C03245FFFF0A0012523626000233
+:10EBB0008F4240003C0308008C6300243042010077
+:10EBC0001040004630620001322200043070000D17
+:10EBD000144000022413000424130002000512C292
+:10EBE000384200012E4303EF304200013863000138
+:10EBF00000431025104000033231FFFB2402FFFBCD
+:10EC00000202802410C000183202000130A201006C
+:10EC100010400015320200013C020F0000A2102437
+:10EC20003C0302001043000F8F8200082403FFFE04
+:10EC30000203802400541024005610219042000446
+:10EC4000023330252442000412000002000221C0D9
+:10EC50003226FFFF0E000F633245FFFF120000391E
+:10EC600000001021320200011040000D32020004A9
+:10EC70002402000112020002023330253226FFFF77
+:10EC8000000020210E000F633245FFFF2402FFFE2B
+:10EC9000020280241200002B000010213202000426
+:10ECA0001040002824020001240200041202000285
+:10ECB000023330253226FFFF3245FFFF0E000F637F
+:10ECC000240401002402FFFB020280241200001D24
+:10ECD000000010210A0012672402000150400019B0
+:10ECE000000010213245FFFF3626000200002021DF
+:10ECF0000E000F63000000000A00126700001021E0
+:10ED00002402BFFF00621024104000080000000031
+:10ED1000240287FF00621024144000083C020060B7
+:10ED20000082102410400005000000000E000D3489
+:10ED3000000000000A001267000000000E0012C769
+:10ED400000000000104000063C0240008F430124F8
+:10ED50003C026020AC430014000000003C02400074
+:10ED6000AF4201380000000032A200021040FEBD98
+:10ED7000000000008F4201403C044000AF420020F0
+:10ED80008F4301483C027000006218241064004266
+:10ED9000000000000083102B144000063C026000BD
+:10EDA0003C022000106200073C0240000A0012C32F
+:10EDB000000000001062003C3C0240000A0012C348
+:10EDC000000000008F4501408F4601448F420148FA
+:10EDD00000021402304300FF240200041462000AFF
+:10EDE000274401808F4201B80440FFFE2402001C2A
+:10EDF000AC850000A082000B3C021000AF4201B8BD
+:10EE00000A0012C33C0240002402000914620012EE
+:10EE100000061602000229C0AF4500208F4201B84B
+:10EE20000440FFFE2402000124030003AF450180DB
+:10EE3000A343018BA740018EA740019AA7400190F0
+:10EE4000AF4001A8A7420188A74201A6AF4001AC8C
+:10EE50003C021000AF4201B88F4201B80440FFFEEF
+:10EE600000000000AC8500008F420148000214023F
+:10EE7000A482000824020002A082000B8F420148F5
+:10EE8000A48200103C021000AC860024AF4201B8FE
+:10EE90000A0012C33C0240000E00131000000000E4
+:10EEA0000A0012C33C0240000E001BBA0000000022
+:10EEB0003C024000AF420178000000000A00112F20
+:10EEC000000000008F4201003042003E144000115B
+:10EED00024020001AF4000488F420100304207C0C9
+:10EEE0001040000500000000AF40004CAF40005053
+:10EEF00003E0000824020001AF400054AF4000408E
+:10EF00008F4201003042380054400001AF400044BD
+:10EF10002402000103E00008000000008F4201B855
+:10EF20000440FFFE24020001AF440180AF40018491
+:10EF3000A7450188A342018A24020002A342018B53
+:10EF40009742014A14C00004A7420190AF4001A4B7
+:10EF50000A0012EF3C0210008F420144AF4201A4AC
+:10EF60003C021000AF4001A803E00008AF4201B826
+:10EF70008F4201B80440FFFE24020002AF4401802A
+:10EF8000AF440184A7450188A342018AA342018BB3
+:10EF90009742014AA7420190AF4001A48F42014429
+:10EFA000AF4201A83C02100003E00008AF4201B8E4
+:10EFB0003C0290003442000100822025AF44002032
+:10EFC0008F4200200440FFFE0000000003E0000824
+:10EFD000000000003C028000344200010082202535
+:10EFE00003E00008AF44002027BDFFE8AFBF0014D6
+:10EFF000AFB000108F500140934301499342014844
+:10F0000093440148306300FF304200FF00021200C9
+:10F0100000622825240200191062007630840080E6
+:10F020002862001A1040001C24020020240200085C
+:10F0300010620077286200091040000E2402000BC5
+:10F0400024020001106200342862000250400005D2
+:10F050002402000650600034020020210A00139AA6
+:10F060000000000010620030020020210A00139A04
+:10F07000000000001062003B2862000C50400002BB
+:10F080002402000E24020009106200560200202112
+:10F090000A00139A00000000106200562862002146
+:10F0A0001040000F240200382402001C1062005897
+:10F0B0002862001D104000062402001F2402001BCD
+:10F0C0001062004C000000000A00139A00000000CB
+:10F0D0001062004A020020210A00139A000000007A
+:10F0E00010620045286200391040000724020080A9
+:10F0F0002462FFCB2C420002104000450200202178
+:10F100000A00139600003021106200090000000080
+:10F110000A00139A000000001480003D0200202124
+:10F120000A0013908FBF00140A00139624060001F2
+:10F130008F4201B80440FFFE24020002A342018B6B
+:10F14000A74501889742014AA74201908F42014496
+:10F15000A74201923C021000AF4201B80A00139C82
+:10F160008FBF00149742014A14400029000000009C
+:10F1700093620005304200041440002500000000A6
+:10F180000E001302020020219362000502002021DC
+:10F19000344200040E00130BA362000593620005C5
+:10F1A0003042000414400002000000000000000D86
+:10F1B0009362000024030020304200FF1443001437
+:10F1C000000000008F4201B80440FFFE2402000549
+:10F1D000AF500180A342018B3C0210000A00139A39
+:10F1E000AF4201B88FBF00148FB000100A0012F2B6
+:10F1F00027BD00180000000D020020210000302172
+:10F200008FBF00148FB000100A0012DD27BD001858
+:10F210000000000D8FBF00148FB0001003E0000845
+:10F2200027BD001827BDFFE8AFBF00100E000F3C40
+:10F2300000000000AF4001808FBF001000002021BF
+:10F240000A000FE727BD00183084FFFF30A5FFFF3D
+:10F25000000018211080000700000000308200012B
+:10F260001040000200042042006518210A0013AB80
+:10F270000005284003E000080060102110C00006CF
+:10F2800024C6FFFF8CA2000024A50004AC8200006D
+:10F290000A0013B52484000403E000080000000005
+:10F2A00010A0000824A3FFFFAC86000000000000AF
+:10F2B000000000002402FFFF2463FFFF1462FFFA36
+:10F2C0002484000403E0000800000000308300FFF5
+:10F2D00030A500FF30C600FF274701808F4201B8EC
+:10F2E0000440FFFE000000008F420128346340000C
+:10F2F000ACE2000024020001ACE00004A4E300083A
+:10F30000A0E2000A24020002A0E2000B3C0210006E
+:10F31000A4E50010ACE00024ACE00028A4E6001254
+:10F3200003E00008AF4201B827BDFFE8AFBF0010FF
+:10F330009362003F24030012304200FF1043000D8F
+:10F34000008030218F620044008210230440000AB4
+:10F350008FBF00108F62004824040039000028216C
+:10F3600000C2102304410004240600120E0013C939
+:10F37000000000008FBF00102402000103E000081D
+:10F3800027BD001827BDFFC8AFB20030AFB1002CB9
+:10F39000AFBF0034AFB0002890C5000D00809021B1
+:10F3A00030A400101080000B00C088218CC300081E
+:10F3B0008F6200541062000730A20005144000B5AF
+:10F3C000240400010E000D21000020210A0014BBBE
+:10F3D0000040202130A200051040000930A3001297
+:10F3E000108000AC240400018E2300088F620054BA
+:10F3F000146200A98FBF00340A00142C24040038C2
+:10F4000024020012146200A324040001022020211F
+:10F4100027A500100E000CB2AFA000101040001184
+:10F42000024020218E220008AF620084AF600040BD
+:10F430000E001302000000009362007D02402021B4
+:10F44000344200200E00130BA362007D0E000CA9B5
+:10F4500002402021240400382405008D0A0014B83D
+:10F46000240600129362003E304200081040000F54
+:10F470008FA2001030420100104000078FA300143B
+:10F480008F6200600062102304430008AF630060D5
+:10F490000A00144100000000AF6000609362003E6B
+:10F4A0002403FFF700431024A362003E9362003E52
+:10F4B00030420008144000022406000300003021FE
+:10F4C00093620034936300378F640084304200FFFE
+:10F4D000306300FF006618210003188000432821D4
+:10F4E00000A4202B1080000B000000009763003C5C
+:10F4F0008F6200843063FFFF004510230062182BE9
+:10F5000014600004000000008F6200840A00145D93
+:10F51000004580239762003C3050FFFF8FA300100E
+:10F520003062000410400004000628808FA2001CF6
+:10F530000A0014650202102B2E020218504000032C
+:10F54000240202180A00146E02051023306300041E
+:10F5500010600003004510238FA2001C00451023FB
+:10F56000004080212C420080544000012410008083
+:10F570000E0013020240202124020001AF62000CA1
+:10F580009362003E001020403042007FA362003EA4
+:10F590008E22000424420001AF620040A770003CAC
+:10F5A0008F6200509623000E00431021AF62005876
+:10F5B0008F62005000441021AF62005C8E22000474
+:10F5C000AF6200188E220008AF62001C8FA20010EC
+:10F5D000304200085440000A93A20020A360003685
+:10F5E000936200362403FFDFA36200359362003E7E
+:10F5F00000431024A362003E0A0014988E220008E3
+:10F60000A36200358E220008AF62004C8F62002496
+:10F610008F63004000431021AF62004893620000F6
+:10F6200024030050304200FF144300122403FF80E3
+:10F630003C0208008C4231A00242102100431024F9
+:10F64000AF4200283C0208008C4231A08E24000802
+:10F650003C03000C024210213042007F0342102183
+:10F6600000431021AC4400D88E230008AF82001460
+:10F67000AC4300DC0E00130B0240202124040038B0
+:10F68000000028212406000A0E0013C90000000013
+:10F69000240400018FBF00348FB200308FB1002CE2
+:10F6A0008FB000280080102103E0000827BD00383B
+:10F6B00027BDFFF827420180AFA20000308A00FF7B
+:10F6C0008F4201B80440FFFE000000008F46012871
+:10F6D0003C0208008C4231A02403FF80AF86004822
+:10F6E00000C2102100431024AF4200243C02080055
+:10F6F0008C4231A08FA900008FA8000000C2102109
+:10F700003042007F034218213C02000A00621821A7
+:10F71000946400D48FA700008FA50000240200028B
+:10F72000AF830014A0A2000B8FA30000354260003D
+:10F730003084FFFFA4E200083C021000AD26000068
+:10F74000AD040004AC60002427BD0008AF4201B83E
+:10F7500003E00008240200018F88003C9382002807
+:10F760008F8300143C07080024E7777800481023B3
+:10F77000304200FF304900FC246500888F8600403D
+:10F78000304A0003112000090000202124820004D7
+:10F790008CA30000304400FF0089102AACE3000075
+:10F7A00024A500041440FFF924E7000411400009D7
+:10F7B000000020212482000190A30000304400FFBB
+:10F7C000008A102BA0E3000024A500011440FFF9DB
+:10F7D00024E7000130C20003144000048F85003C80
+:10F7E000310200031040000D0000000010A00009CD
+:10F7F000000020212482000190C30000304400FF5B
+:10F800000085102BA0E3000024C600011440FFF97E
+:10F8100024E7000103E00008000000001100FFFDE4
+:10F8200000002021248200048CC30000304400FF2B
+:10F830000088102BACE3000024C600041440FFF93C
+:10F8400024E7000403E00008000000008F83003C70
+:10F850009382002830C600FF30A500FF004310232C
+:10F86000304300FF8F8200140080382100431021B4
+:10F8700014C00002244800880083382130E20003CD
+:10F880001440000530A2000314400003306200035E
+:10F890001040000D0000000010A000090000202111
+:10F8A0002482000190E30000304400FF0085102B0B
+:10F8B000A103000024E700011440FFF9250800011E
+:10F8C00003E000080000000010A0FFFD0000202160
+:10F8D000248200048CE30000304400FF0085102BDC
+:10F8E000AD03000024E700041440FFF925080004DC
+:10F8F00003E00008000000000080482130AAFFFF5C
+:10F9000030C600FF30E7FFFF274801808F4201B873
+:10F910000440FFFE8F820048AD0200008F420124A8
+:10F92000AD0200048D220020A5070008A102000AF4
+:10F9300024020016A102000B934301208D2200082F
+:10F940008D240004306300FF004310219783003AA8
+:10F95000004410218D250024004310233C0308009F
+:10F960008C6331A08F840014A502000C246300E88E
+:10F970002402FFFFA50A000EA5030010A506001231
+:10F98000AD050018AD020024948201142403FFF792
+:10F990003042FFFFAD0200288C820118AD02002C1E
+:10F9A0003C021000AD000030AF4201B88D220020B3
+:10F9B0000043102403E00008AD2200208F820014D1
+:10F9C00030E7FFFF00804821904200D330A5FFFFC1
+:10F9D00030C600FF0002110030420F0000E238255F
+:10F9E000274801808F4201B80440FFFE8F82004803
+:10F9F000AD0200008F420124AD0200048D220020E0
+:10FA0000A5070008A102000A24020017A102000BAA
+:10FA1000934301208D2200088D240004306300FFF1
+:10FA2000004310219783003A004410218F84001472
+:10FA3000004310233C0308008C6331A0A502000C96
+:10FA4000A505000E246300E8A5030010A50600121A
+:10FA5000AD0000148D220024AD0200188C82005CE1
+:10FA6000AD02001C8C820058AD0200202402FFFF72
+:10FA7000AD020024948200E63042FFFFAD02002870
+:10FA800094820060948300BE30427FFF3063FFFFAA
+:10FA90000002120000431021AD02002C3C021000B5
+:10FAA000AD000030AF4201B8948200BE2403FFF7DE
+:10FAB00000A21021A48200BE8D2200200043102449
+:10FAC00003E00008AD220020274301808F4201B8E7
+:10FAD0000440FFFE8F8200249442001C3042FFFF4E
+:10FAE000000211C0AC62000024020019A062000BE9
+:10FAF0003C021000AC60003003E00008AF4201B8E7
+:10FB00008F87002C30C300FF8F4201B80440FFFEF6
+:10FB10008F82004834636000ACA2000093820044EE
+:10FB2000A0A200058CE20010A4A20006A4A3000875
+:10FB30008C8200202403FFF7A0A2000A2402000206
+:10FB4000A0A2000B8CE20000ACA200108CE200042A
+:10FB5000ACA200148CE2001CACA200248CE20020B9
+:10FB6000ACA200288CE2002CACA2002C8C820024D9
+:10FB7000ACA200183C021000AF4201B88C820020F9
+:10FB80000043102403E00008AC8200208F8600149C
+:10FB900027BDFFE8AFBF0014AFB0001090C20063F4
+:10FBA000304200201040000830A500FF8CC2007CCD
+:10FBB0002403FFDF24420001ACC2007C90C200633A
+:10FBC00000431024A0C2006310A000238F83001400
+:10FBD00027500180020028210E0015D6240600823D
+:10FBE0008F82001490420063304200405040001960
+:10FBF000A38000448F83002C8F4201B80440FFFE95
+:10FC00008F820048AE02000024026082A602000833
+:10FC100024020002A202000B8C620008AE02001057
+:10FC20008C62000CAE0200148C620014AE0200184C
+:10FC30008C620018AE0200248C620024AE02002800
+:10FC40008C620028AE02002C3C021000AF4201B8CA
+:10FC5000A38000448F8300148FBF00148FB0001066
+:10FC60009062006327BD00183042007FA0620063ED
+:10FC70009782003A8F86003C8F850014938300287A
+:10FC800000461023A782003AA4A000E490A40063D9
+:10FC90008F820040AF83003C2403FFBF0046102149
+:10FCA00000832024AF820040A0A400638F82001450
+:10FCB000A04000BD8F82001403E00008A44000BEF5
+:10FCC0008F8A001427BDFFE0AFB10014AFB0001061
+:10FCD0008F88003CAFBF00189389001C954200E458
+:10FCE00030D100FF0109182B0080802130AC00FFCB
+:10FCF0003047FFFF0000582114600003310600FF69
+:10FD000001203021010958239783003A0068102B05
+:10FD10001440003C000000001468000724020001A9
+:10FD20008E0200202403FFFB34E7800000431024F0
+:10FD3000AE0200202402000134E70880158200058D
+:10FD40003165FFFF0E001554020020210A001691B4
+:10FD5000020020210E001585020020218F8400481A
+:10FD6000274301808F4201B80440FFFE240200189F
+:10FD7000AC640000A062000B8F840014948200E643
+:10FD8000A46200103C021000AC600030AF4201B829
+:10FD90009482006024420001A4820060948200608A
+:10FDA0003C0308008C63318830427FFF5443000FCE
+:10FDB000020020219482006024038000004310246C
+:10FDC000A48200609082006090830060304200FF57
+:10FDD000000211C200021027000211C03063007F30
+:10FDE00000621825A0830060020020210220282143
+:10FDF0008FBF00188FB100148FB000100A0015F9E2
+:10FE000027BD0020914200632403FF80004310259A
+:10FE1000A14200639782003A3048FFFF11000020A2
+:10FE20009383001C8F840014004B1023304600FF86
+:10FE3000948300E42402EFFF0168282B0062182459
+:10FE4000A48300E414A000038E02002001005821C6
+:10FE5000000030212403FFFB34E78000004310241E
+:10FE6000AE02002024020001158200053165FFFF6B
+:10FE70000E001554020020210A0016B99783003A9B
+:10FE80000E001585020020219783003A8F82003CE6
+:10FE9000A780003A00431023AF82003C9383001CEC
+:10FEA0008F8200148FBF00188FB100148FB0001024
+:10FEB00027BD002003E00008A04300BD938200445A
+:10FEC0002403000127BDFFE8004330042C4200203A
+:10FED000AFB00010AFBF00142410FFFE10400005AB
+:10FEE000274501803C0208008C4231900A0016D65A
+:10FEF000004610243C0208008C4231940046102435
+:10FF000014400007240600848F8300142410FFFF90
+:10FF1000906200623042000F34420040A0620062F2
+:10FF20000E0015D600000000020010218FBF001443
+:10FF30008FB0001003E0000827BD00188F83002455
+:10FF400027BDFFE0AFB20018AFB10014AFB0001092
+:10FF5000AFBF001C9062000D00A0902130D100FFC7
+:10FF60003042007FA062000D8F8500148E43001880
+:10FF7000008080218CA2007C146200052402000E07
+:10FF800090A20063344200200A0016FFA0A2006382
+:10FF90000E0016C5A38200442403FFFF1043004750
+:10FFA0002404FFFF52200045000020218E43000062
+:10FFB0003C02001000621024504000043C02000883
+:10FFC000020020210A00170E2402001500621024EE
+:10FFD000504000098E450000020020212402001438
+:10FFE0000E0016C5A38200442403FFFF1043003314
+:10FFF0002404FFFF8E4500003C02000200A21024F2
+:020000040001F9
+:10000000104000163C0200048F8600248CC20014AD
+:100010008CC300108CC40014004310230044102B28
+:1000200050400005020020218E43002C8CC200109D
+:1000300010620003020020210A00173F2402001270
+:100040003C02000400A210245040001C00002021AB
+:10005000020020210A00173F2402001300A21024EE
+:10006000104000068F8300248C6200105040001363
+:10007000000020210A001739020020218C620010A4
+:10008000504000048E42002C020020210A00173F3D
+:10009000240200115040000900002021020020210C
+:1000A000240200170E0016C5A38200442403FFFF9C
+:1000B000104300022404FFFF000020218FBF001C1A
+:1000C0008FB200188FB100148FB000100080102183
+:1000D00003E0000827BD00208F83001427BDFFD850
+:1000E000AFB40020AFB3001CAFB20018AFB1001422
+:1000F000AFB00010AFBF0024906200638F91002C5E
+:100100002412FFFF3442004092250000A0620063E9
+:100110008E2200100080982130B0003F105200065F
+:100120000360A0212402000D0E0016C5A382004426
+:10013000105200542404FFFF8F8300148E220018F5
+:100140008C63007C10430007026020212402000E13
+:100150000E0016C5A38200442403FFFF104300498C
+:100160002404FFFF24040020120400048F830014E1
+:100170009062006334420020A06200638F850034E7
+:1001800010A0002000000000560400048F8200141C
+:10019000026020210A0017902402000A9683000AB8
+:1001A000944200603042FFFF144300048F8200201D
+:1001B0002404FFFD0A0017B7AF82003C3C02080090
+:1001C0008C42318C0045102B144000060260202127
+:1001D000000028210E001646240600010A0017B769
+:1001E000000020212402002D0E0016C5A382004429
+:1001F0002403FFFF104300232404FFFF0A0017B766
+:1002000000002021160400058F8400148E230014A2
+:100210002402FFFF506200180260202194820060D7
+:1002200024420001A4820060948200603C03080024
+:100230008C63318830427FFF5443000F02602021DD
+:10024000948200602403800000431024A482006094
+:100250009082006090830060304200FF000211C273
+:1002600000021027000211C03063007F00621825D1
+:10027000A0830060026020210E0015F92405000112
+:10028000000020218FBF00248FB400208FB3001CFA
+:100290008FB200188FB100148FB0001000801021B1
+:1002A00003E0000827BD00288F83001427BDFFE866
+:1002B000AFB00010AFBF0014906200638F87002CB6
+:1002C00000808021344200408CE60010A062006370
+:1002D0003C0308008C6331B030C23FFF0043102B59
+:1002E0001040004E8F8500302402FF8090A3000D47
+:1002F00000431024304200FF5040004902002021FA
+:100300000006138230480003240200025502004414
+:100310000200202194A2001C8F85001424030023D6
+:10032000A4A201148CE60000000616023042003F31
+:10033000104300103C0300838CE300188CA2007C67
+:10034000106200062402000E0E0016C5A3820044AF
+:100350002403FFFF104300382404FFFF8F830014A1
+:100360009062006334420020A06200630A0017FC20
+:100370008F83002400C31024144300078F830024BC
+:1003800090A200623042000F34420020A0A200621E
+:10039000A38800388F8300249062000D3042007FD4
+:1003A000A062000D8F83003410600018020020212D
+:1003B0008F8400308C8200100043102B1040000905
+:1003C00024020018020020210E0016C5A38200445A
+:1003D0002403FFFF104300182404FFFF0A00182421
+:1003E000000020218C820010240500010200202141
+:1003F000004310238F830024240600010E001646BC
+:10040000AC6200100A001824000020210E0015F92B
+:10041000240500010A0018240000202102002021E8
+:100420002402000D8FBF00148FB0001027BD0018EC
+:100430000A0016C5A38200448FBF00148FB00010BD
+:100440000080102103E0000827BD001827BDFFC869
+:10045000AFB20020AFBF0034AFB60030AFB5002C54
+:10046000AFB40028AFB30024AFB1001CAFB0001888
+:100470008F4601283C0308008C6331A02402FF80D2
+:10048000AF86004800C318213065007F034528214E
+:10049000006218243C02000AAF43002400A2282175
+:1004A00090A2006200809021AF850014304200FFCE
+:1004B00000021102A382003890A200BC3042000268
+:1004C0001440000224030034240300308F820014FF
+:1004D000A3830028938300388C4200C0A38000448B
+:1004E000AF82003C24020004106203148F84003C9D
+:1004F0008E440004508003118F84003C8E42001013
+:100500003083FFFFA784003A106002F7AF820040FB
+:100510008F8400142403FF80908200630062102403
+:10052000304200FF144002C79785003A9383003899
+:100530002402000230B6FFFF14620005000088218B
+:10054000938200282403FFFD0A001B11AF82003CA8
+:100550008F82003C02C2102B144002998F8400400D
+:100560000E0014EC00000000938300283C040800F7
+:1005700024847778240200341462002EAF84002C87
+:100580003C0A08008D4A77A82402FFFFAFA20010A2
+:10059000008038212405002F3C09080025297378A4
+:1005A000240800FF2406FFFF90E2000024A3FFFFC1
+:1005B0000006220200C21026304200FF0002108016
+:1005C000004910218C420000306500FF24E7000143
+:1005D00014A8FFF50082302600061027AFA20014F1
+:1005E000AFA200100000282127A7001027A60014A2
+:1005F00000C510239044000324A2000100A7182185
+:10060000304500FF2CA200041440FFF9A064000054
+:100610008FA2001011420007240200050240202191
+:100620000E0016C5A38200442403FFFF104300649C
+:100630002404FFFF3C0208009042777C1040000930
+:100640008F820014024020212402000C0E0016C5E7
+:10065000A38200442403FFFF104300592404FFFF3A
+:100660008F820014A380001C3C0308008C63777CFD
+:100670008C4400803C0200FF3442FFFF00621824DB
+:100680000083202B10800008AF830034024020211B
+:10069000240200190E0016C5A38200442403FFFFA4
+:1006A000104300472404FFFF8F87003C9782003AE5
+:1006B0008F850034AF8700200047202310A0003B27
+:1006C000A784003A8F86001430A200030002102392
+:1006D00090C300BC3050000300B0282100031882F2
+:1006E000307300010013108000A228213C03080091
+:1006F0008C6331A08F8200483084FFFF0085202B5F
+:100700000043102110800011244200888F84002CA7
+:100710001082000E3C033F013C0208008C427778B7
+:10072000004310243C0325001443000630E500FF7D
+:100730008C820000ACC200888C8200100A0018E98C
+:10074000ACC200980E001529000030219382001CD5
+:100750008F8500148F830040020238218F82003C75
+:10076000A387001C94A400E4006218218F82003447
+:1007700034841000AF83004000503021A4A400E472
+:100780001260000EAF86003C24E20004A382001C2D
+:1007900094A200E424C30004AF83003C3442200050
+:1007A000A4A200E40A001906000020218F82004064
+:1007B000AF80003C00471021AF82004000002021A4
+:1007C0002414FFFF109402092403FFFF3C080800D3
+:1007D0008D0877883C0208008C4231B03C03080049
+:1007E0009063777831043FFF0082102B1040001B8C
+:1007F0003067003F3C0208008C4231A88F830048DC
+:100800000004218000621821006418213062007FFA
+:10081000034228213C02000C00A228213C02008057
+:10082000344200013066007800C230252402FF8087
+:1008300000621024AF42002830640007AF42080471
+:100840008F8200140344202124840940AF460814F9
+:10085000AF850024AF840030AC4301189383003887
+:1008600024020003146201C72402000124020026AE
+:1008700010E201C928E200271040001324020032D0
+:100880002402002210E201C428E2002310400008E4
+:10089000240200242402002010E201B024020021DE
+:1008A00010E2013F024020210A001AF32402000B4B
+:1008B00010E201B92402002510E2001002402021BC
+:1008C0000A001AF32402000B10E201A628E200330A
+:1008D000104000062402003F2402003110E2009282
+:1008E000024020210A001AF32402000B10E2019DAD
+:1008F000024020210A001AF32402000B8F90002CE2
+:100900003C0308008C6331B08F8500308E040010EA
+:100910000000A8218CB3001430823FFF0043102B4D
+:100920008CB10020504001870240202190A3000D8F
+:100930002402FF8000431024304200FF5040018118
+:100940000240202100041382304200031440017D44
+:100950000240202194A3001C8F8200148E040028E2
+:10096000A44301148CA20010026218231064000337
+:10097000024020210A00197C2402001F8F820034CB
+:10098000006210210262102B104000088F830024A7
+:1009900002402021240200180E0016C5A382004444
+:1009A0001054016C2404FFFF8F8300248F840034D3
+:1009B0008C6200100224882100441023AC620010D5
+:1009C0008F820014AC7100208C4200680051102B03
+:1009D000104000098F830030024020212402001DB6
+:1009E0000E0016C5A38200442403FFFF10430159E3
+:1009F0002404FFFF8F8300308E0200248C630024C8
+:100A000010430007024020212402001C0E0016C5DE
+:100A1000A38200442403FFFF1043014E2404FFFF80
+:100A20008F8400248C82002424420001AC820024A4
+:100A3000123300048F8200148C4200685622000E8C
+:100A40008E0200008E0200003C0300800043102450
+:100A50001440000D2402001A024020210E0016C589
+:100A6000A38200442403FFFF1043013A2404FFFF44
+:100A70000A0019BA8E0200143C03008000431024BF
+:100A8000504000038E020014AC8000208E0200143F
+:100A90002411FFFF105100062402001B02402021F8
+:100AA0000E0016C5A38200441051012A2404FFFF42
+:100AB0008E0300003C02000100621024104000126E
+:100AC0003C020080006210241440000802402021F3
+:100AD0002402001A0E0016C5A38200442403FFFF5F
+:100AE0001043011C2404FFFF0240202102002821A2
+:100AF0000E0016E5240600012403FFFF1043011534
+:100B00002404FFFF241500018F83002402A030215C
+:100B10000240202194620036240500012442000195
+:100B20000A001AD7A46200368F90002C3C030800FC
+:100B30008C6331B08E13001032623FFF0043102BE4
+:100B4000104000898F8400302402FF809083000DC4
+:100B500000431024304200FF104000842402000DA6
+:100B60000013138230420003240300011443007F6A
+:100B70002402000D9082000D304200085440000411
+:100B80008F820034024020210A001A082402002427
+:100B9000504000048E03000C024020210A001A0875
+:100BA000240200278C82002054620006024020218B
+:100BB0008E0300088C820024506200098E0200140B
+:100BC00002402021240200200E0016C5A38200440A
+:100BD000105400712403FFFF0A001A3D8F84002483
+:100BE0002411FFFF145100048F86001402402021BD
+:100BF0000A001A38240200258E0300188CC2007CDB
+:100C0000106200032402000E0A001A38024020215C
+:100C10008E0300248C82002810620003240200212D
+:100C20000A001A38024020218E0500288C82002CF0
+:100C300010A200032402001F0A001A3802402021DB
+:100C40008E03002C14600003240200230A001A38CB
+:100C5000024020218CC200680043102B104000038A
+:100C6000240200260A001A38024020218C82001437
+:100C7000006518210043102B104000088F840024C9
+:100C800002402021240200220E0016C5A382004447
+:100C9000105100412403FFFF8F8400242403FFF739
+:100CA0009082000D00431024A082000D8F86001456
+:100CB0003C0308008C6331AC8F82004894C400E090
+:100CC0008F8500240043102130847FFF00042040E2
+:100CD000004410213043007F034320213C03000ED9
+:100CE000008320212403FF8000431024AF42002C06
+:100CF000A49300008CA2002824420001ACA200288A
+:100D00008CA2002C8E03002C00431021ACA2002CDE
+:100D10008E02002CACA200308E020014ACA2003473
+:100D200094A2003A24420001A4A2003A94C600E032
+:100D30003C0208008C4231B024C4000130837FFFA4
+:100D40001462000F008030212402800000823024D1
+:100D500030C2FFFF000213C2304200FF0002102722
+:100D60000A001A76000233C02402000D024020213E
+:100D70000E0016C5A38200440A001A7C0040182108
+:100D80008F82001402402021240500010E0015F975
+:100D9000A44600E0000018210A001B0E0060882114
+:100DA0008F90002C3C0308008C6331B08E0500103E
+:100DB00030A23FFF0043102B104000612402FF804F
+:100DC0008F8400309083000D00431024304200FFD8
+:100DD0005040005C024020218F8200341040000B04
+:100DE000000513828F8200149763000A944200600A
+:100DF0003042FFFF14430005000513828F8200205C
+:100E00002404FFFD0A001AEBAF82003C30420003CD
+:100E10001440000E00000000920200021040000585
+:100E20008E03002450600015920300030A001AA7E5
+:100E3000024020218C8200245062001092030003A3
+:100E4000024020210A001AAF2402000F9082000DF8
+:100E50003042000854400009920300030240202160
+:100E6000240200100E0016C5A38200442403FFFFD5
+:100E7000104300382404FFFF920300032402000201
+:100E80005462000C920200038F8200345440000927
+:100E900092020003024020212402002C0E0016C5FD
+:100EA000A38200442403FFFF1043002A2404FFFF11
+:100EB000920200030200282102402021384600103F
+:100EC0002CC600012C4200010E0016E5004630251C
+:100ED0002410FFFF1050001F2404FFFF8F830034F5
+:100EE00010600013024020213C0208008C42318C2B
+:100EF0000043102B144000070000000000002821D0
+:100F0000240600010E001646000000000A001AEB3D
+:100F1000000020212402002D0E0016C5A3820044EB
+:100F20001050000C2404FFFF0A001AEB00002021DF
+:100F30000E0015F9240500010A001AEB000020211B
+:100F4000024020212402000D0E0016C5A382004499
+:100F5000004020210A001B0E008088211514000E7D
+:100F6000000000000E00174C024020210A001B0E5A
+:100F7000004088210E0016C5A38200440A001B0E03
+:100F80000040882114620017022018212402002347
+:100F900014E200052402000B0E0017C002402021BD
+:100FA0000A001B0E0040882102402021A382004439
+:100FB0000E0016C52411FFFF0A001B0F0220182186
+:100FC00030A500FF0E001529240600019783003A82
+:100FD0008F82003CA780003A00431023AF82003C80
+:100FE000022018211220003E9782003A2402FFFDC1
+:100FF0005462003E8E4300208E4200048F83001412
+:1010000000561023AE420004906200633042007F1D
+:10101000A06200638E4200208F840014A780003AF3
+:1010200034420002AE420020A48000E490820063BB
+:101030002403FFBF00431024A08200630A001B5159
+:101040008E4300209082006300621024304200FF33
+:10105000104000239782003A90820088908300BD60
+:10106000248500883042003F2444FFE02C82002089
+:10107000A383001C10400019AF85002C240200013E
+:1010800000821804306200191440000C3C028000F9
+:1010900034420002006210241440000B3062002031
+:1010A0001040000F9782003A90A6000102402021D4
+:1010B000240500010A001B4B30C60001024020211C
+:1010C0000A001B4A240500010240202100002821BB
+:1010D000240600010E001646000000009782003A28
+:1010E0001440FD0C8F8400148E43002030620004F5
+:1010F000104000128F84003C2402FFFB0062102489
+:10110000AE420020274301808F4201B80440FFFE19
+:101110008F820048AC6200008F420124AC62000460
+:1011200024026083A462000824020002A062000B73
+:101130003C021000AF4201B88F84003C8F83001442
+:101140008FBF00348FB600308FB5002C8FB40028CD
+:101150008FB300248FB200208FB1001C8FB0001815
+:101160002402000127BD003803E00008AC6400C081
+:1011700030A500FF2403000124A900010069102B01
+:101180001040000C00004021240A000100A310239D
+:10119000004A380424630001308200010069302BCA
+:1011A00010400002000420420107402554C0FFF80F
+:1011B00000A3102303E00008010010213C020800F6
+:1011C000244260A43C010800AC22736C3C0208007D
+:1011D000244253083C010800AC227370240200062C
+:1011E00027BDFFE03C010800A02273743C021EDC16
+:1011F000AFB20018AFB10014AFBF001CAFB0001009
+:1012000034526F4100008821240500080E001B7233
+:1012100002202021001180803C07080024E7737819
+:101220000002160002071821AC620000000028210D
+:1012300024A200013045FFFF8C6200002CA60008AC
+:1012400004410002000220400092202614C0FFF852
+:10125000AC640000020780218E0400000E001B72A7
+:1012600024050020262300013071FFFF2E230100FA
+:101270001460FFE5AE0200008FBF001C8FB20018A3
+:101280008FB100148FB0001003E0000827BD0020CC
+:1012900027BDFFD8AFB3001CAFB20018AFBF00200E
+:1012A000AFB10014AFB000108F5101408F4801481A
+:1012B00000089402324300FF311300FF8F4201B84F
+:1012C0000440FFFE27500180AE1100008F42014410
+:1012D000AE02000424020002A6120008A202000BC3
+:1012E00024020014AE1300241062002528620015A9
+:1012F0001040000824020015240200101062003083
+:1013000024020012106200098FBF00200A001CADE9
+:101310008FB3001C1062007024020022106200379C
+:101320008FBF00200A001CAD8FB3001C3C020800D8
+:101330008C4231A02403FF8002221021004310249C
+:10134000AF4200243C0208008C4231A0022210214E
+:101350003042007F034218213C02000A006218213B
+:10136000166000BCAF830014906200623042000F30
+:1013700034420030A06200620A001CAC8FBF002023
+:101380003C0460008C832C083C02F0033442FFFFD5
+:1013900000621824AC832C083C0208008C4231A067
+:1013A0008C832C08244200740002108200021480F6
+:1013B00000621825AC832C080A001CAC8FBF0020EB
+:1013C0003C0208008C4231A02403FF80022210213D
+:1013D00000431024AF4200243C0208008C4231A09C
+:1013E0003C03000A022210213042007F03421021F8
+:1013F000004310210A001CABAF8200143C0208001D
+:101400008C4231A02405FF800222102100451024C7
+:10141000AF4200243C0208008C4231A0022210217D
+:101420003042007F034218213C02000A006218216A
+:101430009062006300A21024304200FF104000853B
+:10144000AF83001424620088944300123C02080019
+:101450008C4231A830633FFF000319800222102123
+:10146000004310213043007F034320210045102416
+:101470003C03000C00832021AF4200289082000D25
+:1014800000A21024304200FF10400072AF840024FC
+:101490009082000D304200101440006F8FBF00207A
+:1014A0000E0015C8000000008F4201B80440FFFE86
+:1014B00000000000AE1100008F420144AE020004A3
+:1014C00024020002A6120008A202000BAE130024A0
+:1014D0000A001CAC8FBF00202406FF8002261024C7
+:1014E000AF4200203C0208008C4231A031043FFF93
+:1014F000000421800222102100461024AF42002463
+:101500003C0308008C6331A83C0208008C4231A0E7
+:101510003227007F022318210222102100641821A3
+:101520003042007F3064007F034228213C02000AE1
+:101530000066182400A22821034420213C02000C4C
+:1015400000822021AF4300283C02000803471821F5
+:1015500000629021AF850014AF8400240E0015C8EE
+:10156000010080218F4201B80440FFFE8F820024D9
+:101570008F840014274501809042000DACB100001B
+:10158000A4B0000600021600000216030002102795
+:10159000000237C214C00016248200889442001250
+:1015A00032033FFF30423FFF1443001224026082A7
+:1015B000908300632402FF8000431024304200FF28
+:1015C0005040000C24026082908200623042000F82
+:1015D00034420040A082006224026084A4A2000879
+:1015E0002402000DA0A200050A001C963C02270060
+:1015F00024026082A4A20008A0A000053C022700EB
+:1016000000061C000062182524020002A0A2000BA4
+:10161000ACA30010ACA00014ACA00024ACA0002827
+:10162000ACA0002C8E42004C8F840024ACA2001889
+:101630009083000D2402FF8000431024304200FFFD
+:10164000104000058FBF00209082000D3042007FC7
+:10165000A082000D8FBF00208FB3001C8FB2001836
+:101660008FB100148FB000103C02100027BD00287D
+:0816700003E00008AF4201B8DD
+:08167800080034300800343092
+:10168000080033A8080033E0080034140800343898
+:0C16900008003438080034380800331813
+:04169C000A0001241B
+:1016A00000000000000000000000000D74706136B2
+:1016B0002E302E313500000006000F010000000022
+:1016C000000000000000000000000000000000001A
+:1016D000000000000000000000000000000000000A
+:1016E00000000000000000000000000000000000FA
+:1016F00000000000000000000000000000000000EA
+:1017000000000000000000000000000000000000D9
+:1017100000000000000000000000000000000000C9
+:1017200000000000000000000000000000000000B9
+:1017300010000003000000000000000D0000000D7C
+:101740003C02080024421C003C030800246320944F
+:10175000AC4000000043202B1480FFFD2442000415
+:101760003C1D080037BD2FFC03A0F0213C100800F1
+:10177000261004903C1C0800279C1C000E00015CF5
+:10178000000000000000000D3084FFFF30820007E1
+:101790008F85001810400002248300073064FFF892
+:1017A0000085302130C41FFF03441821247B4000F2
+:1017B000AF85001CAF84001803E00008AF4400842C
+:1017C0003084FFFF308200078F8500208F8600283D
+:1017D00010400002248300073064FFF800852021B8
+:1017E0000086182B14600002AF8500240086202399
+:1017F0000344282134068000AF840020AF440080D9
+:1018000000A6202103E00008AF84003827BDFFD8E0
+:10181000AFB3001CAFB20018AFB00010AFBF0024D0
+:10182000AFB40020AFB100143C0860088D14500024
+:101830002418FF7F3C1A8000029898243672380CD6
+:10184000AD1250008F5100083C07601C3C0860003E
+:1018500036300001AF500008AF800018AF40008064
+:10186000AF4000848CE600088D0F08083C07601626
+:101870008CEC000031EEFFF039CA00103C0DFFFF88
+:10188000340B80003C030080034B48212D440001B1
+:10189000018D28243C0253533C010800AC23042052
+:1018A000AF890038AF860028AF840010275B400066
+:1018B00014A2000334E37C008CF9000403281821EF
+:1018C0008C7F007C8C6500783C0280003C0B08001B
+:1018D0008D6B048C3C0A08008D4A048834520070D9
+:1018E000AF85003CAF9F00403C13080026731C44AA
+:1018F0000240A0218E4800008F46000038C300013E
+:101900003064000110800017AF8800340280482145
+:101910008D2F00003C0508008CA5045C3C180800D5
+:101920008F18045801E8102300A280210000C8216C
+:101930000202402B03198821022838213C010800AB
+:10194000AC30045C3C010800AC2704588F4E00000A
+:1019500039CD000131AC00011580FFED01E04021DF
+:10196000AF8F00348E5100003C0708008CE7045C08
+:101970003C0D08008DAD04580228802300F0602142
+:10198000000070210190302B01AE1821006620214B
+:101990003C010800AC2C045C3C010800AC24045859
+:1019A0008F4601088F47010030C92000AF86000034
+:1019B000AF87000C1120000A00C040213C1808002D
+:1019C0008F18042C270800013C010800AC28042CC7
+:1019D0003C184000AF5801380A0001960000000092
+:1019E0009749010400002821014550213122FFFFC1
+:1019F000016258210162F82B015F502130D90200A9
+:101A00003C010800AC2B048C3C010800AC2A048883
+:101A10001720001524040F0010E40013000000003C
+:101A200024080D0010E8023B30CD000611A0FFE9AC
+:101A30003C184000936E00002409001031C400F0EF
+:101A40001089027124020070108202E58F88001450
+:101A5000250F0001AF8F00143C184000AF5801382B
+:101A60000A00019600000000974C01041180FFD984
+:101A70003C18400030C34000146000A1000000008A
+:101A80008F46017804C0FFFE8F87003824100800BD
+:101A9000240F00088CE30008AF500178A74F0140E5
+:101AA000A7400142974E01048F86000031C9FFFF15
+:101AB00030CD000111A002E1012040212531FFFEBF
+:101AC00024180002A75801463228FFFFA7510148F9
+:101AD0003C1908008F39043C172002D08F8C000C71
+:101AE00030DF002017E00002240400092404000174
+:101AF00030C20C0024050400504500013484000469
+:101B0000A744014A3C1108008E3104203C180048CB
+:101B10003C1000010238182530CF00020070282543
+:101B200011E00004000018213C19010000B928252B
+:101B30002403000130DF000453E00005AF830008F8
+:101B40003C06001000A6282524030001AF830008EE
+:101B5000AF45100000000000000000000000000081
+:101B6000000000008F8300081060002300000000C8
+:101B70008F45100004A1FFFE000000001060001E51
+:101B8000000000008F4410003C0C0020008C10244A
+:101B9000104000198F8E000031CD000211A00016F8
+:101BA00000000000974F101415E000130000000023
+:101BB000975910083338FFFF2711000600111882CB
+:101BC0000003308000C72821323000013223000397
+:101BD0001200032C8CA200000000000D00C7F821A9
+:101BE000AFE200003C0508008CA5043024A60001EB
+:101BF0003C010800AC2604308F6D00003402FFFF6A
+:101C0000AF8D00048CEC0000118202A600002021A0
+:101C10008CED000031AC01001180028A0000000050
+:101C20003C0208008C4204743C0308008C63044CA2
+:101C30003C1F08008FFF04703C1808008F180448F0
+:101C4000004838210068802100E8282B03E4302177
+:101C50000208402B0304882100C570210228782146
+:101C60003C010800AC30044C3C010800AC2F044897
+:101C70003C010800AC2704743C010800AC2E047041
+:101C80008F8400180120302131290007249F00088B
+:101C900033F91FFF03594021AF84001CAF9900188E
+:101CA000251B4000AF590084112000038F830020C2
+:101CB00024C200073046FFF88F84002800C3282183
+:101CC00000A4302B14C00002AF83002400A42823FA
+:101CD00003456021340D8000018D10213C0F100060
+:101CE000AF850020AF820038AF450080AF4F01784C
+:101CF0008F880014250F00010A0001EFAF8F001438
+:101D00008F6200088F67000024050030000776020C
+:101D100031C300F0106500A7240F0040546FFF4C42
+:101D20008F8800148F4B01780560FFFE00000000D3
+:101D300030CA020015400003000612820000000DA8
+:101D400000061282304D0003000D4900012D1821BC
+:101D500000038080020D40210008608001938021F3
+:101D60008E1F000017E00002000000000000000DC0
+:101D70008F6E000405C202BD92070006920E000598
+:101D8000920200043C090001000E18800070F82146
+:101D90008FED0018277100082448000501A9602173
+:101DA00000083082AFEC0018022020210E00059EB2
+:101DB00026050014920A00068F7900043C0B7FFF71
+:101DC000000A2080009178218DF800043566FFFF1D
+:101DD0000326282403053821ADE70004920E0005F0
+:101DE000920D0004960C0008000E10800051C821CE
+:101DF0008F230000974901043C07FFFF0067582428
+:101E00003128FFFF010DF82103EC50233144FFFF7F
+:101E100001643025AF26000092030007241800015A
+:101E200010780275240F0003106F02850000000077
+:101E30008E0500102419000AA7590140A745014248
+:101E4000921800048F860000240F0001A758014457
+:101E5000A74001469747010430D100023C050041EC
+:101E6000A747014800001821A74F014A122000038C
+:101E700030CB00043C050141240300015160000502
+:101E8000AF8300083C06001000A6282524030001AB
+:101E9000AF830008AF451000000000000000000004
+:101EA00000000000000000008F8A000811400004BC
+:101EB000000000008F4410000481FFFE00000000BD
+:101EC0008F6B0000920800043C1108008E3104441E
+:101ED000AF8B000497590104311800FF3C0E080035
+:101EE0008DCE04403325FFFF0305382102276021F2
+:101EF00000001021250F000A31E8FFFF0187482B61
+:101F000001C2682101A9F821311000073C01080035
+:101F1000AC2C04443C010800AC3F04401200000318
+:101F20008F8C00182506000730C8FFF8010C6821C7
+:101F300031BF1FFFAF8C001CAF9F0018AF5F008444
+:101F400097440104035F80213084FFFF308A00073B
+:101F500011400003261B4000248900073124FFF8AC
+:101F60008F8200208F850028008220210085702B21
+:101F700015C00002AF820024008520233C0B08001E
+:101F80008D6B048C3C0A08008D4A04880344882128
+:101F900034038000022310213C0F1000AF84002086
+:101FA000AF820038AF440080AF4F01780A0002963C
+:101FB0008F8800148F5001780600FFFE30D1020098
+:101FC00016200003000612820000000D0006128297
+:101FD000305F0003001F1900007F302100062080C1
+:101FE000009FC82100194880013380218E1800000D
+:101FF00013000002000000000000000D8F6C000CB8
+:10200000058001FB8F870038240E0001AE0E000012
+:102010008CE30008A20000078F650004000554024D
+:10202000314D00FF25A80005000830822CCB00416F
+:1020300015600002A20A00040000000D8F78000461
+:102040003C03FFFF00E02821330BFFFF256C000B52
+:10205000000C108200022080008748218D3F000084
+:1020600026040014A618000803E3C8240E00059EE9
+:10207000AD3900008F4F01083C11100001F13824E8
+:1020800010E001AB00000000974D0104920800072A
+:1020900025AAFFEC350600023144FFFFA206000727
+:1020A000960600082CC7001354E0000592030007B1
+:1020B00092110007362F0001A20F000792030007BC
+:1020C00024180001107801C224090003106901D509
+:1020D0008F88003830CBFFFF257100020011788314
+:1020E00031E400FF00042880A20F000500A8482169
+:1020F0008D2D0000974A01043C0EFFFF01AEF8242D
+:102100003143FFFF006B1023244CFFFE03ECC82576
+:10211000AD390000920600053C03FFF63462FFFF74
+:1021200030D800FF0018388000F08821922F00146A
+:102130003C04FF7F3487FFFF31EE000F01C65821BA
+:10214000316500FF00055080015068218DAC0020F2
+:102150000148F821A20B00060182C824AE0C000C35
+:10216000AFF9000C920900068E11000C03277824A9
+:102170000009C0800310702195C60026030828219D
+:1021800002272024AE04000CADCF0020ADC60024F1
+:10219000ACA600108F8800003C0B08008D6B048CEF
+:1021A0003C0A08008D4A0488241F001024190002EC
+:1021B000A75F0140A7400142A7400144A75901463B
+:1021C0009749010424070001310600022538FFFE6B
+:1021D000A75801483C050009A747014A10C0000361
+:1021E000000018213C05010924030001310C000402
+:1021F00051800005AF8300083C08001000A8282586
+:1022000024030001AF830008AF4510000000000068
+:102210000000000000000000000000009205000423
+:1022200024AE000231CD0007000D182330620007F4
+:10223000AE0200108F9000081200000400000000A1
+:102240008F4F100005E1FFFE000000008F710000BD
+:102250008F8E00183C0308008C630444AF91000487
+:102260009745010425CF001031E61FFF30A2FFFF84
+:10227000AF8E001CAF860018AF4600842449FFFED5
+:102280003C0C08008D8C0440974D010401208021F6
+:10229000000947C30070C02131A9FFFF0310F82BCC
+:1022A0000188C821033F202103463821313100072E
+:1022B0003C010800AC3804443C010800AC24044054
+:1022C0001220000324FB40002527000730E9FFF817
+:1022D0008F8600208F8400280126382100E4C02B3F
+:1022E00017000002AF86002400E4382303472021B2
+:1022F00034198000009910213C0F1000AF87002096
+:10230000AF820038AF470080AF4F01780A000296D5
+:102310008F8800149747010410E0FDAE3C18400080
+:102320008F5801780700FFFE30C5400010A0000361
+:102330003C1F00080000000D3C1F0008AF5F01407B
+:10234000241008008F860000AF50017897440104E4
+:1023500030D90001132000ED3086FFFF24CCFFFEB2
+:10236000240D0002A74D0146A74C01488F9100188B
+:102370002408000DA748014A8F630000262F00089B
+:1023800031E21FFF0342702130C90007AF83000410
+:10239000AF91001CAF82001800C03821AF4200840A
+:1023A0001120000325DB400024D800073307FFF885
+:1023B0008F8500208F84002800E5302100C4382B51
+:1023C00014E00002AF85002400C430238F84001481
+:1023D0000346F821340C8000AF86002003EC8021F6
+:1023E000AF460080249900013C0610003C184000D4
+:1023F000AF460178AF900038AF990014AF5801385C
+:102400000A000196000000008F630000975101044C
+:102410003067FFFF3228FFFF8F4F017805E0FFFE96
+:1024200030EC0007000CF82333F0000724F9FFFE1E
+:102430002404000AA7440140A7500142A7590144BF
+:10244000A7400146A74801488F45010830B8002041
+:1024500017000002240300092403000130CD00020C
+:10246000A743014A3C04004111A0000300001821C9
+:102470003C0401412403000130C90004512000053F
+:10248000AF8300083C0600100086202524030001CD
+:10249000AF830008AF4410000000000000000000FF
+:1024A00000000000000000008F8E000811C0000432
+:1024B000000000008F4210000441FFFE00000000F9
+:1024C0008F7F0000276400088F91003CAF9F0004BD
+:1024D000948500089490000A9499000C30AFFFFF97
+:1024E0000010C4003323FFFF11F100A603032025D1
+:1024F0003C0E08008DCE04443C0C08008D8C04403A
+:1025000000E888212626FFFE01C628210000682158
+:1025100000A6F82B018D2021009F80213C0108009E
+:10252000AC2504443C010800AC30044024E200081F
+:102530003042FFFF3047000710E000038F83001890
+:10254000244F000731E2FFF83106FFFF30C80007D3
+:102550000043802132191FFF0359C021AF83001CA3
+:10256000AF990018271B4000AF59008411000003E9
+:102570008F8C002024C5000730A6FFF88F84002828
+:1025800000CC282100A4F82B17E00002AF8C002417
+:1025900000A42823AF850020AF4500803C0408003C
+:1025A0008C84043403454821340E8000012E6821B8
+:1025B00010800005AF8D0038939100172406000E9F
+:1025C000122600112407043F3C021000AF4201789C
+:1025D0008F880014250F00010A0001EFAF8F00144F
+:1025E0000E0005C400E020218F8800143C0B080079
+:1025F0008D6B048C3C0A08008D4A0488250F00016D
+:102600000A0001EFAF8F00143C021000A7470148F9
+:10261000AF4201780A0004CE8F88001424040F0012
+:102620001184003D30CE002015C0000224030009B3
+:10263000240300010A00021AA743014A0A00020DFE
+:10264000A740014694EF000894F1000A94F0000CB2
+:102650008F8C003C001174003207FFFF31EDFFFF4B
+:1026600011AC003701C720253C1808008F1804441E
+:102670003C0F08008DEF0440000080210308682112
+:1026800001A8382B01F0702101C760213C0108002E
+:10269000AC2D04443C010800AC2C04400A00027A32
+:1026A0008F8400183C0208008C42047C3C03080024
+:1026B0008C6304543C1F08008FFF04783C1808000A
+:1026C0008F180450004838210068802100E8282B2A
+:1026D00003E430210208402B0304882100C5702147
+:1026E000022878213C010800AC3004543C01080069
+:1026F000AC2F04503C010800AC27047C3C010800CE
+:10270000AC2E04780A00027A8F840018A740014694
+:102710000A0004358F91001830CD002015A0FFC5A8
+:102720002403000D240300050A00021AA743014AEE
+:10273000974E010425C5FFF00A00038130A4FFFF76
+:102740008F9800401498FFC8000010213C05080035
+:102750008CA5046C3C1F08008FFF046800A8C821EA
+:102760000328302B03E22021008640213C01080091
+:10277000AC39046C3C010800AC2804680A00027AF9
+:102780008F8400188F8C0040148CFF5900E8C821FA
+:102790003C1808008F18046C3C1108008E31046846
+:1027A0002723FFFE03034821000010210123302BC3
+:1027B0000222702101C668213C010800AC29046C8A
+:1027C0003C010800AC2D04680A0004A524E20008BE
+:1027D0008F8800383C03FFFF8D02000C0043F82473
+:1027E00003E4C825AD19000C0A00038F30CBFFFFAE
+:1027F0000A0003C3AE000000974A010492040004DB
+:102800008E26000C014458212579FFF200C7C02410
+:102810003325FFFF03053825AE27000C0A0002E62A
+:102820008E0500103C0DFFFF8D0A0010014D58244D
+:1028300001646025AD0C00100A00038F30CBFFFF50
+:1028400097430104920E00048E290010006E10219F
+:10285000244DFFEE0127602431A8FFFF0188F825F1
+:10286000AE3F00100A0002E68E0500108E0F000C2D
+:10287000AE00000000078880023028210A0002B85C
+:10288000ACAF00201460000D3058FFFF3C04FFFF88
+:102890000044682401A47026000E602B000D102B4C
+:1028A000004CF82413E00002000000000000000DBE
+:1028B0008CAF00000A00025001E410253B03FFFF2B
+:1028C0000003882B0018802B0211202410800002A6
+:1028D000000000000000000D8CB900000A0002504A
+:1028E0003722FFFF3084FFFF30A5FFFF1080000775
+:1028F0000000182130820001104000020004204234
+:10290000006518211480FFFB0005284003E0000843
+:102910000060102110C00007000000008CA2000021
+:1029200024C6FFFF24A50004AC82000014C0FFFBF6
+:102930002484000403E000080000000010A0000848
+:1029400024A3FFFFAC860000000000000000000090
+:102950002402FFFF2463FFFF1462FFFA24840004B3
+:1029600003E0000800000000308EFFFF30D8FFFFBA
+:1029700000057C0001F8602539CDFFFF01AC502136
+:10298000014C582B014B4821000944023127FFFF1D
+:1029900000E830210006240230C5FFFF00A4182102
+:1029A0003862FFFF03E000083042FFFF3C0C0800E4
+:1029B0008D8C0484240BFF8027BDFFD0018450211F
+:1029C000014B4824AF4900203C0808008D080484CE
+:1029D000AFB20020AFB00018AFBF0028AFB30024E3
+:1029E000AFB1001C936600040104382130E4007F7D
+:1029F000009A10213C0300080043902130C50020BC
+:102A0000036080213C080111277B000814A000020C
+:102A1000264600702646006C92130004975101046C
+:102A2000920F00043267000F322EFFFF31ED00409D
+:102A300001C7282311A0000500004821925900BCBD
+:102A4000333800041700009000000000924300BCDF
+:102A5000307F000413E0000F0000000010A0000D04
+:102A600000000000960E0002240AFF8000A76021EB
+:102A700025CDFFFEA74D1016920B0004014B20241C
+:102A8000308200FF10400085010C40253C0F0400FF
+:102A9000010F40258F5301780660FFFE2404000AD1
+:102AA000A7440140960D00022404000931AC000740
+:102AB000000C5823316A0007A74A0142960200021F
+:102AC0002443FFFEA7430144A7400146975F01044A
+:102AD000A75F01488F5901083338002053000001D7
+:102AE00024040001920F000431EE001015C0000212
+:102AF0003483001000801821A743014A0000000021
+:102B0000000000000000000000000000AF481000BE
+:102B100000000000000000000000000000000000B5
+:102B20008F5110000621FFFE3113FFFF12600003DA
+:102B3000000000008F481018ACC800009603000683
+:102B4000307FFFFF27F90002001998820013888068
+:102B5000023B30218CD800001520005700183402A9
+:102B6000920300042405FF8000A3F82433F100FF42
+:102B70001220002C00000000924700BC30F200023E
+:102B80001240002800000000974B100C2562FFFE49
+:102B9000A7421016000000003C0A0400354900302E
+:102BA000AF4910000000000000000000000000001D
+:102BB000000000008F4C10000581FFFE00000000A7
+:102BC0009749100C8F51101C00C020213127FFFFA6
+:102BD00024F20030001218820003288000BBF82184
+:102BE0003226FFFFAFF100000E0005B300112C02EA
+:102BF0000013C880033B98218E7800000002740007
+:102C0000AFB800108FA80010310FFFFFAFAF00105A
+:102C10008FA4001001C46825AFAD00108FA600106E
+:102C2000AE66000097730008976D000A9766000C67
+:102C30008F8A003C000D5C0030CCFFFF3262FFFF4A
+:102C4000104A0036016C2025960600023C10100048
+:102C500024D300080E00013B3264FFFF974C0104AF
+:102C60000E0001493184FFFFAF5001788FBF00286B
+:102C70008FB300248FB200208FB1001C8FB00018DA
+:102C800003E0000827BD003010A0FF700000000026
+:102C900024A5FFFC0A0005EC240900048CD10000E7
+:102CA000AF5110188F5301780660FF7A2404000A90
+:102CB0000A0006010000000000A7C8218F88003824
+:102CC0008F4E101C0019C0820018788001E8202166
+:102CD000AC8E0000000E2C0200C020210E0005B3B7
+:102CE00031C6FFFF023B28218CAD000000025400DA
+:102CF00000403021AFAD00108FAC0010318BFFFFD2
+:102D0000AFAB00108FA2001001424825AFA9001000
+:102D10008FA700100A000631ACA700008F8F00407B
+:102D2000148FFFC90000000097420104960B0002B7
+:102D30003C0508008CA5046C3049FFFF316AFFFF99
+:102D40003C1108008E310468012A382124F2FFFE6C
+:102D500000B240210012FFC30112C82B023FC02164
+:102D6000031920213C010800AC28046C3C01080038
+:102D7000AC2404680A00066B0000000000A4102BBD
+:102D800010400009240300010005284000A4102B76
+:102D900004A00003000318405440FFFC0005284035
+:102DA00010600007000000000085302B14C00002F6
+:102DB00000031842008520231460FFFB0005284211
+:102DC00003E00008008010218F85002C27BDFFE85C
+:102DD000000530272CC300012CA40002008310251D
+:102DE00010400003AFBF00102405007FAF85002C0A
+:102DF0000005282730A5FFFF0E000592240426F5C4
+:102E00008F830030240402BD004030210083382B22
+:102E100010E0000924050001000420400083102B6D
+:102E200004800003000528405440FFFC00042040BB
+:102E300010A0000800C350210064402B15000002C0
+:102E4000000528420064182314A0FFFB0004204260
+:102E500000C350218FBF0010000A4C02312200FF36
+:102E600027BD0018AF8A002C03E00008AF890030AE
+:102E70000A00002A00000000000000000000000D11
+:102E8000747870362E302E313500000006000F00A9
+:102E900000000000000001360000EA6000000000B1
+:102EA0000000000000000000000000000000000022
+:102EB0000000000000000000000000000000000012
+:102EC0000000000000000000000000000000000002
+:102ED00000000016000000000000000000000000DC
+:102EE00000000000000000000000000000000000E2
+:102EF00000000000000000000000000000000000D2
+:102F00000000000000000000000013880000000026
+:102F1000000005DC000000000000000010000003BD
+:102F2000000000000000000D0000000D3C02080041
+:102F300024423C203C03080024633DD4AC40000004
+:102F40000043202B1480FFFD244200043C1D080098
+:102F500037BD7FFC03A0F0213C100800261000A81C
+:102F60003C1C0800279C3C200E0002BA0000000018
+:102F70000000000D8F8300383C088000350700708A
+:102F80008CE50000008330253C02900000C2202523
+:102F9000AF850030AF4400208F4900200520FFFEA0
+:102FA0003C038000346200708C4500008F86003046
+:102FB0003C1908008F39007C3C0E08008DCE00784B
+:102FC00000A6202303245821000078210164682BE7
+:102FD00001CF6021018D50213C010800AC2B007C09
+:102FE0003C010800AC2A007803E000080000000063
+:102FF0000A000041240400018F8400383C05800051
+:1030000034A200010082182503E00008AF4300202D
+:1030100003E00008000010213084FFFF30A5FFFF0F
+:1030200010800007000018213082000110400002CB
+:1030300000042042006518211480FFFB0005284091
+:1030400003E000080060102110C00007000000002D
+:103050008CA2000024C6FFFF24A50004AC8200005F
+:1030600014C0FFFB2484000403E0000800000000FB
+:1030700010A0000824A3FFFFAC86000000000000A1
+:10308000000000002402FFFF2463FFFF1462FFFA28
+:103090002484000403E0000800000000308AFFFFE1
+:1030A00093A80013A74A014497490E1630C600FFA3
+:1030B0003C021000A7490146AF450148A346015212
+:1030C000A748015AAF4701608FA400188FA30014CE
+:1030D000A7440158AF43015403E00008AF42017810
+:1030E00003E00008000000003C0380003462007030
+:1030F0008C4900008F8800002484000727BDFFF85A
+:103100003084FFF8AF890030974D008A31ACFFFF63
+:10311000AFAC00008FAB0000016850232547FFFFD4
+:1031200030E61FFF00C4282B14A0FFF73C0C8000E2
+:10313000358B00708D6A00003C0708008CE7008426
+:103140003C0608008CC60080000810820149182344
+:103150000002788000E370210000202101C3C82B09
+:1031600000C4C02101FA4021031948212502400072
+:1031700027BD00083C010800AC2E00843C0108007B
+:10318000AC29008003E00008000000008F820000EE
+:103190002486000730C5FFF800A2182130641FFF05
+:1031A00003E00008AF8400008F8700388F8A00405A
+:1031B00027BDFFB88F860044AFB60040AFBF0044C4
+:1031C000AFB5003CAFB40038AFB30034AFB200309D
+:1031D000AFB1002CAFB000288F4501048D4900AC81
+:1031E000AF4700808CC8002000A938230000B02120
+:1031F000AF480E108F440E1000004821AF440E144B
+:103200008CC20024AF420E188F430E18AF430E1C21
+:1032100010E001252D230001936B0008116000D4FC
+:1032200000000000976E001031CDFFFF00ED602B15
+:10323000158000CF0000000097700010320FFFFFD4
+:10324000AF4F0E008F520000325100081220FFFDD8
+:103250000000000097540E088F460E043285FFFFD1
+:1032600030B3000112600132000000000000000DC8
+:1032700030B8A04024150040131500C030A9A000AC
+:103280001120012D00000000937F000813E00008CA
+:103290000000000097630010306BFFFF00CB402B55
+:1032A0001100000330AC0040118001230000000039
+:1032B000A785003CAF8600349366000800E0282113
+:1032C000AFA7002014C0012427B30020AF60000C7A
+:1032D0009782003C3047400014E0000224030016AF
+:1032E0002403000E24194007A363000AAF790014D9
+:1032F000938A003E8F740014315800070018AA40CA
+:1033000002959025AF7200149784003C8F700014D2
+:103310003091001002117825AF6F0014978E003C99
+:1033200031CD000811A00147000028218F6700144B
+:103330003C0210003C0C810000E22825AF6500141F
+:1033400097460E0A2408000E3405FFFC30C3FFFF29
+:10335000006C5825AF6B0004A3680002937F000A3D
+:1033600027E90004A369000A9786003C9363000ADA
+:1033700030CC1F00000C598301634021251F002819
+:10338000A37F000997490E0CA769001093790009E3
+:10339000272A0002315800070018A82332B100077D
+:1033A000A371000B93740009976400108F9100348F
+:1033B000978F003C329200FF024480210205702169
+:1033C00031ED004011A0000531C4FFFF0091282B12
+:1033D0003C12800010A000140000A0210224382B11
+:1033E00014E0011B8FA500208F4D0E14AF4D0E1061
+:1033F0008F420E1CAF420E18AF440E008F4F0000DC
+:1034000031EE000811C0FFFD0000000097540E08C7
+:103410000080882100009021A794003C8F500E046A
+:1034200024140001AF900034976400103095FFFF22
+:103430008E6800000111F82317E00009AE7F00003C
+:103440008F6500148F8B004434A60040AF660014D3
+:103450008F4C0E10AD6C00208F430E18AD6300240E
+:103460009367000814E000D2000000000E00009EE8
+:10347000240400108F8900483C08320000402821B5
+:10348000312600FF0006FC0003E850252539000125
+:10349000AF990048AC4A0000937800099370000A85
+:1034A000330400FF00047400320F00FF01CF6825D1
+:1034B000AC4D00048F820048064000EAACA2000830
+:1034C000ACA0000C9783003C306B00081560000234
+:1034D0002628000626280002974E0E148F450E1C43
+:1034E0008F670004936D000231C4FFFF31A200FF1B
+:1034F000AFA200108F6C0014AFA800180E00008B54
+:10350000AFAC0014240400100E0000C7000000003F
+:103510008E72000016400005000000008F64001449
+:103520002405FFBF00859824AF7300148F79000C29
+:1035300003353821AF67000C9375000816A000080A
+:103540000000000012800006000000008F7F0014C1
+:103550003C0BEFFF3568FFFE03E84824AF69001419
+:10356000A37400088FA500200A0002460220202133
+:10357000AF470E000A0000F5000000008F590178E7
+:103580000720FFFE241F08008F840000AF5F017832
+:10359000974B008A316AFFFF014448232528FFFF2B
+:1035A00031021FFF2C4300081460FFF900000000E7
+:1035B0008F8E00488F8D003800C0482103442021A1
+:1035C00025C60001240C0F00AF86004800E938230F
+:1035D0002486400031CA00FF11AC00052408000118
+:1035E0009391003E3230000700107A4035E8000128
+:1035F000000AAC003C18010002B8A025AC944000C1
+:103600008F93004830B2003630A40008ACD30004D9
+:103610001080009701123025974E0E0A8F8D000002
+:103620003C02810031CCFFFF25AB00080182402520
+:103630003C03100031651FFF25390006241F000ED2
+:10364000AF48016000C33025A75F015AAF85000075
+:10365000A759015814E0000A8F93003824120F0074
+:10366000527200022416000134C600408F580E101A
+:103670008F940044AE9800208F550E18AE9500240C
+:103680008F450E14AF4501448F590E1CAF590148A8
+:10369000A34A01523C0A1000AF460154AF4A0178D8
+:1036A00014E0FEDD2D2300010076A0251280001716
+:1036B0008FBF00448F84003824160F0010960084BA
+:1036C000000000008F45017804A0FFFE24150F00C4
+:1036D0001095006E000000008F470E142402024077
+:1036E0003C1F1000AF4701448F440E1CAF440148FB
+:1036F000A3400152A740015AAF400160A7400158C2
+:10370000AF420154AF5F01788FBF00448FB60040D5
+:103710008FB5003C8FB400388FB300348FB20030C7
+:103720008FB1002C8FB0002803E0000827BD0048AF
+:1037300014C0FED030B8A0408F420E148F840044D5
+:1037400000004821AC8200208F510E1CAC91002457
+:103750000A00020E2D2300018F910034978A003C4D
+:103760003C1280000220A821315800401700FF3091
+:103770000000A021976900108F9200343139FFFFBB
+:103780001332003500002021008048211480FEA063
+:1037900000A038218F420E148F840044AC82002098
+:1037A0008F510E1CAC9100240A00020E2D23000143
+:1037B000936A00099378000B315000FF330F00FF2C
+:1037C000020F702125C2000A3050FFFF0E00009E3C
+:1037D000020020218F8600483C1F410024CD0001BB
+:1037E000AF8D0048936C000930C600FF000644000E
+:1037F000318300FF246B0002010B4825013FC825DF
+:10380000AC5900008F67000C97440E1400F2282575
+:10381000AC4500048F450E1C8F670004936A0002BC
+:103820003084FFFF315800FFAFB800108F6F0014D5
+:10383000AFB100180E00008BAFAF00140A0001A654
+:1038400002002021AF6000040A00013EA3600002D4
+:103850000A00024600002021000090210A000170A9
+:10386000241400013C1280000A000195ACB2000C47
+:103870008F91000025240002A7440158263000083B
+:10388000320F1FFF0A0001F9AF8F0000AF40014C5B
+:103890001120002C000000008F590E10AF59014478
+:1038A0008F430E18240200403C1F1000AF43014814
+:1038B000A3400152A740015AAF400160A740015800
+:1038C000AF420154AF5F01780A0002278FBF004466
+:1038D000112000060000000097460E0830CC004082
+:1038E00015800002000000000000000D8F4D0178DF
+:1038F00005A0FFFE0000000097530E103C120500CB
+:10390000240E2000326AFFFF0152C025AF58014C3F
+:103910008F4F0E143C021000AF4F01448F500E1C0D
+:10392000AF500148A34001528F840038A740015A8C
+:10393000AF400160A7400158AF4E01540A00021584
+:10394000AF4201788F490E14AF4901448F430E1CDA
+:103950000A00028E240200403C0E20FF27BDFFE03B
+:103960003C1A80003C0F800835CDFFFDAFBF001C26
+:10397000AFB20018AFB10014AFB00010AF8F00406D
+:10398000AF4D0E000000000000000000000000002D
+:1039900000000000000000003C0C00FF358BFFFD24
+:1039A000AF4B0E003C0660048CC95000240AFF7F18
+:1039B0003C116000012A40243507380CACC7500088
+:1039C0008E24043824050009AF4500083083FFFF2A
+:1039D00038622F712450C0B3AF8000480E000068D9
+:1039E000AF80000052000001AE20442C0E000435D0
+:1039F0003C1180000E000ED9363000708F8A0040D6
+:103A00003C12080026523C88020088218E080000E3
+:103A10008F5F00003BF900013338000113000017ED
+:103A2000AF880030022048218D2700003C0F08009D
+:103A30008DEF006C3C0C08008D8C006800E8C02302
+:103A400001F828210000682100B8302B018D582191
+:103A5000016640213C010800AC25006C3C010800D7
+:103A6000AC2800688F4400003883000130620001F8
+:103A70001440FFED00E04021AF8700308E0C0000C5
+:103A80003C0508008CA5006C3C0408008C84006890
+:103A90000188302300A638210000102100E6402BC9
+:103AA000008218210068F8213C010800AC27006C56
+:103AB0003C010800AC3F00688F490100255900888F
+:103AC000AF990044AF890038AF4900208E0700004D
+:103AD000AF8700308F4D017805A0FFFE0000000089
+:103AE0008E0600003C0B08008D6B00743C0408003F
+:103AF0008C84007000C728230165F8210000102184
+:103B000003E5402B0082382100E8C8212409080081
+:103B10003C010800AC3F00743C010800AC39007067
+:103B2000AF49017893580108A398003E938F003E57
+:103B300031EE000115C000158F830038240E0D00F2
+:103B4000106E0019240F0F00106F001D0000000000
+:103B50009159000024180050332900FF1138000447
+:103B60003C1F4000AF5F01380A0002E70000000080
+:103B70000E00090E000000008F8A00403C1F40002C
+:103B8000AF5F01380A0002E700000000938D003E9D
+:103B900031AC0006000C51000E0000CE0152D821BD
+:103BA0000A0003438F8A00403C1B0800277B3D0826
+:103BB0000E0000CE000000000A0003438F8A004080
+:103BC0003C1B0800277B3D280E0000CE00000000B3
+:103BD0000A0003438F8A004090AA00018FAB0010B7
+:103BE0008CAC00103C0300FF8D680004AD6C00201D
+:103BF0008CAD001400E060213462FFFFAD6D002445
+:103C00008CA700183C09FF000109C024AD670028FB
+:103C10008CAE001C0182C82403197825AD6F000406
+:103C2000AD6E002C8CAD0008314A00FFAD6D001C5C
+:103C300094A900023128FFFFAD68001090A7000092
+:103C4000A5600002A1600004A167000090A300022B
+:103C5000306200FF00021982106000052405000197
+:103C60001065000E0000000003E00008A16A0001DA
+:103C70008CD80028354A0080AD7800188CCF00140D
+:103C8000AD6F00148CCE0030AD6E00088CC4002CDB
+:103C9000A16A000103E00008AD64000C8CCD001C9B
+:103CA000AD6D00188CC90014AD6900148CC80024D7
+:103CB000AD6800088CC70020AD67000C8CC20014F2
+:103CC0008C8300640043C82B132000070000000011
+:103CD0008CC20014144CFFE400000000354A008040
+:103CE00003E00008A16A00018C8200640A000399C5
+:103CF0000000000090AA000027BDFFF88FA9001C5B
+:103D0000A3AA00008FAE00003C0FFF808FA8001810
+:103D100035E2FFFF8CCD002C01C26024AFAC000067
+:103D2000A120000400E06021A7A000028FB80000DD
+:103D30008D2700040188182100A0582100C05021BF
+:103D4000006D28263C06FF7F3C0F00FF2CAD0001D4
+:103D500035EEFFFF34D9FFFF3C02FF00031930248A
+:103D6000000D1DC0010EC82400E2C02400C3702550
+:103D700003197825AD2E0000AD2F00048D450024D9
+:103D8000AFAE0000AD2500088D4D00202405FFFFDB
+:103D9000AD2D000C956800023107FFFFAD27001024
+:103DA0009166001830C200FF000219C25060000185
+:103DB0008D450034AD2500148D67000827BD00082F
+:103DC000AD27001C8C8B00CCAD2C0028AD20002C26
+:103DD000AD2B0024AD20001803E00008AD2000202A
+:103DE00027BDFFE0AFB20018AFB10014AFB00010B4
+:103DF000AFBF001C9098000000C088213C0D00FF60
+:103E0000330F007FA0CF0000908E000135ACFFFF84
+:103E10003C0AFF00A0CE000194A6001EA2200004D0
+:103E20008CAB00148E29000400A08021016C282492
+:103E3000012A40240080902101052025A6260002A9
+:103E4000AE24000426050020262400080E0000767B
+:103E500024060002924700002605002826240014AC
+:103E600000071E000003160324060004044000039C
+:103E70002403FFFF965900023323FFFF0E00007654
+:103E8000AE230010262400248FBF001C8FB2001820
+:103E90008FB100148FB00010240500030000302102
+:103EA0000A00008027BD002027BDFFD8AFB1001C4D
+:103EB000AFB00018AFBF002090A80000240200019E
+:103EC0008FB0003C3103003F008088211062001455
+:103ED0008FAA0038240B0005506B0016AFAA001003
+:103EE00000A0202100C028210E0003DC02003021A8
+:103EF000922400BC308300021060000326060030CC
+:103F0000ACC0000024C600048FBF00208FB1001C8D
+:103F10008FB0001800C0102103E0000827BD002862
+:103F2000014038210E00035AAFB000100A000420EF
+:103F3000000000000E0003A1AFB000140A0004202E
+:103F4000000000003C02000A034218213C04080063
+:103F500024843D6C2405001A000030210A000080F2
+:103F6000AF8300543C038000346200708C48000032
+:103F700000A0582100C04821308A00FFAF880030DF
+:103F80008F4401780480FFFE3C0C80003586007071
+:103F90008CC500003C0308008C6300743C180800CA
+:103FA0008F18007000A82023006468210000C82139
+:103FB00001A4782B0319702101CF60213C01080076
+:103FC000AC2D00743C010800AC2C00708F480E141E
+:103FD000AF480144AF47014CA34A0152A74B0158D7
+:103FE0009346010830C5000854A00001352910008F
+:103FF000934B090024070050316A00FF1147000766
+:10400000000000008F450E1CAF450148AF49015428
+:104010003C09100003E00008AF490178934D010806
+:1040200031A800081100001000000000934F0108A3
+:1040300031EE001051C00001352900083C04080091
+:1040400090843DD0A34401508F4309A4AF4301485D
+:104050008F4209A0AF420144AF4901543C0910000E
+:1040600003E00008AF4901783C1908008F393D8C06
+:10407000333800085700FFF1352900080A0004739F
+:104080000000000024070040AF470814AF400810AC
+:104090008F4209448F4309508F4409548F45095C6E
+:1040A0008F46094CAF820064AF830050AF84004C50
+:1040B000AF85005C03E00008AF860060934601090D
+:1040C00030C5007F000518C0000521400083102185
+:1040D00003E00008244200883C09080091293D9132
+:1040E00024A800023C05110000093C0000E830252E
+:1040F00000C5182524820008AC83000003E00008F6
+:10410000AC8000049347010B8F4A002C974F09089D
+:104110003C18000E0358482131EEFFFF000E41C04D
+:10412000AF48002C97430908952C001A00804021C5
+:1041300024030001318BFFFFAC8B00008D2D001C90
+:1041400000A0582100C06021AC8D00048D24002007
+:1041500030E70040AD04000891220019304400030C
+:10416000108300482885000214A000622406000283
+:104170001086005624190003109900660000000004
+:1041800010E0003A000000003C07080094E73D867C
+:1041900024E20001934F0934934709219525002A11
+:1041A00031EE00FF000E488230ED00FF9787005887
+:1041B00000093600000D1C003044FFFF00C310252D
+:1041C0000044C02500A778213C1940000319702540
+:1041D000000F4C00AD090004AD0E0000934D092006
+:1041E0003C03000625090014000D360000C32025FD
+:1041F000AD0400088F59092C24E5000130A27FFF8F
+:10420000AD19000C8F580930A782005825020028EC
+:10421000AD1800108F4F0938AD0F0014AD2B0004FE
+:104220008F4E0940AD2E0008934D09373C0508001C
+:1042300090A53D908F4409488F46094031A700FF63
+:1042400000EC1821008678230003C7000005CC008D
+:104250000319602531E8FFFC01885825AD2B000CBF
+:10426000AD20001003E00008AF4A002C3C0D080010
+:1042700095AD3D863C0E080095CE3D800A0004C9F0
+:1042800001AE10213C05080094A53D8A3C060800BB
+:1042900094C63D803C18080097183D7C952E00245C
+:1042A00000A6782101F86823000E240025A2FFF261
+:1042B0000082182524190800AD03000CAD19001464
+:1042C000AD0000100A0004C425080018952600243B
+:1042D000952500280006C40000057C00370E8100EB
+:1042E00035ED0800AD0E000CAD0D00100A0004C441
+:1042F000250800141480FFA200000000952400246B
+:104300000004140034430800AD03000C0A0004C488
+:10431000250800103C03080094633D8A3C05080012
+:1043200094A53D803C06080094C63D7C9539002448
+:1043300095380028006520210086782300196C003C
+:104340000018740025E2FFEE01C2202535A381008C
+:1043500024190800AD03000CAD040010AD190018BD
+:10436000AD0000140A0004C42508001C03E0000886
+:10437000240201F427BDFFE8AFB00010AFBF001466
+:104380000E0000600080802124050040AF45081425
+:104390008F8300508F84004C8F85005C0070182143
+:1043A0000064102318400004AF830050AF63005432
+:1043B0008F660054AF86004C1200000C0000000015
+:1043C0008F440074936800813409FA002D070007B8
+:1043D00010E0000500891021936C0081240B01F48A
+:1043E000018B500401441021AF62000C8F4E095C18
+:1043F00001C5682319A000048FBF00148F4F095C0A
+:10440000AF8F005C8FBF00148FB000100A000062F5
+:1044100027BD00188F8400648F8300508F82004C6A
+:10442000AF640044AF63005003E00008AF62005483
+:104430003C038000346200708C43000027BDFFF80D
+:10444000308700FF30A900FF30C800FFAF83003085
+:104450008F4401780480FFFE3C02800034590070D4
+:104460008F380000A3A700033C0708008CE7007406
+:104470008FAC00003C0608008CC600700303782354
+:104480003C0E7FFF00EFC82135CDFFFF000050211B
+:10449000018D282400CA1821000847C0032F202BB3
+:1044A00000A810250064C021AFA200003C01080054
+:1044B000AC3900743C010800AC380070934F010A1D
+:1044C000A3A000023C0E80FFA3AF00018FAC000050
+:1044D000312B007F35CDFFFF018D4824000B5600A6
+:1044E000012A4025240730002406FF803C051000E7
+:1044F00027BD0008AF48014CAF470154A740015801
+:10450000A346015203E00008AF45017827BDFFE84C
+:10451000AFBF0014AFB000108F6500743C06800080
+:10452000309000FF00A620250E000060AF640074EC
+:1045300093630005346200080E000062A362000568
+:10454000020020218FBF00148FB000102405000549
+:10455000240600010A00057027BD001827BDFFE0F2
+:104560003C038000AFB00010AFBF0018AFB1001423
+:10457000346200708C470000309000FF30A800FFCC
+:10458000AF8700308F4401780480FFFE3C18800024
+:10459000371100708E2F00003C0D08008DAD0074A7
+:1045A0003C0A08008D4A007001E7702301AE282103
+:1045B0000000582100AE302B014B48210126382144
+:1045C0003C010800AC250074000088213C01080073
+:1045D000AC2700701100000F000000008F62007413
+:1045E0002619FFFF3208007F0002FE0233E5007F3C
+:1045F00015000006332200FF2407FF800207202653
+:1046000024A3FFFF00838025320200FF00408021A9
+:10461000241110080E000060000000008F490818E7
+:104620003125000414A0FFFD3218007F001878C067
+:104630000018714001CF682125AC0088AF4C0818E4
+:10464000274A09808D4B0020AF4B01448D46002442
+:10465000AF460148A35001500E000062A740015828
+:10466000022010218FBF00188FB100148FB00010EE
+:1046700003E0000827BD002027BDFFE8308400FFCD
+:10468000AFBF00100E0005BB30A500FF8F830050A8
+:104690008FBF0010344500402404FF903C021000FE
+:1046A00027BD0018AF43014CA3440152AF4501544C
+:1046B00003E00008AF4201789343093E30620008EE
+:1046C0001040000D3C0901013528080AAC880000A3
+:1046D0008F470074AC8700043C06080090C63D90EC
+:1046E00030C5001050A00006AC8000088F6A006042
+:1046F000AC8A00082484000C03E00008008010212C
+:104700000A0006222484000C27BDFFE8AFBF001476
+:10471000AFB000109346093F00A05021000528804B
+:104720000085382330C200FF240300063C0908003E
+:1047300095293D8624E8FFD824050004104300375E
+:10474000240600029750093C3C0F02040006340086
+:10475000320EFFFF01CF6825AC8D0000934C093E5F
+:10476000318B0020116000080000000093430936DF
+:104770003C020103345F0300307900FF033FC02592
+:1047800024050008AC980004934309349359092187
+:104790000005F882306200FF0002C082332F00FF64
+:1047A00000186E00000F740001AE602501892025FD
+:1047B0003C09400000898025ACF0FFD893430937BD
+:1047C0008F4F09488F580940306200FF004AC821C6
+:1047D000033F702101F86023000E6F0001A65025F1
+:1047E0003185FFFC001F58800145482501683821AC
+:1047F000AD0900200E00006024F00028240400040D
+:104800000E000062A364003F020010218FBF00145D
+:104810008FB0001003E0000827BD00180A0006351D
+:104820002406001227BDFFD024090010AFB60028CF
+:10483000AFB50024AFB40020AFB10014AFB000108A
+:104840003C010800A0293D90AFBF002CAFB3001C75
+:10485000AFB2001897480908309400FF3C02000EE0
+:104860003107FFFF000731C0AF46002C974409080D
+:104870009344010B30B500FF0342802130830030A8
+:104880000000B0211060012500008821240C0004E4
+:104890003C010800A02C3D90934B093E000B5600B4
+:1048A000000A2E0304A0016000000000AF40004891
+:1048B000934F010B31EE002011C0000600000000F4
+:1048C0009358093E00189E00001396030640018984
+:1048D000000000009344010B30830040106000038F
+:1048E0008F9300508F8200502453FFFF9347093E5F
+:1048F00030E6000814C000022412000300009021DA
+:104900009619002C93580934934F0937A7990058EA
+:10491000330C00FF31EE00FF024E6821000D58807D
+:10492000016C5021015140213C010800A4283D8622
+:104930009205001830A900FF010918213C01080068
+:10494000A4233D88921100181620000200000000E8
+:104950000000000D3C010800A4233D8A3C01080032
+:10496000A4203D803C010800A4203D7C935F010B06
+:104970003063FFFF33F00040120000022464000A9D
+:104980002464000B3091FFFF0E00009E02202021C6
+:104990009358010B3C08080095083D8A00402021EF
+:1049A00000185982316700010E00049A010728217E
+:1049B000934C010B8F4B002C974E09083C0F000EB7
+:1049C000034F402131CDFFFF000D51C0AF4A002CF5
+:1049D000974309089505001A004038212404000176
+:1049E00030A9FFFFAC4900008D06001C00404821A3
+:1049F000318A0040AC4600048D020020ACE2000881
+:104A00009103001930630003106400EC2879000260
+:104A100017200118241000021070010C241F00033D
+:104A2000107F011E00000000114000DE00000000A9
+:104A30003C09080095293D8625220001935F093431
+:104A4000934E09219504002A33F900FF0019C08212
+:104A500031CF00FF978E005800184600000F6C0001
+:104A6000010D80253045FFFF02051025008E5021E5
+:104A70003C03400000433025000A6400ACEC000415
+:104A8000ACE60000935F09203C19000624EC0014FA
+:104A9000001FC60003197825ACEF00088F48092CC9
+:104AA00025CD000131A57FFFACE8000C8F50093007
+:104AB000A785005824E80028ACF000108F4409387E
+:104AC00001008021ACE40014AD9300048F53094031
+:104AD000AD930008934A09373C19080093393D907B
+:104AE0008F4309488F460940314200FF0052F821A8
+:104AF00000667023001F7F000019C40001F82825FC
+:104B000031CDFFFC00AD2025AD84000CAD80001040
+:104B1000AF4B002C934B093E317300081260000D1F
+:104B20003C06010134CC080AACEC00288F53007419
+:104B3000AD1300043C0B0800916B3D9031670010F1
+:104B400050E00003AD0000088F6A0060AD0A000865
+:104B50002510000C12C0003D000000009343093FE7
+:104B60002416000624060004306200FF105600C917
+:104B7000240700029758093C3C0F0204330DFFFF45
+:104B800001AF4025AE0800009345093E30A4002047
+:104B90001080000800000000935309363C0B01030D
+:104BA000357F0300327900FF033F7025AE0E00040D
+:104BB00024060008934F093493480921312AFFFF46
+:104BC00031ED00FF000D1082310300FF0002B6003E
+:104BD00000032C0002C56025018A98250012208060
+:104BE0003C0940000204502302695825AD4BFFD810
+:104BF000935F09378F4F09488F58094033F900FFF9
+:104C0000033270210006B08201D6682100074400FB
+:104C100001F82823000D1F000068302530A2FFFC9A
+:104C20002547FFD800C26025001680800207482172
+:104C3000ACEC0020253000280E0000602412000497
+:104C4000A372003F0E000062000000009347010BBA
+:104C500030F20040124000053C1900FF8E180000A1
+:104C6000372EFFFF030E3024AE0600000E0000C7F3
+:104C7000022020213C10080092103D9032110003C8
+:104C80001220000F02A028218F8900502533000137
+:104C9000AF930050AF7300508F6B00540173F82333
+:104CA0001BE00002026020218F640054AF640054B6
+:104CB0008F4C0074258401F4AF64000C02A02821FD
+:104CC00002802021A76000680E0005BB3C14100084
+:104CD0008F85005034550006AF45014C8F8A00483F
+:104CE0008FBF002C8FB3001C25560001AF960048E3
+:104CF0008FB20018A34A01528FB60028AF55015455
+:104D00008FB10014AF5401788FB500248FB4002008
+:104D10008FB0001003E0000827BD00309358093E13
+:104D200000189E000013960306420036241100026C
+:104D300093440923308300021060FEDD8F860060FB
+:104D40008F82005014C2FEDA000000000E000060E6
+:104D5000000000009369003F24070016312800FF7F
+:104D60001107000C240500083C0C0800918C3D90B4
+:104D7000358B00013C010800A02B3D90936A003F59
+:104D8000314300FF10650065240D000A106D005EC0
+:104D90002402000C0E000062000000000A000690D1
+:104DA000000000003C09080095293D863C0A0800E7
+:104DB000954A3D800A0006F3012A10213C090800AB
+:104DC00095293D8A3C04080094843D803C060800F7
+:104DD00094C63D7C95030024012410210046F8234D
+:104DE0000003CC0027F0FFF20330C025240F080099
+:104DF000ACF8000CACEF0014ACE000100A0006EEBA
+:104E000024E700183C010800A0313D90935F093E63
+:104E10002416000133F900201720FEA524110008F4
+:104E20000A000690241100048F6E00848F4D094003
+:104E300011A0FE9EAF8E0050240F00143C0108000C
+:104E4000A02F3D900A00068F00000000950E002460
+:104E5000950D0028000E6400000D2C00358981009E
+:104E600034A60800ACE9000CACE600100A0006EE1F
+:104E700024E700141460FEEC0000000095020024FA
+:104E800000021C0034640800ACE4000C0A0006EECA
+:104E900024E700100A000741240700123C02080022
+:104EA00094423D8A3C06080094C63D803C030800BD
+:104EB00094633D7C95100024951900280046F82144
+:104EC00003E3C02300106C0000197400270FFFEEED
+:104ED00001CF282535AC8100ACEC000CACE500100E
+:104EE00024070800AD2700182527001C0A0006EE3D
+:104EF000AD2000148F7F004CAF7F00548F79005499
+:104F00000A000699AF790050A362003F0E000062CC
+:104F1000000000000A0006900000000024020014B7
+:104F20000A000827A362003F27BDFFE8308400FF86
+:104F3000AFBF00100E0005BB30A500FF9378007EC8
+:104F40009379007F936E00809368007A332F00FF7F
+:104F500000186600000F6C0031CB00FF018D482562
+:104F6000000B52008FBF0010012A3825310600FFC8
+:104F70003444700000E628252402FF813C03100021
+:104F800027BD0018AF45014CAF440154A342015264
+:104F900003E00008AF43017827BDFFD8AFB2001887
+:104FA000AFB10014AFB00010AFBF0020AFB3001C12
+:104FB00093420109308600FF30B000FF000618C29E
+:104FC000320400023071000114800005305200FFED
+:104FD0009367000530E5000810A0000D30C80010F0
+:104FE000024020210E0005A70220282124040001F0
+:104FF0008FBF00208FB3001C8FB200188FB1001438
+:105000008FB000100080102103E0000827BD0028A9
+:105010001500003200000000934301090000282120
+:105020003062007F000220C00002F94003E49821B2
+:1050300026790088033B98218E7800248E6F000823
+:10504000130F0046000000008F6400842418000243
+:105050000004FD8233F900031338007C00000000D7
+:1050600093660083934A0109514600043205007C8F
+:1050700010A00060000000003205007C14A0005366
+:105080000240202116200006320400018E7F0024F9
+:105090008F59010417F9FFD60000202132040001C6
+:1050A0001080000A024020218F4209408F93006443
+:1050B00010530006000000000E00066D022028219B
+:1050C0008F430940AF630044024020210E000602D6
+:1050D000022028210A000860240400013C0908007D
+:1050E0008D290064252600013C010800AC260064DF
+:1050F00016000012000000008F6D00843C0E00C0FE
+:1051000001AE602415800005024020210E00082E0B
+:10511000022028210A00086024040001240500045C
+:105120000E00057024060001024020210E00082E0A
+:10513000022028210A000860240400010E0000411A
+:1051400024040001936B007D020B50250E000062C9
+:10515000A36A007D0A0008A38F6D00848F66007427
+:105160008F4801048E67002400064E021507FFB623
+:105170003126007F936B008326440001308A007F34
+:1051800011460043316300FF5464FFB08F64008414
+:105190002645000130B1007F30A200FF1226000436
+:1051A00024050001004090210A0008762411000126
+:1051B000240FFF80024F702401CF9026324200FF5F
+:1051C000004090210A000876241100010E00066DAF
+:1051D00002202821321800301300FFAA321000826A
+:1051E000024020210E0005A7022028210A000860A5
+:1051F000240400018F6E00743C0F8000240500031E
+:1052000001CF9025AF7200749371008324060001D2
+:105210000E000570322400FF0E000041240400013E
+:10522000936D007D020D60250E000062A36C007D71
+:105230003C0B08008D6B0054257000013C010800F8
+:10524000AC3000540A000860240400018F68007428
+:105250003C0980002405000401093825AF6700746B
+:1052600093630083240600010E000570306400FF84
+:105270000E000041240400019362007D0202982583
+:105280000E000062A373007D0A0008602404000180
+:10529000324D008039AC0080546CFF6C8F64008408
+:1052A0000A0008C92645000127BDFFC83C0A0008BE
+:1052B000AFBF0030AFB5002CAFB40028AFB30024AF
+:1052C000AFB20020AFB1001CAFB00018034AD82124
+:1052D00024090040AF490814AF4008108F42094428
+:1052E0008F4309508F4609548F47095C8F48094CFA
+:1052F000934401089345010BAF820064308400FFA2
+:1053000030A500FFAF830050AF86004CAF87005C34
+:105310000E00084AAF8800601440017D8FBF003046
+:10532000A7600068934D0900240B00503C1508004D
+:1053300026B53D4831AC00FF3C12080026523D58CE
+:10534000118B0003000000000000A8210000902144
+:10535000935101098F9F005024040010322E007FCA
+:10536000000E68C0000E6140018D282124B4008821
+:10537000AF5408188F4901048F4A09A43C0B000E52
+:10538000034BC021012A10233C010800AC223D6CD4
+:105390008F4309583C010800A0243D909747090815
+:1053A000007F30233C010800AC263D7030E8FFFF51
+:1053B0000008C9C03C010800AC3F3D94AF59002C27
+:1053C000974209089710002C8EB10000930F001827
+:1053D00003749821A7900058AF9300440220F80965
+:1053E00031F000FF304E000215C001B2304F000115
+:1053F00011E0014F000000009343093E30660008B1
+:1054000014C00002241400030000A0218F5809A436
+:10541000241300013C010800AC383D98934F093437
+:105420009351093731EC00FF322E00FF028E6821C4
+:10543000000D288000AC5021015058213C0108008B
+:10544000A42B3D883C010800A42A3D8693490934D9
+:10545000312200FF02022021249000103C010800AC
+:10546000A4303D84240700068F9F00503C010800B3
+:10547000AC273D8C8F88005C8F5909580000802133
+:10548000011F282304A00149033F20230480014772
+:1054900000A4302B10C00149000000003C010800AE
+:1054A000AC253D708E4200000040F809000000006D
+:1054B00030430002146000F80040882130440001AD
+:1054C000548000108E4200043C0908008D293D7470
+:1054D0003C0AC000012A8025AF500E008F45000015
+:1054E00030AB00081160FFFD00000000974D0E0872
+:1054F00024100001A78D003C8F4C0E04AF8C0034AB
+:105500008E4200040040F8090000000002228825B5
+:10551000322E000215C00180000000003C09080086
+:1055200095293D7C3C06080094C63D883C0A08004D
+:10553000954A3D7E3C1908008F393D740126602153
+:105540003C1808008F183D983C03080094633D9276
+:10555000018A20218F4E09400329F821248F00025F
+:1055600003E32821031968213C010800A42C3D8A8B
+:10557000AF8E00643C010800AC2D3D983C01080052
+:10558000A4253D800E00009E31E4FFFF8F87004878
+:10559000004020213C010800A0273D918E420008D8
+:1055A00024E80001AF8800480040F809000000002E
+:1055B0009344010B8F4C002C974A09083C0B000EBA
+:1055C000034B40213149FFFF000919C08F8B005068
+:1055D000AF43002C974309089506001A0040382174
+:1055E000308A004030DFFFFFAC5F00008D19001CE7
+:1055F00000404821AC5900048D180020AC58000828
+:10560000910F001931E30003107300F00000000057
+:10561000286200021440010924050002106500FD03
+:10562000240D0003106D010D00000000114000D991
+:10563000000000003C0A0800954A3D862542000112
+:10564000934D093493580921950E002A31A300FF88
+:1056500000032082331F00FF9798005800047E004B
+:10566000001FCC0001F940253049FFFF010910253A
+:1056700001D830213C0540000045502500066C0053
+:10568000ACED0004ACEA0000934309203C040006A2
+:1056900024ED00140003FE0003E4C825ACF9000863
+:1056A0008F49092C270F000131EE7FFFACE9000C78
+:1056B0008F480930A78E005824E90028ACE8001074
+:1056C0008F45093801204021ACE50014ADAB000442
+:1056D0008F420940ADA20008934B09373C1F0800D8
+:1056E00093FF3D908F4309488F4A0940316600FF80
+:1056F00000D42021006A78230004C700001FCC00DA
+:105700000319282531EEFFFC00AE1025ADA2000CD8
+:10571000ADA00010AF4C002C934C093E318B00081B
+:105720005160000F8E58000C3C06010134CA080A73
+:10573000ACEA00288F4B0074AD2B00043C0C080031
+:10574000918C3D903187001050E00003AD2000089F
+:105750008F620060AD2200082528000C8E58000CD6
+:105760000300F809010020213C19080097393D8AFF
+:105770003C1F080097FF3D7E033F782125E900028A
+:105780000E0000C73124FFFF3C0E08008DCE3D6C9B
+:105790003C0808008D083D7401C828233C0108001E
+:1057A000AC253D6C14A00006000000003C0308007E
+:1057B0008C633D8C346400403C010800AC243D8C7B
+:1057C000120000708F8C00448F470E108F900044A1
+:1057D000AE0700208F4D0E18AE0D00243C100800BF
+:1057E00096103D800E000060000000002402004082
+:1057F000AF4208148F8600508F8A004C00D01821C9
+:10580000006A582319600004AF830050AF6300544E
+:105810008F650054AF85004C1200000C00000000A2
+:105820008F440074936800813409FA002D0E00073C
+:1058300011C0000500891821937F0081241901F40B
+:1058400003F9780401E41821AF63000C8F44095C6C
+:105850008F83005C0083C0231B0000030000000056
+:105860008F50095CAF90005C0E00006200000000E9
+:105870008F8C00508E4700103C010800AC2C3D94EA
+:1058800000E0F809000000003C0D08008DAD3D6C03
+:1058900055A0FEF5240700068F45002497590908F6
+:1058A0008F8B00648F9400503C0F001F978200582C
+:1058B0008F8600548F93004C3328FFFF35E9FF801B
+:1058C00000A95024000871C032320100AF4E0024FC
+:1058D000A4C2002CAF4A0024AF6B0044AF74005048
+:1058E000AF73005416400080323800105700008615
+:1058F0008EA40004322300405460001B8EB10008C7
+:105900008EB0000C0200F809000000008FBF0030CC
+:105910008FB5002C8FB400288FB300248FB20020E5
+:105920008FB1001C8FB0001803E0000827BD0038BD
+:10593000934701098F8800380007FE0003E8C82557
+:10594000AF5900808F5809A08F5309A4AFB8001039
+:10595000AF580E148FB40010AF540E10AF530E1C7E
+:105960000A000962AF530E180220F8090000000077
+:105970008EB0000C0200F809000000000A000AA81E
+:105980008FBF0030A5800020A59300220A000A5B8B
+:10599000AD9300243C09080095293D863C0608008B
+:1059A00094C63D800A0009F4012610213C0108003C
+:1059B000AC203D700A00098E8E4200003C010800B8
+:1059C000AC243D700A00098E8E4200003C030800A2
+:1059D00094633D8A3C04080094843D803C1F080089
+:1059E00097FF3D7C951800240064C821033F78236D
+:1059F00000186C0025EEFFF201AE2825AC45000C26
+:105A000024020800ACE20014ACE000100A0009EF28
+:105A100024E70018950600249509002800062400B4
+:105A200000091C00349F810034790800ACFF000C91
+:105A3000ACF900100A0009EF24E700141460FEFB23
+:105A4000000000009518002400187C0035EE0800C6
+:105A5000ACEE000C0A0009EF24E700103C07080038
+:105A600094E73D803C04080094843D8A3C03080090
+:105A700094633D7C95190024951800280087F8212F
+:105A800003E378232407080000192C0000186C0099
+:105A900025EEFFEE01AE302534A28100AD270018BF
+:105AA0002527001CAD22000CAD2600100A0009EFCE
+:105AB000AD20001493520109000028210E000602B7
+:105AC000324400FF8FBF00308FB5002C8FB4002808
+:105AD0008FB300248FB200208FB1001C8FB000184C
+:105AE00003E0000827BD0038935F010933E400FF9D
+:105AF0000E00066D00002821323800105300FF7E92
+:105B0000322300408EA400040080F8090000000049
+:105B10000A000AA2322300401200FF5F00000000CA
+:105B20008F540E148F920044AE5400208F530E1CDD
+:105B30000A000A8AAE5300248F82001C0080402194
+:105B40003C0401009047008530E30020106000090C
+:105B5000000000003C0708008CE73D948F8300188C
+:105B600000E32023048000089389000414E3000369
+:105B70000100202103E00008008010213C04010006
+:105B800003E00008008010211120000B006738237B
+:105B90008F8C002024090034918B00BC316A0002F4
+:105BA000514000012409003000E9682B15A0FFF1E5
+:105BB0000100202100E938232419FFFC00B9C0248A
+:105BC00000F9782400F8702B15C0FFEA01E82021C5
+:105BD00030C200030002182314C000123069000311
+:105BE0000000302100A9702101C6682100ED602B62
+:105BF0001180FFE03C0401002D2F00010006482B1E
+:105C00000105382101E9302414C0FFDA24E4FFFC47
+:105C10002419FFFC00B9C0240308202103E0000878
+:105C2000008010218F8B002024060004916A00BCA4
+:105C3000314400041480FFEC00A970210A000B5EBF
+:105C40000000302127BDFFE8AFBF00108F460100E4
+:105C5000934A01093C1F08008FFF00902407FF8032
+:105C6000314F00FF31E8007F0008614003E6C821A2
+:105C7000032CC02127090120012770243C010800C2
+:105C8000A02F3DD0AF4E080C3C0D08008DAD00900C
+:105C90003C0400803482000301A65821016C1821C5
+:105CA0002465012030AA007801424025AF48081C35
+:105CB0003C1F08008FFF00908F88004003E6C02142
+:105CC0003319000703074824033A7821AF49002815
+:105CD00025E909C0952E00023C0D08008DAD008C11
+:105CE0003C0A08008D4A009031CC3FFF01A61821E4
+:105CF000000C5980006B282100A72024AF44002C01
+:105D0000952200023C1F08008FFF008C9107008540
+:105D100030593FFF03E678210019C1800146702108
+:105D200001F8682131CC007F31AB007F019A282136
+:105D3000017A50213C03000C3C04000E00A32821F2
+:105D40000144102130E6002027470980AF82002C53
+:105D5000AF88001CAF890024AF85002010C000066A
+:105D6000AF8700288D0200508CA4010C0044302322
+:105D700018C0007700000000910C0085240DFFDFA3
+:105D8000018D3824A10700858F8B001C8F8900248A
+:105D90008F8700288D65004CAF850018912F000D6E
+:105DA00031EE002011C0001700000000240900019E
+:105DB000A3890004AF80000C8CE400248F85000CC4
+:105DC000240A0008AF800008AF8000103C010800E2
+:105DD000A42A3D7E3C010800A4203D920E000B3217
+:105DE000000030218F8500248FBF0010AF82001487
+:105DF00090A8000D27BD00180008394203E00008F4
+:105E000030E20001913F00022418000133F900FF45
+:105E10000019218210980039240800021088005BC4
+:105E20008F86002C8CE5002414A0001B8F9F00207F
+:105E300091220000240A00053046003F10CA0047A6
+:105E4000240400018F860008A3840004AF8600109C
+:105E5000AF86000C8CE400248F85000C240A000817
+:105E60003C010800A42A3D7E3C010800A4203D928C
+:105E70000E000B32000000008F8500248FBF001041
+:105E8000AF82001490A8000D27BD00180008394209
+:105E900003E0000830E200018CF800088CF90024CF
+:105EA0008FEE00C4A38000048CE40024AF8E000CAD
+:105EB0008F85000C8F86000803197823240A0008B8
+:105EC000AF8F00103C010800A42A3D7E3C01080071
+:105ED000A4203D920E000B32000000008F850024AC
+:105EE0008FBF0010AF82001490A8000D27BD0018CE
+:105EF0000008394203E0000830E20001912300006D
+:105F00003062003F104400278F8500208CE400247D
+:105F100014800021000000008D2E00183C187FFF27
+:105F20008F850020370FFFFF01CF1824AF830008B3
+:105F30008F9F00088CA8008403E8C82B172000025C
+:105F400003E020218CA400840A000BEDAF8400083C
+:105F50008CA3010C0A000BCBAF8300188D2C00180A
+:105F60008F8600083C0D7FFF8F89002035A3FFFF3F
+:105F70000183582424040001AF8B0010AD2000CC15
+:105F8000A38400040A000BF9AF86000C8CCA00142D
+:105F90000A000BEDAF8A00088CA300C80A000C3081
+:105FA000AF8300088F84002C8CAC00648C8D0014AF
+:105FB000018D582B11600004000000008CA20064C9
+:105FC0000A000C30AF8200088C8200140A000C30EA
+:105FD000AF8200088F85000C27BDFFE0AFBF00181F
+:105FE000AFB1001414A00007AFB000108F860024DA
+:105FF0002402000590C400003083003F106200B608
+:106000008F8400208F91000800A080218F8C0028B1
+:106010003C0508008CA53D708D8B000431663FFF68
+:1060200000C5502B5540000100C02821938D00046D
+:1060300011A0007300B0F82B8F98002024040034C6
+:10604000930F00BC31EE000251C000012404003067
+:1060500000A4C82B172000D10000000000A42823B2
+:1060600000B0F82B3C010800A4243D7C17E0006838
+:10607000020020213C0308008C633D6C0083102B40
+:1060800054400001008018218F8800243C01080042
+:10609000AC233D74000048219104000D30830020A2
+:1060A000506000018F490E188F8300140123382B94
+:1060B00010E00059000000003C0408008C843D748E
+:1060C00000895821006B502B114000560090602B26
+:1060D0000069302300C020213C010800AC263D743B
+:1060E00012000003241FFFFC1090008A32270003D7
+:1060F000009FC8243C010800AC393D743C010800F5
+:10610000A4203D928F84000C120400078F8300208E
+:10611000AF910008020020218C7100CCAF90000CE0
+:1061200026300001AC7000CC3C0208008C423D746B
+:106130008F8A0010240700180082202301422823A0
+:10614000AF84000C10800002AF85001024070010FF
+:106150008F86001C3C010800A0273D9024070040CA
+:1061600090CC0085318B00C0116700408F8D0014EA
+:1061700014A0001500002021934A01098F420974E0
+:10618000314500FF0002260224A300013090007F69
+:106190003071007F1230007A2407FF80A0C3008393
+:1061A0003C0908008D293D8C8F880024240D0002B5
+:1061B000352C00083C010800A02D3DD13C01080011
+:1061C000AC2C3D8C24040010910E000D31C6002033
+:1061D00010C0000500801821240800013C010800BF
+:1061E000AC283D74348300018FBF00188FB10014B8
+:1061F0008FB000100060102103E0000827BD0020D0
+:106200003C010800A4203D7C13E0FF9A02002021FD
+:106210000A000C8100A020213C0408008C843D74FD
+:106220000090602B1180FFAE000000003C0F0800C2
+:1062300095EF3D7C01E4702101C6682B11A0000799
+:106240002C8200043C1F60008FF954043338003F57
+:106250001700FFE5240300422C8200041040FFA039
+:10626000240300420A000CDF8FBF0018152DFFC069
+:10627000000000008CDF00743C0380002405FF80D8
+:1062800003E3C825ACD9007490D80085240E00041F
+:1062900024040010330F003F01E54025A0C800850D
+:1062A0008F8800243C010800A02E3DD1240300016A
+:1062B0009106000D30C900201520000300000000E9
+:1062C0003C0308008C633D743C010800AC233D6C2A
+:1062D0000A000CD6000000008F8700108C88008414
+:1062E00000E8282B14A0000200E088218C91008493
+:1062F00024090001A38900048F440E1802202821DC
+:106300000E000B3202203021022080210A000C678F
+:10631000AF82001400071823306600033C01080018
+:10632000A4263D92122000058F8C0020918B00BC8A
+:10633000316A00041540001524CD00043C0F08000C
+:1063400095EF3D9201E4702100AE302B50C0FF6EFE
+:106350008F84000C2C85000514A0FFA324030042A9
+:106360003098000317000002009818232483FFFCD4
+:106370003C010800AC233D740A000CA3000000009F
+:1063800000A758240A000CCB016718263C0108001E
+:10639000A42D3D920A000D33000000003C010800CE
+:1063A000AC203D740A000CDE240300428F830010F1
+:1063B00014600007000010218F88002424050005C8
+:1063C0009106000030C400FF1085000300000000AB
+:1063D00003E0000800000000910A0018314900FFA6
+:1063E000000939C214E0FFFA8F85001C3C04080044
+:1063F00094843D7C3C0308008C633D943C19080068
+:106400008F393D743C0F080095EF3D920064C02128
+:106410008CAD00540319702101CF6021018D5823E8
+:106420001960001D00000000910E001C8F8C002CD4
+:10643000974B0E1031CD00FF8D850004016D302388
+:106440008D88000030CEFFFF000E510000AAC82149
+:106450000000382101072021032A182B0083C021C6
+:10646000AD990004AD980000918F000A01CF68211A
+:10647000A18D000A8F88002C974B0E12A50B0008E7
+:10648000950A003825490001A50900389107000D3B
+:1064900034E60008A106000D03E00008000000003B
+:1064A00027BDFFE0938700048F8F00248FAD001479
+:1064B0003C0E7FFF8F89000C35C8FFFFAFBF001C6B
+:1064C000AFB0001801A8182491EA000D000717C00A
+:1064D0003C1FBFFF006258252D2E00018F90001831
+:1064E00037F9FFFF3C1808008F183D943C0F080057
+:1064F00095EF3D8A01796824000E47803C07EFFF45
+:106500003C05F0FF01A818253149002034E2FFFFC7
+:1065100034ACFFFF0310582327A500102406000207
+:1065200025EA000200621824008080211520000264
+:10653000000040218F480E1CA7AA001205600037FA
+:106540002407000030FF00FF001FCF008F8B001CCE
+:1065500000793825AFA70014916F00853C0808002A
+:1065600091083D913C18DFFF31EE00C0370AFFFF74
+:10657000000E182B3C1F080097FF3D8400EA68249A
+:10658000A3A800110003174001A248258FB90010ED
+:10659000AFA900143C0A0800914A3D93A7BF00161A
+:1065A0008FA80014032CC0243C0B01003C0F0FFFEC
+:1065B000030B18253147000335EEFFFF010C68245B
+:1065C00000071600006EF8243C09700001A2C825DF
+:1065D00003E95825AFB90014AFAB00100E000076E8
+:1065E000A3A000158F8C0024260200089186000DC0
+:1065F00030C40020108000068FBF001C3C0508003E
+:1066000094A53D8024B0FFFF3C010800A4303D80EC
+:106610008FB0001803E0000827BD00208F980014F9
+:106620000118502B5540FFC7240700010A000DB682
+:1066300030FF00FF9382000427BDFFE0AFBF0018CA
+:106640001040000F008050218F880024240B00058B
+:106650008F890008910700008F8400200100282105
+:1066600030E3003F8F86002C106B000800003821BB
+:10667000AFA900100E00040EAFAA0014A3800004FE
+:106680008FBF001803E0000827BD00208D190018F7
+:106690003C0F08008DEF3D748F9800103C027FFF87
+:1066A0008D080014345FFFFF033F682401F8702158
+:1066B00001AE602301883821AFA900100E00040E3E
+:1066C000AFAA00140A000E04A38000048F870024E0
+:1066D0003C05080094A53D923C0208008C423D8C8C
+:1066E00090E6000D0005240030C300201060002C4F
+:1066F000004440258F85001C00006021240B000110
+:1067000090A3008500004821240A00013C0F80006E
+:1067100035EE00708DC70000AF8700308F580178CC
+:106720000700FFFE3C038000347900708F380000C2
+:106730003C0508008CA500743C0D08008DAD007070
+:106740000307782300AF38210000102100EF302B21
+:1067500001A22021008618213C010800AC2700740A
+:106760003C010800AC230070AF4B01483C19080005
+:106770008F393D94A7490144A74A0146AF59014CBE
+:106780003C0B0800916B3D91A34B0152AF48015463
+:106790003C081000A74C015803E00008AF480178FE
+:1067A0008F4B0E1C3C0A08008D4A3D7497490E160B
+:1067B000974D0E1401456021312AFFFF0A000E2774
+:1067C00031A9FFFF8F8300249064000D30820020E8
+:1067D0001040002900000000000048210000502166
+:1067E000000040213C07800034EB00708D67000002
+:1067F000AF8700308F4C01780580FFFE3C0D800094
+:1068000035AC00708D8B00003C0508008CA5007431
+:106810003C0408008C8400700167302300A67821B6
+:106820000000102101E6C82B0082C021031970214D
+:106830003C010800AC2F00743C010800AC2E007035
+:10684000AF4901483C0D08008DAD3D94A748014477
+:1068500024090040A74A01463C081000240AFF9181
+:10686000AF4D014CA34A0152AF490154A740015812
+:1068700003E00008AF4801788F490E1897460E12C2
+:1068800097450E1030CAFFFF0A000E5D30A8FFFFCB
+:106890008F83002427BDFFF89064000D3082002014
+:1068A0001040003A00000000240B000100004821C5
+:1068B000240A00013C088000350700708CE30000CA
+:1068C000AF8300308F4C01780580FFFE3C0E8000C6
+:1068D0003C04080090843DD035C700708CEC00006B
+:1068E0003C0508008CA50074A3A400033C19080013
+:1068F0008F3900708FAD00000183302300A638214E
+:10690000000010210322782100E6C02B01F860214D
+:1069100001AE4025AFA800003C010800AC27007480
+:106920003C010800AC2C00709346010A3C040800AE
+:1069300090843DD1A3A00002A3A600018FA3000074
+:106940003C0580FF3099007F34A2FFFF006278246D
+:106950000019C60001F87025240D3000AF4E014C1F
+:1069600027BD0008AF4D0154A7400158AF4B014867
+:10697000A7490144A74A01463C091000240AFF80A8
+:10698000A34A015203E00008AF4901788F4B0E186B
+:1069900097460E1297450E1030CAFFFF0A000E915F
+:1069A00030A9FFFF8F85001C2402008090A4008581
+:1069B000308300C0106200058F8600208F88000899
+:1069C0008F87000CACC800C8ACC700C403E0000847
+:1069D000000000003C0A0800254A39543C09080020
+:1069E00025293A203C08080025082DD43C0708003A
+:1069F00024E73B343C06080024C637C43C050800A5
+:106A000024A5353C3C040800248431643C03080080
+:106A10002463385C3C020800244236303C01080004
+:106A2000AC2A3D503C010800AC293D4C3C0108001B
+:106A3000AC283D483C010800AC273D543C0108000F
+:106A4000AC263D643C010800AC253D5C3C010800DF
+:106A5000AC243D583C010800AC233D683C010800D3
+:0C6A6000AC223D6003E0000800000000D4
+:00000001FF
+/*
+ * This file contains firmware data derived from proprietary unpublished
+ * source code, Copyright (c) 2004 - 2009 Broadcom Corporation.
+ *
+ * Permission is hereby granted for the distribution of this firmware data
+ * in hexadecimal or equivalent format, provided this copyright notice is
+ * accompanying it.
+ */
diff --git a/firmware/bnx2/bnx2-mips-09-5.0.0.j15.fw.ihex b/firmware/bnx2/bnx2-mips-09-5.0.0.j15.fw.ihex
deleted file mode 100644
index 627baec7cb5c..000000000000
--- a/firmware/bnx2/bnx2-mips-09-5.0.0.j15.fw.ihex
+++ /dev/null
@@ -1,6081 +0,0 @@
-:100000000800011008000000000051F8000000C8BE
-:10001000000000000000000000000000080051F88F
-:1000200000000038000052C00800008808000000EE
-:100030000000528C000052F8080054800000008438
-:100040000000A5840800528C000001C00000A60832
-:10005000080031D808000000000081080000A7C88F
-:1000600000000000000000000000000008008108FF
-:1000700000000124000128D00800048808000400C2
-:10008000000017EC000129F400000000000000004F
-:100090000000000008001BEC00000004000141E02B
-:1000A000080000A808000000000038D0000141E46A
-:1000B000000000000000000000000000080038D030
-:0800C0000000003000017AB4D9
-:0800C8000A00004400000000E2
-:1000D000000000000000000D636F6D352E302E30E3
-:1000E0006A31350005000002000000000000000336
-:1000F00000000014000000320000000300000000B7
-:1001000000000000000000000000000000000000EF
-:1001100000000010000001360000EA600000000549
-:1001200000000000000000000000000000000008C7
-:1001300000000000000000000000000000000000BF
-:1001400000000000000000000000000000000000AF
-:10015000000000000000000000000000000000009F
-:10016000000000020000000000000000000000008D
-:10017000000000000000000000000000000000007F
-:10018000000000000000000000000010000000005F
-:10019000000000000000000000000000000000005F
-:1001A000000000000000000000000000000000004F
-:1001B000000000000000000000000000000000003F
-:1001C000000000000000000000000000000000002F
-:1001D000000000000000000000000000100000030C
-:1001E000000000000000000D0000000D3C020800AF
-:1001F000244252603C0308002463539CAC4000003E
-:100200000043202B1480FFFD244200043C1D080005
-:1002100037BD9FFC03A0F0213C1008002610011000
-:100220003C1C0800279C52600E00026B000000007E
-:100230000000000D27BDFFE0AFBF0018AFB10014F4
-:10024000AFB000103C04800094820108304370007D
-:10025000240220001062000B2862200114400036A6
-:1002600000001021240240001062002C0000000059
-:10027000240260001062002D000010210A00009D81
-:100280008FBF001834910100922400098E300018AD
-:1002900010800020240300012402000914820006BB
-:1002A0008F8200243C0280089442001A000214004D
-:1002B000020280258F8200248C42000C1040001521
-:1002C000000018210E000D52000000008F83002452
-:1002D000962400088F8200209463001E9625000C4F
-:1002E0000004240000832025AC500000AC4500042D
-:1002F000AC400008AC40000CAC400010AC40001416
-:10030000AC400018AC44001C0E000D862404000113
-:10031000000018210A00009C006010210E00043B20
-:10032000000000000A00009C000010210E000C726A
-:1003300000000000000010218FBF00188FB10014D2
-:100340008FB0001003E0000827BD00208F8200243A
-:1003500027BDFFE0AFB00010AFBF0018AFB1001471
-:100360008C42000C3C1080008E11010010400034C3
-:100370008FBF00180E000D52000000008F85002076
-:1003800024047FFF0091202BACB100008E030104F8
-:100390009602010800031C003042FFFF006218258E
-:1003A000ACA300049202010A96030114304200FF3C
-:1003B0003063FFFF0002140000431025ACA20008C8
-:1003C0009603010C9602010E00031C003042FFFF51
-:1003D00000621825ACA3000C9603011096020112CE
-:1003E00000031C003042FFFF00621825ACA3001080
-:1003F0008E020118ACA200148E02011CACA20018DF
-:10040000148000088F820024978200003C0420059D
-:100410000044182524420001ACA3001C0A0000DBA4
-:10042000A78200003C0340189442001E00431025A0
-:10043000ACA2001C0E000D86240400018FBF001822
-:100440008FB100148FB000100000102103E00008ED
-:1004500027BD00203C0680008CC202B824030001A6
-:1004600004410008008028213C0208008C42006002
-:10047000244200013C010800AC22006003E00008B7
-:10048000006010218C83002094820016ACC302808F
-:100490002442FFFCA4C202843C0208008C42005C9F
-:1004A0008C84000494A3000E244200013C01080047
-:1004B000AC22005C3C021000A4C30286ACC40288DB
-:1004C00000001821ACC202B803E00008006010214F
-:1004D00027BDFFE0AFB000103C108000AFB20018A5
-:1004E000AFBF001CAFB10014361201009243000BE5
-:1004F0002402001A965100081462005A00002821B4
-:1005000032220001104000188F8200248E42000029
-:10051000000223403C02003F3442FFFF0044102B06
-:10052000104000043C030040964200140A000124DD
-:10053000008320218E030100240201005462000682
-:10054000964200143C028008904200043042000FA2
-:10055000000225009642001400821025AE020080A1
-:100560000A000157000000008C42000C10400028D7
-:10057000000000000E000D5200000000960201086D
-:100580009603010C8F8500203042003E3063FFFF50
-:100590000002140000431025ACA200008E020100EE
-:1005A000ACA20004960301169604010E8F8200246B
-:1005B00000031C003084FFFF00641825ACA3000872
-:1005C00096030110960401129446001E00031C00BD
-:1005D0003084FFFF00641825ACA3000C3C0220000F
-:1005E00000C2302596020114240400013042FFFFAE
-:1005F000ACA200108E020118ACA200149202010BF2
-:10060000304200FFACA200180E000D86ACA6001C04
-:100610003C0208008C420040244200013C010800DA
-:10062000AC2200403C0308008C63004432220002EC
-:1006300032240004246300013C010800AC23004480
-:10064000108000080002282B024020218FBF001CD0
-:100650008FB200188FB100148FB000100A0000E3B1
-:1006600027BD00208FBF001C8FB200188FB100146F
-:100670008FB0001000A0102103E0000827BD00206B
-:1006800027BDFFE0AFB000103C108000AFB20018F3
-:10069000AFBF001CAFB10014361201009243000B33
-:1006A00024020003965100081462007500002821FE
-:1006B00032220001104000178F8200248E43000078
-:1006C0003C02003F3442FFFF000323400044102B54
-:1006D0005040000524020100964200143C030040F3
-:1006E0000A00018F00832021546200069642001404
-:1006F0003C028008904200043042000F00022500B6
-:100700009642001400821025AE0200800A0001BF4C
-:10071000000000008C42000C10400025000000008A
-:100720000E000D5200000000960201089603010C15
-:100730008F8500203042003E3063FFFF000214002E
-:1007400000431025ACA200008E020100ACA2000400
-:10075000960301169604010E8F82002400031C00EC
-:100760003084FFFF00641825ACA300089603011035
-:10077000960401129446001E00031C003084FFFF03
-:1007800000641825ACA3000C3C02200000C23025F8
-:1007900096020114240400013042FFFFACA20010B5
-:1007A000ACA00014ACA000180E000D86ACA6001C76
-:1007B0003C0208008C420040244200013C01080039
-:1007C000AC2200403C0208008C420044322300046A
-:1007D000244200013C010800AC22004410600008E3
-:1007E00032220002024020218FBF001C8FB200186D
-:1007F0008FB100148FB000100A0000E327BD002065
-:100800001040001F000028213C05800034A2007029
-:100810008C4400008F82000C008210232C43012C9A
-:1008200010600004AF820010240500010A0001EEF0
-:10083000AF84000C8CA301043C026020AC43001484
-:100840008C420004240301FE304203FF1443000BDA
-:10085000AF84000C8CA20100000219C22462FFFCCC
-:100860002C42000810400003240400022462FFFD13
-:10087000004420043C026000AC44691400002821BC
-:100880008FBF001C8FB200188FB100148FB0001002
-:1008900000A0102103E0000827BD00203C048000D8
-:1008A0008C83010024020100506200033C02800896
-:1008B0000000000D3C02800890430004000010215D
-:1008C0003063000F00031D0003E00008AC830080CC
-:1008D0002C8407811080000A000028213C0280003F
-:1008E00094420108240320003042700014430005A4
-:1008F0002783FFA43C02800890420005304500FF9A
-:100900002783FFA40005208000832021000510C05C
-:10091000004510238C8400003C0308002463532C02
-:10092000000210C0004310213C038000AC64009022
-:1009300003E00008AF82002403E00008000010215B
-:1009400003E00008000010212402010014820008C6
-:10095000000000003C0208008C4200FC2442000120
-:100960003C010800AC2200FC0A00023030A200204A
-:100970003C0208008C420084244200013C01080033
-:10098000AC22008430A200201040000830A30010E8
-:100990003C0208008C420108244200013C0108008E
-:1009A000AC22010803E0000800000000106000080D
-:1009B000000000003C0208008C42010424420001B7
-:1009C0003C010800AC22010403E000080000000024
-:1009D0003C0208008C420100244200013C01080056
-:1009E000AC22010003E000080000000027BDFFE882
-:1009F000AFB000103C108000AFBF001436040100FF
-:100A00009483000830620004104000053066000244
-:100A10008FBF00148FB000100A0000E327BD00183C
-:100A200010C00006006028218E0401000E00022084
-:100A3000000000000A000267240200018F82000803
-:100A40008E03010410430007000010218E040100F2
-:100A50000E000220000000008E020104AF82000898
-:100A6000000010218FBF00148FB0001003E00008B9
-:100A700027BD001827BDFFD83C036010AFB3001C92
-:100A8000AFBF0020AFB20018AFB10014AFB000107C
-:100A90008C6450002402FF7F3C13080026735290A0
-:100AA000008220243484380CAC6450003C02800066
-:100AB00024030037AC4300083C06080024C6087035
-:100AC000026010212404001C2484FFFFAC460000B7
-:100AD0000481FFFD244200043C0208002442016C12
-:100AE0003C010800AC2252983C020800244205B8A0
-:100AF0003C010800AC22529C3C02080024420284C3
-:100B00003C010800AC2252D83C02080024420408F0
-:100B10003C030800246308783C040800248409246A
-:100B20003C05080024A52C803C010800AC2252F8AA
-:100B30003C020800244207D43C010800AC2652E0E5
-:100B40003C010800AC2552EC3C010800AC2352F4F7
-:100B50003C010800AC2452FC3C010800AC225300CC
-:100B60003C010800AC2352943C010800AC2052A088
-:100B70003C010800AC2052A43C010800AC2052A863
-:100B80003C010800AC2052AC3C010800AC2052B043
-:100B90003C010800AC2052B43C010800AC2052B823
-:100BA0003C010800AC2452BC3C010800AC2052C0FF
-:100BB0003C010800AC2052C43C010800AC2052C8E3
-:100BC0003C010800AC2052CC3C010800AC2052D0C3
-:100BD0003C010800AC2652D43C010800AC2652DC93
-:100BE0003C010800AC2052E43C010800AC2552E86E
-:100BF0003C010800AC2352F00E0005670000000025
-:100C0000AF80000C8F8300043C0208008C4200205F
-:100C10001062001F000088212792FFA43C100800EA
-:100C20002610532C3C0208008C42002024050001B1
-:100C300002251804004320248F820004004310245E
-:100C40005044000C2631000110800008AF900024B1
-:100C50008E4300003C028000AC4300900E000D1952
-:100C6000AE05000C0A0002EB26310001AE00000CBC
-:100C7000263100012E220002261000381440FFE920
-:100C8000265200043C0208008C420020AF8200047F
-:100C90003C1080008E110000322200071040FFDA65
-:100CA0008F83000432220001104000213222000212
-:100CB0008E020100AE0200208E020104AE0200A8E6
-:100CC0000E0002028E0401009202010B304300FF6D
-:100CD0002C62001D54400004000310800E00021C12
-:100CE0000A00030C00000000005310218C42000099
-:100CF0000040F80900000000104000043C028000A1
-:100D00008C4301043C026020AC4300143C02080008
-:100D10008C4200343C0440003C038000244200012B
-:100D2000AC6401383C010800AC22003432220002DD
-:100D300010400010322200043C1080008E0201405E
-:100D4000AE0200200E0002028E0401400E0003A439
-:100D5000000000003C024000AE0201783C020800A6
-:100D60008C420038244200013C010800AC220038CB
-:100D7000322200041040FFA48F8300043C10800046
-:100D80008E020180AE0200200E0002028E0401805D
-:100D90008E03018024020F00146200073C028008C9
-:100DA0008E0201883C0300E03042FFFF0043102523
-:100DB0000A000348AE0200803442008090420000E6
-:100DC00024030050304200FF1443000700000000DD
-:100DD0000E0003810000000014400003000000002A
-:100DE0000E00096A000000003C0208008C42003C32
-:100DF0003C0440003C03800024420001AC6401B884
-:100E00003C010800AC22003C0A0002D08F830004A1
-:100E10003C02900034420001008220253C02800008
-:100E2000AC4400203C0380008C6200200440FFFEA4
-:100E30000000000003E00008000000003C02800009
-:100E4000344300010083202503E00008AC44002067
-:100E500027BDFFE0AFB10014AFB0001000808821C3
-:100E6000AFBF00180E00035230B000FF8F83FF9C0D
-:100E7000022020219062002502028025A07000251A
-:100E80008C7000183C0280000E00035D020280247A
-:100E90001600000A8FBF00183C0380008C6201F826
-:100EA0000440FFFE24020002AC7101C0A06201C434
-:100EB0003C021000AC6201F88FBF00188FB1001423
-:100EC0008FB0001003E0000827BD002027BDFFE819
-:100ED000AFBF00103C0380009462018430420200E6
-:100EE00010400005000020210E000FDA0000000075
-:100EF0000A000397240400018C6201880440000A60
-:100F00008FBF00108C6201883C03FF000043102457
-:100F10003C03040014430004240400018F82FF9C5E
-:100F2000904200088FBF00100080102103E00008ED
-:100F300027BD00188F82FFA02403000124050001B3
-:100F4000A040001A8F82FF9CA44300163C02800040
-:100F50000A0003628C4401408F85FF9C27BDFFE09F
-:100F6000AFBF001CAFB20018AFB10014AFB000109B
-:100F700090A20000304400FF388300203882003007
-:100F80000003182B0002102B0062182410600005CB
-:100F90003C02800024020050148200818FBF001C9C
-:100FA0003C02800090420148304200FF2443FFFF92
-:100FB0002C6200051040007A8FBF001C00031080D7
-:100FC0003C03080024635210004310218C420000AF
-:100FD00000400008000000003C1180008E24014009
-:100FE0000E0003528F92FF9C8E50000C8E22014403
-:100FF0001602000224020001AE42000C0E00035D46
-:101000008E2401408E220144145000068FBF001C24
-:101010008FB200188FB100148FB000100A000F4675
-:1010200027BD00208E42000C0A00042F00000000A3
-:1010300094A200103C0480008C8301443042FFFFE6
-:10104000146200090000000024020001A4A20010A4
-:101050008C820140AC8202003C021000AC8202385B
-:101060000A0004368FBF001C94A200100A00042F4F
-:1010700000000000240200201482000E3C118000B9
-:1010800094A200123C0380008C6301443042FFFFB5
-:10109000146200050000000024020001A4A2001256
-:1010A0000A0004098FBF001C94A200120A00042F3A
-:1010B000000000008E2401400E0003528F92FF9C1E
-:1010C000964200128E2301443050FFFF16030002A7
-:1010D00024020001A64200120E00035D8E2401408E
-:1010E0008E220144160200068FBF001C8FB200182A
-:1010F0008FB100148FB000100A00039B27BD0020A1
-:10110000964200120A00042F0000000094A200146E
-:101110003C0380008C6301443042FFFF14620008EE
-:101120008FBF001C240200018FB200188FB1001481
-:101130008FB00010A4A200140A00143127BD0020B3
-:1011400094A200140A00042F0000000094A20016CC
-:101150003C0380008C6301443042FFFF14620008AE
-:10116000240200018FBF001C8FB200188FB1001441
-:101170008FB00010A4A200160A000B0D27BD00209E
-:1011800094A20016144000068FBF001C3C02080009
-:101190008C420070244200013C010800AC22007027
-:1011A0008FB200188FB100148FB0001003E0000858
-:1011B00027BD002027BDFFD8AFB200188F92FF9C3B
-:1011C000AFB10014AFBF0020AFB3001CAFB0001030
-:1011D0003C028000345101008C500100924200001A
-:1011E00092230009304400FF2402001F106200AB6C
-:1011F0002862002010400019240200382862000AEA
-:101200001040000D2402000B286200081040002E40
-:101210008F82002404600103286200021440002A27
-:101220008F82002424020006106200268FBF002057
-:101230000A0005598FB3001C106200602862000B81
-:10124000144000F98FBF00202402000E10620078C5
-:101250008F8200240A0005598FB3001C106200D150
-:10126000286200391040000A24020080240200365F
-:10127000106200E428620037104000C224020035EA
-:10128000106200D88FBF00200A0005598FB3001CE0
-:101290001062002D2862008110400006240200C860
-:1012A00024020039106200C88FBF00200A000559CF
-:1012B0008FB3001C106200A28FBF00200A000559E6
-:1012C0008FB3001C8F8200248C42000C104000D68B
-:1012D0008FBF00200E000D52000000003C03800074
-:1012E000346301008C6200008F8500209467000841
-:1012F0009466000CACA200008C6400048F82002471
-:1013000000063400ACA400049448001E8C6200184F
-:1013100000073C0000E83825ACA200088C62001CE5
-:1013200024040001ACA2000C9062000A00C2302527
-:10133000ACA60010ACA00014ACA00018ACA7001C18
-:101340000A0005188FBF00208F8200248C42000CF9
-:10135000104000B58FBF00200E000D5200000000AD
-:101360008F820024962400089625000C9443001ECA
-:10137000000422029626000E8F8200200004260020
-:101380000083202500052C003C03008000A62825B2
-:1013900000832025AC400000AC400004AC400008B5
-:1013A000AC40000CAC450010AC400014AC40001840
-:1013B000AC44001C0A000517240400019622000C0E
-:1013C0001440001800000000924200053042001056
-:1013D00014400014000000000E00035202002021FF
-:1013E0009242000502002021344200100E00035DED
-:1013F000A24200059242000024030020304200FF78
-:1014000010430088020020218FBF00208FB3001CF2
-:101410008FB200188FB100148FB000100A00104373
-:1014200027BD00280000000D0A0005588FBF0020CE
-:101430008C42000C1040007C8FBF00200E000D522B
-:10144000000000008E2200048F8400209623000CF0
-:10145000AC8200003C0280089445002C8F8200245E
-:1014600000031C0030A5FFFF9446001E3C02400E06
-:101470000065182500C23025AC830004AC8000084C
-:10148000AC80000CAC800010AC800014AC80001864
-:10149000AC86001C0A000517240400010E0003524C
-:1014A000020020218F93FFA0020020210E00035D87
-:1014B000A660000C020020210E000362240500013A
-:1014C0008F8200248C42000C104000578FBF0020F8
-:1014D0000E000D52000000009622000C8F830020A9
-:1014E00000021400AC700000AC620004AC600008A4
-:1014F0008E4400388F820024AC64000C8E46003C81
-:101500009445001E3C02401FAC66001000A2282536
-:101510008E62000424040001AC620014AC60001868
-:10152000AC65001C8FBF00208FB3001C8FB2001869
-:101530008FB100148FB000100A000D8627BD00285F
-:1015400024020020108200398FB3001C0E000F2CE3
-:1015500000000000104000348FBF00203C038000DA
-:101560008C6201F80440FFFE24020002AC7001C04E
-:10157000A06201C43C021000AC6201F80A000558E8
-:101580008FBF0020020020218FBF00208FB3001CDE
-:101590008FB200188FB100148FB000100A000E75C2
-:1015A00027BD00289625000C020020218FBF0020B7
-:1015B0008FB3001C8FB200188FB100148FB00010D1
-:1015C0000A000E9A27BD0028020020218FB3001CBC
-:1015D0008FB200188FB100148FB000100A000EC532
-:1015E00027BD00289225000D020020218FB3001C8A
-:1015F0008FB200188FB100148FB000100A000F16C0
-:1016000027BD0028020020218FBF00208FB3001CBF
-:101610008FB200188FB100148FB000100A000EEDC9
-:1016200027BD00288FBF00208FB3001C8FB2001889
-:101630008FB100148FB0001003E0000827BD002810
-:101640003C0380008C6202780440FFFE240200020A
-:10165000AC640240A06202443C02100003E00008B7
-:10166000AC620278A380001803E00008A380001990
-:101670003C0380008C6202780440FFFE8F82001CD5
-:10168000AC62024024020002A06202443C0210004C
-:1016900003E00008AC6202783C02600003E000084E
-:1016A0008C425404908300302402000500804021C5
-:1016B0003063003F00004821146200050000502103
-:1016C0009082004C9483004E304900FF306AFFFF47
-:1016D000AD00000CAD000010AD0000249502001418
-:1016E0008D05001C8D0400183042FFFF00491023B7
-:1016F00000021100000237C3004038210086202379
-:1017000000A2102B0082202300A72823AD05001C77
-:10171000AD040018A5090014A5090020A50A0016AB
-:1017200003E00008A50A002203E000080000000012
-:1017300027BDFFD8AFB200183C128008AFB400201C
-:10174000AFB3001CAFB10014AFBF0024AFB00010A6
-:10175000365101003C0260008C4254049222000C7D
-:101760003C140800929400F7304300FF240200016B
-:1017700010620032008098212402000214620035B9
-:10178000365000800E00140B000000009202004C46
-:101790002403FF803C0480003042007F000211C01F
-:1017A000244202400262102100431824AC830094BA
-:1017B000924500089204004C3042007F3C038006B2
-:1017C00014850007004380212402FFFFA22200119C
-:1017D0002402FFFFA62200120A0005CB2402FFFF0D
-:1017E00096020020A222001196020022A6220012D8
-:1017F0008E0200243C048008AE2200143485008050
-:1018000090A2004C34830100A06200108CA2003C26
-:10181000AC6200188C820068AC6200E48C820064C8
-:10182000AC6200E08C82006CAC6200E82402000133
-:10183000A0A200680A0005E73C0480080E001424FA
-:101840000000000036420080A04000680A0005E762
-:101850003C048008A2000068A20000690A00062279
-:101860003C028008348300808C620038348501009B
-:10187000AC62006C24020001A062006990A200C565
-:1018800090830008305100FF3072007F123200193F
-:10189000001111C024420240026210212403FF8083
-:1018A000004318243C048000AC8300943042007F45
-:1018B0003C038006004380218E02000C1040000D86
-:1018C000020020210E000577000000002622000102
-:1018D000305100FF9203003C023410260002102B0E
-:1018E000000210233063007F022288240A0005F1E1
-:1018F000A203003C3C088008350401008C8200D023
-:1019000035070080ACE2003C8C8200D0AD020000C4
-:1019100090E5004C908600C590E3004C908400C593
-:101920002402FF8000A228243063007F308400FF5F
-:1019300000A628250064182A1060000230A500FFC8
-:1019400038A50080A0E5004CA10500093C028008F4
-:101950009043000E344400803C058000A043000A00
-:101960008C8300183C027FFF3442FFFF0062182482
-:10197000AC8300188CA201F80440FFFE00000000B8
-:10198000ACB301C08FBF00248FB400208FB3001C04
-:101990008FB200188FB100148FB000102402000223
-:1019A000A0A201C427BD00283C02100003E00008EB
-:1019B000ACA201F890A2000024420001A0A2000005
-:1019C0003C0308008C6300F4304200FF1443000223
-:1019D00000803021A0A0000090A200008F84001C95
-:1019E000000211C0244202402483004000822021D2
-:1019F0002402FF80008220243063007F3C02800AA2
-:101A0000006218213C028000AC44002403E000087E
-:101A1000ACC3000094820006908300058C85000C06
-:101A20008C8600108C8700188C88001C8C84002009
-:101A30003C010800A422530E3C010800A023530DD2
-:101A40003C010800AC2553143C010800AC26531897
-:101A50003C010800AC2753203C010800AC2853246B
-:101A60003C010800AC24532803E0000800000000FB
-:101A70003C028008344201008C4400343C03800066
-:101A800034650400AC6400388C420038AF8500280F
-:101A9000AC62003C3C020005AC620030000000007B
-:101AA0000000000003E00008000000003C02000607
-:101AB000308400FF008220253C028000AC440030CE
-:101AC0000000000000000000000000003C03800057
-:101AD0008C620000304200101040FFFD34620400B0
-:101AE00003E00008AF82002894C200003C08080010
-:101AF000950800CA30E7FFFF00804821010210214D
-:101B0000A4C2000094C200003042FFFF00E2102B8C
-:101B100054400001A4C7000094A200003C03080048
-:101B20008C6300CC24420001A4A2000094A2000017
-:101B30003042FFFF144300073C0280080107102BCE
-:101B4000A4A000005440000101003821A4C70000F7
-:101B50003C028008344601008CC3002894A2000097
-:101B60003C0480003042FFFE000210C000621021E1
-:101B7000AC82003C8C82003C006218231860000498
-:101B8000000000008CC200240A0006B324420001B9
-:101B90008CC20024AC8200383C0200503442001059
-:101BA0003C038000AC620030000000000000000038
-:101BB000000000008C620000304200201040FFFD59
-:101BC0000000000094A200003C04800030420001AC
-:101BD000000210C0004410218C430400AD2300001B
-:101BE0008C420404AD2200043C02002003E0000803
-:101BF000AC82003027BDFFE0AFB20018AFB10014D7
-:101C0000AFB00010AFBF001C94C2000000C0802124
-:101C10003C120800965200C624420001A6020000B1
-:101C20009603000094E2000000E030211443000518
-:101C30008FB100300E000688024038210A0006EA03
-:101C4000000000008C8300048C82000424420040C9
-:101C500004610007AC8200048C820004044000048C
-:101C6000000000008C82000024420001AC820000D1
-:101C7000960200003042FFFF50520001A600000013
-:101C80009622000024420001A62200003C028008A7
-:101C900034420100962300009442003C14430004A7
-:101CA0008FBF001C24020001A62200008FBF001C71
-:101CB0008FB200188FB100148FB0001003E000083D
-:101CC00027BD002027BDFFE03C028008AFBF001801
-:101CD000344201008C4800343C0380003469040025
-:101CE000AC6800388C42003830E700FFAF8900282C
-:101CF000AC62003C3C020005AC6200300000000019
-:101D000000000000000000000000000000000000D3
-:101D1000000000008C82000C8C82000C978300165F
-:101D2000AD2200008C82001000604021AD22000432
-:101D30008C820018AD2200088C82001CAD22000CA1
-:101D40008CA20014AD2200108C820020AD22001461
-:101D500090820005304200FF00021200AD22001800
-:101D60008CA20018AD22001C8CA2000CAD22002019
-:101D70008CA20010AD2200248CA2001CAD220028F1
-:101D80008CA20020AD22002C3402FFFFAD260030D3
-:101D9000AD200034506200013408FFFFAD28003848
-:101DA00050E000113C0280083C04800834840100AB
-:101DB000948200503042FFFFAD22003C94830044E7
-:101DC00094850044240200013063FFFF000318C221
-:101DD000006418219064005430A5000700A210048C
-:101DE0000A0007550044102534420100AD20003C94
-:101DF00094430044944400443063FFFF000318C23E
-:101E0000006218213084000790650054240200010C
-:101E1000008210040002102700451024A062005424
-:101E20000000000000000000000000003C0200066E
-:101E3000344200403C038000AC62003000000000EF
-:101E400000000000000000008C6200003042001022
-:101E50001040FFFD3C06800834C20150346304008A
-:101E600034C7014A34C4013434C5014034C6014486
-:101E7000AFA200100E0006CBAF8300288FBF001862
-:101E800003E0000827BD00208F8300143C060800F3
-:101E90008CC600E88F82001C30633FFF000319806E
-:101EA00000461021004310212403FF800043182422
-:101EB0003C068000ACC300283042007F3C03800C0D
-:101EC0000043302190C2000D30A500FF00003821F2
-:101ED00034420010A0C2000D8F8900143C0280081B
-:101EE0003442010094430044000913823048000347
-:101EF00024020001A4C3000E1102000B29020002FB
-:101F000010400005240200021100000C240300010F
-:101F10000A00079D000018211102000600000000C1
-:101F20000A00079D000018218CC2002C0A00079DA2
-:101F3000244300018CC20014244300018CC2001809
-:101F40000043102B5040000A240700012402002700
-:101F500014A200033C0380080A0007AA240700011A
-:101F6000346301009462004C24420001A462004CDE
-:101F700000091382304300032C6200021040000964
-:101F800000802821146000040000000094C2003486
-:101F90000A0007BA3046FFFF8CC600380A0007BAAD
-:101FA00000802821000030213C04080024845308CC
-:101FB0000A0006FF0000000027BDFF90AFB60068D2
-:101FC000AFB50064AFB40060AFB3005CAFB200580F
-:101FD000AFB10054AFBF006CAFB000508C900000A8
-:101FE0000080B0213C0208008C4200E896040032D8
-:101FF0008F83001C2414FF8030843FFF006218216F
-:102000000004218000641821007410243C13800017
-:1020100000A0902190A50000AE620028920400323A
-:102020003C02800C3063007F00628821308400C055
-:1020300024020040148200320000A8218E350038AE
-:102040008E2200181440000224020001AE22001863
-:102050009202003C304200201440000E8F83001C8E
-:10206000000511C02442024000621821306400784B
-:102070003C0200800082202500741824AE63080012
-:10208000AE6408108E2200188E0300080043102151
-:10209000AE2200188E22002C8E230018244200014C
-:1020A0000062182B10600043000000009242000004
-:1020B00024420001A24200003C0308008C6300F4AB
-:1020C000304200FF50430001A24000009242000055
-:1020D0008F84001C000211C024420240248300406F
-:1020E0003063007F008220213C02800A009420247B
-:1020F00000621821AE6400240A0008CBAEC30000C1
-:10210000920300322402FFC000431024304200FF3B
-:102110001440000524020001AE220018962200346B
-:102120000A00083B3055FFFF8E22001424420001B4
-:10213000AE220018920200300002160000021603C0
-:102140000441001C000000009602003227A4001089
-:1021500000802821A7A2001696020032000030213C
-:10216000240700013042FFFFAF8200140E0006FF7B
-:10217000AFA0001C960200328F83001C3C040800B4
-:102180008C8400E830423FFF000211800064182177
-:102190000062182100741024AE62002C3063007FAE
-:1021A0003C02800E006218219062000D3042007FD8
-:1021B000A062000D9222000D3042001050400078C5
-:1021C000924200003C028008344401009482004C9A
-:1021D0008EC300003C130800967300C62442FFFF24
-:1021E000A482004C946200329623000E3054FFFF0C
-:1021F0003070FFFF3C0308008C6300D000701807AC
-:10220000A7A300389482003E3063FFFF3042FFFFF7
-:1022100014620007000000008C8200303C03800044
-:1022200024420030AC62003C0A0008638C82002C1F
-:10223000948200403042FFFF5462000927A400400E
-:102240008C8200383C03800024420030AC62003CA9
-:102250008C820034AC6200380A0008723C038000B3
-:1022600027A5003827A60048026038210E000688FE
-:10227000A7A000488FA300403C02800024630030E8
-:10228000AC4300388FA30044AC43003C3C038000C7
-:102290003C020005AC6200303C028008344401007E
-:1022A00094820042346304003042FFFF0202102B8C
-:1022B00014400007AF8300289482004E94830042AC
-:1022C00002021021004310230A0008883043FFFF58
-:1022D0009483004E94820042026318210050102320
-:1022E000006218233063FFFF3C0280083444010081
-:1022F0009482003C3042FFFF1443000300000000C2
-:102300000A000898240300019482003C3042FFFF39
-:102310000062102B144000058F8200289482003C3C
-:10232000006210233043FFFF8F820028AC5500006D
-:10233000AC400004AC540008AC43000C3C02000666
-:10234000344200103C038000AC620030000000000A
-:1023500000000000000000008C620000304200100D
-:102360001040FFFD3C04800834840100001018C2B6
-:102370000064182190650054320200072406000111
-:102380000046100400451025A062005494830042CA
-:102390009622000E50430001A386001892420000CE
-:1023A00024420001A24200003C0308008C6300F4B8
-:1023B000304200FF50430001A24000009242000062
-:1023C0008F84001C000211C024420240248300407C
-:1023D000008220212402FF80008220243063007FBD
-:1023E0003C02800A006218213C028000AC440024B8
-:1023F000AEC300008FBF006C8FB600688FB500645D
-:102400008FB400608FB3005C8FB200588FB100545E
-:102410008FB0005003E0000827BD007027BDFFD833
-:10242000AFB3001CAFB20018AFB10014AFB00010D2
-:10243000AFBF00200080982100E0802130B1FFFF75
-:102440000E000D5230D200FF00000000000000001E
-:10245000000000008F8200208F830024AC51000018
-:10246000AC520004AC530008AC40000CAC4000106F
-:10247000AC400014AC4000189463001E0203802599
-:10248000AC50001C00000000000000000000000034
-:10249000240400018FBF00208FB3001C8FB20018EE
-:1024A0008FB100148FB000100A000D8627BD0028E0
-:1024B00030A5FFFF0A0008D530C600FF3C028008A7
-:1024C000344301009462000E3C080800950800C6E1
-:1024D0003046FFFF14C000043402FFFF946500DAA9
-:1024E0000A0009228F84001C10C20027000000008F
-:1024F0009462004E9464003C3045FFFF00A6102318
-:1025000000A6182B3087FFFF106000043044FFFF47
-:1025100000C5102300E210233044FFFF0088102B79
-:102520001040000E00E810233C02800834440100F3
-:102530002403000134420080A44300162402FFFF5C
-:10254000A482000E948500DA8F84001C00003021E4
-:1025500030A5FFFF0A0008FA3C0760200044102A5B
-:10256000104000093C028008344300809462001649
-:1025700030420001104000043C0280009442007E82
-:1025800024420014A462001603E0000800000000CA
-:1025900027BDFFE03C028008AFBF001CAFB00018B1
-:1025A00034420100944300429442004C1040001910
-:1025B0003068FFFF93830018240200011462002991
-:1025C0008FBF001C3C06800834D00100000810C2F8
-:1025D00000501021904200543103000734C70148D5
-:1025E000304200FF006210073042000134C9014E42
-:1025F00034C4012C34C5013E1040001634C60142DB
-:102600000E0006CBAFA90010960200420A00093F57
-:102610003048FFFF3C0280083444010094830044AA
-:10262000948200421043000F8FBF001C948200442C
-:10263000A482004294820050A482004E8C82003812
-:10264000AC82003094820040A482003E9482004A12
-:10265000A48200488FBF001C8FB000180A0008FD3C
-:1026600027BD00208FB0001803E0000827BD002020
-:1026700027BDFFA0AFB1004C3C118000AFBF005898
-:10268000AFB30054AFB20050AFB000483626018857
-:1026900090C200033044007FA3A400108E3201805A
-:1026A00090C200003043007F240200031062003B10
-:1026B000AF92001C286200041040000624020004AF
-:1026C00024020002106200098FBF00580A000B08A4
-:1026D0008FB300541062004D240200051062014EB9
-:1026E0008FBF00580A000B088FB30054000411C0BC
-:1026F000024210212404FF8024420240004410249E
-:1027000026430040AE2200243063007F3C02800A52
-:10271000006218219062003CAFA3003C00441025E9
-:10272000A062003C8FA3003C9062003C304200401D
-:102730001040016C8FBF00583C108008A380001827
-:10274000361001008E0200D08C63003427A4003CB8
-:1027500027A50010004310210E0007BCAE0200D0D8
-:1027600093A200103C038000A20200C58C62027894
-:102770000440FFFE8F82001CAC6202402402000273
-:10278000A06202443C021000AC6202780E000932E2
-:10279000000000000A000B078FBF00583C058008AE
-:1027A00090C3000190A2000B1443014E8FBF00584C
-:1027B00034A400808C8200189082004C90A2000803
-:1027C0003C0260008C4254048C8300183C027FFF62
-:1027D0003442FFFF006218243C0208008C4200B41F
-:1027E000AC8300183C038000244200013C01080037
-:1027F000AC2200B48C6201F80440FFFE8F82001C02
-:10280000AC6201C00A000ACF240200023C1080081A
-:1028100090C300019202000B144301328FBF005895
-:1028200027A4001836050110240600033C026000AE
-:102830008C4254040E000E150000000027A400284E
-:10284000360501E00E000E15240600038FA20028B5
-:1028500036030100AE0200648FA2002CAE020068B5
-:102860008FA20030AE02006C93A40018906300C5E4
-:102870002402FF800082102400431025304900FF0D
-:102880003084007F3122007F0082102A54400001F2
-:1028900039290080000411C0244202402403FF8033
-:1028A0000242102100431024AE2200942642004030
-:1028B0003042007F3C038006004340218FA3001C70
-:1028C0002402FFFFAFA800403C130800927300F7FA
-:1028D0001062003393A2001995030014304400FFE6
-:1028E0003063FFFF0064182B106000100000000030
-:1028F000950400148D07001C8D0600183084FFFF1E
-:10290000004420230004210000E4382100001021AD
-:1029100000E4202B00C2302100C43021AD07001C90
-:10292000AD0600180A000A2893A2001995040014A5
-:102930008D07001C8D0600183084FFFF00822023C5
-:1029400000042100000010210080182100C2302363
-:1029500000E4202B00C4302300E33823AD07001C23
-:10296000AD06001893A200198FA30040A4620014C2
-:1029700097A2001AA46200168FA2001CAC6200107D
-:102980008FA2001CAC62000C93A20019A46200206C
-:1029900097A2001AA46200228FA2001CAC6200243D
-:1029A0003C048008348300808C6200388FA20020B1
-:1029B00001208821AC62003C8FA20020AC82000084
-:1029C00093A20018A062004C93A20018A0820009F4
-:1029D000A060006893A20018105100512407FF80E6
-:1029E0003229007F000911C0244202400242102116
-:1029F0003046007F3C03800000471024AC62009406
-:102A00003C02800600C2302190C2003CAFA60040CC
-:102A10000000202100471025A0C2003C8FA80040E4
-:102A200095020002950300148D07001C3042FFFF41
-:102A30003063FFFF8D0600180043102300021100D1
-:102A400000E2382100E2102B00C4302100C2302106
-:102A5000AD07001CAD06001895020002A502001487
-:102A6000A50000168D020008AD0200108D020008BE
-:102A7000AD02000C95020002A5020020A500002274
-:102A80008D020008AD0200249102003C304200405B
-:102A90001040001A262200013C108008A3A900382B
-:102AA000A3800018361001008E0200D08D03003480
-:102AB00027A4004027A50038004310210E0007BCC2
-:102AC000AE0200D093A200383C038000A20200C5F1
-:102AD0008C6202780440FFFE8F82001CAC620240D0
-:102AE00024020002A06202443C021000AC620278A0
-:102AF0000E00093200000000262200013043007F52
-:102B000014730004004020212403FF8002231024BA
-:102B10000043202693A200180A000A44309100FFC7
-:102B200093A400188FA3001C2402FFFF1062000A68
-:102B3000308900FF24820001248300013042007F9D
-:102B400014530005306900FF2403FF800083102424
-:102B500000431026304900FF3C02800890420008E4
-:102B600001208821305000FF123000193222007FEE
-:102B7000000211C002421021244202402403FF80BF
-:102B8000004318243C048000AC8300943042007F52
-:102B90003C038006004310218C43000C00402021A0
-:102BA0001060000BAFA200400E000577000000008F
-:102BB000262300012405FF803062007F14530002A9
-:102BC00002252024008518260A000AA8307100FF7B
-:102BD0003C048008348400808C8300183C027FFF12
-:102BE0003442FFFF00621824AC8300183C038000CD
-:102BF0008C6201F80440FFFE00000000AC7201C0CE
-:102C000024020002A06201C43C021000AC6201F880
-:102C10000A000B078FBF00583C04800890C30001D6
-:102C20009082000B1443002F8FBF00583490008017
-:102C300092020008304200401040002000000000D6
-:102C4000920200080002160000021603044100056B
-:102C5000024020210E000E9A240500930A000B0763
-:102C60008FBF00589202000924030018304200FF71
-:102C70001443000D02402021240500390E000E32BD
-:102C8000000030210E0003528F84001C8F82FF9CB5
-:102C900024030012A04300090E00035D8F84001C72
-:102CA0000A000B078FBF0058240500360E000E32B5
-:102CB000000030210A000B078FBF00580E0003529E
-:102CC00002402021920200058F84001C3442002023
-:102CD0000E00035DA20200050E0010438F84001C4D
-:102CE0008FBF00588FB300548FB200508FB1004C8B
-:102CF0008FB0004803E0000827BD00603C02800858
-:102D0000344501003C0280008C42014094A3000E37
-:102D10000000302100402021AF82001C3063FFFF03
-:102D20003402FFFF106200063C0760202402FFFF10
-:102D3000A4A2000E94A500DA0A0008FA30A5FFFF4D
-:102D400003E000080000000027BDFFC83C0280002F
-:102D50003C068008AFB5002CAFB1001CAFBF0030FF
-:102D6000AFB40028AFB30024AFB20020AFB000185A
-:102D70003451010034C501008C4301008E2200143F
-:102D80008CA400D40000A821AF83001C00441023B1
-:102D900018400052A38000188E2200140000502119
-:102DA000ACA200D490C3000890A200C53073007F8D
-:102DB000A3A200108CB200D08CB400D4304200FF2B
-:102DC0001053003B93A200108F83001C2407FF8048
-:102DD000000211C00062102124420240246300401E
-:102DE000004710243063007F3C0980003C08800AC3
-:102DF00000681821AD2200248C62003427A400143E
-:102E000027A50010024280210290102304400028D0
-:102E1000AFA300149062003C00E21024304200FF97
-:102E200014400019020090219062003C344200409E
-:102E3000A062003C8F86001C93A3001024C20040B7
-:102E40003042007F004828213C0208008C4200F4F8
-:102E500024630001306400FF14820002A3A3001069
-:102E6000A3A0001093A20010AFA50014000211C08F
-:102E70002442024000C2102100471024AD22002449
-:102E80000A000B3E93A200100E0007BC00000000D9
-:102E90003C02800834420100AC5000D093A30010E3
-:102EA000240A0001A04300C50A000B3E93A20010B3
-:102EB00024020001154200093C0380008C62027864
-:102EC0000440FFFE8F82001CAC620240240200021C
-:102ED000A06202443C021000AC6202789222000B15
-:102EE00024030002304200FF14430072000000007F
-:102EF00096220008304300FF240200821462004042
-:102F0000240200843C028000344901008D22000C20
-:102F100095230006000216023063FFFF3045003F94
-:102F20002402002710A2000FAF83001428A200285B
-:102F300010400008240200312402002110A20009E0
-:102F40002402002510A20007938200190A000BB684
-:102F50000000000010A20007938200190A000BB6BF
-:102F6000000000000E000770012020210A000C362E
-:102F7000000000003C0380008C6202780440FFFEE9
-:102F80008F82001CAC62024024020002A062024454
-:102F90003C021000AC6202780A000C36000000000F
-:102FA00095230006912400058D25000C8D26001028
-:102FB0008D2700188D28001C8D2900202442000137
-:102FC0003C010800A423530E3C010800A024530D2B
-:102FD0003C010800AC2553143C010800AC265318F2
-:102FE0003C010800AC2753203C010800AC285324C6
-:102FF0003C010800AC2953280A000C36A3820019B2
-:103000001462000A240200813C028008344201005C
-:10301000944500DA922600058F84001C30A5FFFF3E
-:1030200030C600FF0A000BF73C0760211462005C09
-:10303000000000009222000A304300FF30620020AE
-:1030400010400007306200403C028008344201001A
-:10305000944500DA8F84001C0A000BF5240600401A
-:1030600010400007000316003C02800834420100B3
-:10307000944500DA8F84001C0A000BF524060041F9
-:1030800000021603044100463C028008344201005D
-:10309000944500DA8F84001C2406004230A5FFFF0F
-:1030A0003C0760190E0008FA000000000A000C3608
-:1030B000000000009222000B24040016304200FFA2
-:1030C000104400063C0680009222000B24030017E7
-:1030D000304200FF144300320000000034C50100FC
-:1030E00090A2000B304200FF1444000B000080212E
-:1030F0008CA200208CA400202403FF800043102415
-:10310000000211403084007F004410253C03200061
-:1031100000431025ACC2083094A20008000214003D
-:1031200000021403044200012410000194A20008CC
-:10313000304200805040001A0200A82194A20008EA
-:1031400030422000504000160200A8218CA3001835
-:103150003C021C2D344219ED106200110200A8211E
-:103160003C0208008C4200D4104000053C0280085C
-:103170002403000434420100A04300EC3C02800818
-:1031800034420100944500DA8F84001C24060006B6
-:1031900030A5FFFF0E0008FA3C0760210200A821BD
-:1031A0000E000932000000009222000A304200089E
-:1031B0001040000402A010210E0013470000000080
-:1031C00002A010218FBF00308FB5002C8FB40028D3
-:1031D0008FB300248FB200208FB1001C8FB0001875
-:1031E00003E0000827BD00382402FF80008220246D
-:1031F0003C02900034420007008220253C028000FF
-:10320000AC4400203C0380008C6200200440FFFEA0
-:103210000000000003E00008000000003C03800004
-:103220002402FF80008220243462000700822025CF
-:10323000AC6400208C6200200440FFFE000000000F
-:1032400003E00008000000003C02800824030005A1
-:1032500034420100A04300EC3C0280008C4201009B
-:103260003C038000AF82001C8C6202780440FFFEA9
-:103270008F82001CAC62024024020002A062024461
-:103280003C021000AC62027803E00008000000007D
-:1032900027BDFFE83C068000AFBF001034C7010027
-:1032A00094E20008304400FF3883008238820084B2
-:1032B0002C6300012C420001006218251060002DD3
-:1032C0002402008393820019504000368FBF001003
-:1032D0003C020800904253148CC401003C060800D4
-:1032E00094C6530E3045003F38A3003238A2003F49
-:1032F0002C6300012C42000100621825AF84001CE1
-:10330000AF860014A38000191460000700E020219C
-:103310002402002014A20012000000003402FFFF6B
-:1033200014C2000F000000002402002014A20005B7
-:1033300000E028218CE300142402FFFF5062000B00
-:103340008FBF00103C040800248453080000302183
-:103350000E0006FF240700010A000CA98FBF001011
-:103360000E000770000000008FBF00100A00093235
-:1033700027BD0018148200062482FF808CC301043C
-:103380003C026020AC4300140A000CDF8FBF001029
-:10339000304200FF2C4200021040000424020022B0
-:1033A0008FBF00100A000B2027BD001814820004F4
-:1033B0008F8200248FBF00100A000C6027BD001808
-:1033C0008C42000C1040001E00E0282190E3000910
-:1033D0002402001814620003240200160A000CCA1A
-:1033E00024030008146200072402001724030012BB
-:1033F0003C02800834420080A04300090A000CD738
-:1034000094A700085462000794A700088F82FF9CCD
-:103410002404FFFE9043000500641824A043000527
-:1034200094A7000890A6001B8CA4000094A5000699
-:103430008FBF001000073C000A0008D527BD001808
-:103440008FBF001003E0000827BD00188F850024FF
-:103450003C04800094A2002A8CA30034000230C0F7
-:103460002402FFF000C2102400621821AC83003C4B
-:103470008CA200303C038000AC8200383C0200503B
-:1034800034420010AC620030000000000000000078
-:10349000000000008C620000304200201040FFFD60
-:1034A00030C20008104000063C0280008C62040814
-:1034B000ACA200208C62040C0A000D02ACA2002415
-:1034C0008C430400ACA300208C420404ACA2002472
-:1034D0003C0300203C028000AC4300303C048000F0
-:1034E0008C820030004310241440FFFD8F8600249E
-:1034F0003C020040AC82003094C3002A94C20028F1
-:1035000094C4002C94C5002E2463000100441021B3
-:103510003064FFFFA4C2002814850002A4C3002A5F
-:10352000A4C0002A03E00008000000008F840024EB
-:1035300027BDFFE83C05800424840010AFBF0010C5
-:103540000E000E152406000A8F84002494820012B7
-:103550009483002E3042000F2442000300431804DD
-:1035600024027FFF0043102B10400002AC830000B8
-:103570000000000D0E000CE1000000008F8300240D
-:103580008FBF001027BD0018946200149463001AC6
-:103590003042000F00021500006218253C02800036
-:1035A00003E00008AC4300A08F8300243C028004A9
-:1035B000944400069462001A8C650000A46400160E
-:1035C000004410233042FFFF0045102B03E00008A9
-:1035D000384200018F8400243C0780049486001A3E
-:1035E0008C85000094E20006A482001694E3000695
-:1035F00000C310233042FFFF0045102B384200016A
-:103600001440FFF8A483001603E000080000000047
-:103610008F8400243C028004944200069483001AA4
-:103620008C850000A4820016006210233042FFFF48
-:103630000045102B384200015040000D8F850024BA
-:10364000006030213C07800494E20006A48200164A
-:1036500094E3000600C310233042FFFF0045102B07
-:10366000384200011440FFF8A48300168F8500241F
-:103670003C038000346204008CA40020AF82002050
-:10368000AC6400388CA20024AC62003C3C02000513
-:10369000AC62003003E00008ACA000048F8400247A
-:1036A0003C0300068C8200040002114000431025F8
-:1036B0003C038000AC62003000000000000000000D
-:1036C000000000008C620000304200101040FFFD3E
-:1036D00034620400AC80000403E00008AF820020E4
-:1036E0008F86002427BDFFE0AFB10014AFB00010FB
-:1036F000AFBF00188CC300048CC500248F8200204B
-:10370000309000FF94C4001A24630001244200207A
-:103710002484000124A70020ACC30004AF82002051
-:10372000A4C4001AACC7002404A10006000088212C
-:1037300004E2000594C2001A8CC200202442000159
-:10374000ACC2002094C2001A94C300282E040001C9
-:10375000004310262C420001004410245040000574
-:1037600094C2001A24020001ACC2000894C2001ADC
-:1037700094C300280010202B004310262C42000187
-:103780000044102514400007000000008CC200080F
-:1037900014400004240200108CC300041462000FC3
-:1037A0008F8500240E000D75241100018F820024E6
-:1037B000944300289442001A1443000300000000C0
-:1037C0000E000CE100000000160000048F850024AC
-:1037D0000E000D52000000008F85002494A2001EF0
-:1037E00094A4001C244200013043FFFF1464000233
-:1037F000A4A2001EA4A0001E1200000A3C02800425
-:1038000094A2001494A3001A3042000F0002150085
-:10381000006218253C028000AC4300A00A000DECB9
-:10382000ACA000089442000694A3001A8CA40000E7
-:10383000A4A20016006210233042FFFF0044102BA8
-:10384000384200011040000D02201021006030219C
-:103850003C07800494E20006A4A2001694E300064C
-:1038600000C310233042FFFF0044102B38420001F8
-:103870001440FFF8A4A30016022010218FBF0018E7
-:103880008FB100148FB0001003E0000827BD0020A6
-:1038900003E00008000000008F82002C3C030006BB
-:1038A00000021140004310253C038000AC62003050
-:1038B0000000000000000000000000008C6200001A
-:1038C000304200101040FFFD34620400AF82002837
-:1038D00003E00008AF80002C03E000080000102186
-:1038E00003E00008000000003084FFFF30A5FFFF68
-:1038F0000000182110800007000000003082000145
-:103900001040000200042042006518210A000E0B3E
-:103910000005284003E000080060102110C00006E8
-:1039200024C6FFFF8CA2000024A50004AC82000086
-:103930000A000E152484000403E0000800000000C3
-:1039400010A0000824A3FFFFAC86000000000000C8
-:10395000000000002402FFFF2463FFFF1462FFFA4F
-:103960002484000403E00008000000003C028008FA
-:103970003442008024030001AC43000CA443001037
-:10398000A4430012A443001403E00008A44300165B
-:103990008F82002427BDFFD8AFB3001CAFB2001840
-:1039A000AFB10014AFB00010AFBF00208C47000CC7
-:1039B000248200802409FF803C08800E3043007F71
-:1039C000008080213C0A80000049202400681821E2
-:1039D00030B100FF30D200FF10E000290000982134
-:1039E00026020100AD44002C004928243042007F0B
-:1039F000004820219062000024030050304200FF64
-:103A00001443000400000000AD45002C948200DA4D
-:103A10003053FFFF0E000D52000000008F82002483
-:103A20008F83002000112C009442001E00122400FD
-:103A30003484000100A228253C02400000A2282571
-:103A4000AC7000008FBF0020AC6000048FB2001883
-:103A5000AC7300088FB10014AC60000C8FB3001C75
-:103A6000AC6400108FB00010AC600014240400019E
-:103A7000AC60001827BD00280A000D86AC65001C4C
-:103A80008FBF00208FB3001C8FB200188FB10014BD
-:103A90008FB0001003E0000827BD00283C0680001E
-:103AA00034C201009043000F240200101062000E87
-:103AB0002865001110A0000724020012240200084B
-:103AC0002405003A106200060000302103E00008DF
-:103AD00000000000240500351462FFFC00003021C6
-:103AE0000A000E32000000008CC200748F83FF9C1D
-:103AF00024420FA003E00008AC62000C27BDFFE8E1
-:103B0000AFBF00100E000362240500013C048008D2
-:103B10008FBF00102402000134830080A4620012D1
-:103B200027BD00182402000103E00008A080001A4D
-:103B300027BDFFE0AFB20018AFB10014AFB0001066
-:103B4000AFBF001C30B2FFFF0E000352008088217F
-:103B50003C028008345000809202000924030004D3
-:103B6000304200FF1443000C3C0280081240000861
-:103B70002402000A0E000E29000000009202000537
-:103B80002403FFFE00431024A202000524020012B9
-:103B9000A20200093C028008344200800220202159
-:103BA0000E00035DA04000271640000302202021E4
-:103BB0000E000E8D0000000002202021324600FF82
-:103BC0008FBF001C8FB200188FB100148FB000108F
-:103BD000240500380A000E3227BD002027BDFFE073
-:103BE000AFBF001CAFB20018AFB10014AFB00010EF
-:103BF0000E000352008080210E000E2900000000FC
-:103C00003C0280083445008090A20009241200186C
-:103C1000305100FF12320003020020212402001262
-:103C2000A0A2000990A200052403FFFE0043102477
-:103C30000E00035DA0A20005020020212405002043
-:103C400016320007000030218FBF001C8FB2001811
-:103C50008FB100148FB000100A00036227BD00204E
-:103C60008FBF001C8FB200188FB100148FB00010EE
-:103C7000240500390A000E3227BD002027BDFFE8C9
-:103C80003C028000AFB00010AFBF0014344201000E
-:103C90009442000C2405003600808021144000125C
-:103CA000304600FF0E000352000000003C02800876
-:103CB0003442008024030012A04300099043000511
-:103CC000346300100E000E29A04300050E00035DB2
-:103CD00002002021020020210E00036224050020A2
-:103CE0000A000F0A000000000E000E320000000063
-:103CF0000E000352020020213C0280089043001B6A
-:103D00002405FF9F02002021006518248FBF0014A6
-:103D10008FB00010A043001B0A00035D27BD0018F0
-:103D200027BDFFE0AFBF0018AFB10014AFB0001067
-:103D300030B100FF0E000352008080213C02800859
-:103D400024030012344200800E000E29A043000913
-:103D50000E00035D020020210200202102203021FC
-:103D60008FBF00188FB100148FB0001024050035EC
-:103D70000A000E3227BD00203C0480089083000E0C
-:103D80009082000A1443000B000028218F82FF9CC0
-:103D9000240300502405000190420000304200FF3F
-:103DA00014430004000000009082000E2442000131
-:103DB000A082000E03E0000800A010213C03800058
-:103DC0008C6201F80440FFFE24020002AC6401C0D2
-:103DD000A06201C43C02100003E00008AC6201F8DC
-:103DE00027BDFFE0AFB200183C128008AFB100144D
-:103DF000AFBF001CAFB00010365100809222000906
-:103E00002403000A304200FF1443003E000000007B
-:103E10008E4300048E220038506200808FBF001C49
-:103E20009222000024030050304200FF144300257A
-:103E30003C0280008C4201408E4300043642010067
-:103E400002202821AC43001C9622005C8E230038FF
-:103E50003042FFFF0002104000621821AE23001C18
-:103E60008E4300048E2400389622005C00641823E0
-:103E70003042FFFF00031843000210400043102AA5
-:103E800010400006000000008E4200048E2300381F
-:103E9000004310230A000F78000220439622005CA2
-:103EA0003042FFFF000220403C0280083443010002
-:103EB00034420080ACA4002CA04000242402000165
-:103EC000A062000C0E000F2C0000000010400053F8
-:103ED0008FBF001C3C0280008C4401403C038000EA
-:103EE0008C6201F80440FFFE24020002AC6401C0B1
-:103EF000A06201C43C021000AC6201F80A000FD5B8
-:103F00008FBF001C9222000924030010304200FFE2
-:103F1000144300043C0280008C4401400A000FBCA2
-:103F2000000028219222000924030016304200FFDD
-:103F30001443000624020014A22200093C0280005F
-:103F40008C4401400A000FCF8FBF001C8E22003826
-:103F50008E23003C00431023044100308FBF001C1F
-:103F60009222002724420001A22200279222002749
-:103F70002C420004144000163C10800092220009DC
-:103F800024030004304200FF144300093C02800077
-:103F90008C4401408FBF001C8FB200188FB10014F9
-:103FA0008FB00010240500930A000E9A27BD002050
-:103FB0008C440140240500938FBF001C8FB2001871
-:103FC0008FB100148FB000100A000F1627BD00201B
-:103FD0008E0401400E000352000000008E420004D7
-:103FE0002442FFFFAE4200048E22003C2442FFFF29
-:103FF000AE22003C0E00035D8E0401408E040140A1
-:104000008FBF001C8FB200188FB100148FB000104A
-:10401000240500040A00036227BD00208FB20018A7
-:104020008FB100148FB0001003E0000827BD0020FE
-:104030003C0680008CC201883C0380083465008007
-:104040009063000E00021402304400FF306300FF52
-:104050001464000E3C02800890A20026304200FF4B
-:10406000104400098F82FF9CA0A400262403005066
-:1040700090420000304200FF1443000600000000A0
-:104080000A00059A8CC401803C02800834420080FA
-:10409000A044002603E000080000000027BDFFE068
-:1040A00030E700FFAFB20018AFBF001CAFB1001483
-:1040B000AFB000100080902114E0000630C600FF71
-:1040C000000000000000000D000000000A00102E9B
-:1040D0002400010E3C0380089062000E304200FF75
-:1040E000144600233462008090420026304200FFD4
-:1040F0001446001F000000009062000F304200FFD5
-:104100001446001B000000009062000A304200FFCD
-:10411000144600038F90FF9C0000000D8F90FF9CC1
-:104120008F82FFA03C118000AE05003CAC45000032
-:10413000A066000A0E0003528E240100A200002493
-:104140000E00035D8E2401003C0380008C6201F8A8
-:104150000440FFFE24020002AC7201C0A06201C450
-:104160003C021000AC6201F80A00102F8FBF001C47
-:10417000000000000000000D0000000024000137D6
-:104180008FBF001C8FB200188FB100148FB00010C9
-:1041900003E0000827BD00208F83FF9C3C028000C5
-:1041A0008C440100344201008C65003C9046001BA9
-:1041B0000A000FF5240700013C0280089043000E1E
-:1041C0009042000A00431026304200FF03E000083E
-:1041D0000002102B27BDFFE03C028008AFB10014A5
-:1041E000AFB00010AFBF001834500080920200053D
-:1041F00024030030304200301443008500808821C1
-:104200008F8200248C42000C104000828FBF001867
-:104210000E000D52000000008F860020ACD100007F
-:104220009202000892030009304200FF00021200CF
-:10423000306300FF00431025ACC200049202004D21
-:1042400000021600000216030441000500000000F1
-:104250003C0308008C6300480A00106D3C10800885
-:104260009202000830420040144000030000182170
-:1042700092020027304300FF3C1080083611008076
-:104280009222004D00031E00304200FF0002140085
-:1042900000621825ACC300088E2400308F820024F1
-:1042A000ACC4000C8E2500349443001E3C02C00BAD
-:1042B000ACC50010006218258E22003800002021B5
-:1042C000ACC200148E22003CACC200180E000D8659
-:1042D000ACC3001C8E0200048F8400203C058000CB
-:1042E000AC8200008E220020AC8200048E22001CD2
-:1042F000AC8200088E2200588CA300740043102169
-:10430000AC82000C8E22002CAC8200108E22004069
-:104310008E2300440002140000431025AC820014D8
-:104320009222004D24030080304200FF1443000419
-:1043300000000000AC8000180A0010B18F82002439
-:104340008E23000C240200011062000E2402FFFFE5
-:1043500092220008304200401440000A2402FFFF6D
-:104360008E23000C8CA20074006218233C0208000B
-:10437000006210241440000200002821006028215F
-:1043800000051043AC8200188F8200240000202119
-:104390009443001E3C02C00C006218258F8200204E
-:1043A0000E000D86AC43001C3C0380083462010003
-:1043B0008C4200008F850020346300808FBF00187E
-:1043C000ACA20000ACA000048C6400488F820024E2
-:1043D0008FB10014ACA40008ACA0000CACA000107D
-:1043E000906300059446001E3C02400D00031E0031
-:1043F00000C23025ACA300148FB00010ACA0001890
-:1044000024040001ACA6001C0A000D8627BD002074
-:104410008FBF00188FB100148FB0001003E00008A8
-:1044200027BD00203C0280009443007C3C028008B1
-:1044300034460100308400FF3065FFFF2402000590
-:1044400024A34650A0C4000C5482000C3065FFFF2A
-:1044500090C2000D2C4200071040000724A30A0060
-:1044600090C3000D240200140062100400A2102169
-:104470000A0010ED3045FFFF3065FFFF3C02800869
-:104480003442008003E00008A44500143C03800887
-:1044900034680080AD050038346701008CE2001CF0
-:1044A000308400FF00A210231840000330C600FF34
-:1044B00024A2FFFCACE2001C308200015040000846
-:1044C0003C0380088D02003C00A21023044100122E
-:1044D000240400058C62000410A2000F3C03800835
-:1044E0008C62000414A2001E000000003C020800C0
-:1044F0008C4200D830420020104000093C02800865
-:1045000034620080906300089042004C1443000421
-:104510003C028008240400040A0010D700000000B8
-:104520003443008034420100A040000C240200010A
-:10453000A462001410C0000A3C0280008C440100F8
-:104540003C0380008C6201F80440FFFE240200025C
-:10455000AC6401C0A06201C43C021000AC6201F86E
-:1045600003E000080000000027BDFFE800A61823B4
-:10457000AFBF001018600080308800FF3C02800848
-:1045800034470080A0E0002434440100A0E000276C
-:104590008C82001C00A21023044000560000000082
-:1045A0008CE2003C94E3005C8CE4002C004530235A
-:1045B0003063FFFF00C318210083202B108000040C
-:1045C00000E018218CE2002C0A00114600A2102104
-:1045D00094E2005C3042FFFF00C2102100A21021D3
-:1045E000AC62001C3C028008344400809482005C71
-:1045F0008C83001C3042FFFF0002104000A21021FB
-:104600000043102B10400004000000008C82001CAE
-:104610000A0011593C0680089482005C3042FFFF7A
-:104620000002104000A210213C06800834C30100A3
-:1046300034C70080AC82001CA060000CACE50038E0
-:104640008C62001C00A210231840000224A2FFFC70
-:10465000AC62001C31020001104000083C038008DD
-:104660008CE2003C00A21023044100122404000547
-:104670008CC2000410A200108FBF00108C620004D6
-:1046800014A2004F8FBF00103C0208008C4200D8DB
-:10469000304200201040000A3C0280083462008052
-:1046A000906300089042004C144300053C028008CF
-:1046B000240400048FBF00100A0010D727BD001883
-:1046C0003443008034420100A040000C2402000169
-:1046D000A46200143C0280008C4401003C03800072
-:1046E0008C6201F80440FFFE240200020A0011A6B9
-:1046F000000000008CE2001C004610230043102B39
-:1047000054400001ACE5001C94E2005C3042FFFF25
-:104710000062102B144000072402000294E2005CA7
-:104720008CE3001C3042FFFF00621821ACE3001C48
-:1047300024020002ACE500380E000F2CA082000C11
-:104740001040001F8FBF00103C0280008C4401000D
-:104750003C0380008C6201F80440FFFE240200024A
-:10476000AC6401C0A06201C43C021000AC6201F85C
-:104770000A0011BE8FBF001031020010104000105F
-:104780008FBF00103C028008344500808CA3001CC1
-:1047900094A2005C006618233042FFFF00621821DB
-:1047A0003C023FFF3444FFFF0083102B54400001C4
-:1047B0000080182100C31021ACA2001C8FBF001084
-:1047C00003E0000827BD001827BDFFE800C0402116
-:1047D00000A63023AFBF001018C00026308A00FFAB
-:1047E0003C028008344900808D24001C8D23002C5D
-:1047F000008820230064182B1060000F344701004C
-:104800008CE2002000461021ACE200208CE2002067
-:104810000044102B1440000B3C023FFF8CE20020B0
-:1048200000441023ACE200209522005C3042FFFFE0
-:104830000A0011DE00822021ACE000200086202149
-:104840003C023FFF3443FFFF0064102B5440000143
-:10485000006020213C02800834420080008518213D
-:10486000AC43001CA0400024A04000270A001230E6
-:104870003C03800831420010104000433C03800894
-:104880003C06800834C400808C82003C0048102321
-:104890005840003E3466008090820024244200018B
-:1048A000A0820024908200243C0308008C63002432
-:1048B000304200FF0043102B144000688FBF0010EF
-:1048C00034C201008C42001C00A210231840006377
-:1048D000000000008CC300049482005C0068182370
-:1048E0003042FFFF00031843000210400043102A2B
-:1048F00010400005000000008CC200040048102396
-:104900000A001213000210439482005C3042FFFF41
-:10491000000210403C068008AC82002C34C50080A8
-:1049200094A2005C8CA4002C94A3005C3042FFFF96
-:1049300000021040008220213063FFFF008320210D
-:1049400001041021ACA2001C8CC2000434C601007A
-:10495000ACC2001C240200020E000F2CA0C2000CEE
-:104960001040003E8FBF00103C0280008C440100CC
-:104970003C0380008C6201F80440FFFE2402000228
-:104980000A0012600000000034660080ACC50038E8
-:10499000346401008C82001C00A210231840000225
-:1049A00024A2FFFCAC82001C314200015040000AEE
-:1049B0003C0380088CC2003C00A210230443001476
-:1049C000240400058C62000414A200033C03800848
-:1049D0000A001252240400058C62000414A2001F75
-:1049E0008FBF00103C0208008C4200D830420020EB
-:1049F0001040000A3C028008346200809063000886
-:104A00009042004C144300053C028008240400043A
-:104A10008FBF00100A0010D727BD00183443008054
-:104A200034420100A040000C24020001A4620014E2
-:104A30003C0280008C4401003C0380008C6201F841
-:104A40000440FFFE24020002AC6401C0A06201C465
-:104A50003C021000AC6201F88FBF001003E00008B8
-:104A600027BD001827BDFFE83C0A8008AFBF001033
-:104A7000354900808D22003C00C04021308400FF79
-:104A8000004610231840009D30E700FF3547010025
-:104A90002402000100A63023A0E0000CA0E0000DDD
-:104AA000A522001418C00024308200108D23001CA1
-:104AB0008D22002C006818230043102B1040000F9B
-:104AC000000000008CE2002000461021ACE2002033
-:104AD0008CE200200043102B1440000B3C023FFFEF
-:104AE0008CE2002000431023ACE200209522005C01
-:104AF0003042FFFF0A00128F00621821ACE0002054
-:104B0000006618213C023FFF3446FFFF00C3102B14
-:104B10005440000100C018213C028008344200804B
-:104B200000651821AC43001CA0400024A0400027D1
-:104B30000A0012DD3C038008104000403C0380085E
-:104B40008D22003C004810235840003D346700800F
-:104B50009122002424420001A12200249122002459
-:104B60003C0308008C630024304200FF0043102BFC
-:104B70001440009A8FBF00108CE2001C00A210238A
-:104B800018400096000000008D4300049522005C50
-:104B9000006818233042FFFF000318430002104052
-:104BA0000043102A10400005012020218D420004FE
-:104BB000004810230A0012C0000210439522005C36
-:104BC0003042FFFF000210403C068008AC82002CFF
-:104BD00034C5008094A2005C8CA4002C94A3005CDB
-:104BE0003042FFFF00021040008220213063FFFFAF
-:104BF0000083182101031021ACA2001C8CC2000408
-:104C000034C60100ACC2001C240200020E000F2CAE
-:104C1000A0C2000C104000718FBF00103C02800049
-:104C20008C4401003C0380008C6201F80440FFFECC
-:104C3000240200020A00130700000000346700800D
-:104C4000ACE50038346601008CC2001C00A21023C1
-:104C50001840000224A2FFFCACC2001C30820001FC
-:104C6000504000083C0380088CE2003C00A2102366
-:104C700004430051240400058C62000410A2003E8D
-:104C80003C0380088C62000454A200548FBF0010C3
-:104C90003C0208008C4200D8304200201040000640
-:104CA0003C02800834620080906300089042004C0F
-:104CB000104300403C02800834430080344201002D
-:104CC000A040000C24020001A46200143C028000F9
-:104CD0008C4401003C0380008C6201F80440FFFE1C
-:104CE00024020002AC6401C0A06201C43C021000B6
-:104CF000AC6201F80A0013458FBF001024020005C2
-:104D0000A120002714E2000A3C038008354301007B
-:104D10009062000D2C420006504000053C038008C4
-:104D20009062000D24420001A062000D3C03800847
-:104D300034670080ACE50038346601008CC2001C8A
-:104D400000A210231840000224A2FFFCACC2001CE9
-:104D5000308200015040000A3C0380088CE2003C95
-:104D600000A2102304410014240400058C620004F6
-:104D700014A200033C0380080A00133C240400052D
-:104D80008C62000414A200158FBF00103C020800C2
-:104D90008C4200D8304200201040000A3C028008BB
-:104DA00034620080906300089042004C1443000578
-:104DB0003C028008240400048FBF00100A0010D7B2
-:104DC00027BD00183443008034420100A040000C8D
-:104DD00024020001A46200148FBF001003E0000849
-:104DE00027BD00183C0B800827BDFFE83C0280006F
-:104DF000AFBF001034420100356A00809044000AC1
-:104E0000356901008C4500148D4800389123000C51
-:104E1000308400FF010510231C4000B3306700FF01
-:104E20002CE20006504000B18FBF001024020001A8
-:104E300000E2300430C200035440000800A83023D0
-:104E400030C2000C144000A130C20030144000A356
-:104E50008FBF00100A0014090000000018C00024D1
-:104E6000308200108D43001C8D42002C00681823F6
-:104E70000043102B1040000F000000008D22002086
-:104E800000461021AD2200208D2200200043102B6F
-:104E90001440000B3C023FFF8D22002000431023F2
-:104EA000AD2200209542005C3042FFFF0A00137DD6
-:104EB00000621821AD200020006618213C023FFF4F
-:104EC0003446FFFF00C3102B5440000100C01821DE
-:104ED0003C0280083442008000651821AC43001C6D
-:104EE000A0400024A04000270A0013CB3C03800808
-:104EF000104000403C0380088D42003C00481023D5
-:104F00001840003D34670080914200242442000193
-:104F1000A1420024914200243C0308008C63002439
-:104F2000304200FF0043102B144000708FBF001070
-:104F30008D22001C00A210231840006C000000000D
-:104F40008D6300049542005C006818233042FFFF27
-:104F500000031843000210400043102A10400005CF
-:104F6000014020218D620004004810230A0013AE86
-:104F7000000210439542005C3042FFFF00021040E7
-:104F80003C068008AC82002C34C5008094A2005CF2
-:104F90008CA4002C94A3005C3042FFFF0002104060
-:104FA000008220213063FFFF0083182101031021BC
-:104FB000ACA2001C8CC2000434C60100ACC2001CB0
-:104FC000240200020E000F2CA0C2000C104000476B
-:104FD0008FBF00103C0280008C4401003C03800025
-:104FE0008C6201F80440FFFE240200020A0013FB59
-:104FF0000000000034670080ACE500383466010032
-:105000008CC2001C00A210231840000224A2FFFC46
-:10501000ACC2001C308200015040000A3C038008F2
-:105020008CE2003C00A21023044300142404000579
-:105030008C62000414A200033C0380080A0013EDF4
-:10504000240400058C62000414A200288FBF001005
-:105050003C0208008C4200D8304200201040000A78
-:105060003C02800834620080906300089042004C4B
-:10507000144300053C028008240400048FBF001084
-:105080000A0010D727BD00183443008034420100C5
-:10509000A040000C24020001A46200143C02800025
-:1050A0008C4401003C0380008C6201F80440FFFE48
-:1050B00024020002AC6401C0A06201C43C021000E2
-:1050C000AC6201F80A0014098FBF00108FBF0010F6
-:1050D000010030210A00112827BD001801003021ED
-:1050E0000A00126727BD00188FBF001003E00008F8
-:1050F00027BD00183C03800834640100240200032B
-:10510000A082000C8C62000403E00008AC82001C4A
-:105110003C05800834A300809062002734A501007C
-:105120002406004324420001A06200279063002768
-:105130003C0208008C420048306300FF1462000407
-:105140003C07602194A500DA0A0008FA30A5FFFFA9
-:1051500003E000080000000027BDFFE8AFBF00101B
-:105160003C0280000E0014128C4401803C02800836
-:1051700034430100A060000C8C4200048FBF00107B
-:1051800027BD001803E00008AC62001C27BDFFE04B
-:105190003C028008AFBF0018AFB10014AFB00010E0
-:1051A00034450080344601003C0880008D090140F0
-:1051B00090C3000C8CA4003C8CA200381482003BED
-:1051C000306700FF9502007C90A30027146000095F
-:1051D0003045FFFF2402000554E200083C0480082B
-:1051E00090C2000D24420001A0C2000D0A00144D1F
-:1051F0003C048008A0C0000D3C04800834820100FB
-:105200009042000C24030005304200FF1443000AC2
-:1052100024A205DC34830080906200272C42000722
-:105220005040000524A20A009063002724020014C5
-:105230000062100400A210213C108008361000808B
-:105240003045FFFF012020210E001412A605001496
-:105250009602005C8E0300383C1180003042FFFF54
-:105260000002104000621821AE03001C0E00035221
-:105270008E2401409202002534420040A202002503
-:105280000E00035D8E2401408E2401403C0380000B
-:105290008C6201F80440FFFE24020002AC6401C0ED
-:1052A000A06201C43C021000AC6201F88FBF00187C
-:1052B0008FB100148FB0001003E0000827BD00205C
-:1052C00080080100800800808008000000000C8039
-:1052D000000032008008024008000F1008000F682C
-:1052E00008000FAC0800104408001084800801007A
-:0852F000800800808008000026
-:0852F8000A0000220000000082
-:10530000000000000000000D6370352E302E306A62
-:10531000313500000500000400000000000000001E
-:1053200000000000000000000000000038003C0009
-:10533000000000000000000000000000000000006D
-:10534000000000200000000000000000000000003D
-:10535000000000000000000000000000000000004D
-:1053600000000000000000000000000021003800E4
-:10537000000000010000002B000000000000000001
-:105380000000000010000003000000000000000DFD
-:105390000000000D3C020800244255043C030800B4
-:1053A00024635744AC4000000043202B1480FFFDD1
-:1053B000244200043C1D080037BD9FFC03A0F021DF
-:1053C0003C100800261000883C1C0800279C55044F
-:1053D0000E00029A000000000000000D00A018213D
-:1053E00000801021008028213C0460003C07600000
-:1053F0002406000810600006348420788C420000E7
-:10540000ACE220088C63000003E00008ACE3200C51
-:105410000A000E6000000000240300403C0260000F
-:1054200003E00008AC4320003C0760008F860004C6
-:105430008CE520740086102100A2182B1460000750
-:10544000000028218F8AFD9024050001A14400134B
-:105450008F89000401244021AF88000403E0000884
-:1054600000A010218F84FD908F850004908600138A
-:1054700030C300FF00A31023AF82000403E0000844
-:10548000A08000138F84FD9027BDFFE8AFB000100F
-:10549000AFBF0014908900119087001124020028EA
-:1054A000312800FF3906002830E300FF2485002C56
-:1054B0002CD00001106200162484001C0E0000395C
-:1054C000000000008F8FFD903C0560002402020464
-:1054D00095EE003E95ED003C000E5C0031ACFFFF08
-:1054E000016C5025ACAA20105200000124020004D7
-:1054F000ACA220000000000000000000000000003E
-:105500008FBF00148FB0001003E0000827BD001803
-:105510000A000071000028218F85FD9027BDFFD86B
-:10552000AFBF0020AFB3001CAFB20018AFB1001482
-:10553000AFB000100080982190A4001124B0001C8E
-:1055400024B1002C308300FF386200280E00005B7D
-:105550002C5200010E000063000000000200202118
-:105560001240000202202821000028210E000039EC
-:10557000000000008F8DFD903C0880003C0560001D
-:1055800095AC003E95AB003C02683025000C4C0009
-:10559000316AFFFF012A3825ACA72010240202023D
-:1055A000ACA6201452400001240200028FBF00204C
-:1055B0008FB3001C8FB200188FB100148FB0001091
-:1055C00027BD002803E00008ACA2200027BDFFE0B3
-:1055D000AFB20018AFB10014AFB00010AFBF001CE5
-:1055E0003C1160008E2320748F82000430D0FFFFB6
-:1055F00030F2FFFF1062000C2406008F0E0000390D
-:10560000000000003C06801F0010440034C5FF006D
-:105610000112382524040002AE272010000030219A
-:10562000AE252014AE2420008FBF001C8FB20018BE
-:105630008FB100148FB0001000C0102103E00008EB
-:1056400027BD002027BDFFE0AFB0001030D0FFFF26
-:10565000AFBF0018AFB100140E00003930F1FFFFEA
-:1056600000102400009180253C036000AC702010E5
-:105670008FBF00188FB100148FB0001024020004F7
-:10568000AC62200027BD002003E0000800001021CC
-:1056900027BDFFE83C0B6018AFBF00108D6F5000B6
-:1056A0002418FF7F340C807101F8702435CD380C3C
-:1056B000240A00313C098000AD6D50003C08800A8E
-:1056C000AD6C53BCAD2A00080E0004D1AF88004079
-:1056D0000E00048F000000000E00004800000000D3
-:1056E0003C0760008CE508082406FFF03C035709DE
-:1056F00000A620243462F000108200622419000108
-:10570000AF80004C0E000BF2000000003C0660165B
-:105710003C0760148CC400008CE500A03C03FFFF34
-:10572000008310243C1F535300052FC2105F004F0D
-:1057300034C77C0094E201F2A780006410400003AB
-:10574000A7800074384B1E1EA78B006494E201F8FA
-:10575000104000048F8D004C384C1E1EA78C007426
-:105760008F8D004C11A0000497840074240E00203B
-:10577000A78E0064978400742C8F008151E0000193
-:1057800024040080978600642CD804015300000193
-:10579000240604003C0260008C4504382419103CA7
-:1057A00030BFFFFF13F900033083FFFF10600018C4
-:1057B00024080050A38000769389007651200019B8
-:1057C000A7840074A7800074978C00748FBF0010AA
-:1057D0003C0A600E24EB0388354600100000382197
-:1057E0000000202127BD0018A78000643C010800AC
-:1057F000AC2C0080AF8B0010AF860048A780006CF7
-:10580000A780008AAF87001803E00008AF84001467
-:10581000A3880076938900765520FFEBA78000745B
-:10582000A7840074978C00748FBF00103C0A600E30
-:1058300024EB0388A7860064000038213546001059
-:105840000000202127BD00183C010800AC2C00807E
-:10585000AF8B0010AF860048A780006CA780008A3D
-:10586000AF87001803E00008AF84001400055080E3
-:10587000014648218D2800043C0660000A00010F03
-:10588000010638210A000103AF99004C3083FFFF65
-:105890008F8800408F87003C000321403C0580003A
-:1058A0003C020050008248253C0660003C0A010092
-:1058B00034AC04008CCD08E001AA58241160000526
-:1058C000000000008CCF08E024E7000101EA702509
-:1058D000ACCE08E08D19001001805821ACB9003819
-:1058E0008D180014ACB8003CACA9003000000000DA
-:1058F00000000000000000000000000000000000A8
-:105900000000000000000000000000003C038000D8
-:105910008C640000308200201040FFFD3C0F6000CE
-:105920008DED08E03C0E010001AE18241460FFE18B
-:1059300000000000AF87003C03E00008AF8B005080
-:105940008F850040240BFFF03C06800094A7001ACE
-:105950008CA9002430ECFFFF000C38C000EB502471
-:10596000012A4021ACC8003C8CA400248CC3003C1C
-:105970000083102318400033000000008CAD00208D
-:1059800025A200013C0F0050ACC2003835EE0010DB
-:105990003C068000ACCE003000000000000000009B
-:1059A00000000000000000000000000000000000F7
-:1059B00000000000000000003C0480008C99000002
-:1059C000333800201300FFFD30E2000810400017BC
-:1059D0003C0980008C880408ACA800108C83040C5F
-:1059E000ACA300143C1900203C188000AF19003013
-:1059F00094AE001894AF001C01CF3021A4A600186B
-:105A000094AD001A25A70001A4A7001A94AB001AB0
-:105A100094AC001E118B00030000000003E000089E
-:105A20000000000003E00008A4A0001A8D2A040072
-:105A3000ACAA00108D240404ACA400140A0001BC1C
-:105A40003C1900208CA200200A0001A43C0F005049
-:105A50000A0001920000000027BDFFE8AFBF001060
-:105A60000E0001D6000000008F8900408FBF00109B
-:105A70003C038000A520000A9528000A9527000411
-:105A800027BD00183105FFFF30E6000F00061500A6
-:105A900000A2202503E00008AC6400803C0508005B
-:105AA0008CA500208F83000C27BDFFE8AFB000104D
-:105AB000AFBF001410A300100000802124040001D7
-:105AC0000204300400A6202400C310245044000621
-:105AD00026100001001018802787FD941480000A0A
-:105AE00000671821261000012E0900025520FFF33F
-:105AF0008F83000CAF85000C8FBF00148FB0001097
-:105B000003E0000827BD00188C6800003C058000F9
-:105B1000ACA800240E0001D8261000013C050800A6
-:105B20008CA500200A0001FD2E09000224050001B9
-:105B3000008518043C0408008C84002027BDFFC8A1
-:105B4000AFBF003400831024AFBE0030AFB7002CCD
-:105B5000AFB60028AFB50024AFB40020AFB3001C2F
-:105B6000AFB20018AFB1001410400051AFB0001038
-:105B70008F840040948700069488000A00E8302350
-:105B800030D5FFFF12A0004B8FBF0034948B00185C
-:105B9000948C000A016C50233142FFFF02A2482B73
-:105BA0001520000202A02021004020212C8F00059A
-:105BB00015E0000200809821241300040E00016506
-:105BC000026020218F87004002609021AF80004456
-:105BD00094F4000A026080211260004E3291FFFFAF
-:105BE0003C1670003C1440003C1E20003C17600036
-:105BF0008F9900508F380000031618241074004F3E
-:105C00000283F82B17E0003600000000107E0047EA
-:105C10008F86004414C0003A2403000102031023BD
-:105C2000022320213050FFFF1600FFF13091FFFFCB
-:105C30008F8700403C1100203C108000AE110030E6
-:105C400094EB000A3C178000024B5021A4EA000AA2
-:105C500094E9000A94E800043123FFFF3106000FA5
-:105C600000062D000065F025AEFE008094F3000ACA
-:105C700094F6001812D30036001221408CFF001455
-:105C80008CF4001003E468210000C02101A4782BEB
-:105C90000298702101CF6021ACED0014ACEC001033
-:105CA00002B2382330F5FFFF16A0FFB88F84004002
-:105CB0008FBF00348FBE00308FB7002C8FB6002806
-:105CC0008FB500248FB400208FB3001C8FB2001852
-:105CD0008FB100148FB0001003E0000827BD00381A
-:105CE0001477FFCC8F8600440E000DC102002021E6
-:105CF000004018218F86004410C0FFC90203102302
-:105D0000027070238F87004001C368210A00028857
-:105D100031B2FFFF8F86004414C0FFC93C11002040
-:105D20003C1080000A000252AE1100300E0003FA4F
-:105D3000020020210A00027F0040182102002021D9
-:105D40000E000811022028210A00027F00401821BD
-:105D50000E000192000000000A00026B02B238231C
-:105D600027BDFFC8AFB7002CAFB60028AFB50024E1
-:105D7000AFB40020AFB3001CAFB20018AFB1001435
-:105D8000AFB00010AFBF00300E0000E624130001DA
-:105D90003C047FFF3C0380083C0220003C010800DB
-:105DA000AC2000703497FFFF34750080345200033C
-:105DB0003C1612C0241400013C1080002411FF8006
-:105DC0000E0001E9000000008F8700488F8B00184B
-:105DD0008F8900148CEA00EC8CE800E8014B302B32
-:105DE0000109282300A6102314400006014B1823A4
-:105DF0001440000E3C05800002C3602B1180000B94
-:105E0000000000003C0560008CEE00EC8CED00E82A
-:105E10008CA4180CAF8E001804800045AF8D0014C0
-:105E20008F8F0010ADF400003C0580008CBF000097
-:105E30003BF90001333800011700FFE13C0380000B
-:105E40008C62010024060C001046000900000000CE
-:105E50008C6801002D043080548000103C048000C8
-:105E60008C6901002D2331811060000C3C048000FE
-:105E70008CAA010011460004000020218CA601001C
-:105E800024C5FF8130A400FF8E0B01000E00020D1F
-:105E9000AE0B00240A0002F33C0480008C8E01004B
-:105EA000240C0020AC8E002092AD000031A300FF36
-:105EB000106C00232407005010670026000000002B
-:105EC0003C0480008C8F010015E0000300000000FE
-:105ED000566000143C0440008C8701008C8D01004A
-:105EE0000000982100F17024000E594031AC007F71
-:105EF000016C302500D22825AC8508308C8A010041
-:105F00008C83010025490100013110240002F94071
-:105F10003068007F03E8C8250332C025AC980830FC
-:105F20003C044000AE0401380A0002B20000000048
-:105F300000973824ACA7180C0A0002CB8F8F0010F2
-:105F40008C8501000E0007C3240400800A0002F3C0
-:105F50003C0480008C8401000E001420000000002E
-:105F60000A0002F33C04800000A4102B240300016B
-:105F700010400009000030210005284000A4102B2B
-:105F800004A00003000318405440FFFC0005284013
-:105F90005060000A0004182B0085382B54E00004E0
-:105FA0000003184200C33025008520230003184257
-:105FB0001460FFF9000528420004182B03E00008D4
-:105FC00000C310213084FFFF30C600FF3C07800073
-:105FD0008CE201B80440FFFE00064C00012430258D
-:105FE0003C08200000C820253C031000ACE00180E4
-:105FF000ACE50184ACE4018803E00008ACE301B83F
-:106000003C0660008CC5201C2402FFF03083020097
-:10601000308601001060000E00A2282434A5000183
-:106020003087300010E0000530830C0034A50004F8
-:106030003C04600003E00008AC85201C1060FFFDFC
-:106040003C04600034A5000803E00008AC85201C77
-:1060500054C0FFF334A500020A00034B3087300020
-:1060600027BDFFE8AFB00010AFBF00143C076000D1
-:10607000240600021080001100A080218F830050B0
-:106080000E0003428C6400188F8200500000202113
-:10609000240600018C45000C0E00033300000000B4
-:1060A0001600000224020003000010218FBF00141C
-:1060B0008FB0001003E0000827BD00188CE8201CFA
-:1060C0002409FFF001092824ACE5201C8F8700502B
-:1060D0000A0003688CE5000C3C02600E0080402141
-:1060E00034460100240900180000000000000000F0
-:1060F000000000003C0A00503C03800035470200CD
-:10610000AC68003834640400AC65003CAC67003017
-:106110008C6C0000318B00201160FFFD2407FFFF15
-:106120002403007F8C8D00002463FFFF248400047F
-:10613000ACCD00001467FFFB24C600040000000083
-:10614000000000000000000024A402000085282BAD
-:106150003C0300203C0E80002529FFFF0105402163
-:10616000ADC300301520FFE00080282103E00008C7
-:10617000000000008F82005027BDFFD8AFB3001C85
-:10618000AFBF0020AFB20018AFB10014AFB0001025
-:1061900094460002008098218C5200182CC3008184
-:1061A0008C4800048C4700088C51000C8C4900106E
-:1061B000106000078C4A00142CC4000414800013E3
-:1061C00030EB000730C5000310A0001000000000F5
-:1061D0002410008B02002021022028210E0003330E
-:1061E00024060003166000022402000300001021B0
-:1061F0008FBF00208FB3001C8FB200188FB1001426
-:106200008FB0001003E0000827BD00281560FFF1E3
-:106210002410008B3C0C80003C030020241F000154
-:10622000AD830030AF9F004400000000000000007C
-:10623000000000002419FFF024D8000F031978246F
-:106240003C1000D0AD88003801F0702524CD00034B
-:106250003C08600EAD87003C35850400AD8E0030F3
-:10626000000D38823504003C3C0380008C6B00003C
-:10627000316200201040FFFD0000000010E0000827
-:1062800024E3FFFF2407FFFF8CA800002463FFFF27
-:1062900024A50004AC8800001467FFFB24840004DC
-:1062A0003C04600EAC8600380000000000000000D6
-:1062B000000000003C0700203C0680000120202157
-:1062C00001402821ACC700300E0003780000802177
-:1062D0000E000342024020210A0003B802002021E0
-:1062E00027BDFFE0AFB200183092FFFFAFB100143E
-:1062F000AFBF001CAFB000101640000D0000882199
-:106300000A000427022010212405000350850027DD
-:106310008CE5000C0000000D262C00013191FFFFE0
-:1063200024EB00200232502B11400019AF8B00509B
-:106330008F820044144000168F8700503C06700086
-:106340003C0320008CE5000000A6202414830010EC
-:106350008F840058000544023C09800000A9802475
-:106360001480FFE9310600FF2CCA000B1140FFEB3F
-:10637000262C0001000668803C0E080025CE52A0A5
-:1063800001AE60218D8B000001600008000000005C
-:10639000022010218FBF001C8FB200188FB1001493
-:1063A0008FB0001003E0000827BD00200E0003336B
-:1063B000240400841600FFD88F8700500A000408C8
-:1063C000AF800058020028210E00035A2404000167
-:1063D0008F8700500A000408AF820058020028216D
-:1063E0000E00035A000020210A0004378F87005056
-:1063F0000E00039F020020218F8700500A0004082E
-:10640000AF82005830AFFFFF000F19C03C0480007E
-:106410008C9001B80600FFFE3C1920043C181000C7
-:10642000AC830180AC800184AC990188AC9801B840
-:106430000A000409262C000190E2000290FF0003EC
-:106440000000202100023A0000FF28252406000851
-:106450000E000333000000001600FFDD24020003DD
-:106460008F870050000010210A000408AF820058F6
-:1064700090E50002000020210A00045624060009CD
-:1064800094E5000490E9000390E300020005340065
-:106490000009420000C82025008328252406000AA0
-:1064A0000A0004560000202190E50002000020218F
-:1064B0000A0004562406000B000449C23127003F9D
-:1064C000000443423C028000000820402403168060
-:1064D0002CE60020AC43002C24EAFFE024820001DB
-:1064E00014C0000330A900FF00801021314700FFD5
-:1064F000000260803C0D8000240A0001018D2021F3
-:106500003C0B000E00EA2804008B3021112000050E
-:10651000000538278CCE000001C5382503E00008AF
-:10652000ACC700008CD800000307782403E0000803
-:10653000ACCF000027BDFFE0AFB10014AFB000103A
-:10654000AFBF00183C0760008CE408083402F0007C
-:106550003C1160003083F000240501C03C04800E33
-:106560000000302110620006241000018CEA0808A7
-:106570003149F0003928E0000008382B000780403E
-:106580003C0D0200AE2D0814240C16803C0B80003C
-:106590008E2744000E000E6AAD6C002C1200000421
-:1065A0003C02169124050001120500103C023D6CCE
-:1065B000345800E0AE3844083C1108008E31007CAD
-:1065C0008FBF00183C06600000118540360F168012
-:1065D0008FB100148FB000103C0E020027BD0020C8
-:1065E000ACCF442003E00008ACCE08103C0218DA1F
-:1065F000345800E0AE3844083C1108008E31007C6D
-:106600008FBF00183C06600000118540360F1680D1
-:106610008FB100148FB000103C0E020027BD002087
-:10662000ACCF442003E00008ACCE08100A00047090
-:10663000240500010A00047000002821240204003F
-:10664000A7820024A780001C000020213C0608002F
-:1066500024C655A82405FFFF2489000100044080BA
-:106660003124FFFF010618212C87002014E0FFFAD7
-:10667000AC65000024040400A7840026A780001E47
-:10668000000020213C06080024C656282405FFFFF0
-:10669000248D00010004608031A4FFFF0186582191
-:1066A0002C8A00201540FFFAAD650000A780002865
-:1066B000A7800020A7800022000020213C060800BF
-:1066C00024C656A82405FFFF249900010004C080B9
-:1066D0003324FFFF030678212C8E000415C0FFFA37
-:1066E000ADE500003C0560008CA73D002403E08F71
-:1066F00000E310243446014003E00008ACA63D004E
-:106700002487007F000731C224C5FFFF000518C29F
-:10671000246400013082FFFF000238C0A7840030EB
-:106720003C010800AC270030AF80002C000028217D
-:1067300000002021000030212489000100A7282129
-:106740003124FFFF2CA81701110000032C830080C7
-:106750001460FFF924C6000100C02821AF86002C78
-:1067600010C0001DA786002A24CAFFFF000A11429C
-:106770003C080800250856A81040000A0000202107
-:10678000004030212407FFFF248E000100046880B0
-:1067900031C4FFFF01A860210086582B1560FFFA65
-:1067A000AD87000030A2001F504000080004308078
-:1067B000240300010043C80400041080004878212D
-:1067C0002738FFFF03E00008ADF8000000C82021D3
-:1067D0002405FFFFAC85000003E000080000000076
-:1067E00030A5FFFF30C6FFFF30A8001F00806021EA
-:1067F00030E700FF000529420000502110C0001DB5
-:1068000024090001240B000125180001010B2004BC
-:10681000330800FF01267826390E00202DED0001F7
-:106820002DC2000101A218251060000D0144502561
-:106830000005C880032C40210100182110E0000F42
-:10684000000A20278D040000008A1825AD030000EF
-:1068500024AD0001000040210000502131A5FFFFC0
-:10686000252E000131C9FFFF00C9102B1040FFE7A2
-:106870002518000103E00008000000008D0A000058
-:10688000014440240A000556AC68000027BDFFE81B
-:1068900030A5FFFF30C6FFFFAFB00010AFBF001440
-:1068A00030E7FFFF000050213410FFFF000060219F
-:1068B00024AF001F00C04821241800012419002023
-:1068C00005E0001601E010210002F943019F682A4B
-:1068D0000009702B01AE402411000017000C188035
-:1068E0000064102110E000058C4B000000F840040B
-:1068F0000008382301675824000038211540004162
-:1069000000004021556000163169FFFF258B000112
-:10691000316CFFFF05E1FFEC01E0102124A2003EF5
-:106920000002F943019F682A0009702B01AE402440
-:106930001500FFEB000C1880154600053402FFFF20
-:10694000020028210E00053A000038210200102123
-:106950008FBF00148FB0001003E0000827BD00189F
-:106960001520000301601821000B1C0224080010F0
-:10697000306A00FF15400005306E000F250D00083D
-:1069800000031A0231A800FF306E000F15C0000589
-:10699000307F00032510000400031902320800FFB5
-:1069A000307F000317E0000538690001250200026E
-:1069B00000031882304800FF3869000131230001CC
-:1069C00010600004310300FF250A0001314800FF78
-:1069D000310300FF000C694001A34021240A00019B
-:1069E00010CAFFD53110FFFF246E000131C800FF2F
-:1069F0001119FFC638C900012D1F002053E0001CEB
-:106A0000258B0001240D00010A0005CD240E002075
-:106A100051460017258B000125090001312800FF90
-:106A20002D09002051200012258B00012543000173
-:106A3000010D5004014B1024250900011440FFF4FE
-:106A4000306AFFFF3127FFFF10EE000C2582FFFFA9
-:106A5000304CFFFF000050213410FFFF312800FFB1
-:106A60002D0900205520FFF225430001258B000150
-:106A7000014648260A000587316CFFFF00003821D7
-:106A8000000050210A0005D93410FFFF27BDFFD8B0
-:106A9000AFB0001030F0FFFFAFB10014001039426A
-:106AA0003211FFE000071080AFB3001C00B12823B3
-:106AB00030D3FFFFAFB2001830A5FFFF0080902158
-:106AC0000260302100442021AFBF00200E00056588
-:106AD0003207001F022288213403FFFF02402021D9
-:106AE00002002821026030210000382110430009F3
-:106AF0003231FFFF022010218FBF00208FB3001C16
-:106B00008FB200188FB100148FB0001003E000089E
-:106B100027BD00280E000565000000000040882108
-:106B2000022010218FBF00208FB3001C8FB20018ED
-:106B30008FB100148FB0001003E0000827BD0028BB
-:106B4000000424003C036000AC603D0810A000027B
-:106B5000348210063482101603E00008AC623D0453
-:106B600027BDFFE0AFB00010309000FF2E020006FE
-:106B7000AFBF001810400008AFB100140010308003
-:106B80003C030800246352CC00C328218CA40000DD
-:106B90000080000800000000000020218FBF0018C6
-:106BA0008FB100148FB000100080102103E00008A6
-:106BB00027BD00209791002A1620005100002021B7
-:106BC0003C020800904200330A000640000000002A
-:106BD000978D002615A00031000020210A000640F4
-:106BE000240200089787002414E0001A00001821EE
-:106BF00000602021240200011080FFE98FBF0018EF
-:106C0000000429C20045302100A6582B1160FFE482
-:106C10003C0880003C072000000569C001A76025F2
-:106C2000AD0C00203C0380082402001F2442FFFF1B
-:106C3000AC6000000441FFFD2463000424A50001B2
-:106C400000A6702B15C0FFF5000569C00A00062AD2
-:106C50008FBF00189787001C3C040800248455A8A7
-:106C6000240504000E0005E524060001978B00248E
-:106C700024440001308AFFFF2569FFFF2D480400EE
-:106C80000040282115000040A789002424AC3800CA
-:106C9000000C19C00A00063EA780001C9787001E42
-:106CA0003C04080024845628240504000E0005E551
-:106CB0002406000197990026244400013098FFFF24
-:106CC000272FFFFF2F0E04000040882115C0002C45
-:106CD000A78F0026A780001E3A0200032624010089
-:106CE0003084FFFF0E0006122C4500010011F8C091
-:106CF00027F00100001021C00A000640240200080D
-:106D00009785002E978700223C040800248456A80B
-:106D10000E0005E5240600019787002A8F89002CC4
-:106D20002445000130A8FFFF24E3FFFF0109302BB9
-:106D30000040802114C00018A783002AA7800022E9
-:106D4000978500300E000E5402002021244A0500D1
-:106D50003144FFFF0E000612240500013C05080027
-:106D600094A500320E000E5402002021244521007B
-:106D70003C020800904200330A000640000521C092
-:106D80000A000678A784001E24AC3800000C19C045
-:106D90000A00063EA784001C0A000692A78500226E
-:106DA000308400FF27BDFFE82C820006AFBF00142F
-:106DB000AFB000101040001500A038210004408042
-:106DC0003C030800246352E4010328218CA4000042
-:106DD000008000080000000024CC007F000751C2A2
-:106DE000000C59C23170FFFF2547C40030E5FFFF9A
-:106DF0002784001C020030210E00053A2407000100
-:106E00009786002802062021A78400288FBF00143F
-:106E10008FB0001003E0000827BD00183C050800F3
-:106E20008CA50030000779C20E00031C25E4DF00AA
-:106E30003045FFFF3C040800248456A824060001C6
-:106E40000E00053A24070001978E002A8FBF001418
-:106E50008FB0001025CD000127BD001803E0000809
-:106E6000A78D002A0007C9C22738FF00001878C282
-:106E700031F0FFFF3C04080024845628020028213A
-:106E8000240600010E00053A24070001978D002614
-:106E9000260E0100000E840025AC00013C0B6000B2
-:106EA000A78C0026AD603D083604000600003021A6
-:106EB0003C0760008CE23D04305F000617E0FFFDF8
-:106EC00024C9000100061B00312600FF0064402594
-:106ED0002CC50004ACE83D0414A0FFF68FBF0014DD
-:106EE0008FB0001003E0000827BD0018000751C252
-:106EF0002549C80024060001240700013C040800BD
-:106F0000248455A80E00053A3125FFFF97870024F9
-:106F10008FBF00148FB0001024E6000127BD0018B9
-:106F200003E00008A78600243084FFFF30A5FFFFA0
-:106F30003C0680008CC201B80440FFFE3C08408043
-:106F4000008838253C031000ACC00180ACC501842A
-:106F5000ACC7018803E00008ACC301B83084FFFF70
-:106F60003C0680008CC201B80440FFFE3C0840385B
-:106F70008CA70000008828253C031000ACC70180C6
-:106F8000ACC5018803E00008ACC301B88F83007072
-:106F90008F8600681066000B008040213C070800C7
-:106FA00024E756B8000328C000A710218C44000035
-:106FB00024630001108800053063000F5466FFFA57
-:106FC000000328C003E00008000010213C0708006F
-:106FD00024E756BC00A7302103E000088CC2000063
-:106FE0003C03900034620001008220253C038000B5
-:106FF000AC6400208C65002004A0FFFE00000000AF
-:1070000003E00008000000003C028000344300015F
-:107010000083202503E00008AC44002027BDFFE0EA
-:10702000AFB100143091FFFFAFB00010AFBF001838
-:107030001220001200A080218CA5000014A00011D5
-:10704000240400023C0680008CC201B80440FFFE0C
-:107050003C074000022720258FBF00188FB1001485
-:107060008FB000103C03100027BD0020ACC501808C
-:10707000ACC4018803E00008ACC301B80A000753A0
-:107080008CA500000E0006AA24060200000028219C
-:107090000A000753AE0000003087FFFF3C06800067
-:1070A0008CC201B80440FFFE3C0A40068CA90000D7
-:1070B00000EA4025ACC901808CA400043C03100008
-:1070C000ACC40184ACC8018803E00008ACC301B8BB
-:1070D0008F83FD8C27BDFFE8AFBF0014AFB0001059
-:1070E00090670008008010210080282130E60040D1
-:1070F0000000202110C000088C5000000E00008805
-:1071000002002021020020218FBF00148FB0001048
-:107110000A0004CD27BD00180E000768000000001B
-:107120000E00008802002021020020218FBF0014E1
-:107130008FB000100A0004CD27BD001827BDFFE066
-:10714000AFB000108F90FD8CAFBF001CAFB2001825
-:10715000AFB1001492060001008088210E00073AAA
-:1071600030D2000492040005001129C2A6050000D7
-:1071700034830040A20300050E00074402202021B2
-:107180000E0004CF0220202124020001AE02000CD8
-:1071900002202821A602001024040002A6020012E8
-:1071A00024060200A60200140E0006AAA60200167B
-:1071B0001640000F8FBF001C978C006C3C0B080022
-:1071C0008D6B00782588FFFF3109FFFF256A0001DC
-:1071D000012A382B10E00006A788006C3C0F6006DF
-:1071E000240E001635ED0010ADAE00508FBF001C10
-:1071F0008FB200188FB100148FB0001003E00008A8
-:1072000027BD002027BDFFE0AFB10014AFBF0018BD
-:10721000AFB000101080000400A08821240200807C
-:1072200010820007000000000000000D8FBF001852
-:107230008FB100148FB0001003E0000827BD0020BC
-:107240000E00073A00A020218F86FD8C022020210D
-:1072500090C500050E00074430B000FF2403003E37
-:107260001603FFF1000000003C0580008CA40178AB
-:107270000480FFFE240800073C071000ACB1014069
-:1072800002202021A0A801448FBF00188FB1001454
-:107290008FB00010ACA701780A00079127BD00202D
-:1072A00027BDFFE0AFB00010AFBF0018AFB10014B2
-:1072B0003C1080008E110020000000000E0004CF62
-:1072C000AE040020AE1100208FBF00188FB1001453
-:1072D0008FB0001003E0000827BD00203084FFFFBE
-:1072E0003C0680008CC201B80440FFFE3C084035DB
-:1072F000008838253C031000ACC50180ACC0018477
-:10730000ACC7018803E00008ACC301B83084FFFFBC
-:107310003C0680008CC201B80440FFFE3C084036A9
-:10732000008838253C031000ACC50180ACC0018446
-:10733000ACC7018803E00008ACC301B827BDFFD08B
-:10734000AFB500243095FFFFAFB60028AFB40020E2
-:10735000AFBF002CAFB3001CAFB20018AFB1001428
-:10736000AFB0001030B6FFFF12A000270000A02130
-:107370008F9200508E4300003C06800024020040A3
-:1073800000033E0200032C0230E4007F00669824D4
-:107390001482001D30A500FF8F8300602C68000A56
-:1073A000510000108F860044000358803C0C0800F8
-:1073B000258C5300016C50218D49000001200008EC
-:1073C0000000000002D4702131C5FFFF0E00070C41
-:1073D00024040084166000028F920050AF80006089
-:1073E0008F860044264F00202689000101E090216D
-:1073F0003134FFFF14C00004AF8F00500295282BDA
-:1074000014A0FFDC00000000028010218FBF002CC0
-:107410008FB600288FB500248FB400208FB3001CD6
-:107420008FB200188FB100148FB0001003E0000875
-:1074300027BD00302407003414A7014600000000D7
-:107440009247000E8F98FD908F90FD8C240F1600B0
-:10745000A30700199244000D3C0880003C07800CF3
-:10746000A3040018965F00123C0960003C117FFFE6
-:10747000A61F005C965900103622FFFF2404000569
-:107480003325FFFFAE0500548E46001CAD0F0028CB
-:107490008CEE00008D2D444801C6182601A3302132
-:1074A000AE0600388E0C003824CA00013C0D7F0067
-:1074B000AE0C003C8E0B003CAF0B0004AE0A00206B
-:1074C0008E130020AE13001CA300001BAE02002C84
-:1074D000A30400128E5F001424130050AE1F00346A
-:1074E0008E190034AF1900148E450018AE050048FF
-:1074F000924F000CA20F004E92090008352E00207A
-:10750000A20E00088E030018006D6024358B400029
-:10751000AE0B0018920A0000315200FF125302A66F
-:107520002413FF803C040800248457380E0007769B
-:1075300000000000240C0004240800013C050800A1
-:107540008CA557383C048000A20C0025A208000539
-:107550008C9001780600FFFE8F920050240D0002EF
-:107560003C031000AC850140A08D0144AC83017840
-:107570000A00083AAF8000602CAD003711A0FF99D7
-:107580008F860044000580803C1108002631532876
-:10759000021178218DEE000001C0000800000000FB
-:1075A0002410000414B0008E3C0780003C0B08003F
-:1075B0008D6B57388F86FD8CACEB00208E43000816
-:1075C0008F8FFD90240E0050ACC300308E4A00080F
-:1075D000ACCA00508E42000CACC200348E44001085
-:1075E000ACC400388E5F0010ACDF00548E5900141C
-:1075F000ACD9003C8E580018ADF800048E51001C28
-:10760000ACD1002090C5000030A900FF112E0276F9
-:10761000000000008CC500348CD1003000B1302354
-:1076200004C000F32404008C126000F02402000364
-:107630000A00083AAF820060240F000514AF00680A
-:107640003C0B80003C0308008C6357388F86FD8C10
-:10765000AD6300208E4A00048F99FD90240720001E
-:10766000ACCA001C9242000824120008A322001990
-:107670008F840050909F0009A33F00188F85005011
-:1076800090B8000A330400FF10920010288C000903
-:10769000158000BC24080002240E0020108E000B70
-:1076A00034078000288900211520000824074000A5
-:1076B00024110040109100053C070001240F0080B8
-:1076C000108F00023C070002240740008CDF0018E6
-:1076D0003C04FF0003E4C8240327C025ACD80018ED
-:1076E00090B2000BA0D200278F8300509465000C4D
-:1076F00010A0022A000000009467000C3C198000D2
-:10770000240BFFBFA4C7005C9062000E2407000496
-:10771000A0C200088F840050909F000FA0DF0009D6
-:107720008F8C00508D9200108F38007402582823DF
-:10773000ACC500588D8F0014ACCF002C959100186B
-:107740003229FFFFACC90040958E001A31D0FFFFEF
-:10775000ACD000448D8D001CACCD00489588000253
-:10776000A4C800789183000EA0C3000890CA000846
-:10777000014B1024126001D4A0C200088F92005067
-:107780000A00083AAF8700602406000614A6001419
-:107790003C0D80003C1008008E1057388F8CFD88FF
-:1077A000ADB000208E4800188F86FD8C8F8AFD902A
-:1077B000AD8800008CC3003824040005AD830004AC
-:1077C0008CCB003C12600081AD4B00000A00083AEF
-:1077D000AF840060240E000710AE004B24040006A6
-:1077E0003C05080024A557380E00074924040081F1
-:1077F0008F9200500013102B0A00083AAF820060ED
-:107800002419002314B9FFF63C0B80003C0C08003F
-:107810008D8C57388F8AFD90AD6C00208F91FD8C38
-:107820008E4600042544002026450014AE2600287C
-:10783000240600030E000E60255000308F87005094
-:1078400002002021240600030E000E6024E500083B
-:107850003C040800248457380E000776000000001E
-:1078600092220000241F0050304400FF549FFFE18B
-:107870008F9200500E000E4B000000000A00093FDE
-:107880008F9200502403003314A300323C02800086
-:107890003C1108008E3157388F8EFD90AC5100207E
-:1078A0008E440008240900288F88FD8CADC4003068
-:1078B0008E5F000C24060009ADDF00348E590010E5
-:1078C000ADD900388E580014ADD800208E45001870
-:1078D000ADC500248E4F001CADCF0028A1C90011FA
-:1078E0008E4D000412600031AD0D00288F920050C3
-:1078F0000A00083AAF8600602409002214A9FFB8E4
-:1079000000000000240400073C0F08008DEF5738EA
-:107910003C118000AE2F00205660FEB1AF840060A5
-:107920003C040800248457380E00077624130050C6
-:107930008F98FD8C93120000324500FF10B301694F
-:10794000000000008F920050000020210A00083A39
-:10795000AF8400603C05080024A557380E000719C5
-:10796000240400810A00093F8F92005002D498211C
-:107970003265FFFF0E00070C240400840A00083A59
-:107980008F9200501088FF512407040028870003BD
-:1079900010E001A324100004240D0001548DFF4BBE
-:1079A000240740000A0008F5240701003C050800F0
-:1079B00024A557380E000768240400828F920050D7
-:1079C000000030210A00083AAF8600603C0408003D
-:1079D000248457388CC200380E0007768CC3003CD4
-:1079E0008F9200500A000995000020212404008293
-:1079F0003C05080024A557380E0007680000000069
-:107A00008F920050000010210A00083AAF820060F7
-:107A10008E5000048F91FD8C3C0A8000AD500020F8
-:107A200092220005020028213046000214C0018085
-:107A30002404008A8F92FD90020028212404008DE6
-:107A4000924B001B3163002014600179000000009C
-:107A5000922D0009240C001231A800FF110C0174B2
-:107A6000240400810E00073A020020219245001BE9
-:107A7000240E00040200202134A90042A249001B68
-:107A80000E000744A22E00253C0480008C91017852
-:107A90000620FFFE24180002AC900140A09801448B
-:107AA0008F9200503C0F1000AC8F01780A00094003
-:107AB0000013102B8E5000048F91FD8C3C1F800012
-:107AC000AFF0002092390005020028213327000280
-:107AD00014E000172404008A9224000924120004F0
-:107AE00002002821308600FF10D2001124040081FA
-:107AF0000E00073A020020218F8CFD90240B00120B
-:107B00002403FFFE918D001B0200202135A80020D8
-:107B1000A188001BA22B0009922A00050143102412
-:107B20000E000744A22200050200282100002021A7
-:107B30000E000805000000000A00093F8F92005067
-:107B40008E5100043C0280003C100800261057387B
-:107B5000AC5100203C010800AC315738924600037C
-:107B600030C40004108001658F84FD8C240200065F
-:107B7000A0820009924D001B2408FFC031AC003FD9
-:107B800001885825A08B000892430003306A000149
-:107B90001540015C000000008E420008AE020008A3
-:107BA0003C0208008C4257401040015B8F8EFD90D4
-:107BB000000281C28F85FD8CA5D0000C8E5F000C69
-:107BC000240F000124090014ADDF002C8E59001091
-:107BD000ADD9001C96470016A5C7003C9658001466
-:107BE000A5D8003EACAF000CA4AF0010A4AF0012AB
-:107BF000A4AF0014A4AF00161260015FA1C9001168
-:107C000092440003309200022E5300018F920050E4
-:107C1000266200080A00083AAF8200608E4600041F
-:107C20003C0580003C048008ACA600208E4700087C
-:107C30009089000024110050312200FF105100B83B
-:107C4000240500883C0480008C8F01B805E0FFFE0D
-:107C50000013802B3C18400900B81025AF9000603D
-:107C60003C101000AC860180AC870184AC82018896
-:107C7000AC9001B80A00083B8F8600448E45000492
-:107C80003C0680003C098008ACC50020913F000004
-:107C90002404005033F900FF132400B024060088A8
-:107CA0003C0480008C8A01B80540FFFE3C0E400E6B
-:107CB00000CE68253C081000AC850180AC800184B2
-:107CC000AC8D0188AC8801B8912B0000240CFF809A
-:107CD00024040004016C1825240600300E0006AAB6
-:107CE000A12300000A00093F8F9200508E5000042B
-:107CF0008F91FD903C0F8000ADF000209225001B7D
-:107D000030A900101120007C240300813C04800075
-:107D10008C8701B804E0FFFE3C1F401FAC9001803F
-:107D2000007F10250013C82B3C101000AC8001848C
-:107D3000AF990060AC820188AC9001B80A00083BA2
-:107D40008F8600448E44001C0E00072500000000B2
-:107D5000104000F8004038218F920050240600891E
-:107D60003C0580008CAE01B805C0FFFE000000009D
-:107D7000ACA701808E50001C3C1140010013782BF1
-:107D800000D138253C131000ACB00184AF8F0060E7
-:107D9000ACA70188ACB301B80A00083B8F86004449
-:107DA000965900023C10080026105738333800045A
-:107DB000130000A33C0460008E5F001C3C068000A2
-:107DC000ACDF00203C010800AC3F5738964F000262
-:107DD00031E7000114E000E3000000008E420004DF
-:107DE000AE0200083C1008008E105740120000D967
-:107DF0003C0680008F85FD8C241000018CBF00188C
-:107E00008F91FD908F89FD8803E6C825ACB90018D5
-:107E1000A0A00005ACB0000C3C1808008F1857401B
-:107E20008F870050A4B00010001879C2A4B00012CF
-:107E3000A4B00014A4B00016A62F000C8CEE00080D
-:107E40008F8D00508F8C0050AE2E002C8DA8000C12
-:107E500024070002AE28001C918B0010A22B0011F9
-:107E60008F830050906A0011A12A00088F82005071
-:107E700090440012A0A4004E8F920050924600132E
-:107E8000A22600128F920050965F0014A63F003C7D
-:107E900096590016A639003E8E580018AE380014C8
-:107EA0005660FD4FAF8700603C05080024A5573899
-:107EB0000E000749000020218F9200500000382159
-:107EC0000A00083AAF8700603C05080024A557382F
-:107ED0000E000768240400828F9200500A000922D5
-:107EE000000038210E000E4B000000008F92005061
-:107EF0000A000995000020210E00073A0200202107
-:107F00009232001B02002021365800100E00074458
-:107F1000A238001B8F9200500A000A850000182129
-:107F20009243000C306A0001114000030000000081
-:107F3000964B000EA48B002C9248000C310C0002D2
-:107F40001180FF4000002821964E00128E4D001433
-:107F5000A48E001A0A000A53AC8D001C8F83007097
-:107F60008F8700681067FF4E000030213C08080032
-:107F7000250856BC000320C0008830218CD10000A9
-:107F8000122500C8246200013043000F1467FFFA75
-:107F9000000320C00A000A6A000030213C050800E6
-:107FA00024A557380E0007682404008B8F920050D8
-:107FB0000A0009220013382B3C0B08008D6B573840
-:107FC00024D8FFFE25710100322A007F014790214D
-:107FD00002331024AD020028AE4600D0AE4000D4DB
-:107FE0000A00088BAE58001CACC000543C0E0800C0
-:107FF0008DCE57383C09800C352C0100ACEE0028A2
-:108000008E500014AD9000D08E4D0014AD8D00D474
-:108010008E4800102507FFFE0A0008C7AD87001C28
-:108020005490FDAA240740000A0008F52407100018
-:108030000E0007F9000000000A00093F8F9200506F
-:108040008C83442C3C05DEAD34B2BEEF3C0108000D
-:10805000AC20573810720090000000003C046C62A5
-:10806000348279701462000824040002978A006C3C
-:1080700097830064020028210143482B1120001936
-:1080800024040092240400020E00061A24050200B3
-:108090003C0B8000AD6200203C010800AC22573848
-:1080A0001040000D8F8E0050240C00282404000383
-:1080B00091CD001031A800FF550C000124040001EF
-:1080C0000E00004C00000000104000042404008357
-:1080D0000A000AB58F920050240400833C05080072
-:1080E00024A557380E000749000000008F92005069
-:1080F0000013382B0A00083AAF8700600A000A1EF6
-:10810000240200128E4400080E0007250000000023
-:108110000A000A2AAE0200083C05080024A55738C8
-:108120000E000719240400878F9200500A000A47A6
-:108130000013102B240400040E00061A240500303E
-:1081400014400014004038218F9200500A000A9A0F
-:10815000240600833C05080024A557380A000B7B41
-:10816000240400878E4400040E0007250000000050
-:108170000A000ABBAE0200083C05080024A55738D7
-:108180000E000768240400828F9200500A000A47FC
-:10819000000010218F9200503C0880083C0C8000A9
-:1081A000240B0050240A0001AD820020A10B000026
-:1081B000A10A000192490004A10900189244000597
-:1081C000A1040019924300063C040800248456BC14
-:1081D000A103001A924200073C030800246356B82A
-:1081E000A102001B92450008A105001C924600094F
-:1081F000A106001D925F000AA11F001E9259000BEC
-:10820000A119001F9258000CA11800209251000DD6
-:10821000A11100219250000EA1100022924F000FD8
-:10822000A10F0023924E0010A10E0024924D0011C8
-:10823000A10D0025964C0014A50C0028964B0016A5
-:108240008F8A00688F980070A50B002A9649001845
-:10825000000A10C025450001A509002C8E46001C0F
-:108260000044C8210043F82130A5000FAFE600000C
-:10827000AF27000010B80003AF8500680A000A9A13
-:108280000000302124AD000131A8000F0000302192
-:108290000A000A9AAF8800708C83442C0A000B5A9B
-:1082A0003C046C623C07080024E756B80087902124
-:1082B000ACC00000000030210A000A6AAE40000095
-:1082C0003C0482013C03600034820E02AC603D68D5
-:1082D000AF80009003E00008AC623D6C27BDFFE872
-:1082E000AFB000103090FFFF001018422C62004128
-:1082F000AFBF001414400002240400802403004097
-:108300003C010800AC3000603C010800AC23006474
-:108310000E000E5400602821244802BF2409FF806B
-:108320000109282400103980001030408FBF00144C
-:108330008FB0001000A7202100861821AF8300789D
-:108340003C010800AC2500583C010800AC24005C4E
-:1083500003E0000827BD0018308300FF30C6FFFF90
-:1083600030E400FF3C0880008D0201B80440FFFEAD
-:1083700000035400014438253C09600000E9202531
-:108380003C031000AD050180AD060184AD040188F9
-:1083900003E00008AD0301B88F8600503C0960126D
-:1083A000352700108CCB00043C0C600E3585001086
-:1083B000316A00062D480001ACE800C48CC40004FA
-:1083C000ACA431808CC2000894C30002ACA23184FA
-:1083D00003E00008A78300888F8500508F87FF186F
-:1083E0008F86FF208CAE00043C0F601235E8001031
-:1083F000ACEE00688CAD0008ACED006C8CAC0010ED
-:10840000ACCC004C8CAB000CACCB004894CA0054F4
-:108410003C0208008C42004425490001A4C90054D4
-:1084200094C400543083FFFF106200170000000066
-:108430003C0208008C420040A4C200528CA30018E9
-:10844000ACE300308CA20014ACE2002C8CB9001814
-:10845000ACF900388CB8001424050001ACF80034E5
-:108460008D0600BC50C500198D0200B48D0200B805
-:10847000A4E2004894E40048A4E4004A94E800DA46
-:1084800003E000083102FFFF3C0208008C42002498
-:10849000A4C00054A4C200528CA30018ACE3003066
-:1084A0008CA20014ACE2002C8CB90018ACF9003896
-:1084B0008CB8001424050001ACF800348D0600BC13
-:1084C00054C5FFEB8D0200B88D0200B4A4E2004851
-:1084D00094E40048A4E4004A94E800DA03E00008C9
-:1084E0003102FFFF8F8600503C0480008CC90008D9
-:1084F0008CC80008000929C0000839C0AC870020DA
-:1085000090C30007306200041040003AAF85008C31
-:1085100090CB0007316A0008114000398F87FF1C9B
-:108520008CCD000C8CCE001401AE602B118000327B
-:10853000000000008CC2000CACE200708CCB001874
-:108540008F85FF188F88FF20ACEB00748CCA001059
-:108550002402FFF8ACAA00C88CC9000CAD09006069
-:108560008CC4001CACA400C090E3007C0062C82452
-:10857000A0F9007C90D80007330F000811E0000438
-:108580000000000090ED007C35AC0001A0EC007C08
-:1085900090CF000731EE000111C00009000000007B
-:1085A00090E4007C2418000234820002A0E2007CE7
-:1085B00090A300EC307900FF133800132408003436
-:1085C00090C900073126000210C00004000000001E
-:1085D00090EB007C356A0004A0EA007C90ED007D01
-:1085E00031AC003FA0EC007D94A700DA03E0000866
-:1085F00030E2FFFF8F87FF1C0A000C908CC2001432
-:108600000A000C91ACE000700A000CB2ACA800CCDF
-:108610008F8C005027BDFFD8AFB3001CAFB200183D
-:10862000AFB00010AFBF0020AFB10014918F0015A4
-:108630003C13600E3673001031EB000FA38B0094D7
-:108640008D8F00048D8B0008959F00129599001066
-:108650009584001A9598001E958E001C33EDFFFF3F
-:10866000332AFFFF3089FFFF3308FFFF31C7FFFFC9
-:108670003C010800AC2D00243C010800AC2900445A
-:108680003C010800AC2A0040AE683178AE67317C0E
-:1086900091850015959100163C126012365200101B
-:1086A00030A200FF3230FFFFAE623188AE5000B41E
-:1086B00091830014959F0018240600010066C804E9
-:1086C00033F8FFFFAE5900B8AE5800BC918E0014CD
-:1086D000AF8F007C3C08600631CD00FFAE4D00C07E
-:1086E000918A00159584000E3C07600A314900FF0D
-:1086F000AF8B00803084FFFFAE4900C835110010F9
-:108700000E000BF934F004103C0208008C420060AB
-:108710003C0308008C6300643C0608008CC60058CB
-:108720003C0508008CA5005C8F8400788FBF00207A
-:10873000AE23004CAE65319CAE030054AE4500DC68
-:10874000AE6231A0AE6331A4AE663198AE2200486D
-:108750008FB3001CAE0200508FB10014AE4200E097
-:10876000AE4300E4AE4600D88FB000108FB20018C0
-:108770000A00050227BD00289785008A97830074A8
-:1087800027BDFFE8AFB0001000A3102BAFBF00144F
-:10879000240400058F900050104000552409000269
-:1087A0000E00061A8F850078AF82008C2404000327
-:1087B0001040004F240900023C0680000E00004CCF
-:1087C000ACC2002024070001240820001040004D06
-:1087D00024040005978E008A8F8AFF1C240900500C
-:1087E00025C50001A785008AA14900003C0D0800AD
-:1087F0008DAD0064240380008F84FF18000D660097
-:10880000AD4C0018A5400006954B000A8F85FF204F
-:108810002402FF8001633024A546000A915F000A0C
-:108820000000482103E2C825A159000AA0A00008C1
-:10883000A140004CA08000C59618000297830088D4
-:108840003C020004A49800DA960F00022418FFBF2F
-:1088500025EE2401A48E00AE8E0D0004ACAD0044C4
-:108860008E0C0008ACAC0040A4A00050A4A00054A2
-:108870008E0B000C240C0030AC8B00288E060010F0
-:10888000AC860024A480003EA487004EA48700503C
-:10889000A483003CAD420074AC8800C8ACA8006062
-:1088A000A08700EC909F00C433F9007FA09900C41A
-:1088B000909000C402187824A08F00C4914E007CD0
-:1088C00035CD0001A14D007C938B0094AD48007024
-:1088D000AC8C00CCA08B00C68F8800808F87007C7A
-:1088E000AC8800B4AC8700B8A5400078A540007AF9
-:1088F0008FBF00148FB000100120102103E000088A
-:1089000027BD00188F85008C0E0006AA8F86007880
-:108910000A000D7E2409000227BDFFE0AFB0001061
-:108920008F900050AFB10014AFBF00188E09000443
-:108930000E0004CF000921C08E0800048F84FF18A8
-:108940008F82FF20000839C03C068000ACC70020A1
-:10895000948500DA904300131460001C30B1FFFFCF
-:108960008F8CFF1C918B0008316A00401540000B72
-:10897000000000008E0D0004022030218FBF00187F
-:108980008FB100148FB000102404002200003821A1
-:10899000000D29C00A000C1827BD00200E0000633E
-:1089A000000000008E0D0004022030218FBF00184F
-:1089B0008FB100148FB00010240400220000382171
-:1089C000000D29C00A000C1827BD00200E00005B16
-:1089D000000000008E0D0004022030218FBF00181F
-:1089E0008FB100148FB00010240400220000382141
-:1089F000000D29C00A000C1827BD002027BDFFE08C
-:108A0000AFB200183092FFFFAFB00010AFBF001C34
-:108A1000AFB100141240001E000080218F8600506C
-:108A20008CC500002403000600053F020005140267
-:108A300030E4000714830016304500FF2CA8000620
-:108A400011000040000558803C0C0800258C54049F
-:108A5000016C50218D490000012000080000000039
-:108A60008F8E0090240D000111CD005024020002D1
-:108A7000AF820090260900013130FFFF24C800209A
-:108A80000212202B010030211480FFE5AF88005036
-:108A9000020010218FBF001C8FB200188FB100148C
-:108AA0008FB0001003E0000827BD002093870076F8
-:108AB00054E00034000030210E000CC6000000001D
-:108AC0008F8600500A000DDE240200018F8700907F
-:108AD0002405000210E500312404001300002821C1
-:108AE00000003021240700010E000C1800000000D7
-:108AF0000A000DDF8F8600508F8300902402000251
-:108B00001462FFF6240400120E000C7B000000002B
-:108B10008F85008C00403021240400120E000C18B8
-:108B2000000038210A000DDF8F8600508F830090EF
-:108B30002411000310710029241F0002107FFFCEB2
-:108B40002609000124040010000028210000302123
-:108B50000A000DFC240700018F91009024060002FA
-:108B60001626FFF9240400100E000D20000000005E
-:108B7000144000238F9800508F8600500A000DDEAD
-:108B800024020003240400140E000C180000282105
-:108B90008F8600500A000DDE240200020E000D88B0
-:108BA000000000000A000DDF8F8600500E000C2828
-:108BB00000000000241900022404001400002821F1
-:108BC0000000302100003821AF9900900E000C18F1
-:108BD000000000000A000DDF8F8600500E000C38E8
-:108BE000000000008F85008C241900020040302115
-:108BF00024040010000038210A000E35AF990090BF
-:108C00000040382124040010970F000200002821A2
-:108C10000E000C1831E6FFFF8F8600500A000DDFB2
-:108C2000AF9100908F84FF1C3C077FFF34E6FFFF6D
-:108C30008C8500182402000100A61824AC830018BB
-:108C400003E00008A08200053084FFFF30A5FFFF8D
-:108C5000108000070000182130820001104000023F
-:108C600000042042006518211480FFFB0005284005
-:108C700003E000080060102110C0000700000000A1
-:108C80008CA2000024C6FFFF24A50004AC820000D3
-:108C900014C0FFFB2484000403E00008000000006F
-:108CA00010A0000824A3FFFFAC8600000000000015
-:108CB000000000002402FFFF2463FFFF1462FFFA9C
-:108CC0002484000403E0000800000000000411C038
-:108CD00003E000082442024027BDFFE8AFB00010C7
-:108CE00000808021AFBF00140E000E7500A020216F
-:108CF00000504821240AFF808FBF00148FB000105D
-:108D0000012A30243127007F3C08800A3C042100DE
-:108D100000E8102100C428253C03800027BD00186E
-:108D2000AC650024AF820038AC400000AC65002484
-:108D300003E00008AC4000403C0D08008DAD005839
-:108D400000056180240AFF8001A45821016C48219C
-:108D5000012A30243127007F3C08800C3C0421008C
-:108D600000E8102100C428253C038000AC650028E1
-:108D7000AF82003403E00008AC40002430A5FFFFC0
-:108D80003C0680008CC201B80440FFFE3C08601520
-:108D900000A838253C031000ACC40180ACC001849D
-:108DA000ACC7018803E00008ACC301B83C0D080063
-:108DB0008DAD005800056180240AFF8001A4582170
-:108DC000016C4021010A4824000931403107007F2D
-:108DD00000C728253C04200000A418253C02800080
-:108DE000AC43083003E00008AF80003427BDFFE843
-:108DF000AFB0001000808021AFBF00140E000E75D0
-:108E000000A0202100504821240BFF80012B50247A
-:108E1000000A39403128007F3C0620008FBF001433
-:108E20008FB0001000E8282534C2000100A21825E8
-:108E30003C04800027BD0018AC83083003E0000824
-:108E4000AF8000383C0580088CA700603C06800895
-:108E50000087102B144000112C8340008CA8006068
-:108E60002D0340001060000F240340008CC90060F7
-:108E70000089282B14A00002008018218CC30060F8
-:108E800000035A42000B30803C0A0800254A5480F7
-:108E900000CA202103E000088C8200001460FFF368
-:108EA0002403400000035A42000B30803C0A0800B3
-:108EB000254A548000CA202103E000088C8200006B
-:108EC0003C05800890A60008938400A024C20001FD
-:108ED000304200FF3043007F1064000C000238274E
-:108EE000A0A200083C0480008C85017804A0FFFE4D
-:108EF0008F8A0098240900023C081000AC8A0140C7
-:108F0000A089014403E00008AC8801780A000EFA49
-:108F100030E2008027BDFFD8AFB200188F92009CCE
-:108F2000AFBF0020AFB3001CAFB00010AFB1001452
-:108F30008F9300348E5900283C1000803C0EFFEFC8
-:108F4000AE7900008E580024A260000A35CDFFFFE4
-:108F5000AE7800049251002C3C0BFF9F356AFFFF56
-:108F6000A271000C8E6F000C3C080040A271000B37
-:108F700001F06025018D4824012A382400E83025BD
-:108F8000AE66000C8E450004AE6000183C0400FF85
-:108F9000AE6500148E43002C3482FFFFA6600008EB
-:108FA0000062F824AE7F00108E5900088F90009860
-:108FB000964E0012AE7900208E51000C31D83FFF42
-:108FC00000187980AE7100248E4D001401F06021EC
-:108FD00031CB0001AE6D00288E4A0018000C41C252
-:108FE000000B4B80AE6A002C8E46001C0109382114
-:108FF000A667001CAE660030964500028E44002035
-:10900000A665001EAE640034924300333062000453
-:1090100054400006924700003C028008344301009F
-:109020008C7F00C0AE7F0030924700008F860038F2
-:10903000A0C700309245003330A4000250800007E2
-:10904000925100018F880038240BFF80910A003074
-:10905000014B4825A1090030925100018F90003842
-:10906000240CFFBF2404FFDFA21100318F8D0038D4
-:109070003C1880083711008091AF003C31EE007F32
-:10908000A1AE003C8F890038912B003C016C50242C
-:10909000A12A003C8F9F00388E68001493E6003CA4
-:1090A0002D0700010007114000C4282400A2182544
-:1090B000A3E3003C8F87003896590012A4F90032D0
-:1090C0008E450004922E007C30B0000300107823FF
-:1090D00031ED000300AD102131CC000215800002FB
-:1090E00024460034244600303C028008344300808B
-:1090F000907F007C00BFC8243338000417000002B2
-:1091000024C2000400C010218F98003824190002E6
-:10911000ACE20034A3190000924F003F8F8E00385C
-:109120003C0C8008358B0080A1CF00018F91003866
-:10913000924D003F8E440004A62D0002956A005C0B
-:109140000E000ED33150FFFF00024B800130382556
-:109150003C08420000E82825AE2500048E44003873
-:109160008F850038ACA400188E460034ACA6001CD5
-:10917000ACA0000CACA00010A4A00014A4A0001689
-:10918000A4A00020A4A00022ACA000248E620014A1
-:1091900050400001240200018FBF00208FB3001C4B
-:1091A0008FB200188FB100148FB00010ACA200086D
-:1091B0000A000EF227BD002827BDFFC83C05800825
-:1091C00034A40080AFBF0034AFBE0030AFB7002C76
-:1091D000AFB60028AFB50024AFB40020AFB3001C79
-:1091E000AFB20018AFB10014AFB000109483007894
-:1091F0009482007A104300512405FFFF0080F02183
-:109200000A0010020080B821108B004D8FBF00347F
-:109210008F8600983C1808008F18005C2411FF808E
-:109220003C1680000306782101F18024AED0002C8A
-:1092300096EE007A31EC007F3C0D800E31CB7FFF43
-:10924000018D5021000B4840012AA82196A400005E
-:109250003C0808008D0800582405FF8030953FFF2A
-:1092600001061821001539800067C8210325F8245C
-:109270003C02010003E290253338007F3C11800C52
-:10928000AED20028031190219250000D320F00043D
-:1092900011E0003702E0982196E3007A96E8007A20
-:1092A00096E5007A2404800031077FFF24E3000163
-:1092B00030627FFF00A4F82403E2C825A6F9007AF3
-:1092C00096E6007A3C1408008E94006030D67FFF4A
-:1092D00012D400C1000000008E5800188F8400983E
-:1092E00002A028212713FFFF0E000EADAE53002C65
-:1092F00097D5007897D4007A1295001000002821A5
-:109300003C098008352401003C0A80089148000887
-:10931000908700C53114007F30E400FF0284302BB9
-:1093200014C0FFB9268B0001938E00A0268C00018B
-:10933000008E682115ACFFB78F8600988FBF003470
-:109340008FBE00308FB7002C8FB600288FB5002459
-:109350008FB400208FB3001C8FB200188FB100149F
-:109360008FB0001000A0102103E0000827BD0038D6
-:1093700000C020210E000E78028028218E4B0010A4
-:109380008E4C00308F84003824090002016C502379
-:10939000AE4A0010A089000096E3005C8E440030C5
-:1093A0008F9100380E000ED33070FFFF0002438013
-:1093B000011028253C07420000A71025AE2200041A
-:1093C0008E5F00048F8A00388E590000240B00083D
-:1093D000AD5F001CAD590018AD40000CAD40001051
-:1093E0009246000A240400052408C00030D000FF83
-:1093F000A550001496580008A55800169251000A6E
-:109400003C188008322F00FFA54F0020964E000820
-:1094100037110100A54E0022AD400024924D000BF3
-:1094200031AC00FFA54C0002A14B00018E49003079
-:109430008F830038240BFFBFAC690008A0640030A4
-:109440008F9000382403FFDF9607003200E82824BD
-:1094500000B51025A6020032921F003233F9003FFA
-:1094600037260040A20600328F8C0038AD800034D1
-:109470008E2F00C0AD8F0038918E003C3C0F7FFFD7
-:1094800031CD007FA18D003C8F84003835EEFFFF89
-:10949000908A003C014B4824A089003C8F8500380D
-:1094A00090A8003C01033824A0A7003C8E42003461
-:1094B0008F9100383C038008AE2200408E59002C6A
-:1094C0008E5F0030033F3023AE26004492300048C8
-:1094D0003218007FA23800488F8800388E4D003047
-:1094E0008D0C004801AE582401965024014B4825AC
-:1094F000AD0900489244000AA104004C96470008B8
-:109500008F850038A4A7004E8E5000308E44003066
-:109510000E00031C8C65006092F9007C0002F9408B
-:10952000004028210002110003E2302133360002FE
-:1095300012C00003020680210005B08002168021BF
-:10954000926D007C31B3000412600002000570804F
-:10955000020E80218E4B003024058000316A00030A
-:10956000000A482331240003020418218F90003898
-:10957000AE03003496E4007A96E8007A96F1007A19
-:1095800031077FFF24E20001305F7FFF0225C824FE
-:10959000033F3025A6E6007A96F8007A3C120800D0
-:1095A0008E520060330F7FFF11F2001800000000A0
-:1095B0008F8400980E000EAD02A028218F840098A1
-:1095C0000E000EBD028028210E000EF200000000E9
-:1095D0000A000FFE0000000096F1007A02248024A9
-:1095E000A6F0007A92EF007A92EB007A31EE00FF5B
-:1095F000000E69C2000D6027000C51C03169007F68
-:10960000012A20250A000FF8A2E4007A96E6007AE3
-:1096100000C5C024A6F8007A92EF007A92F3007A8F
-:1096200031F200FF001271C2000E6827000DB1C0B8
-:10963000326C007F01962825A2E5007A0A0010AF5F
-:109640008F8400983C0380003084FFFF30A5FFFF2B
-:10965000AC640018AC65001C03E000088C620014C8
-:1096600027BDFFA83C068008AFBE0050AFBF005426
-:10967000AFB7004CAFB60048AFB50044AFB4004040
-:10968000AFB3003CAFB20038AFB10034AFB0003080
-:1096900034C80100910500C590C70008309EFFFF47
-:1096A00030A500FF30E2007F0045182AA7A0001473
-:1096B000A7A0001E10600053AFA0001090C90008C2
-:1096C0003126007F00A620232493FFFF0013802B68
-:1096D000001E882B0211782451E000848FB3001003
-:1096E0003C1980089736005297370050001EC4007E
-:1096F00002D7A8230015A4000014140303C2902A63
-:109700001640000200182C0300402821001314000A
-:109710000002240300A4F82A57E0000100A0202141
-:1097200028830009146000020080A021241400088E
-:109730003C0A80088D450048001449808D48004C43
-:109740003C0380003124FFFF3C06001000863825D2
-:1097500034710400AC650038AF91009CAC68003CEB
-:10976000AC670030000000000000000000000000B6
-:1097700000000000000000000000000000000000E9
-:10978000000000008C6C0000318B00201160FFFD98
-:109790000014682A01B01024104000390000A821EC
-:1097A0003C16800892D700083C1280008E440100CD
-:1097B00032F6007F0E000E7802C028218E2F001096
-:1097C0008E4401000000902131F73FFF0E000E9003
-:1097D00002E02821922E000031C2003F2C500008E8
-:1097E00052000010000088210002F8803C030800AD
-:1097F0002463542C03E3C8218F38000003000008C1
-:109800000000000090CE0008938B00A031CD007FB7
-:1098100000AD6023016C50210A0010F52553FFFFB5
-:10982000000088213C1080008E0401000E000EAD67
-:1098300002E028218E0401000E000EBD02C0282186
-:109840001220000F0013802B8F8A009C26A9000194
-:109850000009AC00027298230015AC0325450040B6
-:1098600002B4B02A0013802B2417000100A0882125
-:1098700002D01024AF85009C1440FFC9AFB7001080
-:109880003C07800894F100503C0580003C06002015
-:1098900002B1C821A4F90050ACA6003094F40050E5
-:1098A00094E3005203D560231074001D319EFFFF26
-:1098B0008CE5004C8CE900480015618000ACB021BB
-:1098C0000000A02102CCA82B013450210155B82161
-:1098D000ACF6004CACF70048001E882B021178242F
-:1098E00015E0FF803C1980088FB300108FBF005433
-:1098F0008FBE00503A6200018FB7004C8FB600480F
-:109900008FB500448FB400408FB3003C8FB2003855
-:109910008FB100348FB0003003E0000827BD00583D
-:1099200094F200548CEF0044325FFFFE001FC0C071
-:1099300001F87021ACAE003C8CEB00448CAD003CD7
-:10994000016D40231900003B000000008CE2004044
-:10995000244200013C07005034E400103C03800026
-:10996000ACA20038AC640030000000000000000031
-:1099700000000000000000000000000000000000E7
-:1099800000000000000000008C76000032D70020AC
-:1099900012E0FFFD3C118008962800543C0A80002C
-:1099A0003C06800831190001001960C0018AA0211D
-:1099B0008E8304003C0708008CE700443C1500201F
-:1099C000ACC300488E89040424050001ACC9004CD6
-:1099D00010E50259AD550030963F00523C05080095
-:1099E0008CA5004000BFC021A6380052962F00541D
-:1099F00025EE0001A62E00549626005430C4FFFF29
-:109A00005487FF34001E882B30A5FFFF0E0010D3B3
-:109A1000A62000543C0408008C84002496270052A1
-:109A20000044102300E29023A63200520A0010F7EF
-:109A3000001E882B8CE200400A0011983C07005061
-:109A400092280001240700013102007F1447001C06
-:109A500097AC001E8E2A0014240BC00031443FFF37
-:109A6000018B48243C0608008CC600600124282590
-:109A700030A43FFF0086882B12200011A7A5001EEE
-:109A80003C1108008E3100588F82009800044180FC
-:109A90002407FF80022218210068F82103E7C82468
-:109AA00033EF007F3C1880003C12800EAF19002C71
-:109AB00001F2682191AE000D35D00004A1B0000D77
-:109AC0000E000F0724120001241100013C10800039
-:109AD0008E0401000E000EAD02E028218E0401006C
-:109AE0000E000EBD02C028211620FF588F8A009C50
-:109AF0000A0011620013802B8F86009C90C9000120
-:109B00003125002010A0018A241000013C048008A7
-:109B1000348C0080918B007C8F9100340000902168
-:109B2000316A00011140000FAFB000208CD000144A
-:109B30008C8E0060020E682B15A0000302003821F5
-:109B40008C8700603C048008348300808C72007035
-:109B500000F2782B15E0000200E020218C640070F8
-:109B6000008090213C07800834E500808CD90014E7
-:109B70008CBF0070033FC02B170000020320202180
-:109B80008CA400700092182310600003AFA300287B
-:109B900024080002AFA800208FA500200265102B2A
-:109BA000144000B5000018218CC400388E2F000C22
-:109BB0003C180080AE2400008CCE00343C10FF9F87
-:109BC00001F86025AE2E000490CB003F360DFFFF5C
-:109BD000018D48243C0A00203C06FFEFA22B000B1D
-:109BE000012A382534C5FFFF00E540243C02000867
-:109BF0008F87009C01022025AE24000C8CE300140A
-:109C0000AE2000188FAF0028AE2300148CF8001887
-:109C10003C1FFFFB37F9FFFFAE38001C8CEE00083D
-:109C200000996824024F8021AE2E00248CEC000C99
-:109C3000AE2D000CA6200038A620003AAE30002C35
-:109C4000AE2C0020AE2000288CEB00148FAA002838
-:109C500001724823012A302310C00011AE260010E3
-:109C600090F0003D8E2C00048E2A00000010690048
-:109C7000018D28210000102100AD302B0142482128
-:109C800001264021AE250004AE28000090E3003DEF
-:109C9000A223000A8F9F009C97F90006A6390008AE
-:109CA0008F8A0038240200023C068008A14200008E
-:109CB00034C900809525005C024020218F90003837
-:109CC00030A8FFFF0E000ED3AFA800248FA30024FE
-:109CD0000002FB808F85009C3C04420003E3C82502
-:109CE0000324C025AE1800048F8400388CAF0038E0
-:109CF000AC8F00188CAE0034AC8E001CAC80000C15
-:109D0000AC800010A4800014A4800016A480002061
-:109D1000A4800022AC80002490A7003FA48700020A
-:109D20005240018C240700018FAB002851600002D3
-:109D300090A2003D90A2003E244C0001A08C0001A6
-:109D40008F840038AC9200083C18800837100080DF
-:109D5000920F007C31EE000215C00002240700348F
-:109D6000240700308F85009C3C088008350900805E
-:109D700090A300009128007C32590003A08300309A
-:109D80008F9F009C8F9000382404000493F80001FA
-:109D900000997823240DC000A21800318F99003853
-:109DA0008F8E009C31E50003972C003295CB00127A
-:109DB00000F24821018D502431623FFF01423025DD
-:109DC000A7260032932300320125382131080004F0
-:109DD000307F003F37E40040A324003212400002ED
-:109DE0008F85003800E838213C0C8008ACA700348F
-:109DF000358B01008D6200C02E4400012403FFDF7B
-:109E0000ACA2003890AA003C0004C9403146007F53
-:109E1000A0A6003C8F8900382405FFBF9127003C95
-:109E200000E54024A128003C8F8F003891FF003CC2
-:109E300003E3C02403198025A1F0003C8F8B009C14
-:109E40008F8A00388D6E0020AD4E00408D6D00244D
-:109E5000AD4D00448D6C0028AD4C00488D62002C47
-:109E60000E000EF2AD42004C8FA600202407000227
-:109E700010C700118FA300200003202B00048023B3
-:109E80000270982400608021006090210A00114B2C
-:109E90000010882B962700128F84009800009021D4
-:109EA00030E5FFFFA7A700140E000EA1241100014A
-:109EB0000A0011F63C1080003C1980003C0280082A
-:109EC0008F240100905800080E000E783305007FA3
-:109ED0008F8E00388FAF00208FA40028A1CF000004
-:109EE0000E000ED38F9000388FAD002400023B800F
-:109EF0003C0B420000ED40258F87009C010B202584
-:109F0000AE0400048CE500388F900038000050212A
-:109F1000000A1900AE0500188CEC00343C087FFFE5
-:109F20003504FFFFAE0C001C90E9003E8E1F001CA4
-:109F30008E1800180009C9000009370203F96821CA
-:109F40000066102501B9782B0302702101CF58213A
-:109F5000AE0D001CAE0B0018AE00000CAE000010E1
-:109F600090E5003E8FAF0028240E0005A6050014E2
-:109F700094EC00042405C00001E45824A60C00164B
-:109F800090EA003E01E02021A60A002094E60004A9
-:109F9000A6060022AE00002490E3003FA6030002C4
-:109FA00090E9003E90FF003D03E9C82327380001F7
-:109FB000A21800018F8D00383C108008ADAF00085A
-:109FC000A1AE00308F9800388F82009C360F0100C0
-:109FD000970C0032944A00122410FF8000AC382401
-:109FE00031463FFF00E61825A703003293090032EF
-:109FF0002405FFBF2403FFDF313F003F37F9004056
-:10A00000A31900328F8C00382418FFFFAD80003474
-:10A010008DEE00C0AD8E0038918D003C31A2007FE6
-:10A02000A182003C8F87003890EA003C0145302433
-:10A03000A0E6003C8F9900389329003C0123F824C6
-:10A04000A33F003C8F8D00383C1F8008ADB8004016
-:10A05000ADB2004491AF00483C12800001F0702581
-:10A06000A1AE00488F8700388F86009C8CEC00489A
-:10A0700001921024004B5025ACEA004890C5003EE8
-:10A08000A0E5004C8F88009C8F8300389509000460
-:10A09000A469004E8FE500600E00031C0000000064
-:10A0A0008F99FF248FAE002800028140932F007CFF
-:10A0B0000002C1000218682131F20002004028218C
-:10A0C000164000AA01CD30213C0A800835430080AB
-:10A0D0009069007C313F000413E000038FAE00283C
-:10A0E0000005608000CC3021240D00048F900038E2
-:10A0F00031C7000301A758233168000300C820219D
-:10A10000AE0400343C068008A62500383C058000DB
-:10A110008CA4010090D100080E000EBD3225007FF6
-:10A120000E000EF2000000000A0012E08FA30020D3
-:10A130008F8500348CC2003824180003A4A00008C6
-:10A14000ACA200008CDF0034A0A0000A8F92009C1B
-:10A15000ACBF00043C040080924F003FA0B8000C4C
-:10A160008CAE000C3C0DFF9FA0AF000B01C440253E
-:10A1700035ABFFFF3C11FFEF8F98009C010B3024A3
-:10A180003639FFFF00D96024ACAC000C8F030014FB
-:10A19000971F00128F870098ACA300108F0900143E
-:10A1A000ACA00018ACA00020ACA90014ACA0002406
-:10A1B0008F0A001833E93FFF00091180ACAA00287C
-:10A1C0008F1200080047782133EE0001ACB2003056
-:10A1D0008F08000C8F990038000F69C2000E238091
-:10A1E00001A45821241100023C068008A4AB001CE5
-:10A1F000A4A00034ACA8002CA331000034D9008006
-:10A20000972C005C8F8F00383C034200318AFFFF9F
-:10A2100001433825ADE700048F82009C241800011B
-:10A220002411C0008C5F003824070034ADFF0018F3
-:10A230008C520034ADF2001CADE0000CADE000101B
-:10A24000A5E00014A5E00016A5E00020A5E000228E
-:10A25000ADE00024A5F00002A1F800018F8B0038CA
-:10A260008F8E009CAD70000891CD0000A16D003074
-:10A270008F88009C8F84003891050001A0850031F3
-:10A280008F920038964C00320191502401491825D4
-:10A29000A6430032925F003233E2003FA242003216
-:10A2A0009338007C330F000215E000028F840038E1
-:10A2B000240700303C028008AC870034345201008F
-:10A2C0008E5F00C0240EFFBF02009021AC9F0038BB
-:10A2D0009098003C330F007FA08F003C8F8800389F
-:10A2E000910D003C01AE5824A10B003C8F86003834
-:10A2F00090D1003C36390020A0D9003C8F8A009CC8
-:10A300008F8500380010882B8D4C0020ACAC0040AD
-:10A310008D430024ACA300448D490028ACA900481B
-:10A320008D47002CACA7004C0E000EF23C108000B4
-:10A330000A00114C0000000094CD00523C0B0800B4
-:10A340008D6B0024016D8821A4D100520A0010F702
-:10A35000001E882BA08700018F840038240D000187
-:10A36000AC8D00080A0012953C188008000290800D
-:10A370000A00137400D2302127BDFFE03C0D800895
-:10A38000AFB20018AFB00010AFBF001CAFB10014E7
-:10A3900035B200808E4C001835A80100964B00069F
-:10A3A00095A70050910900EC000C56020167282384
-:10A3B0003143007F312600FF24020003A38300A065
-:10A3C000AF84009810C2001B30B0FFFF910600EC74
-:10A3D0002412000530C200FF1052003300000000BC
-:10A3E000160000098FBF001C8FB200188FB1001437
-:10A3F0008FB00010240D0C003C0C800027BD002005
-:10A4000003E00008AD8D00240E0010DA02002021C8
-:10A410008FBF001C8FB200188FB100148FB00010D6
-:10A42000240D0C003C0C800027BD002003E0000838
-:10A43000AD8D0024965800789651007A924E007D9A
-:10A440000238782631E8FFFF31C400C014800009CB
-:10A450002D11000116000037000000005620FFE219
-:10A460008FBF001C0E000FB0000000000A00143C5B
-:10A470008FBF001C1620FFDA000000000E000FB096
-:10A48000000000001440FFD88FBF001C16000022FF
-:10A4900000000000925F007D33E2003FA242007D99
-:10A4A0000A00143C8FBF001C950900DA8F860078E3
-:10A4B00000802821240400050E0006AA3130FFFF89
-:10A4C0009783008A3C0480002465FFFFA785008AEB
-:10A4D0008C8A01B80540FFFE00000000AC800180BE
-:10A4E0008FBF001CAC9001848FB200188FB1001494
-:10A4F0008FB000103C0760133C0B1000240D0C00C3
-:10A500003C0C800027BD0020AC870188AC8B01B8D3
-:10A5100003E00008AD8D00240E0010DA02002021B7
-:10A520005040FFB18FBF001C925F007D0A0014698C
-:10A5300033E2003F0E0010DA020020211440FFAA8F
-:10A540008FBF001C12200007000000009259007D00
-:10A550003330003F36020040A242007D0A00143C26
-:10A560008FBF001C0E000FB0000000005040FF9E87
-:10A570008FBF001C9259007D3330003F0A001498B1
-:04A58000360200405F
-:0CA58400000000000000001B0000000FA1
-:10A590000000000A0000000800000006000000059E
-:10A5A000000000050000000400000004000000039B
-:10A5B000000000030000000300000003000000038F
-:10A5C0000000000200000002000000020000000283
-:10A5D0000000000200000002000000020000000273
-:10A5E0000000000200000002000000020000000263
-:10A5F0000000000200000002000000020000000154
-:08A60000000000010000000150
-:08A608008008010080080080B9
-:10A610008008000000000C000000308008001020BE
-:10A62000080010CC080010E4080010F80800110C15
-:10A6300008001020080010200800114008001178C0
-:10A6400008001188080011B0080018A0080018A020
-:10A65000080018D8080018D8080018EC080018BC22
-:10A6600008001B1408001AE008001B6C08001B6C93
-:10A6700008001BF408001B24800802400800228008
-:10A68000080020CC080022A80800234008002490DD
-:10A69000080024DC08002600080025080800258C96
-:10A6A0000800213C08002AA808002A4C080020E8DD
-:10A6B000080020E8080020E8080026740800267436
-:10A6C000080020E8080020E808002924080020E805
-:10A6D000080020E8080020E8080020E80800298495
-:10A6E000080020E8080020E8080020E8080020E82A
-:10A6F000080020E8080020E8080020E8080020E81A
-:10A70000080020E8080020E8080020E8080020E809
-:10A71000080020E8080020E8080024FC080020E8E1
-:10A72000080020E8080029F4080020E8080020E8D4
-:10A73000080020E8080020E8080020E8080020E8D9
-:10A74000080020E8080020E8080020E8080020E8C9
-:10A75000080020E8080020E8080020E8080020E8B9
-:10A76000080020E8080020E8080020E80800284841
-:10A77000080020E8080020E8080027BC0800271887
-:10A78000080038600800383408003800080037D462
-:10A79000080037B40800376880080100800800808E
-:10A7A0008008000080080080080047C808004800B2
-:10A7B00008004748080047C8080047C8080045285F
-:08A7C000080047C808004B9C8B
-:08A7C8000A000C7600000000FD
-:10A7D000000000000000000D727870352E302E3021
-:10A7E0006A31350005000003000000000000000190
-:10A7F0000000000000000000000000000000000059
-:10A800000000000000000000000000000000000048
-:10A810000000000000000000000000000000000038
-:10A820000000000000000000000000000000000028
-:10A830000000000000000000000000000000000018
-:10A840000000000000000000000000000000000008
-:10A8500000000000000000000000000000000000F8
-:10A8600000000000000000000000000000000000E8
-:10A8700000000000000000000000000000000000D8
-:10A8800000000000000000000000000000000000C8
-:10A8900000000000000000000000000000000000B8
-:10A8A00000000000000000000000000000000000A8
-:10A8B0000000000000000000000000000000000098
-:10A8C0000000000000000000000000000000000088
-:10A8D0000000000000000000000000000000000078
-:10A8E0000000000000000000000000000000000068
-:10A8F0000000000000000000000000000000000058
-:10A900000000000000000000000000000000000047
-:10A910000000000000000000000000000000000037
-:10A920000000000000000000000000000000000027
-:10A930000000000000000000000000000000000017
-:10A940000000000000000000000000000000000007
-:10A9500000000000000000000000000000000000F7
-:10A9600000000000000000000000000000000000E7
-:10A9700000000000000000000000000000000000D7
-:10A9800000000000000000000000000000000000C7
-:10A9900000000000000000000000000000000000B7
-:10A9A00000000000000000000000000000000000A7
-:10A9B0000000000000000000000000000000000097
-:10A9C0000000000000000000000000000000000087
-:10A9D0000000000000000000000000000000000077
-:10A9E0000000000000000000000000000000000067
-:10A9F0000000000000000000000000000000000057
-:10AA00000000000000000000000000000000000046
-:10AA10000000000000000000000000000000000036
-:10AA20000000000000000000000000000000000026
-:10AA30000000000000000000000000000000000016
-:10AA40000000000000000000000000000000000006
-:10AA500000000000000000000000000000000000F6
-:10AA600000000000000000000000000000000000E6
-:10AA700000000000000000000000000000000000D6
-:10AA800000000000000000000000000000000000C6
-:10AA900000000000000000000000000000000000B6
-:10AAA00000000000000000000000000000000000A6
-:10AAB0000000000000000000000000000000000096
-:10AAC0000000000000000000000000000000000086
-:10AAD0000000000000000000000000000000000076
-:10AAE0000000000000000000000000000000000066
-:10AAF0000000000000000000000000000000000056
-:10AB00000000000000000000000000000000000045
-:10AB10000000000000000000000000000000000035
-:10AB20000000000000000000000000000000000025
-:10AB30000000000000000000000000000000000015
-:10AB40000000000000000000000000000000000005
-:10AB500000000000000000000000000000000000F5
-:10AB600000000000000000000000000000000000E5
-:10AB700000000000000000000000000000000000D5
-:10AB800000000000000000000000000000000000C5
-:10AB900000000000000000000000000000000000B5
-:10ABA00000000000000000000000000000000000A5
-:10ABB0000000000000000000000000000000000095
-:10ABC0000000000000000000000000000000000085
-:10ABD0000000000000000000000000000000000075
-:10ABE0000000000000000000000000000000000065
-:10ABF0000000000000000000000000000000000055
-:10AC00000000000000000000000000000000000044
-:10AC10000000000000000000000000000000000034
-:10AC20000000000000000000000000000000000024
-:10AC30000000000000000000000000000000000014
-:10AC40000000000000000000000000000000000004
-:10AC500000000000000000000000000000000000F4
-:10AC600000000000000000000000000000000000E4
-:10AC700000000000000000000000000000000000D4
-:10AC800000000000000000000000000000000000C4
-:10AC900000000000000000000000000000000000B4
-:10ACA00000000000000000000000000000000000A4
-:10ACB0000000000000000000000000000000000094
-:10ACC0000000000000000000000000000000000084
-:10ACD0000000000000000000000000000000000074
-:10ACE0000000000000000000000000000000000064
-:10ACF0000000000000000000000000000000000054
-:10AD00000000000000000000000000000000000043
-:10AD10000000000000000000000000000000000033
-:10AD20000000000000000000000000000000000023
-:10AD30000000000000000000000000000000000013
-:10AD40000000000000000000000000000000000003
-:10AD500000000000000000000000000000000000F3
-:10AD600000000000000000000000000000000000E3
-:10AD700000000000000000000000000000000000D3
-:10AD800000000000000000000000000000000000C3
-:10AD900000000000000000000000000000000000B3
-:10ADA00000000000000000000000000000000000A3
-:10ADB0000000000000000000000000000000000093
-:10ADC0000000000000000000000000000000000083
-:10ADD0000000000000000000000000000000000073
-:10ADE0000000000000000000000000000000000063
-:10ADF0000000000000000000000000000000000053
-:10AE00000000000000000000000000000000000042
-:10AE10000000000000000000000000000000000032
-:10AE20000000000000000000000000000000000022
-:10AE30000000000000000000000000000000000012
-:10AE40000000000000000000000000000000000002
-:10AE500000000000000000000000000000000000F2
-:10AE600000000000000000000000000000000000E2
-:10AE700000000000000000000000000000000000D2
-:10AE800000000000000000000000000000000000C2
-:10AE900000000000000000000000000000000000B2
-:10AEA00000000000000000000000000000000000A2
-:10AEB0000000000000000000000000000000000092
-:10AEC0000000000000000000000000000000000082
-:10AED0000000000000000000000000000000000072
-:10AEE0000000000000000000000000000000000062
-:10AEF0000000000000000000000000000000000052
-:10AF00000000000000000000000000000000000041
-:10AF10000000000000000000000000000000000031
-:10AF20000000000000000000000000000000000021
-:10AF30000000000000000000000000000000000011
-:10AF40000000000000000000000000000000000001
-:10AF500000000000000000000000000000000000F1
-:10AF600000000000000000000000000000000000E1
-:10AF700000000000000000000000000000000000D1
-:10AF800000000000000000000000000000000000C1
-:10AF900000000000000000000000000000000000B1
-:10AFA00000000000000000000000000000000000A1
-:10AFB0000000000000000000000000000000000091
-:10AFC0000000000000000000000000000000000081
-:10AFD0000000000000000000000000000000000071
-:10AFE0000000000000000000000000000000000061
-:10AFF0000000000000000000000000000000000051
-:10B000000000000000000000000000000000000040
-:10B010000000000000000000000000000000000030
-:10B020000000000000000000000000000000000020
-:10B030000000000000000000000000000000000010
-:10B040000000000000000000000000000000000000
-:10B0500000000000000000000000000000000000F0
-:10B0600000000000000000000000000000000000E0
-:10B0700000000000000000000000000000000000D0
-:10B0800000000000000000000000000000000000C0
-:10B0900000000000000000000000000000000000B0
-:10B0A00000000000000000000000000000000000A0
-:10B0B0000000000000000000000000000000000090
-:10B0C0000000000000000000000000000000000080
-:10B0D0000000000000000000000000000000000070
-:10B0E0000000000000000000000000000000000060
-:10B0F0000000000000000000000000000000000050
-:10B10000000000000000000000000000000000003F
-:10B11000000000000000000000000000000000002F
-:10B12000000000000000000000000000000000001F
-:10B13000000000000000000000000000000000000F
-:10B1400000000000000000000000000000000000FF
-:10B1500000000000000000000000000000000000EF
-:10B1600000000000000000000000000000000000DF
-:10B1700000000000000000000000000000000000CF
-:10B1800000000000000000000000000000000000BF
-:10B1900000000000000000000000000000000000AF
-:10B1A000000000000000000000000000000000009F
-:10B1B000000000000000000000000000000000008F
-:10B1C000000000000000000000000000000000007F
-:10B1D000000000000000000000000000000000006F
-:10B1E000000000000000000000000000000000005F
-:10B1F000000000000000000000000000000000004F
-:10B20000000000000000000000000000000000003E
-:10B21000000000000000000000000000000000002E
-:10B22000000000000000000000000000000000001E
-:10B23000000000000000000000000000000000000E
-:10B2400000000000000000000000000000000000FE
-:10B2500000000000000000000000000000000000EE
-:10B2600000000000000000000000000000000000DE
-:10B2700000000000000000000000000000000000CE
-:10B2800000000000000000000000000000000000BE
-:10B2900000000000000000000000000000000000AE
-:10B2A000000000000000000000000000000000009E
-:10B2B000000000000000000000000000000000008E
-:10B2C000000000000000000000000000000000007E
-:10B2D000000000000000000000000000000000006E
-:10B2E000000000000000000000000000000000005E
-:10B2F000000000000000000000000000000000004E
-:10B30000000000000000000000000000000000003D
-:10B31000000000000000000000000000000000002D
-:10B32000000000000000000000000000000000001D
-:10B33000000000000000000000000000000000000D
-:10B3400000000000000000000000000000000000FD
-:10B3500000000000000000000000000000000000ED
-:10B3600000000000000000000000000000000000DD
-:10B3700000000000000000000000000000000000CD
-:10B3800000000000000000000000000000000000BD
-:10B3900000000000000000000000000000000000AD
-:10B3A000000000000000000000000000000000009D
-:10B3B000000000000000000000000000000000008D
-:10B3C000000000000000000000000000000000007D
-:10B3D000000000000000000000000000000000006D
-:10B3E000000000000000000000000000000000005D
-:10B3F000000000000000000000000000000000004D
-:10B40000000000000000000000000000000000003C
-:10B41000000000000000000000000000000000002C
-:10B42000000000000000000000000000000000001C
-:10B43000000000000000000000000000000000000C
-:10B4400000000000000000000000000000000000FC
-:10B4500000000000000000000000000000000000EC
-:10B4600000000000000000000000000000000000DC
-:10B4700000000000000000000000000000000000CC
-:10B4800000000000000000000000000000000000BC
-:10B4900000000000000000000000000000000000AC
-:10B4A000000000000000000000000000000000009C
-:10B4B000000000000000000000000000000000008C
-:10B4C000000000000000000000000000000000007C
-:10B4D000000000000000000000000000000000006C
-:10B4E000000000000000000000000000000000005C
-:10B4F000000000000000000000000000000000004C
-:10B50000000000000000000000000000000000003B
-:10B51000000000000000000000000000000000002B
-:10B52000000000000000000000000000000000001B
-:10B53000000000000000000000000000000000000B
-:10B5400000000000000000000000000000000000FB
-:10B5500000000000000000000000000000000000EB
-:10B5600000000000000000000000000000000000DB
-:10B5700000000000000000000000000000000000CB
-:10B5800000000000000000000000000000000000BB
-:10B5900000000000000000000000000000000000AB
-:10B5A000000000000000000000000000000000009B
-:10B5B000000000000000000000000000000000008B
-:10B5C000000000000000000000000000000000007B
-:10B5D000000000000000000000000000000000006B
-:10B5E000000000000000000000000000000000005B
-:10B5F000000000000000000000000000000000004B
-:10B60000000000000000000000000000000000003A
-:10B61000000000000000000000000000000000002A
-:10B62000000000000000000000000000000000001A
-:10B63000000000000000000000000000000000000A
-:10B6400000000000000000000000000000000000FA
-:10B6500000000000000000000000000000000000EA
-:10B6600000000000000000000000000000000000DA
-:10B6700000000000000000000000000000000000CA
-:10B6800000000000000000000000000000000000BA
-:10B6900000000000000000000000000000000000AA
-:10B6A000000000000000000000000000000000009A
-:10B6B000000000000000000000000000000000008A
-:10B6C000000000000000000000000000000000007A
-:10B6D000000000000000000000000000000000006A
-:10B6E000000000000000000000000000000000005A
-:10B6F000000000000000000000000000000000004A
-:10B700000000000000000000000000000000000039
-:10B710000000000000000000000000000000000029
-:10B720000000000000000000000000000000000019
-:10B730000000000000000000000000000000000009
-:10B7400000000000000000000000000000000000F9
-:10B7500000000000000000000000000000000000E9
-:10B7600000000000000000000000000000000000D9
-:10B7700000000000000000000000000000000000C9
-:10B7800000000000000000000000000000000000B9
-:10B7900000000000000000000000000000000000A9
-:10B7A0000000000000000000000000000000000099
-:10B7B0000000000000000000000000000000000089
-:10B7C0000000000000000000000000000000000079
-:10B7D0000000000000000000000000000000000069
-:10B7E0000000000000000000000000000000000059
-:10B7F0000000000000000000000000000000000049
-:10B800000000000000000000000000000000000038
-:10B810000000000000000000000000000000000028
-:10B820000000000000000000000000000000000018
-:10B830000000000000000000000000000000000008
-:10B8400000000000000000000000000000000000F8
-:10B8500000000000000000000000000000000000E8
-:10B8600000000000000000000000000000000000D8
-:10B8700000000000000000000000000000000000C8
-:10B8800000000000000000000000000000000000B8
-:10B8900000000000000000000000000000000000A8
-:10B8A0000000000000000000000000000000000098
-:10B8B0000000000000000000000000000000000088
-:10B8C0000000000000000000000000000000000078
-:10B8D0000000000000000000000000000000000068
-:10B8E0000000000000000000000000000000000058
-:10B8F0000000000000000000000000000000000048
-:10B900000000000000000000000000000000000037
-:10B910000000000000000000000000000000000027
-:10B920000000000000000000000000000000000017
-:10B930000000000000000000000000000000000007
-:10B9400000000000000000000000000000000000F7
-:10B9500000000000000000000000000000000000E7
-:10B9600000000000000000000000000000000000D7
-:10B9700000000000000000000000000000000000C7
-:10B9800000000000000000000000000000000000B7
-:10B9900000000000000000000000000000000000A7
-:10B9A0000000000000000000000000000000000097
-:10B9B0000000000000000000000000000000000087
-:10B9C0000000000000000000000000000000000077
-:10B9D0000000000000000000000000000000000067
-:10B9E0000000000000000000000000000000000057
-:10B9F0000000000000000000000000000000000047
-:10BA00000000000000000000000000000000000036
-:10BA10000000000000000000000000000000000026
-:10BA20000000000000000000000000000000000016
-:10BA30000000000000000000000000000000000006
-:10BA400000000000000000000000000000000000F6
-:10BA500000000000000000000000000000000000E6
-:10BA600000000000000000000000000000000000D6
-:10BA700000000000000000000000000000000000C6
-:10BA800000000000000000000000000000000000B6
-:10BA900000000000000000000000000000000000A6
-:10BAA0000000000000000000000000000000000096
-:10BAB0000000000000000000000000000000000086
-:10BAC0000000000000000000000000000000000076
-:10BAD0000000000000000000000000000000000066
-:10BAE0000000000000000000000000000000000056
-:10BAF0000000000000000000000000000000000046
-:10BB00000000000000000000000000000000000035
-:10BB10000000000000000000000000000000000025
-:10BB20000000000000000000000000000000000015
-:10BB30000000000000000000000000000000000005
-:10BB400000000000000000000000000000000000F5
-:10BB500000000000000000000000000000000000E5
-:10BB600000000000000000000000000000000000D5
-:10BB700000000000000000000000000000000000C5
-:10BB800000000000000000000000000000000000B5
-:10BB900000000000000000000000000000000000A5
-:10BBA0000000000000000000000000000000000095
-:10BBB0000000000000000000000000000000000085
-:10BBC0000000000000000000000000000000000075
-:10BBD0000000000000000000000000000000000065
-:10BBE0000000000000000000000000000000000055
-:10BBF0000000000000000000000000000000000045
-:10BC00000000000000000000000000000000000034
-:10BC10000000000000000000000000000000000024
-:10BC20000000000000000000000000000000000014
-:10BC30000000000000000000000000000000000004
-:10BC400000000000000000000000000000000000F4
-:10BC500000000000000000000000000000000000E4
-:10BC600000000000000000000000000000000000D4
-:10BC700000000000000000000000000000000000C4
-:10BC800000000000000000000000000000000000B4
-:10BC900000000000000000000000000000000000A4
-:10BCA0000000000000000000000000000000000094
-:10BCB0000000000000000000000000000000000084
-:10BCC0000000000000000000000000000000000074
-:10BCD0000000000000000000000000000000000064
-:10BCE0000000000000000000000000000000000054
-:10BCF0000000000000000000000000000000000044
-:10BD00000000000000000000000000000000000033
-:10BD10000000000000000000000000000000000023
-:10BD20000000000000000000000000000000000013
-:10BD30000000000000000000000000000000000003
-:10BD400000000000000000000000000000000000F3
-:10BD500000000000000000000000000000000000E3
-:10BD600000000000000000000000000000000000D3
-:10BD700000000000000000000000000000000000C3
-:10BD800000000000000000000000000000000000B3
-:10BD900000000000000000000000000000000000A3
-:10BDA0000000000000000000000000000000000093
-:10BDB0000000000000000000000000000000000083
-:10BDC0000000000000000000000000000000000073
-:10BDD0000000000000000000000000000000000063
-:10BDE0000000000000000000000000000000000053
-:10BDF0000000000000000000000000000000000043
-:10BE00000000000000000000000000000000000032
-:10BE10000000000000000000000000000000000022
-:10BE20000000000000000000000000000000000012
-:10BE30000000000000000000000000000000000002
-:10BE400000000000000000000000000000000000F2
-:10BE500000000000000000000000000000000000E2
-:10BE600000000000000000000000000000000000D2
-:10BE700000000000000000000000000000000000C2
-:10BE800000000000000000000000000000000000B2
-:10BE900000000000000000000000000000000000A2
-:10BEA0000000000000000000000000000000000092
-:10BEB0000000000000000000000000000000000082
-:10BEC0000000000000000000000000000000000072
-:10BED0000000000000000000000000000000000062
-:10BEE0000000000000000000000000000000000052
-:10BEF0000000000000000000000000000000000042
-:10BF00000000000000000000000000000000000031
-:10BF10000000000000000000000000000000000021
-:10BF20000000000000000000000000000000000011
-:10BF30000000000000000000000000000000000001
-:10BF400000000000000000000000000000000000F1
-:10BF500000000000000000000000000000000000E1
-:10BF600000000000000000000000000000000000D1
-:10BF700000000000000000000000000000000000C1
-:10BF800000000000000000000000000000000000B1
-:10BF900000000000000000000000000000000000A1
-:10BFA0000000000000000000000000000000000091
-:10BFB0000000000000000000000000000000000081
-:10BFC0000000000000000000000000000000000071
-:10BFD0000000000000000000000000000000000061
-:10BFE0000000000000000000000000000000000051
-:10BFF0000000000000000000000000000000000041
-:10C000000000000000000000000000000000000030
-:10C010000000000000000000000000000000000020
-:10C020000000000000000000000000000000000010
-:10C030000000000000000000000000000000000000
-:10C0400000000000000000000000000000000000F0
-:10C0500000000000000000000000000000000000E0
-:10C0600000000000000000000000000000000000D0
-:10C0700000000000000000000000000000000000C0
-:10C0800000000000000000000000000000000000B0
-:10C0900000000000000000000000000000000000A0
-:10C0A0000000000000000000000000000000000090
-:10C0B0000000000000000000000000000000000080
-:10C0C0000000000000000000000000000000000070
-:10C0D0000000000000000000000000000000000060
-:10C0E0000000000000000000000000000000000050
-:10C0F0000000000000000000000000000000000040
-:10C10000000000000000000000000000000000002F
-:10C11000000000000000000000000000000000001F
-:10C12000000000000000000000000000000000000F
-:10C1300000000000000000000000000000000000FF
-:10C1400000000000000000000000000000000000EF
-:10C1500000000000000000000000000000000000DF
-:10C1600000000000000000000000000000000000CF
-:10C1700000000000000000000000000000000000BF
-:10C1800000000000000000000000000000000000AF
-:10C19000000000000000000000000000000000009F
-:10C1A000000000000000000000000000000000008F
-:10C1B000000000000000000000000000000000007F
-:10C1C000000000000000000000000000000000006F
-:10C1D000000000000000000000000000000000005F
-:10C1E000000000000000000000000000000000004F
-:10C1F000000000000000000000000000000000003F
-:10C20000000000000000000000000000000000002E
-:10C21000000000000000000000000000000000001E
-:10C22000000000000000000000000000000000000E
-:10C2300000000000000000000000000000000000FE
-:10C2400000000000000000000000000000000000EE
-:10C2500000000000000000000000000000000000DE
-:10C2600000000000000000000000000000000000CE
-:10C2700000000000000000000000000000000000BE
-:10C2800000000000000000000000000000000000AE
-:10C29000000000000000000000000000000000009E
-:10C2A000000000000000000000000000000000008E
-:10C2B000000000000000000000000000000000007E
-:10C2C000000000000000000000000000000000006E
-:10C2D000000000000000000000000000000000005E
-:10C2E000000000000000000000000000000000004E
-:10C2F000000000000000000000000000000000003E
-:10C30000000000000000000000000000000000002D
-:10C31000000000000000000000000000000000001D
-:10C32000000000000000000000000000000000000D
-:10C3300000000000000000000000000000000000FD
-:10C3400000000000000000000000000000000000ED
-:10C3500000000000000000000000000000000000DD
-:10C3600000000000000000000000000000000000CD
-:10C3700000000000000000000000000000000000BD
-:10C3800000000000000000000000000000000000AD
-:10C39000000000000000000000000000000000009D
-:10C3A000000000000000000000000000000000008D
-:10C3B000000000000000000000000000000000007D
-:10C3C000000000000000000000000000000000006D
-:10C3D000000000000000000000000000000000005D
-:10C3E000000000000000000000000000000000004D
-:10C3F000000000000000000000000000000000003D
-:10C40000000000000000000000000000000000002C
-:10C41000000000000000000000000000000000001C
-:10C42000000000000000000000000000000000000C
-:10C4300000000000000000000000000000000000FC
-:10C4400000000000000000000000000000000000EC
-:10C4500000000000000000000000000000000000DC
-:10C4600000000000000000000000000000000000CC
-:10C4700000000000000000000000000000000000BC
-:10C4800000000000000000000000000000000000AC
-:10C49000000000000000000000000000000000009C
-:10C4A000000000000000000000000000000000008C
-:10C4B000000000000000000000000000000000007C
-:10C4C000000000000000000000000000000000006C
-:10C4D000000000000000000000000000000000005C
-:10C4E000000000000000000000000000000000004C
-:10C4F000000000000000000000000000000000003C
-:10C50000000000000000000000000000000000002B
-:10C51000000000000000000000000000000000001B
-:10C52000000000000000000000000000000000000B
-:10C5300000000000000000000000000000000000FB
-:10C5400000000000000000000000000000000000EB
-:10C5500000000000000000000000000000000000DB
-:10C5600000000000000000000000000000000000CB
-:10C5700000000000000000000000000000000000BB
-:10C5800000000000000000000000000000000000AB
-:10C59000000000000000000000000000000000009B
-:10C5A000000000000000000000000000000000008B
-:10C5B000000000000000000000000000000000007B
-:10C5C000000000000000000000000000000000006B
-:10C5D000000000000000000000000000000000005B
-:10C5E000000000000000000000000000000000004B
-:10C5F000000000000000000000000000000000003B
-:10C60000000000000000000000000000000000002A
-:10C61000000000000000000000000000000000001A
-:10C62000000000000000000000000000000000000A
-:10C6300000000000000000000000000000000000FA
-:10C6400000000000000000000000000000000000EA
-:10C6500000000000000000000000000000000000DA
-:10C6600000000000000000000000000000000000CA
-:10C6700000000000000000000000000000000000BA
-:10C6800000000000000000000000000000000000AA
-:10C69000000000000000000000000000000000009A
-:10C6A000000000000000000000000000000000008A
-:10C6B000000000000000000000000000000000007A
-:10C6C000000000000000000000000000000000006A
-:10C6D000000000000000000000000000000000005A
-:10C6E000000000000000000000000000000000004A
-:10C6F000000000000000000000000000000000003A
-:10C700000000000000000000000000000000000029
-:10C710000000000000000000000000000000000019
-:10C720000000000000000000000000000000000009
-:10C7300000000000000000000000000000000000F9
-:10C7400000000000000000000000000000000000E9
-:10C7500000000000000000000000000000000000D9
-:10C7600000000000000000000000000000000000C9
-:10C7700000000000000000000000000000000000B9
-:10C7800000000000000000000000000000000000A9
-:10C790000000000000000000000000000000000099
-:10C7A0000000000000000000000000000000000089
-:10C7B0000000000000000000000000000000000079
-:10C7C0000000000000000000000000000000000069
-:10C7D0000000000000000000000000000000000059
-:10C7E0000000000000000000000000000000000049
-:10C7F0000000000000000000000000000000000039
-:10C800000000000000000000000000000000000028
-:10C810000000000000000000000000000000000018
-:10C820000000000000000000000000000000000008
-:10C8300000000000000000000000000000000000F8
-:10C8400000000000000000000000000000000000E8
-:10C8500000000000000000000000000000000000D8
-:10C8600000000000000000000000000000000000C8
-:10C8700000000000000000000000000000000000B8
-:10C8800000000000000000000000000000000000A8
-:10C890000000000000000000000000000000000098
-:10C8A0000000000000000000000000000000000088
-:10C8B0000000000000000000000000000000000078
-:10C8C0000000000000000000000000000000000068
-:10C8D0000000000000000000000000000000000058
-:10C8E0000000000000000000000000000000000048
-:10C8F0000000000000000000000000000000000038
-:10C900000000000000000000000000000000000027
-:10C910000000000000000000000000000000000017
-:10C920000000000000000000000000000000000007
-:10C9300000000000000000000000000000000000F7
-:10C9400000000000000000000000000000000000E7
-:10C9500000000000000000000000000000000000D7
-:10C9600000000000000000000000000000000000C7
-:10C9700000000000000000000000000000000000B7
-:10C9800000000000000000000000000000000000A7
-:10C990000000000000000000000000000000000097
-:10C9A0000000000000000000000000000000000087
-:10C9B0000000000000000000000000000000000077
-:10C9C0000000000000000000000000000000000067
-:10C9D0000000000000000000000000000000000057
-:10C9E0000000000000000000000000000000000047
-:10C9F0000000000000000000000000000000000037
-:10CA00000000000000000000000000000000000026
-:10CA10000000000000000000000000000000000016
-:10CA20000000000000000000000000000000000006
-:10CA300000000000000000000000000000000000F6
-:10CA400000000000000000000000000000000000E6
-:10CA500000000000000000000000000000000000D6
-:10CA600000000000000000000000000000000000C6
-:10CA700000000000000000000000000000000000B6
-:10CA800000000000000000000000000000000000A6
-:10CA90000000000000000000000000000000000096
-:10CAA0000000000000000000000000000000000086
-:10CAB0000000000000000000000000000000000076
-:10CAC0000000000000000000000000000000000066
-:10CAD0000000000000000000000000000000000056
-:10CAE0000000000000000000000000000000000046
-:10CAF0000000000000000000000000000000000036
-:10CB00000000000000000000000000000000000025
-:10CB10000000000000000000000000000000000015
-:10CB20000000000000000000000000000000000005
-:10CB300000000000000000000000000000000000F5
-:10CB400000000000000000000000000000000000E5
-:10CB500000000000000000000000000000000000D5
-:10CB600000000000000000000000000000000000C5
-:10CB700000000000000000000000000000000000B5
-:10CB800000000000000000000000000000000000A5
-:10CB90000000000000000000000000000000000095
-:10CBA0000000000000000000000000000000000085
-:10CBB0000000000000000000000000000000000075
-:10CBC0000000000000000000000000000000000065
-:10CBD0000000000000000000000000000000000055
-:10CBE0000000000000000000000000000000000045
-:10CBF0000000000000000000000000000000000035
-:10CC00000000000000000000000000000000000024
-:10CC10000000000000000000000000000000000014
-:10CC20000000000000000000000000000000000004
-:10CC300000000000000000000000000000000000F4
-:10CC400000000000000000000000000000000000E4
-:10CC500000000000000000000000000000000000D4
-:10CC600000000000000000000000000000000000C4
-:10CC700000000000000000000000000000000000B4
-:10CC800000000000000000000000000000000000A4
-:10CC90000000000000000000000000000000000094
-:10CCA0000000000000000000000000000000000084
-:10CCB0000000000000000000000000000000000074
-:10CCC0000000000000000000000000000000000064
-:10CCD0000000000000000000000000000000000054
-:10CCE0000000000000000000000000000000000044
-:10CCF0000000000000000000000000000000000034
-:10CD00000000000000000000000000000000000023
-:10CD10000000000000000000000000000000000013
-:10CD20000000000000000000000000000000000003
-:10CD300000000000000000000000000000000000F3
-:10CD400000000000000000000000000000000000E3
-:10CD500000000000000000000000000000000000D3
-:10CD600000000000000000000000000000000000C3
-:10CD700000000000000000000000000000000000B3
-:10CD800000000000000000000000000000000000A3
-:10CD90000000000000000000000000000000000093
-:10CDA0000000000000000000000000000000000083
-:10CDB0000000000000000000000000000000000073
-:10CDC0000000000000000000000000000000000063
-:10CDD0000000000000000000000000000000000053
-:10CDE0000000000000000000000000000000000043
-:10CDF0000000000000000000000000000000000033
-:10CE00000000000000000000000000000000000022
-:10CE10000000000000000000000000000000000012
-:10CE20000000000000000000000000000000000002
-:10CE300000000000000000000000000000000000F2
-:10CE400000000000000000000000000000000000E2
-:10CE500000000000000000000000000000000000D2
-:10CE600000000000000000000000000000000000C2
-:10CE700000000000000000000000000000000000B2
-:10CE800000000000000000000000000000000000A2
-:10CE90000000000000000000000000000000000092
-:10CEA0000000000000000000000000000000000082
-:10CEB0000000000000000000000000000000000072
-:10CEC0000000000000000000000000000000000062
-:10CED0000000000000000000000000000000000052
-:10CEE0000000000000000000000000000000000042
-:10CEF0000000000000000000000000000000000032
-:10CF00000000000000000000000000000000000021
-:10CF10000000000000000000000000000000000011
-:10CF20000000000000000000000000000000000001
-:10CF300000000000000000000000000000000000F1
-:10CF400000000000000000000000000000000000E1
-:10CF500000000000000000000000000000000000D1
-:10CF600000000000000000000000000000000000C1
-:10CF700000000000000000000000000000000000B1
-:10CF800000000000000000000000000000000000A1
-:10CF90000000000000000000000000000000000091
-:10CFA0000000000000000000000000000000000081
-:10CFB0000000000000000000000000000000000071
-:10CFC0000000000000000000000000000000000061
-:10CFD0000000000000000000000000000000000051
-:10CFE0000000000000000000000000000000000041
-:10CFF0000000000000000000000000000000000031
-:10D000000000000000000000000000000000000020
-:10D010000000000000000000000000000000000010
-:10D020000000000000000000000000000000000000
-:10D0300000000000000000000000000000000000F0
-:10D0400000000000000000000000000000000000E0
-:10D0500000000000000000000000000000000000D0
-:10D0600000000000000000000000000000000000C0
-:10D0700000000000000000000000000000000000B0
-:10D0800000000000000000000000000000000000A0
-:10D090000000000000000000000000000000000090
-:10D0A0000000000000000000000000000000000080
-:10D0B0000000000000000000000000000000000070
-:10D0C0000000000000000000000000000000000060
-:10D0D0000000000000000000000000000000000050
-:10D0E0000000000000000000000000000000000040
-:10D0F0000000000000000000000000000000000030
-:10D10000000000000000000000000000000000001F
-:10D11000000000000000000000000000000000000F
-:10D1200000000000000000000000000000000000FF
-:10D1300000000000000000000000000000000000EF
-:10D1400000000000000000000000000000000000DF
-:10D1500000000000000000000000000000000000CF
-:10D1600000000000000000000000000000000000BF
-:10D1700000000000000000000000000000000000AF
-:10D18000000000000000000000000000000000009F
-:10D19000000000000000000000000000000000008F
-:10D1A000000000000000000000000000000000007F
-:10D1B000000000000000000000000000000000006F
-:10D1C000000000000000000000000000000000005F
-:10D1D000000000000000000000000000000000004F
-:10D1E000000000000000000000000000000000003F
-:10D1F000000000000000000000000000000000002F
-:10D20000000000000000000000000000000000001E
-:10D21000000000000000000000000000000000000E
-:10D2200000000000000000000000000000000000FE
-:10D2300000000000000000000000000000000000EE
-:10D2400000000000000000000000000000000000DE
-:10D2500000000000000000000000000000000000CE
-:10D2600000000000000000000000000000000000BE
-:10D2700000000000000000000000000000000000AE
-:10D28000000000000000000000000000000000009E
-:10D29000000000000000000000000000000000008E
-:10D2A000000000000000000000000000000000007E
-:10D2B000000000000000000000000000000000006E
-:10D2C000000000000000000000000000000000005E
-:10D2D000000000000000000000000000000000004E
-:10D2E000000000000000000000000000000000003E
-:10D2F000000000000000000000000000000000002E
-:10D30000000000000000000000000000000000001D
-:10D31000000000000000000000000000000000000D
-:10D3200000000000000000000000000000000000FD
-:10D3300000000000000000000000000000000000ED
-:10D3400000000000000000000000000000000000DD
-:10D3500000000000000000000000000000000000CD
-:10D3600000000000000000000000000000000000BD
-:10D3700000000000000000000000000000000000AD
-:10D38000000000000000000000000000000000009D
-:10D39000000000000000000000000000000000008D
-:10D3A000000000000000000000000000000000007D
-:10D3B000000000000000000000000000000000006D
-:10D3C000000000000000000000000000000000005D
-:10D3D000000000000000000000000000000000004D
-:10D3E000000000000000000000000000000000003D
-:10D3F000000000000000000000000000000000002D
-:10D40000000000000000000000000000000000001C
-:10D41000000000000000000000000000000000000C
-:10D4200000000000000000000000000000000000FC
-:10D4300000000000000000000000000000000000EC
-:10D4400000000000000000000000000000000000DC
-:10D4500000000000000000000000000000000000CC
-:10D4600000000000000000000000000000000000BC
-:10D4700000000000000000000000000000000000AC
-:10D48000000000000000000000000000000000009C
-:10D49000000000000000000000000000000000008C
-:10D4A000000000000000000000000000000000007C
-:10D4B000000000000000000000000000000000006C
-:10D4C000000000000000000000000000000000005C
-:10D4D000000000000000000000000000000000004C
-:10D4E000000000000000000000000000000000003C
-:10D4F000000000000000000000000000000000002C
-:10D50000000000000000000000000000000000001B
-:10D51000000000000000000000000000000000000B
-:10D5200000000000000000000000000000000000FB
-:10D5300000000000000000000000000000000000EB
-:10D5400000000000000000000000000000000000DB
-:10D5500000000000000000000000000000000000CB
-:10D5600000000000000000000000000000000000BB
-:10D5700000000000000000000000000000000000AB
-:10D58000000000000000000000000000000000009B
-:10D59000000000000000000000000000000000008B
-:10D5A000000000000000000000000000000000007B
-:10D5B000000000000000000000000000000000006B
-:10D5C000000000000000000000000000000000005B
-:10D5D000000000000000000000000000000000004B
-:10D5E000000000000000000000000000000000003B
-:10D5F000000000000000000000000000000000002B
-:10D60000000000000000000000000000000000001A
-:10D61000000000000000000000000000000000000A
-:10D6200000000000000000000000000000000000FA
-:10D6300000000000000000000000000000000000EA
-:10D6400000000000000000000000000000000000DA
-:10D6500000000000000000000000000000000000CA
-:10D6600000000000000000000000000000000000BA
-:10D6700000000000000000000000000000000000AA
-:10D68000000000000000000000000000000000009A
-:10D69000000000000000000000000000000000008A
-:10D6A000000000000000000000000000000000007A
-:10D6B000000000000000000000000000000000006A
-:10D6C000000000000000000000000000000000005A
-:10D6D000000000000000000000000000000000004A
-:10D6E000000000000000000000000000000000003A
-:10D6F000000000000000000000000000000000002A
-:10D700000000000000000000000000000000000019
-:10D710000000000000000000000000000000000009
-:10D7200000000000000000000000000000000000F9
-:10D7300000000000000000000000000000000000E9
-:10D7400000000000000000000000000000000000D9
-:10D7500000000000000000000000000000000000C9
-:10D7600000000000000000000000000000000000B9
-:10D7700000000000000000000000000000000000A9
-:10D780000000000000000000000000000000000099
-:10D790000000000000000000000000000000000089
-:10D7A0000000000000000000000000000000000079
-:10D7B0000000000000000000000000000000000069
-:10D7C0000000000000000000000000000000000059
-:10D7D0000000000000000000000000000000000049
-:10D7E0000000000000000000000000000000000039
-:10D7F0000000000000000000000000000000000029
-:10D800000000000000000000000000000000000018
-:10D810000000000000000000000000000000000008
-:10D8200000000000000000000000000000000000F8
-:10D8300000000000000000000000000000000000E8
-:10D8400000000000000000000000000000000000D8
-:10D8500000000000000000000000000000000000C8
-:10D8600000000000000000000000000000000000B8
-:10D8700000000000000000000000000000000000A8
-:10D880000000000000000000000000000000000098
-:10D890000000000000000000000000000000000088
-:10D8A0000000000000000000000000000000000078
-:10D8B0000000000000000000000000000000000068
-:10D8C0000000000000000000000000000000000058
-:10D8D0000000000000000000000000000000000048
-:10D8E0000000000000000000000000000000000038
-:10D8F0000000000000000000000000000000000028
-:10D900000000000000000000000000000000000017
-:10D910000000000000000000000000000000000007
-:10D9200000000000000000000000000000000000F7
-:10D9300000000000000000000000000000000000E7
-:10D9400000000000000000000000000000000000D7
-:10D9500000000000000000000000000000000000C7
-:10D9600000000000000000000000000000000000B7
-:10D9700000000000000000000000000000000000A7
-:10D980000000000000000000000000000000000097
-:10D990000000000000000000000000000000000087
-:10D9A0000000000010000003000000000000000D57
-:10D9B0000000000D3C020801244282603C03080183
-:10D9C00024638320AC4000000043202B1480FFFD23
-:10D9D000244200043C1D080037BD9FFC03A0F02139
-:10D9E0003C100800261031D83C1C0801279C82609E
-:10D9F0000E0011EA000000000000000D3C02800053
-:10DA000030A5FFFF30C600FF344301803C08800092
-:10DA10008D0901B80520FFFE00000000AC64000085
-:10DA200024040002A4650008A066000AA064000B9C
-:10DA3000AC6700183C03100003E00008AD0301B818
-:10DA40003C0560008CA24FF80440FFFE000000007F
-:10DA5000ACA44FC03C0310003C040200ACA44FC473
-:10DA600003E00008ACA34FF89486000C00A05021FE
-:10DA70002488001400062B02000510800044482171
-:10DA80000109182B10600011000000009103000034
-:10DA90002C64000950800009911900010003608086
-:10DAA0003C0D080125AD8108018D58218D670000CE
-:10DAB00000E0000800000000911900010119402158
-:10DAC0000109302B54C0FFF29103000003E000086D
-:10DAD000000010210A000CBE25080001910F000172
-:10DAE000240E000A15EE00400128C8232F38000A32
-:10DAF0001700003D250D00028D580000250F00067F
-:10DB0000370E0100AD4E0000910C000291AB0001F8
-:10DB100091A4000291A60003000C2E00000B3C0013
-:10DB200000A7102500041A000043C8250326C025BD
-:10DB3000AD580004910E000691ED000191E700023E
-:10DB400091E50003000E5E00000D6400016C3025BD
-:10DB50000007220000C41025004518252508000AEA
-:10DB60000A000CBEAD430008910F0001250400021D
-:10DB70002408000255E80001012020210A000CBE03
-:10DB800000804021910C0001240B0003158B00162E
-:10DB9000000000008D580000910E000225080003CF
-:10DBA000370D0008A14E00100A000CBEAD4D00005C
-:10DBB00091190001240F0004172F000B0000000032
-:10DBC00091070002910400038D43000000072A0022
-:10DBD00000A410253466000425080004AD42000CA2
-:10DBE0000A000CBEAD46000003E00008240200015C
-:10DBF00027BDFFE8AFBF0014AFB000100E0014E661
-:10DC0000008080213C0480083485008090A60005B7
-:10DC10002403FFFE0200202100C310248FBF001444
-:10DC20008FB00010A0A200050A0014F027BD001854
-:10DC300027BDFFE8AFB00010AFBF00140E000F4EBD
-:10DC4000008080213C06800834C5008090A400003C
-:10DC500024020050308300FF106200073C0980005E
-:10DC6000020020218FBF00148FB00010AD20018072
-:10DC70000A00101027BD0018240801003C0780008E
-:10DC8000020020218FBF00148FB00010ACE801808B
-:10DC90000A00101027BD001827BDFF703C0880083F
-:10DCA000AFB60080AFB5007CAFB1006CAFBF008CE9
-:10DCB000AFBE0088AFB70084AFB40078AFB30074D4
-:10DCC000AFB20070AFB00068350500803C0780003F
-:10DCD0008CF2012890A40009ACE0008490A6000515
-:10DCE000309100FF0000A8210006182730620001D3
-:10DCF0000000B02114400067AFA0005090A90000C0
-:10DD000024050020312400FF10850016240A00504D
-:10DD1000108A008C000000003C0C08008D8C00DC98
-:10DD2000258B00013C010800AC2B00DC0E0015DC4B
-:10DD3000000000008FBF008C8FBE00888FB700846A
-:10DD40008FB600808FB5007C8FB400788FB30074DD
-:10DD50008FB200708FB1006C8FB0006803E00008D4
-:10DD600027BD00900000000D3C108000AFA00030E7
-:10DD7000961F01168E1901043C1E002036130C005C
-:10DD8000033EC0240018B82B00173140AFA6003066
-:10DD90008E0E010433F4FFFF3C0F004002938021FC
-:10DDA00001CF68249213000D11A0004834C4004034
-:10DDB000326200201440000234860080008030214E
-:10DDC00014C00093AFA600303C05800834A8008042
-:10DDD0009107000830E6004050C000063C0680086D
-:10DDE00024090004122900A2240A0012122A002980
-:10DDF0003C06800834D401003C17800096EF011ADD
-:10DE0000960D000E928E0008326B000431F7FFFF72
-:10DE100001CD6004AFAC00548E14000411600031D9
-:10DE20008E1E000834C3008090790008333800400B
-:10DE300017000028000000008C730050029390230C
-:10DE4000064000063C0C80008C7E0034029E80233D
-:10DE5000060200838EA200083C0C8000AD800044C6
-:10DE6000240200018FBF008C8FBE00888FB7008412
-:10DE70008FB600808FB5007C8FB400788FB30074AC
-:10DE80008FB200708FB1006C8FB0006803E00008A3
-:10DE900027BD00900E000D1A000020218FBF008CBE
-:10DEA0008FBE00888FB700848FB600808FB5007C4E
-:10DEB0008FB400788FB300748FB200708FB1006C94
-:10DEC0008FB0006803E0000827BD00900A000D7ABB
-:10DED00000C020210E00163D028020211440FFDFEB
-:10DEE0003C0C80003C038008346300808C6200346A
-:10DEF0000282F82307E00017000000003C1508002C
-:10DF00008EB5310026B100013C010800AC31310072
-:10DF10000E0014E6024020213C0B80083570008082
-:10DF2000920A002502402021354200040E0014F020
-:10DF3000A20200250E000C9E024020210A000DA71F
-:10DF4000240200013C15080126B583100A000D6962
-:10DF50003C1080008C660030028620231880000868
-:10DF60002409000C3C0808008D083100327300FCC5
-:10DF70000000B821250700013C010800AC27310052
-:10DF8000AFA900308C65003000B4382318E000DB06
-:10DF900002E7502A1540FFDE0000000012E7002AC9
-:10DFA00002E768230287A02131B7FFFF326E00022B
-:10DFB00011C00034327F00103C148008369000807D
-:10DFC000920F000831F6004052C000CE8EA2000829
-:10DFD000024020210E0014E624130018A2130009A9
-:10DFE000921800052419FFFE024020210319B824CD
-:10DFF0000E0014F0A21700052404003900002821A7
-:10E000000E001618240600180A000DA724020001AD
-:10E0100092B6000C3C048008348300808C67003882
-:10E020000016AB0036B10081024020213225F0817C
-:10E030000E000C8D30C600FF3C0C8000AD8000440B
-:10E040000A000DA7240200013A6C0001318B000187
-:10E050001560FFAF0287A0210A000DF80000000044
-:10E060000040F809240400160A000DA7240200014C
-:10E07000024020210E00171D020028210A000D5C1D
-:10E080008FBF008C13E0FF743C038008346800806D
-:10E090008D0400388C66000403C610231C40FF6FFB
-:10E0A0003C0C800003C4282304A200010080F0215E
-:10E0B000AFB40010AFB70014AFA700183C1F80002A
-:10E0C00097E301208D0900309506005C8FB900545C
-:10E0D0008FAC00303062FFFF30D8FFFF0047702167
-:10E0E00037EF40000338682B01CF5821018D5025B0
-:10E0F000AFAB0020AFA90028AFAA0030AFA9002421
-:10E10000AFA0002CAFBE00349107000830E4000837
-:10E110001480008F020020218EA200040040F80924
-:10E1200027A400108FA900303128000255000001FB
-:10E13000327300FE3C048008348C0080918B000810
-:10E14000316A0040514000128FA400248C8D0004DD
-:10E1500011BE00BE240E00143265000110A0000C98
-:10E160008FA400242404000C122400D42A27000DBC
-:10E1700010E000CE2409000E2408000A52280001F5
-:10E18000241600088FA2002424440001AFA4002418
-:10E190008FA600143C038008346500800086F821B7
-:10E1A0008CB10030ACBF003090B9004E8CAE003066
-:10E1B0003418FFFF0338780401CF6821ACAD003478
-:10E1C0008FA600308FAC005430CA000803CC582111
-:10E1D0001140000CAFAB00588CA400208FB0005849
-:10E1E0001090009430C600FF92A2000C8FA700345C
-:10E1F0000240202100024B00352800800E000C8DCB
-:10E200003105F0803C0C8008359000808E0B00308A
-:10E210000171502319400070265900803C180800F5
-:10E220008F183198241FFF80033F7824332D007FFF
-:10E230003C0680003C0E800433110010ACCF0090EF
-:10E240001220003401AE282190A3006B54600032EC
-:10E250003C10800824070001A0A7006B94C4007A3A
-:10E260002486000AA60600123C0D800835A5008011
-:10E2700090B10008322C0040158000043C03800857
-:10E28000326E000115C0006200000000346400809E
-:10E290008C8F00208FB3005811F3000A3463010003
-:10E2A0008C7900000299C0231B0000778FA80058CA
-:10E2B000AC880020AC74000024140001AC7E000483
-:10E2C000AFB4005016C00037000000008FA400500B
-:10E2D000148000300000000012E00005000018214A
-:10E2E0008FA900303137000452E0FE920060102107
-:10E2F000240300010A000D5B006010210A000DF9E3
-:10E30000000038210040F809240400170A000DA776
-:10E31000240200013C10800836100080240900010E
-:10E32000024020210E0014E6A609001292080025E2
-:10E3300024050001AFA50050350200010240202154
-:10E340000E0014F0A20200250A000EA93C0D800860
-:10E3500027A50038AFA800600E000CA8AFA00038B9
-:10E360001440FF6D8FA800608FA5003830B0010009
-:10E370005200FF6A8EA200048FA3003C8D07005854
-:10E38000006720230483FF64AD0300580A000E5584
-:10E390008EA200040E000C9E024020210A000EC432
-:10E3A000000000000E0014E6024020213C05800819
-:10E3B00034A30080024020210E0014F0A076000952
-:10E3C00002C03021240400370E0016180000282156
-:10E3D0000A000EC28FA400508FA200185840FFA35D
-:10E3E0003C0D80080E0014E602402021920A002510
-:10E3F000240B0001AFAB0050354200040240202145
-:10E400000E0014F0A20200250A000EA93C0D80089F
-:10E410008CB600308EBE00082404001826D50001FA
-:10E4200003C0F809ACB500308FB200300A000D5BB4
-:10E43000324200043C07800094E5011A50A0FF6AB4
-:10E4400034C600100A000E8992A2000C122E002A77
-:10E450002A2F001511E0001E241900162418000CA4
-:10E460005638FF3E326500013C1F800893E3001BD5
-:10E470002410FFBD2416000E00703024A3E6001BFC
-:10E480000A000E65326500018C7F000017F4FF8DD5
-:10E49000000000008C67000403C7302304C1FF8420
-:10E4A0008FA800580A000EBF000000001629FF3692
-:10E4B0008FA200240A000E70241600102411000EF2
-:10E4C00052D1FF30241600100A000E6F24160016D9
-:10E4D0005639FF22326500013C1F800893E3001B80
-:10E4E0002410FFBD2416001000703024A3E6001B8A
-:10E4F0000A000E65326500010A000E64241600123F
-:10E500003C0380008C6201B80440FFFE2404080034
-:10E51000AC6401B803E000080000000030A5FFFF74
-:10E5200030C6FFFF3C0780008CE201B80440FFFECC
-:10E5300034E80180AD040000ACE400203C04800815
-:10E54000948300483063FFFF1060001D3C0B800087
-:10E5500024AA0012006A482B5120001A240A000342
-:10E5600094F901208F890000240C001A3338FFFF32
-:10E570002707FFFE0067782B39EE000100096B8248
-:10E5800001AE5824A10C000B116000478F830004DA
-:10E59000A50700148F88000435070001AF87000429
-:10E5A00030CC00405580000F3C0880003C0C8000BF
-:10E5B00035840180A485000E0A000F988F8F000C0F
-:10E5C000240A00033564018030CC00408F890000AC
-:10E5D0008F870004A08A000B5180FFF53C0C80005F
-:10E5E0003C088000950301203C08800895180040F5
-:10E5F0003079FFFF272EFFFE330FFFFF01CF682B7F
-:10E6000011A0000301C02021950200403044FFFF0B
-:10E610003C0B800000A4502335650180A4A4000EAB
-:10E62000A4AA00248F8F000C3C05800034AE01802A
-:10E630002418000230ED8000A5D8000CA5C90010F8
-:10E64000ADCF0028A5C6000811A0000E3C04800034
-:10E6500094AA01163142FFFC244800040105182148
-:10E660008C7940003326FFFF14C00007240EBFFF43
-:10E670003C0BFFFF35657FFF00E53824AF870004C2
-:10E680003C048000240EBFFF348C018000EE68241F
-:10E69000A58D0026AD89002C3C071000AC8701B881
-:10E6A00003E00008000000002402FFFE006238249E
-:10E6B0000A000F76AF8700043C05800034A4007088
-:10E6C0008C8A000090A601128F84000027BDFFF005
-:10E6D00030C300FF0003188230820100000038219F
-:10E6E00010400039246600033087400050E00039B4
-:10E6F00030882000000610800045C8218F2F400080
-:10E700002478000400187080AFAF000001C56821B4
-:10E710008DAC4000AFAC000494AB01163169FFFC36
-:10E72000012540218D054000AFA500088FA90008F4
-:10E7300000003021000028213C07080024E70100E8
-:10E740000A000FE9240800089042000024A50001F7
-:10E750002CAD000C0062C8210019C080030778218D
-:10E760008DEE000011A0000600CE302603A510217A
-:10E7700014A8FFF500051A005520FFF49042000090
-:10E780003C048000348700703C0508008CA53104EF
-:10E790008CE300002CA8002011000009006A382337
-:10E7A000000558803C0C0800258C3108016C48217C
-:10E7B00024AA0001AD2700003C010800AC2A310466
-:10E7C000AF86000C2407000100E0102103E00008E0
-:10E7D00027BD00101100FFFC0000382100066080FA
-:10E7E000018558218D6440002469000400093880A7
-:10E7F000AFA4000000E518218C664000AFA000081F
-:10E800000A000FD9AFA6000427BDFFD8AFB2001889
-:10E81000AFB00010AFBF0024AFB40020AFB3001CF6
-:10E82000AFB100148F8700003C0480009483010E78
-:10E8300030E2400000008021104000103072FFFFE5
-:10E840003C06002000E6282410A0000D30EA8000DD
-:10E850008F8800042409BFFF00E938243503100025
-:10E86000AF87000030F120001620000B3C1400049C
-:10E870002418FFBF0A0010380078102430EA800006
-:10E88000154000863C0C002030F120001220FFF8DB
-:10E890008F8300043C14000400F498241260FFF5F8
-:10E8A0002418FFBF3462004030F901001320000F2C
-:10E8B000AF8200043C02002000E2F82413E00005CF
-:10E8C0003C0B80003C04000400E41824106000CFDE
-:10E8D00000000000956A011E9569011C3146FFFF8A
-:10E8E0000009440000C82825AF85000C3C0E8000BC
-:10E8F00095CD010C8DC44000340CFFFF108C00B08E
-:10E9000031A5FFFF308F010055E0000124100010F9
-:10E9100030F11000522000083611000130F30020C1
-:10E920001660009F3C18100000F8A0241680009686
-:10E930003C040C003611000130E801001500000B0A
-:10E940003C0A00018F8800043109400015200008AE
-:10E9500000EA30243C0C1F0100EC58243C0A100053
-:10E96000516A00AE30AD02003C0A000100EA3024DA
-:10E9700014C000953C05100000E520240000402153
-:10E98000108000070000902100079E023272000FE5
-:10E99000001278803C0E080125CE82C001EE402195
-:10E9A0008F9400181280004702208021108000916F
-:10E9B000000000003C0980009539010E9103000021
-:10E9C000022030213338FFFF2705000410600008C3
-:10E9D0000000A021241F0003107F013A240400023C
-:10E9E000910C00011184011830EA00400012A1C00E
-:10E9F0008F92001C52400001362600403C138000DC
-:10EA00008E6F400031F10100122000CB30D1FFFBAE
-:10EA10003C1808008F18002430D20004330600048C
-:10EA200014C000CC30B0FFFF564000013631000466
-:10EA300002802021020028210E000F5502203021E3
-:10EA40001640000D00002021366501803C04800046
-:10EA50008C9301B80660FFFE2419200024140002E4
-:10EA6000A4B90008A0B4000BA4A000103C0510003D
-:10EA7000AC8501B8000020218FBF00248FB4002096
-:10EA80008FB3001C8FB200188FB100148FB000102C
-:10EA90000080102103E0000827BD002800EC582466
-:10EAA0001160FF7A30F120008F8D00043C0FFFFFD2
-:10EAB00035EE7FFF00EE382435A380000A001027D2
-:10EAC000AF8700003C0208008C4200383C0408007C
-:10EAD000248400381040004B2449FFFF3C03800091
-:10EAE000946C010E318BFFFF110000A02573000410
-:10EAF0003C1008008E1000301200000A30E60100C1
-:10EB00008F8A000431434000106000063C0F0F0064
-:10EB100000EF70243C0D010001AE402B110000DF1E
-:10EB20003265FFFF10C000693C140F0000F4282478
-:10EB30003C18020010B800658F99000C3270FFFF7E
-:10EB40000329982402649021924900042527000497
-:10EB5000000721C002002821362600020E000F55B2
-:10EB6000000000008FBF00248FB400208FB3001C72
-:10EB70008FB200188FB100148FB000100000102168
-:10EB800003E0000827BD00283C020BFF00E4182426
-:10EB9000345FFFFF03E3C82B5320FF6736110001EA
-:10EBA0003C0608008CC6002C3611000524D000015C
-:10EBB0003C010800AC30002C0A00105D30E8010078
-:10EBC0000A00105224100020024028213C120800A4
-:10EBD0008E5200D824040080264D00013C0108001C
-:10EBE000AC2D00D80E000F55240600030A0010E8D3
-:10EBF0008FBF00243C080801250882C00A00107C51
-:10EC00003C0980000A0010C5000048210E000FBC1E
-:10EC1000000000000A0010498F87000015A0FF5374
-:10EC20003C0A00012645000430AAFFFF36260002F8
-:10EC30003C0380008C7201B80640FFFE8F850008FF
-:10EC400034690180AD20000010A000AF3C048000BA
-:10EC5000254F001200AF702B51C000AC24030003FD
-:10EC6000947801202414001A30F140003313FFFF80
-:10EC7000A134000B122000B62663FFFE00A3C82BB0
-:10EC8000572000B4241FFFFE35080001A5230014FF
-:10EC9000AF8800043C108000240CBFFF010C482406
-:10ECA000240B000236080180A50B000CA50A000EFB
-:10ECB000A5060008A5090026A50700103C071000BE
-:10ECC000AE0701B80A0010E88FBF00243C0308001B
-:10ECD0008C6300D02E45000C001221C0386B00015F
-:10ECE0002D6200010045F82417E0FF9A3270FFFF03
-:10ECF000264CFFFC2D84000454800050000020218D
-:10ED0000386A00022D430001006580241600004A85
-:10ED10003270FFFF00076A420012702B01AE4024E0
-:10ED20005500006300002021001221C002002821AC
-:10ED30000A0010E53626000234DF0002028020219E
-:10ED400033E6FFFF0E000F5530A5FFFF0A0010ACA1
-:10ED50000000202124040100020028210E000F558C
-:10ED6000022030210A001098000000008C6640004C
-:10ED700030CF010011E0003D30F801003C120800E6
-:10ED80008E52002413000011323400043C1F0F0087
-:10ED900000FFC8243C0502001325000C8F8C000CDA
-:10EDA000022030213265FFFF0189582401641021BF
-:10EDB000904900043230FFFB2411FFFE2527000498
-:10EDC0000E000F55000721C00251902424040001B9
-:10EDD00012440052324300011460005802003021F6
-:10EDE000324A0004114000048F8D000031A8080051
-:10EDF0001500005A3265FFFF1680FF5B8FBF0024AD
-:10EE00003C138000366501803C0480008C9001B882
-:10EE10000600FFFE24062000240F0002A4A600081E
-:10EE2000A0AF000BA4A000103C0E1000AC8E01B8E7
-:10EE30000A0010E88FBF00240000202102002821D2
-:10EE40000A0010E5362600021140FEE90000A0216C
-:10EE5000952E0110950D000231C8FFFF51A8FEE468
-:10EE60000012A1C00A00108B8F92001C3C05080004
-:10EE70008CA5002430B800015300FF3B8FBF002455
-:10EE80003265FFFF36260002000020210E000F55DC
-:10EE9000000000000A0010E88FBF002436260002A0
-:10EEA0000E000F55240400800A0010E88FBF0024D4
-:10EEB000020028210E000F553226FFFB0A001159CF
-:10EEC000001221C091030001240200011062FEEA39
-:10EED00024040001241000021470FEC50000A021CB
-:10EEE00030E300401060FEC38F92001C952B011090
-:10EEF000950900023167FFFF1127FEE08FBF002454
-:10EF00000A00108B000000002403000334820180FB
-:10EF1000A043000B0A0011343C108000321400049E
-:10EF2000168000033265FFFF361200023250FFFFE9
-:10EF3000020030210A0011B1000020210000202130
-:10EF40000E000F553265FFFF0A0011863210FFFBDD
-:10EF5000241FFFFE0A001132011F4024020030214D
-:10EF60000E000F55240401000A00118C000000005F
-:10EF700027BDFFC8AFB00010AFBF00343C10600C1D
-:10EF8000AFBE0030AFB7002CAFB60028AFB500243D
-:10EF9000AFB40020AFB3001CAFB20018AFB1001483
-:10EFA0008E0E5000240FFF7F3C06800001CF6824A6
-:10EFB00035AC380C240B0003AE0C5000ACCB000871
-:10EFC0003C010800AC2000200E00174900000000A2
-:10EFD0003C0A0010354980513C066016AE09537C4E
-:10EFE0008CC700003C0860148D0500A03C03FFFFA7
-:10EFF00000E320243C02535300051FC2108202622A
-:10F0000034C57C008CBE007C8CBF00783C02600064
-:10F01000344420203C05080124A581382406000A38
-:10F020003C170098AF9E0014AF9F00100E0015F221
-:10F030003C11800036F600C03C1900103C18600CF2
-:10F040003C158000AF1953FC363E0180AEB6013C42
-:10F050008E300000320400031080FFFD32050001F5
-:10F0600014A000593206000210C0FFF93C048000D1
-:10F070008C92014024100040AC9200208C8F0148FB
-:10F08000000F760231C300701070013E2C780041F1
-:10F090005300000824040060241900201079000E99
-:10F0A0003C1F40003C088000AD1F01780A0012227E
-:10F0B000000000001464FFFB3C1F40000E001F66B0
-:10F0C000000000003C1F40003C088000AD1F01789C
-:10F0D0000A001222000000008C940148241700044A
-:10F0E0003488018000144C02312500FF8C830140DC
-:10F0F00010B7017024ABFFFA2D6A000651400013CF
-:10F100003C0580008C86014430A400FF30C300FF22
-:10F1100030D500FF2C76000816C0000226A7000498
-:10F1200024070003240C0009108C01A8288D000A74
-:10F1300011A001942413000A24050008108500146E
-:10F140008F980018000719C03C0580008CA701B8F3
-:10F1500004E0FFFE24140002AD030000A50900082E
-:10F16000A114000B8CB701483C0910003C1F400063
-:10F17000A51700108CA40144AD0400243C088000B5
-:10F18000ACA901B8AD1F01780A00122200000000EE
-:10F19000000692020007C8803C040801248482C053
-:10F1A00003247821270E0001324500FF24100001BE
-:10F1B000A1F2000014B0FFE3AF8E0018000719C0E1
-:10F1C0000A001260AF85001C8E3401283C068008BE
-:10F1D000AE3400208E2A01048E29010094C8004814
-:10F1E000AF8A0000AF8900043103FFFF0E000F4E0D
-:10F1F000AF8300083C0708008CE700C010E0002443
-:10F200008F8700003C0C08008D8C00C4258B00010A
-:10F210003C010800AC2B00C43C1980008F24012461
-:10F220003C186020AF040014000000003C06800081
-:10F230003C174000ACD70138000000005280FF8A24
-:10F240003206000226870140268500802409FF80BF
-:10F2500000E9682400A998240013194030AC007F0D
-:10F26000000DB14030F5007F3C0B200035620002FC
-:10F27000006C402502D550250142A0250102F82549
-:10F28000ACDF0830ACD408300A0012283206000285
-:10F290003C0E001000EE682415A000A68F83000429
-:10F2A0003C1508008EB500203C16800096D2010E59
-:10F2B00026B3000130EF40003255FFFF3C0108004B
-:10F2C000AC33002011E000B6000090213C18002073
-:10F2D00000F8B82412E000B330E280008F990004F7
-:10F2E000241FBFFF00FF382437231000AF87000022
-:10F2F00030EA2000114000B5240CFFBF3C0B000495
-:10F3000000EB302410C00002006C10243462004076
-:10F3100030ED010011A0000EAF8200043C0F002070
-:10F3200000EF702411C000043C16000400F698247D
-:10F3300012600135000000009622011E963F011C5C
-:10F340003058FFFF001FCC000319B825AF97000C01
-:10F350009628010C8E2440003403FFFF108300C860
-:10F360003105FFFF308901005520000124120010F3
-:10F3700030E41000108000133653000130EA002002
-:10F380001540000A3C0B100000EB302410C0000DAB
-:10F390003C0F0BFF3C130C0000F3702435EDFFFF16
-:10F3A00001AE602B11800007365300013C160800A7
-:10F3B0008ED6002C3653000526D200013C010800F1
-:10F3C000AC32002C30F7010016E0000B3C060001C7
-:10F3D0008F880004311840005700000800E62824F8
-:10F3E0003C021F0100E2F8243C19100013F9010A45
-:10F3F00030A302003C06000100E6282414A000A26D
-:10F400003C09100000E92024000040211080000782
-:10F410000000A821000766023195000F00155880F2
-:10F420003C0A0801254A82C0016A40218F8D0018DC
-:10F4300011A0006802609021148000033C09800044
-:10F440003C080801250882C0952E010E910300009A
-:10F450000260302131C4FFFF2485000410600008E1
-:10F460000000B821240F0003106F011E24190002B0
-:10F47000911F000113F9002630E200400015B9C0C9
-:10F480008F89001C51200001366600403C16800028
-:10F490008ECB400031730100126000C530D50004EE
-:10F4A0003C0C08008D8C002430D3FFFB3186000417
-:10F4B00014C0010630B2FFFF56A0000136730004ED
-:10F4C00002E02021024028210E000F550260302169
-:10F4D00016A0000D0000202136C501803C048000EC
-:10F4E0008C8D01B805A0FFFE240F2000240E000221
-:10F4F000A4AF0008A0AE000BA4A000103C051000B3
-:10F50000AC8501B8000020210A001367008010219B
-:10F510001040FFDB0000B821952A0110950300027E
-:10F520003148FFFF5068FFD60015B9C00A00132FFD
-:10F530008F89001C2413BFFF0073282410A000072C
-:10F54000240E87FF006E48241520000A3C1200603C
-:10F5500000F2782411E00007000000000E000D34D6
-:10F56000000000001040FF323C0680000A001295A7
-:10F570003C1980000E0014CF000000000A00136741
-:10F58000000000000E0014F5000000003C1F4000C9
-:10F590003C088000AD1F01780A0012220000000024
-:10F5A00030E280001040FF528F8300043C050020B1
-:10F5B00000E520241080FF4E3C09FFFF35287FFF27
-:10F5C00000E838240A0012C9346380000A0012D20D
-:10F5D000006C10243C0408008C8400381480000265
-:10F5E0002489FFFF000048213C0380009476010E2F
-:10F5F00032D7FFFF110000EA26F600043C12080093
-:10F600008E5200301240000A30EA01008F99000447
-:10F6100033384000130000063C030F0000E3402491
-:10F620003C0201000048F82B13E000D232C5FFFF76
-:10F630001140002F3C0C0F0000EC30243C0B02006A
-:10F6400010CB002B8F8F000C3C0E080025CE00380D
-:10F6500032D2FFFF01E9282400AE682191A90004FD
-:10F6600025270004000721C0024028213666000239
-:10F670000E000F55000000000A0013670000102163
-:10F680000A0012EA241200203C0308008C6300D810
-:10F6900002A0282124040080246200013C0108000B
-:10F6A000AC2200D80E000F55240600030A00136791
-:10F6B000000010218C840140010028213C038000BF
-:10F6C0008C7F01B807E0FFFE2402001CACA4000000
-:10F6D000A0A2000B3C081000AC6801B83C1F400021
-:10F6E0003C088000AD1F01780A00122200000000D3
-:10F6F0003C0308008C6300D02EA5000C001521C02F
-:10F70000387800012F1200010245B82416E0FFD618
-:10F7100032D2FFFF26B9FFFC2F240004148000081A
-:10F7200000002021386800022D0200010045F82465
-:10F7300013E0000600075A4232D2FFFF00002021EA
-:10F74000024028210A0013AA366600020015182B71
-:10F75000016350241540000532D2FFFF001521C07F
-:10F76000024028210A0013AA366600020000202168
-:10F77000024028210E000F553266FFFB0A0013E6F7
-:10F78000001521C010930068000768802406000B54
-:10F790001486FE6D000719C00007C0803C190801DF
-:10F7A000273982C0031930210A001260A0C000016D
-:10F7B00034D5000202E0202130A5FFFF0E000F55D6
-:10F7C00032A6FFFF0A001350000020210007A0808E
-:10F7D0003C1F080127FF82C0029F102190570000A4
-:10F7E00012E0FE59000719C0A04000008F8A0018DF
-:10F7F0002542FFFF1440FE54AF820018000719C0D5
-:10F800000A001260AF80001C0E000FBC0000000058
-:10F810000A0012E28F8700001460FEF73C06000128
-:10F8200026A900043125FFFF366600023C03800054
-:10F830008C7501B806A0FFFE8F8900083C0A800085
-:10F8400035440180AC8000001120009B2418000387
-:10F8500024AC0012012C582B11600097000000000E
-:10F86000947201203C138000240F001A324EFFFFD7
-:10F87000366A018030ED4000A14F000B11A00091CD
-:10F8800025C3FFFE0123B02B16C0008F2417FFFEF7
-:10F8900035080001A5430014AF880004241FBFFFF2
-:10F8A000011FC82424080002A7C8000CA7C5000E29
-:10F8B000A7C60008A7D90026A7C700103C0710005C
-:10F8C000AE2701B80A0013670000102124040100CC
-:10F8D000024028210E000F55026030210A00133C1F
-:10F8E0000000000091030001241500011075FF06BF
-:10F8F00024040001241200021472FEE10000B82169
-:10F9000030F6004052C0FEDF8F89001C95270110A1
-:10F910009518000230F7FFFF1317FEFB0000B82117
-:10F920000A00132F8F89001C3C120801265282C046
-:10F9300001B2702100067A02A1CF00013C0B6000E9
-:10F940008D6318202410000100F098043C05080184
-:10F9500024A582C20073B02501A5A8210006640277
-:10F96000000719C0A6AC0000AD7618200A0012618D
-:10F970003C058000366600020E000F55240400800E
-:10F980000A001367000010210003A080028698215E
-:10F990008E7200043C1160000A00120F02512821EF
-:10F9A0008C66400030D5010012A0003730EC010019
-:10F9B0003C1508008EB50024118000133277000436
-:10F9C0003C050F0000E568243C07020011A7000E6B
-:10F9D0008F84000C3C180800271800380260302182
-:10F9E000008990240258782191EE000432C5FFFF6F
-:10F9F0003272FFFB25C90004000921C00E000F551B
-:10FA00002413FFFE02B3A8242419000112B9003008
-:10FA100032A200011040000732A800040240302149
-:10FA2000000020210E000F5532C5FFFF3252FFFBB0
-:10FA300032A80004110000048F8B0000316A080016
-:10FA40005540002B32C5FFFF16E0FEC60000102116
-:10FA50003C16800036C401803C0580008CA301B8B0
-:10FA60000460FFFE240C200024060002A48C000881
-:10FA7000A086000BA48000103C151000ACB501B8A6
-:10FA80000A001367000010213C0D08008DAD002412
-:10FA900031A7000150E0FEB30000102132C5FFFF86
-:10FAA00036660002000020210E000F550000000005
-:10FAB0000A00136700001021A3D8000B0A001436B7
-:10FAC000241FBFFF2417FFFE0A001434011740242F
-:10FAD0003257000416E0000332C5FFFF365F000214
-:10FAE00033F2FFFF024030210A0014B80000202149
-:10FAF000024030210E000F55240401000A0014A01A
-:10FB0000000000003C0380008C6401003082003E55
-:10FB10001440000800000000AC6000488C66010042
-:10FB200030C507C010A0000500000000AC60004C0C
-:10FB3000AC60005003E0000824020001AC600054F7
-:10FB4000AC6000408C6801003107380010E0FFF91C
-:10FB5000000000002402000103E00008AC60004443
-:10FB60003C03900034620001008220253C038000A9
-:10FB7000AC6400208C65002004A0FFFE00000000A3
-:10FB800003E00008000000003C0280003443000154
-:10FB90000083202503E00008AC44002027BDFFD8E7
-:10FBA000AFB100143C048000AFBF0020AFB3001C15
-:10FBB000AFB20018AFB000108C9201408C90014899
-:10FBC0002402000E00108C02322300FF1062005944
-:10FBD000020428242866000F10C00013286A00378A
-:10FBE000240700061067008E286800075100002DCA
-:10FBF00024040009106000783C06800024090001FC
-:10FC0000106900B0000000000000000D8FBF002050
-:10FC10008FB3001C8FB200188FB100148FB000108A
-:10FC200003E0000827BD002811400059240D0038CA
-:10FC3000286B0035116000053C058000240C001F76
-:10FC4000146CFFF1000000003C0580008CB801B886
-:10FC50000700FFFE34B90180AF320000241F00010D
-:10FC6000241200023C021000AF200004A73100085B
-:10FC7000A33F000AA332000BA7300010AF200024DE
-:10FC8000AF200028ACA201B88FBF00208FB3001CAA
-:10FC90008FB200188FB100148FB0001003E000087D
-:10FCA00027BD0028106400232405000B1465FFD62F
-:10FCB0003218FFFF170000203C0580008F93FED014
-:10FCC000927F000533F900041720FFCF00000000E9
-:10FCD0000E0014E602402021926900050240202116
-:10FCE000352800040E0014F0A26800059267000594
-:10FCF00030E2000414400002000000000000000D8B
-:10FD0000926B000024060020316A00FF1546000AAD
-:10FD10003C0580008CA401B80480FFFE34AD018056
-:10FD2000240E00053C0C1000ADB20000A1AE000B8B
-:10FD3000ACAC01B83C0580008CA301B80460FFFEA8
-:10FD400034AF018024130002ADF20000ADF20004D4
-:10FD5000A5F10008A1F3000AA1F3000BA5F0001023
-:10FD6000ADE000248CB101443C101000ADF100283E
-:10FD7000ACB001B88FBF00208FB3001C8FB2001849
-:10FD80008FB100148FB0001003E0000827BD0028D9
-:10FD9000106DFFAD240E0080146EFF9B000000006C
-:10FDA0003C0580008CA301B80460FFFE34AF0180E5
-:10FDB00024120002A1F2000BA5F10008A5F000102A
-:10FDC0008CB301443C021000A5F30012ACA201B8B0
-:10FDD0000A0015318FBF00208CC301B80460FFFEFC
-:10FDE00034D30180AE720000AE6000042412000122
-:10FDF000A671000824110002A272000AA271000B71
-:10FE0000A67000108CD001443C0F1000AE7000248E
-:10FE1000AE600028ACCF01B80A00156C8FBF00207F
-:10FE20003C0380008C6601B804C0FFFE3462018090
-:10FE30003C06080190C68300AC52000010C00003CD
-:10FE4000000038213C0708018CE783083C0580004E
-:10FE500034AA01802404000234CC0001AC47000421
-:10FE6000A5510008A14C000AA144000BA5500010A8
-:10FE70008CAB01440000202101402821AD4B00241F
-:10FE800010C000038FBF00203C0408018C84830451
-:10FE90008FB3001C8FB200188FB100148FB0001008
-:10FEA0003C0E10003C0D800027BD0028ACA40028AB
-:10FEB000ADAE01B83C010801A020830003E00008BA
-:10FEC0000000000010A0000B3C0680008C9801444C
-:10FED000241900023C010801A03983003C010801FB
-:10FEE000AC3283083C010801AC3883040A00156C6D
-:10FEF0008FBF00208CDF01B807E0FFFE34C7018010
-:10FF000024090002ACF20000ACF20004A4F10008E5
-:10FF1000A0E9000AA0E9000BA4F00010ACE0002466
-:10FF20008CC801443C021000ACE80028ACC201B807
-:10FF30000A00156C8FBF002027BDFFE8AFBF00107F
-:10FF40000E000F4E000000003C0280008FBF00102A
-:10FF500000002021AC4001800A00101027BD0018CD
-:10FF60003084FFFF30A5FFFF10800007000018213C
-:10FF70003082000110400002000420420065182178
-:10FF80001480FFFB0005284003E0000800601021FA
-:10FF900010C00007000000008CA2000024C6FFFF74
-:10FFA00024A50004AC82000014C0FFFB24840004DC
-:10FFB00003E000080000000010A0000824A3FFFFD9
-:10FFC000AC86000000000000000000002402FFFFDB
-:10FFD0002463FFFF1462FFFA2484000403E0000896
-:10FFE0000000000027BDFFE8AFBF0014AFB0001055
-:10FFF0000E0014E6008080213C04800834830080D9
-:020000040001F9
-:10000000906500250200202134A200200E0014F08B
-:10001000A0620025020020218FBF00148FB00010C5
-:100020000A000C9E27BD00183C03800027BDFFF886
-:1000300034620180AFA20000308C00FF30AD00FFC1
-:1000400030CE00FF3C0B80008D6401B80480FFFEC1
-:10005000000000008FA900008D6801288FAA000011
-:100060008FA700008FA400002405000124020002D5
-:10007000A085000A8FA30000359940003C051000C0
-:10008000A062000B8FB800008FAC00008FA60000AC
-:100090008FAF000027BD0008AD280000AD40000470
-:1000A000AD800024ACC00028A4F90008A70D001002
-:1000B000A5EE001203E00008AD6501B83C0680081B
-:1000C00027BDFFE834C50080AFBF001090A700092E
-:1000D0002402001230E300FF1062000B0080302188
-:1000E0008CA8005000882023048000088FBF0010D7
-:1000F0008CAA0034240400390000282100CA4823B7
-:1001000005200005240600128FBF00102402000104
-:1001100003E0000827BD00180E00161800000000BC
-:100120008FBF00102402000103E0000827BD001863
-:1001300027BDFFC8AFB1002C00A08821AFB20030AE
-:1001400027A500100080902102202021AFBF00349D
-:10015000AFB000280E000CA8AFA000101440009B08
-:100160003C07800834E400809086000830C5000811
-:1001700014A000698FA700103C1880083710008079
-:10018000920F000831EE000815C000022408000399
-:10019000000040213C0B800891650011916A00121B
-:1001A000356600808CDF0054314900FF0128202192
-:1001B00030A300FF000410800062282100BFC82B7C
-:1001C000132000080000000094D0005C8CCF005485
-:1001D000320DFFFF01E5702301AE602B118000940A
-:1001E0000000000094D9005C3323FFFF30FF0004BF
-:1001F00013E00074000830808FA8001C0068102BEA
-:100200005040004F30E30004006610232C4600806D
-:1002100010C0000200408021241000800E0014E66F
-:10022000024020213C03800834660080240700013E
-:10023000ACC7000C90C8000800106840346701008B
-:10024000311F007FA0DF00088E390004273800012D
-:10025000ACD80030A4D0005C8CCF003C9630000EAF
-:1002600001F07021ACCE00208CCC003C018D5821D7
-:10027000ACCB001C8E2A0004ACEA00008E290008DA
-:10028000ACE900048FA5001030A4000854800032AF
-:1002900093A60020A0C0004E90C9004E2402FFDFAC
-:1002A0003C188008A0E9000890C50008370D0080C0
-:1002B000240A005000A22024A0C400088E3900089F
-:1002C000ADB900388F0F00148DB0003001F07021EF
-:1002D000ADAE003491AC0000318B00FF116A002CF0
-:1002E000264501000E0014F00240202124040038AD
-:1002F000000028210E0016182406000A8FBF0034C3
-:100300008FB200308FB1002C8FB000282402000182
-:1003100003E0000827BD003830E801001100003D6F
-:100320008FA300148C8A0058006A48230520FF938D
-:100330003C188008AC8300580A00166C8FA7001088
-:10034000240702181060FFB100E610238FA2001CE2
-:100350000A001691004610233C188008370D0080D3
-:10036000A0E600088E390008240A0050ADB9003814
-:100370008F0F00148DB0003001F07021ADAE00344D
-:1003800091AC0000318B00FF156AFFD626450100B5
-:100390002406FF8000A610243C098000AD2200281E
-:1003A0008E27000830A3007F3C04800C0064F821F5
-:1003B000AFE700D08E280008AF9F00280A0016C7BC
-:1003C000AFE800D40A00168E2C6202188E230008B3
-:1003D0003C04800834820080AC4300540240202159
-:1003E0000E001607AC400030240400382405008DB0
-:1003F0000E001618240600128FBF00348FB2003092
-:100400008FB1002C8FB000282402000103E0000807
-:1004100027BD0038AC800058908C0008240DFFF7F1
-:10042000018D5824A08B00080A00166C8FA70010BD
-:100430008CD800540A0016890305182327BDFFE84D
-:10044000AFBF001090A6000D30C7001010E0000CE8
-:10045000008040213C0280088C4400048CA30008EA
-:100460001064000830C9000530C5000510A0001C4C
-:100470008FBF00102402000103E0000827BD001810
-:1004800030C900051120001030CB001210E0FFF938
-:100490008FBF00103C0880088CA700088D06000460
-:1004A00014E6FFF524020001240400382405008D21
-:1004B0000E001618240600128FBF0010240200013F
-:1004C00003E0000827BD0018240A0012156AFFE99E
-:1004D0008FBF0010010020210A00165A27BD001806
-:1004E000000020210A000D1A27BD00183C05080055
-:1004F00024A55D683C04080024847B343C02080089
-:1005000024425D70240300063C010801AC258310E1
-:100510003C010801AC2483143C010801AC2283187F
-:100520003C010801A023831C03E000080000000038
-:1005300003E00008240200013C028000308800FF34
-:10054000344701803C0680008CC301B80460FFFE84
-:10055000000000008CC501282418FF803C0D800A93
-:1005600024AF010001F8702431EC007FACCE0024F0
-:10057000018D2021ACE50000948B00DA3509600084
-:1005800024080002316AFFFFACEA000424020001E3
-:10059000A4E90008A0E8000BACE000243C07100030
-:1005A000ACC701B8AF84002803E00008AF85005C49
-:1005B0008C9800048F8C00282409FFBF0305782342
-:1005C000AC8F0004918E00C42403FFEF31CD007F77
-:1005D000A18D00C48C8B00208F860028A780004C42
-:1005E000356A0002A4C000ACAC8A002090C800C4E8
-:1005F00001093824A0C700C48F840028AC8000DC27
-:10060000908500C400A3102403E00008A08200C469
-:100610003C028000344501803C0480008C8301B89A
-:100620000460FFFE8F89005C2407608324060002BB
-:10063000ACA900008C880124ACA80004A4A7000881
-:10064000A0A6000B3C05100003E00008AC8501B833
-:10065000938800388F8900508F82002830C600FFB1
-:100660000109382330E900FF0122182130A500FFDD
-:100670002468007810C0000201243821008038214D
-:1006800030E400031480000330AA00031140000D81
-:10069000312B000310A000090000102190ED000094
-:1006A000244E000131C200FF0045602BA10D000067
-:1006B00024E700011580FFF92508000103E0000888
-:1006C000000000001560FFF30000000010A0FFFB19
-:1006D000000010218CF8000024590004332200FF90
-:1006E0000045782BAD18000024E7000415E0FFF961
-:1006F0002508000403E0000800000000938500388E
-:10070000938800488F870050000432003103007F37
-:1007100000E5102B30C47F001040000F0064282536
-:100720008F8400283C0980008C8A00DCAD2A00A45C
-:100730003C03800000A35825AC6B00A08C6C00A08B
-:100740000580FFFE000000008C6D00ACAC8D00DC6D
-:1007500003E000088C6200A80A0017DA8F840028E2
-:10076000938800493C02800000805021310300FE44
-:10077000A383004930ABFFFF30CC00FF30E7FFFF21
-:10078000344801803C0980008D2401B80480FFFEBC
-:100790008F8D005C24180016AD0D00008D22012401
-:1007A0008F8D0028AD0200048D590020A507000898
-:1007B000240201B4A119000AA118000B952F0120F1
-:1007C0008D4E00088D4700049783004C8D590024FE
-:1007D00001CF302100C7282100A320232418FFFFC8
-:1007E000A504000CA50B000EA5020010A50C00121C
-:1007F000AD190018AD18002495AF00D83C0B1000BF
-:100800002407FFF731EEFFFFAD0E00288DAC00741A
-:10081000AD0C002CAD2B01B88D46002000C728245C
-:1008200003E00008AD4500208F8800280080582193
-:1008300030E7FFFF910900C63C02800030A5FFFFB2
-:10084000312400FF00041A000067502530C600FF65
-:10085000344701803C0980008D2C01B80580FFFEE3
-:100860008F82005C240F0017ACE200008D39012458
-:10087000ACF900048D780020A4EA0008241901B422
-:10088000A0F8000AA0EF000B952301208D6E000850
-:100890008D6D00049784004C01C35021014D6021EF
-:1008A00001841023A4E2000CA4E5000EA4F90010BA
-:1008B000A4E60012ACE000148D780024240DFFFFA4
-:1008C000ACF800188D0F006CACEF001C8D0E0068AA
-:1008D0003C0F1000ACEE0020ACED0024950A00AEF9
-:1008E000240DFFF73146FFFFACE60028950C0070A1
-:1008F0009504007231837FFF0003CA003082FFFF3E
-:100900000322C021ACF8002CAD2F01B8950E007267
-:100910008D6A002000AE3021014D2824A50600720A
-:1009200003E00008AD6500203C02800034460180F1
-:100930003C0580008CA301B80460FFFE2409001868
-:10094000ACC40000A0C9000B8F8800283C04100034
-:10095000950700AEA4C70010ACC0003003E000084B
-:10096000ACA401B83C028000344501803C04800006
-:100970008C8301B80460FFFE8F8A003424060019BE
-:100980009549001C3128FFFF000839C0ACA70000C2
-:10099000A0A6000B3C05100003E00008AC8501B8E0
-:1009A0008F87003C0080402130C400FF3C0680005F
-:1009B0008CC201B80440FFFE8F89005C938300580D
-:1009C00034996000ACA90000A0A300058CE20010DF
-:1009D000240F00022403FFF7A4A20006A4B9000814
-:1009E0008D180020A0B8000AA0AF000B8CEE00000C
-:1009F000ACAE00108CED0004ACAD00148CEC001C0F
-:100A0000ACAC00248CEB0020ACAB00288CEA002CB2
-:100A10003C071000ACAA002C8D090024ACA90018DA
-:100A2000ACC701B88D05002000A3202403E0000816
-:100A3000AD040020938500582403000127BDFFE882
-:100A400000A330042CA20020AFB00010AFBF0014F0
-:100A500000C01821104000132410FFFE3C070800BE
-:100A60008CE7319000E610243C08800035050180B9
-:100A700014400005240600848F890028240A0004FD
-:100A80002410FFFFA12A00EC0E00187600000000E1
-:100A9000020010218FBF00148FB0001003E0000887
-:100AA00027BD00183C0608008CC631940A0018A81F
-:100AB00000C310248F87003427BDFFE0AFB20018B9
-:100AC000AFB10014AFB00010AFBF001C30D000FFBA
-:100AD00090E6000D00A088210080902130C5007FA5
-:100AE000A0E5000D8F8500288E2300188CA200C081
-:100AF0001062002E240A000E0E00189BA38A0058D4
-:100B00002409FFFF104900222404FFFF52000020A7
-:100B1000000020218E2600003C0C001000CC582440
-:100B2000156000393C0E000800CE682455A0003F37
-:100B3000024020213C18000200D880241200001F2F
-:100B40003C0A00048F8700348CE200148CE3001010
-:100B50008CE500140043F82303E5C82B132000059F
-:100B6000024020218E24002C8CF1001010910031C5
-:100B70000240202124020012A38200580E00189B7C
-:100B80002412FFFF105200022404FFFF0000202166
-:100B90008FBF001C8FB200188FB100148FB00010EF
-:100BA0000080102103E0000827BD002090A800C4A9
-:100BB000350400200A0018D1A0A400C400CA4824AB
-:100BC0001520000B8F8B00348F8D00348DAC0010FE
-:100BD0001580000B024020218E2E002C51C0FFEC0E
-:100BE00000002021024020210A0018EC24020017F6
-:100BF0008D66001050C0FFE6000020210240202139
-:100C00000A0018EC240200110240202124020015E1
-:100C10000E00189BA3820058240FFFFF104FFFDC2B
-:100C20002404FFFF0A0018DB8E2600000A001912B8
-:100C3000240200143C08000400C8382450E0FFD40B
-:100C400000002021024020210A0018EC2402001399
-:100C50008F86002827BDFFE0AFB10014AFBF00189A
-:100C6000AFB0001090C300C430A500FF3062002078
-:100C700010400008008088218CCB00C02409FFDFD1
-:100C8000256A0001ACCA00C090C800C4010938241C
-:100C9000A0C700C414A000403C0C80008F84002832
-:100CA000908700C42418FFBF2406FFEF30E3007FC5
-:100CB000A08300C4979F004C8F8200508F8D002826
-:100CC00003E2C823A799004CA5A000AC91AF00C4D3
-:100CD00001F87024A1AE00C48F8C0028A18000C749
-:100CE0008F8A0028A5400072AD4000DC914500C409
-:100CF00000A65824A14B00C48F9000248F8400507C
-:100D00009786004C0204282110C0000FAF850024F4
-:100D1000A38000483C0780008E2C000894ED012041
-:100D20008E2B0004018D5021014B802102062023CF
-:100D30003086FFFF30C8000F390900013131000152
-:100D400016200009A3880048938600388FBF00183A
-:100D50008FB100148FB0001027BD0020AF85005464
-:100D600003E00008AF86005000C870238FBF001852
-:100D7000938600388FB100148FB0001034EF0C0050
-:100D8000010F282127BD0020ACEE0084AF85005460
-:100D900003E00008AF860050359001800200282152
-:100DA0000E001876240600828F840028908600C4E6
-:100DB00030C5004050A0FFBAA38000588F85003C8A
-:100DC0003C0680008CCD01B805A0FFFE8F89005C39
-:100DD0002408608224070002AE090000A60800086B
-:100DE000A207000B8CA300083C0E1000AE030010FD
-:100DF0008CA2000CAE0200148CBF0014AE1F0018B1
-:100E00008CB90018AE1900248CB80024AE18002844
-:100E10008CAF0028AE0F002CACCE01B80A001936FA
-:100E2000A38000588F8A002827BDFFE0AFB10014CF
-:100E3000AFB000108F880050AFBF00189389002C0E
-:100E4000954200AC30D100FF0109182B00808021B1
-:100E500030AC00FF3047FFFF000058211460000352
-:100E6000310600FF01203021010958239783004CEF
-:100E70000068202B1480001B000000001068004355
-:100E8000240A0001118A004834E708803165FFFF19
-:100E90000E001818020020210E0018588F84005CE4
-:100EA0008F840028948D007025AC0001A48C007004
-:100EB000948B00703C0608008CC6318831677FFF38
-:100EC00010E6004F0000000002002021022028212F
-:100ED0008FBF00188FB100148FB000100A001922C4
-:100EE00027BD0020914400C42406FF800086882589
-:100EF000A15100C49784004C3088FFFF1100001CF2
-:100F00009389002C8F8E00282419EFFF008BF82383
-:100F100095D800AC0168682B33E900FF03197824E9
-:100F2000A5CF00AC51A0002A010058218E05002059
-:100F30002408FFFB2403000100A81024AE020020B7
-:100F40001183002534E78000020020213165FFFF76
-:100F50000E00181801203021978B004C8F8700500D
-:100F6000A780004C00EB8023AF9000509389002CA9
-:100F70008F8C00288FBF00188FB100148FB0001025
-:100F800027BD002003E00008A18900C78E080020CB
-:100F90002409FFFB34E7800001092824AE05002066
-:100FA000158AFFBA34E70880020020210E0017E6F8
-:100FB0003165FFFF02002021022028218FBF001889
-:100FC0008FB100148FB000100A00192227BD002035
-:100FD0000A0019D900004821020020213165FFFFD5
-:100FE0000E0017E601203021978B004C8F870050B0
-:100FF000A780004C00EB80230A0019E9AF90005055
-:1010000094890070240A8000012A4024A48800707A
-:10101000908500709099007030A200FF000219C204
-:101020000003F827001FC1C0332F007F01F870258F
-:10103000A08E00700A0019C1020020218F880028AC
-:1010400024030001910A0078910500C72509007862
-:101050003147003F24E6FFE000C318042CC2002003
-:1010600030670019A385002C1040001AAF89003C9E
-:101070003C0A8000354B00022405000124060001D3
-:1010800014E00016006B1024000028211440000F0B
-:10109000306300201060000F240500018D060074ED
-:1010A0008D1900742403FF8000C3102400027940CE
-:1010B0003338007F01F868253C0E100001AE602532
-:1010C000AD4C083091280001310600010A00199743
-:1010D0000000000003E00008000000008D0F007415
-:1010E0008D0D00742418FF8001F87024000E41401B
-:1010F00031AC007F010C50253C0B1000014B382512
-:101100003C0980000A001997AD27083027BDFFD899
-:10111000AFB000108F90003CAFB40020AFB100140E
-:10112000AFBF0024AFB3001CAFB200188E05001093
-:101130003C0208008C4231B08F86004030A73FFF50
-:1011400000E2182B8CD20014008088218CD3002060
-:10115000106000070000A02190CB000D240AFF8042
-:10116000014B4824312800FF1500000C0005638264
-:10117000022020212411000DA39100588FBF0024CC
-:101180008FB400208FB3001C8FB200188FB10014F1
-:101190008FB000100A00189B27BD0028318500037E
-:1011A00054A0FFF40220202194CF001C8F8E002831
-:1011B0008E070028A5CF00D88CCD0010024D30231B
-:1011C00010E6005C2402001F0E00189BA38200584A
-:1011D000241FFFFF105F004E2404FFFF8F83004495
-:1011E0008F880034026398218D0900100123102399
-:1011F0008F830020AD020010AD1300208C670074B7
-:1012000000F3202B14800062022020218F860040F2
-:101210008E0C00248CC5002411850007022020219B
-:10122000240E001C0E00189BA38E0058240DFFFFF7
-:10123000104D00372404FFFF8F8400348C98002465
-:10124000270F0001AC8F0024127200448F990020F8
-:101250008F320074125300413C0A00808E09000056
-:10126000012A10241440003A000000008E040014EB
-:101270002412FFFF10920006240B001B02202021E5
-:101280000E00189BA38B0058105200212404FFFF6E
-:101290008E0300003C0C0001006C282410A00013F9
-:1012A0003C0600800066A024168000090200282168
-:1012B00002202021240E001A0E00189BA38E005835
-:1012C000240DFFFF104D00122404FFFF020028210F
-:1012D000022020210E0018BB240600012410FFFF6D
-:1012E0002404FFFF1050000A241400018F8F0034E3
-:1012F000022020210280302195F2003424050001D3
-:10130000265800010E001997A5F80034000020218E
-:101310008FBF00248FB400208FB3001C8FB2001841
-:101320008FB100148FB000100080102103E000087E
-:1013300027BD00288F83004400E3C8210259C02B39
-:101340001300FFA88F8800340A001A8024020018B6
-:10135000AC8000200A001AAA8E0400148E1F000020
-:101360003C07008003E798241660FFF92408001A60
-:10137000022020210E00189BA38800582403FFFFA1
-:101380001443FFBA2404FFFF0A001AD38FBF0024BE
-:10139000240B001D0E00189BA38B0058240AFFFF8E
-:1013A000144AFF9A2404FFFF0A001AD38FBF0024B7
-:1013B0008F85002827BDFFD8AFB3001CAFB200183F
-:1013C000AFB10014AFB00010AFBF002090A700C4B1
-:1013D0008F90003C2412FFFF34E200409206000090
-:1013E000A0A200C48E030010008098211072000695
-:1013F00030D1003F2408000D0E00189BA388005830
-:10140000105200252404FFFF8F8A00288E0900183F
-:101410008D4400C01124000702602021240C000E1E
-:101420000E00189BA38C0058240BFFFF104B001AD2
-:101430002404FFFF24040020122400048F8D0028C0
-:1014400091AF00C435EE0020A1AE00C48F850044EA
-:1014500010A00019000000001224004A8F980028F4
-:101460008F92FED0971000709651000A52300048BB
-:101470008F9300303C1F08008FFF318C03E5C82B91
-:101480001720001E02602021000028210E0019975D
-:1014900024060001000020218FBF00208FB3001C14
-:1014A0008FB200188FB100148FB00010008010218F
-:1014B00003E0000827BD00285224002A8E050014EE
-:1014C0008F840028948A007025490001A489007047
-:1014D000948800703C0208008C42318831077FFFFD
-:1014E00010E2000E00000000026020210E00192210
-:1014F000240500010A001B34000020212402002DD5
-:101500000E00189BA38200582403FFFF1443FFE141
-:101510002404FFFF0A001B358FBF00209499007040
-:10152000241F800024050001033FC024A4980070FC
-:1015300090920070908E0070325100FF001181C2B5
-:1015400000107827000F69C031CC007F018D58252D
-:10155000A08B00700E001922026020210A001B34AB
-:10156000000020212406FFFF54A6FFD68F84002808
-:10157000026020210E001922240500010A001B34FC
-:1015800000002021026020210A001B4E2402000AD4
-:101590002404FFFD0A001B34AF9300508F880028FD
-:1015A00027BDFFE8AFB00010AFBF0014910A00C420
-:1015B0008F87003C00808021354900408CE6001078
-:1015C000A10900C43C0208008C4231B030C53FFF85
-:1015D00000A2182B106000078F850040240DFF80AB
-:1015E00090AE000D01AE6024318B00FF1560000845
-:1015F0000006C382020020212403000D8FBF0014C7
-:101600008FB0001027BD00180A00189BA383005854
-:1016100033060003240F000254CFFFF702002021FD
-:1016200094A2001C8F85002824190023A4A200D8AE
-:101630008CE8000000081E02307F003F13F90035DF
-:101640003C0A00838CE800188CA600C01106000834
-:10165000000000002405000E0E00189BA385005812
-:101660002407FFFF104700182404FFFF8F85002880
-:1016700090A900C435240020A0A400C48F8C00349D
-:10168000918E000D31CD007FA18D000D8F83004420
-:101690001060001C020020218F8400408C980010F4
-:1016A0000303782B11E0000D2419001802002021FB
-:1016B000A39900580E00189B2410FFFF1050000241
-:1016C0002404FFFF000020218FBF00148FB0001002
-:1016D0000080102103E0000827BD00188C86001050
-:1016E0008F9F00340200202100C31023AFE20010BE
-:1016F000240500010E001997240600010A001BC0F2
-:10170000000020210E001922240500010A001BC040
-:1017100000002021010A5824156AFFD98F8C00345B
-:10172000A0A600EC0A001BADA386004A27BDFFD887
-:10173000AFB000108F90003CAFB20018AFBF0020D8
-:10174000AFB3001CAFB100148E1100103C030800B1
-:101750008C6331B032253FFF00A3102B10400008EE
-:10176000008090218F8600402409FF8090CA000DE0
-:10177000012A4024310700FF14E0000B00116B82A6
-:10178000024020212412000DA39200588FBF002098
-:101790008FB3001C8FB200188FB100148FB00010EF
-:1017A0000A00189B27BD002831AC0003240B000160
-:1017B000558BFFF40240202190CF000D31EE000840
-:1017C00011C000608F9300441660000924020027B6
-:1017D0008E19000C8CD80020173800052402002038
-:1017E0008E0200088CDF0024105F004024020020DD
-:1017F0000E00189BA38200582406FFFF10460033FA
-:101800002404FFFF8F990034240AFFF73C13800E55
-:101810009329000D2404FF803C0D8000012AF82448
-:10182000A33F000D8F9900203C0808008D0831ACC3
-:101830008F83005C972700788F9F0034010310216D
-:1018400030E57FFF000530400046782131F8007F09
-:101850000313602101E47024ADAE002CA5910000BB
-:101860008FEB0028256A0001AFEA00288FE3002CE7
-:101870008E09002C00694021AFE8002C8E07002C57
-:10188000AFE700308E050014AFE5003497E6003A6C
-:1018900024C20001A7E2003A973300783C10080008
-:1018A0008E1031B02663000130717FFF12300027A7
-:1018B000006030218F8F002002402021240500018C
-:1018C0000E001922A5E60078000020218FBF00201D
-:1018D0008FB3001C8FB200188FB100148FB00010AE
-:1018E0000080102103E0000827BD00288E050014A9
-:1018F0002413FFFF10B3001D8F8300288E080018EB
-:101900008C6700C0150700092402000E8E0A00240F
-:101910008CC9002815490005240200218E070028E3
-:101920008CCB002C10EB00132402001F0E00189B20
-:10193000A38200581453FFB32404FFFF0A001C4283
-:101940008FBF00200A001C0A24020024240E8000FD
-:10195000006E682431ACFFFF000C5BC2317100FFE8
-:10196000001180270A001C3B001033C00A001C59DC
-:10197000240200258E05002C10A0FFEC2402002379
-:101980008F8E00208DCD007401A5602B1580FFE7A0
-:10199000240200268CCF001400A7C02101F8202BC0
-:1019A0001080FF998F990034024020210A001C59B1
-:1019B0002402002227BDFFE0AFB000108F90003C52
-:1019C000AFB10014AFBF00188E0500103C03080033
-:1019D0008C6331B00080882130A43FFF0083102B3E
-:1019E000104000078F8600402409FF8090CA000D38
-:1019F000012A4024310700FF14E000098F8B0044C6
-:101A00002410000D02202021A39000588FBF001841
-:101A10008FB100148FB000100A00189B27BD002062
-:101A2000116000070005CB828F8F00288F8EFED0BB
-:101A300095EC007095CD000A11AC00578F850030F1
-:101A4000333800031700001000000000921F00024E
-:101A500013E00041000000008E06002450C0000F7B
-:101A600092040003022020212402000F0E00189B84
-:101A7000A38200582408FFFF144800072404FFFF36
-:101A80000A001CD58FBF001890C7000D30E3000876
-:101A90001060003702202021920400032409000274
-:101AA000308A00FF15490005308500FF8F8B004408
-:101AB0005160003102202021308500FF38B800102D
-:101AC0002CAF00012F0E000102002821022020214E
-:101AD0000E0018BB01EE30252410FFFF1050000E41
-:101AE0002404FFFF8F830044106000170220202190
-:101AF0003C1F08008FFF318C03E3C82B5720000CDC
-:101B00002411002D02202021000028210E00199709
-:101B100024060001000020218FBF00188FB100149F
-:101B20008FB000100080102103E0000827BD0020C6
-:101B30000E00189BA39100581450FFF62404FFFFD9
-:101B40000A001CD58FBF00180E00192224050001C1
-:101B50000A001CD4000020218CC400248E02002422
-:101B60005444FFC1022020210A001CB59204000346
-:101B70000A001CA924020010240D002C0E00189B42
-:101B8000A38D0058240CFFFF104CFFE32404FFFF3B
-:101B90000A001CBC920400032404FFFD0A001CD4AC
-:101BA000AF85005030A500FF2406000124A90001E4
-:101BB00000C9102B1040000C00004021240A000135
-:101BC00000A61823308B000124C60001006A3804E7
-:101BD000000420421160000200C9182B01074025B3
-:101BE0001460FFF800A6182303E00008010010218C
-:101BF00027BDFFD8AFB000188F90003CAFB1001CDC
-:101C0000AFBF00202403FFFF2411002FAFA300105B
-:101C10009206000024050008261000010066202618
-:101C20000E001CF7308400FF00021E003C021EDC88
-:101C300034466F410A001D1F0000102110A000094A
-:101C4000008018212445000130A2FFFF2C45000828
-:101C50000461FFFA000320400086202614A0FFF94B
-:101C6000008018210E001CF7240500208FA300100F
-:101C70002629FFFF313100FF00034202240700FF45
-:101C80001627FFE20102182600035027AFAA00140E
-:101C9000AFAA00100000302127A8001027A70014C9
-:101CA00000E6782391ED000324CE000100C86021F6
-:101CB00031C600FF2CCB00041560FFF9A18D000098
-:101CC0008FA200108FBF00208FB1001C8FB00018B2
-:101CD00003E0000827BD00289383003827BDFFE0FC
-:101CE00024020034AFB10014AFB00010AFBF001C2D
-:101CF000AFB20018008080211062006500A088212A
-:101D000092240004148000488F880028A380002CAF
-:101D10008E2500048D0700C83C0600FF34C3FFFF7A
-:101D200000A3302400E6102B14400050AF8600447E
-:101D30008F870050978A004CAF87003001474023BF
-:101D400010C00034A788004C8F99002030DF0003BA
-:101D5000001F20239332007C309000030206702184
-:101D60000012C082331200010012788001CF682176
-:101D7000310CFFFF018D582B5160005F8F880028C8
-:101D80008F8900248F8200541049007B3C033F015F
-:101D90008E2600003C11250000C3282414B10078D1
-:101DA0008F84003C8F8A003C8F8800288D4B000078
-:101DB000AD0B00788D470010AD0700888F8700506D
-:101DC0008F860044938C002C01276821020628216D
-:101DD000020C1821A383002C950900ACAF8D0024C0
-:101DE00035301000A51000AC1640005024720004DD
-:101DF000AF850050000020218FBF001C8FB200185B
-:101E00008FB100148FB000100080102103E0000893
-:101E100027BD00208F840024AF8000500087402120
-:101E20000A001D8BAF880024241F000CA39F0058BC
-:101E30000E00189B020020212419FFFF1059FFEE0D
-:101E40002404FFFF8F880028A380002C8E25000427
-:101E50008D0700C83C0600FF34C3FFFF00A33024F9
-:101E600000E6102B1040FFB2AF8600440200202194
-:101E700024090019A38900580E00189B2410FFFFA5
-:101E80001050FFDD2404FFFF0A001D5A8F86004416
-:101E90008F8400288F87003C8CF20030908600C42D
-:101EA00030C5001014A000108F8300502C6800056E
-:101EB0001500002600000000908A00C4246BFFFC7F
-:101EC0003149001015200008316400FF8F8D005447
-:101ED0008F8C002411AC0004388F000131EE00011A
-:101EE00015C0002F000000000E001D0A00000000B9
-:101EF0000A001DE2000000008F890024938C002C52
-:101F00000127682102062821020C1821A383002C36
-:101F1000950900ACAF8D002435301000A51000AC41
-:101F20005240FFB4AF85005024720004A392002CED
-:101F3000950F00AC24B80004AF98005035EE200097
-:101F4000A50E00AC0A001D8C000020218C8200DC54
-:101F50001242FF6B0200202124180005A3980058AC
-:101F60000E00189B2412FFFF1452FF652404FFFF8C
-:101F70000A001D8D8FBF001C0A001DCD8F88002810
-:101F800030E500FF0E0017A2000030218F880028E6
-:101F90008F8700508F8900240A001D7F8F860044A0
-:101FA0000E0017CD000000000A001DE20000000036
-:101FB0009383004A27BDFFE024020002AFB200185D
-:101FC000AFB10014AFBF001CAFB00010008088217B
-:101FD000106200B6000090219783004C8F8500505E
-:101FE0003066FFFF00C5202B1480005B938700380C
-:101FF0003C0880009504012010E500528F8A0024DF
-:102000008F84005430A500FF0E0017A224060001A3
-:102010008F82005C3C0B80003C1F4080244E017886
-:1020200031D00078240FFF80021F60253578090029
-:1020300031D9000701CF6824AD6D08000338802135
-:10204000AD6C081002202021020028210E001D4442
-:10205000AF90003C2403FFFF104300332404FFFF34
-:102060008E0C00103C0708008CE731B0920600008F
-:1020700031843FFF0087282B10A0002330CD003F84
-:102080008F99005C000479803C0408008C8431A89E
-:102090002409FF809390004900994021010F2021DD
-:1020A00000897824000F51403C098000309F007F58
-:1020B0003C0B00808F880028308E00783578000136
-:1020C000015F282530860007352709403C031000B2
-:1020D0003C02800C01D8582500C7C82100A3502518
-:1020E00003E2C021360E0001AD2F0804AF99004075
-:1020F000AD2B0814AF980034AD2F0028AD04007448
-:10210000AD2A0830A38E00499383004A24100003AF
-:102110005070002725A3FFE0240C0001106C001C68
-:1021200024060023024020218FBF001C8FB200181C
-:102130008FB100148FB000100080102103E0000860
-:1021400027BD0020314900035520FFAE8F84005485
-:102150000A001E1F8F9000548F840054306500FFCA
-:102160000E0017A224060001938E003824070034C5
-:1021700011C700188F8500509783004C3078FFFFFF
-:1021800000B87023AF8E00500A001E57A780004C85
-:1021900011A6003200000000022020212411000BB3
-:1021A0000E00189BA39100580A001E570040902172
-:1021B0002C7200201240FFF8000310803C0508013B
-:1021C00024A581600045F8218FED000001A00008E2
-:1021D000000000002CB800051700FFE89783004CB2
-:1021E000978A004C3148FFFF00A848232D2B00059B
-:1021F00011600003314400FF24AFFFFC31E400FF15
-:102200008F9000548F99002412190004389F000108
-:1022100033ED000115A00029000000008F85002883
-:1022200090A700C434E30010A0A300C49783004C1F
-:102230008F8500508F8400283078FFFF00B870230E
-:10224000AC8000DCA780004C0A001E57AF8E005007
-:102250002403FFFF11830005000000000E001B7522
-:10226000022020210A001E57004090210E001AFA79
-:10227000022020210A001E57004090210E001C7BE6
-:10228000022020210A001E57004090210E001BD979
-:10229000022020210A001E57004090210E001A51F2
-:1022A000022020210A001E5700409021938500380B
-:1022B0002404FFFD0A001E58AF8500500E0017CD04
-:1022C000000000009783004C8F85005000402021C3
-:1022D0003066FFFF00A660232D8200051040FFA896
-:1022E0003078FFFF8F91002800B87023AE2400DC07
-:1022F000A780004C0A001E57AF8E005027BDFFD0AC
-:10230000AFB20018AFB00010AFBF0028AFB50024C7
-:10231000AFB40020AFB3001CAFB100143C0C800080
-:102320008D880128240FFF803C07800A25100100BA
-:10233000250B0080020F68243205007F016F702496
-:10234000AD8E009000A72821AD8D002490A700EC51
-:102350003169007F3C0A8004012A1821A387004AC2
-:102360009066007C00809021AF83002030C2000284
-:10237000AF88005CAF85002800A01821144000023F
-:102380002404003424040030A38400388C6600CC7C
-:1023900030F100FF24040004AF8600501224000432
-:1023A000A38000588E5300041660001D3C08800076
-:1023B0009387004930F200011240000F8FBF0028C0
-:1023C0008CB800748CA400742419FF80031988242D
-:1023D00000117140308F007F01CF60253C0D20003F
-:1023E000018D582530F500FE3C0A8000AD4B0830C9
-:1023F000A39500498FBF00288FB500248FB400201B
-:102400008FB3001C8FB200188FB100148FB0001072
-:102410002402000127BD003003E00008ACA600CC78
-:102420008E590008951F01208E460010033FC021E1
-:102430003307FFFF30F5000F32B40001AF860024F0
-:102440001680003BA395004835060C0002A610211B
-:1024500000F51823AD030084AF8200548E490004B8
-:102460003128FFFF1100002BA789004C2410FF80AA
-:102470003C1580003C1420000A001F442413FFFE7A
-:1024800090AE00C4020E682431AC00FF1580002A13
-:1024900002402021938400499786004C308F000130
-:1024A00011E0000B026428248F8900288D2300741A
-:1024B0008D280074A3850049007010240002C940D3
-:1024C000311F007F033FC02503148825AEB10830BB
-:1024D00010C000108F85002890A700C40207582460
-:1024E000316A00FF1540FFE6024020210E001DFA70
-:1024F0009791004C1040FFE8938400492405FFFDAC
-:10250000544500058E430020022028210E00177A32
-:10251000024020218E430020307000041600000A83
-:102520002414FFFB8F8500280A001EFA8F860050B6
-:102530000A001F25AF8600540E001A1D000000007F
-:102540000A001F3493840049007498240E001792E7
-:10255000AE5300208F8500280A001EFA8F86005097
-:1025600027BDFFD8AFB3001CAFB10014AFBF002030
-:10257000AFB20018AFB000103C0280008C52014096
-:102580008C4B01483C048000000B8C02322300FF7E
-:10259000317300FF8C8501B804A0FFFE34900180E8
-:1025A000AE1200008C8701442464FFF02406000270
-:1025B0002C830013AE070004A6110008A206000B2E
-:1025C000AE1300241060004F8FBF0020000448802D
-:1025D0003C0A0801254A81E0012A40218D040000BF
-:1025E00000800008000000003C1008008E1031A898
-:1025F00031733FFF001389800212C8212405FF8038
-:1026000003312021264C0100264700803C1F80001A
-:1026100000E51824318F007F30E9007F308A007F89
-:102620003C18800A3C0E80043C0D800C0085102470
-:1026300001853024014D8021AFE6002401F84021BE
-:10264000AFE30090012E9821AFE20028AF90003454
-:10265000AF880028AF9300200E001867016080212A
-:102660003C0380008C6B01B80560FFFE8F8700344F
-:10267000346501808F86002890E3000DACB2000025
-:10268000A4B00006000316000002FE03001F9027FE
-:10269000001227C21080007A24C2007824196082B8
-:1026A000A4B90008A0A00005241F0002A0BF000BD1
-:1026B00000041C008F8B00203C0227000062902544
-:1026C000ACB20010ACA00014ACA00024ACA0002858
-:1026D000ACA0002C8D7300382410FF80ACB3001820
-:1026E00090E4000D02048824322500FF10A00005AC
-:1026F0008FBF002090EC000D3188007FA0E8000D16
-:102700008FBF00208FB3001C8FB200188FB1001450
-:102710008FB000103C0D10003C0A800027BD00283F
-:1027200003E00008AD4D01B8265F01002405FF80DD
-:1027300033F8007F3C06800003E578243C19800ACA
-:1027400003192021ACCF0024908E00C400AE682471
-:1027500031AC00FF1180FFEAAF840028248E00789E
-:1027600095CD00123C0C08008D8C31A831AB3FFF99
-:1027700001924821000B5180012A402101052024AB
-:10278000ACC400283107007F3C06800C00E6202105
-:102790009083000D00A31024304500FF10A0FFD847
-:1027A000AF8400349098000D330F001015E0FFD572
-:1027B0008FBF00200E001867000000003C0380005F
-:1027C0008C7901B80720FFFE00000000AE12000067
-:1027D0008C720144AE120004A611000824110002FC
-:1027E000A211000BAE1300240A001FCF8FBF0020E0
-:1027F0003C1260008E452C083C03F0033462FFFF5E
-:1028000000A2F824AE5F2C088E582C083C1901B0A9
-:1028100003199825AE532C080A001FCF8FBF002044
-:10282000264D010031AF007F3C10800A240EFF804E
-:1028300001F0282101AE60243C0B8000AD6C002427
-:102840001660FFAFAF85002824110003A0B100EC93
-:102850000A001FCF8FBF002026480100310A007FE9
-:102860003C0B800A2409FF80014B30210109202400
-:102870003C078000ACE400240A001FCEAF8600288D
-:10288000944A001232083FFF314C3FFF1588FF8405
-:102890002419608290CF00C4240EFF8001CF482409
-:1028A000312D00FF11A0FF7E00000000240700046E
-:1028B000A0C700EC8F870034241860842406000D24
-:1028C000A4B80008A0A600050A001FB9241F000232
-:1028D0000800330C0800330C080033E8080033BC50
-:1028E000080033A0080032F0080032F0080032F08F
-:1028F0000800331480080100800800808008000070
-:102900005F865437E4AC62CC50103A453662198584
-:10291000BF14C0E81BC27A1E84F4B556094EA6FE49
-:102920007DDA01E7C04D748108007A8808007AB426
-:1029300008007A94080079D008007A9408007AD4C4
-:1029400008007A94080079D0080079D0080079D07E
-:10295000080079D0080079D0080079D0080079D033
-:10296000080079D0080079D0080079D008007AC42E
-:1029700008007AA4080079D0080079D0080079D03E
-:10298000080079D0080079D0080079D0080079D003
-:10299000080079D0080079D0080079D0080079D0F3
-:1029A000080079D008007AA40800809008007F38D9
-:1029B0000800805808007F380800802808007E2022
-:1029C00008007F3808007F3808007F3808007F380B
-:1029D00008007F3808007F3808007F3808007F38FB
-:1029E00008007F3808007F3808007F3808007F38EB
-:0429F00008007F60FC
-:0C29F4000A0001220000000000000000AA
-:102A00000000000D747061352E302E306A313500B3
-:102A100005000001000000000000000000000000B0
-:102A200000000000000000000000000000000000A6
-:102A30000000000000000000000000000000000096
-:102A40000000000000000000000000000000000086
-:102A50000000000000000000000000000000000076
-:102A60000000000000000000000000000000000066
-:102A70000000000000000000000000000000000056
-:102A800010000003000000000000000D0000000D19
-:102A90003C02080024421C203C03080024631FA0C1
-:102AA000AC4000000043202B1480FFFD24420004B2
-:102AB0003C1D080037BD2FFC03A0F0213C1008008E
-:102AC000261004883C1C0800279C1C200E0002E2F3
-:102AD000000000000000000D2402FF8027BDFFE081
-:102AE00000821024AFB00010AF420020AFBF00182A
-:102AF000AFB10014936500043084007F03441821B3
-:102B00003C0200080062182130A5002003608021EB
-:102B10003C080111277B000814A000022466005C19
-:102B200024660058920200049743010492040004B2
-:102B30003047000F3063FFFF3084004000672823D8
-:102B40001080000900004821920200053042000474
-:102B5000104000050000000010A00003000000006D
-:102B600024A5FFFC24090004920200053042000461
-:102B7000104000120000000010A000100000000033
-:102B80009602000200A72021010440252442FFFEF6
-:102B9000A7421016920300042402FF800043102471
-:102BA000304200FF104000033C0204000A000172A2
-:102BB000010240258CC20000AF4210188F420178FC
-:102BC0000440FFFE2402000AA742014096020002D0
-:102BD000240400093042000700021023304200079D
-:102BE000A7420142960200022442FFFEA74201448E
-:102BF000A740014697420104A74201488F420108BD
-:102C000030420020504000012404000192020004E0
-:102C1000304200101440000234830010008018215C
-:102C2000A743014A0000000000000000000000006F
-:102C300000000000AF48100000000000000000008D
-:102C400000000000000000008F4210000441FFFE61
-:102C50003102FFFF10400007000000009202000454
-:102C60003042004014400003000000008F42101862
-:102C7000ACC20000960200063042FFFF2442000270
-:102C800000021043000210400362882196220000D7
-:102C90001120000D3044FFFF00A710218F83003862
-:102CA0008F45101C0002108200021080004310218A
-:102CB000AC45000030A6FFFF0E0002D100052C023B
-:102CC00000402021A6220000920300042402FF807D
-:102CD00000431024304200FF1040001F000000009D
-:102CE00092020005304200021040001B000000006C
-:102CF0009742100C2442FFFEA7421016000000006D
-:102D00003C02040034420030AF42100000000000DA
-:102D10000000000000000000000000008F421000D2
-:102D20000441FFFE000000009742100C8F45101C6C
-:102D30003042FFFF24420030000210820002108067
-:102D4000005B1021AC45000030A6FFFF0E0002D151
-:102D500000052C02A622000096040002248400082C
-:102D60000E0001E73084FFFF974401040E0001F5D7
-:102D70003084FFFF8FBF00188FB100148FB0001098
-:102D80003C02100027BD002003E00008AF4201789C
-:102D90003084FFFF308200078F850024104000023E
-:102DA000248300073064FFF800A4102130421FFF85
-:102DB00003421821247B4000AF850028AF82002405
-:102DC00003E00008AF4200843084FFFF3082000F30
-:102DD0008F85002C8F860034104000022483000F62
-:102DE0003064FFF000A410210046182BAF8500309E
-:102DF0000046202314600002AF82002CAF84002C18
-:102E00008F82002C340480000342182100641821B2
-:102E1000AF83003803E00008AF4200808F820014C7
-:102E2000104000088F8200048F82FFCC1440000500
-:102E30008F8200043C02FFBF3442FFFF0082202447
-:102E40008F82000430430006240200021062000F4B
-:102E50003C0201012C6200035040000524020004E2
-:102E60001060000F3C0200010A00022E000000006A
-:102E700010620005240200061462000C3C020111DD
-:102E80000A000227008210253C0200110082102552
-:102E9000AF421000240200010A00022EAF82000C93
-:102EA00000821025AF421000AF80000C000000002F
-:102EB000000000000000000003E000080000000027
-:102EC0008F82000C10400004000000008F421000B0
-:102ED0000441FFFE0000000003E0000800000000C5
-:102EE0008F8200102443F800000229C224A2FFF0C0
-:102EF0002C63030110600003000210420A00025517
-:102F0000AC8200008F83001800A3102B1440000B2C
-:102F10000000382100A31023244600018F82001CEA
-:102F2000006210212442FFFF0045102B5440000492
-:102F30002402FFFF0A000255AC8600002402FFFFB6
-:102F40000A00025AAC8200008C8200003C03080098
-:102F500024631C5C000211400043382103E0000898
-:102F600000E010213C0908008D291D80000451401B
-:102F70003C19080027391C5C00C0782100806021C2
-:102F8000240EFFFF00003821015940211120003696
-:102F9000000030213C18080027181D983C0D08003F
-:102FA00025AD1D9C000F582B0006118000461021F6
-:102FB000000218C0007810218C4200001582002009
-:102FC000006D20218CA20000544000098D020018E1
-:102FD0003C0208008C421D8424420001AC820000A7
-:102FE0003C010800AC221D840A0002CF0000202111
-:102FF0008F47002000003021000211C01160004AFC
-:10300000AF4200208D08001C3C0900088CA3000082
-:103010000066182100031880007A10210049102151
-:103020008C44000024C600010068182100CF102B3A
-:103030001440FFF6AC6400000A0002CD000000005E
-:103040008C840000008E102B5040000424C6000128
-:103050000080702100C0382124C6000100C9102B57
-:103060001440FFD20006118024020001ACA200002F
-:103070003C0208008C421D7C3C0308008C631D80D0
-:103080000043102B1440002A2404FFFE0159102194
-:103090008C420018104000262404FFFF0007218006
-:1030A0003C0508008CA51D84008720218D06001892
-:1030B000000420C03C02080024421D980082102118
-:1030C0003C03080024631D9CAC4C000024A50001B7
-:1030D000008318213C02080024421DA0AC650000BA
-:1030E000000631C03C010800AC251D84008220216F
-:1030F0008F470020AD04001CAF46002011E0000AFD
-:10310000000030213C020008034228218CA200006C
-:1031100024C6000100CF182BAC82000024A50004B7
-:103120001460FFFA24840004AF470020000020212F
-:1031300003E00008008010213084FFFF30C6FFFF4D
-:1031400000052C0000A628253882FFFF004510212D
-:103150000045282B0045102100021C023042FFFFD1
-:103160000043102100021C023042FFFF00431021E7
-:103170003842FFFF03E000083042FFFF27BDFFC8D1
-:10318000AFBF0030AFB3002CAFB20028AFB1002406
-:10319000AFB000203C0460088C8250002403FF7F05
-:1031A0003C066000004310243442380CAC825000CE
-:1031B0008CC24C1C3C1A8000000216023042000FE8
-:1031C00010400007AF82001C8CC34C1C3C02001F47
-:1031D0003442FC0000621824000319C2AF830018B7
-:1031E0008F420008275B400034420001AF420008D4
-:1031F000AF8000243C02601CAF400080AF400084E0
-:103200008C4500088CC3080834028000034220214A
-:103210002402FFF0006218243C0200803C010800F8
-:10322000AC2204203C025709AF8400381462000429
-:10323000AF850034240200010A000314AF82001499
-:10324000AF8000142403003D240200043C01080068
-:10325000AC221D943C010800AC231D903C010800E9
-:10326000AC231D8C3C010800AC231D883C130800D6
-:1032700026731C5C240400043C02080024421C74D5
-:10328000240300082463FFFFAC400004AC400000AE
-:103290000461FFFC24420020000410C000441021FF
-:1032A0002442003D3C010800AC221D902402000194
-:1032B0003C010800AC221D7C2402FFFF3C010800F9
-:1032C000AC221D983C010800AC201D848F420000F8
-:1032D00038420001304200011440FFFC8F8200148C
-:1032E0001040001600000000974201041040000545
-:1032F0008F830000146000072462FFFF0A00034B65
-:103300002C62000A2C620010504000048F830000E1
-:1033100024620001AF8200008F8300002C62000A4B
-:10332000144000032C6200070A000352AF80FFCC58
-:103330001040000224020001AF82FFCC8F4301083D
-:103340008F44010030622000AF8300041040000869
-:10335000AF8400103C0208008C42042C244200017F
-:103360003C010800AC22042C0A0006D73C024000B5
-:103370003065020014A0000324020F001482030928
-:1033800024020D0097420104104003713C024000EA
-:1033900030624000144000AD8F8200388C44000839
-:1033A0008F4201780440FFFE24020800AF420178FA
-:1033B00024020008A7420140A740014297420104AD
-:1033C0008F8400043051FFFF30820001104000075D
-:1033D000022080212623FFFE240200023070FFFF1E
-:1033E000A74201460A00037FA7430148A7400146C0
-:1033F0003C0208008C42043C1440000D8F830010F6
-:10340000308200201440000224030009240300013C
-:10341000006020218F830010240209005062000107
-:1034200034840004A744014A0A00039A0000000003
-:1034300024020F00146200053082002014400006B0
-:103440002403000D0A000399240300051440000220
-:103450002403000924030001A743014A3C02080099
-:103460008C4204203C0400480E00020A004420253F
-:103470000E000233000000008F82000C1040003E5E
-:10348000000000008F4210003C0300200043102485
-:10349000104000398F820004304200021040003694
-:1034A0000000000097421014144000330000000098
-:1034B000974210088F8800383042FFFF24420006F0
-:1034C000000218820003388000E8302130430001F8
-:1034D0008CC4000010600004304200030000000DA6
-:1034E0000A0003DB00E81021544000103084FFFF85
-:1034F0003C05FFFF00852024008518260003182BBB
-:103500000004102B004310241040000500000000B0
-:10351000000000000000000D000000002400021C5C
-:103520008CC200000A0003DA004520253883FFFF23
-:103530000003182B0004102B00431024104000053A
-:1035400000000000000000000000000D000000006E
-:10355000240002258CC200003444FFFF00E8102143
-:10356000AC4400003C0208008C42043024420001BC
-:103570003C010800AC2204308F6200008F840038C8
-:10358000AF8200088C8300003402FFFF1462000F3A
-:10359000000010213C0508008CA504543C040800E0
-:1035A0008C84045000B0282100B0302B00822021F0
-:1035B000008620213C010800AC2504543C01080091
-:1035C000AC2404500A0006CD240400088C820000BC
-:1035D000304201001040000F000010213C0508009F
-:1035E0008CA5044C3C0408008C84044800B02821BD
-:1035F00000B0302B00822021008620213C010800F1
-:10360000AC25044C3C010800AC2404480A0006CD5B
-:10361000240400083C0508008CA504443C04080070
-:103620008C84044000B0282100B0302B008220217F
-:10363000008620213C010800AC2504443C01080020
-:10364000AC2404400A0006CD240400088F62000860
-:103650008F62000000021602304300F024020030A6
-:1036600010620005240200401062016B8F8200206E
-:103670000A0006D52442000114A000050000000045
-:10368000000000000000000D0000000024000250B7
-:103690008F4201780440FFFE000000000E00023B54
-:1036A00027A4001014400005004080210000000005
-:1036B0000000000D00000000240002578E020000F0
-:1036C0001040000500000000000000000000000D98
-:1036D000000000002400025A8F62000C0443000323
-:1036E000240200010A00055DAE000000AE020000E9
-:1036F0008F8200388C450008A20000078F65000CFF
-:103700008F64000430A3FFFF0004240200852023FF
-:10371000308200FF0043102124420005000288830C
-:103720002E220081A605000A14400005A204000410
-:10373000000000000000000D0000000024000272E4
-:103740003C0708008CE71D808FA800102409FFFFAC
-:103750000000502110E00013000030213C0C080054
-:10376000258C1D9C01802821000018218CA2FFFCC3
-:103770005102002F006C18218CA400002463020861
-:103780000089102B1040000324A502080080482166
-:1037900000C0502124C6000100C7102B5440FFF484
-:1037A0008CA2FFFC3C0508008CA51D803C02080093
-:1037B0008C421D7C3C09080025291C603C03080044
-:1037C00024631D9800A2102B3C0C0800258C1D9C26
-:1037D0003C0408008C841D843C0B0800256B1DA054
-:1037E0001040001A000831400005118000451021EA
-:1037F000000210C000C9382124840001004B302190
-:103800000043182124A50001004C1021AC680000E1
-:10381000ACE600183C010800AC241D84AC44000058
-:103820003C010800AC251D800A0004A88E04001C81
-:103830003C0208008C421D84244200013C01080027
-:10384000AC221D840A0004A7AC620000000A1180AB
-:10385000004A1021000210C0004328218CA3000060
-:10386000004C3821248400010003194000C9302194
-:1038700000691821004B1021ACA80000AC600018B2
-:103880003C010800AC241D84ACC20018ACE400006C
-:103890008E04001C8F8500380E0006E702203021C0
-:1038A0008F6200048F430108A60200083C0210004A
-:1038B0000062182410600008000000009742010414
-:1038C000920300072442FFEC346300023045FFFFFF
-:1038D0000A0004BCA2030007974201042442FFF03F
-:1038E0003045FFFF960600082CC200135440000527
-:1038F000920300079202000734420001A20200076F
-:103900009203000724020001106200052402000354
-:103910001062000B30C7FFFF0A0004DB24E2000244
-:103920008F8200383C04FFFF8C43000C0064182495
-:1039300000651825AC43000C0A0004DA30C7FFFF0D
-:103940008F8200383C04FFFF8C4300100064182471
-:1039500000651825AC43001030C7FFFF24E20002C9
-:1039600000021083A20200058F830038304200FF5E
-:1039700000021080004330218CC500008CC2000082
-:103980002403000400021702144300130000000087
-:10399000974201043C03FFFF00A318243042FFFFBD
-:1039A000004710232442FFFE00622825ACC500001A
-:1039B000920400058E03001C308200FF000210807C
-:1039C00000431021904200003042000F00441021BB
-:1039D0000A000510A20200068CC4000497420104EC
-:1039E0009603000A3085FFFF3042FFFF0047102397
-:1039F0002442FFD60002140000A22825ACC5000412
-:103A00009202000792040005246300280003188333
-:103A10000064182134420004A2030006A202000739
-:103A20008F8200042403FFFB344200020043102471
-:103A3000AF820004920300068E07001C8F860038B8
-:103A400000031880006710218C44000C3C02FFF634
-:103A50003442FFFF0082282400661821AE04000CC7
-:103A6000AC65000C920300068E04000C3C02FF7F44
-:103A70003442FFFF0003188000A228240082202483
-:103A800000671821AE04000CAC65000C9202000621
-:103A9000000210800047102194450012AC45001030
-:103AA000920200060002108000461021AC45001072
-:103AB0008FA200109203000500021140000318803D
-:103AC00000671821005320218C6200048C830018A9
-:103AD0001460000EAE0200143C0308008C631D8CC1
-:103AE000AC8300183C0208008C421D900062102B31
-:103AF00010400019000000003C0208008C421D9498
-:103B0000006210213C010800AC221D8C8E020018BE
-:103B10008F48002000003021000211C01220000B4D
-:103B2000AF4200203C0200080342282100E020218F
-:103B30008C82000024C6000100D1182BACA200002A
-:103B4000248400041460FFFA24A50004AF48002078
-:103B50000A00055E24020010000000000000000DB5
-:103B600000000000240002D424020010A7420140FB
-:103B700024020002A7400142A7400144A742014697
-:103B8000974201043C0400082442FFFEA74201487A
-:103B9000240200010E00020AA742014A9603000A0D
-:103BA0009202000400431021244200023042000728
-:103BB00000021023304200070E000233AE02001054
-:103BC0008F6200003C0308008C630444240400104E
-:103BD000AF820008974201043042FFFF2442FFFEFB
-:103BE00000403821000237C33C0208008C420440E8
-:103BF000006718210067282B00461021004510217E
-:103C00003C010800AC2304443C010800AC22044001
-:103C10000A0006620000000014A000050000000079
-:103C2000000000000000000D00000000240003045C
-:103C30008F4201780440FFFE000000000E00023BAE
-:103C400027A400141440000500408021000000005B
-:103C50000000000D000000002400030B9206000489
-:103C60008FA4001427A50018000630820E00025C05
-:103C7000AFA00018504000068E02000000000000B7
-:103C80000000000D00000000240003118E0200005F
-:103C90005440000692020007000000000000000DE2
-:103CA00000000000240003169202000730420004C6
-:103CB000104000058F8200042403FFFB3442000201
-:103CC00000431024AF8200048F6200040443000903
-:103CD00092020007920200068E03001C8E04000C64
-:103CE0000002108000431021AC44000CAE00000024
-:103CF00092020007304200045440000B920300047B
-:103D0000920300058E0400148E05001C0003188029
-:103D10003C0200010082202100651821AE0400143D
-:103D2000AC640004920300049602000A00621021B1
-:103D300024420005000290838FA200181040000D5D
-:103D4000277100088FA40014000310820242302360
-:103D500027A500180E00025CAFA200185040000614
-:103D60008E05001C000000000000000D0000000097
-:103D70002400033F8E05001C022020210E0006E7D0
-:103D800002403021920400068F6500043C027FFF50
-:103D900000042080009120218C8300043442FFFF26
-:103DA00000A2282400651821AC83000492020007B9
-:103DB00092030004920500053042000410400014F4
-:103DC0009607000830A500FF0005288000B12821D3
-:103DD0008CA40004974201049606000A306300FF99
-:103DE0003042FFFF004310210046102130E3FFFF67
-:103DF000004310232442FFD83084FFFF0002140048
-:103E000000822025ACA400040A00061692030007D5
-:103E100030A500FF0005288000B128218CA40000F7
-:103E200097420104306300FF3042FFFF004310213E
-:103E3000004710233C03FFFF008320243042FFFF94
-:103E400000822025ACA40000920300072402000198
-:103E5000106200060000000024020003106200113E
-:103E6000000000000A0006398E030010974201048A
-:103E7000920300049605000A8E24000C00431021D2
-:103E8000004510212442FFF23C03FFFF0083202461
-:103E90003042FFFF00822025AE24000C0A000639C4
-:103EA0008E03001097420104920300049605000A55
-:103EB0008E24001000431021004510212442FFEE03
-:103EC0003C03FFFF008320243042FFFF00822025B7
-:103ED000AE2400108E0300102402000AA742014005
-:103EE000A74301429603000A920200043C040040EA
-:103EF00000431021A7420144A74001469742010414
-:103F0000A7420148240200010E00020AA742014A0A
-:103F10000E000233000000008F62000092030004D4
-:103F200000002021AF820008974201049606000A93
-:103F30003042FFFF00621821006028213C03080086
-:103F40008C6304443C0208008C4204400065182144
-:103F5000004410210065382B004710213C01080067
-:103F6000AC2304443C010800AC2204409204000449
-:103F7000008620212484000A3084FFFF0E0001E720
-:103F800000000000974401043084FFFF0E0001F59B
-:103F9000000000003C021000AF4201780A0006D485
-:103FA0008F820020148200273062000697420104AD
-:103FB000104000673C0240003062400010400005A5
-:103FC00000000000000000000000000D00000000E4
-:103FD0002400041A8F4201780440FFFE24020800E6
-:103FE000AF42017824020008A7420140A7400142E5
-:103FF0008F82000497430104304200011040000703
-:104000003070FFFF2603FFFE24020002A742014694
-:10401000A74301480A00068C2402000DA740014670
-:104020002402000DA742014A8F6200002404000808
-:10403000AF8200080E0001E7000000000A000666DB
-:1040400002002021104000423C0240009362000028
-:10405000304300F0240200101062000524020070BA
-:10406000106200358F8200200A0006D5244200012C
-:104070008F620000974301043050FFFF3071FFFF53
-:104080008F4201780440FFFE320200070002102335
-:10409000304200072403000A2604FFFEA743014024
-:1040A000A7420142A7440144A7400146A751014845
-:1040B0008F4201083042002014400002240300090E
-:1040C00024030001A743014A0E00020A3C040040F9
-:1040D0000E000233000000003C0708008CE7044497
-:1040E000021110212442FFFE3C0608008CC6044049
-:1040F0000040182100E33821000010218F650000E6
-:1041000000E3402B00C230212604000800C8302103
-:104110003084FFFFAF8500083C010800AC27044451
-:104120003C010800AC2604400E0001E7000000003E
-:104130000A000666022020210E000139000000005E
-:104140008F82002024420001AF8200203C02400008
-:10415000AF4201380A000336000000003084FFFF40
-:1041600030A5FFFF000018211080000700000000AC
-:104170003082000110400002000420420065182136
-:104180000A0006DD0005284003E000080060102159
-:1041900010C0000624C6FFFF8CA2000024A5000466
-:1041A000AC8200000A0006E72484000403E0000853
-:1041B0000000000010A0000824A3FFFFAC86000050
-:1041C00000000000000000002402FFFF2463FFFF46
-:1041D0001462FFFA2484000403E0000800000000D9
-:0441E00000000001DA
-:0C41E4000A00002A00000000000000009B
-:1041F0000000000D747870352E302E306A31350095
-:10420000050000000000000A000001360000EA601E
-:10421000000000000000000000000000000000009E
-:10422000000000000000000000000000000000008E
-:10423000000000000000000000000000000000007E
-:104240000000000000000016000000000000000058
-:10425000000000000000000000000000000000005E
-:10426000000000000000000000000000000000004E
-:1042700000000000000000000000000000001388A3
-:1042800000000000000005DC00000000000000004D
-:1042900010000003000000000000000D0000000DF1
-:1042A0003C020800244239203C03080024633BD42C
-:1042B000AC4000000043202B1480FFFD244200048A
-:1042C0003C1D080037BD7FFC03A0F0213C10080016
-:1042D000261000A83C1C0800279C39200E0004076B
-:1042E000000000000000000D8F86003C3C039000A1
-:1042F0003C0280000086282500A32025AC44002035
-:104300003C0380008C67002004E0FFFE00000000FA
-:1043100003E00008000000000A000041240400013E
-:104320008F85003C3C0480003483000100A31025ED
-:1043300003E00008AC82002003E000080000102128
-:104340003084FFFF30A5FFFF108000070000182118
-:104350003082000110400002000420420065182154
-:104360001480FFFB0005284003E0000800601021D6
-:1043700010C00007000000008CA2000024C6FFFF50
-:1043800024A50004AC82000014C0FFFB24840004B8
-:1043900003E000080000000010A0000824A3FFFFB5
-:1043A000AC86000000000000000000002402FFFFB7
-:1043B0002463FFFF1462FFFA2484000403E0000872
-:1043C0000000000090AA00318FAB00108CAC0040C0
-:1043D0003C0300FF8D680004AD6C00208CAD0044F0
-:1043E00000E060213462FFFFAD6D00248CA700481F
-:1043F0003C09FF000109C024AD6700288CAE004CC9
-:104400000182C82403197825AD6F0004AD6E002C1D
-:104410008CAD0038314A00FFAD6D001C94A900320C
-:104420003128FFFFAD68001090A70030A5600002A2
-:10443000A1600004A167000090A30032306200FF79
-:104440000002198210600005240500011065000EAD
-:104450000000000003E00008A16A00018CD80028D9
-:10446000354A0080AD7800188CCF0014AD6F001471
-:104470008CCE0030AD6E00088CC4002CA16A000107
-:1044800003E00008AD64000C8CCD001CAD6D00187D
-:104490008CC90014AD6900148CC80024AD680008F4
-:1044A0008CC70020AD67000C8CC200148C83007098
-:1044B0000043C82B13200007000000008CC200142A
-:1044C000144CFFE400000000354A008003E00008BF
-:1044D000A16A00018C8200700A0000B70000000091
-:1044E0009089003027BDFFF88FA8001CA3A9000009
-:1044F0008FA300003C0DFF8035A2FFFF8CAC002C89
-:1045000000625824AFAB0000A100000400C0582195
-:10451000A7A000028D06000400A048210167C82161
-:104520008FA50000008050213C18FF7F032C20261F
-:104530003C0E00FF2C8C0001370FFFFF35CDFFFF35
-:104540003C02FF0000AFC82400EDC02400C2782464
-:10455000000C1DC00323682501F87025AD0D000077
-:10456000AD0E00048D240024AFAD0000AD040008A2
-:104570008D2C00202404FFFFAD0C000C9547003269
-:1045800030E6FFFFAD0600109145004830A200FF65
-:10459000000219C2506000018D240034AD040014E3
-:1045A0008D4700388FAA001827BD0008AD0B0028E2
-:1045B000AD0A0024AD07001CAD00002CAD000018B2
-:1045C00003E00008AD00002027BDFFE0AFB20018F7
-:1045D000AFB10014AFB00010AFBF001C9098003016
-:1045E00000C088213C0D00FF330F007FA0CF0000EA
-:1045F000908E003135ACFFFF3C0AFF00A0CE0001D9
-:1046000094A6001EA22000048CAB00148E29000486
-:1046100000A08021016C2824012A402400809021E0
-:1046200001052025A6260002AE2400042605002050
-:10463000262400080E000063240600029247003082
-:10464000260500282624001400071E000003160378
-:1046500024060004044000032403FFFF965900329F
-:104660003323FFFF0E000063AE2300102624002436
-:104670008FBF001C8FB200188FB100148FB00010D4
-:1046800024050003000030210A00006D27BD002032
-:1046900027BDFFD8AFB1001CAFB00018AFBF0020DE
-:1046A00090A900302402000100E050213123003F96
-:1046B00000A040218FB000400080882100C0482128
-:1046C000106200148FA70038240B000500A02021E1
-:1046D00000C02821106B0013020030210E0000F9E9
-:1046E000000000009225007C30A40002108000032E
-:1046F00026030030AE000030260300348FBF0020B8
-:104700008FB1001C8FB000180060102103E000087A
-:1047100027BD00280E000078AFB000100A0001404D
-:10472000000000008FA3003C01002021012028216F
-:1047300001403021AFA300100E0000BFAFB0001445
-:104740000A000140000000003C0580008CA30E1010
-:104750008F840044AC8300208CA20E1803E0000874
-:10476000AC8200243C0580008CA30E148F8400448E
-:10477000AC8300208CA20E1C03E00008AC82002455
-:104780009382000C1040001B2483000F2404FFF0D0
-:104790000064382410E00019978B00109784000EF5
-:1047A0009389000D3C0A601C0A00017B01644023D0
-:1047B00001037021006428231126000231C2FFFF8B
-:1047C00030A2FFFF0047302B50C0000E00E448210C
-:1047D0008D4D000C31A3FFFF00036400000C2C037F
-:1047E00004A1FFF30000302130637FFF0A00017352
-:1047F0002406000103E00008000000009784000E7A
-:1048000000E448213123FFFF3168FFFF0068382BA7
-:1048100054E0FFF8A783000E938A000D11400005B5
-:10482000240F0001006BC023A380000D03E00008EB
-:10483000A798000E006BC023A38F000D03E00008B3
-:10484000A798000E03E000080000000027BDFFE865
-:10485000AFB000103084FFFF3C10800093A8002B05
-:10486000AFBF0014A6040144960A0E1630C600FF1E
-:104870008FA90030A60A0146AE050148A2060152E2
-:10488000A608015AAE0701608FA3002CA6090158A3
-:10489000012020210E000167AE0301543C021000EC
-:1048A000AE0201788FBF00148FB0001003E0000843
-:1048B00027BD00188F8500002484000727BDFFF85E
-:1048C0003084FFF83C06800094CB008A316AFFFFF9
-:1048D000AFAA00008FA90000012540232507FFFF94
-:1048E00030E31FFF0064102B1440FFF700056882BF
-:1048F000000D288034CC400000AC102103E00008FB
-:1049000027BD00088F8200002486000730C5FFF80D
-:1049100000A2182130641FFF03E00008AF840000EC
-:104920008F8500448F8A003C27BDFFB03C04800087
-:10493000AFB70044AFB40038AFB1002CAFBF0048F0
-:10494000AFB60040AFB5003CAFB30034AFB20030FB
-:10495000AFB000288C8701048CA90024AC8A0080A9
-:104960008CA8002000E988230000B821AC880E1034
-:104970008CA600240000A021AC860E188C820E109C
-:10498000AC820E148C830E18AC830E1C122000FB1C
-:104990003C168000936B0008116000F100000000DD
-:1049A000976E001031CDFFFF022D602B158000ECBB
-:1049B0000000000097700010320FFFFFAECF0E0016
-:1049C0003C0580008CB30000327200081240FFFDED
-:1049D0000000000094B50E088CA70E0432A5FFFF5E
-:1049E00030B40001128000E1000000000000000D62
-:1049F00030B9A040241800401338011730B4A0008B
-:104A0000128000DC000000009373000812600008B0
-:104A100000000000976900103122FFFF00E2202B08
-:104A20001080000330A6004010C000D2000000003B
-:104A3000A7850040AF870038936A0008022038211C
-:104A4000AFB10020154000F127B40020AF60000C8A
-:104A50009785004030B14000162000022403001664
-:104A60002403000E24154007A363000AAF75001449
-:104A7000939000428F6F0014321900010019C24058
-:104A800001F84025AF680014978700408F63001439
-:104A900030EE0010006E6825AF6D0014978C00405A
-:104AA000318B000811600165000000008F65001463
-:104AB0003C0B10003C0A800000AB8825AF7100144D
-:104AC00095460E0A3C0981002413000E30C2FFFFF8
-:104AD00000492025AF640004A3730002937F000AFD
-:104AE0003406FFFC27F20004A372000A978D0040F1
-:104AF00031AC200011800157000000003C0780000D
-:104B0000978D004094EC0E0C97910040000D584298
-:104B10003185C000316A00030005130332291000FB
-:104B200001429825000922030264F825001F90C065
-:104B3000A7720012979500409379000A00158182B0
-:104B40003218003C0319782125E8003CA3680009CD
-:104B500094EE0E0C31C33FFFA76300109763001261
-:104B60009367000900E3702125CD000231AC0007F6
-:104B7000000C582331650007A365000B93710009F1
-:104B800097640012976A0010322200FF8F9100385C
-:104B9000979F004000444821012A982102669021F5
-:104BA00033F5004012A000053246FFFF00D1402B34
-:104BB0003C12800011000016000098210226782B7C
-:104BC00015E001368FA700203C1880008F100E14CE
-:104BD0003C058000AF100E108F190E1CAF190E1877
-:104BE000AF060E008CB200003255000812A0FFFD87
-:104BF0000000000094BF0E0800C088210000902132
-:104C0000A79F00408CA60E0424130001AF86003835
-:104C1000976900103135FFFF8E8C00000191202331
-:104C200010800118AE8400009367000814E000D8DB
-:104C3000000000000E0001B4240400108F8E004814
-:104C40003C0332000040282131C600FF00063C0032
-:104C500000E3602525CD0001AF8D0048AC4C00007D
-:104C60009362000997640012937F000A304A00FFA4
-:104C7000308BFFFF014B48210009CC0033F000FFCF
-:104C80000330C025ACB800048F8F004897880040DF
-:104C90003103200010600103ACAF0008976F0012D1
-:104CA00031E8FFFF06400101ACA8000C97900040DE
-:104CB0003205000814A0000226280006262800025B
-:104CC0003C048000948B0E148C850E1C8F670004AE
-:104CD000936A00023164FFFF314900FFAFA9001061
-:104CE0008F7F0014AFA80018AFBF00140E00019A08
-:104CF00000000000240400100E0001C800000000A5
-:104D00008E92000016400005000000008F7900140C
-:104D10002405FFBF0325A024AF7400148F69000C85
-:104D20000135F821AF7F000C9375000816A000082C
-:104D30000000000012600006000000008F6B0014ED
-:104D40003C0CEFFF3584FFFE01645024AF6A001471
-:104D5000A37300088FA700200A0003160220202159
-:104D6000AED10E000A0001F83C05800014E0FF21DE
-:104D700030B9A0400E0001600000A0212E9100017A
-:104D80000237B02512C000178FBF00488F85003C46
-:104D900024170F0010B700CD3C0480008C990178D7
-:104DA0000720FFFE24150F0050B500EB3C048000E7
-:104DB0008C890E14240502403C141000AC89014477
-:104DC0008C9F0E1CAC9F0148A0800152A480015A08
-:104DD000AC800160A4800158AC850154AC9401788A
-:104DE0008FBF00488FB700448FB600408FB5003C9E
-:104DF0008FB400388FB300348FB200308FB1002CE5
-:104E00008FB0002803E0000827BD00508F910038C4
-:104E1000979300403C1280000220A821326A004093
-:104E20001540FF7D00009821976B00108F8500389A
-:104E30003162FFFF104500A2000020210080A02168
-:104E4000108000E500E088211620FED2000000005E
-:104E50000A0002E72E9100013C0380008C7F01785C
-:104E600007E0FFFE240408008F860000AC64017890
-:104E70003C038000946C008A318BFFFF0166502355
-:104E80002549FFFF31281FFF2D0200081440FFF9BC
-:104E9000000000008F8E0048346F40008F83003C7C
-:104EA00000E0A021240D0F0025C70001AF870048B6
-:104EB00000CF3021023488233C08800031D500FF28
-:104EC000106D000524070001939300423272000127
-:104ED0000012824036070001001514003C09010051
-:104EE00000492025ACC400008F9F004830B900362F
-:104EF00030B80008ACDF00041300009000F99825DA
-:104F000095070E0A8F8E00003C03810030EDFFFFF5
-:104F100025CB000801A328253C0C1000316A1FFF97
-:104F2000269200062406000EAD050160026C98254D
-:104F3000A506015AAF8A0000A512015816200008E4
-:104F40003C1080008F99003C24180F005338000259
-:104F500024170001367300400E0001593C108000F8
-:104F60008E1F0E1402402021AE1F01448E120E1C13
-:104F7000AE120148A2150152AE1301540E00016792
-:104F80003C151000AE1501780A000319000000005E
-:104F900093780009976300129368000B330F00FFAA
-:104FA00001E33821310200FF00E2702125D0000A20
-:104FB0003210FFFF0E0001B4020020218F8600484E
-:104FC0003C1941003C07800024CD0001AF8D004812
-:104FD000936C00099764001230C600FF318A00FF0D
-:104FE000308BFFFF014B482100062C00253F0002BB
-:104FF00000BFC02503197825AC4F00008F68000C56
-:1050000094EE0E1401121825AC4300048CE50E1C1E
-:105010008F670004936D000231C4FFFF31AC00FFC5
-:10502000AFAC00108F620014AFB100180E00019AEF
-:10503000AFA200140A0002C502002021AF600004E4
-:10504000A3600002978D004031AC20001580FEABBC
-:1050500000003021A7600012979000409378000A6A
-:105060003C03800032191F000019798301F84021A8
-:1050700025070028A3670009946E0E0C0A00025E43
-:10508000A76E00108F6E001435CD00400E00015940
-:10509000AF6D00140A000291000000000A00031620
-:1050A000000020210641FF01ACA0000C8CB8000CD0
-:1050B0003C198000031990250A0002B2ACB2000C22
-:1050C000000090210A00028D2413000112800005C7
-:1050D0003C0D800095A60E0830D3004012600042BF
-:1050E000000000008C9001780600FFFE0000000028
-:1050F00094920E103C030500240720003258FFFF55
-:1051000003037825AC8F014C8C880E143C0E1000E4
-:10511000AC8801448C820E1CAC820148A0800152F4
-:10512000A480015AAC800160A4800158AC8701546E
-:10513000AC8E01780A0002EE3C0480008F900000E3
-:1051400026920002A5120158260F000831E81FFF21
-:105150000A000356AF880000AC80014C1280001991
-:10516000000000008C8A0E10AC8A01448C830E185B
-:105170003C0C800024160040AC8301488FBF0048DF
-:10518000A18001528FB70044A580015A8FB5003C21
-:10519000AD8001608FB40038A58001588FB3003412
-:1051A000AD9601548FB200308FB600408FB1002C05
-:1051B0008FB000283C04100027BD005003E0000819
-:1051C000AD8401788C8B0E14AC8B01448C830E1C47
-:1051D0000A0003E43C0C80000E0001602E910001E7
-:1051E0000A0002E80237B025000000000000000DB0
-:1051F000000000002400033A0A0003C03C048000C1
-:1052000027BDFFE0AFBF001C3C1F20FF3C07600034
-:105210003C0980002402001037F9FFFDACE23008A1
-:10522000AFB20018AFB10014AFB00010AD390E002E
-:10523000000000000000000000000000000000006E
-:10524000000000003C1800FF3712FFFDAD320E00D9
-:105250003C0B60048D7050002411FF7F3C0E000257
-:105260000211782435EC380C35CD0109ACED4C1821
-:10527000240A0009AD6C50008CE80438AD2A0008FF
-:10528000AD2000148CE54C1C3106FFFF38C42F7193
-:1052900000051E023062000F2486C0B310400007D4
-:1052A000AF8200088CE54C1C3C09001F3528FC002F
-:1052B00000A81824000321C2AF8400048CF1080860
-:1052C0003C0F57092412F0000232702435F0001010
-:1052D00001D0602601CF68262DAA00012D8B000188
-:1052E000014B382550E00009A380000C3C02601CF3
-:1052F0008C590008241F0001A39F000C33387C0048
-:10530000A7980010A780000EA380000DAF80004872
-:1053100014C00003AF8000003C066000ACC0442C09
-:105320000E0004B63C1080000E000E0E00000000BF
-:105330003C110800263139883C12080026523A08F0
-:105340008E05000038A30001306400011480FFFCCA
-:10535000000000008E0601003C0C800A240AFF8039
-:1053600024C7024030EB007F016C482100EA402452
-:10537000AE060020AF890044AE0800243C03800044
-:10538000AF86003C8C6D017805A0FFFE2419080053
-:10539000AC79017890780108A3980042938F00427D
-:1053A00031EE000111C0000F240D0D0024C2F800E1
-:1053B0002C5F030113E0001C000629C224A3FFF0A8
-:1053C00000032042000431400E0001CF00D1D8215B
-:1053D0003C0440003C068000ACC401380A0004577D
-:1053E0000000000010CD0026240E0F0010CE002A71
-:1053F0003C028008345F008093F90000240F0050C5
-:10540000333800FF170FFFF33C0440000E00092F54
-:10541000000000003C0440003C068000ACC40138A1
-:105420000A000457000000008F83000400A3402BF3
-:105430001500000B8F8B0008006B50212547FFFFE4
-:1054400000E5482B1520000600A36023000C29402E
-:105450000E0001CF00B2D8210A00047C3C044000B9
-:10546000000000000000000D00000000240003AD5B
-:105470000E0001CF000000000A00047C3C04400044
-:105480003C1B0800277B3B080E0001CF00000000FA
-:105490000A00047C3C0440003C1B0800277B3B289E
-:1054A0000E0001CF000000000A00047C3C04400014
-:1054B000000411C003E00008244202403C0408003C
-:1054C00024843B6C2405001A0A00006D0000302182
-:1054D00027BDFFE0AFBF001CAFB20018AFB1001492
-:1054E000AFB000103C108000920B01092412FF8025
-:1054F0000E0004B33164007F8F91003C00515021B5
-:1055000001524024AE080024920301090E0004B3A6
-:105510003064007F24060080240700C0240400407B
-:10552000AE000810AE040814AE060818AE07081C3A
-:10553000920C01090051F82133F8007F3C19800AD0
-:10554000031910213184007F0E0004B3AF820044A0
-:105550008E1101003C0C008035850001022278216B
-:1055600001F24824AE0908048E0E010035980002AD
-:105570003609090001C2682131AB00780165502568
-:10558000AE0A08208E0501008E080100360509804C
-:10559000010218212464004000923024AE0608085D
-:1055A0008E07010000E2F82127F90040333200782D
-:1055B00002588825AE1108248E040100952F000C96
-:1055C0008FBF001C8FB2001831EEFFFF000E69C0C4
-:1055D000AE0D0800AE0C0828952B000C8FB10014FE
-:1055E000316AFFFF000A41C0AE08002C8CA30050B6
-:1055F0008FB000108CA2003C8D2400048CA6001CEF
-:105600008CA7003827BD0020AF830060AF82005018
-:10561000AF84004CAF86005803E00008AF87005C01
-:105620003C098000352309009128010B906A001184
-:105630002402002800804821314700FF00A070218B
-:1056400000C068213108004010E20002340C86DD01
-:10565000240C08003C0A800035420A9A9447000056
-:10566000354B0A9C35460AA030F9FFFFAD390000E2
-:105670008D780000354B0A8024040001AD38000409
-:105680008CCF0000AD2F00089165001930A30003F6
-:105690001064008E28640002148000AD240500020E
-:1056A0001065009C240F0003106F00B235450AA45A
-:1056B000240A0800118A0047000000005100003C45
-:1056C0003C0B80003C04800034830900906700128A
-:1056D00030E200FF004D7821000FC8802724000130
-:1056E0003C0A8000354F090091E50019354C0980CE
-:1056F0008D87002830A300FF0003150000475825C0
-:105700000004C4003C19600001793025370806FF09
-:10571000AD260000AD2800048DEA002C25280028C5
-:10572000AD2A00088DEC0030AD2C000C8DE5003466
-:10573000AD2500108DE40038AD2400148DE3001C6D
-:10574000AD2300188DE700203C038000AD27001C2E
-:105750008DE20024AD2200208DF900283462093C3E
-:10576000AD3900248C450000AD0E000434790900E9
-:10577000AD0500008C67010C25020014AD07000880
-:10578000932B00123C04080090843B90AD00001065
-:10579000317800FF030D302100064F0000047C002B
-:1057A000012F702535CDFFFF03E00008AD0D000C83
-:1057B00035780900930600123C05080094A53B804B
-:1057C00030C800FF010D5021000A60800A00053F2B
-:1057D000018520211500005A000000003C08080047
-:1057E00095083B863C06080094C63B8001061021C4
-:1057F0003C0B80003579090093380011932A001979
-:1058000035660A80330800FF94CF002A00086082C2
-:10581000314500FF978A0054000C1E00000524004B
-:105820003047FFFF006410250047C02501EA302102
-:105830003C0B4000030B402500066400AD2800002F
-:10584000AD2C0004932500183C0300062528001405
-:1058500000053E0000E31025AD2200088F24002C37
-:105860003C0380003462093CAD24000C8F38001CDE
-:10587000254F000131EB7FFFAD3800108C45000053
-:10588000AD0E000434790900AD0500008C67010CF1
-:10589000A78B005425020014AD070008932B0012BB
-:1058A0003C04080090843B90AD000010317800FF6C
-:1058B000030D302100064F0000047C00012F7025ED
-:1058C00035CDFFFF03E00008AD0D000C3C020800E1
-:1058D00094423B8A3C05080094A53B8035440AA4C9
-:1058E0003C07080094E73B7C948B00000045C821EE
-:1058F0000327C023000B1C002706FFF2006650257B
-:10590000AD2A000CAD200010AD2C00140A000533A8
-:1059100025290018354F0AA495E500009564002854
-:105920000005140000043C003459810000EC5825A7
-:10593000AD39000CAD2B00100A00053325290014E9
-:105940003C0C0800958C3B860A00058325820001EB
-:105950005460FF58240A080035580AA4970600002E
-:1059600000061C00006C5025AD2A000C0A0005330F
-:10597000252900103C03080094633B8A3C0708007B
-:1059800094E73B803C0F080095EF3B7C94A400001B
-:105990009579002800671021004F582300041C004F
-:1059A000001934002578FFEE00D87825346A81008C
-:1059B000AD2A000CAD2F0010AD200014AD2C001846
-:1059C0000A0005332529001C03E00008240207D043
-:1059D00027BDFFE0AFB20018AFB10014AFB00010A8
-:1059E000AFBF001C0E00004D008088218F88005042
-:1059F0008F87004C3C05800834B2008001112821BB
-:105A00003C10800024020080240300C000A7202353
-:105A1000AE0208183C068008AE03081C188000047B
-:105A2000AF850050ACC500048CC90004AF89004CA0
-:105A300012200009360409800E0005F9000000005C
-:105A4000924C00278E0B007401825004014B3021D0
-:105A5000AE46000C360409808C8E001C8F8F0058D7
-:105A600001CF682319A000048FBF001C8C90001C7C
-:105A7000AF9000588FBF001C8FB200188FB1001478
-:105A80008FB000100A00004F27BD00208F860060F5
-:105A90008F8300508F82004C3C05800834A4008026
-:105AA000AC860050AC83003C03E00008ACA20004CC
-:105AB0003C0308008C63005427BDFFF8308400FFCE
-:105AC0002462000130A500FF3C010800AC22005414
-:105AD00030C600FF3C0780008CE801780500FFFE1F
-:105AE0003C0A7FFFA3A400038FA400003549FFFFF9
-:105AF00000891824000647C000681025AFA20000E6
-:105B000090F9010AA3A000023C1880FFA3B900018C
-:105B10008FAE000030AD007F370FFFFF01CF58245C
-:105B2000000D66003C090020016C50253526200040
-:105B30002405FF803C04100027BD0008ACEA014C9E
-:105B4000ACE60154A4E00158A0E5015203E00008CE
-:105B5000ACE40178308800FF3C03800030A400FFF3
-:105B60008C6201780440FFFE000000003C038000CE
-:105B700034660A008CCA0020346709800004482B70
-:105B8000AC6A01448CC5002400091540AC6501488D
-:105B9000A068015090E4004CA064016D03E000088F
-:105BA000A460015827BDFFE8308400FFAFBF00109C
-:105BB0000E00065C30A500FF8F8300508FBF0010E1
-:105BC0003C058000344600402404FF903C02100055
-:105BD00027BD0018ACA3014CA0A40152ACA60154EF
-:105BE00003E00008ACA2017827BDFFE03C08800874
-:105BF000AFBF001CAFB20018AFB10014AFB00010BF
-:105C0000351000808E0600183C078000309200FF9F
-:105C100000C72025AE0400180E00004D30B100FF73
-:105C200092030005346200080E00004FA202000536
-:105C3000024020210E00067002202821024020216F
-:105C40008FBF001C8FB200188FB100148FB00010EE
-:105C500024050005240600010A00063327BD0020A4
-:105C60003C05800034A309809066000830C200081B
-:105C70001040000F3C0A01013549080AAC890000B8
-:105C80008CA80074AC8800043C07080090E73B90A7
-:105C900030E5001050A00008AC8000083C0D8008E2
-:105CA00035AC00808D8B0058AC8B00082484000C30
-:105CB00003E00008008010210A0006B32484000CD1
-:105CC00027BDFFE83C088000AFB00010AFBF001454
-:105CD0003506098090C7000924020006350909002D
-:105CE00030E300FF0080802100A06021240B00042D
-:105CF000106200792407000294CF005C3C0E02047D
-:105D000031EDFFFF01AE5025AE0A000090C500083E
-:105D100030A40020108000080000000090C2004E57
-:105D20003C1F010337F90300305800FF03193025E9
-:105D3000240B0008AE0600049139001191260012D0
-:105D400091240011333800FF0018708230CF00FF1B
-:105D500001CF5021014C6821308800FF31AAFFFF9C
-:105D600039030028000A28801460002B0205402314
-:105D7000912400123C0E800035D90980308500FF47
-:105D800000AC182100031080004BF821001F840094
-:105D9000360906FFAD09000435C909009126001136
-:105DA000912F0012000BC0828F2B003431ED00FFC9
-:105DB0008DC4010C01AC282100B810210164F82326
-:105DC0000007840000021F000070C82533E9FFFFB0
-:105DD00030CF00FC032970250158202101E86821FB
-:105DE00000045080ADAE000C0E00004D010A802171
-:105DF0003C078008240C000434EB00800E00004FA8
-:105E0000A16C0009020010218FBF00148FB0001098
-:105E100003E0000827BD0018912500119123001907
-:105E20003C18080097183B8630A200FF0002F88259
-:105E3000307000FF001FCE0000104C0003293025F9
-:105E400000D870253C0F400001CF68253C0E800033
-:105E5000AD0D000035C9090091260011912F0012E7
-:105E600035D90980000BC08231ED00FF8F2B003443
-:105E70008DC4010C01AC282100B810210164F82365
-:105E80000007840000021F000070C82533E9FFFFEF
-:105E900030CF00FC032970250158202101E868213A
-:105EA00000045080ADAE000C0E00004D010A8021B0
-:105EB0003C078008240C000434EB00800E00004FE7
-:105EC000A16C0009020010218FBF00148FB00010D8
-:105ED00003E0000827BD00180A0006C524070012C9
-:105EE00027BDFFD0AFB60028AFB50024AFB4002067
-:105EF000AFB10014AFBF002CAFB3001CAFB200189D
-:105F0000AFB000103C06800090C3010B309400FF3E
-:105F100030B500FF306200300000B0211040009D1D
-:105F20000000882134C409809088000800083E00E1
-:105F300000072E0304A000C4240400048F8700502F
-:105F40003C010800A0243B903C0C8000AD80004840
-:105F50003C038000906D010B31A5002010A00007CC
-:105F60003C0B8000347209809250000800107E00C3
-:105F7000000F760305C000C93C1980089169010B28
-:105F8000356A098091480008312400400004102B34
-:105F900031030008241200031460000200E2982379
-:105FA000000090213C108000360E0A80360809005F
-:105FB00095C7002C910300119102001291C50018A1
-:105FC000307800FF305F00FF025FC8210019788041
-:105FD00091CC001801F8682101B1302130B100FFE7
-:105FE00000D11821A78700543C010800A4263B8655
-:105FF0003C010800A4233B8815800002000000003B
-:106000000000000D9204010B3065FFFF3C01080009
-:10601000A4233B8A308900403C010800A4203B8037
-:106020003C010800A4203B7C1120000224A4000AAB
-:1060300024A4000B3091FFFF0E0001B402202021A8
-:106040009219010B3C0E080095CE3B8A3C0D0800CE
-:1060500091AD3B910019C182330F000101CF28217E
-:10606000000D340024A7000200C758253C0C110085
-:10607000016C5025AC4A000024440008026028212D
-:10608000024030210E00050FAC4000040E00069FB8
-:106090000040202116C00068004020219212010B10
-:1060A0003256004012C000053C0200FF8C930000F5
-:1060B000345FFFFF027F8024AC9000000E0001C817
-:1060C000022020213C03080090633B9030710003C4
-:1060D000122000163C1080088F8C00503C0B80086A
-:1060E00035640080258A0001AC8A003C3C058008AC
-:1060F0008CA9000401402021012A4023190000023C
-:10610000AF8A00508CA400040E0005F9ACA4000472
-:106110003C0E80008DCD00743C05800834A60080C4
-:10612000004D3821ACC7000C3C10800836120080AE
-:106130000280202102A02821A240006B0E00065CF4
-:106140003C1480008F9600503C151000AE96014C18
-:106150008F980048344F00068FBF002C271900018C
-:10616000AF9900488FB60028A29801528FB3001C47
-:10617000AE8F01548FB20018AE9501788FB1001424
-:106180008FB500248FB400208FB0001003E000080A
-:1061900027BD003034C30980906F0008000F7600DF
-:1061A000000E6E0305A0003334DF090093F8001BD6
-:1061B000241900103C010800A0393B903313000261
-:1061C0001260FF638F8700508F82005C1447FF616D
-:1061D0003C0380000E00004D000000003C048008DD
-:1061E0003485008090A8000924070016310300FFC1
-:1061F0001067000D0000000090AB00093C0608008D
-:1062000090C63B9024090008316400FF34CA0001A5
-:106210003C010800A02A3B901089002F240C000AA2
-:10622000108C00282402000C0E00004F000000001B
-:106230000A00075B8F8700500E0006B70240282136
-:106240000A0007AE004020213C0B8008356A008020
-:106250008D4700548CC9010C1120FF39AF870050C5
-:10626000240600143C010800A0263B900A00075AAF
-:106270003C0C800090710008241200023C010800D0
-:10628000A0323B90323000201200000B2416000197
-:106290008F8700500A00075B241100083733008005
-:1062A0008E7F0038AF3F00048F380004AE78003C8A
-:1062B0000A0007663C0B80008F8700500A00075BCE
-:1062C00024110004A0A200090E00004F00000000ED
-:1062D0000A00075B8F870050240200140A00083967
-:1062E000A0A2000927BDFFE8AFBF0014AFB00010A7
-:1062F0003C10800092020109240500010E00065C9A
-:10630000304400FF3C1F800893F8000E37E3008004
-:1063100093F9000F906E002693E9000A332F00FFD7
-:1063200000186600000F6C0031CB00FF018D502576
-:10633000000B320001463825312800FF344560004B
-:1063400000E820252402FF813C031000AE04014C2C
-:106350008FBF0014AE050154A2020152AE030178B2
-:106360008FB0001003E0000827BD001827BDFFE82C
-:10637000308400FFAFBF00100E00065C30A500FFA8
-:10638000344600403C0480002405FF92AC86015452
-:10639000A08501528F8300508FBF00103C02100077
-:1063A00027BD0018AC83014C03E00008AC820178E3
-:1063B00027BDFFD8AFB20018AFB10014AFB00010C6
-:1063C000AFBF0020AFB3001C3C07800090E2010982
-:1063D000308600FF30B000FF000618C23204000211
-:1063E0003071000114800007305200FF3C09800822
-:1063F00035330080926800053105000810A0000CBC
-:1064000030CA0010024020210E00068102202821FF
-:10641000240200018FBF00208FB3001C8FB2001830
-:106420008FB100148FB0001003E0000827BD0028D2
-:106430001540003034E50A008CB900248CB80008FF
-:1064400013380047000040213C0E800835D30080FF
-:10645000926D0068240B000231AC00FF118B0080AC
-:106460003C068000927F004C90C40109509F0004BC
-:106470003213007C11000067000000003213007C22
-:106480001660005A0240202116200008320C00013C
-:106490003C07800034EB0A008D6500248CE8010481
-:1064A00014A8FFDC00001021320C00011180000D47
-:1064B000024020213C1080008E0E010C8F8D006068
-:1064C00011CD0008000000000E00073F0220282127
-:1064D0008E0F010C3C18800837100080AE0F005062
-:1064E000024020210E000670022028210A00088C9C
-:1064F000240200013C0708008CE7006424E6000148
-:106500003C010800AC2600641600000D00000000ED
-:10651000022028210E00067002402021926F0068A0
-:10652000240D000231EE00FF11CD00220240202197
-:106530000E000840000000000A00088C2402000140
-:106540000E00004124040001926C0025020C582525
-:106550000E00004FA26B00250A0008CC0220282163
-:106560008E6300188CE401048CBF00240003160223
-:10657000149FFFB53045007F9269004C264400010E
-:106580003093007F12650040312300FF1464FFAF99
-:106590003C0E8008264800013111007F310200FFC7
-:1065A0001225000B24080001004090210A000899E0
-:1065B00024110001240500040E0006332406000106
-:1065C0000E000840000000000A00088C24020001B0
-:1065D0002407FF800247282400A79026324200FFAC
-:1065E000004090210A000899241100010E00073F85
-:1065F000022028213206003010C0FFA33210008292
-:10660000024020210E000681022028210A00088C69
-:10661000240200018E63001802402021022028215C
-:10662000006610250E000862AE6200189264004CED
-:1066300024050003240600010E000633308400FF09
-:106640000E00004124040001926A0025020A482538
-:106650000E00004FA26900250A00088C24020001E8
-:106660008E7800183C1980000240202103197825FB
-:10667000022028210E000670AE6F00189264004CB4
-:106680000A000914240500043246008038CA00803C
-:10669000146AFF6E3C0E80080A0008ED26480001CF
-:1066A00027BDFFC0AFB000183C108000AFBF00385E
-:1066B000AFB70034AFB60030AFB5002CAFB4002890
-:1066C000AFB30024AFB200200E0004BBAFB1001C7A
-:1066D000920401089205010B308400FF0E0008733C
-:1066E00030A500FF144000E58FBF00383C0980084A
-:1066F00035280080A100006B3607098090E6000075
-:10670000240200503C17080026F73B4830C300FF26
-:106710003C13080026733B58106200033C108000B5
-:106720000000B82100009821241F001036110A0033
-:10673000361409808E1601048F8D00508E38002487
-:1067400036190A808E9200203C010800A03F3B9041
-:10675000972C002C8EF50000932B0018024D70230F
-:1067600002D878233C010800AC2F3B6C3C010800A8
-:10677000AC2E3B703C010800AC2D3B94A78C005420
-:1067800002A0F809317200FF304A0002154000E80B
-:106790003045000110A000C300000000928A0008EC
-:1067A0003150000816000002241400030000A0214C
-:1067B0003C06800034C4090034C30A008C6E0024F7
-:1067C00090850011908200129099001130B800FF5E
-:1067D000305100FF0291F821001FB080332F00FFDD
-:1067E00002D85821024FA82126AC0010017268215E
-:1067F0003C1580003C010800AC2E3B983C01080091
-:10680000A42D3B883C010800A42C3B843C010800DB
-:10681000A42B3B8636B609808F8700508F8900589D
-:106820008ED20020240800060127302302472823A7
-:106830003C010800AC283B8C04C000B5000090214E
-:1068400004A000B300C5802B120000B500000000BA
-:106850003C010800AC263B708E7100000220F80954
-:1068600000000000304A0002154000740040802102
-:10687000304B0001556000118E7100043C0D080082
-:106880008DAD3B743C0EC0003C04800001AE602521
-:10689000AEAC0E008C980000330F000811E0FFFD35
-:1068A00000000000949F0E0824120001A79F0040E2
-:1068B0008C990E04AF9900388E7100040220F809FB
-:1068C000000000000202802532020002144000B4E1
-:1068D000000000003C08080095083B7C3C110800C3
-:1068E00096313B883C09080095293B7E3C03080013
-:1068F0008C633B74011168213C1F08008FFF3B989B
-:106900003C07080094E73B923C11800001A920213C
-:106910008E38010C006828212499000200A77021FC
-:1069200003E37821AF9800603C010800AC2F3B984E
-:106930003C010800A42E3B803C010800A42D3B8AAA
-:106940000E0001B43324FFFF8F8C0048004020214B
-:106950003C010800A02C3B918E620008258B0001B1
-:10696000AF8B00480040F809000000008F85005000
-:10697000028030210E00050F004020210E00069FEE
-:10698000004020218E6A000C0140F80900402021BF
-:106990003C08080095083B8A3C09080095293B7E85
-:1069A0000109382124E600020E0001C830C4FFFFAF
-:1069B0003C0408008C843B6C3C0308008C633B74F3
-:1069C000008328233C010800AC253B6C14A0000682
-:1069D000000000003C0A08008D4A3B8C3546004010
-:1069E0003C010800AC263B8C124000438F8C0044D5
-:1069F0008E2B0E108F920044AE4B00208E220E186C
-:106A0000AE4200243C04080094843B800E0005FB49
-:106A1000000000008F9900508E7800103C010800A3
-:106A2000AC393B940300F809000000003C0F08005B
-:106A30008DEF3B6C15E0FF798F87005097940054E1
-:106A40003C13800E321501000E00062AA674002C9D
-:106A500016A00046320300105460004D8EE500047D
-:106A60003207004054E0001D8EF000088EE4000C58
-:106A70000080F809000000008FBF00388FB7003495
-:106A80008FB600308FB5002C8FB400288FB3002450
-:106A90008FB200208FB1001C8FB0001803E00008F7
-:106AA00027BD0040920901098F88003C00093E0083
-:106AB00000E83025AE0600808E2300208E240024BE
-:106AC000AFA30010AE030E148FA20010AE020E1082
-:106AD000AE040E1C0A00096EAE040E180200F8097E
-:106AE000000000008EE4000C0080F80900000000A7
-:106AF0000A000A268FBF0038240E0001240D000171
-:106B0000A5800020A58E00220A000A08AD8D002471
-:106B10003C010800AC203B700A00099E8E71000009
-:106B20003C010800AC253B700A00099E8E710000F4
-:106B300092110109000028210E000670322400FF86
-:106B40008FBF00388FB700348FB600308FB5002C60
-:106B50008FB400288FB300248FB200208FB1001CA7
-:106B60008FB0001803E0000827BD00403C1F8000E4
-:106B700093F60109000028210E00073F32C400FFF0
-:106B8000320300105060FFB7320700408EE500046A
-:106B900000A0F809000000000A000A2032070040A7
-:106BA0005240FFA7979400548EB60E148F93004462
-:106BB000AE7600208EB40E1CAE7400240A000A17B4
-:106BC000979400548F8200140004218003E0000891
-:106BD000008210213C07800834E200809043006965
-:106BE00000804021106000093C0401003C070800BF
-:106BF0008CE73B948F83003000E32023048000085F
-:106C00009389001C14E300030100202103E0000825
-:106C1000008010213C04010003E0000800801021E6
-:106C20001120000B006738233C0D800035AC098033
-:106C3000918B007C316A000211400020240900344D
-:106C400000E9702B15C0FFF10100202100E9382375
-:106C50002403FFFC00A3C82400E3C02400F9782B20
-:106C600015E0FFEA0308202130C4000300041023CC
-:106C700014C00014304900030000302100A978211D
-:106C800001E6702100EE682B11A0FFE03C0401003A
-:106C90002D3800010006C82B0105482103193824AE
-:106CA00014E0FFDA2524FFFC2402FFFC00A21824D4
-:106CB0000068202103E00008008010210A000A97E4
-:106CC000240900303C0C80003586098090CB007C84
-:106CD000316A00041540FFE9240600040A000AA6F0
-:106CE000000030213C0308008C63005C8F82001898
-:106CF00027BDFFE8AFBF001410620005AFB0001061
-:106D0000000329C024A40280AF840014AF830018BC
-:106D10003C10800036030A00946500320E000A78A9
-:106D200030A43FFF8E0401003C180080370F0003A1
-:106D30000082C8212402FF80032260243329007FBF
-:106D4000000CF94003E94025332E00783C0D10007B
-:106D5000010D502501CF5825AE0C002836080980BA
-:106D6000AE0C080CAE0B082CAE0A0830910300697B
-:106D70003C06800C0126382110600006AF870034E5
-:106D80008D09003C8D06006C0126382318E0007F39
-:106D9000000000003C0C8008358B00803C0A80001D
-:106DA000A1600069355009808E0200383C068000E1
-:106DB00034C50A0090AD003C31A800201100001934
-:106DC000AF820030240E00013C19800037300A00E9
-:106DD000A38E001CAF8000248E0400248F85002425
-:106DE00024180008AF800020AF8000283C01080074
-:106DF000A4383B7E3C010800A4203B920E000A7C94
-:106E000000003021920F003C8FBF00148FB00010A3
-:106E1000000F7142AF82002C27BD001803E000086C
-:106E200031C2000190B90032240F0001333800FF55
-:106E300000182182108F003F241F0002109F006263
-:106E400034C20AC03C03800034640A008C990024D8
-:106E50001720001D3466090090830030241F0005B0
-:106E60003062003F105F004C240500018F86002037
-:106E7000A385001CAF860028AF8600243C19800043
-:106E800037300A008E0400248F850024241800085F
-:106E90003C010800A4383B7E3C010800A4203B9242
-:106EA0000E000A7C00000000920F003C8FBF00140F
-:106EB0008FB00010000F7142AF82002C27BD001868
-:106EC00003E0000831C200018C8800088C8D00248A
-:106ED0008CCB00643C19800037300A00AF8B002453
-:106EE000A380001C8E0400248F8600208F85002440
-:106EF000010D602324180008AF8C00283C01080015
-:106F0000A4383B7E3C010800A4203B920E000A7C82
-:106F100000000000920F003C8FBF00148FB00010E3
-:106F2000000F7142AF82002C27BD001803E000085B
-:106F300031C2000190A7003030E3003F50640028C8
-:106F400034C50AC08CAA00241540002234C80900A8
-:106F50008CAB00483C0C7FFF3585FFFF016510249A
-:106F60003C188000AF820020370509008F8E00207A
-:106F70008CAF006001CF682B15A0000201C020215A
-:106F80008CA400600A000B18AF8400208D02006CF6
-:106F90000A000AF33C0680008C8900488F86002096
-:106FA0003C0A7FFF3550FFFF013038243C04800845
-:106FB00024050001AF870028AC80006CA385001C6D
-:106FC0000A000B26AF8600248C4400140A000B181C
-:106FD000AF8400208D0200680A000B603C1880001E
-:106FE00034C409808C8600708CB0001400D0482B0B
-:106FF00011200004000000008C8200700A000B6069
-:107000003C1880008CA200140A000B603C18800021
-:107010008F85002427BDFFE0AFBF0018AFB100147B
-:1070200014A00008AFB000103C04800034870A00B0
-:1070300090E600302402000530C3003F106200BE1D
-:10704000348409008F91002000A080213C0480003E
-:10705000348E0A008DCD00043C0608008CC63B70BF
-:1070600031A73FFF00E6602B5580000100E0302192
-:10707000938F001C11E0007600D0102B349909800A
-:107080009338007C3304000210800077240300341E
-:1070900000C3F82B17E000DD00C3302300D0102B15
-:1070A0003C010800A4233B7C1440006D0200182121
-:1070B0003C0408008C843B6C0064282B54A0000125
-:1070C000006020213C05800034A90A009128003C82
-:1070D0003C010800AC243B74310300201460000222
-:1070E000000048218CA90E188F88002C0128502BF5
-:1070F0001140005F000000003C0508008CA53B74B7
-:1071000000A96021010C582B1160005C00B0682BB5
-:107110000109382300E028213C010800AC273B741A
-:10712000120000032403FFFC10B00093322B000375
-:1071300000A310243C010800A4203B923C0108005D
-:10714000AC223B74004028218F84002412040006E6
-:107150003C0A80088D4B006C02002021AF9100207A
-:1071600025700001AD50006C8F8C002800858823AD
-:10717000AF91002401852023AF8400281220000253
-:1071800024070018240700103C0F800835E6008013
-:1071900090CE00683C010800A0273B902407000126
-:1071A00031CD00FF11A7004A000000001480001834
-:1071B000000028213C0C800091850109359109804F
-:1071C0008E2B001830A500FF24A30001000B8602BF
-:1071D0003206007F306A007F114600852407FF8059
-:1071E0003C04800834890080A123004C3C0808003E
-:1071F0008D083B8C240F00023C010800A02F3BD1DE
-:10720000350E00083C010800AC2E3B8C2405001014
-:107210003C028000345F0A0093F9003C33380020C0
-:107220001300000500A02021240300013C010800F8
-:10723000AC233B7434A400018FBF00188FB100143D
-:107240008FB000100080102103E0000827BD00204F
-:107250003C010800A4203B7C1040FF95020018214F
-:107260000A000BB300C018210A000BAB2403003046
-:107270003C0508008CA53B7400B0682B11A0FFA84A
-:10728000000000003C04080094843B7C00857821C9
-:1072900001E7702B11C000242CA300043C1F6000E8
-:1072A0008FF954043338003F1300001F0000000022
-:1072B0003C0208008C4200A41040FFDF240400427E
-:1072C00014A000198FBF00180A000C16000000005F
-:1072D0001528FFB6000000008CC300183C19800080
-:1072E000241F000200791025ACC2001837380A00AC
-:1072F000A0DF00689309003C2404000400A01021D2
-:10730000312800203C010800A0243BD111000002DC
-:1073100024050010240200013C010800AC223B6C53
-:107320000A000C0C3C0280001060FF7D2404004227
-:107330000A000C168FBF00188F8800288C89006007
-:107340000109282B14A00002010088218C91006003
-:107350003C0B80008D640E18240A000102202821B5
-:1073600002203021A38A001C0E000A7C022080210A
-:107370000A000B9AAF82002C000B5023122000074A
-:10738000314400033C0E800035CD098091A7007C7C
-:1073900030EC000415800019248F00043C01080023
-:1073A000A4243B923C19080097393B920325C02145
-:1073B00000D8202B1080FF658F8400242CA60005A8
-:1073C00014C0FF9D2404004230BF000317E00002F8
-:1073D00000BF182324A3FFFC3C010800AC233B742E
-:1073E0003C010800A4203B920A000BD90060282130
-:1073F00000A768240A000BFF01A718263C0108001B
-:10740000A42F3B920A000C70000000003C01080011
-:10741000AC203B740A000C15240400428F83002822
-:107420003C0B8000356A0A00146000060000102141
-:10743000914600302405000530C400FF108500038C
-:107440000000000003E0000800000000914900482F
-:10745000312800FF000839C214E0FFFA3C0480081C
-:107460003C06080094C63B7C3C0308008C633B94BC
-:107470003C0508008CA53B743C18080097183B920B
-:107480000066C8218C8E00040325782101F868214C
-:1074900001AE60231980001D000000009158004CCF
-:1074A0008F8D0034956E0E10330F00FF8DA90004F0
-:1074B00001CF30238DAA000030CFFFFF000F610005
-:1074C000012C2821000038210147202100AC182B75
-:1074D0000083C821ADA50004ADB9000091B8000A31
-:1074E00001F87021A1AE000A956C0E128F8A00344B
-:1074F000A54C00089549003825280001A54800380A
-:107500009147000D34EB0008A14B000D03E000088B
-:107510000000000027BDFFD8AFB00018938F001CFB
-:107520008FB000143C087FFF8F8700243C0C800044
-:107530003518FFFFAFBF0020AFB1001C35990A001E
-:1075400002181824932A003C000F5FC03C02BFFFC2
-:107550002CF000013449FFFF006BF8253C080800BF
-:107560008D083B948F9900303C18080097183B8A8F
-:1075700003E9582400107F803C07EFFF3C05F0FF33
-:10758000016F18253C1180003149002034E2FFFFD3
-:1075900034ADFFFF362E098027A500102406000217
-:1075A00001194023270A000200621824008080216C
-:1075B00015200002000058218D8B0E1CA7AA001276
-:1075C0000500003A2407000030EF00FF000F3F00E5
-:1075D000006740253C028008AFA80014344B0080AF
-:1075E000916A00683C0F080091EF3B913C09DFFF76
-:1075F000353FFFFF000A602B3C02080094423B84A9
-:10760000A3AF0011011FC024000CCF40031918259F
-:107610008FA70010AFA300143C1F080093FF3B93FB
-:10762000A7A200168FA8001400ED48243C0B01000F
-:107630003C0A0FFF012BC82533F80003354CFFFF30
-:10764000010D78243C027000032C382400181E0021
-:1076500000E2482501E35825AFAB0014AFA90010A4
-:1076600091DF007CA3BF00150E0000630000000046
-:10767000362D0A0091A6003C30C400201080000680
-:10768000260200083C11080096313B80262EFFFFA1
-:107690003C010800A42E3B808FBF00208FB1001C4E
-:1076A0008FB0001803E0000827BD00288F8A002C47
-:1076B000016A602B5580FFC4240700010A000CFA00
-:1076C00030EF00FF9383001C3C02800027BDFFD8F1
-:1076D00034480A0000805021AFBF002034460AC061
-:1076E000010028211060000E344409809107003009
-:1076F000240B00058F89002030EC003F118B000B1C
-:1077000000003821AFA900103C0B80088D69006C87
-:10771000AFAA00180E00012BAFA90014A380001C13
-:107720008FBF002003E0000827BD00288D1F004800
-:107730003C1808008F183B748F9900283C027FFF8B
-:107740008D0800443443FFFFAFA900103C0B8008B4
-:107750008D69006C03E370240319782101CF68233D
-:1077600001A83821AFAA00180E00012BAFA9001400
-:107770000A000D4FA380001C3C05800034A60A00BF
-:1077800090C7003C3C06080094C63B923C020800AF
-:107790008C423B8C30E30020000624001060001E69
-:1077A000004438253C0880083505008090A3006817
-:1077B00000003021240800010000202124030001E2
-:1077C0003C0580008CAC01780580FFFE00000000C5
-:1077D000ACA80148A4A40144A4A301463C030800AA
-:1077E0008C633B943C188008370F0080ACA3014C9D
-:1077F0003C19080093393B913C0D1000A0B901528F
-:10780000ACA70154A4A6015891EE004CA0AE016DA6
-:1078100003E00008ACAD01788CA80E1C3C0B0800FE
-:107820008D6B3B7494AA0E1694A90E140166302138
-:107830003143FFFF0A000D773124FFFF3C04800035
-:1078400034830A009065003C30A200201040001CE8
-:10785000000000000000302100002021000018215D
-:107860003C0580008CA901780520FFFE0000000087
-:10787000ACA601483C0E08008DCE3B94240DFF9130
-:10788000240C00403C0B8008A4A30144356A00800E
-:10789000A4A40146ACAE014CA0AD0152ACAC015465
-:1078A000A4A0015890A301099144004C90A601099D
-:1078B0003C041000A0A6016D03E00008ACA4017810
-:1078C0008C860E1894880E1294870E103104FFFFD8
-:1078D0000A000D9F30E3FFFF3C04800034830A0060
-:1078E0009065003C30A200201040002627BDFFF824
-:1078F0002409000100003821240800013C06800012
-:107900008CC401780480FFFE0000000090CA0109C9
-:107910003C04080090843BD13C1880FFA3AA0003DC
-:107920008FA300003085007F370FFFFF0066102512
-:10793000AFA2000090D9010AA3A0000200056E00CA
-:10794000A3B900018FAE0000240A300027BD000853
-:1079500001CF6024018D5825ACCB014CACCA015439
-:10796000A4C00158ACC90148A4C701442409FF8040
-:10797000A4C801463C081000A0C9015203E0000859
-:10798000ACC801788C890E1894870E1294860E105C
-:1079900030E8FFFF0A000DC630C7FFFF27BDFFE834
-:1079A000AFB000103C108000AFBF001436180A00C2
-:1079B000970F00320E000A7831E43FFF8E0E01006F
-:1079C000240DFF803C04200001C25821016D602479
-:1079D000000C4940316A007F012A40250104382506
-:1079E0003C048008AE0708303486008090C50068EB
-:1079F0002403000230A200FF104300048F9F0020E8
-:107A00008F990024AC9F0068AC9900648FBF00146C
-:107A10008FB0001003E0000827BD00183C0A0800E2
-:107A2000254A36583C090800252936F43C08080048
-:107A300025082B003C07080024E737B83C0608005F
-:107A400024C634E03C05080024A532383C04080074
-:107A500024842E2C3C030800246335943C02080047
-:107A6000244233303C010800AC2A3B503C01080062
-:107A7000AC293B4C3C010800AC283B483C010800C9
-:107A8000AC273B543C010800AC263B643C01080099
-:107A9000AC253B5C3C010800AC243B583C01080091
-:107AA000AC233B683C010800AC223B6003E00008CB
-:047AB00000000000D2
-:0C7AB400800009408000090080080100EB
-:107AC0008008008080080000800E00008008008090
-:107AD0008008000080000A8080000A008000098081
-:047AE0008000090019
-:00000001FF
-/*
- * This file contains firmware data derived from proprietary unpublished
- * source code, Copyright (c) 2004 - 2009 Broadcom Corporation.
- *
- * Permission is hereby granted for the distribution of this firmware data
- * in hexadecimal or equivalent format, provided this copyright notice is
- * accompanying it.
- */
diff --git a/firmware/bnx2/bnx2-mips-09-6.0.17.fw.ihex b/firmware/bnx2/bnx2-mips-09-6.0.17.fw.ihex
new file mode 100644
index 000000000000..7f39b4a7f331
--- /dev/null
+++ b/firmware/bnx2/bnx2-mips-09-6.0.17.fw.ihex
@@ -0,0 +1,6488 @@
+:10000000080001180800000000005594000000C816
+:1000100000000000000000000000000008005594EF
+:10002000000000380000565C080000A00800000036
+:100030000000574400005694080059200000008436
+:100040000000ADD808005744000001C00000AE5CBD
+:100050000800321008000000000090900000B01C62
+:100060000000000000000000000000000800909068
+:100070000000033C000140AC0800049008000400AC
+:10008000000012FC000143E8000000000000000036
+:1000900000000000080016FC00000004000156E407
+:1000A000080000A80800000000003D28000156E8F4
+:1000B00000000000000000000000000008003D28D3
+:0800C000000000300001941063
+:0800C8000A00004600000000E0
+:1000D000000000000000000D636F6D362E302E31E1
+:1000E00037000000060011020000000000000003BD
+:1000F000000000C800000032000000030000000003
+:1001000000000000000000000000000000000000EF
+:1001100000000010000001360000EA600000000549
+:1001200000000000000000000000000000000008C7
+:1001300000000000000000000000000000000000BF
+:1001400000000000000000000000000000000000AF
+:10015000000000000000000000000000000000009F
+:10016000000000020000000000000000000000008D
+:10017000000000000000000000000000000000007F
+:10018000000000000000000000000010000000005F
+:10019000000000000000000000000000000000005F
+:1001A000000000000000000000000000000000004F
+:1001B000000000000000000000000000000000003F
+:1001C000000000000000000000000000000000002F
+:1001D000000000000000000000000000000000001F
+:1001E0000000000010000003000000000000000DEF
+:1001F0000000000D3C020800244256083C030800A1
+:1002000024635754AC4000000043202B1480FFFDB2
+:10021000244200043C1D080037BD9FFC03A0F021D0
+:100220003C100800261001183C1C0800279C5608AA
+:100230000E000256000000000000000D27BDFFB4B4
+:10024000AFA10000AFA20004AFA30008AFA4000C50
+:10025000AFA50010AFA60014AFA70018AFA8001CF0
+:10026000AFA90020AFAA0024AFAB0028AFAC002C90
+:10027000AFAD0030AFAE0034AFAF0038AFB8003C28
+:10028000AFB90040AFBC0044AFBF00480E001544FA
+:10029000000000008FBF00488FBC00448FB90040B1
+:1002A0008FB8003C8FAF00388FAE00348FAD003078
+:1002B0008FAC002C8FAB00288FAA00248FA90020C0
+:1002C0008FA8001C8FA700188FA600148FA5001000
+:1002D0008FA4000C8FA300088FA200048FA1000040
+:1002E00027BD004C3C1B60108F7A5030377B502864
+:1002F00003400008AF7A00008F82002427BDFFE092
+:10030000AFB00010AFBF0018AFB100148C42000CAA
+:100310003C1080008E110100104000348FBF001887
+:100320000E000D84000000008F85002024047FFF54
+:100330000091202BACB100008E030104960201084D
+:1003400000031C003042FFFF00621825ACA300042C
+:100350009202010A96030114304200FF3063FFFF4E
+:100360000002140000431025ACA200089603010C03
+:100370009602010E00031C003042FFFF00621825A8
+:10038000ACA3000C960301109602011200031C009E
+:100390003042FFFF00621825ACA300108E02011846
+:1003A000ACA200148E02011CACA20018148000083C
+:1003B0008F820024978200003C0420050044182509
+:1003C00024420001ACA3001C0A0000C6A782000062
+:1003D0003C0340189442001E00431025ACA2001CB0
+:1003E0000E000DB8240400018FBF00188FB1001457
+:1003F0008FB000100000102103E0000827BD00208E
+:100400003C0780008CE202B834E50100044100089A
+:10041000240300013C0208008C42006024420001D9
+:100420003C010800AC22006003E0000800601021DD
+:100430003C0208008C42005C8CA4002094A30016AF
+:100440008CA6000494A5000E24420001ACE40280B6
+:100450002463FFFC3C010800AC22005C3C0210005D
+:10046000A4E30284A4E5028600001821ACE6028819
+:10047000ACE202B803E000080060102127BDFFE0F5
+:100480003C028000AFB0001034420100AFBF001C3E
+:10049000AFB20018AFB100148C43000094450008BF
+:1004A0002462FE002C42038110400003000381C23D
+:1004B0000A00010226100004240201001462000553
+:1004C0003C1180003C02800890420004305000FF44
+:1004D0003C11800036320100964300143202000FB6
+:1004E00000021500004310253C0308008C63004403
+:1004F00030A40004AE220080246300013C01080007
+:10050000AC2300441080000730A200028FBF001C03
+:100510008FB200188FB100148FB000100A0000CE07
+:1005200027BD00201040002D0000182130A20080BF
+:1005300010400005362200708E44001C0E000C672F
+:10054000240500A0362200708C4400008F82000C2D
+:10055000008210232C43012C10600004AF82001095
+:10056000240300010A000145AF84000C8E42000400
+:100570003C036020AF84000CAC6200143C02080015
+:100580008C42005850400015000018218C62000475
+:10059000240301FE304203FF144300100000182121
+:1005A0002E020004104000032E0200080A00014041
+:1005B0000000802114400003000000000A000140F8
+:1005C0002610FFF90000000D2402000202021004B0
+:1005D0003C036000AC626914000018218FBF001C4E
+:1005E0008FB200188FB100148FB00010006010217E
+:1005F00003E0000827BD00203C0480008C8301003C
+:1006000024020100506200033C0280080000000D3B
+:100610003C02800890430004000010213063000F6A
+:1006200000031D0003E00008AC8300800004188074
+:100630002782FF9C00621821000410C00044102390
+:100640008C640000000210C03C030800246356E4E0
+:10065000004310213C038000AC64009003E00008DC
+:10066000AF8200243C0208008C42011410400019A3
+:100670003084400030A2007F000231C03C02020002
+:100680001080001400A218253C026020AC43001426
+:100690003C0408008C8456B83C0308008C630110AD
+:1006A0003C02800024050900AC4500200086202182
+:1006B000246300013C028008AC4400643C01080053
+:1006C000AC2301103C010800AC2456B803E000083C
+:1006D000000000003C02602003E00008AC4500146C
+:1006E00003E000080000102103E0000800001021D2
+:1006F00030A2000810400008240201003C0208005B
+:100700008C42010C244200013C010800AC22010C87
+:1007100003E0000800000000148200080000000050
+:100720003C0208008C4200FC244200013C0108000D
+:10073000AC2200FC0A0001A330A200203C02080009
+:100740008C420084244200013C010800AC22008459
+:1007500030A200201040000830A200103C02080027
+:100760008C420108244200013C010800AC2201082F
+:1007700003E0000800000000104000080000000036
+:100780003C0208008C420104244200013C010800A4
+:10079000AC22010403E00008000000003C02080055
+:1007A0008C420100244200013C010800AC220100FF
+:1007B00003E000080000000027BDFFE0AFB1001417
+:1007C0003C118000AFB20018AFBF001CAFB00010EA
+:1007D0003632010096500008320200041040000733
+:1007E000320300028FBF001C8FB200188FB10014BB
+:1007F0008FB000100A0000CE27BD00201060000B53
+:10080000020028218E2401000E00018A0000000051
+:100810003202008010400003240500A10E000C6786
+:100820008E44001C0A0001E3240200018E2301040F
+:100830008F82000810430006020028218E24010048
+:100840000E00018A000000008E220104AF82000821
+:10085000000010218FBF001C8FB200188FB1001450
+:100860008FB0001003E0000827BD00202C82000498
+:1008700014400002000018212483FFFD240200021E
+:10088000006210043C03600003E00008AC626914DD
+:1008900027BDFFE0AFBF001CAFB20018AFB100141E
+:1008A000AFB000103C048000948201083043700017
+:1008B000240220001062000A2862200154400052E5
+:1008C0008FBF001C24024000106200482402600018
+:1008D0001062004A8FBF001C0A0002518FB200183C
+:1008E00034820100904300098C5000189451000C90
+:1008F000240200091062001C0000902128620009F7
+:10090000144000218F8200242402000A5062001249
+:10091000323100FF2402000B1062000F00000000C3
+:100920002402000C146200188F8200243C0208008C
+:100930008C4256B824030900AC83002000501021DB
+:100940003C038008AC6200643C010800AC2256B84D
+:100950000A0002508FBF001C0E0001E900102602A1
+:100960000A0002308F8200240E0001E900102602E6
+:100970003C0380089462001A8C72000C3042FFFF26
+:10098000020280258F8200248C42000C5040001E01
+:100990008FBF001C0E000D84000000003C02800090
+:1009A00034420100944300088F82002400031C009D
+:1009B0009444001E8F82002000641825AC50000073
+:1009C00024040001AC510004AC520008AC40000CFF
+:1009D000AC400010AC400014AC4000180E000DB844
+:1009E000AC43001C0A0002508FBF001C0E000440E4
+:1009F000000000000A0002508FBF001C0E000C9F78
+:100A0000000000008FBF001C8FB200188FB10014CF
+:100A10008FB000100000102103E0000827BD002067
+:100A200027BDFFD8AFB400203C036010AFBF002447
+:100A3000AFB3001CAFB20018AFB10014AFB00010DC
+:100A40008C6450002402FF7F3C1408002694563822
+:100A5000008220243484380CAC6450003C028000B6
+:100A6000240300370E0014B0AC4300083C07080014
+:100A700024E70618028010212404001D2484FFFFAF
+:100A8000AC4700000481FFFD244200043C02080042
+:100A9000244207C83C010800AC2256403C02080032
+:100AA000244202303C030800246306203C04080072
+:100AB000248403B43C05080024A506F03C06080085
+:100AC00024C62C9C3C010800AC2256803C02080045
+:100AD000244205303C010800AC2756843C01080044
+:100AE000AC2656943C010800AC23569C3C010800FF
+:100AF000AC2456A03C010800AC2556A43C010800DB
+:100B0000AC2256A83C010800AC23563C3C0108002E
+:100B1000AC2456443C010800AC2056603C0108005F
+:100B2000AC2556643C010800AC2056703C0108001E
+:100B3000AC27567C3C010800AC2656903C010800CE
+:100B4000AC2356980E00056E00000000AF80000C2C
+:100B50003C0280008C5300008F8300043C0208009C
+:100B60008C420020106200213262000700008821C0
+:100B70002792FF9C3C100800261056E43C02080017
+:100B80008C42002024050001022518040043202483
+:100B90008F820004004310245044000C26310001D1
+:100BA00010800008AF9000248E4300003C028000BB
+:100BB000AC4300900E000D4BAE05000C0A0002C1C4
+:100BC00026310001AE00000C263100012E22000269
+:100BD000261000381440FFE9265200043C020800A9
+:100BE0008C420020AF820004326200071040FFD91F
+:100BF0003C028000326200011040002D326200028F
+:100C00003C0580008CA2010000002021ACA2002045
+:100C10008CA301042C42078110400008ACA300A85B
+:100C200094A2010824032000304270001443000302
+:100C30003C02800890420005304400FF0E0001593C
+:100C4000000000003C0280009042010B304300FF96
+:100C50002C62001E54400004000310800E00018628
+:100C60000A0002EC00000000005410218C42000039
+:100C70000040F80900000000104000043C02800021
+:100C80008C4301043C026020AC4300143C02080089
+:100C90008C4200343C0440003C03800024420001AC
+:100CA000AC6401383C010800AC220034326200021E
+:100CB00010400010326200043C1080008E0201409F
+:100CC000000020210E000159AE0200200E00038317
+:100CD000000000003C024000AE0201783C02080027
+:100CE0008C420038244200013C010800AC2200384C
+:100CF000326200041040FF973C0280003C108000EC
+:100D00008E020180000020210E000159AE02002059
+:100D10008E03018024020F00546200073C02800809
+:100D20008E0201883C0300E03042FFFF00431025A3
+:100D30000A000328AE020080344200809042000086
+:100D400024030050304200FF14430007000000005D
+:100D50000E000362000000001440000300000000C9
+:100D60000E000971000000003C0208008C42003CAB
+:100D70003C0440003C03800024420001AC6401B804
+:100D80003C010800AC22003C0A0002A33C028000A7
+:100D90003C02900034420001008220253C02800089
+:100DA000AC4400203C0380008C6200200440FFFE25
+:100DB0000000000003E00008000000003C0280008A
+:100DC000344300010083202503E00008AC440020E8
+:100DD00027BDFFE0AFB10014AFB000100080882144
+:100DE000AFBF00180E00033230B000FF8F83FF94B6
+:100DF000022020219062002502028025A07000259B
+:100E00008C7000183C0280000E00033D020280241A
+:100E10001600000B8FBF00183C0480008C8201F884
+:100E20000440FFFE348201C024030002AC510000E4
+:100E3000A04300043C021000AC8201F88FBF0018F0
+:100E40008FB100148FB0001003E0000827BD002010
+:100E500027BDFFE83C028000AFBF00103442018094
+:100E6000944300048C4400083063020010600005C5
+:100E7000000028210E00100C000000000A0003787A
+:100E8000240500013C02FF000480000700821824B2
+:100E90003C02040014620004240500018F82FF94C8
+:100EA00090420008240500018FBF001000A010210F
+:100EB00003E0000827BD00188F82FF982405000179
+:100EC000A040001A3C028000344201400A00034264
+:100ED0008C4400008F85FF9427BDFFE0AFBF001C4E
+:100EE000AFB20018AFB10014AFB0001090A2000074
+:100EF000304400FF38830020388200300003182B74
+:100F00000002102B0062182410600003240200501D
+:100F1000148200A88FBF001C90A20005304200017F
+:100F2000104000A48FBF001C3C02800034420140EE
+:100F3000904200082443FFFF2C6200051040009EF1
+:100F40008FB20018000310803C030800246355ACE6
+:100F5000004310218C420000004000080000000007
+:100F60003C028000345101400E0003328E24000008
+:100F70008F92FF948E2200048E50000C1602000205
+:100F800024020001AE42000C0E00033D8E2400003E
+:100F90008E220004145000068FBF001C8FB2001870
+:100FA0008FB100148FB000100A000F7827BD002009
+:100FB0008E42000C0A000419000000003C0480006E
+:100FC0003482014094A300108C4200043063FFFF80
+:100FD0001443001C0000000024020001A4A2001021
+:100FE0008C8202380441000F3C0380003C02003F29
+:100FF0003448F0003C0760003C06FFC08CE22BBC8C
+:1010000000461824004810240002130200031D8229
+:10101000106200583C0280008C8202380440FFF7C6
+:101020003C038000346201408C44000034620200C2
+:10103000AC4400003C021000AC6202380A00043BE1
+:101040008FBF001C94A200100A00041900000000C9
+:10105000240200201482000F3C0280003C03800028
+:1010600094A20012346301408C6300043042FFFFFD
+:10107000146200050000000024020001A4A2001276
+:101080000A0004028FBF001C94A200120A00041977
+:1010900000000000345101400E0003328E24000095
+:1010A0008F92FF948E230004964200123050FFFF6F
+:1010B0001603000224020001A64200120E00033DA6
+:1010C0008E2400008E220004160200068FBF001C32
+:1010D0008FB200188FB100148FB000100A00037C8B
+:1010E00027BD0020964200120A00041900000000EB
+:1010F0003C03800094A20014346301408C6300041C
+:101100003042FFFF14620008240200018FBF001C60
+:101110008FB200188FB100148FB00010A4A2001479
+:101120000A00146327BD002094A20014144000217B
+:101130008FBF001C0A000435000000003C03800043
+:1011400094A20016346301408C6300043042FFFF18
+:101150001462000D240200018FBF001C8FB2001822
+:101160008FB100148FB00010A4A200160A000B1457
+:1011700027BD00209442007824420004A4A200105D
+:101180000A00043B8FBF001C94A200162403000138
+:101190003042FFFF144300078FBF001C3C020800D1
+:1011A0008C420070244200013C010800AC22007017
+:1011B0008FBF001C8FB200188FB100148FB00010C9
+:1011C00003E0000827BD002027BDFFD8AFB20018FC
+:1011D0008F92FF94AFB10014AFBF0020AFB3001CDB
+:1011E000AFB000103C028000345101008C5001006F
+:1011F0009242000092230009304400FF2402001FA5
+:10120000106200AB28620020104000192402003850
+:101210002862000A1040000D2402000B286200081A
+:101220001040002E8F820024046001042862000216
+:101230001440002A8F820024240200061062002637
+:101240008FBF00200A00055F8FB3001C1062006092
+:101250002862000B144000FA8FBF00202402000E09
+:10126000106200788F8200240A00055F8FB3001C93
+:10127000106200D2286200391040000A2402008067
+:1012800024020036106200E528620037104000C3D7
+:1012900024020035106200D98FBF00200A00055FCC
+:1012A0008FB3001C1062002D2862008110400006E0
+:1012B000240200C824020039106200C98FBF002038
+:1012C0000A00055F8FB3001C106200A28FBF0020D0
+:1012D0000A00055F8FB3001C8F8200248C42000C33
+:1012E000104000D78FBF00200E000D8400000000CA
+:1012F0003C038000346301008C6200008F85002075
+:10130000946700089466000CACA200008C64000492
+:101310008F82002400063400ACA400049448001E10
+:101320008C62001800073C0000E83825ACA20008D9
+:101330008C62001C24040001ACA2000C9062000A24
+:1013400000C23025ACA60010ACA00014ACA0001860
+:10135000ACA7001C0A00051D8FBF00208F8200244F
+:101360008C42000C104000B68FBF00200E000D8490
+:10137000000000008F820024962400089625000CAF
+:101380009443001E000422029626000E8F82002045
+:10139000000426000083202500052C003C0300806B
+:1013A00000A6282500832025AC400000AC400004A6
+:1013B000AC400008AC40000CAC450010AC40001440
+:1013C000AC400018AC44001C0A00051C24040001B9
+:1013D0009622000C14400018000000009242000504
+:1013E0003042001014400014000000000E000332D0
+:1013F0000200202192420005020020213442001008
+:101400000E00033DA242000592420000240300208A
+:10141000304200FF10430089020020218FBF0020CE
+:101420008FB3001C8FB200188FB100148FB0001062
+:101430000A00107527BD00280000000D0A00055E97
+:101440008FBF00208C42000C1040007D8FBF002019
+:101450000E000D84000000008E2200048F84002006
+:101460009623000CAC8200003C0280089445002CBE
+:101470008F82002400031C0030A5FFFF9446001E4D
+:101480003C02400E0065182500C23025AC830004E4
+:10149000AC800008AC80000CAC800010AC80001464
+:1014A000AC800018AC86001C0A00051C2404000156
+:1014B0000E000332020020218F93FF9802002021AA
+:1014C0000E00033DA660000C020020210E00034226
+:1014D000240500018F8200248C42000C104000582B
+:1014E0008FBF00200E000D84000000009622000C2B
+:1014F0008F83002000021400AC700000AC62000476
+:10150000AC6000088E4400388F820024AC64000C6C
+:101510008E46003C9445001E3C02401FAC66001005
+:1015200000A228258E62000424040001AC6200148D
+:10153000AC600018AC65001C8FBF00208FB3001C8E
+:101540008FB200188FB100148FB000100A000DB8D0
+:1015500027BD0028240200201082003A8FB3001C0F
+:101560000E000F5E00000000104000358FBF00200D
+:101570003C0480008C8201F80440FFFE348201C0EC
+:1015800024030002AC500000A04300043C02100001
+:10159000AC8201F80A00055E8FBF00200200202106
+:1015A0008FBF00208FB3001C8FB200188FB10014C2
+:1015B0008FB000100A000EA727BD00289625000C4A
+:1015C000020020218FBF00208FB3001C8FB20018B3
+:1015D0008FB100148FB000100A000ECC27BD002878
+:1015E000020020218FB3001C8FB200188FB10014AD
+:1015F0008FB000100A000EF727BD00289225000DBD
+:10160000020020218FB3001C8FB200188FB100148C
+:101610008FB000100A000F4827BD002802002021CB
+:101620008FBF00208FB3001C8FB200188FB1001441
+:101630008FB000100A000F1F27BD00288FBF0020A9
+:101640008FB3001C8FB200188FB100148FB0001040
+:1016500003E0000827BD00283C0580008CA202782A
+:101660000440FFFE34A2024024030002AC44000008
+:10167000A04300043C02100003E00008ACA2027882
+:10168000A380001803E00008A38000193C03800039
+:101690008C6202780440FFFE8F82001CAC62024024
+:1016A00024020002A06202443C02100003E0000891
+:1016B000AC6202783C02600003E000088C425404F3
+:1016C0009083003024020005008040213063003FF9
+:1016D0000000482114620005000050219082004C57
+:1016E0009483004E304900FF306AFFFFAD00000CCC
+:1016F000AD000010AD000024950200148D05001C03
+:101700008D0400183042FFFF004910230002110031
+:10171000000237C3004038210086202300A2102B8E
+:101720000082202300A72823AD05001CAD0400186B
+:10173000A5090014A5090020A50A001603E0000869
+:10174000A50A002203E000080000000027BDFFD822
+:10175000AFB200183C128008AFB40020AFB3001C39
+:10176000AFB10014AFBF0024AFB00010365101007C
+:101770003C0260008C4254049222000C3C1408008D
+:10178000929400F7304300FF2402000110620032FF
+:101790000080982124020002146200353650008037
+:1017A0000E00143D000000009202004C2403FF8054
+:1017B0003C0480003042007F000211C024420240FD
+:1017C0000262102100431824AC8300949245000863
+:1017D0009204004C3042007F3C03800614850007D1
+:1017E000004380212402FFFFA22200112402FFFFF8
+:1017F000A62200120A0005D22402FFFF9602002052
+:10180000A222001196020022A62200128E020024BB
+:101810003C048008AE2200143485008090A2004C65
+:1018200034830100A06200108CA2003CAC6200185E
+:101830008C820068AC6200F48C820064AC6200F0C0
+:101840008C82006CAC6200F824020001A0A2006847
+:101850000A0005EE3C0480080E001456000000004B
+:1018600036420080A04000680A0005EE3C04800873
+:10187000A2000068A20000690A0006293C02800854
+:10188000348300808C62003834850100AC62006CC7
+:1018900024020001A062006990A200D59083000894
+:1018A000305100FF3072007F12320019001111C058
+:1018B00024420240026210212403FF8000431824C6
+:1018C0003C048000AC8300943042007F3C038006DF
+:1018D000004380218E02000C1040000D02002021E8
+:1018E0000E00057E0000000026220001305100FF9E
+:1018F0009203003C023410260002102B0002102339
+:101900003063007F022288240A0005F8A203003C0D
+:101910003C088008350401008C8200E03507008017
+:10192000ACE2003C8C8200E0AD02000090E5004C8F
+:10193000908600D590E3004C908400D52402FF806F
+:1019400000A228243063007F308400FF00A62825F1
+:101950000064182A1060000230A500FF38A500803E
+:10196000A0E5004CA10500093C0280089043000E50
+:10197000344400803C058000A043000A8C8300189A
+:101980003C027FFF3442FFFF00621824AC83001842
+:101990008CA201F80440FFFE00000000ACB301C0BF
+:1019A0008FBF00248FB400208FB3001C8FB20018AB
+:1019B0008FB100148FB0001024020002A0A201C455
+:1019C00027BD00283C02100003E00008ACA201F88B
+:1019D00090A2000024420001A0A200003C030800E5
+:1019E0008C6300F4304200FF144300020080302179
+:1019F000A0A0000090A200008F84001C000211C073
+:101A00002442024024830040008220212402FF80DF
+:101A1000008220243063007F3C02800A006218218B
+:101A20003C028000AC44002403E00008ACC300008A
+:101A300094820006908300058C85000C8C86001033
+:101A40008C8700188C88001C8C8400203C010800C6
+:101A5000A42256C63C010800A02356C53C0108003C
+:101A6000AC2556CC3C010800AC2656D03C01080001
+:101A7000AC2756D83C010800AC2856DC3C010800D5
+:101A8000AC2456E003E00008000000003C0280089F
+:101A9000344201008C4400343C038000346504006F
+:101AA000AC6400388C420038AF850028AC62003C42
+:101AB0003C020005AC6200300000000000000000A5
+:101AC00003E00008000000003C020006308400FF34
+:101AD000008220253C028000AC4400300000000061
+:101AE00000000000000000003C0380008C62000049
+:101AF000304200101040FFFD3462040003E0000893
+:101B0000AF82002894C200003C080800950800CA73
+:101B100030E7FFFF0080482101021021A4C200002D
+:101B200094C200003042FFFF00E2102B544000013D
+:101B3000A4C7000094A200003C0308008C6300CC02
+:101B400024420001A4A2000094A200003042FFFF42
+:101B5000144300073C0280080107102BA4A00000DA
+:101B60005440000101003821A4C700003C02800855
+:101B7000344601008CC3002894A200003C0480007D
+:101B80003042FFFE000210C000621021AC82003C17
+:101B90008C82003C006218231860000400000000E2
+:101BA0008CC200240A0006BA244200018CC2002420
+:101BB000AC8200383C020050344200103C038000EC
+:101BC000AC620030000000000000000000000000D7
+:101BD0008C620000304200201040FFFD0000000039
+:101BE00094A200003C04800030420001000210C0BA
+:101BF000004410218C430400AD2300008C420404F7
+:101C0000AD2200043C02002003E00008AC8200305A
+:101C100027BDFFE0AFB20018AFB10014AFB00010A5
+:101C2000AFBF001C94C2000000C080213C1208001D
+:101C3000965200C624420001A6020000960300004E
+:101C400094E2000000E03021144300058FB1003021
+:101C50000E00068F024038210A0006F10000000045
+:101C60008C8300048C82000424420040046100073D
+:101C7000AC8200048C8200040440000400000000D8
+:101C80008C82000024420001AC8200009602000019
+:101C90003042FFFF50520001A600000096220000D3
+:101CA00024420001A62200003C02800834420100C8
+:101CB000962300009442003C144300048FBF001C94
+:101CC00024020001A62200008FBF001C8FB2001862
+:101CD0008FB100148FB0001003E0000827BD002072
+:101CE00027BDFFE03C028008AFBF0018344201006E
+:101CF0008C4800343C03800034690400AC68003830
+:101D00008C42003830E700FFAF890028AC62003C0D
+:101D10003C020005AC620030000000000000000042
+:101D200000000000000000000000000000000000B3
+:101D30008C82000C8C82000C97830016AD22000070
+:101D40008C82001000604021AD2200048C820018BB
+:101D5000AD2200088C82001CAD22000C8CA2001465
+:101D6000AD2200108C820020AD220014908200056C
+:101D7000304200FF00021200AD2200188CA20018B1
+:101D8000AD22001C8CA2000CAD2200208CA2001001
+:101D9000AD2200248CA2001CAD2200288CA20020C1
+:101DA000AD22002C3402FFFFAD260030AD20003400
+:101DB000506200013408FFFFAD28003850E00011E8
+:101DC0003C0280083C048008348401009482005066
+:101DD0003042FFFFAD22003C9483004494850044D0
+:101DE000240200013063FFFF000318C200641821C1
+:101DF0009064006430A5000700A210040A00075C8C
+:101E00000044102534420100AD20003C94430044BE
+:101E1000944400443063FFFF000318C2006218219D
+:101E200030840007906500642402000100821004E1
+:101E30000002102700451024A0620064000000008A
+:101E400000000000000000003C0200063442004098
+:101E50003C038000AC620030000000000000000085
+:101E6000000000008C620000304200101040FFFDB6
+:101E70003C06800834C201503463040034C7014A70
+:101E800034C4013434C5014034C60144AFA200104B
+:101E90000E0006D2AF8300288FBF001803E00008B1
+:101EA00027BD00208F8300143C0608008CC600E884
+:101EB0008F82001C30633FFF000319800046102111
+:101EC000004310212403FF80004318243C068000B7
+:101ED000ACC300283042007F3C03800C004330211B
+:101EE00090C2000D30A500FF0000382134420010E0
+:101EF000A0C2000D8F8900143C028008344201000A
+:101F00009443004400091382304800032402000176
+:101F1000A4C3000E1102000B2902000210400005AC
+:101F2000240200021100000C240300010A0007A48F
+:101F30000000182111020006000000000A0007A49A
+:101F4000000018218CC2002C0A0007A424430001C1
+:101F50008CC20014244300018CC200180043102BD3
+:101F60005040000A240700012402002714A20003A5
+:101F70003C0380080A0007B1240700013463010014
+:101F80009462004C24420001A462004C00091382B8
+:101F9000304300032C620002104000090080282119
+:101FA000146000040000000094C200340A0007C15D
+:101FB0003046FFFF8CC600380A0007C10080282188
+:101FC000000030213C040800248456C00A000706A3
+:101FD0000000000027BDFF90AFB60068AFB50064F9
+:101FE000AFB40060AFB3005CAFB20058AFB1005403
+:101FF000AFBF006CAFB000508C9000000080B021EB
+:102000003C0208008C4200E8960400328F83001CDA
+:102010002414FF8030843FFF0062182100042180D7
+:1020200000641821007410243C13800000A090214B
+:1020300090A50000AE620028920400323C02800CA1
+:102040003063007F00628821308400C02402004099
+:10205000148200320000A8218E3500388E2200182C
+:102060001440000224020001AE2200189202003C3B
+:10207000304200201440000E8F83001C000511C068
+:102080002442024000621821306400783C02008043
+:102090000082202500741824AE630800AE64081086
+:1020A0008E2200188E03000800431021AE22001873
+:1020B0008E22002C8E230018244200010062182B6F
+:1020C0001060004300000000924200002442000122
+:1020D000A24200003C0308008C6300F4304200FF81
+:1020E00050430001A2400000924200008F84001C77
+:1020F000000211C024420240248300403063007F6C
+:10210000008220213C02800A0094202400621821D1
+:10211000AE6400240A0008D2AEC30000920300326D
+:102120002402FFC000431024304200FF1440000589
+:1021300024020001AE220018962200340A00084250
+:102140003055FFFF8E22001424420001AE220018F9
+:102150009202003000021600000216030441001C27
+:10216000000000009602003227A400100080282101
+:10217000A7A20016960200320000302124070001B9
+:102180003042FFFFAF8200140E000706AFA0001C14
+:10219000960200328F83001C3C0408008C8400E807
+:1021A00030423FFF000211800064182100621821B4
+:1021B00000741024AE62002C3063007F3C02800E5D
+:1021C000006218219062000D3042007FA062000D75
+:1021D0009222000D304200105040007892420000E0
+:1021E0003C028008344401009482004C8EC30000FD
+:1021F0003C130800967300C62442FFFFA482004CE3
+:10220000946200329623000E3054FFFF3070FFFFBF
+:102210003C0308008C6300D000701807A7A30038A7
+:102220009482003E3063FFFF3042FFFF14620007DC
+:10223000000000008C8200303C038000244200300B
+:10224000AC62003C0A00086A8C82002C9482004038
+:102250003042FFFF5462000927A400408C820038FE
+:102260003C03800024420030AC62003C8C8200348D
+:10227000AC6200380A0008793C03800027A50038CA
+:1022800027A60048026038210E00068FA7A000484C
+:102290008FA300403C02800024630030AC43003830
+:1022A0008FA30044AC43003C3C0380003C0200058B
+:1022B000AC6200303C028008344401009482004249
+:1022C000346304003042FFFF0202102B1440000769
+:1022D000AF8300289482004E9483004202021021B2
+:1022E000004310230A00088F3043FFFF9483004E01
+:1022F00094820042026318210050102300621823C8
+:102300003063FFFF3C028008344401009482003CAB
+:102310003042FFFF14430003000000000A00089F42
+:10232000240300019482003C3042FFFF0062102B26
+:10233000144000058F8200289482003C0062102324
+:102340003043FFFF8F820028AC550000AC400004F2
+:10235000AC540008AC43000C3C02000634420010B0
+:102360003C038000AC620030000000000000000070
+:10237000000000008C620000304200101040FFFDA1
+:102380003C04800834840100001018C20064182145
+:102390009065006432020007240600010046100424
+:1023A00000451025A0620064948300429622000E2E
+:1023B00050430001A386001892420000244200010D
+:1023C000A24200003C0308008C6300F4304200FF8E
+:1023D00050430001A2400000924200008F84001C84
+:1023E000000211C0244202402483004000822021C8
+:1023F0002402FF80008220243063007F3C02800A98
+:10240000006218213C028000AC440024AEC30000EE
+:102410008FBF006C8FB600688FB500648FB400600A
+:102420008FB3005C8FB200588FB100548FB0005052
+:1024300003E0000827BD007027BDFFD8AFB3001C24
+:10244000AFB20018AFB10014AFB00010AFBF0020A2
+:102450000080982100E0802130B1FFFF0E000D8444
+:1024600030D200FF0000000000000000000000006B
+:102470008F8200208F830024AC510000AC520004F6
+:10248000AC530008AC40000CAC400010AC40001451
+:10249000AC4000189463001E02038025AC50001C61
+:1024A0000000000000000000000000002404000103
+:1024B0008FBF00208FB3001C8FB200188FB10014A3
+:1024C0008FB000100A000DB827BD002830A5FFFF0F
+:1024D0000A0008DC30C600FF3C02800834430100DB
+:1024E0009462000E3C080800950800C63046FFFFC5
+:1024F00014C000043402FFFF946500EA0A000929B1
+:102500008F84001C10C20027000000009462004E5F
+:102510009464003C3045FFFF00A6102300A6182B52
+:102520003087FFFF106000043044FFFF00C5102318
+:1025300000E210233044FFFF0088102B1040000EF3
+:1025400000E810233C028008344401002403000109
+:1025500034420080A44300162402FFFFA482000E30
+:10256000948500EA8F84001C0000302130A5FFFF15
+:102570000A0009013C0760200044102A10400009AD
+:102580003C0280083443008094620016304200010F
+:10259000104000043C0280009442007E244200145B
+:1025A000A462001603E000080000000027BDFFE061
+:1025B0003C028008AFBF001CAFB0001834420100DD
+:1025C000944300429442004C104000193068FFFFD1
+:1025D0009383001824020001146200298FBF001C9D
+:1025E0003C06800834D00100000810C200501021C1
+:1025F000904200643103000734C70148304200FFB5
+:10260000006210073042000134C9014E34C4012C6D
+:1026100034C5013E1040001634C601420E0006D2F9
+:10262000AFA90010960200420A0009463048FFFF99
+:102630003C028008344401009483004494820042A8
+:102640001043000F8FBF001C94820044A4820042FC
+:1026500094820050A482004E8C820038AC820030FC
+:1026600094820040A482003E9482004AA4820048E2
+:102670008FBF001C8FB000180A00090427BD00207E
+:102680008FB0001803E0000827BD002027BDFFA081
+:10269000AFB1004C3C118000AFBF0058AFB3005445
+:1026A000AFB20050AFB000483626018890C2000398
+:1026B0003044007FA3A400108E32018090C200003D
+:1026C0003043007F240200031062003BAF92001CE5
+:1026D00028620004104000062402000424020002C4
+:1026E000106200098FBF00580A000B0F8FB300540F
+:1026F0001062004D240200051062014E8FBF005889
+:102700000A000B0F8FB30054000411C002421021C5
+:102710002404FF8024420240004410242643004049
+:10272000AE2200243063007F3C02800A0062182140
+:102730009062003CAFA3003C00441025A062003C26
+:102740008FA3003C9062003C304200401040016C7E
+:102750008FBF00583C108008A3800018361001007D
+:102760008E0200E08C63003427A4003C27A50010F3
+:10277000004310210E0007C3AE0200E093A2001038
+:102780003C038000A20200D58C6202780440FFFE68
+:102790008F82001CAC62024024020002A06202444C
+:1027A0003C021000AC6202780E0009390000000003
+:1027B0000A000B0E8FBF00583C05800890C3000133
+:1027C00090A2000B1443014E8FBF005834A4008028
+:1027D0008C8200189082004C90A200083C0260009D
+:1027E0008C4254048C8300183C027FFF3442FFFF6C
+:1027F000006218243C0208008C4200B4AC8300182C
+:102800003C038000244200013C010800AC2200B4DB
+:102810008C6201F80440FFFE8F82001CAC6201C094
+:102820000A000AD6240200023C10800890C300016E
+:102830009202000B144301328FBF005827A40018E6
+:1028400036050110240600033C0260008C4254044B
+:102850000E000E470000000027A40028360501F0F6
+:102860000E000E47240600038FA200283603010045
+:10287000AE0200648FA2002CAE0200688FA200306E
+:10288000AE02006C93A40018906300D52402FF8070
+:102890000082102400431025304900FF3084007F5F
+:1028A0003122007F0082102A544000013929008023
+:1028B000000411C0244202402403FF800242102180
+:1028C00000431024AE220094264200403042007F94
+:1028D0003C038006004340218FA3001C2402FFFF1D
+:1028E000AFA800403C130800927300F71062003359
+:1028F00093A2001995030014304400FF3063FFFFDA
+:102900000064182B106000100000000095040014F3
+:102910008D07001C8D0600183084FFFF0044202323
+:102920000004210000E438210000102100E4202BE5
+:1029300000C2302100C43021AD07001CAD060018D4
+:102940000A000A2F93A20019950400148D07001C99
+:102950008D0600183084FFFF008220230004210030
+:10296000000010210080182100C2302300E4202B39
+:1029700000C4302300E33823AD07001CAD06001867
+:1029800093A200198FA30040A462001497A2001A1A
+:10299000A46200168FA2001CAC6200108FA2001C63
+:1029A000AC62000C93A20019A462002097A2001A46
+:1029B000A46200228FA2001CAC6200243C048008A8
+:1029C000348300808C6200388FA20020012088218F
+:1029D000AC62003C8FA20020AC82000093A20018E1
+:1029E000A062004C93A20018A0820009A0600068B9
+:1029F00093A20018105100512407FF803229007F54
+:102A0000000911C024420240024210213046007FDA
+:102A10003C03800000471024AC6200943C02800616
+:102A200000C2302190C2003CAFA60040000020212F
+:102A300000471025A0C2003C8FA80040950200026C
+:102A4000950300148D07001C3042FFFF3063FFFF29
+:102A50008D060018004310230002110000E2382107
+:102A600000E2102B00C4302100C23021AD07001C51
+:102A7000AD06001895020002A5020014A50000167C
+:102A80008D020008AD0200108D020008AD02000C9E
+:102A900095020002A5020020A50000228D02000878
+:102AA000AD0200249102003C304200401040001A68
+:102AB000262200013C108008A3A90038A38000183A
+:102AC000361001008E0200E08D03003427A4004080
+:102AD00027A50038004310210E0007C3AE0200E016
+:102AE00093A200383C038000A20200D58C620278D9
+:102AF0000440FFFE8F82001CAC62024024020002F0
+:102B0000A06202443C021000AC6202780E00093957
+:102B100000000000262200013043007F14730004EF
+:102B2000004020212403FF8002231024004320269C
+:102B300093A200180A000A4B309100FF93A40018DA
+:102B40008FA3001C2402FFFF1062000A308900FFDF
+:102B500024820001248300013042007F14530005C9
+:102B6000306900FF2403FF800083102400431026F7
+:102B7000304900FF3C028008904200080120882173
+:102B8000305000FF123000193222007F000211C0C5
+:102B900002421021244202402403FF8000431824F3
+:102BA0003C048000AC8300943042007F3C038006EC
+:102BB000004310218C43000C004020211060000BCA
+:102BC000AFA200400E00057E000000002623000199
+:102BD0002405FF803062007F145300020225202468
+:102BE000008518260A000AAF307100FF3C048008F7
+:102BF000348400808C8300183C027FFF3442FFFF46
+:102C000000621824AC8300183C0380008C6201F839
+:102C10000440FFFE00000000AC7201C0240200026C
+:102C2000A06201C43C021000AC6201F80A000B0E65
+:102C30008FBF00583C04800890C300019082000BB5
+:102C40001443002F8FBF0058349000809202000878
+:102C500030420040104000200000000092020008B6
+:102C60000002160000021603044100050240202164
+:102C70000E000ECC240500930A000B0E8FBF0058E7
+:102C80009202000924030018304200FF1443000D93
+:102C900002402021240500390E000E64000030217E
+:102CA0000E0003328F84001C8F82FF9424030012D5
+:102CB000A04300090E00033D8F84001C0A000B0E88
+:102CC0008FBF0058240500360E000E64000030212E
+:102CD0000A000B0E8FBF00580E0003320240202165
+:102CE000920200058F84001C344200200E00033D38
+:102CF000A20200050E0010758F84001C8FBF0058C3
+:102D00008FB300548FB200508FB1004C8FB0004889
+:102D100003E0000827BD00603C0280083445010044
+:102D20003C0280008C42014094A3000E0000302140
+:102D300000402021AF82001C3063FFFF3402FFFF00
+:102D4000106200063C0760202402FFFFA4A2000ED0
+:102D500094A500EA0A00090130A5FFFF03E000087E
+:102D60000000000027BDFFC83C0280003C06800830
+:102D7000AFB5002CAFB1001CAFBF0030AFB400281E
+:102D8000AFB30024AFB20020AFB00018345101003F
+:102D900034C501008C4301008E2200148CA400E491
+:102DA0000000A821AF83001C0044102318400052EB
+:102DB000A38000188E22001400005021ACA200E471
+:102DC00090C3000890A200D53073007FA3A200102A
+:102DD0008CB200E08CB400E4304200FF1053003BA2
+:102DE00093A200108F83001C2407FF80000211C0F3
+:102DF0000062102124420240246300400047102456
+:102E00003063007F3C0980003C08800A006818217C
+:102E1000AD2200248C62003427A4001427A50010E2
+:102E2000024280210290102304400028AFA3001426
+:102E30009062003C00E21024304200FF1440001970
+:102E4000020090219062003C34420040A062003CAD
+:102E50008F86001C93A3001024C200403042007FE4
+:102E6000004828213C0208008C4200F42463000141
+:102E7000306400FF14820002A3A30010A3A000107E
+:102E800093A20010AFA50014000211C0244202401A
+:102E900000C2102100471024AD2200240A000B4577
+:102EA00093A200100E0007C3000000003C0280083F
+:102EB00034420100AC5000E093A30010240A00014A
+:102EC000A04300D50A000B4593A200102402000184
+:102ED000154200093C0380008C6202780440FFFE2A
+:102EE0008F82001CAC62024024020002A0620244F5
+:102EF0003C021000AC6202789222000B2403000214
+:102F0000304200FF144300720000000096220008C7
+:102F1000304300FF24020082146200402402008437
+:102F20003C028000344901008D22000C95230006EC
+:102F3000000216023063FFFF3045003F24020027E5
+:102F400010A2000FAF83001428A200281040000830
+:102F5000240200312402002110A2000924020025CD
+:102F600010A20007938200190A000BBD00000000A8
+:102F700010A20007938200190A000BBD0000000098
+:102F80000E000777012020210A000C3D0000000000
+:102F90003C0380008C6202780440FFFE8F82001C9C
+:102FA000AC62024024020002A06202443C02100013
+:102FB000AC6202780A000C3D000000009523000678
+:102FC000912400058D25000C8D2600108D270018FA
+:102FD0008D28001C8D290020244200013C0108009E
+:102FE000A42356C63C010800A02456C53C01080095
+:102FF000AC2556CC3C010800AC2656D03C0108005C
+:10300000AC2756D83C010800AC2856DC3C0108002F
+:10301000AC2956E00A000C3DA38200191462000A94
+:10302000240200813C02800834420100944500EAF9
+:10303000922600058F84001C30A5FFFF30C600FFDC
+:103040000A000BFE3C0760211462005C00000000D7
+:103050009222000A304300FF306200201040000737
+:10306000306200403C02800834420100944500EA8E
+:103070008F84001C0A000BFC24060040104000074F
+:10308000000316003C02800834420100944500EA27
+:103090008F84001C0A000BFC24060041000216036A
+:1030A000044100463C02800834420100944500EA95
+:1030B0008F84001C2406004230A5FFFF3C076019E6
+:1030C0000E000901000000000A000C3D0000000095
+:1030D0009222000B24040016304200FF1044000628
+:1030E0003C0680009222000B24030017304200FFB0
+:1030F000144300320000000034C5010090A2000B10
+:10310000304200FF1444000B000080218CA20020FC
+:103110008CA400202403FF800043102400021140EF
+:103120003084007F004410253C032000004310251C
+:10313000ACC2083094A2000800021400000214037C
+:10314000044200012410000194A2000830420080D3
+:103150005040001A0200A82194A20008304220002A
+:10316000504000160200A8218CA300183C021C2D20
+:10317000344219ED106200110200A8213C0208003F
+:103180008C4200D4104000053C0280082403000457
+:1031900034420100A04300FC3C028008344201009C
+:1031A000944500EA8F84001C2406000630A5FFFF2A
+:1031B0000E0009013C0760210200A8210E00093918
+:1031C000000000009222000A304200081040000473
+:1031D00002A010210E0013790000000002A01021AF
+:1031E0008FBF00308FB5002C8FB400288FB3002420
+:1031F0008FB200208FB1001C8FB0001803E00008D0
+:1032000027BD00382402FF80008220243C02900069
+:1032100034420007008220253C028000AC4400209C
+:103220003C0380008C6200200440FFFE0000000090
+:1032300003E00008000000003C0380002402FF803F
+:10324000008220243462000700822025AC64002024
+:103250008C6200200440FFFE0000000003E0000834
+:103260000000000027BDFFD8AFB3001CAFB10014B1
+:10327000AFB00010AFBF0020AFB200183C1180000B
+:103280003C0280088E32002034530100AE2400201E
+:10329000966300EA000514003C074000004738250B
+:1032A00000A08021000030210E0009013065FFFFE1
+:1032B000240200A1160200022402FFFFA2620009FC
+:1032C000AE3200208FBF00208FB3001C8FB20018D9
+:1032D0008FB100148FB0001003E0000827BD002854
+:1032E0003C0280082403000527BDFFE834420100AA
+:1032F000A04300FCAFBF00103C0280008C420100E4
+:10330000240500A1004020210E000C67AF82001CA4
+:103310003C0380008C6202780440FFFE8F82001C18
+:103320008FBF001027BD0018AC62024024020002CB
+:10333000A06202443C021000AC62027803E0000884
+:103340000000000027BDFFE83C068000AFBF001072
+:1033500034C7010094E20008304400FF3883008243
+:10336000388200842C6300012C4200010062182581
+:103370001060002D24020083938200195040003B0E
+:103380008FBF00103C020800904256CC8CC4010054
+:103390003C06080094C656C63045003F38A30032AC
+:1033A00038A2003F2C6300012C4200010062182566
+:1033B000AF84001CAF860014A380001914600007BE
+:1033C00000E020212402002014A2001200000000CE
+:1033D0003402FFFF14C2000F00000000240200208E
+:1033E00014A2000500E028218CE300142402FFFF52
+:1033F0005062000B8FBF00103C040800248456C0AC
+:10340000000030210E000706240700010A000CD638
+:103410008FBF00100E000777000000008FBF001064
+:103420000A00093927BD001814820004240200850F
+:103430008CC501040A000CE1000020211482000662
+:103440002482FF808CC50104240440008FBF00103B
+:103450000A00016727BD0018304200FF2C4200021D
+:1034600010400004240200228FBF00100A000B2726
+:1034700027BD0018148200048F8200248FBF001023
+:103480000A000C8627BD00188C42000C1040001E5C
+:1034900000E0282190E300092402001814620003D0
+:1034A000240200160A000CFC240300081462000722
+:1034B00024020017240300123C02800834420080DA
+:1034C000A04300090A000D0994A7000854620007F0
+:1034D00094A700088F82FF942404FFFE9043000508
+:1034E00000641824A043000594A7000890A6001BC0
+:1034F0008CA4000094A500068FBF001000073C00BC
+:103500000A0008DC27BD00188FBF001003E0000888
+:1035100027BD00188F8500243C04800094A2002A57
+:103520008CA30034000230C02402FFF000C210243B
+:1035300000621821AC83003C8CA200303C03800068
+:10354000AC8200383C02005034420010AC620030C3
+:103550000000000000000000000000008C6200007D
+:10356000304200201040FFFD30C20008104000062D
+:103570003C0280008C620408ACA200208C62040C27
+:103580000A000D34ACA200248C430400ACA300203C
+:103590008C420404ACA200243C0300203C028000C6
+:1035A000AC4300303C0480008C8200300043102487
+:1035B0001440FFFD8F8600243C020040AC820030A6
+:1035C00094C3002A94C2002894C4002C94C5002EF1
+:1035D00024630001004410213064FFFFA4C20028CE
+:1035E00014850002A4C3002AA4C0002A03E0000836
+:1035F000000000008F84002427BDFFE83C05800404
+:1036000024840010AFBF00100E000E472406000AED
+:103610008F840024948200129483002E3042000F85
+:10362000244200030043180424027FFF0043102BB0
+:1036300010400002AC8300000000000D0E000D13CE
+:10364000000000008F8300248FBF001027BD0018EA
+:10365000946200149463001A3042000F00021500B7
+:10366000006218253C02800003E00008AC4300A083
+:103670008F8300243C028004944400069462001A64
+:103680008C650000A4640016004410233042FFFF44
+:103690000045102B03E00008384200018F8400240D
+:1036A0003C0780049486001A8C85000094E2000692
+:1036B000A482001694E3000600C310233042FFFFEB
+:1036C0000045102B384200011440FFF8A483001677
+:1036D00003E00008000000008F8400243C02800406
+:1036E000944200069483001A8C850000A482001680
+:1036F000006210233042FFFF0045102B38420001CA
+:103700005040000D8F850024006030213C0780046C
+:1037100094E20006A482001694E3000600C310237E
+:103720003042FFFF0045102B384200011440FFF8E3
+:10373000A48300168F8500243C03800034620400BB
+:103740008CA40020AF820020AC6400388CA200243E
+:10375000AC62003C3C020005AC62003003E00008B3
+:10376000ACA000048F8400243C0300068C8200047B
+:1037700000021140004310253C038000AC62003081
+:103780000000000000000000000000008C6200004B
+:10379000304200101040FFFD34620400AC80000491
+:1037A00003E00008AF8200208F86002427BDFFE0E1
+:1037B000AFB10014AFB00010AFBF00188CC300044D
+:1037C0008CC500248F820020309000FF94C4001A22
+:1037D00024630001244200202484000124A7002047
+:1037E000ACC30004AF820020A4C4001AACC70024FC
+:1037F00004A100060000882104E2000594C2001A1A
+:103800008CC2002024420001ACC2002094C2001AE5
+:1038100094C300282E040001004310262C4200010E
+:10382000004410245040000594C2001A24020001F4
+:10383000ACC2000894C2001A94C300280010202BC8
+:10384000004310262C4200010044102514400007BC
+:10385000000000008CC20008144000042402001084
+:103860008CC300041462000F8F8500240E000DA786
+:10387000241100018F820024944300289442001AEE
+:1038800014430003000000000E000D1300000000B0
+:10389000160000048F8500240E000D840000000037
+:1038A0008F85002494A2001E94A4001C24420001D1
+:1038B0003043FFFF14640002A4A2001EA4A0001E57
+:1038C0001200000A3C02800494A2001494A3001A7F
+:1038D0003042000F00021500006218253C028000F3
+:1038E000AC4300A00A000E1EACA0000894420006E3
+:1038F00094A3001A8CA40000A4A200160062102356
+:103900003042FFFF0044102B384200011040000DF0
+:1039100002201021006030213C07800494E2000660
+:10392000A4A2001694E3000600C310233042FFFF58
+:103930000044102B384200011440FFF8A4A30016E5
+:10394000022010218FBF00188FB100148FB000101B
+:1039500003E0000827BD002003E00008000000008D
+:103960008F82002C3C03000600021140004310250A
+:103970003C038000AC62003000000000000000004A
+:10398000000000008C620000304200101040FFFD7B
+:1039900034620400AF82002803E00008AF80002CEE
+:1039A00003E000080000102103E000080000000010
+:1039B0003084FFFF30A5FFFF0000182110800007B2
+:1039C000000000003082000110400002000420428C
+:1039D000006518210A000E3D0005284003E000089C
+:1039E0000060102110C0000624C6FFFF8CA200005A
+:1039F00024A50004AC8200000A000E4724840004C1
+:103A000003E000080000000010A0000824A3FFFF4E
+:103A1000AC86000000000000000000002402FFFF50
+:103A20002463FFFF1462FFFA2484000403E000080B
+:103A3000000000003C0280083442008024030001A2
+:103A4000AC43000CA4430010A4430012A443001490
+:103A500003E00008A44300168F82002427BDFFD88E
+:103A6000AFB3001CAFB20018AFB10014AFB000107C
+:103A7000AFBF00208C47000C248200802409FF8007
+:103A80003C08800E3043007F008080213C0A80008B
+:103A9000004920240068182130B100FF30D200FF17
+:103AA00010E000290000982126020100AD44002CFE
+:103AB000004928243042007F004820219062000005
+:103AC00024030050304200FF1443000400000000B3
+:103AD000AD45002C948200EA3053FFFF0E000D84A8
+:103AE000000000008F8200248F83002000112C0032
+:103AF0009442001E001224003484000100A22825F4
+:103B00003C02400000A22825AC7000008FBF0020BE
+:103B1000AC6000048FB20018AC7300088FB10014C1
+:103B2000AC60000C8FB3001CAC6400108FB00010B0
+:103B3000AC60001424040001AC60001827BD00280C
+:103B40000A000DB8AC65001C8FBF00208FB3001CAD
+:103B50008FB200188FB100148FB0001003E000087E
+:103B600027BD00283C06800034C201009043000FAE
+:103B7000240200101062000E2865001110A000073A
+:103B800024020012240200082405003A10620006F4
+:103B90000000302103E0000800000000240500358B
+:103BA0001462FFFC000030210A000E6400000000D7
+:103BB0008CC200748F83FF9424420FA003E000089E
+:103BC000AC62000C27BDFFE8AFBF00100E0003423F
+:103BD000240500013C0480088FBF0010240200016E
+:103BE00034830080A462001227BD00182402000163
+:103BF00003E00008A080001A27BDFFE0AFB2001864
+:103C0000AFB10014AFB00010AFBF001C30B2FFFF67
+:103C10000E000332008088213C028008345000806E
+:103C20009202000924030004304200FF1443000CF8
+:103C30003C028008124000082402000A0E000E5BBD
+:103C400000000000920200052403FFFE0043102440
+:103C5000A202000524020012A20200093C02800810
+:103C600034420080022020210E00033DA0400027A6
+:103C700016400003022020210E000EBF00000000AD
+:103C800002202021324600FF8FBF001C8FB2001897
+:103C90008FB100148FB00010240500380A000E64A4
+:103CA00027BD002027BDFFE0AFBF001CAFB200184A
+:103CB000AFB10014AFB000100E00033200808021BD
+:103CC0000E000E5B000000003C02800834450080BE
+:103CD00090A2000924120018305100FF1232000394
+:103CE0000200202124020012A0A2000990A20005D7
+:103CF0002403FFFE004310240E00033DA0A2000594
+:103D00000200202124050020163200070000302187
+:103D10008FBF001C8FB200188FB100148FB000103D
+:103D20000A00034227BD00208FBF001C8FB200187D
+:103D30008FB100148FB00010240500390A000E6402
+:103D400027BD002027BDFFE83C028000AFB0001077
+:103D5000AFBF0014344201009442000C2405003629
+:103D60000080802114400012304600FF0E00033214
+:103D7000000000003C02800834420080240300124E
+:103D8000A043000990430005346300100E000E5B51
+:103D9000A04300050E00033D020020210200202167
+:103DA0000E000342240500200A000F3C0000000022
+:103DB0000E000E64000000000E00033202002021FD
+:103DC0003C0280089043001B2405FF9F0200202135
+:103DD000006518248FBF00148FB00010A043001B93
+:103DE0000A00033D27BD001827BDFFE0AFBF001844
+:103DF000AFB10014AFB0001030B100FF0E000332BD
+:103E0000008080213C02800824030012344200809C
+:103E10000E000E5BA04300090E00033D02002021AE
+:103E200002002021022030218FBF00188FB1001422
+:103E30008FB00010240500350A000E6427BD002055
+:103E40003C0480089083000E9082000A1443000B0B
+:103E5000000028218F82FF942403005024050001D4
+:103E600090420000304200FF1443000400000000B4
+:103E70009082000E24420001A082000E03E00008A0
+:103E800000A010213C0380008C6201F80440FFFE7A
+:103E900024020002AC6401C0A06201C43C02100014
+:103EA00003E00008AC6201F827BDFFE0AFB20018E4
+:103EB0003C128008AFB10014AFBF001CAFB00010BF
+:103EC00036510080922200092403000A304200FF8C
+:103ED0001443003E000000008E4300048E22003890
+:103EE000506200808FBF001C92220000240300500B
+:103EF000304200FF144300253C0280008C42014008
+:103F00008E4300043642010002202821AC43001CED
+:103F10009622005C8E2300383042FFFF00021040E2
+:103F200000621821AE23001C8E4300048E2400384A
+:103F30009622005C006418233042FFFF0003184300
+:103F4000000210400043102A10400006000000004C
+:103F50008E4200048E230038004310230A000FAA6B
+:103F6000000220439622005C3042FFFF0002204006
+:103F70003C0280083443010034420080ACA4002C91
+:103F8000A040002424020001A062000C0E000F5E7D
+:103F900000000000104000538FBF001C3C02800056
+:103FA0008C4401403C0380008C6201F80440FFFE19
+:103FB00024020002AC6401C0A06201C43C021000F3
+:103FC000AC6201F80A0010078FBF001C92220009A2
+:103FD00024030010304200FF144300043C02800020
+:103FE0008C4401400A000FEE0000282192220009B3
+:103FF00024030016304200FF14430006240200147C
+:10400000A22200093C0280008C4401400A001001F9
+:104010008FBF001C8E2200388E23003C00431023EB
+:10402000044100308FBF001C92220027244200016F
+:10403000A2220027922200272C42000414400016DE
+:104040003C1080009222000924030004304200FF4B
+:10405000144300093C0280008C4401408FBF001CC7
+:104060008FB200188FB100148FB000102405009398
+:104070000A000ECC27BD00208C440140240500938B
+:104080008FBF001C8FB200188FB100148FB00010CA
+:104090000A000F4827BD00208E0401400E000332A5
+:1040A000000000008E4200042442FFFFAE420004E4
+:1040B0008E22003C2442FFFFAE22003C0E00033D56
+:1040C0008E0401408E0401408FBF001C8FB2001887
+:1040D0008FB100148FB00010240500040A000342C1
+:1040E00027BD00208FB200188FB100148FB00010D0
+:1040F00003E0000827BD00203C0680008CC2018838
+:104100003C038008346500809063000E00021402B6
+:10411000304400FF306300FF1464000E3C0280084E
+:1041200090A20026304200FF104400098F82FF94C5
+:10413000A0A400262403005090420000304200FF5B
+:1041400014430006000000000A0005A18CC4018091
+:104150003C02800834420080A044002603E00008AE
+:104160000000000027BDFFE030E700FFAFB20018FD
+:10417000AFBF001CAFB10014AFB0001000809021A1
+:1041800014E0000630C600FF000000000000000D33
+:10419000000000000A001060240001163C038008A3
+:1041A0009062000E304200FF14460023346200800B
+:1041B00090420026304200FF1446001F000000001D
+:1041C0009062000F304200FF1446001B0000000008
+:1041D0009062000A304200FF144600038F90FF9463
+:1041E0000000000D8F90FF948F82FF983C1180009B
+:1041F000AE05003CAC450000A066000A0E0003328C
+:104200008E240100A20000240E00033D8E24010034
+:104210003C0380008C6201F80440FFFE240200028F
+:10422000AC7201C0A06201C43C021000AC6201F893
+:104230000A0010618FBF001C000000000000000D8C
+:10424000000000002400013F8FBF001C8FB2001847
+:104250008FB100148FB0001003E0000827BD0020CC
+:104260008F83FF943C0280008C44010034420100A3
+:104270008C65003C9046001B0A00102724070001B3
+:104280003C0280089043000E9042000A0043102632
+:10429000304200FF03E000080002102B27BDFFE0C2
+:1042A0003C028008AFB10014AFB00010AFBF0018DF
+:1042B0003450008092020005240300303042003068
+:1042C00014430085008088218F8200248C42000CDA
+:1042D000104000828FBF00180E000D840000000007
+:1042E0008F860020ACD100009202000892030009E2
+:1042F000304200FF00021200306300FF004310252F
+:10430000ACC200049202004D000216000002160327
+:1043100004410005000000003C0308008C630048D5
+:104320000A00109F3C1080089202000830420040B2
+:10433000144000030000182192020027304300FFC0
+:104340003C108008361100809222004D00031E00B0
+:10435000304200FF0002140000621825ACC30008C0
+:104360008E2400308F820024ACC4000C8E250034D3
+:104370009443001E3C02C00BACC50010006218251F
+:104380008E22003800002021ACC200148E22003C96
+:10439000ACC200180E000DB8ACC3001C8E020004A5
+:1043A0008F8400203C058000AC8200008E2200201B
+:1043B000AC8200048E22001CAC8200088E220058C1
+:1043C0008CA3007400431021AC82000C8E22002CC0
+:1043D000AC8200108E2200408E23004400021400A4
+:1043E00000431025AC8200149222004D240300806B
+:1043F000304200FF1443000400000000AC800018AD
+:104400000A0010E38F8200248E23000C2402000196
+:104410001062000E2402FFFF92220008304200408A
+:104420001440000A2402FFFF8E23000C8CA20074AB
+:10443000006218233C0208000062102414400002AD
+:10444000000028210060282100051043AC820018DC
+:104450008F820024000020219443001E3C02C00CE7
+:10446000006218258F8200200E000DB8AC43001C9E
+:104470003C038008346201008C4200008F850020DC
+:10448000346300808FBF0018ACA20000ACA0000411
+:104490008C6400488F8200248FB10014ACA4000803
+:1044A000ACA0000CACA00010906300059446001E68
+:1044B0003C02400D00031E0000C23025ACA30014D6
+:1044C0008FB00010ACA0001824040001ACA6001CA2
+:1044D0000A000DB827BD00208FBF00188FB100144F
+:1044E0008FB0001003E0000827BD00203C028000D0
+:1044F0009443007C3C02800834460100308400FF75
+:104500003065FFFF2402000524A34650A0C4000C20
+:104510005482000C3065FFFF90C2000D2C42000752
+:104520001040000724A30A0090C3000D24020014C9
+:104530000062100400A210210A00111F3045FFFF85
+:104540003065FFFF3C0280083442008003E0000831
+:10455000A44500143C03800834680080AD05003891
+:10456000346701008CE2001C308400FF00A210239D
+:104570001840000330C600FF24A2FFFCACE2001C80
+:1045800030820001504000083C0380088D02003C4E
+:1045900000A2102304410012240400058C620004D0
+:1045A00010A2000F3C0380088C62000414A2001EBD
+:1045B000000000003C0208008C4200D8304200207D
+:1045C000104000093C0280083462008090630008BB
+:1045D0009042004C144300043C0280082404000470
+:1045E0000A00110900000000344300803442010039
+:1045F000A040000C24020001A462001410C0000AB4
+:104600003C0280008C4401003C0380008C6201F875
+:104610000440FFFE24020002AC6401C0A06201C499
+:104620003C021000AC6201F803E00008000000004A
+:1046300027BDFFE800A61823AFBF00101860008058
+:10464000308800FF3C02800834470080A0E000244E
+:1046500034440100A0E000278C82001C00A210233B
+:1046600004400056000000008CE2003C94E3005C33
+:104670008CE4002C004530233063FFFF00C3182179
+:104680000083202B1080000400E018218CE2002C15
+:104690000A00117800A2102194E2005C3042FFFF72
+:1046A00000C2102100A21021AC62001C3C02800854
+:1046B000344400809482005C8C83001C3042FFFFF5
+:1046C0000002104000A210210043102B10400004F3
+:1046D000000000008C82001C0A00118B3C06800840
+:1046E0009482005C3042FFFF0002104000A21021C3
+:1046F0003C06800834C3010034C70080AC82001C33
+:10470000A060000CACE500388C62001C00A21023F5
+:104710001840000224A2FFFCAC62001C3102000120
+:10472000104000083C0380088CE2003C00A21023EB
+:1047300004410012240400058CC2000410A20010E1
+:104740008FBF00108C62000414A2004F8FBF0010B6
+:104750003C0208008C4200D8304200201040000A81
+:104760003C02800834620080906300089042004C54
+:10477000144300053C028008240400048FBF00108D
+:104780000A00110927BD001834430080344201009B
+:10479000A040000C24020001A46200143C0280002E
+:1047A0008C4401003C0380008C6201F80440FFFE51
+:1047B000240200020A0011D8000000008CE2001C54
+:1047C000004610230043102B54400001ACE5001CB0
+:1047D00094E2005C3042FFFF0062102B144000079F
+:1047E0002402000294E2005C8CE3001C3042FFFFD4
+:1047F00000621821ACE3001C24020002ACE5003882
+:104800000E000F5EA082000C1040001F8FBF001032
+:104810003C0280008C4401003C0380008C6201F863
+:104820000440FFFE24020002AC6401C0A06201C487
+:104830003C021000AC6201F80A0011F08FBF0010BA
+:1048400031020010104000108FBF00103C028008A1
+:10485000344500808CA3001C94A2005C00661823E1
+:104860003042FFFF006218213C023FFF3444FFFF4B
+:104870000083102B544000010080182100C3102138
+:10488000ACA2001C8FBF001003E0000827BD001879
+:1048900027BDFFE800C0402100A63023AFBF0010B5
+:1048A00018C00026308A00FF3C028008344900808E
+:1048B0008D24001C8D23002C008820230064182BDD
+:1048C0001060000F344701008CE2002000461021E8
+:1048D000ACE200208CE200200044102B1440000BBE
+:1048E0003C023FFF8CE2002000441023ACE2002099
+:1048F0009522005C3042FFFF0A0012100082202146
+:10490000ACE00020008620213C023FFF3443FFFF43
+:104910000064102B54400001006020213C028008FC
+:104920003442008000851821AC43001CA0400024C4
+:10493000A04000270A0012623C03800831420010A8
+:10494000104000433C0380083C06800834C40080CB
+:104950008C82003C004810235840003E34660080A2
+:104960009082002424420001A0820024908200242E
+:104970003C0308008C630024304200FF0043102BEE
+:10498000144000688FBF001034C201008C42001C2C
+:1049900000A2102318400063000000008CC3000434
+:1049A0009482005C006818233042FFFF0003184324
+:1049B000000210400043102A1040000500000000D3
+:1049C0008CC20004004810230A0012450002104364
+:1049D0009482005C3042FFFF000210403C068008D9
+:1049E000AC82002C34C5008094A2005C8CA4002C06
+:1049F00094A3005C3042FFFF00021040008220219F
+:104A00003063FFFF0083202101041021ACA2001CB1
+:104A10008CC2000434C60100ACC2001C2402000297
+:104A20000E000F5EA0C2000C1040003E8FBF0010B1
+:104A30003C0280008C4401003C0380008C6201F841
+:104A40000440FFFE240200020A001292000000004F
+:104A500034660080ACC50038346401008C82001CD0
+:104A600000A210231840000224A2FFFCAC82001C0C
+:104A7000314200015040000A3C0380088CC2003CD7
+:104A800000A2102304430014240400058C620004D7
+:104A900014A200033C0380080A00128424040005C9
+:104AA0008C62000414A2001F8FBF00103C0208009B
+:104AB0008C4200D8304200201040000A3C0280089E
+:104AC00034620080906300089042004C144300055B
+:104AD0003C028008240400048FBF00100A00110962
+:104AE00027BD00183443008034420100A040000C70
+:104AF00024020001A46200143C0280008C440100E6
+:104B00003C0380008C6201F80440FFFE2402000296
+:104B1000AC6401C0A06201C43C021000AC6201F8A8
+:104B20008FBF001003E0000827BD001827BDFFE875
+:104B30003C0A8008AFBF0010354900808D22003C40
+:104B400000C04021308400FF004610231840009D23
+:104B500030E700FF354701002402000100A63023A2
+:104B6000A0E0000CA0E0000DA522001418C0002455
+:104B7000308200108D23001C8D22002C0068182329
+:104B80000043102B1040000F000000008CE20020BA
+:104B900000461021ACE200208CE200200043102BE4
+:104BA0001440000B3C023FFF8CE200200043102326
+:104BB000ACE200209522005C3042FFFF0A0012C1E7
+:104BC00000621821ACE00020006618213C023FFF83
+:104BD0003446FFFF00C3102B5440000100C01821D1
+:104BE0003C0280083442008000651821AC43001C60
+:104BF000A0400024A04000270A00130F3C038008B7
+:104C0000104000403C0380088D22003C00481023E7
+:104C10005840003D34670080912200242442000166
+:104C2000A1220024912200243C0308008C6300246C
+:104C3000304200FF0043102B1440009A8FBF001039
+:104C40008CE2001C00A21023184000960000000017
+:104C50008D4300049522005C006818233042FFFF5A
+:104C600000031843000210400043102A10400005C2
+:104C7000012020218D420004004810230A0012F276
+:104C8000000210439522005C3042FFFF00021040FA
+:104C90003C068008AC82002C34C5008094A2005CE5
+:104CA0008CA4002C94A3005C3042FFFF0002104053
+:104CB000008220213063FFFF0083182101031021AF
+:104CC000ACA2001C8CC2000434C60100ACC2001CA3
+:104CD000240200020E000F5EA0C2000C1040007102
+:104CE0008FBF00103C0280008C4401003C03800018
+:104CF0008C6201F80440FFFE240200020A0013390E
+:104D00000000000034670080ACE500383466010024
+:104D10008CC2001C00A210231840000224A2FFFC39
+:104D2000ACC2001C30820001504000083C038008E7
+:104D30008CE2003C00A2102304430051240400052F
+:104D40008C62000410A2003E3C0380088C620004C8
+:104D500054A200548FBF00103C0208008C4200D8BF
+:104D600030420020104000063C028008346200807F
+:104D7000906300089042004C104300403C028008C1
+:104D80003443008034420100A040000C24020001A2
+:104D9000A46200143C0280008C4401003C038000AB
+:104DA0008C6201F80440FFFE24020002AC6401C0E2
+:104DB000A06201C43C021000AC6201F80A00137743
+:104DC0008FBF001024020005A120002714E2000A72
+:104DD0003C038008354301009062000D2C42000620
+:104DE000504000053C0380089062000D2442000101
+:104DF000A062000D3C03800834670080ACE50038F9
+:104E0000346601008CC2001C00A21023184000026E
+:104E100024A2FFFCACC2001C308200015040000AFA
+:104E20003C0380088CE2003C00A2102304410014E3
+:104E3000240400058C62000414A200033C038008D3
+:104E40000A00136E240400058C62000414A20015ED
+:104E50008FBF00103C0208008C4200D83042002076
+:104E60001040000A3C028008346200809063000811
+:104E70009042004C144300053C02800824040004C6
+:104E80008FBF00100A00110927BD001834430080AD
+:104E900034420100A040000C24020001A46200146E
+:104EA0008FBF001003E0000827BD00183C0B8008EE
+:104EB00027BDFFE83C028000AFBF00103442010074
+:104EC000356A00809044000A356901008C45001461
+:104ED0008D4800389123000C308400FF0105102319
+:104EE0001C4000B3306700FF2CE20006504000B1C8
+:104EF0008FBF00102402000100E2300430C2000322
+:104F00005440000800A8302330C2000C144000A117
+:104F100030C20030144000A38FBF00100A00143BC1
+:104F20000000000018C00024308200108D43001CD7
+:104F30008D42002C006818230043102B1040000FF6
+:104F4000000000008D22002000461021AD2200202C
+:104F50008D2200200043102B1440000B3C023FFF29
+:104F60008D22002000431023AD2200209542005CDA
+:104F70003042FFFF0A0013AF00621821AD2000206D
+:104F8000006618213C023FFF3446FFFF00C3102B90
+:104F90005440000100C018213C02800834420080C7
+:104FA00000651821AC43001CA0400024A04000274D
+:104FB0000A0013FD3C038008104000403C038008B9
+:104FC0008D42003C004810231840003D34670080AB
+:104FD0009142002424420001A14200249142002475
+:104FE0003C0308008C630024304200FF0043102B78
+:104FF000144000708FBF00108D22001C00A21023EF
+:105000001840006C000000008D6300049542005CB5
+:10501000006818233042FFFF0003184300021040CD
+:105020000043102A10400005014020218D62000439
+:10503000004810230A0013E0000210439542005C70
+:105040003042FFFF000210403C068008AC82002C7A
+:1050500034C5008094A2005C8CA4002C94A3005C56
+:105060003042FFFF00021040008220213063FFFF2A
+:105070000083182101031021ACA2001C8CC2000483
+:1050800034C60100ACC2001C240200020E000F5EF8
+:10509000A0C2000C104000478FBF00103C028000EF
+:1050A0008C4401003C0380008C6201F80440FFFE48
+:1050B000240200020A00142D000000003467008062
+:1050C000ACE50038346601008CC2001C00A210233D
+:1050D0001840000224A2FFFCACC2001C3082000178
+:1050E0005040000A3C0380088CE2003C00A21023E0
+:1050F00004430014240400058C62000414A200037D
+:105100003C0380080A00141F240400058C6200047C
+:1051100014A200288FBF00103C0208008C4200D867
+:10512000304200201040000A3C02800834620080B7
+:10513000906300089042004C144300053C02800834
+:10514000240400048FBF00100A00110927BD0018B5
+:105150003443008034420100A040000C24020001CE
+:10516000A46200143C0280008C4401003C038000D7
+:105170008C6201F80440FFFE24020002AC6401C00E
+:10518000A06201C43C021000AC6201F80A00143BAA
+:105190008FBF00108FBF0010010030210A00115A8C
+:1051A00027BD0018010030210A00129927BD001800
+:1051B0008FBF001003E0000827BD00183C038008E3
+:1051C0003464010024020003A082000C8C620004FD
+:1051D00003E00008AC82001C3C05800834A300807A
+:1051E0009062002734A501002406004324420001F8
+:1051F000A0620027906300273C0208008C42004810
+:10520000306300FF146200043C07602194A500EAAB
+:105210000A00090130A5FFFF03E0000800000000BC
+:1052200027BDFFE8AFBF00103C0280000E00144411
+:105230008C4401803C02800834430100A060000CD3
+:105240008C4200048FBF001027BD001803E0000847
+:10525000AC62001C27BDFFE03C028008AFBF001815
+:10526000AFB10014AFB000103445008034460100E7
+:105270003C0880008D09014090C3000C8CA4003CC8
+:105280008CA200381482003B306700FF9502007C3E
+:1052900090A30027146000093045FFFF2402000599
+:1052A00054E200083C04800890C2000D2442000132
+:1052B000A0C2000D0A00147F3C048008A0C0000DAD
+:1052C0003C048008348201009042000C2403000555
+:1052D000304200FF1443000A24A205DC348300801E
+:1052E000906200272C4200075040000524A20A00CB
+:1052F00090630027240200140062100400A2102111
+:105300003C108008361000803045FFFF012020212E
+:105310000E001444A60500149602005C8E030038AB
+:105320003C1180003042FFFF000210400062182153
+:10533000AE03001C0E0003328E24014092020025B1
+:1053400034420040A20200250E00033D8E2401409D
+:105350008E2401403C0380008C6201F80440FFFE73
+:1053600024020002AC6401C0A06201C43C0210002F
+:10537000AC6201F88FBF00188FB100148FB000101D
+:1053800003E0000827BD00203C0360103C02080039
+:1053900024420174AC62502C8C6250003C048000AA
+:1053A00034420080AC6250003C0208002442547C2D
+:1053B0003C010800AC2256003C020800244254384C
+:1053C0003C010800AC2256043C020002AC840008F8
+:1053D000AC82000C03E000082402000100A0302190
+:1053E0003C1C0800279C56083C0200023C050400B7
+:1053F00000852826008220260004102B2CA5000101
+:105400002C840001000210803C0308002463560035
+:105410000085202500431821108000030000102182
+:10542000AC6600002402000103E000080000000058
+:105430003C1C0800279C56083C0200023C05040066
+:1054400000852826008220260004102B2CA50001B0
+:105450002C840001000210803C03080024635600E5
+:105460000085202500431821108000050000102130
+:105470003C02080024425438AC62000024020001BF
+:1054800003E00008000000003C0200023C030400AE
+:1054900000821026008318262C4200012C63000194
+:1054A000004310251040000B000028213C1C080080
+:1054B000279C56083C0380008C62000824050001EC
+:1054C00000431025AC6200088C62000C00441025DB
+:1054D000AC62000C03E0000800A010213C1C080096
+:1054E000279C56083C0580008CA3000C0004202754
+:1054F000240200010064182403E00008ACA3000C9F
+:105500003C020002148200063C0560008CA208D018
+:105510002403FFFE0043102403E00008ACA208D0DF
+:105520003C02040014820005000000008CA208D098
+:105530002403FFFD00431024ACA208D003E00008C0
+:10554000000000003C02601A344200108C430080CE
+:1055500027BDFFF88C440084AFA3000093A3000094
+:10556000240200041462001AAFA4000493A20001F4
+:105570001040000797A300023062FFFC3C0380004C
+:10558000004310218C4200000A001536AFA200042F
+:105590003062FFFC3C03800000431021AC4400005B
+:1055A000A3A000003C0560008CA208D02403FFFEED
+:1055B0003C04601A00431024ACA208D08FA300045E
+:1055C0008FA2000034840010AC830084AC82008081
+:1055D00003E0000827BD000827BDFFE8AFBF0010AB
+:1055E0003C1C0800279C56083C0280008C43000CA1
+:1055F0008C420004004318243C0200021060001496
+:10560000006228243C0204003C04000210A00005B3
+:10561000006210243C0208008C4256000A00155B10
+:1056200000000000104000073C0404003C02080099
+:105630008C4256040040F809000000000A00156082
+:10564000000000000000000D3C1C0800279C5608CC
+:0C5650008FBF001003E0000827BD001809
+:04565C008008024080
+:1056600080080100800800808008000000000C8095
+:105670000000320008000E9808000EF408000F88A1
+:1056800008001028080010748008010080080080BD
+:04569000800800008E
+:0C5694000A0000280000000000000000D8
+:1056A0000000000D6370362E302E313700000000F0
+:1056B00006001104000000000000000000000000CF
+:1056C000000000000000000038003C000000000066
+:1056D00000000000000000000000000000000020AA
+:1056E00000000000000000000000000000000000BA
+:1056F00000000000000000000000000000000000AA
+:10570000000000000000000021003800000000013F
+:105710000000002B000000000000000400030D400A
+:105720000000000000000000000000000000000079
+:105730000000000000000000100000030000000056
+:105740000000000D0000000D3C020800244259AC8E
+:105750003C03080024635BF4AC4000000043202BB2
+:105760001480FFFD244200043C1D080037BD9FFC4F
+:1057700003A0F0213C100800261000A03C1C0800EB
+:10578000279C59AC0E0002F6000000000000000D3E
+:1057900027BDFFB4AFA10000AFA20004AFA3000873
+:1057A000AFA4000CAFA50010AFA60014AFA700185F
+:1057B000AFA8001CAFA90020AFAA0024AFAB0028FF
+:1057C000AFAC002CAFAD0030AFAE0034AFAF00389F
+:1057D000AFB8003CAFB90040AFBC0044AFBF004819
+:1057E0000E000820000000008FBF00488FBC00445E
+:1057F0008FB900408FB8003C8FAF00388FAE0034B7
+:105800008FAD00308FAC002C8FAB00288FAA002406
+:105810008FA900208FA8001C8FA700188FA6001446
+:105820008FA500108FA4000C8FA300088FA2000486
+:105830008FA1000027BD004C3C1B60188F7A5030B0
+:10584000377B502803400008AF7A000000A01821E1
+:1058500000801021008028213C0460003C0760008B
+:105860002406000810600006348420788C42000072
+:10587000ACE220088C63000003E00008ACE3200CDD
+:105880000A000F8100000000240300403C02600079
+:1058900003E00008AC4320003C0760008F86000452
+:1058A0008CE520740086102100A2182B14600007DC
+:1058B000000028218F8AFDA024050001A1440013C7
+:1058C0008F89000401244021AF88000403E0000810
+:1058D00000A010218F84FDA08F8500049086001306
+:1058E00030C300FF00A31023AF82000403E00008D0
+:1058F000A08000138F84FDA027BDFFE8AFB000108B
+:10590000AFBF001490890011908700112402002875
+:10591000312800FF3906002830E300FF2485002CE1
+:105920002CD00001106200162484001C0E00006EB2
+:10593000000000008F8FFDA03C05600024020204DF
+:1059400095EE003E95ED003C000E5C0031ACFFFF93
+:10595000016C5025ACAA2010520000012402000462
+:10596000ACA22000000000000000000000000000C9
+:105970008FBF00148FB0001003E0000827BD00188F
+:105980000A0000A6000028218F85FDA027BDFFD8B2
+:10599000AFBF0020AFB3001CAFB20018AFB100140E
+:1059A000AFB000100080982190A4001124B0001C1A
+:1059B00024B1002C308300FF386200280E000090D4
+:1059C0002C5200010E00009800000000020020216F
+:1059D0001240000202202821000028210E00006E43
+:1059E000000000008F8DFDA03C0880003C05600099
+:1059F00095AC003E95AB003C02683025000C4C0095
+:105A0000316AFFFF012A3825ACA7201024020202C8
+:105A1000ACA6201452400001240200028FBF0020D7
+:105A20008FB3001C8FB200188FB100148FB000101C
+:105A300027BD002803E00008ACA2200027BDFFE03E
+:105A4000AFB20018AFB10014AFB00010AFBF001C70
+:105A50003C1160008E2320748F82000430D0FFFF41
+:105A600030F2FFFF1062000C2406008F0E00006E63
+:105A7000000000003C06801F0010440034C5FF00F9
+:105A80000112382524040002AE2720100000302126
+:105A9000AE252014AE2420008FBF001C8FB200184A
+:105AA0008FB100148FB0001000C0102103E0000877
+:105AB00027BD002027BDFFE0AFB0001030D0FFFFB2
+:105AC000AFBF0018AFB100140E00006E30F1FFFF41
+:105AD00000102400009180253C036000AC70201071
+:105AE0008FBF00188FB100148FB000102402000483
+:105AF000AC62200027BD002003E000080000102158
+:105B000027BDFFE03C046018AFBF0018AFB1001420
+:105B1000AFB000108C8850002403FF7F34028071E6
+:105B20000103382434E5380C241F00313C1980006F
+:105B3000AC8550003C11800AAC8253BCAF3F0008DA
+:105B40000E00054CAF9100400E00050A3C116000AC
+:105B50000E00007D000000008E3008083C0F570941
+:105B60002418FFF00218602435EEE00035EDF00057
+:105B7000018E5026018D58262D4600012D69000109
+:105B8000AF86004C0E000D09AF8900503C06601630
+:105B90008CC700003C0860148D0500A03C03FFFF8B
+:105BA00000E320243C02535300052FC2108200550D
+:105BB00034D07C00960201F2A780006C10400003F4
+:105BC000A780007C384B1E1EA78B006C960201F844
+:105BD000104000048F8D0050384C1E1EA78C007C96
+:105BE0008F8D005011A000058F83004C240E0020E3
+:105BF000A78E007CA78E006C8F83004C1060000580
+:105C00009785007C240F0020A78F007CA78F006C55
+:105C10009785007C2CB8008153000001240500808A
+:105C20009784006C2C91040152200001240404008C
+:105C30001060000B3C0260008FBF00188FB1001491
+:105C40008FB0001027BD0020A784006CA785007CC2
+:105C5000A380007EA780007403E00008A780009264
+:105C60008C4704382419103C30FFFFFF13F9000360
+:105C700030A8FFFF1100004624030050A380007EDF
+:105C80009386007E50C00024A785007CA780007CFE
+:105C90009798007CA780006CA7800074A780009272
+:105CA0003C010800AC3800800E00078700000000AF
+:105CB0003C0F60008DED0808240EFFF03C0B600ED9
+:105CC000260C0388356A00100000482100002821B6
+:105CD00001AE20243C105709AF8C0010AF8A004859
+:105CE000AF89001810900023AF8500148FBF0018F3
+:105CF0008FB100148FB0001027BD002003E0000812
+:105D0000AF80005400055080014648218D260004D4
+:105D10000A00014800D180219798007CA784006C7C
+:105D2000A7800074A78000923C010800AC38008076
+:105D30000E000787000000003C0F60008DED080892
+:105D4000240EFFF03C0B600E260C0388356A001011
+:105D5000000048210000282101AE20243C105709F2
+:105D6000AF8C0010AF8A0048AF8900181490FFDF95
+:105D7000AF85001424110001AF9100548FBF0018AB
+:105D80008FB100148FB0001003E0000827BD002081
+:105D90000A00017BA383007E3083FFFF8F880040D1
+:105DA0008F87003C000321403C0580003C020050EE
+:105DB000008248253C0660003C0A010034AC040027
+:105DC0008CCD08E001AA58241160000500000000F5
+:105DD0008CCF08E024E7000101EA7025ACCE08E092
+:105DE0008D19001001805821ACB900388D180014AD
+:105DF000ACB8003CACA9003000000000000000007E
+:105E00000000000000000000000000000000000092
+:105E100000000000000000003C0380008C640000D3
+:105E2000308200201040FFFD3C0F60008DED08E047
+:105E30003C0E010001AE18241460FFE100000000D8
+:105E4000AF87003C03E00008AF8B00588F8500400F
+:105E5000240BFFF03C06800094A7001A8CA90024B4
+:105E600030ECFFFF000C38C000EB5024012A402129
+:105E7000ACC8003C8CA400248CC3003C00831023DD
+:105E800018400033000000008CAD002025A2000166
+:105E90003C0F0050ACC2003835EE00103C068000CC
+:105EA000ACCE003000000000000000000000000048
+:105EB00000000000000000000000000000000000E2
+:105EC000000000003C0480008C9900003338002062
+:105ED0001300FFFD30E20008104000173C0980006D
+:105EE0008C880408ACA800108C83040CACA30014AC
+:105EF0003C1900203C188000AF19003094AE001807
+:105F000094AF001C01CF3021A4A6001894AD001A54
+:105F100025A70001A4A7001A94AB001A94AC001E98
+:105F2000118B00030000000003E0000800000000E7
+:105F300003E00008A4A0001A8D2A0400ACAA0010F7
+:105F40008D240404ACA400140A0002183C1900209B
+:105F50008CA200200A0002003C0F00500A0001EE53
+:105F60000000000027BDFFE8AFBF00100E000232A6
+:105F7000000000008F8900408FBF00103C038000AC
+:105F8000A520000A9528000A9527000427BD0018BF
+:105F90003105FFFF30E6000F0006150000A22025A6
+:105FA00003E00008AC6400803C0508008CA50020DC
+:105FB0008F83000C27BDFFE8AFB00010AFBF001407
+:105FC00010A300100000802124040001020430040A
+:105FD00000A6202400C3102450440006261000010F
+:105FE000001018802787FDA41480000A006718217C
+:105FF000261000012E0900025520FFF38F83000CAC
+:10600000AF85000C8FBF00148FB0001003E00008B4
+:1060100027BD00188C6800003C058000ACA8002457
+:106020000E000234261000013C0508008CA500205B
+:106030000A0002592E0900022405000100851804F7
+:106040003C0408008C84002027BDFFC8AFBF00348B
+:1060500000831024AFBE0030AFB7002CAFB60028CD
+:10606000AFB50024AFB40020AFB3001CAFB200182E
+:10607000AFB1001410400051AFB000108F84004049
+:10608000948700069488000A00E8302330D5FFFF8B
+:1060900012A0004B8FBF0034948B0018948C000A20
+:1060A000016C50233142FFFF02A2482B1520000251
+:1060B00002A02021004020212C8F000515E00002C5
+:1060C00000809821241300040E0001C102602021E9
+:1060D0008F87004002609021AF80004494F4000A52
+:1060E000026080211260004E3291FFFF3C1670006A
+:1060F0003C1440003C1E20003C1760008F99005863
+:106100008F380000031618241074004F0283F82BF8
+:1061100017E0003600000000107E00478F86004424
+:1061200014C0003A2403000102031023022320219B
+:106130003050FFFF1600FFF13091FFFF8F870040C6
+:106140003C1100203C108000AE11003094EB000A9E
+:106150003C178000024B5021A4EA000A94E9000A8F
+:1061600094E800043123FFFF3106000F00062D00E4
+:106170000065F025AEFE008094F3000A94F6001846
+:1061800012D30036001221408CFF00148CF4001052
+:1061900003E468210000C02101A4782B029870213B
+:1061A00001CF6021ACED0014ACEC001002B238233A
+:1061B00030F5FFFF16A0FFB88F8400408FBF00347A
+:1061C0008FBE00308FB7002C8FB600288FB500240B
+:1061D0008FB400208FB3001C8FB200188FB1001451
+:1061E0008FB0001003E0000827BD00381477FFCC03
+:1061F0008F8600440E000EE202002021004018218C
+:106200008F86004410C0FFC9020310230270702360
+:106210008F87004001C368210A0002E431B2FFFF0A
+:106220008F86004414C0FFC93C1100203C10800040
+:106230000A0002AEAE1100300E00046602002021FA
+:106240000A0002DB00401821020020210E0009395B
+:10625000022028210A0002DB004018210E0001EE76
+:10626000000000000A0002C702B2382327BDFFC8A1
+:10627000AFB7002CAFB60028AFB50024AFB40020F4
+:10628000AFB3001CAFB20018AFB10014AFB0001034
+:10629000AFBF00300E00011B241300013C047FFF40
+:1062A0003C0380083C0220003C010800AC20007048
+:1062B0003496FFFF34770080345200033C1512C03F
+:1062C000241400013C1080002411FF800E000245C0
+:1062D000000000008F8700488F8B00188F89001402
+:1062E0008CEA00EC8CE800E8014B302B01092823F4
+:1062F00000A6102314400006014B18231440000E82
+:106300003C05800002A3602B1180000B0000000000
+:106310003C0560008CEE00EC8CED00E88CA4180CC1
+:10632000AF8E001804800053AF8D00148F8F0010C3
+:10633000ADF400003C0580008CBF00003BF900017B
+:10634000333800011700FFE13C0380008C6201003C
+:1063500024060C0010460009000000008C680100B3
+:106360002D043080548000103C0480008C690100B2
+:106370002D2331811060000C3C0480008CAA0100A8
+:1063800011460004000020218CA6010024C5FF81D5
+:1063900030A400FF8E0B01000E000269AE0B00243A
+:1063A0000A00034F3C0480008C8D01002DAC3300AB
+:1063B00011800022000000003C0708008CE70098D4
+:1063C00024EE00013C010800AC2E00983C04800043
+:1063D0008C8201001440000300000000566000148D
+:1063E0003C0440008C9F01008C9801000000982123
+:1063F00003F1C82400193940330F007F00EF7025E6
+:1064000001D26825AC8D08308C8C01008C85010090
+:10641000258B0100017130240006514030A3007F1C
+:106420000143482501324025AC8808303C04400037
+:10643000AE0401380A00030E000000008C99010030
+:10644000240F0020AC99002092F80000330300FFD5
+:10645000106F000C241F0050547FFFDD3C048000AF
+:106460008C8401000E00154E000000000A00034F4E
+:106470003C04800000963824ACA7180C0A000327BF
+:106480008F8F00108C8501000E0008F72404008017
+:106490000A00034F3C04800000A4102B24030001D9
+:1064A00010400009000030210005284000A4102BF6
+:1064B00004A00003000318405440FFFC00052840DE
+:1064C0005060000A0004182B0085382B54E00004AB
+:1064D0000003184200C33025008520230003184222
+:1064E0001460FFF9000528420004182B03E000089F
+:1064F00000C310213084FFFF30C600FF3C0780003E
+:106500008CE201B80440FFFE00064C000124302557
+:106510003C08200000C820253C031000ACE00180AE
+:10652000ACE50184ACE4018803E00008ACE301B809
+:106530003C0660008CC5201C2402FFF03083020062
+:10654000308601001060000E00A2282434A500014E
+:106550003087300010E0000530830C0034A50004C3
+:106560003C04600003E00008AC85201C1060FFFDC7
+:106570003C04600034A5000803E00008AC85201C42
+:1065800054C0FFF334A500020A0003B03087300086
+:1065900027BDFFE8AFB00010AFBF00143C0760009C
+:1065A000240600021080001100A080218F83005873
+:1065B0000E0003A78C6400188F8200580000202171
+:1065C000240600018C45000C0E000398000000001A
+:1065D0001600000224020003000010218FBF0014E7
+:1065E0008FB0001003E0000827BD00188CE8201CC5
+:1065F0002409FFF001092824ACE5201C8F870058EE
+:106600000A0003CD8CE5000C3C02600E00804021A6
+:1066100034460100240900180000000000000000BA
+:10662000000000003C0A00503C0380003547020097
+:10663000AC68003834640400AC65003CAC670030E2
+:106640008C6C0000318B00201160FFFD2407FFFFE0
+:106650002403007F8C8D00002463FFFF248400044A
+:10666000ACCD00001467FFFB24C60004000000004E
+:10667000000000000000000024A402000085282B78
+:106680003C0300203C0E80002529FFFF010540212E
+:10669000ADC300301520FFE00080282103E0000892
+:1066A000000000008F82005827BDFFD8AFB3001C48
+:1066B000AFBF0020AFB20018AFB10014AFB00010F0
+:1066C00094460002008098218C5200182CC300814F
+:1066D0008C4800048C4700088C51000C8C49001039
+:1066E000106000078C4A00142CC4000414800013AE
+:1066F00030EB000730C5000310A0001000000000C0
+:106700002410008B02002021022028210E00039873
+:10671000240600031660000224020003000010217A
+:106720008FBF00208FB3001C8FB200188FB10014F0
+:106730008FB0001003E0000827BD00281560FFF1AE
+:106740002410008B3C0C80003C030020241F00011F
+:10675000AD830030AF9F0044000000000000000047
+:10676000000000002419FFF024D8000F031978243A
+:106770003C1000D0AD88003801F0702524CD000316
+:106780003C08600EAD87003C35850400AD8E0030BE
+:10679000000D38823504003C3C0380008C6B000007
+:1067A000316200201040FFFD0000000010E00008F2
+:1067B00024E3FFFF2407FFFF8CA800002463FFFFF2
+:1067C00024A50004AC8800001467FFFB24840004A7
+:1067D0003C05600EACA60038000000000000000080
+:1067E000000000008F8600543C0400203C0780001D
+:1067F000ACE4003054C000060120202102402021DA
+:106800000E0003A7000080210A00041D02002021C1
+:106810000E0003DD01402821024020210E0003A7C5
+:10682000000080210A00041D0200202127BDFFE096
+:10683000AFB200183092FFFFAFB10014AFBF001C21
+:10684000AFB000101640000D000088210A0004932C
+:106850000220102124050003508500278CE5000C40
+:106860000000000D262800013111FFFF24E2002066
+:106870000232802B12000019AF8200588F82004430
+:10688000144000168F8700583C0670003C0320001F
+:106890008CE5000000A62024148300108F84006083
+:1068A000000544023C09800000A980241480FFE90F
+:1068B000310600FF2CCA000B5140FFEB26280001D7
+:1068C000000668803C0E080025CE575801AE6021B6
+:1068D0008D8B0000016000080000000002201021E4
+:1068E0008FBF001C8FB200188FB100148FB0001042
+:1068F00003E0000827BD00200E0003982404008454
+:106900001600FFD88F8700580A000474AF8000601B
+:10691000020028210E0003BF240400018F870058C5
+:106920000A000474AF820060020028210E0003BF39
+:10693000000020210A0004A38F8700580E000404E1
+:10694000020020218F8700580A000474AF82006083
+:1069500030AFFFFF000F19C03C0480008C9001B8DD
+:106960000600FFFE3C1920043C181000AC83018097
+:10697000AC800184AC990188AC9801B80A00047518
+:106980002628000190E2000390E30002000020218D
+:106990000002FE0000033A0000FF2825240600083C
+:1069A0000E000398000000001600FFDC2402000324
+:1069B0008F870058000010210A000474AF82006025
+:1069C00090E8000200002021240600090A0004C308
+:1069D00000082E0090E4000C240900FF308500FF21
+:1069E00010A900150000302190F9000290F8000372
+:1069F000308F00FF94EB000400196E000018740043
+:106A0000000F62000186202501AE5025014B28258C
+:106A10003084FF8B0A0004C32406000A90E30002BE
+:106A200090FF0004000020210003360000DF28252D
+:106A30000A0004C32406000B0A0004D52406008BB8
+:106A4000000449C23127003F000443423C02800059
+:106A500000082040240316802CE60020AC43002CC4
+:106A600024EAFFE02482000114C0000330A900FFE3
+:106A700000801021314700FF000260803C0D800043
+:106A8000240A0001018D20213C0B000E00EA28049D
+:106A9000008B302111200005000538278CCE000026
+:106AA00001C5382503E00008ACC700008CD8000001
+:106AB0000307782403E00008ACCF000027BDFFE007
+:106AC000AFB10014AFB00010AFBF00183C076000BA
+:106AD0008CE408083402F0003C1160003083F000C0
+:106AE000240501C03C04800E000030211062000625
+:106AF000241000018CEA08083149F0003928E00030
+:106B00000008382B000780403C0D0200AE2D081411
+:106B1000240C16803C0B80008E2744000E000F8B47
+:106B2000AD6C002C120000043C02169124050001FB
+:106B3000120500103C023D2C345800E0AE384408E9
+:106B40003C1108008E31007C8FBF00183C066000AD
+:106B500000118540360F16808FB100148FB00010E1
+:106B60003C0E020027BD0020ACCF442003E000080B
+:106B7000ACCE08103C0218DA345800E0AE384408B5
+:106B80003C1108008E31007C8FBF00183C0660006D
+:106B900000118540360F16808FB100148FB00010A1
+:106BA0003C0E020027BD0020ACCF442003E00008CB
+:106BB000ACCE08100A0004EB240500010A0004EB27
+:106BC0000000282124020400A7820024A780001CC2
+:106BD000000020213C06080024C65A582405FFFF67
+:106BE00024890001000440803124FFFF01061821A0
+:106BF0002C87002014E0FFFAAC6500002404040098
+:106C0000A7840026A780001E000020213C06080063
+:106C100024C65AD82405FFFF248D0001000460809B
+:106C200031A4FFFF018658212C8A00201540FFFA6D
+:106C3000AD650000A7800028A7800020A780002263
+:106C4000000020213C06080024C65B582405FFFFF5
+:106C5000249900010004C0803324FFFF030678213B
+:106C60002C8E000415C0FFFAADE500003C05600065
+:106C70008CA73D002403E08F00E31024344601403C
+:106C800003E00008ACA63D002487007F000731C266
+:106C900024C5FFFF000518C2246400013082FFFFF5
+:106CA000000238C0A78400303C010800AC27003047
+:106CB000AF80002C0000282100002021000030219E
+:106CC0002489000100A728213124FFFF2CA81701E7
+:106CD000110000032C8300801460FFF924C600011A
+:106CE00000C02821AF86002C10C0001DA786002AF6
+:106CF00024CAFFFF000A11423C08080025085B581F
+:106D00001040000A00002021004030212407FFFF2E
+:106D1000248E00010004688031C4FFFF01A86021B7
+:106D20000086582B1560FFFAAD87000030A2001FC7
+:106D30005040000800043080240300010043C804D0
+:106D400000041080004878212738FFFF03E0000886
+:106D5000ADF8000000C820212405FFFFAC8500002D
+:106D600003E000080000000030A5FFFF30C6FFFF71
+:106D700030A8001F0080602130E700FF0005294295
+:106D80000000502110C0001D24090001240B000147
+:106D900025180001010B2004330800FF0126782686
+:106DA000390E00202DED00012DC2000101A2182591
+:106DB0001060000D014450250005C880032C4021BF
+:106DC0000100182110E0000F000A20278D040000A8
+:106DD000008A1825AD03000024AD00010000402109
+:106DE0000000502131A5FFFF252E000131C9FFFF12
+:106DF00000C9102B1040FFE72518000103E0000830
+:106E0000000000008D0A0000014440240A0005D162
+:106E1000AC68000027BDFFE830A5FFFF30C6FFFFCC
+:106E2000AFB00010AFBF001430E7FFFF00005021EB
+:106E30003410FFFF0000602124AF001F00C0482174
+:106E4000241800012419002005E0001601E010219B
+:106E50000002F943019F682A0009702B01AE40240B
+:106E600011000017000C18800064102110E00005CC
+:106E70008C4B000000F840040008382301675824B8
+:106E800000003821154000410000402155600016E7
+:106E90003169FFFF258B0001316CFFFF05E1FFEC3D
+:106EA00001E0102124A2003E0002F943019F682A5C
+:106EB0000009702B01AE40241500FFEB000C188078
+:106EC000154600053402FFFF020028210E0005B51B
+:106ED00000003821020010218FBF00148FB0001075
+:106EE00003E0000827BD00181520000301601821E9
+:106EF000000B1C0224080010306A00FF154000053A
+:106F0000306E000F250D000800031A0231A800FFA3
+:106F1000306E000F15C00005307F000325100004FF
+:106F200000031902320800FF307F000317E000055C
+:106F3000386900012502000200031882304800FF72
+:106F4000386900013123000110600004310300FFA3
+:106F5000250A0001314800FF310300FF000C6940A1
+:106F600001A34021240A000110CAFFD53110FFFF00
+:106F7000246E000131C800FF1119FFC638C9000195
+:106F80002D1F002053E0001C258B0001240D000163
+:106F90000A000648240E002051460017258B0001E8
+:106FA00025090001312800FF2D0900205120001281
+:106FB000258B000125430001010D5004014B1024D5
+:106FC000250900011440FFF4306AFFFF3127FFFF5D
+:106FD00010EE000C2582FFFF304CFFFF0000502117
+:106FE0003410FFFF312800FF2D0900205520FFF24B
+:106FF00025430001258B0001014648260A000602B0
+:10700000316CFFFF00003821000050210A000654B7
+:107010003410FFFF27BDFFD8AFB0001030F0FFFFE6
+:10702000AFB10014001039423211FFE000071080A8
+:10703000AFB3001C00B1282330D3FFFFAFB200185C
+:1070400030A5FFFF00809021026030210044202104
+:10705000AFBF00200E0005E03207001F022288218A
+:107060003403FFFF0240202102002821026030216A
+:1070700000003821104300093231FFFF02201021A7
+:107080008FBF00208FB3001C8FB200188FB1001487
+:107090008FB0001003E0000827BD00280E0005E0B7
+:1070A0000000000000408821022010218FBF002036
+:1070B0008FB3001C8FB200188FB100148FB0001076
+:1070C00003E0000827BD0028000424003C03600002
+:1070D000AC603D0810A00002348210063482101605
+:1070E00003E00008AC623D0427BDFFE0AFB0001034
+:1070F000309000FF2E020006AFBF001810400008BD
+:10710000AFB10014001030803C03080024635784A2
+:1071100000C328218CA400000080000800000000AB
+:10712000000020218FBF00188FB100148FB0001015
+:107130000080102103E0000827BD00209791002A5D
+:1071400016200051000020213C020800904200332C
+:107150000A0006BB00000000978D002615A0003134
+:10716000000020210A0006BB2402000897870024A3
+:1071700014E0001A00001821006020212402000100
+:107180001080FFE98FBF0018000429C2004530219C
+:1071900000A6582B1160FFE43C0880003C0720004B
+:1071A000000569C001A76025AD0C00203C038008E4
+:1071B0002402001F2442FFFFAC6000000441FFFDD9
+:1071C0002463000424A5000100A6702B15C0FFF560
+:1071D000000569C00A0006A58FBF00189787001C2C
+:1071E0003C04080024845A58240504000E0006605C
+:1071F00024060001978B002424440001308AFFFFFD
+:107200002569FFFF2D48040000402821150000409B
+:10721000A789002424AC3800000C19C00A0006B964
+:10722000A780001C9787001E3C04080024845AD8BD
+:10723000240504000E00066024060001979900262C
+:10724000244400013098FFFF272FFFFF2F0E04007A
+:107250000040882115C0002CA78F0026A780001EA3
+:107260003A020003262401003084FFFF0E00068D41
+:107270002C4500010011F8C027F00100001021C0CA
+:107280000A0006BB240200089785002E978700227B
+:107290003C04080024845B580E00066024060001AC
+:1072A0009787002A8F89002C2445000130A8FFFF12
+:1072B00024E3FFFF0109302B0040802114C0001897
+:1072C000A783002AA7800022978500300E000F7543
+:1072D00002002021244A05003144FFFF0E00068DE4
+:1072E000240500013C05080094A500320E000F752E
+:1072F00002002021244521003C0208009042003376
+:107300000A0006BB000521C00A0006F3A784001E80
+:1073100024AC3800000C19C00A0006B9A784001C70
+:107320000A00070DA7850022308400FF27BDFFE873
+:107330002C820006AFBF0014AFB000101040001543
+:1073400000A03821000440803C0308002463579CBF
+:10735000010328218CA40000008000080000000028
+:1073600024CC007F000751C2000C59C23170FFFFCE
+:107370002547C40030E5FFFF2784001C02003021B0
+:107380000E0005B52407000197860028020620217B
+:10739000A78400288FBF00148FB0001003E00008FE
+:1073A00027BD00183C0508008CA50030000779C2F5
+:1073B0000E00038125E4DF003045FFFF3C04080098
+:1073C00024845B58240600010E0005B52407000143
+:1073D000978E002A8FBF00148FB0001025CD0001BA
+:1073E00027BD001803E00008A78D002A0007C9C2C6
+:1073F0002738FF00001878C231F0FFFF3C04080076
+:1074000024845AD802002821240600010E0005B564
+:1074100024070001978D0026260E0100000E84002F
+:1074200025AC00013C0B6000A78C0026AD603D0838
+:1074300036040006000030213C0760008CE23D0469
+:10744000305F000617E0FFFD24C9000100061B00A5
+:10745000312600FF006440252CC50004ACE83D0443
+:1074600014A0FFF68FBF00148FB0001003E00008D7
+:1074700027BD0018000751C22549C8002406000195
+:10748000240700013C04080024845A580E0005B566
+:107490003125FFFF978700248FBF00148FB00010A5
+:1074A00024E6000127BD001803E00008A786002499
+:1074B0003C0660183C090800252900FCACC9502C8A
+:1074C0008CC850003C0580003C020002350700805B
+:1074D000ACC750003C04080024841FE03C030800B3
+:1074E00024631F98ACA50008ACA2000C3C01080066
+:1074F000AC2459A43C010800AC2359A803E00008BF
+:107500002402000100A030213C1C0800279C59AC3B
+:107510003C0C04003C0B0002008B3826008C4026FB
+:107520002CE200010007502B2D050001000A4880C5
+:107530003C030800246359A4004520250123182199
+:107540001080000300001021AC660000240200013E
+:1075500003E00008000000003C1C0800279C59AC18
+:107560003C0B04003C0A0002008A3026008B3826BF
+:107570002CC200010006482B2CE5000100094080C8
+:107580003C030800246359A4004520250103182169
+:1075900010800005000010213C0C0800258C1F986D
+:1075A000AC6C00002402000103E0000800000000B1
+:1075B0003C0900023C080400008830260089382677
+:1075C0002CC30001008028212CE400010083102539
+:1075D0001040000B000030213C1C0800279C59ACD7
+:1075E0003C0A80008D4E00082406000101CA68256F
+:1075F000AD4D00088D4C000C01855825AD4B000C9D
+:1076000003E0000800C010213C1C0800279C59AC76
+:107610003C0580008CA6000C0004202724020001F9
+:1076200000C4182403E00008ACA3000C3C020002D4
+:107630001082000B3C0560003C070400108700032B
+:107640000000000003E00008000000008CA908D042
+:10765000240AFFFD012A402403E00008ACA808D05A
+:107660008CA408D02406FFFE0086182403E000083E
+:10767000ACA308D03C05601A34A600108CC300806F
+:1076800027BDFFF88CC50084AFA3000093A40000C1
+:107690002402001010820003AFA5000403E00008DC
+:1076A00027BD000893A7000114E0001497AC000266
+:1076B00097B800023C0F8000330EFFFC01CF682119
+:1076C000ADA50000A3A000003C0660008CC708D058
+:1076D0002408FFFE3C04601A00E82824ACC508D04A
+:1076E0008FA300048FA200003499001027BD00086A
+:1076F000AF22008003E00008AF2300843C0B800031
+:10770000318AFFFC014B48218D2800000A00080C3B
+:10771000AFA8000427BDFFE8AFBF00103C1C080065
+:10772000279C59AC3C0580008CA4000C8CA2000462
+:107730003C0300020044282410A0000A00A31824DF
+:107740003C0604003C0400021460000900A610245A
+:107750001440000F3C0404000000000D3C1C080015
+:10776000279C59AC8FBF001003E0000827BD00180C
+:107770003C0208008C4259A40040F80900000000B7
+:107780003C1C0800279C59AC0A0008358FBF00102C
+:107790003C0208008C4259A80040F8090000000093
+:1077A0000A00083B000000003C0880008D0201B880
+:1077B0000440FFFE35090180AD2400003C031000A9
+:1077C00024040040AD250004A1240008A1260009DE
+:1077D000A527000A03E00008AD0301B83084FFFFCD
+:1077E0000080382130A5FFFF000020210A00084555
+:1077F000240600803087FFFF8CA400002406003898
+:107800000A000845000028218F8300788F860070C9
+:107810001066000B008040213C07080024E75B68ED
+:10782000000328C000A710218C440000246300013D
+:10783000108800053063000F5466FFFA000328C06B
+:1078400003E00008000010213C07080024E75B6CFF
+:1078500000A7302103E000088CC200003C03900028
+:1078600034620001008220253C038000AC640020CB
+:107870008C65002004A0FFFE0000000003E000086B
+:10788000000000003C0280003443000100832025FA
+:1078900003E00008AC44002027BDFFE0AFB10014B6
+:1078A0003091FFFFAFB00010AFBF001812200013DF
+:1078B00000A080218CA20000240400022406020003
+:1078C0001040000F004028210E0007250000000096
+:1078D00000001021AE000000022038218FBF0018E8
+:1078E0008FB100148FB0001000402021000028212B
+:1078F000000030210A00084527BD00208CA20000AE
+:10790000022038218FBF00188FB100148FB00010F3
+:107910000040202100002821000030210A000845F5
+:1079200027BD002000A010213087FFFF8CA5000498
+:107930008C4400000A000845240600068F83FD9C45
+:1079400027BDFFE8AFBF0014AFB00010906700087C
+:10795000008010210080282130E600400000202116
+:1079600010C000088C5000000E0000BD0200202155
+:10797000020020218FBF00148FB000100A000548BC
+:1079800027BD00180E0008A4000000000E0000BD76
+:1079900002002021020020218FBF00148FB00010B0
+:1079A0000A00054827BD001827BDFFE0AFB0001052
+:1079B0008F90FD9CAFBF001CAFB20018AFB1001498
+:1079C00092060001008088210E00087230D2000467
+:1079D00092040005001129C2A6050000348300406E
+:1079E000A20300050E00087C022020210E00054A9B
+:1079F0000220202124020001AE02000C02202821D6
+:107A0000A602001024040002A602001224060200AE
+:107A1000A60200140E000725A60200161640000F4D
+:107A20008FBF001C978C00743C0B08008D6B007896
+:107A30002588FFFF3109FFFF256A0001012A382B45
+:107A400010E00006A78800743C0F6006240E0016A4
+:107A500035ED0010ADAE00508FBF001C8FB2001886
+:107A60008FB100148FB0001003E0000827BD002084
+:107A700027BDFFE0AFB10014AFBF0018AFB00010DA
+:107A80001080000400A088212402008010820007DA
+:107A9000000000000000000D8FBF00188FB100141F
+:107AA0008FB0001003E0000827BD00200E00087210
+:107AB00000A020218F86FD9C0220202190C500057A
+:107AC0000E00087C30B000FF2403003E1603FFF1D7
+:107AD0003C0680008CC401780480FFFE34C801405D
+:107AE000240900073C071000AD11000002202021EE
+:107AF000A10900048FBF00188FB100148FB00010CF
+:107B0000ACC701780A0008C527BD002027BDFFE0EB
+:107B1000AFB00010AFBF0018AFB100143C10800030
+:107B20008E110020000000000E00054AAE04002067
+:107B3000AE1100208FBF00188FB100148FB000105D
+:107B400003E0000827BD00203084FFFF00803821BB
+:107B50002406003500A020210A0008450000282145
+:107B60003084FFFF008038212406003600A0202149
+:107B70000A0008450000282127BDFFD0AFB500242A
+:107B80003095FFFFAFB60028AFB40020AFBF002C88
+:107B9000AFB3001CAFB20018AFB10014AFB000100B
+:107BA00030B6FFFF12A000270000A0218F920058DE
+:107BB0008E4300003C0680002402004000033E0289
+:107BC00000032C0230E4007F006698241482001D1C
+:107BD00030A500FF8F8300682C68000A1100001098
+:107BE0008F8D0044000358803C0C0800258C57B84A
+:107BF000016C50218D4900000120000800000000A8
+:107C000002D4302130C5FFFF0E0008522404008446
+:107C1000166000028F920058AF8000688F8D00447C
+:107C20002659002026980001032090213314FFFFDD
+:107C300015A00004AF9900580295202B1480FFDC9A
+:107C400000000000028010218FBF002C8FB600289A
+:107C50008FB500248FB400208FB3001C8FB20018A2
+:107C60008FB100148FB0001003E0000827BD003072
+:107C70002407003414A70149000000009247000EB9
+:107C80008F9FFDA08F90FD9C24181600A3E700197C
+:107C90009242000D3C0880003C07800CA3E20018D3
+:107CA000964A00123C0D60003C117FFFA60A005C62
+:107CB000964400103623FFFF240200053099FFFF91
+:107CC000AE1900548E46001CAD1800288CEF000041
+:107CD0008DAE444801E6482601C93021AE06003881
+:107CE0008E05003824CB00013C0E7F00AE05003C21
+:107CF0008E0C003CAFEC0004AE0B00208E13002075
+:107D0000AE13001CA3E0001BAE03002CA3E2001284
+:107D10008E4A001424130050AE0A00348E0400343E
+:107D2000AFE400148E590018AE1900489258000CA8
+:107D3000A218004E920D000835AF0020A20F0008D7
+:107D40008E090018012E282434AC4000AE0C001817
+:107D5000920B0000317200FF1253027F2403FF8058
+:107D60003C04080024845BE80E0008AA0000000020
+:107D70003C1108008E315BE80E00087202202021C1
+:107D80002405000424080001A2050025022020216A
+:107D90000E00087CA20800053C0580008CB001782C
+:107DA0000600FFFE8F92005834AE0140240F0002FF
+:107DB0003C091000ADD10000A1CF0004ACA90178AE
+:107DC0000A000962AF8000682CAD003751A0FF9413
+:107DD0008F8D0044000580803C110800263157E05B
+:107DE000021178218DEE000001C0000800000000A3
+:107DF0002411000414B1008C3C0780003C080800EA
+:107E00008D085BE88F86FD9CACE800208E4500085D
+:107E10008F99FDA0240D0050ACC500308E4C000899
+:107E2000ACCC00508E4B000CACCB00348E43001019
+:107E3000ACC300388E4A0010ACCA00548E42001405
+:107E4000ACC2003C8E5F0018AF3F00048E50001C97
+:107E5000ACD0002090C40000309800FF130D024AFF
+:107E6000000000008CC400348CD00030009030231F
+:107E700004C000F12404008C126000EE2402000310
+:107E80000A000962AF8200682419000514B900666F
+:107E90003C0580003C0808008D085BE88F86FD9C4F
+:107EA000ACA800208E4C00048F8AFDA0240720007F
+:107EB000ACCC001C924B000824120008A14B001906
+:107EC0008F82005890430009A14300188F85005805
+:107ED00090BF000A33E400FF1092001028890009C7
+:107EE000152000BA240E0002240D0020108D000B76
+:107EF000340780002898002117000008240740005C
+:107F000024100040109000053C0700012419008057
+:107F1000109900023C070002240740008CC20018A0
+:107F20003C03FF00004350240147F825ACDF001854
+:107F300090B2000BA0D200278F8300589464000CED
+:107F4000108001FE000000009467000C3C1F8000C0
+:107F50002405FFBFA4C7005C9063000E2407000443
+:107F6000A0C300088F820058904A000FA0CA0009E1
+:107F70008F8900588D3200108FE400740244C823AA
+:107F8000ACD900588D300014ACD0002C95380018B6
+:107F9000330DFFFFACCD00409531001A322FFFFFAB
+:107FA000ACCF00448D2E001CACCE00489128000EB2
+:107FB000A0C8000890CC000801855824126001B6C2
+:107FC000A0CB00088F9200580A000962AF870068B2
+:107FD0002406000614A600143C0E80003C0F080086
+:107FE0008DEF5BE88F85FD98ADCF00208E4900189E
+:107FF0008F86FD9C8F8BFDA0ACA900008CC800383B
+:1080000024040005ACA800048CCC003C1260008164
+:10801000AD6C00000A000962AF84006824110007FB
+:1080200010B1004B240400063C05080024A55BE8C1
+:108030000E000881240400818F9200580013102B39
+:108040000A000962AF820068241F002314BFFFF6F4
+:108050003C0C80003C0508008CA55BE88F8BFDA0E4
+:10806000AD8500208F91FD9C8E4600042564002084
+:1080700026450014AE260028240600030E000F81BA
+:10808000257000308F87005802002021240600034D
+:108090000E000F8124E500083C04080024845BE8FE
+:1080A0000E0008AA0000000092230000240A0050DD
+:1080B000306200FF544AFFE18F9200580E000F6CAF
+:1080C000000000000A000A6A8F920058240800335A
+:1080D00014A800323C0380003C1108008E315BE89C
+:1080E0008F8FFDA0AC7100208E420008240D002867
+:1080F0008F89FD9CADE200308E4A000C24060009F9
+:10810000ADEA00348E5F0010ADFF00388E440014DD
+:10811000ADE400208E590018ADF900248E58001CE3
+:10812000ADF80028A1ED00118E4E00041260003160
+:10813000AD2E00288F9200580A000962AF860068B1
+:10814000240D002214ADFFB8000000002404000735
+:108150003C1008008E105BE83C188000AF10002037
+:108160005660FEAEAF8400683C04080024845BE8DF
+:108170000E0008AA241300508F84FD9C90920000EA
+:10818000325900FF1333014B000000008F9200585A
+:10819000000020210A000962AF8400683C05080045
+:1081A00024A55BE80E000858240400810A000A6A2E
+:1081B0008F92005802D498213265FFFF0E000852BA
+:1081C000240400840A0009628F920058108EFF5325
+:1081D000240704002887000310E00179241100041B
+:1081E000240F0001548FFF4D240740000A000A228B
+:1081F000240701003C05080024A55BE80E0008A444
+:10820000240400828F920058000030210A00096285
+:10821000AF8600683C04080024845BE88CC2003808
+:108220000E0008AA8CC3003C8F9200580A000AC0B6
+:1082300000002021240400823C05080024A55BE8FE
+:108240000E0008A4000000008F92005800001021CA
+:108250000A000962AF8200688E5000048F91FD9C75
+:108260003C078000ACF00020922C00050200282181
+:10827000318B0002156001562404008A8F92FDA004
+:108280002404008D9245001B30A6002014C001502C
+:1082900002002821922E00092408001231C900FF93
+:1082A0001128014B240400810E00087202002021D5
+:1082B0009258001B240F000402002021370D0042B9
+:1082C000A24D001B0E00087CA22F00253C0580005B
+:1082D0008CA401780480FFFE34B90140241F000201
+:1082E000AF300000A33F00048F9200583C101000F4
+:1082F000ACB001780A000A6B0013102B8E500004FA
+:108300008F91FD9C3C038000AC700020922A0005F8
+:108310000200282131420002144000172404008A80
+:10832000922C00092412000402002821318B00FF46
+:1083300011720011240400810E0008720200202135
+:108340008F89FDA0240800122405FFFE912F001B39
+:108350000200202135EE0020A12E001BA2280009DA
+:108360009226000500C538240E00087CA2270005CF
+:1083700002002821000020210E0009330000000027
+:108380000A000A6A8F9200588E4C00043C07800055
+:108390003C10080026105BE8ACEC00203C01080013
+:1083A000AC2C5BE8924B0003317100041220013BBE
+:1083B0008F84FD9C24020006A0820009924F001BBE
+:1083C000240EFFC031E9003F012E4025A08800089F
+:1083D0009245000330A6000114C0013200000000E5
+:1083E0008E420008AE0200083C0208008C425BF09E
+:1083F000104001318F90FDA0000219C28F8DFD9CAD
+:10840000A603000C8E4A000C24180001240400145A
+:10841000AE0A002C8E420010AE02001C965F0016C1
+:10842000A61F003C96590014A619003EADB8000CDA
+:10843000A5B80010A5B80012A5B80014A5B800167C
+:1084400012600144A2040011925100033232000272
+:108450002E5300018F920058266200080A0009621C
+:10846000AF8200688E4400043C1980003C068008FE
+:10847000AF2400208E45000890D80000240D005045
+:10848000331100FF122D009C2407008824060009E8
+:108490000E000845000000000A000A6A8F9200588A
+:1084A0008E5000043C0980003C118008AD30002053
+:1084B0009228000024050050310400FF10850110AF
+:1084C0002407008802002021000028210E00084512
+:1084D0002406000E922D00002418FF80020028219F
+:1084E00001B8802524040004240600300E0007256E
+:1084F000A23000000A000A6A8F9200588E500004D1
+:108500008F91FDA03C028000AC500020923F001BE8
+:1085100033F900101320006C240700810200202191
+:10852000000028212406001F0E000845000000005E
+:108530000A000A6A8F9200588E44001C0E00085DE3
+:1085400000000000104000E3004048218F880058E0
+:1085500024070089012020218D05001C240600012C
+:108560000E000845000000000A000A6A8F920058B9
+:10857000964900023C10080026105BE831280004F0
+:10858000110000973C0460008E4E001C3C0F8000E0
+:10859000ADEE00203C010800AC2E5BE896470002DF
+:1085A00030E40001148000E6000000008E42000468
+:1085B000AE0200083C1008008E105BF0120000ECC8
+:1085C0003C0F80008F92FD9C241000018E4E0018FD
+:1085D0008F8DFDA08F9FFD9801CF4825AE490018D3
+:1085E000A2400005AE50000C3C0808008D085BF06E
+:1085F0008F840058A6500010000839C2A6500012FF
+:10860000A6500014A6500016A5A7000C8C8C0008DC
+:108610008F8B00588F8A0058ADAC002C8D63000CF6
+:1086200024070002ADA3001C91460010A1A6001172
+:108630008F82005890450011A3E500088F990058DB
+:1086400093380012A258004E8F910058922F0013B9
+:10865000A1AF00128F920058964E0014A5AE003CB8
+:1086600096490016A5A9003E8E480018ADA8001432
+:108670005660FD6AAF8700683C05080024A55BE8EA
+:108680000E000881000020218F9200580000382140
+:108690000A000962AF8700683C05080024A55BE872
+:1086A0000E0008A4240400828F9200580A000A4D8C
+:1086B000000038210E000F6C000000008F9200585F
+:1086C0000A000AC0000020210E00087202002021CA
+:1086D0009223001B02002021346A00100E00087C47
+:1086E000A22A001B000038210200202100002821BE
+:1086F0000A000BA52406001F9242000C305F000107
+:1087000013E0000300000000964A000EA4CA002CEB
+:10871000924B000C316300025060000600003821CB
+:108720008E470014964C0012ACC7001CA4CC001A53
+:10873000000038210A000B7F240600093C050800D0
+:1087400024A55BE80E0008A42404008B8F92005837
+:108750000A000A4D0013382B3C0C08008D8C5BE896
+:1087600024DFFFFE25930100326B007F016790211B
+:1087700002638824AD110028AE4600E0AE4000E45C
+:108780000A0009B3AE5F001CACC000543C0D0800E9
+:108790008DAD5BE83C18800C37090100ACED00287A
+:1087A0008E510014AD3100E08E4F0014AD2F00E467
+:1087B0008E4E001025C7FFFE0A0009F4AD27001CED
+:1087C0005491FDD6240740000A000A222407100015
+:1087D0000E00092D000000000A000A6A8F9200585E
+:1087E0008C83442C3C12DEAD3651BEEF3C010800B8
+:1087F000AC205BE810710062000000003C196C6264
+:1088000037387970147800082404000297850074C2
+:108810009782006C2404009200A2F82B13E0001948
+:1088200002002821240400020E00069524050200FF
+:108830003C068000ACC200203C010800AC225BE892
+:108840001040000D8F8C0058240A002824040003D7
+:10885000918B0010316300FF546A00012404000171
+:108860000E0000810000000010400004240400837A
+:108870000A000BC28F920058240400833C050800B4
+:1088800024A55BE80E000881000000008F920058CC
+:108890000013382B0A000962AF8700680A000B49F1
+:1088A000240200128E4400080E00085D0000000043
+:1088B0000A000B55AE0200083C05080024A55BE841
+:1088C0000E000858240400878F9200580A000B728B
+:1088D0000013102B240400040E000695240500301C
+:1088E0001440002A004048218F8800582407008344
+:1088F000012020218D05001C0A000BB32406000175
+:108900008F8300788F8600701066FEEE000038219D
+:108910003C07080024E75B6C000320C00087282187
+:108920008CAE000011D0005D246F000131E3000F18
+:108930005466FFFA000320C00A000B8C00003821A7
+:108940008E4400040E00085D000000000A000BC801
+:10895000AE0200083C05080024A55BE80E0008A450
+:10896000240400828F9200580A000B72000010212C
+:108970003C05080024A55BE80A000C7C2404008761
+:108980008C83442C0A000C5B3C196C628F88005865
+:108990003C0780083C0C8000240B0050240A000196
+:1089A000AD820020A0EB0000A0EA000191030004CA
+:1089B000A0E3001891040005A0E400199106000648
+:1089C0003C04080024845B6CA0E6001A91020007B6
+:1089D0003C06080024C65B68A0E2001B9105000865
+:1089E000A0E5001C911F0009A0FF001D9119000ABD
+:1089F000A0F9001E9118000BA0F8001F9112000CA6
+:108A0000A0F200209111000DA0F100219110000EA4
+:108A1000A0F00022910F000FA0EF0023910E001094
+:108A2000A0EE0024910D0011A0ED0025950C00147E
+:108A3000A4EC0028950B00168F8A00708F920078A6
+:108A4000A4EB002A95030018000A10C02545000178
+:108A5000A4E3002C8D1F001C0044C0210046C82147
+:108A600030A5000FAF3F0000AF09000010B20006B4
+:108A7000AF850070000038218D05001C01202021E9
+:108A80000A000BB32406000124AD000131A7000F3A
+:108A9000AF8700780A000CF9000038213C06080076
+:108AA00024C65B680086902100003821ACA000003D
+:108AB0000A000B8CAE4000003C0482013C036000C5
+:108AC00034820E02AC603D68AF80009803E000087D
+:108AD000AC623D6C27BDFFE8AFB000103090FFFFE7
+:108AE000001018422C620041AFBF00141440000275
+:108AF00024040080240300403C010800AC300060E6
+:108B00003C010800AC2300640E000F7500602821B2
+:108B1000244802BF2409FF8001092824001039805D
+:108B2000001030408FBF00148FB0001000A720212C
+:108B300000861821AF8300803C010800AC25005856
+:108B40003C010800AC24005C03E0000827BD0018CD
+:108B5000308300FF30C6FFFF30E400FF3C08800098
+:108B60008D0201B80440FFFE000354000144382583
+:108B70003C09600000E920253C031000AD050180A0
+:108B8000AD060184AD04018803E00008AD0301B81F
+:108B90008F8500583C0A6012354800108CAC0004E8
+:108BA0003C0D600E35A60010318B00062D690001CA
+:108BB000AD0900C48CA70004ACC731808CA20008AA
+:108BC00094A40002ACC231848CA3001C0460000396
+:108BD000A784009003E00008000000008CAF00189C
+:108BE000ACCF31D08CAE001C03E00008ACCE31D449
+:108BF0008F8500588F87FF288F86FF308CAE00044A
+:108C00003C0F601235E80010ACEE00788CAD000827
+:108C1000ACED007C8CAC0010ACCC004C8CAB000CF0
+:108C2000ACCB004894CA00543C0208008C4200447B
+:108C300025490001A4C9005494C400543083FFFFA7
+:108C400010620017000000003C0208008C42004047
+:108C5000A4C200528CA30018ACE300308CA2001414
+:108C6000ACE2002C8CB90018ACF900388CB80014B8
+:108C700024050001ACF800348D0600BC50C5001975
+:108C80008D0200B48D0200B8A4E2004894E40048CC
+:108C9000A4E4004A94E800EA03E000083102FFFF80
+:108CA0003C0208008C420024A4C00054A4C200521C
+:108CB0008CA30018ACE300308CA20014ACE2002CB2
+:108CC0008CB90018ACF900388CB8001424050001E8
+:108CD000ACF800348D0600BC54C5FFEB8D0200B823
+:108CE0008D0200B4A4E2004894E40048A4E4004AE1
+:108CF00094E800EA03E000083102FFFF8F86005885
+:108D00003C0480008CC900088CC80008000929C0F8
+:108D1000000839C0AC87002090C30007306200040F
+:108D20001040003EAF85009490CB0007316A0008E8
+:108D30001140003D8F87FF2C8CCD000C8CCE001491
+:108D400001AE602B11800036000000008CC2000CC8
+:108D5000ACE200708CCB00188F85FF288F88FF3025
+:108D6000ACEB00748CCA00102402FFF8ACAA00D847
+:108D70008CC9000CAD0900608CC4001CACA400D0F0
+:108D800090E3007C0062C824A0F9007C90D8000722
+:108D9000330F000811E000040000000090ED007C9B
+:108DA00035AC0001A0EC007C90CF000731EE000153
+:108DB00011C000060000000090E3007C241800347D
+:108DC00034790002A0F9007CACB800DC90C2000746
+:108DD0003046000210C000040000000090E8007C53
+:108DE00035040004A0E4007C90ED007D3C0B600E97
+:108DF000356A001031AC003FA0EC007D8D4931D4C4
+:108E00003127000110E00002240E0001A0AE00098D
+:108E100094AF00EA03E0000831E2FFFF8F87FF2CE8
+:108E20000A000DAF8CC200140A000DB0ACE0007057
+:108E30008F8C005827BDFFD8AFB3001CAFB200180D
+:108E4000AFB00010AFBF0020AFB10014918F00157C
+:108E50003C13600E3673001031EB000FA38B009CA7
+:108E60008D8F00048D8B0008959F0012959900103E
+:108E70009584001A9598001E958E001C33EDFFFF17
+:108E8000332AFFFF3089FFFF3308FFFF31C7FFFFA1
+:108E90003C010800AC2D00243C010800AC29004432
+:108EA0003C010800AC2A0040AE683178AE67317CE6
+:108EB00091850015959100163C12601236520010F3
+:108EC00030A200FF3230FFFFAE623188AE5000B4F6
+:108ED00091830014959F0018240600010066C804C1
+:108EE00033F8FFFFAE5900B8AE5800BC918E0014A5
+:108EF000AF8F00843C08600631CD00FFAE4D00C04E
+:108F0000918A00159584000E3C07600A314900FFE4
+:108F1000AF8B00883084FFFFAE4900C835110010C8
+:108F20000E000D1034F004103C0208008C4200606A
+:108F30003C0308008C6300643C0608008CC60058A3
+:108F40003C0508008CA5005C8F8400808FBF00204A
+:108F5000AE23004CAE65319CAE030054AE4500DC40
+:108F6000AE6231A0AE6331A4AE663198AE22004845
+:108F70008FB3001CAE0200508FB10014AE4200E06F
+:108F8000AE4300E4AE4600D88FB000108FB2001898
+:108F90000A00057D27BD0028978500929783007CF5
+:108FA00027BDFFE8AFB0001000A3102BAFBF001427
+:108FB000240400058F900058104000552409000239
+:108FC0000E0006958F850080AF8200942404000374
+:108FD0001040004F240900023C0680000E00008172
+:108FE000ACC2002024070001240820001040004DDE
+:108FF00024040005978E00928F8AFF2C24090050CC
+:1090000025C50001A7850092A14900003C0D08007C
+:109010008DAD0064240380008F84FF28000D66005E
+:10902000AD4C0018A5400006954B000A8F85FF3017
+:109030002402FF8001633024A546000A915F000AE4
+:109040000000482103E2C825A159000AA0A0000899
+:10905000A140004CA08000D5961800029783009094
+:109060003C020004A49800EA960F00022418FFBFF7
+:1090700025EE2401A48E00BE8E0D0004ACAD00448C
+:109080008E0C0008ACAC0040A4A00050A4A000547A
+:109090008E0B000C240C0030AC8B00288E060010C8
+:1090A000AC860024A480003EA487004EA487005014
+:1090B000A483003CAD420074AC8800D8ACA800602A
+:1090C000A08700FC909F00D433F9007FA09900D4C2
+:1090D000909000D402187824A08F00D4914E007C88
+:1090E00035CD0001A14D007C938B009CAD480070F4
+:1090F000AC8C00DCA08B00D68F8800888F87008422
+:10910000AC8800C4AC8700C8A5400078A540007AB0
+:109110008FBF00148FB000100120102103E0000861
+:1091200027BD00188F8500940E0007258F860080CC
+:109130000A000E9F2409000227BDFFE0AFB0001017
+:109140008F900058AFB10014AFBF00188E09000413
+:109150000E00054A000921C08E0800048F84FF28F4
+:109160008F82FF30000839C03C068000ACC7002069
+:10917000948500EA904300131460001C30B1FFFF97
+:109180008F8CFF2C918B0008316A00401540000B3A
+:10919000000000008E0D0004022030218FBF001857
+:1091A0008FB100148FB00010240400220000382179
+:1091B000000D29C00A000D2F27BD00200E000098C9
+:1091C000000000008E0D0004022030218FBF001827
+:1091D0008FB100148FB00010240400220000382149
+:1091E000000D29C00A000D2F27BD00200E000090A1
+:1091F000000000008E0D0004022030218FBF0018F7
+:109200008FB100148FB00010240400220000382118
+:10921000000D29C00A000D2F27BD002027BDFFE04B
+:10922000AFB200183092FFFFAFB00010AFBF001C0C
+:10923000AFB100141240001E000080218F8600583C
+:109240008CC500002403000600053F02000514023F
+:1092500030E4000714830016304500FF2CA80006F8
+:1092600011000040000558803C0C0800258C58BCBB
+:10927000016C50218D490000012000080000000011
+:109280008F8E0098240D000111CD005024020002A1
+:10929000AF820098260900013130FFFF24C800206A
+:1092A0000212202B010030211480FFE5AF88005806
+:1092B000020010218FBF001C8FB200188FB1001464
+:1092C0008FB0001003E0000827BD00209387007EC8
+:1092D00054E00034000030210E000DE700000000D3
+:1092E0008F8600580A000EFF240200018F87009825
+:1092F0002405000210E50031240400130000282199
+:1093000000003021240700010E000D2F0000000096
+:109310000A000F008F8600588F83009824020002F5
+:109320001462FFF6240400120E000D9A00000000E3
+:109330008F85009400403021240400120E000D2F70
+:10934000000038210A000F008F8600588F83009894
+:109350002411000310710029241F0002107FFFCE8A
+:1093600026090001240400100000282100003021FB
+:109370000A000F1D240700018F91009824060002A7
+:109380001626FFF9240400100E000E410000000014
+:10939000144000238F9800588F8600580A000EFF53
+:1093A00024020003240400140E000D2F00002821C5
+:1093B0008F8600580A000EFF240200020E000EA93C
+:1093C000000000000A000F008F8600580E000D3FBD
+:1093D00000000000241900022404001400002821C9
+:1093E0000000302100003821AF9900980E000D2FA9
+:1093F000000000000A000F008F8600580E000D5775
+:10940000000000008F8500942419000200403021E4
+:1094100024040010000038210A000F56AF9900986C
+:109420000040382124040010970F0002000028217A
+:109430000E000D2F31E6FFFF8F8600580A000F0047
+:10944000AF9100988F84FF2C3C077FFF34E6FFFF2D
+:109450008C8500182402000100A61824AC83001893
+:1094600003E00008A08200053084FFFF30A5FFFF65
+:109470001080000700001821308200011040000217
+:1094800000042042006518211480FFFB00052840DD
+:1094900003E000080060102110C000070000000079
+:1094A0008CA2000024C6FFFF24A50004AC820000AB
+:1094B00014C0FFFB2484000403E000080000000047
+:1094C00010A0000824A3FFFFAC86000000000000ED
+:1094D000000000002402FFFF2463FFFF1462FFFA74
+:1094E0002484000403E0000800000000000411C010
+:1094F00003E000082442024027BDFFE8AFB000109F
+:1095000000808021AFBF00140E000F9600A0202124
+:1095100000504821240AFF808FBF00148FB0001034
+:10952000012A30243127007F3C08800A3C042100B6
+:1095300000E8102100C428253C03800027BD001846
+:10954000AC650024AF820038AC400000AC6500245C
+:1095500003E00008AC4000403C0D08008DAD005811
+:1095600000056180240AFF8001A45821016C482174
+:10957000012A30243127007F3C08800C3C04210064
+:1095800000E8102100C428253C038000AC650028B9
+:10959000AF82003403E00008AC40002430A5FFFF98
+:1095A0003C0680008CC201B80440FFFE3C086015F8
+:1095B00000A838253C031000ACC40180ACC0018475
+:1095C000ACC7018803E00008ACC301B83C0D08003B
+:1095D0008DAD005800056180240AFF8001A4582148
+:1095E000016C4021010A4824000931403107007F05
+:1095F00000C728253C04200000A418253C02800058
+:10960000AC43083003E00008AF80003427BDFFE81A
+:10961000AFB0001000808021AFBF00140E000F9685
+:1096200000A0202100504821240BFF80012B502452
+:10963000000A39403128007F3C0620008FBF00140B
+:109640008FB0001000E8282534C2000100A21825C0
+:109650003C04800027BD0018AC83083003E00008FC
+:10966000AF8000383C0580088CA700603C0680086D
+:109670000087102B144000112C8340008CA8006040
+:109680002D0340001060000F240340008CC90060CF
+:109690000089282B14A00002008018218CC30060D0
+:1096A00000035A42000B30803C0A0800254A59202A
+:1096B00000CA202103E000088C8200001460FFF340
+:1096C0002403400000035A42000B30803C0A08008B
+:1096D000254A592000CA202103E000088C8200009E
+:1096E0003C05800890A60008938400AB24C20001CA
+:1096F000304200FF3043007F1064000C0002382726
+:10970000A0A200083C0480008C85017804A0FFFE24
+:109710008F8A00A0240900023C081000AC8A014096
+:10972000A089014403E00008AC8801780A00101BFE
+:1097300030E2008027BDFFD8AFB200188F9200A49E
+:10974000AFBF0020AFB3001CAFB00010AFB100142A
+:109750008F9300348E5900283C1000803C0EFFEFA0
+:10976000AE7900008E580024A260000A35CDFFFFBC
+:10977000AE7800049251002C3C0BFF9F356AFFFF2E
+:10978000A271000C8E6F000C3C080040A271000B0F
+:1097900001F06025018D4824012A382400E8302595
+:1097A000AE66000C8E450004AE6000183C0400FF5D
+:1097B000AE6500148E43002C3482FFFFA6600008C3
+:1097C0000062F824AE7F00108E5900088F9000A030
+:1097D000964E0012AE7900208E51000C31D83FFF1A
+:1097E00000187980AE7100248E4D001401F06021C4
+:1097F00031CB0001AE6D00288E4A0018000C41C22A
+:10980000000B4B80AE6A002C8E46001C01093821EB
+:10981000A667001CAE660030964500028E4400200C
+:10982000A665001EAE64003492430033306200042B
+:1098300054400006924700003C0280083443010077
+:109840008C7F00D0AE7F0030924700008F860038BA
+:10985000A0C700309245003330A4000250800007BA
+:10986000925100018F880038240BFF80910A00304C
+:10987000014B4825A1090030925100018F9000381A
+:10988000240CFFBF2404FFDFA21100318F8D0038AC
+:109890003C1880083711008091AF003C31EE007F0A
+:1098A000A1AE003C8F890038912B003C016C502404
+:1098B000A12A003C8F9F00388E68001493E6003C7C
+:1098C0002D0700010007114000C4282400A218251C
+:1098D000A3E3003C8F87003896590012A4F90032A8
+:1098E0008E450004922E007C30B0000300107823D7
+:1098F00031ED000300AD102131CC000215800002D3
+:1099000024460034244600303C0280083443008062
+:10991000907F007C00BFC824333800041700000289
+:1099200024C2000400C010218F98003824190002BE
+:10993000ACE20034A3190000924F003F8F8E003834
+:109940003C0C8008358B0080A1CF00018F9100383E
+:10995000924D003F8E440004A62D0002956A005CE3
+:109960000E000FF43150FFFF00024B800209382532
+:109970003C08420000E82825AE2500048E4400384B
+:109980008F850038ACA400188E460034ACA6001CAD
+:10999000ACA0000CACA00010A4A00014A4A0001661
+:1099A000A4A00020A4A00022ACA000248E62001479
+:1099B00050400001240200018FBF00208FB3001C23
+:1099C0008FB200188FB100148FB00010ACA2000845
+:1099D0000A00101327BD002827BDFFC83C058008DA
+:1099E00034A40080AFBF0034AFBE0030AFB7002C4E
+:1099F000AFB60028AFB50024AFB40020AFB3001C51
+:109A0000AFB20018AFB10014AFB00010948300786B
+:109A10009482007A104300512405FFFF0080F0215A
+:109A20000A0011230080B821108B004D8FBF003435
+:109A30008F8600A03C1808008F18005C2411FF805E
+:109A40003C1680000306782101F18024AED0002C62
+:109A500096EE007A31EC007F3C0D800E31CB7FFF1B
+:109A6000018D5021000B4840012AA82196A4000036
+:109A70003C0808008D0800582405FF8030953FFF02
+:109A800001061821001539800067C8210325F82434
+:109A90003C02010003E290253338007F3C11800C2A
+:109AA000AED20028031190219250000D320F000415
+:109AB00011E0003702E0982196E3007A96E8007AF8
+:109AC00096E5007A2404800031077FFF24E300013B
+:109AD00030627FFF00A4F82403E2C825A6F9007ACB
+:109AE00096E6007A3C1408008E94006030D67FFF22
+:109AF00012D400C1000000008E5800188F8400A00E
+:109B000002A028212713FFFF0E000FCEAE53002C1A
+:109B100097D5007897D4007A12950010000028217C
+:109B20003C098008352401003C0A8008914800085F
+:109B3000908700D53114007F30E400FF0284302B81
+:109B400014C0FFB9268B0001938E00AB268C000158
+:109B5000008E682115ACFFB78F8600A08FBF003440
+:109B60008FBE00308FB7002C8FB600288FB5002431
+:109B70008FB400208FB3001C8FB200188FB1001477
+:109B80008FB0001000A0102103E0000827BD0038AE
+:109B900000C020210E000F99028028218E4B00105A
+:109BA0008E4C00308F84003824090002016C502351
+:109BB000AE4A0010A089000096E3005C8E4400309D
+:109BC0008F9100380E000FF43070FFFF00024380C9
+:109BD000020838253C02420000E22825AE25000498
+:109BE0008E5F00048F8A00388E590000240B000815
+:109BF000AD5F001CAD590018AD40000CAD40001029
+:109C00009246000A240400052408C00030D000FF5A
+:109C1000A550001496580008A55800169251000A45
+:109C20003C188008322F00FFA54F0020964E0008F8
+:109C300037110100A54E0022AD400024924D000BCB
+:109C400031AC00FFA54C0002A14B00018E49003051
+:109C50008F830038240BFFBFAC690008A06400307C
+:109C60008F9000382403FFDF9607003200E8282495
+:109C700000B51025A6020032921F003233F9003FD2
+:109C800037260040A20600328F8C0038AD800034A9
+:109C90008E2F00D0AD8F0038918E003C3C0F7FFF9F
+:109CA00031CD007FA18D003C8F84003835EEFFFF61
+:109CB000908A003C014B4824A089003C8F850038E5
+:109CC00090A8003C01033824A0A7003C8E42003439
+:109CD0008F9100383C038008AE2200408E59002C42
+:109CE0008E5F0030033F3023AE26004492300048A0
+:109CF0003218007FA23800488F8800388E4D00301F
+:109D00008D0C004801AE582401965024014B482583
+:109D1000AD0900489244000AA104004C964700088F
+:109D20008F850038A4A7004E8E5000308E4400303E
+:109D30000E0003818C65006092F9007C0002F940FE
+:109D4000004028210002110003E2302133360002D6
+:109D500012C00003020680210005B0800216802197
+:109D6000926D007C31B30004126000020005708027
+:109D7000020E80218E4B00308F8800382405800031
+:109D8000316A0003000A4823312400030204182129
+:109D9000AD03003496E4007A96F0007A96F1007AEA
+:109DA00032027FFF2447000130FF7FFF0225C824D5
+:109DB000033F3025A6E6007A96F8007A3C120800A8
+:109DC0008E520060330F7FFF11F200180000000078
+:109DD0008F8400A00E000FCE02A028218F8400A047
+:109DE0000E000FDE028028210E001013000000007C
+:109DF0000A00111F0000000096F1007A022480245E
+:109E0000A6F0007A92EF007A92EB007A31EE00FF32
+:109E1000000E69C2000D6027000C51C03169007F3F
+:109E2000012A20250A001119A2E4007A96E6007A98
+:109E300000C5C024A6F8007A92EF007A92F3007A67
+:109E400031F200FF001271C2000E6827000DB1C090
+:109E5000326C007F01962825A2E5007A0A0011D015
+:109E60008F8400A03C0380003084FFFF30A5FFFFFB
+:109E7000AC640018AC65001C03E000088C620014A0
+:109E800027BDFFA03C068008AFBF005CAFBE0058F6
+:109E9000AFB70054AFB60050AFB5004CAFB40048F8
+:109EA000AFB30044AFB20040AFB1003CAFB0003838
+:109EB00034C80100910500D590C700083084FFFF29
+:109EC00030A500FF30E2007F0045182AAFA4001043
+:109ED000A7A00018A7A0002610600055AFA000148E
+:109EE00090CA00083149007F00A9302324D3FFFF26
+:109EF0000013802B8FB400100014902B02128824C2
+:109F0000522000888FB300143C03800894790052DB
+:109F1000947E00508FB60010033EC0230018BC0092
+:109F2000001714030016FC0002C2A82A16A00002A3
+:109F3000001F2C030040282100133C0000072403CD
+:109F400000A4102A5440000100A020212885000907
+:109F500014A000020080A021241400083C0C8008FA
+:109F60008D860048001459808D88004C3C03800089
+:109F70003169FFFF3C0A0010012A202534710400DA
+:109F8000AC660038AF9100A4AC68003CAC64003013
+:109F900000000000000000000000000000000000C1
+:109FA00000000000000000000000000000000000B1
+:109FB0008C6E000031CD002011A0FFFD0014782A26
+:109FC00001F01024104000390000A8213C16800840
+:109FD00092D700083C1280008E44010032F6007FC8
+:109FE0000E000F9902C028218E3900108E44010006
+:109FF0000000902133373FFF0E000FB102E028210F
+:10A00000923800003302003F2C500008520000102C
+:10A0100000008821000210803C030800246358E4FB
+:10A020000043F8218FFE000003C00008000000007C
+:10A0300090CF0008938C00AB31EE007F00AE682318
+:10A04000018D58210A0012172573FFFF0000882197
+:10A050003C1E80008FC401000E000FCE02E02821BC
+:10A060008FC401000E000FDE02C028211220000F55
+:10A070000013802B8F8B00A426A400010004AC00E9
+:10A08000027298230015AC032578004002B4B02A70
+:10A090000013802B241700010300882102D0102414
+:10A0A000AF9800A41440FFC9AFB700143C07800864
+:10A0B00094E200508FAE00103C05800002A288217F
+:10A0C0003C060020A4F10050ACA6003094F40050EF
+:10A0D00094EF005201D51823306CFFFF11F4001EDD
+:10A0E000AFAC00108CEF004C001561808CF500487F
+:10A0F00001EC28210000202100AC582B02A4C02133
+:10A10000030BB021ACE5004CACF600488FB4001056
+:10A110000014902B021288241620FF7C3C03800838
+:10A120008FB300148FBF005C8FBE00583A620001ED
+:10A130008FB700548FB600508FB5004C8FB40048D5
+:10A140008FB300448FB200408FB1003C8FB0003815
+:10A1500003E0000827BD006094FE00548CF2004428
+:10A1600033C9FFFE0009C8C00259F821ACBF003C4A
+:10A170008CE800448CAD003C010D50231940003B9D
+:10A18000000000008CF7004026E20001ACA200387D
+:10A190003C05005034A700103C038000AC67003041
+:10A1A00000000000000000000000000000000000AF
+:10A1B000000000000000000000000000000000009F
+:10A1C0008C7800003316002012C0FFFD3C1180087F
+:10A1D000962200543C1580003C068008304E000159
+:10A1E000000E18C0007578218DEC04003C070800B3
+:10A1F0008CE700443C040020ACCC00488DF40404FF
+:10A20000240B0001ACD4004C10EB0260AEA4003073
+:10A21000963900523C0508008CA5004000B99021F9
+:10A22000A6320052963F005427ED0001A62D00549F
+:10A230009626005430C4FFFF5487FF2F8FB40010C0
+:10A2400030A5FFFF0E0011F4A62000543C070800C3
+:10A250008CE70024963E00520047B82303D74823DA
+:10A26000A62900520A0012198FB400108CE2004097
+:10A270000A0012BE00000000922400012407000121
+:10A280003085007F14A7001C97AD00268E2B00148C
+:10A29000240CC000316A3FFF01AC48243C06080092
+:10A2A0008CC60060012A402531043FFF0086882BC0
+:10A2B00012200011A7A800263C0508008CA5005814
+:10A2C0008F9100A0000439802402FF8000B1182182
+:10A2D0000067F82103E2F02433F8007F3C1280008D
+:10A2E0003C19800EAE5E002C0319702191D0000D38
+:10A2F000360F0004A1CF000D0E001028241200011B
+:10A30000241100013C1E80008FC401000E000FCEFE
+:10A3100002E028218FC401000E000FDE02C02821B8
+:10A320001620FF558F8B00A40A0012860013802B85
+:10A330008F8600A490C80001310400201080019194
+:10A34000241000013C048008348B0080916A007C5A
+:10A350008F9E0034AFA0002C314900011120000F66
+:10A36000AFB000288CCD00148C8E006001AE602B45
+:10A370001580000201A038218C8700603C188008FD
+:10A38000370300808C70007000F0782B15E000021D
+:10A3900000E020218C640070AFA4002C3C028008F7
+:10A3A000344500808CD200148CBF0070025FC82B33
+:10A3B00017200002024020218CA400708FA7002CDF
+:10A3C0000087182310600003AFA3003024050002AB
+:10A3D000AFA500288FA400280264882B162000BA9D
+:10A3E000000018218CD000388FCE000C3C0F00806C
+:10A3F000AFD000008CCD00343C0CFF9F01CF58251E
+:10A40000AFCD000490CA003F3586FFFF01662024CF
+:10A410003C0900203C08FFEFA3CA000B0089382547
+:10A420003511FFFF00F118243C0500088F8700A4B8
+:10A430000065C825AFD9000C8CE20014AFC000182D
+:10A440008FA60030AFC200148CF800188FB0002C1B
+:10A450003C1FFFFBAFD8001C8CEF000837F2FFFF5A
+:10A4600003326824AFCF00248CEC000C020670216C
+:10A47000AFCD000CA7C00038A7C0003AAFCE002C6B
+:10A48000AFCC0020AFC000288CEA00148FAB002CAA
+:10A49000014B48230126402311000011AFC80010D2
+:10A4A00090EB003D8FC900048FC80000000B5100E5
+:10A4B000012A28210000102100AA882B010218215E
+:10A4C0000071F821AFC50004AFDF000090F2003D3D
+:10A4D000A3D2000A8F9900A497380006A7D80008D5
+:10A4E0008F910038240800023C038008A228000055
+:10A4F0003465008094BF005C8FA4002C33F0FFFF14
+:10A500000E000FF48F9200380002CB808F8500A4DC
+:10A51000021978253C18420001F87025AE4E00045F
+:10A520008F8400388CAD0038AC8D00188CAC0034B2
+:10A53000AC8C001CAC80000CAC800010A48000141B
+:10A54000A4800016A4800020A4800022AC800024F7
+:10A5500090A6003F8FA7002CA486000250E0019235
+:10A56000240700018FA200305040000290A2003D5D
+:10A5700090A2003E244A0001A08A00018F84003886
+:10A580008FA9002CAC8900083C128008364D008051
+:10A5900091AC007C3186000214C000022407003414
+:10A5A000240700308F8500A43C198008373F0080C5
+:10A5B00090B0000093F9007C240E0004A0900030BD
+:10A5C0008F8F00A48FB8002C8F8D003891F200017E
+:10A5D0003304000301C46023A1B200318F8E003820
+:10A5E0008F8600A42402C00095CA003294C90012CC
+:10A5F0008FAB002C0142402431233FFF010388250B
+:10A60000A5D1003291D000323185000300EBF82152
+:10A610003218003F370F0040A1CF00328FA4002C2A
+:10A6200003E5382133280004108000028F850038AC
+:10A6300000E838213C0A8008ACA700343549010005
+:10A640008D2800D08FA3002C2419FFBFACA80038A0
+:10A6500090B1003C2C640001240FFFDF3227007F03
+:10A66000A0A7003C8F98003800049140931F003C45
+:10A6700003F98024A310003C8F8C0038918E003C9D
+:10A6800001CF682401B23025A186003C8F8900A447
+:10A690008F8800388D2B0020AD0B00408D220024C8
+:10A6A000AD0200448D2A0028AD0A00488D23002CFD
+:10A6B0000E001013AD03004C8FB1002824070002D8
+:10A6C000122700118FA300280003282B00058023E8
+:10A6D0000270982400608021006090210A00126FAF
+:10A6E0000010882B962900128F8400A00000902172
+:10A6F0003125FFFFA7A900180E000FC22411000189
+:10A700000A00131D3C1E80003C0B80003C12800898
+:10A710008D640100924900088F92FF340E000F995A
+:10A720003125007F8F9900388FA700288FA4003033
+:10A73000A3270000965F005C33F0FFFF0E000FF4CC
+:10A740008F91003800026B80020D80253C0842008A
+:10A750008F8D00A402085025AE2A00048DA5003874
+:10A760008F8A003800007821000F1100AD450018D5
+:10A770008DB800343C047FFF3488FFFFAD58001CC7
+:10A7800091A6003E8D4C001C8D4900180006190052
+:10A79000000677020183C821004E58250323882B29
+:10A7A000012B382100F1F821AD59001CAD5F0018D4
+:10A7B000AD40000CAD40001091B0003E8FA40030C1
+:10A7C00024090005A550001495A500042419C00013
+:10A7D00000884024A545001691B8003EA5580020E9
+:10A7E00095AF0004A54F0022AD40002491AE003F7C
+:10A7F000A54E000291A6003E91AC003D01861023BB
+:10A80000244B0001A14B00018F9100388FA3003031
+:10A810003C028008344B0100AE230008A22900301E
+:10A820008F8C00388F8700A4959F003294F000121F
+:10A830002407FFBF033FC02432053FFF03057825EF
+:10A84000A58F0032918E00322418FFDF31CD003FFA
+:10A8500035A60040A18600328F910038240DFFFFFD
+:10A86000240CFF80AE2000348D6A00D0AE2A003860
+:10A870009223003C3069007FA229003C8F90003871
+:10A880003C0380009219003C0327F824A21F003CDF
+:10A890008F8E003891C5003C00B87824A1CF003CD1
+:10A8A0008F8A00383C0E8008AD4D00408FA6002CEA
+:10A8B000AD46004491420048004C5825A14B004849
+:10A8C0008F9000388F9900A48E09004801238824B6
+:10A8D00002283825AE070048933F003EA21F004CD7
+:10A8E0008F9800A48F8F003897050004A5E5004ECF
+:10A8F0000E0003818DC500609246007C8FAC003055
+:10A9000000026940000291000040282130CB000283
+:10A9100001B21021156000AA018230213C0E80088E
+:10A9200035C20080904C007C31830004106000032D
+:10A930008FB900300005788000CF3021241F00043B
+:10A940008F910038332D000303ED8023320800037C
+:10A9500000C85021AE2A00343C188000A7C500383A
+:10A960003C0680088F04010090DE00080E000FDE18
+:10A9700033C5007F0E001013000000000A00140D04
+:10A980008FA300288F9800348CC90038241F00033F
+:10A99000A7000008AF0900008CC50034A300000A1E
+:10A9A0008F9900A4AF0500043C080080932D003F60
+:10A9B000A31F000C8F0A000C3C02FF9FA30D000B8D
+:10A9C0000148F0253451FFFF3C12FFEF8F9900A49E
+:10A9D00003D170243646FFFF01C61824AF03000CD4
+:10A9E0008F2C0014972900128F8400A0AF0C001048
+:10A9F0008F2F0014AF000018AF000020AF0F00141D
+:10AA0000AF0000248F270018312F3FFF000F59801F
+:10AA1000AF0700288F2500080164F821312D0001BF
+:10AA2000AF0500308F31000C8F920038001F51C2EB
+:10AA3000000D438001481021241E00023C068008BE
+:10AA4000A702001CA7000034AF11002CA25E00007A
+:10AA500034D20080964E005C8F9900383C0342004F
+:10AA600031CCFFFF01833825AF2700048F8B00A472
+:10AA7000240500012402C0008D640038240700343E
+:10AA8000AF2400188D690034AF29001CAF20000CE2
+:10AA9000AF200010A7200014A7200016A720002038
+:10AAA000A7200022AF200024A7300002A325000128
+:10AAB0008F8800388F9F00A4AD10000893ED000030
+:10AAC000A10D00308F8A00A48F98003891510001A9
+:10AAD000A31100318F8B0038957E003203C27024A1
+:10AAE00001CF6025A56C0032916300323064003FD5
+:10AAF000A16400329249007C3125000214A00002BA
+:10AB00008F840038240700303C198008AC8700345B
+:10AB1000373201008E5F00D0240AFFBF020090216F
+:10AB2000AC9F0038908D003C31A8007FA088003C8D
+:10AB30008F9E003893C2003C004A8824A3D1003C79
+:10AB40008F8300380010882B9066003C34CE0020A4
+:10AB5000A06E003C8F8400A48F9800388C8C00205D
+:10AB6000AF0C00408C8F0024AF0F00448C8700286E
+:10AB7000AF0700488C8B002CAF0B004C0E0010135D
+:10AB80003C1E80000A0012700000000094C80052B1
+:10AB90003C0A08008D4A002401488821A4D10052B3
+:10ABA0000A0012198FB40010A08700018F840038AA
+:10ABB000240B0001AC8B00080A0013BE3C12800875
+:10ABC000000520800A0014A200C4302127BDFFE048
+:10ABD0003C0D8008AFB20018AFB00010AFBF001C32
+:10ABE000AFB1001435B200808E4C001835A80100BA
+:10ABF000964B000695A70050910900FC000C5602E8
+:10AC0000016728233143007F312600FF240200031F
+:10AC1000AF8300A8AF8400A010C2001B30B0FFFFBC
+:10AC2000910600FC2412000530C200FF10520033D0
+:10AC300000000000160000098FBF001C8FB2001832
+:10AC40008FB100148FB00010240D0C003C0C80005C
+:10AC500027BD002003E00008AD8D00240E0011FB8D
+:10AC6000020020218FBF001C8FB200188FB100148A
+:10AC70008FB00010240D0C003C0C800027BD00207C
+:10AC800003E00008AD8D0024965800789651007AB4
+:10AC9000924E007D0238782631E8FFFF31C400C0B3
+:10ACA000148000092D11000116000037000000007B
+:10ACB0005620FFE28FBF001C0E0010D100000000E4
+:10ACC0000A00156A8FBF001C1620FFDA0000000082
+:10ACD0000E0010D1000000001440FFD88FBF001CF0
+:10ACE0001600002200000000925F007D33E2003F6A
+:10ACF000A242007D0A00156A8FBF001C950900EA78
+:10AD00008F86008000802821240400050E0007257E
+:10AD10003130FFFF978300923C0480002465FFFFE1
+:10AD2000A78500928C8A01B80540FFFE0000000054
+:10AD3000AC8001808FBF001CAC9001848FB20018E2
+:10AD40008FB100148FB000103C0760133C0B100053
+:10AD5000240D0C003C0C800027BD0020AC8701882E
+:10AD6000AC8B01B803E00008AD8D00240E0011FB90
+:10AD7000020020215040FFB18FBF001C925F007D78
+:10AD80000A00159733E2003F0E0011FB020020215C
+:10AD90001440FFAA8FBF001C122000070000000013
+:10ADA0009259007D3330003F36020040A242007DC0
+:10ADB0000A00156A8FBF001C0E0010D100000000B1
+:10ADC0005040FF9E8FBF001C9259007D3330003FE2
+:08ADD0000A0015C6360200401E
+:08ADD800000000000000001B58
+:10ADE0000000000F0000000A00000008000000063C
+:10ADF0000000000500000005000000040000000441
+:10AE00000000000300000003000000030000000336
+:10AE10000000000300000002000000020000000229
+:10AE2000000000020000000200000002000000021A
+:10AE3000000000020000000200000002000000020A
+:10AE400000000002000000020000000200000002FA
+:0CAE5000000000010000000100000001F3
+:04AE5C008008010069
+:10AE6000800800808008000000000C000000308096
+:10AE7000080011D00800127C08001294080012A8E3
+:10AE8000080012BC080011D0080011D0080012F010
+:10AE90000800132C080013400800138808001A8CBF
+:10AEA00008001A8C08001AC408001AC408001AD82E
+:10AEB00008001AA808001D0008001CCC08001D5836
+:10AEC00008001D5808001DE008001D108008024001
+:10AED000080027340800256C0800275C080027F4C8
+:10AEE0000800293C0800298808002AAC080029B479
+:10AEF00008002A38080025DC08002EDC08002EA4F3
+:10AF000008002588080025880800258808002B20CF
+:10AF100008002B20080025880800258808002DD06F
+:10AF2000080025880800258808002588080025884D
+:10AF300008002E0C080025880800258808002588B0
+:10AF4000080025880800258808002588080025882D
+:10AF5000080025880800258808002588080025881D
+:10AF6000080025880800258808002588080029A8E9
+:10AF7000080025880800258808002E680800258814
+:10AF800008002588080025880800258808002588ED
+:10AF900008002588080025880800258808002588DD
+:10AFA00008002588080025880800258808002588CD
+:10AFB00008002588080025880800258808002588BD
+:10AFC00008002CF4080025880800258808002C6853
+:10AFD00008002BC408003CE408003CB808003C848E
+:10AFE00008003C5808003C3808003BEC8008010091
+:10AFF00080080080800800008008008008004C6401
+:10B0000008004C9C08004BE408004C6408004C64A9
+:0CB01000080049B808004C6408005050CB
+:04B01C000A000C8496
+:10B0200000000000000000000000000D7278703683
+:10B030002E302E3137000000060011030000000002
+:10B0400000000001000000000000000000000000FF
+:10B0500000000000000000000000000000000000F0
+:10B0600000000000000000000000000000000000E0
+:10B0700000000000000000000000000000000000D0
+:10B0800000000000000000000000000000000000C0
+:10B0900000000000000000000000000000000000B0
+:10B0A00000000000000000000000000000000000A0
+:10B0B0000000000000000000000000000000000090
+:10B0C0000000000000000000000000000000000080
+:10B0D0000000000000000000000000000000000070
+:10B0E0000000000000000000000000000000000060
+:10B0F0000000000000000000000000000000000050
+:10B10000000000000000000000000000000000003F
+:10B11000000000000000000000000000000000002F
+:10B12000000000000000000000000000000000001F
+:10B13000000000000000000000000000000000000F
+:10B1400000000000000000000000000000000000FF
+:10B1500000000000000000000000000000000000EF
+:10B1600000000000000000000000000000000000DF
+:10B1700000000000000000000000000000000000CF
+:10B1800000000000000000000000000000000000BF
+:10B1900000000000000000000000000000000000AF
+:10B1A000000000000000000000000000000000009F
+:10B1B000000000000000000000000000000000008F
+:10B1C000000000000000000000000000000000007F
+:10B1D000000000000000000000000000000000006F
+:10B1E000000000000000000000000000000000005F
+:10B1F000000000000000000000000000000000004F
+:10B20000000000000000000000000000000000003E
+:10B21000000000000000000000000000000000002E
+:10B22000000000000000000000000000000000001E
+:10B23000000000000000000000000000000000000E
+:10B2400000000000000000000000000000000000FE
+:10B2500000000000000000000000000000000000EE
+:10B2600000000000000000000000000000000000DE
+:10B2700000000000000000000000000000000000CE
+:10B2800000000000000000000000000000000000BE
+:10B2900000000000000000000000000000000000AE
+:10B2A000000000000000000000000000000000009E
+:10B2B000000000000000000000000000000000008E
+:10B2C000000000000000000000000000000000007E
+:10B2D000000000000000000000000000000000006E
+:10B2E000000000000000000000000000000000005E
+:10B2F000000000000000000000000000000000004E
+:10B30000000000000000000000000000000000003D
+:10B31000000000000000000000000000000000002D
+:10B32000000000000000000000000000000000001D
+:10B33000000000000000000000000000000000000D
+:10B3400000000000000000000000000000000000FD
+:10B3500000000000000000000000000000000000ED
+:10B3600000000000000000000000000000000000DD
+:10B3700000000000000000000000000000000000CD
+:10B3800000000000000000000000000000000000BD
+:10B3900000000000000000000000000000000000AD
+:10B3A000000000000000000000000000000000009D
+:10B3B000000000000000000000000000000000008D
+:10B3C000000000000000000000000000000000007D
+:10B3D000000000000000000000000000000000006D
+:10B3E000000000000000000000000000000000005D
+:10B3F000000000000000000000000000000000004D
+:10B40000000000000000000000000000000000003C
+:10B41000000000000000000000000000000000002C
+:10B42000000000000000000000000000000000001C
+:10B43000000000000000000000000000000000000C
+:10B4400000000000000000000000000000000000FC
+:10B4500000000000000000000000000000000000EC
+:10B4600000000000000000000000000000000000DC
+:10B4700000000000000000000000000000000000CC
+:10B4800000000000000000000000000000000000BC
+:10B4900000000000000000000000000000000000AC
+:10B4A000000000000000000000000000000000009C
+:10B4B000000000000000000000000000000000008C
+:10B4C000000000000000000000000000000000007C
+:10B4D000000000000000000000000000000000006C
+:10B4E000000000000000000000000000000000005C
+:10B4F000000000000000000000000000000000004C
+:10B50000000000000000000000000000000000003B
+:10B51000000000000000000000000000000000002B
+:10B52000000000000000000000000000000000001B
+:10B53000000000000000000000000000000000000B
+:10B5400000000000000000000000000000000000FB
+:10B5500000000000000000000000000000000000EB
+:10B5600000000000000000000000000000000000DB
+:10B5700000000000000000000000000000000000CB
+:10B5800000000000000000000000000000000000BB
+:10B5900000000000000000000000000000000000AB
+:10B5A000000000000000000000000000000000009B
+:10B5B000000000000000000000000000000000008B
+:10B5C000000000000000000000000000000000007B
+:10B5D000000000000000000000000000000000006B
+:10B5E000000000000000000000000000000000005B
+:10B5F000000000000000000000000000000000004B
+:10B60000000000000000000000000000000000003A
+:10B61000000000000000000000000000000000002A
+:10B62000000000000000000000000000000000001A
+:10B63000000000000000000000000000000000000A
+:10B6400000000000000000000000000000000000FA
+:10B6500000000000000000000000000000000000EA
+:10B6600000000000000000000000000000000000DA
+:10B6700000000000000000000000000000000000CA
+:10B6800000000000000000000000000000000000BA
+:10B6900000000000000000000000000000000000AA
+:10B6A000000000000000000000000000000000009A
+:10B6B000000000000000000000000000000000008A
+:10B6C000000000000000000000000000000000007A
+:10B6D000000000000000000000000000000000006A
+:10B6E000000000000000000000000000000000005A
+:10B6F000000000000000000000000000000000004A
+:10B700000000000000000000000000000000000039
+:10B710000000000000000000000000000000000029
+:10B720000000000000000000000000000000000019
+:10B730000000000000000000000000000000000009
+:10B7400000000000000000000000000000000000F9
+:10B7500000000000000000000000000000000000E9
+:10B7600000000000000000000000000000000000D9
+:10B7700000000000000000000000000000000000C9
+:10B7800000000000000000000000000000000000B9
+:10B7900000000000000000000000000000000000A9
+:10B7A0000000000000000000000000000000000099
+:10B7B0000000000000000000000000000000000089
+:10B7C0000000000000000000000000000000000079
+:10B7D0000000000000000000000000000000000069
+:10B7E0000000000000000000000000000000000059
+:10B7F0000000000000000000000000000000000049
+:10B800000000000000000000000000000000000038
+:10B810000000000000000000000000000000000028
+:10B820000000000000000000000000000000000018
+:10B830000000000000000000000000000000000008
+:10B8400000000000000000000000000000000000F8
+:10B8500000000000000000000000000000000000E8
+:10B8600000000000000000000000000000000000D8
+:10B8700000000000000000000000000000000000C8
+:10B8800000000000000000000000000000000000B8
+:10B8900000000000000000000000000000000000A8
+:10B8A0000000000000000000000000000000000098
+:10B8B0000000000000000000000000000000000088
+:10B8C0000000000000000000000000000000000078
+:10B8D0000000000000000000000000000000000068
+:10B8E0000000000000000000000000000000000058
+:10B8F0000000000000000000000000000000000048
+:10B900000000000000000000000000000000000037
+:10B910000000000000000000000000000000000027
+:10B920000000000000000000000000000000000017
+:10B930000000000000000000000000000000000007
+:10B9400000000000000000000000000000000000F7
+:10B9500000000000000000000000000000000000E7
+:10B9600000000000000000000000000000000000D7
+:10B9700000000000000000000000000000000000C7
+:10B9800000000000000000000000000000000000B7
+:10B9900000000000000000000000000000000000A7
+:10B9A0000000000000000000000000000000000097
+:10B9B0000000000000000000000000000000000087
+:10B9C0000000000000000000000000000000000077
+:10B9D0000000000000000000000000000000000067
+:10B9E0000000000000000000000000000000000057
+:10B9F0000000000000000000000000000000000047
+:10BA00000000000000000000000000000000000036
+:10BA10000000000000000000000000000000000026
+:10BA20000000000000000000000000000000000016
+:10BA30000000000000000000000000000000000006
+:10BA400000000000000000000000000000000000F6
+:10BA500000000000000000000000000000000000E6
+:10BA600000000000000000000000000000000000D6
+:10BA700000000000000000000000000000000000C6
+:10BA800000000000000000000000000000000000B6
+:10BA900000000000000000000000000000000000A6
+:10BAA0000000000000000000000000000000000096
+:10BAB0000000000000000000000000000000000086
+:10BAC0000000000000000000000000000000000076
+:10BAD0000000000000000000000000000000000066
+:10BAE0000000000000000000000000000000000056
+:10BAF0000000000000000000000000000000000046
+:10BB00000000000000000000000000000000000035
+:10BB10000000000000000000000000000000000025
+:10BB20000000000000000000000000000000000015
+:10BB30000000000000000000000000000000000005
+:10BB400000000000000000000000000000000000F5
+:10BB500000000000000000000000000000000000E5
+:10BB600000000000000000000000000000000000D5
+:10BB700000000000000000000000000000000000C5
+:10BB800000000000000000000000000000000000B5
+:10BB900000000000000000000000000000000000A5
+:10BBA0000000000000000000000000000000000095
+:10BBB0000000000000000000000000000000000085
+:10BBC0000000000000000000000000000000000075
+:10BBD0000000000000000000000000000000000065
+:10BBE0000000000000000000000000000000000055
+:10BBF0000000000000000000000000000000000045
+:10BC00000000000000000000000000000000000034
+:10BC10000000000000000000000000000000000024
+:10BC20000000000000000000000000000000000014
+:10BC30000000000000000000000000000000000004
+:10BC400000000000000000000000000000000000F4
+:10BC500000000000000000000000000000000000E4
+:10BC600000000000000000000000000000000000D4
+:10BC700000000000000000000000000000000000C4
+:10BC800000000000000000000000000000000000B4
+:10BC900000000000000000000000000000000000A4
+:10BCA0000000000000000000000000000000000094
+:10BCB0000000000000000000000000000000000084
+:10BCC0000000000000000000000000000000000074
+:10BCD0000000000000000000000000000000000064
+:10BCE0000000000000000000000000000000000054
+:10BCF0000000000000000000000000000000000044
+:10BD00000000000000000000000000000000000033
+:10BD10000000000000000000000000000000000023
+:10BD20000000000000000000000000000000000013
+:10BD30000000000000000000000000000000000003
+:10BD400000000000000000000000000000000000F3
+:10BD500000000000000000000000000000000000E3
+:10BD600000000000000000000000000000000000D3
+:10BD700000000000000000000000000000000000C3
+:10BD800000000000000000000000000000000000B3
+:10BD900000000000000000000000000000000000A3
+:10BDA0000000000000000000000000000000000093
+:10BDB0000000000000000000000000000000000083
+:10BDC0000000000000000000000000000000000073
+:10BDD0000000000000000000000000000000000063
+:10BDE0000000000000000000000000000000000053
+:10BDF0000000000000000000000000000000000043
+:10BE00000000000000000000000000000000000032
+:10BE10000000000000000000000000000000000022
+:10BE20000000000000000000000000000000000012
+:10BE30000000000000000000000000000000000002
+:10BE400000000000000000000000000000000000F2
+:10BE500000000000000000000000000000000000E2
+:10BE600000000000000000000000000000000000D2
+:10BE700000000000000000000000000000000000C2
+:10BE800000000000000000000000000000000000B2
+:10BE900000000000000000000000000000000000A2
+:10BEA0000000000000000000000000000000000092
+:10BEB0000000000000000000000000000000000082
+:10BEC0000000000000000000000000000000000072
+:10BED0000000000000000000000000000000000062
+:10BEE0000000000000000000000000000000000052
+:10BEF0000000000000000000000000000000000042
+:10BF00000000000000000000000000000000000031
+:10BF10000000000000000000000000000000000021
+:10BF20000000000000000000000000000000000011
+:10BF30000000000000000000000000000000000001
+:10BF400000000000000000000000000000000000F1
+:10BF500000000000000000000000000000000000E1
+:10BF600000000000000000000000000000000000D1
+:10BF700000000000000000000000000000000000C1
+:10BF800000000000000000000000000000000000B1
+:10BF900000000000000000000000000000000000A1
+:10BFA0000000000000000000000000000000000091
+:10BFB0000000000000000000000000000000000081
+:10BFC0000000000000000000000000000000000071
+:10BFD0000000000000000000000000000000000061
+:10BFE0000000000000000000000000000000000051
+:10BFF0000000000000000000000000000000000041
+:10C000000000000000000000000000000000000030
+:10C010000000000000000000000000000000000020
+:10C020000000000000000000000000000000000010
+:10C030000000000000000000000000000000000000
+:10C0400000000000000000000000000000000000F0
+:10C0500000000000000000000000000000000000E0
+:10C0600000000000000000000000000000000000D0
+:10C0700000000000000000000000000000000000C0
+:10C0800000000000000000000000000000000000B0
+:10C0900000000000000000000000000000000000A0
+:10C0A0000000000000000000000000000000000090
+:10C0B0000000000000000000000000000000000080
+:10C0C0000000000000000000000000000000000070
+:10C0D0000000000000000000000000000000000060
+:10C0E0000000000000000000000000000000000050
+:10C0F0000000000000000000000000000000000040
+:10C10000000000000000000000000000000000002F
+:10C11000000000000000000000000000000000001F
+:10C12000000000000000000000000000000000000F
+:10C1300000000000000000000000000000000000FF
+:10C1400000000000000000000000000000000000EF
+:10C1500000000000000000000000000000000000DF
+:10C1600000000000000000000000000000000000CF
+:10C1700000000000000000000000000000000000BF
+:10C1800000000000000000000000000000000000AF
+:10C19000000000000000000000000000000000009F
+:10C1A000000000000000000000000000000000008F
+:10C1B000000000000000000000000000000000007F
+:10C1C000000000000000000000000000000000006F
+:10C1D000000000000000000000000000000000005F
+:10C1E000000000000000000000000000000000004F
+:10C1F000000000000000000000000000000000003F
+:10C20000000000000000000000000000000000002E
+:10C21000000000000000000000000000000000001E
+:10C22000000000000000000000000000000000000E
+:10C2300000000000000000000000000000000000FE
+:10C2400000000000000000000000000000000000EE
+:10C2500000000000000000000000000000000000DE
+:10C2600000000000000000000000000000000000CE
+:10C2700000000000000000000000000000000000BE
+:10C2800000000000000000000000000000000000AE
+:10C29000000000000000000000000000000000009E
+:10C2A000000000000000000000000000000000008E
+:10C2B000000000000000000000000000000000007E
+:10C2C000000000000000000000000000000000006E
+:10C2D000000000000000000000000000000000005E
+:10C2E000000000000000000000000000000000004E
+:10C2F000000000000000000000000000000000003E
+:10C30000000000000000000000000000000000002D
+:10C31000000000000000000000000000000000001D
+:10C32000000000000000000000000000000000000D
+:10C3300000000000000000000000000000000000FD
+:10C3400000000000000000000000000000000000ED
+:10C3500000000000000000000000000000000000DD
+:10C3600000000000000000000000000000000000CD
+:10C3700000000000000000000000000000000000BD
+:10C3800000000000000000000000000000000000AD
+:10C39000000000000000000000000000000000009D
+:10C3A000000000000000000000000000000000008D
+:10C3B000000000000000000000000000000000007D
+:10C3C000000000000000000000000000000000006D
+:10C3D000000000000000000000000000000000005D
+:10C3E000000000000000000000000000000000004D
+:10C3F000000000000000000000000000000000003D
+:10C40000000000000000000000000000000000002C
+:10C41000000000000000000000000000000000001C
+:10C42000000000000000000000000000000000000C
+:10C4300000000000000000000000000000000000FC
+:10C4400000000000000000000000000000000000EC
+:10C4500000000000000000000000000000000000DC
+:10C4600000000000000000000000000000000000CC
+:10C4700000000000000000000000000000000000BC
+:10C4800000000000000000000000000000000000AC
+:10C49000000000000000000000000000000000009C
+:10C4A000000000000000000000000000000000008C
+:10C4B000000000000000000000000000000000007C
+:10C4C000000000000000000000000000000000006C
+:10C4D000000000000000000000000000000000005C
+:10C4E000000000000000000000000000000000004C
+:10C4F000000000000000000000000000000000003C
+:10C50000000000000000000000000000000000002B
+:10C51000000000000000000000000000000000001B
+:10C52000000000000000000000000000000000000B
+:10C5300000000000000000000000000000000000FB
+:10C5400000000000000000000000000000000000EB
+:10C5500000000000000000000000000000000000DB
+:10C5600000000000000000000000000000000000CB
+:10C5700000000000000000000000000000000000BB
+:10C5800000000000000000000000000000000000AB
+:10C59000000000000000000000000000000000009B
+:10C5A000000000000000000000000000000000008B
+:10C5B000000000000000000000000000000000007B
+:10C5C000000000000000000000000000000000006B
+:10C5D000000000000000000000000000000000005B
+:10C5E000000000000000000000000000000000004B
+:10C5F000000000000000000000000000000000003B
+:10C60000000000000000000000000000000000002A
+:10C61000000000000000000000000000000000001A
+:10C62000000000000000000000000000000000000A
+:10C6300000000000000000000000000000000000FA
+:10C6400000000000000000000000000000000000EA
+:10C6500000000000000000000000000000000000DA
+:10C6600000000000000000000000000000000000CA
+:10C6700000000000000000000000000000000000BA
+:10C6800000000000000000000000000000000000AA
+:10C69000000000000000000000000000000000009A
+:10C6A000000000000000000000000000000000008A
+:10C6B000000000000000000000000000000000007A
+:10C6C000000000000000000000000000000000006A
+:10C6D000000000000000000000000000000000005A
+:10C6E000000000000000000000000000000000004A
+:10C6F000000000000000000000000000000000003A
+:10C700000000000000000000000000000000000029
+:10C710000000000000000000000000000000000019
+:10C720000000000000000000000000000000000009
+:10C7300000000000000000000000000000000000F9
+:10C7400000000000000000000000000000000000E9
+:10C7500000000000000000000000000000000000D9
+:10C7600000000000000000000000000000000000C9
+:10C7700000000000000000000000000000000000B9
+:10C7800000000000000000000000000000000000A9
+:10C790000000000000000000000000000000000099
+:10C7A0000000000000000000000000000000000089
+:10C7B0000000000000000000000000000000000079
+:10C7C0000000000000000000000000000000000069
+:10C7D0000000000000000000000000000000000059
+:10C7E0000000000000000000000000000000000049
+:10C7F0000000000000000000000000000000000039
+:10C800000000000000000000000000000000000028
+:10C810000000000000000000000000000000000018
+:10C820000000000000000000000000000000000008
+:10C8300000000000000000000000000000000000F8
+:10C8400000000000000000000000000000000000E8
+:10C8500000000000000000000000000000000000D8
+:10C8600000000000000000000000000000000000C8
+:10C8700000000000000000000000000000000000B8
+:10C8800000000000000000000000000000000000A8
+:10C890000000000000000000000000000000000098
+:10C8A0000000000000000000000000000000000088
+:10C8B0000000000000000000000000000000000078
+:10C8C0000000000000000000000000000000000068
+:10C8D0000000000000000000000000000000000058
+:10C8E0000000000000000000000000000000000048
+:10C8F0000000000000000000000000000000000038
+:10C900000000000000000000000000000000000027
+:10C910000000000000000000000000000000000017
+:10C920000000000000000000000000000000000007
+:10C9300000000000000000000000000000000000F7
+:10C9400000000000000000000000000000000000E7
+:10C9500000000000000000000000000000000000D7
+:10C9600000000000000000000000000000000000C7
+:10C9700000000000000000000000000000000000B7
+:10C9800000000000000000000000000000000000A7
+:10C990000000000000000000000000000000000097
+:10C9A0000000000000000000000000000000000087
+:10C9B0000000000000000000000000000000000077
+:10C9C0000000000000000000000000000000000067
+:10C9D0000000000000000000000000000000000057
+:10C9E0000000000000000000000000000000000047
+:10C9F0000000000000000000000000000000000037
+:10CA00000000000000000000000000000000000026
+:10CA10000000000000000000000000000000000016
+:10CA20000000000000000000000000000000000006
+:10CA300000000000000000000000000000000000F6
+:10CA400000000000000000000000000000000000E6
+:10CA500000000000000000000000000000000000D6
+:10CA600000000000000000000000000000000000C6
+:10CA700000000000000000000000000000000000B6
+:10CA800000000000000000000000000000000000A6
+:10CA90000000000000000000000000000000000096
+:10CAA0000000000000000000000000000000000086
+:10CAB0000000000000000000000000000000000076
+:10CAC0000000000000000000000000000000000066
+:10CAD0000000000000000000000000000000000056
+:10CAE0000000000000000000000000000000000046
+:10CAF0000000000000000000000000000000000036
+:10CB00000000000000000000000000000000000025
+:10CB10000000000000000000000000000000000015
+:10CB20000000000000000000000000000000000005
+:10CB300000000000000000000000000000000000F5
+:10CB400000000000000000000000000000000000E5
+:10CB500000000000000000000000000000000000D5
+:10CB600000000000000000000000000000000000C5
+:10CB700000000000000000000000000000000000B5
+:10CB800000000000000000000000000000000000A5
+:10CB90000000000000000000000000000000000095
+:10CBA0000000000000000000000000000000000085
+:10CBB0000000000000000000000000000000000075
+:10CBC0000000000000000000000000000000000065
+:10CBD0000000000000000000000000000000000055
+:10CBE0000000000000000000000000000000000045
+:10CBF0000000000000000000000000000000000035
+:10CC00000000000000000000000000000000000024
+:10CC10000000000000000000000000000000000014
+:10CC20000000000000000000000000000000000004
+:10CC300000000000000000000000000000000000F4
+:10CC400000000000000000000000000000000000E4
+:10CC500000000000000000000000000000000000D4
+:10CC600000000000000000000000000000000000C4
+:10CC700000000000000000000000000000000000B4
+:10CC800000000000000000000000000000000000A4
+:10CC90000000000000000000000000000000000094
+:10CCA0000000000000000000000000000000000084
+:10CCB0000000000000000000000000000000000074
+:10CCC0000000000000000000000000000000000064
+:10CCD0000000000000000000000000000000000054
+:10CCE0000000000000000000000000000000000044
+:10CCF0000000000000000000000000000000000034
+:10CD00000000000000000000000000000000000023
+:10CD10000000000000000000000000000000000013
+:10CD20000000000000000000000000000000000003
+:10CD300000000000000000000000000000000000F3
+:10CD400000000000000000000000000000000000E3
+:10CD500000000000000000000000000000000000D3
+:10CD600000000000000000000000000000000000C3
+:10CD700000000000000000000000000000000000B3
+:10CD800000000000000000000000000000000000A3
+:10CD90000000000000000000000000000000000093
+:10CDA0000000000000000000000000000000000083
+:10CDB0000000000000000000000000000000000073
+:10CDC0000000000000000000000000000000000063
+:10CDD0000000000000000000000000000000000053
+:10CDE0000000000000000000000000000000000043
+:10CDF0000000000000000000000000000000000033
+:10CE00000000000000000000000000000000000022
+:10CE10000000000000000000000000000000000012
+:10CE20000000000000000000000000000000000002
+:10CE300000000000000000000000000000000000F2
+:10CE400000000000000000000000000000000000E2
+:10CE500000000000000000000000000000000000D2
+:10CE600000000000000000000000000000000000C2
+:10CE700000000000000000000000000000000000B2
+:10CE800000000000000000000000000000000000A2
+:10CE90000000000000000000000000000000000092
+:10CEA0000000000000000000000000000000000082
+:10CEB0000000000000000000000000000000000072
+:10CEC0000000000000000000000000000000000062
+:10CED0000000000000000000000000000000000052
+:10CEE0000000000000000000000000000000000042
+:10CEF0000000000000000000000000000000000032
+:10CF00000000000000000000000000000000000021
+:10CF10000000000000000000000000000000000011
+:10CF20000000000000000000000000000000000001
+:10CF300000000000000000000000000000000000F1
+:10CF400000000000000000000000000000000000E1
+:10CF500000000000000000000000000000000000D1
+:10CF600000000000000000000000000000000000C1
+:10CF700000000000000000000000000000000000B1
+:10CF800000000000000000000000000000000000A1
+:10CF90000000000000000000000000000000000091
+:10CFA0000000000000000000000000000000000081
+:10CFB0000000000000000000000000000000000071
+:10CFC0000000000000000000000000000000000061
+:10CFD0000000000000000000000000000000000051
+:10CFE0000000000000000000000000000000000041
+:10CFF0000000000000000000000000000000000031
+:10D000000000000000000000000000000000000020
+:10D010000000000000000000000000000000000010
+:10D020000000000000000000000000000000000000
+:10D0300000000000000000000000000000000000F0
+:10D0400000000000000000000000000000000000E0
+:10D0500000000000000000000000000000000000D0
+:10D0600000000000000000000000000000000000C0
+:10D0700000000000000000000000000000000000B0
+:10D0800000000000000000000000000000000000A0
+:10D090000000000000000000000000000000000090
+:10D0A0000000000000000000000000000000000080
+:10D0B0000000000000000000000000000000000070
+:10D0C0000000000000000000000000000000000060
+:10D0D0000000000000000000000000000000000050
+:10D0E0000000000000000000000000000000000040
+:10D0F0000000000000000000000000000000000030
+:10D10000000000000000000000000000000000001F
+:10D11000000000000000000000000000000000000F
+:10D1200000000000000000000000000000000000FF
+:10D1300000000000000000000000000000000000EF
+:10D1400000000000000000000000000000000000DF
+:10D1500000000000000000000000000000000000CF
+:10D1600000000000000000000000000000000000BF
+:10D1700000000000000000000000000000000000AF
+:10D18000000000000000000000000000000000009F
+:10D19000000000000000000000000000000000008F
+:10D1A000000000000000000000000000000000007F
+:10D1B000000000000000000000000000000000006F
+:10D1C000000000000000000000000000000000005F
+:10D1D000000000000000000000000000000000004F
+:10D1E000000000000000000000000000000000003F
+:10D1F000000000000000000000000000000000002F
+:10D20000000000000000000000000000000000001E
+:10D21000000000000000000000000000000000000E
+:10D2200000000000000000000000000000000000FE
+:10D2300000000000000000000000000000000000EE
+:10D2400000000000000000000000000000000000DE
+:10D2500000000000000000000000000000000000CE
+:10D2600000000000000000000000000000000000BE
+:10D2700000000000000000000000000000000000AE
+:10D28000000000000000000000000000000000009E
+:10D29000000000000000000000000000000000008E
+:10D2A000000000000000000000000000000000007E
+:10D2B000000000000000000000000000000000006E
+:10D2C000000000000000000000000000000000005E
+:10D2D000000000000000000000000000000000004E
+:10D2E000000000000000000000000000000000003E
+:10D2F000000000000000000000000000000000002E
+:10D30000000000000000000000000000000000001D
+:10D31000000000000000000000000000000000000D
+:10D3200000000000000000000000000000000000FD
+:10D3300000000000000000000000000000000000ED
+:10D3400000000000000000000000000000000000DD
+:10D3500000000000000000000000000000000000CD
+:10D3600000000000000000000000000000000000BD
+:10D3700000000000000000000000000000000000AD
+:10D38000000000000000000000000000000000009D
+:10D39000000000000000000000000000000000008D
+:10D3A000000000000000000000000000000000007D
+:10D3B000000000000000000000000000000000006D
+:10D3C000000000000000000000000000000000005D
+:10D3D000000000000000000000000000000000004D
+:10D3E000000000000000000000000000000000003D
+:10D3F000000000000000000000000000000000002D
+:10D40000000000000000000000000000000000001C
+:10D41000000000000000000000000000000000000C
+:10D4200000000000000000000000000000000000FC
+:10D4300000000000000000000000000000000000EC
+:10D4400000000000000000000000000000000000DC
+:10D4500000000000000000000000000000000000CC
+:10D4600000000000000000000000000000000000BC
+:10D4700000000000000000000000000000000000AC
+:10D48000000000000000000000000000000000009C
+:10D49000000000000000000000000000000000008C
+:10D4A000000000000000000000000000000000007C
+:10D4B000000000000000000000000000000000006C
+:10D4C000000000000000000000000000000000005C
+:10D4D000000000000000000000000000000000004C
+:10D4E000000000000000000000000000000000003C
+:10D4F000000000000000000000000000000000002C
+:10D50000000000000000000000000000000000001B
+:10D51000000000000000000000000000000000000B
+:10D5200000000000000000000000000000000000FB
+:10D5300000000000000000000000000000000000EB
+:10D5400000000000000000000000000000000000DB
+:10D5500000000000000000000000000000000000CB
+:10D5600000000000000000000000000000000000BB
+:10D5700000000000000000000000000000000000AB
+:10D58000000000000000000000000000000000009B
+:10D59000000000000000000000000000000000008B
+:10D5A000000000000000000000000000000000007B
+:10D5B000000000000000000000000000000000006B
+:10D5C000000000000000000000000000000000005B
+:10D5D000000000000000000000000000000000004B
+:10D5E000000000000000000000000000000000003B
+:10D5F000000000000000000000000000000000002B
+:10D60000000000000000000000000000000000001A
+:10D61000000000000000000000000000000000000A
+:10D6200000000000000000000000000000000000FA
+:10D6300000000000000000000000000000000000EA
+:10D6400000000000000000000000000000000000DA
+:10D6500000000000000000000000000000000000CA
+:10D6600000000000000000000000000000000000BA
+:10D6700000000000000000000000000000000000AA
+:10D68000000000000000000000000000000000009A
+:10D69000000000000000000000000000000000008A
+:10D6A000000000000000000000000000000000007A
+:10D6B000000000000000000000000000000000006A
+:10D6C000000000000000000000000000000000005A
+:10D6D000000000000000000000000000000000004A
+:10D6E000000000000000000000000000000000003A
+:10D6F000000000000000000000000000000000002A
+:10D700000000000000000000000000000000000019
+:10D710000000000000000000000000000000000009
+:10D7200000000000000000000000000000000000F9
+:10D7300000000000000000000000000000000000E9
+:10D7400000000000000000000000000000000000D9
+:10D7500000000000000000000000000000000000C9
+:10D7600000000000000000000000000000000000B9
+:10D7700000000000000000000000000000000000A9
+:10D780000000000000000000000000000000000099
+:10D790000000000000000000000000000000000089
+:10D7A0000000000000000000000000000000000079
+:10D7B0000000000000000000000000000000000069
+:10D7C0000000000000000000000000000000000059
+:10D7D0000000000000000000000000000000000049
+:10D7E0000000000000000000000000000000000039
+:10D7F0000000000000000000000000000000000029
+:10D800000000000000000000000000000000000018
+:10D810000000000000000000000000000000000008
+:10D8200000000000000000000000000000000000F8
+:10D8300000000000000000000000000000000000E8
+:10D8400000000000000000000000000000000000D8
+:10D8500000000000000000000000000000000000C8
+:10D8600000000000000000000000000000000000B8
+:10D8700000000000000000000000000000000000A8
+:10D880000000000000000000000000000000000098
+:10D890000000000000000000000000000000000088
+:10D8A0000000000000000000000000000000000078
+:10D8B0000000000000000000000000000000000068
+:10D8C0000000000000000000000000000000000058
+:10D8D0000000000000000000000000000000000048
+:10D8E0000000000000000000000000000000000038
+:10D8F0000000000000000000000000000000000028
+:10D900000000000000000000000000000000000017
+:10D910000000000000000000000000000000000007
+:10D9200000000000000000000000000000000000F7
+:10D9300000000000000000000000000000000000E7
+:10D9400000000000000000000000000000000000D7
+:10D9500000000000000000000000000000000000C7
+:10D9600000000000000000000000000000000000B7
+:10D9700000000000000000000000000000000000A7
+:10D980000000000000000000000000000000000097
+:10D990000000000000000000000000000000000087
+:10D9A0000000000000000000000000000000000077
+:10D9B0000000000000000000000000000000000067
+:10D9C0000000000000000000000000000000000057
+:10D9D0000000000000000000000000000000000047
+:10D9E0000000000000000000000000000000000037
+:10D9F0000000000000000000000000000000000027
+:10DA00000000000000000000000000000000000016
+:10DA10000000000000000000000000000000000006
+:10DA200000000000000000000000000000000000F6
+:10DA300000000000000000000000000000000000E6
+:10DA400000000000000000000000000000000000D6
+:10DA500000000000000000000000000000000000C6
+:10DA600000000000000000000000000000000000B6
+:10DA700000000000000000000000000000000000A6
+:10DA80000000000000000000000000000000000096
+:10DA90000000000000000000000000000000000086
+:10DAA0000000000000000000000000000000000076
+:10DAB0000000000000000000000000000000000066
+:10DAC0000000000000000000000000000000000056
+:10DAD0000000000000000000000000000000000046
+:10DAE0000000000000000000000000000000000036
+:10DAF0000000000000000000000000000000000026
+:10DB00000000000000000000000000000000000015
+:10DB10000000000000000000000000000000000005
+:10DB200000000000000000000000000000000000F5
+:10DB300000000000000000000000000000000000E5
+:10DB400000000000000000000000000000000000D5
+:10DB500000000000000000000000000000000000C5
+:10DB600000000000000000000000000000000000B5
+:10DB700000000000000000000000000000000000A5
+:10DB80000000000000000000000000000000000095
+:10DB90000000000000000000000000000000000085
+:10DBA0000000000000000000000000000000000075
+:10DBB0000000000000000000000000000000000065
+:10DBC0000000000000000000000000000000000055
+:10DBD0000000000000000000000000000000000045
+:10DBE0000000000000000000000000000000000035
+:10DBF0000000000000000000000000000000000025
+:10DC00000000000000000000000000000000000014
+:10DC10000000000000000000000000000000000004
+:10DC200000000000000000000000000000000000F4
+:10DC300000000000000000000000000000000000E4
+:10DC400000000000000000000000000000000000D4
+:10DC500000000000000000000000000000000000C4
+:10DC600000000000000000000000000000000000B4
+:10DC700000000000000000000000000000000000A4
+:10DC80000000000000000000000000000000000094
+:10DC90000000000000000000000000000000000084
+:10DCA0000000000000000000000000000000000074
+:10DCB0000000000000000000000000000000000064
+:10DCC0000000000000000000000000000000000054
+:10DCD0000000000000000000000000000000000044
+:10DCE0000000000000000000000000000000000034
+:10DCF0000000000000000000000000000000000024
+:10DD00000000000000000000000000000000000013
+:10DD10000000000000000000000000000000000003
+:10DD200000000000000000000000000000000000F3
+:10DD300000000000000000000000000000000000E3
+:10DD400000000000000000000000000000000000D3
+:10DD500000000000000000000000000000000000C3
+:10DD600000000000000000000000000000000000B3
+:10DD700000000000000000000000000000000000A3
+:10DD80000000000000000000000000000000000093
+:10DD90000000000000000000000000000000000083
+:10DDA0000000000000000000000000000000000073
+:10DDB0000000000000000000000000000000000063
+:10DDC0000000000000000000000000000000000053
+:10DDD0000000000000000000000000000000000043
+:10DDE0000000000000000000000000000000000033
+:10DDF0000000000000000000000000000000000023
+:10DE00000000000000000000000000000000000012
+:10DE10000000000000000000000000000000000002
+:10DE200000000000000000000000000000000000F2
+:10DE300000000000000000000000000000000000E2
+:10DE400000000000000000000000000000000000D2
+:10DE500000000000000000000000000000000000C2
+:10DE600000000000000000000000000000000000B2
+:10DE700000000000000000000000000000000000A2
+:10DE80000000000000000000000000000000000092
+:10DE90000000000000000000000000000000000082
+:10DEA0000000000000000000000000000000000072
+:10DEB0000000000000000000000000000000000062
+:10DEC0000000000000000000000000000000000052
+:10DED0000000000000000000000000000000000042
+:10DEE0000000000000000000000000000000000032
+:10DEF0000000000000000000000000000000000022
+:10DF00000000000000000000000000000000000011
+:10DF10000000000000000000000000000000000001
+:10DF200000000000000000000000000000000000F1
+:10DF300000000000000000000000000000000000E1
+:10DF400000000000000000000000000000000000D1
+:10DF500000000000000000000000000000000000C1
+:10DF600000000000000000000000000000000000B1
+:10DF700000000000000000000000000000000000A1
+:10DF80000000000000000000000000000000000091
+:10DF90000000000000000000000000000000000081
+:10DFA0000000000000000000000000000000000071
+:10DFB0000000000000000000000000000000000061
+:10DFC0000000000000000000000000000000000051
+:10DFD0000000000000000000000000000000000041
+:10DFE0000000000000000000000000000000000031
+:10DFF0000000000000000000000000000000000021
+:10E000000000000000000000000000000000000010
+:10E010000000000000000000000000000000000000
+:10E0200000000000000000000000000000000000F0
+:10E0300000000000000000000000000000000000E0
+:10E0400000000000000000000000000000000000D0
+:10E0500000000000000000000000000000000000C0
+:10E0600000000000000000000000000000000000B0
+:10E0700000000000000000000000000000000000A0
+:10E080000000000000000000000000000000000090
+:10E090000000000000000000000000000000000080
+:10E0A0000000000000000000000000000000000070
+:10E0B0000000000000000000000000000000000060
+:10E0C0000000000000000000000000000000000050
+:10E0D0000000000000000000000000000000000040
+:10E0E0000000000000000000000000000000000030
+:10E0F0000000000000000000000000000000000020
+:10E10000000000000000000000000000000000000F
+:10E1100000000000000000000000000000000000FF
+:10E1200000000000000000000000000000000000EF
+:10E1300000000000000000000000000000000000DF
+:10E1400000000000000000000000000000000000CF
+:10E1500000000000000000000000000000000000BF
+:10E1600000000000000000000000000000000000AF
+:10E17000000000000000000000000000000000009F
+:10E18000000000000000000000000000000000008F
+:10E19000000000000000000000000000000000007F
+:10E1A000000000000000000000000000000000006F
+:10E1B000000000000000000000000000000000005F
+:10E1C000000000000000000000000000000000004F
+:10E1D000000000000000000000000000000000003F
+:10E1E000000000000000000000000000000000002F
+:10E1F000000000000000000000000000000000809F
+:10E20000000000000000000000000000000000000E
+:10E2100000000000000000000000000000000000FE
+:10E220000000000A000000000000000000000000E4
+:10E2300010000003000000000000000D0000000DB1
+:10E240003C020801244294003C03080124639634F4
+:10E25000AC4000000043202B1480FFFD244200044A
+:10E260003C1D080037BD9FFC03A0F0213C100800B6
+:10E27000261032103C1C0801279C94000E001274DA
+:10E28000000000000000000D3C02800030A5FFFFF0
+:10E2900030C600FF344301803C0880008D0901B87E
+:10E2A0000520FFFE00000000AC6400002404000212
+:10E2B000A4650008A066000AA064000BAC67001803
+:10E2C0003C03100003E00008AD0301B83C0560000A
+:10E2D0008CA24FF80440FFFE00000000ACA44FC029
+:10E2E0003C0310003C040200ACA44FC403E000084F
+:10E2F000ACA34FF89486000C00A050212488001491
+:10E3000000062B0200051080004448210109182B4B
+:10E310001060001100000000910300002C6400094F
+:10E320005080000991190001000360803C0D080134
+:10E3300025AD9090018D58218D67000000E0000808
+:10E340000000000091190001011940210109302B42
+:10E3500054C0FFF29103000003E000080000102108
+:10E360000A000CCC25080001910F0001240E000AC0
+:10E3700015EE00400128C8232F38000A1700003D81
+:10E38000250D00028D580000250F0006370E0100F4
+:10E39000AD4E0000910C000291AB000191A400026F
+:10E3A00091A60003000C2E00000B3C0000A71025D6
+:10E3B00000041A000043C8250326C025AD580004F8
+:10E3C000910E000691ED000191E7000291E5000336
+:10E3D000000E5E00000D6400016C30250007220075
+:10E3E00000C41025004518252508000A0A000CCC99
+:10E3F000AD430008910F000125040002240800022B
+:10E4000055E80001012020210A000CCC00804021A9
+:10E41000910C0001240B0003158B00160000000076
+:10E420008D580000910E000225080003370D0008EA
+:10E43000A14E00100A000CCCAD4D00009119000156
+:10E44000240F0004172F000B0000000091070002AA
+:10E45000910400038D43000000072A0000A410254A
+:10E460003466000425080004AD42000C0A000CCC00
+:10E47000AD46000003E000082402000127BDFFE8CC
+:10E48000AFBF0014AFB000100E0015E50080802172
+:10E490003C0480083485008090A600052403FFFE1C
+:10E4A0000200202100C310248FBF00148FB0001081
+:10E4B000A0A200050A0015EF27BD001827BDFFE840
+:10E4C000AFB00010AFBF00140E000FD40080802149
+:10E4D0003C06800834C5008090A40000240200504F
+:10E4E000308300FF106200073C09800002002021F9
+:10E4F0008FBF00148FB00010AD2001800A0010A65D
+:10E5000027BD0018240801003C07800002002021DC
+:10E510008FBF00148FB00010ACE801800A0010A675
+:10E5200027BD001827BDFF783C058008AFBE0080DE
+:10E53000AFB7007CAFB3006CAFB10064AFBF008475
+:10E54000AFB60078AFB50074AFB40070AFB200687A
+:10E55000AFB0006034A600803C0580008CB201287A
+:10E5600090C400098CA701043C020001309100FF17
+:10E5700000E218240000B8210000F021106000071C
+:10E58000000098213C0908008D2931F02413000176
+:10E59000252800013C010800AC2831F0ACA0008423
+:10E5A00090CC0005000C5827316A0001154000721C
+:10E5B000AFA0005090CD00002406002031A400FF41
+:10E5C00010860018240E0050108E009300000000EA
+:10E5D0003C1008008E1000DC260F00013C010800F2
+:10E5E000AC2F00DC0E00165E000000000040182179
+:10E5F0008FBF00848FBE00808FB7007C8FB60078FD
+:10E600008FB500748FB400708FB3006C8FB2006848
+:10E610008FB100648FB000600060102103E000083B
+:10E6200027BD00880000000D3C1F8000AFA0003017
+:10E6300097E501168FE201043C04002030B9FFFF8A
+:10E64000004438240007182B00033140AFA60030E7
+:10E650008FF5010437F80C003C1600400338802188
+:10E6600002B6A02434C40040128000479215000D69
+:10E6700032A800201500000234860080008030217E
+:10E6800014C0009FAFA600303C0D800835A6008066
+:10E6900090CC0008318B0040516000063C06800899
+:10E6A000240E0004122E00A8240F0012122F003294
+:10E6B0003C06800834C401003C0280009447011AE3
+:10E6C0009619000E909F00088E18000830E3FFFF97
+:10E6D00003F9B00432B40004AFB6005CAFA3005835
+:10E6E0008E1600041280002EAFB8005434C3008090
+:10E6F000906800083105004014A0002500000000CB
+:10E700008C70005002D090230640000500000000ED
+:10E710008C71003402D1A82306A201678EE20008A2
+:10E72000126000063C1280003C1508008EB531F4E2
+:10E7300026B600013C010800AC3631F4AE4000447E
+:10E74000240300018FBF00848FBE00808FB7007C40
+:10E750008FB600788FB500748FB400708FB3006CE3
+:10E760008FB200688FB100648FB00060006010212C
+:10E7700003E0000827BD00880E000D2800002021BE
+:10E780000A000D75004018210A000D9500C02021D7
+:10E790000E0016AE02C020211440FFE10000000070
+:10E7A0003C0B8008356400808C8A003402CA482300
+:10E7B0000520001D000000003C1E08008FDE310017
+:10E7C00027D700013C010800AC3731001260000679
+:10E7D000024020213C1408008E9431F42690000160
+:10E7E0003C010800AC3031F40E0015E53C1E8008F9
+:10E7F00037CD008091B700250240202136EE00047D
+:10E800000E0015EFA1AE00250E000CAC0240202139
+:10E810000A000DCA240300013C17080126F794F8EA
+:10E820000A000D843C1F80008C86003002C66023E5
+:10E830001980000C2419000C908F004F3C14080024
+:10E840008E94310032B500FC35ED0001268E0001BA
+:10E850003C010800AC2E3100A08D004FAFA0005845
+:10E860002419000CAFB900308C9800300316A02397
+:10E870001A80010B8FA300580074F82A17E0FFD309
+:10E88000000000001074002A8FA5005802D4B021A7
+:10E8900000B410233044FFFFAFA4005832A8000298
+:10E8A0001100002E32AB00103C15800836B00080FD
+:10E8B0009216000832D30040526000FB8EE200083E
+:10E8C0000E0015E502402021240A0018A20A0009C2
+:10E8D000921100052409FFFE024020210229902404
+:10E8E0000E0015EFA21200052404003900002821B3
+:10E8F0000E001689240600180A000DCA2403000120
+:10E9000092FE000C3C0A800835490080001EBB00C6
+:10E910008D27003836F10081024020213225F08118
+:10E920000E000C9B30C600FF0A000DC10000000065
+:10E930003AA7000130E300011460FFA402D4B02123
+:10E940000A000E1D00000000024020210E0016CB20
+:10E95000020028210A000D75004018211160FF7087
+:10E960003C0F80083C0D800835EE00808DC40038D7
+:10E970008FA300548DA60004006660231D80FF68ED
+:10E98000000000000064C02307020001AFA400548F
+:10E990003C1F08008FFF31E433F9000113200015FC
+:10E9A0008FAC00583C07800094E3011A10600012FD
+:10E9B0003C0680080E0020F8024020213C0308019C
+:10E9C0009063952930640002148001450000000026
+:10E9D000306C0004118000078FAC0058306600FBDB
+:10E9E0003C010801A026952932B500FCAFA00058D3
+:10E9F0008FAC00583C06800834D30080AFB40018B8
+:10EA0000AFB60010AFAC00143C088000950B01209D
+:10EA10008E6F0030966A005C8FA3005C8FBF003061
+:10EA20003169FFFF3144FFFF8FAE005401341021E4
+:10EA3000350540000064382B0045C82103E7C02598
+:10EA4000AFB90020AFAF0028AFB80030AFAF00249F
+:10EA5000AFA0002CAFAE0034926D000831B40008B6
+:10EA6000168000BB020020218EE200040040F8095D
+:10EA700027A400108FAF003031F300025660000170
+:10EA800032B500FE3C048008349F008093F90008F2
+:10EA900033380040530000138FA400248C850004F9
+:10EAA0008FA7005410A700D52404001432B0000131
+:10EAB0001200000C8FA400242414000C1234011A3C
+:10EAC0002A2D000D11A001022413000E240E000AAD
+:10EAD000522E0001241E00088FAF002425E40001FF
+:10EAE000AFA400248FAA00143C0B80083565008079
+:10EAF000008A48218CB10030ACA9003090A4004EAF
+:10EB00008CA700303408FFFC0088180400E3F821CB
+:10EB1000ACBF00348FA600308FB900548FB8005CB2
+:10EB200030C200081040000B033898218CAC002044
+:10EB3000119300D330C600FF92EE000C8FA7003473
+:10EB400002402021000E6B0035B400800E000C9BAB
+:10EB50003285F0803C028008345000808E0F0030F7
+:10EB600001F1302318C00097264800803C070800B8
+:10EB70008CE731E42404FF80010418243118007F5D
+:10EB80003C1F80003C19800430F10001AFE300908D
+:10EB900012200006031928213C03080190639529DF
+:10EBA00030690008152000C6306A00F73C10800864
+:10EBB00036040080908C004F318B000115600042BC
+:10EBC000000000003C0608008CC6319830CE0010D2
+:10EBD00051C0004230F9000190AF006B55E0003F9A
+:10EBE00030F9000124180001A0B8006B3C1180002E
+:10EBF0009622007A24470064A48700123C0D800806
+:10EC000035A5008090B40008329000401600000442
+:10EC10003C03800832AE000115C0008B00000000EC
+:10EC2000346400808C86002010D3000A3463010015
+:10EC30008C67000002C7782319E000978FBF00544B
+:10EC4000AC93002024130001AC760000AFB3005059
+:10EC5000AC7F000417C0004E000000008FA90050D8
+:10EC60001520000B000000003C030801906395296B
+:10EC7000306A00011140002E8FAB0058306400FE56
+:10EC80003C010801A02495290A000D7500001821F7
+:10EC90000E000CAC024020210A000F1300000000FF
+:10ECA0000A000E200000A0210040F80924040017EB
+:10ECB0000A000DCA240300010040F80924040016CC
+:10ECC0000A000DCA240300019094004F240DFFFE9A
+:10ECD000028D2824A085004F30F900011320000682
+:10ECE0003C0480083C03080190639529307F0010A4
+:10ECF00017E00051306800EF34900080240A0001D2
+:10ED0000024020210E0015E5A60A001292030025FC
+:10ED100024090001AFA90050346200010240202103
+:10ED20000E0015EFA20200250A000EF93C0D800826
+:10ED30001160FE83000018218FA5003030AC000464
+:10ED40001180FE2C8FBF00840A000DCB240300012C
+:10ED500027A500380E000CB6AFA000385440FF4382
+:10ED60008EE200048FB40038329001005200FF3F61
+:10ED70008EE200048FA3003C8E6E0058006E682364
+:10ED800005A3FF39AE6300580A000E948EE200041A
+:10ED90000E0015E5024020213C0380083468008005
+:10EDA000024020210E0015EFA11E000903C03021F2
+:10EDB000240400370E001689000028210A000F11D4
+:10EDC0008FA900508FAB00185960FF8D3C0D800853
+:10EDD0000E0015E502402021920C002524050001BB
+:10EDE000AFA5005035820004024020210E0015EF2F
+:10EDF000A20200250A000EF93C0D800812240059D9
+:10EE00002A2300151060004D240900162408000C68
+:10EE10005628FF2732B000013C0A8008914C001BA5
+:10EE20002406FFBD241E000E01865824A14B001BA2
+:10EE30000A000EA532B000013C010801A028952966
+:10EE40000A000EF93C0D80088CB500308EFE0008DB
+:10EE50002404001826B6000103C0F809ACB600303F
+:10EE60003C030801906395293077000116E0FF818B
+:10EE7000306A00018FB200300A000D753243000481
+:10EE80003C1080009605011A50A0FF2B34C60010DC
+:10EE90000A000EC892EE000C8C6200001456FF6D42
+:10EEA000000000008C7800048FB9005403388823D8
+:10EEB0000621FF638FBF00540A000F0E0000000000
+:10EEC0003C010801A02A95290A000F3030F9000101
+:10EED0001633FF028FAF00240A000EB0241E00106C
+:10EEE0000E0015E5024020213C0B800835680080AB
+:10EEF00091090025240A0001AFAA0050353300040F
+:10EF0000024020210E0015EFA11300253C05080149
+:10EF100090A5952930A200FD3C010801A022952969
+:10EF20000A000E6D004018212411000E53D1FEEA94
+:10EF3000241E00100A000EAF241E00165629FEDC07
+:10EF400032B000013C0A8008914C001B2406FFBD32
+:10EF5000241E001001865824A14B001B0A000EA598
+:10EF600032B000010A000EA4241E00123C038000EF
+:10EF70008C6201B80440FFFE24040800AC6401B8B0
+:10EF800003E00008000000000080502130A5FFFFD2
+:10EF900030C6FFFF3C0480008C8201B80440FFFEB5
+:10EFA00034880180AD0A00003C078008AC8A00204C
+:10EFB00094E300483067FFFF10E000423C0D800002
+:10EFC00024AB001200EB482B5120003F2404000327
+:10EFD00034820100945900208F8900002404001A13
+:10EFE0003338FFFF270BFFFE00EB782B39EE0001D3
+:10EFF00000096B8201AE6024A104000B518000491E
+:10F000008F8B00048F830004A50B0014346800016B
+:10F01000AF88000430CE004015C000333C048000AF
+:10F020003C02800034420180A445000E3C07800071
+:10F0300034EC0180A585001A8F85000C310B80000F
+:10F04000A5890010AD850028A58600081160000F75
+:10F050008F85001434EA0100954E001631CDFFFC77
+:10F0600025A40004008718218C67400030E6FFFFCC
+:10F0700014C000073C0480003C18FFFF370F7FFFDF
+:10F08000010F4024AF8800048F8500143C048000E9
+:10F090002402BFFF348301800102C824A479002622
+:10F0A00010A00004AC69002C00054402A465001007
+:10F0B000A46800263C091000AC8901B803E00008F0
+:10F0C000000000002404000335AC018030CE004075
+:10F0D0008F8900008F880004A184000B51C0FFD1EC
+:10F0E0003C0280003C048000AC8A00203C0F800879
+:10F0F00095EA00403143FFFF5060000834820180F0
+:10F1000000A3C02B5700000100A0182134990180F2
+:10F11000A723000E0A0010053C0780000A00100318
+:10F1200030C6FFBF2407FFFE016740240A000FFE20
+:10F13000AF88000427BDFFE88FA2002830A5FFFF9D
+:10F1400030C6FFFFAFBF0010AF87000CAF820014C6
+:10F15000AF8000040E000FDBAF8000008FBF0010F7
+:10F1600027BD001803E00008AF8000143C068000B3
+:10F1700034C4007034C701008C8A000090E500128E
+:10F180008F84000027BDFFF030A300FF000318822A
+:10F190003082400010400037246500030005C8801D
+:10F1A0000326C0218F0E4000246F0004000F6880EA
+:10F1B000AFAE000001A660218D8B4000AFAB000414
+:10F1C00094E900163128FFFC010638218CE6400046
+:10F1D000AFA600088FA900080000302100002821F8
+:10F1E0003C07080024E701000A00107E24080008FC
+:10F1F0009059000024A500012CAC000C0079C0211E
+:10F200000018788001E770218DCD00001180000684
+:10F2100000CD302603A5102114A8FFF500051A0023
+:10F220005520FFF4905900003C04800034870070A2
+:10F230003C0508008CA531048CE300002CA20020C2
+:10F2400010400009006A3823000548803C0B080084
+:10F25000256B3108012B402124AA0001AD070000D5
+:10F260003C010800AC2A310400C0102103E0000872
+:10F2700027BD0010308220001040000B0005588090
+:10F28000016648218D24400024680004000838806D
+:10F29000AFA4000000E618218C654000AFA0000874
+:10F2A0000A00106EAFA500040000000D0A00106FE8
+:10F2B0008FA9000827BDFFD83C058000AFB100141E
+:10F2C000AFB00010AFBF0024AFB40020AFB3001C3C
+:10F2D000AFB200188F87000034A401009483000EA1
+:10F2E00030E2400000008021104000103071FFFF2C
+:10F2F0003C08002000E8302410C0000D30EB8000F6
+:10F300008F890004240ABFFF00EA38243523100047
+:10F31000AF87000030F320001660000B3C1800049B
+:10F320002419FFBF0A0010CF0079102430EB8000B1
+:10F330001560004D3C0D002030F320001260FFF8F6
+:10F340008F8300043C18000400F8A0241280FFF50D
+:10F350002419FFBF3462004030FF010013E00010A9
+:10F36000AF8200048F820028104000063C0E80000F
+:10F370003C04002000E41824146000CE3C06000485
+:10F380003C0E800035CD010095AC001E95AB001CF5
+:10F390003189FFFF000B5400012A4025AF88000C83
+:10F3A0003C138000367401009692000C8E6340007E
+:10F3B000340FFFFF106F00843244FFFF30780100EC
+:10F3C000570000012410001030F9100053200008ED
+:10F3D0003612000130FF002017E000733C031000DC
+:10F3E00000E310241440006A3C0A0C0036120001AD
+:10F3F00030EC01001580000B3C0600018F880004F2
+:10F40000310D400015A0000800E628243C131F0120
+:10F4100000F378243C0E100011EE00AE3094020090
+:10F420003C06000100E6282410A000193C19100039
+:10F430003C0408008C84002430940002168000D91B
+:10F44000240300018FBF00248FB400208FB3001C61
+:10F450008FB200188FB100148FB00010006010211F
+:10F4600003E0000827BD002800ED60241180FFB3F1
+:10F4700030F320008F8E00043C12FFFF364F7FFFD9
+:10F4800000EF382435C380000A0010BEAF870000AB
+:10F4900000F9C0241700004E00002021AF800010AA
+:10F4A0003C0380003465010094AE000E8F91001083
+:10F4B00031CAFFFF108000C62553000430EF010061
+:10F4C00015E000703C180F003A2800022E7003EF80
+:10F4D0002D1900013A1F0001033F282414A0002227
+:10F4E000240400013C0308008C6300D02E25000C8E
+:10F4F000001121C0386C00012D8B00010165102422
+:10F50000144000143270FFFF262DFFFC2DA40004D0
+:10F510001480010300002021386A00022D460001FA
+:10F5200000C51824546000FF02002821262FFFF890
+:10F530002DEE000415C00007000000000007A242E5
+:10F540000011C02B0298482415200109020028212F
+:10F55000001121C002002821364600020E000FDBF8
+:10F560000000000000002021008018218FBF00242F
+:10F570008FB400208FB3001C8FB200188FB100141D
+:10F580008FB000100060102103E0000827BD0028A4
+:10F590003C090BFF00EA40243526FFFF00C8282B5A
+:10F5A00050A0FF93361200013C0B08008D6B002C1D
+:10F5B00036120005257000013C010800AC30002C1B
+:10F5C0000A0010F630EC01000A0010EB24100020B5
+:10F5D00000071602305F000F001F80C03C030801C7
+:10F5E00024639478020320211080FFADAF9F0010A8
+:10F5F000908800005100FFAB3C0380003C0D800070
+:10F6000035A90100952C000E240B00030240302187
+:10F61000318AFFFF25450004110B00D9000050215D
+:10F620009088000124140002311100FF123400BF41
+:10F6300030F80040310300FF24080001106800C8C2
+:10F6400030E200408C8A00048F8B00245560000655
+:10F6500034C60002254DFE002DAC0381558000010B
+:10F660003646004034C600020140202130A5FFFF8D
+:10F670000E000FDB30C6FFFF000040210A00110A18
+:10F680000100182100F8A0243C0902001289FF8F14
+:10F690003A28000290B100133270FFFF02002821C7
+:10F6A000322700FF24F30004001321C00A00115088
+:10F6B0003646000200E6282414A0FF323C0E8000EB
+:10F6C0000E0010543C1380008F8700000A0010E2E7
+:10F6D000AF82000C1680FF533C0600012624000474
+:10F6E0003085FFFF364600023C0380008C7101B874
+:10F6F0000620FFFE8F890008346A0180AD400000BB
+:10F70000112000B23C0D800024B800120138902B6B
+:10F71000124000AF240C0003347001009603002057
+:10F720002402001A30F94000307FFFFFA142000B95
+:10F73000132000AB27E3FFFE0123582B156000A91F
+:10F740002409FFFE35080001A5430014AF8800041A
+:10F750003C0E80002413BFFF0113782435C80180BC
+:10F76000A505000EA505001AA5060008A50F002690
+:10F77000A50700103C071000ADC701B80000182114
+:10F780008FBF00248FB400208FB3001C8FB20018ED
+:10F790008FB100148FB000100060102103E000084A
+:10F7A00027BD00283C1208008E5200D802202821D4
+:10F7B00024040080265100013C010800AC3100D82F
+:10F7C0000E000FDB240600030A0011D900001821E7
+:10F7D0008C65400030B1010012200046325900040F
+:10F7E0003C1F08008FFF002424140004172000028F
+:10F7F00033F0000D2414000200076AC239A400018E
+:10F800002E6C03EF30820001398B0001004B402544
+:10F81000110000033251FFFB2412FFFB021280246F
+:10F8200030E3010050600015321F00013C0A0F0058
+:10F8300000EA30243C07020010C7000F3C1980008A
+:10F840003725010090A900132418FFFE0218802418
+:10F85000312F00FF25EE0004000E21C0120000022F
+:10F86000023430253226FFFF0E000FDB3265FFFF2A
+:10F870001200FF3D00002021321F000113E0000DA7
+:10F88000320B000424080001120800020234302563
+:10F890003226FFFF000020210E000FDB3265FFFF44
+:10F8A0002402FFFE020280241200FF2F000020210C
+:10F8B000320B00045160000D240400010234302595
+:10F8C00024140004561400013226FFFF2411FFFB0C
+:10F8D0003265FFFF240401000E000FDB02119824A3
+:10F8E0001260FF2100002021240400010A001154AD
+:10F8F000008018213C0C08008D8C00243190000100
+:10F900005200FF19000020213265FFFF3646000239
+:10F910000E000FDB000020210A00115300002021FF
+:10F92000020028210A00115036460002130000068A
+:10F930000000000095300010949F000232190FFF64
+:10F9400013F9FF3D310300FF3C04080190849479D2
+:10F950001080FF3D240800010A00110A010018214F
+:10F960005040FF398C8A00040A00124B000000004E
+:10F970000E000FDB3246FFFB0A00114E001121C0C2
+:10F9800090830001240E0001106EFF3C240800014A
+:10F99000240F0002106F000430F30040240800011F
+:10F9A0000A00110A010018215260FFFD240800011D
+:10F9B000952500109487000230A9FFFF50E9FEA1B1
+:10F9C000010018210A00126124080001240C000320
+:10F9D00035AA0180A14C000B0A0011CE3C0E80001C
+:10F9E0002409FFFE0A0011CC0109402427BDFFC0F5
+:10F9F000AFB00018AFBF003C3C10600CAFBE003889
+:10FA0000AFB70034AFB60030AFB5002CAFB40028AC
+:10FA1000AFB30024AFB20020AFB1001C8E0E500077
+:10FA2000240FFF7F3C06800001CF682435AC380CE2
+:10FA3000240B0003AE0C5000ACCB00083C010800C6
+:10FA4000AC2000200E0017B0000000003C0A00109F
+:10FA5000354980513C066016AE09537C8CC70000C6
+:10FA60003C0860148D0500A03C03FFFF00E3202448
+:10FA70003C02535300051FC21082029B34C57C0018
+:10FA80008CBF007C8CA200783C1E600037C4202014
+:10FA90003C05080124A590C0AF820018AF9F001C50
+:10FAA0000E0016742406000A3C19000127399478C8
+:10FAB0003C010800AC3931DC0E00206BAF80001433
+:10FAC0008FD708082418FFF03C15570902F8B02416
+:10FAD00012D5028B24040001AF8000283C14800062
+:10FAE0003697010002E0F0218E90000032050003FD
+:10FAF00010A0FFFD3207000114E0005D3206000295
+:10FB000010C0FFF93C07800034E501408CB90000CB
+:10FB100024100040ACF9002090B8000833030070B6
+:10FB20001070010B286900411120000824080060B2
+:10FB3000241F0020107F000E3C0B40003C0680007C
+:10FB4000ACCB01780A0012B3000000001468FFFB80
+:10FB50003C0B40000E001F88000000003C0B4000E2
+:10FB60003C068000ACCB01780A0012B30000000014
+:10FB700090AB0009241100048CA70000316800FF3D
+:10FB80001111015D2512FFFA2E53000612600016B6
+:10FB90003C0680008CAA00048F86002494A3000AEF
+:10FBA000000A3E02310500FF10C000053064FFFF6F
+:10FBB0002CEC00081580000224E700042407000351
+:10FBC000240E000910AE01A128AF000A11E0018443
+:10FBD0002410000A2404000810A4001A000749C0D9
+:10FBE000012038213C0680008CD001B80600FFFEC1
+:10FBF00034C40180AC87000034C5014090B60008D1
+:10FC0000241900023C0B400032C200FF00028A00AF
+:10FC10000228F825A49F0008A099000B94A7000AC9
+:10FC20003C081000A48700108CB80004AC98002495
+:10FC3000ACC801B83C068000ACCB01780A0012B316
+:10FC400000000000000AC202330300FF2405000187
+:10FC50005465FFE4012038218F990020AF830024F0
+:10FC600027270001AF8700200A0012F20120382167
+:10FC70008FD100283C0B8008AE9100208FC6000475
+:10FC80008FCA000095690048AF860000AF8A000463
+:10FC90003128FFFF0E000FD4AF8800083C03080096
+:10FCA0008C6300C0106000258F8700003C0E0800A8
+:10FCB0008DCE00C425CD00013C010800AC2D00C450
+:10FCC0003C1F800037E901008D3900243C0760208B
+:10FCD000ACF90014000000003C0680003C08400025
+:10FCE000ACC80138000000005220FF853206000237
+:10FCF000262D0140262E00802404FF8001A4282404
+:10FD000001C47824000F194031CC007F00059940D0
+:10FD100031B2007F3C15200036A20002006C502555
+:10FD20000272B02502C2882501425825ACCB0830AA
+:10FD3000ACD108300A0012B9320600023C120010A1
+:10FD400000F2782415E000708F8300043C1808004E
+:10FD50008F18002097D6000E30F5400027130001C1
+:10FD60003C010800AC3300200000902112A000816B
+:10FD700032D3FFFF3C1F002000FFC8241320007E69
+:10FD800030E580008F8200042404BFFF00E43824A3
+:10FD900034431000AF87000030EB20001160007387
+:10FDA000240EFFBF3C0D000400ED60241180000212
+:10FDB000006E10243462004030EF010011E00010AA
+:10FDC000AF8200048F95002812A000073C18002085
+:10FDD00000F8B02412C000043C1F000400FFC82437
+:10FDE0001320016D0000000096E3001E96E8001C41
+:10FDF0003065FFFF0008140000A22025AF84000C2E
+:10FE000096EA000C8E8440003409FFFF10890085BB
+:10FE10003145FFFF3086010054C00001241200105C
+:10FE200030EB1000116000133656000130EC00205A
+:10FE30001580000A3C0E100000EE682411A0000D91
+:10FE40003C190C003C180BFF00F9B0243715FFFFDC
+:10FE500002B6782B11E00007365600013C1F08005F
+:10FE60008FFF002C3656000527F200013C010800E8
+:10FE7000AC32002C30E401001480000B3C06000181
+:10FE80008F880004310240005440000800E6282416
+:10FE90003C0A1F0100EA48243C0310001123010919
+:10FEA00030A602003C06000100E6282410A0003E17
+:10FEB0003C1810003C0D08008DAD002431AC000250
+:10FEC0001580000624030001006010211040FF830C
+:10FED0003C0680000A00132A3C1F80003C0F0800EB
+:10FEE0008DEF00D8026028212404008025EE000157
+:10FEF0003C010800AC2E00D80E000FDB24060003E6
+:10FF00000A0013AB000018212405BFFF0065682418
+:10FF100011A00007240F87FF006F702415C0000890
+:10FF20003C18006000F8202410800005000000004C
+:10FF30000E000D42000000000A0013AC000000009B
+:10FF40000E00159C000000000A0013AC0000000029
+:10FF50000E0015F4000000003C0B40003C06800041
+:10FF6000ACCB01780A0012B3000000000A0013674E
+:10FF7000006E102430E5800010A0FF878F830004FE
+:10FF80003C08002000E818245060FF838F830004A1
+:10FF90008F8900043C06FFFF34CA7FFF00EA382443
+:10FFA0000A00135E3523800000F8A82416A0001F65
+:10FFB00000004021AF8000103C0380003464010049
+:10FFC0009486000E8F93001030C5FFFF1100014E84
+:10FFD00024B5000430EA0100114000553A7F0002C8
+:10FFE0003C0E0F0000EE68243C0C020011AC0051E6
+:10FFF0002EB203EF908F001332B2FFFF31E400FF07
+:020000040001F9
+:1000000024870004000721C00240282136C60002D0
+:100010000E000FDB00000000000020210A0013ABDF
+:10002000008018210A0013812412002000072602F4
+:100030003099000F0019F8C03C120801265294783C
+:1000400003F240211100FFDCAF990010910900007C
+:100050001120FFDA3C0380003C138000366A010067
+:10006000954B000E2403000302C030213162FFFFD4
+:1000700024450004112300EC000020219109000117
+:10008000240D0002312E00FF11CD00FA313200FFA5
+:10009000240900011249001030FF00408D040004C3
+:1000A0008F8300241460000634D30002248BFE00EA
+:1000B0002D6203815440000136C6004034D3000253
+:1000C00030A5FFFF0E000FDB3266FFFF0000482166
+:1000D0000A0013AB0120182153E0FFF18D04000446
+:1000E0003C080801910894791100FFED24090001F2
+:1000F0000A0013AB012018213C0480008C8A01B84F
+:100100000540FFFE349601802415001CAEC7000098
+:10011000A2D5000B3C021000AC8201B83C0B4000A1
+:100120003C068000ACCB01780A0012B3000000004E
+:100130002EB203EF2FF900013A4900010329C02430
+:100140001700FFB6240400013C0308008C6300D0B4
+:100150002E65000C001321C0386B00012D620001D8
+:10016000004540241500FFA832B2FFFF266AFFFCBD
+:100170002D46000414C0001300002021386D000239
+:100180002DAC0001018518241460000F02402821C5
+:10019000266EFFF82DC5000414A0FF9B0000000090
+:1001A00000077A420013382B01E7A82456A0000864
+:1001B00002402821001321C0024028210A0013FD1B
+:1001C00036C60002024028210A0013FD36C600028E
+:1001D0000E000FDB32C6FFFB0A001467001321C0BC
+:1001E00010B0007200045A022406000B14A6FE7C14
+:1001F000000749C0314600FF00065600000A5E03B2
+:10020000056200B030C6007F000670C03C0F0801D8
+:1002100025EF947801CFA821A2A00001A2A00000A0
+:100220003C1360008E631820240D000100CD4804AB
+:1002300000096027000749C0006C90240120382184
+:10024000AE7218200A0012F2A6A0000214C0004BE1
+:100250008F8C0020000749C03C0B8000AD69002056
+:100260003C118008963F004013E000022405000185
+:10027000240500413C0480008C8A01B80540FFFE43
+:100280003496018024120003AEC90000A2D2000BF4
+:10029000A6C0000EA6C0001AA6C00010AEC000285E
+:1002A000A6C5000896D3002636750001A6D50026FF
+:1002B000AEC0002C3C021000AC8201B80A0012F261
+:1002C0000120382114C0FEF83C060001266B000412
+:1002D0003165FFFF36C600023C0380008C7301B815
+:1002E0000660FFFE8F8900083C0D800035AC018060
+:1002F000AD800000512000DD3C09800024AF0012D9
+:10030000012F702B51C000D93C09800096F20020CB
+:100310003C1980002418001A3256FFFF372A01804A
+:1003200030F54000A158000B12A000D526C3FFFEF7
+:100330000123F82B17E000D32404FFFE3508000149
+:10034000A5430014AF8800042413BFFF3C0B8000BA
+:100350000113502435680180A505000EA505001A7B
+:10036000A5060008A50A0026A50700103C071000F6
+:10037000AE8701B80A0013AB00001821000749C07E
+:100380002583FFFF1460FE16AF8300200120382173
+:100390000A0012F2AF8000240E001054000000008A
+:1003A0008F8700000A001379AF82000C240300FF3E
+:1003B0001163FE0B000749C010C00038000B760027
+:1003C000000B20C03C0908012529947800891821D8
+:1003D00024020001A06200003C16080126D6947891
+:1003E0003C0208012442947C00962821000749C061
+:1003F00000828821000AFC02AE290000A0BF000193
+:100400003C0460008C9818202419000101793804FC
+:100410000307302501203821A4AA0002AC86182049
+:100420000A0012F33C06800091030001241600012B
+:100430001076FF272409000124050002106500043E
+:1004400030E60040240900010A0013AB0120182106
+:1004500050C0FFFD24090001954C0010950A0002D0
+:100460003187FFFF5147FE98012018210A00150B24
+:100470002409000130EF004011E0FF1900000000E6
+:10048000955900109518000233350FFF1715FF140A
+:10049000313200FF0A00141E24090001000E6E0311
+:1004A00005A2000F316B007F10E30008000B20C095
+:1004B0003C10080126109478009018210A0014EED0
+:1004C000240200020A00147BAF8000203C0F0801C8
+:1004D00025EF9478008F18210A0014EE24020003FF
+:1004E0000A001523AF8B00200003A080028698210C
+:1004F0008E7200043C1160000A00129902512821FA
+:100500000A0012B0AF8400288C64400030930100D0
+:100510001260004B240900043C1908008F390024A4
+:1005200032D80004AFA90010170000033332000DC9
+:10053000241F0002AFBF001000071AC2386A000172
+:100540002EA603EF3142000138CB0001004B4025BD
+:100550001100000332D3FFFB2416FFFB0256902448
+:1005600030EC010011800016324800013C0E0F00F3
+:1005700000EE28243C0D020010AD00113C1F80004D
+:1005800037E90100913800138FAF00102419FFFEE6
+:10059000330400FF2487000402599024000721C07F
+:1005A00012400002026F30253266FFFF0E000FDBA3
+:1005B00032A5FFFF1240FE990000202132480001C1
+:1005C0001100000E324A00048FAB0010240200011B
+:1005D00012420002026B30253266FFFF000020212C
+:1005E0000E000FDB32A5FFFF2406FFFE024690241B
+:1005F0001240FE8A00002021324A00045140000EC1
+:10060000240400018FB600102403000412430002EA
+:10061000027630253266FFFF2413FFFB32A5FFFF71
+:10062000240401000E000FDB0253A82412A0FE7B5D
+:1006300000002021240400010A0013AB00801821CF
+:100640003C0C08008D8C0024319200015240FE7356
+:100650000000202132A5FFFF36C600020E000FDB8E
+:10066000000020210A0014000000202124020003C1
+:1006700035230180A062000B0A0014CC2413BFFFB5
+:100680002404FFFE0A0014CA010440243C03800035
+:10069000346401008C85000030A2003E1440000844
+:1006A00000000000AC6000488C87000030E607C006
+:1006B00010C0000500000000AC60004CAC600050B1
+:1006C00003E0000824020001AC600054AC6000406C
+:1006D0008C880000310438001080FFF90000000011
+:1006E0002402000103E00008AC6000443C038000E9
+:1006F0008C6201B80440FFFE34670180ACE4000066
+:1007000024080001ACE00004A4E500082405000270
+:10071000A0E8000A34640140A0E5000B9483000ABD
+:1007200014C00008A4E30010ACE000243C078000E3
+:1007300034E901803C041000AD20002803E00008EB
+:10074000ACE401B88C8600043C041000ACE6002444
+:100750003C07800034E90180AD20002803E0000858
+:10076000ACE401B83C0680008CC201B80440FFFE36
+:1007700034C7018024090002ACE40000ACE40004AA
+:10078000A4E50008A0E9000A34C50140A0E9000B77
+:1007900094A8000A3C041000A4E80010ACE0002477
+:1007A0008CA30004ACE3002803E00008ACC401B84B
+:1007B0003C03900034620001008220253C0380004D
+:1007C000AC6400208C65002004A0FFFE0000000047
+:1007D00003E00008000000003C02800034430001F8
+:1007E0000083202503E00008AC44002027BDFFE083
+:1007F0003C098000AFBF0018AFB10014AFB00010CB
+:10080000352801408D10000091040009910700086F
+:1008100091050008308400FF30E600FF00061A0052
+:100820002C820081008330251040002A30A50080F2
+:10083000000460803C0D080125AD90E8018D582131
+:100840008D6A000001400008000000003C038000A9
+:10085000346201409445000A14A0001E8F91FCB838
+:100860009227000530E6000414C0001A00000000C2
+:100870000E0015E502002021922A00050200202129
+:10088000354900040E0015EFA22900059228000545
+:100890003104000414800002000000000000000D7C
+:1008A000922D0000240B002031AC00FF158B0009B5
+:1008B0003C0580008CAE01B805C0FFFE34B101805C
+:1008C000AE3000003C0F100024100005A230000BD9
+:1008D000ACAF01B80000000D8FBF00188FB100143D
+:1008E0008FB0001003E0000827BD00200200202187
+:1008F00000C028218FBF00188FB100148FB00010E6
+:10090000240600010A0015B427BD00200000000DD8
+:100910000200202100C028218FBF00188FB10014D1
+:100920008FB00010000030210A0015B427BD002050
+:1009300014A0FFE800000000020020218FBF001873
+:100940008FB100148FB0001000C028210A0015D20A
+:1009500027BD00203C0780008CEE01B805C0FFFEDB
+:1009600034F00180241F0002A21F000B34F8014064
+:10097000A60600089719000A3C0F1000A6190010DF
+:100980008F110004A6110012ACEF01B80A00163056
+:100990008FBF001827BDFFE8AFBF00100E000FD4B7
+:1009A000000000003C0280008FBF001000002021EA
+:1009B000AC4001800A0010A627BD00183084FFFF5C
+:1009C00030A5FFFF108000070000182130820001D1
+:1009D0001040000200042042006518211480FFFB33
+:1009E0000005284003E000080060102110C0000747
+:1009F000000000008CA2000024C6FFFF24A5000414
+:100A0000AC82000014C0FFFB2484000403E0000853
+:100A10000000000010A0000824A3FFFFAC86000027
+:100A200000000000000000002402FFFF2463FFFF1D
+:100A30001462FFFA2484000403E0000800000000B0
+:100A40003C03800027BDFFF834620180AFA20000A4
+:100A5000308C00FF30AD00FF30CE00FF3C0B80003B
+:100A60008D6401B80480FFFE000000008FA9000023
+:100A70008D6801288FAA00008FA700008FA40000B6
+:100A80002405000124020002A085000A8FA30000B3
+:100A9000359940003C051000A062000B8FB80000A3
+:100AA0008FAC00008FA600008FAF000027BD0008AC
+:100AB000AD280000AD400004AD800024ACC000288B
+:100AC000A4F90008A70D0010A5EE001203E000082D
+:100AD000AD6501B83C06800827BDFFE834C500803D
+:100AE000AFBF001090A700092402001230E300FFFE
+:100AF0001062000B008030218CA800500088202359
+:100B0000048000088FBF00108CAA00342404003930
+:100B10000000282100CA48230520000524060012F1
+:100B20008FBF00102402000103E0000827BD001859
+:100B30000E001689000000008FBF00102402000183
+:100B400003E0000827BD001827BDFFC8AFB2003082
+:100B5000AFB00028AFBF0034AFB1002C00A080219F
+:100B600090A5000D30A6001010C00010008090214C
+:100B70003C0280088C4400048E0300081064000CC2
+:100B800030A7000530A6000510C000932404000122
+:100B90008FBF00348FB200308FB1002C8FB000288F
+:100BA0000080102103E0000827BD003830A70005B1
+:100BB00010E0000F30AB001210C00006240400014A
+:100BC0003C0980088E0800088D2500045105009C12
+:100BD000240400388FBF00348FB200308FB1002C56
+:100BE0008FB000280080102103E0000827BD0038E6
+:100BF000240A0012156AFFE62404000102002021E5
+:100C000027A500100E000CB6AFA000101440007C09
+:100C10003C198008372400809098000833110008A0
+:100C20001220000A8FA7001030FF010013E000A47B
+:100C30008FA300148C860058006610230440000423
+:100C40003C0A8008AC8300588FA700103C0A80083B
+:100C50003548008091090008312400081480000202
+:100C600024080003000040213C1F800893F100117C
+:100C700093F9001237E600808CCC0054333800FF23
+:100C800003087821322D00FF000F708001AE28216B
+:100C900000AC582B1160006F0000000094CA005C8B
+:100CA0008CC900543144FFFF012510230082182B0A
+:100CB00014600068000000008CCB0054016518230C
+:100CC00030EC00041180006C000830808FA8001CFC
+:100CD0000068102B1040006230ED00040066102305
+:100CE0002C46008010C000020040882124110080A2
+:100CF0000E0015E5024020213C0D800835A600803D
+:100D000024070001ACC7000C90C80008001148403F
+:100D100035A70100310C007FA0CC00088E0500042F
+:100D200024AB0001ACCB0030A4D1005C8CCA003CE9
+:100D30009602000E01422021ACC400208CC3003C6E
+:100D40000069F821ACDF001C8E190004ACF900002A
+:100D50008E180008ACF800048FB10010322F000884
+:100D600055E0004793A60020A0C0004E90D8004E4A
+:100D70002411FFDFA0F8000890CF000801F17024D3
+:100D8000A0CE00088E0500083C0B80083569008065
+:100D9000AD2500388D6A00148D22003024190050D2
+:100DA00001422021AD24003491230000307F00FF58
+:100DB00013F90036264F01000E0015EF02402021E6
+:100DC00024040038000028210E0016892406000A99
+:100DD0000A0016EE240400010E000D280000202158
+:100DE0008FBF00348FB200308FB1002C8FB000283D
+:100DF000004020210080102103E0000827BD0038BA
+:100E00008E0E00083C0F800835F00080AE0E0054B6
+:100E100002402021AE0000300E0015E50000000069
+:100E2000920D00250240202135AC00200E0015EF68
+:100E3000A20C00250E000CAC024020212404003836
+:100E40002405008D0E001689240600120A0016EEF5
+:100E50002404000194C5005C0A00172930A3FFFF99
+:100E60002407021811A0FF9E00E610238FAE001C7D
+:100E70000A00173101C610230A00172E2C6202182F
+:100E8000A0E600080A00175B8E0500082406FF8014
+:100E900001E6C0243C118000AE3800288E0D000809
+:100EA00031E7007F3C0E800C00EE6021AD8D00E04C
+:100EB0008E080008AF8C00340A001767AD8800E484
+:100EC000AC800058908500082403FFF700A3382465
+:100ED000A08700080A00170C8FA700103C05080027
+:100EE00024A55F043C04080024846E503C020800E2
+:100EF00024425F0C240300063C010801AC2594F851
+:100F00003C010801AC2494FC3C010801AC22950092
+:100F10003C010801A023950403E000080000000044
+:100F200003E00008240200013C028000308800FF3A
+:100F3000344701803C0680008CC301B80460FFFE8A
+:100F4000000000008CC501282418FF803C0D800A99
+:100F500024AF010001F8702431EC007FACCE0024F6
+:100F6000018D2021ACE50000948B00EA350960007A
+:100F700024080002316AFFFFACEA000424020001E9
+:100F8000A4E90008A0E8000BACE000243C07100036
+:100F9000ACC701B8AF84003403E00008AF85006837
+:100FA000938800448F89005C8F82003430C600FF34
+:100FB0000109382330E900FF0122182130A500FF84
+:100FC0002468008810C000020124382100803821E4
+:100FD00030E400031480000330AA00031140000D28
+:100FE000312B000310A000090000102190ED00003B
+:100FF000244E000131C200FF0045602BA10D00000E
+:1010000024E700011580FFF92508000103E000082E
+:10101000000000001560FFF30000000010A0FFFBBF
+:10102000000010218CF8000024590004332200FF36
+:101030000045782BAD18000024E7000415E0FFF907
+:101040002508000403E00008000000009385004428
+:10105000938800548F87005C000432003103007FC6
+:1010600000E5102B30C47F001040000F00642825DD
+:101070008F8400343C0980008C8A00ECAD2A00A4E7
+:101080003C03800000A35825AC6B00A08C6C00A032
+:101090000580FFFE000000008C6D00ACAC8D00EC04
+:1010A00003E000088C6200A80A0018198F8400343D
+:1010B000938800553C02800000805021310300FEDF
+:1010C000A383005530ABFFFF30CC00FF30E7FFFFBC
+:1010D000344801803C0980008D2401B80480FFFE63
+:1010E0008F8D006824180016AD0D00008D2201249C
+:1010F0008F8D0034AD0200048D590020A507000833
+:10110000240201C4A119000AA118000B952F012087
+:101110008D4E00088D470004978300588D59002498
+:1011200001CF302100C7282100A320232418FFFF6E
+:10113000A504000CA50B000EA5020010A50C0012C2
+:10114000AD190018AD18002495AF00E83C0B100055
+:101150002407FFF731EEFFFFAD0E00288DAC0084B1
+:10116000AD0C002CAD2B01B88D46002000C7282403
+:1011700003E00008AD4500208F880034008058212E
+:1011800030E7FFFF910900D63C02800030A5FFFF49
+:10119000312400FF00041A000067502530C600FF0C
+:1011A000344701803C0980008D2C01B80580FFFE8A
+:1011B0008F820068240F0017ACE200008D390124F3
+:1011C000ACF900048D780020A4EA0008241901C4B9
+:1011D000A0F8000AA0EF000B952301208D6E0008F7
+:1011E0008D6D00049784005801C35021014D60218A
+:1011F00001841023A4E2000CA4E5000EA4F9001061
+:10120000A4E60012ACE000148D780024240DFFFF4A
+:10121000ACF800188D0F007CACEF001C8D0E007830
+:101220003C0F1000ACEE0020ACED0024950A00BE8F
+:10123000240DFFF73146FFFFACE60028950C008037
+:101240009504008231837FFF0003CA003082FFFFD4
+:101250000322C021ACF8002CAD2F01B8950E0082FE
+:101260008D6A002000AE3021014D2824A5060082A1
+:1012700003E00008AD6500203C0280003445018099
+:101280003C0480008C8301B80460FFFE8F8A00401C
+:10129000240600199549001C3128FFFF000839C0B9
+:1012A000ACA70000A0A6000B3C05100003E000085E
+:1012B000AC8501B88F8700480080402130C400FF12
+:1012C0003C0680008CC201B80440FFFE8F89006894
+:1012D0009383006434996000ACA90000A0A30005CA
+:1012E0008CE20010240F00022403FFF7A4A20006E2
+:1012F000A4B900088D180020A0B8000AA0AF000B08
+:101300008CEE0000ACAE00108CED0004ACAD00140F
+:101310008CEC001CACAC00248CEB0020ACAB0028A7
+:101320008CEA002C3C071000ACAA002C8D0900248C
+:10133000ACA90018ACC701B88D05002000A320247B
+:1013400003E00008AD0400208F86003427BDFFE0D5
+:10135000AFB10014AFBF0018AFB0001090C300D4FD
+:1013600030A500FF30620020104000080080882176
+:101370008CCB00D02409FFDF256A0001ACCA00D065
+:1013800090C800D401093824A0C700D414A000409C
+:101390003C0C80008F840034908700D42418FFBF59
+:1013A0002406FFEF30E3007FA08300D4979F00580E
+:1013B0008F82005C8F8D003403E2C823A799005808
+:1013C000A5A000BC91AF00D401F87024A1AE00D458
+:1013D0008F8C0034A18000D78F8A0034A540008212
+:1013E000AD4000EC914500D400A65824A14B00D498
+:1013F0008F9000308F84005C97860058020428216B
+:1014000010C0000FAF850030A38000543C0780005F
+:101410008E2C000894ED01208E2B0004018D5021AC
+:10142000014B8021020620233086FFFF30C8000FC9
+:10143000390900013131000116200009A388005448
+:10144000938600448FBF00188FB100148FB0001036
+:1014500027BD0020AF85006003E00008AF86005C78
+:1014600000C870238FBF0018938600448FB100140A
+:101470008FB0001034EF0C00010F282127BD002091
+:10148000ACEE0084AF85006003E00008AF86005C2E
+:1014900035900180020028210E0018A62406008243
+:1014A0008F840034908600D430C5004050A0FFBA2D
+:1014B000A38000648F8500483C0680008CCD01B875
+:1014C00005A0FFFE8F8900682408608224070002BF
+:1014D000AE090000A6080008A207000B8CA30008B4
+:1014E0003C0E1000AE0300108CA2000CAE020014E3
+:1014F0008CBF0014AE1F00188CB90018AE19002460
+:101500008CB80024AE1800288CAF0028AE0F002C39
+:10151000ACCE01B80A0018DFA38000648F8A0034C3
+:1015200027BDFFE0AFB10014AFB000108F88005CA2
+:10153000AFBF001893890038954200BC30D100FF3E
+:101540000109182B0080802130AC00FF3047FFFFDD
+:101550000000582114600003310600FF01203021F3
+:1015600001095823978300580068202B1480002716
+:101570000000000010680056241900011199006352
+:1015800034E708803165FFFF0E0018570200202164
+:101590008F8300683C07800034E601803C058000B2
+:1015A0008CAB01B80560FFFE240A00188F8400345C
+:1015B000ACC30000A0CA000B948900BE3C08100018
+:1015C000A4C90010ACC00030ACA801B8948200805F
+:1015D00024430001A4830080949F00803C060800FF
+:1015E0008CC6318833EC7FFF1186005E000000005E
+:1015F00002002021022028218FBF00188FB1001483
+:101600008FB000100A0018CB27BD0020914400D4F1
+:101610002403FF8000838825A15100D497840058BB
+:101620003088FFFF51000023938C00388F850034F1
+:101630002402EFFF008B782394AE00BC0168502B8E
+:1016400031E900FF01C26824A4AD00BC514000395B
+:10165000010058213C1F800037E601008CD80004AF
+:101660003C190001031940245500000134E74000F3
+:101670008E0A00202403FFFB2411000101432024D3
+:10168000AE0400201191002D34E7800002002021DB
+:10169000012030210E0018573165FFFF9787005851
+:1016A0008F89005CA780005801278023AF90005CE1
+:1016B000938C00388F8B00348FBF00188FB10014CB
+:1016C0008FB0001027BD002003E00008A16C00D7F8
+:1016D0003C0D800035AA01008D4800043C09000142
+:1016E0000109282454A0000134E740008E0F002097
+:1016F0002418FFFB34E7800001F87024241900014E
+:10170000AE0E00201599FF9F34E7088002002021CB
+:101710000E0018253165FFFF02002021022028213C
+:101720008FBF00188FB100148FB000100A0018CBC3
+:1017300027BD00200A00198E000048210200202148
+:10174000012030210E0018253165FFFF97870058D2
+:101750008F89005CA7800058012780230A0019A503
+:10176000AF90005C948C0080241F8000019F302487
+:10177000A4860080908B0080908F0080316700FFEE
+:101780000007C9C20019C027001871C031ED007FE1
+:1017900001AE2825A08500800A00197602002021CC
+:1017A000938500642403000127BDFFE800A33004F3
+:1017B0002CA20020AFB00010AFBF001400C0182151
+:1017C000104000132410FFFE3C0708008CE7319006
+:1017D00000E610243C088000350501801440000517
+:1017E000240600848F890034240A00042410FFFF9B
+:1017F000A12A00FC0E0018A6000000000200102123
+:101800008FBF00148FB0001003E0000827BD001840
+:101810003C0608008CC631940A0019EE00C310245F
+:101820008F87004027BDFFE0AFB20018AFB10014B2
+:10183000AFB00010AFBF001C30D000FF90E6000D2D
+:1018400000A088210080902130C5007FA0E5000D18
+:101850008F8500348E2300188CA200D01062002ED9
+:10186000240A000E0E0019E1A38A00642409FFFF78
+:10187000104900222404FFFF520000200000202114
+:101880008E2600003C0C001000CC58241560003956
+:101890003C0E000800CE682455A0003F02402021E5
+:1018A0003C18000200D880241200001F3C0A0004EB
+:1018B0008F8700408CE200148CE300108CE500144C
+:1018C0000043F82303E5C82B132000050240202124
+:1018D0008E24002C8CF10010109100310240202148
+:1018E00024020012A38200640E0019E12412FFFFFB
+:1018F000105200022404FFFF000020218FBF001CB3
+:101900008FB200188FB100148FB00010008010212A
+:1019100003E0000827BD002090A800D43504002073
+:101920000A001A17A0A400D400CA48241520000BEE
+:101930008F8B00408F8D00408DAC00101580000B08
+:10194000024020218E2E002C51C0FFEC00002021EF
+:10195000024020210A001A32240200178D6600106E
+:1019600050C0FFE600002021024020210A001A3268
+:101970002402001102402021240200150E0019E16A
+:10198000A3820064240FFFFF104FFFDC2404FFFF3D
+:101990000A001A218E2600000A001A582402001498
+:1019A0003C08000400C8382450E0FFD40000202187
+:1019B000024020210A001A32240200138F850034CD
+:1019C00027BDFFD8AFB3001CAFB20018AFB10014F1
+:1019D000AFB00010AFBF002090A700D48F90004898
+:1019E0002412FFFF34E2004092060000A0A200D4BF
+:1019F0008E030010008098211072000630D1003F45
+:101A00002408000D0E0019E1A3880064105200257F
+:101A10002404FFFF8F8A00348E0900188D4400D003
+:101A20001124000702602021240C000E0E0019E191
+:101A3000A38C0064240BFFFF104B001A2404FFFF4B
+:101A400024040020122400048F8D003491AF00D4B0
+:101A500035EE0020A1AE00D48F85005010A00019F3
+:101A6000000000001224004A8F9800348F92FCB8C6
+:101A7000971000809651000A523000488F93003C26
+:101A80003C1F08008FFF318C03E5C82B1720001E78
+:101A900002602021000028210E00194024060001C8
+:101AA000000020218FBF00208FB3001C8FB20018D0
+:101AB0008FB100148FB000100080102103E00008E7
+:101AC00027BD00285224002A8E0500148F8400347C
+:101AD000948A008025490001A489008094880080B0
+:101AE0003C0208008C42318831077FFF10E2000E73
+:101AF00000000000026020210E0018CB2405000128
+:101B00000A001AA2000020212402002D0E0019E173
+:101B1000A38200642403FFFF1443FFE12404FFFFBA
+:101B20000A001AA38FBF002094990080241F800010
+:101B300024050001033FC024A498008090920080F7
+:101B4000908E0080325100FF001181C20010782772
+:101B5000000F69C031CC007F018D5825A08B00801B
+:101B60000E0018CB026020210A001AA200002021DA
+:101B70002406FFFF54A6FFD68F8400340260202184
+:101B80000E0018CB240500010A001AA20000202133
+:101B9000026020210A001ABC2402000A2404FFFD6E
+:101BA0000A001AA2AF93005C8F88003427BDFFE8BB
+:101BB000AFB00010AFBF0014910A00D48F87004867
+:101BC00000808021354900408CE60010A10900D436
+:101BD0003C0208008C4231B030C53FFF00A2182BF8
+:101BE000106000078F85004C240DFF8090AE000D23
+:101BF00001AE6024318B00FF156000080006C3822F
+:101C0000020020212403000D8FBF00148FB00010AC
+:101C100027BD00180A0019E1A383006433060003FE
+:101C2000240F000254CFFFF70200202194A2001CD1
+:101C30008F85003424190023A4A200E88CE800005A
+:101C400000081E02307F003F13F900353C0A008374
+:101C50008CE800188CA600D01106000800000000D7
+:101C60002405000E0E0019E1A38500642407FFFF80
+:101C7000104700182404FFFF8F85003490A900D47A
+:101C800035240020A0A400D48F8C0040918E000D3C
+:101C900031CD007FA18D000D8F8300501060001C9E
+:101CA000020020218F84004C8C9800100303782BB5
+:101CB00011E0000D2419001802002021A3990064EE
+:101CC0000E0019E12410FFFF105000022404FFFF52
+:101CD000000020218FBF00148FB000100080102161
+:101CE00003E0000827BD00188C8600108F9F00407D
+:101CF0000200202100C31023AFE2001024050001E0
+:101D00000E001940240600010A001B2E00002021AD
+:101D10000E0018CB240500010A001B2E0000202114
+:101D2000010A5824156AFFD98F8C0040A0A600FC38
+:101D30000A001B1BA386005630A500FF24060001E5
+:101D400024A9000100C9102B1040000C0000402104
+:101D5000240A000100A61823308B000124C60001CC
+:101D6000006A3804000420421160000200C9182BE8
+:101D7000010740251460FFF800A6182303E00008BF
+:101D80000100102127BDFFD8AFB000188F90004888
+:101D9000AFB1001CAFBF00202403FFFF2411002FB0
+:101DA000AFA30010920600002405000826100001D1
+:101DB000006620260E001B47308400FF00021E0034
+:101DC0003C021EDC34466F410A001B6F00001021EC
+:101DD00010A00009008018212445000130A2FFFF57
+:101DE0002C4500080461FFFA0003204000862026ED
+:101DF00014A0FFF9008018210E001B4724050020C5
+:101E00008FA300102629FFFF313100FF000342029B
+:101E1000240700FF1627FFE20102182600035027BF
+:101E2000AFAA0014AFAA00100000302127A80010AC
+:101E300027A7001400E6782391ED000324CE0001CB
+:101E400000C8602131C600FF2CCB00041560FFF9EB
+:101E5000A18D00008FA200108FBF00208FB1001C49
+:101E60008FB0001803E0000827BD002827BDFFD071
+:101E7000AFB3001CAFB00010AFBF0028AFB5002457
+:101E8000AFB40020AFB20018AFB100143C0C80001A
+:101E90008D880128240FFF803C06800A2510010050
+:101EA000250B0080020F68243205007F016F70242B
+:101EB000AD8E009000A62821AD8D002490A600FCD8
+:101EC0003169007F3C0A8004012A1821A38600564C
+:101ED0009067007C00809821AF83002C30E20002E4
+:101EE000AF880068AF85003400A0182114400002BC
+:101EF0002404003424040030A38400448C7200DCE9
+:101F000030D100FF24040004AF92005C12240004CE
+:101F1000A38000648E7400041680001E3C088000BC
+:101F20009386005530C7000150E0000F8F86005C9B
+:101F30008CA400848CA800842413FF800093602468
+:101F4000000C49403110007F013078253C192000F9
+:101F500001F9682530DF00FE3C038000AC6D0830DD
+:101F6000A39F00558F86005C8FBF00288FB500248B
+:101F70008FB400208FB3001C8FB200188FB10014F3
+:101F80008FB000102402000127BD003003E00008DC
+:101F9000ACA600DC8E7F0008950201208E67001041
+:101FA00003E2C8213326FFFF30D8000F33150001AC
+:101FB000AF87003016A00058A398005435090C00D4
+:101FC0000309382100D81823AD030084AF870060CF
+:101FD0008E6A00043148FFFF1100007EA78A005876
+:101FE00090AC00D42407FF8000EC302430CB00FFFD
+:101FF0001560004B97860058938E0056240D000202
+:1020000030D5FFFF11CD02A20000A0218F85005C1A
+:1020100002A5802B160000BC938800443C11800070
+:1020200096240120310400FF148500888F8400600D
+:102030008F980030331200035640008530A500FF12
+:102040008F900060310C00FF24060034118600954B
+:10205000AF90004892040004148001198F8E003460
+:10206000A38000388E0D00048DC800D83C0600FF08
+:1020700034CCFFFF01AC30240106182B1460012181
+:10208000AF8600508F87005C97980058AF87003C60
+:102090000307402310C000C7A78800588F91002C69
+:1020A00030C3000300035823922A007C31710003DF
+:1020B00002261021000A208230920001001248807E
+:1020C00000492821311FFFFF03E5C82B1320012001
+:1020D0008F8800348F8500308F8800601105025A88
+:1020E0003C0E3F018E0600003C0C250000CE68240B
+:1020F00011AC01638F84004830E500FF0E0017E14A
+:10210000000030218F8800348F87005C8F8500307D
+:102110000A001D4E8F8600500A001BEDAF8700603D
+:1021200090AC00D400EC2024309000FF1200001688
+:102130009386005590B5008890B400D724A80088F5
+:1021400032A2003F2446FFE02CD10020A3940038A7
+:102150001220000CAF880048240E000100CE20049D
+:10216000308A00191540012B3C06800034D800024B
+:10217000009858241560022E309200201640023438
+:10218000000000009386005530CE000111C0000F02
+:10219000978800588CA900848CAF00842410FF809D
+:1021A0000130C8240019194031ED007F006D382539
+:1021B0003C1F200000FF902530CB00FE3C18800023
+:1021C000AF120830A38B0055978800581500FF8484
+:1021D000000000008E630020306C00041180FF516D
+:1021E000938600552404FFFB006430243C038000E8
+:1021F000AE660020346601808C7301B80660FFFE75
+:102200008F8E0068346A01003C150001ACCE0000DE
+:102210008C62012424076085ACC200048D54000444
+:1022200002958824522000012407608324120002B2
+:102230003C1810003C0B8000A4C70008A0D2000B83
+:10224000AD7801B80A001BC29386005530A500FF87
+:102250000E0017E1240600018F8800683C0580000D
+:1022600034A909002502018893880044304A0007F8
+:10227000304B00783C0340802407FF800163C82571
+:10228000014980210047F824310C00FF2406003466
+:10229000ACBF0800AF900048ACB908105586FF6E7F
+:1022A000920400048F8400348E110030908E00D48C
+:1022B00031CD001015A000108F83005C2C6F00053D
+:1022C00015E000E400000000909800D42465FFFCB5
+:1022D000331200101640000830A400FF8F9F0060EA
+:1022E0008F99003013F900043887000130E20001B3
+:1022F000144001C8000000000E001B5A000000003E
+:102300000A001D8F000000008F84006030C500FFB0
+:102310000E0017E124060001938E0044240A0034C5
+:1023200011CA00A08F8500348F86005C9783005807
+:102330003062FFFF00C28823AF91005CA780005885
+:102340001280FF90028018212414FFFD5474FFA214
+:102350008E6300208E6900042403FFBF240BFFEF6F
+:102360000135C823AE79000490AF00D431ED007F71
+:10237000A0AD00D48E6600208F980034A78000584E
+:1023800034DF0002AE7F0020A70000BC931200D40F
+:1023900002434024A30800D48F950034AEA000EC83
+:1023A00092AE00D401CB5024A2AA00D40A001C6E25
+:1023B0008F8500348F910030AF80005C0227582158
+:1023C000AF8B0030000020212403FFFF108301B4F5
+:1023D0008F8500348E0C00103C0D08008DAD31B09F
+:1023E0009208000031843FFF008D802B12000023F3
+:1023F000310D003F3C1908008F3931A88F9F0068CC
+:10240000000479802408FF80033F2021008FC82129
+:10241000938500550328F8243C0600803C0F80007B
+:1024200034D80001001F91403331007F8F86003483
+:102430000251502535EE0940332B00783330000728
+:102440003C0310003C02800C01789025020E4821CC
+:102450000143C0250222382134AE0001ADFF08043B
+:10246000AF89004CADF20814AF870040ADFF0028E3
+:10247000ACD90084ADF80830A38E00559383005684
+:10248000240700035067002825A3FFE0240C000167
+:10249000146CFFAB8F8500342411002311B100842C
+:1024A000000000002402000B026020210E0019E150
+:1024B000A38200640040A0210A001CC98F8500345B
+:1024C00002602021240B000C0E0019E1A38B006494
+:1024D000240AFFFF104AFFBC2404FFFF8F8E003444
+:1024E000A38000388E0D00048DC800D83C0600FF84
+:1024F00034CCFFFF01AC30240106182B1060FEE144
+:10250000AF86005002602021241200190E0019E14C
+:10251000A3920064240FFFFF104FFFAB2404FFFFC2
+:102520000A001C1A8F8600502C7400201280FFDED7
+:102530002402000B000328803C110801263192EC94
+:1025400000B148218D2D000001A00008000000000E
+:102550008F85003000A7102193850038AF820030AE
+:1025600002251821A3830038951F00BC02262821CC
+:1025700037F91000A51900BC5240FF92AF85005CEE
+:10258000246A0004A38A0038950900BC24A400042E
+:10259000AF84005C35322000A51200BC0A001CEBA1
+:1025A000000020218F86005C2CCB00051560FF60A9
+:1025B000978300583072FFFF00D240232D1800058A
+:1025C00013000003306400FF24DFFFFC33E400FF4E
+:1025D0008F8500608F86003010A60004388F0001C0
+:1025E00031ED000115A00138000000008F84003497
+:1025F000908C00D435870010A08700D48F850034DC
+:102600008F86005C97830058ACA000EC0A001CC6C3
+:102610003062FFFF8CAA00848CB500843C0410005B
+:10262000014710240002894032B4007F0234302573
+:1026300000C460253C0880002405000102602021C0
+:10264000240600010E001940AD0C08300A001C5A87
+:102650008F8500348C8200EC1222FE7E02602021E5
+:1026600024090005A38900640E0019E12411FFFF6D
+:102670001451FE782404FFFF0A001CEC2403FFFF22
+:102680008F8F00488F8800348DF80000AD180088C7
+:102690008DE70010AD0700988F87005C0A001D4E83
+:1026A0008F8600502407FFFF1187000500000000FF
+:1026B0000E001AE3026020210A001D270040A0211D
+:1026C0000E001A68026020210A001D270040A02188
+:1026D0008F9000483C0908008D2931B08E11001000
+:1026E00032323FFF0249682B11A0000C240AFF8000
+:1026F0008F85004C90AE000D014E1024304C00FF31
+:1027000011800007026020210011C38233030003FF
+:10271000240B0001106B0105000000000260202165
+:102720002418000D0E0019E1A39800640040202138
+:102730008F8500340A001CC90080A0218F900048BA
+:102740003C0A08008D4A31B08F85004C8E04001081
+:102750000000A0218CB1001430823FFF004A602BA2
+:102760008CB200205180FFEE0260202190B8000D55
+:10277000240BFF800178702431C300FF5060FFE814
+:1027800002602021000443823106000314C0FFE4EC
+:102790000260202194BF001C8F9900348E0600280F
+:1027A000A73F00E88CAF0010022F202314C401398A
+:1027B000026020218F83005000C36821022D382B36
+:1027C00014E00135240200188F8A00408F82002C0B
+:1027D000024390218D4B001001637023AD4E001019
+:1027E000AD5200208C4C00740192282B14A001568D
+:1027F000026020218F84004C8E0800248C860024E7
+:1028000011060007026020212419001C0E0019E1A6
+:10281000A3990064240FFFFF104FFFC52404FFFF9E
+:102820008F8400408C87002424FF0001AC9F00248B
+:10283000125101338F8D002C8DB100741232013092
+:102840003C0B00808E0E000001CB5024154000751B
+:10285000000000008E0300142411FFFF1071000619
+:10286000026020212418001B0E0019E1A3980064C7
+:102870001051FFAF2404FFFF8E0300003C0800014D
+:102880000068302410C000133C0400800064A024C1
+:102890001680000902002821026020212419001A54
+:1028A0000E0019E1A3990064240FFFFF104FFFA051
+:1028B0002404FFFF02002821026020210E001A01DB
+:1028C000240600012410FFFF1050FF992404FFFF8D
+:1028D000241400018F9F00400260202102803021DB
+:1028E00097F100342405000126270001A7E70034F2
+:1028F0000E00194000000000000020218F850034E8
+:102900000A001CC90080A0218F9000483C140800D8
+:102910008E9431B08E07001030E83FFF0114302B49
+:1029200010C000618F86004C241FFF8090C5000DF1
+:1029300003E52024309200FF5240005C0260202119
+:102940008F8D005011A0000700078B828F85003407
+:102950008F89FCB894AF00809539000A132F00F6D8
+:102960008F87003C322C00031580006300000000BC
+:1029700092020002104000D7000000008E0A0024DE
+:10298000154000D8026020219204000324060002B2
+:10299000308800FF15060005308500FF8F94005039
+:1029A000528000F202602021308500FF38AD001017
+:1029B0002DA400012CBF000103E4302502002821D2
+:1029C0000E001A01026020212410FFFF105000BEEB
+:1029D0008F8500348F830050106000C424050001EF
+:1029E0003C1908008F39318C0323782B15E000B196
+:1029F0002409002D02602021000028210E0019402A
+:102A0000240600018F850034000018210A001CC92B
+:102A10000060A0210E00180C000000000A001D8FAD
+:102A200000000000AC8000200A001E0F8E0300147E
+:102A300000002821026020210E0019402406000118
+:102A40000A001C5A8F8500340A001D4E8F880034FE
+:102A50008CB000848CB900843C0310000207482429
+:102A600000096940332F007F01AFF82503E32825D3
+:102A7000ACC5083091070001240500010260202147
+:102A80000E00194030E600010A001C5A8F85003400
+:102A9000938F00442403FFFD0A001CCBAF8F005C22
+:102AA0000A001CCB2403FFFF026020212410000D2C
+:102AB0000E0019E1A3900064004018218F850034B6
+:102AC0000A001CC90060A0210E00180C00000000C4
+:102AD000978300588F86005C3070FFFF00D048233A
+:102AE0002D3900051320FE128F850034ACA200ECB6
+:102AF0000A001CC63062FFFF90C3000D307800084A
+:102B00005700FFA29204000302602021240200105B
+:102B10000E0019E1A38200642403FFFF5443FF9BCE
+:102B2000920400030A001EA98F85003490A8000DAE
+:102B30003106000810C000958F9400501680009E4A
+:102B4000026020218E0F000C8CA4002055E40005AB
+:102B5000026020218E1F00088CB9002413F9003A6E
+:102B600002602021240200200E0019E1A3820064EB
+:102B70002405FFFF1045FEEE2404FFFF8F8F004069
+:102B8000240CFFF72403FF8091E9000D3C14800E14
+:102B90003C0B8000012CC824A1F9000D8F8F002C64
+:102BA0003C0708008CE731AC8F8D006895E5007814
+:102BB0008F99004000ED902130BF7FFF001F204023
+:102BC0000244302130C8007F00C3C02401147021AA
+:102BD000AD78002CA5D100008F2A002825420001E5
+:102BE000AF2200288F29002C8E0C002C012C68218C
+:102BF000AF2D002C8E07002CAF2700308E0500145F
+:102C0000AF250034973F003A27E40001A724003A9B
+:102C100095F200783C1008008E1031B02643000178
+:102C200030717FFF1230005C006030218F83002CF8
+:102C300002602021240500010E0018CBA466007854
+:102C40000A001E38000020218E0700142412FFFF06
+:102C500010F200638F8C00348E0900188D8D00D027
+:102C6000152D005D026020218E0A00248CA2002810
+:102C700011420053240200210E0019E1A3820064D6
+:102C80001452FFBE2404FFFF8F8500340A001CC9C4
+:102C90000080A0212402001F0E0019E1A38200641D
+:102CA0002409FFFF1049FEA22404FFFF0A001DEBC8
+:102CB0008F830050026020210E0019E1A389006477
+:102CC0001450FF518F8500342403FFFF0A001CC9F4
+:102CD0000060A0218CCE00248E0B0024116EFF2AF0
+:102CE000026020210A001EBD2402000F0E0018CB36
+:102CF000026020218F8500340A001E7C000018210C
+:102D00008E0900003C050080012590241640FF45F7
+:102D10002402001A026020210E0019E1A38200643F
+:102D2000240CFFFF144CFECB2404FFFF8F850034DE
+:102D30000A001CC90080A0212403FFFD0060A0211F
+:102D40000A001CC9AF87005C2418001D0E0019E1A1
+:102D5000A39800642403FFFF1443FEA62404FFFF8E
+:102D60008F8500340A001CC90080A0212412002C89
+:102D70000E0019E1A39200642403FFFF1043FF50EB
+:102D80008F8500340A001E63920400030260202134
+:102D90000A001ED324020024240B8000006B702440
+:102DA00031CAFFFF000A13C2305100FF0011802713
+:102DB0000A001F04001033C00A001ED3240200279B
+:102DC0008E0600288CAE002C10CE00080260202158
+:102DD0000A001F172402001F0A001F172402000EFA
+:102DE000026020210A001F17240200258E04002CF7
+:102DF0001080000D8F83002C8C7800740304582BF6
+:102E00005560000C026020218CA800140086A021CF
+:102E10000114302B10C0FF5A8F8F00400260202118
+:102E20000A001F1724020022026020210A001F1737
+:102E3000240200230A001F172402002627BDFFD802
+:102E4000AFB3001CAFB10014AFBF0020AFB2001889
+:102E5000AFB000103C0280008C5201408C4B014806
+:102E60003C048000000B8C02322300FF317300FF12
+:102E70008C8501B804A0FFFE34900180AE120000E2
+:102E80008C8701442464FFF0240600022C83001385
+:102E9000AE070004A6110008A206000BAE13002422
+:102EA0001060004F8FBF0020000448803C0A0801DA
+:102EB000254A936C012A40218D04000000800008FF
+:102EC000000000003C0308008C6331A831693FFF1B
+:102ED0000009998000728021021370212405FF806F
+:102EE000264D0100264C00803C02800031B1007F5D
+:102EF0003198007F31CA007F3C1F800A3C19800452
+:102F00003C0F800C01C5202401A530240185382404
+:102F1000014F1821AC460024023F402103194821EB
+:102F2000AC470090AC440028AF830040AF88003429
+:102F3000AF89002C0E001897016080213C038000AF
+:102F40008C6B01B80560FFFE8F8700408F860034D0
+:102F50003465018090E8000DACB20000A4B000061A
+:102F6000000826000004160300029027001227C262
+:102F70001080008124C20088241F6082A4BF000842
+:102F8000A0A0000524020002A0A2000B8F8B002C41
+:102F9000000424003C08270000889025ACB20010F3
+:102FA000ACA00014ACA00024ACA00028ACA0002C65
+:102FB0008D6900382413FF80ACA9001890E3000D40
+:102FC00002638024320500FF10A000058FBF00209F
+:102FD00090ED000D31AC007FA0EC000D8FBF002004
+:102FE0008FB3001C8FB200188FB100148FB0001087
+:102FF0003C0A10003C0E800027BD002803E00008BA
+:10300000ADCA01B8265F01002405FF8033F8007FB8
+:103010003C06800003E578243C19800A031920212E
+:10302000ACCF0024908E00D400AE682431AC00FFF9
+:1030300011800024AF840034248E008895CD0012C6
+:103040003C0C08008D8C31A831AB3FFF0192482128
+:10305000000B5180012A402101052024ACC4002826
+:103060003107007F3C06800C00E620219083000D94
+:1030700000A31024304500FF10A0FFD8AF8400400B
+:103080009098000D330F001015E0FFD58FBF002082
+:103090000E001897000000003C0380008C7901B8F6
+:1030A0000720FFFE00000000AE1200008C7F0144EC
+:1030B000AE1F0004A611000824110002A211000B8B
+:1030C000AE1300243C13080192739528327000015E
+:1030D0005200FFC38FBF00200E0020D402402021E9
+:1030E0000A001FF18FBF00203C1260008E452C08A3
+:1030F0003C03F0033462FFFF00A2F824AE5F2C080B
+:103100008E582C083C1901C003199825AE532C0881
+:103110000A001FF18FBF0020264D010031AF007F54
+:103120003C10800A240EFF8001F0282101AE6024AB
+:103130003C0B8000AD6C00241660FFA8AF85003406
+:1031400024110003A0B100FC0A001FF18FBF002072
+:1031500026480100310A007F3C0B800A2409FF80C9
+:10316000014B3021010920243C078000ACE40024FD
+:103170000A001FF0AF860034944E0012320C3FFF5D
+:1031800031CD3FFF15ACFF7D241F608290D900D464
+:103190002418FF800319782431EA00FF1140FF77DB
+:1031A0000000000024070004A0C700FC8F87004037
+:1031B000241160842406000DA4B10008A0A6000517
+:1031C0000A001FDB240200023C0400012484951441
+:1031D00024030014240200FE3C010800AC2431EC5E
+:1031E0003C010800AC2331E83C010801A4229530E1
+:1031F0003C0408012484953000001821006430212B
+:10320000A0C30004246300012C6500FF54A0FFFC50
+:10321000006430213C07080024E7010003E00008B7
+:10322000AF87007400A058210080482100001021C1
+:1032300014A00012000050210A0020D0000000005D
+:103240003C010801A42095303C05080194A5953067
+:103250008F8200743C0C0801258C953000E2182107
+:1032600000AC2021014B302BA0890004000010216C
+:10327000A460000810C00039010048218F86007446
+:103280000009384000E940210008388000E6282184
+:1032900090A8000B90B9000A000820400088102177
+:1032A000000218800066C021A319000A8F850074EF
+:1032B00000E5782191EE000A91E6000B000E6840CF
+:1032C00001AE6021000C208000851021A046000B7B
+:1032D0003C0308019063952A106000222462FFFFDE
+:1032E0008F8300343C010801A022952A906C00FFD6
+:1032F0001180000400000000906E00FF25CDFFFF4C
+:10330000A06D00FF3C190801973995302723000173
+:103310003078FFFF2F0F00FF11E0FFC9254A0001A1
+:103320003C010801A42395303C05080194A5953083
+:103330008F8200743C0C0801258C953000E2182126
+:1033400000AC2021014B302BA0890004000010218B
+:10335000A460000814C0FFC90100482103E0000870
+:103360000000000003E000082402000227BDFFE087
+:10337000248501002407FF80AFB00010AFBF001804
+:10338000AFB1001400A718243C10800030A4007FC7
+:103390003C06800A008628218E110024AE030024FA
+:1033A00090A200FF14400008AF850034A0A00009DF
+:1033B0008FBF0018AE1100248FB100148FB0001021
+:1033C00003E0000827BD002090A900FD90A800FFA1
+:1033D000312400FF0E002082310500FF8F8500346C
+:1033E0008FBF0018A0A00009AE1100248FB10014F7
+:1033F0008FB0001003E0000827BD002027BDFFD0DC
+:10340000AFB20020AFB1001CAFB00018AFBF002CAE
+:10341000AFB40028AFB300243C09800095330116F7
+:1034200035320C00952F011A3271FFFF02328021D4
+:103430008E08000431EEFFFF248B0100010E68218D
+:10344000240CFF8025A5FFFF016C50243166007F0E
+:103450003C07800AAD2A002400C73021AF850070E8
+:10346000AF88006C3C010801A020952990C3000999
+:103470000200D02100809821306300FF28620005FF
+:1034800010400048AF860034286400021480008E8B
+:1034900024140001240D00053C010801A02D950D08
+:1034A00090CC00FD3C010801A020950E3C010801D4
+:1034B000A020950F90CB000A240AFF80318500FFE1
+:1034C000014B4824312700FF10E0000C0000582178
+:1034D0003C128008365100808E2F00308CD0005C6A
+:1034E00001F0702305C0018E8F87006C90D4000A14
+:1034F0003284007FA0C4000A8F8600343C1180080B
+:10350000363000808E0F00308F87006C00EF702304
+:1035100019C000EE0000000090D40009241200023F
+:10352000328400FF10920247000000008CC2005855
+:1035300000E2F82327F9FFFF1B2001300000000004
+:1035400090C500092408000430A300FF106800574C
+:10355000240A00013C010801A02A950D90C900FF32
+:10356000252700013C010801A027950C3C03080118
+:103570009063950D240600051066006A2C780005FE
+:10358000130000C4000090210003F8803C040801EF
+:10359000248493B803E4C8218F25000000A000080C
+:1035A00000000000241800FF1078005C00000000FC
+:1035B00090CC000A90CA00093C080801910895299E
+:1035C0003187008000EA48253C010801A0299514B4
+:1035D00090C500FD3C1408019294952A3111000118
+:1035E0003C010801A025951590DF00FE3C01080173
+:1035F000A03F951690D200FF3C010801A03295171C
+:103600008CD900543C010801AC3995188CD0005875
+:103610003C010801AC30951C8CC3005C3C010801E6
+:10362000AC3495243C010801AC23952016200008F9
+:103630008FBF002C8FB400288FB300248FB20020DE
+:103640008FB1001C8FB0001803E0000827BD0030C8
+:103650003C1180009624010E0E000FD43094FFFF21
+:103660003C0B08018D6B952C0260382102802821CB
+:10367000AE2B01803C1308018E73950C0160202154
+:10368000240600830E001046AFB300108FBF002C3D
+:103690008FB400288FB300248FB200208FB1001C9C
+:1036A0008FB0001803E0000827BD00303C18080068
+:1036B0008F1831FC270F00013C010800AC2F31FCB2
+:1036C0000A002165000000001474FFB9000000002A
+:1036D000A0C000FF3C0508008CA531E43C030800B5
+:1036E0008C6331E03C0208008C4232048F99003434
+:1036F00034A80001241F00023C010801AC23952CD2
+:103700003C010801A02895283C010801A022952B26
+:10371000A33F00090A00211E8F8600340E0020D42A
+:10372000000000000A0021658F8600343C1F08015C
+:1037300093FF950C2419000113F902298F87006C5F
+:103740003C100801921095103C06080190C6950E99
+:1037500010C000050200A0213C04080190849511CE
+:10376000109001E48F870074001088408F9F0074D0
+:10377000023048210009C880033F702195D8000815
+:10378000270F0001A5CF00083C0408019084951183
+:103790003C05080190A5950E0E0020820000000057
+:1037A0008F870074023020210004308000C7202160
+:1037B0008C8500048F82007000A240230502000661
+:1037C000AC8200048C8A00008F83006C01431023BC
+:1037D0005C400001AC8300008F86003490CB00FF7A
+:1037E0002D6C00025580002D241400010230F821B8
+:1037F000001F40800107282190B9000B8CAE000407
+:103800000019C04003197821000F188000671021AB
+:103810008C4D000001AE88232630FFFF5E00001FA4
+:10382000241400018C4400048CAA0000008A482360
+:1038300019200019240E00043C010801A02E950D4A
+:1038400090AD000B8CAB0004000D8840022D802150
+:1038500000101080004710218C4400040164602394
+:10386000058202009443000890DF00FE90B9000B2F
+:1038700033E500FF54B900040107A021A0D400FEE5
+:103880008F8700740107A0219284000B0E00208214
+:10389000240500018F860034241400011254009680
+:1038A0002E500001160000423C08FFFF24190002C0
+:1038B0001659FF3F00000000A0C000FF8F860034B3
+:1038C000A0D200090A0021658F86003490C7000944
+:1038D0002404000230E300FF1064016F2409000497
+:1038E000106901528F8800708CCE0054010E68233D
+:1038F00025B1000106200175241800043C010801CF
+:10390000A038950D3C010801A020950C90D400FD35
+:1039100090D200FF2E4F000215E0FF14328400FF0A
+:10392000000438408F89007490DF00FF00E410210C
+:10393000000220800089C8212FE500029324000B9B
+:1039400014A0FF0A2407000200041840006480212C
+:1039500000105880016928218CAC0004010C502310
+:103960000540FF02000000003C0308019063950E33
+:1039700014600005246F00013C010801A02495118A
+:103980003C010801A027950F3C010801A02F950ECE
+:1039900090CE00FF24E7000131CD00FF01A7882B66
+:1039A0001220FFE990A4000B0A002154000000003F
+:1039B0003C0508018CA5950C3C12000400A8F824D5
+:1039C00013F20006240200053C0908019129950D17
+:1039D0001520000224020003240200053C01080116
+:1039E000A022952990C700FF14E0012024020002C4
+:1039F000A0C200090A0021658F86003490CC00FF28
+:103A00001180FEDA240A00018F8C00708F89007407
+:103A1000240F0003018068211160001E240E0002A3
+:103A2000000540400105A02100142080008990215C
+:103A30008E510004019180230600FECC000000009E
+:103A40003C0208019042950E1440000524580001E4
+:103A50003C010801A02A950F3C010801A025951101
+:103A60003C010801A038950E90DF00FF01051021F0
+:103A70000002C88033E500FF254A00010329202108
+:103A800000AA402B1500FEB99085000B1560FFE5DC
+:103A9000000540400005404001051821000310804A
+:103AA0003C010801A02A950C3C010801A0259510B5
+:103AB000004918218C64000400E4F82327F9FFFF73
+:103AC0001F20FFE9000000008C63000000E3582382
+:103AD0000560013A01A3882310E301170184C02384
+:103AE0001B00FEA2000000003C010801A02E950D65
+:103AF0000A002293240B0001240E0004A0CE00092A
+:103B00003C0D08008DAD31F88F86003425A20001F0
+:103B10003C010800AC2231F80A00216500000000D9
+:103B20008CD9005C00F9C0231F00FE7B0000000060
+:103B30008CDF005C10FFFF658F8400708CC3005C1D
+:103B400000834023250200011C40FF6000000000AC
+:103B50008CC9005C2487000100E9282B10A0FE948A
+:103B60003C0D80008DAB01043C0C0001016C502425
+:103B70001140FE8F240200103C010801A02295296B
+:103B80000A002165000000008F9100708F860034CC
+:103B900026220001ACC2005C0A002220241400018D
+:103BA0008F8700342404FF800000882190E9000AF8
+:103BB0002414000101243025A0E6000A3C05080178
+:103BC00090A5950E3C040801908495110E0020826A
+:103BD000000000008F8600348F85007490C800FDBF
+:103BE000310700FF000740400107F821001FC08097
+:103BF0000305C8219323000BA0C300FD8F8500742B
+:103C00008F86003403056021918F000B000F7040F8
+:103C100001CF6821000D8080020510218C4B00002F
+:103C2000ACCB00548D8400048F830070006450235B
+:103C3000194000022482000124620001010748218A
+:103C4000ACC2005C0009308000C5402100E02021AA
+:103C5000240500010E0020829110000B8F86003495
+:103C600090C500FF10A0FF0C001070408F850074FD
+:103C700001D06821000D1080004558218D6400009E
+:103C80008F8C0070018450232547000104E0FF025F
+:103C9000263100013C0308019063950E2E2F00028F
+:103CA000247800013C010801A038950E3C01080170
+:103CB000A034950F11E0FEF8020038210A0022F32B
+:103CC000000740408F8400348F8300708C8500583B
+:103CD00000A340230502FE9AAC8300580A0021C9C4
+:103CE000000000003C07080190E7952A240200FF2D
+:103CF00010E200BE8F8600343C11080196319532E7
+:103D00003C03080124639530262500013230FFFF73
+:103D100030ABFFFF020360212D6A00FF1540008DCC
+:103D2000918700043C010801A42095328F8800345B
+:103D30000007484001272821911800FF0005308026
+:103D40002405000127140001A11400FF3C12080102
+:103D50009252952A8F8800748F8E006C264F000136
+:103D600000C820213C010801A02F952AAC8E00003C
+:103D70008F8D0070A4850008AC8D00043C03080101
+:103D80009063950C14600077000090213C010801BD
+:103D9000A025950CA087000B8F8C007400CC5021BF
+:103DA000A147000A8F820034A04700FD8F840034B1
+:103DB000A08700FE8F8600348F9F006CACDF00541C
+:103DC0008F990070ACD900588F8D00740127C021E5
+:103DD00000185880016DA021928F000A000F7040DA
+:103DE00001CF182100038880022D8021A207000B3B
+:103DF0008F86007401666021918A000B000A1040D2
+:103E0000004A20210004288000A64021A107000AC2
+:103E10003C07800834E900808D2200308F86003412
+:103E2000ACC2005C0A0022202414000190CA00FFEA
+:103E30001540FEAD8F880070A0C400090A002165FE
+:103E40008F860034A0C000FD8F9800342406000146
+:103E5000A30000FE3C010801A026950D3C010801CD
+:103E6000A020950C0A0021540000000090CB00FF18
+:103E70003C0408019084952B316C00FF0184502B89
+:103E80001540000F2402000324020004A0C2000910
+:103E90000A0021658F86003490C3000A2410FF8039
+:103EA00002035824316C00FF1180FDC100000000A6
+:103EB0003C010801A020950D0A00215400000000DB
+:103EC000A0C200090A0021658F86003490D4000A40
+:103ED0002412FF8002544824312800FF1500FFF40B
+:103EE000240200083C010801A02295290A0021654E
+:103EF00000000000001088408F8B006C02301821F9
+:103F00000003688001A72021AC8B00008F8A00701D
+:103F1000240C0001A48C0008AC8A00043C050801B4
+:103F200090A5950E2402000110A2FE1E24A5FFFFFD
+:103F30000A0021DF9084000B0184A0231A80FD8BEE
+:103F4000000000003C010801A02E950D0A002293FC
+:103F5000240B00013C010801A42595320A002345E9
+:103F60008F880034240B0001106B00228F980034DE
+:103F70008F85003490BF00FF33F900FF1079002BCC
+:103F8000000000003C1F080193FF9510001FC8406F
+:103F9000033FC0210018A0800288782191EE000A1A
+:103FA000A08E000A8F8D00743C0308019063951069
+:103FB00000CD88210A00236BA223000B26300001CC
+:103FC0000600003101A490230640002B24020003C8
+:103FD0003C010801A02F950D0A002293240B00013B
+:103FE0008F8900340A0021C9AD2700540A00221F1E
+:103FF00024120001931400FDA094000B8F8800345C
+:104000008F8F0074910E00FE00CF6821A1AE000AD0
+:104010008F910034A22700FD8F83006C8F900034B5
+:10402000AE0300540A00236C8F8D007490B000FE24
+:10403000A090000A8F8B00348F8C0074916A00FD71
+:1040400000CC1021A04A000B8F840034A08700FE12
+:104050008F8600708F850034ACA600580A00236C50
+:104060008F8D007494B80008ACA400040303782179
+:104070000A002213A4AF00083C010801A022950DFC
+:104080000A0021540000000090CF0009240D000414
+:1040900031EE00FF11CDFD85240200013C01080135
+:0C40A000A022950D0A0021540000000031
+:0440AC000800334491
+:1040B0000800334408003420080033F4080033D8E3
+:1040C0000800332808003328080033280800334C40
+:1040D0008008010080080080800800005F86543757
+:1040E000E4AC62CC50103A4536621985BF14C0E882
+:1040F0001BC27A1E84F4B556094EA6FE7DDA01E78E
+:10410000C04D7481080058D008005914080058B8F0
+:10411000080058B8080058B8080058B8080058D027
+:10412000080058B8080058B80800591C080058B8CA
+:1041300008005830080058B8080058B80800591C42
+:10414000080058B8080058B8080058B8080058B80F
+:10415000080058B8080058B8080058B8080058B8FF
+:10416000080058B8080058B8080058F0080058B8B7
+:10417000080058F0080058B8080058B8080058B8A7
+:10418000080058F4080058F0080058B8080058B85B
+:10419000080058B8080058B8080058B8080058B8BF
+:1041A000080058B8080058B8080058B8080058B8AF
+:1041B000080058B8080058B8080058B8080058B89F
+:1041C000080058B8080058B8080058B8080058B88F
+:1041D000080058B8080058B8080058F4080058F407
+:1041E000080058B8080058F4080058B8080058B833
+:1041F000080058B8080058B8080058B8080058B85F
+:10420000080058B8080058B8080058B8080058B84E
+:10421000080058B8080058B8080058B8080058B83E
+:10422000080058B8080058B8080058B8080058B82E
+:10423000080058B8080058B8080058B8080058B81E
+:10424000080058B8080058B8080058B8080058B80E
+:10425000080058B8080058B8080058B8080058B8FE
+:10426000080058B8080058B8080058B8080058B8EE
+:10427000080058B8080058B8080058B8080058B8DE
+:10428000080058B8080058B8080058B8080058B8CE
+:10429000080058B8080058B8080058B8080058B8BE
+:1042A000080058B8080058B8080058B8080058B8AE
+:1042B000080058B8080058B8080058B8080058B89E
+:1042C000080058B8080058B8080058B8080058B88E
+:1042D000080058B8080058B8080058B8080058B87E
+:1042E000080058B8080058B8080058B8080058B86E
+:1042F000080058B8080058B8080058B8080058B85E
+:10430000080058B80800593808007688080078EC8A
+:1043100008007694080074880800769408007720D6
+:10432000080076940800748808007488080074886F
+:10433000080074880800748808007488080074886D
+:10434000080074880800748808007488080076B42F
+:10435000080076A40800748808007488080074882F
+:10436000080074880800748808007488080074883D
+:10437000080074880800748808007488080074882D
+:1043800008007488080076A40800813408007FC003
+:10439000080080FC08007FC0080080CC08007EA8D0
+:1043A00008007FC008007FC008007FC008007FC0F1
+:1043B00008007FC008007FC008007FC008007FC0E1
+:1043C00008007FC008007FC008007FC008007FC0D1
+:1043D00008007FE808008B6C08008CC808008CA8D7
+:0843E0000800871008008B841F
+:0843E8000A000124000000009E
+:1043F000000000000000000D747061362E302E3178
+:10440000370000000600110100000000000000005D
+:10441000000000000000000000000000000000009C
+:10442000000000000000000000000000000000008C
+:10443000000000000000000000000000000000007C
+:10444000000000000000000000000000000000006C
+:10445000000000000000000000000000000000005C
+:10446000000000000000000000000000000000004C
+:104470000000000000000000000000001000000329
+:10448000000000000000000D0000000D3C020800CC
+:10449000244217203C03080024632A10AC4000008B
+:1044A0000043202B1480FFFD244200043C1D080023
+:1044B00037BD2FFC03A0F0213C100800261004900B
+:1044C0003C1C0800279C17200E0002620000000020
+:1044D0000000000D2402FF8027BDFFE000821024B1
+:1044E000AFB00010AF420020AFBF0018AFB1001452
+:1044F000936500043084007F034418213C020008C7
+:104500000062182130A50020036080213C080111C1
+:10451000277B000814A000022466005C2466005873
+:104520009202000497430104920400043047000FF4
+:104530003063FFFF308400400067282310800009AB
+:10454000000048219202000530420004104000059E
+:104550000000000010A000030000000024A5FFFCE4
+:1045600024090004920200053042000410400012A9
+:104570000000000010A000100000000096020002E1
+:1045800000A72021010440252442FFFEA742101667
+:10459000920300042402FF8000431024304200FFF5
+:1045A000104000033C0204000A000174010240258F
+:1045B0008CC20000AF4210188F4201780440FFFE09
+:1045C0002402000AA74201409602000224040009C6
+:1045D000304200070002102330420007A742014288
+:1045E000960200022442FFFEA7420144A740014672
+:1045F00097420104A74201488F420108304200203F
+:1046000050400001240400019202000430420010D6
+:10461000144000023483001000801821A743014A8F
+:10462000000000000000000000000000000000008A
+:10463000AF48100000000000000000000000000073
+:10464000000000008F4210000441FFFE3102FFFF16
+:1046500010400007000000009202000430420040B9
+:1046600014400003000000008F421018ACC200008C
+:10467000960200063042FFFF24420002000210436F
+:104680000002104003628821962200001120000DD4
+:104690003044FFFF00A710218F8300388F45101C86
+:1046A000000210820002108000431021AC4500007F
+:1046B00030A6FFFF0E00058D00052C0200402021D2
+:1046C000A6220000920300042402FF80004310246D
+:1046D000304200FF1040001F000000009202000561
+:1046E000304200021040001B000000009742100CF6
+:1046F0002442FFFEA7421016000000003C02040006
+:1047000034420030AF421000000000000000000002
+:1047100000000000000000008F4210000441FFFE76
+:10472000000000009742100C8F45101C3042FFFF24
+:10473000244200300002108200021080005B102131
+:10474000AC45000030A6FFFF0E00058D00052C02D1
+:10475000A622000096040002248400080E0001E94D
+:104760003084FFFF974401040E0001F73084FFFFFF
+:104770008FBF00188FB100148FB000103C021000E2
+:1047800027BD002003E00008AF4201783084FFFF1E
+:10479000308200078F850024104000022483000728
+:1047A0003064FFF800A4102130421FFF034218219B
+:1047B000247B4000AF850028AF82002403E000087E
+:1047C000AF4200843084FFFF3082000F8F85002CC1
+:1047D0008F860034104000022483000F3064FFF005
+:1047E00000A410210046182BAF850030004620237E
+:1047F00014600002AF82002CAF84002C8F82002C4A
+:10480000340480000342182100641821AF8300386B
+:1048100003E00008AF4200808F82001410400008BF
+:104820008F8200048F82FFDC144000058F82000419
+:104830003C02FFBF3442FFFF008220248F8200042D
+:1048400030430006240200021062000F3C02010106
+:104850002C62000350400005240200041060000F89
+:104860003C0200010A000230000000001062000556
+:10487000240200061462000C3C0201110A00022905
+:10488000008210253C02001100821025AF4210006A
+:10489000240200010A000230AF82000C00821025C1
+:1048A000AF421000AF80000C0000000000000000CC
+:1048B0000000000003E00008000000008F82000CF0
+:1048C00010400004000000008F4210000441FFFE71
+:1048D0000000000003E00008000000008F820010CC
+:1048E0002443F800000231C224C2FFF02C6303010C
+:1048F00010600003000210420A000257AC82000060
+:104900008F85001800C5102B1440000B00001821E3
+:1049100000C51023244700018F82001C00A2102133
+:104920002442FFFF0046102B544000042402FFFFE6
+:104930000A000257AC8700002402FFFF0A00026051
+:10494000AC8200008C820000000219400062182135
+:104950000003188000621821000318803C02080040
+:104960002442175C0062182103E000080060102157
+:1049700027BDFFD8AFBF0020AFB1001CAFB00018FB
+:104980003C0460088C8250002403FF7F3C066000DA
+:10499000004310243442380CAC8250008CC24C1CB2
+:1049A0003C1A8000000216023042000F104000073F
+:1049B000AF82001C8CC34C1C3C02001F3442FC0024
+:1049C00000621824000319C2AF8300188F42000848
+:1049D000275B400034420001AF420008AF80002452
+:1049E0003C02601CAF400080AF4000848C45000852
+:1049F0008CC3080834028000034220212402FFF007
+:104A0000006218243C0200803C010800AC22042013
+:104A10003C025709AF84003814620004AF850034AB
+:104A2000240200010A000292AF820014AF80001439
+:104A30008F42000038420001304200011440FFFC68
+:104A40008F820014104000160000000097420104FD
+:104A5000104000058F830000146000072462FFFFF0
+:104A60000A0002A72C62000A2C62001050400004C9
+:104A70008F83000024620001AF8200008F8300005A
+:104A80002C62000A144000032C6200070A0002AEE8
+:104A9000AF80FFDC1040000224020001AF82FFDC87
+:104AA0008F4301088F44010030622000AF8300046F
+:104AB00010400008AF8400103C0208008C42042C17
+:104AC000244200013C010800AC22042C0A00058AA3
+:104AD0003C0240003065020014A0000324020F00D5
+:104AE0001482026024020D0097420104104002C8A3
+:104AF0003C02400030624000144000AD8F8200381C
+:104B00008C4400088F4201780440FFFE2402080014
+:104B1000AF42017824020008A7420140A7400142A9
+:104B2000974201048F8400043051FFFF308200015E
+:104B300010400007022080212623FFFE24020002ED
+:104B40003070FFFFA74201460A0002DBA74301487D
+:104B5000A74001463C0208008C42043C1440000D72
+:104B60008F830010308200201440000224030009CB
+:104B700024030001006020218F830010240209001B
+:104B80005062000134840004A744014A0A0002F67E
+:104B90000000000024020F00146200053082002093
+:104BA000144000062403000D0A0002F5240300054A
+:104BB000144000022403000924030001A743014A12
+:104BC0003C0208008C4204203C0400480E00020C09
+:104BD000004420250E000235000000008F82000CEA
+:104BE0001040003E000000008F4210003C030020F7
+:104BF00000431024104000398F820004304200022C
+:104C0000104000360000000097421014144000339A
+:104C100000000000974210088F8800383042FFFFE4
+:104C200024420006000218820003388000E8302188
+:104C3000304300018CC400001060000430420003C7
+:104C40000000000D0A00033700E810215440001056
+:104C50003084FFFF3C05FFFF0085202400851826D7
+:104C60000003182B0004102B0043102410400005F3
+:104C700000000000000000000000000D0000000027
+:104C8000240002228CC200000A00033600452025C1
+:104C90003883FFFF0003182B0004102B004310245F
+:104CA0001040000500000000000000000000000DA2
+:104CB000000000002400022B8CC200003444FFFFDF
+:104CC00000E81021AC4400003C0208008C42043093
+:104CD000244200013C010800AC2204308F62000035
+:104CE0008F840038AF8200088C8300003402FFFFFD
+:104CF0001462000F000010213C0508008CA504542C
+:104D00003C0408008C84045000B0282100B0302BF3
+:104D100000822021008620213C010800AC2504549B
+:104D20003C010800AC2404500A000580240400085B
+:104D30008C820000304201001040000F0000102162
+:104D40003C0508008CA5044C3C0408008C840448F5
+:104D500000B0282100B0302B0082202100862021C5
+:104D60003C010800AC25044C3C010800AC2404487C
+:104D70000A000580240400083C0508008CA50444B2
+:104D80003C0408008C84044000B0282100B0302B83
+:104D900000822021008620213C010800AC2504442B
+:104DA0003C010800AC2404400A00058024040008EB
+:104DB0008F6200088F62000000021602304300F08C
+:104DC000240200301062000524020040106200E05E
+:104DD0008F8200200A0005882442000114A00005EB
+:104DE00000000000000000000000000D00000000B6
+:104DF000240002568F4201780440FFFE00000000AC
+:104E00000E00023D27A40010144000050040802140
+:104E1000000000000000000D000000002400025D02
+:104E20008E0200001040000500000000000000009D
+:104E30000000000D00000000240002608F62000CE2
+:104E400004430003240200010A00042EAE00000007
+:104E5000AE0200008F8200388C480008A2000007D4
+:104E60008F65000C8F64000430A3FFFF0004240250
+:104E700000852023308200FF0043102124420005DA
+:104E8000000230832CC20081A605000A14400005F0
+:104E9000A2040004000000000000000D000000005B
+:104EA000240002788F8500380E0005AB260400141C
+:104EB0008F6200048F430108A60200083C02100024
+:104EC00000621824106000080000000097420104EE
+:104ED000920300072442FFEC346300023045FFFFD9
+:104EE0000A0003C3A2030007974201042442FFF013
+:104EF0003045FFFF960600082CC200135440000501
+:104F0000920300079202000734420001A202000748
+:104F1000920300072402000110620005240200032E
+:104F20001062000B8F8200380A0003E030C6FFFFDA
+:104F30008F8200383C04FFFF8C43000C006418246F
+:104F400000651825AC43000C0A0003E030C6FFFFE3
+:104F50003C04FFFF8C4300100064182400651825F2
+:104F6000AC43001030C6FFFF24C2000200021083D1
+:104F7000A20200058F830038304200FF000210803B
+:104F8000004328218CA800008CA200002403000408
+:104F900000021702144300120000000097420104AF
+:104FA0003C03FFFF010318243042FFFF004610239B
+:104FB0002442FFFE00624025ACA8000092030005D9
+:104FC000306200FF00021080005010219042001457
+:104FD0003042000F004310210A000415A20200060F
+:104FE0008CA40004974201049603000A3088FFFF56
+:104FF0003042FFFF004610232442FFD60002140077
+:1050000001024025ACA800049202000792040005AA
+:10501000246300280003188300641821344200042C
+:10502000A2030006A20200078F8200042403FFFBF4
+:105030003442000200431024AF82000492030006B1
+:105040008F87003800031880007010218C440020E6
+:105050003C02FFF63442FFFF008240240067182123
+:10506000AE04000CAC68000C920500063C03FF7F08
+:105070008E02000C0005288000B020213463FFFF61
+:10508000010330249488002600A72821004310241F
+:10509000AE02000CAC860020AC880024ACA8001046
+:1050A00024020010A742014024020002A74001424E
+:1050B000A7400144A7420146974201043C0400086E
+:1050C0002442FFFEA7420148240200010E00020C08
+:1050D000A742014A9603000A9202000400431021ED
+:1050E0002442000230420007000210233042000731
+:1050F0000E000235AE0200108F6200003C03080073
+:105100008C63044424040010AF8200089742010419
+:105110003042FFFF2442FFFE00403821000237C327
+:105120003C0208008C420440006718210067282BCD
+:1051300000461021004510213C010800AC23044426
+:105140003C010800AC2204400A00051500000000E4
+:1051500014A0000500000000000000000000000D89
+:10516000000000002400030A8F4201780440FFFE83
+:10517000000000000E00023D27A4001414400005AA
+:1051800000408021000000000000000D0000000031
+:10519000240003118E020000544000069202000712
+:1051A000000000000000000D000000002400031CAF
+:1051B0009202000730420004104000058F82000474
+:1051C0002403FFFB3442000200431024AF8200049A
+:1051D0008F62000404430008920200079202000656
+:1051E0008E03000CAE000000000210800050102161
+:1051F000AC430020920200073042000454400009F2
+:105200009602000A920200053C0300010002108091
+:10521000005010218C46001800C33021AC46001805
+:105220009602000A9206000427710008022020213D
+:1052300000C2302124C60005260500140E0005AB6F
+:1052400000063082920400068F6500043C027FFF56
+:1052500000042080009120218C8300043442FFFF51
+:1052600000A2282400651821AC83000492020007E4
+:105270009204000592030004304200041040001420
+:1052800096070008308400FF000420800091202150
+:105290008C860004974201049605000A306300FFE3
+:1052A0003042FFFF004310210045102130E3FFFF93
+:1052B000004310232442FFD830C6FFFF0002140031
+:1052C00000C23025AC8600040A0004C9920300071E
+:1052D000308500FF0005288000B128218CA4000043
+:1052E00097420104306300FF3042FFFF004310216A
+:1052F000004710233C03FFFF008320243042FFFFC0
+:1053000000822025ACA400009203000724020001C3
+:105310001062000600000000240200031062001169
+:10532000000000000A0004EC8E0300109742010404
+:10533000920300049605000A8E24000C00431021FD
+:10534000004510212442FFF23C03FFFF008320248C
+:105350003042FFFF00822025AE24000C0A0004EC3E
+:105360008E03001097420104920300049605000A80
+:105370008E24001000431021004510212442FFEE2E
+:105380003C03FFFF008320243042FFFF00822025E2
+:10539000AE2400108E0300102402000AA742014030
+:1053A000A74301429603000A920200043C04004015
+:1053B00000431021A7420144A7400146974201043F
+:1053C000A7420148240200010E00020CA742014A34
+:1053D0000E000235000000008F62000092030004FE
+:1053E00000002021AF820008974201049606000ABF
+:1053F0003042FFFF00621821006028213C030800B2
+:105400008C6304443C0208008C420440006518216F
+:10541000004410210065382B004710213C01080092
+:10542000AC2304443C010800AC2204409204000474
+:10543000008620212484000A3084FFFF0E0001E949
+:1054400000000000974401043084FFFF0E0001F7C4
+:10545000000000003C021000AF4201780A000587FE
+:105460008F820020148200273062000697420104D8
+:10547000104000673C0240003062400010400005D0
+:1054800000000000000000000000000D000000000F
+:10549000240004208F4201780440FFFE240208000B
+:1054A000AF42017824020008A7420140A740014210
+:1054B0008F8200049743010430420001104000072E
+:1054C0003070FFFF2603FFFE24020002A7420146C0
+:1054D000A74301480A00053F2402000DA7400146EA
+:1054E0002402000DA742014A8F6200002404000834
+:1054F000AF8200080E0001E9000000000A00051953
+:1055000002002021104000423C0240009362000053
+:10551000304300F0240200101062000524020070E5
+:10552000106200358F8200200A00058824420001A5
+:105530008F620000974301043050FFFF3071FFFF7E
+:105540008F4201780440FFFE320200070002102360
+:10555000304200072403000A2604FFFEA74301404F
+:10556000A7420142A7440144A7400146A751014870
+:105570008F42010830420020144000022403000939
+:1055800024030001A743014A0E00020C3C04004022
+:105590000E000235000000003C0708008CE70444C0
+:1055A000021110212442FFFE3C0608008CC6044074
+:1055B0000040182100E33821000010218F65000011
+:1055C00000E3402B00C230212604000800C830212F
+:1055D0003084FFFFAF8500083C010800AC2704447D
+:1055E0003C010800AC2604400E0001E90000000068
+:1055F0000A000519022020210E00013B00000000D6
+:105600008F82002024420001AF8200203C02400033
+:10561000AF4201380A000292000000003084FFFF10
+:1056200030C6FFFF00052C0000A628253882FFFFAA
+:10563000004510210045282B0045102100021C02C6
+:105640003042FFFF0043102100021C023042FFFFE6
+:10565000004310213842FFFF03E000083042FFFF03
+:105660003084FFFF30A5FFFF0000182110800007E5
+:1056700000000000308200011040000200042042BF
+:10568000006518210A0005A10005284003E0000874
+:105690000060102110C0000624C6FFFF8CA200008D
+:1056A00024A50004AC8200000A0005AB2484000499
+:1056B00003E000080000000010A0000824A3FFFF82
+:1056C000AC86000000000000000000002402FFFF84
+:1056D0002463FFFF1462FFFA2484000403E000083F
+:0456E00000000000C6
+:0456E40000000001C1
+:0856E8000A00002A0000000086
+:1056F000000000000000000D747870362E302E314E
+:105700003700000006001100000000000000013614
+:105710000000EA600000000000000000000000003F
+:105720000000000000000000000000000000000079
+:105730000000000000000000000000000000000069
+:105740000000000000000000000000160000000043
+:105750000000000000000000000000000000000049
+:105760000000000000000000000000000000000039
+:105770000000000000000000000000000000000029
+:105780000000138800000000000005DC000000009D
+:105790000000000010000003000000000000000DE9
+:1057A0000000000D3C02080024423D883C03080034
+:1057B0002463403CAC4000000043202B1480FFFDDC
+:1057C000244200043C1D080037BD7FFC03A0F021EB
+:1057D0003C100800261000A83C1C0800279C3D88AF
+:1057E0000E00044E000000000000000D27BDFFB4B5
+:1057F000AFA10000AFA20004AFA30008AFA4000C4B
+:10580000AFA50010AFA60014AFA70018AFA8001CEA
+:10581000AFA90020AFAA0024AFAB0028AFAC002C8A
+:10582000AFAD0030AFAE0034AFAF0038AFB8003C22
+:10583000AFB90040AFBC0044AFBF00480E000591B7
+:10584000000000008FBF00488FBC00448FB90040AB
+:105850008FB8003C8FAF00388FAE00348FAD003072
+:105860008FAC002C8FAB00288FAA00248FA90020BA
+:105870008FA8001C8FA700188FA600148FA50010FA
+:105880008FA4000C8FA300088FA200048FA100003A
+:1058900027BD004C3C1B60048F7A5030377B50286A
+:1058A00003400008AF7A00008F86003C3C03900064
+:1058B0003C0280000086282500A32025AC4400205F
+:1058C0003C0380008C67002004E0FFFE0000000025
+:1058D00003E00008000000000A000070240400013A
+:1058E0008F85003C3C0480003483000100A3102518
+:1058F00003E00008AC82002003E000080000102153
+:105900003084FFFF30A5FFFF108000070000182142
+:10591000308200011040000200042042006518217E
+:105920001480FFFB0005284003E000080060102100
+:1059300010C00007000000008CA2000024C6FFFF7A
+:1059400024A50004AC82000014C0FFFB24840004E2
+:1059500003E000080000000010A0000824A3FFFFDF
+:10596000AC86000000000000000000002402FFFFE1
+:105970002463FFFF1462FFFA2484000403E000089C
+:105980000000000090AA00318FAB00108CAC0040EA
+:105990003C0300FF8D680004AD6C00208CAD00441A
+:1059A00000E060213462FFFFAD6D00248CA7004849
+:1059B0003C09FF000109C024AD6700288CAE004CF3
+:1059C0000182C82403197825AD6F0004AD6E002C48
+:1059D0008CAD0038314A00FFAD6D001C94A9003237
+:1059E0003128FFFFAD68001090A70030A5600002CD
+:1059F000A1600004A167000090A30032306200FFA4
+:105A00000002198210600005240500011065000ED7
+:105A10000000000003E00008A16A00018CD8002803
+:105A2000354A0080AD7800188CCF0014AD6F00149B
+:105A30008CCE0030AD6E00088CC4002CA16A000131
+:105A400003E00008AD64000C8CCD001CAD6D0018A7
+:105A50008CC90014AD6900148CC80024AD6800081E
+:105A60008CC70020AD67000C8CC200148C830070C2
+:105A70000043C82B13200007000000008CC2001454
+:105A8000144CFFE400000000354A008003E00008E9
+:105A9000A16A00018C8200700A0000E6000000008C
+:105AA0009089003027BDFFF88FA8001CA3A9000033
+:105AB0008FA300003C0DFF8035A2FFFF8CAC002CB3
+:105AC00000625824AFAB0000A100000400C05821C0
+:105AD000A7A000028D06000400A048210167C8218C
+:105AE0008FA50000008050213C18FF7F032C20264A
+:105AF0003C0E00FF2C8C0001370FFFFF35CDFFFF60
+:105B00003C02FF0000AFC82400EDC02400C278248E
+:105B1000000C1DC00323682501F87025AD0D0000A1
+:105B2000AD0E00048D240024AFAD0000AD040008CC
+:105B30008D2C00202404FFFFAD0C000C9547003293
+:105B400030E6FFFFAD0600109145004830A200FF8F
+:105B5000000219C2506000018D240034AD0400140D
+:105B60008D4700388FAA001827BD0008AD0B00280C
+:105B7000AD0A0024AD07001CAD00002CAD000018DC
+:105B800003E00008AD00002027BDFFE0AFB2001821
+:105B9000AFB10014AFB00010AFBF001C9098003040
+:105BA00000C088213C0D00FF330F007FA0CF000014
+:105BB000908E003135ACFFFF3C0AFF00A0CE000103
+:105BC00094A6001EA22000048CAB00148E290004B1
+:105BD00000A08021016C2824012A4024008090210B
+:105BE00001052025A6260002AE240004260500207B
+:105BF000262400080E00009224060002924700307E
+:105C0000260500282624001400071E0000031603A2
+:105C100024060004044000032403FFFF96590032C9
+:105C20003323FFFF0E000092AE2300102624002431
+:105C30008FBF001C8FB200188FB100148FB00010FE
+:105C400024050003000030210A00009C27BD00202D
+:105C500027BDFFD8AFB1001CAFB00018AFBF002008
+:105C600090A900302402000100E050213123003FC0
+:105C700000A040218FB000400080882100C0482152
+:105C8000106200148FA70038240B000500A020210B
+:105C900000C02821106B0013020030210E000128E3
+:105CA000000000009225007C30A400021080000358
+:105CB00026030030AE000030260300348FBF0020E2
+:105CC0008FB1001C8FB000180060102103E00008A5
+:105CD00027BD00280E0000A7AFB000100A00016F1A
+:105CE000000000008FA3003C01002021012028219A
+:105CF00001403021AFA300100E0000EEAFB0001441
+:105D00000A00016F000000003C06800034C20E0053
+:105D10008C4400108F850044ACA400208C430018F4
+:105D200003E00008ACA300243C06800034C20E004F
+:105D30008C4400148F850044ACA400208C43001CCC
+:105D400003E00008ACA300249382000C1040001B69
+:105D50002483000F2404FFF00064382410E00019AD
+:105D6000978B00109784000E9389000D3C0A601CED
+:105D70000A0001AC01644023010370210064282360
+:105D80001126000231C2FFFF30A2FFFF0047302B77
+:105D900050C0000E00E448218D4D000C31A3FFFFE0
+:105DA00000036400000C2C0304A1FFF30000302169
+:105DB00030637FFF0A0001A42406000103E000080D
+:105DC000000000009784000E00E448213123FFFF0B
+:105DD0003168FFFF0068382B54E0FFF8A783000EFE
+:105DE000938A000D11400005240F0001006BC023B1
+:105DF000A380000D03E00008A798000E006BC023ED
+:105E0000A38F000D03E00008A798000E03E0000830
+:105E10000000000027BDFFE8AFB000103C1080007C
+:105E200036030140308BFFFF93AA002BAFBF001455
+:105E3000A46B000436040E009488001630C600FFE0
+:105E40008FA90030A4680006AC650008A0660012A7
+:105E5000A46A001AAC6700208FA5002CA469001862
+:105E6000012020210E000198AC6500143C021000B6
+:105E7000AE0201788FBF00148FB0001003E000085D
+:105E800027BD00188F8500002484000727BDFFF878
+:105E90003084FFF83C06800094CB008A316AFFFF13
+:105EA000AFAA00008FA90000012540232507FFFFAE
+:105EB00030E31FFF0064102B1440FFF700056882D9
+:105EC000000D288034CC400000AC102103E0000815
+:105ED00027BD00088F8200002486000730C5FFF828
+:105EE00000A2182130641FFF03E00008AF84000007
+:105EF0008F87003C8F84004427BDFFB0AFB70044BC
+:105F0000AFB40038AFB1002CAFBF0048AFB600400F
+:105F1000AFB5003CAFB30034AFB20030AFB0002833
+:105F20003C0B80008C860024AD6700808C8A0020AA
+:105F300035670E0035690100ACEA00108C8800243A
+:105F40008D2500040000B821ACE800188CE3001097
+:105F500000A688230000A021ACE300148CE2001806
+:105F6000ACE2001C122000FE00E0B021936C00089F
+:105F7000118000F400000000976F001031EEFFFF69
+:105F8000022E682B15A000EF000000009772001091
+:105F90003250FFFFAED000003C0380008C74000044
+:105FA000329300081260FFFD0000000096D8000840
+:105FB0008EC700043305FFFF30B5000112A000E4D6
+:105FC000000000000000000D30BFA0402419004078
+:105FD00013F9011B30B4A000128000DF00000000A4
+:105FE000937300081260000800000000976D001015
+:105FF00031ACFFFF00EC202B1080000330AE0040DE
+:1060000011C000D500000000A7850040AF87003810
+:106010009363000802202821AFB10020146000F52E
+:1060200027B40020AF60000C978F004031F1400092
+:1060300016200002240300162403000E2405400746
+:10604000A363000AAF650014938A00428F700014A6
+:10605000315500010015124002024825AF690014B5
+:10606000979F00408F78001433F9001003194025E2
+:10607000AF680014979200403247000810E0016EAC
+:10608000000000008F6700143C1210003C118000DB
+:1060900000F27825AF6F001436230E00946E000ACC
+:1060A0003C0D81002406000E31CCFFFF018D202520
+:1060B000AF640004A36600029373000A3406FFFC79
+:1060C000266B0004A36B000A979800403308200059
+:1060D0001100015F000000003C05800034A90E00A3
+:1060E000979900409538000C97870040001940426E
+:1060F0003312C0003103000300127B0330F11000A3
+:10610000006F68250011720301AE6025000C20C0ED
+:10611000A764001297930040936A000A0013598203
+:106120003175003C02AA10212450003CA3700009E4
+:10613000953F000C33F93FFFA779001097700012CC
+:10614000936900090130F82127E5000230B9000702
+:106150000019C02333080007A368000B93710009DE
+:1061600097720012976F0010322700FF8F9100384E
+:10617000978D004000F21821006F702101C6602148
+:1061800031A6004010C000053185FFFF00B1102B83
+:106190003C12800010400017000098210225A82B17
+:1061A00056A0013E8FA500203C048000348A0E00DA
+:1061B0008D5300143C068000AD5300108D4B001C25
+:1061C000AD4B0018AD4500008CCD000031AC00088F
+:1061D0001180FFFD34CE0E0095C3000800A0882179
+:1061E00000009021A78300408DC600042413000105
+:1061F000AF860038976F001031F5FFFF8E9F0000CB
+:1062000003F1282310A0011FAE850000936200084F
+:10621000144000DD000000000E0001E7240400101F
+:106220008F900048004028213C023200320600FFD7
+:10623000000654000142F82526090001AF890048F4
+:10624000ACBF00009379000997780012936F000AA1
+:10625000332800FF3303FFFF0103382100076C00E0
+:1062600031EE00FF01AE6025ACAC00048F84004825
+:10627000978B0040316A20001140010AACA400084D
+:1062800097640012308BFFFF06400108ACAB000C96
+:10629000978E004031C5000814A000022628000691
+:1062A000262800023C1F800037E70E0094F90014F6
+:1062B0008CE5001C8F670004937800023324FFFFF5
+:1062C000330300FFAFA300108F6F0014AFA80018B6
+:1062D0000E0001CBAFAF0014240400100E0001FB30
+:1062E000000000008E920000164000050000000033
+:1062F0008F7800142403FFBF0303A024AF7400149D
+:106300008F67000C00F5C821AF79000C9375000869
+:1063100016A0000800000000126000060000000047
+:106320008F6800143C0AEFFF3549FFFE0109F8248D
+:10633000AF7F0014A37300088FA500200A00034F4D
+:1063400002202021AED100000A00022D3C03800073
+:1063500014E0FF1E30BFA0400E0001900000A021FD
+:106360002E9100010237B02512C000188FBF0048DF
+:106370008F87003C24170F0010F700D43C068000E4
+:106380008CD901780720FFFE241F0F0010FF00F6B4
+:1063900034CA0E008D56001434C701402408024050
+:1063A000ACF600048D49001C3C141000ACE9000858
+:1063B000A0E00012A4E0001AACE00020A4E0001865
+:1063C000ACE80014ACD401788FBF00488FB700440C
+:1063D0008FB600408FB5003C8FB400388FB30034C7
+:1063E0008FB200308FB1002C8FB0002803E000087E
+:1063F00027BD00508F910038978800403C128000E4
+:106400000220A8213107004014E0FF7C0000982101
+:10641000977900108F9200383338FFFF131200A8CD
+:10642000000020210080A021108000F300A088211E
+:106430001620FECE000000000A00031F2E9100016E
+:106440003C0380008C6201780440FFFE24080800B1
+:106450008F860000AC6801783C038000946D008A50
+:1064600031ACFFFF01865823256AFFFF31441FFF2F
+:106470002C8900081520FFF9000000008F8F0048CC
+:10648000347040008F83003C00E0A021240E0F00F8
+:1064900025E70001AF87004800D03021023488236F
+:1064A0003C08800031F500FF106E00052407000154
+:1064B00093980042331300010013924036470001C5
+:1064C000001524003C0A0100008A4825ACC90000E0
+:1064D0008F82004830BF003630B90008ACC20004DB
+:1064E0001320009900FF982535120E009650000ADF
+:1064F0008F8700003C0F81003203FFFF24ED00086E
+:1065000035060140006F60253C0E100031AB1FFFC7
+:10651000269200062405000EACCC0020026E9825C1
+:10652000A4C5001AAF8B0000A4D2001816200008E2
+:106530003C1080008F89003C24020F005122000291
+:1065400024170001367300400E0001883C108000C3
+:1065500036060E008CCB0014360A01400240202182
+:10656000AD4B00048CC5001CAD450008A1550012C0
+:10657000AD5300140E0001983C151000AE150178C3
+:106580000A00035200000000936F0009976E00128A
+:10659000936D000B31E500FF00AE202131AC00FF10
+:1065A000008C80212602000A3050FFFF0E0001E718
+:1065B000020020218F8600483C0341003C058000FA
+:1065C00024CB0001AF8B0048936A00099769001241
+:1065D00030C600FF315F00FF3128FFFF03E838219C
+:1065E00024F900020006C4000319782501E3702590
+:1065F000AC4E00008F6D000C34A40E00948B001480
+:1066000001B26025AC4C00048C85001C8F6700042F
+:10661000936A00023164FFFF314900FFAFA9001007
+:106620008F680014AFB100180E0001CBAFA80014A2
+:106630000A0002FD02002021AF600004A3600002F6
+:1066400097980040330820001500FEA30000302179
+:10665000A760001297840040936B000A3C108000F2
+:1066600030931F0000135183014BA82126A200285C
+:10667000A362000936090E00953F000C0A0002953E
+:10668000A77F00108F700014360900400E000188AB
+:10669000AF6900140A0002C9000000000A00034F9D
+:1066A000000020210641FEFAACA0000C8CAC000CCE
+:1066B0003C0D8000018D90250A0002EAACB2000C6E
+:1066C000000090210A0002C5241300011280000777
+:1066D0003C028000344B0E009566000830D3004029
+:1066E00012600049000000003C0680008CD0017858
+:1066F0000600FFFE34C50E0094B500103C030500F3
+:1067000034CC014032B8FFFF03039025AD92000C5A
+:106710008CAF0014240D20003C041000AD8F000449
+:106720008CAE001CAD8E0008A1800012A580001A5E
+:10673000AD800020A5800018AD8D0014ACC4017898
+:106740000A0003263C0680008F9F00003518014098
+:106750002692000227F9000833281FFFA71200180D
+:106760000A000391AF8800003C02800034450140DC
+:10677000ACA0000C1280001B34530E0034510E00EC
+:106780008E370010ACB700048E2400183C0B80003C
+:10679000ACA400083570014024040040A20000129F
+:1067A0008FBF0048A600001A8FB70044AE0000203B
+:1067B0008FB60040A60000188FB5003CAE04001450
+:1067C0008FB400388FB300348FB200308FB1002CFB
+:1067D0008FB000283C02100027BD005003E00008E5
+:1067E000AD6201788E660014ACA600048E64001CB5
+:1067F0000A00042A3C0B80000E0001902E9100013B
+:106800000A0003200237B025000000000000000D40
+:1068100000000000240003690A0004013C06800017
+:1068200027BDFFD8AFBF00203C0980003C1F20FFE0
+:10683000AFB200183C07600035320E002402001091
+:1068400037F9FFFDACE23008AFB3001CAFB1001464
+:10685000AFB00010AE5900000000000000000000C2
+:106860000000000000000000000000003C1800FFD5
+:106870003713FFFDAE5300003C0B60048D705000D9
+:106880002411FF7F3C0E00020211782435EC380CF5
+:1068900035CD0109ACED4C18240A0009AD6C50004F
+:1068A0008CE80438AD2A0008AD2000148CE54C1C9F
+:1068B0003106FFFF38C42F7100051E023062000F41
+:1068C0002486C0B310400007AF8200088CE54C1C42
+:1068D0003C09001F3528FC0000A81824000321C231
+:1068E000AF8400048CF108083C0F57092412F00013
+:1068F0000232702435F0001001D0602601CF6826E6
+:106900002DAA00012D8B0001014B382550E0000914
+:10691000A380000C3C1F601C8FF8000824190001A4
+:10692000A399000C33137C00A7930010A780000EDE
+:10693000A380000DAF80004814C00003AF800000AA
+:106940003C066000ACC0442C0E0005B93C10800031
+:106950000E000F24361101003C12080026523DF0B3
+:106960003C13080026733E708E030000386400015B
+:10697000308200011440FFFC3C0B800A8E26000090
+:106980002407FF8024C90240312A007F014B4021A7
+:1069900001272824AE060020AF880044AE0500245D
+:1069A0003C048000AF86003C8C8C01780580FFFEA3
+:1069B00024180800922F0008AC980178A38F004299
+:1069C000938E004231CD000111A0000F24050D006F
+:1069D00024DFF8002FF903011320001C000629C250
+:1069E00024A4FFF000041042000231400E00020215
+:1069F00000D2D8213C0240003C068000ACC20138E5
+:106A00000A0004A00000000010C50023240D0F00A0
+:106A100010CD00273C1F800837F900809338000014
+:106A2000240E0050330F00FF15EEFFF33C02400030
+:106A30000E000A40000000003C0240003C068000BE
+:106A4000ACC201380A0004A0000000008F830004DB
+:106A500000A3402B1500000B8F8B0008006B50210A
+:106A60002547FFFF00E5482B1520000600A3602303
+:106A7000000C19400E0002020073D8210A0004C461
+:106A80003C0240000000000D0E0002020000000069
+:106A90000A0004C43C0240003C1B0800277B3F70F6
+:106AA0000E000202000000000A0004C43C02400084
+:106AB0003C1B0800277B3F900E00020200000000F4
+:106AC0000A0004C43C0240003C0660043C09080083
+:106AD00025290104ACC9502C8CC850003C0580000D
+:106AE0003C02000235070080ACC750003C0408009F
+:106AF000248415A43C0308002463155CACA500089D
+:106B0000ACA2000C3C010800AC243D803C01080014
+:106B1000AC233D8403E000082402000100A03021E2
+:106B20003C1C0800279C3D883C0C04003C0B0002E8
+:106B3000008B3826008C40262CE200010007502BE9
+:106B40002D050001000A48803C03080024633D80B5
+:106B5000004520250123182110800003000010218A
+:106B6000AC6600002402000103E000080000000001
+:106B70003C1C0800279C3D883C0B04003C0A00029A
+:106B8000008A3026008B38262CC200010006482BD4
+:106B90002CE50001000940803C03080024633D808F
+:106BA0000045202501031821108000050000102158
+:106BB0003C0C0800258C155CAC6C00002402000124
+:106BC00003E00008000000003C0900023C0804004B
+:106BD00000883026008938262CC300010080282137
+:106BE0002CE40001008310251040000B0000302130
+:106BF0003C1C0800279C3D883C0A80008D4E000804
+:106C00002406000101CA6825AD4D00088D4C000C1A
+:106C100001855825AD4B000C03E0000800C0102191
+:106C20003C1C0800279C3D883C0580008CA6000C7D
+:106C3000000420272402000100C4182403E00008F7
+:106C4000ACA3000C3C0200021082000B3C0560006B
+:106C50003C070400108700030000000003E0000868
+:106C6000000000008CA908D0240AFFFD012A40245E
+:106C700003E00008ACA808D08CA408D02406FFFECE
+:106C80000086182403E00008ACA308D03C05601A75
+:106C900034A600108CC3008027BDFFF88CC500848B
+:106CA000AFA3000093A4000024020001108200039F
+:106CB000AFA5000403E0000827BD000893A700016A
+:106CC00014E0001497AC000297B800023C0F80005B
+:106CD000330EFFFC01CF6821ADA50000A3A000008A
+:106CE0003C0660008CC708D02408FFFE3C04601AF4
+:106CF00000E82824ACC508D08FA300048FA20000B0
+:106D00003499001027BD0008AF22008003E000087E
+:106D1000AF2300843C0B8000318AFFFC014B4821EB
+:106D20008D2800000A00057DAFA8000427BDFFE8FC
+:106D3000AFBF00103C1C0800279C3D883C0580002C
+:106D40008CA4000C8CA200043C0300020044282404
+:106D500010A0000A00A318243C0604003C04000212
+:106D60001460000900A610241440000F3C04040025
+:106D70000000000D3C1C0800279C3D888FBF0010C0
+:106D800003E0000827BD00183C0208008C423D804B
+:106D90000040F809000000003C1C0800279C3D88CA
+:106DA0000A0005A68FBF00103C0208008C423D84FB
+:106DB0000040F809000000000A0005AC00000000D7
+:106DC000000411C003E00008244202403C04080013
+:106DD00024843FD42405001A0A00009C00003021BE
+:106DE00027BDFFE0AFB000103C108000AFBF00181F
+:106DF000AFB1001436110100922200090E0005B651
+:106E00003044007F8E3F00008F89003C3C0F0080A3
+:106E100003E26021258800400049F821240DFF800D
+:106E2000310E00783198007835F9000135F1000213
+:106E30000319382501D14825010D302403ED5824CC
+:106E4000018D2824240A004024040080240300C06B
+:106E5000AE0B0024AE000810AE0A0814AE040818E9
+:106E6000AE03081CAE050804AE070820AE060808ED
+:106E7000AE090824360909009539000C3605098049
+:106E800033ED007F3338FFFF001889C0AE110800D2
+:106E9000AE0F0828952C000C8FBF00188FB100147E
+:106EA000318BFFFF000B51C0AE0A002C8CA40050A8
+:106EB0008FB000108CA3003C8D2700048CA8001C10
+:106EC0008CA600383C0E800A01AE102127BD0020A0
+:106ED000AF820044AF840050AF830054AF87004CB2
+:106EE000AF88005C03E00008AF8600603C09080042
+:106EF00091293FF924A800023C05110000093C003B
+:106F000000E8302500C5182524820008AC83000065
+:106F100003E00008AC8000043C0980003523090030
+:106F20009128010B906A001124020028008048215A
+:106F3000314700FF00A0702100C0682131080040E7
+:106F400010E20002340C86DD240C08003C0A8000AC
+:106F500035420A9A94470000354B0A9C35460AA0F0
+:106F600030F9FFFFAD3900008D780000354B0A8005
+:106F700024040001AD3800048CCF0000AD2F0008C0
+:106F80009165001930A300031064009A2864000280
+:106F9000148000B924050002106500A8240F000326
+:106FA000106F00BE35450AA4240A0800118A004D5E
+:106FB00000000000510000423C0B80003C048000B7
+:106FC000348309009067001230E200FF004D782101
+:106FD000000FC880272400013C0A8000354F0900BB
+:106FE00091E50019354C09808D87002830A300FFFA
+:106FF00000031500004758250004C4003C19600038
+:1070000001793025370806FFAD260000AD280004C1
+:107010008DEA002C25280028AD2A00088DEC0030D0
+:10702000AD2C000C8DE50034AD2500108DE400384A
+:10703000AD2400148DE3001CAD2300188DE7002063
+:10704000AD27001C8DE20024AD2200208DF9002820
+:10705000AD3900243C0980003526093C8CCF000066
+:10706000352A0100AD0E0004AD0F00008D4E000C5E
+:107070003523090035250980AD0E0008906C0012FB
+:107080008D47000C8CB900343C18080093183FF869
+:10709000318200FF004D582103277823000B370071
+:1070A0000018240000C4702531E9FFFC01C96825DF
+:1070B00025020014AD0D000C03E00008AD00001027
+:1070C00035780900930600123C05080094A53FE8B6
+:1070D00030C800FF010D5021000A60800A00063C04
+:1070E0000185202115000060000000003C08080018
+:1070F00095083FEE3C06080094C63FE801061021C3
+:107100003C0B80003579090093380011932A00194F
+:1071100035660A80330800FF94CF002A0008608299
+:10712000314500FF978A0058000C1E00000524001E
+:107130003047FFFF006410250047C02501EA3021D9
+:107140003C0B4000030B402500066400AD28000006
+:10715000AD2C0004932500183C03000625280014DC
+:1071600000053E0000E31025AD2200088F24002C0E
+:10717000254F000131EB7FFFAD24000C8F38001C40
+:10718000A78B0058AD3800103C0980003526093C1B
+:107190008CCF0000352A0100AD0E0004AD0F0000B9
+:1071A0008D4E000C3523090035250980AD0E0008F1
+:1071B000906C00128D47000C8CB900343C1808000C
+:1071C00093183FF8318200FF004D582103277823A0
+:1071D000000B37000018240000C4702531E9FFFCC3
+:1071E00001C9682525020014AD0D000C03E000085C
+:1071F000AD0000103C02080094423FF23C0508003C
+:1072000094A53FE835440AA43C07080094E73FE40E
+:10721000948B00000045C8210327C023000B1C00ED
+:107220002706FFF200665025AD2A000CAD200010A5
+:10723000AD2C00140A00063025290018354F0AA489
+:1072400095E50000956400280005140000043C004A
+:107250003459810000EC5825AD39000CAD2B0010DD
+:107260000A000630252900143C0C0800958C3FEEDE
+:107270000A000686258200015460FF4C240A08009B
+:1072800035580AA49706000000061C00006C502523
+:10729000AD2A000C0A000630252900103C03080026
+:1072A00094633FF23C07080094E73FE83C0F080076
+:1072B00095EF3FE494A40000957900280067102121
+:1072C000004F582300041C00001934002578FFEEFD
+:1072D00000D87825346A8100AD2A000CAD2F00104B
+:1072E000AD200014AD2C00180A0006302529001C22
+:1072F00003E00008240207D027BDFFE0AFB200186A
+:10730000AFB10014AFB00010AFBF001C0E00007C86
+:10731000008088218F8800548F87004C3C058008AE
+:1073200034B20080011128213C108000240200802A
+:10733000240300C000A72023AE0208183C068008E2
+:10734000AE03081C18800004AF850054ACC50004CF
+:107350008CC90004AF89004C122000093604098052
+:107360000E00070200000000924C00278E0B0074F4
+:1073700001825004014B3021AE46000C36040980D6
+:107380008C8E001C8F8F005C01CF682319A0000435
+:107390008FBF001C8C90001CAF90005C8FBF001C46
+:1073A0008FB200188FB100148FB000100A00007E59
+:1073B00027BD00208F8600508F8300548F82004CA1
+:1073C0003C05800834A40080AC860050AC83003CAF
+:1073D00003E00008ACA200043C0308008C630054E6
+:1073E00027BDFFF8308400FF2462000130A500FFB4
+:1073F0003C010800AC22005430C600FF3C0780006E
+:107400008CE801780500FFFE3C0C7FFFA3A400037D
+:107410008FAA0000358BFFFF014B4824000627C0D0
+:1074200001244025AFA8000034E201009043000A87
+:10743000A3A000023C1980FFA3A300018FAF0000AE
+:1074400030AE007F3738FFFF01F86024000E6E0079
+:107450003C0A002034E50140018D582535492000C3
+:107460002406FF803C04100027BD0008ACAB000CD4
+:10747000ACA90014A4A00018A0A6001203E0000804
+:10748000ACE40178308800FF30A700FF3C038000A7
+:107490008C6201780440FFFE3C0C8000358A0A00B3
+:1074A0008D4B00203584014035850980AC8B00046C
+:1074B0008D4900240007302B00061540AC890008D8
+:1074C000A088001090A3004CA083002D03E00008CA
+:1074D000A480001827BDFFE8308400FFAFBF001074
+:1074E0000E00076730A500FF8F8300548FBF001088
+:1074F0003C06800034C50140344700402404FF901E
+:107500003C02100027BD0018ACA3000CA0A4001280
+:10751000ACA7001403E00008ACC2017827BDFFE06F
+:107520003C088008AFBF001CAFB20018AFB1001418
+:10753000AFB00010351000808E0600183C078000A8
+:10754000309200FF00C72025AE0400180E00007C1A
+:1075500030B100FF92030005346200080E00007E87
+:10756000A2020005024020210E00077B02202821F4
+:10757000024020218FBF001C8FB200188FB1001471
+:107580008FB0001024050005240600010A00073C06
+:1075900027BD00203C05800034A3098090660008C8
+:1075A00030C200081040000F3C0A01013549080AAA
+:1075B000AC8900008CA80074AC8800043C0708006B
+:1075C00090E73FF830E5001050A00008AC800008BC
+:1075D0003C0D800835AC00808D8B0058AC8B0008CA
+:1075E0002484000C03E00008008010210A0007BF7B
+:1075F0002484000C27BDFFE83C098000AFB00010D8
+:10760000AFBF00143526098090C800092402000687
+:1076100000A05821310300FF352709000080802198
+:10762000240500041062007B2408000294CF005C53
+:107630003C0E020431EDFFFF01AE6025AE0C0000F0
+:1076400090CA0008314400201080000800000000AB
+:1076500090C2004E3C1F010337F90300305800FF71
+:107660000319302524050008AE06000490F9001126
+:1076700090E6001290E40011333800FF0018708289
+:1076800030CF00FF01CF5021014B6821308900FF2E
+:1076900031AAFFFF39230028000A60801460002C03
+:1076A000020C482390E400123C198000372F01009F
+:1076B000308C00FF018B1821000310800045F82159
+:1076C000001F8400360706FFAD270004373F09007E
+:1076D00093EC001193EE0012372609800005C0825A
+:1076E0008DE4000C8CC5003431CD00FF01AB1021BE
+:1076F0000058182100A4F8230008840000033F006C
+:1077000000F0302533F9FFFF318F00FC00D97025E0
+:107710000158202101E9682100045080ADAE000C21
+:107720000E00007C012A80213C088008240B000404
+:10773000350500800E00007EA0AB0009020010217C
+:107740008FBF00148FB0001003E0000827BD0018A1
+:1077500090EC001190E300193C18080097183FEED8
+:10776000318200FF0002F882307000FF001FCE005F
+:1077700000103C000327302500D870253C0F400046
+:1077800001CF68253C198000AD2D0000373F09006E
+:1077900093EC001193EE0012372F01003726098079
+:1077A0000005C0828DE4000C8CC5003431CD00FF93
+:1077B00001AB10210058182100A4F8230008840010
+:1077C00000033F0000F0302533F9FFFF318F00FC4C
+:1077D00000D970250158202101E96821000450805A
+:1077E000ADAE000C0E00007C012A80213C08800810
+:1077F000240B0004350500800E00007EA0AB0009BC
+:10780000020010218FBF00148FB0001003E00008A9
+:1078100027BD00180A0007D12408001227BDFFD099
+:107820003C038000AFB60028AFB50024AFB4002001
+:10783000AFB10014AFBF002CAFB3001CAFB2001843
+:10784000AFB000103467010090E6000B309400FFE9
+:1078500030B500FF30C200300000B0211040009968
+:1078600000008821346409809088000800082E00F8
+:1078700000051E03046000C0240400048F86005429
+:107880003C010800A0243FF83C0C8000AD8000487B
+:107890003C048000348E010091CD000B31A5002006
+:1078A00010A000073C078000349309809272000802
+:1078B0000012860000107E0305E000C43C1F800813
+:1078C00034EC0100918A000B34EB098091690008C7
+:1078D000314400400004402B3123000800C89823A5
+:1078E0001460000224120003000090213C1080006C
+:1078F00036180A8036040900970E002C9083001178
+:107900009089001293050018307F00FF312800FF96
+:10791000024810210002C880930D0018033F78210F
+:1079200001F1302130B100FF00D11821A78E00589D
+:107930003C010800A4263FEE3C010800A4233FF0D0
+:1079400015A00002000000000000000D920B010BCA
+:107950003065FFFF3C010800A4233FF2316A00407C
+:107960003C010800A4203FE83C010800A4203FE4BB
+:107970001140000224A4000A24A4000B3091FFFF50
+:107980000E0001E7022020219206010B3C0C0800AA
+:10799000958C3FF2004020210006698231A700014A
+:1079A0000E000601018728210040202102602821C5
+:1079B0000E00060C024030210E0007AB00402021D3
+:1079C00016C00069004020219212010B325600407F
+:1079D00012C000053C0500FF8C93000034AEFFFF91
+:1079E000026E8024AC9000000E0001FB02202021DA
+:1079F0003C0F080091EF3FF831F100031220001610
+:107A00003C1380088F8200543C0980083528008090
+:107A1000245F0001AD1F003C3C0580088CB90004C8
+:107A200003E02021033FC0231B000002AF9F00544E
+:107A30008CA400040E000702ACA400043C078000E4
+:107A40008CEB00743C04800834830080004B502190
+:107A5000AC6A000C3C138008367000800280202144
+:107A600002A02821A200006B0E0007673C148000D2
+:107A70008F920054368C0140AD92000C8F860048E6
+:107A80003C151000344D000624D60001AF96004886
+:107A90008FBF002CA18600128FB60028AD8D001478
+:107AA0008FB3001CAE9501788FB200188FB50024FB
+:107AB0008FB400208FB100148FB0001003E00008D5
+:107AC00027BD003034640980908F0008000F7600D5
+:107AD000000E6E0305A00033347F090093F8001BED
+:107AE000241900103C010800A0393FF833130002AC
+:107AF0001260FF678F8600548F8200601446FF6516
+:107B00003C0480000E00007C000000003C04800863
+:107B10003485008090A8000924060016310300FF78
+:107B20001066000D0000000090AB00093C07080043
+:107B300090E73FF824090008316400FF34EA0001AF
+:107B40003C010800A02A3FF81089002F240C000AED
+:107B5000108C00282402000C0E00007E00000000A3
+:107B60000A00086A8F8600540E0007C302402821CD
+:107B70000A0008B8004020213C0B8008356A0080CC
+:107B80008D4600548CE9000C1120FF3DAF86005457
+:107B9000240700143C010800A0273FF80A000869E8
+:107BA0003C0C800090910008241200023C01080067
+:107BB000A0323FF8323000201200000B24160001E2
+:107BC0008F8600540A00086A2411000837F80080E4
+:107BD0008F020038AFE200048FF90004AF19003CB7
+:107BE0000A0008763C0780008F8600540A00086A65
+:107BF00024110004A0A200090E00007E0000000075
+:107C00000A00086A8F860054240200140A000944FE
+:107C1000A0A2000927BDFFE8AFB000103C10800013
+:107C2000AFBF001436020100904400090E00076740
+:107C3000240500013C0480089099000E34830080E4
+:107C4000909F000F906F00269089000A33F800FF84
+:107C500000196E000018740031EC00FF01AE5025D1
+:107C6000000C5A00014B3825312800FF3603014033
+:107C70003445600000E830252402FF813C041000F8
+:107C8000AC66000C8FBF0014AC650014A06200123B
+:107C9000AE0401788FB0001003E0000827BD001883
+:107CA00027BDFFE8308400FFAFBF00100E0007675C
+:107CB00030A500FF3C05800034A40140344700405B
+:107CC0002406FF92AC870014A08600128F83005414
+:107CD0008FBF00103C02100027BD0018AC83000CC1
+:107CE00003E00008ACA2017827BDFFD8AFB00010B8
+:107CF000308400FF30B000FF3C058000AFB10014BD
+:107D0000AFBF0020AFB3001CAFB20018000410C218
+:107D100034A6010032030002305100011460000754
+:107D200090D200093C098008353300809268000534
+:107D30003107000810E0000C308A001002402021BA
+:107D40000E00078D02202821240200018FBF002091
+:107D50008FB3001C8FB200188FB100148FB00010C9
+:107D600003E0000827BD00281540003434A50A00B0
+:107D70008CB800248CAF0008130F004B0000382192
+:107D80003C0D800835B30080926C00682406000228
+:107D9000318B00FF116600843C06800034C2010074
+:107DA0009263004C90590009307F00FF53F90004A2
+:107DB0003213007C10E00069000000003213007CE8
+:107DC0005660005C0240202116200009320D00019F
+:107DD0003C0C800035840100358B0A008D65002441
+:107DE0008C86000414A6FFD900001021320D00017A
+:107DF00011A0000E024020213C1880003710010025
+:107E00008E0F000C8F8E005011EE00080000000055
+:107E10000E00084D022028218E19000C3C1F8008FE
+:107E200037F00080AE190050024020210E00077B81
+:107E3000022028210A000999240200013C050800BB
+:107E40008CA5006424A400013C010800AC2400645B
+:107E50001600000D00000000022028210E00077B04
+:107E600002402021926E0068240C000231CD00FFF8
+:107E700011AC0022024020210E00094B000000003E
+:107E80000A000999240200010E0000702404000178
+:107E9000926B0025020B30250E00007EA2660025A5
+:107EA0000A0009DD022028218E6200188CDF000400
+:107EB0008CB9002400021E0217F9FFB13065007F63
+:107EC0009268004C264400013093007F1265004008
+:107ED000310300FF1464FFAB3C0D8008264700010E
+:107EE00030F1007F30E200FF1225000B2407000173
+:107EF000004090210A0009A6241100012405000475
+:107F00000E00073C240600010E00094B0000000093
+:107F10000A000999240200012405FF80024520245B
+:107F200000859026324200FF004090210A0009A6F9
+:107F3000241100010E00084D0220282132070030D4
+:107F400010E0FFA132100082024020210E00078DB8
+:107F5000022028210A000999240200018E690018D4
+:107F60000240202102202821012640250E00096E12
+:107F7000AE6800189264004C24050003240600013A
+:107F80000E00073C308400FF0E0000702404000146
+:107F900092710025021150250E00007EA26A002574
+:107FA0000A000999240200018E6F00183C18800015
+:107FB0000240202101F87025022028210E00077BB5
+:107FC000AE6E00189264004C0A000A2524050004D5
+:107FD000324A0080394900801469FF6A3C0D8008EC
+:107FE0000A0009FE2647000127BDFFC0AFB00018F8
+:107FF0003C108000AFBF0038AFB70034AFB60030E0
+:10800000AFB5002CAFB40028AFB30024AFB200204E
+:108010000E0005BEAFB1001C360201009045000BFA
+:108020000E00098090440008144000E78FBF00381C
+:108030003C08800835070080A0E0006B3606098008
+:1080400090C50000240300503C17080026F73FB0FD
+:1080500030A400FF3C13080026733FC010830003C8
+:108060003C1080000000B82100009821241F00105F
+:108070003611010036120A00361509808E58002488
+:108080008E3400048EAF00208F8C00543C01080019
+:10809000A03F3FF836190A80972B002C8EF600007F
+:1080A000932A00180298702301EC68233C01080011
+:1080B000AC2E3FD43C010800AC2D3FD83C01080059
+:1080C000AC2C3FFCA78B005802C0F809315400FFCC
+:1080D00030490002152000E930420001504000C440
+:1080E0009227000992A90008312800081500000213
+:1080F000241500030000A8213C0A80003543090034
+:1081000035440A008C8D002490720011907000128A
+:10811000907F0011325900FF321100FF02B110218F
+:108120000002C08033EF00FF0319B021028F7021DD
+:1081300002D4602125CB00103C010800A4363FEE9C
+:108140003C010800AC2D40003C010800A42C3FF08D
+:108150003C010800A42B3FEC355601003554098042
+:1081600035510E008F8700548F89005C8E8500206A
+:1081700024080006012730233C010800AC283FF406
+:1081800000A7282304C000B50000902104A000B37C
+:1081900000C5502B114000B5000000003C01080054
+:1081A000AC263FD88E6200000040F80900000000B5
+:1081B0003046000214C0007400408021304B0001A2
+:1081C000556000118E6200043C0D08008DAD3FDC4F
+:1081D0003C0EC0003C04800001AE6025AE2C0000C7
+:1081E0008C980000330F000811E0FFFD0000000034
+:1081F000963F000824120001A79F00408E3900041A
+:10820000AF9900388E6200040040F80900000000B9
+:108210000202802532030002146000B30000000057
+:108220003C09080095293FE43C06080094C63FF04D
+:108230003C0A0800954A3FE63C0708008CE73FDC13
+:10824000012670213C0308008C6340003C080800B4
+:1082500095083FFA01CA20218ED9000C00E9282197
+:10826000249F000200A878210067C02133E4FFFFAB
+:10827000AF9900503C010800AC3840003C010800B8
+:10828000A42F3FE83C010800A42E3FF20E0001E7B6
+:10829000000000008F8D0048004020213C010800B4
+:1082A000A02D3FF98E62000825AC0001AF8C00487C
+:1082B0000040F809000000008F85005402A0302122
+:1082C0000E00060C004020210E0007AB00402021CC
+:1082D0008E6B000C0160F809004020213C0A080068
+:1082E000954A3FF23C06080094C63FE60146482105
+:1082F000252800020E0001FB3104FFFF3C050800A9
+:108300008CA53FD43C0708008CE73FDC00A7202366
+:108310003C010800AC243FD414800006000000009B
+:108320003C0208008C423FF4344B00403C01080002
+:10833000AC2B3FF4124000438F8E00448E2D001072
+:108340008F920044AE4D00208E2C0018AE4C0024BD
+:108350003C04080094843FE80E000704000000007D
+:108360008F9F00548E6700103C010800AC3F3FFC1B
+:1083700000E0F809000000003C1908008F393FD4E4
+:108380001720FF798F870054979300583C11800E77
+:10839000321601000E000733A633002C16C000452C
+:1083A000320300105460004C8EE500043208004097
+:1083B0005500001D8EF000088EE4000C0080F809C6
+:1083C000000000008FBF00388FB700348FB6003038
+:1083D0008FB5002C8FB400288FB300248FB20020FB
+:1083E0008FB1001C8FB0001803E0000827BD0040CB
+:1083F0008F86003C36110E0000072E0000A62025B7
+:10840000AE0400808E4300208E500024AFA30010E5
+:10841000AE2300148FB20010AE320010AE30001C3C
+:108420000A000A7FAE3000180200F80900000000C0
+:108430008EE4000C0080F809000000000A000B38F0
+:108440008FBF003824180001240F0001A5C00020B0
+:10845000A5D800220A000B1AADCF00243C01080069
+:10846000AC203FD80A000AB08E6200003C01080030
+:10847000AC253FD80A000AB08E62000092240009A1
+:108480000E00077B000028218FBF00388FB7003413
+:108490008FB600308FB5002C8FB400288FB3002426
+:1084A0008FB200208FB1001C8FB0001803E00008CD
+:1084B00027BD00403C14800092950109000028214E
+:1084C0000E00084D32A400FF320300105060FFB8C8
+:1084D000320800408EE5000400A0F809000000000A
+:1084E0000A000B32320800405240FFA89793005810
+:1084F0008E3400148F930044AE7400208E35001C1F
+:10850000AE7500240A000B29979300588F8200143F
+:108510000004218003E00008008210213C0780084D
+:1085200034E200809043006900804021106000091F
+:108530003C0401003C0708008CE73FFC8F830030BF
+:1085400000E32023048000089389001C14E3000347
+:108550000100202103E00008008010213C040100FC
+:1085600003E00008008010211120000B0067382371
+:108570003C0D800035AC0980918B007C316A000293
+:10858000114000202409003400E9702B15C0FFF1D0
+:108590000100202100E938232403FFFC00A3C824A4
+:1085A00000E3C02400F9782B15E0FFEA030820213E
+:1085B00030C400030004102314C000143049000329
+:1085C0000000302100A9782101E6702100EE682B1F
+:1085D00011A0FFE03C0401002D3800010006C82B6B
+:1085E000010548210319382414E0FFDA2524FFFC93
+:1085F0002402FFFC00A218240068202103E00008E8
+:10860000008010210A000BA8240900303C0C8000D7
+:108610003586098090CB007C316A00041540FFE963
+:10862000240600040A000BB7000030213C030800B8
+:108630008C63005C8F82001827BDFFE0AFBF00187D
+:10864000AFB1001410620005AFB00010000329C0E4
+:1086500024A40280AF840014AF8300183C10800073
+:1086600036020A0094450032361101000E000B89D3
+:1086700030A43FFF8E240000241FFF803C110080A7
+:108680000082C021031F60243309007F000CC94011
+:1086900003294025330E0078362F00033C0D1000CF
+:1086A000010D502501CF5825AE0C00283608098051
+:1086B000AE0C080CAE0B082CAE0A08309103006912
+:1086C0003C06800C0126382110600006AF8700347C
+:1086D0008D09003C8D03006C0123382318E00082D3
+:1086E000000000003C0B8008356A00803C108000D0
+:1086F000A1400069360609808CC200383C06800023
+:1087000034C50A0090A8003C310C00201180001AEA
+:10871000AF820030240D00013C0E800035D10A00EC
+:10872000A38D001CAF8000248E2400248F8500249C
+:10873000240D0008AF800020AF8000283C01080015
+:10874000A42D3FE63C010800A4203FFA0E000B8D4B
+:10875000000030219228003C8FBF00188FB1001418
+:108760008FB0001000086142AF82002C27BD0020AE
+:1087700003E000083182000190B80032240E0001AD
+:10878000330F00FF000F2182108E004124190002D8
+:108790001099006434C40AC03C03800034640A00A9
+:1087A0008C8F002415E0001E34660900909F003075
+:1087B0002418000533F9003F1338004E240300014C
+:1087C0008F860020A383001CAF860028AF8600247C
+:1087D0003C0E800035D10A008E2400248F850024B1
+:1087E000240D00083C010800A42D3FE63C010800D0
+:1087F000A4203FFA0E000B8D000000009228003CE0
+:108800008FBF00188FB100148FB0001000086142B4
+:10881000AF82002C27BD002003E000083182000158
+:108820008C8A00088C8B00248CD000643C0E800065
+:1088300035D10A00014B2823AF900024A380001CEF
+:10884000AF8500288E2400248F8600208F85002489
+:10885000240D00083C010800A42D3FE63C0108005F
+:10886000A4203FFA0E000B8D000000009228003C6F
+:108870008FBF00188FB100148FB000100008614244
+:10888000AF82002C27BD002003E0000831820001E8
+:1088900090A200303051003F5224002834C50AC055
+:1088A0008CB000241600002234CB09008CA60048AE
+:1088B0003C0A7FFF3545FFFF00C510243C0E8000B9
+:1088C000AF82002035C509008F8800208CAD006084
+:1088D000010D602B15800002010020218CA4006096
+:1088E0000A000C2CAF8400208D02006C0A000C06DC
+:1088F0003C0680008C8200488F8600203C097FFF68
+:108900003527FFFF004788243C048008240300012A
+:10891000AF910028AC80006CA383001C0A000C3AC5
+:10892000AF8600248C9F00140A000C2CAF9F0020FF
+:108930008D6200680A000C763C0E800034C4098009
+:108940008C8900708CA300140123382B10E00004E4
+:10895000000000008C8200700A000C763C0E800043
+:108960008CA200140A000C763C0E80008F85002437
+:1089700027BDFFE0AFBF0018AFB1001414A000087E
+:10898000AFB000103C04800034870A0090E600304D
+:108990002402000530C3003F106200B9348409008E
+:1089A0008F91002000A080213C048000348E0A00BA
+:1089B0008DCD00043C0608008CC63FD831A73FFF90
+:1089C00000E6602B5580000100E03021938F001CF1
+:1089D00011E0007800D0282B349F098093F9007CA7
+:1089E00033380002130000792403003400C3102B35
+:1089F000144000D90000000000C3302300D0282B11
+:108A00003C010800A4233FE414A0006E02001821DA
+:108A10003C0408008C843FD40064402B55000001C6
+:108A2000006020213C05800034A90A00912A003C06
+:108A30003C010800AC243FDC3143002014600003FB
+:108A40000000482134AB0E008D6900188F88002C7F
+:108A50000128202B1080005F000000003C0508006A
+:108A60008CA53FDC00A96821010D602B1180005C02
+:108A700000B0702B0109382300E028213C010800D8
+:108A8000AC273FDC12000003240AFFFC10B0008D6D
+:108A90003224000300AA18243C010800A4203FFA55
+:108AA0003C010800AC233FDC006028218F840024B7
+:108AB000120400063C0B80088D6C006C0200202123
+:108AC000AF91002025900001AD70006C8F8D0028C3
+:108AD00000858823AF91002401A52023AF840028BE
+:108AE0001220000224070018240700103C188008F8
+:108AF0003706008090CF00683C010800A0273FF8AF
+:108B00002407000131EE00FF11C7004700000000FC
+:108B100014800018000028213C06800034D1098010
+:108B200034CD010091A600098E2C001824C4000148
+:108B3000000C86023205007F308B007F1165007FBC
+:108B40002407FF803C19800837290080A124004CAD
+:108B50003C0808008D083FF4241800023C0108007E
+:108B6000A0384039350F00083C010800AC2F3FF415
+:108B7000240500103C02800034440A009083003C2D
+:108B8000307F002013E0000500A02021240A00010E
+:108B90003C010800AC2A3FDC34A400018FBF001860
+:108BA0008FB100148FB000100080102103E0000886
+:108BB00027BD00203C010800A4203FE410A0FF9442
+:108BC000020018210A000CCA00C018210A000CC1BA
+:108BD000240300303C0508008CA53FDC00B0702B5E
+:108BE00011C0FFA8000000003C19080097393FE4BD
+:108BF0000325C0210307782B11E000072CAA0004ED
+:108C00003C0360008C625404305F003F17E0FFE3D8
+:108C1000240400422CAA00041140FF9A24040042BC
+:108C20000A000D2E8FBF00181528FFB900000000A4
+:108C30008CCA00183C1F800024020002015F182526
+:108C4000ACC3001837F90A00A0C200689329003CA1
+:108C50002404000400A01021312800203C01080059
+:108C6000A024403911000002240500102402000154
+:108C70003C010800AC223FD40A000D243C028000D5
+:108C80008F8800288C8900600109282B14A000021D
+:108C9000010088218C9100603C048000348B0E0020
+:108CA0008D640018240A00010220282102203021AE
+:108CB000A38A001C0E000B8D022080210A000CB03C
+:108CC000AF82002C000458231220000731640003F7
+:108CD0003C0E800035C7098090ED007C31AC00046B
+:108CE00015800019248F00043C010800A4243FFAD9
+:108CF0003C1F080097FF3FFA03E5C82100D9C02BAD
+:108D00001300FF6B8F8400242CA6000514C0FFA362
+:108D10002404004230A200031440000200A21823E1
+:108D200024A3FFFC3C010800AC233FDC3C0108000D
+:108D3000A4203FFA0A000CF10060282100C770242B
+:108D40000A000D1701C720263C010800A42F3FFA96
+:108D50000A000D82000000003C010800AC203FDC4E
+:108D60000A000D2D240400428F8300283C0580005A
+:108D700034AA0A0014600006000010219147003058
+:108D80002406000530E400FF108600030000000008
+:108D900003E0000800000000914B0048316900FF2B
+:108DA000000941C21500FFFA3C0680083C04080097
+:108DB00094843FE43C0308008C633FFC3C190800AA
+:108DC0008F393FDC3C0F080095EF3FFA0064C0216B
+:108DD0008CCD00040319702101CF602134AB0E004B
+:108DE000018D282318A0001D00000000914F004CA9
+:108DF0008F8C0034956D001031EE00FF8D890004DA
+:108E000001AE30238D8A000030CEFFFF000E290016
+:108E10000125C82100003821014720210325182BF6
+:108E20000083C021AD990004AD980000918F000A25
+:108E300001CF6821A18D000A956500128F8A003448
+:108E4000A5450008954B003825690001A549003863
+:108E50009148000D35070008A147000D03E0000808
+:108E60000000000027BDFFD8AFB000189388001C99
+:108E70008FB000143C0A80003C197FFF8F870024CC
+:108E80003738FFFFAFBF0020AFB1001C355F0A00CD
+:108E90000218182493EB003C00087FC03C02BFFF7F
+:108EA000006F60252CF000013449FFFF3C1F0800D3
+:108EB0008FFF3FFC8F9900303C18080097183FF255
+:108EC00001897824001047803C07EFFF3C05F0FF44
+:108ED00001E818253C1180003169002034E2FFFFD1
+:108EE00034ADFFFF362E098027A5001024060002AE
+:108EF00003F96023270B0002354A0E000062182494
+:108F00000080802115200002000040218D48001CB7
+:108F1000A7AB0012058000392407000030E800FFED
+:108F200000083F00006758253C028008AFAB0014E2
+:108F3000344F008091EA00683C08080091083FF92E
+:108F40003C09DFFF352CFFFF000AF82B3C0208002C
+:108F500094423FECA3A80011016CC024001FCF4035
+:108F6000031918258FA70010AFA300143C0C0800AC
+:108F7000918C3FFBA7A200168FAB001400ED482494
+:108F80003C0F01003C0A0FFF012FC8253198000358
+:108F9000355FFFFF016D40243C027000033F382421
+:108FA00000181E0000E2482501037825AFAF001429
+:108FB000AFA9001091CC007C0E000092A3AC00156C
+:108FC000362D0A0091A6003C30C400201080000617
+:108FD000260200083C11080096313FE8262EFFFFCC
+:108FE0003C010800A42E3FE88FBF00208FB1001C79
+:108FF0008FB0001803E0000827BD00288F8B002CDD
+:10900000010B502B5540FFC5240700010A000E0E2E
+:1090100030E800FF9383001C3C02800027BDFFD88E
+:1090200034480A0000805021AFBF002034460AC0F7
+:10903000010028211060000E34440980910700309F
+:10904000240B00058F89002030EC003F118B000BB2
+:1090500000003821AFA900103C0B80088D69006C1E
+:10906000AFAA00180E00015AAFA90014A380001C7B
+:109070008FBF002003E0000827BD00288D1F004897
+:109080003C1808008F183FDC8F9900283C027FFFB6
+:109090008D0800443443FFFFAFA900103C0B80084B
+:1090A0008D69006C03E370240319782101CF6823D4
+:1090B00001A83821AFAA00180E00015AAFA9001468
+:1090C0000A000E62A380001C3C05800034A60A0042
+:1090D00090C7003C3C06080094C63FFA3C020800DA
+:1090E0008C423FF430E30020000624001060001E94
+:1090F000004438253C0880083505008090A30068AE
+:109100000000482124080001000028212404000157
+:109110003C0680008CCD017805A0FFFE34CF0140D5
+:10912000ADE800083C0208008C423FFCA5E50004C5
+:10913000A5E40006ADE2000C3C04080090843FF971
+:109140003C03800834790080A1E40012ADE70014EC
+:10915000A5E900189338004C3C0E1000A1F8002D32
+:1091600003E00008ACCE017834A90E008D28001C65
+:109170003C0C08008D8C3FDC952B0016952A0014C2
+:10918000018648213164FFFF0A000E8A3145FFFF46
+:109190003C04800034830A009065003C30A200202B
+:1091A0001040001934870E000000402100003821D3
+:1091B000000020213C0680008CC901780520FFFEBC
+:1091C00034CA014034CF010091EB0009AD480008DA
+:1091D0003C0E08008DCE3FFC240DFF91240C004076
+:1091E0003C081000A5440004A5470006AD4E000C45
+:1091F000A14D0012AD4C0014A5400018A14B002D4C
+:1092000003E00008ACC801788CE8001894E600126E
+:1092100094E4001030C7FFFF0A000EB33084FFFF54
+:109220003C04800034830A009065003C30A200209A
+:109230001040002727BDFFF8240900010000382155
+:10924000240800013C0680008CCA01780540FFFE1E
+:109250003C0280FF34C40100908D00093C0C0800E2
+:10926000918C4039A3AD00038FAB00003185007FA6
+:109270003459FFFF01665025AFAA00009083000A11
+:10928000A3A0000200057E00A3A300018FB8000088
+:1092900034CB0140240C30000319702401CF682521
+:1092A000AD6D000C27BD0008AD6C0014A560001862
+:1092B000AD690008A56700042409FF80A5680006C1
+:1092C0003C081000A169001203E00008ACC8017856
+:1092D00034870E008CE9001894E6001294E4001024
+:1092E00030C8FFFF0A000ED73087FFFF27BDFFE021
+:1092F000AFB100143C118000AFB00010AFBF001838
+:1093000036380A00970F0032363001000E000B8904
+:1093100031E43FFF8E0E0000240DFF803C0420004E
+:1093200001C25821016D6024000C4940316A007F60
+:10933000012A4025010438253C048008AE27083066
+:109340003486008090C500682403000230A200FF2C
+:10935000104300048F9F00208F990024AC9F006869
+:10936000AC9900648FBF00188FB100148FB000104B
+:1093700003E0000827BD00203C0A0800254A3AA85F
+:109380003C09080025293B383C08080025082F44E3
+:109390003C07080024E73C043C06080024C6392C9E
+:1093A0003C05080024A536803C040800248432844F
+:1093B0003C030800246339E03C0208002442377C67
+:1093C0003C010800AC2A3FB83C010800AC293FB47E
+:1093D0003C010800AC283FB03C010800AC273FBC72
+:1093E0003C010800AC263FCC3C010800AC253FC442
+:1093F0003C010800AC243FC03C010800AC233FD036
+:109400003C010800AC223FC803E000080000000057
+:109410008000094080000900800801008008008069
+:1094200080080000800E0000800800808008000096
+:1094300080000A8080000A00800009808000090006
+:00000001FF
+/*
+ * This file contains firmware data derived from proprietary unpublished
+ * source code, Copyright (c) 2004 - 2009 Broadcom Corporation.
+ *
+ * Permission is hereby granted for the distribution of this firmware data
+ * in hexadecimal or equivalent format, provided this copyright notice is
+ * accompanying it.
+ */
diff --git a/firmware/bnx2/bnx2-rv2p-06-5.0.0.j3.fw.ihex b/firmware/bnx2/bnx2-rv2p-06-5.0.0.j3.fw.ihex
deleted file mode 100644
index 52c496331de2..000000000000
--- a/firmware/bnx2/bnx2-rv2p-06-5.0.0.j3.fw.ihex
+++ /dev/null
@@ -1,424 +0,0 @@
-:100000000000000000000C900000005800000009F3
-:1000100000000000000000000000000000000000E0
-:1000200000000000000000000000000000000000D0
-:1000300000000CE000000CE80000000500000000DB
-:1000400000000000000000000000000000000000B0
-:080050000000000000000000A8
-:0800580000000010B180000659
-:100060000000001F01030300000000080500FFFF5F
-:10007000000000180002000000000008050000FF5A
-:10008000000000180002000000000008AC000001A1
-:1000900000000000050000000000000C2F8000019F
-:1000A000000000002B000000000000002B8000007A
-:1000B0000000001091E0000200000008AC00000108
-:1000C00000000010203F004D00000010213F000301
-:1000D0000000001020BF001C000000188000FFFD81
-:1000E00000000008B1000001000000082C8000B0F2
-:1000F000000000082D000008000000082D8000010D
-:10010000000000188000006C0000000B2FDF0002D0
-:100110000000000C1F800002000000002C070000FF
-:100120000000001091DE0000000000080500555599
-:10013000000000188000FFF00000000B2FDF00021D
-:100140000000000C1F800000000000002C070000D1
-:100150000000001091DE0000000000080500555569
-:10016000000000188000FFEA0000000C1F80000261
-:100170000000000805005555000000188000FFE74A
-:100180000000000C298000020000000C1F8000020B
-:10019000000000002ADF0000000000082A0000051F
-:1001A0000000000805005555000000188000FFE120
-:1001B000000000080224002C0000001800040000C9
-:1001C000000000188000001C000000188000001EC5
-:1001D000000000188000006500000018800000B0DA
-:1001E00000000018800000AF000000188000000030
-:1001F00000000018800000000000001880000000CF
-:1002000000000018800000000000001880000000BE
-:1002100000000018800000000000001880000000AE
-:10022000000000188000000000000018800000F6A8
-:10023000000000188000000000000018800000008E
-:100240000000001880000015000000188000001B4E
-:10025000000000188000000000000018800000C6A8
-:10026000000000188000002F00000018800000F639
-:10027000000000188000012100000018800000EC40
-:100280000000001880000145000000188000004EAA
-:1002900000000018800000000000001880000083AB
-:1002A0000000000C1F80000100000000050000009D
-:1002B000000000188000FFC00000001091D4000072
-:1002C0000000000C298000010000000C1F800001CC
-:1002D000000000082A0000020000000005000000E5
-:1002E000000000188000FFBA0000001091D4000048
-:1002F0000000000C298000010000000C1F8000019C
-:100300000000000029420000000000082A0000024E
-:100310000000000005000000000000188000FFB38E
-:10032000000000188000FFB200000010B1BCB00A4D
-:100330000000000B2FDF00020000000003D80000C7
-:10034000000000002C3C00000000001091D40000D0
-:100350000000000806005555000000188000001736
-:1003600000000018800000BF000000102C6201BADD
-:100370000000001880000006000000082C8000B17A
-:10038000000000082D0000090000001091D40000BA
-:10039000000000082D8001070000001880000024E4
-:1003A0000000000C298000000000000C1F800000ED
-:1003B0000000001091DE0000000000002ADF0000B5
-:1003C000000000082A00000600000008050055553E
-:1003D000000000188000FF9C0000001091D4000075
-:1003E0000000000C298000010000000C1F800001AB
-:1003F000000000082A00000B0000000005000000BB
-:10040000000000188000FF960000001800020000A5
-:10041000000000000682000000000010B18A000801
-:1004200000000010B18C14070000000B050AFFFF4C
-:1004300000000010B18A000300000000860A1800C6
-:1004400000000010918C0000000000082A0000014C
-:100450000000001091D4000000000018000D000002
-:1004600000000000050200000000001091DE000006
-:1004700000000018000A00000000000006820000D2
-:100480000000001091DE000000000010BEE1000539
-:10049000000000188000FF7D0000000105611400CD
-:1004A00000000010918A000200000008B0E1000185
-:1004B00000000018000D000000000000068200008F
-:1004C0000000001091DE000000000010BEE20005F8
-:1004D000000000188000FF75000000010562140094
-:1004E00000000010918A000200000008B1620001C3
-:1004F00000000018000D000000000010B1A0B013B3
-:100500000000000B2FDF0002000000002C20000084
-:10051000000000082C800000000000082D000000F2
-:100520000000001091D4000000000008060055559E
-:10053000000000188000FFDC000000082D80011C76
-:1005400000000010001F0000000000188000FFE6FF
-:100550000000000F476000080000000F060E0001B9
-:10056000000000000F580000000000000A640000B6
-:10057000000000000AE50000000000090B66FFFF14
-:10058000000000000D610000000000188000001352
-:100590000000000F476000080000000B2FDF000282
-:1005A000000000082C800000000000082D00000062
-:1005B0000000001091D40000000000082D80011CF4
-:1005C0000000000F060E000100000010001F0000D8
-:1005D000000000000F580000000000188000FFD449
-:1005E000000000000A640000000000000AE50000AE
-:1005F000000000090B66FFFF000000000D61000015
-:1006000000000000026200000000000B2FDF00026B
-:10061000000000003104000000000000309A0000DB
-:10062000000000000C961800000000090C99FFFF64
-:1006300000000004CC99340000000010B196320292
-:10064000000000080F8000000000000C298000015D
-:100650000000000C295200010000000C295200008B
-:10066000000000080200000E000000080280001ACE
-:1006700000000010B1C40A020000000802000003DC
-:1006800000000008220000010000000C1F80000193
-:10069000000000002ADF0000000000002A0008001F
-:1006A0000000000805005555000000188000FF41BB
-:1006B0000000000B2FDF00020000001091D40000AA
-:1006C000000000082A000001000000002C200000AB
-:1006D0000000001091D40000000000082C800000F1
-:1006E000000000082D000000000000082D80011C03
-:1006F000000000188000FFAE000000082C800006FB
-:10070000000000082D0000060000000030800000FE
-:100710000000000031000000000000082D800006ED
-:100720000000000C298000010000000C1F80000167
-:100730000000001091DE0000000000002ADF000031
-:10074000000000082A000010000000000500000062
-:10075000000000188000FF2C0000001091A0B009DC
-:10076000000000082C8000B1000000082D000009E6
-:100770000000001091D40000000000082D80010747
-:10078000000000188000FFA7000000188000001083
-:1007900000000008AC000001000000188000000B01
-:1007A000000000000380B0000000000B2FDF0002FB
-:1007B000000000002C0040000000001091D4000058
-:1007C0000000000806005555000000188000FF8951
-:1007D00000000018800000310000001880000006B2
-:1007E0000000000B2FDF0002000000002C000E00B4
-:1007F000000000082A000007000000080500555509
-:10080000000000188000FF160000000006820000B3
-:100810000000000C298000010000000C1F80000176
-:10082000000000100CE70007000000090562FFFF50
-:1008300000000010BA6C1405000000002ADF000060
-:100840000000000021000000000000082A00000550
-:100850000000001091D40000000000082C8000B0BF
-:10086000000000082D0000080000000C3162001894
-:10087000000000082D800001000000188000FF7DAE
-:1008800000000018000D000000000010B1A0B00E24
-:100890000000000B2FDF00020000000003D8000062
-:1008A000000000002C2000000000001091D4000087
-:1008B0000000001880000015000000102C620002EB
-:1008C000000000188000000C0000000B2FDF000269
-:1008D000000000002C0700000000000C1F80000139
-:1008E0000000001091DE0000000000080500FFFF7E
-:1008F000000000188000FEF8000000082C8000B105
-:10090000000000082D0000090000001091D4000034
-:10091000000000082D800107000000188000FF740F
-:100920000000000C298000010000000C1F80000165
-:100930000000001091DE0000000000002ADF00002F
-:10094000000000082A00000A000000000500000066
-:10095000000000188000FEEC00000000068200008D
-:10096000000000082C8000B0000000082D000008E6
-:10097000000000082D800150000000000000000071
-:100980000000001091DE0000000000082C80000034
-:10099000000000082D000000000000082D80010567
-:1009A00000000010BEE20005000000188000FEDA22
-:1009B000000000010562140000000010918A00028E
-:1009C00000000008B16200010000001091DE00008C
-:1009D00000000018000D00000000001091D400007D
-:1009E000000000080600AAAA000000188000FF45C9
-:1009F0000000000C298000010000000C1F80000195
-:100A0000000000082A000009000000080500AAAA4A
-:100A1000000000188000FED40000001091D40000F7
-:100A20000000000806005555000000188000FF3D3A
-:100A30000000001091A03C0200000010B1E6620727
-:100A40000000000B2FDF0002000000002C3100002E
-:100A5000000000092CB1007F000000082CD9000024
-:100A6000000000082D000000000000082D80010D8E
-:100A700000000010B1A8000600000010205F000078
-:100A8000000000002C200000000000002CA7000047
-:100A9000000000082D000010000000082D80010853
-:100AA000000000188000FF3800000010B1A6001000
-:100AB00000000010001F00000000000F0F300007B2
-:100AC000000000000A600000000000000AE10000D1
-:100AD0000000000F4B620008000000090B1600FF29
-:100AE000000000000D620000000000090D1A00FF68
-:100AF00000000010073000030000000C0D1A000871
-:100B00000000000C0B1600080000000F4CE300185A
-:100B1000000000000C992C0000000004CC99340067
-:100B2000000000080F8000000000000C2980000178
-:100B30000000000033310000000000082200001611
-:100B4000000000002ADF0000000000082A00000C5E
-:100B500000000010009F0000000000000F200000B7
-:100B60000000000C1F800001000000080500555522
-:100B7000000000188000FEA80000001091D40000C2
-:100B8000000000080600AAAA000000188000FF115B
-:100B90000000000F4722000800000009070E000FA8
-:100BA00000000008070E0008000000080280000195
-:100BB0000000000702851C0000000008828500017B
-:100BC0000000000002854C000000000742851C0068
-:100BD00000000003C3AA52000000000003B10E0091
-:100BE000000000074B071C000000000F0F3000073B
-:100BF0000000000F0A960003000000000A955C0048
-:100C0000000000004A005A00000000000C960A0094
-:100C1000000000090C99FFFF000000080D00FFFF15
-:100C200000000010B1963202000000080F8000059D
-:100C300000000010B1A8000800000010205F0000B4
-:100C40000000000B2FDF0002000000002C2000003D
-:100C5000000000002CA70000000000082D0000107C
-:100C6000000000082D800108000000188000FEFF31
-:100C70000000000C2980000100000010001F00008F
-:100C80000000000C1F800001000000002ADF0000AF
-:100C9000000000082A00000D000000080500AAAAB4
-:100CA000000000188000FE820000001091D40000B7
-:100CB0000000000806005555000000188000FEEBFB
-:100CC0000000000C298000010000000C1F800001C2
-:100CD000000000082A000007000000080500555524
-:080CE000000000188000FE7AFC
-:080CE80000000010B1800004BF
-:100CF0000000001F0103030000000008050000FFC2
-:100D00000000001800020000000000002A0000009F
-:100D100000000010B1D400000000001091DE0000BF
-:100D2000000000102053000000000010001F000011
-:100D3000000000002F80AA000000000C29800001A4
-:100D4000000000080254000D000000002C400000CC
-:100D500000000018000400000000001880000010CF
-:100D60000000001880000011000000188000003909
-:100D700000000018800000DF00000018800000DE86
-:100D800000000018800000DD00000018800000DD79
-:100D9000000000188000000000000018800000F52E
-:100DA00000000018800000D9000000188000000B2F
-:100DB00000000018800000F90000001880000147C2
-:100DC000000000188000005900000018800000C4D6
-:100DD00000000018800000C5000000002A0000008C
-:100DE000000000188000FFE6000000002A0000005C
-:100DF0000000000C29800000000000188000FFE3C4
-:100E0000000000002A000000000000188000FFE140
-:100E100000000018000200000000000005020000B1
-:100E2000000000109196342100000010205F0000A7
-:100E3000000000002C1E0000000000082C800006AE
-:100E4000000000082D000006000000082D800102AF
-:100E500000000000000000000000001091DE000013
-:100E6000000000000D61000000000018000A0000F2
-:100E700000000000050200000000001091963416EA
-:100E800000000010205F00000000000009D80000F2
-:100E9000000000002C1E0000000000082C8000B2A2
-:100EA000000000082D00000A000000082D8001024B
-:100EB00000000000000000000000001091DE0000B3
-:100EC000000000000D620000000000002C13000074
-:100ED00000000018000A00000000000005020000E9
-:100EE000000000109196340900000010205F0000FF
-:100EF000000000002C1E0000000000082C800006EE
-:100F0000000000082D00006A000000082D8001028A
-:100F100000000000000000000000001091DE000052
-:100F2000000000000D7A000000000018000A000018
-:100F3000000000002A000000000000000D61000019
-:100F4000000000000362000000000010234200A324
-:100F50000000000002638C00000000002646000034
-:100F6000000000080204001200000010B906081E6C
-:100F7000000000000F580000000000000A6400009C
-:100F8000000000000AE50000000000090B66FFFFFA
-:100F9000000000000C000000000000000B800000BA
-:100FA000000000080CC60012000000188000FFCEF0
-:100FB000000000080F800003000000000000000097
-:100FC00000000010009F0000000000082711001220
-:100FD000000000006690000000000008A31B001243
-:100FE00000000010B198000300000010001F000076
-:100FF000000000080F800004000000082200000329
-:10100000000000082C80000C000000082D00000CDF
-:1010100000000010009F0000000000002596000066
-:101020000000000C298000000000000032140000C5
-:1010300000000000329500000000000573662C00DF
-:101040000000000031E32E00000000082D80001099
-:10105000000000188000FF9800000000230000003E
-:101060000000000925E6FFFF000000082200000B39
-:101070000000000C695200000000000C29800000F4
-:10108000000000188000FF92000000002A0000000D
-:10109000000000082C800040000000082D00002007
-:1010A000000000082D80011C00000000000000006E
-:1010B0000000001091DE00000000000F42EA001066
-:1010C00000000010004F000400000010B74692001E
-:1010D000000000080249001200000010B5840A0058
-:1010E000000000000D61000000000010BA663457D7
-:1010F000000000088305001200000010004F0002ED
-:1011000000000000034900000000000183068C007D
-:101110000000000083C60C0000000010B187001121
-:10112000000000000B6E000000000010BEE900058A
-:10113000000000188000FF7900000001056914001C
-:1011400000000010918A000200000008B4E90001CC
-:1011500000000010B1E92C4A0000000086692C0054
-:1011600000000000020000000000000902EAFFFF8A
-:1011700000000010000C00020000000002040A0041
-:101180000000000F460C00010000000F0285000166
-:1011900000000010918C01FC00000010B7040E410B
-:1011A000000000000F400000000000000D61000082
-:1011B000000000000A640000000000000AE50000D2
-:1011C000000000090B66FFFF000000000C0000009B
-:1011D000000000000B800000000000080C860012D8
-:1011E000000000080F8000030000000C29520000DE
-:1011F00000000010009F00000000000827110012EE
-:10120000000000006690000000000000264600007C
-:10121000000000002306000000000010B198000547
-:1012200000000010001F0000000000080F800004F4
-:10123000000000000000000000000010001F00007F
-:101240000000000032140000000000003295000091
-:101250000000000031E32E000000000573662C0042
-:10126000000000002596000000000010B187001665
-:101270000000000C298000000000000F0F6B000729
-:10128000000000000D690000000000000A6C000072
-:10129000000000000AED0000000000000B6E0000DE
-:1012A000000000000B800000000000000C87000020
-:1012B000000000080F800003000000102053000011
-:1012C0000000000C6952000100000010001F000027
-:1012D0000000000022C58C0000000000231B00005D
-:1012E0000000000027110000000000002690000010
-:1012F00000000010B8170E030000000C2980000049
-:10130000000000188000FFF600000010B1980002F5
-:10131000000000080F800004000000082200001AEE
-:10132000000000082C80000C000000082D00000CBC
-:10133000000000082D80001000000010001F0000B9
-:10134000000000000D6E000000000003E7CF340035
-:101350000000000C298000000000001091DE000059
-:1013600000000010B18700070000000036140000E4
-:101370000000000036950000000000003716000055
-:10138000000000082C800050000000082D000030F4
-:10139000000000082D80000C000000188000FF2FC6
-:1013A00000000000264600000000000023000000AE
-:1013B0000000000925E6FFFF000000000B6E0000A2
-:1013C00000000003E7CF2C00000000082200001BF3
-:1013D0000000000C695200000000000C2980000091
-:1013E000000000188000FF26000000002A00000016
-:1013F000000000188000FF24000000002A00000008
-:101400000000000C298000000000001091DE0000A8
-:10141000000000082C80001A000000082D00001AAF
-:101420000000000573660000000000082D80000227
-:1014300000000000318000000000001091DE00007C
-:10144000000000082C80000C000000082D00000C9B
-:10145000000000082D800004000000188000FF1725
-:101460000000001800020000000000188000FF15B6
-:10147000000000002A00000000000010001F000013
-:10148000000000000F008000000000080F8000072F
-:10149000000000188000001A00000000280A000068
-:1014A0000000000005020000000000082200000902
-:1014B00000000000290000000000000F6568001017
-:1014C00000000003F66C940000000010B972A00444
-:1014D0000000000C73E700190000000C214200041A
-:1014E000000000003CF800000000000C2980000013
-:1014F0000000001020530000000000082200000837
-:101500000000000C6142000400000018000A000006
-:1015100000000000050200000000000C6142000015
-:1015200000000010014200030000000C33E7001D22
-:101530000000000C6142000200000018000A0000D8
-:10154000000000002A00000000000010001F000042
-:101550000000000F0F470007000000080F80000880
-:101560000000000C2980000000000010009F000017
-:10157000000000188000FEF400000000335100005D
-:10158000000000002A00000000000010B1C6002387
-:101590000000000F0F500007000000000A6000006C
-:1015A000000000000AE100000000000F4B6200088C
-:1015B000000000090B1600FF0000000F4C62001035
-:1015C000000000000D620000000000090D1A00FF7D
-:1015D00000000010075000030000000C0D1A000866
-:1015E0000000000C0B160008000000000CC60000F4
-:1015F000000000000B8000000000000006980000C2
-:10160000000000080F8000030000001006C2000464
-:101610000000000C29000002000000102642000219
-:101620000000000C29520003000000082200000105
-:1016300000000010009F000000000000231B0000BD
-:101640000000000027111A00000000006690000052
-:101650000000000C2952000000000010B197320970
-:101660000000000C29800000000000000698000027
-:1016700000000010205300000000000C295200035D
-:101680000000000022C58C0000000010001F0000B8
-:10169000000000080F800003000000188000FFF326
-:1016A00000000010B1C8001300000010B1C6000314
-:1016B0000000000C298000000000001020530000F2
-:1016C0000000000C295200000000000C2952000309
-:1016D0000000001006C200020000000C29520002A7
-:1016E0000000000022C58C000000000027650000FB
-:1016F0000000000026E400000000000822000016A0
-:1017000000000010B1C600030000000023480000E4
-:1017100000000010B1800005000000002348000018
-:101720000000000C298000000000000F0F5000078F
-:1017300000000018800000120000000822000016BF
-:101740000000000C298000000000000030140000A0
-:10175000000000003095000000000010075000035A
-:10176000000000090B1600FF000000090D1A00FF21
-:101770000000000F31160008000000003162340044
-:1017800000000003F162300000000010205F000044
-:10179000000000002C510000000000092CD1007F47
-:1017A000000000082CD90000000000082D000000F7
-:1017B000000000082D80000C000000000000000068
-:1017C0000000001091DE00000000001005C20004BF
-:1017D000000000080F800007000000003300000038
-:1017E00000000010009F0000000000188000FEA50F
-:1017F000000000002A0000000000000F0F5000074A
-:1018000000000010B1C6002D0000000F4742000884
-:1018100000000009070E000F00000008070E000876
-:1018200000000010001F0000000000080900000177
-:101830000000000709121C0000000003CBCA920040
-:10184000000000000B97A2000000000742171C00D8
-:10185000000000000B0400000000000F0A840003D9
-:10186000000000000A959C00000000004A009A0059
-:101870000000000882120001000000010C1708009F
-:10188000000000000C978C0000000000021800000F
-:10189000000000080D00FFFF000000080F80000698
-:1018A0000000000C290000000000001006C2000427
-:1018B0000000000C29520002000000102642000225
-:1018C0000000000C29520003000000082200000163
-:1018D00000000010009F000000000010B197320CC3
-:1018E00000000000231B000000000000271108007A
-:1018F00000000000669000000000000C298000003D
-:10190000000000000218000000000010205300003A
-:101910000000000C295200030000000022C5360020
-:1019200000000010001F0000000000080F800006EB
-:10193000000000188000FFF400000000231B0000DE
-:101940000000000027110800000000006690000061
-:1019500000000010B1C8000B0000000C298000003E
-:1019600000000010205300000000000C295200006D
-:101970000000000C295200030000001006C2000203
-:101980000000000C295200020000000022C58C005B
-:1019900000000000276500000000000026E40000B1
-:1019A000000000002348000000000008220000178B
-:1019B0000000000C2980000000000010001F000043
-:0819C000000000188000FE6A1F
-:00000001FF
-/*
- * This file contains firmware data derived from proprietary unpublished
- * source code, Copyright (c) 2004 - 2009 Broadcom Corporation.
- *
- * Permission is hereby granted for the distribution of this firmware data
- * in hexadecimal or equivalent format, provided this copyright notice is
- * accompanying it.
- */
diff --git a/firmware/bnx2/bnx2-rv2p-06-6.0.15.fw.ihex b/firmware/bnx2/bnx2-rv2p-06-6.0.15.fw.ihex
new file mode 100644
index 000000000000..dcc443e210f5
--- /dev/null
+++ b/firmware/bnx2/bnx2-rv2p-06-6.0.15.fw.ihex
@@ -0,0 +1,366 @@
+:1000000000000000000008F800000058000000098F
+:1000100000000000000000000000000000000000E0
+:1000200000000000000000000000000000000000D0
+:1000300000000CF000000950000000050000000066
+:1000400000000000000000000000000000000000B0
+:080050000000000000000000A8
+:0800580000000010B180000659
+:100060000000001F0106000F000000080500FFFF50
+:10007000000000180002000000000008050000FF5A
+:10008000000000180002000000000008AC000001A1
+:1000900000000008078000000000000C2F80000115
+:1000A000000000002B000000000000002B8000007A
+:1000B0000000001091E1000200000008AC00000107
+:1000C00000000010203F003B00000010213F000313
+:1000D0000000001020BF0015000000188000FFFD88
+:1000E0000000000C1F800002000000188000FFF9D3
+:1000F00000000008B1000001000000082C8000B0E2
+:10010000000000082D000008000000082D800001FC
+:10011000000000188000003C0000000B2FDF0002F0
+:100120000000000C1F800002000000002C070000EF
+:100130000000001091DE0000000000188000FFEFBA
+:100140000000000B2FDF00020000000C1F800000E9
+:10015000000000002C0700000000001091DE0000ED
+:10016000000000188000FFEA0000000C1F80000261
+:10017000000000188000FFE80000000802240025AD
+:1001800000000018000400000000001880000000BB
+:10019000000000188000001B0000001880000042D2
+:1001A000000000188000000000000018800000001F
+:1001B000000000188000000000000018800000000F
+:1001C00000000018800000000000001880000000FF
+:1001D00000000018800000000000001880000000EF
+:1001E00000000018800000000000001880000000DF
+:1001F000000000188000008E000000188000000041
+:1002000000000018800000000000001880000000BE
+:1002100000000018800000000000001880000000AE
+:10022000000000188000000000000018800000009E
+:10023000000000188000008D00000018800000B74A
+:10024000000000188000008400000018800000DA20
+:10025000000000188000002B000000188000000043
+:10026000000000188000006B0000001091D4000016
+:100270000000000C298000010000000C1F8000011C
+:10028000000000082A0000020000000807800000AB
+:10029000000000188000FFC4000000080380010077
+:1002A00000000010B73C0E000000001880000000A5
+:1002B000000000180002000000000000068200009C
+:1002C00000000010B18F000400000010B18F140373
+:1002D000000000082A0000010000001091D4000076
+:1002E000000000000780140000000018000D00004E
+:1002F00000000000050200000000001091DE000078
+:1003000000000018000A0000000000000682000043
+:100310000000001091DE0000000000090561FFFFF1
+:1003200000000010918A00020000000830E1FFFF89
+:10033000000000188000FFA9000000010561140002
+:1003400000000010918A000200000008B0E10001E6
+:1003500000000018000D00000000000006820000F0
+:100360000000001091DE0000000000090562FFFFA0
+:1003700000000010918A0002000000083162FFFFB7
+:10038000000000188000FF9F0000000105621400BB
+:1003900000000010918A000200000008B162000114
+:1003A00000000018000D000000000010B1A0B01304
+:1003B0000000000B2FDF0002000000002C200000D6
+:1003C000000000082C800000000000082D00000044
+:1003D0000000001091D40000000000080500005546
+:1003E000000000188000FFDB000000082D80011CC9
+:1003F00000000010001F0000000000188000FFE255
+:100400000000000F476000080000000F060E00010A
+:10041000000000000F580000000000000A64000007
+:10042000000000000AE50000000000090B66FFFF65
+:10043000000000000D6100000000001880000015A1
+:100440000000000F476000080000000B2FDF0002D3
+:10045000000000082C800000000000082D000000B3
+:100460000000001091D40000000000082D80011C45
+:100470000000000F060E000100000010001F000029
+:10048000000000000F580000000000188000FFD09E
+:10049000000000000A640000000000000AE50000FF
+:1004A000000000090B66FFFF000000000D61000066
+:1004B00000000000026200000000000002E00000F6
+:1004C0000000000B2FDF00020000000030050000DC
+:1004D000000000003104000000000000309A00001D
+:1004E000000000100060000A00000008051600016E
+:1004F00000000010BA9A140300000000030000007E
+:100500000000001880000006000000188000FF6C4A
+:1005100000000010B60614040000000803060001E5
+:10052000000000082A000001000000188000FF7190
+:10053000000000000C961800000000090C99FFFF55
+:1005400000000004CC99340000000010BA992C027D
+:10055000000000080F8000000000000C298000014E
+:100560000000000C295200010000000C295200007C
+:100570000000000822800002000000080200000EB7
+:10058000000000080280001A00000010B1C40A0236
+:1005900000000008020000030000000C1F800001A2
+:1005A000000000002ADF0000000000002A00080010
+:1005B000000000188000FF600000000B2FDF000229
+:1005C0000000001091D40000000000082A00000183
+:1005D000000000002C2000000000001091D400005A
+:1005E000000000082C800000000000082D00000022
+:1005F000000000082D80011C000000188000FF9FF3
+:10060000000000082C800006000000082D000006F5
+:1006100000000000308000000000000031000000F9
+:10062000000000082D8000060000000C2980000159
+:100630000000000C1F8000010000001091DE00008F
+:10064000000000002ADF0000000000082A0000105F
+:100650000000000807800000000000188000FF4B29
+:100660000000001091D4000000000008050000AA5E
+:10067000000000188000FF890000000C29800001A4
+:100680000000000C1F800001000000082A00000983
+:10069000000000188000FF440000001091D400000A
+:1006A0000000000805000055000000188000FF82CF
+:1006B0000000001091A0B00200000010B1E6620737
+:1006C0000000000B2FDF0002000000002C310000B2
+:1006D000000000092CB1007F000000082CD90000A8
+:1006E000000000082D000000000000082D80010D12
+:1006F00000000010B1A8000600000010205F0000FC
+:10070000000000002C200000000000002CA70000CA
+:10071000000000082D000010000000082D800108D6
+:10072000000000188000FF7A00000010B1A6001041
+:1007300000000010001F00000000000F0F30000735
+:10074000000000000A600000000000000AE1000054
+:100750000000000F4B620008000000090B1600FFAC
+:10076000000000000D620000000000090D1A00FFEB
+:1007700000000010073000030000000C0D1A0008F4
+:100780000000000C0B1600080000000F4CE30018DE
+:10079000000000000C992C0000000004CC993400EB
+:1007A000000000080F8000000000000C29800001FC
+:1007B0000000000033310000000000082200001695
+:1007C000000000002ADF0000000000082A00000CE2
+:1007D00000000010009F0000000000002C2000001E
+:1007E0000000000C1F800001000000188000FF19AD
+:1007F0000000001091D4000000000008050000AACD
+:10080000000000188000FF570000000F472200087A
+:1008100000000009070E000F00000008070E000886
+:1008200000000008028000010000000702851C0093
+:1008300000000008828500010000000002854C00D5
+:100840000000000742851C0000000003C3AA5200FC
+:100850000000000003B10E00000000074B071C0061
+:100860000000000F0F3000070000000F0A96000381
+:10087000000000000A955C00000000004A005A00D9
+:10088000000000000C960A00000000090C99FFFF10
+:10089000000000080D00FFFF00000010BA992C02B4
+:1008A000000000080F80000500000010B1A800083B
+:1008B00000000010205F00000000000B2FDF00028E
+:1008C000000000002C200000000000002CA7000009
+:1008D000000000082D000010000000082D80010815
+:1008E000000000188000FF420000000C2980000179
+:1008F00000000010001F00000000000C1F8000011D
+:10090000000000002ADF0000000000082A00000D9F
+:10091000000000188000FEF40000001091D40000D8
+:100920000000000805000055000000188000FF329C
+:100930000000000C298000010000000C1F80000155
+:10094000000000082A000007000000188000FEEDEB
+:1009500000000010B18000040000001F0106000F1D
+:1009600000000008050000FF000000180002000061
+:10097000000000002A00000000000010B1D40000B8
+:100980000000001091DE0000000000102053000065
+:1009900000000010001F0000000000002F80AA00CF
+:1009A0000000000C29800001000000080254000E25
+:1009B000000000002C400000000000000F4000007C
+:1009C0000000001800040000000000188000001162
+:1009D000000000188000001200000018800000389D
+:1009E00000000018800000DF00000018800000DE1A
+:1009F00000000018800000DD00000018800000DD0D
+:100A0000000000188000000000000018800000F6C0
+:100A100000000018800000D90000001880000000CD
+:100A200000000018800000FA000000188000014853
+:100A3000000000188000005A00000018800000C468
+:100A400000000018800000C500000018800000D2DF
+:100A5000000000002A000000000000188000FFE4F1
+:100A6000000000002A0000000000000C29800000A7
+:100A7000000000188000FFE10000001800020000E4
+:100A8000000000000502000000000010B99A2C21AF
+:100A900000000010205F0000000000002C1E00007D
+:100AA000000000082C800006000000082D00000651
+:100AB000000000082D80010200000000000000007E
+:100AC0000000001091DE0000000000000D61000039
+:100AD00000000018000A00000000000005020000ED
+:100AE00000000010B99A2C1600000010205F0000D2
+:100AF0000000000009D80000000000002C1E0000CB
+:100B0000000000082C8000B2000000082D00000A40
+:100B1000000000082D80010200000000000000001D
+:100B20000000001091DE0000000000000D620000D7
+:100B3000000000002C13000000000018000A000054
+:100B4000000000000502000000000010B99A2C0906
+:100B500000000010205F0000000000002C1E0000BC
+:100B6000000000082C800006000000082D00006A2C
+:100B7000000000082D8001020000000000000000BD
+:100B80000000001091DE0000000000000D7A00005F
+:100B900000000018000A0000000000002A00000009
+:100BA0000000000822000001000000000D610000AC
+:100BB0000000001021C2002400000010B1C6000295
+:100BC00000000010234200A2000000090B66FFFF96
+:100BD00000000010BA9A2C20000000000A640000F7
+:100BE000000000000AE50000000000000C0000000A
+:100BF000000000000B800000000000080CC600127E
+:100C0000000000188000FFD0000000080F800003E3
+:100C1000000000000000000000000010009F000025
+:100C2000000000082711001200000000669000007C
+:100C300000000010B198000300000010001F000029
+:100C4000000000080F8000040000000822000003DC
+:100C5000000000082C80000C000000082D00000C93
+:100C600000000010009F00000000001091C6000569
+:100C700000000010001F000000000010BA9A2C03B2
+:100C8000000000080F800004000000188000FFFD35
+:100C900000000000259600000000000C29800000E4
+:100CA0000000000032140000000000003295000037
+:100CB0000000000573662C000000000031E32E00E8
+:100CC000000000082D800010000000188000FF9632
+:100CD00000000000230000000000000925E6FFFFDF
+:100CE000000000082200000B0000000C6952000008
+:100CF0000000000C29800000000000188000FF9018
+:100D0000000000002A000000000000082C800040C5
+:100D1000000000082D000020000000082D80011CAC
+:100D200000000008220000010000001091DE000019
+:100D30000000000F42EA001000000010004F000405
+:100D400000000010B746920000000008024900129F
+:100D500000000010B5840A00000000000D610000D2
+:100D600000000010BA663457000000088305001226
+:100D700000000010004F00020000000003490000C6
+:100D80000000000183068C000000000083C60C00F8
+:100D900000000010B1870013000000000B6E00007F
+:100DA000000000090569FFFF00000010918A0002A1
+:100DB0000000000834E9FFFF000000188000FF7504
+:100DC000000000010569140000000010918A000273
+:100DD00000000008B4E9000100000010BAE92C4846
+:100DE0000000000086692C000000000002000000E6
+:100DF0000000000902EAFFFF00000010000C0002E2
+:100E00000000000002040A000000000F460C000170
+:100E10000000000F0285000100000010918C01FC11
+:100E200000000010B7040E3F000000000D6100003C
+:100E3000000000000A640000000000000AE5000055
+:100E4000000000090B66FFFF000000000C0000001E
+:100E5000000000000B800000000000080C8600125B
+:100E6000000000080F8000030000000C2952000061
+:100E700000000010009F0000000000082711001271
+:100E80000000000066900000000000002306000043
+:100E900000000010B198000500000010001F0000C5
+:100EA000000000080F8000040000000000000000A7
+:100EB00000000010001F00000000000032140000BD
+:100EC00000000000329500000000000031E32E0019
+:100ED0000000000573662C0000000000259600004D
+:100EE00000000010B18700160000000C29800000EF
+:100EF0000000000F0F6B0007000000000D690000EC
+:100F0000000000000A6C0000000000000AED000074
+:100F1000000000000B6E0000000000000B800000CD
+:100F2000000000000C870000000000080F80000394
+:100F300000000010205300000000000C6952000166
+:100F400000000010001F00000000000022C58C00FF
+:100F500000000000231B000000000000271100001B
+:100F6000000000002690000000000010B8170E03DB
+:100F70000000000C29800000000000188000FFF62F
+:100F800000000010B1980002000000080F8000046B
+:100F9000000000082200001A000000082C80000C4D
+:100FA000000000082D00000C000000082D8000103B
+:100FB00000000010001F0000000000000D6E000087
+:100FC00000000003E7CF34000000000C298000007F
+:100FD0000000001091DE000000000010B187000743
+:100FE00000000000361400000000000036950000EC
+:100FF0000000000037160000000000082C800050A0
+:10100000000000082D000030000000082D80000CBA
+:10101000000000188000FF2D0000000023000000E9
+:101020000000000925E6FFFF000000000B6E000035
+:1010300000000003E7CF2C00000000082200001B86
+:101040000000000C695200000000000C2980000024
+:10105000000000188000FF25000000002A000000AA
+:10106000000000188000FF23000000002A0000009C
+:101070000000000C298000000000001091DE00003C
+:10108000000000082C80001A000000082D00001A43
+:101090000000000573660000000000082D800002BB
+:1010A00000000000318000000000001091DE000010
+:1010B000000000082C80000C000000082D00000C2F
+:1010C000000000082D800004000000188000FF16BA
+:1010D0000000001880000000000000188000FF14CD
+:1010E000000000002A00000000000010001F0000A7
+:1010F000000000000F008000000000080F800007C3
+:10110000000000188000001B00000000280A0000FA
+:101110000000000005020000000000082200000995
+:1011200000000000290000000000000F65680010AA
+:1011300000000000248A000000000003F66C940008
+:1011400000000010B972A0040000000C73E7001941
+:101150000000000C21420004000000003CF80000E8
+:101160000000000C29800000000000102053000047
+:1011700000000008220000080000000C614200048A
+:1011800000000018000A0000000000000502000036
+:101190000000000C6142000000000010014200034A
+:1011A0000000000C33E7001D0000000C614200024B
+:1011B00000000018000A0000000000002A000000E3
+:1011C00000000010001F00000000000F0F47000784
+:1011D000000000080F8000080000000C29800000BB
+:1011E00000000010009F0000000000188000FEF2C8
+:1011F0000000000033510000000000002A00000041
+:1012000000000010B1C600230000000F0F500007BF
+:10121000000000000A600000000000000AE1000079
+:101220000000000F4B620008000000090B1600FFD1
+:101230000000000F4C620010000000000D62000072
+:10124000000000090D1A00FF000000100750000305
+:101250000000000C0D1A00080000000C0B1600081E
+:10126000000000000CC60000000000000B80000021
+:101270000000000006980000000000080F80000336
+:101280000000001006C200040000000C290000024B
+:1012900000000010264200020000000C295200034A
+:1012A000000000082200000100000010009F000064
+:1012B00000000000231B00000000000027111A009E
+:1012C00000000000669000000000000C29520000A1
+:1012D00000000010B19732090000000C29800000C6
+:1012E00000000000069800000000001020530000DD
+:1012F0000000000C295200030000000022C58C00F1
+:1013000000000010001F0000000000080F80000314
+:10131000000000188000FFF300000010B1C80013A7
+:1013200000000010B1C600030000000C298000007E
+:1013300000000010205300000000000C29520000A3
+:101340000000000C295200030000001006C2000239
+:101350000000000C295200020000000022C58C0091
+:1013600000000000276500000000000026E40000E7
+:10137000000000082200001600000010B1C60003A3
+:10138000000000002348000000000010B1800005AC
+:1013900000000000234800000000000C298000002D
+:1013A0000000000F0F50000700000018800000121E
+:1013B00000000008220000160000000C2980000038
+:1013C0000000000030140000000000003095000014
+:1013D0000000001007500003000000090B1600FF7A
+:1013E000000000090D1A00FF0000000F3116000870
+:1013F000000000003162340000000003F1623000A0
+:1014000000000010205F0000000000002C510000D0
+:10141000000000092CD1007F000000082CD900003A
+:10142000000000082D000000000000082D80000CC6
+:1014300000000000000000000000001091DE00002D
+:101440000000001005C20004000000080F80000723
+:10145000000000003300000000000010009F0000AA
+:10146000000000188000FEA3000000002A00000019
+:101470000000000F0F50000700000010B1C6002D43
+:101480000000000F4742000800000009070E000F8F
+:1014900000000008070E000800000010001F0000F8
+:1014A00000000008090000010000000709121C00EC
+:1014B00000000003CBCA9200000000000B97A200BE
+:1014C0000000000742171C00000000000B04000091
+:1014D0000000000F0A840003000000000A959C0031
+:1014E000000000004A009A0000000008821200017B
+:1014F000000000010C170800000000000C978C0091
+:101500000000000002180000000000080D00FFFFAE
+:10151000000000080F8000060000000C29000000F9
+:101520000000001006C200040000000C2952000256
+:1015300000000010264200020000000C29520003A7
+:10154000000000082200000100000010009F0000C1
+:1015500000000010B197320C00000000231B0000B7
+:101560000000000027110800000000006690000045
+:101570000000000C2980000000000000021800009C
+:1015800000000010205300000000000C295200034E
+:101590000000000022C5360000000010001F0000FF
+:1015A000000000080F800006000000188000FFF413
+:1015B00000000000231B00000000000027110800AD
+:1015C000000000006690000000000010B1C8000B91
+:1015D0000000000C298000000000001020530000D3
+:1015E0000000000C295200000000000C29520003EA
+:1015F0000000001006C200020000000C2952000288
+:101600000000000022C58C000000000027650000DB
+:101610000000000026E40000000000002348000055
+:1016200000000008220000170000000C29800000C4
+:1016300000000010001F0000000000188000FE687D
+:00000001FF
+/*
+ * This file contains firmware data derived from proprietary unpublished
+ * source code, Copyright (c) 2004 - 2009 Broadcom Corporation.
+ *
+ * Permission is hereby granted for the distribution of this firmware data
+ * in hexadecimal or equivalent format, provided this copyright notice is
+ * accompanying it.
+ */
diff --git a/firmware/bnx2/bnx2-rv2p-09-5.0.0.j10.fw.ihex b/firmware/bnx2/bnx2-rv2p-09-5.0.0.j10.fw.ihex
deleted file mode 100644
index fe59d16b594e..000000000000
--- a/firmware/bnx2/bnx2-rv2p-09-5.0.0.j10.fw.ihex
+++ /dev/null
@@ -1,462 +0,0 @@
-:100000000000000000000E08000000580000000979
-:1000100000000000000000000000000000000000E0
-:1000200000000000000000000000000000000000D0
-:1000300000000DD800000E60000000050000000068
-:1000400000000000000000000000000000000000B0
-:080050000000000000000000A8
-:0800580000000010B180000659
-:100060000000001F05030300000000080500FFFF5B
-:10007000000000180002000000000008050000FF5A
-:10008000000000180002000000000008AC000001A1
-:1000900000000000050000000000000C2F8000019F
-:1000A000000000002B000000000000002B8000007A
-:1000B0000000001091E0000200000008AC00000108
-:1000C00000000010203F006B00000010213F0003E3
-:1000D0000000001020BF003A000000188000FFFD63
-:1000E00000000010B1B8B0150000000B2FDF0002B7
-:1000F0000000000003D80000000000002C380000C1
-:10010000000000082C800000000000082D00000006
-:100110000000001091D400000000000806005555B2
-:10012000000000188000007C000000082D80011CE9
-:1001300000000008020000010000001091DE000035
-:100140000000000F42E0001C0000001091840A161D
-:1001500000000018800000830000000C29800002CD
-:100160000000000C1F800002000000002ADF0000D9
-:10017000000000082A00000F000000000500000039
-:10018000000000188000FFE60000000802000001E7
-:100190000000000F42E0001C0000001091840A18CB
-:1001A000000000082C800006000000082D0000065A
-:1001B0000000001091D40000000000082D8001060E
-:1001C0000000001880000072000000188000FFF19D
-:1001D00000000008B1000001000000082C80010CA4
-:1001E000000000082D000008000000082D8000011C
-:1001F000000000188000006C0000000B2FDF0002E0
-:100200000000000C1F800002000000002C0700000E
-:100210000000001091DE00000000000805005555A8
-:10022000000000188000FFD20000000B2FDF00024A
-:100230000000000C1F800000000000002C070000E0
-:100240000000001091DE0000000000080500555578
-:10025000000000188000FFCC0000000C1F8000028E
-:100260000000000805005555000000188000FFC977
-:100270000000000C298000020000000C1F8000021A
-:10028000000000002ADF0000000000082A0000052E
-:100290000000000805005555000000188000FFC34D
-:1002A000000000080224004A0000001800040000BA
-:1002B000000000188000001C000000188000001ED4
-:1002C000000000188000006500000018800000BCDD
-:1002D00000000018800000BB000000188000000033
-:1002E00000000018800000000000001880000000DE
-:1002F00000000018800000000000001880000000CE
-:1003000000000018800000000000001880000000BD
-:1003100000000018800000000000001880000107A5
-:10032000000000188000000000000018800000009D
-:100330000000001880000015000000188000001B5D
-:10034000000000188000000000000018800000D2AB
-:10035000000000188000002F000000188000010736
-:10036000000000188000013200000018800000FD2D
-:100370000000001880000156000000188000004EA8
-:100380000000001880000000000000188000008FAE
-:100390000000000C1F8000010000000005000000AC
-:1003A000000000188000FFA20000001091D400009F
-:1003B0000000000C298000010000000C1F800001DB
-:1003C000000000082A0000020000000005000000F4
-:1003D000000000188000FF9C0000001091D4000075
-:1003E0000000000C298000010000000C1F800001AB
-:1003F0000000000029420000000000082A0000025E
-:100400000000000005000000000000188000FF95BB
-:10041000000000188000FF9400000010B1BCB00A7A
-:100420000000000B2FDF00020000000003D80000D6
-:10043000000000002C3C00000000001091D40000DF
-:100440000000000806005555000000188000001745
-:1004500000000018800000CB000000102C6201BAE0
-:100460000000001880000006000000082C80010D2C
-:10047000000000082D0000090000001091D40000C9
-:10048000000000082D8001070000001880000024F3
-:100490000000000C298000000000000C1F800000FC
-:1004A0000000001091DE0000000000002ADF0000C4
-:1004B000000000082A00000600000008050055554D
-:1004C000000000188000FF7E0000001091D40000A2
-:1004D0000000000C298000010000000C1F800001BA
-:1004E000000000082A00000B0000000005000000CA
-:1004F000000000188000FF780000001800020000D3
-:10050000000000000682000000000010B18A000810
-:1005100000000010B18C14070000000B050AFFFF5B
-:1005200000000010B18A000300000000860A1800D5
-:1005300000000010918C0000000000082A0000015B
-:100540000000001091D4000000000018000D000011
-:1005500000000000050200000000001091DE000015
-:1005600000000018000A00000000000006820000E1
-:100570000000001091DE000000000010BEE1000548
-:10058000000000188000FF5F0000000105611400FA
-:1005900000000010918A000200000008B0E1000194
-:1005A00000000018000D000000000000068200009E
-:1005B0000000001091DE000000000010BEE2000507
-:1005C000000000188000FF570000000105621400C1
-:1005D00000000010918A000200000008B1620001D2
-:1005E00000000018000D000000000010B1A0B013C2
-:1005F0000000000B2FDF0002000000002C20000094
-:10060000000000082C800000000000082D00000001
-:100610000000001091D400000000000806005555AD
-:10062000000000188000FFDC000000082D80011C85
-:1006300000000010001F0000000000188000FFE60E
-:100640000000000F476000080000000F060E0001C8
-:10065000000000000F580000000000000A640000C5
-:10066000000000000AE50000000000090B66FFFF23
-:10067000000000000D610000000000188000001361
-:100680000000000F476000080000000B2FDF000291
-:10069000000000082C800000000000082D00000071
-:1006A0000000001091D40000000000082D80011C03
-:1006B0000000000F060E000100000010001F0000E7
-:1006C000000000000F580000000000188000FFD458
-:1006D000000000000A640000000000000AE50000BD
-:1006E000000000090B66FFFF000000000D61000024
-:1006F00000000000026200000000000B2FDF00027B
-:10070000000000003104000000000000309A0000EA
-:10071000000000090560000F00000010B18A000B06
-:100720000000000005634C0000000008050A0012EC
-:1007300000000010B9621403000000000300000074
-:100740000000001880000006000000188000FF2450
-:1007500000000010B60614040000000803060001A3
-:10076000000000082A000001000000188000FF2996
-:10077000000000000C961800000000090C99FFFF13
-:1007800000000004CC99340000000010B196320241
-:10079000000000080F8000000000000C298000010C
-:1007A0000000000C295200010000000C295200003A
-:1007B000000000080200000E000000080280001A7D
-:1007C00000000010B1C40A0200000008020000038B
-:1007D00000000008220000010000000C1F80000142
-:1007E000000000002ADF0000000000002A000800CE
-:1007F0000000000805005555000000188000FF1794
-:100800000000000B2FDF00020000001091D4000058
-:10081000000000082A000001000000002C20000059
-:100820000000001091D40000000000082C8000009F
-:10083000000000082D000000000000082D80011CB1
-:10084000000000188000FFA2000000082C800006B5
-:10085000000000082D0000060000000030800000AD
-:100860000000000031000000000000082D8000069C
-:100870000000000C298000010000000C1F80000116
-:100880000000001091DE0000000000002ADF0000E0
-:10089000000000082A000010000000000500000011
-:1008A000000000188000FF020000001091A0B009B5
-:1008B000000000082C80010D000000082D00000938
-:1008C0000000001091D40000000000082D800107F6
-:1008D000000000188000FF9B00000018800000103E
-:1008E00000000008AC000001000000188000000BB0
-:1008F000000000000380B0000000000B2FDF0002AA
-:10090000000000002C0040000000001091D4000006
-:100910000000000806005555000000188000FF7D0B
-:100920000000001880000031000000188000000660
-:100930000000000B2FDF0002000000002C000E0062
-:10094000000000082A0000070000000805005555B7
-:10095000000000188000FEEC00000000068200008D
-:100960000000000C298000010000000C1F80000125
-:10097000000000100CE70007000000090562FFFFFF
-:1009800000000010BA6C1405000000002ADF00000F
-:100990000000000021000000000000082A000005FF
-:1009A0000000001091D40000000000082C80010C11
-:1009B000000000082D0000080000000C3162001843
-:1009C000000000082D800001000000188000FF7169
-:1009D00000000018000D000000000010B1A0B00ED3
-:1009E0000000000B2FDF00020000000003D8000011
-:1009F000000000002C2000000000001091D4000036
-:100A00000000001880000015000000102C62000299
-:100A1000000000188000000C0000000B2FDF000217
-:100A2000000000002C0700000000000C1F800001E7
-:100A30000000001091DE0000000000080500FFFF2C
-:100A4000000000188000FECE000000082C80010D80
-:100A5000000000082D0000090000001091D40000E3
-:100A6000000000082D800107000000188000FF68CA
-:100A70000000000C298000010000000C1F80000114
-:100A80000000001091DE0000000000002ADF0000DE
-:100A9000000000082A00000A000000000500000015
-:100AA000000000188000FEC2000000000682000066
-:100AB000000000082C80010C000000082D00000838
-:100AC000000000082D80013400000000000000003C
-:100AD00000000010205F0000000000082C80014092
-:100AE000000000082D00003C000000082D800124BB
-:100AF00000000000000000000000001091DE000077
-:100B0000000000082C800080000000082D0000007C
-:100B1000000000082D80010500000010BEE2000565
-:100B2000000000188000FEAB000000010562140008
-:100B300000000010918A000200000008B16200016C
-:100B40000000001091DE000000000018000D000001
-:100B50000000001091D40000000000080600AAAABE
-:100B6000000000188000FF340000000C2980000104
-:100B70000000000C1F800001000000082A0000098E
-:100B8000000000080500AAAA000000188000FEA5C9
-:100B90000000001091D40000000000080600555528
-:100BA000000000188000FF2C0000001091A03C0203
-:100BB00000000010B1E662070000000B2FDF00020A
-:100BC000000000002C310000000000092CB1007F63
-:100BD000000000082CD90000000000082D000000D3
-:100BE000000000082D80010D00000010B1A80006D3
-:100BF00000000010205F0000000000002C2000001A
-:100C0000000000002CA70000000000082D000010CC
-:100C1000000000082D800108000000188000FF2758
-:100C200000000010B1A6001000000010001F00001E
-:100C30000000000F0F300007000000000A600000F5
-:100C4000000000000AE100000000000F4B620008F5
-:100C5000000000090B1600FF000000000D620000FC
-:100C6000000000090D1A00FF00000010073000030B
-:100C70000000000C0D1A00080000000C0B16000804
-:100C80000000000F4CE30018000000000C992C003D
-:100C900000000004CC993400000000080F80000020
-:100CA0000000000C2980000100000000333100002A
-:100CB0000000000822000016000000002ADF0000EB
-:100CC000000000082A00000C00000010009F000037
-:100CD000000000000F2000000000000C1F80000139
-:100CE0000000000805005555000000188000FE793E
-:100CF0000000001091D40000000000080600AAAA1D
-:100D0000000000188000FF000000000F47220008CC
-:100D100000000009070E000F00000008070E000881
-:100D200000000008028000010000000702851C008E
-:100D300000000008828500010000000002854C00D0
-:100D40000000000742851C0000000003C3AA5200F7
-:100D50000000000003B10E00000000074B071C005C
-:100D60000000000F0F3000070000000F0A9600037C
-:100D7000000000000A955C00000000004A005A00D4
-:100D8000000000000C960A00000000090C99FFFF0B
-:100D9000000000080D00FFFF00000010B1963202B5
-:100DA000000000080F80000500000010B1A8000836
-:100DB00000000010205F00000000000B2FDF000289
-:100DC000000000002C200000000000002CA7000004
-:100DD000000000082D000010000000082D80010810
-:100DE000000000188000FEEE0000000C29800001C9
-:100DF00000000010001F00000000000C1F80000118
-:100E0000000000002ADF0000000000082A00000D9A
-:100E1000000000080500AAAA000000188000FE5388
-:100E20000000001091D40000000000080600555595
-:100E3000000000188000FEDA0000000C298000018C
-:100E40000000000C1F800001000000082A000007BD
-:100E50000000000805005555000000188000FE4BFA
-:100E600000000010B18000040000001F0503030013
-:100E700000000008050000FF00000018000200004C
-:100E8000000000002A00000000000010B1D40000A3
-:100E90000000001091DE0000000000102053000050
-:100EA00000000010001F0000000000002F80AA00BA
-:100EB0000000000C29800001000000080254000E10
-:100EC000000000002C400000000000092952003FF3
-:100ED000000000180004000000000018800000104E
-:100EE0000000001880000011000000188000003988
-:100EF00000000018800000FD00000018800000FCC9
-:100F000000000018800000FB00000018800000FBBB
-:100F1000000000188000000000000018800001138D
-:100F200000000018800000F7000000188000000B8F
-:100F30000000001880000117000000188000016503
-:100F4000000000188000006300000018800000CE40
-:100F500000000018800000DE000000002A000000F1
-:100F6000000000188000FFE5000000002A000000DB
-:100F70000000000C29800000000000188000FFE243
-:100F8000000000002A000000000000188000FFE0C0
-:100F90000000001800020000000000000502000030
-:100FA000000000109196342100000010205F000026
-:100FB000000000002C1E0000000000082C8000062D
-:100FC000000000082D000006000000082D8001022E
-:100FD00000000000000000000000001091DE000092
-:100FE000000000000D61000000000018000A000071
-:100FF0000000000005020000000000109196341669
-:1010000000000010205F00000000000009D8000070
-:10101000000000002C1E0000000000082C80010EC3
-:10102000000000082D00000A000000082D800102C9
-:1010300000000000000000000000001091DE000031
-:10104000000000000D620000000000002C130000F2
-:1010500000000018000A0000000000000502000067
-:10106000000000109196340900000010205F00007D
-:10107000000000002C1E0000000000082C8000066C
-:10108000000000082D00006A000000082D80010209
-:1010900000000000000000000000001091DE0000D1
-:1010A000000000000D7A000000000018000A000097
-:1010B000000000002A000000000000000D61000098
-:1010C000000000000362000000000010234200C185
-:1010D0000000000002638C000000000026460000B3
-:1010E000000000080204001200000010B9060827E2
-:1010F000000000000F580000000000000A6400001B
-:10110000000000000AE50000000000090B66FFFF78
-:10111000000000000C000000000000000B80000038
-:10112000000000080CC60012000000188000FFCE6E
-:10113000000000080F800003000000000000000015
-:1011400000000010009F000000000008271100129E
-:10115000000000006690000000000008A31B0012C1
-:1011600000000010B198000300000010001F0000F4
-:10117000000000080F8000040000000822000003A7
-:10118000000000082C80000C000000082D00000C5E
-:1011900000000010009F00000000000025960000E5
-:1011A0000000000C2980000000000000066600001E
-:1011B0000000000086611800000000090260000FB6
-:1011C0000000000F0204000200000010B60C080529
-:1011D0000000000C1FBF0000000000102866000384
-:1011E00000000008078F00010000000C33660010AB
-:1011F00000000000321400000000000032950000E2
-:101200000000000573662C000000000031E32E0092
-:10121000000000082D800010000000188000FF8EE4
-:1012200000000000230000000000000925E6FFFF89
-:10123000000000082200000B0000000C69520000B2
-:101240000000000C298000000000001028660075D6
-:10125000000000188000FF87000000002A00000046
-:10126000000000082C800040000000082D00002035
-:10127000000000082D80011C00000000000000009C
-:101280000000001091DE00000000000F42EA001094
-:1012900000000010004F000400000010B74692004C
-:1012A000000000080249001200000010B5840A0086
-:1012B000000000000D61000000000010BA66345705
-:1012C000000000088305001200000010004F00021B
-:1012D00000000000034900000000000183068C00AC
-:1012E0000000000083C60C0000000010B187001150
-:1012F000000000000B6E000000000010BEE90005B9
-:10130000000000188000FF6E000000010569140055
-:1013100000000010918A000200000008B4E90001FA
-:1013200000000010B1E92C4A0000000086692C0082
-:1013300000000000020000000000000902EAFFFFB8
-:1013400000000010000C00020000000002040A006F
-:101350000000000F460C00010000000F0285000194
-:1013600000000010918C01FC00000010B7040E4139
-:10137000000000000F400000000000000D610000B0
-:10138000000000000A640000000000000AE5000000
-:10139000000000090B66FFFF000000000C000000C9
-:1013A000000000000B800000000000080C86001206
-:1013B000000000080F8000030000000C295200000C
-:1013C00000000010009F000000000008271100121C
-:1013D00000000000669000000000000026460000AB
-:1013E000000000002306000000000010B198000576
-:1013F00000000010001F0000000000080F80000423
-:10140000000000000000000000000010001F0000AD
-:1014100000000000321400000000000032950000BF
-:101420000000000031E32E000000000573662C0070
-:10143000000000002596000000000010B187001693
-:101440000000000C298000000000000F0F6B000757
-:10145000000000000D690000000000000A6C0000A0
-:10146000000000000AED0000000000000B6E00000C
-:10147000000000000B800000000000000C8700004E
-:10148000000000080F80000300000010205300003F
-:101490000000000C6952000100000010001F000055
-:1014A0000000000022C58C0000000000231B00008B
-:1014B000000000002711000000000000269000003E
-:1014C00000000010B8170E030000000C2980000077
-:1014D000000000188000FFF600000010B198000224
-:1014E000000000080F800004000000082200001A1D
-:1014F000000000082C80000C000000082D00000CEB
-:10150000000000082D80001000000010001F0000E7
-:10151000000000000D6E000000000003E7CF340063
-:101520000000000C298000000000001091DE000087
-:1015300000000010B1870007000000003614000012
-:101540000000000036950000000000003716000083
-:10155000000000082C800050000000082D00003022
-:10156000000000082D80000C000000188000FF24FF
-:1015700000000000264600000000000023000000DC
-:101580000000000925E6FFFF000000000B6E0000D0
-:1015900000000003E7CF2C00000000082200001B21
-:1015A0000000000C695200000000000C29800000BF
-:1015B000000000188000FF1B000000002A0000004F
-:1015C000000000100866000500000000066600002C
-:1015D000000000008661180000000009026000F0B1
-:1015E00000000010B60C0802000000188000FF1474
-:1015F000000000000682000000000010B18F000013
-:1016000000000008878F00010000000C73660010C6
-:10161000000000082C800018000000082D000018B1
-:10162000000000082D8000020000000C5FBF0000D9
-:101630000000001091DE000000000018000D000006
-:10164000000000002A00000000000010286601F5DC
-:10165000000000082C800003000000082D0000039B
-:10166000000000093060FFF0000000082D8000013C
-:101670000000000C298000000000001091DE000036
-:10168000000000082C80001A000000082D00001A3D
-:101690000000000573660000000000082D800002B5
-:1016A00000000000318000000000001091DE00000A
-:1016B000000000082C80000C000000082D00000C29
-:1016C000000000082D800004000000188000FEF8D3
-:1016D0000000001800020000000000188000FEF664
-:1016E000000000002A00000000000010001F0000A1
-:1016F000000000000F008000000000080F800007BD
-:10170000000000188000001A00000000280A0000F5
-:10171000000000000502000000000008220000098F
-:1017200000000000290000000000000F65680010A4
-:1017300000000003F66C940000000010B972A004D1
-:101740000000000C73E700190000000C21420004A7
-:10175000000000003CF800000000000C29800000A0
-:1017600000000010205300000000000822000008C4
-:101770000000000C6142000400000018000A000094
-:1017800000000000050200000000000C61420000A3
-:1017900000000010014200030000000C33E7001DB0
-:1017A0000000000C6142000200000018000A000066
-:1017B000000000002A00000000000010001F0000D0
-:1017C0000000000F0F470007000000080F8000080E
-:1017D0000000000C2980000000000010009F0000A5
-:1017E000000000188000FED500000000335100000A
-:1017F000000000002A00000000000010B1C6002315
-:101800000000000F0F500007000000000A600000F9
-:10181000000000000AE100000000000F4B62000819
-:10182000000000090B1600FF0000000F4C620010C2
-:10183000000000000D620000000000090D1A00FF0A
-:1018400000000010075000030000000C0D1A0008F3
-:101850000000000C0B160008000000000CC6000081
-:10186000000000000B80000000000000069800004F
-:10187000000000080F8000030000001006C20004F2
-:101880000000000C290000020000001026420002A7
-:101890000000000C29520003000000082200000193
-:1018A00000000010009F000000000000231B00004B
-:1018B0000000000027111A000000000066900000E0
-:1018C0000000000C2952000000000010B1973209FE
-:1018D0000000000C298000000000000006980000B5
-:1018E00000000010205300000000000C29520003EB
-:1018F0000000000022C58C0000000010001F000046
-:10190000000000080F800003000000188000FFF3B3
-:1019100000000010B1C8001300000010B1C60003A1
-:101920000000000C2980000000000010205300007F
-:101930000000000C295200000000000C2952000396
-:101940000000001006C200020000000C2952000234
-:101950000000000022C58C00000000002765000088
-:101960000000000026E4000000000008220000162D
-:1019700000000010B1C60003000000002348000072
-:1019800000000010B18000050000000023480000A6
-:101990000000000C298000000000000F0F5000071D
-:1019A000000000188000001200000008220000164D
-:1019B0000000000C2980000000000000301400002E
-:1019C00000000000309500000000001007500003E8
-:1019D000000000090B1600FF000000090D1A00FFAF
-:1019E0000000000F311600080000000031623400D2
-:1019F00000000003F162300000000010205F0000D2
-:101A0000000000002C510000000000092CD1007FD4
-:101A1000000000082CD90000000000082D00000084
-:101A2000000000082D80000C0000000000000000F5
-:101A30000000001091DE00000000001005C200044C
-:101A4000000000080F8000070000000033000000C5
-:101A500000000010009F0000000000188000FE86BB
-:101A6000000000002A0000000000000F0F500007D7
-:101A700000000010B1C6002D0000000F4742000812
-:101A800000000009070E000F00000008070E000804
-:101A900000000010001F0000000000080900000105
-:101AA0000000000709121C0000000003CBCA9200CE
-:101AB000000000000B97A2000000000742171C0066
-:101AC000000000000B0400000000000F0A84000367
-:101AD000000000000A959C00000000004A009A00E7
-:101AE0000000000882120001000000010C1708002D
-:101AF000000000000C978C0000000000021800009D
-:101B0000000000080D00FFFF000000080F80000625
-:101B10000000000C290000000000001006C20004B4
-:101B20000000000C295200020000001026420002B2
-:101B30000000000C295200030000000822000001F0
-:101B400000000010009F000000000010B197320C50
-:101B500000000000231B0000000000002711080007
-:101B600000000000669000000000000C29800000CA
-:101B700000000000021800000000001020530000C8
-:101B80000000000C295200030000000022C53600AE
-:101B900000000010001F0000000000080F80000679
-:101BA000000000188000FFF400000000231B00006C
-:101BB00000000000271108000000000066900000EF
-:101BC00000000010B1C8000B0000000C29800000CC
-:101BD00000000010205300000000000C29520000FB
-:101BE0000000000C295200030000001006C2000291
-:101BF0000000000C295200020000000022C58C00E9
-:101C000000000000276500000000000026E400003E
-:101C10000000000023480000000000082200001718
-:101C20000000000C2980000000000010001F0000D0
-:081C3000000000188000FE4BCB
-:00000001FF
-/*
- * This file contains firmware data derived from proprietary unpublished
- * source code, Copyright (c) 2004 - 2009 Broadcom Corporation.
- *
- * Permission is hereby granted for the distribution of this firmware data
- * in hexadecimal or equivalent format, provided this copyright notice is
- * accompanying it.
- */
diff --git a/firmware/bnx2/bnx2-rv2p-09-6.0.17.fw.ihex b/firmware/bnx2/bnx2-rv2p-09-6.0.17.fw.ihex
new file mode 100644
index 000000000000..435203d64305
--- /dev/null
+++ b/firmware/bnx2/bnx2-rv2p-09-6.0.17.fw.ihex
@@ -0,0 +1,392 @@
+:1000000000000000000008F800000058000000098F
+:1000100000000000000000000000000000000000E0
+:1000200000000000000000000000000000000000D0
+:1000300000000E88000009500000000500000000CC
+:1000400000000000000000000000000000000000B0
+:080050000000000000000000A8
+:0800580000000010B180000659
+:100060000000001F05060011000000080500FFFF4A
+:10007000000000180002000000000008050000FF5A
+:10008000000000180002000000000008AC000001A1
+:1000900000000008078000000000000C2F80000115
+:1000A000000000002B000000000000002B8000007A
+:1000B0000000001091E1000200000008AC00000107
+:1000C00000000010203F003B00000010213F000313
+:1000D0000000001020BF0015000000188000FFFD88
+:1000E0000000000C1F800002000000188000FFF9D3
+:1000F00000000008B1000001000000082C80010C85
+:10010000000000082D000008000000082D800001FC
+:10011000000000188000003C0000000B2FDF0002F0
+:100120000000000C1F800002000000002C070000EF
+:100130000000001091DE0000000000188000FFEFBA
+:100140000000000B2FDF00020000000C1F800000E9
+:10015000000000002C0700000000001091DE0000ED
+:10016000000000188000FFEA0000000C1F80000261
+:10017000000000188000FFE80000000802240025AD
+:1001800000000018000400000000001880000000BB
+:10019000000000188000001B0000001880000042D2
+:1001A000000000188000000000000018800000001F
+:1001B000000000188000000000000018800000000F
+:1001C00000000018800000000000001880000000FF
+:1001D00000000018800000000000001880000000EF
+:1001E00000000018800000000000001880000000DF
+:1001F000000000188000008E000000188000000041
+:1002000000000018800000000000001880000000BE
+:1002100000000018800000000000001880000000AE
+:10022000000000188000000000000018800000009E
+:10023000000000188000008D00000018800000B74A
+:10024000000000188000008400000018800000DA20
+:10025000000000188000002B000000188000000043
+:10026000000000188000006B0000001091D4000016
+:100270000000000C298000010000000C1F8000011C
+:10028000000000082A0000020000000807800000AB
+:10029000000000188000FFC4000000080380010077
+:1002A00000000010B73C0E000000001880000000A5
+:1002B000000000180002000000000000068200009C
+:1002C00000000010B18F000400000010B18F140373
+:1002D000000000082A0000010000001091D4000076
+:1002E000000000000780140000000018000D00004E
+:1002F00000000000050200000000001091DE000078
+:1003000000000018000A0000000000000682000043
+:100310000000001091DE0000000000090561FFFFF1
+:1003200000000010918A00020000000830E1FFFF89
+:10033000000000188000FFA9000000010561140002
+:1003400000000010918A000200000008B0E10001E6
+:1003500000000018000D00000000000006820000F0
+:100360000000001091DE0000000000090562FFFFA0
+:1003700000000010918A0002000000083162FFFFB7
+:10038000000000188000FF9F0000000105621400BB
+:1003900000000010918A000200000008B162000114
+:1003A00000000018000D000000000010B1A0B01304
+:1003B0000000000B2FDF0002000000002C200000D6
+:1003C000000000082C800000000000082D00000044
+:1003D0000000001091D40000000000080500005546
+:1003E000000000188000FFDB000000082D80011CC9
+:1003F00000000010001F0000000000188000FFE255
+:100400000000000F476000080000000F060E00010A
+:10041000000000000F580000000000000A64000007
+:10042000000000000AE50000000000090B66FFFF65
+:10043000000000000D6100000000001880000015A1
+:100440000000000F476000080000000B2FDF0002D3
+:10045000000000082C800000000000082D000000B3
+:100460000000001091D40000000000082D80011C45
+:100470000000000F060E000100000010001F000029
+:10048000000000000F580000000000188000FFD09E
+:10049000000000000A640000000000000AE50000FF
+:1004A000000000090B66FFFF000000000D61000066
+:1004B00000000000026200000000000002E00000F6
+:1004C0000000000B2FDF00020000000030050000DC
+:1004D000000000003104000000000000309A00001D
+:1004E000000000100060000A00000008051600016E
+:1004F00000000010BA9A140300000000030000007E
+:100500000000001880000006000000188000FF6C4A
+:1005100000000010B60614040000000803060001E5
+:10052000000000082A000001000000188000FF7190
+:10053000000000000C961800000000090C99FFFF55
+:1005400000000004CC99340000000010BA992C027D
+:10055000000000080F8000000000000C298000014E
+:100560000000000C295200010000000C295200007C
+:100570000000000822800002000000080200000EB7
+:10058000000000080280001A00000010B1C40A0236
+:1005900000000008020000030000000C1F800001A2
+:1005A000000000002ADF0000000000002A00080010
+:1005B000000000188000FF600000000B2FDF000229
+:1005C0000000001091D40000000000082A00000183
+:1005D000000000002C2000000000001091D400005A
+:1005E000000000082C800000000000082D00000022
+:1005F000000000082D80011C000000188000FF9FF3
+:10060000000000082C800006000000082D000006F5
+:1006100000000000308000000000000031000000F9
+:10062000000000082D8000060000000C2980000159
+:100630000000000C1F8000010000001091DE00008F
+:10064000000000002ADF0000000000082A0000105F
+:100650000000000807800000000000188000FF4B29
+:100660000000001091D4000000000008050000AA5E
+:10067000000000188000FF890000000C29800001A4
+:100680000000000C1F800001000000082A00000983
+:10069000000000188000FF440000001091D400000A
+:1006A0000000000805000055000000188000FF82CF
+:1006B0000000001091A0B00200000010B1E6620737
+:1006C0000000000B2FDF0002000000002C310000B2
+:1006D000000000092CB1007F000000082CD90000A8
+:1006E000000000082D000000000000082D80010D12
+:1006F00000000010B1A8000600000010205F0000FC
+:10070000000000002C200000000000002CA70000CA
+:10071000000000082D000010000000082D800108D6
+:10072000000000188000FF7A00000010B1A6001041
+:1007300000000010001F00000000000F0F30000735
+:10074000000000000A600000000000000AE1000054
+:100750000000000F4B620008000000090B1600FFAC
+:10076000000000000D620000000000090D1A00FFEB
+:1007700000000010073000030000000C0D1A0008F4
+:100780000000000C0B1600080000000F4CE30018DE
+:10079000000000000C992C0000000004CC993400EB
+:1007A000000000080F8000000000000C29800001FC
+:1007B0000000000033310000000000082200001695
+:1007C000000000002ADF0000000000082A00000CE2
+:1007D00000000010009F0000000000002C2000001E
+:1007E0000000000C1F800001000000188000FF19AD
+:1007F0000000001091D4000000000008050000AACD
+:10080000000000188000FF570000000F472200087A
+:1008100000000009070E000F00000008070E000886
+:1008200000000008028000010000000702851C0093
+:1008300000000008828500010000000002854C00D5
+:100840000000000742851C0000000003C3AA5200FC
+:100850000000000003B10E00000000074B071C0061
+:100860000000000F0F3000070000000F0A96000381
+:10087000000000000A955C00000000004A005A00D9
+:10088000000000000C960A00000000090C99FFFF10
+:10089000000000080D00FFFF00000010BA992C02B4
+:1008A000000000080F80000500000010B1A800083B
+:1008B00000000010205F00000000000B2FDF00028E
+:1008C000000000002C200000000000002CA7000009
+:1008D000000000082D000010000000082D80010815
+:1008E000000000188000FF420000000C2980000179
+:1008F00000000010001F00000000000C1F8000011D
+:10090000000000002ADF0000000000082A00000D9F
+:10091000000000188000FEF40000001091D40000D8
+:100920000000000805000055000000188000FF329C
+:100930000000000C298000010000000C1F80000155
+:10094000000000082A000007000000188000FEEDEB
+:1009500000000010B18000040000001F0506001117
+:1009600000000008050000FF000000180002000061
+:10097000000000002A00000000000010B1D40000B8
+:100980000000001091DE0000000000102053000065
+:1009900000000010001F0000000000002F80AA00CF
+:1009A0000000000C29800001000000080254000F24
+:1009B000000000002C400000000000000F4000007C
+:1009C000000000092952003F000000180004000048
+:1009D00000000018800000110000001880000012C4
+:1009E000000000188000003800000018800001118D
+:1009F0000000001880000110000000188000010FA6
+:100A0000000000188000010F0000001880000000A6
+:100A10000000001880000128000000188000010B71
+:100A20000000001880000000000000188000012C69
+:100A3000000000188000017A000000188000005AB1
+:100A400000000018800000C400000018800000C5ED
+:100A50000000001880000104000000002A000000CF
+:100A6000000000188000FFE3000000002A000000E2
+:100A70000000000C29800000000000188000FFE04A
+:100A80000000001800020000000000000502000045
+:100A900000000010B99A2C2100000010205F000017
+:100AA000000000002C1E0000000000082C80000642
+:100AB000000000082D000006000000082D80010243
+:100AC00000000000000000000000001091DE0000A7
+:100AD000000000000D61000000000018000A000086
+:100AE000000000000502000000000010B99A2C165A
+:100AF00000000010205F00000000000009D8000086
+:100B0000000000002C1E0000000000082C80010ED8
+:100B1000000000082D00000A000000082D800102DE
+:100B200000000000000000000000001091DE000046
+:100B3000000000000D620000000000002C13000007
+:100B400000000018000A000000000000050200007C
+:100B500000000010B99A2C0900000010205F00006E
+:100B6000000000002C1E0000000000082C80000681
+:100B7000000000082D00006A000000082D8001021E
+:100B800000000000000000000000001091DE0000E6
+:100B9000000000000D7A000000000018000A0000AC
+:100BA000000000002A0000000000000822000001F0
+:100BB000000000000D6100000000001021C20024B0
+:100BC00000000010B1C6000200000010234200A285
+:100BD000000000090B66FFFF00000010BA9A2C20ED
+:100BE000000000000A640000000000000AE50000A8
+:100BF000000000000C000000000000000B8000005E
+:100C0000000000080CC60012000000188000FFD091
+:100C1000000000080F80000300000000000000003A
+:100C200000000010009F00000000000827110012C3
+:100C3000000000006690000000000010B198000362
+:100C400000000010001F0000000000080F800004DA
+:100C50000000000822000003000000082C80000CA7
+:100C6000000000082D00000C00000010009F000094
+:100C70000000001091C6000500000010001F0000D9
+:100C800000000010BA9A2C03000000080F80000436
+:100C9000000000188000FFFD000000002596000005
+:100CA0000000000C29800000000000003214000049
+:100CB00000000000329500000000000573662C0063
+:100CC0000000000031E32E00000000082D8000101D
+:100CD000000000188000FF950000000023000000C5
+:100CE0000000000925E6FFFF000000082200000BBD
+:100CF0000000000C695200000000000C2980000078
+:100D0000000000188000FF8F000000002A00000093
+:100D1000000000082C800040000000082D0000208A
+:100D2000000000082D80011C0000000822000001C6
+:100D30000000001091DE00000000000F42EA0010E9
+:100D400000000010004F000400000010B7469200A1
+:100D5000000000080249001200000010B5840A00DB
+:100D6000000000000D61000000000010BA6634575A
+:100D7000000000088305001200000010004F000270
+:100D800000000000034900000000000183068C0001
+:100D90000000000083C60C0000000010B1870013A3
+:100DA000000000000B6E0000000000090569FFFF55
+:100DB00000000010918A00020000000834E9FFFFE3
+:100DC000000000188000FF74000000010569140095
+:100DD00000000010918A000200000008B4E9000140
+:100DE00000000010BAE92C480000000086692C00C1
+:100DF00000000000020000000000000902EAFFFFFE
+:100E000000000010000C00020000000002040A00B4
+:100E10000000000F460C00010000000F02850001D9
+:100E200000000010918C01FC00000010B7040E3F80
+:100E3000000000000D610000000000000A640000D6
+:100E4000000000000AE50000000000090B66FFFF3B
+:100E5000000000000C000000000000000B800000FB
+:100E6000000000080C860012000000080F8000033C
+:100E70000000000C2952000000000010009F00003C
+:100E8000000000082711001200000000669000001A
+:100E9000000000002306000000000010B1980005CB
+:100EA00000000010001F0000000000080F80000478
+:100EB000000000000000000000000010001F000003
+:100EC0000000000032140000000000003295000015
+:100ED0000000000031E32E000000000573662C00C6
+:100EE000000000002596000000000010B1870016E9
+:100EF0000000000C298000000000000F0F6B0007AD
+:100F0000000000000D690000000000000A6C0000F5
+:100F1000000000000AED0000000000000B6E000061
+:100F2000000000000B800000000000000C870000A3
+:100F3000000000080F800003000000102053000094
+:100F40000000000C6952000100000010001F0000AA
+:100F50000000000022C58C0000000000231B0000E0
+:100F60000000000027110000000000002690000093
+:100F700000000010B8170E030000000C29800000CC
+:100F8000000000188000FFF600000010B198000279
+:100F9000000000080F800004000000082200001A72
+:100FA000000000082C80000C000000082D00000C40
+:100FB000000000082D80001000000010001F00003D
+:100FC000000000000D6E000000000003E7CF3400B9
+:100FD0000000000C298000000000001091DE0000DD
+:100FE00000000010B1870007000000003614000068
+:100FF00000000000369500000000000037160000D9
+:10100000000000082C800050000000082D00003077
+:10101000000000082D80000C000000188000FF2C4C
+:1010200000000000230000000000000925E6FFFF8B
+:10103000000000000B6E000000000003E7CF2C0052
+:10104000000000082200001B0000000C6952000094
+:101050000000000C29800000000000188000FF2420
+:10106000000000002A000000000000188000FF229D
+:10107000000000002A0000000000000C2980000091
+:101080000000001091DE0000000000082C80001A13
+:10109000000000082D00001A000000057366000023
+:1010A000000000082D8000020000000031800000D8
+:1010B0000000001091DE0000000000082C80000CF1
+:1010C000000000082D00000C000000082D80000426
+:1010D000000000188000FF150000000806660001EF
+:1010E00000000010BA9A197F000000000A64000096
+:1010F000000000000AE50000000000090B66FFFF89
+:10110000000000000C000000000000000B80000048
+:10111000000000080CC60012000000188000FF2E1E
+:10112000000000080F800003000000000000000025
+:1011300000000010009F00000000000827110012AE
+:10114000000000006690000000000010919B32003B
+:10115000000000100293000000000010B19800038E
+:1011600000000010001F0000000000080F800004B5
+:101170000000000C2980000000000010001F00008B
+:1011800000000010BA9A2C000000000031E32E008D
+:10119000000000000B800000000000008CCC8C00E0
+:1011A00000000010B5CC8C02000000080C8000018B
+:1011B000000000188000FF1B000000080F800003E3
+:1011C00000000010205300000000000C69520001D4
+:1011D0000000000022C58C0000000010009F0000ED
+:1011E0000000000027110000000000002690000011
+:1011F00000000000231B000000000010B198000355
+:1012000000000010001F0000000000080F80000414
+:101210000000000822000003000000082C80000CE1
+:10122000000000082D00000C00000010009F0000CE
+:1012300000000000259600000000000C298000003E
+:101240000000000032140000000000003295000091
+:101250000000000573662C000000000031E32E0042
+:10126000000000082D800010000000188000FEE241
+:10127000000000188000FEE1000000002A000000CD
+:1012800000000010001F0000000000000F008000A0
+:10129000000000080F800007000000188000001BFD
+:1012A00000000000280A0000000000000502000005
+:1012B00000000008220000090000000029000000D2
+:1012C0000000000F6568001000000000248A000084
+:1012D00000000003F66C940000000010B972A00436
+:1012E0000000000C73E700190000000C214200040C
+:1012F000000000003CF800000000000C2980000005
+:101300000000001020530000000000082200000828
+:101310000000000C6142000400000018000A0000F8
+:1013200000000000050200000000000C6142000007
+:1013300000000010014200030000000C33E7001D14
+:101340000000000C6142000200000018000A0000CA
+:10135000000000002A00000000000010001F000034
+:101360000000000F0F470007000000080F80000872
+:101370000000000C2980000000000010009F000009
+:10138000000000188000FEBF000000003351000084
+:10139000000000002A00000000000010B1C6002379
+:1013A0000000000F0F500007000000000A6000005E
+:1013B000000000000AE100000000000F4B6200087E
+:1013C000000000090B1600FF0000000F4C62001027
+:1013D000000000000D620000000000090D1A00FF6F
+:1013E00000000010075000030000000C0D1A000858
+:1013F0000000000C0B160008000000000CC60000E6
+:10140000000000000B8000000000000006980000B3
+:10141000000000080F8000030000001006C2000456
+:101420000000000C2900000200000010264200020B
+:101430000000000C295200030000000822000001F7
+:1014400000000010009F000000000000231B0000AF
+:101450000000000027111A00000000006690000044
+:101460000000000C2952000000000010B197320962
+:101470000000000C29800000000000000698000019
+:1014800000000010205300000000000C295200034F
+:101490000000000022C58C0000000010001F0000AA
+:1014A000000000080F800003000000188000FFF318
+:1014B00000000010B1C8001300000010B1C6000306
+:1014C0000000000C298000000000001020530000E4
+:1014D0000000000C295200000000000C29520003FB
+:1014E0000000001006C200020000000C2952000299
+:1014F0000000000022C58C000000000027650000ED
+:101500000000000026E40000000000082200001691
+:1015100000000010B1C600030000000023480000D6
+:1015200000000010B180000500000000234800000A
+:101530000000000C298000000000000F0F50000781
+:1015400000000018800000120000000822000016B1
+:101550000000000C29800000000000003014000092
+:10156000000000003095000000000010075000034C
+:10157000000000090B1600FF000000090D1A00FF13
+:101580000000000F31160008000000003162340036
+:1015900000000003F162300000000010205F000036
+:1015A000000000002C510000000000092CD1007F39
+:1015B000000000082CD90000000000082D000000E9
+:1015C000000000082D80000C00000000000000005A
+:1015D0000000001091DE00000000001005C20004B1
+:1015E000000000080F80000700000000330000002A
+:1015F00000000010009F0000000000188000FE7036
+:10160000000000002A0000000000000F0F5000073B
+:1016100000000010B1C6002D0000000F4742000876
+:1016200000000009070E000F00000008070E000868
+:1016300000000010001F0000000000080900000169
+:101640000000000709121C0000000003CBCA920032
+:10165000000000000B97A2000000000742171C00CA
+:10166000000000000B0400000000000F0A840003CB
+:10167000000000000A959C00000000004A009A004B
+:101680000000000882120001000000010C17080091
+:10169000000000000C978C00000000000218000001
+:1016A000000000080D00FFFF000000080F8000068A
+:1016B0000000000C290000000000001006C2000419
+:1016C0000000000C29520002000000102642000217
+:1016D0000000000C29520003000000082200000155
+:1016E00000000010009F000000000010B197320CB5
+:1016F00000000000231B000000000000271108006C
+:1017000000000000669000000000000C298000002E
+:10171000000000000218000000000010205300002C
+:101720000000000C295200030000000022C5360012
+:1017300000000010001F0000000000080F800006DD
+:10174000000000188000FFF400000000231B0000D0
+:101750000000000027110800000000006690000053
+:1017600000000010B1C8000B0000000C2980000030
+:1017700000000010205300000000000C295200005F
+:101780000000000C295200030000001006C20002F5
+:101790000000000C295200020000000022C58C004D
+:1017A00000000000276500000000000026E40000A3
+:1017B000000000002348000000000008220000177D
+:1017C0000000000C2980000000000010001F000035
+:0817D000000000188000FE3546
+:00000001FF
+/*
+ * This file contains firmware data derived from proprietary unpublished
+ * source code, Copyright (c) 2004 - 2009 Broadcom Corporation.
+ *
+ * Permission is hereby granted for the distribution of this firmware data
+ * in hexadecimal or equivalent format, provided this copyright notice is
+ * accompanying it.
+ */
diff --git a/firmware/bnx2/bnx2-rv2p-09ax-5.0.0.j10.fw.ihex b/firmware/bnx2/bnx2-rv2p-09ax-5.0.0.j10.fw.ihex
deleted file mode 100644
index f325e6904edb..000000000000
--- a/firmware/bnx2/bnx2-rv2p-09ax-5.0.0.j10.fw.ihex
+++ /dev/null
@@ -1,499 +0,0 @@
-:100000000000000000000E80000000580000000901
-:1000100000000000000000000000000000000000E0
-:1000200000000000000000000000000000000000D0
-:1000300000000FA800000ED800000005000000001E
-:1000400000000000000000000000000000000000B0
-:080050000000000000000000A8
-:0800580000000010B180000659
-:100060000000001F03030300000000080500FFFF5D
-:10007000000000180002000000000008050000FF5A
-:10008000000000180002000000000008AC000001A1
-:1000900000000000050000000000000C2F8000019F
-:1000A000000000002B000000000000002B8000007A
-:1000B0000000001091E0000200000008AC00000108
-:1000C00000000010203F006B00000010213F0003E3
-:1000D0000000001020BF003A000000188000FFFD63
-:1000E00000000010B1B8B0150000000B2FDF0002B7
-:1000F0000000000003D80000000000002C380000C1
-:10010000000000082C800000000000082D00000006
-:100110000000001091D400000000000806005555B2
-:10012000000000188000008F000000082D80011CD6
-:1001300000000008020000010000001091DE000035
-:100140000000000F42E0001C0000001091840A161D
-:1001500000000018800000960000000C29800002BA
-:100160000000000C1F800002000000002ADF0000D9
-:10017000000000082A00000F000000000500000039
-:10018000000000188000FFE60000000802000001E7
-:100190000000000F42E0001C0000001091840A18CB
-:1001A000000000082C800006000000082D0000065A
-:1001B0000000001091D40000000000082D8001060E
-:1001C0000000001880000085000000188000FFF18A
-:1001D00000000008B1000001000000082C80010CA4
-:1001E000000000082D000008000000082D8000011C
-:1001F000000000188000007F0000000B2FDF0002CD
-:100200000000000C1F800002000000002C0700000E
-:100210000000001091DE00000000000805005555A8
-:10022000000000188000FFD20000000B2FDF00024A
-:100230000000000C1F800000000000002C070000E0
-:100240000000001091DE0000000000080500555578
-:10025000000000188000FFCC0000000C1F8000028E
-:100260000000000805005555000000188000FFC977
-:100270000000000C298000020000000C1F8000021A
-:10028000000000002ADF0000000000082A0000052E
-:100290000000000805005555000000188000FFC34D
-:1002A000000000080224004A0000001800040000BA
-:1002B000000000188000001C000000188000001ED4
-:1002C000000000188000007800000018800000CBBB
-:1002D00000000018800000CA000000188000000024
-:1002E00000000018800000000000001880000000DE
-:1002F00000000018800000000000001880000000CE
-:1003000000000018800000000000001880000000BD
-:100310000000001880000000000000188000011696
-:10032000000000188000000000000018800000009D
-:100330000000001880000015000000188000001B5D
-:10034000000000188000000000000018800000E19C
-:10035000000000188000002F000000188000011627
-:100360000000001880000141000000188000010C0E
-:100370000000001880000165000000188000006186
-:100380000000001880000000000000188000009E9F
-:100390000000000C1F8000010000000005000000AC
-:1003A000000000188000FFA20000001091D400009F
-:1003B0000000000C298000010000000C1F800001DB
-:1003C000000000082A0000020000000005000000F4
-:1003D000000000188000FF9C0000001091D4000075
-:1003E0000000000C298000010000000C1F800001AB
-:1003F0000000000029420000000000082A0000025E
-:100400000000000005000000000000188000FF95BB
-:10041000000000188000FF9400000010B1BCB00A7A
-:100420000000000B2FDF00020000000003D80000D6
-:10043000000000002C3C00000000001091D40000DF
-:100440000000000806005555000000188000002A32
-:1004500000000018800000DA000000102C6201BAD1
-:100460000000001880000006000000082C80010D2C
-:10047000000000082D0000090000001091D40000C9
-:10048000000000082D8001070000001880000037E0
-:100490000000000C298000000000000C1F800000FC
-:1004A0000000001091DE0000000000002ADF0000C4
-:1004B000000000082A00000600000008050055554D
-:1004C000000000188000FF7E0000001091D40000A2
-:1004D0000000000C298000010000000C1F800001BA
-:1004E000000000082A00000B0000000005000000CA
-:1004F000000000188000FF780000000002020000E9
-:1005000000000000029A000000000000060C2C0011
-:1005100000000004C60C340000000010001F0000A2
-:1005200000000010B196180C0000000806960004A8
-:1005300000000009068DFFFC00000004CD051A0034
-:1005400000000004CC9A18000000001020D7000022
-:100550000000000C2B56000000000000000000000E
-:1005600000000000000000000000001020D7000084
-:10057000000000080F80000100000010B18001F4AD
-:1005800000000010001F00000000000C6B5600006F
-:1005900000000018000400000000000006820000B7
-:1005A00000000010B18A000800000010B18C140790
-:1005B0000000000B050AFFFF00000010B18A0003D5
-:1005C00000000000860A180000000010918C000056
-:1005D000000000082A0000010000001091D4000073
-:1005E00000000018000D00000000000005020000DF
-:1005F0000000001091DE000000000018000A00005A
-:1006000000000000068200000000001091DE0000E3
-:1006100000000010BEE10005000000188000FF4C43
-:10062000000000010561140000000010918A000222
-:1006300000000008B0E1000100000018000D0000FB
-:1006400000000000068200000000001091DE0000A3
-:1006500000000010BEE20005000000188000FF440A
-:10066000000000010562140000000010918A0002E1
-:1006700000000008B162000100000018000D000039
-:1006800000000010B1A0B0130000000B2FDF00022B
-:10069000000000002C200000000000082C8000005A
-:1006A000000000082D0000000000001091D40000A0
-:1006B0000000000806005555000000188000FFDC0F
-:1006C000000000082D80011C00000010001F000029
-:1006D000000000188000FFE60000000F47600008DF
-:1006E0000000000F060E0001000000000F5800007F
-:1006F000000000000A640000000000000AE500009D
-:10070000000000090B66FFFF000000000D61000003
-:1007100000000018800000130000000F4760000870
-:100720000000000B2FDF0002000000082C800000FA
-:10073000000000082D0000000000001091D400000F
-:10074000000000082D80011C0000000F060E0001B3
-:1007500000000010001F0000000000000F58000003
-:10076000000000188000FFD4000000000A640000B0
-:10077000000000000AE50000000000090B66FFFF12
-:10078000000000000D610000000000000262000097
-:100790000000000B2FDF0002000000003104000009
-:1007A00000000000309A0000000000090560000F02
-:1007B00000000010B18A000B0000000005634C002F
-:1007C00000000008050A001200000010B9621403BE
-:1007D0000000000003000000000000188000000678
-:1007E000000000188000FF1100000010B60614047D
-:1007F0000000000803060001000000082A000001B4
-:10080000000000188000FF16000000188000FF9E06
-:100810000000000C298000010000000C295200019A
-:100820000000000C29520000000000080200000E29
-:10083000000000080280001A00000010B1C40A0283
-:100840000000000802000003000000082200000170
-:100850000000000C1F800001000000002ADF0000E3
-:10086000000000002A00080000000008050055559F
-:10087000000000188000FF080000000B2FDF0002BE
-:100880000000001091D40000000000082A000001C0
-:10089000000000002C2000000000001091D4000097
-:1008A000000000082C800000000000082D0000005F
-:1008B000000000082D80011C000000188000FFA629
-:1008C000000000082C800006000000082D00000633
-:1008D0000000000030800000000000003100000037
-:1008E000000000082D8000060000000C2980000197
-:1008F0000000000C1F8000010000001091DE0000CD
-:10090000000000002ADF0000000000082A0000109C
-:100910000000000005000000000000188000FEF349
-:100920000000001091A0B009000000082C80010D0B
-:10093000000000082D0000090000001091D4000004
-:10094000000000082D800107000000188000FF9FB4
-:10095000000000188000001000000008AC0000013A
-:10096000000000188000000B000000000380B000B1
-:100970000000000B2FDF0002000000002C004000F0
-:100980000000001091D4000000000008060055553A
-:10099000000000188000FF81000000188000003176
-:1009A00000000018800000060000000B2FDF00028E
-:1009B000000000002C000E00000000082A000007C4
-:1009C0000000000805005555000000188000FEDDFD
-:1009D00000000000068200000000000C29800001D9
-:1009E0000000000C1F800001000000100CE7000751
-:1009F000000000090562FFFF00000010BA6C14053A
-:100A0000000000002ADF00000000000021000000BC
-:100A1000000000082A0000050000001091D400002A
-:100A2000000000082C80010C000000082D000008C8
-:100A30000000000C31620018000000082D80000149
-:100A4000000000188000FF7500000018000D000075
-:100A500000000010B1A0B00E0000000B2FDF00025C
-:100A60000000000003D80000000000002C2000005F
-:100A70000000001091D40000000000188000001554
-:100A8000000000102C620002000000188000000C22
-:100A90000000000B2FDF0002000000002C07000008
-:100AA0000000000C1F8000010000001091DE00001B
-:100AB000000000080500FFFF000000188000FEBFD6
-:100AC000000000082C80010D000000082D00000926
-:100AD0000000001091D40000000000082D800107E4
-:100AE000000000188000FF6C0000000C298000014D
-:100AF0000000000C1F8000010000001091DE0000CB
-:100B0000000000002ADF0000000000082A00000AA0
-:100B10000000000005000000000000188000FEB387
-:100B20000000000006820000000000082C80010C7C
-:100B3000000000082D000008000000082D8001348E
-:100B4000000000000000000000000010205F000016
-:100B5000000000082C800140000000082D00003C2F
-:100B6000000000082D80011C0000000000000000B3
-:100B70000000001091DE0000000000082C800080C2
-:100B8000000000082D000000000000082D80010575
-:100B900000000010BEE20005000000188000FE9C6E
-:100BA000000000010562140000000010918A00029C
-:100BB00000000008B16200010000001091DE00009A
-:100BC00000000018000D00000000001091D400008B
-:100BD000000000080600AAAA000000188000FF38E4
-:100BE0000000000C298000010000000C1F800001A3
-:100BF000000000082A000009000000080500AAAA59
-:100C0000000000188000FE960000001091D4000043
-:100C10000000000806005555000000188000FF3055
-:100C20000000001091A03C0200000010B1E6620735
-:100C30000000000B2FDF0002000000002C3100003C
-:100C4000000000092CB1007F000000082CD9000032
-:100C5000000000082D000000000000082D80010D9C
-:100C600000000010B1A8000600000010205F000086
-:100C7000000000002C200000000000002CA7000055
-:100C8000000000082D000010000000082D80010861
-:100C9000000000188000FF2B00000010B1A600101B
-:100CA00000000010001F00000000000F0F300007C0
-:100CB000000000000A600000000000000AE10000DF
-:100CC0000000000F4B620008000000090B1600FF37
-:100CD000000000000D620000000000090D1A00FF76
-:100CE00000000010073000030000000C0D1A00087F
-:100CF0000000000C0B1600080000000F4CE3001869
-:100D0000000000000C992C0000000004CC99340075
-:100D1000000000080F8000000000000C2980000186
-:100D2000000000003331000000000008220000161F
-:100D3000000000002ADF0000000000082A00000C6C
-:100D400000000010009F0000000000000F200000C5
-:100D50000000000C1F800001000000080500555530
-:100D6000000000188000FE6A0000001091D400000E
-:100D7000000000080600AAAA000000188000FF0476
-:100D80000000000F4722000800000009070E000FB6
-:100D900000000008070E00080000000802800001A3
-:100DA0000000000702851C00000000088285000189
-:100DB0000000000002854C000000000742851C0076
-:100DC00000000003C3AA52000000000003B10E009F
-:100DD000000000074B071C000000000F0F30000749
-:100DE0000000000F0A960003000000000A955C0056
-:100DF000000000004A005A00000000000C960A00A3
-:100E0000000000090C99FFFF000000080D00FFFF23
-:100E100000000010B1963202000000080F800005AB
-:100E200000000010B1A8000800000010205F0000C2
-:100E30000000000B2FDF0002000000002C2000004B
-:100E4000000000002CA70000000000082D0000108A
-:100E5000000000082D800108000000188000FEF24C
-:100E60000000000C2980000100000010001F00009D
-:100E70000000000C1F800001000000002ADF0000BD
-:100E8000000000082A00000D000000080500AAAAC2
-:100E9000000000188000FE440000001091D4000003
-:100EA0000000000806005555000000188000FEDE16
-:100EB0000000000C298000010000000C1F800001D0
-:100EC000000000082A000007000000080500555532
-:080ED000000000188000FE3C48
-:080ED80000000010B1800004CD
-:100EE0000000001F0303030000000008050000FFCE
-:100EF0000000001800020000000000002A000000AE
-:100F000000000010B1D400000000001091DE0000CD
-:100F1000000000102053000000000010001F00001F
-:100F20000000000C6BD70001000000002F80AA0019
-:100F30000000000C29800001000000080254000F8E
-:100F4000000000002C400000000000092952003F72
-:100F500000000018000400000000001880000010CD
-:100F60000000001880000011000000188000004AF6
-:100F700000000018800001280000001880000127F0
-:100F800000000018800001260000001880000126E3
-:100F90000000001880000000000000188000013FE1
-:100FA0000000001880000122000000188000000BE3
-:100FB0000000001880000145000000188000019A20
-:100FC000000000188000007B00000018800000F97D
-:100FD0000000001880000109000000002A00000045
-:100FE000000000188000FFE4000000002A0000005C
-:100FF0000000000C29800000000000188000FFE1C4
-:10100000000000002A000000000000188000FFDF40
-:101010000000000003820000000000188000FFDADA
-:10102000000000010C161400000000008C181400D1
-:101030000000001091980003000000080C960002C8
-:1010400000000010B1800003000000080C960001B1
-:10105000000000000C000000000000000D1900005E
-:1010600000000010205600000000000C2BD70001EB
-:10107000000000080F8000010000000000000000D8
-:1010800000000010001F00000000000C6BD70001E2
-:1010900000000010011301F100000018000700001B
-:1010A00000000000050200000000001091963421AD
-:1010B00000000010205F0000000000002C1E000057
-:1010C000000000082C800006000000082D0000062B
-:1010D000000000082D800102000000000000000058
-:1010E0000000001091DE0000000000000D61000013
-:1010F00000000018000A00000000000005020000C7
-:10110000000000109196341600000010205F0000CF
-:101110000000000009D80000000000002C1E0000A4
-:10112000000000082C80010E000000082D00000ABD
-:10113000000000082D8001020000000000000000F7
-:101140000000001091DE0000000000000D620000B1
-:10115000000000002C13000000000018000A00002E
-:101160000000000005020000000000109196340904
-:1011700000000010205F0000000000002C1E000096
-:10118000000000082C800006000000082D00006A06
-:10119000000000082D800102000000000000000097
-:1011A0000000001091DE0000000000000D7A000039
-:1011B00000000018000A0000000000002A000000E3
-:1011C000000000000D61000000000000036200004C
-:1011D00000000010234200DB0000000002638C00CE
-:1011E0000000000026460000000000080204001273
-:1011F00000000010B906082E000000000F58000083
-:10120000000000000A640000000000000AE5000081
-:10121000000000090B66FFFF000000000C0000004A
-:10122000000000000B800000000000080CC6001247
-:10123000000000188000FFCE0000001020560000C3
-:101240000000000C2BD70001000000080F800003F5
-:10125000000000000000000000000010001F00005F
-:101260000000000C6BD700010000000827110012DD
-:10127000000000006690000000000008A31B0012A0
-:1012800000000010B198000600000010001F0000D0
-:101290000000000C6BD70001000000102056000079
-:1012A0000000000C2BD70001000000080F80000494
-:1012B0000000000822000003000000082C80000C41
-:1012C000000000082D00000C00000010001F0000AE
-:1012D0000000000C6BD70001000000002596000004
-:1012E0000000000C298000000000000006660000DD
-:1012F0000000000086611800000000090260000F75
-:101300000000000F0204000200000010B60C0805E7
-:101310000000000C1FBF0000000000102866000342
-:1013200000000008078F00010000000C3366001069
-:1013300000000000321400000000000032950000A0
-:101340000000000573662C000000000031E32E0051
-:10135000000000082D800010000000188000FF75BC
-:1013600000000000230000000000000925E6FFFF48
-:10137000000000082200000B0000000C6952000071
-:101380000000000C29800000000000102866008882
-:10139000000000188000FF6E000000002A0000001E
-:1013A000000000082C800040000000082D000020F4
-:1013B000000000082D80011C00000000000000005B
-:1013C0000000001091DE00000000000F42EA001053
-:1013D00000000010004F000400000010B74692000B
-:1013E000000000080249001200000010B5840A0045
-:1013F000000000000D61000000000010BA66346AB1
-:10140000000000088305001200000010004F0002D9
-:1014100000000000034900000000000183068C006A
-:101420000000000083C60C0000000010B18700110E
-:10143000000000000B6E000000000010BEE9000577
-:10144000000000188000FF5500000001056914002D
-:1014500000000010918A000200000008B4E90001B9
-:1014600000000010B1E92C5D0000000086692C002E
-:1014700000000000020000000000000902EAFFFF77
-:1014800000000010000C00020000000002040A002E
-:101490000000000F460C00010000000F0285000153
-:1014A00000000010918C01FC00000010B7040E54E5
-:1014B000000000000F400000000000000D6100006F
-:1014C000000000000A640000000000000AE50000BF
-:1014D000000000090B66FFFF000000000C00000088
-:1014E000000000000B800000000000080C860012C5
-:1014F00000000010205600000000000C2BD7000157
-:10150000000000080F8000030000000C29520000BA
-:1015100000000010001F00000000000C6BD700014D
-:101520000000000827110012000000006690000073
-:101530000000000026460000000000002306000016
-:1015400000000010B198000900000010001F00000A
-:101550000000000C6BD700010000001020560000B6
-:101560000000000C2BD70001000000080F800004D1
-:10157000000000000000000000000010001F00003C
-:101580000000000C6BD700010000000032140000C6
-:1015900000000000329500000000000031E32E0042
-:1015A0000000000573662C00000000002596000076
-:1015B00000000010B18700210000000C298000000D
-:1015C0000000000F0F6B0007000000000D69000015
-:1015D000000000000A6C0000000000000AED00009E
-:1015E000000000000B6E0000000000000B800000F7
-:1015F000000000000C870000000000188000FF1EA3
-:10160000000000010C161400000000008C181400EB
-:10161000000000080C9600010000001091980002E4
-:10162000000000080C990001000000000D190000E6
-:10163000000000000C000000000000102056000018
-:101640000000000C2BD70001000000080F800001F3
-:1016500000000010205300000000000C695200013F
-:1016600000000010001F00000000000C6BD70001FC
-:101670000000000022C58C000000000023120000C2
-:10168000000000002711000000000000269000006C
-:1016900000000010B8170E030000000C29800000A5
-:1016A000000000188000FFEB0000000082970E0091
-:1016B00000000000A3120A00000000082200001A27
-:1016C000000000082C80000C000000082D00000C19
-:1016D000000000082D80001000000010001F000016
-:1016E0000000000C6BD70001000000000D6E000030
-:1016F00000000003E7CF34000000000C2980000048
-:101700000000001091DE000000000010B18700070B
-:1017100000000000361400000000000036950000B4
-:101720000000000037160000000000082C80005068
-:10173000000000082D000030000000082D80000C83
-:10174000000000188000FEF800000000264600009F
-:1017500000000000230000000000000925E6FFFF54
-:10176000000000000B6E000000000003E7CF2C001B
-:10177000000000082200001B0000000C695200005D
-:101780000000000C29800000000000188000FEEF1F
-:10179000000000002A00000000000010086600059C
-:1017A00000000000066600000000000086611800CE
-:1017B00000000009026000F000000010B60C0802F2
-:1017C000000000188000FEE8000000000682000013
-:1017D00000000010B18F000000000008878F00019A
-:1017E0000000000C73660010000000082C80001838
-:1017F000000000082D000018000000082D800002E5
-:101800000000000C5FBF00000000001091DE00002F
-:1018100000000018000D0000000000002A00000079
-:1018200000000010286601F5000000082C8000036D
-:10183000000000082D000003000000093060FFF0E8
-:10184000000000082D8000010000000C298000002D
-:101850000000001091DE0000000000082C80001A3B
-:10186000000000082D00001A00000005736600004B
-:10187000000000082D800002000000003180000000
-:101880000000001091DE0000000000082C80000C19
-:10189000000000082D00000C000000082D8000044E
-:1018A000000000188000FECC0000001800020000BC
-:1018B000000000188000FECA000000002A0000009E
-:1018C00000000010001F00000000000C6BD700019A
-:1018D000000000000F008000000000080F800007DB
-:1018E000000000188000001B00000000280A000013
-:1018F00000000000050200000000000822000009AE
-:1019000000000000290000000000000F65680010C2
-:1019100000000003F66C940000000010B972A004EF
-:101920000000000C73E700190000000C21420004C5
-:10193000000000003CF800000000000C29800000BE
-:1019400000000010205300000000000822000008E2
-:101950000000000C6142000400000018000A0000B2
-:1019600000000000050200000000000C61420000C1
-:1019700000000010014200030000000C33E7001DCE
-:101980000000000C6142000200000018000A000084
-:10199000000000002A00000000000010001F0000EE
-:1019A0000000000C6BD700010000000F0F4700077C
-:1019B000000000080F8000080000000C29800000D3
-:1019C00000000010001F00000000000C6BD7000199
-:1019D000000000188000FEA6000000003351000047
-:1019E000000000002A00000000000010B1C600291D
-:1019F0000000000F0F500007000000000A60000008
-:101A0000000000000AE100000000000F4B62000827
-:101A1000000000090B1600FF0000000F4C620010D0
-:101A2000000000000D620000000000090D1A00FF18
-:101A300000000010075000030000000C0D1A000801
-:101A40000000000C0B160008000000000CC600008F
-:101A5000000000000B80000000000000069800005D
-:101A600000000010205600000000000C2BD70001E1
-:101A7000000000080F8000030000001006C20004F0
-:101A80000000000C290000020000001026420002A5
-:101A90000000000C29520003000000082200000191
-:101AA00000000010001F00000000000C6BD70001B8
-:101AB00000000000231B00000000000027111A0096
-:101AC00000000000669000000000000C2952000099
-:101AD00000000010B197320C0000000C29800000BB
-:101AE00000000000069800000000001020530000D5
-:101AF0000000000C295200030000000022C58C00E9
-:101B000000000010001F00000000000C6BD7000157
-:101B100000000010205600000000000C2BD7000130
-:101B2000000000080F800003000000188000FFEF95
-:101B300000000010B1C8001300000010B1C600037F
-:101B40000000000C2980000000000010205300005D
-:101B50000000000C295200000000000C2952000374
-:101B60000000001006C200020000000C2952000212
-:101B70000000000022C58C00000000002765000066
-:101B80000000000026E4000000000008220000160B
-:101B900000000010B1C60003000000002348000050
-:101BA00000000010B1800005000000002348000084
-:101BB0000000000C298000000000000F0F500007FB
-:101BC000000000188000001200000008220000162B
-:101BD0000000000C2980000000000000301400000C
-:101BE00000000000309500000000001007500003C6
-:101BF000000000090B1600FF000000090D1A00FF8D
-:101C00000000000F311600080000000031623400AF
-:101C100000000003F162300000000010205F0000AF
-:101C2000000000002C510000000000092CD1007FB2
-:101C3000000000082CD90000000000082D00000062
-:101C4000000000082D80000C0000000000000000D3
-:101C50000000001091DE00000000001005C2000529
-:101C6000000000080F8000070000000033000000A3
-:101C700000000010001F00000000000C6BD70001E6
-:101C8000000000188000FE50000000002A00000044
-:101C90000000000F0F50000700000010B1C6003018
-:101CA0000000000F4742000800000009070E000F67
-:101CB00000000008070E000800000010001F0000D0
-:101CC0000000000C6BD700010000000809000001B3
-:101CD0000000000709121C0000000003CBCA92009C
-:101CE000000000000B97A2000000000742171C0034
-:101CF000000000000B0400000000000F0A84000335
-:101D0000000000000A959C00000000004A009A00B4
-:101D10000000000882120001000000010C170800FA
-:101D2000000000000C978C0000000000021800006A
-:101D3000000000080D00FFFF000000080F800006F3
-:101D40000000000C290000000000001006C2000482
-:101D50000000000C29520002000000102642000280
-:101D60000000000C295200030000000822000001BE
-:101D700000000010001F00000000000C6BD70001E5
-:101D800000000010B197320D00000000231B00007E
-:101D9000000000002711080000000000669000000D
-:101DA0000000000C29800000000000000218000064
-:101DB00000000010205300000000000C2952000316
-:101DC0000000000022C5360000000010001F0000C7
-:101DD0000000000C6BD70001000000080F80000617
-:101DE000000000188000FFF200000000231B00002C
-:101DF00000000000271108000000000066900000AD
-:101E000000000010B1C8000B0000000C2980000089
-:101E100000000010205300000000000C29520000B8
-:101E20000000000C295200030000001006C200024E
-:101E30000000000C295200020000000022C58C00A6
-:101E400000000000276500000000000026E40000FC
-:101E500000000000234800000000000822000017D6
-:101E60000000000C2980000000000010001F00008E
-:101E70000000000C6BD70001000000188000FE116C
-:00000001FF
-/*
- * This file contains firmware data derived from proprietary unpublished
- * source code, Copyright (c) 2004 - 2009 Broadcom Corporation.
- *
- * Permission is hereby granted for the distribution of this firmware data
- * in hexadecimal or equivalent format, provided this copyright notice is
- * accompanying it.
- */
diff --git a/firmware/bnx2/bnx2-rv2p-09ax-6.0.17.fw.ihex b/firmware/bnx2/bnx2-rv2p-09ax-6.0.17.fw.ihex
new file mode 100644
index 000000000000..d2f275788f16
--- /dev/null
+++ b/firmware/bnx2/bnx2-rv2p-09ax-6.0.17.fw.ihex
@@ -0,0 +1,425 @@
+:100000000000000000000970000000580000000916
+:1000100000000000000000000000000000000000E0
+:1000200000000000000000000000000000000000D0
+:1000300000001010000009C80000000500000000CA
+:1000400000000000000000000000000000000000B0
+:080050000000000000000000A8
+:0800580000000010B180000659
+:100060000000001F03060011000000080500FFFF4C
+:10007000000000180002000000000008050000FF5A
+:10008000000000180002000000000008AC000001A1
+:1000900000000008078000000000000C2F80000115
+:1000A000000000002B000000000000002B8000007A
+:1000B0000000001091E1000200000008AC00000107
+:1000C00000000010203F003B00000010213F000313
+:1000D0000000001020BF0015000000188000FFFD88
+:1000E0000000000C1F800002000000188000FFF9D3
+:1000F00000000008B1000001000000082C80010C85
+:10010000000000082D000008000000082D800001FC
+:10011000000000188000004F0000000B2FDF0002DD
+:100120000000000C1F800002000000002C070000EF
+:100130000000001091DE0000000000188000FFEFBA
+:100140000000000B2FDF00020000000C1F800000E9
+:10015000000000002C0700000000001091DE0000ED
+:10016000000000188000FFEA0000000C1F80000261
+:10017000000000188000FFE80000000802240025AD
+:1001800000000018000400000000001880000000BB
+:10019000000000188000001B0000001880000055BF
+:1001A000000000188000000000000018800000001F
+:1001B000000000188000000000000018800000000F
+:1001C00000000018800000000000001880000000FF
+:1001D00000000018800000000000001880000000EF
+:1001E00000000018800000000000001880000000DF
+:1001F000000000188000009D000000188000000032
+:1002000000000018800000000000001880000000BE
+:1002100000000018800000000000001880000000AE
+:10022000000000188000000000000018800000009E
+:10023000000000188000009C00000018800000C62C
+:10024000000000188000009300000018800000E902
+:10025000000000188000003E000000188000000030
+:10026000000000188000007A0000001091D4000007
+:100270000000000C298000010000000C1F8000011C
+:10028000000000082A0000020000000807800000AB
+:10029000000000188000FFC4000000080380010077
+:1002A00000000010B73C0E000000001880000000A5
+:1002B000000000000202000000000000029A00009E
+:1002C00000000000060C2C0000000004C60C3400E6
+:1002D00000000010001F000000000010BA8C2C0C61
+:1002E000000000080696000400000009068DFFFCCF
+:1002F00000000004CD051A0000000004CC9A18008C
+:100300000000001020D700000000000C2B56000059
+:1003100000000000000000000000000000000000DD
+:100320000000001020D70000000000080F8000012E
+:1003300000000010B18001F400000010001F000058
+:100340000000000C6B5600000000001800040000C4
+:10035000000000000682000000000010B18F0004C1
+:1003600000000010B18F1403000000082A000001F3
+:100370000000001091D4000000000000078014006D
+:1003800000000018000D0000000000000502000041
+:100390000000001091DE000000000018000A0000BC
+:1003A00000000000068200000000001091DE000046
+:1003B000000000090561FFFF00000010918A0002A3
+:1003C0000000000830E1FFFF000000188000FF96E9
+:1003D000000000010561140000000010918A000275
+:1003E00000000008B0E1000100000018000D00004E
+:1003F00000000000068200000000001091DE0000F6
+:10040000000000090562FFFF00000010918A000251
+:10041000000000083162FFFF000000188000FF8C20
+:10042000000000010562140000000010918A000223
+:1004300000000008B162000100000018000D00007B
+:1004400000000010B1A0B0130000000B2FDF00026D
+:10045000000000002C200000000000082C8000009C
+:10046000000000082D0000000000001091D40000E2
+:100470000000000805000055000000188000FFDBA8
+:10048000000000082D80011C00000010001F00006B
+:10049000000000188000FFE20000000F4760000825
+:1004A0000000000F060E0001000000000F580000C1
+:1004B000000000000A640000000000000AE50000DF
+:1004C000000000090B66FFFF000000000D61000046
+:1004D00000000018800000150000000F47600008B1
+:1004E0000000000B2FDF0002000000082C8000003D
+:1004F000000000082D0000000000001091D4000052
+:10050000000000082D80011C0000000F060E0001F5
+:1005100000000010001F0000000000000F58000045
+:10052000000000188000FFD0000000000A640000F6
+:10053000000000000AE50000000000090B66FFFF54
+:10054000000000000D6100000000000002620000D9
+:100550000000000002E000000000000B2FDF00029E
+:100560000000000030050000000000003104000021
+:1005700000000000309A0000000000100060000A37
+:10058000000000080516000100000010BA9A1403CC
+:1005900000000000030000000000001880000006BA
+:1005A000000000188000FF5900000010B606140477
+:1005B0000000000803060001000000082A000001F6
+:1005C000000000188000FF5E000000188000FF9D02
+:1005D0000000000C298000010000000C29520001DD
+:1005E0000000000C295200000000000822800002D8
+:1005F000000000080200000E000000080280001A3F
+:1006000000000010B1C40A0200000008020000034C
+:100610000000000C1F800001000000002ADF000025
+:10062000000000002A000800000000188000FF51B0
+:100630000000000B2FDF00020000001091D400002A
+:10064000000000082A000001000000002C2000002B
+:100650000000001091D40000000000082C80000071
+:10066000000000082D000000000000082D80011C83
+:10067000000000188000FFA3000000082C80000686
+:10068000000000082D00000600000000308000007F
+:100690000000000031000000000000082D8000066E
+:1006A0000000000C298000010000000C1F800001E8
+:1006B0000000001091DE0000000000002ADF0000B2
+:1006C000000000082A000010000000080780000059
+:1006D000000000188000FF3C0000001091D40000D2
+:1006E00000000008050000AA000000188000FF8D2F
+:1006F0000000000C298000010000000C1F80000198
+:10070000000000082A000009000000188000FF35E2
+:100710000000001091D40000000000080500005502
+:10072000000000188000FF860000001091A0B002B9
+:1007300000000010B1E662070000000B2FDF00028E
+:10074000000000002C310000000000092CB1007FE7
+:10075000000000082CD90000000000082D00000057
+:10076000000000082D80010D00000010B1A8000657
+:1007700000000010205F0000000000002C2000009E
+:10078000000000002CA70000000000082D00001051
+:10079000000000082D800108000000188000FF7E86
+:1007A00000000010B1A6001000000010001F0000A3
+:1007B0000000000F0F300007000000000A6000007A
+:1007C000000000000AE100000000000F4B6200087A
+:1007D000000000090B1600FF000000000D62000081
+:1007E000000000090D1A00FF000000100730000390
+:1007F0000000000C0D1A00080000000C0B16000889
+:100800000000000F4CE30018000000000C992C00C1
+:1008100000000004CC993400000000080F800000A4
+:100820000000000C298000010000000033310000AE
+:100830000000000822000016000000002ADF00006F
+:10084000000000082A00000C00000010009F0000BB
+:10085000000000002C2000000000000C1F800001A0
+:10086000000000188000FF0A0000001091D4000072
+:1008700000000008050000AA000000188000FF5BCF
+:100880000000000F4722000800000009070E000FBB
+:1008900000000008070E00080000000802800001A8
+:1008A0000000000702851C0000000008828500018E
+:1008B0000000000002854C000000000742851C007B
+:1008C00000000003C3AA52000000000003B10E00A4
+:1008D000000000074B071C000000000F0F3000074E
+:1008E0000000000F0A960003000000000A955C005B
+:1008F000000000004A005A00000000000C960A00A8
+:10090000000000090C99FFFF000000080D00FFFF28
+:1009100000000010BA992C02000000080F800005AA
+:1009200000000010B1A8000800000010205F0000C7
+:100930000000000B2FDF0002000000002C20000050
+:10094000000000002CA70000000000082D0000108F
+:10095000000000082D800108000000188000FF46FC
+:100960000000000C2980000100000010001F0000A2
+:100970000000000C1F800001000000002ADF0000C2
+:10098000000000082A00000D000000188000FEE5AD
+:100990000000001091D40000000000080500005580
+:1009A000000000188000FF360000000C29800001C4
+:1009B0000000000C1F800001000000082A00000752
+:0809C000000000188000FEDEBB
+:0809C80000000010B1800004E2
+:1009D0000000001F0306001100000008050000FFD2
+:1009E0000000001800020000000000002A000000C3
+:1009F00000000010B1D400000000001091DE0000E3
+:100A0000000000102053000000000010001F000034
+:100A10000000000C6BD70001000000002F80AA002E
+:100A20000000000C298000010000000802540010A2
+:100A3000000000002C400000000000000F400000FB
+:100A4000000000092952003F0000001800040000C7
+:100A50000000001880000011000000188000001243
+:100A600000000018800000470000001880000137D7
+:100A700000000018800001360000001880000135D9
+:100A80000000001880000135000000188000000000
+:100A9000000000188000014F0000001880000131A4
+:100AA00000000018800000000000001880000155C0
+:100AB00000000018800001A6000000188000006DF2
+:100AC00000000018800000E400000018800000E52D
+:100AD000000000188000012A000000002A00000029
+:100AE000000000188000FFE2000000002A00000063
+:100AF0000000000C29800000000000188000FFDFCB
+:100B00000000000003820000000000188000FFDAEF
+:100B1000000000010C161400000000008C181400E6
+:100B20000000001091980003000000080C960002DD
+:100B300000000010B1800003000000080C960001C6
+:100B4000000000000C000000000000000D19000073
+:100B5000000000080F8000010000000000000000FD
+:100B600000000010001F00000000000C6BD7000107
+:100B700000000010011301F300000018000700003E
+:100B8000000000000502000000000010B99A2C21AE
+:100B900000000010205F0000000000002C1E00007C
+:100BA000000000082C800006000000082D00000650
+:100BB000000000082D80010200000000000000007D
+:100BC0000000001091DE0000000000000D61000038
+:100BD00000000018000A00000000000005020000EC
+:100BE00000000010B99A2C1600000010205F0000D1
+:100BF0000000000009D80000000000002C1E0000CA
+:100C0000000000082C80010E000000082D00000AE2
+:100C1000000000082D80010200000000000000001C
+:100C20000000001091DE0000000000000D620000D6
+:100C3000000000002C13000000000018000A000053
+:100C4000000000000502000000000010B99A2C0905
+:100C500000000010205F0000000000002C1E0000BB
+:100C6000000000082C800006000000082D00006A2B
+:100C7000000000082D8001020000000000000000BC
+:100C80000000001091DE0000000000000D7A00005E
+:100C900000000018000A0000000000002A00000008
+:100CA0000000000822000001000000000D610000AB
+:100CB0000000001021C2002800000010B1C6000290
+:100CC00000000010234200B3000000090B66FFFF84
+:100CD00000000010BA9A2C24000000000A640000F2
+:100CE000000000000AE50000000000000C00000009
+:100CF000000000000B800000000000080CC600127D
+:100D0000000000188000FFD0000000080F800003E2
+:100D1000000000000000000000000010001F0000A4
+:100D20000000000C6BD70001000000082711001222
+:100D3000000000006690000000000010B198000460
+:100D400000000010001F00000000000C6BD7000125
+:100D5000000000080F8000040000000822000003CB
+:100D6000000000082C80000C000000082D00000C82
+:100D700000000010001F00000000000C6BD70001F5
+:100D80000000001091C6000600000010001F0000C7
+:100D90000000000C6BD7000100000010BA9A2C0371
+:100DA000000000080F800004000000188000FFFC15
+:100DB00000000000259600000000000C29800000C3
+:100DC0000000000032140000000000003295000016
+:100DD0000000000573662C000000000031E32E00C7
+:100DE000000000082D800010000000188000FF8126
+:100DF00000000000230000000000000925E6FFFFBE
+:100E0000000000082200000B0000000C69520000E6
+:100E10000000000C29800000000000188000FF7B0B
+:100E2000000000002A000000000000082C800040A4
+:100E3000000000082D000020000000082D80011C8B
+:100E400000000008220000010000001091DE0000F8
+:100E50000000000F42EA001000000010004F0004E4
+:100E600000000010B746920000000008024900127E
+:100E700000000010B5840A00000000000D610000B1
+:100E800000000010BA6634640000000883050012F8
+:100E900000000010004F00020000000003490000A5
+:100EA0000000000183068C000000000083C60C00D7
+:100EB00000000010B1870013000000000B6E00005E
+:100EC000000000090569FFFF00000010918A000280
+:100ED0000000000834E9FFFF000000188000FF60F8
+:100EE000000000010569140000000010918A000252
+:100EF00000000008B4E9000100000010BAE92C5518
+:100F00000000000086692C000000000002000000C4
+:100F10000000000902EAFFFF00000010000C0002C0
+:100F20000000000002040A000000000F460C00014F
+:100F30000000000F0285000100000010918C01FCF0
+:100F400000000010B7040E4C000000000D6100000E
+:100F5000000000000A640000000000000AE5000034
+:100F6000000000090B66FFFF000000000C000000FD
+:100F7000000000000B800000000000080C8600123A
+:100F8000000000080F8000030000000C2952000040
+:100F900000000010001F00000000000C6BD70001D3
+:100FA00000000008271100120000000066900000F9
+:100FB000000000002306000000000010B1980007A8
+:100FC00000000010001F00000000000C6BD70001A3
+:100FD000000000080F800004000000000000000076
+:100FE00000000010001F00000000000C6BD7000183
+:100FF00000000000321400000000000032950000E4
+:101000000000000031E32E000000000573662C0094
+:10101000000000002596000000000010B187001FAE
+:101020000000000C298000000000000F0F6B00077B
+:10103000000000000D690000000000000A6C0000C4
+:10104000000000000AED0000000000000B6E000030
+:10105000000000000B800000000000000C87000072
+:10106000000000188000FF2F000000010C16140083
+:10107000000000008C181400000000080C9600010D
+:101080000000001091980002000000080C99000177
+:10109000000000000D190000000000000C0000001E
+:1010A000000000080F800001000000102053000025
+:1010B0000000000C6952000100000010001F000039
+:1010C0000000000C6BD700010000000022C58C005E
+:1010D00000000000231200000000000027110000A3
+:1010E000000000002690000000000010B8170E035A
+:1010F0000000000C29800000000000188000FFEDB7
+:101100000000000082970E0000000000A3120A00F9
+:10111000000000082200001A000000082C80000CCB
+:10112000000000082D00000C000000082D800010B9
+:1011300000000010001F00000000000C6BD7000131
+:10114000000000000D6E000000000003E7CF340037
+:101150000000000C298000000000001091DE00005B
+:1011600000000010B18700070000000036140000E6
+:101170000000000036950000000000003716000057
+:10118000000000082C800050000000082D000030F6
+:10119000000000082D80000C000000188000FF0BEC
+:1011A00000000000230000000000000925E6FFFF0A
+:1011B000000000000B6E000000000003E7CF2C00D1
+:1011C000000000082200001B0000000C6952000013
+:1011D0000000000C29800000000000188000FF03C0
+:1011E000000000002A000000000000188000FF013D
+:1011F000000000002A0000000000000C2980000010
+:101200000000001091DE0000000000082C80001A91
+:10121000000000082D00001A0000000573660000A1
+:10122000000000082D800002000000003180000056
+:101230000000001091DE0000000000082C80000C6F
+:10124000000000082D00000C000000082D800004A4
+:10125000000000188000FEF400000008066600018F
+:1012600000000010BA9A1972000000000A64000021
+:10127000000000000AE50000000000090B66FFFF07
+:10128000000000000C000000000000000B800000C7
+:10129000000000080CC60012000000188000FF1DAE
+:1012A000000000080F8000030000000000000000A4
+:1012B00000000010001F00000000000C6BD70001B0
+:1012C00000000008271100120000000066900000D6
+:1012D00000000010919B32000000001002930000FB
+:1012E00000000010B198000300000010001F000073
+:1012F0000000000C6BD70001000000080F80000404
+:101300000000000C2980000000000010001F0000F9
+:101310000000000C6BD7000100000010BA9A2C00EE
+:101320000000000031E32E00000000000B800000F0
+:10133000000000008CCC8C0000000010B5CC8C02AA
+:10134000000000080C800001000000188000FF076A
+:10135000000000080F800003000000102053000070
+:101360000000000C695200010000000022C58C0042
+:1013700000000010001F00000000000C6BD70001EF
+:10138000000000002711000000000000269000006F
+:1013900000000000231B000000000010B1980003B3
+:1013A00000000010001F00000000000C6BD70001BF
+:1013B000000000080F800004000000082200000365
+:1013C000000000082C80000C000000082D00000C1C
+:1013D00000000010001F00000000000C6BD700018F
+:1013E00000000000259600000000000C298000008D
+:1013F00000000000321400000000000032950000E0
+:101400000000000573662C000000000031E32E0090
+:10141000000000082D800010000000188000FEBBB6
+:10142000000000188000FEBA000000002A00000042
+:1014300000000010001F00000000000C6BD700012E
+:10144000000000000F008000000000080F8000076F
+:10145000000000188000001C00000000280A0000A6
+:101460000000000005020000000000082200000942
+:1014700000000000290000000000000F6568001057
+:1014800000000000248A000000000003F66C9400B5
+:1014900000000010B972A0040000000C73E70019EE
+:1014A0000000000C21420004000000003CF8000095
+:1014B0000000000C298000000000001020530000F4
+:1014C00000000008220000080000000C6142000437
+:1014D00000000018000A00000000000005020000E3
+:1014E0000000000C614200000000001001420003F7
+:1014F0000000000C33E7001D0000000C61420002F8
+:1015000000000018000A0000000000002A0000008F
+:1015100000000010001F00000000000C6BD700014D
+:101520000000000F0F470007000000080F800008B0
+:101530000000000C2980000000000010001F0000C7
+:101540000000000C6BD70001000000188000FE9521
+:101550000000000033510000000000002A000000DD
+:1015600000000010B1C600250000000F0F5000075A
+:10157000000000000A600000000000000AE1000016
+:101580000000000F4B620008000000090B1600FF6E
+:101590000000000F4C620010000000000D6200000F
+:1015A000000000090D1A00FF0000001007500003A2
+:1015B0000000000C0D1A00080000000C0B160008BB
+:1015C000000000000CC60000000000000B800000BE
+:1015D0000000000006980000000000080F800003D3
+:1015E0000000001006C200040000000C29000002E8
+:1015F00000000010264200020000000C29520003E7
+:10160000000000082200000100000010001F000080
+:101610000000000C6BD7000100000000231B00003D
+:101620000000000027111A00000000006690000072
+:101630000000000C2952000000000010B197320A8F
+:101640000000000C29800000000000000698000047
+:1016500000000010205300000000000C295200037D
+:101660000000000022C58C0000000010001F0000D8
+:101670000000000C6BD70001000000080F80000381
+:10168000000000188000FFF100000010B1C8001336
+:1016900000000010B1C600030000000C298000000B
+:1016A00000000010205300000000000C2952000030
+:1016B0000000000C295200030000001006C20002C6
+:1016C0000000000C295200020000000022C58C001E
+:1016D00000000000276500000000000026E4000074
+:1016E000000000082200001600000010B1C6000330
+:1016F000000000002348000000000010B180000539
+:1017000000000000234800000000000C29800000B9
+:101710000000000F0F5000070000001880000012AA
+:1017200000000008220000160000000C29800000C4
+:1017300000000000301400000000000030950000A0
+:101740000000001007500003000000090B1600FF06
+:10175000000000090D1A00FF0000000F31160008FC
+:10176000000000003162340000000003F16230002C
+:1017700000000010205F0000000000002C5100005D
+:10178000000000092CD1007F000000082CD90000C7
+:10179000000000082D000000000000082D80000C53
+:1017A00000000000000000000000001091DE0000BA
+:1017B0000000001005C20005000000080F800007AF
+:1017C000000000003300000000000010001F0000B7
+:1017D0000000000C6BD70001000000188000FE43E1
+:1017E000000000002A0000000000000F0F5000075A
+:1017F00000000010B1C600300000000F4742000892
+:1018000000000009070E000F00000008070E000886
+:1018100000000010001F00000000000C6BD700014A
+:1018200000000008090000010000000709121C0068
+:1018300000000003CBCA9200000000000B97A2003A
+:101840000000000742171C00000000000B0400000D
+:101850000000000F0A840003000000000A959C00AD
+:10186000000000004A009A000000000882120001F7
+:10187000000000010C170800000000000C978C000D
+:101880000000000002180000000000080D00FFFF2B
+:10189000000000080F8000060000000C2900000076
+:1018A0000000001006C200040000000C29520002D3
+:1018B00000000010264200020000000C2952000324
+:1018C000000000082200000100000010001F0000BE
+:1018D0000000000C6BD7000100000010B197320D22
+:1018E00000000000231B000000000000271108007A
+:1018F00000000000669000000000000C298000003D
+:10190000000000000218000000000010205300003A
+:101910000000000C295200030000000022C5360020
+:1019200000000010001F00000000000C6BD7000139
+:10193000000000080F800006000000188000FFF281
+:1019400000000000231B0000000000002711080019
+:10195000000000006690000000000010B1C8000BFD
+:101960000000000C2980000000000010205300003F
+:101970000000000C295200000000000C2952000356
+:101980000000001006C200020000000C29520002F4
+:101990000000000022C58C00000000002765000048
+:1019A0000000000026E400000000000023480000C2
+:1019B00000000008220000170000000C2980000031
+:1019C00000000010001F00000000000C6BD7000199
+:0819D000000000188000FE0475
+:00000001FF
+/*
+ * This file contains firmware data derived from proprietary unpublished
+ * source code, Copyright (c) 2004 - 2009 Broadcom Corporation.
+ *
+ * Permission is hereby granted for the distribution of this firmware data
+ * in hexadecimal or equivalent format, provided this copyright notice is
+ * accompanying it.
+ */
diff --git a/firmware/bnx2x-e1-5.2.13.0.fw.ihex b/firmware/bnx2x-e1-5.2.13.0.fw.ihex
deleted file mode 100644
index 651f4346d89e..000000000000
--- a/firmware/bnx2x-e1-5.2.13.0.fw.ihex
+++ /dev/null
@@ -1,10191 +0,0 @@
-:10000000000028B0000000600000068800002918E9
-:100010000000161400002FA800000098000045C042
-:10002000000073C400004660000000CC0000BA2845
-:1000300000009A700000BAF80000009400015570AA
-:10004000000057BC00015608000000B80001ADC810
-:100050000000CE200001AE880000000400027CB049
-:10006000020400480000000F020400540000004594
-:1000700002040058000000840204005C0000000636
-:100080000204007000000004020400780000000078
-:100090000204007C121700000204008022170000F6
-:1000A00002040084321700000604008800000005E6
-:1000B0000204009C12150000020400A0221500009A
-:1000C000020400A432150000060400A80000000489
-:1000D000020400B802100000020400BC001000007E
-:1000E000020400C010100000020400C42010000030
-:1000F000020400C830100000060400CC0000000418
-:10010000020400DC00100000020400E012140000F1
-:10011000020400E422140000020400E8321400008B
-:10012000060400EC000000040104012400000000AB
-:1001300001040128000000000104012C000000005F
-:10014000010401300000000002040004000000FF70
-:1001500002040008000000FF0204000C000000FF81
-:1001600002040010000000FF02040014000000FF61
-:1001700002040018000000FF0204001C000000FF41
-:1001800002040020000000FF020400240000003EE2
-:1001900002040028000000000204002C0000003FC0
-:1001A000020400300000003F020400340000003F61
-:1001B00002040038000000000204003C0000003F80
-:1001C000020400400000003F020400440000003F21
-:1001D00002042008000004110204200C00000400A6
-:1001E000020420100000040402042014000004197A
-:1001F0000204201C0000FFFF020420200000FFFF7B
-:10020000020420240000FFFF020420280000FFFF5A
-:1002100006042038000000020204204000000034E0
-:100220000204204400000035060420480000007C41
-:100230000204223807FFFFFF0204223C0000003FB7
-:100240000204224007FFFFFF020422440000000FC7
-:1002500001042248000000000104224C00000000BC
-:10026000010422500000000001042254000000009C
-:1002700001042258000000000104225C000000007C
-:10028000010422600000000001042264000000005C
-:1002900001042268000000000104226C000000003C
-:1002A000010422700000000001042274000000001C
-:1002B00001042278000000000104227C00000000FC
-:1002C000020424BC000000010C042000000003E82C
-:1002D0000A042000000000010B0420000000000AB6
-:1002E0000205004400000020020500480000003222
-:1002F000020500900215002002050094021500205E
-:1003000002050098000000300205009C0810000063
-:10031000020500A000000033020500A40000003028
-:10032000020500A800000031020500AC0000000238
-:10033000020500B000000005020500B40000000640
-:10034000020500B800000002020500BC0000000227
-:10035000020500C000000000020500C40000000506
-:10036000020500C800000002020500CC00000002E7
-:10037000020500D000000002020500D400000001C8
-:1003800002050114000000010205011C000000012B
-:100390000205012000000002020502040000000125
-:1003A0000205020C0000004002050210000000409F
-:1003B0000205021C000000200205022000000013BC
-:1003C0000205022400000020060502400000000A89
-:1003D0000405028000200000020500500000000714
-:1003E0000205005400000007020500580000000844
-:1003F0000205005C00000008060500600000000423
-:10040000020500D800000006020500E00000000D13
-:10041000020500E40000002D020500E800000007CE
-:10042000020500EC00000027020500F000000007B4
-:10043000020500F400000027020500F80000000794
-:10044000020500FC00000027020500040000000176
-:1004500002050008000000010205000C0000000178
-:100460000205001000000001020500140000000158
-:1004700002050018000000010205001C0000000138
-:100480000205002000000001020500240000000118
-:1004900002050028000000010205002C00000001F8
-:1004A00002050030000000010205003400000001D8
-:1004B00002050038000000010205003C00000001B8
-:1004C00002050040000000010406100002000020A8
-:1004D000020600DC00000001010600D80000000058
-:1004E0000406020000030220020600DC00000000F7
-:1004F00002060068000000B802060078000001143F
-:10050000010600B800000000010600C8000000005D
-:100510000206006C000000B80206007C0000011416
-:10052000010600BC00000000010600CC0000000035
-:100530000718040000950000081807600014022343
-:10054000071C000034D40000071C800034CF0D3697
-:10055000071D00000A191A6A081D14605D7402253F
-:100560000118000000000000011800040000000055
-:1005700001180008000000000118000C0000000035
-:100580000118001000000000011800140000000015
-:1005900002180020000000010218002400000002E0
-:1005A00002180028000000030218002C00000000C0
-:1005B000021800300000000402180034000000019E
-:1005C00002180038000000000218003C0000000182
-:1005D000021800400000000402180044000000005F
-:1005E00002180048000000010218004C000000033F
-:1005F0000218005000000000021800540000000122
-:1006000002180058000000040218005C00000000FE
-:1006100002180060000000010218006400000003DE
-:1006200002180068000000000218006C00000001C1
-:10063000021800700000000402180074000000009E
-:1006400002180078000000040218007C000000037B
-:100650000618008000000002021800A400003FFFFE
-:10066000021800A8000003FF021802240000000086
-:1006700002180234000000000218024C00000000C2
-:10068000021802E4000000FF061810000000040039
-:10069000021B8BC000000001021B80000000003420
-:1006A000021B804000000018021B80800000000C2C
-:1006B000021B80C0000000200C1B83000007A1204B
-:1006C0000A1B8300000001380B1B83000000138805
-:1006D000021B83C0000001F4061A2000000000B2D3
-:1006E000061A23C800000181041A29CC0001022740
-:1006F000061A1020000000C8061A100000000002B0
-:10070000061A1E3800000002061A1E300000000201
-:10071000061A080000000002061A0808000000027D
-:10072000061A081000000004041A1FB00005022871
-:10073000041A4CB00008022D061A22C8000000203E
-:10074000061A400000000124021A4920000000009F
-:10075000061A14000000000A061A145000000006D1
-:10076000061A150000000002041A150800050235DB
-:10077000061A151C00000009061A15800000001456
-:10078000061A09C000000048061A0800000000020E
-:10079000061A08200000000E041A1FB00002023AD8
-:1007A000061A2C2800000002061A23480000002028
-:1007B000061A449000000124021A49240000000097
-:1007C000061A14280000000A061A14680000000621
-:1007D000061A154000000002041A15480005023CE4
-:1007E000061A155C00000009061A15D00000001456
-:1007F000061A0AE000000048061A08080000000275
-:10080000061A08580000000E041A1FB80002024120
-:10081000061A2C30000000020200A2800000000135
-:100820000200A294071D29110200A29800000000F6
-:100830000200A29C009C04240200A2A00000000070
-:100840000200A2A4000002090200A4FCFF000000B4
-:10085000020100B400000001020100B80000000124
-:10086000020100DC000000010201010000000001A3
-:1008700002010104000000010201007C00300000C0
-:1008800002010084000000280201008C000000002A
-:1008900002010130000000040201025C00000001BE
-:1008A000020103280000000002010554000000308E
-:1008B000020100C400000001020100CC00000001A0
-:1008C000020100F800000001020100F00000000138
-:1008D00002010080003000000201008800000028B2
-:1008E0000201009000000000020101340000000439
-:1008F000020102DC000000010201032C00000000E4
-:100900000201056400000030020100C8000000017F
-:10091000020100D000000001020100FC0000000103
-:10092000020100F400000001020C10000000002091
-:10093000020C200800000A11020C200C00000A0022
-:10094000020C201000000A04020C201C0000FFFF13
-:10095000020C20200000FFFF020C20240000FFFFFB
-:10096000020C20280000FFFF060C203800000002C7
-:10097000020C204000000034020C2044000000352E
-:10098000020C204800000020020C204C0000002136
-:10099000020C205000000022020C20540000002312
-:1009A000020C205800000024020C205C00000025EE
-:1009B000020C206000000026020C206400000027CA
-:1009C000020C206800000028020C206C00000029A6
-:1009D000020C20700000002A020C20740000002B82
-:1009E000060C207800000056020C21D00000000107
-:1009F000020C21D400000001020C21D800000001EB
-:100A0000020C21DC00000001020C21E000000001CA
-:100A1000020C21E400000001020C21E800000001AA
-:100A2000020C21EC00000001020C21F0000000018A
-:100A3000020C21F400000001060C21F80000001057
-:100A4000020C223807FFFFFF020C223C0000003F8F
-:100A5000020C224007FFFFFF020C22440000000F9F
-:100A6000010C224800000000010C224C0000000094
-:100A7000010C225000000000010C22540000000074
-:100A8000010C225800000000010C225C0000000054
-:100A9000010C226000000000010C22640000000034
-:100AA000010C226800000000010C226C0000000014
-:100AB000010C227000000000010C227400000000F4
-:100AC000010C227800000000010C227C00000000D4
-:100AD000020C24BC000000010C0C2000000003E804
-:100AE0000A0C2000000000010B0C20000000000A8E
-:100AF000020C400800000365020C400C0000035487
-:100B0000020C401000000358020C40140000037552
-:100B1000020C401C0000FFFF020C40200000FFFF01
-:100B2000020C40240000FFFF020C40280000FFFFE1
-:100B3000020C403800000046020C403C000000055A
-:100B4000060C40400000005E020C41B800000001AD
-:100B5000060C41BC0000001F020C423807FFFFFFDB
-:100B6000020C423C0000003F020C424007FFFFFF26
-:100B7000020C42440000000F010C4248000000003B
-:100B8000010C424C00000000010C4250000000002B
-:100B9000010C425400000000010C4258000000000B
-:100BA000010C425C00000000010C426000000000EB
-:100BB000010C426400000000010C426800000000CB
-:100BC000010C426C00000000010C427000000000AB
-:100BD000010C427400000000010C4278000000008B
-:100BE000010C427C00000000010C4280000000006B
-:100BF000020C44C0000000010C0C4000000003E89F
-:100C00000A0C4000000000010B0C40000000000A2C
-:100C1000020D004400000032020D008C021500207D
-:100C2000020D009002150020020D00940810000033
-:100C3000020D009800000033020D009C000000022D
-:100C4000020D00A000000000020D00A4000000053D
-:100C5000020D00A800000005060D00AC0000000217
-:100C6000020D00B400000002020D00B800000003F5
-:100C7000020D00BC00000002020D00C000000001D7
-:100C8000020D00C800000002020D00CC00000002AE
-:100C9000020D010800000001020D015C00000001CE
-:100CA000020D016400000001020D01680000000255
-:100CB000020D020400000001020D020C00000020E1
-:100CC000020D021000000040020D0214000000405E
-:100CD000020D022000000003020D02240000001893
-:100CE000060D028000000012040D030000240243E0
-:100CF000020D004C00000001020D00500000000237
-:100D0000020D005400000008020D00580000000809
-:100D1000060D005C00000004020D00C40000000489
-:100D2000020D011400000009020D01180000002945
-:100D3000020D011C0000000A020D01200000002A23
-:100D4000020D012400000007020D01280000002709
-:100D5000020D012C00000007020D013000000027E9
-:100D6000020D01340000000C020D01380000002CBF
-:100D7000020D013C0000000C020D01400000002C9F
-:100D8000020D01440000000C020D01480000002C7F
-:100D9000020D000400000001020D00080000000127
-:100DA000020D000C00000001020D00100000000107
-:100DB000020D001400000001020D001800000001E7
-:100DC000020D001C00000001020D002000000001C7
-:100DD000020D002400000001020D002800000001A7
-:100DE000020D002C00000001020D00300000000187
-:100DF000020D003400000001020D00380000000167
-:100E0000020D003C00000001020E004C0000003208
-:100E1000020E009402150020020E00980215002018
-:100E2000020E009C00000030020E00A0081000001E
-:100E3000020E00A400000033020E00A800000030E3
-:100E4000020E00AC00000031020E00B000000002F3
-:100E5000020E00B400000004020E00B80000000002
-:100E6000020E00BC00000002020E00C000000002E2
-:100E7000020E00C400000000020E00C800000002C4
-:100E8000020E00CC00000007020E00D0000000029D
-:100E9000020E00D400000002020E00D80000000183
-:100EA000020E00E400000001020E014400000001F7
-:100EB000020E014C00000001020E01500000000271
-:100EC000020E020400000001020E020C00000040AD
-:100ED000020E021000000040020E021C000000047E
-:100EE000020E022000000020020E02240000000E6C
-:100EF000020E02280000001B060E03000000001274
-:100F0000040E0280001B0267020E00540000000C59
-:100F1000020E005800000009020E005C0000000FE5
-:100F2000020E006000000010060E006400000004C5
-:100F3000020E00DC00000003020E01100000000F92
-:100F4000020E01140000002F020E01180000000E16
-:100F5000020E011C0000002E020E00040000000121
-:100F6000020E000800000001020E000C000000014B
-:100F7000020E001000000001020E0014000000012B
-:100F8000020E001800000001020E001C000000010B
-:100F9000020E002000000001020E002400000001EB
-:100FA000020E002800000001020E002C00000001CB
-:100FB000020E003000000001020E003400000001AB
-:100FC000020E003800000001020E003C000000018B
-:100FD000020E004000000001020E0044000000016B
-:100FE0000730040000C900000830076800130282BF
-:100FF00007340000334B00000734800037090CD35E
-:101000000735000030161A96083572F051A2028496
-:10101000013000000000000001300004000000006A
-:1010200001300008000000000130000C000000004A
-:10103000013000100000000001300014000000002A
-:1010400002300020000000010230002400000002F5
-:1010500002300028000000030230002C00000000D5
-:1010600002300030000000040230003400000001B3
-:1010700002300038000000000230003C0000000197
-:101080000230004000000004023000440000000074
-:1010900002300048000000010230004C0000000354
-:1010A0000230005000000000023000540000000137
-:1010B00002300058000000040230005C0000000014
-:1010C00002300060000000010230006400000003F4
-:1010D00002300068000000000230006C00000001D7
-:1010E00002300070000000040230007400000000B4
-:1010F00002300078000000040230007C0000000391
-:101100000630008000000002023000A400003FFF13
-:10111000023000A8000003FF02300224000000009B
-:1011200002300234000000000230024C00000000D7
-:10113000023002E40000FFFF06302000000008003B
-:1011400002338BC000000001023380000000001A4F
-:10115000023380400000004E023380800000001007
-:10116000023380C0000000200C3383000007A12060
-:101170000A338300000001380B338300000013881A
-:10118000023383C0000001F40C3383801DCD650061
-:101190000A3383800004C4B40B338380004C4B407B
-:1011A00006321AA0000000C206321020000000C85B
-:1011B0000632100000000002063214000000004059
-:1011C00006325098000000040632508000000005EE
-:1011D00004325094000102860632500000000020C4
-:1011E00004322830000202870233080001000000A8
-:1011F00004330C00001002890233080000000000D4
-:1012000004330C400010029906321500000000B4AF
-:1012100002321DC80000000006324000000000D865
-:10122000063217D0000000B402321DCC00000000CE
-:1012300006324360000000D807200400009200003E
-:1012400008200780001002A9072400002CD100000C
-:10125000072480002AE50B350824DC6062DA02AB43
-:101260000120000000000000012000040000000038
-:1012700001200008000000000120000C0000000018
-:1012800001200010000000000120001400000000F8
-:1012900002200020000000010220002400000002C3
-:1012A00002200028000000030220002C00000000A3
-:1012B0000220003000000004022000340000000181
-:1012C00002200038000000000220003C0000000165
-:1012D0000220004000000004022000440000000042
-:1012E00002200048000000010220004C0000000322
-:1012F0000220005000000000022000540000000105
-:1013000002200058000000040220005C00000000E1
-:1013100002200060000000010220006400000003C1
-:1013200002200068000000000220006C00000001A4
-:101330000220007000000004022000740000000081
-:1013400002200078000000040220007C000000035E
-:101350000620008000000002022000A400003FFFE1
-:10136000022000A8000003FF022002240000000069
-:1013700002200234000000000220024C00000000A5
-:10138000022002E40000FFFF062020000000080009
-:1013900002238BC000000001022380000000001027
-:1013A00002238040000000120223808000000030F1
-:1013B000022380C00000000E022383C0000001F45D
-:1013C000062250000000004206221020000000C843
-:1013D000062210000000000206222000000000C0CB
-:1013E000062225C00000024004222EC8000802ADDB
-:1013F00002230800013FFFFF04230C00001002B588
-:10140000022308000000000004230C40001002C565
-:1014100006223040000000A00622354000000010E7
-:10142000062236C000000030062240000000020004
-:10143000062235C00000002006223840000000309F
-:1014400006223000000000080222511800000000AF
-:10145000062223000000000E0622241000000030A7
-:10146000062232C0000000A00622358000000010D5
-:1014700006223780000000300622480000000200EB
-:10148000062236400000002006223900000000300D
-:1014900006223020000000080222511C000000003B
-:1014A000062223380000000E062224D0000000305F
-:1014B00002161000000000280217000800000002B9
-:1014C0000217002C000000030217003C000000047B
-:1014D0000217004400000008021700480000000244
-:1014E0000217004C0000009002170050000000900E
-:1014F00002170054008000900217005808140000E2
-:10150000021700600000008A0217006400000080DB
-:1015100002170068000000810217006C00000080C4
-:10152000021700700000000602170078000007D0C4
-:101530000217007C0000076C02170038007C1004C2
-:10154000021700040000000F0616402400000002ED
-:10155000021640700000001C021642080000000144
-:101560000216421000000001021642200000000195
-:10157000021642280000000102164230000000015D
-:10158000021642380000000102164260000000010D
-:101590000C16401C0003D0900A16401C0000009C52
-:1015A0000B16401C000009C4021640300000000861
-:1015B000021640340000000C0216403800000010F3
-:1015C0000216404400000020021640000000000106
-:1015D000021640D800000001021640080000000179
-:1015E0000216400C0000000102164010000000012D
-:1015F00002164240000000000216424800000000AF
-:101600000616427000000002021642500000000060
-:101610000216425800000000061642800000000238
-:1016200002166008000006140216600C0000060096
-:1016300002166010000006040216601C0000FFFF86
-:10164000021660200000FFFF021660240000FFFF6A
-:10165000021660280000FFFF02166038000000201C
-:101660000216603C000000200216604000000034BA
-:101670000216604400000035021660480000002396
-:101680000216604C00000024021660500000002585
-:101690000216605400000026021660580000002761
-:1016A0000216605C00000029021660600000002A3B
-:1016B000021660640000002B021660680000002C17
-:1016C0000216606C0000002D0616607000000052CB
-:1016D000021661B800000001061661BC0000001F80
-:1016E0000216623807FFFFFF0216623C0000003F4F
-:1016F0000216624007FFFFFF021662440000000F5F
-:1017000001166248000000000116624C0000000053
-:101710000116625000000000011662540000000033
-:1017200001166258000000000116625C0000000013
-:1017300001166260000000000116626400000000F3
-:1017400001166268000000000116626C00000000D3
-:1017500001166270000000000116627400000000B3
-:1017600001166278000000000116627C0000000093
-:10177000021664BC000000010C166000000003E8C3
-:101780000A166000000000010B1660000000000A4D
-:10179000021680400000000602168044000000058A
-:1017A000021680480000000A0216804C0000000566
-:1017B0000216805400000002021680CC00000004D3
-:1017C000021680D000000004021680D4000000043D
-:1017D000021680D800000004021680DC000000041D
-:1017E000021680E000000004021680E400000004FD
-:1017F000021680E8000000040216880400000004BD
-:10180000021680300000007C021680340000003D8B
-:10181000021680380000003F0216803C0000009C49
-:10182000021680F000000007061680F40000000594
-:101830000216880C01010101021681080000000057
-:101840000216810C00000004021681100000000442
-:1018500002168114000000020216881008012004FC
-:1018600002168118000000050216811C0000000508
-:1018700002168120000000050216812400000005E8
-:101880000216882C2008100102168128000000088A
-:101890000216812C000000060216813000000007AD
-:1018A0000216813400000000021688300101012078
-:1018B0000616813800000004021688340101010177
-:1018C0000616814800000004021688380101010153
-:1018D00006168158000000040216883C010101012F
-:1018E00006168168000000030216817400000001E2
-:1018F00002168840010101010216817800000001F2
-:101900000216817C000000010216818000000001A7
-:1019100002168184000000010216884401010101C1
-:1019200002168188000000010216818C000000046C
-:10193000021681900000000402168194000000024B
-:10194000021688480801200402168198000000054C
-:101950000216819C00000005021681A0000000050F
-:10196000021681A400000005021688142008100148
-:10197000021681A800000008021681AC00000006D3
-:10198000021681B000000007021681B400000001B9
-:101990000216881801010120021681B8000000011A
-:1019A000021681BC00000001021681C00000000187
-:1019B000021681C4000000010216881C0101010109
-:1019C000021681C800000001021681CC000000014F
-:1019D000021681D000000001021681D4000000012F
-:1019E0000216882001010101021681D800000001C1
-:1019F000021681DC00000001021681E000000001F7
-:101A0000021681E400000001021688240101010190
-:101A1000021681E800000001021681EC00000001BE
-:101A2000021681F000000001021688280101010160
-:101A300002168240FFFF003F0616824400000002AB
-:101A40000216824CFFFF003F021682500000010088
-:101A5000021682540000010006168258000000029F
-:101A600002168260000000C002168264000000C0FE
-:101A70000216826800001E000216826C00001E0022
-:101A800002168270000040000216827400004000BE
-:101A900002168278000080000216827C000080001E
-:101AA00002168280000020000216828400002000BE
-:101AB0000616828800000007021682A400000001BA
-:101AC000061682A80000000A021681F400000C0825
-:101AD000021681F800000040021681FC000001009F
-:101AE0000216820000000020021682040000001787
-:101AF00002168208000000800216820C000002001C
-:101B0000021682100000000002168218FFFF01FF7B
-:101B100002168214FFFF01FF0216823C0000001330
-:101B2000021680900000013F021680600000014014
-:101B30000216806400000140061680680000000262
-:101B400002168070000000C00616807400000007B6
-:101B50000216809C00000048021680A00000004889
-:101B6000061680A400000002021680AC00000048A7
-:101B7000061680B0000000070216823800008000C0
-:101B800002168234000025E40216809400007FFFD4
-:101B900002168220000000070216821C00000007C7
-:101BA000021682280000000002168224FFFFFFFFB9
-:101BB00002168230000000000216822CFFFFFFFF99
-:101BC000021680EC000000FF02140000000000017B
-:101BD0000214000C0000000102140040000000018B
-:101BE0000214004400007FFF0214000C00000000FB
-:101BF00002140000000000000214006C000000004D
-:101C00000214000400000001021400300000000172
-:101C100002140004000000000214005C0000000038
-:101C2000021400080000000102140034000000014A
-:101C30000214000800000000021400600000000010
-:101C40000202005800000032020200A0031500202A
-:101C5000020200A403150020020200A801000030C7
-:101C6000020200AC08100000020200B000000033C5
-:101C7000020200B400000030020200B8000000318F
-:101C8000020200BC00000003020200C000000006C7
-:101C9000020200C400000003020200C800000003AA
-:101CA000020200CC00000002020200D0000000008E
-:101CB000020200D400000002020200DC000000006A
-:101CC000020200E000000006020200E4000000043E
-:101CD000020200E800000002020200EC0000000224
-:101CE000020200F000000001020200FC00000006F9
-:101CF0000202012000000000020201340000000284
-:101D0000020201B0000000010202020C000000010A
-:101D10000202021400000001020202180000000288
-:101D200002020404000000010202040C0000004052
-:101D300002020410000000400202041C0000000423
-:101D4000020204200000002002020424000000021D
-:101D5000020204280000001F060205000000001215
-:101D600004020480001F02D5020200600000000F80
-:101D70000202006400000007020200680000000B7D
-:101D80000202006C0000000E060200700000000459
-:101D9000020200F40000000402020004000000013E
-:101DA00002020008000000010202000C0000000115
-:101DB00002020010000000010202001400000001F5
-:101DC00002020018000000010202001C00000001D5
-:101DD00002020020000000010202002400000001B5
-:101DE00002020028000000010202002C0000000195
-:101DF0000202003000000001020200340000000175
-:101E000002020038000000010202003C0000000154
-:101E10000202004000000001020200440000000134
-:101E200002020048000000010202004C0000000114
-:101E3000020200500000000102020108000000C878
-:101E40000202011800000002020201C400000000AA
-:101E5000020201CC00000000020201D400000002D6
-:101E6000020201DC00000002020201E4000000FFA7
-:101E7000020201EC000000FF0202010C000000C899
-:101E80000202011C00000002020201C80000000062
-:101E9000020201D000000000020201D8000000028E
-:101EA000020201E000000002020201E8000000FF5F
-:101EB000020201F0000000FF0728040000B5000046
-:101EC00008280768001302F4072C000035D500002D
-:101ED000072C80003A3E0D76072D00003B471C067C
-:101EE000072D800022BC2AD8082DC770471202F6A1
-:101EF000012800000000000001280004000000008C
-:101F000001280008000000000128000C000000006B
-:101F1000012800100000000001280014000000004B
-:101F20000228002000000001022800240000000216
-:101F300002280028000000030228002C00000000F6
-:101F400002280030000000040228003400000001D4
-:101F500002280038000000000228003C00000001B8
-:101F60000228004000000004022800440000000095
-:101F700002280048000000010228004C0000000375
-:101F80000228005000000000022800540000000158
-:101F900002280058000000040228005C0000000035
-:101FA0000228006000000001022800640000000315
-:101FB00002280068000000000228006C00000001F8
-:101FC00002280070000000040228007400000000D5
-:101FD00002280078000000040228007C00000003B2
-:101FE0000628008000000002022800A400003FFF35
-:101FF000022800A8000003FF0228022400000000BD
-:1020000002280234000000000228024C00000000F8
-:10201000022802E40000FFFF06282000000008005C
-:10202000022B8BC000000001022B8000000000008A
-:10203000022B804000000018022B80800000000C62
-:10204000022B80C0000000660C2B83000007A1203B
-:102050000A2B8300000001380B2B8300000013883B
-:10206000022B83C0000001F40C2B8340000001F41C
-:102070000A2B8340000000000B2B8340000000056A
-:102080000A2B83800004C4B40C2B83801DCD650013
-:102090000B2B8380004C4B40062A3C400000000480
-:1020A000042A3C50000202F8062A300000000048D2
-:1020B000062A1020000000C8062A100000000002B6
-:1020C000062A31280000008E022A33680000000032
-:1020D000042A3370000202FA042A3A70000402FC57
-:1020E000042A3D0000020300042A15000002030236
-:1020F000062A150800000100022A197000000000DD
-:10210000022A197800000000042A19600002030462
-:10211000062A4AC000000002062A4B000000000404
-:10212000042A1F4800020306022B080000000000DA
-:10213000042B0C0000100308022B08000100000013
-:10214000042B0C4000080318022B080002000000BA
-:10215000042B0C6000080320062A3A8000000014BB
-:10216000062A3B2000000024062A14000000000A72
-:10217000062A145000000006062A3378000000D812
-:10218000022A3A3800000000042A3C5800020328C2
-:10219000042A3C680010032A062A5020000000028E
-:1021A000062A503000000002062A500000000002FB
-:1021B000062A501000000002022A504000000000D1
-:1021C000062A50480000000E022A50B80000000104
-:1021D000042A4AC80002033A062A4B1000000042B3
-:1021E000062A4D2000000004062A3AD00000001400
-:1021F000062A3BB000000024062A14280000000A2A
-:10220000062A146800000006062A36D8000000D806
-:10221000022A3A3C00000000042A3C600002033C11
-:10222000042A3CA80010033E062A502800000002A1
-:10223000062A503800000002062A5008000000025A
-:10224000062A501800000002022A50440000000034
-:10225000062A50800000000E022A50BC0000000137
-:10226000042A4AD00002034E062A4C1800000042FD
-:10227000062A4D3000000004021010080000000182
-:102280000210101000000264021010000003D000C1
-:10229000021010040000003D091018000200035055
-:1022A00009101100002005500610118000000002E6
-:1022B0000910118800060570061011A00000001812
-:1022C000021010100000000006102400000000E0C2
-:1022D0000210201C0000000002102020000000015D
-:1022E000021020C0000000010210200400000001C4
-:1022F000021020080000000109103C0000050576CE
-:1023000009103C200005057B0910380000050580F8
-:1023100002104028000000100210404400003FFF5F
-:102320000210405800280000021040840084924AA5
-:1023300002104058000000000610806800000004F1
-:1023400002108000000010800610802800000002AB
-:102350000210803800000010021080400000FFFFD3
-:10236000021080440000FFFF0210805000000000B7
-:102370000210810000000000061081200000000211
-:1023800002108008000002B502108010000000005A
-:10239000061082000000004A021081080001FFFFC1
-:1023A00006108140000000020210800000001A8028
-:1023B0000610900000000024061091200000004A42
-:1023C000061093700000004A061095C00000004AF5
-:1023D000021080040000108006108030000000020F
-:1023E0000210803C00000010021080480000FFFF37
-:1023F0000210804C0000FFFF02108054000000001B
-:102400000210810400000000061081280000000274
-:102410000210800C000002B50210801400000000C1
-:10242000061084000000004A0210810C0001FFFF2A
-:1024300006108148000000020210800400001A808B
-:102440000610909000000024061092480000004AF8
-:10245000061094980000004A061096E80000004A12
-:102460000212049000E383400212051400003C10A5
-:10247000021205200000000202120494FFFFFFFF79
-:1024800002120498FFFFFFFF0212049CFFFFFFFFF0
-:10249000021204A0FFFFFFFF021204A4FFFFFFFFD0
-:1024A000021204A8FFFFFFFF021204ACFFFFFFFFB0
-:1024B000021204B0FFFFFFFF021204B8FFFFFFFF8C
-:1024C000021204BCFFFFFFFF021204C0FFFFFFFF68
-:1024D000021204C4FFFFFFFF021204C8FFFFFFFF48
-:1024E000021204CCFFFFFFFF021204D0FFFFFFFF28
-:1024F000021204DCFFFFFFFF021204E0FFFFFFFFF8
-:10250000021204E4FFFFFFFF021204E8FFFFFFFFD7
-:10251000021204ECFFFFFFFF021204F0FFFFFFFFB7
-:10252000021204F4FFFFFFFF021204F8FFFFFFFF97
-:10253000021204FCFFFFFFFF02120500FFFFFFFF76
-:1025400002120504FFFFFFFF02120508FFFFFFFF55
-:102550000212050CFFFFFFFF02120510FFFFFFFF35
-:10256000021204D4FFFF3330021204D8FFFF3340BD
-:10257000021204B4F00030000212039000000008C0
-:102580000212039C00000008061203A000000002D3
-:10259000021203BC00000004021203C40000000485
-:1025A000021203D000000000021203DC0000000051
-:1025B0000212036C00000001021203680000003FD9
-:1025C000021201BC00000040021201C00000180805
-:1025D000021201C400000803021201C8000008032F
-:1025E000021201CC00000040021201D000000003E2
-:1025F000021201D400000803021201D800000803EF
-:10260000021201DC00000803021201E000010003D5
-:10261000021201E400000803021201E800000803AE
-:10262000021201EC00000003021201F0000000039E
-:10263000021201F400000003021201F8000000037E
-:10264000021201FC0000000302120200000000035D
-:10265000021202040000000302120208000000033C
-:102660000212020C0000000302120210000000031C
-:1026700002120214000000030212021800000003FC
-:102680000212021C000000030212022000000003DC
-:102690000212022400000003021202280000240398
-:1026A0000212022C0000002F02120230000000096A
-:1026B00002120234000000190212023800000184E4
-:1026C0000212023C000001830212024000000306D5
-:1026D0000212024400000019021202480000000623
-:1026E0000212024C00000306021202500000030610
-:1026F00002120254000003060212025800000C8667
-:102700000212025C000003060212026000000306CF
-:1027100002120264000000060212026800000006B5
-:102720000212026C00000006021202700000000695
-:102730000212027400000006021202780000000675
-:102740000212027C00000006021202800000000655
-:102750000212028400000006021202880000000635
-:102760000212028C00000006021202900000000615
-:1027700002120294000000060212029800000006F5
-:102780000212029C00000006021202A000000306D2
-:10279000021202A400000013021202A800000006A8
-:1027A000021202B000001004021202B40000100471
-:1027B0000212032400106440021203280010644037
-:1027C000021201B0000000010600A0000000001687
-:1027D0000200A06CBF5C00000200A070FFF51FEFBC
-:1027E0000200A0740000FFFF0200A078500003E088
-:1027F0000200A07C000000000200A0800000A000F9
-:102800000600A084000000050200A0980FE0000070
-:102810000600A09C000000140200A0EC555400002B
-:102820000200A0F0555555550200A0F40000555582
-:102830000200A0F8000000000200A0FC55540000B7
-:102840000200A100555555550200A1040000555540
-:102850000200A108000000000200A22C00000000FD
-:102860000600A230000000030200A0600000000784
-:102870000200A10CBF5C00000200A110FFF51FEFD9
-:102880000200A1140000FFFF0200A118500003E0A5
-:102890000200A11C000000000200A1200000A00016
-:1028A0000600A124000000050200A1380FE000008E
-:1028B0000600A13C000000140200A18C5554000049
-:1028C0000200A190555555550200A19400005555A0
-:1028D0000200A198000000000200A19C55540000D5
-:1028E0000200A1A0555555550200A1A40000555560
-:1028F0000200A1A8000000000200A23C00000000AD
-:102900000600A240000000030200A06400000007CF
-:1029100000000000000000000000002E0000000089
-:1029200000000000000000000000000000000000A7
-:102930000000000000000000000000000000000097
-:102940000000000000000000000000000000000087
-:102950000000000000000000000000000000000077
-:102960000000000000000000000000000000000067
-:10297000002E0050000000000000000000000000D9
-:102980000000000000000000000000000000000047
-:102990000000000000000000000000000050008D5A
-:1029A0000000000000000000000000000000000027
-:1029B0000000000000000000000000000000000017
-:1029C0000000000000000000008D009200920096C0
-:1029D0000096009A000000000000000000000000C7
-:1029E00000000000000000000000000000000000E7
-:1029F00000000000009A00DB00DB00E900E900F7BE
-:102A000000000000000000000000000000000000C6
-:102A100000000000000000000000000000000000B6
-:102A200000000000000000000000000000000000A6
-:102A30000000000000000000000000000000000096
-:102A40000000000000000000000000000000000086
-:102A50000000000000000000000000000000000076
-:102A60000000000000000000000000000000000066
-:102A70000000000000000000000000000000000056
-:102A80000000000000000000000000000000000046
-:102A90000000000000000000000000000000000036
-:102AA0000000000000000000000000000000000026
-:102AB0000000000000000000000000000000000016
-:102AC0000000000000000000000000000000000006
-:102AD00000F700FE00000000000000000000000001
-:102AE00000000000000000000000000000000000E6
-:102AF00000000000000000000000000000000000D6
-:102B000000000000000000000000000000000000C5
-:102B100000000000000000000000000000000000B5
-:102B2000000000000000000000FE01030103010E90
-:102B3000010E01190000000000000000000000006C
-:102B40000000000000000000000000000000000085
-:102B50000000000000000000000000000000000075
-:102B60000000000000000000000000000000000065
-:102B70000000000000000000000000000000000055
-:102B80000119011A00000000000000000000000010
-:102B90000000000000000000000000000000000035
-:102BA000000000000000000000000000011A0152B7
-:102BB0000000000000000000000000000000000015
-:102BC0000000000000000000000000000000000005
-:102BD000000000000000000001520176000000002B
-:102BE00000000000000000000000000000000000E5
-:102BF00000000000000000000000000000000000D5
-:102C000000000000017601B5000000000000000097
-:102C100000000000000000000000000000000000B4
-:102C200000000000000000000000000000000000A4
-:102C300001B501F0000000000000000000000000ED
-:102C40000000000000000000000000000000000084
-:102C500000000000000000000000000001F002354C
-:102C6000023502380238023B00000000000000007C
-:102C70000000000000000000000000000000000054
-:102C80000000000000000000023B02760276028095
-:102C90000280028A00000000000000000000000026
-:102CA0000000000000000000000000000000000024
-:102CB00000000000028A028B0000000000000000FB
-:102CC0000000000000000000000000000000000004
-:102CD00000000000000000000000000000000000F4
-:102CE000028B029D000000000000000000000000B8
-:102CF00000000000000000000000000000000000D4
-:102D0000000000000000000000000000029D02B270
-:102D100002B202B502B502B80000000000000000D7
-:102D200000000000000000000000000000000000A3
-:102D3000000000000000000002B802E600000000F1
-:102D40000000000000000000000000000000000083
-:102D50000000000000000000000000000000000073
-:102D60000000000002E6036D00000000000000000B
-:102D70000000000000000000000000000000000053
-:102D80000000000000000000000000000000000043
-:102D9000036D0374037403780378037C0000000060
-:102DA0000000000000000000000000000000000023
-:102DB000000000000000000000000000037C03BBD6
-:102DC00003BB03C303C303CB0000000000000000EB
-:102DD00000000000000000000000000000000000F3
-:102DE000000000000000000003CB041F041F04319A
-:102DF0000431044300000000000000000000000057
-:102E000000000000000000000000000000000000C2
-:102E1000000000000443044D00000000000000001A
-:102E200000000000000000000000000000000000A2
-:102E30000000000000000000000000000000000092
-:102E4000044D0453000000000000000000000000DA
-:102E50000000000000000000000000000000000072
-:102E600000000000000000000000000004530456B1
-:102E70000000000000000000000000000000000052
-:102E80000000000000000000000000000000000042
-:102E900000000000000000000456045B0000000079
-:102EA0000000000000000000000000000000000022
-:102EB0000000000000000000000000000000000012
-:102EC00000000000045B045C045C046E046E04807B
-:102ED00000000000000000000000000000000000F2
-:102EE00000000000000000000000000000000000E2
-:102EF000048004ED0000000000000000000000005D
-:102F000000000000000000000000000000000000C1
-:102F100000000000000000000000000004ED04EECE
-:102F200004EE050205020516000000000000000086
-:102F30000000000000000000000000000000000091
-:102F40000000000000000000000000000000000081
-:102F50000000000000000000000000000000000071
-:102F60000000000000000000000000000000000061
-:102F70000000000000000000000000000000000051
-:102F80000000000000000000000000000000000041
-:102F90000000000000000000000000000000000031
-:102FA000000000000000000000010000000204C05A
-:102FB0000003098000040E4000051300000617C03E
-:102FC00000071C800008214000092600000A2AC0D2
-:102FD000000B2F80000C3440000D3900000E3DC066
-:102FE000000F42800010474000114C00001250C0FA
-:102FF0000013558000145A4000155F00001663C08E
-:103000000017688000186D4000197200001A76C021
-:10301000001B7B80001C8040001D8500001E89C0B5
-:10302000001F8E8000209340000020000000400020
-:1030300000006000000080000000A0000000C00050
-:103040000000E0000001000000012000000140003D
-:1030500000016000000180000001A0000001C0002C
-:103060000001E00000020000000220000002400019
-:1030700000026000000280000002A0000002C00008
-:103080000002E000000300000003200000034000F5
-:1030900000036000000380000003A0000003C000E4
-:1030A0000003E000000400000004200000044000D1
-:1030B00000046000000480000004A0000004C000C0
-:1030C0000004E000000500000005200000054000AD
-:1030D00000056000000580000005A0000005C0009C
-:1030E0000005E00000060000000620000006400089
-:1030F00000066000000680000006A0000006C00078
-:103100000006E00000070000000720000007400064
-:1031100000076000000780000007A0000007C00053
-:103120000007E00000080000000820000008400040
-:1031300000086000000880000008A0000008C0002F
-:103140000008E0000009000000092000000940001C
-:1031500000096000000980000009A0000009C0000B
-:103160000009E000000A0000000A2000000A4000F8
-:10317000000A6000000A8000000AA000000AC000E7
-:10318000000AE000000B0000000B2000000B4000D4
-:10319000000B6000000B8000000BA000000BC000C3
-:1031A000000BE000000C0000000C2000000C4000B0
-:1031B000000C6000000C8000000CA000000CC0009F
-:1031C000000CE000000D0000000D2000000D40008C
-:1031D000000D6000000D8000000DA000000DC0007B
-:1031E000000DE000000E0000000E2000000E400068
-:1031F000000E6000000E8000000EA000000EC00057
-:10320000000EE000000F0000000F2000000F400043
-:10321000000F6000000F8000000FA000000FC00032
-:10322000000FE0000010000000102000001040001F
-:1032300000106000001080000010A0000010C0000E
-:103240000010E000001100000011200000114000FB
-:1032500000116000001180000011A0000011C000EA
-:103260000011E000001200000012200000124000D7
-:1032700000126000001280000012A0000012C000C6
-:103280000012E000001300000013200000134000B3
-:1032900000136000001380000013A0000013C000A2
-:1032A0000013E0000014000000142000001440008F
-:1032B00000146000001480000014A0000014C0007E
-:1032C0000014E0000015000000152000001540006B
-:1032D00000156000001580000015A0000015C0005A
-:1032E0000015E00000160000001620000016400047
-:1032F00000166000001680000016A0000016C00036
-:103300000016E00000170000001720000017400022
-:1033100000176000001780000017A0000017C00011
-:103320000017E000001800000018200000184000FE
-:1033300000186000001880000018A0000018C000ED
-:103340000018E000001900000019200000194000DA
-:1033500000196000001980000019A0000019C000C9
-:103360000019E000001A0000001A2000001A4000B6
-:10337000001A6000001A8000001AA000001AC000A5
-:10338000001AE000001B0000001B2000001B400092
-:10339000001B6000001B8000001BA000001BC00081
-:1033A000001BE000001C0000001C2000001C40006E
-:1033B000001C6000001C8000001CA000001CC0005D
-:1033C000001CE000001D0000001D2000001D40004A
-:1033D000001D6000001D8000001DA000001DC00039
-:1033E000001DE000001E0000001E2000001E400026
-:1033F000001E6000001E8000001EA000001EC00015
-:10340000001EE000001F0000001F2000001F400001
-:10341000001F6000001F8000001FA000001FC000F0
-:10342000001FE000002000000020200000204000DD
-:1034300000206000002080000020A0000020C000CC
-:103440000020E000002100000021200000214000B9
-:1034500000216000002180000021A0000021C000A8
-:103460000021E00000220000002220000022400095
-:1034700000226000002280000022A0000022C00084
-:103480000022E00000230000002320000023400071
-:1034900000236000002380000023A0000023C00060
-:1034A0000023E0000024000000242000002440004D
-:1034B00000246000002480000024A0000024C0003C
-:1034C0000024E00000250000002520000025400029
-:1034D00000256000002580000025A0000025C00018
-:1034E0000025E00000260000002620000026400005
-:1034F00000266000002680000026A0000026C000F4
-:103500000026E000002700000027200000274000E0
-:1035100000276000002780000027A0000027C000CF
-:103520000027E000002800000028200000284000BC
-:1035300000286000002880000028A0000028C000AB
-:103540000028E00000290000002920000029400098
-:1035500000296000002980000029A0000029C00087
-:103560000029E000002A0000002A2000002A400074
-:10357000002A6000002A8000002AA000002AC00063
-:10358000002AE000002B0000002B2000002B400050
-:10359000002B6000002B8000002BA000002BC0003F
-:1035A000002BE000002C0000002C2000002C40002C
-:1035B000002C6000002C8000002CA000002CC0001B
-:1035C000002CE000002D0000002D2000002D400008
-:1035D000002D6000002D8000002DA000002DC000F7
-:1035E000002DE000002E0000002E2000002E4000E4
-:1035F000002E6000002E8000002EA000002EC000D3
-:10360000002EE000002F0000002F2000002F4000BF
-:10361000002F6000002F8000002FA000002FC000AE
-:10362000002FE0000030000000302000003040009B
-:1036300000306000003080000030A0000030C0008A
-:103640000030E00000310000003120000031400077
-:1036500000316000003180000031A0000031C00066
-:103660000031E00000320000003220000032400053
-:1036700000326000003280000032A0000032C00042
-:103680000032E0000033000000332000003340002F
-:1036900000336000003380000033A0000033C0001E
-:1036A0000033E0000034000000342000003440000B
-:1036B00000346000003480000034A0000034C000FA
-:1036C0000034E000003500000035200000354000E7
-:1036D00000356000003580000035A0000035C000D6
-:1036E0000035E000003600000036200000364000C3
-:1036F00000366000003680000036A0000036C000B2
-:103700000036E0000037000000372000003740009E
-:1037100000376000003780000037A0000037C0008D
-:103720000037E0000038000000382000003840007A
-:1037300000386000003880000038A0000038C00069
-:103740000038E00000390000003920000039400056
-:1037500000396000003980000039A0000039C00045
-:103760000039E000003A0000003A2000003A400032
-:10377000003A6000003A8000003AA000003AC00021
-:10378000003AE000003B0000003B2000003B40000E
-:10379000003B6000003B8000003BA000003BC000FD
-:1037A000003BE000003C0000003C2000003C4000EA
-:1037B000003C6000003C8000003CA000003CC000D9
-:1037C000003CE000003D0000003D2000003D4000C6
-:1037D000003D6000003D8000003DA000003DC000B5
-:1037E000003DE000003E0000003E2000003E4000A2
-:1037F000003E6000003E8000003EA000003EC00091
-:10380000003EE000003F0000003F2000003F40007D
-:10381000003F6000003F8000003FA000003FC0006C
-:10382000003FE000003FE00100000000000001FF59
-:103830000000020000007FF800007FF80000026F27
-:1038400000001500000000010000000300BEBC20C5
-:103850000000000300BEBC2000000001FFFFFFFFCE
-:10386000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF68
-:10387000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58
-:1038800000000000FFFFFFFF00000000FFFFFFFF40
-:103890000000000300BEBC20FFFFFFFF000000008F
-:1038A000FFFFFFFF00000000FFFFFFFF000000031D
-:1038B00000BEBC2000002000000040C0000061806D
-:1038C000000082400000A3000000C3C00000E480AC
-:1038D0000001054000012600000146C0000167808C
-:1038E000000188400001A9000001C9C00001EA8070
-:1038F00000020B4000022C0000024CC000026D8050
-:1039000000028E400002AF000002CFC00002F08033
-:103910000003114000033200000352C00003738013
-:10392000000394400003B5000003D5C00003F680F7
-:103930000004174000043800000458C000047980D7
-:1039400000049A400000800000010380000187000D
-:1039500000020A8000028E0000031180000395001F
-:103960000004188000049C0000051F800005A300CF
-:10397000000626800006AA0000072D800007B1007F
-:10398000000834800008B80000093B800009BF002F
-:10399000000A4280000AC600000B4980000BCD00DF
-:1039A000000C5080000CD400000D5780000DDB008F
-:1039B00000007FF800007FF800000174000015008F
-:1039C0000000190000000000FFFFFFFF40000000A2
-:1039D00040000000400000004000000040000000E7
-:1039E00040000000400000004000000040000000D7
-:1039F00040000000400000004000000040000000C7
-:103A000040000000400000004000000040000000B6
-:103A100040000000400000004000000040000000A6
-:103A20004000000040000000400000004000000096
-:103A30004000000040000000400000004000000086
-:103A400040000000400000004000000000007FF83F
-:103A500000007FF80000050900003500FFFFFFFFB0
-:103A6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66
-:103A7000FFFFFFFFFFFFFFFFFFFFFFFF4000000012
-:103A80004000000040000000400000004000000036
-:103A90004000000040000000400000004000000026
-:103AA0004000000040000000400000004000000016
-:103AB0004000000040000000400000004000000006
-:103AC00040000000400000004000000040000000F6
-:103AD00040000000400000004000000040000000E6
-:103AE00040000000400000004000000040000000D6
-:103AF00040000000400000004000000000001000F6
-:103B000000002080000031000000418000005200D1
-:103B100000006280000073000000838000009400B9
-:103B20000000A4800000B5000000C5800000D600A1
-:103B30000000E6800000F700000107800001180087
-:103B400000012880000139000001498000015A006D
-:103B500000016A8000017B0000018B8000019C0055
-:103B60000001AC800001BD000001CD800001DE003D
-:103B70000001EE800001FF0000007FF800007FF8E8
-:103B8000000004480000150010000000000028ADEF
-:103B90000000000000010001000D0205CCCCCCC1EA
-:103BA000FFFFFFFFFFFFFFFF7058103C0000000009
-:103BB0000000000000000001CCCC0201CCCCCCCC39
-:103BC00000000000FFFFFFFF400000004000000079
-:103BD00040000000400000004000000040000000E5
-:103BE00040000000400000004000000040000000D5
-:103BF00040000000400000004000000040000000C5
-:103C000040000000400000004000000040000000B4
-:103C100040000000400000004000000040000000A4
-:103C20004000000040000000400000004000000094
-:103C30004000000040000000400000004000000084
-:103C40004000000040000000000E01B7011600D641
-:103C50000000FFFF000000000000FFFF0000000068
-:103C60000000FFFF000000000000FFFF0000000058
-:103C70000000FFFF000000000000FFFF0000000048
-:103C80000000FFFF000000000000FFFF0000000038
-:103C90000010000000000000007201BB012300F3CF
-:103CA0000000FFFF000000000000FFFF0000000018
-:103CB0000000FFFF000000000000FFFF0000000008
-:103CC0000000FFFF000000000000FFFF00000000F8
-:103CD0000000FFFF000000000000FFFF00000000E8
-:103CE0000010000000000000FFFFFFF3318FFFFF16
-:103CF0000C30C30CC30C30C3CF3CF300F3CF3CF308
-:103D00000000CF3CCDCDCDCDFFFFFFF130EFFFFF69
-:103D10000C30C30CC30C30C3CF3CF300F3CF3CF3E7
-:103D20000001CF3CCDCDCDCDFFFFFFF6305FFFFFD3
-:103D30000C30C30CC30C30C3CF3CF300F3CF3CF3C7
-:103D40000002CF3CCDCDCDCDFFFFF4061CBFFFFF61
-:103D50000C30C305C30C30C3CF300014F3CF3CF399
-:103D60000004CF3CCDCDCDCDFFFFFFF2304FFFFFA4
-:103D70000C30C30CC30C30C3CF3CF300F3CF3CF387
-:103D80000008CF3CCDCDCDCDFFFFFFFA302FFFFF98
-:103D90000C30C30CC30C30C3CF3CF300F3CF3CF367
-:103DA0000010CF3CCDCDCDCDFFFFFFF731EFFFFFB2
-:103DB0000C30C30CC30C30C3CF3CF300F3CF3CF347
-:103DC0000020CF3CCDCDCDCDFFFFFFF5302FFFFF45
-:103DD0000C30C30CC30C30C3CF3CF300F3CF3CF327
-:103DE0000040CF3CCDCDCDCDFFFFFFF3318FFFFFA6
-:103DF0000C30C30CC30C30C3CF3CF300F3CF3CF307
-:103E00000000CF3CCDCDCDCDFFFFFFF1310FFFFF47
-:103E10000C30C30CC30C30C3CF3CF300F3CF3CF3E6
-:103E20000001CF3CCDCDCDCDFFFFFFF6305FFFFFD2
-:103E30000C30C30CC30C30C3CF3CF300F3CF3CF3C6
-:103E40000002CF3CCDCDCDCDFFFFF4061CBFFFFF60
-:103E50000C30C305C30C30C3CF300014F3CF3CF398
-:103E60000004CF3CCDCDCDCDFFFFFFF2304FFFFFA3
-:103E70000C30C30CC30C30C3CF3CF300F3CF3CF386
-:103E80000008CF3CCDCDCDCDFFFFFFFA302FFFFF97
-:103E90000C30C30CC30C30C3CF3CF300F3CF3CF366
-:103EA0000010CF3CCDCDCDCDFFFFFFF730EFFFFFB2
-:103EB0000C30C30CC30C30C3CF3CF300F3CF3CF346
-:103EC0000020CF3CCDCDCDCDFFFFFFF5304FFFFF24
-:103ED0000C30C30CC30C30C3CF3CF300F3CF3CF326
-:103EE0000040CF3CCDCDCDCDFFFFFFF331EFFFFF45
-:103EF0000C30C30CC30C30C3CF3CF300F3CF3CF306
-:103F00000000CF3CCDCDCDCDFFFFFFF1310FFFFF46
-:103F10000C30C30CC30C30C3CF3CF300F3CF3CF3E5
-:103F20000001CF3CCDCDCDCDFFFFFFF6305FFFFFD1
-:103F30000C30C30CC30C30C3CF3CF300F3CF3CF3C5
-:103F40000002CF3CCDCDCDCDFFFFF4061CBFFFFF5F
-:103F50000C30C305C30C30C3CF300014F3CF3CF397
-:103F60000004CF3CCDCDCDCDFFFFFFF2304FFFFFA2
-:103F70000C30C30CC30C30C3CF3CF300F3CF3CF385
-:103F80000008CF3CCDCDCDCDFFFFFFFA302FFFFF96
-:103F90000C30C30CC30C30C3CF3CF300F3CF3CF365
-:103FA0000010CF3CCDCDCDCDFFFFFF97056FFFFFBC
-:103FB0000C30C30CC30C30C3CF3CC000F3CF3CF378
-:103FC0000020CF3CCDCDCDCDFFFFFFF5310FFFFF62
-:103FD0000C30C30CC30C30C3CF3CF300F3CF3CF325
-:103FE0000040CF3CCDCDCDCDFFFFFFF3320FFFFF23
-:103FF0000C30C30CC30C30C3CF3CF300F3CF3CF305
-:104000000000CF3CCDCDCDCDFFFFFFF1310FFFFF45
-:104010000C30C30CC30C30C3CF3CF300F3CF3CF3E4
-:104020000001CF3CCDCDCDCDFFFFFFF6305FFFFFD0
-:104030000C30C30CC30C30C3CF3CF300F3CF3CF3C4
-:104040000002CF3CCDCDCDCDFFFFF4061CBFFFFF5E
-:104050000C30C305C30C30C3CF300014F3CF3CF396
-:104060000004CF3CCDCDCDCDFFFFFFF2304FFFFFA1
-:104070000C30C30CC30C30C3CF3CF300F3CF3CF384
-:104080000008CF3CCDCDCDCDFFFFFF8A042FFFFF31
-:104090000C30C30CC30C30C3CF3CC000F3CF3CF397
-:1040A0000010CF3CCDCDCDCDFFFFFF9705CFFFFF5B
-:1040B0000C30C30CC30C30C3CF3CC000F3CF3CF377
-:1040C0000020CF3CCDCDCDCDFFFFFFF5310FFFFF61
-:1040D0000C30C30CC30C30C3CF3CF300F3CF3CF324
-:1040E0000040CF3CCDCDCDCDFFFFFFF3300FFFFF24
-:1040F0000C30C30CC30C30C3CF3CF300F3CF3CF304
-:104100000000CF3CCDCDCDCDFFFFFFF1300FFFFF45
-:104110000C30C30CC30C30C3CF3CF300F3CF3CF3E3
-:104120000001CF3CCDCDCDCDFFFFFFF6305FFFFFCF
-:104130000C30C30CC30C30C3CF3CF300F3CF3CF3C3
-:104140000002CF3CCDCDCDCDFFFFF4061CBFFFFF5D
-:104150000C30C305C30C30C3CF300014F3CF3CF395
-:104160000004CF3CCDCDCDCDFFFFFFF2304FFFFFA0
-:104170000C30C30CC30C30C3CF3CF300F3CF3CF383
-:104180000008CF3CCDCDCDCDFFFFFFFA302FFFFF94
-:104190000C30C30CC30C30C3CF3CF300F3CF3CF363
-:1041A0000010CF3CCDCDCDCDFFFFFF97040FFFFF1B
-:1041B0000C30C30CC30C30C3CF3CC000F3CF3CF376
-:1041C0000020CF3CCDCDCDCDFFFFFFF5300FFFFF61
-:1041D0000C30C30CC30C30C3CF3CF300F3CF3CF323
-:1041E0000040CF3CCDCDCDCDFFFFFFFF30CFFFFF57
-:1041F0000C30C30CC30C30C3CF3CF3CCF3CF3CF337
-:104200000000CF3CCDCDCDCDFFFFFFFF30CFFFFF76
-:104210000C30C30CC30C30C3CF3CF3CCF3CF3CF316
-:104220000001CF3CCDCDCDCDFFFFFFFF30CFFFFF55
-:104230000C30C30CC30C30C3CF3CF3CCF3CF3CF3F6
-:104240000002CF3CCDCDCDCDFFFFFFFF30CFFFFF34
-:104250000C30C30CC30C30C3CF3CF3CCF3CF3CF3D6
-:104260000004CF3CCDCDCDCDFFFFFFFF30CFFFFF12
-:104270000C30C30CC30C30C3CF3CF3CCF3CF3CF3B6
-:104280000008CF3CCDCDCDCDFFFFFFFF30CFFFFFEE
-:104290000C30C30CC30C30C3CF3CF3CCF3CF3CF396
-:1042A0000010CF3CCDCDCDCDFFFFFFFF30CFFFFFC6
-:1042B0000C30C30CC30C30C3CF3CF3CCF3CF3CF376
-:1042C0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF96
-:1042D0000C30C30CC30C30C3CF3CF3CCF3CF3CF356
-:1042E0000040CF3CCDCDCDCDFFFFFFFF30CFFFFF56
-:1042F0000C30C30CC30C30C3CF3CF3CCF3CF3CF336
-:104300000000CF3CCDCDCDCDFFFFFFFF30CFFFFF75
-:104310000C30C30CC30C30C3CF3CF3CCF3CF3CF315
-:104320000001CF3CCDCDCDCDFFFFFFFF30CFFFFF54
-:104330000C30C30CC30C30C3CF3CF3CCF3CF3CF3F5
-:104340000002CF3CCDCDCDCDFFFFFFFF30CFFFFF33
-:104350000C30C30CC30C30C3CF3CF3CCF3CF3CF3D5
-:104360000004CF3CCDCDCDCDFFFFFFFF30CFFFFF11
-:104370000C30C30CC30C30C3CF3CF3CCF3CF3CF3B5
-:104380000008CF3CCDCDCDCDFFFFFFFF30CFFFFFED
-:104390000C30C30CC30C30C3CF3CF3CCF3CF3CF395
-:1043A0000010CF3CCDCDCDCDFFFFFFFF30CFFFFFC5
-:1043B0000C30C30CC30C30C3CF3CF3CCF3CF3CF375
-:1043C0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF95
-:1043D0000C30C30CC30C30C3CF3CF3CCF3CF3CF355
-:1043E0000040CF3CCDCDCDCDFFFFFFFF30CFFFFF55
-:1043F0000C30C30CC30C30C3CF3CF3CCF3CF3CF335
-:104400000000CF3CCDCDCDCDFFFFFFFF30CFFFFF74
-:104410000C30C30CC30C30C3CF3CF3CCF3CF3CF314
-:104420000001CF3CCDCDCDCDFFFFFFFF30CFFFFF53
-:104430000C30C30CC30C30C3CF3CF3CCF3CF3CF3F4
-:104440000002CF3CCDCDCDCDFFFFFFFF30CFFFFF32
-:104450000C30C30CC30C30C3CF3CF3CCF3CF3CF3D4
-:104460000004CF3CCDCDCDCDFFFFFFFF30CFFFFF10
-:104470000C30C30CC30C30C3CF3CF3CCF3CF3CF3B4
-:104480000008CF3CCDCDCDCDFFFFFFFF30CFFFFFEC
-:104490000C30C30CC30C30C3CF3CF3CCF3CF3CF394
-:1044A0000010CF3CCDCDCDCDFFFFFFFF30CFFFFFC4
-:1044B0000C30C30CC30C30C3CF3CF3CCF3CF3CF374
-:1044C0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF94
-:1044D0000C30C30CC30C30C3CF3CF3CCF3CF3CF354
-:1044E0000040CF3CCDCDCDCD000C0000000700C07A
-:1044F00000028130000B81580002021000010230DE
-:10450000000F024000010330000C0000000800C052
-:1045100000028140000B816800020220000102407D
-:1045200000070250000202C0000F0000000800F067
-:1045300000028170000B819800020250000102709D
-:10454000000B828000080338001000000008010002
-:1045500000028180000B81A80002026000018280BD
-:10456000000E82980008038000028000000B802863
-:10457000000200E0000101000000811000000118AD
-:10458000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC6B
-:1045900000002000CCCCCCCCCCCCCCCCCCCCCCCC6B
-:1045A000CCCCCCCC00002000CCCCCCCCCCCCCCCC5B
-:1045B000CCCCCCCCCCCCCCCC00002000000000007B
-:1045C0001F8B080000000000000BFB51CFC0F00360
-:1045D0008A7BD81818F67020F843015F646260B8CF
-:1045E0000CC45781588099812198918121849178B8
-:1045F000FD71A208F61321A019C240330419184E08
-:104600000B23C40F02D5988830307C878A5503D994
-:104610000CA2D471FF40E375529862AB2510ECF503
-:1046200058E491F10634792E4954FE4602FA071AED
-:10463000DF5744E50B2940E86CA8F803347961A8FA
-:10464000FC79A8BF1E2A6237F702541E005BBBD25A
-:1046500053600300000000000000000000000000A4
-:104660001F8B080000000000000BED7D0B7854D577
-:10467000B5F03E73CE9C9949662627214F1E6112E4
-:1046800020028638BC0228B74E480850691D6C5578
-:10469000B468070810F296A297D6F6CB04428C8035
-:1046A00036F8FB408B3ABC2A2A6AC048510187A7DA
-:1046B000E8F5F606AB9656EB8D68519147E456A5A2
-:1046C000FF6DAFFF5A6BEF9D39673201ECD77BFF6F
-:1046D000FBDFEF8F9FDF619FBDCFDE6BAFD75E6BE0
-:1046E000EDB5F7D86D1EA65FCDD8D7F807CF7A1BEA
-:1046F000632C23F67CC4CE7E18743356B0CEB7C27A
-:104700009D0EEF77E56D4FF63196B37BAD3205DE4A
-:10471000E7AC6F53E615C6BE0FB8A0723CBCDFB560
-:10472000562981F7396FB42973F1E9B0B14E68CFDA
-:10473000345F0AC3270B3096C9D890894CFC05DC3E
-:1047400039C58C0DC47F4217E78C64C6C63196B755
-:10475000D216092BF03E5439937919DB0470E5A485
-:10476000C177EA5FF6D9B16D8376BCCBC998537334
-:104770006A5FE733963B9BD9183C072FE3EFF1EFD5
-:104780006BF83F2F6C2D0F61A6721E963DE92760D6
-:1047900048E6619EAFD544F076EBC151B179CAE7E6
-:1047A000FA465FA65BEBFD5E3E97DCF6897E177CE2
-:1047B000FD18B61BCA5824AE7D6D58D7D815F00425
-:1047C00004B417F6FE7E262B29463ADCCAA6D0B3DF
-:1047D0005EF3DD8878A93F62676180BBBEE1443942
-:1047E00096D92E850DCBEBFDFD2866277A943045B2
-:1047F0003B81F3F5322FCE4FADF13D540E786E482C
-:104800000E9461BF0F2787E829DF67CF9B9E1D02AB
-:10481000784A17158619D0FDDC3AC5EF80CF3F5690
-:1048200022BA1DE851FDFD86A269D0EE6D3D740DE2
-:104830007EB7488DB6D861FCDA390D054001D6A99E
-:1048400073FE19BCABE4530DE83698B1704A1AD226
-:1048500085B1E3263AE0DFF1E1A2ACF68DC78B3DEE
-:104860002BB01F0D7B89D07CE5FBBCF0912143E38D
-:10487000C663C5040F433819EB5212D175F08B256E
-:1048800047B4A2BEC7FBCF9F4798CB21E00EE95BA0
-:10489000EBD123CB01BFA52FD8A357033D6A3728FF
-:1048A0001107946D7B5D01A4CF99CD5006BA443DAC
-:1048B0003AB53F6D38A95CEFE8BCF72A2877BFA06E
-:1048C000B28DD8EDF0241BCADD09013B1B0765C082
-:1048D000C742172FD66ED8772BF657B9CBC15C4895
-:1048E000CF17177DF72A282F027EC326B55B9AF4CF
-:1048F000FE505E1C51DAB17C760A23FE08A7E991CE
-:104900002D30DE596F67E6F5202F271B9DCC07A0C1
-:10491000ACF074667E1FF8A82AB2BD1CBFABDAA645
-:10492000F811EDA52F6C399C83F37A12F80AF8A8D8
-:104930007A6B32F349FCC1FF27602A5743FD129876
-:1049400027CAFF22D656CE541C7FADEEF3C4F075B5
-:10495000B2D1A0717AE4E9491807BEAB7B56F1E306
-:1049600014EB6C2C847275E645D7EC4D6E9C5F930E
-:104970005EE0C179DDA563BB4591B93B5165554505
-:1049800036E8E5505FB57E83BEB010F1067AAF1011
-:10499000E1EA67856B9D1A40FC2E49756E54013F14
-:1049A000CC1DC8BE2E01FF9C6C043556102B57A1A0
-:1049B0007C933E89E8B34CEDCB9554E2D7EAAD2A1F
-:1049C000F359F889D33F7C94D33FBCC713D99217CE
-:1049D000A3DF1283EB4949BF25A9829E5A77712232
-:1049E00078EE457A003C6D882F78AE11F07927B3C8
-:1049F000120DE8E20D30436117E7CF363B9BCB60E9
-:104A0000EC37D982803609CA3ABB8DF91933B4DA4A
-:104A1000401994FFC2826FE07C18F3FB8280E71696
-:104A200085CDC6791F4260613E2D393AE1AF6D6A8E
-:104A3000F126551130A76379E12F57E5D1F76FD1F2
-:104A4000F71A7C3FAAEFEF8DF28996EF8DF24AF9C3
-:104A5000FD7BD88E392FFC7D5BF995D6F1CBABE48D
-:104A6000F71FD1F8EE0BC36F4C9B6C1D7F5A0D7D69
-:104A70005FEFE0F4EA4E75463642B9D9E50F684873
-:104A8000378D45F1BD9656B011DBA9921F5867408E
-:104A900085EFDDDB52C7AC6266BE98F2271CCF0300
-:104AA000D262E68B948949167E4C0DA459CAD093E4
-:104AB00071E2F2981E0A789D048FDE5F277D51D245
-:104AC000DF49F0DEB1D745E53BAEE4F0DED1DF4DA6
-:104AD000728630B01C28EBA12B0CD37A04702A2CE0
-:104AE0009BB12F94904B196F7EEFB3E1FB2495356A
-:104AF000E07C921C8CF4D15D79C59BC226FCB40E7F
-:104B000002FA42395DD1391E055EEF1AB4307BAE30
-:104B1000699C9641FAEC8D85FCFD7C378E17CC5450
-:104B2000500FEADD0586BBF7388EFC8996719CB97B
-:104B300095344E5EDC388EDCCAB8719CB3378AF788
-:104B4000629C21171AE7AEFC2BADF3C9ADA2718AA6
-:104B5000E2E7935B15374E129F0FBC17E3F8117F06
-:104B60007DCE67C864EB7C06D7D03857E138E34D7B
-:104B7000F3195C13378E9BC6C1F7380E18523E9658
-:104B8000057477742F24FABFE2227B4177849EC09C
-:104B90007ED9BB2E46FAC407E366A15E81C519E43F
-:104BA0005753D2689C2F9380FE6E339DB93EA22747
-:104BB000E89F05024416018840FFD4091EADD8368F
-:104BC0002BB7099FBB4AB3E7A25D72BFC73F0C4436
-:104BD000E7CCAE527D7E02FB66419BFD4497857F0C
-:104BE00085DE9BC28637C0F81DA86C4CE513A0BFBC
-:104BF00018E8ADE3A0BFF0F9B1B04F3F02FDC674B5
-:104C000033BC4D348F131AC7E389F57C1DF972ED5F
-:104C1000513B187B38CC5B8500F70D621A0BDAC06C
-:104C2000F833C959BDA047F78B8EC846A2476080AC
-:104C30000DF89CADEB07B812EDC0CEFC83B047E198
-:104C40006F800D6CD99B5BB71FC266EF2873072D71
-:104C500081F9CEEE586B1F00E533F6AE5BFD6E5367
-:104C60003FB3EDC771DE4EF80FFBB92964B7D8A783
-:104C70003FA8B4966F89B3576B947C410F31AE2F28
-:104C800062477ADD90C9E1B9059F63B0DA207ADD29
-:104C90006AF06F253CF577DA5994D6A3AE0C5688A6
-:104CA000F8C820BB2824D79538F86EB53B0341A03F
-:104CB000E7AD3F56098FF1F076ED4D0ED8C05EEAB4
-:104CC0005AF76F76B4BF2F06FF0F9759EB59988F9D
-:104CD00027F12AF9E0C6D925FD3E32B5BB2934A318
-:104CE000DF47267EF941E52C4BF996869B2CED7F1C
-:104CF000B86CAEA57E6E78B1A57E7EEB6D96F28225
-:104D0000B61F5BDA2F5AD764A95F1CB9DB525FBDAF
-:104D100075ADA55CDBFEB0A57DFDAE0D967ADBDE44
-:104D200011D7A23CAE785B65689F7DE13E712FDABA
-:104D3000575F189A1FDBD421AF811C7ED2984DFC9F
-:104D40007DB2D147CF33BBC63AD11EAF4F02798671
-:104D5000B57EAFF28770EB64D423D01E74F87EE585
-:104D6000C370189CA7D7141FF1BDBA4E6751605588
-:104D700085A5F5F075B71AABD7BAA07E6CDFF5EA5A
-:104D80003A2D61BDD6A525ECF7ACD25D80F65DF875
-:104D9000770E8676605FF603FC0DC0F5A2AFFA537E
-:104DA0003656D96ED23B27141BF1C10DCA9413A8F5
-:104DB0009F6B742EEF353B72A6A03F58A3470B1A8A
-:104DC000DC1718AF1D80C9C27EF2695E8B230362B7
-:104DD000F24BF41B6291FBA52CF447D4CFA7F6A9A4
-:104DE000A46759F440EEF746E1F88113F89EEDCA46
-:104DF000A0F5F19DC640BF8FC09F3BD6389D9EBF9A
-:104E00006F0CF6FB0874CD7B8DB3A9FC7E63889E86
-:104E10005D8D95F43CDED840F51F352EA3F289C692
-:104E2000303D3F696CA5E7C9C636AA3FD5B88ECAE2
-:104E3000671A23F4ECF103843DCAD285FD27EC7593
-:104E40005839A87C4ECC41857F73BFD59F8D727D2C
-:104E5000CEFD6501DAB9E78E816192C03F94CF78CB
-:104E60007EEB9B7E015AEF174680FE637BD7BB9299
-:104E7000387D5C36369D81FEB97B98CE34183FE98B
-:104E800095CBC95E86F71A237D19F1CFF224E81F6E
-:104E9000E79C75713AF5F0C723FF5E8CF1871B84A0
-:104EA0003E4C3AA03670BA6DF223DD4CF8E376D969
-:104EB0000B429FC7E1916CB99CDEF83C9D21F1D972
-:104EC000998B7180FB95E0081BF0C1B90E07CDEB03
-:104ED000DCEEE408C36F313832E94278E370546F96
-:104EE000751966FD50DB9E6A58F5458E61D617E749
-:104EF0008E6CF2A2DC2FC9B6191F8D45FE0808FE84
-:104F0000E07C27FBAF6DCF33DC967EACE5736DCADA
-:104F100074F48340B9A77C3F817F209F4BB275E337
-:104F20002390EF935B87A4E0B8E0C71938CEA94679
-:104F3000C3E0E3661B66BEAC599644ED257C7DF567
-:104F4000FBF7860F2D830F9D8C50FFF5906FEE675A
-:104F500033ED4F14CF61BBED5FE2BAE380FFBFA634
-:104F600078804665D96F7DBB1A765C81EFB759C6EC
-:104F700083EF7CD287C6F5AA6FBA6BEC84292E50DA
-:104F80008763907FE4243A87A0C714E8EFACE66E0D
-:104F900055609CE9361FD5D70B7EAC7576E9217834
-:104FA00075BA83D3A3AF714E361EF169A03F2A9D17
-:104FB000E091C13895ED23CA503F9EEE58911902F9
-:104FC000BEAD56CFDD114CF07DAB4DE1F044ECDDD4
-:104FD0005DA6F9C8380A63D0AF33063F72FA0953A9
-:104FE000395E5FCBE77DD82FF047DDB6A3E55701EB
-:104FF000FC75BB3ED7118EE9B6D07DB68CD8FC15BA
-:105000009C3FF453B5F5031DE7F7893D5C70E70558
-:10501000F4546F38DDD914B793F0855927DA31F39A
-:105020007AE28ABE1BDF05D1FCF49FEC6C15C0C18F
-:10503000FE02ADA0DE2E6A2B58D08BF89AD7514DC8
-:10504000F1C54F6DD26E6A2B46FE38CD6CD3717EA2
-:10505000A7D99BDEB126FC75D8B8DDCF5AB91D1390
-:1050600086FF101EB0672D76CDA275D6F242765D12
-:1050700026EA8D85F7DB590450B418ED22C91F309C
-:10508000EFCD366EEF2E620D2D68CF690EEE1FCC80
-:1050900033983600E0AAFDD5A3C568F7BF6CB311FD
-:1050A0007D649C61711A87BB2A3DA207A0FEC38E56
-:1050B000B1375C85DCE788B4E0BACC52987F0BEB63
-:1050C0008DCFF9AD56F82E067F3CBC8C2DB7C02194
-:1050D000FB9570A85B95402401DFBD26F94EE89151
-:1050E00034D56AE767C595DFB389F8A5CA54A4F338
-:1050F00069C319B6A550BD3F8AF1911D0EFF0AA0E4
-:10510000EFEDB66017EA67B00B8A98A9DDEDB6102F
-:10511000BD3FA5BCB110ED53A6458BD0BF8735452B
-:10512000437ED0053FA849DE228CC77A18AC9F2069
-:10513000970E840FFA69F154CE6445187F053985BE
-:10514000FEEEF1961F51A0EC727730ECCF916D8D91
-:105150002FBB7CD6723DFE03E9309C511C2779B8E9
-:10516000B51E162C86FCE6F15BDFFFEF1E3C458981
-:105170006FBDC4D2F074BAA32A8CCF266AA7CC76AE
-:10518000739D93C34F7E39B45F2AECF93AE60B5313
-:105190009C389BF3C1D219368267A9C7E70F43BD7C
-:1051A000A20518CA1FC6AACDEB58FD7910B97EA674
-:1051B000B2D6AD235FD69FD75804F47D912DE4512C
-:1051C000C723FE0264E73A01595F03C89A7BBAC558
-:1051D000EE6503D3C4FA3AD030CBEB40A4F3F81811
-:1051E0009DA55EB00BBD08FA224BCD403DD85D4E6B
-:1051F0007E09EB223D21DBE9B17603118EBEDAB9DF
-:1052000062EDF212F557FBAB67768601FF55CF3D95
-:10521000E005E2B34FB5B64C3FBCAFD9B2D28B7C00
-:10522000FC8916F6E2BC3F8DA8D313F1F30DAA2238
-:10523000FCB1805B417F58D0E9E453ABBF8B78FF72
-:10524000728BDDC026F55B1D510710B1AE6331E7EF
-:10525000A7AD8E0F78F9AECF919EF5BBACF256F5A7
-:10526000C4039918EF040C71BF9145C97EAEDBFCF5
-:10527000C772B447EA5937E989F8EF70FCF369B4AB
-:105280007ECDD5537AD7CBFD977AC1F7F51DAB3FCD
-:1052900057BD58B6CA77A5F047A6A99E748A2B4D6C
-:1052A0006013906E120F2CC2EDE1154F3E54F401C5
-:1052B000C0716AF33F79154BDC88EB8773EDF31F00
-:1052C0007FC9D7B75E3F23FCF9D87711FACEB78BE9
-:1052D000DBEF6C377FD6D8A35EF4976A36D8FD2013
-:1052E00099ACE6994DBF7C04F9FA770E8A33543FA6
-:1052F00073E89D2BA15CBDDD9E3E934FC3AD64C69C
-:10530000E8510FFF2F1B13C37FD5F38774DF28FEEF
-:10531000FEA769313A546FDFA7B351BDF156DABE2B
-:105320004FEF7227A047FB07E5686FAF78F22B1DA0
-:10533000E5EAD3BD0ACBCAEBFD7DE5864364CF2108
-:105340009E887E823E3DF4EA45A7E8775F1A47EDE6
-:105350000C5CBFFAA2D3485CFB32888F9F7D09E3C7
-:10536000F7BF77F871FE95CFFEC88BF3F8586BE066
-:10537000FCFCE8CACC008C5B690F671AF4E4EF2BE5
-:105380001FBB9DF86CD1D1DB33291EC00239365AC0
-:1053900043C33938BF05EBAFA7F92D6421E2B7CA83
-:1053A00047D56004E3591A9BBE3D813CBC21E4E132
-:1053B000E38D0E5C7BD8C7A860D13F7C53A57D02EE
-:1053C000C66EA378C3ED721F822DA1F2174E4EA7B1
-:1053D0004DAA4DC6379C163EDD7C5727D2E7E4A088
-:1053E0004016C627010F61812F05F58E7A746A1663
-:1053F000A70FF369C5E23BD08BA5F81EDB77DA0374
-:10540000AE22CB77621DE3E32F15E303DC49688FFF
-:105410007D9C09F64D82F97DA54ABD0CF68689BFB3
-:105420004C72CDE57CF3DD5CAEA59C47664DC7FABA
-:105430003FBDC5E507BFC3751DE08A6651FDBEEFE0
-:105440002BA4071C2C9A489E37DB853C5BEBE5FEC2
-:1054500024C0ADE1FA14E313E83F8DF04F76DAC2D1
-:10546000FBE13B935EAEC7F1A89D1E7B6F5AD71739
-:1054700009F97F5515FBA342FED97A2EF77DDBBDD6
-:1054800061EE1FD823BF7C04E515E413D7999A6712
-:10549000EC419CF767DB0EBC7333F0F567ED524EC1
-:1054A000AD7A335E4E2B778C6789E4F433B79F2552
-:1054B0009453789F504EDD5DC4C7FFD97A53E2ED17
-:1054C0004C9CDE947AB02FFCC5EBC135AA2FA11EEF
-:1054D00084BFB758716FBE93FC26F9ACEAE9DAC114
-:1054E000143792FC28F9AD871F25BFC5CFD38AB7E3
-:1054F000F8FA1785BE9174B62F67610FC64BF7A8EF
-:10550000E45F9F05985A80BE67B7E54530EEBCD290
-:10551000C5E317678D6E6F1A3C57A6F2727786DE69
-:1055200082FA41BEEF76F1F8F6D960B737D5E45785
-:105530007CB05BF5FAA0BE2BC2A627F23740F3126F
-:105540001C5DACAF7A1E0F9EAABA7397A1DFDEA6D0
-:10555000D27E7645D38D5EDC073EBB7BC8CF513F04
-:105560002D780D0C4C80F72CDA812938BD80867996
-:1055700009F305BD3F61E10727C3FCE6EFE6FE4204
-:10558000C59A38FBDEBD54477D03F6FD716B5C9B0D
-:10559000F34D95E8A772BDB5BE8AAD21BA55C5F1E8
-:1055A0005148F8811334C147A3D968E187F1F885E0
-:1055B000D05753D5C29FA39D71F6088F2B9EDBADAC
-:1055C00012FECF6D532218F7A1F8EE24A47FB7CEB8
-:1055D0004CFEF229E437BD6F393EF5C21F8AEF84D5
-:1055E00026353BDF2DFA053C4FEDFC5DC1CB58FE67
-:1055F000D56F73DF65BDDB97EEFD33ED1F9FDDEBF0
-:105600002038CEEE7D35F74E2CBFE4F0239C679713
-:105610003B68FF2CBCD7131986F58380DEB86EEE8D
-:10562000F9AAA88BD69D66A2D33C8DEF779CDBFDB3
-:10563000EFEF2B987FB0DBE1C379D4EFE57921F56B
-:105640002FB928EE7276CF57C521F7DF6F3E753A36
-:105650000B11FF79D8EC1DC8AFA97C1FA0FEE5494E
-:105660009B9A703FBC639F8EFB2BA5AFFCB508F5E2
-:10567000CBD91DDC4E3863EF7A0CF7416BB5A1CB6B
-:10568000ED28F768B3F507BBD3BE604AB830115EAA
-:10569000381ECE021E705E80974AD48B7DE1A359DE
-:1056A000E3FEE67F3F7C7C7E2B8E5FB37B02C94DA1
-:1056B0000C2F4A80BFF7449C0ACD9FBFDFFB5511DA
-:1056C000DA3D9FB537D13A7EB1796FFA1F376F2532
-:1056D0007A29F3DEFFDF9CFFA76B7C5D8A9783DE70
-:1056E0007CFEAB3BA8FCACC74FF05EA2FC1FFF9F4B
-:1056F00046F71D4077EFC5E9AED8FFBBCEFB62741D
-:105700007F4DD0DD63605EC1D93D7FA578B99CFF38
-:10571000C5E6EDFB7F74DED2FE5965F3B7E543FBCA
-:10572000352CDAE90338570EBFAE0DC34CE0260422
-:1057300013D923413BF78F5485C761D8201E1762C8
-:10574000C29FA014301FC65116925DA7B95BC8CE88
-:10575000649ABF3300F85835729E9F7235D89863AB
-:10576000212C0F9CECA7F8669C5FA58DFCF611B46C
-:10577000EF9B9B003E18A7D9A319602931FB705BF2
-:10578000D45144CF0FF079978867D90DDDE257B82F
-:10579000E3FC0297CF5AEF10FD3BD97E03F3889CC0
-:1057A0007E8D45B01D6B0B9BF3071CCCF41DD417ED
-:1057B0006200D6643F7E53FC35F5E06F4C6700F124
-:1057C00037C246712D4AEA237CF823AB781E85D375
-:1057D0008ACF964EC4A3C6C0FFE3F322BF91097FD0
-:1057E00051135D68C36D0197B59DF08B2E4A1F4E16
-:1057F0008FDC1A419F25167A48BC5F802E167A48A6
-:10580000FC7E53BAC4D3231EFFDFB7F3B89BA49327
-:1058100025BF2383FB2151F0435EDDB689E21DA73E
-:105820009FFAE0BBC8A7D52FABCC09DF9FD9E661B3
-:1058300051945F2DA2A33F55D5A1268CF34ABBBC42
-:10584000FA390FF179D50E4764267C5FB5F3C32290
-:10585000B29B96771F1E807181A7144EBF7057119F
-:10586000EEDB5569DC3F88EF6FBD9DC7054EBD98E7
-:105870003C1BE30FCA569EAF58D57EA3DD61DA7795
-:10588000FE5F769EF70AED489EC34F2AB4DEF4868B
-:105890008FFB05A79E54387CBBEC11CC7BACDABAED
-:1058A000410FA15FB9F5738A63973EF78CB78BFC04
-:1058B00045D5EA3F6F55899EF024BAC5FBB1751DE9
-:1058C000B5E427D4B50B3F31CE8FAA7E6ECFCE3054
-:1058D000A0A6FAF927BC187F39D9B9C54BFEE956FD
-:1058E000EE7F6A6E2DB17F7A31BFB4FDEE847EE922
-:1058F00049FC07F813FBEC71FEFCD67E97B67FF9E6
-:10590000CC178F619CF4D48ECF1E43B86BFEE3DFBF
-:105910001E43FB9EED75195B60BEF54FBD4DF12634
-:10592000F9DDBB424ECF0C62E11C6877E6770ECA08
-:105930001F39B3E7E35CF4E7CE6CFF7326FAF54B4F
-:10594000F74CCDC2792F7DA1348B259077F944BED9
-:105950008C5C429C309E0E073A0E901F72FA988320
-:10596000FCBE9EF8427B2D8FD7F8445C615BE23829
-:10597000ACF487EB3A3E2CE7F131E1175F2C8EF067
-:1059800016D0F18A4BA0D73611278AA3D769FC0716
-:10599000D0E5AB387A7DC1428FE7E03E6447BF3E39
-:1059A000E308D14BC0938CEF1EB6076C3ACAC18E88
-:1059B000E41E3ACD443A3DF3452EC6C33FB177933A
-:1059C000DDD3BDC761A07F5FB5E7B72417675E3839
-:1059D0004AF15326E2AC6758CF1F8F8B29627E9B1A
-:1059E0003D3CFE20F08DF1099F97DE8B3804E75790
-:1059F000199FE82B2E314117794F22EE5CBBF95DE0
-:105A00009DC5C579948948A70F2CF17139EFF8FE2F
-:105A10000CC4C304737C2D71DC47FACD313AF1B864
-:105A20009A8C9F9DD920E26EF07EE018F407791CD5
-:105A3000A33EA2FC96259043195F1BA3C7C961E44E
-:105A4000D2E26A1783F76FC5C7309DAF0B122FA73D
-:105A5000FE92580F7F47E7723DDD169AA99BF6B379
-:105A60007F28F65924BE24BCA7441EDEA9A7548A69
-:105A700007B5B41F207D1A2FCF757D9C83B855E7DD
-:105A8000F1D6BA5DFB8A50EF9CDAFF22F15DDDB6FC
-:105A90000FF430F47378EBF33AB727399FA39E8E57
-:105AA00098F4F4A967F715F1B81FCFBB8DEFBF5A73
-:105AB000F45FBFDBDA7FFDB6CF2DFD5787DB75BE08
-:105AC0005E5E789C935AE0469CEFC94E3B437D77DF
-:105AD000B25D9D1E496407EA76CB3E68CB519DD6E8
-:105AE000AB716F26517EEED2A3D3DF4DC17D3A104C
-:105AF00033B47F3B9A385F75FC2C3000E9D271F4E7
-:105B00006615D78D9D8847931D5CFC5643A907E415
-:105B1000B5F8BDE03864AB783D30E198CD02378C04
-:105B20009385FAB819FAC17C7ACC1FC2FD51D55BB6
-:105B30003E1DE1510D9BE14AB87EF2FEECEE2043A2
-:105B4000BBDC6E58F395B3AF1371B4A8356F3D5BF2
-:105B500067C3711F9CD992FCB81FB0644460F421E4
-:105B6000CCAB5F904D71E29CEFF1EF4E1BEEB0EDD0
-:105B70008AD8BE6DF279E81FF3606C91B573E0BB13
-:105B800064AD5DC17D007832A4CBEDB6D0463D0357
-:105B9000DBE9CC07AAF1315DD128FF429C7B91FD66
-:105BA000C9767DED07CB7348AA807F88D80F1EC4C5
-:105BB000BA14DC0F5EEFE1E79106BBD3E9BCD12656
-:105BC00061AFF970DF15DB3558D7ED8B9E476AB5AD
-:105BD00096D34B4B6E1BEC073F58BFA354037D90ED
-:105BE0007E63C9F60106EE4BDF5F8A79F7E94F94D1
-:105BF0008CCE81F26C475119D5FF4BC9E85C28FF68
-:105C0000A8755219D5572B9417B847EF2E0DBB63C3
-:105C1000F29901C62DE65B80DCEE47B93D1D3CD50F
-:105C200082B5B5D77FA9F3F3302C88F31F3491CF19
-:105C30007FA0FBBDED38DFC1B6AE26E4BFC7F77C61
-:105C4000958AED7CCCA0791AACD9C07D797835F1F4
-:105C5000EB0BE4FFC4E7C1487E7F2E39F41B84E3DD
-:105C6000EE79C31F2A479D5AE3273E8ADF276646FF
-:105C70003AD1A542D005E1749AF2902BF12402E9C1
-:105C80009B3203C751C235EAD7977F73784E487E5F
-:105C900011E7C04CE7A43E45381F4E0ED133FE9CA1
-:105CA000D47E3DF819F253CEC2F3B908BF3CFF547D
-:105CB000BAC84D718173BB59C491407EE4736323AC
-:105CC000CBD086F65DFFB623F4671C37FF15DF8E59
-:105CD00023D0DF1515BA1F53D7AE58362E431BCB32
-:105CE000F884D09E1074CB465AA27CDDC1F8B91C52
-:105CF000871240BFF1EC8F0CD2BF032B66925F710D
-:105D00003639AF1DF327CEDEC9F300608557500E3C
-:105D100006ED4E89A2FF037CFC651C1F7F695D6751
-:105D2000ACE39EFDDAB7AB8BFA33447F60E864A244
-:105D3000DCF0BFB32AB7B3CF36FA080E300BF7E169
-:105D40007A7AA9E3653BACE7F400EFFD1D26BCE7DA
-:105D50003AFAA45F9E83D38F9EF1F45BE86CC8454A
-:105D600039AE0AB697A36BFAF1C23B8A91A9DFD686
-:105D7000439761FB9AD99D8779CE504301EEB3F5E5
-:105D8000A62F3F8F95B97B6E931DE315481F5F6F5C
-:105D90003A5EB1CC9FA1F5B3D0752CC27FC5EECFD2
-:105DA0006D08BFA4E74322CF3FFEFB6F3914316E6D
-:105DB0004D931DE324BB74B267E3DB4DC74355E34A
-:105DC00063E52267318D9B65E3F18EDEEDF9FA170D
-:105DD000EBD749E7B2FAE2C72283F707F8FFB61913
-:105DE000FFDFED1BFFB3B01DE09F9EDF00FF3762BA
-:105DF000FBBEF02FEDE86AA117AA711F05F8E88F26
-:105E000081EB3287C2F8E5AA9BE460F11695E40FB6
-:105E1000DACFCCC98CE991C5931AF6E17C173FAA79
-:105E200010BF568873A69F89BCFEF87CA885B3C3B3
-:105E3000B4BFD32B2F2A12E7D7C5E5BBD7C7F87657
-:105E400030CF53E3E7B6542117A58B0A53D01EDA9F
-:105E50006BF7FD0BD9D9AFA96C6302FC6F402633F9
-:105E6000D1755083CD9227CB2A522DFD962D2AA491
-:105E70007DEF251EDF05FDAAC1CBACEB765ED87A9F
-:105E8000CE6848ABF59CD1B0B6FE96F697ADCBB7D1
-:105E9000D48F888CB4D45FBE758CA53CAAFD4A4BC8
-:105EA000FB2B764DB1944747BF6D693FF6C8759699
-:105EB000F2F8CE9B2DED271C9B67A99FD45565A9B1
-:105EC000BFEA932596F23F74FFC46AA7D818E94742
-:105ED00096A490BE3CD8383117F3B1D938A50CF14F
-:105EE000592AF2090FDEA6DB0C2F3E0B6C06E8AD3B
-:105EF000FD0B66D2BA7FF0B6CC808F9EC501F46BE5
-:105F0000983A795CA27CCDA9C6A45C735E54A9D3EF
-:105F10006ED16F530D6B79A743ECFB0DE67CF372EA
-:105F20009C7CD91B2647C13264FD170FCDC2F140BE
-:105F3000CEF60A3DB7F792F45C6643319641CE0E39
-:105F400026923326D6D912C14FF00CE8981F59E695
-:105F5000A1F538802F7DF43EAC81BC4C71FA071E50
-:105F6000C279D9FCE9C88465B38307797F625D662D
-:105F7000C36DDF645D96729E6D13F96B693C7FEDB6
-:105F8000E1050529CC84DF3F386CC28E6EE34FE318
-:105F900088AB276F35DFFCFE9324CD942FA72C9A76
-:105FA00049F922D97DE8453D3B7FC666D0C77A8E48
-:105FB0008F9EF27DCB6C5BC23CB06EA147A5BD3518
-:105FC00022666F75233D4E67BFF920E629D5CDE9DE
-:105FD000267B2BDBD676DB619CD7EBAA885FFAF8B1
-:105FE000F92A61272F9871DF6D87715FFA9F87917A
-:105FF0007E92E3AC6F9C3E43339D231FD887DF74B2
-:10600000B993C3F358E3F0191594B76DF0F3A2A256
-:10601000FFDC706D39DACD8345BEE983B6C4F92E55
-:106020006ED14F16921CE135DC2427A717BEE7D5A9
-:10603000601E8FC0EAE5C47DDB2B3A8BB91D16F0DC
-:10604000E339D4DCE82D0F62FBDC6C8DF25DE3C735
-:10605000CF9A136ACDC3F8679ACDEFA672B782EDD7
-:106060001D3F65AC1FB46FFE0F95E069DE3F89F2FE
-:106070003F1CEE0686FBA9725E07D21E21FCA81DFE
-:10608000C9B40E32B12F2EE3AD5F645774A2BDF1D7
-:10609000C5FD761AEF0B98A301FD7FD1A1D2BEEB0F
-:1060A000E1B4A4A80DCA6AAB87D6EF5CB43DA1FDEC
-:1060B000C20E4FC49717C38BB66E329D87710CE426
-:1060C000F36F4E7347DC7934EF749CB78453CE7B07
-:1060D000501F7E6689803BE7B29E731A0CF95835D3
-:1060E00034EA77412A3F8719699C28E8659D4F4B20
-:1060F000F675D7DE84E787DE5219A686F8BADA6825
-:10610000FE0B61FE115F6FFC9EF6E57D695309CEC3
-:106110001284535D574EF3A076F05DEDE30A7B24C5
-:106120000FF930349DE8DADF46E7027BD9074E2EBF
-:106130005F339C3C2F57CF2E98B1B91F3E87925C9E
-:106140007CC7D9E7BA1F74727D44CF6F70BF00ADB2
-:10615000FF521FA9019BB073B95EEAB19FF4D00F43
-:106160009C19B1B29AF2D322ECB76FFB6CFB3E1DC7
-:10617000ED333723FB59EACDBEEC33B4CB90DFA42B
-:106180005DB6386E9E30BF1A31BF9A44F3EBA56FEF
-:106190006F6E9076CD12E705ECCA0C3DB13E7A5297
-:1061A000D0A1DED019C59B688D02BDB3D846E78D5E
-:1061B00099167199CF97AF774ABB6EF73E1DF10CD8
-:1061C000F3463C6783FF5C4E7AC79E302FFC62FE2D
-:1061D00048FEEAC21D47B03FB07311FA736DBE941A
-:1061E000B40BD817F665AFBBCC78BDCF29F2B96335
-:1061F000787C40E0F18184784C073CDA2CF6E1CEE3
-:10620000021FE1F117CE0BD887A7BFF77E31AE474B
-:106210006704BEEA7AFC5CAE9FFBC32285F1AA5AF2
-:10622000CC5F76F232EE07E15E0CC6E18A6CC127E4
-:10623000B0FFFA5DD673873F73F2381973F373B307
-:10624000B2BF4CA1EFC1AFFED61F7DA4F7FF11E78F
-:1062500013F3AFBB8AD1BF5AF1C26529689795ED98
-:10626000BCC9C0E7B9F4A1B49E9DDEE908209CA793
-:10627000D378BEDEE99D130E63FCE1B3C623F96655
-:106280007D7FFAD9A3C576E8E7F48EA3C51AE507A2
-:10629000472C7661EDD7BF29C6735832AFBA875FF6
-:1062A0009C7C9DB8DFC5E31A19997A0BE68B9F4F4A
-:1062B0004A257C3D9069BB3751BC06D527EDDB7B79
-:1062C00074DAA75C32C2B7C28DF19A3C83F2705780
-:1062D00028819C05B8CF32CBE9C77D80F47C363C61
-:1062E0002F055118626EC0A7E3601B1D374DEA34BD
-:1062F000F6A17924E3385A29D7B7DDD7EB9437963E
-:10630000ACF91E9A03E5ECD91AAD7732AEE348E654
-:10631000E792655CA7079ED7ECB40E2DC90BB59527
-:10632000C0774B26A5D177DE59EF10BF9CF5D9C2B7
-:10633000769C8FD64DF19D9F370ECF180A78347218
-:106340006C33C8A6F90B60CB94FFEFD5583805EC39
-:106350009BD5C0FF4381FF3B1A9DD4BE05EC432370
-:106360008DEE4988DDF361929B1D8D06B5FB65635B
-:10637000367D775FA38F9E3D7604E3DF5139817EC2
-:10638000FDCF7ADED3C8EF1391E57F1B07761AD0D5
-:106390003B7D025015F0922ECE9FCBFA471A5F1B21
-:1063A0005236542003F0D9BFC6D8B0EA02F0A63B5B
-:1063B00022A978C4F872170B974DC43CBFEE7BCB73
-:1063C00053F17CC45D656523008FB8BF7D2590CAFD
-:1063D000755F339E4FCDA9F13561DC2F6797D28E63
-:1063E000EB57CEAEB525B88F00EDE8DCA0EC37C397
-:1063F000C5F55CF2818795FC51B8B9C0F7E5D99E27
-:10640000E448A2F3A5E35C5CCFF95D7C7F70B5D86E
-:1064100057EF9EE526BD987CC045FC92B3FB72DA2F
-:10642000DF73F7B1AF1CDF4FF2813F531CD8ADB41F
-:10643000EDC37D4AB680DB9F929FFAFA0EDBEB97A5
-:10644000D0FEAC5FA3B83098BD34BFD3B30612BE44
-:10645000B1BD598F9FD513DB650181A795F6C47136
-:106460007A8DF171C67576D37E26DEDB84F8CE791F
-:10647000AB4D417FFDB4C2F331FA033E764039673C
-:10648000721BDDEBF49C3354EE82EFFE641C2B5840
-:1064900009E0B80A7F9F8BDF497CA845BA13F5490C
-:1064A000CEEE0FF8391F5B978EF96F8BEE7E9EE272
-:1064B0008FAA1ECCE3E5952B313E99E10D6E403E4F
-:1064C00061E1E7CB0E029F3C20CE2DE31BD47BABDA
-:1064D0005DA21C6E6F0E009FACB6F3F2A2BB9F23B1
-:1064E000BE596D0F2EC673CF586E86FE57A7B6677E
-:1064F000DBA0EC6E7AA6F9C8202CCBF6CF34872728
-:10650000831DEA92FA39988378EF291B501E652A79
-:106510006BBCCC9CFC29E7577BE0CF870700BFD43E
-:10652000EDE6F7DCF4E06DD75A05D7A35F361EF130
-:10653000356B424EA4FE8075FEB26C467E8A1E51BB
-:1065400022F90ADEF7D19A69CE57F941B222E21652
-:10655000F0BD39FE1877AE8D8ECAE0FADCCCF3427E
-:10656000E2E9FA7652495B52069E470DAD52510F51
-:106570003E633728AFBE4B23BD7D4AE6D537D8C929
-:106580001EAC11E75CEDCB43AB46A05CDCA2F9315D
-:10659000BE509DD75682F650F58B79FE2616CBD38A
-:1065A000AD4E6DCF1CE38EE5E9CAF20A1197CA4AD7
-:1065B0006D484D2DC4FD98B5B9B85F52C7DA6EFD70
-:1065C00009C2FB86CA90DF3FDD372905EF1DAA858A
-:1065D00032C6C16A3B8EEA2168776512BFEFA6AE6C
-:1065E00003F8C6CDEFA1091430B641339250CFFF66
-:1065F00032D030124DE24DAE5F97B9FE81B127F235
-:106600000306D2F995BB8F353BB1AC1B23D8682C60
-:10661000FF6B33F259F5681BE559B2F0BF1E0C0C45
-:1066200015FBBD506E750D9A6A8E7BE7887386F5F3
-:10663000EBDD741E0CD6E58DC8DF75EB6C61DC3FBD
-:10664000B3393BE91CD02B2E26E8633D3F75BFC212
-:10665000F56178018FA72E9D91F66D3A3FB532DF37
-:10666000085F20AE5B793E89CE49C9F295493EEA82
-:10667000BF520BD33E52E5792F9DAFFAFB8DE7B4A5
-:106680009CD7EA3D9E9BE091E3D5C4C623BA1E1871
-:10669000F3FA8343816E4BB7DB6D0E13DF2DDD2ED6
-:1066A000F6E75D812CEC2743E77866E80F02AFD16F
-:1066B0001D37BC1CD6B241FF4BF90E9F6B2E9B8C35
-:1066C000748BD533ABFC07D01FBF274996FFBDB9EC
-:1066D0006C6082F64971EDF365FFEA4AEC3F1E9E5D
-:1066E0008CA458D909EDB5BF3A7ACA08DF5A5B5C69
-:1066F0007F69B2EC5E89E34BBE6ABD3BFD5018F882
-:10670000EA9ED4B612D4FFDD0B980FEFD1427EF58E
-:106710009BF46DAB8BCB75E5F97C0BBD63782FB02B
-:10672000D0E5E3C66CCBBEE7A2394B697FB6D52571
-:10673000E8C5C2FC9CCDFA012C628A07FD7F38FEB9
-:106740005638AEEC038E6FFD17C3E1B38C1783632D
-:10675000A805BEBF158E8D37147C3B0F9A3CA084D4
-:106760009DF9B82EFC8CE7C5A9A965BE26DC97F972
-:10677000994671FD618CE7BBE46BEC883606E5A7B2
-:106780002D807110B69CDB2BF0BED53E86D621F253
-:106790001786EC76CCC5BC8DFCCAC0627CB2818504
-:1067A000B4EF23F749998813CA7D9E61062BC17BFC
-:1067B000FF8E27CDA5752A3F38A71AE3EAAA675CA2
-:1067C00012AE870FD822611C2F7C1F1F2FC31669A2
-:1067D00077A2BDE41D6AE07A97E1E5FA8FAD2AA4BD
-:1067E000F56FA32D7FE46D00C74AA524E935C47376
-:1067F0006A3EC5C7F13DDEB3B351AC5B6AAADFC0E8
-:10680000756AA358B75608FD2EDF27A705E7A21D16
-:10681000F1F355D3A63A27A11E0AB4F683F5E6DEB6
-:1068200055D356664FC2F5C697EF84F5E5DEA469E9
-:106830002B9D30998D4DBEFE466AAC3CECAFB05AF4
-:10684000939E98B632007AA7D9BDA40AED1CA83F42
-:10685000847EE2136952EFF0FA7CA9A7502F811EC3
-:10686000539B7ACA61D44BF93D7A671AE99DCD8F63
-:10687000A9545E0AE3A11D03F308E3FD60DDC33400
-:10688000F28F5C004B12945D23F269FF0CE6CD920F
-:10689000D0FF1FC1EBE57E873ECC46FB1DD81EF125
-:1068A000E8CAE1EDF559FCBCB4EE7193DF26F74F71
-:1068B00054B17F9724F254146316F9C1CE35639610
-:1068C000A01FE51C6ADD9FD6E3F259D4F8FC1677C9
-:1068D00094ECAEB62411BFEEC7B2E9DE04F11E2C73
-:1068E000E531F8CCBCA9B984EED3F33003F3A9B3F6
-:1068F000435166B697E4D301EBA8CF24370E370B8C
-:1069000024CAA75898CCED61F7798DFB890AD8374E
-:10691000B88E7A841D2EEC23BBBCE7286EDD95F67D
-:10692000925DDCA7B774C6942C3C97A4BA034EB40E
-:1069300073F61963689F4665FE6B4B4CF64E737495
-:1069400006C5273523C0D0CE795DD839AAE1676660
-:106950003BA7A5111C7058AB361517D0FD358FB865
-:10696000A2CE2148DF076C7ED41B07C65485158C48
-:106970004F2E6324A79B8A33A7E03EC3062D98724F
-:106980000BCACB5B309E8FD38DEF73AF50309EFE22
-:1069900085339882FAE09E5466F1A3AE4DE6FEC8B8
-:1069A0009624AE7FA49FD002F044010EEDFC48BABD
-:1069B000CF67B4B04BF53965142FC334208C7F3AC0
-:1069C0005803E587CAFBEA1CD9364BFEA376BE887E
-:1069D000E2895B92F83872DCBBC47D83B2EC640D53
-:1069E0003C6E0C3C9EC87FAB15703AC01EF2917D88
-:1069F00012B7FFDFDB3E227B45D2A7C74E51F8B965
-:106A0000D0BEECA3FAF3368B9E8D9D67D7492F9F9E
-:106A100011F705C83C10B7D0672DD9A1B6ABF2620B
-:106A2000F70368221F648DB81780656BDDE673F885
-:106A3000C9188F81FA669117921C77AEDFE55E4A1E
-:106A4000FE826BB8663907E66421FACEE1B3BED7A1
-:106A5000B2E3EF0B08F7E48151DEA2C61E56E872DE
-:106A6000006EEF0E107958A793DFA77823D8BB07E5
-:106A70009CB42FC1CF89CA78D837B58F5F47BB8AFE
-:106A8000FCC2E9A3B1DF45B81E613C9B0573F8A6C3
-:106A9000633BA3BCA1247F17E3778E91BDA54A3D3C
-:106AA000177EBE19FDA80CB37D67B2D72E5FFD7CA3
-:106AB000737321F91D545E74771BE9C1952E595EDD
-:106AC0004D6558AFA2E8F7B09D0E1FF2137C1F4032
-:106AD000B961371490BDACE6834B0B7097E1FD872D
-:106AE000B83FB0D3B111ED59F06BE7B94C71B2D3E7
-:106AF0009E63B9AC30617F614B7FB9DFAC3F18BF9B
-:106B000003F38C647D99775D54E5DFF9F03B36B093
-:106B1000F3FD30F4FFC00B0EBA9744DEB31CCFAFC9
-:106B20005392B9FF8E7AC39CCFA9CFA90820734A8C
-:106B3000F974642759F2BFA5BC6AE787937CCAEF52
-:106B40005E4FE2FBC79A16A0B89A76BE90E47F8BA0
-:106B5000A06B4BA3719171D2FA18670CF5D3F7387B
-:106B6000C5424F30B13FA619E67B64FA92D7F8FDD3
-:106B7000C078FD269F52BFED15FDCF4DB6C697AB31
-:106B8000D6B51F4616FA892D54913C1EF3BEDEF38E
-:106B9000E2525C638B16A1BCDDDEFB7D1D4EEE4731
-:106BA000224E50B0F5B6FDC8AE0DC9A1F54950AEA4
-:106BB0004A16FB00D9B0AEA9B86EF1BCA587B11ECC
-:106BC000F31B42BE87A6A29E9A554EF1EBE7928335
-:106BD000BFC1EFEEBEAE98620512EED58D3CDF4E22
-:106BE000EA4B37E20BDA3BB4061EF77407A2685F84
-:106BF000DC97FCF6540DF950E372B06CF5FE951875
-:106C000017716A7EE22BA7DBE6C3F5DD09FE1DAE38
-:106C10007B4D6E1BC59356E03DC0F0BE599969A0EF
-:106C2000BC2EF1E467B10BE847ED7CA6D0BFD67B64
-:106C300075FEFEE3A4D3F7BDEEEF3930298AFD6976
-:106C40007E46F93388840F4D7A55AEEBF1DFC5F7F8
-:106C50002FF129F1EBD04284571DED8604703D9948
-:106C60006CDDB7CD92FA33F59D8228BCAD55BABC28
-:106C7000689F805E7C12F9A46E54F7AF151FE9D3AC
-:106C80004C6ECF84E57D0596FB91645C5E7573BBAD
-:106C900046C2BFE4B5079CE67DA77878E3D74B777B
-:106CA000A1353FC3393029EEBEE0263E8E1624BE04
-:106CB000B14F0E38514E9A8C3106DA2BCD9AEFB780
-:106CC00001CA2BB193DD0C76B8657CF9BC47DC0FAB
-:106CD0007C54D851F1F51E719F72FCFBCF85FD707D
-:106CE000CFBE9B480FF7453F3C508DF4F5E433038E
-:106CF000CFE7D805BCDE8BF4DB171FDDBB8FC77574
-:106D0000B589CE08BA58F1E3A9F66000CF93A9A3DC
-:106D100019D9BBEA203E3ED0D2C0B8B0775C1A1B6E
-:106D20006E5A67EF1E7A1DBFDF39C3A0F37DAAC775
-:106D3000164C64674A3C1D4C96F75470BEC9967C4D
-:106D400033ECF7740FBA896FBA13F1CDC164AEAFEB
-:106D5000100E333DEF1E9A9F95883E31BDC8F9EA6B
-:106D6000627CD121EE4BAC45DC807F5323CEDB9F90
-:106D700012F704CD4B16F70519DC2E96F75F7468F1
-:106D80008164B4ABE6F5EC5307E85C4A8D2B903296
-:106D900009F9F228B77B3F2EE1F7967D6C0FA4200E
-:106DA0009E3F3EAA2A4DB4CFCFF302659ED5C7764B
-:106DB000DFEA91503FFF176AA089AAADF6DC2916D9
-:106DC00018FBCF68DFEE5269FF28EFBEB9EA2868EA
-:106DD0005F01861EF2D1BC527718D7DF8EDF37BC39
-:106DE0008F7A68FE630EDF7218E7E0BAB15F62F96E
-:106DF000C41A8FCF4171B27C05EF155FBA36CFA0B0
-:106E0000FDA3654CD81943CB4B8732F614FE53C60D
-:106E10009D9D74CFB8A80FB694C1FC466674D8DCAB
-:106E20000053C41D6CC1734E2B9B82D9E8FF5DBB20
-:106E3000A6A005E38F999981CEAB411FAF5833BC13
-:106E40001CFDC18E47447FE1112DE8EFBD6C0BE5C1
-:106E50002950FFD49A29E594973B44F67F03D5CF78
-:106E60007BFCB22F8F1988D3CA728C9915CF91F001
-:106E7000D49697826E5F30599697E8584E4F669633
-:106E800038983DE64F529CADA3C77FBCA31CE3607E
-:106E9000F3A734946AD07F9EE7A72D85201A13DAD2
-:106EA0004A8C005E99EBB9AF3C39036FCD0B54E3CC
-:106EB0007A32D2737F39CE27BD9FB5FF7455C45344
-:106EC000D9BA16ECAF07BEF0D6168CAFCAF66FDE95
-:106ED000F34E4B78608CEFBF1BBB5FE93BEE0CBA07
-:106EE000B7EE3086D8729775EB3C9F57E4DF0CEC19
-:106EF0002AE27945A23CBC8BE75DCB72362F772C1A
-:106F00004FBCCEFFDCCBE5AD232971FDCFDC5C5F50
-:106F100000DCA4E7538EB1C0B6047254E17653BBD3
-:106F20004360E739D362F274AD83B18998DFE4E45A
-:106F300070CA7EE2BFBF538CC3C2D7A6211FCF1435
-:106F40007C3EC4AFF03CA55DC911FC3D06F0B2B477
-:106F5000EFC17CB68A78C45617FBE12C183A338906
-:106F600085F0DE9C8C7E502EA4EF03DBDDB1FEDECF
-:106F7000E022CCA60E096EC6FEA666E58C5E9117D1
-:106F8000EB07E06E768EB1C0AD4D4CC3FA707F8CCE
-:106F900093F4E0B390CF03F884F005C33C8DBF1F9A
-:106FA000D0D139321FF5EF484CBA31E9F9E2CEEBD6
-:106FB000E83CCD52AFD81FF1F1EF334A79DE4BF701
-:106FC0008BC9FCFE4C676781793FEB21B7C833B8AA
-:106FD0006BE643740EBAD3CEE8FCC2F6920BE61D04
-:106FE000D6605CCE6437D66851F2C76A302E371649
-:106FF000FB7B83CE1F623F3E117FC6B85AC68AC450
-:10700000F497EB60CD798385FBF5D697B1FED35924
-:1070100078ECC5E715EBCFEA37F6EE4F17717C81B8
-:10702000774DE05D4F0CE75EC9A7806F9B89BF1667
-:10703000087E93FB8167768ED868DE7F95E7864071
-:107040003F3F8DBF8F10EE4C227FA5580B5C83ED28
-:107050008B3BD3687F40F287E40B49D78EB4068A16
-:10706000B7743FACD039AE78B80E49B8D6F17BFBD7
-:10707000B2E68454F33DE3521EA0FF0ED1FFB8895F
-:10708000243F8F727900B9B905E517EF61C179F82E
-:10709000BB8ACCBF4720E12F425E1C4F74E4F87FCF
-:1070A000C125F25738DE7AE3BFFF45E8994BF42C4F
-:1070B000EEDC4FF3ACE9436EABBC5E9EC7762CEAC8
-:1070C000F541BB3182FF3BDA3FA47BC53A76A94C40
-:1070D000F1F179A3DE2AEED1C7E35F9D02FA38AB66
-:1070E000A70CFAD28774E8D19F51A733D6FE07DEEA
-:1070F000F1D39A515F8A7B7BD355586DC6C4E0F8B3
-:10710000939BDB57134389E3580D5E8F458F3DBC3E
-:107110006C0AFB10E67FA59BE75F4DEC0AD3EFEA14
-:1071200048B98ED753FD3C9C8E86E7FF929E725DD8
-:10713000444FB9A49EE2EF0FA1CD3B06D7D7AE22B4
-:1071400005ECE60A5B2013FDAF8F8EFE84CEA72CE4
-:1071500012F939A3303F07D7CD63415A573EC54A8C
-:107160009EA733D09381F9DAD63C1DB6999F6B8DDB
-:10717000E7AB181F8585FD26E010EBC1B58EAE6725
-:10718000793CC32ACFB20C70D6D98698EADD7CDD73
-:107190009274007A37D33DC7428E8FEFCCDA80FAF3
-:1071A000F64D0FCFB3491F12188DF3977209EBAA52
-:1071B000E013DB0FAF7373BD715D02FE9DECE17AEE
-:1071C00076C13ACE371DFFBBF41AC47BC79B69A9B1
-:1071D000CB4D7AA24CC8B1EC57EA21F99DAC9F2265
-:1071E000FA9BE6E17251E6E67C877024CA272833D1
-:1071F000ADAFC43FAD9C7F60BE61337FBF29FA8DC8
-:10720000E153ACAB02CFB53AE017F0B7D51EEE8F25
-:10721000F949C59D36EAAF629787F2322BDA391EFB
-:107220002BDAF6D9AA4DF889EF6FA987CBD1067171
-:107230000FED211BF01BE2DDCDE13BB33387F4E71B
-:10724000220FB71B2EBE6E5C9A9ED920F23180BEF3
-:1072500094BF58FBD2800D563DCDFB4BEF175A81A2
-:10726000E7F0D21F627ECC29033C451580FB4B8F93
-:10727000D03B7A40C7F3B6DD0F33DA8F1F362730A5
-:10728000DA07E5FAA07B8C02FD15B4713D5C7C3F0A
-:10729000D83128774EB92EBCB6CD3CDE9D1E8FE589
-:1072A0001C61C53A8EBF6160FF3C8D4FE8E759B263
-:1072B000E3393CC71F6CBF0AE34EF2FB5641FF8B1C
-:1072C000C1578CF08D8BC187FD53FE8A3BB81CFBE8
-:1072D000ADFBCD8E01E67E1FE8E977DE1417EAF9F3
-:1072E000B5B0EE9074860EE0B98B8ADDA906DE9308
-:1072F00000F26C437F478E5BA1C9DFCBE92AC67BD6
-:10730000C20B7AC69174FDDD33E6F96FF2B8FFAEB9
-:10731000F4EDD043349FEEED00AF2F86978EF6B993
-:10732000CB5DB84E1C637E5C2724BCC3E674793108
-:107330005FA45EAC1F305F1BFA2FE9BFF0B1158868
-:10734000B7CE29744F423C5F4B3A0D675C7EA49FD9
-:10735000361C03FC50DEED2912FA87919F7BFCA5B9
-:107360003D4FF37B2D385DEAE7703A7679425F7ADC
-:1073700032627208FA9CEE2FAEB8BF471FB5F3F722
-:107380009DB973009FBFF64839B7D2253DD8EEA20C
-:107390004B66055F9F7E71546415A7338DDFD1EE78
-:1073A00089280A9EA36D68427F5BEA0984C79CAF67
-:1073B00024E1E9A123033A8E8ABD1F3687F7570FD0
-:1073C000F28E7C54A33628390AE9018AAF66A11EE1
-:1073D0008072563B6FC776F3FB1B249E6A6E844E09
-:1073E000C1EFFC574F21CD43E22B6B4ED45653884F
-:1073F000F9CAFB077F64A2F311B15F8078B98EFCF4
-:107400000DAEAF6BD4E040F45B599683CEA1C23A87
-:1074100044FAE5908B692EE8EF5578E2BA3455BD11
-:107420008DCE094D1DA2901C830690F11EFA3DAE33
-:107430006BAF4EE6795B7FF9D1509C674632E743EC
-:10744000E8C729FA71D23A28D6837FC905BB4E898D
-:10745000E9E5438A42FD1CFA87CB37AE50627C894E
-:10746000FDA1FD7448993590D6CB8E0C911CD46546
-:10747000C927EBBD9E75E562BDD95F44FF2EE66F5F
-:107480002A774D039E9A30BD3D8A574E3785D56980
-:10749000FF08E34E057FD385FAD3CBF9FA505E5847
-:1074A000F5225CC314BA5FF97052A890DFD3CBC742
-:1074B000C914719B4C91AF8CF6023E235EAEFF4720
-:1074C000A6F0E78FC533D39B38CEB356D4D78B7B8A
-:1074D000AD579524CE671BE8552CF1966BC5BE05BC
-:1074E000DEFFEBE57EA7C8B3E5FB1C60DF137E4B38
-:1074F000EF9A43FB765F745E9FC2EF6FE0FAE04362
-:1075000025F0EB1B157C06E9FEBCF0DB2AE5BF7F0E
-:107510006404BC98DF549B94380FBB44CCAF56CC6A
-:10752000FFE3467EDFC27CDC4F03FD31D6CBE7B103
-:10753000A86D6C39D27BD11A85F6D3E4BEBDA46F99
-:10754000E57AD5124F9F8FFB69FDFE163FCADF8794
-:107550001F35CEE247C971E3FDA9E38DD996B8FF87
-:10756000BCB621E29E0BDE7E3EF313DCF35B0758D4
-:10757000F6FF586BC6A5DD030AFE5338217C3AE9B5
-:107580005BF9FE78A39385CD707C3294F21E067A67
-:107590004337217D637024B3B0190E3699FFEE9501
-:1075A0008BC75DC10EE7FE0B3C37B8C94EA77B6A9F
-:1075B0007BE260A03F8C14D4472573BDE3637E83D8
-:1075C00094AF9AC989FD8771C2CF1DE7E6FE71CAE3
-:1075D00031E94F27F9502F4A7B3CFEBB861EBEB5D2
-:1075E000DA93178B3F00FF86CDFE517CBF2DA2DFC3
-:1075F0006FCE2FF97DF04BC17F89DF5D3C3944F1BF
-:107600003DD6A6502ECA8432AB1FF48897AFE78FC1
-:107610007893E97B695757CCB1B67B0CDB8DC76794
-:10762000F225C573CCF6BB3204F51FEF4FFEEE4ECC
-:10763000DEC93729FFF377E827427F6FA404B6201D
-:107640007FAC11F9F21BFE7A207B3EDA43FF6CA778
-:10765000FDFA924797AEC07C6677BB62D0F9A35D16
-:107660005679F8CEB2F6C115808F7641A71A3F9FA2
-:10767000478D3FAA0F75637E351F7F60FB3E453304
-:10768000F1DBC04ADEEE25AFDD129FD98B65E867DE
-:10769000B7D7907ECBBE19E9D83EA0A11DD01F7FE1
-:1076A000EF06E0E9DFC0C88EEE3F4EA1FEBF336EAD
-:1076B0008382BFBF25E7D96A9B5568C077AD99C95A
-:1076C0007E5C6F328DD0419C67CD7BD1282E8F138D
-:1076D000DEEBD4D0BF1A6E040EA1DCC979F954A335
-:1076E0003FDAEDC9EF71F8DA7AE24A7CBD616CB538
-:1076F000B04337727B4C654718B7C7695DCF5C3EB6
-:107700009CD63D399FCC34B16E64B210E61F43FB6A
-:1077100056B2539C7CDDCF5CCE7F2F4FD233E667D1
-:107720008E18837EE69035516D1E7CF7D27A5BC24F
-:10773000FB353E14788779BC6F9EC7C5F4956C679E
-:10774000EF23CE28F93D797A62FF9DB17BA9BEE493
-:10775000D1F49B492E9B75BA0F51E27FB811FC1CE6
-:10776000E1E9DFBE4141DC1C177905C7573DADA0FB
-:107770001DF9A3C5CC5013F0538FBC2EDB31B8C21A
-:10778000A437A17FA2C786B83C71196F71A570FF9D
-:10779000E71623C852C653DE2EF9CF8B37F3DFDD51
-:1077A000E8131F97882FA592DBE535B3F9EF8E9686
-:1077B0003CAA11BDAB9BF9EF0ED66CDB4EE7ECD8C3
-:1077C0004F991FE5BDA67DBB5201E3566FDBAE2C82
-:1077D00030E16F404D84F2AB2FF3C87D8728D9CDBF
-:1077E000F17C8DF102B4530EBBB8BC9F2A71877136
-:1077F0001FE2943D5483ED4EE524FB719F52E2FB62
-:10780000D5EDD3E8BE03CF0E47149FADB68DD94E4C
-:1078100068D73A52F7231F0D3742C3102F695AB069
-:1078200003BF4F4DF7F8711FC3E7606368BDBE44E7
-:107830003C4C88E387093FE57272638A57C805A309
-:10784000BCA7AB533CD27E22FD74D8CEE7B1837186
-:107850007823DEC0B814E4C323FC7713FAD74415A9
-:10786000CC17891F37C64F812B11FE4B87B35D475D
-:10787000BD5E2DF44CC9A39B950F4D70CF40A30A5C
-:10788000F973DB0605E364504F7A06DA33CC4BEA32
-:10789000BF8DFBA5D550BFC0A457E43C12E897208C
-:1078A000C2E77EAFF320D72F51BE2F20E08DA7E790
-:1078B0009C141F8D5F0EE601BDD7C3C3D12F3E9C24
-:1078C0009F44FD49798F97CF3982CFFBAFDFACD88A
-:1078D000DCB47F4276A4844FB67B23654A08E199E5
-:1078E00030BD93F050BB5EA3F94CD583436F33C9D1
-:1078F000435D0AB7E3F6DFF83EDDFF73FFAF8E129C
-:107900003FD6823F4DFE44DB51FD7A5C57C24FAA01
-:10791000B8DF750D3749D883E25EAC6B3AB8FEAD7F
-:10792000EDD8AEE13D92924FF34EEEA7FBB46ADB89
-:107930001D0CFD28E0BFA548EF783EBD547A821E9D
-:10794000E27E525817F1BC501EFA39523F47843D2F
-:10795000CADCFCFDBD024F31FE09B5A458F4AB8B67
-:10796000E422EFE498FD989759EB57E8BCA48427EC
-:10797000BD34B17D2EF5A2D4D718370C9AF4FA5A3B
-:10798000A4EB782A47B93FCAF2715D9670C6D3E975
-:10799000E514AEBF13F0D3232909D62BB97EE73DFA
-:1079A000B643C37B91249F5C83F435F1C99329FCD2
-:1079B0007EDD275334EAFFC112BEBFF8A09DAF534E
-:1079C0000F3639295FF2D59B78FE96E7663D8ACF60
-:1079D00043B67935587FA83F87A3D5B69CCED781CB
-:1079E000FC3D95427CE2655C0F72BD77FFF35C6FF6
-:1079F000D584DDE4CFD684BE5F4179ADE92E3FDD8D
-:107A0000F7193AA85FEF89E1359E8F7C3BF6D1EFFD
-:107A10001D5FD3CEE50DF426F1510C7F1CCF524EE5
-:107A2000A43C44E4FE0DF001B77BB8BF5428CE3B24
-:107A3000563AFD745EB252C4550BC5B9C7E2630134
-:107A40005A0FE6093A14D982AFE2BC2AD6C4C5550A
-:107A50002FD1EEAF5EF6FA08FC5DB0AAEC23F494E9
-:107A6000F2087EA9456EDF11FEDF1E41EF3F08F9E7
-:107A7000AF1ED74EF256FD5103C9A97B3AD757EE38
-:107A8000F7AC7A96B17BC47CD7D0775393DBCB71BC
-:107A90005F78EAE30ADDABD9179C8BF01C18FA6F0C
-:107AA000EB0F78E7A23C8BDF8792E765CE08393988
-:107AB000B55515BF97D9A05FC8AEBE587F2CFA96B2
-:107AC00042F795089FEFD4B6D2497F44BF736B0A43
-:107AD000FD7EC967DBBEF7E33FA6E3EF835CEDC73E
-:107AE000F53F7D4590F8A53BC3E5DFC8E3ACD33156
-:107AF0000ED5D47EC08BE76B3E7DFA8A31A88FF11C
-:107B0000DE2D9CFFC9E7D5658897E54F3CF72DAC86
-:107B1000AF8E28FDD02E3DB5F5F1FFC0DF81AADC88
-:107B20005C4FBFF3BCE2E957C8BEFF3F75A9C786EB
-:107B300000800000000000001F8B08000000000013
-:107B4000000BD57D0B7854459A689D3EFD24DDA140
-:107B50003BE93CC9A393404025A1131208F2EA2453
-:107B600084872076408620AFE61D20241198591C7A
-:107B7000DD9B8620221767E2EA28F8DA0E838A3333
-:107B8000CE18306A90A0CD43C4195D5B040767919D
-:107B90006DD4419090F446671677B8C3ADFFAFAA95
-:107BA000749F930EA83BCE776FFCFC8A3A754E3DCE
-:107BB000FE77FDFF5FD51A5FF3DF52ED8454EFE9E6
-:107BC0006F3510422EFEF2E1716428218D2D8DFA61
-:107BD000A099902F7FD98CF5C3CFBFF4C67FD3F780
-:107BE0006ADCB14E78EFCB970FE9E1798D47EB6A0C
-:107BF000A125F11CD5CFB2D0D2FB824C1209994AF3
-:107C0000D8DF637B0FE91D79B4DE221142BF27550F
-:107C10007ADFA02CFA5DCB5EED1233BCE123A49891
-:107C20008EFBFCC2511EA8B7251092127EBE554F86
-:107C3000BCC6385AF623C444CB4BA566AFD49F903C
-:107C4000D565E6AD505EFA8DA9CA47BFABD50773BF
-:107C50006D309FA1C405F578AB86900418E76E5D82
-:107C6000AD19BFC77E3ED21102651EF192F34308E3
-:107C7000A16FEDBE361CC6FB2DBE4FDF2B3115129A
-:107C8000327BDE3909E61333B45EB71AE7F96BD6F7
-:107C90004E571DD93E623D1D8F8E7B0DFEC687CB94
-:107CA0003CAB19DFA700C132B5B532CD01EBB71B34
-:107CB0009CB07EB1BED46A4FA3853EBF6DBDC729BF
-:107CC0003B0879FDC289890368FDF921D270195EEC
-:107CD00097A5856EDA7FADD78CE3ACD950463EA32D
-:107CE000F31D6F95F0FB442BB1DF4AD753A12576E6
-:107CF0003394849CD41542FFCF62BBC3405CA488FC
-:107D0000966FCE7E7623FDE4319D27A518FAD91A09
-:107D1000D03BA0DCCDE64FBFB79A0BB13FEBADF047
-:107D2000BD91AC85EFBA364EB36F93B0DF802E2E87
-:107D30003C6F424219B3F2587F4500A7C9DE2A784A
-:107D40009F38F4B8BE2FE115C4A3377F7E1E940F71
-:107D5000B1F96A8807E825514F4B84AB27AB92D223
-:107D6000CD7C6B6995B5385C26F663ED6AB83E0547
-:107D7000ED149E67AC2E2CC99E784246F57E4F943A
-:107D800002FE876777EA8374DC470F9C43BAAD0530
-:107D9000BA85F13D9FEB611D826E9708BADD7F0EBB
-:107DA000E976499B84F454DB56A0077ABDD4E022DF
-:107DB0009F69699DD3DF63527039D0B577BFC9FA27
-:107DC0002C8553A7A0CFEDE7CECB141ED96D290E7D
-:107DD000099EEF6774FA9646E30538BDB5EB96E663
-:107DE0004629729E1B113E5235413EA9AD273E03E6
-:107DF0006D2F7D7AFD8929B4BEA69A380D943E6A0E
-:107E0000557494F5CCA75B805E6C35A4C8E480758E
-:107E10009E9D3880F65F5B438A814F5327B8F643B7
-:107E20009DB4496410D4ABDD4B61FCDBEC2B9D327F
-:107E3000EDDF36C1DD0AE3DD661FEB94697F8FA5B8
-:107E4000B76C31D2766F05B13EEB00FC36956969AF
-:107E5000FDB10A87954292C26D7732B493217AE7D9
-:107E6000B340C79EA535D05F6DF25C27D0492FFE89
-:107E7000DFBF7108CCB7D6D1CF69A2EF4F6D939019
-:107E8000AE88D74C60FEB514BE509FEA1BED83F957
-:107E90005CE6F01370ECD40516C0FC3A5F31102F8D
-:107EA0006D9F3A81D1AB6D420BCA8FB7F74F3A2E17
-:107EB000E587E9D2F2AAC10FF538AD5572825C228E
-:107EC000330D91786DD291856EFA9D6D32EB2767F7
-:107ED0003BC3EF739C9F9E03B981A59EF36F13A3D1
-:107EE00077AB37DF4DE9E132C73FFC3968BFABF113
-:107EF0001F143F4BFDC84F352FB2FEEC0657C1BAD9
-:107F000008FAB59713E4E33D26B2B0923EDF63630F
-:107F1000A59A5EDFE5F3C87A662DE27D09C53BE0F0
-:107F200035753B7D0E70A3740170A378443AB8CDCB
-:107F3000BE02F1B664BB7417E2D13B82403D219E84
-:107F4000AD53DD7F80CBC53D26779144FB0B255893
-:107F50009CBB24988F4B63827A81CDB98BC0F7EE9E
-:107F6000DD305E4292C9D91821AF08711769E8382F
-:107F700017122D0CDFBEF7B533F2801F1DD86F82AC
-:107F80004CFC04E50FC976E785BFABC861FD55F031
-:107F9000FEA63579F349368307C285C3C3B7B15FFF
-:107FA00055A43CFD08E041FBF5DD44AA406EBCA5AC
-:107FB000276623F46FA5E3D0FE12778DFEE5369C8D
-:107FC0005F23BEF7A6D58A6545BCBBA81E44708E4C
-:107FD0007B3DC045AC530D8FF91C1E87672F28D001
-:107FE000001DDF697602DF3D7A405A8C74ED355210
-:107FF000A604BA677C48283E802F88478BF8A8AD36
-:1080000077FBA2D37D25F259ADDDE4344948F72E44
-:10801000D47F5EB38FD13DD37F319399BE0239595E
-:1080200099D75B1E083903FA0DE859F045EDB860A1
-:108030002EE0F7DBCA954E1DE3F34E0A07E023C19D
-:108040003796D719BF6CDBE82885F66D94EF23F1DE
-:108050007D4CEF45FE3D96DDCF09FDC23CDD96B07F
-:108060007C4FB4BAFBD9609E1AFF166D56581ED7C6
-:10807000BEFE60AE270AFD09796CD4323967F4C5BB
-:10808000F858BF6C3C2305B7A5104B2FE8A3980DFB
-:108090000C3EEA7ED26D664E8F46EBE7548F4FA7BB
-:1080A00048EA9F43C8648D27DD46FB5F630C1EA32F
-:1080B0009825191B427A984722E82EE09F5D313EB1
-:1080C000905B8989C4B32F4ABFFD6D8CDE045E9A34
-:1080D000E2181F25C6B2F747D918BD0CB5313E2DA1
-:1080E000E3EF8BF90BFA77683CE788DCB71E13DF08
-:1080F000D17961BB980FFD7E2B61FA17E79BB829F8
-:1081000077D7B6087C84F9E8A642C053CE76BF760E
-:10811000B1393C8ED0A76AFCC3FC817F603D95439A
-:10812000FB7EAFE910E347353D4EE17C62B0112C98
-:108130009B74FE3F235FDD6D21BB607E3B882B9EE1
-:10814000CEABEE8DC18C1F5CA15CE8FF609C6737F5
-:10815000E063E4044EE7F4F90CFA7CB596780D146C
-:1081600027ABF7E87C4123E3996BF4FF62C0139DD2
-:108170004797C5E895299DBF1FE7A982EFBD65C454
-:10818000E907BDF4532A3F80FF88BF18E44B1D095F
-:10819000C6029C6BE5402EA1F8BF1AE3990FF4F8D4
-:1081A000A9269001CF090922BD9E31C5E613DA5FE9
-:1081B000ABDE9FFE4F30EF7764B28BF6D34D5C534E
-:1081C000611DDD014D9C97AEE393B60F7F73807EFA
-:1081D00035FFC0E5F9F70294B6C52C789296F38C7A
-:1081E0001AA37678181E672CD1E5EB8F395D2434FD
-:1081F00032BB2BB4D1E003F8A8DF1B1FC7F05F77B9
-:10820000259578E3239F33395AA70DE9C184ACBB88
-:108210009241BC74DC4F34A4BA258A9DF9A18DE942
-:10822000AB564AFAD1DA4F733ADBA323B93B603E2F
-:10823000CD540E02FCB40E9417D58F6439B7D16AB1
-:108240006B76E818D811A15F4828FFCFE898DCA129
-:108250007F771A4784F5279827601F565BBD7E0DF0
-:10826000951BD5EB2D7E391F9F6BC700EEBC562D9D
-:10827000C8C1C55C2F2EA97FFB1B2996B66B8971DF
-:108280000CFDEE0BF3D258500BCB7FBC2E118CEFB4
-:10829000A4794DC89F844CB0823D2EB9A6C9D7623F
-:1082A000AE67CF69D16E477AA1F82D8F733F09F879
-:1082B0009ED79FC17BDEBA189F3742FEDDC1E1A386
-:1082C000A6B33D40A374BE6725A657D4E3BC1057A0
-:1082D0003609FAFDABC5FD1CF6BFEE32CAB379070D
-:1082E0004C19A0B7565FD1205EBA0A02B91BB28002
-:1082F0009E43197FA0F05BDD6EB07A1DD0AE57E0D3
-:10830000F5D3062AD072C3F5C517064E246680AB96
-:10831000730BE079C9D618E21D129E1F18D240B720
-:10832000B55708F6B3B8FDEDD320A76BB541A48BC4
-:10833000C54633C2BDF68A16E741B6EA3A82E27B09
-:108340003ABFF858573BCCDBFBC018DBF95BE8C3FE
-:1083500024FA1CD7E5390CFCF4784C2C71313EF032
-:108360000DA6F3EF363AFAC75138D4E929DE876112
-:10837000376E6384DD44D22C4ABCB6BFF30DCC67A4
-:10838000A9D1A307782CABAAD703BFCDEBEF2FB6AB
-:108390000E8DC4E718F9DA2DDF1E9FCF73F9F2892D
-:1083A0009ED27B14FE3ACDE5EF782E273E49657CC0
-:1083B000F14906A9DE07E5CDB4A4DF7D92CDEB85BA
-:1083C000ACAEEEE72AE78B4FF2991EF2AE657A412A
-:1083D000FD5E271FAF3CCE751EE0269E0F8F63CF3C
-:1083E0005F88735D043853397799D3A1DF46FB9BCF
-:1083F000F7A601E9906C0EE5021E7BD695CBE79BB4
-:10840000187D5EB670BF5F437FF43D17DAE36F9867
-:108410007CB0BF20D3A8DC0539BB369D809CA5E38A
-:108420005EC5F772E9B8F89E01D741B652F94B190B
-:10843000ADABD88178D9564AE913F8FFA0C10AFC40
-:108440002FE849D0919A7E4C7142AF31FD7A07E80E
-:108450005719F5AB298EE9573DF02FED51CFECBC04
-:1084600081886FA433F9DBE3FBA09170F8BAE3E3F2
-:10847000509FFBF3DC79BDE12CE4DF27FD9474E130
-:10848000E3781CC0DFEB81731C7BCF9EC3F499B0F3
-:10849000FB6FE1EBDACDE5B428857E1A3959696FB7
-:1084A000ECE6F263B72D164B8A97C1B07EA1D77A5E
-:1084B000E1FB29866FFADE5058CF3C4368413CD53A
-:1084C0004B3FA2F68EBE10BF7B1EBEEBE57F98C071
-:1084D000F469DD5A0B017D3F228ED9B1A4289401A5
-:1084E000FD9121B4CC03FEA3F246BA31FE60AF9FEA
-:1084F0004279E4F65807DB57CA7440E09921C40179
-:10850000FD517897C62584E1AD1EEF0C3451FB6E0A
-:108510006A9CA43D0F382A200580AF051F7C659911
-:108520004FBBBC6C357A35543FFC58E3B903FAE9CC
-:10853000B8E71DB4E7CFE8FDB94DE628ED7AFF3383
-:108540008F4BE1F6852FC85E3D9533AD818E5FCCB4
-:10855000A674B938203B61C8C5F7FDF9BD91602705
-:1085600007744ED8AF523B61BB96CEFB8C86E1932D
-:10857000D42BF7FBAB38DEA9BDA42523C2F249E812
-:10858000FB95C43F08EC8225C4A587F2D3BB574CAA
-:1085900023145ECBCCEB516E5D5C3B05EDE0E5C496
-:1085A0008BED4BB6EA3E8DD413CB9A94F5153B94E4
-:1085B000F5953E65FDD24F18BDF5A67B665F259407
-:1085C00047B71B1EE17479491FBDBD318ED169F9D2
-:1085D00003D31E47FE0FE88881D2C9FA83A5492438
-:1085E000CAFBA2ACBB924D7C117A286C57E412DF17
-:1085F00070E8EF2AFAF9A01FD8BFAE37B992609F92
-:1086000071A92CFA3CFE778FDDD2AF8F7E63B1DF8C
-:108610004BD9D75F67DD1523BED7FB7B33F64BED18
-:10862000A7A8DFEFE670B81417BDDDD7D37F32EA15
-:10863000C5F0778C0FC2E3A4A15EADBB6255E8E93B
-:1086400070BB9DE955BEFFA778F5A2BDCBED39AA59
-:1086500010ADE763C2724CD78FCD47F0CD671231B2
-:10866000A6A0BFEC612E479DF960F77E067615F057
-:10867000ED24C71B413AD525F78ECAD56687F94A3E
-:10868000BD1E4A8F5F0623EC82B6388B1DF5B99369
-:1086900038615CC10F0BEEA9E8EFA178FB8FFBCA34
-:1086A000933C4323E9CE8BE3D7EA853D6756E871D7
-:1086B000A2D2F34BDADE417B6DA9D19D0BC2E94F0B
-:1086C00007EF413E594EDC89C01F5D07076778FE02
-:1086D00007FA5DCC67A677918ED9E714A8946F67E7
-:1086E000F0F9CC6C67F6A2C6E8D2E1382EE2B026EB
-:1086F000E2169CCD970A592DAD8FED993F3813099D
-:1087000019C3E72FC1F714BE637949167B9261DE66
-:108710000618978E6722BE64281B47391D508E9716
-:10872000DC5A360F1FE27922A94F83F735C6A0CC59
-:10873000D649679008DFF7C00BEB165EDF7C67F762
-:108740008265F0DC6C41F9A3E7F3F846C84D2331AC
-:10875000C2BA0D66FF4558978597DE32667F7BB3B8
-:1087600089B391BED68FB41018D76CBEEC85C55AAC
-:10877000895582BAC9DAED877DC865ABD9AB198650
-:10878000F2F4FFA03C95DE5D0E78A1F29BF9A5FA0C
-:108790006AD7FA71FF23E4631C9F5F23978F2984B4
-:1087A000C1C14EDC875C94AEFFC5B27C1A89053529
-:1087B000EEC1F177C64E3E0EF305C0A39E9FACFD01
-:1087C0003452CF24B8B50AF99754A5ACA77894755C
-:1087D00023396305FA95FCEEE46BF1B8AF1B027E1A
-:1087E0001A1D973777F663F312F49316AF51D82119
-:1087F0006EBECFAF8DD313F40F261A8D6418DA2511
-:1088000069F1CC2E394B314DF7832194E705E35DB7
-:10881000837E41E1BCE503D9B989E2698BC5B151D9
-:108820000BF6DE1CC9F92C92678B1FFC3ECD0B6C3E
-:10883000CE6DD06E72FDFCFF40FB0732017BAB0EAC
-:10884000FCEDF1F0A2B514BE6BCEB0E27BF6F210F7
-:10885000FA49430F12B4A77AD1E9553A7F0AEF5F7C
-:10886000429DC2B76EA975F58BF4FD14778C538ABF
-:1088700068DF0DED749E12A70B783E7E04EC6BD979
-:108880005F4E7B41C0057E0B978CFAB0AEBDE08891
-:1088900099CE23C753E004B21DD8CEE32A76838F46
-:1088A000C51528D7D279CC32B279D4B597DE514CE0
-:1088B000DB07068613882FC41C77CCAD81260DDD1F
-:1088C0004FC3776531E8CF3AC9FD4A84CB83912AFB
-:1088D0007E1B1DA67F6C2F10756A36B84630770553
-:1088E000D6ED8C0F9C44FC31FEBC9584FFE0FBF27E
-:1088F000707F288F26849BC3FC469756687436D6B3
-:10890000D0F7DEAA9C84745807FB2E8A8F915AFFF9
-:1089100021E0EFD1BC2CE02559DC84F0DCB6D17F1E
-:108920005897052E14B70CF511D6071BA1BFB192AD
-:108930001FCB8CAA871B81AC5E03E30CED4E4F0569
-:10894000F0E3960A6205FBABB1C4E9B4D2A6D955EF
-:10895000CCEF3AABCAE8033FFE2C2D61F12EAD27D8
-:10896000EB4794AF7E348FF97BA13E2FC29F22E26A
-:108970001B27E93E666F147BE0B578A6C7C4F77580
-:108980009BF58A38D2CBF1CCBFB5337EE24FE2D92A
-:10899000FCB280FFEE8BE77265081902722582EF48
-:1089A000BDF05E47E9EFFB920BCA762E1766B91E43
-:1089B000D1A11DCFE58390C36EE043FA5D4072E91B
-:1089C000007E1F9731F89F285D89F26136F1E073D0
-:1089D0004A203A77A41F6972843D44C799E556DA64
-:1089E00047B3AB947541AF62DC391E65FB0C61DFA8
-:1089F0004E56DAB7F3FEE9AA0DF56FD2736BAE658A
-:108A000062DC04F7FF75144F2C6EA2657194CD7A69
-:108A10001FD849756D77BF95007C741FE17CB457F2
-:108A20005A3A14FDB0D2B2083B62408D4F02B93FB2
-:108A300098AE2980780D61BCE8A4CE7708E228279B
-:108A400057D215D3791ED1B378E45113F1823F5A2E
-:108A5000D0A76506F3A75232C6B8489A35C609F4BE
-:108A6000B4555388FED7ADB11667A4BF73DB464A31
-:108A700077117E578781145A39DD44DBFFBEC9E583
-:108A8000E16312F37F7BE71871BF9790E356C41B35
-:108A90001264721AFC883F897788F7D1CF01F1BA46
-:108AA000E1B4F449CC9EE9F95E269BD1EFA8923F50
-:108AB00009F14EF4F727F4CF43BF7D557BC16E9487
-:108AC000376693739014EEBFCAD3AC5D06FE83F68F
-:108AD00066ED527398EE4E00BD02DE62480CD06B1C
-:108AE0008F1F6F9F01FD783FD6B83F02BAACD1FB14
-:108AF000F389929EF1795F7A6C05A7175D997BCE19
-:108B0000323A9FAEF7F4CCAF751F417E7D79BF0D31
-:108B1000FD90DA1904F5C9E65282F4D0D52CA1FDF6
-:108B2000F685AD1AF7019BA526D4139D7113117F0D
-:108B3000ABCC47715F5BFD94EED348BB6BD56E65E4
-:108B40007D3509E0BEBAE6C55EF48CF24BC8C7DAE3
-:108B500056E57764A0523E1670B95FE876CEAC80D9
-:108B6000A9573973D8BE9AF80D741DC5EFEAB9FF3D
-:108B7000771ED39BE43909ECAD2ECB0599F13993DF
-:108B8000C7C5BC3FB51E2AE6F6D4382AB760FF2910
-:108B9000EC23FA3ED68F6ADAE5644D785E45FC3BFD
-:108BA000619709B92DF0525A424809A5FB643B97D9
-:108BB00043D9241BF04AFB477EA0E37AF571D8BF66
-:108BC00017F66DA3F97814EF5ED0B35E8DD10774FC
-:108BD000B445AA47396D245C5E4B1E94CBAF79BD7A
-:108BE00032C07514A99F398DBE37C61888017850D8
-:108BF0007A48B32784E9A491F833F64A0A7AC1F691
-:108C00000EDBEFA3D28BD02FFE8F997D3195AE185E
-:108C1000FAA980400E2D8F4A6C5F38C9FCA816BE99
-:108C2000FFBD660AD2C364E2D3C2FC2AAC4A3C4F01
-:108C30004A56D6A7387AD1810CE3BA383CA70E51F0
-:108C4000B6BB845C234AB99645AE229EC983C77ED3
-:108C50000C7E81980D6408D81DD442447E53CB838A
-:108C60007176B3C23E8A88838CB317F78E83747192
-:108C7000BFEEAD24B8FC45A937BD74BEB5414E8EDC
-:108C8000A02B41C7AFF3BC09E94D1E6F2D62FEC09A
-:108C9000B09E67F43282D76E057AA3EF2F147492D8
-:108CA0004932814EC6B699FC32856B01EFE756A07A
-:108CB0009BC2B03EF76BCC0E7D36D08773AB2CF7E2
-:108CC000B6DB13E31C4827C3352EA49362E28C075E
-:108CD000FC94185B1AB530FFFD230778CC0ABA580C
-:108CE00062473942E902F9AA975E54B6ABE846E01A
-:108CF000EF38B7972711EF40188F8AB1A3602FFB89
-:108D0000B318DD541017D2C9DBD953783CDAA3C5A8
-:108D10007E88521F961B9574A0A62B3AA226725CE1
-:108D2000359DF54537994037421FC6DF986EEEEF07
-:108D30009B6EEEBF1EDDA8E945C893BD266B39D8F2
-:108D4000A575D512CAE1E1EF0D6C84FAE0355998AA
-:108D5000D7B2D7E644BBB5AE9EB517055C32E4BDCD
-:108D6000E4ACE7ED59EE72A8D76D60F187E2932C81
-:108D70002F66E07DACBD6053FD110BE8772FFBFE45
-:108D8000F58B5BE458DAEEDBC2BF2F6D2A877ADD04
-:108D900056F6FD17103FA2F81D71DAD708CF6FDA2B
-:108DA0009EE564DB4F66CF8EE774BA57DA7704BF6F
-:108DB0006B62DFAD3866EC47D00E6676EB38BECE20
-:108DC000F14FB175DA3FBB6DB283D2EFB29017EDC0
-:108DD000A6F39A9A11286FFAD867964A4D695052AD
-:108DE000BA4139E33252BACE66F1C55D7488437632
-:108DF00066078AB81CE40944E6051CB233FFA37871
-:108E00002F318EB038F21316F4078BB8A1FF712200
-:108E1000019FC11AB9FE8F1A479C94538FF1C34921
-:108E200099227E18D42EA6E3165CFB6A62347FCAB0
-:108E3000713EEE059EF7209E57FBB23440177B81B2
-:108E400048520148AB7F0776D35EF0BF32A5E125DB
-:108E500025805756FFC8BE62DBD6340A5F4DBDD6AB
-:108E60000B4A2683EEBF68D7D303C4DF3FB6F7FCB7
-:108E70002769891FF413D1B2F92F6FA47A500ACB56
-:108E8000A55942EC8C19847C7A27C7D367766E6F1C
-:108E90000C27C341DECCE278FB91B15EC7F4659349
-:108EA0004EC5FF5F20FFEFECD36E56B6ABE4433503
-:108EB0001F7739B797579210DA05E7251F9617766F
-:108EC000327B79B5F924DA155D4F303BB18604D198
-:108ED000EE50FB0F57EF51D6D7B428EB756DCA7A19
-:108EE000579E17C7E9DAB96604F8EFAA77BC877E00
-:108EF000E16A21277C4A39410D2426271EBF19FD2E
-:108F0000361A2395134500AE7E9847329CB8E2414D
-:108F10001E8092BD46EB0FC22729B4AE711B1350C1
-:108F20005E4C8EFF5C8C2F639CF63D97238C979E46
-:108F30007DA14A4E14087FCCC038F45709B951C0FE
-:108F4000ED123259BD6F7C14F96F38AFE52428F764
-:108F50003DC2CEA0DFA39D11D0987D1A4DA45DE146
-:108F6000437E2C34523D812CE434B2FD4A1351E14E
-:108F70007730ACEB3AFB2665BB0AFF62DF3282E357
-:108F80007F0EF10C007CDC49DC6F817E38F171B51D
-:108F900062BFF4F11F270A7F0AEE9BBEFB7EC9FF6A
-:108FA000BDF64B3D783751FB9196E533A60CFA059B
-:108FB000C4BD5B4D98CF5927313C27CE399911E973
-:108FC0003F3CD14012B4117CDF38C56084F860A307
-:108FD0008EED27664CFD64C4E208B9F192B1746A63
-:108FE0004231E021F0937F87FDC53B32C17C99F689
-:108FF00004C47B77137D4EE9ADFBA95B9C5EFAF858
-:10900000928EC51BBF90EA97438A9398C7F20DBF13
-:109010003369A91E5B21FBDE08427C55F2BD5A4331
-:10902000DB4EE93D73A0FFD51ABF9EF9ED0218276C
-:1090300015FDF7ED87F4A2BED31F667A3124F573D0
-:10904000323FAE373732DE5495C8F657EFC7B9977F
-:1090500001DE85DE13F18433774FEA0FAAE16BE27C
-:10906000EA0F714E490BB1A7DEE341BEC0E608BF6F
-:10907000F21953F4B8C0DA04265FF7016FD1FFED9F
-:1090800036D73A18F702DFFF5DE0F1AE0BB12CFEE8
-:10909000F5BF7ADE67E5A309CCDF7D81C7C72EC4A3
-:1090A00029F78DE2BDC778F97983D1B839029F8E4F
-:1090B000C70DF53ECC93E27921EB09DB27EDB735FF
-:1090C0006F8B8887362794EE837925E4B8F42900DE
-:1090D000BFFD4C0F433C1AE2C64556CF76C04BADA0
-:1090E00083B820EE4A1C41FD4C883FC2BE13ED07F9
-:1090F000462F5D26568A79352754EE83EFBAEE0E59
-:10910000223E7BEA954C3E3627B871DCAE59A29DD3
-:10911000D71F0A72FC33FF81F067F7150F53C7BFE3
-:10912000A8E26076B689C93175DC7BBE90633CEEFF
-:109130003D8FCBA1F9EDCC3FBEC048B60CA0ED0BE6
-:10914000DB93D87E31D69BAB887B7B63BE531E837B
-:10915000A0CFAEF4404FBCF6898878ED1A1EEF5BC5
-:1091600023D6D7AA5CDF9B097DC66BDF4C8812AF84
-:1091700055E705BC0AFA7D60189E6BAD6CFD157253
-:109180004DB91EE4C45282F9E16BDF59D268A4F5EF
-:10919000B50F82E70FFE98BDBA86C3ABAFF925B80D
-:1091A00035C4A1F013F7238E887D718A274E51476D
-:1091B0000B3822BF724075AAE2FBF4FA6CC5FB992A
-:1091C0001B6E56B467790B15F59CADB72ADE1FD41C
-:1091D00054A6A80FDE719BE2FD0292D31FE3B1C734
-:1091E00065F095909B7C3314EDB7ECB94BF1FD170E
-:1091F000A4FEB131F4BD5613D303C4EB0A0CA57021
-:1092000059CAE79FD7B258F17DA3D432C24FDF5F6E
-:109210001A60FEF6616DAB14FD5D8A9DC8F6113CC7
-:10922000FE584FFF6372DC21A33DD4269127A4DEB4
-:10923000F1C8EAF687B70C20BDED0AFA877A7E15E9
-:10924000D5F36047A9ED0C39D16247FD904A52AF82
-:1092500045F055980ECC6887753F25A33FAD800C2F
-:109260007E7C0CC247477C8EDEF8EA26CCCFD3FD4D
-:10927000A2C509FEB215EF2C41FA33242BE9C0E454
-:1092800050D241CC10251D589C4ABCF72F51E25DAD
-:109290000D679B4B4907028E02CEF193957421E036
-:1092A0005B42FF03F81692D031CC9FF6494E3F89BE
-:1092B00012EF6D6BC675DCC86ECB53C173F8515796
-:1092C000A319E1C4F2A9849D64E0FE69B5DF5CD80E
-:1092D0001F6313B9DDC3FB117EEE2D9217ED9C9E2B
-:1092E0007856893FC39F05F64E3D61FE127769624D
-:1092F0004254BF1A3EEFCBAF26E028EC99D560CFA1
-:10930000D07196110FCAA5CFB93DB3C2FC28C605CE
-:109310002FFD91C1B79AF8505E7FD77839D889244C
-:10932000C2DFA886A3D42EF92DC0075C6EA7927663
-:1093300021B73D983741C9CE3842115F50DAA1C4F8
-:109340002545CA2761978AF1043C85DC12E3194858
-:10935000BD9C0C7CA092636488DA4E55FA3D849FD4
-:1093600004078B88638CEC894FB07D62D8EFC5FC15
-:109370001C7266562301FBDB2AFC1A81B9F05CF8EB
-:1093800035D4FBFB1BC545677AA5E09359BDE3A126
-:1093900022BE4A97F9D9BFD38FC7488E74186FC6BB
-:1093A000EB831388269A5FCE79FA00ED47D684E2E4
-:1093B00023FD65C27FFDB614C479FF88B8EE27117E
-:1093C000F6422D699938370BFC9F546FC542C9FC92
-:1093D0003EA44D6D97B278A286AE04E87B358988AD
-:1093E000176685DBB12EF7AE8B3C971BE97747926A
-:1093F000559C5BC965ED4CBE89FD5B5FFB2511CFBC
-:109400007F4B4F615218CE6B793191EF33F3493E68
-:10941000F44FF9AA2511F7E7940FA548BEEBC983CD
-:10942000C1F65E7CA75ABF88E7CB9622F4BB2C8995
-:109430005CEFB78087B023BEA26B83725BA203CBC5
-:1094400035FDCE7CE482E6A24046A4BD5BA76779E9
-:10945000C1A445693F9F4CD47078B9E46F03A7BE9F
-:10946000F1C0F3C2381EBEAD3D24F2C204FCFE289A
-:10947000E46018DE671572AC67DFD603EFB3D1E4A2
-:109480009C80C7E5E2C0738027D9723211E0FC5797
-:109490008BFB33C04FFAE9E0794903FAAEE3B92711
-:1094A000417FB5C9B83FAA1DCBF2836AF763B09C70
-:1094B00074B61B301E58DD7604EDB28E062A4007C6
-:1094C000F60D9F9E75AAE0DCD73E45ACE3BF557410
-:1094D00026F244E8FAFEA6A0A7DEEBFF5B347A137F
-:1094E000F94915F2D0FEC188FD483BDFF798B46E0C
-:1094F0006D12FDAEE8C3B458804B85DC7E2C15E0C0
-:10950000B05EC2F347E30DC40B7EFE147E0EAD24A5
-:1095100058EFB4527824A799F13CD1E01FCB6E8864
-:10952000637EB27E5DDC125A7ED94087A6FB8DC178
-:1095300092C68D7446F69DFD6911C4D7E661DEF1D1
-:109540007C038BFB67FD24C69F43E5C39B7A6204C3
-:109550003ED365D7E3798B904DC67D865D2613801B
-:10956000AE049CED316C1DE279E9D3BB25C86312D2
-:10957000CFC7378686AFA5E539C07771789DE3CB35
-:1095800043C3EBCD61388BFC40A20D65CC88E08BEA
-:1095900037393C6A13F45B400F761AF9FE8FEF03FC
-:1095A00089558BF2633D8FB39F194477A2D88FDF23
-:1095B00002F958B52657FF91E0E7823C025A7C6DCC
-:1095C00075F5B7E1FA1D682FAFE7765527CFDB5E5B
-:1095D0003FA52C09F6517DE53D952631FBBE86C79A
-:1095E000BFC5F31AAD1FF3956A20DF3822DFE9BB50
-:1095F000E61B8BFCF13EE160D3122D8543AD44DCCC
-:10960000D77BEFC0DFE4A8FBDCEA24CD75F3DF16DF
-:10961000F2F589FCB65AC86FA38FD6EF2F4D2251B1
-:10962000FAEBD133576E55E49189FCE8DA2BE3303D
-:109630008FACFC810E3CF707FD38CCE1FCB6BEE0F8
-:10964000FC66229B472DE4850D8F7CCEE446B87FD7
-:109650003BE2E1570040F073B4C9E88FFDD571CD0E
-:10966000E45D51E6FB501283CFCD095AE48F5BFCD9
-:10967000C4D51C657CF19E38170270AECCEB3DBFA3
-:10968000D6B2E002983FE4AD461BAF2189EDAFC5ED
-:10969000BC5BE382CB399DE3B98C9EBA5589C77F09
-:1096A000E572BFF5B660069E2F9A123D3F5EE07BE5
-:1096B00084B65E0278042D9E03686FCEA6956190F5
-:1096C000D7EFD7B0FC29C6677DE13D0C6F8D229F97
-:1096D000B037BCF58867D19FD88F5CDC2163BCFFB5
-:1096E000E209CE97C46596287F2DE2FAEA226171DD
-:1096F000838B4D12EE43167B08D940E5CBA2DDAB40
-:10970000316EB3FCD9E15B404DC1F3FBA81C599409
-:109710004CC8385A2EDEAC8CDB2EDDDE2B4E4322BD
-:10972000F522353B715FBDFC51E577D564FB7F8247
-:10973000DD53ADB26B06733FD7BE249ECF37828C0C
-:1097400000F9BEF6D9AFF490B2DB17BD7F49F97AC4
-:10975000A016E4A015CBA349AEFD49141E1F26791F
-:10976000DA416E777DC0E0D05DD3CDE4FE5376D490
-:10977000370610CEF49F86B92CFEFA001517107725
-:109780003318985D23EC39595E27C7D2F6517F5ABA
-:109790001F07F8B3FF7AD264B0F7137E1DE3027897
-:1097A0006D2B7515C0FE7F5BA519F3188C0616F797
-:1097B000F5FD6AD46108030C6C79B80CF69FD6F6F7
-:1097C000437EF08F6CD5FC279E2BD93A8EE5B98964
-:1097D00071EADA2BF7C27C32EE647A635B96ABC037
-:1097E0001AD12FE1F6592D8759D7C1C13F1F4DF12D
-:1097F000F8E471348FE9FAB2D10F773361F814F9D4
-:10980000543076A41DDA41F50F24E589FACD2D9266
-:109810005F47D7B3A6752FC62F6A36F913E7829E26
-:1098200079418BF11F313FFB9B296510E711FA65E8
-:10983000AE6445FD2FECEC3944FCB1385115A783DB
-:1098400039DCBE9E1BC3E0BB983833E0BBBB8C2425
-:1098500016FCD373CB5B8A51FFACD6D940AF8B7863
-:1098600047DFF640743F51ED7316763E560AE542E7
-:10987000275FD27D0761FEA2A8E78D4CC99CCF72FD
-:10988000B9BD3790B820BE56FBC6E066F00718FA9F
-:10989000B1382C953BC69242B4778DB08F5979C0C0
-:1098A000E467FE6A1F3F07EB2A807C90BA1969853E
-:1098B0009897709ACA0F0B9C2F0C66209F52B92262
-:1098C00051DD969D1C334D4BE9BB3695DA53B4EE12
-:1098D000DE91CCEAD9C1E51A5ADF905CC8EA3707B5
-:1098E000CF437D53F258562F0C2E9769FDE9E4A91A
-:1098F000AC0E1B3B4A58BF4A9E31CD0BF6848DEB14
-:109900006B6710CF05D7BE3E5813E9A77C2C99C9C9
-:10991000A52FB9BFF5CB2CB27006C07B4810CF9DE8
-:1099200089F77E9A2CEC5B96DF2BD629BE23C9D112
-:10993000FB2FE0DFADE4E779C7C790AD2616A7F2AD
-:10994000C652F81F6D1F8C71B6C4E438E68FB3D2CF
-:109950007E8AC2FD08388AFEC4B8AB40AF82BCD54F
-:10996000317FA9681F97CCE4381D67338E3394C1CB
-:10997000BF76465A01E08DE24BCBF1A565FBCE6682
-:109980001C17FAB5E5A37C1F0EFEEEA357E9FB59A1
-:10999000E179ABE9632AA78F958D2CBE18B2E5203B
-:1099A0001D8D8F61F61E2952AEE3690E87C7926D39
-:1099B0000C8E3DF84892709C460EC7340AF7BCEFF7
-:1099C000BEEEF93FD0BA23F0E592A1BDEDA65D91C0
-:1099D000EB11F9DAA29F2F37AABE2B617953B5712B
-:1099E00039F8DD032662C4E76457CF7759F9CCCE46
-:1099F00004FB53DCD740BCE3D04950C3A546CFFDA0
-:109A00000B2D3C7F70A08B9D3F9E31AD88AFCFCAA0
-:109A1000D7673546DCBBD0C38F274319775A7AD333
-:109A20006F0FDC7BFA1B5AC8FB53F075B4FE803F06
-:109A3000FAC2C7CFFFDEF810F354C1B307CEAAF9BC
-:109A40000978023FE3774395F428E6B92959E40BF6
-:109A5000ABF83AEB7B8E57CABE5B730FCF03762809
-:109A6000E9794D6B9606E2E7E2BBC9E0634F08FB7C
-:109A7000DBF625F37D6B1A49EB23FFEDD5E4E87E99
-:109A80003A7CAEDEBF75D958DEB3DA6FD095E00C04
-:109A9000C0793EEF65763E7DB4CADE80F8CB3E737A
-:109AA000F8BBB03E51D6E514C607BDFD40213C4F82
-:109AB0005B64287BD9E1A47B9DE4EA695A6A571468
-:109AC000F52F5B9745EBA79257A1BC2E1A50F65580
-:109AD0001695DF7F485ECDEAB7947D950DF51DABF9
-:109AE000D9FBE35D2F837C27DED5D326A484ED87C5
-:109AF000D3C90E849B5CAE21404706F96E27E84926
-:109B000001CFBECA2283A63E9A7D7AAE870E587CCC
-:109B1000A284EBE712B13F0F6A15FBF3AE5876DE75
-:109B2000B80BF4295D6F47B2E77C32D829311D0BA1
-:109B3000B268579B62CEEAC11E925C5477819FC384
-:109B40006125F3209FAE639B1BEC23B2CA69D4222C
-:109B50003CB9DF89AEED1AEDE7C01B2FDC3B800D71
-:109B6000E386798CE2FC5FF7C6377F81F868DD9782
-:109B70006627B8F546B5EF5C07F6D5A8F6DF7FC3D4
-:109B8000F42D3BA721E63D0AFC87F479499B01E7C8
-:109B90003FAAFDA665F0FEE80FDB73803EC69EF18E
-:109BA000378238E83AF8DA00C5F90CF285F47DCE50
-:109BB00067F4C0E34FD478EA8FF030A624003CAEBF
-:109BC000629E5467C2892D41B4D394E760A85D8E2C
-:109BD000F1D56ED2CF097102718E5BEDAF3C5D495C
-:109BE000D7479F8F0DD11944D8CBE3AFD0FD7D84EB
-:109BF0009D5D4A6C8A7AB93145F17E85354BD13EFF
-:109C000029F92645FB144781A23E75C828C5FBB734
-:109C10003B4B15F53B4AA628DEAF74552AEA05FEF4
-:109C200016C5FBC38FB729DB4F3A100FC3CFB8CB94
-:109C3000C18E77063C8D508EEC682AEFEF20BDFC7C
-:109C4000B445415F233C1F7DB5BED84FA29C5F59F0
-:109C5000E541FF7EAFF32BA5EC7C7BA7869DDF1053
-:109C60007ED9AB319EB180A7B7250A760AEC71C6C2
-:109C7000503CE0AB62E143982FD51D22E8CF6AD576
-:109C8000077F361AF4FC7C19EDDE569E67D35A9591
-:109C9000E7035FDE6929F82AC4E9BDF3D9F980B189
-:109CA000D4C2C575434C53023C7914EB2E252B5579
-:109CB00078BA5B51AFB0DEA3787F52F24645FB1411
-:109CC000C7832A3C3DACA8DFEEDCA9C253B30A4FE0
-:109CD0002F28DAC77E1E6C04361ADFE1952D74FE3C
-:109CE000B79E6E2A07BC8C3EE39D0FFC52E4F7340E
-:109CF00082382C3E5A7F044A3FDD4F819FEA7043F1
-:109D00003296471B1CE8673AD63004CBE30D4E7CF5
-:109D1000FEBB86122CDF6D7061F96F0D93B10C34B0
-:109D2000B8B16C6968C1F7F735B4614921980EFA8A
-:109D3000C21EDF73AF423AECE73B35C15A88A0AE92
-:109D4000DB7900E56467BF6027D43791D7A74D80E2
-:109D5000F35CB09902FB0A4A8ACFFB525D7F49A1AE
-:109D6000F54D29AC2EF2125A34AE02B0AF1FD8799D
-:109D700064BB369D90FB37BA93AD365637D23A2244
-:109D80001BFAF01ED9EE4A23E437A0326EC5FA342E
-:109D9000A8779958FBA69D47A679513FB0F8F19D49
-:109DA000E1F8F10330AE3A7EFC9B0B0E0BF8534EFC
-:109DB0005C1D6C81759DE0FE231729D02DA265A93D
-:109DC000B640077AF1B4CA8E10659DA6B409FA6D43
-:109DD000D13867615EF06D3A0279E83324B61FED41
-:109DE000B10353991CEFBADD80FB9D931AD732CC97
-:109DF000779242CF00BCF6A49C44BDD265096500B1
-:109E00001C9E4BF990D51342CF48CE88BA8EADF345
-:109E10005F534EE03E22CA3A77A7448993BF90C26F
-:109E2000E3067E573A9EEBE5F59395AE35A0274EB7
-:109E300096BA06C17C4EB80DC83F5EB7C507F99605
-:109E400044EB2A9E15E157C949D5E17777EA199F76
-:109E500091BBE4A8E7CD4B53999D857883FDDC9CAD
-:109E600018B4C34F6AA29F179F93CAF4F5A57ED179
-:109E7000FD2B77F1F6B29916ECAF6BBD09E3B75D38
-:109E8000EEC1680775D5532851FEE8BA507FF91521
-:109E90006C3788D016C629E77239F59BF6757F3E78
-:109EA00045DF3FBB3EC68932DC7A33EAA7BBF8CB3D
-:109EB000F3E38D68B7CC9F915E067A692E8F772D7C
-:109EC000B0681331ECA5B5E9E18AA0A5E6822DA022
-:109ED000FE97DB2BF5365AAF4EBB7B0B94AB063EA1
-:109EE000AC87239A3543F76E01F3710D65AD62DCE3
-:109EF0002F05DF6BA0F35AB84176B0FD933877B8E1
-:109F0000FA3BE557083A3CC9F364287C715F38375F
-:109F100095ED7BC4777339BD5D4CE1765B1EC9BBA3
-:109F2000A68CE35C063AE998FF5E6E1F7E77653B80
-:109F3000B7DB3ED2B371D5F7508871E771BC9FD4BF
-:109F400013970476DC5D16A48FFCAAAF3615D3F503
-:109F5000E7B75B35188717723CC0EE032BFEDC8336
-:109F6000726E6447F0B95304E9BC0DF8E4467A6AAE
-:109F7000A67723EA87515F53FD0372F1AAE7EC2924
-:109F80006CB5473D8FE96FA8E6F2B11EE5DAD186E0
-:109F90000D583FD6E0C5F278C3562E1F9BB0FDDDAD
-:109FA000861D5C3EFAB87CDC83CFDB1BAAB07CA3A9
-:109FB000C183E55F2DEEB8D40420360FE667BEB549
-:109FC000D340E0DEB4EE7603D229E580679EB44349
-:109FD000FE8BC10AE7EED479306A79DB83FFD65E67
-:109FE000F76164A41647E4BD807D96D937FD9C20B7
-:109FF0000E0BC893114F24DD0EF2F984C36101BB2F
-:10A0000075646A32ABBB1C161DAD973C41EB54BE68
-:10A010009CF0382C065A1F959AC2DABD0E8B89D651
-:10A020006F7D2285B5FB0806A9C73F91713BC89F8C
-:10A0300052221D057E2837664D8094D90A6BE9515E
-:10A04000E08349C98B26001FFC36C5817438C5B131
-:10A05000F128D4A70E69D6C2511B97B960337C573B
-:10A0600066AFD4C27713D2EEDE0CDF4D1CF8B036EB
-:10A07000F2BBC943F76E86FA3467B316ECC1DFA6AC
-:10A08000B0F3FDA21F5117ED42BE8A3CAD61ED6EEB
-:10A0900094E3F96D6E94E3022E657756DE0F7EBA77
-:10A0A000BA36C92AC13CEE947A82EF900B577B9561
-:10A0B000720B95B3D39FB8C9B291F2571DD46FC537
-:10A0C000FA431BA3CBDD99A951F4CB1F389F82DE45
-:10A0D000847CE83FE8D97D1E2FF3F5D5B52FB22C4F
-:10A0E000427DE5B1807EDD9FC2F4E541AE1F2FF3D6
-:10A0F000B29B3FAFD3B8E6C3384B53FBE4EB6A687F
-:10A10000A77CAB3A27D0473BE7EB55A95C3FF07BF8
-:10A1100013D610769EE846F95A2B23F76F5990977D
-:10A12000D3720CF245D5F90F3570CE28A7771E30C3
-:10A13000958B2CEFB14D993FDAB3FFE8C7E41E1CB5
-:10A140005F844D4763DFEB7E2035E1BAEB56B6F313
-:10A1500075AF242CBF59BD0EE24940DE12F9CEBDC9
-:10A16000D7138CBE9E5EEBE0F7EEA9F2ACA91DF40E
-:10A1700038CCA762A18580FF26524E9CBA8E9C5097
-:10A18000CB9DBF973CBB8EBC79319ABC11E79DD566
-:10A19000A5B0E7E09C14E4DBC17D2FE0A7FFA74456
-:10A1A000CF6BD04F5759E82F1AD89FD9834867767D
-:10A1B0009BE775782EE959DC5DE4B15ED0787F0BC2
-:10A1C00076D1B12796A01CEA04E540F9F10D5A07B3
-:10A1D000B9536475FB017E6408A39FBEF233DFE6CA
-:10A1E0007AB177C9F849E42976357F93817EAC1B33
-:10A1F000D07B5F70A890C704E13C4077490C9A3C43
-:10A200001D12F14B85906F9D88764447BA5E0BE531
-:10A21000DF7B9FD8919E8BFDABF78B1D29254636A2
-:10A22000EEC4C950B6E93D3B16C13E699401F749F9
-:10A23000EFF3FCBEE99F5EB583BE9A2EFB13F3A538
-:10A24000DEFBCC8E77E69539F27BEF37E9FA26C054
-:10A25000FA6EB4EF741B03710046F5FEB366C35F7C
-:10A2600008E4458FDE7095C07D6437DE8F1219C417
-:10A2700044E169E711288B3F77611ACE880BF547D7
-:10A28000A01CF535DB9EDF289FE8D62B2D47D8F1A3
-:10A29000F0A1CAFB164A7ECFF6ABBCEC754FDB2AA9
-:10A2A000AF324FADD45F8C7914723016CACB5210D6
-:10A2B000FD5EB286DDC320EE5FA0FBD8C401C5B051
-:10A2C000EF65F952E321CF884EAEE2A71F2FB817F2
-:10A2D000F9DE84F64FCF3EF6150DE609B46A5DFD52
-:10A2E000C7C23E76C320E7465AFF8F40C22F0ED02A
-:10A2F000B2CEFA1712797F5BCD866E45BD6363F8E7
-:10A300009E20C883AEF99B8C7AA78690AD80AF1A49
-:10A310007258BF36420F9296FFEC81FB302AE72A33
-:10A320000170B8AFD24C77D1F72AF97E83781B59E8
-:10A330009DEFB308F9EC7617EDB73281BF4F664F4A
-:10A34000C77ABA68AF62F541A2BFD7D8FB29A2CEBF
-:10A35000FBBB49D47FCEEA59E2FB16F67D9E18FF7F
-:10A36000BDDBB1DDC2DE1F3F60FD74900342BE570E
-:10A370000CE0F925FC7E1F2AEFA70C48B86E5E8919
-:10A38000B29DEB03719F4FC54FA7C4BC07FCDC22F5
-:10A3900061EE5BCD7D3AF46F5F8A6BC98F3C9F2C79
-:10A3A000F250DCE51617D87B6B5E1DBC4BE6F93826
-:10A3B000606F6CE3F1E50AD98CF188EEED4CCEF7D5
-:10A3C00065AF2DDFF0BA029FBDDAF93DCA18A8A328
-:10A3D000E35D7E2809F3DBC9C000C6C3570C90C4F7
-:10A3E000F92A3CDF2AF2BDEC39C405FB53FB6B268E
-:10A3F000764FE5E70194BFCB5F63FEDE353B8FA070
-:10A400009E5B2C3B908E0F6779D600DD765AD87D07
-:10A4100084CB37BC81FCBA2193DB09D6D050053CF4
-:10A420007BC3FF9E1BC0FF9E7F24FCD57E66713ED2
-:10A430007AD577CC4BEBB4B038A893E3E9538D636E
-:10A440000487D723B09ECBCB02B9361992860389F5
-:10A450002CEFE8DD62D80775D75BF09EA379EB3E61
-:10A46000C98F3C97224AB5FD7F0EF8A8380CAFE69D
-:10A47000DEF07D16F0731DF82ADB7F60F826698315
-:10A480007A27C44D4FB37BC746043ED547E6BBBCD5
-:10A490003580E9DDFEFC1E6A75DED65B032C0C4FB1
-:10A4A0003C1EB366C6BB63201E23F8617C0C6901A9
-:10A4B000FF3AA56B27A76B27D0B5A0DF705C867E1F
-:10A4C0001785BFC2F44B147969EF0E50DE0B46E1DD
-:10A4D00016B801DD06FE9174DB4AED5F8C63BE6247
-:10A4E00042FF891ACE5F71B80A786BD3AE0F676DE1
-:10A4F000DA0F03676D9A43E17F10F0EE4B3FA9F14D
-:10A5000023E61D854F8BBF0F9F36A67339A50D62BD
-:10A510009EA81AEF3169BDF0DE3FEDFA7857B6FF1D
-:10A52000C07857C34D5DD6F0F8A6FA795E9A88FFD9
-:10A53000FE3070FCFFCD7F3EBFFE90A27DE18677AE
-:10A5400014ED8BBC1F28EA638281722073E10F1F18
-:10A55000772184F6E5F7F5ABF7E54F9FFEF20A0D9C
-:10A56000C4DB4A02CC9FFF65BA67531A85F3FB1A16
-:10A570005FA385C275E49916766F57752EE60FAD09
-:10A58000E373FC6ACC7F9DBD97D2CD57C480FE4E4D
-:10A59000FFA19BB48EBCDE74507A45435C11796890
-:10A5A000A5469BD685FE1AE28A46370F70BAC1FCD3
-:10A5B0001FCAEF5546A2B3533EAFAA9230DFA98A15
-:10A5C000B07C685AFA3DB47DBA96F8E1DEE34AB34E
-:10A5D000D66FC0389FF23CB381DF8B4CECF18A73AD
-:10A5E000CDB24BC6BCB459252C3E7897B905CF9354
-:10A5F000CE39BEE9F2BDB49D6CF616B37C6B71FE2C
-:10A60000EC8F9AEF12F77B208DF17997C4E3C89213
-:10A610000EEFC7527F37378DF1D97479A30CF92E1D
-:10A62000A10F08DADD82EFE8FA8E1B0AD9F90AF8E1
-:10A630005D8A4AA2F30FC6F3CE0F97C3FB35271DE1
-:10A640000897BA928DF980C7BA09D239437E785FEC
-:10A6500053B7E16BECA7427EB111DEEF3ECD5CE17A
-:10A66000233BE83EC511E9AF0C2E00BEBCD1FE472E
-:10A67000CCFB4C831FE9E96CC3712CDF1FF7FB6235
-:10A68000B033820D81A87EC9EFEB1F107E01E12758
-:10A69000107240DCCBB7378DCB05A33400EF53D31A
-:10A6A000B252C8CBD7D27AD92B076E205F0FFC23CA
-:10A6B000E5EBB7A5F39A64A617D5F4ADA66B41CF29
-:10A6C000709F37FC1EC15DD4DE03BD3A9778F36AF4
-:10A6D000A89CAD5AD1A41B2D7D7FBA5E65FE3C833C
-:10A6E000443967F2DDE5B983E54796CBB83F10F909
-:10A6F00009020F9DBDF1D69D767D3B53D9FE0FB764
-:10A70000E33F5FF0FDF41A51D80396F45EEBB6A573
-:10A710005F7FDDCAF61F78DD11E75F16C89AF07912
-:10A720000FC81F063BAECBC7CE33566735E13DF2AF
-:10A73000A424140B76E3CA8332D221D1BAB42911EE
-:10A74000F74D7510FF47408F2BC6ACC07370BDEE40
-:10A750008932B7E2B938F57D51225FB896F7A3BECA
-:10A7600037AA96E709D7AAF27646A4F3FCE042524C
-:10A77000C8F22B9476A9BAEC6C200ABF64E7D50620
-:10A78000F4038C4B6FF999372D8C8709E9BDECB830
-:10A79000C937C0DBE47F24DED4F42A5B76E379A8F2
-:10A7A000EF4AAF57335DF3D313C272781EE47015CE
-:10A7B000C13DEE061FDCF72FEEC7EE92D87D345D6B
-:10A7C000E708FA8D6E74BFF2A8931E3CCF39F25D94
-:10A7D00097CCF20858BE81B05384DD32BA2324B33B
-:10A7E000FBEDF939289E17F46DE5973360453B473B
-:10A7F000F8DFFE5E7E6BA1E70E1A995C13FEC1A224
-:10A80000A01BEDB84E9DBF18EEB3F7EE3745B5036C
-:10A810007E96AEB9EE3DAE7FB5787E06F43293CB30
-:10A8200077719F6B85CCEE7BEE0EC8E8BF5BFFCFE8
-:10A830001FFEF649C78DF7F575D6EEA8FB2251D657
-:10A8400069D87989C27207E6EDC17E09FC77C29F9B
-:10A85000A77EFFF5CC321FCCAF421E83F76B76EF9D
-:10A8600060F3E90B2F751B42387E9FED7CFCBA83A9
-:10A87000C5D6C8FB30CEA5F7ECCFACE78D61BC7E6A
-:10A880005BFC8F0D5529EC9BFFD7F70DD3656A3A1A
-:10A8900052FD9827F9987D4A989D3A8F04B05C4004
-:10A8A00042587A08CBA75F4C9C582E256E2CA76582
-:10A8B0007A4EA5637E4B2811F3215FFDEB50A09BE0
-:10A8C000CBE3463741EEDC0F65A775153870FCAE5B
-:10A8D00057FE9A01792D37E2FFF858D70598A73A25
-:10A8E000AEF16FA532C64F88712DCAFB4A7E4B026E
-:10A8F00099C0E262DB12B390DFC2F22FA959C83FC0
-:10A9000088B7E69DD3B0FC909512DEE7DA16D42026
-:10A910006BE52DCBF2C1FD3C6DADAC3D6F8DCD2710
-:10A92000D17ADE28136BBFDBE683730FF34910F98E
-:10A9300071219C7A90E11C0C936FE2FE736AB167FF
-:10A94000839DB5ACDDC8F2F7497020C8F1FC3EF636
-:10A95000371332189F0FCB66727B5899D20FD18F65
-:10A96000B7AFCC2C5B960171D90C574C065DDFB0AC
-:10A97000B8C0B6478AD02F8FBFB3F2C5A87B307E50
-:10A9800028BE6BCA2CB3C27B2F492CDFDC7B90FF27
-:10A990006E01092546DE273A2DB33C11DE4BCF2050
-:10A9A000DC6E8E0E57F83D3A7794FD9CC8671C0606
-:10A9B0007B2AF48FB37BA95E92583DFF19EB1D9B58
-:10A9C00087A20FDF0B766D53A66730AC63989E109D
-:10A9D00033CCFF69836F17DA9FF519E08F5CF18C38
-:10A9E000410376C1C754ADC2B9927F6F3062F90995
-:10A9F000DDE742F91F749F0BE539BACF85F233BA10
-:10AA0000CF8572D91527251A42DEC970B9603D225B
-:10AA1000DEA69EEF28016F31FE413D8EBF32D3830B
-:10AA2000F0EDC1F77EE28378C84BB6506ADC75E87A
-:10AA3000AD6F39E3E5FBBDE8F959C332D8BE36BF87
-:10AA4000558B7A3CBF2D18BB3CE2BDE9197A6CCF1F
-:10AA50007BE5733C27DA69ED81AF4BA24B9EAE617B
-:10AA6000F5E9CFE4227C5766BA96C1BA297FCF8038
-:10AA700075E4B77DF82F709E87F68F79045D52E8F4
-:10AA800031B4F355EB50C341ACEB255B601B7CFF4D
-:10AA9000D22BD9B0122A6F08E31BA02329DA7A3708
-:10AAA000E27CEF30848AE09CCA1DD7E4A879C32BEE
-:10AAB000334B11CE12D05B42049C38BEBE2F5FF7E1
-:10AAC000C4B3399D1271BF06C84E07E8A1ABB1608F
-:10AAD000D755F2787D5BEBC0F7617DDEE33219E498
-:10AAE00040FA55F0DD0E8E1F51E61DD4BB014F2FED
-:10AAF0001D3C3F10EE5FA5781908F7B16ECD18A484
-:10AB0000F02FE68DFAE68947ECF83EFCB21A95CFB5
-:10AB1000CD15904F32D778E82D58D27CEBB90AC8C2
-:10AB20002759982C1D837291236B22E491887CF71E
-:10AB300025434A8F012B4D7356A23D560AC225422A
-:10AB40001F941B63F865D042FFC42BEA9392072839
-:10AB5000DE9FE2C851B44F1D728BA25D8C3BCD3994
-:10AB60005CF1DEB0B85036ECBFE83AD8FDD7CFCABA
-:10AB7000987797F7CAC9DB6EA1F5E9CFCDC2FBFE86
-:10AB80005EE2EDD3F795E3EF0B765178EAA92175F4
-:10AB9000A1E4C1C71E81CE54F67DCDC15F1E7339BD
-:10ABA000AE63DFDFC0AE17F27575BBB118E4EBB76B
-:10ABB000B5F3D578792583DF1FC2EDFEBEE8A58702
-:10ABC0001F2407A3177EDF969A5E20B394D11F2B14
-:10ABD000A79F60E7C0BEAB1CFB13C8B18873983D4C
-:10ABE000A5CADF364CEF7C7F1DF8DFDF93099EABF3
-:10ABF000E3E7F396C3BFE5309D93A5CDF7C37D5240
-:10AC0000F4B917EC4F3807EAA2FD5FCEE07653CDDA
-:10AC1000A1FB538AC2ED64FD39C5FBE43E698BA2FA
-:10AC2000BE394B59DF5EBA25F2FBBEE4E1F21D8B63
-:10AC3000F41E3CBF2945FD3D57319F8AC326CCCF2A
-:10AC4000BB1DF24EE8A3DAA20FB4106FBDBD0FFD1D
-:10AC500029E4CE1C99D4476BBF92C1E28ED30E9BE0
-:10AC6000309FE5BBF6FB318525E60BBEC6F4E7C792
-:10AC7000FD03DA48BCCB99ACFFCBC50FFFF35F20D7
-:10AC8000EEB99F60FEE6651B93FBF9AD5F6834B4D7
-:10AC90001CD68FD14BBE35A8017DD2551DE385FC56
-:10ACA000FCBA9516CCEB1C961DFAC85840484CE6E9
-:10ACB000B69F1B29BDFD110E3346E8D32ED8E3D035
-:10ACC000BAFD5F1FBC6333FDF7D4C326BFE67BAC80
-:10ACD000C74E6D28D47F658CBF1700DD70BD02BEE6
-:10ACE000F3BAFB498F9E017900EB87FA6D990FBD8E
-:10ACF000FF289D77DD3B8CBF21534EBD6F9F1BB15D
-:10AD00006F274F31BE34D2FFC09E5B75B4490FFB35
-:10AD1000B91BF3770BE6CD7C5BBECECFBC211F9F6A
-:10AD2000984AF152B79FDD33D1DD3E08CFB5F6A585
-:10AD3000BFEB766890FF44BDB35D9E0CF4AA3E273E
-:10AD40002EE049ACB98A7B9CD68EFDAF19A027D7DF
-:10AD50001ED4B2648FBEC6D9AA218E88715E7AC312
-:10AD600050CD7EA792CDBF4BE8E7837F8E2B1DCAC7
-:10AD7000CA8D51F41CD5CB3A3BE8E54AF67B0BA7CC
-:10AD80000E269501FC4F49C4EFC073572CCF78268F
-:10AD9000EB0E9E9BF1FE90E421DAC87B0EC53E725D
-:10ADA000D6C15983C08EFCA875F1298A19B22833FF
-:10ADB00007E96536F1A2DD7BCAE64E077FC3741E44
-:10ADC000EF3F650B75803C3E35364682F83DED7FA2
-:10ADD0003389B8AFEF94CE9DCEEE831079C5377F1F
-:10ADE000AF7BDB2AE4FB4AA742BC7A1EB1C23EF22B
-:10ADF0000E99D9B5E44DC69742DED549813898E71A
-:10AE0000B4CC19EB3221FEBBE167B8AFEC819B9665
-:10AE1000FFDED3B7B46B7BF6AF7B24764F8993D933
-:10AE2000FBB5632EFD62369C73A3FB6C89CE677104
-:10AE3000DB21BC8747BDAFEED9DFFC0FFDA3BDF71B
-:10AE400047EE87607DC2EFADDE27F5D8E5C2BE7B59
-:10AE500096E5B91F19FB78E76A5A5FFF6C0CC2F1DF
-:10AE6000E233062FC8EF8BBB0CB8DFB918173AB323
-:10AE70000EEAFBF29C5E1C2D17CF7709FA5EA171DA
-:10AE8000FC01F40EF99D0EEFDDF8E26903FEBEC78A
-:10AE9000CA5FDEB40BF64F5FA43B7EFD22F8F77E5F
-:10AEA0009D80F7019064F6FDED9C1F81BF1C141F6F
-:10AEB000F2F316B41B56BE9C82F24BE0EFC2D326CF
-:10AEC0003C077FF1F8CCFEE007EBD0EC65BF3329FF
-:10AED0009BBD208757EF32A1DD47F49E9760FDE5CB
-:10AEE000CFDF3E7B388CFF610281F574B5BF8CFEED
-:10AEF000C7307EA3EBF5EEF61C26077AF42CCB9B2D
-:10AF00005D18BEA7F915E87F0D11F720B2BCD94234
-:10AF10005962BF3BF950F473E0C73299BD5823FC26
-:10AF200025F1C4980C7CE821ECDEC78706E33DBB25
-:10AF30006733F9F96512E2E71D05BD9DA93D80FE65
-:10AF40001203CBD7EBE35ECB1399367C7FB9F16B61
-:10AF500085DFA476C315657D28FB1DE6C246C7F0D4
-:10AF6000BB69B98EC3F9BF92DCA7607DAB5A1E7E68
-:10AF7000F55D84CB533FF9238C7BDC8C7E1AF22E5B
-:10AF8000839F7AFFB2DC18E271876685DD7B7EE7FE
-:10AF90001F307FE4FC2BB7E0EF942D9603E7E17EB2
-:10AFA000AC4E4BE0ECBDB4DC77FC04E2453DDF5E2B
-:10AFB000717889C9951A58C770C85F715FCA44BE55
-:10AFC00065FCFEE9B63C849FF0D3765D8CBEBF1273
-:10AFD000F314FD8BF989FEC57BDF707C5DD607F22B
-:10AFE000412FFB200E11B1AECBB1817CF8295C5F03
-:10AFF0003ACBE7BE1C47EB117473A378CDFF055C19
-:10B00000F134E600800000001F8B08000000000003
-:10B01000000BAD580F6C13E7157F77679F1D623BE0
-:10B020008684FC217F383B10D2262447FE786902B3
-:10B03000E39A908822B69AC0B48CC138DA42293497
-:10B040008D97C086E8242EF5C43F819A69DD46A716
-:10B05000D2192618D2404D3340AC02E68256C8863B
-:10B060005A77651ADD2274CB5A16AD2149195B85D2
-:10B07000D42D7BEFBB3B9C73025BABD98A5FBEFBDD
-:10B08000BEEF7DEFFDDEDFEFDA00E26A15C0B3B997
-:10B090006F80A31AE8137667037C05CC4F56A6038E
-:10B0A0004200ABE87F099FD7FDF62EE703580DBDA0
-:10B0B0004E2806B8CE776F130580E1DEEF3B550FC3
-:10B0C0002D5AE2BF590AC0697FE4C7CB00C6E9B375
-:10B0D0007832057000ADA3CFB840BF1AC04CFC6DEC
-:10B0E00084D208F2B9E5F7687C25C02C8973DC743A
-:10B0F000E3742114D23A9C97E33548FB5C7214E563
-:10B10000D9C6878B24DCF7AC18AF0021B96F1BAF11
-:10B11000B2E7C3DCD58D10A4E3E215612FC0E8745B
-:10B1200011B80CA433E58492857CFE01F251E4331E
-:10B13000EA84B63E3CB7A6898FF4313D1C833ACAF7
-:10B14000C703C7E4AB29C3E7E5008BE8B9DB943B51
-:10B1500080CF2BEDEB93FAD8C767249EE95793C9AC
-:10B16000477ACB27E3F1B8391F85B840B8E2679535
-:10B170001B716F307107500440BB3C678E9F737B1F
-:10B18000E24205CAED736B02EAD3700EED82E3066C
-:10B1900047FC4DA29C02B07D06AE3DEB1CBE2707CE
-:10B1A000E1905BE6203EF5A67939E4B506D7EDE2FD
-:10B1B0002240E7BAA187D17D5C82C9F1451863546A
-:10B1C00001BF8328C2CFE8120833DA021146974242
-:10B1D0000FA3CBA097D1E59060141E8E4721402786
-:10B1E0007DC77F331DC9634FF3E3486BBE0A915E91
-:10B1F000CF641CBE4938D43E08078D237FFCAC3891
-:10B20000B4809ACBF8A5E25150CAFC3B150F17F950
-:10B2100023DA2D0D62B94417812E105D4C8E8B7C84
-:10B220001E05C941E32650D8B8F97FC4A14E571D69
-:10B230006AF91478344DED173B4CBF1827DD6726AB
-:10B24000ED745292D8D8B217A09CE1F993ED683D05
-:10B25000AF496FFCBBE407F841AC31ECC8C3717572
-:10B260006357318E8F49ADC6B8A1F117411C1F8FAE
-:10B27000AD0C3B1E21BF6EAC76CA00DDDDABC24B10
-:10B28000705E4DF35500C615B495F0E43F5BFD06C6
-:10B29000FE6AF736D98F71A4167A64D2CFED42CC0C
-:10B2A000103FA158803AA4454BE3179DB86E89A87A
-:10B2B000F6503CB6BBE33E0971DFDADD9C03A8EF34
-:10B2C0006ED158EFC27DEEAAA45EF85C4BC3715FED
-:10B2D0005F591717BCFFF9C8F790544B72CCD58053
-:10B2E000E438CDC986251B73DA304F0C279CB04F4C
-:10B2F0004A9EF3A31CF508C901EE1220BBE7BB0D63
-:10B300003EC37D65656497930412CD6705AA09B7AE
-:10B310000F73C22769FDA8D7F0AF936487DAFBD318
-:10B32000DF4BCACF697DEAF3D10F5100DC7F415278
-:10B330005F27793BD23F2DA1BC34B2E0BD5D7A20BE
-:10B34000E9A71C9EBF06F58E2A1013591E59E8BFA7
-:10B35000897914D006E368CFD10DC80771A809AB6D
-:10B3600051273EFEC29AB1102629E27B8ECEED1007
-:10B37000F5A205B8EFA5953744C3CF0A0C3F33F3C8
-:10B38000D0F90BFDCFE71BC3304C88AB8E0B77FF9A
-:10B39000F927C4AFE3B647A6E5C9787AB90B7CB400
-:10B3A000C863CB1B569CD59F75C5051F8D1FDA4002
-:10B3B000EB16BD37504C7A2D1ED0A35EE273FE0F04
-:10B3C000F9861C665D503EE13E4F5D6816283903E4
-:10B3D000749E16622EC4AB938B5CF2D2F824276B5A
-:10B3E00028FF5FDDE81F19B45EF1E4A15E9B4CBD50
-:10B3F000DAFB8FEEF222DDF4CA93CBA182C2C1C97F
-:10B40000F2B7845F8AFF2DC79DC97CCE7ED110A87C
-:10B410006707589FB8487ED0DE6B5FD701FB3FA619
-:10B42000BCD33131CFA35CC392378BD9CBAC57405F
-:10B430002504F93D6DEE253D3C24F77931E6E29097
-:10B440001EEA92FD3436E3074EBCC0FCD25A0FAF61
-:10B450006432DB5BF1F4CC1E943D338957E53197C0
-:10B4600042B8571ECB5148BF4A11D68519DE31E686
-:10B470007795E81B1CFAD36BD3C7823C9EF3DAF9AD
-:10B4800052193328BCB15381BFCC49CAD769C653BE
-:10B49000B370A249443FB8FD14F83124A1B3FFA70B
-:10B4A00051378E3BF702AD80DBF4837C6E0FF131B8
-:10B4B000E253DF5F9D4BF63E65C6A72B97076902F7
-:10B4C0004E69D234904A93630B5F97699FF4D21907
-:10B4D000B679AF3CCBB63FA32E68DFAF2989F21017
-:10B4E000E56363FF74E561DBFADDBE962BE4978BC1
-:10B4F000121B97132E994BAB6CF32170B3FEA1B6C0
-:10B50000C023C7703FDC31EA791D7E593D808840F9
-:10B51000FA35E8003F467BD40F3B6C764FD3D11F02
-:10B52000715DDAB50976C73F97641FCF0F987E50DB
-:10B53000000513FD2089B3E71E8ECC0FFA7111E1CF
-:10B54000EC1563D8724CC22904733268BEF68A00C7
-:10B5500031867B971CC7E733C376BC73DAEC78E798
-:10B56000A9767CF337D9F12D8CD8F19DBDDD8E679E
-:10B5700040B3E357BCA7DEB67E6E4FA36D3CEFE051
-:10B5800032DBFA8762ADB671D9F1D5B6F5F37B9FA0
-:10B59000B0CD579EDD6C9BB7FC2AD5EE0BE29DB675
-:10B5A00075A976AFBEB2C3C6D7B2B386DFFFA79D7B
-:10B5B00037A7D8F95B281BC5DDDBBEA1FD14865F6C
-:10B5C0004E37F252B3B030A190BD173A65B2E93BA5
-:10B5D00052669397E2DDAC4361B30E417817B37BBB
-:10B5E000D8F41339215FA23C5A753DDCE4C3718D58
-:10B5F0001EB944E93834D4D39421313791FCB89E34
-:10B60000337179BC8E03872D5E709C9DC46DA5D669
-:10B610002D64E0E2864F6351962EC9A9F0FC567363
-:10B620009EAB33F2FA0A250D1C13F058643E072A2C
-:10B63000DAC86FA131052BCDFB00F6E520525FCEB5
-:10B64000BB63D1C054FDA47C50607D92CAFAA6CBE6
-:10B650009CEA24BACA9D28A2FA75285B7D298079C4
-:10B660007E849725D667717A94941A25C558D17926
-:10B6700027AC9453FF8EFFCEC2BCCB5F0D6B1E2652
-:10B68000BE5F47F955539EC301F55000F11FE4FC1E
-:10B69000BBAA71EFDBF51F1551FD71098804E6C1E6
-:10B6A0004C9FF2133A47DBBD703AB35B0EEA8779E1
-:10B6B00054E725D63F683B38761FF888983D3221FD
-:10B6C0004EF73859DD01F37EB4D6C4CBBA1FAD3185
-:10B6D000CF1F44169B304FAF3D7B99E1B2257718C1
-:10B6E0001C99CCDF589FF46481A76A1FE9A454CB4E
-:10B6F000ADF3E9B9755FCA173E4B5D6C16CA33F4FA
-:10B7000029FA458B6EC91D62F7B97BFB4F1875E4AA
-:10B71000FEFC355667937A1BFC07F7A6B3FA32B8DE
-:10B72000B7B0916892FF08E3BF36F2AECD4FD66D49
-:10B730007FDFE67FEBB53FDBE6F5AC31673EEAAF96
-:10B740009FC96BF93AE277EBB42B44F746B4DB358B
-:10B75000B28BC55F3F306F099DF7DFF5FC1BC377E8
-:10B760006067021C73927ADED8799D8DF59D3AA3AD
-:10B77000A97A5AF74C8B8A17A1D481F619E3A6C986
-:10B78000470293CFD91C34FAF08147B31BA9CE0EE0
-:10B79000148A0E839618E3BC3AB7316E594A74D4B2
-:10B7A000E9D943F7CC010E140EFD610DA7BCBA1EFA
-:10B7B000F97E3B5BFD98FCB363F3588503E3A1A3DB
-:10B7C00052FF0647A97FBA7A87F4E7B0BDCB9BC189
-:10B7D000E42CA1BE6388D72A38CC0515C19C15D4AA
-:10B7E000970F4DD346A812971C99618C45233E4272
-:10B7F000C17FB178A8F1ABFF263E1F70429CFC567A
-:10B80000FB25173BCAFC4D175BBD2C9EDAE8DE45D5
-:10B81000F75DBA6F8CA619D419E4987E620AA55E0A
-:10B820009D682868E4B566617F0947FDC1411750EE
-:10B830003CE0390AF515DA7957EC288EB35176EAEF
-:10B84000537E2D1AFD7CD5AF5C71CA1B1BDD77982A
-:10B850009DF28201C62FAB183317F2C97AD1158B2E
-:10B86000927C7AA26805CAD7E3C4FE85E2FA1ACEB2
-:10B8700023DF5B07E61DD937C11E7941E37E084F00
-:10B880000118F3398769BEBD7FF006E5918B01B5DC
-:10B890003088FC0779294479A4DDF7A648F9A73256
-:10B8A00028B17D282FD317F3C1773986B3DBFF0189
-:10B8B000FAEB3A4C3619747FE3D5B9C15ABAA7E806
-:10B8C00022F1438F60FDDFFDF4BFB521F1C372A407
-:10B8D000235EB988CEB1CE45392A898FA5B72547D1
-:10B8E00092CF83FD7AA37BCC16BF375FDE5D4271BA
-:10B8F0005225700C9FD4F52D262E034EA3FF4B9D91
-:10B900005F4FF6AC9DC23EF3007291BAA661AD43A3
-:10B91000BA927042FC6E7D0DF5617D8BB280ECDBDE
-:10B92000DEEA91296F59FC918FFAFA03CEF92427A8
-:10B93000FC25B2C3E6C8F7CE5C9592F3E87FCCAEA7
-:10B94000DA01C35FDA2FBC7FE3793CE5999FCDAF85
-:10B95000A63C6DED4FC579C42BB1F73B4F087186FE
-:10B9600023E2BB9AF8F75DF95D36E162E1FC79719B
-:10B970001D2D4C88C47FF4F0DD2209F7B79FBB7CF6
-:10B980009DFCB6DD7CBF00A7ECEF0D102F8DEE9374
-:10B99000F7EA08E5D6D96C9A9BD8B7B9ACFD050E85
-:10B9A000FB7E6CD0793CEF94796F394BF9628AFB5E
-:10B9B000EDA904CF4AF4A95CEC0BA9FE60BDA77AFF
-:10B9C00063D5FBADEFF22C0EB60680CD935C6457C9
-:10B9D0004E7F8BD51FEBFD4594C3BA8AB8758AEAB2
-:10B9E0000BE497A076B17A24CC46BBE2BEBEDF2C36
-:10B9F00033EF69467DAB35EB592DF121F9CB335847
-:10BA00009DAB31CF0DB9B17F0A52A9D0CCF734E646
-:10BA1000FB8CBD6FD9EE77FF01E91E35E2601400A3
-:10BA200000000000000000001F8B08000000000064
-:10BA3000000BFB51CFC0F0038AD5151818D6293159
-:10BA400030DC5266607055616038278F90A31556C0
-:10BA5000E5A04CFF0B4606865740FC0688DF319276
-:10BA6000AE5F4B18C15EC9CBC0A00DE4D7006955CD
-:10BA70000106062E205B0788F701F9F780F81510FC
-:10BA8000BB08313070F331309802B11810EB02E589
-:10BA90007D81F4373EECE6EB09E3B7FFB9002A5F9E
-:10BAA000521095CF20805F7F97207E796921D2C385
-:10BAB000C44E9DFCF868A240EF40E09B0CA87C0BB4
-:10BAC0005906062F3906861E7908FF1A92FC3CA0FB
-:10BAD00098A52C345CC5816907C8BFCC80DD5C1992
-:10BAE000A0BC36507E15D41C00DF43986568030067
-:10BAF00000000000000000001F8B08000000000094
-:10BB0000000BE57D097C54D5D5F87DF3DE9B2DB384
-:10BB1000852C842D4C58141070085B1094C9860134
-:10BB2000020C8B881675588410208980FD51B51F32
-:10BB3000139688967E0DA2965AB0030D82FDB00D25
-:10BB4000183560A0C366B1451B5C10BB7C1D16D9BF
-:10BB50000C2404A5A3C5FADD73EE7D99F75E664853
-:10BB6000B4FEBF7F7FFF7F102FF7DDFDDCB3DD73F9
-:10BB7000CEBD910D76424613F235FCD07499400843
-:10BB80004989A6F4E79F5FA71232C94CFF2512929C
-:10BB90002FDA081942C8441B099A689D89A3E8C78F
-:10BBA0006442DEAD128222B4A1F502C3082926EC5C
-:10BBB0006792446A85DB0969CE7AB562909B10C1B1
-:10BBC000EB25CB3369EA769199908E3AF085E020A7
-:10BBD000C4996520A40F6BF335FD9BE8B5625F4AFD
-:10BBE0003EA9A083269FE2EBACA9DF71460F4D79F9
-:10BBF000277F3F4D7997A24C4DBE5BD91D9AFADD48
-:10BC000097E768F21981719AFA3DD74ED1E47B57D4
-:10BC1000DEAFA97FEBC6D99AF2BEC1624DF96D3B8A
-:10BC20009668F203AA1FD3D4BFBD76A5A67C50E8C0
-:10BC3000694DF9E0A3CF68F243EB5FD0D41F7E7269
-:10BC4000ABA67C44F8579AF29117766BF27736EDF3
-:10BC5000D5D41F1D39A8C967933F68EAE79ADFD793
-:10BC6000E4F35D7FD6D4BF3BED8CA67CACFB534D9B
-:10BC7000B98207E3FB5CD37C9FE0F987A69D447CF7
-:10BC800014D884184919A6665289A99554636A2361
-:10BC9000F5989E49F7DF8FF8F962A08250BC5B15DA
-:10BCA00068FAEF249ABE9BD5D3E9EF0FBD7909A1BD
-:10BCB000783B91754D269A6D2191E299C94C0216F7
-:10BCC0008A0A8E08C5B7248A771182A92B42F16DA2
-:10BCD00030C5BB8819D30E910EF83D29E2C2343924
-:10BCE000D219BFA744D2304D8DF4C0B463C48D695E
-:10BCF0005AA41FA69D227D30ED1CC9C4765D221E6C
-:10BD00004CBB46EEC0EFDD225998A64772F07BF798
-:10BD100088175377641CA61991024C7B44A660BD1A
-:10BD20009E111FA6BD22F7E3F7DE911998DE129946
-:10BD30008DE9AD113FA67D22C598F68D1461DA2FED
-:10BD4000B204DBDD1629C3B47FE431FC3E20B21C13
-:10BD5000D381919598DE1E0960EA893C8DF50645F0
-:10BD6000D6629A197906BF0F8E54623A24F2027E87
-:10BD70001F1AD988E9B0C8564C8747829866457E15
-:10BD800085E988C80E4CEF88ECC6762323D5988EBB
-:10BD90008AECC5EF77466A31BD0BF02D09F02E8491
-:10BDA000A937F27BFC9E1D398A694EE43DFC9E1B3F
-:10BDB000A9C7342FF227FC9E1F3989E998C8694C1E
-:10BDC000EF8E84312D885CC2746CE402A6E322CD30
-:10BDD000D86E7CA409D3C2C897F87D422482A9C238
-:10BDE000EF4896DC1056F0AF07FC7FA6EBDC6D94B5
-:10BDF0002F11BFE16B9A121BC58311D1FAFA94720D
-:10BE00003BE49332C5AB048ADF899417023F9C5808
-:10BE10002604EFCEA0F8911C3E0C7939CBE436D144
-:10BE2000FC03A44906FC25A4DEEE1B40C88111E7F3
-:10BE3000BB8629BEBE9B12EA46911B7E90DFCA30AC
-:10BE4000A79EC06F1BA430FD3E31F9608ADF06ED6E
-:10BE5000296D64027AD3F101BF293A025F7E402244
-:10BE600001079DEA71E86104D60B99687E6621F1AD
-:10BE700066D2FA15234C3382749C8A4C5F918FA64C
-:10BE80003FCEF0CD80F4F7403C74FE87787A9C1862
-:10BE900030FD32DD85E9CC477A337ACAA340ECD451
-:10BEA000361C1E4865ED88AD291DD6D7DE7612A159
-:10BEB000ED8646EBBF4C7C1FC2F7400EE953668B04
-:10BEC000D6A3DF4F42BD18DFFF1CEB7BAD813202F2
-:10BED0000AFF400763701BC827E2764E867999DD1A
-:10BEE000CE29F6F8F37A7285ABBFD44B3DCF20CE86
-:10BEF000EF4981CCA866FC256DCA00EC1FE561C046
-:10BF00006AC1FE450E7FA5DD67004FDAEE3D8BAFBF
-:10BF100091C9537757848BCDD52EB8D076D7112EB3
-:10BF2000126D676F7FBBF869258333F1BA711EFC10
-:10BF30007BA9890404BA8EA66DF6E0D60CC06137E1
-:10BF4000F2CF221767A0C9141854AE1725C21208E1
-:10BF500039BC3F2164A0F573B6D9B7821ED09813BF
-:10BF600078DE0770DE2A936DB4CACAFD3F3AF173DA
-:10BF70009ACFD9221313CD2F48786E18A170BB55D4
-:10BF800010D8F801EF815EB47F3F517EBC02F43FD0
-:10BF90009FB0FE1B054647816D4E84EB85BCAA8A87
-:10BFA00091340DEF5B5C48281F3F4FC1DA89E2F7FF
-:10BFB000022B9120A51CDC88F009C867C38A7C414C
-:10BFC0007A96A279B1757E3EE415FAA7EB5E1094DD
-:10BFD000A379FA77E10E6D5E052FDCF7268B1CDC6A
-:10BFE0008A78D585C1478197B70B831F87579E45B0
-:10BFF0000E1892115E41E0034EC18D7028B2C82127
-:10C0000091F65344E1082458B4EFA95480D3C21DDB
-:10C0100016D759D5B88BAB1335F9D2DA4EAEB32A51
-:10C0200039DA7CF4970EA0D3256906D759CADF1AEE
-:10C03000567893CED22DBBB2A20053053F16576758
-:10C04000B86C9A7EB4F9E64AA180E1B7DB396D405D
-:10C050007C3C5B9266749DA5A47A690793B797565A
-:10C06000985D304EC30A978B8D9B86A902AF45CB56
-:10C07000AD585F995FBC7EBFEBF9115243CE9881FA
-:10C080009FD3B29EF1EBC7A527E93323D2499D7C0C
-:10C090001DF0C64CFF7E6D403CC2BCD26F69B51826
-:10C0A00030DD0EDF776AC6A3EDDCE754F2253EDD16
-:10C0B0004AE49C0A2F97420748A766DC673FEDD108
-:10C0C00049FB6B946C6B418F9AC0F1A714EA517EC7
-:10C0D000B0D81C36FAE9A7CB356C3FE28D7369C541
-:10C0E0008E2EC0D78ACC9546605645D57DF3809E6E
-:10C0F0002ED7AC4A05F9B2506CFEBE2F46FB1F2B63
-:10C10000741B949BB4F232C8E749FBD5D019B1B582
-:10C11000AC9BE61B0C74285BEB7E7F2A30B953B2D4
-:10C12000F3F8989174FE25B5578D308F0982FFA7DB
-:10C13000424A74FD02AC9FF653BCE39411D677419A
-:10C140000EDCF278C64DE0D96A9EB6B47309AAF93E
-:10C1500005A82249E9757616A757E2BEF7CF943EA7
-:10C160002FFE41264FD379901BB4162D4FE7A573B0
-:10C1700089CF01F09A5DB310F9CF45E03F208749A0
-:10C18000E530C08FCBC45000EBBB4CDE730C56C106
-:10C19000EFA060E4F0A1AA2CE507261C0AE1D6096D
-:10C1A000F895A9A8A25E1C08DFA500E74BC2D7C876
-:10C1B0004F8202F2B322F63D40CCE5B88EB58C1F1B
-:10C1C00005E81FC83F5CA9E54FF3376AF3F3C8944D
-:10C1D0005489F29779CFCAB447CADFD4FC8FC2EF33
-:10C1E0006581C9DDF9A4ACC245E7BFD948F789CE5E
-:10C1F0007FB68B485DE8FA16BFB179D82C9A7F5B81
-:10C200006072ECD20A3AFD5B683F1DD8FA8B970743
-:10C210008DDEFEADD777A666F0F49104FB63F2B134
-:10C220005891BFC42D0D436E4995DCF8EBEF5223B6
-:10C230007A2D0EA847BFABF8F39CB5DAF5B5B57EFD
-:10C24000FD7A097906F1AD78C7640278A6AC47D9C2
-:10C250002F653DF20EC11B8C4107618EAF0A5F6BEB
-:10C26000E2F053F48ECF75F92F75F9AF757905BFEC
-:10C27000654EDF14EF3F1786023D378D6178123629
-:10C28000B2F30CAB678CD6FBF266F54C9C5E68BDD6
-:10C29000AF6F56CF12ED4F32A4B4AEB7F88D575EE4
-:10C2A0000F50FC2EFECD730E42F1F1A25499EAA17B
-:10C2B000DF176D5BE300385D90020EC09B8B41B1D0
-:10C2C0002016BC46180445DFB00974DF4B14FC1F70
-:10C2D000553E11E4FBF56DB2EB69BA2FA53B4C213D
-:10C2E00013DDEF929A05856420E64FB1FC93570168
-:10C2F0003F4A6BE5D3EA7D2DDEFE5CAADB8EFBD0E8
-:10C30000C5003A30097521342DA9FA640CE8D1A58D
-:10C31000A409F159DF0EC687A31DE5D7B38CCED68D
-:10C32000E5CAB9B1947D22A5353FBA0AE7C65222C3
-:10C330009D56E35111E032D5F3FA19ECC9705E2035
-:10C34000C3C970E02B0A1C483005F9F2AA977F3A5E
-:10C35000F0149D4743D51F1C820A3E544342B83413
-:10C3600057CFF95BD24DE4C2158A9FE41675BB2006
-:10C37000B673D7D20974A4D93A962E92438E9114EB
-:10C380009E8BB6C81E8A9964D12BBF7CE9054A777B
-:10C39000E46393A73785F7C2578E9CB883E617EE00
-:10C3A00092930BD9326C426A743F4AE95FB0CB2852
-:10C3B000F02F7EF588D13D807D7FA243741F16EE5D
-:10C3C0003A6024035AC32DB7FA80316C8BB11FD564
-:10C3D000A7C6803EB3EAE5BF1B61BF2FEE1748C773
-:10C3E0008CD6ED8BB61C41FD05E084FBC7F7A76535
-:10C3F000BF5AED5368E2DE2158CF05FC3ADE3ED944
-:10C4000041560F453CFEF55E3A7ED19F4C1E587F4B
-:10C41000D1AF973A601DE7A53286CF9BD7A47AE9C2
-:10C42000B8457220D58529FB5EF4E2A38867F38FB7
-:10C430003F8A7A19C58F4E069419814EB0BE873750
-:10C44000DD83EB9B47FC886F459B455F10F880447C
-:10C450000A76C5A087DF707A38BF95724ABABEF3F4
-:10C46000C01F41CF7D4FE4FCF111D4231FE56BA524
-:10C470009A0CE63F37B37DAA301814BB9C5983A7AA
-:10C48000554F221FBDD4CDDBD1D51FE1A0F04DE427
-:10C49000A7E2F1FC8E6C7F18FFC57614EF72E13BCA
-:10C4A000D4AF97BD96819A769C5FB2F197F1F1E98E
-:10C4B000BCADA07F9C4F657242BFBE3F1914FE48C1
-:10C4C000E5AB0ABF5474CDE8BCEA2946D70A9D07FC
-:10C4D000271740F9671F30FA8176207FE8BC421D9C
-:10C4E000B1FCC03401F980898462D17395CCE959DB
-:10C4F0005B4E3934EA6F74DE92E054E309EDBF031A
-:10C50000C21FF59279CFD2762A7DBA14C6C37AC6F5
-:10C51000E8F78C28DDCEE7F4FF2BA0FF8428FD93FD
-:10C520004D29ED3A9F2D92832FBD00F44AE933E067
-:10C53000067A957DB0EE4F771E3A713FC5EB4FAB53
-:10C54000153AD5F24D3D9D16ED7E94007EEAE9F454
-:10C55000D3AE6524269DD2EF31E9B46BF87F856FA9
-:10C560002A703BAE831BE583BFD8EB8E0F3F3D1F88
-:10C570002C35B863F241FAF30119D61AEF147C5343
-:10C58000F0ACF8BF1677077ED3828F0ABEB5E0A362
-:10C59000826FFA756AE1A62FDF04FC46A51FC82B3F
-:10C5A00049C04EF7B9699F88E7C4467793A3031D36
-:10C5B000778D853C047A76A38BE71359BE29C5583D
-:10C5C000017C41F9DE642133003F1B7D4D8E449593
-:10C5D000FE7CAA4E74B8697938480A62E9D594E3BA
-:10C5E000E2F86112AFBC1CE1972FDAD2970F81738A
-:10C5F00095E801DD6D6EF9BD0E305934D6F59C34E9
-:10C60000837E7FF86D116D1A8D56C74098173DB720
-:10C610004B9D287CE7F07DBE4002CF8FA2EB9A5362
-:10C62000C7F4E2B9EBB4F098675B66043E43F5CF1C
-:10C63000281EA8F045F113146DD296179375B85FB4
-:10C64000C53AFCF1F3F34E2791E3CF2032889F37B0
-:10C650000CD0DF12CEA7F2C5FE936650B8371E1578
-:10C660008989E69BEB445201EBDC290409D0712057
-:10C6700005F1B084F207A23A1736009E19E3D36F92
-:10C68000C36B7F1DF638ADB2E8F53F0FFC394D1B8B
-:10C690005EFFF8963721FFC647E97F26ADEBE7EE50
-:10C6A000FFE241E0EF8DFB4D04ED24FB7F97FE3868
-:10C6B000E4F79A3C68E75869F2A27EBCDF1EEC0DF5
-:10C6C000E5DD987D69D5BEBF0F0CA3BC598DFB94E9
-:10C6D00027B2734473DD3FFE5B488694AE0AE4E8FC
-:10C6E000FE04D4AF4BF75A8270E86CDCF7F7617E3A
-:10C6F000DB77B79E1223F123FED9C98CDD80AF8989
-:10C70000CC9E56FAE6885F96D3F117D71C30CEA19F
-:10C71000E5B9BFFD6A20F095C6DD4C3FB822875FC2
-:10C72000241E422689CF95CB74BFAE80AED699F237
-:10C7300025F14476C0160B2E0C0E8D140EB02E0A69
-:10C740009722E087F1E031EFDF161E571F84F117C3
-:10C75000D50D2762861A2E82977DB707CD02AE9F30
-:10C760007DDFFFF781C0773FAD2E47F9DDD6BAD721
-:10C77000C0BA53FE5F5AB7106ACFBAABFE6DD7CDC1
-:10C78000F0BF9FC8E4919E0E5AE3F91BDFC7FCAFD0
-:10C79000ED1E9C6F3BE9FFF0BFEDFABFE5BEEF1663
-:10C7A000D01FD7D6BE9FF9B75D775BFBFE36DF772C
-:10C7B000BB0BECBD8DFBBE4A27AAF5B7B56E83F463
-:10C7C000EFCADF6EBE6E45EFA93794B986D0F97D0A
-:10C7D0004C2AEFC9A0E91FBDD792E1384A69C017BA
-:10C7E000EBDC9029B1738309EC4C50F11E41B11779
-:10C7F000D56BFCB85D8B50CF98E8FD31EA07442A31
-:10C80000ABCFA6F5EB73E6789EC61A9927FD909FED
-:10C810007627CF6BCF531373C61F05BDEEDD723A7B
-:10C820003F885BE826B9A8A644267945D403698ADF
-:10C83000FADF87E963B0DEA42CED79E23EDD79E032
-:10C84000DE19DAF27B78FFD3C9332960779B3E97F4
-:10C85000D9DDEE25656B5CAA7DBA47D78F4322DC14
-:10C860004EF2EDE037B7057E4B101E245BF46C23CF
-:10C87000ED801F61F0AE9F3628087618227918FCEB
-:10C88000A62FF6A01D949F3365DE5EB6ADAD07BA48
-:10C890009589F67CA99C13DB8233E1E74FECAF4727
-:10C8A00014EEB257C4F3A7AA5F848BB21FDF741FC4
-:10C8B00094FDFBB6FB310CF62386FF6C81D97C0F0F
-:10C8C000F82FCC7D043CB74F5A27621C8CB9BF802F
-:10C8D00070F465C9E8DFF9C4E01B068A73E1E0E1A2
-:10C8E000258FB16E3D009F051C8EF34819EA9DE42B
-:10C8F000C6D75F8F02BF114286967B099940CF2130
-:10C90000F34609212B5DF77C89049C9960D714C8F4
-:10C9100069B55D33A8CDC3CF5DA9D17EDAAA1F8FDB
-:10C920003F7CD7E9DF283F3ADD8B9E572095707812
-:10C93000497D4E7CA88EC1B1749110EC817814921F
-:10C940007D2ABFCEC71CAFFFF6C460E473D93F1980
-:10C95000E0C4F3ABB71FEAFBA55CDF6F0EB89D60C8
-:10C96000AF69AEEBE9047B4CF3D15C879A2F2AE9DF
-:10C97000717E8E7C7F8519D3C63CA15284F31669E3
-:10C980009A887238CF4280EFE8DBED9114BB4B19E7
-:10C99000F333D21F7118EC23FB994F9B3A3BA8F657
-:10C9A0006DDD848BD2C0D6FB003FA7557E927F15EC
-:10C9B000BE706E05B81EB784C7F862ACF70F1C7E58
-:10C9C0008507BF30829D604A5D860C709992276A08
-:10C9D000E26E0E49FC3C35980C8679151E1CEB184E
-:10C9E00001FB7254F458287C4BEBAE1AFD31FC6D00
-:10C9F0007A7842FF60173E237BE6013CCFFCD842A9
-:10CA000002941EDEE1FE1F5AE405FE45BBF2827D64
-:10CA1000EC0389F915FACACC2E3EB5305B4EA1E382
-:10CA2000F6AF710D0211D399D7EF2BBBB1BC0B6FD1
-:10CA3000A7D4EBBC88D53B657495C45AFF04235B2F
-:10CA4000FF7CE2F97E96F0EFB76FD93FB187724075
-:10CA5000BEE709C8475AE33541FA682E1082207FA5
-:10CA6000E11C8BF94201E5FF3B06561E98C2E4A586
-:10CA700082F77A380B3283B3327E86CCF0D92833F2
-:10CA8000F8287056E0AB9FAF529FF2ABD16AFBCA59
-:10CA9000A4DA41BF06FDA4A44E7081E9AF440A1B8D
-:10CAA000810E4B6BD7CBE02FB8CFCDFA25926FA07C
-:10CAB000DA5FDB5796703E873247A2FE786D1DD352
-:10CAC0008FBD73AF3A400F7AC7E0F9E348A0C7774C
-:10CAD000458C278807C73FAFD8312D4F52F79B8130
-:10CAE000F39CBA285B0673D0F7161D903BAAF0A9F9
-:10CAF000AFDC01CB95EF9D17B933E13B1D0FE7117B
-:10CB0000F84F13D946BBE85F5D9F9340CBBF579664
-:10CB1000C8F0B0A8FA8011F319585F194F19474FA0
-:10CB20004FD30A1334F939B9E1AE009742536899EB
-:10CB300027069E1E96153FC93794135E8AB703FFDA
-:10CB40007F901357C77863C06D83DC4A3E748C2591
-:10CB50001F9694BB3B02FC97ECEBD9118863C9DBB1
-:10CB6000F9A9B1E4C3872B983FF023CACF206D9C6D
-:10CB700046E5C3ED2AF930CD82F8A16FF743B99DA0
-:10CB8000F241D9AFFF653EF321C88718745D296B68
-:10CB9000E5C3F4BA59281FA64F13895B658F7B52F2
-:10CBA000E67EAEB8F2213BF53ECCCB9E841878F3FE
-:10CBB000213F97005C218571404EFC96F37DBDBC02
-:10CBC00088C7CFA71805EEAF6E839FFF5F82B3C201
-:10CBD000CF97D0F30BE881ADF19020BF5E721FE5D7
-:10CBE000E702E023E3E74B1EE076491D7FF5017F76
-:10CBF0001DA2E6AFAC7D899FC983D2DA8C9FCEA4FB
-:10CC0000E5F757CA1E33AD7F7F94DF0E53F3DBDFAA
-:10CC1000727E4BE19CEE8AB1BF33662610B7965FF9
-:10CC2000F5023E7566D0EFFABF0A78FF8E887EC4A3
-:10CC30004FB81C3F36E87743C07E9E6C94107F3E11
-:10CC4000E1FCEBCA8AE0B43C4AC7B973993EBC78B0
-:10CC5000A7887028A9617A5E492F6BD04DF36332A3
-:10CC6000BF407FE0C27DCC1F48015598ADDAC78533
-:10CC7000EF842BBA40F91601FD99F33C0BD18E4F8E
-:10CC800036323BB199FE61711D5EB4232FE6F05A36
-:10CC900050B705EDCD0B825A3BF4E25EE32EC2396C
-:10CCA00040E1BF0B77E8CA3D4FA1BF6231D89B5529
-:10CCB000E70F91EB0F0F8BA1FEAF426CE71FD9B9C5
-:10CCC0004ABFFF4ABD96F517FD8BEB3F4ED73FE4B9
-:10CCD000BB5F7F7BD72D1B39BD679221401F9F18FB
-:10CCE000BC48EF81DFD3F5D371E6AEEFDD511D67B0
-:10CCF00094C4E9F21D83BFA213D42B11B0DEFC4D06
-:10CD0000BB8EA4D2FCCC6A3208CCF4F3376AE5625D
-:10CD10008B1CAE71A39C9D59B64B98DD1FE04DCA8C
-:10CD200000CFE6649AFCE04F3D6E6942FEA5E0DD6F
-:10CD30009D4686CF23F9B8673A37E5E139A25670A8
-:10CD4000215D842CEC5C41E16FA1F94323FE3E861A
-:10CD5000C31BED31A5B56C7F4AE97E005D8DA9E36B
-:10CD6000F91D4C0FFB1E9537E80FAB3B2043BB2250
-:10CD70005A3F09F94D3F8D9F0BFC73D9A9AA7DDB62
-:10CD8000778AE1ED36C14362EC5B1FFA27E6BE7D90
-:10CD900047F8AAC0E34E23D7E7F9FE1DB7D4170E14
-:10CDA000463F94E0D90A95EB12D18F72B6B227EEC6
-:10CDB000E3788EBF7ABC06FDDEADB2274D8689438F
-:10CDC000BC658105E3DC70DC1E4CFF51F313FDB93B
-:10CDD000B994D4A31E3341F0FF5552C5B54DE7F1C8
-:10CDE000278A9F5655EFA7F24DEA91349701F8E450
-:10CDF0005225DE12E28753316E097F0E751BF6D184
-:10CE00004CBADE6B6B450FF87FEE35B84F8C02FAEB
-:10CE10007D5A268097D78EC95EA6772620DF9DF59E
-:10CE2000CE19194C21B3284C60BF67FD90F1D73360
-:10CE3000D019FDF6272AB7BCE0AB27D543217E7871
-:10CE40009AE740BE9BEECB3D438EAF013FDCD45C06
-:10CE5000D7891300DFA74402F03DBD3617CF274B1B
-:10CE60001F1110AF4F523842FB7BA6659C3841C75B
-:10CE70007D606D0AFAD5667A8FE4039ECD9964B71A
-:10CE8000817F6D7C1F91F855707C80D4A39D626674
-:10CE9000D923F7C07C8BA81C003B6B51DDF1FC8EC5
-:10CEA00090DF2478DCB4FFD280DFD8916E61FDC6BC
-:10CEB000AB46B0B7CCA3F5607B4A37B17AA55582B3
-:10CEC000C702F858B71EF9CEBC2A81B8A03ED5F7E4
-:10CED000CCACDFA099F65BBF89B6A7F9F9D01EFAF2
-:10CEE000AD4A9C0E7EB4D263226B9F55FE16F0A510
-:10CEF00079B41D2D26F5558F607F0B3609248DF6EC
-:10CF0000579495F19F59D0DF31D903E51F1DF8994A
-:10CF100011E6FD201DAF13ED7F8E18CE87FAE47168
-:10CF2000C1B50DED4D2C4EB691D301F9A013A32F31
-:10CF300081E7B91EA8C8C3F78D3D109FE62D2FAF1E
-:10CF400080758503291970042AADBD6A04BDEE2CD5
-:10CF500085B39FEA6D67781CDBA1C0196358C5A72C
-:10CF60009A8C3DB1FDDCDA6CA4EF87890FFDDDFE04
-:10CF70007226874FADB10405D03F6417CAC9436B11
-:10CF80006E7D1ED67FE51519FDA357BA85D11E7B90
-:10CF90007E934C02748EAB3689C837CEEF64762010
-:10CFA00071B38CF9F98F1A317F68D3D431C00FCFA8
-:10CFB00053F8031EE66ECE37427E3EE5EBA618FC24
-:10CFC000639EBB98F10B1D7F98BF514BFFADF8C519
-:10CFD000B2318CBFEBF8C1E2AE1568E7D3F38952EA
-:10CFE0006253F84326E4EB439D107F4B8EC904F453
-:10CFF000B912C9F5E046C09B9916F01453BA081D42
-:10D0000001BE762D28B803B4FC7B0FED190AF03B66
-:10D0100007F006BA589784FED479C1590857259E5F
-:10D0200070FE462D3E2BF14BF7F945E255CB81A220
-:10D0300004E255D5FBE887142FE9780FD50A418B18
-:10D0400000F9536F3D3A04F32EC0C392E55C9EAEE7
-:10D05000B323DE7EF483AB6B002F1F7C42C0F993B9
-:10D0600080BF02E44AC946C10D76CCF94FB0F6F351
-:10D07000697BC0978F7EC6F087E2B11BF0BC64D39A
-:10D08000FAB7B07E95E086FE3FDA320BE56F51408D
-:10D0900024585E750AF5632A07300EE850404C05A7
-:10D0A0003C2F596D72C13E2AF8A2E0DF2999F9EDB3
-:10D0B00089D933702A6DB7C5E8C675EBF14E9C91DE
-:10D0C00081F855BA5346FC280D307C3AF58A8878A9
-:10D0D0007868CDBD883F57B60971F02FD7D809F0D1
-:10D0E0002FC8CA5BF0EF6581E31FC3EBF3CB183E9B
-:10D0F000E64239E0DF6B5C3F25C4A6D63B14FC5307
-:10D10000F0A92DBC6B2597E2E01BD58DA7C3BC967B
-:10D11000AEB1E0BC732BF64C5F8E7423A37F3EB799
-:10D12000E207A940A7F3241687A1C071B1C4E27435
-:10D130005ACDE3D97263A7F6CC47378F0351B9981C
-:10D14000097211E24A42749CDFEDFC25C6AF5DFE18
-:10D15000D5298C4B5CF826DD775AFFCA4E3B09A1D6
-:10D160003E1D44FE525C23625C289142C3A6AAEE97
-:10D170008F28F1160B7F6347F816EF36050B69FB16
-:10D18000E2D7CF0C447FF8CAA6B7807E02BF1298C0
-:10D190005D3E101E3815E22A2516F7A197BB234CD9
-:10D1A000CC5ED3B0276106E83FC28E03E84F2AAEBB
-:10D1B000BE5736A9EC931E938CE3D27AEC9E0BDD1E
-:10D1C00077F023C2FC260F50CFAF9CF5F732A39B1C
-:10D1D000E25A19F5A2E21D5BD0AE57BAE32AC6BDEA
-:10D1E000E6FEE61507C0A1B456D4C643ED104326AB
-:10D1F0008CD7124F99187FD2C42595D4B07B1925AE
-:10D20000D53CEE471717B3F037FB5E0F50D02C7CA0
-:10D2100075BB03E8E852FD3607C093F687F14493E7
-:10D22000B2E2C41BB5156754FD54CC38A34BF00FC4
-:10D230008A200F9AB4F1996407E35374D787F9628F
-:10D24000D833157D65E12B9FBF0871AF0DBB3F7DC6
-:10D2500011E6BDE89FD75E84B80DB2DFE202FDA102
-:10D26000F4571F62FCA0D26EB9899F7F5EDE8E717B
-:10D2700097573E36A1FE7765DFF974D00FAEECFA12
-:10D280002215E22997EDCB47FBC3B2D7723B921828
-:10D29000E75B2505BC0CB623EE53BF0F876AC4902D
-:10D2A0008DCEF3F24913D2774BBC58F562167FE767
-:10D2B000E671623B63C7D52AF14D25355327DD0959
-:10D2C000FCAD86C9F19678A7B6E2C33EA0FB797B98
-:10D2D0003BF66D278FFFD3EDDB65F807DD9FE74C4D
-:10D2E000DAF8B0CF6B1EFEC50B505613FB3E9942C9
-:10D2F000C76DC14B89DB9D63F2064D4037BBFF0B09
-:10D30000E3F060BF0ADD20E73F4F07BBE505B90941
-:10D31000ED814DFB4C2E88DB2ADEF711D2C795D765
-:10D320008E635C2CE1F1B35748CB0F8B77E43689E1
-:10D33000D22A3B8B2BE37087B833B703BFF3F832A5
-:10D3400086B74ADC59BC78B30F4D3DF8BD0B1617B4
-:10D35000B7D85D6F04F8ABE3D0842CD8A7539AF804
-:10D360003D65DDFAFE5C0087E1EAB8C978F17C5CD6
-:10D370001F6FD927C687AF6CE171942DF19184742A
-:10D38000CD84781F26EF4A83C24724063D2A719335
-:10D39000F57A7A0CB62F5EB2EDF97E3B781C32310D
-:10D3A000FB930297861BB1F9F1A79CBEE9B9E49201
-:10D3B00049752FE5217E2E51E2C894F9565433B9B0
-:10D3C000DBB083E9857A7A2EE1F676FD385FF0717D
-:10D3D0004A6A0F0C04BED370700FC73786CF253B47
-:10D3E0004F19039C3F07D5FC19FA8BC14F4433EB0F
-:10D3F0008F9E6363F657BAF36ACCFE2E49DE7B61DB
-:10D40000FE97EA999E71A95A2C08C6E8FF32973F09
-:10D410002DEBB61BF15C253AACC87F96D9B34E3ADA
-:10D4200093213562FCC2AA721EEFF0434F1AC079F5
-:10D43000957D1C81F9AC01F8A8CE99B2CB4F40CFB5
-:10D4400091D37C43E0FCA4CC572937261B4850BD20
-:10D45000FF5200EF474EECF17709E44BFD0AEDBDBA
-:10D460008E7AC9752489F6579F2778409F6D8D67FE
-:10D47000DAFE277B458D3D0C6CCFB0AE668F01F791
-:10D48000D36E08B9681562B7D4A7E141CE4DDC521E
-:10D490002A8674A35FFBE9153BBAC13D2B07F1084F
-:10D4A000506EF7B4DC6FC1FE9C4417671D201FC08F
-:10D4B0007D481B67264EE23A0076096B1FD207FCB7
-:10D4C000D62E62F5C0FB0A1BF8BDC775763FCADBD6
-:10D4D000B874E361F75E143B91334BD2DC8B49F4B3
-:10D4E0006AF349BA7B900ABFC62B7414FE63F8BB7B
-:10D4F0000F89F96CFD60AFEAAD9A6F620AF184A002
-:10D500007C820DE3996D36363F65BE743EC80F28A8
-:10D5100098D87CFA8703A087D379E9E898E0BD27FB
-:10D520003ABFD3BAF969F4B8FBCC5C3E4844023E3A
-:10D530006233D7130EE7666D9C698040BC81B305EA
-:10D54000AEB49CF693214C3241DC820B4EC13D714E
-:10D550003C5DBBAE2EF57DB15AF8C708F4171D36F9
-:10D56000829FDF2CC0F19974045C032048F54600CB
-:10D57000C64F6D4A3E84FAA2AFE6389E3F17571F4A
-:10D58000C77203E4699A94E0CEEB328890A7D6E69E
-:10D59000E5A5F5857AB3D20C1ECC1F96808E26FBAE
-:10D5A000D30C8360FA79AB0F8F22643B29EB07160B
-:10D5B00025F36AEFE1A3DD00AF083AED48C07B1820
-:10D5C0007073BB92A70C10DE57D86E6DC97BCD94DB
-:10D5D0002F6EEFD1920F40BE0A807F078CE73DBCD3
-:10D5E0001AE27CCCBED5663AEEE4CD06A4BBD111DE
-:10D5F0001B9E3F48B803F26742CAACBE18F7A55B52
-:10D60000EC3CBC5E5B7C7C3B8F479EECF77BE0AAEE
-:10D61000F7702E8F892B3C18EE63379A673F6F5651
-:10D62000D3E1E666B1079DDFF3B0F7B4BDB3C03513
-:10D63000AE0F9D9F739381C5CF9AFD3F87FABD9F23
-:10D64000F01BA0CA68125E2A001FFE4B32CE47199B
-:10D65000A7621F3B5755AC31045722FEBA05906FA5
-:10D66000D1FD0BEBF6AF89ED5FED29DCBF92BA532C
-:10D670006CFF6AB71C30727B3C9C5BB613CF2E30BC
-:10D680003DED5A3B234FA2FB92646AAA807D95C967
-:10D69000F4BCC2BE08D7DFC4842B9F5F5B70DD7E05
-:10D6A00061EB8F06825EDF60F0F426517829F54E3B
-:10D6B00098599CD864ABBF0EC6297D365C01E7DF64
-:10D6C000BD17DE433F70EF86E6D0403ADFDEA3B8F9
-:10D6D00039858FBBBD612BFA33B7031EBBC175EF14
-:10D6E0005F0972323E3C187EB7C0A3E614C2C70081
-:10D6F00079FA7D37BF4791532B78414E2499A81C66
-:10D70000A5E91FCDEC1C73C62CF294D9199D0D3DD3
-:10D7100024D08B73A619F03CE5E46974FD3CFECF80
-:10D720002C69E48BB29F0A1E11529900E79C02A754
-:10D73000FF2F5ABC7926A1072D1F7DF6F452B0EBBE
-:10D7400029EDB6AD209EB9AAFBD0147FF668DAE5C4
-:10D750003F6A057BA8521FF032D63981B6BB04ED73
-:10D76000601C58C79EB3CD22C0BBBDFBAAFF5EBFE5
-:10D77000828ED72B3EFDF8B2D9BD22FDF77F9A15D8
-:10D78000BF23D347BCD17B7FFF047C586C0E3BA6E4
-:10D79000D1FD2DC9BE660438AC4CB8323296DF33A9
-:10D7A000DE3CEA6FDC6A03397D30628A798FA0AF94
-:10D7B00085E917EFAE98E1013FFC532DF704983C43
-:10D7C000CBE37C37AF577121635AAAB83130587018
-:10D7D000B9990F5FE8FC0AB27649203FF3894A5EA7
-:10D7E000323BC504D0479ECA1109C6A9B9648D7CD5
-:10D7F0001B0FF67207BC0B52761886BF3B4D7B0F92
-:10D8000074D2A85312BC5730368B8A6301DEA7D17D
-:10D81000968FD7DD139DEC9DE5C9E3E5D7F0FF4179
-:10D820005CE7A4ACFB3C796A392155F6817D3EFE6C
-:10D830009518536F7CB4053E3E84EB1B160A9FDBA4
-:10D84000619DB3563399747378E8E1A8874BDE5F26
-:10D85000E6317BA10E1E77DFA83C9C14030EADD7EA
-:10D860005DD907E4A6023F3D1CEAA12EEA4DA620A1
-:10D87000E881F55218E1584FE118E07EAB7CF53EA7
-:10D880002BF3E1FAC378FE5D0F4F3D1CA97E81FAB0
-:10D89000C3D80176B4831D0378611C40E50726FADE
-:10D8A000FDED5E32791A785F6834C619DE45105690
-:10D8B000E40DA12C0FFD322EE65FA1F29CE1C35FC7
-:10D8C00098FDAA30C2E63FC6CDE265283C4EEBE0AB
-:10D8D000715A87079A738B7E9E6FC03F46C4C00FF4
-:10D8E0008E078B2CFC7C934EDC70FF7FD8C7439C4B
-:10D8F0008C2FC4968FA323BE967E98DEC1DEE710E0
-:10D9000088BFE5BB8BF613F2CA18FF996B76217DB1
-:10D91000E4126F12BC07014186304F655E8305DF5C
-:10D920000F2D29F07ED3D824F5FB10CAF8CABEE427
-:10D9300072F8E592C0013887E612E933F5BA95FE30
-:10D940002A2C5CCFEA4EBAA39F1C8CA143A3FD29CD
-:10D95000EB4B4A22217C3F4430E33D27FA5FC0D89D
-:10D96000213A9E123F9A689F526941BF4E196171D8
-:10D970001221DCCF1C5E9EC3DF6922E6B8EFF29075
-:10D98000AF13A2F37BD12248F86E029FDFE5A3E636
-:10D9900000C46B3C26F8B7021C1A846303015E5472
-:10D9A0001FBB05EFE9EBCAAF9D3C5C02E5B4DE3C72
-:10D9B000ACC7D7B5506476327AFEC7F7505AF371C8
-:10D9C000664FA3E426C1FC15FCCFB132FA1E4FDC32
-:10D9D0005DF1BD34E297203D6C61F7D0EE3EF90C6D
-:10D9E000EEDF1FAC771F057A2B204109DFF9716943
-:10D9F000F1B04D3CEDA33FFFF2775DA4A67480EB40
-:10DA000041CBADBD408E29FAC27B16DF6F61BD07E9
-:10DA10002D8C3F9FF60E7D17E4C2ECECC12786D01B
-:10DA2000D460F6E1BB0B0F035E517866015ED1B6A0
-:10DA300007A1EB4E88574761DFE6ACD5E19599D950
-:10DA4000D36653B605EBC8592B7FA99E570BBCB8BC
-:10DA50005C6C4B3F2487A9429F0AEF2D30FC3C6849
-:10DA60003105406FCB798AC547CC21FE172B057C49
-:10DA70000740A3AFCFB530BBF7DC9F5990CE69E329
-:10DA80004D65E0E7B2F0F71CFAB077775AC6AB54B1
-:10DA9000B5877D37A7221ECEE5FEC3B3023BB7CCC8
-:10DAA000B5E4B37BBF1BE566353EEAC78FDBAFAE9F
-:10DAB000DD4181D9490ECA6E8C0753DA5DB1303928
-:10DAC000DE6CEEBDC97093FBE0F3CC1DFA4B49D17F
-:10DAD000FC398B65462CBD40E9AFE55CDE729E30BB
-:10DAE000AE39DC357A9E3094CB47B4E709F9C8BF2C
-:10DAF000729EB03F2D1F594DDBBF6DF3A55A617C5F
-:10DB0000C9D717E0FE1CD70FA926D3576D974EB57E
-:10DB100032FD3075790E393338FA3E9B20D199E0C9
-:10DB2000FB1AFE729037D20C82FC9FF2998762C575
-:10DB30000525DA733A5B8746E9EF2983BBAA92C5CC
-:10DB40002BA0BFD7B77C36EA7353971761DA78FA00
-:10DB5000C62D4087391C9EB75A995E5A9AC0E84331
-:10DB600010FCB7427FF55ED10EFED485B522F7D703
-:10DB7000B177ADA64E1053E0FB19B38CE7C08376A6
-:10DB8000B6AF67087B9F26E7B8C95743D31B247BF2
-:10DB90009C55A5EFDD2079982769A9E8BF56EE2BA3
-:10DBA0009E21196CBE6B997FA0796D06C6311F94BA
-:10DBB000B5F6A85156A60F8FB2B2FD9DCDDFB103C9
-:10DBC0007C82F724664B6EB40FCE8E18D93B6A74F4
-:10DBD0001E886F166D3FF956163F91CFE13F1BE44B
-:10DBE000E460A8A7EF4762FD73BCD5C3FD4D4BEEC3
-:10DBF0005880D30DE21D6745BEEE96003E39430EB8
-:10DC00009F04FED6363F0F08C0CF4B6F08A1EE60D1
-:10DC10002FAB91F17CD6C0F5FBCB35875267D3741F
-:10DC2000F1AEF71D700EFC9E95E95397A57A7C77AF
-:10DC300062D16B22DE9BA6689AFA3D6C3F6718BBE7
-:10DC4000F7C1EE2D2872EE8EAF7A76F5613D76FF44
-:10DC500040D1AF72CD8120CCEF60B98876292A07F8
-:10DC600035EF90E4D7B07B097ABDEB11ABCCE3354F
-:10DC7000D93E2E73B171E2D16D4EC44A822ABACD1B
-:10DC800091DC12CC3F27E220410AF7CB17B66E9801
-:10DC900048F13C9026E3398F1E7F0EA3DEA7F8C122
-:10DCA00003344FC739CCD773A466EA34785FE52DC7
-:10DCB00052B67A00AD9317F6273322A6A7B4615166
-:10DCC000BD2BDFA5D5F7F4FA6041DDFAD5F0164B90
-:10DCD000037C80F1CD268C236EA5279AEF8EA91F99
-:10DCE00012B21EF1F08ED77E391EDE9FB8E3A2C1BC
-:10DCF00005F39B6C7533FB62CD357C1FA18484A634
-:10DD00004379498DE80AD1564748CD6D201715391A
-:10DD1000AEC02574E390D903FCDE22BA56C23ACDD8
-:10DD2000F7D820CE626463FF64906707CD32DA21B2
-:10DD3000732CBD6D7354F87C3099BD1B7024B9A74A
-:10DD4000F6BB79C36D20D7F6F0B8B5C3E7EEB7855B
-:10DD5000B1DED464D4CB1439AED357157BD7D8DE1B
-:10DD6000628BBD4BADE71271D3B3165A3EFE561906
-:10DD7000EFBDE58599DFB4951CBFE15FCDCF239A58
-:10DD8000EF055C3F6825D7A370D6E8A16F58B95E50
-:10DD9000E9260340AF0CDDD8B010EFCBD625B8563E
-:10DDA000A23D81E92D8D678B374C80EFC744661FFC
-:10DDB000B921221D1DDCBFB07B5845BF5422E0BEF7
-:10DDC0005D1F74F5CA9B745FAE7F62F504E0B354C7
-:10DDD0007D5B6CBF5890C329D499D9D9039DD93B99
-:10DDE00018ECDC7957F4DCF90EF001784706C443EF
-:10DDF000DAA65346381F5FA6AA38E2175D34E0D78B
-:10DE00005DDEB0A8BE7F738AF3DFC956EFFBC01F8B
-:10DE10000324A70B55424891D59B0D71E04D938982
-:10DE20006B2B5DCFBE0B39824CF3A3B66578049A99
-:10DE3000DF0D8A25F0CDD7C420C493EC867B6BB46C
-:10DE4000DF05F595C60C3A6EA04644BBFE026E1F78
-:10DE5000BF2007D21355F85199C0F8C905D9FF0B57
-:10DE6000E8E7C2C726B4775FF8C41A53AECE48605D
-:10DE70007CF74D2ECF3213DC980F35EC7DAB339D04
-:10DE80005728E21A04702FDE7155847793EEE4FA76
-:10DE900057E1B3F5ABC12E33715393047CC71774AC
-:10DEA000E583489DB2C323831C9AB6D327839A3D4A
-:10DEB000BDA60CE39066D4561E81FCFDA16ACCF78A
-:10DEC0004FF047002E77AD6D3A04E8D2AB9248F898
-:10DED0008ECF674CAF4AE5F3E811F11C7422366728
-:10DEE0001B00BF5BC67FA25E02D57DE26A363EEDB7
-:10DEF000CF9040D77D5759532EC8B5F4E5ACBF74C9
-:10DF000072A0DCE98EF63BFA46BDA0B617BCF898C5
-:10DF1000AD88F15B06F7F4C73B6FC173197159F116
-:10DF20005D454E4F398FDBD00F70FD07CC0F707DF4
-:10DF300010D3A7AFFFC0160CC4D0A7A378163231F8
-:10DF4000FC52F08D9859DE6B067CFBFEF36556A003
-:10DF50009B649FDBA88E3FCCD950D8EF6DE8DF6281
-:10DF600042BB5CCB78EBD97810880B78ADC8B1D9BF
-:10DF70003AFF4B940F30BAA05D04615C2525C24A7C
-:10DF80001751E749280DE6939EC0F85C95D13D13E3
-:10DF9000C6ABB29A5C30DE6C736F23F0AD16FB2615
-:10DFA0008F4F1BC9F5CB7D170E26C1BE5F1F549E38
-:10DFB0000E7A73C8F073E4536DE1DD4FACDEE10916
-:10DFC00038CF00EAF94AFD3DE7ACFD414EBE69603D
-:10DFD000714FC433AB3BAC5769378DA7BBB99F4E6C
-:10DFE000A193E47AE2DDD21F41E5DDAD82C7A4044E
-:10DFF000468F4ABA5B7607189DB1B8CEDDF690B968
-:10E0000027D0F39E9E984FF6119B07E2586A7B7BC0
-:10E01000C05F43F9C0A404955DEA4ECE1F92EB9B0E
-:10E02000902EDB7B1E18C6E11B92AA397D11E453AA
-:10E03000405F8C7F87BAF0F778D0FF077C83EF4F83
-:10E0400027210DE3C1719F95752773BEB08CD33D19
-:10E05000C001CA4B795E295FCCE1952FF677AAE320
-:10E06000C75AC9F5E56904F4C7FCE59D312DE5F310
-:10E070005D605E8FF6D205C9EBD14E9AECADC474EB
-:10E08000415E257E4FDB340BF163C1C6D8EF8C1D9A
-:10E09000E57AD9E50B06F69E94C1DA19F04F297F8F
-:10E0A000C72A737EE97F1CF0E162CD86E707BAA339
-:10E0B00076DFEB96CA89F703FE6F135DE5B03F5537
-:10E0C000F9823B065EA9E107F02AADFA1CFDA62500
-:10E0D00024CCFCA6DC2FAAF84F83558C9F5EE4FA73
-:10E0E000599155AB57562618383FAD1F7F3B1D3F02
-:10E0F000D4DC2B13FC4121292C4A6CFFD06E047C0C
-:10E10000D885F8FE74FA638047821DF51EE0ABBB2C
-:10E1100054F8B170E7968ACEF49F77DD60F77742C6
-:10E1200012B1A9F9B782270A3FD6AF6F2BC75F0597
-:10E130000F4746E5D4D6046E1FED49FB2D59DF8C01
-:10E14000F6D137147A067C037A5EABE0DB20037BE2
-:10E15000374D4BC7C3BF23FEBEE79917D2D1FE9000
-:10E1600045E916DE5903BA8E8117BF6DE103FEBD86
-:10E170000931E4C145C1FF8BA49ED1F67BCE8DEB66
-:10E18000375BD5CFCF389E5F97FDDD5D31E01585DC
-:10E190002BE90CF850447706E04036092E75DC7BFD
-:10E1A000F22666E7AFE7F055BED7EBE03D3AFABEA0
-:10E1B0005C3D8377931144765A90E905C430AE33C1
-:10E1C000C8F90556EF38B4B7AC37107C4F55C84185
-:10E1D0007C4FAE7AEEDC574320B5F440BF09711B8B
-:10E1E000008F163CE5C6F3E0CA972C8897E71258D3
-:10E1F0009CC4CA2A99E1A75C89F875F193E2EEE024
-:10E20000770950B9DE3B86DCF9AD4E9EBFCAE5A862
-:10E2100082773DD631BCAB92BCD644155E6E27DE0C
-:10E220004CE6EF6772251E3E46F1C83548C1A3593A
-:10E23000F47B8FB56111F68BEEE335A0DF9EEB9A90
-:10E24000909FC5DB47C5BFA6ECA7C2E787DBB4F745
-:10E25000FA641B5B4F729C7880A89CD3F26578FFB0
-:10E26000CF36544B0F70E552594F23874B3CBA9829
-:10E270006363EF3E57FC75C38340CF15EBAD9E95AE
-:10E2800024EAA751FCA7CA3C3ADA048D3F47EF675E
-:10E290006934FB536D2ABC023FA01BF93DF3AB2848
-:10E2A000BF8760C93616E7B4078A808F9CB506D54C
-:10E2B000F7776F958857CAA470B565E0BA6F0516F1
-:10E2C00042F3C9CB8DA4173D775D1F71E0B083D6B3
-:10E2D0009FD0142EBC9D2E718F313C6D12D87D893C
-:10E2E000B718F40CB4D103FE37B07E89AB5A33CFE4
-:10E2F000811CDECAFE54FC754E5A2C3F8002C77842
-:10E30000FB3287C3C3C9CBF5F46FE1E59FB69B7EB3
-:10E31000034EA0DFBB48A01CE22FE8011DE3D65A44
-:10E32000E8971ED8A1FF029B967E957C0CFA2DB033
-:10E33000A9E9371266F4CBE9D459257B63E92DD3DB
-:10E340006DEC9CECACCACF0679E4F461D839D00D01
-:10E35000D2FB024AEF40C701A0DB8E004F86673D2B
-:10E36000BC9518EFD8A38AE9E3D713D97A17DCE96B
-:10E370003D00EF252FA0E7018156ADE4F41E1FEE0E
-:10E3800021A7C0E49B13F8CC5DA3C2B92087DD6050
-:10E39000EFE888BFFA023765F428120CD17D77DFE9
-:10E3A000208C7F7CF2C2838F01DF586FC37B4F8A42
-:10E3B0005C4A4DF017DB86C6A76B8A975EB0572D77
-:10E3C000F9C2C6CE8D71FCE2A3971B48AF24C4F3FB
-:10E3D000A56A3C1FED6B1201AE4909FE34399190DC
-:10E3E000D5B69C31E66E747D1954EFA5F9729A5F2B
-:10E3F00007F6B70E61C2F315B64EDFDE5EB77A9D43
-:10E40000F72DB0D7BD94E05D09EB82380048EFEA04
-:10E41000D224227F6BA75FBF14EC77743DA7EFE98E
-:10E42000F7D22CFA75F67DBE0A2855ECC9C3B93D62
-:10E43000B9B46E10DA995576E50DB0FE7876E5B68A
-:10E44000C67570BAA7F88DE73F47569308FC51E1AF
-:10E450002B5B6C1D383E8709BCD7AED017F025D09A
-:10E460007795F802B03BDAD15F11447C85BC333339
-:10E47000CA6FD6551A62C63F55DB6C1A7A51F82915
-:10E48000A9FBC7EB8F29EF2C32FE5AADE6AF5595AD
-:10E49000A75399FECADE2D5BCA6D001B567AFED8C3
-:10E4A0002B397AEF7984C91880F716E981CEED52BD
-:10E4B000C54F0A7542C80E71795FD222C0A32F0DD5
-:10E4C000986EF80F5F4106D8594E1A90FF96F07B70
-:10E4D0004D59DD09BEC353CBEDA3D9676C5EF0FF88
-:10E4E000370A66E49F8DA7AC0190AB8D7603DACF37
-:10E4F0000FEF33215D5CEB65E5F68FA0C64EA2F809
-:10E5000073AE1D9B9304FCFF79EED77CFEBE5BD0FF
-:10E510006EA9D8732589C2BC0384E9B07B9939CB35
-:10E520003BA3BD55B1EFA69A67092C8888F52F99B2
-:10E53000D9BA5225BF00F6F12D6DC43F9CB1191513
-:10E540003DF82F00DFD227C24638E72A7AB022AF43
-:10E55000BB37F438007110DD0B98396D4B83C10067
-:10E56000EBDB42D12831A3355EB5E04FEB38838B2E
-:10E570001AB9B486C519B4E479BB5FF03883D167A2
-:10E580004FBF8AEFE999FD1F6BDAE5A75863BDD34A
-:10E590003D7DF963D83E1EDE4F37B0F779F4DF13C7
-:10E5A000EC9C6F4B655DF07ED4DFBE9FE08E61C753
-:10E5B00099FED7D9F87B24F476B7E8F8FFE1C9A330
-:10E5C000FB26DBB9DF2F9DA4835FAD2D3FA67EDE4A
-:10E5D00027647FB758F2491F67A78CD7BA3D3B978E
-:10E5E000B5D43312FF2E1BEB3753D5EF283BD37F27
-:10E5F000A60B04E3DFC95704E5B4822714EEDDED72
-:10E60000B47CD83B67065BD1CFD324021FB876B267
-:10E610005757F4AFC739872AF321C4DF3B561CC7CD
-:10E6200074788727C6FA46D8997C9E2E333F85702A
-:10E630005F6FB40B4CB7980475DC7E6F65BF74FEDA
-:10E64000D88396E178BF11ECF9B1E0A7F7D3F606CD
-:10E650001FEA5006174F0C7C52FC820A9C2BB2BD5D
-:10E66000D912B3A7E13DB5642FE39FC90504FD6B43
-:10E67000C3052FC263BC3D03E7B785C7C75D3BC673
-:10E68000E2598765BBF1F73C51393116E03A9A847B
-:10E690005F35A8E2AD143CA97885CA638DBD31A071
-:10E6A000394F27723EEC82F72654F5DC4F000F8875
-:10E6B000CA81AEABCD9A7CFA321791547222D19BAB
-:10E6C000A6C977F5B9AC708EEA5AE0D6B453F04ECD
-:10E6D00089F7C39F6458B70BDF3DEAC0E7335CF0AE
-:10E6E00023DE005F033BF202BE9F74BDF371BD05E4
-:10E6F000E16B6ABC51D6DBD6BA4EAF70232F3CBB60
-:10E7000082CE97F28539EB32CAD310EE2E02E78B18
-:10E71000732BCCF8FD61DE3EF1D959788F3671B597
-:10E720001BEDB889DEB2B7E09E4F62991BEF15CCA6
-:10E73000AD1404B0F7503E83ED36AF7061AAECB76C
-:10E740008B960BB6E83BE3F1E4D75A7BBBE5D75A8F
-:10E750007B0CF965307BDE06BFFFE23AD10D78B164
-:10E76000AAB003DAFD3654B3FB6E87EA58DCDD86C7
-:10E77000E94C8E28E35E79CD89F2E28AF2FB54BC43
-:10E780005FA64EC178802F5381CF6EB3F99FB7AB90
-:10E79000F8E586BAA116FEFEB246FED01F17DC7F52
-:10E7A00040DF9C007AD2A0B5524FA4FB1761BE6433
-:10E7B0005E78B0A527E0A9FF7D78A7F4DAC9CFD2AB
-:10E7C00061FF143F9FE20754C651FC8482E0DF6E74
-:10E7D00057F1A9D67E40ADFF4A7498314E374B644D
-:10E7E00071BA2A394B601F57813E48F16CD5292BED
-:10E7F000C263D5578CDEE83C5F85710EDB8721FE56
-:10E8000028F294CE73E0BB243ACF524353BAFA9D18
-:10E8100052D53CEB6E3E4F5D1C2B9F97689770BEA8
-:10E820008DC4EA8179D51A3D27FD2067AF58D19E66
-:10E83000D7E8BDC302EFCD36923B2CF00E6DB5CDBF
-:10E840007F14F643ECD6E4003DFB50DDE0BE30DF44
-:10E8500078FED8265BCE31A84FD7F7474847BBC2D2
-:10E86000D77EED8EAEEF267EDCF7A1FE3758FF5F38
-:10E87000BEC9FA4BE1F767300339EA5302E7BB7AC6
-:10E88000BC12EA0E7C01F143947E306E33904E82CE
-:10E89000AB289C2A0630FC227309FFFD395A3CD86C
-:10E8A00066F335C07C14BABB097C9A609D1B6DBEB3
-:10E8B0006648611E700F84F299CFB8BC7AD568881B
-:10E8C000EA5149498C5F3525128CAFD1FBC913ED54
-:10E8D00053FE01ED52FBF80557FF6F84E792E3A664
-:10E8E000F00B615C84720F7531F87321BEAB466E1C
-:10E8F000D0FE9E1D2D1CAA6D3E8703FC3839EC3DD1
-:10E9000039C02B78FFED26F0E8E04078F85320B5C9
-:10E91000CB145F002859B3D200CE8D666F2AF895CC
-:10E920007697333834BEC3E0B0E7AC01F1F839D2A2
-:10E930000FE92ED3D0FC20F44FF9477758D7A8A67B
-:10E940006A01CEBF1D8BDC06E0B35D9A3CA2E1E616
-:10E9500078DBD381FCDE7F8B83EDC352D887C1C7C0
-:10E96000987DE62678DBCF91F28DE03ED891D27E7D
-:10E97000FE42F16AB8438557ED8D9B12F8FD497D43
-:10E980007FF43C84FE83037B4CC88F4A76B3FBA2A2
-:10E9900025FBCFE3B9BB64AF0991326FAF85DD7B57
-:10E9A000A861E557B263C70178E1978F817CA87EA3
-:10E9B000C4A395BB0166AFF436BB7A8951BF6AD256
-:10E9C00004768F60158F4752FCAB0E8E6749DD7C55
-:10E9D0005E902B49F904EF13386C2CAEB0F57D0135
-:10E9E00046B729BC9DCBE51600DEFAFB0329F09E55
-:10E9F00034F38F23BE8806AB07E47E5281AE9EAD12
-:10EA000000FDAF29BAFB06F31DDCFF6A2469C0478D
-:10EA1000AA2DB1EF097DE650F43A2B9EEB243EAFD0
-:10EA2000C376237BE7C56EC6752F49244985989721
-:10EA3000509EEBFB69C12BAF41730F25A9C0AA798A
-:10EA40006721C5D74193EF38A3B3A67E277F0F4D2B
-:10EA50007997A27E9AF26E65999A7CF7E57768EAD3
-:10EA600067508453E77BAE1DA7A9DFBB728A267F60
-:10EA7000EBC6FB35F5FB06676BCA6FDB51AC291F94
-:10EA800050BD4493BFBDF6314D7D318E9EBD87C3D1
-:10EA90005954F46CFB103FDE3BB29B0593EA3CF704
-:10EAA0002CAF97ED284803FFF76AFB9834386F1EA8
-:10EAB0004E1CE60CC7E85749BFED396CB743D0D8B8
-:10EAC0005773B8FDECCA41CA45E0F7591CA27880DB
-:10EAD000BFBFC9BFDBC1F5A9596EA8CFDFB5903C58
-:10EAE000B88EE90E33DAC5F4FD3FEB706BEC758A36
-:10EAF0005E2F1A3CAE42213EBC3E6B27BCF67E47E1
-:10EB0000F03AA18B1752CE6FFA76571DCC7E4AF998
-:10EB1000ED07C00F5BCE69A449F4E139EDB32B01D9
-:10EB200002FC94A0DE124F0F50C61704DF5FA11F36
-:10EB30003D3FF52D9FC7CE99062FDED78A777EBB46
-:10EB4000CAD71F3DBFE5CFC0FD48346AE0F4B71611
-:10EB50003AF76ACE6FAB1387E1F96DB5EC4D6BCF29
-:10EB6000F9ED6FC0938602DCD9BEB6ECA7D1E3669F
-:10EB7000F73CB5FA4B6B7D9BCA3FBACE0DA0C709D7
-:10EB8000A0972531FD7B377B0F4019B71DFAB6E4FE
-:10EB90006C87BE6D229EB59288FB657532FD7AA9A1
-:10EBA00045FC56FA7592F31BC8BFF7640FC6FFBF4A
-:10EBB000374124F02ECBB582E1788F3A1E3E7EC0DD
-:10EBC000ED2FEF39197CDBB25FBCB7A2E8A6F72FB7
-:10EBD000DE1BCBE22CA7E8DEDF1DE164783095A7D1
-:10EBE00014406887B8FCBA1DE3E52F8FFB107F6FD8
-:10EBF000D2E59AC14302F87BC23CCB20DE2660B34B
-:10EC0000A37D6FCAD8A143CAED2A3CE2BF8F2CF77F
-:10EC10008D771C60BF99B2AB674AC0161F7FA6F202
-:10EC2000F511297C0BC653BF79117F5FCD943DBD93
-:10EC300053987D511B9FA6B7FB4C595E82F8A6E402
-:10EC4000174708C6A3B5E42576DF787144C2F8B546
-:10EC50006ECE96F8F6F49BBD9BD65E78EABF2BF09D
-:10EC60007C6FEC45766FDE125BDF58E1143476245E
-:10EC7000FDBD9578F731E6F1FEAF158CC0FBF7537B
-:10EC80008CEEDEEDB1532970AABF713E01F8C27E51
-:10EC9000B80F13A3FF879C8C9FEDF77E920466E963
-:10ECA0006C73532EE07F36B783C788D75F0A7434FE
-:10ECB0003A52F09DC4EB3FE1D4C6EB1738195FD14F
-:10ECC000C7EBB775DF68B231B67C9BC1E14EE1F7A7
-:10ECD00021D0EBD2CD32C6FBCDA7730880FD6D8B62
-:10ECE0008CF6B7F76F9808F841CE6F927F09F169FB
-:10ECF000459B7B6E7E96E68BC69AD06F337F0B7BEF
-:10ED000087848CB504C12F5BB4E5D1547857FC538C
-:10ED10004AB78BA8D2347FF373180FF3FED9A7310B
-:10ED2000FEFA22D033FD5EF4D593D301FE7B8C95A1
-:10ED3000B70DA2E9A29D82E6FE447195459357E284
-:10ED4000FE94FD2342F45E859BCA91979CDAFB53A7
-:10ED500083A3FEAE979CE8EF0A639C7CC904767F90
-:10ED6000EAD039767E3FD28BC50586C6DE5B388811
-:10ED7000AE636C0A7BBF451F4748C03906EFABF056
-:10ED800038DFB11F4B2DF75C58B9D796AFBA3FF0BB
-:10ED9000D68A32DC97B13F637693B1192CEE3D6E83
-:10EDA0007C615AAB7B007D406EB68A2B8CDEEF39DE
-:10EDB0001D0B6F0EE9E8FAD039164738EF187B3F84
-:10EDC000AB2DBEF9019FF7FB67FB3DF06B0A8FF798
-:10EDD0000B18177FFFC6DD6BF07D1A9F40209EF356
-:10EDE000FC8DD8F7C8529C8ADEE46FB96F03FB3301
-:10EDF000B560414B1EC8F21EDF239AFB38EDE737A2
-:10EE000037E7274F3AD93D4A3D7FD7E3FDFF29FE3B
-:10EE10003E65EC9174B89F4FD397F09EFE2EC61FAF
-:10EE2000F574AEE7E733747C30CAC70D9A78E319FE
-:10EE3000C00786AAF9B911F9FCFF00D1E7EDCB00B4
-:10EE4000800000001F8B080000000000000BDD7D2B
-:10EE5000797C54D5F5F87DF3DE2C496692C96412AD
-:10EE6000B2336189A088C3BE457D098B51080EB8B5
-:10EE7000A1824E02216C21816A456BBF1948C08076
-:10EE800060635D8A8A76A041D1A20D8835D6A01331
-:10EE9000A5086A357EC5AFD62A0D82088812412D95
-:10EEA0006DA5FCCE39F7DECCBCC984A5B5FFFCE26C
-:10EEB000A7BDDC77F7B39F73970914319DB9190B80
-:10EEC0000CD782B50A631BED7EB33395B1A1F66012
-:10EED0004A2163ACCEB921C13F80B1941476ABCF47
-:10EEE000CED869FCBB3C9C76D88BE2B0FEAFE2FC8E
-:10EEF00076E730A8F75666114B646CC8DB4D8A1F65
-:10EF0000EA1F53D8B4A618ED4EC5991883FA5BCD05
-:10EF1000BC7C2BD61B102ECF74169E8A837EB7D94D
-:10EF200020857A8CD99C07FAC1BC988925A98C9533
-:10EF300028FE4C1CB7D2D67E5F29942EDCFDBD0581
-:10EF40008AD843167FBA3614D69369F16ECCEB3A61
-:10EF50006E1F271F376D4911DB3F8431AB8D05E2F2
-:10EF60000633A6682C601E8CE3F8979AA0BD368DF8
-:10EF7000B155008F3D3037ACCFFAA59B581A633F8F
-:10EF8000B131FA0B14319C0C0B7C161FAC85714E01
-:10EF900031FD425CFFBF987E11CEEB13A60FC0BCC3
-:10EFA0001CB74EAC533331FF9618F028772A7C1CDF
-:10EFB000E6CBF739205FC4FC91F090A9CFA951BDF1
-:10EFC000C2876FCC6D87F2CFF7DD94CB20DDF1D017
-:10EFD00088A4F618F565FA8B9A6AEF38687A6F8D0F
-:10EFE0009FD224C6749CCF9A9A39DE717D187342E1
-:10EFF0001EE7556EF1E52747F433C499CC18AC27CA
-:10F0000071D4D6B65E40270756AB4EC503293315DB
-:10F0100063FBFDC1A4E26D03783BB7A11D9FA70A66
-:10F02000E4C57AC3BAEDDA3FDA05EC4E335C2FA3C0
-:10F030007EBB5B67B9C09385796DD8DEF2D9553652
-:10F04000D60BFA537427E6253D8C8211901EEEC133
-:10F050004FA3605CC57FAB93DAE929B2FC741E8EC6
-:10F060005F4C79393ECB763196D13DBC98A2CFC268
-:10F070007E0E31BD1CD3664BE02227ACB7399ECD46
-:10F080008945CFF3117FB09EFE4E412FCCEE3C78E8
-:10F0900091180FE6F76482BE10FB3966F355637A68
-:10F0A000595647AD8A7413E714F5DB19E21DCA6F90
-:10F0B000C77296DECEAE06785F06935D05D9970FD0
-:10F0C0007DC63C00A7C48E03CC03E32722FE62C0AA
-:10F0D0002D2199C3ED0F8C15C7E63B4E670131CF4B
-:10F0E00046E017933BCC2F4F41BB2D0390EFFC82A2
-:10F0F000EFF4AB503E34FED2A5AC82F25EBAC784C8
-:10F10000F4E16E637A10E121E02EFBFFC469A17E79
-:10F11000910F9533F0E143E7C9878DBF9C648AC3A3
-:10F1200079DEC5BC7D3D58EE596683FC138B9DDEB0
-:10F130005590EFBD1A080DEAE72C89DFA042FDA02B
-:10F14000E0A79E0FB26571503B6F5D8786F261D27A
-:10F15000DD6D9A0DEAE7D5B56B289F5EBAEBD15C01
-:10F16000A4ABC39F5FA53AB0FF6F64FF0020E0F738
-:10F17000314E8E4336B2B427E2A709E79D1AC15734
-:10F18000F1FEDF22BF5F56DD31D60AD57297300D12
-:10F19000E5E561C5FFEB94DED86FFCB4E000442FD9
-:10F1A000A7B7970E1EE95F06F9ED92DF95A24C9680
-:10F1B000CE5841A399E059D0F8D02D08EF82C62B44
-:10F1C0003405AA3CA185140DD759AD6B01C8BFEB1E
-:10F1D00034D3F8873F9FD753C1F9FED9CAFAC68006
-:10F1E000EF9BA2FF2681E7972DB1E97667A7DCE1C7
-:10F1F000FC34862952BEEE443A04F99AD81BE0B199
-:10F20000F0CEE3245F9F727A68FC27B4A69D993400
-:10F210002FE60DC0A7799BDE23792FC791F5E66F06
-:10F220005EBF02EB65DFE61CA47AB05D7B1CD2CF2B
-:10F23000F7711C5FDFDF191F5CAA10FD0FF25D1C68
-:10F24000830F59C86A4A270CD878AADB4C2301AF30
-:10F250001D1D8528F7A0CB65C89757257B681DB273
-:10F26000DDFA0E673CF2CBD9F4C14181CF73A5C35F
-:10F270003792B9DC0A74D59B47115EE7A1373B840E
-:10F28000DE3CF16FE94DA12FA5FE94E54A32C7E7B8
-:10F290003DCE6EF5A6923CACABDE74B3E0BD03612F
-:10F2A0003DECA8C9BB91751D3720E4DBD178DD9A10
-:10F2B0000C6981C27C386EE2D1CF98122187160B7F
-:10F2C000BEDE2AE9C0C56E9D12631D95A23FD3F430
-:10F2D0000E4B3BF6D3A210FD775DAF85EA815CEC67
-:10F2E00081F3BEAC27C84DA5ABDC8C818F5CAC9F95
-:10F2F000F5B6FE3A12C9E8E4C60440FF99F0D10B16
-:10F30000EBFF2A4EEF8DEB93F01F7C5ABDD537A053
-:10F310002BFC2F1470BECCA1F7C7767F137CD61DB3
-:10F320005E4625737BE6AA648E97AD0E512FCE58AC
-:10F330006F6632874B45B2912F23F0372A3986DD2D
-:10F3400023E5F0D1785F0196FFE1D0D604A42389AC
-:10F3500027297FA2F115E6B3A5341EC0793CB68FEC
-:10F36000D63FB27DB41E0AB70FD0BCD7231D21BF34
-:10F37000211D79B89E583F203C3F49E77EB1CE1F02
-:10F38000E2F52908BFE8793A8F9A9433CD33B9C3AF
-:10F39000AD20FF27EB4E4A5F3E6452705ECE0E4DAD
-:10F3A000C17939857E8CD683202E045C793F6F0825
-:10F3B000B9B1E2AB99E988E71585FEF46AA83FD9AF
-:10F3C000A1CF4238DCE3D4CB717EA50E7D36E64F6B
-:10F3D000C571FE1F95ACCFC1EFC9C28E8A9E67B5BD
-:10F3E000C01FC0B30AEB258E6301D487979FB40773
-:10F3F00041C4020860DEA01F12756711EAB1C4752E
-:10F40000CC8B749A92D0D16A857CC743CCBB01F275
-:10F41000F9018FC98AFAED367D19A62BBE52C9EEC5
-:10F420005C51C882CBA81F6E87B2BA5E41D2DFC0E2
-:10F430006F91F4BA4CC079593297736087D42473B2
-:10F440007E5A9A1C6187483EEACEAE88E0C3FAF342
-:10F45000E4C35FE078E7C1870F083E7CF05CF8F01A
-:10F46000B1301F3E8AF5CFC687CF083E7CE32C7CA7
-:10F47000B85BC0ED5D513F061F3E138B0FDD821E52
-:10F4800024BD231FA2BE0F2577CACFDFC5A2F77305
-:10F49000E0CBE6E473B00B3BFB3B47FAEFCEFE1B41
-:10F4A000E33AB3FDB7C7EEA4F5487E067E793399FB
-:10F4B000F48EFE16C205F8E56DCE2FB1F9AB53DF21
-:10F4C000747039C1584302D28F9CE7E702AF00AF96
-:10F4D0000FB01FC967D24F91F0EBA40761F71E155B
-:10F4E0006962C7670CE502C06D6F24BD3E25F82533
-:10F4F000309211BF8047558476E54B47C18E44ABAF
-:10F50000CFC5E75BB0B6ED756475A635244C757450
-:10F510000FA72217B773BA83138C7F2C963C6D41CB
-:10F52000BCD9BBDAF3D1F8FA44ACC7E952CE88AF04
-:10F53000B3CD43C20FE77109CDC3635A15A1E7CD1F
-:10F540002E45F2B7E682F4F2711D2AA3798512C026
-:10F5500085EA94A72C1BDA0FEDDADE1E6E6F77C1F9
-:10F560003C2FD7A1FD80707B189FE45DEFDB409EB0
-:10F57000919DAC9B503FADC8E3F4104DF78D683FB3
-:10F580000C88C0574326E1EB3E9B3F13FB6FD43CF6
-:10F5900026B4EB1AEB9D4A80F0581D8FF463B7EB4D
-:10F5A00044B731E490C7757E72A88F8BCBA1BEAEF5
-:10F5B000739043035C9D72E822ACEF3C8B1C1A23D2
-:10F5C000EA17B8B87CE94E0E5D26EA1509F8C69030
-:10F5D00043635C31ECB96D369DFA8DC1A79763FD2D
-:10F5E0004CA7AEBBB85E2B7445E835683716F3F709
-:10F5F00089F6AB1B4CFDC87E66F1DE587E86CF6572
-:10F6000037D829970AFF81B5FCF3F7770D67AC0A65
-:10F610008BF83C7DAED4B03FD1D8F0591AE21FFE32
-:10F620000C7195079679DFED83787B476568873E97
-:10F63000F03FED168477737CE240764978DCAA7F50
-:10F640000041A6005EFE61A254E27161CBD2210CA2
-:10F65000FC88C2FD3FE4A25D796CDF3F283ED261A9
-:10F660002FF3E3F83BB6F338C989B767A6A07D2E20
-:10F67000C75F8CF882798D5707348560BDC777598D
-:10F68000BCA86F55E6F95501CCA76A979905494E74
-:10F69000311BD637F3E932F3AE156D6A22E6B58039
-:10F6A000886F28A7C99FF12421DD9A77A90CF990CA
-:10F6B000B9797980D9969E067F3369A4897922E247
-:10F6C00021C97A3CF344C427528A5D867CAA2FD391
-:10F6D00050BFC7B45E86F20CFF8586F2AC39830D4D
-:10F6E000F99CEAD186FA3DC1DF89CCE705AE32D478
-:10F6F000EF5D3FD590EFDB7093A1FE056BCB0CE582
-:10F70000FD83F30CE515BB9FB7A05F7DD1A6C58631
-:10F71000EF1737DD6568070069EB0374328B71F80A
-:10F720005FD2BCCC507F56FBBC4948B78342AB8C00
-:10F73000ED1ACC07383C030CE1F905F35B90CE34AD
-:10F74000D6B1330BE0BE30A87843506D6E735E6F58
-:10F75000E4872FDF2CDEA50C8479ADE5ED643F73E3
-:10F7600083C6FC7C7533F14F349EAB58AF24CF5029
-:10F77000A40395059530DEE76F32B66718EF827601
-:10F78000F3C57AA2E9E20B56FD7001D247406FEB58
-:10F7900093165EB799350D0FE17741274E412772D9
-:10F7A000FD72FE72DD4EF80FCB41E15B90CE663705
-:10F7B0002BEC51A5EBFAE6B4DCBF222BC63A190BB1
-:10F7C0005AD0DF8E9EFF0E97C37D3001FE91CB7223
-:10F7D000316EC5BAF0879DE4F1F1756AD00A74AD57
-:10F7E00006FA45F18771FDD1703C5F7EF10838580B
-:10F7F000D38DFC12E7898FA6B7E121D615AE09FD9E
-:10F800008C7C24E128E1EAF066C6A42B0FFCC7E15A
-:10F81000ABB31F13BE1D08DF8BC2F03D66F39F40E4
-:10F82000397CE2A36F55A23B7FFB10D463DDE9A5D1
-:10F830006447D1DF44FD5CAC5F9500723109FAF991
-:10F84000EC877CE4B74EB9BCA4CC3B0EE4A2A2F892
-:10F85000594A6AF87B9BAE3A8602BEE637AB5ED465
-:10F86000C3C7347BBD72092DD3E34C43252DF1C6AC
-:10F87000F128F1A6B4BCFE7705E0056DFC168CBF3F
-:10F88000167B6D384FC6A6539C5301F7E67402E908
-:10F89000D9C414D2BF3AA3F8DF71E6AD85FE6A1D64
-:10F8A000BFBFE82CF110570AD90FFEB478B43F3A25
-:10F8B000DA4F3C87DD6B6D4E1C678ADF4FEB198199
-:10F8C0001304BB9A39014E11F12268978DE34E79EA
-:10F8D000FC9709680FBF74E0B84AFAE51337D9C33B
-:10F8E0004F315F7F940F5DEDEB00E93D69AF837FA2
-:10F8F000D43B85DBDB7D5322FDA34EBBFACCFD80E0
-:10F90000DDD10FED99EE52E53595F4698712EFDD03
-:10F9100010439F8E4C31EAF94BC3F1B8912911FA8B
-:10F9200073E1ED2776E23C00DE63709E0E07D8356A
-:10F93000CA39D93597633FBF4A4824BAEED8AD06D5
-:10F940002F8006C76D9E2417DA9142CF2A1AE8103D
-:10F9500057843F6B730DD0866079FF2416C34F9197
-:10F960006911D64B09E75F8B33FAA32B06F3794D68
-:10F9700011EB5C29ECA7F2146EE754611C2E251CD8
-:10F9800087AB9AC6E3CC0F45C52FCB531C547FA53C
-:10F99000BDA81CD7BF224F21BB6985A218F6915282
-:10F9A000530ACB71BDB78AFECBA16F1CF7A95E7C51
-:10F9B0005EEE28FF3D0FEB0FC394F70B9CD41FE9BD
-:10F9C000CFA2AA31E1392F45C4B1E399B4BF896F01
-:10F9D000260ABE9920E4E5957D415E1273E993C63F
-:10F9E00043F93851CED4757BAC503EF10233433AE3
-:10F9F0001B877209E5BCD3FC597BBFB09C9FD0AF7D
-:10FA00007A078A872BD2E17B843C2966BE2CA483AB
-:10FA10002B3DC6EF13F74C388CFC3A9169D40F7D1F
-:10FA2000CFE3704D7085E97D594AA7BCF79C06BEAF
-:10FA30000EC5FB1F28C1F8C39F54EF066AD53624B4
-:10FA4000D22FFB85C0DB6AE1A7E03E12FA1F2E91A0
-:10FA500046C3E717293CEEB0DBEEFB05C2F3214BB2
-:10FA6000DB4F70BE214B7B6D128EF301A37132E729
-:10FA7000E8AD981FE6F3308C13AFC863762FD2E75A
-:10FA80002013C541DC7EE7380BE4DDEB14B4849928
-:10FA9000596301C7E0B05C684EC913F3AA6D4D828B
-:10FAA000FA49EBBE61BDC87F708E73A21C9AC56215
-:10FAB000C6359F167431E5F15E1AFA614936450F75
-:10FAC000C658C7D302CF201736E13A2EB7ED1BA296
-:10FAD000907EE07E07BAB2F47F074CC18D4AD7F61C
-:10FAE00076FBD8E7900E251D5FAAB2EA2D764E5F11
-:10FAF0005322E458B3A4A7738C470F9BC362C64D2F
-:10FB0000DF17782AB7F95EC1F90EDBE3A1FD8E0A93
-:10FB100029EF679998067478A320C31BD7B5FE9D7B
-:10FB2000EC8B1F4E9F56A5DDCEA87F86FB0F150BD5
-:10FB30001C41DC8FA868C90B50BC698E42FB245560
-:10FB40002DEFF9305F3174A893E46482A21CEC4776
-:10FB5000263FE37251630725FDA90248D0FF34A177
-:10FB600067409FAC4E807555AC5BDF9A01457F01C5
-:10FB7000C301F1FF9089FB7FD1EB4A8BE7F059314C
-:10FB800005FCE04128764FACDC918D78AEBE50F19B
-:10FB900082B1B2F4F8EE5D978AB85826961FDFADB1
-:10FBA0004B3F3293A61162309FA7E23BF3BA2D9DE3
-:10FBB000E481CC0730DF88CC361AECB5078EEFAE87
-:10FBC0001B40F44B7A8969200F2E0EF3FB47AAFFE6
-:10FBD000A39FC1BAAF0365BC6430A61A9B4E784A96
-:10FBE000A7755E2BD619F807530EDAC270B9AE6549
-:10FBF00037C1FB23338C07CC632EE2A031DF954461
-:10FC0000FBC9603FD03AAFB7358C47BD7ECCD2310F
-:10FC1000D08BF184ED1FE60460FC4F7F7EC2C18073
-:10FC2000EEFEAA7538F0FBA1BBDF77E880DF4FEF6F
-:10FC3000568B917E6F117A52C22DCECDE9E166B717
-:10FC40008FB9511ED69C1AEE8F8C0B2D4925FD368F
-:10FC50003708338CB097E66F4A400BAE335FD994C8
-:10FC600062C84BBD576965D5B1E2A097BA39BEE607
-:10FC70006E5E6FC9F2E0F87E178E7F08F40BD2CD6E
-:10FC8000A16D8E20FAEF723E659B0759D09EFA6BEC
-:10FC90008B9585D03FD3DACCCCCEE5A602F4EA171B
-:10FCA00074193DCF9DAF24507FE50F71395B0A6316
-:10FCB0002D01B8FA5BE6923C8D5E47F9A79E093D9F
-:10FCC00000DEE52BC172F1F0FA7703DEFC4BEEF9B2
-:10FCD00006EDD3E87596068CF27566BD312FE57E8C
-:10FCE00085C037889B7AB4F3CB1B8CF52A5AEEA5D6
-:10FCF000FE2B502ECBEFB0FE216E61170E67235006
-:10FD00000ED7DA7B25F9CFA0678FD680419ECFD85A
-:10FD1000911A1BA5876A18A5CCED217C2C6879EF78
-:10FD2000A748370B9BB758B09FBAE078279033B3FA
-:10FD3000B600C7A33D8DFBE3D07406EE8FC33C6BCA
-:10FD4000712219B87FEE1BEF067C999D51FBE5628D
-:10FD50007DD305FC99DD45F4351DD73310BF6BDF2E
-:10FD600046AEE7F8AE21361C77B25CD70858977AD2
-:10FD7000EEEB92EB91EB93E595203763C90549DFF4
-:10FD8000CCCDF5CDACC6292B320114B5DBBFA038E4
-:10FD900000137E8826F0A3D957911FA231F033F8C3
-:10FDA0003AB91F12607B58049D45D35105C2019991
-:10FDB000D8C9DBD9847FD2493F2D6B081E12CFD022
-:10FDC000613ADFB70CA5E3BE25D0D181283A32E4F1
-:10FDD000CB1B8CF9AFCDEDB9C8DF402F0722E1FB7B
-:10FDE00075D4791999CE70F7E2EBF7E8139C505E61
-:10FDF000CE7C2B9CB4FE06E2C3435AC3CE9F21DFC8
-:10FE00003572BAFFABC0FBC76E5F2DE29D69FA4049
-:10FE1000946F45CB325437D42B5DAD38919F66D665
-:10FE20000D9A807C3898E9D4DF8C6EECCB8D02FE85
-:10FE300065D5666601E3A0CCC348AE956D53833C9F
-:10FE40004EA7DB4B00BE73041E2A576EB164403AC6
-:10FE5000A7BA82DB3D41CE2F0057B27BE6AD6EA53F
-:10FE60003802F85131F94DEAA9CA266379155B4D7C
-:10FE700078A88AB27F82921EBDCC8BF4E8FFA9C31A
-:10FE8000A6249D7DBDAC6B9C88E248C777F5257B99
-:10FE9000F8B8C7D303EBF901E76D68E76BFE11F81B
-:10FEA0001DE044FAB263694210EDFD7D27C18F4524
-:10FEB0001BD4E91F6101B8B47F9C437A5CD2A75C74
-:10FEC0004F956D35D1671533FAC9A5E09061FCB740
-:10FED00074634A10CF0340FF039BD18EDA68263B40
-:10FEE00029C016A733A033DF7233C9C3B2E664F268
-:10FEF000D3CBEAF8BE51D9E6E4A0CAE30F7B30EEDB
-:10FF000022F1B0AF6EAC2583F094E745FDCB9ACDDE
-:10FF100006FA96F889F673E7D5B7EE4CF7741F0723
-:10FF200089C0CF816EF07320123F7BA2F0C3EE4EEA
-:10FF3000E17266D11FFBE23ED9F1EA38AF1AC36F16
-:10FF4000927A886503010E0FC7138B33393E98E60A
-:10FF50004D437C9E583D8CF0158DA7E27FCD247CCF
-:10FF6000B08F1D0CE3CC337AB35BA7C2F75B15CE21
-:10FF70001F336AAF2C467DFD959033EF827CD22DE6
-:10FF80008CBD07F24907F9F43EC82DCC7F50934E43
-:10FF9000F90F6B3C94FEB9A61FA50784DD27F9066F
-:10FFA00008C08276E309C12F27A4FC62B7A5A3E9A4
-:10FFB00050FCAFF7879930741BB8EBAAF160CF5CA7
-:10FFC000AD1BF5DDB46B8DFAACDDEC9C908E76EE5E
-:10FFD0004A85F653CA7C630CF599E6B14C417FBD66
-:10FFE000DF90F077B25F3D96A9C0EF374E4A31D42B
-:10FFF000BFBE3ECB904F48F5D0FCA614F7367CBF71
-:020000021000EC
-:1000000069FA45867CE94900C210A46617E1E13629
-:100010001B13F104178FF38AF334DF568FE871074F
-:10002000CCF7DBB7CD541E8D0F89D7596B4DCC0F54
-:10003000539BB916D606FD1E68003C41BB2F3F728C
-:1000400030A4E3159B87BC3312F2FB369B295EBBC1
-:10005000AF2EE53EB48FF66D4E4DC438B07F852A85
-:10006000EC08A78545C8ABB1754BE99C4D69D0EA52
-:10007000257B6147E00999F728C8F78CF3CB1E353B
-:10008000887139C01F8F673C63A57D884360B7398D
-:10009000412F1C52581DA6A85892A0FCBBB6D420D4
-:1000A000F273F1BF543D1DE9E99938B1CFA4507FF7
-:1000B00047DEEBBB6115D197A729447C6B25FF6711
-:1000C000663B5F1F53066721FE0F25333D192651FE
-:1000D000B9F8C3BD1AE0696E7EDBC010B49B9E17F1
-:1000E0004ABD01DA1D6D34D3B91BECD709F9CADF5B
-:1000F0005AD77339A2F7407F220CCFE0405CF70C4F
-:1001000093EFF254C0DF91D9C18124CFEE4E25BECA
-:100110008A86FB018B9FE01B403E50C2F231CC67C8
-:100120007CFF10845A06CA9999666F1AEAA703AB36
-:10013000CD647782FE48C4F119DB4A747C40F34CED
-:10014000C0751FA8CF6328AFE4B865AB55F2B39074
-:10015000FEA8FEFDAA1F6C0426F554A05EF1B31E96
-:100160005DE9E6278B46F4C0F544DBB732FD1A782B
-:10017000D51F612FCCDBAEFAD03F6243DBB56B2FCE
-:100180008E5C471DDFB748E7FDDF26E4FA825E6F2D
-:10019000ECB59B50AEF74E42BFE7F01E95E8EC7011
-:1001A000AF86E1E9BDF178CC6BC3EF80FC97258188
-:1001B000831AE49FB0FA17205CE79B563FA140BB2F
-:1001C000632DFBEF1B03ED8E3C6BF6E2B0F39E99C3
-:1001D000DB93F619847DDD556EE9D23E4853D2D1CA
-:1001E0008E7092DEF6D4C120B4FE20CDF366D6B474
-:1001F0001CF1E65CC0BFEF1FE65885719A99C01EDE
-:100200009176F77E33B70BFE2795FBB552BFB7A4A7
-:1002100072F932D3C4E99ABDA2909F8AF64E9F0824
-:100220007D2CE5F29A546E4774EA65D644F26A363C
-:100230009EDB81F52DD8640D06F3A88D13F97C2E75
-:10024000470FDB8D7202C69D6779F661E4A10AD67D
-:1002500046FAF3883938BB2D0FDBAFAF73517BB350
-:1002600097E2C5429FD88081501E5508BEAB6C50A6
-:100270008221E21BAE17CB45FF0CF54C84FCEAAAA9
-:10028000578CFAA45CE8D17216156F6E30EA375FAE
-:100290000277E2E7C1B8A82FC3F302FB186036DB90
-:1002A0001FDC3999E6AD788331E651C13A422ACE56
-:1002B0007B33DF77889E57F43ACE759EB3BD53C625
-:1002C000250F8D18376ADE12DE14B08EC08384FBD2
-:1002D000EC0087E7EC1685F0F5B9B0CBE4BE8BC433
-:1002E0007B05F34DC6F384150F82BCCC0BD341A71D
-:1002F000DEDF12A4FD952F5943A21DE87EC1DA2D41
-:10030000D78FC276EBDE23FF62BA2BD4D794CC58BA
-:100310004AE0F355C53931F655A2EC831F0B3E3840
-:100320007B6DB86807F0286F54F5B881867AD45E83
-:10033000DA077302010BC661E788F8E6D9E659854A
-:10034000F5069FCB7C63DB33FFE9BCBF4F15F1B9EA
-:100350002EF650DF987E54A71D7416FDFB89399444
-:1003600083FAB7234723FDF3ADE6FDB0D08DFAB88D
-:100370002FF905DDC9D7D9420F97A35E86F4E0DADD
-:10038000E713D16FFFFCC1E7693FD7F26C7922DA3E
-:10039000C507D7CEBC2F002C7570F34CD2C3158F78
-:1003A0004A3DECB744EAF7B16B4B7FFD73A4CF4DE8
-:1003B00071B41F317B875FD8DDE0B7A01C5CAB3028
-:1003C000D20B0F72B95781FA6A00E9AB0BB0DE4F5E
-:1003D00067FB2F403A8FF84E7AECA733FD23A83DF8
-:1003E0007386D0EF02C919427D25F5A9D4B39AC905
-:1003F000DF270DE1A5BEFDC19DB0FEAFB6AAE4DECC
-:1004000055AAEB739DB8CFD18DDCFEF7E16DEA8480
-:1004100077DE39C0BB0CE14DF60F87F767F51CCED0
-:10042000FB5773B8AFD8DC3B11FDDBCFEA7B93DD24
-:10043000F3D9E6BE04EF59AB00DE64F77A8C764F51
-:100440003DC01BED7C84378C5BB6C323E0EDE5F04B
-:10045000AE177A67354F6775816BE01694273FFDBD
-:100460008DD58BFAFC505C2815FD91435B5486E7D3
-:100470002C3AED2261BF48387FC71A9E403BAA8BB9
-:100480003D73BF95617C76EE0B8E2083FC11A5B089
-:100490000722E068C31B89385E78FC4E3B665ADA57
-:1004A000B0083BE61CF1B390F9E81EC2C296373E95
-:1004B000423B5ED1B95FBFD0660F21DF82BF73348C
-:1004C000529E2B1E94691827F1DA6C4807D9CCE3A9
-:1004D00023BB46EE77F919EE777DDFF79B5B1613AA
-:1004E0003F77E447C6C9ABE243668C2F756C510871
-:1004F000DF95B715261632DC4FABA679DC9EC6F524
-:10050000B1A2EB1437B402DDC4C3784BD23C24CF84
-:10051000158F93C711D7C1B88EF07CA3BF4F46D2B9
-:10052000437D6E8F1D77DE98C6ED804AD5447EC729
-:10053000020BF73FE47996E5621ECBD3B81F726FCA
-:100540001A3FCF770CCF8340BFC72EB58AF3D9E3CC
-:10055000289ED9193F9170736A5F77CA2BE42BAD3F
-:10056000231BE1B477F47B66946B7BB12D19D380A8
-:1005700080E168C7F0F6EF98EDF56857DE3CF20DC4
-:100580008A83EE8DF379D0DEDA9B6AF3221D05B6FD
-:100590005B89FEEE89E7F16FE64ED2909F6E12F214
-:1005A00076468155C720EFCD05F7F830857102B842
-:1005B00009B1A2F0F5E54847B7A6EFBFDD064B5AF3
-:1005C0006AE2F6CA5217A373409780B98E71583CFD
-:1005D00022733AE54C74638C5B2FC0F8EC68C60953
-:1005E0006A24C1D39007B852FEE587AF9BF8603606
-:1005F00063FFCB3C17239E17204C900E4A93C8FFF5
-:10060000BF1AE3C42E4C35A2AFA91A0B98785A8FA3
-:10061000213519379E2CD679DD48164A82F5857624
-:1006200033435CFD8690297401C0ED6A2DD48AF0B5
-:1006300033D93C66F4037CC5CA60F48F172C3BB7F2
-:10064000F9BEF3B07FE283059037F1C38B1D772AA3
-:10065000C10D00A79B81B9912E6FD1D80E7530C7FF
-:100660001BD25D95CB13A07A8B14B13FC4E3F91272
-:100670002F83A0FB48F8DE2CE607FDD427627B4BD6
-:10068000ECB8D1C769D2FFE576E67CC1A7F3259D1A
-:100690006D36F2E73F249FA03D0B70BB59A4DDD11E
-:1006A000F9DF44FF7F1374FEF9798E576965215A8B
-:1006B000F7762BE1518E7BB548BF4BE3F6B29C87B2
-:1006C000A45F26E24F2690184847071A6AC95E9A27
-:1006D0001315FF6591712A3556BE53EE984E636A25
-:1006E000E99885F3512E8B237EB9D9D2D4B7DADEBF
-:1006F000B51ED8D184A24ABB8DECBF85AC9DC7B3D3
-:1007000084DD2FEDC5B968E761BCB291DBB59AB065
-:10071000C74BC13F43A22BAD8FB077E17F939BB70F
-:100720008CC7783E18267EDAB7B0DBE8DCC6E40575
-:10073000463BC92CEC2273945DC4A2CF85083B29AB
-:10074000FA5C882AF817EA727F459C0BD184FDDB9E
-:100750004947696681CF80611F7E3A6B33F3FB6244
-:10076000227E27F4F378D5DE0FE5CD7425DE8BF6F7
-:10077000FEB14247C09484F125338D371DF800E562
-:10078000C82771FC7CC58CA49F4E463B787AA24555
-:10079000C3F45367AFA41B18CA1B55EC1B0527E213
-:1007A0003E532DCA4D9EBF57CFA62898C86F7C0BCD
-:1007B000F767AEFD01E64BF92727EAE0BF1DFBA373
-:1007C000280F401EE975B9E4DBDFF2FC43B2FC7789
-:1007D0003CBF52966FA3F18EAD91FD8BFCFD51E5B0
-:1007E0004BA3CA1FE1F9F13DB64D0C207CC4BED32A
-:1007F000F4D10AED3BCD41BE02F84D5F16227A9A44
-:100800006E7A8DA7452C84FB8E67ABB7A8876F0ED9
-:10081000EA67D571C081F6C99D19FA1CB4AFAE4D17
-:10082000F5FB7AA05F3845095870FF714F305FE8DB
-:10083000AF98E7E7E7083E5D98EEA3F6D2DE857E47
-:100840006EFC77FA39D5A34B3F653D52CFBF9FDD94
-:10085000E97C7D11FDCCFF77FA1998619C8FB4FF7C
-:10086000DEC8D457E0FAD801B7E15CE4FCFFF1261A
-:10087000A1FDC8F05C24807EFEB2A6DC21D0FFFC86
-:10088000E75ECA9D1D115F5878D2C474B013AB4E99
-:10089000324ABF6CFDB3C503F359B8ADD53201EA96
-:1008A00055413A36625E0BE4B960D6AE4D8DB05F0D
-:1008B000EEED6112FC743FBFC7F5DC61DA3F9E6F5D
-:1008C0006A3AF828F2E3681E678C5EDF4F7AF0FD23
-:1008D000BEBD783E20867F727F0F6E8F6CCFD61B99
-:1008E000709D8B5146423AB636F6F98A8F457FD3D2
-:1008F000E3B93C9F39DC61F35C82FBD9FE5ABCAFA3
-:10090000377B5DDE608C57DF915AF4688F33C67F8A
-:100910003B78FCB785C77FA7BBDA6E0365C53EF899
-:10092000D5FBF7DAC05F9DF82BD6B91F8C71D56265
-:10093000ABE4BB2313C715503C8FF2CD3D0EDC1B3F
-:1009400080F6BBE2F9F99119232E8E4779D09E9754
-:100950006072829C08B84B3FC079CC1871E904FCE6
-:100960005E6875E497F2FD03A28B80DBD784EBC64B
-:10097000FA18BFF15B783CCFFFA64AF13CFFC004F8
-:100980007FACF307CF09387CD083DB67BB00CD6831
-:1009900057C979C8F1C120BBAD0DFA3BB02C63102B
-:1009A000DE8BFCD85DB887E022C6FFD8ED6F8D1CCA
-:1009B0001F963B10BF9FEB3C5E1174B147E0CD57D3
-:1009C000A0323D42DE4F1D9760C85F3B2985E9910B
-:1009D00071E56BB30CF969D37B1BEADF34EB22437F
-:1009E0007989B56D68F579D8F9550E473C9E6FF851
-:1009F000B4E5BBFFBB19EDD746D5ABC07AE66EDFD9
-:100A0000F87F63A0D6713C364CF6A887E27B47F0AE
-:100A1000BC21F29EA66B91FB525FB1363AA719B189
-:100A2000EF61D85F9AEFDC41E7447FAC7DA9133DCD
-:100A3000C4BEC7603C628E7AE8835C3C5FB2D0CEB5
-:100A4000D7F3D54BFB2C74BF03F507D0F715D8505F
-:100A5000453E0F50BC7D6CF33EBA47F7500F2E97C2
-:100A600017662FD2C002655590A2DC9F00F22909BB
-:100A7000E8A3AD955DBC0DCF57E739E83C4CE5C91F
-:100A8000A98CA5201D05062C827AF3EB8B29BFF0DB
-:100A9000643CF5FBAEDA3681CED1BFA8D0BE484962
-:100AA000D68C65682760FD9FC07825BFBBA218E182
-:100AB000B3701B3F3753A2FEEF50EC67414331B593
-:100AC0002F51D92E05ECA18963B97E2D415B06F229
-:100AD000EA70C72AD4ABAA2594FF18CA138B83E403
-:100AE00049D2C99B68FCAA93366A9F95CEED3473B0
-:100AF0003B9FD7F8933EFA2EF19E97DECB70EFD353
-:100B00009CDAA895D9B13EA3FA579DBC9052B9CEB4
-:100B100037FBFDC68D72CC9CFAED043C27FCA65B2E
-:100B200071927915256F4F548F486231E4914CAD25
-:100B300042CEDE7C929F43EF95A98F4887794EBEC7
-:100B4000BB5DC37D2A66B739115E93470EF2CC8E2A
-:100B5000E023F5B51BD1336056778719F5F9CD90B1
-:100B600046CAE35BBB91C797A69B0CF776A47E6150
-:100B7000C11BC9FEBE45DE53167C72A1A82FDBB790
-:100B800091ED04787CC14A76D4984CBF2F1DCADB06
-:100B90000AD9B4AD241FDB72717FE8C79A3FE0D950
-:100BA000A6903FD34EF730268FF498D03EBC2EDD72
-:100BB00064B0D3CEB68E2251FF5D952D417DF2EE0D
-:100BC000E597B7E9D05FEBCF860C41B92FC79D9D64
-:100BD000CEEF9D3367C70FE8B756BD92E041BE2EFA
-:100BE000C1BDD6A161BB1DBE338C7356BD62DD8015
-:100BF000E799AA12C16F87F1C7BE1A17423A6E7DF4
-:100C0000354E43FDF075B67F36E273ECAB178CC3FF
-:100C100073747A8B556364DFE81508B7EEE67B36AC
-:100C2000F9144D67922FFDF59C5F4A059D9609FECC
-:100C3000F30B3E3A51DD83F8F0C4DD30695847D9F3
-:100C4000DDCAC5DBD01EF038E81C96E4CB12F4F305
-:100C5000E07BC945C9E4EF46F01DF1E182934EEA1D
-:100C6000AFF2A447F0B98BF292DFCA04BF48FAF69C
-:100C7000093BE26799FE87111E25B5C0EF787F73A7
-:100C800059C650E4A330BD589C4857402FE9B323C0
-:100C9000E8A1B615E8C541F44272C8076924BD5CF5
-:100CA0002DEF1531E7843498F7E4BA3CC3BDA2C7F1
-:100CB000CE93EEEB05BD94D9437DD15E3557C77910
-:100CC000F19EE47137DF875ABC92C36FB1D93716F2
-:100CD000ED87C58F285EC00CD915288F867F546D8F
-:100CE000898CABDE787220F3C0FAAF39D987D23B5A
-:100CF00052FD4F231C4A4F5E2FE035F0DFDAEF1C28
-:100D0000A6F3389A3968F5AEC7FDC438BF8AF83DF6
-:100D100094C39C0F44C4D130EE87F13FB90F2AE34E
-:100D20006A56DC378ED093DF690DB9E8E77489AF76
-:100D3000151AF70B17B4FEEF7013941FC9D329CE01
-:100D400036C3E47F1DE979DED4E07366C8CF5FF374
-:100D50007C22C6F5253C9BB4505FD4934D00478C54
-:100D6000F735AD568B83DC9E49E0FB7C9CAE251DA0
-:100D700047D3F7BC93BD889E4E545B49EF9C007AE5
-:100D800065117A275ADF483AAED498F05B93E8DCD5
-:100D90008894FF617DB3FEBED148774735A2FFB08E
-:100DA000BE99EA2BE4F44FE7CEA3E9FFC59A743A63
-:100DB0004F24F548B4BE8996EB525F7D92E1FF1E49
-:100DC000E154F4DB7F3EFF317CBA4AE37AEB2ACD73
-:100DD00041F4F3DF92FBFF3C4FFA3F2CEA83FD4ADC
-:100DE0007621CAF5C8FEC66416256640794A06D73C
-:100DF000ABFF6D799F92717EF29E65F0F99F4DDE9B
-:100E0000E76770791F2DDFF1A222CAF763DBFBD3FE
-:100E10003EFC5E06FA00F55E4B8267A390FFA41FBE
-:100E2000E293826792FFDBB367E667C496FF1764BD
-:100E3000FC07F2FF7CF944D26F77FC32F15E6E9FC3
-:100E400031B4CF9448FB8CC365D7855C0F44D86917
-:100E50003C9E027CD55789E49B0DF78D46BE39E652
-:100E6000F6E25940C927926F24BFDC2CF8E356A163
-:100E700017247FBC9AE1BF11E125F963C1D668FD53
-:100E80007066FABAD95DCD503FDC0A69247D593BC2
-:100E9000F583912F6EE9A4AB73E38B4919E766479D
-:100EA0002CCAE0F7DCFF8B74B508E927065D2DFE40
-:100EB0004FE8AAABFDFAE150BCAF766228D0515E94
-:100EC000988E26BEC5B8DDD09BDBFF9D7462C9A19C
-:100ED000B8CEC4D3FC1CAFA45389DF68B9F85CA6B4
-:100EE000EF61C4B7F41BFE5BF2EFB1F3C4F3CA7356
-:100EF000C4F36681E71FD15E7C31165E99D36588A5
-:100F000047007F5F43765C48A32341DDE1D5BC9673
-:100F1000F397CC2F0F6952EFA6A0DE057A69FE4F3A
-:100F2000E8A5642C13F18D4393304E39F11722CF8D
-:100F30008E4E423EBC7EA42C3FBC5AEF837286C9C3
-:100F4000FD038A8FBCAB8A7CE0C8DBE3605E131FC5
-:100F500060E1FD05281F5F90D4194F41D743D6FFAC
-:100F6000F0912FDE5E4DFCCCCFF9307FBBC6F7D5BC
-:100F7000447E28E41D11F99151F975BC7EA2D6CEAC
-:100F8000F8B9CC20D7032A6E3572FAF145D82580FE
-:100F9000C909787E62F236C589F1909B0A8ED1FE2E
-:100FA0007378FDC727E905B82FA888FCF76FE37AA7
-:100FB0006FDAC6F3A71EF9C7EA8026FA4BA37819A1
-:100FC000FD599B145DC5F320239560AFBCAE703E08
-:100FD00015A5F7F04F33B66778CEEA7CDA239EA9E1
-:100FE0007D2F6A1FB29EC7F83714C4BE27E2C8140B
-:100FF000F5445C81FA07585ED314FB1E4CAAA8DFA7
-:1010000086FB4504AFA43508BF368B8467E21AA47B
-:10101000A7F18CE77B3E9A581218C0A7AF47ADFFE7
-:101020004CF35732BBAEDF636C1F3A13FCAC5DDA96
-:101030000BFA9963A4A724CDB7E304CC23C9AD3838
-:10104000D13E5EE88B5B8D7E40983E324A703D6DAE
-:101050009D71FD68FACF2C41FA5FC864FDEC35E460
-:10106000E7983AEB737E90F405EDFBF1F7F7A8FDF6
-:10107000A847B3D6207C003F544E79ED0CFCD01429
-:10108000952F88E21F41FFC4BF28E7013E7D63C85A
-:101090009969023E5F8973E46D45DC5E6C13F7E28B
-:1010A0009664F238AD3F93DB637324DE23EECDB05C
-:1010B000083C3371AF2662DD04A71BDD72DD052518
-:1010C00093605D6D2E5EBE3873E49A4076381FDD06
-:1010D000DF6D990525B83F11EE7FF49F506FDC2836
-:1010E000E0B62473CC9F025C1E2AC89795442080EA
-:1010F000F76D4A80CE61215DC458B7DE95AE0251CE
-:10110000ED75F319DA4FE8DA5E8F6ACFCCEEF3694A
-:101110002FF036290AAFC551781D17959F2EF34140
-:1011200083FC9372B1ACF9FEE5696E8C4F2A74A70B
-:10113000374CCF57113DCF774AFA9DF827A4D730C7
-:101140003D4F22384F6D92F2B0640DCAC329280F6B
-:101150004787F3D7A0BCA0FCE4123D29525F5CBDD9
-:1011600046073CDF502FEBFBA8FE4D75B2BF29545C
-:101170002EF1C802534B70FC1B870A7D11B8E64F55
-:10118000583EAF85B7FFEDA3D7FE29D0E70CFCD0C2
-:101190001005977551F94054FD07CFA25FEAA2DA16
-:1011A000DF1D55BE3A2ABF362A5F6F6C5F3A4B216E
-:1011B0003E2C057A40449C8D2F5FCEECF47F3AF5AF
-:1011C000A96227BBCDC057136B79FE8F8F9696D43B
-:1011D0000F88C867CE2C89E40BB9BF0AB23680FAF3
-:1011E000CADC8DBC7CBE3BBAEC17AD6F79F95FF100
-:1011F0009F19B4CF63B00B5E578DF95655CE7BD196
-:101200009F6E1B10B91F5A5D8271966EF75DD8C232
-:101210009271917649A092E844AE53D69F70EAB499
-:101220008AE3FD25B3B2A411F7758AC47EA48BA707
-:10123000A0D754D49B55222E3301CF0363BDF85061
-:10124000DFC59176086BCAC775B6FE8CDF9308D4EC
-:10125000027E30CEC6BC168CABB426252D7912EAA0
-:10126000BFFE337509EAD1BD4B52E81CD66559DC87
-:101270008E7C3DA9675A39E45B136EB5E0FDF3D669
-:101280007BC653FA9AAAAFE8005EFBFBA37797D818
-:10129000FB637912C1E7BBCC25254B81CE4FE225FC
-:1012A0002568EF7739D3F01E075B6566FC3D24EFB8
-:1012B0001344376BAC83D08F2E5D7A11ED5F953D73
-:1012C000346502DDD3586EA67D0DF8A3FB3AFE55BA
-:1012D000E3E99CD7AC3A9106AEA0F4D57FFDA636E3
-:1012E00011CF2D3CAED0FD904BBF6D7A0BDF5DAAC8
-:1012F000A8EFED45D4BC02763D9EBFFA6CED0574B7
-:101300002F647F5C359D7385FA0CEB57FCE07967A1
-:10131000F250ACAF3AF148C941F88EF6F0C195EA07
-:101320000605E795E888C7733C074F79DE41BB1691
-:10133000CA9DCBE0FBC1E573D3D0CE3AA878121595
-:10134000BCC7F0D8AA92F40C7C3FC12AF0B9CA51AC
-:101350000A7C5D6AEAA417D21FB393793E356B55B8
-:10136000C94698FFC1472EA0736EBFCCD2D3B2003E
-:101370004EB766EB3DB286E13CB99E7AF55F7CDF05
-:10138000F0E5A36569484F79599C8E5F39599656A7
-:101390001661EFCCFE4A23BCBF6AF1DC86F37C35D4
-:1013A0003E47A1F3E8AC2905E3DEB3849F09F4BB13
-:1013B000E4F91876CF0F992AF57BC0BA84ED8779C6
-:1013C000B7DE7BDD5807C0A5F54585F0308BF96B9E
-:1013D00031CF9A63EF8BFE90563410E71FA6FF754E
-:1013E0002467C9DF80FCC8AC47D604D00610E73BB1
-:1013F00019BE3E85FCBA392E1807F09CE5D6276049
-:101400007D96DE943FD511C1A7A2FEA7017E7EF98D
-:1014100053A88FFEDEA781BF3822F72F64FD8A44D0
-:1014200047008D8F2F1C0E0DF1B657AB3988E71E84
-:10143000673F6E263D31FBF1D4BB3B701D405F7DA5
-:1014400059D775D46599895FBADF2F7DDAC8B7ECB3
-:10145000E933F2EDD4C7369534DABBE7DB0AE1D7DE
-:101460004C78DC4CE7F82B863934DCB72C7AFC8FCF
-:101470001BE9DEF1A2B8C1787FA3E2712BE1B7DDF1
-:10148000E10838715F35D1A125632AE8616916E763
-:10149000B3B12AD36C8329A57B1B723FF0F092076E
-:1014A0001EC663A64758F0FA1100BFE3882880CB18
-:1014B00071796F2D6A7FB072F7F396427686FDC11F
-:1014C000B3EC0BE20D78E4DB73DD1FBC232B7A7FDA
-:1014D000D09C8FFB8F15627F70EC3A1ED7A958C243
-:1014E000DF65199BC2E3C4076A02F81832AE37E021
-:1014F000C47BD60F727D54C194A00DFE79C5BA4548
-:10150000F45EED1121874AF15DB501C85FDE5CF440
-:10151000EB673F1E4770AD7862EEFF3D02EDDA9754
-:1015200096B823FDE835821EA07F86F798653F5F59
-:101530002CFD792ECABFB1BF067F18EF4326B3E753
-:101540006ECC433C65E4E23EA6AC57B1EC67F9BC17
-:101550001EF8D3E03797AE54797CEA052BE9479023
-:1015600009E92CE23EFAACBADD16CB80F0FDB8CF2B
-:10157000208F4F2C44DC93B320BCE4BD2DFC4B1FCB
-:101580002EEC730FC91B7A6F7ABA49A1FB5D20E973
-:10159000E85ED4CB593C1EDA94C5EDDED25C2FDD7B
-:1015A0000FAABCCFEA5DC6CF2BB1CE7BF1781ECCA3
-:1015B000D4369BF62D7F6FA5384A555D9C1E97C883
-:1015C000CF536C1D40E7C6350BEEB778B85C795940
-:1015D000D05F9567CA15482F50FE9186E7D51C5CF1
-:1015E0007E56268BF700A1BD09C63986FFEACDFBE2
-:1015F000CD181831BE22BE433F9EC470BFBB4CAC59
-:101600001EE33458BFFF408463CAF5D3707ECFAA6F
-:10161000C4C7B0F8FB46A23DF8AC3A04FDE0D29551
-:10162000AF4F588BF92D83F046072B7DEE7DD22FDF
-:10163000F305FEDBC5B9B932C8E33B057B041FF9EE
-:10164000551E1FDA23E025E9409657AEE4E7A72AA6
-:10165000975BC9DEA95CFA21F55BE9684B43395D0C
-:10166000F98299EE797F28E65DB634A7E023A0AB36
-:10167000327312BD2BBE205062C1FC820685F2E19E
-:1016800076A9B948A75FD6BD9888F4B33F2ED41782
-:10169000F556C7A2382F9E5794F1B92FEBFA6EC0BA
-:1016A00038CE2C679B03EF6BCDBAADB70BE5FC5E74
-:1016B00067C882E57B9BF24C98D79DCE02CCEBDAD3
-:1016C0002594FF529C57A13FA41785E379C1E6D723
-:1016D0002DBD60BC1FC47ABF7AF6FD7CD46B95B972
-:1016E0006DF9A87F800EF2B310CECF28A4B7176E85
-:1016F000E6E7F8251D2C443A00BE9B27E860E1B6DA
-:1017000017EF407E5888F81FDC958E804E77D0F713
-:10171000ADEB2730DE7E07D289D47790AF33BB3074
-:101720005E27F2300EE64F213C8751F9385E1E18D5
-:10173000C0CF03B6D3F9C62A719FB3533E7583E772
-:10174000CC6CB17FB6D44AF236339BAFBB7DE50B90
-:101750008988C7AF9E7D7D27C6892BB78256F7C47F
-:10176000E00B01972A844322AD83EC902A5C7762D8
-:10177000180E9DF42FF8B18AF175CA755769020EDB
-:10178000B25CB4CFCAE6EB5CC004DCB65DC0F94F16
-:10179000F01BF233BDBB24D6E77719DF97D7C5FA24
-:1017A000FA8B7401D005DE5F63787D53CA0928FA8D
-:1017B0006ACB7A8A13497CC9794FCDF6483DA22776
-:1017C000BBC2786C37C57E5F7B54369727FB96F794
-:1017D000C86D06B87D09FE189D37007AD522C693DC
-:1017E0007423C71BFBDB2957E17AA1FF10F62FC733
-:1017F000DD1B48D0B09FBD8CF307D227CA4FC997D5
-:10180000636B675C3508CF4307BE72F4467B5BE0D1
-:101810006F6A367F0750473B01DAEBCD0AC5A9F75F
-:1018200009FF7FDFF21713CB22E0E413F3967486EF
-:101830007F18BF92F3DDE5E271DFE8794B3924E7E9
-:101840003DF69E1BAEC2EF72FE925E257D4A384A7F
-:101850003A95F703A3E995684DEA4FD520EF493F44
-:101860005E91FD8DC56FEFFA3D3ADF6937D5A5EF83
-:1018700088BCF7B65F9C77EF48653CDECF806A2373
-:10188000F48ED4F3117A65B516A157AADC3ABDB728
-:101890003367E8A27CD4632F64F37329475893A578
-:1018A00010FA5B70A86D42A2276CAF5EFA6D48C556
-:1018B000F76E166CE3E7D724DC171CDD41F45F29D3
-:1018C000EE6F95AE7CBF6404D2F9D366DAE72C5D87
-:1018D0003E9EEE69CFDD387338D211DEFB40B97E13
-:1018E000B871D810FE5C9B33ED7ABCFFD1F8C0F51F
-:1018F00037C1F759CDAA97E43BF4837C5B7AFB10A0
-:10190000A6D07ADB4B70FFB4E34ED58976FE988D76
-:10191000C3EEC6FA631C3D93713D7A630AE5752DEB
-:1019200089F483B48FE5B9BE5A33A78B5F67737FA1
-:10193000F5E1CE5411E7F96AF371FFBD637D1CBD7B
-:101940007335DD22EEBB6EEF417E489505AF5ED26A
-:10195000FD59B2C7E658982D839F0FB765C0F7DDD4
-:10196000E6B6DB518FECBEDD3188EE1FA83F0C2FB1
-:10197000E3FE23CDA324C5F8AE949CC71382DEA357
-:10198000FB93ED7789F3D9FBC5FC0FD73D7D3DEA8D
-:10199000C1C39BFABA70DD5F6C8FA3F771BE887A02
-:1019A000AFF37CEFB301FD46DD175B46F36BCAB6C0
-:1019B000F3FB5CC28E93F47ED6FB5C9FB8A3F6115A
-:1019C000CE7C3EE9680DA37BE7B7812D8EEDC72560
-:1019D0009C7A1ECF05CE6EB03AF1DECF01A477DC43
-:1019E000BF7A41E5F7936D9CFE0F6C1914447F7329
-:1019F000F627FC1ED68EFBEFA17309E5605FE2D1EE
-:101A0000CD4E7BF9C1FBAF473638EEF5AFC88076D7
-:101A1000C737F173145DDE77D8FDFCCEC8F71DCE55
-:101A2000D74E3E57FB58C6233EC936BE1F20E12A7B
-:101A3000FDA45701FF230787E1F475CD1CB28F8FFA
-:101A4000D6F8293DA6ECBB6F0CD2AD2389EE37BC8E
-:101A5000DCFC808AEFD1546E1BF403FAC5A3ED4978
-:101A60004EE4D7AF6B96D0FEE8D19A6AFEEE4AE715
-:101A7000BBCA414A2FDDD64AEDBE6E1ED282F78127
-:101A80005FB12709B91FBD1FC4F1D8DD3D67B9AEED
-:101A90002377727CCA791FD9343311D7D5FA584AC3
-:101AA000CB28C463429213EDBC0A714EE4E05A6E37
-:101AB000471FB2253D3909E07368DD3569F85E508E
-:101AC00079EBB5D7E3F7D9DB1527DAFFDEED531253
-:101AD000D13FFB5C6B4FC4FB5F9FAF95F7C682F4B1
-:101AE0007EEFE86246FB55A3431AF3E4D1D633D127
-:101AF000C9A8A31ADDCFFD12F7B1305EF2433CC591
-:101B00004B98D89F2A7F89C7593AFD59E1CF8D114B
-:101B1000EB1E91E392FB0EF47DEC48FEFD8B75CF3E
-:101B20004FC6FE0E379A9D38EFAF1BF93B16F3C038
-:101B30000FC3AB008736713F675E93427EF1E14D84
-:101B4000A0A7615D958BCC3ADD6B8DA2BFB1508EA5
-:101B5000E72225FDCDD38344D7D1EF8C24B326BA19
-:101B6000FFF663D1E3C539467FAD930EBBC3BF809B
-:101B700013F22DD2A1C4F3BCB5FC7D5B57D3A042B8
-:101B8000A42789F7E87B0EB51646F71902A6787ADE
-:101B9000177A8ADD635660FDD7B8DBC7A1F87C24CD
-:101BA00087CB4575AC49C7FB7AAC96BF63D0253E61
-:101BB0009DC3E5E89B398CD2B21C7EDE58DE5B9378
-:101BC000292C2487DE654C707DE7812AD7E46C9A46
-:101BD000ACC1FCA78C71DDDEDBCBD8CD39CF4DD6C7
-:101BE000806EA70C71BDD00BF2331EDFCCF397B81B
-:101BF000869921BF54F9DDE47190BF2B479F9293E2
-:101C00001A1E47F60BDFAFC5EF8752FC37E40C43D3
-:101C100039CEDF2D3BA6740C5C9217AEFF9EC2F648
-:101C2000BEAC84F3ED6646EFE594E1FC53BB4F3761
-:101C3000E4E8FE9C6131CA19A3FB6365017E1F08BD
-:101C4000FE7CB6343AA746F45426EF07D51BEF07BF
-:101C5000312FBF9F26EF6DC97B59FDC3F7CDD69DB0
-:101C6000CF7DB363E27E5CF4BD3FA585DF97AB0D0E
-:101C7000B0F638C243D47D9F04FE7EE3E217BEDA9D
-:101C800081643557DA2BA86C8787DF3960E9FCBCA3
-:101C9000C0ED820EBFA8617DFA002B5FDDD696E80D
-:101CA00081C91E9D1CCA47FEF658FDF508A72FD610
-:101CB000D5662F76E3FD58AB7712D43F14E4F74F87
-:101CC0001708BB9335A60A3E57439743BD5D79FD80
-:101CD000E99D8B5F0A7A3A9A17CAC577870279DC41
-:101CE000CF817A74FEAD78D915A958EFE8967BFAC2
-:101CF0009403DEACF8AE9F8B5286F7C5AE84BE4728
-:101D0000BAE8BD3FA6D2FE6E90FAC37A89A8D73D45
-:101D100033D379FC9DDF2F947892F0EF82179802ED
-:101D2000DAA5261B33E3FCFBB3754ED4C7123FF292
-:101D30007DDBC52FF038CA62A5BD2E05F3CF2A740E
-:101D40007EEE0B1BBF0FD455CF6DB420A8E7AC9B24
-:101D50006978C748BE23FB63C7835ECA11F7C20711
-:101D6000B14191EFF45688B6E3D5E91E7C677471F2
-:101D7000AA8DDE3759FC786FD2272C703BD181AC0D
-:101D8000C7D6A5107DACC85309CE739B19BD4F545F
-:101D9000D29C49E71D2735BB284D3C994EDF0F3FAC
-:101DA000F9D6502E7F381E4A9EEA41EF8A973C753D
-:101DB00041117F74AFCB3B49FC3D6DBB8DEE1B2FBA
-:101DC000DECDF5D2E2EB548A5332710FCC27A6E375
-:101DD000B3D7535CC7C762BF0FEC93EF03EBE63397
-:101DE000BE0F2CE16B15F8897E2FF8BADD43D2D1F6
-:101DF0005F95EF05CBF708DBC47DAFE87783EF494C
-:101E00009C40EF064FD3B91E897E37580BC479D159
-:101E1000BE3567DBF9BB16FEE87784DB355CF7F58A
-:101E200005FC1DE1EBA619EFD3990BBE21396D2EF0
-:101E3000E8F28E9219E9DBEA33D6FFBBD42FFD59C5
-:101E4000FF33BED39C6DA1F7F0347CC71CF2D78B57
-:101E5000779AD18E43FBFCB8CEDFDFB3C6F375B7FC
-:101E6000B1A1E9C8F7FFBFBF4F7EB677C9A3DF2195
-:101E70008F7E7F7CC8AE5F1AF2C3DA1E35D41FF1A5
-:101E8000D10643F9A8F6670CE5630E6D35E42FED36
-:101E9000F883A1FEE5275F33E40BD95B86FA636D17
-:101EA000EF1BF2E39D7F31D4BF227DBFA1FC4ACF5F
-:101EB0009786F289FD4E18D7A3F927E4223F7BFFCE
-:101EC00069683799797E81EF7BDFE036D1BB26C523
-:101ED000B946BA1B97C3E30AAC0FCB45F9355E9DF3
-:101EE00044EF241D6F52F8FBD2DDE8B124B0F7B403
-:101EF000887192751B3882E17C4AB1D3904FF5A569
-:101F00001BEAF798E6319467F8FB19CAB3E6780D37
-:101F1000F99CEA9186FA3D97E8867C5EA0D850BF8E
-:101F200077BDCF90EFDB30CD50FF82B57E4379FF98
-:101F3000E01C43F9459BAA0DF98B9B9618EA5FD2EA
-:101F40001C30940F0AD51BCA87EC6A30E487B5AD04
-:101F500035D41FF151D0503EAA7D93A17CCCA1264F
-:101F600043FED28E6643FDCB4F860CF942B6DB5062
-:101F70007FACED3D437EBCF3CF86FA57A4EF33949C
-:101F80005FE9396C285FF0A597EE4BB397F97ED8DF
-:101F9000C47EDF18CACD6E46EF6057B2782FEE3B95
-:101FA0004ABBA6C4FB7743BF4FE6F2380AD0527B48
-:101FB0001CBE1F19F051FCC7850702514EE13D754B
-:101FC000173F4F339DE2486ED26FA48A3C78BE071C
-:101FD000EC8044F4AEF2F2D04E4E08DB63D9A72376
-:101FE000CED79DCD1EDB96CB681EFB73FD4FE7A6BB
-:101FF000A2FFB16502BDFBCE022B701EF23DC07781
-:10200000A2DEBB96E995B6432CF25DECDD710DD9ED
-:1020100083CFE0BF5F693BCAF0BDEDCE7E45BC42D9
-:1020200081F52D8EE8FF3EF017B43E8C35D400FFCD
-:10203000808DF4CB1A27E51FAC49A7FCC3351E4A97
-:10204000D7D6F4A3F4D11A2F95AFAB1949F9276A63
-:1020500074CA076B8A29DD50E3A3EF8D35D328FFBF
-:1020600024F8C5986E023F19D367C0DFC5F2CDE0F2
-:10207000FF62FEB99A00A54D35F5F47D6B4D03E581
-:10208000B7D5ACA5FCEF6B829436D76CA2F40F35B4
-:102090004D54DE52D34CF9576A42940FD5ECA2FC52
-:1020A0006B356D94DF51F311E577D6B453BAABE6D7
-:1020B00010A56FD67450F9DB3527297F54C45DF71E
-:1020C000E51AF723645EBE5B21EDBFC968BF2371CB
-:1020D0008C347F6DB0DFA3ECE8687C1C11E3E03B3F
-:1020E000BD43816ECD99F91B6A23FCA7AFC478F27A
-:1020F000BD8AE8772798B04FE5FBB0F23D8BD962F7
-:102100005E1582FE87217DF623FA7CFB7CFC05E9C7
-:102110000F5E9BEA3F45F499630A903F6CE7F791A5
-:10212000EF48F5B39EC370DFB07C278DE7F4D2FE95
-:10213000618935947AC3507A079EE272DD8D572506
-:10214000CE89775BFECAE16CB4A78BFFA5D27B6416
-:10215000EF981DF4BB97293D395C527A9A0CE93F00
-:1021600053FDAE9E907EEFA8BEC504F3FFFEB245C0
-:102170004FFE242FEC275F8DAE26F8375398C74CBF
-:10218000E71199FEC73CB49BC0B0C2FC0D2C40695E
-:10219000C0EDCFC275DD080637E6FDA3ADB9B1D6F7
-:1021A000153DAF7C31AF7C311F99F64FF3F7C5FE7B
-:1021B000BE77E834AF77465D918FEB92F39A27DED6
-:1021C0009D98CC3A9EC0F97DBFFD9B834AEF30FCC1
-:1021D000A53F4EEF02A0BFB34811EFFF75797F8096
-:1021E000CAA7DFAE907D3603FC19DC2792EF0D1CE9
-:1021F000AF36937CC4F709701FED78F5E776246756
-:10220000A8C7709FA3160FF64079EDCF15A2AFE9CE
-:10221000F88E08B49F9196C7EF4B339B8E7A787AED
-:102220008B753DD2E974B0F7D07F02FA2844B8CF5D
-:102230001BA5D27DF5774CC17C85F693CB2D0ACCBE
-:10224000ABC2ED35FC8E4434FE178AFB07F23BD05F
-:10225000D54484D7D72F8DE847F1F7574679104EEC
-:10226000B5267EEF28F0A62A7EDF8B8B6675CCC55F
-:10227000145F649AD78B71A212714FA555654B629A
-:10228000BD1F5F29F0F44E3A7F5FB0366A9FA5BC50
-:1022900027F72FCB7BF2B873C96BBBE99DA585BB34
-:1022A000F87B906C68FB80C877793AD7B3E4CDFEB1
-:1022B0007D22D651D5BC8F9FAF60ED0322CF9FAF5B
-:1022C00010E34BFA512D0EFF7A7BE4FC3AE97901D9
-:1022D000D17332D0736FA2E783B8AF38D9EA49BA65
-:1022E00041C15FC7635FE3FB47FE5F3BE93C913C55
-:1022F00057348BF928AD00F423FDFA02F7D37BB7EE
-:10230000F358137D5F387226FD3E6D15EB18970E5E
-:1023100070BBAE7EE91FF1B9C06B1AEE1F8F71D58D
-:10232000A9C1D23F623AA5513988FE29F0C3CF1125
-:102330001FED4AF5723CC279D3E6C2E5B83538598B
-:10234000E5F8606F717C00BDE8AAABEB3A81FE97BF
-:1023500013FD27EBB40E35B1D840FFD397315D7133
-:1023600087CFC777F2C3C8F97FC52D60A675D0BEE9
-:1023700079D52B5617E2791EE3FA3A6CFF493DCD29
-:10238000F5FF7CD0FF58EF88A0E723398CEE211CA5
-:102390005118DD6F97F623CBF5A70FEE1DD6B74783
-:1023A0004CC1E189BD491FAFC3F9EE4CBF86DE0FBA
-:1023B0009AEFB6D1FBB0479283B951EFA1D07B4DD4
-:1023C000327E759F99C793A2E7A58CDCC97FE7C4CD
-:1023D000C202B82F81BFF33D1CF938D3427C568B23
-:1023E000A0C5385891CF13ABFF3AD1EFAE53DCCF35
-:1023F0000DE4F0774BBA8CE314E3C4F371A4DEE888
-:10240000FC5DF13466186F7BCF3CCE070E9DE6BFB6
-:10241000D4944C7226C3E66FC1F5CB788EF4FF7668
-:10242000E57DD187FCF41F6AE93D267ABF00CFF530
-:102430005CC6E5D13B660FBD4BFC4E611EC5EDA5EC
-:102440009CBD7A248F7B5D2DE35C055171AEA8386D
-:102450000B2B881DF762CC6BC671FBB34F247C2815
-:10246000BEF25A8166F83DB1D784DF79BCD83D947D
-:102470007E2FCAC3CF5925A6F0F7463A1C2AD1D9D8
-:10248000EB01AF1D7F9F6495888FAE8E7A177CD548
-:10249000D0C54E3C176075F0F73ED714C5CF893CC8
-:1024A000BFEECEE7EFC33C995F98E18174803D5861
-:1024B000446A59D73C387F45ACE72227C0DB84F615
-:1024C000A64FC439E5EFDC8C23BD2CF17CAE7AF944
-:1024D000192DB82C1ED7EB66C4778EB536929F6A3D
-:1024E000931EC2A3D4B3F2A71E47B9C1345F3F1CE9
-:1024F000A775783CB343FDEF5B2D147F7AC554F686
-:102500006B7C97B8E3CF5686E71C9A1C591A1AB70A
-:102510004DA72E1C47A963CC04FE3E274BC0774431
-:102520000739D96F7E874812F7C92CE9CFF80E809A
-:10253000DC6E52D82EFE0E979E80EFE13599D88939
-:10254000CB617EFF0FA64C086300800000000000F6
-:102550001F8B080000000000000BED7D0B7854D5A8
-:10256000B5F03E33674E66269370327930E40167EA
-:1025700092C98B4CE290F054AA93106840D0E15578
-:1025800083243A58F446854C8AB445AF5F339000B3
-:1025900001F42FA2B548BD7640A568B50D4A6D6C13
-:1025A00023770242B197EA606D8BBDB57FF0F6F7F5
-:1025B0006AAD12C47AB1A5E5AEB5F63E9939930974
-:1025C000A2BD7FFFEFBFDF8D1FEEECB3F7D98FB554
-:1025D000D77BAD7DF28CA3F6FECB18639359C0CCAC
-:1025E0004A18D34A838A96CBD854D641F57B954076
-:1025F000DBEE1C289D565F18FAD58E33F919D4D915
-:10260000C78E48A9C458E0986C313B18EBF3041D01
-:10261000F8DE05FCB90A9EBB4C16C5CBD84685B57D
-:10262000F54299E1B3336665F47301FE05CE953149
-:1026300056C7D858CDC4D814C6BA5DFE985F8ABFB5
-:102640009F5C32551E1AD4DF2FC6FF17AA6FA58BC9
-:10265000BA9931AF23D22061C52F6BEA54C6E8770F
-:102660008DB12A95052D30451A0B30DC0F9BEEB34A
-:1026700006AAB1B1517DAB02FBF9A50BE9179997F9
-:10268000C90CFBE9F3FC6102A3F51EB267D6B031B9
-:102690008C851BB4FB1A2743F953B3AF8B7AA993EC
-:1026A00071FCCC6C1635C1F3A10C73648F9BB1C364
-:1026B00061EDA95EA81F96AB088EF774C266000490
-:1026C0005B3BA1A2C4E7DB3A798DAA013CD332CCB3
-:1026D0005F3A8C702E32A9A5B08FCDF3ED4D1180ED
-:1026E000E3BD0DF6362C73CA2C8C01BC97165B68C3
-:1026F0003D7BCBEABF5D0CF5564760B6A47138B0A0
-:10270000BC381CE001E3FB0D32DC6F8BCA06A5442C
-:10271000B830804B06DF00BE770DDF32BB4666E186
-:10272000314EC65E9EF1F663BD304EC64E587736CA
-:10273000BCDF71460EC23AD8F90B57D901DE01BD94
-:10274000FF4C89BD9978CEF0EFCD0AB13F37C15328
-:102750007D4B6F375F3ADC2D4BD6573058EFA64E86
-:1027600017C1AB47F2F9C7C27872C7A93BF0F94667
-:10277000193A02BCC25E25F238CE23072A703FFA0E
-:10278000782BCB1A6ED0004E19D3FE907E0BF4FB43
-:1027900028CFA42170366A377DDF8EE777329DE13E
-:1027A0007B99D9B1B647A17DE8F572B60786F9E8FD
-:1027B000D6E00415CE630B9CD39B1E5C4D64AC69C4
-:1027C0003A9683634D2E02AE8B9741177FCE447BA2
-:1027D00084EA6FB98BE99C00FEA2FF20F5DFA26CB2
-:1027E000B7DA711EB755DD9380F7579959472FCC4B
-:1027F000F775A40B7CEF7C97B63003EB12D5EFEFA7
-:10280000DC19F89D07D713A1327B7E840501DFEC2C
-:1028100015612D0CFDAC1B5810DF4F86E7DB6E9960
-:10282000DEB71E7A8869D02FDBE39382D02F673E14
-:102830008CA7C399D1B987C7D442BF3D80309311CB
-:102840003EF64838055D5E93DB704CCE1CFDFC9275
-:10285000F180093CD0CFD3FA577310F902632E13DD
-:10286000E2DB5A2BC7D3C6622BA379D729BBD3602F
-:10287000DE27B42C5AF787390D639877F4F91E8157
-:10288000F309033D4580AEB0DCD3A9B230E0C963A3
-:10289000802F58DFDBA951B9AFB382CA273B7DD463
-:1028A000FE54E774AA7FAFD34FF5DECE26AA3FD3FE
-:1028B00019A0FA81CE66AA3FD719A4B2AFB38DCAC8
-:1028C0001F7576507B7FE73AAA5F9506E786FBA9DE
-:1028D00008BB16C179F4DCA9F83580CFA038C7C38E
-:1028E000FEE26C1F9CB7ADC2043407E5F11D0CF786
-:1028F000637399FC1138874DAE1DEC8B505AA66658
-:10290000F448C057363EEDE8918031DBE4FB19F224
-:102910008347A4701BF331F693483020CF60CCE39B
-:10292000FA528313EA3F8BDCB2DD0A785BA62D6C8A
-:102930005E9F50D7326A6FDBAFC6EB13BCBB653B03
-:10294000B4BFAADDBA3D47E2EB60F98CFD26727B8D
-:10295000603DE051B4988511EE436E2582F8B812BF
-:10296000CF4BC6F5ABB4FEAB5997CB04EB9FA02978
-:10297000B54837D03FCA722EBDFFA0A6D1F3E4F709
-:102980002ED6CF34F992FA31F345C6C376E922E365
-:1029900058A5C5D618AC7D9B45F08F5C07F18F1EFE
-:1029A0000BBB310070EFB1F1F2CA6289F8ACB3B879
-:1029B00061B71BE6DDEDE672ABC716561B70FE6A0B
-:1029C000930FF9055BE7FE7931CCF7959FCA6CABA5
-:1029D00016C7CFFF1078503A2183CBCF7FB4464A39
-:1029E000619ECF4F78BADB09F5D2477D3E33F4DFE5
-:1029F000C67C76C493F03D26F638D4BF3BB9C4B943
-:102A000010BA574DF98113F9ED5237E70311C69A01
-:102A100010DFD66FBC65C220941F9DE07C4A71F325
-:102A200079765B621D749E531C6C0F0981EDE9C8B9
-:102A300077D6BBE090A631661AC74BC5A25E8FFD64
-:102A40001410D461588FF29769D6008CD7752EADCB
-:102A500009F90863B174E4638A2DA866C1F3ED61D6
-:102A600013F1852ECD119160DC6D8EDA631AF24F71
-:102A7000D5E42B45387A4D04C76EC7172266E4CFDC
-:102A8000D2FA36942F11F519AB1B9E47BC2615E9D7
-:102A90003CE25FD484F57050F6956A8241607BD049
-:102AA00019D98AE3B2A17FB90CDB5B980FE1B03191
-:102AB000EF4F87D2A1DEB554F599796F4D06B93342
-:102AC0000E7F8329BB2C831BD2711DCB787FF8CD61
-:102AD000B710E5701A3FBFAF0FCC558B49EECB61F5
-:102AE000A14748178010658BCFEA83F61A476D938C
-:102AF0001F4A39A3D6AAC13EBBD55AEB0ADA3F73A7
-:102B0000803284228FF853976A22398CED5F447AA1
-:102B1000EF662F7AF28894A8BDDBB16300E121DF74
-:102B2000CC985BC3F5C17C3ADF0378584B661ED363
-:102B3000601F3DB738691FB2E4A33ABB59A675E7D9
-:102B40006BF628AB013EAF2C38C6807FE45B6F9FED
-:102B50008FF5716DF2EF0613F8F4D8A0B19EDB6C1F
-:102B6000AC6733A85BE3F32E7273FC4D865B323C9B
-:102B7000C6A9DD2770FDE382323D4C5EFF43EA03C8
-:102B800059F50CD7E9A075E6396EAA070801CA0500
-:102B9000D623FEFDADEBAC511759DD307F4D8E894C
-:102BA000D496CBD8D0061C779BC0F71E373FCF38C2
-:102BB0005D9975BADC8A7439619D898513E48E3B11
-:102BC0006C67E184F94A7A9C867AE9F67C43FFF2E5
-:102BD0009DC586F6CAC844437BD5BE5A43BDBAF7E5
-:102BE0007243FFCBFA1A0CF549D17986FE75C716E8
-:102BF00019EA5362D71BFA4F3B7993A17DC6E06D6A
-:102C000086F62BDE5E63A87F6EE82E437F5DDF4E87
-:102C1000968FDD822F7C5A3D3BCD05989D305FB26B
-:102C20001E9FAC875BFFDAA56D407CCE54089F6584
-:102C300094E7505F73A7124943FCBFD2A7217FB925
-:102C40004BE0A3B7DC7F1F9E5B7DA695E482ECE0A2
-:102C5000FD64C71CD253C6EF04BE54875A231B6EB3
-:102C60004F47FEDC190E783CF175DBD4ED0CE9B76B
-:102C70003EB3890D3AE2EFCBAA9F0533703E8DE655
-:102C8000B3AA61EA67D3E0FD847D1D34999803F906
-:102C9000F88042FA7A6F46818CF4D7FB97898D547D
-:102CA000665C3107F17D92CA1EFD3EF4EF95D83186
-:102CB000067A52AF899D059D8D3D936447E9F6D311
-:102CC0007813B363B95B1ABC83A19DD271A2612C46
-:102CD000233BEB59DCF7BDA043E0BEEEADE17AD675
-:102CE000C6BC791AEA653DEEDE63C5B89E5C902BE2
-:102CF000480872C0877A85BEDF37C479CAC53D836C
-:102D000028FFD6645935D49764EBF6C0EF005E8F88
-:102D100058069FE8827AB7A4AE42BB237CA7C3F7CC
-:102D20003843FD91C34DCB30D56D80717BD7FBE52A
-:102D30002C68EFDDC27CDD481F39F51BB2E07969F4
-:102D4000E10A9313E9C1B37E0396AFA01E0BF0AB6B
-:102D5000F4EE3665437BD5E4FA6686B25785F9B260
-:102D600047C72773E64E86FB611EF92DC42BD4BAE4
-:102D70002FC0D2EB9D70DE30AF0DCF5BA292E06032
-:102D80003BE788D8B0EEE170B1F9A5483AD4733C7E
-:102D90007EC9EFC5F776D2F9DAA2463D16ECCF37F9
-:102DA000DC53509F359EAB6C7D80D6B7CDC4E9A275
-:102DB000274B3B8EF2B9C7ED717669F175EA7CE578
-:102DC0006D618FEACF75BE723DDA1453E2FA0DE001
-:102DD000F94E5309EA67DB19F227DBDDDB19E2B5AF
-:102DE0004D0D6B0CF5F0AF8509CF75FDF60E413337
-:102DF0008DC5CD5694D767736A499FB5ADDB4BE758
-:102E0000950C37DBA089F92F02D7CCB25D24DF8186
-:102E1000016B68871FCA73B4ED4EA1F76FD0389D60
-:102E20006D01328E79098FACC8AF2DC2CE004C3007
-:102E3000A17C3BAB326E27F6BAA97E4716AFEBE317
-:102E4000DC915B3BF662FAB70DECC260C23EB6C0E5
-:102E50003C08978DE71736215C994CC4C1B6FDC577
-:102E6000BB7B2BC252D8351B04BCBFAE71F88E574A
-:102E700018D905BE9CF94D24FF5C4FD2F905CE153B
-:102E800093109E56EC24F883116DEEA0F55B74F957
-:102E900064BA7019AD595360FD05F8A4184B2EDFC4
-:102EA000A0CBC00509F97F823CE305C9F702FE3BD0
-:102EB000C803637BF94E63BD3292F47E98BD86F2FF
-:102EC0007F25E3F0AADA676CFF16CA71E01B2B8539
-:102ED0001C67DB2D24EFACB0A20B5CFEC6E521F035
-:102EE000876B7A63F5E9304ED1748B414E1624F628
-:102EF00003F8D5DE6A0AA0DDA0FB5F74B807DA4CE0
-:102F00001685E84123380D3F17FE9664FE3D3E8D41
-:102F10009FCB212523B2C1CDFD12C1326E6707813F
-:102F200024EF957DBF6A417BEC98D907983D7C9E44
-:102F3000C9E7BF6F583F0ECC2F267B77B00EED6FE1
-:102F40009C2F98309FEE37292C0F2E2A86FE1F3497
-:102F5000E54CC6734A2B6416A463DD2FA2DBF9BBD4
-:102F6000115760BC6DBE573B0EC33A369F4C239F32
-:102F7000C66CF3F1639D505F532413DF53A7ADFA82
-:102F800036DAD30DFF0AEDF0CE664D1B4BFAFC315D
-:102F90000BD9F50D02DF1B849DA6FB4F6E2BE6FAC5
-:102FA000F42DA28437ECDC4E8FDA51EFADDA073C1A
-:102FB000DB882FE9BCDD4F7A71756F72BB9F21BD35
-:102FC0004F14F80075473DD427897A2F93B25538AE
-:102FD000E7CB9A070FA1C9E17DE9881DF5B0FD3661
-:102FE0008E1F4F0ABD2F8F49BE28AC3F6F9FC3175E
-:102FF000817E1966B63F06FBF0BD28BF399800CF29
-:103000009A7E63DDCB12EA6E5C87B17E8FD621217A
-:103010005CEE690154842D6F28CEC879AB8A21CC2F
-:10302000CB10FF669B1D93D0EE5A53EF6008D7B4C8
-:1030300053E5DF8C219F396166283FD474EDBE468D
-:10304000785FFD976CDF7A2D7EFE4F76228B67ECE2
-:10305000C10B3ED6ED89FBA99E82F34479F33DB0C6
-:10306000C7B1BD17CE15EBCF803D8EE501B0C7F1DE
-:10307000F973608F63BD0FEC712C7F04F6383EEF5F
-:10308000077B1CEB7BCBEA1F4CF66F25FAF9E2FEBF
-:10309000AD4149F76FA5015C1BD04E9C92E0E70A59
-:1030A000723FD7278FE3D7C721FFE1887186FD885C
-:1030B0005615FD27C5F0C61878FEDE9DBFDE8B7263
-:1030C000658114DC87F8BD7ACA9B0AD7B38714ECF4
-:1030D000FFB00DF01FF854E128FEC32B679DBA2303
-:1030E00017ECF41F15B72E443BFFCADB4FD58D8775
-:1030F0003A2B39C6EBDF39F56C01F0EA5B4AB6F0E2
-:10310000FAFDA7CE1642FB18F6ECC2C619E47724E6
-:1031100039F6B0C49A13F5C09F08FA0CADDB41FC38
-:1031200014E400433874E505488E9ECE19CA5C014C
-:10313000FD43B94379375D84CF87D63D48F2AA2B4A
-:10314000F3F7A4A7740DCB151FC9157D5E5DAE7C8A
-:1031500020704F972B6B6CBC3ADC2F5842CFEF1787
-:10316000FE1F1629A57AB68DD7FF5783F60ADA47D0
-:10317000001FB2870F674EFCFA4CB43F9B645F1A86
-:10318000D4EF77D4DA502E9D15F40BE386D1DE0F01
-:10319000CFB6461EC743CDD1881E9DFAF8391E54BE
-:1031A000CE9853ACE3C5CBED51F40774355AF7A074
-:1031B000DEB9C3514CE3754D57C2E887D1EB1B2EE6
-:1031C000BFDC8A7A4756A6D38D759D3FE9FE5BF832
-:1031D00031E3B80D62BB0D5647D49C89E861F943D1
-:1031E000A23EED6031C21F9F090C17A0B7AF9570CA
-:1031F000BCAA63BE667CAE481D6144C68771EDB84B
-:103200008F0CE1CF44093535611FFE02BE2F7D1FB3
-:10321000194A58EC83F4A91D0E5314F5C21DB02FA2
-:103220001CEFDF8B35824FF2BE18BA6861DC59D3D0
-:10323000C5BAD59907701DB34DFE6E7CEFC8C72D7A
-:1032400039887E7358878CCF4BC0F245FF2DA07410
-:10325000F7858BE827C9FEDB2BFF4DA2FDB0DB1500
-:103260003A17A58CEF7B97127133328423E31665EE
-:103270008C8EBF2525FC7CE3F8EB67484F5D4E3F05
-:10328000C75F7528733DE26FD650DE06DA5734E526
-:103290007924E371F2F9D4206D73396046F87ED257
-:1032A00079EAE7A8E341B2FCFA5A89AA9FAF8BF604
-:1032B000E9AFE074A0EB5B0CECA18C91F0DB04E3D4
-:1032C0006965F1BAE20A901E6DC9F155A09FB7EB8E
-:1032D000AFE6B6547EDE1B049CD667DA49BFEECA61
-:1032E000E4FAF540E63C835DD408769204F861CEBA
-:1032F00066BD4847E631D7939FCC3C1635285C57CE
-:1033000092DE3A663ED75B55D05B53CCAB9732EA40
-:10331000AD29F4D961BDD5398FEBAD990AE9AD0F6F
-:103320006728CDBB53F09BA9255C2F1CC07DA4B0A2
-:103330000BC11E247FA56E0F2A6A90EC3A7D9F5325
-:10334000055DE9FDD3D40E86FE33B3E2D3502F35AD
-:10335000DBB99E9906DBAC4890DFFAFC934A785CB7
-:1033600025AB9CEBFB262BD74FAE7C45EA4805F7F7
-:103370005089EE5F498D777F03DE105FA875287E48
-:10338000D40F6A1DAE06D40F467B0F4CD2F0DBCEB5
-:10339000385FF1FD75AA99E48FEC73219EF55A060A
-:1033A0009F7D05EDBD230E9237BD1985349EAE5F1E
-:1033B000835D1BAE8041F6FF1928D134D29E053BB8
-:1033C0006B4B09C6BFD6E44DE6E3829E573D52AF34
-:1033D0004CF61B0CD37BE65E377F2F320EDF93D685
-:1033E0004C1F8B78954CEF7A59E4FA69D14A5857BB
-:1033F000D1B86354EACFFF8999C90F97DC3F327C7B
-:103400000E5C2E57C26463CC248F23B8EEF7D6BE71
-:103410009AE783A5B4CB67482E7FD0317DCC668DEB
-:10342000F3DB7D2867BE2413BF2DBC7520CB9970BC
-:10343000CEBB3AFB8A640FC61762458D1EF2F7F9C0
-:1034400053ADF7B83E7F7402F1678BC0032D27366A
-:10345000B71CE0AE394C3E542540F81AF840BD9CEC
-:10346000D5A8C2FC459DCCE780BA9BA9E4F72ABA4F
-:1034700060267C2B3ABC8CF07842CE9014F626CC99
-:1034800083AC38217EF2614723D167D1D8617B8F2D
-:10349000E20C1FE64417227D7FF8005F51D1A3C6DE
-:1034A0007690B1E497BE65AD3D8226E384BB5513AB
-:1034B000D68BBE2DB14237AEE3B07B33FA757E9822
-:1034C0004E7E1DF34E0FF965BE2D050F105C23DAFD
-:1034D000574C2562B3D06FF557ED7BB6921C8BCD60
-:1034E0002539F665137B3C85DFE9E725DC8FF19A0A
-:1034F000C0F722D7CB452BEBB03C4EE77DA9F4C4F7
-:1035000004DFDE3C663BC5C5C20DAC02EDC31E0B3D
-:10351000E0550A7AF57B387F19E6C7027E36B45645
-:10352000602CB324F4BC7D4F3EF9641ECA6D46F690
-:103530006472BC36BDA2971AD37D7E86FE0949F51A
-:10354000733EAB865D618C03FDC59C12AFC77804EA
-:103550009F766F7261FF468FCF857430E09EEABA26
-:1035600009E0E770282C2D810FEB78F262C654D267
-:1035700043F471D664145FD42E57801F6B1791D318
-:103580000AFAC7519F3934C3AAC17A37396A63A886
-:103590006F6D72E4D4929FDD017C23C1EFE4701C57
-:1035A000253C74F8B83FCE81FC17FD4E62FF03EE58
-:1035B000A3B47FBDDFBB820F397C511EA7046B060D
-:1035C000FBD9E44018ED0C5B0E23BBD266E5F49406
-:1035D0000EC7614DE023FABCBF2BE1F6DAA6C2DAD2
-:1035E000583DAD4F46CF01DBE4AA75913C4438A36A
-:1035F0003E3A6E581F25FF4AB180B33E4ED700DFDA
-:1036000067609DCBDF988D7668C0E5C1711D375925
-:10361000C3281732265F743CAF4732F887E2E3AD28
-:103620009B25C62BC6F1CC19B52A8E67413E910267
-:10363000FF6688757D56FF19405425BB8D71FD0AC4
-:1036400030DE954A8FD04BABF0838D7C8FF349B73A
-:10365000B05F804FCEF6A0DD52F8E6D17AEAC5ED34
-:1036600016E75CB94286F3FA004ED02CC5EDF8643B
-:103670007DA6DE3C44724D9747BA7CDA85FA8C12FF
-:10368000A7A77CCEB958415B80E4B6941320BC0157
-:10369000FD4643BA31637C3805DCB608F84B99D354
-:1036A00035A497C6F38305F8DEC18CB70B5882BFEB
-:1036B0004DE7872F7EBCD786ED1FB6355C546FD1A2
-:1036C000E3C7A3C58D33EFFAFD9712F596D1E2C893
-:1036D0009F143F3E94A9909FEE11C9C897BA043F2A
-:1036E000FA9AC00B6771F02B88478F48011FE98D4C
-:1036F000C29FE22D0FDE89E733BE47616138CF8379
-:103700001F4F75217E5C2A7C753F7BBED0A7F21DC2
-:103710007B25A4D3FCB688847EF282B65EC97F91F5
-:103720007E8B3C9C9EF5FE1631FE55F29019E5D538
-:1037300055828E0BCEC9AC22410F5CE0E1FA944574
-:10374000E8EF99879EB0E178874C819E32940F997B
-:1037500026EDF1047AB7DC5A6B6D48840FC67F52B0
-:103760009CDF773DC37A17D947BABCB5E8722247C8
-:1037700036C889503AC75B5DDF095DCEED21490A45
-:103780003E86F03E7DF9EFAF4196755AEA55304ED0
-:10379000FE49F18F61BDC61459A1DB31482F3E5956
-:1037A000FDF120BC3FE93BF5440F535890CA698CAA
-:1037B000EB7DA0473DE321FD0E969C70BE0C5D0F96
-:1037C000799FBC8F473C5CDEDD2BC7C8CF7AEF7991
-:1037D00089F878327CFEE8D1FD5AC371BE8BFA4974
-:1037E00035F493BA316E65F463D61D33D6A7C48C15
-:1037F000F5692793FDA2FE5F24FA451F06BA427EB3
-:10380000A0FB410BC3917A15D65BC47A296E58D0C0
-:10381000E634C0F54AB3C8A7607E29D13F5B202FAC
-:103820007807DFFFFDF0B98749CFBA45B4FF43E31E
-:10383000CAAF74A3ED3CEC67D5085EFF3077D16C5E
-:103840003CD7647F6B514742FC918DF4B3DEF2B0FC
-:10385000C5D01EF04F223B60F112A37F96D691CBCC
-:10386000F75B503B72FE4F9E17FE3947CEAF8FBBC2
-:103870000BF80DF251761ECE752AC28DA1C78115A7
-:10388000C95109E3D7F91DCC8FFA70C15AE64F151B
-:1038900007282CE578900C6716BE8AE0374B3CCBA6
-:1038A0007798C94ECF5F6B223D301FF801F2816BD4
-:1038B0005601B940BD6095467AE4B56D26867280A2
-:1038C0009DEF34BC0FCB257FA77EEEBB703CD4238D
-:1038D00057B38809F7D33191E889D6556CF08BBF7F
-:1038E000C9E16525785D3BDD62F06B16A11F3301F0
-:1038F0002E3A1E14243D7FC1A31AE802E45961291F
-:10390000E13F9773A528E76049EFCD38B917F3D9A0
-:10391000AEDCC068BF4359F608CF93188E27982FA6
-:1039200094037FB2CEAA40BFCA36D56EC27C8683CE
-:103930005983DF62598CD594B270E34CC6FED93EF0
-:10394000542541FDF2D24777F4C0A11CB40D7D1778
-:103950009DBD0EC7938B9A3E17AF67661EA43A9B18
-:10396000CE3419E063C719609F7675DE3E33CC6FA5
-:10397000F73AC8096967C3744AFBE9BE5CBB07F341
-:1039800041BA4B4DA427B1C476D8C7774A553DBF3D
-:103990008CF2DD58138FEF278E2FE75C64FC7930B3
-:1039A000FEE44F31BE95AF3F0F1F817CC9C3F5A325
-:1039B0009F1AC7C7F3456751E2FC623C998577635C
-:1039C000FC05E673487C3E15F34DF29831BF6078F4
-:1039D0003E15E6ABFE3BECA779E479582E761ED770
-:1039E0007FBAF3E836F969BDE11A07D93F0C9A4D61
-:1039F00053D1CEE0F3D964F6A25CCBE1DA3D350ECB
-:103A000057D0F7685CE8BEFE8280B305E1AC2A04BB
-:103A1000E7D1E07648E5F94E5B547B64BDFBFFC11E
-:103A200079B9F87925CE877AE325CF773DCC97739E
-:103A3000E9F3217C917E86E10B67B221EFD2E10BA5
-:103A4000AB0A5F0A7C0FC1B8A604B8C6F38A1E523F
-:103A500051FFB75902561FF0DF03A53C5FD19BB35E
-:103A6000C84A7906B98BAC98BFB7D1EB68C278DD8C
-:103A700046CF12AB25414E6FF4B6503BF4A77C28DD
-:103A80006FD48EEE0956CD6264FF6F99D9E85A81E2
-:103A9000F8D3C1F3ABF47C235D1E3211BFA47DC10A
-:103AA0008B633E7760E810F4DFD23199F2C9C664C7
-:103AB000FD89F2A8B6B5F97CD8FE2D8C33813EF194
-:103AC000A0883321A2921FADE6F247312E5B5BBA8C
-:103AD00046C2748EC25546F9949F94A7537B26D64E
-:103AE00080F9586C05CFB772B5C849F2D048B7DB3A
-:103AF00010AE3C2F2A2271F81AC6FB3D32E95CD485
-:103B0000EFF730B4EF9E85B1CC46FA32617E523287
-:103B10003DCA8A5FAD47BD7C8D89D65180217F101B
-:103B200071B5D5F35D2BE079E1CDB24F82E763BD8E
-:103B300077539E1268F5A46F78BDC71BB03E629F95
-:103B40002B8DFB48DE57F2BA4170911EA29F57EDB4
-:103B5000195F3ADA51B5A58B288F8C7E747A372796
-:103B6000ED271BED5F93DF0672CCEE49D81733F4D7
-:103B70001376DA7F6DFD242213D25172FCEB6B01B8
-:103B80005A671AF359157AAF85EC453DAE968FB456
-:103B900083E73E9EF1B844F2FB53F9FBCCC5E36CDE
-:103BA0006976303D81FEA4DBECE4BF4C4B833A9C4C
-:103BB0008FA430EB3878BE4BF8FDD64B4CC67A7CE0
-:103BC000BE28E5A9774981ED3E3796DC5EB26405F3
-:103BD000280F11C3B48976E721CCEF80F635B7BA48
-:103BE000C7A2DF6E0C10440CED661197D2FD24992C
-:103BF0002583CB517E1797952CB6A27C46C7D2E57C
-:103C00008C5DB6B7E8FEF0CC385DA69DCB675A82D6
-:103C1000FD922677509E47DAB9F1067F4A54D85D67
-:103C20007ADD9F2337E27C73D02EC0BC26A676E3D4
-:103C30007BF500142DD13F7ACE6518273E7EA16119
-:103C4000DE28D8CF897180D1C74F675A45E2F8C5C1
-:103C5000A38C5F9634BE9A72FCF8B8D9867137CAC5
-:103C60009C5F8473EC9154FEBC95650D5797E58E6F
-:103C70009E87F6C532E177B302CBC7B893C09BCD20
-:103C8000AE0ECA4B33DB797CD422E2258733DA8847
-:103C90005FB142635E5A0353656CDF9839E798045D
-:103CA000ED0D0EA39E7ED5F937CDC877AE928D7AF5
-:103CB000BA9F75107E5EC98CCF2D85463E40BA36C0
-:103CC000FAFD3326C7287F2DD7417906A3F90F7E49
-:103CD000D3C928AFCA921EE840197777D9B4EC8DC2
-:103CE000D3A13E86E3D7D6B2F98BD11FF41B81C78F
-:103CF0001B81EE118E2D6BC6EE36278CDBA2444B5A
-:103D0000518EB498781E3FFDC0FCBFC9CD277F6A95
-:103D1000F2BC94099CE08F6AED90029E847DFC4683
-:103D2000D0C5F07C7714EC463D7678BEB4E8149AA2
-:103D30006F381F48CC97F7D9E67B43D0B33E5FEB93
-:103D4000578CFB6B5562B4BF561313F9FF7CBE371B
-:103D5000707FEECF309FC8EB1A9EEFABC6FDB5A6C5
-:103D6000C5687FADC3F6A4982FEFB3CD97A6745066
-:103D70003CE63E899FEBA1BD4BEE477FFCD9F96B3A
-:103D800034C437DD3EA3FB3366BA3F4372EFDA42F9
-:103D900085F4067DDC7D9DD3995FE17E1B2C2B662F
-:103DA0004A740FA072BAE4C778D8C340F7FE32F461
-:103DB0004BA9D41EE97451B9A753A3F231B007FD42
-:103DC000E49FF251FD6C19B787EF1BA72E5B89FAB0
-:103DD00042BD9DE741CFBC0234D1B8BD0506D82114
-:103DE0001BE61B7E814DDA8A68BE93C323A7312F61
-:103DF00082E7649FF462AC13EA6933CC1AE677A7D2
-:103E0000B9592095DFE57D913FB359CF9BFF9CC405
-:103E1000E3EDA08FD4C3FE6F14A066E6F912EA5555
-:103E2000D77E358BF491962583192AACE30669D2A7
-:103E30002F3C008FFF2DF4911BC7733A4EB62773AA
-:103E400050B24CC6BC3E732402BF2ECE584CF6E88E
-:103E5000E2A58C39E1FD6BF13D902BAF087DE6E5E5
-:103E6000C13486F65AB891C7996FB8DB6847DE67E8
-:103E70008BAAA8C7DD372987E179B4AC35B66F16B0
-:103E8000F182C54976E5B5497934A065F27C10DC4C
-:103E9000F30CC6DE2DCBC8A13C589147F384F00B40
-:103EA000B1C21C4AB676CEF58CC1F8639A92FA7EFE
-:103EB0008E3E5E8EE03B2CC74F70D0F3CA99F9A9B5
-:103EC00049F4BE984F7F6F97F4D4B88BF935416FA2
-:103ED0007B6BB082CB67D4AF59B931DFE7ECFCE242
-:103EE000AF37B254783B24A35F415FFFFF2D7CFDC9
-:103EF00011EE17CA57667D3899DF432B6489F7CFD7
-:103F0000F47CAAC5C37599A15EB954AFBA86BC78D2
-:103F1000DEAF7D2EDDB795F04FE80FD1D74D17D22C
-:103F20003FFD78C3EB70F98BB83F4EDC1314E38D83
-:103F300006E7E47C07DD6F433F53E3FED8AEDD3C8C
-:103F40002F323FA7E11DBC3F85CFDF34E095F19EC6
-:103F500054D7C01312DA17DFC27B5F727C3EF4D3F2
-:103F600086497F35DEDF1A218F19BF97A3AFA74B94
-:103F70006115648F9A803FC07C0B1C83B2A4A1DFC3
-:103F80007D88EEF3DD59CECF057387F97D18AEE756
-:103F9000990B4C3C7F6382C6F53ECFD0F8C4B8D0B5
-:103FA0000DE55CAE2F487F75AD06F26F49F9938B36
-:103FB000313F69C19857D7BAA17E5DF97717CB8099
-:103FC000470B0A5EFDD00D3ADBB2F2A778BDEAD509
-:103FD0000F8BA1BEBCFC695EBF8211505ACBBFB72C
-:103FE00018F9EA0DE5AAF0F3C50A71BE0512A78F0C
-:103FF000CF5A9AD34C29E3F7FF50AEFB139905E74C
-:1040000009F4FFE424F2A380EE7FF527C51BB12954
-:104010000FEF13899F9C4CD267E6E1EF00CFABE531
-:10402000E800BE6FB24609AEE59837534128F0C0AC
-:10403000858BE44724E39104E8BA0EF5654D652DC0
-:10404000A01F77AD63415B49029E33BFC0739EC71B
-:10405000A3AF479F7FC4BAE0486567E2BA1EA67166
-:10406000F4759D9E9416C67B677AFC545FD7696988
-:10407000E811744644AB0697E2B99ECE181A2F4158
-:104080005DAB5097503D77E811C99750B7F073BCBE
-:10409000B7FC27A4F7AC95FCF79623BF541C74BF5C
-:1040A000AD47E879DB728361C6F57BCA770C17F1FF
-:1040B0007B038D93257F627CFF9B02BFF22A7839B8
-:1040C0003B6D7BC709C0C7D00189AD87FEA1F367EF
-:1040D00015B4C717F49F52D0EE6E3F704A41BBBA79
-:1040E0001DEB304EFBC30AF1AB64781754980D7189
-:1040F00074DD9E385254B63107D6D3BE52F2618A6F
-:10410000EC9AE7B366637DCD0ADC2563D7CFDC3F4D
-:104110001BC9BB3530B011CB1BD9E0118C172C0B50
-:104120001AF5FCE56D46BDBCB5C3A84FDFB81D4E02
-:1041300007E4D78DEB0A0CEF31D490613DCBC47905
-:104140002E73DD1333D7603DE1BE8E44644DFE9D7A
-:10415000E57C07501AFD160BFA25A2E3F6662BF94B
-:104160005F8F14F13CFBD02A33E50585101DB0DECE
-:1041700021097F969FF8A32EBF67F79D395A80EFDC
-:10418000AFB2101C58D81F43FF43B3C0A71B9B9B63
-:10419000DE413C6BD66EE3727CC25E0BF957825CEB
-:1041A0001FD784FFBBA5EFBE4627EA9F6B25F26FA2
-:1041B0002C6F33EAEBADF80BEA6FEBA448D48D70AB
-:1041C00032B6DFB8CE587FBD5CC8DB2A568574F2A4
-:1041D000DB7249A67BC5A2FE87A25FBE1C8589EE65
-:1041E0009202A710EF5629D11A946B774941AAEB96
-:1041F000EDF0BC9DCB1D2EEF4D4051C4772DDCAFB3
-:10420000105E2D113E2E1F21FF13F403F3C87A4ECA
-:1042100005F7B777D9026BC95E7A4152511F69948D
-:10422000FDB2D31BB76793F13157E0F7CB6CD08B5E
-:10423000EB2A43A003FCCB168F89A03FACEC9F5721
-:10424000507E63599DE433113D9BD8BA5A2C65E2E8
-:104250000FA86FDAA02C33F73613BFBE4C5179FE8E
-:10426000A08B25F201FF134C4278E1D271DEAB0B3B
-:104270008F7D8CE778CDCE7BCE20BFF394F86BEFAB
-:1042800083F56DB3F1F9B73D2F91FEDAEE3D4A7C2F
-:10429000712CA009CEDBEE12FCB10FF8A3BEFF62B9
-:1042A000BCD70FFC0A2F8ECCF7D2BCE3F4F8809E6B
-:1042B0005F1B6D305D00BE3356CC5B50A311BCF26A
-:1042C0006EEB9570DF452CBC1EFD44328E991B2F82
-:1042D000753FFED278BCFA9B789EAB5D830AE9DF1E
-:1042E000225E9DA2DFEE94FDFCCCE047986D3E9FE0
-:1042F0008971E5352F945C34AFC26C3519E8D5A2CD
-:10430000DA0D747D758591CE17F88CF47DEDF4127D
-:1043100043FB427F95A17D71539DA1BE347085A161
-:10432000FF75CDB38CF6BE6B9EA1BF4D5B64A8A795
-:10433000575C6FE89FE1BBC9C86F727A297F40B1B3
-:104340008607831ADEAF676CBA33CEAFAB32AD9857
-:1043500064CCEC753607963D93D2A2786E3DF93C5D
-:104360009E9AF6D2975D5184FA98A7ACF5507E5785
-:104370008A3460BCC82AECBC897733033FFFA72A84
-:104380008EE77AB9A42278632594DE7D5A01CF970F
-:104390008E4DC4F3B1A20311F1F8392BE91D972515
-:1043A000E9BF4535F5CB2AF0BDBBFD73C92FD5C795
-:1043B00054BC57BB47E1F94CE1E778FEACB76FD08E
-:1043C000E44FA0B7FF53C1E5FD37020D949FD4DE43
-:1043D0000FD20CF17BE79B0AFAEDDAFB0732516E44
-:1043E000D404DE5450BF8E3F17F2441EB263FCF279
-:1043F000FBBDA9F3D0BE51A1D0F84705BF6DFD327A
-:10440000E7B78070F3D13ED2F967EB7EBEBFD6A589
-:104410000AD1B7CE47817F1AE261C97C79F9CCC84D
-:1044200046A45DE0A306FBE5C62573DE417B0824B8
-:1044300035E931C0478DED859B88BE6F4CB26FBAB0
-:104440002A86F9A9F702D0CBC98029E5BEF654C95E
-:10445000B4AF93C15904EF6F00DCD06EFCC60838CE
-:1044600071F87D127C9E16FE44FD9C92FB7DA78A0E
-:104470009FD3D3A3F0CB77059FDD23C56A919985A0
-:104480000276C2D3E556EB52CC33385AF4D1268C9F
-:1044900027B4FE40425B96FDEBC04B799877A0ECC9
-:1044A0003F9287F910A1DE23790CE0B4CAA2AD4790
-:1044B000BD18F0C0B71ECEA5BD2F4AEB5FDD5B3740
-:1044C00080CF57F7493E6485A10367E6D03ED9E027
-:1044D00026D4E3F78CB2AEFD153CAFADBF42E37915
-:1044E000F7419813E5EC8134B2635BF7031FC275A3
-:1044F0003D2FD13D8C3D5BACCDA9F493A7AAF877B5
-:104500001B5EDCA2308CA3AC82F7711F478B8E2A16
-:1045100056C49BFD12D984A1DE134BD11F1F5A6BC9
-:104520006118B7D5D7F75E51ECB7B8FFD7575A180F
-:10453000DE2FEC5AC9E3B1AFAF35D338E69B2D542B
-:104540005F762BCF133EBCF2DF3615C0B8AFAF920B
-:1045500028BF7ED6CD7F3C8AF565B7723D28197F8E
-:1045600087F135093F97058D7837024FDB3E1B9E5B
-:104570009EAC10F66B15AB41390BE73E7B2CE2CFBE
-:104580009D8CEE37369F3F6C190BEB2DDEA4FA3075
-:10459000B45B6D8E6CCC43BE7098B74F5AB55BE27E
-:1045A000FC45A37BEF053D0A43BBF15D715EEFE285
-:1045B00079E5E2D68624CC6B6372AC18D7E716791E
-:1045C0005CCF5858F37EF423C99CBF54FFD0B53B51
-:1045D000D18FB44BE0A3CEF7AAC0DEDF4F7EE8DE7A
-:1045E0007CBC8FFEB485FBC7C68BF14A4B86E62C9C
-:1045F0008432BD92CFFF47B10EBDFE9CC07FF687CF
-:104600004709BE0BAC1CEEF3D6455B701FB7C8C1A3
-:104610003F23FF9B3FFE97AB50AEF514FFD44BDF1B
-:1046200065611349AE85C4791C9EF1EF0FDF81F9F6
-:104630007695763AC785871E8AE1B9B67B64CA3318
-:10464000B4954E1E1BBC881F21744E33DCEF6BEFFC
-:104650003F33C79F82AEF757F1FD578B7B7CAC9FF2
-:10466000FB0F801FCBD36BE3FDF4FDEB7E0F5BE90B
-:1046700063744E777C894DE2F7FBEFA37196AF3AF6
-:1046800021E1BD94EB2C7E8B03E0FCCB316C29DA6D
-:10469000C13FED64744FED38DE570356F272A74AFE
-:1046A000F598B8B7F66AA746E5754A603CCA95A57D
-:1046B0002F769422BC0E173D18C0EF359C3E2EF489
-:1046C00059A6F2FB8E02F7CEF69B9915DACF1E9013
-:1046D00022E43411EBBFE15C3E0B023FF9B5B81F99
-:1046E000B77ADDCF89CFF9DACECC413B63D2AA537A
-:1046F0009BB01E5AF7C739A837FC16E404E257A846
-:104700004F622E18A7E59C93DE5FDD7742417BFE6A
-:1047100069D3D01C847FF8A044F7AA421D67887F24
-:104720003E2CFC2B37546671BED13FC944E7E99F4C
-:10473000C8ED1371FE0313FF9489FCCBBA4E7BE5E1
-:104740000A3CC763663AC7AD0D43996A8A73390953
-:10475000E3A24FFBD7221F2FB9BD5909935FB6596A
-:10476000E06D72FBF59526DD0EB7883C2526C17AF3
-:104770005A047EB532FE9DA0963E296A07BA6DEDB9
-:104780009F45FE8DD68E8B7F0766347CBBD4B29D51
-:1047900071FF865E47FB2B315F0BED2FE37DF5301C
-:1047A000E1555A91676CF022FA5D68309FE227ED7F
-:1047B0003D8CE225ABCF4DA4F2FDE737D3BD27AB4F
-:1047C0007DE841940BACCC447AFDEAB051BF992D01
-:1047D000E876B6D06FD654827D52C186ED13B043D1
-:1047E000BE5CC9ED90CC43CC609F243F27FBC42A1C
-:1047F000FC86305CF09914EB9E57D57057652ED22D
-:10480000D576C26F06F88D7895BCCF8D959C3E7598
-:104810007A5E76E81D05F5DD505F6A7A5E5A55BF0F
-:1048200011D7B36594FCBBAB05BDAFDEC9085EA173
-:104830009D4E82D37B6C67A001F0F23D5807DE5F8E
-:104840003F1D08A467C1FBA78381748CCFE9F4DF07
-:10485000BED34EEF6DF12CCAC6EF6DECAAE4F1F3B6
-:10486000F7FB665911CE37ECE474A7CFF7DBE8B25B
-:104870006CA49F29962105FD9385FDA73251AF9B1E
-:10488000F2FCE26CA4BFD1D6B975A258E7BAFCA578
-:1048900074EF077ECC40F7B70B3916DA105510FECF
-:1048A000B7AF6384BF03CFFD6B3BD2EFFBFDE92ABB
-:1048B000CAC9F75E480F23BF3F7D302D6282A156E3
-:1048C00089EF24BD6719BC86F4C7E7CD94AF103AD1
-:1048D000F8EE83488FA1E7D2E81ECDEDFD9BCFA077
-:1048E0009C5BD53FF71D19CBA7FEBEF4B07ADDF86F
-:1048F000A589F9C5EF76EECB47FEF9BECCF9C4ED3C
-:104900007DCF923E7BFBF9B335983FF8DE0B7F9E5F
-:104910008AFC2CF4CF67A7221F0BFDF8EC546C0F18
-:10492000FD30BD23957EF2E32AEE3FD1E5A3FB35B2
-:10493000D9E067B959E087BB7B7B137ECF60CA891A
-:10494000251407D0DBA794F27BCC537ED1987D73DE
-:10495000C27BDD3199F225269F684C5F998097D7FD
-:104960005759747FCDA5F947441E82EE1FD9129383
-:10497000F9BDBA36337DBF6E798CC7DF93FD268CC7
-:1049800005AEAEC6F3BE35D787DFF1C1FBEB181716
-:10499000397D676984EEAF87AD473C097AD0B2981C
-:1049A000299A867E90FEB428EA43CB62F2A9B40429
-:1049B000BFC86FD56736A21ABF2C68F46324FB41C9
-:1049C000E027434E889FB4AE8D5A7439B500E6FF98
-:1049D000E546A662DC66847FA4F9F3E48749F69392
-:1049E00068B107ACF89EE6E1DFDDD1F54C3CAF03E2
-:1049F00029E87DC344CEB7743AEA8E99E81CBA63BD
-:104A00000D560F94FF28DA0F80D80C635E50FFE23A
-:104A1000C7D14EEF3E7F5D3AC2ABFBB5450CBF2B15
-:104A2000715A6DB096E27BE73F6F5DEA8DE3C70890
-:104A3000FE3191F3C7617D6014393753CCFBF79297
-:104A400077D3279A84BFE1FF6F790776F55513B9BD
-:104A50005DBD9CFB3DB85D9D2C2774FEAB8F1B128A
-:104A6000F01EC97FDF21FD05EC5FE2BFA1891AF5C9
-:104A70002BEC5F984D76F16B4BB235C7C8F14B64A8
-:104A80009FC9E91D39BEAEAF85C2FE2356B463FC93
-:104A90003CFF34B444A2EF4B850212E9D9A1164B76
-:104AA00004DBF5F5C496F0B8E0529F44DF0BD1F576
-:104AB0003F5D3F1C6E9F0CEDEEB8BEA8EB85B100CC
-:104AC000F78B2EF15BA8FD3A25780BC2E9B7511B95
-:104AD0003D9F32838F0B7CE008FA3FAFFB8244DFBF
-:104AE000F3D2F5451D3F93F5C90FFA4B2EFA9DBA47
-:104AF00087055EEAF4353E892E7439B5AB92C3A7BB
-:104B00001DE57436CAE98F9541C7E87A37C8E9BB15
-:104B100070FDBB2A19BD3FF917722095DD9D21C696
-:104B2000DF8AE7066561ECC57A5C6F118B515ED454
-:104B300068F2F3B62A4E0FA3B5EFAABC343AFE8151
-:104B400098FFEF45C7FB27FEF7D05B87F53F25F5BC
-:104B50003EE755D5FF6822C0D56EEEA0FB51EC5F55
-:104B60002CE4B74EEE1712F218E499018F8F142936
-:104B700026B47B426DDCEEEFC9D25E21FBE4257EDC
-:104B8000EFFE7691AF74DB3995CA1EFC8018B67FB4
-:104B9000D94D7E9BDBF69DB0F8E1FDE56BA549E8BC
-:104BA0000F5ADE66DC4F4FAE7F6EA21FBC675C2FD4
-:104BB000C515C28F9768387E2B6E16FD213DF91101
-:104BC0008C3DB6A31FE7327C9E70DF02E6592D9E16
-:104BD0005F21FC3B2C490FF8F1C0EBE4EFC1B810AA
-:104BE000D2AFD22F515E48E818F777B4F773BEF012
-:104BF000769B44FCE46D919F115A6723FFB6AE4744
-:104C0000BC23FADD7AA744FADE08BDC26F8CBBACC8
-:104C10007EEC17C41793F508E7013E0EC65BD02F54
-:104C200073A468AA84F5D56017E2F74B439A766DB2
-:104C3000015F1F8B107FF11BFC281F1CFB37B22369
-:104C4000973F2FB16CD23B92E22F3DF392E22F4778
-:104C50008F14E03842CF50E13FF41F26EB19ED7D71
-:104C6000272C68177C529C45A91AF6B7905F708272
-:104C7000CCFDAC13FA2515FD4913049CA66DB113A8
-:104C80009CE6BCB1321BE95C3F9FF717F2F37AFF59
-:104C9000F50FEBF1BDA96FC82AF2DB1FBFBEF6E727
-:104CA00005BCAE59357C6F6D3ADA21EFBFB1261DD8
-:104CB000E1F86328F13B4A3F3C29A7F41FAE15FCFD
-:104CC00008E45B4115E6DBDE2DFCC632C8B78CB8C4
-:104CD000FF25F9BD1DC21EEBC1EF1B21FE3DCFE339
-:104CE000DB3DE382F3A8FE5031CF239639BE3EDB95
-:104CF0009FA5A2BE57059BC538ECF7ECAC1BE32B78
-:104D00003DB9C19F127D3C6422FC85F7F97727F6F7
-:104D10006B24EF106418FFA8015963A5BCC61C8A58
-:104D200083E8DF85190776A8F88EC2128CBB5689F6
-:104D300038488D9DC938FE364B706B25C65D0664BC
-:104D4000DF7A7C47F665E3F79292E3317A7C588FFD
-:104D5000CBE871E2D1E23212CE53C3F12CF13B2702
-:104D60007AFC857D81E76F764DEFA0FBAF63B12FB5
-:104D7000F1CF11F194D5686F26C753EEAAD4FB1B6F
-:104D8000E3695B2B9E217CFBB471B41F4C1C6D7ED0
-:104D90008D9E27CF3F39EB833CB25FFEF21F9924F3
-:104DA000CFFACF92DC393D9426EE710E723F75BF7B
-:104DB00085ECF5D36007E526C8B35F55F2710FF5B2
-:104DC000CF227C3C106B4CC7FE7FADE4F0D9F2DA09
-:104DD00092C5A84F876332CFC766DCAE391093A760
-:104DE00070FD60049C364D4C0127AB3D751ED054C0
-:104DF00081D753ABF8BE67BDCEED95D05A1E3F505C
-:104E000005BD859A14E227478BF224DD8F3C365589
-:104E10007CE1F921E2B3ADB7F2F8EE25C717FA0647
-:104E20002CAC3885DFB6690EF19B4BF5D732B482D6
-:104E3000A7C6F9F3769D9F5473FFADAB8AE7F33BAA
-:104E40003B26D5E377F1F47DA78023F35E5A9C2FB0
-:104E5000B3FAD2FA2DACB8B47E9B2B529C5F8A7EFB
-:104E6000DFB8C47E3FB8C479D353D1578A7E7FBCA4
-:104E7000C4795FAAFC9FF8E7703D39BE991C0F4DBD
-:104E80008E73A6BD747318DB364BF70C4511BA99B7
-:104E9000CF35E3F7D3E5ACC7ACC8D7E6CFE0F180B8
-:104EA0002D8DD6C86E291E17D5E1F55135D7BB54C7
-:104EB000EF99307E3F71BC3FD6980D747C7A062303
-:104EC000BBE1B44D7C0F4956C72DA4F353E97B38A1
-:104ED0003DB6D4F1A527C578A3F191A29AFAF3556E
-:104EE00053E8FE50CAEF54DC2FF440B58F91BF86D3
-:104EF000C9DAB84534AF360EE5CC9817F9F3CC28AB
-:104F0000A3FC3E68772F22FD5973E3FA7688B897A1
-:104F1000735E991BFD744E90B71817B90FE323E425
-:104F2000D757A99F3E5F9797CFB7C3C2248C63859D
-:104F30002B795E056BE935C4358E5BA2BF5B2151D1
-:104F40005C632CD2FBCF4C51EF1E373F1784AFF779
-:104F5000804AF19697677CA782EEC58B38C71D2AD9
-:104F6000EF7218ED0C58C71D2FD411FE2E3F34E3FD
-:104F7000572DA80F7A6482F3083D5CD85727857DAA
-:104F8000A8DB5783682726D81B555ED3687CA92ADF
-:104F9000155FDA2171FB37FC336EFFD629BE92C450
-:104FA0007CAA69021E2BA2DC0FABDBB535FE88297B
-:104FB0000FE05077A7399A06B2B76E53B582FCBAA4
-:104FC0006E53919DFC4A2BF79B7478A73AF77AB100
-:104FD000CE2DC786282EF16CF23D732F8FBB0E09A4
-:104FE000FCE9C2B385FA1DA572178ADF3133557308
-:104FF0002ABF782BE8FDB8BE153D7CBD7A1CA435D0
-:10500000AACDC2794E1D19DA84656D9B7B16F90D08
-:10501000579DD984723374FEECD1ABC80FA068A938
-:10502000EE0B586BCCB48E6751114178CD95296F3A
-:10503000B76EAE4CE7ED6CB5911DEEB430337E9F8C
-:10504000D5B990CBB1DAA69C5958674BB2480ED768
-:105050001ED3B26EF6C6ED7CE7DCB5B908A74F8A61
-:105060000FE9FE82EB14FF4D788E9F363EB4FAF8BE
-:105070006B946776C3A0313EA4C77B468B0FE9F1E2
-:10508000D950D387867872481E9A837E95BA174E78
-:10509000517C38D427A92E773C6E143A704621F8FB
-:1050A0008A7811F457F0BD3A38F6714EFCDE008F65
-:1050B0001F3D87F9B80A7E4F4FA5BCDB1F613E6ECE
-:1050C000197E4F8FE7E31EC47C5C05EF7FF07CDC2C
-:1050D0004322BF37D47F86E24D3D5E63BC428F479B
-:1050E000DC2505B679730DF10AAA27C72BCC766E9D
-:1050F00087868E59E8BBE8A1E356E2B3F5FD2B267F
-:10510000A03EA67FAFBC1DE30509FEA5F7FD3E1B33
-:10511000DEEF793FE0B3619CA06EE01D4523BE1336
-:105120002DC014A67639A6A0BD8F70A03CBFFE7A14
-:105130001BC2F513FDFA7DFFE3D7FF347EFD8C38EB
-:105140005D12FFA80D98E85E79ED31BFEDE604FE33
-:10515000B025C0FDC35B3CC5447F0F048AB356260F
-:10516000FAF19BB8FDE69CEBB1253E5F54C3EF0F0F
-:1051700038A5D4F70B5EF7EAFED711FCF6756F4A37
-:105180007D27753C604B13E723BABF7F647CC0F773
-:105190009227C1CFFFFECFACF47717069E4F23793D
-:1051A000FED10B697B50EFAE6D5A392103EAB5276A
-:1051B000D3989BCB23435C617993C96FCB4C154744
-:1051C000F017D0F74293E3054D26E2EFC3F18226B4
-:1051D000F914D5857E7EC3997FCFC04F643F2B45A0
-:1051E0007AD0BE7876B5E41B6023E3073070019B6C
-:1051F0000EBB68E27682AFD94A76C127C5155A0E32
-:105200009CD8887E82496C7B0F7E7F7292C7A48275
-:10521000284A1157E0F99DB5428F48F60F207EA02D
-:10522000DC4FF60B665673399459CDFD983B51AF60
-:10523000CF8D8FA3BF977CEE5F147269343FE3621A
-:10524000D1DEDD54BB05CF2D3CDFC490FF77373571
-:10525000583D09E3B9AB79DECC0E8C53E424C62962
-:10526000783C22393EA1F3A7BA818FE7E0B93FD05D
-:10527000CFFD472117F767D61DACA77B26F17572C6
-:10528000FC7CC0357CCF308BF17D312BF773915F87
-:10529000A176FE8787F0EF12B04016FD9D83D07196
-:1052A0004F9703F9C87C798AA4917F7BD8DF8DFE64
-:1052B000A8C5AFB4CDC37CE0BAA5934EE0B92C6DC0
-:1052C000B150DED1E2579AE9FBE3BABCAA5BBA7BE4
-:1052D00003FEDD9AA51592CFA6617B5303B65FFD51
-:1052E00054143D7B6C01AE0EE825761C7A17937F33
-:1052F000BBBE1AD65BB750F8BD5BB85C5DDABFD0F9
-:10530000C23F6E659473878B3E22BBF96C7F1DF99B
-:10531000B3B331DEEA8DCB99BA1740FE64C4E5CF52
-:10532000DF2A77BE58CDEDC0CB40FEE07A9C0B79EA
-:105330005C30F9FCDDE2FC479327A3F14F941FFC9E
-:10534000EFF2840B24575CEE6A684F4F8BCB5FB54E
-:105350000FEA6347C7BF87847E95358AFEF580C014
-:10536000F751F335FAFE3E7EEFEDD5FF3DE257BA39
-:105370007DA3FBBF757BE8F702CE7AF9AEC08BBF89
-:10538000395F198562CA7C6567EA7CE51B7A25FA74
-:105390000E8BC8573EA2B0FAFD3998A727EE2544D8
-:1053A00002A4DF1CD9F5EB4D4FE4E0BD044945B143
-:1053B000B3BAF704C9E7D5A0CF901ED4FF2EF74BA0
-:1053C000F5F2FCD2D57DC6FB0F7AE9ACE1F1F646E9
-:1053D000D80FF991451EDF9C039CAE437E25A2B9F0
-:1053E000D12FF41539D12F14D262B97A7E6084CBD3
-:1053F000A594797CED6C88F2FDDADB241FCA83CF9B
-:10540000EC27F2F3FCBE4BF513FDBCDA987F7AAEC5
-:105410008ADFFB690E4A12EAA356536015E5F71EB0
-:1054200094D45479A2EF087973B5F0D3EE55381EB1
-:10543000ECBD5CA2BC5ABC1783E7BBF720CF9FDF53
-:105440005BCBF3E775BFAC9E175F19F7CBD27D1826
-:105450003D9F5ECF8FD7EF872EDC698FA27EB1CDC7
-:10546000D2EB423A1CFE4E0FEA22D06E17DF194FE4
-:105470005EE72FAAEB775553BF51F59B3F56A7D058
-:105480006FFCC24EFB73F5A87AF95FAB8D7A39D504
-:1054900093F5F2FF2ABFEC37C43E53F9D552EB67C0
-:1054A00023FABD7889FD7E980A1E5DB6D4DF0B6DA8
-:1054B000AD11FC37E9EF92B011F77BB87CEB91B4FA
-:1054C0005F5D41712E0BC5B974FED293C1C7F78AD7
-:1054D000F1F4F2F3359CCF8CF65DC945A2DF5AC9D1
-:1054E0005F553305BF1F6FF49355F71AFD6497F5A9
-:1054F000390DF549D17C43FFBA63C586F629B189D8
-:1055000086F669276B0DF51983971BFA5FF1768391
-:10551000A1FEB921A39FECAA738B92EE1D71FCAE84
-:10552000078C487C6F96F58B867E056DC67D15755C
-:1055300018F735619D715FFAB8EEB0717F253DC6F1
-:10554000FD39D17FEFFDECFEFB9857E3DFC1E92F7A
-:10555000A1EFFEED68F2D077AEF5FB7FFF09FEEF1D
-:10556000D922F072000000000000000000000000DE
-:105570001F8B080000000000000B53E16760F8512A
-:105580000FC15BF918182EF021F8F4C01CCC0C0CDC
-:105590009C40ACC8C8C02001C4FC40CC06C49E0CD2
-:1055A0000C0CFF81F81B10BF05E22740EC0CC40770
-:1055B00058B09BE3C6CAC0E001C4DC40B378988908
-:1055C000B7DF8917C17ECCC3C0700E889FF1D0377A
-:1055D0000C061B5E27403FBB7E43ED3A2932F0FEAE
-:1055E00006612131609A1447F0A78AA3CA0B8B2168
-:1055F000D8C9D294D9950FD40F00F19321F080032C
-:1056000000000000000000001F8B080000000000E8
-:10561000000BED7D0B7C94C5B5F87CBBDFBE92DD45
-:10562000CD26E44900370960501E4B80C84BDDF0A1
-:105630003252C40411828A2CAF10027914A9A5FF3A
-:10564000DABB0B2804AADE5851A37F6A17041B2D6E
-:10565000DA80D11B6DE02EA208D56A684551AB0DEA
-:10566000888808498C8F6AB57ACF3933DF66E7CBF3
-:105670002E89B6FE6FFFBF7BC3AF1DE79B993367D3
-:10568000CE3973E6CC9999B3268383192E60EC1B2F
-:10569000FCBB9C319B893136A62B6D573A86AB39C2
-:1056A0005DE5B7F9BDCC6B66ACCE6FA5748B3F9D45
-:1056B0007907C3779FA1306867EC5EBF8BF2BFF0BC
-:1056C00017525AEB2FA27A77FA4B287FBBDF47E9B4
-:1056D000667F197DAFF157537E837F0DA59BD4451F
-:1056E000692C05FA66458559C98C553D9393B719C0
-:1056F000725B668D4F504743FE15233366017C9FD6
-:105700004AFD31D5BD69E0E8AE7A1A9E9BD449FDC9
-:10571000104EED128E17B3325B8C7A5938CE3B9710
-:105720000878F6D69A9CE4A8F50623BCDB4B00DE8D
-:1057300050287085AC39D1E15D8CF03697A8BC5EFD
-:1057400072B0263B3A3C0FD6ABB941C04B0F586301
-:10575000D41B83F536DC20F0EBE7ABC98ADEEF78AB
-:10576000ACC75CEADF5AAD8CFEBEC9C6FFB7BB4E04
-:105770005D2CF246CC263136AEAB9D3E652CC0701A
-:105780009C2AF315121FDC995F7F93CFD84D081325
-:10579000DA0726B19011FA0F24B1E0FA2CA9FE4CD9
-:1057A000AADFDAF7EB6F52A5FA014394FA26D6A0E6
-:1057B00060F9CF518E80EFF7F97329DD28E4E7BE59
-:1057C000A106C6B05DBA393808DADDE3F790BCDC73
-:1057D000ED1F4BE5770939FC7721674121670FA25F
-:1057E0009C41BA15E5CC8CFDF95A4B014EFBDE7895
-:1057F000B6D94DF2B598F05419C1DFB077C8F6CDDF
-:1058000000FFBE1B569DDE06F46F6B1EE63142BDE7
-:105810007B866AF2C5BC2CB9ABDE3DB34F38170DA1
-:10582000257A97219CBB3D827F2A0C2CA2DEDD339A
-:10583000C2F52AB0DE5D9E30BC5064BF774D09D7FB
-:105840005B457C56584983BD3B5F763085E623082F
-:105850000AD1D784F48579F9EC80EB9456689F924D
-:105860009C97C6A0DDFD381FCD38EFDC4417AD3D59
-:10587000D2D907DF332CAC1AE10365F71B015FD3E4
-:105880006C7722D2E5F66B8B98328CB1BEA23C3598
-:1058900050A464015CFB9C2205BF9B6643397C7766
-:1058A00089F2E435BCFC762C7774952762397C4FFD
-:1058B000AA8672C8DBE7F2F23BFCC089C15DF5360F
-:1058C000019F7DC4EF74FE1DD88AF4318DE6A98650
-:1058D000F713282440BF83988EE9C27FD3A07B337F
-:1058E00016DABBF0B50DAEA7BC86DFA6C17194D7A2
-:1058F000F0B15DD82F6321A47D97F465DE5C311F84
-:1059000058773A277AB3A5F24CD593A0029D325F1F
-:1059100032B200B02013C413E1E9DB153103E1D941
-:10592000E3FC4BEEDDFC330D95E9A0A547053D34C6
-:105930003A6CEC2FD3C13240A6C3C601321D2C17DE
-:105940009C9F0E3B989BE81C8B1E5ABF9B87C8FDF3
-:10595000C65D24F7BBF922B9DFB88BFF39FDD664E9
-:10596000C9FD5AB3E57E6BB2E57EAD39FF58BF4C39
-:10597000F5C064407DA5FD5D28E9B7AB99EF2CB675
-:10598000473D87F349D373A6641FF3D9BBF809EBEE
-:105990001463F99170064B7A15E07C8AF5008EF756
-:1059A000FC705C3A3883F470BE16F8B0483DDD0DEB
-:1059B0000E1BA81F8749E1ED428688FE99EA6345E0
-:1059C0008EC8761E5DFF39FAFE9D8A1887E1BCFD00
-:1059D000BB7574CDD6E39326F06186F3D183B97499
-:1059E00070B2F470DC029F90725E386EFD382E1437
-:1059F000FD071469FD027A0CEB6AD70EF8D13A95CF
-:105A00006709EE04FD10DAF7E5295C07CE355EEB99
-:105A1000B640FDFD232DA1CBA1FC5CB0206881F236
-:105A2000C94F1E75A21D53F1A451C572C33E1BADD3
-:105A30002F6D3B142AAFB2B4DC3901CA3B9E34B29D
-:105A4000EDD45DA601C7774AE81416E2F9521BCFE0
-:105A5000566CDB7F23B62F6BB2301BC0AB787AD984
-:105A6000CC09905F76C8C4B04AC5CEB5E6BE905F9B
-:105A70001E541A300FF8D23A15C8B3057742FD7597
-:105A8000FBBE6C43FCCF359A06213E67609D70C318
-:105A90003AF192A3257536D0A73CB87B1AB62FDF12
-:105AA000A57840C301FE3B0F6620FE8F281E0BB079
-:105AB00070457D3C7347CC97538D461AEFAA6D4ACB
-:105AC0009001BC65AC761AD2B302898378782C41F8
-:105AD0009BD235DFCEF8EBA83F2D5FF108F407ED40
-:105AE0002B1F573C38E44A03F3E13C6E7BDA56F255
-:105AF000901DC7BBD63CD881E3DC68C67ACB820B4D
-:105B00009FB2B911CF6DE66988EFD66DE6D2A14894
-:105B100047B6A06828E2F77F65FCEA8C5E1CEFAA16
-:105B20009196ED46C083D943036739BAEBD933B0B8
-:105B30005EB923D6CF72067A9FD6EFA0B97858D730
-:105B4000F72F0D89A43F56D41B99DBDAD58F261F7A
-:105B50008123423EF63A88DE1A3F57B9F814D0F84E
-:105B6000B92A51F057EDC89F35AC3B3E77225FC84C
-:105B70009E7651FA0B583731DD02EB3CD2EF5EB026
-:105B80009FDC64977BE8FB03602761BA15EC244C2B
-:105B90001F043BC92DEC24ACB71DEC244C77809D31
-:105BA00084DF1F067B1CD37AB0C7F1FBA3608F6331
-:105BB000BACB1FA0EF8FFB6B286DF0D752BA07F955
-:105BC0000669A33F48F59EF2D753DAE46FA0EFCF02
-:105BD000F89B28BD5DD0D1399115E03AEAF432172F
-:105BE000923D6986B7C004F9A4229E4FBD21506042
-:105BF000867CAA0FF24097BE2B430516C8F7ADE688
-:105C0000E5036E6193AC901F10E0E5D9B77B27D90F
-:105C1000209F5DCBCB076F0D4C8A83FCE0202FBF0C
-:105C2000685768523CE42F6AE0E5C39BD9643BE4C3
-:105C30008787783EEF25EF6407E4F35A783EFFCF7D
-:105C400081C94EC8E7B7F2F6E3CF068DEE28EBEF39
-:105C50001E937B31AA9C03CADB5E3503F266F74DC7
-:105C6000A8128F2AA728DF68F252F9FB4ABB578592
-:105C700075BED1ECA5F22F94CF29FF94C947E5F169
-:105C800006A580F2661F95F737C451BEC914A0F26D
-:105C900011863E3C6F0E507981A15F01C27FC61410
-:105CA000A4F26B0C8378DE1CA4F25FA8C30BA640A1
-:105CB000FDC70DBEBDA8EFD62BBE32B40F99DA904A
-:105CC0008EFA4AB32B77E2E0D0CECC30D33CD8F377
-:105CD00087FC87681EE05F32E64B1F46BB14E01C62
-:105CE0002438268063EC194EDECB632538792F9754
-:105CF00069705E2138B6DEC1D9F3F278199F97CB6F
-:105D00003538C7088EA377E3CA7B65A28CCF2B2BCF
-:105D10003538C7094E62EFF0693C2AD3A7F168987D
-:105D20003E67707D589FD23B7C46BF26D367F46B9D
-:105D300061FA7C4CF864F40E4EE36B327D1A5F0B13
-:105D4000D3E72B82D3BF77E31AFDBA4C9FD1AF873D
-:105D5000E96332209CACDEC179EA6D993E4FBD1DEE
-:105D6000A68FD380F419D4BB71E5BF23D327FF9D41
-:105D7000307DD2089F21BD83F3D43B327D9E7A27AC
-:105D80004C1F37E133AC77E3CAFF8B4C9FFCBF84D9
-:105D9000E93384E08CEC1D3E4DEFC9F4697A2F4C59
-:105DA0009F3C8233A677F88C3D25D367ECA9307DE4
-:105DB00026109C71BD83D3744AA64FD3A9307DA60B
-:105DC000109D2FEDDDB8C6BE2FD367ECFB61FA5CEA
-:105DD00045700A7CF5840F03388ED8709E3927D31E
-:105DE000E7997361FACC213853014E4ECF70C6B794
-:105DF000C9F419DF16A6CF02827365EFE03CD32603
-:105E0000D3E799B6307DCA88CE57F56E5CE3DB6583
-:105E1000FA8C6FE7F4A9B278263BD0BE4B649EEDB6
-:105E2000D0E492930D079C9037D99907C1BEA48402
-:105E300076207C582BC92E543D9A9DE2616887CE0E
-:105E400070BA3DE8F7316AF6086BA1FD827D57A272
-:105E5000E40FFAD230E916C4D701565BA45D923044
-:105E6000364EB28712BD4952BE4F615FA97E4A517C
-:105E7000B6549E567291549EE1CB93F29965E3A578
-:105E8000FAFDAB2749F90BD64C97EA67056649F945
-:105E90009C9AEBA4FA836A1749E517D6954BE5431C
-:105EA00082ABA4FCC5F5FF47AA3FAC619D543EA25E
-:105EB00069B3543E32F40B293FEAD00352FD312D31
-:105EC000DBA5F24B8E3D2A958F6BDD23E5279C7E6B
-:105ED000466707CAFBFFF5058CDB831966B20743EB
-:105EE0000E33E5CDFB6C64FFEFC73CF0D3DC7706E7
-:105EF000E5CDCF2E7627E37E1A01C07A5FD0B7ECCE
-:105F000042F4F7DC3CDE77A10BBEDF6CF68D70450A
-:105F1000F1477854DF3E03F98B5A14968EA9DB8043
-:105F2000699C51ECD72D5CBE3666E53F148890D352
-:105F30009AFE30FF207FD86026FB5593EF8DFD4BF6
-:105F4000D31746F4B3A1BFB964FB50FE7DB11DFB6E
-:105F50002B7A11E75995B96330E2A5EFC7923D5608
-:105F6000EAC73AA08CFA790DFB89F07B590694E9CF
-:105F7000FAB1966C17DF453FC7705CB1FAD9983D0E
-:105F80005E1ECF8072EAE75D5D3F1B0794EBFA89E6
-:105F9000E3E381EFA29FF7CE3B9E9C89F2782E58D7
-:105FA00049FD74E8E866B960A5AE1F3BF583DF17CD
-:105FB000933F17760169C0674B4729C9C17FDA58FB
-:105FC00000E4C29C59FE6BCCB3B76C6C10F6E38650
-:105FD0007EA11ECBE5FEA3A70D49349ECFE280FF34
-:105FE00011766AD77E3640FBE2A5024516048C6026
-:105FF0007F5B296473C9AEE20137B9216D3A30F095
-:106000006EEC678BC33308F26D4D93CD8BA3C8D371
-:10601000D25AD3A9D648BF88B6BF99C472ABA1FFE4
-:106020005D369794D7D2958A8B097F04E54FC0BE21
-:1060300085C17EE0CFB02F6040AA774D7C9FF60EE1
-:10604000EC6F30DF0AFB1B2C676C2DB53B21FCB4D9
-:10605000276E578248EFCF7EF24313E9F1007B357C
-:106060003D15FD6EFC6FC19A78F4F187F15B18E87D
-:1060700023E5415D661AD2695F48FBDF8EA72DC11B
-:10608000ED48D79A4CA0A9A897CDD8EBB0C9CD4878
-:10609000A26CA6612C63B3AB8BA7A6D12C52FAAF2E
-:1060A000023C67358E34410BD6666ABDD163EF8200
-:1060B000CBBCA613481F2BFC4338D714423EA2FF8B
-:1060C0006B8BE4FC5CA676E581DF838DD9826FA2C1
-:1060D0005FB7D7847C2D4AE5F8CCC5340F8BB9BFA8
-:1060E000A3C4C5DB6AF8542D36B110ED4F03290C5B
-:1060F000FDD18164AA779DB6CFD4E15762B27A8B85
-:1061000080AE250B8D44573DBE6FEE8BF71A86434C
-:106110005A73B7095D9B3DE13FCF2797B332DE9FAE
-:1061200046574D5E4E09FE9E40FE43FA3EF21FF07A
-:106130003E29F8DF25C79CFF5516DF4CE47FC7FDDD
-:106140004646FC127C9F23F8BEB456E6FB1CF49333
-:1061500043FD39ABB382EBB17E5D1F89BF307099CF
-:106160000EB5774D05B5DA0DFFB7851C5C57B3FB4F
-:106170007964EFF565BAF1093EDC28F8305F478FA6
-:1061800039826FF305DF96B1C06D19E43F0A9AD0EA
-:106190002F36AF4C61A82FAA7EAAF1AD55E29B4FD6
-:1061A000E39B0EDF1B05DF6EFC09E79B1EEF56C16C
-:1061B000B7D6BA8F4D2CBB3BDE7A3C17ACD18D2BBA
-:1061C000A0E75BAD38777099D1DE29F616F439195E
-:1061D00051FF9AC22BFB9C8CD00BD716154BF9B9EB
-:1061E00025F3A4FAF37C0BA5F2EBCB964BE5F3ABCE
-:1061F0007F28E517ACF989547F6160AD54BEB8665D
-:106200009354BEB4F62E29BFACEE7EA9FEF2E03662
-:10621000A97C45FD23527945C36E295FD5F4B4545A
-:10622000DFB06FC8D5285F2F1D3532F4977DEA792E
-:106230009FFC759F7A4C1EAC538932370EE5D94DC1
-:10624000F27CCA9F4BE969BF87E4FD8C7F2CA56D6A
-:106250004D07ECE87FAC8A03BD9F0876B8F1CDB559
-:1062600035FD70BD81F6E3196B36B6AE0D40FE000C
-:106270001E46C1BC99516766A1510CA4BB6F589EC4
-:106280003B8C11E5AD3D94D7A92CD4A77BF98CD6D6
-:10629000E8DFDB958EC119E8277CC3C27646F8EBB0
-:1062A000BA9F57B04CB42B62959F35B0B2C8F3ACCF
-:1062B00093467E4EE2344E3A698474A599CFFF9599
-:1062C0007B32263127E64383ABA3F85DC2FD350060
-:1062D0003269C8E71C69DE2FABBBB86B9E33EC2775
-:1062E0009BE476797094F47D45FD04A95DAEE27B74
-:1062F000D708F5CEEE37D27ACD4207065C330CF1E3
-:10630000F39EC4EFAC2985ECAE16BFB7CFC9818C24
-:10631000FDD15F48E9ABFE224A5FF397507ACCEF9C
-:10632000A3F44D7F19A57FF65753FA8E7F0DA5ADC7
-:10633000FE00A527FC35949EF4D7527ACA5F47E940
-:10634000697F90D233FE7A4ACFFA1B286DF337511A
-:10635000AAE9CF9EE4EFB4585FCFA0FC459133F398
-:10636000AD6C5DCDC42E398B532DEB50CE34FACEAF
-:10637000A8B308794895E42111D76192B31ECAEBFE
-:106380004C420E63B58F5E8EF2D6F77B9037C6D641
-:10639000911CCC1472F75DE58DA1373E05E52953BC
-:1063A000274FB21C6A72A4E9815CA568B83AA64B73
-:1063B000AE661AB99DA4C9D5CFD14E8C626FDDA04F
-:1063C0002A62FDE3F611F36518D07E5B25FCFECC56
-:1063D0009D4EF94ED1F77A00D782F5D4602EAE23C8
-:1063E0009DB97F1B8CFEF1CE6316867EF858E3D3F1
-:1063F000CB4B6CBA7B69FF501A84456D54F7725BC6
-:106400001CA7ABCDC00A591E9ECFE61FF3013FE388
-:10641000FEF3E23CDCD7C27795915D15F41447F1A9
-:10642000B73394F1B49EE9ABD53FF5C097F9786ED8
-:106430003E53CCF3B803467EAE1D7AC8734DC4F903
-:106440000CECB7D3D1EFDC31C8EC22FB21D457A63A
-:1064500063B0AF44C703833E1B8CE71B9B400E71A8
-:106460007E750E1C9CC0CE231F3DE9F99EE8B9281D
-:10647000D8B797F434333C37027A6EC7FB2FBDA5EB
-:10648000674F7AB227FD786233A7B353D8A7B1E834
-:10649000DC3E09E65D1439BE475565396603F97976
-:1064A00087467FDC9746D0FF52BB9BEA3FB7EFADF4
-:1064B00001ADD04F67E385098C9FE7905DD7F1A4CC
-:1064C000B0DBDD99321F5BFB125C0DCE734FBE3E1D
-:1064D00000F7C9B76106E6D993F145BF5253BAE058
-:1064E000F5F61C3ED6B8767FCBF9D99EAACDCF96CD
-:1064F00001284F9F093D10737C3DC9298E0FE05C38
-:10650000A5F0F16D3016FD0EF54C787CA3537A356D
-:10651000BEAA04335346007E0EB3992530B643F528
-:106520001D54691FE7690DA09F625FBC673DB0A461
-:10653000CA79E6E5901BDBC9FE8C15F536976C3FF2
-:1065400025BA64FB29C315693F751E7AC8E903FCA7
-:1065500056A51B5C2747E13AE715EB1C5F5735FC56
-:106560002A1AB25C76098E9CEFAC550A1B489EDC59
-:1065700009B3A39C9769E9AA74B3EB24AC5767EA03
-:106580007312B0DF337EAB8BAFAF2E17EF37DD1555
-:10659000B9BEAE5C1347F535FC62C1FD67E3C75871
-:1065A000237BD78AEB2294E5C4AE1F939FEA27662C
-:1065B0003A976E367D86F6BB2D57B3DF55CA6B70A2
-:1065C000AB1A8C01CB08FCBE4BEA0FDAB9B53366C7
-:1065D0006C175B6E54764AE327F0DF8A07EFB46FDF
-:1065E000B5129F7D003101E0B5ABF61A94AB132ACA
-:1065F0009FCF55424E2BACAD669F9BC8DD82F2BC4F
-:10660000682CD326CCDCB7404F7FF0A289EE69B16D
-:10661000AF007A7ED7558125ACC8894ECF458D2BEA
-:1066200066E0BAFD8141DB0FD7E6E3B8CF31432105
-:10663000EAA573EC8FCE5111F3758889FB63580D71
-:10664000DFE704E01F8E6F69ADBCEF595627E74BBB
-:10665000D9AC54D4B7A55B4C2C08B82FC77D933662
-:106660006ED0BF1926EED758C6AA37E03EFD5E139E
-:10667000F7F72C72313513F0AAF88F5FE6A3DFC766
-:1066800063E27687769EBC3C89E35D3E3B68F642DA
-:10669000FD771B47CD018D0BED831BC8FE29669E40
-:1066A0009DAC3BDD17D7C8F8F584BF1E5FCD0EEA61
-:1066B00076AE2DF048AE57BCC1287AEE329322F662
-:1066C0007F7C7ECC36C9FE9C7926D9EFA3C981494F
-:1066D000C8C109D577B5690CE73BF251513BCCBE37
-:1066E000887AE6AE7AB3CF57CF82F58C546F9E2965
-:1066F00005EB754CA3FD3103791ADA55CFD605EFBA
-:10670000460E4FAE57F11F8F3D15007929FFED3D25
-:106710004E06EBE6076A6DAA07BEAFDC799BD30B8A
-:10672000E96935E0447E7E10341646A3C796303DB5
-:10673000BC7605FD69423E594D80FC149FED34B98D
-:10674000C8CF5F6F0959404E2B1B97CF60C3297F7D
-:106750009CE7377E64C47C93CCAFF25FDF93EAE6BC
-:10676000F76CB83F8985C8CEADDCF1DE345C2FAA6A
-:106770005807C999BE1DF6FF7912CDEB85E684EE68
-:10678000E58027F913AAC42CAB6AFCF9474627E633
-:1067900065F92813F62AD209F7F9B7991CC9A7E2B7
-:1067A000217B09BB04E7B9460F16E476EBFA47EE06
-:1067B0001B7E1CF039BBE345A73234523F7039EBE6
-:1067C0006C58FC2BAB21B61E6903398CB48F00309A
-:1067D000B57337097BBB99A72B4D2127DE6759B9C4
-:1067E000CDE40109642B1F3332BC07C0DEB004D1F5
-:1067F0002FBAE2B1E75F1B0F745FB1DB943C830FEC
-:10680000C7AEA476F1A50AFEB726AF8B0FE54F3CC5
-:106810006F760FE3DF6F49EAE2C78ADDFBCD6C5884
-:1068200077FA4D6ED86F6EB547E14BC3F169B8CEBC
-:10683000AE7FE4AF66F4277EB04F616959DDDB9728
-:106840006D7B9ED63BA413F151F029CCB76EFC0AA8
-:10685000CD7C6634D573A11E8CC5AF6542EF823CFA
-:106860003FFE0CDEFF79D3E2C1F1973D7E9313C763
-:10687000F1BE5ACDE5FA97B7A5E2FC2E3305525D7D
-:1068800094F2EF650FFE88E46DD9911FA592BDC00B
-:10689000BC1906D2C5810C1CDFD2ADD7D2F84A99FB
-:1068A0008FE4AEEC97C622BC8FF8A9CA0A77479945
-:1068B00017716685F0797F3B183230BEF7717F899A
-:1068C000FAEC8F46BA17C5D80FE9DED88FC45861E5
-:1068D000E5A3FCA756CEA7E3424FE24496E475C772
-:1068E000C616E4CF99FEDE343CE7003A0404BD94BA
-:1068F0006F00AEF1C8D434CE1FE656F3453BD0EF5F
-:1069000093F13BD66F31796DC3A576421FF2FE57E6
-:106910008BFE01EF385CAFDE4F8D6EEF8D11E383A0
-:10692000BF1616215F11F39BCFF71D9BF8FCD6E62F
-:106930007BB0B810CB3F7995CF1F6C87EB03E01588
-:106940004AA3F2FDB315D207B0AF8E36AF7798C425
-:10695000BC96CBC152A4F51EF0569584483901F877
-:1069600049447FDA07976E817611F65715F647F599
-:10697000CC5DDF23D68765420F98CC30FF2FEE9A8F
-:10698000FF6C2B9FF73DD9932B4DC1871FC0F9FAA0
-:1069900086C51370E37C3515E1B83FDC75E0B5EBD7
-:1069A00040AE3F6CD0E6A9AC3FF5F3B46CCF1816FF
-:1069B0006D9E7E6887FD55B4790ADFA3CE537B2B8D
-:1069C000C9F1F7AD3F35BA0D35CB7A13F5E033EEAB
-:1069D000D8F4D3EBC1DF9BDC4447BD1E84BF5759BD
-:1069E0007E77B9D3E44D93B3F2DF545C80FA262C62
-:1069F0008F9ABC85E5519337FD3865BAE9CBFF2AFC
-:106A0000F4CDF5D6C26BD02EB67630DAAF14CC36D4
-:106A100006719F6CFD84D17C9F74433CE5E71A5B53
-:106A20009F409BEFAD8AB9C3701DBF9E054CFCDC37
-:106A3000BCD64476EA57DF7C3311C6739DA0EBF5D4
-:106A400040E6AB800F25AA128A033CE7A92C909060
-:106A500084FE62859D88C0E3FA32398F7F97A576E0
-:106A6000C1E9A9FEB7B5ABBF6B7AC4CFCFAEFE8488
-:106A700029ED2FC0708E90A3E2667E4E51355A09E3
-:106A800066D3FC6B558B22F6098F99B99D7164CA48
-:106A90003563907E05738725907CD70EA17D609528
-:106AA000D05B9D017702EAF3CEE61CDAF7751E5A39
-:106AB000ECF045D15F07849C3D2FCE59DAED4AAD0D
-:106AC00011E4BD9D7590DD12B0DBA2FADDEACC06C3
-:106AD00061EF08BEC19F11FA2F1172380F9A26E498
-:106AE00045F06DF6551FA8CEEE7CC0BF1311FB8696
-:106AF0007F94BE28D748DF03B6D6694551FC338F53
-:106B00000A7D7DD9B35F98719D9BD25CA0221DA7A1
-:106B1000D88D92BF63BB365F87B2A188D765CF2E71
-:106B2000BF630CC871D521A3C706E3AB6AFEC8ECEE
-:106B30008BB27FD3D313E1A3FDD86AE6F6F15153AC
-:106B4000D152A4EBD16BF979EE9FCC9E8A6878CEB6
-:106B5000B6723CE7B1A24F472BFF7AF42D98EB08B1
-:106B60004D027A74DAF9FDE4EEF2C7E77DA74B092E
-:106B7000AE55500E8D3C9FCCEFFF4E63BE3B262A98
-:106B800034DF2F8FD45F054DC58FE17D96CA66C572
-:106B90006580F24AB5D58C725CD5B45B45BBFC0709
-:106BA0006EFECE82A9D5C36647F8B75ACDDC9F7476
-:106BB000E06FD7CD47FA7E3CDBC2102FEFD08F9C21
-:106BC000B8DE7FDC3C8AE641AC71FDC1EFB9660AF4
-:106BD000FAE3CD5C9FE9E5615A72BC94BF7632EB73
-:106BE00087E7BC97595A6FF244E1DF3A0B9FA7BD84
-:106BF000D66FD6FF61FA6D22E8372ED7A648FD364C
-:106C0000DDC2E53E42BFA545D36FABD6BAD3502E09
-:106C100056EDCD4943BEAE3ABC34259A7E7B41EC5D
-:106C20006B0F8B7BD2EDFD40BF8D88D06FFD40BFD9
-:106C300045F1838FB66876670FFACDFADF33FF5ED2
-:106C400040FD1665BC5708B9D3F45B61F35AD26FA7
-:106C500085FD8CD27DA4CB2CC28E8BA9DF16DE7372
-:106C60002DE54D9EF828F2837445FD7658E839EC01
-:106C700007F5DCCF2CDF4ECFCDB3727C7BD473FF16
-:106C80004D74D6F4DCAAFE0AD92FDDE590EBB95598
-:106C9000595CCFADDACBF5DCAA415CCFE9F5DBA4DA
-:106CA0006EFA8DB7AFCC85F6B44FCCBAEF06BCCF39
-:106CB0005762F258A1FE0CB7F6BEA07A4CA4BEFBF8
-:106CC000992586BEF380BEB3F7ACEF5E417DA792F7
-:106CD0001E1B88F3482F1FD307C64BF7D58E7E7136
-:106CE000EA37BFC5F9F20723DD077ADDC0F743FBBA
-:106CF000BE38350AE7DDCB880FCC979D42FEDAFC23
-:106D000063499F4E1ECAE77BC5A1385A272A1B1527
-:106D10003EDE5B94A01BD781BF7D4EFBE4F97BF97F
-:106D20003E79AE85D383FDD8C8DF4500091646C835
-:106D300043C9E7E5E4E72B519915EDD70587A67F11
-:106D40008076EB82CF6BC8DE5D80DFF17EC5EED64C
-:106D50000D99D0EFFCE50AED3798B80FA1DD97B893
-:106D6000BE793FDD5FD1DF83D0F4F9FC6AF9FB0225
-:106D70009D5D7F408C13EC59A20B7BC518D53F77E6
-:106D8000404F0F0F1F7FC56A6E1F87E901F4712BFB
-:106D9000DDE9011C9DB130B56BFCF39F8471257753
-:106DA0008D4BA3877E7CDAFE6481981BB1C6ABD184
-:106DB000AFDB78357AEAC6FDBC45D84517B36138F4
-:106DC000CF5E37F8EE188372F17B183FE03367DE51
-:106DD000A0B4483DFCA2D0E757F98E4F497523BDBA
-:106DE000F8FBBBEBCA763F9F0AE3B8DA9B9587575F
-:106DF00011AEFD9BD9877E8403B60ED26B9A5C5D83
-:106E000068E572FE7701E7685FD7145A3F9A141756
-:106E1000CD97904E6F897B6155404F9C8F554D6249
-:106E2000BD0179C3F9364D5B7F90FEF09F573573F6
-:106E3000FA57552B44FF99ACE320D2B73259F1846D
-:106E400000D4B4A6DDB7E13DAA176CF01DE76D993B
-:106E5000E2D9CEC961CF488D2A976A34B964D54347
-:106E6000C8AFA0AD830BB05E12BE17793D05ED1320
-:106E7000BDBD7199A5E528E271D98F4D6C1BEB6EF4
-:106E80007F68FCCE857FDF44BBCFD383FC0E12F638
-:106E9000E50B486F3BD2B5C38C725F15E2EB8656AB
-:106EA0005EA5BAA7107D347A37C1BA309AD31BDFFA
-:106EB0007DE9E979B5964779C6FACD8A09DB5F099C
-:106EC0007CE80345930D5F1CD4E417DF89E9E98270
-:106ED000FBFF8C88F98E7A29F2DCB1B2E908D16522
-:106EE000FA6A30AB22E88EFAEA7CF4E9361F9AF6A9
-:106EF00047BD07F56DE7C38556793EECB375BC38E1
-:106F000002FD5B7B15D207AC3951DADF5F61E5FB2F
-:106F1000A603361FC96DC76113DDF7D6EB8DB182AD
-:106F2000FEB89F887C0737190782E7BB2E1B7B576B
-:106F3000C3239BCB4FA4BE7EC1E6233EC5823F4DFB
-:106F4000C08F652F85F1C5FEF03CC52DF7A75F2FDB
-:106F5000343F4F4FE3BA46ACF7DF755CE1F349D6F7
-:106F60006266DC9FBFDB1C71CE3447F8F9353F58B1
-:106F700044BD999631B1EBA1BF2504E37E61D743AF
-:106F8000E4D73DF7E8F19928B72B7E676456E073A4
-:106F9000DB2E070BF17B14665C57CB1B8D51CF4565
-:106FA000185B4FF8ADF8AD83F44AF91E4B7006B488
-:106FB0002F7FEADDE1E89F6A5BC7F54BE051211FB7
-:106FC00081D6E1785E5EAEF2F3623DBC1F0B79398B
-:106FD000FB747C09EA47A59EBFEB2C6F986BB2440B
-:106FE000ECCB2BF1C08DD7A37BC8814714F28377FC
-:106FF000C76F2DAFF708D77BE54DA620BE0F2DAF8D
-:10700000DF46FBD9AAFA8FCC68C74DFEED63644713
-:10701000543519653F61BD3164213FA6F138A67A28
-:107020007F5D656305CDC7CA06E10FD3F98B56FCBA
-:1070300076EF530120CD8A277EED443D73A665A7E8
-:1070400093FC70F5DCCFA6DAD5E87EB89EFC6F0D18
-:107050009BA2FADFCEE07FC0FCDB6A95FD6FACBE81
-:107060004FAFCEC1573CF6E983782E7476CF870FA9
-:1070700022DE2BBFFEF8C19FA27DB2CFE6C2F5AEE5
-:10708000EAD1A3E457D7DA3D25E655DB23BF7EF8E6
-:1070900001987F6D6F58E8FE55DBDEF707B8619CFD
-:1070A0006DBBBF4845FFE5EABD5369DFB2FAC9C908
-:1070B00069E7BB47827219ECC579889E0F071A8D64
-:1070C0000CDF419E3B66213B23EC476DA8E07E69C7
-:1070D000B7F09FEE8A7EEEA4F9FD2A1BAFB9FA52F3
-:1070E0005CF71A4D1E377D177EC09EFCA6AF023F8F
-:1070F00047F4826FBB845F5CC7B773F81FC09F3FC4
-:1071000059657FF3A78D4B7FF5009635F689E937F2
-:107110000DF5825EDAB9D636ABF71D2BCE873DBFB3
-:1071200021FF34F20B6C6ED6F6D8A703D0DF70DAED
-:10713000D47123DDBFD86BA17B42E57B5FA7F9D17A
-:10714000F6E4113A2F62E25CA98D85FFF83980D808
-:10715000CB54ED70707FABA03BFA63DD4EFA2EFC92
-:10716000AE5C6E357F6C2C3F6C1F9BB8072ECED962
-:107170002A76BC65663ABFB63216F9745C3A17D403
-:10718000C6AD87E7423A5C12799E10CBCF2DF468EA
-:10719000984FFC1CA16D9B385F089F1B30D62F0FAA
-:1071A000EFBFF3F3EEAAA0F23A8B321FB5F304A7B8
-:1071B0004D371F83BD3B47E819DFEF460FC5C6F7C4
-:1071C000AD1A5DCE7E155D1F0FB129E2FD812FD76F
-:1071D00016B1EE2C10EB4925D08BBF27E3F89E1596
-:1071E000FBBBB38F1A83B80FDED07080F4AA7E5E2B
-:1071F00057B2E8F143C6DBB83EA96CDA3F1CF5CFC5
-:10720000D9679F26B9ABDC75DC1C003807EB9F30D3
-:10721000B70EED9273D4D7C1087D7DF6F1FDC3F9A9
-:107220003907DF47EAE15F21E05735CBF0AB767DE8
-:1072300024C15F116830BBEC3DF77346F5CEC5F154
-:107240009E6931515C94330DC6C268F14A86622052
-:10725000A9942E3A6D70F0F771C62433D991AB1D05
-:10726000638F2524636A76E33E7AFD5A7E1F72FDA2
-:10727000CF3CE9C897F58973E81CA856474757B231
-:10728000AB00F7D7AE2945A351ACF47A20D16B906F
-:10729000F05EED284CC3F7DCB70A7B84A91E7ABFE9
-:1072A00067744E2BC471185D06972DEA3ACAE199AE
-:1072B000EC45142FC2E492DFD37DEFF11FDCFDE437
-:1072C000F80F817EFF68FC07467130FEDFC77F083C
-:1072D000603FFF02F11F42E4B7D1E23F247FCFF1CC
-:1072E0001FD63239FE83E06738FE83E0E7FFC67FB2
-:1072F000F8FF2BFE8331EEEF53303E8316FF21253E
-:10730000CE3C3532FEC38571095323E33F8C8B4B52
-:107310009F1A19FFE10771595323E33FCC8FBB68D4
-:107320006A64FC87AAB8515323E33FAC8D9B48792C
-:107330002DFEC3DD7153A7CAF11F664E9D02F9B63B
-:1073400038DFDF71BD8A15FFE13D9C2C637A8EFF2B
-:107350000070CC716362C77FD0C38915FF01E02440
-:10736000109C18F11FBAE11323FE03C049273831DE
-:10737000E23F74C32746FC078093457062C47FD008
-:10738000C38915FF01E05C1497123BFE831E4EACCF
-:10739000F80F006714E11323FE43377C62C47F00BB
-:1073A0003813094E8CF80FDDF08911FF01E04CA570
-:1073B00071C588FFA087132BFE03C09949F8C488C4
-:1073C000FFA087132BFE03C0994BF8C488FFD00D94
-:1073D0009F18F11F008E8FF08911FFA11B3E31E233
-:1073E0003F009CE5042746FC073D9C58F11F00CE5A
-:1073F0002A821323FE831E4EACF80F00E7A7042752
-:1074000046FC876EF8C488FF00706E253831E23F75
-:1074100074C32746FC07807307C18911FF410F27FA
-:1074200056FC0780732FC18911FF410F2756FC07B7
-:1074300080F32B821323FE43377C62C47F0038F530
-:10744000248731E23F74C3E7BBC67FB085062A3983
-:1074500014FF81E24486E33F247FEBF80FCD88EFF1
-:10746000FFC67FF89F19FFE166BBEFEB38F2837E22
-:10747000B7F80FB6F86F17FFE1667B517C3CEE2F33
-:10748000BF65FC87D4F86F17FF01FA498F1F13BB44
-:107490009F58F11F7274FDF414FF01FA1974DEF1A4
-:1074A000C488FFE0D1D1EDFB8AFFF045DCF9E33F72
-:1074B000FCCBC559806D0A9EFF149328B27F99B802
-:1074C0000BD7C6FF93E32E90B1F0AF1477417BBF8B
-:1074D000DF60C2F5EA4DC1F7D7845CBC25E22F1C02
-:1074E0008B197F217815F94597CBF117A60B3ECE66
-:1074F000F3C9F2309DF1F386E953B278BCCC325D2A
-:10750000FC855CF9FC7A86EFC81400C7AEF2C8E3CC
-:107510003822E46166C947CF217BAE1E1B3DFEC207
-:107520002CC18F621D5DA60BBE158BF47A7C920276
-:10753000F23CA3EC888A749DE96E55C9AFFD038DBA
-:107540007F6E897FB3055C3DBEB304FF665DC9F9FC
-:10755000A7C7FB55E49F13D2B251C43F3DDE7A3C2E
-:10756000F5FC6791FC8E889B51C0E4B80B93AD721B
-:10757000DC85A92E39EEC215E972DC852BDD72DCC3
-:10758000851FE4CA7117AEF2C87117AE1E2BC75D16
-:1075900028F6AED5C57DD8A48BFB70972EEEC3FD23
-:1075A000BAB80FDB74711F1ED1C57DD8AD8BFBF04F
-:1075B000B42EEEC37E29BFB8E6B0547F69ED112921
-:1075C000BFACEE0DA9FEF2E071A97C45FD07527932
-:1075D00045C34752BEAAE90BA97E6FE33EBC2ADE33
-:1075E00003BF26DE031F13EF81DF8C11F7E1AF3FEE
-:1075F000FFE2B6C8F7F85FFEFC9BDBF03DBE41BC86
-:10760000838D15F7215C1E23EE4357FB6F1FF72177
-:1076100025F99FFF0E3FC7CECF3727C44FCAB1A76A
-:107620007CF777F8D716C9EF99E796C8EF9973EC0E
-:107630005C9FCFF3C9EF9AAF2F93DF3597D97CD9F1
-:1076400088873EEEC384786F8E1DF5A5789F1FC294
-:10765000F7A9B0363E8BEF53217D0EE33E407A1002
-:10766000E33E407A08E33E40FA7B8CFB00E94B188E
-:10767000F701D29731EE838A712302226E448D88FE
-:107680001B512BE246D489B811411137A25EC48D3B
-:10769000681071239A44DC8810C139E13F44E949FC
-:1076A0007F0BA5A7FCC7283DED6FA5F48CFF34A583
-:1076B00067FD1D94B6F93FA7B4B7712334B9FC3305
-:1076C000DA0D66EC9FCBB126A733EC033744CA69C9
-:1076D00091FDA20D28A7B1E245CC459AA6C48E170C
-:1076E000112E8F112FA2AB7DEC781169A3BFBF784B
-:1076F00011FF16CFE5F51F8D1731BF5A8E67B060A9
-:10770000CDF9E34594D98A56A35C6AF2F86FF1FC8F
-:10771000BCAAA77811DBEC8A58AF812E6877015D8F
-:1077200068BDEEE1BDFD738E8773713FD1997BD14A
-:1077300079E31CE8E52236BD795C83EBBEE73811BE
-:107740003DD155ABFF66398F5FF06FF1E78F5FD0AA
-:107750002D4E444FF105067D467AB2B771227A5A12
-:10776000177AA2E7ACEF394E444F7AB5277DFAC7B6
-:10777000E99CCE13E2CF1F8F231C17CEDA72901A2A
-:10778000BBBC34B555F10EBC60B68BFC27EDBBC459
-:10779000BD312F73BB52F93B75B437DBF7240C674F
-:1077A000F47EDDC5BCC09F78F15DD9B57F3F9EA753
-:1077B000DFEA64DEC4248A07EF36E6E03E6CA415F7
-:1077C000FD29158D1FBDFC3B806B6B36D27DB276DB
-:1077D000C0A185EC3E6F22F22D9EDD4EFB743CE392
-:1077E000FAA64FE47B66DDEF37609588F39BA946E8
-:1077F0003BED9B3AB7F27B9E4676F17D1347D37DF6
-:107800006A167413FFC84E5D21F0ECC414EBFBAC98
-:10781000643F2E3BFC447E88F1F3CA48BF419F423F
-:10782000D94F5367730EC777952CE06D41FB7B8969
-:1078300080975224FB6F3E5C547808CFE997F84A52
-:10784000E91E425A89ECCF61E2DD386EC7C2F7E526
-:10785000009FD226853DA0747F475ED67CD706DC8C
-:10786000E72C0FEAED6F968B7256CEE23CB8EF5DD7
-:10787000512F973B1CE23E879DD97B45B7D60BEF36
-:107880009B987C5EBA7942587F9783EEC32E3BBCAF
-:10789000D88CCCB2A4CB74B3B965BAC5E7CAF4D15D
-:1078A000D3CFE191E9A3A75FC258D9FFA5D14FBBC0
-:1078B0006FA832715F34C8EF91767B87DFB48DF0AB
-:1078C000D4D34F4FAF510E714FA28B5E45D6545259
-:1078D000F98467861A22F9D6CF874C7B48C1FFEE20
-:1078E0009F1C5C4BAD3C0E15F5563A07CD9425BC5C
-:1078F0005D3CCE078C2BCB3C341F70478FFEDD7870
-:10790000F66721F7EFB26F20BDA9F8B9E38BA07439
-:107910002BCADB08FEFB0BE4AFD27E3781795CB863
-:107920008F6AF05BDD4B543C1764EE2503F13CD0CD
-:1079300045E99DE2DD6FFB5046FBFE86D027A97826
-:107940008E76675EC74CF43F542D6545B87EFDC802
-:10795000C9DF5D6C12E90827F7CF6C2E3230EF6873
-:10796000FC1D1E635041BFABCB7BF872B4479B4DEF
-:107970006E7A47ECEA78F97A2A1F45EFA3330CB503
-:1079800023111FA84FEF6BDB9BDF752E8ED0C36DCD
-:107990004D770FC1FBC5F71BA2BFEB2D7568EFDB61
-:1079A000F8FD8E115D71064A1D63281EC19DD9D058
-:1079B0004F657127F15193CB0982FECF954E27FC7D
-:1079C0009E6C56DCE8AF9B66BCE107C300BF714705
-:1079D00055AEBFC4BDEED1A2FED3CC938EF88EBB04
-:1079E0009429387FC6BDC13C0124717529DDA7FBF0
-:1079F0009D73DA21E4D7946690279C0F67ED1EBC37
-:107A00002A3FA645BE2F9738C57700EF175E728CC8
-:107A1000913EBBE498AABF1F63C4FDFEB856F9FBB4
-:107A200004DDFE739D26774E968A72B7E52B23E11F
-:107A3000D5DEC13CEB006EFB92BE746EDBFE09230B
-:107A40003BB1FD2B6361B4FB25773BB8DFEB7E33A5
-:107A500023FD7D7FA99DDE393C5B5A7E01DA179FAD
-:107A6000FDC47741343F65849D96C0DF9F7B13D86A
-:107A70005894C35B154EEFDA8CA228EB9626779AC2
-:107A80001C6AF297511AE78B765F33D9C9EDA34987
-:107A9000A5B98A19E5679FC290AE6DEB00AFF3AC54
-:107AA000DB01B62E13F1A96AFA98EE61599B95A8ED
-:107AB000BFCBF384C3C9EF03AE0BACC5FB1737C311
-:107AC00024423D9561AECD8A063FC0B6905DFA80F6
-:107AD000C3CDDF0D58451C21B53603EF23B4354D1A
-:107AE000BE7203E0F900CC07E4EFFD260FE11DA80C
-:107AF000608CEE930A7F5DBF996CDBE608FB77AF85
-:107B0000A3E030CAED6107B71BFBF83C0AE2EDF9D0
-:107B1000FB5F9D08BFFD730BF1AFAFB037B57627A4
-:107B20001D9C3E254EEF016CCFCA9249F9787C4EE0
-:107B3000F7923EE837077A47B1AFB4753DC9C7E859
-:107B40007C22C96E089272F27ADD2EE9BE7780E659
-:107B50008D360F584861F85E5FD36F4AB31272805A
-:107B6000DC8FB6DA4378FF2CA90CC69D8CF13CACB7
-:107B70001C5E8B7A56F66B813CE6A371CFE8BD3F65
-:107B80003A5211BEA6F7347D796B22D747B7DEA5EE
-:107B9000523CD0AD6AAB0DFDA9595EF7240C4D9354
-:107BA000A4BAE95E4AFF323E0FE3737E9918B6032A
-:107BB00060928FFCDAB820DA7BA60C94A714A49705
-:107BC000EF4307A4C30F753C8BE682C7C6FAF0FBF0
-:107BD00053424F08BB669A58EFC6BD67E0EF284393
-:107BE00097B3C8F7457A3D0172FF27FCFD9EFBDF86
-:107BF00053294E68583F944EA3F58919871E403982
-:107C00009BF022E3C751423FB8E01FD2E792977C36
-:107C1000EB118DEFAA17F4FC66216B388F3FCD3640
-:107C2000EA10CCB7C875D629D67BA1476E2A1EB8F4
-:107C30001EE797264717DCE231FA22E8A86F1FF605
-:107C4000532AD6F077770EEA91978C783FACBD0037
-:107C5000F80D747912E70BD03BF193E095C8F72D3E
-:107C6000CD57D850BE6F0D4D72CD803689D6226269
-:107C70005E22F3923F270FA8837122D69350C07ED5
-:107C80005D2DCA72A6E03DAE42C9DFA3FD2E1E0CDB
-:107C900094F812E603C871E43D564D3EF5F2A8C9CA
-:107CA000EF7ADC60E1F91D7ACC21352A0DC4200B76
-:107CB000DBEA423DABD997EBC3F65C22ED33560BC2
-:107CC000BB68BD7D9A95D4C0FE645ACF57E3FA04D1
-:107CD000E35F9DC2681E68E3D0CB63D5E706168CD0
-:107CE000D81F54A91D748FAFEA73330BF6C171FB13
-:107CF00026E1B835BA8C1474D1D321DB29F69B82E6
-:107D00001EB1F1CC77E1FDD944AB976D243C27D16E
-:107D10003DE786509E15D7DBDB7478F602BF39D17C
-:107D2000F053ED31F013F1DB2630DFEF5A415EF313
-:107D30006FAACBE0EB057B353D827FFA7933B6A99C
-:107D4000FA803962BE687E5DFD3C19D1CCAE41BA85
-:107D50008F0BA90CCF5F7B9A2F9F88F156C5737A42
-:107D6000B5CFE9188CF2B943F5553BC9BE6835600B
-:107D7000DCDFF6A719CD67CFFE934E8A6FD4D2BB56
-:107D8000FBE99A1DA5D94FFA7A9AFDA4E95DED7E2B
-:107D9000F876A7CF8FFD2B4D209F30FEF52EBE2FFE
-:107DA000DAEBF0ADC3EFF130063C4A62B9A12CFE2C
-:107DB000FE5596FF58F21EAF93E706A013FD4E1630
-:107DC000E8FF414A773CB4FEA73813F9790BCC663B
-:107DD000D443FDF219EFAC92D1FDC97EC3990FD700
-:107DE000A77E79FCDE5F50ACDBDB84BED5D2BD8ED6
-:107DF000A2FB117F93CA0296BCEF8E37A28AF7B11D
-:107E0000B73BBDF7A1FC590BBD348E4C17F3A0FD59
-:107E100099A93628F86E3269A55BE1F7B059D73BCE
-:107E200026809739C35D80729289FB68ACDF1C3D68
-:107E30008ED6134E9364677A58384ED513D82FD800
-:107E40009907CD80779F195ADC2BEDDCC6A3209DC6
-:107E5000DA1C7308E9B64F156E8F27727AE9F703BB
-:107E60004878C44F15F9DBCC4CB525B1AEDFE13411
-:107E700058C98E8F679E06D44B2F3BB3C5B9A8A7B0
-:107E800006F3FFAE7658138776C9F19D13677954D0
-:107E9000A8E2BCB47338EE99409E0F23BE6D133B2D
-:107EA00007DF4AC4E818C0E5C66B94E2E268F46FE5
-:107EB0003249F4B7E13E3B520F3ACCB48F6C53E2F7
-:107EC0003C38CFDA962B1C4FC52AE206A9F2FE5F9A
-:107ED000E8234DBF763AB308FF7816A07D00B37A49
-:107EE000AC748F5DE08F7115C9AFB3373EB81DCF4D
-:107EF000A3747114F57116272FB6D3BD8B2D7B6D2E
-:107F0000B42FED2CE2E7F39DCD16D2BFB1E6691A8E
-:107F10002A83F3C40B04BA7520DDD24CD589A8F7A7
-:107F2000D2E6F3F9AFA7473B0E14F73B7F3005A32A
-:107F3000BD57D7D2F4F4BEC56897A567A453AA7DF0
-:107F4000AFB3AB51EF611B1314294EDF10E851ECB6
-:107F5000738C09F0FD9CEF8FAF7959D7BDF6BA3815
-:107F60004EBF4EDFF8848751AE40E0E8F704B473AB
-:107F70004DB19FD7E22769FD6CF15B8B31E467DD82
-:107F8000A2E9365C075298F7CA793829B798D84ED3
-:107F90006A972BDD77BDD73FB218DF276726F07BC6
-:107FA000B49F6C994AEF9953D93ADB60A043699129
-:107FB000C183FE80738BDE741A407E1665B6E4A31F
-:107FC0009C26987C990963C87545FB8D6525E660FC
-:107FD00008E8955C070A81E818B892E8B8D010D58F
-:107FE0003F9C9DC0F79D6F89F5243D7D40F19251E6
-:107FF00091F97E44574D8E60FE642C19DD150F13E8
-:10800000F87951429479D06E624DF85E42D347C9F7
-:1080100042CC347DA8C97132CE0FB4E38A403F49C7
-:10802000E77D5035B5EBF70C95E617BE403BD679AA
-:10803000E924D237306F6B48CE73B9FEB4A13E8BC2
-:10804000F05BB5EF7DBD3FBE637AFB671F3BF05D24
-:10805000CB5FD40E07EAAFD3B7FCC98171C0DEBED7
-:1080600085EF936FD4D9FF5709F90826144D41BA0B
-:108070002EF0FF3D3FD25E636BB8FF7979507EBF33
-:108080008AF7BF23FD80150DFAFB00011EA74CFCEB
-:108090003EA79E0FEB041F96EFDA66CE7463FFBE19
-:1080A00039D8FF69B1BF39DDE8A0F7141A3E8B76E5
-:1080B0008D34A3CDFF97668B78A7D762E27AD93B40
-:1080C00003DFE7F804DDF4781EDC174FF096DEC31B
-:1080D000DFAF2E84BED6805EF435F3384AFA712CB9
-:1080E0007DDB3D0DFDE84B3729B48FC3FAB7C03AAD
-:1080F000E15BB391DEF1E8C7B93020FB73F4F11A0C
-:10810000B5FDC032C1FF25F86BBC3951E23836F3FA
-:10811000F774CB74F645E7A19C781CFF9A0461675D
-:10812000E7B34B306EE79E43D909D1E26168E95964
-:1081300071DE8FF7FA313DED67944E4970F3785D4B
-:10814000CD476E46B9AA6CDA4DF111F705DFEB3376
-:108150001EAA14347F6144A12A10F6D87C618FEDE9
-:10816000615C6EC08EDE8CF27FF9E73A3B5A8CF38D
-:10817000064DEE0F2591DCDC80E31A8EDFD54FA291
-:108180008DEBEE04F9FD576FC7A58D471B9F565E1B
-:1081900021DE9FEBDB69723E45C8DD921DC51BFAEF
-:1081A0000229D6EF7D7F8088234771B63439D2CB40
-:1081B000C932C1B7B03C34DF41E3D2F806F29E2E9B
-:1081C000DE25A5A33FA327B9D0F3BFCDD43A00E75E
-:1081D000AB9EFF6D31CE7DB627F0738D256EEF34EB
-:1081E000F4AF8079B8C115613F9C566B0FFE14E760
-:1081F000D10E2EC791EB22194B2F9A689D5DE57029
-:10820000A725DA05DFC6E1FB454B00EB69FD9CF2D3
-:10821000D7CC1A48E78DB5B3060EA4771B946AE550
-:10822000A5F77FEC44FBB43D97917FA1CD21E37B83
-:1082300004179B319872FAAF545BBE7E0B75D08EDB
-:10824000168ADF7AEA2BE19FF8CA52186D9C6713F1
-:10825000B81DA8DD3FB951CCA31B9BF97BBB455B87
-:108260008BCDE4075823DFD77849714DCB84A6BE68
-:10827000869166E4B39E1F4B3D57D03BF06E7C6108
-:10828000B7135F97EADFB5897B4C0B847CCC74B95C
-:10829000859DE6A377C44BEA8C64DF2F7357D3FE2A
-:1082A00066851AFD3DD61897E1BCE3D18F6361A3C3
-:1082B000427A4F8FFFB21D6B37F465387E3EBEEEBB
-:1082C000E308F5233D23C6C95A2FE7EF32C5BAFDAF
-:1082D0005F995EED8C008000000000001F8B08009D
-:1082E00000000000000BB57C0D7854D5B5E83E7356
-:1082F000CEFC24334926FF21413C21111212E29089
-:1083000084000171F24BC4080301826075405184FE
-:1083100090207A5BEFABB79990682DFA7AA358CB8F
-:108320006DEDFD062BAD0A4880A08126E9041403FB
-:10833000040D820A96D68014B1053280B5587D8F1F
-:10834000B7D6DAFB64664E92426F5F87D69D7DCECC
-:108350003EFBACBDFED7DA6B9F65ECD94B720E636A
-:108360000FB7CB8CE53356FBACEC65A98C2D63CAFB
-:10837000E9BE0C46BF6BA9F85F67E59204C6EEC57F
-:108380003F5568DB57553278AE5CAE9985CFF56FB7
-:1083900090995982EB1EEF53C971D036498E461819
-:1083A000C71E379EEEB33066817FD746D33C8C25FF
-:1083B000E0FCFCD723B1A75260FEB38AFFBD08786A
-:1083C000EE2CC0E181799678F873F47EF8FF32C71D
-:1083D0008C2F2478DFFDEDF229730E5E5D6D32C0C7
-:1083E000F8A52F496C1D8CBFFF69DD78B12EFD3AD1
-:1083F0001EDAF0A3B9E91981710F7B9F0BE9C3DA8B
-:108400005456C0D87D023EF6EA7F05EE73F84DAEB5
-:1084100008C632ED117167B3A05BC0265D4B63AC3B
-:10842000CE1A99C3A2A03533C2233B64F46E02B8BE
-:10843000D644C08201CE355BA3BD1EC4E3EA68C644
-:1084400046C0B8F68D26B70DE6C4DFED8C9DAB6F48
-:108450009E9B9E0EEBAF7F7A6EBAC2D82CBB9DB1AD
-:1084600089408FB6E7685CB7E29A6487FE2A4BDFE3
-:108470008FEF5683F03899D363995C696286C07C2C
-:10848000FA7659B3F1CBBEA0751621FC56F86312EB
-:10849000C02FFF3DF8D5C4685B006EFDBC7FAADF2E
-:1084A0001002F74A85395B6C81F568E326DA0DB472
-:1084B0001EFDF37A7A30E6A5717ABAAC443A04D15B
-:1084C00017E15400AF3D1D56EF5A89F888E0F67465
-:1084D0008411DC1793D6CD3D93C7D8617C00E0AE04
-:1084E0001DF132F55F515C6E7B3C5EF48F728DC77F
-:1084F0006762199B323CDE6046C6607C2ECE0FE37D
-:10850000768539F3988CD75DB1C807D31BFAAA2CAE
-:1085100040AA3AFBA40A05DE33FDB9BEAA30E83F03
-:10852000629FCCFB9BFA8E5A1C8C35B02915A5F0A6
-:10853000FC63700FE7BB5E9B6F762D66C05735807E
-:10854000534B0CB4C7C6BC8DF256D35B5921454280
-:10855000CB984FCA057E7046FAAC39D4678530AEE9
-:1085600033CAFD1FB8BE55579B2EC938EE98C2E5D9
-:10857000A53B8EF0A000EC61F05C53B853B503BE90
-:108580009A622C8EC654BAEE098BC1BE535583AE87
-:108590006BF4C0E7108E2603734643DB75604C54C2
-:1085A0005FF6F078EBAA57AB14A0FFBEFA0C6AF5A1
-:1085B000F78B4CF674073C5F6460EE16DBE0FBAFB4
-:1085C00022BF109DD414A4736DB789E41C7F12F0F0
-:1085D000FD2AA1876A81405100CFAA63CC171E896A
-:1085E000E3CABF50B06D95D8E910BE6281BE3C3C75
-:1085F000DC37DAD6E27C4A309F703C152BA9554A0D
-:10860000D07B4B6D99217D39D19081EB6172B8633C
-:1086100013E0574E31ACDE01EB976F8616F0A1D810
-:108620001DF212689B4BA6CB4BA16D34B2852DD8A1
-:108630001AD8F2603C750879D2DA4B76D76F90EE93
-:1086400017DEEF2DB0929E1A6927F916EB6D941C78
-:108650003ED4439E2EE6D804D79A6417E37CDCC24E
-:10866000908F7F2FE671980D3B55E0D7F7EC0F12F6
-:10867000FF3AA20C8FA642FFA3E615150AF0AF231E
-:10868000C570251578F478F34ADECF325C190DFDFC
-:108690004F9A6B787F2A4C99CCD8C9E655159E6CB9
-:1086A0009C97EB31B6C59985EF510C12C9A9B2D789
-:1086B000E46D843F9B22393F3519812F6370BC4A9A
-:1086C000E39F6A28DE6C05FE578A9DEA6A1BC73560
-:1086D000F2C3FFB4D5F0285B0DAB118FD822BECF0B
-:1086E00088756B7460ADCEAC39A8175A9C5973234A
-:1086F00010AFEECF11AF793DBDD3510FB77EF0492A
-:10870000813B9BD30BE7C9EB612C12D673E1AD9B88
-:1087100036CA52803E97EC45E7515F4BA0A61F87B3
-:108720007549AA9DDD0372D7E864AA09D695C85E8B
-:10873000B2A3FD30207D4005B532AE5F3AA35C5F49
-:10874000E2736CA48FEC4CB5DDF515BE5FD3CFACF6
-:108750003766483DACD757A69CC765067C1093D2B8
-:10876000767C29EAF3DF9A1DB7A8088F933D0E7037
-:108770006C333085C5107B642870DFCAC21DEB5096
-:10878000DE1D2CC903F2856823E0E01707F6D02828
-:1087900064485B073C5FCAA09D8470DD4AEB929100
-:1087A0009F2630978C7AAB8079ADD8F677BC9584CC
-:1087B000F87A3E8CDDE782D6F22A737A83F4467E1D
-:1087C000B444F89F1563A436DCD83217F934FC1290
-:1087D000B3A31FD0FF0B9382F38360DC89D71DFB0B
-:1087E0000D0CE1FCB5D16B8F82BE3F53515F6681AA
-:1087F000F9FA059DB5799F37A999D1D0AF8A91082B
-:108800002FBF2EE2F6D8FF85C9FB722AE2C7B2DA83
-:108810001B2457E3A3F9B8BAB8E2B1D1F07C4B47B7
-:1088200038C3F74FEA0C3720FE376FC90D433ED8E7
-:1088300086B881F5C798ED8FE07C315700DE54BAD9
-:10884000EE24BC2AEA8428C06BE14C9BBA0EF0FEF1
-:10885000EBB09699C8F7FEAD06F632BC629BC93103
-:1088600007FBDB2EAB76D4B3BF4E6D09A7F56C3595
-:10887000D07AB685FBC7AD01B8D7652815089F62C9
-:10888000650AEA5FC550AC3E02D7A74573FDA8E96B
-:10889000E39A6895FACF4BF0FE5C1C57447253265E
-:1088A000DB48DEFAFDCC6B86F7C4CFEB95911EE179
-:1088B00073809590DF159FCC703E17121A5A9BD18A
-:1088C000AB929E75DA9600DDA70B3D3BFD644D250E
-:1088D0008BC48EE3D854986F9FCDC8705DB7B13EFE
-:1088E000D902FDDBAE32870FF9E7AA427E981DFE62
-:1088F00005FB7B65629E5F494C898271455FAA0AD0
-:10890000F257110BF5DBCA36947F81F6ADC4A2BBDA
-:108910008EFE5C24B64AE03ACCB3285AF861A3D85C
-:10892000A86BA4CF60D6046147555C7FF67FE1BA9F
-:10893000FA2B4C0E5CFF769BF3E3A9A8077B8D6CAA
-:10894000131B5E8E7E550F1A7D0C08C7D570E68D01
-:10895000253EB421FDC76D68F684C17AC7A5F3F939
-:1089600091DF506F8CFD455C2CEAED8868AE4FB40A
-:1089700056E32FE4237B14E723FBAD01F9FB5E7480
-:108980002A8DD3E409F90BE7D963F42E760D61172C
-:10899000812FBF877CB9DDC62A90CF9F1961598886
-:1089A000F2A4BD67B7E07B7DFB54C39A2E23AEFBD8
-:1089B0002FA0FF01EED2E4ABA660FBDD15C7E12DD1
-:1089C00093BF25BFFA62BB44FE7C423BD7D7C17C34
-:1089D000316268BE7801F17A3DBED0C7011A5FEC02
-:1089E000B81E5F74FF637CF18B68E1DF0ECB17DF8D
-:1089F00046E2FA1FEB2849647FC78F69137C30DC9D
-:108A0000FD2956AED7F4D7DB053E779B9AEFCC41D4
-:108A1000B9BFCBE040B906AAA7CC05FBB23B9C3F4F
-:108A2000C794D569D8DFAE703DB2BDDD4C7A64BB6A
-:108A3000CDED267B9D6461E82730C5DDF77DD47FD1
-:108A4000C916755D10DF3E2EF4408BD137E573F407
-:108A50007F0F70FA4EBE2B5736C1B8110F70B9CECA
-:108A60003F67DA28C33CD53145BE6818DF17CDED26
-:108A700062DD1918057C597BC644FAEDADCE23E5BD
-:108A80004E1BF9374EE4AF497B8E941767E378CEDF
-:108A900047DDA2D5FA53704D3164768E25017E5D97
-:108AA000C24E4C615C0FB9903F72027DE634523C7D
-:108AB000A6F1413563596827E6F639CA908DAA2A8E
-:108AC00042E95BED9B4971DFFCE3CEB20858D77CED
-:108AD00097EEBEA07FB58EFEE007FF01E564D5E608
-:108AE000DE4E1BF2ADCAED698B697516F77B56A792
-:108AF000A1FFAFC911FD004F2DBFCF78795D901D4B
-:108B00005763F83A9F752874DFD367F2DE0297FE49
-:108B100037E3CFB5087BF3AD90E3DCC7DE588CFCC0
-:108B20009BB7DCB90FF1BF284EA6EBFFC97C96348A
-:108B3000A48F4321FFABC5A8967C2E05C631C595F1
-:108B40006183FB7BE2C3F3F0FDD531EE6B4827A6D2
-:108B5000F8BBF1B94985B9792857B6094DB1687F95
-:108B600034B801AE8A4DB6001C1A5CE785FEA98EAA
-:108B700059720DF180CFA15E693B75D682CF6B74BF
-:108B80006FE9B8C4E91D447FA47780FED27DD8D7B1
-:108B9000F06011ADD6FFE7E9EF1B89F41896FE18D7
-:108BA000F747FE8FE83F2A6608FA833F958ED73550
-:108BB0007FAAC5047E7576A0AFD1BDDA5E44E31C02
-:108BC000265819FA4F9D1057A21CBAA3D1B9613B80
-:108BD000EDFC5DFDBF3F3B0A5C4036292686CB930A
-:108BE000C93F06FD8D093E89FCBE0920F0F7909F24
-:108BF0003592F49D43E0879D95A4B319DC05BF969B
-:108C000082FE9F2F16E56082B9D287FCBEC33A3D33
-:108C100005FDB75CEBB434E4A737331E3B8426E78D
-:108C2000CDE4E53B5F51037E8EA6D7F68969B5F7A3
-:108C300097C770FADF0E6A16FD3D740D83E1D0F41C
-:108C4000379205E1907CD5866B56D2C7ED7D80AF1B
-:108C5000DB110EC06B97C45A517F17199C7125E820
-:108C60008FC5FB14EED77D3D4A05BEA96C7FF73852
-:108C7000C25B69B1F930DFC21CC6F37D41F912BD98
-:108C80009FABF9259ADFAFF92D5A7C89FE0DDECF17
-:108C9000C7EB00BFDD0C00A2FDF159BC0DF0FEE7F3
-:108CA0002FAB994E21AF0AACA352AC6336EB25B87B
-:108CB000D8B7D7AE4D03FACC12F8A8EC86B8300777
-:108CC000EF337617E0E12E85C78B7739203E0CE233
-:108CD000A3D99343FBF89B9E1098E77AE3F5FA7FBC
-:108CE000AAC817FCB371A6D676831D3A0D0C70B0D6
-:108CF0009EC73485A3658F82F1803BD380FC5827C3
-:108D0000EC1A84C943DB2321AF8586BE1C07E0B77C
-:108D10006BCF3764FFF6EEF9E623F4E7A67CA130CB
-:108D2000333C5FF8457E14EA07E60A9DB7EE8FAD47
-:108D300056C6AF13FFD48AB5EFAFC78C18C267A170
-:108D4000F637E79F5F8FF37D7946E1BC2DDE5F6EDE
-:108D500072A7DB6DD8F2787FBFC4FD1DEDFE7E23C8
-:108D6000C00DD737C568717FAF42F919F89983E80C
-:108D70007C17C6FBB901BADE75AEE20B2567307D04
-:108D8000F0F7FF23DED7E2FCB744FCC0F69D30A924
-:108D900000D78CD64714F4A36724C9CC19F4DE3B62
-:108DA000542B7306C5FB6FC4E8FC907DAFAD9F05E7
-:108DB00076A4AE477684A1BCB66F3F9483FD5ED99E
-:108DC000611D828FF4F89DD1FE8882FC9F10CBE557
-:108DD000E67AEF2F1C077C722BD29D911F77B14052
-:108DE0002239D2D377EF9E9FC7F6650F8FEFE1E868
-:108DF000AFA7C36FCE1747215EAE470F3DDF76C2E8
-:108E00003A3DB03E1FACD303FED6DE7A3BF5DFAE73
-:108E10004FA2BEC6AF751DBF8C457F4DE3D3B25880
-:108E2000CE375376AF8F65B600BD347C5D1474AB1E
-:108E3000668EF9B3E0CF5D922382F48487F5261520
-:108E400004EC55F5B172F233347B552D671B51FF9D
-:108E50006AF60AD3C2A8CFF4F6697E7A9111D5AA30
-:108E6000DE2EC1028DC8BFD50B43AF57F4342B1192
-:108E7000D433109D2449E043F8D51A3C1F3217C162
-:108E8000ABA7A7069F1E2ECD9FAE1674837596E1E5
-:108E9000D2E7AA45B48E417655ACF746EDA93936EE
-:108EA00034CEBA72AEF4FD9C21F87538BED5DFD74A
-:108EB000F44039BE20975A0FFA1109B10944AFF2B4
-:108EC000AB26E6047BC14686B1CF82F3EFAF649256
-:108ED000BD7B54D8DFE1F8A6F6AA81B96303FC6331
-:108EE0006C7BCE8AFCB35B69B662DEF136DB9CC676
-:108EF00028C053E91F8BE7A15F57D76760989A2A6C
-:108F00006BBFB40FE3F6BAE3CC81FAB0B8BDAB04E3
-:108F1000F9ED6DA557A638FA4BC69E0BF20FDBDABA
-:108F20001BADE83FB5C5C914A7EF8FE6FCA8DD6F00
-:108F300089E5FCD776E6F22CE710F73F13F74B4FA5
-:108F4000E51AD148F6C74750BEA1FC6903ADBF542E
-:108F5000B25755A2FF718791FC7A885BFEF07DCCF9
-:108F600037B599B763AABEACED878FD881102DFFB6
-:108F7000E7B30633E60FE6488E97615CB9EAEFC2C5
-:108F80007EF9BC54DA8799F47F65F25FFD774B94E4
-:108F9000F7280776C17EF93DA95ECC3FEC9178DFDA
-:108FA000D3C1F3FECCEE899D05EFF9A03276C23A2B
-:108FB000E229AD7F4BEE3A261838289E7A6C17DFEF
-:108FC0003F7AAC4CA2FDA3327B0AF304F155F9D3EE
-:108FD00040CF3CE0C7F6C462E4DFAA0A997983F87F
-:108FE0007ABECBCABC41E3F7877178FC92D98BF982
-:108FF000124D5E670AFEAE5E181B327E0EE37EE205
-:1090000042D66C44F9AE13F0D415013CF0FC4C117F
-:10901000A7DEED4E09796F256641606856DC68B2BF
-:109020008FB3BFEC23B33A473E796C31BC87657090
-:10903000F9D0E4AC4CAE69223E48921C181FCF9781
-:10904000C0AB9451DF85CAD1ECC9A1FD394EBD7EBC
-:10905000089577BD1ED7E47C7E876CC4387A7E91F4
-:10906000E46043E803BD3FADD703930C8E7730AE89
-:109070009E7BD549FC35480F9CACF887F4C05B203B
-:109080005B93415E7FA4E9839BD84DA80FCAE42D72
-:10909000EB913FFAC1AE9987E00FCD2E68F176399A
-:1090A000C827F2033BCFF725CAAE829CC606E2ED85
-:1090B00001FD007E8363087FE657B16921FB490308
-:1090C000FA22C86F3016FCF37E4319F88BA65C8435
-:1090D0006F24F3E4919EA2FC1EB43ECAB3255DA2A8
-:1090E0003C4A1DC4F114CFB35F125CA8D7A498000A
-:1090F000DFEBFD092D4F3B42E409F4FC3090B79BB8
-:1091000067F4229F69FC506EE772513E4FA6FCB98E
-:109110009E3FB4F75D8F2F7C12F085F477F842C83C
-:10912000D38DF2C5218D1FD259FA8DF083C6071A4F
-:109130005FE8EDC5415DDE65387B71F23AF6E29D90
-:109140000C23E965BD9DD0ECC28138AE7FC7C7F264
-:109150007D8A9999F36DE8578C407D80FE9EB037EB
-:109160000379A30D9C0FDEE95BAA486837500FA472
-:1091700006E15DE44D35BEAB7D9A51FEB052E89FED
-:109180008B1D3C9F56572A7B2DF06749FB73EB796B
-:10919000DF48F9B622A54BB1C0BCB31D9203F3352D
-:1091A0004E917F9B75D5E455293F3FF47E7A95E03B
-:1091B0001B8C7370FC6CA7E4851074901EAABACA4D
-:1091C000EDBE5E1F5589FDF22ADD7EB9294ED0F530
-:1091D0006676F3BFD2EEC7C72570B919868EDAF36B
-:1091E0001A1D35FA4DC0B1283FFBBE36A911DC3F30
-:1091F00046FACDB8AAD03CA3E242FD962FCFE7FEB7
-:1092000027C574627C5DFB25937BFCF0F05FCF2F5C
-:10921000BD59F3C3855FAEBD7726C8780A3A863A52
-:10922000FBA1BDE7BAF6423CAFA7D3E4B8D0784281
-:10923000A387A64707E15BE8D9E1E8753D3DABE9C7
-:10924000B37FB59ED5E6D7EC80F65EBDFE1D2E3E03
-:10925000D3F4E9531B0D9417B94DC4C1B7893CEB46
-:109260008342CE970B7DDBFF178B01FDAC6D9DDC40
-:109270001F7198ED87D06F08E4F3385D9F8C601EF6
-:10928000DC2F674AAF85F62F8B81A4B87F99CCF786
-:109290002FB7283E17E96987C21A405EFE2AF216E8
-:1092A0004FEEF52C463DFDE4E93106DA47577CBD2B
-:1092B00018174FCA55683F28DAAC52BEF76287D9F3
-:1092C0008ECFF5EFFE5E9711E7F90B7360A8F67687
-:1092D0008779603F06F54299DC23635EBEDF0FBEEF
-:1092E000388C9FB6D05782F1CE6DACB711E3EA420D
-:1092F000A4E310F47B55675FF479FB920EEE27959B
-:1093000044F0BA9FE980467CEFF43613F985D7CB59
-:10931000DB177DC9C85F1A94AF6FE37A0606119F09
-:10932000DC68DEBE107D3DE0E39FE8F40E1B267F87
-:10933000BFCDC4F773FC478C0CFD5E762E6EC8BCA7
-:10934000CBF5F2F8BB3BC39D6A24EEBB71FF7C7783
-:1093500067B253CD197E7C4E9FBF18F395DBB6CC18
-:1093600055284E14F9CF41FB223AFCED9058931545
-:10937000F369ED8E528C3F86DBE728F63B69DE1BF6
-:10938000C51B63CD9CCEA27EE9762163DBCE863BF6
-:1093900091BFB79D4D76223CBB057F6AFCBEFBCCDE
-:1093A000E570DACF343955DC07F6475B1C2F13BF65
-:1093B000723E6F1931C68BFBADDB853C6C0BF71F22
-:1093C000CC8A0BDECFE0FB179DF59EAA33E9B4DF14
-:1093D0002D61BE51DB27F680BC505D4E0C237E32E2
-:1093E000B21686EF6D74B29F633B7D9A1A85F8BE04
-:1093F0001CA7ED47AA519467F8F64A816BFC60BC44
-:10940000EFA877513D496BFDC22A05607CB3DE4D64
-:109410006D5BFD726AF7D4AFA6FB6B0F453E8E768F
-:10942000BFCEB9A04A09D21B9FC5F3FC526ED6E944
-:1094300012E473F60D6318EF4C7FA24F463D71FBAB
-:1094400055584748DD887219F14CF9CBB4403F5567
-:109450005A12867C79FB55E8078D97E2A3391D9A4D
-:1094600094A65B0A485A881FC2E29D17E3E0FA0FF0
-:10947000ED2E7F5C3CF241F5BE0B8CFA97F1FA0EB3
-:10948000E96EF9028CCBF31551DE380FF3C6B9340F
-:10949000ED62C4DFC42E13ED7B6BF9DB5C31AFF3FF
-:1094A000ABD03C729EC8DBBEC9FA289F9C6F81C0BE
-:1094B000CA807071FA39A5F94912E6FBE24D0EAC8B
-:1094C000579898E6CAC37C6B573CA3FC695757C2B0
-:1094D0004815F0E054785ED7A9E575D9DFCFEB7673
-:1094E0007F1AE9217D057E0AEAA7EEA3910E1FED02
-:1094F000FF59C8FFDB810F627D4338AF1760F3E689
-:10950000511EFD760B5F07D89FF878CAFBF9F61D50
-:1095100086E77E7B99F17DC4DE93B43F5D62C84CE3
-:10952000EC0338F74963A3B07DF1D3C86C6A8F466A
-:109530009E47FC741AAC2ABEF7C37A56857567CE6F
-:10954000F76DB49F31FD7D9B82EDE1FA3EAA477B2A
-:10955000BFFE1CB547EAFDD41EADBF4AED3B701DF2
-:10956000F9E7103C8F6DEEE2087A6EC7A20813C2CD
-:10957000DB19C9B668EFC17A335FB8AF1593F9EF5D
-:10958000C57FBECE7213D83BB37BBC3481B113F11F
-:109590009FCF54A07F68C6A87FFF0BDCFFDD4F2E56
-:1095A000ACB3005CF38EDA5A7BA0FFE94F2EAEB36A
-:1095B000A19E3D140ECA0EF546FF41907496873663
-:1095C0003D9971053B19FAB1A2EFE99F590A245F51
-:1095D00050D297C580B5A6FCC43FD302785C6075B5
-:1095E000FF1BF64D9E976696DE847DE6C17A2EBF00
-:1095F00064A4F89E8D94E2B07E6599DD7D2C3EC812
-:109600007E3BA53FD2FE51815362D1714457DACFE0
-:1096100062F653B1C1F2B6CC5E760CE971473CDF1D
-:10962000BF9A384D7206D749E8C74D3CA396229D94
-:109630000ACE9537613BBB229AFAAE85939A509E2B
-:109640004B6DC33D5F42CF2F8837127F162B524898
-:109650007D887E5C1E3013FAC7FE03E1941798786C
-:10966000CCDD8875A36549A9B9B2D0798CFAD11B34
-:10967000711F6D62E587A5B1283F36C981E6A180DB
-:10968000F535C5C661FD231644E1BA9E2BC1FA9D8E
-:1096900089AAE440B41539BB5AF1F9224784A308DA
-:1096A000FDF1636A299A9CA3CA84C3F9306E46BA55
-:1096B000ECB0C044477D774CBD00FDA28C28CAE3C6
-:1096C0001629ABAF1CA67E84A341C5756CFC792D11
-:1096D000CD63267BBE6356C97F20FF14BBA228E75B
-:1096E000576A3B3537B82E0CD64D7017D9656F9831
-:1096F00084FCFD83523BF4778C9218CACF515FE60D
-:109700009FE97E77B81A0680EE30D94B71BE1D26D0
-:10971000C9BE96FAAE121CEF196354314F541EF7AE
-:1097200045C8FC334AA5296710FEECA80978AD624C
-:10973000E4A590FB3D8BAC64272ADFCF267FA8678A
-:10974000510AD98BCAF7A71563DB63E07E7AE5FB84
-:10975000951574DFC0E3DFCAC5DF718A3EC5BB95CE
-:109760008B5751BF4B4AFC777CDF95ECA85CCCA3B0
-:10977000CD4CFF7AAE12ECFFADCE24F9CF1579BCFB
-:109780002243E6FA6900FFA307F83E4465B6145287
-:1097900037372BFF54483DA86BDA1721FDB9A59741
-:1097A00042EA43E7557E1DD25F304FAA0A1E5F7A18
-:1097B000209FEC6BBEA85FD2F24B458285DEA9CF1D
-:1097C000A82A05B93C00ED03A01F8A7A45DE55E1C1
-:1097D000717506FC433D586AD3E577994AFBD91564
-:1097E000DD7CDFBA3CCE783AD83E54C84F707F411A
-:1097F000B7FEDC0346B293B9D132E5AB34F82A4662
-:10980000863EAFF95F1502CE1D0677530CE5C79C67
-:10981000BDE87F68F06BEFD7E0AE90EF29A5EDBF14
-:10982000EBC0AF87170025FF4D0FC78178118780E8
-:10983000BF41FE5937AF4B835FDC50765BF3CF2BD4
-:10984000414F4507EB299B1487F576C3E9296DDE67
-:10985000E1FC306DDE6576173DEFDCFAD9D1423997
-:10986000A89F7A2A3626B8FFDA67EB43EEC79FAA8D
-:109870008A0EEE6FFAAC0AEF4F57D4461BF0E34165
-:1098800026393CC89F3DAA82FBCF25C79C4DD89660
-:109890009D746399299B71C6D384EDD4F3DE1E3386
-:1098A000ACEB8E0C59C5B85DF33FF4F09A13781CFD
-:1098B00072F0AA6AC5FDD31D1ED58AFEFB8E275401
-:1098C0002BFA1F3B9CAC02E331679A6135FAF3CE69
-:1098D0002C5E677855E8E16FE2F9F35A7B5A717FA5
-:1098E000837A11EBC2D127A8FDDA4F75E007D1AF1B
-:1098F000CA1EEC571D54BC367CDFC127BCB6E07DC8
-:10990000C21BF5ABFE8C363A1EF96C4E887C96581D
-:10991000EEAE0A96EF32FB9290FB9FC6A904FF8C35
-:10992000A48743C6DDA13E12D2077F3103FD9146D5
-:1099300013A33A598F81D7C9EAF1F8A8C0A3C36627
-:1099400047378619E354AA6BD38F739470FCE9AF41
-:10995000A727F0B86823C80CB6F72470F8F475B1DF
-:10996000FA3EC47C0B713E983909F9DC61355C0123
-:109970005797391392EEA47AD93CC3A369D0AF4E5E
-:10998000C8E2FDA9869D581F7B774236EFDF6AC883
-:1099900033821FF02B36FE4EAC07AF0D13759D0FB3
-:1099A00024D27E9816DF2886532F2EC638738F91C7
-:1099B00061FEFE1913D8BDDCC0BEB9D5CCE352ABF5
-:1099C00089D76D3F957AF429D41B6A987B7A02F97E
-:1099D00051C52AE2EFBCDD42759D8FED2E4B44FA56
-:1099E000DF93C0F35C593BA726A17EF917BC7F56D5
-:1099F000C2C4E1DF8F75BE38CFF91D59E47F67DD42
-:109A00000CE89502F887F098AE87419840E72598D2
-:109A10003309F36C8DD1269AE79E04CE7F37DA0E98
-:109A2000AAFB8D32ACDE0EEDFD82FE0FE07B095FFE
-:109A3000FE51737063CEEE1F35773CEF237D6539A1
-:109A4000D78F7EACFF3B11B4AFC246FA69FFE5E3A6
-:109A50007BB21CE89F7E12CEF1B7D03BBAB14FC5A6
-:109A6000FA0DEF4D582F9191E8AE453C2C327B6FAB
-:109A700021FEB1AD8EC0F96FB41E78F07B21800459
-:109A8000FA544FE1F4D1DE0B38B5A03DF8589C03F1
-:109A9000D1E080F7FF00F9408367000E5D5DB89666
-:109AA00067AEFBA381F20C7512E83DE8EF3CC91CE0
-:109AB0001E98E7A2E6AF8BBC266E45E17BA61C5E36
-:109AC0005A628336BF6D258F737B95903CD7A4E394
-:109AD0008A7EBF83ECD654ED795D9E71AA886BA710
-:109AE000EAE2DA1713849D4966C9C1798035226E8E
-:109AF000B8DC333A0AFD4CD45132E0D5A4CA6C72BA
-:109B00004C40CE5B21EE674171BFC667E38FD9EF52
-:109B100047B8C71F63F7915DD7E61DC82F70BC5CBF
-:109B20003ECEF132A12FE3A7D3A06FEC3632AF1AAD
-:109B3000584F2107955DC6FFE078BBC98B75CB05F3
-:109B4000077E99E7834BE624035383F010A6863300
-:109B500035482F5A336242FAB2866F61CFF3C4FCA4
-:109B6000118EE49079F6C49477A37DCFB32D27FBB3
-:109B70001E357974C83CAC4709B1F3B028DABF9CF4
-:109B80000840FD0CF05A704C09B1E793E23CB86212
-:109B900036F9A4A2B3FFCD32CA41E199D0EB0786D2
-:109BA000A3CB70F863393F45FFEE1FC55FB4331494
-:109BB0007FB115A1F88B7785E22F7161289E46B899
-:109BC00043F192B27C5CC8FD9B56E786F46F7EBC85
-:109BD00030647C2A18A4E07EDAD33343C6DFD23C5B
-:109BE00037A43F76C3A290F199DEA521F7B35E5D5D
-:109BF0007143F41EDFB226649C9EDEB7B6FDAF90C3
-:109C000079357A7BE0DFBF82DEE6C4507AA70AFDB1
-:109C10001AEDE4F565FD46DBD312E8234C13A15E93
-:109C20008B6E7FF76BCC43788A55AA9FF3CC64B4D4
-:109C30000FFD82EC92500FA5C0148634AA5FA7FADC
-:109C4000BB1F1B0C21FBE28989DCBE2726F27CCDE1
-:109C5000CF4DFCDC520AF88F64870C2C102F031EAA
-:109C600022315EA678FAC7CF60BCDC14DD97A14232
-:109C70007C6CC6FE4D017DB9C8AC36F6013E26C8E7
-:109C80005C1F829E4C4B84F93F919E30723FC263B1
-:109C9000443F22C5C23C91B9643F287F1CCDE224D9
-:109CA000ACC78F0AE869F51A106BDF8A2C3A07F502
-:109CB0001E4282FEAF2586ECE8DD9A7E5A9E49FA66
-:109CC000E9B22DD40FBBFC401A5D3F71AF99F6FB92
-:109CD0004F883A446DFDE784DEFA53BD85DAF3F52B
-:109CE000F6103DB67CE3FA08F41F4F64707F51BB59
-:109CF0005E82789B88AD2CEC9AC58EF9AC7BC0381F
-:109D00004701BE5775F7452E62E43716E3BA6B3745
-:109D10005EB9F74DE8D719FC09DC3E7878BDCCC7B1
-:109D20008CFCCFEA6F5888FF343791C7E973C5FCC4
-:109D30000BA0B1039E1600FEA3B17D775A39F2271E
-:109D40005CA7F369B3BB19D59FCC71A7D23EE35191
-:109D5000E6F8701780F89D4495E09CC75CB45FFFFF
-:109D6000D1BDAB2270DCC07CDA3CC028E86F7C1C23
-:109D7000ED312660DC7F1BAF6F80F759F0BAEB9EA8
-:109D80009427D10E69EFFB88B92F7C88FBDDCC418D
-:109D9000F36AF3331613A29F762C5FF9692CBC6F1C
-:109DA000CD0103E513D6749829EEEA5FF1D7AD2F04
-:109DB000C2FDFB52FA6E42BBFCC98A6FC6203FDC73
-:109DC000BD01F410ACB130CAFD7062509C72E281EA
-:109DD0002B11781FECEBA617D1386E36537DEF2789
-:109DE0002B368F09F6471F4D2CAAC5E7D8E41B3B3D
-:109DF0006F58F27A6622D563097E7A58F0D39AD7E3
-:109E0000C6921FB52662809F787F13AFEFD0D6F140
-:109E1000A1E0C715AF7F5D107CCE7407F0913A8644
-:109E2000EF6BA920533B7B2EE7E0FD57147713C25D
-:109E3000D779F57424F677BEF737829FCDBB31789A
-:109E400051063D0581FD65EDDCE5C2F6D83CA43B3D
-:109E5000C85933CEBFE837AF5DF81DE2A763F3A65C
-:109E6000EFE3981B3C7FC9847D71083C807DA1F89D
-:109E7000A09F85F3731D428F2AB8839E86E7991CA5
-:109E80002AF1B3931DC27D97C62E03C3BA9548DC51
-:109E9000B409CAB345CA06CD08392D49A09F855ECD
-:109EA0007925F1E49D4DE4E787FA3DF96FAF08F1BC
-:109EB000775CF08FFC9D97DC8D9807BAAEDFE333BB
-:109EC0002C3145DDB8FF0381B0532A105B38F06BAD
-:109ED0004B14FB22420F77A21C61FD3FCE85F97A1D
-:109EE0005F383F670CA602F5F80F604DF8B02945C2
-:109EF000B4D2C50C0BE8C5BD897F78E669D09396CE
-:109F000074BE5EEC37E2DFDD9CDF06FCABB7C791C9
-:109F10009E62DFC2DB100F225FA1A7533EC8078BF2
-:109F20000D9233F1BC6FFFDF22314FBB35467D1FF1
-:109F3000E9E03F20D33E4D98D2678A1E222E7B1344
-:109F4000F59E89FB4D546FDEC6F38116D5C9300EE0
-:109F500008B3DB27049FB36B17FA6ED5FE4F469903
-:109F6000800E170C3D91D9307FCDAE1D91E8C6DF34
-:109F70006B747F8A7CB7F2C40705763ACFB671144A
-:109F80009D03F08DA6BA83F10AF328B983E1A8DB1B
-:109F9000904BC6B8760325E3D9F8F6BC87501FD599
-:109FA000F9F83A716E2CFCCB6C63D4BFD8D6188309
-:109FB000F3D5FDB62319E567733C8F135FBF3A8E67
-:109FC0003FAF3005C77F99182DF8D96BC03863B300
-:109FD000884F2E5E35D038EDFDE3DB8A643BF043DD
-:109FE000B6AF792FC543ED6615E91AF60AE378682E
-:109FF0000F2339AFEB9CC1309FDF1FCD1C12DCDF7C
-:10A000001AEEFF039D33EB30AB981F0DB337B31837
-:10A01000987FABD80FCD048EC2F34ADA75ED7D611F
-:10A02000ED3FC55802F981F2B4614A33BBCD168CBD
-:10A03000E708C2733CF2533CBEC767C0FC88FF16FA
-:10A04000C65E26B80270327AAF066726F9735B4D9A
-:10A05000FEB3787E05E0B223FD33198793B58F55A3
-:10A0600031BE0FB33B691D6176D5E19106C35597AB
-:10A07000C3BC68BF7FBC960DC82BCA6F5D78A06F4C
-:10A080000119D83A9A09F9B63F5B3A2DB80F8A649C
-:10A0900072E0F9711B629E6D1A49718347C63816CA
-:10A0A000DA88185CA7CACF3B636A2897E301F7C533
-:10A0B000AD167E7F603CF0B70DFB363ECE1165B726
-:10A0C000CE94484E28AF572BE4FD31C977F67690F1
-:10A0D000D3BFF8F6E6A8004BCDBB7B884F571ADA02
-:10A0E0005F1C0FF7375ADCF94980CFB74E1AE81CCE
-:10A0F000E99F5E0BF35662FCB87B63827308F9D06C
-:10A10000CFFFC3E36B9F4F41FAEF9654CC9BF61BF6
-:10A11000FDA310DEDAF6CF4D548FD0768AEA938E07
-:10A1200024B99DF89EC96D0DB46F3C8535D3BE71C1
-:10A1300096387FDD92C4F5C7E563635E6E08C2FFA3
-:10A140008349DC0F637EF7CD2837ED423E3BD12FAC
-:10A15000817697F08F7675DD9DA606E5FD1AD8DE2F
-:10A1600014C4F75AF636B5DAF57E2F3FCF98F5913D
-:10A17000E53E6710FFB993B89FE716EFF327B917CD
-:10A1800024A1DC769D3645AA785EA56514DA911681
-:10A19000F09FEC43E065406E757254A7F84D38BEF1
-:10A1A000EE1C3F770A746EC2FAFFCD1FB58D5B02BD
-:10A1B000D77701AEB1DED373C24C758FBB8CAE14B2
-:10A1C0001CDFF0E15739A8B72A1069F0BFAF3A5643
-:10A1D000DE8C7803BE2F0E47F9DACE488F69F299EC
-:10A1E0008DF209CF6723DFE7633F93F4F056532FD7
-:10A1F0003FF7B98B9FFB04BE273900BEB7A39F90E2
-:10A200006D0739A0E7C7927C6FED35D0F9540FE8A0
-:10A21000F15BA85F5C85FDADBDA576926FCCC3E711
-:10A22000A29CFAF6D23C2D108320E924E60AF61F00
-:10A23000DB1323898F35FD783091EBFF960C350ABF
-:10A24000EBFFADB21C2217417690F7859DECDD50F7
-:10A25000FCEC0BD3D0DE09BB20FC27769CEBF94746
-:10A2600085AD5AF34EE1EC2DB0CE3587E5817A6E9F
-:10A27000F4577D824FF60AFF15ED849AC7EB67F01D
-:10A28000FAC40DBCCEB5C0B9BA04CB38265734EFEA
-:10A29000C3B6D0D55282678EA72DECDDC7CF1EF393
-:10A2A000F3E3AD7BEFC8C27DEAFE136686FB24AD07
-:10A2B0007FF3FFE175C0C3773B01FF43D825580EFC
-:10A2C000F11F58EA149634F87EBFA4E98FF9952857
-:10A2D0006F175BE5401FEC612D3038F67F9D54F51C
-:10A2E000AC07004B1BE17C1D59A230D94D6DFF918D
-:10A2F000BF25A02DD8758CFB4DAD266716F24FEB10
-:10A30000E8D0F3FA5AFB62123FE79C6F6643E625FA
-:10A310000F09BB37C6C39E413EAA6D95ED5EA0FBFB
-:10A320008556D96902FFE6ACD39D806765CE31CFF3
-:10A3300082A968E745DCA87D4F6519FA2760A71E4A
-:10A340007C61501EDF807CF450BBC47E066B5EFED9
-:10A35000D2D0FB0A35629E87DB36EE4F013AAE78EB
-:10A3600025745C8DA813ABD1F92F8792447C98C6D5
-:10A37000D2D02F01FE21BD605458B719F8F5C16441
-:10A380007707C61B9BC5770C407F921C7608BEDC06
-:10A390002AEA04FC5B25DAD7CB7CD52B1BE0F942FB
-:10A3A000C52BA39D62D0E23EC164A7BB1CF10BEBA1
-:10A3B0003E86FB35CB851E5CAEF9655EBE9F01E631
-:10A3C00096FCB229CCDB1889EB7E5572F854FC8ED2
-:10A3D000C8A03A5C5A779D5877CD8623FB318C5BB9
-:10A3E000D5123AAE4EACBB4EB76E6D5FFBCF49BADD
-:10A3F00073C837B86FF16723F7133E10F368F7CDD2
-:10A4000023B83EAC05F0906E355ED9EBE57E9D0D30
-:10A41000BFC373BF80F77E41EF3AE633A5C0B8559E
-:10A420002FF075B26743EB3F1F6C7DC484F1959E9E
-:10A430002F966F31923F0A8833A1BFA8E78B156230
-:10A44000DD2B74EBAE754B3AB8B89F3C18AE960551
-:10A4500048D7555B8C0CEB11F5702D6B59528E7CE7
-:10A4600036985F395D5688F90270AEA6737C370A5C
-:10A47000E7A811822FC7B17144978AD81BA28BDE3F
-:10A480008FDDBE7F9C15E5FB72F7688ADF35BAEB7E
-:10A490009F2F177EF08C0D8CDA0B6D25D6F118A747
-:10A4A000F4181C924AF156E478C0475E87CC2AA182
-:10A4B000DFDF9EB6DE0378CF3D9C5F85F17CDE61F9
-:10A4C000039D77DBD99D4FFBC07907D263D3281F4B
-:10A4D000EDA0EFCDC03C643FFB7B72D7E3B980FEBB
-:10A4E0009ED27C9C57827168E773851D68E8C9B568
-:10A4F000069FEF2E18C1E3F5A7923EFB31FAE13338
-:10A50000B61BE97CC30CA3FF3DAC9FDAD9ADD0BE2E
-:10A5100075CDE1A56BC390AEAF49B46FBDBF774DAC
-:10A52000DC62E4AB76A31DF7A1FBDBFF6D2FDEF74A
-:10A530006C91E87B12751D65595BA19FBB31CF11F2
-:10A540007CDE2B375A25F8D8082BC5C3336E3292E0
-:10A550005D3C9F6CFD25FA372B9C1B498ECFEFD9B4
-:10A5600069A2FAB9AD1243D3BF3F69DF1B888FF3ED
-:10A570006F1E31A1935DD27AC4D4F777ECFD052F1D
-:10A5800004FE1407379B304E59B551EBF799904EA6
-:10A590002EE1FFD4BE728AFA2BDA24D2332B5E92DC
-:10A5A000E93CFBBE8EB74CC8C7B55B2496981A74BD
-:10A5B0007F8314F21D84A58CF3C152A1675632EF3C
-:10A5C00053C9306E6533AF23604F87D6E5AEDC32BA
-:10A5D00087BEDBB4AC79687DF3B0E0EB87301EBC9E
-:10A5E00015BF83143AEE61EDBB5C3A7E7E5CE3E717
-:10A5F0004C9689FCFC55911A950DD7BF3AB2E2E60C
-:10A60000A1CEB1F7083BACD9C1CB3E03D911FDB8FF
-:10A610008B6D5708DEBA9ECB26B483E5ED9708EF25
-:10A6200095ED5D54C7711773D7209EEE6AB7DA5166
-:10A630008E2BFBB85E9AD96EF67A25BCDFD284F4F5
-:10A64000ECEFE4758B9E3D12F92F9ABE7A48E0EF4D
-:10A650002181BF874041A7E4A21FCBE3DE873336C9
-:10A66000EE8F81FBB5E27ACD817D91E8EFCD6497E5
-:10A67000EE457AC07B18BE87BD148AE73B1987E395
-:10A68000CE2DBCDE596FAFFA4764CDA6FC23C49D26
-:10A69000084FCD96503CD7EAE2ED7523B87DDEA495
-:10A6A000C373A59F59B3110E5576786974AF82EFC5
-:10A6B000EDCE9128BFDAADA6450DB5FFA8B5EF09DF
-:10A6C000BF59EBCF16E7AB5BECCDB6E038D894CCF6
-:10A6D000EDFF8A29B207E934103FA4EFCB510D8179
-:10A6E000F801E286DF8C88E771041674BC3B526681
-:10A6F000717181F8E18749EB2B73A15FB785CBF9C5
-:10A70000C5C9301F7EDF4B61E45FD66D31D339C0E0
-:10A710003AA03BC509EDFC1C83AB5D2A437A83FF5D
-:10A72000FDEE888978AE8619E360DD73DA389FCF55
-:10A7300029BD447C72209DAFF7B2A2260EE58F6B37
-:10A740007E389EC35283CF3F805CE2F8DA765E0F9C
-:10A75000D4BAF7EB51A9A8D73AFE3A6A09B45746DA
-:10A76000F0F56B7E9E1FFCBCD1DCCF3986FEE78303
-:10A770009ADCD8F93EDA83C2CE30A989F8BBD6D8A4
-:10A78000F2760CFA4D5BF9BE3DDB6DC46F9CB18671
-:10A790000F5E6F8A81755F7C5DA27A347CFE09E072
-:10A7A000B38B4B5B4EA31FFDD5560BF98F0F828FDA
-:10A7B000383D77B03C6A72AB7D77AA81AD257F7258
-:10A7C0002D6BA27695E0E38B6D8D26CA9B79839ED7
-:10A7D0001F3DD8EF58A5E33B537228BF357C104E80
-:10A7E000FE5FFF01D98EFB2780A7FF4E0EC687F0C4
-:10A7F0002F5AF786113DFB8FD8C85EFC49F0D979F6
-:10A8000091376E982CD3FA0D53789BD5F9D668A45E
-:10A810001FE21BEBDE3777BE358E9FA7F612DE57A1
-:10A82000BE8A49F120385BAC94DBD3FA0D1F2CA211
-:10A83000EFF0D4ED19806B8C292E00D770FC2F49D6
-:10A840003C1E3448A1F160DD6ED9155CEF05EBB913
-:10A850000FF54F929003A6F813D02F1999AC92FDE3
-:10A860006A68E7F43474F016DEBF80E73B8CF4FED0
-:10A8700041F78B3D3578FFAB542BDF4FBEEAA9C4BF
-:10A88000FE7747CB544FF9DD0F568C0DD69B0CE16C
-:10A89000047AD619FD0914371E31107C75472E270E
-:10A8A000A4DB501F6D2CB567A3DEE1FA6EFF68EBE9
-:10A8B00072E4630FBE373130CF6BC2DE325C6F1291
-:10A8C0007A152FF079C57AD7B2B9223EE67C942D5D
-:10A8D000FC3D882B26264F1C1C57DCA83F09F6E0C0
-:10A8E000E86209EB89140FC6B53B8F737DD0D0F1B8
-:10A8F000D0A7C8E7759F98A9BEEABB9D0F8DA53A62
-:10A900005BB7FB56F42BBEEA7CF856CAF3496B09D9
-:10A910002E0FC29784FECB8709580FBAAAE3C3044F
-:10A92000B2AFBB26AEF744A09F927B275E07BF81E4
-:10A93000F80FFC17E2BF9D3DF99ABF62C579571D1C
-:10A94000505C889F5507F20F55A21F71B8381FD56C
-:10A95000B874389FFC953CF4576C01FF455B4F651C
-:10A9600032AF77E9EF0AA33C81C44673FE61E92167
-:10A97000FC53D3FA0ED9F59A3639A46E507BCE9D8E
-:10A98000ACF07D7E8D7F5A2427F1C776DED6B4EDFC
-:10A99000A4F5AD34B610BD1BB618F9FDADBCD5EAB3
-:10A9A000AA3D2CC683F8388497800E334D5EFA6E2C
-:10A9B000C5C154EEBFEBE9F15932CF631C3CE1BE97
-:10A9C00019F9E560917BAC7D08FBE061C53C3E95E3
-:10A9D00004BE5BF97925FDB853C93C8E8F8C0D3DC3
-:10A9E0003F3A605F9239FFCC340DFD3DBD9F69F267
-:10A9F000C4D83306E08BA39546FB3AE1B78F08FA3B
-:10AA00005E42D55D46F20F8E32FB3B5867384BD322
-:10AA1000AF93B95DD5F2DDAE0D2ADFD7197CAE91CB
-:10AA2000F4E47C6D3EFD7969E1D7CCD7F935EB359F
-:10AA3000FD37868D41FDD722CEB9ADC90CF306E7AF
-:10AA4000A3F4ED7EB18F81E775B06DC8FC98F23646
-:10AA500007BB4EBC41756627C2D8689E97A3FCF51C
-:10AA6000AA61F2D70D03F2382F84BF347A5C10DF6D
-:10AA700055D1D3E30D81776D9F2D5CECB39D56DCF2
-:10AA80006F24535DD67913FF8E9A9FE2AB864CEE0E
-:10AA90001F5D2893685F1CE01C650ED2EB1746F023
-:10AAA000B8EABB0B24CA9B76E1788C9F5A24AAABE8
-:10AAB0005EE5EB35211F8D695DF224C9AB871D630F
-:10AAC00041DFA9986DE17671806EDABA07EC568C99
-:10AAD00087EBE1386A713CDAC159C2EEE9CF218DCA
-:10AAE00065BDE51857563B2507EEDBEBE93D77E101
-:10AAF0008477E2FF013A9F4B761F21FDD67B7901D7
-:10AB0000E63F0F667E3E0AED65ED307CFB3BC1B74C
-:10AB1000DAF7591C63D546FC3EC98F12DD9F207EB3
-:10AB2000FB0DDF468E63F87CDF7FAF91902E8CE8C3
-:10AB3000319C9C9C12F39D4A16DF258CE3FB24CBB1
-:10AB4000B18FF26AF48EA4FC42F68DED4B35EC7EAB
-:10AB50003707F5D6C5AE0339A6203A9E5F03F28EBD
-:10AB6000F6A3635F826A0BE63303F1972469FCA6C0
-:10AB700008BB18CA77E791EFB2B1FD30321DF5EE90
-:10AB8000F6A391B7E07CBB783BC09FED328D837814
-:10AB900067CCFC8860F89E24F82EB4F07918EB1B83
-:10ABA00053353EF87EE3707C6B4CE1F584217CAB41
-:10ABB000ADB705BF8783FE7DA799BE8783F9E6E819
-:10ABC00020B9484DE1F230497CFF660AF3D0F70026
-:10ABD0002789EFE04C51984F89C17D2E9FCCF765B6
-:10ABE000F9798602C1BF93145F17D6394C11FB3235
-:10ABF00085AC97C64D677E6A9DCC4EE7148A9983D3
-:10AC0000DAC916DF9D9876C96E69A1FA3F5F821294
-:10AC10007DD622CE430C41B7C0FA15FAEE0DF1A550
-:10AC20008CE76186FE6E4A650A9773FA3807D2F799
-:10AC300002A3FC147EDF0C5F325561155877749BBC
-:10AC4000C22CE100EFF6B70D24BF9D7DAA17EB40A3
-:10AC50001DB1E2B92F18D5BB4E7272F944D382757B
-:10AC600012DA7AF5782884F9303F364981C892F0B3
-:10AC7000E8A3F7DDCEF8398D22A6D207566EC78F2E
-:10AC800027935EF7539C54027112EA7583C543F80B
-:10AC900028C3E4CA44BEBF1109F314364BEC38EEA6
-:10ACA00057A4F1F56AF3170223E0B9BD32B15E4C47
-:10ACB000811E8FE1FB1E9154385C6AE7DF094AA0D0
-:10ACC000EF04DD285EFB13F8772123EFF75FFC7EAE
-:10ACD0007E60FFC781DF0D8A0C7C8FD281E74C300C
-:10ACE0007FE753CE07FBCD77A72CAD4E9918A897D9
-:10ACF000636EA6A25FA1AF9743F49D0B3ADFACD57C
-:10AD00007BBCEA9DABE2B9B98571163A4F9B6B19D2
-:10AD10009587762B23D15D9D42751F5B6EA14914EB
-:10AD2000EF44574480CFADCC3919F11CA8D7E3DFED
-:10AD30004F1A38CF94C0E8FC9FD5CCEB199F01B9CE
-:10AD4000C0EF178154A958D7C29E28A1FAC7A7A25D
-:10AD50002D0E3C87604678AD01781B2DA2EE47573B
-:10AD600077D96833D0F7381B59389DE79E15E6FE32
-:10AD70001EAEFFB188623A2F9DB56D5A12F983B0AD
-:10AD8000DE69DA7A0D83EB10B1FE0F9FD3D7FF692E
-:10AD9000EBC2E3EBF85EBBC097B64EBB76DEC7A94D
-:10ADA000849CF7D1D6FF4C385FA71177E2D3E859DE
-:10ADB00015F5837E7D1A3FFC3FDDFB356D605C0041
-:10ADC00000000000000000001F8B080000000000D1
-:10ADD000000B7B2ACBC0F0A31E818565181826F1D5
-:10ADE000A18AD112CFE066607804C42C3C0C0C859B
-:10ADF000407B23807424101F01E2A340ACC2CBC06F
-:10AE0000100BC471403C07C89F0BC4A5409C05753E
-:10AE1000632B0B03433B107702713710EB30333059
-:10AE2000E832136F7FBE0803C31309045F51126831
-:10AE3000A734FDFC3FD8F00A7DFADA276DC0C0B018
-:10AE4000D502C15703B2B759A0AAD96E81DF8C1DB4
-:10AE500068F23BD1F8BBF0E83FAB87CAB7D540E515
-:10AE60004B693130782285899D067EB7A0E30AA020
-:10AE7000DE4A200600FB72DB43680300000000008E
-:10AE800000000000000000001F8B08000000000010
-:10AE9000000BE57D0B7854D5B5F03E731EF3C8CC9E
-:10AEA0006412420818C2092FA30D382121058AED2A
-:10AEB000400091A206B50A1575C22309794DC0C795
-:10AEC0008FB56D0682111034582C51A39D2028781F
-:10AED000830E3448908003581A7A5183D7FA687BDE
-:10AEE000BD4129200412F185DEB6FE7BADBD4FE6E3
-:10AEF0009C9319E0DEDBFFBFFDEF1FBFF6B0CFD99B
-:10AF00008FB5D76BAFB5F6DA7B648B8B484308F906
-:10AF100016FE7E40C8748910D23FFA74BE4E549219
-:10AF200048485D0E2DA710923E9C848840C8E46A74
-:10AF30005ACE23E4D13B49C89A49C8FE2316FCBE29
-:10AF4000CACFCAB45DD8720DFD3E82BD7F328BB6CA
-:10AF5000A3EF9FBC2062BBE04C12DA4CCB4984F6D5
-:10AF6000368CD021FCF89CECADB78FA2F51BEFB46A
-:10AF700010AB4AC8137418329E1017F1D9096DBA74
-:10AF80006A38EBEFF19996E745013E46D2E6D3F2F7
-:10AF9000EA29C5F9AB69698DCCE06A9853FC7C90CD
-:10AFA000F6EFB10CC379D07A4F3A69BDC7DE2F21D5
-:10AFB000AB69BB0D732D427136ADD7A4CC0E65477E
-:10AFC000E7AF3DE71289B70B5A2DE3E0E9E3CF88FD
-:10AFD00002CF5F4CB4E0386BAB193E683DC592467A
-:10AFE000484BC7019B9FF6B7B6A2E5E834FAFD913E
-:10AFF000E1162FC52079A4E380FD4A3A7E30CFE2E6
-:10B000001D416BA74B11C1E38C8E379E50C0C7D238
-:10B010007ADE1D36D5D9B73EED7712CC7B0DC5BB98
-:10B0200098196D3706E0A4EDD6529285E9B8BF9421
-:10B03000BD8761DC5FDE902C0449B4DEF50024D4CA
-:10B040009B6B21115A8F483D3642C7593DF16DDB4C
-:10B05000085A7F75A1052641D67AB5EF5E3B81FE81
-:10B06000A68E3C3C1CE87A3DFD0EF3C87E7C36CCB7
-:10B07000FBB1290A01FCFF52A0F5288A1B8A941F04
-:10B08000027CAE6AE281F7F4E98B85D756C18670FF
-:10B0900090351B08C9270002FEADF685560E05FE49
-:10B0A000CA235E28A77B697B67DFF69D8215E9D2FC
-:10B0B00020070702FEE2D16F38C7E7EAAC2576A089
-:10B0C0000721F56985A308590F78824125BF3ACB3E
-:10B0D00015ADBF5260F85927139F40E79790A7849A
-:10B0E00096513C5BB23D7360BE4EBF42AEA3E55588
-:10B0F0004270A0087419A590CD2AF2857D042DAF69
-:10B10000BD2AD90BFC572784D324F87E03FD4EBB00
-:10B110003C5038660EF067A357417EA6FC7318F0CA
-:10B12000BDD69F4C56ABF8BD03DB3B877BAC880993
-:10B130000A0FC54B3FCA4B80D79C9BEAAE1F06F453
-:10B14000196BF10085560B93D4F9203F49360F8CCB
-:10B150002F8FBD19E927F74F16888EDE3F077A53E8
-:10B160003C3DAA16FE1C9E4FE77D943482D65F9329
-:10B17000F34A03D0E999FB6D48BF67C6762C06B940
-:10B180007AF242EEFB7E944BC5BB99F6F36CCE8906
-:10B190004C42077C7CFA474980BFC1C3EBEF216E6C
-:10B1A000FA9CD953434653F8487DE1824CE413E1BD
-:10B1B000168AD7C14B15A2DA182DBF25F09DF8C20B
-:10B1C000D9ACECA4F319CCE9DCD2F1B6AD08FA9B0A
-:10B1D0004B2223DDF8DE969A1CD53383F348249561
-:10B1E000F6FFE4C24328E7CF5C9DEA65729E86FCC9
-:10B1F00092C1FB4987FA54BFA4D94830813E07B7B2
-:10B20000F7DC0C700DCE3A3117E0DCFFC62101E807
-:10B21000F6ECE85415F45192BF837452BA0FCE7E07
-:10B22000F741A8E77286D20AB3B1FE5FB19D09FE6D
-:10B2300066D5B709F0B64DA83E0CF409E658BC8CAB
-:10B24000DE4C0FAEB93735047A64B0E34FB3C4A116
-:10B25000C80784A452F83C04E5A44E88D88641BBB4
-:10B260000758BB212424009E076705178B6EA8EFA3
-:10B27000170A5D7DC76D018D08F241391DF875BB58
-:10B2800042CA0A63C8C16B5C9EEB04321BF9994841
-:10B290007F03BE1992C4F8462B3F0BF0D071B7BFA5
-:10B2A0009EFCC36C0ACFAF960ECD11293C8F42BBDA
-:10B2B0001872B396CB81A39D04058AD7FDBFFB9D71
-:10B2C0001DF0B6DD424AA1FEA4ACB0AD93D315E8A3
-:10B2D000B190B0FE1BB337DA505F0859C8770BC77F
-:10B2E000293EFB6890BFE5829FB64FF330BDECF27C
-:10B2F0002A21D0CBAEB4A060A1F0A8D9C4B33193B9
-:10B300007517A4F89B07FF00469758FD356B9342CD
-:10B31000ABE9F779D954D0006F1457163AEE02C250
-:10B32000E639CF5BB718E84748A105F0B9DAC3E8BA
-:10B33000D308E3D0A934A6B37ED6DE4742CB818FB3
-:10B340003CACFD706842E9363CEF95FF25D07ED3DA
-:10B35000793B907B68979016B259683BB5DA4210FA
-:10B360003E29725800BA8F4A55019EC634EFBFCCB1
-:10B3700004F8674BDE8DF4F3708083F6D3586DF1DB
-:10B38000A1BEC8539A404FAFF6313DAFE12B938F2A
-:10B390009BEE8D0874EE2493EA49C4932F62F74024
-:10B3A000399BC19399C7E6D50BFF2825B49C364E2F
-:10B3B000B74508D4D3F050CCFB2BE6F370A68556E6
-:10B3C0004A00771E839BAECB084F7AB6D2047290A8
-:10B3D0009EC6FA53297E34BC035C0E0DAE3C5A1F48
-:10B3E000F4B0576902567070F88AB3193CFB8FBCF1
-:10B3F000DD2EB0FE50AE1C1C5E079F3F017853B996
-:10B400005EA7FD35CB1141A4F5436389BA918DA6A2
-:10B410004AF9D1EF8F57533CD082938F43D65B517B
-:10B420001EE8ABE0B7940FE6D7D37256543E46AC55
-:10B43000B41AE4C5C9E74DEA991C51B68940BB4C22
-:10B44000C2CA1628D379146719E58C7875650A87FE
-:10B450000BF89DEA9F65E315C63F57313B86105DAB
-:10B460003DE0F3B1EA736BF0BB82EB7AC64F150394
-:10B470007C83AB53278BA04FDA9FBAD9027C752F00
-:10B48000B18889C8CF42AFFEA2E3ED5812B1C32400
-:10B490001DED85C980B78CEAE4C90AE0B1DD8F658E
-:10B4A000477BB50F9FB0348D216410D18D9309FA7D
-:10B4B000D553DE4CF14AAA9530E8EBB17A38E9F77A
-:10B4C0008CD7EB6701BD1E5E7C6820C86FAAA9FD02
-:10B4D00068CB5094D3C1AFD35A38FE899F41FD55F4
-:10B4E0005C9F3800E231F87C1D9E839D54CF523D15
-:10B4F0009D4111AC8C89EA8BD557BD9BE37772FED9
-:10B5000049C667049E66BDA2AB7F15AF1F142E5AB5
-:10B51000EF04D6D3E0317F3F2758504FB9C0CEA4B7
-:10B52000F87D8C78E6E0BAECB5E0BA98C0DF87BD6C
-:10B530000726233DC3C42B6482BEFD9B55CF073F26
-:10B540008197A06FA530CA8992E140FB90CA710231
-:10B55000AC7B8D527529BC0FA73B08E88503530FC0
-:10B560000980CFF456FF109043CDCE9DEC0DA7C1BE
-:10B57000FB470EFBAF44F98C63376A76A2793E57DE
-:10B580005CBB1CF5C1107F4F3BACF7CE0AC97B1DDD
-:10B59000F0979FC2E5443DA992EF52F8BDC165A066
-:10B5A00067553F2D0FA0CF0AFE2C65DF57D594E6D7
-:10B5B0001E97A2FDAE1A4EED51AA17D777ACB7DD94
-:10B5C000007646B54505BE5DEB7DDBE673427972DC
-:10B5D0003FC0734BA166F74504182FFD1D1FDA7994
-:10B5E000633D8A0794D6286B64A047B75E344E7DCE
-:10B5F000770CC0416EA5441C189F8E74BEC867F1BD
-:10B60000D61380C5A25B47F667EDC0F5E50D721550
-:10B61000D2455B57B475047BA4FA653E97A347D423
-:10B62000B04D407D456597D2673ED7234EAE37A9D2
-:10B630001E667A8EAF276B17A7E27AA2E94FB0ADEC
-:10B640004149CCE7FA766DCEF3493750989CA06714
-:10B65000412FA591C9B0FE8E003D03FA490A0A3078
-:10B660005EE3580F598DEB98519F8EA8667AF09142
-:10B670003482FC44D7A12658EF1AD3C369D04F6354
-:10B68000F501C1AF5B3FB5F5CE55DD41400FCECBE7
-:10B6900063EBDCBC6C36DE1F00416319BCA057CDE8
-:10B6A000EBDE2F26EE406599C0ED2D33FE050BB382
-:10B6B000031F9BF936E271ED82C7F149EA37607FDB
-:10B6C00069364683555907F0FD1ABF653AD8DDEB58
-:10B6D000A58E95C329FCEBA7CF5382F4FB1A2FF359
-:10B6E000BB564F9CF73CAC6B568BC2E0AA2E457BF9
-:10B6F0003581C3B501FA463F5141BFE8BE3B37AE85
-:10B700001C4AFB49A37E8CA042A590CD4ABF3B8139
-:10B71000A6A0BFFD1106BF974C2631E0FF57C1C15F
-:10B72000FC507F47FB08A4A7C503F026787B6CE09C
-:10B7300027AAD40F53558057B58F42782D9E656A3E
-:10B74000B4FDEFB9BF70172CFC60DFCF79773AC832
-:10B75000D7BA3B995F6686FFBE49A1760B8E43D070
-:10B76000AD73C5C1EB5CD060A07FBC2184CB95C517
-:10B77000E03A2E307A3DD631F97AF4930AE97BDA51
-:10B78000D1E31D43ED20DF667BEF99840F73D0DE9C
-:10B7900031AD33972A0F36E9FB51D6F00CE4B76D83
-:10B7A00016D45384303D27108BFAED305844185C82
-:10B7B000C87A547FAF90237316D0FA2B763A09E0FB
-:10B7C0004BE38774DEE7EA6ACA0731E6DD2E88F1CB
-:10B7D000E8CEEC0C4EF70E18AFFFA5E94FA5D90E39
-:10B7E000765B385437A80CFC8F6AE6EF8623075047
-:10B7F000FFA44FB90DFD942D4DA97316005F65F997
-:10B80000BC800E0D1EB04F62F989332CB68BFAEF57
-:10B81000F1F47043C50AF47B1B3A62CF7FA285F92D
-:10B82000DB61AA27BDD9F1C7CFB7303B3AC9C2F90E
-:10B830006EEAA134FD7AA6ADABDA3A3B582241510B
-:10B84000B71EDECAF1675E3789546F1BC9F81CFD4D
-:10B85000C786052C0EB161A205E32B1A9FD37A6926
-:10B8600080573A0FB4E7281F86C09E7B8CD4A3DC98
-:10B870000469FBCDA42FDC7712CB65CD6F029F5FEF
-:10B88000EF78DCBFBE8BEBAB7539F7DBA12B3A5EF3
-:10B890001AF047C0CDF464A58BD9B1053BE5C80FBC
-:10B8A000281C954D02DA59967D7684F3DC265AA63B
-:10B8B0005D475C0AD63FEBB1613960ED78F47BB44B
-:10B8C000DCB35324684766392CC0AF2738BF923C9D
-:10B8D0005A067BD8CE8A954DFBEF82FE4A5BADC4FB
-:10B8E0004EFBAFDC5D72E3F768B9A45D2650A5722C
-:10B8F000F33265102D2F0A096128774FA60B15E04A
-:10B9000025590981DFDEEDEE48FD119DF7E91A1B8F
-:10B91000512928B5AE8ED45B293ECA42DBA741BB74
-:10B92000B2660134229DC7E64303615E5B052FF8D2
-:10B93000F7E55B120CF6E0093A951FD0EF4BE83CB7
-:10B94000412E4B48FD3458E72A37AF53545DFCE194
-:10B95000748D07C7D1CA955BE938B45DD54B8217A2
-:10B96000A65865217ED043E776DB673FE784F92D53
-:10B970005346BA605E0F2B50AF2454F48A5D05F82D
-:10B980009A9469F47B59639302F1AD8095DC0D7E46
-:10B990006EF9967E46B81A4494D72549B68DA0CF45
-:10B9A00089D39776F3A8BE743E5D4375ECC868B939
-:10B9B0000CF421F2614899A5AB3F444C427E2DDF47
-:10B9C000221AED6CBEFE078F32FA07F7BA30EEA7E7
-:10B9D000D16F09F79735FA2D49E2F4947AF263C1F1
-:10B9E000F328D083C2530FF8A2CF351C3EF7443260
-:10B9F00009E22E6E1FF10831F8DAFCAC974911B05C
-:10BA0000EE3F2D9F35491A88EEC362883C7956CCAB
-:10BA1000993485967F6F29DC6C41FDE155418E3468
-:10BA20003FFB590B93CBBA810AE2AF7E6AFE732CBF
-:10BA30003E4170DDAB9F5AFC3CD805B4FD360BCAC5
-:10BA4000216D3F2A7E7BCFB47186F69E69A55AFB95
-:10BA50009DD8DE76F1F6F5D32618C79F56A6B5DF3A
-:10BA60008BF03B2F0EBFE7BA89C6F1AFABC0F60132
-:10BA70002BA3574F920DED9A1576AF4F6276540473
-:10BA8000DE4BC92337423D51E307D2E103FBDBD94B
-:10BA90009C346635D1F3C5E437000E1795163D5F2B
-:10BAA000248E7318F831C9976C28D39E3C27BEC3E7
-:10BAB000CB3088DB86F0288314D4179306D910DEA8
-:10BAC000FBF7D9B17CFF0406EFFD839C2867B8B66D
-:10BAD000503ADEAFF8AFD1DBADB0324128E94DD1FD
-:10BAE000FF11E037FA5EB5C07B8748AA513F5B097A
-:10BAF000EAA38733F39F0BEAF0B37230A52F2D9F93
-:10BB000005FBA77F14AF0F0F2E4E2BD28D53375846
-:10BB100099BD319BBD9FEF84F10ABB010F01A56761
-:10BB200024D895E671AC43C719C6B16594E238DFF5
-:10BB300098C6B166949AC6B1CDDEC8DFF371FE0235
-:10BB4000F38A37CEC3432718E7935186E35845D38A
-:10BB50007C32CA4CE338D87CE87B3E8E5DBCD87C16
-:10BB6000864D34CE6748058E93222A86B89575484F
-:10BB700085691C278E03EF611C92CEFC1BC5DA532E
-:10BB80008CF47FCD4EC09E56ACFE17A05FF2473BB3
-:10BB9000417DA2D27107805E49C6FD827FB524E354
-:10BBA0007CBE7450FA3BF5740E6A7601DA3B0B39B1
-:10BBB00088245487FE7915E7D105CDB33296C1B3F9
-:10BBC000B520AD08FCECF52E2FC44FCFB51628F3E9
-:10BBD00063D8050BEBE5139D06FEE57A6F32C9AA23
-:10BBE000063F8BDB015AF904D55F84EAAD8FA8FECE
-:10BBF00082E74999EA69FAFE38D56F44D1C3BB0C94
-:10BC0000DB9D90181E4F34B275E4CB7547658CF3FD
-:10BC100005C93B59741EB7F1692CAC4F60BE028751
-:10BC200023C0E9D1B3DB1ADA88F4F05D01760F693D
-:10BC3000E84771C5EB0D057C517149C6E215601FDF
-:10BC4000FD78E5F6DF40B57785A2C14BE87C67B7A4
-:10BC5000AC93AFA0E57372E75D5EA7AE9FD9F247E4
-:10BC6000306F1BFD0FFA99E3A765DDF877941ACBC7
-:10BC70007712295AA6749B2A0EE5F4E0E3AA21194B
-:10BC8000E8755B2A83E74E788E81CF1EA4D75D1EB0
-:10BC9000D6568327F0A04C22B81E75F667C66D7F76
-:10BCA000ACE7D7D615137C77C9365F21A5E75D0FC2
-:10BCB00088884733BC9DFB127C16EA5775367C2674
-:10BCC000837F7929F8EF5E6AFC4E826C3C0DAF1AD7
-:10BCD0001FDC3E7B52BFE3BA7A73FCD7F73BAEE37F
-:10BCE000973B4A6719CA7756CF31D4BF7B6991E138
-:10BCF0007B517091E1FBFC958B0DE585F50F18EA02
-:10BD000097342C337C5F145A65F85EBE659DA15C48
-:10BD1000197ED2503FD0DA64F86ED977D54D208F96
-:10BD2000B5BF1709D8675F384F3C0AF6D5174E09DB
-:10BD3000FDAA2AE0352A87A76AD290BF4FD7A8F874
-:10BD40003CD79A8BFB6301079567BAD66FA83DBCB9
-:10BD50006CE544D023B43ED5E14FD7BEB52C487D29
-:10BD6000F78D10A4A67C2F362824D20FFC98E45E11
-:10BD7000BEEE1175DF3B2FF1BD812E58B97DBF8B13
-:10BD80009DB1DF770B3D23C1BE0B7E60C5FD9B7867
-:10BD9000F603FDBB82C4F01FB46717C437747AE79B
-:10BDA0003591D9D5D788935F13E9B34261F25EB17B
-:10BDB00063E064881754289191D531ECECDEF1C230
-:10BDC000149801D00F939745A12BA2F28BF41B6618
-:10BDD00090FB1B2CFE7DA09FBBF68B6C7F207230EE
-:10BDE00003F669AE117DAFC17BD2DA1FD7C7776B7F
-:10BDF0007CFD8E0F27E4FD9AE9F8FC434D613F88F6
-:10BE00001FFDA96636963FACF1E3B3B3A6149F1F9E
-:10BE1000D554E3F7E3354BB17CA22688CF53352BBD
-:10BE2000F179BAA61EBF77D53460F95C4D089F9AA8
-:10BE30001C68F62849E1F61FB7D7E9CA81E5F37C0B
-:10BE40000E22FD7707CAB5370DE4FABCF3CB91603B
-:10BE5000E79E7FDF8A41F4787832F35B7CFAF970F1
-:10BE6000BD2F0E51FAE7F6FD6E7730FAD82D643A01
-:10BE7000F867AB462804E2EA8ED7BE83F6327D2F00
-:10BE800011D49721AF7E1FB1B77F98F3804BD34970
-:10BE9000AB7FE2A97FCF9F970DF461F4751C14ABC3
-:10BEA00019DD9EF302DD74F86376D94EAECF4D787E
-:10BEB00094B8DC99F179B6BF86CF8E0C88B7548AD6
-:10BEC000851689BE3BDF62C5799D6F4B60FBD89EAE
-:10BED00094CB8AE7956FB17BF4FAA1329CE431EA06
-:10BEE0008B811EBDBE38DFFE9C1BE47E499AC57364
-:10BEF0003C17F8C3C7F983F19DD67F6538D3E33487
-:10BF0000F4632C9FAF17A6B37D4535F1D618FE819B
-:10BF1000F65C92A6788E53BD707ACBB0441897FA2F
-:10BF2000711E18A7ABC6E361E3A679F47C59B1D4BE
-:10BF300081F535F8E2F5FBF7860F76FC3EB6B15891
-:10BF400013C469E2D58F4B0FE97305FC03D2267F3A
-:10BF500009EB8E234B5B77242C6BFD06C262D07AF3
-:10BF60000DBC6F368C47DBA99A0F0DEDE2D35D2235
-:10BF700027347A523D791DCF0FA1CC8C74F6D31E95
-:10BF800013697FDD927325C479332515F55D0006AD
-:10BF9000A2FC5469EB54FC2AA2BB03E39EE334B930
-:10BFA000576FFF2365B94FFE59C67806F90BED9D13
-:10BFB0007E97F9D705A4D00D4EC6BC96F299A0275E
-:10BFC0003FB168F6407D3ECCFB2CB1E07EFE59F2DD
-:10BFD000B63B576797954A3C3EB992ADCF41FA1FA1
-:10BFE000CC8FDA6986F5BAA4C1582E2637A7823CD1
-:10BFF00014AF9761C7962C82F55EB76F325BF2E0A3
-:10C00000BC4B48751DD829AB65B68F3ACF43A42BDE
-:10C01000285C95BB9EC9077B3620317DAFF9CF8B5D
-:10C020009219DC652921C547BF7FDC927BDBF708CD
-:10C03000B40FD5815E0BBA8837563C66FE4A237C26
-:10C040009782DF0C2F21CB0D7068FD6A70885B84AE
-:10C0500098791A3F93041ED761F2B15632DAAF8F46
-:10C06000733C68E50DA672A3A9BEC62732E7934CC0
-:10C07000C9FF38E89F4A5BCF34B4D308E58FEC683A
-:10C080003D255A6FC3C5EA59A19E88F51AA5B1F19D
-:10C09000EBD9A3FD35C5EAAF72D7B65782949FCAD4
-:10C0A0005E7EC20D41DF4FA4FA54887F556C7EC876
-:10C0B0000D783A2505DD40EF4F4262CCB8E07BBDFC
-:10C0C000F8F23905F02390B529DE5F7CE446D0D73D
-:10C0D0005F6E96312F26B0C51AB1523EAE6A593402
-:10C0E00013E2F7B47C8C951FFE14F60D03AD467A6F
-:10C0F00096BDF0442AC489282699BD4D22687754FC
-:10C100006DFAF334D0E301D2837C686E07E35F48B5
-:10C1100046B92F5212FB7ED7F215025CCE022D8F4C
-:10C120007C0A79090113FF94F6AE279D0AC411DA3F
-:10C1300025570AFAE5DF25DF053DA0E18384983D18
-:10C1400051BB75C3E863149EAE4DFFEC160C7E37F1
-:10C15000E3C3F3E1F9BF7A558DAF67CE717F28DA7B
-:10C160002E84EDD45666FF9036F6AC90236EB03731
-:10C170002B9A642FE55052B1EDB9E79F023FED03D2
-:10C180002BFA69E5DB7EF3EE045A2EDF2EA7CC6492
-:10C19000D3710AA951BA04E8FF968E89D2A1ECD7CF
-:10C1A000BF51D451ECFD4F93A3F428DFBE5F21A310
-:10C1B000FAE2AF20BC5FE974C6A04BF8D834B057A0
-:10C1C0006AB77EA580DFF5C93E810CC8ECDBBEB442
-:10C1D000E937B81E029E908E9C4EBD74EB43AFC8EB
-:10C1E0008DAFE6613D0FE8C978F47A91EBE5CA5D61
-:10C1F0002E9204F1CF3F584333818E2FDDE38679B1
-:10C200009C94AA195F3FF3502AECFF95CAC1540FC2
-:10C210003ED9FBD267EF437E2B11AA53D93EA66FBE
-:10C22000208F970F84F92D6CFC11CEAF98F891EF09
-:10C230004A9F110B213EFC8544A66F8F211737C8FA
-:10C240006CFFE9E4462B24F9919360E7837DFDB60A
-:10C250008871564216E33ED87D5A1C972CC1F217BE
-:10C260007C5F6AB86CD1FC439B815F373DDC01F495
-:10C27000393DD83700E0A47808727C09B0DF2F1E62
-:10C280009D3A80D187E51B603BAAFF0BE03DD4EFD0
-:10C2900090719F50D78EEB4B36FEBD7C7C0AB70366
-:10C2A000D6B393A96CBFD23CBFA57C7EF4AF83E824
-:10C2B000F84B27DF4CDE37AD62F2ADC97B68D67430
-:10C2C000F8FEF93B4C7EA01DAC1F14AEC800FCBEAE
-:10C2D000FF5601F581954462C9F52699CBB5F17BEE
-:10C2E00080CA29C40528DC12E43344F984F69F8C03
-:10C2F000F847BFA4783D6DA7B3CF02301ED653A236
-:10C30000EF75EB4709D703D365A3FC93C6FE97658A
-:10C310002F56C82408A665C50756F4BB2BB6C98599
-:10C3200030EF33CD07DFFD31E5EB33614D4E8DFA54
-:10C33000D32CA7A53B360BC09F66393D534A57EB1C
-:10C3400058724ADFC794D3D2CEFF2BFA53C35BC0D7
-:10C350008437AA07872459E2E3CFAC075DB21A53AA
-:10C360000FD2BF77487E5FBED3F84DE3336AA10D8D
-:10C3700001FDDDCB8F1ABFF5F2A3C66FE6791AF186
-:10C3800066FE3E010C350A57E16E19FD928A36B6FB
-:10C390007F43DB1DBA220FF1E3C3E58BD41FBA2222
-:10C3A000455F0E99CA61537D9FA95C68AAEF3795D6
-:10C3B000AB0DF52B5A0F2A2CC92862A8675DFA1419
-:10C3C000F938867DAFAD3381964F9520F0437A8F53
-:10C3D000027A4E5E4E4D33889FED15D1DFEA567BD3
-:10C3E000DCC9F4FD4376E6C7767B783989957BFA1C
-:10C3F0002B75A0E7B4F73D7616E7EC2EEC7127E934
-:10C40000FCFB636DA21BF6833B432C1FB52F3CB591
-:10C4100028379D24DE7716179C2A3A339682FF56DA
-:10C420002F7AC1355CB0EC7637ECBB75B70DBB69C4
-:10C43000367DBFF0B008E633E976B847035C24E800
-:10C440009306E6F3FC09FA778A047F3911F226DABB
-:10C45000987DBD608DC91E76DEAB607ED97A5D5C4D
-:10C460004BC7FF65BC9FD246E3F732B206F9AFCCAB
-:10C47000240F7EEE0F1CD5E42187E4B0FD6DC2FCD5
-:10C4800058AE77A78AD937CDA678EF6E17316FF6F9
-:10C490007C9B48EA609ECD02EE7392607F94AB2A4B
-:10C4A000D283FA4EC34B17C88D125F1F75EDFCD7B0
-:10C4B000FC07813F5EF9E3E8A7E9B3EB950F46EE91
-:10C4C00081F2AEF732FE48FAD62FD8F735EE237652
-:10C4D000EFB3629CAB7BDF6F331E84F2AB568C7381
-:10C4E000752FB7E23E4A709F2B3402BE0F66FE40A6
-:10C4F000EDDEAF46B33CC91548A7BFC8CC1F39DF36
-:10C50000F6EF1F42FEC8F9363A2BB00BF625A0DC39
-:10C51000045EB5A3FFDDBDF7AB7CBFF3EF379F2A09
-:10C5200085F891FF5C64F60EE0D724160F0EEC1927
-:10C53000FF1CE43757B6EC5720CE5EF0DA5F478336
-:10C540009EECDEC1EC9D7372E7B3B01F66553E5D95
-:10C550002E533C9F03E11944C873CA988260762C1D
-:10C56000BC303C74533CC0BC285E4A41BFC7C34783
-:10C5700086F28F8A8F4FEF627AECBB98671FC58B6C
-:10C58000E063EF5D219B80F367EFF77D351AF4CC14
-:10C5900099F032B4472E35EF6B15B6CFF23F67DE18
-:10C5A00042E472E63DF71F96DE8CFF3F82F5B57FD1
-:10C5B0005F39E8CBE7BBEEC7F24B2E2FC27B99F277
-:10C5C000FFD3FF6974DF41E9EEBE34DD9FFE879D36
-:10C5D000F7A5E87E98D3DDE581FDE5EEBD7FC5B822
-:10C5E000A936FF4BCDFBD5FF47E7ADD9EB332CD5B3
-:10C5F0004766D1FA4748647D2185F3F5F4A9EFCC6D
-:10C60000A25F7F1BC71E39ADB0F8C76F09CB130CF3
-:10C61000A6092CCF83FB450584ADEB05592568673A
-:10C6200014643D82F60191AA8FE4507CCCC858E88E
-:10C6300065F96063F01CCA7503AFF5623CD0E41F76
-:10C64000165C7D7D3BF829079751F8E83807078B82
-:10C650001E6A299129E972C43A1A9FC7E079C83D38
-:10C660001DEB4D711AFDA399E0DFE8FCBDEB55E32E
-:10C67000F769BCFFE9E4400AE4934CF7CA2404F5E7
-:10C6800048FD0AFD3EF234533F87C0AFD5C5CBFE0F
-:10C69000A3F84BB7323FF2B764C9911CC05FBA8CA4
-:10C6A000F1C04BE28FB0FCAFEB06E6E079142279E3
-:10C6B000117F330655727C32BF59E2ED25675D0765
-:10C6C000C8AD44A8DFCBEC32F49735BFF7527826DB
-:10C6D000DC9F96F8D01ADEA57419F35675FD225E1C
-:10C6E000347AFC47E9A0D1EF3F4B8F73267AA47FC1
-:10C6F000EE91403E0BB8FD3FE5F30E11CBE95E092C
-:10C70000F7A3B8FD3FC9992481FD7FAD745404B9E6
-:10C710002CB1B5CE8038BDCD2B205F5FD96541FFF0
-:10C72000C6962720DEB31A242C1FB578C682A17DB9
-:10C73000E3F7769D7980407CD8A7A0E14D0A597C2B
-:10C74000FE2FDF7E3B513BAF81DF09B981FA5F0BE2
-:10C750001A49C441E7B75022C1C46488EF0AE423F0
-:10C76000437CD75886BFEFA746FBB954FD787AE4DF
-:10C77000EFFDDC45F5D647942976C313F755282BF2
-:10C78000E8FCE3EFB6317C058E90D050D40B3EB17F
-:10C7900050B76FF68895E98F5D7FDA910B71B149DB
-:10C7A000DDD9894C9F0E47BF20C0FD82F3444D84E4
-:10C7B000FC83F36DC312715FB05D74F963C465B639
-:10C7C00072FFF99F209F823EBB37917A3887D14D07
-:10C7D0007A301E1BDC648BB9BF7BBF558B3771BAB7
-:10C7E000D13F513B6FA462BE4830514FB7AE999FC5
-:10C7F00048A3FBD201FE3ED2ED97FC57F10BFE3A67
-:10C80000E077ABBD735AACF3602B39FE6E3CF0356C
-:10C81000C631AF6E6BB200FF5EBDC962D86F0C5AF5
-:10C82000B9DF35868C01B86E3C6077E5015DDA458D
-:10C830002FE40F06DA3E55FC31F6ADCCF884FE212C
-:10C840002EBECFCAE2FC7BE4F07CC0EB9EB336CCBC
-:10C85000CFD9ADD497C782F34A3BD3730B49F89E27
-:10C86000D199FF78F89DD4ED8C4C063F7313E1719C
-:10C870000C33FF11E4E3F35B089E0F05BF14F4C211
-:10C88000F966760E98A2642DF8D354DE7FA08FCB84
-:10C890005CD9BAFD9FC00EA86A133C903A5B25751F
-:10C8A0002A106F0DB42689B0EEE6A85A5EA567D4AB
-:10C8B000AD3AB9D86765F9C60727ECB903C6FDAC30
-:10C8C0004B21608FF85EEF71C3BAFD595B6E62ACAD
-:10C8D000BC79EDF9EB1A32638A04FD10C4BB991FD1
-:10C8E000B29B1D86F2F744FF2090AF1BAD9DF77AF7
-:10C8F00063D0CF6F637C76D9FA2DF4FF997E7B47A6
-:10C90000D36F7EB150274759B63EFA6D402CFDB625
-:10C9100044500700DE97EC1D3600E8BAE4B0DC3F77
-:10C92000967EDB56C3F6F35EE6F9B0DD2D54BF5DAF
-:10C93000A3D36F2D36CC8B33B74BB659F8BA7809E1
-:10C94000FD16FAEF91BF6DA0DF62CC77848DE90D03
-:10C950004DBF8D6E3B86FA6D748BC590379A6EBB5A
-:10C96000947E13FADF0AF670BBEC4D88C13FDBB84A
-:10C97000FDFD32CFC3837140CFDD6163FB9B97AB7D
-:10C98000E7B2ED8CDE97D473FF4D78D6F4DC929D40
-:10C99000DA3947331F323DB76437D57302F023D3FA
-:10C9A000734BF6B27B1CCCFA2DAB8F7E2358BF2A7B
-:10C9B000C2DA075A3337CCA5FD8DF1C95E1BAD3FF6
-:10C9C00026AAEFC6EAF5DD1D3676EF421F7DD77E3B
-:10C9D00079FA6E27D777548F0D05FD6AE60F6F9BA6
-:10C9E00031EF78CFF893CDBF06797943C47DC3A3E7
-:10C9F000FC5CDA9BE34FE6017F35DB98FEADE5FC9E
-:10CA000077AE2688FD17BCCEE657E964F9C8552DE8
-:10CA1000CC3EAC6A16422AFDE7B4095F2B00FFA2A8
-:10CA2000BD021940CBB3ACAC3E7941DBF722337386
-:10CA300074FCB0605C39C6ED1748C40671F972E742
-:10CA4000B44F201E5F3E8EC5F1CBF9FB45873BEB13
-:10CA5000209EBDE84901F73D09CF07D0F21B4BDA14
-:10CA60009661BCD69C17A0E9F34521E3FB72533EC7
-:10CA700063139FE72CB113F142DE1263E62534996C
-:10CA8000F1D1CEF1B149C475B3171F143F6A665F87
-:10CA90007C508ACECC498DCE7FD11B745E79D17902
-:10CAA00069F830CF4F8B3B97F376F1E6ABE1AFCF30
-:10CAB0007C357C9AE6FD1CE80D5008392417F2629B
-:10CAC000281FA0DE08FE4EC4F3FB8593460CD0EB76
-:10CAD000E1AD5C9FE7D64F2A1848005FA41AF8A67C
-:10CAE000B861F1A18174DE63DF57C7C0F2F8BD09F8
-:10CAF000563FEC8F6EB5F7A05ED3F8EA1BCE57EF2A
-:10CB0000723CEE19548DE75403AD8207EC8A40C4A1
-:10CB10008EF80B50FCC1F995003FBF18A0FC05F240
-:10CB200074F0C92F19BEF60A2AC4C7A769EB0FE033
-:10CB30009FD6CF6D63F80F8404C47F1EE9C1FD91B9
-:10CB4000AA06C11BA1F5AB5A1763DE83A66FE99F46
-:10CB5000534F0F1D3F4AB1F8112BE9D6BF725EEF5C
-:10CB6000466BFDBBC09F37BE2093261D7F66D1FF5D
-:10CB7000BE8D41270D9F97E2CB0B1C4FDB008F4EE4
-:10CB8000C0570FB39F225FE3391AED7B400A1AF0BA
-:10CB900058F0D4858BE269AC8627E053D0536D45BD
-:10CBA00022948B5B05D22FB3EF3C617F522FB78B62
-:10CBB000F61E63FD3F23E0BD2566BED5E6DD876F2B
-:10CBC000E3F02B9C4B03BFE872F9F61B13DFBE6941
-:10CBD000EF39920B7CBB5760F183B624C3FEE22091
-:10CBE0003B5BFFB7DA297FC3BED661D9BB51ED2BC2
-:10CBF000DF097CFD02BB5F7F2EE92A9808E43D6EC9
-:10CC0000B1611E19C23194D9957ABDBACD4EFADF01
-:10CC10009A17BFFF81BCFF78768D561E05E341BE93
-:10CC2000572B1D2F2B3A9E59AF6B7EFEA5E635F292
-:10CC3000BF38AFDE3C4CD281FB4E9992FF31AB2E18
-:10CC40000FEE369E67442140FB4A572FDB76917AE0
-:10CC500024CD83E79FEEF1687CC6F2DD0B791EFBE5
-:10CC60005471E27BB07E7EE663FB7C7916F2FB8931
-:10CC7000A09F27CB788EEFB32332C66B3F9BC2F2C7
-:10CC8000386F7AE3A004F1999B4039517CDC34562B
-:10CC9000407F058E61C1BED92E6ADFF846E27C7204
-:10CCA000E11C57CEA6FA02387F3C664BA8169EDEE2
-:10CCB000829E9437018F93440278ECF0F52B80FB31
-:10CCC00093EEF933C1FB43E83A8BEDC7B493FE50C2
-:10CCD0006F82AF3FBA03E35BD617407C74D641A79F
-:10CCE00013EE67C96AB4509F218ABF0924540B719F
-:10CCF0009BF1C77DB700BCA5D45E80B873695B5358
-:10CD0000AD1BCA8D8257A5FD0782FE696E3A8F6DF5
-:10CD10000D9F4EFB0EC823AD07DD041A59BDC0267A
-:10CD2000B87808DEAFC33C9BE24D021EFCDA161257
-:10CD3000888DF51BB2D17EB735D2F679B04ED0F6DC
-:10CD4000D0EFA64FDFB905E4FD88C8DA37B37DEA36
-:10CD500062DA4E05BEDDB418FB5BD4289034DA5F8E
-:10CD600069335B074A8FC85EF8DEB2FF495CC7666D
-:10CD7000D2F1066682DE8F4C8132C9153C18EFACC9
-:10CD8000188974EBE6724E268E60FA43E065EE3742
-:10CD90006876D3BB7696EF5BEC5DA6F4A3FDBC3959
-:10CDA000AE7F26A405045A3FC5FDE7E314CF7EDA23
-:10CDB000E5519EB77170DCC74AA76E1DFACCCEEE66
-:10CDC000B75AD03A09F319169242CC67B8713CB3FE
-:10CDD000D7DEBAD61E822B0EDE927BD2E1FDC16B6E
-:10CDE000AD68FF9EDB26231F9D1BDC89F1E9938D37
-:10CDF000329E1BAE6D64F7739D6C66EBB8F80CDB6E
-:10CE0000D72F7129583ED878CB3458DF4E6E62E761
-:10CE10001D0B9E99AA40B9A449F0B2FB8B987ED411
-:10CE2000FCB7620FCB47D0F45F259F779FBC45933B
-:10CE3000BEABD4D61B93BEAB847D65373C8DEF0370
-:10CE4000C4C9F420D8FD40F7C8D7C8BF554764020D
-:10CE500076BFF071D734CCC7DA2B603C7F7C9BE087
-:10CE6000837DFDD2F7AD21B457434577FF04F4F835
-:10CE7000075622A890D74EF14EF5C3386BCF9F7E50
-:10CE800041DF7F72D4069930944F8A10CF5AFE67E3
-:10CE9000DE6696C79277747D2A9CB72453FAA1BEAA
-:10CEA0002D6910895FA7373E117CB7FC98E965BCF6
-:10CEB0009F42A35F9E525F0CEBD83007D34BEA66CC
-:10CEC000197244C8611E27A1F6349EBF5DB47B5D14
-:10CED000AA42EBD5F1FC8F457BD7A58AF47D2DAC1A
-:10CEE0005FB4FE2285F5BF689FE069D2F5AFB5D784
-:10CEF000FAD3FA51761BFB19B697972FB31F0D0E75
-:10CF00006DFC78F6F8B87FB9B01EEE8B19F79688ED
-:10CF100049C7E33E9E394CBFDFA13DB5F86BFE3BF0
-:10CF200016E2D3E16DDC9F1CC4A7E38B96B154BE1F
-:10CF300029DD6E681542004ACBD8634A651E963DCE
-:10CF400020CF553C4E5B3585ED5BB5E41C5D01F2B1
-:10CF50003D334F403E2041BFD22F05ED2015F6173F
-:10CF60004AF258FB12DA1EE4AEE5492687541FA8A0
-:10CF7000A02FAA1AD74DC3FA9B0415FA6F692AC2CB
-:10CF8000F5BE749C48F0FBA663687F94B61E4B0107
-:10CF900079A5F2B91ED6DFAA8956BCCF4B933B4D7B
-:10CFA0008EDF92F97D4D36CF28C8EB7F10808A2125
-:10CFB000BFE211C2FCD46619E52C308EC9E55BDBFB
-:10CFC0004494E783D7DE8E72786EB310478E0B14CD
-:10CFD00038977C32C4BEF7CAF15681CB31D30F27C4
-:10CFE0009D4CAE0BE03BC8F14E81FB83CC1E34CB95
-:10CFF000B126979792DFF22D26798E23B71D52E73F
-:10D00000AD30EE3DD7DA11EE82EFEF7EF71ED43F62
-:10D0100032E67D147CFF8154D077C512CB57D2F015
-:10D020005829B17CB63E70AC5FA60CBC2C788C70D5
-:10D030003C6D7745F587087CCEEEE10A6E9291CF84
-:10D04000CD72F85F959FBF973C1FE6FCA3C123EE0E
-:10D0500065ED217F2C42F1F4DBE6E7304FF5EC8BF8
-:10D06000C76E043C97EFA17C4BE77BAED9C5EF7B45
-:10D0700009E13A53D622621E389122F9B7B8F47208
-:10D08000C9F290CA5F76217F94ED60F9A465AF7C08
-:10D090003C1AF34496F7607E55F0456E6F063B47A9
-:10D0A000035F97492C1FCA2CE7B73A98FDD9B53BC7
-:10D0B0006136CC43D8C2CEE997856F97810FB57A98
-:10D0C0003F74C85A3DDCBF0C52BE85FD75804F7F52
-:10D0D000EE5CCB83EADACAE4BEAC55467FA96C4B62
-:10D0E00013C6B1035B3EC53CF78297B761FC20D005
-:10D0F0002A1AF31EB788B87F459FB84F65CE3FAC5C
-:10D100006AA9C4FDB6AA30CFEF33E5BF95BFBCF71F
-:10D110009520454DF9AF5F70831E38DDB1D90DF80C
-:10D12000A4FD61DEE0F73F970C7951F1F37B7DC6FA
-:10D130007CC2F0AA98F984A7E11F94C11F70707E89
-:10D14000D5F230B7F4E379DA91FCC218F1FBDE7363
-:10D150003BDBBE7816F2DCBB769C7916E0AEF8DBE2
-:10D1600067CF423E13D967C77529F0E2EF314F58B8
-:10D170006BF70B07F7F3B7BE80F9D5E73EB0A29F78
-:10D18000736EEFC90CC85F3BB7FDEB5488C7DDBBBE
-:10D19000772AC62BEFDD593080C4D0EFDA13F8328E
-:10D1A0007419F9DD663A1C6C3988795767DFB7A2C4
-:10D1B0003EEBCD0B0D57B23C5B95E78336C7CEA354
-:10D1C000D7F218AB5A6EB9E95AD0CF2DCC9EEBCD21
-:10D1D0006BBC541EE83B949ED75C06DD9A799EAFEB
-:10D1E000896E67E11F943E6113DDBE6859F8ABA7F5
-:10D1F000E05B4BBFB879A091CBC09796A7FF738730
-:10D200006F8F03CEFDED4808A6317A85660A60EF80
-:10D210007D9101E71A4EC93D98EFD1B3D7EA817CE1
-:10D22000C6B2BDEFA17C9CDB7914E3AA84E7C99F59
-:10D2300023BD7F2CAF59E0F3DBE462F9A31CEF9030
-:10D240005FAABAF13DCF23657CABE597C6CB2BED4A
-:10D25000710C6571687E6EA092FA49FCDEACDE7CD2
-:10D2600053611CD0E998214F579BB7B93F0FD79B0B
-:10D27000D1FCE8D879BB5ABE60944E6C1DD1F29FA8
-:10D28000CF35F1BC69FA3E7D0CE4C1B1F53A10121C
-:10D29000DE2331E451CB8F3EE330E545872E2F2F3F
-:10D2A000FA52F0FE67F1F1A183C5AB35BC74FD25E0
-:10D2B000B63E561298DD49FD533901F705987F7A3D
-:10D2C00037F74F357C69F0D68599DDD0B585F907FC
-:10D2D0006679AE8A735F520A1FA7AA75FF68D03BB2
-:10D2E0005D0776737E63FC5CD57C8CE5DD52FD1CAE
-:10D2F000D2EB677EBF84B9BF0CDE5FA02D767F8145
-:10D30000E64F63F6775AF2DD0EF09FEE6076D2E9D3
-:10D31000B0383DD6FD36B604D9903F50E762F76588
-:10D32000886E07DA47F7BAC6BD9F98024F05F37AB1
-:10D330006A97F13CA09F79F15ED15AD70C02F03C7C
-:10D3400004F8D1C519648F9F809D26A715E6896AC8
-:10D3500014DE5E7AA45848484F7F29920EFAFCC327
-:10D360009C9332F4F76FA6F8C8BF49A46E0085EB12
-:10D37000DF828277991ADFAED6CAFE9F8A86784608
-:10D3800095B5E743B0CFC96B76DC0F17F7D9831893
-:10D390001F7B96DDAB7170E757CFE3BD3CBFB21288
-:10D3A0006E170AA00F4A789CE2E4CEAF9EFD77B0DC
-:10D3B00023A1311DBFE4595A1FECE7E604B4F7BBC3
-:10D3C00077248E863840C96B0FDE08FAA204741FDA
-:10D3D000D8992F0F08D5D2FE4EF467E513DB06E38C
-:10D3E000B980F21D2ECC273CB8735715E8FB732F7C
-:10D3F0002710D0F767E5CEBF4139B0279134A9682F
-:10D40000F7A9FA7575119154BD3D570E65437E0B12
-:10D41000C1FC168CBF517E2E6F4DC4F31FBA7A5CCF
-:10D420009E8383F83D518340EEA8DDA81AF39ED970
-:10D43000F705094C7F05AC3DF7B3FB1058FD80D2D2
-:10D4400053CCCAF58398DC7660FDC51ABFF2EF7D38
-:10D45000FB65F503092C1E10ED87B5AFB2B2FB35A5
-:10D46000CCF4FD6982C0CFE3FEF5CA58F74FC48003
-:10D470009FDDCB259020DCBF4AB6DB314FAB428924
-:10D480008C847CF55714B6FF51E18E8C847CF53D7D
-:10D490005CFF55386899BE1FC4E180FA5026B6CEAD
-:10D4A00097F05EA75D76BC0FAFF235970FFD8457FE
-:10D4B000BE3AF1741EE4AB25609E74E56BFF0BE988
-:10D4C0005F698DDC05FCDFB3DD8AF793766D3F9CE9
-:10D4D000017643971CC948BEC8BE4E65D86AD8A716
-:10D4E000D6E671BA66E90438C7AB9D332C8BA32FFF
-:10D4F000DE4860791D4D09BE5F313D67BC5FE67453
-:10D50000CD6CC3BD8965B6D87AAC19F4822E8E274E
-:10D5100046CF153643BF674967DD204A924AA107C7
-:10D52000F7C7CBB664A683BF7BC07E25EE5B1D909C
-:10D5300055F407E1A9D7C7A76ABCB9129EA7CFCAFD
-:10D5400095281CDD4D9F160F22901F689F1D4B3F95
-:10D55000ED4D48407E2AB359639EDFFC1DE7B76D51
-:10D56000206F63D978DEECE8B807E49002704C7461
-:10D57000AA389F32EA07B07BA2E6E4EACF6D2F9289
-:10D58000EAB11E952FC4C722B25EC973F6D52B8BA4
-:10D5900096E6E54AB9A8B0BEE9E537314A27124C0C
-:10D5A000413B49E23424EB071AF2FD25B9D006F8D5
-:10D5B0005248A1471281D4F528A70E12C6A7939A04
-:10D5C000216C1DAA26101F3FC5F767AD92FA18DE21
-:10D5D00037D32EA23EBF14DEDE4B7023DC56A99A51
-:10D5E00078D1DE98E9017B4C08FAC9B7941F6A6BC1
-:10D5F000A6E7B273E1C407796E6EC2E0737B0E7D5D
-:10D600000DF601E533768FD5F749A8968E07C78CBE
-:10D6100031FE3799DD676F1EEF2F9C0E24B8DF7047
-:10D62000DF39FCF568F7E781BF9EF8B771B01FE3FB
-:10D63000F49008D84B094E1249180DF7E449A7F5A4
-:10D64000F2EB26AC3C94B233E835CF44E377335F5A
-:10D6500013AFF479AF5E14B1FDE7A6F69F5FACBDE2
-:10D66000868F806DA3F7786E142F0E3E87E064EFEF
-:10D67000854EC0C768B7B716E8A8F47CF820E06309
-:10D68000B493F983290D44EFAFE53A99BE5AC1EF3F
-:10D690009FA67F854E5D7FC463C3F8E82A8EF7DEC0
-:10D6A000FA5ADCA44F7DBB0478ED53DF1EAFBE23D6
-:10D6B000767D573C781262C39314A7FF60ECFA554D
-:10D6C000AFBDF7664485974C6F40709E9F5BCE75EB
-:10D6D000827F95F8616A11E30AB61F60A29B03F886
-:10D6E0008FF28363B8EE3DFC5FB68E7E4363D09FBE
-:10D6F0004490EF8A383CB4EC1C48E1FB310777CA10
-:10D7000026B65F39F75E1627FAB18DE5971EE3F767
-:10D7100001CD6D607EF5DCA56C1F9194B2733E1E49
-:10D72000FA1F8C77277442E97D67BD108A64C2BDF9
-:10D730003526FBB5F77E9C450AD42F32C55D347E75
-:10D74000D2CE23CDE7F67526E7CF85A4C705726F45
-:10D750003EF7FE3AD76B9ADE0FAE2359706E5FB478
-:10D7600038BCB03F2AF273A6C4CDEEF323BEC1ECA1
-:10D770007E392D8F2B4B4D84F58D84F97BBECFB236
-:10D78000E47A7580FE9C9674C181F783D4CADE3436
-:10D79000D083F2056AD751574DB93094A8BA736453
-:10D7A000D49E43E1963DECBE44C953484AC00EE4C2
-:10D7B000F703909419BD76D75B140F4BD6A9786EFA
-:10D7C00075A193D999BF7015DEE31C0BF6E5382FD0
-:10D7D000BBE7D648C7E04E36BF5A985F665FB86B66
-:10D7E00015AF17EDCE19D462C0388E177FDF41B464
-:10D7F000AAEFA9208FFF2CB3DF2BE8830746BFF3E6
-:10D8000029C9782FFB02F7EA0F814FD7F0FB0857A1
-:10D81000D664E173754D1ADA9D75355E7C6A78B110
-:10D8200079EBF1DE37DB70D69FCDE3677605B56522
-:10D83000209F42F25447A06C4BAF2660EFDA7BF199
-:10D84000538FF8517ACB7E2C5B3DEC7723E486999D
-:10D850008867DA9E94D0EF4B5CFEA7404EECEAD589
-:10D86000867BE4AC69634CF70D9AF0A6F1C7368667
-:10D87000BFB502E30F33FED6CA1D2AEC2BAFBDBEE7
-:10D88000F7DE19C41F35EF19FE7EC7F6D9E2E2CFE5
-:10D89000938CF6EB82FCBABB204FFA11BEBFF87036
-:10D8A000CD38C4D72A7E8FE443353E7C8A803F3A08
-:10D8B0003F6B7690C0FDE8ECB721E8D359E883FBD5
-:10D8C000678177017FA293E1D39A568DFB6B362750
-:10D8D000C397E80C225E6427C397E864FCA6F0B205
-:10D8E00004F8CBC5F6F89EE2EF00F0972D7D82019B
-:10D8F0005F4ACAE4CBC3DF93147F148E142E5F6695
-:10D900003CA428EC7E4A4DAEE2D9714FD0F9C3BA9F
-:10D91000BDA186E0B37F1C7F71A88BAD9B2996EAE1
-:10D92000FD32E02399F0F52448D2F3094B3D84BF42
-:10D93000B42051A12C303848FD60C3BD92A24732BB
-:10D94000DDCBA66E003E587F58B640BEBCB874868C
-:10D95000E13CA838DB97A4223EFD784FF323352A1B
-:10D96000D26F1DD011EE01E5FED7439C9E0FF37BD5
-:10D97000285771F958CBE5E5312E27B5FCDEE435A3
-:10D98000D3599E554A8E85DF571621FA3CA6246F3F
-:10D990009828142EB4A9557CE23D8BE47D6B680475
-:10D9A0006D97904D7CC02749EF3F1062F735160EFA
-:10D9B000043B2849BB7F71A29A34070FC24624E674
-:10D9C000775055887E4C8725D63D55B5DE03368881
-:10D9D00087C68327C1EBCB7C888E97D0E042FBBD06
-:10D9E0009FBF70CE425A76362460FC2F81FF3E8B5B
-:10D9F00093C25DA2A377BC7BA837BAAE4F74517AAD
-:10DA00007A0046FA7CBC6118FE2ECB137221FE8E82
-:10DA1000CB137C3DD5EE39D7DA7DC3F5A33BEF6A56
-:10DA200083DFBA5EF6613BCF44A3FCAFE7FA3679F9
-:10DA30008A91CF357D7BBC57DFFA87023CA917A6B8
-:10DA4000A01E4BB939B6DEAD9515BCB7BC761493A4
-:10DA5000F36091C2CEB5F4D50318A73EEF1FB911FC
-:10DA6000F4A8C657CB09D33B41E2F0E23AC4EFB782
-:10DA7000D1ECE095700F20D7AFF01487B3DF1F48CB
-:10DA80009DCBEEF35DC3EFB17A94F215C17B4FBD30
-:10DA9000F89CE162FB13CB6D63F03EB55AA705F528
-:10DAA00084F48135042687B47FBC07E20592ECED4F
-:10DAB000F041BCCF2585E1DEDC5A671EDEFB2E245B
-:10DAC000E57980FE5FBA160CB9583E1D9D28DE9799
-:10DAD000E94929241F65E36E009E5F913D37138855
-:10DAE0001B6E48A9B603DEC6BB585CBFA1281FF158
-:10DAF00048F17B93AB7FB49F01B367F4DE8305DD10
-:10DB00006E88730EE60E17B397487A900CD7C979D2
-:10DB100083F63B276A9064E9E47DF9886904F68717
-:10DB2000FACA791C3DB699E9B115426C3DA6D9995E
-:10DB30009A1E934DFA417BD60D996E38A7A5A4780D
-:10DB40008177E119B478C1BE7BA5EE8E24C443353C
-:10DB5000E081A4CDE8F55F7F3014ECC7FC98FC664B
-:10DB6000D65F0B7AD7735F2AD0E994AC0E9803FC8A
-:10DB70007438F67A3EE9F1AB1E033E58F03B51D0C3
-:10DB8000EFA7945C5889EB69F18571F82C6D988E3C
-:10DB90007C4F200AAEF3C34E36DEE706B84E36F0B1
-:10DBA0003C80463904F919271BEEC3FB4A20CF5BA2
-:10DBB000D4EDEF933C15ED4BED9EB193A17BDCFAD8
-:10DBC000FDDDE25FD87D60B7C6E3AFE2C6D87E3D3B
-:10DBD0009E35828D3CE2CD027B98DA373D11B07FD5
-:10DBE000365ABD41122D071FB7C7CC4F5CE29AFAD7
-:10DBF00004E07D89CBF70CC83971B27B41E3F3397E
-:10DC00001BF7046C02C37ED3533C4F53F2BBF5F7B2
-:10DC1000BBF5DEC7C9E324C416E7BB43FB7D8338ED
-:10DC2000DFDD2C9F8378627FD7FC8484A89FD00A95
-:10DC3000F3A86C3853F701E289FB091CEE533283D9
-:10DC4000FBD4F356F63B3726BE38C5F34716090C0E
-:10DC5000AF1A7F9FEAB577FC780F8D99FF848D57B7
-:10DC60006D184FFBFDAC5DC6385C05E51FE01B6120
-:10DC7000E378CC5F171E1FFF18E4257D7E44C4EFB8
-:10DC800065176CF8BDEB67DE0D7321CEF3868CF75C
-:10DC9000757FDE3E3591C5798C71E8856EB6CE9F75
-:10DCA000E6725F7C6135F2672F7FD42F5440AE8AD5
-:10DCB0002F3C8AF64CF11601EF8924C19E43932430
-:10DCC000CE8713A0FDD969CB01DF13EB717FA3646D
-:10DCD000B3D5BB5AE84BE7D32ED570AF7A49E71AD4
-:10DCE000EC97507B2A45B7DF7D8AE701975C60F7A8
-:10DCF00003124F90A401DF73BD13E55FE3BDAF5D79
-:10DD0000F6D871F66FB83D537C6182C16F88CEEF53
-:10DD1000FB4C3EF97A5ED2398EC1D53B9F0DE36351
-:10DD2000CD273A8F89D8BE2B29F6F8991CCF276AC0
-:10DD30004AE1E406295558BDE2FAFB14D027C58D07
-:10DD400049C9826E5E250DE5863C8C92C622659E91
-:10DD5000AEDF281D1CBF9D343C4A87CC47E5EB96BF
-:10DD60003B61BD2F74B961BC8D8BF27FA2427F4CA9
-:10DD7000FF7C22D76754A37EB9C71DEB5C43A65B2B
-:10DD800035C4954A1A387DA89D9CA7A38F46177362
-:10DD9000FB134D25F93F8178F293EC5690F87AC742
-:10DDA00044B7CCD8789BD08BB72CCC07BA34DEBE26
-:10DDB00063C8FBE983374E5F0D2FDA7B6A1FE502EC
-:10DDC000BE2640C0A93FF4C3E87F297C45C7E5F4DF
-:10DDD0009F147B1EFEDE792C25416A3F2CB8E43C63
-:10DDE0001E2441DB45E6A1D19F5C6DA0BFFFD11190
-:10DDF000D7811C6AF45E70E049E4DF05541E615F60
-:10DE0000FE64FD7D86F5210A5F1CBA0F0F92ECFCC3
-:10DE1000FF7374FF440E6640DE57701D5B474E6D06
-:10DE20007C24438FE725AE490B812E6453FFCB5AE8
-:10DE30003F8293BDED2AAE4B32C6C376BBFC0137A1
-:10DE40007D5FCAFDEA1549D346C65AF7A95F381166
-:10DE5000E2CFB535D32742BC4DE67623FCB216D8C7
-:10DE60009B70057AACFBB5EA395D1FAAA9C6F835E7
-:10DE7000B10589477FDE9730BBE81BC2E22D5A3BD4
-:10DE800045F67B20FEA908A410ED39C9BF32330F37
-:10DE9000E2182939411DFE1E7533BB6E4DDA010FA4
-:10DEA000E4935A69FF108FB1A54BE78DFB94AC9CAE
-:10DEB000238C97613E724A98603C339BBED7E15BEE
-:10DEC00049A1705EC4DF946C6EDC2F9208B3D3B4AA
-:10DED000F9D337B89E3DCCD7A5E510C74D013BCC53
-:10DEE00082FED07A1EA7FC654D21C78384EB98354E
-:10DEF00089D5571219DC76885B8BB0AE46B0EC82C0
-:10DF00001B7644BC9A0C7F7F3489A8F83B7DFD4882
-:10DF1000A40EEF3199D4793FBCF725F8B7001F7CE8
-:10DF200039B0E34301E2D085FE2B61FD6D108339EA
-:10DF30002AADFF2BB12707EAC1EF7BBD9FCC9E43E3
-:10DF4000206FD9AFDB9762F772AAFAB89EB93C642A
-:10DF5000A964DAAFF9CB95FAEF4D09BE5D0047CA67
-:10DF6000C702EEC3D4DAD9BD3EB5AEDB1261FD3EC9
-:10DF7000CAE985F407FE696776CC79494D4CC6F845
-:10DF80006656EEEB86F1BD86B2C4FDB74D941F25F3
-:10DF9000DDBDACC3259F05F865443D7DAFA75F8C13
-:10DFA000B85AB213AFBF8DB90FA3C147C725803F81
-:10DFB000F1C234B6BE9AF8608FC0E00FBAB8BF4560
-:10DFC0008222D0738E765FB0B48295B5DF8B002A43
-:10DFD00052383ED0F617C80A56E6FB9481796C1F7A
-:10DFE000D20CCF9CB6873B20AE3FA76DE07CD89F7C
-:10DFF0009AE31CF96778EE917B0E24801D789F8050
-:10E00000E73F7EFCFBD7E504FADCF9CE463C6F7CAB
-:10E0100096CBDD5DA407EF61F7130FDF270FE1FB60
-:10E0200079F00373580ECBE0A7CF8D847E74032D57
-:10E03000DDF97AE80630DBEE6AEFF90DA8017FD84A
-:10E04000330DF700B476ADDE43ACCCDA45F160E3D6
-:10E05000F6A80DE7159DB70DF1F0416FDE7810E9D8
-:10E06000D18B277EAF928697DE7927DE3603E2BC1E
-:10E07000F1F4D91C67D69FD9E60783CB8CA7CFE1F3
-:10E0800013B5233F77FBEC8954BF7DECF639E0599B
-:10E0900061EBC99086A2BCB8A15C25FA87A4523C6A
-:10E0A0009C1DECBFB23FE0A3A3DF65E9D10FED4CAF
-:10E0B0000F90BC0C9C8F76EFFBC1074EBAC0EEAC44
-:10E0C000DBF95E063C2BC5CEB5B7637C53447FE8D5
-:10E0D0007CCB95173D1FF621C49DE8FA372251E30A
-:10E0E0004336BFBBF9F99ABB5B12F07CCDDD4B45E3
-:10E0F000C3BDCD772F65797744EA187DABC15E5FEC
-:10E1000011B71F880398FB99BF7432F9B81FECB39D
-:10E110007A26615CE059C65FF3A7F844C8479EB011
-:10E1200052C078CBF8E36A6B272DCF0F25E1EF1DA6
-:10E13000CD7F60492EDC4350D5C1E27B03C4C53995
-:10E140003F83F8C901B68E437931C8B7D3A73A7572
-:10E15000F1FE2EB93A07EEDD0BDEE9F401FF14DD26
-:10E16000EAFB007F2F91C721B47575574311E6B1C3
-:10E1700016CD55C701DD8BC276FCFDC1221B911C5B
-:10E18000548F1549C406CF010A91ECF074101B3C62
-:10E19000F397B37BB28B1B66A17DE01E57A8C0FD31
-:10E1A000B7456D2F7C01ED4BA4C87E76AE85E1A707
-:10E1B000A8EDF0D7C03F0B7D859877F89D2D8AC1DB
-:10E1C000FF1B153696AF6935967322C6726EBBB1CA
-:10E1D000BC15EE38D3D91107F65A719D283FC3CE2E
-:10E1E000E9BD2AC0DA04F1602BCA5341795B3EECE9
-:10E1F000479F79C96581EF7BFECAFCDE9EAD76BC88
-:10E20000EF6DFF1F1CC40179852FDB37C2F7338EFA
-:10E21000703EC4E1687DF63B5B85E191E0BFBD7275
-:10E22000B5E6A78746C3BC5EF91BCB93E9D96AC59F
-:10E23000DF4F39B3FB8597605FECCCD62BD0CE7A1D
-:10E2400055085AA0DFE02A467F339F966F31FAC502
-:10E25000F727327DD32D307C5FD9609CF755216341
-:10E26000F9E789CC9F9A4774EF3361FF5EAD4B832A
-:10E2700075F5B9D8F70D3FC4E5E2C517158D6F45A3
-:10E280007E3F1B5175E797F644F7EFEEBD02F22A89
-:10E29000001743A3EFCB4DE36AFD1726B27DF814B8
-:10E2A000BE3FD3F38688F8396DFADDC25EBBAEA6F9
-:10E2B0007AE014DD3A54DCB03FB508FCA3C6FDA9F2
-:10E2C000F374EB4BC5D683A977605E9284BFCB54C1
-:10E2D00031E7F94727A4C07B310CF0C277887B7502
-:10E2E000857FE3867AD4DE1D23EAF05ED270DFC03C
-:10E2F000293A39FD8FF2A5264F15DC3ED935AE639C
-:10E300001AE4899737B0DF6F2A0FFFE816F8FD454A
-:10E31000D2C8CE99E64BA450A4F253B1FD473F8436
-:10E32000DFE30A3C33D60BF0D02E6E85F7E5CD9FA8
-:10E33000E27982D5A6DF11D09EFB387D69FD888504
-:10E34000D65F7D9BB314F413EDF775281FC8DA88E8
-:10E35000F79BB84FB1382D7DFF3EFC24CAA9C9C137
-:10E3600037EFA04DCF90F0BB3764C2BC8D7C46F92F
-:10E370005600BBAB67B380BF6B4B2DADFC9BC1A4FC
-:10E38000F62DC3BC5BFAFDEE58E79D17858CFD9812
-:10E39000E9FF07CEBFF42F4BCF47E67AFD6606F1C3
-:10E3A0005C62C552AAEF74767EC5F17ABCCFD13CCF
-:10E3B0000E06E174F906B05EAA28DF76EDFE21C1F3
-:10E3C00096CFF36687B132DE5B08FC4A19A5FC6A7A
-:10E3D0003245057CDF4CA6C3F35521F2A828323D17
-:10E3E0008171A06D09A827BA3C9DCF3F0DFCD53C9B
-:10E3F0000AE34F83F879CF2E3582F73C76F3F86441
-:10E40000978795CBDAEC980773E6AC827A7459F863
-:10E41000A01BE8D1F592DD02BF4B7A667BBFC990A5
-:10E4200027D91566F7FF9E0EF7C3DF7F8DB76E996C
-:10E43000F581B64E1E837FC27A9AE8FB06D65BB2A0
-:10E4400082E5910EE8579D13EBF724B476294A75BF
-:10E450000EF829FF1B63EBB5D4008000000000001C
-:10E460001F8B080000000000000BDD7D0B7854D5E9
-:10E47000B5F03E73CEBC92996466324926218F096D
-:10E48000841020E024860814EB24040C187542D173
-:10E49000A2B638804080BC44DB46A55F26244242B9
-:10E4A00051428D08087140B1F48A6DB0A8C106EFE1
-:10E4B00080F86AB537DADE5EB5FDB92370295A1ED9
-:10E4C00023F452DBDBD67FADB5F799993349AABD6A
-:10E4D000F7B6FFF7FDE9478FFBECC7597BADB5D722
-:10E4E0005A7BADB5F744BE6EF1EC2D60F0172850A5
-:10E4F0009C8C5DF2BB3C9BA0BC4482573318333AE2
-:10E500007C465B3A63D672C6BCF0CFF186BC5786B8
-:10E51000FA53B2E79BB6718CDDC57C0686CF72BF1D
-:10E52000818D853E9DD0388BB1650A0B290E782EE2
-:10E53000F4BE2F4DA53263D07FD92E29D801FDEF2F
-:10E54000DA6C64CCC4E8EF33F8B7A217CAC5B1F2ED
-:10E550002A16343019FE63575C3B187F95123A2A0D
-:10E56000A530B6DAC442C930EEEAA7B4FDD6B01081
-:10E57000C1D370E03363FCF8303FC600B4FF64EAF7
-:10E58000BCBC6EDB34C69C0628C3BC236FEB8388FF
-:10E5900087FF907D34AF35CC4FE3DCDE5AC54EA506
-:10E5A00031D67C5F6BD65DF0BCD87A7FD65D5743A1
-:10E5B0003DC201DFB730DE9FC1BCF601CED654B3F9
-:10E5C000502EC0B71CE69B5406E541293405CB26E6
-:10E5D000164829E3EF53CBF87CBD71F0D5B31EFA92
-:10E5E0005EFD2EED7BF68B34C267031BA27AF654D8
-:10E5F0005C3DE0A341E0A1E100BC8FC3C3CC03526A
-:10E60000C07A1596821D19005FD359C63641A9E913
-:10E61000D06746CDF8AC8731C04366126366A0D799
-:10E62000A3125BD45F42FD26D64D8136F8771D9646
-:10E63000DBA9DD0981BF476F5991E587765BEC5017
-:10E64000CE16089E0EDFD0E1C7A91C32C17792AE6C
-:10E650008E96A9BE623D2FD7D98A6BB6E730B64DEC
-:10E66000EFCFB2011297C9BED77480BF271DFE5BE2
-:10E6700090DF96E9BC790ACE97798B7C00076BE531
-:10E680007878ACAC65624B490CAE187C9CBEDBA4C0
-:10E69000FE900EF82C7058F2EC7323DF46F47E4B9C
-:10E6A000AC5DB34DA279A41E0BBF3606E9FEBCC417
-:10E6B000F642BB1DD287AF8D817E3BE6B9590794E8
-:10E6C0005D4027B90CDFB34E09F0527EA8EEEE573D
-:10E6D00091CEE5499EF1F0683C5429375A68FE779F
-:10E6E000FA009ECCE4963D3AA8CFBCB3B80CF91B17
-:10E6F000E67DE702787FAFCD4DDFCBB270BABBD6F7
-:10E70000070AD696E0F77D77BF0ADF8B4C49F2E027
-:10E71000F733015756073DBBCCD88EB54BD8EED159
-:10E72000143E7EBA4EBEB30ECB65BCEC582779F7CB
-:10E7300012F36DA579671A590DC289EF8325B46468
-:10E74000BC07A93EC8E93BBBA514C7CB1CC79F4E5D
-:10E75000432807C7794BA5F760968E6520BCF0DF8C
-:10E7600000CFBD072B331DD0FFAD732645970A4F51
-:10E77000176343D84E0959183E0B8B797B93685F1A
-:10E780003A3B131783334FDBEEA2DE9B7A35E0254D
-:10E79000F08ECC901EBFB37853EDD0EE4B063E8F7B
-:10E7A000443AF6217D603ECD9F02E46971745B744A
-:10E7B000C580E3357FAAB0E0D5B1F7E7DA4C2C5835
-:10E7C000142B37D41F9B8BED1AD9D006E4ABC6FEB1
-:10E7D00064168CE3F72F258DFC5D95BF9B3FD5B16B
-:10E7E000401AB16F8ECF8AF8896C588EF01F91D87D
-:10E7F0003E86F5061688FB7EF3A70E6D390A67067E
-:10E800008D136BC7B4ED067E4FEDD8F4700A7EE72A
-:10E81000822D9CE210F3C37ED9326B41BA5C0CEAC4
-:10E82000027A58C717DCBCFE226335FD96587B750B
-:10E83000BC0B8B0C2C44788FD0B8889700C8B69D41
-:10E84000839F18DC506E183C4A7851F9211E3F8195
-:10E8500038B991D13114D2C19AFE856D55578919B5
-:10E8600048714C5DBF6BBABCB3A05ED669D67372FB
-:10E8700079747D93587954270B79D0D0553D2BBEB0
-:10E88000CCDBC7FA37D654C3FA2F2FE1FD4FD89A05
-:10E89000DE58AFC4E411CC230FF1122D9B12CA161F
-:10E8A000284F892BDB12EA9D09F5AE84720E6F7F2B
-:10E8B000CE1ACA933D8C7D645B5BA3807C3997152F
-:10E8C0005A2C417973C7BD35D520E71ACB87BC32A6
-:10E8D000CACF41C923B118FE9A3CCC1B04FC593C59
-:10E8E00061C3B212C4C3D06BB8FE1B06249B047C68
-:10E8F0006EE93F18A232F673C7F5EB97A85F43FFA6
-:10E9000087D46FD4F18B75B48E37159FA4768000B1
-:10E91000DB69A0D35799C45201A5058AFF8FA8BF10
-:10E920001AFB7FC3F52E8B18F8FCB81CBC90E57D54
-:10E9300085E4E011C986EB2ECA7738AE25C6EF6AAA
-:10E94000FB5F4D19FC571C26F9DE4FDA1568FF7F77
-:10E950001A7F338D01A97E854D66A05C0D4E447DE6
-:10E96000BC93F927A21EFA7AE3F8A33A6877421F0C
-:10E97000DECD005FC5F64D350AB43B610DE74A2098
-:10E9800043266DEDE5E5F4F06EC46760EBA384DF2C
-:10E9900013B9E15C1D94A7DA43BC3C3EBC1BCBB76A
-:10E9A0006E7D8697A7847365E83F3670A0A61ACA65
-:10E9B000FB6C23AFD77C3B97E32A7C97C779B3EDF9
-:10E9C000E9C8765C4FECD603C6401E2E5EFDF1B35F
-:10E9D000FB000F8BEF4F2639B5EFDC57E6FB68FEE7
-:10E9E000019F5201F290B33ED763248F15B203B258
-:10E9F00050773962F4B0E60DB949CE4F6A3988FADA
-:10EA00003E737109C9F94F53BDEDF669B1E7271996
-:10EA1000F00438DAED362E97659D97DA3F6025BB16
-:10EA2000678B99CF07D60DD1D722E8512EE6536ECA
-:10EA3000D7D133CF3687C6FB40F2EE30C9F8640138
-:10EA400033D2735512D91977EC01B90072B957C096
-:10EA5000DDBB75623000E3DF21311FCA8D5EBB373D
-:10EA60000BE5C30B7F91EFC4F9F69642199E3F1652
-:10EA7000F2BEB7CE9B658FD38BBD7B78BD2A777AEC
-:10EA80000B787F55DF6476F0EF646E99B817E791E5
-:10EA9000AC302F96972F2ADADB4E7A7B01CD9B790B
-:10EAA000BD5912CCF7F4AAB13AB42355FAA4157A99
-:10EAB0006FC2F9DC8EE35B627452BFDF8EF346BD3A
-:10EAC0002F83DE87F93EE0F0D3FCC10E984A76A092
-:10EAD000B003DA71BED362F8654A781ABEFFFF0848
-:10EAE0004FF760FDFF144F23C88B00B66B6C0579A0
-:10EAF000A18B9317027FDBA4903E93CB0B0FEA39D7
-:10EB00007CBF00E4E3ED36FF468447FDFEE2071AD2
-:10EB1000C9EE53E14AFED68B355F65C3D759A25D76
-:10EB200076E203D366067AEC84A19FE4E289F9CC0D
-:10EB3000D38EF243C7EA118FAA5D5971FF9AB718B5
-:10EB4000D8B397ED32D1B95BF266E1BCBA81AE269B
-:10EB5000D4C37586E0BE82985EECB50777AC40BA48
-:10EB6000DE52E209B8493FD27A0BB42653BB5E7B32
-:10EB70009829583FC36D034890CE448FC86D86E0F6
-:10EB80005E09E9CDF9A577D5A4604022BA07A8FFB0
-:10EB90006D9C7F7AEB18D9F7BDB7B9886FCC2C681C
-:10EBA000467846E3838C0E467CC414EFD43A6B0C53
-:10EBB0000F3F13EB3AB93CFCFCBFA11DB9D94C7611
-:10EBC00024EA4CDC77B19E4C8217E8F902F187BA4F
-:10EBD0005F7A242BB889F6679E0AA4C746AB7709EB
-:10EBE000C1FFED6437C2BFCBCCBA4C65B8FD609DA8
-:10EBF00024EF043CACE73186F6D99DC23EFBF7FA20
-:10EC00004B56B4035EB573FB0A19C504F26F29E3D2
-:10EC1000F54BD7257F88FB99A5EBE49011F62BAC3B
-:10EC20006B8E371CB7CF208E82F1FC425EB2ED11A5
-:10EC30002BF28D1FFBA5E0F87FB4BA2D5886FE534A
-:10EC400091ECD0BF38D6FF3DB16E17CB1C7ED69667
-:10EC5000EC46FC26CAF5F754F87A1EF3C67F4FFD42
-:10EC60004EE2B8B08F7B1FF105780FA5A23DFF6D76
-:10EC700099E89A08AFD31079C80CF58BDB64FB7A5E
-:10EC8000C0A7BFD54AF355E1BD3333722DEDAF12A6
-:10EC9000C63F93DC54A1E0FCC5FE83ADD3EEBF18A4
-:10ECA00033C4CAC017CB5984F631C3DE8B7D6BE207
-:10ECB000BE8FB1BF18E3DBA9EB85B9A504F8055FEA
-:10ECC000B92505E9E69738DDA2F44E805BC5A7ECCF
-:10ECD00018199F4E433817E595BFD5487848ECAFD3
-:10ECE000EABDC7CCB03E80AFB64B12F1E3F6FB9263
-:10ECF000498F3113A763F3EA2437F2E74E43E469FF
-:10ED00005A372F1919D2F5A239F202C9A342EE37A8
-:10ED1000B8F833790FB6BB90CEF9FAC2613DAD2792
-:10ED20000E0CD83B3F93F752BDC4C7BDD09EECC676
-:10ED3000F5D88C9884EF3707FEAB8D01FE4EE9F8CD
-:10ED40003EB87940BBDFBD00FFEACB6272E122E34F
-:10ED5000DF090C703900335D45DFB923896D82719D
-:10ED60009B749217EDA3A6D593821D9C5F4CB85E51
-:10ED70001A04484D3AD8F795C5D67793EE6411EE4C
-:10ED80009B1A4C9B87E414AA3F8EFB2D86FB25E83B
-:10ED9000B71A3B150CE7E7A6CDBFFD33C2DD7448BB
-:10EDA0004BF786187F489F49D83F8E5F0A627C40A8
-:10EDB000F635CA876A161C2F713F0C96936B8682B4
-:10EDC000E8876916FE89F463E1B9C81FD6F27EB6FA
-:10EDD000149ECD67B97D317370CF2BB8CFB5D70CEA
-:10EDE000E5E2349B5BD75E7DFAEA187D5538670C07
-:10EDF0006E9571FFA6DA2571FBC7890BA6C43FD7B4
-:10EE0000533FDC8FE2F7C2F80AD785C2F5D936A1A5
-:10EE1000CF40EF91DC5DDE3381F41EEA25945FEA9A
-:10EE20007E16E519CA8F271D558B1C30CF92B4AAC8
-:10EE3000AF38A6F1EF901D8F9BA019C3F199A85789
-:10EE4000D476B8AF6DB18CDE2EEAE7D991CAE583EE
-:10EE5000225179C54FF57B36117C0AF1CBDADD05FD
-:10EE6000246F557F4C83F043AD10FE9B15C27FB3DA
-:10EE700072BB91B9E3FD55416DB941ACF74616E659
-:10EE80007EACFD501FEFB7A966212BD6A3FF069FCE
-:10EE9000FDDAFECD2C385B41FA0E7C668C7FCF7A92
-:10EEA000F97CEF1474DF61E67E9B99EBF6C8DC1900
-:10EEB000C5E79B5AE62D7810F5C49B7AF22FFC87A4
-:10EEC000A0938A17A3A3EAEB88EF24DC8F61BB072A
-:10EED0008D8497D3A08F0F0ABFC602DC67B6F9B343
-:10EEE0000A0B113DB6BC05D6E1F8DDF492B91EF966
-:10EEF00065B343A7E1A72A879ECAE4EF41BCB727C1
-:10EF0000935D0D689E8A7C543156D5936C2AFA998C
-:10EF10003ED483BD05E5A65B2D7E1C2F8C76019427
-:10EF20007708F9B5C361A0F1D472741F27F805BE44
-:10EF300043E3A1DFC517C707C168FBADC25EE4723A
-:10EF400061DBAA24924731BED531E2DB129F01FD7D
-:10EF5000452F0939F2122094F651FD662E47142EE2
-:10EF60009F5E3A3B89E4DE1B1FAF26B972695112DE
-:10EF7000334AD4DE2B61FDF3C6E07A28DF25FCA8F6
-:10EF80002F49DC0E0C1CB1D2380D06FF0EF42B34C9
-:10EF90003C37DE0314632F1882DF7F1AEB5F369352
-:10EFA000DFAA2185C3D9F0D21892933FD6079FF9E3
-:10EFB00001F9218C649F3524B953A9FE27690CEB14
-:10EFC000BB92FD8348CF6C23B71B1B0CA1223BE0F7
-:10EFD000F16490DBBF2751D0E0F88356B26B00CCD0
-:10EFE0002CFCFEA9EE4CCF26770C2FA71E9A4CFCCA
-:10EFF000BF4DCFE91638CCFD9A27F5BEB959503E22
-:10F00000F97CA907768EECA2CF1032008CCD5BB8CC
-:10F01000BDB64CE7EE6B45D9F472B247B3DF7C78EE
-:10F02000652DD637AF5E7713CAC1D1D633CAF37810
-:10F030007FED0516C9A3FD66FDD8FE107CF7C2E082
-:10F04000440FA947E60262039FD878DBD37AC03722
-:10F05000F2D7113DF1EF171D1FE78BFB3FD42FF8BF
-:10F060009D6690BF513F32C9DFB8B23C5299D3B3CD
-:10F07000F9A54C619F69EBEF48F55F40B9D6F4DD27
-:10F08000DF9F6825FC4648FEB11EEE1F3FADF72E00
-:10F09000463EB557870C4BE3F6B78634BE8E9619BD
-:10F0A000855E672143FCBA53EB2BAAB47CAE3EF5D8
-:10F0B000697C1F691DE2727C78BD4EAC9BAF185114
-:10F0C0006F71D70DECA7CF727F8621CD4DF533CF71
-:10F0D000860CCBA09CBF2E6458219EB82E00DF2149
-:10F0E00013CCFBF40E2B5FCF80061C67C57446F66D
-:10F0F000C80A19ECD0327CEF1E08035DCE3C6FE7E6
-:10F10000FCF527C00AE07B0913ED8C60B782DC7A3E
-:10F11000B1530AA15DBF64BB71AFB900D7B157B697
-:10F12000223D774B24B796745616ED80F2EA43538E
-:10F1300088FE29D3395FAE0EDA49FFCD147270997B
-:10F140003168203BFA19EEA783F1C91E6E804E5933
-:10F1500065C3F180F25BC30F416D9C6166BF90A7F0
-:10F16000FBE3E20B63E3E47A7F427FB0E3B4FC119C
-:10F1700050F50E9773CC9D89724E95C34687AF3478
-:10F180008DE4526126D217E8C9E5E44189F0DAC876
-:10F190005AB8DE10F23EFA5DA12FCEC801AE978CB0
-:10F1A0005BE93937AD80E8B61AF50DF9CDF9FE6E99
-:10F1B000343E989BA6137271643EB85EF041C35909
-:10F1C00016BA16BED7B08E851AA7F2A7752AE941DE
-:10F1D000AE0F4D229E61E2F18ECFD38B897A70986B
-:10F1E000DE4BD0779906A1DF049DE3FDD9A8EF6738
-:10F1F000AE0BCAE8D7CCB379AFCD4C8FD92FCDEFBA
-:10F20000994CEEABB0EC63632DE89FA97CC685FEFC
-:10F210005DD88FE3BA4A06BCEC81F7BB55FBD6C577
-:10F22000E7EB3270FED52B3E566A41BA0CD17E35E3
-:10F2300092CE6CC88F2A3E775BA15F19F6E3EB2D67
-:10F24000DADFC43A93E2FA57BD6426B97AE5B035FD
-:10F250006824BBC39F6F87F1327E65243BF4C24BA9
-:10F2600056D29F1784FE73AAFB7EB681E8D38A74B8
-:10F270004D476EAA1A83FE5326CD1F832250B5C375
-:10F280001AEDA3F9B3457DC1D0AD9CAF8CB45FBC82
-:10F29000620F7F13CB000F43FBBA05E98CFEF643E8
-:10F2A000B34B1F80F7CD3E8B8763DF5F8AFC6A9488
-:10F2B000EFBD15FD2A73E57591FB601E8DB9169B98
-:10F2C00011BA54E7FFFA97B741F9A3437A66443A73
-:10F2D000EF9BBD888D1D5DFEAE0AEA4F86E3D6CB5F
-:10F2E0009AFDDA7263BFB6DCCC9493E13879FC58AE
-:10F2F0009AD5796632C90ECF67C0DF4663CBD93D58
-:10F3000000AFF1C746D2470D69FE5D69E837D545C4
-:10F310005E433C1BF3CF4D453F4555FE9F28AE73E2
-:10F32000E5DBCC83705F315792FEBEB2C3EC0EC4F6
-:10F33000C9AF66C1FFBD79B554DFBBD3E896787D10
-:10F34000EDB40AB407E9DBF867D201FE9BB7CFFB47
-:10F3500088F64D68B543B917ED4BECF79C146C4734
-:10F36000FB713BD77BE7C17E34A1FE14EBA9591E8C
-:10F370009C6B82FFEC75D44C44F9A2FC59F121FD41
-:10F3800037E25071F6EEE1E8FAE47E9C1BD08F3351
-:10F390008EFC3887516E349AC2864A18E7BA3FFF0E
-:10F3A0008EE4F2CAD6A564D7C7EC5C23C99195F761
-:10F3B000F9E9FD2B3BAEA7799D8179237ECEECE662
-:10F3C000FBB995399620C2779D9DDBBF2BA19F2469
-:10F3D0000DC74B221E7EB3EB7A17D2FB378C7F2FE3
-:10F3E000D0CFED84DFD8865248FEB85B52D0CE6BCA
-:10F3F000DE7EFD4728B756EE963DA8C7D9112BF9FA
-:10F400003D56EE9E3371B905C7B99C568978EB9B82
-:10F410006393E9BDEC0B72FFC9D075F05EE9BBC622
-:10F420008DEBE4F86E2387CF6E7A1AE1BFEECF3210
-:10F43000F1BDA2637EB4577B0DDE89B8DEDCBBF67E
-:10F44000CD45BCFEA62E5B47ED9F95980DF1606FF4
-:10F45000CDC0F72B25C587EBAB7EFBAADA787BA462
-:10F46000334D267C57E6AFCB085B88DF6F453DD731
-:10F47000B85B4F76DDF1051FFCF236678CDF57CAAB
-:10F480003DB7CE8CB3379A77DD28F8013436E06982
-:10F49000A5C093317F5D117EF7F3F87FE5FA9622E0
-:10F4A0001E8FF9EBEB20BABE77F1F5F007D0F7B479
-:10F4B0005FCF7168ECFBD1F641AABFD9E461DE7D74
-:10F4C000168A1B7A719F9BE754A83ECFC9ED6CE565
-:10F4D0000F6BF7BF0DF0F7A7F98D4E789FCFBCA546
-:10F4E000485777C45605E6244E89EC1FB6CBC8EDC5
-:10F4F0004985FBDDB6A5B3A737C5C1998DE3A5D373
-:10F50000FAB43961DC0BEFFFE935C45F53DEB9A90A
-:10F510003C9EF63B8A4F590679DCD2E2F131E48B0E
-:10F52000E6C13A7657494C1E367BB8BC4E9CD77222
-:10F5300027DF67343B23344E753A5F67AABF77678E
-:10F540006B12F9F5763A8366BEBF0D3094E73795B6
-:10F55000CB3CDE22EC129FF09399BCAF308CC730CD
-:10F560008FEC190FE521EFA9CE3428BF5D3EC723EC
-:10F5700043D9E27DB26B2CCEDBA317F5E3C85FF86D
-:10F58000D6AC4AB24F6EF2CAF45D569F42FBF521EB
-:10F59000EFCF9D77C1776F66DEB4D3F08D1A50D66A
-:10F5A00048C721FC36DA018ABFDC19E75FBDD133D9
-:10F5B0002FED74BCBEF472FD8FFBF17E113718097C
-:10F5C0000F2569953311BFD77D99D3E1E367F9FE24
-:10F5D000E36333F763ABED3EB6723D53EB94841DAA
-:10F5E000D89F87723E5AFE5AB1260EEC34F4E7E1FA
-:10F5F0003AFBADA41D6775978EE2B3ABBA18C5632D
-:10F600003FFEFE8B79286F3FDAF762DED238F812C0
-:10F61000FBA9CF5B9D5ABF94EA87748AB8F4528FD6
-:10F6200091FBFB46F143AAEDD976BE1FBB08D21D64
-:10F63000F94EED77B13EC98B76E545662279B67411
-:10F6400050F835BDDE4227EE1FD4FE09E36F41FEC0
-:10F6500001B8A40189F6E7C9251192AFAB4CBED71A
-:10F66000C6B8312FC54BF499877494905FBD069C42
-:10F67000B722F67946C5D788F45CDEA3A56396D396
-:10F6800026E2944EA2BBA1C9A2A07EC8E810F2FA5D
-:10F690001B3ADABF18B25D16944BD715257562DC9C
-:10F6A000DD99943215FDE6B9D9C5D43E50C5F93A75
-:10F6B00090C1C86F95C55A2492B736EEE7CE99CE61
-:10F6C0006C98E7F1A293DB832EE6D92E933DD82FD9
-:10F6D00091BF5FCC5F95EBC82F28E73E964CC42FB7
-:10F6E000D2A044F69DACEB5F8CE38EC63FBD09FC17
-:10F6F000D3FB0FE69F3EF57BC3F8C74F71BAA52E2B
-:10F70000D3C8FC23FCAA5FB8FD6871C26F98543F50
-:10F71000B384F3AD15E3D59A2C21792AC98773F107
-:10F72000FED45D6067E27E448D2B8EE958E2E6767A
-:10F73000FA5018F7E5C9D79848CF7D47375480F677
-:10F740007C629C11286B47798F3286FC8AAD55BE4E
-:10F75000D36971FAFE08DF3734DDE7A5F7B307B9DF
-:10F760007E6F2E3490DDD93C200590CE4D3E43D0A7
-:10F770005440719525A4B71F32BB799CC4DD4E71EE
-:10F78000926FBB791C25EA470DF73D80FC566F212F
-:10F79000BF4362BCE585BFC8FCFBE3197DBFB794DE
-:10F7A000C7777AE7B9C9AF911847635DDAF5ABC699
-:10F7B000512E5A0131F0BDA59BCD44876C99E39938
-:10F7C000A59AB87E192E07C85F9B315D1046C43BD1
-:10F7D000A2EB1A240396B345BD1A9FB196F80AD03E
-:10F7E000C2BD3DEDB93793D2FF967C86D6EFFCD5EE
-:10F7F0007C8680B116F3194C683D8B7A041BF4ADFE
-:10F800005AF69ADD18BF89D52B60379A0624F1BDC8
-:10F81000E76F9853087890D4EFAFDFE4B550BC5849
-:10F82000F3BD78F89484F1F530BEC52DDA070ECC1F
-:10F830009BA3505C52D47FD68DF91B5BF4DAF108A0
-:10F84000A5A23F16D4EF1DCF9CFB9DCD3931BD0F36
-:10F850007680297D5A4CFF6FFCA0B6E72AF856B295
-:10F86000EDB201F5AAAAC79B9D3CBF2171BD3AD25A
-:10F87000F97A05FBD5914E7283DBB5B5223E09F6C8
-:10F88000EC5C5C5ACDEB7C0CE393602F64A4631EAC
-:10F89000C3FBE7CE1C45FA2DF898ECF9E64F15EEC0
-:10F8A0007701BB03ED7393E07336A0277DABF2C104
-:10F8B0006A217F7AEDA0EF915F8F48D302C4172DA4
-:10F8C00079B7000DEE4FF7BA697CB1EF4A847746FD
-:10F8D0003AF793341757ED28C2F19F9218EAFB4D7F
-:10F8E000C52733D02E691EFC3063795CBF55038F6A
-:10F8F000121E56EDD78F38FF19E9DCBE6C3AFC3C7E
-:10F90000F9073F0E4AB496EB9560F74C28D7D7EB32
-:10F91000D04263E5C125B791BF7F91818D87F9E51D
-:10F920000B7DD4BCFF2B8199B83F837F12BCDAE9F1
-:10F930005B417A6FE7229305E30ECDC54BEF263C82
-:10F94000D892BC88874DC55559F89DA6BAB9368A54
-:10F9500013807D85F54DF7DD4E7E1315AE4D03FA10
-:10F960001AB4BB2AC0CEFA11C09DEB985FE381F5B3
-:10F9700037463E587A8F05E3C223CBDF7FC9E0F4D8
-:10F98000EC947C819BCBC94FC8E2FD7EF903DC9EE1
-:10F99000AB4B3768FCC275E9DCCE9C15189A8DBC60
-:10F9A000F7B2124E46BBB799793FC1FD25F359DC3A
-:10F9B000FB884E5C8E38DBDCE43F3239C3DFB90AAA
-:10F9C000EB6729B47F604AF811FCEE856EA76713D8
-:10F9D00013FC8BE5FB4A822847FF39DDBF18F9ACE1
-:10F9E00042D88F170E5F5F8A7E36D53EEADE630E01
-:10F9F000621CB0DBEAFE6E0DCAC13F283CEE6D8A88
-:10FA00000CCD467AFCD141E3769B83DD48FFC0569E
-:10FA10003DD51FB6FA5721DF9CADAB29A2BC1B4BCD
-:10FA2000A008E3BC7A670F433B01B60BE44F3039C3
-:10FA30007D0CE3A1B3034B1409E57C82DD315BE46B
-:10FA40008F92F084F755428C8D072E3863A225D013
-:10FA5000F9595ACC0E79E34F0B157CA9DA273A13E2
-:10FA60008F67552F4A6232F2FD86C86B3AF45F3BCE
-:10FA700087C87E6DEC97E83B8DC5CF513ED81A9173
-:10FA80007714CDFF51C2940FB53E3D59E8F14ECEEB
-:10FA9000EF6C88F6CBEC00A7276361CA938AED234D
-:10FAA000DAA99D3A9E41F8DD1B85DF053418D53F64
-:10FAB00094AEDA07EBC553CDEBE2DFDD260D7965B9
-:10FAC000C46BA9A4F117ABCFA7D2B97D987A2C3219
-:10FAD00017D76FE4B09AA7C9F330774C9BE441D3B2
-:10FAE00069589EE6C02773916FC0D0A6F5DA34F04E
-:10FAF000C5F234BF2FF60DFFEB799A1EC9BB179ED6
-:10FB00003F4AB773BF959AA7E9E1F853E36C89F9C7
-:10FB10009917B2420ACFB70AF7ED43FE1C30521EC6
-:10FB200057EDC0EBEFA17EAC35B17E8C4326DA19E0
-:10FB30006DB6AF0C22DF5F3C7FA6EF418679BA2F0E
-:10FB400078285F23C17E48DC27ECC52659A3DB7BE0
-:10FB5000EF46E9C9EDBD68F97FDDDEE3F67C601FA5
-:10FB6000CF0F50E579B3D89F5DACBF94827AE6445D
-:10FB7000149E843C86A7441EC3E0C8790C8AC8073B
-:10FB8000027B3D407C7290C775DE783A99E4C725C8
-:10FB90009BB217EDA5F3D6C83711598AB0933A8FA7
-:10FBA00018DD282F40DE91FC0E1CD4F3380DC66DF5
-:10FBB000308EF3F24411C711F1A29792C96E6948D1
-:10FBC00071A7627F354EF363A16F1A92787CA62BE2
-:10FBD000D97F397D84B8CD1E617FED81A16C38DE7F
-:10FBE0007B4611C7060181FB9D877279DC41C46D9C
-:10FBF0002E8AB8CDA9625DC8C0FD10E4A77277292E
-:10FC00002C0BEADDEF99836EEECF32E940EF2F53F4
-:10FC1000E3362F733FD532119F39B5602EE5072D9E
-:10FC2000C7FC7719FD18DCCF1CCDC767361DCE6722
-:10FC30000D888B9D28620280F56BE0B5A493D09E61
-:10FC4000707742998C656F4F0D7C7769A78EF6238C
-:10FC5000CBBAB4FEF22B9BEEAE41FDBDB193C71FF4
-:10FC6000035D12E9EF65CCEB427B43E587828C3480
-:10FC7000A273A053E7C5EFCCC8E0FE04407D90E638
-:10FC8000279E9D7AE1671770B4335D089F3A893FDC
-:10FC900037DA949A11F5B218AF53DF62AA443B36B3
-:10FCA00057477EDE2B06EF22F2933A8A886E9DD666
-:10FCB00096AE1A5E4F6BE58A39E2A3FA6B156EE8D1
-:10FCC00031B703E564668688DF24CC77798FB69CEC
-:10FCD000187F5815D4969731FF842C3C87B05FFB72
-:10FCE0003E3383CBA92B9B0A849FDF437EFE4EBD10
-:10FCF000FBDD029453DD0AC9C9F61C8E2F5D2E7FF1
-:10FD00008EB5572F22FBC00E7605C1CBE11F7BAD10
-:10FD100053427DD969E77CF93F853B11DECA8C22CD
-:10FD20006E27A07187EBA85B0A727C71B8BFA8BF71
-:10FD3000626986F01708F9132DFFEFEF37393F7628
-:10FD4000CB62BDD948FE2C15F1C65392E7E910BE2F
-:10FD5000B7805D00702FEB96CBD03E99FD150BCD93
-:10FD6000A3E96573D008F58DEBC279B88E9AAAC263
-:10FD7000452D23E015A15554B905ED963A617F80D4
-:10FD8000EBB64B1B871A1E57F47E2B231DF721A7BA
-:10FD90000EBE8EF43E6826BD04FF75D488FE8EC369
-:10FDA00005642F4D4DF5B765A03E4F0AF57DAF00B8
-:10FDB000ED136E1F350E1AF7A0FDB7B4537B6E8698
-:10FDC0006DD6C6B9589783FC19AC57FB1ECFA768F0
-:10FDD000FA0D8B7B713DBFCDE09F8876DD755FE6C8
-:10FDE000F1F5F3AB740CE9BB4CF6AC403972DEAC08
-:10FDF000B5BBCF5B39BDFAA274F614219DFB46A5B5
-:10FE0000B3A708E9BC4CC7FCF1E334229DAFC6ECB4
-:10FE1000734EE7F3CF5F5384743E77F09A22A4F3D6
-:10FE2000367D8F17D7CD930EFF5EC4CFE9393EB232
-:10FE30009BD4BCC92FCA8F8732B4FA305AFE3BF923
-:10FE40003F46D383A1281C5A3DE834B873501E2E78
-:10FE50003519FFAA3EC4BF11FD692623F9235EFEB2
-:10FE6000D3E58751BF050665B23FD4F15E56FCE38A
-:10FE7000D05FF0F27B2E4F401A7DFC066157B94CE3
-:10FE80002C807E0FD5DE57EDC64479FC0B319FD315
-:10FE900019DE1AB4B355FF6CBD18D314BCCCEDD326
-:10FEA000A724F2BF9ADCFD3C7FFEC8121BFA67CF85
-:10FEB00006B93FB6E9F952F2D7AE0ABE12C2FC2724
-:10FEC0003628D970DFB0EAA90F53309E0DFBD0530E
-:10FED0001971F19539621F7A36782A05E3DEF0FD53
-:10FEE0006AFC7EB2336240FE6D82FD1934614D4A78
-:10FEF00084CE0D353919E9FBF201ED7E4D8D4FEEC3
-:10FF0000F41948DEED1C9482B83FCB30F80B7250E8
-:10FF10003FB11CDB99E4D87AF924C36BCB9C161F44
-:10FF200017F65ECE88CB570AEF48253E0CEB999723
-:10FF3000EC801D56219778BCE63F77D9833C7F89BA
-:10FF4000B7FFCF600195557DBD429CC35B21CEE1DB
-:10FF5000A1FC0E25C8EFF87234DEAC9E3703791E83
-:10FF60001A29FE1D97B714DFBF8945447EDE674618
-:10FF7000CDB8D17C9D965237C0BDE66B163A67D896
-:10FF80000C7CDD5A16E3C3063115950F9B845FB7D1
-:10FF9000B9FE24ED039AF17C05DA551ECE870DB02B
-:10FFA0003FC2FCCDC475CBFAB5F98CA3ADE329995A
-:10FFB0005ABD122DFF83FC98D333B5EB579DBFEA92
-:10FFC000078FCE7350E2EB2B615E89FBCA44FFB50D
-:10FFD000BA2FFCA272EDE64CAD5C8B96FFC172EDC0
-:10FFE0008ECCD1E49A363EF037CBB5C4384121F7F8
-:10FFF0007F639C00E3B6FFD338C147EE9E0C1DCF54
-:020000022000DC
-:10000000C3D7C44FBBA4969B4CE330AEC8E3CB8DA3
-:100010005623C56113E3AACDEEB9228E38F4CB196D
-:10002000A8370FE919EAF37ACB4A8A5736CB070C7F
-:1000300078A470583C51394A76FBDF1A575F9F19F4
-:100040008DAB17605CFD15CBE5347F1C3DAB4AC022
-:10005000C02F193DDF68B3A053B2C88B30290166A9
-:100060008FEB3F5ABFDE4C6E27BF22F2635C069EC9
-:10007000C7BEC50AFB3098BF4BC7F377EE4FF76D8D
-:1000800043F9687273FC3E71F8AB0CCF1D3DA1EFD4
-:1000900027391268B478501EAA7E17757C45F80F70
-:1000A000BE28DFFF2081EF7FF077E6FB447C0CA8C1
-:1000B00072E76F8D876D07DC68D607A3B8D75B182A
-:1000C000CF2918CEC7A38D331A3FFF34D3F75A2652
-:1000D000C947EF54CACBFD82F226B93C720AFD3BF8
-:1000E000EC90D18DFB0D933897C13667893C4A4F10
-:1000F000451DE513F3730DEAF98FD1ECC20FA3721E
-:100100009ADB851F8E2AA7FF7B76E1030EDF299CF1
-:10011000E7E94A6F11EACD8D56801FF77BDF378EF6
-:1001200078CE423D0F00FCC4CF9B3CCBE3E0897C02
-:10013000F58704FDF287BFB37E194D9EEA5D2A1C48
-:100140007F67795AFFC714F47B8E3E4E80E0A8A8E3
-:100150001AF28AB815C3B8913A8FE6219E7F96218C
-:10016000F2AAD4F7116117DEE9F266BAA0FFB9F777
-:100170004D26960A2610F218DA633E0BC5039AFA4A
-:10018000799E48D33A46715FF51C65D3401D43BB49
-:10019000AF3FCD5F8079601B3FB004E454F4932FF0
-:1001A0006068EF5D789F971BD2FCE3294F6C5D5828
-:1001B0001377A8F8ECF206F46700BCE41F708AFC21
-:1001C0004C15BE3A179767EAF32681EFE8BC9C1CF2
-:1001D0004ED62F07D14E4C760F911FA9E91037DE6E
-:1001E0002A642FF9EBD91A079D9F683A54594AE7B8
-:1001F000CDFBCDA568E756FCAAD686FE8973D73A13
-:1002000029CF204F0EAF423BEB9FD3FDB3105E6B67
-:1002100079701EDAA9F960A7A2DD7BEEE0BC527FFF
-:100220009CBF7B1BFABB61DC6D56AD3F9B99789EF2
-:1002300078FD5E9E077CD8EA9F8BF8DD66E6F006C7
-:10024000B68ABC67E1E74E5CFFEABA8F9E73BCC317
-:10025000447169552E6CD3333FEA3D559E94883CDA
-:1002600039C007CFD31BACE3F91EA26C716AF3153A
-:100270004F67CC2941784AD0D13B0DEF518848E8EF
-:10028000775F2EE2F0D78B7C0A357FCAA8F8BE8E46
-:10029000EDD9BA9A58FC7D2CF617F177912793FC8B
-:1002A00029B79FC7DA0CC43756585FE41F01BE4117
-:1002B000FACC8A0CCDC6F34485BDA15988CF973FAF
-:1002C000D5113E94BAB7287E928A648371C66D0EAA
-:1002D000774F403F8AED17D7225DDC3DB62A445D5B
-:1002E0007F9AAF91E0505A8A715F59F5AF7A9E07B5
-:1002F000782499FC03BD790D940778E103E388E73E
-:1003000046D46780ADA7BCBFB1033F273FBEF59081
-:1003100034623E6797CBC2CF0D078628BF8CCD7263
-:10032000123E9423BFA2B8AFD2AD9007A353EFD52E
-:10033000E139A8403B23FFE5F85E9B0EE9922FF2DE
-:100340004B2EBEFC5F53FDB44F51FDF6419E0FA4F2
-:100350000F6FC07D97D21EFE32AC60D678C8AE6BF0
-:100360002AC1F1224D3CAF3D99219FE40F8C5BFFE8
-:100370002528E777D99884F2E7A535F9E42F857920
-:100380008E1F619E77BB78FE8E722459877A4BD977
-:10039000CA28FF50B1675411DC8F4219C65923F89F
-:1003A000468D4702B82ED44777BAFCBB11CFD17324
-:1003B00032AD49FC9C8C3877696DFDE0593C7FD2A9
-:1003C00067E0E70C8FBD3C7901F9EDBA1509E970DA
-:1003D000C5BE24DF06EFF78B756B558698CD128F5F
-:1003E000FF63946F39F608CF4B53F49C4F946EE73C
-:1003F0001EF40B7E9AEAA7BCD26B3B4332C5B36CAA
-:10040000A71FA971C7ED6BB6733DD2B49FEFA713B9
-:10041000F7319FA73F8EBAB47649B4FC0FB24BDEDA
-:100420004AD01B7FF3FE8469F77589F649E23E6E78
-:1004300098DD9D30DE68768A9AD75115FB0EF1C3A0
-:100440002B56D50E0A68F25EAA2CE2DC9B493BFED5
-:1004500053224F47CD83C9E870B7635E79E4DB8CE4
-:10046000FC6C6A3E4EA08AEF1B023A139D8773B163
-:100470001ECAC319C3429244F67F98CE7566623E87
-:100480000EF47BDF3596E0DECD3C5D32C943B784A8
-:10049000709B318F83F236833B56E0776EB1D07715
-:1004A000CC98C7713586E2BD3B507ECEAEE77188F1
-:1004B0006CD0B7C8B7D9859C0FCD8B783E879AAFE3
-:1004C000A1E657A878A812F8CD9EB0A200F707DDE4
-:1004D00092FFFBEA79DAF873D2D1F3D1ABC6D279C5
-:1004E00093E8F9B94226EABFD839E9447CAAF91D54
-:1004F0005536BF2D2B7DF87959953FE2E84670EDD2
-:100500003CC2EDF5AA7A03C17F71D57CF2235E5C13
-:10051000A563B86EAA068D9CDF12BEB7337A0F466C
-:10052000D04CF75D08BA7F9EBD0AF42C463FEDB172
-:10053000B69AAB4F036E8FB7F9E879D12CF5CB574C
-:10054000D179C6C528992E67EDACC57B0A2E5A23F2
-:100550007978CFC1E5EC076FA4727AE404965376FC
-:100560001EBA11EF3DB8383ED287F71E14EEACE448
-:10057000F5C883D98C5D9555716380E6CDFD4EB38A
-:1005800063E7B3CB113F8D2CBC6188FC3B3C7F1FE4
-:10059000F3FD900E2E8B81EC1997C8B364D522EF32
-:1005A00012233050EEC82AA578B585B90F0D617DAC
-:1005B0000E3F2704F5C4BF1DE3B95FD824E8CA7213
-:1005C000543F523880F2A9A3C04EFDA372F490317B
-:1005D000C8FD59FCFBEF3C3F85E24B6AFE2863B641
-:1005E000DC855328DF445356EF37608A2D17ED859D
-:1005F0000EBDB04B45392DD55F97156717BD33E755
-:100600005B25B80ECEBFF04021CAA5EB0D60B78FB9
-:1006100020877E9DCDE5D045BDA54B023BEDE7296A
-:10062000FEDB719CF79217CFB5C3BC16A5551AEC2B
-:10063000086FE0FB32CAC574416FFB420E9FBDDA02
-:10064000272D87713BCCB07EA17FBA5FF1529EBD52
-:100650007FA1740BC0DD2171790B9D52695F52EC53
-:100660004EC5FCE506715E5216EB7E46FF5619ED4F
-:10067000E977DB06662A8531F87E2EE2CB3F2F60D4
-:1006800077D68DB0DF6DCDE2727B81EC9E827CB43B
-:10069000411A78AB360BDFBBE9FD9C94D672CC3B9C
-:1006A000BE3EB9A51CF5CFB0F7A9F0BE24AE6CE4F0
-:1006B000ED1A4C913C3C9FEC4DF6AFCBC2B8D092BA
-:1006C0000F296EF9CDEC774E60DEC13BFA9ED92939
-:1006D000A85F0AC4B97EE1377C6D82EA3734F1F253
-:1006E00064EE378CE6734DE1F964B50BF939C55A00
-:1006F00091AF30D7C6CFF5CC2D2FF074008837B12D
-:100700008882726FEE7BBE14DCB7B385FE72DF9415
-:10071000D1ED19E6D2BBE3D7EB3C775C19FEDD5097
-:10072000AC2DDFE8D1966F9EFEE709F1E53DC9DE0D
-:100730001D38EF1F4B3CFF313083D9689E4E298016
-:1007400076C7E417B3C5F94E9EA7F74F625FF4E290
-:100750007446F519FB4D7B31FF5DF533CBA27EB2BC
-:100760008B99F21DFCBE00D4571149E4FB39299640
-:10077000C25EB8DBC6F1076D0D30CE0B4BDCB43E6C
-:10078000322C3AF6655C43E526B2432AC69892902D
-:100790006F8E09BE53CFEBAA7C58A1301FE62FC045
-:1007A000A717E2F31DBDED28FA97031F31C6E955DF
-:1007B000A950FEA1F81663ED547E4CF0F7310153B9
-:1007C000E0DB0AADE757AD06A2A7FC13790FEA09F3
-:1007D0008CCDA0DFF8D2E649049FBA7E6055173A67
-:1007E00033C8A52DC655740844B1B02754FE460B36
-:1007F00008DB8DC1FF2C203E27791399C6EF4FF8F7
-:100800007901972791AD0E711E8CC7CB724DD171B6
-:10081000BD386E56F43BFCBC51862843554807F35F
-:10082000FE4D560197CB83AFFF81F4B2C5E3C7EF0E
-:1008300018524C744E465D37B6CEDFBE553B03E7CB
-:1008400059F40D9AE77CAB0DE7590C6CBDC8414FCC
-:100850006F1A8DC7D78F9CE471E33AF94ACDE199BD
-:100860004A1CDF40FF46DE3F59DBDF05FD1D71FD01
-:1008700053A07FC9F0FE4F594D21DD541CA7C21D66
-:1008800026791EA2C9CC17F3923378BFF9221FB480
-:100890003005DAA3BE29D6E66BB0E91E13BFAF431D
-:1008A0009B9F71BDB42E0BD7D53C53E36018C67B1C
-:1008B0005DD0ED7A9DFF77783FDDEB8B8B8EE37A11
-:1008C000AB310515DC0FDDC0421B9098172BFD4F97
-:1008D000D8C7913CF80BAE8B26D93FC101E5F3FA9E
-:1008E0009EC2BB0B68BD7C96356D38BC2A5FA8F0F4
-:1008F000227F209F45F92301EE289D6EEAA744B68A
-:10090000DD60F7E053B583186BE1F9C6EEDCD8BCC7
-:100910008089E69A5A0AD10E79BD3D4072E37AFB8E
-:100920002394D7F4E7317E6736C0B5E8AA4FE85E76
-:1009300013E65A3201ED7B80373D3BFDFF1DBCAA1B
-:10094000BD372CDFF6238326DF76B475A57EB799F5
-:10095000F1FB69660FEEA1FCD9E685160F9E836850
-:10096000C6FCCF728A2F911D87E784E99E13C924A4
-:10097000ECAE2F9A97CBD7616FA39BECB7A81C174F
-:1009800079E5BDA51CEEDEBBDDEA3D27DCBE5BC222
-:10099000F83D29EA3D27CB6D54AFE69FF7EEE17EA7
-:1009A000BCDEE727D07929B0DFC85E60A93A0E5FC8
-:1009B00081F67E15FC933262F9D2DBF4DCDEDCA931
-:1009C000F354209E77621CE8AFC47FBF9AADF59BBD
-:1009D000A8E544BFDE930EFFEDC817CB4BBC7912E0
-:1009E000F0CF3203F7DB017FEDC2B31535ACE5295B
-:1009F000BC3F701E6BF9856E1CF1979FF86BF22758
-:100A0000FC5EC1187F2DE1FC1520A1A4F25794AF24
-:100A10008A13F3ABFCABB17DAFBDFF574D68A70E9A
-:100A20001A892E6A9E5CE23A8E83E7B49EC3E394F1
-:100A3000658267ED48F07C113E8FE7AF4CC6F979CF
-:100A4000347ECF5458C05A16E3F73DC9FE76843F32
-:100A5000CAF71BF87E6418DCB285F8E3D6DB649E27
-:100A60003F9ECCF515C62BB2E0FB75E2FBB7767363
-:100A70003EBAD56A20BEAB1B6CA47C2256CDE30ED9
-:100A80001EF81FDF077A09BF8B44BF85CE523DB2E7
-:100A9000ECC25A6D7C6291458D7FF8F4B81E6F5D93
-:100AA000A83F19AFEF17B1CD9F60DEDB228C63A8A2
-:100AB000FDE0BB8F6747E31813308E715CECD32FDA
-:100AC000027F23FFBF9ABE72D7DDC0B7131E2F2946
-:100AD000437FCE9C8C554F6D85F2F7764EA2F2ABDC
-:100AE0001977DCFB0ED6F71551B91A2F71C1FD46E7
-:100AF00023EF5F5C71DBFC02F8EE71B31817D715BA
-:100B0000EEFB92FCBD75D0CE35756C19E623560B05
-:100B1000F970F16E9E0F7FC355569EE2B9D24D7E9D
-:100B2000A3EA2451FF753EEE5BA5FF568679A9D551
-:100B300063238BE93EC6B21F4FC2F271E993C5230E
-:100B4000C54D26174BA189809F6A076F5F5BF6FD35
-:100B50006CDCC75757F1F2644F65F738ACD75D5A74
-:100B60003CD2B9D09F8AF5143DF724D6E98BDE0F2D
-:100B7000E99C93CF2479708ABEE91FF27B892C927D
-:100B80000DFD8F3E6F81827ED2D95E9EB758656A19
-:100B9000CFC2FDEF4D7E4339E69FDA4CA5C7D1CEDB
-:100BA000489D5E390DE93BDBC4F4A89780CFFF85F3
-:100BB000F8FC9A4FF25290B92C5A3E57F9A84EE5DC
-:100BC000EF6A2D1FC3FAFCD7ECF4CF97AFA3F13136
-:100BD0007CFFDFB1FFA22F69F54A74BC84F596381B
-:100BE000FE687200FFE2E55C0C8E7E5A573998155C
-:100BF000360ED75D8FBAEE220887413744E73EF2C2
-:100C000025CF243AF0388AFE57E1CB05D9C6CA86EB
-:100C1000C3857F8A6A9771086CB60CFC2EAF877EFD
-:100C20005EE688C105DF676350EF6FE0F0EC965A2F
-:100C3000B8DC1076B1BA3F6E52E73BA09D6F45120B
-:100C40003FEFEC42FF05F673964EFA6B70370BBD23
-:100C5000B9D0E47BC80873B8C5BE8CF8E1AB2CF002
-:100C60003CDA27C654BF634C3AEEBB0247C205E4E8
-:100C7000CFA5BC01A077DA9838FB44852B111F4D16
-:100C8000A3C8C344B813F110A3CF10D957EAF9A9E8
-:100C9000E8BC12E6D361E5EB3532CDA8DE5F528CBD
-:100CA000EBE26D699227DE9E7E3B416F27C2A5DA9B
-:100CB00011AA5E55E1417F11FF7EA41DCF90DD3862
-:100CC000662CD99D2ADF640AB80C3A69C438EA8DCB
-:100CD0006374AA7F4E43C7C4734E2ABED4BCA044DB
-:100CE0003CA9793DC3E23509F1C8D1DA49603F8FAB
-:100CF000710CC79F1AEF7144FD5C029FA512C93F9A
-:100D000087F073CDF6F0F309B5ADFC9C7C6D0D4C0E
-:100D10000070FFB6F01FA8787EC8EEBF8DF347784D
-:100D20001AEED3BF3BEF698A73A8F7C825E267F9CB
-:100D300028F8198DCF47833F2DD5B712BF7B5E1A98
-:100D4000AAC0CA2DE9E2FE41E62FC07560B715546E
-:100D5000A21F02E4EA679FE1660EAB80AEE50E7F5C
-:100D600033F2F957996F0ED2D751E3D773FF3A2375
-:100D7000FFED5AB1DF9A23F4EDA55D32C507AABD98
-:100D8000131F9B8576E21B7A16A4F5EE25FDB94666
-:100D9000C07F099FD8DEC2F5EECA377F54012B868B
-:100DA0004DD8AE8BDDAF00FF26069334F72B4CDE1B
-:100DB000EFD094A7F4676BDA5F353056535F1A9A19
-:100DC000A4A9BFFA8D324D79DAD04C4DFB6BDEAB66
-:100DD000D2946784E76BDA7FE9EC024DF9DAC8ED6B
-:100DE0009AF6A7C4BE9805BC43C51978BF389FEFD3
-:100DF000759F2ED5F4FB6DCADC37900FEFDACCF37C
-:100E0000972B01339A7B267AB85DD102FFE374F504
-:100E10002988AF15606F63DEF2CAED5ABBA37E70FE
-:100E2000EB0694A5897915AB594B155E49979857F0
-:100E3000516D5BA243BEFBA731C2EEB8865D23EEC7
-:100E400085F9AB742D62E3FF5B7435BAB47435BBBE
-:100E5000B5744D2ED6D2D5EAD1D23575BA96AE76C6
-:100E6000AF96AE69355ABAA6FBB474CD5CA4A56B37
-:100E7000965F4BD731F55ABAE6B668E99ADFAAA56C
-:100E80005F4160B5965E09F456E5E5B8AEB59A7671
-:100E900051BAFBEA291F667CCFFD9A7155BA07E06B
-:100EA0007F9CEE2D94AFFEB7D29DB120F95F13E980
-:100EB0007E3681DEA0AF3E42B90076C6397C2E9ADE
-:100EC00020EC79DFC876862A7FE2F57AFCBE75349D
-:100ED000B9344C8F897DECA87A2C611FFB3E66F1FA
-:100EE000907DB499FC3CB709FEBC8CAF66A01FF5A1
-:100EF00007A49FDF0740A6035CEF23DCF09DF79378
-:100F000026939FE10E16D2D3BDBF98890883DE8950
-:100F100089C932DEE7E3A6E732A1BF970B3F8437EA
-:100F2000D99F92C3FD0FF919F8DD9C217EFFF25B7A
-:100F3000695FE89E8293E887079D721AFDF0F0BC16
-:100F400060E6FC7046950F5EE676C6E16DE96C8959
-:100F5000F4323A7C703FBBF4AB12C51996FE9E3F4B
-:100F6000C7E770BB37F1D9D1AAE28DEF876EC871A0
-:100F700093FECD61FDC27E637ECB381A87FBCD9F89
-:100F8000E4F78F3E2B3165BA838E49111D334D1C1A
-:100F9000AE67F5CC84F87B86F9DD8897EF28209A38
-:100FA000789EFE24E487A5BF7F672CFAB164D975CB
-:100FB00013DE2F3D1DBF0770CCF95A8B847EDD4CAC
-:100FC000578B847EA361EF0FDD2FE1F9C26899F1A1
-:100FD00076F8877850FD73C53A1EA78EDCCDF717DB
-:100FE0004F7D9D91DFA9A3355019C0F8940C0607D9
-:100FF000E6B1E8F979E41B72B8DF2D8B0DD1BDA6FF
-:10100000EC3561178AFBE04B44DEFB0511E759B173
-:10101000C7C4304FA2E4E05107C67556002D875073
-:101020009F297EBA5FA364C7AB0E7ECFB8DE8EE782
-:10103000D8543D3A3ABD1576262E7F1CE8D8329218
-:101040001E5F93CBE3B31D6D35B3302EA3C2F360A7
-:101050009B7716F287AC7818C693F0DE9DF8FC33C8
-:101060008313EAE3D6AF62A9D194F5161F5D66B18A
-:10107000A1AD85F84C2FEE07DA98B3D616FFBB0169
-:10108000AB7374E21EF200433B9B8B7A7C2A675061
-:101090003EFC91F17DA8D105E3C4CBB57BF358BCF0
-:1010A0005FB9ABCD47F06E90FC7E1CC458C842E6D9
-:1010B00014CC5BC0B397F07EC7F56F601E8DC1BACC
-:1010C000D613728F8E37A34BB9122F971EC801B952
-:1010D000941C934BDF6D3B4B78EA685B44DF037CE9
-:1010E000318C9F05B2B87DDAD1B684DEEBC0CE423A
-:1010F0007E7A65C784A36EA83F01FFF09E1CA39370
-:10110000C3C5CAF3483F2D167C803EAB5CE09F13FD
-:10111000AD7AE2B37B722D415C84F7BC3DFE28DEE4
-:10112000F369005E92FF06B8A3DF11783208B904B4
-:10113000FCE4C3F566C856C8FFEBB02D203AFD7736
-:10114000C753F16B3033BA87C6906B21BFCD17857B
-:10115000F37B39097ABE3C8FE4E83D022FAFECE027
-:10116000794727EE6564BFDE731FF7BFDDD3C8285C
-:10117000FF9BB5C25F458C6F54799D8E3781C0CB84
-:101180009E361034458C3DDC66C293572C19FD64A5
-:10119000E36274ECF12A7674C76FAD76D6E1F3E1C1
-:1011A000E9A77B50AC6C99F5BB217CA28F1BBF6F6C
-:1011B0006B6141B43329160BDFB7D74319BE9F22A9
-:1011C000EA53FCBC9C2AEA5317F172AEF739A91A0C
-:1011D000014B8883E45A1CF30A51EEDDC5F8B95B74
-:1011E00071EE7EB790BB632C8EBA6AACFF1AA37CFB
-:1011F0007CB5FE71519F6539D9350EE5F2426DFF20
-:101200001D020F9996933DB3295EA2AD57E31BE9EA
-:10121000964B6F50FF126DFDA3A2BFD57269683661
-:10122000D6176ABFFF90A84FB67079C87CFCFE54F1
-:10123000B5FE3BA2DE8CF5F87D8FB6BE5B7CBF436E
-:101240000A127DE88E585C3FE9DC5FDAD7C6AEC58E
-:10125000F5D3D316A175F470DBA7442709992C3D6B
-:10126000B6AE6CAD6CC4F3E092906729EEB0D73B9C
-:1012700082BC53EB1D367EDE5D7619888F8C16217D
-:101280002FC43A8CCA0BA9C5C3998BFBB13F8F9F62
-:1012900061815D41FB220FFE909F73EED5317F9CF3
-:1012A000DCCA6E4862FEB8F6AEBB1C9A72C6D7B2F4
-:1012B00035ED9D0BC76AEA2DE59334F5CC9B4BEBDE
-:1012C00065ADE0ABA492324DBD7A0E9FF5E46AECB9
-:1012D000677DE14C4DBB4BC56EFAFD9033F3D4DF17
-:1012E00019F198502EACB58ECD44BDF34CDB74345F
-:1012F000B2D9B3B09EF0E8D4013BCF2F3E807159F4
-:10130000B4D7DBBCF47E1FD483E5C29E84F5E686A9
-:10131000F67BDA6C547EA2CD45CFDD6D6E7A3EDE73
-:10132000564CF53BDA3C547E0CC6C7E7A3300EBEE4
-:101330007FA4AD86CA5BDB7C54DED2B688CA0FB50B
-:10134000F9E9F99DB67A7ADFDDD642E58D6DADF427
-:101350007CB02D40CF8EB62EAABF46D0FB8038C7BA
-:1013600078A0929F4B4EA4E3AC5C49732F983596BE
-:101370003F302B17F307FAC39AFBDD71DE349E99D9
-:10138000CF3F71BC3A1C0FBE3B890DB527F3754C9E
-:1013900071C7F1039EF5C9C0EF635A381D0A0622D2
-:1013A000549F55CF695127E065CE00CBA9E0C750C7
-:1013B000B1DD0569A82A99C76129BF8CB9609E155E
-:1013C000E27E1C62BBA00EE152A673BDA9D2353AE3
-:1013D0006F3B8713E73F12BC5F13F397CBFBF9FD1D
-:1013E00017353D2164FB246F0BDD7F615AE40BE16F
-:1013F000EF57387D7E3A8F3FE9D3B9B0B90139F361
-:10140000E997991B9E390DDA7D4FF65D659AFD854A
-:10141000FCE9C3CC7D358C5BA2DD9F2415AED5F4F1
-:1014200033E5DCAFA93738D76BEA97AE29D8E0426D
-:101430007C8E61149F316E6E6718525CDEBB95E046
-:10144000DA24F07E4172D379DEC041353ECFEDF330
-:10145000EF09BDC24C9B693D4CB0F362516A4087B5
-:101460007AE1DC8F52491E3DFD842E88FED7892CFF
-:10147000A8C3F53F19CC3DAC9F8237E8CA74A58A52
-:101480008CE552E696B17C358BD0FE04ECF3F5B9D1
-:10149000DC3E7FC28CF1C15CFFF778DE5288F466D7
-:1014A00091A06791BA1FD9AE24FA65BB72890FB5B6
-:1014B000E7993A859DDE6EAFC8C4B8E88551F2CA97
-:1014C000ACAE9933F177B4AC59D3E9A9BE7FC8ADBE
-:1014D0001BF19CEEE3025F2ADF4F0426177CFF38E6
-:1014E000CEE37CF9BB19B8DD6B2A8C10FF5F90BC92
-:1014F000AE2588D73765CE878359342F45E05539D7
-:1015000058E95A02F853DE1EE709B0D8779E6EF309
-:10151000CE549458B948E445EE6FAB9B591DF7FE85
-:1015200075014F311BAA41FD545CA2F30469649715
-:10153000467E990B7BBC78CE5C29631E146F1359D1
-:10154000CF7AD4D5CA5F64CA73518ECD606ED81776
-:10155000582C21867941AF47E7C934BFAFF43B5BD4
-:10156000752ADD17981D957BA813F1F79486907F57
-:101570007ED7ABE7F33AA6AD2FB6F0FC9D15C58636
-:10158000A05BC2B07A0FDD8BA7F4490C4D7FE52F2D
-:10159000B3090FEC8564E2BFE4ED53E94AED9B1417
-:1015A000FF0F91BEE743EE1774E3042F42BBC6C999
-:1015B00086BD688F4D40BCE0840A8B09AFCBC57CEB
-:1015C000F7B72D213CFD5ACCA33337011EE6F1E2DB
-:1015D000BD912B7A55FF87769E0F9557DD8CF7ECE2
-:1015E000750CC9C256D2E273937E682AFE36DDF9C5
-:1015F00030C025139CBF46FACBDB2BE8F795408122
-:10160000D0FC1A9F80FD7E01C9A31AD2DBD374944B
-:101610009F9AC857A7841C6BC9E5797F56D79767EF
-:10162000E2EFBCC5CAB3883F9FD1B162CA2FD1F1E6
-:10163000FDA59ABF0186831BF775A579BAE83D1A07
-:10164000F3515FDB7594F727EF49A2F389B25DA1EF
-:101650003CE34E4BB56D358E635328AE32579E3505
-:101660008476B3D1AEBB1AEDEEE37BEF1FC2FC1262
-:10167000395761E82FEAB429DCEEC8D1513E9662B1
-:10168000AF36611CA6C872BA12F17974CF37C9BFE0
-:10169000217F43E488087F925E90AC93B5D0F881B7
-:1016A0001C45DCE7E1AD2DCD10210437EE7F6A3E0D
-:1016B000423FCA71DB2533DA2B6ECB0AF2A715E65F
-:1016C00015D07CF4186F83F213EB2ED9516EBDB98F
-:1016D0006783A300EDE7A0423648F19F3BB2E9DC07
-:1016E000F91E039D8B57F19A1F503471BBDC566D68
-:1016F000D99810BFD3279C4BCACA2B107A6E110BF6
-:10170000C5CD47EFE2FB35E6B4D07EA7304F629FF0
-:10171000E962E531A2BC5F1FC8F6007E8EED5991EB
-:101720008FF3BA72D84F79BEA3D9FB1FE7BAD5DFC2
-:101730004332EBE87ED59019F37E9F6A63E968DF58
-:1017400099820AE55DEF13F2ACD0C2F9DF90CFF9D0
-:101750003CF159D8C3D79D722029988C74B3F59762
-:1017600005804F26BF328FB941FF15DABCE43F2C0C
-:101770006C35A463FEC0DC1F5A884F2E5992C84FA7
-:10178000A8B42679F07DC7DE8A62771CDCC1365B9F
-:101790003AE6E5EC6D33A5A39C0A8E225FC7D975A6
-:1017A00094AFECD6F17CBAF9791CAEF979FCBE970E
-:1017B00079A2FCA4125880703E09F4C43CE9A39BB2
-:1017C000B93DBCB6DD4470AC7D731CD955A3E1EDC9
-:1017D000E936573ADE0FBF77B32E1BFD4795DD85FF
-:1017E0009BF09E84B5567E4FAC9C3AE9314C4567E0
-:1017F0003FD533B4DF3B52667A96C5C97739755603
-:1018000031F2952C07B2D12F7267DEFC9B315F124B
-:10181000E8B713CB2BFB4A79D91AC8C6FCCAE6BE77
-:1018200069BC9C1ED889F995DFEA9BC1CBB9816C54
-:10183000FC1DA9B6BE6B79797C60279637F655F208
-:1018400032FA9E40766EE99B7333CAD90E83A71E87
-:1018500005F20F00FE1280BF5F3CB70ABCA8F5CFAF
-:10186000E17BC0F321F14CAC7F41F41B18A5FE25B0
-:10187000513F38CAF82F8B7EA151FA1F13FD8E8F6E
-:10188000D2FF35D1EF8D51EA7F22EADF1A65FC9F46
-:10189000897E43A3F47F57F4FBC528FD7F29FABD59
-:1018A000374AFD07A2FED709E39F10EDC3E2FD58BA
-:1018B000EBE60F42C07763418EA05C2AB66E76E0FD
-:1018C0003ADFDB554EFCDF51C1E33B2ABF8FC5DF5A
-:1018D0006F827A5D3EBF4F4A97CFE33CCF88F1815C
-:1018E0000FB720DFAD7D5BA63C9B0E9DE76C10E53E
-:1018F000E8261DD9036BDFE4FBF3B5DD4A30FEFCBF
-:10190000C53309F06F10F0750A789FCCE3F139A365
-:10191000CB955E1BEF47B269CB9896857217E4377B
-:10192000E5ED167757751597638C4C471688D26886
-:101930000AE17D0D8A55E8055B794F31C26751E8B0
-:101940009CBA625742FBB1BFAB9CEC3B15BE4E8BC1
-:1019500042F775C956AE07E6FE70960DEDAC4EE641
-:101960001FF2627F9742F6FBD1AE321BCA3D83F570
-:101970002E1BAEDF76379F5775537112CA6BF92154
-:101980001DC9EFE336BEDEFB5C3AF25B805EA1F37D
-:101990002C20AF3DA82326B0503B9D8F78F885259D
-:1019A000DCAFC7ACA515745E448D434B4A9CFD7FEC
-:1019B00059E0275FE81105F50B3C9F2C17E71C0247
-:1019C000DCFF0464738D893BAF79394FE6E740D47F
-:1019D00038A25C4BF716E5AD5334FEF79C7BB5653A
-:1019E0004382DE5012F4CAB82E9093717AA7206019
-:1019F000D3944FE609BF8E8779D07E9DFBC3CD245B
-:101A00000F2FA17E9346977B51F92BE4F193E21EB1
-:101A10009E2703FC1CF1D1CD653F417AAFEDD6D1B5
-:101A2000BDD35F548E3E93C7B87FDA0F7A07ED19A6
-:101A30008565E37EE9F3F0305EEF73D0BD0A9F83E6
-:101A40008FF18F963B50DE8EF72BA47786E98DCFF2
-:101A5000C1D7B392E73D3FD2D19EC4ED6A1B9F77B9
-:101A6000678693DF4724CE1FCAC25E7B50F8C195BC
-:101A7000D4B96EFC89904E7B0B9537489ECC1BA049
-:101A8000FD46C96FC3F21B8E24AE777293880FF7A1
-:101A9000A32D43F71C16F8D03FD21F34A8F71486A5
-:101AA000F0FF0E627E8E7A0FA28BEC33710F63EF24
-:101AB000CDD5D85EB14D469373DA138F6DD1830DBA
-:101AC0007AD0C0A2EDF13CD533C775E29EC4DD5B90
-:101AD000D05E3D98C434F7401E443F3A8D17DC82F7
-:101AE000F73EC2F76E90610F767DFEF7B658B26290
-:101AF000F054B90F6C69A73C59BE2FB1337E4FF734
-:101B000079773805970BEC4FAECAC77DF99ED3198C
-:101B10009ADF5D13ED5345FBA6C148D30137B59F4E
-:101B2000960FEBA07120925242EB2B5211DF3E45F3
-:101B3000ECF7E3DA7F89C61FA57DB10ACF81776F05
-:101B40002DE1ED2B71FC0BEE7006E5BC24C0933645
-:101B50007CFCEBFF1A3C9344FBF3A177A9FD05162F
-:101B6000CE985240FD6EC27E17DF7AB742CC3B035F
-:101B7000ED64908A37E37B34B7F8EFB1B490FDDCC5
-:101B80006FEAB1A1BD66D6F7F850EE16E2BD4ED3AE
-:101B900063CF05F985DCAE4A78DF6F6269B5C88F1F
-:101BA000AD3ADABFF49B86CA4AD09E7ED102320F8C
-:101BB000F5C23A0FCAC181F05A4F09B4EBCB99452F
-:101BC000FB8A8386967E3ADFBBC442E74FFB6C3DBF
-:101BD000365C3F667B8F0DE308F27DDC7E52965AC1
-:101BE000FC4F213F85D6162F8F5BBF556E3DC1DF61
-:101BF000FDAA6533EE03BAF59E9E0968675B15CAB8
-:101C00003F57960ECEA7F3823FD03192EF30AF2AE6
-:101C1000287736EAE8BEFA87DD4BEF413C30C5E76E
-:101C2000AB827E79E98A84E72F1E547C268C5F186C
-:101C300085DDD6E7E1BFF7AA7E7787B02F77E4F39B
-:101C40007BABBA971C287E0DFAF5B5AEEDC7EF99C0
-:101C5000279A18E699F5E59CE9C6F3A28FBB60C701
-:101C60000B78B034E8E8F75A1EAF8536A9E8CF30D4
-:101C700068FC15CF4AFDD43ED0A8A37D82A5C4A0A0
-:101C8000F16FA435E8BCE8773CE0F66F427EBBFA22
-:101C90006DE506FC9E6BBC6243FDF490EB17261DC0
-:101CA000C09952AE1DD7364B3B8EA35A5BEFACD5D5
-:101CB000D6672CD4D6BBBE6648F0D768CB29C847B8
-:101CC0008847900116D04349BC8A2559AED0EF858C
-:101CD00075FB77F54C8036C6E440E96B006FD2A403
-:101CE00024DAEF6F7C3509171FC81F467267E314AB
-:101CF0004679AFC772BFE9427D9A889FBE1C03CD6B
-:101D0000D75208F82CC0FDFA59FA5D2F0B8B6B5790
-:101D100080F8F13E93CFF7EFCC5581FE394672F053
-:101D200059D57F7C0B3F4FD5D7CAFDD20F2DE27915
-:101D30008134830A5CDFBC7D0AFECED854F4DB77A5
-:101D4000DD8DF98E8978CDC4FC3239C61F1BD4F3E2
-:101D50002B787AB2828B655C7797DCFCFECD970599
-:101D6000DF1C14F72D44DB23FE3218DFCAC2786F64
-:101D7000E6ABFE077E1E609B1A8F1165BCC610CBBA
-:101D8000078F3B6EC0F5B46DA1A30CD7D346619706
-:101D9000A5E618BC1301DE47DE3004A4ABA0ACB04E
-:101DA000E37AD0E7071DFCBB86379302789EEA11E1
-:101DB00057399DCFFA389FFBF39EABF4FCBC96D607
-:101DC000A342E7DF1E717ACC65DCDEC0BBAE19A58D
-:101DD00016816971B4B68CF6A98F783D665CAF8FB9
-:101DE000E478CC989F6CCE526CB88E1D2E85EED1C7
-:101DF0007AC4E4B7A1DDE2000588BF1F67C8ED998A
-:101E000047E7920087BA0A1E1260228F0FF3E8D2CA
-:101E100004BEFA5C77D9F0FCBAB3F0D0B7D0AF9E6D
-:101E200086E3A5F07E8827BBC0D3A57C37CF4B16B1
-:101E3000E3A7DDF51CB5C7BFCE8AB8F13C9CBF0C4B
-:101E4000F358907E074D7C5F1D273A3EF392DF7E6C
-:101E5000C34F38DEDA73F9FD4186358CF661CF5514
-:101E6000FAF71F45FC6425D13E3BDB955D85FC916F
-:101E7000FDC6CE05780E61C34FB8FE342CE7F1A63F
-:101E80006C8599BE8CF34EF7DB108F89EB30EB78C5
-:101E90004F1D32DBFF054658D4C60080000000000D
-:101EA0001F8B080000000000000BD57D0B7CD4C503
-:101EB000B5FFFCF6954DB249360F424248D8CD8B5E
-:101EC000401E6CC24344D4E5114445BA913722FE0A
-:101ED000420204482080F6A6D69AC50445C51A2AAF
-:101EE0002A5AD48D02C58ABA5440ACE85D1E5AAA5B
-:101EF00056D3AAB7542B4D842AC82B86F65EDA7ABD
-:101F0000ED7FBE676692FD2D89D2DEDBCFE7FEE373
-:101F1000A71DE637AF33E79C3973E69C33B33B9399
-:101F2000D82D3E076349136DCC6567F4F777FEBF84
-:101F3000740B5B674E622C650AFF5E10F63D2D65E3
-:101F40007C7E0963A9D38DF5D35858DECDEB1DEE09
-:101F5000BC8DC53336A0DA58EF89D8A3A5CC845CF4
-:101F6000D877F3B7E79BB5F67B078F60CC9F6EF110
-:101F70006C75319619311E635F4721AF3193EBEFDA
-:101F8000398C8D772532D60FDFEB5DBE62C676DAEF
-:101F90009C131C298C75AE649EA779FBF12FAF9F13
-:101FA000FB36CFFF67A6C319C56B651C6E692BE2B4
-:101FB000DFD95E7D30EA6FB6E84FC5F2F2CD47FA61
-:101FC00033BFC658542CAB0F723CD94C4C47FA77F0
-:101FD000FC5D8D71AC34CE78179FD448C67817015C
-:101FE00053DA3F9F06070E2C747AD09FBBCDCEFBF1
-:101FF0000D5A9C85169E1FF9D4A30F5A33310F0E2C
-:10200000E3189AB6978D66ECB9437CDC013CE77F18
-:10201000E2C189165E1ED35DEE47F94E9349E4FD99
-:102020008107278E656CE0A1E01A8793B18AA7B675
-:102030003F68E7788BFE9528F7F1BCDF02BCD40E31
-:102040006AE7F33B90B594E6DFF4BB2816C5EB15C1
-:102050009B3D9B90671F47B3AD3CBF7DF7D8D92E02
-:102060005EAF296E944B2F626C9A4BA3F95720ED0B
-:1020700077F1BCCC368FEE715CFCFD7A8937C63CBB
-:10208000475A397D8B9FB1B1FB786101E006BD5A9B
-:10209000A3034F83BE2D8F72A663ACDA29685EBDA1
-:1020A000E7BEACFD3C7D25AEA2CAC5DB57C74D4C93
-:1020B000053C191718D39339DD1AED4CE7B8CA4817
-:1020C000F999C6387C03530E8D630EF04DDB1A2749
-:1020D000D2FA18A687F165C6050BD387A33F2FF563
-:1020E000873F7B2AB850FC3527E96C0D87C7CF7135
-:1020F000BD15DCE98CE9D04AC0F813BDED6A7D64FA
-:10210000834FD9EC6011B84EE0C1C6716A2DE3A9C6
-:10211000C3128AEAA5FE6DB29ED9EE089987F1D462
-:10212000F9E611EAD76139DD6EEFA9670F58081F8C
-:10213000AC9605F234C2933F0AF98424CA33AFD770
-:1021400095920AFE6784DC0C0B3B14C5C725EEE5AF
-:10215000EB279D85287D82A3C791834A99899FC5D6
-:10216000327C62E0E3A7199B1CCED72A350D3211D1
-:102170007CB90DA67EC7397E0A0F46131C96752CB6
-:1021800010CD07CB053D38DD72D7B380C58D7AB64B
-:102190007EC793D1CE25F9C06962345E7028D6D54A
-:1021A000A6371DEB5902D197E4CEA61856037CA999
-:1021B000F1185B43FC10907CB1B9D1497454E5032C
-:1021C0006B0F44D031C94047552FE3C200A2674F7F
-:1021D000BF01EA2FA36117F143C6852CC927AE6F53
-:1021E000E93FBB8FFED3A87DDFFD0FA4F19F087DE3
-:1021F000903895A3E2C79DBB127D3C8DB6B6F83CE6
-:10220000BDE039E356A39C1CB6D72877155EA2AD76
-:10221000DE940A8EFFE8DB4C9E56DEDF65478CF5C8
-:1022200026BB3F4CC47AECA91F4A9986FA75A2FED8
-:1022300015278CF57DE37647D417F05D7DC1582FC7
-:10224000923E91F072B8FACD08836B823DCAD07E7F
-:1022500076E54570F59B1506D73569C6FAFA9ADE1C
-:10226000E1BABE20EA1BE152F5BE33FAD2EA45CE0E
-:1022700063DAE4A83EF02EEACF9A7D69FDDE54F3DE
-:10228000CDF56E69881CC72FF72BBEB6F83A4EC63F
-:102290003FF812486E3079A3F93EEA649D0CEBA832
-:1022A0004BAEAB24E6A4F5CC17BE8675F53EFE9981
-:1022B000CED810B7EF2BC8AF0976EFBC8779D58998
-:1022C00072BF6253788F97A3735FF18DC517F31FA9
-:1022D0006377115CAF6ABACE689FB57BB6F2F55DE5
-:1022E00098C1ECE95C0F606981EC1BE3188B752BDE
-:1022F00079CD450D8773A8C4DDF30382AB12699DC8
-:10230000079200CF3F3A6E7FB737C9DDAFA77E6433
-:10231000BD9EFA024F365B7025E0ECAC7378B03F9F
-:102320007C8022DEEE9999512133C7D739AB639D6A
-:10233000C6E5CC91D8F96FF6E378783F5E77A1FFD8
-:10234000D9B3AEBD1B79ED40B26B1587EF5C65FB71
-:1023500028E0D51BABE7BA391CB5767D502A9FE241
-:10236000994C7D7002F0EB4B26BCF27F14FB7A8512
-:102370005FC0335113F84F4ED08B31CE4453DB93B3
-:102380003E7CB3B48D423BE6EC47F09DB17179D70A
-:10239000CBFA5778182FFBD96FF57CD5C9E7B77FF3
-:1023A0004382A789C35B9D3C6BFE0A5EB4D0E44BBD
-:1023B0000D990D705F81F16A1D9583D201B755C2E9
-:1023C0006DEF27F1EECDFD26B89B301EF6B51F68E8
-:1023D00081AD6E414BE45FF62706EEE3F928D3F9B1
-:1023E0000F203F3A8B4D1EBE47B0CD5CBFB0F37D92
-:1023F000E53D89EF27B8FA634FA2EFEBF03D2D469C
-:10240000B44F7BC41468E2ED7DE35F213A3DB3DC59
-:10241000E131F3B12A99CB06BEAD625E1BE0FFE36A
-:10242000B8BFBDD6CEE737C7AD4FC73C6E4936659E
-:102430007D4070E885159CDFD85881FF6FE307C6A3
-:10244000D69BD828C66E94FAC14289C769CC6BC5A1
-:102450003833986EC5B8BF396BF3422FFD0D7450F9
-:102460000EEF2CE6A7EF735880D29B5888EADFCC9A
-:10247000DA29FFEBD892CC060E5FC5A383F3B01E1A
-:10248000C3F0BE54F2CB2D29825F3EEF0FBC6FEC40
-:102490007749FC5BA109FC0D71EBABDDB45E5D29F6
-:1024A0001EC0E49C30D01717B67E26F613FC677169
-:1024B000E67DD3FA69EB8A2F61C3481E38D2391EF4
-:1024C000AE91A4BCC6BB6C0AE60B0982F5FA1DB935
-:1024D0005ECBCD0E96C2E9D2E63207A2382C93C766
-:1024E000AD4CC37C7FB186FD6A38A7DF2FC69959F2
-:1024F00013D5F452BBA9B2BFA903279D847EF20E67
-:102500000BA58CE0EDCA2FE88712387EA69A7734A7
-:10251000738D9B4D1E68FDB43D4CAE5D9BB2D3C226
-:10252000B8FE725DAEF1FB94229E0F93BB5399A54A
-:10253000A79CD37F3FF003B9C35ACCE0DF47DD71DE
-:1025400029D057D85036549C0F3835C2E6D365FF92
-:10255000DA768EB77BCBAD3F093E5A9578763EE969
-:102560001D16319FE5EF9A49AFFCB49181F3D87104
-:10257000AE1F7AF319FB8CEB17C89F684CA3F40BC2
-:10258000AE0F203DDD5840E5671B3D94FFD2EDFBCB
-:1025900009E8B460DD9716EC4BF7442B7C0B3856FA
-:1025A0004BBEBB2773D4A37FE578BDE71DBE303893
-:1025B0003C35C19649007B75E6A777417F5EFDAC4F
-:1025C000E641BD65FBBC36078767E121FD6E90796A
-:1025D000F13BED532126EAA0BF72BDE15EAB6F3740
-:1025E000C61BF9E1F1549D57F0EEEB783399D7FF14
-:1025F000BC7134C175B2D14B709D6A9C4C694CB6AC
-:10260000EF55D4F7B22F6DA87FC38E0E4B06AF5F88
-:10261000EED5BC588F57795920C0E1D96415F27DA9
-:102620001397EF589FE38A6F7CE25606F9ABBF81A0
-:10263000F63392AACA93F9F7A9A32B2DA837EB2B4F
-:102640002ED3DC3D7CF8EDEB50E0A34ED2E5CCEB95
-:102650001AE1E9CC9EC2EF5CC1FB7BFDB0999939D0
-:102660005C5D174C0457D79198009456556FD56E02
-:1026700033E993AB326D01E06FD5EEC2FED0A74EC9
-:1026800071BAB1FC9EF14E3DFF6F2E3D4C8E9E4ABD
-:102690000AFEE74790539F0839C5F5CDCF1E871C2A
-:1026A0001B38C003BA9FB572BD1C8866F5B1D8C788
-:1026B00096DBE4FAE27206F95331E21C3CEA858CBF
-:1026C000F1582F18CF65EB9143F92F3C9AFD7D57B8
-:1026D000CF78DB830B3F7A9CE7CF044C7E2BDF6700
-:1026E000CEB0E0D99F438E6E7178703EB847E3F06C
-:1026F000601FDD3A80F2059A25A681F83940EBB5D6
-:102700004073591AB8FCA9FDD96303C04FAF721CBE
-:102710008CE6E5AF6E8825F9F4AAD573B401FD3DCA
-:1027200021FAFBC90FBFF7E95EA40FD4957D0F48CE
-:10273000CE4E227C57FF68C950B4E7FB344BE7FD0F
-:102740003DF7B2168AE6EBB378E3FEBBD2397CC321
-:1027500036779806F0B4748BD684B430F3BAC36677
-:102760005E6ECF76111CC377B8CD19585603021F81
-:102770005D4DFBB7715F2FDAF8E5781C2FD5FE3E73
-:10278000540B7ED18AF370D691329DF0D742FDEC86
-:10279000DE37EDFD9B18E6C13507C05D69F3D07EDD
-:1027A00012F0B782CE67F402CF7D58D33EFF63A00C
-:1027B000EF193DD583FD658FC91F3F06F58F5A6818
-:1027C0009E2F6FF975BC95E713765959342FAF2BAF
-:1027D000ED9C84FA75992E3A87673E79CD64E0675F
-:1027E000F9AEDDADD44FADDDA3619DED3EFF6606D4
-:1027F000CE43D7324F1EF86E97C8DF3FD1EB01BFF3
-:10280000D5B4FE59E4DB7C94F799FD6E0BEA5709C9
-:102810003DE751B98FB1F6129277C4CAAE1E7ADD88
-:10282000CF8B51BEC9ED4FAF77F4EC7F7CDF2ACC64
-:10283000E6E5E936D9DE392DCBF70FEC5B36B90F7B
-:10284000A9FE1EB5317F34EF27937FD7B0AFDAC42E
-:102850007EBB95CB17F08BDA6FF9B857648BF65EB9
-:10286000C8C90CBEB996F2F9643C1A15A03DFD1218
-:10287000C7577AD28A1821CF94FE313BB9E9B57691
-:102880008ED73FC5EBD7607E0BE57ECD2C9E34CC3A
-:10289000EF58BC7732C6AFB57766610E7C3F9C823D
-:1028A000FC7233D79F72C2F427FBA5ED875109DE76
-:1028B0001BD1FE52EB8F8DE95DFE8EED1A4DF2F7C6
-:1028C00035297F57FFD9C44A797EF5C351244F6813
-:1028D0004FEB052FAFF1F5AE73F9F2EFB01BF0F44B
-:1028E000CA3FB59BE9FC71C854FB26DF4F69E86C11
-:1028F000FC5F6753C208CA7B41E6ABFE64EAF57C25
-:10290000A8524EA77ACCCBFB95D1DE70F5574E1B63
-:10291000F5EF48BAA4F99AFB98AF395ECC771FE679
-:10292000CB69B7FACB329297FB2E719E9951DE3567
-:10293000A06FE43C38DCF7E07B24DCDDFCDD79696A
-:1029400070DFA631BF09EBEC4B5B00EB6C1F07138C
-:10295000EB76DF92A200D6F31E9BC8FBE36DA47F4B
-:10296000EE8B637EC88F7D15A901BF1B729009FD98
-:10297000B41F13E5D1B2FD9C546A3F208AF33FCFC8
-:10298000B39B6264FFF56F17A37C4D868743C0F548
-:10299000DBC0BA6CD26FCD64373C22E5F5C6C4D03B
-:1029A0004D66FE7DE397F90CE31C61A18C15A857D9
-:1029B0001343726863A2373D89E371CFD766DA1794
-:1029C0003696F2BC83E434D977365678D313797EC1
-:1029D000AEA4CBC6D6C0D647D05F4581C7CFC719F6
-:1029E0006066F554CF2DFAF9C82ADAFD4ED285AFCC
-:1029F000635AE7EF672F0801CFFAD4580BEC221C7B
-:102A0000E3E91A87FFF1EA3C46F252DABD664B1A57
-:102A1000CCEDE103AF7D14F45AF13767E1D668C815
-:102A2000E31935D164973A5273579C8B8F374337EC
-:102A300087A2A0FF4D2F37D89DDECFF6D2B8FC601D
-:102A400021CF09A12AE0F1F54E3B835CEE8B9E7508
-:102A5000C171C9C7C3F8A1C626E4C709A90FBD1231
-:102A6000A7BF0B7E5FB1F7DAE4E361FA5EF5C2F26D
-:102A70007CB2FB565FDAF9AE09741A46EBD56F02E9
-:102A80007F04A389FE936FB413BDBB1CA6A76197F7
-:102A9000BC45CAAB261C84F9F7A6DD5181BBF8B74B
-:102AA0001551A19990579CFECF6E035D5F8B26FA5E
-:102AB000D7DA043FD5FEBC90F86B8FCDEB5E8BFE72
-:102AC0005F8F22BAD7C6BB12A8FCAD6426F98FF47B
-:102AD00086DA98507E22C7E7BA58FD24F0C6F98EF0
-:102AE000ECC1B536F1FDA8E4ABA3BC0FC0E1AF8FDC
-:102AF000237E6432AF7F3F99CE535C1F25FED51FE6
-:102B00002CA4BC6EF3A62FC4FA58154BF01D95F6F5
-:102B1000B4A3B589C4DFF31E5CF60EE3F43CEADB34
-:102B2000766F3EAF77749FD5837DE9F70DE6908D84
-:102B3000D3F5EC1DC7466DE2F9F6BB3ECED2C3EC31
-:102B400068F3EEAA9B8276F396DE3115FB655FF89B
-:102B50009E571BC5656E0F9D5272BCE61C8E7F4F43
-:102B60008E6ECBE1F35C51D4BE0872EFACADED4993
-:102B70009C0F3E4AD0A3F1FDDC2B9F6F237968E9BF
-:102B8000CC877EBEDCC2F9007C29F7CF15922F5F7F
-:102B9000CCD113509FE38FF4F1D8A23621F7EEB8D1
-:102BA0003439FFC5BEAD7B343ECEB2987DCB2935DE
-:102BB000074AD0CF292D14AFE5007F5C8FE3FD9D40
-:102BC0007686E241075D9E9B966D37CE0B7FB0AB5C
-:102BD0002CC33F78BB654133D955F8FE6E03FCCB5F
-:102BE00060E935F813845CE1FD3C4DEBD0F1FBF975
-:102BF000DFE7F85FFAEC9032E893CB12F7FEF00AC9
-:102C0000AAC7DB293E375F9C57F3B9181E31BFD3E3
-:102C100092CF4F33290767DBBACFE1D083CE3EDFB7
-:102C2000DFC037679F1D42F92FB44E2D86C37556FE
-:102C3000CA23E6098EAAC001C21B1C057DF611F944
-:102C40007D59727014E48F9247CC1E2CA17375418C
-:102C5000B004E74925CF982F984FDF03C17CB4DF3C
-:102C60006312760AFAC3BC9FCB68253CD8C57A5C50
-:102C7000FA5C21E1458D1349BFC8F94ECD11FE0123
-:102C80000EEF2D3E5E7FF0269BA17C48C0989F29C9
-:102C9000EB0F8AA0CB0073E7FE28C8FB6718ADD7FF
-:102CA000C8716FCE11F6F49FFEB49B0E66795E6418
-:102CB0002E457F97D0B7ADC0F7EFBAF17D6B069781
-:102CC000A7CB30C7EC9EF9EF29D53320F7CF9A84F4
-:102CD0009D7A4F22CF1741CF11F8547985C7483ECE
-:102CE000BAEB778B32E04F5997D3EDE7E80F7E6B65
-:102CF00082BCE4F2A2C92AF0F14563CDF0E3169C50
-:102D000047EBD3AB2D3DF359B4A9D48EF5B278730C
-:102D1000A97D41D879A769FBF0C32E4E97D3DB2D4F
-:102D2000643668B2047E083DBA69BB39E867546E00
-:102D3000F7F2FAA71D07DE45BD459B13CBA0F7AA06
-:102D4000F68B37DD965E1D86EFC2ED46FC17078DCC
-:102D500079D8A3C3F33F822E38F21F6F571A32E699
-:102D6000871F36E63FFFE0D69960E397470B7E3F2B
-:102D700011880BC04F55F3F1A4C3D8D74EEC793965
-:102D80001EF459F649F59B38B72CDE64E4334E3710
-:102D90000D7ABD7F9B46FCB12410B9EEE47ABF6882
-:102DA0003DAE5176CD82703E89A4E729169CE9E5B7
-:102DB000FC54DBB06A38FC21355338E372782E0FAF
-:102DC0006EB0C16F10395E5FEB9E39BC2ED8AB2A56
-:102DD000478BB2310DE3D931187DD7FF7A12D65B1C
-:102DE000E5FD1AEDFF952F0D3E04F9DDB173CE75AB
-:102DF00094CE9C4C7850F6B3C5FBB4501CCF3B47E7
-:102E0000BBF6B6F3760B031AED0F0B9AA37AE41018
-:102E1000FF5FF5FA083836869573F817EFDDFF1770
-:102E20008DF75FB3D9D86E09C717E4FED22D7F8F17
-:102E30000AFFAECE7D63F6B59A31EF850A7EFF5567
-:102E40000CF3122E482E3AA4BE721C192EEFA39238
-:102E50007C6DD85FC66C14EDB8C0AAC47CEB1C3680
-:102E600017E65B6767A1580EC7E1389BD7C9BF9FBC
-:102E7000DF1447F6A945515C2F2CA3944597A19DDB
-:102E800087F6E9CFDE3393BE5287B1D1CF531A9D77
-:102E90007FEA606C44FE19915FC242340FF08B37B9
-:102EA0007C7E01639EB5887353AD25B41FF858CA64
-:102EB000DAC5B987D3D11BE68FABE5F33C92047D2D
-:102EC000C8D87E050B52FD157BFF1E15FE3DCC4E6E
-:102ED0004AE73975AE34DB9817FAB1F9CE18DAEF54
-:102EE000B9208E017FAED5BC8FD9CD48C5BCFC1BA7
-:102EF00084FE33B755EC175C3FCD077E366E18E283
-:102F0000819E3297EBD9D1D02396C450BD8D898C48
-:102F1000EC2B1BE7E40B3DFBEB974218A7F3618D0D
-:102F2000EC231B4B45BF1B1F1842E590871A8D13DE
-:102F3000457ACBC60A559E497AD247002D1D7AAEF6
-:102F4000FCDECF45DF0798BDF9D0D7D943D174DE79
-:102F5000577AED33497A7C6EBF9EF92A3D98D55C4D
-:102F60009AFEB755EE779D1B84FFF7B8E67BD31426
-:102F7000A6970ECA15FBC3A8F1DE6DB21EF901AA11
-:102F80004D15F75DCDE1A97EC4E46A72F7E09D7945
-:102F9000BDF998FFF10DD165E0B351E385BDE76858
-:102FA000A990DBB1239837C0D3825CB17F14E49A37
-:102FB0000C695A0CE73FDECFF172611F8E1BE123D3
-:102FC0003B1BD7D9487E47CE638484AFDAE67BEBE0
-:102FD000CA5EE0E9E6838942CF38BE527B5AC0C55B
-:102FE000E9CAF3A37E144DF6B9E3725F51F8E77CAA
-:102FF0003392F66929AF36483ED900FA633F5B2227
-:10300000CE413D7C62E483B99AC02B7B40E8A71B8C
-:1030100013455EF1013FEFB0BF824FCA19E1BDAF6A
-:10302000738F9AE7C65651CEE93D05F48E3CF728DA
-:103030007A334B6024CE8D7DD17BC1E8C4519A890F
-:10304000FCD67EF8ADB1D7115EEEB504EEE2700CA1
-:10305000B408FC675A047F71A9EC8F29A3FA5E1BA0
-:10306000CF573EB4987979FDCA0C46F6205E9F256D
-:10307000A03EEF06712CD82BD0AE3241F45BD99F25
-:10308000D13981FEB8BCCA459A4DFD7A4D49A27D21
-:103090007C19B5F79B447BAF85A78372843EDFB96B
-:1030A000362AF034E4F33D99F9E08329E38D7CF08E
-:1030B000EFB962BF57E9D03C97342A79D2B0BE1736
-:1030C000340FA1FDA229DA57B71B747B5EE8FF9588
-:1030D00077DF7CC348C0F742B207E07D317527F93E
-:1030E0001B1634CFB9ED439C1BB647D3F76BF2F4F4
-:1030F000DB7347420F74CDDFCD3F2C9871D096C65D
-:10310000DBEBC18A333FE7E954FFCE77A10F4C9D3B
-:103110006EA6FA5399B08FB26631CE0DFE2F2D698F
-:10312000BCBF1BC66A1433D011EDCC5AC9E1AF94B1
-:10313000F4BB5BF26F53349BFD3307E0CACCCFE6A0
-:10314000DF6F8086D98BFFEA90AA3F4EDB0CBD660D
-:10315000D004B1BE547DF4837EDF92EB6983C48BCF
-:10316000CA73BC52FDEA75511D39F148ADA1C13C8D
-:10317000EDCC1FFF30F86A4A369BB40978FF9E19E0
-:10318000B10A1CDECE4A5AF771F92EF0A9CE588842
-:10319000E223024388AF3BC67576DCC3F31DAD83E3
-:1031A0003D64F391E7E885385FB9502EE498922F9B
-:1031B000479DED71C4AFF25C5D2559E38F0D131E81
-:1031C000B98CD7AF72D83AB01F2C7C785A3CE24CFD
-:1031D000AA369A453CC77AE3B99A9F7F5F045D227D
-:1031E000CFC991E761F00CF8A87ABD467C38A8C930
-:1031F000634B2739A63931BF6A472817F2BDDA1366
-:10320000ED41F9E9466FF2F15CF8232653CABEE2BC
-:10321000781F057B2CA3208E0379FA3EE0A9B2A586
-:1032200092CE8BB1453AC9A7BFE5BA08CF53604FDC
-:1032300084BCB1B4A7631DD6A9EF49CE7C07F17356
-:1032400034031E3AACCE7CC0D5B136DA847D73CA65
-:103250005D82AFF93AB35B78FB7B2D2C06EBFD3E2C
-:10326000D97EDE1A8BAF95E707DA99252E097C55B2
-:103270004A7C5D3658DF003C9CF8011B8DFDBF6A1F
-:10328000FD068247F105B3B44D4C867EB7D55D7619
-:103290001FEBE1A3B2C1E3DF47BB6E7E98AE111F07
-:1032A000F0747F0EF1C38D47503E657C2877551131
-:1032B000FC58B5CC0B3F421AF3C01ED0C53A499F0B
-:1032C000E8E2FA04E49992274A6E703EF022AE4793
-:1032D000D157C98F6D8D1C248ED7ED8D764A7FDA3C
-:1032E000E864162E037634A651FE854617A5C1C69E
-:1032F00002FAFEB3460FE577358EA6FC9E462FE513
-:10330000F7364EA6F4E78D3EFACEF1427248C91563
-:10331000258F143F29B914C947F3397AAF2AA3F688
-:1033200024F794BCC33C4C653DF248D1375BF3F9BC
-:10333000D3DC9063ED73202FCACDA79F7F197692BF
-:103340001A8727CA05BC08B9D7E5B0939CCFB2B19C
-:10335000BD38AF37ADF476DC13B6AFDE54A3314BD6
-:10336000189FDE5C1FCD2C617C7C4B43A2213FAFBC
-:10337000E1FD37FAF3FEB544DD91C7E1387AE7673E
-:103380004FFC967F7FEACE2FF2406F0EC7D64731B3
-:10339000EE1D31DD702421DF6C25FD61508C380776
-:1033A000E10F7459C0C4FA7CEACEBFD2FAEE688845
-:1033B000729979BD050D5184AF8F40278ED7DF4BB1
-:1033C0003A55AE3DF6FCCB58E777D848CE2D6896F7
-:1033D000EB721DC76798BEF6693A23BD4CF33206FF
-:1033E0003FCCA73FB085F89ECF3ED5EC010DBA0F7C
-:1033F0003F24CDE3DFF575BFA0F82BADE130E9C385
-:103400003AE2B26027F05B0DF1585A838CD36A1F01
-:103410006888A38A1DE1B5413E80A741B70505072D
-:1034200018D6356BD19CD802AAE5F7EA751AE91BC4
-:10343000DDFA429E99E8589F6BA1F45DAC71DA2FDA
-:103440005A687F52FCCAE585378075D1526A5B1491
-:10345000268717C8EF5505264AD5F7FA5C1BF5F302
-:103460002E8403EFF7BE826CDB4292732E1BE48046
-:10347000AABFA0A0ECEEEC11E8675C0A0B5B8FDE44
-:103480003C0BB5AF47A017CE477661FFAFED631F8A
-:10349000507AC909FCF372829FCE5B4B5F78EE05D0
-:1034A000F8C7967E1C45745A3A4CDA238A02A3A6C2
-:1034B000913EE375687C9ECB25FD273EF7497C3B1A
-:1034C0002F5FB14BD82F79DA8174F91D3564D75A43
-:1034D000EEE1EB230972D5E8473EF4C2C7F1ED7483
-:1034E000AEF06720BE906F0B192C0DFEA2639360A7
-:1034F000175FC13AEF465C5764BB15DA57F1C2BE9D
-:103500002FFCE4CA7F59FEDA9F53098EDDE7532171
-:10351000D756BCB63655EF65DE2B22FCD7CA6FAE48
-:10352000EC602BD8FA2FE1778BACB72A4FFAB52F86
-:103530006397919DC2C2288E61955DE0A12B909703
-:10354000C07A19AF7BDC4D5CB0F3736897C595E02A
-:10355000E1709EEB238EEFE53CB13F9F917ED473EB
-:103560003BCCA4179EDB1147FCBF7CC7436F5EC1F9
-:10357000F3CBB7681896D5B136C2D3F25D66660F45
-:103580003FDFC06E93DC379CCB9E8BAB073F2D0992
-:103590006ADEAD45F0CBBB12FA85EB8B929F964568
-:1035A0000547111D24FCF749FD48D55BB2EF211BEF
-:1035B000E8C5EB9D25BDE5C558E8DAFCAFF35DC075
-:1035C000796AF370F2EB2E09EE5C4EFBFE8E582703
-:1035D000A6F885D5688F0AE489F514C813FAC629B8
-:1035E00069FF3DF58299E40FE0C43AFC4213765E30
-:1035F000D56E9B6CB74DE2ED863CB11E55FD25C1E5
-:103600008EF85C5EFFF3BDEF531A94F35AE2682B19
-:10361000C17EF9F9AED8C9014A7F3CE9553EDE9931
-:10362000E0B8142D6C5DBD9627E286CF6C364F0650
-:10363000BE5840C51905693EA776646874AE05BEDC
-:10364000397E4EED7A29DE44EBD62FDA493A9AECF0
-:10365000C29EEAB6B8A4FDC2EE849E31976B75098E
-:103660005CDED5ED12F10091DF557D5A6FE9E0F790
-:103670004E9BE07FE9BF97FE25C489903F3ECE1662
-:10368000C0FE3A7F986BD64D90676F5B053D06BADA
-:103690001EC5B96AFE7BC964AF586575F547FE4F14
-:1036A000EF58C97E3E7FB85CE769ED23619FEC70FF
-:1036B0008B7DBD761D5F217CCA0338FDFD7C7EB508
-:1036C0000113C5531ECBCB26B81EAF31796DE4E78D
-:1036D00008E5C34E79D4C6FC66E8C93F8B26FDAE2B
-:1036E000365BD8DD1F07BFF3B43629949F0C7B9758
-:1036F000A463ED8DBC3C8C9EB54F87F2A1B79CB600
-:10370000093B1ECA9D48CB44BD26C937E807FD7654
-:10371000B89D6749BFDC1DC7A0E79B5E8E13F6848A
-:103720009F4493DF41F57B5EF25593F473F9B70A3A
-:10373000F80017F4E625B6967CE8956ADC25F12DAD
-:1037400034DE6939DE929816E13F907161A84FE34B
-:103750005B9917E7F1CE67A3483FFD22BD6D0FC609
-:10376000FFE2D921E407EF700716EDA572AEB7713D
-:103770003A2CFD695408F09E7C368EFC9C27AD42A5
-:103780000F3A19974A7AD0E1B847E6A3BFAE2D5158
-:103790001AEC292735664B43F9D67EE4AF5ADAD8BE
-:1037A000407E82A57CB9C31FCDD3C9F02B9FDC3AE4
-:1037B00084EC2C277F6926FF22FFBE0EDF75D632F0
-:1037C000FF76ACBBEDB16467FBE2A77F1B12EE7F17
-:1037D00050E9D22D467B92A2BF2A4FC917EB2B2569
-:1037E0005FE0312D5FEC3375B1C147B2699E62BDB8
-:1037F000723AD0798BAF8F54D8A78F065F49D51C0A
-:10380000C07328FFC7C0FB7671AEF9628795FC22B2
-:103810004B5F8EF392FDE69ECB4CD82F969A85FE99
-:10382000BB94B39B48857D68697C3ED98738BEE9E7
-:10383000FCD8B9D52CC711E39EDC9629ECEF219971
-:10384000DF531C009F4F4962B7DC48FACDE612E017
-:10385000F5FC965813F8828FE385DF7EE9EDDF17DC
-:10386000F84C5844FA38431CF428F8CB85BCACBB60
-:10387000E78A04C4C3B0F7CC0CA2EFBCC5D31FF2D7
-:1038800030125F8BF3A5BCDCF3840DFEB35ABE5E31
-:10389000101FB44CFA4D97FD54237D6ED9DD573C73
-:1038A0004A72F05D2BCBE3709C0E3E141F4E8F0AC4
-:1038B000D94F4F7B0FD55FC6EB8BF66FC7133CDB41
-:1038C000AC1EC01349C74B6EFF53F325B5EFE68F0F
-:1038D00020DFD74B2E9EF779D6F6DD8F2147764431
-:1038E0007BFCF435487EE753D6E022CCFBD4F3D101
-:1038F000245F4E258AF5FE3997877E1BE0B8FE418E
-:10390000B26FFC661A83E85E1C30F6ABC69D992F39
-:10391000E46F5DB22701FE8C3A4E07F4C7E9F21D51
-:103920006AFF9E95DA47CE63A46CD7BD3E9F8F2574
-:103930007E393540D0E3D40B83695FE948147CCEEF
-:10394000E1CDC239E554A2487153067CB0549E4380
-:103950004F8D0BD2B9FB94B693D20EAB68B7B4417E
-:10396000FA6D39DFA5816FC093F05BD9D7B7418F6E
-:10397000807D7A5419A5A1A8A48BEDCCE04FEC432F
-:103980002FE40B7B16D41AC875F26F907E12B441E7
-:103990001EEB528FABDD71B1BF8CFCA03B34F2FB50
-:1039A0003C20D729A04E51F671CE8FCBFC9A17F14F
-:1039B00046CB9A572E01BF2FABDF7013F85DCD6356
-:1039C00099854DC6F9AA4333133C1DD17CDD000F08
-:1039D000E1E365F7E07793821720A7929E49CAF545
-:1039E000E67CB15F21DFC2FBAB6DD6D6D3386E75F6
-:1039F0009E14F35378E268B1C14EC6CFF9A2BC8FD2
-:103A0000F92B3823E7AFE009E60BFB4487DBF5E051
-:103A100058D0FB5766B29F9EFF6A7842D237E8655E
-:103A200038B175DB8B39FCAFF1BD1AFDF821DFB081
-:103A30009E618FE670E66F36FA3F0AB618F3437759
-:103A400018F345BB8CF9927DC6BCE79031BF558E0B
-:103A5000ABF084732EE2DA70CE458A73AE2B5F9C96
-:103A60007391C7391729CEB9F88E732EF238E72231
-:103A70008F732EF238E722C53917DFCF4AF95D2B55
-:103A8000ED8EA003C557BD12ADFCE0B45ECECD49AE
-:103A900025F9A9FC99E7961451BEDB9E5361277B5B
-:103AA0008E8AD3B929413F924F7EC3B6BBD34137EB
-:103AB0004B3BD97157FC5CD8716BCBA21DB02FB4B6
-:103AC000AFFDFC6EA84F2509FA27F914D7D4B94DDC
-:103AD000C42B85486EB4AF71BD77B5A01FD93954DA
-:103AE000DC4D25F6BBA4BEE918E94761EB8D7E935A
-:103AF000483F4AA4FF24920F94DFE4296B673AE41D
-:103B0000FDB167EDEB01FF31691F63B39DA47F2910
-:103B1000BDBA5BFF7A407B1AFBF6D7F949D4BEEBFE
-:103B200030D7B77BD96F555A75A18CF4C6EEFC7AA5
-:103B3000CD44712369F1B40FAD963065699D1DF7D1
-:103B400040DEC599681F3FEF30D1B9E0FC0766D26F
-:103B50002306433F0F9BCF90408C81BF0AB7274578
-:103B6000F8FF0618EA0FDB9B1DE1FF1B6AF44B4DC3
-:103B70005FB31FE7EB69EB871BEA55FBAE88C0A379
-:103B8000845BEAA54D776CCA82FC591DD745F0AF1E
-:103B9000DE1D4D71B5D51C5E2FFC72C87014D4D8D3
-:103BA000BD5381BF9AA03511FB7C95DC7F58837192
-:103BB0003FAEB130BF33A987EF6A9CCC9BC8DB9F77
-:103BC000296DD966E2743B63DAFCC85817FC4AAD2C
-:103BD000594ECE57B76AC1D4CB797F7FB3E84583BE
-:103BE00039BF6559433F9C0779B93387ADE1F58EFD
-:103BF000AD7F299EF46EC9675956670CE8DDDA621D
-:103C0000A67301EC52E6A41E7E686D498EC975F458
-:103C1000CCB387FE5FD1FC385D3CB8A7D8E538301F
-:103C20007035F4B8A0986FCD38CD4F7AB29CCF2ABA
-:103C3000B9AFB05CD1CFAD327F5C9E17D4FC4E0FD4
-:103C4000D95FE2821FB3716F961972DCB4631BEE09
-:103C50000FDC19A35F337824E225F37E3B968FBBFC
-:103C6000F44311AFFBC78D13E22F87FEF9BCD533A8
-:103C700085E7EF6979C68673F1524BC0867367CDCD
-:103C8000B3AD362F4FAFD9DE4ADF176DAFA4F3F6D1
-:103C900062564FE7C8132AFE56E2A366BCB6D9C9DE
-:103CA000E17E61B0901B3531226EA3DC3CF60DC481
-:103CB000A59FDFAE9562BED37D3B6D95B03FCB7ABD
-:103CC00091EBA3EB9D69E5FD604F0A0ABF675FEBCF
-:103CD0006146A880D6C3B40B2E4AA75F184AE7D81E
-:103CE0000F99AF98E44451C479F61D1187DCB54FA4
-:103CF000AC831A5B28651AD6C9EB565A27755C7EC9
-:103D00008D2EC33999B1313CF58D351BF875C5C47D
-:103D100058033FCF6649063FF24C5CDA0CCB4F9F0D
-:103D20009263A83F6B7A6104FF97F594931C196323
-:103D30008833A9BBC3EFD2289E65BCF13B4FEF206F
-:103D40003EBBCED0BE8EDDD8530FE7E02DBF263C64
-:103D500033D666C379ABC624E26A66EB1DF27B3BC1
-:103D60007DE71331ACC341399EDF8A7DD14A767934
-:103D700065979E8D7FE7F4B62F7242CB71111F0AB3
-:103D8000FB8221BE900340E74F26E85027ED3D75AA
-:103D900005C2DE53E76FB321FE96E3DF92C151B255
-:103DA000BC45237B1EAF6FCF4812F93BF07D97F1E6
-:103DB000BE01FABB80F2C3E64AAC97C8F2E57CDEEE
-:103DC000D03396C34E033B93EA5FF6ABF873F1260C
-:103DD000A3DD6839EC396174FC72B08BF874E9F6D4
-:103DE0009D6F0EE07899E64B2CC5FAA90D56582B1D
-:103DF0008B2EE63325DFCFD798C8CFDDF5CE41E255
-:103E0000B3AE1A0BF1F3B7E163B957D83323F96FA7
-:103E1000119F0FFCB28B76699E8026EA012F03C0AA
-:103E2000971178C9E8055F0A4FDD788B285F8C7F92
-:103E30008C40DC801608B97BC38BC4A3EA3F024FD9
-:103E40006CB4110F8B74D77B90378B0E9B59E0129B
-:103E5000E6BD18F3C3F87C7E18FFC60BC24EA2FC69
-:103E600006332F5828DFCD273E113F3D7D8A715DF7
-:103E700076F38D4FAC93191752A9DDFF36FF7C1BEB
-:103E8000DF28B823E393D5FD9EFF1A2CED8423D9B8
-:103E9000485AFF971837ACF67B85E741778EA678AE
-:103EA000A22E4736E90FDDFB8DD358BE2A2E9BE2AA
-:103EB0008875699F53725797F5D43895BCDC351CCB
-:103EC0007C3C301576D7BB9B73B2DAC3F4127DAD60
-:103ED00095ECA6596B9229AD8C76A662BFA85C635F
-:103EE000F6611FFCF4DEFEA9A361875F6B4D99C2EA
-:103EF000BBFEF47B23B25831F2E5941EDB10353B58
-:103F0000DC9EAD525781D80FEAEE3C42FBD719D365
-:103F10003BF1B3B1CED6EE8E4748CDB2B5EF8F723E
-:103F200072D5A3D5A20F2A401CA1D6BACD09BC399F
-:103F30005B4B608F1E06DAF5EBD11396AE2DEF0FBB
-:103F4000FB57EDD7079FC4FEAEAFB1A642CF3CF9F9
-:103F500001DFFF34DABF483F3881F8E314F8AD627F
-:103F6000E97EDB098D79E1BF5962DE5FE234ECA7BF
-:103F7000FB66028E5762F46105E4A70D6C4BC3F833
-:103F80001E3FC54BEA6BF2127AB397A874C526A1FF
-:103F9000BF6D53F65A69D785DE8E3CF4763885A01E
-:103FA000B7230FBD1D29F4767CAF90F6FA414D9DE5
-:103FB000A53877FAC7B3827ADA5F1D05D0CB576B85
-:103FC000311EC89BD59AA73FEC606C4BBAD85723DB
-:103FD000E8ABD22B3BB96E15C6EF575FB0B3F0F824
-:103FE000B1712CD1909F604F37D42F77BA0DE5D7A0
-:103FF000A40D31945FEB2A35E4AF2FB8DC50FF06F7
-:10400000CF3843FE3BA3AF35D4AFF05618F2D326DA
-:10401000CF31D49FE1AB3494CF9ABDC4503E475FBB
-:1040200069C8DF54F33D43FD9BEBD718CABDCC698B
-:10403000C1FEB60FE7298EF7D7719EE2E9EA5FE588
-:1040400039C2E93A7682A9BE377BFC7725FF6E1A22
-:10405000E25D09FECC94F74032E57D8EE60217F171
-:104060006706EEEDD379B62D1D7C13592FB27C6C0B
-:10407000EC81F32E4EC33F6C9F39DDC2E5C3D8CB34
-:104080000E0CCFE1F9A421F74FB770B932F68A03CD
-:104090002F65F3FC80216F88F26107CEA3FCFE211F
-:1040A0000F8AFC3446AA45F690F1D3FD7C1E63AF1F
-:1040B000CE5EEF11F6905EE32D550A3C206E11782E
-:1040C000401AE2FC89F400E74FA487387F56E732B4
-:1040D000F626E74FA487F9B912DFDFE2E74AA4EF3B
-:1040E000F07325D277F9B912691B3F5722FD4DE3D2
-:1040F0006C4A3F68D4A9DD7F34D6507AA4B19EBE05
-:104100007FD4D840E9EF1BFDF43D50A0EC0721B26D
-:10411000B3287FD272F8F16087DB6B3D1DEE6755E7
-:10412000FE40E5FF6BAA67EDB158A7ED96C4CFEC52
-:104130003D7EBDBEE5AC857D16A66FB5C67A9F2BCC
-:10414000203BC94027C96BF97DBC362DB38CA77FB6
-:1041500071E93B41EF1965556B13DCB807526F05E8
-:10416000BF7C68EAFD5E707381B03FAC1AE2DD434C
-:104170007C22FDD8CA8FDC1D9F12E6E73685C5C5B7
-:10418000D05F587C8BF237AB789AABEC223E4FF97C
-:104190009355DC8CEAAFFC02237977E53A0BE927EB
-:1041A00071161642FF2A3EE64A7BB014F10257D63A
-:1041B0003A280EAD3FFF6E2BA37A5E334FB7FC99C2
-:1041C000D72FE9F15FF797F0F37282BFFC824E764A
-:1041D000D72BA5FF1EEDEDA2DC8FF6889D829EC138
-:1041E00053B2AB3D8138A7B21E7F3AEAC78AFA21A3
-:1041F000F497FB9F7CBCF89EF59399142C453C5595
-:10420000E67207C5536D1E17A2FB5B2BDCFAA7A055
-:10421000932FCAF9492CAD9F9C4CD8092AA4DEFBE8
-:104220000D74F81CED147E149E155D147EC3E28E91
-:1042300008AF7DD129923E917451F428BFD0836795
-:10424000E0E9623AF4D009F6D8FF2B74186109D27C
-:10425000FDBFA85ABB07707D1B5D6EE96493709F1C
-:104260007870B6DE0C3C575E70BD897C151B370933
-:104270005B932AF77C4BF92C94F7EBBBFCB63ECA58
-:10428000DF8E56F1085E4729A7CB04293F56970BCE
-:10429000FC4E769B09BF138A16933ECA1C42AF732D
-:1042A000F1FF204F267DE56B467F93528CFAA1F2F9
-:1042B000075F27FB9B1CE107BE4EEA8DD745E885CB
-:1042C000A38648BDCFCDDCE2DC27EEB94F94FB746A
-:1042D00086A4730E3FCC8F051D996E81D03A847BE6
-:1042E000EE25B807EEA7FCB52C40E9F52C44FBD62B
-:1042F0000D5CC021FF1DC6289EF160ECD4792B789F
-:104300007F13864FC8C5F7B07B7DD70CE947F7FA16
-:10431000FEE00CBBD77760A28BF48603F61CD26359
-:10432000B00EAC6176B45F72B98F5086837C5F400B
-:10433000FA06DF17723993FF82EF0BC85F57B0861A
-:10434000A1DD249731DE44B5BFDE399E5986F72DB5
-:1043500077AF2F796520EC2B6F270E9E08BBF3DB20
-:1043600089974DC47CDF4EEC6F1269948DD2E29731
-:10437000737BD3B3141FF68C378959922FC6AFC203
-:1043800067241E157EFF097CAEEC0D9FCDC001ECAD
-:104390007AF6F7E3D3B2E1FF12EBBFEEE5E2FE807F
-:1043A000FF2440435CB25DE025D2BEF379231B08B5
-:1043B000FCB22D09F4FD36C94357368CA1FA5735A6
-:1043C0008CA6F95D11A3DF35848F73BA2C94CF3599
-:1043D00007F6F9E626BA7F7BE605B307FA77ADD98B
-:1043E000B5DE83B5FEB6B82FC7BE3A98057F1BDB96
-:1043F000D27BDC6EAD5DE1CD4FF8F4667B9BC5FEF4
-:1044000027EE11ABFD776094887755F759FBDA8F6B
-:1044100047C508B932304AC8414527DE8EF219BC7B
-:104420009F515C6E643C1843FAF78824EF63C0A781
-:104430003A4723BE09FBD455A1C204E427E33CC993
-:10444000F36FC9FB696F0DAD4FC9E6F83E68D39FA6
-:10445000413B66FECA8C75DD94A7D13DF7AEC339EA
-:1044600029C0F756B5EE4A5849F87B034A3FEE1E7D
-:104470002FC54C7EF155F08FA6E0DC64277BD1552B
-:104480002C9FFCA613E5F8E5BFACA27710D4BD8F36
-:10449000A83493F1FD1C578CE13D98D88224433E0B
-:1044A000CE33C0503F6174B6A13CD13BD4509E3C4A
-:1044B000B9CC90EFE71B63A8DF7FF678E3BB6EFA19
-:1044C0007586FA1935371AF24A7E65884F2CB37E05
-:1044D000AEA1FDA0860586FA6EFF52E3FB367E6F25
-:1044E0005B412AE49EF8CB59B7CA50FEE37871AF1E
-:1044F00061B26311BD5791D772BB717C49A78C041F
-:104500004127E612F2D5CFFF03DF94A719E5ED04AA
-:10451000A7F1BCCDF5410DFB7B46BDC5F0FDD3FF3A
-:10452000219D23F1D2C5B7A610EA431FE2F9ABF4EF
-:10453000A10FC2AE3131C5EA0930614F0F9F17ECB0
-:10454000E9E178803D3D3C0F7BBAF15D2823DD61D8
-:104550004F0F2F1F7ED848F7916D46BA5F76C4483B
-:1045600077C58F91F4B9BCDDC80F91F4B9E244046A
-:104570007F487ACCE6FFFD5DDC93267A4D7268ECCD
-:1045800071F73F4F9FD4A19C3E853DF4F9EF0C3D60
-:104590007D683FDC4F3F9F6503BD3AC57B7D2BA502
-:1045A000FC54F184FCBC2BEED3DD6E26FFFE515390
-:1045B0000BBD9774C0A9BBD1FE96A27A0DFE8334C1
-:1045C000E6DBB988C337FFDFA3C89F307F90B8D739
-:1045D000C98ADA29CE5EC9B9F919228E65C850791F
-:1045E000BEF0887896A2A1422F8CF33829EEB5B29E
-:1045F00048DC23E0C782ACF9C5E09F77A2F16E6189
-:10460000D74661BF6FB78AFBA57ECE47F08B414F7F
-:10461000841E9729F5A8A6DFD9ED807FF02666D8FD
-:10462000178704EC86B8CBC2ED4E43BE389866A817
-:104630003F6CAFCB505E1A2A30940F3FEC31E44709
-:10464000B68D36D4BFEC88D790BFBC7DB2A1FE1525
-:10465000277C867C06EB7C0CF81DA489F368F5505A
-:1046600011C7C3D710F993E6DF9328EE0FCA73AAD8
-:10467000D283553CAE2EF92E529F1E64D329BEB76D
-:10468000299D79E81E805D9E4F9851CFD6653CAD3F
-:10469000D24799DF184FABE268BBF571A97F2B7D3C
-:1046A000382C8ED61B1E473B5FDEF38DDCF7EA25E8
-:1046B000DD23E11F6413F36DFA9E8DEE2D28B822E1
-:1046C000E1F99B8CEFDC6AEFFDFEC89D4385BFFDE1
-:1046D0009739BEEF825F9F84F8C8E96D3C4FBB9F5E
-:1046E000F357D30F6C9EBB5CDF3EDEFC61623EF392
-:1046F0004CA65B2A8A286E69F6CFC2C6FFA11C773A
-:104700007591D6EBFCE62788B822966073817FFB13
-:104710001E4FE033CDC69AE99E8B8C3BBF797DF06E
-:104720000198C8E7D95AACE2FDB28015FC30653C6F
-:10473000D79F4A61B7FAFA2107D7339E6CB0901D14
-:10474000E2E1A137CCF0E7F6DC2318C4CF17E00F85
-:10475000E82A3897D88B44DCEC9EA162FD979BBF7A
-:10476000EA8EFF267B3A63527E8B734B2FFC467C8E
-:10477000A8E6F1AF8E038FC4933A1732B9EFE44A3B
-:10478000B814FEBACFF1127F2A1EDFB5D2EA7BDA67
-:104790004171FD9311CFA4E837B048F0E589A182BB
-:1047A000DEA80779D457BD72735102ECB55DCC9584
-:1047B000E0FC067BE4BF0A2F0AFF7DDDEFE94B3EFC
-:1047C0005C2417FAB8EFD3177FD2DF3F70EF274C86
-:1047D0003E88F812498F40AE89FCB9F7C419D771E9
-:1047E000FF4281DF7D6ABFF0F3F3A4514E30D897CA
-:1047F0009BD69AA59C10FB2AF40D7C5FB8D64AFA8A
-:10480000066B10F1C835521633E64B1D3302FE58C5
-:104810002BBD67759597913EB2C0610BB4F2FA95C6
-:10482000FEC87DD54BEDC95FE3C2BB259EBB617F52
-:10483000AF5A67ACB7D821DEF55A18712E5D2CCF70
-:10484000A58B23CEA5D185725FF6300FE94DD2FF3F
-:10485000ACE0ECE6AB400EC505E39C6A16F6128AA6
-:1048600057EAB6E3C3BF10F68E26C7674C01F6EDD4
-:10487000664BAF7164DDF8ECC34F7E1A7E7217D6BB
-:104880007F17DDFFE9DA152DFC68CA7F21EB9FF663
-:104890009FA772D4476F674ADB4AE047EAF677443E
-:1048A000F84DBA1CA6F8D1E86F87787F41C5012C76
-:1048B000FD6BA0C419E6E7D4DB4D86B88BC8545F06
-:1048C000B39BE2025A2D7A59219FC7298BC78EF7D5
-:1048D00022EF751C48C57DED29D25E13096FB71E06
-:1048E0003A56137E42BFD043BB266BA48772B9C829
-:1048F000B08E943FBB828552902AFF81BE6E34E118
-:1049000059F90F2A43A309CE194D8BAD78B2AFFDEB
-:10491000B13BCA635C3D7E85F64C118FD2977F61B7
-:10492000DA050FF537FDC218EAA7A2D02DEE7135D2
-:104930003FB0127C34743BB3629EED11F1D82ADD96
-:104940005F28ECDF470B95DC96712E6B34A1676B0B
-:104950004CC5BD90DC56F9F32D325F2EF2ABD78AF1
-:104960007CBB7CC7689BB437609E48311F9C8B77AB
-:10497000487B04E68114F3C077C829E421A7908717
-:104980009C421E720A29E414BE2F60BEAC52B3F0E2
-:10499000834C0C5B37F0834C0CD383E00709CFC307
-:1049A0000F125E1F7E90F072F841C2CBE10709CF73
-:1049B000C30F125E1F7E90F03C1B7D6D4F1E72CDAB
-:1049C0005B61C84FE3FAF8C4B0750B3F4878FFF05D
-:1049D0008318FAD3571ADADFC41A0CEDE10709AFCE
-:1049E0007F4B8366F093DC22EFA5576D4A22FE9839
-:1049F000E3F6FDB090D3F70FB15FDF66C539CDBCEC
-:104A00006F099D9FEA623C82CE2D9305DD4D4CD00F
-:104A1000B9730ED1F90E9BC8978BB8D8DEFC0D1375
-:104A20007385BF0129FC0D48E16F400A7F03DEC397
-:104A300086BF0129FC0DF80E7F0352F81B90C2DFE0
-:104A40008014FE06A4F0372085BF01EDE06F400A18
-:104A50007F03BEC3DF8014FE067C3F0ABF476E0F94
-:104A60005CD0DB730DE73BCE8786F39DD39087DE6A
-:104A70001E5E1F7A7B7839F4F6F072E8EDE179E892
-:104A8000EDE1F5A1B787E7DB86BA685D427F0F6F7E
-:104A900007FD3D3C5FDCE27F0336A61B369F3D846D
-:104AA000B43D4E7B52E3A2E0BDE78ECD80DFA83D52
-:104AB0005ACB4AE44BDEAA9D9C3191EB67BA8C2F0E
-:104AC0002B619DF4BEB32EDFADD1438CE2618BFF31
-:104AD0009226E482BA37843F4EF7D25D8CCE011520
-:104AE000723F55ED3DCC6926B925EBF7E47BAF1756
-:104AF00039BEAA47F2320C0E7E402C451C44E91DFB
-:104B00008E32C4716F3369220EF22E11871AC95783
-:104B1000E6222197B699761E88415C4BA546EFC5E3
-:104B2000E75BD861BCE35DDC525F067DE15461A2C6
-:104B30009C57FD18C4C528B8951D90CB09BA5735A8
-:104B4000B693D9AA8BF09E18B32D847CB7093D018A
-:104B5000ED707E2CF46BDEA7C3F8FBCF85627FD3AC
-:104B6000FD2BC754F3EF853BEAC7E0BED69418D1BE
-:104B7000EE274FC5131EA7366B4FE35EDCD81DCC66
-:104B80008BFB975F4B795AB8C369ABA6719D74CF05
-:104B90004BF55BB9398BEEA555B2F6896964CBD775
-:104BA000E81D7385373EBF43981F17F187ADA48F6B
-:104BB0008AFB2231F2BE88BA27E2B6F8424347F6B2
-:104BC000DC17B972446239E2B5D83EF1EEDE0D234E
-:104BD0002AD7F6E3FDEB01F1EEDE957FAA7F83F2A3
-:104BE0005BC4BB7BC406A3681CDAD706FB357AEF2F
-:104BF00061AABFD594E2C2FDD135D654D4DFC13C01
-:104C0000507F0633710F52C157C4DA4C78779C6FCE
-:104C1000310793C3F8884B80E9A07BA9C74AEF41CD
-:104C200054589C56C88DC87DFCE278BA083D2122B4
-:104C30001EA2E98E2359E66CD87B4C9E10E4D6EE7A
-:104C400058D21794BE5329E3A0CE37BF41EF59572E
-:104C5000EE14FA81CEE500E49F8A8FA8CB0964990F
-:104C6000A02F0C682D49328BFDBF08F791FC2FCD8A
-:104C70001CEDC23DC637285EBF72EDC804715F47A8
-:104C8000F81FAA259EAA65FC0B2B72A642EF54EFD3
-:104C900098969BC726D07DB716A1CF29FB4BE5AFD1
-:104CA00086BF093A573E21DF03595749F78022E36F
-:104CB00050947EA8DE3B59D26CA5F89625117AE077
-:104CC00032A9072E8BD003AF2B8AD003D5FB74B249
-:104CD0004EE5AF0ECE203DA55EBCC7376F8DD05BD5
-:104CE000D84EF18EFDBC35134C78B762DE6EAF47FF
-:104CF000EB853FDE93FACB140C9A8C389F0194CE4F
-:104D0000BC9046E9AC0B052407701703F46F7F8550
-:104D1000913EFDBED4576620CE0FF7E3FC51329E84
-:104D20008F91BE54CA9CE5901B43BDDA4198AFA752
-:104D300058F5B588239CD2CAE83ECC0DD06B78C11B
-:104D40006CE839C3C1E7EE72BA173059A3FB1537C7
-:104D50008C5829F99AF339039FFB25DFFA28DFBD28
-:104D60001F48FED6FD1D167A97D5AFD9F02E9B2E83
-:104D7000CFB38A7F23F97CBEFCBD09E61076A66E10
-:104D80003B1480A5C755AE9A097D713E6C7703240C
-:104D900021398AE28A447973D155339B71B8F91F5E
-:104DA000DA27E6A9DF61E07A16E4E9CDB796DA16EC
-:104DB00084C9958A92F1CF14F7EBA1FB82EE7B6355
-:104DC00045FDA1FFAFBA37AFFF37DD5FACE278C674
-:104DD000FA989FD07E1B5EC6DD52C4BC1347E33DEC
-:104DE00066354F1642BCDA5C99FF75D1E2FF585721
-:104DF00044F8A17C60C794997E5A2F425EDD047905
-:104E000065869CD29F2CC2FD0E7BFB24D023B6A8C6
-:104E100053DE8797FB51843DE2D745820E91768918
-:104E2000AA2221C799C5957513DD5375915D4FC1B0
-:104E3000FFA9D5786F50A5BF54FB48E3BF26DEFE1F
-:104E4000CB54FDE7901F8F98C4FDED01E61626EDCB
-:104E500043E27732E4FA61F23D831EFA73A901FA64
-:104E6000DFAB39C3E9AFAFD3C4BDE93EEC38ACA08A
-:104E7000F3B1ADB0E3358ADFE7782A5FF0D153B7FD
-:104E8000DB48FF9E676B7B03EF34293C7EDCF0231D
-:104E9000ABF89D97501EDE9F9A5B1F4DEFBD569459
-:104EA000F8DA4097D8220FD1E319C494F2FAED4E04
-:104EB000DFFB984FDDFAFD4FE2FEF88A7D6EBAD730
-:104EC00058B9B7F46EBC6B5151A21F4179A5C369A3
-:104ED000C3FEBDBC3991F6B3F9FDE5FD42D6497E6E
-:104EE0002A85FFCE2261C7DA5622FA3F27CF21104A
-:104EF0009415867A32AE38629D28FB60A49D21F21B
-:104F00003D81BED68FB227C07E600BB32F2AFB84B3
-:104F1000B5E0D339D83FE7D98CF7E154EA2E96E7CC
-:104F20005C790E5CD8BD7F154DEA0F7D798346BF55
-:104F30005B53ED70CDBA9CE7AB0F5B1129C8A6247B
-:104F4000B9C43B12F78A772416F0F50A79334FC6B5
-:104F50000D556F1A4DEBAD3AC0D3E4BED7E54D1BEE
-:104F60000E66BE02FE0979E99E78B5D36B4B0A5BEB
-:104F7000F7552D9AE19EB9CA27160B7BDC3C3C61A4
-:104F80005E0679E1B6E12D97795CAD401C9ABBD8FD
-:104F900065F0BBF27A14C730259BBD29DEF1E170C4
-:104FA000BBC5786561FD2F6831DE97E7F5C5BB1499
-:104FB000C571D45FA593CF1BF60FA793E0E47820CB
-:104FC0003C753EC0FB73D138448FAA50C08AF3F6BB
-:104FD0003CC44FF0FC5C67C08A7116348B772BF4AD
-:104FE000F5621C7D5DA2AD18FA92C569CB04FEE4A2
-:104FF000BBF61C3E9283D51C2FB8FFA3EE0146E200
-:10500000A752C25BDD9268D4C35A3658418F397DAE
-:10501000DC9FBF41D27D41F338BAFF5C6DF1527C19
-:10502000BD2EF1FBC795D1F7C13F3067E3A35637DB
-:10503000CF5F592CF8F70689D729D9A13C7A9F660A
-:1050400065B40770CE71B6D0FCBAF1FB30C7878665
-:1050500077507C845FCE177EC491556F34D2B307EE
-:105060001E81DFEA8D95B4DE1659749B331C8E4D7C
-:10507000FBF370AF670E5FDF7877873975BA6FF330
-:10508000D9C3B3B2689E1C4EE035CEE39A84F7666E
-:10509000389F101F2B7E51F783D5780B8BC53DC1F0
-:1050A00085C5BDDBD77BD6A597F49B264E5FD8BDC3
-:1050B000FB5A97365C34E2E3DAAAC53B6091EB54C5
-:1050C000AD4FB52ED53A55EBF749AB2F94A6F5C8A1
-:1050D00019BEDFD6FFAC173C3D23E19D2BE9CAF199
-:1050E0007A28FC5ED1FA62218FE6651BD73BFA4332
-:1050F000BFB7ABF2F1A13CDC0354F5D5B8F3E4EF54
-:105100007481EFC16FB74BBAA3FE2AAA6FBC1F51BF
-:10511000D52D2F76AC4D85BCD8A991BEBBEA818335
-:1051200099FF063DF679A1C79EAADDBA3C1D76031C
-:105130004B202BFC7DA6EA90900F0BB9FE0379B1B2
-:1051400048EED3D7E4E9F7168F0CABF7D0F3F9BAF2
-:10515000902F21C897DF3FFFEA87635C3DFBA78262
-:105160007FC1BA5F5B2B1DE1F8127C7E5F4117DDCA
-:10517000FBAA72D85C88B3AD6AAE2479CBD2F87939
-:10518000420B8B938AE083CA668DDECDAA6A18151E
-:1051900030FF2FCAE5AAF515F4368FA2937A7F4324
-:1051A000EDA70AFE1D12FEB9928F5F94EB6F6E8D14
-:1051B000DBB688D6BDDB5605FE97E573AA8DDFBB4F
-:1051C000E9D4ED672EBA3B4DDE63A173C97AABB06B
-:1051D000EFED88237DF5D4AA97DF9DC9EB7DF148DB
-:1051E0006B16F41305C76269C75B28ED718BA4DEEB
-:1051F000CAE9F47A71989C5DFC94A053D50BBFFA70
-:1052000004EF43CDCB96F2EC0171BF7C417027D106
-:105210006DCEBA0D5637AFF76EB1DB20A7ABEA4BB8
-:105220009DB04FCF5DD76A851C78B758E02D92DFCF
-:10523000E7C9B8548557EC3B5A98FF42D587FCDB49
-:10524000C9C7B97565743CE232D438FF25F9B8AAEC
-:105250003E3109E355D557FE10E71E25EF23D7DD74
-:10526000B168B11E16F0FEB02E8F8DF3D03DDB7904
-:10527000F2F7A522EB9F9574FBB155BC2398111B47
-:105280007C96E20A56C478201F7273DB031817FC61
-:105290000CB86D26F1EE606E6DFB978083ABC51484
-:1052A0009F8214EF1D414D4EE5F9A74DE23E10627D
-:1052B0004B90A694087E80690AE52CA59DDE3F0BE5
-:1052C0008BCF34F0AB8D6D5987F7576C298C7EEFFF
-:1052D00045F1A7EA47F1A7E2DFBEE6E728B9B4F94E
-:1052E0001D734B3B4481270BF728E63F3898DEE7D8
-:1052F000FFB679DAE43B78DDF38D12BF5B70D17CC9
-:1053000073C5B9A5EFF96E2C4FED65BE91F354EB63
-:1053100044C55E77FB155A845FE198C6F72FDEEE31
-:10532000D8CA688AFB52F35276EF4B8D97F79424D4
-:10533000493B427B1CF4C879F2F7205848E4F1BDA0
-:1053400022ECBBDAF7D5BB614A3E1FAF97FB226B5D
-:105350007F00EB9935E4D03B19475B8EC5E1FD8EAC
-:1053600063E3047CAADDAD5671EF95C5D95C783F47
-:10537000919FAFE8771F1636F7A773E4CD0D392458
-:10538000176EF6270ABB83D4EF174939187B6BE5F4
-:10539000DD97A1FE26B753E3E32C74783EDB44EDA2
-:1053A0000B3DD007633756D8B249EF15E700E50744
-:1053B000BA55633EBACF043989F565DA9F8B7D67AC
-:1053C000F126710E986262EBE02F1CD4E49B940EE0
-:1053D00039F1987837926D36BEAB7420CF777D095E
-:1053E000F016F11ED9ADD6A0B73FE438D7376067C5
-:1053F0005AE8F091DEFE969493473776D0FBE40AA4
-:10540000AF17DD53B1897BA99D7126B2BF5DEA7DDF
-:10541000956AE94F527CA3FC518FE3FF2E079E4C07
-:10542000B4AF959BE7D1BB3E776F9C4069F586F2A0
-:1054300047FCC5B80FEB4B1D43705BC93E565D374B
-:1054400041DC1F7D3A2A11E79B2CAB3F2B5C2FAD33
-:105450006EBD87EEA99C688DA67B2A139D1513133C
-:1054600053E8BD5DBAF7A5EA7D5FAECBA575130C19
-:10547000F74C16F23E1107FBE7602CC595AAFB23FB
-:1054800077C6E8DF2DE927EE915CEE12F747D2A947
-:10549000BEAB577BB84A3F6B14F711C2EEC54C9DAB
-:1054A000C3DBD7D6BD148F7E963DFCFE288E19D85F
-:1054B0009FEE02DDBAEFC56C12F7629A705E821E33
-:1054C00099E49B3907F8FFA599F0DFD77835F851B3
-:1054D00092B073C4CD8104D25BF510B3C19FAC3BD5
-:1054E00019E9C527CCAC017A80D25FD4F747245E96
-:1054F0004E24B464813F966C7B340BFBCBC938914E
-:105500009FB76DD65B9057FA9628A19F5B18E9C3A9
-:10551000557EA15FB39A24F52E66F47CF8634B6246
-:10552000C53B3CF2FE8C824BBDB77AD222DE8BC1EA
-:10553000BD18F0FBC796D042D0F763AEBFE21CFBAC
-:105540007D29C73E6E31D3EF8EF8F942811EF2718C
-:10555000CB4B71B89FABF4B572F3EFBD788F66D5C6
-:105560006E714F15EF9AD39B95D20EB25CDA41560D
-:10557000BD629D84DF1DE1FA177DA9B5846CBDD1A4
-:105580006FA9D4AFBAF3BB76D2B9AD7687D01F6A14
-:10559000831DA43F287D44DD8B5BB6A383F409D52E
-:1055A0006EF92E8197BA5DE27B25E2D6E5EF856A3A
-:1055B000B9384F6B94FFA468C1AC3596F07C25E5F3
-:1055C0003F2952F6914ED207EF2BF80D9DC3EB9A6F
-:1055D00065BF3C6F0D1BEF0D30693FF13DC781F694
-:1055E00062DF57E575BB12A97DA82E661DF679EF1F
-:1055F00072870569539D83F6FDCDF5A602CB0800A1
-:1056000017E3811EB74FC66FF55BF61FD1B01FA41D
-:10561000B3CE8378F7F580533F027E55BF67A9EE7E
-:10562000BD9C7BEDF3E1E8FFAA41EDE7F1C6837590
-:105630004DDD2CF827DA4BE43C8ADA8783AFFB1D7B
-:1056400010F2F9092B5B47EF075B7C0C76FB90F4BB
-:105650002BFAFF6212BF2FA1859E09D7AF52860990
-:105660003DDC1725FC8B5EB77E12707C47B3169726
-:10567000E24CED32E7A17FF53B2A4A4F1D2FE5733F
-:10568000A63C5FD906A439C0C79AD74BF710EF2ABA
-:105690003A50857DF9FE4E3BFDBEAA8AC31BDF1939
-:1056A000437A6BE680C9B49FA97B29078A4C7EBCEC
-:1056B0007B7E3FB38BB8007B845E6B8AA678646D7B
-:1056C000DF2FFE02799E61FEF2207EA724E3DF3405
-:1056D0007AFF727ED7674FE03766E6B14029BD8317
-:1056E00097A89B86410E774DEED039C9EE7706ED2F
-:1056F0001EB14FB070F8F77DEF2FF149A61EB8CE5E
-:10570000757E46EF0A9EEBB493BD76FC3EF9DE5EF5
-:10571000043CE7D25C1417CDEB85F0BECA3987890B
-:10572000DE191BBFEF20BD9B375EBDAB6737BEAB3D
-:10573000C7DA3213614F261B2A570A529B04DDAE8B
-:105740004A309E13F38689F356DE30213F14FEBAA9
-:10575000EC67DFD6B59E75B842F9EFD5EF4DD5446D
-:10576000D1EF4D75EDCBF9C6F713DE87FEC0F5829C
-:10577000F5D9DEE261FD7AF6CF19122F6A1F36CB1A
-:10578000FE6748FCCC7098043E227E6F43F187A2EE
-:10579000BF8257D157D18DDDDEF606EE05717A1541
-:1057A0003FC8884E97119DFEF2CE5A5CF31F60F6FB
-:1057B00076E8EEFF8B740A450F869EF0B0F8FDADDB
-:1057C000C8B84656C0689DCF37C7901D5097EF8226
-:1057D000F3F5FD06D6B75AD78326B717637F3CCAC1
-:1057E0008FDE80ABDD14A4EFDF1D26E20907B2B621
-:1057F00074197F33127A59937CFFB8FB770C973872
-:10580000E8BD917301F5FE71E0B1457CDC8D338A12
-:10581000C8AE7F8EC9F55ED3FD4EB678FFB8FB9D4E
-:105820006CB39FEC247362C8CED3FD4E769E78EFA6
-:10583000FA558DE5E31D5A7F859DE2E323DFC9E636
-:10584000FBCCB3F0673C5E13437E28F53EF278A7AD
-:105850005E0F3A46BE8FFC88E69BB310FD153BA851
-:10586000BFF639312F6C13680EC18E73B4218EDEF2
-:1058700085567CA9ECD783FC1D8F014FEA5EE71F9C
-:10588000247F29BCAB7B6D0AFF8ACFFC5646F73FCD
-:105890004107BC2BABDE67D7EE907243DD277CDD82
-:1058A000E342FA40A2BE0E7037ADE47283ECE2ED43
-:1058B000B761BE4F7C2FCE0BB88E9A8CBFDFABD2B8
-:1058C0008786990CBF133A5FEE57F355DC7F83311F
-:1058D000EE3FF21DCDE404DFC3C378FB33DAFBA354
-:1058E000F0F19DFF36F71A47F2A45CFF2362F5271B
-:1058F000505FDD7F50FAE13BA59F67D2EF8D7C754D
-:10590000907E5771AED31740BDE85CE10FF8437A43
-:105910003BDDD7F8C39CBF66923DF90EF1FEE7A5CB
-:10592000C279F17D5AC10FAB178A78C30C564FFC70
-:105930009BD6734F331A70FCFF769FB6E7BEEBE43D
-:10594000E1C729EEC247BF5711498FB151075E72B7
-:10595000F193CA6F877D318BEE93261C58EDE6F9E3
-:10596000A32F9E15F98C03E7DD9C36ED2F9E13F9CE
-:10597000C203E7711FF5D3173B45FE0A46FEACE3B1
-:105980002F7E390BF74FFBBBF53F825E332FD4BF21
-:1059900081EDF5C335372E74D37DCA8ACC02719F51
-:1059A000F26394CF485DB03641EBB94F69F2F8FE2F
-:1059B00008BE3DF7A5E06F3787157CF2CFA6EA3E1B
-:1059C000A992B77DC945B5EEFE55F761D53A66DBBC
-:1059D0003CEBAC6042FF3F7D4F9579F8BCFE1F9BCE
-:1059E0004A017000800000001F8B080000000000CA
-:1059F000000BB57C0B7854D5B5F03E73E6994C920C
-:105A000049C80B02E104420C18D299BCC05BEA1DE4
-:105A10002089015A1B6CB52018068D90D76442A8C6
-:105A20002DB5D80C0611A8DE0B5754B068274000DE
-:105A300035E8A0012718EA00922252BF98FB37F2FE
-:105A4000FD5FE10B3E90979310B557EF55B96BADE5
-:105A5000BD4FE64122DAFE7FF8DAEDDAEFBDD77B03
-:105A6000AD7D86B1B196F3D18CFEAEC98C1D3FFCE5
-:105A70009EA249646C4681D16A90A034772BC602FD
-:105A80000EBB01DE7595F935B1BC9F36B45FA2D768
-:105A900066C17E7566EA973908FD72B1DF9F476B74
-:105AA000B1BE416F356430F6B48EB94D098CC5680E
-:105AB0008EC8B84ECC2063CDD07FAC8131631E63DD
-:105AC000297AC6B01DFA312394BB06F97AE3121A7B
-:105AD000563098675C85D9DA9C81BBF53056C8583A
-:105AE000DA28FF68DC5FDA4A3DD5C7687A94063366
-:105AF000638126FFDC0F33192B8E8ACD653F8052E0
-:105B0000CFB2711F4C13656D85F54AE4AFBAD20070
-:105B10006EEC906CB0342B36946F671319ABD702D0
-:105B20009088FF33795A711D6D77F51EE8D7939CE5
-:105B300066DD08E0D8D4832C331FC6BBCA72D804F4
-:105B4000C68E5A1C39D62468679B241C1F9DC3C768
-:105B5000FFAC2C7A870CE3FB0FDF54E880BA3B0CD8
-:105B6000CA0166652CDF3B7A81F61680E39442C950
-:105B700002B075EC02ED688053940312B41BDDA3F0
-:105B80001714DF82E7335A3ECC66EC174C62718003
-:105B9000970CAD63BA15CEEB2CFB44CF34D83EA0A6
-:105BA0002F9F0AF76A854960FDA4A3704FB0CF818B
-:105BB00039319E1D703E96A314627BBA6E20D602C8
-:105BC000F7D1FF95B6CC63A671B13F87FA6BF8F7B2
-:105BD000AF8C3DD72953BD0AABE5375689EED79533
-:105BE000697E0CEFAF3ED568A4B2F36A29C379B4DD
-:105BF000E59977C03C763D5B529E73FDF801AB861C
-:105C0000F695B10E103A86C8CBCE14F8BF28A6C2BE
-:105C10006E369DB1965F41C5BFF0763809D34FD23D
-:105C200008F896ADC5DAB0FE76EC1F6C6776230BEC
-:105C30008E775AA76E5D9B29D6433C2F639E497091
-:105C40008434D62031B8BF54E627FCBC644BA07323
-:105C5000D11FE0E9D94453CB46A45719E8328F4A03
-:105C60006681322D1AD683F6B4374C1EA4AB5D265E
-:105C70004EB7991A5EEED2F0FEFA28E6463A1D07B4
-:105C80003083F26D9BE377B6249AC74FF3C8FB6D60
-:105C9000488FA39997D64F616EDA8FDA6F2CEB3667
-:105CA00021CCB40359844F5933EC7D26D9666E4616
-:105CB0003A0B34D9D947DA607D203A765528FEEA86
-:105CC00071BC3974DC2C1AA78E77AED2B08F46E146
-:105CD000E1FD443FCE4C8DDD9383E3D89B521ED62D
-:105CE00077EBCB6382E37A9B8CEC23B8D7FFD3C4EA
-:105CF000A83CDD64A1F5FF6F532A957F6B52A8FE87
-:105D00006C5336957D4D56AA7FBF693A95772D8A9B
-:105D10002940FA77F966B28F8C42CEC0FF9C5E9D17
-:105D2000A32F04EE9D393C1DBD26E8A83763F8F685
-:105D30006E6C077CF6DECAF1D97F3FF3ECC820BA5F
-:105D40005C6B49B81EFF30C284E7EB8F610BBC70FF
-:105D50004F6F1748347FFF680EEFB7EA683EBB8687
-:105D60006DC5F16F17E8F9FC133455D86E4FE0F3A9
-:105D7000F666010CFB59307DE6CBC897F664A8CFD8
-:105D80000BC2BD5378BB7D0CAF57F7ABB6FFCE66E9
-:105D9000E17428F0DEAF83F57388DE697EB5FFD746
-:105DA000459C0F23FB7B3235659E61EE23C1C6FB0C
-:105DB000135FC07DB8910F3242F8A25E21BE50E958
-:105DC00050A5BF976CFC9E330D82CE4127D0FDA11C
-:105DD0006E40F99A027C20D1BDD8199C679724F8AF
-:105DE00025921FA04439AEF283CA072ABDA7019F9E
-:105DF0004909C173FC28825ED5F2B495E3A53B390D
-:105E0000E601C26BA7CE02A210FA03221310BEB3A2
-:105E1000C00EE34A1E35370C27BFE2FED97B50E5A2
-:105E2000C108F770DDF9F5BCFCBEE727F986721BE7
-:105E3000E9761879F5B53581F6A3D26D92CDFE5F7E
-:105E4000483FFD92492BC54169E2741379FEB70BB7
-:105E5000F83954FA79C9C6B8BEC4734EBC5EDEA91F
-:105E6000E7193AE77246722F338AD747E2573D5710
-:105E700088DC8BB11506EF93316E0F8C057B606368
-:105E800046907E03495F2E43FDB5CDAAD0FEFEA00D
-:105E90009109FFAA3E19AA97E425F373C2F40CB343
-:105EA000001E070E1B88BFFD1A56F50A8C6B255580
-:105EB000113CF76D362E0F06174CD2AC827D05FED5
-:105EC0006E76A3DE0A8C19382BC1F8C0563040C854
-:105ED0007EB0FF584A66EC7ED029A897AE809C63BE
-:105EE000598CC9DB3E3F2BC1BE976D9319DA350142
-:105EF00010DB328C733D19E331F2718CC1B83A3149
-:105F0000AE79EBA777217D9D07FA44FBE62353FD8D
-:105F1000040676CFEC6D3ABAC765317A0FD61FDB2F
-:105F2000FAC48945009F6F9714B4374A6533B5D7D3
-:105F30003C2F7B709D3A73E94509EC9C407BCB5329
-:105F40005150EFDCAB63261857DA2E59FD30FF7243
-:105F50006F0CDE0C5BB645F77E5F76506EDE26F486
-:105F600058D52EC90314C3AAB687B7D7EC0A87EB56
-:105F7000983608C3FCB36C318964FF4D6636B4FFB4
-:105F8000D89604545643723B92AE506D237EEC8DEE
-:105F90005C1E33F659F21D4097F2E1CFD3DF377321
-:105FA00078BE80CF01FCC9E7FCFED57BAB1732FF82
-:105FB00093D1ACC00BE7AC3F6CB2B8E160F51D32D9
-:105FC0009D23E08DA37B7645F5DD4E7C7A48B6A017
-:105FD0001DB6C127BBB1DDD969DAA98173D61F907F
-:105FE00018DA9F4E9FC1C3EFE9EA326C5FEE335976
-:105FF000146C3F6460328C0F00DE4C88C7717D8466
-:106000007FC42BDAA7F0F763A928887F19F19518C8
-:10601000C457F356BE9FF37B397E4AE5D55AC25723
-:106020008BC45242F0FC67CD8B43F8C27EB3B7FD00
-:10603000B50BF1BC0CF6675010EF32E1F93CE0070C
-:10604000E7D51FFE28BDCF1CC4B70CF8FEAD3A1E25
-:10605000FA2FBF01BEAB987B1DDA73DF17CF69C87B
-:10606000FF4964F79EFF03DABD31608F23E908FB27
-:1060700038A9B6F778222C589170D9B902EA27A529
-:10608000BEC232C14E90E21D8F225F9F9DF39747A3
-:10609000101D3D735FB4215D34EBFA5A9F860A7779
-:1060A0007CB41579B03F63FEF6D7609DE2842FD3B0
-:1060B000F723BFFCC96041727A42F023FE1901FF49
-:1060C0004EC6EF1BF0780ECFEFEC34F80D708FACAE
-:1060D000BDC43E640F4C407DECD5A39C2AD10F5427
-:1060E000AC407B1CE6C375242023E4EBDACE3F9F53
-:1060F00096609CA424B2C5081BCD7E19E769D35DC8
-:10610000193A37CC2359FE42FDDA6C13E8FC1353DD
-:106110007EA4A0FC695EC81C5113BF4DCE3392F320
-:10612000CF0A7F6544FB6F0479AFDA7DCC3D361E24
-:10613000F90BEF82F30F973BCBA733F127F842C05F
-:10614000556BDCB146E8BCFC666B2A9EFF63A4B3CA
-:1061500058A4BF53DA51B0AFBA5689F0568FF483C2
-:10616000FE15EA37A8EFF70A39F27C77F1A8442C3C
-:10617000252B702AABEE94AD7E68AFF6717ABA8E9D
-:106180006E84FCA869E3F2E33A3A6A0338C44EAB82
-:1061900047BA5261C0F7C9A0FC987A0DF6FBF234F9
-:1061A00026F4955BD05B4E5C1FD0CB2053E22C399C
-:1061B000217A4BE2F6962A576EDA0AA23E64DDC9CE
-:1061C0001E23D386AC7BF35E4B183CD59B1AD6FFBF
-:1061D000073E25ACDDE6CF0E6BCF3F610D830BBBD9
-:1061E000A787F59F76DA1E06DFD25716D6FF8717E8
-:1061F000CAC3E0C11C38CF3076C7901E4A95C2FA98
-:10620000CF514C61F3CFCB8E0F8307CDE27E841D3F
-:10621000A8DAA75FD8B81D1459AAF7FB136BF83A90
-:10622000AA5FFCD3E9E1EBCDB787AFF75DF1B21B15
-:10623000EC7E2DD8F57B413F62F902D8FF5AB0EBD6
-:10624000DBC0FE47F825B0FFB1F482FD8FF5AF80CB
-:10625000FD8F703BD8FF081F047F05615F531995C0
-:10626000879ACAA9FE46F7D725D63D21D63D29D61D
-:10627000FD47EF492D9D6593345F009FCE4CB8A834
-:1062800047396C6FEC2BC538C0C05B32DB810CE248
-:10629000F09C684A447D348AA1DDC2CA07DEC63854
-:1062A00045FD8189968D0AEAA1FF7C07DB03EDB2EB
-:1062B00082F2FCA8EF83589CE7CA17C087F938EE32
-:1062C0008358F48FEBBE64046F847605E039FB419C
-:1062D00030903D03720DFB67AAB047CFA02C6FDB57
-:1062E000AF477CD4EEDD4FED6F7975E1ED7B5BC29E
-:1062F000DA2DD81FCA5AAD87FCFB4B3E753E3FF5E1
-:10630000AFCB94EC68175FDAFB9FC9CBB05FDBBB08
-:10631000C9F77DCB7D7F72F0C51C94EB4ED0C37E58
-:1063200073701E67874EC07CDF7599FB4B1350114D
-:10633000B4496C121457D826B60AE45DADAFB50E59
-:10634000E5506DF6221DCB207924E20D206DD15E43
-:1063500042E71EEEEF8AF7D3D8FB60DE37BCC76F8B
-:10636000B723FE3A8FC5E2BAFDED72983F73771EF0
-:10637000B75BEFCED313DEAEB41F8B55A07D83F792
-:1063800018BF6FAD9FCE7D54C0FD50D23DFB643A27
-:1063900077F5171ABA7F75BEFBF3649A678E6F5252
-:1063A0000C9EABC7CBD773E529B4CE9CCCA595B8D2
-:1063B000FF93A90B0B65B2F34030A35C9D32AF1580
-:1063C000E303B55ED93E9CBFB546CCDBA5E374F8CC
-:1063D00056E6AB5D63803E4E968DB291CC17FD7E46
-:1063E00093C7EDF152BD2313F5428F5989413A7E8F
-:1063F000B86C620CE2F52896585FB653EF80B2A6EF
-:106400009DAFD763E98E457AEB69CF97D16E51E79F
-:106410005B89EB1686D0F510DEDC84A72A4F8B193A
-:10642000E709E28FD7BBF2B81D7ED2F3EE5D68A715
-:10643000F464475B112F5D7A46FE6D2DE015F54142
-:106440004F675A0BDE83BA9E4BE0A33F5B43780D48
-:10645000F874A2DFA25616D64FC7F1B52B7C3F16B3
-:10646000CFB97F5B847AE959B0ABA1BA4ED7908C93
-:10647000E7FF787BF8FEAAC43DD7E9FCC9C921F43F
-:106480005AD731C42F66A2EF0E953F14C2A78AC710
-:106490009E6C6EB7F5A41A3CE82FD6ED6F25BABEF8
-:1064A0003EBED39D81767EDAAF8D1437BC913FAB73
-:1064B000DA01217E0F433F4E5736B1503321A8EF0A
-:1064C000AFD9EC2FE615A23F544EFE5E0F1B588647
-:1064D000CADF8976701CCADDBF3D85EB0EB683BD71
-:1064E00007EB3A8DBEB91F829D35680546817D0F49
-:1064F0006ED779847F6246FB7499B04F3F561C4536
-:1065000032E857E71A0D9DAF2E278ADBB5424E7E43
-:10651000B23FE3A748AF7527648B11ED50F05B08DD
-:106520006EE37641BD37E3DF67A0BDDDA6233B40C8
-:10653000B53B9CC2EE382FECD9F36B06F464AF1E6A
-:1065400096D813B08F2ADFE6AE346877E6CC257B89
-:10655000D529B751FC71F9D670BBA0DA130ED7EE6E
-:106560000D879D117683EAB7F5E40DD90F93D1FF1E
-:10657000289167A4201F7C2CF0A9FA232BA75A533B
-:1065800090DF376895B96A3C00EFC975F8D56ADCC9
-:10659000AFA72ECA4A7EC1AA43749FFD9F71BFA3B5
-:1065A0003F9571FB88F17BEDF771FA76E924EE6790
-:1065B00000B9D27C46C9B3069AFADD83B124971894
-:1065C0002B437E685CC8FD483BC65CA1DC9727E294
-:1065D0004511FAF2566D9F1C1F221F3ECB9B40FBBC
-:1065E0002FD63307EAA9953156D25BE38DDCDE2E38
-:1065F00059EDB5211D8C07FFD81012CF1E6F1E90CC
-:10660000B0DFAE8778FC5CF5EFE76B2DBAF810BD14
-:106610000792276C7E90247CFC8DE6B7C0FCE6E0F8
-:10662000FC70DF7178DF9F1658491FA7CF67AC9BBE
-:10663000F8B181F8513DCF15A0B362A0338C9920F9
-:10664000DEEAB61FA138B09375933F521ACBF751CB
-:106650008AFB41388A97967C2E37CAF3F9BD350BF1
-:1066600058955B6FE5DBE3F3A1DC9BEF48CAA77AA3
-:106670000BD1E54A412B60A7A4F40D23771BFFC281
-:10668000FDAA4F810F90CFEF699094CC303B88D317
-:10669000B78B57B1CBCCDB3B03EFC16DEFCE4E4692
-:1066A0003F8AF3D59255262533844E5D48E7702FF7
-:1066B0005596EA1FA3DDED5895AC60BCDF85743FAD
-:1066C00001AF91D37522FC43FFE23A3AF786C3F05B
-:1066D000B71DE9AB9E19ACA8475CBEC876AB16E304
-:1066E0003AF9F9C0073707F9205DD0658B43F2A06E
-:1066F000DC6FF94ACBE3588B258A5BDD0995489717
-:10670000F487FDAA667A70FE3B01447F886D4924B8
-:10671000BEA14690233F17E7BD53EB3F827C7C5CD4
-:10672000E7CDC078CA7127CFEB2C646070807C59AC
-:10673000CCBAA9EC8DAE3FE0A7C9DDE3D06F7ECF28
-:1067400061A0384ECBDA1D31284F73D95ACBF96C82
-:1067500054EE6CEFB5FC91ED0A2024765EC50BC5B6
-:10676000853611FE55BCEECDB7CF47FC8F34BEF653
-:10677000AF076E4797A2F681567D0A279BEEECA2E3
-:1067800020FE5CCC9B8DFB55F135843FD8F358B887
-:1067900087056CA008FD1A156F46F8371CDED4FB80
-:1067A0004CD70DFC0CAF0CF412C997487CAAF75BD0
-:1067B000CF1A743CCED5F0CE42E87FF75A8D82F6E0
-:1067C000E175F8BD011EFC26DEE48F91C8DF1C09CF
-:1067D0002F2A3E54FC9C8EE7E34EDF23539CEEFFB2
-:1067E000355EDECA773CFA6DFC18C97F23F1DB9277
-:1067F00055117C19C17F2ABE1CAB6289CF543CD68F
-:10680000298CFCD6BACE18AB8705F167867F883F06
-:10681000CC53503CA65D62CF48DF850FFB28AF11FB
-:10682000891FA00D3BCAF59D11FCA7E26D24F9A3B9
-:10683000CAAF33CC7FDC22517E80F3E7AF0C1ECC95
-:106840002FAAF901350F704CC8BFC8F20CD81D989B
-:1068500077D998DD9384F65AAF5E9D87E71FCFAC5A
-:10686000E91EB702C69F99C9CB5EB4D342607B14C0
-:106870008FC39D196D70E3BD9D9126CF423D7E462D
-:10688000FAF5ED1C4ED12B082F4C996501B857A78E
-:10689000C6ED1E1672D843E59985D38AA99FC4DE3A
-:1068A000C4FB5024564EEB48524219ECE7CC0393FC
-:1068B000F29A59F0FCAFE4737BD62BE4F9501CFB41
-:1068C0003712C5B197800AB060BC7DD6D36513A0DE
-:1068D000FEEC83136D94FF6B0C5F1FF56806C50714
-:1068E00037D37CB77E31A05B9A13DCD790FE2BBEEA
-:1068F000CAEB2B27913F512570684F98CCFD58CF9C
-:10690000C438D447AA7E1A3CF1AA39347E7911F4EE
-:1069100017D387C0931F4F0FD56F4776FF3E0BE706
-:10692000A9D2BB73AD507FA1E50FE9680754ED7E96
-:10693000348BECD2DD1BB2D0BFA8DAF1FB2C3BC10B
-:10694000D10EF26FB4FCDC97F7DDB27363881DFCE7
-:106950006021F70B161B8F94A07D3AF7E64F1EC1FE
-:1069600078F8A407258A8BDDC3BA1F41BD5991CDA4
-:10697000F9886D31925C87F928EFD83AF927BB5036
-:106980009E9FCCFE405709FD4C055ABA8F0AE67906
-:106990002C05E361EB258A8705FB8FA33CE6D2B586
-:1069A000923E3511F561BC4D56705C3CEDE3DEF571
-:1069B000B62EACAF58CDEBE71A3CED3D38CFD37ACD
-:1069C0006BAB8213954F280FC90B9B0AB8DFB5E458
-:1069D0003189EC71759D494F25B7849ED35420F4BD
-:1069E000F98C6EE2FF9F0ABCFC78F5BB6FA62A9873
-:1069F0004F72C41540FB3B4F9ECF44F9559C7031FC
-:106A000007E97C92DEF14C359E7B8781E28705B9F0
-:106A100069720AF4CFFBE5CC27B05CB27AE933D5D2
-:106A20001807DD6A243F4ADD5FA3A468D0DF3CD6A7
-:106A3000F28B7BF1DE2E3C69243BBAB1E5A614361D
-:106A40000C9FAAE51EC0BF92C5D8F34D462A5F6CC5
-:106A5000B230058EB8AF2995E0979B142AD9024E23
-:106A60005F8DC25F1D69BE7CF0F715905705EB6125
-:106A70003EB0376D26FB143CE7A429CE1D1BC4B9DC
-:106A800026C1789B3B6336DE43C186155D688A2646
-:106A900017F0FCE2DB3DEBD3C98E5E7DEEB96A6890
-:106AA0005F5A509E5F00F76DDC7E95FCFC631D8F86
-:106AB00056505C7F87819F4F9CFBC2935929CF60C2
-:106AC000DCF52D1DF9DFAEEDE79EDB00E57D8FAD3A
-:106AD000D087D2FB773DAF4DECE7467C35D23D7C8D
-:106AE0007FBEFA7D3AF1CF0EE0AB9C7F9CAF5CABF2
-:106AF000D7D0FD3D5A507E37DEFB059D3B1DF9E9A1
-:106B0000C2E41F119DBB0F4B74FFAA1C57C72F1067
-:106B1000E7ADD5781F237B50C8F1CFC1F3C3FB3D50
-:106B2000D2F17116DAC39FFB167EEBB90F36610600
-:106B30001DE35A462A23DB8BF48E8956385F9186F3
-:106B4000DBC191ED0F17A871719E6FC73F8C0BD7FA
-:106B500009FDE9848DC525A0FE93FC51B998E7B8DD
-:106B6000EDA216FD2FF0EBDE0FB72FD9FB217A7CBB
-:106B7000A4FDDEA8ACC779B441B93BEDB486F943B6
-:106B8000F4F62D7D51CC1FB2EE90DF01757ACCB3B7
-:106B9000748C26B98078C3BC4CA063F20E842FEAB3
-:106BA000391E0307C1BFE27115261705CF79B1E37E
-:106BB000722ECAD9C8F3D61FBA4CF451E77BF4AA97
-:106BC00044E79F73519B7BE3F31FD97D3917F1771E
-:106BD00051D757847E5440DF978B78A87F9DCBF3A5
-:106BE000EF7B0F6A7DF57A3D8FEF4916F2074BE494
-:106BF0002BE4C7074E703FBEBE6327C9D3C14E1EEC
-:106C00004F7169BA4B5330FED070AE0BE5D9602A94
-:106C1000F7AF607E3BDEDB8C89420F6A07D2E783E9
-:106C20005C3B2AF2B5AA5F7701F9578FF378EBE85E
-:106C30003D526E3443BBE212F233D457ACCA58878C
-:106C4000747EC193849120F676EEFFD453FCED8DD3
-:106C5000688B4C762BD486E06FE81C1E993F9C61B4
-:106C6000AA9F1ECDEC21FD5C7AE5A7E41F9FE47985
-:106C700032D714CE4FEC10E727E7DA23FAD490F995
-:106C80005E52E587B01FE7BEF13FC497A76CF6538D
-:106C900028CFA25116E27CA9711E4912FD8A827981
-:106CA0004073A7F0C7CB646A77F964361AC7A4C6E5
-:106CB00050BEBE8C6DD2A2BD3B977967F077327D16
-:106CC000FFF643689FF7869C8FEFB1C07EA6FC71EC
-:106CD000699423B311ED238D24EED55B303F549F8F
-:106CE00015727B6B862C911E1B181D4D76CA9C0558
-:106CF000CEC5B85FB55F9996EB339887EC2CE61953
-:106D0000C8C57C26F30FE4629E53ED77D71BD10DE7
-:106D1000A41799B7E0AE9075C61472BDF929E69F25
-:106D2000419EB844FEB344FEEA29F4A31A0FF33C93
-:106D300061AF26E33D7CAFE5867B46BC5E06BCDAF0
-:106D400051FF3898DD8EFC3335C983FCE3DA2731F7
-:106D50007CB756DF61D881719D7A5D5F32D2F306D0
-:106D6000DF5FF548CFAE03EFEA95A9389EC781C033
-:106D70005ED7E0FDBA84FE72FA6E7A0FE36ECE1330
-:106D80005C8B3AB5EF925F5FDBBE9FFCF73AE6277C
-:106D9000FFBDAE2D9C5E0653799C3D923FC6142AE2
-:106DA000617C31672BE78BBB64D680728E89B8E932
-:106DB0009CD414B24782E3849D285F7E04ED97FE45
-:106DC00009925582A9FAA3DC6BD12E7267717BA65A
-:106DD000FF4F2F162C23B9E229F819BE8B11F6EEBE
-:106DE0009CF59BB572C87EE674F238617F14AB3AAD
-:106DF00048F8768C453CA4E7958F2DE4EF6472E962
-:106E00009D8F86C73523CFF1AC88E39CC4384F4EA5
-:106E100070DFF3D2D2B81C631EA29F2E0D5F5F7D80
-:106E2000F7A28E5F21E869C81F92787C6A24B98234
-:106E300079944A9147A91479944A9147A91479946D
-:106E40004A9147A91479944A9147A91479944A918F
-:106E500047A9147914AC3F895BA5F7703B9F417A31
-:106E6000E8421E1B13847B1322E031E1FD7B13A457
-:106E700070788C44FD8B0B773EE3CEC138A645C8B5
-:106E8000252506EDAF0B261E5FEA8871CC2D84FA0E
-:106E9000CA39CDBBF97B443BBD67294E58B818F9B8
-:106EA0006B30D1C0500EB90B1DF3111F274ECCCE45
-:106EB000DC4CF2D164C53C77EFDD37C7515CEE2D79
-:106EC00099C9B0E4CCECFCB50500CF344B44B720F5
-:106ED000277E50AEFA9330CFEC4E9ECF2891EB2A0E
-:106EE00071FEC6D1A67C8A6BE53B161586C40F4A97
-:106EF000C72CCF443BA84BA7BC87F154F75F740C59
-:106F0000FD2835FEA6F6EBCD9B598DFB9A933D717E
-:106F10006D1ECA1B602E946F763D6BC37DD935D133
-:106F20005233C92B458BFC5F2DF03D4BE1F6B05F32
-:106F3000AF6813D06F8F9A99E85678BEAA52E4AB27
-:106F40002A45BE0AF1730AE36650BE03F55876433C
-:106F50003D9691EFB9761794AF24BA6503E9A1EF96
-:106F6000C1E6225F7139938EF4FC8288C367178A69
-:106F70007769F9E50FF2715E9AA756C4DF2EEBC26E
-:106F8000F378EAB8E07846E51D3FE0F299C5E9F903
-:106F90007BD7B1CC8DEF69EF786D34C593021E8D30
-:106FA0005B170730F038CA2FF61AF76F592AE797A0
-:106FB0003B5E4DA17ECD220EEA4CE8CE4A40BD2B71
-:106FC000F84A850F7EC3DFF938F30086F275899F92
-:106FD000CF794777563CC001C9A4C1F8B873076F91
-:106FE000EF117CE79C20E613E761466F3AE2A3FFCE
-:106FF000F06BE9F702BCD1EC5FC6E5BD3F8BE43432
-:10700000F367E17BA1CB92F72CBEB7FDF5C17F59A9
-:1070100084EF6B2FEBBCCF21FCDB8333382CED3FAF
-:107020006B096D4FF2A6E37BDC5F1FFCE1227C9FC6
-:107030007B3969FF73F1D61058F7CA596CD73F3CBA
-:10704000635131F49F67F09C6842BA7999D397698C
-:10705000DF81F3783FB51DDC5E9FB5EFC0955750DB
-:107060001F1F88A17CBDAF3083EEBBB963CF6348DF
-:107070006F81FD3AE2838D6D7F7DEEB7D4CF4061A5
-:107080009479066F01865CDC457FBB1BF7352FDAF0
-:10709000FB19C29B8B6EA37DCE1BC5F9F9A9A2B9C2
-:1070A0008B903F0307F6FD0AF96F5E1C18B2B89F7C
-:1070B000174D849F9A572717631C2010D35D81F3C7
-:1070C000D7BF60B0229DD6BC9A320BE302C70B79C2
-:1070D0007CBA7ACAA674D4AF9A43CFEFFE2DC629E4
-:1070E0005F30517EC695C0EDBB1AB9A56805E16F4A
-:1070F000E76E7C371278DE4479D26A9803D7ABDE2C
-:107100003D89E2EAAF7FFD4105E2A144DEBE1BEB13
-:107110003FDB65D2E03DF4E8ED713F423EECD191BA
-:107120009F592DE0EADE517C3FD17DA584BFC44D3F
-:10713000E9A85F6B46FDE676DCF73C79D373E8E7B8
-:10714000B03D06CA155C7C1EEE0DC65D6CD5D12B1C
-:10715000D5C0F3315AA497CBD2A68A6770FE56DE0B
-:10716000EFB26913DDA7BBF52686EB413F86F2EA55
-:10717000B2B439ACFE62EB9E5CF4432FBD308FFCA1
-:107180005195CE557EA9D96508D387240992C57B30
-:107190000952B36E66063D5B2DC04B07B7059E6175
-:1071A000C1F197DA747E3DDC51B581ADC5F7C12AD6
-:1071B0003FD4A4DD5686E7ABD1B464A1BD529DDFB8
-:1071C00057817C71D1C48CA9F88E4EE8AB9AF63504
-:1071D000F3D1EE1D693FB1E25DDFE7820F3FF79922
-:1071E0003CA1F9C1C8F26F4D4C3915F26EF89E06FC
-:1071F00003D9EEEA7C6FEBBD75E89FD52770F97176
-:1072000016FAB7811C331771B9B76455787FA9880E
-:10721000BF4BACD7F765A1DE53E7FFA650956B7D5A
-:107220005928AF22C7CD9385BC7951227953D32EEB
-:107230009D93E19E6A8C6E0FBEDFA94167929F53BA
-:107240007B4DE2E3528BC4BDC3D8A78B3268DD9A75
-:107250003693DD04E36AA3FA62D11EAA8BE98B455B
-:107260003B277048663B04BA1293057E2608948536
-:10727000C41DABBD3ABB2977183CA3DD84EF73F086
-:10728000BF61FDB622CE2755BE685A8F59FA8A9043
-:107290004EABB6878FC3735942F82FE0DB991CEAD7
-:1072A0008FDBC4BEFBA573C427FD5FBF9F8E78AF85
-:1072B000D1B0B59847BC24F1EF1E00A6EF1E2E8971
-:1072C0007C64CDDFCD51482F973EAF23BE0D487D66
-:1072D00024D7CE1C5C407229A0EB23B9D65354416D
-:1072E000F22110DF578172EACCC17ADE3EBAAF429A
-:1072F00081F64E84B17D1C237D7FB9E801921FF396
-:1073000064FEBE81EDD459781C687D6F13F9153A7F
-:1073100025D4EFBE52A4E66DF4C173CB41BE093053
-:10732000655F3BF2619599E239603FB5BD8276DEDB
-:10733000C2642BC6C5AB701CA7037D68FE2F31E16C
-:10734000CB65889F45718E3B8B308F9DD347FE0365
-:107350005035D9E9F57F32901FD9AF1BD88D722AED
-:1073600037CEB1B008F651A7EF5E87A1A72BBABE02
-:107370002ECCFBCD95B93C627B385D057276F2EF81
-:107380002444FEB0BA88CB5FD05BAC05E942E2F89A
-:107390003DE67BF514CA9540F74492C7917C73D1C2
-:1073A000F7442CCA87D3A0C7DD217EFEE9A57B2840
-:1073B0004FBF00DF654079EFDA707A18FCEA67E4C6
-:1073C000EFB1C742EA910EB784C3917484F4E80F19
-:1073D000933B6EA29B3D82AF6A6775D7E33D0CC1BC
-:1073E00077002C87C04723E088FEAC9CDB097BF04C
-:1073F000BF61DEBA71FE5EF2CFF7F177B1CDA0BF0B
-:10740000083E104D7963CD3ED04F895C3FA15EA808
-:107410008DEDA6B854E08081F2230F777C4CEF19F4
-:10742000810E29FE52DBF15A32FAED3EF4139248F6
-:107430000F26D33B95031DC9E86FA8F5751A6F9603
-:10744000788F4F76BA5AEF94FD59B8FF5AA93B1777
-:10745000DB7D8516D11F60196146E7A89338BFB35D
-:107460000E99E47924DEF60A7A05B9904BEF2C0EDA
-:10747000F1B8802A07AA853C398AF5399CEF2D6A34
-:107480005E49C2F772D1C3CA879B8A547BB881E236
-:1074900036BB8A147EAF623CCDCBE34AD45EFFFAA2
-:1074A000E5DC0939384E11E342E4D0C4A05C41FE6A
-:1074B0004F25FE7F58970CE7AA794EB236A39C5A07
-:1074C000BCA614BAB3E5DA15A5142F13EF3F23F7C2
-:1074D000154947F6228EDF1A4D7C4962C87C97C059
-:1074E0005D4FCD233943EFE8EF4F7CBC14E313BF6E
-:1074F00058BC99E87948DF84F2399E673B97E3C826
-:1075000036D734D7D3F1F286967529C3EC23729F10
-:10751000D58E96D264E5FA7A75BF974CEAFE66E995
-:107520009242EF61C19AD22428971BFFD17BE0E7FA
-:10753000BDD461F0A35EAD5EBC625DDC3074739D52
-:107540003ED81EA2BF26207E3D94D71869FF9165C4
-:107550009DE4EFC5381103BE6A25FE027E09D10BFA
-:107560006542BF0EC51BAA968E47BF9339968E47BC
-:107570003D037C55611DC6AFC42F4B34F476C34D1B
-:1075800065E47E3E2BE271D2B222CE2FA76CF66F5D
-:1075900050BE8EF4BD85619AF4ADDF5BA46906DF51
-:1075A000417E4B4B8E51300F54323B9AF73B6CB2BD
-:1075B00060DCA6FFF09714D7ED7FC4BC80E70BCC4E
-:1075C0006C34B477A54EDD11AA473CD3385F46171B
-:1075D00070BBC595ADFBF6B8504ECC505C88EC86C0
-:1075E0009C68CA93047C9F92DEEAEF2CB4603E2331
-:1075F000D00DDE21F093EBEBFF4A46FD1AE8FC8844
-:10760000DE8305BEFA98DE896D10EFF48EFAC43B76
-:10761000AB6E2586BE8B2BFBA014FB6D1465303E34
-:10762000C0E35A6AA9FAFF21FEEF946985C3FABF45
-:10763000090E73685C4049192E8E121A17C8D4F2CD
-:10764000B800961817C8CCE4710184312E8025C685
-:1076500005B01EE30208635C00618C0B208C710195
-:107660002C312E80F59F89EF1FFA4130F178A599D2
-:10767000E4FA4A7CDF0EF7B7F230CF3BAD6C9529C8
-:107680007F8BDF3FA07EBBEEDD4CBB7837E3DD4C6C
-:10769000793CD701D98A2872E9068E631CC7B55F89
-:1076A000B2AE41B9D2B480D6DFD059F8DE62AC6F49
-:1076B000D559350AD111C7638B44EFF46B3A5B2976
-:1076C000EE549C72584FF56D12C338E95D06EEE733
-:1076D0003A65A8CDA33C28D9C14E4337F91FB57BE5
-:1076E00025A532F49DC6F4AB2407D47CF232DEC467
-:1076F0009C5E935239CC3B90A177E7E2DDF432CC2B
-:1077000033E37B71F92B7AD7EF04877414D2E156F7
-:10771000FEFED902FF88DF23DE35D574EE5F87EFEA
-:10772000A122F3CD43DFD345E49DEBA789BCB28D05
-:107730007F5F51F664E5BE03B0DEE02603D91BEEA1
-:1077400042C703D39230EF6FA7F8C8F1C326F28B7C
-:107750003EDC7C53587C84E53B1E9C46F9F9B11411
-:10776000AF68D449A48F67974D4CC17B9C7D42473D
-:107770007AA737AF7C35F66B9CAA503CAAC4C01ED2
-:10778000A079C47B29151F25CD924703F05266A529
-:1077900077F64BE09A305ED9AF33AFC7774D4B18D1
-:1077A0007FE7A0D24DE36689E8060304789F15E2DF
-:1077B0003E9774FEF94B7CC7709F81DBAD691A9EC2
-:1077C000BF4EDBC8DF33DCCF1C7AD4B3CB91BA64B5
-:1077D000D28F7FEA837A47F4D8746E972B2938FFCB
-:1077E000D2933A7A6F5B92F2932C07E9E9627AC7F7
-:1077F00020F917C9D76E1E997F22DF311CD771B9C6
-:1078000002F748FE5017D225C5651C549E6CAAA2EB
-:10781000F277E27B88EBDFFF0F9C453F312D25C6D9
-:107820008A726EC4EFDDA2BEFD7BAF17C4FBB53418
-:107830004D4FBE82F7F177B315EF437D2778CA56D7
-:10784000BE1FF1648F656E0B7D0F061210EEB5142E
-:107850000F22615CDB6BC7EF8E060E4B167A977CAE
-:107860009D7CDCFC08BE1371654A1649C1F8F7A679
-:107870009264D877E9840CDAB7CBC7E3A37443C921
-:10788000183FE7F84ACF731C9B5618AC9F27F82681
-:1078900000FD399DFCD083F4F61DE2A6BBB0BF9B72
-:1078A00099E87B6AFA83FDCCBB791CC54F55BA19A0
-:1078B0006C4BD98174F39E90FB8B17BFAB43FDDFFC
-:1078C0009BEFE8C17D54545E7D2499CE377CFC4A01
-:1078D0007DA71E19BF0A959FFF3FDEA79F6A6AA07A
-:1078E000F29DA655547637B9A93D44FE5F1A41FE74
-:1078F00047C63FAF227F47C63F99518923FD09FC08
-:10790000CDE3CD11F1CEB251F7AE87FB9BBD456FF4
-:10791000C52A35FE89EF87579A491EFCF7B461E303
-:107920009EEABD99294E3AC84C7978FFB3B2276ACE
-:1079300035D0AE9DCEF1A7C61D913FF07CC81F5833
-:10794000227F68B541FE78560F2C5CC0F5BC9BF4D5
-:10795000BC89F0BA6E0DC80F80EF639630F97125BF
-:10796000427E80C371377D57D56960182754DF5137
-:10797000CE82E28BBC61E48997CB937151DEE7E95B
-:107980007BFFFA287A9F7B5CBC873BBE81BF87ABBD
-:1079900064E5B4EE30722516F171DFA881B37F8003
-:1079A000FEF7FDDE4CF6CABAD1CB8AFE19B9724D8C
-:1079B0007CD7F234FEAE80F6DB7E57E03109F3A1CE
-:1079C0008DF7301BE259FD5D811491CFFE1EBF2B58
-:1079D000306D7AE177FF5D815BA78F5F1CFABB0298
-:1079E000B7FA3238ACFEAE001BBF7884DF15983D85
-:1079F0003DE9FADF15B86D3AF71747FA5D01B02790
-:107A0000CB705C92CD3E07CB34B1CFC8EF694F8AC3
-:107A1000FC5D97C6B118CBD258B796EA359E02FAEC
-:107A20000E5EE3FD25F981F98E9FE3794B9FB04D02
-:107A3000C90638CDE02539D99B67BF13EBAFD9EC28
-:107A400077E13A917173C42DFAF7B09FBBB13DF263
-:107A5000DD958ACF15D3B9DC6814E58CE6E1BF2744
-:107A60006F9CCEF3F237DA37ECB706D71BDAFFA6F6
-:107A7000A505B81FD86F2DD6C37EEBB064E684B0E1
-:107A8000EF53AFA73337D155E3744E5F20CFE67D78
-:107A9000C8ED412AB3B49E78B41FC73CE489C7FD42
-:107AA0008E691930E177107F740F9850BFFF71F520
-:107AB0008009EBFF68E7EF9523E77F793AF703B298
-:107AC000660CD0F8F168E3937D3E108FF65356D5DF
-:107AD00087EB28DFB27732E997F142BF8C7F68826B
-:107AE000AF0FE86DFCB638CA67B3E2446AAF3172D3
-:107AF0003EAD79A8F2E00185BEDB9AF76188BD331F
-:107B0000D903FB0EB3BFB483FCDD25C0784F7B7572
-:107B10000423CDA27DE564FCDDE5182137D04E5B62
-:107B20000C72C159F5E69794F7C7F1381FE66891D2
-:107B3000FE7CBA41F17D9A05FDD0E50BD674915FCC
-:107B4000B875A85EF899FBD7A1DF0CF65B587D4DA0
-:107B5000E5912ED437B57BC3EB9D0D57C97F05FB4F
-:107B60002DACFE9E5F9ED3F3DF2F08AF07FCEE45E2
-:107B7000BA54F17B5CE79D8C7EDE71679495BFDF24
-:107B8000F7D2EF95EC10DF3FEFFC8F599C6E04BEEF
-:107B900061BC3774FCC8F4D14CFDDDB35836F2C378
-:107BA0008D4A552E0DFDFE899EB929BE373786E4D4
-:107BB0008E4BF855F59516D2F369F546925F25720E
-:107BC0009415E1A1DF3F2993859CF212FFF7DC1E9B
-:107BD0004F713C3A00C2095329EF93DCCCE1812478
-:107BE00003C987124D79DD1E28DFD4847FC7FE2CA0
-:107BF000CA0719F9977F87E9D27BF977E25AA5106E
-:107C0000FDDC66C9BE0DBF7B6C96441CB1DA4CF935
-:107C1000827E8C2FC279B6C47BB62D8375B6DC9973
-:107C200043F6713FE3F2D4BD80E7ADB6C4972F5E53
-:107C300081ED0BA750FBC16F263E5E80F653759415
-:107C400015EDA72D366E5F6F999F4DEDAF4BCA1A9C
-:107C50003CB7FB2146EB6C99CFCFBDE5F171E2FB60
-:107C60000B8F09F9794B8B7D34E6A366591C1710ED
-:107C70005F63443E6E4B06D443F99454BEF07E9C41
-:107C8000672ADFEFEF6C0AC98FE30BA73CBE5B21CD
-:107C900035E2C7BC906B6E0CF9C1FF0BB81F749432
-:107CA000704700000000000000000000000000001D
-:087CB00005020D0000000000B8
-:00000001FF
diff --git a/firmware/bnx2x-e1h-5.2.13.0.fw.ihex b/firmware/bnx2x-e1h-5.2.13.0.fw.ihex
deleted file mode 100644
index ea3e254335b1..000000000000
--- a/firmware/bnx2x-e1h-5.2.13.0.fw.ihex
+++ /dev/null
@@ -1,12849 +0,0 @@
-:1000000000003BE8000000600000068800003C5053
-:1000100000001968000042E0000000AC00005C50E5
-:1000200000008DF800005D00000000E80000EB001B
-:100030000000E3140000EBF0000000940001CF0882
-:10004000000058E80001CFA0000000C40002289082
-:100050000000F9640002295800000004000322C0D7
-:10006000020400480000000F020400540000004594
-:1000700002040058000000840204005C0000000636
-:100080000204007000000004020400780000000078
-:100090000204007C121700000204008022170000F6
-:1000A00002040084321700000604008800000005E6
-:1000B0000204009C12150000020400A0221500009A
-:1000C000020400A432150000060400A80000000489
-:1000D000020400B802100000020400BC001000007E
-:1000E000020400C010100000020400C42010000030
-:1000F000020400C830100000020400CC40100000D0
-:10010000060400D000000003020400DC0010000020
-:10011000020400E012140000020400E422140000B3
-:10012000020400E832140000020400EC4214000053
-:10013000060400F000000003010401240000000098
-:1001400001040128000000000104012C000000004F
-:100150000104013000000000020401D00000890603
-:1001600002040004000000FF02040008000000FF79
-:100170000204000C000000FF02040010000000FF59
-:1001800002040014000000FF02040018000000FF39
-:100190000204001C000000FF02040020000000FF19
-:1001A000020400240000003E0204002800000000B9
-:1001B0000204002C0000003F020400300000003F59
-:1001C000020400340000003F020400380000003F39
-:1001D0000204003C0000003F020400400000003F19
-:1001E000020400440000003F020404CC00000001AF
-:1001F00002042008000002110204200C000002008A
-:10020000020420100000020402042014000002195D
-:100210000204201C0000FFFF020420200000FFFF5A
-:10022000020420240000FFFF020420280000FFFF3A
-:1002300002042038000000200204203C00000000DE
-:100240000204204000000034020420440000003575
-:10025000060420480000001C020420B80000000131
-:10026000060420BC0000005F0204223807FFFFFFE5
-:100270000204223C0000003F0204224007FFFFFF6F
-:10028000020422440000000F010422480000000084
-:100290000104224C00000000010422500000000074
-:1002A0000104225400000000010422580000000054
-:1002B0000104225C00000000010422600000000034
-:1002C0000104226400000000010422680000000014
-:1002D0000104226C000000000104227000000000F4
-:1002E00001042274000000000104227800000000D4
-:1002F0000104227C000000000C042000000003E840
-:100300000A042000000000010B0420000000000A85
-:1003100002050044000000200205004800000032F1
-:10032000020500900215002002050094021500202D
-:1003300002050098000000300205009C0810000033
-:10034000020500A000000033020500A400000030F8
-:10035000020500A800000031020500AC0000000208
-:10036000020500B000000005020500B40000000610
-:10037000020500B800000002020500BC00000002F7
-:10038000020500C000000000020500C400000005D6
-:10039000020500C800000002020500CC00000002B7
-:1003A000020500D000000002020500D40000000198
-:1003B00002050114000000010205011C00000001FB
-:1003C00002050120000000020205020400000001F5
-:1003D0000205020C0000004002050210000000406F
-:1003E0000205021C0000002002050220000000138C
-:1003F0000205022400000020060502400000000A59
-:1004000004050280002000000205005000000007E3
-:100410000205005400000007020500580000000813
-:100420000205005C000000080205006000000001F9
-:100430000605006400000003020500D80000000665
-:100440000205000400000001020500080000000190
-:100450000205000C00000001020500100000000170
-:100460000205001400000001020500180000000150
-:100470000205001C00000001020500200000000130
-:100480000205002400000001020500280000000110
-:100490000205002C000000010205003000000001F0
-:1004A00002050034000000010205003800000001D0
-:1004B0000205003C000000010205004000000001B0
-:1004C000020500E00000000D020500E80000000742
-:1004D000020500F000000007020500F80000000718
-:1004E000020500E40000002D020500EC00000027DA
-:1004F000020500F400000027020500FC00000027B0
-:10050000020500E00000001D020500E800000017E1
-:10051000020500F000000017020500F800000017B7
-:10052000020500E40000003D020500EC0000003779
-:10053000020500F400000037020500FC000000374F
-:10054000020500E00000004D020500E80000004741
-:10055000020500F000000047020500F80000004717
-:10056000020500E40000006D020500EC00000067D9
-:10057000020500F400000067020500FC00000067AF
-:10058000020500E00000005D020500E800000057E1
-:10059000020500F000000057020500F800000057B7
-:1005A000020500E40000007D020500EC0000007779
-:1005B000020500F400000077020500FC000000774F
-:1005C0000406100002000020020600DC000000010A
-:1005D000010600D80000000004060200000302200B
-:1005E000020600DC00000000010600B80000000068
-:1005F000010600C800000000010600BC0000000069
-:10060000010600CC000000000718040000A900004B
-:10061000081807C800070223071C00002C2C000044
-:10062000071C800038930B0C071D0000293119317D
-:10063000081D686052F40225011800000000000047
-:10064000011800040000000001180008000000006C
-:100650000118000C0000000001180010000000004C
-:100660000118001400000000021800200000000122
-:1006700002180024000000020218002800000003F5
-:100680000218002C000000000218003000000004D6
-:1006900002180034000000010218003800000000B9
-:1006A0000218003C00000001021800400000000495
-:1006B0000218004400000000021800480000000179
-:1006C0000218004C00000003021800500000000057
-:1006D0000218005400000001021800580000000435
-:1006E0000218005C00000000021800600000000119
-:1006F00002180064000000030218006800000000F7
-:100700000218006C000000010218007000000004D4
-:1007100002180074000000000218007800000004B5
-:100720000218007C00000003061800800000000290
-:10073000021800A400003FFF021800A8000003FFF9
-:100740000218022400000000021802340000000019
-:100750000218024C00000000021802E4000000FF32
-:100760000618100000000400021B8BC000000001EE
-:10077000021B800000000034021B804000000018B3
-:10078000021B80800000000C021B80C000000020C3
-:100790000C1B83000007A1200A1B83000000013806
-:1007A0000B1B830000001388021B83C0000001F4B0
-:1007B000021B1480000000010A1B148000000000CE
-:1007C000061A1000000003B3041A1ECC0001022711
-:1007D000061AA020000000C8061AA00000000002AF
-:1007E000021A1ED000000000061A1ED800000006E3
-:1007F000061A36E800000004061A36E0000000027F
-:10080000061A500000000002061A500800000004FA
-:10081000061A501800000004061A502800000004B0
-:10082000061A503800000004061A50480000000460
-:10083000061A505800000004061A50680000000410
-:10084000061A507800000002041A404000020228F4
-:10085000061A400000000002061A400800000002CC
-:10086000041A62C00020022A061AD1000000000209
-:10087000061A200000000124061AB000000000281B
-:10088000061AB1400000000C061A330000000014E4
-:10089000061A33A000000068061A81080000000252
-:1008A000061AD1C800000002061AD1D800000020A4
-:1008B000061A249000000124061AB0A000000028A7
-:1008C000061AB1700000000C061A33500000001424
-:1008D000061A354000000068061A81100000000268
-:1008E000061AD1D000000002061AD25800000020DB
-:1008F000021A292000000000061A30000000000241
-:10090000041A30080005024A061A301C00000009CB
-:10091000061A320000000008061A5000000000020B
-:10092000061A508000000012061A40000000000263
-:10093000061AD0C000000002021A2924000000009C
-:10094000061A304000000002041A30480005024F29
-:10095000061A305C00000009061A32200000000868
-:10096000061A501000000002061A50C800000012BB
-:10097000061A400800000002061AD0C80000000253
-:10098000021A292800000000061A30800000000228
-:10099000041A308800050254061A309C0000000931
-:1009A000061A324000000008061A5020000000021B
-:1009B000061A511000000012041A401000020259D9
-:1009C000061AD0D000000002021A292C00000000F4
-:1009D000061A30C000000002041A30C80005025B8D
-:1009E000061A30DC00000009061A32600000000818
-:1009F000061A503000000002061A5158000000127A
-:100A0000041A401800020260061AD0D80000000242
-:100A1000021A293000000000061A3100000000020E
-:100A2000041A310800050262061A311C0000000990
-:100A3000061A328000000008061A5040000000022A
-:100A4000061A51A000000012041A4020000202679A
-:100A5000061AD0E000000002021A2934000000004B
-:100A6000061A314000000002041A314800050269EC
-:100A7000061A315C00000009061A32A000000008C6
-:100A8000061A505000000002061A51E80000001239
-:100A9000041A40280002026E061AD0E80000000284
-:100AA000021A293800000000061A318000000002F6
-:100AB000041A318800050270061A319C00000009F2
-:100AC000061A32C000000008061A5060000000023A
-:100AD000061A523000000012041A4030000202755B
-:100AE000061AD0F000000002021A293C00000000A3
-:100AF000061A31C000000002041A31C8000502774E
-:100B0000061A31DC00000009061A32E00000000875
-:100B1000061A507000000002061A527800000012F7
-:100B2000041A40380002027C061AD0F800000002C5
-:100B30000200A294071D29110200A29800000000E3
-:100B40000200A29C009C04240200A2A0000000005D
-:100B50000200A2A4000002090200A270000000002E
-:100B60000200A274000000000200A2700000000059
-:100B70000200A274000000000200A2700000000049
-:100B80000200A274000000000200A2700000000039
-:100B90000200A27400000000020100B40000000185
-:100BA000020100B800000001020100DC00000001A9
-:100BB0000201010000000001020101040000000127
-:100BC0000201007C003000000201008400000028C7
-:100BD0000201008C0000000002010130000000044E
-:100BE0000201025C00000001020103280000000075
-:100BF0000201607000000007020160800000000137
-:100C00000201055400000030020100C40000000190
-:100C1000020100CC00000001020100F80000000108
-:100C2000020100F00000000102010080003000001D
-:100C3000020100880000002802010090000000006E
-:100C40000201013400000004020102DC0000000186
-:100C50000201032C00000000020160740000000784
-:100C60000201608400000001020105640000003000
-:100C7000020100C800000001020100D000000001D4
-:100C8000020100FC00000001020100F4000000016C
-:100C9000020C100000000020020C200800000211CD
-:100CA000020C200C00000200020C201000000204C4
-:100CB000020C201C0000FFFF020C20200000FFFFA0
-:100CC000020C20240000FFFF020C20280000FFFF80
-:100CD000060C203800000002020C20400000003406
-:100CE000020C204400000035020C204800000020C7
-:100CF000020C204C00000021020C205000000022B9
-:100D0000020C205400000023020C20580000002494
-:100D1000020C205C00000025020C20600000002670
-:100D2000020C206400000027020C2068000000284C
-:100D3000020C206C00000029020C20700000002A28
-:100D4000020C20740000002B060C207800000056D6
-:100D5000020C21D000000001020C21D4000000018F
-:100D6000020C21D800000001020C21DC000000016F
-:100D7000020C21E000000001020C21E4000000014F
-:100D8000020C21E800000001020C21EC000000012F
-:100D9000020C21F000000001020C21F4000000010F
-:100DA000060C21F800000010020C223807FFFFFF9C
-:100DB000020C223C0000003F020C224007FFFFFF14
-:100DC000020C22440000000F010C22480000000029
-:100DD000010C224C00000000010C22500000000019
-:100DE000010C225400000000010C225800000000F9
-:100DF000010C225C00000000010C226000000000D9
-:100E0000010C226400000000010C226800000000B8
-:100E1000010C226C00000000010C22700000000098
-:100E2000010C227400000000010C22780000000078
-:100E3000010C227C000000000C0C2000000003E8E4
-:100E40000A0C2000000000010B0C20000000000A2A
-:100E5000020C400800000411020C400C00000400C9
-:100E6000020C401000000404020C40140000042195
-:100E7000020C401C0000FFFF020C40200000FFFF9E
-:100E8000020C40240000FFFF020C40280000FFFF7E
-:100E9000020C403800000046020C403C00000005F7
-:100EA000060C404000000002020C40480000000A0E
-:100EB000020C404C000000F0060C40500000001FE7
-:100EC000020C40CC00000001060C40D00000003AAB
-:100ED000020C41B800000001060C41BC00000003F8
-:100EE000020C41C800000001020C41CC00000001CE
-:100EF000060C41D00000001A020C423807FFFFFF29
-:100F0000020C423C0000003F020C424007FFFFFF82
-:100F1000020C42440000000F010C42480000000097
-:100F2000010C424C00000000010C42500000000087
-:100F3000010C425400000000010C42580000000067
-:100F4000010C425C00000000010C42600000000047
-:100F5000010C426400000000010C42680000000027
-:100F6000010C426C00000000010C42700000000007
-:100F7000010C427400000000010C427800000000E7
-:100F8000010C427C00000000010C428000000000C7
-:100F90000C0C4000000003E80A0C400000000001B7
-:100FA0000B0C40000000000A020D0044000000325B
-:100FB000020D008C02150020020D00900215002089
-:100FC000020D009408100000020D0098000000338C
-:100FD000020D009C00000002020D00A000000000B5
-:100FE000020D00A400000005020D00A8000000058D
-:100FF000060D00AC00000002020D00B4000000026B
-:10100000020D00B800000003020D00BC0000000249
-:10101000020D00C000000001020D00C80000000227
-:10102000020D00CC00000002020D010800000001CA
-:10103000020D015C00000001020D016400000001CE
-:10104000020D016800000002020D02040000000110
-:10105000020D020C00000020020D021000000040F2
-:10106000020D021400000040020D022000000003E7
-:10107000020D022400000018060D0280000000127C
-:10108000040D03000024027E020D004C000000014C
-:10109000020D005000000002020D00540000000884
-:1010A000020D005800000008060D005C000000045E
-:1010B000020D00C400000004020D00040000000145
-:1010C000020D000800000001020D000C00000001EC
-:1010D000020D001000000001020D001400000001CC
-:1010E000020D001800000001020D001C00000001AC
-:1010F000020D002000000001020D0024000000018C
-:10110000020D002800000001020D002C000000016B
-:10111000020D003000000001020D0034000000014B
-:10112000020D003800000001020D003C000000012B
-:10113000020D011400000009020D011C0000000A4C
-:10114000020D012400000007020D012C0000000721
-:10115000020D01340000000C020D013C0000000BE8
-:10116000020D014400000007020D011800000029D3
-:10117000020D01200000002A020D012800000027B6
-:10118000020D013000000027020D01380000002C84
-:10119000020D01400000002B020D01480000002755
-:1011A000020D011400000019020D011C0000001ABC
-:1011B000020D012400000017020D012C0000001791
-:1011C000020D01340000001C020D013C0000001B58
-:1011D000020D014400000017020D01180000003943
-:1011E000020D01200000003A020D01280000003726
-:1011F000020D013000000037020D01380000003CF4
-:10120000020D01400000003B020D014800000037C4
-:10121000020D011400000049020D011C0000004AEB
-:10122000020D012400000047020D012C00000047C0
-:10123000020D01340000004C020D013C0000004B87
-:10124000020D014400000047020D01180000006972
-:10125000020D01200000006A020D01280000006755
-:10126000020D013000000067020D01380000006C23
-:10127000020D01400000006B020D014800000067F4
-:10128000020D011400000059020D011C0000005A5B
-:10129000020D012400000057020D012C0000005730
-:1012A000020D01340000005C020D013C0000005BF7
-:1012B000020D014400000057020D011800000079E2
-:1012C000020D01200000007A020D012800000077C5
-:1012D000020D013000000077020D01380000007C93
-:1012E000020D01400000007B020D01480000007764
-:1012F000020E004C00000032020E00940215002085
-:10130000020E009802150020020E009C0000003022
-:10131000020E00A008100000020E00A4000000331E
-:10132000020E00A800000030020E00AC00000031E8
-:10133000020E00B000000002020E00B40000000423
-:10134000020E00B800000000020E00BC0000000207
-:10135000020E00C000000002020E00C400000000E7
-:10136000020E00C800000002020E00CC00000007C0
-:10137000020E00D000000002020E00D400000002A5
-:10138000020E00D800000001020E00E4000000017F
-:10139000020E014400000001020E014C0000000199
-:1013A000020E015000000002020E020400000001C3
-:1013B000020E020C00000040020E0210000000406D
-:1013C000020E021C00000004020E02200000002099
-:1013D000020E02240000000E020E02280000001B74
-:1013E000060E030000000012040E0280001B02A281
-:1013F000020E00540000000C020E0058000000090C
-:10140000020E005C0000000F020E006000000010E1
-:10141000020E00640000000B060E006800000003CE
-:10142000020E00DC00000003020E000400000001B8
-:10143000020E000800000001020E000C0000000176
-:10144000020E001000000001020E00140000000156
-:10145000020E001800000001020E001C0000000136
-:10146000020E002000000001020E00240000000116
-:10147000020E002800000001020E002C00000001F6
-:10148000020E003000000001020E003400000001D6
-:10149000020E003800000001020E003C00000001B6
-:1014A000020E004000000001020E00440000000196
-:1014B000020E01100000000F020E01180000000EC5
-:1014C000020E012000000000020E012800000000B2
-:1014D000020E01140000002F020E011C0000002E5D
-:1014E000020E012400000000020E012C000000008A
-:1014F000020E01100000001F020E01180000001E65
-:10150000020E012000000000020E01280000000071
-:10151000020E01140000003F020E011C0000003EFC
-:10152000020E012400000000020E012C0000000049
-:10153000020E01100000004F020E01180000004EC4
-:10154000020E012000000000020E01280000000031
-:10155000020E01140000006F020E011C0000006E5C
-:10156000020E012400000000020E012C0000000009
-:10157000020E01100000005F020E01180000005E64
-:10158000020E012000000000020E012800000000F1
-:10159000020E01140000007F020E011C0000007EFC
-:1015A000020E012400000000020E012C00000000C9
-:1015B0000730040000E50000083007D8000502BD30
-:1015C000073400002EF7000007348000311A0BBEEC
-:1015D00007350000356F18050735800038C42561D0
-:1015E0000736000014C5339308363400398002BF33
-:1015F0000130000000000000013000040000000085
-:1016000001300008000000000130000C0000000064
-:101610000130001000000000013000140000000044
-:10162000023000200000000102300024000000020F
-:1016300002300028000000030230002C00000000EF
-:1016400002300030000000040230003400000001CD
-:1016500002300038000000000230003C00000001B1
-:10166000023000400000000402300044000000008E
-:1016700002300048000000010230004C000000036E
-:101680000230005000000000023000540000000151
-:1016900002300058000000040230005C000000002E
-:1016A000023000600000000102300064000000030E
-:1016B00002300068000000000230006C00000001F1
-:1016C00002300070000000040230007400000000CE
-:1016D00002300078000000040230007C00000003AB
-:1016E0000630008000000002023000A400003FFF2E
-:1016F000023000A8000003FF0230022400000000B6
-:1017000002300234000000000230024C00000000F1
-:10171000023002E40000FFFF063020000000080055
-:1017200002338BC000000001023380000000001A69
-:10173000023380400000004E023380800000001021
-:10174000023380C0000000200C3383000007A1207A
-:101750000A338300000001380B3383000000138834
-:10176000023383C0000001F40C3383801DCD65007B
-:101770000A3383800004C4B40B338380004C4B4095
-:101780000A331480000000000233148000000001BE
-:10179000063220000000010206328020000000C84E
-:1017A000063280000000000206323DA8000000045E
-:1017B00006323D800000000904323DA4000102C150
-:1017C00006323D00000000200632500000000400F8
-:1017D0000632400000000004063240D00000000243
-:1017E00006326B680000000204326B70000202C215
-:1017F00006326B1000000002043274C0000202C402
-:101800000632DA40000000020632E0000000080064
-:10181000023308000100000004330C00001002C66F
-:10182000023308000000000004330C40001002D610
-:1018300006322450000000B406322AD00000000214
-:1018400006321000000001A002323DB80000000086
-:101850000632500000000020063251000000002037
-:101860000632520000000020063253000000002023
-:10187000063254000000002006325500000000200F
-:1018800006325600000000200632570000000020FB
-:1018900006325800000000200632590000000020E7
-:1018A00006325A000000002006325B0000000020D3
-:1018B00006325C000000002006325D0000000020BF
-:1018C00006325E000000002006325F0000000020AB
-:1018D00006326B780000005206326E080000000CE1
-:1018E0000632DA880000000206322720000000B429
-:1018F00006322AD80000000206321680000001A03D
-:1019000002323DBC00000000063250800000002082
-:101910000632518000000020063252800000002074
-:101920000632538000000020063254800000002060
-:10193000063255800000002006325680000000204C
-:101940000632578000000020063258800000002038
-:10195000063259800000002006325A800000002024
-:1019600006325B800000002006325C800000002010
-:1019700006325D800000002006325E8000000020FC
-:1019800006325F800000002006326CC0000000526A
-:1019900006326E380000000C0632DA9000000002B9
-:1019A00002322A300000000006324010000000021F
-:1019B0000632D0000000000602322A340000000087
-:1019C00006324020000000020632D0180000000657
-:1019D00002322A38000000000632403000000002C7
-:1019E0000632D0300000000602322A3C000000001F
-:1019F00006324040000000020632D04800000006D7
-:101A000002322A400000000006324050000000026E
-:101A10000632D0600000000602322A4400000000B6
-:101A200006324060000000020632D0780000000656
-:101A300002322A4800000000063240700000000216
-:101A40000632D0900000000602322A4C000000004E
-:101A500006324080000000020632D0A800000006D6
-:101A6000072004000093000008200780001002E611
-:101A7000072400002ADE0000072480002E050AB893
-:101A80000824E4A061D202E8012000000000000068
-:101A900001200004000000000120000800000000F8
-:101AA0000120000C000000000120001000000000D8
-:101AB00001200014000000000220002000000001AE
-:101AC0000220002400000002022000280000000381
-:101AD0000220002C00000000022000300000000462
-:101AE0000220003400000001022000380000000045
-:101AF0000220003C00000001022000400000000421
-:101B00000220004400000000022000480000000104
-:101B10000220004C000000030220005000000000E2
-:101B200002200054000000010220005800000004C0
-:101B30000220005C000000000220006000000001A4
-:101B40000220006400000003022000680000000082
-:101B50000220006C00000001022000700000000460
-:101B60000220007400000000022000780000000441
-:101B70000220007C0000000306200080000000021C
-:101B8000022000A400003FFF022000A8000003FF85
-:101B900002200224000000000220023400000000A5
-:101BA0000220024C00000000022002E40000FFFFBF
-:101BB000062020000000080002238BC00000000166
-:101BC0000223800000000010022380400000001269
-:101BD0000223808000000030022380C00000000E3D
-:101BE000022383C0000001F40223148000000001DE
-:101BF0000A231480000000000622100000000042AA
-:101C000006227020000000C80622700000000002BA
-:101C1000022211E80000000006223000000000C08F
-:101C2000062240700000008006225280000000045E
-:101C30000622670000000100062290000000040058
-:101C400004226B08002002EA02230800013FFFFF84
-:101C500004230C000010030A022308000000000007
-:101C600004230C400010031A06228100000000A08B
-:101C7000062286000000004006228C000000003C86
-:101C80000622B0000000020006228800000000804A
-:101C900006228DE00000003C0622404000000006C5
-:101CA00006228380000000A006228700000000407A
-:101CB00006228CF00000003C0622B8000000020062
-:101CC00006228A000000008006228ED00000003C20
-:101CD000062240580000000606228000000000088E
-:101CE000022211480000000006223300000000021A
-:101CF000062260400000003006228020000000081C
-:101D00000222114C000000000622330800000002ED
-:101D1000062261000000003006228040000000081A
-:101D200002221150000000000622331000000002C1
-:101D3000062261C00000003006228060000000081A
-:101D40000222115400000000062233180000000295
-:101D50000622628000000030062280800000000819
-:101D60000222115800000000062233200000000269
-:101D70000622634000000030062280A00000000818
-:101D80000222115C0000000006223328000000023D
-:101D90000622640000000030062280C00000000817
-:101DA0000222116000000000062233300000000211
-:101DB000062264C000000030062280E00000000817
-:101DC00002221164000000000622333800000002E5
-:101DD0000622658000000030021610000000002876
-:101DE00002170008000000020217002C0000000388
-:101DF0000217003C00000004021700440000000825
-:101E000002170048000000020217004C000000907A
-:101E1000021700500000009002170054008000904C
-:101E20000217005808140000021700600000008A22
-:101E300002170064000000800217006800000081A3
-:101E40000217006C000000800217007000000006FE
-:101E500002170078000007D00217007C0000076C12
-:101E600002170038007C1004021700040000000F65
-:101E70000616402400000002021640700000001CFC
-:101E80000216420800000001021642100000000184
-:101E90000216422000000001021642280000000144
-:101EA0000216423000000001021642380000000114
-:101EB00002164260000000020C16401C0003D09085
-:101EC0000A16401C0000009C0B16401C000009C4B0
-:101ED0000216403000000008021640340000000CDA
-:101EE0000216403800000010021640440000002096
-:101EF0000216400000000001021640D80000000158
-:101F000002164008000000010216400C000000010B
-:101F100002164010000000010216424000000000BE
-:101F2000021642480000000006164270000000023F
-:101F30000216425000000000021642580000000045
-:101F40000616428000000002021660080000042409
-:101F50000216600C00000410021660100000041449
-:101F60000216601C0000FFFF021660200000FFFF49
-:101F7000021660240000FFFF021660280000FFFF29
-:101F800002166038000000200216603C00000020AD
-:101F90000216604000000034021660440000003564
-:101FA00002166048000000230216604C0000002466
-:101FB0000216605000000025021660540000002642
-:101FC00002166058000000270216605C000000291D
-:101FD000021660600000002A021660640000002BF8
-:101FE000021660680000002C0216606C0000002DD4
-:101FF0000616607000000052021661B80000000171
-:10200000061661BC0000001F0216623807FFFFFFC2
-:102010000216623C0000003F0216624007FFFFFF0D
-:10202000021662440000000F011662480000000022
-:102030000116624C00000000011662500000000012
-:1020400001166254000000000116625800000000F2
-:102050000116625C000000000116626000000000D2
-:1020600001166264000000000116626800000000B2
-:102070000116626C00000000011662700000000092
-:102080000116627400000000011662780000000072
-:102090000116627C000000000C166000000003E8DE
-:1020A0000A166000000000010B1660000000000A24
-:1020B0000216804000000006021680440000000561
-:1020C000021680480000000A0216804C000000053D
-:1020D0000216805400000002021680CC00000004AA
-:1020E000021680D000000004021680D40000000414
-:1020F000021680D800000004021680DC00000004F4
-:10210000021680E000000004021680E400000004D3
-:10211000021680E800000004021688040000000493
-:10212000021680300000007C021680340000003D62
-:10213000021680380000003F0216803C0000009C20
-:10214000021680F000000007061680F4000000056B
-:102150000216880C0101010102168108000000002E
-:102160000216810C00000004021681100000000419
-:1021700002168114000000020216881008012004D3
-:1021800002168118000000050216811C00000005DF
-:1021900002168120000000050216812400000005BF
-:1021A0000216882C20081001021681280000000861
-:1021B0000216812C00000006021681300000000784
-:1021C000021681340000000002168830010101204F
-:1021D000061681380000000402168834010101014E
-:1021E00002168148000000000216814C0000000425
-:1021F0000216815000000004021681540000000203
-:1022000002168838080120040216815800000005D3
-:102210000216815C000000050216816000000005C6
-:1022200002168164000000050216883C2008100197
-:1022300002168168000000080216816C000000068A
-:102240000216817000000007021681740000000170
-:102250000216884001010120021681780000000169
-:102260000216817C0000000102168180000000013E
-:102270000216818400000001021688440101010158
-:1022800002168188000000010216818C0000000403
-:1022900002168190000000040216819400000002E2
-:1022A00002168848080120040216819800000005E3
-:1022B0000216819C00000005021681A000000005A6
-:1022C000021681A4000000050216881420081001DF
-:1022D000021681A800000008021681AC000000066A
-:1022E000021681B000000007021681B40000000150
-:1022F0000216881801010120021681B800000001B1
-:10230000021681BC00000001021681C0000000011D
-:10231000021681C4000000010216881C010101019F
-:10232000021681C800000001021681CC00000004E2
-:10233000021681D000000004021681D400000002C1
-:102340000216882008012004021681D8000000052A
-:10235000021681DC00000005021681E00000000585
-:10236000021681E4000000050216882420081001EE
-:10237000021681E800000008021681EC0000000649
-:10238000021681F0000000070216E40C00000000B5
-:1023900002168828010101200616E410000000043E
-:1023A0000216E000010101010216E4200000000015
-:1023B0000216E424000000040216E42800000004D1
-:1023C0000216E42C000000020216E00408012004BA
-:1023D0000216E430000000050216E4340000000597
-:1023E0000216E438000000050216E43C0000000577
-:1023F0000216E008200810010216E4400000000860
-:102400000216E444000000060216E448000000073B
-:102410000216E44C000000000216E00C010101204D
-:102420000616E450000000040216E010010101014C
-:102430000216E460000000000216E46400000004DC
-:102440000216E468000000040216E46C00000002BA
-:102450000216E014080120040216E47000000005D2
-:102460000216E474000000050216E478000000057E
-:102470000216E47C000000050216E0182008100196
-:102480000216E480000000080216E4840000000642
-:102490000216E488000000070216E48C0000000128
-:1024A0000216E01C010101200216E4900000000168
-:1024B0000216E494000000010216E49800000001F6
-:1024C0000216E49C000000010216E0200101010157
-:1024D0000216E4A0000000010216E4A400000004BB
-:1024E0000216E4A8000000040216E4AC000000029A
-:1024F0000216E024080120040216E4B000000005E2
-:102500000216E4B4000000050216E4B8000000055D
-:102510000216E4BC000000050216E02820081001A5
-:102520000216E4C0000000080216E4C40000000621
-:102530000216E4C8000000070216E4CC0000000107
-:102540000216E02C010101200216E4D00000000177
-:102550000216E4D4000000010216E4D800000001D5
-:102560000216E4DC000000010216E0300101010166
-:102570000216E4E0000000010216E4E4000000049A
-:102580000216E4E8000000040216E4EC0000000279
-:102590000216E034080120040216E4F000000005F1
-:1025A0000216E4F4000000050216E4F8000000053D
-:1025B0000216E4FC000000050216E03820081001B5
-:1025C0000216E500000000080216E50400000006FF
-:1025D0000216E508000000070216E03C0101012098
-:1025E00002168240003F003F0216824400000000B5
-:1025F0000216E524003F003F0216E5280000000017
-:1026000002168248000000000216824C003F003F84
-:102610000216E52C000000000216E530003F003FE6
-:1026200002168250010001000216825401000100CE
-:102630000216E534010001000216E5380100010030
-:1026400006168258000000020216E53C0000000059
-:102650000216E540000000000216826000C000C0C3
-:102660000216826400C000C00216E54400C000C02B
-:102670000216E54800C000C0021682681E001E0057
-:102680000216826C1E001E000216E54C1E001E0083
-:102690000216E5501E001E00021682704000400027
-:1026A00002168274400040000216E55440004000CB
-:1026B0000216E55840004000021682788000800033
-:1026C0000216827C800080000216E55C800080009B
-:1026D0000216E56080008000021682802000200043
-:1026E00002168284200020000216E56420002000EB
-:1026F0000216E5682000200006168288000000020D
-:102700000216E56C000000000216E57000000000F3
-:102710000216829000000000021682940000000061
-:102720000216E574000000000216E57800000000C3
-:1027300002168298000000000216829C0000000031
-:102740000216E57C000000000216E5800000000093
-:10275000021682A000000000021682A40000000100
-:10276000061682A80000000A021681F400000C0878
-:10277000021681F800000040021681FC00000100F2
-:1027800002168200000000200216820400000017DA
-:1027900002168208000000800216820C000002006F
-:1027A00002168210000000000216821801FF01FFCD
-:1027B0000216821401FF01FF0216E51001FF01FF5E
-:1027C0000216E50C01FF01FF0216823C0000001317
-:1027D000021680900000013F021680600000014058
-:1027E00002168064000001400616806800000002A6
-:1027F00002168070000000C00616807400000007FA
-:102800000216809C00000048021680A000000048CC
-:10281000061680A400000002021680AC00000048EA
-:10282000061680B000000007021682380000800003
-:1028300002168234000025E40216809400007FFF17
-:1028400002168220000F000F0216821C000F000FDC
-:102850000216E518000F000F0216E514000F000F16
-:10286000021682280000000002168224FFFFFFFFEC
-:102870000216E520000000000216E51CFFFFFFFF26
-:102880000216E6BC000000000216E6C000000002CE
-:102890000216E6C4000000010216E6C800000003AC
-:1028A0000216E6CC000000040216E6D00000000686
-:1028B0000216E6D4000000050216E6D80000000764
-:1028C000021680EC000000FF02140000000000016E
-:1028D0000214000C0000000102140040000000017E
-:1028E0000214004400007FFF0214000C00000000EE
-:1028F00002140000000000000214006C0000000040
-:102900000214000400000001021400300000000165
-:1029100002140004000000000214005C000000002B
-:10292000021400080000000102140034000000013D
-:102930000214000800000000021400600000000003
-:102940000202005800000032020200A0031500201D
-:10295000020200A403150020020200A801000030BA
-:10296000020200AC08100000020200B000000033B8
-:10297000020200B400000030020200B80000003182
-:10298000020200BC00000003020200C000000006BA
-:10299000020200C400000003020200C8000000039D
-:1029A000020200CC00000002020200D00000000081
-:1029B000020200D400000002020200DC000000005D
-:1029C000020200E000000006020200E40000000431
-:1029D000020200E800000002020200EC0000000217
-:1029E000020200F000000001020200FC00000006EC
-:1029F0000202012000000000020201340000000277
-:102A0000020201B0000000010202020C00000001FD
-:102A1000020202140000000102020218000000027B
-:102A200002020404000000010202040C0000004045
-:102A300002020410000000400202041C0000000416
-:102A40000202042000000020020204240000000210
-:102A50000202042800000020060205000000001207
-:102A600004020480001F032A020200600000000F1D
-:102A70000202006400000007020200680000000B70
-:102A80000202006C0000000E020200700000000E46
-:102A90000602007400000003020200F400000004BB
-:102AA0000202000400000001020200080000000110
-:102AB0000202000C000000010202001000000001F0
-:102AC00002020014000000010202001800000001D0
-:102AD0000202001C000000010202002000000001B0
-:102AE0000202002400000001020200280000000190
-:102AF0000202002C00000001020200300000000170
-:102B0000020200340000000102020038000000014F
-:102B10000202003C0000000102020040000000012F
-:102B2000020200440000000102020048000000010F
-:102B30000202004C000000010202005000000001EF
-:102B400002020108000000C8020201180000000291
-:102B5000020201C400000000020201CC00000000DB
-:102B6000020201D400000002020201DC00000002A7
-:102B7000020201E4000000FF020201EC000000FF7D
-:102B800002020100000000000202010C000000C867
-:102B90000202011C00000002020201C80000000045
-:102BA000020201D000000000020201D80000000271
-:102BB000020201E000000002020201E8000000FF42
-:102BC000020201F0000000FF020201040000000008
-:102BD00002020108000000C8020201180000000201
-:102BE000020201C400000000020201CC000000004B
-:102BF000020201D400000002020201DC0000000217
-:102C0000020201E4000000FF020201EC000000FFEC
-:102C100002020100000000000202010C000000C8D6
-:102C20000202011C00000002020201C800000000B4
-:102C3000020201D000000000020201D800000002E0
-:102C4000020201E000000002020201E8000000FFB1
-:102C5000020201F0000000FF020201040000000077
-:102C600002020108000000C8020201180000000270
-:102C7000020201C400000000020201CC00000000BA
-:102C8000020201D400000002020201DC0000000286
-:102C9000020201E4000000FF020201EC000000FF5C
-:102CA00002020100000000000202010C000000C846
-:102CB0000202011C00000002020201C80000000024
-:102CC000020201D000000000020201D80000000250
-:102CD000020201E000000002020201E8000000FF21
-:102CE000020201F0000000FF0202010400000000E7
-:102CF00002020108000000C80202011800000002E0
-:102D0000020201C400000000020201CC0000000029
-:102D1000020201D400000002020201DC00000002F5
-:102D2000020201E4000000FF020201EC000000FFCB
-:102D300002020100000000000202010C000000C8B5
-:102D40000202011C00000002020201C80000000093
-:102D5000020201D000000000020201D800000002BF
-:102D6000020201E000000002020201E8000000FF90
-:102D7000020201F0000000FF020201040000000056
-:102D80000728040000C00000082807A8000B03491A
-:102D9000072C000032FC0000072C800035780CC0A6
-:102DA000072D00003AC11A1F072D800039E228D0F4
-:102DB000072E00001C3E3749082E3710391E034BE2
-:102DC00001280000000000000128000400000000AD
-:102DD00001280008000000000128000C000000008D
-:102DE000012800100000000001280014000000006D
-:102DF0000228002000000001022800240000000238
-:102E000002280028000000030228002C0000000017
-:102E100002280030000000040228003400000001F5
-:102E200002280038000000000228003C00000001D9
-:102E300002280040000000040228004400000000B6
-:102E400002280048000000010228004C0000000396
-:102E50000228005000000000022800540000000179
-:102E600002280058000000040228005C0000000056
-:102E70000228006000000001022800640000000336
-:102E800002280068000000000228006C0000000119
-:102E900002280070000000040228007400000000F6
-:102EA00002280078000000040228007C00000003D3
-:102EB0000628008000000002022800A400003FFF56
-:102EC000022800A8000003FF0228022400000000DE
-:102ED00002280234000000000228024C000000001A
-:102EE000022802E40000FFFF06282000000008007E
-:102EF000022B8BC000000001022B800000000000AC
-:102F0000022B804000000018022B80800000000C83
-:102F1000022B80C0000000660C2B83000007A1205C
-:102F20000A2B8300000001380B2B8300000013885C
-:102F3000022B83C0000001F40C2B8340000001F43D
-:102F40000A2B8340000000000B2B8340000000058B
-:102F50000A2B83800004C4B40C2B83801DCD650034
-:102F60000A2B1480000000000B2B8380004C4B4088
-:102F7000022B148000000001062A29C8000000046A
-:102F8000042A29D80002034D062A208000000048A8
-:102F9000062A9020000000C8062A900000000002C7
-:102FA000062A21A800000086062A20000000002032
-:102FB000022A23C800000000042A23D00002034F85
-:102FC000042A249800040351022A2C500000000017
-:102FD000022A2C1000000000042A2C0800020355CD
-:102FE000042A300000020357062A300800000100BE
-:102FF000062A404000000010042A40000010035937
-:10300000062A6AC000000002062A6B0000000004C5
-:10301000042A840800020369022B08000000000053
-:10302000042B0C000010036B022B080001000000B1
-:10303000042B0C400008037B022B08000200000058
-:10304000042B0C6000080383062AC000000000D88F
-:10305000062A24A800000014062A254800000022A1
-:10306000042A25D00002038B062A266800000022CD
-:10307000042A26F00002038D062A27880000002279
-:10308000042A28100002038F062A28A80000002224
-:10309000042A293000020391062AA000000000281B
-:1030A000062AA1400000000C042A29E00002039334
-:1030B000062A502000000002062A503000000002BC
-:1030C000062A500000000002062A501000000002EC
-:1030D000022A520800000001042A6AC8000203956F
-:1030E000062A6B1000000042062A6D200000000432
-:1030F000062ABCD000000002062AC360000000D8E7
-:10310000062A24F800000014062A25D80000002210
-:10311000042A266000020397062A26F800000022EF
-:10312000042A278000020399062A2818000000229A
-:10313000042A28A00002039B062A29380000002246
-:10314000042A29C00002039D062AA0A0000000282E
-:10315000062AA1700000000C042A29E80002039F3F
-:10316000062A502800000002062A503800000002FB
-:10317000062A500800000002062A5018000000022B
-:10318000022A520C00000001042A6AD0000203A1A6
-:10319000062A6C1800000042062A6D300000000468
-:1031A000062ABCD800000002022AC6C000000000A7
-:1031B000042A29F0001003A3062A50480000000E3C
-:1031C000062AB00000000006022AC6C40000000063
-:1031D000042A2A30001003B3062A50800000000E93
-:1031E000062AB01800000006022AC6C80000000027
-:1031F000042A2A70001003C3062A50B80000000EEB
-:10320000062AB03000000006022AC6CC00000000EA
-:10321000042A2AB0001003D3062A50F00000000E42
-:10322000062AB04800000006022AC6D000000000AE
-:10323000042A2AF0001003E3062A51280000000E99
-:10324000062AB06000000006022AC6D40000000072
-:10325000042A2B30001003F3062A51600000000EF0
-:10326000062AB07800000006022AC6D80000000036
-:10327000042A2B7000100403062A51980000000E47
-:10328000062AB09000000006022AC6DC00000000FA
-:10329000042A2BB000100413062A51D00000000E9F
-:1032A000062AB0A800000006021010080000000165
-:1032B0000210105000000001021010000003D000A6
-:1032C000021010040000003D091018000200042341
-:1032D0000910110000280623061011A00000001894
-:1032E00006102400000000E00210201C0000000076
-:1032F0000210202000000001021020C00000000287
-:10330000021020040000000102102008000000014B
-:1033100009103C000005064B091038000005065056
-:10332000091038200005065506104C000000010069
-:1033300002104028000000100210404400003FFF2F
-:103340000210405800280000021040840084924A75
-:1033500002104058000000000210800000001080A1
-:10336000021080AC00000000021080380000001045
-:103370000210810000000000061081200000000201
-:1033800002108008000002B502108010000000004A
-:10339000061082000000004A021081080001FFFFB1
-:1033A00006108140000000020210800000001A8018
-:1033B0000610900000000024061091200000004A32
-:1033C000061093700000004A061095C00000004AE5
-:1033D0000210800400001080021080B00000000184
-:1033E0000210803C00000010021081040000000068
-:1033F00006108128000000020210800C000002B5B7
-:103400000210801400000000061084000000004A32
-:103410000210810C0001FFFF06108148000000022D
-:103420000210800400001A80061090900000002412
-:10343000061092480000004A061094980000004AC6
-:10344000061096E80000004A02108000000010807C
-:10345000021080AC00000002021080380000001052
-:103460000210810000000000061081200000000210
-:1034700002108008000002B5021080100000000059
-:10348000061082000000004A021081080001FFFFC0
-:1034900006108140000000020210800000001A8027
-:1034A0000610900000000024061091200000004A41
-:1034B000061093700000004A061095C00000004AF4
-:1034C0000210800400001080021080B00000000391
-:1034D0000210803C00000010021081040000000077
-:1034E00006108128000000020210800C000002B5C6
-:1034F0000210801400000000061084000000004A42
-:103500000210810C0001FFFF06108148000000023C
-:103510000210800400001A80061090900000002421
-:10352000061092480000004A061094980000004AD5
-:10353000061096E80000004A02108000000010808B
-:10354000021080AC0000000402108038000000105F
-:10355000021081000000000006108120000000021F
-:1035600002108008000002B5021080100000000068
-:10357000061082000000004A021081080001FFFFCF
-:1035800006108140000000020210800000001A8036
-:103590000610900000000024061091200000004A50
-:1035A000061093700000004A061095C00000004A03
-:1035B0000210800400001080021080B0000000059E
-:1035C0000210803C00000010021081040000000086
-:1035D00006108128000000020210800C000002B5D5
-:1035E0000210801400000000061084000000004A51
-:1035F0000210810C0001FFFF06108148000000024C
-:103600000210800400001A80061090900000002430
-:10361000061092480000004A061094980000004AE4
-:10362000061096E80000004A02108000000010809A
-:10363000021080AC0000000602108038000000106C
-:10364000021081000000000006108120000000022E
-:1036500002108008000002B5021080100000000077
-:10366000061082000000004A021081080001FFFFDE
-:1036700006108140000000020210800000001A8045
-:103680000610900000000024061091200000004A5F
-:10369000061093700000004A061095C00000004A12
-:1036A0000210800400001080021080B000000007AB
-:1036B0000210803C00000010021081040000000095
-:1036C00006108128000000020210800C000002B5E4
-:1036D0000210801400000000061084000000004A60
-:1036E0000210810C0001FFFF06108148000000025B
-:1036F0000210800400001A80061090900000002440
-:10370000061092480000004A061094980000004AF3
-:10371000061096E80000004A021205B00000000101
-:103720000212049000E383400212051400003C10D2
-:103730000212066C00000001021206700000000078
-:1037400002120494FFFFFFFF02120498FFFFFFFF25
-:103750000212049CFFFFFFFF021204A0FFFFFFFF05
-:10376000021204A4FFFFFFFF021204A8FFFFFFFFE5
-:10377000021204ACFFFFFFFF021204B0FFFFFFFFC5
-:10378000021204BCFFFFFFFF021204C0FFFFFFFF95
-:10379000021204C4FFFFFFFF021204C8FFFFFFFF75
-:1037A000021204CCFFFFFFFF021204D0FFFFFFFF55
-:1037B000021204D8FFFFFFFF021204DCFFFFFFFF2D
-:1037C000021204E0FFFFFFFF021204E4FFFFFFFF0D
-:1037D000021204E8FFFFFFFF021204ECFFFFFFFFED
-:1037E000021204F0FFFFFFFF021204F4FFFFFFFFCD
-:1037F000021204F8FFFFFFFF021204FCFFFFFFFFAD
-:1038000002120500FFFFFFFF02120504FFFFFFFF8A
-:1038100002120508FFFFFFFF0212050CFFFFFFFF6A
-:1038200002120510FFFFFFFF021204D4FF802000E8
-:10383000021204B4F0005000021204B8F0001000AC
-:1038400002120390000000080212039C000000080E
-:10385000021203A000000008021203A400000002EC
-:10386000021203BC00000004021203C000000005A5
-:10387000021203C400000004021203D00000000082
-:103880000212036C00000001021203680000003FF6
-:10389000021201BC00000040021201C00000180822
-:1038A000021201C400000803021201C8000008034C
-:1038B000021201CC00000040021201D000000003FF
-:1038C000021201D400000803021201D8000008030C
-:1038D000021201DC00000803021201E000010003F3
-:1038E000021201E400000803021201E800000803CC
-:1038F000021201EC00000003021201F000000003BC
-:10390000021201F400000003021201F8000000039B
-:10391000021201FC0000000302120200000000037A
-:103920000212020400000003021202080000000359
-:103930000212020C00000003021202100000000339
-:103940000212021400000003021202180000000319
-:103950000212021C000000030212022000000003F9
-:1039600002120224000000030212022800002403B5
-:103970000212022C0000002F021202300000000987
-:103980000212023400000019021202380000018401
-:103990000212023C000001830212024000000306F2
-:1039A0000212024400000019021202480000000640
-:1039B0000212024C0000030602120250000003062D
-:1039C00002120254000003060212025800000C8684
-:1039D0000212025C000003060212026000000306ED
-:1039E00002120264000000060212026800000006D3
-:1039F0000212026C000000060212027000000006B3
-:103A00000212027400000006021202780000000692
-:103A10000212027C00000006021202800000000672
-:103A20000212028400000006021202880000000652
-:103A30000212028C00000006021202900000000632
-:103A40000212029400000006021202980000000612
-:103A50000212029C00000006021202A000000306EF
-:103A6000021202A400000013021202A800000006C5
-:103A7000021202B000001004021202B4000010048E
-:103A80000212032400106440021203280010644054
-:103A9000021205B400000001021201B00000000192
-:103AA0000600A000000000160200A0EC5554000023
-:103AB0000200A0F0555555550200A0F400005555E0
-:103AC0000200A0F8F00000000200A0FC5554000025
-:103AD0000200A100555555550200A104000055559E
-:103AE0000200A108F00000000200A18C5554000063
-:103AF0000200A190555555550200A194000055555E
-:103B00000200A198F00000000200A19C000000004B
-:103B10000200A1A0000100000200A1A400005014B6
-:103B20000200A1A8000000000200A45C00000C003C
-:103B30000200A61C000000030200A06CFF5C000055
-:103B40000200A070FFF55FFF0200A0740000FFFFFD
-:103B50000200A078F00003E00200A07C000000005A
-:103B60000200A0800000A0000600A0840000000564
-:103B70000200A0980FE000000600A09C00000007D3
-:103B80000200A0B8000004000600A0BC0000000372
-:103B90000200A0C8000010000600A0CC0000000336
-:103BA0000200A0D8000040000600A0DC00000003D6
-:103BB0000200A0E8000100000600A22C00000004A2
-:103BC0000200A10CFF5C00000200A110FFF55FFFE6
-:103BD0000200A1140000FFFF0200A118F00003E0A2
-:103BE0000200A11C000000000200A1200000A000B3
-:103BF0000600A124000000050200A1380FE000002B
-:103C00000600A13C000000070200A15800000800C7
-:103C10000600A15C000000030200A1680000200073
-:103C20000600A16C000000030200A17800008000E3
-:103C30000600A17C000000030200A1880002000031
-:103C40000600A23C0000000400000000000000008C
-:103C50000000003100000000000000000000000033
-:103C60000000000000000000000000000000000054
-:103C700000000000000000000000000000310032E1
-:103C80000000000000000000000000000000000034
-:103C90000000000000000000000000000000000024
-:103CA000000000000000000000320056000000008C
-:103CB0000000000000000000000000000000000004
-:103CC00000000000000000000000000000000000F4
-:103CD000000000000056008C000000000000000002
-:103CE000008C009000900094009400980098009C34
-:103CF000009C00A000A000A400A400A800A800ACA4
-:103D000000AC00B100B100B300B300B5000000008A
-:103D100000000000000000000000000000000000A3
-:103D200000000000000000000000000000B50102DB
-:103D30000102010A010A01120112011B011B0124E7
-:103D40000124012D012D01360136013F013F0148BB
-:103D5000014801510151015A00000000000000001B
-:103D60000000000000000000000000000000000053
-:103D70000000000000000000000000000000000043
-:103D80000000000000000000000000000000000033
-:103D90000000000000000000000000000000000023
-:103DA0000000000000000000000000000000000013
-:103DB0000000000000000000000000000000000003
-:103DC00000000000000000000000000000000000F3
-:103DD00000000000000000000000000000000000E3
-:103DE00000000000000000000000000000000000D3
-:103DF00000000000000000000000000000000000C3
-:103E00000000000000000000015A015F00000000F7
-:103E100000000000015F0160016001610161016259
-:103E2000016201630163016401640165016501666A
-:103E300001660167000000000000000000000000B3
-:103E40000000000000000000000000000000000072
-:103E50000000000000000000000000000000000062
-:103E60000167016C016C0179017901860000000095
-:103E70000000000000000000000000000000000042
-:103E80000000000000000000000000000000000032
-:103E90000000000000000000000000000000000022
-:103EA0000000000000000000000000000000000012
-:103EB00000000000000000000186018700000000F3
-:103EC00000000000000000000000000000000000F2
-:103ED00000000000000000000000000000000000E2
-:103EE00000000000018701BE00000000000000008B
-:103EF00000000000000000000000000000000000C2
-:103F000000000000000000000000000000000000B1
-:103F100001BE01E9000000000000000000000000F8
-:103F20000000000000000000000000000000000091
-:103F300000000000000000000000000001E9021A7B
-:103F40000000000000000000021A022102210228E5
-:103F50000228022F022F02360236023D023D0244A1
-:103F60000244024B024B02520252028A000000003D
-:103F700000000000028A028E028E029202920296D5
-:103F80000296029A029A029E029E02A202A202A631
-:103F900002A602AA02AA02FA02FA031103110328D6
-:103FA0000328032B032B032E032E03310331033489
-:103FB000033403370337033A033A033D033D034019
-:103FC00003400381038103880388038F038F0393D6
-:103FD000039303970397039B039B039F039F03A3F1
-:103FE00003A303A703A703AB03AB03AF03AF03B064
-:103FF00000000000000000000000000000000000C1
-:1040000000000000000000000000000000000000B0
-:10401000000000000000000003B003C20000000028
-:104020000000000000000000000000000000000090
-:104030000000000000000000000000000000000080
-:104040000000000003C203D703D703DA03DA03DD5D
-:104050000000000000000000000000000000000060
-:104060000000000000000000000000000000000050
-:1040700003DD040A00000000000000000000000052
-:104080000000000000000000000000000000000030
-:10409000000000000000000000000000040A050D00
-:1040A0000000000000000000000000000000000010
-:1040B0000000000000000000000000000000000000
-:1040C0000000000000000000050D0514051405188F
-:1040D0000518051C000000000000000000000000A2
-:1040E00000000000000000000000000000000000D0
-:1040F00000000000051C055C00000000000000003E
-:10410000055C05650565056E056E05770577058017
-:1041100005800589058905920592059B059B05A4E7
-:1041200005A405FD05FD0613061306290629062D1F
-:10413000062D063106310635063506390639063DA7
-:10414000063D064106410645064506490649065014
-:10415000000000000000000000000000000000005F
-:10416000000000000000000000000000000000004F
-:10417000000000000000000006500656000000008D
-:10418000000000000000000000000000000000002F
-:10419000000000000000000000000000000000001F
-:1041A0000000000006560659000000000000000054
-:1041B00000000000000000000000000000000000FF
-:1041C00000000000000000000000000000000000EF
-:1041D0000659065F0000000000000000000000001B
-:1041E00000000000000000000000000000000000CF
-:1041F00000000000000000000000000000000000BF
-:104200000000000000000000065F066E066E067DDE
-:10421000067D068C068C069B069B06AA06AA06B996
-:1042200006B906C806C806D706D70748000000002A
-:10423000000000000000000000000000000000007E
-:10424000000000000000000000000000000000006E
-:10425000000000000748075B075B076C076C077DE1
-:10426000000000000000000000000000000000004E
-:10427000000000000000000000000000000000003E
-:10428000000000000000000000000000000000002E
-:10429000000000000000000000000000000000001E
-:1042A000000000000000000000000000000000000E
-:1042B00000000000000000000000000000000000FE
-:1042C00000000000000000000000000000000000EE
-:1042D00000000000000000000000000000000000DE
-:1042E00000010000000204C00003098000040E4029
-:1042F00000051300000617C000071C8000082140BD
-:1043000000092600000A2AC0000B2F80000C344050
-:10431000000D3900000E3DC0000F428000104740E4
-:1043200000114C00001250C00013558000145A4078
-:1043300000155F00001663C00017688000186D400C
-:1043400000197200001A76C0001B7B80001C8040A0
-:10435000001D8500001E89C0001F8E800020934034
-:10436000000020000000400000006000000080000D
-:104370000000A0000000C0000000E00000010000FC
-:1043800000012000000140000001600000018000E9
-:104390000001A0000001C0000001E00000020000D8
-:1043A00000022000000240000002600000028000C5
-:1043B0000002A0000002C0000002E00000030000B4
-:1043C00000032000000340000003600000038000A1
-:1043D0000003A0000003C0000003E0000004000090
-:1043E000000420000004400000046000000480007D
-:1043F0000004A0000004C0000004E000000500006C
-:104400000005200000054000000560000005800058
-:104410000005A0000005C0000005E0000006000047
-:104420000006200000064000000660000006800034
-:104430000006A0000006C0000006E0000007000023
-:104440000007200000074000000760000007800010
-:104450000007A0000007C0000007E00000080000FF
-:1044600000082000000840000008600000088000EC
-:104470000008A0000008C0000008E00000090000DB
-:1044800000092000000940000009600000098000C8
-:104490000009A0000009C0000009E000000A0000B7
-:1044A000000A2000000A4000000A6000000A8000A4
-:1044B000000AA000000AC000000AE000000B000093
-:1044C000000B2000000B4000000B6000000B800080
-:1044D000000BA000000BC000000BE000000C00006F
-:1044E000000C2000000C4000000C6000000C80005C
-:1044F000000CA000000CC000000CE000000D00004B
-:10450000000D2000000D4000000D6000000D800037
-:10451000000DA000000DC000000DE000000E000026
-:10452000000E2000000E4000000E6000000E800013
-:10453000000EA000000EC000000EE000000F000002
-:10454000000F2000000F4000000F6000000F8000EF
-:10455000000FA000000FC000000FE00000100000DE
-:1045600000102000001040000010600000108000CB
-:104570000010A0000010C0000010E00000110000BA
-:1045800000112000001140000011600000118000A7
-:104590000011A0000011C0000011E0000012000096
-:1045A0000012200000124000001260000012800083
-:1045B0000012A0000012C0000012E0000013000072
-:1045C000001320000013400000136000001380005F
-:1045D0000013A0000013C0000013E000001400004E
-:1045E000001420000014400000146000001480003B
-:1045F0000014A0000014C0000014E000001500002A
-:104600000015200000154000001560000015800016
-:104610000015A0000015C0000015E0000016000005
-:1046200000162000001640000016600000168000F2
-:104630000016A0000016C0000016E00000170000E1
-:1046400000172000001740000017600000178000CE
-:104650000017A0000017C0000017E00000180000BD
-:1046600000182000001840000018600000188000AA
-:104670000018A0000018C0000018E0000019000099
-:104680000019200000194000001960000019800086
-:104690000019A0000019C0000019E000001A000075
-:1046A000001A2000001A4000001A6000001A800062
-:1046B000001AA000001AC000001AE000001B000051
-:1046C000001B2000001B4000001B6000001B80003E
-:1046D000001BA000001BC000001BE000001C00002D
-:1046E000001C2000001C4000001C6000001C80001A
-:1046F000001CA000001CC000001CE000001D000009
-:10470000001D2000001D4000001D6000001D8000F5
-:10471000001DA000001DC000001DE000001E0000E4
-:10472000001E2000001E4000001E6000001E8000D1
-:10473000001EA000001EC000001EE000001F0000C0
-:10474000001F2000001F4000001F6000001F8000AD
-:10475000001FA000001FC000001FE000002000009C
-:104760000020200000204000002060000020800089
-:104770000020A0000020C0000020E0000021000078
-:104780000021200000214000002160000021800065
-:104790000021A0000021C0000021E0000022000054
-:1047A0000022200000224000002260000022800041
-:1047B0000022A0000022C0000022E0000023000030
-:1047C000002320000023400000236000002380001D
-:1047D0000023A0000023C0000023E000002400000C
-:1047E00000242000002440000024600000248000F9
-:1047F0000024A0000024C0000024E00000250000E8
-:1048000000252000002540000025600000258000D4
-:104810000025A0000025C0000025E00000260000C3
-:1048200000262000002640000026600000268000B0
-:104830000026A0000026C0000026E000002700009F
-:10484000002720000027400000276000002780008C
-:104850000027A0000027C0000027E000002800007B
-:104860000028200000284000002860000028800068
-:104870000028A0000028C0000028E0000029000057
-:104880000029200000294000002960000029800044
-:104890000029A0000029C0000029E000002A000033
-:1048A000002A2000002A4000002A6000002A800020
-:1048B000002AA000002AC000002AE000002B00000F
-:1048C000002B2000002B4000002B6000002B8000FC
-:1048D000002BA000002BC000002BE000002C0000EB
-:1048E000002C2000002C4000002C6000002C8000D8
-:1048F000002CA000002CC000002CE000002D0000C7
-:10490000002D2000002D4000002D6000002D8000B3
-:10491000002DA000002DC000002DE000002E0000A2
-:10492000002E2000002E4000002E6000002E80008F
-:10493000002EA000002EC000002EE000002F00007E
-:10494000002F2000002F4000002F6000002F80006B
-:10495000002FA000002FC000002FE000003000005A
-:104960000030200000304000003060000030800047
-:104970000030A0000030C0000030E0000031000036
-:104980000031200000314000003160000031800023
-:104990000031A0000031C0000031E0000032000012
-:1049A00000322000003240000032600000328000FF
-:1049B0000032A0000032C0000032E00000330000EE
-:1049C00000332000003340000033600000338000DB
-:1049D0000033A0000033C0000033E00000340000CA
-:1049E00000342000003440000034600000348000B7
-:1049F0000034A0000034C0000034E00000350000A6
-:104A00000035200000354000003560000035800092
-:104A10000035A0000035C0000035E0000036000081
-:104A2000003620000036400000366000003680006E
-:104A30000036A0000036C0000036E000003700005D
-:104A4000003720000037400000376000003780004A
-:104A50000037A0000037C0000037E0000038000039
-:104A60000038200000384000003860000038800026
-:104A70000038A0000038C0000038E0000039000015
-:104A80000039200000394000003960000039800002
-:104A90000039A0000039C0000039E000003A0000F1
-:104AA000003A2000003A4000003A6000003A8000DE
-:104AB000003AA000003AC000003AE000003B0000CD
-:104AC000003B2000003B4000003B6000003B8000BA
-:104AD000003BA000003BC000003BE000003C0000A9
-:104AE000003C2000003C4000003C6000003C800096
-:104AF000003CA000003CC000003CE000003D000085
-:104B0000003D2000003D4000003D6000003D800071
-:104B1000003DA000003DC000003DE000003E000060
-:104B2000003E2000003E4000003E6000003E80004D
-:104B3000003EA000003EC000003EE000003F00003C
-:104B4000003F2000003F4000003F6000003F800029
-:104B5000003FA000003FC000003FE000003FE00138
-:104B600000000000000001FF0000020000007FF8CC
-:104B700000007FF800000CDF0000150000000001BD
-:104B80000000000100000001FFFFFFFFFFFFFFFF2B
-:104B9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25
-:104BA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF15
-:104BB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05
-:104BC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5
-:104BD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5
-:104BE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5
-:104BF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC5
-:104C0000FFFFFFFFFFFFFFFFFFFFFFFF00000000B0
-:104C1000FFFFFFFF00000000FFFFFFFFFFFFFFFFA0
-:104C200000000000FFFFFFFF00000000FFFFFFFF8C
-:104C3000FFFFFFFF00000000FFFFFFFF000000007C
-:104C4000FFFFFFFF0000000300BEBC20FFFFFFFFCF
-:104C500000000000FFFFFFFF00000000FFFFFFFF5C
-:104C60000000000300BEBC20FFFFFFFF00000000AB
-:104C7000FFFFFFFF00000000FFFFFFFF0000000339
-:104C800000BEBC20FFFFFFFF00000000FFFFFFFF92
-:104C900000000000FFFFFFFF0000000300BEBC207B
-:104CA000FFFFFFFF00000000FFFFFFFF000000000C
-:104CB000FFFFFFFF0000000300BEBC20FFFFFFFF5F
-:104CC00000000000FFFFFFFF00000000FFFFFFFFEC
-:104CD0000000000300BEBC2000002000000040C017
-:104CE00000006180000082400000A3000000C3C0FB
-:104CF0000000E4800001054000012600000146C0DC
-:104D000000016780000188400001A9000001C9C0BE
-:104D10000001EA8000020B4000022C0000024CC09F
-:104D200000026D8000028E400002AF000002CFC082
-:104D30000002F0800003114000033200000352C063
-:104D400000037380000394400003B5000003D5C046
-:104D50000003F6800004174000043800000458C027
-:104D60000004798000049A40000080000001038064
-:104D70000001870000020A8000028E0000031180FB
-:104D8000000395000004188000049C0000051F80AB
-:104D90000005A300000626800006AA0000072D805B
-:104DA0000007B100000834800008B80000093B800B
-:104DB0000009BF00000A4280000AC600000B4980BB
-:104DC000000BCD00000C5080000CD400000D57806B
-:104DD000000DDB0000007FF800007FF80000192ABA
-:104DE0000000350000001900001000000000000065
-:104DF00000000000FFFFFFFF400000004000000037
-:104E000040000000400000004000000040000000A2
-:104E10004000000040000000400000004000000092
-:104E20004000000040000000400000004000000082
-:104E30004000000040000000400000004000000072
-:104E40004000000040000000400000004000000062
-:104E50004000000040000000400000004000000052
-:104E60004000000040000000400000004000000042
-:104E7000400000004000000000007FF800007FF8C4
-:104E8000000005C700001500FFFFFFFFFFFFFFFF49
-:104E9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22
-:104EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12
-:104EB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02
-:104EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2
-:104ED000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2
-:104EE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2
-:104EF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2
-:104F0000FFFFFFFFFFFFFFFF400000004000000029
-:104F10004000000040000000400000004000000091
-:104F20004000000040000000400000004000000081
-:104F30004000000040000000400000004000000071
-:104F40004000000040000000400000004000000061
-:104F50004000000040000000400000004000000051
-:104F60004000000040000000400000004000000041
-:104F70004000000040000000400000004000000031
-:104F800040000000400000000000100000002080F1
-:104F900000003100000041800000520000006280EB
-:104FA0000000730000008380000094000000A480D3
-:104FB0000000B5000000C5800000D6000000E680BB
-:104FC0000000F700000107800001180000012880A0
-:104FD000000139000001498000015A0000016A8087
-:104FE00000017B0000018B8000019C000001AC806F
-:104FF0000001BD000001CD800001DE000001EE8057
-:105000000001FF0000007FF800007FF80000112E73
-:105010000000350010000000000028AD0000000076
-:1050200000010001000D0205CCCCCCC5FFFFFFFF45
-:10503000FFFFFFFF7058103C000000000000000060
-:1050400000000001CCCC0201CCCCCCCCCCCC0201F9
-:10505000CCCCCCCCCCCC0201CCCCCCCCCCCC0201BA
-:10506000CCCCCCCCCCCC0201CCCCCCCCCCCC0201AA
-:10507000CCCCCCCCCCCC0201CCCCCCCCCCCC02019A
-:10508000CCCCCCCC00000000FFFFFFFF40000000B4
-:105090004000000040000000400000004000000010
-:1050A0004000000040000000400000004000000000
-:1050B00040000000400000004000000040000000F0
-:1050C00040000000400000004000000040000000E0
-:1050D00040000000400000004000000040000000D0
-:1050E00040000000400000004000000040000000C0
-:1050F00040000000400000004000000040000000B0
-:10510000400000004000000040000000002625A0F4
-:1051100000000000002625A000000000002625A0B9
-:1051200000000000002625A000000000000E023252
-:10513000011600D60010000000000000002625A087
-:1051400000000000002625A000000000002625A089
-:1051500000000000002625A00000000000720236BA
-:10516000012300F300100000000000000000FFFF1A
-:10517000000000000000FFFF000000000000FFFF33
-:10518000000000000000FFFF000000000000FFFF23
-:10519000000000000000FFFF000000000000FFFF13
-:1051A000000000000000FFFF000000000000FFFF03
-:1051B000000000000000FFFF000000000000FFFFF3
-:1051C000000000000000FFFF000000000000FFFFE3
-:1051D000000000000000FFFF000000000000FFFFD3
-:1051E000000000000000FFFF000000000000FFFFC3
-:1051F000000000000000FFFF000000000000FFFFB3
-:10520000000000000000FFFF000000000000FFFFA2
-:10521000000000000000FFFF000000000000FFFF92
-:10522000000000000000FFFF000000000000FFFF82
-:10523000000000000000FFFF000000000000FFFF72
-:10524000000000000000FFFF000000000000FFFF62
-:10525000000000000000FFFF000000000000FFFF52
-:10526000000000000000FFFF000000000000FFFF42
-:10527000000000000000FFFF000000000000FFFF32
-:10528000000000000000FFFF000000000000FFFF22
-:10529000000000000000FFFF000000000000FFFF12
-:1052A000000000000000FFFF000000000000FFFF02
-:1052B000000000000000FFFF000000000000FFFFF2
-:1052C000000000000000FFFF000000000000FFFFE2
-:1052D000000000000000FFFF000000000000FFFFD2
-:1052E000000000000000FFFF000000000000FFFFC2
-:1052F000000000000000FFFF000000000000FFFFB2
-:10530000000000000000FFFF000000000000FFFFA1
-:10531000000000000000FFFF000000000000FFFF91
-:10532000000000000000FFFF000000000000FFFF81
-:10533000000000000000FFFF000000000000FFFF71
-:10534000000000000000FFFF000000000000FFFF61
-:10535000000000000000FFFF000000000000FFFF51
-:10536000000000000000FFFF00000000FFFFFFF34F
-:10537000318FFFFF0C30C30CC30C30C3CF3CF300A4
-:10538000F3CF3CF30000CF3CCDCDCDCDFFFFFFF1FF
-:1053900030EFFFFF0C30C30CC30C30C3CF3CF30025
-:1053A000F3CF3CF30001CF3CCDCDCDCDFFFFFFF6D9
-:1053B000305FFFFF0C30C30CC30C30C3CF3CF30095
-:1053C000F3CF3CF30002CF3CCDCDCDCDFFFFF406B3
-:1053D0001CBFFFFF0C30C305C30C30C3CF3000141B
-:1053E000F3CF3CF30004CF3CCDCDCDCDFFFFFFF29A
-:1053F000304FFFFF0C30C30CC30C30C3CF3CF30065
-:10540000F3CF3CF30008CF3CCDCDCDCDFFFFFFFA6D
-:10541000302FFFFF0C30C30CC30C30C3CF3CF30064
-:10542000F3CF3CF30010CF3CCDCDCDCDFFFFFFF748
-:1054300031EFFFFF0C30C30CC30C30C3CF3CF30083
-:10544000F3CF3CF30020CF3CCDCDCDCDFFFFFFF51A
-:10545000302FFFFF0C30C30CC30C30C3CF3CF30024
-:10546000F3CF3CF30040CF3CCDCDCDCDFFFFFFF3DC
-:10547000318FFFFF0C30C30CC30C30C3CF3CF300A3
-:10548000F3CF3CF30000CF3CCDCDCDCDFFFFFFF1FE
-:10549000310FFFFF0C30C30CC30C30C3CF3CF30003
-:1054A000F3CF3CF30001CF3CCDCDCDCDFFFFFFF6D8
-:1054B000305FFFFF0C30C30CC30C30C3CF3CF30094
-:1054C000F3CF3CF30002CF3CCDCDCDCDFFFFF406B2
-:1054D0001CBFFFFF0C30C305C30C30C3CF3000141A
-:1054E000F3CF3CF30004CF3CCDCDCDCDFFFFFFF299
-:1054F000304FFFFF0C30C30CC30C30C3CF3CF30064
-:10550000F3CF3CF30008CF3CCDCDCDCDFFFFFFFA6C
-:10551000302FFFFF0C30C30CC30C30C3CF3CF30063
-:10552000F3CF3CF30010CF3CCDCDCDCDFFFFFFF747
-:1055300030EFFFFF0C30C30CC30C30C3CF3CF30083
-:10554000F3CF3CF30020CF3CCDCDCDCDFFFFFFF519
-:10555000304FFFFF0C30C30CC30C30C3CF3CF30003
-:10556000F3CF3CF30040CF3CCDCDCDCDFFFFFFF3DB
-:1055700031EFFFFF0C30C30CC30C30C3CF3CF30042
-:10558000F3CF3CF30000CF3CCDCDCDCDFFFFFFF1FD
-:10559000310FFFFF0C30C30CC30C30C3CF3CF30002
-:1055A000F3CF3CF30001CF3CCDCDCDCDFFFFFFF6D7
-:1055B000305FFFFF0C30C30CC30C30C3CF3CF30093
-:1055C000F3CF3CF30002CF3CCDCDCDCDFFFFF406B1
-:1055D0001CBFFFFF0C30C305C30C30C3CF30001419
-:1055E000F3CF3CF30004CF3CCDCDCDCDFFFFFFF298
-:1055F000304FFFFF0C30C30CC30C30C3CF3CF30063
-:10560000F3CF3CF30008CF3CCDCDCDCDFFFFFFFA6B
-:10561000302FFFFF0C30C30CC30C30C3CF3CF30062
-:10562000F3CF3CF30010CF3CCDCDCDCDFFFFFF97A6
-:10563000056FFFFF0C30C30CC30C30C3CF3CC00060
-:10564000F3CF3CF30020CF3CCDCDCDCDFFFFFFF518
-:10565000310FFFFF0C30C30CC30C30C3CF3CF30041
-:10566000F3CF3CF30040CF3CCDCDCDCDFFFFFFF3DA
-:10567000320FFFFF0C30C30CC30C30C3CF3CF30020
-:10568000F3CF3CF30000CF3CCDCDCDCDFFFFFFF1FC
-:10569000310FFFFF0C30C30CC30C30C3CF3CF30001
-:1056A000F3CF3CF30001CF3CCDCDCDCDFFFFFFF6D6
-:1056B000305FFFFF0C30C30CC30C30C3CF3CF30092
-:1056C000F3CF3CF30002CF3CCDCDCDCDFFFFF406B0
-:1056D0001CBFFFFF0C30C305C30C30C3CF30001418
-:1056E000F3CF3CF30004CF3CCDCDCDCDFFFFFFF297
-:1056F000304FFFFF0C30C30CC30C30C3CF3CF30062
-:10570000F3CF3CF30008CF3CCDCDCDCDFFFFFF8ADA
-:10571000042FFFFF0C30C30CC30C30C3CF3CC000C0
-:10572000F3CF3CF30010CF3CCDCDCDCDFFFFFF97A5
-:1057300005CFFFFF0C30C30CC30C30C3CF3CC000FF
-:10574000F3CF3CF30020CF3CCDCDCDCDFFFFFFF517
-:10575000310FFFFF0C30C30CC30C30C3CF3CF30040
-:10576000F3CF3CF30040CF3CCDCDCDCDFFFFFFF3D9
-:10577000316FFFFF0C30C30CC30C30C3CF3CF300C0
-:10578000F3CF3CF30000CF3CCDCDCDCDFFFFFFF1FB
-:10579000302FFFFF0C30C30CC30C30C3CF3CF300E1
-:1057A000F3CF3CF30001CF3CCDCDCDCDFFFFFFF6D5
-:1057B000305FFFFF0C30C30CC30C30C3CF3CF30091
-:1057C000F3CF3CF30002CF3CCDCDCDCDFFFFFFF6B4
-:1057D00030BFFFFF0C30C30CC30C30C3CF3CF314FD
-:1057E000F3CF3CF30004CF3CCDCDCDCDFFFFFFF296
-:1057F000304FFFFF0C30C30CC30C30C3CF3CF30061
-:10580000F3CF3CF30008CF3CCDCDCDCDFFFFFFFA69
-:10581000302FFFFF0C30C30CC30C30C3CF3CF30060
-:10582000F3CF3CF30010CF3CCDCDCDCDFFFFFFF744
-:1058300031CFFFFF0C30C30CC30C30C3CF3CF3009F
-:10584000F3CF3CF30020CF3CCDCDCDCDFFFFFFF01B
-:10585000307FFFFF0C30C30CC30C30C3CF3CF300D0
-:10586000F3CF3CF30040CF3CCDCDCDCDFFFFFFFFCC
-:1058700030CFFFFF0C30C30CC30C30C3CF3CF3CC94
-:10588000F3CF3CF30000CF3CCDCDCDCDFFFFFFFFEC
-:1058900030CFFFFF0C30C30CC30C30C3CF3CF3CC74
-:1058A000F3CF3CF30001CF3CCDCDCDCDFFFFFFFFCB
-:1058B00030CFFFFF0C30C30CC30C30C3CF3CF3CC54
-:1058C000F3CF3CF30002CF3CCDCDCDCDFFFFFFFFAA
-:1058D00030CFFFFF0C30C30CC30C30C3CF3CF3CC34
-:1058E000F3CF3CF30004CF3CCDCDCDCDFFFFFFFF88
-:1058F00030CFFFFF0C30C30CC30C30C3CF3CF3CC14
-:10590000F3CF3CF30008CF3CCDCDCDCDFFFFFFFF63
-:1059100030CFFFFF0C30C30CC30C30C3CF3CF3CCF3
-:10592000F3CF3CF30010CF3CCDCDCDCDFFFFFFFF3B
-:1059300030CFFFFF0C30C30CC30C30C3CF3CF3CCD3
-:10594000F3CF3CF30020CF3CCDCDCDCDFFFFFFFF0B
-:1059500030CFFFFF0C30C30CC30C30C3CF3CF3CCB3
-:10596000F3CF3CF30040CF3CCDCDCDCDFFFFFFFFCB
-:1059700030CFFFFF0C30C30CC30C30C3CF3CF3CC93
-:10598000F3CF3CF30000CF3CCDCDCDCDFFFFFFFFEB
-:1059900030CFFFFF0C30C30CC30C30C3CF3CF3CC73
-:1059A000F3CF3CF30001CF3CCDCDCDCDFFFFFFFFCA
-:1059B00030CFFFFF0C30C30CC30C30C3CF3CF3CC53
-:1059C000F3CF3CF30002CF3CCDCDCDCDFFFFFFFFA9
-:1059D00030CFFFFF0C30C30CC30C30C3CF3CF3CC33
-:1059E000F3CF3CF30004CF3CCDCDCDCDFFFFFFFF87
-:1059F00030CFFFFF0C30C30CC30C30C3CF3CF3CC13
-:105A0000F3CF3CF30008CF3CCDCDCDCDFFFFFFFF62
-:105A100030CFFFFF0C30C30CC30C30C3CF3CF3CCF2
-:105A2000F3CF3CF30010CF3CCDCDCDCDFFFFFFFF3A
-:105A300030CFFFFF0C30C30CC30C30C3CF3CF3CCD2
-:105A4000F3CF3CF30020CF3CCDCDCDCDFFFFFFFF0A
-:105A500030CFFFFF0C30C30CC30C30C3CF3CF3CCB2
-:105A6000F3CF3CF30040CF3CCDCDCDCDFFFFFFFFCA
-:105A700030CFFFFF0C30C30CC30C30C3CF3CF3CC92
-:105A8000F3CF3CF30000CF3CCDCDCDCDFFFFFFFFEA
-:105A900030CFFFFF0C30C30CC30C30C3CF3CF3CC72
-:105AA000F3CF3CF30001CF3CCDCDCDCDFFFFFFFFC9
-:105AB00030CFFFFF0C30C30CC30C30C3CF3CF3CC52
-:105AC000F3CF3CF30002CF3CCDCDCDCDFFFFFFFFA8
-:105AD00030CFFFFF0C30C30CC30C30C3CF3CF3CC32
-:105AE000F3CF3CF30004CF3CCDCDCDCDFFFFFFFF86
-:105AF00030CFFFFF0C30C30CC30C30C3CF3CF3CC12
-:105B0000F3CF3CF30008CF3CCDCDCDCDFFFFFFFF61
-:105B100030CFFFFF0C30C30CC30C30C3CF3CF3CCF1
-:105B2000F3CF3CF30010CF3CCDCDCDCDFFFFFFFF39
-:105B300030CFFFFF0C30C30CC30C30C3CF3CF3CCD1
-:105B4000F3CF3CF30020CF3CCDCDCDCDFFFFFFFF09
-:105B500030CFFFFF0C30C30CC30C30C3CF3CF3CCB1
-:105B6000F3CF3CF30040CF3CCDCDCDCD000C0000B9
-:105B7000000700C000028130000B815800020210B3
-:105B800000010230000F024000010330000C000051
-:105B9000000800C000028140000B81680002022062
-:105BA0000001024000070250000202C0000F000086
-:105BB000000800F000028170000B81980002025082
-:105BC00000010270000B8280000803380010000002
-:105BD0000008010000028180000B81A80002026021
-:105BE00000018280000E829800080380000B0000F4
-:105BF000000100B0000280C0000580E80002014002
-:105C000000010160000E017000038250CCCCCCCCAE
-:105C1000CCCCCCCCCCCCCCCCCCCCCCCC00002000D4
-:105C2000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCB4
-:105C300000002000CCCCCCCCCCCCCCCCCCCCCCCCB4
-:105C4000CCCCCCCC04002000000000000000000000
-:105C50001F8B080000000000000BFB51CFC0F003B9
-:105C60008A59051918AC84117C7A607E4ECAF43BBF
-:105C7000F232303803B12B103700F1616E06862303
-:105C8000DCC4EB3F298F607BCB32309403F1766923
-:105C90000606133984B8AE0203C33C203F012AF63E
-:105CA000144867CB53E6EEC182155431C564951193
-:105CB0006C452CF2C858094DBE461995AF4C40FFB3
-:105CC00040E3781D547E8F16847EAD0DA113D0E481
-:105CD0007BA1F28E507F25EA6037D789487FA7B233
-:105CE000A0B9078DDFCA88CA37E340E52741D5034D
-:105CF000000749300AC8030000000000000000004F
-:105D00001F8B080000000000000BED7D0D7854D5BE
-:105D1000B5E83E73CE9C9949CE4C26BF4C20C04975
-:105D2000082168A4C70069B0584F2060A8D40E1499
-:105D300069AC8A032244082452EBC3ABFD328100D4
-:105D4000010204B13414A44300A5B7B43752B4D44B
-:105D5000523AE0A7C5D6F7BDE0B356AFB66FB4145C
-:105D60007F8A12F3AED6BE6BEBDB6BEDBD93734E49
-:105D7000664810BDED7DEFC6CFEFB0CFD93F6BAF1A
-:105D8000BFBDD6DA6BEF71BBFC246F34211FC3DFBC
-:105D90007584FC2F8D1092DBFF747B4934FD738476
-:105DA00064E698D1441921C372CC389944DF075571
-:105DB000DD23F5B713CF9399334350AF25D70C119B
-:105DC000DA474BE67C1281BE227584E411A2780981
-:105DD000FE89FAEEE05C2F29C3577FFB587C9709B8
-:105DE00059172CCA8076CEFE09891132D95A7611FC
-:105DF00022FAA4EDBC006F068557A72F289C699353
-:105E00005CB1EB0B29DC7A0CE14E2FA070D3F2C908
-:105E100091CF78C7D0F2A66B5D86075BDF4D480552
-:105E200021ABA02FDA76D35571FE5D31A03C433E05
-:105E3000DCAC427B9D181E5AF65FD51857B19DA960
-:105E4000E5D37641C2DA054B97CC261308C930D585
-:105E50007EB8583D9C7F3AAFE7D1E9F7D2FEEFE933
-:105E6000A4ED3D3900A50409FB69FF958EEFA5332C
-:105E7000DF807ED389A55F3A8FEDF08F7C42BE40F4
-:105E8000FC39E7A0F3CF93CF031E487516215306C4
-:105E9000E2AF1F6F51A42F217536B8041D3418636B
-:105EA0000C21D7B7265E72E550784C17013CCD9493
-:105EB00035DF185ADE765A463C6CABEDF106359C60
-:105EC000DFEC7CDA6E34EF677425C5039DCF9E2628
-:105ED0005AF60CC46FC1A46E13F8C33FA95B22B479
-:105EE000BF0283906C3A9F60232D17D176247E6683
-:105EF0000CE52FF2009B6F94FEF771513F1E331992
-:105F00000A88E6C07326E091E2A9E01EC7FB4A8634
-:105F1000BF4C62C16B217213E2E90EC0DF95C8F37A
-:105F200063117FD12CC4EB50F127E011F80B723EC6
-:105F3000BEBE2651AB00DF4CA5F8037C513CA6D376
-:105F4000F9F6BEE489C985D08DD91D027C8BF95440
-:105F500032FED9C2E1DA08F81B879F5CAE1021BE81
-:105F6000B22E93C94B5C82727A199D01EDCF6732D4
-:105F7000FCCD903509C6DB5CCAF8940E20B92A071F
-:105F8000C245FFB0FD660A8F668167B3B7CB2BD1E0
-:105F9000F2760A6F14F04F8E04811FC5BC3DBACB58
-:105FA00086572594E6E07306A7806FBBC9E4D80244
-:105FB00007BE27DD5DAD1285F383192EB2491ABCE9
-:105FC000DF6D7DFDD8FB77F63B287C89A0AF98CEAE
-:105FD000EF8367656313C5CF66BDABD545E1D85682
-:105FE000CDE63B90CE97395E4F8FB77892653C8374
-:105FF000C9CBA73E0EC9B4CFAB32E80B965DFE38D5
-:1060000024B87034D03F153D3E35F8750ABF054FB2
-:10601000BEE2A004FDFBAE7AD04B50EE8F78010EAD
-:10602000E73803E0758CEB1C47298D9A0A96ECFA49
-:10603000C8138C1162D12F58478727D3CBE9865DCF
-:106040009FF84AEDFAD9A9CF15D03701686FD7D795
-:106050003D42CF083D3D69887AC6AC43788B48DF26
-:106060001FCAF3182ECFD30F253ABC147FC57B84EB
-:106070009E7EE057A5941F0E829EA6E5831D04D741
-:10608000C38347498CC935D3D713786713B8DEF972
-:10609000419FBEB1E3E7CA76731AE89D3262BA7CCB
-:1060A000B49F31878911A7EF0F93F8DCF1A0C78E59
-:1060B000B1F97BE97F563D7D05C7E395871B5D40C0
-:1060C000CF317BEC78BC82E3B7ECA8E33DC7DF15AA
-:1060D0000EFC6D837F507CE54B1C8F634909E27198
-:1060E000EA10D73B8E47A7BEEEC3E31EAAAF29DE58
-:1060F000B2830C8F2D6D2E02FAA137E642FD585A5D
-:10610000D8E842FDC9F5F6783EBFF17CBD3BC0F151
-:1061100027E02C9E6D5401DEC612E324E8E5CC7620
-:106120008A37027ABAA00ACA3B1E22489FB10FE9F9
-:106130002EAEDF109E4CBEFEEEA82E7F16E4A2F718
-:1061400021C590E9380789B1C62BF5E3379B8F9FAE
-:10615000CDF1F86543B6F1A1938ED91CAF4EFC94F6
-:106160001EB0E37FAC834E63DAEDE56C075D6E90A5
-:106170001CF6C710E9E15148D49305E518DA755EBD
-:106180008AFB5C5A967FFC940978D63AD8BBCC3609
-:1061900057AC908EE36F6165A54D8955513CDC0687
-:1061A00086172D8F6B2531B047E56A9324281EC7CB
-:1061B00005E344A678CBAE268837E2B02F05FD8AEA
-:1061C00039131473FECFF872B90FE8B52348F10EF6
-:1061D000EBE26C85B7377CE1ABFAF1EED40F5FAB45
-:1061E000B5E3FDA670BA0D5FB3F46C5B79E2E9E14B
-:1061F00017A593D01F828F04DE06D0A1D55EF65777
-:10620000DBCB4EFD13951CFA678874524F91529068
-:106210008B71AE34A3B37060BDED928BDB43DED8DF
-:10622000593ADE4222910CDAFF0A921805F83EA68E
-:10623000E9F87DA52B9107E50BA467E7C831FDFDC3
-:106240008F52C83189DAED1245EF6A0AD2702F8970
-:10625000A7A33D4CC2DE3C4401E245A2FFDF8AFC1D
-:10626000A2B8005F2382EC3D896628500E11F1A789
-:10627000239D3CFC9FF9AB9FF98B44E92BF1A70CC4
-:1062800074A4E3BB4904F9C14BDAB19C46BAF0A946
-:10629000916E7C06A8C68667900425786611039FD8
-:1062A000E48AD8637194C30782C8F7BE3F908FD346
-:1062B000FBE7B38ED36D3809FF48CA053AC4895746
-:1062C000EEE7433FE7436AAFA15ED64A19FF6A9300
-:1062D000E8BA5A86F28F7E17F988E2B702C665F5EA
-:1062E00005BEB772BB7A4B9317F5CDE6A6203ED517
-:1062F000A98D61002FB33AD17107A55786AE1AD781
-:10630000D3F90FABEE89839CF85B99DF966630FC7E
-:106310009EDCF8C44B8BE8FBB6428DF9412DCC9E38
-:10632000CDE0586C9B9C88ADA5F06D2DF41A56FFFE
-:1063300040E8A7ADD7260EEDA7DF3B75DA23FDEBCE
-:10634000AC3E9258037253A08226229B27FC930EE8
-:106350007A2DADB8A7C9AA77B40F65A6BC0AA25119
-:10636000E02B3ABF282CEF4EBE6A2BBF02F562DB52
-:10637000A967894E2B14D5C44DC0977F2A3565E98E
-:106380003CFC35BA2BAA8154465E053C67B4062511
-:1063900093E22FAB5A9F0632AA119DE96BA53B04ED
-:1063A000F23BA0FF91F1D01DB4BFE8B5AA7110D99E
-:1063B0004A77CDF7A796872D1BEFFDBA99C4AE0A91
-:1063C000BA24A4FBA96BF3F2C1FFF591607EFA2415
-:1063D000902F951C8475EBDA25A32349DAF5CB5968
-:1063E0005CD835499FA9DAA5CBA4B1CBD26F898BF4
-:1063F000C9A1CBE5C5676619E3A3A252EE17B71290
-:106400003396040E93C3AF2971C2FC39DDF559E20E
-:10641000EB6DAE2FB648A4B62BC9F74E0ECF0C7954
-:106420008F09EB6FC646B64EFA28A85D14BE2285CA
-:106430003E2DED66F1FA87F8F312F450DE4320307A
-:106440003943D3833EC7B8E259FE09C6DD46C79536
-:106450005D415CF704DE9DF4144F97CB87F53EB8A1
-:10646000F6C5101881A9E0D4414687D167017F861F
-:1064700050D713BD943D9DE35D6A7F5F74B1793859
-:10648000FB2507985D95C1D7AF93534A9AD1EF9DED
-:106490002DFC50BBDE007F18F451E701BAF01782E3
-:1064A000DE60E5CD318276566F1965E42288277467
-:1064B000A3BE2D20119463FA09CBAD5CFFAD07FD9F
-:1064C000479FEF93F02DAEC9A04762A7145A69F613
-:1064D000A4BBA7258B1FDD09F231F9D2D6A92FD293
-:1064E000E7426F7829F4AF19674C505B99F3249415
-:1064F00027A75C51F60CCDB5C80D91055F30796AC0
-:10650000E1FC0E723387966B8A93C3D9B9B1223FEF
-:1065100082FDE9C3D1EE50F4E1D67E3BBFCCE46A04
-:1065200087437E3AB8FCAF017EBCB479E6D5D0672C
-:10653000D08899A02EE7471B9F06BACD93221B5CFB
-:10654000B4DEBC7BC26E903FED40375D23F1FD268B
-:10655000C0478DDE0E94239AD91D85E7E6B245A883
-:106560009F7B436CEAA9F82ACD74D9FD27A73F3851
-:1065700044791C6F44A701BC7AED7B277375A05347
-:10658000E461806B64F86415A05DD3CF9859167AE6
-:106590006597327DB882F371E66C4A37D0778A19F5
-:1065A0009AE387688EB91FE63BD4F153F13DD89D3D
-:1065B00080AF6CCEE72D06E3732107195C0E5AE01D
-:1065C0003BE06B12E3FB96607930D93AB187AFF3C9
-:1065D000DFE37C5F4092EBA193AE4BB7C3C6D367BA
-:1065E000095DC1009EF749E469987F1697B3CCEA2C
-:1065F000980BE011F234DB38539D9D03768A5E0ED2
-:1066000076B118F71DCE6F0BBDE6AFA17D4D71B30E
-:106610009245E735AE8C18A05E6715674A563EFF77
-:106620006D5FFDF0F3505F2BEB46BF7CB076DD7CF9
-:106630007EF3A4F0CBC87F0FB42B5EA47BF815ECDF
-:10664000E7816EE2B5E89B228E6779E3A92AA04331
-:106650006F2309025FCED71B9F9680BF43E1752E43
-:10666000CB3C66E9763B9EF2F99BD0EFC8463B7F78
-:10667000D69076855CC2BA314A8AF400BCB31FE872
-:10668000467833AB993F4CE1EE45BDF2E9C3FDF1ED
-:10669000C5E07E13843517E47D1FEA330A9F225339
-:1066A00038C6CD8E2B5988F7330AC047F1ACCA16CD
-:1066B000391FAA7CEF00E0260F2EE72DF08F29600E
-:1066C00027477264E03B61F7264E12E66FD9E396E6
-:1066D000C25E0E84A8BD4CE525B32641C03FCE3E28
-:1066E0002D1BD7D32AC36A8804FE9FB063B3B85C5E
-:1066F0000AB8B6723B794B5308E5285BEB390D714C
-:10670000FEADF92E630D01F9AD40FB6D4755220436
-:106710007E60B0B262E31DB47D5B938EF5373619AF
-:10672000D87E4353253EDB6B5E47FB776B88D9BF32
-:106730009B9B4AB9D3C1E0CE1276728D885FDAE1B5
-:10674000A2ED6DFB1FA23E0959E25A4596F63AD3D7
-:106750003783B54F9F648F8BF5B53787D6DE67D803
-:10676000DB57998956F087833CEE2FF45E80D7097A
-:1067700056BAD06F1678F694DAE9DE5E937C3F471E
-:106780003C9DE3113DCD367F12AD43F85671F85272
-:10679000F5B38EC75F44D9CDED4567BD15325F1F98
-:1067A000F9BE54908FB5C3A4F8B0C461B239DF6D9F
-:1067B0009DCDFC321264F13AE197B909B1F9656EE9
-:1067C000BE1F8565D4F751A68F1DF08BF62A6F9FEB
-:1067D0000A0ED5D9DF59DA4F85A51F079CA9E073AA
-:1067E000EE939137EDFDA4D65F8E76E7874687015D
-:1067F000EDC06A28B596B31CE5E18EFA458EEF57D9
-:1068000038BE973BCAD738EA4F7394BFE4A83FD746
-:1068100051FEBAA3FE22C7F7658EEFAB1CE57FB22F
-:10682000D72FBBEB93E1F7FF333C09B91A88979850
-:106830006D9FD7295745243E2A0E7E43E6734BE0D1
-:106840005342969473CC1761712D129F60F55FFFD0
-:10685000A845FE00EB58E747665A98CAD581F6E787
-:1068600003A08FC4FBF3D2AB81F13A21F56A7C25FA
-:106870008B03B5A3DCA411E5F544295049C2F8996E
-:10688000575B8C28F716D3F7567DD5CEE4AD18FCB0
-:1068900022DA2EBA5D45BB2F3A92C4C6D2766A81FF
-:1068A000BDBE9BF74F7258FFF89EF65BAE307F215E
-:1068B000146EAF02D91D5EDB75129E4EFC84A64796
-:1068C000AF7E06E20B3B981F7E6006F5032C7AEE46
-:1068D0006685E9B7DB944BF64B5F9C28F7F77FE0C2
-:1068E0005B9AD14CAB1C0020C0EFFF963706F18CB1
-:1068F00051109F639B07189F1B49F81F8FC381BBD3
-:1069000008EBCB48ED34C6DBF4BAE029D0757395BB
-:10691000121CEF7B52CF7818CF957EFE6AB62EFE02
-:10692000ED63B47B38FE429B2B12518A3FB24D354A
-:10693000C61258520D94238F425A3CE5C01E0CDFFC
-:106940006B61D565EF157F16C4D9C2585641EFC2A9
-:106950003A067C24C3FE761CCB7E92C07206B76FCB
-:10696000C781B3087E00D125A6270D09F6994237C5
-:10697000503F3CC9BA1196AAC62993FBE39492CE24
-:10698000E29152DB337F91205E594A74B64FC5E3E2
-:10699000821B65E96388B70687B6CF13BAC54E5721
-:1069A000A2B49339163EBEA58F9E0C5F63426CFE67
-:1069B000A16D6A23F8310766D9F940D497954BF653
-:1069C00007774E18F3D9F141A63206E119C807B787
-:1069D00006213E2D4529DED2878EB7A06C7E5DC193
-:1069E00079122CFF40326F053A89B242CC05D6F2BB
-:1069F0006FE5F0422847A791D246ADBF1FFA7E71DE
-:106A00008AF74B93BD1F27ECD5B36CFD2EE1323EC8
-:106A10006C4FD005766461C7AA34AB7D55C2D7E907
-:106A2000473B8EF860BEBBEB93EB3FF1DCC2FDBD94
-:106A300054F502527718E841262BE460127BFC499A
-:106A4000E06F8B1E0D38ECC2EA966815B4CFAA75BC
-:106A500011880BD3F51DEDBA426E1FEE9C1A9554AA
-:106A60002A873B7611B48FB35A16F9ACF3C9E7F312
-:106A7000D9393B2F0DEC957D8B177D09FD156AF7F4
-:106A8000CB181F8F6C82FEF36BD83EBF13BECD7C3C
-:106A90007EED8B199E9CDFD355124926874F2ADC49
-:106AA000CF55A212C9EBDF37D97CF2BE5F8DA7E3C9
-:106AB0009554BA0C9FDE0FE7B83E7B2981F84ABF98
-:106AC00046096E027BAA43B5D999FBF63CB86B31F7
-:106AD000F837F43DA88347AE6D1C1EA6703DFAE55D
-:106AE00025CFDE057CBFCE45401F0938B432BB9DA3
-:106AF0007BB24F3EEDE3D27E991F47970F39C9FE17
-:106B0000C9E5E2A3838F9B8A4F9CEBA9930F2E6567
-:106B10007DB851BEFCF9FD18E490C293C7F3B58669
-:106B2000D5EACC6FE37294ED158A848D93C7F92C66
-:106B30006BF6833EE0B35DB5E5283FBDB31749A0D2
-:106B40004F441E54AAF152C193EE6EF7411C74D704
-:106B5000E207A56478CB8FB0F890F3BDE966FAB48C
-:106B60004D6997A07DAA7AA3DC9C1FB85CE5F379F8
-:106B700085A6C6C380AF3C43216B28BE76CC5E544D
-:106B800055027C47E510E22AD53504ED877C93ED6C
-:106B90000B0529BE9EA4EBDECEC5C488D37A3B4D3F
-:106BA000D5B61F23E4D0C98F3B175F5CBF10AB7F06
-:106BB0004EF95F716B6C7FB09814831DB523857D92
-:106BC00076A9F80D2D76B1F86875F920FABCF9525E
-:106BD000D7A9F9D7023F0E35DFCDA12FC853BB6629
-:106BE00095805F6B507D4192E1C7AE1F06C387134E
-:106BF000FF13009FE99F1D3E9DDFB3DD3CBE3D447A
-:106C00007CB4D516FD0FDC034F51DF391FD14EE4A4
-:106C1000A77D91F4C820FF2670E818F0260C7C565A
-:106C200093303EBB95C857DCB4FE4CD28865117FCB
-:106C3000AA53828C1E3CFF45EC732BD319DF8F9B2C
-:106C400048629DB07E4C9DCB377F15F39C178C36E8
-:106C50000A47127F8A903538EF118EF558C427867F
-:106C6000D5B7CF2EA7FD8E98EDC2F8C588CA23B63A
-:106C7000752CC0E547F4B7BB7268EBF3238EF5F9CA
-:106C8000112581F95D8F54AE6986E546C97A339442
-:106C9000ACFDB80E3B5EB77ED4E50B278167F7E20B
-:106CA0006398C7B5BBF2E2F1934706E19B7172723C
-:106CB0007BF68B1EB6AFB43BD37B334B2E5A6DCBDA
-:106CC0004320B256681D77F74724337C517D629785
-:106CD00097AD6E9E6FE0277EE0FF54F810CFCF1A7D
-:106CE0000F8F4E6B5C164ED2BEC4C3EC89759924CF
-:106CF0002A533E79F4652506790E84EBE18A9BF5EB
-:106D000018D80BEB404950FDFB6815C1EF1599FCF5
-:106D1000FBC33AE6558DE8205195AE67235E5ABC19
-:106D20002393D66B5B4C3DC7C2FEF76DC6A956D800
-:106D3000177EE20517C6732B7C71AF41E755C9D7A3
-:106D4000C1DD8B4F61DE71748F628C45FD2E11A900
-:106D500002BD785B1CF3845B61EBBDF1A04FA7ED36
-:106D600077E909ECE79B534E7975D82F2FE8F6C2E7
-:106D70003CB754B2F5F2C8E2A2AF96205AED79269C
-:106D800033E5A9DD261D6FCB62B65F9199E8F67AEF
-:106D9000E87C02B50AB99EC217D0D87CDBD6911820
-:106DA000AC53E53C9F442273D01FCE77E409E5390C
-:106DB000F24D82C6CCB760DF3F08FBFB3009B97EDD
-:106DC000C755A06F1B5C3C0DD54439F5F3F9F90D9F
-:106DD00013EBCF948FFB60DF77578B12C4F5CFD1C5
-:106DE000AF731E411239694AD80F8EB3EB21B64EEC
-:106DF00006276B06D558B429873B48E1CEA643B693
-:106E0000D8E11678758EE37794DF14FC3C828C050C
-:106E10003D24E2CC027E27DFE654C48E3E4FE7BB22
-:106E2000FB050DD7EBDD95CFDFD200EB7CA907F397
-:106E300023BEF4C1A1FA7FA1CF5FBF77AC189E3704
-:106E4000E41F98D4007880FC8889A42F8E97073D92
-:106E5000A3FDCAF59A18AF6C5F8B3B075F45FDB485
-:106E6000BCE5D4CB75108FCEAF2768FFE62B8C3FE7
-:106E7000FD2DAE5833853FE79A76E48711B571044E
-:106E80005AABED92A29678A7C8FBF6D747308FE2AF
-:106E9000FADA76CCF7F6F3B8AF7F523BDA4933E44F
-:106EA00057BD68AF71FA89FC77217F4EFA942CEEBA
-:106EB000AE817E46B42806803DA2BED105709554B1
-:106EC000D2358BD2ADA4A34B62FE1FCBA76729CFCF
-:106ED000F419AEC3BC2CB287E5178A3CF040BD9DC7
-:106EE0007EC1BEFCF9880BFCEFC20EC7F770CD1B4C
-:106EF0008C0FEDF42C52393D4B781E21C7C3088E00
-:106F0000872DF57C7F4EF3C62E66D7BEC0F7E75EB1
-:106F100084F98F1BF8FDA614FAF746D0BFE0B7BA84
-:106F2000BA5B011FE41A17FA714E38B6D633BD7733
-:106F30004075D9ECF8CB1DFF36AEFF6557E2EF3256
-:106F40007E7DDFFCFF3EE3DFFF771E7FD3DF19FF8F
-:106F5000BBFECEF33FF41F3CFFF9A592CD4FEB549F
-:106F6000BDD8DF4F3C223E66D7DFB22BB9BFFDBA9A
-:106F7000EAB2E5138BFCC4E9B5E6428897F80D76D2
-:106F8000DEC3D9DF0CF9B956D083BB785E36D5A302
-:106F900026E4A9664C1179324CFFD570FD57C3F534
-:106FA000DF91147AB5BC92E9776A5FC4F442583233
-:106FB000DAD19F099C56303FFB08A1CB0CE835DDA8
-:106FC00093343F3B8FC3EDD4A7795C9F963FE7781E
-:106FD000CFF5A8739D2FEC8B9F128C9FFE7795E7C2
-:106FE000033BF4AAC0C3AE4A662FE7CC4D6E0FB682
-:106FF00039E8A84D6AC4FC03273D5E57997F2DE808
-:10700000B1D06BBEA2E6A6A67782D3FB3A4EEFDFE5
-:10701000A83C1F8AE789A4A277A5878DF379FFD9B9
-:107020005033CC265C857490399D64D2D68DF15F47
-:10703000F24D62F52FB77E44ED1058FF35CD584321
-:10704000CB9FCF212E9174FF91D89FA37FEE6E1618
-:107050004795735487BFE5B483BD513837B3DB74AC
-:10706000C5A285604F74EE5E09EBD30B6998A7BC8F
-:107070003BB3E339F4E7DA272A0087B01B098FCF47
-:107080008249C1F2509CFB4E76BB7FF7475D71B0E1
-:10709000BF828512C6FD5AF50773929EC773D8FB4F
-:1070A0009AC76FF377C9F543B3DBD7727A537F3151
-:1070B000D76391EFB5FE9913591E547510F67724D6
-:1070C00073A60BE2E9A9FA8148EF39CB7E539D62A2
-:1070D0008E84FE24F01F4BFBFD47420A587C5ECC99
-:1070E0007FA8E707EAEF62FBDE1CAF39D7747D2A81
-:1070F0007EA4F0FB453D919FE7ACE7F4C7AF779BDB
-:1071000053607E43857F2F301CC4B3CBE49A64F177
-:107110008304D7AF5AF8B1676FA25527CD93587C37
-:107120009F9A6DD6FDB4B61CA52659BCEB975C4E54
-:107130007EA3EA5CAFC7499684F92404E625E4D12E
-:1071400039FED57CDCAB2F73FC17B85C5FCDE59ABC
-:107150001003F763528D5BC5F586787ED271137C80
-:10716000DE552A8F6B0C32EE1C3ECF399739DFF398
-:107170007CDC39439CEF423EDEC2CB1CF7433EEE43
-:10718000C2218E7B37C7EFDD978967C52BF17E86DD
-:1071900086E7663E5EF3658E1BE4E3360F71DCED39
-:1071A0001CBFDB2F13CF057CDCED0E3CA792DFCE9E
-:1071B000CB1CAFD4CBE4E700975FA75E13E36BF97A
-:1071C000AE30B4DF1DB2F77383878D2F9E24FE315E
-:1071D000FAAF23F8BEEE9495F72E32938C2BEA3B50
-:1071E000D7E354E3DCC2E335E229C609F0FDD02938
-:1071F000D7D07192E047D4BF5A657A3055FFCB386B
-:107200003CCB2E711EA27E15F43F3975FFF7713805
-:10721000EE73C03F58FFA2FE9C41E06FE570B45E84
-:1072200022FCA2FEC241FAFF0E87E33B9708BFA8EB
-:107230007FF720F87984C3F1C825C22FEA370FD22F
-:10724000FFE31C8EC72F117E517FFB20F8798AC384
-:10725000F1D425C22FEA1FE89377BBFC69E23E0612
-:107260008394429EF1289266E0FD0646E224F801EE
-:10727000DA6A76BF01E9729E87B29CA3A2227EF2EF
-:10728000BE9228D4DF7B178BFBEDBD9AA01FB137D0
-:1072900097E729F3B896C6EDC1BD57B338C8DE10DD
-:1072A000FD6EF1CF44BC68AFC1F29C7B0B581EB39E
-:1072B00056D68E26260E97C74D441DF269D8B92A98
-:1072C00061EF89F3556B799C6AAF49304EB5B78C45
-:1072D0009577579398ABD072EEAA348EF9A760D801
-:1072E000423CB6FFDC984956975BF23156C731DF16
-:1072F00040E179231421C49697E138AF25F60F6F4A
-:1073000032CC19A0E60A27B1FDBCC2B0DD7FA88748
-:10731000435CB4FEEFB99E0C4E4A7E9EE6B05761C8
-:10732000F4E3F99AF3F8FC05DECA393DB7CE79AF3C
-:107330007B3A9DE7B353DD983FFAEC698EC7A9729B
-:107340008CED9F1377B27338A9E26C5A47E3293862
-:107350009F7BD373C40032FAF798EB748CAB7D84B7
-:10736000FC8771353AEE4D7BDA15E0BF591DFA7492
-:107370008807CE7B4E5FAB41DE7507314C40EF474F
-:10738000DFC07EB25A881163A46A0EA29DEB88CF3B
-:10739000F17393223E07E16AAB7F398BCFBBBC25EB
-:1073A000B80EB6EECAAB3D36FB7516F733BF627A40
-:1073B000ECE725F9F9C7590E3FB3C36B8FD7691DA9
-:1073C000E11910FF96E79D31E1FCF3B8B0141C46BB
-:1073D0003FDF16DEAE407C72D69E46CC5F4FB5BF17
-:1073E00095F1F05CBFD57E17FBD9BFD973717B5D7A
-:1073F000C41944DCE134E4157BC04F0F71BA30BED0
-:1074000012FC91354FB2F1498797E9910E2F8BE32A
-:10741000FF179F7CBA7CF23BAF3DFED001DFA83C5A
-:107420009618C9F7E9EBBCEA7FC9EB674087802F64
-:10743000391D487D862D8F58E45539F1B681E34DCD
-:1074400094BD29CEBD14F8F83AEBF4EB5F8D54C12E
-:10745000BC449C8690FB1DFB9B538D8BC5256471A2
-:107460005F8CEB5519E653EAE3FA47210AF6EF98E9
-:1074700007CA7D1E9E53643038FA5BC7CFAB89794B
-:10748000B98BC326DCB742C7C0FD3EC8573F520682
-:10749000EB63D0366FD3C7D69B4DA58CDF36952ACC
-:1074A000B174965F65BFB7A8B8D39BCCAE104F62DE
-:1074B000BDB7A26820BC6A71246A8547E5F038FB35
-:1074C000999B129E3A5BFCEB52E1F18C27A41BF8CE
-:1074D000568911A697BF61EBCF551AC3F3FDA9FAE0
-:1074E00051743E2F075D528DEF2DB0E741A93969E8
-:1074F000367E57B42C479E9483BFFAE242431BCF9B
-:10750000796EB1859F4771B6F729EDC44882779FA0
-:10751000EECCC788211D9CE76ADC4107DC8EFEDBD0
-:10752000E05D923C1C71DFD006BEAE6D5462686FA8
-:1075300045299890EFB98EF3A5128CE1BD5EDFF678
-:107540004949E74F8CE4EBAD529C1C7E6F811DEFE7
-:107550006A4E969D0E4AF2731C1B85DC070F98F647
-:107560007BAC9C727EDCB8D87ADE77AF96F43BF9C0
-:10757000633AA5833EC73D0943A4AFF261369E6BD3
-:10758000EF2B53BD0AF15A2A2398CFEBAC7F46E08C
-:10759000EFD54E845FE8E9F43D22AFF693CD4392F8
-:1075A00008DF27B7B74F29875CCFC99CAF9F1E6400
-:1075B000FEA9E89B56ECCC2B1C1A7D7D20F7B0EE83
-:1075C0002926BF0CCB2EF7A9C6234136DF4B95FBEE
-:1075D0004F0A67764D84803E53431112A1EB7C7EA7
-:1075E000A81DF7C935A9270AFE1895291DE8BC3B37
-:1075F0005B67F76658EA4DA3EDDC85AEA81BF24049
-:10760000F87D30D110E982FA108FE92CEBAFA74951
-:10761000240CFCAEE52A61782FFACB986AEF8F9A9A
-:1076200009B2F51C96C817405787CEDF3D85FAA7EB
-:10763000B4BD4AEDD07DC9F4491AB343D39FF29942
-:10764000982710D662C092F9936298CF995F470C41
-:10765000F0E74A3ABA498476FA6D8063327CA7F340
-:10766000D620FFA31DF7ED733CECDC7A7E7DBBB426
-:10767000D0324E691AE3EF6973BDB84E7CA38A9D80
-:10768000DBEB0E2D6AAF82F12AF97D7A390A194EA9
-:10769000F1E17FC9C3FCCF490902F809F2BC863782
-:1076A0009B48F9E2B184BCDDE4C5E7F9A6203E833E
-:1076B0001FFDCF10E4B9AC9B5CA143BEF507FEBA39
-:1076C000D1B06EBCDB14C2EF5BBE65E8904F249F67
-:1076D0007A19EF8FE8E7F7A84C2A210F366102FDEF
-:1076E0002CF3EFF459F6F9FBE645E7BB908EB3595E
-:1076F00072DD0EE3417911F2A957562DF91F2AF7D1
-:107700001BDDEB48F8B132B8C72426DD5D6679EFA2
-:10771000A3761BACAF938348F77E7CC69A39BEAF85
-:10772000067F37FF398ED7B99517DD37696B8A77B2
-:10773000578FED2F6B29CEBBCD714FBB2E0DE2467F
-:1077400070D8938E377D6EE930C0D743EEE4F72FC3
-:10775000C8C1894631D48DE6BB500EF93D2BABC66E
-:10776000EBC3322DFDCFE17C299FFA29E237BD8C96
-:10777000E587D0BFD9F996FCFF82481DDE8F441AF9
-:10778000D93918B10F39FAD644336C498C5E6D3F44
-:107790001F33939FF32C5CE7C2FCD7C229A843494F
-:1077A0006133BBBF6ABF6C94037F3F4C5EC88403E8
-:1077B000EB0514BE9154540BA3F67EF62F99FD0CE5
-:1077C000C401C4B9D1B52DACBF51BA715A87F849BB
-:1077D000990BEDE5D1C4F042FFA3351781734563E2
-:1077E00088A59F4238476BEFD7096FA1DFE5827804
-:1077F0008780671439EA3573B07F12A3ED0BA89B1D
-:107800003722097CCE71C6887A579597C7499271FD
-:10781000494F33EC0B0D187F907E9BD2B81DEE279D
-:1078200001D0E77B2436FFE8B3B27110E87AF72184
-:107830008CD714ACEAC075BD238DD977EBA93DA0D8
-:10784000B9C14EA1CFB1A9F9500E52C465E0FA9169
-:1078500094FF1E4DABDA9606F1B0B469DB800FD30E
-:1078600014FD6B783FE76937817DCC34B31DE50F9C
-:107870002E64023B6373595106C85B5AA39AD45FC6
-:107880006B4973237C7BD22405F242296FE1BC94BF
-:107890007AFD3B3369B13BD7FC1E8CF397DC083E85
-:1078A000C5FBD0A25A1DF873FAD2328C7FF5764808
-:1078B00018FF7A438AA990AABD7C5EE304B82F67BB
-:1078C0004E66E41168B7548EAF77537856DCDA58B9
-:1078D00002F8990DF97EB9305C94F98305AF1B0A63
-:1078E0009C072B50E26ECADFDEE0A997D8335A0519
-:1078F000FCEE859330949E8162F32DF09BFCFC1C82
-:10790000924C7AA2901718984AC8EB16BA814F6722
-:107910002DC39EAEB59C0AFF833D17D3B6AF8F85AE
-:1079200055DE3025B40B62883F35684C0038E5D011
-:10793000E9BC62CB3AE7E1F3F34C5FC4EF4932B9FB
-:107940007F6310AB7FEBE1F3021DFEBAA5BD3B6484
-:107950002FCBC14F771EC2EE967EF1D77340C7B5CD
-:107960008FBB31EE39FD7177FC3A5A5EB14FC2756B
-:10797000C67582E9F5770F4828F771BF8A7AE09DCE
-:10798000A017CB0D9EEEAD5FA0E59EC765D28968BE
-:10799000A9C57BA5CE89F5F4182B2FE10ED28A7DDF
-:1079A0002717407F75C73C04D689153F5D7AE317DA
-:1079B000687929E563A8B2E260B33A9C96EF8A49F8
-:1079C0005D50BE308D209F45B3D418E4B55C08747B
-:1079D000E7DDA4E13A46F471B0BFDD9D378FF2E3F5
-:1079E000B2D86333A1DDB2C3124452E93C0E3E93D8
-:1079F0004FE15AF17D09D7C7E587D2D95D2B1C7FAE
-:107A0000E7E854AEA3DF57D179823E5C4ADA6702D9
-:107A1000BD561CDCAE5AD7B9B79B4A31F5439457D3
-:107A20007C9F8E43DBADFC9164C0145742BE03AC17
-:107A3000973FF5D5EED7607ECD6A891FE6B54185C3
-:107A40007A4B630B9FF0E900DF3E7526FDBE6CCFDD
-:107A50003E754919E08DDC0EEBEAF2435712DD4228
-:107A6000D7731D32FA0BAB32BD9D78BFA966BF0F2D
-:107A7000A51F2E62836B19D71BD4EF53ADE7DD9E94
-:107A800048CF443E5D7E48B68D23E81F3D43D879FC
-:107A9000B49FFBF13C9AA09F58AF04FD56890BFFA1
-:107AA000949E8A64F06C057AC0B91BEADFC0F3C10A
-:107AB000A6103E1F6AD2914E3B018FE3585E0ABC6E
-:107AC000A7725B05F756054CB8180CCEA5985590D3
-:107AD00087991566E5BC5B23927E113B5D3C77BAC6
-:107AE000230BC1C8999AFEDD190AF5C776AA91BB86
-:107AF00021641D543A6754D335AF3E3D5C916ED935
-:107B0000F75B2FB1F37D9F4BD771FEEBF355C4F7B5
-:107B1000CEDB2AF6F3F813AE933B6F5BF208C4C7D3
-:107B200069FB2FA6837FC1F7FF52B5CF5B50696B0E
-:107B30009FB7A04EB49F89EDBD176FBF73C135F6D7
-:107B4000F1172C13ED6F44F8B58BC39F77FB54FBF3
-:107B5000F8B7D763FB060FA36F4FA617F3AD5B7C97
-:107B6000461CF4315EA83609F2C94B3AA19E5877FB
-:107B7000A8E637217F5B3B9C59BE8958F968DA0239
-:107B80008003F2B2AC7C9451996693AB4C33CB56E4
-:107B9000CEAE196EAB9F1B2EB27D1F567B85832FF9
-:107BA000353CBF8865000A0C730AA73A5C457D54D2
-:107BB000359CD9C1F79EF061F9DE6BD8FCEE1DAEA5
-:107BC000A11C03CCE097DFAB463E67BDBF95C03D2F
-:107BD0004854A7DEA945EE8379F4BFD75DF03E8D0A
-:107BE000E73BA57908EABB0D8515FBA3167CB68E8D
-:107BF000A4FC40CB2DE92AC33BA7C386914B425638
-:107C00007B7DFD48B516FC0D787F8706E385D7C3DD
-:107C1000780D6A4F09D81DCE713C4595B671BCA34D
-:107C2000EA709CEDE92C9E2AC6F18CAA738CE3AD18
-:107C3000EDE4EFF9383B80CF528DB3A1E81AFB7C1D
-:107C4000462DC371F63AC6D9306A99639C34361F03
-:107C5000FA9E8F13BBD8389E3153EDF3195D8FE335
-:107C6000FCC0399FD1F58E71341C07DEC338D4F0C7
-:107C7000D5E1BE2CD5D3B304E9FF0B1FDA39AA270F
-:107C8000F228DA39AFF8D0CEA1B54CA8474A997F8F
-:107C90007B4F7A16D2E783344A7FCD4AE728CF3B21
-:107CA00088A25F7C270791C4284454BFADE43CB848
-:107CB000F8F09C51CDF03C363DB410FCD187FC1857
-:107CC000C77BF7D874F58E24FAE8CE76F7B98485A9
-:107CD0009FFBF42A8FC786D2D93EA4289FE3F19F49
-:107CE000D7214E449F6FB809FA436779BCA81FDEBD
-:107CF000666C778EEFEB9DDBC3D6A90FB69F71A3A1
-:107D00001D11252F9451B8E7F369DCD96EBF2FB34D
-:107D100081D3A3E7A71E760E889823F03EBC8E6C15
-:107D20005BBCF07727BEFC0CCBBB2323E0DEDFAFD0
-:107D3000B73EF634547B515A3872159D6FEDD1ED34
-:107D4000EE11B4FCAE3BB1C0D02CFDD4BAF1DCBD19
-:107D5000F0436E8EB86DF6F32D75F6F26D0E7BFA6C
-:107D6000D5F422B13FCBC6D5636EA0D77CD863A52E
-:107D700024BC0D9E987C17447A2D08B2B6029E86CC
-:107D8000FBDD248EEB5D2217E39CD15C8CD344C4D5
-:107D9000BAE5806F81DB6B86293D17DC27231E9DAA
-:107DA000F0264EA49B2EEAE7243AFEB71BCEF10C38
-:107DB00006FFEDABEDDF49D46DBB8740F0C1D76A5C
-:107DC000ABF69FB5F0C7CD9159FBCFDAF034C7566B
-:107DD000BEADF1665BFDDB572FB47D5F18BDCBF602
-:107DE000FD8ED6BB6DE53BDBEFB3D55FDAD16CFB27
-:107DF0007E576CA3EDFBF243DB6DE5155DBB6CF5C7
-:107E00001B8EEDB37D779D18FF15F4037F23E37977
-:107E1000E7F7B5735BC17E7B3FA8E07ECE9B7CFF1E
-:107E2000EE6D7EDFCF4AE0BD29203F13BDE0373441
-:107E3000A45179A6B6C4042D777DEB54D02304AFAA
-:107E4000D428D746AC8F5267770A3F9F2877A8245B
-:107E50009E0DDB2BFD71D81EB9FFBB92A0DF27A6BC
-:107E6000FE2E772849BF2B092569BF17A49E12B0A3
-:107E70001FA32F7B929E03EF974B32825CE43EC997
-:107E8000F32E5267F5DFE66B2C3EF44CFAB4F95A48
-:107E90002EDC8FC1E4BDFE48FE34F01BEAD57849E4
-:107EA000B27D9BBEF1BA24BC3770BEC6E4E5AED845
-:107EB000085B3C6DF9A13136B97F292D729346EBF1
-:107EC0009D3F29A39E25F1A7467DF52A18DF9C0F2B
-:107ED000EFC9B15C5C1F5F6C32F79FA57EC04B4D54
-:107EE00035F8FCD7A6F0FEB3D4257CB5A916CBBFD8
-:107EF0006F8AE033D15487CFD79B1AF1FBD9A6D52F
-:107F0000583ED714C5E79B4DADF87CBBA91DBF9F5C
-:107F10006FEAC0F2BB4D317C0A3910F62E09737B33
-:107F2000526C981056EEE57390F3441CD3C0FBA33B
-:107F30007AB50F4AC08EEE7DC98379B7A9F0E4E423
-:107F4000BBD4F43371BD5F12B3C799C5D397C6E8EC
-:107F5000E373911AC891D83856C5385ADA2FAE440F
-:107F60007B9CBE57D865B231634E927B3BF142E4B5
-:107F70006183D349D43FF7DD7FAF585406F42942DB
-:107F80003CA53D253732BAED37BE7AD5E0F8439BA4
-:107F90002F7F201EA55FFC6E14C4A7DEC915F8EC68
-:107FA0001E05C12D450BEF023EEC3DEAC179F51EE1
-:107FB0004F67F92810541B42FEEBF243BE98553F21
-:107FC000ACE8CA8CD9F5457ECCAA2F7A4FEF0F804A
-:107FD000DCAF0AC9B1B313813F4CCE1F8CEF44FF15
-:107FE0002BBA0A639AAD1F7BB9B75DAAC17B1F8903
-:107FF0009E312F89FF219EAB422A8EF3F6A1319844
-:108000007F40FDC4D85916EF8CB17143312B5FD638
-:10801000AF4E8F9DCDEE872F55BF9F367C841C259C
-:108020007FF0A63E8F3BD89328FFA6E2FD6EC7DD0A
-:108030001FC0BAE3A1FF7F8CF9420A9645BF0D5DD0
-:1080400072D403E779C961DB78B49D2E7C7458AF94
-:1080500052D3DD9E0FFE7BE0255CB7D9F9F2089C78
-:108060002FA7FD5D50B456E973FDE7CB1B385FAE1B
-:10807000F026D4087DF5CED13117CD0779BBE97450
-:1080800050190B7904ED7871445DD7F86AD08FEF01
-:108090001C5D9B07F1B4E572EFBDC9CECD7EA8B1E2
-:1080A000381B89B97B1296F988F80C21B45F6F3FB1
-:1080B000FCC0E9E72C65A7BE164F979FC5DD571E8C
-:1080C0003E33F30B14FE95C7DE53018E635AC4E5AD
-:1080D000B7CC5FE2E7EB971D7A4D85F9BDE98E9647
-:1080E000DC7F113D35104E2D64DB0F8D926E90E3D9
-:1080F00045EC3718809FBEF60A15CDB77EED26F009
-:10810000BB0E62BF429C7B584CC201C0D7A2A3CB1E
-:10811000313EFCD61337707BAEBD02F8E31DE2AAF8
-:1081200081F9BD439E0F4CB4E0AFD8CFFC18D2CA42
-:10813000EC18712E90DAB336BB666987BDBC84CC6F
-:10814000CD03BDB1E42137895114DD452CF72FD182
-:1081500079E7F899BDBB9434AE077B4EF130FF60F0
-:1081600051902823A83E5DF193872BC0EEBFD2CF5C
-:10817000F61D451CE3AE2C66EF2DCB89A9B09FF010
-:1081800087A313E77F01B8CF135B0FEB32C948BE5B
-:10819000FF7747AB1DBEC1E077C22BCEBD0F88A7CE
-:1081A0007038E44352D2FCB4297ECE775C8FACF1B8
-:1081B000DBEDFC0D8EF26C3F8FB3CA44063ABF1361
-:1081C000F4465D19F81DCFD9468F788CB53ADCA7F7
-:1081D000150E037F51BB6002B1D4FBA316C1F7E7B4
-:1081E000A5E796E03973253E01F3F1BC04F314557D
-:1081F000CE0F725A6002F91CC4491BD1A95FEB0B68
-:10820000744279BD9F9D836A0039A5FD6D09CC3C00
-:108210000D717D2F698F9B85B0FF6D8F7FFB747B08
-:10822000391DE409F409BC007A1804E345E9A5F610
-:108230007A7EC35E5ED687A7B86C3DF711F06A718F
-:10824000F89D2152A99CB7DACD2BBD0C7EB8111C2C
-:10825000EADFC3EDF995448F62DE6288F1C13DB378
-:1082600058DEC43D7EDD88D2EF9262E2F9880DD0FF
-:10827000D4B28E357C28919845AF37283D2AF065D9
-:10828000C3870ABEDFAB45BE057855898976AE97B0
-:10829000220DF6AF15ADC666F792027E2FA0237FA2
-:1082A000A1CD1FB4F97B422FB8B95EA4FA62833F17
-:1082B00017F460CF4CB6AF9E50D9FE0EABA7F6D7E1
-:1082C0006B033852D5F3F5D7DB9EACDE8A9FFCF00A
-:1082D000892895F765FFF2ED006CA6BDA5B4E741CE
-:1082E000FE43FDC17501E0E337956800E6FD562CBD
-:1082F00079DEFB2FB9BE837C27382FBF92D3E9EDFF
-:108300007FDE7C23E0FD83836E3C6FDF70C813F754
-:108310005022AE3C7A17E3A7439ED7587903FE6EEE
-:1083200054C331BBBC2D7BF4DB793A6EEE4547F08C
-:10833000FBD8D17E5E79E08F33C11E69203DA8272E
-:108340009CED60FC0FB370FD5A08E7FE9DDF45BE53
-:108350005503E7FB86A39B31AFAAE1E82CCCA36AC7
-:1083600070C8791DF7438EF9EDBFB321F04162CC9F
-:108370002E5EFBFDEF4C788DC273FEC0AF03922DD5
-:108380007EC4F4446FD71DDF7B524FADDFDFE57E47
-:108390007D7FBB18B6D38F313B9E1C67CF7A773C6D
-:1083A000007E53FD3EB7413508A9FFE1FE47BE0BF5
-:1083B000FCFDB207E30DCB7FF8F48BD7D0F2F2C708
-:1083C000DC39B3D93434C80316748133EE90AF2B43
-:1083D000E8B0ECC74FABFA55ECFD0359FDF458FE7D
-:1083E000D849955C35107FD3BB4EAAECFCB9832EDF
-:1083F0005DAFCD04BB7BEDF7FFAC827CBD75422247
-:10840000C30A07B6AFDBF734DA758027A423A75376
-:108410001FDD06D02B7EE39393B05E10D6B1C1E88A
-:10842000F55DE0995CE4EB1F3D09FB05FFEA3100D7
-:108430000F753FFA4600E6F386D2C8F8FBE175797E
-:10844000B08F5EE78EE605F1C9DED7EDFD26F2DDE1
-:10845000D233DFCC637950663EFB5DA3683EC60134
-:10846000F7DC84F35C4222C87F750FCB9887FEBE91
-:10847000426A1E4B221FD705981E7BA3D38397DF2A
-:10848000BD010A17FCC5E7E5183B6FCBF212BF2907
-:10849000F63DE0DE465A7EDFCBE8951B70897BAD6A
-:1084A000BC36BE3DB0A11BE8F4F6487318C42B29B6
-:1084B0001EA21C6F12E821F9CC8C618C4E44572A05
-:1084C000783BAA27A7C37BA8DFED367D136CEDF8B8
-:1084D000BAC6C6BF878F4FE14E03FBEC8D3C6AEFF7
-:1084E0002499DFF280907F6A7F58F8CC22E74CEE27
-:1084F0000F6C64722EE43E36A706BEFFDB0B4C8E7B
-:10850000A01DACF314AEF830FC7E729E847AC14399
-:10851000E2C9E4FB809BCBB7FD3BF5CAD1BE157C1D
-:1085200042E15760DDEAE717B6CF4BE980F6DB9210
-:1085300087687BAB7D0EE3623DB5FFBD65BD5FCA5D
-:10854000F5C13501C7EFEEECC91DD27D79F5EED846
-:1085500023DF05F9A5F20AEB4FFD0FDD9827F2A7FF
-:10856000C34FBDF875CAE77FEA12726BD7A74EB941
-:10857000AD3B32992493DB3F6906492AB7F47D521B
-:10858000B9D512C8CFFF51FA54E06F51C09EE7240D
-:10859000F4632A3C3AF5E3DFFC3AE2D3A91FE9DFB2
-:1085A0000BA462201F0AFE137CB7EC072BF0774167
-:1085B000FAF853F05F1F7F0AFE73CED78E3FE7F7BE
-:1085C0002BC15011F162FA74AF21513FC4537F2E79
-:1085D000633CF50285693DA5F385C385788E789D5A
-:1085E0008FF9E717823D81AC32BC0707CB3DB9EA72
-:1085F0007AD017E27D8F8FC5BF2F847B02D63C9047
-:10860000D78ECB01D8EF4AC4484D327F846A648448
-:108610002341527D67F1E20B60FFC17869A362409C
-:10862000B719B2366A35F8F9EDECBCFCE2E6AF05F5
-:10863000601FFEC2F131DB407FDDF9AC4CF8EF2862
-:108640002A906F7207A7FF9B24BA732A9DE71DC764
-:10865000995FB1B82D39BF2CE3F59768F7A8A097BB
-:10866000A85FF0BA351EBE8CFF9E64DD1EC7FBE31B
-:1086700037205F2D73F05584FB8D3F147C7535B921
-:108680009AFB6D2E6B3EDB0CB96C1BD825174EB3D5
-:108690003864EF7119E9D17B5862F94F100F9E02CF
-:1086A000FCD0A35AF3D8CE03FF25B9DFA0EFFBE33C
-:1086B000BFABB89F56A97FE29509BBE9F3FC132F26
-:1086C00097FC0CCA3FF9EDA857C8C0FAD34FFC0578
-:1086D000F7B32F9CF0201C174EFC72D4FD507ED2B5
-:1086E00083F7D55C58E361F99F27FCB1B1F07D2495
-:1086F000CB175AFBF33F4F48E0BAD482747B29C0B2
-:10870000FCB1DEE3FFFE7BC81FEE3DEED1611E0D26
-:1087100027D2717FABE1491FC6692EFCFCCF15D66D
-:108720007CA6CB9DCF4A7E1FE2053FA9853CE50B89
-:10873000996CDFA0E16753F6C339A215474FAAB081
-:108740001F33FD177F9D007AE7C211664FBCEB4EC9
-:10875000EC857DD63F046EDFE086F82EACD7C309EA
-:1087600069CA885D0FF7E10CC40BC3C3058A07987B
-:1087700017C54B1DE8CB54F8F83FFFB0F8786F01F0
-:108780008C5F7FFCF32837FD78914CF6DE1F83A3C6
-:108790004D74FEECFD893F4F00FBE84F5DCDB8CE38
-:1087A0000F36EFFC8CFFD7E62DC58732EFCA7FD896
-:1087B0007933FE3F11D059DE9F430E06F2F94FEE9A
-:1087C000C5F28FFC06C23B44F9AFFD879DFF27A48D
-:1087D000FB114AF7C0E074FF6F196C5FF81F6FDE82
-:1087E00083D1FD594E777F10F2102EFCFCAF185F3D
-:1087F00017F31F6CDE3BFF93CE5BD8439B5C467B3D
-:108800005121E461C7BB750AE7BAD2B9ED1096925F
-:1088100079DEB513AE6732987F214B2C6E4346B29A
-:10882000F811E1FE46DFEF416AEC7C95A2AD67F7F7
-:10883000912906DEAFB7E98A4506E67690F29722DF
-:10884000502E988ABF73EBF4BB942BBE741AECFEC7
-:1088500096660A1F1DA7C5AF04A9E544DCA5AEB8FE
-:1088600067023E5F83E7061EFF7207559BDFA13953
-:10887000FC059F6EFFEEE1FD7BC9A920E42F790D79
-:1088800005F3537DA43D6ACD37F0104B3BFABD1381
-:108890007E10D0624F5E2AFEFE9CC1FC4F592AEF2B
-:1088A00086BC5832DEC5EE3727EC5CF1A60223B653
-:1088B00089E55D78EDF85CDF0D785408F50FD9BCDB
-:1088C000D0AF24DC9F5478174AA9CBF4D9EB717F41
-:1088D0006950FA307A8CAAE7F45965A387C0FB4542
-:1088E000E862A387C0EFA5D2C5490F27FE7F95C1D7
-:1088F000E274824EB67C905CE697C4A981FCCBC33F
-:10890000FB312EF2CE3FBF7623F0E9F29FC9C44B74
-:10891000DBBF7BD84FE220BF4A4C053F6BD95119D2
-:10892000E3C2FF174BEE49A70080000000000000E3
-:108930001F8B080000000000000BED7D7B7C54D5F0
-:10894000B5F03E33672633999964F29ACCE4C52496
-:10895000811834E0248480823A218020F43AA008EF
-:108960007AA38E10209827485BDAEA8F09411A1EF5
-:10897000B641E5A1453A2028ADD8061AB9A0A8838A
-:108980003CC4566FA3E5DEA2450D8A82C823A51715
-:108990003FDACF5BBEB5D6DE3B73CE6402DAAFBF43
-:1089A000FBFDF3E59F937D1E7BAFBDDE6BEDB5F761
-:1089B0005CBE0C7FB73076595C196B652C83B1BAFD
-:1089C0005F3B184B67ECC19D09E1C9F970DDF5E922
-:1089D000503684B1734B7A0E65C3FDD02F15DF5628
-:1089E0007C3DD43DF40EB8FFA0CAEE0F9444FB9139
-:1089F000D754A781B1E18C9DD9639B11B633A66C86
-:108A0000DB771FF5DB31DD94A044DFB33A4D342E24
-:108A1000BCE7C7E7A15F28E1414ADFFE186BE1FD33
-:108A2000FD42E1F0ED3685AD08DFB64DE620C0D160
-:108A3000B4EDCF663FC051F5EB1793BA61BCA6DD2C
-:108A400046162966F47799E173632461285D8FE304
-:108A50009531BF5DA960AC11FFF5C2B5B361324B72
-:108A6000826BC7CA3F1B93F07BD327DD96E8F7756F
-:108A7000BF7E7557085053F79BE793BC703DDDB53B
-:108A8000358995507F0F98931953EDAAEE7DECF739
-:108A9000526ADF7E605CC65C709FDF624D1DCBF961
-:108AA000789DDF39C9103E06FD48B8617EA7F11FE9
-:108AB0000F63239D8EF4CFAF83FF47B011978D7066
-:108AC000DD96C6D80D7DF114C55788D3F3C58B1B31
-:108AD00043809F333BBFDC88F0D7FFFD2F1B7F0413
-:108AE000F863AF599D5B61DE4DBFFC8F24A4AFFCE2
-:108AF0006EAA53A1EFCEE5B29007DE3BF77E423877
-:108B000004B7CEBD7A32CF0BF33DB7E3AF2E2FBC07
-:108B1000BFF0D5719938FF852F5565327BFF709C6A
-:108B20005BCC5838410B5798E8E8DD0D9D664273E1
-:108B3000AFB8C6D0637FE7FE3C84F3ECD1045F029C
-:108B4000E209EE2D2A43FA009D86F2F6C380DFC6C5
-:108B5000ED3FFEB371683C3C87B20D6EA4EBA7E31A
-:108B6000114EC622D9CC8DF8ED59E6B4F77DBF97EA
-:108B70005E47809ED77F03BA6D5FCEC7ED00BA25F2
-:108B8000F5A5DB59FC07E8D38474B345E976910574
-:108B90007FEE298476671AD1351EBE22DF005FB5CD
-:108BA0000AEFFF26A7FF874E949F9DB65E7A4D463B
-:108BB0007ABD78318F01BD4F997AEE63E58CF5BCB3
-:108BC0009AE0DC0CF71F7CF58F2427E75E7AD78CC0
-:108BD00074843FBB02F33AC77AFFBA709E8D8A98BD
-:108BE000E716472421298AF7C6F09409DE24BA7FC4
-:108BF0009CEE8739FF22FEB2913EE17D772A71E833
-:108C0000D1E12CA079B07006CDBB61CB9FCCC83729
-:108C1000924E481F6524D2EBF878BC2FE924E71D5B
-:108C2000DB9F13F1304243B72D5C0EFBD2B5C7CCAE
-:108C30000AE3D10BE0C5EF105E689FDB94A02AC960
-:108C4000FC7E0ECCE39C89CDE84038C2CA1FE3D13C
-:108C500097B125349F1762E552CCEF6A727935B827
-:108C6000FF51BC3CE37452FF123F67BE8EAF9F0FB3
-:108C7000A19C03FCBBEDC183C83F8C59C227A09FB8
-:108C8000FB99C2920BA37893F09E5119E9DD33BF93
-:108C900034864330FF651DFB49CFC6CA37CCCBDFD6
-:108CA0001167BC3F8AF11A77EF1B8A7AE8CC1B7BED
-:108CB00088FF1AB71F3787A09F43DB7E63EE2E899C
-:108CC000F23BEAEFB0467F9FF9D5BEA1A46FB1FF9A
-:108CD00038FAE684E8BF69AFBEFFA6ED7FD6F55F40
-:108CE00017EA303BED571FE7B4EA9F8EF33DDD6591
-:108CF00062A8FF4E77182784E38CFB96B05F124F73
-:108D0000CBDE35931D2B7F2F319C00785AF8EE84F3
-:108D10003F25A7E3D5EC05D4B2CE16CE579D8FF8EC
-:108D2000B3912E9DEFDE63447BB20BF1784DB4DF3F
-:108D30008A23CD550E90DB8A63817264AB587D30F7
-:108D4000E2A84107378C9389FA7929F4E3857E9864
-:108D5000EA7307A05F63D2F809088FD169705AE3FC
-:108D6000DA55DE9FC91E604180CB0476DBABE1277C
-:108D7000F7D4A4A12C19A7E731A05E5800EC85FA1E
-:108D8000D96D66C52AC0C70C89BEADD0EF82C1FEC1
-:108D9000D283D05E30DBED0BC173CF1DFCBBB34E75
-:108DA0007BC8703DB6F3C22847B64B46E605D5777B
-:108DB00046797B0E039560137C95DD61233B6353FD
-:108DC000BDEBAAA16DAB557D8051F6993D989B9264
-:108DD00081DF99E93B4F8AA27E8EF34E6249286F6C
-:108DE000B27FF99EEC97A991A1387F66612A03BBF7
-:108DF00092C338DC46319F42D6A5207FB74E49DA70
-:108E00008CED0D8E5AB2FF79AC679F1FE8F66CD2DD
-:108E1000F8C3A8C7E05F03BE97DBACB7EF0316E962
-:108E2000DBF92135467EBD8600F05F619BFE7E7AD0
-:108E300055E5FC013EC6EE4BE99CA082FE4E9F5ECE
-:108E4000B9231B703A69C57BBCFD7C65A907DAFFB5
-:108E5000B1BA61A20A7A24FDF795A579D0BE90FA3D
-:108E60008389F4BC0E907423A8FED54327864AA2BA
-:108E7000729B0160261B499E6F463C9C0D9C598647
-:108E80004F1BA67D658647F817403CE48EE478C802
-:108E9000B11FDBC1E0FD0186EE16E4CB9FBFFABF38
-:108EA00052F03D2F73D27C9D6CA9F3730B4E9E8DB7
-:108EB000BC3CEC4AFA4C659F4B3E3446E520D91544
-:108EC000BC3D05F86AD9CCE275E351D7D6FB88BF23
-:108ED000606427D943F9BE339DE85323E883705A71
-:108EE00080CF66F357582D6B177A68AC13C7514281
-:108EF000F5C6CBD77D7B78664ABE713007DE57EB6F
-:108F0000BD045757867F36E2EBAF1941BACAFBEE74
-:108F10009933BC41C0EFCD2981B9380FCF9C4B7933
-:108F200008FFE41446FD55CDB5FBD1AE5ED80BEA83
-:108F30002F8E5CC9EBE6C5CCA70EEAFFF9D4D4E0CE
-:108F400077B1FF82D7BD3B0F437FD7D7987D5618A7
-:108F5000E2FA45E53E358DF109A1DF21E8E6465A02
-:108F6000A2DC7D8F8551EECE27287E3FB4CF3FE433
-:108F700024BD9C5333F930DAB3F3B6FC8E08DEFF20
-:108F80009197E4113C0005E521776F72C49A44FC87
-:108F9000FC550C3F7FA5E75FFDB8E72F7B77775344
-:108FA0007F4ED11F3844F03C57D0E9BC91FBE5E738
-:108FB000177B090E701FF7A1BDFDA6E33D9922FCAA
-:108FC00024419F47ACFE35480FC0FF3A2DFE7FD6A7
-:108FD0003F1D37E27B4047BAC6D2718EA5390FF5E7
-:108FE000C283818EF1A0B1D9C939DFAB40E69E9230
-:108FF00012DC82EFD7CFE83A6422689A8B506EFB7E
-:10900000D259217DEEDAFB408B09DA4D48276F5F9C
-:109010007A5EBFA894E8A6A16F07F67FFDDE3F1B2E
-:10902000107E49D7750AB703B1DFBF92A28871EBF2
-:109030005B4C80CF0BBBCDE4FFC6BE7730C54BEF9A
-:10904000C9F6504B854F0539CD34B060BC7E0FF664
-:10905000E9D7E24B88037F6F7F4EDE1FE0FF4D2D87
-:10906000FE7FD73FFEFF5DE0FFDFBF25FE8F209D27
-:10907000FBC3BFF4BBEB847EA863ABC8DFFCCC3F73
-:10908000D53510C61F6FB4933CCCDB6A243984F706
-:10909000277B5C517D32EF86E67D38DF79CF28C4AF
-:1090A000B73541AEE7BF9C33F910EAF7D9ED7AFF47
-:1090B00069CE8C9019E19CBB5E7F7F5E38261E6472
-:1090C0001ABD0E7C7126CABF03B8DE7193BD340A87
-:1090D000F9A89A5B928CFED26B26EFEFC91F7FCB6B
-:1090E000C836C7C17F5E6A3ED963D9CE6D06246992
-:1090F000EC3CABB11A505FCA7EC7CE2DC944BF66E7
-:1091000081C37BC5386CC022BD5DCF0F2532AFA6B1
-:10911000DFC2B6545D7B507B96EEFD6BD617E89EA2
-:109120000F0E5FAB7B7EDDB6325D7B48C78DBAF735
-:10913000AFDF3D46D72E8DDCA67B7FD8E1A9BAF6FE
-:10914000F0AE7B74EF8F383A53F7FC86EE0775CF9D
-:10915000479D5AA06BDFD4F343BD1F6360A427591A
-:10916000A2427AF3C0E253152790E1CA95B188CFA5
-:10917000AA91FCDD03F3CD0667125E8B0C4EE08FE7
-:1091800037664F263FE0C07C97DF4BD70A3FC63F8C
-:10919000CC38BA3C18C7CF1DE7FCA2E28466DC2AB3
-:1091A0008B49A7E7C639F5ED61A9227E18C0F9669B
-:1091B00064AA5EBE8CCD9323666866CD1B9889E356
-:1091C000819C8D4AE57246D7ABCA59527305B641A8
-:1091D000CE2A53E3C81913F6B652F0135CFDE632FB
-:1091E000642C07D9653FDEF4D2FD900AF1CA188BD2
-:1091F0002FE720CECBE04B47261C3B237080F72780
-:10920000EC332B367C1BFB2CE5DC6DF086C8AEA561
-:1092100032CA2F3D35BB289969F07B4FAA41E883BC
-:10922000761E473AB70D53251E0BB4F7270C578B04
-:10923000A3F795B9933351EEDCFDE845B3BB70F06D
-:1092400016D0C7664F3E5DE5FD65330C13C271E86D
-:10925000DB90CAE30CE9770D8EFA5D0D88DFB3EE83
-:10926000F7D60E027C3556F790DFE536B4CF3F8453
-:10927000F3FAAD91E7CDC0B342BD305BF8D1B3276F
-:109280003E3EFF10E8A7D9EF0C22FD24C7D9B03825
-:109290003258EB37E4F413576D13F06C5CEC1F5C41
-:1092A0003388E022FD20FDF4BC50C3788C7706B0F3
-:1092B000668A1BD71A586DBC7E968B7E3291E40865
-:1092C000AFD34E727276CEB12415E691E8082E47E0
-:1092D0007E9B797D5705F7C7FCBEA9C03F79917B7E
-:1092E000D7E2FB796E958595BEE3675607DBF261A1
-:1092F0007E4B530D3E3BB57B147C3FE161C6D2E013
-:10930000FDA57F37123C4BDFB88161BC96606F666C
-:10931000E8D7CA79ED4F7D9AF063ECB4911D64E80B
-:109320009202FEBE2B687FD15DD3857EC7C5274DD7
-:1093300034DE4598A313FABFD8690CA3F37E283511
-:10934000316280B6B1CD41F63B0F7D50787F4EA79C
-:1093500023ECCD8FE2455D3F9A45C0DE25E4F0F970
-:109360002F4DB587EDF934EFD5386F09A79C776E8F
-:109370003F71682495DB59E62FD6D1D903315917AF
-:109380008EAD82F30FFD189F34519C383BC54E7053
-:1093900086178706D798FACE6F997BEAED77033C5C
-:1093A000AD478CCC08FD78BBDB091F73001F616FD4
-:1093B0005F7C9FF5E67F653012DC11E447E3FAF14C
-:1093C000342F867E3D7CD7F073853D9D8F7C199C24
-:1093D0004074CE32B0ADF97DE7F1662ACFDF1E4E84
-:1093E00075D2D5EC2EE272E21E38780BF4F736EA2D
-:1093F000290B8BE707FC3E95FBD3748DD54F600797
-:109400004308C785F50AD1F3A412369B006575772A
-:1094100036933F20F593D16F24FF43EA290917E8DB
-:10942000B10F5235F6D198FCF050ECB77F7F6DC785
-:109430003E33FA6B4E46FE9AD4A3FDF96BE8A721A2
-:10944000FF493FED54CC3C617E5F8AF97D196F7E08
-:109450007DF4EF3DCDD2CFF973EA15FCCC0C737CD3
-:10946000FD744D1AA74393D3CC283F85F132FA0FF0
-:10947000F30CE1CD988752C3D6291AFC64A5493F65
-:109480008FFB1BFDE9BDABC525052B4B48FF5EE8F7
-:10949000F226A7C235FD53A5395E3FC6452F0C43C2
-:1094A0003ACDB356DAD2004E679A1E5F4F2DEF6366
-:1094B000BFD2D238FEE8DA077F76C09F41E727EEB9
-:1094C0002AF212FE3C6957F013CFDEF15105DAA5FE
-:1094D00073024F8DBD712FD7D35960AC30AFD5C05B
-:1094E000FCCF9E28E6EDCB0AAD7A50BE6EA33D3090
-:1094F00008FB6FDA3DF159ADFDFE3A95E7D3983D93
-:1095000095F2ADB23F97D0FB1067DFFC9997F4FF5F
-:109510005748DF68BCDD5D81F156EB4BD724A37F54
-:109520003676D7DD4EBC5E481F48783DBB2BC18FD9
-:10953000709E4D057D6CC7F688439887F872F1E1FF
-:10954000542D5DCEFEEADD0A13F47376E7BB152ACF
-:10955000E63344BEA6D71E5DFE434500BE0F8D61B7
-:10956000C5CD760D9F58B8BD78D2CAF31D192EF31C
-:1095700032763DC4231929F4FD1A97E12778DF6874
-:10958000F943DE0994B398FCCE93266FAB1DF80C1B
-:1095900062391FAE132C18ECF7CCC6FCCE1437E59D
-:1095A000655A15AE4743B3791C9A5EC08AF3A13F52
-:1095B00093C168C4EF7A3CCCB7195E4938D01E41DC
-:1095C000B597D8D5E147F0CB1353099FA3CE3815F3
-:1095D0008C27643E48ADE2FDF54C3387376BF24093
-:1095E000EE192AD9459BDAC1504F3F90914AF0CBF2
-:1095F0007C50D5D419814A84EB5103C533A078152A
-:10960000D487D9621EF99E9DCBA56FA3BA902D1960
-:10961000267FD84AE0FF8180E724AFC18FF9D7A425
-:109620009CC85113F877D94B19FB44E347DACC4275
-:10963000DEDE3192BC39BEBEC53203FC235B22CFD5
-:10964000AB260596CDC7BC38DEFFD732A40BFF9EF4
-:10965000E863C434150B2503C88E91FA7E25FD3AC4
-:10966000175B7C0381A1772E76D2F5B9C56E82EBAC
-:10967000F1C55EBAFE747131DDEF4F4EAF767D6C91
-:10968000318CABE1A7F4118015986FBA91913C3FF2
-:1096900036BC2279661C7F405E9F5E7CD835769012
-:1096A0004020D023ABDEB969453ED119850866F765
-:1096B000CE72FF68C61E35F9E73360ADD5695F8F9E
-:1096C000C5BCD54AC54079AAC7D3DE5C1ECAC1ABAA
-:1096D00097E86EDBFF3EC37CA7A7BC5D4179F7D45A
-:1096E000B7131F947775B1A0B8EF87B6E708BFFF2F
-:1096F000A895E379156313105EBBC202783D67E558
-:10970000FEE0E756AE1FBF10D72169C18D28C7FF05
-:10971000E53C5AF42880672DF9200FD73B6CFBFFFE
-:109720004AF960E350B305E5C3B3F738AD83180DCC
-:10973000DD660626F9F5273EA6FC9AD11CC8E7EDA2
-:109740009756603B2329B0095D3616FA78E2013757
-:10975000C80DF2C38D848D10CAF14AAB68878E1193
-:109760001E569A78FBF527FE44F35E690ACC43BC8B
-:10977000607B29F4B732A5C36D80B6BDE5FDE587F2
-:109780006FC2B67CFFFDE521F8FEE534A96F021E2D
-:10979000D41FBD6D27B48768DA2A6F330BBFCAF9AF
-:1097A00035ECFFEBA16CE0D7C6BD4A0782E6D9BB1A
-:1097B0005AC1797A76AF267CD31FC8074E83F2A4AC
-:1097C000969019BF7F6EF161E752A0B39ADAE64234
-:1097D000BC5FE30EFAFDF1F21319D2FF85F7B579FC
-:1097E000B6B0A9A75BE38F7B18971BB614F4431C94
-:1097F000FF626846E517E9D0CF934A708511F5CC32
-:109800008B2627EA11D6C5F5D019D1170B67917FA2
-:10981000536FE54DD392E08AC1A827EE557D183FDE
-:10982000D7E5B757A27DAFDB93EF6B61517EA94BB4
-:10983000E9709521FFA4E8DBAD22EF9299D29C92CA
-:109840005282EB11ABF370BDA091B5DFF74384F703
-:109850006D23433FFD8B7D37248F827603B4D16F18
-:1098600068E87CD78CFCF9443AD79F8D9DC03FD0E7
-:10987000CF2A902F3F38329B546722EAA7E7FCCDCE
-:10988000D7A28BF7F5137F9B6805FA3E5FE077223E
-:10989000BDDDE9A61516701A9F373B07B3526CDB86
-:1098A00089BFEA4A0D5C8E98FDB77E55AC7F42FBBE
-:1098B000F813136FD3E6773DB82E03786EDA600F96
-:1098C0001992C9DEFC6FB4B78DEB0D21D45F064B46
-:1098D0009719E9EBC6B55DA28F93F0B650EAF3187D
-:1098E0007DBD7062EA6DD85EF86881337485FC6571
-:1098F000ED251B0B6BFCA327D2B91CD7AA215A4715
-:10990000A9BD9444CFFF79E3595978D895C6B3D30C
-:1099100073395E7D743CA2EBFEB2DFAE1D08745B52
-:10992000B8C36448D0F0DDC21D62BDDAEACFC47EA0
-:1099300032CC4CE01DFC7DC0AF9ADFDB0EA920E7E6
-:109940008FF5CAF98015634723DDA2CFD9489D1E44
-:10995000F063BCF958A2D403D7C47F3F31E6FD02BF
-:10996000D9F6AD189BD3179E8CC468DB02EFABFF12
-:109970009DD0DB46F8561B62FA4B95E38FA4FE247C
-:109980005F1D4FABFC6D68203C4F69AFC4FA8D9EE4
-:10999000D9CC8B7619F9D5A7D1FBC7D3B85CD75EE4
-:1099A0002AD4D13B8AF722DDFD938BDDBA75BFB98E
-:1099B000D50B697DF238EA79EC878528AEAADD906F
-:1099C000CDC21A7FEAFFC3F18FC231AA1F386EFEE3
-:1099D0001F86235F279F513806EAEEFFA3706CBEF7
-:1099E000ABE8B67C78658D12B214A05D78C440797E
-:1099F0001363CA586F0BAE3F3CA2929F872E09D6C5
-:109A00007F14A8ECB05A86F2D3EEC7389F2DE1F947
-:109A100023B8DF662A233B447E70E1DE8407D04F03
-:109A20002BA8F5CFC32BCB29A1F50DB92EC8441E09
-:109A30004CAE670C72B24A159CB751190F909D2A13
-:109A40000854D7A13367749427A27D5C630887709C
-:109A5000BCD0E37CBC0C43B8C382BA3769A013ED19
-:109A60005D4612D77F6C4509D9BFCD86826BE7036F
-:109A70001C8F2A95896F219E530A28FF8BF717C0E8
-:109A8000FDCDC26E19537C4EB4539B85DD6A15FA29
-:109A90005DDEB7A5061E407FE254FAC2DB2C37A07C
-:109AA0001EF2B7A581BD3999BE7085DB83F6C65B12
-:109AB0006001FB72F2C987C8DE6C6EF1663953A291
-:109AC000ED41FF0DD69AF4C4432BD05F596A5FF085
-:109AD00020FA3BF0FCB716D0B3CFA70ABD239E17E0
-:109AE000F4EA29D04BA0C78C2DBDED10EAA5825E0B
-:109AF000BDF310E99D2D1B8DD47E07C643FF07E6FD
-:109B00001132E27C07A9E4D75B019644685B071732
-:109B1000D03A11CC9B25A27F3D983F97F97CF3204A
-:109B200003E5F3F17DC4A3D5C3DF374F613E5CD7B6
-:109B3000323BEC1487C8F501A358A74A14751A8A5A
-:109B4000730AC5779655650B301EB30CD4AFC39A14
-:109B500063EA398CB1F51DF608F95F5FA48BBC7E12
-:109B60001A735F2E8CDE07BD5D8657D7DD4B2B1138
-:109B7000DE050EE634625E2518A175CE58BB66017F
-:109B80003BEAD5C887C5CEFCF1EA090E65703FD621
-:109B90007E49A5F8E64905FC1BB4A30ECE67D23F6B
-:109BA000323925DFEAEDAEF4974C297C2E0B278E57
-:109BB000C9C4F8DD68F75BD0CFD9E72CA3BC80918E
-:109BC000F96EAFD4F83B4B231329FFA63AFDE48787
-:109BD000178A38D1E8F431AD9FB36C310496D73091
-:109BE000F66C45D1189487A7AD114B21D2778D81A2
-:109BF000E2BDFD650F8614CCBF2D6224A7CF56B8F9
-:109C0000C6601E7D931A48BE17E5E5088CE7E5742B
-:109C1000E3EBB9AD0AE68B2F5A02C9A80F1E43BE6B
-:109C2000D7E0E5D7021F7F4FE7FAE75113978B651F
-:109C3000004F04E0502F5D47F9ADD5193CEF61AE00
-:109C40001E4BF91F33E003F37B09AC39E4A4F9F2AE
-:109C50007C5D82DBA0AB0B542F0DA5EFFF9E6ED079
-:109C6000C5D56D304FAF467F595988F27588E3AD41
-:109C700071FC977732783C62017FC84BFE49CC3A41
-:109C8000775FFF88FC15499F5E3F4501FFE40AF1BD
-:109C90005813C4CB5A7DDFA4F690FE6D827818EF7E
-:109CA0009F735AC83F94750F76A1CF96B983EDA3E1
-:109CB00090CF139386621E40651D84945558F7809B
-:109CC000FAD0ADF6F4F23FC87CAB356933BEB75479
-:109CD000D441D87C7AF94964ED113FCA67B1466E28
-:109CE00018E23B44FD2678F5F7190B328C33547794
-:109CF0006C9D44A8B71E8AEAF954F614AE5F4BBFB8
-:109D0000375BD4239DB57D447934F07B2BD3681D1C
-:109D1000A087E21699EFF9B67E7221F68179844523
-:109D20007FA938817236657C3EDEB7A99C4FC0158D
-:109D30005713CA30BC1A3F2F05E67FB7B07FE9C67C
-:109D400076AA1B795DC4B3FFE59CE1A1380AF0490E
-:109D5000F53689BE6E8A17859F66ECD58F1F2FF763
-:109D6000EBFDCE90D6CF5BB9E6E3E54B79BC42ED97
-:109D7000D79F8890FE7CD42ADBAF501BEC5C04E3B9
-:109D800025B62BC18B7C08DFFB51DED85D45E4672F
-:109D90001B0B5816E2636C9285F4A67157C266F4E9
-:109DA00083212E7E394DB35E7CD671340FFDE138B0
-:109DB000FD8574FDE57DBBFE60FC4EACC791CFC751
-:109DC00026AD8F18F9775EFC8EE5747D1482FED780
-:109DD000BC94C056000A9F36E9E55D5E370B7946B4
-:109DE0007DA3AD873457D7F891A9A55C27B813593F
-:109DF00044C34F52CED54B835944232785197C5DEC
-:109E00005555FD9447522F95D0F3BFA34CD338CE70
-:109E1000AB8C93DACF38C3487FF43F4E85D02F4CBC
-:109E2000AC5FA9545723F5427F721EBB4E16AB1789
-:109E3000E555EAC5CC0CDEFFBE0C7DFEF5C1F51D77
-:109E40008790854EDB830732A83EEA58129AF07A53
-:109E5000436428F2F1677DEF37E2E4DE4EE379FFF9
-:109E6000A26DF3DF4076EDCA085E443FE8B71962A1
-:109E70007DD20DF6D088F60EEC4509E5732FA6636A
-:109E80003E37E85D378EA13CDD45F9DC6457A00420
-:109E9000FB5F36B582720E12EE958B799D9AD4B324
-:109EA000763548F8B2A8217E7506C186337621C37F
-:109EB000344955109F5C8E8EAEB940726055FDC41A
-:109EC0005756A7C18B7E8115E242D4BB2D4E035F4E
-:109ED000BF715B28FFBF4C810811F4C68294822BAE
-:109EE000AE8F9B2FB9C8DE02246EADDEFEE78F93E6
-:109EF0002EEC837E1CD5C9FD06B69FDB6144C2A74C
-:109F00001A7D2CFD81D8EF62FB97F894F8B5205E9E
-:109F10004BC81EC6F537AC2EFD7A66A6D4B71947D6
-:109F20008B2270B741E94E42BF06F4A8D5857A7AF4
-:109F3000484F92C14BFAD7C5FDA090E06B66D7F2AF
-:109F4000B5CC53CB7949F817BC35DBA25D7F898549
-:109F500037D6CEDA4BF4750B56AFBE6E41EE0B30F2
-:109F6000AA01E21BD368BF05E5A4C559E6443F67D3
-:109F7000A9EAFDA39FEA2D4CE46F83FFAE1B5F5E51
-:109F80001F03F947384A5D065D5D8DBC3A701D259B
-:109F9000CE77535C5C4F3DB6EF6ED2C3AA8FAF3322
-:109FA000C5D28FB176E21747117352FE54C09B742D
-:109FB000957EFBE3A39FECB3929FAC8EB484B1AECD
-:109FC00033763CA329E05750EF9632F2938DB97C5B
-:109FD0007CE3204675E049E5A9AC5883C765EEA946
-:109FE000F47C41869321BD8D0E43201EBF483C0D5D
-:109FF0007419747CE3967CE3F9A008E540C33781CB
-:10A00000787C33D0C5F515C2A1A5EF327741663C07
-:10A01000FA44F522E7ABABF1C54C1BF7733ACD5CC4
-:10A020006F36208E205EAACF302FC3FCF7190B7F2E
-:10A03000CEFCC5DC2FB3709E9B69CB0BA33FD4A98C
-:10A04000FA6DE897CDEC5DB7F5D37E8F7AAB3FF92B
-:10A0500006B48FEF72BFF964A5BD4D817E4E9AFCA8
-:10A06000C988EF93EF1A95165A07E7F573B20EE910
-:10A07000A4C9BBF25A783EEB67467F0B3DD6FB8303
-:10A0800067987FD83BE81FEF36D27A4BFEE30F1874
-:10A0900087C0FB35E028223FCDACB287D00E777E5B
-:10A0A000D0FC11EAA3591B13BC4BB08E65FDB0AFB9
-:10A0B000B0FDF92A873781F26C058A07F35FABF3AD
-:10A0C0009DB46EB2888978EECE4955A0437F89430E
-:10A0D000CBFC35CCF973269F87568E85795E9BD154
-:10A0E00069B0034CCABAD04A0BD0EFD196801BE3BB
-:10A0F000C70ED7F495183FBA5CFEAE5B205E3CE11C
-:10A10000BA7B12B63B9F96FDDDB3D20F7AF91543A9
-:10A11000305F81E7B6CC872651FD6AA1EC7F193DFF
-:10A120009FF9F36BBE3A0AFD97AE5B3F09736E155C
-:10A13000D5E2FBD03304DFECD1B2BDD9563510BE29
-:10A14000B7315D1ECD148D47294FD7D9EB5F3D3711
-:10A1500009E3CF59639AAB54E87FC9BAED2B4B4062
-:10A160004446B4573AFDD0FEF1BA3726D980DF3ADB
-:10A1700099BF0EE3DD95EB0E4CB2DC04FDA7E9FBC5
-:10A180004F378A7C6CE8F04ACCE3F5C2C7DE5FE962
-:10A190001F187D7F983B61552827CAFFFF22F81FB3
-:10A1A000F8FD572E5C07B4741FC2145DDEA21E3387
-:10A1B000AF7B15F52939DD4379DD8D681777F33AE3
-:10A1C00065D976F376E792F8F6FECF6E2E779D8905
-:10A1D000F19F7F24F439C0EDC7FA95E4A3CCBF3DCD
-:10A1E0008E3C1D74D949FE0E82BF67498DCAD5EDDC
-:10A1F00020DB23B1FEC7C2E194FDC47E7F4CE8277B
-:10A2000016BA3D15F978B2E0F3429FC2EB7876DBDF
-:10A21000C283D0DF6311F50E98CF3691CFD8666533
-:10A22000F74F81A15D892CB803FDCF346897D0F733
-:10A23000FE1DF6687F6F735166E30A035BB0BF7162
-:10A24000999ED2D6FC683F00F7524B990E6E75640A
-:10A250002A3E0F65CD2FD1E0B384CF03F884F005FB
-:10A26000C3BC700BC84B67D7B5052B600A2B5D5E6E
-:10A270005DDC57D13595F6A5FCA79BFB3FCCCBBF4A
-:10A28000CFA8E275213D7B6C94A76096AE22A49383
-:10A29000FCEE92C047D58F27AFC3F7EABB4C8CEAE0
-:10A2A000FF77545ED11FA8C7BC9EC67FAC5723144E
-:10A2B000CFD5635E6F18F6F7B619ED18F6E315F90A
-:10A2C0006BCCCB65B4C6A7BFB487F5975258685816
-:10A2D0005FBD19ED3F9D9E5F6D5ED1FEF47167DF3E
-:10A2E000FECC621D40E05D157837C7877340A6E05D
-:10A2F00053C0B741C35FB305BF81F6243FE0DCAE76
-:10A30000C19B57E46BC7E5FB6E403FBF700BEACBC8
-:10A31000AE448A5B2A54FF247CBFA22B95D6172417
-:10A320007F48BE9074ED4C6DA67C4DCF530AD9C1C9
-:10A3300058B88A245CEB158223B33A687C40039FAB
-:10A340009407E8BF53F45F3E92E4E7192E0F2037DD
-:10A35000F7A2FCE27A25CEC3D73D74EA90BEF0FFA7
-:10A3600014EDDF70A223C7FF4B5651CFC1F1D617B2
-:10A37000FFD957A1671E3DAFE87A83E659DF8FDC2E
-:10A38000BEED4E2238338F4692BCF0DE1382FF3B87
-:10A390003B3E4D1A8572B1DBC8142F9F37EAAD0AD8
-:10A3A000A98FD99CB7C780FECBEC6D83BEF4221D6C
-:10A3B0007AF567C46289BEFFAA7BCEE4A5F02C3D86
-:10A3C00081CB6BBA11AC4D59148E6999DCCF1A1937
-:10A3D0008CEF97BEE776D07389EFA71655B14F6122
-:10A3E0007E3F73F1F5CF91DD2105E922E53A564F25
-:10A3F0002DCCE4F2383FF3FF919EB25E454F59A554
-:10A400009EE2F70F427084EFB95CDD4315F09F6B5D
-:10A410000C7E17C66127DEFD21EDE3982BEA5686F8
-:10A4200060DD0ADACDA301B22B5FE0435EBFF20824
-:10A43000C680B3DBF5F52B6C0BDF271ACB57513EEB
-:10A440000A09FF5DC021ECC1ED09DDBFE245C67A16
-:10A4500079966D80B3D150A8796EE7764BD201E83A
-:10A46000BD94A546E5F8935D999B50DF0E73F3BC50
-:10A47000627AA1BF14E72FE512ECAAE013C3FD53E3
-:10A48000ED5C6F4C8DC3BFCF08F99CBD9EF34DE7CB
-:10A49000DFAA2621DE3BDF4B4D59A2D1135B851D80
-:10A4A00094FD4A3D24BF93CF9F15FCB12D3389DA2B
-:10A4B0005B5D0E91E731C4DD37B755635F897FDAA5
-:10A4C00038FFC07C435AFE1EE65674F6B5D7AE0A76
-:10A4D0003C379801BF80BF6DA65016D6ED54741955
-:10A4E000A8BF9ADD0EAA07ACE9E078AC69DF67A8DF
-:10A4F000D3E027B6BFFFC8E4FEC02603AF233A6807
-:10A50000007E43BCDB397CE77679487F1E16EF5D21
-:10A51000DD6E7C333DB3C9CCEB4881BE54CFD7F060
-:10A5200072F626BD9E6E11F80FB6E23EB6F475CCFB
-:10A5300087B55680A78802704F770BBD63F69B7175
-:10A54000DF6ACF538CD6F30755FB4BBDD06E0AD8CC
-:10A55000CB14E8AFA89DEBE18A27C18F41B9B3487E
-:10A56000BBF0D676ED78C7321D221EE1FC5CB39EAF
-:10A57000E36F10F83F2FE015FAF915F9F11C9E4F23
-:10A58000D6768CC2FC93FCFE0B41FFABC15781F029
-:10A590009547E1C3FE919F983DB004FB6DFCC3CE8F
-:10A5A0006C6DBF5F65727D9B6E9C39C68A7A7E3505
-:10A5B000D81D92CEE07EDC9750B337C5B982913C6E
-:10A5C0001B30EE91E3D6883C24C85DC514985A51DF
-:10A5D000EF3892AEEFBFA89DBFEAE6FEDC3F8BBE30
-:10A5E0009DE620CDA76707C0EB8DE2A5B3E38125EB
-:10A5F00056B41347990FED84847750757712D69D22
-:10A600003409FB01F33560FC92FE332F6B45BC75BA
-:10A610008D3163FC14CBD7924EC58CCB8F8CD38AF3
-:10A62000718100DAB9EEA142FF308A773F79F9D51E
-:10A630001756507CC5E9D254CDE958E90E4E7767DC
-:10A6400044E510F47905EAAB9A277BF55107BFDFA3
-:10A6500095570DF8BCDE2DE55C4F97F4408715D774
-:10A6600035245F9FDD3324BC82D399C6EFEC708420
-:10A670001505F7A136B760DC2DF504C2A3ADC39470
-:10A68000F0F4D291011D8744EF0FAAE6FD3581BC9D
-:10A69000231FD51B9B158F427A80F2AC99A807A087
-:10A6A0009DD9C1DF637BF9B908124FF5D3A1538857
-:10A6B0003BFDEE129A87C4576675C4500FB72658F3
-:10A6C000AAFC2734FEDA61B1DE8078994AF106D718
-:10A6D000D7F5C6400EC6AD2C3381F671821D22FD22
-:10A6E00072D0CA542BF4F7265CD12E8D33CEA77DC1
-:10A6F00034E30A159263D00032EF13417FFAF65B20
-:10A700006C24FFECEB8706E23C336C9C0FA11F8BA3
-:10A71000E8C7427650D883DFE7815FA744F5F2416E
-:10A7200045A17E0EDE74DD66AA2D147C89FDA1FF95
-:10A730007450999243F6B23343141771F8FBB7671C
-:10A74000DD79F85C1B2F627C178D374B57DD0A3C97
-:10A7500035624247C4E044E9289FFC7D807F1CC4E9
-:10A760009B5698FF0382AF0FE6878C4908D7209845
-:10A7700037DC3A94182C69B647C77189FC8D4BD4E5
-:10A78000EFA2BF80578387EBFF9F78B8BDF8505C7E
-:10A790005D49F1F33D17C5F38FED5C4FAFA88CBF5A
-:10A7A0006FFB11615764DC79BB58EF80B8F3113748
-:10A7B0008F3B45FD295F1F01FF9EF05BF5E36A5A61
-:10A7C000F7BBD8352D999F87C0F5C12C51FF79FF74
-:10A7D00023D37E8A7C7602EBCC010F9F0A7E39E17F
-:10A7E000F427619D544362FC3AE267053C0D020F79
-:10A7F0002717F3F30B66E1BA1CF0DF1A37F7F3E61D
-:10A80000B60F1B8F749FBB4AA17539B9FE2FE95C47
-:10A81000BBC1A8CBAFCFC275B9B47F249E2AED27A8
-:10A820009E2AD7C55372DCD8B8EA93C56EDD3AC00C
-:10A83000CCF642717E047F7F16F311DCB3DAB27579
-:10A84000EB88AC2DE31BEDFBC7382A14173EB3EEA3
-:10A85000FE278B2D2CA485E3D440AA9F78C41D7CB1
-:10A86000C5AD83C3C642BA7CE86827ED27B2F23C87
-:10A870002CF8E33C8E81EB263BF9EB13D09FEDCD1A
-:10A8800087811E7126A35EAADCEF1E1E8D1FA49C6D
-:10A89000D58F8E1F47AC117ED01A178F93938FCA16
-:10A8A000B83AD18BFA51FAE5B1DFBDD7CBBF7ABF49
-:10A8B000F26A7908E0E390364E8AEDF794FB1F8D3B
-:10A8C000BF0BFBE197A2FF91F8BB627490F27CACE6
-:10A8D0005DA19A961163F5F1D0D768D787E3D5A625
-:10A8E0008B876AAAF5EF310FB7FFCC63D3F9F1FD7F
-:10A8F000E153EBC72B85A807797F8D822FF24FBFDD
-:10A9000047F5A4A33DDC2FF265F9133C705D25EA01
-:10A91000C95759F97EFE4DFFBDDF3D0BFDA3774CB6
-:10A92000B4FECF7673BEA97C66612B9E0F60EF509C
-:10A930009CDAFDABDF59A4F86B40AED3847EACF754
-:10A94000F1F9D4FB22E68176AC2FE670E474EC5387
-:10A95000540DDFE5D4F2F7723D265D5E3C5FB4072F
-:10A96000789C328ED937311DDFF7ABE81764752834
-:10A97000643FB39A19F9D559E50AF5FF9DF24DCA1E
-:10A98000AC92E87CDB0C534A9CF05D9BCBE643FB2E
-:10A99000F3C3ACE0351E84EF582482E672C4B12EB6
-:10A9A00015E3AD5559FE62C4839CA7D7E8CC423F5E
-:10A9B000DE768CC3D7DE9B67E2F687B195C22FDDCA
-:10A9C000CCFD33233BCCB87F4E76DEB5A498ECA00B
-:10A9D0009C8F2B55D811170BEEB4D3FB6DE4B758F1
-:10A9E000B81FE05A5244FEBCA46B34EE1C5C867166
-:10A9F00067E1AA883A13BE7B798321EE7915E305D6
-:10AA0000DE611E95DA795C4D6FC9F74CFDE41D25BA
-:10AA1000DFDB26C48FE7C112D2F3CA67D2EF21F978
-:10AA20005C6A6698AF96F85F9515B813E1C9EAD8E5
-:10AA3000A4206E3E11750A9F24F27CFC272B5E50E9
-:10AA4000D0BF7C681E731A59FF70D72F32FA6BB4CF
-:10AA5000F2BCD44C7491F14A141E9E8769F070FBCD
-:10AA6000B42F2B5083E337EE5E4D71F5BC2DC7CD6F
-:10AA7000575C87F88678536AB9BF5E3FC342F54C8E
-:10AA800095CFA844F7BAA5665A37ACDFBE83F6A7C0
-:10AA9000B187990FE5BFBE63875203E3D66DDFA18F
-:10AAA000CCD6E031BB3E4CF5DBD738E47A4484FCAD
-:10AAB000E958FEC63C02FA2F87AC5CFECF54DA435D
-:10AAC000B83E71C614ACC7F7CE786C3E5CC79478BC
-:10AAD0007F73C7AD745E8063674204AF6D86CD6ED1
-:10AAE0000BBCD776ADD987FCB42A2BB81CF192AA3F
-:10AAF000063AF1FB9474870FD737BC09AC8CECF79E
-:10AB000037C4C38818BE18F130979757847E813FA9
-:10AB1000AAA77AD6C3FD725C5E427D75C8C4E7B150
-:10AB20009371780D1EFF7A944B763895C6CDAA8F17
-:10AB300028587F113B6E94AFFC1B3D19DF06CE0EEB
-:10AB400033EAF93AA16F2A9FD9A27CAA81FB458FEB
-:10AB500091E0CBDABE49C1FC193C277D03EF33AC51
-:10AB600077CADACEE3D53A783E5BA35FE43CE2E80D
-:10AB7000994E84CF7EACEB00D73311BE5E20E08DC2
-:10AB8000A567C4E3A5F1C783BB40F7CDA1628C974D
-:10AB90000F1524527F52EE63E534E2E17E65D686DE
-:10ABA0002D8AC14EEB2AE45F4AF8E47BBEAC310744
-:10ABB0003C84872EC243C30695E633CE1C18385F0B
-:10ABC000230FEF89FEDE98FE119DABF3E4BFBD4B72
-:10ABD000FCD8007136C519EDEF9AA7A19D09FDC2F9
-:10ABE00088EB6093B88BC2D68A73A72675723DDC5A
-:10ABF000D0B9439D658FF269FEE937E8BCAA868E1D
-:10AC00000486F115F0DF518427964FBF293D411F7F
-:10AC1000F1F829641679BE603EC63F524F1B84FC92
-:10AC2000333BBF7F41B4A3FC133CEDD1E9592BC9A1
-:10AC300045FEE9B237B0DEB3C1A7D0791D129EF44C
-:10AC4000AAF87EBBD48F526F633E31A0D1EF1705B7
-:10AC50005DA11DE1712A2B403B2DE18CA5D3802CF9
-:10AC6000AEC7E3F0D3DF11DE58BB25ED79FEC69DFC
-:10AC70002AEEBF917C3209E9ABE113479699E07067
-:10AC800064A9D4FFDA4ABEEEB8D6C4EDD5DA160B05
-:10AC9000D561BE7937AF0B73DC638EE0F5A06166DA
-:10ACA0003D3E3F98C5E168332CA1FD68207F49599E
-:10ACB00019C827498CEB41AEF79EFC0DD75BF521F7
-:10ACC0003BC5B9F5C13B6B68DD3FDDEAC37A591678
-:10ACD0003C609EE688E235968FBC3BF799711E93E7
-:10ACE0003AB8BC81DE243E8AE22FAC9313290F864A
-:10ACF0005E3F2198CFFD201E479588FD81B5161F28
-:10AD0000ED2FAC15F9D612B14FB0E2A89FECC14CB3
-:10AD100041878DF6C0755998A75915936FFD8671B7
-:10AD200040DDA2DF51DCF5A0FB2DBA4A79847855CD
-:10AD300027B73766713F3B5F5C2BB3389FD495775D
-:10AD400090BCD59D682639B54FE0FACA7E2CC62F37
-:10AD5000648F09BE5B45E38EB3758CC7F5E2713F26
-:10AD6000579CADAC7F38E7E23E2B8CE736EC4F7A50
-:10AD700000E5F96B882634FB70A666713939B30D8E
-:10AD8000104EF6A8D97C253FFB6AFDB1C81185CECF
-:10AD9000F910B83CB3BDEA86CF707D675BB20FF7A0
-:10ADA000D37FB9FD8E1F7C06709FD9728B0FED7F0C
-:10ADB0007A6B80F8A527C3EADBCCF3AF13303FD51D
-:10ADC000D2B13F09F7ED7CF1C2F565A88FE7657157
-:10ADD0003D75FA37C645889725CFFFFA667C5E1722
-:10ADE00056D2D02F3DB3EDE77FCF827E6AB734E1F4
-:10ADF0000962ACF585D7C9DF378437F1FBDB92C92F
-:10AE00007FFDE2D9D53723BE5B3B5AE9F9E96737C5
-:10AE100051FB8DE77FFDDADFE0BDFA4012ED673EC2
-:10AE2000FD9B7D4497FAA04A75E7BD7C1CAB077774
-:10AE3000ECE37A10ED37F2FD0CAE9F241F4BFEFDC4
-:10AE4000E2F9FB6FD0DA0379BF4DE469DA12B97D1C
-:10AE5000F852C869DD187B1B5EBF7CD14AE76E36AD
-:10AE60009ABB8B307EAF2FE17CF17D818FFA8EF91A
-:10AE7000A6463B7D4FFDFC27303D5E87007F627D0F
-:10AE800017BCB5E532D529FD8AEB99443612F33863
-:10AE9000D3AB8FF37D9B25CDA63A82F305FE1C66CE
-:10AEA000AD7D5EB1307EDCB83ACBAECBD366754EAD
-:10AEB000C9F192DC27F80669FCDAACDA60AB03EE84
-:10AEC000DFB630E8C37DEF2F9F7A6F3CEE4F78BE40
-:10AED000581946F4372ADC7E85EC344E03AE0F4118
-:10AEE0005CF1AC9013084BD36F84F98C53593A6ED4
-:10AEF000DD1DC7D81113E985ADF41CFC17F2CBBCDE
-:10AF0000AF4FDF8AFECC5A53D0331CFB6913766FE8
-:10AF10000B871FBE77DACBA83FE78DDC0F5F80DFA2
-:10AF20009D6F999C8E7E3BF4DB65D2C459C09179AC
-:10AF300068F7B0BF72C4D384D00CB23F5E33CD4F3C
-:10AF40009EE709F31F7AEF90A87CC6E691503F6117
-:10AF5000DE775F56E55ED433F2EAEA270FC3B2F933
-:10AF6000737FB69FAEDFF47CD037A69FE3F6FB95E8
-:10AF7000E3C4B78DC8B7387EF084CE7ECF927CBB59
-:10AF8000E738F1EDACDDDC7E37EE2E3523BF7EB940
-:10AF9000D8CF3E0507B651F0DF5AA57B0EEDFFDA9C
-:10AFA00063A57D7DE7247FAE3AFE39D69B16ECF68D
-:10AFB000509EE0DC1ECEA7070D068AEF0F6EBE6E18
-:10AFC00053ABD2D76E821F4D72D2D8CC841FBDF046
-:10AFD0003DF4BB1A6A799D79630C1FE56FFC641917
-:10AFE000F24B0A78BD583F037ECA78DA1759CF86EC
-:10AFF000A39C668DF5EFC9A6F53F1E7767D5823E07
-:10B0000081F66DE9F37C789455CA58F07791FFD2B8
-:10B010006FF2613E6C6D6EC732F48B43E3189D9BFB
-:10B02000BAD6D43E06E3DBB5E3BC4EC024E06D0BDC
-:10B03000F9CDACD82CEC570DF9DB8DEE7FF551BE78
-:10B040003A56FEF7B490DFD6E84DF4E139B6937680
-:10B050002B0BB89F6267087F23E017DB93C2A3C264
-:10B0600008CF59813F89C773A62E3A4FF7DC4B09A9
-:10B07000743EE1A4B19C5F53C67690FE7873CFAD69
-:10B08000649F255F3A7625909D4E559D0AE62F18C0
-:10B09000BB23414BD77651879B22EC48E12A4EDFF8
-:10B0A000C46CEE6724661BC4D52CF85C9EB712A254
-:10B0B0007CC259417FFCF36ACE6B6AA889903CD56B
-:10B0C0006FE7FDA527F84B1FD2F0AFF497E47A2B7A
-:10B0D000AEBF4E89C3DF3E0147FEC60544F759B5F2
-:10B0E000E23C8755DC8F60C0178837A023F1C16D23
-:10B0F000E973896EB35629F7101D431594D7947ED2
-:10B10000576CFFE5D95C2F6EB306CAB18EAF27C36B
-:10B11000E1C3FA806D297E03AD0F94A6507E2323F0
-:10B120008DFB8119C20F8CCA7DA0DC00E39C7239B3
-:10B1300038BDC3BF57316FEDCFF6C6F5EBFAC6EF9A
-:10B14000BCBFC9EDA1A118CFC8F563898F704BE2D0
-:10B150000CAD3EBD51E0233C98CD40BD0171829DB8
-:10B16000F2EB4E1807F3049B473DCBF304FC5CE77E
-:10B17000C26C9EA71B97162847BF2CA330B090DB4C
-:10B180004F3ECF587CEC13F6FD8DE9F795627CDAE3
-:10B1900078A7DD8772F7E42BCA4CE2EB90050FFB32
-:10B1A00001BEE772080E13D5ADB1A04AF4686C0E6B
-:10B1B00084E3F3FD1492B346F0F3D0BF9F847C9EEA
-:10B1C0004E7C1FE67CCFED9FCC23A09ED4AEAB4837
-:10B1D0007D20F50CDA37E46729178D377717217D45
-:10B1E000BFA95E3967E2727E0EF0807224E5C6F177
-:10B1F000329797152DDE4A7CBE02E45E4BEFD8B83D
-:10B200000BE1C4F855EAF71F66051AB3318E3044D6
-:10B2100096D1DE52A18F1B5F5E5E146F7F90D4C704
-:10B2200016711EA6256C0B6BD741B0B6C25146D71E
-:10B2300010DA23DBA2F87996966C695FFBD4A5B58A
-:10B24000640FEF5B97E642DB85F2B3D946FBD4642B
-:10B25000DE29B6DF87B2155D7E47C625B89E81EF31
-:10B260003F23E4A75DF0E573D932CF1BD6F1BFD7FA
-:10B27000103C8E7505FDD931F9DD3F2B0F26C791A6
-:10B28000F63496FE723D06E733A5A4FFF7DAF731F0
-:10B29000B1CEA7E7C717859CD46533BAB69B2217F2
-:10B2A00049AEE63B18D5F3AC67FE345CE77BED1A9C
-:10B2B0002E0FFE9E22EC7F606ED09A9311CDF7E2A6
-:10B2C0007D8C3FEB54164A009AD46D3385B5FB64F0
-:10B2D0007E86B58600C779872564043EAFC80DEE2B
-:10B2E00045FE0A8DE1FBE1423FB4D2FA1438D2C3E5
-:10B2F00051BF34B1EE24C473A3B1AB08F393D5AE00
-:10B30000E03EA4FF2786AE3C5ED7C1D7CF8E897CB6
-:10B31000EE3191CFED344772BF9F1E3D9FEE02E3A9
-:10B32000755517BA0CA918F77DB8FB0F2FBE025F31
-:10B33000DFFBCAD97B7F84D85A61BBEF6770ADB69B
-:10B340001803AA26EF76CC115FCF7E20F8A8B7EEBF
-:10B35000A925216E3E7F6B0E7FAF2966BD7A6B0EED
-:10B36000D7A7D17D4F7CBDFAC37ECEB5BA2147D4D5
-:10B370004B8A7AACD8E737E7707EDB666245EB1123
-:10B380009E4D0E5AE7672A3F8FACF6897C1FAECFE1
-:10B390007716F0F3EF7BD62864078E99B8FE81BF4D
-:10B3A0003B2D15513B8A6E0AFA89B5CE50C400FA7E
-:10B3B000A376A12382E760C27D7534CA5AC8497555
-:10B3C000C133857D9CD5FCE65F319F51AB32CB68A4
-:10B3D000F8EEA4BD2609CDC39CEF3E8447CCB0CC8B
-:10B3E000EA76513F2ACE57F34F365EB65DC9AFD3EA
-:10B3F000EF1BF9454E80E5C0FCAB9339BEAB1FE2B5
-:10B40000E7ECCAF77F23E43696DFB621AF02BC1F14
-:10B4100029DCBEC48EE3CC1DF302F253B53B60A31E
-:10B42000FE1F3A4B7AADFA152B9D7F5487EB5CA03B
-:10B43000F2CE9776152DCA47BEEEC9FB23E6C9F6B4
-:10B4400026505D721DAE7769D6A7FB5BEFEA7F9D44
-:10B45000CB6B46FE6DBCA410FD67EE7DF328EAEBD6
-:10B4600046B59BF862A6C54E786FBCA4D273D6666B
-:10B470003AA3DDDFB6D0EDCF47B8433F1E9D42EB88
-:10B480006599709FF0574CE7632C10F5E0CEDC60B7
-:10B4900031BEB7CE96743FC67D172CFC3CA4263334
-:10B4A000AFFB6662DFB0A43FCB71E8E9BBF7ADBF8D
-:10B4B000225C3596209D2B397B06C4C946A447647F
-:10B4C000B8B3444BD7D1DFEA5C5B7B0ED7371F9A0A
-:10B4D00079DD4F5FBEE67A69AB7C2F8BCBC787796E
-:10B4E000AC76275EAF852B7CF761816897F1766C2F
-:10B4F0003F33857C7C3894DBA5D0025BDCF33CEEEB
-:10B5000014E3FD22C73F19F125EF3F25E4CF99EB66
-:10B51000BF1DEF83DEBB03F51EF0632405FAAB7E8F
-:10B520009DFFBE005BDA4375A7BDF32A12F0BAE2B5
-:10B53000C3F5FD68BFF7607FF09E9FFCF3D7ACB406
-:10B540006F8D4D063D8C7A77412E43BD0BE3CEC403
-:10B55000F1A1DF480ABD9740F3606DA08F41E0CEB6
-:10B560000FF7125D5654029F968BF3F2BD51BE92B7
-:10B57000FC14CB474D424FC5598F6F42B862D7E399
-:10B580000112A237F1DBB7D8FF352A8DEB7F90E7A8
-:10B590001FE4905D8D0CD1D6F3493C4B3DF861A280
-:10B5A0009E2F4C02CE16F15E2F9EC5F953E985DC25
-:10B5B000BEC93860B5A0BB557C27AFD25EC5E6F3E7
-:10B5C000ADA25F6B4E92A4CB6308A7B4737DE8BDB8
-:10B5D00081D31BDE7B9CF44742CF7D6960A7EE02DE
-:10B5E000FF07CF9F84EFECF85D9F7CC4586E5F9B94
-:10B5F000163818DAFF0D39A24EBBBC87AFB715C39A
-:10B600007508CA1FE81DE5EAF4C3D8DF037AEED750
-:10B6100058EF01E329583F944A6AC08BFD01BE9F51
-:10B62000D7E23B76BC63F808FCBD1D39625F5C293C
-:10B630002B457ADDF7EE5F1CF77AF17C72BE1FF7BF
-:10B64000337BF025ECE7CC0FDE22FFFE983952D495
-:10B650006E8FF3DC1CD9B84E893EBFFF17C610FEB3
-:10B660001E4567D79935D3812F6776197D38E4CC8D
-:10B67000872FBE3302FDE62E13AD1B81DFB00ACF4C
-:10B68000E73C26EA0059B33EFE7F57D047EE0B96C3
-:10B69000FA49DAFF79CCC7F552223F0FFD93F973CF
-:10B6A000695F700D0B1CC2F3D0BF583091FCE2B93A
-:10B6B0002C48E771CF6AD39F871B7B8E6EECF9B95C
-:10B6C0009880477CC59EA3FBE5F7AE9C2F97F52B92
-:10B6D000B1CFFF26F8F1CB7EEACB4F0BFE95F500FC
-:10B6E0004DB21EE0D52BD70334C5D40344FD0C590D
-:10B6F0000FF035AF0778555F0FF0E598F8705C10E4
-:10B700007034E1393A71FB4DA2FB5F165C799E4DB6
-:10B71000782E4EDC7DDF76BADF5F3D822D57E0A9C3
-:10B720009F7A8C845CD9BF47678F6DB9DE183F2B39
-:10B73000879E37C5D435449FF37A06991700BA52CD
-:10B74000FD9CF4EF62F7C3CB7CBC949F4F1566F170
-:10B75000501E6DB5881B7C43D11FFE14FD2C94DF59
-:10B760005BBDAF7503A8B37E7443915A1095AFD8F3
-:10B77000F9005F9ED6EE3B1F902BCE6FF0311FED90
-:10B780004B147271DF0FC625633EFFE387AB74FB7A
-:10B79000CD7AF7A39BA57F67D7D9731663EF67EDC3
-:10B7A0007E8BFCB71A4B80F6BD7DF6EA0FC8CECF74
-:10B7B000610117CAC9F957AFC90BFE5FD87909CF24
-:10B7C0001DA1074CDC6F4F27FF64AA80E78EBDDC0C
-:10B7D0007F3458FC261AC7CFBC4E1785E61C5E5036
-:10B7E000B678EEDD4DBDF097D07919A305FC0A7E41
-:10B7F0000FF8BD495CD9CCA01BE196FBF881EBDCCE
-:10B80000786DBDC1E7C5EB2D4A40659AFD9DE359B2
-:10B81000730EBE6FB0741BC5F962742E7C42145F48
-:10B82000D47688F6D23B2FDC371BEFDBF9F9C26602
-:10B8300001473057EC5BB6300BCE3BC11EF982D6C8
-:10B84000FBC4353486FBE3A1025E479C88E717C042
-:10B85000B876FBD9104ED6C99CB42FDFEABC10C114
-:10B86000B844F3BB1035B9C335BF0BC1223C5FD51B
-:10B87000DFF398DF8D4815F0B50A3DE9C1F3050BFC
-:10B88000E91C05D2938F3BE6D079E219F685B40E18
-:10B89000FD54D2045AA77421E2B13E7E82E61C0414
-:10B8A000789E11D09F7F903943DFF604F56D0B3BF6
-:10B8B00046F55C4A24E0BE9C163DE7D124F4CD9DBC
-:10B8C000891CAE3B1379FCD69AABDF971990BFE782
-:10B8D00092CACF4938E7B258B0AE02FC93D65CEEBC
-:10B8E0009F7C0494863891FFDE4BE92DFE416BCAA4
-:10B8F000F1774C8CBE2540A7650E6F8B8A7EDFDD0D
-:10B90000E277BFD40EAA57D8745F8A0FEB6B9659B3
-:10B910009D9598070DE5F2FC4F93D8A70114A9DB7C
-:10B920000EDF6D9A9A4DEFA557F550FEB467392397
-:10B93000BFAA0F9F7E0DFC0FF87E16DB787E438D2D
-:10B94000AF0BF7ED7AFC46AA3396CFB7E07380537E
-:10B95000117C81F76FA988FE2E53E1DED2FD78FEBF
-:10B96000240B2A3E9E8EF412BF4F13FE7CD3DECAF8
-:10B97000DB87035C855DC3888D07EE15EB2FE90936
-:10B98000627D989FBF1BFBFE407C1FDAB6C3DE7F43
-:10B99000ADC7470688BBF1BB31369AF711917F627C
-:10B9A000423F8C8891BF515179A0E7A5A2DD24EADE
-:10B9B00001F1CC087F054F6FD07BE95C3E7C4CFEEB
-:10B9C00071B9BD9145FFB09FAA68BFA4A7C6461F25
-:10B9D00047E510A65866F1B5D6C37B07A7F075F406
-:10B9E000116A641FCAFB28712D155736B39DF0BB31
-:10B9F000A225F286291F532D0123B62B9CCB5BB1C8
-:10BA00009F9B94085DF366AC6E4535EDCD2B14FC21
-:10BA1000161C87F2B96C1CDFDFDC3AD2E773C2A3D5
-:10BA2000E933787E76DA0C0BD54D4F53F9794C4CCF
-:10BA30000DE6DF0572765735CF0B63BB5A937791CE
-:10BA4000EB204720BED911C73FF0E671BB25BF6F81
-:10BA500012753EF2790E1EF40C001AF2C67F9C4B52
-:10BA6000F684AFF77E962BFCB462561CF3FB315F75
-:10BA7000901EA8FC5D7F7A42FF5CE88969FE274C36
-:10BA8000E4DF0B7D21F57240D42F75897354DE1FDE
-:10BA9000C3F1FE5EE53CD21777B266D2E777B1908C
-:10BAA00009F1DBABFF2768FC2318675A40EF2F4DE5
-:10BAB0009F11EB57717E95E3DE1DD43F9F2AFDDE7B
-:10BAC000097ABFB7FAFB5FA7905DCC7CAEE1F2804C
-:10BAD000689D52534C9D52A3A8536ADA3DFF60867D
-:10BAE000A64EA9692FAF536ADC7DB53AA51E5A57F9
-:10BAF0003A620AEFC3F59623F3402400CEFDA2AECE
-:10BB0000E500D6B59445F9D23195E75D817D69FDB3
-:10BB100024C769F3213FB519CA284FDB96E4F069C1
-:10BB2000F3A22B5A80EF34F959599774A49FB8B8EF
-:10BB3000388FC7A96B159E270FDD6DA13830A33054
-:10BB4000A05B97C830B2A3986FFC58F8416B451EB4
-:10BB500004D7F586C135AC70FFA6F77BDCEF84F91E
-:10BB6000C9187D9491E6A375818CE42194DF9FB17F
-:10BB7000B7740BE91BBBD587F5FCB2FF19C14D2A81
-:10BB8000D60B35EDDDA4D6D8A37C372A4FF0AB8D8C
-:10BB9000D9905F7BF37D3B1328DFF7993D704B1EF7
-:10BBA000CCA7DE1C19CAF4FC4CF7FBB36B7305BFC2
-:10BBB00098C604EE9E0DF09C7FC7CCF35E0F3392C7
-:10BBC000D7DFEC49A17CA53A95917D595AC9F8EF88
-:10BBD000BB6C52C89F3B99C2CF0D5A3A85911D3C10
-:10BBE000973A9EE8378F850FE1B940B51B4CBAF301
-:10BBF0007F1EDCA26FD7B30EB237F5DBFBF033E963
-:10BC00002DA91F1B98D7887AA8B153FF3D1BA8D731
-:10BC10008FA5C21E0C9B36B6D504DF0D3370BDC593
-:10BC20001EF6654FA5B8BB9ADB51F61C9D3775DE35
-:10BC300071CAC8E59CEBE3E151ADA9B34BC3857F65
-:10BC400075B3CA7F1741FA4BC3C5EF241C30EC35DE
-:10BC5000D26FF20878CAC577D24F93FA5AD2A5723A
-:10BC600024FEC603443779C2DF2960054857E89FA0
-:10BC7000E441C140891F714CBFB7304A8C0774E75B
-:10BC8000E7CD192C61E4A3654A33E9690B13FA5A2D
-:10BC900009925EFEB750C8887C70036BBE037FBFFD
-:10BCA00073B4A5CB467EA93DF868DEF0289FB4B2F8
-:10BCB00048DE0E45C72FF4FC4CCAEFE2F28BB42BE2
-:10BCC00091F7B9BF3189811F08E3FA3FE07ED001C7
-:10BCD00085C78BE00F1EC078F1778689C40F13618A
-:10BCE0001AF8DE38A79ECEB7BAF5ED89DE3E7C6045
-:10BCF000D4FEFE04489C8AF04C2AD6BFE797FA8D02
-:10BD0000E9F55B3EFB9AD7C12F3FF45DCC1BD816FB
-:10BD1000B162F463C073F4C5FB7DD16DC25EC459DA
-:10BD200037D99697D177DDE4BCC8FFDEC8BAE76C97
-:10BD300057FAF2CDB9838B8C6E0D7F497E7E59D434
-:10BD40005928AF8BF5D9729E2F8CDA79CE3715A290
-:10BD50007523F21DBCFF96E417F13B2137EDB64683
-:10BD6000F077704A453F3722FF9445ED7AC460F77B
-:10BD70009A0B904F7C6D46635F7FDE95EA257E19B6
-:10BD800066F013BF0C67BE34A4D3484B47AB8AF0B0
-:10BD9000EF19911DB4EBF8E31DE20F05F883F2599A
-:10BDA0007DECA3FE790CFF483A1E167EF4ADCC4B19
-:10BDB00071C404E14747F239FF54D9EF54F1FB371E
-:10BDC0000B78BE612C2E28D23E53BD5DACB2E8F993
-:10BDD0002096BF60448376DC587EEB8F6F0620DFB1
-:10BDE00048BB987675BE39DF3FDF9CBF12DFC4F2D7
-:10BDF0008BD42B3BACCE2A3BE6B76A15D2C7C3DE49
-:10BE000019D88AED6B1AF2A90E66478A6F3F3D6F0B
-:10BE1000E6CFCBBBFC46AC93295C289EE707AAB0D3
-:10BE2000DDB488AF530C3FC2EB68063ECC9F972E23
-:10BE300069DE8FFBFA9A42FCFB97BF5846FB9BC218
-:10BE4000CBC4F795ED55D86E6AE3DF9FC4F5A6EB3A
-:10BE5000B1FE2DDC8AF707AFCAF7F1B094FBB5B796
-:10BE6000083EDDA1ECDC4FDFB5F3EFE61EB224D2D5
-:10BE7000EF060ABFF56631CF5B36F079A67F7A1BF5
-:10BE8000FD8EE8EC9E10F94F9F1BEAE9776AFA8B6A
-:10BE90003F2B95F61CBCDE8AFA040FDFB2005F1759
-:10BEA000F0F5C8CD30C47503B83F28D7F1B0AE4027
-:10BEB0005B4770DD001E17C9F75CA97C1F1A7BDA8F
-:10BEC00041F962B9CE1859C71494339CA3F003E228
-:10BED000AE3BDE5AD84CEB8DB70E90EB8DDD2A9E33
-:10BEE000A35E7AF92FE3E3E559CA06F03CD0295165
-:10BEF0002721EFD786F3E977C1762093D03EFAF079
-:10BF0000EFA92DCE056762DFDA8E7CDEF60FD8F062
-:10BF1000D3B61CC0AFA159C573D4589E42FBF6FEE0
-:10BF2000A58B459293FAC27FABCA2266BEEF8EE024
-:10BF30009FD36ADECCF74F72BD344DAA9DD18348A2
-:10BF40004EEF1474FACE00E1770C63C350DF4C134C
-:10BF500074BBCB027E2BE9B576538CFC4F1980FE67
-:10BF6000C653FDFACFFAE731FAA1568C3B47F8CD1C
-:10BF7000F3F0F7478D78BE3BF79F4F3DC5FDE607D1
-:10BF80005907E523CF3FCDFDC506981EF24B9FDF35
-:10BF9000E7DAA66F3774C4FE2E6C88FAEFF3BBABFA
-:10BFA000253CAF7BFEA9860ACCEFD5AE7F87F2C7D2
-:10BFB000B5525F84F5FA021C0CAE2FD65D4B791D8D
-:10BFC0008385FF2EE630D017586F320CEB48A1FF67
-:10BFD000A162DFFE72FC84EFD77F6800E98D09540F
-:10BFE000674AFD19697DF71DBF374A1F693762F53A
-:10BFF00045A9CCD70C4CA57C96D41FA5C24F611384
-:10C0000062E3C727490E8789D64F06E8E320E97720
-:10C01000C0F7E4777419EC618341EB6784492ECB58
-:10C020002C602F48947C1626F6FFC7D0F971A273B6
-:10C03000FF7194FE790C1FC838A642F0C1DDCC4FC9
-:10C04000F1D12EC107EFBDCF7FBF6D9A7D21F1E108
-:10C05000FB1F70BF53C651DF3E7E8AFC43F1532F56
-:10C06000DDADE04FDAF07728260E5A83EBE49D56DB
-:10C07000FE7BD50AA7B3EBEE2379DAFCE27BF8BBB3
-:10C080002B9ADF73689D9860C175C456138F2FA6D5
-:10C090004EFAB062A6467F0C49ABDC85F85AA6740E
-:10C0A0007DEF4F186FBC25CE4FDD9B4174BFD0C5CF
-:10C0B000EF5FD8709D2F04B7BF3489F3A894E63999
-:10C0C000581A25E198237EA765AE31FC5A37AEC7D2
-:10C0D0002AE15DF50AFDAECA01ECBFCE1031F3BC1A
-:10C0E0005E17E5E965FFFDE72943A4CFCC6F70FB40
-:10C0F000D8A324FA789E37A4FBBD9E035E1E6F551D
-:10C10000E406BA060C8FDABFD8BA8363F36FA57D55
-:10C11000A9FFC5FCC9B82EAAA8FCF79963C7C53A00
-:10C1200083A59A3CF5316BFCF5838F849ECF435CED
-:10C13000C1F88BB2FD1FE33C4F89B8F094581F3B08
-:10C1400095C4D7CB4E0BFD9CE715EB79E27A4AAC50
-:10C15000A79D4AD5C793F23D83977F7762B125B0FB
-:10C16000544357EFBA8466CC4B64148ABA92858CD8
-:10C17000C74F7B5274E72438BC9579DE0C7C4F9C0A
-:10C1800033B087DB655CC7C675E6F559C14B88B728
-:10C19000462FF3E33A2DF3769BEFC0F54AB13FF714
-:10C1A000BCE09BF3567E957039BC53F2BC88EFF926
-:10C1B000DD44D7DEF6946ED297FF072EE42C97006D
-:10C1C000800000001F8B080000000000000BD57DE0
-:10C1D000097C54D5F9E8B973670B9909939040101D
-:10C1E00088938D246461B261D86492808A22262C5F
-:10C1F00015651B50C2964DA0FDA5D5BE0C06117944
-:10C20000DA426B5BFCBBBC01C16AB52562B0B126EA
-:10C2100076544AA1D53A22286A6A4754D69044A057
-:10C22000567FF2FBFBBEEF3BE764E6DE4CD89EFA9E
-:10C23000DE4BFC7972EEB9F72CDFF9F6F37D07BB24
-:10C24000B322C999C058F7ECA099A98CD965FD21F2
-:10C250005E871F031BCCD862FCCB09A5D5E657F33C
-:10C26000E0EF0DA6CE6026B5B36F52185354E665C5
-:10C270007150C964CE0A3B3E9DE0389A0D4514B416
-:10C28000433F7566DB066534BD5E6185FEE68BFE69
-:10C29000D870BB11FB9FC7BB62F3DBF67FA5C43030
-:10C2A000B6C0CAD60F83F6856D43CC3003B62CC614
-:10C2B0003BD291836F4C761C8571156FB4FA4D3467
-:10C2C000F48D3F93FA968C19D951393F5A8797319B
-:10C2D0005CD78800AD6B63694FD27F1531D6D36EC2
-:10C2E000716C83716ADAFE7A588175D5C8F5B568C4
-:10C2F000D797ED54182BC69AD5F7A995B15B98C27C
-:10C3000006423FAD364F36C2ABC61AA479428FE61D
-:10C310008A5C18EDFE09B1B4FE21F03DCCE7C546BC
-:10C3200037FBC41482E72A075FFF14B5BADC1CCFC1
-:10C33000D8993B99C3028F56EDBFA3C90AF5550F93
-:10C3400030071FDD6D6063A07F01AFFEE69750618F
-:10C35000604EABA8E3B07306306766A83ED413A75F
-:10C36000A943BF0CE7B152F43B6CD9559AEF47D4BF
-:10C37000A768DEBFBA6194A63DD95BA0A9A76E18D5
-:10C38000A7793F7D5399A69EB1E546CDFBF92C7563
-:10C39000208375D6ED53990F409BE59BA169CF7E15
-:10C3A000FA76CDF7C758FDAF27C07B2D5131790CF8
-:10C3B000F0A8292A661B96CCEB0EE4007CEE14EB69
-:10C3C000C86D5EACE9E754CC75FB705FEF0C544D63
-:10C3D000638057A35B5768FA5DA956F37DDB643A27
-:10C3E0001284EFEAE117E159C07AF60E03FCA8F5D2
-:10C3F000292E3F342FDDC2DBE577CB5BB7D277CB7D
-:10C400007DDAE72B9FD6D6BD652CB3DE06EB74DA5A
-:10C41000E38F02BEB2ABD855DF84D155080FE025BB
-:10C4200018EFCC63AACF928CF0C9F8CD04828F8923
-:10C43000F99C7DF7EB0C632E3FBEFF9CDDE585FA92
-:10C44000D2FD77D07C2C895A3C88726AF1203A530D
-:10C450008B07769776DF079668F75D0FDF58F7A8AA
-:10C460000BC277D00D5ABC90702D81DF6F13AE8F49
-:10C47000E8E059B8C7DD642338B159D631083F3EEA
-:10C480005F0BAB50592AFC1D0F7C069EBB7817EC46
-:10C49000B4C3E63500FE3CE3548CC427443FF94660
-:10C4A000FFABB89EF58A97E17751CC9788FCA2A99B
-:10C4B000C49FE4877D29B0D6E3CEB1CF6C15BF47CA
-:10C4C000BAAF36FBF3B05DF6F799CD43CF3B953766
-:10C4D000AA18AC9719FD79C40FAD8CC697701C33A0
-:10C4E00080E3F14A5661C6715E14F8FCE9FBCB08A3
-:10C4F0008E55AC7EAF1BC63BF50187EF72E6A5F704
-:10C50000966CD2C2A10FFC747003B471E2B875626C
-:10C51000DD2B18F31952FBC2536953FCF63C04435C
-:10C520009BE4DB9E6F0A39DA213CC7B1DE1FE2DFF4
-:10C5300012BEF08212CE9F703CC7E0D078129E925D
-:10C540006FC9712CAC5E4D443AD0F13196A9DD270C
-:10C55000864C620CFD473F7F021E6A8D13830DC619
-:10C560007E70F28C5D23C6618B3D8908272BDB44EE
-:10C57000FBB751716D50611CF5EAE42606F02C748E
-:10C58000B855DCAF6216988BCF4BACCD4D46E8EA80
-:10C590006A76DE41F834E4A99A6F0685D6A1C8759B
-:10C5A00079156684FA44519FE955828F26E37AFE15
-:10C5B000FA158E3B519433B184FD83657EF2217C64
-:10C5C0003C41718EC0F166FC292301F166BD52CF5A
-:10C5D00074F33BFC32F4A31A7A06E17B5398C7C884
-:10C5E000E5AE8FE4CD5F9520CDFB07CC7D1F965245
-:10C5F000BED5B2E6EBE642BDB605E4560C96517EDA
-:10C60000154AD6AA8327331EC1BA015682F8BD1235
-:10C61000EB72DF9343ED5457FBD6D7C21A86C65D43
-:10C620005CBE3F98EC10F2B167246FE7FC6D998017
-:10C63000D73229B77CDAF975E01F4319FB8B1960F3
-:10C6400052807464F51A063296980C7489F3CC63A0
-:10C6500079D83FD0D5F064E87F701CD0A1124E7716
-:10C66000FC7DD9DE87EE74EB67F5B0B96301DEF6C9
-:10C6700022B30758EE1DE1EBBD0478483D6221BEB0
-:10C680000BE37DE174525933A0E35D373617059211
-:10C6900050FECB7DAA33334F33EA2DCD0934AE7C27
-:10C6A000EE4E360878013E5E029CFADF8734D28770
-:10C6B000E43E5CAA3E347E109FBF84DF75C9820FC2
-:10C6C00086E07DA3069E0CE099AB81F78D91E02D6D
-:10C6D000E171BA38F014EE936A3F3818E13C2FB19B
-:10C6E000E2966400C188C3C1A38A01E55DE7538F68
-:10C6F000A2FC6A555D48C3B513397FAB7D492592CD
-:10C70000EF6AB3F814F87E59EBEBA4977536020381
-:10C7100035F50F9FDE75EAE0DC170E7CFFE43AAAE0
-:10C720007478B6E0EDB3F6F94E5ADF8AE4840BAEC6
-:10C730005FDB2ED67FEA476C61450EAE2F67603017
-:10C7400027346E26EE37BCFFD3988A7A845BD13BC0
-:10C75000C363102E53D4B6BD57211CD6282E0B8C84
-:10C760003BC9C2BC51B0BF431BCAD927B04725C182
-:10C770007A9703E09138DCE652011E193F542B7C76
-:10C78000D0EF3FD7AC8EBB03CA938D30743A3C5781
-:10C790000C1584676CD7473F81FE32ECF35C1BA11C
-:10C7A00036DF02F38171927F14ED4F05FEF067339F
-:10C7B000B3229D9952EA0F4C857E7B625517EABFE2
-:10C7C000F12A9B8C7825E11C1FCDD7219F973EBE77
-:10C7D0005D09DA42CF2735F514AE82F2E66427AD63
-:10C7E0004BAE7352794F21EA3B12CEF1A9FC7D6624
-:10C7F000EC499A114617D9021E1DA8CF013C6B13B4
-:10C80000CCEB51FE7559799DB93349EF5D63E57401
-:10C81000D11195E443B9D8016B0D507F7E3BB385B0
-:10C82000F1C328F7C06B60DDEC6D95ED80E29CC331
-:10C830003D3096E0E1E0FD083DAB8BB11B104E6B47
-:10C84000A6960D898332A189C3478F273B93159AFA
-:10C850005FF597407085A1E7D546BFD961C3E7660C
-:10C86000CDF3230037AF25545F7C3CED3A46FCC541
-:10C87000B51EDFBF634334F386E9552D621EFDC14B
-:10C88000A536D6C88C008F5A85555CE8BD97FF5BEE
-:10C8900025F8EAE7FFAEE02F09E591D7F76632B752
-:10C8A00067CAEF9FF61BD43B6B03266681476B5E1E
-:10C8B0002A1DC222F4D70BE72FC733DFA0B0BA314D
-:10C8C00048F0A8FDF25A7A5E7E7FA719F11EFB712F
-:10C8D000C2F33551EE21AE0BC0395BC0B9F6CB586F
-:10C8E000E61D14FE9CE355A8FF786AFF1D0210F0B8
-:10C8F000D6DBAAFA76C0A7BFDB67B8615B84F97E96
-:10C900002DD63F2AC148F492ED67EEAD11C697EFE0
-:10C910000D8E033E6DE370AECCED3BBF96B2E002F0
-:10C920009CFF3593993BD278A7C57B72DE2D71C1F0
-:10C930002A81F7232BED617587761FA3C5F82D3764
-:10C940000693B0FFAEA96C4E7384FEE57E8F31D6A0
-:10C950002B088FD2444F06F291EA5BA10278326431
-:10C960009EDFE0C909D15D7FFB1E8237D85D851748
-:10C9700082B799DA657F270E08BA646E9B02F4B419
-:10C9800048C8AB45DB574E03DED96BBF9CD802F6D7
-:10C990000B0C7182D5BF6EC7FA2685EC93C51EC6F7
-:10C9A0001A80EF54ED285C8F626B512263D7C6F179
-:10C9B000E7F760B9CE1492B3F47F370B978B72FC14
-:10C9C0003B1FD4EAADCBD8839FA3DE73E200E70F11
-:10C9D000A09E92FD5DF5B0B6BF65DB6F3A86F35C55
-:10C9E000A6D37F3250C103FD233545D81363D81831
-:10C9F0009403AB769C35C738FBA7839340EF69E976
-:10CA0000C82F1D548E49718F4A81FDE87E9BCF73DC
-:10CA10004A8A272F05FD0D6FF3799DA93EC3E5C412
-:10CA200063F1249F2CC8CCE14FCB5CABAF09E6711E
-:10CA30003FB09328808FC5C2F520A9FFA9EA6A35C7
-:10CA400006DAC77EB6260EF737FED9EB6FC0FE12A8
-:10CA50009E8D76E37A3696BAF3D15FB0B1D2E66AAC
-:10CA6000822EADF03DCA0FDFEFC6BE76156A07CD48
-:10CA70009BCB8621DAB5BDEA477FCA06C3E77B8731
-:10CA8000C1FB1BAE65AE26161AA7AEADF2799C4F60
-:10CA9000D22C2E673626BBF31D61FD32A1CFD50AFD
-:10CAA000D875B767FC7C3CECEFA3FB489D86F5A5E9
-:10CAB0000C44BE318AF17D66E7014E80273876B896
-:10CAC000DEDA09F28A6584EAA39A15BF09D653D340
-:10CAD000F2BC01E561F5BDFEC173512E3D63746D7D
-:10CAE0000B9B5FFC9F8796396342F268AEE2207D24
-:10CAF00041EAE5B731F99343783347E0CD6D421F02
-:10CB00009F1BCDE1BB98B992F0BBDBAD2CC60024D6
-:10CB100035B7BCB998E4D54A532CEA3FB89648FBE0
-:10CB20002DCBFEFC4AB54FD9BD0AEC7B97D2331210
-:10CB30003B3989BE1EEE5FF26D4BEEDBCFDD298205
-:10CB40000E470AFD308DB9EDB0EEDA5732B66E847D
-:10CB500026CB00D8C702E24BD69202D28FAD68F73F
-:10CB60002C7F39CAAFC484E0C21CEE7C03FA09668C
-:10CB70000C2FD8883AE961E02F40605DA66012D1A1
-:10CB800031F01D0564DFC329932B8D80E7B55781F4
-:10CB9000FE05F5D7B655F27A4AB0CA00F593292BAF
-:10CBA0002B8D8097B5A38247B17E2EE547BC5E10E2
-:10CBB000AC52A13E30751D7F1F0D4140ACE1A9FF75
-:10CBC000B3D20BFD9F8C15F2DD155C80F853FBA7EB
-:10CBD0000CC3C6B0F55A5339DF3A19C5DF3B99CCBF
-:10CBE00016CE4078670647E23C7BF12245EAC39BBC
-:10CBF000A894EB94DFB1C4C8FD3F99C2FB5F5E2EE1
-:10CC0000F49268B601E106DBE48D01F8EF69CBD858
-:10CC100086EF6F488913F0827E8A42FD4838CAFE4B
-:10CC2000E4B82B50EE223F36013F0EE3A3CD295C42
-:10CC30006EC238EB689C1C0EFFDA19C3F371DF601B
-:10CC4000BF8C62BF8CDC4EDDCAE707FDC6E611FF74
-:10CC50002F34C2FB7BCEC3FBC9A179EBF1A35DE00E
-:10CC6000C7F2266084A4A7A5121E4D8AE6FA212BDE
-:10CC7000D2AE63602A879F353596AFB3773F86285B
-:10CC8000344E9380E370807BEEE5AFFB2D319F6FD8
-:10CC90007BDD61FBE556B1BD356B5BF87A18DBAC2B
-:10CCA000E9E7E45ADD77254080388FB854FAEEFE84
-:10CCB0002866A5E76C5BEF77C9795C2F457DB546A3
-:10CCC000E8D5CC7B2D3915AA05D7A8D910303BB1B2
-:10CCD000BD5971FB103FD3607D08DF19D38AC4FAB8
-:10CCE0001C627D0EBE3E9F064FD9C19EA459F6BE62
-:10CCF000F8DB0BF7DEFE720A447F1ABA8ED41FD21D
-:10CD0000477FFBA1A47ECBFB21E7A983672F9C75FE
-:10CD1000F393F0447AA6EF72B4F828E779AE3FBAFD
-:10CD20004EBEC2F14AF977353F867D44FDC4A9C5A0
-:10CD3000E79A9664C3E29CD077ADB897C521FF5CB3
-:10CD40005AAAB07387B3E1C8BFBD65DC8FEADD6561
-:10CD5000713539C9AF97995A1CD1AF47CFF5F65EF7
-:10CD600077AC9929A41769FD0CDD09AE801BF5D4B9
-:10CD7000D3CCB503FA1DAFD33BBA613F77D942DFBD
-:10CD800085E489B6FE43C13FFBFA8D7A92707E45F9
-:10CD900096B2179C2EC6CA52B712BF2E1A58B63A70
-:10CDA00019EAD7A73E49FCBA6858D95974CD4C4DF9
-:10CDB000DDCEEBD9656753B0FEE476FEFE24F70BBB
-:10CDC000C8DF99777BE5E4A121FDE1C654278DAB4F
-:10CDD000961B18E29145BDCB857252C2B3BFB2C853
-:10CDE00062A88FA4BFCEECA5677E9E5122E4738912
-:10CDF000B4E783468D3DDF1D63F5AA00D76E94A787
-:10CE0000B0DE05A99E3908FFBAE8CE05A80ADF1BE7
-:10CE1000FD9119F521C50DFA06FA459C0E360FE66F
-:10CE2000A9746EAC203D7085CB6A24780A3F15AC9E
-:10CE3000ED1BE8E7E5579EB97B181FA602E73156C0
-:10CE4000D07FDD2B5F7DF121CAD1933617AA816394
-:10CE5000DB1E598DFAD5D8B6BF7FC5E5AD8DCEA9FD
-:10CE6000E4BCC7A2BF119E97B45A68FE63DBB296BA
-:10CE7000E0FBE3DF694B45FC98D8E16F4276D0DDFB
-:10CE8000FEC7619EF0732B764CF926FBF2F58B5EA4
-:10CE9000787C6666A85F023C7EC2E171BE0AFD8AAC
-:10CEA0005D0907D607494F1BCEFD98E27BD0CB33F7
-:10CEB00091CECFB0012E3C57E8B6F37EF4FECDC341
-:10CEC00095B03E783EB1076610A6374FFAD20A0CED
-:10CED00024542F65B19A7AB975A8E6FD298E644D60
-:10CEE000FBF589599AF6A9CE7C4DFDA6CCB19AF7EF
-:10CEF0006F76956AEAB7944CD5BC5FE9AED4D4F3AB
-:10CF0000FDCD9AF70BF7B56ADB0F3A691F0A3B2A8A
-:10CF1000CA519F77053C4D585ED3B9A97CA093F5C3
-:10CF2000F1EB16057D4DF87CFCF9FA623FEBEBDF87
-:10CF3000652B3C741E60C17D51C3CE074A03448FEC
-:10CF40005D069733DC8F3B6FB067672AF97101ECA0
-:10CF500000EC6BAD3D8370BFA62C7C488DC17DE994
-:10CF600061E4FF6A31077F361EE5FC7C95F4DE162E
-:10CF70002323FDB1654EAE0F7D7F8795E08B1F2289
-:10CF80009F9A1F4DFC642268B8B46E3C0355709F95
-:10CF90003C9A7597B2E5BA7DBA4B539FE2F8B1E679
-:10CFA000FDEB13D76ADAA73A1FD0EDD3664DFD66C5
-:10CFB000D723BA7DDAAADBA76734ED133F0D3621FC
-:10CFC000194DEAF4AA7698FFB8C39BCA715FC67779
-:10CFD00078E723BD14F93D4DC442F6D4BF8EA51F9A
-:10CFE000EC2AF46BBDD69848E59E4627F9A5F6369F
-:10CFF0006652B9AFD145CFFFD65842E51B8D6E2A98
-:10D00000FFD178039581C60A2A9B1B9BE9FD5D8DA4
-:10D01000AD54020447A0BC881F24E40FD4D1DEEF36
-:10D0200032046BF1C4F5B327CF115FEC1A10ECC2D8
-:10D03000FABDEC2CF1C5401A233AB4A633E2635D85
-:10D0400069EE6569509E4BE5F56E936D03CA816686
-:10D05000833B1FF5EBAF9E3CBFD93882B1FBD65660
-:10D06000243A6279DD0A75DA6C34CCBCE737BB87C9
-:10D0700033F67B1419E3A85E89F5EE28DE7EEEC94F
-:10D08000F3955E9A1F3F6F9E153A6FFE2A35C2795F
-:10D09000F3EF8F3BEDE86F39703EC38EEB3A20FC27
-:10D0A0004B6E966F5A0465A931DF8472F1B04E8FD2
-:10D0B00090E5BF6CA5065C4FB3C1351BF514EF8D31
-:10D0C00026B603F8C50C85DBA3BD7A601A9747DD49
-:10D0D000375BC8DE3968702F413C073EFD04C2EB68
-:10D0E000AA34FB0C845FB7BD2709E1909866E3F58D
-:10D0F000849E27145758DDC4D7199B163DA39F75EE
-:10D100000E4E8BB0CE61690E1A9FF9DD2350FECA18
-:10D11000FAC14A770DCA8983A5EE749CCF810A0BA8
-:10D12000D18FB7C2EE4B4726677417CF0EF3BBFC07
-:10D130002ACD44FB36CBCCE98CDDAEFA7644B0D3B5
-:10D140005E48E3FA3EED1BDA73B745931E7ED0C00E
-:10D1500096ED8A00C7BFA77139776A4064FFCB1B81
-:10D16000027E6533EDD45FF79A283AEFEDAEC82022
-:10D170003DA8BB1EA004F4D17DBCFEF46E6AB7C806
-:10D18000A3303AD79C2BF8D4EFDB56FFFB10BCFF43
-:10D19000D19A6817F170C728924FB78B97E70FB2F3
-:10D1A00092DE327FC68832944B73C5F9D802BB71C8
-:10D1B000301D931963CD0EE8E74E5BFE7A14FF55E0
-:10D1C000F195E658A82F1B7ED77A2C57A46D36C749
-:10D1D00041599DF3FC7A541F6B80B48AC95E0ABE24
-:10D1E000D908F35AD8A03AB9FD24E49A7BE565C57D
-:10D1F00063483C4438229E027CC92E7C53C05B7E2F
-:10D20000F7A680E7DC34A1B7E5B2DC6FB4E73E0BEC
-:10D21000114F3AE7BF39B21F3FBDB65DE86DEF9AD7
-:10D22000F9B82B9F36F9C2FD4972DC7F88791C342E
-:10D2300033B7827ADCED76C28FBC3967EF2D86F585
-:10D24000E7B5390C746E2FF9788091FFBEF8530F53
-:10D25000F1B96B3A834F1D6284E7AD4827179353AA
-:10D2600033BD6B493E8C3D07F207F9E279CF478722
-:10D27000880F2E137CB09EF8D79EC606AAEF6DF4D9
-:10D2800052B9AF7183E0839BA8FD8DC62D820FFA42
-:10D29000041F7C9A9EB735CEA1F295468FE083FCA1
-:10D2A0005C7586C0A779899E7548FFF2FC7296D599
-:10D2B000634278FDE5110B53F17CA2CD42780A144C
-:10D2C000F0C4A3F1182F63716C74F68D9BD1F3DB5E
-:10D2D000DEFDD79DF3AE49746FC27DE98D9341FDAC
-:10D2E000ECEAFEF1E70073DA919F3CBDBD82F8C71E
-:10D2F00001A7D38E7AEB3369953350AF3DE076DAF0
-:10D300004D50FFDDF64ADEEE71DA2D507F366D06A8
-:10D31000AF7B9DF628A83FB75DD47D8C0EB59FDF0F
-:10D320007EEB0CF4639432650FD243B9357932B099
-:10D330006B908FA57B900EAE4F5C3419E9C099E6D7
-:10D34000247C98EA5CBB07EB37656E350E72A2371A
-:10D35000347F1D7E57165F69C4EF260FBF6B1D7E9D
-:10D36000775DDA6663F87737E43CBF0EEBD35C5B3E
-:10D370008DA80F3AD3F879A9EC47D665BBE4AF681E
-:10D3800027209E8E6EAB203E9ED75A417C5CC2A564
-:10D390006C56E57DE8A7AB6B551C0ACE6396D27B35
-:10D3A00058AF800E517B1EA805F8AC7FFBE2B8B5E4
-:10D3B000188782F57154FFC5DAC87CF72F88077A81
-:10D3C000BEFB9EA053949B95D0CF7B403FBBA09EBD
-:10D3D0002ED657D7B6C8BE88EC198F1DE56B761AC6
-:10D3E000978BA385DC5C28EA778AFABF6CEEB7706E
-:10D3F0009C77FBA7EB0FB01DE8B68ACFA30F5D6B40
-:10D40000DB055D770838B2A29E24ACD7B04DE42787
-:10D41000BC587CD7F270FB2D19E3249A29FE421FD9
-:10D420002751CD02BCBF665D9C050B9AE93CB63521
-:10D43000EC39F123617F0CE07C6F0E326BC0BF7F53
-:10D44000A78973C7BEEBFE4AF0ABFED6AD6D17EBF6
-:10D450005ECE7C14D7A65F07F324106DADB41DA477
-:10D46000FDECBB9E60E4F5F45907B7DF651C8BF457
-:10D47000CB831E14955E8C7CD0CED07F13CE270E2E
-:10D480005D804FE8F9D1B7C5E72EC06F92709E7AE4
-:10D490007E23E3B3F4A5D4E7A0EEC5F83CEF2B510F
-:10D4A000E4A7FFC4E9C9C27EBACB7ABE30A07D161C
-:10D4B0001F243C6B002B0F9F2B667E4E0F5F8CC48E
-:10D4C0007D3B6EF0FE01F5A2921D8F119FEA42E1B5
-:10D4D00000F4E8823AF29D2D575514E0772C93E33F
-:10D4E0004FB7C2E5A2A47BD007A91C9BCEE551DFB4
-:10D4F0009269E21ABBB77E95447EAC8BE07B7F706D
-:10D5000098A24E087A91DF974493CAD3A930BF02FC
-:10D51000FA5F67E960D2233A47988D587EDB7662DE
-:10D52000E78891D4BFDE5EEC1C5A62E5E35E7703C8
-:10D5300096AD66CF964568278DB5909DF496880781
-:10D540009C1ECDE3A7DEC27362786FFA91F3F128D7
-:10D55000BFF4F666E7FE7965CEBCBE7627AC7332C3
-:10D56000AEB3FA63C37DF8EC72EDD0EA862F987102
-:10D5700010C8ED86F3CC587829762953915D141C98
-:10D5800076BD8E65F1A781B83C27DA9F527F10F6F1
-:10D59000E945E2904A7AB8BE30E93CCB3416A19F07
-:10D5A00069009DDF28257FE776AB28E5B9C8043EF2
-:10D5B00005B6C060F39953347148894628E7A9C17C
-:10D5C0003158EF62013A27D1DBB37F157E28B06B6B
-:10D5D00037A6935F8AC727C18E0C42FC9DF293F752
-:10D5E00017DC4D7C208AF4A15EBB76B781E20C5A31
-:10D5F0008CEE8113D1AE6D4877AD85FABF0209BFBD
-:10D600007A19CA3AC717043749BFD50D67099EBDB5
-:10D61000E703C2EFBBC904F207CAEAFF56490E5539
-:10D6200033B681F68DBD665E15261759F3E7BDF05A
-:10D630001F0D7CAF12014876D684996EF8AE52D891
-:10D640001FCCDBCEEBC2EE626CC44C37F453992096
-:10D65000DE679B79FB08D9FE0B5E4F97FD7D3E830D
-:10D66000EA43655DF49725EBFB793D598E7792F798
-:10D670009F2BEB165EB7F3F75F48FFC34CE40B92AA
-:10D68000DFBF942EE4443ECB177139EDE9C5178C0A
-:10D690004BD1B60BF9B0F019D56B1E8DFB3335FAB3
-:10D6A0004DA4EF668562E7AAEF3191BFFB545C732E
-:10D6B000DEEA307B45C6B15494DBDDA8FFD5BC98CB
-:10D6C000B14D15F13CA87F7CE1E47AF914D546E729
-:10D6D00013671EE47CBF3FFDADAAE165CD7EF66910
-:10D6E00057156E8FE3C11D8C77FAA1215BC9BE4827
-:10D6F0000BD0F9F98782DF0D06DE5A12178A178BD5
-:10D700004F656EB457E3FF08FC19F7F8D300F1E357
-:10D71000AA3F72FF6FCD23AF93DC5BAC3AC99F5B2E
-:10D7200096E3F918E1D3650F905FB1AAE1159AD796
-:10D73000992C61573A7A72C2E179A22FFC4F5F04AB
-:10D74000FEA7BF4FF8EBFDCE2B6C7B68BD2B2E33B5
-:10D75000AEADCBCECF455D629F8E189C6304BC2CD2
-:10D7600023012EA7970446C6AA18741C18CCE3966A
-:10D77000DE2846BBE84CBD9DE1BECF5BFDCF3C4FF4
-:10D7800004BFAFDE1EB80DC72C0EC12B61641FF89D
-:10D790000EC5F12E005F6DFB770CDF21C6A0D98589
-:10D7A000E7A88719F5332670C41C1E1F337624C7DB
-:10D7B000CB81ADFCDC481FF73576A49DEF93389FF5
-:10D7C000A999F1C6043C9F91F430299A35A3BF1D55
-:10D7D000F0DA25F0DA85782DF137744E03DF45A0B5
-:10D7E000AF10FE6AE1EAEE0BD7C9232F8CB7DAF649
-:10D7F000EF18AE2DA00FD3B9E6EE28F2A7E8E1BCF2
-:10D8000074243FDF92F06EB8089C1BBE2338378C1F
-:10D81000746AFC1112DEFDC927FDFEC87947A0D34A
-:10D82000E22BA1D3AF33847D630C529CA97EDF1B16
-:10D83000FBEE7BD345E8A9E9FBA4273DDCF465B505
-:10D8400038EFD43FDF3A92FBCDBE2B38FEFFE64FD8
-:10D850009F5FFFAAA67D61C37E4DFB22EFDB9AFA94
-:10D860008460A01CD15CFAC7AF3DDEF33AD6AFD4DA
-:10D87000CFDE9F7F7DFA0B4B0D78FE5612E0FEFD4A
-:10D88000C5999E2F90AFBC65F035D901AED77434E1
-:10D89000AB741EE6CBA773C0D5628E6727FCE7A3E7
-:10D8A000BB016FCE320BF93FFDAF66199DB97DF11B
-:10D8B000A0F44B95B9C3F4C4526BAC11F5A75260F8
-:10D8C0007991F0E66B8137140F04F43EC7CA4CF12E
-:10D8D00040E773E62814FF3487F1786A28FD1E6854
-:10D8E0009F6E647E0BD42B6D46BF85CEFD78BEC384
-:10D8F0006C3E4D663182C686F65DFC20B28367E1E0
-:10D900004398AFEA56299E6D76093F2FBCDDD66C51
-:10D9100042797ADBBE7B4FDF0DED6C9DB798C76B0C
-:10D92000CBFCB50F0C97730EF8F5484EE7DD8A383F
-:10D9300057564C2E8C73D57FF7D6484E67D3D5B546
-:10D940002AC6BFF4BCCD48EF967407EBDB6729E02D
-:10D95000F919E3709DCCE4CF8841FD797339BE5F3E
-:10D960007DD04970A92B599B87FB583759F9D8921C
-:10D9700017B26FEA1ACE919E3E457DAE09DF3F7326
-:10D9800098BBC6AFE9F4AA68AF84FC97C105489775
-:10D9900017B383E4BC3B1AFD844F1F35EEA3F2ADF1
-:10D9A0006BFF5E8C7A46B03110D17F79A5FE02E91B
-:10D9B00027907E03C907FE754FF910C4CB74C917B1
-:10D9C000ACCA30E40BCCC84BC92FB333FAF0D7D173
-:10D9D000191796ABDAF6EF98BF5E2A9E572772B9F1
-:10D9E000A8C76F3D5E4B7C86CF8A1518F776D0F7B7
-:10D9F00050AECE65DEDC6AE0B373966E328D57AE04
-:10DA00001CAF57D83E4D6211F2542E9F9F3B79BCFC
-:10DA100064B94AF6818C5790FBB03843F81943FB40
-:10DA200056957161B9A86DFFDEF5F84F175C995CEA
-:10DA3000639AFC86B57DF1F5BE8BE0EB7DDF27BEFA
-:10DA400086E5CF2C500DA17C118C27463DAEDBC75F
-:10DA5000F32197256F8AA1E0CC929E18D41B97B72B
-:10DA6000AB8487CCE8360E057C5D2AF0B593F9DFF0
-:10DA7000457C5C3A6129E5D12D7B2C725C71AD78D7
-:10DA80007F85ADC58CEB5CB15DFB5EAD882BAE7E5A
-:10DA90004EEB17AD9D70FD31ECB75617CFF36C868A
-:10DAA000881F2E60053CEE42AB9FEACBAE46A6F146
-:10DAB00057769D6F247FC00BBF3DF94BEF8430FB41
-:10DAC000BF2FDEB65F046FDBFF6FE2AD6ADF4E791A
-:10DAD00055978BB73F1AE53E80F396FC781EF226E9
-:10DAE0001877DECB169F17CF478B9DDCBFA9F89A1E
-:10DAF000F0BCADFB2B46FEA3C5C2CFD95F5EBA8C8E
-:10DB000037187BD0D7C4E30DDC2AE6898ED957516C
-:10DB10008EC715856FD4933ED2EFB995CCAF12F175
-:10DB20004397CAD7A45F6FCCF17AD2B35C0107E9FF
-:10DB300043E3BE6C7E1DE5E3B7E5EF96F270FC2093
-:10DB4000EEBF280A56909ED765F217BF877AC24B60
-:10DB50005111F5047326D78B667A179978BE619FA9
-:10DB6000F34073269E070AFE6FB0BA4D08A7296AD4
-:10DB7000E7AF6E45FC09A8E4DF5BF3D377FEF0A8BE
-:10DB8000F3E2767F9DE32CE90DFDE9FF75069E7FAC
-:10DB90005150EEA4383FB4A7D0BF27FD7DFAF78BD4
-:10DBA0004695256692FF6942C08DF3D9C2E7D3DF5F
-:10DBB000FED4357CAEF12FF6377E5D7BB1637118F4
-:10DBC0001DDC96A948BBC371D41ADADF4BC5838923
-:10DBD0003D7334FACFFFEB76C57415544B909FB963
-:10DBE0008A8FEBAF8CEBB1F35880CA05AC874A0F34
-:10DBF000E3F1F78B998BCA3B451EF3DE2CCFCD9911
-:10DC0000781E61EA194CF1932F7E9D837873FADABE
-:10DC1000F19B30D6EEBBD2E3BAF39D347EF7EEAF84
-:10DC200093300EE6627C614DA2DB9319E1FCF91F93
-:10DC3000A52A9DB7B0C38F929CA814B730B0C9FC79
-:10DC40001CED0B6732E143882F0ED92AF9229ECFB3
-:10DC5000E67E6CE0F124CB155F3ABCDA1A34106929
-:10DC6000E52E49F6A9586FE1EDB935B13E05EAB99F
-:10DC700063A378FB5DB13EF4A3CF6741A2C78540A3
-:10DC8000A2582E629CEFDDC1DC3CDF81F5A4A01E12
-:10DC9000B6A4CDCAE3FD59300DF97B5E3FF64F5B6C
-:10DCA00026E7D3A353383F1F5DA6F553DC2BF8C0FE
-:10DCB000275965FF447A3A96E96EC272745C60E354
-:10DCC0002F8BC86FCFD07E3836F6C774DE28BF1BC7
-:10DCD00030AA6C03C26FA7C2E3D3BDED168A8F8052
-:10DCE0002F065784C5F5EFCD2AFF19F6F72BE1F77C
-:10DCF000EB0FAEF09D266F36444F5E9ADF68B4B9E5
-:10DD0000C8FF0E0F4A685CAA3FF5F4B459EB72C81D
-:10DD1000C7EF45BD77C028CFFFC2798D363366C3C4
-:10DD2000F93F6EF16D23FDB43E09FD954B9FB01890
-:10DD3000506F781FC42DE6A17CD868A5F29F6007BC
-:10DD400063F92FB083B1FC18EC602C3F013B18CB7A
-:10DD5000255FE683B060AC2CCBDD9A591C3A9FD38B
-:10DD6000CFF77901CFDEF1DBCD34FE27591E826F6C
-:10DD7000EF7EBFC47C78A8B333B6E7AAB80BE05BEC
-:10DD8000FF7C86C3459E17EADB7F2BF63DAFC54877
-:10DD9000F23DAF35185315F6DEDE4C33B5E7EEFE37
-:10DDA00094F250BB1CBDF0752BB0E4E9065EDFFBBE
-:10DDB000F46282EF2759EE7F225C81BEFF86655EAA
-:10DDC000EB3BBFC0FC1FE89FE20EBA959E5F931D20
-:10DDD000A05B871E0E725D3B63031BF1FB9DBB5373
-:10DDE0007025C06F18A71BC42325D27AD7D27C6FA9
-:10DDF000B1F414615ECB2DDFA811E38C3FC92A2555
-:10DE000038FF18F12D210C4E62BFAE94AE7BCFBF10
-:10DE1000059E32797F07F24E27CAA1F331A8EF554C
-:10DE20008AF3FDD696B4B7707DDE7D2A4B7712FE5D
-:10DE30006AE8CE91C5F14496B9EDE60ADCA79DEDFE
-:10DE400047D3EEB4D1BEA42DC171B3D235FEC7DC29
-:10DE5000B15FFDD72FE3E97D070E751BDB3A05E3C4
-:10DE60004FE65A5FFD0B2E69BEE3E329187FB230FF
-:10DE700051D98BE52267F275187722E3E3EFC82CBE
-:10DE8000DD8BA434CD55497A5A2932973079506EBA
-:10DE90008DC643C1DEFA14C7204DFDFAC4619AF75E
-:10DEA000A73A5335ED3765666BDAE5B8D35C859AEA
-:10DEB000F746C7F5A4A07D06EB207A603B548AD3D1
-:10DEC000CBDD7DF0C66CA84F7F6AB60BD5929DA2C4
-:10DED0007DFAAE721FEE4737C0D30C0AD4F1920719
-:10DEE0007EFD4BEC4CA7FF57B73FB9D7EDBC0CFDFF
-:10DEF000BF1FBD5FF2D9956DD662E4B3976A07E89C
-:10DF0000F7272F4B6B17F48737BD74A13839DEEC38
-:10DF100057D98E08788311A91C0F7939FD00CF1FBE
-:10DF2000BB5C7EF619F2B34121FAE82D757EB9D1BA
-:10DF300066D75BABD14FFFA6CA281F4FE4F555E16A
-:10DF4000DF6A08DFD99D5BEF1B1A4FCFBDA8E762E0
-:10DF50007EA91BFAAFCA12FEEFEA57EF1B5A146AEA
-:10DF6000676B3ED6BCCFEE51D66BEAEB92B5F507A8
-:10DF70004BD7877FDF1F5FACDAB2C8ECA1FC4FC57F
-:10DF8000ED8BC01FE47CA6BC1645717D3763BC0ACF
-:10DF90003CAA2D7ADB88E7B437F7234725FFB94D34
-:10DFA00065F591DAEF12FD4E7B2D8AE2602EB7DF28
-:10DFB000F701961467F8472E47DF1F183086EFFBEE
-:10DFC0003D595C0F3D5DBCF9A75FE0F9E84B8CE281
-:10DFD0003E4FC772FE9FD772CC608072F4008E2FC6
-:10DFE000798EA001E54AF7B2682FC6F5D72DB75351
-:10DFF0003CE8E8949E77ADB0F5EB9ED9FBB015F602
-:10E00000ED034C820C93ABDD681441FDA1ACBDB3B4
-:10E01000D6C1DF37BD16E5375CC17A1EC2730994DD
-:10E0200083659CCE1720DE08F9823EF6BAFB58AF16
-:10E03000BC41BE80EBC7FA9E67F61F7C18F5F0FD69
-:10E040009CCE31C24E6FDFCF0DB3EFD9639C2EADA6
-:10E05000F0CBE39474F4BD6793D976413A6FA6B8D8
-:10E060009B4BA5EFA7919EB32F48CF076E82FDA9CA
-:10E070007B89DF6B71A62D9DF262FB93E7755B5484
-:10E08000A24359EF6A536F40BCD5E7A14BB832B7F2
-:10E090008BE853DE1BB56AE27F66A0DC5CD56EE4DC
-:10E0A0004122FD8DB34165CEB07176BE625946798D
-:10E0B0006E62FEDD525EB7FF3BAE3487976B23C8BE
-:10E0C0003D90D3A67894D3950AD99587DA87942181
-:10E0D0009C0E29CCEFA4BC2D1EA73C937787CF6D57
-:10E0E000745F496226C5274BFB52DA95B3DB67A7FD
-:10E0F000A35EF96ECBE243B073ECC3AC541AEF5697
-:10E10000E6253DF8506CC508F44B4C17F1018762C9
-:10E110007B3A912F1F9A18ADE0793FF4BF0EFB9721
-:10E12000EB3A64AA18C1EF9F9071C9A3AEE89EB8FC
-:10E1300029EA3DA537E1F9F63CE640BBF21695EB3E
-:10E14000B9ECCF9C3E25DFAB53027138CFBD5933BC
-:10E150004E67C177431A7E26FCAA026E461E877858
-:10E16000A97A6EAF3DFBB4C2EF457171FDBF76C2B7
-:10E17000A95FDD8A797260772B309FC5ADAFD2BDC4
-:10E180003F7A3BBBD7DEF93FF4A7F6B5972A2CA31D
-:10E19000C2FCE47ABBA9574F97FADE0E1E27FFFA9E
-:10E1A000C4DF74AD84FA9A1DD104C7134F58BCC89C
-:10E1B000C74F6CB390FD7322AEA76335D677E5BA2F
-:10E1C000BC349A4B732FDA5283F33D943FEC6F26A5
-:10E1D000BAD7E3D8E3163FC67B2C7F326B1BDA53EA
-:10E1E000C746389F7D0EFD81CF26D03D03CCC3BFEF
-:10E1F000BF59D023D29713540FF5B776D22396BFC9
-:10E200003094F898DCBFE38F47511EFD897D3307BA
-:10E21000A2BFACD3F03CE5F130D5E6457EBC725BE5
-:10E2200014E9810D0E4FD628585FF96F6FBEB510F7
-:10E23000C77F2781E17ABADB5E207F65687F23CBC9
-:10E24000F7336DA99C0FF4CA5B1E77BB10E36E53C6
-:10E2500029EE7634C2B786C97B1779DC6D81AAB8FE
-:10E2600029EFE0A1C879E4EE515C7FAC96FE9341C2
-:10E27000CC9A8874E861B4DEEE8732B6A1BD33670C
-:10E28000545CEFFD4C3C5F52E25B47EDCBE43FB1A9
-:10E29000F078BFA8C8E7D8D346F1BCE22AEB398DA5
-:10E2A000FFA6B6E12B8D5FA5368791DC2D6872162F
-:10E2B000DE05E56A01E7E52915B7E0FA56346F7E19
-:10E2C000F10D82CB633FFA00C7DD6723BF0D7B836F
-:10E2D000C34F6FCF54593F17F4B45573CFCCD147C8
-:10E2E000DEA37893A3BBB3F370DF16AB81A3781FD3
-:10E2F00057973DF0D1DD50EEDA7780F6453FDF3EAF
-:10E30000E7F60AE72BD5B88E4118EF52B16414D165
-:10E310002DA7F7231B73097ED29FDB7D22B2BD257B
-:10E32000E729FB97F393FDCBF7568BFD3A6D0EE48F
-:10E33000A17C4ECC746AD6753A2690176BC3E7DC85
-:10E340009F773A0EEA6178F35D9DEFDC2EFC3C8707
-:10E350000D6B7F6806FCEB6CFEA5C913CE472FF34F
-:10E360005C47CE57C695CA3CDA874789F388116C5B
-:10E37000443FF9B75B90CEAAFBE6DFD2F3FEF26F23
-:10E380007BF36DFFCDF36D657E6D51B9A13E3CCF42
-:10E3900056F2C3A26C789E83E7FE5AF95E345AFBAC
-:10E3A0007E7FFCB1209BDBD7458322E7BBEE1FC5F8
-:10E3B000DB9B989FDF3F28E4E278017779EF97D4E1
-:10E3C000536A05DF96799EE3DB78DCE67891B70344
-:10E3D0005C80F25CFBDCEF96984D7255DECFA74077
-:10E3E0005FF3E222E50B07681ED7B21E2ADDCC617F
-:10E3F000C412C04FE5645641E575AC9ECA1BD826D1
-:10E400002A6F64CD544E63012AD928BF88F7BC8790
-:10E41000E7994E5D6A40F95A746B64BDF8D445E1E2
-:10E42000E0A5FB032F170ED7317ECF5F1F780CCFEF
-:10E4300024FCD6C3439FAF399105E9E2924988B8DD
-:10E44000A968073B29BEB59CB9A93EE512E1501267
-:10E45000F418797EAF0E1EE591F1E29CA0FF9FA219
-:10E46000EC2C0EED5356B693DFDF20F60B0CB144C7
-:10E47000E4FFFA7D94CF8BA2CBCE3A8145389E6DD6
-:10E480009C4D79DC8565AB53A19E92BD6936E579DB
-:10E490008F2F7B01F3BCD39EDDCCEBA3CB0A4D2E9B
-:10E4A000D022D7FE6236E6337A44DCB447C44B331D
-:10E4B0004FBEE69E2CCFDA1FD2BD639E113617AE3B
-:10E4C00053E685ABA9FC7C35E906FF6B2678AFDD0A
-:10E4D000E189CE46B965F5C738514F583B85EE8F77
-:10E4E000BADFCCDF97F7D9C8F5C97B6E76EDCA5E87
-:10E4F000ADA45C7C1ED0FF50ECDFB3369DF2E33C54
-:10E50000BB15910F5736640EF08DCE8089617E81E8
-:10E510001CCF94E249C2F71926C5035D0C1372B8EB
-:10E5200073577636EE5356B638DF8F4F2E4438DEAB
-:10E530009A529185EFCBBCE82CDC9784FECBCA6C59
-:10E540007706BEAF7F2EF3B2C7657B72B1BD2EFAE0
-:10E550003CE59B75E5BFB33E98DC374FBDC9CD7C2C
-:10E5600066E22BDAFCF4EE2566BACFA9A8C2D38402
-:10E5700021CAD7CCEB1983FA31F45B929D80F7095D
-:10E580000693F2E1BB8767F2FC777DBE77FB2BFB3E
-:10E5900035F9ED92CE7AF3DBCFF0FCF6107D3DB28B
-:10E5A0009A85E5B74BBA9174370EF3DB63B09EB52D
-:10E5B00004DF9BF84E07E5B74FEA088AFCF6F7B48C
-:10E5C000F9EDEEFF5C517EFB3171EFDB312BBF2F9C
-:10E5D00049DE27B56A373FFF5DA5F0FBA456FD9ED7
-:10E5E000DF2725EDC265627D35FB77ACC773BE655D
-:10E5F0008FDD41F75131710FAA137EC3ED42792FA0
-:10E60000A93E0FA60EED41D29BFDA477E9F361EA86
-:10E610001E2B277BB04EA747AFC816F6A090674CBD
-:10E62000E87F4BC5B7B80E1BD96766D23B573DBED6
-:10E63000DAE5C0BAA02BF6D87374EE26DF678F0D2B
-:10E64000225C9074B67C8342FAAB84DFE8A72C6E20
-:10E65000BAC7F8A921A4B782BE2DF2987DDCCF0FEE
-:10E66000B882F1F03B637B52504FDED99EE9020E37
-:10E67000CBFED4EFFDD3CFE9EE9F7E5273FFF419AA
-:10E68000FC1FEA69C70D3EEC670CCBFCF904A81728
-:10E690001F37BA7CCED07DCC17BB7758C2DF22F6AD
-:10E6A000EB72EF21D6DFF72CF31FF4F711DF2FEE1B
-:10E6B000239ED8CF7DC416B54D25FDE19C51732F07
-:10E6C000F135629D254EE6C37B7EC7751A35FB5F2B
-:10E6D00012DCC4501F8A3A68D4F8112C4E6DFD39F3
-:10E6E000890FE27E91BEF0B6F5C2D342F04CFB0D2D
-:10E6F000C15377CFB38453EF3DCFC36D84F7E3F6B7
-:10E70000BFA0223FB8DCFBBEBFEFFBBD2F769FB79B
-:10E71000FE9E6EFDBDDCFDDDF32DF73DDFBF4AF350
-:10E72000BE7EDF0BF7FD447B0FB5D86F2FFC7E9BC1
-:10E73000FB7D325BF877C57EF7E00568C0CFFE1140
-:10E7400073FC4124CBE9D1E23E3869D74F30919D2B
-:10E75000F5967350B91DE95FC8A90A21A75845333A
-:10E76000AF0B7C7105781C41C1617E7F455190C71C
-:10E77000138C391E393FE896124573BEDBF7DE6213
-:10E780009E673CFE3C8FD3D39FFBCBBCA14A7794C2
-:10E79000F6FE867EF288A41F07F47866463DDEC04A
-:10E7A000EFB38B70CFF11635353C8FC843FE9D59C2
-:10E7B000D64012E27354B2273E2721946F3409F3F6
-:10E7C0008A14B20785501AF8038CF3ECC624DBAB2D
-:10E7D000307FD4F603CC9381E93B8263B8B98B3F99
-:10E7E000C9399E1139C0078F288EF585F0ED3FC6D7
-:10E7F0009D4A42F964C173ED023AF7BD3A27FCDC49
-:10E8000057DCCF1F343849BFF0FE4421FBE11476BA
-:10E8100036368C5E3798445EA3EEDF2F10F694FCFC
-:10E82000F70B8E4017CB806FCF6FE579D42B133B5E
-:10E83000851DC6EF71BD63B88DEE7F62EE4217B7DE
-:10E84000C3A57D354CBD1CB979B1F8A29589273493
-:10E85000762E7B6ED0259D2786D6CDFB3FF24034A9
-:10E86000C99B230F8C203F5FA8FF2EB2FBE7D76B1D
-:10E87000E38C1736BCAFC1BF45DE8F35EDC1F81E46
-:10E88000D330587FF0C5A1D7CD05F89DDE6D198333
-:10E890007406FB362B27CC0E0E3E943199EB0117F4
-:10E8A0005BE7299A4787881395EBFCA8F130D5835D
-:10E8B0008D415D3C8F576397CAD2FC1AA37B727A55
-:10E8C0009401AE487E9693395C6FEF1079901D22CB
-:10E8D0000FB243E42D76883CC50E91A728F3473B41
-:10E8E00014E6C6788A798AFB8945C9943F7A17AEBF
-:10E8F000B36E454F1EE6DBD58D0E2E5054CA1F5DFC
-:10E9000083CF23E48FE661DEFB1F726EFD01EAF91F
-:10E91000C70778E95E92A79E9BC1EB664E1F2FE664
-:10E920004CFC01CF27F5FC0FECE75345F5D3FD1761
-:10E930002F29749ECADC41F38C0BE497DE97C3CF7A
-:10E9400017D6EB4AF2452760FF4CE47B3D3892F244
-:10E950007EB65828EF07C6A1FC2B79FEAFCFCF2A91
-:10E96000F8B3C58F7C43FA611EC94996F702937FBD
-:10E9700025FEE7169EB7150C24619E17C6FBE0BD69
-:10E9800019EC2073F33C307E7F9FDC87477244DCB8
-:10E99000195EA45F14CA13ABD97FE423E42365395D
-:10E9A0009EC771FD327FA926E6558A9BD899E3A4BC
-:10E9B000EF60BEB45EE007EB1482731F3FDC0EFC19
-:10E9C0005E9FFFDEDFFA4F2F09FC3A2739943F158F
-:10E9D0009637B53327CC5F26E711EAE7C2782DFDDD
-:10E9E00049217FD7FD23914E0AD00F1EC1CEDE2BC9
-:10E9F000E0D2618AECBFFB384789983F5790C11835
-:10EA0000FA0BE57D93EF209CD0EF749B8BFB4119B3
-:10EA1000BFB7AE6686CD857C4BF68FF7E53E7F812E
-:10EA20007196A754BC89EB5F51CFFD7DB2BD5BE110
-:10EA3000FBEA7D88E34BCD2BEF7F74378CB2FCB7BC
-:10EA4000B985C8A7E5F77A3877D979FEDE62D54F60
-:10EA50007004F87E80FBA4F7F35D295C2F377F1AE2
-:10EA6000E045F730F6F583032285E96F16F9FD706E
-:10EA7000EDFD6616FC771860BC1661F7B408BBA7FD
-:10EA8000D524FE9D1C9D1DDC12E071442D89668AF3
-:10EA90001362E2DF7590727FCDDB3CAE684D32A32E
-:10EAA000769C1FEEAF12DC4B72A8F79E2A05E42B72
-:10EAB000C0EF94C3A3E6A21FDAB39AE4927A35ECCE
-:10EAC0002FFA4DFF76A3B0E7B89C2B1672AD18FB5A
-:10EAD000C175E40C24795724C61D63AD277D7A2CBB
-:10EAE000F30AFF8EF0833CB097ECC0FF0D9F4D61A1
-:10EAF00077606800000000000000000000000000D7
-:10EB00001F8B080000000000000BFB51CFC0F0037A
-:10EB10008AF92C181856593130DCB0666070B4612F
-:10EB200060D86C8E90BB218E6053133F97A74CFF2B
-:10EB30003C4906860540BC0888974892AEFFB71648
-:10EB4000825DACCAC0F007C87701D25FD519186ED4
-:10EB500003D97F81B803C85F03C43B805804C8BF92
-:10EB600009A499D518189E00E97F40BE34907D44D1
-:10EB70000DBBF9FFB5F0DBBF5D0395FF128D7F4143
-:10EB80001DBFFE284DFCF2AF09C863C35EF6E4C7A3
-:10EB9000471F057A0702AF474BD7E2A60C0C7A66EF
-:10EBA0000C0C85D0B4BF0649BE192826610A617FC6
-:10EBB000D103E617207F258E7CF11528CF0F94EF27
-:10EBC00037C76FBF38335A7AE1C154F39609C1AEE3
-:10EBD000174295DB248CA9FEA708030300E92850FF
-:10EBE00078D80300000000000000000000000000D2
-:10EBF0001F8B080000000000000BE57D0F7454D54A
-:10EC0000B5F7B973EFDC9924772693106042024E72
-:10EC100012D458038C18302613B821098424E0003C
-:10EC20007E34565A07E421B640A3B5ADEDF395E125
-:10EC30008F315AACD0F2FAD4767DDF40D5D5F6B913
-:10EC4000DE0A8A4A43422790502488112DD66AFB57
-:10EC5000A276D9F81AED80C1C6EFA38FEFEC7DCE76
-:10EC6000C9CC3D994942F5AD7E7F64B537F7DE7377
-:10EC7000CFD9679FBDF7F9ED7DF63963B7B988E75E
-:10EC80000A422EC17F0B09F95C2E21645EFC2A9E8C
-:10EC90002F729270C61C42B29C077A67E710B2D8F6
-:10ECA00050FD4B7C844C75AEED26A5840488C3E7EB
-:10ECB0005008E9525EE89D4DEF8FBBEC7E0781FF67
-:10ECC000EE22643E21773BE99FB4FCF173F40AEF36
-:10ECD0003FB145082D5FAB361205BE772A7E870F00
-:10ECE000CA9BC6B22984D410F6DF8273A446A1CF92
-:10ECF0006BBC773492D984547B68AD4EF6EE12FE2D
-:10ED0000BF49082D5F4158FDA6D3FABE82EC3AA751
-:10ED1000BAE12EA60667D1FA2EEAD6F7DE257F24C1
-:10ED20006E2897F0BC80F603FEA03CB88AB872DE6D
-:10ED3000CBA07FDF406EB8A4D2AB3689901BE37CBA
-:10ED400091AF848409994C483BFF5E23C1D9704F31
-:10ED5000C833D87EB6E0635D3FF1D27EE79411FF01
-:10ED600012CA87A9756617A17CADA8D1191F6BE7D8
-:10ED7000E7F61B84FCE083B63C52423F8F6C423E78
-:10ED8000E6703E767DF0FC9B5B806F7504F976D86B
-:10ED9000EECF0D968CA62750979D46683D7B824707
-:10EDA00033B01E42FEF3D2145E4F11211DC1C2CCFE
-:10EDB0005092EFC4F591AD1E421CF1FBDD26A96B0C
-:10EDC0003346977B1E06731E54BF06E9ACE0BCFCBD
-:10EDD00081429ADAB0DD261CA7C39CFE6EF368461A
-:10EDE0007F09BC8F66D8683FC2E76CE4495A45C7C3
-:10EDF000E0A274A077BB698BC2F38E413D02FC2078
-:10EE0000DEB6BC15B346D37FF8DCBAB9D8AFD0268E
-:10EE10004BBBDF1FA4FD35A07FCF642CA6F59C1F44
-:10EE2000B479543AAE7BF8F3C3A1B60C0F7C37909B
-:10EE30008DE3F9C856FAF7D5A9F9F1C8822F1786DC
-:10EE40000C28E7B4F263F0FC89223A6E1D7B353F53
-:10EE5000F46B3C7E7E9FB723EEB3FDD16A0FAD37D6
-:10EE600010F32BA017D983844C2A00BDE838E6861E
-:10EE7000F16D24A84781E0A2B42B593FFCAA0FDE14
-:10EE80009F52413E029E28F663841EA0EF6AA0D3E3
-:10EE90008BD747797B3F8471C4FE6D4FBB8AD27B91
-:10EEA000BE4CC37AF69BDBAB34ACEF62540579DC25
-:10EEB000C4E429C717DA6607FEAF27FEB00FEA25BC
-:10EEC000D8EFFFCEFBFF635E9F68A76330BB4A03AA
-:10EED000FA9A881FD4A456BDAF0BBE0F6C64F4CF52
-:10EEE000B8B75901FE5D715F3F5E239CCEDDF03DFA
-:10EEF0002D90DF1C53806FD3EF89E275EFB6B7BA60
-:10EF000080BECC9D240D6CC19E1A5B167CB767F148
-:10EF1000B43478EF0E52C5A7F620E0F7DCD54DFBF0
-:10EF2000B3B746433AF70E52FED372EEB0C70F7A2C
-:10EF3000ED0EFBF8D5EF87F2BFE4FC38CCDBEDE457
-:10EF400074B8C3262FD75C02E5DCE1305E23BC9F9A
-:10EF5000C4B719E5EE6E2E77BFB4873E077CCF1994
-:10EF6000245E42F5F9F087F5B9D0AEA85F2EFFD444
-:10EF7000E3FFF37A783F7990BC6D9F0DD7E85A682C
-:10EF8000EF6AE8871BEEFBD62A68A722A847E6456A
-:10EF90001B21C5713B95331C5C7A13DAC75AD42305
-:10EFA00061072A06759B9299A86735A8077BB91E49
-:10EFB000D40C46514EA89E1DB3513E853FA07A46C3
-:10EFC000E5EB70D086E3FD444C473B4C8AA3792B9C
-:10EFD0005CA3F5A8E3DC86B9C06FA14FA3EDC7FF22
-:10EFE0001BFAB597F62394C4AE89F684BEC9EFC761
-:10EFF000D5374F18F5AD83EA5B18F819B4A5CD04E1
-:10F00000FD6BB5A19E786BDABA98BE6C427DCB5988
-:10F01000CFE899BA26827A309EDEEDF579AA34A837
-:10F02000BF89E969C7E03BDB1C301E6B08B71317CB
-:10F03000BBE03E702FD36B59CF643DCC0CF4A17E66
-:10F0400016EC8C11B8FA7634A25CD356D250FF522B
-:10F05000E86107E861E9FF3F7A5823E671CA982C16
-:10F06000CAFFFA186178C8B30FF150AD8FE3A182DF
-:10F07000D76FFD2A7DFFA23D03C7F5C5C9F421DE88
-:10F08000AB110238E3CA7F5973372D5F9F23F0CF4E
-:10F0900046D4EF3AAEDFC7E011D59FAA7E85CCCF2C
-:10F0A0008672EFEEAEA6E54F0E103FBC3AE9531163
-:10F0B0004F750F12AC4FE8671DEF6F37BC07791B18
-:10F0C0002611D04F81236AB97E9FCC61EFBB2F12EE
-:10F0D000B403A2FC49A244547A7F9CCBDFF9E2DB63
-:10F0E000FF87BB90903F6F8BCD8ED2E7FF6E8B7DFD
-:10F0F000DD468BFE7E99EF69B81FE0E5FE83CBE924
-:10F1000020C70D27AE0DDDA450FC5349621BEE86CF
-:10F11000EFBC458FCC2550DF47330865ED57AFFE78
-:10F12000CB7BA4102869D383AEB85E89FA443D2F07
-:10F1300078434D0A1D8F81C8BB6E18BF0F0E7E34F9
-:10F140001BAEC49884386B3C3C1610E315EBDB0116
-:10F15000B883D450B9981F978BA9B1BE63886387D1
-:10F1600018FE22759B711C2A3D8C4F5D17CEE6C19F
-:10F170007747385D9DE7FAF2D01ED659EBE9B4F730
-:10F18000AF09B2FAF1FB80878DA3A0A75DD8074530
-:10F19000E025365E01FE7DB9D637690EE57FF909B7
-:10F1A000D5BF8D7E573EDC5F4392D89D889285FD0A
-:10F1B000AA18B0CA67E785E32AF085D2AB02BD95ED
-:10F1C000B13E95D96D2657012E5795B133167B2E3A
-:10F1D000DAEF8C9D699803F66380D9A7547CEDE63D
-:10F1E000FD38CAC7FB88D04F12C900FA7B28FD0F33
-:10F1F0008DF17DAD47B5D02DF4ADDA9961C1E70B46
-:10F2000087B325BC6FA5778116457E2D007E91D4EE
-:10F21000FCFAB6928DF52F1CFEDBF825DB11516F41
-:10F2200027F0B164345D04845BD0ADFE9FCFD74E30
-:10F230006E67A8BFD20DFA4AFA0FA8A08FB5AA81AF
-:10F24000F6A5E26625E248B02FA29F0BB95E4DBD40
-:10F2500048D06E980304CB1D8E31FB9F8ACEA35BF2
-:10F260004DEC5FD645DF4E98571719C17CD09BAE49
-:10F27000C97F647AA69C43FD322FBED7FB55CAFFD7
-:10F28000535CEF0E6FADC3EBCB5B9B912F014371D2
-:10F290005D0F54CD64FA562DEC1A9F4F4E70FB71E2
-:10F2A0009CCF33AF6E0DE1F357B66EE47C65FD592C
-:10F2B000C4FB1335AA0D18CF6E6711CEFB0B355367
-:10F2C0004BE65755C4AC7274CC47F18E0178EBA86D
-:10F2D000713DCCC7D43F46BCC2EB19F92E5F6953D0
-:10F2E000E6C4EFCF0A5CC4CBFDCAFF2CF3EB6ECEB5
-:10F2F000C0F9A02216AA05BED63629C4097C9D3EB7
-:10F30000AB318B3EFF7C93759C457D3D39EF4E02C2
-:10F31000BE5704825A905E6BA3B7683E57EA71E805
-:10F32000D1828DD7E1F832FDA988F5D798948E2542
-:10F330009E8246F44787351BD8C3463ACFF5A35E75
-:10F340007890CF62FE3895A3D64500EF0DEECF0042
-:10F35000FABB3DEA64B86E87C981CA51ED458A4F50
-:10F36000E78CD1FEB046794E2BD2A2CC5FA3F5C07C
-:10F37000B5C750F9F3208E470FAD179E77FDF5877F
-:10F380008D737300F7ABC89F00F9DAA9EB60FEF24A
-:10F39000DB91DF426F851C741B6C7EEC8959E7475B
-:10F3A000C4B7F455CFE0F76F5E09F323B1235E12C3
-:10F3B000F8577C7FC4B87DEF0AD03BA2FA0919FD4B
-:10F3C0007DF066D5A247E57EAB9ED5974EB2DCF7C1
-:10F3D0000CAEFBF15DD05E2C9DB517DE64A1F78805
-:10F3E000C1E6DF9E08C30762BE16EF0344D66FB9BD
-:10F3F0003F8B4EF9C1CE50F9043B53FD49A951430F
-:10F40000EBABC9513DA097C73CDBCE82BE7C10F868
-:10F41000F53760DEAD2BB1D2DF3138977DEF5591F6
-:10F42000BEF69CEBF1FEB0D72EFA6F2C037AE02FDC
-:10F43000FAFE08E97F7536AD7755C44AD78A6086EB
-:10F44000E57E73DD24896E6B5CA8FAE2068CEF2CF6
-:10F450002AEDDA914DEFCBC11415419CC961F92E0B
-:10F46000E0B4DE97437C877EB78048CF2F2EC6B8A6
-:10F470004E39C475C473E0A764C7E93DD221E6796B
-:10F48000593EC57C9D4A7EDB6D6423C443C8D0CA07
-:10F4900071E242DB93CEF744DBABC0F897739CD0AC
-:10F4A0006E6FCB80E795E798FD2443D949F18D3CF9
-:10F4B000EF13F2359423C14FE209939CF9C8C7A416
-:10F4C000FD127C69A5C37209F00EC749F87112FDDF
-:10F4D00096BF9F02FA4DFBB3B8E9408687CA5775BD
-:10F4E000CC86F2D561EC41FD6CF7AB5C1FFB2F25A0
-:10F4F000CA674353D529880FD2F204F4B7C3B80BB7
-:10F50000F537781DD35FAADFA88F01AA8F897858B5
-:10F51000C8BF2CEF03247CF67A68977CF4DA2AC003
-:10F52000C10759BBB2DE53BD433D3E4FD4547A8E22
-:10F530007AD943F532593B97AFE73613DA3F7FD09C
-:10F54000C570F7283D7FB56612B4E754587B9FB16C
-:10F550009E1FE1FA23CBF7687D5F6480FD3F6FC893
-:10F56000FACEECDD62D7BBAFCE66C52D7AFF59E986
-:10F570007BA0789F0A5049E8F178FAFEB7EA794A09
-:10F58000FD9DA07ECBCFB7D814A62F29F433AEF7BC
-:10F59000612CB7C3458A213ED6AEA4FBB717809E27
-:10F5A000B3788D5C3E5DE5F51267F80FB43F6BA94B
-:10F5B00053964959BD99F4CF808156737DA8775BE6
-:10F5C0006CFD53E0FECF2436E55A15FC067208E2C6
-:10F5D000408A49C8BD9424C5E7216BA8A3D5A2865B
-:10F5E0002ED968796520FA890203790FF101AEBB43
-:10F5F0005A09D954FADC41F963D0F2443B83788F3D
-:10F6000022201CA7E55C09963B8D28C6CFCBEC8356
-:10F61000FD426ED05F5BE379EF5A5A2F892A97AE8D
-:10F620008DF7F3297B24CF6F403F233FDA02F1A609
-:10F63000C774FF93BED1FDFCC426FC9FCBEBE7272C
-:10F640005456909F36C6CFB02DDD0FF12CB97E53A6
-:10F65000BDECFACFA6D36B05F071CE683E2A839439
-:10F660007FC007ED3F2F81BF57E16572A5FE593777
-:10F6700021BE425467E4CA2474ACE774B4A8E66CB3
-:10F68000E0B75ADD86FC390CE36F00FF72C8371211
-:10F69000E4AB52D5B17F6A0369C67985446D6037A2
-:10F6A000C61B0FBB463415C6B1EF12DADB164E9FF0
-:10F6B000833E37E6A61E2FB5C11F8BD271227F660F
-:10F6C000E37478A9552EBFC6E9FF32D0358F992152
-:10F6D000A8BFDCCBEC90FA27BD3992448E7708FEA8
-:10F6E000737EC9E50FDFC2FA2FCA7F87CBFD372FA4
-:10F6F0005FFE574F2D4A3D6E42DE95C1E3A9C6AF6E
-:10F7000039D9FC364BB5713AC2CA44F4A15265727C
-:10F71000A956D37183FED55AF9F86DCE8F55BCDE4C
-:10F720002F2A6633C8C3D54AF06E15DAA9E943FD1E
-:10F730002B847AE8F36B89790F3CA7EFBF01E5488A
-:10F740009DF53D7DFE2D7CDED487EB4AE279976204
-:10F75000FE23FFEE9FB05ED3FA9ECAE156784EE5D7
-:10F7600085A873E1B90FE9A172429C602FF6DDFE16
-:10F7700005E02BFDFE7EAC9F9CB17C6F070391CD15
-:10F78000AECA5C767D1CE48EFB993B9A4CE4AB4E92
-:10F790009AB91FCCE6AD057CDE728202C33CECD187
-:10F7A000715ED4D2CC48945EB33D5113E278934855
-:10F7B0005F18FCA8D5D27CDBB4C63ABF7C61BD75AE
-:10F7C0007E59B329CF72FFA57B8A2CF7A1FBAEB57A
-:10F7D000D4B76EE7F596FBF5BB2A2CF71BF6565B04
-:10F7E000BEDFF8E306CBFB2F3FB1CA72BFE9E95B8E
-:10F7F00093AE4B8AF9EE41DBDB9BC01FDB01AF12FE
-:10F80000E60B2DBEEE686338CCFA1D153F9F361F00
-:10F81000CA110C29C872AA49EB96AF8FE8CFDD96C2
-:10F82000F9F668B820C74B596A166806C6DBC26687
-:10F83000DFCC29F1F9BCDA47E76337F8E1C9D757DC
-:10F84000355EAE8AF457C3B8999AB59CC6D7590DA0
-:10F850007F0CE329F23AABE663F3B44CEF19D5958C
-:10F86000037689D6EDC3F555237B42EBABE3F68FE8
-:10F870005AC209F58FB75705FD2C4ADDAF05A531F2
-:10F8800015C89B68BFE2745A718F58DF5EC68A92B2
-:10F89000F282273280DE653E86874829C3374EFADA
-:10F8A0008FCDB38CFF0DBC7CF01E8F1DE2C8C11A3A
-:10F8B0002B9D0D1C3F513DD4C04E94174BEF81CE74
-:10F8C000D950CE8A93BAB93CAA1A5FE79E4FE6E3B5
-:10F8D0003870BD5D21F4B696C5278827F9FA77FD03
-:10F8E000302D84819888256FE06471513A7CB7ACE3
-:10F8F00095F81C149F3C386F9B6711D5FF46D3EEDB
-:10F90000AFA3A5ABFD2C1E5E6FAAB8CE7B4531BB65
-:10F910006FAC51224B287DF5A13E8CE735AE8F6C44
-:10F9200083EBB48D510DE990F8FAB82F926553E34B
-:10F93000FCCDE3FCCA137CE57C14767CDA26EB383C
-:10F9400036965AF9B59CF353E6F372CEC7E5121F0B
-:10F9500045FCAC44E3F22CF17119C7A1CE794563A3
-:10F96000FA758FF33897901F4D9AD784FD1899DF59
-:10F97000B8FCB6801D079CE7E13885CF7B55331571
-:10F98000F4836ABD0AF2B776E63E4B7C73C9885CA5
-:10F99000323A6BF97897E7BF8A71CDCE1C3EEE9470
-:10F9A000AFB5F3E372D83093E563ECE4FDEEE038F5
-:10F9B000BA9DC72D5BBC67D4C4B857C78CBE7C3F0B
-:10F9C000BD7FE942DF9AAF517A1AF3157F1DB41B50
-:10F9D000E271565EEFE1EBB6E5037D27CEF561DC23
-:10F9E000E7A59CA231E38802BFCBF250EE0FD6C050
-:10F9F0007CB224FA0B15FA5F1EA36C53002747351F
-:10FA0000C05F8DDEBB358C73E5DFA541BCB1367FB1
-:10FA10005F35B41B20A1DD5510F7CAB1FBA33E88AA
-:10FA2000FB8477BA419F4B985E6EA4FF12F552D0CB
-:10FA30005D31D8AC019D4B7C92FFC2E5A8D62B3D31
-:10FA40009FB904E52820C9D13D420FAF245726CAEB
-:10FA50008F8817E8E70AB91E26971F310EFFCEC719
-:10FA6000E1773C7EFC268F7FBEB1D587D75F6D2DB9
-:10FA7000C6E73D5BFD78FFFAD632BCFF358FCBBEC3
-:10FA80000A71568C930679BCB509EF7B79FC54C892
-:10FA9000E7037CBDA356EDC0F860833FE4F424ACDB
-:10FAA0002B3470BA51A4015F9414255DBF75CC3816
-:10FAB00084FC3B3322FF04EDC0CAC682FD0F51BE59
-:10FAC00038BE434280171D477FA15D45E5BAA1AE10
-:10FAD000C0BE01DA0BB769D7D3FA1AA2BFD08AE049
-:10FAE00079E375F6DB93B42FDA49D5BE6CB756D5FA
-:10FAF000A9921F2AD68F4261E8E7D458280AF40554
-:10FB0000BCBACF9104F777E56EF0825CB59C0B79B7
-:10FB100041AE5A72D93A032059901B9DCBA9281F98
-:10FB2000F05AD7D7754E77077D0EF476C4C65EF7C8
-:10FB3000167A20CA55686DAAC748DD3F397EB4538E
-:10FB400049EE8F5ED46CF89D1BFA4FED37B5851AE0
-:10FB5000E8198828D03F958A0DE8976110B42F19CD
-:10FB6000FE10B7B7D6F939AB2C18AC827239C4BFC6
-:10FB700004CC96D1EF05B951CB16BF0FF327294915
-:10FB8000B0C7E0CFC8FE7CE2BD8A262AECCA86ABAD
-:10FB90005C8EF1D7E022D47A1DA3EF7B03D6F8AFB9
-:10FBA000C1F95BEE3BF11BB097DFF3DB58B91CB634
-:10FBB0004E7ABE6C1DE2AD728EF71D6437964F27EC
-:10FBC0006D78DDC1F97DBEEC0C81F95BD5281ECEC8
-:10FBD000017A9C9130FDDE2DD96DCDB0F25BA13C58
-:10FBE0005903B87940B3F8114A19B3DF4EF0C3C1D5
-:10FBF0003FE1B824EEBF85C82560FE0471D24EBB3C
-:10FC0000D5CF12D7DF6ACC0FB1D9A5FCB6FFEBF97F
-:10FC100077FC33E59FF0FF46F0DBB13B09ACA788EA
-:10FC2000FC3E51FE57521C49CF7FBBC64CC2F72A3F
-:10FC30003BE3FB7576096F05E476D2C2C04F9DFAAF
-:10FC40004969CAE87A52B54706E68E138FDAC6FCD0
-:10FC500044CDC3FAC7F373A8BBAD58FC0EA7E905A2
-:10FC6000BF6FD4F75E9B454F47D3CDF8F359D3BB55
-:10FC7000903A9A705D2EEC7019C3892B7C1427D2B0
-:10FC80003F57184C4E4F572991ED28A7A6C58FAA6C
-:10FC90002B5BF23EDA25EA67E8F339FEA6F4B742B9
-:10FCA000BDB49E5772C57723F6C47669CEE87A82D2
-:10FCB000350CF790F0CF9726C60582545C8AE74250
-:10FCC000BDEC7B5AB4EB52323AB8DD0A96DDB5DCB6
-:10FCD00070C3BDA93C0A38AE24011F005F673AAC6F
-:10FCE0007C96EC5FCD28BB67B5B78BA9FC1EA2ED57
-:10FCF000D4A9CD8D35B4FC923DEB0EBE88E408FF4F
-:10FD0000C297B4DE53F0C78D80F6AC7885F8599E63
-:10FD10004575D887EB822B7214122900FAAD742C2A
-:10FD2000CE97FCAB1CB91FBB711C8F6A741EA1E37C
-:10FD300075948EE36EF47B93FB49C27F5B583084ED
-:10FD40007E92F0E308F7E33CF45F221EABE4E5AB00
-:10FD5000EEF169B07E5025C58F2B47F28109FA4933
-:10FD60000B8995DE4AEECF554AFE9CD0F79F0ABD1F
-:10FD700015FE2AB78737093FA93239BE10D70E2999
-:10FD8000BF8DE247B3ED32F4800055B4BD4632C2B8
-:10FD9000278B7C75155CD516A57CBDC99FC6F2AFB7
-:10FDA000299D9AB0E7C82786B797F3F237F974947C
-:10FDB000FF804741FBDE384E3C2250C6D6555E36AA
-:10FDC0001496371826AFE17A11A7A786FEEFDEB9A1
-:10FDD000D09E552EF27D7DD59939306F28FE0819B9
-:10FDE0002DAFB57C5CE1FBFBB2C14FA1BE7636AC5A
-:10FDF00067C8F1883E0899527F9CFA4A05A3FDF92D
-:10FE0000057C7CABFC04C47E943FBF808FEF8251A5
-:10FE1000FEBA1567BF1C7B07F3ACCE9728B82ED26D
-:10FE200055F031FA09629D26CEBFE3E84F05CA3E80
-:10FE300062790323FE08AB6FB9A8AFEC18E617DEB2
-:10FE4000EF3986791CA74FB0F5EBD35ACC007F640D
-:10FE5000A9C05794A35191FF5E007912ACBE28CF80
-:10FE60006778D9F96A06D84D9117D21948BE3EB7BE
-:10FE70005065F16371CDD7198E2BD6D9FC23EEC511
-:10FE8000F88EC8937AAA94F97BDFB68CBB5C3F945A
-:10FE90006FC2B85FB42438467E41A3C4678F6EC575
-:10FEA0001BE3E15AD14F990F723F47E98BCEE260D5
-:10FEB000ABEDE6747D72BC1D31DFC9E5573893E7C1
-:10FEC000CD549559E38E72DECC6A7BA804EAAFD696
-:10FED000949D993EB46BA84F472F1A8863CEC78E66
-:10FEE000EE8461ED196271CF4AA2F23C1AB311D6C9
-:10FEF000D3C43E871A1EA790E918AFFDCAA17EF4AD
-:10FF0000B3AB866335207F3705BAD0AE2EA37675A6
-:10FF10005212BBBA581DDC3909F4D7AFA07D78F96D
-:10FF2000ADBE9A494C9F313FD5AC2CD226811C786E
-:10FF300092C7A116703949A577F4430D70C344F5F3
-:10FF40006EA53E82836EB85434FE38A59287F3B115
-:10FF5000F35F4B161F15D7EA14E3BB8548FCEDB0E1
-:10FF6000C695E57A449C87A81DF9A0CFC2FF95CB22
-:10FF70007D5B67F1FE9E597790FE04BF4ED803BDAE
-:10FF8000ACCD80F8446FD9D8F3859CAF5645ACEB27
-:10FF9000CED54EEBBA73AB66FEA36EC1496B99BF6B
-:10FFA0005AB616FDD5E5250EF457BB66DD81FEA9D0
-:10FFB000F0AB5B6E3C807117914725FC5399EEDEE8
-:10FFC000DC670C28371EDDC28FEF74B03C20F0DBFD
-:10FFD0007DE8B7BF8DF94572F9430EC6AF2735F3FB
-:10FFE0000740FF4EBBE95D0BEB87B31CFE27938CEC
-:10FFF000C31B0EA6DFBD29D6514FC382C664EC07D2
-:020000021000EC
-:10000000F2419E6F841F2BF60D4DF532BD6DE07EE3
-:100010006C45C95AD4C72C2FF55B816F7EE6B79229
-:1000200041AB9FBADCE8CB83F197E73B7588FBB522
-:1000300013F45B1F48637214F210A797BE4FD328C6
-:1000400034A5F3E82E75D173C08F07B208FA03A761
-:10005000B3F4C8FE24F18617B9BDAB553759E4ADEA
-:1000600092E312BDA6DF8078C0E9A1B1F3F21E923F
-:10007000707A6131A972B8E11AAB027ED07BD3816C
-:10008000D718E64B7F77D686C264F5ED6FD592CE52
-:100090004B6FF1715BC9E7BBAC3A169FDC52A263B0
-:1000A000BC776ADDDBC7514E1BB99C2E7360BF7BEA
-:1000B0006769382EBD3716B4C17A65EF2C27E6275D
-:1000C00074CD7AE1ADBBC1AE96297CBFD9468BFC1D
-:1000D00056525C9D0EF57B55C42B5BA8FF920EDF3C
-:1000E0007BED0CBFF03C90CD7C4C4F1F64F8E64399
-:1000F000816F381F5709F96F14F1502B8EA2E6C497
-:10010000B24E43F8FAC312562DB5534C1F3E6C64E1
-:10011000F1CC2DA2FF870EEC043D6CE072D475612A
-:100120008317F5F5D0018CA7B5CC5A8BF1A3AEDCC3
-:10013000B33ADC6FF6BEA7C3BD8C33C4386F297BDE
-:100140001671482F1FE7CD1077A7F2BFC4CBF0552B
-:1001500074CAB5769F11CF6396F1DDCA681AF67F2F
-:10016000D5451BFA9D2BF9F747A6FC4987EFB64406
-:10017000A91E53FBDEA0F5CF00DC9221E1C50F9F45
-:100180003B900FFADD33FB8F58EE8AB2B75B80EEFF
-:10019000696507308E9F77E8407736AD7F7931F11A
-:1001A0009BBED1EDD7F2F9694B0EDB07B1C51F0934
-:1001B000C33EB00F8608CE4F0B9F3B56ADF892ADB5
-:1001C000B79804708858AFD1BC7CBD83AF3B908B8F
-:1001D0009794C4F16AD0424EB0BF2D65AFBA81DEAC
-:1001E000C283EA5A90EB9AE7AEFF22C81FB9D1E169
-:1001F000B992F6E703CFAFDD5719ECFD1DACBE0594
-:1002000021CA8F869203F91B668DB62B237A53F28F
-:1002100097AD214AC7E9A52FE4035E7B95DA5B1F02
-:10022000B4C7ED95EC272D94E6D3C090B4CE24F559
-:10023000D7A5ADB8D1310FC6F347DE820479A2FA53
-:10024000BF0EE8DFFCA8D303FA9275E8155D05BB85
-:100250004671FB920479DECCE5A5C16076AF6516E8
-:10026000896C5740CEDE6BAC007D7B5165FB500E38
-:10027000BDCDF23EA579A197CF1742AE7B73DF715A
-:1002800083DC7D7890EB47D8A624C6918CB2D8CD7C
-:10029000301E823F1D929D0990E4F3C22907C3A935
-:1002A000951A7B6F50BB0DEBD4F27B13FC28C04139
-:1002B000DC9F12EFD73B18DE15D7CBC82BF8E177C0
-:1002C000A8BE77ED3AEABD1DED9381787DF3A103D9
-:1002D000C5B00633E5E0811A9EF78DFE98CAFB395A
-:1002E00095F8D03E2D379CB87E20CBB7BD6C5F14FF
-:1002F00060B3989FC111D7A6C4ED869A187F48E2D3
-:100300007F91B0F9DACC843C2C3AAF13B01FD55EA4
-:10031000167795E524ABECC04E361F50294C58C7D4
-:1003200095E5B6C10879617D9AEACDFB6C3D93CE27
-:10033000531097501BFD389E5C3E6DF41FCC7B190B
-:100340007EAB7CDA8B750B4E91E978C4C1D7C5388A
-:10035000EE17F37296B71FE95B6EB4E543FB53BD2E
-:10036000FDE86751BB9E0F572167C24E8FC8DFACB7
-:100370001BEAC14E815CC392F7E9B2EBD3C1DE3513
-:1003800078193E21521CBDD73BB69FD12DC9E369D8
-:100390000FF3AB1ACA48BA2713F49DC59B7A1FCE38
-:1003A000DE9791108FDB630FFDAB6372FCDE5DF2B5
-:1003B000F97A8F1BEC0BCBC72AA766CB5E148F6331
-:1003C0008A78A958BF13F1D15171CC922ECCD7B2F3
-:1003D0008B3C0ABE9E372A8F6782F9678EED6D9A35
-:1003E0009FAF93200E6BE4F1B7A1B9E3C441B70905
-:1003F0005C76DC31797C5CF628F72BDF00E341AFDB
-:10040000B7383C783520BF8492DA9B961CAF1DE04C
-:10041000F8E572F4F3840ADFB176DE7458FD4AF130
-:100420003C8E83991E4C2D3BD09D88832B5B296F7E
-:10043000E838E9AD6406C94C2D77CB47ECDEB3163E
-:10044000F91AC1C5E3E061215F83AAF967C7BCD48B
-:10045000E51A381DA9DEB7CC723441FE142D47A62B
-:1004600066B2EBD5F4DA3DFB40BE8D3E3F09B82BBA
-:10047000818EDEC70E613F5ED6D9FE97DE0B1B0A6A
-:10048000611EEFD24CE29C3771F991F5C939CFF476
-:100490006DA3FAD799EFC4FD7E9D5E86375E81928B
-:1004A00009F2B45E0F799C93718A304936377242F3
-:1004B000CEC168D64C6CFFD66D19FDF70413ECFA6B
-:1004C0002E78958BE70660BF1ED4FB31BFE6365A07
-:1004D000BB83B673CC50A7ACA3F7454E66F78F85A8
-:1004E000ED16BE886B9193C9DD7A3D58047492B6BF
-:1004F00066D4B3B58A1A04FD27FE89C5E576B4270C
-:10050000CF132D8DD73F07EB3F48EB07DCE0E771BA
-:1005100077E2999234CECEFB1D25A40EF4E57B59EB
-:10052000563F739693E9D99C78FD1589F5CF7132C2
-:10053000F9A7CF17E0F3A7D9F35CFEBCAA88E5A919
-:10054000093E8A7A6BE3F5D5E27787D877939D7C6D
-:10055000BD80D32DF0BD9CCF74431A1B8F2AA17789
-:100560009A8278BB9CE26FC4F7DABE6318BF73F25D
-:10057000FD91690E7CDF916B477CDFF10941FCD96D
-:10058000E962F1C8AE0B676FFD2ABDD78689251FCA
-:10059000DCC165481B7A0AE36FE5F97C3F1BD7573E
-:1005A000B16FEB486CBF655D55ECF3E974F23C0C40
-:1005B0005EDF025E1F9170BBE897C039ED7C9F4EF5
-:1005C000B9E8DF407407DA958128F6ABD2C3D68349
-:1005D000BBB2BE81FEF503179ABD8971C1AEE9C7F2
-:1005E000D9BEFD7C4A77499C2E8DE3B1F261DBA632
-:1005F00003C00F4DC18CEDAAE88B1905B4FF8B4EDB
-:10060000A8FE34E8BFE4672CC9E779D41CE7A6C28A
-:10061000F5BF54623F80FA6D19178B80FE2353FE9D
-:1006200055053C5A1E7D43059C5EA9B1BCDD851273
-:10063000FE6887F33A809EBFDA2236DAAF9EF3EF88
-:10064000A9307F5C311CC17E4F1BEEC3BC89BC014D
-:1006500016DF5D30534985EB7764421E868FED735C
-:100660002DF7EFAEC9867A87F8BEE5D8F94940D7AD
-:10067000685C6FC529015F15F67B04E7E7B3B8D264
-:10068000E5E2E94AEED708BF408C3FE503EEE36AB6
-:100690001FBEDB09F36315E76B61BE8DF907D30B52
-:1006A000D7A07FF089EE817CDF073C5F77A27F4097
-:1006B000DF837F5009FE4126C4E5FAF236B846F7DB
-:1006C00047C853E1D0C75B43B4FC11FBEB79806BA7
-:1006D0008F5E782A0FECB2C80B17B85E9477695515
-:1006E000CF83BD16790802E73B04CE8F3513D8CFF0
-:1006F0005F396CB3E07C0797AB4A83E955FB5F0930
-:10070000AE7375BDFF5E6F01FDBEF34516879E1A81
-:10071000EB5713717E39E777E7277D78FE8890FFE6
-:10072000CEF7D939221DF97C7F0AC7F98B092BBF77
-:100730001870BEFBF271FEEC3466774C8EE317F353
-:100740007C54F1BE9FDB7119DFCBEF2F17DF138EC7
-:10075000DFE3B8D82AB75DBB0A713DA5DCE364FBD3
-:10076000CD0662CFDE45AF5362A127F600BF2FA6AC
-:10077000FBE13307F7BFC6CDE794F0FE5412D79BD9
-:10078000287D9495DF8F7A5249F504F6938FD2072E
-:1007900019FFE7C78E41F90584E955F57088AD8FDB
-:1007A0008D83F72B8DFE3CC4FBC38BDF677EC3D8E4
-:1007B00078DF94F297EA663AC6F64FD3AC786C814C
-:1007C00088770C37B378E47033C623170C717B79C4
-:1007D00081D94B319E0F70B913F65CE867E785B39A
-:1007E0006A28C16E8EC8F730DB872BBEEFCC6778E6
-:1007F000FF275A1FEA73E7D0DCF4C438958CF73B27
-:1008000001EF97401C89E2FD39A0BF04ED5E27E0AF
-:10081000FD04BDA578FF9AB404FCE61E5A5DEF8185
-:10082000F5E009E613083F7631F8B1D909F152A78E
-:10083000D58F4D25DF67F9FC1DE7671F9B7F86FB82
-:100840008E25F253E3B8D60178724E7CFF7A672A80
-:10085000BE7E62DDC72CF2B53B8727E637515C5B75
-:100860009F363975B94A4E47AAF70F5CD011D702A7
-:100870001E9F3A875DAFA6D7EE8FFBF212712D3126
-:10088000181EEB7CEC37B83FB8338BE2D992443E6C
-:100890006F1B077FB0FB055E3B5F87B1E20922CD8E
-:1008A000FFED2E260747291EC1F848DAAF908F1DAD
-:1008B0009F9CC5F6657C22F0888C4388843F04BDEC
-:1008C000EDF98CEF476267BEEB877D7327C43E531B
-:1008D0002B2E91F9353E1EE9437B2ECB7987CBC475
-:1008E000BCAB383ED1116F3C60677843E0138A3B64
-:1008F0008EAD05DC3140481A89D32F708AC01D6245
-:100900007E6C1FE6E72D79F8BC20E19411FBFF29EE
-:10091000718AA847C629723D9D3CAFA39DE2966DA2
-:1009200088638EE33C3B51FC22E395F17049E54C32
-:10093000864BDAFDEC3C268167645C52E7EBC23CF7
-:1009400040815F268A5304CE91F18A4C5727E09765
-:1009500092387E91F18A2C4785F9642DC4F7058E73
-:1009600049A59F50EE0E771CDFA42A47ED33E29E87
-:1009700094F50CC52E17F7FC1AEC4A6ADCC3C6B90D
-:10098000F222C13CA05478E4017F3F3B8F489A3764
-:100990008EE49F7913F7690EE83E157111B5934601
-:1009A0006A3C24F46EA4BF60074AE2F3524ABE0CCC
-:1009B00070FDC81F7BFD65A27849CC17B3D3D87CE6
-:1009C000906A1D323D9DE1AA070B997F2CBF8FE7EE
-:1009D00095587113C99985F2FD55BE2F39158E2290
-:1009E00024E66671A930B683F9E480C34037E7F3A3
-:1009F000BC024A6A70269909718D20BC8775AC7952
-:100A00004A244C495B01CFE9B856D5B075A033B341
-:100A1000D83913A7AB1C38AEA73E6479875D2E1674
-:100A2000573D7D5D9A7F3F25E143A897CEB767D2BA
-:100A3000FA4A615CA78B7E66B37E2ECB886EC27548
-:100A4000F0EBAFB5850B46DB8707D3391DD906AE72
-:100A5000A735F0F814AC07E6CD1DBD1FA035BD00CD
-:100A6000FB0DF9EF79B4DC4E5BDF770BE9A3341BA8
-:100A70005B3F95F9FADB7445E4EB841D097C689CC7
-:100A8000E934D3A83CA67D8EE50374D638709D2941
-:100A90000D96CC69BD0F1517BA92C987E897FCFC73
-:100AA00061DEEF33D363787EC6CB3C8F77B3A68409
-:100AB00081DF6880617E9A346DDF43B4E8D274765A
-:100AC0006ECCCBCFBD8271A197B2381F4C05F31508
-:100AD0004EFB983E853D4604F655D2EFEDABC7D0B0
-:100AE000E7BEAA25C51C8F1105D6C9E08FC2D1FC6F
-:100AF0005E55A762BF577976DD05F3C699BA5733BD
-:100B0000E0DCC7E54336027AB7CA537E073CEF7292
-:100B10003139063E03FE5F55F3F9AFC0F3C646EB2D
-:100B2000781C4C2F44FE56686C3C60FCF2E68E6EDE
-:100B3000977848489F92C0FFC00BDF5412D62144DB
-:100B40007E8A3345BE5EAA7E2B8976578DC719A74C
-:100B500096EDDB0DFB5B82A5ECFCCB061F09C37A8F
-:100B60006E839F440BB87C61DE4CF74CB6AF87EBCD
-:100B70005756D9BED642884B0E696C9D599A5F2A4A
-:100B8000E858E567439C9C8DCFE9792AE2910AC831
-:100B90006BC4F32B197E6F30D722FE6F7CB87B5766
-:100BA00021BC57F36BAB7C6C1DD492477588C5DDB7
-:100BB000564872EE92E2FA157E290F90E7EF75160D
-:100BC0003FE101F979309BCBCF5C05F5E815C5F71E
-:100BD0007061C23C7363BAF0CB88CF9E201F23F2B2
-:100BE000C0C757E67B2A7ECA7C92E542E6F7699742
-:100BF000C4AF14FC4FC5EF8AB2AABF2B7F3FB03BF6
-:100C0000EC20B75DF63FE6B37815B5C109F644E6CA
-:100C1000DB0786CF0576E2CC108B87BD34DDF74548
-:100C20003C8F8AEA319E9FC9F5213E0E541FDC8914
-:100C3000FAFCFA0CD0672A6776A8A7D154CC34D036
-:100C4000BF830FDC85FD063D75C7F548E6FF28FD2F
-:100C5000A3FFD304BD45A3F548CE0FFB5BF5EF4ED4
-:100C6000B0E7946F73D37D7815F6B49178BE98B8D9
-:100C70000F55AC937715B40461FF78C3808DC07CA9
-:100C8000D33EF48CB60EF6A5D62938AD19A40FE9DB
-:100C9000355A59FEC3558FDF4B203FFDE1E9C40FA4
-:100CA000F6CA6865F910F43DE64308BC2ECE4DA4A3
-:100CB000EF4DE687B376EB79BB2EBF359F67E5E056
-:100CC000225C4FE82EE6F148EE37883C5622ED6371
-:100CD000698127B9F1FD1EAD1722E83FB4A7D8D727
-:100CE00022AEB21F205F7B8EFEEC2BE00754CED4E9
-:100CF0003D00292A87A24EA8EFBB2547EB105FD500
-:100D0000291E5867EBF9B86D07A172B4B2E49DA42F
-:100D1000B8E4F0073FF4433F0EDB77FBB3C13E6C12
-:100D200067F356DAD525D3D78D817B427555750586
-:100D3000B353E78DDC9AC1E7F7AE3BF73F08EBD939
-:100D4000833AC643EB393E6ED07637ADA3E3D9BDC7
-:100D500054F16FA3CFBBAFD9D37C14E2C8EFEBC083
-:100D600071D27BE1A97CF0234E3EE66C82FA7B3E99
-:100D70007EEAC7983732A8CF87FE8ED07FA5C1DE26
-:100D80007FF8FC09B0332B8B5796423B691AD90D7B
-:100D9000F274C550DB9B70AE41C3803E0FECCFCAEE
-:100DA000BA7DCE7F003ED53DEBBC925EA70DF96AC1
-:100DB000613C33D243733228BD792505F7E7403BC8
-:100DC0007EE23791AF7D04F8BA528A3F5672B96914
-:100DD0005F5AE04A8C639C192A74617E421DCF4F92
-:100DE00058AA06C10F3EE3B9D28571C73A9697203B
-:100DF000F36B25C7E92BEB0AA627C3E385757F4173
-:100E00001CDE7E8DA32919BF6FE2FC4EFBD386FD4D
-:100E1000D0DFB41F393D00AFD352E45B6667F07C8E
-:100E200052EFC4E22002CF50BE3AED0971108AF7AA
-:100E30006FCE4888AF5C6EFBF519CC0E0CAAA12FC3
-:100E400001FF2B781C64BCF843F938EB6E548E908C
-:100E50004F2B797C62A5884FD4174CB7C42788E9FB
-:100E6000053B7B06D6DDC0CFD6566C013A7A3F6093
-:100E7000EB6EA9E477E5CCA76E3D9A60EF7AED269C
-:100E8000EE97ECBE86F949FF55F23B226775CFB667
-:100E900096D2E70F95AC9C0CF62F418E5B613C2EF1
-:100EA000578E65FEB52F2D7211232ECF428E47CB64
-:100EB000A582FEA890EF54E301E5C01F5D398E3F87
-:100EC0007A66E9D549E53F5ECFB931F5A086CBD545
-:100ED0004D5CAE2A89E9C173A9F2DE44BFF557DC47
-:100EE0001E8FC889AB0FE341E1279DB83EDE7941F3
-:100EF000C7F3CD3B9FD8F8139837BA871679DEC36E
-:100F000079BCCAB38AD2750DF80F25383EDD5A4236
-:100F1000BCFB8D0CB11E6ECDDFFD37CF1FB2ABD841
-:100F20003C6B54517ECFE1F3C4E70A9E4887F97CBD
-:100F30000ECFA39FDDA1279D973984202539AFD8F7
-:100F400000FA971CB4963346F691B7D960DDEF737B
-:100F50004F4BEFF9FE6739DFB13723F9BE6731DF59
-:100F60003A2F8C1D47FC39F7AB9FE6F9BCFFC6CF83
-:100F7000ED6BE3E7DC3E03FB56E9F520EC5BA5CF28
-:100F80009F877DABF4FE10DFB74AF227762EBB3881
-:100F90008749E77C68CD8D58D607C53EEDF652955A
-:100FA0009D53E1D5F11C548A9B6C987FC2F1A22D10
-:100FB00023E0D4E9B8EAFF4130FFE4EBEFF7A13CCE
-:100FC000ECE2F3AC8C633A243911573DCE470DE285
-:100FD000589DD3434DC1123E602037F3A6EE7B28C7
-:100FE000014FFF2F2E172DDC6F0B5F209127957877
-:100FF000F9972E90A71E421C45C22AE00EF88B8A54
-:1010000070FD00411C575FFA00FA5F80030197E111
-:10101000F96085101F7D1EF15CFDD0FC3BF8FAC124
-:10102000281C37C23715F9C4F079E92B1827A91FF6
-:10103000482E6FF1BCA5A6EE9909FB0C1A87C43A9D
-:1010400005A5644A7C5FB92EC9955C4F56A982E319
-:10105000B2AC98EDFB12EB1C623C7734F7617E4733
-:101060006FA9C307F1051927CA385F2F65FBC2B402
-:101070001BD9FED4FA0B2CCF1005664AFCFC349D1C
-:10108000E7EDB67B427E38AFA4C12FE1DE189BF7B7
-:101090002A8BAD785EC6FBFA802EE1FD309B0FB740
-:1010A000B3F13CFD21413FEAC9BD2C3E70D8EB6352
-:1010B000F24722E8F72CF4DAAE7BC807EB526CBF9C
-:1010C00065F9103B6FB37CC087FBA7170E92E855FC
-:1010D000B3213E4A5AF13C20897F0B095B7758E8DF
-:1010E000F5754F86F8A34676C23930539C6B4DD0C8
-:1010F00003DDDB8CFB6BAA9D0A9E934DF8FA98E00A
-:10110000AF9E7E6A07A8C0429ECF277E1762AAF3D1
-:1011100000CA813E4E5C56AC7FE95CEEC47A56153F
-:10112000AFBF6A90E5B1C97290E53CF7269CA3BCBD
-:1011300068C8C0753179DCE5715D64C4DE7D04E2A8
-:10114000F617D2FDDB619C9D6C9CC538EA6A870A64
-:10115000FB3588C6C64BAC7355CABF0F21ED8393D0
-:10116000E912E71F7CC590F685711CBF8853D79A9A
-:1011700076C0B2BE22AF031CE6F9083FD1D839A22F
-:101180008707C75EAF3ACCD7AB886782E70EF2F32A
-:10119000022ACA483AE09C8A41C2E4EB615B2471AE
-:1011A0007D4BDE27EE1E5C5D8FE7AB793C789E427F
-:1011B00005A1D7523CE715F31B4D72C0B21E6772F2
-:1011C0007BAFF3B898AEB07E093EC9F4DD3664F566
-:1011D00087BE18B6EE6FB8F55EEB7E8C5B9AF32C8B
-:1011E000EF976C2CB2BCAFF55D6BB9FFBCD77ACE74
-:1011F000CF7F0B59CFF959D5542D9D63673DE7E754
-:10120000A63AEB393F0DE6AD92FE9AD67507A58F4B
-:10121000AF5FBC5534569C37617FE198E7FEA01F55
-:1012200098645F8BBC3FF1AC21E28D563DE80E57D0
-:10123000B17371067C7BABE8FD51E2D7D0C1E5E725
-:10124000FF887D7BB55EB69E337ABF1DA34BD84128
-:1012500079DF8F38B7AF62B00FE5A0523E9FCF9BCA
-:10126000FC7CBE570C8E17C4391729CEB318357FB6
-:101270004FB47F7C1D6FDCFEF176CB49DF3138E760
-:101280002355FF26DAAF91BC2D383790F2A30F1EFD
-:10129000E5B2F706D5B79D59C5789E85DDB92866B4
-:1012A0004C8EC73B8979FDC4F66DF3383E31578DBE
-:1012B000539EE9BDDDE9637261327CB45331237022
-:1012C000CE5DFC3C0B827640E7F3A97CAE45DA4E5E
-:1012D0006296501685179128E28D42676407AC83A9
-:1012E000E6B27DA32DD7D870FE693967EE86FC93F0
-:1012F000D66B34DCB758AB1A585ECF67F35300D6C1
-:10130000A0203FE2A4D964398FC3BBDD037AA2FFDA
-:1013100098BD4FD59F8E5CB63E2C3F2F72313CD48A
-:10132000A505F35C281FA697AD4744F0DC32916F0A
-:101330009B2ACF9602470FDA6D22F0011BBFFB619B
-:101340003D2589FEFA5D4CCF02254AC40E79A337AC
-:1013500093887D0CBFB2C36B4B1ACFC875F1B8E848
-:10136000C54B781E9D2ECEC7CB63E7E37549E74E8C
-:10137000E6F27E1E7039991C143CC5F6A34AE79428
-:10138000D7FB3690443C5BCEE7193DF60EC6994E2E
-:101390000F8C8DC3C5FAD32EBE4FB9FA822D988C0F
-:1013A000FEDFBB3496176CD893F66F3DA7B7638604
-:1013B000FFB5209583967FB6E1F9D2016FCB34DC7F
-:1013C000C7EDFA07C2E25D8CFE7AAEA7016F640733
-:1013D000A1E31788BEF128FC3E875EE6C0F5E7D39F
-:1013E000D7507C426568578CE2C58278FF5C7CBE32
-:1013F00009EC3D5A5754CACECD8778CF9201964713
-:10140000BEBC6C1F3F77A51FF725CABF0F525E17E2
-:1014100032615E5EDE18DD81F8C7EFABC2DF0B2103
-:10142000FE6D6CBD50DE3F6920EEEA186272DFF19E
-:10143000537F17FEFE8657E046B3B1764AFC7CAF79
-:10144000CA734777C2128C7CBE977C8E90F0CB74A7
-:1014500009570A7FAC81448E69CAE838732A7FEC49
-:101460009F5C1C8F5C43FD313AFEB73958FE6CE03F
-:101470003EA50C9CC6B4FB945CB05F2D7C9C5EAB1F
-:101480000C615E404B8AFD747FE472FF5A6514F76D
-:1014900029751484BCFE31CAE7BA542CAF5F64E7E7
-:1014A00078E84E96D73272E5795C42AE0BDD0E7667
-:1014B000AEA19BF9DB0B2F3D9D37D6FC591E0811C1
-:1014C000E80FB52F49F365F689F6A3EC3C0ABDF5A4
-:1014D0009D9A64FA2CF470BD1EFC890BF61D2ACD72
-:1014E0009134B403133F7F728EFAE9EDCD9F0CF374
-:1014F0001968FFA4FD5F7CA01F3B42D6DF7512D7A1
-:101500009346C889FCF71ECD007FF377E9A1C3603D
-:10151000F720DE0DFB053B62CF38D19E4A7C97EB6E
-:10152000B9CDCDC653F7B1F7E437A66F65429CE459
-:1015300006371B17BBD3EC81FA67DACDE340DF83B4
-:101540008B92AF43BAB44527A1DC7546F01494EBF7
-:1015500088EDC7F8F12769E64BF0BC54334FC375EB
-:101560008FDD7C99D9E91ACF7BC5F17D0CA9C6190D
-:10157000162EDE2B4EE4D7A7E3B3DD19EC87F6E990
-:101580003C18322E739CDDF45A07730BFDBEBF323C
-:10159000F97A7B0B9727AA67989F25F6B904BCC4F4
-:1015A0004C367F89F274FCCF035D0FEAE120ECD763
-:1015B0003A3DCD46F627D839712E414B8CF985E757
-:1015C000EF51F633BF90E0FD4FEF2CD80FEBBB3758
-:1015D000CFE07ACCF759DC7E8F75DFB368F7CA4C61
-:1015E0006542FAF9CD4C260777673AF0BA2D93D1C8
-:1015F0003B61FDCC61F5083DD535765DEE61ED9F33
-:10160000E1F57FCCEFA91EE6B8991EF6BB2E6F7CE4
-:101610007EB8AAE8D3CB87D007DD6FCD33FD16D7D0
-:101620000761AF289DD7B8518E9A43E99747E79451
-:10163000F2CF408EC57E033543B1C4C303DC7EDEEA
-:10164000E416B8C8AC7433FD5D00D731F477919BD4
-:10165000E96F8DDBAABFB56EA6BF8BDD4C7F97B857
-:101660003F85FE9E05FD81FC3C1EC727A7AC768703
-:10167000E2E255D07EBDA6F07DDBE40F4A82FF5149
-:101680003F1022269B2C9F48C40D14BF9AB85FE3DD
-:10169000356B7D3D7CDEA276EC4B506F0FD7DF1DA6
-:1016A000BF65FC033E3E93442F051F55C75A2FE4E8
-:1016B000C5A79AE7026EB6BFBDCAC1F6539013B470
-:1016C000FD5996FE6C067E8DF4274C3DBBE4FD096A
-:1016D00027ED4F9FB5BE84FEDC0BF58AFE2CBC7453
-:1016E0006A4C7D0C087DF4445598B7035AF279A1F1
-:1016F000DDCDE6CDDF67983BA17E59BEC475179757
-:10170000AF54FB5EBAB445BB80DFE51AB383C4882F
-:10171000F6AB09FD2B2F5E2BFA1DB225C6D906921A
-:10172000DBC947DD237AF728CADF5EB64F87CAF5E3
-:1017300063D0CE6D933CAB715FD747CC6E9EFDEB13
-:101740007D76F89D94A69C3DF7C3F5A49BE5BDACC2
-:101750003D57E88661E8AF64FB1D5B72D9F9682DDF
-:101760008AF59CB4937C7ECCCD147EF5C4CF11C792
-:10177000B392FF4EF31BE54F07B74BFD69459767E3
-:1017800097E67D06EDDF3C83203E6ED9A7E33E035E
-:10179000A137B7C1D8B2730D4CC8A3F812BDB7D1E9
-:1017A000FB7E70BA291DA17C42BC73B15C58C77323
-:1017B0000FCCD7983D327F0DE34BEDD0596E875E4D
-:1017C000877B6A877EF369ECD0336EA637AD54868B
-:1017D000FA400EB508DF8FC3FD11DED7F2E2639643
-:1017E000B89DF0A73A06F61B61C81B2C66FB4F5349
-:1017F000B52BF205C7FB3D82AA7F5EE70427600791
-:10180000C575104715BF5FD701ED1BD09EAD11F810
-:101810007A92A8B80E2FD7D7329DCFFB2E2ECFB9F4
-:101820001BD0BF927FBFAEDA1BD93597D613387164
-:101830003B3B2FE1E2ED64F52CC0272102E76AEA89
-:10184000F40AFBDA05DDAECCAB2CF1409D28DAE2E0
-:1018500092B81DA98E91E8C252C437B87F0BEAF145
-:10186000F17A42B360BECFC273564F1627CF4FD81E
-:10187000A58672322727F041FADD0B3AFE93E13D4F
-:101880001DFF2999F370FCA766B279C80BF7BFE179
-:10189000E3B84B0DE6C1F3500E5B82A6E5F379F990
-:1018A000E9999F819CEC20EC776F417E13D7ABF7D1
-:1018B00070FBF0B3C9A11268AFE6A72BBAA7D14F4E
-:1018C00036B5ADC5738A175E11FBE865CA1F92A7CE
-:1018D000E37A60CBC3D679E4071CFFFC3C53ACF73A
-:1018E0005D1E8EA0F6EFC64CA48FD9BFB097FDBE8B
-:1018F000E7DADCC2EF31F8481DCC29F1736A6B3CA2
-:101900002B6AE0F70ABFFC74C15C38D74AE7F67966
-:10191000B1B74B5F07E30ABFFF94C49E378ED8412F
-:101920006ABD2DF354F2FCD42F65B2F993EAF1B2FB
-:101930004CA6BFCB81CE7D93CD9B32E7FDFDECA3C2
-:10194000B043218DD91BEA3785C16F5A3DDCDC03DA
-:10195000D35413D9530BEB1B542E3700BD5F701EAD
-:10196000E8613F9D129E06ED5279BC83CBE3462E83
-:101970005F777279FCF2A7E9D76A687C5E6AFC2916
-:1019800070B8C0DFD4CE7F2B93E1649FFBB399374F
-:1019900076F0FA42EECB9C376EF90CDAA778E3FBCF
-:1019A000C0C7924C3226BE7D94CBD5639923F8F6FE
-:1019B00031F86EA1D37C3C33116F949CF803E4C9D9
-:1019C000C5F14697CAF1869618CF0E50FCC5F3EACA
-:1019D000D6DBE6C7F5448F25C7216599237ECACF9C
-:1019E000D0AEEC6238A46C846EFF4004F4701AD759
-:1019F000F737983D5EABF7AF07FB7C3E8B7D1FCB87
-:101A000062E3F81CAFEF6DC59534BEF942E608EE0F
-:101A10007901DBBB8FB5A7665CC77EB743D815BB22
-:101A200082ED88F87059B6B59D79D9360B4E95DBA5
-:101A3000E98EF7AB1BE5F81EB1EFD7EC81760371A9
-:101A4000BE4613F90AF6C5363F819F1CD7A5C27161
-:101A500009FC7B05FBD3CADA19E15F28B99DC5DF14
-:101A60003564B8F475A02F957CBCC5E5E37771F9B2
-:101A7000F81D978FDFC37737CF60E370DB24EB7EF1
-:101A8000F277F977F7723E89F192E9FF7A362B37D0
-:101A9000C20FDF892712716DA0386B7513C42D5BDF
-:101AA00055BFCD375ADEE87F336D09F6581F88E001
-:101AB0003C510FF296C4EEFE25CEAFBFE0B8D43055
-:101AC0007E75A5F0E3EECC66FDBE257F5FCD646834
-:101AD0003F7CC9F27B2D5FD8D8A526FA09FF1BBE33
-:101AE0005F0B5400800000001F8B08000000000006
-:101AF000000BE57D0B6014D5D5F09D9DD9D94DB275
-:101B00009B4CDE1B48C224040D1A708110A304995B
-:101B1000BC780688BC4445591E86F04A22624BAB0D
-:101B2000FE2C2684A76DB43EB045BB2054AC682380
-:101B3000A64A31D00D08E2B3A1ADA2B58F2008A806
-:101B400008216A5DAB7EFCF79C7B273BB3D905D4AB
-:101B5000B65FFBFFF1EB77B977EEDCC7799F73CF08
-:101B60009DBDFEC3E373350721E7E06F44B0AC4A87
-:101B7000B010924C48FD0CF741359F10AFCBE2DE20
-:101B80004A7AF65B1E2F63BF51D93E298EF67BE35E
-:101B90002C5136D37E374C11345F1E21233B89E60E
-:101BA000A3E37F192F103294104591B0FF1509ACB3
-:101BB0003E4AEE985B1966FEBEFCF9689568CD74E6
-:101BC0009CD10AD17684E977295FE7A8E8F0E38C15
-:101BD0008271E8F331848D13FA7C1C7F3EAA24FCC9
-:101BE000FB97C1F8741DD35DCF94271058CF26AB57
-:101BF00087F6CBB16AB90A6D5F53D2B128DC7B4E50
-:101C0000A9240F9E4751D059071372337DD742073D
-:101C100098494B9996EB45CF6085CEEBA1E070D10A
-:101C2000E7B45BAFCA01840C726843A0FD8B282D1A
-:101C30001FCA7C491B0AE3DC6BD50AA04E889F9023
-:101C400002422610F637C1EEF08BB1F41F85D65351
-:101C50001D76D6762E1BFEFF0CE5F8E58408C42F12
-:101C60009CBB1CEA3E11C6BF5A3DF8B640FB5FADB7
-:101C7000BF77520A792F5D391EC3EB22AE0BE1B359
-:101C8000CBFA90EAB0F4DCA75EEE7278EC0087BF86
-:101C9000447BC6C33AEB5D9B1D2A85F72B9E66BB32
-:101CA0009BB61F8E2308C7BFC66813613FF5BB48AC
-:101CB00075336D176384BA6603FCA6280C9F531511
-:101CC00086FF36499B0AFD47D8B56930EE944C8AA9
-:101CD000273AEECCC48EA546B8CFE474309DE3EB32
-:101CE0006699F50B5DE754DEAF4812BC31B026C7EC
-:101CF000C163620A8507E9FECBB1D0FA58F8974A6A
-:101D0000FB9D54A64D4FA2385B2DBA2DB42EE70A89
-:101D100048CFA1E32EE2EB9D2B572E82F512B54E54
-:101D2000AD7452FA90C3D3C731DEBF3C025D66F199
-:101D30007596C1F330EFA771FE284B6A13097DBF7A
-:101D400088F35B68BF490922E36337191D6E9C7AEB
-:101D500085D13F5D773DD297C2D69D63AD5C09FBCF
-:101D600098A11C2A8FA7CDC5F7244D2349000F0B3E
-:101D7000B165219CEC84C249E270A2CB24505F6221
-:101D80006775297A1189A365A6CBB76E20C0AFC14C
-:101D9000EA5669FDBD93EF8984D2D9D6FBBB0442D4
-:101DA000E5C5AE4E4212B3601C1946843FCB39A143
-:101DB000E778F4992AE9F351D05C739268364ABF08
-:101DC000D714764E22B1A6F7C9393A9EA3B3DD2BBC
-:101DD00000FEECC41B730592F11F735270541C2F4C
-:101DE00095CE0BFB913F253ED88FE6F2549081842F
-:101DF000C47776FCAC16DB1DEE51B82FE2007E0BEB
-:101E0000EE7309F29FBE2ED9D1F1D88F69FFD6CFDC
-:101E1000A2DD77C3BE3B477EC0D643BC4EE06BB16C
-:101E2000C2EDC983F76CB83E0BFD0FF86C7880AE3D
-:101E30003797AF1726C937AC9FF4DCCF7AB1F27968
-:101E4000C0C74C3BD16207A37CD809F5BE56DA81E6
-:101E5000C2B151117C5EDAAFF1FEB9ABB3405EAFF7
-:101E600097DCFD08D039D929503A1F46E75D46E591
-:101E70008E5C481C0AADCB2EB6FFC67B9236C508D9
-:101E8000F05C2233E8F3619DFE2F040A8758575512
-:101E90008542F721F3F7050A38785F501532633031
-:101EA000D06DBB48503EB8101E3AFF689712E1381B
-:101EB0005D373C02FA2A9388D74EFB0B2E36EE355F
-:101EC000A453247D010F5411D0B284B8B16C143DD9
-:101ED0006F02FDD9658A57BA7EBBC5EE5B2100FE55
-:101EE0002A5F1B8D702F538EE706E5592439049025
-:101EF0003BAEC355FCEE72AF7C6978BEFA30C83792
-:101F00001F32B94CF986CE33259BC99DFDCE8E1963
-:101F100046BE5FAA30B9B494F33D91189FCD95B5F4
-:101F2000B380C7487CBE8CBF9706CA07F89884E781
-:101F3000E39FC7B3F54CB9DBD7D88BC26F4282E0C1
-:101F4000063D5CBE7D96D45B0DF693B9BE3B97AC67
-:101F5000917894C3EE93BE24D03E32EAF7C677C898
-:101F600074187F16979F27F8B8EFC7B375C4703DF4
-:101F70007E44704E0F0717677CB71C74C2F8C4C349
-:101F8000E022C60CEAF4D379486F3E8F55C079DA67
-:101F9000B2997C8C4F30CF13CBE53895FBC9F12833
-:101FA000F77DE9D0EF152B5B5FE8BCE9C179D37110
-:101FB000DE456CDEB120E781FFD5832F829C2FE2C6
-:101FC000743AB6D343C0EE011EB61404E5BDACFAB4
-:101FD000C53ADA5E1441CEF70FCED31FE7A9637876
-:101FE000DC9EA25D06EBA476C1E550B6652B282FDA
-:101FF000DFE865219B295FCE4ACBFE11884D7D9C91
-:102000004D7C9F6D598DAED9145F722771DB90CED8
-:10201000AB51EE1571F952BFCB43E0B9B7179599A3
-:1020200086F7E5CED976E2C0ADFCCF39BD3FF051A1
-:1020300067769C270C5EF472DD72268A88BA18DFF8
-:102040005BC2DF0BEDE778606F0C8CBF16FA5F4A5E
-:10205000F996EB1BBA615CDF58CE3BF59D9B633A6A
-:1020600068BF5DB9734CEBC1E7948F1A731F8B0186
-:102070007BA93583EA0190532F8B28271B9D0C8F5A
-:102080008D6955C4638073A9CB2F1E8771BE9A4397
-:10209000A651FC15B93CE4126770DD45B9555E21C7
-:1020A00009DB9F8BA2E3CC89BF04E946CEF3909174
-:1020B0000E804B33A9A2FB9715BFE8A6656927F1EF
-:1020C0008FC887FE54CE0B6C3CD5691C8734C3384F
-:1020D000B29BD203BCD7E9C7F5EC3A797E383AF225
-:1020E0002C26F9ADF325B5EB6A802ECA946BCBE2B2
-:1020F000E9F80BB6670D16E9F8235D6DF2EC3C9438
-:10210000DBB5401F9B92B53AA49FFF257B6E3AF149
-:102110005901EFA332991E985023F83653F83486AC
-:10212000D8098D9C4E2F0DDA37AB61FDA450B71343
-:10213000B435F1E7B783EF893FBF1DFC93F8F07624
-:10214000F0FDF1CC0E7E209ED9C10F4249EDE08713
-:10215000E2BF831D3C5C21BA1DEA43F8C7B37AFD98
-:102160009F983D1ABAFEF9F1CC0E5B4DF7DA0E746A
-:1021700029F92446E78C4FAFE67C3AF624E597BC74
-:102180009EF4DF4AE9DF4BE9AF8BDA4D6256647AA1
-:10219000F25F245F163FC0F8BEDEB517F9EEB79CBC
-:1021A0003F5BF9FCADB96205E0F315222AA2D073BA
-:1021B000BCC60C8F0BE47A28FF695F99E9B9D4E5B6
-:1021C0005B3F18F8E6E01C372C2B941F655A560D20
-:1021D00008AEFBF79C0FBBE51311A49117C1873024
-:1021E0008E6700D819F112F05F3D61F37A0F8AA86B
-:1021F0002722F111A59B77E30DF31503B00DEBA793
-:1022000074F367C02FE5B3BF7C177AF93EA70FEAD6
-:10221000871C87F192787D5604FFE2E3F86EBBE0FD
-:10222000639C7706D343CE7895BD479264D02F9AAE
-:10223000989109F2858E7B16C6DD1377FE710341F6
-:10224000BD1340BA5DC6C67D1E8CECE49EE38E4A8B
-:10225000A0F6479871EC5C8EDF10C15F50B85D430B
-:10226000F2BAED136B02FAED6C7D4F246BB684E489
-:1022700020DF1471BBE525C1AC9753B93E57B83F79
-:102280002726B0FE646EF7B80A8CA3C353B7036663
-:1022900071F9A08F93C4F92F2E4161EBAA66EF1359
-:1022A0005E1FC9FD270A97DEB82E3B7B7E21BFE863
-:1022B0002E85C52D2671BBAA1336C8F41BC27574B2
-:1022C00024BF2B68F7F507B81037EB9FC6E143DB57
-:1022D000F3B0BD82ADE352450D1B3F88841F1DFE48
-:1022E00052025F4F2E1B9F78BBE17625EC53A797D8
-:1022F0004870DB13C7E056A0C3AD818F13220FD601
-:1023000049CD7625CC3E47727AD5EB31B966F910C6
-:10231000299E9215D413E3111FF96CDD91E22BFD78
-:10232000F87E2FE378A0EF4D41F839D87AEF52BA12
-:10233000DBAFC3F67436DECC60FB0D388F8BF58FC8
-:10234000E4F7CFE4EB9A9AD08DA759385E127B2F31
-:10235000349EA09737F2F54D0FAEAF1ADFCB61EF89
-:102360004941BC2FC4F6D1ACFDFAF44D65C92AE051
-:102370008D8E037AC2C5F4C10DD56DA2D1DEB93EF2
-:1023800042FC4DE2F35605D7FB7DDCA7C6F67F2263
-:10239000AEBBFD87386F119B3792FC3811C7C6BBA7
-:1023A0009DEFE31AF08BE918F101922B2581D714E8
-:1023B000ED1E45BBA406343FE88F924F6515E474CB
-:1023C000B9E8F00A541E4BAA1DFDE4288968E0D73D
-:1023D000B67DF63D57471ED6FDA0D7574515DBC144
-:1023E000EF5C9D25B9411F16DF2B31FFFA9405E5FF
-:1023F000FD4871118EB357D1EDDC5B4D7EB4AAA8B8
-:102400001551B00EBB4854E6FF578CA7CF477079E3
-:10241000BDD79E6881F18665B078C108B50AFD75A3
-:10242000F215F3A335FA1F93DF1AEA6599BF27A5C2
-:10243000D711014BB3BF2D93F567C581A817D08E77
-:102440001AD669F6BF6575E409185F2686F7E8BCF9
-:10245000DB129C49684FE5907EE728FFD872056241
-:10246000BB02FC6CCF76C0CF18B54A29A1FBB1A541
-:102470007BEC208773ACFEDE104F684897DD5E6012
-:10248000C3FBCBEC59E06F3551FF1CE1A0255C3B51
-:102490002088275B9146800E294E90BFBA4B072BB0
-:1024A000854486C7B7136C580EE275FD7928DEB3F4
-:1024B00013A319FF13BBF7582EC80981C4513A5C06
-:1024C0004C3A32811EC534C6E735968E14A89F213A
-:1024D0009D2949B4AC6F924687F37FD6F1B8D41AE0
-:1024E0004B787BE95EEB9857010E12C40DAEC0B875
-:1024F00080C7D637183FD0ED553D8E10C96E6D148C
-:102500002BDF04BA1614FF17D0BFA7FDEB65FB4EF7
-:1025100067725A2FF5758C4F64FC6E4BB463BF3DE8
-:10252000779692D92AE2E908C7D3C12B012A5973B9
-:1025300015C0D3CB590FE6405CCA9E757F12F0E7F9
-:1025400068C2ECD372FA8E8B962B1D9E9309067B84
-:10255000634CCE2CB49B8A32EBD09E5A15C12FBD52
-:1025600085AF43E27432C8E1390BFBDA7AFF123BE4
-:10257000BC2F2995D150EE094CC292DABD9FC0F311
-:1025800055E9AC7E213CBCC4F939D2FA47815E8062
-:10259000784D7AF73E84C4647CEE950707F761585E
-:1025A0009F3531CCFA3EE5FA485F9794C3E932D7BC
-:1025B0004C77457CBFA989BABF78D174F7D6C5D00E
-:1025C0005DE87EC7642D1DDD9F04D7AFEF57DF3F69
-:1025D000DD6F1FD86FB9C4F6BF55F168300485B3FD
-:1025E0000AFBECB12F7B78BDEF48B47CD3FD3C985F
-:1025F000D0F7E2F7F30DC69D96F80DE0B47FB8E68C
-:102600000279D2904CE993E2A94160A5DEFF0B6EFE
-:10261000A7FDFC9BE32BA5DF37D85FB14B7811F406
-:10262000E108CF9152D86E59D120503BC08F930111
-:102630000F2579F74AB369BDF1CE39283FF70FAFBF
-:10264000C375AF729AD7AB9742228FE3676AC87F90
-:102650000D9CFFCA09F323F57E4F72F918CA1FA11A
-:10266000E385F2F54A873617D62524323D1BF4FF61
-:10267000DA45A3FF57C2F5D770FB6DA6F8C770EE19
-:10268000FFADFA34DBE1A51BEDA27AED9FE2FF7D01
-:10269000419F809F945E6237FA7F0DF6526C5F9582
-:1026A000A18DBE2209F4B1E8BE9B20FCD01FF40A24
-:1026B000A2B2358C3FB82A43F68FA0CF6D0AF90538
-:1026C000ACAF94EA4B88BFD8148D5C32A0A75FB83A
-:1026D000D75E4A206ED2A590E7C01FBBD07E1E48B1
-:1026E000BCC464474AE017F2F1D12F54EA4807C648
-:1026F0007B4A09D835D0AEA25DA5118F13F408F539
-:102700000B0DF2A9CB7E1BF27BE87C546E3D027C64
-:10271000DEA0303E0EF507BB389FEB7236941ECA22
-:102720005D8C6EA2E8D2AD4C6EFC2271684FBAF897
-:10273000E6F2696E19B800D79115FBC1559B1AE8EE
-:1027400094C0E59993C8F8A9D2F14C033CD7C70FC0
-:10275000C50FDDB906F174B06758FC86DA6BD48E0C
-:10276000B2527B6DAD109C7F0DA78348F888A4AF53
-:10277000F775CBB5D038D16DE6F317C54B920A5833
-:102780005C9F8481BFC8EDA4D5945FE0FC668DD5C5
-:10279000ED02BFA2BE5FD1DB1EA0BF7E32B377A425
-:1027A00026D7B561FC90B511E2DAEF2526203CA3CF
-:1027B000732C26FB8C7A0626FB31D2BE095F9795D7
-:1027C000EF4B0078E61AE119B2EF3205F70D663DDE
-:1027D0008C1B6B71133FE58BD84CE24681156BC1A6
-:1027E00038ACCEE70AE7735D1E3814F6DEB0A4BE3F
-:1027F000EC7C4F74748A145FEB92A83D4DC7A9D747
-:10280000F6A25ED5DF8FE3FB770C67F14687D3AF87
-:102810002861E4DD8F2F80DF264D8A2FA3EBFBB1EB
-:10282000C2EC6F69B8A5D287F12816AF5538ECC451
-:10283000E27C3BD8ED05E0780F85F5EC508C712BF0
-:1028400091AF27C649D7731E39B98AF3B75EB7A9C6
-:102850001D65B07E294B53E20DEB1F94A4EB9576DA
-:10286000E4EF48E3DDC3E5BC2DDD4DAAE8BC768787
-:10287000DB0FE75A36ADAA00FC05BBEA26730CED68
-:1028800076AD6088CD80F7A67EF2F4707CB92089A1
-:10289000C97FA7A455C27B4E4522704EE6E4F6726E
-:1028A000A47123ADE342F38D8A349F1ADEAE884DC6
-:1028B00062FC270DDF5109729A0C9048BF307A42B2
-:1028C000E0FD62E50E15F88AD2A327DC7867126571
-:1028D0000EEF7F117FE8767771CBC16CBADE7A8715
-:1028E000E416407E159E6C570D7281EAF509490683
-:1028F0007B59747850BE892A3B771F6D63FEF6FEC4
-:10290000E1E673B2299C5E5EE56524B97079928533
-:10291000DB4DFF9A7D7E53FC0D4A2226B834015CC4
-:1029200008F0D77D0DF561E42585CF926F039F6593
-:102930009CBE1EB9007C32FECDF0B9105F07F9CC09
-:102940004B8E86916FF54E396D8E89FFA91D12A1B0
-:102950005F95A13D121FEAF4310AF002FCD0A49960
-:10296000E2027292B79DF995B79BF59CB8C8CDE588
-:1029700033F9AA808539E12FDE41FC31B1C1F1E59F
-:1029800032733CE1C9241E17882251009F2EF72480
-:1029900001F214A22C3306410834853409A02752D1
-:1029A000609C81D44FE6F23C540F266BCC4FEE4D29
-:1029B000EA04A657D2717D497C1DA17A308DFA3583
-:1029C000108F0154833FDD5B82182F3CD5F01C5CD7
-:1029D000F05AD05F76119F00E3A7930E2CFB402A9C
-:1029E000021D3F8BB40B39147FF796570D02F9FD8A
-:1029F00062C83E2E648FEAA56E7F2CFB37C1FB9D1B
-:102A0000FF5E78AF2835C0BBEB3BC27B0A973BA18A
-:102A1000F1BC31DDF1BCA617310EF715B33FDABEBC
-:102A20009631BED790C5E279E562C506B0E7C7A882
-:102A30003201FD26E576AC833C27DDEE049704E207
-:102A40005C7ADCCFDE6F4EE560782E9D4438E1D9AC
-:102A5000908AF2CC998CF286D91123F8FAC7A8553E
-:102A6000F62CD5E83F3599CECF644E07635C25E858
-:102A70003F357C757EBBE362FDA43DD2030EB06B97
-:102A800074FFA83E670EDA3DA1EFF9A5A63F435CAF
-:102A9000D29F6353575078BCCCE5D5CBFD1E928CAA
-:102AA000E7BFA17E906E578DE0EB2FCD997510FC9E
-:102AB000AE31CA6C06130E0799CFD3E0EAC273F0A9
-:102AC000DF7E65417FAB8BFB5B63B89F05FE4E9558
-:102AD000B3E73E87279BCFD574FF694CB7FFD4245B
-:102AE00019FDA73111FCA7D1B6CE57AF80BC9057C6
-:102AF00045CC0B8904DF50BF2954FF8C4E667A67A2
-:102B000076323F270A81A71EEF0B3D976ED4F94F0F
-:102B1000F20A46FE0F9D5FDE3B06CF05896288C73D
-:102B20006607E38982E625CB0607E38761E2863301
-:102B3000920D71435D8FE9746CA37DED78CE1C3EE0
-:102B40009ED89A75A02FF30B5F4C04FC972B2C6E2C
-:102B5000A4AF8FFA85F3930D7E615127D3DBB6FFC7
-:102B600053D7B182C297241037F30FEA547B3EBA91
-:102B700013896B591C1DF3B4C638048C874BFE288F
-:102B8000AC979D72FBA268DDB6F76109FC84524ADE
-:102B90003F5142907EC670FFA221E7E83AA0AFAE57
-:102BA0005392FB7C7E7799430CA1D3E8601DE55BD3
-:102BB00082A9BE5AF2AC647CDB2B086F11F2C1B261
-:102BC0004DF9675B25AD11F63DCAAEAD4AFECFC4E7
-:102BD000FBCF605D8272E05BE13D380FD30760B3ED
-:102BE0009134C37C0EDA7815CCA322FD77C7A59764
-:102BF000123C8FD90638033FF763E28338CB0BD6FC
-:102C00009744D0478D7C9CAB49932AF765EB857E32
-:102C10004F6C756D5A0BF238390BC77BC1E1590FF8
-:102C200036E4C12DD22088DBD4ABCFDA217F76EF1A
-:102C3000D6C6F40E03FF1D7CC2D3279C7FA897F451
-:102C40002FCE5288FB8A65A5265A5CD82E42BD87B6
-:102C50007DB6A54581799ED86A0F6B4775713EBFD9
-:102C60007A0BB36B47E75ADC1402A48878A50438C2
-:102C70008F7113B79F36C40CD8D15E02BA284B446B
-:102C80003F9FD6F7C5D27ACC500DFD83FE0376E088
-:102C9000FBFD3F2E71B33C4AAF6330ADAFCB2D1976
-:102CA000BA16FA477BDE04FC513DD324A13E6D8E5B
-:102CB000813C8098019392A98D4B620452192E0E8B
-:102CC000F84132B3F39EB0EA7095300F72EF5619A7
-:102CD000F9EB609A88FC46E1B608EA7F4F8B2194B5
-:102CE000124999E62D03389693E67AF0A7CAD46B79
-:102CF0005F8C25DF027EF93B14E0FF756087875902
-:102D00005F1B5F1F0A114A3F07B634DC40C2E45123
-:102D1000EB74F88B18ED1380C31A7EAE4B5C939066
-:102D20007E22E3FB6EA41F67B3BF3E9AC2F1EAEDB9
-:102D30004DBD8CE3EF4F564DF1371DDF90FF4CAE8C
-:102D400080FC5B0FE6D3D69FB420FC5EC9137C02E7
-:102D500085CF815C91DA6C745539765F3F5A5FCFCD
-:102D6000E9B862FBA1865E00A494245CEF2BB98FC6
-:102D7000D9597EEBC5C7AF87503E5800E7C9141F2D
-:102D8000A394689F4AF1B51086C887FC1CBBCF4F3F
-:102D9000E76B73B697C6D1295E4816DC9B815E72DD
-:102DA0008902F2035D100B439442EB2032909E9215
-:102DB00008E673AD2BC8DB0CF2766DBADA0CF98637
-:102DC000BB07D831DF2C349F78B750F7623CE499C9
-:102DD000C40B28AF0FE4FE1ECFE90EA4DB08D02BF6
-:102DE00026FCD2E70D098C4F63F2CDF6677E4A16BA
-:102DF000F7B389D756105C574C8E5D8BA284F45282
-:102E00003C7BFF608EE0037A3BA872F940F7BB156C
-:102E10001201A91D346D4064BCBEDC6F94AADBC5F1
-:102E200082BE4F4BCF7DBC20F85667C33EFAD37DA0
-:102E3000D0BA3357C0F99DCADA5B099685F3E01C16
-:102E40003374FD35298C2E654A76B920DF9A578F69
-:102E500031E6C7C885B74E70C4621E13DA95A9B9AA
-:102E600002D35F27D9796E8FFC6C857864137EA8B6
-:102E7000D591121C2FE6D3E7BE0FF9BFE30A057FF9
-:102E800014AC87E737D3FF6B03FD22E7CC62F9D799
-:102E9000B99B703F630BAD6E38CB19EBF03595D015
-:102EA000FACB1F4818CF1E97330AF3AB43E75FAB4B
-:102EB00010FF680ADF97F3248477D4258FE1386FF9
-:102EC000E45950DE8C837C6CC85F36E655A33E34F3
-:102ED000E7738F13FFAC1543B39BF12B91BCBD403F
-:102EE000BE4F7099E1E73C693E2FAEC8B799EAE35F
-:102EF000F2E49078A597C58733185DBCD45FF06D78
-:102F0000CE0AD2D9D893093EA033F8130B4C7034B3
-:102F1000ED33A653D6007E07FB3FFE1338278951B9
-:102F200057DD8AE7E01CFE3A9DC470BC3BD39FFF8F
-:102F30003EE8291DFEA17470F1F8BFB6B218F09FEB
-:102F4000AF9FDF87E03F04DF1883D4F7D1B727DED8
-:102F500071FEAC9EF8D6E9A0C7BEEF69599D4DF150
-:102F6000FA8A933E003C6F927D770B413C5D10AF37
-:102F700039C548376B952607C8FDA84B8E3AC0DF88
-:102F8000D0E98288ADF946BFE39F85EF92F50273E1
-:102F900026DD820FE27ABF83475705E77936A53BE6
-:102FA0009FE8D914D013952C8FA35E1BCCEE5DE562
-:102FB000337DDA433EA4B07B1D6DD697D2CF97A761
-:102FC0005AE1F010381FAB877C3BBA3F79FD2CB833
-:102FD000D140E429B3505E92F5028BCB17FD01E599
-:102FE000FB5C976FA510663EB464709D2A937B4589
-:102FF00089D89F4CD7F3922A5FC5F54F61F58B5D59
-:10300000D7EBFFA4751DA0B4420CFEE7446E37EB6E
-:1030100076F70407CB3B9C5024223EDED822F830C2
-:103020003F92F6F3523A59C0C97622B703BB0A9FC2
-:103030006D1CA4823DA899EC4EA1A80DEDBEB8422E
-:10304000B33F18AF459BF09F383AC1544FAEEC6583
-:10305000EA9F3A3DDB1C57F05C667ADEBB7AB0A98A
-:103060009E5177B5A97F9F6525A67A9677ACA97FF3
-:10307000DFD5934CF57E4D3798FA5FBA61B6E979A2
-:103080007FDF02D3F3CBB72D31D50734FFD0D4FF88
-:103090008A9D779B9E0FF2AF353D1F72F03E537DA8
-:1030A00068FB4F4DFDAF7C7BB3E9F9551DBF343D47
-:1030B0001F767287A93EBC7397A9FF88C05E53BD77
-:1030C00098BC6AEA5F6AFF83A95EAEBC6BEA3FCA3E
-:1030D00075D4F47C8CFA91E9B94E07E3723F31B5AF
-:1030E0008F777F19724FA712E59B0CF180BEF0A875
-:1030F00009CB68D2CCCE75483B962F1578DCA94019
-:103100009F8F7A1B2121A9DEDBF957389A7EA3B065
-:103110006F1CB39F3462949F7A7E2AF55BBC5194F6
-:10312000146203946E8750BA0B08582A012A591367
-:1031300021DE138565422011DB1303F15826057A41
-:10314000637B72200DCB94405F2C53035958BA0215
-:1031500097639916E88F65AFC0107CAF77601096C3
-:10316000E98161D89E11B80ACBCC4029B6F7091481
-:1031700063A906C6619915188365766032F6EB1B64
-:10318000B816CB9CC08DD8DE2F703D969704E660B4
-:103190007969601696B9818558F60FCCC7F2B2C02E
-:1031A0006DF8DEE5815BB1CC0BDC81ED03023FC045
-:1031B0007260A01ECB2B022BB07407D661BF418179
-:1031C00035580E0EFC04DB8704EEC5323FF0336C3D
-:1031D0001F1A7818CB82C063585E19D8846561E0E5
-:1031E000492CAF0A3C81E5D58167F1BD618167B0AB
-:1031F0002C0ABC80EDC303BFC1F29AC03E6C1F1104
-:1032000068C3520BBC8AEDC58197B12C09FC01DB68
-:103210004B0387B02C0BBC8BEDE58177B01C1938C4
-:103220008AE5A8C0112C47073EC2724CE0032CC7A8
-:10323000063EC1F7C605CE625911F812DBC707BEBC
-:10324000C0B25BDE45CC57F658D09FE57E6A647FFE
-:10325000C18B72D2CAEFC5416E35E6FFD709BE51A8
-:10326000943452933A305E682DB461BCF026D26932
-:1032700065E7D0ED4ED04B6D579D488738DA1BC9B6
-:10328000FE0C63BE8395C701CAC553188F9A90B4CC
-:103290003719F4E94DB419F28C88760EF32027F033
-:1032A0003CC89B24EA60D1A51E8211AEC27E7E1B63
-:1032B000ADCFA820DA60DABFF12A1BDE2F6A1C4CE2
-:1032C000FD205ADE93C5F2657DA94C5F3ECCCBC78D
-:1032D00053D9F9CB5F0B589EEB8C5BFB317E2A4BAD
-:1032E000BC80DFC4E0307420CF8F757466627EECE2
-:1032F00045BEF7A714FE1EEFBF3CB5F2C954BA0E87
-:103300006F09C9AD7304FBD1F6A723B43F03F220C4
-:10331000B47DAF85E1C3FB96C8FD84CAB849E7F127
-:1033200013DE58DE7ED98BFD82F5DF45F043095967
-:10333000C1CE0FF77E50711DD587130B4537951CF5
-:10334000E4CFCB770E3FD68FCD0B71506F8988F1CC
-:103350008B194587F627D2FA8CA5F19877DFBDAE99
-:10336000122B3E9FE07AEBB217E9D66FAAFBCDF0A5
-:1033700063A6789307EDAEDB388D12CDFA8F0EFD84
-:1033800039D22B8BFBDE0693AB20FFAC386EBB66CD
-:10339000F59D2F3F866836A299E89EC16B1DAC1F34
-:1033A0007C7F62B7C0BCB1BC0F852BEA7D6FACECF3
-:1033B000AB17C07957E380EE62F23AC9F9E2CB006D
-:1033C0004F092E4E920E07D83191E029B8581C347F
-:1033D000AE487379297E1ABE16316EBC2FBE4001ED
-:1033E000FAFF91232715F843E2FD1ADADEC1F856F9
-:1033F0005C7E27F13A58FC5EB5C139BA1DCB95CB3E
-:10340000DD58362C2FC4726DFA7D76889788C9985E
-:10341000094CA232E6623C489FDF1A3FDB5EEC2695
-:10342000E4CB87BE1E07212411E20CD444F89AD6BF
-:1034300057509FE2642AA3CF375CC71CC00F2753A5
-:103440005596876F61E7C631F97E0DE28D316EA525
-:10345000445283EDF89784ED9BC11F798374AC9F30
-:103460000C70D4D87D8C7A7EDFB4BEB81F87ABFEDB
-:103470005E08DE43F02CCA6E3CB716A369FFBCC8D9
-:103480007875B9585E02D09744E9EB6FB06EB037EB
-:10349000B5180B8CA7E3B74BEAC47CAA7A217CDE73
-:1034A00065B68BC987064553CE778E4214E91F4611
-:1034B00079EAC8DB1942CF0E94AF58877C2E2EAF25
-:1034C00076A46AB92E3A7EF3355C0EA427A01CA020
-:1034D000EDF75D4DD7BBD3C2FC146F828CFC4281EB
-:1034E0001087792F76356ED279F220562D5734C950
-:1034F0000AE7036A1CC06B15CFD7831BCA4639F095
-:10350000AFEA1794173E961719D27FA785F3557423
-:1035100014EE4BE4F0D0DF9BEE62F2F8C1ACCAF1DE
-:103520002E8C8FA8E92057697D22C08BEE3F1DF8B5
-:103530008AD6AFC5BAD25D9F8CFD5DAC3F26D25C0A
-:10354000841CA6EFDD80EF49DDE3CCC0BAA37BDEAF
-:103550009B719EA4EEBA079FA7B3FE173B8F5E76C2
-:10356000EFFFF74C4E7E2A697109143E95CBE65465
-:103570009651BD3D79D97C2CDF5BDEAE815C3D4E42
-:10358000E54903856B6571DF24F073268FEFEB50FF
-:103590000DF43A8FC735F7AEB68E067D57B246ACFE
-:1035A000DC82FCB4C214B7FBBECBCAE34D6C1D5524
-:1035B00094C7EFA424376FC3A1CB1A0CF6E86CE2D2
-:1035C0009681DEE7ACB606E99A18F853616D3B2D9B
-:1035D0009E1F5D0FFB582BF2F30ACEAFF184FBF375
-:1035E0006A4AE579F40E596D239E30F2B8277C08BB
-:1035F000F907E5834F1D391897A5969A3DDCB83A2F
-:103600009C22CD372F42FC5787930E6FBDFDE8FA01
-:10361000210AB3AB7D2638CEB96728C62BE7F178EF
-:103620003D89B773FE64FDAAE83C3BE03D49538108
-:10363000DEA11E4EBEE8F356D17FDD39381C7C3941
-:103640001CD65A991E0F81EFF10DFD62410F85E2E4
-:10365000EF62E15C6B23789FA273AB93C59192A656
-:10366000E3F8D57C7E923403D753CDE77B714F8C42
-:10367000DF42FB976C756E063FF84C89F7C14A90A4
-:103680004F9BAD98CF76F79E756FFD0CEE7D6CB2BB
-:10369000E299C9FC98070AE0FCF42F5C8E5205D031
-:1036A00006DF4FF010FD4F1360FC79848D7F463F9D
-:1036B000FFD81A87F03C59B6A571182D3B762FAE6E
-:1036C00080B8CB893DE30F80DF3C3F9A4878979DD7
-:1036D0002832F29FD77ACC6C1F48C1BAD8B33E0FBC
-:1036E000EA86F8D17C9FF59891CE176E33D78DF08E
-:1036F000B218E1A59699E1A5969BE025FCD6E917BD
-:103700000DF02A8BEA97047A7DBF4BC5F1AAA35628
-:10371000A6007CAA77AFC172E1B628EF31C3BC8B9B
-:103720009BE34DF5DA9D695EA35EE93AF8582CD02B
-:10373000E11297E83D46F5DCA9E55A3DD831A79757
-:103740008FC652C7FFE2E62CAFC3348EB9DED52454
-:103750008C66F2598D9B721E7E5DE292719E0FB750
-:10376000317FF3C3E5762FCC736AB9E265F3BABC57
-:10377000CC8E62F05AB42CC67B6C48707D91C6FD2D
-:1037800067AF8F901672D44EF0CECEB9F3E8ED88C5
-:103790007249FA5446FDD16AFD3BD08D9DFEEF1C67
-:1037A000C65125ACEBE3D6368B5EC8272664BB69D1
-:1037B0003EFA9E7ADCC06F91F582F93B13FD21162B
-:1037C00086F2999D8378E01C848E774672AC8638A9
-:1037D000827E0E520B13D1BE8BED1DB287367DDC7F
-:1037E000D2F7BCF7CC299EB2402F57DB9B6450B672
-:1037F000D5CDFDCB809F3E6EA94F01F9B150ECFABB
-:103800005EB8FB5EA5699C6F7DD64EB3BFE8D3D78B
-:10381000992599F88C38BAF74DEBA722E40B8F4F16
-:1038200063F66CCDF6432387D1F5D7EC3C2B63DEF2
-:103830005A9A677C9A61FF023F075AB0ED888CF66E
-:10384000A7D57BC91DE7B3EF7BACD3E132E51D7A89
-:10385000493BF0E7EC42A233EC75EF5279F3C1AB90
-:103860005602E787E42BDA8B3ECFE44FE792CA5843
-:1038700080D7EC9685287F3E786EDC01967FD45405
-:1038800000F4F131B160DEDCC7E4F7B1430CF05B6A
-:103890009626EB7144BB31BF852E300DF3D3AB1BA5
-:1038A000DBE1DE988D485E2E9704F6BD1A9F80F20C
-:1038B000AC9AB57B897D05EE633593475EFA1FD4DC
-:1038C0006F6932CBA7791BCCF52A322905F2BBAB45
-:1038D000EEB7420611996F947F147E33D3581EFBC6
-:1038E0003C52D708F6DC2332C5135DFF6C8548BD1A
-:1038F000A91E5AFCFC2305B3687D791A3BDFF990B9
-:10390000FB19F3C13CA5CF172CF3C95A5ECFFD1D9F
-:103910006D19326D18C1F198DE5AA0DBAD448538BF
-:103920007E6FF85776E4FDF76E11F1DCA937B41B12
-:10393000E4F39CD5E6FD5D68FFA1FB25E43EDCC712
-:10394000826DD7A2DFA6EF47C797BE1FEBB6F0F791
-:103950007C1FE4F4DA7DBECAE1A7FBDD4FA631FB94
-:103960005DAF3787D47F1D52D7E9DBCAF99BD2FD03
-:103970009369C9C0CF9D23199D74C8C6F35039D827
-:10398000AFF97CFD6C9C5F68BF5F9FAF5F5470BCFC
-:103990005DE1FA2D7EFEA9E7C01F5DF0AB0762E195
-:1039A00030E803A92905F284166D5D190B703A29D8
-:1039B0007963816E3EF089A3C3C1ABB31B5E9A43AA
-:1039C000A078AFD1E9BF68C504D0EF7FDF6A55C0EA
-:1039D0002FACDD66F3C3F7976A5AE6E3790DAD1FA6
-:1039E00061F55578AFB276A7F53D235E173CFE40F2
-:1039F0000AE677106F6F769EEEEF0D9F0EAAD9F252
-:103A0000FE48F0936B4927D273E87B307F2001E5B5
-:103A1000F52C39AEE7733D6E5ACB9A486DCBBAB3ED
-:103A20001037AD6D197302F8BE9648EF19E9A91A5F
-:103A3000689AFA2B47D278DEDD95E44A902F3A3C1B
-:103A4000882F19E573FD130F0D3C42D7736ACBAB7A
-:103A5000B182D15FE5E7ED5DCD73FE96781EFD7016
-:103A60009AD2A9313F5E97BBEA4EBA80545A6D652F
-:103A7000E522AB3F761885EBA24D56BC1FBAE8A9EC
-:103A8000C77EF153C8237AC786E71F0B9FDAFFD69C
-:103A9000D5B4BEF0196B5205DB8603CE8375BCD45A
-:103AA000D2FFC1F9848E8705CFEE9721FF0BDAC1D3
-:103AB0003FD0F1B1F09936990CE809BFD2E636B99A
-:103AC000C311062FCD4746E23DA3273E9701EF1FC6
-:103AD000EC11486A56CFF7AB37ED473B06E08478E8
-:103AE000E478EAC65B0F7CF927ECCAC77E0AC8ED0A
-:103AF0000BE16B1FE8D564A4EBA777D17554FFC920
-:103B0000E60638543F7D5B2CECE78454C7E8FB9114
-:103B1000952990E7566DF5A62858B2F6EA476F4703
-:103B2000BA9B77E8F61476CF414BE3F91D69B0CF25
-:103B30005B364EC57D56110FD25FF5236225E4C179
-:103B40007C2691D1CF84E18FEA5E4CAF9ED84C9118
-:103B50004BF77902E46552D0DFD1EF35DFDE1D0788
-:103B600061E7909FF173C86B7A594CFAA59B6EB7C9
-:103B7000AC42B9FA6186960AE793140EBA1C45F96D
-:103B80002A1E2A4F657862F218DFA3F4570AEDD097
-:103B9000BFDD8AE7C286F7B8FC64F32FE5F3D3757F
-:103BA00047833D722285E98DD0FDDDCFF747E0C226
-:103BB0008681CE0C7CCEF87ECB1AC6E73ADFFBAE10
-:103BC0001D0DCF3FFD23E323780FF4115D973F15C3
-:103BD0009FB74D11502ED8883F1C7F6FB172FE36B3
-:103BE0003FA71209ED399D4EE8FA25F81E59905E5F
-:103BF000E83C098807B457AAEEA7EF1BECEC5A98EB
-:103C000017FBC9C1F6AC201FCFE3F2604E2FB33CC7
-:103C1000201B932F2A2EB0C8EAFBC54F817F29BFF6
-:103C20007A55E05F2BDEBBF968FBBEB76EA074FE71
-:103C300051B3CEB766791ACAB7D53B6EC7F86028BC
-:103C4000DF7E945E47C2F26D3ABF3717CAB7E91DEF
-:103C5000FF5679AAC36F5D08FCA87CFCF92E3532AB
-:103C60001C43E5E3A5BDD4B0F291FEFD9114F4A48C
-:103C7000439DFE74BA5BF0E4E23E2087BAE953A7A5
-:103C8000BF6EFAD4E92F74BF66F8853E9F02C94E15
-:103C900006FBC17A37F13A29BE3B778BF8BDA433D6
-:103CA0006A672CC47F5646919960879F51783D9EE4
-:103CB000D53B93E54690137A7B67148B579EA9EC0E
-:103CC0008C8D37D8D7475AC55888EF76F8C2DFE7CA
-:103CD000C08C443A7F4784FB1E7A3CE24C74EC4033
-:103CE0009C2F3AD307F82A171D99CBF2C10F13F175
-:103CF0003B3E73575C170BF921675AFB4E9C4EDB1A
-:103D00006F79997FC6CFAB496914CE7338DE4F12F5
-:103D1000EF8345747F735A99FD3C777D783AD1CF14
-:103D2000CDAB1C4B659047D46E0DD20781E7EC3BC1
-:103D30000BD51B43DA5BC7213D2D08A1270FF78F59
-:103D4000DE047A82B8EB203288FB2716633E48B93E
-:103D5000983711BECB79E6A08879EB5DAD226984F6
-:103D60007D6E177C04F8DB9B8C745943E58731FE2C
-:103D70007B0AE8EE3CF7E84EFDFA2F0577D02E8B54
-:103D80009E7B77E0CF6879EAB9772E7901EACF1F79
-:103D9000CE7C9784F1B3F67C7133C8FF337B6C041F
-:103DA000E32A7B5ECABC03EABB6C987774E66E9B21
-:103DB00086F6F41E27E6D19DC960F1D4FADD9F0F87
-:103DC000C47C74D2C0E8AB37BBB7D5D5FAE55FF198
-:103DD0007E6D2BDD15E8DB3D31688FD7EE8AF281F1
-:103DE000937A66F7E705C6F38BEFBA9F1A99C5EF8A
-:103DF000CF38C974887B9D896771EBDA17AE7A0C6E
-:103E0000F2E117B7B4C9706FA7F4B75F0F04797305
-:103E10006607B3234E5B3B1E256E42627ADF768FC8
-:103E200095C2F934D87694571EEFDD321ECE377A1C
-:103E3000C285C1E10C8503EC8BC2A51AE464247829
-:103E400064FFC7C2E3ECCD30FFA2D62BF1FC210802
-:103E5000174163ED4E9F5DC0FDB3F63D9F0F0479A2
-:103E6000FC51F30AD4EF17DA77F1FF73FB16FC1756
-:103E7000B36FCF7FECBE19FD1F07FD94DC930F7A63
-:103E8000D2F9F3DFC3FAD34E37AEF722F9DFDB9B6B
-:103E9000C51DFEF3F6FF2DF1BE43C0FC950BE1FD01
-:103EA000E7FFB5787F99E3DDA9409EC499DD5F67A0
-:103EB00012C3FE2FB4EF3DFFA5FBD6EDA0764B9DC0
-:103EC000924FD7F70E699A9A45CBDF699F2481DB21
-:103ED0006A8B704E73BA37F32B6C02CBFB265305FB
-:103EE0003DBED46ECA7B4AAF467B6382760FFB3EF3
-:103EF0009354D70E79A7ED2573DC6BB1C7E0B73DBE
-:103F0000509F329CD7CDFED684927107C1CE7B6381
-:103F1000055D1FE4F965480ADCE598A8896817D2B1
-:103F200012EDC137334762BF8985667FE3FA103FE0
-:103F3000E1BAE9E6E753F9F8D3C87DC910A79B3683
-:103F400097C5E9AE23752B8DDF519B1A32CE2B100E
-:103F50004033D891DF147E6ABA0EBF25080F52ACE9
-:103F60009FDB5D007E84C1BB7DCA20965F2CB919A2
-:103F7000FCA62D7663DC94FBA156FEBED5B1BA1D1E
-:103F8000F8D64ACCFEA7EE475E08CE84FBA7385E83
-:103F90007610EE564D44FFD4302EC245C7C737C504
-:103FA000838EBF6F8B8F2EC087E15C572FE7DB6757
-:103FB0002D8473083BE4BBD37D4D5CCFEE8FD8F3EB
-:103FC00004846365A115EF4DBE6FA92C00C3B962CF
-:103FD000C895353F64C3BA013EF3391CAB481DDABE
-:103FE0009DE4AB73E78A0AF0F40FEDD6F91A21E3EA
-:103FF000A95F525524F8A3E9BEE749C41B3718E26C
-:10400000A00279CF1807F599EBF0774D4A709C0B19
-:10401000F58F241FFED9E5DFA83C7A8F22FB089498
-:1040200098374324A3FF38B395C1B17691E0CB46CE
-:104030003AF25B8DE7BF0FA4B378E3DFEE1C827228
-:10404000AEF8C703E2985F9B8FF93CB5DCDEEFF278
-:10405000AA7110CFE96AED1B07F19AAE83A5B1E111
-:10406000F2780E71BFF20FCBED589E29139AC43827
-:10407000BC773201F570591401B913FADEEDE97A13
-:104080005CA68E9D4B1296875FC5F7318FBE1A973F
-:1040900060C0DBFAF11F48037BE201FEDE339CAB1C
-:1040A0007C57F8821F0B703D14D53132DCF709576D
-:1040B00071F855ECFD4286F8C1A4D62CFCBEE4A4F0
-:1040C00032D194A7BA3C9DFB5343C8105857C5DE64
-:1040D00031B157015E0E8AEE280ADFDAD6B3B22775
-:1040E000CCF95C283C617C88231FB5BAAB009E47A5
-:1040F000EF89C2FBFFAFF3F3A23CFE5D48F87410FA
-:10410000C4CF9AD2593EC8FBE92C8E3EB9A2D89AA8
-:104110004CE7CD6B5106415E592FDEFFFD74159FB4
-:10412000F7E6EFE9FD7A2D62FD8EC84A4DB8FDC76E
-:10413000640AFC3CC4FDBD42E13F0F6FC53F76FA07
-:10414000E15E5C5799C0EFCD84D23541FEE81A2D6F
-:10415000F840FF821F8BF50A01F5FFEB7ADEDD24C4
-:10416000A62F75BA0F85F36E0E677DFEBFF0FA5E5F
-:10417000AE377438EBF00D5DAFDE9FCAAB11C67879
-:10418000CBC49D839E06FBA4A655502C74A81AA9E7
-:1041900043063EACDD79AF15CE17AEE7BFCF42A4E4
-:1041A000CA81C6F3DDF7D3D9EFBCEC1B3C0CEDC7DD
-:1041B0004FD633FB589B7B3616ECA0D72DEEDF0D88
-:1041C000037E7C43347DD73CB47C77B9B2A0CC6A03
-:1041D0001C370BD7397951B115C243372E6AB3A6B4
-:1041E0001AE8E97DC8C31A1A6CEFB548C5FC453A10
-:1041F0001FAEC3FB231B817C8CBCE6F69218FAFC35
-:10420000C6BA784687D5CD6D32D6D97786F5F9F41A
-:104210007942F9694A458CA93EA7B4231DE0526151
-:10422000F32F7587A1536F867EAEF20DF58446E9B4
-:1042300076E0FF0F7AE2ECC870DF419D98D1433FF2
-:10424000A486D30F4B56A8A900FF25BBFBA602737B
-:104250002C79B93C259C7E7873393B3F3CCCF32EBE
-:10426000CF4CA1FAE10A837E981285F411FADE554B
-:104270001917A91F747CFD9BE5CC9BA01FC2F0758C
-:104280004586593F4C6B9D85FA61DA1491A8867872
-:104290005C69068FDF46D40FC529D763DDEA8E0936
-:1042A00043376F72BF04E00A25CC037AE28E0C26F6
-:1042B000F743F5452479AE5CAC3CFF5F82B32ECF6B
-:1042C0009750FF85FD0E4E281D1294D74BAE17F068
-:1042D000F74B96EC66F27CC94D3C2E19225F2B41C0
-:1042E000BEE61BE52B7BBFC6C3F441EDCEAC8766B3
-:1042F000D0E7373459DD76DAFF86A0BC2D30CADB33
-:104300003B32241DCE994A18FC4E9F114354B3BC36
-:10431000CA01397574D04B79CF02DDBFCEEE99BD9D
-:10432000CFF5F86B835ECA8778FAEFF9B89B391D31
-:104330009D5E4E1694513894CE65F6F0E2ED22C2A1
-:10434000A1A685D97935DB04BCCF3B72F017786E16
-:10435000B870373B3784EFF9161BF0B8F0F58EC60E
-:10436000DEF07C9380E79E55EE85ECDEDF061627B7
-:10437000B6D3FF205F624D74EC6682793A1AC69B11
-:104380001773B855D83A0FC0FB158F0BEE4D28D7D1
-:10439000CCF1E9C539633F00BF60E1B69076F71A0A
-:1043A0003CCF580C7167831FD2C6F7778BE8CF7B61
-:1043B00016F2027F2786FDBDB3B65038547F4738CA
-:1043C0001CA270C8FFF670A86DBD17F36FBEEBFEA0
-:1043D000F76570FB7030C9077E79DFA221FF7B5F34
-:1043E00011F15EF1DC7BFBA51AF3940E6530BBE2A4
-:1043F000758BA7310DFAD5B0FBC7F3363EB31FAEB0
-:1044000086CF682683206C3F6F83594F76EBE51685
-:1044100015F5EE8CBA6704F89EFF2D22C1DF019BD3
-:1044200033D8E681F3D743519D28CF743AFC12E884
-:1044300090C2FD0B3EEFD15E9D65E857EC1414E48D
-:1044400013F89E06D4291EA2603F577D3E92C31DDD
-:10445000E333B53B199E6A295E80CF46527B17F441
-:10446000C88D54EFE079596B9B15FA57D37E892894
-:1044700077DCE8EFEAFA09CEEF8A530C78DB7D842B
-:10448000D1EF56C14DC2E02D97FE773EBC45C29795
-:104490006E3F5C2CDE74787CA9CB6F8EBF4351EDF0
-:1044A0001543F09C8AFD0E10698DC77395634D7D91
-:1044B000118F519982E9BB32DD7805FD68882F5D47
-:1044C0000B0BC70FD747619E1CCE9BCDEC21A37C65
-:1044D00009F5A36B493BDA35629AE7E174435ED88C
-:1044E000349EBFD27DAE1BEC37392339723FE22AAE
-:1044F000C1F31F3DBF167E390AF3C1787D5F46C107
-:10450000E11974BF9FAC16F17EF27516F5AD22E08D
-:10451000E3B5560274F9C96B568DD9A13128876766
-:10452000BD7ED40AA19159905F40FBCDBA8BC9DB07
-:10453000A330186DFB13D5631A7CB784340F85BC88
-:10454000FD29EEB672C8DB9E9A7F68259CD34D2E5E
-:1045500055DE7A0BE0BB462400DFF75697A2BF7208
-:10456000DBAD02D2F5DBCBF1B7B0C8D429596FBDB2
-:1045700045E7BD6975329EB3CDD0F69703BDCD99A1
-:10458000E874C039DDB85C91780C70BC89B463DC28
-:104590006246DDAD5361BDD5542F40DCB5BAF55050
-:1045A000792AD4370AF83B6AB55E8F0C57A0DA3700
-:1045B0009C9521FE5245FB017A6A37B27EB55B04B9
-:1045C000BCDF5345E503ECAF6A8B40E022493BB5C5
-:1045D000FFEC6C5C9F9D8EDBBE91BE4FEBF3E07DEC
-:1045E00018774B3CFEDE5DED6BEC7E5055E18A03A7
-:1045F000209FAAE87BF43169DF722B8E377FA340BE
-:104600002035B8BA30EB478530DE6B56FC2EC8E15A
-:10461000B6876558F7CD74BE343AFE1CB1A31CF3BF
-:10462000ACEF1014CC83FEEA07C80767381F90D799
-:1046300096313E13789DDB85BA7EBC37339BE5BB54
-:104640002F5BD108FBEAF02667814B54BBF3AC0C1F
-:1046500076DEB1E5F0E1198A379E07B7CF7B54EEDD
-:1046600030C8A9A733FBB2EFE4EF2C463EBF855418
-:10467000E2B9B86705D3CB475646F904B047AC0A50
-:10468000EACD7D2B2F7D10F67FFA292B9E979ECEAB
-:10469000E8C0F8EC898D56FC6E48FD4611E5C889E6
-:1046A000ED2C2E243E3275641AC08FCA01A0BB7D4A
-:1046B0001B4B659087277C02BE5FFAC8ED292CEE64
-:1046C0006B961F55EA0294178F4431F9306F43F807
-:1046D000F3D588F262E94826DF43E4C1E2F4468C70
-:1046E000FB85CA895AE2D0E5C360A8B7FBD3907EA8
-:1046F0006B5EB312B0EF6A24E5E60D403733A2E0FB
-:104700002499F2857F3FC8B74F7C82EAA5CF6F9C82
-:10471000F99BA100BFE3006FE08BF58978BE5AE5F5
-:104720009B8570D5F311E76D30D3B39EF774BD4709
-:104730000CDEF3A1FFBBB13A8668867E87EFA274D8
-:1047400049E79BB953C0EF211DBEEBC881DBF3B134
-:10475000AE001DD62CE37A75BD13E9F6F00FCEAE90
-:1047600004BABCF94E01D74FBC9E46D02B351B0472
-:1047700015E29AF3EE64EFCFA3EF03BD1C7E98D150
-:104780000FA56315E8BC66E3BD07B0FF164185F1D0
-:104790000F6F9A857AB8DA2B127CBEE508DACB5413
-:1047A0001F60DED03EAF9802745ED3605300AF3A14
-:1047B000BDE8F477847F7F9AD8DD0327C3EF536485
-:1047C000AAECBE7C08DD89D3B390BE6AB75B915E6C
-:1047D0006ABD8C9E8E3C25221DEE5B79DD48A09F34
-:1047E000D35B8508F447E92B3F485FE223567C7F83
-:1047F000DE132CBEB06F23A3EB132DCC3E2D7DA476
-:104800001FFA35F35EB712167F200EA3FD71213A11
-:104810000CA5BB1E7A89D36124BAF3589BA741FE2D
-:10482000C1ACA7E9FAD520BC4A1B7F807180D2C6F3
-:10483000EB71BF3AFFC0BD16C8DB98DBB482E5332D
-:104840004A2CBFE71BAF2B641DCB339D41FA175990
-:10485000FE899FAEE3A5ED8FA11DF0F12F8F607E45
-:10486000E3C21728FE69FFD3DB9DC48F76B60FE540
-:10487000CC821611F34B89E42F986CB8BFA5E7657D
-:104880002CFC9513E1BE6087CD5741DF5FF0DCD192
-:1048900081784E7E37B353BDBF64DF9921DE8E81B0
-:1048A00093213F5362F921A1FA3790C9E230A77EE4
-:1048B0001383DF6312B6B5E139D382E6EBAC36433E
-:1048C000DCF24CA615E7A5FDD83D338A7F385F841E
-:1048D000F5197F4F42CF0B39F504E39F053BAD68D7
-:1048E0001F2DD8B609E37DB5DBCE62FE6CE9AF9E25
-:1048F0008A0538D4EE14CDF953DB44BF0DF3BCC4A4
-:104900002336F65D0E531E534D0BBBDF51D3CCF354
-:104910008442F26716FE6AF7735E0A9A85CF3E1EDE
-:104920000BFCF461FBD65880271D0FF38F2616462B
-:10493000C84FBA505E52F31A9E97341E7FA7233495
-:104940002FE943F807D5E3997D42F2BAB631B9456C
-:10495000B15F10EE1E926EBF2C7CEAB347218FF63A
-:10496000D48E8F1E85F52FFA9F4F1E85BC0EB22761
-:104970004A017BA2F6976F62FEA1FE5E611F664F41
-:104980009D7EE271CCDF3CFD8E0DEDC2D3BB4F644A
-:1049900082BD70FA992F52202F73E9EE728C4F2C42
-:1049A000FD7529DE0F8DE46F027DFA2E227F34140F
-:1049B0001FFB5A44BF83AEF3E3B76DC8FFDD7966D2
-:1049C000CD8B59FE9ECAF3CBB687CFD3D5F3A16A60
-:1049D0005A264F1C0EF2AE85E9F5EEFCA80BE595C4
-:1049E000FD91E2F58A8BC0DF769E3FD83C3E6C5E3F
-:1049F000D9C7F00F8AA76921F8FBACE5969FFF1491
-:104A00009EB584BFA7ADF3F585E0A6E701F7EDA35A
-:104A1000CDEA037CB4E349CCE303BC55A8A0FF3F37
-:104A2000CB84F8E6496B27C60D3B77DB14C8F75AF1
-:104A3000B0FB30F2CBE95F1FC23C5BC2F3714F9316
-:104A4000EE3F9637C96317B55B9C2C1F8DC31FF2D1
-:104A5000D5D4586CE779698C8EF57CB548796A0FA6
-:104A6000F5C966F1439E9FBC586D971547105F804E
-:104A70001FA110F075C494FFA7EF3B743C05E070D4
-:104A8000A531FF32523E20B7D37BE08BC9E5D39BE3
-:104A9000783E66779E2521E983213F88E9C35A9FA6
-:104AA00070381C7EF5FCCBFBFA70BF53E74FDFC5B7
-:104AB000E55D5E78DDDF0E2E0D7DD8FD001D3EA785
-:104AC000BE0A2FA79FE2FC4EFD96ED7D0CFECD4C5D
-:104AD000EEB7E87967FA7A1B9B995E3EB58DD98D62
-:104AE000A1FC5D13E1F7B45EE8C3E20D353BDB06E4
-:104AF000821C3AB5F7379CEE7CFC1ECE11D9CBE573
-:104B0000B6CF28B723FC7ED97E3E1EF577C38E57DD
-:104B1000BBFD6CD8F13E94B4EB60FD1FB6333BE4B3
-:104B2000C36631ECEF20FCAA8FD5E407363A65F472
-:104B3000BBC4D86894474B9D856FC377DD963A65B3
-:104B4000CC77A85FC1F323EE72E3EF78D43BC7E2E2
-:104B5000F74B57027C0C7EA855F1E0EF4E585D955F
-:104B6000F9E05F85DEEB94932CC467C4BFE4C5FB1A
-:104B7000BD13B23F9740EFB42F37DF1B699794FD09
-:104B80008974BCF632C10DF66E4F3A338F7FAD2675
-:104B90009AE26710AB867D75B9D9F7D09C16BF42F3
-:104BA000BB106754BB0B1D3D95FD5E35FC4C179C3F
-:104BB00083AF5D6ECF817B5CB1C48DDF1976BABBEC
-:104BC000EFCFE0787124246F9BFF5EB5830B95389F
-:104BD000A2B441DC223A97FDFE8342A2DDF0FDA2A1
-:104BE0009FC46A78AF69BDD3837A3822DFB8D9BD54
-:104BF0001A3D9E1457C8EE51FE5FBBEBC4160080F1
-:104C0000000000001F8B080000000000000BB57DB5
-:104C10000B7854C5F5F8DCBD77379B6437D9900421
-:104C2000C2FB6EDE0921591E09A82837E16110D0A8
-:104C30000511505137E1FD4AE2A396AA9505621A83
-:104C4000296D8380528BBAD050FD5AB480B4828DC6
-:104C50007603D162AB36A0566DD52E101194C70ADB
-:104C6000948FFAC3F29F7366267BEFCDE681ED3F0A
-:104C7000FDEA30F7CE9DC779CF3967660921E40A8E
-:104C8000FD7F92A6B485EC04FFA09E4C747537FCA2
-:104C90005723A4373CA77F2A211365072123E977EF
-:104CA000132C811809DF4FC9A2EF1DEC1392944A0F
-:104CB0003C41783FD5E1F1D3F60E876F0A49206475
-:104CC0004382F6A6444BE2518E8672A12B955C4935
-:104CD0002724B120E4B7D0C789A3E973DD3CE89F5E
-:104CE000E475E2FC8E9AE677543FBFFEAA33E5787E
-:104CF0003CAD2844B922D3F1ECAD84D0D2E951CEF9
-:104D0000C13891FEFC4429A1E3F0792612FA9EF6FF
-:104D1000E396362A57E83A5CC425910C1CCFF4DDA3
-:104D20000017F60F75DAEF5EF8C73584F45BA6B6A8
-:104D3000D8E83ABD76C90560E843E7DA0A40505A38
-:104D40006D008CA71CA21EB49102DA6ECF215B8885
-:104D500096CB771EC2F716A8D332395E1DDF7F18B7
-:104D600021930359DEB43C68579166F160BD554903
-:104D700025A46E9A2FCD320CA69FD5D0328090E715
-:104D8000494DBE44DFDB6BDDAD07AF27005A3A1952
-:104D900078EF6ED50AE03DAF131224741DCFC7B56E
-:104DA000D7357B1AADA7B7D7FD506F04E05F0BE393
-:104DB000B95B6BE9F7BB54EF44958E3BED190B9152
-:104DC0005208197BC91190800E42BD08E90B9FD58E
-:104DD000C4015EAEC0DFD84809F025A99176E6F798
-:104DE000E676749EE53BE9FAA7F92ABCE347103260
-:104DF0004A627025AED088E94E9847E56CB538F226
-:104E0000DDB467CEC9E9747EB3294D11FA3CB1DC3B
-:104E100075532E9D5FE2160A2D15DAFBEE82796737
-:104E20003DE2B300798C25A1FB258A4FF2490ACED9
-:104E3000478C53F79A8CF45BF79825B01AE957958D
-:104E4000BC43F5F80B99F01766F8DB7B04F157D5F6
-:104E50007484E16FEFD666C07F5593E48A51613D5B
-:104E60009E5D9488C8FD816BBCCA408AD798701D2E
-:104E7000E0D54A4679A7C4225CEF85F574802B9F64
-:104E80005F77707DFEC4B61F17D2A6FE53164F166D
-:104E900089C04BB4DBACDA102E7DD27D8F021CAA08
-:104EA0003786EA62E9BC5E3D7138C147E79B75EA27
-:104EB0005CB090CE376B0CB271FBB8CF9FDAD66C7A
-:104EC000A3FF7C1EE898BEC826BED52E4757F060CB
-:104ED000F4DD0E8F3D47103E16A8D3E7BB6D64117D
-:104EE000E0B56CAFA40580BE63C83D5E5AAE572DD9
-:104EF000B88EEDAACC4B89E1F154BAA2D2EFCB66C1
-:104F000058B4002D137919597F2DB6DBAE2A580AF3
-:104F100078087C0A3A22A4217E1AC5635A8EEF597A
-:104F200023DD3C119F4EDF8F6D3B7A3FB144BEDBEA
-:104F3000BE9278E75923ED28FD3C6CF86EC2F7E28B
-:104F40007C0591F64097402766FCD0EF7630BC3E5A
-:104F5000110FEBD8D7764E0678F714AFE6E7AD2BF6
-:104F60007DDEF1D6CEF9C75B2A7B01AEE6E7418054
-:104F70002FC2C7EE6FCB05A92D91440A6AB9AF2F96
-:104F800008F35B6E0F25CCA0F8AD2A3D6F0338AC5B
-:104F90008E3F739D2F4A3F9DCDA3F5728EC34BD795
-:104FA000B7FF520CC2DBDCFE2B8ECF7757CEF68ECE
-:104FB000A704FA785C42210A5B3F793F93EA87F1C4
-:104FC0005CEE8ECF5C3285092DC5CFE5B8742586A1
-:104FD000A0425068BB09F084CEAF7CF42E85A44378
-:104FE0009DB613F2D88DFD6E2345800F6B1B3CB729
-:104FF000D3FF811E999C79D349D02FAD4A684D22A9
-:10500000057D6B9A84FAE7C6CB0D2DA0BB6E4CB321
-:105010001AF4DC24D5589F0C7A4F37CE348DE29D9C
-:10502000BF3F8FFF0DE0FA6E56296869FF3767C6EC
-:1050300005FC74C9B78CBEDD3B5EA72F0E7D2BDF50
-:10504000E32DE8089FD16E011F2FC2F595580A9FE6
-:10505000225867452DD3495DC3C30C47335CC67FD7
-:10506000B2600A29EC08979EAEBF1DAE84FC04D640
-:10507000375993C95A7704AE66F8D0BFA9D0EE501D
-:10508000296D27815D704AB1D0FAA46B2422EC828D
-:10509000097ABCF3F999E16A869FB03726F3EFDE0F
-:1050A0000678517A9A2C6F71003D4CFA61EBF864E6
-:1050B0002AC7260D64F825410A5CAAD76F20083359
-:1050C00080EB36A43B9715ED0CAAD7197D7C32F105
-:1050D000A444C79F7289BEA3F39CA84A01CA2200B8
-:1050E00097A326B81C35D1C551FDBACDF37D05FE79
-:1050F000714D147A511A7281EF8BDCDC3E1944D465
-:105100002B541F957C3C3291C987E87A72EC256F4D
-:105110007B3F0C1E0D483712F1B53F77D17E829A46
-:10512000358582818CB3BB904FC6116D4D9B1D4060
-:1051300021E33CC5BC4EA6793537FDBE944C5AD30D
-:10514000A687F327429F33788FE3F01B47FCCD728D
-:105150000294CA05FDBA457F93C47A0693C1600FD5
-:1051600035AB2AD3FBBC3FB1BEE4641294E804C360
-:10517000923DB04D82F913BFAD57643C2BC7EFC7CA
-:1051800099D36F75A3DCAA21002F305B009F65FCCB
-:105190007D99DD1184F910BBF5543B5EC086217307
-:1051A0005CC787205CC895F8C8FC2ADC92723C3743
-:1051B00032BFD307ED7E99D2B5A7AF6FBE9BCEF3BA
-:1051C00094F47621C08BDA65D920CFCDEFCF7FD490
-:1051D0005205EF69BB05D88EAF6BA92C21DD845F2A
-:1051E0008B096C734793E7AB98FCB5534BB42442DF
-:1051F000F765718CCF2713AF02F6E5FE58C6672D11
-:10520000B18B911F26929ADAA1B4BFBFC4DD78108A
-:10521000F86C12F163BB092E231D7647A73791F076
-:10522000DD60F74ECEB59AEC683FE2677F6C4E26A4
-:10523000E8B3FDB14C2E0BFBE149B7778D1BDF0FB7
-:105240000A805C3EAA15BF0B7AA2B274C4DF46D2B4
-:10525000D262F7DA009FF381BE285C47037DD16FED
-:10526000F743D77D91BED601FEE6D69BE8CB9E8C58
-:10527000FD7BA91883799569D66FF476753BDCB808
-:105280009EECCE5E242D0AC9A5709DC7E9747F6C83
-:105290008C1FECB8B2C7291F53F8CD25BE671B245D
-:1052A0009887D560BFCF8BB5A2BD37EFE7B1C8EF08
-:1052B000F4E32D3574C805F4F95ADA0FC95507E837
-:1052C000F53A69D07D0FF8B7AB488FF35CEC591B0A
-:1052D000EDA36F2FE8974A370A4FB2D97A4E4F970E
-:1052E000E6F13BEDD7F4DD7E89CC06BDBADFAA0E30
-:1052F000F0E8F4C76E37B39BCED9B3B658D23B872C
-:10530000D3027BB2A68C88D48FC7C6CE8E66278880
-:10531000FE045C23FB8B130D2D6322FB0BCBAA2F0A
-:105320004CFB8B2FFEABFDC5A1AD5FB4D6D2F934DB
-:10533000647AFF0EF446146F1EC07D13B71729A5BB
-:10534000E44DD3E1E1EF6E66CFF45E318E1CA3A491
-:10535000146327FED8E194DF15E2B70E87F6BE5539
-:10536000168A57653641FD43E50DDA99E6F57E9CD0
-:1053700059F6198C27F8B02C8ED239E5BBC72D6AA7
-:105380006303D8D37F96A96D49475F3117EDBC5BA6
-:10539000572CC6F2ECD1CBD9C0FF651CAEA7417F1C
-:1053A000835D1DCFF8A73A9EF1CB2B69BED340FF9A
-:1053B000AD9AEC1C49FB5BBA57F6C4E0F2C38360BC
-:1053C0007DB74E9553E1F931BB15F789FB9D0CCFA5
-:1053D000C78854BE13ECDE4331DE3DB45C9056EA20
-:1053E0004AD7D9830BD2C6639D9453C38ED2DF7D37
-:1053F0007646F7C7889BCDBB5EF26CA78FCED5BB38
-:1054000013810EF75B89C1EEB0A4337BD992CEE055
-:1054100058798932E108465F3574FC4A45B5819D6B
-:105420005F79C986CF611E487FB1C67EE2793FF1C0
-:10543000EDFD48E80CD81F6BEE4761CF391D9BF19D
-:10544000F0A87B5C22AC67419AE64A4779AF2A0014
-:105450009FB2912D1F81DCEB5ECEFB2590F3D5979B
-:10546000A5E060BAFE537BACB87F3BC5EDFFD37BB4
-:105470000EF4AEA4E5F25DEF25C03ED19DCEF075F1
-:105480005A694D80F92DFB1DB59B0B906C7BDF8914
-:10549000DFCF2D59CB86B1EBF5DFB5DF660CF062BF
-:1054A0003B3AC19288FD35CEEE0FC0FCF6AF926755
-:1054B00003DEA87E14F69704F270C21E598B2DEC01
-:1054C00068978D4AB7727E63787CC0C5C6E98C8FB9
-:1054D000CB2EC593808E8FCB145581F9975D4AC032
-:1054E000E7A74F6CDB7033A57B7F9A15F781747B40
-:1054F000D48276A1C4FAA56CDD9249C769E1EB7943
-:1055000063CFAD33AEA3FF7C13F40C6D333EE44B9D
-:10551000614C4D777125113B6B82CB680F9AED453D
-:10552000A1B7CA9BD6D7F62700F7C0ADD7011D9EFD
-:105530005008D061077BDA7E632776E37A84C7ABB5
-:105540007B7E89FBA53EE92AE3AB3DE727021D5799
-:1055500091E04CE8B76A8FEC0AD2D66F903D434099
-:105560007F08FDDEBEDFB97CC0EE01F91F2BBB5604
-:10557000C33AEDB739540AA7EBCE16A4A09EB35B8D
-:10558000CB41FE95C56639E6EAE8797F8A5C0E7400
-:10559000F0464A86F1B97DC310D073FB2C4C1EB582
-:1055A0001CBFC311C276B7A6A0BD26F4BBC93E1569
-:1055B000FEB0495972209ADD4BE42D1B63E9FBC90B
-:1055C000395622839D1E5A827ABF837EBFECC37DEB
-:1055D0008059CF0BB8534823BF74B04F237036D8CF
-:1055E000A98FA6533B6D08D2C050B03B8397372C90
-:1055F00085799E6D8A77AD46BF03B36BCEB62DD944
-:1056000030159EBF2DA31FE5EC6519F969FFEB4B23
-:105610000787747C4C3505E2E9E2B0AFCFFC81E24C
-:10562000E7E2E7711E3F3C56760E89B62F16FB2542
-:105630003A723F4B1ACEBF9F6534B21BEE4F6F8854
-:10564000EC4F37A6E3FE343C11D446DA962336A05D
-:105650008BD3D45487F9FA29F2B753B8DEA0856406
-:10566000976E3E2FA44BDCDFA13D0D72C54FCAFAE9
-:1056700053E3842C8AD34AAF03BB731A716DA3EB37
-:1056800079ED449964A5F531DBDD1E89D67783E198
-:105690000974FB3B39B09DC2613795C7BB69BF8BAD
-:1056A0005B1B6C6E3AAE7F0F9DD4285AA7880438D6
-:1056B0009CB0FA0725E9E8645606932B27ACBEE7B1
-:1056C000A09F131FC710D8079EF83C2EAABE1D9C92
-:1056D000C1F4ED1FB89EFB37A7F7E0A957DFEC47F1
-:1056E000E715BCE41A06705FF2C2D772051DE77AAF
-:1056F0006E974DD9D85A0BFE9B9BB78415903FDE11
-:10570000806B02A8DAE92F78ACA09766ECF05AC15A
-:105710000C9FB9A7C60AEF67EF6D7803EA770477A5
-:1057200062FD7CBAEF8F00971BEAC307805C321BD7
-:1057300088027C412E307BEB533E8FF44B9EFD89DB
-:1057400048D5A516A0F3F6F11F6955C0F4B9B9966E
-:105750008D4FFB7B0BF074434D781CE8B7412B5801
-:105760007F8348F3AA4435D2EFD8CBAD92DEAFF0B9
-:10577000EC438E454CEE32B80F7AB8DFD6B5C82769
-:10578000AE38D0F782AFCA1E766880EF8B3F880BA9
-:10579000C4B881CE98BD7DF1078E803F8ABD1DA122
-:1057A000B3600CA32F416FC4CEEA9A1DE8EDC12768
-:1057B0006BE2407EA478559B4F87C7B20D53F2DF52
-:1057C00082FE6363D07FD73EDE7A361EFD3E1FE841
-:1057D0005AE8B34AA007835F4AC803C617B48B00D0
-:1057E0008C2B4A22AD76117D9D04D3603E9F03DC55
-:1057F000E9778D36750E8CD71817E382F12AED59AB
-:1058000036905FED7E5070265239721DB73B5F3B7C
-:10581000B13F19F07E71D8AA41B03F085A7E81F29B
-:10582000AA3BBABB2D5DFB0FD3B7FE41B0BF12ED53
-:10583000F71D8F2B007DF9079077801F4FC56058AB
-:10584000AFF8AE7F06D3F7945F70FD824F525A894E
-:10585000B6B50041A5EDD6C1A337E70B51EEB6AA08
-:105860007EC667D44E01BE7306ED19C0CFFB32B0C1
-:105870009EE2250E0F7D5FBD37CB23AB28077A67ED
-:10588000A446E4C3F55C3EA4B486912F7BBA4FF8DE
-:1058900096C337A8ECE4FC45504E017F31391EEC2D
-:1058A000CFE490BF3FE005E406C74F5F89960B3910
-:1058B0009EC5BA53B85CB84EAC0BEC375A2FC960D2
-:1058C000F247BC1FC9E136412E480C45F1FFB4D365
-:1058D000DD8ABE04ECC9092BFA635992C1E6BBD834
-:1058E000BE1EFDAA8B53D6A33F35456BC072F1F89F
-:1058F000067C9EB6A502E963F166C9E01F15E5CFF7
-:10590000B87D76FA8405F51BB1C4F503FA13EF37B9
-:10591000723BA44FBAAF0CE07C72CF86270BD588C0
-:105920007FF8626CC3CD7700FD6F975DAB003F8D54
-:105930001324350A5DE9E107F0AA6EFCD744985FAD
-:105940001509D5817C569B24949FEA5E5AF6A1C422
-:10595000DFC8E4E9496EA72D8A33DA97B338DC4E05
-:10596000585B2717D1F183E73287835F27A88464C8
-:1059700085E18F007F801C7621BDAF1DF410D09192
-:10598000E444FB07E4EA2E1D7D2CDDB1B5AE1FFD1E
-:10599000E70D975DC364EC8738F4F25BD08990C75C
-:1059A000E6F52DE6781574785D444F2DCEE07E54F3
-:1059B0004059D5FA73E8477D94E3AF11E80DF8B983
-:1059C0005ED0DB300BCA5B131F8FFA1FC9F77D4F08
-:1059D0003C3D08FD13A329DF52BE3E097C1D852EE8
-:1059E000EADAE5806F5546147D7052F23D979C11BE
-:1059F000F97EDFF19BF22B75FDF8383C2E5A7D8342
-:105A00005D51E015812BE907F4B0886206E040B6ED
-:105A1000482EB00BC5FB942D2C1EF014E723F15C2F
-:105A2000D405BCC702BC3310DE4FC17CA95D600346
-:105A3000959D16607601B1DCD40FF4FCE238ED26BA
-:105A4000F4C7ACB710F02F11A90CE93DA571D3F143
-:105A50006F4742199B8EF1156A77031D2D7E5CC539
-:105A60007DE2EA5FC5225DBE98918EEB5ADD6865E6
-:105A7000F4696D40FA3AF9F992C1109FF153BD9E55
-:105A80001545EFD499F4F943194C8F0ABA4B5FC707
-:105A9000E8AE51D1E2927474F93CD18683DC167A77
-:105AA000A5337A8CD0916B98A0A30AFA3CBD3E2412
-:105AB00003BE281E5F053ACC58174679D6191E45F5
-:105AC0001C4EE053C8F9FFF0F98BF1DFE6723E851A
-:105AD000DB3B1DF1BACAC00FD747F8E12F0C3F11CD
-:105AE0007EB0AA91F5FC9EC3A533BEC8CF7461BF3A
-:105AF000759F6EB81BF8B96E7D9C673589C4734479
-:105B00009C55CCE3334E879DC56376A9BE4F334C7D
-:105B1000F14215E53D8BBF4CE076FA7DDB63D0BEEC
-:105B2000D807AF408EB4C505C0BE14DFE528445386
-:105B30008613F255861BE79F032284D65356D84816
-:105B4000261DF7E235CD2D09B4FDD470684A115DEC
-:105B5000E23E5B68C62DE01726DA12B033D0970F0D
-:105B6000F47F8AF54B5C3B0DF3FC1787B7C04FDD24
-:105B7000A773D3A2C50B041C3BC34B7E268F9FF19A
-:105B8000F766FE6F15FAAAC7FCEB4F04FEBD81F85D
-:105B90005741FC845C262ED0D3EDFC7B99B0F85C99
-:105BA000A6917F453D0AFF2666EAF9F75288F12F54
-:105BB000E7D3C446AB16CD6E19986965EB6A9C5065
-:105BC0000AFA28D14BD06F429789FCBE98F23BF07D
-:105BD000B11FF8B60FC093C9DF74ADE16E789FDED8
-:105BE000C8ECF18B496CBD8BAFD79A65E07FBA1FCB
-:105BF0009068D306CEEF9DC33D982831FD9608727C
-:105C0000E68631A171A08755881BF481F531FC8EA1
-:105C10001D4302418A77F53261F2E3F3A7EF7E0874
-:105C2000E4C67A87274B8DE8A54FD37DC332533B1B
-:105C3000E76B4A971AF8B1EEFBB783ED1F3B899FDC
-:105C40008F5D2123FD513ABF365307FFB1DEB00C03
-:105C5000704D8EF7A55993E83EB0316BBA7D205D4B
-:105C60009F9BDABDB45E4EEBEBC02FD72B4478FD83
-:105C70000947DFFF224F2033F330F8F1966768932E
-:105C8000328B31AE3D19E67343FFB08CF2AD87F134
-:105C9000FF6AF0EBD1F51CBD2DFF5715F469E5ED5A
-:105CA000DE3A782BFCCCA3B89FB9BA6918FA9F7575
-:105CB000FEE63B60BCCEFCCDDD8D9BC0F99ED237AD
-:105CC000EEFF12468765908F42AE2CCAECC5E939CB
-:105CD00044A60F8DF017C825B077451E02F8239D06
-:105CE00018CF0820FD413D717844DEAC6BB094477D
-:105CF000A3EFEF673AA2CA53D2F47FBF7FA884AE66
-:105D0000175E31F9FAFD4C9D7C6D6C38DA9BD9AF8A
-:105D100054FB537BE27EEE03D8B0DAF3D74CA0BB42
-:105D20007765F4C35C1363F34BE02FD088EAEACDC8
-:105D3000FB03B66B9282CE425AFF46221AF837BF57
-:105D400091B1DCF0A8B7DC0DFE968F2C287FABC09C
-:105D50007EA3F0193D9804ECF49F7BB9DFB4F4986E
-:105D600043833C81B3921DE5E7D923717ED0AB67B5
-:105D70009D16F4ABB7BC16837C713E338EFB41029B
-:105D8000067F8988F79C7F7B6E32C8FF2779FCF3FA
-:105D9000C958E68F7DF2F66CF4630A7FAFA250D843
-:105DA000F782B41E0AD75E6037F7473FACF0FFF6C4
-:105DB000B657482CE9888DA3D8D9FA7A2B3E09FC2E
-:105DC000E75BBBC997F84DA64DD8C38D00E7EA47FE
-:105DD0004236D8EF0A7B58E8EDC1A7D29B216F620B
-:105DE000703973AF6D3D65B1C03AB752724A727780
-:105DF000A42F41475B3BE625ECCAD4EBA7C7585E0E
-:105E0000427B9D7FF71CCF4B18DB76F465B0F328FF
-:105E1000BF6F357C372135CE17456ECD5CF1307EB6
-:105E2000DF19FDCFB4105F343DF21ED72344A9E93A
-:105E30000F7A8AFCF3C178358A3F67E6A795A900F7
-:105E400017B31F2E32FEA338FE3B99EDF1CE411061
-:105E50007FEB2EDE699EF7DFACBE81D1F494C0B338
-:105E600079BC8EDFB3FD597B3B1BF1ED72B07E87B1
-:105E7000EBFA55B2981D345362F17CF22D417D2D21
-:105E8000E884C2FD0BA08B92778E8D88C338505862
-:105E9000067970FEA3CC01188FEF643F2AE6432DEC
-:105EA000E7AC68791F743C6F343C48594C8FCEB4D2
-:105EB000B23886747B16FA0766C6C648313AFBE4E8
-:105EC00074BBBED50C71DBFDB1A346A2DFD3AA0E15
-:105ED00088063F733CF774264178025C3C51E849E0
-:105EE000C49D059CEB4AB55285F9D5C83650811A38
-:105EF00093A329E504E36FA3240DE1910C467331CC
-:105F0000D03FCBA73BFFB68C72A1A4540D4008959F
-:105F1000EA8BA4AC62CCCF7AD9A2CBCF127452F761
-:105F200022D5CB06BFA3DFB0AF4EE2F2985A8FDA8C
-:105F30002E5D3BF5119001117D30A0D66EA80F7A31
-:105F4000C045149DBE48D2D20CF5015E571CECA78B
-:105F50000694AB86EF04DD89FC40FC4B8175BB02E7
-:105F6000901FD18BCF6794E443BA01F9067EE561B7
-:105F70001C9F74BD4559B41C5B1E3AAFA71BB1DE14
-:105F8000EED67574259D0F15606D2BE97CA95C9884
-:105F9000BBCEBD2A0DE1EE22B0CF38BED28ECFE708
-:105FA000F3EF933656D4F5A54324D5AAE8CF4DD2C6
-:105FB0006ADEEC0BF99835B44EFFE6354812F87DF1
-:105FC000A89CC1EF9E59E9C252E0DB45DF4BF4BD0E
-:105FD000BF8CE4427CA7333DE6CD7218ECBE2EF4B4
-:105FE0009837ABB8A31EB3D83D6F417EC0F2265997
-:105FF00005BA5833A517FAFF36EC943CE08F3BD036
-:10600000C4F2F436CC64FA448C7BE67789A837CEA8
-:10601000488CCF494B12F2417512C74D6D12C66BB9
-:10602000CFF2FDF6B24C9F2F4B672F6D682A8EC5BD
-:10603000B8AD492FD13F9744BFC3D89D04F6D3B024
-:106040007A2503E5C022F89E2C088D88CD00BAF58C
-:10605000BD37460239706110E0D31C0F1471431133
-:106060004F7C25CD77AF7EFC8E7142637C4B4EB06A
-:10607000E7029F8D96E33CB251FF12C0EB1AB013BA
-:1060800029DDAD391287F059F32DE33F3ACF1F02D6
-:106090009C5B9C25484F42CFD27916BE4B3ACEB37B
-:1060A000DA12463FA26E9E7559C55DCDD39407CBDB
-:1060B000E7D50E7F1ED7929D0ACEFF2C89F3C03CF8
-:1060C000F7DA3C1FF9400F9F8943BF9FC04F15E788
-:1060D000B1B3141F129DE7D9BD23622D0EB08F7C82
-:1060E0004F02BCE481E104B0CF0F348DC883F57456
-:1060F00016DFDD9B59F67416F299EF19E43357E871
-:10610000FC4B6A64FD5DC485B742FBAB80CFAFBB7F
-:10611000C6A3113ED58AA35E628E75B4C3242EA792
-:10612000CD74273535FF1BF29228BF615EA87F1022
-:1061300009ACA170AB1BCAE88FCC232AEA65139D7A
-:106140002CCBF4BE0AF8127CDA057C5E8779DF93EB
-:10615000E90D4209F3E83F1CE5D2FE2CA6DF5EB64E
-:1061600059F07B96DF9244305FC71C77FF38B3F25B
-:106170002DFC5ED85FB93EC95570557C70B86BF880
-:1061800005912E9673382D877830E4B3EDB19E32A9
-:10619000E44D98E0F0FD4CEF270C0E94CE46323AD9
-:1061A0005B43BA844708DADF93E93B06A5D34AE9A3
-:1061B000058032BA220DE0BC4BD5303F61F72A068C
-:1061C0008FB3EF3078EC6BB3205D6F22F9C897C3C3
-:1061D0002DE7EE86FEA97C390DEB1A13DE29C1BE30
-:1061E000B9CF22D50272B97FD8235BBAA6DBAFB391
-:1061F00070FFE4BBC0F1703FE061C4DBCCAFD305FE
-:10620000DD5EE274DB53B84BD95DF27507BAB26656
-:10621000A746E8AAA7F958942E48FF5E1DFBA3FBEA
-:10622000288C3B34EF8B417955B55B42795EF5FAAA
-:1062300017B85FAF7A35068972FCABB1F8FEDC1E89
-:10624000F6FE4C69F43C8284EC5EA8A796EFBCD7BE
-:106250006BD4D37ED4473FD3CEB932E5485C367990
-:106260002A3BA7B086E73D89F86C02A7B3E4815EBC
-:106270000DF450F20482F984090E96A7D8F13C027D
-:10628000E3DB54FE9DCBA54A0067F3F904398EE5A4
-:106290001FA692755F039C92CB8DEF531DE518AF3F
-:1062A0004D359D6310F02ECEE6F6B38DA4811CD93A
-:1062B00069CAC710E5FE6C6E07D626E17E50E1F391
-:1062C0006A71DA906EEF73DA71DDF72591E429587F
-:1062D0005750FF9BFB1165926621AAFE9C45791CD5
-:1062E0005175F651AAB797A1DE67763F43FBBEBE54
-:1062F00074C3FBFE8BF20DEF07D60C37D407AFB893
-:10630000D6D0DE4D01A0AF67D4DF64689FD530DD05
-:1063100050CFD97C87A17D5EA0D2F07EC80B4B0CFC
-:10632000EF87EEBCCF502FDAFB90A1BDDC895DFE7C
-:10633000A36CB63F92855DEE1CE903BA929D762967
-:1063400046B7FFABE4F8284D284F83B879AD7362A8
-:106350001AEC4F5B92A83EEEC2EFF65DF76D7E81C0
-:106360007F6E7F9571BFDB99FD548A50FAAB3A403E
-:10637000E9A008ED2F7F36F72354A8D03E6C437D6B
-:10638000A278701D3313ECE84F33F75F99AD1AFC18
-:106390007C621F205B3CAE2952E7F01274D91DBC11
-:1063A000EA395CFF5B78FDCD946F24F67BE6EFFE67
-:1063B000986DE1F6B86F5BB67E5F47C2B217F775AE
-:1063C00017CEF809C85182764D75BC0BFD12663B9D
-:1063D000408CFF4A9AF7372057CDF2D4BB62016B4D
-:1063E00067A11B0CB9F3FDDE1FB3CDFBBD09B311D3
-:1063F0001F4936039C5E6CC7B366D8EFD52695E07F
-:106400007EAFD6AAA5F564BFF762364178D7035EA2
-:1064100075FB3AD9E6515D28E78DF64B47FB9CEAC0
-:106420003FBACE0D60D749609725337B7DB784EBAB
-:1064300016E37E07FBFCFDEC1ED8E731C453AFC862
-:1064400088BFBF67337BFCFE58F93BD9E3C7AE4634
-:106450001F1EB67A30CFFDF05499ACA2703C5F3E5F
-:10646000AA0F89228F45F93EF7DF6CCB2188B7EE62
-:10647000FC1F87572EEAF2BCC7E1492C8F733AD034
-:10648000916EDCD81C46171939DC7F13C3FC18A7A2
-:106490007FEFC47309A76FFA208138212F6EC4489B
-:1064A0003FE43913CF0390B7E37738D14F387D52AB
-:1064B000F1C8554E1D5D8D66701EF7CA3B09E0FFA1
-:1064C00099BE2B23D5EFE89C9E32F8FA8812CAC6F3
-:1064D000BCED3F9CECADD272FABEAC54E6A734E6FC
-:1064E000BB99FD46D3575419F878F925890492755C
-:1064F00075A515F30A975F52F0F9E96CA35FA953EC
-:1065000078F5109EE6E7029E87279D1C04FEF43373
-:10651000B1D1ED8F5B38BCDBE9C7744EA6B3F31F76
-:1065200025BCFFF3E5D7F4013937DDA666F5C4CF06
-:1065300025E0D47AF98B789013AFC3F99B28FD1727
-:10654000E5B0B8D2EBDAE7703C8294DAC3E380EED0
-:106550004BB93F3DCAB9807139E087B954FE3F3924
-:10656000173025C7782E202D478D7A2EA0BBF34DEE
-:10657000D36CD1F55D6E047E1F00BFDEFF8CD505A8
-:10658000F35A08B613F8EFB65AD17FF7DEE51802D2
-:10659000F1942FB6587F09796E8B9EC9786623AD2A
-:1065A0002F9A1483F19F855BAD2C3E37293600AEC0
-:1065B000AA455BBFD77B2E1DEF2BCAB7CBB2E8FB3A
-:1065C0006736615ECD7B6D6B31BFFB24F0337DBEE2
-:1065D000E8DB1FCD04F8EFB3350C190676FF0EC9C2
-:1065E000704E634963ACA12EF20805FE881439BFD2
-:1065F000A1527DF2608EF1BCD68848DCECC11CE66D
-:106600002FC13CFCAAA9ECBCD681E36CBFFF462697
-:10661000CB330C4E9A3565185DC7A4542BFA4BCC7E
-:1066200079898420D2C9029E373CE96305CFE54EC3
-:106630001AEA443BF0CD95358807FA9D6382EEBC9B
-:10664000C2A49F33BFCB2437CBABEF345FD194A729
-:1066500028CE0F75C84F8C9C1F3A1A8D6E36E4F009
-:106660003C45CED7078EB37CC4056FCB6C5DDDC8CF
-:10667000CDF7F93ADE6BCBBFEB250A8FF7CA991439
-:106680007FEFF28D8F81DFEB0BAF44203FF48BCB9C
-:10669000D1CFAD7DDEAE5F7DEDE77A003FB7962FBF
-:1066A0006EAF035BDEE6BDD770EEA7E7F2A66B79AF
-:1066B000322B87C521CCF2DD4CF7FFBFE4FBF44958
-:1066C0006F0CF23BB1FC1594A77631F968E673B311
-:1066D0003C17F332CF77F925D990BF9CCBE54044E6
-:1066E0009EDBF03D35F7713DFE1225B046423BE0A2
-:1066F000831CDA6EA423905C4A87A8756D8BEFCA61
-:106700007F43F7CF1F43FB3BDCBE4FA04CFE4BBF8C
-:1067100032D0F723DEDE89F987673BC9436F769B6A
-:10672000F2DA2463BCE0CB9CD266C8E77F50A5A513
-:10673000CEBE1E499990E73D7CC9F9F3A710B7ACCE
-:106740007AEB22F2E7269B2F0DFC03FE7E36CFF676
-:106750002879231772AEEE3CC316EE9F27B9B9868F
-:10676000781FF889306FE1681CFA89D6A669DFC006
-:106770007C9E4BD3FE0FCA2169DAE51C1D5E6AF9C7
-:106780003A154B74BBB83857D0BF17F5F8FC322A0E
-:106790007FA3D0A19ACBCE01943E79FB20F0C77D98
-:1067A0007EE48E41201F5B368DEA32DFED67C09FAD
-:1067B000547EFE18E47E56249EFA13CE37C2DF3D87
-:1067C000DFE6CDD6E769C9B949385EC235BB5BD3D0
-:1067D000299DB4AD93517EB739587EDB318752DEA7
-:1067E00058C0BE4B317CA7B0FD07D03DE563C5A1C5
-:1067F0007CA39747C5B90CAE9DADB33897ED136C2C
-:10680000C46387EF6D476FB2831E9525CDC5FCFF2E
-:106810008C1EAEA123003DFC88CBB19369BEA2DCE7
-:1068200062F88EE9DB6BB8BE551C26FD3AA0EBF88A
-:1068300078639A3632978E3F314D2B86FEF6DAFC1E
-:1068400043806FF6C645CF57BB2E97D923FFCEE1C5
-:10685000F4421C68BFE27832C6E96FC865717A0DF0
-:10686000CA1BFA87D7401E7AB3DBC5DB87F0DC1D75
-:106870007D3F01DE93B410B905F2E7E864E17CC422
-:106880001F4E1C2520BF12C26D04F269124C79B054
-:10689000A2FC0787DBAB3CEED991EFD83CBD1CFED8
-:1068A0008D945FE0BCA8E01788AF43BEC483AA8F75
-:1068B000F31DCBF7687CA297047196744DB5007DEB
-:1068C00040FE29C827737ED08E5C76FE1DF850EA04
-:1068D000820FE7F379F6940F1B9F98628985793EC2
-:1068E0004430AF8372C26A3BAD3F7B9FCB03E7C7A7
-:1068F00032D611DC070D5C11B70DF649351C1F832C
-:106900003792D5B1B4B59BE7F7897C6A776D48C1FA
-:1069100073060FB1FCBD939FDF243BA1FFAF45FF82
-:10692000C67C4191DFE7CFB518ECC2DBD27D0F23E7
-:106930003E4DF9D89DE7817D9907790E3F11FCCE38
-:10694000F370C6F03C9C318D9BD01F37A6F14645B5
-:10695000A24D9E558212ECF79EADD114D037CFE5F3
-:10696000B2BC9CEEF2E39EE6FDFB01CFA99DE75988
-:106970003ED92E773AE4593E999BAACB2BFB01CB0B
-:10698000B3FC7E2ED323CFF23C9A676B98BF6EC9BF
-:106990000B8750DE8B71443B918F37E001968FF768
-:1069A000AC128A05FAB9184BDAF3CC57A1533E342E
-:1069B0002CFAF90591576ECC271F1C0E97623E10DA
-:1069C00021784F42BF3CD5A007B7865D71C02FDD4F
-:1069D000E983DFE75E9D3E782A8FF14D14BDD9949F
-:1069E0007B757A33087443F5E60128AF5A6F727DE0
-:1069F00029F4A7787F88E373562ED39F51F4E621BC
-:106A00008E5783DE4C2101CCD320A72C1E7DBEA83F
-:106A100028BDBCDF97D3B50F61BE63B83F25E1D475
-:106A20005122E9E45019E76B71FFC4F3BDC83DD3AF
-:106A3000A2ACE37ACE9F963961BCAF22A1498A9A73
-:106A400087D6ECB689F8ED1730EF1B0653B92975D8
-:106A5000949B51F07106E6D9FF6DED0010C9B54960
-:106A60008DF1603E75818F73B968C768E7A114F036
-:106A70001F7EC5B88F14F0FF86C3C396A5FD1BC645
-:106A8000F913E7B3CEF0129BC7F0D12F8FD9332281
-:106A90007F7DB7C91E1D91C7E0322ACFC8973AFC47
-:106AA000C5E645B17B841C7E39DDEB80F7AF9ED80F
-:106AB0001D0F7424F024E48F195F113E5B85E352AF
-:106AC00038A7E6A576D43FE27BB31E8A7CEFC7F9F0
-:106AD0006E053A1AC9F27DF07C013FA720E627E84F
-:106AE000DCC3D779205D73E715779CA7EB9445EA63
-:106AF0006A9E49E11409F83F497361F98713160941
-:106B0000E6E50A2B982FEFE2FAD1AC07A9B8E074BA
-:106B1000C3FA798ACB8DBAD32C0FB1AED49706FEC7
-:106B2000FFDE59DAC83CE423AD18CABC2CAD04E63C
-:106B3000D9EC66788ECDD346435DE40B98E7A9E5A2
-:106B4000B5E71D8C857609E3891FF421DC370371D5
-:106B500096049EC790A0B9CA408F256C21982790B3
-:106B60001C1F6E8E81F8DF26E2817353D97ED50219
-:106B7000FBAF8C07B4D550D69DE6F7E694123C7770
-:106B8000D99E47579B8E7974C06F7A7A9DCEE73134
-:106B90003D8FF125B5436EC963F39A06A5B0430452
-:106BA0001F756657E8F87076DED5F1E13DD0FE2A14
-:106BB000F8706E1EE3C379793DE0C3A579ED7CB82A
-:106BC00004DA77C7870F71FE7BAA1B3EFC39A7CF7B
-:106BD000E7F23A95A30FE54595A38C1E04BD031F6C
-:106BE00082BE6FE0FD51F9B9321ABDF7802FEBF389
-:106BF0007A6017B6F7D743FAEFCCFE8BCFEFDAFE09
-:106C0000DB0279E3BAFD1EE597A7617E945F7E0102
-:106C100025E5972D8C5F54965F6EE2AF767D136607
-:106C20007202F2F3F4795ABFCB6BD737DB01CEE6B1
-:106C3000BC9C31267FFE3B9CBE9B7899103E4A400F
-:106C40002E50B8BDA4A7D7E739BFF847B3BC53AAA5
-:106C5000D9CAC0AEDC778ADA91003E2E0FC66C6EC0
-:106C60003D007623511AE2E11EACCEE0D42B5F1535
-:106C7000F99551E144C7FF633479DA04787374B449
-:106C8000E7CDF8DA91C7E83CC4E1F15DE721E00720
-:106C9000F328C279A896B53A3DFF41445EBD0F780E
-:106CA0001B3B3E2C139C57301EE227429E9201F460
-:106CB000FB911DBFFF24F2FD27B0DEB11AFDBE20FF
-:106CC000F27D12B8F233408E51798676B286E71C97
-:106CD000EBDC8C1ECC74DF6863E724DAF1D5D00FCF
-:106CE000F1E5557D5F42FF8D0A3B4FD258EF92D8B8
-:106CF000394196EFFB5E8686FC1A450E85AF520E33
-:106D00005DC843FB4CFB1794DDC9A1CB9CBFA91CFC
-:106D1000FA3F681FCAE95A0EC5E7337839F2997C01
-:106D2000E94C0E25F076BDF225839F522787E2F3CA
-:106D3000A3C8A107550687287C9A985F0CFE15CD3D
-:106D400095CFF834295FA7D7E877C9D09F17BE4FF2
-:106D5000C5BC33CCB7F093384FB47D869AEFE86961
-:106D60001EB59A9FDA31FF8C749347BDE1D1900D27
-:106D7000E02DF29CC4B8E6FC6981C7AAA65523C8D9
-:106D800050C8D3BA3C08ECCAB347BE41FFC8DECCFA
-:106D90004A0FACB3E5B55186BC2C31FE7DDC9F3685
-:106DA000412ED809FED973076DE8F79489FAD418F3
-:106DB0003A9FEA8356124039C5EE2910F130EBC1F3
-:106DC000BA56F0C75B89EEDE28DCCFA88940B7D67B
-:106DD00083ECFE2692C2DEFB897D15DEB738DA1819
-:106DE000E74FD28C71FEE4F25EA6B8BF31CEDF670A
-:106DF000B631CEDFD7678CF3F75F34DC14F737C6D4
-:106E0000F907AF2833C5FD8D71FE8CFAE9A6B8BF2E
-:106E100031CE9FB3D918E7CF0B18E3FC0BDF7AD93B
-:106E200006FBEA212FDC678AFF1BE3FD1420AD99E6
-:106E3000BAFB648AF6AE36B49F1762F7940D0BAEB8
-:106E4000357ED7C0EE39F0D3FF013CBF203E1BD0CA
-:106E50009942C26FF687FC9680E409D2668BF7EE02
-:106E60002A817238F78B2FDC6CBC1F6171C058FF10
-:106E7000EACFE507210FAC1A9888F653FD82140873
-:106E8000B83BC7FBD2178CDF0B3FEF52BE9E73DCC3
-:106E90002838B745C6F3CC663A59F8D6ADFC5E3112
-:106EA000AD15EE8F107010F4E2E2F422E625E0B1A9
-:106EB000545E867C2EE020EED7AA32ADBFC37AF7AF
-:106EC0006EC5EFCCEB36AF6353BE31CE473AF08997
-:106ED00083E509D175419C5CF6E79AF8C40887CE32
-:106EE000E0D753BE51391C62D28C7C13ABC699E9F2
-:106EF0000EF16D86677CAE919FCCF0747AFA45A551
-:106F00002F713F2AAE07E2217B25F2B4D411AE8B5C
-:106F10009AD6D7F58F424F840430CFC30CDFE67C7E
-:106F200063BC6597EA6B01F978FEA30B32E2D517D3
-:106F30001A01FAAC8BFCB383BC7D4FE3ED87F2758D
-:106F4000FE1173BCFD2CE449EACEAB48ED78D34C7E
-:106F5000799207FE0D7124FA8DCF067ED8728F9D2F
-:106F6000DD1766CE5FF3FD331FF5B046D00F788E88
-:106F700078D6D0FED6387F3FA41BBFC8B1FC62963E
-:106F80005F00FA6B6C3874FE25E85E6975C138D114
-:106F9000EE29359D3F3C0DDF77760FE4F3C49B4728
-:106FA000A2C4ADC5FE55D8ED749F74219FD9331787
-:106FB000A1BFF67D52BB7DDD753F228FACB352DAA7
-:106FC0002FA35E0D4B719E68F798C50E31EEFF75CD
-:106FD000E73D6387E8F468D5F7CEBF09F3A0F07604
-:106FE0000CA1F3743AA97D23F5C8BE71413F4FC58A
-:106FF00027205D87DF9203396EB8DF4A4DEC55D00C
-:10700000F19E2691575803F73025C3F3BCC4AEF266
-:107010002FCA4CF76099EF33AA1BCEE695CED7392D
-:1070200085DB5125BC2ECEA5097F5CF56CE66FDEB5
-:1070300064F263960C71627B6F665909ACBFCE2D0A
-:10704000A1FD5427498678D2F1FC527CEFE1FD97EF
-:1070500000EF15E3F93A9C578A691F7F8EB73F9777
-:10706000CFFA857BB180FE6CB21C159ED70D61F303
-:10707000FF3BB7A3BEC3FD34EFC78CEC783F8DF95F
-:10708000FEC489B9352D201ECC71DFDF75773FCD69
-:10709000FB13A3C67F01BEF1BD22743F6388F19E3E
-:1070A000C4609C6FC354F047BC237BB6E157AD234B
-:1070B000F4FBB48A21CC2E5DC7F72D1057C2FD0812
-:1070C0002FCD70AAE0706AC8F45600FD6DB2B5DE2F
-:1070D0000FF41BB4B1FB42C31F101CA7DF22AD1974
-:1070E000EAC55E15CF57D4B98903EE190A0FB3A0CC
-:1070F0005F24C5E71A0FF7FEA66C917A0138855C0C
-:10710000B02AC4EFA4F4B276881BF1B08EAC6986C5
-:107110007B5112B77C4DD2713FE11AEF0279348F67
-:1071200044F5733ECCE963DA33E90AECCB12EDD1D6
-:10713000EF79787888C863F33E04F431D67E6484AE
-:10714000847A82ED43606B8BFF69B318CE358BF286
-:10715000BD8C717EF84ED0F3F532A9D9E56074A6E6
-:10716000BF7F6DED90ABF34F172F2251FDA8DBF9D8
-:10717000BA72546F03C0BDF87D15E31F0B85DC9F09
-:10718000672170CFE9ED9C1C6FDFC2F2E1C9E52BEE
-:10719000576461C713EC9F403C62E1326700E21321
-:1071A0000B9BDC78FF1F592461DCA4BAE99017EA35
-:1071B0000B478E74A1BC8C9724B807124C08261F6D
-:1071C00015725CD09FCC8144FB9FCDF50DD52BEB88
-:1071D000E2E9BA166ED9DA0CE72CFE410D08C0FFC1
-:1071E000267E6EDEBC2E713F5DE4FEBC4F36E9EFBD
-:1071F000E7B6ACFAC707C6FBF3FEF1C17F737FDECB
-:10720000BEDFFCE303B89FDB7C7F9EE0FB8F64DF87
-:10721000470FD37FDF4695F28AE1502A640EE229B8
-:107220000DD73983AFD3FF0D918EDB2370B9ADE954
-:107230002D84F747563A1E651E6B19038DF5A14440
-:107240008C2F8B7CA499F68609A0D7CFDAC28570E3
-:107250005EECEC6B1F0E84BC834F7F78DE097908EF
-:10726000FF54C24E787EE291F79C1AC5EFA78FB00B
-:107270007BB6EEE6FA52C0ED1F9C1E0A0BBC87815E
-:107280001EEE59F96D89FEBE20B22215F5DCE280B2
-:107290008C292C428E2C7D211E2CB9F6FAF29DC928
-:1072A00086BAD07FCB63484D34BFA8AB80F1CDE226
-:1072B0001D5B6DFD5518DFD706E39F80C4694A3713
-:1072C00027F638D14E16F3A9DC31CC0676D53F9B94
-:1072D000624810F66B4AAB959D37D5A648945E7D03
-:1072E0009C2ECDF37CF3F578EC6FFE26266F2BE811
-:1072F000582B285C7D4DECBE4FF33AE67FAA4EEC4E
-:1073000043E13DFF716AC1A8ACFD23146FBE153F78
-:10731000C2FC71F33A2BFCE6FB3D3594F70B397E4A
-:10732000E7D61BDF2F6CFA31F6338FA8EB204F72B4
-:107330007E83F9FDA42F8048179AF2D16D055C1E5B
-:10734000979051208FF7DB3312A39D3B15E5A9954C
-:107350002E64A22F57DAB13CB192607978888A7096
-:107360005FD674E841A09FAABDBBF01EA696C0845C
-:10737000144AD6E4C6A6DBF1FEDA1B79DCFCAE8E3D
-:10738000F78BA6151443FE91E9BC375FF71C8E07F7
-:1073900071FE7B0EACB7109E2B17F4EB397730C320
-:1073A00001E3BAC5BA46D175C93D5F97588F589F5A
-:1073B00078BF9CCACFA8F1704EE787B9BC9ED7387A
-:1073C000ADAE1F05C59AD7BE40FF00E1FB92F6FBAC
-:1073D00091ED3F6E85798F27A67D899FBC4F74F410
-:1073E000B69068783FAC99AE049EA9DEC6EFED7CFE
-:1073F000DFD24E4F4D3F41B8087CC30D82FA7BA9C6
-:10740000285D19F609948E0CF5F90DC6FA196B680A
-:1074100010F0FB42D3EF459C31E5D388D25390CE98
-:10742000E0A06A13E1DCD07CE2AD6379C7ECDCE17B
-:1074300009A5E1CD87810F1B191FFC93E37F6781AD
-:107440007716E09F285A21DE17B9BAAF0C171F57DD
-:10745000AC935CC05F736B87E1FD43C38986FDDD40
-:10746000D589DDF910E7FFCA1A2BB15163A1928EBD
-:107470000172AE728F2CEEFB724CED0DF7D7303EE1
-:107480005AFEF82E5B5F5A2EAA59C8ECA100E31BE6
-:1074900071AFB6A03FA19F96AC6B46BF03DD6F19DD
-:1074A000F8AB1ACE8114021F9B9ED7DC8878A836D1
-:1074B000D945DF2BE0FB330FF1007DFA1E74DAE1D2
-:1074C0001C5977EB261DFD49E86F3A77300BEDE547
-:1074D00073AADA07DAF912D83DFE92E21B05CF292A
-:1074E000BC508F8657C5E3BDC6472EC944C5FB5562
-:1074F0007CA3E0BC7FE8EF0309BBAF8DD1AB586F35
-:10750000B57D1DEEA3AB4DF45A41376CE027AED8E4
-:107510009E8C796AB4FFC2BD605F6DB7A2FDE4279F
-:10752000F7A5C1BD1ADEC7D8BDBC957B93701F5FA0
-:1075300059CBE24B953B92F09C30DD47BF0FFE19D3
-:10754000818F23B5E36C7D115F6EBC2F8CECB5FA97
-:10755000F93DE748E7024F1DF7C1263CD537BF99F3
-:10756000A676DC17EBF0D4D6099E0CF758FE5AC865
-:10757000118E27F208973FF7BE910571B57335B1AB
-:107580001E39CAFEAAFD3EE379D7623E9DF03F96C2
-:10759000F713BFAFE0E90D783DBFAE18F166C657EF
-:1075A000F97FE6225EC8DF9D04FCD27765907BA65A
-:1075B000D3E7F7488C5FEE5A33A91CF4F9810266D1
-:1075C0001FFF95CA2D2D879043546E69546EBD4799
-:1075D000E519D43F589986F50F57AA587EBC321743
-:1075E000CB366E170A3EA2846003BBF2AD0266EF93
-:1075F000BC5520FCC10FA4816951FE9FF78A2DE084
-:10760000EAF5CF9F3981DA3BB768467D387B8651F2
-:10761000DF85ACAE89707ED9FF38BB17AED27B9DBB
-:10762000A13D5154DB34D8D7E78E883C477E536D5B
-:1076300070FEFEF629C986F633EBFB1BEA470A54B7
-:10764000764F507986E1F91D738618EA15FCDE5BEA
-:10765000A28E46BE7980E7C912329AE185E7DF5CE7
-:10766000A819D5E7FB74BE17DEB6E27B333E045E95
-:10767000E76D96898FF6377733955F748A6D0D14B1
-:107680004FF4BBAF3E72C2591952B763C4BBA36972
-:10769000FDC80E96AF7BA436F9A7603F1DD9919A1D
-:1076A000007E635F9DCCED0C17DEF726FA1D57BBFD
-:1076B0000AF3722A023178EEA2A2C5FFACA8C34F2A
-:1076C0002EA089077CF3BE1C084A883FE6F7F875B0
-:1076D0000CC62D4E50BBCE45F5C40989D4420907CE
-:1076E000C512E9FB7FB5A60680AFCBFF236B6940CF
-:1076F0004FBF8EE5712909FBFBF250D6B6B5485F46
-:10770000EACE20F26F0CEE8FE686D8FA8834BC3FC2
-:10771000E0FF4412D192E82496DFF7E1670AC5D36F
-:10772000E2ECD642B817678E3B983A8B7E77AAD1A7
-:10773000CAEEE9A7FDBA687DF96F62F8FD8F5A1F9E
-:10774000D86F44E019288475A7F6F3A60EA5FCF1BE
-:10775000E5824021CAB5475291AFCC706FB3F910A2
-:10776000BE7EE003292227237CC6E28D54B8F505AE
-:107770007933D7EAE90DFAAA6D9D95DD8FA76809DF
-:10778000ECFEC9DD48C76D8A3A11D6DD56EFC6FB5F
-:1077900083C4B895EB648DDD5F49E912DAAF977D5C
-:1077A00070DF8FD05BFE7AC907F70299E9E6FE7BAE
-:1077B00047619EBFD9FE15E519CAAB3E9D1DB1E4D8
-:1077C00035197FD7838C0C29330CF783B1DF3F2128
-:1077D000BED186FCDB65E97FFACC6141BB2611F6A0
-:1077E0004527DF9791CE4EA63794A465403ACDFE4B
-:1077F00092EFD3FA5753FDC7E11CF13D837D65003D
-:10780000D7A59675CF4A1638777DECA770CFEE973F
-:107810002F5A3D30EC925F2F1E8C71096E7F77944A
-:107820005B9AB0177AC33D5115AA0BF5B85A2B11C4
-:10783000B6FE00CEF34EB2F331C09B6B197B7EAC2B
-:10784000D8B916FC03734DE7D88EF17B3A660C6508
-:10785000F244E8FB0D4399DD34D7C2E89ABC2EB15F
-:107860007BB4F8EF5F087D20E4B590FBF38632FB34
-:1078700042C86B6A39A0DC5A00B747D1752E7B210C
-:1078800086F9D355E202382E6668225B873279B1D9
-:10789000C4F6E293C04B0B492BEAD32FAD8105AD63
-:1078A0006EF87E6B6D2FFCDEEA41FF32D72F70CD74
-:1078B0003FC8A5859CFF963748781F14E17A723E31
-:1078C000EF9FBC608DE88DF428FAC5A457E673BD20
-:1078D0003A9F98ECC006A3BEF3C6B3CDFE123A2E73
-:1078E000E8CFC8BCA8FD4C61B7C01778F3669CB759
-:1078F000E4094499C742120EC2BD58CB77307FBD10
-:10790000795EE675F4749E0B3CD3C6278DD48D6BDF
-:107910009AB780373AB8757810705FE067F05CD03E
-:10792000C4E21F9F737B4DC46BCCF85F48BC3743E8
-:107930003EE2C28D547EBA23F420E860F1AE00C668
-:1079400067BE220D090ECA07CB36EF9A798D0AFB66
-:10795000FC43B80F99D32B9865492224D97FE8C9F5
-:10796000F281DDC727FE577022FC7E71FC8EC26556
-:107970007E23BB3F5CD78EE7DDFB91AE17F9FD366A
-:10798000F0DF2EE2FED0EEE659ADB073FEDDCF970C
-:10799000C1F17F3DEF778776661F6545DD6FB5DB0B
-:1079A00045DDE8E34FACC181A08FC30315D4471771
-:1079B00014CF87A529A09FB370DFD099BC5DC0F517
-:1079C000F27CD0D3B43CBEF965BCE7E9F38D2F63FC
-:1079D0003CD8F6E2FC04B0978F6F9EFB53380771DA
-:1079E0007CC75CD4CB0B9F167AD967D3EBFB719B1A
-:1079F0002B9EFB21D0E90BB118C758D0E2E3F63833
-:107A0000DDD7805CA4E3A19ED8C8E4E042D05F0546
-:107A1000A8BF72A0DD830B7C3940EFBAE7A8D71E60
-:107A20009CEB1B85DF135790DDB3EA0A82FE12FA46
-:107A300055E8DD57FBFA2E0F053E92DFFEE0077496
-:107A4000FDA777CBE8D3592E6F1D04BF0FD3991C28
-:107A5000FFEEF0B6B4C3DBDD03785702BCD11E6283
-:107A6000F03E5ACFE07C6C1D837BDD8E8C04D80702
-:107A70001FADCF403BE8E88E2C84F7BCB514DE6820
-:107A800007AB463BA89EC21BEC7F80371DB7B245B3
-:107A9000E5F0F63078D7733DB48E95F33AC0D57FD4
-:107AA00037C895077F19E3C1FBBA6383A9B04F3983
-:107AB000B14B2690A7D16E27717B46C0F95FA4E138
-:107AC00059B0AB3AD837EB6308F87317FFCE89E7A4
-:107AD000A4BE944AFB00024E35FC2901C68B8CDF04
-:107AE0006ED7780A8B75764D0FF15345BC788EA111
-:107AF000AAE94F1F815D0FD72CC1BEBF4ADC8FB1F1
-:107B0000D7783F86A4824CC3F3B2763BD0C100F352
-:107B1000FD213EFCBD9C8B595FDF7D1FF273385BFE
-:107B2000EF57AF8E0B5AC11F15DE2521BE973F5070
-:107B30009A504A200E5783F3985AC8F4B3A469E8C0
-:107B4000678CA1741347C7F3C265C2F05C7531BF7F
-:107B5000E3163AAE33325FF3F39B4110817E7744F4
-:107B6000F753FF908FB35CB6E03E64998DED4744C8
-:107B70003ECC5D85CC6EB8AB90ED4BE616B27C93F7
-:107B8000B3903C45FB3D7B7D0CCFEF1E8FFE4F71CC
-:107B90003F8222E0E652CE187E674209E3EFC07CC6
-:107BA00076ED21BC7FF733F8168D6B8A8012B06BAF
-:107BB000D8F7EF5AD9BD2E778EFE13FA4D3F8BF5CD
-:107BC000AA607F7D966AF7001DF9E11E3C4A7F3F5F
-:107BD0008A63FE729292A8007FDDC1E5ED5D63626B
-:107BE00034D04B778EF991174A3A8E1F821675A5BD
-:107BF000071E033ABA27EDD8F7EC7449AB2CCC6ECC
-:107C000059D58B601E511135DFC16F4B5FEDB992B5
-:107C1000DC15DD18FDDCCBC09F7B2D6104351AE13E
-:107C200069A853B8627DC34BA5B3360E20E430512A
-:107C300087029E97014C800E2A12D12F700BF89567
-:107C40007B41A9207D4D5788DFC2CA7A07DEFBC180
-:107C5000FCCC37F375DE369A0413E9FA826F118390
-:107C60001F7E56D012CCA170BB45093603FC2C7682
-:107C7000D50AFB026FB9341CF6CBCB56F76CBEBFEE
-:107C80007A69CAAC8D6368DDC2F21CC23F90F09E77
-:107C9000963B2973035DDEAD90167938C31BD05D2A
-:107CA000752F761F79F85E89C79398FF5FE0651896
-:107CB000ED5E0FDF3BF9FC683FF509F0BD2DBA5FC3
-:107CC0006937A753616F2EE57CBA54D0D90E237F54
-:107CD0001E167C02F62D85DB9DBCEC8CCEFFCAFB0C
-:107CE000FF6B21F35FBD7695E32D8F2141FDEF56AC
-:107CF00089716FE1E53B85CC6E16F310F44BB85FEC
-:107D0000CA422506D0515BC31AB4971699FCC444E5
-:107D1000EFBF92A3D5DBE58EE50A94B6F03C988FD1
-:107D200074432CF2CB9DB69D59EC9E1963BBE50DB7
-:107D30008CFE973BEC68078AFBC5C53E40D88D8B0F
-:107D4000C1DE037BBF91D9B70AB7CB2BE87E0D8884
-:107D5000CE4A42B5FD61DF5CAFB37F519E717FCFEC
-:107D60009E613E18E74E871DE39F372F33DA4B564F
-:107D70006E475A3BFEFE9D31AF84DB4BE6BC129949
-:107D8000F3316DCBF6313CAF44E1F6B0A0A30F0B5D
-:107D9000ADDCAFE237C4F1E790562BBF778EF9F731
-:107DA000B89E9E203BF03E863912BB67EB6CA9D390
-:107DB0006FA172E9137ECFCDB91A76CE79CE0FD8E6
-:107DC00039DEBB121FBC19ECE239093605CA4FF87F
-:107DD000EF7D7DEA4A4F9C4540FEC83CEEF4935946
-:107DE00010BF59037294D59FD2C6A0178DD79FF8A4
-:107DF00010DECFB84CE78DF50DB3343ADED937F845
-:107E00007B3FAD437CE831C1C79B597D9378BF85EB
-:107E1000D51F17EFB7B2FA4F44FFBCBEDEF47E9514
-:107E2000E9FDCF597D70D1D6597EB0E379DC6ACEB9
-:107E3000B512C6AD34E0330ACF39AB83485F732C3B
-:107E4000FB5959468210B7ECAEDDE422AF06FA5A70
-:107E500076B639C15E99314CC37AFE505F7E11C54A
-:107E6000CF926992DF06F1CBF703D95C9F45CFC76C
-:107E7000E7FA699287F527EC5FDACF88A2E2ABEFE9
-:107E8000E7A3A20EFD8CF92EFD34769CCF84EFB2D1
-:107E9000AED861C67E843DB86DB8E6837991F1D7DE
-:107EA00019FC9C4B1FF524823D49DE65BFBBB574B0
-:107EB000F5CE412368FF4B5FDA376881CEFF5075FE
-:107EC00049261A95C3D597242CBF6AFED806F74BCE
-:107ED00054ED69B64D2C80DF0B6AB68DD3CD6B990E
-:107EE000C833262165BACE9E995F64E17CC57E7752
-:107EF00068E94B2731FEBCD4B2F3F8D3C097D73230
-:107F00003FA4797D53F9779F417E4194FDCAD222E7
-:107F100026879F1EA92D01B84D0198D1F6E3D644BE
-:107F2000CFD3D8C3FB9B13C7E4FBDC12A75D2D8224
-:107F300078B86F0D9CFF5BB0C53D1CFCDA5387968B
-:107F40003D50D4A57F38CCFCC34DCC3F3CA757EB6C
-:107F500003547991DFFE36F814DCFB3CF929D21E7C
-:107F60004F06BF2B1E8747BEFB70D6F831E8EFC324
-:107F7000FA1345879E82F3DF07F9EF31DC356A6833
-:107F80001CC885903BDEE2A2FC3CA3A0E2B780BF08
-:107F9000BB465D3F119E97C638B32B589C01E962E2
-:107FA0004681772DBC87F6E0DFF1D998BFCFF76720
-:107FB00019FD7DBEC2785FB4FC857A0E87DF16B1ED
-:107FC000F31B072D749EC323F310E35303ED815677
-:107FD000DA5FDBEABEC3E09CE5CE82D297909EF8E2
-:107FE000F83B0B7CBFD08F0F1409CF7B3A8FCD4568
-:107FF0004C9FBEC4F1E61D43E94D27F7A78F8F378D
-:10800000D4674C49269ADEEF3CA3BFA13E7B4E8647
-:10801000A1FD1DF38618DE4F8D691D597315767FFE
-:10802000B5D31907F9119F36FDEB6F77823DDB2839
-:10803000E3EF172D7E6DFBDFE0F7BCCED10527A364
-:108040007DAAA2FFEFCB83EC775889A229FA38D614
-:1080500069D2FA24C47D75F191A8F163111F59EA20
-:108060006AC13CCDFF368EF56E118F630D87D475D6
-:10807000D0471F0C823C952A075BD7E97D47F0F774
-:108080004C20CFE34A09C47F091A89D59756E1EFFE
-:10809000C88DE3BF275D5DC4E473D5807B15B8B799
-:1080A000A09A9620FF2752399548E9A4B5990CDD8E
-:1080B0000379DB6E27E6D52CBF742BFAF50FC6F9D2
-:1080C0000BEEA5ED96D64FC27AD5A578ECF7AF7238
-:1080D000EB44CCCF7F45C2F8C9D4FE77AD86F943D7
-:1080E000FBFBE978537F7B6339C0A96A0FCBBF994B
-:1080F0002A1F1E09FD2C6B9884DF4F95C94189DA30
-:10810000498997EEC47EA7828D43EB7289732DE86F
-:108110005DD916CCFE05C8159B13E54AF5A558FC9C
-:108120006EF238A69F2F16B17D8B35C4E635E1D2AD
-:10813000347C2FF07FB928DD709ED49ADAA8C07DF8
-:10814000ADD69084ED6FBA34044BB1CE3FE7FE124A
-:108150007F9FCC9A7A6122E4DFFE394572A1D9650E
-:1081600092BBE76B4625EAF7D3FF0F762BD097003B
-:10817000800000001F8B080000000000000BCD7D78
-:108180000B7854D5B5F03E73CEBC9299C9E4C9843E
-:108190002470024908106032791042209310109127
-:1081A000C000550906199047401E21BEE295FB67A5
-:1081B0004212088216B5BF45453A205AB4B6372256
-:1081C00056DA224E006DACFE366A1F786B6D502F6A
-:1081D00082458DE0B5F416E5AEB5F6D999394382FE
-:1081E000D0DEFEFF1F3EBE9D75F63EFBB1D6DAEB3C
-:1081F000B5D73EB978117ECA19BBA895E6F332F31C
-:10820000263276D37989790B18FB3ADF9BE04E66EC
-:108210006CD6861EC592C418B3599C4F66025C92F8
-:10822000AF2ECF0BBF271FA961EA18783FA9D7E867
-:10823000B5C1FB504EB185EB1731E6ED0098B11E8C
-:1082400065AE3DFCDCE53630968CCF9B192B827EEB
-:10825000FBDAFD8CB114C66E7632FED3088D52194E
-:10826000336AEDC5FBDD12D4C1BC022F98834FC227
-:10827000EF291EFF6837F4D35DC1E6EFC77E94EEA9
-:108280002173ECFF73F3AF9699454AA0757871DCC2
-:108290005925AAE15EE8CFDDB78E0095DFB68E0CDA
-:1082A000ADFDAF65D6D801F3F8757979B717FAEB5C
-:1082B000BCA7A04056C3E356B84D8417E6ECBDC03A
-:1082C0000A195B773856BD17D6590D3442B8F725D1
-:1082D00073704F263D67521296E63D12D4AF73F489
-:1082E000E6F860FC292F5B436C2CF4FBB25561303F
-:1082F000CE1B85FE0AA4E794974754490E98E421C3
-:10830000B3C2A0DD75E3BC9588B781E67B318A4FA7
-:108310004429D6CBAA261A583163B759F86BD3E64D
-:108320004881B838C6FCEDD73206735D7C7E1E638B
-:10833000C04F4BCEC712ECDFCE9F9FAB1F340DF169
-:10834000786E034C1AD6B1648334E600AC8BA97600
-:108350007736E0A13A6DE146E640BC1B68BDD5A387
-:10836000E3832DD0F4BA29F680218EE8D185F45824
-:108370007D3E9EFA5B733E93C6597B3E91E075E766
-:10838000AD542E393F9A9E0BFEF6217F437983C769
-:10839000BF1EF151DD72CD741CC7BF31B5D06F8BDC
-:1083A000E4179313F90AF8C5B53C821F5A3A815F66
-:1083B000ECC42F8A17F0EA8332925F6623FDF31034
-:1083C00013CE692930EF59AD99867B59B8FE4EA47A
-:1083D0007FD195F3FD2D1ABF2CB185B20DD09FB181
-:1083E000DEEADE08F33A9BA44E43BC346CE1F86B42
-:1083F00030FAA6D861DE0D8F486EA00CBBA5D86EF2
-:108400006180A7E2E3F5267F04BFD79C1FCB54C051
-:10841000C7BCF35954568FF1B722FD179FBF41A334
-:10842000D3582A995A62C0F9DC8E74557142259C42
-:10843000CEDAFCBEAC1F3FE82E18FFCB378C545F62
-:10844000E40DDC8CF33106CDEEDD309F5356BF8C4E
-:10845000F43D95C19C0FC1144F1959C009F4BA6578
-:1084600087CC02D0FF5228FD509E8A67DE780FE24B
-:1084700013D699CBFBBE08FFFF53D93E840D07BA34
-:1084800036FCFE7D6518632B73BAC786A0DFDA8AD7
-:1084900050F28DD0EF99BD467700C65DDDF976B11B
-:1084A00001EA3FC9F40E6232A06AB07F17D275D5D7
-:1084B000DCE04F8C00DF7ADFF38E096A189F1D4ADB
-:1084C000285B81F73B008F019857C736797A90F087
-:1084D000CF62E78C09F3B5E0E368FE5E757E38E1B4
-:1084E000E75CBD79CC01E45FE0577CBE46E3F35B1B
-:1084F00091EF890F39BF0B3E5EA37079B5C6161791
-:108500000CC03A8C3DBC5DF5BF01FF01CAD71ED837
-:108510007D7F29F2DD1985F87FB5B64FAAE5B9BE92
-:108520000ACEFFEE1678FE62930B9015E6FFA9E7E0
-:10853000E750BBB8F337517F82EFA3E579C4BE6142
-:108540000CDE7B31DFFF16E2A9F2477F7BFEDFE125
-:10855000D10C2594F358129676E29F7F96DCFFDDCE
-:1085600055F2FF31ADFD74335BE4CBE3723DB2BF36
-:10857000144FE5695CC7676E89CBDF7FB2BCFFEC47
-:108580002AE5FD1FAE50DE4BF95CDE47CB7706FDDA
-:10859000A17CFFFCA5914194FFEF33D007A8F70E13
-:1085A000C5AA4F6AF29FF4434C5CF072F2FFD1C24D
-:1085B0005BA4FCFEE5BF21FF1F90FF7FEF3E11FC97
-:1085C00018BD5FAEDBDA4D7A81BD283194BF62FF02
-:1085D00074C570BC748DE27A20BC6F24DA570CF637
-:1085E00055B614B96FF6DC5F8AFBE6F324770B1BF4
-:1085F00078DFDCA4ED93459A5E10FBE3D17C7F61CC
-:108600007EC4FE58BD3F5A3F5C9EBF6E4AAA67A813
-:108610001F164119C95FE63EFDA0DF1713F2AF6ECA
-:108620005F8CD0DA7F1B5FCDFCE7F3D5CC01F8AAD5
-:108630003A3FF9EFE7AB687E3A57FFFB4215E67326
-:10864000AE10F82833CC3FD7BDCEB8DD30DCEE7E9F
-:108650009245F0892923D882ED2EB27AC463B43CC6
-:10866000147CBB05EC009CA7A07B574C206F7DDEE3
-:108670003F4FFEDD997F7576EFD2FC2B931F9B91C8
-:10868000CED8EFFF9CBDF8607F74655E6E1784E9FD
-:10869000629E47765C08149C34305D8D3BF8FE1278
-:1086A000705B48117A3711F52EF0CB43FF08BF54A9
-:1086B0004F815F0723FCBBF9DE74E8EFBB1A1C781F
-:1086C000773ED2E7861251FFFB1DDE2C9433F06B10
-:1086D000298DE06516C2AF061F3F5E85FCFB505F2B
-:1086E0007D00EBA796C569EF332FBA1EA2FDFEFCF5
-:1086F000DF1EDF46FB793BDFBFFE1EC53726022E9D
-:1087000004D81E019744C13B797B87D2C39C848FD8
-:1087100020DFAFD0BFE4E1FCE38BB04B8092D3E22B
-:10872000D1AE3C2039EF05FA2F28FBDC84F40AAFE8
-:10873000BF87D6BFF690A4C11F1DF70269161CE0C3
-:10874000F0F1FC533B028AD61FE079B58666738749
-:10875000E495818EAB4BA4E0B0CC4BF17CBC4F3E9A
-:108760008979802AD6BFCF4C8557F73EEE6F7A7F46
-:1087700018BD1F325FC5F83796316FD07669BB538D
-:10878000A2DD058045FF80CB79B0BE60DEA5ED7B24
-:10879000B5F6DD068386AFAF7720FEBA4D029F1790
-:1087A0007678CB80FE8CC3FF957F617E208F4FDF74
-:1087B0001BB5FECBCDFFBD7CBDDD803FAAFEFDD04D
-:1087C000E5F0F7C125F8D3F8A74ECF4F718AEFD85F
-:1087D0003998475C92E444FB78ADCFBA0DFD803008
-:1087E0007F986B703DDD56D6C7CF7AFEB7D454C1A3
-:1087F000FAD632511FF308F93986BEF67C3FF4F100
-:1088000017F3E6023FA10980EF2779AC8F046C448F
-:108810001FAA2738EB32FBA1230A2E8BDA3F1AFF5F
-:10882000D3FE45390FF8C9EE47CE1478387E3E9511
-:10883000D87C9493DD95DC5EEC1EC6CB791E89EA6C
-:10884000277A381DA66865774C041ED2C374869FAC
-:1088500010FA2311EB263CD52469EB0E8CAC990958
-:10886000EBEE4EE0F5D5FBB31F099485E1E8FE661B
-:10887000EF1F59837CD3D77F60C4BB88D71A0D6F95
-:10888000F3F6E7BE1BE0F250C27DB9861804A87566
-:10889000400AC8B0EE35C817FDAC3BCD73C9BE0A5F
-:1088A00044BDEF355EE6FDCC4BDFF746BDCF8C49CE
-:1088B00057F3BE46B79951749D1E45D7AA28B8569E
-:1088C000C0419DFC137271C9C107DA52601EB7EE38
-:1088D0009350CD44F07309F1F3AD4EC1BF13DE45A3
-:1088E000791FE6E75282E776087E9DF808CAFF39CD
-:1088F000280F4BC3F03C94170497D578C745EA8BF3
-:1089000049547F63BB683F99E005ADA2BFF2475071
-:10891000BE0A3A02FA6A70BC9A42A12F2ADEC5F654
-:10892000AB0EF1F737792ADFBDEC7ED81E85979D17
-:10893000517020AAFDF7BE45BFB446BDBF21AA7E37
-:108940005B14BC230A6ED7BFBF78A944FB7031F01B
-:108950000312E2DBF6E5C39E3E3BB54F9F4A36B2BB
-:10896000DB74FBEABA160E073DB36BDA6D11F07ECD
-:108970005F8D266F695F1819FF01591B407D651CCB
-:10898000405EDE3F105FE646EB5B5EFF27FC351581
-:10899000ED60A6B30B8ECA7AB853D6E61DB8F9DDE2
-:1089A000DBF3F0A18017D6A07F70DDF7F5EB02BFF7
-:1089B00055ABBFA9A6AA2CC22E6137119F88758A14
-:1089C000F6D3BEBE28E3783FDDBFA0662FD4D756CE
-:1089D00086B2EBB14CE025E83519F5E63A2D2E3399
-:1089E000ED25D9877AAD362694DD106987B08E1CC7
-:1089F0005C67E73D32D127D002F4C1381B739B304E
-:108A0000AED21917D7F814B43F7A8FDC887AF4FD08
-:108A1000C6C4149C7F6A01B7238FC60D4D590670DA
-:108A200067EC22930AED3A374FA5F288ECDDD40BC0
-:108A30007BED379E5535B691581F47F8E9DEBFAC40
-:108A4000A619F6C13B1E95DEF72738530EA2FD7C12
-:108A5000AF913DA9E27CDCBB886FEE33E7A31FBD7D
-:108A6000B879740ADA934BFEF79C69A9D06E499BDA
-:108A7000D12D513B3616E7EDBF77AA09EB97B66AC1
-:108A800065E01A2A5FFEE6891607B4EF7D5C72EF97
-:108A900081F693BEEC787D2CC02BDA87BB913487AE
-:108AA000CF1B9813C6F960C788A00CFCF8A1B5FECF
-:108AB000D559BC3DC3F62B2EA86FCE2AC4F6B2738F
-:108AC00023B43F09CFD11E3EB945DE23E1BC1CF6DD
-:108AD00018099674F26BF54DB46BA1DEB9119E9F27
-:108AE0006C5B998276D649497548B0FE5E4F638DBE
-:108AF0000BF865C50EB346BFC6D4C5B0AF171BFA99
-:108B0000F885F4C7F2780EF7EEBFABE64998FFC9D7
-:108B100047463810CF6B0BBC5F78501F157ACF7A61
-:108B200092719E5C4FBDFC8DBC08EDF15F9C59922B
-:108B30008271BB0B1A1F1F3EBF24654984BDB3FC65
-:108B40005385E8FEB249BD1DE7F9724C8684F12CCD
-:108B5000A07B22C6BD976A7E26F06FE3F3FDD83D69
-:108B6000BFF7C844A78FCC8DEC43D8549D5BAF9F13
-:108B70006207BC74BE28111D96327F0BC2ECA0E4C4
-:108B800046FA45BFFF9BB195D682A248FEDF4272EE
-:108B900096FC0D80139FDF44FA906D800713A03C74
-:108BA0006A253FDDF8AC3568057C2E4DF24EC3F6E4
-:108BB000CCD59133D71EB14FB5F67F0CD8A9FD1F88
-:108BC000A13DFA7B7F0CFCC1CE6C97DAFD2B1CF625
-:108BD000001A1F1FDBED0AD2ED7DA5E9E4DDF0DE12
-:108BE000F2C78DA427963F9EBCA117D701FC95CD57
-:108BF0002E5D87BFC048F81D70DFB2EFD754E9FC87
-:108C000089872FBB6FC7143C5CB3376FE07DBB42D5
-:108C1000F36BA63D6EF4E1BE5B51645718E89BCA46
-:108C2000C75F7912F7C78AF5568F1926BEE27133EE
-:108C3000D1B7C76E0F38A1DEEFB02BF1504E2CE04C
-:108C4000FCB0B040A5728ACC148B87CA568CAF9EFC
-:108C500085F924027CBAF1A187C7C3389FB0E00D23
-:108C6000E3017F6791508097B307648A3F32C5ABB9
-:108C700054833CAD635C8EAC79ED795305FC5A5757
-:108C8000BF6226FA812B83C60F7A341FEFA2B64C3F
-:108C900094BFEBF823D0C3FAFA756CDB17F2586275
-:108CA0007B13EEDF351D51F5F5D77C8C719C754C2F
-:108CB000F9A047C479611EF30AEC49274703E06134
-:108CC0001EC0103B5B6FCC61B0C41536D887B0DED8
-:108CD000293B797C6745A31C3443FB29893C5EFC16
-:108CE0005113D07F04AD3BE00478C5F7B85E5AC19C
-:108CF000A4A0057EBD66E77A05F7CF2B1E8EA7C51B
-:108D000012F3E17EF8D0EA1E82FEFDF2C7AD84DFE9
-:108D100015BB56FEEE1178AFA7B93A29D29F5EA9CE
-:108D2000F105F4CF2C09E17E3E6EFED7212807A77E
-:108D3000FC00FC6258EF8A78F6939A4CA457EA102C
-:108D4000D5166EB762E33D39BC1DF8D5B0EEC55BF4
-:108D5000641EA77AC14C7A1264838BE4B886CFA5CF
-:108D6000ADAF994C7928D7B775CBD0FE0380651B82
-:108D7000E12BA0E1D184F85A84EFA6F2775CC59A82
-:108D80009DAE92DCF1E3FA6A0DD2A2B9A4077A4D46
-:108D90002807BE5FC0EDDE6D5AB97888FB668A434E
-:108DA000DF6F76A35CC31F59CC03FCB03586EEE5BC
-:108DB0001807663F35533C655DABD56B75909FE2F8
-:108DC000DD8FF3539862C2731795CB97EF6B7CB826
-:108DD0004E9D730DF20DD41F57A07E8D9DCBD135C6
-:108DE000F180776ED77A0D30CEE7F8DB70DE6FEA70
-:108DF000D888F125ED39F4A33AC2FD7619583BC65F
-:108E000065B0FDC8B188C7C41BE6E3FC7E2CD37EE9
-:108E100086C5DF5F8276E18FE502F487176F393A06
-:108E20006D07C2CFE53BB1CBC53F7987F4CCAD1A16
-:108E3000FD7BD03F40BD03F073507668FBC92FF334
-:108E40003851878627C107A27ECD16238FDFB799B9
-:108E5000C9EE59D3FC7BEA778DBD3B05E5F59A1742
-:108E60008CC528D79FD7E6BDA439A3EC38F0D5121E
-:108E7000639C538247AB03D52684576F97080EBF78
-:108E8000973C04F9F4CFAD2F3A907F3EB486B251AF
-:108E90007FF5AEB7BAF7E002B438DD9F5BB3F76099
-:108EA0003C67A9B3DB2E41FDD2DB8727A0BC7FDF67
-:108EB000193261FDFB1D990684BD4E6719C25E65BE
-:108EC0001CC17F0651D6A1F9ABC86F6B254EE7D503
-:108ED000CF1E350D83F18E17F0B8F9A73F7E270717
-:108EE000F5DB9A21DD39A887800F72D210CFCF48E9
-:108EF000A4BFD73E2B7BAD63C37CB016F900F6DD73
-:108F00002A8D0FD61E78F12EDC0F6B91FE9E4BF949
-:108F100008F8F4183DDFBF7B1AE3EF1F433E117AD8
-:108F20000FE05623C6DF4C1A0CE320FCAE864FA898
-:108F3000AFE2F581BC7A1E5733A19DBAEEA031D0C5
-:108F400013716E34109DBF2AD0CED19ACD2477BF35
-:108F5000D2D6DDB3E50507D2F1D31F1F7D15E3C5DA
-:108F60006BF6837657FBD9171A5ED6211E1CB40EFA
-:108F7000B247D6E1BA1D613CF4F1BFB61FD731BE8E
-:108F80004EB1EE758A860751AFBDFF176D9DAB9947
-:108F900086B70323F8FED3F61BEE6794AB627DFE23
-:108FA00004FEBEE0D3F442BE3E6321E7D7D5C0172E
-:108FB000EE3CE21FAF49C809A8FAF4B9DD142F123C
-:108FC000F412F31E5BA80A79E78D4F08D3B1C7C02E
-:108FD000EA3AFA89B3241772FC9D681B34E420E056
-:108FE000EDCFE097A1FD85FCAA448C27F8468C378D
-:108FF000E5477366E07AA1FF10F62FC67D3F10AB00
-:10900000603FEF33BE3F903F517E8A7D39A565E1D9
-:109010008C7C07B6FBD43E3C0FD7CBC71F5BE8A4C4
-:10902000F7BD682FC0FBDE8312C5AB4F687180139C
-:109030006D2F3A9644E0294F7B4FF019FE601C4B90
-:10904000CCB72B81C77FA3E72DE49098F794CD3759
-:10905000CEC0E762FE825F057F0A3C0A3E651B9236
-:10906000C9AE89E657E235A157659DBC27FD784D0D
-:10907000FA1726BFEDD2E7D1709FFDD4EA3A9615D4
-:10908000A1D73FC4380FCA93A7E520C913065C1BBC
-:10909000A17784BE6F5E7F8D13CF198DCF4A6E345A
-:1090A0007D22F4CC362542CFD415AECF417DF6607B
-:1090B000E1302EF793BCA7919EAB4F754F73A8611B
-:1090C000FB75D29721390EE36107323D917A75F530
-:1090D0009963B40FD6B0EE4DE87F2DDEF24EF578F1
-:1090E000E4F7A78D74EEB9B86DAA09FD81954FDE3E
-:1090F000528CFCF441FB7092EFA7F71615107F31EC
-:1091000067CA0DB00F96EE7DE88605F07CE941D97F
-:109110004D721EFAC1FDBBF88E0226D1BA7BAAF1B0
-:109120003CB5F76ED98976FFC4278B3660FB89F68C
-:10913000A1F1B80EEFDE4482BD4A1CE909612FBFE0
-:10914000AFC9CB1623E78F0DDABEBAADAFE4FC335F
-:10915000A5A52507CFE37B77839CC6736993DA11B6
-:10916000C2F15E1A447EC93A70A35C40FF5312B745
-:10917000CFEA4CCC92EAA1E7965478FE9AB1FB0E66
-:10918000D427AFDD61CF6FC609C8178A97707F9269
-:10919000E60176348D2FF026E6714F21D74FD1FDB1
-:1091A00089F7BBD0FF40B9AACDFF74EBD337A03EFF
-:1091B0003CBD2F3B01D7FDF14BD676B4AB3E3672AA
-:1091C000F9D867EF048D1F45DA6B60DFE960B0E71F
-:1091D0007430F0F1477AFB7023CDEBBE429BCE9EFC
-:1091E000137C5FBB3E3B2E320F21DA8E6759D1E7ED
-:1091F0003DE3E3583F724794679A0051C0A873D08B
-:10920000B68771AB62BF7EBE1BEDFEED66A719D6B9
-:10921000F911F23D9E67BD2007F1FC066D74DC0775
-:109220001F3D971F44FF73F97BFE69D8FFB10736D6
-:10923000539EC232B033074911F6F3F71EB801D975
-:10924000FFACDBBF2915DE3BBB8FE75540B52DCA10
-:109250006E7E3555FDC7EDE62BB597459CE2E7855B
-:109260009ADDEC666EC4B3C0AFF09F5E063E28F197
-:1092700084F1F559531DD9CB679AFC547E2E9DB8C5
-:109280007F22F2AF3DCEBD075EFBC5C187E434A4AB
-:10929000F381FC0BE82F97DAE29CB86F3F6B6AA46E
-:1092A00043CB334DF5540A3A8B38DDA4039DF4DEED
-:1092B00067070B0E4D84F70EDBE2B81EB8E49C88FE
-:1092C000D3333A8FE4B6F5E307E173B1AE4FEEE680
-:1092D0007415F3FE64DF2D0E5C57E7638987262043
-:1092E0003D63E39C68F7ADD0F2474EEEE076F5299A
-:1092F0004BDC533331EF64E7BC1406F27659E77761
-:109300006EC0E7CB5F929CE80FB85F9AE3C078EB42
-:109310007F283D0E2796F05E08E7A304659447A5D5
-:10932000D3199D63958614A666D2D130F1CB8433D0
-:109330004A10F34EFE8CE75B1847B910437114A630
-:109340009D5B2DFB198FBFF4F9B99A9F37515B775D
-:109350004A5102E76FEDF99412FEFCE39DCFCFC2B4
-:10936000FE4EEF353A71DE9FED3552FFABC03F3315
-:10937000C07C4FEDE37ECFAA0E89FCE5D3FB406FA6
-:10938000C3BAD6AC377A4D7197F2E114A8EFB18524
-:10939000F970953748FCCD347EB4C0BF8BC32EE541
-:1093A000C778D6B109F1F18FF2A5AD48EFC7F5F155
-:1093B000E3407CA0E10BF731F2A3A0F72AA00B9EBB
-:1093C000CF2674E457205F09FA0B3911A864B9A8B5
-:1093D0005F5B4C2C17F37802861837EEEF3936D5E1
-:1093E00028011EE625F554A138BDBB88CB49798AF2
-:1093F000C16B40FDD2622639102D47B28BB8BDF447
-:109400002CF234FCAF2872723B8AD5933F224AD0AB
-:109410003B19A8C7E7C426FCA70A4D3C2F7C7F81D7
-:1094200002F39F3331E18EE16EE09B171E5FA000D7
-:10943000FFCE2948786118C065453B393C2EA1C84C
-:10944000087073F3AE055500D71479DD45C9E17195
-:1094500044BFF0BC009FFF7CB4BF18CB75261BC96E
-:10946000E9CFA5DEB18D99E1F66F49ECFD5F48616A
-:10947000B8C7C886A09D57D137FFFECB8D45DE7299
-:109480003EAEFEF912C6DA28FF2EF0CBE312F7C784
-:109490007C9614CA6323BE5A62B185C8AF6F379EEB
-:1094A000E9A337F2913B4E41BACED2F868B612EA40
-:1094B000C4F747B256E7490B99523B2F260E2CBFF3
-:1094C00061E3B193A23FE097CF8DB05EE06B09D826
-:1094D000B311B68C0448AE05F9251DFAE55FB1DF7E
-:1094E0009600EBB1121D6A9DC86712F31B2E42B99C
-:1094F00026D63116E3276B62870491EF1B5EF8F4E2
-:1095000018B2D74A61BFF84B88DF6F77F2F5307F2A
-:1095100029F1E31D1A3F7EDCC4EAB360EBCDEEEE29
-:1095200076A830E933B34239B8DFFF34C45F5784DB
-:10953000FEFECE96F406E09F4FF79BDD33A1FDA91A
-:10954000E0F314BF5BADD9A56C6FB2B6EFE550394F
-:10955000B4EBCA1CB907F54B4311D7D76732434365
-:10956000EE41B991C9FD2068477972D3375E938C7B
-:10957000EDCE3CB7396B19D0CFACB0803D814AE617
-:1095800080755F0B7D97006C0458A673E020D10BAB
-:10959000DB3950DFABB7B8789C9EF950AE087A093A
-:1095A0003A5C421F9802DAAD060B33E2FC47B29DEB
-:1095B000CE93B1613A7D6C013C621CCD027884FD92
-:1095C0003D15830F85884F1E7769907A5A1311FED7
-:1095D000B144797797EAC1274D88F2BA9DB790FCDC
-:1095E000117247857FFDC99DAB8E1FED9CD2AFDC0C
-:1095F000790CE50EAC83E5B3FC8BDC4024FAAED0ED
-:10960000DE9D2AD7AA0ACE3BD9E2C6B85AC3E3C325
-:1096100049DFB00BBF217F58B4633B13895F3665C8
-:10962000CA84F79507259E1F79308DA95035F360C0
-:1096300022958EF3A9F4FCF453AF1772B9C4E95222
-:10964000FDC3419594AFFAC311548A7934687C37CD
-:1096500055CEEB08A11D61837900DCF01AD75B0DB4
-:10966000D7CB14DF6428A2539098FCC7676BA73848
-:10967000908FF5D9F9D245B2DFD538A48BAF4B66C0
-:10968000C83FE07504389E2DCD8867B3CBC0D47E2B
-:10969000EC0FB34627AB1AC3D408FF43098CFC6E0A
-:1096A00019C665BF637407A1BEC5EAD883FB8905E7
-:1096B000BCDDE847CCD7DEEBB672FE88CD4DD0BD21
-:1096C000BFD931AD0BF96DBE97EB1DBB7BB06E7C86
-:1096D000B3BCDA884CC6FCDC5E14FC407C09E3CEEB
-:1096E000F649A45FAF9F0FF511FD1ACBBE20396E6E
-:1096F0002CD3DB99669FBEDD1F84DE19C94646D296
-:109700003F8C779B17EDF4B35E3BF13168F7EF9731
-:10971000017C439791E17ACD317C5D671153181F2D
-:10972000F5CA418C9B6C463CC0F3B8123D3EE3BD8C
-:109730007AFC254ED7E323D9A75FFFA0F9C374F5C0
-:10974000A9FE51BAFAB43A8F0ECEA82FD5B51FDABA
-:1097500058A98333033374ED87B7CFD5C1D9DB174D
-:10976000E8DA8FD8B144573F32B84A573F7A5F831F
-:109770000E1ED3F12FBAF6E30E6ED4D5E787EED5E1
-:10978000D517743DA8838BBA1FD5B51F7F7C8FAECC
-:109790007E42CF33BAFA89A7F6EBE049BD3FD7B591
-:1097A0002F3F7F440757B0D775EDA758DED1C1537F
-:1097B0009D7FD0B5BFC6F5A1AEFE5AF5CFBAFAEB84
-:1097C00072CFE9F93586CBBF6AF7DF74EF7D9EE68D
-:1097D0001F558C3A533EA320DFB62C945822C6D591
-:1097E000BBE659500EE4156B7248E3C3E1453C2ECD
-:1097F000C1B2D810946753E5990CE376673BB87F04
-:109800003D90BE8B0375A5448C1BEFB58003198674
-:1098100013A73B7570B2CFA56B3F68BEAAAB4FF5DF
-:10982000E7EAEAD3EADC3A38A3BE44D77E68A35716
-:10983000076706A6EBDA0F6FF7E9E0ECEDF375EDDD
-:1098400047ECF0EBEA4706EB74F5A3F7D5EBE03114
-:109850001D8DBAF6E30E0674F5F9A1765D7D41D74C
-:10986000761D5CD4BD43D77EFCF1A0AE7E42CF3ED8
-:109870005DFDC4531D3A7852EF415DFBF2F3211DAB
-:109880005CC15ED3B59F62794B074F75BEAB6B7FF2
-:109890008DEB84AEFE5AF5B4AE7EF59FDD213A071E
-:1098A000F8053F57BB2EF70B5DBD3109EC5A8C43D1
-:1098B000B218379E5F0AFBA7DAFD575DBFF7160F98
-:1098C00023FB0278A9C72AA37DE4A3F85102261638
-:1098D000025FC6811043BE4257A196E25049A4EFF1
-:1098E0004835A99827047602000986CC4CB4A763B2
-:1098F000C3765BFAC5822BB7DB76409F388F5F1645
-:10990000FBEF2B4E467FE5B96968B7AF64814D38F0
-:109910000FD07B713DB03FDEB4EAE319A2BCD602A2
-:10992000F88918EF35EBF674CF65FCFE6B2D67A850
-:109930007D5FBF5A9C4382F53544F47F3FF8150A9A
-:10994000D875DB9B60FF80C3F8609393E0EF35B977
-:10995000087EB849A57247532E958F36B9A97E6700
-:109960005309C1BB9ABC04079BA653B9A7C947CFEB
-:10997000F736CD27F829F0A3B1DC077E3596CF80E6
-:109980007F8CF5CF82BF8CF04F9A02547634B5D3DA
-:10999000F3FD4DDB093ED0B483E09F3605A93CD8EA
-:1099A000B48FCA9F377550FDA1A683041F6E0A119C
-:1099B0001C6AEA22F8485337C1C79A8E13FC6A53CF
-:1099C0000F955D4DA7A8FC55532FD5BFD1749EE0D0
-:1099D000335ADCF6956249776F4AC08C55113F08BF
-:1099E000FB7016DAF9C81C25C6CF74767E94BD1DAF
-:1099F0004D8F4FB4718C95602E62FC7070CE9E9628
-:109A0000083FEB2D6DBCCD312C6005F9D66CE07EA6
-:109A10006D7302A33C6EA6D9AF2B34BE6449DC6ED5
-:109A20005DAECD6B85C6FF45C89FB9C49F6F5C8D89
-:109A30005F21FCC65163FC27883F330C01F29F6D08
-:109A4000C11CB49FABC7F83F42B97EB67ED9AB34D8
-:109A50009ED34DE78FD5E650F28D181F794DA6782D
-:109A6000DE40E3ADD3F2CD07AC3F7C3A1DEDEDE92E
-:109A7000DFC87EC4D39B46FB7C8C17FCA598FBA754
-:109A80007F2936E8CA77C6F8BFC2797E65AFBFD9ED
-:109A900000F3FF6AF2FAA76ECB0CFBD3B3D1250516
-:109AA0003F680E538D94D7C8BCAF644257D78381AB
-:109AB00085F08D2C40E577F2FC17715D35608823C9
-:109AC000EC2F350FE96F5DD1F38A19CFE71533DE3F
-:109AD000A02BA5B17EEBF8229C9797E6F5E6846B68
-:109AE00072705D625E956355ED3E44EF2E9CDF57CC
-:109AF0002F7D71521A1EC6BFF0DB375568F928EB6F
-:109B0000251E9713F69A96CF22FC8EDA3BA420DA14
-:109B1000EB0BC1DFC173A6F734FBF33D2BD7CF6747
-:109B2000EB8D24276BA518379EC79DADFF0F1BB289
-:109B300035B467785ED282894250DFF2AF12F159B4
-:109B40002DF463807E8AC666D27A6A99C58BFAB88C
-:109B5000F6907937F26B2D987FE867019FE48C4788
-:109B60003E9920074C6007BF6908E648742EBDCCBB
-:109B700024C1FC5624017F0C1B980FD66AF719C428
-:109B800073E02F37F6F7D9CFC6E7521CFFF0041564
-:109B9000F1D562E0F79802BF92DD3C3F868B687991
-:109BA000E2188A4F32C5EDC6F852B576EFA5536676
-:109BB0008DCFF5233FE78EE7FBEB4D97717A90FA57
-:109BC000D59FD7CC18CFFDD0195ABBEA23AF65E09B
-:109BD000BDADB55D46F24358614F9ECFDECF7A1AD8
-:109BE000B7DE9915C1D7EB0E9EE0F91AAC272F32DC
-:109BF0009FFD56AD5FC147B2C9EEDF6D8B9C1F1F45
-:109C00001FF87A0EE2E1AB78E0EBE1C4D727D1CEC2
-:109C10009E6556E36E84B207501482D2FF0327E597
-:109C200027893CA5A5CC47E50A6003E4635FE00112
-:109C300013E27F15EBA0E76B4B6E1982F03AD65B0F
-:109C4000E5423FA2BDF91517CC72DEF607A6625CAD
-:109C5000766E70F12B58CED92B9D44BF15F6C512E8
-:109C6000E4E31EA9BE6D308CB7E0D98AB634783EE5
-:109C70004BE6F460AF737A00BF78E5844BD709FBFD
-:109C80006015ED83782FAD43764CD7ED83DA8DCC1C
-:109C90002B2585F3EDFBF645C9AD7F4A433F48E9E7
-:109CA000A5F3F77587CD0948E7558CEBEDB01D2876
-:109CB000F435B7036E053B00DB7DA2F1F327198C69
-:109CC000EE357C228163E709DB916C88DFE5191EA4
-:109CD000D6BB9F1882C58EE1A4979B71BEAFBAE632
-:109CE000A9182FBB35C9E296B13E3E38849FA3F632
-:109CF000C9777631361CEFBADFC8E34FD1F3924A09
-:109D00005EFD2BDA0D66130BE0B906EC6B568CFB8F
-:109D100079B089F6590BA216E366953EB5BFFE5B96
-:109D2000B57EBBBEE6FE6F00D683F77C2E19C7A9B1
-:109D30008D13C3C711FA03C723F991C274E3ED1958
-:109D4000CFF7F59B762FCDBFD9104FF2E60F43FD2D
-:109D5000BB91EF44DC47F8855D991F6791FF7EA1B9
-:109D6000251DED73E05F9EC73899CBA5378D6A003E
-:109D7000E1372B3229EE2FE4EDEC121E279B2DE26A
-:109D800062655171B1A8780C2BEB3F4EC698DB8809
-:109D9000E38E64EF09FC501CE6489942740F00DD25
-:109DA00031CE7C44F34F2B62B95F9E509248EB4C0E
-:109DB000B8368BF8CD91C842740E659789DF8EB2A4
-:109DC0007C5B42849CB8578BAF6E033B8845C4D5FF
-:109DD000EF2D6CB060BEC1661BBFFF785F654C5D48
-:109DE000647E7CE2649EFFF2C3C915AC04F0976701
-:109DF0000B5692BAF62A2AAE47D2D637DA09F83786
-:109E000060D73E2D4EEAB6F0B85415E96B41F72BFA
-:109E1000D5D7CF28C18D31B8FE2446FBD0BEC34A6A
-:109E2000F254EEF08630557BD9E4B9EF223F33C5CA
-:109E3000978BE37416C7301BB4FFAAD344FEFD61B1
-:109E4000C3921F9870FFBD6B6678DED9614F535087
-:109E50005F747C3DAA8A4AFBC4698CC739630D20B4
-:109E600028F29DEC897F43A269F7D54CAEA3933EBF
-:109E700002147748AC8B51DCCD1B6B009FACC3C088
-:109E8000CE95C3FCF6DB3C0F8D2316F4C9B8DEA1DA
-:109E900093FC9F227F15B37A82EF33F9EA76C3F8F9
-:109EA000F72558886F3CA906BA3FC8FE6AA3BC1FB5
-:109EB0005F97624415F76299FFDCF808BBCCE73284
-:109EC0001831FFA7CD04F23B0FE32831FCCC8A7197
-:109ED0007BDF773E87E6F78D264F5B5DDE6EBC88C5
-:109EE00032205E9D4A6F5FDC84F8329DE27D02CFB6
-:109EF00091F47416EBE8E93746D2B304E8392692B8
-:109F00009E5EE96AE8F90E26A1155DCAC7814AF589
-:109F100081AA42AEFF30952E9A8F2BCC936C980776
-:109F2000D3E9900D48D7CE98B43C8CDB093E167C23
-:109F3000DD0F3FAF3F8A72255D71E279B2B93A8693
-:109F4000CE67047F0BBE9E5EDAC7DF8F95023E1799
-:109F5000DA7C5351F644F337C6CF22F9B876407E07
-:109F600067CEC87D3E0BEC8DB804B4934EEDED8802
-:109F7000E0E3DAFA2F142E772E96C71487E37DB329
-:109F8000CA24F64124BDE1FF07B9DAFAC84E52C827
-:109F90003F1378BD52FC1BBFD39C8B76DF26BCFFE2
-:109FA00008F86A97DCDE411807AB3F711B3E6FD3A0
-:109FB000EE2507F24CDC1ED3F695E86FD9E4CA69AA
-:109FC000B8FFEDE3CFC42E87765FA51854444E9BAF
-:109FD000BAE4DF689F1E8F65F89E23B1BBEE09DAF5
-:109FE0007723189E277EB5D23F14CFF7B7009D3E4A
-:109FF000A0A4EDE020039D7DF50CC27D07C875F19E
-:10A00000D2EFE2CF99561F24F80F138669E78C5ED2
-:10A01000AD7D0FB5DF62DA6E89C171322DCE3D1193
-:10A02000FC5FAEC5E35B4BC4FD9F1615F3DF5A4BD7
-:10A03000B83DFB50D3BE491F65E37C3A267D04F34F
-:10A04000499C19647EE0EB98DC808AA923966FA670
-:10A050004878CF818D621D18A7C7E7CD63C2FDAFD9
-:10A06000D4FAB5A09D03F4B36C0CA89172D662909B
-:10A07000FCFDE5C9FC718242FBD5B29151BDE5C83A
-:10A0800023F4FD80C42CB784F9D5968DDB199EDFAF
-:10A090005843FC795296575A1AD16FD24C9877048C
-:10A0A0005F007F05E2402E59F6006316221D6228EC
-:10A0B0005E193DEEACE4CA2EC531309F44F31BD38C
-:10A0C000F84DF08D5827DD8089F80E40D5300BE92A
-:10A0D000C9B646D36EB4CF7795C4135EBE4CAA8C76
-:10A0E00063FDD8A7A2DC057C1030A33F6DA1720FE1
-:10A0F000F8E38111E84FBB087E0AFC712CF7813F21
-:10A100008EE533E08F63FDB3E08F23FC13F0C711BE
-:10A11000EE007F1CE1FDE08F237C00FC71847F0A50
-:10A12000FE389607C11FC7F2E7E08F63FD21F0C735
-:10A13000112E37037FE07A7203AEB940D7F6BB4DDC
-:10A140005ECC33FC6D0997A747BDC312DD407F6B22
-:10A15000AE8162E5D6371E64B81EABCB40F7CC3675
-:10A16000B91E64B7A09F5B6C277BABEDC7DC8EB1DB
-:10A170002A0F31943BBBA4401D73C3782537D5E229
-:10A18000B960966B7D6502C0474A16EFB4C0FEC841
-:10A1900051E7CC6F8E8055BB67D573CE303C346FA2
-:10A1A000B7029E0CFBE5C15B76E215239C07E61720
-:10A1B000BF55B2BC16F3EA43C318D923BD9926CACA
-:10A1C000E3598AF4CAC6F9F373C0EB588B0BCF3945
-:10A1D00087AAE02D49D49EE24C57DAFEB7252A3DE6
-:10A1E0008F7EEF72ED0C8557D48EC997E90FEBA5E2
-:10A1F000CBF46391E659BA61EE5B8D9A9C4AB691B5
-:10A200009C6AC7B80FE0BDDDCACBFC52BECF8DA59E
-:10A21000950F4F80F2E1099CAEEDD680B312C71FB7
-:10A2200063A03C07D698F9CE3018EFCE5F290CF327
-:10A2300045057F9ED1F8207BA89DEBEB7B2C74CE4F
-:10A240007FCDD01FB726009CFD84DB8DF9105B9974
-:10A250003B06F924B0CD4079913F2A1C9E30079AE5
-:10A260008F2E7A2101E5FA8C097C1E412D8FA8B929
-:10A270006DF9508C537DF51697877FD3C6D96DEC59
-:10A28000AE277A16D918CFCBDA4EF648B30B880D25
-:10A290003AD390CA4B93D1B900DB99C030C0BC6DA2
-:10A2A000D3D7E32DE80FB69C374FE779B5DD649F30
-:10A2B00098AC7E673C3CDF1E30905C68516D940723
-:10A2C000B7D5E6E9C27BD301A781F265B7E61908E5
-:10A2D0008FADB61B82E8072852731DEAB1A073BF89
-:10A2E00025139E07F30C94FF18F4CE9D8E70C0CFFB
-:10A2F000BF47413F58EF4FA0FBE25B59EFEBE3B0A4
-:10A30000BE96DB696D29FF752416E3E2D73BDDFCC1
-:10A310001886A9983746296406F4C77B36C6E23CFE
-:10A320006A98E6EF06C8BF759839FDBEDB79AD7354
-:10A3300018D91911E75D668CE1B92D6EA81F6BF372
-:10A340004C47FF53B17B2C9817D8EAF45816D3FA30
-:10A35000793E1BE56B40BF2D4E03F9C1587F0BEED4
-:10A36000F75646F97083B5FA56DB839D880F651959
-:10A3700063992ACE4F09449E275A869775A9B08EB5
-:10A38000F6E509B40E457213CC962934EFC16A0C78
-:10A39000DD937EC854DD85F6E460CBAD74EE955A4E
-:10A3A000A7E8CEA506F9F570F27C3D9CC894F0B9FB
-:10A3B00016F2D9041197D3E32D1A1FA9CED6B77080
-:10A3C000FEA97EBAC47BC9FC1F717E2FBE82E13C10
-:10A3D0006D34CF14DB920AB49B9299AF19F9EF1F39
-:10A3E0009DE758E75C4B268C3F36C940E6D138D60E
-:10A3F000BB11FBDDAAF17B7B26A767785FC9625F93
-:10A40000364D48C6F305033874E1FE3303E0D8E95E
-:10A41000CE17127470F6F6C1BAF623760CD3D58F28
-:10A420000C8ED2D58FDEE7D1C1633A4A75EDC71DD8
-:10A43000ACD4C1F9A119BAF6055D73757051F70274
-:10A440005DFBF1C797E8EA27F4ACD2D54F3CD5A025
-:10A450008327F5FE8BAEBDB0EFA3F5E3DD13B87D2A
-:10A4600071B576BDD93558F7DD9C68BF21DAEEB7F6
-:10A470007CD3A26E447E7698889F15D4E7780E7DB3
-:10A4800037F79F2C93DD2AE5396BFC5854EEDD84B9
-:10A49000F2B4C26121BDA0D8783BC5368DEC9521C0
-:10A4A0003B4CF43D1FC5C9FAEA63513E37052665AA
-:10A4B0006587E76D756E67B87F2B1CD319E6298910
-:10A4C000F715A797F9318F1B3FD28376923340ED72
-:10A4D000AC2ABC1FB18EC30603B3A11C073F0FFDFE
-:10A4E0008381FC3AE1CF09FF6D20BF4DF86B430C2F
-:10A4F0002C06CBDD52CF6DE8DFE7D5BF553988910B
-:10A500005FB70FF9F53EBC078EFEDC586E67B5A548
-:10A51000CC5031DED39ED9D1350CE7936CA0382ACC
-:10A52000D8CDEEB911F6E2DB9AFE5186B5F7A0FE62
-:10A530006B88B7A8682F2996DD933E027CED32F632
-:10A540003C8DF18B56C9B9BA03E5E2DD36CA0F7905
-:10A5500048C39B6A37146C847E3B9ABD0ADEF7EFD2
-:10A56000D8C2DCADB83F922A36C6C3F3ECF4C506B8
-:10A570000C138DC86ADE88E5B109FC3C6864DE6EA8
-:10A580004322D48F2EAC988F7131D9B99BFCD981DD
-:10A59000F84976EC60B81E96A59C44BE42EBFE22BC
-:10A5A0004CBD2201E80DE35A91DE12958407EB7948
-:10A5B0005BD08A7016C78BD52B0563256EB7627E7C
-:10A5C0005D45C20EA2AFB067D1CEF5737FF76DE4E3
-:10A5D000A3A4997ABA2A96BD848FAD06BE2FDAE37A
-:10A5E000D537503FB7676625B4A8E1790AB9F24775
-:10A5F000CD0E17CF855C998D3938C961FB06F87C83
-:10A6000007C6E7ACCA76BAE769DDB09D215F5BF1AA
-:10A61000563CD9FB01D547FAC3A7CB4FAB1A36DF5F
-:10A6200082FAFA5C9287EC596BE34F697ED178B37A
-:10A63000F6F03CB581F0EAC87994F43B086015FD6A
-:10A64000FE2329B6BAC8B8A828EFD2FC13A3C8279E
-:10A65000024F02F5D93991AFE48DE5F38BE7F0D1E4
-:10A660009C0534BFDB923D832E676F5BC1DFF447EF
-:10A67000D07D8BE2B3201EDA2ECC994EEB56683398
-:10A68000B0AD5FE7EDA678B3E62FDDA5E1B7B58401
-:10A69000E3738889DF337027CDA4EFA40DC6F84893
-:10A6A00041385E32AA94E737BA034CE6F1BEBEFCED
-:10A6B00076C3C571346715EF1FE09920F2631AE382
-:10A6C000FA0C9A74623ECBF076459F0FAFE9F334F3
-:10A6D000FE3BC87F7DFD881D7A786430EAFD00FB73
-:10A6E0000DEA7BB477299EB14F5FFF18EA6D901396
-:10A6F0004B35BDCDB6F3FC120BCCE822D7B761FDCC
-:10A7000007F260564777452CF49351A2CF3B498B13
-:10A710006C07F8F3AC34D0BD1211DF1178F7D519FE
-:10A720008C26E27F55770E27E239D1F25ABAE7CC70
-:10A730007ADC5715B1B12ACA598C77F8CDDC7FF78E
-:10A74000833F739FE2FE7D2DFA5F5D32E561097AFA
-:10A7500046D37F6F9F3DEC2B2F253FBAA700FD7A94
-:10A760001CCF1F319E88CB6497FBA7623B119F399A
-:10A770003B5D794552C3F116113F7818F719B4DBE8
-:10A78000EA7EBBFE28CCE3E87133C54AA6CA6F74E3
-:10A7900035619E55864272CE397EF50FD04FAFFCA3
-:10A7A00003D4635C52550791FDDE65A47841A5C6CC
-:10A7B000EF959A5F26E2320BB579D7940A7B281081
-:10A7C000C3FDFF500CDAB9A3F7818CD6F34B2CAF45
-:10A7D000E771BA311DD1F55ECA7F1AA5F103E6AD66
-:10A7E00055A460BA18873B9894E8043A8F9BDF73AE
-:10A7F000045D8CBCD75E8941BBEB392BE78F673496
-:10A800003B2F85496ECCEF4FD9677307A19D5D66DD
-:10A81000CF75C33ADCC7145D9EDAD8437A388F45CA
-:10A82000C099380F3DBC4DADC7A36BB6AD165811DE
-:10A83000967C47A9964792C37290FFA6CAB67CF44D
-:10A84000B31A2A6C0CF16A3E31E2FBDD2857DE9226
-:10A8500019EA0B67ACFA4015BCEF7C3DD1DDAC8644
-:10A86000E9FF0CF8DBA8471EBEE866ADC670FCEB3E
-:10A8700059A067169D4F3BA9BE03E88AF07EF0BF42
-:10A88000B3E87C3A979EFF14FC6F840F82FF8DE53E
-:10A89000CFC1FFC6E787C0FF46F887932B1EC4B819
-:10A8A000D97BD00EF92226FF806538C6CB6D32DD0C
-:10A8B000DF89E6C7CDF51FDA6E049936CA953C33B9
-:10A8C00019F9E17699EE45432733D1BF8D8CBF4509
-:10A8D000C623C3F1B71E49C4DFCC409F519A7FD92C
-:10A8E0001787F3F338DCB7F7E315FD509CF3927E3E
-:10A8F000FAE29D96C047B928B2241607CF3FBDFBA8
-:10A90000DF9F427D24A7FAF7E23E5953F48189DBA9
-:10A91000E7FC5E56BAB68F765A793E6ABA96471405
-:10A920001DE79C3CE5C46DC980B2177F7ED3428C85
-:10A93000134CBEF544C11080BF29FD25877F78E206
-:10A94000F934C0D3D289ED1C7EE8C4B97437E671FE
-:10A95000EC5F88F9C38E44AE07776AF79B047E8F5D
-:10A9600069FB665DE313A4EFC11E61888F96141F17
-:10A97000E9E1CF937A1D8BD1AE4BEE4D597219BDE3
-:10A98000B1AEF1297A7FA7E43E15C4794FB0F0BC8F
-:10A99000554D2F9DD57857E8A5062B07C57C187314
-:10A9A000D1F387B47811F3A6D17B89560E1F759425
-:10A9B00092FEBABF52FDB5CACF3FC98F3EEA18F525
-:10A9C0005DCCCB6B99AED0B9E443368F15F5DBE7A0
-:10A9D000DABAA0FF00C60902532D745EC492E6D312
-:10A9E000BE4E10E324D5523E4382369F63A53121EB
-:10A9F0008C23B45459F6A01C7DD0368CFA6B2931C7
-:10AA000005307E23E08DA5301FC067BC2321136174
-:10AA100021E7447C99E1E91CF45BA92DBB52E44990
-:10AA2000588C6722ED701BEB26FE711B5419EDC884
-:10AA30000D13395F1530F77C7C6E92EA03C88CB831
-:10AA40000E43E43AD42AFD3AD4A9BA75480D9610BB
-:10AA5000DA8F2D53611DD0FE98BD98E61B4D37B19E
-:10AA60009E0F4B55C257F43A99762E25EE1F543A55
-:10AA7000CB0EE0BCA61ABCAD38AF57FE5A9B841F64
-:10AA8000E89BC6EA157C3E3C9C0FD47A35F91693B8
-:10AA90003F94F839DAAD265A9F71329FCFA3A66052
-:10AAA000265D0C5182A9787E3C101F674E8CE663B0
-:10AAB0002FC3FDD592E0E57CECEC7534231FC7F77E
-:10AAC000A66CA47585FAA54F343F47D32B6F22138C
-:10AAD000DF079111FFDF465F41D7E8F334C12F1B39
-:10AAE000263A05BD5DB4CED010DD7923F4A0F6770B
-:10AAF000CEBE09FA5323CEE54C2E1FD9E3C62477E8
-:10AB00002EC6A55BBE91FBBD7F59ABE1A9D9114310
-:10AB1000767A8B83DBE99D8E193AFFAA0AFC2D3CDD
-:10AB20008F96135907EE2B396E01C5DBE441689906
-:10AB3000115BE8EDDFB899DCFE757A2E7BFF4AE900
-:10AB40009175DF73BBC4FE4D98C1ED5F8789ECDF63
-:10AB50009D76D3FCDDFDC89DC289DC4FEAC475F447
-:10AB6000E35F825F49714FE1579A9C7EF20FC53ACD
-:10AB70000BB57D26DA9B9DF50CE370B2C9ADA2BD85
-:10AB80002B6BF764312F3A37C22E10E38F9BC8ED41
-:10AB90008EC1E53C5F53E4C74FFEB554DF1FDED7DF
-:10ABA0004C147649FF7CF70FF00DC9098FCDE445B1
-:10ABB000BBC36373511EF940EFE151F8A984B09C07
-:10ABC000717F532C933E52DC742FA0C3D8F3FCAF9B
-:10ABD000D16F7CC5467AA7C39E4EFD09BBBD2296A8
-:10ABE000517E33F8C9815CE8ECB9BFC18E3484FD75
-:10ABF00063F0D7364F8C38D73CD27092CE8BA2ED13
-:10AC0000D5E8F843DF7E773C95C9E7134CC5FD2BAB
-:10AC100035940C42BE8ADEEFA2CC70158C5A0AF332
-:10AC2000CA48CDA7523C7F9CC9D3FBFB6EDBAE3E2E
-:10AC30003A703D3D12068B93493FEFC2797F7AFB14
-:10AC4000DB296E15EFEB7E417AFA6C7D49DC66E418
-:10AC5000F7DC0492AFE9DAFD33319FF4959DF109F9
-:10AC600036CC03EC1D89F973C126DFA82A23C50D54
-:10AC7000BDFDCDF757DAFE63A1A12CF2BB446A52A9
-:10AC8000F7B52300EFAACDE056697F3949FF0939AE
-:10AC900050A1C4573981CF339A98DBA6E2A79B9D78
-:10ACA000143FCBB82813BF651CE5DF971E9AD42B41
-:10ACB000E1778FFAC6D1F2A4C439CC97F555B43FE9
-:10ACC000330631D68D7210F43DCAF92F934273705A
-:10ACD0007F7FF93D3EA38C27F4F5A07329BEBDFC10
-:10ACE000F698A00A5D0FDD00F3C3F9FC4062E99914
-:10ACF000388FA3999B313EF4622CC587E41D59140B
-:10AD0000DFB93ED5BF7F22CCE3D3A07AA761B8B626
-:10AD10005868B7E6AE18FA2EC14EA9FB5ACACBB88E
-:10AD2000C340DF6D8DC6D75B13B95FF9F644BECF64
-:10AD3000325CC59CDEAEC2514B13AF7C3F7D83DFDE
-:10AD4000D601FA6E8D0BD2799EC82BDB66EC9FAFD5
-:10AD5000CACAB87CE993C71AFE2CE80521BF489AF5
-:10AD6000DDB7EF99679E4961FC8AE2307E6E197902
-:10AD7000BE1C9315A4CA18B797E48FE4F47239EB9C
-:10AD8000AC770580BF377F2DF73BBEBD4C93D31901
-:10AD900077BAB07D95EAA6B233A3F8F862C09FCD2A
-:10ADA0006662E608392CF8245ACF37D8875DD6DF9B
-:10ADB00037813C562F138F306979649B8E4CB0E0FD
-:10ADC000774B37D93CDD687F6DB22579285E6F03FC
-:10ADD000B91111BFB2D95E253EB4B9795CCF86F204
-:10ADE00017E357B8FE3C9CFFABB47ED1EEB4268788
-:10ADF0006CEE109DAB5ADDDBA99D45F1D1FD3B4BBF
-:10AE000012A37C088B937FEF3426CBC02CFDC8E3C4
-:10AE10000F501E433F9BF23CDD95343F05AF65B1BB
-:10AE20004D2E8F8BF421E219DE3F6A2F8E8BC4CF1B
-:10AE3000500DCF2D9D7C7DBEC654675501FAB5BE21
-:10AE400094B222EC678905BFAF27DB0B2FDB4F6E77
-:10AE500019972BE17E1E49A94AA47E86623FB2DD86
-:10AE6000E3C47E8CDA775BA3F15CA4BDFFF7C6DD9B
-:10AE70000083940F447821C2847474892E6D183F26
-:10AE80004BECEF3D2E173335FF05E4624519CC6BD3
-:10AE90004DDE07AFF23DC6FD96846B79BED1592DCC
-:10AEA000DF3C3A4F23DA8E11FA47E823E847C67EA3
-:10AEB0001E453B6644781F0DE6128BA5D5F9F87E3A
-:10AEC00049F211BF805DA3E27E91B57CC1E8F56CCB
-:10AED000D6F027394A54D41755177AD2F0BDC3F6A5
-:10AEE0005369DC8ED59F471FFBEB5356ACFFB2AEC8
-:10AEF000F2B2F68A387F1EE8DCD9F12F9FAC8FB40E
-:10AF000057063A87FEB6F3E7230E13C5F97649FADA
-:10AF1000FBF5CD9A1CDA5026E232FEDB901EBB24F4
-:10AF20009F9B5F98E6F199A272FF9DF87C48BB89D0
-:10AF30000580AE87FF5AECF247F473A57816F1FA54
-:10AF4000C19A3D35D8F69484FB74705D50C2787B0D
-:10AF50005A5D87E4BD4CBBD9655C8F8BF646ADFF6F
-:10AF600072A557467D55EEE47A31EDBCC27223E4FA
-:10AF7000CE8C32BE7F8D9AFDEE38F2B415FB3B626B
-:10AF8000F0B5E7A07E7018D42723F6BB71A5C75291
-:10AF900019B1BE163C47EA878ECF94F5D95DA4BFA0
-:10AFA00085BE350A3D91A4E8F4C4BA58CEC7C2DEC6
-:10AFB0005957CAFDA175B1DC2F7FD1E57F02F7F3A8
-:10AFC000E7A59FCC1AAEE23DDB0E139EBB7FDB797B
-:10AFD0004A9F7D63082E16FE0CF2BF5B71FEA2072E
-:10AFE000DECFFF6105D97B45F8E512198F70B9FDF9
-:10AFF00007F6D473385E014E3D82DE2CEABB860331
-:10B00000AD67277E4BAD08E37FDD14C7BDEF82D46B
-:10B01000EF7D8A2FCB84BDD0776E78D938AC8A711A
-:10B02000D84C3C07D3C7490BBAF47051B71E1E7FEA
-:10B030003C3AEEEAFD6D64DC7527EC33941322CEC6
-:10B040009A1E0856E03DF30CD641E7906975093A1F
-:10B05000BC4E96B5FC0CFCBC7244FC374DA93E8D31
-:10B06000EF9FEE5B5780E9EE07542DBD133FC519E6
-:10B070008EE3AA84AF15D7CE9D8A748D8EE766D4F1
-:10B080002BBAFB84D171DCE53BF5F70D7DDE7CF25C
-:10B0900007E67D471FFF1579EDB8DE34CFA5E37FC6
-:10B0A000FBB8F03FE1D2F145BF8F82FC21F9AA7DC8
-:10B0B000C73803ABB01F2524E179F8E07A46DF33C7
-:10B0C0004EBB9D79FB3B57489BC4F1158D671628F5
-:10B0D00027FC4DD19E0DB6F1BCD7C1B71BC81E1CB5
-:10B0E0000C7281FEDEC16AC612014E5BAD923D3923
-:10B0F000BBCEC0503FB00B4DBAF761BA144F1574B8
-:10B100007FD4C6F37A33D6B0A001D7533F8AF61363
-:10B11000CD6B982EEEAEFB2EC1EC12FD7DDF8CA820
-:10B120007BBE820FD2A29E1F2A73EAF605E8B9B44D
-:10B1300049C4275CFF65A3FE83297D3AE1F8539853
-:10B1400087377923E3DFC3898FD1BE87D3775E2129
-:10B150005F047E3D6299928BF6CA56678C01F32399
-:10B160000EC7F73CC6E2191B338905F0FB9D2FC7BC
-:10B17000F48E96009EF0D29E5DED4094C3D6DE1F05
-:10B180006130D9B6EDE99BA747C08EFB5F22989549
-:10B190003015BF2F84B9ABB8EF629C33F6E1F77C72
-:10B1A00063F26C149C8C61FAEFF8B496AADB30BFA2
-:10B1B000A435DBA0DDB38EA887753C35C929F2E242
-:10B1C000284F8F4DE7F90291FD639EF780FDCF80F8
-:10B1D000FE0BAFA27F0B9F7F0A3E023D9382F3C717
-:10B1E0003838F68FF4C5A051E4F85A7F0A0BECC644
-:10B1F000F31D18CF26F1F19C98BF92C2F4F90A7D95
-:10B20000E33961BC31FF17D633FF527A182F478FCD
-:10B210000557478F568397E61B186B233F08BF8758
-:10B2200085DFBDB36AE359B5EF7F215E5B8BC378E1
-:10B23000053B90FA85E6CD17353C633E628AD344E0
-:10B24000781E086F479C3C7F6A8B3326D89CF9FF99
-:10B25000805E2E4EAFC8F1D09EBCE2F116C0784998
-:10B26000573E1EE217F74F1F7E81261B53AE1CBFB1
-:10B2700030ABC095E0F708F46B88C06B384FE9112C
-:10B2800027FA0556A3CF82799BCF4FE2F98F7949F0
-:10B29000732D94B7903C97F290DBF26C9457DF9645
-:10B2A000F51D8B31424FB7E5D5523DB4A7FCAABC82
-:10B2B000500C8629D818D64D71802D65552EF40B6B
-:10B2C00003F53C5F4BE42F097DC8B4F3515A17BC1A
-:10B2D0001837E940EF1168BFA5BE90F2D3E2E2FF54
-:10B2E0008BF2B2B6D6B9DD58FF189E63813DF1B03E
-:10B2F000768E858C4AF1B4B1A54FE0B9AF27BB413A
-:10B30000C2E3A6F4D57AFD34382AEFC7F345772592
-:10B31000E677B1C53C7FCB55AB44E943FDBEDD8A42
-:10B3200078E579564189E357D7DFE949C9A4E7B6FB
-:10B3300064ED6115D0EFF3D097ACDF5F06CC778A70
-:10B34000DE8F8AC94BDF29630D069A471AA6108043
-:10B350008AF38C99E95A0CCFD39729F4FDDA417915
-:10B360001B28EF09AC7CB237F2F2DEA844F89275E4
-:10B370002ED5AF237A5DD1F316DF5716F4F27CE1B8
-:10B380008E45FFCA933D97F2D2E847EC77396A3D84
-:10B39000600F5B930CF45DB998AC8875315D3BCD63
-:10B3A0007FFB9F857F3F8971FB39FA5CEC7FF1FB66
-:10B3B0004766E6B698E83D715F879FB70DC6BD83C7
-:10B3C000741FC2787E78F4FBC5FC7DE6E2E76FE689
-:10B3D0001866C1FB3AD2AA188A639ACD00E37D1E93
-:10B3E000ED7B658F6AF1B6668929A99EC8F1429402
-:10B3F0005F2F5BAECB42BFE188659E93EEC9697E4D
-:10B400009431DE47F98D2C3741E78F1ED1EEBB35E5
-:10B41000ACCC1C84F1BB38A8EB46BF5A715B90DE04
-:10B42000226EE218DE7313EAF16193872FB2002EC9
-:10B430000EA3135CCAD8B8C3193FC0EF148BFD69C3
-:10B440003ECFBFF7D1072BF5943F623E3F44F73C18
-:10B45000A4F96102F626295538DE34F40F92F1DEA4
-:10B46000B8B315DFAB00E4E8BE2FA07D3FE4D2FE09
-:10B47000D375CF43E05F479E0B0CDC7FACEE3B0502
-:10B4800066F077FAEF3F27AA7F67BFFD87FB4DD4B1
-:10B49000F5DBA670B911488A09F617DF5B36B9F2F9
-:10B4A000BAC94503E7B72D9DACC5E12C20FAF11CC4
-:10B4B0004AE39FCDAE7ACA779363F8B9A911C4085D
-:10B4C000F2D3517B1DC92D96AECF7713DF2769C309
-:10B4D000EF8E407DA54D6FAF57B0DEA3E324F4534C
-:10B4E000F5F6FA645439783EC5A2EDF87A3A273574
-:10B4F000A6EBE5C2456DBF18EC85DD941F976CA3E4
-:10B50000BC8681E20BEF3531CADB32C6FAEA51E77D
-:10B51000FDEBE1F143DB4A008EE37CB6F5F0CC4570
-:10B5200018377A4FE3E736900374CFB561D06E39A0
-:10B53000A2DF5A53281BF54AAD81DF17A01F18FF61
-:10B54000BDE4C114678D1E577C7F46C00BEBA54937
-:10B550005911EB7B4FDB1F7DE3DD96B61BEDDABEA9
-:10B56000F1CCA1221AAF2FFF481B2FE5EF1BEF8F65
-:10B57000DAFE16E32DBC53BFBE85A66E5ADF42ED40
-:10B58000FBA762BC3FE2FA32FF8EF1B4BCB1BEF160
-:10B59000EED2AF6FA1B99BD6B7B0CFBFD4C64BF92F
-:10B5A000FBC613F90E66737D1DF2D340790F22DFBF
-:10B5B00021C795A8CB77C09B2715598C3D2071BE1C
-:10B5C000787D72CD0F30CE7F6E66839BEC14CDDF1D
-:10B5D000A37B4432DD23223D3A3B9DDB21A2FF7D4C
-:10B5E0004D25CC3B82C783B0CC2D93E89EC2C812B8
-:10B5F000C98BE76C3B417EE077F476C13EC7FA60C9
-:10B60000938BCA3D4D2A957BC1BFF452FCCB4DF0C4
-:10B6100085C9DC5F7C20D559B314ED8F8A189EA7AD
-:10B620005D36112CDBB0FF06FBE58815F3216F605A
-:10B63000F9F8772D7376707C2655A5D0F7F663F26E
-:10B640008F753701BCB9445631FF7CB3DA7F3CE7D4
-:10B650002F5ABECF662DBF3280F72E49A9803F59A1
-:10B660004C7F3F8BFFC833E95ECEECBBE2C9BEA97D
-:10B67000FD4E8FDD09F3B859CAFF6D16E0E34F9A0E
-:10B680007DB368C80C9207D1FE69126AAA42CC3B0E
-:10B69000948341F8759E7D1EF9B7F3AE672C01DEE9
-:10B6A0009F8DEF819EFAB5661FBDD96366E8FF05E1
-:10B6B000AAF8F9F5CD1BF47EE903D69013EDC20785
-:10B6C000F29318D2A3F6767DFD6613DF6FF3A2FC2A
-:10B6D000D4D951793FE23B8A9BF1D7098C7D395906
-:10B6E000FB8E9196F7B35F8B33B1F4044A0617F7DC
-:10B6F0003DCD66D6EFB9A4E82F11041DBD97E42512
-:10B700003C88BC77263F9B8FEF8BF1C47B8F4ACF61
-:10B71000A65E2E6E0A76E0C99E5CAEEFD15EB7964D
-:10B72000EBE7796EE6B0EF56B1FEF8B657C1388553
-:10B7300098FF3F8B5F8FE27A414EFF7ACA9785FC74
-:10B740003E5E3A8BBC8727F2BFE6F5C10A7D9FF8C3
-:10B750007A01BA7AF390DEBF9914EBBE97F84FB333
-:10B760004742EF1A2EC65E7D7F7DF370793374F702
-:10B7700060B5FE06C2F340DFADA09FE2709CB7A5A6
-:10B78000D9EDA27B77C9FC9C6D7052E569BCE78559
-:10B79000F51FE8F84B7F9FABA5F36909FD96C7F04D
-:10B7A0001E9C31224E54D721B5D9B0DF208F2B8576
-:10B7B0009EA6F86F7A5D486ACD0BDF1B8A968BE9EF
-:10B7C000ABF5F7D2A2BFC7586DEB512415E3FDBD11
-:10B7D00074DFB1AD5C3B9F411C63BB646E4FCA69B3
-:10B7E000069E2F3254E5F66556EF90C8F38E55E568
-:10B7F000DC6EA88E7DFB761544AFBFBC6311E645B9
-:10B8000055C7BD7D7B26C0B7943FB708BFB3589DD1
-:10B81000F6F69799206F9795EFE7F0E8B7BF1C060B
-:10B82000F08AF2E7398CF91E80A495E50716A1BCD1
-:10B830005D552EBEBFD84DF7BFE554CE477F776923
-:10B8400036F4BB2F6F2B17714B46F7BD7D877E7982
-:10B850001CE5944FC479BDFAF34DA67D7FF13AC142
-:10B860005E490EB29766E0EF80CFEBB4EFF6182C8E
-:10B8700021C2EB88F07751BE7735DFED09DFB7E7FE
-:10B88000DF9D6A69647EFDF715BD1AFFF3BC2131A7
-:10B890001F31FE25F3C2EF0B2644CE6B27F523E6BE
-:10B8A000F579BE39208D0B9FD78A797D2EF5EEC2B2
-:10B8B000A047CF94DEC548D7CFEDBD43F0EFAB94A2
-:10B8C0008786FA094EEEDD25B9236023A7E323E539
-:10B8D000FF87ECA951A9DE47CA317FCFC4BF83D00F
-:10B8E000AED9915B93FD01F4EB81DF286F3390C1FA
-:10B8F000EF3B5415EAFF0EDC131A7F1579F9F9F4C2
-:10B9000054F3F6FAB70AF1BBEC126B86F6EB2E9CF9
-:10B9100033A1DF5F7DE88409FDFBB5074E98D07F3A
-:10B920005F8B30F4B376A7A9DFBF4357EA95C5FE16
-:10B93000D5F92BAF64E4B425C17CD62EE5DF016BCD
-:10B94000F859FC54841B16E32AF1EFF93D37155FD3
-:10B950005BE8EB6CC37211EB7905CF256AFC7A3F8B
-:10B96000E2A63ABDDDBFB05E6FAF2FDA0ED401BDE7
-:10B97000B6A8312DEA7B80FC3B83351A3D6B5CDB3E
-:10B98000BAF13B06352CEA3B83011E47BA89AF006A
-:10B990004A7D7CA41AFF9E15AE63B54C71DE57320A
-:10B9A0003629784F6E5DBD44F97B530F7E61A27AD4
-:10B9B0006887E74A2983F9F7F484FC14FAFDA6970F
-:10B9C000761B315E10FDBDC145F3A7D377C5E7AB4C
-:10B9D000ABB87E1FFABBA909F03CFA3B82B507B9A8
-:10B9E0007EAF6D9482F8DDDE9BEAF4FEC042D6DDC8
-:10B9F00086FECCC27AFDF3458D7AF823A1D746B3F3
-:10BA0000D1B83F4E974B0AED170D3E93F1BB37432C
-:10BA100030BE3BD5C7BCC027AB4DA1B1A8E7DCA960
-:10BA20007E82453D3C5F8BF27FA07DF8FF4BF9DFC6
-:10BA30005818855400800000000000001F8B08008B
-:10BA400000000000000BED5A7D70545596BFB7FB07
-:10BA500075A7BBF341E73B31045EBE58244D68D265
-:10BA60000441778AD7DD494FF8723A40866008343E
-:10BA7000B350152549478953B1CADD341063072DEA
-:10BA80004B59B4C0F28F06C5D51ADD0D92C1CED286
-:10BA9000301D302C3A387676D08171B582CB3A524F
-:10BAA0008E9088A3B8CB167BCEBDEFD1FD3A2F8AFE
-:10BAB000B353FEE16E527073DFFD3EF77CFCCE396E
-:10BAC0009710E1A3B1D984E8082537F484EC344811
-:10BAD00056E7024202EDD47E5024A419DB4D84FDCA
-:10BAE000DC28C1FF797F56D74FAE3B244A480DCCA6
-:10BAF00063F676119CE718B51E844FB5822464D98D
-:10BB0000E03B254D0369D0177F96C4CB05928E90FC
-:10BB10005C427E43C66CA48C90592930610E94AB74
-:10BB2000A78502B0EEAC5F6D0A50986F9683DA7508
-:10BB3000B0AFE5B0E3EE6A2C05B21ECABB0542CC3D
-:10BB400050CED20F34E1BA649ED17A90EDB7809096
-:10BB500085842CC33F619CF432A11FC37970EBB87C
-:10BB6000EEF2E9A7BFA619307EEFE3137A28CBCB1C
-:10BB7000A4EAA7607F8F99F9FA8F0DD1D07698A7A4
-:10BB8000C376EA1CF6CB97085BB7A3202D8AFD4944
-:10BB9000D8F0C79BE72F8576D14AD6674165858D5A
-:10BBA000AD5B28D30E56261F433F1A75E96E5442EB
-:10BBB0003F79DD1F794476EEBCFB06289EBB9804D6
-:10BBC000B65358AF0CD6413A2A2521A6C04518DFF6
-:10BBD00008F7340DFAE90B7DCF2F8171ED0563462F
-:10BBE000528AEDE346EF5CCD7EAF2EA9D1E8270166
-:10BBF00001617F0F58395DEAF4D73380F2E4816345
-:10BC000065F9C436F97E94526FD21151E107F86795
-:10BC1000B05A88383B5E5F3E3B5B555F692F52F5FB
-:10BC2000FFC9A232557B8354A96A5F5DEF50D51BD3
-:10BC3000BD77A9FAAF6D72ABEA2905CB54FDCDE211
-:10BC40002A553D75F63DAAFEE9F69FA9DA49CE4090
-:10BC500081379D10A32930E6033A04815717C1FDAF
-:10BC6000A518D382741A219519D0194A8BC39C86C2
-:10BC700065707E4A14EF2D785B4615D653DE7CB096
-:10BC8000208A549FF68AC909E52F68C8950D73006C
-:10BC9000997C0340C7390F13299440CF636E1DBBB5
-:10BCA0004FA5DC26F9FECE09A5ED25B1086E047E70
-:10BCB0006273F07E4C16F813F9F88829847C3C0FE7
-:10BCC000E6248BE3F32CF138BB251CF7B0B414F950
-:10BCD000948489B502FA1D30C2CD423D70C4C8C6F5
-:10BCE000D9C2633A2941DE042797CFA7BDAEA53854
-:10BCF0007F47845A09F2F7DE8F8CA20DEBC319122D
-:10BD00009455DE8F8C242DF1FB05237EEF10C62D7C
-:10BD10005628FF69405F1FD2E09341C9C8F8F95423
-:10BD2000B191C94FCB83FA500A65FCBFC209FCD65A
-:10BD300024CB61CBA1F1A81ED66F013D13804F4DDE
-:10BD4000E27D2B08CA93CFC0F48D097E519E9E2EB2
-:10BD5000CC3840E671F92179846C94A5E99E45516F
-:10BD600003D2ABB9D510D74FF06FE31ACF255A05E0
-:10BD7000F376267D9FDEC7E47B63A2BE427A49E963
-:10BD8000391F833C924A62BB01F272CEABD33CD7DF
-:10BD900009B7C0CE75CEE766F47E1AE8A6A748C7F5
-:10BDA000643A71FA7D1B7D5EC5BB4EB8A7E47EFF89
-:10BDB000E2A6BCDF14FAD2E2E4ED0768AC1A95996A
-:10BDC000DF6B617CDA6CDAB4F5A203E9FF651F452D
-:10BDD000FAFF92921498FFFDE137F344E4F3432312
-:10BDE0007963309F7F60248F009FB519C4ED420EA8
-:10BDF000E303FB76B8978E7094EDBF7DC0318CDF86
-:10BE0000DBC3D48EAAD03F38E161E724637DD6340A
-:10BE10005C577B5F31598FBF2F898CCFFC3E5833E5
-:10BE200007C7A7844214EF1DF410EE6B889227A178
-:10BE30007EA0DFD414D298E70CD21BC6BFD16F24EA
-:10BE400002F0491B8CC7739C2A3E653421DF1C829B
-:10BE500073513CC768632ACEDF6520228DEFEFB3B4
-:10BE6000E2D88778FEF39B0D2400DF776ED6337A15
-:10BE70009FEFD2B379F45BFEA3AF08EAEB80FF52E9
-:10BE800060AB27375F3D5504F39E6F853A9CD7BD65
-:10BE9000C5C0E46FDDFD94F54FE65F855F9F95F9C2
-:10BEA000739D4FCD6FC9FC3A894F5BBF1B9F7E15B9
-:10BEB000E7D32AB4B370EF75F9C83F0F11FB419473
-:10BEC0009FEB270DF9B0DFD23EAB7D07D4E7EA4305
-:10BED0008FE4A15E38C9DBE7B7EDA75CBF88F7E068
-:10BEE000B98A8246B28B221FF1FBB23845568A646A
-:10BEF0009CA6A2BC0AB152D443B0B484F7FC9A8188
-:10BF0000341DB2E177AE5FE6BE5EB07F5702DF0E52
-:10BF1000499C1F15BD576924BE4369D87FE0B6060A
-:10BF200098E755188FDF67C8F355948D7B1AA09C4E
-:10BF3000E3E47A3047DE87527F4FE67FD22A50A46F
-:10BF4000E34A13A7FBB2EEE87A3C47E974DF6DA839
-:10BF50003757CC78AF0DED5AB0F42D9B0FF747EC67
-:10BF60003AECEF97E97E72F11F9EDB06E735DF6E54
-:10BF700061F7DA70625F0CEFB9A35C2078EFE68AB4
-:10BF800005F93E0DFE534AFFB512E2CB8ED73B2298
-:10BF9000131E4943AE47DD5CAFCE35F2F393081074
-:10BFA000A990E963615175BC9F727E4276B0FEE64E
-:10BFB0008A17D83D6DBB9FCC67708A3CC5CEDDDC4F
-:10BFC000364A37C13C6B0D92210DE8FCDEB4A6ADBC
-:10BFD000172B0879AB0754241CE44C8F89F8FE0A10
-:10BFE000F0528F95D5633D05ACFEAF3D222B7367B4
-:10BFF000787F84F4697CA3B302E975B2F819AF0BBA
-:10C00000D6B972C6C0E840888BD1699BCC7B5723D8
-:10C010007A6282F6AB833444687CFF1BAE15111F35
-:10C02000E893DFE37A30B0BDFBB74CCFD95B273C58
-:10C03000621AF2D5853EACFBBBFFE441DCF021D8AF
-:10C0400009E42F7F9892029867FDB56C36BE3D3C9F
-:10C050006A14910F74E31EA47FE03825C897FECEC2
-:10C0600009A63F9F837349B0EFBF756672BD1199F2
-:10C07000AFE3F7B980E314F9FE87E7FC6706EA2F20
-:10C0800053B7F8CE5D788FA7F5EC1E77B9C633AC01
-:10C090001AF7720EE625297CFF5826B737190315C3
-:10C0A0007618D724F36D72FB43323F02850D881357
-:10C0B000F08702DDD6CBFCD50247990678617D98E2
-:10C0C000462D20B72D11F72501CB4E4A3E52E903EC
-:10C0D000423E4AC0C953F1DBAD961D385F45BCBE38
-:10C0E000CE079326E09CE6D65434A209EB07185FEE
-:10C0F000A51497E7FBBE01DFF9C700AFC17D75004E
-:10C10000101281EFDBAF55B2F2F2D0A322CA89C977
-:10C1100032FE0CDA05324BC7707D7B408D6F36CB1B
-:10C1200072BBD9CDE5F929271510F782DEAAC473B1
-:10C13000DB0B7D7B902FFF58FC5EC609F8DC668C1C
-:10C140005611EDEF1D88874D284FB06E25DCCF6B63
-:10C150001AFBBED7EDDAE7CC45B97A92F13701FE8A
-:10C1600046BE4A3EE70B32EE51E479DD894B46C4C8
-:10C17000BBFEB0B63C77B99D2FE07EFA09A9D7B2D5
-:10C1800073F7C9F2DEBE97327AF9F766333A7D4625
-:10C19000F67A5DC0979FC13E0E005F5EF17A533321
-:10C1A00061FC159F37352B2D2EFF1D7B53D9B8FE13
-:10C1B000F255D99BA03E847C0FE7B81C769B90CEAD
-:10C1C0001BF672B953D6FB30BA2E1BE5A7C6306EEC
-:10C1D000B443FBF4C8850CC4753543ABB351FEA61C
-:10C1E000DAE7CB2E7E1FEDDDDBB65ECCE6FCA007EA
-:10C1F00079DA2ADB31FF8EA811E9BFB59B30FE1D2D
-:10C200003EF27E07CAEFE548AA15EDDE67C7520386
-:10C21000A8EFAF1C4F09E960AA36E477D0679F19F1
-:10C22000C6EE66F871486F45FFCC7FFCD367501EA1
-:10C23000FD47401A61DEAD914727D0BEB545965EF9
-:10C2400012B07CE5FB9587F6EE9FB3F32AF54F7BA2
-:10C250004C22EACFCB02D7135BC387199EDD7AFD50
-:10C260006A95D786E7FCAF85A8CFFCBFBABA10F5B0
-:10C2700098FFE8D585D8EE7F3DB5530B9FBCEFD630
-:10C2800033BA2AF6B1E4AC2025F6EB95F9A3A4F76E
-:10C29000C9FA52A05FCDE81ABB5E8CB7D754E8BC90
-:10C2A000D8BFE6DDDAEC2D89E362423D7E5F305A8D
-:10C2B0009BBA39812F1F721B643D04520DFA679D92
-:10C2C0004CC375058FC7F455581702328EA0371826
-:10C2D000DE26A2B010FD7782CE3DE98F090CCF0497
-:10C2E0005AF5A10A686F8EE9247315F3EF038938B4
-:10C2F0008310EFF2B978DFF7E6DA7789CCDE931EA8
-:10C30000AC3F5411427B4F02A691F2041CB42EA6FE
-:10C310008BA600DF344552A28887D6C5840BAC2E8D
-:10C32000E3A30FADAF3D826E27E0A38B893807F002
-:10C33000D045355E22E9B85F052FBD87B80AF06C9D
-:10C340004B57D480F60A7092AAFFC6A61F5F423FE1
-:10C350006C63B7FA7B494CD0AD84739680BA433294
-:10C36000F4C7F698503E149C89F735A821EFFB5D81
-:10C37000FCBE1439EA8DE9D83DF4C65CA672289F4C
-:10C3800095E568D0AA230198BF37B2FA20FAE9BD33
-:10C39000D7D7A622BD7ACFAE223B50DEAD2E5305B5
-:10C3A0008EBBFE6353A32DCE1F93F4878BEBC73850
-:10C3B0001ED0B673CDF2BEBE2F7BB7D6F5C3B07715
-:10C3C000E0576F70E532BFBA99C73DB85F9D6C27E3
-:10C3D00014FDABCCFB847CCF93F5EF25865FC0FFCB
-:10C3E00065FAF70997C8FA4D8F346433BFF8EC9AB1
-:10C3F0006C316DF2FC65825D97659B3CBF82D7FC1A
-:10C400000169C4847E8CA467F2E95F434314EB5E48
-:10C41000CA70B67FBD2184EDCA7E626B28EBD768F7
-:10C42000A721338DE33F051FDE6C5F00ED2571BC56
-:10C43000A8E0C29897323F688D6460EDB9337C8F75
-:10C44000B86AF07C66F6BD66319F17F4C008FA47FB
-:10C450006B7F4A09D303325E54F833194F7E1E298D
-:10C460009BF64D71A3E764BE54E46B46925C28765C
-:10C470006A48B6D31D68A71D68A7BF36A21C4C85A5
-:10C48000BBC14EEF73B171848D5FF0AEE0D5F2BBEE
-:10C490006DB21CBDACDC5BEC0D27EEB798C4B6A347
-:10C4A000BF3895FDEC9771CC54ED43323EFC3639E4
-:10C4B0003E2B9FEFFB92E3D80F448E6FE23FA3F633
-:10C4C00039EF753BCF23FF5AF49D3127CADDAF0DFD
-:10C4D0002C6E9DDCEF09D91E833D53DDCF48B15151
-:10C4E000877E8FBF95C7018299E23BCC3F79534F3E
-:10C4F000709EADD70A194EBBEF5A262B838584DB7D
-:10C50000D1074B58DCE6BE97460D128C6FEEA2F3B6
-:10C51000311ED4DCAA3E4F30575A9A18070F160E18
-:10C520009C42B90A1C2C1371FE163C2CC6435A338C
-:10C53000433B317E81719C79F8DD12A703ACD32E89
-:10C540007FBF4B8EEF90241C7074F83C8BF7F8077C
-:10C550002941F93546407FA03E39CDE31D1D11AE7E
-:10C56000173EE936337DF289C0CFE1EFA6A1ED3465
-:10C570008E232E459ECA43399B842724C01379718C
-:10C580003CD1FEC2BB4C1F26E387AC41BE8EBF4DE3
-:10C590001FC278CC48F1428AF576F007F311278A5A
-:10C5A000E24F8AF8BE4888E91549152739701BB74C
-:10C5B000FB9F9FFE77E647360F5192CD7087142B75
-:10C5C000CF8BE38E8DC165CCFE2B3863E3CC532338
-:10C5D00045389F8C33ACF08BF1C3649CD1111E3570
-:10C5E000A05F30094F24E1880AB73A2E3853E07132
-:10C5F000D699116AC578D24C999E77F45B182EF6BD
-:10C600007CB0391BE55CB99FCB0DFCBE2E9FFFC2F1
-:10C6100089E3167E205851DF1E3DDFF5DB225E17D1
-:10C620004D228EEB4A453FE4F2070FA4223D8F4294
-:10C6300049405E5F3F2768C60FFF3E1E37BED38D61
-:10C64000F6ED61396E2C807D4B8FC75F92C7BD269A
-:10C650008F0B829BC1E28E4384F16FB0D0B78CD533
-:10C66000F79592832CEEC3F9F57024D38A78AF1234
-:10C670000EDB0D7AE21F2DA417F32BC15CDF5B4CA0
-:10C680003EF6E918FFC2789697091C1299BD4392AD
-:10C6900061FEA3CA087BA9267C3190B739F2BD158B
-:10C6A000821F8AF917D8CD9A1B40A74A390F5265C5
-:10C6B0002102CEFF98C1B7EB76CCBB0C0BF6ED3860
-:10C6C00046B06737A44FCEC70077B37D2979198A62
-:10C6D00079976FC8CB505CA78AF31BCBC31089DE58
-:10C6E000488DE75FC84FBD2C29B473512741BF73F4
-:10C6F000B187F0EF93F3298F3B35F229FBD0FE3061
-:10C700007DABCEA7ED9AFD1AE3B7EF9A473BEB520C
-:10C71000E64B5E5FE47E67D2FA0B323FCF63FECB1F
-:10C720007F7F95C1EC59E42AB33B57C653488CC56B
-:10C73000EDC6789C3A6260FEFA15F0837213ECD96C
-:10C74000974E4E87131137E3C7C1586D2AF62F96BF
-:10C75000ED65FFD935AB57229FC4047B05DB25F778
-:10C760006B0663420DC70793E874D0A5919F3259B9
-:10C77000B83E4FE6CF46993F1BDD9CEEEEF3DC5F03
-:10C78000F177F1FC815596377F27657AE554711E64
-:10C7900055E2C8F95AF985A171A6675BEEA5F68046
-:10C7A00038757E61B7EC6724EBA18EF0217E6FC9EE
-:10C7B00071DB7A0FD33BB71AB725E80D2F8CEBE965
-:10C7C0000145AFCCE571DC3BDC5676DEACCEF9CE74
-:10C7D0007C123FBF063DC55AAD3CDEE47EF3EA6EF7
-:10C7E0002D2FD829DD5ABF17A55B5B77F016FB9D6F
-:10C7F000BDC57E73B4E44CA35F8EF3D6CEF18966DB
-:10C80000BFFFA379D0E43C67725E3439DF99F2E66A
-:10C810009600B63D4A1F1F8F2275338E3451105932
-:10C8200021F30513CAC98AC53C2FD05F6B0AEDA757
-:10C83000F1FCA842AF020FC75F56DB44201BE83C67
-:10C84000438AD566833C5F594C98FF70C5CCF3038F
-:10C8500044B01636B0FBB316AE02BD1F346BE79979
-:10C860007E5D27E3E929F4C9128F733ACA8B1571EB
-:10C87000B9C63D1E96E394D63061711B228885AB04
-:10C88000D8BA6221DA9B696FF0EF195122ED67FB8C
-:10C89000124B56311C2D96E0FE76CBF9AFAC65B34A
-:10C8A0004A305E97057617F3234F619E84F901564F
-:10C8B000D64F59EFF95ABEDE6E03A198CF0ADCCEEF
-:10C8C000DF57907FB3AAF21B670CD18B9B28CB6FED
-:10C8D000DC81FB7F5B17B51D28E1F782F4B50D5AAB
-:10C8E00059DEE5378BFF61B68FADC3F31DDBACBC02
-:10C8F000CB49F437601FDB8E3918FF369F58FCBBDD
-:10C90000F5880BCB0546E749785CF6B3CEC97EA225
-:10C91000E2678DA1BF98E0772CAFD54DA59796D74C
-:10C920006AC8D56ECAFDE0C0DBDC0F7618ED659DE8
-:10C9300009F7B4B696F3C3A6288FC72AFE6D9514DF
-:10C94000D2E5011D1C0FE9A32960AF1D7D738DA8E1
-:10C95000B71D7DC516165FDA7C48A7D05BEBDE37C6
-:10C96000D5723BD27F7A9CE5270E27E5299FAF350C
-:10C97000B2F62C991F9FAF251C4F55083BD10C4F89
-:10C98000FB6BAB5E2B3EDE02F81FF7B729C8F7AB97
-:10C99000E4435AA2A21BD7B93032DE8765756B8992
-:10C9A0009BC50FDB26FAD07EFAAF5F3DB584C50389
-:10C9B0008C22E2ABE479E778F46CFDC30848905E22
-:10C9C0004B8510F6732C15D87D67B598993F9E65F9
-:10C9D00020FA34AC37707B565D9FE3C63A5993C951
-:10C9E000EC71F56931738B2DEEEF672DEDCA453A89
-:10C9F0007D5B9E48891BE4CE907620BF7DD73C515D
-:10CA0000FB99B3463CF78631759E48C9FB4C952788
-:10CA100052F2B4FEFA2F547965BF30EEC1F88AE3C2
-:10CA2000D8059627F687A9B5A0249E3FF20F4E1889
-:10CA3000197DE5BC11F437E2B8C11E9E3F3A02EB06
-:10CA4000631986F34AB08F7F86F3621981F3E2F7A8
-:10CA5000E33DB35919EDB1B3F244CF22563A806D9C
-:10CA60000AB330EF34C1F24E2FD5AAF3164A5EC294
-:10CA70005EE8FD05D229216FC1EAC9790BBD85FBAE
-:10CA8000A3FED306FB01F8EE3F63627AD619D934D0
-:10CA90001371D997A3BE99569607C8667EA5C20F93
-:10CAA0009725BB3913FD01AFDD8CF902C7F025A333
-:10CAB000C8F44EB4089F3275083123FAFD4807893F
-:10CAC000E139A719E9FAADF1FDF0FFC7F7BF4B7CDB
-:10CAD0007F5E5C2E99FEA8F6EAA4FD589E96CC5B7C
-:10CAE00012F443BF97C789FBCB4B99FCEDF19666D7
-:10CAF0006E4E8CE7D7733F2E6B69B939F17B97C7C0
-:10CB0000C0711F255E2D3DF6F5D4FAF66B2D7D4BD9
-:10CB1000A6C80BF4D7733DA2C4FD27E709EC6F96B6
-:10CB200027C4FB2FBF0D7C0A7EEBF0500AB3E75FF2
-:10CB30001E4B3980F8BBBA7EF3CC74A8579F4B21AB
-:10CB400025DC1EA9F20BCDF53AC99CA1954F908A20
-:10CB500074C0B793F206F53AA6DF6FE60DEA850BCF
-:10CB6000AC2EE3F40D137F482FA148FF5010FD8C2D
-:10CB7000C3EDD43E4C26E71160E222B2084E517F4D
-:10CB800096E595ED9DD42E8ADF9E5FC893E30C1D3C
-:10CB9000E14C3DF279CB1B84E0BBADC979867A8646
-:10CBA000F7ABC993C15A7C8F55AEB3A23D4B8E17DC
-:10CBB000209FA0FD4F8E13CEABE3F7384FC62B61FD
-:10CBC00019DF57CBB84419977CFFBD75EA7C4472D6
-:10CBD0007B97DCDE5B5FDD8FF71758A12368077A50
-:10CBE000EB5DA6F284F95C75FC1DCD6ECC5BE42494
-:10CBF000E62D787E22395FA1E829C7F0D71EBCFF59
-:10CC00003D111E4FF217F0F8A6E3B8F334CA7D7C4D
-:10CC10009FDCDEEE813B8E311C65CF24FC5CC4C4FE
-:10CC2000E35E2CCE50BDE28B13A9483F2FD82BD406
-:10CC30004B67CA77A6A13E5921D45091C5BB6FC698
-:10CC4000BF313EB5FA9DD66504ED7FE3FC51A47B70
-:10CC5000E37A037B87A4D8ABD5EF347978FBFE1D4C
-:10CC6000166C9F4DED6611BFD7BBF0FBF257A218B3
-:10CC7000E9232B91DA2037B13317059497DC19BEDD
-:10CC80009FA17FE46890E3E0EBB97D6D8C34184898
-:10CC9000DA647B77B2F84BE6475F8D38587C3B1BF4
-:10CCA000F3AFB6B8BD701C033B94FE97B343BD759C
-:10CCB0005646CF796087703F590D3C4F987CFF2EC8
-:10CCC000F9FEA7B22B53E951B423BA455C6E684113
-:10CCD000DCFE8AE85FDF11B7C3D630D4F3BF21EEA4
-:10CCE0002DE3ACCC2970D82F657E9FF2FD46F8FB72
-:10CCF00089831FAAFB81C4C1653F4789872B7E5169
-:10CD00009A8C639532DDC3E9FEBF7EBF8CC651F3BA
-:10CD1000FD7296F6FBE50D03147186F27E79C44828
-:10CD20009C8772F0DD1E25DB51BE430D0CE78C3C69
-:10CD3000FBFBBE97E17BC720B5A2F9691F1865769A
-:10CD4000BA1D700DC343914F799C6A80BF376D0F38
-:10CD500053492B0EBA40B6CFB512617AA35D7ED788
-:10CD6000E719E4721D8F13FD5C488C13F9C558AEAA
-:10CD7000F25E30C4ED93E6BBBE0E32CEDE0376B477
-:10CD8000527B14BE27C78D92E3454FCAEF00A78C94
-:10CD90001B49DFEDBDDF9FEAD2733E061650E2CF9E
-:10CDA00005B53C4ED4E4A314E737E9BC6DECDDEFE8
-:10CDB000716AD57A3F9AEAE17667B91CBF7DD1C81E
-:10CDC000F9E1C53B297B4FBF9CF038ED8BC7F9BB20
-:10CDD000FA17ABF9BB7A255EABBC97BF3D1EAFDD42
-:10CDE00083F15AE59DBDF26E9E9010BB8786BD967D
-:10CDF00028E28DC70C0305288FCA7BA3A375DCDE50
-:10CE0000595248A7967C7E55E73C5AC7FAE9A6884E
-:10CE100077FAF23D1A71209FECB7157BA6C4E9A200
-:10CE2000275785D3593D19A7FFA5E2B547EAC8544E
-:10CE3000FBBF5F1BAF4DEA77F116FB9DABD3A0C7DD
-:10CE40004E397E924CDF1E8FA287A75B193FDDDC37
-:10CE50003FE1F95C39EE3522DBB920157F7717CB3E
-:10CE60007F1958FE4BD133C1743EFFDDB29E51CACB
-:10CE70007BE53268D08ED374C9ED730AA595788F9F
-:10CE8000952FA9E3667307D471B379E12C557D7EA4
-:10CE9000F436557FC7E952557B4D6C8EAAFD8E73D3
-:10CEA000D5AAFAE2B13B55FDEFFAC4A5AAFF685C2A
-:10CEB0001D375B724D1D3753F8DB091C9138CE6D61
-:10CEC000FA1B55BFA256F5B98A3BD5E79AD9AD3EB4
-:10CED00097326F49407DBEB2A0FA7C5918D7B7FD92
-:10CEE000F971FDF15A518EEB979971DCEEFA7233BC
-:10CEF000E2183DE631E1FBFF001DADB367003400F1
-:10CF000000000000000000001F8B0800000000006F
-:10CF1000000BE3146060F8510FC1D3F9191836F310
-:10CF200023F8F4C0C79819188E83302303C33E201A
-:10CF3000DE0AC46B80F83D0303C352203D078827F7
-:10CF400003711710BF048AD5B1623787858D81813F
-:10CF50000D884F02CD3AC54CBCFD8A7C08F6215E97
-:10CF60000686B5407C9497BE6130D8F00C41FAD962
-:10CF7000F50C6AD76ED181F73708B38A3330304A5F
-:10CF800020F8FD12A8F26CE20876960C6576950101
-:10CF9000F50300295128158003000000000000005F
-:10CFA0001F8B080000000000000BED7D0978544540
-:10CFB000B670DDEE7B7B49BA3B9D90952574802051
-:10CFC0002A4BCB1201113B2189010306440928D2C7
-:10CFD0006C2184249D01661E3EFDFF6E0842C4D173
-:10CFE000898A1AFC195F83E004079DE0A0139DC0A5
-:10CFF000348B8833E804C70597795F401E204212BE
-:10D00000A338E8F3C9AB73AA6EBAEB763769B7FFFA
-:10D01000F97FFF840F8ABA55F7D4A9B3D5A9537500
-:10D020004F149D9524DD40C825F8A1E5AB0A2124C5
-:10D03000255876489DC3E581C1F6B55E177119097B
-:10D0400079C06BC272BD379DB8AEA0CF47EB8AFCEA
-:10D050001642EEF7DAF1F9E3DE122C1FF59662F9CB
-:10D0600088D78DFD1EF29663F92B6F0D96F77A8B9C
-:10D07000B0BDCEBB0AEB372A0BD2605C425CA6ACDB
-:10D0800064423C2F0F1CB981D6D6678E4F9047D390
-:10D09000FA5FF5449F45DF1B2D17F987D206B9A427
-:10D0A000286B74B09F8AE78D4A5E5F80F3F8581D45
-:10D0B000EB67AA792D3B72BF2C3286E2395646FCCB
-:10D0C00089A564727672C47E8301DE2343D93C89CC
-:10D0D000DDF9DAA0C8F0AE06780F0DE5F825DB27FC
-:10D0E0000F8A0CCF09FD7EE5E4F0D23B0F0F8CDCFC
-:10D0F0006F0CF4AB7372787D7DA60191C71D0FFD97
-:10D1000062E013C589105F8BD19F9DF5FDF9455CE9
-:10D11000F42FC5A763AF79EB0609F9370DE8B4D64C
-:10D12000BEFCCC163A4E7BCB30A7DE41C8672E67DB
-:10D1300082DD1213DF6E8179C4C0B752182706BE94
-:10D14000CD8D916F0BA05F0C7C5B02FD62E05B6597
-:10D150008C7CFBD94F846FF7021EDF836F1B62D478
-:10D16000B75FC5C8B78D31F26D538CFAF6648C7C0D
-:10D170007B2A946FEA73B5DC4124B48B372A253BB4
-:10D18000A09F27B3CD3620EB27C1BF3DDF53EFF67D
-:10D19000C7C8BF5763E4DF11A04F0CFC3B1A23FF45
-:10D1A000DE89917F1FC4A8776DB8CE58E4AFDA86C8
-:10D1B00010FCB93400FEB5D84F5DCDEB7AC03B8989
-:10D1C000908C7039504BCA51940799B8DBD9BA5535
-:10D1D000F0CDA51C425698E87FE9FBBE3C12D0D3A7
-:10D1E000F17D36E2AF9584FE9F039E84E47F732930
-:10D1F00055E8EFD345EC4F74D0FE30C815E5FF6617
-:10D20000EF102CEBB91C6D2ED2A13CF8920D285FCB
-:10D210004F789DD8DEE01D8BE5635C2E3772397A3E
-:10D2200000E4EE0A90C3522E574CEE082971945335
-:10D23000BA76EC89271B1C28576609F09499BCDD47
-:10D24000BBE7CAAD1B28FCCD35BA2BB785C8D913AF
-:10D2500045AA7C51C94C0EF67BA2FC846DC150A43A
-:10D26000B70DE03414EBD47EBED07E0DEEEE7EBD65
-:10D27000A0DF63C55CBE6412081DF7B1D2EE7EE983
-:10D2800012A5CBBD12296DB284F3658AC4F4942A29
-:10D290000AF243E6F4DD9F7796B4D1F76DF6916913
-:10D2A00084964F827EA2FE39B054DFAFA7747653C6
-:10D2B0007A641A494D13E04B5A2585E22B8F752469
-:10D2C000821C3D34CE45242B21FDA19D8EDF677449
-:10D2D0001BC9A265E2F836220D837EB49DD6537831
-:10D2E0007BC650DA4EE13C04EDD6607B2A6F4F736B
-:10D2F000F0F7AF63ED0F7B098EAFF6BB8FF2D94D20
-:10D30000F15B47F1C5E7C5C4057494293BFD21F3E2
-:10D310009F2DE971DE95BC54F1BF2FFB54C6FCA1D3
-:10D32000417CCD832F66CC0FC1EFBEC173B0AEE29E
-:10D3300063BEA212EBFD57F5A69E18D707124EE763
-:10D34000D49903847687EC443FCD71444F7C945F3D
-:10D350000E2A9E91F8F30515E71F54FF5C8C1EDA28
-:10D36000F6BB3574589721D2C1D05BA4C3BADE2274
-:10D370001D0C7D2E4F87299203E147A3873AEE8645
-:10D380002BC571E3AE12C7DD7095386EDCD53FCC8E
-:10D39000B8EBFB89E31A33C571D7678AE31AFB7FC1
-:10D3A000BF7189ECA40F99B9200EF8679E60DF2E3B
-:10D3B00010F7C3A0DF60E7F4C9413B27DB4B88DBF4
-:10D3C00012E42791E9CB39A170EE14EC2A85F37FA2
-:10D3D000381CD7E5E1D83570E66AE16CE37048A8FF
-:10D3E0009D0E8343EED0CEE3B7FCBD802E647CBAA5
-:10D3F000BE92126BE87B4ECDF8B76BC7DF0D760C93
-:10D40000E6A1BBECF80E0D5DE768F1D9C3E110DDD4
-:10D41000E5E841EC1A38B3B5700E713801E9B27025
-:10D420004AB5F3785DE5AB24AC5F941EC382EF751B
-:10D43000E4759E423FE845C5B19DB64B7FB2066E8E
-:10D44000A0FD8F6C91FC465A0FEC8DC7F5E3FCB63E
-:10D45000E958DF778D11D789F3CEC97E23B527939D
-:10D460005E78DB06F6A5EA05BD0C75DDDE8F6D6D19
-:10D47000142F8FB1F5C1EBE8F3CE17F4642B4A6398
-:10D48000A10EE87E8ACB2659C5EA656656ADDAB2AA
-:10D49000EF4E805BDE6C24660AA7EAA525D3AEA317
-:10D4A000F5258715025DAAB6AF36F4A6F5A57EA9C7
-:10D4B00009EA1D79A41CF469CDDEFF6C87F5E8FC50
-:10D4C0006E251BC63F4BD70907B5C747ACADA9337F
-:10D4D000291E15FE5D85F05EC54EC9492D1CC57718
-:10D4E000FBA10CC07787E434527A2F6B8C270ED5C2
-:10D4F000DED1BFA776EB71FECBE9FC0985B784D4FA
-:10D5000017023DAB803830BED3E8374B417D3BEB53
-:10D510003D8CE3A9F5AA1D743CFA7EF5739213A61F
-:10D520005AAD236EC0B3FD2573E9531698E76AC35D
-:10D53000602BCC6FBD01FA2DF1CF7FD1EC003CB751
-:10D54000180A01DFCD5B0C6543817E645EC950C063
-:10D55000EF2F227E0D7A17CC77F935C6AD7AE0A78A
-:10D560002530688635DCCE9EA5EB952364FDAC2086
-:10D57000CCEE13D96F983E2CF8FC257D22CAC1B29F
-:10D58000463D7184DA0D2E1FBEA384F9317BACFEBB
-:10D59000ED59413E2EB77379E57C5C9EC8F92A7738
-:10D5A000E6CC18168ECF83C01723F38FA07C98AEDD
-:10D5B0009B0EF47F1C48BFC7A8FFE440FFC889CF7B
-:10D5C0009FA07E12949BA99F04E593D44F82D24FD3
-:10D5D000FD24E8B795FA49506EA37E123C7F9AFA73
-:10D5E000E7503652FF1C9E3F43FD7228777A7DF844
-:10D5F000FC396F1D964DDE7A2C9FF73660B9DBEB58
-:10D60000C77E2F7A1BB16CF636E1F397BDCD58B6C5
-:10D61000780358EE053ED332E06DC572BFF7189619
-:10D6200007BD6DF8DE21EF192C7FC9E96E9B4072B2
-:10D63000652A2F3617B1039B928A5DB9E0AF249516
-:10D64000B07AEA1DBE5C03ADA7BA699DD2B1776519
-:10D6500020D748EBBD6B587BE63D24CF44EB993E89
-:10D66000D63EE097AE3C33AD0FA867ED8337FBF2B3
-:10D67000E2687DB09FB55FB53390174FEB5735B17A
-:10D68000F6E12D649285D68707587DE411D7242BC7
-:10D69000AD8F6C65F59C0F7D936CB49ED3C6DE1F79
-:10D6A0007F2E302981D6C777B2F6895F937C3BAD58
-:10D6B0004F2412D6F32CB9F989B49E6767F5C2BE20
-:10D6C000F3654784F57DAFD2B6104CDACF7539B922
-:10D6D00032F513F61ADA5680C95DAFBB21571E47E3
-:10D6E000E9A79045D0BE4957C4EA06B212DA7FAB2B
-:10D6F0009B8EF5FD8A03DBF7E8E6B0BAC181ED7FCA
-:10D70000D52DC4FA41C585EDC77595AC6E7061FB2A
-:10D7100067BA9FE378871437B62BFAFFCDEA06374E
-:10D72000B63F2CAFCFCDA7FD2BF56E8F8ECA75AD52
-:10D73000E42E2703415E9BD2C11EAEE37EEB2C9DFF
-:10D7400003E57E5D8601F56CEF7FE53C857A063F5B
-:10D75000C9502F7B1AFC5E0A6715C251281C7DCF69
-:10D7600070267E33568033F19B7215CE6A84638EA9
-:10D770000DCEDE6FC68BF87C53A1C2D9A0A3F6BE36
-:10D78000D61ADBBC265E9A20E273A95285F308E222
-:10D7900093181B3E01E55A014E4059A2C2D98C7024
-:10D7A0005262C3C7651827C0711996AA70B6239C28
-:10D7B0008CD8E0040CD789F81896A9709E43FAF427
-:10D7C0008B6D5E2EE3F5223EC62A15CE1F109FAC50
-:10D7D000D8E0ECB78AF4D96FEDA64F00E164C73604
-:10D7E000AF3C9B489F3C5B377D5E433857C606671E
-:10D7F000BF4DA4CF7E5B377DDE4438C3629B575E4E
-:10D8000082489FBC846EFA7C8070AE890D9F83290C
-:10D81000227D0EA674D3E724C219131B3EF9A92258
-:10D820007DF253BBE9731EE18C8B0DCEC154913E4A
-:10D830000753BBE9F305C2B93EB679E5A789F4C938
-:10D840004FEBA6CF258493EB6E447C0885638D0E49
-:10D85000E7503F913E87FA75D3C7A407380514CE29
-:10D86000C09EE114668AF429CCECA64FA21EF46295
-:10D87000726C700E658AF43994D94D9FDE88CFD4CE
-:10D88000D8E655D85FA44F617F461F8FB173921DB4
-:10D89000FCC644E2DC4A5F9994FCB383B0EE2816E0
-:10D8A000E204B047A4C036804FD756F44B65A7EAD0
-:10D8B000073909F8B9C5368713E2017AD5DF21ADFA
-:10D8C000B81FB1EC4C14E24D2FE9F38603BE56EAC3
-:10D8D0001586FA3D0963E3047F2BD19524D47B158B
-:10D8E000F516FAA7940C10DAD34AAF12DA33DC2318
-:10D8F000857A9FF2F142FF7E357942BDFFAA294227
-:10D90000FF2CDF0CA13EB06E8ED03FBB7E81D07E5F
-:10D91000454385D07EA57FB950BFBAF15F85FEC370
-:10D920009AD608ED239A3708EDD7041E16EAA30EFF
-:10D930003F21F41FD3BA5568BFF6D83342FBB8B6BF
-:10D94000E785FA75675E16FA5FDFB95FA8DF70F1E9
-:10D95000CF42FF5CF237A13EC9F481D0BFC0FE9137
-:10D96000D07E63FA271A3F568C5FD4E612E6CF6664
-:10D9700018D09F0D580D5837EC35B3FD0DD49321B9
-:10D980000E518C75C3FE858E6488070000EA4FE453
-:10D99000F62EBF02E255BF18EFBE02E2B8BF30B8A4
-:10D9A00047D823F841EDB2FB1E3DC6135B25920E0E
-:10D9B000A54307659C9EC7138C4C7ED767E53CE565
-:10D9C0000BD183BA7ED4BFA0F5F57A8AC798A0FEA2
-:10D9D000ACEF57963E3F649C75FD0CA55B87B2E7A4
-:10D9E0000B2D305EC97D309EC7D03918F0D28E63C2
-:10D9F0001C305618C794598EE36C84715282E31818
-:10DA000033CB35E3984AB7F2E77C9CC7406FA28DD1
-:10DA1000B37EC078713E991538CE16CD38EB332BD6
-:10DA200034E3C4B1F9D0E77C9CA72E378E71E004B3
-:10DA3000713EFD2B719CE7B4F3E95FA919C782E33E
-:10DA4000C0731887F4A5BB9834CA67636719CAC145
-:10DA50009FCC182733F4A9F80DD4C90766920DE3BB
-:10DA600038E8B8B41F199244859A907FD127217F56
-:10DA7000BE88A3FC0F89A705F7E33EDCD72FE62875
-:10DA8000123FC588EE93AAB96C2EDA393D738583AF
-:10DA900096CD07063D02E36CB43AB369BDBD7992F9
-:10DAA000616104795A5CAF9C6A0B91F3EEFD591EDB
-:10DAB000195243C75F1167477CD4BA5A26E9C4E7B5
-:10DAC00027E8BE8BD0FDC987749F42E87EE5238599
-:10DAD000ED33FF9DEECFA0DE46F767D04EC86A7CDF
-:10DAE000EF048F339FF8A5E4077A7F71D7CF145CDA
-:10DAF000277CE4ADF4548826B09F79ABE2291382E9
-:10DB0000F8CDF7F512EAD41CF7D1A5E3BE16E3076A
-:10DB10009D2F19FD5B81AE757D284D79BF0184BCB9
-:10DB2000BB77EA21C986D53EBAB184CCAC995E9068
-:10DB3000865A24F55B4EF19CB1FB1A85BE41DA95FD
-:10DB4000B63B9D96205CE2524E007D4CF40FC0B96E
-:10DB5000A588D643C6BFB544ACCF2272B04EF97D7E
-:10DB6000523F80B0F83F1FD7E15280AF25748E1925
-:10DB700094D5B3A01C09CD2C5E536A67EFAAF87840
-:10DB8000162A2480FB6B5F0AC4B1892F19FBCD5183
-:10DB9000F7C91AFC4A1593AB84D2B574BE1EE9AA24
-:10DBA000C5F7FDBDF12EDD705AD63DA24068B627FF
-:10DBB000FC67BBC57652CEC653E9AACACB29CEDFD5
-:10DBC00013C07F5A9E06FE53BC4F72FE07E598F1C4
-:10DBD000DF63744F03FE776ED213E417E7FB6D9C8F
-:10DBE000EF8BEB45BEDF06E771B4FF6D2BB358BC7E
-:10DBF000A9A197C05F3A71910EF50F1550B31A861F
-:10DC0000FFDFB91CCCA9DBF50AB0F7F672CDFC3802
-:10DC10001FEEE47C98ABA1C76D9C6F7339DF961043
-:10DC2000DFBD1918BFF02B10D79B5D2E11B0179ECA
-:10DC3000BB55BEB5097C73AB7CD3E07B27E7DB9D8E
-:10DC40007731BE69F16EE37C6B6BF84C2103C2F156
-:10DC5000D6E2396F95665E3E2DDFEAB95CDA0DE0FB
-:10DC60004F4D77E5AE3819D2FF96A2C92B4E86D814
-:10DC7000855B4BA60BF559A5B385FEB3DDF385F6A1
-:10DC8000DBCB970AED736B7E26D4E7ADBA4BE83F4A
-:10DC9000DFB75A685F58779FD0BEB8FE21A1BEA4F7
-:10DCA0006193D07FA97F8BD0BEAC7187D05ED5B495
-:10DCB0004BA87B9A5F12FAEBF65E7933C8D791B71F
-:10DCC000F504E27D179CA731CE78C1A938A1CF49D0
-:10DCD000AF03E5F89477089667BC4E94F3B3DEB1D2
-:10DCE0005856834C8E033B7BC002F1534F1CB5FB4F
-:10DCF00089741D97C7ADA99B00EB0D6D1F4FC8BF61
-:10DD0000CA37ACF1F5A55A00716F4AFFE206030964
-:10DD10008C2254BA7B77CB73A73EA4BDAD87F606A1
-:10DD200099047A85B717B7457EDE21750ECE80B887
-:10DD3000EC7B46B23D24DE187EDE42FA805F11ADF8
-:10DD4000FD9C8E94879EF76C95D939CF117DDE5658
-:10DD500099E2556960FA5FF97C461EB1413D30B8E1
-:10DD6000C67299F19A283269C0E78182DE2F69B8BC
-:10DD70003AA8E704C661F674A97F94F07C59E3756C
-:10DD8000C27B6F48EE2D80C7B97D7A5CAF49E04019
-:10DD9000E62DC3003FD75619D6D1E614F4BB5ABDC1
-:10DDA000AE15271542DEF41661F996B704CB77BCA1
-:10DDB000A5581EF3BAB17CDF5B8EE587DE1A2CFF17
-:10DDC000DDBB0ACB36AF0FCB13DE3A2C4F7AEBB16B
-:10DDD0003CE56DC0F28CD78FE5596F2396E7BC4DBB
-:10DDE00058B67B9BB154ED674FF27786AFAF674172
-:10DDF0000E8DE1727670EDBC35757D837276582E8E
-:10DE0000433953E95BDC60E4F2902AC8C35F611DCB
-:10DE10004E0179E9A1BD41E17218EDFDC8ED206F19
-:10DE2000BD7F047923640DCA8105E4EE7BC81B81A4
-:10DE300053841490A73E1A7912E550952355CFDFED
-:10DE4000904ACE817CA9726591993FA4CAD5FDE024
-:10DE50002746F0B77A2B125FFF987F4402B93A2029
-:10DE6000D9727E5E417C2EAC77F1B16B29B856E851
-:10DE700027FB87C03AD235E4ABC110DFEF3A4685C5
-:10DE8000202BFAFCB4F2129DEE2EDC3F94F929F31C
-:10DE90007B85B79BE3185DCD3A524446C2F972CEFA
-:10DEA0003137E567DC9FAE1E09FB66FA5C26490048
-:10DEB000C7EF9C1EE1BC800C2248E79EE8ABF63F12
-:10DEC000F5C47FE6C0B9BF05F49CCE3DEE80BE86AA
-:10DED000E9EF53CE5B42CE973C46673AC4C13BB3B1
-:10DEE0000D76E63F4C12E94826E1F9814AC703D98D
-:10DEF0005F0C86F399FBA81C827E750D1A9C402E40
-:10DF0000231F3DD9FB9EE8B900E61B133D0D04CE4F
-:10DF1000B9283DB7C27DC758E9D9939DECC93E9E4B
-:10DF2000D8C0E87C84FBA7D1E8AC9E8769F1B845EE
-:10DF300091391FB81C933B34F42F15E8DFD7EAC0A2
-:10DF4000FE07F77E9009E7785DBBAF48204343DFCB
-:10DF50002F60E73DDDEFE70B7A20FDE9EF99B03F59
-:10DF60003EF8C2BB58AE254C0F375A4AE62A6382A8
-:10DF7000F062BD47106D5E1E4512E7D5837E76A424
-:10DF8000AAFAD99A09F2B49BDB81B0F9F5209FEA8D
-:10DF9000FC0EC0FC289CA920D3741EF972C95DC276
-:10DFA000FC46A7E0BC7B9A9F27C140A411143FAB5D
-:10DFB000C14012A83C2AEEB50AEEEB9C6D3E885398
-:10DFC000EC8D77D65296786C67DF0838E03D319E4D
-:10DFD000B1ACD15C23FA4F8935A2FF945113EA3FCB
-:10DFE000751D7ECAE6A6F82D4FD7D79CEC05EB9C95
-:10DFF0008BAF736C5D55F1AB6ACAAAB10870C47A75
-:10E0000057BD54C4EEE13812664638EF53CBE5E90C
-:10E01000061CE76CE3C00418F7ACD754C3D6577B93
-:10E020000D1B37BD26747DAD5C155F73725410BF38
-:10E0300068707F68FCA844908F4CB02ED2B681D116
-:10E04000FB47E5A7FCB901CFD55B942FC07F370F05
-:10E0500051FD7719EB2A5C4F93DE671C01CF770ADD
-:10E06000E3D1F71CEAD938BC175D6E64724AE5A7A4
-:10E070001ECEBB08DF1F9890CF6E0A3181C2EB9095
-:10E080002D7520577E85E9B387CB6995A9CDE076BC
-:10E0900020B95B41AE178C55E5DC31EB036AA73F35
-:10E0A000FE8B82F7CCC8D7147A4EF0AAC3225262F4
-:10E0B00083A0EA82DDCB8A61DDFEF8C59BF83EBD18
-:10E0C0003E07E67D9EE88AC02E9D276FDA4685E8EA
-:10E0D000EB6985C5B1481DDBE7F8E81F98DFE27AF8
-:10E0E00071DFB3A441AC979119A9606FCB362AC4F4
-:10E0F0004F715F0AFB2675DED4FEBEABD811B92581
-:10E10000A4661DECD31F5358BC67819DC87DA8BD74
-:10E11000AEFAC3AF7320EED3AE307F573D0F5F9A98
-:10E12000C4F6831533FD0617EDFFD1EE51B7518BC1
-:10E130004BDFF7AF43FF673A716E27E1745F5827F3
-:10E14000E2D713FE5A7C553F28EC5C9EE391DC2815
-:10E1500045BC2FF535B773AA7E2419EC42DC274D58
-:10E160005357E540E172E057DC56430AE33BF05178
-:10E17000923B0DEE907E8660BF24C398E8FD8CD064
-:10E180004F8FFDD258BFCE42DC1F132A4F4383FD71
-:10E19000CC41787DD9B862BFAA3F3CFBA28FCA4B65
-:10E1A000C5EF1EB511BA6E7E2CD7A73AE9F3CAEDBA
-:10E1B000F7DA5CB43C23FB6CC0CF8FFDFA88F77DA7
-:10E1C0006F31A8F470592488A771F924753E8C53D7
-:10E1D0007CB15DB1E33942A33160A4F259BD7B69E2
-:10E1E00031198EF5E3ACBEFE533DD49B457E55FC04
-:10E1F000E6D15407BB27C4E24924807E6EF5B6FF02
-:10E200002884F5C2433A51CEB4EFC1F8179350AF0A
-:10E21000E71B12C2DBF162702ABCCF7E3CBBEFFF72
-:10E22000546F8372F269D0238F464ECAB9DF0AF465
-:10E2300082FD7EBEC19A8CF6FE5A722DE8BB4A174B
-:10E24000E267FE6BED8EC7871FA7789DDBF6179BF5
-:10E250003434D44E3079EB6A5AF86F265D747BD231
-:10E260004EE531D44FA280F13D4733F7BB5B58599F
-:10E27000A9046C701FA7728BE2A492482A9FD51341
-:10E28000B89F40DE33FA213EBAECD957DE194FE988
-:10E29000BF6C97925CCCA663915283FCF1D0BFAB6C
-:10E2A0004606F951F1FB570C8E61ECF93D4941BE30
-:10E2B0002CDBB5CF408685D37152D33E439B2502DC
-:10E2C0007F9A8E17C27A5BBBE31F06882B7EBC57F2
-:10E2D000226959E1EF976F7905D73DA013F293F3C7
-:10E2E000AB9B7F617C0B4C7B7934F6B3833DEC892F
-:10E2F0006FD9B09F4B41F97EEE65B8C7F4BED10926
-:10E3000074287F6E850DE6735AAE6172FEEB7B5307
-:10E3100041DFCB155FAA1D4BF6BCFCC99FA3FC2DAA
-:10E3200039FAF354F41F882B4387B6D99701F35C6D
-:10E33000BCF9569C671971A31C96FF5A5F02F74CF3
-:10E340002FC8A46857043DF98B81ED5F4E6FA5CCB3
-:10E35000A5F33C0DF8817D7B53EFDF8E71F39FE1D8
-:10E360003DB89FF339D39510EB174C8C5F5B0C3A9B
-:10E37000351E6A12E477DBFA56E0D3D97EAE343824
-:10E38000F7A074F071BA4997285CFDD18234C62792
-:10E39000E29073F87BD4DE4F82E7D0BF5571998746
-:10E3A0000BEF71FBC8C65FC9C7A778C7C1FA753A3A
-:10E3B00035B2FFF70F3E3FFAD34A42E42C44DF99CF
-:10E3C000FE6FBB8FE9BBAAFFFEE945D0FEF95B4CAF
-:10E3D0008FE03D582F285E81346CDF375342FB407D
-:10E3E000F7D991F47C9BC2F55C6CA73B1C5CFF5594
-:10E3F00039A1F8CB5242A8BCD07192900FB83F2EF1
-:10E40000DB48DF0FF1CB3C302EF633049F87AC1B8B
-:10E410004BB85D38A4B10764734A4C7E74A5E27FA3
-:10E42000FA09D0DFF78C4E9F03F4572981F97FB2A8
-:10E43000F3C03B73A89C7FD2A4EAAD6857B57A5B62
-:10E44000FEFC1812496F3FB1D07D5724BDA5CF23E4
-:10E45000EAADA50DE5F9FF965D55E9D7AEA11FD848
-:10E46000C7971DD1E9A8B58F1B0C8E88F691FEBC0D
-:10E470004572C2E550953F55EE2A7E5BD51FEC50A4
-:10E48000B77CAAF2D72D9FAAFC69E72BD24FDBFEFF
-:10E4900007D06F8AD7EDA64DD3C07F3675128CC3D7
-:10E4A000E7CED4E33D4DD3E784DDD3B8231EEBB3F1
-:10E4B000F46DBF079FF083AA59C3609DBF9DF814F8
-:10E4C000766E5FAFA01FFBF5A54B13E87CE670FAF4
-:10E4D000DE4EC93D95F2A35496027114CFD932F1A4
-:10E4E0002524413C59222742F0B8BD5CACC3CFC4BF
-:10E4F000D4209C9EFA7F5BBFFBBB9647295F4F648D
-:10E5000013F2372871FF411DEB10799ADEC2CE312C
-:10E510003CA325FF00D4C336B924641FE13132FB8C
-:10E520007334FF963140BFDC59C312989C0FC6FD6F
-:10E53000A287DBB12E9F2301EC7B57CB40DC177603
-:10E540001D5E687547B06707B89CBDC2CF613A2CA5
-:10E5500052BD9ECA7D07E944BFC66731478CCBCD0B
-:10E5600031AA769AF38DFEE8E9F8A55C0E67D357D9
-:10E57000134686F06DE6D48F655B381FE0E744C82C
-:10E58000BEE2FBD217E41AE87BC0DC565812217EAB
-:10E5900053C9E93771FF970658F7F25B7265A063BC
-:10E5A000BE452FC4431619B9BE0E254301AF89FBE2
-:10E5B000973E3086CAB1E7B0DE69A6F3F3B47C6A51
-:10E5C0007047D8DF69E909F0C1BFDC6A64FEF2DB9D
-:10E5D0004AC962A0EBDBB7B2F3DEBF199C5591F0DC
-:10E5E0004C37337F733629B9305AFAE9D1377796E9
-:10E5F000359047E9D16561F7B5C3E58FE97D975D52
-:10E60000F2AF96400EF5AC9ECCEE371712F703131F
-:10E6100024D4F71B42ED576EF3F467E13E4D758B42
-:10E6200064D7D1F66AB9CD0072EC69DE2583DF7E4E
-:10E630009383B8707F2DD70C9B1912FFA2CB1ED2EB
-:10E64000EBC05773E6027D3F9B692480976BE8A778
-:10E650003658FF3F6B19857A106D5EAF7BC9B47C6D
-:10E6600005E0307BA69587C2E478A17EEB24D21723
-:10E67000CE81271ADB563823F02FDFC4E42C66FB4B
-:10E6800066FAFFCCBE4DA0F68DC9B5126ADF2CA686
-:10E6900030FB9616C9BE2D5FED4803B958BE672002
-:10E6A0007EBFB5FCB5C52991ECDBAB7CDFFB1ABFA7
-:10E6B00007DED197DAB71121F6AD2FB56F11E2E47D
-:10E6C0005FC46ADF4CFF33FAF72AD8B708F3359BEB
-:10E6D00044FB56D4B21AED5B515FBD705F8998A8B8
-:10E6E0007D8BBF9C7D9BFFE8AD58579CF111E407E3
-:10E6F000E80AF6ED356EE7601CB0733798587C3346
-:10E70000563BD72F563BF73F4467D5CE2DEF27A179
-:10E71000FF122E87CCCE2DCF62766EF91E66E7965D
-:10E7200067333BA7B56F7961F68DBD5F3D84BE8FC2
-:10E73000FBC7ACC7EF80FB84A58AD344FB173BD44F
-:10E74000EF276AC684DABB1B4C32D239CCDE393FA4
-:10E75000C5EF607AB2777F057B978D766C10E89174
-:10E76000563EA60C8A17EEB3BDFDE5A9DFFE0EF4FA
-:10E77000E5753DDE177A57C7F6477BBF3C350AF48F
-:10E78000EE2113B3BF4B4C8C9FED5E1FDAD3494390
-:10E7900099BE57DDC3E857BD5B62F35DA9F73B60E7
-:10E7A0001DF8EA22EE9FE7EE61FBE759C6D69478A2
-:10E7B000B897F42F0A61DF7D90E2F921F2507AB127
-:10E7C00002E380CFC7D9B6C2FEB2542626F063E773
-:10E7D0001D9EF231F8AFF32ED6A1DF3B0F9EC33959
-:10E7E00009BF27A1DEA398D3BCEB953E24FC7EC4D1
-:10E7F0004423E3C3C415927F4B16DC4710DBE76963
-:10E80000FCFA757C9ED49F45BA90BFEA23C6EFD62A
-:10E8100069E9E164F3AF5AA917E9512345A407E573
-:10E8200068F1FCD4E0FCE7BED0B6AE0FB42F957013
-:10E830003FA5D2433B4F953EEA7E651ED7114FCB95
-:10E840002E05F8A59DBF4ABFB079ABF4D4CCBF4E1E
-:10E85000B51F579361A06FEFEADC0F8C01F9F83315
-:10E86000A503C5EBB6D9D969A1F6F8416E97A6BA4A
-:10E870008FE7A73A806EECBBC439E5BB5E49A5F3D0
-:10E88000B9D9953512BE1FBEF52B831BE20B07CC01
-:10E890009D68DF54F9FA84CB7B80C379BBB73D1FF9
-:10E8A000D79166C98E7A13D0D82F7E7FCC730FD3C1
-:10E8B000AB03D23FD6F5198D7485658014AAEB1091
-:10E8C000F081FE776A0BE38307F840FF3B8D741EEF
-:10E8D000023A57274BCE00F46FDE752FC8CDAB66DA
-:10E8E000FA1CF4B75C72B2EFCB882523F5B2F2299B
-:10E8F00047924F0C4EE404D7C579D02F29DCEF980E
-:10E90000686C7D1BF09848F5610B09F74354BE0F06
-:10E91000A17F2E45BAF7D3831C7FCCE5F355A0B772
-:10E9200005E8DA69007FC61360EB87DAEE911DF91E
-:10E93000481F95DECD747D18CDE8AD8B40CF9BD5BB
-:10E940003AA7A7A74552E0FDC974FFDA4B82D3ADC1
-:10E950002F0FA9720CDFC369E901F1808C10BD078C
-:10E96000FB147A3E59DD7C14E932652575AF42E827
-:10E970000E76EB72F489A617D5CD3F8C5E7CA2D1C2
-:10E980008BBDE6CEBF8C80F8D71E09ED0369491414
-:10E99000F6FBF166E6671C30BB517E3B5F53F0FE31
-:10E9A000B9D68E7CCDE51EF617A1DFFD4D8289809C
-:10E9B0009DB39BC9472A1E03981C85DAEF57CD6E7D
-:10E9C000E45734F8717C1D8EE63FA9F51B613CB815
-:10E9D0008FE810C70BF32F78FCA7A779A5F171BFBB
-:10E9E000EBBCBACF3349AB81B0F8FF0A63C8B9D4E6
-:10E9F0006DFC5CA03B4E16EC67375DA61FC45F0242
-:10EA000074DEAFEE7C0AE3BFE79F393E0DE477D9B1
-:10EA10001FF5C444F9DCBED34A02ECDE8501D6D929
-:10EA20008ADDFA88E72884D4B2EF1C7F6745FB5261
-:10EA3000F1BCD15F4CDFAF78F1A3E110B76A5FC3DF
-:10EA4000EC8CEF192E1FBEB6E170BE5E21B3736170
-:10EA50002DBCEBB8BC9C7B29BE14ECA4D4C8BE5F13
-:10EA6000AD689AA51843F6E923CD0A8E4BFBE1BDAC
-:10EA700065DF0E09E3E5E1F8AD66F07630FB57D1CE
-:10EA8000ACF8E13BD88AC62DB8BFF5347E6A00BF2A
-:10EA90006ED2EF9E65DFD736EBC5F861A33E60C44A
-:10EAA00038A7FEB87138D35B49884755A15E563701
-:10EAB000F13899267EB4EC777B5EF451D22CFBFDC5
-:10EAC0006F6C606FCEB66EB7617CAE91C5DF648B44
-:10EAD0001C393ED7535CAEE93E1E979B7A9A0C0FC9
-:10EAE0008FCB9D85FF503D9C6FE6FAAAC6351B7BF8
-:10EAF000C5747EBEECD90B4FC279D2B9E73F79120B
-:10EB0000F0AFFCE6B327EF867389BD663BAC7F9E12
-:10EB100067DEC6F8BBFADEDD5CCEDB77FCE6E92714
-:10EB2000A81EB6BF67C47B5BED7B4E67C2F78CED5A
-:10EB3000BBBE4C85F8E6CA3D05B89F59F9C2A4B4DE
-:10EB4000CBDD3F01F9F4C7707EA2E5C781DD7A0213
-:10EB5000DF739E3F6644FFA33BCEDA54C5E2D70E77
-:10EB60001E5FDD19F9BC4A8D0756EFBEE5E6EB6185
-:10EB70001DDCAD381DF89CC7077B8AABBE45F93A52
-:10EB80002206FEEDE4F1F3A6A911E3AAE7E13F9422
-:10EB90004F9BCC625CF5C2EEC5FFF604B4EDEE15FA
-:10EBA00035AE1A88816EEA795899D9B5CD0CFAF14B
-:10EBB000FC6F318E0D7CA33E39697FF64226C4235B
-:10EBC000CE289D77E23DE53D46BC6754B1E75DD474
-:10EBD00097F6178EE23913E1E751EDA4FB879D1BF1
-:10EBE000F0BD8E679B95C56339FD215EEBB0E17387
-:10EBF0001E976572ACC66BA3C569DF37B3FB50EADD
-:10EC0000F95CD5B60F0C4413FF96C602BF8E0BE716
-:10EC10008AEABCB5F0EC40876B43CF1FA2C5C3B9ED
-:10EC20005D0DE3173B7768DFC2CF23BACF1908E940
-:10EC30003B12CEC7D9B9B9C72FBD1B89BFEAF9C3EB
-:10EC4000DB5AFDF4C776EED033DEDF8D2EAF9AD9D6
-:10EC5000FE56A5CFB9AF23DBE94EAEEF749DE93088
-:10EC6000E3B9315B67E6F175A69AD28D7DF7C6F000
-:10EC70003DC7F781E79ED1FB61BFBCAEE900DA5B1F
-:10EC8000AD9E571316FFD28E27C531FFA0BA79DF8C
-:10EC900070B047E7F6BF84F257BDF3B8C147E11C37
-:10ECA0006AFCBDA16D6850DEC18EFB43ECF8B9E78C
-:10ECB000F60D67E72291F3B4D8387C4F8B08DFB3A9
-:10ECC000F35301FE325F93C16EE9799CB3B26B16C8
-:10ECD000CCF76CAB42E03EFBD9267D913FC2B89F9A
-:10ECE000C13A362648A77556F61D9F3EC9807EE676
-:10ECF0004AEBD863F0FDF84AABC101FBEDDAD5EC85
-:10ED00005E65EDFF72A6035F6A136FC373A37A0D8E
-:10ED10001DEDC9F65CD887DBF34B46835869ED419E
-:10ED2000A24B27E0BDD25A94E6B0405E2FE6A71072
-:10ED3000D989DF19EA6D8545300FBD5D6737475CBE
-:10ED40005F193CC5C2F2662876F1BBBFEF9007831E
-:10ED5000403E8E6F9D07A3539307A3FCC6FFD7F2D7
-:10ED600060F8609C9F401E8C00C677D43C18C93F59
-:10ED7000721E0C882F8D0EC983D1A9C983C1F9F8E1
-:10ED8000CF3C18FFCC8301A59A07E39D0D65059044
-:10ED9000A742CD83716683A700F252A87930BEDA0C
-:10EDA000B08AD5791E0CCBFDAB0B42F36064DEBF9D
-:10EDB00001DBD53C18CEFB1F2908CD839177FFE6F8
-:10EDC00082D03C1833EFDF5E109A07A3ECFEE70A0F
-:10EDD000843C186BFF500079305E8F77B7C6A5442E
-:10EDE000CF83D11CE788290F0685F31EC2899207BD
-:10EDF000430B275A1E0C0AE744DC98E87930C2F02E
-:10EE000089920783C2F904E144C98311864F943C77
-:10EE10001814CEE738AF287930B470A2E5C1A070DD
-:10EE2000FE0BE144C983A185132D0F068563884F2E
-:10EE3000899E07230C9F287930289C048413250F72
-:10EE400046183E51F2605038E908274A1E0C2D9CA6
-:10EE5000687930289C2C8413250F86164EB43C18F4
-:10EE600014CE55F163A2E7C108C3274A1E0C0A67F6
-:10EE700014E213250F46183E51F260503813104E1D
-:10EE8000943C185A38D1F26050380538AF287930A0
-:10EE9000B470A2E5C1A070A6213E51F26084E113D6
-:10EEA000250F0685330BF1899207230C9F287930B3
-:10EEB000281C37E213250F86164EB43C1814CE5288
-:10EEC0008413250F86164EB43C1814CE7284132575
-:10EED0000F46183E51F260503877239C287930C293
-:10EEE000F0F9AE7930CC8141D240CC8381F938BB86
-:10EEF000F360247FEB3C18BF027CFF9907E39F7906
-:10EF0000307E8C3C18B75ADD7F8FC77DE377CB838B
-:10EF100071265E9337A2873C18B75A4BCE823C7F4E
-:10EF2000DB3C1817E2BF5D1E0C3ACE3F2E374EB4C5
-:10EF30003C183ACBB7CB8341C7912D632E339F2822
-:10EF40007930122C62FE901F2B0FC6B1F8249C4F13
-:10EF5000B43C183FB97C13749B05FBB4E9288AE4E0
-:10EF600027937F62B485C70D7FA8FC1330E99C9F6F
-:10EF700052FE09358F419302EBE1FB9CEFEF70B934
-:10EF8000F880E7A13816350F857F2AC677978A79EA
-:10EF900028A6703ECE768BF23085B0739429F9594D
-:10EFA000FE5AD8AF976BF2500C11CFE98BDD47F3C7
-:10EFB000293832D529CEE328978769A59F1E04F604
-:10EFC000DC3C36721E8A199C1FD3357499C2F936FF
-:10EFD0009D97B7C3A739549E8BCB8FCA40D7698EF4
-:10EFE0003619E3F437A9FC7308FC9BC9E16AF19D6B
-:10EFF000C1F9376332E39F16EFB7807F14EFB7CACA
-:10F000004721FFB4786BF1D4F29F84F23B247F4810
-:10F010002E11F34F4C3289F9270AEC62FE891BD37B
-:10F02000C5FC13931D62FE899B8688F927A63AC505
-:10F03000FC13378F15F34F4C77ADD6E4BFB84F9321
-:10F04000FFE2214DFE8B4D9AFC175B34F92F766859
-:10F05000F25FECD2E4BF784993FF629F505F58F7AC
-:10F060009AD07F71FD51A1BEA4E13DA1FF52FF7175
-:10F07000A17D59E3C7427B55D3A742DDD3FCA5D080
-:10F08000BFA7FC036FF1EFA1DFE1DF431FE3DF4325
-:10F09000BFDF43FE8B772C4BD785E6BF78DFE25985
-:10F0A0000779098E5B1C3CAF40E4FC16DDED51F2A4
-:10F0B0005F04DFFFF6F92F52927FF87C043A2BFBB6
-:10F0C0001EB0B7254F674DF9EEF9086E2D11BFEB55
-:10F0D0009E552A7ED7ADB3B2EFB567BBC5EFBB6F08
-:10F0E0002F17BFEF1E11E796000F6DFE8BDE1697F0
-:10F0F000CE0AF692E72908C077BAD9106F2BC2F270
-:10F1000020E4BFC886785B29968721FF052DFF0C78
-:10F11000F92F687904F25FD0F20DC87F910DF933B1
-:10F120007C3C7F461DCF9F51CFF36734F0FC197EA6
-:10F130009E3FA391E7CF68E2F9339A79FE8C00C233
-:10F1400039E13D8CE5496F2B96A7BCC7B03CE36D18
-:10F15000C3F2ACF70C96E7BC9D58B67B2F62196BD7
-:10F16000FE0C552E3F04BFE10A189FC9B32AA757CA
-:10F170003FF0C8BAD0FC19231ED884721A2D6F46EE
-:10F180000E7CD397123D6F46777B94BC19C1F7A3D1
-:10F19000E7CD481BFDE3E5CD986BF961F266CCAD98
-:10F1A00011F33ACC5B75F9BC1923E24A6E41F9E3DD
-:10F1B000F238D7125BDE0C9F55E2DFE553BA80DFF1
-:10F1C00045E982EB750F79070E5A9F1E02FB89AE47
-:10F1D00021575D36DF83562EA2D39BE57798F32324
-:10F1E000E7CBE889AE6AFFF72B581E87B9966F996F
-:10F1F0002FA3877C0B07B3BF403B196BBE8C9ED6F9
-:10F20000879EE839E347CE97D1935DEDC99EBE391D
-:10F2100085D1B9770F7456BF97AE34B51EC297ED3E
-:10F220002E546D997F0F9F3BD38EF1998E9DFC5E7E
-:10F230009C8B38ECA9EC7B7DF0373B9E4F184EF051
-:10F240003B7E3B7151FEC4F3E7D2CE7DFBE05EC056
-:10F250005A1B71252681B3471CFA81B00FBBC60427
-:10F26000F19AAADD9FBEF1470AD7DCA2C7FB721D47
-:10F27000148756F4FB5C89C0B778F24BDCA7C3193E
-:10F28000DDA55EA1DF756B7E0F0774490D9E3F15EE
-:10F29000E82DB86FEADACCEEB3EAC9D58F4F188DF6
-:10F2A000F7C689DF81FC433F7519C7B38B10670030
-:10F2B000FAEFB4E2FDD525AF2D34C0A070DE1A1AE6
-:10F2C00037E85524C6811ACCB6E1706F2F5DBDBFFB
-:10F2D000E773B5821FBE88C34D2911E3449F2C28D4
-:10F2E0003A0CFEF3227719DEAB482B15E346847FF8
-:10F2F000470FDB32F03365C2EF75FAD97DCFB0EF3F
-:10F30000EA9BB7209E4BFD9AFB4B8D625DA5DB39D6
-:10F310002BBF9762219698E8D676C5E31392BF3D3E
-:10F32000DD8CE922DDCC0E916EF14344BA68E966CA
-:10F33000758A74D1D22D61AC185F53E9A6DEA7FCA3
-:10F34000A1E89664E3F73C82F42A31A5A2C9473CC0
-:10F3500033E400CAB7561FFA5802F01B7E48BF6458
-:10F36000FF6A7CCB6995C16EA533D0445AC4DE8B4D
-:10F37000077D80FCBDC489FAA0FE3E8A78F2219701
-:10F38000FB8FC8255AAE987EF0F802DABA19E46D00
-:10F3900004FB3D1A18AF4A22B89F5388D30EFBA82E
-:10F3A00026AFC9B94881734DE25C940DE799762C7C
-:10F3B0001FE4DF3B770C25B8EF6F0A7C9E0AF70647
-:10F3C0001E1CD9390DE20F9EC5A404D6AF59096C95
-:10F3D0007D5DC64B5B028BCF6C28D111D768F87D61
-:10F3E0004A7ABF44C76BB7BB5EBB01FCD116763F00
-:10F3F00080D83BDFB81DDB47E1F7E119BAFA6B00B3
-:10F400001FDA1FBF2BEE68F9C8B630C40EB7373FFE
-:10F410007225DC6BDDA48BFC3D73818DFFFE1D7EB0
-:10F420003F654430DF42816D0CE6657870001DA7B2
-:10F430007A7A17F25195CBEB38FD0F964D41FC5E71
-:10F4400068911C10AF2BD4DF71D3308ADFB8B76559
-:10F450007EAF97DD5F1FCDFBD79AA9FEA2FDAAFF65
-:10F460001BFC9E95974ECA980F71744D19DE13FCC4
-:10F47000A3ADF030F02BC7D5340AE429BF2511CF56
-:10F48000713D1F12277E9AD52ADE07CCE1F7B673AD
-:10F49000DA881F84E2DA6362FBB836B17E9D66FFCC
-:10F4A00039DFC6F5D4465241EE367EAD9760FDE8B1
-:10F4B000E824CE3514DF8E45BD71FC8ECF09FA8964
-:10F4C0001D5FEB8B22DD8F596E63FCDB642068BF10
-:10F4D000379559F0DEF9FEB28AFEE05F7C7197BB8A
-:10F4E0007FA43865889F96C0BEBB772590B12087E2
-:10F4F0006B2546EFFA8C9208EB962A77AA1CAAF2A3
-:10F50000975116E78E740FF5339B847296573644E5
-:10F510003280FCEC9530FCD5BE86E2759975DB47F0
-:10F52000D6F4017C3CCD9FE17D32538BE48A744F4D
-:10F53000E7619B8DDD6F5CE35B0DF7467E419508CF
-:10F54000EC5486A13E2B127C1FD9887EE95D3607DC
-:10F550007BCFC4F320C9F519709FA2BD79D2E475A1
-:10F5600014CF27A83EC07AB5497122DEBE2A42F0E8
-:10F570009E2C8FD7F59D46B66C08F17F37DB721B4A
-:10F580006D145EA38D7D6FD9CBED94006FE77FFD89
-:10F59000C306F03B2E1A917FBDB9BFA9BE7780D3B9
-:10F5A000675C826B2BBC4FE0979F51E3E374DB9C5D
-:10F5B0008B46415C9ED23BC40E06F9E663F951DCF2
-:10F5C00004CF3F922C3A9443E27239ECC27D761F0D
-:10F5D000EA8DAA07242011C853A0DA37A9450A5892
-:10F5E000A9DC8F365902708F2EA99CCE3B19F29A56
-:10F5F0009818BC56F99C18D7A2F29803CE3DC1AB1F
-:10F60000F3104805F8AADD53EDE5DA44668FD63EDF
-:10F6100024635ED4CD729B19E2A9592E471EA4889B
-:10F620004C921D78AFA65F3971520C49FCC05F2720
-:10F6300076FB0154C9AFF9463F2FD2775B176DCCEB
-:10F64000DF1E97E0FE33D06BF8E1CEFDE02E38CD23
-:10F65000A417BBFFC5ED04F76B0AF97A37EE3F74C8
-:10F66000EC7BD1C00D24F43B2AAD9DD86466EBFC45
-:10F67000B8EBD9BA37EEBC05D7BD6E3B515688EB17
-:10F68000D4C8965107E09EC5C80F997E126E1FEC34
-:10F69000F40FD029E7B04F0FF4F9B67641CB6F12D3
-:10F6A0003075D787EAE01C86EA5BC8FB673576646D
-:10F6B000C5F441B5185EE672D4FF1EA7DE1D4247B1
-:10F6C000EDFBDD714AC9D4FDDC3110ECC8113DDC25
-:10F6D0000BE9C8A5F3A3F3DFC8F525F173FF649820
-:10F6E000D7C6961BCD20DF6B0379F662FA4EA2A92E
-:10F6F000049997485C18CF19493D32C88F518B4205
-:10F7000041FD41A58424A4C03DB42221DE432C49FF
-:10F710003CFF4B00F9D22DA7548E43EFE5AAF2A986
-:10F720009547557E6BE1A005CE0721624E4BBDD4B7
-:10F7300084878146B2D90EEBBBEA5FD6727FAED624
-:10F740009CE9C7EF977C19E81FADE4FE51ADA5D049
-:10F7500084E6605F32AEEB2B217E42E9B03285D980
-:10F7600079753E5AB9F45CD4137FC83EC12377E261
-:10F770007D44CF45033E5FA7B807C0FC55FA5CC384
-:10F78000E9A3A58794C0F79D9C2E3DE39B63877BEF
-:10F79000C1892617598FF8E6E13DEEA6C04813ACA3
-:10F7A000BFF76AF08D01CF6B13C684E3295BA2E03B
-:10F7B00099CCF0BC8EB8FFD846E53767455D6D3C07
-:10F7C000EA15792B3D275CAFB47AA4EA8D1AE7BD20
-:10F7D000B6B2FE005EBBED416F3CF18C2E4EA5042F
-:10F7E000EF5739F7C4A31DD1EAD3E77CFE9E7846D4
-:10F7F000BF058A7B06CCCFA3EBCC043919EE20BD24
-:10F800008A2992C39BF5A8E7A435B67BF8AA7FA501
-:10F81000FA55DA7EAA5FA5DA63F51EFCDA04F77CF6
-:10F820009003A999CA2DC5A7D6CEF64B9B6DEE4580
-:10F8300080573CC53D0EF68D430259ECFB5F512FBE
-:10F84000A2E941BC46CE9B0232AE0B3EBA2E644BBF
-:10F85000E178A8E30F4A48647CA45A0EEB7DDF1CD4
-:10F86000C206AB269837A7EF70E28675ABEF4876F5
-:10F870009F714D02B3BFB5096CDD52CBCDB692BBC3
-:10F8800051BF65E2338EFCEE7803AA70DF7C6D8297
-:10F89000EB2EA087A9C885F3E863274EF04BFBC881
-:10F8A0004D127C379A54E990D83D7312FC7E8BC27E
-:10F8B000EB53ECC8057DED03FB6BE8DF1239CFD8C5
-:10F8C000A309EAFD5EE67F3A49771EAF471398FF2A
-:10F8D0007908529FF42A56F382A9E7394E09E8D4F1
-:10F8E0006EBD0D916EBF20313F3D91D14BBB4F009E
-:10F8F000C287FEFEBD7B0D44362791E0EF59D599B6
-:10F90000D0BF8F27CE26B057BB1206F0734C671DB1
-:10F91000D47F25779A128706E55D95E30727CC709B
-:10F92000422A52DBF55DC3614F45E57A27D0BF7DA2
-:10F9300042D760CC41493A3399FCB8F442BE209595
-:10F940000FCD8AC00733ECC343EDA4D53004FCD1FE
-:10F950007629CE09F72CDA974A0C5FC9C4F329C976
-:10F96000C23CD3E3997FDDC1EDD53B09592827AAD5
-:10F970003DA6F3AB83523B0F8F11EF7490CE3DF158
-:10F98000FEAD706EA5C93FA9CD4F3969A105EF7FC6
-:10F990006CDC63C6FD6B57093BC7EF6A31A27D8EF5
-:10F9A000A6B7696DE688711CB5A4F47B0BE897A631
-:10F9B000D424823D4C9B7BD2067CD7D2A543F25DFA
-:10F9C0007308F645AF2B11BFBB55CBF4F49B121750
-:10F9D000D1FEE91993B1549F3758E488F7CD4F739E
-:10F9E000BD52E5F14A3A22DF0F9D06793CEF7EF3E6
-:10F9F0001D1709DEDF6F8863746C886374EC728F87
-:10FA00004F781AE4CD9781FAB0583D07E5FB7F3572
-:10FA1000CF943ADE46AF2951A62AD0B0608A19D6D3
-:10FA20008914E29A3C1B9475A342E03BA2C7BC3BFD
-:10FA300012F3318E6D12EFF9DAD9BDE1CF3716E04E
-:10FA400077DEA9648D7930A5475989CE09F183F312
-:10FA50000BDEB7E9A83C2DE8D39A03F2FBBAE22605
-:10FA6000F63118EAC2FDC99252833F40F996DC4054
-:10FA70000D05A5CB7F03D85B39A8008000000000EE
-:10FA80001F8B080000000000000BB57D0B7854D5DB
-:10FA9000B5F03E73CE3C92992433794E1EC009E1F5
-:10FAA0009D108724BC1F4E9E448830BC0485EA808C
-:10FAB00028CF2488D6DFB6DECBC444F4A2B745E90C
-:10FAC000AFF4D6DB7FB0A2A8200182069AA413402F
-:10FAD000E4113408A8A8AD5129620BC908EAC5D6BB
-:10FAE0007BFDD75A7B9FCCCC4922D8DE4E3EBFED62
-:10FAF0003E8FBDD75EEFB5F6DA872EC977134B641C
-:10FB0000CCB7D8C0B64A8C7D87BF1B43ADD96E60D9
-:10FB10002C89B196383BB54EE70CC7D284F07E8570
-:10FB200063693E63D5D6D85C16876D7F3F8B85F1C0
-:10FB30008A58EAD202685BACAE5A95B12546AFDD71
-:10FB40000ECF774EBA3CA48EE12FD8DF3392B12E80
-:10FB5000236B94E2B01F606C0C4350F8CFED56ED70
-:10FB6000D097F0FFE1FD448B2D20C3B8CCA35CEC13
-:10FB7000B0F047BE1B281E4D66CC285E939ADEF877
-:10FB800046CA652C7672116370DFCA5C8FB22CB8DE
-:10FB9000318CA99E18C6A2D833F6F3D98C19F07D02
-:10FBA000584757F3BBFD7C00C71FFEE54A0C83FB9B
-:10FBB0001F29C118570E63171E3C15E3B6C1F50780
-:10FBC000E5723FF46F4740C687F0926F870BA31929
-:10FBD0007BC4EE1981EBBA63DD7F8FF1DA42F7D98E
-:10FBE00003703195B1157E19E7E6F0C27FABB659C7
-:10FBF00019B384FA95F509117DC018E1B5D2CCD6B8
-:10FC0000D4DB7AD26305D203E65DB17D8B295DC575
-:10FC1000F9BD93ECD0BFA0C0AB80EF0B0D317E5F80
-:10FC200066089E25DB4799D2E1D6474D661680755A
-:10FC300030A5DDC86C84B50A09F0E61578D3C37920
-:10FC4000B8C54AE3DDF57F65BF1996BA18E67A2094
-:10FC50001E9E6F5A51C1727BAEE3AE3FA86529402C
-:10FC6000BCBBFE4D623E953FFF601E3CFFC0235F64
-:10FC700020DDF4EB5CEC337ED211B16E376300CF44
-:10FC80003241EF3B1F8DBCBFACE9311A6729F39AB3
-:10FC9000909E776DD4DFBFE933E4BB654C095D0707
-:10FCA0003C5C3E9265453CDC618F493C0F20038FF4
-:10FCB0008DFD0EDEDF7D64609C37A7277EB5F6E202
-:10FCC0003AE06F33637F5E67A1F6C23A46ED08BB48
-:10FCD0004AF459DD74F27EE4AFAAC65D261CA7C5BE
-:10FCE000FFA78409F04861D3373232572173DF7B95
-:10FCF0000EF0F92326B3EF007FBB19E79FF546CF3F
-:10FD00003D48AF1BAF96D37DFDFA1769FC7F249E5B
-:10FD1000F86711AE3B17AF2B5FF6B6AE9FE2BA8025
-:10FD20009FD95858977CFDEBD2D6A3AD4FBB5F2926
-:10FD300003DFF5F2BEC6EF23843E58FADCACF5696A
-:10FD4000808ADAE6CFFA77103FB1D328BF1A3F2D69
-:10FD50001374D2F38D46C76EFE68FA775A9F463FFA
-:10FD6000E07FA7C1896DC06918D7934FF47CA1E7E4
-:10FD7000834E63477F945F3D1F744A6C416FEBFA7B
-:10FD800037FB405AD752D55D6687FB7731CF7A3B38
-:10FD9000AD67235DBFA06C3CFC3394ABE7385F7765
-:10FDA000EB3933973776DCE847BDB936464D71D825
-:10FDB00004FD80CE9DBBCC3E7C4E9BE7FC3AB77BDE
-:10FDC0009011F15E4EED9FD779DC830687EEDFFD63
-:10FDD000AB2BB12ABCDF358C95A3DC77C644C2BB04
-:10FDE000CF2E133CFB900EC87F4AFBFF7C803AE984
-:10FDF000B9F631A847CF7FFB5FB11E78BEEB5B73CE
-:10FE0000796FEB3C2DE807EAE5B413F8EC7621674F
-:10FE1000B73755125D963C33CB84FCCC1EE0F8B46A
-:10FE2000C01FEAD7B6A8D867711D8B1B24D2237ACE
-:10FE30007ADCE59AFA39EADB3BFD85F47E0FFAB00D
-:10FE4000C789BE77213D8685E831D6A1727854F8FE
-:10FE500003BEB943F0CD79658DC9007AE4FC3380E7
-:10FE60006F007995C2DCBDE9C1FE0ECE877DAD473E
-:10FE7000BF8EBEE05FF65CCDFA3486EB1F654AEBC1
-:10FE800045EF68EBBF8BB96249EF88F5B28E1B492D
-:10FE90005EAB2D7C5E6D9D2B9AEE9C817C51B519DD
-:10FEA000E895D973DDA87717F7026F997CD168813F
-:10FEB000F7BA1E905CA86FFBA283A627EE12F85A31
-:10FEC000B96DF10C349A8B613E3913F5D1176FC6B9
-:10FED00024A25C415FFA1E7A35C91F9B711D8CE319
-:10FEE0007B09E07B8374FDF45BB6B9D03D28ECB9A7
-:10FEF00015FE9BDC83C2F5998EAE6CDBACD0F3644F
-:10FF0000B7DD26B4C7F10EA1BF845EEE5BBE60E133
-:10FF100000E7DA1D0EB26F6C8D83F46375D3165350
-:10FF2000B8DDD5E44B93B7B10E3BF15955E313F46B
-:10FF30001CE85FD501FD4A4BC7CF6F55C3F0394E62
-:10FF4000D051AE30A1FEEE4B7F82BEF9B2236C9D44
-:10FF5000231CC2AE08FD7B2DFDA0C1AD1F57D307EA
-:10FF60001ADC1ADF6BEBD1F37D5FF0E9E9C2989FF1
-:10FF7000FB0B3AFAAC427A84F5115E05F0DBD66CE5
-:10FF8000F53F04F0B6491C7E5F7314C1DFE92C769F
-:10FF90009F033FAF2A7521B527F0C554F4EB3CD33E
-:10FFA000109F9A3FC70A1222FC247DABF93779C211
-:10FFB0009FDA1BE5CE0713093F4F02F2C3949A8ED6
-:10FFC000391620D9AD8EEDE50A8C3FE5898E395181
-:10FFD000D05FE8D8C1FB5B3B4E595C8CD5B057CAAB
-:10FFE0004BA07F3BA013C7BB565B60F62C44F95D6A
-:10FFF0000D7E9205ECD1EAD3430EA1DCAD6EAF28A5
-:020000022000DC
-:1000000097C0EEAC068323813DAA74C706ACB9D471
-:100010006713E0B9E7EDDE65C42F57EBC86EAD3E60
-:10002000AD70B9399248EB5700F62878AF2E1AFC1C
-:1000300055C0575DBCC5559B49D77D51F1D877ABAD
-:100040006AD8758D1EF81EC25167606E07B4AD4741
-:1000500087C4757C8FDD6E5DC72A14E08383EB2C2B
-:10006000D4EAEF179AEC83D0EE151A98B7377DF9DA
-:10007000A483FB8DC0E4E948E7AA23269277FCA17C
-:100080001F5829F4511510280EE0A93CCD02D1B11A
-:10009000F85CD9E70AB60D12FB24C25F61A1BEDC91
-:1000A00037DCD7DB56E17883C3F984E3A948912A8A
-:1000B00094B0794B6C51117D39C5300CD7C3E468CD
-:1000C000D756C0AF9C6E58B31BD62F0F8016F0A129
-:1000D000D85DF2626837164F9197405B6BE476B556
-:1000E000D6C09687E3E905811FADFDC0E1D98A74CA
-:1000F000BFF456FB182BE9AB0C3BC9B9586FADE404
-:100100000A50DCD4CA5C5BE15A9DEC619C8FEB1910
-:10011000F2F11B621C97D9B047057E6D747C40FCE0
-:10012000EB8A33DC9B09FDC0131FF17EBAE14A263E
-:10013000F0F781273ACA15900757B6E1CA40E81F81
-:100140007AE2637E7F220C0906EAF0139F94FB6C2F
-:10015000382ED7676CBB3B1BE7510C12C9A972C084
-:10016000E4AF85FFAD8BE5FC54073C82FCF786B01D
-:10017000B3EB6B8A5EB602FF2B456E750D8CE3C741
-:100180008069F4DFDF6A7894AD068A53B0457CBF9E
-:1001900029D6ADD18135B8B367A15EA87767CF8E78
-:1001A00041BC7A4F225EF3DBDAA7A03E6E78FBFDFE
-:1001B00031E8AF22BD709CFC3688DD603D975EEB78
-:1001C000B7450E8B473F7014BEE3003996DCDC9FC9
-:1001D00094543B5B047257EB66AA09D695A28BEB4D
-:1001E0001A18D72FCFDB3D7FC4F7584680EC4DA1BE
-:1001F000C3FB31CEAF8F57597B7CAF7A59AFB74C29
-:10020000B90FC8E8E7C4A737BEB704F5FBEFCDAE1A
-:10021000C12AC2E5660F003C3B0D4C61F1C426C308
-:1002200094028C3FA35D1B50EE5DCCE90339C330D3
-:100230008D80845FE298B0B855AC07DE2F61D08E18
-:1002400045F86EA0F5C9C857A3984746FD3586F90D
-:10025000ADD87635BFE644BC3D19C5EE40BFCFB240
-:100260008DB9FD61FA63403CF7F726251809EE6861
-:1002700063FD6CE4D7E82F981DFDAAAEFF34293842
-:100280003E08C874BCEE3A6C6008E70B46BF3D0EF2
-:10029000FAC1E18AFA2C0B8DD725E8AD8DFBA44974
-:1002A0001DEE407D93C0FB2F1472FB1CFCDCE47F31
-:1002B0003613F16359E30F932F673CF75BBD494554
-:1002C000F1F1D0D63747339C7F6C4BB401E9F0F2A3
-:1002D000F6BC28E4879D881B587FBCD97E0F8E17FB
-:1002E0007F05E0CDA4EB6EC2ABA28E8A03BC4E9814
-:1002F00066533700DE5F88AA9F86FC1FDC6160CFF3
-:10030000C2143B4DAE59D8DF7959B5A3BE7D21B398
-:100310003E9AD6B3C340EBD9191D1CB116E0DE30AE
-:100320004C2947F8142B53500F2B8622F51EB83E4C
-:10033000349EDB574D2F2F88E7F2F3A404F3E7E157
-:100340007385243FA5B28DE4AE2BC8FC669827695F
-:100350006EBB8CF4889E05AC847CAF046406FD49BA
-:100360001E46498D4936A35F257DEBB62D06BA4F53
-:1003700011FA76CA87AB2B78DCE33A3D11C63B68AD
-:1003800033325CD764D621A33F38F92A7305907FB6
-:10039000AEF278C60E7FE83F3DAFF3074BC578EE6F
-:1003A000A0BD042F17B2483FAE7473D9E712CDA396
-:1003B0002A68A78B2DBAFBE8E7C5621B193795C5DC
-:1003C0000BFFA63FEBFF1DE937E05E98EF3E3B9F3A
-:1003D000AF54CEF915AEAFABDCE4423CECB2B9DFC2
-:1003E0009D887AB1DDC8B6B2BEE5E979883FFDE007
-:1003F000730CBB6A65FE7CE2471BAE67C4E68DBE2C
-:100400002858F788417C7CE43BD42343FF333101F7
-:10041000F5F855A15FB456E333E4277B1CE727FBCF
-:100420000D2139BC333E939ED3E40AF90CC7D96F32
-:10043000F42FF4F46227813FEF44FEDC6563144738
-:100440003D966A598072A5CDF3BCE0637DBBBE6664
-:100450006DAB11D7FD15D80380BB24EDAA29DC9E16
-:10046000EF49E27C552A7F4BFE766793C4D0CF4F8D
-:100470006EE2FA3B9C3F527BE78F5F225EAFC51F67
-:100480005ABCB0FB87F2C791BF8F3F365C933FBE2B
-:100490008D453CDCD75C9CC2BEC7BF6914FCD0D77D
-:1004A000FDF156AEE7F4D75F1178DD67DA383D1716
-:1004B000F5C0CD0617CA39503F7D36AC635F347F37
-:1004C0008F296BB2B0BF4BE17A65579399F4CA2E6E
-:1004D0009BD74B76DC6961E83F30C5DBF133D487CD
-:1004E0006916754318FF2E8DE7FC566F0C8CFF0CB8
-:1004F000FDE2A39CCEE36ECE934DF05CEA522EE774
-:1005000005174C5B300E2B4D28DC817C7402751670
-:10051000B4D5E7E029407CD53913E9BBD75A4E96CC
-:10052000617E11FC1E37F2D9D8FD27CB8A72F07993
-:10053000AE4FF78A56EB8FC735C5B3EE78D723ECAD
-:10054000C678C6F59207F92437D4676E23C56B1AAF
-:100550003FD447033F805CCC67AA3116869C73CE9C
-:10056000F330984336A73C92CEF303D3283E9C7BCE
-:10057000BAFD55D0CC6C9E47775FF0C17C1D1F80C3
-:100580009D3D1E8FFED2F180C980F399D664737FA2
-:10059000684D16F293264FF4033CD5FF61D8B31B88
-:1005A000C2EC7B6C0297A3C75D0ADDF77598FC83EC
-:1005B000E1D2BF33FE5EBDB03F9FA33C63FC70DF62
-:1005C0002B0BD18EE62F771F44FC4F4F92E9FA2F69
-:1005D00058C09285F47129E497D51BD5E2CFA4D0F9
-:1005E000734CF10CB3C1FDFD49D1F9387F6982F735
-:1005F00022D28929C123F8DED80979F9285FB651BA
-:100600007509688F34B801AEF2ADB6101C1A5C677C
-:10061000055F94262CBE88EBC7F750BF347E7CDE86
-:1006200082EF6B74AF6FFE82D33B8CFE48EF10FD00
-:10063000A53BB0AFE1E12BA157B4FE3F4A7F2D7F30
-:10064000704DFA637E20F6EFA2BF352129447FF07A
-:10065000B3E2B1AFF7B3EA4DE077E7F4BC5EE82868
-:10066000A4E75D265821FA552D1077A23C7A1DB4D7
-:100670002FB0C7CEE7EAFAC3F9FEE022B2C109F112
-:1006800084F76A537008FA21A30212F985A340F097
-:100690001791FF95417ACF25F0C4CE4BD2F961DC9A
-:1006A00045FF2E1DFDC34002FA51A3CC1501E4F70E
-:1006B000DDD629E9E8D7E5592765215FBD3AECBECB
-:1006C000E368825E4D5BBEE73935E4FF68FAEDA072
-:1006D00018569BBF2081EBA11B41DDA21F882E6312
-:1006E000381C9A3E47F2201C5260BEE13B2BE9E5E4
-:1006F000A60EA0C78D0807E0A155620DA8CF0B0D6F
-:10070000EEC462F4D392020AF7F7BEE98FF9C18A08
-:10071000A637DE43782B703F04E35097F162773EB3
-:1007200062604F3F58F357B4B840F367B4F813FD15
-:100730001EBC3F405CB79B0140B447018BBF06E63F
-:100740007FF2B23ADC2DE4568175548875CC64EDA5
-:100750000417FBF6BBEF26017D66087C541C81B8AC
-:100760003117EF337633E0E16685C79337BB207EE0
-:100770000CE3A399E322FBF89B921C1AE75ACFEBF8
-:10078000EDC044DDFECC3FDA1E017BF409B8CEC7D4
-:10079000D6F1B874C240D9A7A0E11C9769407EACDD
-:1007A00016F60DC2E85EEDD24BC22F9E60E8C8750A
-:1007B000017E5BF7FF8DECE081FD7F7B07FDBCF1E7
-:1007C0009F2BCC0CEF4FF8BC200EF5041BA7125F3B
-:1007D00069E356FFA9C1CAF875E2FF2AB1F6C30062
-:1007E0008F7B28C267A1F677179FDC84E37D794E63
-:1007F000E1BC2DE62F337907611EBBCCC4F3018722
-:1008000025EEFF68F70F1B016EB8BE2941CB0BB474
-:1008100093DDC79F398CCE37633E202F44D79B2F63
-:10082000947FAEE4F6A40FFEFE37F2015A1E60ABD1
-:10083000C01F3B78D6A4025C531BEE51D0BF9EEA8A
-:1008400094993B6CDE9B542B7387E5039E49D0F94A
-:1008500023075FDC3403EC49759BEC8A42796DDA3F
-:10086000753C17FBEDB2CBDA0B1FE9F13BB5E91E86
-:1008700005F9DF98A8927C5F6BFE0923804F6E40DC
-:10088000BA33F2EB3AC74824477AFA1ED8FFEB8412
-:100890008E9CBEF1DD17FDF574F8DDC522DAEFB9E7
-:1008A000163DF47CDB02EBF4C1FA02B04E1FF85D9A
-:1008B00007D6D9A97F689D93FA1ABF5637FF36012C
-:1008C000FD368D4F4B1338DF8CDFB72981D942F4C9
-:1008D000D2F0F5A1B0577BA3347FC3356F065C3AE5
-:1008E00005768718D4C7DA9D6342F66BFEE932F2CB
-:1008F0003734FB355F5E544A6A53D82F4C23A35ECE
-:10090000D3DBA9B9EA6223EBCD3E2D88EC97B76D16
-:100910005462A867203A4992C087F0B33538CE3088
-:100920000FC1A9A7A706971E1E6D7D9A7F3D5FD0B8
-:100930006FCEA04C23C2DFC3AE8A75E2409887B861
-:100940005EBBFAB58E9FAF5C28792BB717BEED8BD7
-:100950007FF5F7357D508613E451EB43BFC298987D
-:100960004C742BBB6A626EB01B2C238A7D1A6657AF
-:1009700058C550E29F7B851DEE8B7FAAAECACC9BEB
-:100980001FE22363E31356E4A37DCA462BE6272721
-:10099000DB66D5C6019E4AFE543417FDBCEA0E0341
-:1009A000C3145669D3170731AEAF7E8FB9502F16D7
-:1009B00035B51623DF1D52DA658AB3BF64EC893082
-:1009C0007FB1B1A9D68AFE5463A24C71FC6107E7DE
-:1009D0004BEDFE9644AE3F1ACF5D9EE1EEE5FE196B
-:1009E00071BFE4E33CE2A3B24741AE310E4D8AA1B0
-:1009F000BC4489649F53817EC84D46F2F3218EF931
-:100A000023EE035E6A34EFC2D47E69E323F7D88114
-:100A100010F5FFFD698D19F30BB324D7B3F05C9982
-:100A20001A6CC57ED9DC4CAA7B18FB3F32F9B3C1E6
-:100A30005B25CA8B9401BB60BF6C51A61FF313FBEF
-:100A400025DEF735F37D0266F725CC8079DEAE48EA
-:100A500018B581784AEB0FCEDBC0042387C557F762
-:100A6000ED9549CFDC572AF971BFA9D49ECE7C61A0
-:100A70007C55F6A889D635BB29A508F9784EB9CC9E
-:100A8000FC61FC1D107EE13C0FC4E161EF1D8EE2B4
-:100A900070051703DC52486EA7093E9FC5B89F3802
-:100AA0007F4142C47BF0C62D688F6E6D8238157A07
-:100AB000D344FC7AAB373D625E0FE37ECD09162C42
-:100AC0008983F1FB250D24FE9B11B48F0EA8A87716
-:100AD000CE24A25E63C3B89C6872572AAFAE237E51
-:100AE00070F27DB2791248938CFA2F529E668E8BEB
-:100AF000ECCF72F7A83788907FBD5ED7E47E5EB3F7
-:100B00004CFB72F30A2517EB453FE8FDECB1D17DB4
-:100B1000E8856FD587E37AD30B1F96FF5D7AE135C1
-:100B2000082BC681FCFE3451E8877EAC1FEA875251
-:100B300079FB26E4972EB077E65EF845B3175A3C6A
-:100B40005E06F24AF27E91EF67945E4D65BEFC5000
-:100B50003CDEAD2FC09F70F5E2E73C9D984572D416
-:100B6000AD5F34FD11E64F18C7FCE3FE4429F89150
-:100B7000A63C842F83E02B633C1F588685439897BF
-:100B8000737E41F9966A88F329DE67BF25B850CF96
-:100B900049F12139D0FB195A5ED72AF2087ABEE80A
-:100BA000CEF3CD35521D8CC61765762E1F65736545
-:100BB000CABBEBF9449B4FCF1F015D5EE69AFC2157
-:100BC000E4EC87F24773A2D8571DC4065D0F5F6837
-:100BD000FCA0F187DE8E1CD3E567FAB2236FA21D5D
-:100BE00019DDB71D797D9891F4B5DE7E68F6E27760
-:100BF000495C2F6724F27D8E69C3E7D9D0EFB02618
-:100C0000F13A0DCD0E75E79736737E78BD63892274
-:100C1000A13D41BD9019867F916FD5F8AFEA51890A
-:100C2000F28D15422F7536F3FC5B7589ECB7C0FF6A
-:100C300016373DB189F78D949F2B545A150B8C3B79
-:100C4000D325B930AFE316F9BA196E89E7EB5C9199
-:100C5000FBF42D3AFACE117C349305EBD01FD7EB81
-:100C6000A53957B95FA0D74F73C4BEFB1CDDBEFBCF
-:100C7000554DDE07B001FF4C7FC09CF4FDFE80F6B1
-:100C8000BE46478D7E2AEEC5A11C1DFCC6A4C670BB
-:100C9000FF19E937F5AA42E3D893045F0A7FE6CB50
-:100CA0008B79BFA0984F3C5FDDF485C93BB26FF8EC
-:100CB000AFE5B7C6A29F3E3AE4B76BF34E53184B6D
-:100CC00047C74C674F6689EB3FD47E0CD7AD43A333
-:100CD00083A6477BE059E8D9BEE8742D3DABE9B364
-:100CE0007FB69ED5C6D7EC8036AF5EFFF615B769E6
-:100CF000FA74FD1603E54B268BF878B2C8C3CE4FC5
-:100D0000E2F1C1AD493CEEECFACA62407BB9B38571
-:100D1000FB272EB3FD38FA05A17C1FA7E7C331CC12
-:100D200087FBEC4C69B7D0BE67119012F73DD3F842
-:100D3000BEE77625E0213DED52580DC8C9397C0F3C
-:100D4000E679F8806F21EAE9873F1962A0FD7725EF
-:100D5000D08EFEC9D83C85F68F1C6695F2C19DCD1C
-:100D6000663BBED7B5EFFFB41A719CAF980B43B882
-:100D700043CDE6EEFD1BD407A5729B8CF9FBAE209C
-:100D8000C8083C3F6941A018E3A0C9ACBD16E57B8B
-:100D900002D2B117FAFD2A498BB37BCFEF17377315
-:100DA0003FAE3846263F6E8AAFBD18F7ADA62892F3
-:100DB000AB169FD5E5F75FD1C51FA1FCBEAAF0FA1F
-:100DC000435DFEBE91EB99EBCDEB4F40DD067CBC65
-:100DD0005EE373A16F581FF9FD9D26BEEF133C69BA
-:100DE00064E807B30B89BDE663AE95E7DFD712ED84
-:100DF0005663719F8EFBEBFB5AD2DC6A6EDFCFE746
-:100E000076048BD03CEEDC3E5BA1FA35911FEDB150
-:100E10007FD2C7FE88BBD17E08D5695FFB21C55F45
-:100E2000AA94F6B95EBC69750B4CD43FDDC8B49F7B
-:100E30009BE474E7F96837F2F9CEF3696E84EB79D5
-:100E4000C1A71ADFEF3B77399AF6414D6E15F78F40
-:100E5000830E8BEB59E25BCEEFF5A943FCB84FFB59
-:100E60001B21173BA383C7B213C3F73DF83E47CB03
-:100E7000BA47679F33D27EB984F9486D7FD907722C
-:100E800043753DF18CE20F23AB67386FAD9BFD1AC4
-:100E9000DB2993D438C4FBE5446D1F538DA33CC4B8
-:100EA000B757A8CE508FFFDDEB9807EB511AD659F4
-:100EB0003C0AC8FFABEBECD46F5CE7A476FF3A9535
-:100EC000DA878EC73E8076BFDA6DF22861FAE39D3D
-:100ED00064EE77E5657F524CC5DF7F6354873EE55E
-:100EE000C10E19F5C58D57611D117527CA65C43727
-:100EF000E537B342FD4C69710CF66FBC0AFDB0E7F3
-:100F0000AF2439B83DAA53EA462793B4105FFC2DAD
-:100F1000C9DD9104D7EF71783EC176B734FFE02583
-:100F200046FD73BC7FAB7C099ECB0F14525E391F0C
-:100F3000F3CA7934EC42C4DFE85613ED976BF9DD60
-:100F40003C4DFEBE8ECC33E78BBCEEABAC83F2CD1A
-:100F5000051608B40C0817A79F5B9AE794301F98F2
-:100F6000647261BDC3E82C4F3EE6635B9318C547CE
-:100F7000ADADC9196A0E720FCFFBBAB5BC2FFBFE1F
-:100F8000BCEF918F627DA4B7AE9A687FFAC8A9586A
-:100F90005780F60B2DE4FF69F5C82DD1BCCE8065D6
-:100FA0002CA03CD38DA29ED162F69A93495F050E88
-:100FB0009E80F77E7F99F17DC7F60F695FBBD830C1
-:100FC0003C05EB7E0F4A43E3B07DEAA3D81C6A4F91
-:100FD000C55E44FCB418AC2ACE7B669D5A82756D02
-:100FE00027D6B112AC637B6B9D85DA93EBECD49E74
-:100FF0005AE7A4F675B88EFC731C9E477E71BF65D8
-:10100000A37D92296FD9146CF316C650BBFBB6189A
-:1010100013C2DB12CBB66BF360BD5A203AD080C945
-:10102000FED6A7BC8F59FA81DD337B474AA3186BE4
-:101030007BCA3B5D990CE34EEDFF93AFE0FE9BC98D
-:10104000CB1EB3005C734FD91ADAA0FF76F2F2C759
-:101050006CA86F8F4783D2C3F5AE38EE1E0474437D
-:10106000A590C605978D837E82D65F31BD641263DD
-:10107000B71477643360ADECE495D32D80C75BACD7
-:10108000DE1F63DFE44B9A5ED20FFBCC87F5604135
-:10109000C948713FCB9012B1FE65A6C3FB4672589A
-:1010A000FD9E5BFA13ED338D714BCC41871F8CB4E1
-:1010B000EFC5EC1F2784CBDB4C47E91B488F89C960
-:1010C000BC0E78F424C91D5E5FA17F6EF439B504AF
-:1010D000E934E642591DB633CB1DD4F72C185B8793
-:1010E000F25C62EBEBFD627ABF3C99D78D1429521A
-:1010F000445D89FEB97C6026F48F8347A3294F3075
-:10110000FAB4B716EB4F4B9D9979B2A6FAA8EFD86F
-:1011100082FB6DA32BCE9424A0FCD824179A89318E
-:10112000ACA32E01EE17DAB1A00AD7F54431D6FFF1
-:101130008C562517A2ADD0DDDA80EF17BA625C8538
-:10114000E88F9F564BD0F49C52469D2880E7A60E10
-:10115000925D1618E854E0A68997A05F382C8EF2AD
-:10116000BC85CA9A2B27A81FE3AA51711D5B7E5D1F
-:1011700045E398C9AEEF9E51FC2FC83F459E38CA43
-:1011800009023E4AC2EBCA60DD0477A15DF6474919
-:10119000C8DFFF5A6287FEEEFE1296CBC37CC3FF08
-:1011A00042F78F44AB5100E86E93BD04C7DB6D92EC
-:1011B000EC0F51DF538CCFFB861855CC1F9525467D
-:1011C000458C3FB5441A7F0EE1CF891B85D7CA33C2
-:1011D0001C11F7DB6EB3929DA8782B87FCA2B6DBBF
-:1011E000D2C95E54BC35A908DB3603F7D32BDEAA7F
-:1011F00028A7FB061E07572CFC915BF429EEAD587F
-:101200005849FD5629E52738DF959CB83CCCAF4DB1
-:101210001B945AA244F8810349FEF3447EAFD030B8
-:101220007CD32480FFDEA37C9FA2222733E2F9191E
-:1012300005524978FDA8675254447F7689A324BC9F
-:101240000E756E456A44FF96B99911FD92A3056427
-:10125000BF410F5494801E380AED5260C1025107FD
-:10126000A5E59F0A054B15B68BBCACC2E3EB61F05C
-:10127000877AB0C41669A77747733B5FCED6D0068E
-:1012800049F911BEBF5D9668FC24DC4E94CB15363F
-:101290005E97158987BCA346B2977931921FE3FA0E
-:1012A00092A34BEBD0F4966744BEAFF961E5023EE2
-:1012B0006D5EE673B7A33FA2C1ADCDAFC15F2E2F68
-:1012C0002AA17CF735D6A18797C17A503FE8E1681B
-:1012D0004A16FE1AF81FE4AF897324F04BECCD7E5A
-:1012E0006BFE7A05E82B47B8BEB2498958B7D79745
-:1012F000BED2C6EDCB2FD3C69DE9F0D0FBEE1D9F2D
-:101300009E9A2087F5333F4E880FEFBFF8E9A688F5
-:10131000FB491FCF7184F7B77E3A07EF4F51D45A7C
-:101320001BF0E53126B97CC8076DAA1203F4283EEC
-:10133000EDAEC3B6F4432F96ABB2A9E77C75D84E99
-:10134000BCE86F33C3BA6E1A26AB18BF6B7E881E1B
-:10135000DEBF26F3BCC3B1ABAA15F75977FB542BFC
-:10136000FAF3BB1F54ADE887EC76F37319EE2C0348
-:101370009D8F7167F37AC5BF24F3BA834EF1BED651
-:10138000FA8DDE4E841BEBCCD137A8FA264875E5E2
-:10139000C7D0BFCAE9E95F1D53FC369CEFD8837EF6
-:1013A0005BF87EE2F5FA577F041E43380A99E40998
-:1013B000D723C596284FB8DC96DA1D11FD93C20FCE
-:1013C00099EA4C8D78EF263533E239F01B87A15F1F
-:1013D000526B62546FEB33F07A5B3D1E57A4F0F80A
-:1013E000CE65B3A33B83FB66726FE7915CC5865EF7
-:1013F000CFB7A5A4707FF03F5218C1352B85C3A786
-:10140000AFAFD5F76BF17C0FE293B99CC8E72EAB79
-:10141000E10AB8BCACE0E927A6535D6DBEE1DE2C65
-:10142000E8573CBD753AAFAB35ECC13ADB194F3FDD
-:10143000CFEFDF60C837823FB0CDF7C274AC2BAFBF
-:101440008AE2F5095551A23EB46E7444DCA3183EFD
-:101450007E6A21C69FFB8D0CF3FC8F99C00EE6853A
-:10146000F6D9AD661EAF5A4DBC0E7C7DE6A9F5A837
-:101470003F3E8BF2E6A5509EB148453C5EB45BA86A
-:101480003EF4BE7DA529C807B35278DE2B7BCF443E
-:10149000279D2FFBE7C151FC7D7060FD308E73717D
-:1014A0007736F9E5D903189D27D1E801E1335D8F3F
-:1014B00082F081CE6330B713F36FB50E138D332BEB
-:1014C00085F3E3F5B63DEA89E30C6B7641BB2085F5
-:1014D000C7CDB7E2BC046FB0FF2CDCD0B307FBCFA5
-:1014E0001EC9FB486F59CE0BA27F1BFC510CEDC3EC
-:1014F000BC1FCDF1C63282B46FF3EEA26CD706BA30
-:10150000CEF1B8C03FB0B643C5FA0F7F3FACB718B5
-:10151000E8F42E457CDC66F60F26BEB2AD89C179B3
-:10152000AEB7DEB8EFF921E0047B327F3CA79736F7
-:101530003FE0D882747C579C3BD1E001387E8C70B0
-:10154000687075C3A3AB3FEF147E7B278E971BCAD1
-:101550005357FFC940798A6A09F424F4F77CC85CC0
-:101560003E95E8437950DCD2C2F9C69F58526C834D
-:10157000B6A071158F8FDB9588BC9866CF268AE759
-:10158000C7BEA744D8A38922FE1DAFCB4F4E6C9C8B
-:101590004EE7F826EAE2E25FA488BC651A4B0BCF5F
-:1015A00023AC15F1C6E5B68171E89F2A10E7CA8021
-:1015B0006F932AB371F121BDD0B08E459C53D4F8FE
-:1015C00070E469FB9D38DFC8D3EC0EF207B471BB41
-:1015D000F3131C2F97DFE37819D531ECE949D037A5
-:1015E0001E3132BF1A5AE7040E2A833087E2A4CB99
-:1015F000176C645FC61C9D43F5DE66A781A961EB8D
-:101600008F52A3991AA62FADC3E223FAB2A04F5D61
-:1016100054A41F902FE68971A5458CB73FBEEC08F6
-:10162000FA05F9B6E5E417C48D1B18311E6B532279
-:10163000FC833CE67163DCE802FAE27ED998D34A87
-:10164000841F302EB091CEA18EFB30F2FA847391BC
-:10165000FD037DD1A52FFCB1DCA7D12FFCA1F87330
-:10166000B823F197501E89BF244F24FE521644E23E
-:1016700027D51B898FF4E52322EEF75B9317D11F43
-:10168000F0C08488E733C18085F7B31E9D16F1FC56
-:10169000E08DB323FA4337DF16F1FC70FF9288FB2D
-:1016A000D9DB56FE207A8FAC5F1BF1BC9EDE37344F
-:1016B000FE34627C8DDE3EF8FBDFA437730AFF50F8
-:1016C000D03B51D859879BD7AD75196D8FE2797C86
-:1016D0003C3682FACE81E7E963D1FEAB5497E79BB3
-:1016E000C6685FFB97B24742BD940EA8356451BDF2
-:1016F0003CD5F5FDDC6088D867B73BB93F647772AD
-:101700003DFE6B133F2F950EFE26D929030BC5D93D
-:1017100016AC77648299AC8F639C5DE7E818A63AB3
-:10172000306F07FDC921BDAAE9D1DBCC6A6D07E89E
-:10173000975132D793A03FFB39619EF7A5078DDC07
-:10174000FFF019D1FF48B7305F6C1ED919CA433B6F
-:1017500058A284E700E2427A5CFD0E887570653617
-:101760009DC37A134140BF5975D17ED3AD9A9E5A1D
-:101770003E9CF4D4655BA4FF767969165D3F7BBB24
-:1017800099EA07CE8A3A470D0FFAF3D6DA396CEDAB
-:10179000FEF22D9B62D0EF3C2BCEFF6AD7270BFCCD
-:1017A0004D76CAC2FE59D6603E6C1118F138C07B26
-:1017B000E5918ED8DB18F99B9370DD555BAEDCFEAE
-:1017C0002AF4AB0DC1646E377CF4DEFC77F9B9EE18
-:1017D000F97F8BFCAE408593C7F91562FC5BA0B125
-:1017E000039E6E013A38B07D635219F2275CA7F36D
-:1017F00071338F3023CAF32C6F26D54D9C62AE33E4
-:101800007B01C4F94E95E09CCB3C46CC5BBD737B21
-:10181000650C3ED73D9E360E300CFA25EF3A7CC65D
-:1018200064CC1B4CE67513309F05AF7B16A53F8C2F
-:1018300076499BEF1DE6BD7406E83B9BB9685C6D7D
-:101840007C86E9F9303DB57BF9AA8F1260BEB547B9
-:101850000D948F58DB6CA678AD6BE57FED780AEEC2
-:10186000DF91DED10FEDF6FB2BFF3604F9E1D6CD8B
-:10187000325381DEAADD7BA7336C5FE5ECD22B31DE
-:10188000781FECEED6A7D058BE6CA63AE2F757BE4A
-:101890003C24DC8FAD74162EC7F7D8B8EB3BEF585D
-:1018A000FCD2F014AAF712FCB442F0D3DA178792F4
-:1018B000BFB536A69B9F787F2BAF1BD1D67146F064
-:1018C000E3CA97BE89F8CEC46EE023D5CCF7C5D461
-:1018D000A160EFDB2EE7D2771F8CDE7F75C2BC2DB7
-:1018E000573F89C5FE9E37FF4AF0B3B9D7072FCAC5
-:1018F000A26F4C687F5A3BEFB9A029211FE90E72F5
-:10190000B601C7BFED772F5EFA00F1D3FCF2D69F88
-:10191000E133D779FE7397967714F6C625F001F672
-:1019200086E28B2E16CDCF9308FF46C11DF92CFA07
-:101930009E874A7CED66C7711FA7B6D5407526B154
-:10194000B8091496AF8B950D9A51725B9CA0AF8528
-:101950009EF97FCEDB2AEAA83E20D21F2A38B43275
-:10196000C20FF2C05FAF7ED033DE5ACC2FE9FDA1AB
-:10197000F101C36253DCF7F84587A6F5EA17414049
-:10198000ED96C688AD21F835E8F4F37E2157F53899
-:1019900016E6FF03D1FCFC33980EF47B7F9ACAF560
-:1019A000B72D83F1F36952E7300BE8CB16E7A2C7F6
-:1019B0001F856B96417CDDD8AFA53335F9C47FDD3B
-:1019C0007ED7A111A4B7D8B7301BE243E43DF4742D
-:1019D0002BC0F3ECF9617227DE0F1CFE6B2CE67D49
-:1019E00077C4AB6F213D824765DAFF89523A4C8E4E
-:1019F0005EE2BB57510F029FCAA9DC1E581A797EBE
-:101A0000D1A2BA19C60F5176FBA8F0737F8D4E1E76
-:101A10004F561E7EBFBF09E871C9D0169B03E3AFC6
-:101A2000DEBB3B16DDFF0C93F703E4C35567DF1EF7
-:101A300063A7FCCD96FE180FD607F87730462ACC60
-:101A4000A7E4F584A37A332C2601CFE927503BB2D3
-:101A5000297F19F2597580AF13C7C642BEE18D12B6
-:101A6000F53B1B6BE371BCEADF37A7A13CBD9CC40F
-:101A7000E3CD97AE66F3F715A6E0F341A74310D385
-:101A80006FC0F8E46511D7745E95E9396DFE918DEC
-:101A900085B21DF82127B0F100C5514D6615E91A30
-:101AA000F51CE378688A22B9AF6E99CAD0EE77390F
-:101AB000984B82FB3BA2837FA4F36ECD6615F3ADFA
-:101AC00051F68D2C1EC6DF21F659870347E179298F
-:101AD000EDBA365F54D3D31873203F50DE374AD95E
-:101AE000C826DBC2F11C437876A4723EDA111D30A1
-:101AF000609E253898B16709AE109C8CE6D5E01C35
-:101B0000EEC7F3843B4CC1F3786E06E0B223FD8749
-:101B1000330E276B1AAA629E20CAEEA67544D955C9
-:101B2000974FEA0957752EF3A35DFFF943AC5B6E3F
-:101B3000518EABA3437D0BC8C08E814CC8F9CF1F1B
-:101B40002FC908EF836219177A7FC8AF363E5E3718
-:101B500089E2099F8CF12FB431F1B84E95D6A76078
-:101B60008A298FE301F7DBAD167EBFFB79E06F1B9F
-:101B7000F66DFC39579CDD3A4D2239E1F5B8421F2C
-:101B8000DC2705CEDF08A4FD2A702057055856BF74
-:101B9000B19FF87495A1E9A99170FFEE28AF2B15BC
-:101BA000E67BED43039D6BFDF38B51FE0AC0C7B08E
-:101BB0007D5B92DDBDC8877EFC47DE7BE8C974A4EF
-:101BC000FF3E49C53C6C973148DF37A96AFACC44DF
-:101BD000F50D8D1F53DDD39BA9DE4938CFB8C61A4A
-:101BE000DA8F1ECF36D27E74B6380F5EEFE4FAE39A
-:101BF000F2E921CFD684E17F492A972F16F40E40CF
-:101C0000B96912F2D9827E0AB47B85BFB4B7F5D622
-:101C10002C352C7F58C30EA423BE1F6287A8D5AED7
-:101C200077F9F9B9CAEC772C77B8C3F86F9190F7C8
-:101C300045A9224F96EA9D8DF0AE6AFDC414ABE231
-:101C40003999FAFE6857EAC19FB2F782976EB9D503
-:101C5000C951B51234E1F3D517F8F957A0731D9E99
-:101C60003778F99DC6118BE1FA5EC035D695FACE6C
-:101C70009AA9BE72AFD1938ECFD79CF93A17F55679
-:101C8000090201F07CDDBC6A00E20DF8BE281AE50D
-:101C90006B17233DA6C9670ECA27BC9F837C5F8054
-:101CA000FDE1A4877798DAF9F9D3BDFCFC29F03D72
-:101CB000C901F0BD1DFD861C3BC801BD3F94E47BFE
-:101CC00047BB81CEC9FA408F0FA67ED11CECEF68CE
-:101CD0002FB1937C635E3F0FE5347080C6A987D82F
-:101CE000044927314FB83FD9E88C25BA69FAF1B0D9
-:101CF00093093BA1C6E17903AB2C47C845983DE465
-:101D00007D612F4FFC2AF0F82FD176B8855D10FE4B
-:101D100014F3E6939EBF57D8AAB5AF4F98B91DD616
-:101D2000B9F684DC5D3F8EFE6B40F0C901E1CFA2C5
-:101D30009D5013783D0E5E1FBD99D7D58E71AF298A
-:101D4000C6B3CFE3CA371EC47682A7BE18CF3E4FB4
-:101D50005AD07E909F81E6E7D91B0EDC948DFBDE86
-:101D60005D67CD0CF75D1AFE1AFCE34B8087FB5BC9
-:101D700000FFBDD825580EF11F58EC74E6EC79BF72
-:101D80004BD2F4C7A90AE4C7CE0639D40740AA80CB
-:101D9000C1B1FFDBD4938FFBA09F95E67E3E15FD7E
-:101DA000ED742FB55D27FF9A8CB660EF69EE47356D
-:101DB00098DCD9C83F0D0323BF1FA0B54FA61A89D1
-:101DC0000E057D7CBFEB482ACF6F0EF1B1C7908F17
-:101DD000AA1A64BB1FE87EA941769BC01F3AEFF6A2
-:101DE00026E3D99C0BCC77CB44B4F3228ED4BEF738
-:101DF0007217FA2960A7EEFE65EFFB0FAB99F65B51
-:101E00006340BE5AD624B1FF001C2C7F26F2F9D5C0
-:101E1000DAF76A1AB71CC6EF88AD7C4E771FFD153E
-:101E2000FA0E46A41F732455F827592C0BFD13E016
-:101E300023D20F46851D3103DFAE48F7EE437BFC0E
-:101E4000B2F8BE02E85192C77D4E615744FD417021
-:101E500007AF2B1EBECD2F1BE0FD098A5F467BC559
-:101E6000A0C57D87716E6F197D87C9E73E8DFB3EEA
-:101E7000CB853E5CAEF9697EBE3F026637C24FAB92
-:101E800016AB1FCFFCB5B1B8FE6D12C5CBABB645D6
-:101E9000EEA7548BF5AFDE7CF2309ABCCA7ADD7DBA
-:101EA000B1FE6ADDFAB57DF3CF5323EBBFAE773FCA
-:101EB000E42F46EE37BC2DC6D1EE9BD2B87EAC8265
-:101EC0006520DD56FB65BF9FFB7936FC5ED09D62C9
-:101ED0005D770AFAD33AE1B9CA6D923F803CFE7849
-:101EE000649DE95DF58BCB90AE7A3E5929D6BD7CD9
-:101EF000BB91FC55FCFE0FCA9D9E3F568AF5AFD4A0
-:101F0000ADBFCA2BE9E0E37E744FF8EA6F413A5760
-:101F10006E37B2DEE0D3E8B552E3EB3EE0D5E0D475
-:101F2000E0FEA1F0F64F13F9AD116C04D1A93CE12C
-:101F3000BAE8A4F773771D1E41DF5BBB7C6420C544
-:101F4000FB1A1FE8DF2F137EF2D4CDDC6FBCD45810
-:101F50006C1D89F14C9BC125A9149FC58E04BCE45E
-:101F600037CBAC02FA5D4D599BF0FB8379270AE62B
-:101F700060FC9F7FC240E7EFF61C29A07DE7FCA331
-:101F80008312B228CFEDA2EFE3C038645FBBDAF270
-:101F900036E1F984AEB692021C5782E7D00FC8131F
-:101FA00076A2A62DCF1A7EFE7C4C1A8FEFD73B3F30
-:101FB000FD39FAE9537719E99CC55463F04DACDB60
-:101FC000DA7344A17DF2D527963C1485F47D51A2A5
-:101FD0007DF2C3ED6B1317229F3519EDB8EFDDD5F8
-:101FE000F4E30378DFB75DA2EF5E54379766EF80C6
-:101FF0007EDE967C57F8F9B33C874AF0B1542BC586
-:10200000CF53FB19C96E5E4CB3FE16FD9F95EE2DA6
-:1020100024DF17F7EF3151DDDE0E89A1293BEC3CBF
-:10202000F80AE2E3E2AB274DE88417379C34757C6D
-:102030008F3F70C92FB300C5CD1B4D18C7546ED14B
-:10204000FA1D26A49347F84755CF7D4CFD95E8CF60
-:10205000C37C2B9F91A97EF760F36B26E4E7AAED82
-:10206000124BC90CBBBF598AF85EC312C6F960890E
-:10207000D03FAB987F7D1A3CB76A23AF5B608F4639
-:10208000D6016BFCBD42F0F7AAEDB3E8FB533DBEB1
-:102090005B8871E30DF81CE7EF659B23EFAF107CC5
-:1020A000BD42C7D73F4913FA67381B8E7CFD75A127
-:1020B0001A9703D7BF3EB972406FE7ECDB84BDD6F9
-:1020C000ECE5E58081EC8DFEB9CEC62B046775DBAF
-:1020D0006513FAA7654D5F10FE2B9A5AA97EE46638
-:1020E000E65D8DF8BAB9C96A47B9AEE8E07A685AD0
-:1020F00093D9EF97F07E3DD53977B5F0BA49DF7EB9
-:1021000089FC1C4D8F69DF775C26F0B80C14787A57
-:102110001EFABB3C6EAE1271F28A615B0EE33E7B2F
-:1021200095B8BFFAE8C158F40FA7B12F6E47FAC0AF
-:102130007C0CE763CF44E27DBAD08BD3B773BDA8E4
-:10214000B76B5DA9D933298F09712AC2B57A7B246F
-:10215000BEAB74F1F963693C3FF6820EDF15416650
-:10216000CD413854D9E5A7A7DB159CF7482ED85B9D
-:10217000B4936AD6F77E87F14DE1676BFD99E21C57
-:1021800078BD7DA32D3C6E8E4AE7FEC2CAF1B20F28
-:10219000E9D51D6F0C3A98AB1A42F106C419CD6906
-:1021A000493CEEC082923732649698188A371E7185
-:1021B0006EAAC8837EF5762EF79DE3603C3C7FAD2A
-:1021C00030F247ABB79BE99C6235D09FE28A267E0E
-:1021D0009EC2D3249522DDC15F3F9A86FBB19852FF
-:1021E0008575CF6AE47C3FABE40BE297A383F87A72
-:1021F0002F2B6A4A6FFEBBE6B7E3F93035CC7FAFD1
-:102200000239C5E7AB9A783D52C3816FFA67A29E47
-:102210006BFEAFFE8BA1FD5AD845CD2F0C825F38E7
-:1022200090FB45F4BDC9BB857C2DB3F37DBABB855E
-:10223000FD61521DF17995B1FE503CFA593B78BDD4
-:1022400000DB871F8503FDF8F64B75F1B0EECE97E6
-:1022500024AA87C3F7F17B949D4BEA3F41BFFBEB78
-:102260001D16F237EF06BF654A5E4FB9D4E45BFB3B
-:102270006E560D7B88FCCF87581DB595829F3B1B02
-:102280006BE9FBA09ABF42EF0FECE98F540ABEAF97
-:10229000D4F15F547A24DFD5BC1D4D7E63D751D96C
-:1022A0008EFB3180AFDFA485E345F8210D07A288BE
-:1022B000AE5D276D6447FE2CF8EDA2C83FD78C9326
-:1022C000090F86F1BCCD6E796D20D211F18EF5F734
-:1022D0002FB7BC36829FFBF613FE576D9323BE0FBC
-:1022E0005B591FF9FDD79AB76FA3EF0855EFEF863B
-:1022F0006B88293104575F7220493C8E34489171B4
-:1023000064F53ED9135E7706EBB903F551BA900731
-:10231000A6049331FF35009D0680AFA689D3D5D0A2
-:10232000CC5B98FF169E2731D2FC3DEE17F956E3A1
-:10233000FDAF33AD7CFFFAAAAF02FBF70F94A9AE55
-:10234000F3FEB7570E0DD7A30CE104BA561B83C991
-:10235000146F9E34107CD5272F270FB2A15EDA525E
-:1023600082DF0F9D2EF4DFE181D6E5C8CF3E9C379A
-:102370002534CECB69BC7E8FE17A9DE86DFC928FCF
-:102380002BD6FB109B2DE26ACE4F39697CBD108F96
-:102390008C4BEF251EB95EBF13ECC3A98512D63353
-:1023A000293E8C87F7BCC7F5424DF3B28F90DFAB67
-:1023B000DF37539DD7FD2DCB8652BDAFD77B03FAB8
-:1023C0001B5FB7ACB881F283D24304970FE173A2CD
-:1023D0005F732619EB522B9BCF2493DDDD3B7A9361
-:1023E0002F06FD97BCE9781DFC09E23FF06B88FFE2
-:1023F000F6B415687E8C15C7AD3CAA78103F95479A
-:102400000B8E57A07F71A2A800D5B974A280FC984A
-:102410007CF4636C21BFA65B4FA6733FA6AB358AE5
-:10242000F20B121BC8F9870D8AE09FD50DAF93BD43
-:102430005FDD2847D42F6AEFDD99AED038CB34FE6C
-:10244000A997DCC41FBB78BBBA710FAD6F95B19E65
-:10245000E85DB3DDC8EFEFE0ADF67D581F8BF721E7
-:102460003E8EE325A0C334933F03F3D3C732B99F15
-:10247000AFA7C7E7E93CFF71ECAC7700F2CBB14204
-:10248000EF507B2F76C2C78A785C2B097C37F073BC
-:1024900053FAE73E4B97C4774222CFB76AEDA9744F
-:1024A000AE3FA7997AFF2EE06FD2B57309EC3143A6
-:1024B0000146C546FB06E1D7A7867DD761CECD464E
-:1024C000F2174E31FBEB58EF3843D3B3E3B87DD569
-:1024D000E7CBE789F73C9B55BE5FA43B3F334F3BBF
-:1024E000DFA43BEF364FF83BF374FECED3E9C28F47
-:1024F0001FC286A01EAC17E7EFD60E8FF287E7B398
-:10250000F4ED61B12F82E787B0AD19FE2EE57D8E27
-:10251000B59E7D85EADDCE46B1813CAF47F9EFCA75
-:102520003EF2DF35DD72393782CF34BA5C12DF8399
-:10253000D1D365B7A6AFC4BE5DB4D8B7F31BBDBBDE
-:10254000519E2B2D174DBCEE3068427D56339CFBBF
-:102550004D974A25DA6F0738FB9BC3F4FBA5541E41
-:102560007FDD7F8B4479D7567C1EE3AC7A89EABC49
-:102570002B03ED26E4A7210D8B1F26B9F5B1D32C33
-:10258000ECBB1A332DDC4E76D34F5B77B71D8BF740
-:10259000717D9C482D3E8F767186B083FA735143CE
-:1025A000597B593AC033DF2DB9B01EA02F3ACF5E08
-:1025B00030EA7544C3F5D2BB33DDFB4E3ACA79FB32
-:1025C000E55B308F7A6CF867FDD18E56F5C1C71F79
-:1025D0000B3CEBBF2BE31AAAD6E2F7556A9DDE0E41
-:1025E000D29F866F6347301CA7E3376B25A4132364
-:1025F000FEEF4B7E3E13E37E96CEBF770FB8A77DEE
-:102600009755E9BC4EEB98D19F41798A9CEBDBF75B
-:10261000AAD9F7462EEAB3CED6A3B9A630BA5E5CE5
-:102620000B7A00ED4AF3C164D516CE7706E237493E
-:10263000D2F84F11F632920F2F221FE6607B2676DA
-:1026400010EAE35DA76207E3787B79DBCDAF4DFC51
-:102650007BF6101F0D9917130EDFC304DFA57A3E1A
-:102660000E631D43E68C0CBF5FDB171F5B33888F47
-:102670003B22F8585B6F3D7ECF07E38016337DCF5A
-:1026800007F3D78E3039199AC1F5CF58F1FD9EF175
-:10269000CC47DF391C2BBEE3335E6101251EF7CD2D
-:1026A0000232DFF7E5E72DC6087E1EAB045AB18E75
-:1026B00062BCD8E799C0DAE9B9292C48AD9BD9E9C1
-:1026C0001C451173513BCE12988EEE544E7D3DD574
-:1026D00025069215C7798B38AFD10BDD42EB57E851
-:1026E000BB3DC49F329ED7E9FDBB2FB333B8DCD3CB
-:1026F000C74590BE9718E5B9F07B6D38C9448595FC
-:10270000637DD3648559A201DE5D870C24CF2D1D26
-:10271000AA1FEB535D09E2BDCF19D5E18E75737920
-:10272000459383F518DA7AF5789800E3619E6DACED
-:10273000029128E13140F3DDC8F8399242A652FDFA
-:10274000736946A6D0F7418AA38A218E427D6FB075
-:10275000F8081FD33354BA8FFB25B130CE848D12C5
-:102760007B0FF73FB2F87AB5F1270023E0F9C2E911
-:1027700019DC9E614AF5BD78BE8F124B05CD2576DA
-:10278000FE9DA364FACED1F5E2B52B997FEF32F628
-:10279000CE60E7CF0A42FB492EFCEE516CE83B9B32
-:1027A0002EEDDF830844FE7B1077642CF911F2A331
-:1027B00056AFC7BCFCDF7DD0D7EB85D5E7B10B6149
-:1027C000E7B0B5BA926DFED92A9EF35B9068A1730B
-:1027D000BF7996FEF968C7063ABD34FEFBD2F6C152
-:1027E0003498E21FED8909F1BB95B9C721BE437545
-:1027F00083FC3B50DDE7AE92199D57B49A797DE595
-:1028000063201FF81D26902E15EB68D883C5548FC2
-:10281000B9DE6171E1790933C26D0DC15D6B11DF04
-:1028200005B5F07D717D3D68ADCD40DF1DAD65D155
-:10283000740E3D29DABB2E03E0BA2FA688CE776747
-:10284000EF9CE444BF317CFD93B4F51B7AD647C2BC
-:102850007A1FC9E8A51E515BA7F6EF76D805FEB42E
-:1028600075DBB5734A6E25E29C92868FC7A2F9BAD2
-:102870008DB8F39F45EFAAA837F4EBFDFFDC29BC28
-:1028800016A064000000000000000000000000002E
-:102890001F8B080000000000000BB3D36660F851E6
-:1028A0008FC0C19A0C0C5DD2A862B4C41D120C0C6E
-:1028B0009780F80B106702EDF5926460F006E26D08
-:1028C00040BC1D88C5A518180280381088FB80FC04
-:1028D0007E204E07E224A81BB30519187281381F09
-:1028E000880B815848808141588078FB8B151918D6
-:1028F0005EAB22F85A6A0C0CC91AF4F3FF60C3816C
-:10290000B6F4B5EF16D0BEE56E08BE0490BDC20D9C
-:1029100055CD4A37FC66AC42935F8DC65F83477FD7
-:10292000810D2A7FAB292A7FAF3903C3072435DB0A
-:102930004CF1BB051D2B00FDA788274C9730A2F258
-:102940002732A1F2F9A17C00BE1E313CA803000091
-:1029500000000000000000001F8B080000000000C5
-:10296000000BED7D0D7854D599F0B93F736726992A
-:1029700099DC24433260126E7ED0A001879860B04B
-:10298000586E20E147A30E082CB440262888166D07
-:10299000C49FC6DD500609BF0921E14F70D11D104B
-:1029A0005DEA63FBC5565B75BB7682D646AB356880
-:1029B000D787767765A015BFBA761BD96D976EBBA2
-:1029C000F57BDFF79CCBCCBD9900FEECB7BBDFF30A
-:1029D000C5C7E770EE3D3FEF79CFFB7FDE73C725BC
-:1029E000FB59701A631FE31F9413731963B5A9B2DF
-:1029F000C5C362D9398CE576488CD530B6B25D89CD
-:102A0000CF827F1676B4BC82F5E56D6EC35DCA5881
-:102A1000FF036E7F0DD44F6F57C26EE8DAA8F8A897
-:102A2000BEACCB15761BF07CEB472FE7E3FB8D525A
-:102A300098419DB1BB199BCCD81A0FFC13EACB2A45
-:102A4000921DF8FEDD2D523886AF99E99B04EF6F99
-:102A500065FC7DF3038AC664A8EFBBAD894D64ECC9
-:102A6000961E98C5430DD9C7BC3D63058C45F82318
-:102A7000D6B205DE57A6DE4758D7470AF46B8E3923
-:102A80009EEF9BF53E0BE07B2DF51CD6730CFF31C2
-:102A900085B14B993F783A1BFE1D66E18F15281BC7
-:102AA000F2191B9DC297B3640CA01FC5D85CC65C0D
-:102AB000AC1CC6A9BDCCC5CA607D161EDB381E97EE
-:102AC000354984C7653E46F577E74AF1074BA91FAC
-:102AD0009B5E0D253C2FC88332C8CC4228231E960E
-:102AE000C806F8E7B65DF61EAE7F034E359ADA27C4
-:102AF00002F07E018BBA18C0F7672C46E56216A774
-:102B0000F2CB2C41702C6543252AD4EF52129B182E
-:102B1000CC130E45A7E3FEFEAEFED8BB12BCBFBF72
-:102B20005AAA9D0225F3E5D1BA2FB43E6B7E954596
-:102B3000AEC37118935D113F63E3AD751E66B18A34
-:102B400020637A8F8FD3CB61D6CFA03EBE41D04BCE
-:102B5000E3FB7208D6DDF33C0B633D049B3905EAC9
-:102B6000A1AEACF806A8F73C1EAB47BC1C6B01CC71
-:102B700043FF638D6E295A05A54B7745A00CA98CA0
-:102B80002980A7FA86F59202EDE646F938E34D4D25
-:102B9000665742FD704C52C573ECAFEB314987FA72
-:102BA00078A83F28E17BDDC5609C86865C57B20A29
-:102BB000F1DD334687B2E2B0969001BFF5A64ECF65
-:102BC000195B4474355ED0DA5C93F79B7B38CFCFCA
-:102BD000E83DFBD3C7D67BC0EF25457CDF8E1D2E9D
-:102BE000CB417859D4DEBF4865314F5E0ACF3BD721
-:102BF000C10B770ABFBB0E976D45BC1DEB53C3825B
-:102C0000946DE3C3B8BD0DF0FE4C951C560CE4B3B7
-:102C1000220E7F85EED77DA97176AE83F697A5E06B
-:102C20006854A6F6133E4C46FC38B706DA57A5DAC8
-:102C30003F81ED018E3D080FF55B73D48BF3441893
-:102C4000CD33123DBCB04EA77E83621DD7FCEF3062
-:102C5000EDD3DC861689CF2BE06BB0C36795167C6D
-:102C6000238D7F4CC0658D6FCDF7C4BA10958D4A0A
-:102C7000D523F7E2BA8E687C5DF38DC77723FE8E8D
-:102C800078C231A83F79DDDF8CB91786B862FAF3D4
-:102C9000973FC370BEE50FDF8EEB7A2E8BD6F5D44F
-:102CA00087675EBB910D9FF72D81879F9E9B3F4459
-:102CB000756BFEB9A63446023AAB34A5840BE8E541
-:102CC00058FD571EBED7C07ABF89F2A4D23C664ACF
-:102CD000504E846168BF99FAA78F419E554277E4B0
-:102CE000C7490D520BB67BE2C687BE741F3CFAA9DA
-:102CF0008BC37DC55F72B82FBB7EED9308EF653740
-:102D0000AEFDF93350BF028520F0DDA537ED5FF34E
-:102D100077F0CF6F2CFCCBE57B18C9855836C09176
-:102D20006B4A0CF777D9F7DD36B972EC793FC99564
-:102D300042B33486FCB7AC4F22F9DCDFE866417C55
-:102D4000FF3377DC8DFCF5806452FB67DD71940FF7
-:102D5000C75C8CA13C5E76DC1B477E61AB9691BC68
-:102D60008E58F2DACC5F7A2F8CF76E8325CF399D9F
-:102D7000D27B58DFBBE62FB65F0DFDCF98AE308A11
-:102D80004D4B5E38F1FCAEC06FA4BE9CE860999AD2
-:102D9000748533D043739B6293DBF50D2789AE9620
-:102DA00041C9D2F874AEE0B3650DBF10FCA9935CC5
-:102DB00072C2F3466D617126BA3B25E0490A7A7BFF
-:102DC00017F7FB32840F7A21DD742971254D4EC32C
-:102DD0009F2B3281EA3164E95BB6D8E1B4E4764BEB
-:102DE0002CDBA6AF40FEFE0BCACDE6B67CDBF3B90A
-:102DF00039AC76EAA793C37F20399C94081ED0BFD4
-:102E0000B4FF91B81447B968EDCF1D627F22158CCD
-:102E1000D6F3AB03523C06FBFBAB23627DFBA4B8AD
-:102E20002211BD9AA73D382ECC599EDAFFDBC5FE94
-:102E3000A7F68FE3C7C2574ACFE56E4A02082DBEF8
-:102E40004809CA6B8B7F2CFCF6EFF95109EE5F61E4
-:102E50005B69771DC2794021FEFDB0FE6431EEDB77
-:102E6000BB2EC02BF48F1C7E2CC07C29F85B841CED
-:102E7000FCA003E8059E4B0867651A9C026E17D6F6
-:102E8000A1DDED0D521FF2E92FC5BC56BF1F6D9994
-:102E90003113F173478FC4103FB71FE95DF6E7B0F8
-:102EA000FED5F1EC304EF1ABC6E2C02500CF8A1E54
-:102EB000FB7E9EDA727300E9E6C3BEFC021CE7F6F5
-:102EC000A9090DE15C9D78553380CE6699BD5A32D3
-:102ED000035D7DD8B72180ED3F547B6EBC06E7D9FA
-:102EE000A784D7C3F8AB8F94CE34399D12FDAE16AC
-:102EF000F83DA9F6CC1C03F0B57CA39CE4C17B7D16
-:102F0000CAEC7806F9F97549213A58DDE696719DC3
-:102F100023D1CB871D2E96C079D404E173A4761FEC
-:102F2000F4B5D0FBFE070A6F40FBEDF67617C98BB0
-:102F3000DBDBDC444FAB1BA4389352FCB642C0BB76
-:102F40007AB742EF4F9A12C90F6BBF6E17F476F241
-:102F5000F055AFA0BE3F03F207E5EE8C8D3FD42EB7
-:102F6000013CACD8C2E5D1C9DDB94BEF413922F4FF
-:102F7000E51D62DCDBE28A8D3F56B667DBF623DABD
-:102F8000956FAB9F3E927F631DD2759742FAF39681
-:102F90008D8F6921924F767B13396C5241CABE3CAA
-:102FA000C186165C23A5E8C9A29F5BDBC0DE0C0CC2
-:102FB000B7375B8E48648F5EB49DD90676E6C4E170
-:102FC00076A6254722689F95A7E4882537EE52A26A
-:102FD000638300C7AF5DD1CBF2CB496E3C20D522D5
-:102FE0009DE8BF45BB92C5945A946F172B2F68B1CB
-:102FF000161FC1DF7B1D405719E87506D215CC336B
-:10300000B3A73F233DCF900C1A2F4537B704886FE5
-:10301000715080A3D96376219C97C0C4DE6A2A9937
-:1030200092C74B15EA9B1166A087536BA5F8A15276
-:10303000DECE87F214E0BA069E37775D1EDF26A14A
-:103040005D087FA83FDBB8DD0DED4C7F1E3D3725C9
-:10305000288BDA4B5FC6FDB904048056CDDBE33C18
-:103060006067114AA07DC25D4D5D6301288BA19F01
-:10307000CCFBD37B6C1720391EA7F5E2F8384E85C0
-:10308000125F8372C6A2E36542EE805CAD5481BEDE
-:103090009A595618F566735BF979ED971BC276F964
-:1030A00071539D5D0FCC35EDF2FFE6D997D8DA2F3D
-:1030B0008894DBDEFFD9A22B6CEF1747AFB2D5BFE8
-:1030C000BCEA0BB6F64B5B67D8FDA49FE6D27AD676
-:1030D00008BE1C09EED785BCFC89C33EB5CAA6EB69
-:1030E00013356FC33EB175EEF0E3509C98C316F5EF
-:1030F000A5C9159F2C113E7F036CC2FD833F7D4CFB
-:10310000780CF1799BFEC2DD9A89EE34D10FCD2582
-:10311000B4979CED4F2C8679D2FAFD9B24111D9E0D
-:10312000EBC73C3DBF04905B80937300F577B264BE
-:1031300009EE9B3BD7A0F777C9C902ACFF860DED1E
-:10314000CDC7FDF5258B917F9A55F69C9483FDC2E2
-:103150001E37CC07D6106B03FA6869FBD171B4E354
-:103160002423C89660DDE34B207FB30ED787490B3D
-:10317000EFC087BDA1E88712C021B5F7FF5EC2F797
-:10318000DF6706EA61962CCA45FF11A74AE7C3A686
-:1031900019AC15F175A2D18E37AF58C7CF2599DA82
-:1031A0003DC7CCDF221F9D9474BE3E01EF36C93C63
-:1031B0008BF35970BF9BAB6BECD3C1ADC8B508F7AF
-:1031C0008F08EE0DAD2C99AD8C0CF715CC74CBA3FC
-:1031D00086C373969959999ECF0276CDF4FC7237C7
-:1031E000AB447BF58494155E5F8AE5D03F7E0DF895
-:1031F0002AF60D5FF87163385D4C957369FE666160
-:10320000EF16B64B896CB44F9987EC57D6F390E91B
-:1032100041B926445C4B9B7412D7CF3A1ACDA427F0
-:10322000B55E66482CBDDDB97D6F73537B4BDE58B0
-:1032300072CBC2A725572CF965E1D539FE48720635
-:10324000C753F310FEE824399D4E74C0C70484C7E9
-:10325000ACC6FDB3F60DDCC898A77AE47DB3E414E0
-:10326000B463E8FF8FB45F8027B2EB5C6146787A85
-:103270003738B4F42958F7401BD7D7EF1631B20FBF
-:10328000CFB45D359083F8F1782A103F857C2A56BB
-:10329000181C5A87F2D5A726FA11AE42A1BFBC8CE2
-:1032A000EBAF4266ECB81AFDFBF6934BB09DB53F11
-:1032B000B9627F9A617FD01F69F60D15A39DE44620
-:1032C000BD06EDDC2077512E17B6BFFF1FA8170BE8
-:1032D0001D7A112161E9706455EDB8DA481FFFA32A
-:1032E0008D685F5AE35287F4FD0F6A2711BF85EDA1
-:1032F0009BEF5602B6F1A58F110F426EA3D9756EE2
-:103300009E52B457E5843B90A20B275C56BF91E8D0
-:1033100084A5CF536EAB933DE1ACBBC39A4D3EBF8A
-:10332000FBC7F29C56DF79E8CD399E93BE9D7C2089
-:10333000F0F029E87413A7532E172CBEFDCFA2D3AB
-:10334000A8B5AFB1DC3B8EA07EEDD2C2B30CB413F6
-:10335000867EC8ED04B77108E92C266555C2FB6866
-:10336000874A76A36557F4AFFDEB2D65F0FC44ADBD
-:103370004C7EC489F59CEEF73CC0ED514B6F478500
-:10338000DE46BB00F10A76C3809B971E1CC7BFFEBA
-:10339000E65209E0F61843FD6E6CDF6690BD9A5365
-:1033A00017D71BA18C571CF28C3352722919CBCF23
-:1033B0005B0EFBF5AD5C635984ECEBE8E8B9FED439
-:1033C000FB1FCB5C3F4D2B6179B361BCE45639FCEC
-:1033D00020F44FBAEC7ACC2AD7285C5F26BDAC0427
-:1033E000FDE091DA0D29965ED535DA97F903C771BC
-:1033F0009F46DA07D8019DE298E7E890E31DE6A131
-:10340000F1937EBB1E3A29F49005FF27D0AB0B8BBE
-:10341000813EF64A99E1FE488C177D0E0080FD8EB4
-:10342000AACCCCD4CEB9EE7F10FD12B24AF3EDA8EF
-:10343000D8391BF73B1653C2E9FB61957FA170FD9C
-:103440009933B721B711DAB1F599DBE589768FDDCC
-:1034500097B508FD2B409D8AF19A504C9F371BE38E
-:103460009153F326A18FFD63D43F30EFEEC819BD11
-:10347000C5F789F051105246C6C79BB2CCF7D1C1EF
-:10348000B77BC05D43F999943C147F6989B933F2E5
-:10349000B125A79CF2C8A9E724D3646DD5C3E58AFA
-:1034A00035EE27D567201FB2945129BBFD9C3EBB4A
-:1034B000587A1C410E94C82CDA97C13FBD5AE17866
-:1034C000EA8FF138856ACAA4B7662A4D4C023C6D72
-:1034D0000832920779B8D7C8B70D2C0E2860F92C9E
-:1034E0003CE0437912945982FC56A71F6836A11F0D
-:1034F00018E4A0317D54597F213C0FCE5F49E70C81
-:103500002CC2E5AD0EFF713E32495FB8055EA3B136
-:103510004914E7CC6BB2CB7137FA81201FF506C78F
-:10352000F3F933E9BCC1CDD29EC33AAE52FCC1D34C
-:1035300060DAB36A5683FC59BDFFAA5D8B61FC9AC1
-:10354000476E7E1BCBC907EFC9FF1294758FEFBA88
-:1035500019CB92D7A26333C553AD123885C9750014
-:103560009F8F19EE9C91DB19EB9508DAD5B08F1D72
-:10357000480FC9587916D2F72A85F37FFF022D80AC
-:10358000F119750B97ABEA7C401ED13FF7D39B53E3
-:10359000FE34F915AAF093947685E20849BD8CE2D1
-:1035A0002D87B6C81A96206763388F357FAF88534A
-:1035B000778A78AB13BEDE92A162948327D67F44CC
-:1035C000F6A1A2678567C37C5D7E5642708878410C
-:1035D000B3D8BFE4DA7A4F7ABC48117E4EC7D139EE
-:1035E0000306D2C18012F61AC4371A8E1BDD329D33
-:1035F00061FC65961E66684F740ABF47F1990CF727
-:10360000355B6733D1AF85575A08FB57B17002FB62
-:10361000B7F7236E61BDE6EDC8073FB896DB2127FB
-:103620004AED721B48A80BF694CD2A5AAF226D368C
-:1036300005275D8534FF7BA540C8554EAF6FD44E3E
-:10364000796C1BD0C1736EF31E65D427E023875CB1
-:10365000FF01B009EEDBA3925D9E5BE541271FB53C
-:10366000496417AA265FE74CE5C346D4931BC16E95
-:103670002C3486F3CBC6D719D98D1B81FF62A5994F
-:10368000F8A75A421971B1FC93D79E2B611CE3B382
-:10369000F2CF5F2AE29C4EF00FD05902ED984725F9
-:1036A000A3730AACEF3BFB1A7F3C055E3F7B604592
-:1036B000F635507E2FBEF1FA6B60FEDB1FDF938D77
-:1036C000FBFCE8ABC04FE7F1E32D7E6A461BF63CFE
-:1036D000713663AD9D9F8CF515C44F6F295C7FF5E6
-:1036E0002FF8DD1B57FF7F7E3A1F3FBDAD007D4E9B
-:1036F000FBD3D9E2E879E45B7311D3D0DE823626BE
-:10370000D27934682F7D6A16E17B9D8BCB31BFCB9C
-:10371000CBED8E107FEF1CEF6FD44F1E3F5850FE45
-:10372000D9F9749DCFFCE8F3E077903B246F4E8C81
-:10373000B3F37DA78BD3DDAF5C9F787DEF7CE17326
-:10374000581FD8F564DF5DA73203FD80892F7848C4
-:1037500058BC3A6EE311648969F03C94C7DFBBF34F
-:10376000485EC6D18E19522AA9BFC9B81DDF54B30D
-:10377000F9083F9718AC5804FEF21CF817DA23D763
-:10378000F9B85F01E3B0108CBFDA1B2D5647D17832
-:10379000E45FBEFAFCBE20CA97D73D66093E674982
-:1037A0003517CF072CBB63647E57D9E9343FEB69EB
-:1037B0008D111CA72ED5285E89622C00F5ADA5972A
-:1037C000529C928563C725AC8FD219CA71251859AE
-:1037D0004C76489BDB9805F5AD6040C58244B72424
-:1037E0003795F6DE5000E500D825F85E8DCDF568FA
-:1037F000E8BF8C923108CDDC6D1F91DF7DA298CBA4
-:10380000DB8E298CCE69061EF8B7A532DA3BED6E49
-:103810003AB700BB91F8352AE44632383DD4827E6F
-:1038200046911696A0BE29F68BE35FE3F2C4F44CF2
-:103830004E8F8FF078474B88FBBB4EBB6FF3D72F73
-:103840007BD3C0F17EF85AD7E550BEFEE4CF5FBF10
-:103850001CDEBDF1ADD76A30EEEDAED36C714737EB
-:1038600033DE447B0B7CA68486F2397672096E6661
-:10387000CAAF9362889F688D3F8EEB45DE46FC247D
-:10388000A728FC7C11FE42005F40C0D71D3C554577
-:10389000F3C4DEFF8F4CF29EFE260B3D02ED36E7B1
-:1038A000DD1F4739929A6F12C9A728C827F423A3AE
-:1038B000BE9E256B683E7FF841ECF347D8D5C9A979
-:1038C000F3C2435BE6B5209EE72EF0E84867EED8EA
-:1038D000E6BB91CE9DEB3CE37BF0520CCDD9E607E5
-:1038E0003E715768A697EC5F7698F64334B1E0D600
-:1038F000418160DC01FA2F5BC132F437A03FAE1387
-:10390000E419DADB563F206313D77BC637FD528AB2
-:10391000F78B7885D5EFA69844E7043795031B9479
-:103920000FC7D3069FFC93AFE1B94B4CD1154E079F
-:10393000A18A34BCE19F3D6EC6E9E2B27D76BD0B43
-:10394000F32F2CC5F73185E8C5C92FE3E3F6F61B45
-:103950007CE73FD71FBE9F1CCF1305BF59FD2DF835
-:10396000085E29537CDD7E2E73539DBD3E77183E45
-:10397000CE0FD774D57E6ED3E0B38F3733687F3FD9
-:10398000BBC85EDF80F19B4FB26E07DF3D3DC6FCDA
-:103990008EFA19FC7A4BEEBEEF89FC2D8DA38619A9
-:1039A0008ED3BF60EFFC794007853AB73B0AE72F1B
-:1039B0006CC8AD4139C5449E4966FBA350E87BA560
-:1039C000FD252507FD5193B74F2E796B460E9E17A7
-:1039D000D7313A4F8FAAF7C4728C943DD2AF966715
-:1039E000219E3F7F7BE46E6F7ADE4DCA1E79E055E3
-:1039F000A326833DA2DE239930CEAC25608F54A54B
-:103A0000DB23AD12CAA0EC25608F90DD117D0FF194
-:103A100035925DF263CBBEF767B6ABFFA0723D0B8C
-:103A20007AE69F3E8B9E19E735FF45FD1CEC8169C8
-:103A300025C6CA48063AFC40E5F10E4B7F36061310
-:103A40000A9E9D83DE545DF0FCDABAE44B288E3B7F
-:103A5000F49D415C37ACC7E5AAFDF4EB39A372785D
-:103A600026AA3C0F66A47EDF1AC15FF16A5E61B7C9
-:103A7000D8F7BB7FC13BBA8CFE0BF831E8BF247D81
-:103A800065DB302E7826A652BC4E9DBF72F75CA433
-:103A900027B0B3393D9FDFBEBE7648B6F1F1B4B36F
-:103AA0005936BEAF67F673BA191EFB395DA36E3F78
-:103AB000A79B15B29FD3CD31ECE774D757DACFE986
-:103AC0009CF6FDCCD1AEFF9EF67DA891113F5DC066
-:103AD000BE077EBA09E969247EBA2EDFB83F92613B
-:103AE000BFAB356EA7AEF6461620DD4D33B85D1779
-:103AF0008DADA77CC0BC28C89B528A1B52DCCB8AE8
-:103B00006B59712F2B2FD08A6739E35756DCCB8A3C
-:103B10006349311EB76AF6445720BCCDED27659442
-:103B200023FA73300F3282758E372C3EC7E5414B36
-:103B30007BE6B89C33FE3662BB4FC9579F837E58E5
-:103B40008FEBB5F403F0F9839F85CF416E6DC3F120
-:103B5000FE05F97D14C9936EDABF0AC035DAE9B003
-:103B60000F1AC6E9179CDE8FF138F5B89BF8F6629C
-:103B7000FD5F4C749061D3A2E083633C2B1A2B252C
-:103B8000FD62F18DC5274EFF78187FFC57F3CF45B6
-:103B9000FAC7C03FDF739D471F017F3C8FF89E56D9
-:103BA000C9F1EBE4078BFE8124125235EE773481A4
-:103BB000ED2D7A672F864D8473A2F06B4E8CD6C89C
-:103BC000BF38F1FCBFF373D8E73DE171628DF87E39
-:103BD0006277417C5B698ACF2C7E6AF7447FEC4A2E
-:103BE000CB03B1F21D0F7BCCD7F17948ED4BA0BFD1
-:103BF000129ACDC21B0CE2B363FC39E7535F9851B4
-:103C0000FCF433FB657B5D713C1F6A91869632F252
-:103C10005B99867CAB0A79F26256F424E2B3797A36
-:103C2000A484D3D3D0381FC0F58B0E85FCB5CFCA82
-:103C30004FCD23E1FF1C3EA243AEDAE1F901E97268
-:103C40000BE55B28A4C5374819E495C0579C85C788
-:103C5000E0FA603FFF1DF19857C5245A8EE0E366F5
-:103C60008FF907D767B33F14AD36C5C780378F8646
-:103C700072B11AF0563E1C6F275D7CFD4EFA0BA9FF
-:103C80004919E93F0472748394764E2AF062AD6755
-:103C900024F96CD169DA7943484B5FEFFFA372D9FD
-:103CA0009297977BA293711FDC6644C83F93F6D727
-:103CB000296786DB41329D339E01BB07BB5DAC7C2F
-:103CC0009D76D68B87256CEA5985CA6BCFD2E109E0
-:103CD000FBE2D96C2ACDB3F954D69FCDA572FAD99F
-:103CE0004BA89C717634950D67011830711ACF96E8
-:103CF0005239F3EC1554CE3A3B9ECAD967AFA2763F
-:103D000073CE4EA2F2BAB35FA0F2FAB353A874DA3C
-:103D10003FC67A95E4B725BF2CF9EE94DF96FCFBFD
-:103D2000BF26BF630D1765FF80FEFBAA761EF93D17
-:103D300092BC00BEBE4F4B971329FD7CBFF619F80D
-:103D4000FAB8E053E0DFF7300EE3012F8EE2546162
-:103D50001EA70A189A81791AFBB0096CA9BF3472A0
-:103D600012E306CD0B3C7A0CE01E28D5483E6D0BC5
-:103D70006A74EEB659D2477379904C20FDED0C6908
-:103D800034DEB63F2A5ECC5F7869544100E7E9F63D
-:103D9000CB3AB6FF566E72DF2D788E3F85850FC108
-:103DA000782BF6ECF1A4FBE1FBD13800F802B1A7C7
-:103DB0001903BEDE38EA774B713EDF5446F118280E
-:103DC000CD4CF962DF748BF36975288478DAEA9355
-:103DD000491F74EB1E91879A1C68413FB74E66DB02
-:103DE00060DE0DA3DFD98260ABE3CA7694417D67C4
-:103DF0005D991737E9E9573E08913D01EF10142806
-:103E000013A23473607F3ABD61E37CE76D8A31B4FD
-:103E10000E8915FBBBAB476EB7C93F1042FAE89855
-:103E200034B9F21698BF7752C1689C7F7BCD511B85
-:103E30003E14DD1E4F5130E0887E785D92E26A1BB1
-:103E400064634719AC2F20F2AD01CCCA485ADE8119
-:103E5000058712867570B8120A5F0F2B80E7B97557
-:103E6000895892AFD7C4B8ABCF970CA1BFA8D49D47
-:103E7000A6785BA73FB988EA0E38ACF17FAB5979D9
-:103E8000019C6F7C826F9A277D7B11E5915769B405
-:103E90006FDDAEA105588FAD75B1C733C46F36085D
-:103EA0007EDE5679FEB88CEAB3C3D1EDB5FB8B1636
-:103EB0003CEF8BD20947B36B6854A6FDFBB4F35FAC
-:103EC00068DD9FF77C9D23E40F5CEEB6EF4340C8AE
-:103ED000F3E629DF0EE1B9B8054FA704FB50F3F96B
-:103EE000EF43F3142EAF3FEFF5FE4F1BF7F71A8F9A
-:103EF000AB009FCE2EC738E398C9218CD7FAAC7897
-:103F000074384EF949018C47532F83F490AAF3314A
-:103F1000149525900FE5EC0F13B84F4AB566282489
-:103F20006733EFBB12DE44796D4EFEB4E0A6BFC925
-:103F3000C274A0F343AF159F36D4C9FCBE04C67F3C
-:103F400015669DCFF2F8B4D55FAD90291E4D81EC7A
-:103F5000B47154D0C3788EA3609C3A6FF8FCDF4DE7
-:103F6000D1A37DFE221E1F5754EE07BE27717CC4CD
-:103F70005E5528DFB3EB792EDFD87146F2BBABD6A6
-:103F8000A073951DF03FFA0FB15A5F1CE95671E41A
-:103F9000E39DA99C1E42396AC5C5693E7E3E4071BB
-:103FA0006ECC53A4B8B9C12AF07DB700CD1A47B57D
-:103FB000E2F2956B26613BBFC13CCFC1FAFC752C88
-:103FC0007109C01B74B76EBDBC34433CBC72CD37A5
-:103FD0009E8479773F35FD574F427D971C7EB50E05
-:103FE000DAE57FB98EF0EA8C876FAB944D1DE583DF
-:103FF000CF7708F7156C68A28B5B7BA4183ECFF6D1
-:10400000F90EF2FD6E0D298817D0938817AF332F64
-:10401000321DDF6508C7CE8179F06FEFD679CB709E
-:104020005E841BF32B57F4D66BA867824BECE71723
-:10403000FE267BDD5B658773ABD8BF0BD1BF330F2B
-:10404000B1C79CB708E9F64C5063286F36AEBDFA8D
-:104050004692FBDB1536AE3403FD3AD6D5A9B948F6
-:10406000FF771BF57B2B506F346894D7D31DF7C6B1
-:1040700031C57B7B5DEADCC466BF1B1A3FC7AA91D2
-:1040800013EE4C76BC381F0B8867CC710ED63D5BA7
-:1040900026BBA6BB87CF638DD75DF79607E5C448DF
-:1040A000E33E3DC63CE2467B2A9A7751F72EEEDB93
-:1040B000E8E2743D458B4BA5688FEA0B17417DF311
-:1040C0003899EC2126FCBFEE6BF979E2C39A61BB0B
-:1040D0005FB169CA4AB21B6E72EB82BFC02E9C9060
-:1040E000BA6F71C06BBEE086E7EA733012D803EF97
-:1040F000E5866F44BA680C7E4476D4AD45B28EF442
-:10410000B5624F23AD6BB32EB304DABD6A2B19A988
-:104110004DACD5C4F3004CD444BA9B036F64BA17BA
-:10412000913CD40970CE195738691BD4DC45AD9445
-:10413000C7D26848E4875D07984179D0521C51A5E1
-:104140002AEC37FF1DB4FBE6044B65F4F7AF535977
-:104150008396669F835D7CCC9DB6AE13E3F604E543
-:104160002A9C1FE6C1F91779E83E811BEDE32B532A
-:10417000F6F14444649A9DFC6B342A319E5194F8C4
-:104180003DE5797F3F29E3BCEC0556BD4DFAE47E61
-:1041900035F897BFC4FD8C33A31F530D3F6B5CE212
-:1041A000EB9AD827716FE5B027F21B1CDF8A074C0A
-:1041B000D4F8FDE6CD2D2C1C4B8BAB6C7EFECF8F47
-:1041C000A3BD6AC55FCEE5DD09382DB837492C8B14
-:1041D000F4BC27FA0777BA5FCC926573277C7E70B0
-:1041E00067C897F3D5023F8D15FC93575BE145B93E
-:1041F0003916F37D701FDAB93C31E1BFF47C1F45FD
-:10420000305F30DCDA2F1BC3E59222EE4D015D4BAF
-:1042100068C73AF38114CCFB99385C6E1C10F47FAC
-:104220008947E4FF4C6693B91F6E3FBFF22FE57AD2
-:104230009FB5E665BC87FA7DA1F75F147E6542DC19
-:104240006B3C2AEE2DBEBCCE203FEF957595540EEB
-:10425000AC0BD3F3D7D6D55199BA5FC5E7CD177656
-:10426000988A41353CE7F7B1B801F0FA47AD192813
-:10427000453EAFE3F7BBBB9B4E6D2927BB919F5BD0
-:104280006C2EAA4E14A2FF02B0E643DDE5EBF3F07C
-:104290007B5EE6606501577388F7FFEAF30A275DE6
-:1042A000E8D6FE3BF6DBC75A19CABB8069DFEFECE4
-:1042B000B0D3BFE1FBEF2ABAB87DEFC57FC03E7E29
-:1042C000C9DAF7ABD9D5FCFB0C17278F918F2A855C
-:1042D0001C1803FC7400FC79B7C2F3D5F3799EABCC
-:1042E00019E2FC66AABC1E1B2FDABB3809B1813C5F
-:1042F0009ED75ECCCF13A81FE695E37B0C4BBEC0C8
-:10430000E35B2C47E4BF8F15E3AC16E34EACA67B12
-:10431000BBFCFC9FF5E958FA5892EAB9C007580669
-:1043200059AB84C81CC306C9DF2E9686A86E487A8E
-:1043300016D6CBA47019F7C3E3A43FCB15F3DB1556
-:1043400084FC88CCE345C9C5644F825E46B91857E2
-:10435000238B50BE6C68D3C28089737972787F0ECC
-:10436000CB0D7D350378FE118BC9247F94E75896D9
-:104370007E25D97BA4BF36ACCF3B984DF91A49CAEC
-:1043800073DFEF29B5E9A989BE85D7E9B05F1B4581
-:104390003E9D0BFAB30CF9A7563E1D8C5B92E9BD0E
-:1043A000556EF46B8B32F9FD0F7B2411CF488EA62E
-:1043B00038A0D8D7F85439E37DC67D1E6ED73C5A55
-:1043C0009AD99E66EC411A6FBF47778C9B6CA1FB14
-:1043D000333A8F6F64B94CCAAFD9D8C6EFE95BF8EE
-:1043E0001B0D762DDAC31BFBE6CF46FE8E55AA9435
-:1043F0006F0EEBF721FE5C222F79E3F8E0C16C1E13
-:1044000097284539DD8FF8AB4DC35F706513E2AF78
-:10441000E3559EDF0BFADCC732E41B5AF873F9D878
-:104420001733BDB7CA8E51DAA24CF7868F7A2C3B70
-:104430003D59CAE984E32FEB5A3592A97D42E0BB8E
-:10444000A48C45CF87BF7E8F6E1BD73AF755468821
-:104450007749BE04C5B9266ADCCED8B098E375C3E7
-:10446000F3D71C8FA69D43FC12879C928A075B7131
-:10447000634B6FB67BA2FFE81995D297ECFB8CE4F7
-:104480002E7BC17310F72DC339C4294F6D867388F5
-:104490009E8BFBBECB58C1B787B61C9D87F3FC55DE
-:1044A0001D23FB2AF00C9F37576771B914BF536067
-:1044B0004A1867B926A2D7A3FDE66A6726E6CF8C1D
-:1044C00015719BC2F63E05E922087B5928E1BDA67D
-:1044D000640CBF67327637233F512D9CB96ABD21EA
-:1044E00044695A7E94C286FA697DED9AF1782981F1
-:1044F000F553D40F63C4FB40FBCC5FA1DC1C1389D4
-:10450000521E2EF48BF9D1BE10782CF072BE5DDEF7
-:10451000109624681F0C26293EE994EB63003F9710
-:10452000A4D96F015167ABB89C96E13FD4F3F91160
-:10453000BBDC1EE7B8171D70E4BDE47A45BEBB25A1
-:10454000B78BF8A64E5007E54C7E794ABF3AE04358
-:1045500019569DEA1FB0EA9F113E2004A2670B1E68
-:10456000BC4A8972778F4BFFCA53A89FEB359E4791
-:1045700026EECB650BBCFBD061867603535E3171B2
-:104580005F7784F97769CE4C9D477E68769D759FED
-:104590008EDF5786328671BA6C31BF75AF2E9B198C
-:1045A0006F96033D649B49BA57A75BDF55305902AC
-:1045B000F370749F4C7974BA2F42F2A9678147C790
-:1045C000EF7C68E29E9E4BDC1FCF364FD3FDBAECEA
-:1045D00061EBE3F7EB2CB8B3B3AADE2C376CF3AC8A
-:1045E000C7F836AC7D74C6FB7575DC4FCA36791CCE
-:1045F000226D7CBA5FB7636A99ED7E1DCD837E9C88
-:10460000A03FEB9E9D13AE73FD6A32DB6913C27649
-:104610003BE242F7EB5C217BFB1D17C8CFFAC4F7E6
-:10462000EB041E86B573D8832ECB0E1D2533DCBF5D
-:10463000330D327D4724F7A3646486447109D2F7B1
-:10464000969D97C787FA6F67E7E55979FD0E3BCFCF
-:10465000B2DF7267DBF1EDB4FBDC5511EA73B176C2
-:10466000DE2EFC07D0CB435E879DD794993E9CF20B
-:10467000229F0DEEBE12C6395AFB2305F3D576E50F
-:10468000F2EF1FB161FEC15B33685F7CFC7B47BB0F
-:10469000A6F4ABF8FD9BDF2D656427597104B78044
-:1046A000795791BC9EC2EE5D0F117E82020F4DF8CC
-:1046B00001B21AC2557C1CF199E9C5BC85FC26469D
-:1046C0008D0A2BC2B4EFF85902992E6DC554D4E36C
-:1046D000F58895343CCDF0D8BF13D0A8E73BF6D190
-:1046E000BECFE7CEC11FE4DF539863D8F7DDF29366
-:1046F000D09CC5F9AEAFB4D3C1092932A84097A761
-:10470000B34A85FD33A8A3BEEC5EEB22BBF1A12525
-:10471000655BAF447F3528EBFC3872681CDA47CD07
-:10472000474D2FDA79DB23D3BDE3E0FD431D4A1863
-:10473000CDC3A796AC7915EBB1DD2EB2839EEA9B73
-:1047400057B0228DEF36EF5EB07031BEEF70917EC4
-:104750005FB1E7BE81D220F677D5A67F6FAA65E369
-:104760007D3AFA6D6FD47A33DA31576771BB64A33F
-:1047700096A4F8D3C6791A43976B6349FDE8156888
-:104780003F5CA365BC4F7E57969BDFE773B54A2815
-:10479000DF0BA399EF0558EDC6D6FC96CE3182B358
-:1047A00065867E9CEBFA7932D61F827DD5A5143DB5
-:1047B000E5097ADA5874EFD60A5CDF40E67B875663
-:1047C000B9366B1CA7D3889DCF5D854DA371DD2EB7
-:1047D0007764A01E89AB50D6312EE272B7466E4682
-:1047E0007BF46A175238DBDCF1C38645B82F614988
-:1047F00097609EA01A59457416CC62A80F1A964469
-:104800005A112F85A0FF30B45758F44B3AA728AC63
-:10481000D39817EA9E253D0917BCF75444AF42BC14
-:10482000BFB4967FE7A530E8A37B4185117E0E5784
-:10483000D8EE6668326C0417D845FE814471222791
-:104840001F59EB6A5ECAE5F8EEB5BF1D95E97B33EB
-:104850001559658457AF615FB707F52E8C33D51CAA
-:104860005C42F8AE71B338F1AF9BE87B57AD8BE09B
-:10487000DA35E5E45710AEDFFD3E8BF6FB5A664AAB
-:104880000857FE103F67B5E6C96F1A54783C9CF391
-:10489000A193EF2C7E70C2B773F63C3A8FDBCC0647
-:1048A000E723BE636765A2A3CD456BBCE971D15612
-:1048B000417FB00F245F623AA3FD56FE95ADC77CE1
-:1048C000D88D5F8C54227FBCEDE5F756EF5BAAD103
-:1048D0003A1E9AAB51BCF1217F2BD1FDA98DAEF0D0
-:1048E000210447D517E27EEE2EAE0863BCEDEFF053
-:1048F000F039CD3FD83DEA4B9588CF2FFE218B8FE5
-:104900003345B5C6F919D17BAD97E09CA1B4FF6CD6
-:1049100005DAA14BE4C9943BBD6A09C92F9790E31E
-:104920002F2FC9AB473F2570C372C6E5218F5304B3
-:10493000D656F3FB0C0EB99FA85377CFA05DE2F1DA
-:104940009F7A21EFC6DE30BD1ED7592FF482A966AB
-:10495000FE2E63AE685F381441936C58FC2757E80D
-:104960008FB1BB1DCF855EC81D16071FACB819E4FB
-:10497000CF97B2841D3942DC67D79279C40F678024
-:104980001F282E5D7292E83F067202EDE637A4649E
-:104990006845DA7998F59DB99F887850C42CA53C74
-:1049A000E1B7443CE8A7E2BB73EF8878D071110F00
-:1049B000FAB98807FD03C683F0FB61DECB69DFC669
-:1049C000D57DD48F719C9D350B3C068C33551F7C57
-:1049D0000981FCA239E813F9F7046FD0D24373CFF1
-:1049E0001FA74A205C6E8C4B71385F16DFA37B4596
-:1049F000C03520E07A4DC065E941941B48676CAC36
-:104A0000AA67928741B555C2F35E9417FD4192178C
-:104A10003C4F3CB84632260C971330DEE8743BDD41
-:104A2000A2BF53A37C44C7CEF11FCDE2F70E5F5A5D
-:104A30003B6B3F0BA6C9A3C8C2554877F9B03F28C6
-:104A40008FA24D5C8E47F1DE459A5CB5E269B023DA
-:104A500061D23B37703C8D245F2E24570A1D72654E
-:104A600037CA15A8EF46B9124C972BADFDB8EE200A
-:104A7000CA1596D243C1C827932B3FF396D9E22497
-:104A8000967CB91AD898ECC430E853FFA7D7A76F23
-:104A90000B397121BD6AE57F044C467A7D0FE685AE
-:104AA000A03F339ED13D1CC51CA47CA2DC7617C35D
-:104AB0007C90ADD86534FA330B291F64C77C8F8E88
-:104AC00074F1B09408213EF7493D5EBE2F7A3FDA7B
-:104AD0000BDB26F038C98E3FDEE3453BFBA5DB0B45
-:104AE00002788ED39B6BE581E88B6F85FAA94646E9
-:104AF00074B262CF0A5BDEC3CFB3F2081FB9319044
-:104B00003F808F876FE7FA4737781E089419F34084
-:104B1000DC3E110F526321A48F6D52D4437198462D
-:104B200099F4546F98E7AFF4825F8EE783BD0D3B35
-:104B3000E7A07EDE70ABCC285FBCB2E71E94331DCD
-:104B400013161AC897AED1656FA239BEC1277BD3A1
-:104B5000F348F13841ABE6E786A2347300E4CD5E5A
-:104B6000D338DFFD5155F87DD8DF7D9E3CF8CEDC93
-:104B7000D0688C13F4362E0CE1BCBDA322A13CCA34
-:104B80004F1943F6C0C6519B1663FCA963B9C6D240
-:104B9000EDA461F305EDF6B51567541B78FE488763
-:104BA000CCFDCB5C713E0D7C5589784B5F27C2A94B
-:104BB0009A3C7F04D7ABF0F5D2F74D731BC03FACE6
-:104BC000E2EB47FF55F7E9A3517EA80D3C7F64B3A4
-:104BD0005F5F8C7EA3130E6BFC6BB3259B7FA45B86
-:104BE000790BF56BF8396211CF5BE8759D3F6FA1CA
-:104BF00043C843CB6F1C091F2EC73975AFD71E079B
-:104C0000B4E0B952944E3846CA17F8B4F35F68DD81
-:104C10009FF77C23E511ACC9966CF72B72AD7C969F
-:104C2000C635219413163C9B2F903FF269E16A6EC2
-:104C3000E4ED3FEFF5FE4F1BB73E9BEB47E0D301A2
-:104C4000BC47D931716608E5502A1E3334508EF6C0
-:104C50009CB8CF68E58FB874FE4F55E5DFB993B3C4
-:104C60008BE83BCBEA749E3F427F19F240363136E7
-:104C70001BFD1D55C46F9C7C7A21F89D792337FB61
-:104C800084DF1875CC27F2449823EF440DF1FC1211
-:104C90002B9FA44B82F50553F92023CEEBC0DB7884
-:104CA00021F7DF73F41FB6EE30BF5F69E59F0CCBD1
-:104CB00023992AEFC72D18964722F2517A728D3820
-:104CC000CF13E77925A836319E372C8F64EAF4108C
-:104CD0007E53725A89E87703A3EFEFF67879BD77B0
-:104CE0000E8BE3F7CE7AB18EFC54CB28AF65587E9D
-:104CF000C9D43584278D4596F1F31D7EDE6FE1C161
-:104D0000995F72417ABB401E49D0677D8F2242F382
-:104D1000F4F8C33FA923F8643A8F2FF8D2F170FA60
-:104D2000F897F8B89CEC1179783DB9F67CBCFBC4D7
-:104D3000BE548876CEFDD58B385D77D5EB1477776A
-:104D400037F078E5B0EF40D4D8FD01673CEF8490B0
-:104D5000D7175ABF33AEB76D84FB660B7C3C8FEB25
-:104D6000A12587282FF6CC2AD0B380AF87319FA505
-:104D7000E6E2F3595ECFE2F92CBD46FDC24B518FFE
-:104D8000453586F2B417F359E0FD868611F2594491
-:104D90003CD18A8F8E94CF927BEE3CDE9ECFD27B2D
-:104DA0002BCF67E9EDE1F358E3F53654939D35D207
-:104DB000B84F8F31651FEE7FC5C59D9F4E2B89FC77
-:104DC00019E6AFF4946AFA8306D20BA7E7AE468DD4
-:104DD000E8BBCBC5FDD8D868EE3733351E5A086D11
-:104DE000B6F8138B289E2CF2327AC5FDF9BFCF326C
-:104DF0006CF67167E3774368D7031DBEAC733EA1C1
-:104E000071F2D5D2F5600332B7DE62A24F3990CD90
-:104E1000E308AED0B181BA343ADD22F41DE2470690
-:104E2000FCE44AE7F015950B28BA4F7F6B047DBE72
-:104E300091CDE7B7E890A993C2FCFC8F55A01CB1B7
-:104E4000FCD761ED3CBCDD30F9E390233D98DF8673
-:104E5000154B9EDC60C9133B5D5AF28339E4CC39B3
-:104E6000793287DBE9E7E409C80FFCD499530EF5E2
-:104E70007AB9BEB0E071A3600639F29E2B6C8BD379
-:104E800038E5CE85F8E8F3963B2F65E70BFB83CB3F
-:104E90009D20D206F24DB6758EC8EF3D9C99FA2042
-:104EA000C9438FCAD7ED8930FA9D00ACA33CF7E027
-:104EB000394A46B95E2D51BC419C8BE48BEF0F3EC5
-:104EC000EC0A537EDAC3C0CFE8E74D309CF6D9F93F
-:104ED000CF159CE7490FAFFD1AF7CF00DFE8775DEC
-:104EE000AC1CB2E4C487D97CDDE7E8CBE4705AF4AB
-:104EF0009546CFF47D018B7EAD712D3A66C8A00535
-:104F0000E7A15741D7188EA638754C8A631CC4CACE
-:104F100023B3C67BC3C7ED9191EE5759EDBE63F93C
-:104F20005DE7E2C17A40A77CB21EBA6FCEBA38FD07
-:104F3000CD61BBD53555944FA032CA278894A03F88
-:104F400073D867F78BAD7CB06925E110CA890DC2B3
-:104F50004EB7F2C8ACBCB4C3BE5CEB9CD9969FB64E
-:104F60006184FBD96F9EC3CFC57FFF04BFDBB6DA78
-:104F70006B3E8E7211F0658AEF39511E9A35EE77CD
-:104F8000059E5EF7984FFA3EC3FDC917B3EC7957FB
-:104F90009D3EC31117E0789DA8C7EAE93E5E94DF05
-:104FA000AB729EAB8F74FFD5796FEFDCFD5771FE4E
-:104FB000DEEC89BE4CF0BFC8F3DFF470F46027FB71
-:104FC000FCD673C06BFE04C7EF14FC3D2DC8EFED9B
-:104FD000BCEF89BE8DCFAF63DCAFB6EC9CC3D80EFF
-:104FE000FAFB5F06A90DF4B2A996D36B5125A3EF86
-:104FF0008F4F6FE5F51D4BF9774DFB5FE7F73EB639
-:1050000045F9F74CA15F9F0C78D9319EEBC3FD5554
-:10501000BCDF7EBCDF847C5AC1EDAE3C8CDE2B282D
-:10502000AEA3544EAFE9F14E80F70796CA1417DDD0
-:1050300023F822C04C8A736CABE4F3ECAA909F1067
-:10504000DFA359740BD43B67AF9C8CF74BB68B78BE
-:10505000CABEC52B9FC0BCBE0F02E582EE1274EF24
-:10506000B5E7F86D141F7968499EB412D6B8EF60A1
-:10507000E6FC962ABF2AFAC5DC229E24CA8486E56D
-:105080005653E4ADB632F13DF69886F1A76706793E
-:10509000DE6AF7EA678ECD447D5C29539E59D7E0DE
-:1050A00051EF65B8EE3A9ED753A426A474FFC5EB22
-:1050B00077713BADE6A8C7A81ADEFE99C1A3447775
-:1050C000DB01EF4A9AFF270B38BBD19F807E7B5DC7
-:1050D0003D0333A1DDDE717952CC48B51BEDE7FC11
-:1050E000D7BD4416DFA167F41D874EF39407E5662C
-:1050F000279E7F40FBEE1A2B2FB587EE65ED9D3383
-:10510000790EE6896FBB81074BBBC287C84FEE990A
-:10511000CDEDB2BD12B4837DD9D7A25D4FF7985AB9
-:10512000799C08CA8C71A25E4C0446BC8A733B4AC7
-:105130007D81793B1BFA06709EA23AFE7D8BA29A76
-:10514000CCFD5F08B8A9FF3E578CE29F23EDDFBF7F
-:10515000FA383E3BABF8790163718A4BED167E1746
-:1051600053A346FA77425B021C3F3B5DCCC478995F
-:10517000AF4E23BD2E870DB243FD603F623C6E9B58
-:10518000145B8CF921B1491A7B9C30627AC761FCAF
-:105190006E425E18E96F939408E1779563E3787C3B
-:1051A000FB686427DDBB3A00763485835982F4546A
-:1051B00077348FEE431D8D540F527F5F85EEB634EA
-:1051C0000AE6CDD38722199B74D9A6AD68D7744E51
-:1051D0009175CCDBEC94EAA3385E2CD7437164D78D
-:1051E0009479B47FAE517952BA3EBAD1CFF5C2D0DC
-:1051F00084C88D7E585768CAA95C8C5B6EAF7D658C
-:105200001FEEDF23F77B888E1EA91DBC1BE7D97F0D
-:10521000F6AAE351E24B7E5EF768EDE952B47B7685
-:10522000359DCA45FC15637C0EF46171058FA3A101
-:105230000624FB4CED6137031E8BDB3466A4E96367
-:105240002FE3E779F8E79B4C728FFE9E193CE569E6
-:10525000C1F196B0C4A5017AEEC1789625678AEBB4
-:1052600058A200E4E1FE15EFC4304FEE91890574B9
-:105270008FB248BC27C909E39588F1FADF78653D0C
-:10528000B67BB4BAC04079513C30340F954471D5E7
-:10529000698AB385ACFB1F5163FFAD449F327DA784
-:1052A000B238FCCE5FE03A02BE3ED273D09EE266D8
-:1052B000CE7504269AF7F9018FDF945A5F1D174CBB
-:1052C000F963F487FC782FBF975D9CF50F7395B455
-:1052D0007CDB121117D8240DCE26BBF4016E878F0C
-:1052E00065719273C555B1BB79BE6D94F26D9DF336
-:1052F0006EF79FD3AF12DDA3CE6F12F74AF8EFD847
-:105300009488DFB171D27D28945FD57155AABE2FE4
-:105310007A8AE8FF69CDB82BD3F71EF609B9B049F0
-:10532000F863D6F86373F9F856FD519DD3E3D32F94
-:10533000E75D5F05EBF9ABB6B24918FFDC31821FC0
-:10534000B732C0E92F7B002C1CD003FDAFBDE6C5F2
-:105350007C96A765B60AE5547D55C293AC12788455
-:10536000F1C91783F10F84BFED41B9F4D54025C1D0
-:10537000B5622A8F1B74563D48E740219DEB1DE422
-:105380004F94EFBE504CC2B8F7F21AA61F12F19616
-:1053900018E09FEECECB2C95D7BF3D97FC1CE015B7
-:1053A0007EAF067393268BDF9F28C773A24D778B42
-:1053B000FC5919F1DD29E601BEA5790E148971EEBB
-:1053C000E3F63FFA17D8BF5CCC535EF7DDAFA11E02
-:1053D0002FD2395DA4E0EBF3107CAD3223F8D4C4B6
-:1053E000ABE8876E9F546020DD1C0885DF6E82FA73
-:1053F000F2452AC5E3CB6B381C075A65FA3D207F7E
-:105400009D7690EE8F99A02FD2F06588798B6A12E5
-:10541000129E6B19AD7C5DD0CE8B72D108033C50CF
-:1054200037C4BACEC13F4923F88B3C83985B740ED6
-:105430000F2B713CA0DF9575BC9F3FD4B705E5D815
-:10544000F23A0E37E87782A728AC1D447D5F14E25C
-:10545000E32D07FC1C925270655B70D5C9947F5593
-:1054600054A31D443F385BC0B732CCE1E97FFDD483
-:1054700080C4C73370BC6C016FB6583F25EC16086A
-:10548000FD00E33DE54AD4E3BD9C5353987188CFBA
-:1054900046F12CEBFDAE56C003E0C72FE661BBDD45
-:1054A000C44FB0C4D8C732FFFD10232D6E51B15B7D
-:1054B000B3D5FD62FF58177F4E7E1CA9445E9785C9
-:1054C0005FB7B2CADE8FD5A4D5CBF07E19A7F7F5AA
-:1054D000D7F2F38E0313B87D847EC739FE463A9F18
-:1054E000623CD615C4F71AE9BB9276FBB8C5AD0588
-:1054F000D3513E140F3C3C4F86F514DDCB64258719
-:10550000E8593A27FF60BE6FAF49D0FDD9EC81481A
-:105510001ECABB92D6BCE9F8FDB7EC8128D5B3070B
-:105520005A4D9E7F062E4C1EE6EBA5CD538A729AED
-:10553000E7D3B156AD0FE55A6D3A9CF0BEE4E59E57
-:10554000B9D87FF3DDAF8C46FE2D70F4F7E470FF21
-:10555000A1F8656815C0F94FAFC5F6567C271B2129
-:10556000CEA3F2652C8B7D208FA12C11F97796BCF0
-:10557000E89CF0CEA4A84FD00FE5E3B144BA9DEF6C
-:105580002CA1FD78D13E269DB7DD696A3752BC69F2
-:1055900020C0E34D0161AFF630633FE9F71A9EEF9B
-:1055A000E1C3E7A03FFA6A8E4EA7FDEC6361A4E772
-:1055B000E2B63FB9D3E5F5CD8152710F3A4174AFF0
-:1055C0009564D1F91EF0317DDFF480DA4AE7AC7DD5
-:1055D00045FC5CF3E89C5724C467D1733C4FDBB2B5
-:1055E00097A7D72442F8BCEBD5E865C49F23D89F82
-:1055F00096BDE95CCF25F50F923C181B655E3C5FBC
-:10560000F3AF56298FB5240A7055A15C00922E0481
-:10561000F86B62EB916E8C28AF1BAB45B90ACAAB35
-:10562000C1BE5D3750FE4B576ADCAD1560D7A2FD99
-:1056300034B8DB7303DA2BAD608D18682F9EF2E06F
-:10564000F754BA5BA7E7239E9F8958F66542C2F1DB
-:105650008B7E6A92BD58AB6B3AC66126B813A3D352
-:10566000CFE90ECC79A79ABE2736FFE2F2C946D21F
-:1056700027088B9CA647FAAB8E927E79C23F9EF498
-:1056800090A5572C3D4223827CB945F0519791F06B
-:105690004824AF807701CE5B508E001DFB8BB83C59
-:1056A0000739CCE59CA54FEEE67ADF929F15629C08
-:1056B0005B50DE42BFEEDA27726F40B922E4AC3FA6
-:1056C00064CCC4F3B90A215F991A9370BE0353F8EE
-:1056D000F72A030E795AD1CAC7E90A31A227D04363
-:1056E00007916E0E1425E89EF881D6A352FA3D5319
-:1056F0004BDF055A930CF77F5C1D9783E3845CFDB9
-:105700008EDFE0F4E9E172F59CDE13F276AB79947A
-:1057100089EFC266CCC3FA7BA1CF7B2A0E915FB022
-:10572000EDD653844F2B1E1A12F1D0EEAAB7E8FD26
-:10573000F628BF07B0CB9C3E87E08F2CD728FFB45C
-:10574000E6E89C32F4379A966B68D79D0C1458E7BC
-:105750005FDE85684FB6AE22FBD727F6F1A1301386
-:105760007EA7467ED67D4BBF3D80FD43E0174906B0
-:1057700036EAF3B891CEF17B0A88EFE82075F6D5CA
-:1057800018F41D08E73ABE17E0DFA5F5479303E3D9
-:10579000685F65BAD2E3AB61E4772E07BF0E87DDA1
-:1057A000AD86BD13E0FDEE26595FCF52FDFF578059
-:1057B000E7A34DF4F37B0A3B179FDE8271BE9D4B3E
-:1057C000C577CE1CF0DFD7D8E751681E8C09501E74
-:1057D00073C6EFED57F9B3F8F7176AFA06D09E0FC4
-:1057E0005471B85E0C181CEF831C8F3D1199F8683A
-:1057F000D760B517F59DD36E7C24FBDD493CAFC562
-:10580000AE6F2E542F76C8FD09EEBEEB48DE7D53F9
-:105810002679C518977712930DFC5D8D9600A7A782
-:105820002A21AF3B5C89FD9857D0F1AC8FAD375240
-:10583000745124C6EC6C9533FE7EDAA180C2F77FEA
-:10584000F8BE73FB41ECFB93020F17DA7F0CB3A099
-:105850003DDD17DF34E60E94E3ADDC7FEE4BBC4557
-:10586000794745B31792DF73E4E0A5E40F14559927
-:10587000B6DFD7CC1EC16FADC8F19C371E30923C4D
-:10588000DEB7BA83FCEC7D8399EFC514E4F0BCB4B9
-:105890003E9097F87D9391E6D77338FFFD5340D043
-:1058A000DD9C77E87B19697AF665A16749DF16AB5D
-:1058B0002CA6A4E5394C10F873EA4FA6C63D97D63E
-:1058C000109D13FEF689F38B874C99F06ED1399EAB
-:1058D0001F205E611DA6A0433ADFE861710FF24D03
-:1058E000AC89E77938E19EE0972F6A7DC11CEE878D
-:1058F0009C9B4FF8EB13FD1CEE9DB5F7D33D4798ED
-:105900002F84F421FDE03F4ED37DA8675DF47BB684
-:10591000339E752530A675E741FE7B8BF28B5E8248
-:10592000F39F0FF3EFAB27FCDC1EFBB5CE7FAFE898
-:10593000ABEEC1EE2F407DE85985913D1907C505B5
-:10594000F47A5AD02B7B8ED7577A79F5CE83FDCB5C
-:1059500070BC55CFF13CCC3B9FBFEDC62F40FDB690
-:105960000117DD19B8F3F1F5DA18A8DF1E97FAB0C0
-:10597000FE9BE98C7EEF3396A7519CEB3781C18269
-:105980000580EF0FD679987119C649070BE6031EFB
-:10599000EE883F3D13FBDDF1941446B69DF1ECE338
-:1059A000AF8C06B8EEFC8644F95F5F39926DB30B9D
-:1059B0004FC352A6C1FB3507F9EF46DEC67A662211
-:1059C0003EEE7CBC977EFFD0C2E707EB2A9991F6AA
-:1059D000BB61777EE369FA3DC3BBBE25D1EF2BDE09
-:1059E00025F37B44FFFCBC77D1633E5CDF7AED524C
-:1059F0003FAE6BB386ED6E8BB77C17539AEE881F64
-:105A0000D466C2FB3B0E1CD456A25FE666CDA87FCF
-:105A1000BE72E40A9BDC39BD4F21FF604DAE87EEBC
-:105A2000D7339F199A3761F83E7FB08ED9E0BAC359
-:105A30008A13A8716D6E5A7B97CEFDDFAF1C516C37
-:105A4000F3587640EC18D70BB1BFF553FCDCDABF46
-:105A500035C2EFB6F66F8D15885787266782A71B6C
-:105A6000F703E0E959A753B9735D88CADDEB0CDA97
-:105A7000A7BD884728BB04DC81A9AC1EBFCF1F305F
-:105A800079DA715E93598F77CBF222BC5EB0244AEB
-:105A90007EC848768C55EE75455BD087ECDCD13FEF
-:105AA0004B05BB67AF16BD1B235F7AC7ABB31AA00C
-:105AB000FE3739918D39246FC206F29DE59F7F3DF7
-:105AC00087CBDD4DA335C2F7DEA5931F532CFF0B0B
-:105AD000E37E4B573E81F604F4DF9E437C1BA6EF2A
-:105AE000748DD4BF60599DAD7FC1B25556FF3DD472
-:105AF000DF73FEFE7B975D639F7FD91D56FF4708CE
-:105B00007EDFF9E12F689E6A9FBF7935F5FFAA9B7A
-:105B1000EFEF50AE87F2E93BBCE1848BFC6746DFD8
-:105B2000E750F32E3D44DF4F3A17671A3451CFFA4E
-:105B30009ECAAD463996A2A3E9DFC475F881BBD2EF
-:105B4000E928A72ECBC657B9669EAD9E3F7B8CAD8C
-:105B5000FDA84899ED7DE1A2CB1D74E9D3290F96EC
-:105B6000717D6A629C13E0D4C6F0EF35D58FF1D019
-:105B7000FAEE7FD14BF5FBAFE1EBBB7F8C8FF89852
-:105B80007417ECFBFD5AF4CA74FB18D62561C8EBF8
-:105B9000193D3A90539BFEDC90F17996C27FC72E57
-:105BA000CBCDF5E5E6D2C98FC5D2F0B9A518E8018D
-:105BB000EA6FE768B638CFE6E295A196B479361574
-:105BC0006B8B0E55F1E7B7A01DAF47FE0EE7FBAAA2
-:105BD000367429DAAFCE79DC6575B6793C25AB68C9
-:105BE0009EA4631E77C92AC73C9E4587C47331CFE4
-:105BF00029A49391E6D95C768D7D3D2577D03CBF75
-:105C0000C6796AD3D6537287639E2CBE1E782EE661
-:105C1000F9CD79D7533ED5BE9EB1AB699E7F77CC87
-:105C2000E31EBBDA318F8FE6C1E7380F2BE27E949B
-:105C3000E61E5A49FBFF032FC33890E68EFE355D02
-:105C400052F97B2FC585A19589EDFE0FF9438DD2C1
-:105C500000800000000000001F8B08000000000012
-:105C6000000BE57D09785445B670DDBEF7F69274F9
-:105C7000773AFB420837801034C40E840CE0320DB2
-:105C8000411E3A80C1155CA0C3923DE988380F4798
-:105C90009D34041111B551D4A0C034080EF840034E
-:105CA000132040C006D4C119D438CF7199059B4543
-:105CB0008210930651F1CDE25FE754DDF4BD9D0EF5
-:105CC00030CBFFBF79EF8FDF4C51B7F6B3D539A793
-:105CD0004E55939C0442461172308EA62308F92635
-:105CE000C67DB5C34AC8F7F0F74342FFBC8424F32E
-:105CF0003485903984FFF9170BA490905A33CBCE9A
-:105D0000DE3C256B01A42D45692505F41F2B6CCEC7
-:105D10002B14423A5B8A8CB372C3FDA9E91C9F7CA9
-:105D20003298C3DA7E4FC2E378C7929C3A3A7E59E2
-:105D30009C03E7A3E64FD6D3BC899063F504D376E2
-:105D400099CC28A6DF4FD4D3090CD6CE7701B63B29
-:105D500029D17F26D17495E0F70A745DCB3F90C9B5
-:105D6000001CE6C31CBA8E3BF832E6F862093187A4
-:105D7000E7E1311117B40BED32F9D709F0D5D5C7EA
-:105D8000904693C64442D4F9F627E48FFB26BD2DF6
-:105D9000D831DBC7309290BB966C7D0BAA7D2494E2
-:105DA000F49D4BD73BB579B9DC87E63BE5E074A7BA
-:105DB00055D3CF54F918ACDB4CFF837EA6B9695E8E
-:105DC00033FEDDE5FAFCBD440AE7B309B9CAD19F49
-:105DD000E3838FABF865C0D71D744DE91485F74296
-:105DE0003A0C8A1D88AFE90ED6569D8FE72199049B
-:105DF000603E523099E4424932D673433DA5E7FCF8
-:105E0000A6CB665731C5E7F407458463E47C83FB82
-:105E1000625D863C9A367E2593FE979EFF8CF9FA4A
-:105E200072E265E3A97055E9E0CEA9639E3DA1A1A8
-:105E30008F69EE1B9F3DA183D3145DFEDEBA69BA64
-:105E4000FA33E697E8CA4BBC15BAF2594BEED3E5E4
-:105E5000E7F81ED4D52F6B5CA02BAFF03FAE2BAF75
-:105E6000DAB85C97AF695AA9ABEF6959AB2B37EC3D
-:105E70001B7233A1706CF8AD484C148E5F5B4F3EC3
-:105E8000754D12A49213E07EAA3E0DE9FA74BD820C
-:105E9000692DD0DE28E09FE16637C5932726544A56
-:105EA000E20979C477ED9225D7D2BC91968FA6D41A
-:105EB000EE1BBBC49B49C8128782742F361A4980D7
-:105EC00092AA4012BAE93A246ACA8397286F944882
-:105ED0006078CF723118FD7B97101A9441D7E1FD9D
-:105EE000D44436083DF93CCC97A40F49EBBDBCC364
-:105EF00040CA9B34726783C380F349768CDDE0A08F
-:105F0000F4506D64FC5EBD2D7D2CB1433E30A8CEB7
-:105F10007A91F19AE86452A11FC62F15FE3E61FEE8
-:105F200045FC0DD0F1FDE038F77A071DAF63BF38AF
-:105F300015E6410207B36E1D0AE3BB36C077D242B5
-:105F40003B49A7FC5DEF7AF6C415847C523F01D330
-:105F5000DFD5173F7B4226E40FF553317FA4DE8D5A
-:105F600069B0BE1CD363F575587EA27E3EE64FD65F
-:105F70007B313D55BF04D3D3F53E2CEFA86FC47CD5
-:105F800067BD1F53950FA83C9A510C7C5A5C6C005E
-:105F90003E9D6B21FC8FE5CFF13588F4DF6DC8D7CE
-:105FA000CE34E0EB73D66F0665507A3BF70925A631
-:105FB000ECDEE1144977BDE3CF6500FC95FA29F1E9
-:105FC00024F62CB7C430FC580C6402A1F2E7F12B84
-:105FD0008C44A2E3C7BC71D53A311BBF4B403A7425
-:105FE000E3704EB145E97F20417C5D0A4F6AFD9325
-:105FF0002FFEA970662EE0A73FD249CC41B18EE1B9
-:10600000ED6527E0ED52F093387F45C25178E38F7C
-:1060100059415AFFCB64159E6D5984A6B73A8A4FF1
-:10602000011D9C6B36E1BACEB5C6FA09F4E14842CF
-:10603000BAE81D6E6C1E551B2D3EAD7CA8698AF713
-:10604000E9E545BA4F2B2FCE1D7AD90E7C3F374D4F
-:10605000F49D180EF4E1E2F4C1E84EEDBFA629DB91
-:1060600067D5F5A3CF9FF309139A50CE2B71B70DC7
-:10607000ED7D9E73D38C38CEE98D03E260DCD3F5E1
-:10608000661F8CD351EFF0B171D37C5ABAAC9E1F0E
-:10609000EB3B91189E5F6FFDFEB3E7474833396EC7
-:1060A0002608FAEF07F45EBF577C48E78DC5401F0E
-:1060B000ADF237B0EFC4E4A8FB8E8479B55F4F939F
-:1060C000E8355D0DDF37EBC6A3ED94932A9EFA5FAA
-:1060D0000CEF1239A9AE93CAC9A15476039D52623E
-:1060E000463CBB698F71B4BF2EC9BA44A0E398E2A5
-:1060F000152CF7C040949E6ACC41A35B4170B781D8
-:106100009E3573A4CAF7CA9DBFA724F7C5AF65B271
-:1061100014CAFF4C7BA7E5322F9D4D8AED848E3744
-:10612000B3B96A22C8C92F76FC88EB29BE4258F75A
-:1061300097C43001F8E44BF21BFB708D5E3639DEFC
-:10614000C8E6B784EDCF5EFA1FAC8FEA69BAFDBA34
-:10615000AC519F2F25B7A4003F94AE90899FCEBD30
-:1061600002F67B75DD94EFAF8F677A5C19A95B0C43
-:106170007ACA52994C057CCF7410A90F9513353B00
-:10618000571796D0FCEDF106A4ABD354BF53A81C0F
-:10619000AA48607A4C6592DFE8A2E5C79B87DF7169
-:1061A0000D81F6FEC520D7BC36E2DC407AC27DD632
-:1061B00012FDFC2E35FFC8F912B210E7ABCE43ED4D
-:1061C000579D87B85170F9A3E8B3B3E285B09E4CF0
-:1061D000D3FBE3F5FAEB7CC86BF4DB4722F20B232D
-:1061E000F22A9DC89C4E4CF1EEF9F1C94017A1F17D
-:1061F000A8A7114A1FB9E17AC670BD472E56CF0431
-:10620000F544ACB7F062F52CE1FE1E8B56AF66E7A5
-:10621000961D5E4A4F95AF3F6727549E7F21F952E6
-:106220009CF47BF58647ED00A75392D70EF8FEC28B
-:106230002F4E8806AF7DDDF0725905B02390B4294A
-:10624000DC5F7D6232E849DF6C901D22ADE2D968E7
-:106250000A9828FDD636574C2479983FCAF28F9D6C
-:106260001521DFA2C767E5CF9F4B516C8807A66F4A
-:106270009300EA1DB5EB3F1F0F72DC434248879144
-:10628000ED60FC0B09C8F725C6B89EE5749EA827EB
-:106290007B389F799A9F382BDA21BDB11DF8CC133A
-:1062A0004147E5DDFB4BD0584CE7F37ABC2DE9E4E0
-:1062B0005534FB03F20390072A5C889FE9150D9B78
-:1062C0005EC83B4AE7D5B1FED77621572B47183D2C
-:1062D0009E6B9AF5B3DD4AEFF2A693DB45E1767E3D
-:1062E0006CA7B4303D88B4B2B45A0ED841EFAC5E5E
-:1062F0002B3B29A592EA2D2FBFF222D86B9F9AD073
-:106300005EABDAF2D647A369BE6AAB9C34912DC767
-:106310002AA484F1E3A1FF9B3F2C8C8FCA5FBC654C
-:106320005486B2EF0F2784F152B575BF910CED0979
-:10633000C7A2A6FDC6A0350A7E9A8E8E07BDA561AE
-:10634000D3B746B0BFBED82790D4EC9EEDCBD7BE16
-:1063500085FB22C009F1C9F1D58DBF1E780B4CDE3B
-:106360005D80F51C202F2F85371F97D3353B6D247B
-:106370009ECEA3FC7726FF44C0E76BF7DB613DEDC3
-:10638000521DA3F3D58FA6B8E8F8E5B237C5812929
-:10639000FB5EBEE601A4BF32A12EC581FCE44A37F4
-:1063A000A0ECF6A6C33AE7ACBA1DD7594ADC488739
-:1063B000E5ABC5623F4DBF96C884AD51F8A43081AE
-:1063C000F149FB3A8A5CBACE76D0FB41DFFE8DE81C
-:1063D000DF80F6E97D04E4FF037CCD74A7C4FCD71D
-:1063E00066862F6B8241B517CD3AFA5DFF581BE0E8
-:1063F000E9745F572ACC93C2C1CBE1267C4FFB15D1
-:106400003FB82195E1892852216F47F78322F80E82
-:10641000F5DB6497254FD78ECB4F36FE3C3E3E9D35
-:10642000770CEC6FED2954BF8FB2BE99B03EDC17EC
-:10643000E93EA7A1330DBF33FE5FFF38E37795FF39
-:10644000FD532640F9F90F191F413BD84FE8BC0214
-:10645000A958BEFF3601E5838904A2F1F97A99F3C0
-:10646000B9BEDC43F915FC042A9DD0F94B429C9639
-:106470005EE838098807B4574A57D0F65AFD06C671
-:10648000C57AC6F077CDBE52C6E5427E029507B109
-:1064900061794056255F961E592D132FA89CD59FD4
-:1064A0009AD01EAFDE2217C3FACF6C3EF8D15D94AE
-:1064B000CECF34A97CAB97AB917C5BBE6D8300746F
-:1064C0001AC9B767CAE92E1E8D6FE9F7A87C5B1E53
-:1064D000FC7F2A5755F84D4BD0CB532A1FFB810A1E
-:1064E000D11B1C23E5E3D7A06F25F7948FF4EF436E
-:1064F00052D8930E55FA53E98E6A70FD40AE77D3A9
-:10650000A74A7FDDF4A9D25FE47AF5F08B2CEF0F78
-:106510003612A593E25D54A3A3F8AC6E15FC26E4F5
-:1065200073EFDB7D0A104E2EDCDE88EFED3E49DA9C
-:10653000BC3F22DF1451DF15912F8EA8EF8EC8D7F4
-:10654000E9EA57B71C3412C47F4057CF34FF257295
-:106550003C8A3DA8EE3F9EE6B3462FD04566C8086C
-:10656000724F5E485537F0AFED15D1BFD6A584EC1C
-:1065700009F4FBA31666A77539783E9EE543C9C6A4
-:10658000C520F7D4EF210B41FBBCAB38648FD7D8C3
-:10659000FF475B45BB42CB837E3241EB4708CFA729
-:1065A00001F11D24BD9533BF61578C3D0FC78BC9C9
-:1065B000F203FDDD205AB3E683BDE7139D947CC84A
-:1065C000EC0577DA09A5B3AED601374FA5DFE7BCF6
-:1065D0002382BA4DD1E392D229DDCCE2747C8A7851
-:1065E0009FBF96AE6F562BD3C3672F8B4EF795BCCC
-:1065F0007EA9759E11E42BD5A38F69FDA295641920
-:10660000D25DF9AA88EFAD3F42FEA88CE00F37B704
-:106610001FF6AAFC914FF251BE10C2EC5F2E976F8D
-:1066200010736F9E4AF1D07548242605EC59912CC1
-:1066300086756E16FCE02F20DE64E4B35A124279B0
-:10664000A8C2A903F86870EF72AA63FB1F0B1F02B0
-:106650007AD9F1FBBC9768DAB1E3D3417B20BFF371
-:10666000E3ACDF939EF58BF67D371DF6B3AE7D264A
-:10667000F48B75EDFB65D64390DF6D42BF58D74272
-:10668000930BF8C0BBCFE6BF02CAFB32FBA161EFA0
-:10669000B77941DC5F1721DE4E2530FBE55CEB9FCF
-:1066A0008E084990D25581FEB02F16F9C8B3DB820F
-:1066B000F67AD7DE6F0BDDD67FDE7A6A8DC48DF475
-:1066C000682353B701FDC633FFB167CFA89717D032
-:1066D000F16B9AF71B67D1F2A237FE9207F2B36B08
-:1066E0001BD38B3AE5E01AE224E4AB84B2C765F031
-:1066F000F301336510F274E2C61BBDB9D1E0C2E00C
-:10670000D045E100EBA2702907B9DF1B3C62128D76
-:1067100048EFFF7AF0383B9DC9B51F10F00B85E1BB
-:1067200022B8D8779BDF2CE0FAD9F77DDFE681DC51
-:1067300039D3B400F5954BAD7B48E2BF2A1DFCBDB3
-:10674000EB160297B3EE09FFB2F866F4FF5E8282A1
-:10675000F38CE4839E74BEF3C7987FCDE6C4F95EE4
-:1067600026FF97FF6FC3FB368A77FBA5F1FED8FFA4
-:1067700058BCBFC3F16E7398409EEDFD0BFA59D51E
-:10678000F55F6ADDAFFC0F5DB7AAC7DF64A83B3CCD
-:1067900085D63F4C022B8AE93CDFCCBCE1C329B44F
-:1067A000F497BDE8271F25323BF097A07C80FD972A
-:1067B00026F837A05DC1ECA622C2F6F5A29C32D421
-:1067C000378A729E40BD81487587F3293C6ECA9A0C
-:1067D000E35C8AD5877DE2A6F97F4BBFCE89FEC3F5
-:1067E00008FBB1E8CA1B0F81FD7270019D1F1DE7F8
-:1067F000605FD1413527322E530E98F2303D0AE9C1
-:10680000DBF609586F9C556F3F4D04BB47630FDEA5
-:10681000A8E8CBC7F3FE2790034912ED7F825326E9
-:106820007EA8477C8BB4E7CEE323FAD946754CADFE
-:106830007FED6F859F3989D999BF24730FE703FCDA
-:106840003265F41F5E127E006F8457BE7F29E856C2
-:106850009213E17753460D8727B3AB25DE5EB22E48
-:106860006E03BE9508B58B995E86F6B46A175F0A0B
-:10687000CE84DBDB121F5A85BB9449ED6D7DBF08CA
-:1068800017151F7F2B1E54FCFDBDF8F81DE0634457
-:10689000181F99E71D12F06711B707C69D6F1331D6
-:1068A0009FE994F0FC85DB0363ACF112D803D74970
-:1068B0001F88C09765E65D95708E60760A48D7831D
-:1068C0003B0C68EF980B04847B4EA384F90F0C8E6D
-:1068D00011A0684FBE66E7990709F8935D46A67850
-:1068E00017337FFE9FBFFFFEDA42F0ABB0BF32FA34
-:1068F000BF49D41E9BBD8A0462E8FAE648C40B2156
-:106900000E737C0239A6F307EBF3F0777D4AB89F4C
-:106910004BD5EF4D8EFCB3D39D546E1DBB82905D65
-:10692000903267BFA4B59B7FD0CAE0E5394CFCFD2F
-:10693000512EB8C462CD39DBBF2731F9B1F30FDB7B
-:106940008683FF6C4C576E1C93A70506A04B0FB7B0
-:106950000BCE11250EE215CEB50E88C373C443A22B
-:10696000CD1DC56FB389DBD3FF518F4E65D2B59E68
-:10697000F844B09B4808FDB7DEF5E6A8E7C13393BD
-:106980000C9C6E38DEE89F5808E7166CFC39B46939
-:106990009C166F1D13BF90F27AE201FE8E69CE57EE
-:1069A000FE51F882FD0EF0DD64098E2F8E223FE647
-:1069B00071F84D3EF01DFA3BAF6C5D6B00FABD7295
-:1069C000BD41773E599DC4EDAE616418CC6BF201B8
-:1069D0008BAD00F07248745AE8FA3CAD678DEE2832
-:1069E000E75C91F084FEC18FFE6A123B17D8233713
-:1069F000CD02B8EEF9D24CBC14BFBB8CBEAA68F372
-:106A00004C4A61726E0E69BA3F2FFB5F0FBE63BACC
-:106A1000AC81B16067AE27DCAF11497F04E9F8DCD7
-:106A200046E287FD14EC52900BE73613DCCF294881
-:106A30009E04BB9AF2FB0FB57E9AC12D5BFF03F457
-:106A400080DA56C161A0E5B552D008FE584F4BBC64
-:106A500008FB6EBE425C783E2C3986DEA6E18B5781
-:106A6000932484EFC1D17BEE8671BFEA3012D04708
-:106A70005C6F86ECB06F7FD53A1CF9A0B775FDA2AC
-:106A80009E548E93A11F260F23E92177738C2E7FAE
-:106A90008DE8CE00FE9A6C0ACE7346C1DFC4644610
-:106AA00067972DDFFCFF9FC9B70F55F9E6168B35A9
-:106AB0007C9494CCE85E23DF52A3C9B7B982920AD2
-:106AC000709FBB77402AE075EE3B727234F9B6A531
-:106AD0009E9DFFBD4EF911D2AE662ADFAED6C8B775
-:106AE000662ADFB27BB6FBEBE5CA37FF7F0FFF6D8F
-:106AF00001F91665BDF11C7EAA7CCB6B3D8AF22D97
-:106B0000AFD940148DDFC99C7C29F92624DF06FA11
-:106B1000F021D9191B857EB670FDFB751EB707E302
-:106B2000809CFBB764765E7AB9722E3D85F1C925EB
-:106B3000E5DC7F139C553937773B9573D9D1E890C5
-:106B4000C9B9B9BBA89C13801E999C9BBB9730FF09
-:106B50005B847CCBE921DF08D6AF0DB0F69E96ECC6
-:106B600017EEA1FD0D73C94E33AD3F2C2CEF4668D7
-:106B7000E5DDBF254B08E71EF2EED0E5C9BBED5CB5
-:106B8000DE5139D61FE46B247D385B6374F93DA375
-:106B9000DA37FF02F8E55D11CF173F30B073A0F789
-:106BA00046B517007DADE4F3F170FAEBACF762FF88
-:106BB000456FB2F5D56C66FEEFDA66A61FD6AE1746
-:106BC000FD0AFDE7F8D1DF1961FE157B05924AF356
-:106BD000534CBEE7AD20837F2E13762E4626E66B00
-:106BE000E861F6C82AF4E33758ECEB08E5E3D9127C
-:106BF0003183BFBECA3AFE0BF0D3578D64FEFD2A27
-:106C0000FE9DF0B801350EB2B4E5BEB7FB909EF123
-:106C100003934D0C8F935F16FC6BB3217E495F5E2F
-:106C20001511FFF8145FE71431887021EF8B51E3E1
-:106C3000189E8A84C7210E0FBA7E1D3CFC425478F0
-:106C4000508C4ECC4F09AFBFE2DDE062F0E757ACAD
-:106C500014F0DC578547E43A55F8A8FEE92ADEDE51
-:106C6000D37A1F9EFB47AE5F855F8F75ABF08C5864
-:106C7000BF2F999F7BE593E1104F43E901E587F72B
-:106C800057140E749CE23157A46AE5F1F31C0EC34D
-:106C90007D638AD209C08DD401FD9436DEF7763A41
-:106CA0005DFF884F9461B04D5E33DAE48673D44D56
-:106CB0009610CA3795BEDA557AE7FDECC9A81B8B4A
-:106CC000F67A8BE000FDC213B0201C3D94CE2CB4AC
-:106CD000CAC195DF8CE770749890AFF8BE43E16E3F
-:106CE000A0F5C7ABFB10853BF0CDF0D6B3789E5B2B
-:106CF0004042785E52DB283803741DB52D0C5EAA25
-:106D0000BCA57F562D3EA2D0A3148D1E0938890B39
-:106D1000C3FB6015AF37D9E4FB08CE6126537A5F19
-:106D20004BC278CCA1FF011E23F1A4C2F352F4F9A7
-:106D300039D73FB6001CAD00AF10D3A302745FB0CB
-:106D400085CB3D925707C7A2172F30FADA2B287050
-:106D50009ED00D27A0575A3EA295D12BC04D01B809
-:106D6000B79688902FA5F04DCCEEB94E38BFD4F22F
-:106D70006FC5DEA3ACFFD5829344A15F75DDBDD1A5
-:106D8000EF3F4AB7ED1174FB9E25747838D0ED5E65
-:106D900081F9115AE375E78EA61476EEBEC942E971
-:106DA0001BCEBBDE919DEB949E7C7E81C313F47F52
-:106DB00045E3971A020B80B3C08D668C3FC379F40C
-:106DC00067FAA556BE6EB190E4DB0A7AEFDFC8ED34
-:106DD00081DEF41B353F14C603B9D742C7CB098FF8
-:106DE0001729DF557BFF52EB4A4CF9C7D6D51DBF9B
-:106DF00049DAF0FCC914EF7E2809FD3F2C3EE90E6C
-:106E00001E9F4467807A96A65E5AF288DEEB913424
-:106E100033EEC3F7F3B8F81B442BF1D2757CE5923F
-:106E2000914EE92EFDDB6B412E8FA5FB084DBE3A3E
-:106E30003CE2E37BB05CC4F3A89BDF4DAC8173BA4A
-:106E40009B4118D1EF37E70BB8FF7E009D8D023DC7
-:106E5000D64C5C264EC2B47CE40FE2D16F94BFDE08
-:106E600057A4507E1AB6D1DF00A9B32894F41EC0EF
-:106E70006F8C48007E6DAEC422D8BFEEFF9CE48BC1
-:106E80000AEEB3D8CFB0432419EA8D7625A3393062
-:106E9000AA794511F847A71CB45A81CE73561988B0
-:106EA0005B43BFA389BF01FC36A34EB86E05FE2B22
-:106EB000A7FA02F89DCB5BD736D821BF4A702AB417
-:106EC0007F8FD73DDE4EE7B5A5F1ECF8AB800F69BB
-:106ED0003DE8C6B38AD5F3AC179C102A5BDABA1C1E
-:106EE000E3714AD70BC401F5FD0231B37EFD66DACA
-:106EF000EF9655B43DCD97417BE877FDD90F6F05EF
-:106F00003E3F2CB2F69BD9B975296DA700BDAEBF27
-:106F10000FFBAB58259034DA5FF96626FFCB0FCB19
-:106F20004E286FDEBF12F7B18974BCF46C90F78104
-:106F3000719027C30507FA3B33EF42BEEEE27C4D6A
-:106F40003AA632B921F03CB71B54BDE9400A8B0F79
-:106F50002E752E3026D27EDE1B999C0D61029E96E8
-:106F6000B3781E7D82C2D94DE1FC018FE73838F23B
-:106F7000B831A8D97F3E4B19807438BB650CC6392F
-:106F8000CC21C518E7307914D3D7DEBFCEE217E89D
-:106F9000BCDE974399F0FDE07526D47F3BB7C878F7
-:106FA0005EDCD93788FEE9F6553281788D86552228
-:106FB000CAC5F6CD6C1F1757DF3E3E1DE0B74170C6
-:106FC00082DC3CB8AAC808FB5ABB5FC0F645AB1FC1
-:106FD0004861760C9387AADD56EAA8D0ED1F91F29E
-:106FE0004D957F351C0E9172AE46DD6722E45C0D37
-:106FF0009C37DB21D57FF7102B937FA0F703DE03AF
-:10700000DF21FDD61E9609E8FDC2F18EF118B70505
-:10701000FB262D1FD52AB8E09CBFFC13931FF55506
-:107020007FC98C9F80FCFED4440405E2E029DCA9E2
-:107030005C18690AFDE159FAFD8B0FCC102143E978
-:10704000A404E1ACC68B166C60F12D051FAC482979
-:1070500005388C4B44395BD62812B7465E7C21B884
-:107060006EBD8BC963C7068D3C2A30FA4A61FF7238
-:10707000A43239A86C902166846CE7F289EAD32E99
-:10708000D01B2A762D4F31D27A8B793C48C5DEE56C
-:107090002954349006D8B768FD0A23EBBF629FE0FD
-:1070A00058ABE95F6DAFF6A7F663DCA5EF67C05E8E
-:1070B0009EBFCC7ED479A8E3F7A68F8FFCCF0B2B95
-:1070C00004DADFC8F7450C521E797CE200ED7987BF
-:1070D0009AAAFED7C20F0DC4A581DBC83FC4109782
-:1070E000862E9A4750FEA6789BD4C2F4A1E611479B
-:1070F0008D35059877003FD7723F6DED38766ED5A8
-:107100009CFFC122E0EF890502D201F1BA8D8949C5
-:10711000A8072970BE5056C0DA97D1F6C077CD2B9C
-:10712000191F5279A080BCA85DB57C3CD65F2F2882
-:10713000D07FF3DA12DCE7CB478A04CBD71F45BDFB
-:10714000A3BCE56812F02BE5CF15B0EFD65E6B72ED
-:10715000007FA87CA7F2F1FB328B0F2166C750B8E5
-:10716000075096A244E55FF1306176EA6619F9CEE0
-:107170003392F1E5FB5B44E4E783D7DD391EF8B0D9
-:107180007383D00B1F533E2D08F3A9B89AC5EB9417
-:107190006D62F6CAC1554C3EB437333DB168B53C5B
-:1071A00009F265EFCA84F9BD983E78B9FCDC434F1B
-:1071B000D9189D9F7BE3DFC972D347F7D3F9DDFC74
-:1071C0001A9DBF128657D1F50FDAD14F7FFD345C7F
-:1071D000AF2A874A2516CF34DBB780C5FB4A2CEE91
-:1071E000ED6F9E57C43C1E4BB185E58808F41ECF59
-:1071F000E2A4D7CB48EF91FCF88FF2D13F8BAFB729
-:10720000733A52E723EE65ED21AE2C40E1F8CBCD89
-:107210002F635CEB97AF1E9D0C78AEDA43E997AE17
-:10722000B773B38D04406E497EDC6F2A9B458C1F7B
-:107230002752A0F0569B963F597C52D5EB36A49B23
-:10724000CA6D2CEEB472C7F13C8C175918C2B82B1A
-:10725000EFAB5CDFF406F380BE2B25162715C9EFD4
-:10726000635299FED9B12B762AAC43D8B81FCF5BB5
-:107270002B9BEE9481FEBAE547AAACD6C3734C2F84
-:10728000A55F386787F94D19AA9DDF02C453C72649
-:10729000C6FF952DB2DF02F3DBB816FDD99E8D67D0
-:1072A000313EBEE8F52DE847F0B488FAB8C88D2223
-:1072B0009E63D114CFAB22E3136B9B6BF0DCADB6B6
-:1072C00089C7FF45C4C555BDBE77879782A6EA1713
-:1072D0003FB7833C38DDB6C10EF0A4FD615CE1F53B
-:1072E000E7255D7C54EFF1C02E7DBC61D3E33CDE2D
-:1072F00070523BC9EB196F781AFE01FB4D6A44BC12
-:10730000E6C6441EDF1D282C8EE2CFEFBEF7B3E5A4
-:10731000EB351027DFB1EDCC1A987FF55FBF5A032C
-:10732000F14D649F05F729CFABBFC5B862B5DD82CB
-:1073300054466F9D9B7E8E71D99D9F9AD0DEE9DC6D
-:10734000DB9E05F16D9D5BBF4B01FFDCBCBD37A033
-:10735000FF72DEF6A2541245DEAB29D0A7FF32E25F
-:10736000C223F171B0F920C6617DF98909E55B7727
-:10737000FC68530D8BCB5578DCE8E6E871F86A9C25
-:10738000636DF3AD375F07F2BA99E977DD718F97D7
-:107390008A17FD90E2F5EACBC0DF661E17DC3429C0
-:1073A0006ABCE897F00F8AA79FA5EAE345BF6E9EE7
-:1073B000F3B317A1AC39B1D778D1C065C04D8DF307
-:1073C000AF4E75BD9A0A7CB42DD69BC6F0E69F28B9
-:1073D000801EF87516DC8F382587300E24B4D7E46C
-:1073E00080B8C7CABD1F23BF746EFF00FDAD84C740
-:1073F000D97792EE3F160F2DF075AEB7B138530E18
-:107400007F884355ECF89DC79B323A56E3507B8BFF
-:107410003F0DA6F2FBC3FCDE410DB59B589C7A38AC
-:107420002E551809F83AAA8BEB55D71DD99F83CB57
-:10743000D1705C75F4385F358EB027BED8BEA2C659
-:107440004D77AEE5F1D6F47BE630889363FBB9C7A0
-:107450002F7C1C0DBF6A5CF5EF23F0ABAEAF37BEDF
-:1074600050F9F352F3FE7BE1F26E2AF367ABF0E9D9
-:10747000F8737439FD0DE7776AB77E9DAAB16F671F
-:1074800070BB55859B3ADFC54D4CAFE8D8C8EC873B
-:1074900048FEA6EB71458BB397D298FE5BDBB23FFB
-:1074A0000FE450C7815D9CEE185DD76E3ECAE27452
-:1074B000A9DCF66BE536617EE4C8FEECBC3F4F6BA1
-:1074C000F4FE3C9BCF46EDEFB4E4BA13E67FBA8DF1
-:1074D000E951A79BC409FE28FD5FE0FB52F7BA6D96
-:1074E000468C9712ED31A84FCDB38DFC242E095256
-:1074F00023C6FD342CE071428F38D300CE0DB69BED
-:1075000008CCE751808FC6FF203BDC04F43839AD4E
-:10751000B84054C2F355CB8D4906E2D7E25F0A6406
-:10752000827C3F92DF2E437F9F45F84D3E93C8E219
-:10753000543AAFCFBC827381D2BBDEADE6DD0F8B98
-:107540003A3F47AD297404F477F28605FDD6E23E52
-:107550008B17FD666B2CB8CE83DBBF7D05E0D5F9BC
-:10756000331361E7089430A85C28E3FE8BF6EDDF67
-:10757000AEF913E899D0988E5FB686D607FD7A7378
-:107580002CDA035DDBE2F2509F7CE3A1C92037CA0D
-:10759000600F033DEFF5547F03EDEF6432CB9FDCCA
-:1075A000D217EF13546DB361BCE1C1ED3B6B41FEEB
-:1075B00077BE1E0BC7D1E44B39F857C87BF6C49190
-:1075C000B50AEA818A76BFAD2092A2D5F3AA20AF90
-:1075D0008B7F2168A7A33F8ED273554B1CDE1FD132
-:1075E000D4E3FCECCD60F7650219C077549FD48DCD
-:1075F000A396DF96D69FDFEF0DFD98BDAFC0EA7B67
-:107600008CA15296F76530BE6DC3FA252ABDF2F201
-:107610009EFDB2FA33D2FAEBEAA9ED6B4DA42E1A15
-:107620001F54A709FC7EEF5F06477BCF22CAFCF1FF
-:10763000FB0302F11A400FD86AC138AE6A636010CA
-:10764000C4B7EF30B2F3916A7B6010C4B7EFE1F2D8
-:10765000AF3A86E6E9F70C3E0FA80F79620EBE0638
-:10766000F8AED969214BC17E7FC3E6023CD7ECF866
-:10767000F6E44B0510CF168B7EAB9A37FE1DF15FFB
-:10768000630A4C07FA0F6D359175B47EC7D677B291
-:10769000408FE8900359091739F7A96932E9CEB14B
-:1076A000D5759CAEF70F84FBEBEABDC5CA5EE4C599
-:1076B000DE34A68F2E4F733D9D867C6D75A0BC86F3
-:1076C000FE44E8A76580F65E73A5125D8EAD4A9311
-:1076D00075F768C5F03DC555D0EF9724B83883A23B
-:1076E000A44608E1F979E5C6B343C11EFEECA757ED
-:1076F000E1B9D667C6D05090DB9F6585866AE5F113
-:10770000A97AB322C9E897C0B46BEDD9D20C02F1C3
-:107710008396A9D1E4D396B4589C47E5C3B151EF01
-:1077200083EEE6F4B61A6830998D0B7E0875DCCFCF
-:107730008C7E23CC23375DC1F2CA4CBF11BE576D7E
-:10774000DC3540F7EE84E4C37A94BF101E156485DF
-:10775000B1C0DA53AE54CCB72A12DE8F96FEAB9B83
-:10776000DEC4309ED0C909716A1C877467423FA885
-:107770007A1F40928BCD002F2329764822A0DA87EA
-:107780007C1A439A30B5527584ED437504E28A4EF3
-:10779000F1F35B93A43C0DF2C3744844797E29B89D
-:1077A000FD32CD8EF3364975C4897AC74407E8D5D2
-:1077B00082D74DBEA7F4D050BF71C00976FEEF82CC
-:1077C00038383B61F3B33BDEFE0EF4034A6768676B
-:1077D0007BAF27FE063A9E6464793296F8A39DC774
-:1077E00077703C10EF7E943F5612FE0BD17C2C4AF2
-:1077F000283A6EDC5F47829D6B759000E84DB1566C
-:107800001288A5A935573AADE55F3B61F9FE949C16
-:1078100041AE39AED59747D235714AE7BBE5A2886C
-:10782000EDCF47B43F7FB1F62A3C3CE601D9ECFEF0
-:107830003B834B0C5F8377ACF34210E09167773664
-:10784000001E8DA1230F013CF2ACCC4E4C6A245A91
-:107850003B6E403A93578B04B65FD2BF62ABA63FF4
-:10786000E230A3FFF4710EF7EEFAAA5FA5477D8B15
-:107870000470ED51DFD25BFD98E8F56DBDCD273684
-:10788000FA7CE27BE9DF1BBD7EED1B1FBF1750E0DA
-:1078900023931B1231A8F7A007A483BD157724A555
-:1078A0008451053B2788C05B0CD01FA58798819A1F
-:1078B000EFF07FB91AFCF58F827F1240BA2BE1F30B
-:1078C000A1796B3A9DDF5D7CBAE3D6B373CC7BE6DE
-:1078D000313FD25D0FB3FB42477FCAEEEDDFD3C825
-:1078E000ECED7BE6B3733352CEEE0139E87F30DE48
-:1078F000BDD009C5F7BD3EC11FC886777022F4D739
-:10790000EEF7761E90A07E49843F46A527F5DED28D
-:107910002CAE5F6773FA9C434236E0FBC87BF4CD24
-:10792000692C2E8D9A632E58DFDD7C7DEA3EE05D6A
-:107930004E72E05D00D110E384F31191DF5B257698
-:1079400023BBB77A5B824EFE9CCB51E260BF236FB4
-:10795000F2EFFC3DA2B9372AA9DA7B5ED285587CCA
-:107960007FA44176A6815C942FFC8828942F8C17E5
-:10797000061045730F8DEA77C8ECB283A01F4772DB
-:10798000149332D00BE3399D25DDD4AD87BD4FE193
-:107990003277B982F760EF4C67FBCBD28CE239408B
-:1079A00017A27DA4D36DED8957EF76B6BE06585F5A
-:1079B00076CF7937189D4ED4436FA21A04FA7B9C78
-:1079C00066988F68523E56803F7F2D13B0FF7BC272
-:1079D00081E1F35C52821FE25F66DB971E01BA5DB4
-:1079E00056EFC073B425F539982EAD4F433D7471F1
-:1079F000BD1353152E66A7CF2552389B07B2FECC78
-:107A00000E37D333E83E04F11792A32E0079736644
-:107A10001D01FDD7D20D1F1FC2C7D89D7763DE049D
-:107A2000799ACA8D1311BEB43D29033F6A867B192A
-:107A3000C0C7A25C49140D5D98D286E9F23DE0A66C
-:107A4000D2C71606BF2705461F91F07B526E53E042
-:107A5000FCF9C91BBBDFB541F851759FC1EF57EC6D
-:107A60007CAE57F83912509F9D5DB8783AC4553FA7
-:107A7000C1CF211FAB1F89F07A1CE2BA06837DE0DB
-:107A8000C25404F8513A32E57A8948DB9B143667D0
-:107A900093B5D8652860B40BF013AD0C9EA6B43A2C
-:107AA0003C8F335B19BC44AB17E1225B19BC442B00
-:107AB000A33723CF4B00BFE1D81EBF53F835A78FA4
-:107AC000003C8CD6C1CB9834F6F2E0B792C28FCE90
-:107AD0002389F357241C92E09E426E98AF7AD3EB31
-:107AE0009EA3EB877DFC050A1F48937BB11F933350
-:107AF000981C4D32D4ED97011E0984EF2F5E9259E8
-:107B00004858A822FCA57989027981CD83ACD7E3B6
-:107B100055744811EFBE292F001DAC784736C03987
-:107B2000A938FF47BAFBA4E25457BC82F0740BB0EB
-:107B30003F3F51AF20FE96031E07C3FEC8ECB1477E
-:107B4000393E1F033E41FC32FE7892F3CBD39C4F6B
-:107B50001A9CECFEC4B2092C2E2B29DFC0DF430B8C
-:107B6000106DDC53BCB38918E9BC50C756300DA06A
-:107B70009EF189C97F056D179B4B5C4027F19F3CA7
-:107B8000E8C7B592E274D08BE2B9FE4BAE55E2A7DE
-:107B9000E145DA80C4EC102A0AD1AE6933447B0790
-:107BA000ABC179C00C7ED3DEE6B37FCA0EA4CBD2C4
-:107BB000AB313C9824BA8BA7CDA1796B632CFA0723
-:107BC000639DEEC24781CF1B6D48A7563AFF320D29
-:107BD000DE637BC1EB8B19371A32281D8AA0B451A2
-:107BE000FC3ED338C002707E4E2E4E07F9FA1CDFE1
-:107BF00067290E14ED3954079793F6822B75F6EC2E
-:107C00000AD985ED1CD7EAE5C00A2E7713C6E9E943
-:107C10005D95BB1F75CB5D7732CC27E5C238E4C7D5
-:107C2000A45BA2CBDF06D9E88577051A86327EF7FA
-:107C30009618D97D989EF200FDDAE7DC83D6813C68
-:107C400055E96B2161F2C74B629CB81FF177745400
-:107C5000FD7809BC37C8E52CA4E24023D24DCA3DCB
-:107C6000068CCF5BC6DFCB7A8AD217A43E4A5F90E0
-:107C70005E97C1CE33169A87E1BB6D0D5603CA0BD2
-:107C8000E95393DF0AFAEAFE510EF02348B2B3CD6E
-:107C900005FE409BD4B48E40BD0233BC2721C417DF
-:107CA00038800EBEB1CDEE77B1383C8A4E01E8C8BF
-:107CB00091544C8EE5E2E901DE7B911DB710F02B6B
-:107CC000BE90546701B8E56630BBABB1A410E14883
-:107CD000E13B362339DC4FEAD49BBADFDB826E5FAF
-:107CE000E8E5FECCE40CAE47677AC9400DBF370A21
-:107CF0005C0F53BC2447C3F70BAF184FE05CA927B8
-:107D0000BFF722CF363079B648882ECF54FD539531
-:107D10006772849C50D3C5FD26E8EE7719939C408A
-:107D2000BB907A0D144592F7EA27EF8E4738CC02C4
-:107D30003890B49BBAEDDA1FF607BDB2302ABD45C4
-:107D4000CAB1D9DDFBBA2B05F0744A5652A7013DE2
-:107D5000BDD3DBBEEE2A453AF4F551605FDAFFCCC5
-:107D60008FD0AF73E2199B0272A8ECC2E3B83F94C4
-:107D70005E18856979E38DB89F0BCF4E2A047A6827
-:107D80005F7543DEA7E0E7F1D970DF6E6F2C1A84D0
-:107D9000E791BE5805E23BDA1B697941B81CE2C5A0
-:107DA000454DBC0001EFBBE6FE372950502F55DF93
-:107DB0003DA3769D7D34F885568B782FACF4599B86
-:107DC0000BF4CFDEE8AF7455747F00DE614AC70163
-:107DD00073408FDE6F1F1D0AD07E67AF63E7080D0B
-:107DE00046D7C900E84DCF58F01CB22121FABB207C
-:107DF00073326E580672604E86EB39C49395BD534C
-:107E0000DA3B3FB0F14FC221339C63BDC8DF4791DD
-:107E1000DCF629BA7336768E7592FB5988B997F2DB
-:107E2000185EAEF4526E67F122C411BD5CB53362C8
-:107E3000C3764613ACA3A6F1CCE24F115EDCCEE0D4
-:107E4000F33E25B3799F7AC5E45F1885FE4FF1F8BC
-:107E5000940A81C157E58353DDFA911BDFC389A4DE
-:107E60005361DD901746D17EBF3A24E3BE514DE900
-:107E70000BE96ADD288C8F179E19F534C40D9F3FDE
-:107E80002C6279E5050B96773CE27C01E29E42EF9D
-:107E9000CA04E4D3F94337C4313F91DE8F7D6F1FAD
-:107EA00026178E71F9507AE109A4DF6E3AF1CD31CF
-:107EB00002FF955E788AD1F74601DFAD24DEEA77CE
-:107EC000C70CE4F4391ADA574C5A08F0BED687E7E3
-:107ED00024651B4C4ED00722F17C2C43D1F93DCABE
-:107EE00082CBB05F42F5AF24CD79FA291E675C766C
-:107EF00081BD57481C5E9206FCC0E553988EF5EF95
-:107F0000D07658A2FBE9CF71FDA7F4C2353A3B23E6
-:107F1000BCBEEBF17B29DFFFCB82A3301F5ECF0B12
-:107F2000A3A2AD27BC8E6BB17E477CF4F1D3399C04
-:107F30004FD6971317956FE54656AFD4F78011E4E7
-:107F40004EE9AAF80441B3AEB2C62A5D9C47D9AA4D
-:107F500012E34C4DBF613C2C7E778C14C643FA4B28
-:107F60000B262DB4825E502CF7017E5A5751F81320
-:107F700005FA63F2E90BD99705F2BABDF17E7BB43D
-:107F80007B13E97D22F0D3C8F143F5EA020D7E545C
-:107F9000BC44B63FB9B6ACF027E08F5EC95E21E9BC
-:107FA0005DFE44E02D3B3ADC8675C32D07E38D2E44
-:107FB0000DB7AB7471453DE0C6F1ABC245FD4EF562
-:107FC000A8ABFA8C80F108BBBFD3C8F07F297885B5
-:107FD000C7E5F81F137D1D53BBD7319F7829A3CE6A
-:107FE000BEE43A1E225EF345D6A1E29FBCA2C3FFC7
-:107FF000D497D6221FAAF89E7D6025D2EF6CCA8F37
-:1080000070DEDFEE7BC01E2DBE686A6F781FE8252C
-:10801000B985FFF7F0FE85ECCD82B832EF720BDA4E
-:1080200023A7D63D91A585F39C8C31F7025EC8FA53
-:10803000E4CBDA3FBC639D87C0BEF43E23A33F6D13
-:108040006B86BB0CDA97733B7C51FCF841D1F4830F
-:1080500047EB0F0D013F5D437D1BA632D72F09E88B
-:1080600097D9A82FB9A2BDEFB5A40F932B8FD6B780
-:1080700031BFA7D94B1CDAFBC484E94FFF4598BF39
-:10808000466D6794DD0EF09F1A05528C7A9FE45E70
-:10809000925D007E8FA47CAF067E8BFBB0FB48CB4D
-:1080A000D20E38E03EB189F60FFE1C73A6744E7FE7
-:1080B000CEC9F2F9C2A722C437CB494D04FDA1B9FC
-:1080C000F4BB06DEC6A4369D7F3A120E92D98EE727
-:1080D0004D1261FA9CBA7EFA05F7A5C7F8BEB482C4
-:1080E000FB359FAF6F42BFFFC2583BEE7F8BFB1942
-:1080F000983D6596F0BD1A533CAB6F8C63F3B68028
-:10810000DF5B847D3580791BBCE823E2D36802E421
-:10811000E38922403E910416E33B2963823F86EFC8
-:10812000CE34B71FF0F84D7ADB1101FCD8C5EEC193
-:10813000B0FF368ADE7C85D6FF9918CA877A59B493
-:10814000E8930496F6837868B7E65C8BBD13AA685B
-:10815000FD8291F97EF3A588F39E3F0FD6962F4FAF
-:1081600073BD0EF368B0B07786928E0B789ED360A5
-:1081700061EF0D35D8EE88837DFC577D98DE8E74D7
-:1081800000747488E933E724252E81F94995377501
-:108190007E7EB3F2A6661C89DB7BEB295D4A9A736F
-:1081A000958192CB007473858F7ED7CE338A3F2E14
-:1081B000C18ACFF2463DCF51E70771FB0047F1C2BC
-:1081C00078B4D722E9614FB79FD92B023EA7A9EF18
-:1081D000174B8B583E9EA87F687F7DDAAD8F2E624D
-:1081E000797ECEE999C9CE311B4AE2303E4E9DC719
-:1081F000B4D6C7DA404F9DD69A3E0BCEB7A65907E4
-:108200007D0EE91E39742016F4C00704BC5772D7DE
-:108210006FDF946369BAFDC375789FF9732E4FA71A
-:108220009310BE0BEF260E7ECEEEC7EF338993E799
-:108230009B64B0EBEF09F86F9F4473F7BEE99F04AE
-:108240006ADBF443A1B7400CB89B1CE3F10C416D11
-:10825000D7E27C9BE559BBEEF54B665C4F78BD667B
-:108260005CBFBA3E3A53847F377CF87B4D2A3CC4CE
-:108270009974DD945EA6C5DD7113B9885E3ECD9A12
-:10828000F3393B3461F38984CF7928A2FA63471F1D
-:1082900017C9A4F8FB7D1F970069B5399425F547E8
-:1082A0003E91215F2BBAFB41E8F3977DDD8393017B
-:1082B0000E6D8997253F8F5818FF1F017A8638AFBA
-:1082C0000B49B82EF51DFA830FB6DB40EF5CBCFD01
-:1082D000637C67B9460C3E7927FA4345B49BCE359B
-:1082E0000FBEE8FDB323E0A7A2FB5FDF4CF59E25A0
-:1082F0005BE70C89F1C98CE6588CC79F315FD4BD10
-:10830000233D633E8BE723525BDE6D3A7D7D51AFAB
-:10831000FD80BF20B29F59F38BC8F1E1704EEB187E
-:1083200083FE83358CBE668D738910EF3C7A89801D
-:10833000E7ADA34E282D419A9FE58F77027BCE7A39
-:10834000F03F07C03B07B56DCC1F982ADE97FF08AA
-:10835000F8590EB07D1CF2F7019D585D8A55735E89
-:10836000D021D7E5C37B7FDE7BAD2EE0FF92DB5CC7
-:108370009FE27BBEDC5FA1EEAB3B1B4B304EB6E415
-:108380001E6524E0BFA4C9E2C2D44CA4182AC74A7F
-:1083900024628634D548240BA431C40C69E142F62A
-:1083A0006E7769E314D40FEC238B8DF01E6F49EBCD
-:1083B000CFBF86F6655260BF9017864F49EB3BDF13
-:1083C000015EE7B88A319EF1AA8D469D1D38B449F9
-:1083D0009FBFBA459FCF0FE8F3C30FE9F31B3209E4
-:1083E000D2D14CF3ADB900AF037B4D742F82F83F6F
-:1083F00013C6BB1C13187EBC9B2C280F8BAA5A0BD0
-:10840000C10E3EF39ACD0076F49EBFFC02CFC3436B
-:108410005B6209C459EDFF5D0C898178C5D72DEBEE
-:10842000A0BC8AE20EFC9755AF5BD6821DBEE34A24
-:10843000D58EF7E7C17A76FC95C5D7843699FC705E
-:108440003E7E66D7CF5F83F3B4339BFAA07E754C34
-:10845000F01A6260FC2F98FF33C8DF8B0BF2F7E253
-:10846000AA36EAEDE2B9994CCE04175E13174D6FA8
-:1084700052D39CB4C4DC71746E5D8F9B66801F68A0
-:1084800070A31E2E6ABD217EFDF78778FFA3893178
-:108490004CA7D91027E06FB0C3FEFB72F477921798
-:1084A00072FE79F5D5EE76227F278E289A7B53616E
-:1084B000F94DE6F581F80D807FFFF0F72AA2998F3C
-:1084C000463F99C0FBFFCACCE29993F8FBFDA7EBAE
-:1084D0000FE1BEDFADF7D5BB5CE334F9D2C6FD29B1
-:1084E00025603FADDA9F325303AFEA4D0753EEC626
-:1084F000B827093CB8A47ADA2B4F81BFA27A93D867
-:1085000004F38472805B47D35B76A847F5E161E0B2
-:108510000709EBA337B8C669F8F86FA55B95DFAA22
-:10852000B9FEB27364DB788853AF6A149C50ADAA6D
-:10853000E9F65B2701BC57B17BAE85122916297F6E
-:10854000556FBDFD4743216E66F50827CC877671D0
-:108550001B7CAFDA7C16EF332C8DF8DD0335DD9D07
-:10856000C9F4425A3F60A0F597DE612D07F945FB3B
-:108570007D13F20772D6E1FB2AF653ECFC817EFFF5
-:10858000C440F5965363BDEFDD4D9B9E214D1F4DBD
-:1085900002BF52A39E1E297D0BA097853608CE757B
-:1085A000F87561E12DA072BB1660BC2F2D9F11EDF7
-:1085B000BE75855FDF4F24DE3FE2F3A57F395AFAAF
-:1085C00089AC9738D18BF1E4D5F3A93CD4F809AA4A
-:1085D0004FF8F07DC9C8718896AE993E41149087D6
-:1085E0005B2CEAFB4782B990C7E90E60797C571192
-:1085F000E894124AD595649C02F0BE854C80743490
-:10860000C815784F7F64531ED4DF2D045F7909FBB2
-:10861000B3A11CEF7004F09DC90C7ECFB44361F987
-:108620002EEEE754CB2B5B2D186773E64B23CAD98C
-:10863000054D07318EBEE3358BC140E5C199AD894B
-:1086400063211EB3A389BD537CBA2971ACF122FB0F
-:1086500076A4DC50F7D3A3F04FBAEFFE29D3F54D43
-:1086600026EC538B58BC6A6A625D7EB4DFBF50DB78
-:108670002519EBF2C18E09DD6B75AE433879B32550
-:10868000F483A739214EA84460FD1AFB158B7D6940
-:108690007D1BAD0BFEE8844322FE5EC371D1F963FE
-:1086A000C7007C4F1EF5A0D9056E7C9F922C62718D
-:1086B00095B324129028BDCD82FD280FF32897672B
-:1086C000AD1230AE6CF632FD7AE09D5CED3E5A4163
-:1086D000FCEC7D0BAD1FB13FC4BBD0FD06DEB53455
-:1086E000B3F88BCAF5FA76552480F3A9DEFCBD29D0
-:1086F0001ABCBE26EABA5C99B02EE11633CEEBFE68
-:10870000E7E2D8798F91B8603F0D3D6743F95E4548
-:10871000DCD8DF5D7C5FF73C58E29A0D7278FE2C66
-:10872000D7EC44B86FCBF63F34F990BF05DC77AA9D
-:10873000C691405FF6EE06817DB5AA55080C85BC52
-:108740009978EDC3D877787F00D6ADBD5F534E7C66
-:10875000385EF92AFD77F221C36B35BFC748D66B67
-:10876000CAFB837EC6E051BDD9A4F3EB8CDE2C7826
-:108770006D78DFD5DF9042E7577B8ACA0A0271AA7B
-:10878000DF9B74FD433CCF08DCF78985E2EDB96ED1
-:10879000B9EE1F122DCEFF0887E373B797A603BF6C
-:1087A0003E0D7A6B0607F448945BDC7F4002663A24
-:1087B0004ECCF0EE3C96172E64F9C9AB5F99DC788D
-:1087C0002DB5F364379E0BCD128BDF86FB602FF740
-:1087D00073DFD2978E33CBE0CA92906F5D83D01F48
-:1087E0003A9FC1E185617543EAA2E8812A9E9F17FD
-:1087F0009A02702EEBDDC5F42F5B4148D6EEAFD563
-:108800007D993C8A3B10C47B13A1ED02DEB35C2949
-:108810001CC5FB882B6F5408D8F769144F208F575D
-:108820000A649140E152D03CE5BEB700CF05314E1D
-:10883000F8B98B9AE631628D15D7CFF4B4D8BAB5B2
-:10884000709E933A236718D0395DF78C5BE8F7FB8D
-:10885000FA2A385EBA95E13D6DA1371B7E072AEEF4
-:1088600040F17D6F011F0E8DC17BB2A91456B60475
-:108870004C9780FE9546160850EF393BEB3FD920C8
-:10888000CE9802F9612C9FF0B0E05A87C4B71CFB68
-:108890004F359109304FF80E7AA419FC0A58EE674B
-:1088A000F82DAACB87FE5207B034C918C8847E0EB3
-:1088B00077E3DB8D76C53CBE8FCDDB3A2615ECBC6D
-:1088C000C31DD4E0A672EB709AAA0F05ACF8FB505A
-:1088D0000373587D6E17CECB67F70D92B2F4F5BADD
-:1088E0006457DC7090A31F303DFEBCD585FEE96B5C
-:1088F0008CD1FD592FF5657A8BE78240FC9A7DC0BB
-:1089000033F51BD42B3D1724DDF78E7AB32ECEB969
-:10891000BAFC00DEBBAF216D18875DD314AB8BDBD7
-:10892000BD2626FAB82A7D7B2E88C41B755CA3FE63
-:10893000FB8544E24D8C562F45FF9DAE43976FF962
-:10894000B67B1DF09D8C0CDAC11E9CC8F5DA2EBFDB
-:10895000C12B5F1DC64BA723A8DB773A1596EFE224
-:10896000E7716AB9DA7FE75423BF57C4DE5506F8CA
-:10897000780713F262EB59F44757B7EE1FCF7EDF4B
-:108980008BD185164E5E8DFC4869680B18286FFFE9
-:10899000A6EFA9A7728750123BA0F2F1E9A75C9459
-:1089A0006F5344838EAF630BBAF91CC5CB7306912A
-:1089B000CB85334F8DBB569B67F5C3ED3B268FA30D
-:1089C000BA7D412E6BFF87BE5FBEB77060582ED157
-:1089D000756415DB34797344DE4AF34335794744D3
-:1089E000795244795A443E93D5EFB005B2442721D9
-:1089F000ED7DCF4E9646C13976603ABC28B0ACE1E9
-:108A0000ABC9E368BEA6A00DE3676A5B05271EEB52
-:108A1000ABF1F14EA667599D41FC3DBBD882B6B77C
-:108A2000410E54B7080E81D2BBB5692BC6D554434D
-:108A30003B45D3AE89D99DD54D47B15DAFFDE71814
-:108A4000909F97E61CC37AEAF9D19DA4FBF73A2ED2
-:108A500080BCAC696A67FB70C4F95167BAEB20CA85
-:108A6000C388FBAF1EE8D71AA67BB5FEEF87B6FE1C
-:108A700016BA899D77768144EBFFB1A67D04E84B59
-:108A8000F0C625C8FDE705FF10D89F5F24EE21B092
-:108A90001FDD5B73C57E03AD77440EAE86A71A0655
-:108AA00065596E96A89C3E620BF615A82CC9599381
-:108AB0007833C0F34872105F68F8E99A2456DE37BD
-:108AC000D817CE5D73B37EC8F257045743FEB63550
-:108AD00057B2FCD0605F91B6EFEFBDEA6680FF064B
-:108AE0004774BEED9BC5E4B93ABFB27C575A16E84D
-:108AF0009BD56CBF80EB97662A17A7579EDEB28185
-:108B0000C261FA4F62515E6DE8B8F5A6625CBFB70C
-:108B100018E2DCD813EF7C3F43B92CA11E900E7BEA
-:108B20005842181FB6AC3605E5FD95755B61DF4F01
-:108B30009D9E8BF2FE7CA6AB3E6B4438FD76004BCF
-:108B4000EBB3D87D8F54D180F106A90FD9500F7A9D
-:108B50009A9F2751BE41FC5A393E866531F9372C20
-:108B60008BD949197D6FA887F5DCC5F5D3158FFB27
-:108B7000375928FC7F07449284FE6DD477EF5E4B13
-:108B8000E5461CC453B8D2411EDC0DFEDFDC705E2E
-:108B9000D5DF57E4D3BC356CA7AD98E24AD7C60100
-:108BA000AD58CBCA5579B3229BB557F79DD406066D
-:108BB0009FD4A787AC8375C44A04EF5FCC993A6809
-:108BC000DD02DCBF6FC1F912972B1DECEF1315FD11
-:108BD0000DA057AAF8792CDF3511D723B278751577
-:108BE0004FEAF8F57CDDB344BAFFD3753ED4CF8DA0
-:108BF00070A4FA401E0B2E60FA403D386293C3F019
-:108C0000255270047CFF5F04A7FB60DDFF289CA257
-:108C1000C88B9FC2B835F3A9BC3068E40587DFF381
-:108C200042404E2DD0BC5F42BF831D78675FF7A3E3
-:108C3000599A739CE90FD5A0FEA7CE2BF6DF774E8D
-:108C4000B893F4E4B348FDECC8EFCCCBD00F686C1C
-:108C500042B978E426E25C00F2839FCBAAFA65E190
-:108C60004FAA0E831D752E4BC4761615AF42F1D652
-:108C7000520AA7C7E9B60AF7D1BD53587C8FBA6F1D
-:108C8000AEE0EFEEAE78F02A8CF3EB2241FC5D36DD
-:108C9000EF4882F2AFBB7CDA202CA7F8F65A80DFCF
-:108CA0002B62F0770756E413BC67B362DA9558BEBF
-:108CB00047F52B4D33E3382BA6307A5A51C1E230B9
-:108CC000611F01B8F5460F290DCCBF4124579E36D0
-:108CD0001EE05D8EBFD882E0F68F41AF5C6641BD7D
-:108CE00012F64E3C1FF1A5E27814AFDBB390BED96B
-:108CF0003C663D9BEE5F8AE33AD13E7FCCE62A415B
-:108D000079F548AC02F35F65214BCCC3C01C218BC5
-:108D100050EEF1F910DF0B18E73183EB6B9F959F55
-:108D2000B3813EF02697374030602FCF24AC7CE6ED
-:108D3000C3B147C1BE99F9B088F70BC9921B5CFA61
-:108D4000F30E3AD714F08FF3BFC6900DE0E08676AD
-:108D500076E8FFBF6CF09E89FB6176BF9778697BF0
-:108D60004D3CF4C7C0BFE06717D9FC497DAC12ED9C
-:108D70005DD08FB97CA7F37769C753C789EC97DAC1
-:108D8000779F00BC28DC03700F2CF488C87FAF5598
-:108D90003FDF2463E8490B2D9F5E2FC62FA4F0749C
-:108DA000CFB7E17AD5F9CE480D5DC77E1756DFFF04
-:108DB000C9D8DA42F087ABF60879586F8F815FA285
-:108DC0003B2F629C34DA353DBE737B36D20E24E4F1
-:108DD000AF266DBDEE7B1A8A10317F4E578A200177
-:108DE000DEDC3C7EA11BDF11F356E169E8171D9E16
-:108DF00049C6605F905BEEF9268443647B75FF7B18
-:108E0000C142BC6027360A02D263E383B1B89F1126
-:108E100033C3A3A7324601FA7CD118C23826EF6EBD
-:108E2000F6FB9F5D96D00E944B03993FA1EB3D71ED
-:108E30002DD4EB4C6674DDB94BE6FC44D83B12EF05
-:108E400089EBB05C60FD762E88C5F828B8FF698490
-:108E50007B99DE3FD5837F45B5E38FEF60EF29C077
-:108E6000EFF668ED60B8375B3E2C2C1FF07D18E004
-:108E7000E79658EE277257E07877C71088C3A83571
-:108E80000818D75B5B7925DE2321FC1DE76A3EB518
-:108E90005A03B5078785F9BCD6706C10D853D5E650
-:108EA00065F8BE332D7F13EC30F899DDEEDFF1C8A5
-:108EB000EE49D7B5CBCEFC05EFB537EBF15F1DA67C
-:108EC00013BC1F57A9A59BEC303DA0BE0D72621CC0
-:108ED000C17BF9369E8F9DD0E6073F8D87FB2D9293
-:108EE0000FB0776B6D054D04FCA69E534CDF18DD6B
-:108EF000BAF620D8BFF113DAC0E2A2F599DF2DF25D
-:108F0000FED0A8D6E522D875AA9EA2B12B87DC3266
-:108F1000549BB2FBB660A7C27841F804FC21B1FDB6
-:108F2000ED79BEBFD17D10E5F11CDF60DC07619FEC
-:108F30000239A6DAB920D7408EBCDC6FECD47E743F
-:108F40009D79CAD85BFBB1739821A8D77B2FEFBC62
-:108F500049AD07F6EEC5FD610C6EA195714C4EC092
-:108F60000F80829FF8D7F25A7CD71B042F9DEFDC2D
-:108F7000D5D92877553F4D35F7539572BF4E29F710
-:108F8000EB805F551BF70A7E4B6DBE9AF37D0DFC9F
-:108F90009E14BE17600AC7BD823F671C09D8A01C7B
-:108FA000FC3A7676BF4EDBDE43FC4512D2F9F7265B
-:108FB000DDBB582BD87A6770BCAFB4307FCEE88762
-:108FC000D78ACC49C5D61B37CC95FD6841F87DAE14
-:108FD000CF399E54B818FB8DBD17E01E23B2F7CDD4
-:108FE000438FB2DFBB3E41F7E7ADDCDF718B15EF9E
-:108FF00017BB06425C82E4C8BA25CAEFB62EDD6D07
-:10900000C177FA97F563E7C1EAF7B1FDD8FD5DF4E2
-:109010000301DC17C4A29E4DC19C077454D85FDDC8
-:109020002F491EF89F8EF2F8CEDA3BAC6EE82FC8BF
-:10903000FDE22BFBB17D6B653FF6DEBF9AEFB6EB31
-:1090400038BDA8E758E08FD1FAAFFDDDF599FF44B0
-:10905000DD5F9FAF8841B914A65B03DE9F8CCD2DE9
-:1090600036821F6937972325DC5EDF0D07B4204F5A
-:109070009AB8DF59724C87DF05DA7D2A17E325930A
-:109080008C4CBEECBE2B8640FCDEA1D3AF3EF11E65
-:109090002D3F77CA88EFE1CDE6FED6DD0271C178BB
-:1090A000DEED26F423561B99BE58BD6F28D3538C92
-:1090B000EE9510D7EDDD26A35FABDAEEDFF40A966E
-:1090C000A73B2966E13E28D37377C5B2F631FEFF90
-:1090D000780DECCE7DA94E2FAD3F3FCDBD0FF09A60
-:1090E0006152E2887AAE2A84EF8B1EF333BDF81802
-:1090F000081E18A7D5C67F47CE953E87F673FCF1AC
-:10910000545C0F95B7A83F1D7FCA84E766CF778F61
-:10911000CBFC9FC7E4627C2FE6D8F67C27B52C49B0
-:1091200057B13100FE6DCFD34C9F9B6550D6007C6C
-:10913000C8BE58A7CE1E7DAA8CBD1F51F9F0E48B86
-:109140009D63837CD7FA773B49280BEDD1F2FE4D26
-:10915000104FDAD93AC4C98EABD2F090A4969F2FA3
-:109160009F90197C437B65A4E7CBED1FE8A2FB77BA
-:10917000EE4482BFDFA63D4F8B3C87E8996778F4C9
-:10918000EC4EE57A9BBEFCD64C7708E45BED33DF12
-:109190001E99AFC078219487C4C7FCE92764D774AF
-:1091A000A0DBF871015D9C9659617C35CBC4F77BDF
-:1091B00012306AF9502D2F1C4BA29EDB9814A60783
-:1091C000D8F8B97364F9FF014BC990C00080000062
-:1091D000000000001F8B080000000000000BC57D90
-:1091E0000B7854D5B5F03E73CEBC92996426992481
-:1091F00093F7C93BE4014308112DEA24040C98D2EB
-:1092000009A062B538BC41C943B0BDB1C5662011E3
-:1092100002A2861A1128E0848762D5367801A34617
-:10922000EF8048B1D5FBC7475BB4F7F78B4A2952AB
-:109230008188964BEFB5F55F6BED7D92394322D86F
-:10924000DBDB3F7CB0D967BFD65E6BEDB5D65E7B0E
-:10925000ED1DB36A602C81C1CF4C334B64EC1AC650
-:109260007F324F316FD0C6984555A9FC9A5321D310
-:109270007CC867AE0C991689D40FE909230B59CA2B
-:1092800021DD620FEECCC2965E86FD2C9A00FF8532
-:10929000A68B64D66629C3EF6A4FBF8BB193079C38
-:1092A0009EF5F09D7DF995CC2A189BCB443D336B00
-:1092B000B7C431F67C9B14B240BDB99BCD3BADD059
-:1092C0005FC56AAF6C87FCC076C9B313EACD6DABDE
-:1092D000CCDF02F93BF7977A64681A83E3603EE8D3
-:1092E0000CCA50FF9AE649ECE3718CCD37074D0A62
-:1092F0007C674F4B6C0FA3FEDBB0FF65D02819E0F5
-:10930000F90A7FAE1F4A176F36C364F9DCBFC27F0C
-:109310008261F96CE8B7BB4B66305FB617BE170EBB
-:109320007D5FA6840E49318CD57747B4677F330FB4
-:10933000D643405980F0E832B13B7C369A74525D96
-:1093400029637FC0FF263366CAF48D53C76326376F
-:1093500069861DE65DC5E735B04F22BCD6B326133E
-:10936000C37E3AE319BB3A6C5C0B0B45437A520E51
-:1093700050F922F3464A6BD42C1AEF4ED66F62395D
-:10938000D8EF80C907E3D9FB80AE2597CEBF06F999
-:1093900060FCC87C3055F0C1B2532C742D8CB76C76
-:1093A000250BD58FE6A91DD2450A0BC4005E170117
-:1093B0000E62451A55C6F1AA160EE16569509F471F
-:1093C0007CAA6178463C869737F67C650ECF279954
-:1093D00018B3C60DD119084570274D6A1ADB047001
-:1093E0005EB3322833985F4ABA77522EC01B5DCEE7
-:1093F000E7DB78DC6251C760DEC7B2A1DE17699592
-:10940000CFE54179A3C2BCDD501E0D78E982EFDBC8
-:10941000AD2C80FD3F9EA752BF6E13E75FA3E263B2
-:10942000636D4897BE9001E992C01CC88F1A3EB781
-:10943000DBA15D19B693A8DD607B0B6B8B0A6B5FBC
-:10944000F5A29531582F175EB007CD509529FE4CE7
-:1094500027F497F87B335B0FF9B32FDA97607F67B8
-:109460008D6C7637D477C9ACA99BF8650DE1FF8781
-:1094700048D7F1C84D55A90C795F9A96CADC58BEF9
-:109480009ABED73B81BF86A1EF607956DFCD9CAFF6
-:10949000CCEA4E18EF82B3FF079807785800F2CB5A
-:1094A000550E77E3FE49637F04DF1B7D360FC7BE91
-:1094B0007F2CF2AB59BEE7660BF0D71479E5C0BD3F
-:1094C000308FFA749BC30C4DAA33FFE3B7B742FE4B
-:1094D00093FD4666463AEF99349B655F0A87962E60
-:1094E0000D1A3FEA0F5B2F77EDD5E7EBBBF5F94699
-:1094F000A67CD4AFF101A0608B6A779D8C26D9E160
-:10950000F90AF8DB6C6E3AD505F09A5F327B56C1EA
-:10951000E706D5BF03D7538361E028E2D99CF9E978
-:10952000683FE0A52AF3CBA3A988FFFB9807E1BE1B
-:1095300060AD9C4BF4D862550361F2AB51F07F678C
-:10954000462D95776E35AB122FAF1D0F726B092D1F
-:1095500061AA623100FE1B374FFD441A4DE516A487
-:109560004727F029B57B4E0AAE82764B362FAE6583
-:10957000507E86054D1680E70F623D35CABD532CDF
-:10958000F0DFCEB89A51285F94BF2A3EA4FF5AEC70
-:10959000EAEA217CBD34B83E2D1D27002F373289E1
-:1095A000C5E2BC9DFE97709EF5967E5325F473FD33
-:1095B0005FBF20B9BCB8F9D59C13E350DE78E71241
-:1095C000BD617E284716DF7B88BE4B332C04DFC984
-:1095D000745BD00CDF5FDD62E679A789F227B74BB9
-:1095E000945FDC2D052D5958FF627C25CAEFED46AE
-:1095F00087995D8AA748BCFC71DBEF621880FC4745
-:10960000102DB8BE98A329C667C7B2A69819A58819
-:10961000AF1B3E41F9B578BBEC09A19C7ED9EEC9E0
-:1096200063989F3C6AA10DDB7F1E5F89F8DB31D90F
-:1096300021D377D987728829DEBEEBE1BBB2E32A5A
-:1096400015D7CB91ED1CEEC54ECB1348E7EBFF2AA7
-:1096500013FF2B06E6DF67433A7847E1BA53B7EDCD
-:109660009982F8FD635D8A81EA3F2B3107E2C3D915
-:109670009C88DF174B8A0FD7D992CD4B6B59CC10F2
-:10968000DED7A832E1BD32736562BF8DF8FE66D4C5
-:1096900077F5DB81CF71FC19EFFFF656D710DF4B62
-:1096A00033364FBF06FB7FD248FCA5F5D3B8EDDBC0
-:1096B000823F180B019E160B3C993357E6E3F8974F
-:1096C0005B0F8B5737E53B6C975F1783EB7D1BACCC
-:1096D0008F62C6FEAA4AEC2BA0034B8B233D33D2EC
-:1096E0007AD4F493ADD0C0F5BE8779F7409A64661A
-:1096F0005E09E457769642E5D95926C287F297E586
-:109700007BDF04F89F53FDD15990CF64DEB1A86789
-:10971000D40147552CF4664306294738CCC13D2473
-:10972000E7200F78DA94C09E581F066786E80FD6A8
-:10973000AB0BFB39FBDE9747118F0D199F8E46BD92
-:10974000DD78F10B930AF4B4F54A24676D1E1F43CC
-:10975000FE68ECAD630B4A86E463A387CBEF4BE472
-:109760004C9691CB33D700F533359BCBB74E275F63
-:109770009F5B9BA38228F7B6BA8256043ABA3CC0D4
-:1097800050BE4F2F973D08B666A7F82C9C5E16EF8B
-:10979000AB4C467EF5C81E14F17DDE8FDBE221FF67
-:1097A00066F9648F0C799B77577B36CEDB6314E5C3
-:1097B00039019CF71B132BC95E99EE95695CB624A1
-:1097C0002688AAA2CFFB8E6B018CFB1DE67DE404EC
-:1097D000D0B1069437D2B10FC7067A9D71F8272011
-:1097E0005EB4F97CDB33F59113E1768697DB03F009
-:1097F00089EBB1F2E1F1305AADBC0EFBB9FE3A4E45
-:1098000087D3CF9A83AB61FCD356D03361FAE2B4ED
-:109810009DEB1D5F9624ECC2EE0C94FB837965945E
-:1098200001D7FD3D0E8E0F97A93B03D7DB9F247D0B
-:109830003F77B6CB2C08726669BBC48200E2E9A709
-:109840009ECF40F9FBC99EE733E685C117D94E4B41
-:10985000BFAB8DD7F198D702E3CD63DA78A1341C82
-:109860006F9EC7FC21CA0FD63ED9DB1F663F90848E
-:109870000CABCF367B497E9F83D5887CA7B53BB7A1
-:1098800024CA8B76E63966094A30D4BC5E3964C690
-:10989000FEBCDE5C17D0BB416B1FD17FA7E01FA9C8
-:1098A000470AD9A17E74C900C9DBA516DFD15428A7
-:1098B0005A8A7484FA53918E12F2ABD784F35624E9
-:1098C0002ECFCF387C7767C1BC1676E8E9989EE545
-:1098D000E0F375B8B83DD86053505F24B6326E07D8
-:1098E0007EDF10447DED8A8A19CDC08E31A5B86D1A
-:1098F00028A7AECF8F6A33C4E2F78C20D64F4F290A
-:10990000A476812ACEDF8144166C95B0CB2689ECF3
-:1099100040473F53E07BDA04E6580FD9DE2C6E2730
-:10992000BA9967B34C7662B78476A286074DBE2398
-:10993000DFA0DC3B2D59886FA45E89EC3ED9D03D79
-:1099400007FB1D898FB644F0D1967F321FED1A9127
-:109950008FFC2AF191DB323C1F81DCFC46F559C0BB
-:10996000A700BE9204BE1E16F265E0FB16A21BFC09
-:109970004838DF5AD15FADC5169247939CF87450B2
-:109980007E433FDBC0FEC47D4A32DACF90A6B6CE1E
-:1099900055B9FDDED72F417FD1575948EF3D60E8DB
-:1099A000CB423B3FA9A8691FF247D29C92B256B264
-:1099B0004FD29C28F751D6E0FC1B9A27F9B81D001E
-:1099C000FD221FD599683FD1706FA58FDB0135B49B
-:1099D0003E1A375855D467937AB356217F34AE0474
-:1099E000FB08E56F4FD79645906F9865F3A09D6291
-:1099F000B5CC2CC176AC5DBFCED649DD641707A6C9
-:109A0000320FCAED734143C03806E56CFF8E1FA1CB
-:109A10001E5F5AE209A8B8DE045FE632D20B9D4E03
-:109A20006F721CE0F5E0DF64DA17758E853CA42FB9
-:109A3000097A76D679939D909FB7C14A78EFECE288
-:109A4000E5E7EC8020E83F45E6FDB1580BD73397BA
-:109A5000CA030BE23D7102D37E36633E45CB773CB1
-:109A600046768CB6DE3BB3383CF6125F165ABEB76C
-:109A7000ABE3FAA260BD27CA066D531440BB3B1A84
-:109A8000C7E4792F0EF7A8010049C1EC7F6FAC9EA7
-:109A9000189EE7F587DA3F30A33A8DF4EB60398200
-:109AA0000D7A57CB7BAD00C75AFB50B902F6A4A57F
-:109AB0004712ED27CC980CAAF89C24C60F281BBD92
-:109AC000808F87AD4C375E387C4A44FF46E8DFA67E
-:109AD0008AFA8152DFE45C80B74C6BBFAAC30BF0FB
-:109AE0003D6CD4F7472815ED31A38DF7EBDCD73764
-:109AF0006E481BD2FF600FD8B3C70FD9016BDFAF21
-:109B0000ED180363453B3E37A17ED5F479A34B2284
-:109B10003B2372BD2665F3F50A766D5236C90D6E8C
-:109B2000EFD6A2BD2B939D3B059756E34A1F43FBFF
-:109B300012EC86D46CB21B3E3D7908BE77CE384D10
-:109B4000767EE34585EC8F46B03FD06EB7F4727BEE
-:109B500096F51849EF6A74BF53C89F4E27E87DE415
-:109B6000D397A5F1C8A78C3565DC043468C9F6E63F
-:109B7000211CDA7E2C12DEEBB2B95DDE5858B52519
-:109B80001FFBDF2D31D4FBEB0B3F4A44FBA4B1F7A5
-:109B9000C3C48561ED96F63C4A7858BAD738ECFCD8
-:109BA000AFCB9669FE0D2F1CF0E27A3F1D94682D15
-:109BB0002F5182EBD0AE5CB2C480961A2B0FCEBD73
-:109BC00015D73D9B6D627930BF5CD44BB89FD83BB5
-:109BD00033700DEEDBE0AF049FB6FA16D1FADE3A31
-:109BE000DB62635908E7BCBB090F8E282FE2617D59
-:109BF0006155328ED35037C581FE9346B0B3B0BCA9
-:109C0000E1DEEF923F45836B7D8FB106EDAF0AB089
-:109C1000B7FE15E04E8F9B56E381F5982AEF1BBBEC
-:109C200002F29B4690BFBFC9E1F46C937C81EFE0E8
-:109C3000BA7F41627BD4A1F2CC1E6ED7DD9CCDED04
-:109C400040EDFBCDD9DCDE9C18E89B84BCF78AD2C2
-:109C50001F8DF66F23F37E86FB4EE6B3A97B884EFD
-:109C60005CEEB85A54F22B595CFD0F8CC1F2890A94
-:109C7000ED2798D2FF088E7B769DCBB39E09FEC55B
-:109C8000FCBD2541DA3F64FBE7237D2B841D79F67B
-:109C9000851BC6CE2B19B293D6755983AB010FEB3A
-:109CA000ECEA4F6A50BEFD4521F9C62C037D939026
-:109CB0001EFF1547FDAEB306D721FD031B8D54BE15
-:109CC0002FC5DF807C79AAAE261FF7C1CC16C8AF9E
-:109CD000037E32BA3A18DA0BB07D203F83C5E563C4
-:109CE0002AE42705E62A12CAF908FB6312FA796802
-:109CF000DF0083C3F72A21B6F2800B4E5A6809B4FD
-:109D00007D153F648F1CFB7296821F353BC560F149
-:109D10002FC5A6D5B3A3988C7CBF66E0A801E61337
-:109D2000EDEA233BB6BE5BA271EA0B9F33A1DFE4F1
-:109D3000AE6EBE2E1BC53E00F09781F6C0DAEC6811
-:109D4000A1C7DB38BFB33EDA47B367383D19837A22
-:109D5000F6F0FDC42AAAA7F5675ACDFD5EF5C21F2D
-:109D6000037290CA7F922D897DED6A9176F0548CB2
-:109D7000BB49EAF3CA88D7B192279C6FB4F4292172
-:109D80002F620F0F4CC1F53B00FC857E992D52DDF3
-:109D9000DDAFC1FCB68C2FF2A009E5067692CBF0C0
-:109DA0003BB022E0BDBCE7B329C8376070D37A6D01
-:109DB000E8A994EB6DA4B769FF9814DDD485E54953
-:109DC0007714925E8D1AC7EE9801DF7F2EF09A6CA1
-:109DD000E37E2EF7EA40D6F2121CDF77F76B387E6F
-:109DE0006914F929938036F6384ADBD12FE466AB43
-:109DF00024ACF7680CEF3FC120DF5157427297F255
-:109E0000711EC9BB13D29E6C27F76799590DC28981
-:109E1000DF693F069C81FB59F473613F49393C3D42
-:109E20009B1C5250406C65FD3BF6207FF6981D88C8
-:109E3000A7DA9E5F1E477D596B61DD32DA2B117602
-:109E4000C6CAF49987903FCF9D39B9E37EF8F6E80A
-:109E50004D073D7EA28BDE7E88DC2FECC42AC92311
-:109E6000DB7BBFCBD6DB7B83F97FB8BDC7EDFAC008
-:109E70009E68754F983C6F14FBB4734BCEC7A09E81
-:109E8000F97890BF404F570CD92BF376477F88EB7A
-:109E90006AD0EE8FB01B8E3D111D40FA9FEFB69237
-:109EA0009F4E41BB07E039631FF80122C765F27975
-:109EB00025DC3FEC337A56437F8D779EFEB901D681
-:109EC0009DD205764F2CDAFB6A2CC9D9D765B60727
-:109ED000ED32C5EB40BF8706BFE29CE2F696A05C80
-:109EE000E4F35F660AE5931D64624B281F13CA47BB
-:109EF000BBE725A1779645411EBE37BBFD7F41BA22
-:109F0000A598B9BCC276F8BD4BD85B5D801207E25C
-:109F1000E538ECBBB384FEC6FDCF83E9C1F5E4C7E9
-:109F2000B1103D3F7EC5BC13FD3C1F171A4226EE03
-:109F300097203F96DAAEB064A8AF1EB70655EEEF95
-:109F4000B21840FFCF7FF8AE37705F31FF15EEC714
-:109F50009A7FE7CAE9B8FFF878C61413CA9B85CC84
-:109F60004F7EE7C58CFBA197B220F757338701C717
-:109F7000BB0BC4C656143501C0FE55F059324868B3
-:109F800057A86D9027A3D9DB5103E3CE6B33D0BE26
-:109F9000647EBBDE9F7E61FDDD35A8C7D7B619B8EC
-:109FA000FDD82E911E9FCFBC6EB43B34BC16E4C4CA
-:109FB00073FF689BC18BE35C9F6322FE03120569FC
-:109FC0007E226D330A3FBC80631533843035483CB4
-:109FD0005DEB506A86D3CF5A7F6DC6260BFAC30657
-:109FE000D20DE407BE60F2CE263F6A5C3E433F627C
-:109FF0009BBDA9BD8697D39AB9601DF051F9B50AEA
-:10A0000037F8981A87F2323D87DB0F91F35DD8A1BC
-:10A01000CF479E4F2C0DEAF3F399BF203907FD4639
-:10A02000FAEFE9395C5E5D589F25CE013C740ED095
-:10A030006654DFCE4279B54E2179B92A8DE3CB90B3
-:10A04000CED36C67F56CE25F27D817042F873FFBF0
-:10A050005A97847AB3CDC9F9F27F0A7724BC37E4E2
-:10A06000E413BC6D68E4C1786DEBA420C71787FBCF
-:10A070004AFD174B72F4726830FF8FDF77727E5C97
-:10A08000278BF5E6203934CFC1E7F4B1E479228497
-:10A09000DF6D601F00DCF3D7C96568A74C9A69A320
-:10A0A0007934BC62257F6BFDCAFE0CB267ABFAF354
-:10A0B0009B86C12B42AB68F20BEACD73C13E01D740
-:10A0C0006DBBFE9C0A342D0B3F779A99E6BD2F2776
-:10A0D00001F7231FEFFB25D27B9F95F413FCEF9034
-:10A0E00019E5D70B596437E5A7F9EFCF41BD1E1528
-:10A0F000DAF16416DA29DC4EAAEF3577A11D38AF04
-:10A100002DECDC0BFFD9A03F0763ED71E4DF609D10
-:10A11000FAEF4BB645B4BBE45C8CEBFB4D26FF2855
-:10A12000B4EFAEBFCE9B8C72F5CC520343FACE9700
-:10A130003D8B508E9CB1EAEDEF33764EAFDD8374EC
-:10A14000F6E4239D778F48674F3ED279BE81F9C3ED
-:10A15000FBA9473A037D97093A9F3970553ED2F9DA
-:10A16000D37D57E5239D37193BBCB86E7665FAF76A
-:10A17000221E4F4CF691FD04F22AFF9BF0E38B1157
-:10A18000FCF8E2FF1E3F52BB91F4E1D19CE1F5A146
-:10A19000CBA4A6A13C9C67317FAD5EC49F61FD6BE3
-:10A1A0001633F9255EF9F2F3879E403BA457263B10
-:10A1B00044EBEF15C59F837E85578EBB3D0169E457
-:10A1C000FEEF16FB18B78505D0FFA1D9FD9AFD1843
-:10A1D000298FDF17783C9DE3FD36ED1785BF768923
-:10A1E000E8D312FC9CDBA9BB25F2C75AD46E2FDA48
-:10A1F000BD0D2FCF75A0BFF65490FB671B0E8C25AD
-:10A20000FFEDD2E0ABA154B40B7B2507EE1F96EE19
-:10A21000FE3006CFBB613FFA494ED87E74B2D88F6C
-:10A220009E0A7E1C83E7E230FE54D4CBD1AE0113EC
-:10A23000F26F03ECD3A00A6B50068E627F0D2EE600
-:10A2400009A0A8E8D1EFDBB4F3CBAD3E13C9BBAD99
-:10A25000BD5210F76989267F561AEA2796E6A07341
-:10A260002EB15EFE33C79B983B3EFCDCD8FB971CAF
-:10A270007EAE4CEDFBB7C4121FF61B9997EC802DF8
-:10A280007621971492537FDEE6A47D0FFD40FD3FBB
-:10A2900007B328AFE9EB450A0B2980F745B3BCEFBC
-:10A2A00021DD507E8722E477787EF03C9AF571FDBF
-:10A2B00002F23C34DCF9B838A7C6F3DDF0F60D6CD9
-:10A2C00080DAE139AFAE5F6D1FC09AC6AA00F75DB4
-:10A2D000B7DB3C68BF34025F37970DF1E1323115CF
-:10A2E0008D0F1B849FB771C947B41F68EC911CE8A0
-:10A2F000DF5DE6E17CB80CF649E6D197AE5BD60DA2
-:10A300007C1806F748EB785CAE7E1D0FE6FF49FE31
-:10A31000CCEB72F5EB579BBFE6171F9C67AFC4D71A
-:10A3200057C4BC22F79791FE6C6D7F78A572EDA69D
-:10A33000087CDCF4BF8C8F91E4DADCDC91E49AFEDB
-:10A34000BCE01BCBB5C873835CEE07C773033CD777
-:10A35000FD9F9E1B7CA276241A480F7A75E7A96898
-:10A36000A7E338EDDB65B20FA6C8FC1CBADE6E268B
-:10A370003F6DE4796BA33A459C2FF6FDF66AD49FB6
-:10A38000FB8D0CF5FA12DB623ACF6C949F3139D415
-:10A3900061CE19954364BF7FD3F3F775B983E7EFB7
-:10A3A0005978FEFEAAEDF3787F185DAB4AC0D02F36
-:10A3B000A1389661E5F623824FA245FC8445093019
-:10A3C0006758FB91DAFD3497DBCBAF8A381AB7892F
-:10A3D000B5637CC6C3F6682FEE4BDC061EE7D3924E
-:10A3E000EDDB8E72D2A2723C3FFEC22DCC00F37F19
-:10A3F000DCD84DF224506FF3A05CD4FC305AFF56E9
-:10A40000B15FBD52FE3F30C8779CFF07F3FF247950
-:10A41000F06FDA78DFF49C6C33E046B74E189D8716
-:10A42000BD81E73B5997F2F348FD8CC4D76FE7FA3B
-:10A43000DECC25B9E01D4DE7FE572877A2CB073EBD
-:10A44000467F0FDB6F5671DF817E0FD2971B92B96B
-:10A450001E533C158867B0F72A304EEA03FCEFD54F
-:10A4600023DB87A706E513B70F4F8D289FFE3EFB22
-:10A47000F04799BED3C867272ABDF9A83FD7DA01AC
-:10A480007EDCF73DC5E36BB659397F6E93385FB21A
-:10A49000E678CD7F42F30A3CCBCFC723F98AE5E9C2
-:10A4A000F96A30FF4F96ABB64138FE97E5EA92FF66
-:10A4B0008A413FE8C8FD04886E15557D84B78197B1
-:10A4C00025B633CC3FDDD8C7E3D4D205BCDAF70BD1
-:10A4D000C2DE5D94E7CDC078AF4FDFB358582C98FB
-:10A4E00042C8636897F96C743ED0D0CDE3481A56E1
-:10A4F000323A0F6E40FF6709FA05EB18DA7FCFA9F1
-:10A50000FEC2BCF1789E610BC8B1E8379FC1D0EEA6
-:10A510003BFB1ECF37A8FE122C6F5CD9AF3B87A840
-:10A52000F8EAF335E8D70078C94FE042BF4D189DEF
-:10A5300066E7F1F84B2DBD29027EF4E313FF77CBDC
-:10A5400041B417A3D53E3A1768D8CF8DB80AD94B76
-:10A55000FE7B76571C433E6AD85F39F635AA6F1DDD
-:10A560008BF66EC5EF6B1DE8A7F8F45A17C51F648C
-:10A57000C8FD4BD1DE3A92ED9F84F8B09707A7A2B1
-:10A58000BD9A09F62ADABF9FEE9B3A16E1D6E4DFC0
-:10A5900026F47F43BF9BEC7AFF36B378B3EE47FFD8
-:10A5A000F7CE24DA3FEE4BF17F1BE7BFC9CAE10DBE
-:10A5B0006CB4F2F52AFCDE91EB5F5BF749B281C621
-:10A5C00049BACD42E7D49A5CD864647E4BCE903CC5
-:10A5D0001927E2E9001F3C9EAFB78EC78188BCCD2A
-:10A5E000A58F6B3C9D33791CC2332E4FA1760B2D6A
-:10A5F0000312FAE1178AF3F91B449C85166775C6A6
-:10A60000E15B80F8602B6B86CEE5B3B1BD83F3BF11
-:10A61000889F89BEC8EDE86C8789F8C6DECEF8B998
-:10A6200012F00DD267E240DFA458984F6E6768229F
-:10A63000E2F3958B06C28752F7069DA7C422D9A0E4
-:10A640009F9C0DFDEB0AD09FE278F75AA48BDAE1CC
-:10A65000A842D43DA7FAEEC9A375DE5488FBCBAA65
-:10A66000DF1879BCE0CBD1640774662CA378C1B342
-:10A67000EF03BF665DAA0FB434C056537C6076CF3B
-:10A680003BE4D7B7EF97868DFB7C38CFC6E36F02EC
-:10A690007D1487C626BA081FCACBBF0FA0FDA1AC88
-:10A6A00053C893D166F41AAC48D7558CFCF0799D09
-:10A6B0000E03D22553C49D9C7BE5BF47FB69BFA217
-:10A6C000F9F1833C4EC8D8BF06F75FCAAAFEEB601B
-:10A6D00005B3FAFD4E4303FA3D8D030DE437793996
-:10A6E0009AFCA3993D39ABBF05F9CC76079350FE90
-:10A6F000BC785726F27500E69937CC3C9BF38CB4B6
-:10A700005E9497A30DA8B7948D8CE214156762151B
-:10A71000C1FD28E4A19FE5826FB4F34900D78DFA0B
-:10A7200068519E7F37D23B5AC801D61C45FE44BBB8
-:10A73000C2FD1EF6E6F79F5D05F91DC21F7BF89569
-:10A74000E219E4BF5BA74848870BCEB9990EF8FE23
-:10A750008B3C6E8FD8953EE6B085E3FF30C56566CD
-:10A76000BFCCE3D61423E713659DAB0BFD835FA439
-:10A77000F929FEF4DAB6904CE75B8E138FD4A8610A
-:10A78000FB9BCD5C8F34ECE5FBEAC8FDCCE5F4C760
-:10A79000B13CBD5D3E98FF27D925EF0C8EFF77EECB
-:10A7A00053987E7F17699F44EEE72EB1BF23FA1BB3
-:10A7B000C94ED1E23CAA86C6217E78D5AED94101E8
-:10A7C0005D1C4C958D8FCB2CFAFE9F12F13B5A5C91
-:10A7D0004C62ABBA0AE3CF07EE63E46FD3E276B420
-:10A7E000389D4015DF47040C20F7B2F07CA883E2C7
-:10A7F0007352594892683FD0CFB07D12C6E940FBF2
-:10A80000FEBC6C827F3BF3B4CB24175509E1B762E1
-:10A810007C473CC21DDCB208C7BBC946E35931BE08
-:10A82000239EF611B48E537C3CAE73D2121E0F9A47
-:10A8300002FA17F329B99C2FADB34D14E7A9C56DE2
-:10A8400068F11D1A5EAA04BE530A1665E17E418BAB
-:10A8500003D914157CCA2A63FC8790FB4B0D24F79F
-:10A86000B5F8BACE3C3588FC7E0EE3406D571EEF3E
-:10A8700011895F2DEEE3FA747F72FE788AFB203D2A
-:10A88000AAC56B68FC1246C78015C6DFFA32B7DF6F
-:10A89000AB969808FE734BA7917FF1DC5203C3750A
-:10A8A00054D56BE6FC1731DED6D92616C27E95A0AC
-:10A8B00015E5A7C60797B35F81AE85E8BF3DDCB25B
-:10A8C00037E704ACF9232DDD949EB34ADDF2184C32
-:10A8D00007E6A0A41AFD64C64CE56A8C6319C8900B
-:10A8E0008075CAF6E6CEA27CC2C007989FF6E4AC9B
-:10A8F000590AE8897379033B24A8EF2FF87026E5FD
-:10A90000912753189BF0C46F660668DEDC1F35493B
-:10A91000F8A3CC4EFFB5F909785FA07F4D1FF97DF4
-:10A9200078DC3FC605223DDC3613D9376E118FC95E
-:10A93000AA457C269ECC40BE35792C9D67DB98BA13
-:10A94000BF0FCBD3CC5CDF33CECFAD79DC5F4C2AED
-:10A950001265679AE65FEA0FA0BC6ACD7252FB41AE
-:10A96000B9BADF1CE47E2E3EFE5B074AE91C4A8B27
-:10A970003365CC913EAB94E25174F987ADFC5C94A5
-:10A98000298E74B41F5A8DC24E15F9A834FF77F37F
-:10A99000C3ECA4B726FF4B09AE8733077F948B72B5
-:10A9A000EA0613D8F1C3C8A5D4422E97CE196DED8F
-:10A9B00012D86D6FA4FAE723BE8E47CF99E284794F
-:10A9C000CD8EAF343911DEC05332CAC904416FE7AE
-:10A9D0002C0E9FB3DA272D847E5BADB09EA17D82C5
-:10A9E0005FF192BDEE9F25DD0470B74AC27E676AB3
-:10A9F0002CD9ED856A2C9EFB2D6B7E87E2AE6521FE
-:10AA000007642107DE6EE9CF55F240E5766F94D1F9
-:10AA1000DE7E479C3FBF93C5EEA81B66FFBB299F08
-:10AA2000DB873364B514F9C875FFC4776A812F6476
-:10AA3000932748F44BB7ABC8EF87EC15EE7EE84799
-:10AA4000CABCAF1CE3965BD3EF2BC7B81339CEE378
-:10AA5000F685E537E5733EAEC67A88B7E8A672D4C8
-:10AA600063FFB0FE62A1BF92BFBFBFC17ECC1CAE70
-:10AA70006596810C05D6A7C7EDDF8A74BB30F74316
-:10AA80003A8FFD41CA5B1F60FCC45BC68E4931280A
-:10AA900087B224C1B7DC5E3B5AA0F93D79DCFBD11B
-:10AAA00062EEF70439C4E32B4BF93D9BDA598CD69F
-:10AAB00073AD88BB98E2E0F796A69467795A616A0D
-:10AAC000D3D98082727ACA715F0CD28FCDF297FB94
-:10AAD0004A47B6C398DBA886CB95A96A581EFEDE06
-:10AAE00058A8CF7FDBA3CF7F67C25F0BC2F31BDD0C
-:10AAF000DEE771DE2F493C8E33703573D03C5D52FA
-:10AB000000EDA5E2E753BA847F97E20D7F26F67346
-:10AB1000CF4F60549EB8D7B213EF1F687E7259941E
-:10AB200017BB9925338EF0417A764012718B2E3AFD
-:10AB30000B6207EF7670FC415D13F47370AE4AEB65
-:10AB400038D16660D7E15A2FB790FDA4AD8B562B54
-:10AB5000F037E0B122D51285FCDE6AF46CC6BEE4A3
-:10AB600028B38A7AB532C6427DCB3F56482FADB264
-:10AB70009A29F4F5F0835194AF50980FE33500C44F
-:10AB80005998BE65F4049B70BE500FE7DBEA64245D
-:10AB9000AFE40A13E969E897E87A78A321C868FE68
-:10ABA000950AC5630A98B5750723D1F7C7C4BA9645
-:10ABB0000D2C44722CC54272EC08F48FFD1E7E5D94
-:10ABC000EE223F5BA17A3B969FB714D0FD9CC6C195
-:10ABD0007B478A01812B147694B397DF0FD3D6B3CA
-:10ABE000265F22D73348C15C5722E320AAF80F4CD6
-:10ABF0002311F53E237B5E3B3F4CB768E58A17C7C0
-:10AC0000491EACCFEF67258A7C6A4116AD37A81282
-:10AC10003294A1FDF1CBBF20DF6AF261C7DA1F9346
-:10AC20007CB814FF85DFA7FC34BB83E3BF200DD7BE
-:10AC3000A11C559086FAAED5E9517D61F94258467E
-:10AC4000B3E3103F500FF2336B3ECC55C2FC83A9E7
-:10AC5000052A094BA8E78D07380E5BD5345CAFC3D6
-:10AC60008C5BCFC78DFEC78EEB8671A1DE613B8CFE
-:10AC70000BF5765BCD2143CC70E34F5071BCCB8D8F
-:10AC80000BE824A44E137806BE08A05FEAB0DD40AE
-:10AC9000FC394DC4EF1E4EE0E3B1427D7C4D6E1495
-:10ACA0008C4FFE587D3CCD0DD2B636D4CB8F596338
-:10ACB00076223FFE52F0C9D1E81FE7A25DF5CB39FD
-:10ACC000F94750AE4C895DD5864C328D7593BCD119
-:10ACD000E4DE85E40F2B300FF2EF9A02A0FB0FB2F7
-:10ACE000DF9A839D1F713E968BFA0FE4C3B70A1259
-:10ACF0002E855FE3470D6EE4435C07837C1801BF3C
-:10AD0000C6476C7A3705206E07BB1453CD4E65AC31
-:10AD100089C789ABE943F303269E6269E2F35815BC
-:10AD200020B86F703E42F168D78EF2FB10DED96317
-:10AD30003ECB50B0B27B6E01EEC300DEBAFF9FF097
-:10AD400046DAE5978B97D6E08A5CC7DAF8D28CBDF5
-:10AD5000142FDD38CB46F1D39344DC69E31203C5ED
-:10AD600011C1FE8DECFE066609A21CBE46D8D15A62
-:10AD70001CFF8B12F77F060E98D53D61F6F8A57182
-:10AD8000D42AC5690756F278EB417BBB9EDBDB8397
-:10AD90007A4DDC1BE81CCB6579E7DD2AC553BC2462
-:10ADA000F1FA81B98CDBEB75A27CA143C45BC05C7A
-:10ADB0001287E2D93BBB18F17FA73D9BCA5364AE13
-:10ADC0007FD8B7B8FEE9CCE2F664E7ADF9540EFBE4
-:10ADD000825188F7F932D8CFFCFC9EEF0FF2F87859
-:10ADE000917EDA4D05DC2E1BB473443ED22FBB2B73
-:10ADF000D3BF05F9656189374302BE9A6FE27E577A
-:10AE0000E0BB6D7867A68635ED5672F0FE45D3BB84
-:10AE1000861CE2BBC789EF8A81EF72747C172C18FD
-:10AE2000CFE52F0A538DEF06F9AD30325ECEFF1419
-:10AE30008EDBE9ECFE7D03EE2B7ACD44072DEE315F
-:10AE4000729D87C173C2C8E171C932C1B36F3878CE
-:10AE5000AE84FFC3F92D89713E1F691D24292C6022
-:10AE60002F1B5A071BDDFE10C23FB81ED6F07DE433
-:10AE70002570CB36E28B9B6F9539BF46737D8EE78D
-:10AE80004DC9307E9D18FFE675BE6A27D6AB930884
-:10AE90000F75BDF51417C6AAF9B99107FE203CAD90
-:10AEA00042CE69E75BB345FB998E3A23FAE366D558
-:10AEB000EACF9966DBF839D6CDB38C1F85DB3DB37D
-:10AEC000D986CF308E71369E4369F5818FDE2F187B
-:10AED0003C872AC073A823C2CF720EF81AF9FEB5B8
-:10AEE00084C5DBEE06BE2BF8694919FAE326272E46
-:10AEF000DDBD11F24F6E2DA2FC6B89B7DDF3169606
-:10AF0000EFC8A77CB541223E3D57CFDB1756DC3A50
-:10AF10002D2B06E5BFE817D713EED7A3FC9D755080
-:10AF2000CF3D3ABB0CE34BAB85DFE0DCDD8CCA6F79
-:10AF30001C63E721BB8B55F2FB554789F2EFF17E8D
-:10AF4000DF18FBBB328C33AECE1E9883FCFD46D996
-:10AF50004B45983F227D3667B873AFE24229340AE9
-:10AF6000F0521DC7EBD7963D95827E98EA2A9E2F18
-:10AF7000F654AECBC172C3F939C3DDFF8D12FB9E0F
-:10AF8000C1FB6C625D3FEFFD90EEAFF92C9207A71D
-:10AF9000E89BF021F91D984D72A0EBCCE7CD52D083
-:10AFA000CF3DC9CBE350AB2CAB92517E4DF79BCA42
-:10AFB000319ED861197B04E30C6227548E47BA4E48
-:10AFC000B230A22BF0794C21FAB5AFFA2C230699B6
-:10AFD000CBA6E7738D8FEA34FEAED6F331AC4F5774
-:10AFE000E1F8CBCBDB91F818C6CFC0F6B3BFA5D73D
-:10AFF0003783FD45ACB7C8FE479203F8132E178779
-:10B00000E0E8A6759586D17D39B8EE3AB475370675
-:10B01000E13019FAE81E4FA6E429A20BAD133C1645
-:10B02000D24711706BF0A5836C636597C2853F8A28
-:10B03000662F72081C8E441C9797433B2F8B1B82F4
-:10B040000BC6BF1EE9C0D67078B64B4D5C6E88FD4E
-:10B0500081E6CF68D0E6DBA39F6F4514BFD7EE46ED
-:10B06000BF13B6738D2DFA3AB81B853E9D65F13D31
-:10B07000688639DCE49C4FFC700B683427CCFF6F8A
-:10B08000A9FE3AC447AB1478B93F8BFCF114FF0119
-:10B09000F49E51186607687045E2A36104791809A7
-:10B0A00077241E86E8D3978CA9761F6E705E11F305
-:10B0B00069B5F3F53A30DECCDFB550C01485FC9BA2
-:10B0C0005211C5A16870BD2971BF6440E2F78F3489
-:10B0D0007B2212BEC87B7A1A5CE8EFE3700CACC22C
-:10B0E0003B820F166A7E3E4EAF24019FC9200D7B26
-:10B0F0001EFE60A141F3B3EAE819797F4DC39B16A8
-:10B10000E715892F2D4EEB9273B78873E591EA49C5
-:10B1100060A7A7C65D8A47EDDC2E6ED04FC9FD4003
-:10B1200003F7DA490EC60DFA298F2968DF4FF21CA2
-:10B1300052D02EAFAD8109000DDE147E1F0DDF0F42
-:10B1400064F8B71492DEEE1F8FFE959F4C7D82CE81
-:10B15000AB3E30703F7D247EF68C809F91F87D243D
-:10B16000F8A3D27C4FE2B867A4BE0A2CECCC16E759
-:10B1700042CC9F85EBC1E9C8AA44FF11C8D7AFBE36
-:10B18000C24D2B16015DCB33FDBFC076B730DF64F7
-:10B19000A46F5C8DDFC8CF4918F9E1978BFDE3649C
-:10B1A000A177CF6FE3F11ED5DE518F4D44BBF198EF
-:10B1B000910569DD7B497FDE25E03F0F2A3684F566
-:10B1C0009FB193FE5DFCFA7C8AE328D86C187A4F15
-:10B1D00003FE8E0A46E9DED328DE1BA7CB9776A7AF
-:10B1E000E8EA8FE9C9D6958F0D15E9CAC71D2BD39B
-:10B1F000E5C7F75DA3AB7FD5F12A5DFEEAFE69BA2C
-:10B20000FADF3A354397BF76E0BBBAFA1F0FFA0F61
-:10B2100084DD10F0F615C2BC1788795F7F719EAE91
-:10B22000FD9F62A61C437E5CB081C7A55702867451
-:10B23000EF8B7470FBA209FE207D27B3018A076C97
-:10B24000084A9E10C3F836BDFDB1B4A78BF078B99B
-:10B25000FBF805AEB90634B94F170AFBE32A761599
-:10B260008F67FD7ABAE6B3BCBF8BAE66B79EAE56AB
-:10B27000554FD7E8423D5DED1E3D5D6327E8E9EAA5
-:10B28000F4EAE91A5FA3A76B824F4FD7A4D97ABA21
-:10B2900026FBF5744D5DA2A76B7A939EAE99CD7A8D
-:10B2A000BA6505EED4958F446F4D9EE6B42FD7D581
-:10B2B0001FA4BB6F09C537E575FC50D7BF46F70023
-:10B2C000FC41BA17301187F93FA47BE1283DBD410D
-:10B2D0006F8D1A359EEC8D124C671708BBDE37BC9C
-:10B2E000BDA1C99F70FD1EBEAF1D492E5DA2CFC47A
-:10B2F0003E77447D16B1CF7D8F81BEA5413690DF6C
-:10B30000EA56C19F87A338DE3FC7A2ABA11ED499DE
-:10B310000070BD8770C338EF4515933FE2BBACDBCF
-:10B3200088FDDFCEFA289DC30628F53307E9EF79BB
-:10B33000CC43E902E63309FFC4F45109E8B7E8AFAA
-:10B3400040FD7F61EE5B1FD0B9D61BF157F40EC5EF
-:10B3500047787E92C7D849210F4EE0390AE4CF5A88
-:10B3600007F5ABEA0AC3DB49E16F9C3749223DCDC3
-:10B37000E4288AEF9A778B44E744F3FE93A78B4641
-:10B38000493C1E24226D6DD6F0C7F7473B47A90400
-:10B39000471AEB16F61CF3DB72A81F7EEEB1CB4406
-:10B3A000FB58B785C3F7ACC4940971741D8EE8EAE5
-:10B3B000B670789E35320BE2F369E65791180F2884
-:10B3C00020A2F83D8C22E48F79FFF95636FAE9A2E3
-:10B3D000A25E98557D359ECB0456919FFC7B4CEF29
-:10B3E00027BFBD49223FF9F7004E48DD0E8F1BED08
-:10B3F0007C2DFFB080B71AEBC1F7247793847EA928
-:10B400007F587FFB7FC8EBFD9DFD0DF6C3385CF8D0
-:10B4100083F4D3FC9E85061E27317037DF1FEDFEB7
-:10B420001EE3FEBBE6406500CF45653094308ECA12
-:10B43000C8EFC7EF1CC5FD9EC9AC8FFC0BECA8661E
-:10B44000D7FA49FE9688FB1767C5B9E2A22E0BC34F
-:10B45000389D927D87E2F01C7111F0601FEA61C592
-:10B460004FEFBF946C792D8EFBFD8C4EBC57A9E934
-:10B47000FF91F9546127C3EE3100DF350D677FBCC2
-:10B480005AC4E3035A5BFA46E139A006CFFD2DC743
-:10B49000282F2B1E86E797F83E5478FCA3C905E5B4
-:10B4A00061F24EB141FB303964B4F9E89195352D24
-:10B4B0007D74BE6814EF58AD4D5BEEF087D9898777
-:10B4C0004609FBC71260B84FE02A0A53E524CAB503
-:10B4D000FF627C1F6D76433FE1F2F362020B3F1F78
-:10B4E000686F394EF0AE91FC7EECC49CCB4256A006
-:10B4F0008F59C1BBC0F07DCB0DC7308ECB645FEEE2
-:10B5000009A923E3CDEC562E84CBD3B723E4E94F2E
-:10B510005A068A719CD6967E0D5F0CCF6B03C9DCF0
-:10B52000BE6E6DF984BE1BC03E447E7B754BC1214F
-:10B5300015CA3F80BFF8DE8ED9C5E162175DA457FA
-:10B54000E7083E405F5C3AF0CF07CD46E2B315E92D
-:10B55000363A2758F166DE212FAC67134C57FE06AA
-:10B56000700F8DC3F16412F214F8C987F2C194A26E
-:10B57000D079419C6306D1E9EFED4FC3AFC9CAE86A
-:10B580009D2453BA8DEC822B85F36FA3F83B408347
-:10B59000F6C94517C9FF15022FDABB4F1FDCC3C818
-:10B5A000DFB3E25EEE375C51CFE81E026B869F8A06
-:10B5B00021BED1F44C02BE50031F3B5A60C5411757
-:10B5C0000FB55898BF00EC108CDBCF19A2638757DA
-:10B5D000716288C1C66A571DA60F4D38D181E2EF4E
-:10B5E000E1895FF4618A670438BEA38905D13EA66C
-:10B5F000B37F18DFB904F2307E8C288FF1F37CAC76
-:10B60000288F9DCDF3E9DEE7A46A042CE23C2BDD14
-:10B6100016373517E5F402C6EF818B7720B60B7D20
-:10B62000916A8BABABC6F2DB19DD0BD1CA7F2ACA9C
-:10B63000936D1FB5E7A01E99A56FBF45E021C9F620
-:10B6400051C7243AF7D2976BE74A09B6F3C7A87DEA
-:10B6500089BEFC51D1DE6E3BDF3709CB73F5E33F8A
-:10B6600028CAA36D5C1E321FE3EF1588F20744B9A8
-:10B6700015CB717C0F2F97B5773944BD75020E8CB1
-:10B68000A923BFEB28EE77DDD1622921BAB45C246F
-:10B69000FA3CD4C2287F6B511CC909430DC7779C63
-:10B6A0008BF383A3990DFB4EC1AD42AEC5A8FD5EE1
-:10B6B000EF30724F2B8F73F0771864B789F8C96C2D
-:10B6C000137243ACC741B92135793893713FFDE519
-:10B6D000F81A16DA05B48F32E007F93AED1E03F3D3
-:10B6E00087C9CB946551CC1F56DFBD204E974FBC08
-:10B6F0003D4557DF352B5B576E2B2FD295B35971D4
-:10B70000B46E960BFE8A2A29D3956BEF43B0DDA267
-:10B710009E58BFC6DC6B74F5CE17AAB1C8E327A745
-:10B7200082FEA178068F05E5C3727B7612EA9FA799
-:10B730005B2610729E857505462B7BC6C9E3DC9F90
-:10B74000C1F34328FF598B97BEEF817215D25DB0CC
-:10B75000EE54A8DFD5E2A0FCE32D6E4AB7B7A8945B
-:10B76000FEB4A590CAB7B47828FF18F48FE9A3D027
-:10B770000F7E7FA4A586F21B5B7C947FB86536E5BF
-:10B780001F6CF153FA40CB12FABEAEA589F26B5B87
-:10B790009A29BDBF2540696B4B3B6F57C4F5CC332D
-:10B7A000E25EED3395FCBE7C241D3B8B841F52C4AE
-:10B7B000ADD887E2563A8B306EA5BB9FEC702D6EEC
-:10B7C00005E74DFD59F9FC23FB7BAA88DB6F45ACEF
-:10B7D0006F55345FCF743E9CD7E3591D0D7C9FDAC3
-:10B7E000C4E990D53340E5C94B382D9E12FCC95CA5
-:10B7F00001965641510254EFACD45715CDCFD529FF
-:10B80000CE91B9619E15E2FD2662BBA001E15226F0
-:10B8100070FDA9D17570DE4E0E27CE7F3878F70BFC
-:10B8200078E5F26EFE2E4B4D4708D93ECADB44EF59
-:10B83000B25866FB420AA42E9F9FDE8928BA3805BB
-:10B840003667206F2E5EC75448D396E9F76D290BF3
-:10B85000CA74FB22F9E2434C0539602BD1EFAFA249
-:10B860007297EBDA59D27EA82B37B956EBCAE7DDCF
-:10B8700095B5C68DF84CE5E74BE60DAB5832C0B533
-:10B88000B07323C1F59198C75949A5FBE5817D5A4D
-:10B89000BC05DF5F3C29F40BB36C207BACC0C9B3A3
-:10B8A000F9B10103EA874FFF3596E4D2138F1B826B
-:10B8B000E84706F164C0F55F0C661F9697B27ECA32
-:10B8C00063A80CE6C73255C6FC383640FB2BD85F60
-:10B8D000BC5F8471ABB2FF712BE4CFA4FB9FE4711A
-:10B8E0007321D29FF9829EF9DA7E6AB312E95FEE84
-:10B8F0002F22FF8DFE7E5D9BD85FB459B99F6E9558
-:10B90000B32209EDD6B323C439DADDAF1E5D00F8EA
-:10B91000B6271FA274D02FA71A86BD3FFE4504FF8D
-:10B920008F026617FCFF05F2FF99F2B713D10DD510
-:10B93000903B40EBE0ACE475CF45FCBE2E737E84BB
-:10B940001D17CE4F11F855F655BAE7021E953773FD
-:10B950003C013634CE132DC773300E41CBE78B3804
-:10B96000DDBD2DC9B9D561DFD5624EC742D657833B
-:10B97000FAAAB0C4E00962C75E87CE8F61CDEDF050
-:10B98000E27B084A19F3A0981BC53A56A3EE56FE6F
-:10B9900026539C9572F86AA6C27EC6660B318C4B04
-:10B9A000D3FA65C21F728F909B5F38AA63E99DCB63
-:10B9B0009441F9873A927D61F3F6211F7DD169E4C4
-:10B9C000F33AAC2F2FB471BFE1A242535095F05D12
-:10B9D000B50E7AC751D921B1B42C846312E1811D0F
-:10B9E0008C263E8CDE3C9A0560BD943BFD9662F44D
-:10B9F000DB85D483861CC19350AFBED8B413EDB39E
-:10BA000002C48B0DF1726B6E350E9D5B48F85D289C
-:10BA1000E63DBE98D3AB2D3D021EE6F1E27BA78B3F
-:10BA20003A353F8E7E9E0F96577D07DF856CED93EE
-:10BA3000B95A8BC0E77A63DFE8B9D0F5997E804BBD
-:10BA40002638C717A30DBAB98205488FF3F9D53F39
-:10BA50002EB1AD5924976A488F8F37B0F0F3532D2C
-:10BA60009D58CCE5EFB1221E876A771F257E1CCA40
-:10BA70001F39BA00F0F1B48115D2B9B181EF8FB599
-:10BA8000781D19FD0078AFA158C845D6C6A6A1DE1D
-:10BA9000761A28FE54EE8AA27BB3B253A1B8F736C9
-:10BAA0005BB5E34EECC7A1D039D11479621FDAD16E
-:10BAB00066A7611CDAE14776FEB00FE386E4748581
-:10BAC000A1DFABCDA1703B24CD40F1808AB3DA82F7
-:10BAD000E74AF9B6139588CF435D3FA07722E4EF9C
-:10BAE0008B981DE117330A92B5B126EA3F90A688DC
-:10BAF000F766BCB56313C591888AFBA19A4F70BFE6
-:10BB00007DC471DE8AFB02D5B688FC81F715F37D12
-:10BB1000A211CF0F21FFF8CAF34E945FAF77AD8922
-:10BB2000CB427B3AA8902D52F8D7D6147A0FA1CBEE
-:10BB300044EF356878CD0C28BA73C8F4667DDE1CF6
-:10BB4000711E698CB827B75C8C8F2797A1B0F91844
-:10BB5000DD7CFFC65C36DAFFDC572CDEE914F97BAE
-:10BB6000447EAF3190E201FC1CEE5A9489F3BAF0A6
-:10BB7000829FE2CE47B2FF2715AB62BC80D540EF73
-:10BB80000287AC1887BEBB8579D0CEB30415BA073F
-:10BB9000B047C8B35C1BE7FF3B4AF87A8D4C733B58
-:10BBA000F8BA539E890A4623DD1CDD650158E7C5B6
-:10BBB000AF4E652AE8C15C87D780FEF7DC66930745
-:10BBC000EDCF29BFB0119F9CB7F1382EA5F9011513
-:10BBD000BFB7EEAC2854C3E00EB6383C289F76B60B
-:10BBE000583C181B1F1C41BEE6380D143FAF1A7895
-:10BBF0003CE72EB11E7715F3F788760A39B34B0967
-:10BC0000CC403877013D316EFFD0066E1F2F5F6547
-:10BC1000213896BF9E43F6D548787BA2C5EDC9452D
-:10BC200078361852D05F55B92E773DBEDFB1DCCEE5
-:10BC3000DF3796638B1EC3AB11ECD74686F67C6B61
-:10BC4000CC359EF961F25D8E9D58887C25CB8114A0
-:10BC5000F4E7F43C7DE1268CE705FA6DC57CA8F895
-:10BC6000839B307E77AF3D9082F1BDC78A3FE2E58E
-:10BC70000981AD18DFDB577C9297A707520C903FE4
-:10BC80005E7C9A97E705B662BEBFF82CCFE3D91B5E
-:10BC9000C8CE53C5E76F0AA0BFC5E4598202F9E7D1
-:10BCA000007F092CB16E919E1678D1CA9FC3EFB068
-:10BCB00001DB2FD2C8F283A25DCF08E52F8AF2DE26
-:10BCC00011FA7F45B40B8DD0FEB068776484F647D7
-:10BCD00045BB632394FF4A94BF3142FFFF2EDAF540
-:10BCE0008DD0FE6DD1EEDD11DAFF56B43B3E42F948
-:10BCF000FBA2FC3F22FAFF40D4EF17DFB3ED1BDEBF
-:10BD000047FF7D36C811944B85F60D71B8CE77B6D6
-:10BD10009713FFB756F0732A8DDFB32546EF0EDF7A
-:10BD200056C2DF3BBBAD84CB71A584F339F0E1C3D0
-:10BD3000C877CBDF94299EA8D5E039154439BADEFF
-:10BD400040F6C0F2D7F97E7DF93A25187E1F486B80
-:10BD5000AFC1BF06E103C66DC314D6DB97C5FC9C1B
-:10BD6000D1EC767B6AC3E499D1A1CF83BC602877FC
-:10BD7000417E53DC78E1BAAAF6C2723CEB339005FF
-:10BD8000A2D45B42F88E8862177AC151DE5188F0E6
-:10BD9000D9147A3F4193F3CCE6D6F935DA6C0ABD73
-:10BDA0002727DB79F9945F4C74A09DD5C6FC7D5E96
-:10BDB0006CEF56C88E3FD45EE640B967B22F70E094
-:10BDC000FAFDB894E3BDBAA1300AE5B5FCA081E460
-:10BDD000F711075FEF3BDC3CCE0AF40ADDAF0279D6
-:10BDE000ED411D51C042AB506EEE7DE8E05CEEE7E8
-:10BDF00063F6B115747F493B579794B07D406D0948
-:10BE0000C74FA6D0230AEA174877958B7B3701EEF8
-:10BE10008FCA54983B35ECFE706D89CCEF3D69E7D5
-:10BE2000A1722DBDAB95B152D19D23A4DDA3CF9BB3
-:10BE300022F48612A15772DA414EEACE4F1CBAFCA8
-:10BE4000B74A849FC7C33C68C74EF9C5069287E7C7
-:10BE500051BF4923CBBD41F92BE4F12E4400CAD197
-:10BE600000BFDF7E6843D9AF90DECBD719E83DEB4A
-:10BE70002B95A30AE218F090E797482FC0845270E0
-:10BE8000DF74393CE4197D71F4DEC765F091F76821
-:10BE9000791CCADB3CBF42FD5FA2372E83AF67250A
-:10BEA000CF713FD2D11925EC6A6000F4DBC545752E
-:10BEB000E1F9BE49F853B438652549E1EFF58B7BCC
-:10BEC000B2B2E0E3FB99578DCBC1F78A9AC8BFBFE6
-:10BED00062DF3D6EB4DBD71AFC0ECC1F8B9B368025
-:10BEE000E32C874D3FE26F2FF641EF72BE7D33FAB0
-:10BEF0004DBA8326ED5DCD10FEB30FE38FB4773BD3
-:10BF0000DD64AF897CD5CDD530DF6EC5518C266818
-:10BF100047C9E44D46B049F799D8607DBCEFF7F4C6
-:10BF20001183E8EFC64DD52097F64531DDBBA5FB63
-:10BF3000D0CF4EF9E99BF09D5218EF4619F6663BBB
-:10BF40009F99B5C976F5103CBB9FFDEEA655E8B0AC
-:10BF500013FB1427E3EFCD9F51FB6390B4B05F59FF
-:10BF60005F82FBF5AE1389E1FB75AD7EACA8DFD037
-:10BF70003BD0F08C4AF53B4A801FEA7B06624A08B8
-:10BF8000DF0315E1F563841F20ACFEA6AFAB5FA80D
-:10BF9000C1F3CCDB3797F0FADBB0FE59B53F9162C5
-:10BFA0007A22E089BFB4FF9D04FF08FD1789FA6774
-:10BFB000426F53FDB3AC3FB1348BDA3D85E39C7BDC
-:10BFC000E3ED0A31EF443CC779D7E6FD197E6FC136
-:10BFD0003E707FA734A9F8BDDBD2E140FBCD6AEC0F
-:10BFE000F0A11CCEC5F7C7260CA5CFA2F2187FE999
-:10BFF000F7487EEEB6B0F85AE4D76603ED6F7AFAEA
-:10C000000D0F205FEE489BE8C0FDF33E535F5909DA
-:10C01000DAAF076C64BF1A323FB5A2DFDC5CC0D771
-:10C02000BFD5D9E42981BC35BD84DE0F95EF5DDE37
-:10C030004DEF98DFC7DFF7527E6CF2EF46FE0A2D18
-:10C040002F5C18B6BE7797F27B96EB5EB36DC0FDA2
-:10C05000C13AA3A7A300ED70BB42719FCA8F0F4ED8
-:10C0600023FBF0E70646F21FE65905FDB6CD55E87D
-:10C07000F7300C94CEEB2B217CF87C55502F2341CC
-:10C0800091F07ED0FD8ACF82E71D6661D7EDF0F09A
-:10C09000FB61DAB81784FD79A184BFB7B623EDC27E
-:10C0A0007B8B5DF8FE8389EE75DA961942A618BC83
-:10C0B000E7B6F3D462A46774FF3ABCE71C95A238D4
-:10C0C000707E3FAD85323A97EBA6EF817A03ED1B88
-:10C0D000E29719BCE87F8CCA35E9FC1D361827DCCD
-:10C0E0001F1233DAFF47A4E7B837951B11CFEEBB19
-:10C0F0000DF43EEA83EE772D068033A65CDFDE3159
-:10C1000051DF3EAE5A5FEEAAD59727CED297BB6FCE
-:10C110003745F875F4F9268DAF4026D8404F45F1E4
-:10C12000221665BBD082FB9EB5AF4531A2CFCA4D6A
-:10C130001D05B83EA307085F514551E417589B6C95
-:10C1400022B9BEB694FBF50FA79B6EA43CCC0BF9AD
-:10C150006347DA51DA8F5C8217DBA9BF62FF3616BC
-:10C16000F61DFDF2A3BD96521E57C3DC15E8C7634A
-:10C17000240F9F95BC9E4388EFB7B8BF624733F743
-:10C18000633F388BC741D20C2A70BDF3FA31960D4C
-:10C190007DB82F8BB1B5DF8DF19D91784D14E70DF2
-:10C1A0003BF0762FF29D9FBF1BBD46BB6785DF2B03
-:10C1B000E8D604BD8B366BB478EF4FD809B1EEF8F2
-:10C1C00092B6B0FB1A89C26FF2F0C47956D41FFB45
-:10C1D000C43B2283FDA934280F79457F54A9E6AFDB
-:10C1E000E1ED3769E73C229FE0E4F97D47E26EC468
-:10C1F000F5B569565C19EEF7D70AFB2E36CDE41D6E
-:10C2000005F37AE49829208D81BCC28E18C12ED8FE
-:10C2100017C7C735BD1E15C07B818FB8CBE99E619E
-:10C22000AD80FBB94ACF3BB8DE07601DED84FE1F31
-:10C230007179AC65E2DC3400F051A8159828876A62
-:10C24000CB68BFFB88D76345BDF9489AC78A71DAC6
-:10C25000D664C581716B716E85DE897BC4E277A07F
-:10C26000FD13078AD484E749E91D53E97E1DE0DA0E
-:10C2700050C18F1A98886FC4F8C27881CF1DEE051F
-:10C280000E7C97C195BBFF5FD04F1F8FFDC5F07629
-:10C290008827A7C0D3AC5295E07689FEE3173C47C8
-:10C2A000F5F1A7AD22AC3F4147D35416C47D9A3671
-:10C2B000BED6CF60FFCC4BE7006B7EC5F1B62A9DA2
-:10C2C000BF8F65BA8BD17EEEB94AFF5EE4B381E4DD
-:10C2D00028927729EE942AE4A394635B67E0BD8BF0
-:10C2E00035BF8AE2E32CE4FC9EA230CB7538EF0424
-:10C2F000BF03F118B95E938F74D421536A74895CBB
-:10C30000BFC90A6B97E32E5DC7C96E5755FEE8613A
-:10C31000D673C47A493E36F07DEC3F725D6F8FFE76
-:10C32000602CD72361DFE5CBE7DBA4FE7524879380
-:10C33000155A67E911E3E13B7B98979841C5B8E846
-:10C34000DDA54EC1C7A0974A91EF1D936CFCBC9D23
-:10C35000F8ABEAF90DDFFD35E42FE0EFF3815AA9E0
-:10C36000C73AFA482FF6F80BB0FE36C5FF38FAD3B5
-:10C37000B71D4FA2F72BCDD1FCFD5153C47B299A99
-:10C38000BED85DCAFD486AC4BB9BDF34ED4E4B2B63
-:10C390007678B0BFB77F6B49F8C7DB3F6947BA57BC
-:10C3A000D9604D3F5372F326BCFF6C7D93973F0DD0
-:10C3B000F980827859467E97C31977D2FC5BDF33C8
-:10C3C000933FAB54F66CC63CFBBD95FC717B0F4CA8
-:10C3D0009C8DEBA4D55EA1A2BD7F40ACE37F156927
-:10C3E000E4BC6493C78FF640E4F7674B35FF9BE7E7
-:10C3F0007817D0B7749789DE711A8C8FE8B2F2780B
-:10C400005461872E10F26CC1C1F5198718BEC35153
-:10C41000F75A29B45F60AF4E4478522F4ACC0FF2DE
-:10C420006F9B389F4D753D27A19C49731DA9447989
-:10C430009FCEFA56A1DC486FD29F97A55E54A8DD27
-:10C44000BE142FF5873F18076A62624DC7F9D92AD3
-:10C4500094F329FCBCC5E488E271A1EE6ADD3D6A73
-:10C46000ED7DDBB7851C35014E8D6590DA147E6F4E
-:10C470003FA2FEEF443D19FDF6E8FC771C3D4EFD62
-:10C48000DA944FC3E34D715F4A426B193FFF043C9E
-:10C4900005701FCA62E3F879A9D7AB86C7DFA68209
-:10C4A000DC359761FC4980E24492C5BD082DAE079A
-:10C4B00030E044BF9B16F7B193E9ED112DD5F6E7B7
-:10C4C000B9CD32ED3B8A5FB5F2FD413B0B5A25F405
-:10C4D0008731923BB91BF8F9B4E617BB0D1713EA85
-:10C4E000257C0F97C6EBA6386ACDAE02FA92DC59CE
-:10C4F00017F1CE94F68EB66134E78B6D2D0EA2A3A4
-:10C50000569EE68FA4A3FE9C53AB977A3195F9E330
-:10C51000C3FB0D527FA9CDFB891F522F6650F9B680
-:10C5200016F532FD678FD07F32F1CBC8FDA751F9E8
-:10C53000F6D0BBCEE9808A9F0EEC77FA54942BA1FB
-:10C54000A99E61F09C7A8F5E4E8EE9D1CB5D0D2F56
-:10C55000DB14AFAB0EF0BDED1E83A78B61FCA9BE53
-:10C560005E4DD66F9CFC5D6BAD7EC83513EB2FE343
-:10C57000F5BF754A5FDF577920B23EC177FD457D33
-:10C58000BD48FA44C20B7025DC1406D7248BFEF795
-:10C59000DACD9E7B095C09B784C175835B5FDFBF21
-:10C5A0006A78B86E2C347F2D5C5ABDEF4CB8B27AE5
-:10C5B00091F39859631E01EFBCFE2DB3AFACDFDBE6
-:10C5C000967C7DBD3B9A23C7096871DB3A7B24BE0C
-:10C5D00099DBEF0E364071269ADD11C71C22FE8BC7
-:10C5E000DB0DEFE07F93197B60B46FCEE804C4BF2E
-:10C5F000F7F64755BC1FC3F515ABE5EF56C2BEA411
-:10C6000034FC5DEE21B85653BF2F61BC13E9598B42
-:10C6100007EDCEE254664946E3CB1DCCC6F7C7EA28
-:10C62000476BF29AC7971709DC3D9BD2BDDC49EBFB
-:10C630003C1887F07CD371EF1DEDBD67F4F8A1FACB
-:10C6400023F95B343C994CDDF47B1D06EA6D1ED466
-:10C650000FEF6211B4DB75B3398476B516877A3C77
-:10C660007ACED10495DE3D588DFDCFBE65EA1ACC59
-:10C670004B87E3D5E536BC37D5AFDD2F5D83785BDF
-:10C6800066F167261AE87CB500F7C3CC172F2E2376
-:10C69000FB4A878BD3D0E0A99638FEA3D2FC0FE3E8
-:10C6A00038D586BE1D3EFCA6F4F17DB62381BFBB06
-:10C6B00084EFEB0CB3FE353C54897E0E193D5F0EC2
-:10C6C000C0FC0E6D8CA57BF80BE26F99836FB22CCA
-:10C6D00034F812F1003D0CEEED04B76D6E6632C217
-:10C6E0006D14705B1204DEBDB95F07F760BCCC7DD2
-:10C6F00092F67E3AE59F0F38E9BEBBD9F0F9BB331D
-:10C70000510F971A3C68776E03FB02DF77FB3F02FD
-:10C71000DFDBF18C258EBED3BB6F6E71EFCBBDC955
-:10C7200040EFBCF8AA5E203AED6AB07970DF3E9720
-:10C73000A9F4EEEA7C710FE60F95FFFD723FCCEF96
-:10C74000A5D1FE83388F3BE20D19EF121CFE627AF1
-:10C75000476BE295C5CF6AE7F033847DB050E07156
-:10C7600026F352DCEE4DCC6FC471DF3E6BF2A25D5E
-:10C77000FAB68847BE8505E8FBAD2C48E96D2C4428
-:10C78000F5BF872FCA42FEADE8D1E9CD005FDD637A
-:10C790000579B81EC3F0FE06D219F8E50E17E79723
-:10C7A0003F2621DE3B13AE887FEB248EBF0746FB7E
-:10C7B0007FC3D7ABEAF2204C8E4969E847195C3F4A
-:10C7C000D5099CFF1447DED7AD9FBEF3DA7D7FAF5E
-:10C7D0002DB902DFFBE23F3778EFA278718CCB777F
-:10C7E000011DFA547ECF11C4863D0074AAA9942974
-:10C7F0006E6FED67E27E363A31A0DE2FC7CAF43E97
-:10C8000099762E395DF4373D8DDF57ACAD9CD91646
-:10C810000B7899F2657F7908D29A34FDFDC5A9AEEF
-:10C820002E7AD27C5AAEFEFB8DAC830E886B4BF415
-:10C8300071E6D323FC9F87706CE0AB8BA345BC648F
-:10C84000112B0ABF6FF01DD1F67CEDE7A673307E89
-:10C85000C918FF57488FE5DFFEC31CDAD729ECCD96
-:10C860007130BF867F97C99EFCA80566528071D53E
-:10C8700016E60583FF24D815983FD5E2A6F434D8F0
-:10C8800001987EDA5248E5675B3C949F35C667198C
-:10C8900003FDCE6BFF4C417DB4568BC7167068719B
-:10C8A000856B45FCC40AFBF2E318BFB08202DE19B7
-:10C8B0002CF68E2908FE9D3DDD473185EF32EE4393
-:10C8C000566C94C8AFB3F0887F0D9279F11BFDD3FD
-:10C8D000514C8CFFCD8944DCA7D7A31D0BACBF22E4
-:10C8E000CE9B340658C0DBFBE1D178A8FFC7960980
-:10C8F00004DF272D5E82EF4F2D3594D68FF1A5539F
-:10C900003DF619BDF3F4ED673E54F0F7B34DF64A2A
-:10C91000E4BFBFCECB8241C0EB662397EF9B41BE05
-:10C92000E3FAAC2C9DB1FD1E86F2D75F80F3BC29E3
-:10C930006EFEE478F83E7DC25C05EBDDF225E8A0F2
-:10C94000AC213EBC1C5F9F794522FC9C79C549F80F
-:10C95000D0F0542FE875E660F177F0DDB3578EC95B
-:10C96000147F7AFEA281E03B7F3C8AE25323DB2FD7
-:10C970003F909384F6D89F807E78F0B1FC4031F9E7
-:10C98000E3FFF4ECBFA8E171BF7F8AEBBEF03ECAC3
-:10C99000A9FFCBE514D89B27B7A21C4B4BA1F77B73
-:10C9A00006E3D5585334EAB10693585F206730FF49
-:10C9B000A728BE0FAEF8796A15AE171C0FE3BDCCE1
-:10C9C000E2F760407F1FFC10FA3BB8D54DEFFD7CCD
-:10C9D000BAEFB16C1C7F6FF7C2F7B742FF6782FCFA
-:10C9E000F7609C61DD675F4479BADB467ECBB512A8
-:10C9F000C085FA744F0AE50B2525AA999C19411E9A
-:10CA00008722A90ABE7FB6ECB92D29C85F784F1DD1
-:10CA1000E3EA5FDA184D72EA25A3E78366EC6F3B21
-:10CA2000EFEFC987EEFDA807D307EBCBEE4539370B
-:10CA300086C7312EF8C9D2226C0FFA9A7EDFF3D363
-:10CA4000CF4B21F48394761E5A8D714C63B67D686A
-:10CA5000488174EC6EA915D3E2F469C7D07F70D712
-:10CA60001895DA8F7B264BC6D8F4A294E0FBD7F357
-:10CA7000B8119D7E2FE9FCAC0AB7999A9E2F92BA05
-:10CA80004F77E1BE38E37819BFDFC5DFAF3ED03B5B
-:10CA9000F39DDB18CE032C08847BAE89E22E583040
-:10CAA000D085743EE32FF4D0BB2ABEC016E4AF336A
-:10CAB000FE44BA5F78D01088C1DFE314F880FFBE6F
-:10CAC000A1E777BF1583F114B1FB8D0C7F2F76FDA5
-:10CAD000D88129141F92AED27E3C7DC70D35889F28
-:10CAE00086FD07BAA89F65160FFA63971CF89CEE9F
-:10CAF000BDB0A93C0EF5CC7E9E7FA0DA4BEF9D2FFA
-:10CB0000E9FA33CFF7F928EF930359747F623EB700
-:10CB1000771E13FA8CF58F66E1EF2169F47A008AAB
-:10CB2000B17C73562019DFBDD2F420E8AF8770FDC9
-:10CB3000A1DB91DA3B66F27BF257A8BF4C421F693A
-:10CB4000FD3D66E2EFF4A218C1DF8BB3CDC4F5EE74
-:10CB50001E9037C82F9ADE857177E0BA3589FB328F
-:10CB6000A9A064C7C27C521F3373F97D85E347DEF9
-:10CB700067D5EC90D9F1AD746FF5D354FFCF701C2D
-:10CB8000EDFE2A533CF4AEE0EF53BD4F8F49E0EF8A
-:10CB900075E01C402FFE02F30D32D85139617694B6
-:10CBA000E5CAF4E2DF52BD07709C2BAD1F29872731
-:10CBB0000AF857D80D8487158F9AC91F3651DC4360
-:10CBC0009D78FE7834CA93157F2E23B9D2CAD8B087
-:10CBD000F879B985C779FF1BFA1120BDF68B7E99CC
-:10CBE000F623470CCB8E827E2510C87F38D01A5B87
-:10CBF0004E792F92FBBA2F0CC3EE17B514E8F52E21
-:10CC0000C9E92FF5FE87EBBF74D0EFCD64B6B82B22
-:10CC10009AF7D0FB3EFAF96BEF6CC1FCFA51BFAF4B
-:10CC2000F8CC40FCBBE2B332929BBD57385FABCB34
-:10CC30007B12E18C9C0FC0FF29D22712FE417E1F80
-:10CC4000B832F8BF2F31FA7D43A0AEC8BFDD2BDE6E
-:10CC500031E85D5A42EF691CC4F748506ECEE0F7E8
-:10CC60008E7AC5FDE4DE0407BDF7F19291E703B7C4
-:10CC70008AF6E27DC8DE5B53F87B1DE6A65F97620D
-:10CC8000FFAD3C3EAED718A4DF53FBFF00D94A30BE
-:10CC900097008000000000001F8B080000000000CB
-:10CCA000000BE57D0B78D4D5B5EFFECF2B33C9242F
-:10CCB000998490072161F220040D3879F10C3040FD
-:10CCC0008268D10610058C71420284BC088FF6C4BC
-:10CCD000969AC100A2C51A8E886851070A14156D6C
-:10CCE000A888A8C13382505A5F69B51E5B2D4D04D8
-:10CCF0009F3C1282F6620FB7BDFBB7F6DE99F90FC3
-:10CD000089DADED3EFBBE7BBF1D3EDFEEFF75A6B69
-:10CD1000AFB5F65A7BED69FFD12097D7C998D13AC4
-:10CD200037E7743E63EFF90C5E7334632D9AFF5658
-:10CD3000630163DE0B16B63B8DB12D31FEE4E53C9D
-:10CD4000BF65D95554FF3DC666B6E5E0BB3B2996A5
-:10CD5000A707FF66BCBDD4CEF3B93CCFD39734361A
-:10CD60009FCA67BB9362787E6178D468760DCFEFF7
-:10CD7000F0EDDE1A87EFD9D4CF10236BA47A69A225
-:10CD80009F3F9A45BB3F30FE97C4D8A366E6B5C522
-:10CD90003236DEB568B8AB9031CF8D1126168D4294
-:10CDA0007792C6E7F348D57076AFC6B3AD0F3116AC
-:10CDB000CFD87C2BA33F351E2A5AC730364F7C660E
-:10CDC0000B16EFB679F87CE655DBBAB4D17C1DD5ED
-:10CDD00077453AF978F33C467F5814AF705389BBD6
-:10CDE000335BD4FD7B3AC675D3B8AC6A10CFF0D4B0
-:10CDF000E4AF647CDC977BACEC5E0E97BFE36F4ADC
-:10CE000020E510636C30639FDAC4F8F56D531F386A
-:10CE1000ADFAE3FF565BEC1BB56894A7FA181F7FC9
-:10CE2000FF104F01FA5F7EE8BA074E5B03F5AA16C2
-:10CE30009764314360DCD07142C76B01DEF878C380
-:10CE40008047DEA485171880BF369B0FF863A69E27
-:10CE50003F2CE5F996F957B9EEE5D99973AC6E8D8B
-:10CE6000E3A1F740982F4CC3F77037D6D57238D26C
-:10CE700067E0F9DB3501FF168DD177EF7EB36F37B1
-:10CE8000FF5667F13DB187B7AB7B79A48B8FCC0E92
-:10CE90005AF87F50FE6284288F72A7AD2F40790226
-:10CEA000E1F725B3339ACA7F6D64541EEECF8AE151
-:10CEB000F06E4AF4CC71F1790F09E3F8B7A35FF192
-:10CEC000FDA4A4BF93BC5BE0D7DB1849FD3299F702
-:10CED000FC7090EF5E5A8F3B6931F2ABAEA6F578ED
-:10CEE000300F3E2FD6A0D17A4F3A7CF764F1F293FF
-:10CEF000ED83691E71921E4E96FEE58DB1BCDEC9B2
-:10CF0000434617FAFCA0C9E8B744A15CE0439B6321
-:10CF1000CDDAC6DB9D7A31D215C6CBCBEEAF7D1D07
-:10CF2000DFCBEEAA9F4569CD9A1B19AFDF79D7FBFE
-:10CF3000A99E9C2BF15156C75B05E1F14E97BB1E94
-:10CF4000F87DC4E569C47A97E7742E619CAECE5B28
-:10CF50003A1E6346C6DE1DEA5985EFDD2F7CB20717
-:10CF6000DF399EB24A47F16598389D807E3B471372
-:10CF70005D2F97F49B9EEBB903FD713896B30CC6F9
-:10CF800022723A2C98075B33F85BD1C9E7EDBB0FEF
-:10CF90006A7C9CDAF0F6064A8DBED1E8E78CE68F13
-:10CFA000D232088E1EECBFB30E7F14F0E131F03C9C
-:10CFB000C74FED5EFDBAF067E2F3AAC5FFF076B5A4
-:10CFC0006D46B70DFB87F92C987F2DB304EAA7892E
-:10CFD0007D083AE0FDECA4FD6AFFA0FC871C0F353C
-:10CFE0004F8CCCBB97E3A736E6D04F26523DDE4EA2
-:10CFF000ED17E39579B59E2BE723D67756EE83B3ED
-:10D00000FC8B19F4B32F4CD03F13F471FE892449E3
-:10D010003F826ECF3F31C287F9C4CB7D735EF31A76
-:10D02000C2D1EE47CCB59BCF8BB9DAC6CC1E85D921
-:10D03000B78D9913C9D856C9D76A07B58D01BF52A4
-:10D04000FC8B59DB46CFE6E52CBB6DF49C5101FE11
-:10D05000C74ADBB2E8BBAF2D0BED0F1A5835E0A97C
-:10D06000E653F354F20E828755ECD79AA7AE26F812
-:10D07000A8715AC047C08FC12FA2AE5CF7CB2E4D0E
-:10D08000ECFFC83109E06B03E13F3B71500E58C91A
-:10D09000F90596DBDDBCDF11DB2CBA7E54BD913E79
-:10D0A000FDF75FA17F4E6FC342F039C4D8F34A1831
-:10D0B0009F2FFB198713BB72BC3765BB279FECC33F
-:10D0C0009F51E09331A7A21B27C149E0E90F1685C4
-:10D0D000A7D5C99C5FD70226E901781DCCF524436A
-:10D0E000AE9C471EF22686E779DA20E1AFF20AEE1F
-:10D0F000A1F477D71F962477F2F6FFE532D0BC4231
-:10D10000E1BA96C30FE52D66767B296FFF79F38927
-:10D110008CD3E6C07A3E6E76BBB9A8E9CB2FD99600
-:10D120006BC5BE5BBA3DD7BA2808EE2D7BF34F38EE
-:10D13000395ECFEE356124D662F2FD64421CBE1B1F
-:10D14000DBBC8CCAAD6E5EFFACFDC89BA8B7647B30
-:10D150004C9ED11968BF745B89BB2A08FE57EFD576
-:10D16000E363549B3E7FCD217DDE9CCB881EFED1A8
-:10D1700076B97E7D3EFF843EFFC93BAB6FC63678F5
-:10D180007E9CD8379FFA227D560ED7EAF7679C809F
-:10D190001CFDF4E0F351C057ED9FAA8E2733AC433A
-:10D1A0004FA71C8F9A89AFD7BB47237A59E60BDD6F
-:10D1B000BF926F5CB1AFD712BEB0B382E92614BF85
-:10D1C0006758DBCD6E4E5F754D6F67408FA99EC56A
-:10D1D0000919F2BB6DB385D9AF1C6F20FEC1EC6E8F
-:10D1E00027E3F457314E944D689ACE4EF1FED8A6FF
-:10D1F000DFCEC07EADF8B146FA46C5B3235E05DD8D
-:10D2000074ED5F703DA537CF24385432B705FC70FC
-:10D2100069BBE68FE479C738E7A14EDE6EB14F7384
-:10D2200061DE8BD68505F819FFB76A53C83CB60492
-:10D2300095F3F92F3DF4CA571AEFBF7ABBBEDD3222
-:10D240000E2FC88F9A5D7F0F0BFECE152182D784DB
-:10D25000F61D46AC7BB19CBF927FCC3B99617D13A0
-:10D260004413761AFFE172C332CC539C5B1890834F
-:10D2700013B688F69CF15560DDF5768B13EBAEB7EF
-:10D28000327F049FCF89488BDBC1BF5FDC1649FA30
-:10D29000C39230E6B5E651CA6C7968E78A46BB8F1F
-:10D2A000DF32929E54CF790FF5F3B8E66B413F46DB
-:10D2B0004DE47F26F2CB989FD603BA7107AFD3A770
-:10D2C000CFB3D641A497D499FCAF002E35AC93E0F0
-:10D2D000CD383EDD0A8E1C6E757C9DEFC542FFD2B7
-:10D2E000B75FCEDAA8FEF2437F0F0BFECEF54C6699
-:10D2F000E5F5B787F394E6EF23381A2DCC6DE0F30C
-:10D3000034DE19EEF3921E521A0E3A354B7D79CB6C
-:10D310003DEE2CCC7BBDE6CE72808F6DB6B9C0C71A
-:10D3200016EE1072684B0CD75FE3486FA6F60BA1A0
-:10D330004F414F5920F8DD9698363FF8FE9607D3B7
-:10D34000843EF53723C1A5E73E9B6FA7067D5AE8CB
-:10D350003D5B368FA0F6E097A44FDD1729DACF1694
-:10D3600070DD32D8E1F3F2FC1F31C524E8D9EE2C90
-:10D370002BB5E37A5A5A404E297DFA67C33C7701B0
-:10D38000DF6ABD4AFF66D5DF4EDFDC2DE567CF667D
-:10D390003E4FDEFF69ADF4B821481F7E2057F0FFF5
-:10D3A00031D3DC7B643D17EA551966DF3B85CFB787
-:10D3B0006AABC1D99216803B73BBB300E7D39B6DB8
-:10D3C00079A0B331D3189D274EE60A7E1E51C0DCEA
-:10D3D0003E9E6E97FD6ECF35E8D2C4704E7FBC9FE7
-:10D3E000D3257E33F01B59506A813CE4329CF87996
-:10D3F000E83AF6E60AB9596529FDCDA47EE6D34799
-:10D4000007C5426F39BD42DB29E625F03CE6DF6DFA
-:10D41000AE165AB7989F823BA79B4292F7926FC570
-:10D42000F4D189EF091B47ED66A54F03FF9A8E4E95
-:10D43000089E5BEE1B45785C28F1CCEEB3493A615F
-:10D44000ECAF282F7152F9379DB7D43A391D5039B6
-:10D45000C7B71FF80E3D6F297C3393AFB0347260AD
-:10D460007C2F1A173346E3A04E36316F18870B64B2
-:10D470001EC1E51E93EF2E3E9FA12601FF1493A02F
-:10D480002FCE9DBDE17954DF6DE1F98A07963237E1
-:10D49000AF5F91CC5C9AA8CFA2519F7763E42964D7
-:10D4A00006DA55448B7E2B1298EF2EA9F7835F6521
-:10D4B000224DA77EDD8658D13E2A8FDA7B0DA2BD94
-:10D4C000DBC4D3611962BFF4AC0FA3FD5371774A7B
-:10D4D00016E860D6343D1DE4E709BA51E9E3794E18
-:10D4E00029675C89D8DF8BD68D24B9D1622BAD7FBB
-:10D4F0000EF87A3A82F4C18A0DB7DD5088F93D33CF
-:10D50000081A0EFBFCC6FD63406F8BD62DF8DEEFCC
-:10D51000711ED96BA3EFED799EF3B9D0B73567F9DA
-:10D5200073FCC3A279472D89BCBDA76DF6B91779E5
-:10D530007AA377FF9BD00B6EBCC948F56F646D7FF3
-:10D54000F923F8C23A31CE0DDE0BA644DEDF0D45DD
-:10D550001A437997CD91BA82CFBF42E2EFAF721FE3
-:10D56000B4D8D8FC5FDA31AF94AC74FEFD0668AA7B
-:10D57000FDE881E3F2A49E3855DB0EBD67D874B197
-:10D58000BF547DF4837E27031EBC9E59C245E539F6
-:10D590005CA97ED5C6B0AE8C28A466FF089E2E2E50
-:10D5A0009866CBE3F566A5B3193837F5DC61643BC3
-:10D5B00069BE3D15B4EF23B39CD8F71EC6FCC4F773
-:10D5C0007C2389EEBBA6F674DDCDF35D3B46B85AED
-:10D5D00088AF8BF3FB620723F9DE3555F035C55F65
-:10D5E0004E3A3A23895EE579BE5292C6474DD3B78B
-:10D5F0008EE5F52BED962EC883C50FCE8D72F27990
-:10D60000566EE1E7792EC7D826FD799E9FB733F293
-:10D61000065F792E0F3D7F83664047559B34A2C33A
-:10D62000612D2E4B12F131CD81F555D9FD99907FA9
-:10D63000552E9B0BE5679BDD0F9CE6FAE1F9E69919
-:10D6400094B2CB1CEE7C9E5701797CDF8FCDF7B86E
-:10D6500000A78AD60A3A4F46E478883F2D97743758
-:10D660008B835903BF317526611F76E5CAEFB18EF2
-:10D670002C3BD1B38D010E5D664716E6D5B5DE664F
-:10D6800080DC9C7597A06BBECFAC26DEFE1E130B14
-:10D69000C77EFF1BDAF37596AD3595EEE0F9A1561E
-:10D6A000668A8C055DE5125DFFBCC063061C3EFD0D
-:10D6B000111B07BDA072D3669A8FA20B66EA281EC3
-:10D6C000043D6F775A1ECED78A8E7E5E30EDDABC6F
-:10D6D000607AB849233AE0E92B19440F7366113D8B
-:10D6E0004CF367AEE4F32A31D63137EC0C89CC1514
-:10D6F000C6E7DFCB7A489FE8E5FA04E499E2278A97
-:10D700006F703A705BE303F8DDD3CCA7C279F2DE29
-:10D71000662BA54F363B9889C3775F7322E59F69D7
-:10D720007652DAD69C4DDF7FD9ECA2FC81E671946B
-:10D730003FD8ECA6FCA1E69994BED85C4ADF155F01
-:10D74000E270213EA4F88AE2478A9E145F0AA5A3EC
-:10D750007227F606B527BEA7F81DD661C80BF023C1
-:10D7600085DF74ADD49B98063ED6B900FCA2C47880
-:10D77000F6E9E7397C7BABEDAE3027E022F85EAF0F
-:10D78000DD4A723ED5C20EE1FCDFB2C2DD75779094
-:10D790005CBDB55A63A620BABDADD1C64C41747B01
-:10D7A0007B538C2E5FD6F4F6B104DEFFDF533C5E74
-:10D7B000E0E5E49D1F3FFA9FFCFBE3777E3E1CF80B
-:10D7C000E6F3D8FD10C65D13DE378F58E4D79949CC
-:10D7D000CE0C0B17E7A461E1E29C843FE0671113D4
-:10D7E000FBF4F13BFF4AFBBCAB29CC6984FE017C16
-:10D7F00071F87E20F1B5A8298CE058B1FED4D3CFC2
-:10D8000063BFAFB110BF5BB44EEECF8D1CAE417A9B
-:10D81000DB87498CF433CDCD581387DF873FB2F8CF
-:10D82000B9EC671F6A569FC61B6AFCD054C6BF7B03
-:10D8300036FEEA3DE8DB5AD309D28F3D56BBDF887E
-:10D84000F979CD6783FBD39A8E533DD63934E6E31D
-:10D8500008DA8A0C708C28705BC02740DBC0DFA21E
-:10D86000EC230CFB9BB56A8EE17C5D55F27BD546C3
-:10D870008DF40E05FF27F28CB4AF4EE79A08AFD3B4
-:10D88000B0670713032339A5E896F30DB70FFBA381
-:10D8900035D7B224881F2F92DF2BB30D94AAEFA7A0
-:10D8A000F9B6443FD3B0B978BFF766A75B1613BF8C
-:10D8B000735AC00F54FD45D9791BD20BD0CFD43841
-:10D8C00016B42F9FCB33C97939841CB37239C6DBA8
-:10D8D000D50D200F947EF229FE773CCD9FCE5F358B
-:10D8E000CF3CF5CC8BB04BBC1F4678AAB946DA3793
-:10D8F000727C63E6925EE3B66B7C9D0D12FFC54FB2
-:10D90000FD29AA93972F3F20ECA73CED42DAB0A661
-:10D910009AEC650D2EBE4FB00F0E993FEC0CA2CBCA
-:10D92000579F793FAA93CE17DE644322527F32E39A
-:10D9300069C381533318FA633D1B1CF62BDB2DD7CB
-:10D940002ED33953ADA3E4F097F134BE76299EEA85
-:10D950001F5E1FDF9F1D6439337DD8B77FC9CEE0BE
-:10D96000D6D9D596B34D178C7CBECBD7CCFC0474DE
-:10D970001E5AFF93BCC838D00F1BCBC6921DC3C420
-:10D980000CC0F74AAB8043AF6F7834FB1AFBCBF285
-:10D990006DBC1157B57A4DCE68179F6F37ECE7FD18
-:10D9A000D4CFC91772FD1CDF478C9FA5BAF719E9C0
-:10D9B000BCD0BD2F92E8BF61DF03C727F27CC32E26
-:10D9C0000DC3B27AD641706A386064D6607906FBBE
-:10D9D000CEA081E759FB546423E869599BE6DECD6C
-:10D9E000E7D36B75460F0E9A8F2D5FD0536D58DBC2
-:10D9F0001882AB9CFFDF253F53F596B53F6001BE13
-:10DA000078BDF3A4BFFC228291DD8CF5BC89799EA0
-:10DA1000D99EEF827D6F59DBFE0692FFFB221CC36D
-:10DA2000F93A3E97767ED5CFE07CB19F06E70BBDF5
-:10DA3000E38CB4E79E79C6487C08F3C43EFC1C7AAC
-:10DA40006ED03C93E53C93F3857E7304FBB130507C
-:10DA50007F595B575426AFFFC9A1B7291D2EC7595F
-:10DA600066EF180DB9F9C98188993E4A7F3AE325D6
-:10DA70003EDEB9B6A9715AD0BECACB3753BFE7B69E
-:10DA80001B67025ECC3748EAF96DB49E33FB9235D2
-:10DA90003ADF02DE5CCF3F73E0D92803ED5BAF686D
-:10DAA00027F168B00A3B6D588C53EA99D656E81BAB
-:10DAB0000BB97617CDF95DFD810B247F43BFABFA1F
-:10DAC000B4DF9270FEEE21BB06FF33807EEB1D02B9
-:10DAD000E725C69C04EC83F26B9CB7DC0A3EF69A01
-:10DAE00059E061A8F3219CABCADF1A44768B956696
-:10DAF0006702F25FBCCE0F827CDEE5F9727F27768B
-:10DB000016C2CED99526E47ADD467E50E1EB19C2E5
-:10DB1000F1EEE54BAEF31999273FE0279A9F9F4E10
-:10DB2000EB7BA4DAE0B6909FC59F05BBE7490BF3FA
-:10DB300092DFE89736E10F481776FD47A4BFA82E7D
-:10DB4000D69F3508F62F89C7BA39BC3C089F753B6C
-:10DB5000FD59D05FCE5A849D0FE50EA479A25E8B4D
-:10DB6000A41BF4837EBBD21CE749CF7C2E9241DFFD
-:10DB7000373C1F29EC0A3FB7ED0C0B929BD592AEB8
-:10DB8000B8CEE4C5FABDBBC5FC302FE8CFCB2CAD79
-:10DB900059D02FD5B8CBA25A69BCB372BC65E1ADE0
-:10DBA000C23F6111F648D4A7F1CD8CFC283D4F84CB
-:10DBB000919EFA7952C7418CFFF9132319E47857E3
-:10DBC0009A6FC9212AE7FA1BC747CD93617ECCF72C
-:10DBD000B327227D8CD7FFCC2CF4A1CF22E3491FA1
-:10DBE0003A11B9B59CFC32BBC234D8553ED3982506
-:10DBF00011E5BB851FA3A6B989FC0F357CBBB33CDF
-:10DC00004A67B258948F247BCB67BFE6FB54A3EFDF
-:10DC10001BF1DDC35ACB7F807DB73782EC6E9F3F0F
-:10DC2000F95F23FBF35BD4ECD2DB97141DA8F27BE6
-:10DC3000245FBA47C2F1BE7C07E1BF3EA26D6B3ADA
-:10DC4000AD53EC578E073A77F1FD110F7BF7C9B64C
-:10DC500017E2353BE0ECCFFA29E0BE579C6F3EDF80
-:10DC60006726BF4BCDF3916EB2E3DC3DD600795110
-:10DC700063147A708D81838FA7DA9D7BB3A067B719
-:10DC80003C61CB033C38BCE91CD9B3DB28C711E3AA
-:10DC90007EB62745D8F5FD327F7014D9F567C5B239
-:10DCA000DBE7909EB37D34E07A7157840174C1C77D
-:10DCB000716B1C3E353FF8A18067F412D2CBF9FEA0
-:10DCC000237E5927F965FDDD13A327623FBD6564F7
-:10DCD000D00B2E9A5C09E087A1F0FA40F295DA8326
-:10DCE0008F5AE0B7ABE3FBC6C3F74DADF48FD53E1B
-:10DCF000A9915E57BB61E243C407DF34B3E17C1EE8
-:10DD000067DB1E880AC6C771C9CF02ED5D54BF9696
-:10DD1000D717ED5F8BA2F9EC31BB309F503C7EEB07
-:10DD2000F64F1ABF55FB3EFA68E3727DF495EBBEE1
-:10DD3000C83ABEFF3EF8C93E1BD9AF38DE53A177C3
-:10DD40009C31B72DC1BACF3C6D233E732646ECF70C
-:10DD50004F383FF48EC03CBE733FD9377E37974172
-:10DD60001E2CF5E9FB55E3BE26F96FFD205734EC78
-:10DD700064F51C0FE88FE3E5BBD4FE2D33B50F5DD2
-:10DD8000C793685718B43F9F8E207A393344E0E335
-:10DD9000CC332348AE74C5083AE7F34DC579E54C5A
-:10DDA0008C481994114E0735F23C7A666A1B9DBF68
-:10DDB000CF68FB29ED328B76354DD26FCCE92E1131
-:10DDC00074039A843FCCBAA903FA04ECD563F22811
-:10DDD000F587C55E6977067D420E651408F9C53082
-:10DDE0005EBCF47F909ED266015FF6483DAE6EDF6A
-:10DDF000957E38E0B76E9F467E2483EA87CF3A4E01
-:10DE0000D9CB393DD67A35B70DF359B76219F991A7
-:10DE10001A37DF0A7A57EBA835B199380F7569467A
-:10DE20009A4F978DEF1BC02178BC20BD2B32300E4E
-:10DE300073C4939E49CA754C819057C8B7F2FEEAE5
-:10DE4000D6699B689C3475AE14EB5370E260B1C028
-:10DE50005EC6CFFBA27C80F5AB7986AE5FCD6778DE
-:10DE600081B05374A539EF2F02BEDF30BA704EBFB8
-:10DE700078393F3AF66BF4329CDCFAECC67CFE79DA
-:10DE8000A0293EFF2F257FAB855D9ACF336BBBDE8C
-:10DE90001F92BD4B9FBF6A9F3E9F73409F1FDDAE89
-:10DEA000CFBB5ED5E787C871159C70EE758E10E705
-:10DEB0005EA438F73AC3C4B917799C7B91E2DC8B36
-:10DEC000EF38F7228F732FF238F7228F732F529C7F
-:10DED0007BF1BDB240F0EF3A6977041EE097612F05
-:10DEE000D8949F9DF64BF78278E29FCA4FDABD2CFB
-:10DEF00087F27D769DD956B2EB90ED86EB25738740
-:10DF00007A6E282884FFB4634312F066EA247BEE1D
-:10DF1000F217853DB72ECF66879DA173FD271BA005
-:10DF20003E650DF5CC41FD6E73CF1EA203939FF8A5
-:10DF300046E75AE75B5304FEC8DEC1ECB1743EA964
-:10DF400080BC8B1D188FA17E15B649EF4709F5AB34
-:10DF500084FA5342E940F9511E37F72481DF9F7A52
-:10DF6000C2BA09F33F25ED646CBE95F42FA557970F
-:10DF700018ED04A795F7693B21A75615C452FBDE9F
-:10DF8000135CDFEE47DEAAB4F252BED0AB557E93EF
-:10DF900066203F8DC74D7268959C53AAD6D37537BE
-:10DFA0006824D24072FCA2DD40E7828BEF18498FD3
-:10DFB00018B1CDA05BCF485FB88EBEAEDE1B1BE2B2
-:10DFC0000F1CA2AB7FCDA1F4107FE0557A3FD54D59
-:10DFD0006B5FC1F97AEEA67C5DBDAAD289217094EF
-:10DFE000F3967A69CB9A6DA9E03FAB227B69FEABD1
-:10DFF0009EB3D1BD8B2A2E5FDC7CDDD5C870FE5868
-:10E000006D75DF08F855B7996360D7AA94F2873524
-:10E01000E9E571B589791DB101BAAB7630770C6F3E
-:10E020007F2EB7758F81E3ED9C61FBD62227FC4BD9
-:10E030003B521D9CAE566B6DF1E3797FA7623C3B72
-:10E040000AF87E4E35FB7F52067EB93F83ADE5F57B
-:10E050004E6D7A368AF46E4967A9664738F0BDA3DB
-:10E06000D548E702D8A7600F52F4B0A3755078A640
-:10E070003DB0CE00FE2FD3FA385EE8DE48AFFDC8D3
-:10E08000D055D0E3DAC47AABA76A5ED293E57A566C
-:10E090004AB9C2D6897E56CBFC69795E50EB3B3BD0
-:10E0A000F295D14EF8359B0FA51AC1C70DFBF6248A
-:10E0B00041BF48F0B463FF54EF18FE9F457CDC9AE3
-:10E0C000DF1B19FCC81F6D991E351EFAE7D366D7F2
-:10E0D0002C9EBFBBF567169C0B6A4C3E0BCE9DD5A4
-:10E0E0004FECB0C0FF7FEDDE1DF47DC9DE0A3A6F54
-:10E0F0002F658D748EFCD42CE4B48247F5346DBB4F
-:10E1000083CF3BB350F0D7EA70711FA4C458742C6E
-:10E110000EEBDDABE562BD3795EEB754F0EFEF4A9D
-:10E120003E1CBA3F7A5F9F5B321876A536E1071D29
-:10E13000683FCCF38FA4FD30F7521AA5375DBA9A29
-:10E14000CE55BF67A5A3884FE4849C675F370ABBA1
-:10E1500059BBD807D5167FDC5CEC9397CDB44FEA5A
-:10E160004DB07DE39CCCD8049E96161975F4BABCCC
-:10E17000384247CFF359ACCEAF7C331BA2CBDF3450
-:10E180002B4357FF969BAE0EA1FFBC4039F191097E
-:10E19000BAFB2BF56BBC4E8DEC68D3F4DF79BA86F5
-:10E1A000E8EC7A5DFB7A3627500FE7E05DBF253853
-:10E1B00033D661C179ABDA20EEEBCCF774C9EF9DB1
-:10E1C000F49D2F44B70F8765B8FE53C84533D9E790
-:10E1D000957D7A3EFE3FA33FB9C8112DC78D360A03
-:10E1E000FB8247AF7774D0F993093CD44B7B4F7DCA
-:10E1F000B6B0F7D47B3B2C8D7682BF299983A4A13E
-:10E2000055237B1EAF6F4D8E15F935F87EC01CB0BF
-:10E21000B330D1DF25949F305660BF849637F075B8
-:10E2200043CF6880BD86EC4C333F213B931A47F6C1
-:10E23000AFE874E936BDFDA801769D207C2E2B74D5
-:10E2400012BDD6ECDD7F7C0887CFDCD2985CECA3D6
-:10E25000BAB6D9E68A9C2BE94DF1F98BD506F27B4B
-:10E26000F7BE7E94E8ADB7DA4474FD4D7069700B6B
-:10E27000BB66281D2EE1EBB2F2F1971CD05C3E4D3F
-:10E28000D4037C86803E43E093DC0FDC14BCFAE0D0
-:10E290001752BE14FF5380FB049ACF9FD61F5C42D7
-:10E2A000E0A9C60981171BA787C7128FF32DF09F1E
-:10E2B00025278CCCF72DD6BF14EBC43CF83A318F10
-:10E2C000399784DD44F9136EBE64A27C1FDD94721D
-:10E2D00078E561DFE9F7691F1D958A7D33EF523CD0
-:10E2E000B5FB57D1D337D1919ABFE2DB817D74174B
-:10E2F000C98DE58591711F7356C1FFBF90F882E407
-:10E30000AF03EBA55EC1473D7A3933ECCE7174EFB4
-:10E31000A8D79E4E7A459F1C72E8CB5746A627A0E9
-:10E32000DC23ED768A1F7B643D354E052F770E0288
-:10E330005D0F8D873D76C3BA8CD4CE207DC5B3DE0C
-:10E340001C0F7B61EADA419456D81CF19023156BBF
-:10E350008DA5908F1FDE93103F0EF6F9F5E6B859A4
-:10E36000BCEB0FEF284865A3902FA1F4D4E6B0F9D9
-:10E37000C1766E956E2B147A68FD9DEF915C3B67BC
-:10E38000783D6A3EF6DDFAE7A270F5A676FDDB631E
-:10E390001C5C25B93BC6F35021F95177EC71006E36
-:10E3A0008E1DA361A7FE396C688303FA43CDFA92F0
-:10E3B00004D8C5EAFE76F431C87DCF5A733CF4CF59
-:10E3C000CFDEE1725123B9467AC3A73646E7A54F9F
-:10E3D0007747F8E0BFFF54636EF87796195F19ED41
-:10E3E000D0C9D9F69B318FBD099E9F1716627CDF7D
-:10E3F0009E448CEFF2D2FD4CCFDAE1D1FDD95154DD
-:10E40000BA7C9BD0EBF6283BAEB4F7429F471EFA8E
-:10E410003C1B21F479E4A1CF23853E8FEFC7A41DD7
-:10E420007F584B4F2ECEA3DE692CBB91E4AE3D1B33
-:10E43000FAFA2A2DDC457AA6E64A807D8CBD1323A4
-:10E44000E46D087E553AA987EB5C41743FE59295EF
-:10E4500005DF339BCA6274F9E9D6245DFD12479A41
-:10E46000AEFCDAC491BAF2EB9CB9BAFC77B2C7EB56
-:10E47000EADFE09AAACB7F77DC75BAFAB3DDB37531
-:10E48000F9B93317E8EACF2BADD095DF327F99AEDB
-:10E490007C8167852E7F6BF51DBAFAB735AED595B1
-:10E4A000BB99C304B9D78E731687FBCB3867F17459
-:10E4B000D51BC3EDC1782D9A6E68ECCF4E7F5EEA16
-:10E4C0004313C7BA3F037DA418041DF2D40D15E20F
-:10E4D000B2942BC9CCAF89736E4712E826B45E683C
-:10E4E0007951C4918B4E8EC32507636F35713E52AF
-:10E4F00034F6487E06CF3F336681C84F3CF26C3A13
-:10E50000CF1F3CB8F55613E71F45D71CB988F2D189
-:10E5100063CB457E2E2395E3C898BF2DF4F2751486
-:10E520004D49DFE41276927EEF69AA1470C0FD4671
-:10E53000C001A99FD327D2239C3E91BECAE9B3CA8A
-:10E54000CCD8714E9F484FF0F326BEFF869F37917F
-:10E55000BECECF9B48DFE4E74DA41DFCBC89F47719
-:10E56000CDF3297DA7D943EDDE6DAEA6F4BDE64619
-:10E57000FAFEC7E6264A3F68F6D2F7C431CAAEE0D3
-:10E5800027FB8BF23335C0BF07FBDC21F3D9603F9B
-:10E59000ACF2132ABF604B23EB8CC03EED34C57C3C
-:10E5A0006C0DF8FB06E6B326F671901EB639D19DC8
-:10E5B0003186C61FEA207F8FFC3E4D9B9B02D7DF32
-:10E5C000ADA33D23C7707CCFCBAB5C1FCDF9C79407
-:10E5D000CB8D66D0CBEFE53DD5D0FE2F4B3A891BD6
-:10E5E000EB1E8D7693ADE21EDE64ABB86737D9D4EF
-:10E5F000D9027ED4F22573E21ECD2B9116E24F2D67
-:10E60000F7987CB0536A5F30CA4F8A63946FF9B24F
-:10E6100083EEE54D76B81249DEC87C9FFF1C7F4132
-:10E62000F765943F5BDD9329FEA2733AF480497647
-:10E630008B332CC4FF0EBFF52B91EFAAF9308CA7BA
-:10E64000FCE4BBBE647EC3E8803F7CB2B5230D769C
-:10E650008249ABADAEE0FB3FCAEFAD7DD161843CFA
-:10E6600051F77CD4386ABE9126DE5F5EE01ECF642F
-:10E67000475B2EEE35B4D4DBA9BF04FEDD9247F52F
-:10E68000DC466AD7960B3BF0A43ABB0BF66DE56F00
-:10E690004F90EBE6F5689DC55F78E8BEC12479DF51
-:10E6A00000FD5845B917FD4C8AF32799B0FE468BFB
-:10E6B0000BF6D04735DE3E2FE0FF47FD88A0FD8BEF
-:10E6C00079A2DFCCBFF0F9426F77BB09BE73D5F9F1
-:10E6D000CD29F3523E33EB34B25F1965FEB7A33D4B
-:10E6E000CB81F7D230C79F22689F67A4C0CE315B31
-:10E6F000EAED5F432FABFF7BE8C52DF03D94913DE4
-:10E700002D946E145E149E07A22385F7A0FB5A84F5
-:10E71000E7BEFB57B29F50FA1A88AE143D4DB60AB9
-:10E72000BC03AFB847A3E848FBA26D07ADA3CE4A30
-:10E73000724ED151281D5C4947822E5BBE67A5FEF3
-:10E74000AEA4A300FE018F7F9E8E3A8C90BBFF2863
-:10E75000FDDCDEC36644F3A27BAFF15C86DCA8B8C7
-:10E76000E43C8E7C259B3A0324A5CA1F40F9E02B8C
-:10E77000CB43E94BD57F7180FE3C5FF498A383E8DF
-:10E78000729294817F18A0FE6BF25EFC6B3675DF8F
-:10E79000C36DCFE574305DF2E1552582BE66A619E2
-:10E7A000C99F313D6729E9F7CC2EF46327FF87EC39
-:10E7B0006DD2BF7EBD6C37E372E93A8C33234EAF26
-:10E7C0007F5F2FF5EE9921FEF6EB73AE253DFCFA47
-:10E7D000103DFBBD31528F4E6369E27CBD89F4DF91
-:10E7E00062B91F9325BE339C4656C4E15EC23C26E7
-:10E7F000088157CF5BDCE8EF5AE6A5FC75CC47E90A
-:10E8000077989FF4801BB8C040FEBB8CD1FDD1A38C
-:10E810001137962DE7FD4DCF9F9E89EF75D69E54FB
-:10E820008B01B7033D9F413E34183D7F869E792E74
-:10E83000C53302E7E323C54ED2C38E5833482FC4F5
-:10E840007E3207D92B7FCDE56826977347B99C4563
-:10E850007A8CCBD94C2EEF7EC5E52CF2D767AF650D
-:10E860006837C3A9BFDFA3DA7FC7319D99060D2C96
-:10E87000C7BE33FA85A1B063BD1633A218787B2DCD
-:10E88000666C31D6FB5A4C8241A461164A473D9FC3
-:10E89000D99FDEAAE83530DE0C1A2F14BE0A9EA1DD
-:10E8A0007054F0FD27E039686CE195F0BC0CFD1E5A
-:10E8B000F653EBDB5189E9F033CA78BA08C107EBAC
-:10E8C0009F1F958075D459055C26354DA47472D36D
-:10E8D0007866CA273F9317F0FD0C4B80C139C4CE30
-:10E8E000C64CD328FF3D495BD9099EE198C7D93C66
-:10E8F0007F16D7C8D827DB5BA2703FF3DC334617FF
-:10E90000CE357546E72617ECE4AF19455CD0E5A394
-:10E91000A9F06FB25DFDDF97AEB32AF87909AE3F7B
-:10E92000BBC64DFB8DC13B1B1FD06B8686897BC64A
-:10E93000E45EC81B58CF19132EF8CCD030C11F1578
-:10E94000BE783B2177793F63385F4BBE3F9CCE3525
-:10E9500005C3DC45580F3F2F505C516F7604D92B0F
-:10E960007E23E31227FBAFA6B8BC9938B7F3EFC6F6
-:10E97000F0A89DD8F7BF917189BF18E4B916EDAF23
-:10E980004DCB4B043CA630E157B9CE6A76F9F99CE1
-:10E99000AE1B2BF7E168365AC6F5E8CE1FCA4ED239
-:10E9A0001B6724393499653D043B41F10933D9098A
-:10E9B000FAEEBB250ABF68EF898B46F09592488D29
-:10E9C0000D4A0BC4E784251A9833486FB739C399A9
-:10E9D00033687F4464C7EAF291AE21BAFAD1E3D238
-:10E9E00075E531EEAB74E58366E6E9F2834B27E823
-:10E9F000EA27CC9FA6CB2779AED7D54FAE9EA3CB27
-:10EA00002BBE972C3EB194C685BAF6C39A16E9EA96
-:10EA1000A7796B74E50A0FCCEBEEC88E075F147F05
-:10EA2000191B57EAEAFD344AC49BCCB42F9985FDE3
-:10EA30003EBCF507FA79195FD7287ED429F8AD973F
-:10EA4000FF033A2A49D4F3DFE90EBD5D23B9D1A40F
-:10EA5000CB6FF847F1ECB94A87E7507870BCBBFC44
-:10EA6000A8CFE5B797E74B7E5D69827E01FF45F051
-:10EA7000FCE1BF085E2FFC17C179F82F82EBC37F42
-:10EA8000115C0EFF457079FE093D9E0B3BF4781E2C
-:10EA9000FB9E1ECF8AFE06C2C7F84E3D1D84E26370
-:10EAA000E2A7217421F1309FFFD31F1EE828C2E99D
-:10EAB0007F7A2323FBDC37E1E58510BC4C1AE9693A
-:10EAC000C77E9D3FE862AA0578EAF18CC079F233EF
-:10EAD000692709BDC7E9E5EA00C521FCC048F1374F
-:10EAE000270DAD1AF8B23FC5736C2CAF7F7B4E2358
-:10EAF000D14F222BDDBF84CFA7FC3FC2C88F533E2E
-:10EB00004CC4EBB29C4E8A7350FCAE3C59DC237A69
-:10EB100063AC3CBFB9C47DA28EB1429F8D7439E80D
-:10EB2000DE71458E88E3E0C7AED4F251A09FD76D69
-:10EB300023400F5B84DFA413F1C271817861E89BED
-:10EB4000D0EF52A47ED5F207AB15EB18B18DE9E4F6
-:10EB5000E4489F5577EFF5EABD0E5D7E545BA2AEAB
-:10EB6000FE35879CBAF25C7FB6AE3CFF844B972F94
-:10EB7000EC18A7AB3FF63DB72E3FBE73A6AEFEC462
-:10EB80004F4B75F964D6F330E03B4C13E77D2BE730
-:10EB90004B740FCC29E281CAEF8E1171A0D20EA066
-:10EBA000F469751FDA23E92E544F1F66117A6A4BF8
-:10EBB0001213E730AB3C6F31BDBEEE91F799959ED5
-:10EBC000CABCFAFBCCEA1E739F5E2FF576A51F0721
-:10EBD000DD637607DF632E97F1DBA1F22F6E9CB029
-:10EBE000EF85CE7F9845ACB7E50E0BC58DA879852E
-:10EBF000CE67799EA0DBDDD6FEE377D2C769D47FEE
-:10EC0000516EE99071BCDE6366978FEC28578CE7F4
-:10EC1000EAF4E25CF9238BEB2EE7378F577E8D58B1
-:10EC20004F99C170FBEC1CBA2F36FF9741E3E78D7B
-:10EC300013F41D3F41EB777DE5D1E23E178BB638EB
-:10EC400041BF038F27E0996861EB28CE48DEFBBF08
-:10EC50006D53DB7D23785199A5D54CC60BE63383E4
-:10EC60001E664DE3FA542EEC822F3E62E7FAC6632D
-:10EC70004D26B2F38C1F37AC8C6B627D711CC3F8D0
-:10EC80007903F4019D05E79427C71B699C85E3C4BC
-:10EC9000FA4A8C97FBEEDF93FF8231C9BF19DD87FB
-:10ECA000E987DE880ED53AFE55F7F115DD86C249B3
-:10ECB0009D2F99943B99725E0A7E6A3F28F8A97845
-:10ECC00008E70A73E94E3BC555CCC43D3285BF9772
-:10ECD000C70B7EB409F02814F5C08F06AA5762CC82
-:10ECE00089863DBC9739A31D5F63EFFD17C62910C8
-:10ECF000FC078AAF1A883F5CC1170688B71A883E9E
-:10ED0000E9EF1F88BB0AE20FE25E8FC4872FD34072
-:10ED10007EF4BB23F5FBF8857102BE1EB98FB97C6A
-:10ED2000B5E7EAF90483FDBE65BD51F2092157A19B
-:10ED30006FE0FBE2F566D237182BDD8A38A28FB67A
-:10ED400098E97EEB64B773864BF8E749EF20BF176D
-:10ED50009F5A85572F4FB97CDF093D780A736D8024
-:10ED60003FA372A3BE7CA97DC66790E78B43CEA567
-:10ED70004BE5797569C8B9F4A971521EBB988BF43B
-:10ED800024E9E7AF9675FAE8C897112DED2EB43F48
-:10ED9000794AF7C2145C9CF0D7E407F21C7EE1D9F3
-:10EDA00090D3EB4CFDDED7EB83DF00F711CEE23ED4
-:10EDB0008213FBBD97E2AD7A0FD8849F52F983642A
-:10EDC000FDB3DE8B548EFAE8ED5C6EC768E8217DFA
-:10EDD000FEA3103F54AFDD10350EFDED33537FEA37
-:10EDE000BE45CD5F7DA31D41FE644FA75177BFE5B2
-:10EDF0008AF9AF7D8EEE5FDC1DE379077CFC8CC960
-:10EE00006505FEEEB11F89479CFC2C69B7099D6F13
-:10EE10009FDE59A4093FAC57C4CDF6CED4E81E00FE
-:10EE2000E7830CFB46DD1B98CDFC7148953FC6B3CC
-:10EE3000713CC159F9632AFCE3699EF35A969AC35F
-:10EE40007995CE87D794843B037E9ACE1471EF6771
-:10EE5000207FCDDC4BB9D4DF4D9726523F17C7A595
-:10EE600009BD6BDD7D2B404757ED6566ACB333E4E0
-:10EE7000DEBB4A2B25BFF18E577C5ADE275AAB11D9
-:10EE80009DAFD498BA5F447C5AE52FB6CA7C89C836
-:10EE9000AF5A2FF29D66F1CECC1E696FC03A9162D7
-:10EEA0003D3817EF93F608AC0329D681EFE04BC845
-:10EEB000832F210FBE843CF81252F0257C5FC44A98
-:10EEC00053738DC2AF541CB46FE0572A0ED27BE04F
-:10EED000570ACEC3AF145C1F7EA5E072F89582CBB3
-:10EEE000E1570ACEC3AF145C1F7EA5E03C1B775DE3
-:10EEF000200F3EE69EADCBCFE5FA7771D0BE855FA1
-:10EF000029B87FF89574FD7956E8DADFCA9A74ED6E
-:10EF1000E1570AAE7F7B93A6F33BDD2EDF03A8DC2F
-:10EF20003688E8E3A5D1A5AEF17CBFFE39E26FDFFC
-:10EF300033E31C606C5F06BA5D591FEE12786E9D5C
-:10EF400029F06E6002CF3D0B08CF6B2C225F22EEC2
-:10EF50001FF7E7BF29360BFF0D52F86F90C27F8372
-:10EF600014FE9BE2E1C27F8314FE1B7C87FF06290F
-:10EF7000FC3748E1BF410AFF0D52F86F90C27F8312
-:10EF800076F0DF2085FF06DFE1BF410AFF0DBE9F5F
-:10EF9000841F29E8DD0CE8E999BA731DA743DDB9A0
-:10EFA000CEA1CB434F0FAE0F3D3DB81C7A7A7039DE
-:10EFB000F4F4E03CF4F4E0FAD0D383F3ABC739893E
-:10EFC0005F425F0F6E077D3D383FAAD57B0CB6A32D
-:10EFD0001BB69F7F156967A4F698C659C18A170E9C
-:10EFE00094C1CFD669D3526338A7346B2F9615F3EB
-:10EFF000BC47DEE31BCD7A0CC037F9D939DE3C7E45
-:10F0000046F78E477D9544E5CAAF4B7F1CEFB907A5
-:10F0100018E9FDC764BCA76AEF620E2352553F9002
-:10F02000EFBF5EE8F8AA1EF1CBA079F083612EEE67
-:10F0300099E4AEB1E7E1BEFC1E8326EE9BDE25EE31
-:10F04000FB86D2D56EC997F618F61F09C7FDA10A2F
-:10F05000CD8538862C133B61CE039C1AF3A01FDCB0
-:10F06000373E46AEAB7102EE1FA9792B3B20E7136A
-:10F0700014BF56D4C32C557C9C495F30CB62F077CB
-:10F080008BD00BD00EE7C5ABBD9A7B67107D3F34AC
-:10F090005EC8378F77C5842AFEFDEA7D8D13101771
-:10F0A000372B5CB4FBF9E35104C71BD7693B117FD5
-:10F0B00058B48FB911EFEA93F3BE7A9FC35245E378
-:10F0C0003A289E4EF55BB13D95E2FF2A586731E242
-:10F0D0002B5881C6E01F5570E3EB7B15EBCBE25B51
-:10F0E000C54CFAA788CB099771392A1E272CA6B4DC
-:10F0F0000A724BC5E54C2A8829C1BD38D6CE5C08BA
-:10F1000003BEA1A062FD60DEBFC7E776E15ED1A4C9
-:10F110002F1A8F517E5729E5890CC6D03824D7463F
-:10F1200078357A5FE346EF0E439C13F1BA6BCDF16D
-:10F13000A8BF8FB9A0EE70514371A76A7E39ACC3E6
-:10F1400060D38077767450101D710E7013F09EEBB3
-:10F1500032D3FB1BB34D0E33F846A81CBFF2DE6260
-:10F16000889E1072BFA465CD7BA9C674DC2F31B810
-:10F17000FCE05BCF4590BEA0F49D0A79DFECE2BADB
-:10F1800063836FE1E515FB857EE0D9A611FF53F798
-:10F190004DEA337CA906E80B43768C8E350AF90FCD
-:10F1A000BE78C6FBECCDD8A215EB8F515C44C5FAF6
-:10F1B000C268111725FC1055124E55F25E11CB7125
-:10F1C000C443CFFC90F31DF708BA97184D7185AD75
-:10F1D000429F53F616A50FAAF7632ADEC83F0EBC5E
-:10F1E000573C2ADF65D95841F157A1F77C6AA5BE83
-:10F1F000B76C9D99EE0F2D0BD1076BE57DA1DA1051
-:10F200007DF0DCF8107D509E5FD47DDE8A378ECE97
-:10F21000237DA5D14C7EB9B2B5427F61FB990FF138
-:10F220000C656BA71BF06E48D9736E97D60F9DBC0B
-:10F2300025F598599D3682EB9C4BC994DE7C298933
-:10F24000D25B2E897B94887D011D74BEC0488F7E61
-:10F250005BEA2DF370AF12F188DE30797F9291DE98
-:10F2600094CB1C25E01F57B9B5A350FB66993DEB25
-:10F27000716F73D60E46F1473740BF41FC17F41D3E
-:10F28000D8DD0BD24A280E63A646F12C3714AC9079
-:10F29000F4CDE99D81DEBD927E4B29DF2717249DA9
-:10F2A0007BBC5D26C0FD06AF66C13B7C1E798E55DA
-:10F2B000741C4AEFE511D2FE6417F6A53EFB132637
-:10F2C0008B476DBCD1B7E17E6B396C764398403C7F
-:10F2D0008779648E281FF162F46DEB70A8F9BFB4D2
-:10F2E0004B94190C22DE89EB5BE0ABB7ADCEB52CAD
-:10F2F0000AE22F5F4C9C3663626100EF8B42E2F4BE
-:10F3000056DE333CE1EBE2452B399CB14FCAA33BBF
-:10F31000BFC729945D3B81B98BF999750163EAF107
-:10F320001E3FEE052E94F9D52F8EFBD3463BC187A9
-:10F33000F2D327A4DEE625BE2AF8D6ADE05B46F080
-:10F340002BCFD409C4AF3A67001F11393DF21D021B
-:10F35000299742EC10AB2738C57A43EC11953982D6
-:10F360009F339333F5568A0B76923D4FCDFF43B3CF
-:10F370003E4EB3CF2F3241CA93E67F4D7CC3FFCAC6
-:10F38000F0DC86F56D3588B8F921C65626ED42B415
-:10F39000FF15FF60F21D8900FEB99E467E74CD11F7
-:10F3A0008C7FCF464DC4A90F60BF61D93D0FEF865A
-:10F3B000FDAED9C210E7FA7896A0A3C77F60213DC1
-:10F3C000BCCCD2710CEF642938BEDFF4EF66B2CB4F
-:10F3D00033FF70BCFFB5B0D1E6027FFE6262E92A5E
-:10F3E000CC3B22C745F898C1B719FA3F9952FA7D2C
-:10F3F000C2D7A6571E43DCFEF2F6348A23AD3894FA
-:10F40000BB01EF897C31D1F3C309F0E3DA1D16C8E3
-:10F41000F186753124D7CA13645C27EB213F9582AE
-:10F42000FF031384FDEABA2241C7DDF23C028639AC
-:10F430005B574FDEE30ED927CA2E186A5F087DC7D7
-:10F4400061A0FDA3EC08B01B5882EC8ACA2E61CEE5
-:10F45000FE7001E46899451F7FA8D25795DD4D9E47
-:10F460000717F7C9B19C1909D09B376B0EC8B12A91
-:10F47000BBF396F13C5F75C28C1B986C56AC53BCC9
-:10F48000DF718F78BF6311DFAFE03765F23E56D58D
-:10F49000B6F1B4DFAA7C3CCD1F785FDEBAF968CA4A
-:10F4A0000BA01FBF9BE2F2AB1C6E4B6CD0BEAF6CCF
-:10F4B000D57471FD2A7F6082B0C39571351DF0BB94
-:10F4C0006D759A056FE89471F502F7FB5E9DE0D4C7
-:10F4D000C555F37A74AF61563A3B2EDE4FE2F34ED8
-:10F4E00013E3E505F5BFA855FF3E01AF4F7AD1CB39
-:10F4F0001322097F150EBEEE34A40E9A278703C18E
-:10F50000A9E73EDE9F93C6217C54FA7D669CBBCB67
-:10F51000709F82E7173A7C668CB3689D782FC4B3DE
-:10F52000498CE3D918631905BDC9E4B0A4007E383D
-:10F530002CC7D1FC880F5671B820DE4AC55D86C243
-:10F54000A742CEB7AA3546AF8FB56E36031F0B065E
-:10F5500078AFA047D2EDA2755329DEBCCAE4A678E5
-:10F56000068F84EF472B6CF7C22FB060CB43E63495
-:10F570009CB32708FB738FDC77B3D2FDC3E95DA092
-:10F58000153617E6B9C0D14AEBEB83EF831C1E1A80
-:10F59000DE9F2925F872BAF0E27E5ED5163D3E0365
-:10F5A000F311F0ADDA5241FB6D89C9637104CF6389
-:10F5B000DB2BC3710F6501DFDF78EF88393C14DF87
-:10F5C000F4F183B7A4D23AF93CE91E94CB3903EFA6
-:10F5D000FC703A213A56F4A2E2B2D578D689222EAE
-:10F5E000D33AF19BF6A59BF49A168E5FD8BB07DA47
-:10F5F00097160476F1712D55E2FDB5D07DAAF6A7D8
-:10F60000DA976A9FAAFDFB98B9D49FA805F80C97D2
-:10F61000B78DBFEC074E33E47C174ABC72B8BE1AF4
-:10F620001CC775CD4481D7B274FD7E477FE837652E
-:10F63000A2D8EF65D3FCC31177A9EAAB71CB6245C1
-:10F640003BD03DE82D65A2A1AFFE4AAAAF8F47A9E6
-:10F65000ECE317FBD6C7835FECD748EF5D79DFD1CA
-:10F66000947F833EFBB4D067CFD4ED6E4882DE68D2
-:10F67000F2A506BF8B55E517FC6131D77FC02F96E9
-:10F680004839DD9EE7C99918B47FAB1E783ACB2381
-:10F69000F88B1FFCE583A75FFAFD0467407EAAF99B
-:10F6A0002FDAF85B73853D185E627DF766F7529C32
-:10F6B0005DA5DDE2C4FDE5CA7515C46F59223F574B
-:10F6C00068017C87D241C53A8DDE17AB6C1AE333F3
-:10F6D000FE37F2E5CA4DB3E94D248527F5DE899260
-:10F6E000A76AFEDF95F35F28E978CE44B1FF16568E
-:10F6F000A75996D0BE4FB35482FE65F9822AFDF712
-:10F700003E3CF5F9977336607F206E88CE279BCC00
-:10F71000C2CEB72F92F4D5332B9F7FF3665EEFF303
-:10F72000AD3B52A19FA8792C95F6BCC5D22EB7440B
-:10F73000EAAD1C4F15C1785AFAB8C053E5336FFCD7
-:10F7400009EF7295A54B7E769F88E75FD4B69FF050
-:10F75000B660E366731AAFB762629AEE9E4C652399
-:10F760003FE872782EDCB8C30C3EB062A2805B2802
-:10F77000BD97C9FBBE0AAE903B5A90DF42D507FF4A
-:10F78000DBCFC759BDC21605FBB41AE71149D7959F
-:10F790008D31B118AFB2B1E2273877287E1FBAEFAA
-:10F7A0004ED9C47E58C4FBC3BE3C35D54571CDF09F
-:10F7B0006BF52757374BBCFDD42CDE6F4C8E687B26
-:10F7C0000270485E1EEE027FC8CCEC24BF31E819FF
-:10F7D000F3B618C47B8F99759D17300FAE52D3FDC9
-:10F7E00014A478670A2A763CCFEF3488F8AB74A368
-:10F7F000489F97F0E1E57E94B3B84E7A77AEEFDD9F
-:10F80000A4107AB5B05D1BF1DE8D258EB95A9C012E
-:10F81000FA54FD28FA54F43BD0FA7E21F9C837ADEA
-:10F82000EF549AB44764BB5211A7527EFF0817ECFD
-:10F8300033DFB44E8B7C7FB06FBD9C58C7C5F6B329
-:10F84000DE4C716E1978BD5B4AE2FB596FE83AD520
-:10F850003E5177DAFBFC0BADC2BF704AE3F28BB7C7
-:10F860003BB5C246F7BFD4BA94FDFBDBC621BC3D15
-:10F870003156DA133A23A1479685CBFDEF17797CF1
-:10F880009F1DF45DC97DF55E9BE2CFA71BA55C645F
-:10F890009DF7613FB3A60C7A9FE464EBA948BC973F
-:10F8A000726AAA989F6AB7DA2CE28C59A4C589F7C4
-:10F8B0000FF9F9EA6413FC3EEB12E81C795B53067E
-:10F8C000F185DBBC31C2FE20F5FB25920F46ACAEC4
-:10F8D000D88077BE176F4B73687C9CC576D7C7DB23
-:10F8E000A8FDD52EE883115B665BD249EF15E700D2
-:10F8F000E5275AADB1528A1B039FC4FE32BC920960
-:10F90000B9B3749B3807CC32B08DF0130E6B299DC0
-:10F9100091043EF1B04671E66CBBFE1DABB1F9A59A
-:10F92000E7E9FC17F20EDC6A739B3B017C9CEB1B46
-:10F93000B0372DB69792DE5E2FF9E4C92D5DF41E27
-:10F94000BD82EB15F13F161107DC1369203BDCB7D4
-:10F950008D03AA927E254537CA2FF508FE331E7007
-:10F9600032925C2B3196D17B4A1BB64CA7B46A739A
-:10F97000C956EF28C41F97C64FA0799BC94E56554C
-:10F980003F5DC4EBEE0C8BC1F926D5EC4D0DD64B8B
-:10F99000AB76DC4DF13F9FEEB051FC4FB163767119
-:10F9A0004C1CBD774CF175AA5E6A91E03B35F5D3EE
-:10F9B00075F13B8B799F7867F3CBB608BA1FA6E247
-:10F9C00072EA123C494583457CCE78A788CB49A290
-:10F9D000FACE7EEDE22AFDB859C47904C51BDDB824
-:10F9E00080B7AFAB7F360AFDD43EF8F6188781ECBE
-:10F9F00050C3D17F5FBCD136116F9425CF4BB3621A
-:10FA00004B6F5E00F8FFDA48F01F68BCEA439ACEFD
-:10FA10008F779B2F9AF4568F9F59E047F63818E955
-:10FA2000C59F1A5913F400A5BFA8EFE3255C3E8DCE
-:10FA30006E4D057D2CDBF3502AE4CB6791225FB637
-:10FA4000E796DF805F79768509FDDCC4481FAEF458
-:10FA50000AFD9A55C7AAF7486DE59C8EA6174588FA
-:10FA6000778FB6E9E3CDD53BB79F99C4FB3C883788
-:10FA700002BDBF6FF22F067EDFE7FA2BCEB1A9459C
-:10FA8000823EDF6F35CEA07B437CA3400F79BFF56C
-:10FA9000D948C4432B7DADC4F8811BEFFFAC7C4E2D
-:10FAA000C405E37D7A7A2B54DA411AA41D64E50B70
-:10FAB000E619C971A47FD1973A93DFD21FFE6AA4D9
-:10FAC0007ED5973FB09FCE6D75FB84FE50D7D6454F
-:10FAD000FA83D24754DC61EDBE2ED22754BB860395
-:10FAE000022EF507C4F78A6C83B2A3B8B54C9CA765
-:10FAF00035CA7B5FCC2F5F6B0ACEE795AF05B39F0E
-:10FB0000A0EC233DA40FDE9BFD3B3A87D7AF93FDCE
-:10FB1000F2BC3968BC6A1051A1F89E61477BA7EE20
-:10FB20007C577F2086DAFBEBC33742CEBB1BEC262B
-:10FB3000A42DF57692FBDB1B0DD9B8A7EED6C25DDE
-:10FB4000D0E3DAE5FDADC1B5EFDA603F48623D478D
-:10FB5000F1DEAE3FC5F3C322DE6F025E773106E20F
-:10FB600089BA0F7F928FFE270FEBBC883735CCDA2E
-:10FB70009472F8295A8AE43A723AF341D7838F088B
-:10FB8000FEFCA8996DA4779B4DA50CF67BBFF42FC6
-:10FB90007ABF32D0FBB3ED9AFF67C1FAD521499FF6
-:10FBA000A561C2CFB873B46713E6F15DCD3C2A9767
-:10FBB000EE1D1A87A3FF6EE987547AEA34C99F5372
-:10FBC000E4F9CA3224D10E3A56F7ED34B79BE23D40
-:10FBD000EFCA395209F9FCE31E2BC50B4CEB092780
-:10FBE000BD3565C84C9267EADD7615F77324C7E02A
-:10FBF000C57BF43F6656712FC01AA2DF1A6C743FA2
-:10FC0000596BFFD557E0EBC9C60B47A3715FF6DF11
-:10FC1000347A7FB4BCF7E347DF62380FFB72291EEA
-:10FC20003AC5B307EB39D93BB3CBC351F763479B15
-:10FC3000D525E4050B5E47FB1D5F45C51A02F3EBB6
-:10FC4000EEF998DE75ECEEB192DD765ABB7CE730CA
-:10FC5000643EDD894EBA27CDEBD1FBCFDD7603BD07
-:10FC6000EF36ADFD28BD57384DBD6768D5BF67C8B5
-:10FC70003A52626057265B2A570EE25B04FE264723
-:10FC8000EBCF8BAF15097DF1B522ADDFF7EE55DC7B
-:10FC90008A922B2FDBF7DC26EC52629F2E577EFEDA
-:10FCA0004BE9A44FF4B6677CED3B166F43AFE0FA27
-:10FCB000C2856BDC6F171506E4EA3C0927259F55C2
-:10FCC000DCC23C09AF797683804FC8EFAE28BA0911
-:10FCD000A58B50BC2B7CB21F741C433C16C7E3A8F9
-:10FCE000FB19E1EF24E1EFABD7D7E3D985214677C4
-:10FCF0009727EDFF45FCF96D23A0473C68203D4266
-:10FD0000DD77F4C8F7DAD5BD4796CD881F941BC3BD
-:10FD1000C95EE891EFB4733E700C7C40EDFF613337
-:10FD20003B47418E9EE44774CCAFD3D046DF532788
-:10FD3000A5D37E1DCA3A92E4FD9C42E86FC6C0FB83
-:10FD4000D444F72D9AEFE125B87F39CF4EF7DCBBCD
-:10FD50007D21EF53CB77CCBB99E40FF3D53BE67C09
-:10FD60003FF3765B1688F2BE77CC87333A476DC98E
-:10FD70006559D0BFD4EFFE0CF88EF9B258B29B3E55
-:10FD8000F2886F24E4817ABF7A4A8A2771D2E02B05
-:10FD9000DFAFDEAA952EC0EFC0784789F9762E082E
-:10FDA0007F668F00B71FF69E934D91F46EB7A253F6
-:10FDB00065E71EE6ED7A18705271B57F96F4A6E0FD
-:10FDC000AFE20AE342F0A0E8CE6B6614870B7C201A
-:10FDD000CEA8EFF763D648FEA2E23A5F763991FEED
-:10FDE00038D5933B09FB70058733D9D13BBF87F5E5
-:10FDF0003E7A47A41BF33B297FD722745F154D320F
-:10FE0000287F31C50D944BF956AEE2049AF4710285
-:10FE1000A1EF9C860F2D9D0CB89DD3DE1E838FAF66
-:10FE2000FF6F63BFF74FAE9D24F84466A267C624F8
-:10FE30009273D374FAE4EBB99FA4D0EFCC5C3E3A52
-:10FE400014F2EF9694D2EBD0AF2D53F80FFE9CD462
-:10FE500049711E7F5EF0D714B23FAF11EFB37EDB66
-:10FE6000795E19D72CE861D562712F319935121D51
-:10FE70002706E2656D98C7FFB4B8E640DCF15EFA8C
-:10FE80007D91979BDB324E0FEF07EF61479E75F236
-:10FE9000938DF7F0CBE514F71B7D64551ACF6F3CBB
-:10FEA0007CB49CE27C938F5C4CE3B8B9F7F0AB2256
-:10FEB0007FF5918B880BDE74F898A80FFFC110C6F0
-:10FEC0007E72F878B997E3E38ED19EFB81AF9B2FCA
-:10FED000351E8338FEFDDA398BD328AE75764AB6E7
-:10FEE000886B5D07BCCF8B5FB43E5A0BC4B5EE9BED
-:10FEF00024DA755F10FBA0FB82A0F330F083C1FF12
-:10FF00007CAAE27B151F1E885FAA7DF8AF8A4F5638
-:10FF1000FB99ED716D348318BDFF74DCF093936829
-:10FF20005DFAB8E16E73CF63E457BAC09CE013AFDB
-:10FF300044BEEB84BC682914718D5A4F8713F73186
-:10FF40008A0A44BEE54287137C1E79D8B7BA634457
-:10FF5000BCA38A8B6DB9E04FC23E2942FC22AF5F41
-:10FF6000DCD3530E3E5A84FBBC69E8FFF851391EBE
-:10FF7000437FBB2E88B8C36E5B87D321C7413F7CCC
-:10FF8000DC34F0C7A2D556BA77D472A17105F55307
-:10FF900066EF1B570B19D7FAF5E34ED782C6CDECA7
-:10FFA00015F19D18D7A91BD74F71C1BC3F8A3FEDF2
-:10FFB0008E7125E2DCAFF2C528E7F987E4EF54142F
-:10FFC00039FD46C8011527956091EF71CB730BAFD2
-:10FFD000477199BB7AC53ACF37FB6BB09F8A25DF53
-:10FFE0002EB608B9C90CE12EDCC72E315E3E9E8CC0
-:10FFF000F3C90BE27C521C56BA1DFBB1C124F80DAB
-:020000023000CC
-:100000008B53BF97D6B1ECE7BCDEEFE293E9F7C5BF
-:1000100086261E6499381F2F9F9903B9C1F5EE33C8
-:10002000C0F7EF58AB267E874BB49F3B3382EEA1DF
-:10003000741F1E5188FD3327CCF91CE3FBB677D221
-:1000400057B44FE7443B0B71E2E93DFC5F229FE070
-:100050007C0EFE5D2BFB8AF473E5AFBD25E0AFFDA2
-:100060005F18A77EE6398BD0CF7AE89DE6FF9A2409
-:10007000DEA7E3FA3BE91F3DD7C97737739C852894
-:100080004F35F744016EDD974DE2DD5AD6137553B7
-:10009000907FF6B176F19E6D285D1F9E2CE4C0F234
-:1000A0004C3BBD77D69068B552DA7E6106FD1E8C5A
-:1000B000A93413E703B7A57FBBE32F260B7995B6C9
-:1000C000C112F0BF73F9E10E672AEF65E318DBF1A7
-:1000D000FDF0BEF317448C65B83C8F79131F2F36A3
-:1000E000E9EABB51BFAF9C8967DA54FB9C97ED8F5F
-:1000F000AF33C9F180E725E2FE44A8BC689812DB63
-:10010000F75E21C9DD381BDDBBCA344A7B1EAFEB6D
-:1001100020BBA0F0DF26FF878DE2E876D9041D66BC
-:100120001A44BACB20E37DA5BD4F9D637E3CC53309
-:1001300069CA60EAC74FFD18F7E742AF48626D34FD
-:10014000BED2CF543DAE87D988C9C8DF7B2B321AC7
-:10015000FA85E73B93A7964E2E045D7BD947417203
-:10016000E27C44545330FE1A8C7ABBE73B93A75190
-:100170003BD5BEBE693AFB88E211FD443FF59906C6
-:100180003AB73618D9ABF4BB03AC83FC99AADDBBF4
-:100190009C4F7E44EF36B8297D8FF3CB8FE8BEDFCE
-:1001A0007C4A3F68F6D0F793CDD594763637D2F7B0
-:1001B0000F9B9B28BDF9D6C802D0FFF2436BD947ED
-:1001C00041F2B1BECDEC09BE5FF3EED4FEE9E8FB2F
-:1001D0009385DFE6DDB4FECBEF57E593053EBB1715
-:1001E0000B3D93D3E53A47ECC0FA4277A4B897F0B9
-:1001F000D234717EED4E12F9C6C9E2BD50B7816DA1
-:1002000043FB97A65928FF6EBA81DE7570C78A7EB8
-:10021000DFCD32909E76FD8CA90D80933B9E7FCFE3
-:100220000BE4DFBD4A94BB8788EF6ABEAA7CD294F8
-:100230003E3B4296381F0BFF3BA777EABF0FBFC577
-:10024000627EA1F5D57DFA5078FC56EE5BDA17D0C8
-:10025000DFB10FD282F6458393F685A243457F0D29
-:1002600053C47ECD0C9374CE6517C10F320CE7E3F7
-:10027000041BF907DDF05FF0F5EC92F1EE57EC07A7
-:10028000E90F50FB41ED0345EFC97C9F097F87587B
-:10029000C72463FF76FA87268B7577C447927EDC86
-:1002A000DD6E7640DE4C320ABF4377FBBC02DC0BCE
-:1002B0002FB9DBDED81FFF7A53B6FFA7E1A0F8C144
-:1002C0000070B862FD1669B7FF07D74FFC0D7C7B45
-:1002D000B1B897194AAFED9395DD5DD0ED3B93DD55
-:1002E00007413FDD9ACD84734AB7ADFF7BE42F4DC4
-:1002F00013FB42D14FC31426DFA1E1EBCCB892DF50
-:10030000A9F5F4AD732923BE9729E38D43F1ABD64C
-:1003100015C4F75E9F3C38004FC6B8BEC2FB195AE1
-:1003200067A773AAA2DFF383BF5A02F9357FB253DE
-:10033000F8990C46F91EAC90277DDF3523C55D0585
-:10034000C91906BDA5E7B0F0C7F9F93909FE2CD8DF
-:10035000A083E3AE2D53C4BA7BE7171A602738FF9A
-:1003600017BB1772EBFC909E93D04BCE6F13EF9D93
-:10037000F31E6769B83782F81F277EB745F8418CAE
-:100380000F7F7912FAD092878DA4BF9CC7B199B71D
-:100390005BFEA0F89D3B757FB04EB66BD976F166DB
-:1003A000FA7D334E9FD07F3EB235A4432F9EFEF0A0
-:1003B0008327F0FEFA92E734989BD951D8DD79FE75
-:1003C000E3BD46F13BAB32EE6486BCDF5FB35BDC82
-:1003D000EFAF43BC09F497033BB6E2F727EBF79A7C
-:1003E000998D7F9F8177D2F8384BDB22F94192F7C4
-:1003F000BB451F377A2DF36E803DB97ABBFE7BCDAE
-:100400002E7DBE2EE4DEA23645FE9EC148964BF7F9
-:1004100013B7087BB1E2DB57EABB5E82AF7BA5BABC
-:10042000AFFB05BDEF6D3CFC65EA8776919F2DF330
-:100430005D3C7FEE4B017F05B706C9F3CF25B18246
-:1004400036BEBE86C33607EC000D2F083BC1F9B699
-:100450006882F3F2F04EF22BB0178D0EE861F71CB4
-:1004600032925DA1BEDDF633FC2E6DC3731ABD570B
-:100470005B7F28CC27E0736109CA971EB2399C289C
-:100480007F318CC1FE7C9EE30DF762CFA77412FE14
-:100490008157D825F8DF2CFC7E85C2BFF161E14F82
-:1004A0005EF284C4CFB65526C2AB4F63096957E2EA
-:1004B00049E1F95786A7FAF08476D31FFEFD7189CA
-:1004C0007786789BA3DB2AE9773114BE2D873F4AD4
-:1004D00085DEABF06CE478FEA16AEF94EFE17D0D70
-:1004E0009EAB8167FB3F8EE73F423E1692DEFBF1FB
-:1004F0004FA1F7465AC88FAEEC1ACA6E31B8F6DD76
-:1005000063717CE0E189CF929E5B1E7BA67E052312
-:100510003BDAB5536047BBEE0DFCAC2FFBDDF54F6E
-:10052000E5823E5ACC9DF4BB31DE18F1AE7C77DA21
-:10053000ECEDCFF3F18A63BF4ADD8F7DF37218B91A
-:100540004FE6CA7D893F6BF0BB80ED36B2B7D5B7B9
-:100550008709FBDA01BDFFAC3B49FC4E5F89A5A7CB
-:100560007C05F472DE1FC651E7C1DA76F9FB2FF283
-:10057000FC56ABEC0CFB42DE8772BC41F5EAA68868
-:1005800078DB8C84494EF0A19605CC139EF175FC66
-:100590009E11BF57BF9737A01E3800DF57FA1FF3D1
-:1005A000EAED1C8AFF2C95BF2FD9B73F64BE7AAD08
-:1005B00037CA6A24BAA3771BEA1E15BFAFF809E849
-:1005C0002E2A404F0D323EEDD8F77F63C2EF3475CF
-:1005D000EF12F7233887DC8A7BFA67DB443C5C4DFB
-:1005E00041D718BF13BFD321F8D0B27D9ACF99D687
-:1005F0000F1D31DF06F1AE7D083DEDFBFA770FEF01
-:100600000DF091517FE7F0DC51C2A4DCF2F61B3F04
-:10061000D927BF427EC7E37F5A3C776F0E5FCFD7A3
-:10062000F81BAF4DD4BFE3729D53FF3B4DDFC9D6DE
-:10063000FF4E53AF5DC247EA834A4F3D3445C8F190
-:10064000D054C1F706977E1C752EFEEE38FD78B3A8
-:10065000DDFAF1BE2D5EFE5571ADDF04BFE372DC45
-:100660001372DCDFC871FF5938A974A0F1FE7F4D09
-:10067000FF0F822563C60080000000001F8B08006A
-:1006800000000000000BB55B0B7C94D595BFDF7CB0
-:10069000F3CC7308210904C2242421608803245464
-:1006A0002B94C9D300D6065C2D68840152C83B80C8
-:1006B000B5D2D6FE3208222F5BA8D1A2224E82E10B
-:1006C000A1613B118289863A286411AD1B698BFDBB
-:1006D000FD56DCF828F23213A374E5575DF6FCCF23
-:1006E000FD3E321942B5DDDDE4A737E7BEBE73CF6C
-:1006F000FB9C7BA929CE317C394588DC9873E69E2A
-:1007000008215CAB7A8A12B385E87B43154D0E2134
-:1007100084DB7BBC3E5688DA8EE1625332C1257D94
-:100720006F1A00B78DB36FA2F18DED7F781BE3BD1B
-:1007300007558785C65F6BFF280AFB5CFC325C8827
-:10074000E158F7519420B8FAB2C2F0261A77103C5B
-:10075000AB5515FE4CDACFE83363FC62AA0E7BCDB5
-:1007600082DA929656730FB5557B5B79FC0D9F69C3
-:10077000F0F8DEC641E376CCA7B6CAE88DB2537B6B
-:10078000BE5DDFCFCFF3AB53159717FD7BFF10B7DF
-:100790000CF35ADE895B4AED15FCCCBCB6FDF4D0F7
-:1007A0000B996E5A57D341FB440CEC53D361D26082
-:1007B0008977756A6B510CD14BB428228D9A8B6264
-:1007C000AB584DF4AC6A6FAE16D45F95718F49107B
-:1007D0005D023EB518DFA71F8388A37576FA8BE804
-:1007E00077D1F779D452DAF755DFB1DB5DD4063A29
-:1007F0005F8FC2770307697EE6003ED35D44BF1C6E
-:10080000B4662146D0BA83AF4739687CA3EF7549F7
-:100810006FA39FCFFD9A0607A8653AB7AB7CEE8A17
-:100820002F55A6BFBEDFAD2E95F799D59E168973BD
-:100830009DF4C9EFCD7539647FEAE232E07F226131
-:10084000418E9ACC78BB000726CE69DE44A854F9C5
-:1008500068DFCC6BE9B654DBB7CB24E6FBC0B7D47A
-:10086000035DA3483E4E140F9F4C2357E7DDE33250
-:10087000F0BC22B33B7505CD3B19E188B4D37E0FA4
-:10088000158F8B045F5F438BFEE25D6637B595077E
-:10089000E5F74EDABBA3206F270F4E553DCAC07E49
-:1008A000776ADF15C2C3ED00DF3CCCA7726F63042B
-:1008B000F619E09FEC9FEBB2F3FC13DE77EEBA87FC
-:1008C000CE773223DC09BE749945B98FE5843E8228
-:1008D000EF752636820EFAF7E6821FB42E9061601D
-:1008E000BEF6B69BB479F7348B41F34CCCB78BCFC3
-:1008F0000DC6C7EEFDE097F7D0FCEA675461A1EEA4
-:100900006AD38A389CFF931D83F12BD7E85C6DF284
-:10091000C7C505C96B75C7557D8960F9EED0F5C3AC
-:10092000C1FCD4F978324395782558BC8250AE6E1C
-:100930006D66B92675F3D8A6702BECD4268677277A
-:100940002B74FEC407ACCEB584FF738A366EA03616
-:1009500086608384CDD45AA97DC624FBA1B6583FB6
-:1009600086D8A9106C2A1E976348A17DD4D6C9E009
-:10097000EBAB335D8FBA088FCD334B66CC043EA210
-:100980006F99A06FD65C8AF08868210AD5F79EC05F
-:1009900077FB0F9A04EC478DB5A3F26392D37E27C1
-:1009A000290AE1DDBFC3E4F5B0FCB9229469422C09
-:1009B000BB49EACD270EF734751CCD5F63E0F355D4
-:1009C000B7A85E1BCDEBAD271210C93F6D4DFE01E0
-:1009D000E4B5FAB86AB7D2B9F37DC9BF9A0EB8C503
-:1009E000E4B4D0FA5A1F75125CBB57F13AE4FE0228
-:1009F0007A597313CBBA3863AB4D1159D4AEE9337E
-:100A000063DE99C38A788CE66D0E8B6A02DE3599B7
-:100A1000B3CF2951D4AA5BD627D27ECBB79B3EEC6D
-:100A2000B1CAB557E8BFBACE6D2CB715DEC1FD55BA
-:100A30007B07C335C23800D3FECDF8E36621DA5C0C
-:100A400091B1676EA0BF2788095754D0697A3CF4EA
-:100A5000E104F84AF2241A88D82385B86F92331E2D
-:100A60007ABFD1E8980D3A043A4D76D0ABEEF081DA
-:100A70000AE0EDAD0E731AE8A8B5AB5F61BA06BE29
-:100A800020BADF486D82E0F30784A46FA05DCA79C5
-:100A90009D49F15AB19E68C8FB5915EF1A1A0A7898
-:100AA000FAA3D83E09510CBD58B520C7003B073505
-:100AB0001684CAAF747D506C46251AADD4FFEF1969
-:100AC0007BD4614176E23F5D298C7F8159B87DD42A
-:100AD0007F5FA4331A723FD61A9505BCC65A93BCE1
-:100AE000A0FB5863DF1A7C7FF328C5F1106D7D24CD
-:100AF000EBE5C90AE0DA0827E44449586C043D36BE
-:100B00008F5A6C84BC8FB5FB324A3207E0028C43AB
-:100B10001F8497BF5714E136E23BCF8D54FC06DAB1
-:100B20003F6023FCA02746BB09F8054C121662CD96
-:100B300020FCC82231FCFF8E9F9DF08B18C08FF8DF
-:100B40001D8DF59F67137DA84D9A2B4437DB8515C6
-:100B50006C17747A5E24792F205EA529526EAA77CD
-:100B60001C29C2788DE85E8F754551F21C45380FFF
-:100B7000E030D9AAB9925FB95A7B7FAEF42FBAFDA3
-:100B8000ECC8751973A9DD9E5B62465BA866C6F763
-:100B90000C61EF5729569693CF49FF608FEF5DA107
-:100BA000D8533306E45BD7AB3AD975557FAA7EBFDD
-:100BB000CB2C52F0395777068D970BA9D78B56DB84
-:100BC000ECA9C17A043D237A94DB2B6E13A46FEE5B
-:100BD000D571F6D4A9D4AF5E340BC89EA65FB1F42C
-:100BE0007B256508FDF285E865FB60D86F9372EEA2
-:100BF0008F54BC6B09FFD4DCC17A97A4E941A35B95
-:100C0000E1F3357E6564D853AA7841F33BA9737547
-:100C10008C7638CC2BCFF5C23FDE496029FA1B62B7
-:100C2000594F7990ECD7BF68E7BCD3E83F02FB711E
-:100C3000CCE44BB6D3D0B11AAB13FB2F1014E89011
-:100C40005D2B15DDDC9E0AAF6DF3F3E69E3190AFB0
-:100C500077DD1627E2B0C6754D91B0E359629DFD70
-:100C60004C06820AB1F7CAD4EBC7332438E28CCEE3
-:100C70001738628A53C06F9DAFDB735D79B939D77E
-:100C80005F5FF5A7B6DBBF03FB757FB3395E8A49AB
-:100C900077C6B401BEE97CAD131EC65BE7D755FE2F
-:100CA00011EEA3410FF5E25CB633CFAA82E30A8DC1
-:100CB0007F56FA1D8A7F3A7D676A7C58DE21ED51A6
-:100CC000285F757AFF9036C4F7C98FEE607E080BF7
-:100CD000DBBF50BE7F135F28C22CC5507EAC458061
-:100CE0009F8906691F1397919C10DEF708F7E11E94
-:100CF0006AEF0A7FCBC472A8F1E75EF087A6BE2B2D
-:100D0000BCDFCF48FEBFE34F476EC903C17A18AAC4
-:100D100077D7D3B36A87F3DF75BF479686F42B4442
-:100D20003F43F44FE7977B7514EBD9553EAA2D52FC
-:100D30005F357E45D0EF90FA863FE87B35ED8AD768
-:100D40009FFC2DF44F21C4896F8F85E89DCE9FEBCA
-:100D5000D91DDD4E9D16FE63763AFFA9141907785A
-:100D60007E62F136034E3794C3EE9D9A28DB039AD8
-:100D70007D0B6D4F539CA3901FDB94717204FCF5A7
-:100D800029B3BE8FCDDB4CF89F5ED33D6625AD3FCA
-:100D90009D2BDB53880B836057985804BB7E7AA445
-:100DA000C5033A9D5626E4C13F9C561EB85DC2F16C
-:100DB0006607E005F17976824F99E47CDDAFE8F6CD
-:100DC000FFF482EF14F03C451C053D1C8A28E1EF3E
-:100DD000284A4C31E173FAFEB4296BC5C0F99B7205
-:100DE0000DBCCEABD96FC283E9DEF753C5DB445DE2
-:100DF0008BE05208FFE4BCDF14A750FFFB3F1B371A
-:100E000019FC75AD1AFC7DF8EBE41B016FE37DBEA8
-:100E1000F7659F6971905FBAEA270B3E93FD6539CC
-:100E200006E84BB9C64357CC8468F0A7DF3B2E1ABF
-:100E30007E47F743FDC70F44B883F8768EFC9418BD
-:100E40001F044F783429D88F1DD9BD391DFB949BC1
-:100E50003D594EEA3FDBF87412E28DF2DD8FA47348
-:100E60001CBC7B633AF299F2A6CDE92E86C3DD9CC9
-:100E70004F19E5B92FECBF79D7A6A0B8BB2A5F659B
-:100E8000FC4BAD470AE16F67DFF0E9C3769A97F64E
-:100E900033C50EF1BA57743F0CFFB810F131F2B7F9
-:100EA000062BDB73DACF05FE374FF8FE73D0E31362
-:100EB000191F99CA68DEE55C23D367A1F06E89A784
-:100EC00071B141B1378BE0F9631A317FF13AC59CBA
-:100ED000003BB062D864D58175C3188F251B267777
-:100EE000A17FE183B27FB6C57BF024F6F98DD9D915
-:100EF000EC607B9352326900FFCBB9665EB7688BBA
-:100F0000C2F1BFFE9DB427E21A83CF7959E3BFF83F
-:100F1000CAA2802F3FD0F872DB83EF1C4DA07DED7D
-:100F2000B1EE2BB01B6F3F7E26D54FFD0531E7326A
-:100F300021E76966F75315387793C5897364672588
-:100F4000AAF1347FCA8F731F43BBE8C1C54F55C098
-:100F5000DE6EB772DEA6E3B74A711A608F5F6FFC70
-:100F6000E112D0EDECE3568EDB57358E8F1743E858
-:100F7000A9DEEE21FE3B28D1D9576FE5F6857ABB75
-:100F800070903CECAF4F60F8B7F50E6EC57C295FF2
-:100F9000ABB4FCF87AFB4DFD325C38289ECDDE60A8
-:100FA000130EB2534971AE517974CEB489354D1BCD
-:100FB000B573A5D1FAC99EE47CD0217BE3CA2E8407
-:100FC000BCE63C998FBD797243128CF2F2073FD890
-:100FD0005941E373F34AC6E551BF75C7675C57785B
-:100FE000BDE39185A0777993459E4F3BF7D9C7D351
-:100FF000E39FA2FD3D6F9838DFAFDBF1C1CE8DD40A
-:101000002EDDB2D21C2CEFDFF6BCC91A3EDFA4578E
-:10101000D7A3C33FAE579B93587F9A48AF32FF790F
-:10102000BDAA7B700DD3EF81BC92D9A0FB59932749
-:1010300009FA7476C20C9673CF6185E9AFDB717DD6
-:101040007DB176DE2A836FCBF4E4013B7E496433C5
-:101050007D8F747C928EB8F752FB82BF7BEE437417
-:101060006E3F9DBB9DE8EB1F7FEDF834B37B9C93F7
-:10107000CE37CD20E3DD6BE2D63C83562FE83697A2
-:10108000444A9A2BA8CB68FE93FC98279AF0A9EEC5
-:1010900054FC6159F067B79E3322DFA3BCF1C3E073
-:1010A00038827E3E0CF2DBD7C3F79BDA5AEC9336DC
-:1010B0006077BFF36783F007F9E99B7BC2843FE861
-:1010C000BB57F313EA33139F7A3B46B25D00DF8CC4
-:1010D000A8C7754C68027CCE2CF9D87B88E22659CB
-:1010E000C711EAB481739EEBB890053B1B7ADEDA38
-:1010F000972FB07C54B73FF299C2E79F75CE98F511
-:10110000CDE73FB2FB4216F877CED4330DF956AF98
-:10111000B9270B7CA87D45DAF37F940E7A7FC5064C
-:101120003A08E979AD62653929542F72DDA0F7B824
-:10113000AC1BD476EC627BDADF29EB377586EEA246
-:1011400078D43B567CD0057BD69F20F328DADF0588
-:10115000BA4D1FA7F941635FD25CB26B2F5E950752
-:1011600099FF9D85FE8EC73EBE6AD80191152E104F
-:10117000579C873E53FFC2D5C9EB21E767BD23A625
-:10118000C03EBE99F5B75AAEF7BD1A6E5739EEA1FB
-:10119000DE20FE5D3D875715AE41F58070E10A9A6D
-:1011A000576776FC80E3E313AA405C573751EA9314
-:1011B0007859EA53CDBA23E684A0FD76429F186F92
-:1011C000192FCE7EF56FAC975B66BA3AA197E1B066
-:1011D00085D82F21DAAB28DA3CE27FAD864344A7DD
-:1011E00096F717AB3C5ED7AE8A91589310E94DA3A2
-:1011F00073148BAD46C4D3B3856F3AEA36C2D8F3C5
-:10120000CB5B687CCEABEAD44D82F3A745259C57D7
-:10121000BA5357213E32281A5D7DD97383FD599EFA
-:10122000F453D35585FD58DFC8708E5366CDAF2972
-:1012300005BEFABCAC61721EEDC37196F0F665CDC9
-:10124000857EFAFBB2E6450ECCBBEBD5F015EC176C
-:10125000852FFBAEA0EF84E5CBFAE8E7E447202733
-:10126000759764BDA350FDEA09C4E7AB0E93BC209B
-:101270003E3424BF6B801D273A83AF1788AF2EF80A
-:101280001FB770B9A03F934678A13F75FB15614425
-:101290009DA8C3D2843A52ADA9270EF2BCB1FD4F2E
-:1012A00066C8735DDB3B66C724AC9775275248B6AA
-:1012B000E3759AFFAA691FFF2EEA7C35C7A517AD13
-:1012C00031BEC3F97BD5C156CED3AB859FF3F4EACB
-:1012D00096C1F2D29FE0E0BA48A87E84E53B06E9D9
-:1012E000C5ACED522FEE52C50AD839A1D569672594
-:1012F000C4733C32B04EC6BB2EF5C2C3885F022910
-:101300008A53A1AD02619E75888B3CE9329E09FC2F
-:10131000EE85EC656C57BCD977D0B9025ABC3B6BF3
-:10132000C336A31A84CFAC4E59970C8489F243CCB0
-:101330006FF768F041B84A22F27358AFB2605703B2
-:101340000659470D3D47BD562F3A817A52E600DED9
-:10135000731213A51D135E969F2E83FCBECB40E334
-:101360005306D62FC997EB07F2215907BB9E5DD9CB
-:101370004DFC2923FEEC253EA37D9EFC7119D999D5
-:1013800016F2C780FF95FC315A5F7D06F7BF58EF14
-:1013900064F860FD4D0C1FAA7731DC5E5FCCEDCBAD
-:1013A000F525DC7F02A87E17FF7BBA11F2D0051D60
-:1013B0001B35009F8A0981470D9E7F2A46190C8F95
-:1013C00052787E76FED38D1ED48B66DA35FD764458
-:1013D00022FE3A6B9375A8B33659876A1DE5BE2580
-:1013E0009FC6CB66ADDD2DF350573AE615C42CE011
-:1013F000FCB59FF257D8A395F9EE3CF0E5F8F1FC67
-:10140000D46D6C276D5C073D75F70DD15C077C834F
-:10141000F271FA746EC6D475D904E746282CBF64FD
-:101420002F6E2CD1F34ADA27BF53DEA314AAD56559
-:10143000D87FD548DB54D8DFCF5DEEDB80874EEF19
-:10144000A251CB53110F75991CEFA28EEBF9BD4938
-:10145000209FD2EB7DFABC0E57EEDD58372B63DCB4
-:10146000BA29B03BA464B0732EB368015E2E43B8B2
-:10147000B296ED96C3083B70B726C7790E1917FBD5
-:10148000CD0E630CEA3761B9B11E5AD7A5F1F9B890
-:10149000C6E7131A9FDF429D8CDAB7A91F6D37F597
-:1014A000A39D01FA4A7965BA3D915752C6F22BFACB
-:1014B0009200EB75C1D9D02F696F9220D75B34F9B8
-:1014C0004DD0EC4D576E49955CE7E37DAAB47ADBCD
-:1014D00005ED1E443FAFBE6E60BDE076DE8DC2639B
-:1014E000859D7F49E69D6234C52304CF7B299EED0F
-:1014F000906ABD23F363D2F37953651E200E58E43E
-:10150000BC04470EF464AD566FEDF51A3C26D4A723
-:1015100063BAD363E07F35FDD2E143FFADB2BDAE28
-:10152000994230B5AF28F27C35F3BAD38761BD62FA
-:1015300033707DBB498E9FD4F4AF2645DB4F3B8F84
-:10154000B0FA92C08FC0E197929610BC29C2BF4CEE
-:10155000DA7D7F3ADB6BE14F9F07BBA8F8DE174EC1
-:101560008A2B0BA62E318E043D7C3B015717E42CB1
-:1015700031DE8CF1D6F7EDC1E3237C498A1D70B6CC
-:101580001C1FD1BA7398330836BDF83EC6CD869C71
-:10159000250504CFB1788FD7436E7E2BE5CBB6BF40
-:1015A000ED0CE856D521E3F6BCFD6D175F845F6E48
-:1015B0008B74C2BCEFCB4F667AAFEDD8B305F2D6D1
-:1015C000DB2AEF0336B5FC69E7CF799E05D724B453
-:1015D000AF2F5BD077561EFDE362E03527DCF705C1
-:1015E000E0878ECE643CE70C977AFDC8D1BC25D04D
-:1015F000D3DEB6FD3F81FECD89A68016F8BC60E340
-:101600003A44E5810905D0D3DEC8EE85D8BFF67926
-:101610008B13725A79203E0FF58143F9B21E5E3169
-:10162000716B12FCACE1E57DBB7F8EFBD5E76D7C79
-:101630002F541723E3BC4AB571DA4AE6DFAEDD4F1B
-:1016400003EF7D36BE9FAD40AD8AE08ADD695CC7A1
-:101650007FE5EB8F16820F85EA8EDDE8FFE2399B8E
-:10166000017438697645CF801E9E3471BE59A1C180
-:1016700015A7864B7CC27B8A987FB15B93E0672B72
-:1016800087FFF476E03D47DDBA13F98ED863E1BBFE
-:101690008973FB886EB4EE5CB3690AB8DCBB2FD2E9
-:1016A0000879B9A06C5DF814F66F96F32ED8B632AF
-:1016B0003D3DCDE305BE47F304ECD60565DBA0FE5A
-:1016C00073CD7BB2908F9E7F7E0EE7A5BAFCEAFABF
-:1016D00052F99C65905F644B40F6A852FB5BD83D85
-:1016E0002282FC6D85069E3FF464EF536260FDF933
-:1016F0001693DF4C34AAB08875D698017DA84CBCEF
-:10170000B518E7AB3434A6236EA998DAB3107A7112
-:10171000CE26AC0934EF4DCD6F551E5C3317F1EF7B
-:10172000F5F0B9A2D9A34B09D27F5D6AB77983EFEF
-:101730002543DBF7EA85FDADB401F8DE15168EE131
-:10174000F5FDDE34FBAA91A7D5C648FBF13ECD6F6F
-:10175000213BF6B5E6EF16AD1E3CBF3F3F86BF5FAF
-:101760006BEE4987FFD3F70FE46B7EC3D8930E7BF4
-:1017700015BA6E0EC211D8911714B6239507950F9E
-:1017800054A253A5D5E355411761D6CF69BCA2C871
-:101790007509D334BAD3DA0D05C9FCDDCA169BCB63
-:1017A00046EBAAC27AA210175547F64421DEE97D1E
-:1017B00059154D1ABB62E334FEA4682C0BAA3756A8
-:1017C000F84C2E5BD6107C46FC44F396E36FFAFE91
-:1017D0003305297C9EF2F670FE9EB0F74C839C96F2
-:1017E000EF18BC0EE7B207E95F6FFBAEB8E0BC3C98
-:1017F00045C33BA07CC07A12F8FAC324F0BDD220C6
-:10180000D6E1FEF23CADC1BD26C1C22A61BEF7AC35
-:10181000FC6B4418E4E5FCA56AD6DB5EA587EDDA2F
-:10182000DB0573D92EF59A7AD8AEBD7EF42EB60FAD
-:10183000BDC37A16C24EBD5DB05C8E8FEC59E8A078
-:10184000F1FD3A3C46B0DF7FEF680DDB8F39AA7CB3
-:1018500057217699ECB21EB4E1543DE71726477044
-:10186000FE7DBA40ABF70CF087F32E5D6F7A85638F
-:10187000FF41E8617904D775288E6A7911F1DE821B
-:101880003827DE6B94639D940373F07D636CCCE525
-:1018900065E0CF1DA3DD450539B8DFECE13C82A44E
-:1018A0009AFD4DEDEF2C9C4F064C7DBB61A7D247B6
-:1018B000BB6717101ED5E6EEF5D984D245534F17F6
-:1018C0004AE4B355698FC41E2957BD99BBE43D8DC9
-:1018D000765F79B7467F41494C23E44291FC7DBD58
-:1018E000FDC05BB02BBDDDE3D81E87EACDB9F6C7DE
-:1018F000A2601FFE4C7EDC1394EFFF79F11EBE67E1
-:101900009D8FF720D42E5937581EFABFBA83F33E65
-:10191000B125A81F72D830180E9523C8A37F90DD7B
-:10192000F130DDB76B7A5595D75D0B3A5C85E711E1
-:10193000AC06C1AF85C021F345898C13B6C3FF1334
-:101940003DAAC7F84F719EBEDF2460C7D792FF62E1
-:10195000B82DDC8B7CC5B09FFC53ACF44FF00B551D
-:1019600051DD5C9FEA6DB3F07DEF431D9F24E1FCE8
-:1019700024875C87A9EA78290EF9FB3E2D5F203F7A
-:1019800018C7EF63DA3AE29077E8FDD5065F3AF0E0
-:10199000A28888E375BDBF46F5A703FF2AA53B0BC8
-:1019A000E3FBF2EDDA7C8255C082CF51AD487D1762
-:1019B0001D2ADBF350BE3DA9C92BD9852C7EDFF152
-:1019C000B2AC0FE876A042B327AFA13F53EABD5DAA
-:1019D000BF57A2A515D0F721EC4342811E17AFE0F7
-:1019E000FACDE3050E096BEB795F595FE2F1DA5747
-:1019F0002E64A564629D362FD80E8D1BB02BD0FFB0
-:101A000004D6FF874C7174AECA9D8A732DEC54E9DD
-:101A10009A229A2E961B571671DD4C78386F0BC59B
-:101A20002B548E2617483A551A8615C606ED779E12
-:101A30006C7AC214B6337ED89D1FC53E5A843AC50F
-:101A40000F4BE5BB81ABFE2658CF719E1DD28E4356
-:101A50006DAE18AE95E3E52B1AD7C70F8147289EC8
-:101A600015EEC6A238C7B5FD3ABEE76D3A7E79A637
-:101A700011C17498BFA66804B5CBADFF2C1DE479E5
-:101A8000CF7758FCF0AB15A52BD7470F2137D7F8E8
-:101A9000831D41FE2B05FCF5F2FDC6F5F00F6DAB85
-:101AA00015FF29D48B04E95533EB17E94B905FB848
-:101AB000B920A4EE50BE782CE26AE15E3C167E8628
-:101AC000F46AA17388FC920CE42803BF19F1701B1F
-:101AD0008ACF5F0AE4BBA49B0BA49E6F99E90AC05E
-:101AE0006ECE500D1C8787EEF765818C27BAE322F6
-:101AF000EFD7DF7380D9335449B74443FFDBD0B706
-:101B0000C4B84807EE830AF3C3E5BCC3363BEA37E3
-:101B100081C397B9BE1B783862BEBC378810236971
-:101B2000BC2B615253B01FF975A13C6F78B68C5B2A
-:101B3000EA324C7FBF3E941979B53EC47143663892
-:101B4000DF97F4B67FCE7E2BD09963C7BD466F3743
-:101B50006587A44F755FFF571CFC6B6FE75FF81D2F
-:101B60005AEF579FF0FBB48DDAFBC0D7DAB5F75DBB
-:101B7000DD8E48F4078A3F2AC2BC4D5A3B5027905D
-:101B8000F562BDD5F35FBD1E1094078F2E1C3A0F72
-:101B90008E714704D7091CF143D55582EB04A9691E
-:101BA000B24E801675825493AC1300469D002DEA08
-:101BB00004E8479D0030EA04805127008C3A015A1E
-:101BC000D409D0FFC57CF95E2640422CEB97116CFE
-:101BD000DFEF6B56BD88CFEF3B2CEFA1EE6B54F8D7
-:101BE0009DD645FA3EFCDC35EF750E6AEF757CDB61
-:101BF000F85EAFAE4D75825575A6BE63A8EBD4B541
-:101C00002ACE35B02FF5F3F9FB1B3B73DE2D457F54
-:101C1000B3C96970804F97E250AFAAEC6CE6FA53F3
-:101C200041FC6133F3B74511A897DE6591796E8D5C
-:101C30004ABD53F83E94E3E01A4B37E71F557B1536
-:101C40007B59F07DEE4D9FB11D586B8B6A029E351E
-:101C50003E9BBD6C88F71F7C2FEC1057EF9B97C9FC
-:101C600029A226A288EF9B97E19E995AA17E65E45E
-:101C7000FB634A4C87431EF1AE2A0366DD2EF53E18
-:101C8000E43D556567EBFA4471ED3D342A03E07F8E
-:101C9000E8FDB3BB3032F64C380C85988CB8A9F807
-:101CA000F1B2FD6DF4BDFEAD168E3B56E6BB97431B
-:101CB0008E8E995C5C273976D8C6F9D1C7DBC60F02
-:101CC000AA937CEE725717F2FDFC68AE5BAC32292A
-:101CD000EC97F38BC7C5F3BB81E326F63F1DAE92AD
-:101CE0005ACC5B35C9C1F5A9428BB89FF7D1DE69E3
-:101CF00051CBFA54B856F11A085E2C9C66E8CF22F4
-:101D0000221BCB8B296203DE532D12F27D832E37EB
-:101D1000ABB6291C1770A1200EF79292BE8B3AFF2A
-:101D2000ED32DE2F2CB5C8F835D120EFB31337C90B
-:101D3000F72D3F126E33FCED72F28B68C94FFEAE89
-:101D400087FADDE1A393647CEE88C7FE8B4F98F899
-:101D5000BD6F61FCF7D3DDECAF0BF81D83E2BF472D
-:101D6000BD72C3F5F527F41DC33193B42F4447CE9C
-:101D70008BBA20975C9F71737BA2BE9CDB1933A545
-:101D80009DBEFA2E91786407FEE17DEF235F4C8CB7
-:101D90008F74C2DEE97A7FCDFBC430D9EAEF13C776
-:101DA000502B82DE276E713978FF44C3C9A90ED04B
-:101DB000E3AF114ED0437FA7B86566C92EF0C915B1
-:101DC000253CF82EEE51B6125D8B701005756E9F96
-:101DD0004B45DDFAB062E777D1D7D8C96D0FE31D67
-:101DE0004F5DAA62571CA8876F2D8C23BC8B529223
-:101DF00019EFBA76592F650AC5A19EAEE983CBDDEE
-:101E0000563862A07F8EA617BD345FCAC92D5EC842
-:101E1000DBB7A8A33E87F91E6173366BF91AF83E4B
-:101E2000E786315C4FD5E5A6BF25BE0972F346A112
-:101E3000F433A5A5EF98100774E5BA8FE2FC0BCB3D
-:101E40003E7B388ECF37741D8BEC28DF4B86D6B1A6
-:101E500074BBBC5BAB83C37E1AB53AAB51ABB31A50
-:101E6000B53AAB51ABB31AB53AAB51ABB31AB53ABD
-:101E7000AB51ABB31AB53AAB91EB772BB87DBB7EC8
-:101E800035B7DDF51E1E0FB2FFEF5DC7FE87D641E9
-:101E90003FC2BCD03AA8B03AA2D98F927ECBFA7397
-:101EA00048DDB378F8920D44BFFC06B3135D7A1D8C
-:101EB00014EF97EF8B607B70B170C8FAA74EB7082C
-:101EC000AE97F60BDB14D03F2F639CD140E37FD558
-:101ED000F8A0D71FA11F381FF4032DF4C39836A014
-:101EE0001FCF984985B3A5BFF7B0BFB7315FD7AF54
-:101EF00021FB41F052611F643F2E86D80F4A3CEE11
-:101F0000061ECB3AE5BB26FDFD661E355F4E19C2A7
-:101F10009EF8A43D1913E6DB87EF8CA90DE3F7C10A
-:101F2000C7B4F758C736CA777165A284BF3B845DD2
-:101F300089023F960EEF7BFF699ABF747304C72D29
-:101F4000EB472E9BF6BFB12B9F150AA6DB6FEAFD70
-:101F5000951F132E056152FE0ACC2203F735C210DD
-:101F6000C67A50A86E51703FBAEA5E31197C2EB025
-:101F700094EC009EF1DAFDB688D5EAADC6EE8A3D56
-:101F8000049F8C4B74E25E6B74C22181F74F8575A0
-:101F9000C599B08BFE31EE09453978BFBC55C1FA01
-:101FA000F04C79FE3B8AC39B205781C3E373C0EF9B
-:101FB0007916471BEA00CEA284A5C8F3E7453B7219
-:101FC000500770768D9270BCA34D7122944D585A73
-:101FD000C0EFCFAC5B3FB6E2DD9A22A2E95C96612E
-:101FE000EE1C7CA7A6F85399378B3EF6633717C9CA
-:101FF000FC6BC46BC28F7BABBE59917C7F26321DBC
-:102000003918A7B8F2BB45241F7FFC9EEB16AC4FD6
-:10201000D4F08CC72DA20AAE76DBD09ED0EEF3BAF8
-:102020000CEE52B445511E23F71BBCD968DF34F8BF
-:102030007E8C7E92E722EC57F4D8E4891904275A63
-:102040007C6C273B5CAE5BB1FFAB335DC5180FAD5D
-:102050009F83B7C8F3099FDB302FF41D96CECFA521
-:102060004552EECB8AA4FD98BE56DEC786F2BDACC3
-:10207000C8A0D9B7BF8F37E15B8AEFE9F88BAD8B8A
-:10208000B3810FE17B2FF0247C17625C44C470BDE8
-:10209000E3FA72E6E1EF951549F9227B56F5B1B402
-:1020A00067DCA61BBDC3103F8EFA857718F01DD5DF
-:1020B000D867C3BFC378D6D367837F7FF6C13E1B83
-:1020C000FA9F75C977D2A1FB3716C9F713E9D3FB7D
-:1020D00078FD58FA5637C7E97DC31047A5977FBCEE
-:1020E0005EDEBB64B07F19ABF997B1BF4869EF21E1
-:1020F000791BFB6434DF6F8B82581EAFB44A3DAD51
-:10210000FC45D9A1366AC76F277C83E2AF095EC25E
-:102110007B505C64EC97EF2D09069DF69A1886CCEF
-:1021200022BEAA11F2BDE528CD6E206E2B25BB5034
-:10213000537EF432BF03C07AEC8F3B5BC85FBB4970
-:10214000C2E4AE918F2E9FBFA68BF3C3ED57FBB5B4
-:102150007CB3753DF2678ADF06F557961DE982BFAD
-:10216000A9DA3BB8BF66C5679CC752FC36A8FFDE3C
-:102170001F7FC0EF6CEADA07F7137F9F029F75FE9F
-:102180001E33F92620DF3B5613E694FF7EC0B712BC
-:10219000FADE541DC1EF6777FD3A8FE546E737ADAC
-:1021A0006FFA76F2B196E77BF24406F4E19BDA5ED1
-:1021B000D8A7B441F6C9C375BED9916C77EAB4FC0F
-:1021C000AAB6CCCE7E3EB1D6CAF6AB500D7302AEE7
-:1021D000354A3B238A55CD4EF958FF4FDE3E8CEBF6
-:1021E000797C00C03193F8DD71DC5A09F78DB0B00D
-:1021F0007D28349454EFA1F6A86105DB8104BCB8B6
-:1022000024BE3F03FBA0427F655DB5CEEC53E4FDE9
-:10221000BE2307F9AE7EDFD4B0D1DB7A10F9B2E28B
-:102220007D7219EA8A7746F0FD4100F5463A4FC3C0
-:102230003069471B16A4B31F088892D2958843E6DD
-:102240008771FDB16198E351DC2736544CE438FACC
-:10225000D07F4BBFDB37D7EA441CD530D9B106EF6E
-:10226000551A7EE1E0F15714B99FE751499F86B9AD
-:10227000F2FC0D15319CF7E87C6868748DC4FDD4C0
-:10228000CC31EEFF00DF4769F7730DC9D44FED1372
-:102290004AC9821F619F4912DF19331DAC77C716E7
-:1022A0004C7C74B783DD891FF74475B32307E5C5FC
-:1022B000FF033C759D8B10370000000000000000FC
-:0822C00005020D000000000002
-:00000001FF
diff --git a/firmware/bnx2x/bnx2x-e1-6.0.34.0.fw.ihex b/firmware/bnx2x/bnx2x-e1-6.0.34.0.fw.ihex
new file mode 100644
index 000000000000..33b584c7c1ab
--- /dev/null
+++ b/firmware/bnx2x/bnx2x-e1-6.0.34.0.fw.ihex
@@ -0,0 +1,9476 @@
+:1000000000003BB0000000680000070C00003C202E
+:1000100000001AF8000043300000007C00005E3051
+:10002000000079E800005EB0000000B40000D8A035
+:100030000000800C0000D9580000008800015968B9
+:10004000000039C4000159F800000090000193C07D
+:100050000000ABA80001945800000FFC000240080B
+:100060000000000400025008020400480000000FD5
+:100070000204005400000045020400580000000083
+:100080000204005C0000000602040070000000048E
+:1000900002040078000000000204007C1217000037
+:1000A00002040080221700000204008432170000BE
+:1000B00006040088000000050204009C12150000E0
+:1000C000020400A022150000020400A43215000062
+:1000D000060400A800000004020400B8021000009A
+:1000E000020400BC00100000020400C01010000058
+:1000F000020400C420100000020400C830100000F8
+:10010000060400CC00000004020400DC0010000023
+:10011000020400E012140000020400E422140000B3
+:10012000020400E832140000060400EC00000004A1
+:100130000104012400000000010401280000000067
+:100140000104012C00000000010401300000000047
+:1001500002040004000000FF02040008000000FF89
+:100160000204000C000000FF02040010000000FF69
+:1001700002040014000000FF02040018000000FF49
+:100180000204001C000000FF02040020000000FF29
+:10019000020400240000003E0204002800000000C9
+:1001A0000204002C0000003F020400300000003F69
+:1001B000020400340000003F020400380000000088
+:1001C0000204003C0000003F020400400000003F29
+:1001D000020400440000003F020420080000021155
+:1001E0000204200C0000020002042010000002049F
+:1001F00002042014000002190204201C0000FFFF6A
+:10020000020420200000FFFF020420240000FFFF62
+:10021000020420280000FFFF0604203800000080B0
+:100220000204223807FFFFFF0204223C0000003FC7
+:100230000204224007FFFFFF020422440000000FD7
+:1002400001042248000000000104224C00000000CC
+:1002500001042250000000000104225400000000AC
+:1002600001042258000000000104225C000000008C
+:10027000010422600000000001042264000000006C
+:1002800001042268000000000104226C000000004C
+:10029000010422700000000001042274000000002C
+:1002A00001042278000000000104227C000000000C
+:1002B000020424BC000000010C042000000003E83C
+:1002C0000A042000000000010B0420000000000AC6
+:1002D0000605400000000D0002050044000000205B
+:1002E00002050048000000320205009002150020BF
+:1002F000020500940215002002050098000000305D
+:100300000205009C08100000020500A00000003358
+:10031000020500A400000030020500A80000003122
+:10032000020500AC00000002020500B0000000055C
+:10033000020500B400000006020500B8000000023B
+:10034000020500BC00000002020500C00000000021
+:10035000020500C400000005020500C800000002FC
+:10036000020500CC00000002020500D000000002DF
+:10037000020500D400000001020501140000000184
+:100380000205011C0000000102050120000000021E
+:1003900002050204000000010205020C00000040FA
+:1003A00002050210000000400205021C00000020AF
+:1003B00002050220000000130205022400000020B4
+:1003C000060502400000000A04050280002000002B
+:1003D000020500500000000702050054000000075D
+:1003E00002050058000000000205005C0000000843
+:1003F0000605006000000004020500D800000006A9
+:10040000020500E00000000D020500E40000002DE0
+:10041000020500E800000000020500EC00000020DA
+:10042000020500F000000000020500F400000020BA
+:10043000020500F800000000020500FC000000209A
+:100440000205000400000001020500080000000190
+:100450000205000C00000001020500100000000170
+:100460000205001400000001020500180000000150
+:100470000205001C00000001020500200000000130
+:100480000205002400000001020500280000000110
+:100490000205002C000000010205003000000001F0
+:1004A00002050034000000010205003800000001D0
+:1004B0000205003C000000010205004000000001B0
+:1004C0000406100002000020020600DC000000010B
+:1004D000010600D80000000004060200000302200C
+:1004E000020600DC0000000002060068000000B800
+:1004F0000206007800000114010600B800000000A8
+:10050000010600C8000000000206006C000000B8F0
+:100510000206007C00000114010600BC000000007F
+:10052000010600CC0000000007180400007B00005A
+:100530000818076000140223071C00002A1E000090
+:10054000071C800031E60A88071D00001DDD170228
+:10055000081D4470577202250118000000000000B9
+:10056000011800040000000001180008000000004D
+:100570000118000C0000000001180010000000002D
+:100580000118001400000000021800200000000103
+:1005900002180024000000020218002800000003D6
+:1005A0000218002C000000000218003000000004B7
+:1005B000021800340000000102180038000000009A
+:1005C0000218003C00000001021800400000000476
+:1005D000021800440000000002180048000000015A
+:1005E0000218004C00000003021800500000000038
+:1005F0000218005400000001021800580000000416
+:100600000218005C000000000218006000000001F9
+:1006100002180064000000030218006800000000D7
+:100620000218006C000000010218007000000004B5
+:100630000218007400000000021800780000000496
+:100640000218007C00000003061800800000000271
+:10065000021800A400003FFF021800A8000003FFDA
+:1006600002180224000000000218023400000000FA
+:100670000218024C00000000021802E4000000FF13
+:100680000618100000000400021B8BC000000001CF
+:10069000021B800000000034021B80400000001894
+:1006A000021B80800000000C021B80C000000020A4
+:1006B0000C1B83000007A1200A1B830000000138E7
+:1006C0000B1B8300000013880A1B834000000000FE
+:1006D0000C1B8340000001F40B1B8340000000054D
+:1006E000021B83800007A120021B83C0000001F4CD
+:1006F000061A100000000273041A19CC0001022728
+:10070000061A2008000000C8061A20000000000297
+:10071000041A499800040228061A2E280000000234
+:10072000061A2E2000000002061A0800000000022F
+:10073000061A080800000004061A08180000000243
+:10074000041A08B00002022C061A2FD0000000067E
+:10075000041A2FE80002022E041A2FC000040230EF
+:10076000041A300000010234061A300400000003AD
+:10077000041A301000010235061A3014000000037C
+:10078000041A302000010236061A3024000000034B
+:10079000041A303000010237061A3034000000031A
+:1007A000041A304000010238061A304400000003E9
+:1007B000041A305000010239061A305400000003B8
+:1007C000041A30600001023A061A30640000000387
+:1007D000041A30700001023B061A30740000000356
+:1007E000041A30800001023C061A30840000000325
+:1007F000041A30900001023D061A309400000003F4
+:10080000041A30A00001023E061A30A400000003C2
+:10081000041A30B00001023F061A30B40000000391
+:10082000041A30C000010240061A30C40000000360
+:10083000041A30D000010241061A30D4000000032F
+:10084000041A30E000010242061A30E400000003FE
+:10085000041A30F000010243061A30F400000003CD
+:10086000041A310000010244061A3104000000039A
+:10087000041A311000010245061A31140000000369
+:10088000041A312000010246061A31240000000338
+:10089000041A313000010247061A31340000000307
+:1008A000041A314000010248061A314400000003D6
+:1008B000041A315000010249061A315400000003A5
+:1008C000041A31600001024A061A31640000000374
+:1008D000041A31700001024B061A31740000000343
+:1008E000041A31800001024C061A31840000000312
+:1008F000041A31900001024D061A319400000003E1
+:10090000041A31A00001024E061A31A400000003AF
+:10091000041A31B00001024F061A31B4000000037E
+:10092000041A31C000010250061A31C4000000034D
+:10093000041A31D000010251061A31D4000000031C
+:10094000041A31E000010252061A31E400000003EB
+:10095000041A31F000010253061A31F400000003BA
+:10096000041A320000010254061A32040000000387
+:10097000041A321000010255061A32140000000356
+:10098000041A322000010256061A32240000000325
+:10099000041A323000010257061A323400000003F4
+:1009A000041A324000010258061A324400000003C3
+:1009B000041A325000010259061A32540000000392
+:1009C000041A32600001025A061A32640000000361
+:1009D000041A32700001025B061A32740000000330
+:1009E000041A32800001025C061A328400000003FF
+:1009F000041A32900001025D061A329400000003CE
+:100A0000041A32A00001025E061A32A4000000039C
+:100A1000041A32B00001025F061A32B4000000036B
+:100A2000041A32C000010260061A32C4000000033A
+:100A3000041A32D000010261061A32D40000000309
+:100A4000041A32E000010262061A32E400000003D8
+:100A5000041A32F000010263061A32F400000003A7
+:100A6000041A330000010264061A33040000000374
+:100A7000041A331000010265061A33140000000343
+:100A8000041A332000010266061A33240000000312
+:100A9000041A333000010267061A333400000003E1
+:100AA000041A334000010268061A334400000003B0
+:100AB000041A335000010269061A3354000000037F
+:100AC000041A33600001026A061A3364000000034E
+:100AD000041A33700001026B061A3374000000031D
+:100AE000041A33800001026C061A338400000003EC
+:100AF000041A33900001026D061A339400000003BB
+:100B0000041A33A00001026E061A33A40000000389
+:100B1000041A33B00001026F061A33B40000000358
+:100B2000041A33C000010270061A33C40000000327
+:100B3000041A33D000010271061A33D400000003F6
+:100B4000041A33E000010272061A33E400000003C5
+:100B5000041A33F000010273061A33F40000000394
+:100B6000041A340000010274061A34040000000361
+:100B7000041A341000010275061A34140000000330
+:100B8000041A342000010276061A342400000003FF
+:100B9000041A343000010277061A343400000003CE
+:100BA000041A344000010278061A3444000000039D
+:100BB000041A345000010279061A3454000000036C
+:100BC000041A34600001027A061A3464000000033B
+:100BD000041A34700001027B061A3474000000030A
+:100BE000041A34800001027C061A348400000003D9
+:100BF000041A34900001027D061A349400000003A8
+:100C0000041A34A00001027E061A34A40000000376
+:100C1000041A34B00001027F061A34B40000000345
+:100C2000041A34C000010280061A34C40000000314
+:100C3000041A34D000010281061A34D400000003E3
+:100C4000041A34E000010282061A34E400000003B2
+:100C5000041A34F000010283061A34F40000000381
+:100C6000041A350000010284061A3504000000034E
+:100C7000041A351000010285061A3514000000031D
+:100C8000041A352000010286061A352400000003EC
+:100C9000041A353000010287061A353400000003BB
+:100CA000041A354000010288061A3544000000038A
+:100CB000041A355000010289061A35540000000359
+:100CC000041A35600001028A061A35640000000328
+:100CD000041A35700001028B061A357400000003F7
+:100CE000041A35800001028C061A358400000003C6
+:100CF000041A35900001028D061A35940000000395
+:100D0000041A35A00001028E061A35A40000000363
+:100D1000041A35B00001028F061A35B40000000332
+:100D2000041A35C000010290061A35C40000000301
+:100D3000041A35D000010291061A35D400000003D0
+:100D4000041A35E000010292061A35E4000000039F
+:100D5000041A35F000010293061A35F4000000036E
+:100D6000041A360000010294061A3604000000033B
+:100D7000041A361000010295061A3614000000030A
+:100D8000041A362000010296061A362400000003D9
+:100D9000041A363000010297061A363400000003A8
+:100DA000041A364000010298061A36440000000377
+:100DB000041A365000010299061A36540000000346
+:100DC000041A36600001029A061A36640000000315
+:100DD000041A36700001029B061A367400000003E4
+:100DE000041A36800001029C061A368400000003B3
+:100DF000041A36900001029D061A36940000000382
+:100E0000041A36A00001029E061A36A40000000350
+:100E1000041A36B00001029F061A36B4000000031F
+:100E2000041A36C0000102A0061A36C400000003EE
+:100E3000041A36D0000102A1061A36D400000003BD
+:100E4000041A36E0000102A2061A36E4000000038C
+:100E5000041A36F0000102A3061A36F4000000035B
+:100E6000041A3700000102A4061A37040000000328
+:100E7000041A3710000102A5061A371400000003F7
+:100E8000041A3720000102A6061A372400000003C6
+:100E9000041A3730000102A7061A37340000000395
+:100EA000041A3740000102A8061A37440000000364
+:100EB000041A3750000102A9061A37540000000333
+:100EC000041A3760000102AA061A37640000000302
+:100ED000041A3770000102AB061A377400000003D1
+:100EE000041A3780000102AC061A378400000003A0
+:100EF000041A3790000102AD061A3794000000036F
+:100F0000041A37A0000102AE061A37A4000000033D
+:100F1000041A37B0000102AF061A37B4000000030C
+:100F2000041A37C0000102B0061A37C400000003DB
+:100F3000041A37D0000102B1061A37D400000003AA
+:100F4000041A37E0000102B2061A37E40000000379
+:100F5000041A37F0000102B3061A37F40000000348
+:100F6000041A3800000102B4061A38040000000315
+:100F7000041A3810000102B5061A381400000003E4
+:100F8000041A3820000102B6061A382400000003B3
+:100F9000041A3830000102B7061A38340000000382
+:100FA000041A3840000102B8061A38440000000351
+:100FB000041A3850000102B9061A38540000000320
+:100FC000041A3860000102BA061A386400000003EF
+:100FD000041A3870000102BB061A387400000003BE
+:100FE000041A3880000102BC061A3884000000038D
+:100FF000041A3890000102BD061A3894000000035C
+:10100000041A38A0000102BE061A38A4000000032A
+:10101000041A38B0000102BF061A38B400000003F9
+:10102000041A38C0000102C0061A38C400000003C8
+:10103000041A38D0000102C1061A38D40000000397
+:10104000041A38E0000102C2061A38E40000000366
+:10105000041A38F0000102C3061A38F40000000335
+:10106000041A3900000102C4061A39040000000302
+:10107000041A3910000102C5061A391400000003D1
+:10108000041A3920000102C6061A392400000003A0
+:10109000041A3930000102C7061A3934000000036F
+:1010A000041A3940000102C8061A3944000000033E
+:1010B000041A3950000102C9061A3954000000030D
+:1010C000041A3960000102CA061A396400000003DC
+:1010D000041A3970000102CB061A397400000003AB
+:1010E000041A3980000102CC061A3984000000037A
+:1010F000041A3990000102CD061A39940000000349
+:10110000041A39A0000102CE061A39A40000000317
+:10111000041A39B0000102CF061A39B400000003E6
+:10112000041A39C0000102D0061A39C400000003B5
+:10113000041A39D0000102D1061A39D40000000384
+:10114000041A39E0000102D2061A39E40000000353
+:10115000041A39F0000102D3061A39F40000000322
+:10116000041A3A00000102D4061A3A0400000003EF
+:10117000041A3A10000102D5061A3A1400000003BE
+:10118000041A3A20000102D6061A3A24000000038D
+:10119000041A3A30000102D7061A3A34000000035C
+:1011A000041A3A40000102D8061A3A44000000032B
+:1011B000041A3A50000102D9061A3A5400000003FA
+:1011C000041A3A60000102DA061A3A6400000003C9
+:1011D000041A3A70000102DB061A3A740000000398
+:1011E000041A3A80000102DC061A3A840000000367
+:1011F000041A3A90000102DD061A3A940000000336
+:10120000041A3AA0000102DE061A3AA40000000304
+:10121000041A3AB0000102DF061A3AB400000003D3
+:10122000041A3AC0000102E0061A3AC400000003A2
+:10123000041A3AD0000102E1061A3AD40000000371
+:10124000041A3AE0000102E2061A3AE40000000340
+:10125000041A3AF0000102E3061A3AF4000000030F
+:10126000041A3B00000102E4061A3B0400000003DC
+:10127000041A3B10000102E5061A3B1400000003AB
+:10128000041A3B20000102E6061A3B24000000037A
+:10129000041A3B30000102E7061A3B340000000349
+:1012A000041A3B40000102E8061A3B440000000318
+:1012B000041A3B50000102E9061A3B5400000003E7
+:1012C000041A3B60000102EA061A3B6400000003B6
+:1012D000041A3B70000102EB061A3B740000000385
+:1012E000041A3B80000102EC061A3B840000000354
+:1012F000041A3B90000102ED061A3B940000000323
+:10130000041A3BA0000102EE061A3BA400000003F1
+:10131000041A3BB0000102EF061A3BB400000003C0
+:10132000041A3BC0000102F0061A3BC4000000038F
+:10133000041A3BD0000102F1061A3BD4000000035E
+:10134000041A3BE0000102F2061A3BE4000000032D
+:10135000041A3BF0000102F3061A3BF400000003FC
+:10136000041A3C00000102F4061A3C0400000003C9
+:10137000041A3C10000102F5061A3C140000000398
+:10138000041A3C20000102F6061A3C240000000367
+:10139000041A3C30000102F7061A3C340000000336
+:1013A000041A3C40000102F8061A3C440000000305
+:1013B000041A3C50000102F9061A3C5400000003D4
+:1013C000041A3C60000102FA061A3C6400000003A3
+:1013D000041A3C70000102FB061A3C740000000372
+:1013E000041A3C80000102FC061A3C840000000341
+:1013F000041A3C90000102FD061A3C940000000310
+:10140000041A3CA0000102FE061A3CA400000003DE
+:10141000041A3CB0000102FF061A3CB400000003AD
+:10142000041A3CC000010300061A3CC4000000037B
+:10143000041A3CD000010301061A3CD4000000034A
+:10144000041A3CE000010302061A3CE40000000319
+:10145000041A3CF000010303061A3CF400000003E8
+:10146000041A3D0000010304061A3D0400000003B5
+:10147000041A3D1000010305061A3D140000000384
+:10148000041A3D2000010306061A3D240000000353
+:10149000041A3D3000010307061A3D340000000322
+:1014A000041A3D4000010308061A3D4400000003F1
+:1014B000041A3D5000010309061A3D5400000003C0
+:1014C000041A3D600001030A061A3D64000000038F
+:1014D000041A3D700001030B061A3D74000000035E
+:1014E000041A3D800001030C061A3D84000000032D
+:1014F000041A3D900001030D061A3D9400000003FC
+:10150000041A3DA00001030E061A3DA400000003CA
+:10151000041A3DB00001030F061A3DB40000000399
+:10152000041A3DC000010310061A3DC40000000368
+:10153000041A3DD000010311061A3DD40000000337
+:10154000041A3DE000010312061A3DE40000000306
+:10155000041A3DF000010313061A3DF400000003D5
+:10156000041A3E0000010314061A3E0400000003A2
+:10157000041A3E1000010315061A3E140000000371
+:10158000041A3E2000010316061A3E240000000340
+:10159000041A3E3000010317061A3E34000000030F
+:1015A000041A3E4000010318061A3E4400000003DE
+:1015B000041A3E5000010319061A3E5400000003AD
+:1015C000041A3E600001031A061A3E64000000037C
+:1015D000041A3E700001031B061A3E74000000034B
+:1015E000041A3E800001031C061A3E84000000031A
+:1015F000041A3E900001031D061A3E9400000003E9
+:10160000041A3EA00001031E061A3EA400000003B7
+:10161000041A3EB00001031F061A3EB40000000386
+:10162000041A3EC000010320061A3EC40000000355
+:10163000041A3ED000010321061A3ED40000000324
+:10164000041A3EE000010322061A3EE400000003F3
+:10165000041A3EF000010323061A3EF400000003C2
+:10166000041A3F0000010324061A3F04000000038F
+:10167000041A3F1000010325061A3F14000000035E
+:10168000041A3F2000010326061A3F24000000032D
+:10169000041A3F3000010327061A3F3400000003FC
+:1016A000041A3F4000010328061A3F4400000003CB
+:1016B000041A3F5000010329061A3F54000000039A
+:1016C000041A3F600001032A061A3F640000000369
+:1016D000041A3F700001032B061A3F740000000338
+:1016E000041A3F800001032C061A3F840000000307
+:1016F000041A3F900001032D061A3F9400000003D6
+:10170000041A3FA00001032E061A3FA400000003A4
+:10171000041A3FB00001032F061A3FB40000000373
+:10172000041A3FC000010330061A3FC40000000342
+:10173000041A3FD000010331061A3FD40000000311
+:10174000041A3FE000010332061A3FE400000007DC
+:10175000041A4CB000080333061A400000000124AC
+:10176000021A492000000000061A2500000000109F
+:10177000061A258000000012061A09C00000004861
+:10178000061A080000000002061A082000000012D5
+:10179000041A2FB00002033B041A4CF00002033D70
+:1017A000061A500000000004061A449000000124AC
+:1017B000021A492400000000061A2540000000100B
+:1017C000061A25C800000012061A0AE000000048A8
+:1017D000061A081000000002061A0868000000122D
+:1017E000041A2FB80002033F041A4CF80002034108
+:1017F000061A5010000000040200A468000AFFDC72
+:101800000200A280000000010200A294071D29111D
+:101810000200A298000000000200A29C009C042488
+:101820000200A2A0000000000200A2A40000020921
+:101830000200A4FCFF000000020100B4000000014F
+:10184000020100B800000001020100DC00000001FC
+:10185000020101000000000102010104000000017A
+:101860000201007C0030000002010084000000281A
+:101870000201008C000000000201013000000004A1
+:101880000201025C000000010201032800000000C8
+:101890000201055400000030020100C400000001F4
+:1018A000020100CC00000001020100F8000000016C
+:1018B000020100F000000001020100800030000081
+:1018C00002010088000000280201009000000000D2
+:1018D0000201013400000004020102DC00000001EA
+:1018E0000201032C0000000002010564000000302A
+:1018F000020100C800000001020100D00000000148
+:10190000020100FC00000001020100F400000001DF
+:10191000020C100000000028020C200800000A1130
+:10192000020C200C00000A00020C201000000A0427
+:10193000020C201C0000FFFF020C20200000FFFF13
+:10194000020C20240000FFFF020C20280000FFFFF3
+:10195000020C203800000020020C203C0000002176
+:10196000020C204000000022020C20440000002352
+:10197000020C204800000024020C204C000000252E
+:10198000020C205000000026020C2054000000270A
+:10199000020C205800000028020C205C00000029E6
+:1019A000020C20600000002A020C20640000002BC2
+:1019B000020C20680000002C020C206C0000002D9E
+:1019C000020C20700000002E020C20740000002F7A
+:1019D000020C207800000010060C207C0000004F54
+:1019E000020C21B800000001020C21BC0000000123
+:1019F000020C21C000000001020C21C40000000103
+:101A0000020C21C800000001020C21CC00000001E2
+:101A1000020C21D000000001020C21D400000001C2
+:101A2000020C21D800000001020C21DC00000001A2
+:101A3000020C21E000000001020C21E40000000182
+:101A4000020C21E800000001020C21EC0000000162
+:101A5000020C21F000000001020C21F40000000142
+:101A6000020C21F800000001060C21FC0000000F10
+:101A7000020C223807FFFFFF020C223C0000003F4F
+:101A8000020C224007FFFFFF020C22440000000F5F
+:101A9000010C224800000000010C224C0000000054
+:101AA000010C225000000000010C22540000000034
+:101AB000010C225800000000010C225C0000000014
+:101AC000010C226000000000010C226400000000F4
+:101AD000010C226800000000010C226C00000000D4
+:101AE000010C227000000000010C227400000000B4
+:101AF000010C227800000000010C227C0000000094
+:101B0000020C24BC000000010C0C2000000003E8C3
+:101B10000A0C2000000000010B0C20000000000A4D
+:101B2000020C400800000562020C400C0000055148
+:101B3000020C401000000555020C40140000057214
+:101B4000020C401C0000FFFF020C40200000FFFFC1
+:101B5000020C40240000FFFF020C40280000FFFFA1
+:101B6000020C403800000046020C403C0000000C13
+:101B7000060C40400000005E020C41B8000000016D
+:101B8000060C41BC0000001F020C423807FFFFFF9B
+:101B9000020C423C0000003F020C424007FFFFFFE6
+:101BA000020C42440000000F010C424800000000FB
+:101BB000010C424C00000000010C425000000000EB
+:101BC000010C425400000000010C425800000000CB
+:101BD000010C425C00000000010C426000000000AB
+:101BE000010C426400000000010C4268000000008B
+:101BF000010C426C00000000010C4270000000006B
+:101C0000010C427400000000010C4278000000004A
+:101C1000010C427C00000000010C4280000000002A
+:101C2000020C44C0000000010C0C4000000003E85E
+:101C30000A0C4000000000010B0C40000000000AEC
+:101C4000060D400000000A00020D004400000032B2
+:101C5000020D008C02150020020D009002150020DC
+:101C6000020D009408100000020D009800000033DF
+:101C7000020D009C00000002020D00A00000000008
+:101C8000020D00A400000005020D00A800000005E0
+:101C9000060D00AC00000002020D00B400000002BE
+:101CA000020D00B800000003020D00BC000000029D
+:101CB000020D00C000000001020D00C8000000027B
+:101CC000020D00CC00000002020D015C00000001CA
+:101CD000020D016400000001020D01680000000215
+:101CE000020D020400000001020D020C00000020A1
+:101CF000020D021000000040020D0214000000401E
+:101D0000020D022000000003020D02240000001852
+:101D1000060D028000000012040D030000180343AA
+:101D2000060D03600000000C020D004C00000001D5
+:101D3000020D005000000002020D005400000000DF
+:101D4000020D005800000008060D005C00000004B1
+:101D5000020D00C400000004020D0114000000097F
+:101D6000020D011800000029020D011C0000000AEC
+:101D7000020D01200000002A020D012400000000D5
+:101D8000020D012800000020020D012C00000000BF
+:101D9000020D013000000020020D0134000000009F
+:101DA000020D013800000020020D013C000000007F
+:101DB000020D014000000020020D0144000000005F
+:101DC000020D014800000020020D00040000000187
+:101DD000020D000800000001020D000C00000001CF
+:101DE000020D001000000001020D001400000001AF
+:101DF000020D001800000001020D001C000000018F
+:101E0000020D002000000001020D0024000000016E
+:101E1000020D002800000001020D002C000000014E
+:101E2000020D003000000001020D0034000000012E
+:101E3000020D003800000001020D003C000000010E
+:101E4000060E200000000800020E004C00000032C8
+:101E5000020E009402150020020E009802150020C8
+:101E6000020E009C00000030020E00A008100000CE
+:101E7000020E00A400000033020E00A80000003093
+:101E8000020E00AC00000031020E00B000000002A3
+:101E9000020E00B400000004020E00B800000000B2
+:101EA000020E00BC00000002020E00C00000000292
+:101EB000020E00C400000000020E00C80000000274
+:101EC000020E00CC00000007020E00D0000000024D
+:101ED000020E00D400000002020E00D80000000133
+:101EE000020E014400000001020E014C000000013E
+:101EF000020E015000000002020E02040000000168
+:101F0000020E020C00000040020E02100000004011
+:101F1000020E021C00000004020E0220000000203D
+:101F2000020E02240000000E020E02280000001B18
+:101F3000060E030000000012040E0280001B035B6B
+:101F4000060E02EC00000005020E00540000000C1A
+:101F5000020E00580000000C020E005C00000000A1
+:101F6000020E006000000010060E00640000000475
+:101F7000020E00DC00000003020E01100000000F42
+:101F8000020E01140000002F020E011800000000D4
+:101F9000020E011C00000020020E000400000001DF
+:101FA000020E000800000001020E000C00000001FB
+:101FB000020E001000000001020E001400000001DB
+:101FC000020E001800000001020E001C00000001BB
+:101FD000020E002000000001020E0024000000019B
+:101FE000020E002800000001020E002C000000017B
+:101FF000020E003000000001020E0034000000015B
+:10200000020E003800000001020E003C000000013A
+:10201000020E004000000001020E0044000000011A
+:102020000730040000B00000083007680013037692
+:1020300007340000332700000734800032520CCAF6
+:10204000073500001A8C195F083539A058CC037881
+:10205000013000000000000001300004000000001A
+:1020600001300008000000000130000C00000000FA
+:1020700001300010000000000130001400000000DA
+:1020800002300020000000010230002400000002A5
+:1020900002300028000000030230002C0000000085
+:1020A0000230003000000004023000340000000163
+:1020B00002300038000000000230003C0000000147
+:1020C0000230004000000004023000440000000024
+:1020D00002300048000000010230004C0000000304
+:1020E00002300050000000000230005400000001E7
+:1020F00002300058000000040230005C00000000C4
+:1021000002300060000000010230006400000003A3
+:1021100002300068000000000230006C0000000186
+:102120000230007000000004023000740000000063
+:1021300002300078000000040230007C0000000340
+:102140000630008000000002023000A400003FFFC3
+:10215000023000A8000003FF02300224000000004B
+:1021600002300234000000000230024C0000000087
+:10217000023002E40000FFFF0630200000000800EB
+:1021800002338BC000000001023380000000001AFF
+:10219000023380400000004E0233808000000010B7
+:1021A000023380C0000000200C3383000007A12010
+:1021B0000A338300000001380B33830000001388CA
+:1021C0000A338340000000000C338340000001F418
+:1021D0000B33834000000005023383800007A120F9
+:1021E000023383C0000001F406322A88000000C2D6
+:1021F00006322008000000C806322000000000025D
+:10220000063223E80000004004322E580004037A0E
+:10221000063250A000000004063250B80000000250
+:102220000632508000000006043250980002037EFF
+:10223000063250000000002006323000000004008A
+:1022400006321C0000000004043218300002038033
+:10225000063224E8000000B402322DB00000000075
+:1022600006324000000000B40632300000000020BA
+:10227000063231000000002006323200000000204B
+:102280000632330000000020063234000000002037
+:102290000632350000000020063236000000002023
+:1022A000063237000000002006323800000000200F
+:1022B000063239000000002006323A0000000020FB
+:1022C00006323B000000002006323C0000000020E7
+:1022D00006323D000000002006323E0000000020D3
+:1022E00006323F000000002006321C1000000002F1
+:1022F000063245A000000024063227B8000000B4D2
+:1023000002322DB400000000063242D0000000B4BA
+:1023100006323080000000200632318000000020AC
+:102320000632328000000020063233800000002098
+:102330000632348000000020063235800000002084
+:102340000632368000000020063237800000002070
+:10235000063238800000002006323980000000205C
+:1023600006323A800000002006323B800000002048
+:1023700006323C800000002006323D800000002034
+:1023800006323E800000002006323F800000002020
+:1023900006321C20000000020632463000000024F5
+:1023A0000720040000870000082007800010038237
+:1023B0000724000031A500000724800008190C6ADA
+:1023C00008248EB06C9003840120000000000000FF
+:1023D00001200004000000000120000800000000AF
+:1023E0000120000C0000000001200010000000008F
+:1023F0000120001400000000022000200000000165
+:102400000220002400000002022000280000000337
+:102410000220002C00000000022000300000000418
+:1024200002200034000000010220003800000000FB
+:102430000220003C000000010220004000000004D7
+:1024400002200044000000000220004800000001BB
+:102450000220004C00000003022000500000000099
+:102460000220005400000001022000580000000477
+:102470000220005C0000000002200060000000015B
+:102480000220006400000003022000680000000039
+:102490000220006C00000001022000700000000417
+:1024A00002200074000000000220007800000004F8
+:1024B0000220007C000000030620008000000002D3
+:1024C000022000A400003FFF022000A8000003FF3C
+:1024D000022002240000000002200234000000005C
+:1024E0000220024C00000000022002E40000FFFF76
+:1024F000062020000000080002238BC0000000011D
+:10250000022380000000001002238040000000121F
+:102510000223808000000030022380C00000000EF3
+:102520000C2383000007A1200A2383000000013848
+:102530000B238300000013880A238340000000005F
+:102540000C238340000001F40B23834000000005AE
+:10255000022383800007A120022383C0000001F42E
+:10256000062250000000004206222008000000C899
+:10257000062220000000000206224000000000C6E3
+:1025800004224318000503860622432C0000000B9A
+:10259000042243580005038B0622436C0000000B05
+:1025A0000422439800050390062243AC0000000B70
+:1025B000042243D800050395062243EC0000000BDB
+:1025C000042244180005039A0622442C0000000B44
+:1025D000042244580005039F0622446C0000000BAF
+:1025E00004224498000503A4062244AC0000000B1A
+:1025F000042244D8000503A9062244EC0000000B85
+:1026000004224518000503AE0622452C0000000BED
+:1026100004224558000503B30622456C0000000B58
+:1026200004224598000503B8062245AC0000000BC3
+:10263000042245D8000503BD062245EC0000000B2E
+:1026400004224618000503C20622462C0000000B97
+:1026500004224658000503C70622466C0000000B02
+:1026600004224698000503CC062246AC0000000B6D
+:10267000042246D8000503D1062246EC0000000BD8
+:1026800004224718000503D60622472C0000000B41
+:1026900004224758000503DB0622476C0000000BAC
+:1026A00004224798000503E0062247AC0000000B17
+:1026B000042247D8000503E5062247EC0000000B82
+:1026C00004224818000503EA0622482C0000000BEB
+:1026D00004224858000503EF0622486C0000000B56
+:1026E00004224898000503F4062248AC0000000BC1
+:1026F000042248D8000503F9062248EC0000000B2C
+:1027000004224918000503FE0622492C0000000B94
+:1027100004224958000504030622496C0000000BFE
+:102720000422499800050408062249AC0000000B69
+:10273000042249D80005040D062249EC0000000BD4
+:1027400004224A180005041206224A2C0000000B3D
+:1027500004224A580005041706224A6C0000000BA8
+:1027600004224A980005041C06224AAC0000000B13
+:1027700004224AD80005042106224AEC0000000584
+:1027800006224B000000001704224B5C00010426C7
+:1027900006224B600000000304224B6C000104275A
+:1027A000062238000000004006223000000002002F
+:1027B000042251C00004042806221000000000C0BA
+:1027C000062215C00000024004221EC80008042C86
+:1027D0000622390000000008022251180000000003
+:1027E000062251D00000000606221300000000025D
+:1027F00006221410000000300622392000000008D4
+:102800000222511C00000000062251E800000006D0
+:102810000622130800000002062214D00000003037
+:102820000216100000000028021700080000000235
+:102830000217002C000000030217003C00000004F7
+:1028400002170044000000000217004800000002C8
+:102850000217004C0000009002170050000000908A
+:102860000217005400800090021700580810000062
+:10287000021700600000008A021700640000008058
+:1028800002170068000000810217006C0000008041
+:10289000021700700000000602170078000007D041
+:1028A0000217007C0000076C02170038007C10043F
+:1028B000021700040000000F06164024000000026A
+:1028C000021640700000001C0216420800000001C1
+:1028D0000216421000000001021642200000000112
+:1028E00002164228000000010216423000000001DA
+:1028F000021642380000000102164260000000018A
+:102900000C16401C0003D0900A16401C0000009CCE
+:102910000B16401C000009C40216403000000008DD
+:10292000021640340000000C02164038000000106F
+:102930000216404400000020021640000000000182
+:10294000021640D8000000010216400800000001F5
+:102950000216400C000000010216401000000001A9
+:10296000021642400000000002164248000000002B
+:1029700006164270000000020216425000000000DD
+:1029800002164258000000000616428000000002B5
+:1029900002166008000006140216600C0000060013
+:1029A00002166010000006040216601C0000FFFF03
+:1029B000021660200000FFFF021660240000FFFFE7
+:1029C000021660280000FFFF021660380000002099
+:1029D0000216603C00000020061660400000000265
+:1029E00002166048000000230216604C000000241C
+:1029F00002166050000000250216605400000026F8
+:102A000002166058000000270216605C00000029D2
+:102A1000021660600000002A021660640000002BAD
+:102A2000021660680000002C0216606C0000002D89
+:102A30000616607000000012021660B80000000167
+:102A4000021660BC00000001061660C00000003ED7
+:102A5000021661B800000001061661BC0000001FEC
+:102A60000216623807FFFFFF0216623C0000003FBB
+:102A70000216624007FFFFFF021662440000000FCB
+:102A800001166248000000000116624C00000000C0
+:102A900001166250000000000116625400000000A0
+:102AA00001166258000000000116625C0000000080
+:102AB0000116626000000000011662640000000060
+:102AC00001166268000000000116626C0000000040
+:102AD0000116627000000000011662740000000020
+:102AE00001166278000000000116627C0000000000
+:102AF000021664BC000000010C166000000003E830
+:102B00000A166000000000010B1660000000000AB9
+:102B100002168040000000060216804400000005F6
+:102B2000021680480000000A0216804C00000005D2
+:102B30000216805400000002021680CC000000043F
+:102B4000021680D000000004021680D400000004A9
+:102B5000021680D800000004021680DC0000000489
+:102B6000021680E000000004021680E40000000469
+:102B7000021680E800000004021688040000000429
+:102B8000021680300000007C021680340000003DF8
+:102B9000021680380000003F0216803C0000009CB6
+:102BA000021680F000000007061680F40000000501
+:102BB0000216880C010101010216810800000000C4
+:102BC0000216810C000000040216811000000004AF
+:102BD0000216811400000002021688100801200469
+:102BE00002168118000000050216811C0000000575
+:102BF0000216812000000005021681240000000555
+:102C00000216882C200810010216812800000008F6
+:102C10000216812C00000006021681300000000719
+:102C200002168134000000000216883001010120E4
+:102C300006168138000000040216883401010101E3
+:102C400006168148000000040216883801010101BF
+:102C500006168158000000040216883C010101019B
+:102C6000061681680000000302168174000000014E
+:102C7000021688400101010102168178000000015E
+:102C80000216817C00000001021681800000000114
+:102C9000021681840000000102168844010101012E
+:102CA00002168188000000010216818C00000004D9
+:102CB00002168190000000040216819400000002B8
+:102CC00002168848080120040216819800000005B9
+:102CD0000216819C00000005021681A0000000057C
+:102CE000021681A4000000050216881420081001B5
+:102CF000021681A800000008021681AC0000000640
+:102D0000021681B000000007021681B40000000125
+:102D10000216881801010120021681B80000000186
+:102D2000021681BC00000001021681C000000001F3
+:102D3000021681C4000000010216881C0101010175
+:102D4000021681C800000001021681CC00000001BB
+:102D5000021681D000000001021681D4000000019B
+:102D60000216882001010101021681D8000000012D
+:102D7000021681DC00000001021681E00000000163
+:102D8000021681E4000000010216882401010101FD
+:102D9000021681E800000001021681EC000000012B
+:102DA000021681F0000000010216882801010101CD
+:102DB00002168240FFFF003F061682440000000218
+:102DC0000216824CFFFF003F0216825000000100F5
+:102DD000021682540000010006168258000000020C
+:102DE00002168260000000C002168264000000C06B
+:102DF0000216826800001E000216826C00001E008F
+:102E0000021682700000400002168274000040002A
+:102E100002168278000080000216827C000080008A
+:102E2000021682800000200002168284000020002A
+:102E30000616828800000007021682A40000000126
+:102E4000061682A80000000A021681F400000C0891
+:102E5000021681F800000040021681FC000001000B
+:102E600002168200000000200216820400000017F3
+:102E700002168208000000800216820C0000020088
+:102E8000021682100000000002168218FFFF01FFE8
+:102E900002168214FFFF01FF0216823C000000139D
+:102EA000021680900000013F021680600000014081
+:102EB00002168064000001400616806800000002CF
+:102EC00002168070000000C0061680740000000723
+:102ED0000216809C00000048021680A000000048F6
+:102EE000061680A400000002021680AC0000004814
+:102EF000061680B00000000702168238000080002D
+:102F000002168234000025E40216809400007FFF40
+:102F100002168220000000070216821C0000000733
+:102F2000021682280000000002168224FFFFFFFF25
+:102F300002168230000000000216822CFFFFFFFF05
+:102F4000021680EC000000FF0214000000000001E7
+:102F50000214000C000000010214004000000001F7
+:102F60000214004400007FFF0214000C0000000067
+:102F700002140000000000000214006C00000000B9
+:102F800002140004000000010214003000000001DF
+:102F900002140004000000000214005C00000000A5
+:102FA00002140008000000010214003400000001B7
+:102FB000021400080000000002140060000000007D
+:102FC00006028000000020000202005800000032CB
+:102FD000020200A003150020020200A40315002035
+:102FE000020200A801000030020200AC081000003C
+:102FF000020200B000000033020200B40000003002
+:10300000020200B800000031020200BC0000000310
+:10301000020200C000000006020200C4000000031B
+:10302000020200C800000003020200CC00000002FF
+:10303000020200D000000000020200D400000002E2
+:10304000020200DC00000000020200E000000006B6
+:10305000020200E400000004020200E80000000296
+:10306000020200EC00000002020200F00000000179
+:10307000020200FC00000006020201200000000025
+:103080000202013400000002020201B0000000014F
+:103090000202020C00000001020202140000000102
+:1030A00002020218000000020202040400000001F3
+:1030B0000202040C00000040020204100000004064
+:1030C0000202041C00000004020204200000002090
+:1030D0000202042400000002020204280000001F73
+:1030E00006020500000000120402048000200434DF
+:1030F000020200600000000F0202006400000007EE
+:1031000002020068000000000202006C0000000ED5
+:103110000602007000000004020200F40000000437
+:103120000202000400000001020200080000000189
+:103130000202000C00000001020200100000000169
+:103140000202001400000001020200180000000149
+:103150000202001C00000001020200200000000129
+:103160000202002400000001020200280000000109
+:103170000202002C000000010202003000000001E9
+:1031800002020034000000010202003800000001C9
+:103190000202003C000000010202004000000001A9
+:1031A0000202004400000001020200480000000189
+:1031B0000202004C00000001020200500000000169
+:1031C00002020108000000C802020118000000020B
+:1031D000020201C400000000020201CC0000000055
+:1031E000020201D400000002020201DC0000000221
+:1031F000020201E4000000FF020201EC000000FFF7
+:103200000202010C000000C80202011C00000002C2
+:10321000020201C800000000020201D0000000000C
+:10322000020201D800000002020201E000000002D8
+:10323000020201E8000000FF020201F0000000FFAE
+:1032400007280400008D00000828076800130454B4
+:10325000072C000033FC0000072C800038B20D0062
+:10326000072D000039171B2D072D800005D9297364
+:10327000082D8A204EBC04560128000000000000E2
+:1032800001280004000000000128000800000000E0
+:103290000128000C000000000128001000000000C0
+:1032A0000128001400000000022800200000000196
+:1032B0000228002400000002022800280000000369
+:1032C0000228002C0000000002280030000000044A
+:1032D000022800340000000102280038000000002D
+:1032E0000228003C00000001022800400000000409
+:1032F00002280044000000000228004800000001ED
+:103300000228004C000000030228005000000000CA
+:1033100002280054000000010228005800000004A8
+:103320000228005C0000000002280060000000018C
+:10333000022800640000000302280068000000006A
+:103340000228006C00000001022800700000000448
+:103350000228007400000000022800780000000429
+:103360000228007C00000003062800800000000204
+:10337000022800A400003FFF022800A8000003FF6D
+:10338000022802240000000002280234000000008D
+:103390000228024C00000000022802E40000FFFFA7
+:1033A0000628200000000800022B8BC0000000014E
+:1033B000022B800000000000022B8040000000185B
+:1033C000022B80800000000C022B80C000000066F1
+:1033D0000C2B83000007A1200A2B8300000001387A
+:1033E0000B2B8300000013880A2B83400000000091
+:1033F0000C2B8340000001F40B2B834000000005E0
+:10340000022B83800007A120022B83C0000001F45F
+:10341000062A3D4800000004042A3D5800020458D2
+:10342000062A3D6000000006062A30000000004821
+:10343000062A2008000000C8062A2000000000021A
+:10344000062A31280000008E062A33680000000397
+:10345000042A33740001045A062A3A780000000254
+:10346000042A3A800002045B042A3A700002045DD8
+:10347000042A3E280002045F042A3EB000040461CE
+:10348000042A250000020465062A25080000010020
+:10349000062A297000000004042A29600004046739
+:1034A000042A2F480002046B062A3378000000D853
+:1034B000022A3A3800000000062A3A88000000324A
+:1034C000042A3D880010046D062A502000000002E6
+:1034D000062A503000000002062A500000000002B8
+:1034E000062A501000000002022A50B80000000115
+:1034F000062A50480000000E042A3D780002047D90
+:10350000062A3C1800000026022A50400000000055
+:10351000062A36D8000000D8022A3A3C00000000F3
+:10352000062A3B5000000032042A3DC80010047FE8
+:10353000062A502800000002062A50380000000227
+:10354000062A500800000002062A50180000000257
+:10355000022A50BC00000001062A50800000000E24
+:10356000042A3D800002048F062A3CB00000002699
+:10357000022A504400000000021010080000000160
+:103580000210101000000264021010000003D000AE
+:10359000021010040000003D091018000200049100
+:1035A00009101100001006910610114000000008DB
+:1035B00009101160000806A1061011800000000229
+:1035C00009101188000606A9061011A000000018B5
+:1035D000021010100000000006102400000000E09F
+:1035E0000210201C0000000002102020000000013A
+:1035F000021020C0000000010210200400000001A1
+:10360000021020080000000109103C00000506AF70
+:1036100009103C20000506B409103800000506B961
+:1036200002104028000000100210404400003FFF3C
+:103630000210405800280000021040840084924A82
+:1036400006104C000000010002104058000000006D
+:103650000610806800000004021080000000108046
+:1036600006108028000000020210803800000010C0
+:10367000021080400000FFFF021080440000FFFFA6
+:1036800002108050000000000210810000000000C5
+:10369000061081200000000202108008000002B520
+:1036A0000210801000000000061082000000004A96
+:1036B000021081080001FFFF061081400000000297
+:1036C0000210800000001A80061090000000002404
+:1036D000061091200000004A061093700000004A76
+:1036E000061095C00000004A0210800400001080FF
+:1036F00006108030000000020210803C0000001024
+:10370000021080480000FFFF0210804C0000FFFF05
+:10371000021080540000000002108104000000002C
+:1037200006108128000000020210800C000002B583
+:103730000210801400000000061084000000004AFF
+:103740000210810C0001FFFF0610814800000002FA
+:103750000210800400001A800610909000000024DF
+:10376000061092480000004A061094980000004A93
+:10377000061096E80000004A0212049000E383401D
+:103780000212051400003C10021205200000000285
+:1037900002120494FFFFFFFF02120498FFFFFFFFD5
+:1037A0000212049CFFFFFFFF021204A0FFFFFFFFB5
+:1037B000021204A4FFFFFFFF021204A8FFFFFFFF95
+:1037C000021204ACFFFFFFFF021204B0FFFFFFFF75
+:1037D000021204B8FFFFFFFF021204BCFFFFFFFF4D
+:1037E000021204C0FFFFFFFF021204C4FFFFFFFF2D
+:1037F000021204C8FFFFFFFF021204CCFFFFFFFF0D
+:10380000021204D0FFFFFFFF021204DCFFFFFFFFE4
+:10381000021204E0FFFFFFFF021204E4FFFFFFFFBC
+:10382000021204E8FFFFFFFF021204ECFFFFFFFF9C
+:10383000021204F0FFFFFFFF021204F4FFFFFFFF7C
+:10384000021204F8FFFFFFFF021204FCFFFFFFFF5C
+:1038500002120500FFFFFFFF02120504FFFFFFFF3A
+:1038600002120508FFFFFFFF0212050CFFFFFFFF1A
+:1038700002120510FFFFFFFF021204D4FFFF3330D6
+:10388000021204D8FFFF3340021204B4F0003000EB
+:1038900002120390000000080212039C00000008BE
+:1038A000061203A000000002021203BC0000000484
+:1038B000021203C400000004021203D00000000042
+:1038C000021203DC000000000212036C0000000181
+:1038D000021203680000003F021201BC0000004019
+:1038E000021201C000001808021201C400000803FF
+:1038F000021201C800000803021201CC00000040BF
+:10390000021201D000000003021201D400000803DB
+:10391000021201D800000803021201DC00000803B3
+:10392000021201E000010003021201E4000008039A
+:10393000021201E800000803021201EC000000037B
+:10394000021201F000000003021201F40000000363
+:10395000021201F800000003021201FC0000000343
+:103960000212020000000003021202040000000321
+:1039700002120208000000030212020C0000000301
+:1039800002120210000000030212021400000003E1
+:1039900002120218000000030212021C00000003C1
+:1039A00002120220000000030212022400000003A1
+:1039B00002120228000024030212022C0000002F31
+:1039C0000212023000000009021202340000001945
+:1039D00002120238000001840212023C000001833E
+:1039E0000212024000000306021202440000001905
+:1039F00002120248000000060212024C00000306F8
+:103A000002120250000003060212025400000306D4
+:103A10000212025800000C860212025C000003062B
+:103A20000212026000000306021202640000000697
+:103A300002120268000000060212026C000000067A
+:103A4000021202700000000602120274000000065A
+:103A500002120278000000060212027C000000063A
+:103A6000021202800000000602120284000000061A
+:103A700002120288000000060212028C00000006FA
+:103A800002120290000000060212029400000006DA
+:103A900002120298000000060212029C00000006BA
+:103AA000021202A000000306021202A4000000138A
+:103AB000021202A800000006021202B00000100468
+:103AC000021202B400001004021203240010644029
+:103AD0000212032800106440021201B0000000012D
+:103AE0000600A000000000160200A06CBF5C0000F1
+:103AF0000200A070FFF51FEF0200A0740000FFFF9E
+:103B00000200A078F00003E00200A07C00000000AA
+:103B10000200A0800000A0000600A08400000005B4
+:103B20000200A0980FE000000600A09C0000001416
+:103B30000200A0EC555400000200A0F05555555568
+:103B40000200A0F4000055550200A0F8F0000000AB
+:103B50000200A0FC555400000200A1005555555527
+:103B60000200A104000055550200A108F000000069
+:103B70000600A22C000000040200A0600000030761
+:103B80000200A10CBF5C00000200A110FFF51FEFB6
+:103B90000200A1140000FFFF0200A118F00003E0E2
+:103BA0000200A11C000000000200A1200000A000F3
+:103BB0000600A124000000050200A1380FE000006B
+:103BC0000600A13C000000140200A18C5554000026
+:103BD0000200A190555555550200A194000055557D
+:103BE0000200A198F00000000200A19C55540000C2
+:103BF0000200A1A0555555550200A1A4000055553D
+:103C00000200A1A8F00000000600A23C0000000491
+:103C10000200A06400000307000000000000000094
+:103C20000000002E00000000000000000000000066
+:103C30000000000000000000000000000000000084
+:103C40000000000000000000000000000000000074
+:103C50000000000000000000000000000000000064
+:103C60000000000000000000000000000000000054
+:103C70000000000000000000002E004D00000000C9
+:103C80000000000000000000000000000000000034
+:103C90000000000000000000000000000000000024
+:103CA00000000000004D008B00000000000000003C
+:103CB0000000000000000000000000000000000004
+:103CC00000000000000000000000000000000000F4
+:103CD000008B009000900094009400980000000079
+:103CE00000000000000000000000000000000000D4
+:103CF000000000000000000000000000009802DE4C
+:103D000002DE02E802E802F200000000000000000B
+:103D100000000000000000000000000000000000A3
+:103D20000000000000000000000000000000000093
+:103D30000000000000000000000000000000000083
+:103D40000000000000000000000000000000000073
+:103D50000000000000000000000000000000000063
+:103D60000000000000000000000000000000000053
+:103D70000000000000000000000000000000000043
+:103D80000000000000000000000000000000000033
+:103D90000000000000000000000000000000000023
+:103DA0000000000000000000000000000000000013
+:103DB0000000000000000000000000000000000003
+:103DC00000000000000000000000000000000000F3
+:103DD000000000000000000002F202FA00000000F3
+:103DE00000000000000000000000000000000000D3
+:103DF00000000000000000000000000000000000C3
+:103E000000000000000000000000000000000000B2
+:103E100000000000000000000000000000000000A2
+:103E20000000000000000000000000000000000092
+:103E300002FA02FF02FF030A030A03150000000052
+:103E40000000000000000000000000000000000072
+:103E50000000000000000000000000000000000062
+:103E60000000000000000000000000000000000052
+:103E70000000000000000000000000000000000042
+:103E80000000000000000000031503160000000001
+:103E90000000000000000000000000000000000022
+:103EA0000000000000000000000000000000000012
+:103EB000000000000316035700000000000000008F
+:103EC00000000000000000000000000000000000F2
+:103ED00000000000000000000000000000000000E2
+:103EE0000357037B000000000000000000000000FA
+:103EF00000000000000000000000000000000000C2
+:103F0000000000000000000000000000037B03BB75
+:103F100000000000000000000000000000000000A1
+:103F20000000000000000000000000000000000091
+:103F3000000000000000000003BB03F700000000C9
+:103F40000000000000000000000000000000000071
+:103F50000000000000000000000000000000000061
+:103F60000000000003F7043D043D045204520467BE
+:103F70000000000000000000000000000000000041
+:103F80000000000000000000000000000000000031
+:103F9000046704ED04ED04F204F204F700000000ED
+:103FA0000000000000000000000000000000000011
+:103FB00000000000000000000000000004F704F80A
+:103FC00000000000000000000000000000000000F1
+:103FD00000000000000000000000000000000000E1
+:103FE000000000000000000004F8050A00000000C6
+:103FF00000000000000000000000000000000000C1
+:1040000000000000000000000000000000000000B0
+:1040100000000000050A051F051F052205220525D1
+:104020000000000000000000000000000000000090
+:104030000000000000000000000000000000000080
+:1040400005250555000000000000000000000000EC
+:104050000000000000000000000000000000000060
+:10406000000000000000000000000000055505DC15
+:104070000000000000000000000000000000000040
+:104080000000000000000000000000000000000030
+:10409000000000000000000005DC05E305E305E783
+:1040A00005E705EB00000000000000000000000034
+:1040B0000000000000000000000000000000000000
+:1040C0000000000005EB062B062B06330633063BEB
+:1040D00000000000000000000000000000000000E0
+:1040E00000000000000000000000000000000000D0
+:1040F000063B068806880695069506A20000000085
+:1041000000000000000000000000000000000000AF
+:1041100000000000000000000000000006A206AE43
+:10412000000000000000000000000000000000008F
+:10413000000000000000000000000000000000007F
+:10414000000000000000000006AE06B40000000001
+:10415000000000000000000000000000000000005F
+:10416000000000000000000000000000000000004F
+:104170000000000006B406B70000000000000000C8
+:10418000000000000000000000000000000000002F
+:10419000000000000000000000000000000000001F
+:1041A00006B706BD0000000000000000000000008F
+:1041B00000000000000000000000000000000000FF
+:1041C00000000000000000000000000006BD06BE68
+:1041D00006BE06D006D006E2000000000000000087
+:1041E00000000000000000000000000000000000CF
+:1041F000000000000000000006E2074F0000000081
+:1042000000000000000000000000000000000000AE
+:10421000000000000000000000000000000000009E
+:1042200000000000074F0750075007630763077639
+:10423000000000000000000000000000000000007E
+:10424000000000000000000000000000000000006E
+:10425000000000000000000000000000000000005E
+:10426000000000000000000000000000000000004E
+:10427000000000000000000000000000000000003E
+:10428000000000000000000000000000000000002E
+:10429000000000000000000000000000000000001E
+:1042A000000000000000000000000000000000000E
+:1042B00000000000000000000000000000000000FE
+:1042C00000000000000000000000000000000000EE
+:1042D00000000000000000000000000000000000DE
+:1042E00000000000000000000000000000000000CE
+:1042F00000000000000000000000000000000000BE
+:1043000000000000000000000000000000000000AD
+:10431000000000000000000000000000000000009D
+:10432000000000000000000000000000000000008D
+:1043300000010000000204C00003098000040E40D8
+:1043400000051300000617C000071C80000821406C
+:1043500000092600000A2AC0000B2F80000C344000
+:10436000000D3900000E3DC0000F42800010474094
+:1043700000114C00001250C00013558000145A4028
+:1043800000155F00001663C00017688000186D40BC
+:1043900000197200001A76C0001B7B80001C804050
+:1043A000001D8500001E89C0001F8E800000934004
+:1043B00000002000000040000000600000008000BD
+:1043C0000000A0000000C0000000E00000010000AC
+:1043D0000001200000014000000160000001800099
+:1043E0000001A0000001C0000001E0000002000088
+:1043F0000002200000024000000260000002800075
+:104400000002A0000002C0000002E0000003000063
+:104410000003200000034000000360000003800050
+:104420000003A0000003C0000003E000000400003F
+:10443000000420000004400000046000000480002C
+:104440000004A0000004C0000004E000000500001B
+:104450000005200000054000000560000005800008
+:104460000005A0000005C0000005E00000060000F7
+:1044700000062000000640000006600000068000E4
+:104480000006A0000006C0000006E00000070000D3
+:1044900000072000000740000007600000078000C0
+:1044A0000007A0000007C0000007E00000080000AF
+:1044B000000820000008400000086000000880009C
+:1044C0000008A0000008C0000008E000000900008B
+:1044D0000009200000094000000960000009800078
+:1044E0000009A0000009C0000009E000000A000067
+:1044F000000A2000000A4000000A6000000A800054
+:10450000000AA000000AC000000AE000000B000042
+:10451000000B2000000B4000000B6000000B80002F
+:10452000000BA000000BC000000BE000000C00001E
+:10453000000C2000000C4000000C6000000C80000B
+:10454000000CA000000CC000000CE000000D0000FA
+:10455000000D2000000D4000000D6000000D8000E7
+:10456000000DA000000DC000000DE000000E0000D6
+:10457000000E2000000E4000000E6000000E8000C3
+:10458000000EA000000EC000000EE000000F0000B2
+:10459000000F2000000F4000000F6000000F80009F
+:1045A000000FA000000FC000000FE000001000008E
+:1045B000001020000010400000106000001080007B
+:1045C0000010A0000010C0000010E000001100006A
+:1045D0000011200000114000001160000011800057
+:1045E0000011A0000011C0000011E0000012000046
+:1045F0000012200000124000001260000012800033
+:104600000012A0000012C0000012E0000013000021
+:10461000001320000013400000136000001380000E
+:104620000013A0000013C0000013E00000140000FD
+:1046300000142000001440000014600000148000EA
+:104640000014A0000014C0000014E00000150000D9
+:1046500000152000001540000015600000158000C6
+:104660000015A0000015C0000015E00000160000B5
+:1046700000162000001640000016600000168000A2
+:104680000016A0000016C0000016E0000017000091
+:10469000001720000017400000176000001780007E
+:1046A0000017A0000017C0000017E000001800006D
+:1046B000001820000018400000186000001880005A
+:1046C0000018A0000018C0000018E0000019000049
+:1046D0000019200000194000001960000019800036
+:1046E0000019A0000019C0000019E000001A000025
+:1046F000001A2000001A4000001A6000001A800012
+:10470000001AA000001AC000001AE000001B000000
+:10471000001B2000001B4000001B6000001B8000ED
+:10472000001BA000001BC000001BE000001C0000DC
+:10473000001C2000001C4000001C6000001C8000C9
+:10474000001CA000001CC000001CE000001D0000B8
+:10475000001D2000001D4000001D6000001D8000A5
+:10476000001DA000001DC000001DE000001E000094
+:10477000001E2000001E4000001E6000001E800081
+:10478000001EA000001EC000001EE000001F000070
+:10479000001F2000001F4000001F6000001F80005D
+:1047A000001FA000001FC000001FE000002000004C
+:1047B0000020200000204000002060000020800039
+:1047C0000020A0000020C0000020E0000021000028
+:1047D0000021200000214000002160000021800015
+:1047E0000021A0000021C0000021E0000022000004
+:1047F00000222000002240000022600000228000F1
+:104800000022A0000022C0000022E00000230000DF
+:1048100000232000002340000023600000238000CC
+:104820000023A0000023C0000023E00000240000BB
+:1048300000242000002440000024600000248000A8
+:104840000024A0000024C0000024E0000025000097
+:104850000025200000254000002560000025800084
+:104860000025A0000025C0000025E0000026000073
+:104870000026200000264000002660000026800060
+:104880000026A0000026C0000026E000002700004F
+:10489000002720000027400000276000002780003C
+:1048A0000027A0000027C0000027E000002800002B
+:1048B0000028200000284000002860000028800018
+:1048C0000028A0000028C0000028E0000029000007
+:1048D00000292000002940000029600000298000F4
+:1048E0000029A0000029C0000029E000002A0000E3
+:1048F000002A2000002A4000002A6000002A8000D0
+:10490000002AA000002AC000002AE000002B0000BE
+:10491000002B2000002B4000002B6000002B8000AB
+:10492000002BA000002BC000002BE000002C00009A
+:10493000002C2000002C4000002C6000002C800087
+:10494000002CA000002CC000002CE000002D000076
+:10495000002D2000002D4000002D6000002D800063
+:10496000002DA000002DC000002DE000002E000052
+:10497000002E2000002E4000002E6000002E80003F
+:10498000002EA000002EC000002EE000002F00002E
+:10499000002F2000002F4000002F6000002F80001B
+:1049A000002FA000002FC000002FE000003000000A
+:1049B00000302000003040000030600000308000F7
+:1049C0000030A0000030C0000030E00000310000E6
+:1049D00000312000003140000031600000318000D3
+:1049E0000031A0000031C0000031E00000320000C2
+:1049F00000322000003240000032600000328000AF
+:104A00000032A0000032C0000032E000003300009D
+:104A1000003320000033400000336000003380008A
+:104A20000033A0000033C0000033E0000034000079
+:104A30000034200000344000003460000034800066
+:104A40000034A0000034C0000034E0000035000055
+:104A50000035200000354000003560000035800042
+:104A60000035A0000035C0000035E0000036000031
+:104A7000003620000036400000366000003680001E
+:104A80000036A0000036C0000036E000003700000D
+:104A900000372000003740000037600000378000FA
+:104AA0000037A0000037C0000037E00000380000E9
+:104AB00000382000003840000038600000388000D6
+:104AC0000038A0000038C0000038E00000390000C5
+:104AD00000392000003940000039600000398000B2
+:104AE0000039A0000039C0000039E000003A0000A1
+:104AF000003A2000003A4000003A6000003A80008E
+:104B0000003AA000003AC000003AE000003B00007C
+:104B1000003B2000003B4000003B6000003B800069
+:104B2000003BA000003BC000003BE000003C000058
+:104B3000003C2000003C4000003C6000003C800045
+:104B4000003CA000003CC000003CE000003D000034
+:104B5000003D2000003D4000003D6000003D800021
+:104B6000003DA000003DC000003DE000003E000010
+:104B7000003E2000003E4000003E6000003E8000FD
+:104B8000003EA000003EC000003EE000003F0000EC
+:104B9000003F2000003F4000003F6000003F8000D9
+:104BA000003FA000003FC000003FE000003FE001E8
+:104BB00000000000000001FF0000020000007FF87C
+:104BC00000007FF80000016A0000150000000001ED
+:104BD0000000FF00000000000000FF0000000000D7
+:104BE00000000000140AFF000000000100000000A7
+:104BF00000201001000000000100860000000100FC
+:104C00000000860200008604000086060000860878
+:104C10000000860A0000860C0000860E0000861048
+:104C20000000861200008614000086160000861818
+:104C30000000861A0000861C0000861E00008620E8
+:104C400000008622000086240000862600008628B8
+:104C50000000862A0000862C0000862E0000863088
+:104C60000000863200008634000086360000863858
+:104C70000000863A0000863C0000863E0000864028
+:104C800000008642000086440000864600008648F8
+:104C90000000864A0000864C0000864E00008650C8
+:104CA0000000865200008654000086560000865898
+:104CB0000000865A0000865C0000865E0000866068
+:104CC0000000866200008664000086660000866838
+:104CD0000000866A0000866C0000866E0000867008
+:104CE00000008672000086740000867600008678D8
+:104CF0000000867A0000867C0000867E00008680A8
+:104D00000000868200008684000086860000868877
+:104D10000000868A0000868C0000868E0000869047
+:104D20000000869200008694000086960000869817
+:104D30000000869A0000869C0000869E000086A0E7
+:104D4000000086A2000086A4000086A6000086A8B7
+:104D5000000086AA000086AC000086AE000086B087
+:104D6000000086B2000086B4000086B6000086B857
+:104D7000000086BA000086BC000086BE000086C027
+:104D8000000086C2000086C4000086C6000086C8F7
+:104D9000000086CA000086CC000086CE000086D0C7
+:104DA000000086D2000086D4000086D6000086D897
+:104DB000000086DA000086DC000086DE000086E067
+:104DC000000086E2000086E4000086E6000086E837
+:104DD000000086EA000086EC000086EE000086F007
+:104DE000000086F2000086F4000086F6000086F8D7
+:104DF000000086FA000086FC000086FE00008700A6
+:104E00000000870200008704000087060000870872
+:104E10000000870A0000870C0000870E0000871042
+:104E20000000871200008714000087160000871812
+:104E30000000871A0000871C0000871E00008720E2
+:104E400000008722000087240000872600008728B2
+:104E50000000872A0000872C0000872E0000873082
+:104E60000000873200008734000087360000873852
+:104E70000000873A0000873C0000873E0000874022
+:104E800000008742000087440000874600008748F2
+:104E90000000874A0000874C0000874E00008750C2
+:104EA0000000875200008754000087560000875892
+:104EB0000000875A0000875C0000875E0000876062
+:104EC0000000876200008764000087660000876832
+:104ED0000000876A0000876C0000876E0000877002
+:104EE00000008772000087740000877600008778D2
+:104EF0000000877A0000877C0000877E00008780A2
+:104F00000000878200008784000087860000878871
+:104F10000000878A0000878C0000878E0000879041
+:104F20000000879200008794000087960000879811
+:104F30000000879A0000879C0000879E000087A0E1
+:104F4000000087A2000087A4000087A6000087A8B1
+:104F5000000087AA000087AC000087AE000087B081
+:104F6000000087B2000087B4000087B6000087B851
+:104F7000000087BA000087BC000087BE000087C021
+:104F8000000087C2000087C4000087C6000087C8F1
+:104F9000000087CA000087CC000087CE000087D0C1
+:104FA000000087D2000087D4000087D6000087D891
+:104FB000000087DA000087DC000087DE000087E061
+:104FC000000087E2000087E4000087E6000087E831
+:104FD000000087EA000087EC000087EE000087F001
+:104FE000000087F2000087F4000087F6000087F8D1
+:104FF000000087FA000087FC000087FEFFFFFFFF2C
+:10500000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0
+:10501000FFFFFFFFFFFFFFFFFFFFFFFF0000000399
+:1050200000BEBC20000000000000000500000003DE
+:1050300000BEBC20000000000000000500002000B1
+:10504000000040C000006180000082400000A3001A
+:105050000000C3C00000E4800001054000012600FC
+:10506000000146C000016780000188400001A900DE
+:105070000001C9C00001EA8000020B4000022C00C0
+:1050800000024CC000026D8000028E400002AF00A2
+:105090000002CFC00002F08000001140000080003C
+:1050A000000103800001870000020A8000028E00D8
+:1050B00000031180000395000004188000049C0088
+:1050C00000051F800005A300000626800006AA0038
+:1050D00000072D800007B100000834800008B800E8
+:1050E00000093B800009BF00000A4280000AC60098
+:1050F000000B4980000BCD00000C5080000CD40048
+:10510000000D578000005B0000007FF800007FF872
+:1051100000000166000015000000FF000000000014
+:105120000000FF0000000000000019000000000067
+:1051300000000000FFFFFFFF00007FF800007FF885
+:105140000000035F000035000000FF000FFFFFFFBD
+:105150000000FF000FFFFFFF000000FF0000FF0046
+:105160000FFFFFFF0000FF000FFFFFFF000000FF29
+:105170000000FF000FFFFFFF0000FF000FFFFFFF19
+:10518000000000FF0000FF000FFFFFFF0000FF0016
+:105190000FFFFFFF000000FF0000FF000FFFFFFFF9
+:1051A0000000FF000FFFFFFF000000FF0000FF00F6
+:1051B0000FFFFFFF0000FF000FFFFFFF000000FFD9
+:1051C0000000FF000FFFFFFF0000FF000FFFFFFFC9
+:1051D000000000FF0000FF000FFFFFFF0000FF00C6
+:1051E0000FFFFFFF000000FF0000FF000FFFFFFFA9
+:1051F0000000FF000FFFFFFF000000FF0000FF00A6
+:105200000FFFFFFF0000FF000FFFFFFF000000FF88
+:105210000000FF000FFFFFFF0000FF000FFFFFFF78
+:10522000000000FF0000FF000FFFFFFF0000FF0075
+:105230000FFFFFFF000000FF0000FF000FFFFFFF58
+:105240000000FF000FFFFFFF000000FF0000FF0055
+:105250000FFFFFFF0000FF000FFFFFFF000000FF38
+:105260000000FF000FFFFFFF0000FF000FFFFFFF28
+:10527000000000FF0000FF000FFFFFFF0000FF0025
+:105280000FFFFFFF000000FF0000FF000FFFFFFF08
+:105290000000FF000FFFFFFF000000FF0000FF0005
+:1052A0000FFFFFFF0000FF000FFFFFFF000000FFE8
+:1052B0000000FF000FFFFFFF0000FF000FFFFFFFD8
+:1052C000000000FF0000FF000FFFFFFF0000FF00D5
+:1052D0000FFFFFFF000000FF0000FF000FFFFFFFB8
+:1052E0000000FF000FFFFFFF000000FF0000FF00B5
+:1052F0000FFFFFFF0000FF000FFFFFFF000000FF98
+:105300000000FF000FFFFFFF0000FF000FFFFFFF87
+:10531000000000FF0000FF000FFFFFFF0000FF0084
+:105320000FFFFFFF000000FF0000FF000FFFFFFF67
+:105330000000FF000FFFFFFF000000FF0000FF0064
+:105340000FFFFFFF0000FF000FFFFFFF000000FF47
+:105350000000FF000FFFFFFF0000FF000FFFFFFF37
+:10536000000000FF0000FF000FFFFFFF0000FF0034
+:105370000FFFFFFF000000FF0000FF000FFFFFFF17
+:105380000000FF000FFFFFFF000000FF0000FF0014
+:105390000FFFFFFF0000FF000FFFFFFF000000FFF7
+:1053A0000000FF000FFFFFFF0000FF000FFFFFFFE7
+:1053B000000000FF0000FF000FFFFFFF0000FF00E4
+:1053C0000FFFFFFF000000FF000000FF000000FFD4
+:1053D0000000FF00000000000000FF0000000000CF
+:1053E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD
+:1053F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD
+:1054000000001000000020800000310000004180FA
+:1054100000005200000062800000730000008380E2
+:10542000000094000000A4800000B5000000C580CA
+:105430000000D6000000E6800000F70000010780B1
+:105440000001180000012880000139000001498096
+:1054500000015A0000016A8000017B0000018B807E
+:1054600000019C000001AC800001BD000001CD8066
+:105470000001DE000001EE8000000F0000000000CF
+:1054800000007FF800007FF80000021A00003500DD
+:1054900010000000000028AD00010001FFFFFFFF29
+:1054A000FFFFFFFF00220006CCCCCCC17058103C9F
+:1054B000000000000000FF00000000000000FF00EE
+:1054C000000000000000000000000001CCCC020140
+:1054D000CCCCCCCCCCCC0201CCCCCCCC00000000D1
+:1054E000FFFFFFFF0000FFFF000000000000FFFFC4
+:1054F000000000000000FFFF000000000000FFFFB0
+:10550000000000000000FFFF000000000000FFFF9F
+:10551000000000000000FFFF000000000000FFFF8F
+:1055200000000000000E0000011600D60000FFFF82
+:10553000000000000000FFFF000000000000FFFF6F
+:10554000000000000000FFFF000000000000FFFF5F
+:10555000000000000000FFFF000000000000FFFF4F
+:10556000000000000000FFFF0000000000720000CB
+:10557000012300F3FFFFFFF3318FFFFF0C30C30C5B
+:10558000C30C30C3CF3CF300F3CF3CF30000CF3C5F
+:10559000CDCDCDCDFFFFFFF130EFFFFF0C30C30CC1
+:1055A000C30C30C3CF3CF300F3CF3CF30001CF3C3E
+:1055B000CDCDCDCDFFFFFFF6305FFFFF0C30C30C2C
+:1055C000C30C30C3CF3CF300F3CF3CF30002CF3C1D
+:1055D000CDCDCDCDFFFFF4061CBFFFFF0C30C305C2
+:1055E000C30C30C3CF300014F3CF3CF30004CF3CE6
+:1055F000CDCDCDCDFFFFFFF2304FFFFF0C30C30C00
+:10560000C30C30C3CF3CF300F3CF3CF30008CF3CD6
+:10561000CDCDCDCDFFFFFFFA302FFFFF0C30C30CF7
+:10562000C30C30C3CF3CF300F3CF3CF30010CF3CAE
+:10563000CDCDCDCDFFFFFFF731EFFFFF0C30C30C19
+:10564000C30C30C3CF3CF300F3CF3CF30020CF3C7E
+:10565000CDCDCDCDFFFFFFF5302FFFFF0C30C30CBC
+:10566000C30C30C3CF3CF300F3CF3CF30040CF3C3E
+:10567000CDCDCDCDFFFFFFF3318FFFFF0C30C30C3D
+:10568000C30C30C3CF3CF300F3CF3CF30000CF3C5E
+:10569000CDCDCDCDFFFFFFF1310FFFFF0C30C30C9F
+:1056A000C30C30C3CF3CF300F3CF3CF30001CF3C3D
+:1056B000CDCDCDCDFFFFFFF6305FFFFF0C30C30C2B
+:1056C000C30C30C3CF3CF300F3CF3CF30002CF3C1C
+:1056D000CDCDCDCDFFFFF4061CBFFFFF0C30C305C1
+:1056E000C30C30C3CF300014F3CF3CF30004CF3CE5
+:1056F000CDCDCDCDFFFFFFF2304FFFFF0C30C30CFF
+:10570000C30C30C3CF3CF300F3CF3CF30008CF3CD5
+:10571000CDCDCDCDFFFFFFFA302FFFFF0C30C30CF6
+:10572000C30C30C3CF3CF300F3CF3CF30010CF3CAD
+:10573000CDCDCDCDFFFFFFF730EFFFFF0C30C30C19
+:10574000C30C30C3CF3CF300F3CF3CF30020CF3C7D
+:10575000CDCDCDCDFFFFFFF5304FFFFF0C30C30C9B
+:10576000C30C30C3CF3CF300F3CF3CF30040CF3C3D
+:10577000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CF1
+:10578000C30C30C3CF3CF3CCF3CF3CF30000CF3C91
+:10579000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CD1
+:1057A000C30C30C3CF3CF3CCF3CF3CF30001CF3C70
+:1057B000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CB1
+:1057C000C30C30C3CF3CF3CCF3CF3CF30002CF3C4F
+:1057D000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C91
+:1057E000C30C30C3CF3CF3CCF3CF3CF30004CF3C2D
+:1057F000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C71
+:10580000C30C30C3CF3CF3CCF3CF3CF30008CF3C08
+:10581000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C50
+:10582000C30C30C3CF3CF3CCF3CF3CF30010CF3CE0
+:10583000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C30
+:10584000C30C30C3CF3CF3CCF3CF3CF30020CF3CB0
+:10585000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C10
+:10586000C30C30C3CF3CF3CCF3CF3CF30040CF3C70
+:10587000CDCDCDCDFFFFFFF3320FFFFF0C30C30CBA
+:10588000C30C30C3CF3CF300F3CF3CF30000CF3C5C
+:10589000CDCDCDCDFFFFFFF1310FFFFF0C30C30C9D
+:1058A000C30C30C3CF3CF300F3CF3CF30001CF3C3B
+:1058B000CDCDCDCDFFFFFFF6305FFFFF0C30C30C29
+:1058C000C30C30C3CF3CF300F3CF3CF30002CF3C1A
+:1058D000CDCDCDCDFFFFF4061CBFFFFF0C30C305BF
+:1058E000C30C30C3CF300014F3CF3CF30004CF3CE3
+:1058F000CDCDCDCDFFFFFFF2304FFFFF0C30C30CFD
+:10590000C30C30C3CF3CF300F3CF3CF30008CF3CD3
+:10591000CDCDCDCDFFFFFF8A042FFFFF0C30C30C90
+:10592000C30C30C3CF3CC000F3CF3CF30010CF3CDE
+:10593000CDCDCDCDFFFFFF9705CFFFFF0C30C30CC2
+:10594000C30C30C3CF3CC000F3CF3CF30020CF3CAE
+:10595000CDCDCDCDFFFFFFF5310FFFFF0C30C30CD8
+:10596000C30C30C3CF3CF300F3CF3CF30040CF3C3B
+:10597000CDCDCDCDFFFFFFF3300FFFFF0C30C30CBB
+:10598000C30C30C3CF3CF300F3CF3CF30000CF3C5B
+:10599000CDCDCDCDFFFFFFF1300FFFFF0C30C30C9D
+:1059A000C30C30C3CF3CF300F3CF3CF30001CF3C3A
+:1059B000CDCDCDCDFFFFFFF6305FFFFF0C30C30C28
+:1059C000C30C30C3CF3CF300F3CF3CF30002CF3C19
+:1059D000CDCDCDCDFFFFF4061CBFFFFF0C30C305BE
+:1059E000C30C30C3CF300014F3CF3CF30004CF3CE2
+:1059F000CDCDCDCDFFFFFFF2304FFFFF0C30C30CFC
+:105A0000C30C30C3CF3CF300F3CF3CF30008CF3CD2
+:105A1000CDCDCDCDFFFFFFFA302FFFFF0C30C30CF3
+:105A2000C30C30C3CF3CF300F3CF3CF30010CF3CAA
+:105A3000CDCDCDCDFFFFFF97040FFFFF0C30C30C82
+:105A4000C30C30C3CF3CC000F3CF3CF30020CF3CAD
+:105A5000CDCDCDCDFFFFFFF5300FFFFF0C30C30CD8
+:105A6000C30C30C3CF3CF300F3CF3CF30040CF3C3A
+:105A7000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CEE
+:105A8000C30C30C3CF3CF3CCF3CF3CF30000CF3C8E
+:105A9000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CCE
+:105AA000C30C30C3CF3CF3CCF3CF3CF30001CF3C6D
+:105AB000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CAE
+:105AC000C30C30C3CF3CF3CCF3CF3CF30002CF3C4C
+:105AD000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C8E
+:105AE000C30C30C3CF3CF3CCF3CF3CF30004CF3C2A
+:105AF000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C6E
+:105B0000C30C30C3CF3CF3CCF3CF3CF30008CF3C05
+:105B1000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C4D
+:105B2000C30C30C3CF3CF3CCF3CF3CF30010CF3CDD
+:105B3000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C2D
+:105B4000C30C30C3CF3CF3CCF3CF3CF30020CF3CAD
+:105B5000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C0D
+:105B6000C30C30C3CF3CF3CCF3CF3CF30040CF3C6D
+:105B7000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CED
+:105B8000C30C30C3CF3CF3CCF3CF3CF30000CF3C8D
+:105B9000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CCD
+:105BA000C30C30C3CF3CF3CCF3CF3CF30001CF3C6C
+:105BB000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CAD
+:105BC000C30C30C3CF3CF3CCF3CF3CF30002CF3C4B
+:105BD000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C8D
+:105BE000C30C30C3CF3CF3CCF3CF3CF30004CF3C29
+:105BF000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C6D
+:105C0000C30C30C3CF3CF3CCF3CF3CF30008CF3C04
+:105C1000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C4C
+:105C2000C30C30C3CF3CF3CCF3CF3CF30010CF3CDC
+:105C3000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C2C
+:105C4000C30C30C3CF3CF3CCF3CF3CF30020CF3CAC
+:105C5000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C0C
+:105C6000C30C30C3CF3CF3CCF3CF3CF30040CF3C6C
+:105C7000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CEC
+:105C8000C30C30C3CF3CF3CCF3CF3CF30000CF3C8C
+:105C9000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CCC
+:105CA000C30C30C3CF3CF3CCF3CF3CF30001CF3C6B
+:105CB000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CAC
+:105CC000C30C30C3CF3CF3CCF3CF3CF30002CF3C4A
+:105CD000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C8C
+:105CE000C30C30C3CF3CF3CCF3CF3CF30004CF3C28
+:105CF000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C6C
+:105D0000C30C30C3CF3CF3CCF3CF3CF30008CF3C03
+:105D1000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C4B
+:105D2000C30C30C3CF3CF3CCF3CF3CF30010CF3CDB
+:105D3000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C2B
+:105D4000C30C30C3CF3CF3CCF3CF3CF30020CF3CAB
+:105D5000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C0B
+:105D6000C30C30C3CF3CF3CCF3CF3CF30040CF3C6B
+:105D7000CDCDCDCD000C0000000700C00002813069
+:105D8000000B81580002021000010230000F024097
+:105D900000010330000C0000000800C00002814038
+:105DA000000B81680002022000010240000702503F
+:105DB000000202C000100000000801000002818003
+:105DC000000B81A80002026000018280000E829810
+:105DD0000008038000028000000B8028000200E021
+:105DE000000101000000811000000118CCCCCCCCD7
+:105DF000CCCCCCCCCCCCCCCCCCCCCCCC00002000F3
+:105E0000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCD2
+:105E100000002000CCCCCCCCCCCCCCCCCCCCCCCCD2
+:105E2000CCCCCCCC00002000000000000000000022
+:105E30001F8B080000000000000BFB51CFC0F003D7
+:105E40008A5B591918EC39107C7AE0A58C94E95FCB
+:105E5000C3CCC0B019882F00F12E66D2F57F9642D0
+:105E6000B0CF483030BC03E29D620C0C2B2411E211
+:105E7000D1D20C0CFF81FCD350313BA09EDD52945B
+:105E8000B97B140F0E7C471D957F5C15428740C57A
+:105E9000EFA2C99F80CACF5780D0F7D4B19BBB0077
+:105EA0002A0F0001FE3753600300000000000000CD
+:105EB0001F8B080000000000000BED7D0B7454D513
+:105EC000B9F037E735672633939390C704123C83C4
+:105ED00001820618303C54AA93F068E8A53A3C04C5
+:105EE000E447195034822411D39AB6FC7F4EC8E49B
+:105EF0000102C617A52DDA81E2BDD185BDD1466B61
+:105F0000FB6B5710A5B9B5772DA4A8B4451BD06B72
+:105F1000C10237DA72A1FFB2977F7F7BEF939C7348
+:105F20003293876257EF6AC3D2937DCE7E7CFB7B30
+:105F3000EDEF754E141803CA8D0097F0875CD7B942
+:105F40000020BBEF6ADE073556095900154145DFD1
+:105F50004A9EAD17237A7D09B97F85107E0AF0FE2F
+:105F6000B839300940C671790053F17FD300A4CC11
+:105F7000969C988FDC1357A6E3D59CCFBC5648005F
+:105F8000DA547CBE6D5CB2E7BDEB27E49E6E15E88B
+:105F9000CFA53100B5C76F9DFF9AD926FF8D027F2F
+:105FA000D68757935F66C08C4B22C027F98BD23BB4
+:105FB000F5D4F37D54D7A54963012ED42D9FFFDA84
+:105FC000D8FECFD78B50DD5EDCFFFE75A052BC80C3
+:105FD0006A28D1897DFB5E0FD0E9CE0468CEDFCC84
+:105FE000F69B4590752DB9DFF66F9A54D407E77A82
+:105FF00089F49BDA7F3F00069DD79CA7777CA2CBD4
+:1060000036DE39AE773E3E1E24F26F3A00ED42F6A0
+:106010003FCD15BB11EFBBF3171923497BFDFE5292
+:106020008815A786BF975E9F117E735C4A3AF27E01
+:106030009FEC6B6822AC071F2AAD375D47F8E8F785
+:10604000CF89E1CDC847BBC7CF8100B90F8C8F4C3A
+:106050003A9DDED790938C3F52D1E97F8387F29FA0
+:10606000C95F15C2CAF44EF8ECFC7537F2579A8531
+:10607000BFDA170F38DF67E5AFB893BF383ECEB44D
+:10608000B3FDC3AE118C2E9C5E4EFAA4A4CB671D4B
+:10609000D79F9FB6205EDDED8B8D9190849F38BC9D
+:1060A00026BD3E2FBC83F111402BA5334054C4F5CF
+:1060B000FBEEB3ABB7447381409B87711F23F83E5F
+:1060C00046C49AEE13089C7E682D1F1722EDEED56C
+:1060D0000B500EFCC7E79FC66B6371595719E997C0
+:1060E0001ED616CE23576F11B8709F5B70B2EB703F
+:1060F000BE4AA3B418E905B4FD8C7147C4403C40C6
+:10610000042007E06B7C4F00822E91B682BF8E493F
+:10611000B60F053A193E5C97DCFDC7A7DABFD23748
+:106120000E2E85F0FF1B01F737D8385840C6A988D6
+:106130000E83E23BC3314F7A843D37E9E3074B9B43
+:106140003C3F8ABF507CDFF757594F8347549DA887
+:1061500014A550D012D81FB40C89B4BD7388222264
+:10616000678D16EC31047D70BA340294B7FB28C3F6
+:10617000C1427F1F7CA7C145F7135C130F3591798E
+:10618000CF97F8C2943F34F2DFD4FEFB79B00E19FA
+:10619000D9D22EDE0BC8E771C24763C878A3989C9A
+:1061A00087084FE1F39A555FA5B95C9C2F9DFC01D0
+:1061B000BA341DC50C59855C0B858827F0F9F94365
+:1061C00072E071A8FC91B6C0421F183EBD82DC6E21
+:1061D000182A7F7CDEF54CBAF697AB7A4ED71A15A3
+:1061E0007C782E2F4A6A7FA4A6EB2394AEDE4288E9
+:1061F0002492E8E902978BCB8161D337F44AE823F4
+:10620000F692F77E1BBDC4DCE9CBF70C800F31CBD7
+:106210008E0F735E4FADA87F80CA4BD2049C4FC1D6
+:10622000F990CF828F1840CECFF3C8DB041F62EB0A
+:10623000944E6C432150BB8CFC74BA48DB138C2405
+:10624000B68618FF235D4CF8DCBA60C3AF94E5B5A1
+:10625000B561B9E1B2C2EFA955281C0AB511C83C15
+:106260001A9990A042F24127F2ADC9AFC80697AE85
+:10627000C4F6B76C7CD0A24F85647430F915D1CACE
+:10628000F8F55B43D32FCEF596D8E11DF2389FA4E5
+:106290007F683987528F93E043933E048915388194
+:1062A000850F9A6578C93519A0217F29C4C8DD6694
+:1062B0007C44CEB126BCE6211F4ED5E879D9E692C2
+:1062C000104EF35C856026ED37CDA5D3F904B59A61
+:1062D0009EABA22FC2CE57FE3C355C6CFD1CBD357B
+:1062E000A211FCE6426B4420F4914A20DC09A84745
+:1062F00023807C0061C61722B7D3CDF171CECF1EAB
+:10630000384AC713ED6A68F43CB3CBF15C913C2486
+:10631000F36C2982849BD2A955C5B6542401FA0591
+:10632000443FF9F2A6A39EE63FE28230C29F8EE789
+:106330002BF2C72CCEDF2EA2CF089E7D2576F9F654
+:106340003AE45FE2E7713F7D96C29F30AF4EFBEDCE
+:10635000FB2E6EBFA5818FD29B8F075F727BD5B45A
+:10636000DB4CBC660B40F109BF90134F85F8DE484B
+:106370007BE3BB1909DCB751165DDD48F0609C7406
+:10638000851B909E52A4279D3CFFF09F45EA2F65F8
+:106390002FADBD02D7DB5E678C2DB4D883DB25CD56
+:1063A0008B78DE139FAAC62C7AE66688BDE8B2F821
+:1063B0005FA160D3D8C26B28FF9DEC2EC2A3C2455B
+:1063C000F9CFE38B075F47B9E4F77BF1636D8BFD92
+:1063D000DB59B9C0CE4BB8A93442D66D41DD3592F8
+:1063E0003E365C04CE963CD6FE797D4E299E9F2D8E
+:1063F0007ED6FEA4FEFD483DE58B981A25F76A81FE
+:10640000E3A58BE085D25FCF5D3831355D9CFBDF46
+:10641000211DF6E0FE9FF01D993F1ECFCF99421837
+:10642000D1FE44CD116DB5051F2DEEB2B7111FA3DE
+:1064300020E102A45F3C8BCA4F107A7F22D8CEE3C2
+:10644000F2940F8769BFD1D19E52196F2DD75EC5C7
+:106450006B53F0F90C2A4F3047FB90CABFE8BA746F
+:10646000F5D0E53DD57E032E8826B3E7378A9954CB
+:10647000AE022564DF36BD9EAF517EE4F37E0D692A
+:1064800044F6B72783C04484678FDCBA3C9A84BF44
+:106490007FEE1268BF787C5E742DE533761E8CE645
+:1064A000E741E3E2DBC3C80F50A8E7227D242D4675
+:1064B000F5AD84E707E11F398BE915498DB48C27C9
+:1064C000FC1A3A2A8241C6855A33CA54D40F1A504C
+:1064D000FB05D1B96422DB2F9EAF6EC2712897995C
+:1064E000E47AC9B26F087AFBE4750CAEA3D0752EBE
+:1064F00003BDB3846983D37924B497E261968ADEBD
+:10650000979BCEA9C63BE91B7031F9DAD87021629E
+:1065100010FC351D7709222AC5D6424A2F95EBA6D5
+:106520000B724C45BB71CBD704D84BF130B09D12E8
+:1065300077D82992168DB8C8F89115DA5464A15409
+:10654000E3765608E58924F3960B4CEF6FA978A4FF
+:1065500095AABBD7ECFE9EBC3242ED52E2F79523E2
+:106560003DCC719E42C647B08FEC87F49739FF5DF2
+:10657000C85E940E49E4C0BC7E0FE11FDFD71EC584
+:10658000F9CBD9AF5AE4F6D5636C7ED3DEB9903738
+:10659000F0FC267E2E960B7018E1937A3C40E53D88
+:1065A0009BDA61A3391349B5846FC8BA3274D7E353
+:1065B00079B753808AF662BE69D2CFCDE9F3FDFC8C
+:1065C0004F3CD8EF3651A0F08C8AF46C41BD3F6A45
+:1065D0009300E88F548A3ABD9FBBB2FA804CEEB765
+:1065E0003442D8A7E33A6CDE96031E7A5E2A5990AD
+:1065F000F090FE8742399B915EEE3844DCA49FFB0D
+:106600005E2272D82E84844E9ECBB53103E19582F2
+:1066100051746FE060E82EB59BFA2D60E39BA64DA8
+:106620001B55ECD7AC6FEC0AA1DF522851BF45D106
+:10663000AA23945D3F25F830FD0A2217A138740A79
+:106640002554CF277CB483CAE8A67139DA350B3AD2
+:1066500089DCB6647CBD13E133A601954BB403D04D
+:10666000340089D813647CFC4E2DBC15F922CB7004
+:1066700059F97437C4B659F943D2DA297FB4FC45C5
+:106680005C9E4C2FDE2B307C5673BD77414ECC4741
+:10669000BC6EA92772E0EADFFF7A8EFFEF1A8B6EDD
+:1066A0001E4FF5133B7FCCE75D2EDD16AF1C7951F5
+:1066B000A1FB71DA2FF3B8FDD2944FEC178A07587B
+:1066C00080F64A1A277D5318E8737706240C428F08
+:1066D000341E178062667FA8E41FEAB9DCE576BB4A
+:1066E000C5EDB04F52D92DDF7445DBA95E232A09D1
+:1066F000E1DFE56A9D3F0EF19DC7FC46E7BEBBB8F2
+:10670000DF3857DC166A22703D992584DD7A1F3FF9
+:106710001470B978128C1397C83C7BF2059D58C051
+:10672000B0A746A0F6C9799DD9E7F08187F6BF8268
+:10673000C3D2B86911F58B7AF532979B6D75AA4D66
+:10674000BF38AF3EA53596EC5CF273FAA4CD8AD083
+:1067500038872F9CA0E70EEE33993DFE6071993A81
+:10676000909E938A94D5147FF965A725BCCE74FAC0
+:1067700045C9E7755EC16A4F8AA9FB0DF5BA85E088
+:10678000E9A46C9D3FAAE239E121E728CA85274C9C
+:106790008EA4005EB51C84DF130EFBE8B5BBB49C71
+:1067A000DD8F6EC5AB3AABE7F06CEAA74994EE7BA0
+:1067B0005462075AF031490C517CF6E2B750B0ED03
+:1067C0005F95AACB914FD57C01904FD5D8D7BB2EE2
+:1067D000E17C84FE6343C9F848E2FEA99D6FF69010
+:1067E000F30606A0C3E7E58B5F08A69F6CA717FD1D
+:1067F000B1C63D389D7BE9DF2F7EF1B7416F75163D
+:10680000A137E299D09BF9D7DA569433292E50FF5D
+:10681000C7EC77411863A39F74916852E237EF2A5F
+:1068200085A4FAF082A0D0FE443F94882CEEEAC200
+:1068300078E65C71533930B906F4B754E22F50BA98
+:1068400093F550CE9B3FAD5311EF6A4CA1F679976B
+:10685000ABAEB45E1A8E9E6470C16E66978C32CFFA
+:10686000D90D433B672F9043829DB3D5F43C92BA38
+:10687000ABD55202EF15F7B2F3116DB04CD21E4DED
+:10688000CEB7CE501FFF85F83A7271EBE17149CE59
+:10689000A3EFC53F39E046FD950FEC5CAB6D8FA0D3
+:1068A0005EF1E777E2B6F1BC5921127CE5151AA535
+:1068B000B8A591BBE6D17D7C57022A47177061824B
+:1068C0008F9D9B9FA8376611B98B443B0511FD62D4
+:1068D000A07A91D8B9DCAEB3AFFBFD4D4204F1EB29
+:1068E000C910F6A008FAEFED34DC16BD4CD6BD0792
+:1068F000D735CFBFBCC276C0F59D76414A7BE02F2D
+:1069000022F7B3A6D7A3DF950F0CCE873727EAD19E
+:106910004E2C7547EEA7F477F807BDF1251EC75E2C
+:1069200033D314227DD96FC93AF774C9B0159B9F30
+:1069300092DE96F8CE3D780E117DB3869F63774246
+:1069400034800FCF8240E36667E148E01A0B9D1F59
+:106950001215B64E8B7CB2DB12B75DDBCADAA6FE2F
+:10696000B97B97BD7D172CCA9108DEEE7A4C460F95
+:106970000DEE71F8A375A246F9FB6EA86E423C3489
+:10698000CA4C0ED668208D202ED2861F3F311DEDB9
+:10699000FF9D22F36F3E22FCA55BF4CD3A5F42419E
+:1069A0007CBDDF71CDD2EB01C7279A46A2BF9D0106
+:1069B00049CFCD3B5AECF00D06BF135E80CD14DEFF
+:1069C0005470486DAE48327B7A9F69B7727AD5AA07
+:1069D0008149180CB9E06157A30CA87D61BCE74957
+:1069E0003490750E70FB9158429359FEA27A065E60
+:1069F000071B7748D4B93E1FDEB83752ACB741ED1C
+:106A00005690FFAB24A3DC25F4C5A154B93A328AD1
+:106A10006C497EA9B493D8EAD67E2D43EC572E0C50
+:106A2000D0CF09EF694D3584C9FDE1BE1962C75069
+:106A30002E2E08B14AEAFF73B8DD886711AF12A5A0
+:106A4000278D8B84705D5F0BFAD11E5F07B5473CC5
+:106A5000BA64A37795A9078A80C673D28AECCF9DC2
+:106A6000F1923F8866FCBE93CA170D75922D0554AE
+:106A70005FA788F6E14CE94C6F7FB25E25EE6B3282
+:106A8000ED44F54B0DD72F95A03F34AB84CA178D3D
+:106A9000C3D5CC1F63201C35D97A18FD7009C211EB
+:106AA0003A8783AFAA2EBA2061F1ABABA41E05E5ED
+:106AB000A88AE86FEBFD8D4116274EA5B765507586
+:106AC0005F11DAB102C593A891B665DF9FB4BACA67
+:106AD000B91F94BE64007F776390C581D76C199B02
+:106AE000CEE229767D758E9F0F3FDFFF0305FD9770
+:106AF000B3CF9CB809F7B9FEFF8AA09275CFEDF726
+:106B000043273D37120A9E1BEB3AC4A471768006D8
+:106B10009617FF573FA5D7BAE7DD890564FCBA177A
+:106B2000DF9F0404BE739B7B0E8D42FBF919178B0C
+:106B3000771BDD931693FBEB2458154D325FA1C4F0
+:106B4000ECD4333F495B8EF2EB6A3B703B9DB77DE3
+:106B500099ECB69CDFA32499AE4BFA45F0B9F1B499
+:106B60002B3136895F62E619CE3CED62F0BD2453CD
+:106B70003F6F5DDB1E2546E0A86AFB98EA8BD9FFD4
+:106B8000FA6C00F150F59268B3E3AADAC44EF72428
+:106B90007A3D81578C9FBAA6239F707EE9D840E347
+:106BA000A695ED0F7E2C0670BC5D6F11BC843B1169
+:106BB000AFEF88E105D8FED1BF047482AA8F0E3FE3
+:106BC0001540BC9279572BE9189FB7F337CE7F3128
+:106BD000B3FF7C003D348F5BD5BE85ADE7D08B1F06
+:106BE000E12F79FDE3ABFF24D9F3E3D036B4FCED1C
+:106BF000FA67CF3F6990F5CE3CFF87270D02F7BDBE
+:106C0000FFFDC727BF8572F9338F867ABDEA99B732
+:106C10000260E1C3B512D3AFE70A88CB44FA9DFB0B
+:106C2000B53B8106C1B9577E3F5A27FB3DF7DC9F34
+:106C30007374D2BFE695B9B9B8FF9A1766E70E64C8
+:106C4000DF229F26DC56B812747EFD251733165EB0
+:106C5000E657075D0E761C1C8D709E3DE60E635A4E
+:106C6000AE8ADCAB9D8A74DA40CF596C6F22F8ADE6
+:106C7000DCDFFC31EA87FE7836460934A845D4606B
+:106C800010E9FCFE3C4A2FE8A1E7A3B37FD55142AF
+:106C9000C7C9A9E9761E3E5550CF55EDDFC2D67360
+:106CA000D0ED2CFE726D7FBA6D76D0ED3CDCFBFD35
+:106CB0003CCC97778CB0E5077AEDD4DEB878343DDC
+:106CC0003A807E30E57F30BCD2FC09812B2A451EFC
+:106CD00091508E9E4FEBA5EB02A4EBB3E74703E187
+:106CE0008B5372CFED781EF4BCE2D6303EB0EE95F9
+:106CF00077A85C9D7BE14D45A7E718F85CC4AE3CE6
+:106D000007BD3F87D1CEAC643E3E54EDF377BA0366
+:106D10007DF4A94C2C2CD703F4FE097A3FC1F8BDB1
+:106D2000327160892B09BD7E298D61FA3F914DF149
+:106D3000B261DF6F15F0D9E9E89A89743C310FEF41
+:106D4000A7A2A3B97F0DF73FC342CF7D4C4E9DFD57
+:106D50002B893CE279D74BD784EB1D482297E7F685
+:106D6000B8253CEFCEA15D95341FCAEC99E1E64D04
+:106D70000E39E5DACC9B703CA4E60F26DF83ED6F7D
+:106D8000B8F8EB90741B1F99783CF369727D7F9281
+:106D9000EB8B4A30CA475ED9DF0E91206A8C0AF528
+:106DA000C17B061D52C27F679E1169FCA7A9FD2009
+:106DB000D5DB4E3D518971CB24EBFDD15CEFA503B2
+:106DC00093509F9D79F527943F2BF79F50D0BE3F5E
+:106DD000D4F623A5BBB84F1EF03C4858CE83333FB2
+:106DE0003C3089E981E471515A6047E0AC7AD93E80
+:106DF0007FD5FE8F6DF3AF37DAA97D30D83A1F49C2
+:106E00009165B8DF8F0ECBD49FFCA85D4C1A27FE8E
+:106E10000F3C0F2D766DD39BF37E8BF9AD92235EE5
+:106E20001DCFCD8ECD91DCED68AF1D9181E60FA415
+:106E3000C81FDCA4DDF1A657C7BC73C791A5A26E1D
+:106E4000F1437FECC0E78CA3C66C3F996F4637F1E6
+:106E50007FF5FE7A63E671E25759F8A0E6CDF25C61
+:106E6000D4F7E887EAE371BD7010FD5C3130AF9C68
+:106E7000E5A505CD93F4BC66F3C9BE288D4FC99A2C
+:106E800000BA65DE5190A8C73C3AF87CCEBC4354AA
+:106E9000B5E697961F3E802E66D6E297F3709E0069
+:106EA000C4B50FA9FD09E14B03D85FCE3C8389CF60
+:106EB0005EF94B917748D36E0F1E80FEF3F5CFAF8E
+:106EC000C454CCAF34F9D6B4842CF995A660BFFC79
+:106ED0004A4426786871258F478C91CBE6E073E2AF
+:106EE0001DC7923D5F2E333EBF11BAEF5F8D7046D6
+:106EF000599E6696035F5FE2F8FAD964B271A242C6
+:106F00004B41976482DFD94B227199DC9FBBB2E77A
+:106F1000EA5769779EA731C60B97D2868EBFE1E606
+:106F2000E34ADD8B56CBD983E7E352E585FBE030BE
+:106F3000B83F9E69CB4F1C7CF7011AAF97A1BA25C9
+:106F4000648913E5747A208271FE2C9DDA87399D5D
+:106F5000F77C672DC699B3F2C31EE83F8F74F17AB0
+:106F60001ACF30F3F4527E84C6E5254D2F15E93A49
+:106F7000CB2298CF6FD681DA1FCDC181E33553E4A0
+:106F80009881F4942EDE40E715545E5730C47D7E20
+:106F90007B7180E23940F08CF24EFD1FDCDF71170F
+:106FA000CF87771B22E6C34F64D0FC404082228CFF
+:106FB000075C7079C39B43D02F1F9E8A7FB74B8697
+:106FC0004AE3247ABF7CF82ED9124F53311F4E8BDF
+:106FD000F9ECF970D557137C5D47FFC662EF86FA6E
+:106FE000FAF5C99D231F8E73615CC6689E8D764538
+:106FF0007306F0FC38CB8737F37CF8B38DD366A3E8
+:107000009E6DF698CF67B0FE66DBF8F5AB111FAD4D
+:1070100003A1EDD372CF66EC9F350AAA69FD9914DE
+:10702000855B2C7AF0B82CB13A5539F2BC6CAD279F
+:10703000E2FC60E67B0EBEFB7BCA57781D8374279B
+:107040007C8571A99CCED360D5ABE6D5E49F667DE7
+:10705000E0F8AE7C710ACD9398ED40562C1249C2EF
+:107060004757BAD9B963F271200809D4AF8199B1F1
+:10707000EFAC45BE0EFAC26914CE07689DC90E0D6D
+:10708000749AA770EC6387BE91F2EDF92CC2E516F5
+:1070900079E90FFF0D1C7EE61F9FD7781C306840F2
+:1070A0002C097CF2C512BA8F2972E4B7563C665D92
+:1070B00091BCCEF60E85EDA731BA92E5D12BEC79D5
+:1070C0004F4C335BE3A6D35CB153A837CCFCB9A0DB
+:1070D00046797EC330E3EAC1DE78B68EF580F71AD2
+:1070E000A8DFE495ED860BAF592C1F22AAB18FAD16
+:1070F0007C2C69DD4C0E1DF9BDB9E2198A971D8300
+:10710000D06F5B1DCBA76EADD3A8BDBDA52E48DB50
+:10711000CD753ABD36D545E8FDFEFCF4F3E01DC85B
+:10712000473E2FCD270DC6270FD585E97CF1BA99AB
+:107130006C5E97C9EFEE06E4774530E5C74FDB3E5E
+:10714000D1948F2CDADEEE62CFAF514653F931F98C
+:1071500079B0FD8989E994AEC39D3FE57E67F986E4
+:10716000B4DFF44EB6EE50D7713BD6D9314BA57A89
+:107170007947FE20EBB4B27506879FE16BDB81D3C4
+:10718000B45EC04DE4DF43F6E1D62249E5C1949FE9
+:10719000FEF3B8A9DE6ECE62F94FB9D0174165DEB5
+:1071A000ACF37C21916BB47FE4A29C32BC2F87AFFF
+:1071B000A2F5DC72B18FE6E3E4C29C3BB0BDEDC04A
+:1071C00016AD8CEA01819E5FB5D00D58974BC486F1
+:1071D000C663E5C2A2B5D85F43B9247064BA99FF0B
+:1071E00024175E77378E3F30E590DE9085E716E313
+:1071F0003FE8966CFCEF94FB94FA2B68AF5F04E9D0
+:107200004E40BF74DB94BB8AA87CAA967AC62475CC
+:107210007DA63E217A638D62A9E354608E8179D385
+:107220009DB7DE154EE62F91F3749D92DD7F1E73A0
+:107230007C851CDDA0B0BA74B0D7A527CF4737072F
+:10724000CD7C74B58AE7A814ECADA75B9047F0C27B
+:1072500052A9D05B4FE733EBE9C22CDFD54AFE25BC
+:10726000CB4B3BEBC42F573DDD16A5B79EAE00EBD5
+:10727000E97E2A43B813F3EA6F89E1BD7A7FBE73D2
+:10728000CEE77C2FC23C0752C965A762CF87E6C50F
+:10729000ECF950B8D3635BEF359497E2C1F5CBA816
+:1072A0000AFB3C05D5F6FAD72B6A336DED9031D247
+:1072B000D6FFCA9631B6E7635BAFB23D1FBF6BAA7C
+:1072C000AD3D21719DADFFD56D65B6F6C4F6AFD865
+:1072D000FA4F7E6991AD3DA57385ADFF355D6B6C51
+:1072E000CFA71D5E677B3EE3D8465BFBDAEE6FDA25
+:1072F000FAD712F34641B9CDE2F5C259B98235CF7A
+:10730000DA924DCE25E2B7EFC8260C43E3D9ACFEA6
+:107310004A618F7BF380CE7192AE44349AB71F37A7
+:1073200007AF20D5D0F354D273CA747A7FFA3CBC2D
+:107330004289BD0E56D1591D31FA65F67CBFBD1E7E
+:107340005811B7D1B206F7F12F77B926F5A7AB924E
+:107350006F9783A1D613CBBA63DC30E5E28C291793
+:1073600005442E683CED5311FD1E98E3A7F685C534
+:107370003FA27834FDA31B5488A3C968CA45E9CA53
+:107380009E51B48EAFD72F720BC3A95F33E52F6028
+:10739000D1FB91AC3E3DD33C7368FA554C5C63B372
+:1073A0000F9DD786C0BA54FA31E01E403F4E91A3DC
+:1073B000196EF42FA5880196F80B54CB36B8870ABE
+:1073C000E7673D07561386B3EA15134E85E86DCC83
+:1073D0002B352DBE893AF55003363ECD591EA5FEFC
+:1073E00009B10BAF76DBC633FBF06FCD4EFE8D6C73
+:1073F000DFA7692F9B780F84C2B49E04F204407FFC
+:10740000AE69562C88F1B416EC62F10F1F705F491B
+:10741000E7690C2A02D6B93776B1387B835ACDE2B8
+:107420000E72358DBF34640B5AB23AAE3BDD2CBFC1
+:107430002BD63E3876DF007C252AC9E30E0D7C7CF6
+:10744000C3816F74B17352D1D19F06E234BE6FC94C
+:10745000BF8970381A72E13A3BE83A010E57A040F2
+:1074600080FAD0E070DECCFD1DA976CB80704A0892
+:107470006712BA9870C611CE92D470FAB3CB687EF8
+:1074800052AADD46D731F1BACACDE8E584DBC4B7EC
+:107490000C91F2D9D83EF1E5284D8712B223BFEF07
+:1074A00098C9FC66A2D86DFC6AFA2D845FEB915FE7
+:1074B000258DF92FE6FB055F716B0CAF9C8EA067E5
+:1074C000D2B8432016A775E7FE18F3B7FBF40DE317
+:1074D0001BBF1C01EC2FF9049ABF5378BCC2ECF718
+:1074E0009E9BC5891A667547711FCDD74AB019F59D
+:1074F0000FD63763FC2E9FED378EFB22F0FCCC9D20
+:10750000C1F891AFEB8525E9B41052DC1F1C480F80
+:107510007B117F23FAEBE327DDFCBDE03CC863FA77
+:10752000B87819E6A353CDE3B44BCCFAE7E1D7B56D
+:1075300057D33846B36F6317C681CC381C044B92BF
+:10754000C6CDFBF0CAF2897DF45DA67712FA49D365
+:10755000A6523E69CEE7F4AD76D4E99A75DD9CAECD
+:10756000669C1B822CBE63D2D9D38BCFDD03E2D3C2
+:10757000C3E5C689CFAEFFA1F8FC11DA28E4EAF72B
+:10758000B3F7C2E1E03780E68DF2EDF2688E33F9B1
+:10759000DDB9FF536E7EBEFF0FDDBFC90FA9FB1B18
+:1075A00049FD1433FFE9E7FCA6E2DB4D44F1BC3EA4
+:1075B000F364CB955978FE32BFDA3F334EDFAB959B
+:1075C000C1D0502FF8CDFAD912FB7BA0DE62BB9D53
+:1075D000A53AFC1185D72DF57BCF95DB63CEF797C8
+:1075E0007AF1EBA0D7683545FE6A88EFFDECE4F947
+:1075F000B4BC9AD67AF46FF3EE6475F6BB65588521
+:107600007577232B0CC19B85F995D0736964FF793D
+:107610002F3F5C3F0A4972A71E42B3E17BAA6E8BE3
+:10762000EFE7DDDB5AEA65CFA7E03CBB54A677F372
+:10763000CA5B693D59C30BE3D3D16F79EDDD651AA0
+:107640009EF79F6415D2B8EED917DD11CCEF9DCD12
+:10765000840A5AB7F5E28C436897FFA1AE2B53B268
+:10766000F0C9D91FBE395D26443AFBFC9BD3254A9D
+:10767000AC84EDDCDF70E957D3116EA30C8AAA311C
+:10768000BFA629F47D932A95E5B3CC7A9C9D394A0F
+:10769000135E7FE261FA382757D881ED5A0C70A14A
+:1076A0009DC0E3EDD79FD197613D644697ECC27AC8
+:1076B000B9875D86E123D70B271EA6EF5D2B9DD5ED
+:1076C000183621F7C30711E5C658E6675C08415133
+:1076D00088E87DEFE1EAF1D43E76D42399FC2FCD02
+:1076E000061A97E8B9554DEC0D617C58FFF64AB281
+:1076F0005EC34A89D6CB6C970EAB5A123DF68667AD
+:107700008C0DEF7E1E2F3EF8EEDDADA564FCC62984
+:10771000AC8EDA77624A3A2491DFED7533E9FA816B
+:10772000BC93E5A508D6A7E4EEF43EBFC727819138
+:107730004E8E4839241832C18B6F26C0490BDF3575
+:107740000910D1C8F317EB80CED351A7D26B5B9D44
+:1077500036B69018FADFAD0BD2EB63753ABD3E52E8
+:1077600057449F3F5417B6C93DAE77B288B743A977
+:10777000E5F6725FF17DD8931638764E24524FE8C5
+:10778000B593E78B1E2C9E9ABE66807CC3EEBAAE84
+:107790001173C6726411FAE5D7687BB60E00FFEE6E
+:1077A0007AD7AA459837B94F8AEEA5FA3196B7C865
+:1077B000A21F1BE5581E1056BC5FC99C33278FCAF9
+:1077C00023959792C331C03A9BBC60AB0BE3D6794B
+:1077D00047D97DF3FD074A2F22683FCE9AE39251A5
+:1077E0006F16433B82A514C7A08CF49F91BDA414CF
+:1077F000EFC344FBFDE90A936F9CB78C5CA7AAD149
+:107800003615EDA6CC5DC6B3643F7FEA70EB988772
+:1078100079E8D53F2B187F8FFF5A51D18EC97BF95C
+:1078200004AD4B88BBBA156292C11B2D6BE748446F
+:10783000CFC4793E802A16C22771D4B1349EF9FB99
+:10784000F89C627CFF2476DADA7FA737761FB65180
+:10785000F1AA41C2471EB3FF9A78249FB4797DEB09
+:107860001B2DABE3066D93FE53583B4EC6BF9811DC
+:107870001B25107CF9EA57C5BBBE846DB3FFAA383F
+:10788000D6C31E52593D26F8622194B7DEB646DAB9
+:107890007E4B5B626D50D9D5DCEF86837F3E847A68
+:1078A000AEF265573B8246F41EC3FF4B0FD3EF2465
+:1078B000B4D575697199D3DFA40311C90941A07EBC
+:1078C0008A927025C610FD31817F1722AF24A2D77E
+:1078D000A37E4DC861D49B577899DD382141E6B12C
+:1078E000C8D58414DF1FA17959A4E33656D7DB8F9E
+:1078F000BF3CCC9EAF05632BFA0DB05FD668BE903F
+:10790000C71DCF98E71CF73FEFF5B0A6BCD9F05ED6
+:1079100085FA67B544E35AEB43ADA50A5967FD4FB5
+:10792000426172B242A387D51DACCF68CF994AF8A5
+:10793000A431C3DE7E98D7B906338C8CCC62AC0BF5
+:10794000787834E6ED2BA1F5F66F22BCBF64F9C15F
+:10795000D307AE4DBF9EB437FC92C5753774BCA932
+:10796000C4483FC1C3EB093AA67C05F757B94D009F
+:1079700021C4E433329EE039D27A9544F864A27788
+:10798000C45C4F01C0D363229A40F860FED68246A1
+:1079900015DB8A3601E566FED6C246E4ABF513CDAB
+:1079A000EF2414BE1E29E4F54C23719D07E21877DD
+:1079B000DEB7A2FC2B78CCE6084C6E0923D2FC9EE5
+:1079C0009811A779A7FF6C14685C1B53EE9BA66205
+:1079D0003D1D7449E4BA5361F4339AD8FB0CE47E3C
+:1079E0008B3C15E9C2DE1B228E24D5FB635F76D368
+:1079F00038726175E41E6A1768C592F5BD2CE0798E
+:107A0000E32BF03732CF780D4AF1BD80A73D2CFE35
+:107A100057B87CE97A1C27FA977851CE73C4844111
+:107A2000E7FF1E8B3BEF1412EDF81EA31128A4F400
+:107A3000DD19607C613C524CF9629F5076D57D84A3
+:107A40000E8DAED55BFF0DE99A51084857BCBF912A
+:107A5000DCDFC7E929668435A4DF3E4ECF784230AB
+:107A6000B07EC5BCFFA26BCD3D286FB76ED93F4736
+:107A70002578CD71475A47103A2CDFB23F1EBC968D
+:107A8000D2618C4AF0BEDCB33F8E74D8571F19A95F
+:107A900059DAE3FF42AC115A07BE9FCAB394F1C84A
+:107AA0003A9477F2FC3595F0E9D399A6BE60CF0BF6
+:107AB000C7F4EA8F0890B346ACEFD3272A391F0AE0
+:107AC0002DFDE710F9FEE727599DF997C87A28EFB1
+:107AD000641F343FDB33414AA0BFEB25B0A0DDE299
+:107AE0009D3886D6CF917D03DA253D13257ACE9A2F
+:107AF0007169F70481BEE78DFD911FBC05AC3F1194
+:107B00009428EA4D295F02D4EB92B83B3241C7700A
+:107B100030CBBBBAB485F43D514F9125CF0A7D756A
+:107B2000BAB41DA29F97B1B5C7BABBF3046257663A
+:107B30001D5FE81A4DE65BEAE1FE4616B1B7C9FDE6
+:107B4000151E662F3D1035BE8C210DD0BBF3A87ECF
+:107B500082E854BCE6DE56989B2C1FD277AE3BEDF4
+:107B6000EA6E6A3FECF009E5C9EA4F0BBD3CDEE086
+:107B70003B42BFE7510B44FE512ECCF764B9FE30B7
+:107B8000DF1F70D6FB9AFA44CE607BAC995F968B70
+:107B90007A40E2F5439216D6B0FEB1D45F42EDBE14
+:107BA000C7B99E120F5C7B33BE47A1A03E00D45FD5
+:107BB0003103F3FF3D79D08EFC2A052360CDD39AA3
+:107BC000FAA0A94EA5D7A7A68E2B4339796A6A4E8B
+:107BD000994664E0E0A49F7661DEE8FC6E26BFE78C
+:107BE0000FAF35687CC960F122642B1A67EC7C9476
+:107BF000BE27FB0329FA10AD7BC5FA0502D2B60CED
+:107C00007B7DD5082FABA3ADE2F036CAEC79731DAE
+:107C10008B072B17AFA671A9F3FCB93B76277DAF75
+:107C2000C24DCE327CCF5105C360DF196078C0F7FA
+:107C3000986C798B8B93E8F82A0FC3BF59CFE1ACCE
+:107C4000DB30E119CBE1E9FFDE849D1EA6FF65D2A2
+:107C5000C11C5FE38AE46A03F04DD545111296F822
+:107C6000475FFDB542EF9FC3BAF574ACB389B55E0B
+:107C70001F42394850FFC8E3AB01E0DF35A27C1A50
+:107C8000947AAC75E2698EBAF57EF2A2DBDBCEBAED
+:107C90008515C81CD3981EA7F5A6127CC745E87D9C
+:107CA00036EDBDE968D75611F5A062804832345CE4
+:107CB000FF1CB7F7A597EF8B8CD2FBF663C60BCCF6
+:107CC00076E54B0B691CA16A9F8FD6E357A2FE9BFA
+:107CD0008C75FD4697DB56CF1FE9C4FA39F9253676
+:107CE000DFE31C9E3F691579B8EF37B8FF9323C4D3
+:107CF00044F652CA618A87B827720C34A6CF24C2D0
+:107D00001371B3DEC2581B478761A702367B69A790
+:107D100097B5FF73CBDA789C9DB3DC9EF984DA3F8C
+:107D20008D1EB37D96EABB9D4A6B27EA3BE345B7C0
+:107D30008EE717194FDF93365614D173201E8291A8
+:107D40008887D73214AAE7E22FB8F7A29E9BAAC66B
+:107D50000EA916BFE16CC6DBA3D1FF4A329F619B1F
+:107D6000AF6078F391F53B10AFE6F3D73276768AC1
+:107D70006C9C4EBFAB917F78F46AD2CE79D14DDF47
+:107D8000EB31FD4D275F2A5E265F4D8EF7F314948D
+:107D9000371FEADB6A2A67EEA03DAF65CA9D7271A4
+:107DA000822DBEFF383F67152986A14AF2BC983E56
+:107DB000AFE2746DE27506A9D7C94CB1CE35549EB9
+:107DC00053AF339DCB3B703996B4DEEFB10CF01E50
+:107DD0009F33EFE1D453BDF2CAF5D0169C1FE3BA2E
+:107DE000101BE325D77589F6795E3A3A3609EDE03E
+:107DF0005F737FBCA8EDE157F1786E7147EEF24CEE
+:107E0000A3EF657D17AFC39587F95EE0F1947E7AA5
+:107E100088D95777327BB566FE546ADFD56C1FA3CD
+:107E20001903F8491517D36C7A48F0E8FC3B77063C
+:107E3000D547151703F4F9E55BCF637BBFA4FF7A41
+:107E40003EFADC5CEF5E879E3D38E9173B0BC9BA12
+:107E500035CFC982DBB24ECD73BC3EDF43F4AE5D9D
+:107E6000DE2328EF52087ABF4782FA619BC2DBC645
+:107E70008CC639F968D75AF4C34CB4BFFAC6E3F7D5
+:107E8000E5B679CDF19146B487FAF54F73F41F63E7
+:107E9000CE5F4EFB3BE131F50FB6D1DE92FEE2360E
+:107EA000E1A3FAEB61C1315FA6B9FE423A9F69775F
+:107EB0009F6BB9F57543423E6D2D45FFA9672DE8CF
+:107EC000F8DD871F48616FD8C2B7E75466F7575C83
+:107ED000BCD246EF3EBC8FB3DDFF7D5DD0564F7BFD
+:107EE00077AC86D6519F5339BD88654EC7ED1E6568
+:107EF000ABA3FD071C9F158EEB53C071C35F198E9A
+:107F0000904D3EFBE028B4DDFFAC704454A68FE7F3
+:107F1000F1EB5C8DBDD73A5777851BC8ADB9E4BE90
+:107F200087F0FA97C95525D7B912183EFA3DD20401
+:107F3000EB4FDAE8DFDFFC97FB3FB89126AA82B669
+:107F40003A0191D7613BF50EBE77CDEAD854DBF705
+:107F500042CCAB5764F594CEFBDD3C6EF0EDAB2B21
+:107F600001ED6962AB277DAFACD1C7FA811A146C01
+:107F7000716EDE36EB702F175C7FE4E7F4B7AFBEAF
+:107F80000930AE2B215C49FAB573B89AD408CDC339
+:107F9000C5B581BF07F359E191D34C3CDD40F124D5
+:107FA000A6C0D32A1FB72FB418F5939A825F0C3C52
+:107FB000B9BDF00C8C9F6FA43178E0E215948F442A
+:107FC0004EA7265FF2EFDB98F98F26F58B857F723F
+:107FD000DAD0E8BB87F7FBA2E95B3A44FA8E30F9C6
+:107FE0004DFB62E1593C4478AE35F92D18A1F4FA05
+:107FF000A2E0593B44787E6ED24BFF62F1F3C01091
+:10800000E139CBFB29692C3EDB54C4DEF7F08AD181
+:1080100087B0DE6130B9F016DAFD6C35DF6BAFB3D7
+:10802000FAC05EC7956A9FBFE1FB4C254F2BE44425
+:1080300036D2EF581D8B07BCCDFD93DF5434F86961
+:108040007CDEB14E5370AF7FA0B8CDFFAAB0BF3772
+:108050003B981C17A4B1FCCFAD31FBB865CBD31C4A
+:10806000756106FB4E30C75FAAF9FE5EF0361993C4
+:108070009843C01BC1577A6800BFE172E32B95DCBF
+:108080000D175F716D78F81A4CDED722BEA60D1D54
+:108090005FA6BCFEBDE24B1926BEFEDEF9ABF41FA7
+:1080A000F81A16BE160F571EB95DFBF78AAFA1CAA4
+:1080B000A3D36F23FE5D78A0F7FF2F37FE9CEB7FE5
+:1080C0005E3C9AF3AD48E1E7A5C2E7607098D76ED1
+:1080D000EF10F1EAF43FFFDA7875ACFFB9F1CAE7C7
+:1080E0001B365E0781C3BCFE11F13A0CBBAE4D617D
+:1080F000DFF574CE93ED67DF5B1BEFAA3E321FF313
+:10810000C75F15697EFAC8EE391BACF540D97E66AB
+:10811000FF1F299FBD81D65747D368EDD95121FC58
+:10812000EF2598575EC4C639E73FC2F1F55FBE0C34
+:108130001ECFD6B391AE47A38B07944728B7EC8BDD
+:10814000E68D2CF415FBE3FB08E8DB4B300FB12088
+:10815000391C269D53AD3B5CFA1E8DFE6058FA67B4
+:10816000B0FDFE876FA8767A82E2310B7AFFDECD12
+:108170005588CF3681D5C31DC75B79F8DD35A09D05
+:10818000962DCFDD83748AF9595EB043D13760FEF6
+:10819000C4BD78C1837E42B7A3B764B8DC167C5DEA
+:1081A000E3677ED5F495C9FDAE08E783BEF12E18CE
+:1081B0009F84BF27F37EB7AC64DF07032952B0C8A2
+:1081C000F21EE90ABE8EF9DC397EBE3F40C71F4D64
+:1081D000F15EFEF57CFE654B061E0FD5ECFB3B8485
+:1081E000EF0AACEFB1F6F219978FE3BED81C3F81CE
+:1081F000E76D57EC89AF211F4DF0B1F7802408617E
+:10820000FD95394F96049D0AC1FB07B25E8079CD7A
+:1082100024F37C75A07952E1D5DC8FB90E8A227ED9
+:108220004767AECAE28825118059183F7487EF630B
+:10823000F943C60799BC0E7146755AA21EFD5E89A8
+:10824000ECD3026FC7FF9BFD4FF8BCE388A0D1F7CA
+:10825000CF1D78184C3F6CE47C9325C6367B306F7D
+:10826000B2CA95F43B73EBFDECEF0C15F87BEBA574
+:10827000E83AE31E8BC9F87D8AA512CB7F114E2CFC
+:10828000B0FEDD9102CE07CE715922AB37827798CE
+:108290003CB7ED5D57904C7E7EC5E5B4C05F64ABE6
+:1082A000735C12BD4F46F95CB260A1ACFBF0B9CE75
+:1082B000F88DC3D1A6C40AA6F8FAF094520F71FC47
+:1082C000741C8B35E0773956D5BA689D40F126C6C7
+:1082D00077AB361D103690EB1E2E7F0B910696F96C
+:1082E0009EE0746DDBEB1D8DF0B799F91B9C98C077
+:1082F00071FB2EA0F990C7FD1F34613EA4DB053C45
+:10830000FF1B2DC7FC6F37AF6F7B8E3CAF4778E705
+:108310006453F91EB7E9E31AD4CF1D0AD0BF7BF12D
+:10832000BB2DEE04BE4F60F24BAF9ED874A10EEB96
+:10833000871F553A2722DF6437547F2D59FE743F3B
+:10834000A7C39F7CD1F46476A07935F5B9D96F9134
+:10835000A4CBC9FA2F2E779C6B1CEE11EECEB390F6
+:10836000248FD9CB878981EDB4B7B81EFF9523CF71
+:10837000BBE458F23863975FE0F396ADA7E796E168
+:10838000D669CD3487C7C45796C1F0B4748968D311
+:10839000B7AB16A439EC1E86D79BDDFA93B88F478E
+:1083A000F7FE62227D2FCA713E78C59882CFEF8694
+:1083B0004E19F5C42951A7D7B7EBECDFFD7E1B6240
+:1083C000DBA7E1F9592B2695ABF739FFBCBDFC8E35
+:1083D0005B28FC715143F84FAC1C71D34CD42FCBAC
+:1083E000E5F05832EE44FC7EFF5ACBFE7BED1A07D7
+:1083F0005CBFA9B863C0736BD9723BDDDA14661732
+:10840000185F6172780FE1D15994BFBAB7CF20EBF2
+:108410001F49644ED9CABA03FE7DA7C5FCF7534273
+:108420006CC70CA26F4E0B2C4F627C9DE98D258F83
+:10843000451B31757ABAF69A57BA49BF8B7C7FEFE4
+:10844000D50E7C3E3AF969DC63767B6FFA31507069
+:108450007CAC26F979B0554BE37FC72B3C1AF5CBA2
+:108460006D9B92F7FB213233A1EFE9FF162B92C5EA
+:108470002727680CDE55D1E4E327687EF61CCFA5DC
+:108480002478FE2090C6F59C361AF5F4AA14F076EE
+:1084900007D8F9F57EE303B7A11E3825D8F5F39187
+:1084A0000093D7F600E3EFD37B57C8D948A72697A8
+:1084B00086FC7032233C01F96D75FC047DDFE55FBD
+:1084C000020CEE43DEA81E9886F2B2686E36A14B0F
+:1084D000C74A08BBF4D4FABF2860EA7F16AF25E785
+:1084E000DF0778FE91A11F50FB438A8CBE75229D49
+:1084F0009AD6819F168C75B4CE70AF97D595427879
+:108500009AD58E9FCEE13EBD6F78F4BE25EAB0834A
+:10851000FAD97FAD9574DD7D691AD6A51C29173B64
+:108520006F24407EB82F8D7EBFD62917A9D61FAEE7
+:108530001D787ADFF0ECC0C1F6BD32101A921D78BA
+:10854000BEFCD11D2528474AEBA464FAD7D4D347F3
+:1085500079FCDDC93FE6B582F3C5A9C4C070DDBDB5
+:10856000CB0ECF6DD576784C79399568F0AE463C18
+:1085700041E744AB5D0A73A60D72CEB2FC542A38B3
+:108580003705EC7A02390FE9700FD737EFD53E1A6D
+:10859000B0D2C1B9FFD302F70F9E6475B963A3AB24
+:1085A000CBB2F53EFEDCC2E7BFDC7C699E33CE7900
+:1085B000FED6F9D03CE706E3C3AC14799C027C718B
+:1085C000998C5F2D690AE6EB0B023A6B83360F5FDD
+:1085D000D58299E6DF57D147E3FB5FA7F77AE97BBE
+:1085E000C0C6567702BFDB7E6AEFF513ACFBE9E24B
+:1085F000F459B524837E9EE294109E9F4BEBCE44AB
+:10860000FA9DB5B78F65CEC3F6A38705D4D0705B4E
+:10861000CD6A11F7F77A80BDB7B36AD39BD41E1C1D
+:108620002E9FAFAAB69FFF13701FD9163B4BEA29A6
+:1086300041FE49858717100FE8074517CE45FD7C99
+:10864000C72617D5B72FF279EE9022546F439C9D21
+:108650008FA0127C9023E4046E02F1F138FFAE94F7
+:108660001455ACEFC9ADDDF6C05CAC7B75CACB97D9
+:10867000D3199EA6A433BD7DC81B7B2F90DDA79F79
+:108680004FBAAA0FE4922EEB039AF91D5F2AA7E6D0
+:108690007ED673B8889DF62CFDBE30DF1FF438F807
+:1086A0004D68ADFC29E2BF4CA57681D74DF43ED68E
+:1086B00045FFC04BEBA84CB932ED1DE7F8A552CCF5
+:1086C00066377ECAF59ED976DA21FF382F92F71FDA
+:1086D000931E1A929C5EAEF36252FAE5392F04CED5
+:1086E00067CE73A357AE9BD8FB20278E7D32379978
+:1086F0005CDFF819E170CAF3A9BD5EF65DE31BFC0F
+:1087000054EFF4F953B909F4979D7281FE147EC7B2
+:10871000E3D1BD6F4CC4BADE13DB1FB82D193DAFDA
+:10872000D6781D7677AE2D9EB72600B4FE1BC87A8C
+:108730004F59E637C7F5CACB20F1CBA52BAEA5FE26
+:10874000E4DB2BAE1FBDBAB8BF5FD1AFBF2BF6F8CD
+:108750002DB86E3DF7A777B82BF626F303395EFBED
+:10876000C789EDF6FD2D9B4A1BD1A5DE9C76C397EC
+:108770006249D6EFF56B36258FC7FD9F74875F631F
+:1087800010BF86E0A37BA5189859D2E7D7741B5F6A
+:108790008C5FF33BE8F9F71954FE93C3F7643AB3DF
+:1087A000534F29B11DD712F84E13FFC740F911C816
+:1087B00038E497EF26F7D71EE1E37EB76998FAEA27
+:1087C00098DD9F49257FBD707D4EF96B537A0A5025
+:1087D0000FFC6ECFA7EF3E80FBD9E3A5F876CE73F2
+:1087E000A32672FFC24BF9D63C9F3B14A6FF7FF72E
+:1087F000D591F4EF553BE503A0F5A6EBC8F3E37B79
+:108800008529F81DC4B6BD6915C9FC9C159A8BFB5A
+:1088100017F6780F70FBEE16CE6FDADE67AAADF1B1
+:10882000E877B8BE32E300AFA4B37376C982850A95
+:10883000C67BD6F6C69B803A2BDA55F97BF03B52C5
+:108840006FF1F7B98C35FEA4EFC7FD82F3E56071D7
+:1088500088E52BED7182250B063E6F3E4C24AFCB95
+:1088600032F939D57AC33D5FDA12C3CB8B0DB64FDF
+:108870008F36347FE416A8FE12C63B964258C6EBEC
+:1088800012A89EF85382CA0F772DA6F0BC65FEDDB4
+:10889000E14FEF9F68B563FE8BE3FBFC92FBBF8A61
+:1088A000EAF21DA57A62B2F3C919F7792B053ECF1A
+:1088B00070BBE71DA433F2EB5231299DDDDC8F7FC5
+:1088C000672593A3FF0F425212950080000000001D
+:1088D0001F8B080000000000000BDD7D0D7C54D5CF
+:1088E00095F87DF3E62BC924992433934FC2840075
+:1088F0002206984008A80813422428950904080A6B
+:108900003A7C88817CAAD8B25BB74C0860A46E1B05
+:10891000566A5DAB74A0C152C536D1D422A638A028
+:1089200028FEABFF06EBBAB845775017F9924456CC
+:1089300017BBEB963DE7DC7B336F5E6620B6757741
+:108940007F1B7FEDE3BE773FCFF739F7DC3B972EF8
+:10895000C1DF0CC62EE99E8BAA5516B232FABB04B3
+:10896000FFAB9E9B145576D9ED8C3919FBC7A5AD8D
+:1089700089FE22C64E19E065096381C7D4E06E0501
+:10898000CA41FE5EF6E7B22B54FF547041AADF36AF
+:10899000783CF9BCEB5118774C649C65CDD1E386EB
+:1089A00059602D73C038C144FBEE0286FF0C592676
+:1089B00046DA77DA0D340E3B9569602EC6EE936D7C
+:1089C000E38CF7BB0DD0C15583EB571BBD26BB66AF
+:1089D0009E2B52DD8C4D8E94ABE746CF3335C54E82
+:1089E000DF19B3E7FB92193BBD2BD14BF0989E1CCE
+:1089F0001C05F3ACB0B2800DE6F9F093D7BCCF46BE
+:108A0000305625E051EDFBD484F0386DE8DF9C8CC6
+:108A1000EB7ACB60DF0D43951EF39AB4F05B9BA21B
+:108A200050FFA73B2E0FBFB5297C9E0B2AA3E7B7AB
+:108A3000F058625459BFDE7FFE9B072662BFFFFCE1
+:108A400037174DDAFE177D91CB421991F21D358A09
+:108A500037583478DC8E54F390E0DEA183E31D5F59
+:108A6000E453FF0E953577C65897C76EA5FA0B7D70
+:108A7000652627C073E5FD8A47812E8AED6E1A6F41
+:108A8000A591793B613ECCE8CEAF02B83B5B9BEF52
+:108A9000F3C5E8678D9DC3EF339B2FD57E19F8BDD5
+:108AA00023E841D65B64F49B62D55F5C130DDF3035
+:108AB0006395B1E67FFF57A44739BEBEFE50E7512C
+:108AC00097C2F932C312FA84A9F0E21CF453FA15E2
+:108AD000C6D5D5D78FFBD702EEF1C63FFD47B536D9
+:108AE000161CF60AF8FB7D403F31BF27D3F7B75875
+:108AF0007BE37EE2EF24CF6E0443C7CAEF01DAD9ED
+:108B0000EA39F7BD0AAFD91F920B68FCA5BEA315C1
+:108B10000856F6E5C3E311EF9F573EFCBD1298DA05
+:108B200069B3BF35191A9CDEA87802EEC1E3BC8593
+:108B3000EBB430F6F6062BADF70FD096F0330BFE04
+:108B40002F9BB131AAB70E850AFBB6C5BD5BC3B773
+:108B50008EF51737B0F18CED31FB36E21446DFFFAE
+:108B6000E93A86328F0569DE1F983C6B08DE8C116E
+:108B7000DF1FDF65DBB915EAFD3199E3032839DF33
+:108B8000374E23278C762A0F153FBF8B839FAF2A42
+:108B9000A7E43AE38D0390A7F9CE9F696B5352196E
+:108BA000EB36BBEFC4F5F4CF49B0EF0214CE377B00
+:108BB0006F46F8BC75D4606829A06E8D48A70BF885
+:108BC00010ACE09682EF8E2D41F963F226C054AAD4
+:108BD000A00DBB16E868A62D80FD95FC6EEED3882F
+:108BE0009F876B2C6E15FB9BEE7E4F85F2FC9B2CBA
+:108BF000EE8DD05F69EF88830EE87FE15CC5CEA083
+:108C0000FDAC39A39C61585FD27AE82707A7F79D8E
+:108C1000CAF2918C3D85835DC7F8840116F3155126
+:108C20000E3CD5360BE4C15867B7C106A05EB8ED5F
+:108C3000A9362BF4BBB9C597654F83C9A6B5B459FE
+:108C400087813E72797B6778189B9AD65A69BD01F5
+:108C5000D6F998EC6F539B378FB1170DFE0205BE06
+:108C6000DF91F644A511E6EF2894E377D2F7453774
+:108C7000ADD9BD0EFADFBCED50A511E7BD548EFF96
+:108C80005A65B911C69D26CB6F58B1EC4812ED71EB
+:108C9000BE5319338D88CCDF9805E3A7CBFABD9579
+:108CA000B3A0ED3B65CDE54618FFDD6DEFB41525AE
+:108CB0003036656E99DD0BE5F7D3CE5726017EBAC7
+:108CC00019D029943F48EBA7F93B5483E8FFD336EA
+:108CD000EF349C4F602C7E57029FB5551633D660FB
+:108CE0000DBF8AE4DAB43E6075C13F262B9C4EACC2
+:108CF000A6666F2EC0CEB4AF2C944BD369E7F4991F
+:108D0000171A877A6CA03C06CAE334E52C5EEEDEC7
+:108D1000C8EE88256F83E95CEE7527C6FE3E318D6F
+:108D2000CB03801BE993D463CCBB37865EC94EB3BB
+:108D3000513F871359C09A1EE1B779C0C353812FA1
+:108D40009995CF53F633487FA4713DCB02F3D2916E
+:108D50006FE66217B0F4428F1240BA66CD49C15136
+:108D6000483B2C645C80FA4335D07C9DAA72471541
+:108D7000F4E74A64FE2E783A331895A1BDB7CB16B6
+:108D8000E9EF0D41F71585BE0EECAF2233BBB8B548
+:108D900020D20FCC7B937562D4BC8D53D3F1FBFCF6
+:108DA000E2BB8B34F02CE2EB003AA07630CCD3332C
+:108DB000800FBA7BC78ED80AF3FB5027774B7BE72F
+:108DC0009B18D4DB9C2EE4899BB7779673F9D37FED
+:108DD00077527017F2A7D5538C7892EDE60AB897C0
+:108DE0003F30F78758AFBED7C42C506F5D57592618
+:108DF000BB8C5EACFFE27A169CA4291B4366943BB5
+:108E0000F55F4CA7F7E50FBC61463EC57EDCB0AE12
+:108E10007509DE4C0FC2AD3536FE196BA179D47FD2
+:108E200091C60293B4EF399C22FD3BE8FB95D61521
+:108E3000E94F65C18CCBF567A6EF0370370AB89B85
+:108E400063CFF35E49A7006F8386BE160A7A03E9F3
+:108E5000E7457978FC96A25D28EF23E36EA476DDE2
+:108E600046C023DA81BD896EB48B4B8D5C7E96F64D
+:108E7000A6DB034A843E245D48BC76A73797D17AA7
+:108E8000AB14FBAE82C1F3FA6B392FA14F3397FAC3
+:108E9000D5E59AF9497E80FEBB45FF2553897F9E23
+:108EA000E0FC007CB30CF917ED165C8727346E7E6E
+:108EB000F2E0F97F0CE485F5018F1CFEDFB005516F
+:108EC0000F48B80D867FEE15F0994FDF4B7B0F9959
+:108ED000719DF571F8F6DBE929346EE6B1508A1B15
+:108EE000EA9DB57379D5DD3929E17AE48BB9068637
+:108EF000220CD78DF66AE980BCBDE1F599A01F323E
+:108F00006519E5AD1BF130207F43566BA47EC3DFAE
+:108F1000DD306713D4775800FF4564875A99C69FA0
+:108F2000F8591A976353FD2CA6DDD2929E4CDF258B
+:108F3000BCFF7E7D39FB10D6F7AF76CE9753C301C9
+:108F400005F122F95A2FA78E083C1EFE1F9353CA23
+:108F500015E454959053FCFD6130F3B19ECB151A86
+:108F6000A7804E5CF1FAA451E8CFDC93A5BA3F028A
+:108F7000BE5AA078863D03FD565BDD9B93DD113A1A
+:108F8000A96656B70DE10E46D325D4FB7313A88C02
+:108F90007F68975C6857381D32776AF5B8F8724871
+:108FA000CEE39E2C338DB7E2C151A97EEDFC849EA9
+:108FB0009867093DC30A07F3B92CC3FC1B0CAAE64A
+:108FC000BB8DEBB3AC64EF87698087B7145643F36E
+:108FD000D1D94BFF21FC36BDBDB449D8914E342FB9
+:108FE000898F0DE49C66B659828C3709A09F9AD967
+:108FF000C904BF860CF51A3AB8989647F358BA18C0
+:109000003E4E00A6B4BE3CE1230D1F1DC1F9905E8B
+:10901000084D463E05B119358FA5AA2F4F41BB35E6
+:10902000D3E24139037822381C4E60C60418F73564
+:109030007822DE2AD4BB0F9A1C48078AA795A0BFC6
+:1090400053D8A72C84FA66DE8C24B25BD997F78EAE
+:10905000AC0278389338DD423F56D18F95E844C84A
+:10906000BDDFE65FBD0BF593949F120FEC4B95FAB5
+:1090700093DF0F2B557976281F765E55DCAA44DBEB
+:109080003F680F45ECA7C40767033F4EA9EC0C19D6
+:10909000EC285592E77C0BED70B09F12603D19E90A
+:1090A0005C0E1C2E08A829D8DF285807BC7A35D1B9
+:1090B0005FD46C8BE0036C1C3FE2CF6586A78DF319
+:1090C000073EBBD23932AECFE0CFCDE2E94AE1F57F
+:1090D000F5F4F6830CCE9F6B150EEFAD655C4EE894
+:1090E000EB8D17FD36580395AE115AFBCAC7900E8B
+:1090F0008D8CDB5913D2059D947378953FB0341550
+:10910000F5E6E7BD0B535951448E6E56FC760FD4ED
+:10911000DF6CF27D9FE21DFFA032F447CC697E7BBD
+:109120003AD4CB488AED2F57A7F3F966A03F0DF547
+:10913000BE27FC1DD317D7909F7D23DA65F03D2510
+:10914000AB9AE439C2D00DFDA6B2FE805D83BFD4D8
+:10915000A98628BFC1F4C5786AFFD5ED86E23876C6
+:10916000434994DD20C7D5DB0FEF6DC8A2F9CBF6DC
+:10917000CBB2DEAE609AFAB7B3F066ECEFF675B933
+:109180005171A27876C75A8127B4130231E7658EF0
+:109190007AFF1EF88901EDF8A7F8F891719380D154
+:1091A00022E34E48F7D6A5133F4DB39FBC061E6081
+:1091B000BB5F5249DF90DC07BDE4DD69237D548944
+:1091C000F25AFA47C8F7F654E4EBB27BD3276BF4B4
+:1091D000A368A797439F087FFA13A167528F497B23
+:1091E00031D1AD28117D33585F093DA3938B57B220
+:1091F000AF815E035AFDAFEFF787E97FAA5D59188B
+:10920000873E46FFB7D895A5D3FCEA38949B950ACC
+:109210001B058F29B3A2F5FCD3E9DCFF783A3D2981
+:10922000CA5F99BF34BADE2FB0DE647C260DC95FF9
+:10923000D1EA21454579C7FB6B14F45070E62DB394
+:109240001BE4EF19B483A0DED10CEFF348579B1257
+:1092500053C6A37ED8F99FE56376C2BCFBDF3479A1
+:10926000766177FB387D942D59D76A84F7A64EC571
+:109270006E6191F9D9D6774D5805EB3D28F054EF42
+:10928000E0EBA87784CC2361DC9C7A3E7E5EE741EC
+:10929000C5A8916F79B5BCDE6FD24D51FAE6B758CB
+:1092A000867EDE94FE070BB65494607DAF712B88EA
+:1092B000BE9C4E85E2C139CD0000A0831C0FEFDFBC
+:1092C000E6092A2B8B22EB6C335415A15E687325BB
+:1092D00079502F6439FCFF80EBAC3F1E0A2198A621
+:1092E0001CEF35A27D37D1E17D87F84AACD3ADDAEA
+:1092F0007350AE261DE7F36BD7D13B63DF15F3DA6E
+:10930000C5E5ADCA8E30C407CA0E18CFB5710CE9D9
+:109310002559DF952EF4848BF99F25BB8AB531C280
+:1093200017A375B8368E26FB5EE23362475D3D11AA
+:10933000EDA8C28742C615D06EFFE386CA5876E212
+:109340006702EEB08E3EED3AE2F185D463B29E291B
+:109350008E1F2DE93DA932B67D0A1A80BE972D7168
+:10936000DC8AEBAEDF6466162502FF890E9F21C3FF
+:1093700089F8DAA9206C247D6D4A7F4AC985F5DD1C
+:10938000BB86D955167FBEF5EB9F9BB04AE36F4174
+:10939000FF848F9D6656ABD5A7D29FC8C9E0F6F46F
+:1093A0006A872F0DC76DDCB7CD8CF85DD371C2AC69
+:1093B0008D770F5AC710E1A5D4723FA5BEC61AC457
+:1093C00075962D3112FEEA369983288FEAF7768555
+:1093D0000C684FDFCF3CC8EFF59D5DAFE6005C72D7
+:1093E000EBBD935577A4BFDCFAA082F3710111F6AF
+:1093F000929F1732A37ED6D335DAC36897BC9AC042
+:10940000F9FD5C992DA000FCCE99FCF558EF5C7637
+:109410009227501081F76B5DB38F28C0D2C9CF5A05
+:1094200042F86C33ECCAB242BDB6B1660FD2D14439
+:1094300087BF3403E0946EF47563FB3447B2A7052D
+:10944000DABA2D6C22E9E721C2618A8E1EA6DCCF32
+:10945000F9A4362345DA7B13510EF93278DC156313
+:1094600042289F5E35F1756C627CBE5DE9DE0AC400
+:1094700013B3A7D3B839F52105ED7DFDB8117AF204
+:10948000DE9CF115E81BEC3C33CAF53A2167CA961D
+:1094900074281F6AE8E0563064B05ECEDE9D0AFA9A
+:1094A00081F0BDA5C241F59905E5CC5EBE1F51070F
+:1094B000DFEFD4C815B98E18F26539C2D776BCF77C
+:1094C000152E5F42447F72BE7A7C3664B869FC1BFD
+:1094D000C12CA0F7E6C01837F4F7EA8844EA4FF247
+:1094E000BB9E3F1B049DE7D474281837702471BBC2
+:1094F00051CE4FD63B9A31F36E9CCF94CA5E8243D5
+:10950000438D91F026E75361F68D44FF6B83E8EFBE
+:10951000D0E2F7CD61286FFFD551A2C78676C54B43
+:109520007E41FB51F3428CCF057EA6623CF6666E0F
+:1095300092B0477E7994F4C8CDDD3C4ED0D0DD6545
+:109540005C698BD069C19943B7239D35745A5882A1
+:1095500082F8E376AB9E4E41BE10DDB38099F6B340
+:10956000403E06489E327F01FA2352FE7689B81F9C
+:10957000B3F1F77F27E62DFB8DC8CD04A2F7823328
+:10958000130F59019E0D1EC503A612D8DBBC1EF495
+:109590001F22F9CBD808F4CB64FF7AF81D10F679B6
+:1095A0000C3CEF40B8EAF588D4AB053B66327C4A08
+:1095B000FC1905DC65BFCF6498A9DF67328CDCBF7E
+:1095C0002BE3F1EB4D26AE3F36B55883C8D7AFA598
+:1095D000DD7844190F704A3787F079D8B0A21EBFE2
+:1095E0001FCEE1F368336C1CD3CCF5D7CF713E8727
+:1095F00016A7302E9FB83CDAFE1C9727F5011BF901
+:1096000089F5FEEA55B4FFE048F0A0BDCFFCAF9865
+:10961000172647E8418F5FF7B307CD6EF87E7327B3
+:10962000E78308DCB89E92740B728EF0DE952EF7FD
+:1096300023FC050857F0DF5B30CE20FDF794A5BE74
+:1096400040B27B30BF6608FF7DB2F0DF4D53AD7F87
+:1096500051FFBD6EFD6FB2B1BC36EB757A4A7E012B
+:109660003F318AAF7E2FF01D12CF0F04BDD4957409
+:10967000123FD47DD44C7C64ABE4F2C4763C5A0EE9
+:1096800032F6B7C22E7888E05091D479A38AFEF0E2
+:109690008F157B2B8B3FEFBB94E6FF7F2DE2A54B15
+:1096A000A57D29F62558F5A500D704010351EF3310
+:1096B00041EFE7F60022902F8DCDE6CBD9BF57EAD8
+:1096C0009785DE5610DF7502D6E7F6965FFB2F18FA
+:1096D0004FDC93EA19054B3FBB77C15FFD0BB43FED
+:1096E000D731C3837ADAD1EA23FAE9772678306E64
+:1096F000E850C1B2057A68E97C39E57ADC177B7AF3
+:10970000C244949B490EEE079E794E5D8FF0D9F8C6
+:10971000D35F4CC7EF75412503EDC6737B7EFC47D5
+:10972000D48BB51D4DE869B0D6A75F223BDC10DCB9
+:10973000C9DFEF4925FBF2F44FB64D47B8B776B60F
+:10974000D2F7333FD949E5433FFDC5817F477BC30E
+:1097500097E2C17A679EDBF69D7F473AAF4EF1E014
+:109760003AEAFD46BE6F2BE95B2FB7BA0E129F4A4D
+:109770007AB919F52EC2A986CB1F49CF1F887DA5BE
+:1097800015E5B63694671F6C4DAE8D154F9C20D6EF
+:109790008B31179263350AC5D3DA806A30AED19621
+:1097A000C8A6E233A92864CE8571162FED9A4E76AD
+:1097B0004FE0C46AACBF605F02DB4AF1370CDE8267
+:1097C000FD4FA4CED838108327C14F86DE3B2E81B3
+:1097D0007DFD0EC807D23B3AFB7F41DBEB7F403972
+:1097E0005A6D0D1F74BA23EFDB449C06EA93DE2901
+:1097F0005D173B1E3AC561137CCBF5664E77559ECF
+:109800009BE484C5334A63970E3BD6BC15C410CB8A
+:10981000A9EDBD11D771D398E593882E30CE87FA84
+:109820002760A3FE1B304E097C56E910F10F3B73F5
+:109830005C07E3571899C3864FC6DE36911CD94D95
+:10984000FD82FD417695FBA5C5BBD11E79C4E4CF51
+:109850009E8CFDB409BDD5C1E70DEDEDB85F0AFDE5
+:10986000D9AF9B48FDF49AD2A97D80B79FDDD1A2E4
+:1098700044E60B949A8F7A0BFB2BB1A19E09D4106E
+:109880007EDC665AD719AC924DEB1EBF6C5C847FB0
+:10989000F5F11D9467B80FBCDA51B6DCE18C3C657C
+:1098A000DC470FCFDDE2FB470EEF7207CE634F467A
+:1098B000945E8967AF1C5A7C9EEBDF174F90BC69A2
+:1098C000443AC6F1FD1F45E9DF95928E5F38417439
+:1098D000BC721FD7BF8DFB8ACD48B7673778D98751
+:1098E0006080368A7DD64794F06A8AF3BC9060C760
+:1098F000F8DD79A16FEA1E3A7112F74747ECCB26E3
+:10990000BFFEFC0B0935D8CF618381E07978D7356C
+:109910003B5B15ED3CB93F007630916A23D8A9DC5A
+:109920000E5EB50DFDB3865AE641FE6FD4D14FE30E
+:10993000BEA3442FD20E2ED8317F15B73F133C095A
+:10994000E8BFCDE2F628037B14EBA7CD0AB69889D1
+:10995000BE8A4B91BE0E2D3EB005F578E32C66C74E
+:10996000FE1F19E67D2197D6A330CC6779C4D43E7B
+:10997000D308ED1FA970DB019200B70EB27BD91896
+:10998000B3D073ABC85E6ECCBACD437CA697072F1D
+:10999000B490DDD5E84EA4F9DCBC4FB987DB2336A3
+:1099A000C6E7AF107DDE1CBC3E88FBCA9F08F849A5
+:1099B000389E37F5DE8EF038FF4B2044F87EF32CCE
+:1099C0004EAF69B33A498EBCF6C26CD2E3922E9385
+:1099D0009FB7903E4F37DA150FE9B505162D5EDBC0
+:1099E0004D5C2FA5093D53F810C7EF2F043FFDC272
+:1099F00061104FB3A073116FB107C6A3DEFD44E041
+:109A00009FC408CA77214F1A5685889FEAF7F2FE4D
+:109A10001C166FF1BD1AFA759473BD28E3FEB80FDA
+:109A20005015435EBC2DE651B063C536B4976F0246
+:109A3000BCA34AC91923E428D005C22DA7D6477470
+:109A40007093E32E8F5A40FB07E427F6B79859AC82
+:109A500038CF31B12E6786AF04E3CDCECC64B2737C
+:109A60009C6A992101DB152B9E5D6EDADF243BAFEA
+:109A7000DF99EDD915C5EFBE1203D43BE54AE67870
+:109A80000EFED6387F1CF2A15BFAE95176DF607FCB
+:109A90009BDB8D73DB03E3D10F91FB17120EC19695
+:109AA000C41AADFC7C5FC02178358FE7837D6FA33E
+:109AB000F8B51DC641BF7ED7F53FE17E7D2BD57B36
+:109AC000CDC1E31915B03EB4DB9C85BE755C9F2605
+:109AD0007B62C163B543DAE5B717A35FD9586DF36D
+:109AE00020BF6D7F515941F48CC141F4B7FDAB08E3
+:109AF0000F0CF080FCC0FCDC2F6D6CF60563D37B93
+:109B000015F15F23F29F42F44EF176A0F720A7777C
+:109B1000AEFFA4DF8FF2B12AC67EA8942F8DE6F0A7
+:109B200068A463C90F8DD3C3A3116E439527E74D76
+:109B3000C0FFC83F0007E41FC92FC9FB399F6C6DE8
+:109B40007197E1F7AD15CCDEAAD1477A7F09E78995
+:109B50007EA794EB590E5FBA13E30086D016CCA310
+:109B60009072B871FF83A363E5B949396C3572F916
+:109B7000660D26055B35F4857B7BC913E949793B86
+:109B800049EB63C745463979BC6EA879112ED4E5F7
+:109B9000286F762505515EC93891BEDF4CA7121596
+:109BA0008F917E0BEE2F60FD3227B7434A9C9C2E8F
+:109BB0006F72CA786C30CAEF711BFC27309F289EE9
+:109BC000FE92EDFE52712B398ED4A37AFCCBFD119F
+:109BD0005C4F5551FC7AED07B97CD2D3E37C617FB1
+:109BE000A5E25AE17F3F17FB5983F1CBFB6135C6F4
+:109BF000A8FCB73643576DACF8D7C10D222F6ABB0E
+:109C00007148F9753F17F5BF27F2BFD85263543E2C
+:109C100095CDE36EC1F8E9841E77B14AE3F2385678
+:109C2000F274F629EAE194A9ED63304FC9E98BDEBD
+:109C30001FC9AC498CDA7FC8F6A74795736B73A22E
+:109C4000EA0F6B1E11F57DF8FAB151DF0B0213A379
+:109C5000CA856DD745D51FD53E33AA7CD5A33745D8
+:109C6000D5BF3A383FAABCB5A5B306F172CD9E5B0D
+:109C7000A3DA4D30860DC5F07E5CE78AE83C311DE5
+:109C80003C67FE518D49873F7016103E27EC8B864E
+:109C900047EAD46878605A1CF697CA447F897FF0F7
+:109CA0005C2E8F3595193F0BCBF60583E98159ED75
+:109CB00025DAFC8308FD04A3F2DF661A55DD3C02B9
+:109CC0007F12FDC59BA7DC5F8BBB8E3870DB27E462
+:109CD00084848B492C2B757ACD65E162BA125C586D
+:109CE000D83314B8E8F7F706E2CDBAFE3626355277
+:109CF0003EF0DB58D0D8C761C147B2BC2890CAF546
+:109D0000906FC115EC681E07F65BF8FEA4FEFB45DC
+:109D100021D79C300782CF10F9FA7D8187E3C8D71D
+:109D2000E870EAF97AFDA78733517E5732F29BED4E
+:109D3000CD2D9FA2DEBAC31862C530EFED623D8F14
+:109D400008B9F0E8063BF5F398D87F7C7C839BDE6E
+:109D5000EFD830869EC10D1E7ABF6BC3547A7680D1
+:109D60003D87CF273754D273CF061FD57B6A430D6B
+:109D70003DF76EF0F3790DC2172B253BC7971133D2
+:109D80005EBA3CA00E094F4CCD8BA92FE3F6A32E53
+:109D9000BD6C1EF9FAE34BE6BCA2E11B8B2BD9414B
+:109DA000FB9953D814DCCFBC52FB8B1B6AE6BC3248
+:109DB0006AE87C24E9897D9931DA17237EE417F972
+:109DC000936F3B2F6E0DD8E2C32B4267B1E1546D08
+:109DD0003D9F83CEFA78B41934ED8FE9F8B8DA9F55
+:109DE0001AD36E287771FAACB1F0FDF7253AFEEE82
+:109DF00010DF3B5CDC2E7C378E9CB9CE6510FC1FDF
+:109E000030D17EE020BEFBDE0DB1E0DBED7247F12C
+:109E1000F112BF0EAFBA7EDE35B50FF3C4E0B32B3F
+:109E2000F523D7A76FB7C9C5E5D6AEFFA3FCF9EEFA
+:109E30009DC9E43F20DC9C9AF5BF7B67524DACB8CE
+:109E4000CC5E17DF1705EB9C15A493A91F30A3ADBB
+:109E50003886B9F93EEF483BC687641E407C7A35A8
+:109E6000521C8960A80E862BE0C36D2E84FE8D03E4
+:109E7000E3848C388EC710D16F9853C334E73CD439
+:109E8000C1F400ED0366CADF09E750DEE357A427FB
+:109E9000A63E3EEA72FB7483DA7F4539B3FD6B96CA
+:109EA0003392CFD9970F8F8AA5276B50CE5C07646A
+:109EB000E82AFE6EA0E8CAFD7E55F8D5A861DAB79B
+:109EC0001E32FCF6398614975A6F4D198FC6D5C5C8
+:109ED00004FE0CCC64FC3CD6FB0941B4F343629E07
+:109EE000E0F84FE07E75F3147CF664F90EB9A0FD3E
+:109EF0000A33F713F35CDE975D502F51EC039B336D
+:109F0000CD5BF0C9EC7C1DE3311F14BADA6270E757
+:109F1000E33A3E523C57A39F6237043DF84C61A19F
+:109F2000713CEF2EE847FF2CE39A4437FAB789A338
+:109F300019EBA578B82701E366E6A4F05B23D19F6F
+:109F40007DD148F1A1F198CF06E5F17F9F1B0C90E0
+:109F50003FE726F99021E0B615ED70683F8FF9DFF5
+:109F6000C5F99EB65B030698D7C3951313301F2A15
+:109F7000B4470D98F1BC42EFB9BFBB19D63DA1570C
+:109F8000A538F30436E9F59128577A4DB4DF5B67BD
+:109F9000640F21DFC483E7D96FC6CEEF2ACAE4720B
+:109FA0004FE66DE9BF2789EF67E3E411FF87D00B28
+:109FB000323FC624F3639CDECBE6C79874F93126A2
+:109FC000A38FE13EB069203F6629A3FC18E8479BB8
+:109FD0001F737666EC79A8997C1EA62F92E2F49BFB
+:109FE00042EFCF8EB8FC3A4D5F2444E55947DADBA7
+:109FF000E87DBCFC9C3C09A738F9495903F3CB66C2
+:10A00000810C6D3B4EBF9171F2E8BB4997E713F9A4
+:10A01000CEF37B36A5713A399865772C87AE97B326
+:10A02000B009E9F40E9BC384F1231FF374D1B91D69
+:10A03000A3A93F2CF96E04D6337E8076B601242D79
+:10A04000DAD977AC377D10D6C8A92A6F7499617DAB
+:10A050008DDC5D9FC568BE8963C7505EDF05E64E37
+:10A06000B55F466E2EB5AA56A366BDC7E3D80D7E72
+:10A07000019FE3D9B1E13727D31095A734B87D4AC2
+:10A08000D479B47BED979797085F7F86B67F3D1EA6
+:10A090001CF4FD4A7076B672FEEE2F5378FEFE5F1A
+:10A0A0001CDE69229F8D9F0B30E9F2D0D767B9394A
+:10A0B0005D0DCC9BE7A1BF6CF7ADC8A476EED1DAFD
+:10A0C0007300DD466FD244781E1772470F973D022A
+:10A0D000CEFA75778B7CFA4495357769E0AF5FEF00
+:10A0E000E3028FB2FE2613DFBF823F9F15F0B28CD2
+:10A0F0007139DB9A3942E485A719511E2EE55DB00E
+:10A1000065F657693F49C27910FC04DCF570F431FB
+:10A11000F7ED98B77D25782E3F9A6846B97FBBB595
+:10A12000FF30FAA6E15EC33B23E179C236F2640751
+:10A13000C37DB731CF1F62180FF1F0FC09368BECED
+:10A140001C2590AB5EBA66E876CE9614FF18E48BB9
+:10A150008F44BEB5D4435B72CE8CC6BCF9D4F4B286
+:10A160009A2C27C5DBBD19483FBFB670FA79147A1F
+:10A170008272D381AB77A27E69C9F22FCA9A1CC9B9
+:10A18000DF63DEFED1987FF055E1037F26A49F2B8D
+:10A19000C1675B26E37C98129B3E8EC4A10F3D5F96
+:10A1A000D0B9B292AF8F2F243CE57E859CDFA22CE4
+:10A1B0004E7FF229E1A6CF1B5A946510F5B8DC68F2
+:10A1C000C9F2119CFB867D7A3201E67E5C97E73509
+:10A1D00020BF86B87E09EFAF4BFE1E4F8C3DBFFE01
+:10A1E0004CBEAEFFA9F92D91F31B1F7B7EA6ACA13F
+:10A1F000CDCFC7FADF4FFB1AF417E07909E2996D6A
+:10A20000EA27B9783C3DF63C470E799E7ED3D7A12C
+:10A2100067257DB3C0F25ADAA7CF4A8CB94FBF0881
+:10A22000FC26F47BF4FBF5725F1EE407ADB7DADAC7
+:10A230007F7B06E27D9658B78B85D2701FF38085B1
+:10A24000E2FEFAF55F23D60FF02A4639C5E6F6534B
+:10A25000FCE2F8E8D872A1388BF3C540FD363E4EDB
+:10A26000BC7305D70AFEBCD2B90256E2A7B85F9903
+:10A27000D51652010FF7087C9873D77AD02E2CCBC5
+:10A280007AE318AE13E07F6E009E9A3CBE331B8EBD
+:10A29000D8479AE2CBED3AF5D9D2E618EB99E7F434
+:10A2A000CFC5750CD4DBF3BA7DA4065FE358D8C0E4
+:10A2B000CF45F71BA2FCE14CF695FC61AF95F34B43
+:10A2C0006ABA8FF401EA07D43B5BF65F5B8CC84443
+:10A2D000FB02F378FA9313498EB6E65C37C6AD817C
+:10A2E000676396B45BD538F6E29F97F71FB19794F2
+:10A2F00028BB35D2BF91DE4BFC94D9FE5F4C7CCCA1
+:10A30000737AEF453A1C9DEE5D874F3DFC020F4C82
+:10A310004B23FF18E13723D2DF00FEE3E0F9C74EFD
+:10A32000EF77B0BFDBC4F91945E6EF0DC4298CF611
+:10A3300093D608BC878A97EFE13FC03FDD91E5DD0A
+:10A340008A78315B043F321B9D0B97F60AD3D935CF
+:10A350006C2ACF275D96F5C61F30CEB32585B3ECAA
+:10A3600096EF24505EDD1D8ADD8CEB06FBE3BD1FFE
+:10A37000417D3F0BBDF76DDAC7927646927A296927
+:10A38000E8F3947EF295F2A80FA11D06F39969B047
+:10A39000D1BEE621209B6C901B33CDFC59361BA807
+:10A3A0000AFA9BA9E6F584615E9FB373E93740EB37
+:10A3B00044114F5C77747202D2E54CA3E98C566E5F
+:10A3C000E9E31C5D59D1718ECFD9DCEFD3DEEF18F4
+:10A3D000EEEF3F3C7766A636CE3210E710EB581012
+:10A3E00058CEE5A94ECE497966B0F2FB439897B9AD
+:10A3F000ED2E8A1771B883736D84F20DB28CCE097D
+:10A4000094A7092429D81ED67D8378B215FE2C94F2
+:10A410003398BE83E381D79785CFD66B3D6E7CCED4
+:10A42000507C463E8F20CF3764CD7958DF600DAB2E
+:10A43000FC5C1ECCC085EDE578BC9C2CCA9BAA2F89
+:10A44000DC7EA77B70FC82D992C9DE358B799DB604
+:10A45000DB0206786FB1854E535EAA78EAE31C17DB
+:10A460000D8100E6657F4B0DD27C935828D48B710B
+:10A47000092B80C040F1831348A7E0D534E23C1398
+:10A48000EC1742DF6698DFE855B09CA1D3474EDB5E
+:10A490003ACA7776FA8C3A3DE457906F326BF4EF14
+:10A4A000A3F593951DA773404AC8977529E3CA7110
+:10A4B0001A7D7CC63493A3B87F0DB77BDF49E4EDEA
+:10A4C000245D28D95CFF34A69B19E5B9B8AC56B415
+:10A4D000DBCF279FC2A396A837DA506F584D5E8214
+:10A4E00087D41F0DDD7733C44FE3BE2A86F4FA4FBD
+:10A4F0000ADFF70C2C53283F41DED75053C4DE84CB
+:10A50000966C59F6086AB7F0887F593D94ABDF60C6
+:10A51000E34250AF7886AF02EF65691DC73C1BA1CF
+:10A52000DC9AE07FE697B89EA32AF5D324CEC33207
+:10A5300066AFDB0BFDEFBC7598672B2EA9BC7F0BBC
+:10A54000E6FFF43FC8EC982F32884EBF84F501FE39
+:10A550007F82659877D32AFF13F741FDEC37988700
+:10A56000EA88EFE88B20DE14410FF87E06BC6F12FC
+:10A570007453D8A3F07D7B8785F226D8B14CE2973F
+:10A5800085563E4E534FD9BCC930AFC2DE4944C692
+:10A5900023A13EE635616601CFAB63E427EBEB8F89
+:10A5A000C4FA6E8A52F17C9A1C33DD7BC4849C9B76
+:10A5B000A2E3B7EB23F44FDF8B45B949E8A3283E6C
+:10A5C000C17EC02FF796F26D7C6AE7E0FCE061F295
+:10A5D0008FF3ED752CF287FD9647C621F93B4B7C36
+:10A5E0003BBC640EE5734F31860E225F5F2F9EC524
+:10A5F000E2897C6D05382E36361F76C27AD2D63384
+:10A600004F0B8EB2D4DD8AFD95309F8A702EB53FF8
+:10A61000D88AF3BB76E9D10CA4AFEDD985447FD3BA
+:10A62000AC9EC2042091D6A91E8F1D5ED52C550864
+:10A630002E0B6BAC41CC5B5B38704F8FBF6011F061
+:10A64000CD62BF22CECFFB0B966AE2B0329F6F91F4
+:10A6500005FCE718727A7B36B78764FB2671DE4407
+:10A660007E6FCFB6D1F76F66DFB82C9BF22A789E4B
+:10A6700033F0BD3F7B72448EC0B89487B280794D71
+:10A68000B8AE05826F25DF2FF4DE4B76EB425FB468
+:10A69000FDF94F0AC777608942F6E0E29ACBDBA763
+:10A6A0004DD9729F37CF7E3229F25ED29594DBF37B
+:10A6B000518FA3BCAD04BDADB18F977EEBCB346A97
+:10A6C00097F964C3A5E191F32D4DBAF32D8DE27C8A
+:10A6D0004BD3BE16930BE95D9C6F69EA39B1459B7C
+:10A6E000D727E134F87C4B3FE5332E32070FE2B930
+:10A6F0009F456B618D50FF65711EE2153C0F313136
+:10A700004247C9B7268478BE9C97F2F6F2EC491E00
+:10A71000CC3369334CA43CA1B694648F362F676B5D
+:10A720004B7305D693F941F23CCBA238FBC08F673F
+:10A73000733BF91185E76905965809DE4E951DD3DF
+:10A740009ECF7716FA283F6E59B69BF0FE88882375
+:10A75000603EE9247806C11CE3F8E2EDF5F201FA67
+:10A76000DB84FD95177A282FA63C95E79739337C33
+:10A77000C5F71445FAADEEE1F978D5BE4F5FE5793E
+:10A78000B55525084FBD3C97F4A597EB407F9D48F4
+:10A790008F170D5CEF44E4BB6FC99DD05FDF9B66F4
+:10A7A000CA9B63F77B1513B47BEE75BB07CFD16DE6
+:10A7B0002AF35555D077239DF373D5B09005BE97F6
+:10A7C000BC61DE85F97AB5ACDD8CFDD5EAF4D65AEC
+:10A7D000DB2B66E4CFB51DA6083D32CC33F414A2C2
+:10A7E000A0ABDF3B28EE41F247CA253D1DB391D116
+:10A7F000F2A758CA5B900B5C5F2DE57A8E3DA9608D
+:10A80000FCA72FF9942AFC67927793A590D2C9F9F7
+:10A81000C93DAF91BD321DE403FA670A96C7537D67
+:10A820002A83FC1C8379A3D7B344A2AF41768298D4
+:10A8300057C9C0BCB93D24E562D9546E6A4ABCC050
+:10A840003844CF729F6E32DEBF03CFEBC5B8DF3224
+:10A85000788B420AE289050D856847F8C9DED1DBAD
+:10A860003FA5D6E6242BAC6F2A6B27B938E5F02B31
+:10A87000242701CF9FA09CF9359378F65851CE54E8
+:10A8800060C29F8ACF683CCDB66D37229C6667E96F
+:10A89000F11130225CE7B807E189CE0778E3E0C91F
+:10A8A0002BE5088B962305EC4B7E1EF9C157EF4331
+:10A8B000BFF74A76C821A7DF9C43F233DA1E899797
+:10A8C0004F979A63137EEAD0F2E9FA4CDC4FB88EC8
+:10A8D0008557EF5506D3C5F9C3EBD52C0DFD48BA06
+:10A8E000DC2FF2EB959744BE6E4932E9B9885EE4FD
+:10A8F000F82F15A5EB90AE34F8BF615F4248057A9A
+:10A900002B16EDAF437A9818D18B2183CD6D8671CC
+:10A91000B7289E363506DE5DE96ED27F930C5E95D4
+:10A92000EC29E6C9403C03DE8B105E53AD9DAD467D
+:10A9300098E749B3E747E8AF943137E1BD4CA75FEB
+:10A94000CA6DD546E4CF72AB1EBF5EC27B857DD09B
+:10A950007BC39F82F7E18877A93F86607F02DE2B69
+:10A960007262EC13C6C3FB2D7F22DEF5F8967CDF06
+:10A9700095602FB7615CB796E7114F7A73642B9699
+:10A980005D0D0574BEA52BCDF3327D6FE6DF4B7AEE
+:10A99000BD2ADE9B58B80EBE43B9ABC0578EE5A6A4
+:10A9A000F50AC9CBC96FFB5BB13CF27EFEBD786393
+:10A9B000F3CB78FF585380B7DF7F7A0BDD2311DCB0
+:10A9C00022DA97B59763B9A98DB7FF38D91A40FF36
+:10A9D000BAF458B015DF5FFD109F87B4EB66083AF4
+:10A9E000EB529E7D99DAB5F37677BD6A4DE4C96E78
+:10A9F000DC4E9B2ED639E371BE4EC7873755BA81E0
+:10AA00000EEFEC0F98900E4E1AEA4B495EC6F1B766
+:10AA1000CA94F63C7CCE06B9C008DF409F23789EDE
+:10AA2000E92E18626B0EB78B647E26E6895769F0B3
+:10AA3000B53587FB09B29E2B9DF17CE2C792C96EAA
+:10AA400095F9A3A11F3205E300B846D2AF71F249D0
+:10AA500067173693BE9C3D5CE691868D2B60DCE2E9
+:10AA60004BFF7A632CFF7A9B18F794C87B97EF6BA8
+:10AA7000830506F43FBA9078E87EB5796FA25DD27F
+:10AA800085FBC19AFB41BA0A78F9C78FDDFCB76D27
+:10AA9000E0ACDE6568360650E8E72B74DFC92DBDF3
+:10AAA0002C949A3278FEB38D2CC4F31DF8FC57B762
+:10AAB0009A776DD5D8E90BA5D898368AF448B5C0F1
+:10AAC0009394170B05BE80BFF7207F2FB236935D9E
+:10AAD000B844C8F7352C48718A353AFEAEB37DF6D6
+:10AAE000BEC180F1B0683E6E80E970BDD0BFE35D4D
+:10AAF000807FEDA3C976D4F30D9DD1F56A1F7DF358
+:10AB000018B7AFA2F9BC56F279309ACFF1A649E254
+:10AB1000F31F8EA5FD17799E2FC1DAFF7E8045D6E3
+:10AB20003BA0DF75FC9780E7FBC6A0DF62E079857C
+:10AB3000A22CC7BDD0CEF57000F4B0F07348D45E3F
+:10AB4000383E2788F4502CF857F271B1D0E783F4DF
+:10AB500075A5DE8FD94EFC31499424DCA57E867E16
+:10AB6000483FCBF382A097DFF4927F0FFE27CE738E
+:10AB70006C34BF6C55403E1744FC15C0DB3F23DEF0
+:10AB8000401E5B799CA29DA13C8B6BF7DBD6C5B4C4
+:10AB9000FBC18FA07D80C1F67E28CA8ED7E32B9E95
+:10ABA0005D3F80AF04B09792D08F67242FF7E17399
+:10ABB00008F91C20A7FF3D967E361FE2F5FA77269E
+:10ABC00050BC40C6C725BFF5E572BBFA57595E9623
+:10ABD0008BFB57A2FFE377CFA67DEACF9897F6A924
+:10ABE00031CF2837469E04EE536FD2C4498FA7C594
+:10ABF0008E5B27E772BFE71BB97C5D794E6F4A2EEB
+:10AC00003C4F99795CFC54A278A6F07D85EC81FAE2
+:10AC10005C4E4C10E55322FFFA547A743C5DD62BFF
+:10AC200016F53EDA60B56ED2C815F70F2DCDA8AF78
+:10AC30009C85225F7D1DA7D7BE17D2766AEF699BE0
+:10AC4000965BF60D9C97B3D06BCEC638CB0B5C2FC2
+:10AC5000341AC366CC2BB9C1E1BF0AE1D4E866DE81
+:10AC600067B11F77D8BC00E0DC27F6E7FB4CDCDFE0
+:10AC7000E84BE04F39AF69B955DFC0767D7787493A
+:10AC80003E0C94ABC2C4FFD3727D346EDF42F95DDB
+:10AC900094FF969799F00FCB045F509C37465C77F2
+:10ACA000701C37FADE992673EC7D6596971C159F0C
+:10ACB0005DD6C3E386B75BD9965CF87E474F26F92D
+:10ACC0000FB52981D1768AE3FD7971D7BE61BDB414
+:10ACD000AEAD65FDF98F95D03E2EC57D1A7A5E2307
+:10ACE00039D720F9A43B9A4F96E40E6DFF431F1706
+:10ACF0001F02FFACC88DC13FCFA37E3245E07F8FDE
+:10AD0000C877AA50EBCB312E746115A373AFF7BC93
+:10AD1000AE123DDDF38C42F74048FBAC41C037DE5C
+:10AD20007AF0DC805B233FF0DC805BE39FE1B901DC
+:10AD30006D19CF0D68EBE3B901ED773C37A0FD8EBF
+:10AD4000E706B4E562B6B215E36C4D6DCC1E74F344
+:10AD50007304DAF6788E405BC67304DAF6788E40B8
+:10AD60005BBEC0381C2F3CAE529C1ECF1368DBDF8D
+:10AD7000F5FAA42CA49BEE049E3FC602DEDE2280E0
+:10AD8000CB2A01173C67A0EDEF6CCA8D4718D0DDC8
+:10AD9000AADED573F13961DFDAA8FEEAD47AA243DC
+:10ADA000D6CEE56E33FC47F2532D52711E9FEF5302
+:10ADB000584601DE1BAED39F3DDBB6A0E859138C8D
+:10ADC0007E5FC734F1DA82C171F98EDC64C7499EB7
+:10ADD0006B9CA38DD344E8C0E609E1FADF563DB190
+:10ADE000E8A0985D954AF199232AC61ED8C7ACF908
+:10ADF00091698A267EAF8387252B9A1E12DCD1F4B7
+:10AE00009034269A1E923DD1F4903A359A1ED2BCC7
+:10AE1000632F0BDF8CCA68FAD0C3772AFC87F09DBA
+:10AE2000883742625C09D68971DEBF147C7B75F07D
+:10AE3000FD9C4D2BB7B9E973B5B534629F941C697D
+:10AE4000A64D5A7DDC53C251DA09327E3999713FE1
+:10AE5000DD8AE72C0BD10EE0FE1BEA7F94AB27CDF9
+:10AE6000DC6F430A42397927F3933CBA53A7FFEFCB
+:10AE7000B26D37A3FE1FB45EB0B8F0BE40FD7AD10C
+:10AE80008E629A78925EFF2B3D4A28793C2EB74716
+:10AE9000CA65FF253276BCCA50E4C5719BF7739C26
+:10AEA0003F3A7ED6D2A8786F4C7B4ECE43C2458EB9
+:10AEB0006F61CD6A16D2F318BDFD15ED2F4BFF9AC9
+:10AEC0003AD5C4A3A57F2CFD133D9CD5E10564773D
+:10AED0004DB24BBFB8F7367C2FFD61BD1F7AA57D03
+:10AEE000A9050125FCA382883D7983782E10F122E3
+:10AEF00058D687BF87C6D314F7301C6FFEFEAB9CB5
+:10AF0000482F5B9466A69BDFB117A11FD5D09FC1C8
+:10AF1000E32FFEA8FDAAD79430CD7B11F36EC66750
+:10AF2000A388A73576BF46FBA88DDD3C5EC0F645FD
+:10AF3000E3456FEFAF659DE60265B0BD5FCF7AA9CF
+:10AF40003FBD7D3F884EAEA0C777E4C97B3B78BE4E
+:10AF5000001372A956C02B9E5F6044005F1BB9B7F7
+:10AF600013F8A12C6F72247FD6950E7E8C8A7918E7
+:10AF70006E73AC3C298697AA804DBAD2564D726248
+:10AF800065DBA0B88499F8A9FDF2EB9376C05FE584
+:10AF90003182FB883C37DF874A9C7BC48B9F4B7A8E
+:10AFA000F3B5E73E9ACCFCBC216B8E3E97BF3ACFFF
+:10AFB00020CF4DA94359FF60B8FE69F9F832FF0070
+:10AFC000E0B7460B3FB98F20D7F3C9E4DE27317EC7
+:10AFD000A826CFB2A25F9B9AEE6FCA73E2BD0CE1C6
+:10AFE000930ACA339B9BF243CEEF3BFD0EFAEF72FE
+:10AFF0007D8C851FC17B6D6BF7A9E40FD6EE7B9925
+:10B00000ECA2F8FE5EFBC0FD09627FE37E1C473FB9
+:10B010002F99CF5CA116A5863576FABC3C1E0F1879
+:10B0200035DCB711DB95FC2E2F05E76B1AD149F7FC
+:10B0300061F5DFC7ED6087CA6621FC40EF71BD6F27
+:10B0400033D2BE832329A0A6A01DB79CF1FBE73C09
+:10B05000CD1E2415755811C5695DF7A93EB4BFDF33
+:10B060005BB7320DCF29BB9257A515C2738685DF1A
+:10B0700047E3520C3E7EDE74451ADEFFB1CCC2F7C8
+:10B08000E50BBE99142A047E7BC9CCEF197524F90F
+:10B09000E9DE82FE3495E67366032C6D14EE7B7C4C
+:10B0A0003609EF1BC8F9D23611E7932DEEB3A8CFBE
+:10B0B000E3E7B7CF3E737112FAABEA251B9D6B979E
+:10B0C000F4E7288CEDAFCC17F06874F27CF7F3C28C
+:10B0D0007E3C2EF65B65FEFB3AB10F787CF4C0BD7A
+:10B0E000604ECC0B694CF0A62EC678C451156FCCBF
+:10B0F000609FD9BDA9696437F33CF675C27E382FCD
+:10B10000F23DD7CD999989FE45BC3CE997F2B8DD6F
+:10B11000FB75DD5329F34EE3C221CDC88C13E8BE85
+:10B1200025DFE5EABDF84735263C4F8AEFF1F2E529
+:10B13000DFCBE37E9BCC876FC47C7878B5EE85B29D
+:10B140004C76993CE946BC875C935F837E1AAEAF30
+:10B1500011EF21A7FB49CFD1FD1CD80FDE1776A533
+:10B16000FB22E70B3837621E7986F6BD9BBF1FE8CE
+:10B17000DF41DF9F12707BEA88A172578C79260E1F
+:10B18000E3EB1EEB34FA705FF29A10BFEF335E3DD3
+:10B19000797E3BDEBCBA67866FC779637E66ACF1A9
+:10B1A000BE147094F3ED4E0FAFF6F1FDBCD155C94E
+:10B1B0009AB2BD3F7FBE46BE4E11F8E9BE299C4FF4
+:10B1C000F700CCE1FE6B3C3C971A9B1584C31769D2
+:10B1D000FE5B50FEC97B8AF11E639EE711B82CBE50
+:10B1E000237056A3CE1D0C86B399BECBFEA4DC39CA
+:10B1F000FDA84A72E7F45B821F99D7A694A2BEE22B
+:10B200007C759AF1B8EEE976FEBB1F2BFC607B8261
+:10B21000FC58DE5137177FB763F5EE495B50FCE30E
+:10B22000FBFB41FE2CCF626C3A3C576C8ADE1FFB65
+:10B230009C3D447A6ED5437A7DE633A39C5DBD3D4B
+:10B24000BA7E2D7BE853B40F6A7576AF4BE85DBDCF
+:10B25000FDEB1926F27E4A59E95739DFF428F34EFF
+:10B260001946FA9FEFB74D16FBE9FAFA4FB8399C29
+:10B27000EFD9FDAF66FC29A078FD9E01793112FA65
+:10B280003DB7C14ECF6F0CF3CEC4FE970DF3570CF4
+:10B29000C338C4510EE70BF51756535CBA86DB0171
+:10B2A00016BC5C05FE69B9CD4A7EF40378BF18C0B0
+:10B2B000D962E1F685B4AB54F55E3505BE5FFB2F70
+:10B2C000ABD2707D8EA76757A2FFE17C3AC98BF89D
+:10B2D000D85AE62D46F9BDB5CA46FBC43B0DFCFE67
+:10B2E00041AB85EFCF059FBAF610868347766E9BFC
+:10B2F000897E86BDE76008E3126D06BEFFDA369DE3
+:10B3000089FBABF9784D3D555D38AFFC6A90F7D0BD
+:10B31000DFD6026FB15DD33F13F652A3C045DFAF56
+:10B32000AFFA3EDE77F5A32364AEC23A4750FC6B1A
+:10B330002CE37423F34BE8373134F1A273A07F98E8
+:10B34000E6DCF3D84E25644AA17BF5288E5DBF313B
+:10B35000E4BA0DF5E7CFF87EAD9C9FE3A5EC991814
+:10B36000EF97FAF436CC6FC338B0B07B9730F9C79B
+:10B37000F70B6A045D2F11F6EE6D491CCE2B9887F2
+:10B38000CE5DDD6A6529185FBEADBC7332DD7B5DC5
+:10B39000674A437B45C6BDE3E13D5E7CA6F1C964D7
+:10B3A0007E4F8ED23F1A3B398331909248BEBDBE4C
+:10B3B0009F8787097E1E2DECB491CC8BFB2C8D07CB
+:10B3C000AEA27C7C4B22DF5703F96645BC1E467D4E
+:10B3D0000EEB5EF3624288EF1B07C57D382C40FB05
+:10B3E000310732695FC151E8A57DF7F3A6703EC908
+:10B3F00003905F0AE8CEBDC37A6FC1DF6169CC01FB
+:10B400003B0ACAEF3EF1DE2D46A0C7C611E1D57852
+:10B410004FB8B2E3DF78796CF82496937628F3A8D6
+:10B420003C31BC5A85F2E81DA9F3A83D3A5040587A
+:10B430009376B8E6E139E233227EC93C61BA1FA8AF
+:10B4400071FF55066D7C70783EB737CF24F07A6770
+:10B450000AD81DF311DE63C2A3B5BF97A0E61B98FF
+:10B46000F65E65B94ED98E65C5EEFF45A107D68853
+:10B470007B7D6624B1B604BE5F1140FBEA959EABAE
+:10B48000082EC161E9025E61BAAF51F6A33FD72F22
+:10B49000C75D8B7A1BE5BA29FA1CD191615C5FC04C
+:10B4A000389B689C226F31DEC7D3383FAF18F10656
+:10B4B000F8320A7C19B91FB893CF0FFA4D1B4F7A97
+:10B4C0006412E689BDF225D42F88CC5B4F1F6F0B29
+:10B4D000FA58D3CAF799FAD30A898E662471FB8F7A
+:10B4E0009500FC408E8D16F01D9E9FC6E13780872B
+:10B4F0004C85FA6F15F0CBE3F5BFEA7A4F7E4DEB42
+:10B50000D5E0C98B79C7AFECBB9AF024D7C3D8B6C6
+:10B51000A87ECEB4E8DA4DE579298DE985D4EE012F
+:10B5200071BFBEBCAF18DB1540BB19E5FD93901F82
+:10B53000E47D6D2C309D9CF57A212D06EE5FEBE4C9
+:10B54000F9296CA497DF43347F6E89589F5DACCF97
+:10B55000AEBD8F6E800FDFEECFAFD6DC472DDF0F95
+:10B56000C07DA0BFA289A2BF287E8ED51FF2453C18
+:10B570007C64E573BAF88BE143CE5307CF0138EB17
+:10B58000E627E1897C4CED8AA2F949CE3369008F28
+:10B590003A7E2EF813C713F9FD0D7F25F221DDD178
+:10B5A000F4DCD05D60C0FD53D9AEADB3C587725E2B
+:10B5B000C6BB2DDD5501D47F4D3D6594B7D9F0ABA9
+:10B5C000679E0F40FBB5BFF8410A26D39E36B6BB37
+:10B5D000D0CEADDFBD39C58BFB25C6400ACACFD35F
+:10B5E00041B532D639C0C67C45FAD16447350A7DAB
+:10B5F00073E6A9EFDE82F0F8B7DD263BEAD1A63D7F
+:10B60000969085E2206BC88E82F2095E7EE053F44C
+:10B610004B9BF645DB496B7FFA03979BE829906BC0
+:10B62000C0332E2C94CBE0D9D861F2841C3C9E0808
+:10B63000C3B026D6BF05E7A76F8FF3F802F0DED4BC
+:10B64000A92EC7F3BCFAEF2049C80E6BEAFE2ED92B
+:10B650005D4DDA3803E0A1368EDD75477E74BEB5E8
+:10B66000840B0B3AC9AE69FDD90FC79FB0E13D9A73
+:10B67000BF49518AB4FA7223C1E942E7CA1FEF7782
+:10B68000C7D7ABE7D12EB068DB71BCBAF729B427B6
+:10B69000C17AF8B3DE144A413FBF7EA7C9039A9727
+:10B6A000D53FF39327713F84BD6BA17B0FEA9E3991
+:10B6B000FCCE7550AEEB3239E6F2E9DB1457043FAD
+:10B6C0004D6E6E9F487CAC7DEE30DD2F88EFD1AEA5
+:10B6D0009578A9EB3A6866E306C3AFBCF3A0F8BD62
+:10B6E000051D7E3A4FDC48F778FEECA219E9FAF422
+:10B6F000018565160C6E5FBBF3700AD21FC209FD8F
+:10B700004B89A701BC0DC257E896FD25548FE21A5C
+:10B71000F1F0E6CD677C9FE757CFFC1C7FFFAFF6CB
+:10B720009F2C1E5C7FEDCFEF4DC1757C6C6CE6F4F9
+:10B73000FDC4669717C6AD35055C767AF2F7B53B62
+:10B74000EE23BABBEBE87D2EFE3B1ADE6CC3545AE7
+:10B750006736AEEFCEC717D2FA56333FD15DED1341
+:10B760003C3EF1B9F81D063D3E4F0AFEF87897853C
+:10B770002E2DFA1813D1318FF02D55E4F9DECDB40A
+:10B78000F75780C54DE5CF457CE0C5017B805999D1
+:10B79000262EDBD4F1402FE2E7CC306F26EEAB0152
+:10B7A0001C02025E0ADEABAB1EADC8E4F8616EA3FC
+:10B7B0008C2B83FD5D8EEFB17EAFC99B303EAA9D81
+:10B7C000D8AFE7E3CBF804CC3B11F7FD3E76C53E9E
+:10B7D000B7E5182EF99FF5322D7DC5E3F78E078961
+:10B7E000AE3E7B9BF34D63B0AA92BEF79A4278A41B
+:10B7F000B83178B05A21796089BA6F69802E3A4C95
+:10B80000829FA3BFC33C8D8A16BE07785EEDEAED2A
+:10B8100096A87B102274638EBC2F88F0A7F4A3EE49
+:10B8200012FCAF5FAF5E1E9CD0C903F6B87348F739
+:10B83000C9D49B824F3E86FC0BFC8A7E66FD332674
+:10B84000F2F3CFEE7DF99D5B81CECF764ABE8D9629
+:10B85000AB7ABEAD7D76328BC5B7676D1E16936F22
+:10B86000E17D4CBEB545F669DCECEB93AB77C59159
+:10B87000AB89C3C57ECEC03996A254CC753FF35474
+:10B88000DD708A0BE8E02AFD59BDBCECC877C7948F
+:10B89000970CAF9ED2C051C24FD2E3DAA71B689C6F
+:10B8A00001BA957429E976802E07E55746C151FF04
+:10B8B000BD57C8A38173431BC14F413BF6D72AFD37
+:10B8C000FE491FCC650BC0BD6F6F01ED836E167610
+:10B8D0007E9FBD3F05E37A9B855FD18FF1C4D4C8BD
+:10B8E000FBFE049137E0EB4F49D3D845277AD414B7
+:10B8F000B4E3C2C1D8BF232BEFA70CC7F99D597978
+:10B900007EA942B5E5AFC7386D3BDF9F5CD5B23845
+:10B9100005E3197D3D85F43B4277BE0EFE2ECCB784
+:10B920004FC635035E637669E45ED3532C40FB95C6
+:10B930002B7BEA68BF501F07596DAB4EC5FD407D9C
+:10B940001CE42ECC83C23CE4C7A3DFAFC5F808E2F9
+:10B9500049474F7EA4A7ECC1F4543D5CF065312B00
+:10B960008EDA7F1572AD422DFA3EDA277DE0B7639D
+:10B970003C88A945BF457DFA39FAF1C8000127D1B5
+:10B98000699DFF94CCB322BA9674A7F7DFF5CF7305
+:10B99000BF7CAF14CF03D53FFFFBF13F82E7B9E790
+:10B9A000DF1DFD22967FF58FF9BF6783EB971FF8A8
+:10B9B00003F92B7D072C349FBE03AFE57F1BCBFB28
+:10B9C0002D1E9C6FDF460BFF1DE803C974DF74DF7B
+:10B9D000301E676BFDF5C5F161D2539B7812F27092
+:10B9E0007E4FEC859EFF781FEF55BDD0637163DC01
+:10B9F000A1E94012F9E14DFB13E87EF8BE5F5F2C30
+:10BA0000D5C68BFEDCF5348AF3167DC9AC06F35B34
+:10BA1000FAD2B8BFD6F4E2B53F692940BBF420DDC5
+:10BA2000575CFED27F8E47F9D3F72CB72BC03FDF90
+:10BA3000819B88DF1DFEDCF74DD978DE88915F7D24
+:10BA400095FB33F2AB07C385C3A10FE080EB02B8CF
+:10BA5000D03DDDF1E0B1EB7F2D3C3E257FA1BE67FF
+:10BA60000AF151042E0AFFDD919EE4A055A1F5F3E1
+:10BA7000F7072E8E473BE96C670BE9FD2BADFBE02A
+:10BA8000FFB9752BA1A1AC3BFCBF76DD9CFE570F27
+:10BA9000E7FA49CF0783E9FC57DFA4F2CF933D349F
+:10BAA000DF21F23F6EBFA27CFFEF5EFF7F01F65207
+:10BAB0009D150080000000001F8B080000000000A2
+:10BAC000000BD53C0B7454D5B5FBCEBDF3493249C0
+:10BAD000261F2008C19B2F51F2194802E1A7938429
+:10BAE0005050C409488B157000955F4822D89A566B
+:10BAF000DFCBC4440CD4D547D5565BD135A0509E7E
+:10BB0000CF3E530C96564207540AADD5D142054D4F
+:10BB1000E948AD480D6404157CA5E5EDBDCFBD99A0
+:10BB2000B9378988ABAEF55EB2C8F1DCF3DB67FFED
+:10BB3000F73EE7586F035F8713A03711E6EF28C47D
+:10BB400032053C900ED0F0E2C4A75AB20056777E80
+:10BB5000B408CA00EA764F0019EBD5BFFE477198CA
+:10BB6000FAEF903CE27B62C021E1F73D9F89EF7BD9
+:10BB7000CE1503961FEE90827212D6EFB32F0FD020
+:10BB8000BC9930BF03CBD6AE73C5612C01DA00CAB5
+:10BB900001AE546D5C9ED9FDF763523A95761570EF
+:10BBA0009D863D0940F337FC2A2E00387F6FD7B9B8
+:10BBB000F13E9CF722FD5C0BD0D38C538C8ED6CDFE
+:10BBC00065CFCE3F8DBF07BBD4BDF04EF1E358F635
+:10BBD000BC7034FF45AAFFE2AD51EF60597FC97DCB
+:10BBE000EFB52DC5F63BAE5419BEE8BEF7DAA08816
+:10BBF000F67B7011F5EFDD93E8B267117CFF180555
+:10BC000031FBBFD4BEAFF97FBA6F003FC01000ABAD
+:10BC1000EC7564237C0F4230A462793FC08C0E67C0
+:10BC20007F785651E3101A0721180A2083F891D320
+:10BC300057CE82242A377C2417D3F83933B2100E1A
+:10BC4000BF6A716F55A98785F1D03ED21DD880702B
+:10BC500081E25DBE19EBD62BEBDC1B78863B01C67F
+:10BC6000037CCBA1CD3774D60C09E76B6D41B8705E
+:10BC70009ED62116572BCEA3A896A0BD98CB77A908
+:10BC80007C60E87507685DC56983A036F622FE739F
+:10BC900002D60BB43AAE179F1B53C77F71B0CFA526
+:10BCA000E0FA716E0502B8253BC48CC7FE33551708
+:10BCB000EF331E027E97F3F2F1F4F825F064C68F9D
+:10BCC0008EB77E780270D07885FE8BF69FBE2144B9
+:10BCD00072A880E20F8BFD481725C2A73BC381F3F2
+:10BCE0005993EF706F90F8BBAA8CD7C659E8CF1A5A
+:10BCF000037E117F9EB8E2289E63E6E3FD9BF17C04
+:10BD0000B9F8D5E912077398CE71239DEE00C27F72
+:10BD1000BF2AF07E3FE25D92A2F8D5F166A6433DD0
+:10BD2000F14E7914FFD1728AEBFD314C48B888C8C6
+:10BD3000F557414123CE53234F09FB71FE331509BB
+:10BD40006E3BC98B0441691C969543AB00F7D193B8
+:10BD50006953A89C1AC13DC5C07BED79072831FB0A
+:10BD6000AB841443BD27339FC7573B861BC6F50CD6
+:10BD7000AF70D0F71A5796A1FFEB7149C55042E357
+:10BD8000A6CFA0F6AF655C651837FB78CFA6C5587F
+:10BD9000DE2885CB88397A0E2EA8227CCD54C71A8E
+:10BDA000FAED42B542F21CA991035B101FB5527027
+:10BDB0006831E2EDFA828946F8249846FBACB3205C
+:10BDC0006B61BF1BDC9586F61B2B661AE6ADF5D4BE
+:10BDD0001AEA754D9F82920630B9E90228A50063E0
+:10BDE000831D86F1A5077619FA27BD0A722296638C
+:10BDF0000FA9AD5496768752897D6D690EBF2519BE
+:10BE00005938ECADC6EDC0F80F1A5FA2B2C981F87F
+:10BE1000C0EFE7E24489F4623EF71F8B0BB422BC0B
+:10BE2000E72C011FE1E16E39504065FC883B8A2117
+:10BE30001BE064C6837232C10FBE632AF2C1C48F95
+:10BE400003AD54BFF64287EC233DBC5DF6DB4A8868
+:10BE5000EEB3127E4F7AB74302A27B9DD3E20990E4
+:10BE6000DD4AED285E1BC35F1F7E1B6EF516F6973D
+:10BE7000D74D7995119ABF2DC3B3712FE9CDAA3F44
+:10BE80002D92B3FBF703971209EB78C9A671DEEC8C
+:10BE900091384E4E9CE620BD1E5F2DF3BEE06BD662
+:10BEA000C0569C679DC51DA7093FDB57D774EB663D
+:10BEB00092EBF62CA11FE27F07AA84F0C7A7F9E452
+:10BEC000221AF71F126C85E87A4B2B80F791926546
+:10BED000117CAFB8862C2CA2F1895C1F5F21F00881
+:10BEE000B32C813C9C72EFD413FE44C443FC8D966A
+:10BEF0004CB4409054E1F95D2ED6C787DECC94490E
+:10BF000096A0C042FA640DAA37D227C31ECC7A7419
+:10BF10001F8D3F60853C2C962EF09CCDC5FAF767AF
+:10BF20005940C2F6CE8AAA84A218FC259D97402DBE
+:10BF30008DD6DBB3548623490903C971D27985DBD9
+:10BF4000A129DF42FA465F276981FAD6DA9875405F
+:10BF5000F1AC22B8375CDDAD92BE4A3A22F6091048
+:10BF6000CEF0E2D6FE86765125422AE18C8589FD07
+:10BF7000E9F0B7EDE5292AD231ADD29DE2A6F2670C
+:10BF800088E4498C673FA9BFEFD39F2BA8F6686868
+:10BF90001AB66F271D28DA83807CBCC1A6B5930A28
+:10BFA000C17A9AA4B5FB1FF54E233ACAC6FE25D91D
+:10BFB0007DFD3D8E8CE8FC53363F1A6A2BEC8FD703
+:10BFC000BD53ED6C87E3910FECD877CD5585C360F9
+:10BFD000003B11C56BC225F09A24F07A01B53DAE45
+:10BFE000739743ACF39EA48E22FE7AD882529F03AD
+:10BFF000F092CB579D554EF0078BE8FB9224CFB0C3
+:10C00000A9C86F9D36CFA8EF901EE98A736FC171E2
+:10C01000B5777EF85813C9F1ECBF15A007039D8AC8
+:10C0200027611CAED3E0FA94E5BF462E4C26FFA64E
+:10C030000F8FC4BFB8E6F72DD13AE983A4285E3D3F
+:10C04000B9D8BE2106CF0E07E92B51FFF7AC67BC6C
+:10C050006D44DFDB1C8CA7B59A0CB5A5C0460BF26E
+:10C06000FF59D7B6AF133F9CDD6E05F2933AA99105
+:10C07000EC638183E508D2C319B5C8F7456F58BC96
+:10C08000E48775237F78883F1AF30DF39D9DF25660
+:10C090006A118E3B9BAEA4127E56866D8CB7850AC4
+:10C0A00004EDA81F3BD36FABAEC4F6CE232AB777FF
+:10C0B00068F33C9BE7599EC576659AEB7DDC97E477
+:10C0C00099245F1C3338BDC862BEAFEB43C4730311
+:10C0D0006D3375703E68AB7404C8AF6CA8682924D2
+:10C0E0007BB026257F18E03E1AA6496C5F1B9A3E5E
+:10C0F00066BCEBF32BE76550D3A275778ECA7650FA
+:10C10000513CCC0FCA791BB7D7359D65BD8DE06416
+:10C1100091DCF4B408FDB6D10AB7D66259F74FF9ED
+:10C12000D65AEC5F872CC5F601F6D9D6C4E83FE8AD
+:10C13000F8A84FCF9720ED1E9EF5663CE9D55AC969
+:10C14000350F700F87B36DB5CA70ACC7B9E64958E3
+:10C150000F6CE9F5723DD335CF82F58EACDA5A65B6
+:10C1600022D687BB7E687103FC69CB4AD13FCB7571
+:10C1700098EA07B31E10ED89820F7E98755BADBFFC
+:10C1800090F8CBC97839D39EC0F231189E9735BD4F
+:10C1900068C04BBF7659BAD54B7C355FE8C153EBCD
+:10C1A000476C66FF2737944F6B6E273D8B781B8A51
+:10C1B000B4A9C07FAFA0DC3B100FE939E0B160FF4C
+:10C1C000F45FA0FDA1FEEF854611FE96FD222E280C
+:10C1D000213D563FF1928DECCF1259CD27B9FAF59A
+:10C1E00068DF7F935C9D4E0C717D59D31E86EB1FDB
+:10C1F000B92EE19FB822855EE4CFE5B0D146EDCB04
+:10C2000041394E7602B528FB312B9D2FDBC80F5BE1
+:10C21000F9B4F57838C68EAE82F03192D3BA67ADF4
+:10C22000C7C331F616687C0C7F1DB70838140D1F84
+:10C230004BE4D0229B806B2FC1B53A15FD7999CC88
+:10C240004368A88FFDA0BA028E4332E281F86EDD0A
+:10C25000156F17FB06B07B1DCD68E751E47634EF10
+:10C26000E2B21DE724BD334C09DBDC384FBDA69795
+:10C27000C7878EDB2066FC31CD7E25EF92B85DD777
+:10C2800017D176619FA0D033D68270AC9EF3EA14AA
+:10C29000A28B4ECF6B13A0232E95E9E2D6E8E226BF
+:10C2A000BAE8F8477C962A38EEE50B382E6B20BEAC
+:10C2B000D0F12FE0ED8C17FA22B2338EFD2433FC3F
+:10C2C000E7343ED0F791902DEA83C19F909D28E8F6
+:10C2D000FA2F863F215BC8B1791FBA1CF7C57D2DA7
+:10C2E00003FB293ADC97CF6721DB17E1335DCFD41D
+:10C2F00083AF80E6D7F58A8E671D4E1D5F9D14FFC4
+:10C300000C00A7D2F44BC37E945015050D50909DA0
+:10C310002DF458C74C203A284DBBB9DFE5EE47D77E
+:10C32000B783ED4BD7B3E6FDE9FA56DFA7AE77F555
+:10C33000FD4E4545C2FA10C3768AABAE3DEF33F8E9
+:10C34000BD95B0C2E017573BEE34D46B5CDF31F4DF
+:10C35000FF5A468BA17DA6BADED07E7DC10F0CF5BB
+:10C360001BDC3F36F9ED9B4D7EFB7F1ADAA7844339
+:10C37000EC67BFD63C031474ACAEF920C2FE76B0B5
+:10C38000D9C5F57DCD195CBEDCACB27CEF6F2EE07B
+:10C39000F240B39BBFFFB6B982CB579B3D5C869AF8
+:10C3A000BD5C9AF5C2ECE7BFA1507C5211DA584D42
+:10C3B000AA7C5B8EEFEE6CE487D72D81D644C4D384
+:10C3C000846EE18FC372B33D3E77EC1EB2EB2E9BC1
+:10C3D0009BEC61DBDE89923A803F9784F6CE13C3F3
+:10C3E0002F49B3C2E021BF07CDF340FC756FB6857E
+:10C3F000E9476A1F50EEE63BC09A8EF2367FBEE4F4
+:10C400006E15E6C00FA95C067DD83E5B013FD9FFE3
+:10C410005AA712B42731685E07C2394F8009766A7D
+:10C4200027FB9D9EA690DF7A137D4478658F0CD7FD
+:10C43000E0F77915BFFB8CE2E46F3A3BACC42737D9
+:10C440001FB8EFD43DD80E6DFE72928F3EBFC1FF74
+:10C45000B6E572FC867BB3855CF54AEE9087FC9D61
+:10C4600014C51DEBFFEBA5375BF8FFB35BFD721244
+:10C47000E233F206B01FA7CB23EEAF9DE0D7E5A2D3
+:10C48000D6A504472791BDFF4135F5AF3BA4325EE9
+:10C4900074B9D0E5408FFB7439A8919F6DA5FE67F4
+:10C4A0008E00C7CF137A7C1F3C4FFB34F99D15914A
+:10C4B0008DD514875D2A4E9C74BEE325EAB7A7D9B3
+:10C4C000C77CB4BB793E97C1E6E51A7F3672FDE5BD
+:10C4D000E626AEEF6FF67379A0B95DE3CF8DDCFE93
+:10C4E0006AF3635C7FAD39A0F1E976FEEECE11F61A
+:10C4F000F7E350F530E2BFA7B245DE061C951C47B6
+:10C500008022CA2FCA2775192F0A7FCAC41F66BE88
+:10C51000D0F901506F4888AF6FA29D25FB700BF8D2
+:10C520008B1663397FD946EB64E9CBF3C54A671BA9
+:10C53000FB1F667DB80282ACEFFAEB77E1FF5F4A42
+:10C54000BFCB189F92BDD2F5DF6A08F37C76F94E17
+:10C5500037E54FBE3ABBE2D2EC0A2CA6FE7D7176DF
+:10C560007CF722D972E9383B7BA418AFC7D9E83FE2
+:10C5700002D9E5DE80CC7EF5F2AC8D491C675744CC
+:10C5800092C80F58D125333D30CE548623DD9669AD
+:10C5900074EB81E01F892ECBA62CE33CDCF24DC668
+:10C5A000FDAC74DE941C5407F4D306DC673D3CF804
+:10C5B00011E5E3EA357CF17784A7A9FBE6992FC75B
+:10C5C000F4FB243B319DF355136002E103E177074F
+:10C5D00049CE0EC92C6783F1C5698C4F88CFCF3502
+:10C5E000CF9FF932F2FDE90BCD1C7FFD33FB811F9C
+:10C5F000F8477E75F45A97E74DC8E1BC5BD846F220
+:10C60000A3D36F1DE948847B5D95234081766FB984
+:10C610004BA1F57B258F4C7987DE77C1DD82F8ABA6
+:10C62000DCFD9B23241F950E279F1BE0267A62E9E1
+:10C6300039F190AFD589FD26BCEA91C97D2F7F39AC
+:10C64000DC4ADD747BA3DB9FC93D11D9C779815CCE
+:10C650009623C0D8E262CE17972373BCD94AF1263D
+:10C660002AA4B3CEE90CEFD920B8E97B348F25F2A8
+:10C670004B932F78E424846F9D161F4E7CCFCB7094
+:10C68000781C2AEB17BB164FDA332CF82D8A479704
+:10C69000CDB79DF29DF0AB38CEEB9AE19B9023F4A1
+:10C6A0007872AA7702E3D7A9E653DC5023F76C7BB4
+:10C6B0009CF8A133C14D791BB3BED5F5DB607E7B01
+:10C6C00083EBEC807EA45E3658C439C1B86AB59459
+:10C6D000E23FF22F292ED4E34473FF9ABCAAEB0861
+:10C6E000BE1A794AC84370B92C9FCBA70D4D1F7D48
+:10C6F0006E9CA6AFDFD055EE5A12930769CF91B466
+:10C70000FCAEE27ADF11A5DB17A5EFD4C87C83FD70
+:10C71000F9BFEEAFCD46374742192A9202C28F00C9
+:10C72000E14F2C8010978B20C2A50F3989CA25E0D4
+:10C73000E6F236F07219CEF535E790BF608D0C2524
+:10C74000393EF5C2DF0B892F4E5D33D995A546EDF5
+:10C75000AB6E6F2FD7AEC6D379D200FCF090C6B7C0
+:10C76000BADE1E943E26BDDD3B16F5834C79A1C88A
+:10C77000A21729DFBBC7EEDA1AA31FC06FF4170791
+:10C78000D317358A88DBB75BDCAF531ED1FF5A1A4B
+:10C790000C245F7A399BFC49E4C7E40561251BF949
+:10C7A0002D3FD5F334F1B3FF812929AC87498F5C44
+:10C7B000897478579CB7C00A299087FBDAD529EA93
+:10C7C00045B7A70424B6E741A6C742085B691FB76F
+:10C7D00002B0FE5C0C2A974BC1C374C199138A51F5
+:10C7E0009FDCDEA98CDB807095A446B249CE8A26F8
+:10C7F0001E4D9570FD62F2639D9C6369277F4387A0
+:10C80000F3448EF0632FE67876115D4B52431B1E86
+:10C8100026FF6EA705C8BF3B31F13B77408C7D1CDE
+:10C820009157D545FB784E12E77CFE2EBBC88F4151
+:10C8300064A837C6AF0EE756BF44F3FD568BE7A199
+:10C840007B3D9FFFD4BA044E61DA10C6018E1B45B2
+:10C85000FAA7BF9CF9795C09E97B91EFF34305AF37
+:10C86000CBF577724ED4B689FDF8C9AF1A91E73B84
+:10C87000447095D850A511FC4FD8035BD8FF691CB4
+:10C88000457988654FDA2D648F8FA23EA5F3CE7768
+:10C890009A1D5CFE09E3142AFF8C710A95EF629CD5
+:10C8A00042E55F304EA1F2F6F3635129231D723D3C
+:10C8B0007F617D39C83E06D7177ECDBF86F9039DBF
+:10C8C000D3756B7C5DDCF9DE7D09C407BB64771E24
+:10C8D0008250B453E17CC2E9DD130272562C5E7DB6
+:10C8E0001182A378D71F1E9A5C46E3149784FD4FEC
+:10C8F000EF3A3B94E31F137C7DF8E8B2097C68F0C3
+:10C900003E9712DA40E39FDB994D10A23E00C187AB
+:10C9100044CF01F261002DCC27CFE708FFF6467B1C
+:10C92000A42CF65C12C8F453DE51B31735F285A47B
+:10C9300070A1967F9D487C9DFB3AADE73F20431E4A
+:10C94000F3A731BF50902BF0A097455D362FE545FA
+:10C950009EEBFAE39CEB110FB327CD2C9763E42DEC
+:10C96000237788E837F1B39F3C9CCEFD5DB4D4CDEE
+:10C97000B0B9C685FD6E71EC7D8550B0D0F56E4DB9
+:10C980000AD66FCD90F653B958CD9A9EAA12B80127
+:10C99000DECFD282CAFDC462B3DCB536B2AF952415
+:10C9A0005431FAB3DA914027A07DF51A579AA1FEC7
+:10C9B000B58C1186FE33D51C43FBF505630CEDFAEF
+:10C9C000BAB3DCA5867E24AFE4FFE23E98EEB05514
+:10C9D000E6F394A29D1FBFBD8AF77F7319EDBF17C1
+:10C9E000F1674307E1838AF53F7A98D4C6CE7D4943
+:10C9F0007CBE6AF233EBBA9EDAEF5107F7333F8120
+:10CA0000DD03FA67F583F8675FD4CF44FDF110E9E1
+:10CA10008F92176EE2F3F2E7267E76854AFE722E3B
+:10CA2000FA9F884AB3FFD9ABF99F66FEE9E3534901
+:10CA3000157C7350667DABFBA166FE01B84FB3E376
+:10CA4000A2BC5C399FFDA6B03B7F25794F8BE56B7F
+:10CA5000AD34E5154A6C680728DFF77B19B6D08737
+:10CA60000B08878EFF9C28DFC36D9B5F195EC6DFB6
+:10CA7000FD89B864BD966768CED5FC8EBABDAF0C93
+:10CA80004F8FB6C35DEF1AFAC3BDD27E43BD2DCB27
+:10CA9000587FB0727FECF8C1F4D0B24D77DA7C9455
+:10CAA0005F7E44E41BCDED3A3C35FBE23CA42F9580
+:10CAB000DD768E6BEA5D1ECE832883E44174BD7003
+:10CAC000B30C8D03E9B70DDABCB3F6C581FC25E6DE
+:10CAD0003D8ABC42F0F87F21ECCCD1640F7863D65C
+:10CAE000F961AEC8039F4AD9F86F9F62BF53BF0474
+:10CAF00037A1FE548AD0B7C59D272C16B213F182F8
+:10CB00005F8A5D614B2ADD53599EE0A773E086156D
+:10CB1000897E3AFF29C98EFCD181A47F2277EE431A
+:10CB20000EE4BBB72D1683DDE9255D87F56D4FCF8C
+:10CB30009943E76DD7EF8B0B5ABEC47EB6511E9357
+:10CB4000EC549590F745C437FAF916CA47C3FD600F
+:10CB500038EFA2FD53FD58EED7DF7C84CE6B0E0A72
+:10CB6000F9C766A739AEBC2526AE844D427E1DF8B6
+:10CB70004BFECBCA9737DA28DEF9AAE47E6FAE33D4
+:10CB80001A5F8EEE2FCFBABC371C16F27E66F727DF
+:10CB90006F925E3F83F62E56DE757CE972DEF0986A
+:10CBA000CCF2A87F3FBD5B9E111800BFCF6A7C000E
+:10CBB000AE7CC3F9D79AA9E7E6905D5BD3A5F0B93F
+:10CBC000DE60F6BAA1DD78DEF5DC1EFB72711E2C8C
+:10CBD000F6D1ABDBD3AE4F522B0B45D9C2E7AE1B20
+:10CBE00035BD23FC18B4A3D674B2A3B512E7D10E99
+:10CBF000770DE37B15872508AAE3788A9B1C48B745
+:10CC0000B9623AFAEE247F0C320A145A678E46CF84
+:10CC1000B95A7E675ED7BC3CA2D71F3B971CF66013
+:10CC2000D327B939BCCF6F809FFDC1C329DE4CBA71
+:10CC30005F30BB55F0F7E194480FE5830E4F4D9000
+:10CC4000E85C09E76F8BF5F70E5BBD998DBC2FFD96
+:10CC50009CF16AF962C265C4B39A3E447AFA25111E
+:10CC60009731FF2BC31F64BE5A0181FD1E5CB7DEE6
+:10CC70001D64BF741588F8DCEC97D74FF9D0467661
+:10CC8000C11C4756EEDA7B84CE2FFAE5134CFC7AB2
+:10CC9000A9FC81397E1DCCAFCF4FF566E4C5E4EF2A
+:10CCA000CCFE799F1FAAFB515B13F87CE7A5A98FE7
+:10CCB0009E5E85F5BBB626B8285E3EF9A4DD4F7AA8
+:10CCC000F9E4167B40C2F693A9916E8A134EEE28C2
+:10CCD00072E30CB0CCA2FED7B364D79FB1325FE051
+:10CCE000CA86FB096BA6DECDF7F6D66C4D94E8FE3E
+:10CCF0000C6488763D76937F9AC87EC18AE787F375
+:10CD000079A56E5F483EE87CF98327E23CE4E49F26
+:10CD10003C303799F2763D969FF3B93CC8F71EA395
+:10CD200073F755DB12C7F1FD8B4260BA2DDF721528
+:10CD30009F536E547C9368FFD53FBD6118DD075B40
+:10CD4000F1872140FBE9DDFD3C9FE345FDF481FDDA
+:10CD5000BB33BB7392A1308A273D9FD7FE748B975C
+:10CD6000E85E2EA9E2BC051A3D23882F76D502CDB8
+:10CD70003B4E16F73D23EB13D82F35F35D6D9EF038
+:10CD800003EBF4BC411A3832487E7CC078E85D3F42
+:10CD9000660B9D6BADC84BD5EC74247F4ECC7DC229
+:10CDA0001AB9BB9EE2BD339BEC9CCFE8891BF83CD3
+:10CDB0006B615E0AC3B7CC613CFFAE6FFACC582FF3
+:10CDC000040FE99D71AD6AE99D58AED5F0DF92E997
+:10CDD000F5E5E17A2B3B7EF0C2AB8C974DDF7E9B75
+:10CDE000D63DE01479945705FECCFEFF3287C85734
+:10CDF000006C6678F5EF279E788BCF494FEC1C933B
+:10CE00002FCE7F43EF3F9EC5E7BEC7EEC172C781FD
+:10CE100037992E6678FB9DDF4912EFB78EF6914663
+:10CE2000E7B4DE6FE7F1FD1D11B72DD950C4F8D37B
+:10CE3000CFD17A4F0E1C9FE870EAF3EBF0E9F3EBE9
+:10CE4000FD5A357A5DA7C507A76CA1D37C1EFEC22B
+:10CE50001889F2747DDF5343C52931FCF255E5C5CD
+:10CE6000BFA9E5358E585ABE65A3FB6D1D0F5B7DCE
+:10CE7000B17AEF32F3E17D7EA00754D750614AD8F2
+:10CE80006EE1E694A1746EA7D54918B03E45034FF4
+:10CE90002278E8BE9F56C24A5F06E7BB693E99AE5C
+:10CEA0000F06B8DE5AE956A9BC56F22AE2BE5680F1
+:10CEB000F9723A348EA47D581C613EDFD2EFABCCC0
+:10CEC0004B59774316AED73604D6911FD3661572E9
+:10CED000E15F9CC0F19B8E27DDCE80ABD0605FDA36
+:10CEE0005CA02A38CF7C05DAADA9A2DF9588E7C31C
+:10CEF0000796BC427EC25B4AE3105AF7A8F3912220
+:10CF0000C942FE5D209162C4B7DF7CA6FCF7D8F76A
+:10CF10001DF04C7522FFDCF41B07EB7D733EE276BF
+:10CF2000F0717D1984AD1FE3B83F4FFC9FADFB202E
+:10CF3000BAAF3F4FFA7427C507B7A4DC574EE3F5E5
+:10CF4000FB93E67B7A275D4EBECF67BEAF7723F8B3
+:10CF500042C4CFE72CBE7A91FF689C40F6B737C534
+:10CF60000612F6EF1DA2E1E314303E7AADDAF88F37
+:10CF700054AE97558FE3BC229C53591F4F36D99B13
+:10CF8000B2311611875D14FDA7461483BD292BD13C
+:10CF9000F2367F57D92FBDF6BCF2B9F6A82E5FE462
+:10CFA00059CAD22C8D03F98756ADBD1582B2D88FE0
+:10CFB000F01326F7F1954726FAD56BF57AB267C8D4
+:10CFC0004FBD490E3F5D509CBC5BF0D76425B897C0
+:10CFD0004AD4AED0447EC52EB4773A1C74D697316D
+:10CFE00086F96092CE9F38D702ECB74E6AE4B8C596
+:10CFF00041FE0C961BA410C3710D44B8F46876BCB6
+:10D000000ADC5C4E032F97C89F5CCE404B42E5750F
+:10D01000D0C1E52C0809BB7F75B095ED19DCEBE2BA
+:10D02000F86FE6320BF91B65DF18385E187D493C56
+:10D03000A0C08DBF7C3C4C0794BB9C01F031B280FA
+:10D04000F587191F66F99C0A6199E59314430EE56B
+:10D05000095496D36AF070BDE60BE2A122EC533876
+:10D060004F63C647F5C07CE1D6F0F1E77C10E71FBF
+:10D070001A9D96E6AB5CD7E985729541FC6FA6A335
+:10D08000FEBD2CA1EA2C5D29BF7E5BE65CBA1F5574
+:10D09000565AB59654F282FCA2B9743FAA6C72D566
+:10D0A000F37474B9685BB1A89754955ADD68DF5A78
+:10D0B0004AE64EC3FE3EED3E31CC17FEF55D9ADFEB
+:10D0C000E26BF996DB8572E2CB74BA697F0E74EE7F
+:10D0D000E95E8A9C23CEF946CD08EEB362BFA38AEF
+:10D0E0006F7A3E9DF73982492AE2FDAE961ABE7FDD
+:10D0F000F6804DF4B7DB457E55DF177EF7C7617DBF
+:10D10000C78E316BA5ECC1D7C779E7E60F2138F29E
+:10D11000FC24AFBE9D925B50B26AD87C94CF9E90A7
+:10D1200015281FAAAF939EE99B4F7080239FF3643D
+:10D1300023347FA667C798314497A5F9DA7DAAF40E
+:10D14000AC52C25B43A67729CDDF9B28F86B29D16F
+:10D1500061C8E0E5F7F23D8B697EF3F7DEBF2200A0
+:10D1600038FEAE7CDF329AAF21E102DBF7D363FFFA
+:10D17000B02E9C15E5530989B400F7DDEA81808D56
+:10D18000ED8076CF5C3B77EABD1DE7413C94797D2D
+:10D19000ADA4D2262C888C27FD89F3AEA1751B6C1B
+:10D1A000E1516371DC23738FD9049F8D147CA6E950
+:10D1B000A1AE3D07EF1921AA5E8891AB863D9F7D08
+:10D1C000FA0EE2AFE18CD34DDDA3F2F4E3B51C4FD0
+:10D1D00082D3A03774399BB4CBCE7EF5E4DD57DD26
+:10D1E0004EFDA6FEA13B87F6756D7798CFB37ABB4F
+:10D1F000DE1A21E0D0E38D73D297B1BB74DECA7121
+:10D20000DC4E71DEBA466A7C2991EA3F93DC7E846B
+:10D21000FF846637F4B878B9B6AFD507B7AEA3BC0C
+:10D22000C8F24D4B67F17D9C80881B54FC25F9FFAB
+:10D23000045EE573EE55DBCDF144C446F45FDD6179
+:10D24000BAD743F130DD5F88D5EF03C4C34FE56B38
+:10D25000F9AE4CC8E47DC80B927D03E83B73BCFB80
+:10D2600018789EC9677FD62BD3FAE5CAC0F9842700
+:10D27000A2EF3B581E96696B139E9C1CEFDAC4BD4F
+:10D28000DF27D6BA5D54D7E47333F24A05F9D16D7E
+:10D290003F66FED7C7E9F2BAA25DDCAF864D69CC26
+:10D2A0007325DBEC1EA26BC9B6611C5F601CC47EDB
+:10D2B000DFE66DF676AAB7DE1FEF974B289F1CB905
+:10D2C00082F22AAD71E27D129947BAEF59922DF29E
+:10D2D0001CC774BDAED975FDDE6C5FFC9398CFF7AB
+:10D2E00093FBDAC38A21DE68D5FCE732828FFCC06B
+:10D2F00046AB889FE204FC7BDFF87A02F9B13B156C
+:10D300006F02E5A5CF1CCA4E8601F0A697E5685EC0
+:10D31000E073CE0BCBDF9A95F379F42A7B4CBB6795
+:10D32000AEF1E7AF9A3DF0176B941EFABE6AE46760
+:10D33000AB6D94E7B80D5C94F75873F0A9567A2753
+:10D34000B3663D7046E10CFDA178E1030B9F674F8A
+:10D350003A589A41FCD8A9E93B3ADF5563F86A3C50
+:10D360002585B07FF94808D0BBA138351ED498B8C0
+:10D3700038A120D5504F745F61189F5C916D68078C
+:10D38000BF2754383EEABFA678AE36F47F20693A0C
+:10D39000BFA3991ABA83F34A6933C619DAEDC8D71D
+:10D3A000745F013E16FE4F05FEB25D854699E09C16
+:10D3B0001C06F809F2DDA41EA37F5411DEC87160BB
+:10D3C000DC21C510D7DB2F91674A1AADC9D54818A3
+:10D3D00029F48319DFC67B0D6B0ECAECC7ADC944B7
+:10D3E000C7336B707CEBF2A7E37D88D788F761F3D6
+:10D3F0008D781EEE33E279C472239E331B8D78BE86
+:10D40000B2C988D72CBF118F39ED930CFDF3365676
+:10D4100019EAA31FBBCED0FFAAC01C437DCCF66F78
+:10D420001AFA17752C31B497EC5AF9B9741F1B5CB2
+:10D43000636837D3BDF4C0774D7CA8309ECBB577F9
+:10D44000553AFDFDF84BF49F0CDEE4A044E9407F23
+:10D450002BC9E3BF8AFEB3476BF75874FA7F41BD0F
+:10D460005AA8F94FE6F759B31384BE79EDC0994332
+:10D470001EACBFAE965A33C86FD2FC03AF7E1E619E
+:10D480008AFBF438E5C60AC974DE1E67386FBFD45C
+:10D49000FDB4F250D0501F7B48BC6B1A77C4FD120C
+:10D4A00095E5EF79E4D8774C133F66B3DC2FEED4E3
+:10D4B000EFB9E97113643CC971E8021D7E1282F173
+:10D4C000FDF38B7A7C6A8E5BF578B5FF3B29E1979B
+:10D4D000DC2D0F16C78AF8558F5BBF0E1E7E0F56C8
+:10D4E0003ED2B76E34DD9FB244D2A85D8F6709B1DA
+:10D4F000746EDC4B8865E7E2E05C4F21BF23E5BC3E
+:10D50000F7CA9657E6D27D7D04DF151E2FD23FF471
+:10D51000F3E468DFC6D1A8778F4BAE75A538F6B5B2
+:10D52000491F8EA2F91E1E2DF20C76193184F66762
+:10D53000D8020FD0F7FC54CF23A387F4BF676D2E1A
+:10D54000CDF77F3A9B835C2A2E37DFBF31E707C3D5
+:10D550001695FD4EFF7725BE6FF321013731EAAFF7
+:10D560009C69B7B2BF025A3CBE50C3BF9EB758A019
+:10D57000EDE7384EB11CEDEFC25DBF61BAACCAE851
+:10D58000D1F21D8DEC5F2F1DE91CC7F7C93CA56EBC
+:10D5900091E7D2F318232EEB9DC8A5F6BF2AE3A48A
+:10D5A000218F04CFA67DA1F3EDE8BEC5FCC7D78BC4
+:10D5B0007CE4F1F5999CFF8ECE7F9AF3490B1BDF3B
+:10D5C00030C8C5AD4D470D72B0D8FFAEA13D9C1E11
+:10D5D000B152FE30FCC2F0E9B720FE4EEDB4F33B91
+:10D5E00066E4833746C7E4CFC2EBC74CE3F79097B6
+:10D5F000DCE7870C47777388E9ABEFF358F311AE9C
+:10D60000879BC35C9AF7A9E729F4D2B60F0AE89E74
+:10D610007D448A77535ED89CBFB8DBA2BECFF72289
+:10D620000BB2B57382C6122FD34FE42BBAB577A1D4
+:10D63000DDDABBD06EED9D67B7F6AEB35B7BBFD9CD
+:10D640006B75B6535EA35B12F77716489E2717E3F8
+:10D650007AC9237D1F915C35AC8C142BB84E43499D
+:10D66000789184741E39C4F731E145C2706138BFC6
+:10D670000BF2F33DAF0F2CFE627A47E32EC8B88958
+:10D68000E2BC0FE2FDA7C91329D89E26EA362187FE
+:10D690001505FF60B97B0F27A3FDF97F2989BC928F
+:10D6A000336CA3775053D37D503044DCDFE2F72F47
+:10D6B000F89DF852CF73F65A851FD8ABF983F6025E
+:10D6C000710EE83095D944F3725A0F343FFFC17C94
+:10D6D0007E37B2C90EE4BFE2FAFC4E46BF67627EF7
+:10D6E0004733EED7767EEFA0E743471464F17CF42E
+:10D6F000BE86E432FD7B09ACB7201C1A45EF71FAF7
+:10D70000E03D24DE439EA23C724CFE794481F6CE7D
+:10D71000F13630BCE7597DF0F8318AB37E3DDA77D7
+:10D720006501CEBFC4A28E27BAAE4EDACBF9AEB138
+:10D73000052AAF8BF08AFDCAD046745AED08737E75
+:10D74000EC52F9F0C1F67FEAF6D08F0A39FFAB163A
+:10D75000F37B3A6D5D84636C414CDE5A87233ACF8C
+:10D76000E7F3BF9ED7D5EB279E78205FCBCBDFEAD0
+:10D770001DC09ECED0F0D26D1D388FBEB440C423E4
+:10D78000FDE8331A4D11DD538C471B81E53CC21374
+:10D79000E5816FC6FD707EC23396E8BB7A8E93DF5B
+:10D7A0008DEBF3E33CBE9F7FCE3A2D99DE1B89FFC4
+:10D7B00056368ABCBBDEDE2B09BAFAD78B3CE8EAC8
+:10D7C0003D478FD1FFBF60C54F8B4A39BED7C69B3F
+:10D7D000F18CF8E5F74D4B64716E85F85D40F39B75
+:10D7E000F3ED5F16AFBD99E27CB577F367A3E8DD93
+:10D7F000E86ABA7F46EFBCB4FC15741AF352882F5E
+:10D800003FE52BFA9F47019F6BD9353B62D7C78F06
+:10D81000540CE3BB9DDEB5C41F2F687A03FB072CB5
+:10D82000B87EA71E279BF2289D2191EFECCCB0B1CA
+:10D830009F4CFE0ED927DDDFB9EB0D91EFBC2B4BD2
+:10D84000F8D1041FD1573AB29FFD843EFB2FB95542
+:10D85000C29FDDEABB9FD607DF5AB65FF295485FED
+:10D860003ABFF8ED755A3E40D8C372CDFE95D33C11
+:10D87000E4E01426B35D2CD3D645FF91F36E13C1BB
+:10D88000D72A80D1F266EBF7731EE17F01BC43AE6D
+:10D89000E0704400000000000000000000000000F4
+:10D8A0001F8B080000000000000BFB51CFC0F003ED
+:10D8B0000917B0A1F2AFA1F1933951F93F5951F9CC
+:10D8C00017D0F884B02E1303C30A46D2F420E39D88
+:10D8D00040FD0780F838109F6322DF1C103E28CCE3
+:10D8E000C0F0458C816116906E01D26781F82B10D3
+:10D8F000DF06F245441818948178BE28034314903B
+:10D900005E0AC40522107D8780748D287976AAF37B
+:10D9100050E6E6514C195E298DCA2F55616058A614
+:10D92000CAC0F05A0DC25F8824CFA0CEC050A60254
+:10D9300061EBC931307400D5CC94C66EAE3E50BE9A
+:10D9400013282FA00EE10300D191FB3B68030000D8
+:10D9500000000000000000001F8B08000000000015
+:10D96000000BCD7D0B7855D595F03A8FFB7EE424E6
+:10D97000B9819B90C049081834E0490C0F11F12679
+:10D98000441A6CC41B8C1A6768BD606B231588C869
+:10D99000687C4C7381248497066D2D83FEF462AD00
+:10D9A0004329ADD16287A98FB9202D689D1A2D56C4
+:10D9B000ED4FFF46C6B1D42A7F44F1552CB3D7DAD8
+:10D9C000FB24E79CDC04D0CE7C838FC33E673FD62C
+:10D9D0005E7BBDF7DAFBBAA104E0128053F8873D05
+:10D9E0006F9000206FF0095EA3092200CD9A5B5F63
+:10D9F0005F0CF04DC538A857B1F7A365E3073ABEF1
+:10DA00009F580B610005EBE70318F83FD66E4D7089
+:10DA1000F5A84490BD531666E1D3ECDF7C36AB002D
+:10DA20005A257EDF3831D377F30929577F9F17E8CE
+:10DA3000CF29066AEBE1D727EF37CBECBF020845C9
+:10DA4000DE0AB0BF4C87E9A71480E3C10559691805
+:10DA5000BEBFB7DBBACF5327007CD4F6DAE4FD13A0
+:10DA6000867EFFA6022D3DE543DF4F0736E854C40E
+:10DA700047D21D9F3C38EF81790619922E64ED0143
+:10DA8000D29E1CF6DCB1F93CB56C104EE73C00921E
+:10DA90001CBF9FB39D2752932E60A50A29318BE0AE
+:10DAA00052D93FD300A82A5B97253B1A80E072C069
+:10DAB000DB11F9DBC03BEC7A897AC783AB3B91B4CD
+:10DAC000D6B838BDB4E7C9C66A184A2FE67A98783E
+:10DAD0003CD3F5B81D7C348E4947CDF2C211D7FD39
+:10DAE0007474743DD2D179FFFD7494FCDF4B471DF3
+:10DAF000D4CFFF323A02E8E6F8823E15C71F7CCF4A
+:10DB00009F91853D12D2192BF622DC457C28286A8C
+:10DB1000EDBC599EC2C41418CF9DC3E45651DFA278
+:10DB20007A847BF4E1797FC26767634DDDA56C7E03
+:10DB3000F94D3D2F7D893D23F1949460EB751FC80D
+:10DB40002854587F3725ABD9FCDAB1B399008F241C
+:10DB500017C592385F88018C02F8073127005957A2
+:10DB60005939447FCD340F37A4393EA4539EA1EDDB
+:10DB7000879B7F08DB99758AF1FF2B00E777BA76E0
+:10DB8000B0928F9764FF20BEC70C8E4FFDE4375BC9
+:10DB9000CA80F8B17FEFC5BF107E6FFE1F19AF00BE
+:10DBA0002A7D281F42F5B296C2FAD093ADB272E434
+:10DBB0002615D24C461454754B2EFDF4EBD2095069
+:10DBC000D7C3D7476A080DC2F79F2011FD8CBDE36C
+:10DBD000CDED6B19C99D581834883E3480DC9CA16A
+:10DBE000F3F94E1B12B2A5DC582325683CE3B95269
+:10DBF000D63ED9C8F5DE7DF50BB2ADF2CA23490297
+:10DC00006F4EFA005D9D866CC5E943AD9763BE29F2
+:10DC10005F9C3ED4CF491F792B2DEDE0ECD72B62D2
+:10DC2000DA0567481F5F743C735D87F2D52AB1AE91
+:10DC3000A53E607C7B6FDD828C76C6F0EB5A49FC9A
+:10DC40001EA987582A43BBFC81F54C0E7DB2F551C5
+:10DC50000696F716DB7A29A3A7356D1F011F4AC464
+:10DC60003E5FB35F5FABA2BF99CB8AAA26637F6E8C
+:10DC7000EC8FD1D9BAE8BD4960FC7002699BE143E1
+:10DC8000E9AE4863194AC1F881804066655F349601
+:10DC90005A4F7490A27531E1F3E8B20DFF6AC46F78
+:10DCA0002B435352B2C2EF6B75131C6E1C8FD1BB4A
+:10DCB000A2B10E192AD420A47D61ACC1E14732384B
+:10DCC000351ECB77DAE8A04BAF844CEB60D22BA2A9
+:10DCD00095D3EB9D67265F9CE335DAE13DE3764122
+:10DCE000557FCBA287866FA7C25BE6FA30247E0DF4
+:10DCF0003B983AB84E6B5DB0473A9FE9EBC2AB2117
+:10DD0000C1DEAEC54F17129D923DB3B6B05243BAB5
+:10DD1000821D928A709A7A14A23954AF42D2A91FF6
+:10DD2000D9DB02584F09C6E8697E1F1E2E417FC904
+:10DD3000D8DE52D6EFE5627D2F177A0DAA5C6FF61A
+:10DD40009970939E5507CB6C1EEFDECEFEC7E8247C
+:10DD50005921A57E200DFD5E8F7A91C9A57A7C6F31
+:10DD6000912B5B06F8204AEB552FBE3DFBC4AB134D
+:10DD70002F60F4D16B2880626BF5139E582DEBFF5A
+:10DD8000A58BA5944712F03238E70B385F88E5166B
+:10DD9000219DF6D67A888EE77FE9A30892F1B13DFE
+:10DDA000BF5133D1CBFC59AE4138D87FCBADF363F3
+:10DDB000FFFDF3C0BA14D238265C4B2B1582A37733
+:10DDC0009694C271F6FFFE8F775FC4E07CA14A3261
+:10DDD0003C3AC11B02365E6FECFDC8887E8739BEB7
+:10DDE0000E1AE2D339BEB91EE1314078853F30BC0E
+:10DDF000B2F19235FD7D6B10CF4724630D1B2F6B65
+:10DE000076EB381CA7589609DE75B3BCB2C2E8079A
+:10DE10005E1B25233E8382CFB3DCDDDEF10CCECE4C
+:10DE200009323CC45EAD2B1D599EB53BE499AAC591
+:10DE300063126BAF27B54A6504BE48C5E4BA4CF21D
+:10DE4000EE7989EBC98EE402AD14A7B7DF6E07A2A5
+:10DE50005E8A5BF42AB3179F97D8FC5D114EC7D931
+:10DE6000B5716E27F68E22F91510EB9135654116C6
+:10DE700064B083879D071B2893DD9C2D73F8E030E9
+:10DE8000EF5F35FBCF19B9FFB5A2FF8F9B25E845A2
+:10DE9000F8D4B817D71F621544CF7E419FB03287A0
+:10DEA000CAA6DCF594C5BB8AD93A7AA232E83ACE42
+:10DEB0002F49EBBC81AD712103C55FCBBEB3AA1B5B
+:10DEC0003E53C82EC9964F24930C8E0D7B6F049D34
+:10DED000D9A9FE680AA83CF9062FE26703530A7C19
+:10DEE000FC1EC0F1038C6C51BE06987CD551BEEA75
+:10DEF0003D699995D53A3062EC534833243F2399D4
+:10DF00007DD192552A7BDFBE10887E01AD080B7E45
+:10DF1000DBA32FC71406576713905DD319A9A1F986
+:10DF2000B597D7788BD1DEA957E93D9C64F830EDE1
+:10DF300010260FFD6510C3F136E4432A88BC549BBC
+:10DF400047F4E8D6F8FCF52DA590BE807DCF9EB6AF
+:10DF500017C74FFE231813F89024D754932ED44498
+:10DF60005242FFAE5533D667A0BB2D90C892A7DAB8
+:10DF7000E894F4AE136F596EB80CF1DB59C1E8BFE9
+:10DF800078683F85C83F8CDE52C6822B4A328C535C
+:10DF90002CEB441F6659FFD84DF00F577FB01EB3CE
+:10DFA0003373B1EB98847881DA08CD2F0706FEC46D
+:10DFB000B09C2BE63B0A5AA85E7446F75EE4B38237
+:10DFC000584F35E2E23BA1AB5FA2758307358C4722
+:10DFD00030684B4FE50ECA895890CB89E3864CF2E6
+:10DFE0003124A7B518EB20E4EB8D92B2D681FC88E2
+:10DFF0002C6CC2005EDFD63D19FDCB3018127E0FAF
+:10E00000196AD22A7FB280956DF61F1C2A9D46A4FC
+:10E01000C5F902B4BDC8325A59CB39D8DF7D0C20BE
+:10E020001FF393378612A42F3EF285A7E0601FC925
+:10E03000F1AC346F5F8676F76D8ADF588FF46070CD
+:10E04000FDE065FFA0FCCB9AA1DAE47176CC5ECE50
+:10E0500075E88DB94A90E69B7D39087D10AB9F30FD
+:10E060006A103E065903D2CDE65A1570BC6090C3C3
+:10E0700065C299AB9C4CCB40701C4138187A088E15
+:10E08000701990BFC7E039E280E788039E23567875
+:10E090005ABD7CBE4EBF7FB12CFC7EE6F7A21E3C73
+:10E0A00001EFC4EA90606245A457C21AAF1BF4F6B0
+:10E0B0009251A58146EBEFF4FBD9FA1CB7E9871919
+:10E0C000A2AC33BBBE84E0B37F8742A2132A2B30BD
+:10E0D000E0BF2E9E61E247BFE6FF32BEBBF1A00B60
+:10E0E00090AF18FF2AF8DD25BEDE28FCD8C5A8FFB2
+:10E0F00099DEFE1AC4C308DFBB2093BDFC2EBC1CF6
+:10E10000BEC02217EF93DD428FB305B5F22F185131
+:10E11000F4ABD56067AF1226349874269DA2753390
+:10E1200080FCEE20A7B7247857917DD1C5F5A3E9EF
+:10E13000F77DBDDBAEAFBFB1C55EBE01168C42FA46
+:10E14000BAE1DB2E48B17E6FB4DA1F6C7DEE9035FC
+:10E1500082EF1BD0D2A905C9CE6AC2792CD6404520
+:10E160003F6DE9BFFC9F698BD87CB60A3DFA3693B8
+:10E17000EBBA456F2C89A4DCB1F2A1F35B2319F350
+:10E180002F92869FDF5A57EF7CB40F929B5CE4D7A7
+:10E1900081D35FDBAD90BF666947F05EDF659FDFCF
+:10E1A000E9E6EF9C2FF35868BE4B762C22BD39DC94
+:10E1B0007CDC3BA4582A837E7BCCD48742BE98F477
+:10E1C0006DF275B206B8BDF7FF7CA9356CBC57502F
+:10E1D0003ED2FAB79CCFE3282DD3F179BA76BFFBB4
+:10E1E0009CEDFEF039DBBD29E4B8B3DD526F9F1B17
+:10E1F000D773B99AAC93E4413BDAEB6A898D61A895
+:10E2000070EDA94EA32966A9D77586F50E4A256734
+:10E2100054AF4E1EA1BF63C2CE38B0EBFBEE3EE45E
+:10E22000BF9D6FCC47FDFECD2715F0B2791DDB15E4
+:10E230008234D2A79A72A3BDB284D1558ACAE96941
+:10E24000575AEC2A46B1D4FF371F0D917DB0E471C7
+:10E250004FAA9EB55FF2B3FF98020C0FC756F7FFA7
+:10E26000720CD2EB4E89FB7FC9BE2957B2F74B54D3
+:10E27000B82E9E814E6485F3CB3BFF1A6842BB4F9C
+:10E28000DAB1F7ABD46FCF352E94CB66BD4F6417A0
+:10E290008DCBEAC5F07BF287526A82C4E16B983C71
+:10E2A000D4EF7EE78712876F8F2BE543F8766C7784
+:10E2B0002758BDE53BDE23BA9DF3E88FC38887E589
+:10E2C0007B149BBFBB7C8792F64CA1E71BF844CD27
+:10E2D00028317E5B26F875D9EEA5A40796F56C78F3
+:10E2E0000FF975F91E974DAE33BC1869C4EBAB8AB4
+:10E2F000518FE59FFE735867A87A3BBA33AC9553AC
+:10E30000BF8BDC8CAEAE98616F87FD7F9C33B43FD2
+:10E31000807E8A6B2EEF59C7C703AE6F4C3E7D1BC4
+:10E32000FF923F546F4C52ECFB0E27E08569148737
+:10E33000DC919BD18F33F585C9AFDFFCF1896D4945
+:10E3400036EE3B8FFF795B92C17FD35FDFDF7627AD
+:10E350009B173CE3D3500E2DDFF94A182C78AF55AC
+:10E36000B81F76EC87FFFCC856C62FC75EF7905DD6
+:10E3700077ECE93F8ED5D9BC8F3DF6C928B43B5721
+:10E380003E7DE968A4AF954FCC190D23F80F48AF37
+:10E39000298F755D53B4AEFA1E098330004F89A7EB
+:10E3A000637D9EDDADA43174FBEE6B9E9487E167C7
+:10E3B000397BD75A89EBB594F41096EF62785EB644
+:10E3C0006BED7BCA944CF84E8E91A3F8646C13C528
+:10E3D000F5BEF28A8BABF0E93274A40FE827F9EFAF
+:10E3E0006CB7FC105BD7F3875FC71370D28DF85FF3
+:10E3F000BE6B1D1FD7B18EEFE25F2ECCA0FF87ACA6
+:10E40000E34DDFDB8A1F77E7D2BA0FB78E4B9FB899
+:10E410006A44FFCC9407A7C36FB3C4E13A5F89ADE8
+:10E420005090AF1EFFD1235B237C7DEB19428EFD04
+:10E43000F8C4580C2E1F75F57F15E564FFD31EED4B
+:10E4400021D666C9D3AF129F1D7BE225B74E72124B
+:10E450008212D37BC760E04F2FEAC165122F2C7F59
+:10E460003894F68407D76959AAA14E0FD3FB37E831
+:10E470007D8AD3FFB2D4DE4629C3BAED544AB85CD4
+:10E480004EE5115E96EABD6E2D685F4F6906AEE3FC
+:10E490001B7391EE865B4773FE1ACE7FBA653D1FF4
+:10E4A000E67C3B1C7F1EDBEE51A5ACC1F53D26ECA6
+:10E4B00083E529E955C8C0B700AB39BCC3EC3F9A26
+:10E4C0004F273D3CECA007B3BD39EFD3F1F5E9E7A9
+:10E4D0007376F8FAB6A2DBE8C6C4DB3B2733CBFB86
+:10E4E000B49013CB205957307EA8BE52219E1C53A6
+:10E4F0003C086F678F4272FC9D1D0AD9E94EB9B086
+:10E500006C187FFCD70AB73F96EDD93B05E5D73BA2
+:10E51000FBFE55D021A7F365BBDE702785FC4F5964
+:10E52000E53FF697613D5E13702F7F2A737FCB77AF
+:10E53000BD97B1BFB7D5D83508FFDBBD2E48B22E89
+:10E54000DEEE5132C637F6292E5B1CB73334EDB5FB
+:10E550002C8C6F86FD3ACE7BCDEAD8AB49B4435EB6
+:10E560007601D981AA71D4C3BEAF09F969DF7B4DA9
+:10E57000F806D02D7ABADD8127351A273F588DC489
+:10E58000AB78EC3565F3475D9A6C831BD46421C688
+:10E59000537E5DFC4715FB7D11EDBF7306EBBFA8F5
+:10E5A00042472EEBEFC59864AC820CF12947FFF18E
+:10E5B000590AE8563A8B95C9D6F86A78DFED149770
+:10E5C00068859634C689A0107A7E60E9F7C1360D59
+:10E5D000D26C7CA82B93ADF1554F4B4BCCC3E028AC
+:10E5E0005CA995A06936DCF8452DB23DAE2DC65F1D
+:10E5F00021E209B063E7CE9DACDF3AFC56827E0C87
+:10E600008F5731778AEC9839420EFE9BB083F749D9
+:10E61000F1FDE867C5F4CD2ACA39A974B38AF6C4F6
+:10E62000BC93DDEA620B3DCE2B5D5588F472F0336E
+:10E63000A529135D35AA9CAE5615AF2DC4F6077DEE
+:10E64000B7157227344AF32C10F3DC5FF48D601F8A
+:10E65000EB776FF137364E6470D54515C0784B5D5A
+:10E6600064D1C60A36FF82438AE163E582E6A49A52
+:10E67000983C749C6D28EF19FE1E423C32F81F6EC8
+:10E680008B52F991369D9E3BDACAE8B9B3CDA0EF23
+:10E69000BBDA6650B9A7AD8E9E8FB7C5E97DF80E7F
+:10E6A0007F02E977775B13BDFF595B829E352AE7CE
+:10E6B000B779021F9679D33E58637B7835C6514CA3
+:10E6C000FC39F15DCB282E87F60D241DF13D5AE56E
+:10E6D00072C589D7D6D620D9A5DB24B0E1739ACAF2
+:10E6E000EDC8B880E3696FE23215F7F9EB4ACBC9A0
+:10E6F000EE81B881727A9B14BFA782F1CB81A2E927
+:10E7000051ABDC0D051371D5422F63BB787C66BA23
+:10E71000CAE5531DACDA9FC5E08B9D041DE9CC9C76
+:10E72000E7BE6ABD10E5E2BE550C9E72FC2E439911
+:10E7300085CECCFE660AF82098594E0FD22DE7FF01
+:10E74000E8CCB2CD1827668EA7314127ABDBD66E59
+:10E75000B36AC6BD75A263934E18FF1C288A503752
+:10E76000DC5F6C2EE6DF7D9CCE5BFBDEA3F856748F
+:10E7700014D8E28D1DCD32F9395B0FF3B8F489E678
+:10E7800092CD1359FD6A8637F4DB73E69566252C26
+:10E7900074BD51D0D3566F3C4B1B417F758A7A664E
+:10E7A000F9902FF12D5C97EF8EFB493ED2F356572F
+:10E7B000EA5A948FAD873DFA6A36A593817812BFE5
+:10E7C000C70BD97B06D289BA951E9A5A90EF3FB4EF
+:10E7D000DEA56F3EC7C2E721C3CED7DB5A478E4BBB
+:10E7E0009B706F43B84788CB9A709BEB71A2AEB118
+:10E7F000FF1B30140FCE7E73E6358E38FE83C8774C
+:10E800001EC2C3362BBD15B668B4CF60B637E7EB72
+:10E810006CEF9CEF60BEC299EDCFF4B82017D7F330
+:10E82000B1BF8CFDE98B804B1E57508E5DA7267AB9
+:10E8300010EFD3A085CAA0F6E723BFFCD6CFF970AE
+:10E840006BE723F9C4476AAA18F5C2998ED701F17C
+:10E850007835EA2D4336ACF2DC7CFE4235E30469C0
+:10E860008A1FD116331B520EDC15CD84E781FE0BB7
+:10E87000D577ACFB491B01B89F9EF6D23E070644F4
+:10E8800034562E3E0895EB597F3B853CA956B95F1F
+:10E8900078C1417DBBC2E3474A43C88247114F3527
+:10E8A000E3581D701768ACA95BADD88BD54D3EBC45
+:10E8B000C29DF82DE2CB1DD569FFDD1549105F81A2
+:10E8C000887FCF1271FA4B95C301945FADD01B388E
+:10E8D0001FF9F99002E41727C6135F5E34CC3EE1BE
+:10E8E0002E619FEF10F2FA1141370FA3BC66CFEAF9
+:10E8F0009EDE34B2F4AC875373F0F99090DF292197
+:10E90000BFC355FEB4C4ECCEBBA71D4DB43038BA5E
+:10E910008F1E5770294D793153C067CA87993E0EB3
+:10E9200047B8BFF366B4BFB7A1FC473DE73A30FE36
+:10E930001E86AF8E84DBF0907C89D7B5E03C0A65FB
+:10E940009AC7CF0B6B641F2B3F658081FD3DD816A6
+:10E9500023389EF2F6BFFF22C6F767B98D247B1FCE
+:10E960003E79FF2DD86F58FDD13FE0135213F8FCCC
+:10E97000855C32F9ED59D70109F5F9D38540E38576
+:10E980004FEEB90DEDE7F0C9E76FC77697A4A03653
+:10E99000C0EA072B767FF97CD67FD6E532A0091A2C
+:10E9A000ECEE4F74B3FAA5AD2DD538B57F93D201F7
+:10E9B000FC9E9CA7921C1C0BB15518E7C8DB9890D5
+:10E9C000F07BE8418EB78BB6F4FEAA1A109FDA3EB0
+:10E9D0001C6FBCAB98CB5FF9B939B8F7E2297AD391
+:10E9E00087EBFAECD11580F2CAF3814CFBF14F7F33
+:10E9F000B002BE61CDAF38AA668C838D7779F8BE40
+:10EA0000D5070BBAA7E89CBC907F66FEA9D64B7CC5
+:10EA1000FE02D8F661CDFD2AB37D859418EFCAA316
+:10EA20007D09BE7F25DA5FA4A02DC78A7F96F97E77
+:10EA3000693C15B0C641827F92E399ECCC2A974A93
+:10EA4000F0B41BB5477FCDC653A75F4DFA17BAED9B
+:10EA50007038DB3138AA381C1C3E138E2246EF3E3C
+:10EA600036FE53C77F978FF07D5C67EA95DE00FA2C
+:10EA7000F97B4FC8C46F9BFA81F4CABEAA7D5EC4FD
+:10EA8000E3C6AA1A3FB773383DE6087A7CB88ED73A
+:10EA90003F51C5F7F5E1E429DAF77289EF3979FBDF
+:10EAA000BCB457918C05ABA7A17E32FF58F2081871
+:10EAB0006E8A93F63C02B935C7562E8202477E4ACB
+:10EAC000C9A05C453FBB2EF2FC38064A48EC3B57D8
+:10EAD0009BFBD8CA6103E7FF80A9FFDABCF4DCDE48
+:10EAE000F25000E31CBF30E9A4B9670ECE6FD64DDB
+:10EAF0003DCF86D97C2E3ECAF7CD9C792928F75088
+:10EB0000CE6ED4D2B9563D0AAA87E031F7372E3EF1
+:10EB10006ACF5399E5C84319928F75967EE572972F
+:10EB20003DBFF0046C9C4474D15B625B9FED173277
+:10EB300037E6FCA1FEE540BFC27F8228976F3942CD
+:10EB4000AEDC7D87D28CF651F8B2CA6CEB7E68BB26
+:10EB50008BEF9BEDFFBD0730FEBEB6D64B711B732E
+:10EB6000DFDC5CF70D986485F90DED3F0B205E9FAF
+:10EB70008C94F8F0F9ECCC9D245FCDFD7F8F98D379
+:10EB8000EA993BBFDC8C72294F269DD251B86F0C9D
+:10EB9000EE27DE5BEBA5FDFD70A0AFE759560E7EBC
+:10EBA000E436703FFBE9EA7493D55FFDB18BEBA5CA
+:10EBB000FB5DC2CEDA68DF6F66FC70BF8B7DF70449
+:10EBC000E3B45F297B459E84C3AF31F111DE972FFB
+:10EBD000174FE6CF92C983F6F883827EB60AFF66A6
+:10EBE000A3B0CB9DFD14376BFBDC68E7DFA4552A8F
+:10EBF00019F8735CABDD2E286AB1D3FF98663BFD34
+:10EC0000878C02871D9126BD65EADFB5BEE078B42A
+:10EC1000BF2A997EE4F680265BF7D79DFA77A71A7C
+:10EC2000FB99EB2CEC907020DE82F876DAB5FB04D1
+:10EC3000DEFFA2C4D288DF801ADF47FDAA719237B7
+:10EC40004E3B61089CC0E09C3C229CBF3A1B384F65
+:10EC5000B71FF0911CDFF22203797616883C8B10E7
+:10EC6000D91F1D21EE9F74B8B85FD02FE8E80D972B
+:10EC700042F33B26CAB303D092397F8CC7878EA359
+:10EC80002182F54667CED7450B85BE8FC9FCFDB8FE
+:10EC90008BEFABCD1E37F2381F88717EADC6FEBF3D
+:10ECA000CBB26FF3A42BF69EB5FCA18BEF830DAC1A
+:10ECB00087C8C735EDA53D6AEC235786BCB49C795F
+:10ECC0002AEDDF9E00BFA130FC3C930FBB81C991B0
+:10ECD000672481CFDFFB488F99F81EB0A7517EA033
+:10ECE0003E381C4861FCC45C0773DFC59C87693FE4
+:10ECF00094B9B93C6174E37313DC71BE3F08699247
+:10ED00000F05826EB6FA16DE53CB9E77CF7CFB35AD
+:10ED1000CC4F78F7099F8E706DAA3A12B6CA4D682B
+:10ED2000B6D38FF9DEF5F118DA97BF554A8C765BCA
+:10ED3000E328917E37B67F46D2C97F4BBEA290DDD5
+:10ED4000FB8C949A44FBE82AD0FEC533374653EB3C
+:10ED50002DFB1B4EBB3EC7D7F7C0729C7733B39FCA
+:10ED600060E8BA9976B959C63C106BFBF96CD9B911
+:10ED70005DCDA6CBF8BA42CCDB50630A100926E879
+:10ED8000391D747A32FBDF7033BC5D00FDF9C84772
+:10ED9000AB03632FE2F6C67F1BDE66E378FFDBF092
+:10EDA0003648B74E3DCDF719F2041E42D042FBED76
+:10EDB000BF685ABC6E021BCF5D18247B35AFA9FD1E
+:10EDC00066398CD97DBD1AFA977962FF1B1AB97E14
+:10EDD00036F7A373EAEDFADCA9BF3DC2EEF00CA34F
+:10EDE000D79D727338BDBEC46DD7EB03F1E261E409
+:10EDF0009F335E7C7AF9A7DF535B8C7919B1576B2F
+:10EE0000D9BAEC9BA5527C333C1EAE8B5BE8E1B0DB
+:10EE10005BA1FE0EBB791C643DE3D7D4399CCFE1E6
+:10EE20001CD4074C01E1FE41919CC2FC9AB5C95427
+:10EE30001DE69BAD552768D675AC2E62762DC3EBCB
+:10EE4000A61A7FB3D5DE7ED3EFE271D840F541E458
+:10EE5000C7F260AA86DCBB1873FC46F13C4B5CB77A
+:10EE6000F334E8C37D570F70BDCD38C2CBF54AAD42
+:10EE7000F616E56326E0546024BD60CFBFDCA9A68A
+:10EE800056FB111F111E6F096D91281947E989A5BD
+:10EE9000D17F981C58B095E4901A2FC371F64E6339
+:10EEA000662FABFFE15E37D9393DA1312ADA95CF24
+:10EEB000C88BBFE766F3ED7FDD03B87FD2F3D9B926
+:10EEC000748EA12774D15CA4831E099827CBE6CF4A
+:10EED000F88727FB4000E3F4E13931C03865FF2FA4
+:10EEE000C078888DEF8AFE344E79BA100BC833583B
+:10EEF0003B1F7461BE8AF1A9FFFD4B18DD3D1EACBE
+:10EF0000BCEF7C18F4FB4D7FFF627FE231E4C78EDB
+:10EF100051BF6B463EEB62702A6487C5A2087765D5
+:10EF20009E4CFC0779C1D404F6BEFA60A416F3CF58
+:10EF3000AAD50A94340C0EBEDE877C892771BEB533
+:10EF40005A436D36AB5F7548277B656EF4E6FD5816
+:10EF50009E7698973BDC40F620F22F58F8AFFAE304
+:10EF6000B134BF5F0A39DE1E8DF5C6A411D64353F6
+:10EF70001DE737EC792B563AD0A6D9E820E1B2D27A
+:10EF8000C10C460793AD741093CE860EBE8D5838D3
+:10EF9000237EE17C729BC2F96628DDB77873CA874D
+:10EFA000F28739EEFAAA9C08FA19261F68D3EFD225
+:10EFB000B0EC59E4267FCFE40B931F4E7AF9BE02E2
+:10EFC000E38B3A1F7B3606F54B33F105FA7356FA9D
+:10EFD000BF72183E990FFDFB31C77EBE0AC92C26B1
+:10EFE000427E7DE1D1D2B116BA77E269FE2C098E5C
+:10EFF00058E4D1A953BC6CC1A33690F7AC9C39BE80
+:10F000005F56F58E8885EF3A99FD8C4661976C4086
+:10F010005E31F2DD62BF07FDD5FAC7A214CFF7C497
+:10F020009B294F6DFA3B811B181D7E384AD671F221
+:10F030001DFAE247897F5F0B00DA6D9BA62D1987C9
+:10F04000FEC9873726C6A13FB68EE1FF081937A94A
+:10F05000D132E53EF58DE6FB637A943F1351FE1EF7
+:10F06000C4F79428C744BD3EAAC7D6D9260F377B1C
+:10F07000397D6FF6723B709DBBDB8BFCD55FECA5D9
+:10F08000FD53B3DE250AB7DB6678787D38B946C70D
+:10F0900078D50C0F6F775F5B2AFEE6048473073D1B
+:10F0A00073EB5380F17F7F5952C7F8BB7735243219
+:10F0B000D97DF779791CC0BBEF9F68DF28B7D4A052
+:10F0C0003856A49EF56759AFF90C35594C7E30700F
+:10F0D0006348C71DBA9FECB0F9919A3FA95386AE19
+:10F0E0002FFE39625927EF5F95440FC50BF87EC696
+:10F0F0004AE1CFD59678892F3A5ADDDB712A0B3C4D
+:10F10000D9DC0E8DD48C982F8B7E53D283712E2F09
+:10F110003D713F23790EDFCF487AF87E46D2C3F7A0
+:10F1200033F089FB19F81DF733B0FC93B6189571CD
+:10F130005F03CBB8AF8165DCCFC032EE67E0734FC1
+:10F140005B333D7FDED642DF9F6A6BA5F2251E6EE4
+:10F1500067435932BA80E1B9EB76770CF7A9D789C2
+:10F16000F5793656926BB075F445B8DFE97BE15E10
+:10F17000C0F9F8A23C6ED419BD17AE67CFAEA9A1F5
+:10F180002EDC2FF63E1AA4A74FBD0FF420EE4F241D
+:10F190009B3153B6C5F3C41C95E9F7D2E8CD353998
+:10F1A000AC7CABE7C93518BF9AA8AF32166B836544
+:10F1B0003D54B9E4314B795CF976D5CFEADFB9F645
+:10F1C000E935C8A708071A6F1D9EF49C556CC9D372
+:10F1D0002540E735FA8BDD29A4B3AFE17A21FD782C
+:10F1E000B85DFF655813453F799CEEAE44FE60F56F
+:10F1F000D39C2ECFACFE3ADC94CA1BDA6EA47A7292
+:10F20000D519D5036584FEF0BB34423F1DB046C31B
+:10F21000B3631B9097312EE80B909FD6E5E27CD923
+:10F22000E5E3CFA35E73FFA8669E978D3B4FF06921
+:10F23000972F5E87F9CAFD93658A17F4B858179817
+:10F2400084DB5AFC9B1236EEADCFAB8071E694871F
+:10F25000DB3713C685B8BEBCD34BFAF24BE37EDC7A
+:10F260009EC3CA13BE6F18A8FF3680E1473A496EA5
+:10F2700094693FF74755E3731A58F5F3A63E918317
+:10F280007184CF047FA7F07C112BAFEAB8611CC654
+:10F29000953E7C89CBA547C538DB5DBD2DB49E531B
+:10F2A0008364370074935DB02AAAD23EBC9CCF9F82
+:10F2B0006E97F67758CFCD146F92C1E3FE6CBA9774
+:10F2C000FCEF8F3DE25C5A2FD90B6E5F42CB66EFAD
+:10F2D000BB9332F1FB1ACD9FC2D4FB0DC14A3A2732
+:10F2E0009B2C5729CF7A43398FD3054257A7D04E4D
+:10F2F000B867AF8FCB87A097F2AD52E5BB0FD6446E
+:10F30000F0296BC8EFA9D8823AC2BB266B94B7C567
+:10F31000FE46DF9B239497BD01C4BA34F37866C7D9
+:10F32000A84F7F85F1DB355FD70C715688F21EC977
+:10F33000B491F1DC6EFFBE00C2F315F39C51DFEA1D
+:10F3400000ABDFBE5833701DA66835751827ECD0AA
+:10F350006ABCC85781C9B5DE45248706F292E93CEC
+:10F360005B7B39B757F13BF225B4C37E3CBF3246D5
+:10F37000C8B24076A584764E473D858D306FD796CE
+:10F3800067D99E7319E5B12BF37308CE0E8879B156
+:10F390007EB29EC79DC704BD69B4E3C698F1434CD5
+:10F3A00031B6F811B937D9F394F39B55DB398ED1C7
+:10F3B000097B394FF805798E7CE64F3DE63E8A1D84
+:10F3C0004FCEF9E6461ECA467873F160B23E743EEF
+:10F3D000F7452A1B709E63343FC11DD55657A3FCC9
+:10F3E0001A0D2DAB90EECE1A5E079C53CADB7B71D3
+:10F3F000DDA7E82A9D5B381FFA5763BF1B049D7782
+:10F4000015DBF564CAC3FD06C68F95C88F18E74A99
+:10F410005AC6C7386FD232DEF8AE1C5B79427781AC
+:10F42000ADFE395B4A6CDF27A5CEB57D3F6F47A5A2
+:10F43000AD3CB967A6ADFEF97B6A6CE58AF465B6AA
+:10F44000FA171C5C602B4FEDFD3B5BFDE9AF2DB661
+:10F450007DBFB06F89EDFB454757D8CA17F7DF610D
+:10F46000AB6FDACD4EBD58EEFD7CF6B207CF75D945
+:10F47000E282767BDC694F7BFFBA465F8D722DECB2
+:10F4800026FA56518FB3F28ADBB93FE39D6DE82827
+:10F49000574A841C0D056317E2BA5587BDA40FD4E3
+:10F4A00020AFA706E792DD31760B934717A015082A
+:10F4B00003DF032897DB92F152D720DC3EAD9BCED1
+:10F4C000285487EB00E3BD667B558B412284E3E93A
+:10F4D000DC9E61DE22D6F3E9ACBD651ECFC8321DCD
+:10F4E000E9EE677ED74316BF6B383FCBE9579DA93E
+:10F4F0001F3556063F3EB74BF1167C96B7BC54837A
+:10F50000E974CCBFFA0AE261933BDEBC1DF7434AC3
+:10F51000FCB42F66FA575DC53DC417FDC52AE9172F
+:10F5200050F5F20596F8569797CBFB80F701F2EF6E
+:10F53000D492190775C4FB2A95E20E1B241E1F499D
+:10F54000B27540BDB66DE6D1F7FE91BDF79678C7AE
+:10F5500078993C329E75C770BFF33E81D712ADA239
+:10F5600086595CCCBE68D887CF893AB333D8B3AC60
+:10F570006CF33E7CDEE1E5F974E71A8FD5A02CF13F
+:10F58000CEE6F69F32C59D5A8DEBA7713886A33320
+:10F5900035670BDFAF2A55DF427A436BFB943C485B
+:10F5A000073EA403899E443FBE4890F4860F0F7720
+:10F5B0006159955201F63D521A9330CFA23ABC855B
+:10F5C000F6557C69BBBDCAFCCD2EC46BA4DEBEDE85
+:10F5D00001EF3682AF5DE2F1D7AE6CFD851A067F92
+:10F5E000575E490EC64E303ED16091379B85FDD6A1
+:10F5F000E4934DFD4FF24646DE983A68EF30FADF6D
+:10F60000228F47F8BA01E596EFAE6E407AF7696C43
+:10F6100035D1DEFE5692E8DFB4776F11BC555BD270
+:10F6200044FB5EEF472AC9BEF5B5FE2423FE7C7D70
+:10F630000AC42E181EAFE1895B49DF43895B47BBD3
+:10F64000A25577C7B667900786D007EB30CF03E1A6
+:10F6500011791E5D021FE6BEDBFB66FE93D807BE76
+:10F66000251B6CFB7FB7E4558E1EC91EF731BF2FDB
+:10F670006181771D1B07F1D271B2A12E4EFB80C0B4
+:10F68000CFA57D56BE9DCEFF0AFFC510F6CB0C0F51
+:10F69000C7EF5837909F3007E31717A0B7F9E53A3F
+:10F6A000E44B33DE71C49B43F83792A0B490BDE2C3
+:10F6B00032F5967CEA7C8259779B714A3279B95E41
+:10F6C00063FFEEC57314E3BBECE7932674DBCBE773
+:10F6D0006CB19727A5EC6566351F42BBA001387E4B
+:10F6E000CEDB61FFDE60C6F96AF9B90A2F1BF91497
+:10F6F000D7BFB673AC20F4BF194F2DEA4957A37892
+:10F700002D5C69D7AB0542CF1738F4676548213FB8
+:10F71000BFFA60643FDA8F66FCE510267F59E2A9E4
+:10F72000661CC529CFFD873703FB42FE72C2C3E3C7
+:10F730000B09E6DFB4168AB845117FBA14FDC585FA
+:10F7400064A7B59C83F2E9696FE2032F192DF67364
+:10F750000FC7EBD45F483A1F276119E7B6B2E497A9
+:10F76000F8F453944762C6314C3FFD642036CFCB4A
+:10F77000D67D83F172CBB318477ADD03D8CFA5CA03
+:10F780000B07DB587945914A798FDAF49BBEE7C7BE
+:10F7900038207E67E5EA627D34D1FF732EF2D7D739
+:10F7A0000A7A36CFE398718F6C1FB79F433ED32EF2
+:10F7B0004AFA455EAB1FEDDCF37630D96CD3733C6F
+:10F7C0009E66C6CD26F7D8BFF78094ABB1F53BBF98
+:10F7D000292573BB2A16ACB6C4D5CF15EB356561A8
+:10F7E000FADE85ACBC0B5295783F4485A00B63BF15
+:10F7F000FDFCD72890E89CC0A8438A9162F5A73CFD
+:10F8000065FF5EEE381F76AEF3BC9823CE1B52E048
+:10F81000BD456CBC8D7A8B84F273E34266C3B3F250
+:10F82000B93E912F3C112622FD5DAA048D34E2F7EA
+:10F830001585F486E78D735E5D84FAFC259E97A29C
+:10F840008DD737D7B2B2F62B85F49316808A8AE02B
+:10F85000605CF8FE5306B4BB06E34C3BD9BA964E47
+:10F8600040FFDA0BA8577EC2D617CB3DCC1FC7F29C
+:10F87000E3CC1FC7E76EE68FE3FB9F317F1CCB7B9A
+:10F88000983F8ECF9F337F1CDF3FC5FC712C2F0F1D
+:10F89000545FE28C5359E3768371AA3EC98C53A11D
+:10F8A0002839EED6699D07E255091EAF3A7D3F31F2
+:10F8B000B31F8A070EE947C405DFBDFD778FE079E6
+:10F8C000E9A5535777E1B957AFCB8C8BF13C08339F
+:10F8D0008FD9E4BFA5BB6FA6FD6077FEA1165C8F34
+:10F8E000DD5541BA53C8ED4A68281F9DFE97E97758
+:10F8F00039ED5FF3E9D4477EB4032E403BA99BE288
+:10F900003EEB5D5046E76025BF817CE18C439A7CED
+:10F91000FCA2AF24E3F9A5817C58119FF140CA8B6A
+:10F92000F132B724E629F2354984B12E36203F5B07
+:10F93000F28B83E5698A73048331B2BF24669791A1
+:10F940009DA625A21887EA1C26FFF541C1A7ABF2A8
+:10F95000DD746F44673EDFFFAF2D34A2D87E4DFECD
+:10F96000B4A8351FD6CCD7DD1F9AE6EDB3F4B72285
+:10F970005432A29E52985ED547D0AB8A87E7ABAF90
+:10F98000D977A117F390D70717F7A27DB53E1AA133
+:10F99000F3EA7BF3A791FD31503F3A83F29595202E
+:10F9A000B75B95A897EC5615E75F3E58DFACD72AB2
+:10F9B000E433633F8ACF05823D54CFA3C629FEE1DD
+:10F9C0008900ED5779BC3C5F20C8FC6BAF2D6ECA37
+:10F9D000C7BDD9C7E5DB7A3D11C776EBA3AA8EE296
+:10F9E000687D5925E1798DC0F39A3C53EF1B646F14
+:10F9F000F4083968F6B346F8EB6B9ADD6477C55BBB
+:10FA0000B363B5B9947FF903E4BFF5C187BC98CF60
+:10FA1000EECEAF1AB1DF27C5FA0DDFEF1B35B517F4
+:10FA200050BF3D3E36BE3BB458C37E5DC3E4D91FD4
+:10FA300014707E5EFB92614EA3FD2E30F56D2A6A36
+:10FA4000DD27763EFD68275E30B4DD52BD6F2EE6C1
+:10FA5000F9AA90ACF32B43CF292CDBC3EF9DDAA49A
+:10FA6000F692BDB3E9A494F1BC43965F12CEFE803A
+:10FA70001F6EB357C6087E1A23BEEB68AF14A35F90
+:10FA800069B72F2E38682F4FEDB597A7BFE6B4574B
+:10FA900062AFA0BDD228E45D2F93CF3C69A25F4541
+:10FAA00039104FA6AA11EE06E85985FB942E11676E
+:10FAB0006E14FAEA0AA1CF5C7E1E971DD3ECB7F94B
+:10FAC00089E6FD1985A2FFA2DAFD37B7A3708D9BE9
+:10FAD000F68F4EFE65D1BCC7AB494C3AECA0869878
+:10FAE000FDFCE9150E3BC7690F55ABDB29BFB2C062
+:10FAF000117F30F729719E780ED739FED98E6BF6BB
+:10FB0000B795E92DB457CC7B09E8DE2ED6BE484D1B
+:10FB10004B06C353410B50BEDF989510DB9E818E80
+:10FB2000A789751F82B7E42584B739E25D4190DF6C
+:10FB30007B5250ABA4F462CCDFEF21FDBDE0263652
+:10FB40001FB2974FD13EB4593F27BB672FEE136EBC
+:10FB5000AD97B8FF9804B243CC75DE1AE4E7651A96
+:10FB60002E965232B66F29A1F109AE92C1F5657891
+:10FB70003AC2F1C4F3CBAEACB39FEB6970D81B268D
+:10FB80003D5CE178FFBA4F23FA30F9E0DD0B5F9B73
+:10FB90003896C1B1544AD6059433D79316FE709D5A
+:10FBA000423EC4BF8FA2A9107FECF3FE54A3FC8099
+:10FBB000ECBE078091E4657E48D6CE02F8377FFF21
+:10FBC00079122B37F8CB3BBA2EC6E389FD3F42A30F
+:10FBD000CCE3A9B8B4AE68B0ECF75F4CE588188701
+:10FBE000B91649BEDE967B0A18BCDF15F9011B6207
+:10FBF000B059C11C4B59DB6C140FB6CBC176D2087F
+:10FC0000EDE2B059CDD02E68B663E8EA34EFF528BE
+:10FC1000C127FF2E0B78ACE3AB88374D0FD2B99DCF
+:10FC2000B9AA86790F5F148E51A79B770236BBC69F
+:10FC30000F6DC7C05E65C22F67863F85DFADE3BB32
+:10FC40004680FF6F8D8FD3F5E716DFCF1A3E567DC6
+:10FC5000F5A8E1E78B70B9E87E0C3D285BFAB9673F
+:10FC6000EF2714BF56AF053A97A3BA629AC1E8BC12
+:10FC70005CFB36F9E16A76AD8676C03A56463B6063
+:10FC80005D4F37C5A9CB4BEFED42A22F4FFB01E5EE
+:10FC9000C164D0B277B17E276B2A66E2807AF17EAA
+:10FCA00019E3DE7039D0B990ACBD7E7E8F45F1CCC2
+:10FCB000EFA37F949DEDA53850207BDAF7B9B1CB47
+:10FCC000E3C126FC81EA43351827571BC040565430
+:10FCD000A5145423934D02DA87F0C776DF86E72B0D
+:10FCE00099E223FD44773BA05E1571F1D19C64A09D
+:10FCF000CBAD35A09F907C5EA5F8FB68BCF2861169
+:10FD0000657979CE6684A73CC13A90107E1ED79A59
+:10FD10009C908D34EBBFF23DDE0EFE9D9F0760BED2
+:10FD200044D313C141BC9A7265B488974717DAE38C
+:10FD3000C9D0CFE6CCDA57FEFB821F603C61D410FD
+:10FD4000F9CDFD6BF3DE9CACF720FE04ED6BDAF52C
+:10FD5000865FDC4FE177DC7B302E683F8737C46FEE
+:10FD6000F8569CF480070CAF9BEC8B85643798FEAB
+:10FD7000C856AC88F1FF22E079D9CEF6D3787B88DB
+:10FD800072FFC4E367665E25FBBEC41FA37C1F0F22
+:10FD90002B333C4A6EF0E6B3F705328F8BAC9240C2
+:10FDA000C5F2E07869DAA75F2B195D8634E8FFAE0B
+:10FDB000D10CCA1F809539367BD9CC435D7163F174
+:10FDC000E81CF6CC1A3CFFA3213DAEC82B25FB391D
+:10FDD0009CDBF7F7285F8FAF5F7FA917E529E62F38
+:10FDE000CC04F8ABBFA323C9E4ADE7E331A05BECDF
+:10FDF000328FDA427130CFC7636DEFD36DF6F38285
+:10FE0000B1A05C8BE3E461F23EC683416BC776D55B
+:10FE1000603F17E8F938DF66A70FF65F687B9F66DB
+:10FE2000F68CF53E8AE1FB0F805E66ED7FFC30FDCF
+:10FE30004F74F4AF65EC7FB0DF5C5BBF1D2A8F8F22
+:10FE400026237E5A77A73D3039505310C81B217E98
+:10FE50001FE0F1C7B5D1168ADFD700637846279730
+:10FE60009C3CA2F0F36B40761B14DAE3F735827EFC
+:10FE700065461148BF97A8F67BC06683F35E30BB2A
+:10FE80003DD48B8C827E65A8AA97E2F89F0475F416
+:10FE9000BF86B3977BDB80E2C7B3037DB7E03EF557
+:10FEA000A51B1E7075CC10F9AF05CC8ED8D0732968
+:10FEB0009EF3EB15E7F33A2232E1255E339ACEDB6F
+:10FEC00098FDC4DD3001E5615CE6F909F4878DDF5A
+:10FED0009B57F0D0FA0CF8739EE76C8849F1520BEF
+:10FEE000DDF4CA0CAFD6F1E68CD9AE58E611F7C0F6
+:10FEF000541A4FD8B903E38DFA7CE3BD24E24EE6F1
+:10FF0000780D73EDF36B706B34BF06C1BFE6782FCD
+:10FF1000E1FC32E0F7B4E3C99C6E06C6FB927D7E3D
+:10FF20000D1E8DE6D720EEF51D186FD4E71B6FADC3
+:10FF3000AB258176DB6689F3FFDD817FED40BFED88
+:10FF4000FDFA1551D207C22EBE021BB07A57A87C0B
+:10FF5000BCF985DED42ACB785B991C88893CF7985C
+:10FF600007F337342AA7DAA2F47C88D9D931CADF5B
+:10FF700028A3EF8FB41954DED136839E663F6533D4
+:10FF8000F83D3393664919EDED5F06B8DFB8395F88
+:10FF9000BBF66BA897AAFDFCFCE38C8B2066B17FB7
+:10FFA0009941BCCF87FB2F574305EAB6895B38DC04
+:10FFB00091DA51295C3F7FC5FEDE3656F6B85C3AD1
+:10FFC000EA53C60BF14C7EEADE00F7C33D6E2EEF1E
+:10FFD0006126BFB770BED02BA0D44B2EC4C715D995
+:10FFE000B4DFBFA03116D218DE1A25E99552A1A7B9
+:10FFF000F0FCCA5562A99C767E043506EB37125395
+:020000021000EC
+:1000000052781FD15585079B502FC74357927F10B9
+:10001000670D73583F57093D59FD860730DF012EA4
+:1000200075131C8D8D767B7EB32FADA17DB2B92269
+:1000300002B83E0BEAEDDF3D6ECE8771C73D05F39A
+:100040004F736F01DD9D95218FD4199F7C32608F96
+:10005000439E80F27B6AF1636164C47B0B5604C0EB
+:10006000BCD73263FCC884E74D94635391DEF650ED
+:100070003CCC84AF404D4928AFC734EFB1E53531B2
+:10008000C492316CC6E141D955817E88733E5BA52F
+:100090005DF923DD535200EA5B7D65E21E4F69E89E
+:1000A000BC7F1710F9B703F39EF5622964E21F1EA7
+:1000B000779D7F503156E9837831F1F03FCD479DF0
+:1000C000018ECF17E77C50C5FDB742DB7D99E63D39
+:1000D000C0570E9455502DF47CC51237D93310EB10
+:1000E0002F47BA3B747180DFDB66DA2FE9D765B43E
+:1000F0005FBE78FFB1225BDEA6E877B8F572E61145
+:100100005ACE7D0EE6B9637E89C4F7B10A30CF2D91
+:10011000CCDF1FB1DB99B63CB7357B7F28619CEF04
+:1001200001CCC7B3EC5B8F61FE3CCACDC29BEC79BE
+:10013000754EB8CCBCAA8173B3B31AB55D3ADD93E2
+:10014000D88D17CF746D49C6C1921F699E1334FDB7
+:1001500069E7F94025C8EFCB8B8AF316CE78F06DAE
+:1001600072522B96301F35E5AD66CFF29C848147E5
+:10017000D36F539275F85E193DB319F1B0B0F54ED7
+:1001800003E3775A6EE6B8F442A1BF2F0A72BA3978
+:10019000EC4A17611C3B91537351302F43FDD66FCE
+:1001A000517FB387B97FBE51F4F380D0E7CEEF978C
+:1001B00007795CE59AA532DD67E183504A2AC67D5E
+:1001C000E3EE19742E6FD95623D3B9B783E144BD3A
+:1001D000151E5F293F6F0DD07321E26BDD5F1EECB2
+:1001E0007994A132E72F4192A3390AEFD7D2BE31D9
+:1001F00053FB673EF92D9D537E06CFA9CCC4FEB6B6
+:10020000CEC5F8F7A6813224252C678B72F2B6B9D9
+:10021000E8EF0D962BE6566319699011D9ABC1DA58
+:100220004EA4974D120862BC94D777F1FABBC5F77C
+:10023000D997BDF37D3C970BD3DCE4076E12F688AB
+:1002400009DFEB419E37F3FA69F079ABF81E447C85
+:1002500046CE0A9FB766C2C7EB39B1DB8253B19F66
+:100260001EBA17D2F717EF4ACC23FEA73630BEC608
+:10027000E6F080B1FB87F700B5FF5670EAD0F6F3E1
+:1002800072626DD86F70E9119A5FA83488EE0DAC78
+:100290009B0ED44F0638D666EAC75CD774169763B0
+:1002A00027D076CEC375E5F69FE2E98DE2FEBF5614
+:1002B00075FF2D1A93239DC5DD4D99E8FB3B21BEAB
+:1002C0004F9D3D4CBC7A97A0C757B5F877118E76F5
+:1002D000ED5EBA4FD52D71BB61DD8C3E902CED7E6D
+:1002E00015E2F519DCDFC3FAEE0BF93DA72186779D
+:1002F0004C300B5571F8D7E98700F3BA43D14394DA
+:10030000171AAAEA237EA7A30A059CAED05FF30AB8
+:10031000FB6C57F0DAB94817398A49777FEE443ACF
+:100320005406CB4497DB7378FB97427FEE4C3291B7
+:10033000BB8DD92F78EF46B280E78D38E7F72F21B4
+:100340004E1FF787638F23BC43F0E9E9FBFE3DAC0A
+:10035000FDA609FCBCCD6CB9B7E97AA4CBCB82640D
+:100360007FB1F74DD673C86F0A7CBD19E4F6D3A6EA
+:100370004FBCF4DDB91EC3D1EB0BA2FDE7A0D7172C
+:1003800032D109A3D77F477AB3D0EB0790995E0F9C
+:100390000D43AFAF607B275E9C6505625B707F5647
+:1003A000FD74EE0EEC4FFDF2AC2D8FB2A7F2E95DBD
+:1003B000495A4D43B29D2F35C7A99012FF11B4C8B9
+:1003C00077F33EEE1B83BCFF21FD4E9FB605E5D8BB
+:1003D00019F47B2C387568BF4F0539BCB32F0B2639
+:1003E000329D1FDF1252E9FB43213EFE707C7330C9
+:1003F000C4FDD9E1F8E65141578C6FFE7A267CF3B3
+:100400008741BE7187F2CE846FBE4D4F5F29E71BD7
+:100410003A863C7328DF40F2D54E94AF9DC59C2FA1
+:10042000466F7AB313E31C037C943C41DF95C132E1
+:10043000C963938FFE73D309E22367FBF030F75251
+:100440008D15F33E188E17E13C62E769EDFC9C4D7B
+:100450001FE9EDEDD0BFD74379B63CAFD59F4CC671
+:10046000B8D9D00B78BE7FA2C0C336F4C1D0CF9923
+:1004700026E24C6A2F2C080DE5E75055BACA7A9F40
+:10048000C0D362FC0F43F1C9A1A9385EDF24B4BF19
+:10049000865BA74A31DE3DD9B1CA5006FE3F9D1E9C
+:1004A000BA26C4CFBB5E23FAC9F98BB705ED4F2737
+:1004B000BFCF5EF6F33F3D32423F8DA27D7DE873B4
+:1004C000F37F7D2833FF5F1EB2F37F15DEB799817E
+:1004D000FF1B33B567FC7F55E86FCBEF8B4219F8F4
+:1004E00072E619E2FB6181EF87BF20BE570B3AB974
+:1004F000E3F3E3FB8E61F07DE719E27B7528837DF2
+:10050000C1F0BD2644F6CAE3047F480F521CBB6B02
+:100510003AEC964A32C2B1C1DA8F57E7FD30BC7F60
+:100520002031BA9FFD699791E99E19D6EE5E2BFCAA
+:1005300066BBCA9066266FDF8CFEF9035F0E52BC65
+:100540009FE9C7FBFFC674F050263A982D7339F423
+:1005500041F0B14E8CB37D81FE7F92A9FF6621D719
+:100560004F6717EC1574C1E6FD4468EA50F9B75DB2
+:10057000FC2ECAFDE1C45321C257DF3C9457DBEE89
+:10058000C891301E55184B4BE8273C2EF4D87921E2
+:100590009D9F6710EDB6A96909F359B6B568129E1B
+:1005A00037B2F4F74B1C6FB8FE9C7030F89EC3F165
+:1005B0003F0CC59EC767A598DFD9DA490DD9B19719
+:1005C00043A47FE287486E9F6397DBE63CE478377D
+:1005D000E5BDF86664FEDD96C783AAD063F1DF5BF4
+:1005E000E5FF2B0374C5FB3B5BFDC3E07B2BC4F530
+:1005F000CAD14CF039F1723A38F34203701EC77E0B
+:100600009D7ACAD99FE9B79AEBE4469D648DEB0CBD
+:10061000E8BDC45F897F3B643A87345FC893F93390
+:10062000B285DDAEF9B1FF07449CFC819BEEADC6FF
+:10063000FDEEED77691588828266AEF7F49BC652AF
+:10064000FCD317966C714CF339D0DEDD3309EF190A
+:1006500067E386C2ACDE25B3208D7E6316DA0D1407
+:100660008FD0E877BB723CDD518C9FAE93BA9B165E
+:10067000A35E9D17E4E74AA28DA7B9AF6DB58D6E55
+:10068000215A759AFAABA8BE16E8A6FB2FCEB8BEC3
+:10069000A7BB29537EC994B06CE275527824BC463E
+:1006A0002314D732F13B741CBE7ED5F11609F11D1F
+:1006B000AA92343C7A15627482F6925CDA4BF94C59
+:1006C0009757717A01E6978C7C7F46A769AFCD0A70
+:1006D000E77D71B8CC7AC38F27EA39CE2BE0BE17FD
+:1006E000C567835C8E5145563E7E303763DCDF7CC8
+:1006F000AE6DD30A5597B5FF14E179ED40FEB41104
+:10070000457BAB15383D42D44B7618DDCB6E59CFC7
+:1007100084589FEF66C5FF3E4CF019740F2168DACC
+:1007200019CD87B55B4CED54D62E74E6ED867F9AD5
+:10073000BF5767E871CBBD6726BF8E4E2401EF9986
+:10074000F1978326B1F58F84CC7D424E07DF0E9A58
+:10075000E5246D92C74BBB795EBE6ED209972B5ACA
+:10076000A0272657006CBEBBEE4BD149ACBFD2448C
+:1007700014AFD067E5032AF9E1BC0CC9BA03FB0B3F
+:10078000917FB4732583E9A9F6DA03072F067E5417
+:100790008A7E4FADF600C93BB38C175294B1B27F3D
+:1007A000A01CF34659B964A09CC4F236A12737DFD8
+:1007B0005D7BA03D48726CA3953FAA051DFEADE987
+:1007C0006FBBDEAEE13983645425BB6A9D831EF6A0
+:1007D00084F97D2C93B5C4365CD7F977F5AB787482
+:1007E000C55B1C09213F8C8B7E90C4FBF2C6CD12E9
+:1007F00069AAA5FC9E86EDD195C497DB715D80A7A3
+:1008000025607C72707D5299D7A72C45EBE3D7F910
+:100810007719CBE46FF3F85BA08CF3B3E6E1F1BD9D
+:10082000C704BDA6C33C7E9416F2352BDA4EFE9467
+:10083000B74EA6F871569D6CD31BF48B77D44EB58A
+:10084000DDFBFF7A4EE2A9B0452FB01AF132360F28
+:10085000FFA4480EEEBF5497A92BD1DFFE9EB0FF38
+:10086000D83A3D40EB5411F127486EC79FB5CA8F67
+:100870008175137839DDBAFDB62D61D4BA865FB7BC
+:10088000ABAF5532DE93F6DB30F75F8F35FDE7FD1A
+:10089000389DA5DE7EBABFBBAB7415C561CDB8ABC4
+:1008A0006777757A8C3E980FB83A109E854FE7B8F7
+:1008B000BF3DF95D8DCE897CE2C9B89F7452E0F9E5
+:1008C000505B13B5630B4CBFB7721D4E85E7B1D9B2
+:1008D000CEF199E711BE0A9C181AE38B2E4739B462
+:1008E000B849A17B1BAE037B3EC557CDBCAF563389
+:1008F0003F8EE77D25207B2EB2E1A2A4E3F722C044
+:10090000988BE7E887FC8E84D8DFFABA236FE29AE7
+:10091000A64546ADA8F73EFD3F45F369D4B9FC6D49
+:1009200034F8FD3D57C5AF356A2DFBD1AF7EA664C7
+:10093000CC9B9C9765E2236ED44E188A8FC571C9F3
+:10094000ADE9A7C7CB99E261915A31374F1F8A07AA
+:10095000E7FC19C636219EBFCEF08C76E770F860B2
+:10096000F5683D5EBD56A1DF8F99ABD4BB701FE427
+:10097000FA0689F698187EC3222FAEFE520BBC4EA3
+:100980003C3AF175FDD340E706AEFF4E88E26D2F8D
+:100990009BF8495F42FB17E6FE89659E4778FE9605
+:1009A00046F35C30A3E217786F42A25DA2FB1AD92E
+:1009B0007C6DFB808B219E85E716D8BC8F0CB3EE37
+:1009C000B6FD40277C4EF87D42AF38F7C5404D97C5
+:1009D000A31E9C9D25F605A78021F6C7B2281DB74A
+:1009E00034B3BC75DE3767D2D975AD0D03E362FF52
+:1009F000122406CA1A9ED77A4ED97415FBFB8A2890
+:100A0000FF1DC3F8B5B91DF86D3E98BF2F14A3FDA7
+:100A1000A6EB04FE1A98C787BF7D7609134EB8AFC0
+:100A2000373FE6D38396791EEF96EAC439AAACC65F
+:100A3000C9D82EB957993214DE1551FE7B858C0E1C
+:100A40003FB0D2A16F02BF47D68917135F8B06F163
+:100A500032E56CF0F22A2ACE3CDAAF213BB75FF2E6
+:100A6000D27978731F87FD35E966A2F3D6AC62614F
+:100A70000FF0799BF77701B4907DBF509CC73AEC9B
+:100A800082A6C7827C5FA7D222B76ECBA9BE35CB28
+:100A9000E2579BFB3AE67D51263D7FD51B4C2B9CB4
+:100AA0000E6DF7410DE63125288F49C9BA49477CBB
+:100AB00074E1A70BC9EE5985FD2B01BE5FE57BEE06
+:100AC000A75D57E983EBB7FE6B4F744F6565FFD7A2
+:100AD0007F93A44EF51CC25B48AC5BB55837133E00
+:100AE0007F397F6F593F1E3F2B13F133B18EC3E91E
+:100AF00009731DCD75433B0AE9D757A67E9AE9775E
+:100B0000F7607F553FF26922AA520E5D427AB383A5
+:100B1000EED9027D1BEEBF5FD7EAB2FDDE5202CFF7
+:100B2000E963FD753EE19718D47E713E6F0F65DC79
+:100B30006E1CA0FB246B6FC903026F7814AE5B1FA1
+:100B40006B8B7962ACBF51A8EFA1CB324EC9D0718B
+:100B500087EDCFD14E19D837310CC322AF1FCBE26E
+:100B60007AF278B4AA47CE107F319F8BBDB985AA9F
+:100B7000253FEC48BEB729E3EF0689FE06EE8D1B44
+:100B8000B013DF39B07FD6A09DB8C1F5C703078B7E
+:100B90002C7622FCF100F9ED03E5B3B3135FCFFA35
+:100BA00023D9891FFDDE43FAEA789D9FD621B775C8
+:100BB0000EFC079EB755F1B7FCC8BEA77B6FBCAD56
+:100BC00063683E92CA3087BF07A61B12E2FB4896B5
+:100BD000CEF7637548871870B9AA2121BEEE15FEBD
+:100BE00028A3B349D6DFFF3D22E66B8EE3F1421224
+:100BF000CF199BFD323A584579A5F5407AC4DC8778
+:100C000035F9D9ECE7589664CBAB3E03FE3D9635FB
+:100C10007528FFBE20B7FCE11FD17E7D5EA17CD090
+:100C2000AF446FA7F757B75E4FCF6B5B6FA4E7C7B3
+:100C3000423FDF2A253E463EED6DFACD576E63F406
+:100C4000BA7CB787CE952DBDF54F77237F7A5BD9D8
+:100C5000BA63BBAF5FFF9DA9ECBB7B824CF66B57C1
+:100C600011CFE770AF9278BC5F77D7ED66CFE670B3
+:100C7000F544CD02D77F01C39B58310080000000AE
+:100C80001F8B080000000000000BE57D0B7814D5D9
+:100C9000F5F89D9DD94792DDCDEEE6B5900713C2DC
+:100CA000230AC44D202128D60D011A2B81A0A8515A
+:100CB000826C0884008104B4B2552C1B021830D613
+:100CC00068B562B57C8B85D6B6DA06A52D6D23DDB9
+:100CD000085AA81463B50A562020B5286A228FB294
+:100CE000B6B6FEEF39F74E7666B21B82EDEFFBF734
+:100CF000F7FDE2D71EEEDC3BF771DEF7DC7367EB46
+:100D0000EC5347390A09216EBB811411B2CA42FF64
+:100D10002D1372F1E8FDEE05C984C45BAD1EFA84A3
+:100D2000989AB21F32D0323920921D148809647EFD
+:100D3000C5580ACD0CBA1D122185000D081D00539F
+:100D400008B184054292A09DC7D368A56529401CBF
+:100D500000C3123E370942453B7DFF0BF8BB2E0214
+:100D600095FE2C619190F1309EFE7D133EDF249B19
+:100D7000CAE07D3189CD43793F9BBF9FCDE76309B1
+:100D800027B07924E9FBB1B3E722696CB7F69FC7B6
+:100D90007D89A5231D741D7576EF288084741B2B17
+:100DA0006C84DC61FDFD61218F428B35245248FC4F
+:100DB000C68FBA7309FE7D311CFEBFCAF1FE184210
+:100DC00004D22D7C41879EF9B9101A46F11757229B
+:100DD00006D765532838CA274CA0CD4A8C1EC06759
+:100DE000D78864DB70D5F8C50E01F1F7BAE4B0C15D
+:100DF0003C2BA68915C1B1D87DCA1CE8675A4DD1D4
+:100E000066369C85A412329FFD9BBC2E6F6F194ED7
+:100E1000EB0301A36724A5E37C4B2008F39B4FA4BD
+:100E200040B7059B085F080865A988BF47E73B7F77
+:100E3000AAE88DB36BDA912FE83CC97AB26F04ED62
+:100E4000FF0E810F10A065FADE315E3C3EF5DCCD71
+:100E5000B08C6EE2300DA7EDEFE8AE9E41F2B0CA65
+:100E60000AFCB488B79BEF379EEAEB97FEAF3AA037
+:100E70002D2F28CE7F859281E225583601F8EC0A85
+:100E800003F2594D8BB6DDA277AFFF80D8A15FE9A1
+:100E9000541FBE619EE461C66FD39A1D32C5D3381C
+:100EA000878C749F39F5BDA9849667117233F43B22
+:100EB0006BAAE808D1D6AD7E03F1D2891FF28A4130
+:100EC00081AEED506EF781EB006FC5467907AC350A
+:100ED000973C785332D48F77009E2BE0D9106C4F1B
+:100EE00008B4735B8223E9B32EEF7BD61A15DF1D9E
+:100EF0002A7EEF0A1FA5D75603A98BC64F8434E17B
+:100F0000BCF6DD138FFD1C7F54089AE9FCA7899F6E
+:100F1000FF61229D4FCD7D468F59C6651980AE3346
+:100F20003C4C1E09F15AA7517CDE4158F93D525103
+:100F300014A2E3D7E41F2D31D37E6A360828A70A0E
+:100F4000FE29BE4FAAF1E66BAC480CC98877CD7379
+:100F5000DA9909F899E2F9640C3C9F54E3D9FFEE61
+:100F60009171FB54ED363B6CC9C0E7A480147C4101
+:100F70005173814C4E1C4FFAAF5B8117D71E1EB7C1
+:100F80006F24218F12EFC3A87748B754318ED2490E
+:100F900022DE687A60BA9DC9C134F123A4CFD96238
+:100FA00051067C1DF27F68A51C460E7D2E96019E83
+:100FB0008997369A1479EF870E13E279AB89780115
+:100FC000CF5B875A824DB4ABCE7BAE4CEB46FAC8B2
+:100FD0008F4F063AFEDE4876C8B1E76BF38B6404A8
+:100FE00065CC72BF8050A1DF307F1C91C647DA0DFF
+:100FF00023D1E7BF1BE498B64F59430C321DD719D4
+:1010000020DE6014BE50DA2DB7F44E9708B60F39C3
+:10101000E9FC56C886A040D79B2FC88CBF8D8DDEBB
+:1010200074DA54EA981D4827300F11E721D3F949A3
+:10103000747ED9FE042C0FF72721CCF13B118EF0E2
+:10104000A763FD487F0EC251FE6C7C3EDA3F06CBA3
+:10105000B9FEF108AFF0E723BCD27F0DC231FE52DA
+:101060006C37D65F82709CFF067C9EE7BF09E15516
+:10107000FED9083DFEB9589FEFAF4158E0AFC6E733
+:10108000E3FDCBB03CC17F27960BFD2B1116F9EF8A
+:101090004538D1DF8CB0D8DF84ED26F91FC0F2D5FA
+:1010A000FE6F23BCC6FF30C2C9FE27B11E1410E07C
+:1010B000219ECBE303F242079514E07019F83896AD
+:1010C000DC5DE4F668BEC37B1CF84E696732109F96
+:1010D000BABDD2EE1CB71B4EA06B94FE3EE1F4FAF3
+:1010E000C473F23BA349846E2DEEA60A2246E8653E
+:1010F000DE55124AA7FF5CB17B3601BD40729335C5
+:101100007CDA5F3FB0F51DE3FA6BABD4E515817F68
+:101110001B8927401F954F785D807EB6C952593094
+:101120000ABF8D761AF1BD710EDFBFC05E25649FC8
+:10113000DA07FA6456C0F18729C02F63937F3F8591
+:10114000F6376CBD0146A0AAC4D13985EA1D792ABB
+:1011500041BDB88D1094A76DF15A7B3ACCC9F041CE
+:1011600048FBFEE1284F230A98FDE9BE1EE4CB743C
+:10117000CF70B2391BE42D2448B4BFC02A42762870
+:101180003603DA6F5CF003A88FF467C2750E6B212B
+:101190002F59E844B2DBE4297114E66CF1BE144720
+:1011A0005F1919F44D89A7E5D1CF045E0278457B1C
+:1011B000704A02856376875EA2E6948C0B754FB108
+:1011C000D2F255FBC95E406B7E975C6AA3E5F1875E
+:1011D000BD7B291B90C26E5FA95D86F9049BED74EF
+:1011E0003E5B8F114F132D177FD426261215FD4D10
+:1011F000C4B7534517DB84AEA949F49F197739F278
+:1012000045785FEA8E738EED4F9F6DB06E5827B5AF
+:10121000233BE8BA32BC21C1A1E2931B9C4C6F5125
+:101220003A5CE5043BB4A65782756E5BEFB221FDD4
+:10123000E21D253064EF34E2785A063E96104FA640
+:101240000DC351DE15BEA3F8BD62B64D8D3741D139
+:101250006B75ED6363E3F70627D37FFF2DF87DC73A
+:10126000C1E421167E2DC02B932E2DC755CE3E39BD
+:10127000AE74A6C46ED7C4F1AFC7F33603D94F6DB1
+:10128000151D97F229932B12A04DD770FEBE145E48
+:10129000EFFE2FE3DB9B9C03E395C8C9A82729BF7A
+:1012A0005E417262EB1BE82F9AFD7A80E351A5E75D
+:1012B0004CE02FB638A89ECB89ADE76E755E427FB5
+:1012C000713D63E27A5C196F0BE7EFFDF68AEF8000
+:1012D000DC58371802206725C4867241DCC99C4F50
+:1012E0001CF1C02733444709E81B329AA01F9D30E8
+:1012F0003618807DCAB0805C20423350CA80C7A1B6
+:10130000B9C1CDB4EB6CEA674894FEB4AB10408B26
+:10131000EC302CA0EB4E54E4CD51ED56CB9B62EF5C
+:1013200023F2A8F0856BDBE66CC6AFB3A9FFF236FB
+:10133000C753A41F01DB6DFCC6D06D9B557A709B13
+:10134000DB8D65A57D2CFEBDA0F0EFFA75C407F21C
+:101350003139BADFF0BA53E47CDBEB053E0F7C8514
+:1013600038C09F71AE3F89FAC949F59380FA898DDB
+:101370009FE18FFF418096BB9CA95C9F3BE26FB1D0
+:10138000FDFFE3E71D4EC2F4D46447A748EB875145
+:101390003B24839C4EA6739F00F83221DD65C2E892
+:1013A000284F2641F07B29DE4206D0BF065B10ECB9
+:1013B0008CC9D4E60579262627AE7FBFDD77DC39D8
+:1013C000805C3812E47C206AAF335C66A5FCB731E0
+:1013D000DB110FE58F69B9D54DC77575135E6EB119
+:1013E000A2FCD0BFA148C510DD1B807D54CA5E0B96
+:1013F000B41FDE570E40792BF82457D3FE1FFEDBB7
+:10140000FEF51431B39DDE4F9C8CAF7B017A47D340
+:101410000D6A4E849F2FE50F28F219912747BE22AF
+:101420004FD563511FFEDD5918E92F967FB38BEB23
+:10143000CF04D7C0FE8DC2F797EDDFF0F97EC6F579
+:10144000522CF98F3BF0C696EDB4BCCA2DCAA7A8A2
+:101450007F671BFA569744CB16EA6FBE47CB064B05
+:101460009704EDCAA9845A29BEBDD4C983FD8765F6
+:10147000022BC31FEC3FCEB609654C5FCB8973C608
+:101480000D84C720AE6795DB84E3C58D1C9108727F
+:1014900065E77C4524210876DC5EEC9016607FDDF4
+:1014A000E446DA5FAECBA0916BD05BCF8F05BDE495
+:1014B0009260BF6EB69080CD15E91FCA890511FDF7
+:1014C00044F83EEE4EBE676A5BE7491C01727A88BB
+:1014D000C551DABEC9E4B23C8304D7819EF012D96B
+:1014E00041DBC711E58F0A2E2D1B7969C6DF05E2A6
+:1014F000A5F33FF87711A13082846C74BF57EE11C9
+:1015000042B00F34192C41B0A525432DC40465BB4E
+:10151000216806F93829E03A4D050941507E538784
+:10152000162776D3759C3BB8D7EA8B42FF5B7DD5F7
+:101530009EA9E363E3B1AFDDBC971D80C727E5F546
+:101540000EF023036E09E30E9BA0A94AAFDFEA3237
+:1015500029FED06C17F8430B7BD79B80DED9C9E8F6
+:101560000F91112EE4DB21EE5D9B4AC064D533FF61
+:1015700074280936A9FD2A85BF8EB87C73A19F27E0
+:10158000B91DA162D9350AE2555724BBC02F2D6978
+:1015900018DA01FEEE136B8967A111F5C14C68EFF3
+:1015A0004D6ACF07FE7DD2B3EB470F013ECD745F8E
+:1015B0000C7A7CFC51AB4CE95555B83705D6F3078E
+:1015C000DDFCFBFC0FFF37112FFA7DF03217DD0732
+:1015D0008342CC2379B00F3EE7B9293184BC9514FE
+:1015E00055BEABFCF7623FCA7EF85D6328D3115548
+:1015F0000EB5F856C6AF12D8BE961805A6FFB81D90
+:10160000A5FAE53E58277D0DEDA6D72C3C0DF6E654
+:101610009C67BC07EC762C7DA3CC87E27164852D9A
+:101620004ABD402AA2E989C75DCC5E5719E97E818F
+:10163000D60B2B0B1B615E5536AB007CA7B46BE65B
+:10164000ED147E56E25562E2E785407F880F465BE7
+:10165000FF7C229D57C7A39A41D65218BE3C51FC2D
+:101660009558F83A6C6C2B87791D5E249226DACF58
+:1016700039DFC43412E57D05BE037C43E9B21CF6B4
+:10168000FC852A7A8E888EBFC36BEB3C538D117A12
+:10169000F6ABAF8EAB04FB5D0978548DBB9FE3E5E1
+:1016A000848BD97B62F6C90E5A6F5AF098838C03EB
+:1016B0003D75BE306083B858EFCF9B80DEF7D930E0
+:1016C0005E51597DA1B0699C0A9FC5048DE4FCBDA3
+:1016D0004F3864FABC72E4FA948035361E4FB8D89D
+:1016E000BA1E800793301EB3D77519F11832D6850C
+:1016F000FC46F6C67942108FFC93E801BF01C6F59F
+:10170000A1FE64F1E4BB1C6C5E713A3FAFD2BF42F4
+:10171000A35F12C2020926A9CA523BC66713C212AE
+:101720003ED7CBDB0E178F3B717953F01F8B9E0A90
+:10173000FEF5CF431CEF87AB97C8103734C547F78A
+:1017400083D392040D5FBDB5D6A719EFED7F8A9ABA
+:10175000FDB202CF73FA9EF34D4A837855A5293026
+:10176000723072AEE0E7ADCF1F7740BF719F99A393
+:10177000CADFC7DC3E517BDA72B3ACB2A7B789EBE4
+:1017800001EF0912D76F3AB9F3825DA5F8BC0EECF0
+:101790002A9D62C225ECEA7C12E88438B27E7CC5C0
+:1017A0009EEAF94BB1AF7ABA297CE04CD2EA4B25DC
+:1017B0006E184BBE14B93AC2E55F8F7F3DBCD5A40D
+:1017C000F57B14F87E1F3DE24880EAC73B4BC420FE
+:1017D00011903FD03E1E7E4C407F33546D46BB5C23
+:1017E000531D87F1D99A7C11EB6B1E14D17E86A80C
+:1017F0007EA8A7F3F903D713FAF86C09113C5355E7
+:10180000EB9E39214E53BE6DD1B7FFB016E2CBC56A
+:101810004619C63B24B37873C02BA2FF4AFBF08461
+:10182000203EFDE8B51EB0670A3F1CF28A286F8192
+:1018300037450F0CDBC5E3D1875AF28322D059F02C
+:10184000F58D23E740FF3532D0E1887B8B03F45DD3
+:10185000DC3F1FAFA8C0FDA34FCE47BB499D553A03
+:10186000EF382EA7A5438B6F013B7EBCD548206E79
+:10187000747CCD3994E7EEB58D9EA92323F16525BF
+:101880003EAC8F33EBE3CBFDE2CABA78B2C20F7A3B
+:101890003EB939067F28FA2A167F503D5695947234
+:1018A000F97A4CD11FEFF075960EDDF26013C54347
+:1018B000C24211F1A0F0E591CFEFFF1EE8E138CA76
+:1018C0001FEB809FFFF9C397611F42960851E3C841
+:1018D000DFEBB37B942EB911BADCE65BD25706F18D
+:1018E0009F5BB7B2AF0CEBD7DB95D87A6D60BD3597
+:1018F0002C89C581F476472F0FFF69BB5359FD58DA
+:101900002EBC5F59BD280870D3504B1DE85FBD9EAB
+:10191000D0DB09653EFA79268445121CAF9EB78C50
+:10192000ED2276C284F57E8B3D0F9CF58B710C0603
+:10193000C00904BFF4585CB019C76BBCAA02E7DF4A
+:101940003811A09F78BA03B03E773CC60FDA325800
+:101950007BF1FA78E68F4F70E13A45C5213FEFC43D
+:1019600072335FC35897EFD9243A8F66AF210ECEFA
+:10197000154A6DD20108B9B44D31103389E049F1EF
+:10198000DF094406E87AB14E807D67BEC59483FEC8
+:10199000E92EE4DB6FD27D21E5F78307C55DDBE847
+:1019A000120F7AC62746F3CF1538CFFD0DD40BB7EB
+:1019B000F86B101EFDFADB5920AF770BBEDFC2BCFF
+:1019C000BA2A6B1E2CA4F369D82DE2B9D2BCBB8F06
+:1019D0008C62FB34EDF9A468B7E4421CA55988F782
+:1019E000801E51F0D86933A17E693ECAF460F309C4
+:1019F0008197D93E621FAF3FF7AE0DF7190ADEE9B6
+:101A00007A0EC1F8DE6F3B713DCA3EE3DF58CF91DD
+:101A100081D793E1407D017C2546E62FDA245C578F
+:101A20000F89F7C0FCFD3C1E44DE8D43BF59A16FFA
+:101A300003E73F85BE2B387D7B3A2E7CEB1ADABE5E
+:101A4000CDEBC253063193E07A7BDE4D40FE50D69B
+:101A50004BF9E06398DFDE0E6627DA8ED918BE6C8C
+:101A600045B9303FC5BF7624313F59BFEE2ABE4F3E
+:101A70000F27097DFE2DC4297CAE29E1A428F2A000
+:101A8000F8B514CFFF80FA1207391F24113C2BE35D
+:101A900028E32AEF9993B5F255C5E30AEF1A4925D1
+:101AA000C41361DC02D5FC56BB4ACCC929FDC7FD75
+:101AB00037E8E84ABE0C3A3648D6162191F4ED8B49
+:101AC000319426F79773BD9C091D9D9FC1F9BC5E9B
+:101AD000FE2F1A1A8940FB5D2DFA0EBB286CF69179
+:101AE0006E734E7F79B8941EA1F4BE32B9B0BF3E7A
+:101AF000192C9D0B93FBD1B93079003ACBAE8A8972
+:101B0000500FEB4F2FC07DDE2428839E300DC7F190
+:101B1000902F7B9D24F8346D94C4E328CA7C202E3A
+:101B20001147DF2B4BCE46FA0B120918693929D71A
+:101B30002380DE1F041F94A9E7F71FE0839B06E6BE
+:101B40008310FA25CB39BD972B7916BB06CEB31877
+:101B500004DDAA61DC8B064FAF2FFBF2E956DF9F55
+:101B60006EF503D3CDD700F2D36C22E7D10F2FAEA1
+:101B700076C378FBEDDE9389F4F99E26AE4FB22949
+:101B8000DD68FDCBC922EAAB47C895A887BF6230A4
+:101B9000E0FC7BA8FE7D3A3B1ADF0724177DFFE2BD
+:101BA0008D04CFE3E8FABE998CFE4F4080E7ABE7A7
+:101BB00013033C77CB4DC470197A6813D713AA75F9
+:101BC0006E52EB81287AA815EA293FDE05FC689160
+:101BD0001DD2407A68CBE5EBA12DFF613DF4FD817C
+:101BE000F9EFB2F9EA598677AD3E50F858D917C4E3
+:101BF000CA17A2F248D25DFDC725C483E7612576E6
+:101C00000BB3BB3B05B4B3CD27F27D58B659502971
+:101C10002876F8EC2E562F4E89EE0FFE3CD985FC27
+:101C2000BBBC7DA547D2E48104F0F943DEB38E113D
+:101C3000542F4E17ADB8BEA472163F54D64FF5ECD4
+:101C40008C69A93C6E4AD79394C9F09044FD013841
+:101C500047B3F3FD4162B1A4F1FB15BCAD162B04F3
+:101C6000887B3B9309A4DD50BF7ECD6838BF777A6F
+:101C7000B5ED5348EBA7220E42501E5CD47E431CA8
+:101C80002BA94CD70EF62179D05EF53CBBFF7EE246
+:101C90007832DF4F98881BEC0A11AB06E41BD57E27
+:101CA000E2FDE441EC273E4A56CEC7B5F6AB3D8E89
+:101CB000448D0BDC93C2F71FE79DE8FF8ADC6E4D75
+:101CC000EDCEC6FC94553619E305A2E8B1CCC8EEBA
+:101CD000FFBED36B20B26A7D4965F14456ED1F52B9
+:101CE0002A5C9A725AE5504DFB21BEE19AFAF4BA89
+:101CF0002B35F5998D059AF230FFD59AF6D9540017
+:101D0000D4E59C96AF69DA8F6CBB51531EBDE57666
+:101D10004DFB2B820B34F5639E59AAA91FD7BE4AEF
+:101D200053BE6AF73D9AF6CD3CEEABC7CBB51CAFC0
+:101D3000CD12D33B4DD6028C47365BB5F1C8B414F7
+:101D4000A67F4A1227E7421CBCF9647E2EE07B9FE7
+:101D5000FD6A8C8BC7E20BBD1E8BA53FF5CF8BF8C0
+:101D6000789FBC6432801CACD84BE5F52A5AB6BECD
+:101D7000B311D6D432969DA74A84E5F728E72BCA3B
+:101D8000FB7DE72B9287C557ED56B2390A5FA4A5B4
+:101D9000C851E39F0A1FC5C2DB3D83C4DB5778BB34
+:101DA0007F176FEF0AA4523D8F2A7E9EAD7F6F751D
+:101DB0008A819F07FB2A5398BF33211E3D7107CAB2
+:101DC000E3E5EA7F651E54FFD7A4A480FE7F63DEAF
+:101DD0006AD0FFBBCC1ED8937D52F946EDE332B4F6
+:101DE000AF65ED0D9E5CA04BACF8F7EA947EF1EF89
+:101DF0003A16FF8ED7E06D514AF4F877B3FDEF182D
+:101E0000FF6E3679720713FF5E043A2305E8C0F8C7
+:101E1000A38FBE3C7E1E6B1FE427E48000FB1EAB3D
+:101E200024C339D7A5F6B5743F9B0BE7A96DB06FF6
+:101E300052ED73E8FE96EF6FE2D02E50BBD79A8238
+:101E4000FA911C90E9F38B74DFBB5986A262FFBC48
+:101E50001ABFDC4C3C169388F47C04E849BE49EE7A
+:101E60008A13215E163A3839FBDFB2E7DF4BB90C33
+:101E70007B4E2E7D2E8776A79CAE7F5D14BF4B7F59
+:101E80000ED7E77F839F26E0791CE26903B58B704C
+:101E90001ED799C2ECF386A36C9FBCE1C46C37CA11
+:101EA0004D4AD180E77083D537BF4DE9E797FE36BD
+:101EB0006500BF5459FF2ABEEF9D268E6D8778E3DB
+:101EC000D9B009F12612961FD9B0DF4882484F9643
+:101ED00067ACD0D118DED805F6D948F479C572229E
+:101EE000ACDBB85F44FD4492597D80589AC0CF491D
+:101EF0002CD6DA2DA7576BB792CA5C3A3BA6B55BD6
+:101F000069955ABB35C4A7B55BE975053A3BA6B5DB
+:101F10005BC3FC5374764C6BB7725A6ED4D931AD37
+:101F2000DD1ABD456BB7AE086AEDD6986756E9EC89
+:101F300098D66E5DB57B9DA63E3FB459533F7EFF5C
+:101F4000239A7261D77735ED171F7801F36F261E3C
+:101F50007E5AD36E52F78F35ED28C2BB204F7B21BE
+:101F60009284906B4E3FAFA95FC8FDB46B7B7FAD91
+:101F7000E987B4B17CEB00FD0FE8F557E2338173DC
+:101F80002291DE57D2295D5704054F88365BB27B1C
+:101F90006711CCE3CCB1EBF7433F8BB768F3B49751
+:101FA00004B5E506323C11F44303E58B20E5936567
+:101FB00090BFADD26BCB48A31DF32106C9678B0F31
+:101FC000DC4430EF33E0ED82FC74659D0ABF793963
+:101FD000BF29F353D6BB8CFA7D2139B24E2FFD8F2A
+:101FE000ED23BB4DC0B7B5BB05F25DA1FF7AEA3A60
+:101FF0001EDE981E655DFA75E8FDCEBC546D1C7B37
+:102000009A68C5B8FED937450F8B0F6AE570D501C0
+:1020100016CF5FF59C80F1353D3E14BF34165EC48B
+:1020200000DB273424936050257F32C787D9AD95D4
+:10203000BFB3F00F98CF536210F282E2E4783DBF55
+:102040001585487F3C27E46AE5548F679B67685491
+:10205000BE92E97F308F5AC2CEA5F47CA5C7FB8A19
+:10206000DD0F9B402F5E2EDEE7A56ACF0795F38339
+:1020700012BA5A53943C3805AF745F5E935A187B7A
+:10208000DFDA907AD9FBD686D4FFECBEF59ED40178
+:10209000EC5C0FC4CBA85FA98F97F58F8FEDFD4C3B
+:1020A000B0631C9AC5BF7C1E0BCB57D1D9C95CB796
+:1020B000C64EF6ED7B4F0AC166DAF912BB7713CC38
+:1020C00067A9DDBB196099DDFB807ABDCD142F783F
+:1020D0003F87DAA99D51FCC3975315BFA802E3229D
+:1020E0001B4A587B7DBB9FA5B2FB3C9D29456EF4E6
+:1020F0003B4FE433FB692B1AD0EF7C889FE73C0011
+:10210000E7852323793C0FF273152A765EA0DB0660
+:1021100063855B9DE7FB48AA13C7B34F7ABE0BF2FA
+:102120009D9B1D06872083FF6CC073D1F55E6BD924
+:10213000AEB1ECBD64CD7B12DA6111F00DFEBC5581
+:10214000FABB9A6F5FA6B884FA58EB7C3995F9BB55
+:1021500046E2B580DE55CE738D27F32DA06F25C1E5
+:10216000E38896C769E4795253F879AEE860E7BB33
+:102170007D727E893CA97ABB6F9F9A6ECAB9EE1CAC
+:10218000BBF765A0AB5F0A98C1BFF45BA2EF7F5FAE
+:102190004D65FE470B5F1F7534918F707C7150F158
+:1021A000933753312E17C07CC5D5A2E734C4E70658
+:1021B0001BAF3A9EDACFFF399E3A70DCFC64229C5A
+:1021C0004F240E95703B21797281FF5BE0DF9330E5
+:1021D000BEFA3EBCDF2FFF5476F17C5A79C07C5AA0
+:1021E000A59FD94EEFC78057DA5F4F2ACBFB5B2FF5
+:1021F000AAFAB15FA21F8AA7DC46EBA0F0F739C3A9
+:102200009FE7340B265C5E5CD39CD62FDE674E1BAB
+:1022100020DE77F1E8E844384F56E256FA76167F2A
+:102220005286FA7E4C8B533BFEC6025676A531BAD7
+:102230002D4E647C3F8ACF43C90354E2D69619C41D
+:102240000BF71D1EE1F9D94A3FA3D26CD83ED13518
+:102250006514CC7763B680FBCA8D4E41B3BF3C9901
+:102260005A322A8DB69379FFA3D2189F6E1BCEE205
+:1022700033FA3CC833BCFD99D42908E99B57003E8A
+:102280004DA218158F63D2581EC64988911546E293
+:1022900067358FB1FB5D4ADC4C890312E2792B81F3
+:1022A000EA95F75A8D04E25A8B44EB46E0C3BEFB35
+:1022B00073FC5CDD41FF037B593DB602F38FFEDD0D
+:1022C000FB5B80CF04577F7B599AD6E7A7782EF324
+:1022D0001ED7D7D22EE3BCBD3B9EF16DAFCD8AF1A8
+:1022E0006C7DBB859C3EAD3C4E01FA1AEC864B24BE
+:1022F0008DD1ECC7C234C637178F9ABDE8C794C5D5
+:10230000633E8772FE2149C01B98061E0068F1A734
+:1023100067C07DA2BEF30F99E07B49562BBE27C94B
+:102320002464832BA1924780FCB26E53F7863498C5
+:10233000EFB58207EE0FA455393AD392E11EA18C76
+:1023400062B6319BD88BA13EDF80F5CE398E8D46AB
+:10235000C8BB96099C6413231DC746C7694DCBC6ED
+:10236000F5B7066EEA4CA3ED12E55E327C2CE8115F
+:10237000C77437C87125CB5FD7AFEF3E2E1FD60D80
+:1023800074DF00F890A3E781DFC7F98FEA99354041
+:102390008F1299EC62F7A2581E2AA45963BEA08737
+:1023A000E54B2740BE510ED33350FF90B3741DF060
+:1023B000B9225F22C737F0BD3A1FBE95E33B4927DC
+:1023C0009F0A3EE9004D900F21CD20C8D7B3AAA2A5
+:1023D000CFF7879CCECBED158FC07C674D6EC23C8E
+:1023E00077F2F9175F8845E0F43239A1EF1388439B
+:1023F000C42533FD1B27CBA88F8943C03C538BECEE
+:10240000A983729CF56A870876CFCCCF0B171A8800
+:1024100044E5AD94F7E3AD24C2FBB92CCECAF4ABCE
+:1024200044DE57E442E4C82902FBC9FEA85FD49AFF
+:1024300040D7536A3D88E78871231A4BE05EC1CBD1
+:10244000F3591F8FC4C8DB3F99C8E8E0127D6E03C3
+:10245000F8F4E4E4ABFB26239DAF841B9A0F6C7861
+:10246000F7D5FD993C7E0EF9E281775FF55ABF7C86
+:102470007EF9BEC7DF7D15F2CBBF3CFF7B04D0E306
+:10248000272963C1BCF5FCAFE8B3C3A2EFF0BD14CC
+:10249000FF3753A6F21700944815D29BE50FCDE104
+:1024A000780EFC9DE2D912C1F3CD1D07107F878DF8
+:1024B00074DE747CE314866AE33D893C1F2388FD47
+:1024C000DF62699B06FE4D8FA9370FC6ED79F1EDEE
+:1024D000CC00D52747EF3B672394FF8E4BBD367862
+:1024E0007E7ACD1B36C0D7D13522DE7FC37BC9AA09
+:1024F0007CA0F7395F95BA2B8E025FCD5FFBCF22B0
+:10250000B59F4DFC296877970445B8E3DBA7FF9694
+:102510003D93C0998E9597B72769CA8A3D5E6E8EA6
+:102520007E4F3CDDCDE8BEE4D96D26C8872F75FB14
+:102530007A409E4EF37C83D3BB6CB8BF52E6B3E0C7
+:10254000D97C13EC278F77984908F85EEA32128C11
+:1025500053796708946F7D9C0FF5F37C654F02F605
+:10256000B7E83111E348D5742C3FC5ABAF6309DB45
+:10257000DFEAD6B1E8A83C1DF4D5A24D0209C8ACEB
+:10258000FD1A4A379FFF7E3C5FD1AF536F5F2E909D
+:102590003526D0237AFBB290785A2683DD6AD33E63
+:1025A0005FDCF100F6BBF812E7314E37DF9F159183
+:1025B000895FE4409C7938E60BC6B237A7D732A1D1
+:1025C000FC70AD05E1476B1D088FA631BE5DB6BB43
+:1025D000F3957414EBAE22B04371074A2DB793887C
+:1025E000FF2C6DBB29F4A40C7CA9CD87ACE27856F6
+:1025F000FCE7C5FC9EC1A5FCE72A58E700F9905509
+:1026000083CC873CBB7FBC059E8F57F03191E203A2
+:10261000EDEFD8D7647269FB1B0B2FB1DE5B0EDFC9
+:1026200039888267456E8E723BB270FBEC8D43E950
+:10263000049A5FFC6B5637F2258B4328E754A27B44
+:102640006317AC5F24BAF85F80BC4954FCABE7CF9A
+:10265000C5C4C3EC8E95BD67E171893EBEEC7810B0
+:10266000F1AAF011DC2830B80186DC86E2FEDF0D2D
+:10267000E8F77D80366DF913637716E88DC5BA7873
+:10268000C12742F4FDD734F770B67ED93B1DF22244
+:1026900016918A8D2CAEDE86F8392DB5BD722FC805
+:1026A000F376264FCB7FF9DC2F404F2DFDD9637693
+:1026B000D0531F486DA9305EFD8E0D762FE82B2973
+:1026C0006087F73F088A51EFEB06DDFC1C9078AD80
+:1026D0009017B602590C042C3013F4E4DF76181D61
+:1026E00010476D78C61C32537CACD8C5F048CB2758
+:1026F00058F97EC457C36EAD1C2EFDE163A932EEBE
+:10270000E703E91C7FE9A0AA576C3762FEE88A3725
+:10271000450F0CD3407A717DFAF7611E614AB78686
+:1027200076B1DA94D8BF9E7A3C2690B3865D8C4E03
+:102730000D3A3FB38EEB653DBFB7E9F89CE205E388
+:10274000614A3E2B0932FDDCFCA3C7F34ED0797DF4
+:10275000B4FD55BB3036C2EF04B22E291DCEB6D71C
+:10276000CC873C83587CFE09978B3EBDCFED8CBC5B
+:102770009B4E0C7CFF0E06EB8D21FB35141FF5DB09
+:102780008C9E007D5CFF9CE8B5829F74C48CDF77D3
+:1027900058F6DCCB6F5D4DE7B76CA73179065B86E9
+:1027A00015F4B342A706E0EF82085D96BEF0B209C9
+:1027B000F220E1F91A57843ECB76769A20AF528FF9
+:1027C000C7D2F64E13932F1D9DDA4F4C07BBDCFC8E
+:1027D000A38B26E0830FF608045C48FDFB75DB5EE7
+:1027E000B683FE003C81FD50E8D547BF7E740BCD1B
+:1027F000FCF5046CE780739A58F45B09732944FE76
+:10280000FEE9AFE9F875EF983DB0FEBA9FDE698743
+:1028100075FC556A647CFEBD0DA9608FEB8C8154FC
+:102820000742F6BC6EEBD791FF16BFFEF554827AD5
+:10283000D33B04E497AE7308AC6FD15337E3FA6A25
+:10284000890FF9AFEE7B6205F88917245216CDCFB8
+:102850001F3284C9C95F9F36E3A6E0AF26C2BEC35C
+:10286000F14791E5F19195E8877C9DAF956A622CDF
+:102870005FB0303A7DCCED33E17AAC81B76AD87E77
+:102880003FEAB10F33BD6920EF140FDA78EAEBD3DA
+:10289000D2B8FEC3EFA5E07B94EF4AE139B4EF3242
+:1028A0007AE3F234EFF1BC5636FE5D7C7C3AEF7889
+:1028B00088CBFD3555BB7F55E05787287130D24511
+:1028C000D4FC154BEEB76F42BE3AFF26D32B2B82BA
+:1028D000B3CBB0BECB184A83FA60E71C01F502F512
+:1028E0002FA2C9F57623976B6D3D9DA724A8F1BB58
+:1028F00087DD8BAB7D94B653F92111BE31459E67C0
+:1029000047E453C9AF58ACF3CF14A8D70B4943B42D
+:102910007A41799F3C9512F51E56441F0490AEF5FE
+:10292000C6E00FBE0B727CC48CF70CEB9F33E2F752
+:1029300072CE3CBBF7ADDB29BF9F6957E457AB674D
+:10294000F5F25BF7FCCD249AFC9E49AE2051E59749
+:102950003E8F2ABFC92C7FFF7F5ACF2E8EA167AF33
+:102960001DD2CF9F48BC86163FFCF1B261B8CFD2D2
+:10297000E155C1A75E6FBEE596A3EA4DFAF7265171
+:10298000E151C19FC2974B7FB21CC7E9E35F853F0E
+:1029900015FEEDE34FFD7AB578D4D71BE0CE51613B
+:1029A00084EEC675747F0DE7AE2F8A78EEDA23F7D2
+:1029B000DA5D1097E579373D0E5E76B2726F8A69FF
+:1029C00023E80FE5796F1CCB43E8A9E8B53B557EBA
+:1029D000FD890ED10E79F5DDC1E8F912984901F1B2
+:1029E0008C18F914CAFDD969A235CB0FFBB2367623
+:1029F000DEB3B0E9563BF8D33D1D39B32AC18F3F52
+:102A000020A24FD513CFF3AB025E6908C56B0D5BF7
+:102A100032394D02DF013FBBA663D90CD8342E6C8E
+:102A2000D5E2A3D63A07CFB36A1F3546F88280BFF6
+:102A30001334819F55F794F6F952C8AB02FAE8F8BF
+:102A4000C8077C14E51EC646858FF2493EDB27F396
+:102A5000F32AAED7A68963675542FEE27E764FE23F
+:102A60006C874836C27A9FE5E7578114E4CF159406
+:102A70008FD571CE8F80CF46C7B6DF1FFDFC68D1E2
+:102A8000BDB449FD2FFE9CF724851FFDE2C8A8DFD9
+:102A900040F9976F67FD99F46F5FBAE7B33B308FEA
+:102AA000728F99C0BEA867CFEFB2EE85F2AFCD1E90
+:102AB0009867CF3AB63F0EECB1A15DEFC964FE5FF7
+:102AC000F38B17F3BAD13EAD477AED1CC2EEA99E47
+:102AD000EDF8C73101F2E93AE8AAC0EEF27D57C33A
+:102AE000AFE3707FDDF3E245CDBEF2DF5DCF0A7E5E
+:102AF0005FA9C7462AE17E718F93DDEF6CF8CDA404
+:102B0000EFC37DC5E5BB3A4D35B4BEF4B7FFCC038A
+:102B10007DD3F33CF327A87FBB155CEA8E275E6D5F
+:102B20003552FA7D023EDF50BAEFFE6E4239DCC309
+:102B3000E88F1786871E8A075817C54B1DE8C958A6
+:102B4000F8786308BB3FF2DF878F4FEF80F1EB3BF4
+:102B5000261288A747F02278D9731BE65DD0F5B31B
+:102B6000E77B2EE6817F74A9F57EFA7F6CBD8943F1
+:102B7000FFBBF9FDF12132CE4FCFF7FDF9FA977780
+:102B800063F9A7360FCE7790F27ED5D0FF5BF42E97
+:102B9000FF5F4BEF039CDE36079CA7F4BCF8CF2CFD
+:102BA0007219EBAEFF5FBAEE3E3FC7E0B14CA0F347
+:102BB0007B87046F2E1162E7713E3154BB8F98C939
+:102BC000FD8899C9B5E83FCCF4B2F84A3329D80F4B
+:102BD000F7D4025E11CF1D309986E2A16B4E7E10B4
+:102BE000F3B6A4C0C8EF401ED72DCB3DEC3B5FDA57
+:102BF000FDD5CCD4B232F0DF0E35D179D176876CE9
+:102C00000647335DC22CAF88FE1E85E8E7FD69CA22
+:102C10000D981732AB58BBCFB85DB76FB8B5525BE4
+:102C20007F0B793A05F2EF6EA93362BED0CDBAF6CA
+:102C3000AB873A709DB792C60D2C3E7379783AC037
+:102C4000F1D41F0F03E3AD1F9EF87E127379E4FEEB
+:102C50007833FBD8FED24C2BB8BFC5F3E4560D0A2F
+:102C60009F84EF3BCD7C6805BF662FFB5EA7AA5F04
+:102C7000C48B82F7CBC5B742273DDE15FC2A78D33B
+:102C8000D3E12938934889E03F02953C121F51E770
+:102C90005BCEECF31BAD88C7D7B6B3FB0AAF15D735
+:102CA000B4E643F95901FDB50B93C7130B5DEF2152
+:102CB00023D9CDEE7F79654751249F4528FE1D9E7F
+:102CC0002B403EA17A5F0AF984EA75413EA1BA0C15
+:102CD000F984EAF6904FA8AE877C42753DE413AACA
+:102CE000CB904FA86E0FF984EA32E413AADB433E7F
+:102CF000A1BA0CF984EAF6904FA8AE877C42753DE4
+:102D0000E413AACB904FA86E0FF984EA7AC827542F
+:102D1000D7433EA1BA0CF984EAF69047A8AE873CA7
+:102D200042753DE40DAACB902FA86E7F5DF8254D2E
+:102D3000B984BCAA695F6A7943539EE6F8B3A6FDDD
+:102D400057DDEF69EAAF97CF68EA15FADF907B4E5F
+:102D5000F31CCE2C0245B08F617FE59E7F68FA910F
+:102D60004805C6994DA411A105E2B714C69376840F
+:102D7000562AE6004B47F972D2815FB706360273D6
+:102D80001D9A74310BF4FF6B936F62F1077E4E3026
+:102D90000BFE2953264EF83C03F6B5CAB9A73D2CC5
+:102DA00092D078CA876101A1239C404249940FC305
+:102DB00071085DE1247C9E1476224C0EA7E3F39407
+:102DC000F01084A9E11C8469E16C84EEF01884435E
+:102DD000C257201C1A1E8FEFA587F3116684AFC15E
+:102DE000E799E14908B3C2A5F87C58B804A11CBE14
+:102DF000016176F87A84C3C33761BB9CF06C84238D
+:102E0000C273F1F9C8F06D0847856B108E0E572319
+:102E1000CC0D2F4378457809C22BC377E27B63C280
+:102E20002B118E0DDF8BCFC785BF81302FDC8CF04F
+:102E3000AA7013424FF8016C971FDE84B020FC6D1E
+:102E40007C3E3EFC30C209E127F17961F8098445F6
+:102E5000E1EF239C18DE86B038FC138493C23F4216
+:102E60007875F8057CEF9AF04E8493C3BFC1E7D71D
+:102E7000867F85F02BE1BDF8FCBA7027426FF855CC
+:102E80007C5E123E80704AF80D7C5E1A7E1DE1D495
+:102E9000F09FF1F9B4F01184D3C3EF21FC6AF80478
+:102EA000C2B2F01984D7873F40F8B5F0397CEF867D
+:102EB000F0A7086784FF81CFCBC39F21ECDBEF4FE6
+:102EC0008E752FD167F802F6CF56D7A0BEF345C84E
+:102ED00016CDB9D4E30976D493B3D6B03C928D2500
+:102EE000E7A6A25FBBD22CF3EF6BEAF4EAE756F059
+:102EF0001F3640CD10D607E401CEE3FCFB5AF1DECD
+:102F000014F097361674D7433CE4C1ECEE2A84E9FA
+:102F10002CBEBA9EC307D259BCF4F651CCCE56ADE6
+:102F20001C89E757247970EBF803D8E79448FBFA3B
+:102F30004C5EB6F666E1BD8041F633D87697CA8F0F
+:102F40005A95EE0BA6A35FA4BF9F37E8F79F413DBC
+:102F5000F1E5DF6F1FE8FDE39C5EF68C8A5D384F7C
+:102F6000C99B07F553D60D1193693FD5AD8203EC8C
+:102F700064CDFAFCE940BF02E2C578E2BC18795D95
+:102F800047D2599EC682462381B8E20299603C77B7
+:102F9000C12E96E70B71D072CA17759C2F966FDA07
+:102FA000690217B4AE7131CB3F0AB2389385FE0780
+:102FB000FCBCB47536E61F2D7B461B7FAA87B88EF6
+:102FC00008E7C8DAE70D3CCEA48F57EAE34B7F4C05
+:102FD000E7F1250FCB3B226206AEF7025D2FE473CB
+:102FE000F8EEB65940FF533CE03989B27E255EA920
+:102FF000E081F4BFCF8079A167F78FC43CB5B3B24D
+:103000009C06ED7C549CBAAC90FFE09B08CF29FE57
+:10301000309FA4B72901F3914E507D2E43E293C314
+:103020003711BE9FD6FD4E26E1DF6FD49E1B585A46
+:1030300031FFBADA4807A6EDAA7724E1FD47DA5F47
+:10304000DE6E8847EE30623E5080AC7293E2FEE75F
+:103050000A151B8CC81F0B763B597E58C0FB26E413
+:10306000EB2BF438B13E673AE4152D68C9CEC7B0F2
+:10307000DB6E23FA79CA79A942A7FE79D11589F0C6
+:103080007DC4A52DAF233D29BD34F5F5AD9FE2FDEF
+:10309000014AAF5331E8756A207A5932B4F482B8E4
+:1030A000F2AD50B92609E5B46A5D6864A38A1FF5DC
+:1030B000717A9261C5FB8E4A3E71D950460F2279D2
+:1030C0005281AEE75A0B915E7A3A95FDAB06E94123
+:1030D000DEB1E1F776E7E590F937D2E7F379DC7214
+:1030E0005EF3F5E83F676730BFFEB5B5906B49C842
+:1030F000EB6B2DC44B9DE737D63AB0FCA7B56E2CD1
+:10310000BFBD564678646D2EC2532696CFA3C81312
+:103110006500CCAB1B9DC1E4687486B2AFBACB0D21
+:1031200071E9B27FBD5108F93D2981E499D3AE45DB
+:10313000BF5B93A75139479B87D16DE4795E9B04B0
+:103140000F7C476541C5359AF624777CA40CF6833D
+:10315000E78D2C6871E2F7DB6E9B91A4697F4B4B86
+:10316000BAA67C5D868CF39B5D96A3797E7BD51891
+:103170004DB99AFF6E02B1C41BD4E753D4336279C0
+:10318000DE0ED6F67CE3C4B4D574FCF3078D58AFDD
+:10319000A7C7295300F7E381A7CD1EB043A7E11EBF
+:1031A000192D9FFE9388FAEEB491041C54759F1656
+:1031B000C87A804462F274E13093A7B27F8904F642
+:1031C000E1E4C7663CBFABD9229000DCA1EAA59838
+:1031D000A7E3DEF52333AE7BE11691F8F0BE92DC77
+:1031E0000EE7D677ED18ED8173CB7939A14CB8B7DE
+:1031F000D7FBF338CFD3B4B6A69BBD7F9AEEAF9D75
+:1032000090972414E0F9C1C7E56DB506C837100FD3
+:10321000A6809C7EFCBC88F194252BFF54E400BD65
+:10322000F64AFB5BC5749C536D228E7BE619F33620
+:1032300011E5DD9B06DF758DAC3B8871867DEE8ADE
+:10324000BA0CCAC71FD606F350EFAC61F1EDFEF819
+:10325000A1EB057A03BFAAF458C46EB17332AA7CFD
+:1032600086807EA8317AF0DCF454AB11CFF3A8FE4F
+:10327000C7F3FF536D4906A67F9E47BE5B20C92654
+:10328000F5B80B5A452FFB5D08D904F3250F8B3E8B
+:103290003211CA2C5F21D022F8D8798D96BE77AE34
+:1032A0009C88F78BF5F9530AFC84CA944F750EB4C9
+:1032B000F445763E4B26744BEAFC7125BE42DCACED
+:1032C0007FE53B3EF5C31FFFD6640ACF7AD92707B7
+:1032D0002F6CB7A17EFCC8F052D16A0ACF9407DEEA
+:1032E00097285D1A45DFA380CF6586D6AD029E8BF9
+:1032F000BCF72D388FFFF039A307C590E76B2DFD84
+:10330000F1926103E507C10CD8F972285570C357D3
+:103310007909E66FCC25ED3C3E1064E75830098A08
+:103320001F473D3BC77AAFD0B619EEE1D6E8EEEDC8
+:10333000BEC7EF2DFC3043D0D8E7BFF0728D81C9F6
+:1033400027D9C3BEBF08792F2354F654D1A7BFC8CD
+:10335000188EE3F6D955D28E7AA5967F1FB8FE193E
+:1033600033BBA7231307C8E312461E7216E4998ED7
+:10337000B3D4F4DC77809D17932EB4731F1A83B5F2
+:103380005DD9F0FEB6F52E7CDFE80982FC723B6069
+:10339000A18A03F4C762C2E6B7BC4D088654710A1D
+:1033A000E5F73808D80595BEE96F0FB4766011B718
+:1033B000778B882EDFA74D6B972A126CB8AEA56D60
+:1033C0003CEFB96F5E22F982E2ACD6177C6526CE5F
+:1033D0005BF004A3CC6331E90DC17780973FCBEE5E
+:1033E00003E9E7A55FC760E759EB993D15BE27DC08
+:1033F00037AE6EDE0ABE095C5052D141C17B6D8092
+:10340000E1B3B643407AFD85FB55CA3D3B85EE8B63
+:1034100049C54CD06B8B1FA5FBC2EC081FF4D9EB40
+:103420009D41F497CE9036BB95F27FFD969DB74CAB
+:1034300082F79E7ADD04FC5DE50A8D3438E1276968
+:10344000EEF956596614FBAEB3E7FF29FC101E6770
+:10345000C2F7283E166D1731AF41D58E9FEF07108A
+:103460004F7501827944756F8A9E66FAB40E7ECEDE
+:10347000A7E0F2E7ABE0E77F7ADE7A3F263B7360B6
+:103480003F46AF5FFAF9313AFB09F726C05EF6A670
+:10349000B03CF0F39237D1857A59A777530AF0BB45
+:1034A000A38ADEADE5764F196711D83B5A7E7FCBF4
+:1034B0000B76883FFCE5D11752318F02ECCBD888D0
+:1034C0007DB9BB868D77F72FE3306FE9E3F2AE3C31
+:1034D000F0FBAABEF73BBBFABBA6756EDF75993051
+:1034E0005F6E0F978BDBB21C600FFDD1F32AFAEDF4
+:1034F000BF62ADD3768975DAB4EB5C00EB54DD07BF
+:10350000A9E1EB3CD9C2D6F75E2B5BEFC27EEB0C98
+:10351000E039C8DDDF377B02E86784D08E9FDE2983
+:1035200012B87FD6E767E8ECFE05D2B615F0B17C9D
+:10353000D5DBC724CA174B4651FC503EA87AD88C1D
+:10354000767EC9CFD9F9E78742491A1EC0EF0BD959
+:10355000BF419F2FA5FE01F8179179F4D9FDC599B8
+:10356000852ABB3F48FCADE071A8151DBFC3DF8BAA
+:1035700012BC2C1F7285F21D98DDBAEFC0C8A003E3
+:10358000D83D790BD02983C86C9FA88DA7FE6DE428
+:10359000A777AC42FEEF1DA5FE5E6F437CC808F91D
+:1035A000BEBD3B05F48B96DF55622F2190DFCAE24A
+:1035B00060EB3399FD12BC5ECC7B3153BAC6D3F1BC
+:1035C000EECF94D973D9C1F2BA9F22F8DD1965BE46
+:1035D000FAE7101FB780FDB31AD0FEE9D7FF8B4C76
+:1035E000E62F2F170DE84FD79B985FDDC3BFFBF089
+:1035F00028AF7F3493F9D7DFE5F1811EF023E17C1A
+:10360000FA5A33FE5E0F2153314E2E11C67F92823D
+:103610003787F4499F7CA3BFDC9B0178BA83741978
+:10362000819E338B67CB706FE058AA05BFA344FF20
+:103630002AA09FB9BC9F4346764FE0188C41D735EE
+:1036400097C7938FC16740E9F8C78698D08F0DBCA4
+:1036500068463FE1FE7816EF23C98912F0F9ED5C68
+:103660004FCD9B6CF6C2F9C0DCC9F75700A4FD052D
+:1036700008C55795A577433E1DA7C9C0EC7C938B21
+:10368000E07D49B2BEBB10F07715758B214F9EAE21
+:103690007ED7174903F191F69E423DC415AE268CA4
+:1036A000C18A11BF9A72BD89D51FCC3C36F3D10CAB
+:1036B000BABF866C26B0338023E08BEA44DCE7CEC9
+:1036C000823C7E174009F9ED4689040C0CB658F18E
+:1036D0003B442CAF5F3907B9B9988412E9FA420725
+:1036E000B4F7286E0D1942A3E17C470A7502FE0C5F
+:1036F00016D9E8A0E35494090580F7FA75839BEF87
+:10370000F1CC0F70BEF5F0BD2B98E73704CCE799EC
+:103710004B851EF8F40E89EC130B18FD800F1B5C13
+:103720007200DBAD647CAEDCDF50E8924FBB57E348
+:10373000772E9F1FEDA7C50EEF9BA2C74DCE70F948
+:1037400050FCB4655C6E97297CF7AC565E6D5932BF
+:10375000FB9E1AF883146F73398CC5F7F159ACFFCF
+:10376000F82C165FFBDB658EB7DC4C42B8EE17CD4C
+:10377000484765DC591C5AB258FEB2320F857F6B40
+:103780004923E6DFD4F2788C816A12CCD36DFB3EFC
+:10379000E6F7EBF384A8838479674BB7EB9FABE242
+:1037A00039A2462F619C5330F52E84F9095F89F3C5
+:1037B00000BFCF35B5633C40DFCED826A09C1B5B55
+:1037C000A83F25F0F32D5A36B70AF8FB0E73337A6B
+:1037D000C7E1F7CAB95F5DCBE94AB5F774B80754DA
+:1037E0000BFE149E7FF1EF446D617EA4C4FDDF05E6
+:1037F000AD5A3F63EE7A959FC980E65EBD59971F2B
+:103800006EE4FEC67153EF38D0F7FA7BF6C70D6C45
+:10381000FE815482F991CA3D7B89FB930A3F0DC911
+:10382000326ACEC594FB9C55A0A7D8F70E74F95404
+:1038300056FCEE4A95C0BF57C9E38A67A9BF89DF26
+:1038400095391A87764B8933F694D8028644F89CCA
+:10385000252BCF4BBC7B26F89955769304F0A2A17B
+:103860001BC7592D76D9B2B32371DC8D25E3B74040
+:10387000DED0ACADA3675932F19483DF471AFB1A4F
+:10388000E4ADCFF99CCE1FCBE36679E9FEA8E7E56E
+:10389000DE3B2C54452FCACA9B25517BDEF358EFE3
+:1038A0005628AFCE9A384BA276B0E7C1DE2CF88608
+:1038B000F0EAADD7B0FA26A5BF6B66417E70CF1394
+:1038C000AC3C87D607C0CFE5F780AAAE1650CFAE86
+:1038D000E6F647891F55195E62700AFB9D8F4BB54E
+:1038E0000B6455AC063F47B49DC2DF13D82C7BB1A7
+:1038F0007C5F866F7E16ECA3660B0113DC8B7F3337
+:10390000388ADBAFA8BF7BB13A93C9E5BA61AC3F57
+:10391000055FB49FBAACC2CBEFC701FD146AFA5978
+:10392000F965E673B4FF7CEEF932F3F1CADAF928EF
+:10393000FE99F29DB957B2BDDF81F92DFB26DB0F51
+:10394000935356CDFDFF738DBF1C0576FFDCB3E6A8
+:1039500024E0C3653FFD55562DF87FDC1F3AD3792F
+:10396000C40479DF2BC2ECBB380D61F69D9C15BBFE
+:103970003A4DD3C7421E6BA7A95435BFFAC8EF5CB6
+:103980004937AAFC9827B30C3CDEC67ED771D94FC5
+:103990003FC0EF092E33B4BF0F79BEE46A1647D398
+:1039A000AFB399BF770CCEFDA3C40BB66531BFE3AF
+:1039B000628E3708EB5C9745B02CC6F86ED787BC93
+:1039C000BFAA78A6C76B8A6C1699E2BBF04D5F332D
+:1039D000E49DD63E955D20D2790433A6FC386BC0B9
+:1039E000F8662F8B6F76B0F86695ABEB2E6AA4C89D
+:1039F0005FB6CE7DC8722D21373C4EFAEEFB41DC1E
+:103A0000B0CCACC8CFAA595327B3781994F767D56F
+:103A10003F04F2B39FFF3EDBBC89E3E241CEBBB380
+:103A2000130C0E2AFF3BD3ABFF027C316FE2B5D300
+:103A3000E17989D936AA9AC5C7913F76A65784A05D
+:103A40001EDA43DCC3670AA5DC4AD7E1FBBD8879EF
+:103A5000D3BEBC045FB47B2A7BB8BDFA4B163B0FC8
+:103A6000DA6FA0F32C88CC43199F72FC5D5D10B710
+:103A70005A37241FFC687B46C9A9ACC2C8F8F60CAB
+:103A8000DFEBEAF1E972F3E0F960E77188D3E31460
+:103A9000A75BC56411BE94D0A7D76F9C9AA029CF0D
+:103AA000999144BCEAB8E99C744DB9B22A47D3FE57
+:103AB000F6856334F5E5E6AE098D97E1EF37D89EDC
+:103AC000C1FCDEA31D17DE9A0B7EEC76D123D0F568
+:103AD0002C7971C75B907F7D167E82A480C5C5D886
+:103AE000F71AF9798CE49534E731075E3081DFAE5F
+:103AF0008AF3EBEEE51DC438BEFE3C46C917FFB2A3
+:103B0000E731D230FDEF797EF40A5D1929DDDD89D8
+:103B1000F4693EC0F2989BA9DF02DF13FBEA2E7323
+:103B200010BEE1FEF1AF4E9864D5B94C43B8097FA1
+:103B300057B774F7093CB7D991C5F4F68A8E4F4D43
+:103B4000704FEAAB1D2B519EA753FD9548F9A6ABCC
+:103B5000938CDB05F1E46C1BE6E12C6BB91EE3D41E
+:103B600089E1B908EBDBAEC7FE96876FC2F20AFEA9
+:103B70007BBEFBE3BBA6831DDEFF0B27EE075F13B7
+:103B800043A39E847ECC36D40FE5E9F3D6819FB063
+:103B90003F3E30F64E3A5EF9CFBE8A79E82B760981
+:103BA00018372D17C97E01F2EFC371D85FB9F8C776
+:103BB000092BE9F31B4A995D2D071F87D68B45B664
+:103BC000CDF83DE918BF93E619C6F48AB19BCD7BC9
+:103BD0005A7836F6A7D4170D1BAEF99E9F3165BBF8
+:103BE000B4C01A598FB15B40F8B5F018840DBB66AC
+:103BF0004B907FFEFBDCEF27039E687BFC3E587FEB
+:103C00007D3C319144D15B0A34733D3C17F4309CC8
+:103C1000DB677B670C4B81DF23EC962CA047AD164E
+:103C200007F82F338BF3E55AD5BAC4976EC37B10D0
+:103C3000E6E45E23D8EFB914AAF5F6FC1876E6C6DA
+:103C400061CA3D9B26F6FBBB8A7E7FF7EBEC3BA867
+:103C50003C3EA0C8D375C30C9AEFE974094C2E0200
+:103C60003F67E702D3B37D0B61BE5D25A4F279D433
+:103C7000A35D59701FFD3F357F4A5F0BD0DF2E7566
+:103C80001388632C19A6D81D26CF979AFFAD7CBD4B
+:103C9000AF89C40F7CF1DA75D77579E9BC3AEF1DAD
+:103CA0003F1EEC8232DE3DC3589E2971F47E8EF9B0
+:103CB000867B126488EB97C399C784883F0FF98885
+:103CC000103F6CD8637E1A3E90DA60A7FB7B2BE432
+:103CD00005C685806F3B7F1B2781FD1833C277CFD8
+:103CE000B042783E7A2A7CC7C7DB619608FA41DE8B
+:103CF0007B015FB1E67B29FDA5C8A39ECF7C2D4C3F
+:103D0000FE7C5C0EAB39DF2EE072582D7912E13C5F
+:103D100066FE4111EF452E58238CDB05F101D98653
+:103D2000F7F4153954E4CD087C391EF893F1657D1C
+:103D3000D8C9E53B9BF7CBE4A05C64F976E5639CCE
+:103D4000B87F5E114EC2768ABC2A72BA3EDBF76338
+:103D500058777933956F3A8E6FDD9009202F113E99
+:103D60003139809F289FB86B557CD0DCF999047C51
+:103D7000629C2C209F98292C55F151459F7FE298F9
+:103D80009E4AE731737D367E4F59A9FF591FBF0CFC
+:103D90008EDF9FE2ED17584323C1AF3536C679E079
+:103DA0003BF2679365D463AB3609F8E384AB8C15BB
+:103DB000A5E05FAC7A42C0F81EF81DA07F8A0E37DE
+:103DC0009AD4E720B785F3F0BCFAA6F00884C10CBA
+:103DD000DF8BC017D5E15B381EF3A29EF79D6FBC49
+:103DE0001FE36AE783660FFBCE98367E57E8F5E05F
+:103DF000F99FF1A0916C9321EEE613F17C2F93389B
+:103E0000BE2DB0F81DC4F394F89B724EA7C4E1CC4C
+:103E1000F03D5C951DBD20B565C13EA45F3CAE8400
+:103E2000D9FD8FB61BD9BDADCE3F161968FD87D918
+:103E30005E8CCBED73FBDE86F52CBD31F853232D64
+:103E40002F7BF0053BC4CB157CB64BA191B05F6ACC
+:103E5000A77884F8607BAB581664FE4EC26C557E22
+:103E6000452CBE5E1ACE41FC28F646D1DFBF5CEB86
+:103E7000C64DA9A2C72F658714FE5ECEE56039C87E
+:103E80000151DB9BD915F0BB662457C07BAE117B7B
+:103E9000C3E441D1D394DF516ECA733231AEAEE880
+:103EA0006DBD3DDA2BB67FFB6A3847937D7132C515
+:103EB000CF949FFCE385776855FDF33F9A0A742AF7
+:103EC00019231038C7BC949EFC7FD95BF3F900809E
+:103ED000000000001F8B080000000000000BB55B15
+:103EE0000B7854D5B5DE67CE9C9949322FF28020ED
+:103EF000249C993C0825E0F08884879F0702018470
+:103F0000E0046F1135CA2422CF840494CF28F4CE64
+:103F100009090894DAA0D6528B7642C1528B6D788B
+:103F200058D38A303CA441AD1DAF7DD02A7450CA0D
+:103F30004B9088F582B754EE5A6B9F939933495052
+:103F4000DBAFE3E7B7B3CE5E7BEFB5D7FAD7DA6B7B
+:103F5000ED73100F7E2EC94318B3AE2C678A9DB146
+:103F60007BA12D81F63AFE6E634C624C69059AB1D5
+:103F7000A879A623F6DC299B18CBC0E70D8C153158
+:103F80003643E77B7F3963B73076BF9BF15F3D30C7
+:103F9000F565ECDA0013F14DB1B239FE42786E8E60
+:103FA00064C7CF57EA9920CBC09A270B34EF8C9582
+:103FB00051B32D1DF8EC36F7360FD0C5C3E4798523
+:103FC000317EF12BCA5D26329B900AF29AA32CB562
+:103FD00010E7D7E556F93A5F22779AC6FF3B91D5AD
+:103FE000B7C2F8DFDD765B4401B90EAC18314294FC
+:103FF00063EB15CB16DA5F591A8C1DC958C76BD6FF
+:10400000D016909BC17C02F05F7A6D50683D6CEDDC
+:1040100004EBB8C68056F7A6C8B8AFDA7D29C45FEE
+:104020009BEC0A09D05FEBECC8F7833C25FB93C2FD
+:104030006C28ACB33FC9CC60DD2B390F14CB45F8ED
+:104040007CE044C10942EFB59A19F0A9D9CA68D4F5
+:104050005B4FF2EBF225B6FAFE4BCB05D5E5626C71
+:104060005A89433541BBE86A0E6323185BBC762A44
+:10407000B5AF043341C98C4DBA5A0ECA60ACE6EAFA
+:104080009DF47CC9D514A2A77D3B528AFB61AF0881
+:104090006C1BC85FD6EFBE550CE46B4F6643F6C091
+:1040A000BEDABD59BE46E8AE6E9E4AFC65BF983C7E
+:1040B00005F7B5640F30E3B8022194877A3A653783
+:1040C000B1DE8C3D64E3E27F5AF7A791328CFF7436
+:1040D000A4631803D64362EB536304B2673BDA73FD
+:1040E000C2CFFEB1FB2FC0275D159902F258AF0A6F
+:1040F000D446E4C022D407F031067CD5BBFA8E0C3E
+:10410000D8BF0A9E7E25C98047A9FA1309F16485A4
+:10411000B624AE7F8E8693443DD6CA1CD75FD50F9A
+:10412000EEFB8A785A8578CAF88FE26915EAA91BEE
+:104130003C3522CEFE553CDDC08E3EE689E16CDA90
+:104140009B1C1F2CC7E1DBC6082F2477BB252BD473
+:10415000087CF7A25D115FD7591DEA730EDA372D7F
+:1041600086D7973C819FC4DBB93D592D5C5AF855E1
+:10417000EC7C37C3B8716F7A1D53E0F91C68E3E338
+:104180008615ED57D8757F3BBEA69D9FD5F8BFCC51
+:10419000CEAF6976666EB0E348B29F8C764DB43B85
+:1041A000DA15ED5EBBCFBAE546761D9C1B68EF2E97
+:1041B0004E3077B209E58CD9C57A27E2E6D3B099BB
+:1041C000A17FF564576913D7BB4EAF0E9BA784E858
+:1041D0003C6069E543082F47FF9DF85356D2FA77B4
+:1041E0005B2FC6CEC8757E33F0CF2A86AE9BB07FDC
+:1041F00069B362C6F8027F8EA1191566237D6AF441
+:10420000B2C844D8EFB4A73AFB55EC9F34CEA58D85
+:10421000670A6CAB93FFB45C1BD9407237733B06E3
+:10422000A266FF90387A24D08E38BA3881DECCF975
+:10423000F11C71D33C211EEF617E6138D2FA7C9A69
+:104240001FB08ED25E60BF197B04F77AB0F73DE3F2
+:104250002E59D03E6525D123FD60BFFF273FEAB729
+:1042600027C1738C83206FB2A7A159356BE3C17F3F
+:10427000AA35355A5B0545043B55170B21AFA7AB53
+:104280001E933DC6F30C7F66E3786619F9F5C6A365
+:104290001D69BC97C687AD5F63FDBBC63125D44D94
+:1042A0009CCCD4F9AE01ADCF0FBABB13F617EAC65A
+:1042B000DF640FF79F88C954C3405F059EEF35DB6D
+:1042C0006E05FB328E8F6F789EF6AB855C5C256148
+:1042D000BF3792D7E9D1FD38B65FD9383E7C237D10
+:1042E000A577D197868F0546BCB8CCFEC39F821CAC
+:1042F000AE74C1AD82FD97F893363017DA5FC7F719
+:104300008FFC4A7FD85F12EBC4AB11DF21FF44D092
+:10431000E312A6F76F69C673C96FEAE4E778DF2B8B
+:10432000748E2F00FCB8181F3FD1D3D2ACDAC91E4F
+:10433000D44F74EE0DF0DE9A408F4BF00F0DDFE49A
+:104340009F18B7413F79DDC48D4A4DBF1705361B15
+:10435000E35E6402CFF7225EDE3678787EB750D314
+:10436000E352AD8D24C7E9A17FCCCEF00BB302C3DD
+:10437000BE494F77A76BFB56C3FEE9B0AF482A1B77
+:1043800022004E56B4EC6D6ECA8A8DFF564BD88F04
+:104390007AE89C4FDD17C1B87FB7A6A78696FD11B6
+:1043A00095C73301FDAE86000138D823A822ECB3AF
+:1043B0000671D0CD3EA775F51B3561BC22DD607C52
+:1043C00079571C2A09E39994FE75C66B769A9E600C
+:1043D000C72909769C984057E874C810CFF438571D
+:1043E000D5B671756F9063F176018F098CD7166120
+:1043F0001863CF78DEF0DB47235E65A91FC4FC6736
+:104400003D6F456C80E5728C6784DFDF362B6097EB
+:104410003BD1DF897EDBAFB8103F75AB33813FE422
+:10442000F95DB30D58EF69DA28614EB3D5F34EB399
+:1044300019EC77F7C85F1CC1F9CCC2BB91E9C20D7A
+:10444000F0DA9CB08FCD09B49AC0FFF497C4F7A6F8
+:1044500084F12B13FA3724D09B12E8B5C6F195737B
+:1044600005F2934AB01F2AEECBFCE6D79ECE7CA184
+:10447000F33C13EC942719703FAD91D3873D27FD92
+:104480006B0BE3E8960FF47848389618FFDD9BCE67
+:10449000543C3FA41EE2D9AE9EE25941E279C7FBEB
+:1044A000FF8A7FF6C5BC9319CEE543A2913E20EA70
+:1044B000FED61179D88E0F75FA921FF3F169DF37A6
+:1044C000EE0BEA42ADFFA27F22F8FFB4EFEAFD1740
+:1044D000FD4ADC3E75FED27F5E1771BDBFB45CF055
+:1044E0006F85F92A2684F3EAB04DE52D9C33229E90
+:1044F00063B536EE4FA5AF897E3C672A92C379CB70
+:104500000AE3F6C95AF3719F075688641FB591D71D
+:104510002355CC6761500A1D70B9EA5F00FE432B3A
+:10452000C47A3CD74ED4A7F546F9077B79BD77C846
+:1045300035A0F783401F4899639181EFC0E393A8AA
+:104540003D282A6B3A00C7573DD7FCF641D8EF22E9
+:10455000FDFCBDE58ABF01E2F4158F4CE303A9EE33
+:10456000DE6D98AFAE97D83619E5F13D4FB8F98EAC
+:1045700075D87A90A3B261706FCCDFAABE575EDAAD
+:1045800017F8AA564B3E81F8D850943BB07E92055E
+:10459000FBE73669AD3A99DAFD5FEC7E7328F07778
+:1045A000AC137D5B8079DF55AFB30AE4FA3089C77D
+:1045B000E10F2EE43A51CEEF7A03A217EC5AE974D8
+:1045C000240B7878B865E74C9877438E62F616C569
+:1045D000F8F77F21CEC17CF3D50B55BD03403BBD21
+:1045E0001CAFFBAE56F5AE8A3BEFE75D34939EF70A
+:1045F0005BE48731BFDC9F9C25A8E4C7AD69E5E09B
+:104600002F73B5FC1AF052BFBB9B73FF1F1E917036
+:1046100076CA5ACF3E04101FF876C63894531F57F7
+:10462000F4FB40A303F1DC5F1E1E9F47BBB227DCF7
+:1046300084FB88E12CF51D3C2F298F063ACFEBDA5D
+:10464000A802AED821C8FF518E74A514FBD94A60C8
+:104650008038C6325BF3E3EF236279EA2A2D1E70BD
+:10466000BEE3AA83EAD6E33B924258CF1C57DF73DE
+:10467000307B3C3FF793F94E878A87F11987C38CCB
+:104680007A3D610E9E7E14C6CD7B4EA2383AEFB9BC
+:104690008C951D180FC09E79ACEBBAFFED9568DDC7
+:1046A0001EFD84C9E513C7C5F9893AA01CF7D39349
+:1046B0009FDCE61D50BEB5B0673F99AFE5EDA5CFD5
+:1046C000497EC4F9FC228799DD0C75F673AF6F4300
+:1046D0003CCE5F9A34DC0A82CF7FCE4AF68D3A1CFC
+:1046E000AA1BFA034E87B917B4FFA5E121DA90445B
+:1046F000758AD8DB42714F5C5324A37E4A4466B668
+:10470000C1B9223A7DB29FD34D6EA8DB563B8A6574
+:10471000B4EF0AAF4C7AEBEC77CDBE5D80BAE632EF
+:10472000EC230DC69DAB7FEA995120DF79169A35AF
+:104730000AF47E190D0DEB5CDE238654AC8BCD8A1A
+:10474000B90CE2DE02C6FDBDE6E86ECB78F8734137
+:10475000DDFCE9581F2D0C491F44B5DAE73AFCFF90
+:10476000197BCB82F9EDE2EDC6E7E03116F4AB9AA6
+:1047700056E3F35AB6E1137128B6E60FA205DA73D1
+:1047800058B7FEFD3F0F391CC757ED75A49F1E0C8F
+:104790007F0C67C341B3B04EA1EB2E845DBD48F2E0
+:1047A0008AAB9242A847319B9F0F9399104A42408F
+:1047B000B861DFB0EE95E0B121870110E2632348D4
+:1047C0002FA78280A781A00FA78DF8C5C7C4901519
+:1047D000D62D49634A2FD4E733E58C39489FAA1B6D
+:1047E000E8C9E975668C4FE7B4F85229307F2BF998
+:1047F000BD2F1BEBE379CF2591FDE63FBFF08F3F47
+:104800001889F62A4B8FF7A3C735DCC17CCC961AE2
+:104810009BE74CC3B7B2519E921F415D89F5A61824
+:1048200078E66E8A97293E8A5BEEE87746214E1A33
+:104830005286AD678893BED9DEC2D8F8F9AB56E48C
+:10484000F3F150AF3A315E25D17EAAF7580927958A
+:10485000EB4485CEC72C0B9D8F1F3425115DDDBF2A
+:1048600098FCACD2C402B80FC8053329AE7395B317
+:104870006A3B5376DB31CE6F88884EB28FAAD9CD92
+:1048800082F6D9E24DA3F5E7A08EE1DC3AE8D5F453
+:1048900062E2F861FB84D0368A4F7532FA7F85492F
+:1048A000A03897E88FBB3109C371D9BEFB715CCDCD
+:1048B0001356DF2A0F9741D4E5013CD59822F37EA9
+:1048C00088F3FED24AF71AB5B08F2427D517CA2E1F
+:1048D00090BFD6CCCC16BC9792793CD3E5A995CBAA
+:1048E00027234EA1FF9819FA6B1C3C1ED7F4E2F760
+:1048F0003DCC610B6D8B5F0F65CEE1E36427FAD988
+:1049000068C20BFABD09FA2F31DE5FE22C96A3F0E4
+:10491000BCDDC4D6E23D09CA336868DCBA40F71D85
+:104920008A785C6AF63AD00E69B366E37A2F891406
+:1049300097C0999E28C6FCEF257104D6B195EB0E61
+:10494000956E427AE730378A50F9F377E97C5AACB2
+:10495000E12C8A793F9E5740EF84F63D2FCF2F02FE
+:1049600022BFC779CFCBF37F5DAF7A7FCD3A89EC99
+:1049700051B39AE3A1A6E14F346F8D23D21BED51C1
+:10498000F3B2740BE2FA941627AA1AB2C61D037C7E
+:1049900054492EB7008FAAD5320BD2D5CD02D1FA09
+:1049A0007A35EBFED0DB54C8E7C3D6AAE128366FD0
+:1049B00046369E671FED48CBAE8CB3FB474DAF38F4
+:1049C000653BFA4D38CF8DF7304B937C5BC84FB9C0
+:1049D0003D3E6ACADB82F73473DD118700FD731F29
+:1049E000CE49C573EE843B6CC1FE13AD1E13D28A53
+:1049F000DB3D0E69C57C33D11F41086FD5EA56C433
+:104A0000F11281E3A67AC7218B17D64BCAE138BBD6
+:104A1000F8D2BBF9785F50931DC9C7F3177095DFC3
+:104A20000FEDF2A24079C2921DA292343486AB25DA
+:104A3000882BF0FF451AAE96EC79E511F4D3258862
+:104A4000A7E15D710975E5617ABEABA594F1F187C7
+:104A50001177FA790F749384F76A168D8675904EE4
+:104A6000CEE1B881FE89BC5F2DA47384452D980FDB
+:104A7000D78A3C4F007FCAC43CA2B64D523BE325C7
+:104A8000AE8BFD85B1FE9E703338879F27550D563E
+:104A90003A8F066B7A89AE7BD989B8B8F8D2A12350
+:104AA00063B0BEDA25B831DE77F1434D6FB5A82784
+:104AB00027ED93F2A25AD48B33A6A74E7FD3705121
+:104AC000CBB81E74BDD49A353DE9FDDAF8C21C8E10
+:104AD000C36AA6E975CF40EEEF9A7FEBE788BEBFC9
+:104AE000402A1FAFE3EBBE1C8EFB31DA3EAB013731
+:104AF000BE42C29762B945ABFBA1EBE2CE16BA3714
+:104B0000D2EDA9CBBD5C5B1FE2B4D22B3566E7A822
+:104B1000892DE8EE9EDAAFE94FB2F3B872B2A1DFA9
+:104B2000FDF5A0BF453B441F290F6BAEB875ADA680
+:104B3000A883F2D2C74437EEABE467E5B7E3BE75AE
+:104B4000DC49DB0573DB48AC337A91FE75F94AFA30
+:104B5000F86FEFC57117467974394F0A61B297BA89
+:104B60005370F33C376AC1FB43DD4F13E5BD2F475C
+:104B7000D0F201618C7033CAE393D1BF199C8324B6
+:104B80008FFDD80A5A4F3DBEC23334B6CE09D56127
+:104B900046BE138CC7011D9727B5FB8893AB5FA159
+:104BA0003C585FE7A1AEEB04EAD3BBAEA3F32FD62C
+:104BB000F875BF684FE5F82F69FA13F1E971167FB0
+:104BC000780FA7EB53D75B9C5F1AF4A3FB97EE4FCC
+:104BD000BA5DFF55BF622B33285F7D5CDB37F94838
+:104BE000EFD8B980F8C4F3CE6A015CDA0DE726E5A8
+:104BF0003593FB7F620974F35CD753E2F3583DE5CC
+:104C0000CE46FD4FB6679A300F604D998773E3F239
+:104C1000B20FF1BE0BE36906E3EF33187865DC7978
+:104C2000AEE76BFA790DBF0D9DB884F1B5E9CA39CD
+:104C3000EC5F3072693EE6119772BCB4EE79D66AC9
+:104C4000190FF3559F8D943AE558BD72EBDFC3A25F
+:104C50000BEF03F7780CF542F585C3E4DF352CB292
+:104C600006EBDBCA75EF968D42BBFF14F271E09B39
+:104C7000DBECA173EFDCD6074660295BB93A8FE81D
+:104C800085DB1EE4F43A9ECF55AE2E7A01EFE33F6A
+:104C90004C524A11DF1D1B0537D65B63B715ADBCFF
+:104CA00007FAC73A06F442B98F6FFDB06C0CD60D07
+:104CB000F522F98BB2F5A959D8AFB4893EDCEA5C8C
+:104CC000E65E790FE2DBEC227F3BA19D138D12C7DC
+:104CD000D91B5A9C38A8C58D831A0E4B1A1BF34D4D
+:104CE000B86E0B9C4FB0FF0A8BDC1AC6BAEFB53E0C
+:104CF000BE2DA82F285333014767059E7F2FB03064
+:104D00001BE2EAA814598EF21F5DEE18D6800288C5
+:104D1000D76E41BF50B43A0BEA265A57D797BEFE1A
+:104D2000512D8EE8F3E8E3DA319FC2F34393F75C49
+:104D3000D34F67619E706E7B5E2A8BD3FB39DC1785
+:104D4000E87B21C4C55DDDD47F7FCCD1EF23427CDD
+:104D50001DEDDEF0A8D4DC1FDFDF421E7F2A3E2FD0
+:104D60003FD39264433C421E6F7C2EF1F304F278F1
+:104D7000C373F09B53C67C5FABEFC40A57A09B384C
+:104D8000A4B78979FEB91C7BFAE914D625CFD7FDE3
+:104D90002E71BC9ED777DEB3BC6F4F781F33CAC568
+:104DA0006EB0FE852018066ABF16F45D907762CA61
+:104DB0003F7747B09E6CB6BAADA0DF53E857F81EF8
+:104DC000F06591E78936E60B032E4EFD61840FFDF9
+:104DD00070DEFBDCEFE6B50A217CC57E78E3E322DA
+:104DE000F23FB859607D84B83AEBE98DB3D0ED2E2F
+:104DF000FB026BFA02FFE5ED824F2509157B427D30
+:104E000075A4AFDC737DF5EFD655FA3D53A2DE33C2
+:104E100073B5FACAC77C46BDF3FA7C3FC0A7787861
+:104E200057BD5F0806A88EFA38B880DAD1AD2D25B7
+:104E3000FD40FE4BC2C927C6A2FF385C744F7221E9
+:104E400058472F013F6E1B716D06E8E755BBCB8DB0
+:104E500071E3E3603D3DEFC48B86CF5BF71C10FB35
+:104E600031E2DF3B16F8F7D95DF85AA39BF76DDC0A
+:104E7000BE9041F1F7A35ABDFDD0D2517DF0B9BE2D
+:104E8000DFF38F723BEBF29FDFFE8013F3D3033F20
+:104E90004CDB3B1AED9BE272238CE66F12596004E7
+:104EA00063A737F13874D6E67A613AE8EDECE63B71
+:104EB0007B633DF8A0D461F1C1BCBED7CA9D787FA9
+:104EC000F63773D4E9C616F8C32887392462FC1B69
+:104ED0003385D17BC0316133933DF48A9E7032FAC1
+:104EE00082391406FA237C3F88E7F6B564FE9E5E9D
+:104EF0007BEFF7E0AFF87D5AE7FD89768F3056DB20
+:104F0000EFC3B9A95C4FDAF39262FEFCCCE6DD3365
+:104F100070BE735B2537CAFBF15689E65F0475BC2A
+:104F200009707816F086F16BD1EF451F42FADC76F6
+:104F30005E272F02DCE27D71CD5249B1B8BAE2B1F1
+:104F400044E7DB2B507DADE37291122A25BD6BF84F
+:104F5000B4C17FD7E1C8E8C55AD7A03E1271FAAFF5
+:104F6000D6FD8B1197DDC583041CE8FAD2F110C37E
+:104F700027235CEA764F6D1D36BE1F0D50295EA8B3
+:104F8000135801E6058D165660461C98927DE8E799
+:104F9000F536E750BC67BA92C4DB474CEED7B15E3A
+:104FA000BE62922501DA13B91EB2C323A26F12D2D8
+:104FB000527A94EE07C4129362C2F3AED14AF12240
+:104FC00031DE3C9ECBE3703F041BB43FCE75532BC8
+:104FD000B13ACA1FF416369885F949794AEA673218
+:104FE000B03CBD75CA4C33ECAF7C6CEAF21CC82CEB
+:104FF000376F9D3113DFEB968F487DD90BF4F3B9F2
+:10500000659CBE39B54802BAA1E18E991381FFD5DE
+:105010005CE5C9DCA2D83AFABCF0FC7BB940BFDE43
+:1050200027B009DB5A8B7D2DC6FB4B42C712931864
+:10503000E37F4760275E1562745462D9984FFF186A
+:10504000DF7915F5DC9EC9555A72BB795EC5D86A01
+:10505000D46395FA9B6398AFC1CF6F03BCDDA1E128
+:10506000ADCA660F232ED85AE942272EBC18975C8A
+:1050700066F4EF199AB9EF30870FE0F841ACC97DBB
+:10508000DA46A9E0E6EB693DC779704C765A9F0F86
+:10509000F6774982FD825D05056C0D2E2580922BE9
+:1050A00020BE097B7FF339CEDBA8B26812D9A1C23A
+:1050B0008D71516001D375686B52000FA0A7652FE9
+:1050C0005F3C8CF05FA8E75399FCFB8CE51A1EEF60
+:1050D0008828DF6F01A1CE04597A2ED8FA223BF836
+:1050E000B119D63D670AFC06F55D6D7A2B7B998C6C
+:1050F0007EDBE8C4FCE5E2CF45DF741857ADE5ED93
+:10510000EC9A18BE0D9EB77B066D591F87A3482EDB
+:10511000CF172E78C2D92B307E7878DDC9AE1DCA64
+:105120005E01FC53BC538BF05C7A9A29FF931BF70A
+:105130007E7186B9FBEF2FDEBC89E73B6C2B3F5FAE
+:10514000AD66A63A52A9654ED0C75490A518680915
+:105150006891DEC787687DE473629E223F90C9DF55
+:10516000D7303FFAA36E47DD3E5DEC0622637E6ECC
+:10517000B23109FD6510DBEC46FFD6ED3749B4537B
+:10518000BC59F632BF8F5B26449BD2907E09CE4B32
+:10519000D497E6975DCFCD6D1634C582CD0F507C88
+:1051A000D2E3920CFF217EFE53F792D7F57373186A
+:1051B0001B86B8FAB27C478F4B601F4B5EC6D7B0D8
+:1051C0000FAA08F63B5F5B7B9258219B512F193643
+:1051D0001FC6E565CFE5D079C79A9E64F17C6C73F4
+:1051E0001AE1738D47243B96B5F563323C5AD826B5
+:1051F0003019CEB9E96D69443BAFF625BAEC277D8D
+:105200002660FEDFF9DEF22703893EF7C29B230307
+:10521000FC7EC586F3FB992E47612BE64397ED2074
+:1052200007D8C16F5F4BF7857ED659C708D705A44D
+:105230000125E84F8AA472BBD81AC8AFB57D2D737B
+:10524000733B2E3BCACFDD65E3F9FB3DB33AC8851E
+:105250007890DA451602FA9B47C5A230B0366A71DB
+:10526000D99A6962729C3D92E46426C7D56F4C5509
+:10527000225827CDD6709252906AE87F5C08482861
+:10528000D76CFB3CC28DC3779361BE4876693BE91E
+:1052900023C0F35B1D4F4CBC6046393F1B27B03425
+:1052A000C0C53767437FDCBCD2B84F260AD41AF397
+:1052B00062D0CBA91BE1696A9E86A7416C10E129E7
+:1052C000413FE01F947F5E86731CD326C82EBE3FED
+:1052D0000EE859ED120BC9946F92FF5C5652E8FE2E
+:1052E0007EB5A6271D77FE81CCA1C0BCAE62A3DE31
+:1052F0007A2946BDA54D31EA29C36FD44B9FD95EAB
+:10530000437FDFC0370CFDFD160C37D05975630C99
+:10531000FC03EA2718688F7ABB813F67ED4C039D39
+:10532000D77C8F817FE0A62A43FFA0D02243FFE0F5
+:10533000EDCB0CF490D6C70CFC37B7AD32F40F0BA5
+:10534000AF37F48F687FD24017459E35F08F3AB65D
+:10535000C5D03F3AFAA2A17FECD95D06FAD68E5F9E
+:105360001BF86FBB7AD0408F676F1AF84B6CEF1A3F
+:10537000E849EEF70CFC93333F34F44F953F32F499
+:105380004F2BF8D44097F9FE61E07FF6A6C0268C3B
+:105390003FB34D1B8EAB0CE3B3FCDD7180E7BBD29A
+:1053A000CDBE30327DCDBA2D94A7E5691A6E3F632C
+:1053B000F6FB4DDE2F8F83AB312FC8405C4F6778F3
+:1053C000DF7BB955205CF7743EBB20DF35C7EDA30A
+:1053D000976283023C46A74D711BE80C7FA681BFF4
+:1053E000CF6CD9D0DF375060E8EFB7C067A0B3EA21
+:1053F0008A0DFC03EA1503ED51A718F873D6FA0DD0
+:10540000745EF36C03FFC04D0143FFA0D00243FF65
+:10541000E0ED75067A486BBD81FFE636D5D03F2CAE
+:10542000BCD6D03FA2BDD94017453619F8471D0B51
+:1054300019FA4747B71BFAC79E6D35D0B776B4192E
+:10544000F86FBB1A36D0E3D951037F89ED1D033DB8
+:10545000C9FD6703FFE4CC9386FEA9F239437FF5CB
+:1054600047003FCC9F5F15E8FDD7B4824F0CFD523B
+:105470003AE4E9783FCD927DA2D0354FD7F3B732E9
+:10548000DFE786751E31D5D17771574C3CAFB3E459
+:105490007B097790BFDB6C1467E1841A42572D0DAE
+:1054A000989FBA54817087A94605DD17A6D37B055E
+:1054B0003A1A65FC0E0DF21B20524D1E0FD60F2915
+:1054C000B13CB4FFF5115F3D0F4DCF67FCBE293FE6
+:1054D00090949F81F5D8CE52AC4F1632750DCA010B
+:1054E000E7AB0BDF33BD9D64BC37D2DBA936D05FA1
+:1054F000DC7A47939AFB0FBF81DF4EB55D20FECE6D
+:1055000079B57B2501F6B72C6EFE27A06E324309D4
+:10551000D91C04FF023F7D32E826FAE96026D1CF8C
+:1055200004656A37050BA87D36E8A3FECDC162A2EB
+:105530009F0F2A44878253A8DD12F4D3F3ADC1D95B
+:1055400044BF100C50BB3DB880DA178375D4BF231D
+:10555000584FF4CF832AB5ADC1B5F47C57B099E864
+:105560003DC14D44FF3218A2B62DB89DDA5F075BEE
+:10557000A97F6FB08DE87DC130D1E1603BD1078359
+:1055800011A20F078F117D2418A5B63D7896DA3742
+:10559000821DD4FF56F02AD117B4FBFEF1F9FC5E50
+:1055A0004ED78B4E333691F0A0E7B533B06E4170D5
+:1055B000144B1F1BEA9684FA21D11EE7B575A40986
+:1055C000706C639E7353FE96C6B87CBF4C5BEFF164
+:1055D00064A62641FC6BC0621EA0D890CA428DF41E
+:1055E0007E95E7DDF3355CB2749E6FCFD3E49AAF5E
+:1055F000F94311E2B380F0F9D6D7A993F43AF95BF5
+:10560000FD03F7113EB34C2ADD13D843F998F78711
+:10561000FA0702F920DFE5BA078FD07A6E5F3E2ED7
+:1056200052660D67DC85F73F4745BA2FED69BD5AD5
+:10563000EDDF2FF4D8BFEF5C7F3C87A67C21D27DC5
+:10564000FADB926336DE8F2CD3F4B22CDF6468076A
+:1056500066F997A29C67F2EA5E7808582A96E6B93E
+:10566000306FBD034B6BF0FB72264BF47D2C535E09
+:10567000C74F26BF09891DD2773195DA9DFD028F6C
+:10568000E17EEE860202E9C0186B7677FB4994A7AB
+:105690004993A74993436F2766F91B71BE53798AD3
+:1056A000419E47B364ED7BF78EE751AEFF7DED93EE
+:1056B000D3424E4CDFFABDC49AF1DAF7534B05FDE5
+:1056C0003D35CF076D4CCF07A9BF6239BF9FB90FDA
+:1056D000EA327C5FF9BE160F2FD749142F2B846452
+:1056E0001FE6D397EB960FC4FD24C6CD0A18678238
+:1056F00071158C7F0F51F17E0AE10BE663F8DEAD88
+:10570000023277ACFFAAB3F47B8FA83D83CBA3E032
+:105710007BD8397BAD2D58A7024EB6104E468BAACA
+:1057200005EAE4B74DA17C41247C580490777E3A89
+:10573000E0A39BBC40C7C112EDDFC7E8CF015F3BD0
+:10574000507F1FFF6A5401BD37D9375A46FD359A3D
+:10575000C01E785FF386C8BF93C02B76FC8EC355FE
+:10576000D842DFF9631281F61AEDA0F721074456FB
+:10577000BFB39BF8F9DB7C5E5FBD9D294D09D1BCB1
+:10578000C6F77C47343B1ED1EC5B76F068D62330FD
+:10579000EF927689EA1D36325AE8EFE6FBA6DAFA8E
+:1057A00037FBE6C6EDA3B6ED24FF2E8A450BE3BF1B
+:1057B00087FA9BB6BE8E27D1E208B4D8E3E5E3F7BB
+:1057C0004580EBB7345C9FC6BC7E865576DD0543CD
+:1057D000A3A09A30B4811FB9E9BB3AFDFBBAB9CC9A
+:1057E0004FED7C8003E2D8AF6EA4FA77116BA5E78A
+:1057F0004B8A1FC846BA96754CCCC4FA656DC3EB8C
+:105800009920DD9DCD1B27E1FDF3CC50E5EBD8962B
+:105810006F154E63DD0D7E711CD78F0A75ABB124F9
+:10582000BD67C7F8D578CF3B43E476606F723B0025
+:105830008E1431B5EBFEC00F4EE178F003925FF7A6
+:10584000838A551C3FFABFC7E8F48BE2C57FED871A
+:10585000EF3ECC1DF45D48ED3E6B2AE26B11569E87
+:10586000627C5EA89FCF3C2F580C7901F29D97B8BF
+:10587000FDCF1F4FA27FF7725E007C0CEF8A7B3D4D
+:10588000CFBC62E2F76E8F88B04511EBE5A7484FB9
+:105890000B6CA1A1A827389FBF401C2EFAB075CD74
+:1058A00030BCEF9B10CAC67C557AD1EA6BF418E283
+:1058B0003CBB9E12BBC77B42E2F76A89F276C95BAA
+:1058C0008A8F7C8EF984D5C2547C9F04FECFFDFE66
+:1058D0000497FF8A2990798BC8F315AAA3FBFBA92B
+:1058E000FE67BD6DBEF542D7F59BB475DBFFC9EB16
+:1058F00069358BD1F7388972086EBE6EA23CD664CA
+:105900002E877EEE749587DB4197277FA087DF5334
+:10591000642BB4EF06532F8A5F97C440DE403C2FC0
+:10592000B5FB31BD8E6DF79CA1B8CEAE35F6E7DF85
+:10593000F7867B3A4F2F74D6CFDED879A7DF33B105
+:1059400071DDDF0BFA6D6E09ED3693F928EE0F620B
+:10595000EFEBFAA17BA6FF0732EFAAC6A039000041
+:1059600000000000000000001F8B08000000000085
+:10597000000B7BC8CEC0F0A31E82C539106C6271CB
+:105980002D0B03C37B56D2F5C17005507F3110E754
+:1059900001712610A700713C104701712810BF0249
+:1059A0009AFD14881F00F16D20BE06C41781F80C03
+:1059B000101F47B277291B03C31A36D2EDFF8DE4BF
+:1059C000E70940761910CF20231C46F1F0C0723C45
+:1059D0000C0C5ABC08FE5E5E5479791E047B99203B
+:1059E00065766D05EA070050DE58A18003000000CF
+:1059F00000000000000000001F8B080000000000F5
+:105A0000000BD57D0D7C54C5B5F8DCBD773FB3BB2D
+:105A1000D97C10120870F3014608B8240141B05E29
+:105A20003E8CD1A206B4482DD505F908494822DAA2
+:105A3000CAABBC66490209883628225AD4054141BE
+:105A4000898D7CD8D406FECB4731F6A98D1615ADCD
+:105A5000B641FB14154844119FB57FDF3967E666F0
+:105A6000F7DE6C08D6DAF75EF8F19BCCBD7367CE33
+:105A70009C39E7CCF99A898D6532CB10C6BEC69F9A
+:105A8000CB18BB59668C8D8994A3EFBCAEACA90032
+:105A90007EFF9BCDBF558DB4D3CB214CA2768CA578
+:105AA000323696B1CB1CF02BB49BF2FC893F5D944F
+:105AB000CCD87E26333B3C0A2B5392AE867EF67FB3
+:105AC000C5FCF8DEF2BC3BBDC38DDF05194B61ECB4
+:105AD0007B8C7F17CE50D37DB95861167CAE39E8E8
+:105AE00077E8276B63157C7FE60B377D6F86432F46
+:105AF000D957161616DF7C9D89FD2A9F75E4887A92
+:105B00000683C19980379DC6D5E13DF4CE0704EFE9
+:105B10000105E055638CEF00F89323F0EF67D7C5DC
+:105B2000B35C0EBF363602FF378587E6DF8FB1FAEA
+:105B30006AF5FBD956C6EEAE66DFCF1ECAD85DD574
+:105B40000EAAAFA8F651BDB63A95EAF50A7C0278DE
+:105B5000A8DFC64241F8DE5B00EDF5FEE0BF3BD7B3
+:105B600061A8DB92E17B47A4AEB8530D7547BA6AD2
+:105B7000A80338475261DE23F823181F7060C7F16D
+:105B80001D4CBB00DF0F25BC3805DE6A3DC36EC867
+:105B900004BC34BC22332419ABAACD42F886BA6DBA
+:105BA0006A08E01BE15E308D79615C6F8031685777
+:105BB000FB2063F7C2F3E1EEC20FF1F913D07F03CC
+:105BC000F42B7B1B8EDAE1FDAA0C9B2A235E762840
+:105BD000EF229E1CF00FF196B391D723F332D687B4
+:105BE00033A8EBF380EF7F9FB0FEA80470D466DB90
+:105BF00054BB1419A77B5DFAE87FD8BA73F73F54FA
+:105C00002D9E8C74AAF73B8C056A7CEEFFBDFD8E41
+:105C100000DC26E545FAD5C7E9B35F58FE62F876A1
+:105C2000D846160A4B3DC719AAFA8B82B8DE1B1557
+:105C300016CAE0CF93811F860A7EA84F9FE10AB85B
+:105C40007BC2C3A2C7C98CACCB50D536C7320ACAF7
+:105C5000EC996512D0075B17F55D262750E4975F36
+:105C600054FB881EEFAECEA1726BB54F433EB9FB1D
+:105C7000EFF2ACE6DC9E7CF8579453F0DD3D5646DF
+:105C80007418DCCE425B25ECAFEAE81CA8AF199D86
+:105C900092B75A25A02D28C774FA5E23A944DF4184
+:105CA000A06F947F66FEB8DB5A7C15D2FBAAD11692
+:105CB000A906F19CCDE97DA835ECC882E76BD665D5
+:105CC0008E0688D91AFFAB1D38EED0A1C388BE87D7
+:105CD0006773FAFFFD98F50E9483DDF35F9AA26572
+:105CE0002731168FEBE38EAC97EF3CE9C037310AD2
+:105CF0005F31E8401FE79FCD0FDF1D7D359E93BECE
+:105D0000D6F8333FB4C3FBADC0E7B2D413AEC42161
+:105D1000E1D4E2DC9EF436341BE80CD7C97F6E3A3E
+:105D200033976BAB43EC3D187C7D752AD1DDBA6AA5
+:105D300095CAD54887202751D6B0F150473AC4F5C7
+:105D40004A2FA07AAFFB155B4EFB51C2D410433EE5
+:105D5000598FF479093E5FA169B045F5CFD1EB2C9D
+:105D60006C01D9BF0EDF0FA0BA865BD85D925E7F53
+:105D700026A8C1F7FD7278BD507A26589B0DFD39D3
+:105D8000F9F745D2292D981EFDFD5D9A3631D21EB8
+:105D9000EAE1C9D9D1FD41FFB9D1F01CA4F67A7F5F
+:105DA000F3A4635A10EAEB9CBC7D8374F45FD2FFCA
+:105DB0006AA93115379A5552375EA89FD57A3DD8D2
+:105DC000A869B9917132963FAD05A3DFB3A70DEF76
+:105DD000C72E6F0C06016F0FB0E22C09D637715633
+:105DE000552AA844CC393BA459D568F838BE23F3CA
+:105DF0005B4FF0BAB2F9FB5CE98F5A6DD4FA4C9262
+:105E00005E0E22FCBA7E63E5A4057A4FFA6D2F027E
+:105E1000BD5BFBDBFCA467A443250DC69B1A642A6B
+:105E2000C06151830CE5815555DE8FE6039DFE0070
+:105E3000CE71046771D5AC5EE00C46C3A9C3D1171F
+:105E4000DC3A1CBDD3291FDF4C4F936F1CF78789A9
+:105E500040E2CE76AB1FF53C54995822FCF2D57D3A
+:105E60009A025DA6DC04B85769DD66B1AC9EFDF60A
+:105E70009F358085A2E6F9CF5ED72CAC8F21BCDDA3
+:105E80002C8D89AC2FD4E744E3719C6867A63F7DD5
+:105E90007E0E9C9F1A3DBF5A4D2988CC8F298DA913
+:105EA000C59EBEE7B7CE593CABD8DDB3DDEF25AE1E
+:105EB000474F9E31EE5AC6C72359928CE3E545C63B
+:105EC0004B9EA98F178A395EBFE2EF169F667ED47C
+:105ED000E17522BC19D1F0F2F5D7E15D6D05BE8DFB
+:105EE000B1FEDF35BCE7CB7F2E90BF2A7C6FC901A6
+:105EF000FECBED9DFFFED9FD25E3AF404F9F2A2C41
+:105F00007C19E0F1F6E98E50508AC8B97F35BE524F
+:105F1000F015ACDFED2FDD72EC320B5680AE47464C
+:105F2000C6AF905482BB37FAEE6D3E8C850CFDFCFB
+:105F30004FCDA737BC7ED772E87CE56BCDEB2E6EDC
+:105F4000DF65B310F27F7DDBE5F10CBEAF7F714AF8
+:105F50007F84C3DE308269F98CDD8F9F805E512F94
+:105F6000F45D767DDE79E919ABAB995607FACB1E65
+:105F70006F15E945F512A3EFD780DE16023DA6E0C6
+:105F8000952D8E396ED4ABEEA5B2DECA488F297836
+:105F9000E5906F0A4CC135347134DA79F54EFDF96C
+:105FA00091A22C787E57363C07D2A8F7F0FEE07914
+:105FB00031B68F1BCA9FF706571CA84D75517877CD
+:105FC000DA428158F2F17B160BE1E75ED4BBECA814
+:105FD000F7AB543A5D8D01243AD7609BBA39A3E7F9
+:105FE00077B32C5CEF5F3BF4D9306E73AB84FE76F5
+:105FF000E0F2C7892F5DD98D9A05BFF773D7C0BD71
+:1060000026FDCA9DABD753A529B067BA4CF5BBF5A1
+:106010007D37A84E427DCD2BF49D4935974EAA8DF4
+:106020007ECF2E9A84FBAEFEFEA69A31F43ED1516D
+:106030007574228C9F08F2B316594751A52AA4976C
+:10604000EB1363D2CBDA2B1DB342F07EEDE5C33206
+:10605000E6C7B0736015699DF57A529191AEEF1560
+:10606000FAEADD427F4D451E8F926B4EDEB45BAE89
+:10607000392FE072CD95A32E47BA4C2A627ED4B355
+:10608000D702FE0251EBE4CC01F9166577242AC64B
+:10609000797D57F37980693FB4F4EBBD7F337F3D61
+:1060A000C00273B07DA2D8A75C397E2990DBF7FCD3
+:1060B000CDF3ED6DDEDF17F884712A628DF3AFC288
+:1060C0004BA21BC629F8E78FE3C271A2FD45E78901
+:1060D00077D84784DF8DC9B80F98ED2A57814F6272
+:1060E00016AAB6A3FD9D84AF00EF1ED658340CF857
+:1060F0003AA978E5AD68AF79DEBEF243360AEA1D0B
+:1061000073A66159979BD73619DAC5FB7DD30B89E6
+:106110004E19E1791576467CB768F924981FE1009D
+:10612000F8EE51CB4D9382B99CBD71BD7F22E682C2
+:106130009AB7A2EFEB99B1E66163618E5FE96B7B81
+:10614000CFEF7B9BBF35F29DF0F72D213F695FDFDD
+:10615000B16936F21B06E11FDAA309A67EE2355BC0
+:10616000C4AFC8104F517578FF42375FDFFA2F195F
+:10617000CFC7EE75A8A807655B7C68A7C7335F0229
+:10618000EA7FAEA9A00880BCF02577052D6ADFEB79
+:106190005207A605ED674077D3A3F4DB3F5BB87EDB
+:1061A0009C3C636AC60AE8F74C01F70327F9B8DF9D
+:1061B000C13C9FBB603F0BDBA3EAB99B897F6B812E
+:1061C0009E32812F82B916F267AFCADEE98BE66B89
+:1061D000264B026F66FA60AA027894057DC8D9162C
+:1061E000CD39EADBD387FC0FD247DCB4A8EFD83730
+:1061F0005F2F8FFCCDE8E3DB8EA7AF6B4FBE5A2E2F
+:10620000D6759E03F59B95A933E263C9D9DED7F510
+:106210005E5A57B067B5508CFE13BBD733D8B34C1A
+:1062200011EB493FB719D64BEE3F76D6A673AD5B5F
+:10623000B2111F7ABFCEA5B2FA57145E8A8FFCE462
+:106240000ED1DF2AF5DE20EA2967706F077CC88D42
+:10625000A3C3B89FB26CE6DFCA9B901EE254B5D0D0
+:106260006AAE2FD3BAE8F0D9D22D86F194649701A3
+:10627000DF6C1668D951F03B97DA080E078E07E3FA
+:10628000C83EE85042FF3F0B3BBDD423F587437D1A
+:106290009D85F53B0D74509F9E1773BF53C4BAA2E2
+:1062A000B9CAE9F5CEF3932FE6F1AE37C27BDEDF54
+:1062B000B915F5FD283F5DEFDF29EC7D1D5F80C43A
+:1062C0001F77D33B5FA79556D622C5833C489DC90F
+:1062D000022AD4F115EC630D588E473ACCF3915E47
+:1062E000B04D52104E626915FFF3FD6E382AB5406D
+:1062F000B7164780F024BB3546EDD5F3DB0FCF5AF8
+:10630000B99E9C2C3143FB65B28DDE2BAC98A1BDB0
+:106310007CF69D2B52A95F0D1E8D8DC061EE77B866
+:106320001C58268F41B2E3F0E007E81F601D39E4F6
+:10633000CF4E13383B3B7F06D913BDC1F7A089BFB1
+:106340001E14F6012B2EE8635E9C8FCFC298EDD809
+:106350005E515D380E3B9E437CA08AF1370733E9DE
+:10636000F9E68673F3F92F110ED04F1FAD7650F971
+:1063700058B58F4AFDFD63C2EED922713B447FFEC2
+:10638000B9CCED845699EF179B1D8D4EF2431F7CBF
+:10639000F0CA61C05F038EC87E27E02F6B913F314A
+:1063A00010435EE865F61A23BF3179F639E15DFAEC
+:1063B000F6A4E987A2F8B149F624BF1F07BF5CCC59
+:1063C0002E46FAEBEBFBB3D5DAF44343BF3D5EB6A2
+:1063D000083BF4F3DA9797939E13BE8CF87380A072
+:1063E0009B01E55C1EA8752CA422FF7EF5358BA6CB
+:1063F0000FD8A92DE84F1F58C2D843D07EF33C8B4D
+:1064000086726BE05A5BC842FCAEAEC67ADA11996E
+:10641000ADA6BAE69E13E58F4F93DF5E0E14CC86D1
+:106420000AFD4CF7ABEBFEFF4141637C62208BF22F
+:10643000CB437F6942BF4B33F9F1BFED7AFCE57F77
+:10644000683D1E53FC2E5FD4F759122B8EB50F9E5C
+:1064500011FB54D6DD5BB83D52E266EF45C52BB665
+:1064600048FE44DC0C1E5DB373BF0DE35125CC3FE9
+:1064700014F09D5EE5B344C3A72871D48F9569E1FC
+:106480000BA0CB15736676EC45B9359119E4580C21
+:10649000F9A128F85D32971F8FAD99C1CBAF647217
+:1064A000EAA4055908E35B53E755EDB7A22828672E
+:1064B000E4EF4D2B094A08CF802AE65755A22BA2BC
+:1064C000AFB4D92CA4F178CD9154A08FC182BA0673
+:1064D000235DE0FEB3D418171A5865A48BB4126379
+:1064E0001CA83FD2057CD7DF442FE67E06A87E8A13
+:1064F000C765042D3C5E34CB18D749635D1F3E81D0
+:10650000F01D72FBC3384E9D715C73FF0A0B5CA0DB
+:10651000801CD9F3F3896002C3AE1C9C9C8478D99B
+:10652000EC288E27B982C1AB187E971EF4AAEB1D0A
+:10653000BDB48FC8D1A0C1BF662E1B86A6DC36179E
+:106540005AADF204188D1FCC20F96E15F1CA8319CB
+:106550003F75A05FA33E398FF213F6631DFD38EA45
+:10656000B0FED172DF8A7EA4A4487D85885799C782
+:106570002B54385DBECFB442C4C3687B3015E9D913
+:10658000AEA6E4231CF654D0BB627C374E71717BFF
+:10659000CFA77C698CABB97DEF8BE029F16172E20A
+:1065A00079E1235F09FC10C70F4E067302E93F91A2
+:1065B000856A717DAB1AF93E17697713D231B40B36
+:1065C00062FCBFBB5D00DA8D34B4BB45F4A719DAB9
+:1065D00015F7685722FA638671B51EE32E16ED484B
+:1065E000AFEB6EE7EFD1DF12312EE983DDEDD41E84
+:1065F000FDDDA1C36768E7EBD16E990E9F615C6614
+:106600001CB7FBFD705BA896F4CB62F2C71EE8577F
+:1066100048F472A85F6111C6C16F7BC1CA65C436F8
+:106620009EE7210BBADA2FDAD5B9395DD556B371A9
+:10663000E5201F1B44BE4AAD7BAE2310F55C5F3FD7
+:1066400078EE8BFD7C8983EC31F15C6970925F138D
+:106650009E933D56F777596C5A3F9B8C71CD0674CB
+:1066600054613D78758D960DFC9EA618EAABD2F963
+:10667000FBAFEBAEAE09A2A34F29A6F808D0E7F70F
+:1066800073A3F8B07BFC7F19FCDC7F1C81FF4735CE
+:106690009A120D3FAFEBF0EB75E720FE5EB6CE9E93
+:1066A0008CF35921F6F5CF946535E44FFE5F3BBF7F
+:1066B00045A6F55964581FBDAECFCF6A2DFD3F36B4
+:1066C000BF3B4CF3BBC334BF3B0CF3B35B974E0EE5
+:1066D000669FFFFCCCED565B8B49DEAEE8F7782A6F
+:1066E000C2B542F8A79D56AD6639C61DFA75EBDBFB
+:1066F00024DF4733ED6F2837FAFA6EA3A2927C7637
+:106700007A2C3C68D3CF161A9AC1E19A0172A1453E
+:10671000F171F92DE03C62AA7799EAF0CB97B86F56
+:10672000FA986E4F9AE47C1FFB5A7D06DF4F1A3CA5
+:106730009A44792E625FB3E9FBDAA099B48FAD4831
+:10674000CD23FB65FFA005248F56A60FEBCFF3F0FA
+:1067500052495ED9C55EF34035CF5BBB5FE407AD00
+:1067600048CFA376F7EBF19250BA61DF3CF0830596
+:106770004519201F4F1FE1F98AABADDC7EA8AF663B
+:106780001ACFC37350B90FFA0D408356D0F7B07CBF
+:106790000EF43D2C5BAA53A97CB65AA572278C8BAC
+:1067A000E5AFAAFD5436558FA352D7171F14FAE24E
+:1067B000F7D22DB47F3E56CDC62BD0FFA66A0795E3
+:1067C0008F56FBC62B40970F57A752795A9A31CE56
+:1067D0004AFED38EDA7858AF3DAF6653BED2C4744A
+:1067E00085FC1E4C09CBF10591E73A5E4F4B932F88
+:1067F000B502DE2F512DBC9D2354EB8DDD6E32F69C
+:106800003F4E55081EE60ECADEE498EDAEC0766334
+:106810009339DCCC17A8F5C4EE6F1A8E9B972CE049
+:106820004B566BDDB1FB9B8EED2E4A15F0A5761D08
+:10683000888BDD6E268E3B3255C097DE3E392EF6B4
+:10684000B83FC2FEFA2736521CE932B477A03F7B2C
+:10685000BABA897C16A2DDE64155CC0274DB3FA9A9
+:10686000B10ADB5D5A55CC32A1CC4C296616A07F0B
+:106870007B32BC077852453F13E6F1F79BF1BD2709
+:10688000EABDF87E7C09BC877A667FE37B7D3C7B32
+:1068900023D3E54998813CB0AF61DD793D584FB1D4
+:1068A000F0FA9DD60393296E69E3ED1FC13AF463B4
+:1068B000AF337E9FE2E2F57BF4F65EFEFDD3A27D70
+:1068C000FF443E6FE78D8E10C6C51EFDF79FA6CD17
+:1068D000CD8DCC77C8CF975E38376A7E8FFE7C35FA
+:1068E000BDD7E733A47A0DBDEF8D5F53675B981674
+:1068F00025B7521A73499F1C6DAF22B9337AC8CCA1
+:10690000F01C58176B31876BDF8A553535D9045722
+:1069100090F205045C0FFFC408D7A09F1AE17AF833
+:10692000A746B806DD716EB8565BB95CEB0D3E1834
+:106930005F8B1E3FB4DC38BE5A631C3F54631C5F40
+:10694000ADFDD6E387A3D7E5917F338E3FF867C6C9
+:10695000F11FF99971FCC1777EBBF1FF59FAB8D7E5
+:106960001AF80FABD0C7E568BDB32A68D03BA15D6C
+:10697000BB681794A3F5D840D0A0C742BBD7443B0F
+:10698000CDD0AEB847BBB7443B661857EB31EE5F8E
+:1069900074F82CD1FDF97BF4F757ABB0172CD1FD6F
+:1069A000A93DFAFB5087CFD0CED7A3DD29D11F3325
+:1069B0008CCB8CE3C24F0EE6F3DCC15C7EF4F72E89
+:1069C0009DDA40F1AFFE2C20A1DFCF97C4461FC255
+:1069D0007D398BE7DD27142E1D82FB784382D1DFC2
+:1069E000D5CFC6F729C52653BFBE38564579878E01
+:1069F00060DAF4A87C8B32D1AEFBBD3B98765DD4D7
+:106A0000FB14F17D83885727AD1C538B72C537105B
+:106A1000DAC7A0B7541BB70BF5F72CD9DFAE01BC12
+:106A20001B7E3C63CC6A163DAE95B71B22C64D8FCC
+:106A30000D5743061FB714C7CDC5E7BA7E114C23C7
+:106A4000BCF978A93F5FEFF9A9F457C04BFD548713
+:106A5000458E87F76BB89F53F7B727D8AA1C98B70E
+:106A60005B3BC8C236AB94877C4E3F4E5DB5D1EFE1
+:106A7000A9F88A35B4F70694F8F264D6FB770F15B7
+:106A8000598A62C51D0AC4BCEA4A263766C3F8ECB7
+:106A900090D17F0B84CDA2F36186CB81025B2CFF6A
+:106AA0006D1DF79FEA7A50C28073FB6F6B857ED1B4
+:106AB0003D0FE828D6FACD12F0B10D1C6F8A8EB7C3
+:106AC000C41964DF25D45CE9F0C5F86E95A97F2769
+:106AD0009BA161BBB8E446662179C2CF4DE87A55E7
+:106AE0009D6F33DF87D280A6300E94BC338CFC734D
+:106AF000A6809FA35052434189EC513E4F542BF145
+:106B0000274E0907D1DF386083C2C220B7D65A02A8
+:106B1000B36C185FC96E24FF98E2D324C4D3596BB9
+:106B2000E84A3A5700EAE266A927BCB7D8B83FF866
+:106B30002175C61F3262AC63894D35C4B7077C61CD
+:106B400063E1FCDEDB47DA71B8BAE93415E8732497
+:106B5000C90DA2D34A592BB7119FA7FBC8EFA8CBE9
+:106B6000579DFF459C7BEE38267ED41BFE04F358D0
+:106B7000D46665C83FEC2B681D15FF5924FC5F7374
+:106B8000855F751E2BF6E2CB93CC52847C7592BD4B
+:106B9000EACD8F5AAF069B8DC3D56025FF961ED7D1
+:106BA0009DDF6835F8BB166E30D617B019292897C7
+:106BB00016ACB3B210E07391C91FB614E70BF02FF7
+:106BC00064552B7DDCAE207D7AAE8F2949B0752CC3
+:106BD000FEF5C363E740FD17887718FF23A017353C
+:106BE0008AAF4ADD211BE647BDB73B7FE60486DF5F
+:106BF00087560E40799AC0629E2FBAA5C1085F5F82
+:106C0000F09BE165ACE69C7028DBA498FEAB877531
+:106C1000FE10EBB5D4E11DC540CE9C75F2B2DB9FF2
+:106C2000F26727C9F7BD4847B4DE5517F1FDA0EA62
+:106C3000622CFBFAEE80A03FF3778B1D1D36E48FAC
+:106C40004AA5AA48B244E24D766B401B08DF595B67
+:106C50002685073243BB86F36CD726659E57BB2239
+:106C6000CB39FA3B25E4E5F33B1EB3A15D76F2C9CF
+:106C700063D7201F96FD56660E68776A878785C999
+:106C80002E09D9509E94EE9663C667290300F056EC
+:106C9000F62B0FC989D29DF6D034F8BEF4D9F74649
+:106CA00031C0C3A99AAEC303711F7D52E271D26095
+:106CB000C728DCB74A157673718CFE3A04DD9DF85F
+:106CC0004D1CE5B548DBF6DF44FD36DF60B547C94E
+:106CD0008737705FE2EDB87F6DBB141A1A437EE808
+:106CE00071AD13DB250E5F8B35E444F8B66DB2054C
+:106CF000008ECA6D9F101D4DF9559317F150D92282
+:106D00001BFCBE95DBE4B07D1495C7B0C478890444
+:106D10007C5DC1B87CACD8BD98FCE115CD777D22F7
+:106D20007BF17B233D035EFC61C4EB1BB27F1AD673
+:106D3000773DE15501551FB56FF5225EA1DF39B6EC
+:106D4000788CEB1AFDD8D8FF17893DFB03CBDD8685
+:106D5000F455D9BC8A8F67E2978FF097B49EF113F0
+:106D6000BBDD934C7AA21E3FD996745E7A6259D3EA
+:106D700099478230DE899D1F3F1204B8CBFFFFA7E1
+:106D80008FDC897ACD3EA70FF9BDF2C9D7BC2C6A3A
+:106D90001FCCB073BE3BB5FD89C71F023E39F5A6B7
+:106DA0009DF2F24EEDFD6030E6D39E7AE6BF52547E
+:106DB000687FFBDECBC99EBF7DCF94FEE7DA0F91E3
+:106DC0004E43F668B842D4BFDA22A1B20586BC2889
+:106DD0004DEB7270B7CC9C00E7C9A3F610E63557AF
+:106DE000C2B3A579B84E8B49FE627D19E0B7624700
+:106DF000FD27F2A858780E0EB4A46209EC928AEB33
+:106E00007CDDB597166069F5AB4817AC8BE4A7F944
+:106E1000BBCA23B09E17F5BE7E67D85736CC3FA9B4
+:106E2000DCB18A8F6B5ABF93F8CBF89EEB7799DD74
+:106E300018FF3AC3CA1F7D085FEE4E8A19D7D5E303
+:106E40005F8BF7FCE09C7A932E07FAC26F89C4E14E
+:106E500072DBB56BEDC84F3B9F7AFCA164BEBED31D
+:106E60000021A79ACE0C66401FC7AD5D37A17CEC10
+:106E7000DA6BF7E17E5EBAF70DE2AF537B5EB1A944
+:106E8000241F995B023DE114EBFE6947BDA142E27C
+:106E900095CA2D9EB0DD1B59A78AD0F422D54BCFC1
+:106EA0008FD1F310A7FB8AD0FEEBA518EBB6D29ECC
+:106EB000C9E571A81FE165F1963FD9288E1DB59EE1
+:106EC000D2385CC76385F8BCB775D4E7EFC3F95F08
+:106ED0001CB59E5B38BFF6C697A736D915CC4BD0EC
+:106EE000D7F794C8BFAD0C496FB018FCAAEF6FDF9D
+:106EF000341EBADC440FFA7CFBE2E7BEE7F1CDF0CA
+:106F0000742B26578EE989AF135FC596EF1B857CDE
+:106F1000A860554503B27AEE4F0A188C033322F06D
+:106F20009EC05800D0D98927653A2FBBB2F920C935
+:106F300069B35CA8E8454F6EB2733BA7A265FF2812
+:106F4000945F270EFC86E8B062C7311BDA4787B72B
+:106F5000EDB275E446E81EE57F741EE689A7F78F5B
+:106F600022398DFDC7589FE744FF95ADC6FE2B77AC
+:106F70007C62E8BF2CD86C23BF681FE37CA4683711
+:106F8000E07C3F6AB732CCBBFFA8592E8AA5DF3C14
+:106F90006AB71AF3613C638FA25F514EB4A928EF20
+:106FA000EA966B6F04715F7CC5CACF3D2ADA51CC7B
+:106FB0000BA84DB0A968AFD6796632354A6E379ABC
+:106FC000F0E94BF64DC2B89A6F6A7141B4FDA4C3A3
+:106FD0009FA0590CF0DFEE29EA8FE79FD00E53F106
+:106FE0009CB1E227BFB2EC2D2CC2F9C83E8BCF1961
+:106FF000737FE6FD59DDC56437597D96EE5C13EC71
+:1070000077F4949923D075A630D5A0E7AF9DCAE355
+:10701000B8FAFCD70E621B19C8DDB552571BE6B390
+:1070200007AFE4F9814CD8E95EB4D3337AEA734C04
+:10703000D354943F247E787BA6459D0FB903C0B1FD
+:10704000601E8FC54FCAFC1DB246793D361C370BFA
+:10705000EDA7103D8F6361AA5B1C5CFE7858153D5F
+:107060008F671D8DD9D0F9DBF6E2B32837EF2D4AB3
+:107070009438DC61CADB4810E358E2D2D3CEC5FFB6
+:107080006CAA7222DAEF63671BC92E41B7E3D749B6
+:10709000113CE879717ABF6B9D1325DC6F707E031C
+:1070A000F15C8F3837EFEB9EAF46F57E7ADD340E1C
+:1070B000B6F48D155B2CB162405264BC2DA091FCDE
+:1070C0001C03583395E9AC9DCA44874F5208BEB79C
+:1070D000C92F6561EFB2AFE34CF09D873E7ED6A22B
+:1070E000BD1980B2D62A9EBFE3096D85FABA04663F
+:1070F000381F9CE9E0F264ACC3A2E72707A2EDAE1B
+:107100005A564E737726F3632CFA773F7004863B0A
+:10711000A2E219B2BB9DE77F09FB57B7D72F97971C
+:10712000F1F87B2AB7AB7B5B9F15D5C506BBDA5C54
+:1071300036F673CCD9C4087EEEA7921CFCFCB2C60E
+:10714000545F34FD61AECDD8E8BC464D23FB5EBC38
+:10715000B7C2F4F0A51DF128F7A4BF62A4BF7E4812
+:107160007F1DA2932EF25354CA81229C6F6A76959A
+:10717000C49F0724EECFD2649C6F8AE8DF12579E2B
+:1071800076AEBC2A360BE8232AAF659DB01F158565
+:1071900029AE3C8467A35877335D1AF354757DCDCF
+:1071A0002D6A76912FF7BB8257E93C8A92ECA6FCB8
+:1071B000147741DDAD789E5C61553E949F6E3DFF36
+:1071C000C4CFF30A75BBD89963CCE7B49BF257AD33
+:1071D000C2FEEE91CF2DF6DD7BF0410C7DD8BCEFE9
+:1071E00056394C7AB4F89E8D8B9D37A8EB61E74BEE
+:1071F000F7663BB2DCD17E9806F769946FA9087FE9
+:10720000C3A4EB7DE407EFDC21F1736B263AEADCE3
+:10721000193F0AE521F22FDE6F11279E4B3BF6EF57
+:1072200047BDA9CECBB484449273AA0C785F298D54
+:107230007648502EDEFDC9CBBF45FF7AABCC706BD4
+:10724000EE84B9B5E3FC142D01172B8EAD31ACEFF4
+:10725000379D4FCFB822E7B7253E9DDFDCF4FDE92F
+:107260001D129D9F92D98807F01C44659B9585E06F
+:10727000FD69C6FB3FBD91EB030B5F805160FD379D
+:1072800088F1715F8ADE3F928A5C4C8DCEE3096A99
+:10729000ED78FE7F9EC047BFE244C3FB8FE716B583
+:1072A000917F26B080F44F3C5716DD5F99BCEC020D
+:1072B0001C8F093F860AFF90FEF4F99FB5046C7C91
+:1072C0009F288E0F933E03F62FDA0D2189F295CC7D
+:1072D000FE8E8A1689F6A745B03FE1BD028B422695
+:1072E000FBD19447A7E3DB4C97071D421F7433770C
+:1072F0002F78F587797C94F86AC90B3C2F6C4993F9
+:1073000014A27CE68E0BE219E15926BFD107AC6AC4
+:107310003DEC1C11FA35E1CD9E6AC4B35335E23918
+:107320002EC788578FDF8847339EE3C7651ADA97E1
+:10733000C9E536223281E71CF88778063948F3A878
+:10734000807984D59EF82C695DBB12FD1B7DE2D14E
+:1073500084BF8F4DF83BC35AF7F3B720525388B51B
+:10736000797EA41226FE31F39B8EA7745FFB247AEC
+:10737000E6F790BF38557422CDE3DF0D703473E625
+:10738000C9F313BFE979C271DDFBE57BEC6B286FB4
+:107390009B7EE818C6D3CDFCB5114BE0EBE66A87BF
+:1073A0006F1E8CF77435F3CDB362BCDA47658C7D04
+:1073B00094FA077AA4FDE01E8C4B26235F2BA1CD07
+:1073C000DCE68A9B86E7FC5AAD3EF45BDE93D7751C
+:1073D0000DEAED95F3799EE38F5D7C5FBDD5C5FD2C
+:1073E000B08A8BE737AF2EB6300DEDFB563924A1AE
+:1073F000BFC8A7BD7019EA5DAD5695F6355FD7CB0E
+:107400003FA2F7F93E8CEFA6591A47231CD09EFCE9
+:10741000ED9DADEF796F89D2774EB5DC7721EE3BEC
+:107420000F5A58492C3D3EDBC9C73F95F36E0A926F
+:10743000E3624717D9D1F51D55C5382FDD8EB0ED64
+:10744000E6FEAD8A96E9A44F1E5AC0CF63EE39C15D
+:10745000CF6316CAB3BF3F12EAE35F53B8DC64DA06
+:10746000B43929D484D6711DE64B221FFCD512AA4B
+:1074700021FC34FE11E354B5FFA950BE6C4115BF89
+:107480001FE4B7DEC2362CC76ACDF9C8D7535B13E9
+:1074900026E17999CAB7795EE59876A33F87C9E571
+:1074A00007D10F76E628DF962F3EAA98ED2E19F722
+:1074B000E3F11DC6E713FAA0DBC94EB11F7959CA23
+:1074C00037C98BBDDBA25DE9E4712C3ACFE5576289
+:1074D000DB4F0FBBB87E057891504E7576317F0D2E
+:1074E000E0A973DE009A6FE767FCDC65E75772512D
+:1074F0002CFBE82627A797076D3C6EFBE002776818
+:1075000039FA4D17940E41BBE8F37F0B0C8915A790
+:1075100088D8072CDE427B9E16CFC6215FD4F1733C
+:1075200066AC312DD6F9799D1F74FED0F9226D819C
+:107530002B10CB7FF9AE93DB6F9317E44836A4D7BB
+:107540007D12C5784ED5005CE7C06390D50C4478B9
+:107550002A5B3E25FF82A335B61FFAE7785803E978
+:10756000B626B87C02E0EBA7C0D441E4075B6346D3
+:10757000ACFE836C1DF99BE663923B7EE7E07634BC
+:10758000531AD36678904FA65CB912E07C08F80FC6
+:1075900049FE41AB9FE00E2E668CFCAB0AE7FFF480
+:1075A0006BD8A6D551F6568373D23A5CEF754E1E52
+:1075B000EF480AF82584DBFFF7B35EECBFF30B3B23
+:1075C000ADDF00E1E7D1BFFB958E1F97760FD14B62
+:1075D000493209437FC0EB9B07FBFF452D80EF2815
+:1075E0007A8CAC5B90BE4B0C80EC2BC0F38C163AC3
+:1075F000BF82F616DA13954CFF0992F2A9F31F1E0B
+:1076000036C3735ABABC955AA5B007E46681C31D48
+:10761000467F4A6209CC1BE351CCC1FB6B37EAA31E
+:10762000287951EEA20CA07D5AD83BBA1CD6E5773A
+:107630005D029783756B15CAA7DCA87438D17F9C4F
+:10764000A1A99331B52A515129CF615009469C41D6
+:107650003E663D9CD0ADF74C60EC99BFCB31FD1B35
+:107660001F74E32BF02CE26B545BD701549FFC4E4C
+:107670009684EB5D28F49BF127B93CD2F3FB2B8574
+:10768000BD619647BF013A478131FE52BEEF8D3F43
+:10769000E9F623FD74CBA10585B48FE6B5E61FC4DA
+:1076A000FC9CBCB7393F32217FC07A23BC8C6D0B68
+:1076B000CA880FB3DCE94BDEE8F2C4BCCEA05C772D
+:1076C000D731752EBF0DF82C6AFF36CBA9374C7217
+:1076D000EA0C9BD8FF7235424F794BFD07ED51F410
+:1076E000A3CBA9083D85886ECDE348CCD15DF76575
+:1076F000A17C7951463F48E7241E9F0C221FA1BF61
+:10770000E2B3D09538FF75AD573891EE77B64D712D
+:10771000205B2D49E5E7BD94FDD70799209FE8B888
+:10772000AE953954770EE2C542F8907D508F9AD7C6
+:10773000E946499C7754E3AF8F713F825E2E49E55D
+:10774000E7B976B665C6733B334CEBDE4DF7C20F37
+:10775000A1F3854EEF66FAD6F9A19671BF84AE3FCC
+:10776000C852B3B00B8D7E815ADDCF1174529CF894
+:1077700076A10FD6BA87DD85D7DBD48527FB302EDF
+:1077800071BB2793F2996FEFC7F166C6835E567E91
+:1077900001FA6154DE79A5D2457EADCA2F6C86E729
+:1077A0003A5E7BC3878ED74B10AFD23F8ED7B36282
+:1077B0007DCDF8FD47E79DBE645CCC7373FF57E653
+:1077C0003D81057EDB4176173FB7A1D3972E2FC6AB
+:1077D000DEB6218D88A3DD78AE479723E35AAA0E43
+:1077E000A28A68961317B5B2EB104FE3C30A1DB116
+:1077F000ED4B6E7C86BFA4D1F98B592E8073F4F3C8
+:10780000B3CA76C0A3512A4B9A06408D6A57488E58
+:10781000B1F6F38B4335873F4B41FFA2AE979ADB1E
+:10782000E97AA9BEBFE871A0D5AEC0421C5F6A016B
+:10783000BE81F9D7FAB8BDDBE00C94E2F33880D909
+:1078400085B97639E10C6E9F1AF9B2373E8C33F167
+:107850005933E085CE21C03E3754EA09873E7E96F3
+:107860002B81C309D486FA4BFA58C607ABE0F7D987
+:10787000A58F6201DC87F1F826CEB3C1C5F7935519
+:10788000420FD3CB0667F17284DFAAB0A03DEF1F91
+:10789000875BF70BAE7669D52E18C751A4D13C068D
+:1078A000FA981FF5FA814AB3E4073812CB55A9DBE1
+:1078B00059A3EFDF78EE679A3A89CE9765333A1786
+:1078C0003B10F5A018EBF34B17F7572F76741CC637
+:1078D0009079E5B4AA22EF39E2D391FB06FCC24FBE
+:1078E00065CCC3E8DCFBC6208C4BBEF3EF9F7A303F
+:1078F000EEF417A5CB83701E5FF6470F9E377867AF
+:1079000019B7336E32E9333B053E7D71C5DB117F1C
+:107910003757FF7DACE1FCF8521E47591492D1E86D
+:10792000ECA6EFB26D71E49BD3EB8B9B930C759D32
+:107930004E17DB799E9479FEC785FDB468C726DBB8
+:107940004015C70FFC16C73F2EF4B5E3BB3DE4CF8F
+:10795000D0E199BB63B40DF1F09756BB88C3B75B18
+:1079600039FEB569183F0B88A530C379785F1CF5DF
+:1079700037FF7E99F48B3930D652A0EF40EB22B21C
+:10798000B3CDF398FF8E5AD81FD66FFE2A89F452D2
+:107990006CBF0CE821B0B49EE26CE679CE099AE3A4
+:1079A00099CBC84E37E779CC63EA5D133362E47B49
+:1079B000B4F238F9C23EEC9A775C425F18CB2EC61F
+:1079C0007CF4332CF717B96ADF76CDF16A46495A51
+:1079D0001F553BA83C51EDA372BB4BE5F1EC96FD66
+:1079E0008789BE94F6B1C8EF3BDBDE8BBB518DC8F7
+:1079F000EDEF6DFAF4E02FA19ECFB8FF46F78FCFE1
+:107A000016F8BE4CC8EF85421FC8FFE2DCF27B3699
+:107A1000CE77544F7875B93D1BEF938DC2832EC737
+:107A2000CDF838DD9615477EC638731CF8DBE1A526
+:107A3000B7EF16CBB1F30675FED92EE879DE96E9DD
+:107A40002B07C0F8B57B3F18CCEF036647503EE8E4
+:107A5000F469A63FC6AA6CC8CFDD74D67A37E14771
+:107A6000A70BE0A354117F4C45BBCF4C6F7DE513B2
+:107A70009DB2760C463960A6AF53128B79AF68621F
+:107A80001CF797CF53B542B443617B59C9E3745C8B
+:107A9000FE1C571A0FDF89FCB985F3C7E25F373D3B
+:107AA0008B72A7F457F77B51EE7CA834A6E078E5FB
+:107AB0005B577831CE7D5C097AF1FB0F4372CCBC09
+:107AC000C2057192906BC67C05D610BC06F9F6F320
+:107AD000AD561FFA192AB7D9791C7C37C71BD47940
+:107AE000FC7B77EC7C85D227EE4F51797EAA316FF3
+:107AF000618B95F24FD05F86C3F416C7ED8E0B37BE
+:107B00009F3BBE5DB9FBAE9879277A7E80996E6700
+:107B10009AE815F042764C10E021B7B8885BD76E32
+:107B20007F60D43180EBC496FFF04AB9D17E731EDA
+:107B30001F3FDD7CCBA318E2E98D5E4F09FA8EE88A
+:107B40000DA198790CE5D6B017EDF0F24D56B2EBD9
+:107B5000CA9B64E6C07C9637EDB46F9735FDEEF5B1
+:107B60004B00BEB267ACC9D3F834285F415FA7EEC3
+:107B70003C12B12EA5BB7EC7E3BDAAC82711EB53AB
+:107B8000F6CC7E1BE6C598F138A579BFADC3948FBE
+:107B900040EBD47CAC90CEE56D3F6BC3FDF4C37D70
+:107BA00012EB9FD1F3FB924DBFF3A27C403C515CA2
+:107BB0005EAC57EFF942E16B9E2BA076E487EB6D4C
+:107BC000FD2EC6351A43F4FDF473307EC95B76CAC8
+:107BD000572A79FA36CAEFF940A9E274FEF08A14FE
+:107BE000DC5F4BACC1141F95FC79C9233F21FA5BC4
+:107BF000F8CA4F52F8791E2D8DFB6D8269E4CFD8FB
+:107C0000F8039ADF021620FA2B79582E467FC919FD
+:107C100085153D13834FFE2CF8E483CD760CA2B27C
+:107C20000F84DF32F8AA2CEEFD35C793F8BD2B6721
+:107C3000841DBD2BCEA2E7693BA2EDAACA2DF5EDAE
+:107C4000B83E1F0DD2FAFB28AEAF0405BE24D2C742
+:107C50005FB9BCBF9063745F8CAEE74CC1E7D8BE20
+:107C6000DD4AF7C6447D67B8F7E576313EC0ED9250
+:107C70002E823225B63FD3ED9674F878FE8B4E5F98
+:107C8000BDF1FD169E4FF2D9112E57302F86DEB76B
+:107C90005BC3FD0DF93076C3BD22917C0FABE06B69
+:107CA000E37B8093F255BAF1BB4FA238EB82757635
+:107CB000631E5C37DD98EFBB31E6AF2C34E95B7AAD
+:107CC00069960B6FC699E2681BCF2F7FA5DC1AA2BD
+:107CD000BCA3F237ED643F9437598B111F1FEF3867
+:107CE000F8FA8D40E71F37EB7C6B94AF66BE2DD959
+:107CF0003986C5E2DB8FDD7E16936FE1794CBE7568
+:107D000047E2112AFBEEE4EBC25EE4ABC5DD431FA4
+:107D100088C7BCDC8F9E2C1B427E06135E75B96A39
+:107D200096971BE3D45EF2EAF87E1EC977E4F8D397
+:107D3000E9B1F4A9C5344E37DDEA74A9D36D2F79C2
+:107D40005A663C9ADFB7097964F6670427B31CBC0E
+:107D50005FAFD6C672D0FF1CB4B8FC5B3362E4756B
+:107D6000B0AA0B50CFA87167C4CCCFF5BB7D68C655
+:107D7000326BB22AC78A77FBA75862EAF1F96E71B3
+:107D80003F09D202EA936E8EB73A115F014B90F22F
+:107D9000FEE98C36C297E0257EB2C27346E72AFD23
+:107DA000746EDB1F67F9540515ECDA35430A15F4D8
+:107DB000A7E65B6ECB82FA823579850AACB37F8207
+:107DC000655726D44BD6E4F3FA45967C2B90E6E330
+:107DD000C182C2A9D0BE429FE7BC78837F43B11C59
+:107DE0005B8F7117E5392BAB85FA5DC0D78EBC4828
+:107DF000BC37CECE824EA8C7D9A084FACA8C3FAE7B
+:107E00004423F03E7BE06A37C9A3C92AE2F584CF58
+:107E100041F932B7FFE672CACF2C7373BFF1885DA8
+:107E200013E8FEDDEF60FC1FBBC7F43E7E9D95F7B7
+:107E30007362E7882988D71143F8555F3AFEF31437
+:107E4000959E3B9BF1E829F17F2A9EFFA84DB051FA
+:107E50003F65DDEB757E65ADC86B90E3381DC8F1FD
+:107E600096AA67A05C22D6FF36810FFC417BB973CE
+:107E70006FFFCDFCDEA7AEC1B8BEB27CFACFA8378B
+:107E800076FD38CE8FE757DE72717CDD10BFC63AC3
+:107E90001CEA798EC1B72151BF25EDF80996D77834
+:107EA00002FFCEF1CFC2D8DF8D37C9BC3F7795072F
+:107EB000EF519334AE474B4034B3010FB51A536DB5
+:107EC00059C8A2C67C0B59CEEB0AD3B81EC3B82C36
+:107ED0001DF64158A71BC6F375029CD2BEF8C638E2
+:107EE0005E9F15CAACED50098EBB118ED1F6D02025
+:107EF000B47F6E04B588D3B5D1FED6E3F495FF699F
+:107F0000213BB352526BDD50DFF53623B97CCAE515
+:107F100015F907FC7E19DD2F31FEA5B95370C90A8A
+:107F20005ACA781E87F043E971F433AC55C6C9F4D8
+:107F3000F0539BE4E104B686E4645FF1B1C7DD620F
+:107F40009F19C0067CC3F85893FB3CE263E96E5D61
+:107F50009F17F176B1FF9F7E3193F285140573F27E
+:107F600018B3A932A588E8DFED36C95F9D8E471E9C
+:107F7000F1DD8278197984DDCCEDA55EF2238E33B4
+:107F8000CA6B1EDD9143F91156737EC4510B253C1B
+:107F90008D7D215F457CD689B8F1378DDBEB71FF94
+:107FA0007CFEA8471CFF396F11C541F37DB1E3F892
+:107FB00097C8B329EEC05EE4EBA7C7F1999C2B23C9
+:107FC0009C67C28C25219C478CF7C55C9C1C94291E
+:107FD000ADE66DE3F34BCCE7594CEBFD57F37A9FDD
+:107FE0006F1EC487FC7EB5D16C14E54158451EC494
+:107FF000B32C705F741E848EC7BEF24CCC7925E61C
+:108000003C92B480114F034B861BDE0FAACA33D4B7
+:10801000872CBDC4D03E0336C2E87A56C35586F6D7
+:10802000431B6718EA176CB8D1D0FEC2D05CC3FB03
+:1080300011DB4ACFB9EE239B9718DECB96503EDE7C
+:108040000BA9AFFB452D3F8B4917FABAEB795A982C
+:108050006E84F81D03EBFE5006F98FA6486ACFF533
+:10806000F78783B42F7FD3F5CFF6087DE81BF2BBEB
+:108070001F898DF25AB99ED8697537A05E9C00B0F1
+:10808000A1BC35EB1709ADCFFF17FEDD899EF916B0
+:10809000EA72A4A33B646D3CEEF7FD447E649D450B
+:1080A0009C279DEC207DE01E8BE5E6E87B922FF57A
+:1080B000707BE0520FDF5F7E09FB26EE9303E358EF
+:1080C00090F64F0B8BDC6701F3F52631716FF1A64B
+:1080D0009553D3319ED991A326007F637D5044EE02
+:1080E000DF68576B311E305AE6721CE4FB959E7EAA
+:1080F000B8EF2CB372FD2768453C0F74B0A0378FE2
+:10810000F63D8A6B26B06469492E9A5EDDFB8BFAD8
+:108110003510C3C1D211F16807BD8C906090D6E1D3
+:10812000A2FDFF87BADC2BB990E4DE69B79E37A6C3
+:10813000D279C7D3F3B2E8F99B3701D701FFBC6905
+:1081400033DA457DF9A74A36DDE741FFFF9B39CC9D
+:1081500090675026F056861762E2B993D07FA6202A
+:108160005A3AE7FF6D18025D29B5AF44115DBFE1D2
+:10817000D662CADBDD3D3D88FE3FDDEFACF753D96B
+:108180003A8975DF230CFDDDF006F77FDDF037A3BC
+:108190003FF7671E7EEEE86762BC9950F8006F33C8
+:1081A000613D12B07C7E6221F2033C0F4B50BFB6A2
+:1081B0000D543FA0FBE9810C2BC2F347E67F6D0F06
+:1081C000C0B3C2A3D238D7B3622BC2F5FA4D8B3DF0
+:1081D000D8AEBB3FBD9F8178A613F6E984A03505D4
+:1081E000E8A7EB5289F67518CF81CF8B670F5C81BA
+:1081F0005B873EDEEB2C70F23558EF19CC4FFDEA71
+:10820000FD33E632C8C19D25657F49CA44F967211F
+:10821000FFC792BD76927F9DA5679BD6C3FB9B0748
+:10822000760C42FDE2ADD2BF0D43BCFC7083CC5452
+:1082300058FF475D81B59E28BCBD39EF530FBE077F
+:108240003D61EB7ADCE49FB2D339AFB74A9F1A168F
+:10825000AD57FFD233693DD21D1B777EF19E294F6A
+:108260005E48F6B64E5F8B047D2DD97E01E9834BC7
+:108270003CDDF4C5EB5BB3E83CD15889C5B423F1D0
+:10828000DE0FCC4BDF097485E708F77DC1F3C777B4
+:10829000BD98984FE751596047F4BC76BD7CE30820
+:1082A000F2B71E4D3E2F78912783A85F310EE74B22
+:1082B000823F66B526E50BFDAE05FBBFF1B7DB4F90
+:1082C000FE09F1B3F7A9AD77629B82F3C30713FBF5
+:1082D000985FE001F631B27F3A99CB6F8F61FF3C36
+:1082E00023F4AF3B2C1AD925672DC5227F9DDB21B6
+:1082F000B2C59F8A79DCCDAD721CE2CD8B068B2E88
+:108300005F4027F4E23D8CE2FE7C07D8672384FCC3
+:10831000F9C3DD9F16D671FF8E41AF2B38546AD05A
+:10832000E78AE11FCAFB8B37066AF14EEE5EF5BAAB
+:10833000B085ECE17F54BF7BF71F94F7273D9CFF8E
+:108340009B73B8FC6E0EBB42DC6E60F9A8EF35790A
+:10835000F97E7025E68900FE6DD2A91C07FCFEC9D6
+:10836000DD6756364C84E5CEE6F8C03AFDFD95361D
+:108370004EA7DDFADFA1E1FCEFCB8973C005E25C1B
+:10838000B4199E02E02BBEC9BA0CFA63F8F09774D8
+:10839000CEA52951FDC304D4E7414F41BE772A1D24
+:1083A000B68418F37B16E527D0F7382FDF3F1C2D56
+:1083B0003C0EE75035BAF7CCE9F38D467B496FFFA9
+:1083C000B187EBAD8B0FBF35D806EB74D2F2A21795
+:1083D000E308E57B767AD14C1E1517F07A51AEBED4
+:1083E000F9EA581FE55B6D1A8C766D7398C72746BE
+:1083F0002A2CA8C4B8B7B972433E5DFE5DB121898D
+:10840000CA0BD19F008F2AC37C9EA75A6A63DEDB0A
+:1084100059F9FFF60EC0757BAA1F3F2F35B2357F85
+:1084200021CA3F84C50A72EEC92F46507F43BDDC86
+:108430009E87F1157CCE58C882F71D3D25ECB553BB
+:108440005FC8D44EEF7764CB24D9076B991B6E3C81
+:1084500040F661AB5DC575766EE1F7C1395B9D2471
+:10846000F72AF75DC1EDB8041EF76C7275FD599CD3
+:108470006353314FD2E96B6489D07F938DEF8F17AF
+:108480000203EC74479EEBE3395B1FA0A4764736EA
+:10849000BF57CFA934B24BDDD178F710FC8582BE2F
+:1084A0009A5C610BE6ED74E15D950457044E46E37A
+:1084B000EA705E48FA7C93ADEB7D3C7F49E7EB5474
+:1084C0008483C3C95A2F5051AF70FA78FCD6E95350
+:1084D000FD41A9275C95A340CF057EBBA78645FE3D
+:1084E0003E06E6B1B9227507F044532613F761E55D
+:1084F000D4A37ED15D4781342EF2FD8FBC23EAEBFD
+:1085000026929D1394D1AE87D29388F3E4FC85F72D
+:1085100017F4CBE378403F719C83BFEF6E0FF4EE0E
+:108520004EA47B8DA99D3FDE177795C4BAEF35D554
+:10853000FD4EB74BE1F72F43FF56F8C028156029D1
+:108540007FFE39A2DB324BEBFA912A9E4B0CCCF723
+:10855000C278BF7EDB827F53917DB4DD49E79073A3
+:108560007EB389FCD5E6FEEA8FD6DC8B79D99DBF38
+:108570009154CC03EDB47651DCA8A2F5033AAF7860
+:1085800045CB313AB765890F5462BFE35A964F41E4
+:10859000FC8D678DB5E8DF03794871FAE6542E3F0C
+:1085A0004E1F19B6797914BEEFF70ABBB02B300411
+:1085B000F9A655F0E73ED46FA0DC23F4AC3DFB7F79
+:1085C00098157D0E2BC80E903FAC861DA2FC42FD77
+:1085D000796748A17360235E77DCAC45D1DB2F045B
+:1085E000BFFFC2CBF5A0ECF8C00A84B76CFFBB3666
+:1085F000AF8A79ACCD8351EE36831E76AE7CC64A07
+:1086000013DF74E7B71CE7F772C3BAD6C5C33A3DA8
+:10861000F57ACB70FCBB22003FA3FBAADEB493DC4F
+:10862000DC93C1F96FF96B9F8F42B9F5F9DEB22186
+:1086300088AF3BBC3CEE0F743ED985FCF40C23396B
+:10864000A6F3632EF223809EEBE37E945CA473E496
+:108650003F5B3BDD03DAB587DF0B01744E740F74AB
+:10866000EE43FD22D707744FDF5F40FCDCD46EE1A0
+:10867000E7C0418E0FA5FA64CA57696A9FEA237E54
+:10868000B6006AF3902FC307A89F667EE76D81E965
+:108690003ED78F3149634C443EFE9787CBFFE61CA3
+:1086A000351E6D84385936F041D43EC9EB621F95B2
+:1086B000E26FAC5F878946ED625F107AD73EA1E733
+:1086C000B2A35CDEDF26F6B225BFBBE4DA1D30DFE5
+:1086D000252FC95CFE0B3A3920F4E043D5A954C7D5
+:1086E000FD4285751A0325DE773756AB9A82DBCFBC
+:1086F000B8A2C683585E52DC3C058F4C4D9CD57E9B
+:10870000909F61D34620FDED3E70E508CADF7DD322
+:10871000CE304571F7975D7F7E12F351F701FE630E
+:10872000EC4BE89F6514BF29267AEC8D6E3AA58E36
+:108730006B26F8613ADEF22B14D8E82B9030001F3C
+:10874000AF794BEB8300D00FE3B5A3488F77FA02E4
+:108750005476BEF2650ACAF43D47DEF5A2BCDF6D71
+:10876000D346209DEDCE047B20067DFE4ED04F41AA
+:108770002F79155F7A797EFAB020BB0BE9A762B733
+:108780004C7FBFE0E46E59C373D8EF6B8114D47390
+:108790008EB3E0CC09B8BF0BBB763E473B9B8F7ACC
+:1087A000CB28BA2FC3606732799985EE7B6F95C865
+:1087B0003F5162D243CA59E3CA81B86FB46EB2E185
+:1087C0003C4AB718BF2F47FD651496E7B657BFF46C
+:1087D0000AFD258B65A1FE02F443FE89AED764FF36
+:1087E0006646F93D6D98DFF39485E307E425F1A132
+:1087F000AEC73CE1D34EA05E7DC223F613618F76F7
+:10880000354994DF7FE1369E777DC9717513E3F3B7
+:10881000A7BCB01221072F5178FCE2922359140F04
+:108820001DA731F2872C68954288C7125DAF13E708
+:108830002960DB25BD6E3C0BD5E2FD720BB7497498
+:108840000EA36C9BD17F5FBEE195C3681E2E6E3672
+:108850009D8F177831C73776E22F31E21B83E3858E
+:108860003F67301B6C386FD5767EE7AD3E16E7AFBD
+:108870005F15FDEBED26C473BAA910F32D0FC921C6
+:10888000F1F729DD987F7B8BA08F5B047D54B2B01C
+:108890000DF3F717AFE3F3656BAC867B8B17ECBE7C
+:1088A00095CE2398E9A864078FBB010229BE53B275
+:1088B000D1F8BE54E0A3D4848F8A8064828BEBDB32
+:1088C0003DE16A9E89EBBB788795FE4E8719AE33F2
+:1088D0006C36E511FDB3E133AFD375FA3A0D67C3DA
+:1088E0000DEB5474EEFB0922F68D51FF7DE6F0701E
+:1088F000CA7739DD9649FE039D3ECCFD140AFDF989
+:108900008A0D5CCF3CD932256E24DA452F2A7E09A8
+:10891000FAC97FE9332F9EF7C8DB2B338C0B76B671
+:10892000E6DF85E7B477B5655F87F751E4BDA4D08E
+:10893000BE91FF521EDD0B92F7525E5C16E551A808
+:1089400049880FE887F6DDCE17B3FF988BF2B36D39
+:108950006A01A279F98B7971A81FEC62DC1F21BD35
+:108960005490D411B58F94C773FFC0CAD4F7EE41A9
+:10897000FDFD8A67F8DF1FBCC2DAF532E61FEC6A3C
+:1089800053FCCBA15EFED2DC1ABCA7A27CBBE447A1
+:1089900035FB70FB92E41F219DB55A7D7682F72747
+:1089A00007F07D708744F78557EEBD7C4413E67968
+:1089B0006FCAF7479FCBCE4B50EFC3BC4A961647C2
+:1089C000F6F71583ACB49F9E1810F718DDC7A26D9B
+:1089D0002A44397BE2B95D363A37D824B15498C875
+:1089E000E1D4834FD3FD1ECFBE42F90A5376BF4276
+:1089F000F909BDC9FB93219985C9EE6EA47B611667
+:108A00006FD2EB1D740EA258E84D155B8E51BD144C
+:108A1000F57F18AF74A31C52E1D7837B7F4DF90D0E
+:108A2000153B787E03BC27F9538AF1533542E7732F
+:108A300019A783B942FE94317ECF5059233F47A7EF
+:108A4000DF8BA4D3F9FC1D73280FAD47BE19DA974D
+:108A500014876824FAEE79DF10A7EF1EF72499E84F
+:108A6000FB573A7D5FC82E44FAFE7C12CF0FFBFC09
+:108A700015575C2ECCE7F31764CABB3F079DD37E26
+:108A8000FAA2D8FF4F872DB43FE9ED4EB57C4AFBE3
+:108A900048E58BA76DA8AF16B67E42EB30AD75FFEB
+:108AA00054C4F3D52C508E78BBBA35CE877C3EADFE
+:108AB00083CBADAB5AED21F4535FCD9AEB707D3B88
+:108AC000F73D519788F4F238A7175D9E2D14F85C96
+:108AD00028F0B950E1F73D95E6EE5F8F6ACA558CF4
+:108AE000CB9BAB9A85BCD968C46FA7B55921BA197D
+:108AF00029B1C68C9EFB5D19EBA0738F9D6923E89D
+:108B0000EF4906C15E453DAC7C87390ECEEDFA0AD1
+:108B1000D37E7A205EDC67F00DEFC178D7B42ED318
+:108B2000BAF87E7615D013C643DAC235B928F77481
+:108B3000FC98D7A54DCD8A3FD779E79785DEAED78C
+:108B4000AF15F74C34FB1ADDD176F8153EBE9F9475
+:108B50008E9783B8AEDDF64AF6C151AA2562AF8082
+:108B60009DF2657C3F6EB78C86AE9F4F97597272AF
+:108B7000C45EA94FBD6F5A5E32DE1FC1E5C5A97143
+:108B8000D01FE60B288CE454E50E7B08ED0C3C77F7
+:108B90008476C07F03EEF3D8290080000000000037
+:108BA0001F8B080000000000000B8D577F6C14D74E
+:108BB000119E77BBF7C33EFBBC87CD116AE2AECFF7
+:108BC000BF3018B3312636A449D62E6928B8CE193D
+:108BD0001A429BB45C4814D284B351845C242AB1F9
+:108BE000B6898A42AA466AFF88AA28DA448A94A8E3
+:108BF000343A84514C655BE7C424B6532408D0183A
+:108C0000D4B427FEA069656383149C5691E8376F3E
+:108C1000F7B833366ACE92E7DE7BF3E6CD7CF3CD50
+:108C2000BC778F0E5EF7A5EB886283E21182AC2CD5
+:108C30008AFBB4A5441D44DE9246C80161A40872B3
+:108C4000D3755FBC8068BCB2A2280EBD1BAABE4C07
+:108C5000C3F8167F1ECECAAEAF15A262A24E48BDA3
+:108C6000383BDFA9A67DACDF39284C1BB2FFC3FF20
+:108C700094951712CD0CCD953D0DD9A8798896F213
+:108C8000FC0F57AB3877F6929FA2E538D8322FD039
+:108C9000FD44CF91F3D9A3111D5882F1E80B6D5417
+:108CA0008F0971B8949A61D74B460AFB3A2F2A86EE
+:108CB000A563FE9497A889A8E7B33F8F2E2921BA10
+:108CC000F6BE30FCBAB3FF570D18EFB60F2F81FE7A
+:108CD000CDF7846141FDB97B881EC2FC9ED7BD578C
+:108CE000D201E7AC5BF27FF2CA41E8258E05F4576A
+:108CF00030EAA1DE52826E2F1D963241AF5E57429E
+:108D0000B037D0E7635CC8CED91F257AF1DDF9F61C
+:108D100012A466C788EFC0DF5A3A4673D61FD50A39
+:108D20004BAE06F1A5966A6F29EC7FFE5181F36781
+:108D3000C615CD2F246E6F7E27179F3180B19CE71B
+:108D4000F34C429C33E70AEC3CE8FDFB10D66A8802
+:108D5000A60EC1B81F769A158987678323570F7FA0
+:108D600010E57C32FEF135447F1CFE6095C9FE9310
+:108D70004DB49EFD86DECA1CBF93702AC74FF865AE
+:108D8000A4705ED75F1503E6D9AF6A5F49D6AF938B
+:108D90006A3A64E4F063EE90D9315A8574890F65BC
+:108DA000BE3C6254CADBBC39A5C4ECBAEC18F1EC89
+:108DB00032B1FF27CC0BF843EA6C24063F7FA6E9CB
+:108DC00092273D834E7E3D438EC4F93B8871C19806
+:108DD000CF5FB0DE6AEDE5F59BE541B218B7AFAD08
+:108DE000361E7747157A05E3EECF5EA8A19CF3897E
+:108DF000FD447EBBBCB311E66DD7398FF4AFEBDC1D
+:108E00008D4825C65BE8AD4D1AC65B297998D73FDA
+:108E10008E069F675E5B7CEEB2AC9D2F8B14C77F86
+:108E20008E17F62CFABD63D78DB797B6491C7A5DBD
+:108E30005EED2E72E23DA8C5BBB90E67CEFD37824E
+:108E4000B0E9E4852B21CE5726DF77D6DD6DBF71E3
+:108E500002E373B3453FFF2478D030AE5A4588F320
+:108E6000C4649EDDC6B80CEDF9C741CEDB653F7129
+:108E70003D740FEFA921B61B8FAF8DA10E6F0EFFB2
+:108E8000622DE340A257FA65B17FF06B7AE062444D
+:108E9000C77C62E86284D71327D7FFCE82FEBA333D
+:108EA0000D5B79FEC4982AF9D770A651F2EFC45F22
+:108EB0001A8B2BD87132826C3731AEC6189FC478AA
+:108EC000E3A76DD04B9C696D147CCC99C662EE3FD4
+:108ED000EB04C5925817E395729C89E7379A22E311
+:108EE0009919011F302F28EAF0872AE7F1676FFFF1
+:108EF000691FC7B1774031737994D9F796A64A3B79
+:108F0000EF307F806F4F5298921FC71DB977E08472
+:108F10008CEF456F52E6BBE798D759FF9323895EE4
+:108F200093FB2C5A62311E9FF214F2B0C567AF203A
+:108F3000B838514E3B938BF4C3AAB090FB262EC594
+:108F4000BFCB7C996889D768750BF52C6A95F19031
+:108F500070F1EEF76EB617B157E1DA0B15D3AED854
+:108F600022EB5AD8E1CF161FC517F3E78B4C3D1102
+:108F70001DF58017E7DBBC1AF39FC82C588E3EDB2B
+:108F8000EEF6D9ED3FF29ABEB55827ED741ED6DB4A
+:108F900033FDB619FD0C7D21863FEE6FB1D76345D9
+:108FA0002940DA61CEEF73DB28E6A50AD8D93C7FE9
+:108FB000FE71EE97F52C5569E76E7DF022F7C1D56D
+:108FC000F8524DD5DC074929080AF0E6AB31AFA6C7
+:108FD000487FED4AEE0777C697E9331FA3FFE9E81C
+:108FE0007F63E87F2C7B6A3FAF4F038F89914BEF04
+:108FF0008765FFCCA32813F01B5847DC09CD3DFB48
+:109000000E7B3DB7EBF3C7F3F896C9CF34D1E664D6
+:10901000DDC2FC5C77EFB34460CA07B25217ED3B88
+:10902000E2411CAB14877F7E6FDC2C451CDE8196F1
+:109030005429F7D35A7451C437FD88B0B9CFC3CF80
+:10904000327F4E9F9F5E2EE47AF70E615BF83A52B4
+:10905000FBB9BCB713A9B33EE65375FFD32FCBBA08
+:10906000B5E80245B2797C2CE0DC97B7F397899795
+:1090700017758E0F7C96FDB8444AD6E7FBB1DDBD6F
+:109080000F1F6B9E9FBF1A3AFB8352F8F184290C85
+:109090007BB1BCEFBCEFF452FAF6795F158E1787FF
+:1090A00081C7CCD91B3BD6C0DE44ED3FCBF81EEDCB
+:1090B000BC0B7FEF0D3BB8760543F55484EE52A30D
+:1090C000F7A581C7F1C2F80A69C7F34D6815F1FE2B
+:1090D000F49B2F09CE0749FDBBD54B855B2F15614E
+:1090E000CDA98B125AC7BC7A4F73C6135E7B05F7A6
+:1090F00003AAC36366C3FFEFBB3DA73EA9E7BC5C01
+:109100001B19AFF7E5E46FEA25D43DDF23431F4584
+:10911000F4825C7E795C7EA9520AB1CDBD1FE7F373
+:109120006D8AF9C6F93EFE51FB93CC93FEED2542C4
+:10913000CFB93F4F9E0F55E5D89D1E54A43EA9E9D7
+:10914000EAC70B73FD7C59FA399D74EC11A5ABB7D6
+:10915000AFC95DEF73799B96BCFDF5CA7D31AEE377
+:109160000C6F557278DB39D041F23E72E34EFAF063
+:10917000057E59C37EFB1DACCF7867CBC23975F134
+:10918000AC8B73534A483E6E204B61BB4DB0F81414
+:109190008F554AA9900F504ACE13AD20E6F1FD2E0F
+:1091A0008F9BD4D488A8977A960A5E6EA4B352EFA8
+:1091B000219A95D2243478C85632A46C0EA4B67283
+:1091C000FBA84B2615E6532AA286AF828FDC4A16EF
+:1091D000CB5F367E95AE66F809653C6E76C516E9BE
+:1091E000D7BF75EBDCE0B71AE7799AECB731F52019
+:1091F000A5153EE40195362B88E7419502F9F0F775
+:10920000F8A847D6EF705AB7B97F19C5EEBE7F618F
+:109210001FC64DA653A77CD53CD5908DF74E1C3666
+:10922000C25E11EBA974C42B714CC9F31E66C71141
+:10923000770BE92A8F7BC3E56E9F9FFD399FF3FD76
+:1092400041BF7CE7780296C4E3485897790B02CF78
+:1092500010EC6C7C4DD024CE352A9C7833F637E266
+:10926000D557D4C0FA42EA634C93980F069C7D44CC
+:109270009B34C64BA4229E5BC16F8FEB4C84A4DF52
+:10928000A16766AF1D94EF36BFF6365C32063F9994
+:1092900014784F0BD3A403EC4FA020C5EF6BB06341
+:1092A0002AF75DFD4678F71FC2F047E89AC48BE2C3
+:1092B000A4F33B6319BDA1F1BDE161BD6207BE2FFF
+:1092C00081DF136EBFBB9CEFF48D77ED6DBA07F9AC
+:1092D000D8591230381F0D81B27504BBED85716904
+:1092E000F7B23856258DA8F67AB69BE17990CC6610
+:1092F000C659B8F93A1070ECCDE539926B92F91C69
+:10930000443B0FC0AFA3A88B00C656AB936FEBEFE7
+:1093100079761FCE9BF3C424197FA91801C9F76879
+:109320007CB209526D35F57D05FC64471CC16C1C8F
+:109330007D7C0EEE637A160F449061BFE6C4D3576E
+:10934000E059C9BF97FA28DFC0E388F6173A3CDB3B
+:10935000FF459E4DE50BFD1BF1C74738BE398F31E8
+:109360003921EFD17D4DDCEF18A7EF6570F2647104
+:10937000DA6947FBD2BAC4658CFBEB7D7EFBDE1459
+:10938000F6FDD46F57B1FF193C90204952CDC53935
+:10939000838FC6F9631E9BC85F26FFD12C4E47F30F
+:1093A0001D7CF0F3CDC141471ED72C8C3FC3A3FFDA
+:1093B000010A95CE3EB00E00000000000000000043
+:1093C0001F8B080000000000000B7BC9C7C0F0A382
+:1093D0001E81BDD0F8E8B89917BF3CA9588601C1D5
+:1093E000CEE6626008E060600804E2DD40BC078809
+:1093F000A539191842803814882703F95380380793
+:109400008893816A1B981918B6B13130EC05E223B4
+:10941000407C9A8D74FB9F8A3330A4C920F85B800E
+:10942000EC4D72D4F5E3281EBC38C600953F4713B7
+:1094300095BF449B81E12E929AB99AA4992F68C84E
+:10944000C02004C4008B7A89656803000000000016
+:1094500000000000000000001F8B0800000000005A
+:10946000000BED7D0B7854D5B9E8DA7BF6EC994921
+:1094700066263B0FC2248664E70501031D6288400F
+:10948000D14E5244B4D48E685BF478740848781393
+:10949000F09556BCD9900709093058AC81224E107E
+:1094A00011156AA4F8AAB40E88163DB64D5B5BD1BF
+:1094B0005A1B11410139296A9D5AAD67FDFF5A3B7C
+:1094C000B3F7CE4CC0F6DC73BFFBDD1BBF8FE5DA14
+:1094D000EBFDAFFFBDFEB5462645442A20E40BF860
+:1094E000FB1A21B9222164423C254452FB9C901274
+:1094F000ED8B62539E7C613B9FFC67A3CC798D9082
+:1095000061907E9F906C426EE365F42F00F9A93C58
+:10951000A3CF474F895F26D1B2783F5309CBABA287
+:1095200040BE10E0ABB95C1FA7C1E91D47D208F9E6
+:10953000C4C552AD861655D2F42D57A4A9901097E4
+:10954000102A66EBACFF4A702CA61743DA24905918
+:109550003DEE04F320AB195C76E788A42A3E7F6BCE
+:109560003D3D6D6A24243A2A9EB749FE288C4FA6B9
+:1095700010FF8309DA4DA4EB40F8B88904F0903964
+:109580003CDE154213E1BB9D04A2365CAF9FC03C9C
+:109590000F78AA8E84B208E99C22FB1DF079530E45
+:1095A00081797975B8CE2AC0BC0C799590AFC33F4C
+:1095B000B8DE685B319D47AA5F246BE9A7A69C0AC9
+:1095C000271D93AC9FF4575F88A6A9520F512075B1
+:1095D00093404FF9E0790689C8F7F12E723E70B0DA
+:1095E000EE8F1DD680ED6947D9F1F96EB0D379D1F0
+:1095F000F568134402F0595739332D94601FF47401
+:109600000DC0972EBCA5D18969D3C49969A41C7AD1
+:10961000EA9F05705E3F295B5C2BC4E1A2C3E1C0F9
+:10962000A4179D7DB45E3BDF9F4EDF4127B46BE7FF
+:10963000FB6E85DB7A800F2DAF2102CEBB6558CA49
+:10964000AC4802B8D4102F96AF77D176B08E1C12EA
+:1096500079B010E6D3D73587E6BD13950A80B715E4
+:109660007FA60E93B0BEDB4D220EDCDF803B8796DB
+:10967000A71236BE3B8FF8A3743D2EB7DBAFD2BC2A
+:10968000345124511DE6F8EF72D33E7849BD835022
+:109690007A4D9D326F061947F36AFF1118DFF9A65C
+:1096A000C31F800AE532B657E87F5F14D1FDF8DBAF
+:1096B00087584EDE16FC0FC2FC767078296C7C67EA
+:1096C000896C1ACFFEF93541806F47F98A9455426B
+:1096D0007CFDB2719FE9BA6D96BC7DECCC6F15AB89
+:1096E000C9F7D3DEE725D18B6865DB0D43EE7BC37D
+:1096F0009BE32F3D54169FCF8F8827EB3800EB62FA
+:109700007231D2FF39DA7FD2E8BFF4901DD7291A1F
+:10971000F950B2FA6D1CCFF47C7B21C513C4B33E63
+:10972000DFD563E3DF5FE5F841B46AE46F12DFBFC2
+:10973000F64B48BF8DC2B769ACACAEA67090DC7278
+:109740005418C7C6ECAF02BAA67FF0BDBCB557F03F
+:1097500042E636137F6C29BE8A328EE4F393B2CC94
+:10976000FBF365E1F73CC0EFC238FCEC249816052A
+:10977000BC0DFA103E1E7D1E977C478DAA09E0782D
+:1097800031A53B3A9E3D2B42128DABF341BF10F801
+:1097900035F01F9BEC47BE4526CB09F9A05D109123
+:1097A0004FC5E1EC94101F09FFDB1F42B8C30C9DAD
+:1097B000D91C7E8097252FFE0DE027A9249AEAC5A3
+:1097C000EFCD5205A5039568A994FFCB129120FF18
+:1097D00029007B02964F9533804F4CF38780FEED36
+:1097E0007C3C65B6EF6A4F7C3E9FF27D8D97877C0F
+:1097F000DF3695DBD97C3D9C7F28734C7831D03E99
+:109800009DB5B7AEF723C2D6FB29A547863F737C2B
+:10981000410FF4434CEB6E516F08D6AA280F3E85DA
+:10982000FACD5F09F4CC017AE5F2C02A5793F263CE
+:109830008B3CB5FB0C79F84731E05311FC9BA7201A
+:109840007D11AB1CE76960C43F270F69CB4472767A
+:109850009C203039A565E1FA753A225C4FD0F79B20
+:10986000F27593FC90613E94EFB948043B4F25514B
+:10987000CC7B483DE63F9E581115683F0EA9AF0DC1
+:10988000F89783F251AD70F0F81BB83C49B68E0DD5
+:109890009724E6FFF9807C80DFEE7A1242BCBD415E
+:1098A00001BA12B410F902E88B84B9FCF5FB60BF71
+:1098B0005A1B1BC83BA584A41CBC8EA863611FEA6D
+:1098C000038172D04B6815CA824949254B25BF6A6E
+:1098D000C4C7817D24ABF87841A43B8A17970AD08E
+:1098E000BFD38C3703F85142896E12E6D560C2FEB1
+:1098F000F87EF27A49F16760FFF5F5A832E2AB0530
+:109900002F5C958A00A84DB3BD309FE17C36C343E0
+:10991000ADCBC571B02FDAF49174ADC3FB66CF0047
+:10992000D1E979F38AF7415E3597571CAEA1FB94D4
+:10993000E657AE9E4653570911009E6DD0592EF43E
+:10994000F7A2564DD7DB049DD1FCF5AB9E0D686E9A
+:10995000861E66BD5254251D5F8A86D44B842F1CFB
+:1099600083DB275BBFDD22D70859717E7AD00DAC2F
+:109970009D46FF03BA4AB7F4931630F3710F31E4F2
+:109980006979F380DEB4FC7F643C85AC76AA14056B
+:10999000EDAAA844E8D869444997286AB8A64A2499
+:1099A0004AF34A567F4054CFBD2FCD844C677C3C50
+:1099B0004C8C78BC99D3B9AFB6B9B095F6FB71A50C
+:1099C000DB0F743E9CB2C1CC8CC1EBE9B0C8E18E18
+:1099D000F2BB11EF9B88E62C02BDBE5C44FDA54D99
+:1099E000DDAB18E5D0B33A3F19841F4495AA9035F2
+:1099F000207ED85431E0F2FEEBF861D57BCE173FE4
+:109A0000526F30EFC797DDAFC3801F13CE1F3FFEED
+:109A1000D5F1F47D4DC6977CB5B7A25DB1266F68D0
+:109A20003D7EF0BEAE46FEE952492092A0DD2F05F4
+:109A3000C12C7F8C69B6515EDC62DA2FA960DA91A5
+:109A4000EE21E021A91639A8F3B1069B7A2C133A2E
+:109A50005050DE38797FEDEADD1AE8ED1FE7018628
+:109A60005079125E1E1540AF2961F61D742002BDAB
+:109A7000A88108DA212097E8BE38F8FCEC3EB31E36
+:109A80006F5352CC7ADC2C4D30CEDFD520E33C9C9A
+:109A9000301EEDD741ED0518D79647A22E6F1C5FFB
+:109AA000612866AFDF795E78A0E32B8095E1ABB9E2
+:109AB0005DABAF22A15E3768BC6BCDF34DCA97ACEE
+:109AC000EDDC927ADCA06F246F2791E306BDC50719
+:109AD000B2C5B0FFAD76F2B440F5BC26DF77349C5A
+:109AE00037FC9303FC89A03CB3E5D490900A7252F2
+:109AF00065EDD40C265F7709267B5BFF9E7C1E6C90
+:109B0000BCD8CD84F482DC9154D47F93D56F6AF4B1
+:109B10007D55A242C8DEF0C06489EE5FF3AAC0ACF6
+:109B200020ADBFB671D764F8AED7AB11454EBF5468
+:109B30006C56811EC3F196D07A4EFC4ABE00FB885B
+:109B40007266D580472ED233592AC3AF7CFF883046
+:109B50004007B4CB25225BAF833C8DF5A023A847FB
+:109B6000B938CBD386906FB10702414A776BA5888D
+:109B700073054D5B5C3CAFF27C3ACF2B3C5FC8F386
+:109B8000643BE6ED32CDD375A5D8230AE65378BE03
+:109B900090E733783E9DE78B785ED88EF91699F57D
+:109BA000D721F5B0FE53785EE5F90C9E5778BE8854
+:109BB000E7C95E36BE83E553ED3DACFF549E2FE40E
+:109BC000F94C9E4FE7F9629E17F6623E299F2C637F
+:109BD000F08FF305066F1D0F09C0D5E4E78A5AF22E
+:109BE0000C5F32058687B16FEA78E347FE48DCF9FF
+:109BF000486FC3B9BFA1E906E66F20DC3F62F87E7B
+:109C000058057E334BF40F455F8F707EBA8BEBB1F6
+:109C10003B1B15D4BB7734FA30DDDEA8E2F748638E
+:109C200019A6DB1AFDF87D6BE3444CB7340630ED22
+:109C30006A9C8EE9A6C620A61B1B6761FD0D8D21BF
+:109C4000CCAF6B9C8F6947633DA6ED549F85744DE7
+:109C5000A386694B631BA64D8D614C7F7843C54B32
+:109C6000A0D27EEC1651CE279BFF85BB44131F1E4E
+:109C70001D31F3C5515D19A67C6938D754BFB8AD05
+:109C8000C8545EA88D319517345498F223EA279B67
+:109C9000EA5F30BFC694CF095D69AA3F2C38D394E0
+:109CA000CF987ABD29AF4CA935E5BD950B4D797795
+:109CB000F90A53FF2925DF37E59D79AB4DF53B5C6C
+:109CC000A19F8A942FC8596B4DF524F7DD6679352D
+:109CD00023EBBCF816F948CB06BCD2F98795DFDB3D
+:109CE000F2492080728BC99726C05BF0678D209166
+:109CF0000705F0235D7E18FC178E1226771C83E47F
+:109D0000A6B93FD9BDF38846C7A9F61EF6F519E8EE
+:109D10008C18ED4ECAF7FF2C32BFE2DABB989DDCFF
+:109D20007957627B19393BADD7F979623FED9F4492
+:109D30009B452F60764AE75D02D6FF57FBD7CBAD38
+:109D4000FDC6C7A37B5C65B05341EE4F60FFA7190A
+:109D5000F4137B5FFA1CB07B743BD6C6E9BCBACC6B
+:109D6000FF763385778B42FC0E9A6F71D710D02B1C
+:109D70003E5618DD931DF9686FEBF507CFCFA0575E
+:109D800020FF4931D9FB927B26F29796ACA1F532A0
+:109D9000396623512AAF6C3101FD72B2149C5E48C2
+:109DA000E9577ED5E65F45505E26B4DF09B91BE171
+:109DB00060B3E837CD732D7C6FEA085CB75DE76F61
+:109DC0005935F8BD59197A5E0E9817CC87CFCB1E3E
+:109DD0004BC5D41673E17C27C532313F31968EE9ED
+:109DE000C5B10B30AD8AE5603A21568C6965AC107F
+:109DF000D38B621762BB8AD8684CC7C72EC2EFFEEE
+:109E0000D8784CBF12FB2A7E1F179B84E9D8D8D77D
+:109E1000F17B79AC1AD30B63DFC0EF636257603A12
+:109E20003A760D7E2F8B5D8DE9A8D8BF613A3276E8
+:109E30001DA6A5B1399896C466635A1C5B84ED8A49
+:109E4000620B302D8CDD82DFD5D8724C0B627762CD
+:109E50009A1FFB1EA623624D98E6C556617A41AC57
+:109E600003DBE5C6DA31CD89FD00BFFB621B31CDD6
+:109E70008E6DC6343DF600962BB16E4CD3628FE2E8
+:109E8000776FEC614C3DB19FE07777EC714C536399
+:109E9000CFE2F794D83398BA62CFE37767EC00A6A5
+:109EA000E7DA2739CFCCC76D5929A6FCC463663ED3
+:109EB0005EF5A6998F57BE6AE6E315AF98F9B8FF2D
+:109EC00090998F8FDB6FE6E3E5FBCC7C7CCC6E3327
+:109ED0001F2FDB61E6E323B75E6FAA5FB2C9CCC771
+:109EE0008B3A179ACAD566331FCF5FF97D53FDBCF5
+:109EF0005B579BCA7317AF3595FBE69AF97736D94E
+:109F000062B6BFA76E37CB91298F98FA7357EEB51B
+:109F10009C034490CFA494FFD4D4CE597230A15D59
+:109F200063F57F0348244ADF779014FF5A61F07E7F
+:109F300066707E90097447D32C4E77C380EE689A82
+:109F4000F18DC5787EF4C937DB7E416D4392710196
+:109F5000FD673274BBA12640BFB7E6E879A209903D
+:109F60001F4198DF80BC5F8DE5852CDFD574AC5A2E
+:109F70002B477D9EFB154E57835FACD5C5F20FD99D
+:109F80005E59057E858CB440AE9FA63BEC89F9F8FE
+:109F9000633619E1714A0C6CB3D1F5FE6775DFEDDC
+:109FA000E00FFCD411DA6EA3DF173B4305E06AFE35
+:109FB000C01E7A4802BE48020FC0F73412D861436F
+:109FC0007E6DF67B36828140FBF98B187C18CA3394
+:109FD000AFDA857691BEEE56CFD0F3B9CFC6E45254
+:109FE0006B3A41BB51BB4746798A7F55713FD5BD1E
+:109FF000A9DE009477DE236F87F320BB3F9BC9095E
+:10A0000062911F9B5A9783CBD101FB6933FA3D7B49
+:10A0100031F5927EF47F2A441120D5D73FB0EE115E
+:10A020006CDD141E87603D32F84B697E75EA55136E
+:10A03000613D141E2F7078BC681B961C1E044E0ACE
+:10A04000AAB82A01FFEC164CFEC7778550AF8D9D4C
+:10A050005FE27C54CD8F707BC4C6FCDD3AFCE8DF48
+:10A06000AD19BA3F86B53B82FB60E94FEFA7D7C673
+:10A07000C7E7F250C7E34C918412C1BFA591F99F85
+:10A08000C9AEFC2FE5AFFECC2E261CC72E05F19CD9
+:10A090007410DFCBB2D8F5592138D385F38784E724
+:10A0A000A99364EECF900ACEEB3C4AF79790DDF986
+:10A0B000E755FF217DDD70BE908DA063FB74281FE6
+:10A0C000F3A5BC7D31D7EB9EFFD353D125940F74FC
+:10A0D0005230B3F348B33ED7B949C473F4E2114CDC
+:10A0E0003F6CE07A80839A0DAE710639DD69D60B3C
+:10A0F000DB7438EE37C3B19822F44F2BE8FFB80B6E
+:10A10000D8FC14F37A9AF5F55AE6D152EE2746BBFD
+:10A110005B1A1B1421EFD8C4E6611D9FF0F3035DA9
+:10A12000EF75B8B9DF4429C07EF571ADE310DB4AA5
+:10A130003C1F4AAA8F58C7F992E76F174989CF2F5A
+:10A14000E9FE209C4AB87E441AE81FCD8FE4F3D77D
+:10A15000FBD3CFE1F4FCF37FAAC3F3EDD6702DEA75
+:10A1600079AD3E26A7C967B477E88F24C617FD3CB2
+:10A170007C0DD88D60CF95D438B15D568169BF5CB8
+:10A18000A59B9C008F66E56E05D2B565AC5ECAE8FE
+:10A190001DFCFB76FCEEEAAA3F0CFAA28BEAAD129C
+:10A1A000C07BC4AD58AF595981FED9942EE6B74D46
+:10A1B000E1E5B925AB9D10A2911B0E38A11D5125DB
+:10A1C0007F29B4EB0A4F2F027F571BF14B6C0A4ECD
+:10A1D000D8C7ED1C0E7925520DB4CB0B6B9A0BDB57
+:10A1E0009100B4D3EB45F87AF3CBC45570AE901F11
+:10A1F0008E846BC04F574FFCA5F8FD60B4D0507FE4
+:10A200001BEF5709B3F993F9AC9E5EBE95F7E70EC5
+:10A21000D7F756433F9B58B92FAF12D837C9566B63
+:10A220004598CF3A8EB7CE424960E741ACFD161D46
+:10A23000CD2CF45E1A66FE4EBD5E179F870DBE974D
+:10A24000C7E97E0DB7E7F57A3FE4DD8DB4B40FF3CF
+:10A25000EF8E4AD6BE89DBFFFA7E97CACC2FAEE3DB
+:10A2600047327C256D067E060BD452CCF9860C93C2
+:10A270001D47EA73CDF9F945E6FAA131E6FCAC0ACF
+:10A2800073FDC06453F92703FE92880BFD22DC5F47
+:10A290003292D7D9D2C5F03CEE8FEB7319ED8B3CDF
+:10A2A0005E6F5B3D8B7369729F5F5C4918FC16C8DB
+:10A2B0002C981F46D1FB69ECC2EFAD81DA141877F8
+:10A2C00067D7D0FDFD84D3D5E39CAE1EE3FBB787F3
+:10A2D000EFC7A3DC1FF330F7C73CC4FD310F707F1D
+:10A2E0004C37F863E8F7FBC11FE3003F4D10D32D57
+:10A2F000E08F413F0DF3C7FC90FB6336803FC60102
+:10A30000F8D780E9C6F1E1EBC0CFD6C1FD32EDDC74
+:10A310002FE3B5337FE3C6CB02B950BEE3B2C4F638
+:10A32000AED7CEF024171414CABFF389164D01BA64
+:10A33000E82404CE5B9CAF680137CD8FDEC589640D
+:10A34000BF1648A5F9511196CFE3E3809CC0F8A74A
+:10A35000061617E3C8D3C86CD8A73CAAED50F8AED0
+:10A36000E1F8FA9AC4C68372A41B95F88C7CFB0DA5
+:10A370002170449A00FDB2F9B8422101CA86DFDAA1
+:10A38000AFC9B45C59DC1B80ADF2B6F544C17E5652
+:10A39000B528EA1B1BABFD87E13C6BF3EF6D7EE458
+:10A3A0001D59C4841FB4EF8476757E6C1BEAB7AD6B
+:10A3B000F53CBEA892D5CB4F627F8FD96196FF65E1
+:10A3C0005BCD764F6BC3CC21FDC5C36789167F92E9
+:10A3D000E55C608A191F5B036C5EC9FAF3569AE765
+:10A3E000E32E37F7D7EA1E7A3EAED855A8EF27C33B
+:10A3F000F332B1D66D9F10CF17C72EC5FA56FD4E5A
+:10A40000227E543EA4A97200CE79A5A94A00F45A2E
+:10A4100069AACA533FFF1EE0F920CB2B03E7DBB943
+:10A42000F661087FCBF97680C0F9F3C6D184D917DD
+:10A43000DA9CD5812934FF6D82F6C2EBD2B21A2D97
+:10A440008FD2CB0CA768FB0AE01B8B57D0E3BB3243
+:10A45000E5487B21E5E39B378A643BCDEF080F4D50
+:10A46000CF83E218DC01F4CF14772A1520BE93B510
+:10A47000DBD4294E4F14377031A72F728858F5E678
+:10A480008B61BD2D9D33159067D2B57EB40F88CA00
+:10A49000E6AFF3BFCC2D43EF5FBB65BEAE247E9B22
+:10A4A000EFE9F328637C53C7EFCCEF0F8D5FBA7EE3
+:10A4B00016EB114CFE9D61D706ABED142EAD9B89BA
+:10A4C000DF4DFB69FDDCC6FC64FB597C998EBF4DFA
+:10A4D00081A3C8AFF5F1739568B500F50F4C222A3A
+:10A4E000DDD791EE9088F6E001CADF81FE24AA75DF
+:10A4F000D2FACAFC6880FBC905D87FA5DEAF411E31
+:10A50000F603F806D89BBC3ECA8D7003550F29FD93
+:10A5100037815FB330CED7753C68F271FF3AD53BD7
+:10A52000B0F433BA3EDD1EA1FF8CEC62FBDC3A8C4A
+:10A53000F8719965F5C486FDB0382989EB8FAD9E19
+:10A54000DBF11C509BC0F4026A350704A82769445C
+:10A5500084F1E72AFEB5345BDC350EF98AA4680283
+:10A56000E0DB0C21741BEC771CAF7AD83A38DCACFA
+:10A5700070BF96F3D59424FB9922337D3B53F65F4D
+:10A5800009F6E4E67B287E2788779164D6CF039B83
+:10A5900066A68D56E3F4AA973F6253B19F387DCBF0
+:10A5A0002C4E2F6AB63FFE5FD7E377DBCD7174FF89
+:10A5B0005F8FFFBF5B8F5F3780AFE7D2DBD9FAC910
+:10A5C0002C73FF71FD5D53709E5DAC5CB7073A2C38
+:10A5D000FDEB7ABCAEDFEBFABCAEB793C17A3D9728
+:10A5E0007781D5010AD0516E961FD51A58AD419981
+:10A5F000C5CF61A36CCDE8AFF8C042D792DBAC7792
+:10A600009C3F3F9050DE13FF08133FCDCC1D5A6E88
+:10A61000E872F49311BADE1E427D9A949411A37EDF
+:10A62000B5B3A18608743D5B7DC4CF978EE3E4F299
+:10A630007539FB029A884E0D331FDE3AFFA06B94EA
+:10A64000819F3BDC3D01380F77FB7A217CC9C877BD
+:10A650004BE409C08FAB90AF39D530EECF5DA05F32
+:10A660004E180C57E073BE0CE8D1C25F48B017E239
+:10A670003D8AC7138CAB77409414E5030E3FE34F3C
+:10A6800049F9CC79C669E87113F9F40FF8CB2A209F
+:10A6900022D0879E36C7931385E289213E80BCD79E
+:10A6A000448CF17E3ADCADED9A951A2511BF7B43BF
+:10A6B000085D210F8127563F14B1F067AAB08910B9
+:10A6C0007F583C633AFA9706FC5192995F3B227A95
+:10A6D0001CCBFF2CDF9E2327E6DBC9DA0FC43D7FAE
+:10A6E000497F5D3B3F8FD7E97B80AE2DFD88E53DFF
+:10A6F000A42FC1F8EE7233DC534ACC76C53F802ECE
+:10A7000027C0F97186E9BBE4CE4DECFFE77199B53E
+:10A7100013F56D53BFFB478ABF0B0EDB09E827BA61
+:10A720009CD1FDB10B203E93EE4F2DC46BD27D9C8E
+:10A730004B825E28FC8088D341FFF880FCD67B9159
+:10A74000619F36CBCCFF4EDAEC47E11E901E877836
+:10A750007398E5F5F9D47599F3F3C8CC6C388798FC
+:10A76000B7C94E20EE7001918EF6E9F3A7FA4B3B84
+:10A770005C4CA0FDD691FA56E0672DDCDF5EAB1095
+:10A7800009E206973C755FD56C9A8F70FDE72485CA
+:10A79000BF6A882F5BE88EC8709EF0CEBE8BBEF37A
+:10A7A0005502ED23ADB9103F984E307ED00AF739EF
+:10A7B0006DE6F99D6BFED6F9EAF78692CD43DA2570
+:10A7C000248C73FBB1ACC72D6AE7759FE9B760FCB9
+:10A7D000A23FDE7C9FE95CED5EFB27DBBD29AB245D
+:10A7E000D1FDA973B57B3BC9784B9C7D32F08B655D
+:10A7F0005268BA50148FD392EDC1C0051414D2D34D
+:10A80000E3A370A464A8D7769EF50EC379C779D464
+:10A810009B2E0ED1DF194EC7BFD8FD800CF4F9C1B5
+:10A82000236F5F057AF5A2676D54A6D3F2DD1E1281
+:10A83000457B2322831C5BB8CF867E372245ABAE97
+:10A8400031F05F8C90A5FD2F7ACC8371150BF73A10
+:10A85000223368FB854FBE338E50389C59DDFFE2B2
+:10A8600005603F3C22B03842AD6FDC35F4FB4289D5
+:10A87000DC144CC407399E9F7E267516E091B0EB20
+:10A88000C08DD86FCF77ED0EC339DE5F65764F810F
+:10A89000D6C3F325ED6121522AB0F919EF2BE8F167
+:10A8A0009BA71F16D8FC9EB6475C30BF5DDD728843
+:10A8B000D65BB6EB2F88B75F7F6C8F17E0B0EC6983
+:10A8C0009B89BF2CDB658B3AC661FAB603EFB904EE
+:10A8D000DC02E5234B91C5D074DF128CF75EDAD32E
+:10A8E000F1179B17DA9BE987C2C51F05B8BE66F34F
+:10A8F000CF80FC4F1EF2821D78B2F7412FC095F633
+:10A900003B5BA67875E947063A23ACFF58C6E0FEE4
+:10A9100008E99701BF96F5B4B3F12CF47912FE273C
+:10A9200067B05C18E930CB858FC92B55A818EECAE3
+:10A930004C181F3F201738BD2EDAF3F1368D8E7B71
+:10A940007AEFA96D1A9DFFE27F7CB8ED4ED0037FB0
+:10A95000EE5280CF2C7BE4F75E62807BB583D1FB27
+:10A9600099871FDAB985D2CB99D71DA8B79CF9D999
+:10A97000897C95AEFBCCE37FCB867B02B7FEECB245
+:10A98000E100875B9FF8FAF0A1EC7EC0D788C3B8DE
+:10A99000AF11EC5F7D5A60C1F8FB796AD99FE7F788
+:10A9A0003D9F0FF3FCE08803EF152EA3DF1A2A600A
+:10A9B000BF9620DF87FC4A0AE7A5BBD7FCC5362E29
+:10A9C00011BCB50B441FA4946C7CB0DFD77CEB9218
+:10A9D0004A48ED7E15FA23FDC8B7ADED96BD4AF79E
+:10A9E000F52BC9F7F163F2990CF05FB6BB9D8D6B47
+:10A9F000D9C70FE07F260DDEC79B1CE6F3958FC9F4
+:10AA0000E2FB5197DF9799305E4ADFC7254F7C7B89
+:10AA1000483D40E707E782EF7C1EF757EE082C73AE
+:10AA2000005DED4DD57C6C7F233368D9993D1FE7E0
+:10AA3000138A1FEFD9FB6F043ED9FF3387B29D7E87
+:10AA40005FF8B3D790CECE3CF11B5965F79DDC0281
+:10AA5000D513CE9081BF5ED01B96F233E4653B3CAC
+:10AA6000518737BE4F4B23574F57BDF8FD6DFC1E26
+:10AA700061F8BF3472E05A21C1BE3DEC28627C39D6
+:10AA8000320CE1B284F4CA4AB9793F8589B08F6F3C
+:10AA90004F03BC4BB68FFAFA1558FFC586FDDCC1D3
+:10AAA000E8D65A7F29A54FF00B0EEC6B44788D2425
+:10AAB000A0D333DD0E09E27BCFD8CF713FF74BEA4D
+:10AAC0007F0F38929CBF71389C8BCECFB5BE2F0BB9
+:10AAD000BF8DE0B41E36188EA73F4BCCFF9F730886
+:10AAE0007C1EA1E9B9B6C1F2CB4602DA0585F1F9BF
+:10AAF000B6F6D890AF9FDE65C3FBA6563EB1942450
+:10AB00003EA7FEA53ECED307C6013F3B7DF0198E82
+:10AB1000970CEF97EE7E5BD6B83C8818E54112FFA4
+:10AB2000D46B9CDF2DDB9FB8BF65BBFF92B0BF939A
+:10AB300052E0BB30FF93BD76A2D12E4EF6D8A627A9
+:10AB4000D29F0E38EC26FDA9D55375248DB6B37966
+:10AB5000535418BA6975E035B0E7B4DFDAF11C83F5
+:10AB600048FEF71C704FD393A2AEA5F06AF2CE4315
+:10AB7000FFA3DE5FB3054E922FA8815D2A65052BEA
+:10AB8000998ECCE6AD97DB15D1346F2A67F3400E72
+:10AB9000BD35FE841DD6F9678B3EF86789B40EA7D4
+:10ABA000FDFD5913FCABD444F86DEE3FB4D24654CE
+:10ABB000A3FC73F4BF05F321CFB908C495D87EEE8A
+:10ABC000D2809F2CDBE68A38E87A9E7FE2939D0054
+:10ABD000B733F73B88C310275EC7EDAF134F7CB286
+:10ABE000EDEFB4FC0434A6E3D76DA3F5410FDF9D70
+:10ABF0008AC1FAFFB9376D1CA1FCB9EEB93BAF02AF
+:10AC0000FE52073443EBD73D361CF5BAE3C358FE7A
+:10AC1000F89E1111D897C53FF9D95290238B7E9C8D
+:10AC20004AC03479FE89D76E84FC99E73C18D778FE
+:10AC3000E6B91397021D50FD5935CAF105C67704D0
+:10AC400068BF8B20CFCA852F0CF1328B20A57C6387
+:10AC5000D1D36901F0131AEA61BB658EFEDBD151D5
+:10AC60004BB45C116D9C682ED0E1A25DE6F1F29CC4
+:10AC70004C7F5A26F7CF63F5C3B98C5E7BB1DD6894
+:10AC8000A7602AB7B6D7EB8F721659FA61ED973ADB
+:10AC9000487D22FCAFE4FD2EDAF5F928737F1AFF18
+:10ACA0006E1D877DBF4D60F74AC8E32E3C475B2C85
+:10ACB000474766507A7D5226F3816E177BA323D3D4
+:10ACC000E978CF723EB93885E6E9F75C3E0FA80F08
+:10ACD00079E2ECFB31ECEF92A75C04F07DC9731EC6
+:10ACE0003C6F59F2E427C77F44BF9F7E2215E3B42F
+:10ACF000973C7707EEF71247F446F06BF73FEE40CC
+:10AD00003FF2E9C75FCA073DE4B43D9A9F31847DB5
+:10AD1000BEA4070EC107AF83DA0565F5743EDA46B7
+:10AD20001677D64052FCAB68BF0DE0D7003C7ED30F
+:10AD3000C5E2A3F839EE0AEE0F3A3B574DC3F99737
+:10AD400033FFD60A7E4F7DC537D5E1E98679405C71
+:10AD500028B988903BE4FA51C0676DB16F1015FCBB
+:10AD6000EDB1624CF57A3685AA59706E90C5CEC9A0
+:10AD7000ED597E52570EED581C11715F394067BF77
+:10AD8000A65BBC62B33A1CFAFB7727E32F1DAEC06B
+:10AD90004227F21937DEF7C4755286A03DC1D6F5B9
+:10ADA00089C0D6659DEF2776CD01FC3C7EBECDCE19
+:10ADB0004D1A24F53538A72487395F1AB47E4667C3
+:10ADC00067950CA4337D1D1D8D0AF293F6461FA6D0
+:10ADD0006B1ACB888A71F87ECCDB383C1CE51AB143
+:10ADE000C1FD5795CDD5E10E06E05C02FA047FABBC
+:10ADF000CD1D42FC72F8EAD1F677BA991FD2E6D699
+:10AE0000481D4DED6E0627B8770A7092795EEA9A72
+:10AE10008170A5EDF1FB025768A313FD11634C7C13
+:10AE20004ACEAA30E507C14DC78B3DFFD3F02308BA
+:10AE30002FF0D3A8E83F9F88706B690C60FEFF007D
+:10AE4000FC9E61F09B4C5403FDC85935A67C52F81A
+:10AE50006DA6F0CB8AD395150E0D3C1E4DA7A764A9
+:10AE6000F4FBC34682CEBCBB1BBB30D5BF6724916D
+:10AE7000EB392E819FF78756C1F91F51985F856482
+:10AE80006924CFE04F223E0DEF31E19B2650EE6664
+:10AE90007E447D7F6D8A74DCCCFFD4D7603D77BC67
+:10AEA0006C17815FD91A1E20EF641AE87846D0A586
+:10AEB000229CFDE8BF6DE2F2B565603FCDF4D1D1D3
+:10AEC000A862BA8ED3C9064E271B61DFC13FE717C0
+:10AED000714F3BA713949FF7D03CB3EFA3C4E8D7BF
+:10AEE0004EF7F744ED74FF9127A998B2775E8E383C
+:10AEF00022A5B45D6A390900BEA41FF95E84BDDFD6
+:10AF0000D283F7FBD339FCC8FEA2F4EBF0FE34B1D8
+:10AF10003339456C2C0DDBC17EB2C2B7C97FD00975
+:10AF20007677B2F964FB35473E1D2FFB4D07F2EFF4
+:10AF3000AC1B7A8ED4D275B83B53D19ECCF6337C01
+:10AF400074FB43429D61FFB293E87D9B5D57385C83
+:10AF50008087107F4BF9F6DD5DC52E3CBFB0F7F85A
+:10AF6000800F76A43339A3CEA2A35D1C6F7796F32E
+:10AF7000476FA599FE757EAC4CA930E1B1CE6F3319
+:10AF8000A69AF15DE7B76F0EF0DB608E0BCE3563EE
+:10AF90005B911EADF8DF649735E12BF0DE06617E34
+:10AFA000A7B705F60ECB603E80F12867FB0AB7C352
+:10AFB0003B00AB79FCB346E905E50EF77FEA77B9CC
+:10AFC000F690609B5A08EF81500485776328FE0055
+:10AFD0003DACA7F843305EC8CFE96422A63A7E565E
+:10AFE00083F3C4A0B7D94A5E14D9FD0B11640E9146
+:10AFF000A81DE8063FD381494ED00B253B8B53E972
+:10B00000F7883D7036D6E29EE984F86821BD12F7D4
+:10B01000FDAF9EDA82A1CE5508C4F152BC51DC7E50
+:10B020007214C6817BBA40174A05017B728FBB3709
+:10B0300005EC1BBF4B349DE374B842D35C86FC58CF
+:10B04000189DEFDBD770FDAC1FEB783339BD933C17
+:10B050008D9418E85B8F0B25AA46CA0C74BEBA748F
+:10B060001A8173CDC1F49D848F3DF8DFC3C79A0A5E
+:10B0700022B86F762BDFC8A2FCDD8DA9262A30FF0F
+:10B08000BDCDFF361EF1AC0EE041DCDB07F497AF1F
+:10B09000150D9EA7956FC5E5918AFE2A2A8FEE9D14
+:10B0A000087C30893C3AF0A751DF9269F93B2FD9EF
+:10B0B00004A3BF6E7EAC1DE5415D6C1251E97C6B53
+:10B0C000BB7E80E9BCAE6EC4FBF7222D5ED8C7F70D
+:10B0D000DA983DF75EC41EC17884CFBEF8C2067E02
+:10B0E0007DC2FA7F6F6B13D623E07D318CFBDE5679
+:10B0F000D69E54AAA84F9FE56BACDDE008405CF9F2
+:10B100007B5DB4DD10F0AC056328817E8AF7FF21FA
+:10B11000D69FD48F023EA7D3FB1D32E54B0087B7E5
+:10B120001C09FDEC0B5C97AD03782F70053601BF51
+:10B1300021EE8CF37A87E21D91EABD08EF90F76A61
+:10B14000939F95F931DFE17A31712629F7F2F64ABA
+:10B15000E2F2259DA75EBC8BE65ACB434162B0AFBD
+:10B160006D84D9D74B9FAEE6EF7DB0F924C04FA6D2
+:10B17000CF763A900FCDE5FE201D5FE3F812F2F294
+:10B18000FBA0267C5A10DB88FB2D748CBD771285C2
+:10B19000DF87148FC02F27745C321CE868D5DAAFC4
+:10B1A0006EB881F6FFD12B36FC3E3FE6C2FAEFDFE8
+:10B1B000E5BFF706D0D77F69C733F68F0E5F86E706
+:10B1C000B1EFDBCD7E841B5318FDFED1C5EC917928
+:10B1D000B10E937E3CAF6D8E0CFEC779B1F5F87D54
+:10B1E0001E1CCAB07B1B87AA4BE0BC86E0F9E81F97
+:10B1F000DBDF9DBA1AE55905FAB1EAD63912DE232A
+:10B20000F9A34B35F19DBABE4EEC9750FD282B9B10
+:10B21000F767E01F7531B87402FBA311B867308F70
+:10B22000F39181F96DB59BF8C8FBAEC47E925303D0
+:10B23000EBFB2AD2D1E0F55DCAE84B1FB78FD15D99
+:10B240007C3DF74E4AB49EF83AA660FDF7D3138FC3
+:10B250009F91C2C63FDE389F04281FAA75D07A6E20
+:10B2600018FF96D68960676F4DCF100CEBAAEB5A8A
+:10B2700044028675D56D9D2DD71AFA8DEF83ED05A5
+:10B28000E33E64A4FC63EAEA7290DBC17F003DD533
+:10B29000765C322E847636E327EFD8FDF9C0574F1F
+:10B2A00074DD9290BE33522CFBD3C5F787EABD956F
+:10B2B00086FDD1F7C5DAFEF89FEAFE7A17F8013667
+:10B2C00033A52619BC06ED5B6162B89573FC3C4E54
+:10B2D000E56C08E1A63E7904F07A5D2AC6712687FE
+:10B2E000DF85243414FC92E8AF54DF294D9900E344
+:10B2F0001284435D17C38373C12D3E2EC783EAC4F6
+:10B30000EBB97E000F1A884609F6A87C2E3CB8934C
+:10B3100068CE21D6318007A34C7870FDDAFCCB8053
+:10B320001EDF033D65D4E0FD3F2A6BDEC9700EB41D
+:10B33000D686E74C4753B4ECEB597E3CF0E7A3DEEE
+:10B34000F055932BE3F9050F967A671BC63DD1762E
+:10B350008B37919FF5FA64F853A291F2AAFF7DF81A
+:10B36000F34E927B570B5CD537A6005F0E27F6E7AE
+:10B37000EAA9CEBF6D69EE01BB13E4E95177D15F55
+:10B3800023B4F451576801F47387A88E9B2DC4ED44
+:10B39000CF41FA67E3F44B8E9582BF3078C9313BD9
+:10B3A000EA43D81F01BDB290DFDF42FF460ECA0359
+:10B3B000EB79E9FA94C284E7AA2D8DF5171DC30035
+:10B3C000228D28867B6012617AD4A784F9BDF4F5BA
+:10B3D000C8F690E207FB522041C073BB146A833861
+:10B3E00028BB2F6BBC66806B670A8BFF731D3AD43A
+:10B3F0005648DBBBDE7D45C1B8153A0EF8D79C79BF
+:10B40000D259A37FDA9EC5E2124989E17B11C42794
+:10B41000D0BCC9CEA7F31DC24E7D566070D03C0E85
+:10B420007E0F4EB381DCBB4E7FF8024047F1E575DD
+:10B430003D0E446A66E5E97A71332BE7FECB65B5CC
+:10B44000CC3F69DDD7EBF6AFC177F5AEDB9F3307B5
+:10B45000FC58D7B947BD0BE70BCF820F1FF03D9DBE
+:10B46000C9656BBBC7389DFE5BB7A8D9E9BE1CB2E6
+:10B47000F71F84B876ED36F64EE2F5BF3F644FA570
+:10B48000E91BAF1EB5435CD14D10A043D7359BA837
+:10B490003253822308D739A4C7C3F23DC3667A8CDE
+:10B4A000FD515315FA5BCECE79AFFFFDAB9781F816
+:10B4B000A4FDB5407AD32B4486FE67EF535BD9B524
+:10B4C0003BDEDF7EDA9F18EF2F0E4799D9399213B2
+:10B4D000E112879313E1F6FA405CA4867E14039C84
+:10B4E00051DFD0E13C00B7B459579271C9E9E53A50
+:10B4F000F7C877C9B8F8BCAC70FE088A28BD3D9380
+:10B5000012F815D04D2425F06B48173BFBF3A5220C
+:10B51000BC77F83BE0B34B6DA182EC62BC8F386A1C
+:10B5200018C471F5263E5FB5D2E95B402F10CFCD30
+:10B53000E32B6FE4EB7BFE7B273C1837F9C46BF9F8
+:10B54000902EB1F5ADFB2ED0DB7FD850FF3EBB6F08
+:10B55000D49071696F717FC7C914FD3D16B6BE9B4B
+:10B56000B81E77D3BED408BC7B795383CDA4FFDE4D
+:10B57000D4C0E23888D43BEE5A931ED99CB41FB095
+:10B580003BADFDE8EB3B989F7B21D887F74F90556B
+:10B59000F03F1C78E5ECEB75349F32C289E7B2EBE3
+:10B5A000D239FE568BB8EFF7A70752C782DF696D15
+:10B5B000865FA3EB5CFB02E911297C0E8EBE3D5237
+:10B5C00043C75B7F89883EAB0DB107306E522B6756
+:10B5D000EF14295C1FDDD07BB40BF0F1C41107FA26
+:10B5E000FBED1E765F75AD3D980FFAFBBBDD72C2B9
+:10B5F00077EFFEEE96705DDD421FC6BBCD21612761
+:10B60000F08D7DBD3387C37CBC7EA200FA9FD86AD3
+:10B6100013F93D28EEE7884ACCCFAE492C1FE0A9AC
+:10B62000E232C6ABB54F9F8AF114733B7F8371C280
+:10B630005E7E9FC93A8F0B53D97C3DBD1957007C64
+:10B640003D53457CD3C8E3EFC778F182DE1A19DB9E
+:10B65000878521DB17AC54AE00B8427BE0FF05E7DD
+:10B66000D9BE3895C53B6DE47672B7DDDF3A95F605
+:10B67000D3BD2E5D80FDD0EB4D4965FACC89A9BACA
+:10B68000FF268CFE9BFC12C505EFA3E40790B8894A
+:10B69000A7328C71B8DBA11EF36F221CBA473F1989
+:10B6A00085F3E3B5201B609FED0C9FD6AE13D09FB2
+:10B6B00049E1970BF2E2DD7B1CDF807514B4090AC7
+:10B6C000D8DE344D38EF5BDD4E66B774DE8B762006
+:10B6D000B847A1DFFCADBFC3797992AC779B9BC122
+:10B6E000EBDD73E0475AAA9DDD1B6AE8E57652144C
+:10B6F000DF3F0CEBEFC2052AD9BB84524035C6A10F
+:10B70000C4E987D961749D0138DFAA9D2847C00F1D
+:10B7100020B675E33BBF73C20E72395D5FA7D01BC5
+:10B72000007AD12688FCFDADC05B00A7F51B8763BE
+:10B730003CDB1A31908FFE9DFF25E3F9D8C1C0D9BB
+:10B74000CD73687EDB4419E9E26080DD6BBD7F6507
+:10B750005137D8E19E861A7CB737A2E04BB8A4A92E
+:10B7600092BC0CF1A44D2B4545A0F5C341FD7E8153
+:10B7700092027831DEF6E11565707E9623822F897C
+:10B780009C10D8BB202D2B6B14D8D716254B30DA44
+:10B790002DB7A432F9F2ABF4E02DA934F5DD75B77D
+:10B7A0000231DD1B62991782BF506B9355F67E30D4
+:10B7B0007B4F2493EF4B66AF189DE7C5BC7B3E35AE
+:10B7C00091374C617ECA1F5C1962FE453893AC42CA
+:10B7D000FF22FFF3E1BE66F1DCDA312998D9B47AB1
+:10B7E0001ED6877EB2693F999562B48AF6BB3D3D0D
+:10B7F000B00DE5C9654E841391FABA004E91CB7233
+:10B80000FD10D77AF7A491BF8127A5320FF7CF0497
+:10B81000391A1991F24637F0A91659053ACF5C79D1
+:10B82000FC06F89EEEFFE12D906636FFE14E900794
+:10B83000E97D7F69C4EFD365937F2FF3CDF73F8711
+:10B84000F2CCA06CF2139E4E0FFE3095EEFBB6F2DA
+:10B850007018DE3DC51DCD8EAF63CFAADEE9F08E38
+:10B86000F589AB45FF765E8EEBDAA444D632B85547
+:10B87000825CD3E1B646547BE01D65ED2A27E247A2
+:10B8800009E9457E9503A7C8C5F17DC97CB37D391B
+:10B89000C44958E7F308A75BF883772531FE9ECAB1
+:10B8A0003139676A0AE0F5E315BD3ED0E3D7A52735
+:10B8B0008E4F38E966ED1D49EEA71FE7E5C012BBC4
+:10B8C0002A300D8C85D44DB43448F39CF83EE1E326
+:10B8D000A2FA47C4F3BB6D2AEC0FD4B7D3FD3BF0FB
+:10B8E000F249F40F1E08FF0ED317DC657A7FD16C86
+:10B8F000DA7E7DE551F6CEB7C270A4AE8DF18B3AFB
+:10B900005F9F13CE2BEACA89B29DE39BA6C319FCA5
+:10B910005D5C5ED55ECBE09A554EF0BC157C62F066
+:10B920004E5936D4A3F0CB6A5BB51CF791F46AC5C7
+:10B93000B4DE7AE817F6A799DD3B21A4CF89F41B82
+:10B94000B6E17923A5F75FC179626DE7703C6F8737
+:10B95000EBE9D05F061F3783F7D74DFB01FFDF8987
+:10B96000361BD98EFCAD97405E5D497119F1B3BFAE
+:10B97000BA8CF6AB562ACA5A1D0F743E4649632E3E
+:10B98000951700B7B99AB61CF0EFA8537919E6914C
+:10B99000BAC9A1C2FAE76E7AEA0ED05B527D7D6D1C
+:10B9A000C01FEA26B2F96674D2EFA8DFA8BF82FAF8
+:10B9B000759D0E958DC7E157C9F18CC3E1663EEFC9
+:10B9C0009BB7B279A78C8884013FEB5652B8425995
+:10B9D00088E13DB834BF1091AE0EC3FA3D5A36F639
+:10B9E0003B6C96852E2CF8A7AFAB96AFAB76255B5C
+:10B9F00017E1F444A715857E6B2BD93AE712D65E82
+:10BA000084EFB4FF9BF97A6AB52731BDB9CD61EAFD
+:10BA10007F5BD98E5E984F61B9AC0A0867F63E66C7
+:10BA20003E5F577E331B2FBFFC4984176930CC170C
+:10BA3000FDA2863CA5AB132F51C2A27AAE0081FCB9
+:10BA4000B4DFA3DF93F11CA56493795D27DA473D4A
+:10BA5000D009FECF7B643CAF785CF4BF558076A8FC
+:10BA6000AC32FEE3FFDD0CE0D33737E3BDA93DD5B3
+:10BA70000CFE27BE4922800FA587831900EFD2C391
+:10BA8000219ED6E33936DE13AB8AE331359DDA04E5
+:10BA9000E097B1E247E7031FA0FB0CFAE008E3BC24
+:10BAA000E9FC32DBB26B200E296B62468D8C4FFABB
+:10BAB0005ACA0F6F9909EFD7661DDA720B8C934340
+:10BAC0000CEBA1E5459E62A4BBCC43B414EA351C43
+:10BAD000BF0BF6A393BF2F5F0A33CBC0F410A4991A
+:10BAE00094BE3B32609E12995A11E7070FDE533520
+:10BAF0001EF80ADE29A9C0344A2A06F30D43FDD1F7
+:10BB0000BCBE2624A837DAA39AECF207EF99361ABE
+:10BB1000ECF7F5A027D27D6A27CA87101FA3F94545
+:10BB200084FB7A7BD4594EF36BA8DE08FACB86B23D
+:10BB30003F884077EBF7113FE04766F01F0EE33E8A
+:10BB4000CE71A7E3BA25997400FD1F1C7D7C3AECE9
+:10BB500053E48088EF48D4FCC2BD2515F4A1D75921
+:10BB6000FC49F74BF528BF6FCF9713BEC34CCEA14E
+:10BB7000275AEB6794CE443F5EC1A68DD3E13E4E7B
+:10BB8000DD74C97F39AD9DB5A9BA1AF4183548B12D
+:10BB90006B389DF7D6F1AB8008D519ECBC4A9DCE29
+:10BBA000BEAB5359DAD138FF22B0DBC3BB24173CFC
+:10BBB000853CA69DBD57D7517ED619A27A6965F5F9
+:10BBC0005EE737E9F76395540AD2EFC7A69C75C1C3
+:10BBD000F9CCFD95359900CF7D6D66BD8EC0636A49
+:10BBE000D40E1AEB08073C745E9DBF27084F9B23B9
+:10BBF000DA554BF3B6A7DCA0E10CB26FDA3BBB67BA
+:10BC0000019ECE2DC3F0E441EB3DCBE5C59C867E85
+:10BC1000BC5755A811768E1ABE1799F2CD9C6514A3
+:10BC20006ABDC8743C9B987D1296022F025F0E97E6
+:10BC3000876468A2F3B3CED2DA9DC0CFFE067A1D28
+:10BC4000C8B9FAF978FF11E9DF06FA507F7522BB0F
+:10BC500029989A82F33DB1F59AD7C03F3DB781E963
+:10BC6000FB055B3F14703FA8DE9743FB2FA8C4275A
+:10BC70002AC9DC9561E758D89F1291A82ACCA787DA
+:10BC8000809D10A6F2C70807BDDF7FB6FD3AB70357
+:10BC9000DB07C1781E165F8F9BAF27DF4FD793401E
+:10BCA0004E5FC5C7BDEDBE0F0F4C02F8AF64265204
+:10BCB00041F86DC169984781767EF3F816F447E143
+:10BCC000B9D3CDEE437B2AFBF0DE9195BF833A0FCB
+:10BCD00074BB2DF5CC7866DF9BF9E9A03CC72BEB54
+:10BCE000F77C0BBF1AEBE8B912F7770F7BEF9C10CC
+:10BCF0004AB74E7C065465EFC446F477C9EBA1DE23
+:10BD0000188F5B013CE81CFD870A80CF3AAE2FDC20
+:10BD10005C4ED05EBD39AF17F58539CD5C5F90FCC8
+:10BD2000ADC06453B7A693B506FD0143FCE188B1ED
+:10BD300099EB0BBAFCE772BBCED7DB867215F40326
+:10BD4000835CADD5985C2DF031B95ED746C75139CB
+:10BD5000325719F51226C7D54D5C7FE07238938FA4
+:10BD60009BD5C6E45526E8115E083FD0502EE35916
+:10BD70005E765C6F1956CEE46566E7E328D75E0110
+:10BD8000A7CB04E01B4C5E8EF8CDAB1A80C9473FB1
+:10BD900077513EFD142FF729543FCB88EB676B4456
+:10BDA0007ECE44987E88B1F5749E8FF1FAFAF71D25
+:10BDB0007C7E8F1FCAF806F0D707C345E36D06BA2D
+:10BDC00045AF27CDE757B273FAFC06764EEDF1CFBB
+:10BDD000DB69339C3F34BB99BDD9ACE35543D407F1
+:10BDE000FDE2FD40E4E3EC7DA976FE1E946E5F7DEE
+:10BDF0002795FB3538FE2493273A1FF29080B79C95
+:10BE0000C2F7586427F26B8DDA4BB0B663E1A6DC5B
+:10BE10008540EFE1AB2B61FEEB27FD15E32E0A9287
+:10BE2000D88B7F073B93C1E14BF175CFF457991D38
+:10BE3000DA2B26BC2733D123E13C7B24920AF07411
+:10BE400085D9FB84AE8972C2FA177A18DF943DEC6B
+:10BE50001ED1FA493BF17E6352F92C11CD96409EDA
+:10BE6000EAF2B613F6793221D5EE59AD1AF2FD4851
+:10BE7000D086FC95A0DD19E6BFFFA295C9E837EC96
+:10BE8000B4879DB01F1B2AF9BE2ACE6EB88FFEA5BF
+:10BE9000F785C203F6B93D2046E07E793BB554C72D
+:10BEA00032BF0EFE7ECE096ABF1BCF292EF3881C3F
+:10BEB0004EAA08F189056D0CBFD64F92711E6BC753
+:10BEC0006777DB0A8DFC97C12998CAE0B476D28BDC
+:10BED000885FE73BBF790D774E3E6638473CBEF939
+:10BEE000A1228073FC9D96C090F717E635FC66F2A0
+:10BEF0008E04E70303E56047B9C10E8C5C6F3C67B5
+:10BF0000F9770FB3AB431EB3FF0EF8AB1D8D8B4813
+:10BF10002EF897F65C12F1A2FF7E313BAF5DC0CFE9
+:10BF20006B4FEEB806DF53184BD1CA9E60DFDF6F50
+:10BF300034BFA7F0FE830FE532BF46C414E7B160FB
+:10BF4000E73363D8BB661AFF9D0CA26655B177AF85
+:10BF5000514EBFE8D71CF8EE5C10F9900CBF5301AE
+:10BF6000FE76A0E062B8D7DF83A91BE8B778F07B44
+:10BF70006E19540D43BB8B0431CD26F598FA481841
+:10BF8000D35CD283691ED8B9C52017FA31558922EE
+:10BF90001203DF2F227ECC979020A612EC5B66FC6A
+:10BFA0005C42DAE5C4F80B38BF00BAD7CF29F4F306
+:10BFB000FD199EDA4E0F327BF379C5524F609D0713
+:10BFC000E11F45BE3D87B3F0C33F1ED303F77B5649
+:10BFD000AC63F74B74BE8E760DEDFFD10C2607B423
+:10BFE000BB05E45FAB53AFBA14E1D8693F6D3C6F5A
+:10BFF000204E6709FCFE8BDEEF1CEE5F98C3E51F49
+:10C00000B8B7D9FD3B3FDEFF99037E0643391928B7
+:10C0100067F7AAF57EC4D42923873ADF33B4C778FB
+:10C02000E45A8BFE7F4EB96DC9CFB5B6FF8C4E2852
+:10C030003BEE877BF452359F9D3331B94D1149C595
+:10C04000766D8EB7D10E0B5F1630C2E510C77F5DDF
+:10C050009ECCB5F8F5ADE95C89D385A51F2AF9D248
+:10C06000E15E04BE6962A06BFDDD5BFD77D2160464
+:10C0700042720E6BE6C3773DF8BCC3646B4D0E4D48
+:10C08000DF83BCC19F7FD81BFAADC7608728817A48
+:10C0900091BFFF8774388FD3E165B6CE6AE06F2712
+:10C0A00042C40FF6C30252BF1EF431F2AA0DF9DBEF
+:10C0B0000574DE7205D86F44133330AFC1EFF97CDD
+:10C0C000D0C8EEE51CE7EF56EFE4EF249DE2EF5415
+:10C0D0008FEDBAE32AC08393FCBD6A9DFEF571C75C
+:10C0E000F6A4CE06B93FB6E7923AA8377697230A68
+:10C0F000702EDBD71E04BF10BCCF9242C7C9A3E38A
+:10C100003933808F1094B7A73A5322ABE93C4F756F
+:10C11000D9902F7F5C2EE23B23F0CCA58DCF2F2D25
+:10C1200003FAF9FB8DA0879CE47C447FEFF154B5C2
+:10C130008AF6F10B7BD608702FE1D46C15D77D2AD7
+:10C14000A7273F83C2C7E765F1E525BB1DD1223A8A
+:10C150008F858FBC5E540BFCAF28BC30D13973BACD
+:10C1600097F1BF534F108C873BE5E2BF4FE4ECF1F2
+:10C170001AFDACA95EC164179EF2F0DF39CA3B47D5
+:10C180003D1E5F4EDC3D5E46F73D5E388FBA37F5AB
+:10C19000C7787FEDF813EC9CE285CD75F9E08F1A36
+:10C1A000EE55D939FE9E9F60DC38AC03EC683A3F0F
+:10C1B00015E6776FEA5B27C1FF40DBE1FD0CBDDDD3
+:10C1C000F13D75AC7E17ADEF45B8136F05E0038305
+:10C1D0003BD9CDF884AE3F2E8A64E3EF2DC4CB4526
+:10C1E0002C8729BA28FCC7EEBE1ACFB5467B3398F8
+:10C1F0007C507AC6CCC4F987F3611D7B2E09E58398
+:10C200001FEFB8FE7B4E52381FE030C3131AED35D6
+:10C21000F0F7F7DF7E0AF97B9958FFE7BB002FF7AD
+:10C22000B2DF1FB9E3CD8DA2917F4CF432FFFABD8E
+:10C23000A94BBD701E757CE09D9C308BF7D9CFDE7D
+:10C24000615DC469EF7837B59F283CDEDFFD032CC4
+:10C250003F3EF08E4D0FC693BDBFFBF90C486B7986
+:10C260003C3F895C83F445E1D2E64C20AF06EE45C5
+:10C2700045D87DB733027F7FF43E1D6EF5F24CD377
+:10C280007915A3EFBCAD8587505F8E24BE276795D7
+:10C29000F7D6F764CF750FF828A7D363FC9D92A556
+:10C2A0009ED0B7BD09E4486DC7927C80732DDCA990
+:10C2B000C33887AF5E0EF636DE3761EFC946114EE2
+:10C2C000FA7BB1643C2B4F67F9C5DE2BD7804E74E7
+:10C2D0005C7F7F56FB1A2B2F64E56DBCFC254F70ED
+:10C2E0002E1B9FBD2744B9623AFC2E85CEFF92AF2C
+:10C2F000DFFCBB143F029E3C01FB5B8AFD49B4BFDF
+:10C30000B1FF7A7F3ABFF997FB71FEF7F6A3F361AD
+:10C31000A04B08D9237EFF98FF0EF8FDB3EDC9AC02
+:10C3200002133FFF6473712B9C037DCCDF0F71748C
+:10C33000AE2220976EDEB4D1F4BB26D677BD9A78B4
+:10C340003C895C4CE9CC40CFFBBD4C8FDECFF92162
+:10C35000FCB90DEFF9C05F673686DCA0FD378ABFF8
+:10C36000F35E46C2A85F8D213D9896935E4CC791BF
+:10C370007E4CF198B4185C7D7E1B7FAFB70A16BF68
+:10C38000D819BA1F42753F75849E017C82777B0560
+:10C390001BE8454B27C3FC7FEE55F4DFF52496DF01
+:10C3A0004B8BFF0E880A7ACD0CDF507A0D51A4D347
+:10C3B00003F11B45F8EEEF0B5EEC37D9EFBF2DB75D
+:10C3C000BC7FC2EE11EB7058427A300EE285AD2B85
+:10C3D0005E1E4DE1BF70B707E5C1C8ADCDF8FB5F8C
+:10C3E0000B496F36DC2F1DC9DF93205DECF785F418
+:10C3F00077224677394CEFD42DB1FCFED022FE7B5C
+:10C40000618B2CDFF5FB9B1DF021411C81F5FEE7C4
+:10C410003BDE24EF369527FE1D18EBFDCFDD3D22D8
+:10C42000C6F7AC80782121CEF746EFA87798F1AB1C
+:10C43000E7D212C3FB4E4D829FD9D39E94C083C2D4
+:10C44000E071462A0CBFF60842C238B26FA6897C5A
+:10C450001F9AC995B49FA6C59202F666532405CFCC
+:10C46000419B1466175EE0A971829D4ED2457C47C0
+:10C470006E9A6D0AC697CB4BA48BE0DCF3D0F685A1
+:10C48000BD707FA1C927A19FF68274760E4A7244BF
+:10C490007C1FA059D99B3E07F6C9CDCE1947282449
+:10C4A0000271F007BA6F1721DF44CD96E1308E108C
+:10C4B000EAC57B373912E1E7AF33C653FC2BE0F80E
+:10C4C00020914EBC7F3C75C93117C8F502BEEF13F1
+:10C4D000D20A99DF98EFE7B686A3E980A72F75B750
+:10C4E000FE761AEDCF1E9130AEB5ECF3A637A6D18D
+:10C4F000F1FABB658C67D5E190BF5232DD9FCDBBB1
+:10C50000D59C972DF788256228A7F9517C7C78C0A7
+:10C51000296A8CABCA0A3067A1E246FCB8284D20D4
+:10C52000786EC3F3A3214FF174973D5C03EF61EE86
+:10C53000FA93807E8783DDF30A304EFF995001E045
+:10C54000B78E0FD6FDFB1BD7872806B8F8FD6017FE
+:10C550001CD659F1A7B99194823FDA193994722106
+:10C56000ECE3613BBE23D5C2F56F89FF4EAF8E2F42
+:10C57000D6B4C582772D9F5F8378D74FF16EFB10BD
+:10C580007827292AEA09F63CE207F2B767F5E62A96
+:10C59000B4DD854FC97E3705D9B4C7CAD3409FB92A
+:10C5A000F0F9EBF09E2CC00BDF796C904BC1EE776D
+:10C5B000346495C2EF1D4D7BCC8DF878D6CDCE7FFF
+:10C5C000A486543F94377557F954035EB7362AA5AD
+:10C5D0005229BC6FEA2C85DF456A4DF23BCC23D251
+:10C5E000C520F897646EFFCF4B63F39D97968AE959
+:10C5F000CD3C7F9FA4CD84F9DF47F107E2050EDC37
+:10C60000CAF077458E13EF3DAF78A978F8507140A6
+:10C610003B1B7DA500B7ADB7D6A2DFA37AF921D722
+:10C62000E540E71EA702F868F38EBC770AE0FBCB73
+:10C6300076BCF7D5E4A952E718FAB37927A25FC907
+:10C64000266AB96014DD9976E4722907F045DB02A9
+:10C6500092A869C373974B943FEDF268B9022DEF2E
+:10C66000D8F03CCB0FD3B608B4FC071B7EC1EA8FD1
+:10C67000D072E1973F7EB4E13F5879A9B605F20F39
+:10C680006CF835CB836E41F5984737FCEE72B82FC6
+:10C69000DD64F7CF02FFCE8FE9FCCBE9FC7B78BAF3
+:10C6A000278DF973F4F2BDF09DC27B1F4FADE54FAE
+:10C6B000F2764F2729FF292FDF9FA4FF9FF376D122
+:10C6C00024ED0FF2768792B47F91B73B9CA4FC6572
+:10C6D0005EFE4A92FE7FC5DBF52669FF5BDEEED586
+:10C6E00024EDFFC0DB1D4952FE062F7FD3D2FF5B36
+:10C6F000BC7E1FFF9EE7697B43A37897D7CD5EF68C
+:10C700002CF3B4A1FEBEB5BE12F1BF6902D33374DF
+:10C710007CCF83784D9A2F52585C5591C2ECB85F0C
+:10C72000F0FEAB97976C00BC5BF14B1BCA532A47DA
+:10C73000F0F774B5E52CEE65C54BEC3EC88AE51202
+:10C74000BECFAEE3E32F2CF3DFC6E7D7CCE7FB5C2D
+:10C750005A113F6FF195CE30C67B2AE6BC93D213B7
+:10C7600084EC346731F952B6BCC6390AE407952F18
+:10C77000C0375BDC7214EED1B72812963767D52824
+:10C7800050AE2912CA9F96AC1AE71CF4E764A07F4A
+:10C79000A280C7ED352B12DEE397D2A762F9B4C7AA
+:10C7A0006628C0479B497F3ABCCFA7AD94F0BCF642
+:10C7B000407D0D7E2F48FF281DF8F38174B6AE43EF
+:10C7C0009E175DF08EAB749B88F26224C08F8E5BE7
+:10C7D000B4528CA8B4CA21658508F9079A99BCA2FD
+:10C7E0007F9EF186771477DD5EF532C4EF34AD932A
+:10C7F000F077B6E14F32C88312FE3BA5994A8649CD
+:10C800005EDDC7FDB89ACF8971782512F1197FBF17
+:10C810003253E1E769B619F88E5971D82C9F0ADBBB
+:10C82000CCEFD81458E493555E8DA8A7FCD150DF07
+:10C83000E1534CF9CFD3F87B167EE2077D66C5E362
+:10C840002B2E8750769D5FEBF2E5BF005F71521291
+:10C8500000800000000000001F8B080000000000A6
+:10C86000000BDD7D0B7854D5B5F03E67CE3C3349E7
+:10C8700066263393C97B1220040838811023BE2614
+:10C88000216044B403A2E2A338E11920C9044A2B71
+:10C8900056BC4C48C440B186DB8840810E2A8AF5DC
+:10C8A000D1A1458D18EC808878ABBDD1D25ED4D6AD
+:10C8B0008EC855501EA3B648BDB5FC7BADBD7732C2
+:10C8C000E724516CFDEEFDBE3FFDEC619FBDCF7EC8
+:10C8D000ACBDDE6BED3DE7CFD3BF2B09695D19BD64
+:10C8E00062A89E902D2B4DC314FA6CFD72DC4C5245
+:10C8F0004E4822D5E27F482264F54ADB3065182194
+:10C90000E779FB621B7DE92264AB129E4E9CF41911
+:10C9100051484B2121FB96C904CA4BB34C11236DDE
+:10C92000B2F4D5DF5D3D1CCA4B641FF1F67DAF7DCF
+:10C930003EBAD2330CC67F259D60BFFAA034ECD836
+:10C9400038FA6F25E809A41232A443391A3711FCCA
+:10C950003B4FFF2B6CA7E592BEB25E1FB0D9AC84F3
+:10C960001490A476743E8AA6AC771DB6074BA17FBF
+:10C9700005FBD7CE23AF99AE3FA95FA3C7A62AAFC9
+:10C98000969A4BC810FAA47305F8845D7264075D2B
+:10C9900067EEF2BB261CCB2024E7A0A58DC01A3A77
+:10C9A0001E24C44D880EC6A6EB5624BF97E808691E
+:10C9B0002B2CF349F479E8690B83539E15E16490BD
+:10C9C0007C99D7D0A7510ED8A07FFAE787FEEFCD8C
+:10C9D000B36C5F5B08C5A009E090BB9376984D8B64
+:10C9E000E1DC35FEA1749F28B8C904A8EF69F7D32C
+:10C9F000F5EF947ACBB5508E460CAC3D2131F8BFA3
+:10CA00005DB2C4EB895FF110F29424F1FA91B5356F
+:10CA1000B9B4BD621BA5F80899DD31BA5D7F39D480
+:10CA2000CBE27B3FA9A4EB83F17819E0F2C4015E6D
+:10CA30001FBEB4BD86CE6797418C4FC2D07E972C67
+:10CA4000B372B8BCBDE632DA5F35FF3E9CBFC69F0D
+:10CA50008BF3B9466727A4D97665BBF592BEF9B6C4
+:10CA6000D827B5B728849CF2C6D3E87691C6EDC71F
+:10CA7000DC8476B57A6630007024C44702A309F9D5
+:10CA80006FC98BF822F64FBFBB2A9C435F9D39F8D4
+:10CA9000455A297D8674F18329147E8D5D4193BEAC
+:10CAA00088C259EF0FE714F67DD7B87B1A095238C0
+:10CAB00085BACBF039C0778714F99FFACE64B88075
+:10CAC000F14EC5DE6C7A925635EA82EDD621D89EBB
+:10CAD000B0FD1F787DE2FB534FBE79238C77DA1BC4
+:10CAE000774F01BC8C51B80CF09D68DFD4554500E0
+:10CAF000EFFF62F1AFB48D27E4263BA333A234FBF2
+:10CB0000A07DD4D461F3D17AB3BE23E0A3EDE9567E
+:10CB100046E4CABEE72ADB506CAF7DAFA59FA8896B
+:10CB2000644CA5781D6E507C3B0894C329636879DA
+:10CB30005DA332AE854E6955D91FC69642F9192BB1
+:10CB400031D2726BC3014F29D091CF40287B21EBAA
+:10CB50002E8966011DB7351A663E42E7138D2DF505
+:10CB6000CC2BEDEBBFC54E098FCE7FCDCB94CE2E17
+:10CB7000A24F7DD42EC1F7C314027468B6D37DA62C
+:10CB800065739683840BA19D751DD0E31A7DB0B6A5
+:10CB90001ADA65C964071DD73C6C466D359D87C799
+:10CBA000254B3A9C47CD91F9B4BED56600CE467E62
+:10CBB0006B9FBD13E0F484E26B063A7CC26AB585D4
+:10CBC0006905E58D7EA05B6598330265A38E3447C9
+:10CBD000E9FC72CA48206AED9BE76F397FFCADCD56
+:10CBE00080F35D678E4EABA2FD5896CAB6301D6FBE
+:10CBF0004DE3869EC9749C9F363EFB460B7DBFD697
+:10CC0000AD109887D5A9C40C69148FAFA573A4F390
+:10CC10007EAA256003FE997029E4215A6F196A20C3
+:10CC2000DE243E682DA5E524FE94E154FC66FAFD61
+:10CC3000497BF0D7363AFEB8D70F9BE07BCF7859C7
+:10CC400006B2892A6C9FD3CAD5FDD82E53F7E3A824
+:10CC500051D73BA7AAEBDD33D4F59EDBD4E5ECB985
+:10CC6000EA722DE0DB786848E75C41D7C1AA8825E5
+:10CC7000FEC94A9286F0790BE06F29967D001F73FA
+:10CC8000E323C7E7D3FA1CE02774FE640C89ECA009
+:10CC9000FBB93FFF87DE3885B3D1D1ECB597F68776
+:10CCA000474E9EE91AD82FEB50C546687BEB1F4FC5
+:10CCB0007C09FD5B4952BB42808F3F0EFB0B7F1E00
+:10CCC0003A9F54F88717E0DDFCE7BB41EEBDA1F3C6
+:10CCD00001BC731A151CFFBE19DE88AE903527B44F
+:10CCE0007D1A6F9F665AD7A31B439F7F5CB34497FF
+:10CCF000D61FAE6ED22C015D52FC407941EA08CAC3
+:10CD00008B7B65520F7843C995407F36F880F29946
+:10CD1000890E03E2CDE71C7F28A6C950EFB6B13ECD
+:10CD20000D5973CD40CFF71C64F87F8F81F5D3DBAD
+:10CD30009F17074511047C52679755FD6CB0F1367B
+:10CD4000BCECB2B3F2AE038E6B802E37CC708C0588
+:10CD50003C31CA2408FDA5E79AFC23E8FACCAF1AB7
+:10CD6000C212ED345D2107F40EDADE426E0FD07987
+:10CD70006C3A6409EBE87BF3BC7FB711E01B7636B5
+:10CD8000EF5DAB7CBF033E90A853108E6657876D56
+:10CD90006C295B4398CECF01FFA0FCB16A58A70D68
+:10CDA000F6D35CD581F2DB5CD6D10170DA3455461E
+:10CDB0007DC23157467C36E745DF184ADFEBE7C9CD
+:10CDC00036E8CF4105BB8176F293DC8E4000FAA5B0
+:10CDD00030972B18AA40BFB8423A4E0687ABD3B95A
+:10CDE000FB0E89F69301FD8D61ED014E760EA75283
+:10CDF000BB17F1D3C9FBCD184ADB8F61FDB455F4E5
+:10CE0000F523F671532D89C0FCC4B8A29FDEFE89BC
+:10CE10005F02BEAAFF0D851BDD2729DF8493BB6758
+:10CE20001189180B013E81E6ED48D756F210D08BE0
+:10CE300033B71AF028FBD0E6E9F218F8CE82E3E81F
+:10CE4000E79108E071B6424C5738407F09201CB585
+:10CE5000F49A75A0E37A4A23BDFBA2A5DF2C85B422
+:10CE6000EB1CFDE938CBE9AC2E1E33003D6BE82509
+:10CE7000EB50E2FB80F45ABADE9672BA0CE04292B2
+:10CE8000DBEBBEBEACD345DF980C9B9549E50405B2
+:10CE90007DBE663C42FE6184B24464EFF921C0F776
+:10CEA000ED8C7F102AAF28B1EE1A6B9B68053A5DB6
+:10CEB0004210BFAA9F5B77CB6F687F6787196C2092
+:10CEC00057F20E75F4807C245DC1E1B00F5B94E0F5
+:10CED000CF5268FD96239904F8F61A339909F8ADF4
+:10CEE000703CD7CA97164E375E90739E7FFE29F42A
+:10CEF000C1E850F7281BA5BD96F5B14326D7FFA280
+:10CF00009E4586A19E957BA0A7C50AE377F8DB4DD9
+:10CF100014BEE6D759FB302D8715805F4301D0E161
+:10CF2000FEBCF90827E56D23013C1DADF347A04C7D
+:10CF3000DE3113E0BF3B9FB9ADDE0BFCC73DC50B37
+:10CF40007CE8DF81DE29BC3A38DD6BD7AF18FC41C5
+:10CF5000D027B4EFD7027C713F03C7EBE83E8E7E4B
+:10CF6000D840D6D2CA1279767B21D0C51ACA7F6939
+:10CF7000ED6C9DB7E94752DFFE3C61AE8AD8C1EE49
+:10CF800058692241235DD73989042971E639DFAC1C
+:10CF900002FE934F6212C8D9FC66AAF0025E2DB35E
+:10CFA000906012BEE79E53B0FD13667FC4CEF9BFFA
+:10CFB00089F2013DFB2779C21120754EC6A3407F3F
+:10CFC000D13F69790FF80671D6F87BED8D22C05FED
+:10CFD0002AF7E9784FF1F5EB290CF563E97F56392B
+:10CFE000661CD3BFFD2F397C14933506FC52B1BEAD
+:10CFF0007604F98B4D3999DCCE1461F2863490C8F1
+:10D000003089C105CBDFB3613987F25FE358D4FBC8
+:10D01000C34698671AB33F88DFEF75BA815E08028E
+:10D0200039D744DA4DB41D623BA5B72CD26346BD57
+:10D03000F900F1023D5088D93F4841964500AE5B6A
+:10D04000A8884EA603F12CB2B17D5296EBD05E1AA1
+:10D05000F59219E7A36F261133E84330370A6F655D
+:10D06000198928606F2D3760BB229B17BF339066EC
+:10D07000D4679FFAF2DD6CE0D39683541FBB08F6A9
+:10D0800059463E65B1A8E98F62287E17E7F8B17569
+:10D09000A50DF7B9D73E0B1EE6FB1C6F017991BFBA
+:10D0A000CCA1DA5FD12EF75C0E098E4BEE3782FDF4
+:10D0B000E50E3D209152A8CFC7FAAD2BBD5FD37FBF
+:10D0C000D120FD67211E0DDE7F2ED66F8D1DB65F30
+:10D0D0004741B12571C01EF0F6E9D75A38E72E5303
+:10D0E000F3E58BBAD4650117B3DEEF9C46616EFEA3
+:10D0F000BEECDB4EFBBBF888BA5D6DE1EFD1BEED57
+:10D100006B1F735E0FEDA9FDBD9DBEBDF4B8BA7D6A
+:10D11000A0EA653BD0715F7B36BF2BCFA9DB69F7F7
+:10D12000473B5F3A2FD70D49F39A6832AAEA67D690
+:10D13000F59B97EBA6A4795DE551B70FB60C3CAF14
+:10D140006B4A8C5F392FD1EE3B9517D64EBB8EEBD9
+:10D150006B8D83C09DB5BF69E685F57B6BFD57B7C9
+:10D16000BB7DB9769C30F2875AC93FCE41EB67C38D
+:10D170002BD017AD16D47BB5F812E1F26902E87333
+:10D18000F43935D53FC1419F954077F46978FC0F5C
+:10D19000B7007F39F4F4C84CE0EB3920E7109ECC9F
+:10D1A000AFB0ABC1837E8500A7532A4FDA805FEC16
+:10D1B000DA49BF4B63F34AD69F321A985D6123095F
+:10D1C000A467A12F39884D62F638D377061B47DB59
+:10D1D000FFDDDC1E98B37C22799FD2E1B3065B951C
+:10D1E00002F6D93609F58139357E5D2AC58F09EDFC
+:10D1F00012FA8DE6DCF9BD71C0572E39E6ED8AD3FF
+:10D20000F77322761F0CDBD443FC118A5799BA2599
+:10D210006577D3E703FBA9FEC3CB4B00DFAC7E2FC2
+:10D22000D81B753023DACF497D73990DF8E677ADB9
+:10D230007EE09B7533FC6FE17AFF4EB512DA6E1E0D
+:10D240005B3A79AE739AC14BF58CBADBBC95A0F70B
+:10D25000D445CD7E7C9A8862A1EBA8A3FA183C3312
+:10D260000D4431C3D3424CF0AC58C5F4AFB4CA80BE
+:10D27000A18E8E5FD7FDD85FE1BB054A6C1FD32717
+:10D2800023B8EEBAEE57FF06FADA3C7FC000FC6224
+:10D29000D44E03D349393E8C8EAACBC00F92CB65B6
+:10D2A000317579DC2175F92D07C38B3D526414EC7F
+:10D2B000CF1E2AE0C02E0E3F654479B17FAF11F733
+:10D2C00067F1C796EDE07F9AB8D88A7CFDE39F9B13
+:10D2D000D11FB5478E3E0DE5F0D3296857EF7B7B14
+:10D2E0004F8544CB8B7E912A43FD0B5FEA10CEB075
+:10D2F0001C3D7DBFF8E911DBD7D2F78BC7452B6CFE
+:10D30000F4FDB32309E9817A253206D6F7EC3F74A0
+:10D31000D87FE27163E4218A0F1F3FFFD8D377D112
+:10D32000F13F7E3CC721D17DB914E4016D37E16145
+:10D330009305EC8C091F3F3904F8C5E29D46D5BA28
+:10D34000B63A24AE3778D300DF06F3271E5DF31814
+:10D350007E5F72FC08E2DB1E7D58B6C0FAD730FC57
+:10D36000D2B67FC4C1E48D98077C5748F7E7CC0953
+:10D37000CBED7E5A1EBE510DDF111175F949079391
+:10D38000EFB349D2FB42E8AF68B507F4D4ED04F53A
+:10D390009992E37FBCA510F46823D31FB4F3788679
+:10D3A000CFE3E73FA7FD30FEA063FA335D31A5C7A9
+:10D3B000C51C8F5F9098FE4AFF96E550BC5D0C82BD
+:10D3C000BFA8EFFD62CD3C44FF4B1C8C6F38B95DAC
+:10D3D0009D785D87FBF1D1CAFA71C786F59FCF07AB
+:10D3E0002B9B47D4E8FBCAF3372E399845BF6BD83F
+:10D3F000E5423B51BC6F78FC25F7ADF4FDC99D8A31
+:10D400000F54D7869B1FFDF10468F7B82E0AF385E9
+:10D410007AF0479E8CBE9C06EDE66FB18FD525ED68
+:10D42000C3828DDF1F5193C40FBF293D08FA6DE001
+:10D43000F6ED73953D937300BF374A3E68B6387A70
+:10D44000C3F5D782AEB245E71B46EB2B1412D08D45
+:10D4500045D37B063C1B763D73309BD687F68EAF5B
+:10D460008075AD9503D78C06FCDFA6473F96162E38
+:10D47000A7F97ED3EF6332FD7EED8DD6FA8815FBDA
+:10D480003D00E5FD250FE9E2E067394EF9137B7FAA
+:10D4900044A63479BCFB9E31E04FDCA3B7B6039EB3
+:10D4A000EF4965FB107E4A877C9EC4D83A2670BF40
+:10D4B000F1E23F751A14FA3C7E7C555A15A323E419
+:10D4C0002FC0949D747DF50F8F46BA5BB0514D27E8
+:10D4D000A29D98EFC288BA5E8B1F6919C2DF404ACD
+:10D4E00092F14CDB2E636AD80074D5B09CF2E32431
+:10D4F000FDA7E1588701F426ED38A00112B1AF3A3B
+:10D50000C44FE2C5F59AD97AA9CA6AA2EBFD08FE12
+:10D51000C5FCDE12D8E58B245C22593C92D47829D4
+:10D520003C174F27B5F0DC23C57EACE3FC0CFDEFC8
+:10D530004FA5203F3B698B3FFA53C0BF27F37C6167
+:10D540005A95CDFD7227BDB134077D9E01BA00FC0E
+:10D55000B3B1F2A26ECACF297D7F7CCA807CBD2583
+:10D56000FA521AECD7C9A7CDB24CF7E5E35D19D54D
+:10D57000E0CF3919FD4D1AACEBA3684635F8E50646
+:10D58000E3375A3E25E4F97BF0CF4B287FCEF08F6E
+:10D59000C900F8B66580324E32339ACB9A07A07F25
+:10D5A000F19DD3D05CE605BEF15DAB0FE8F3D20C84
+:10D5B0002FBEAF93587FF0E7A7F59F1ECA7808F6F5
+:10D5C000FFD0BEE27490F39F126F3AF0DF29AEC035
+:10D5D0001519948F78AA7BFC3AF0FF4D21BE56FABC
+:10D5E000CDFB3ADF0F6C14CE7309953BF02C0F1A6C
+:10D5F000D05FD2E6C279CD51484CA1783A07E4E237
+:10D60000182C239CE76C9122AD741E73D7A9D739CF
+:10D61000BFD3D8B7BFF4BF8584324620A02D49EDD3
+:10D6200068FF0B41FE51F82D3291580AED77D12356
+:10D63000EAEF169318CEA7E1C9F3C681E0F8570EBA
+:10D64000C7292EFF4D192AFEA547FEB59804AE80C6
+:10D65000711773393BCFB80FE711BAF3CE1173A925
+:10D66000DE7066F95D23E666801F907D47364A8846
+:10D670007F8B6B482C8FCE6B71B7141B0D7AC061FA
+:10D68000B63FA27FB28DB5BB85EB29F3283C40EEB7
+:10D690004F78520AA7523B669E899A60C03FF8BAFB
+:10D6A000A03E9D96EB4907AEA791C4711EDFE3FB38
+:10D6B00007112980E75F0FB37D9B50BF5D07933A49
+:10D6C000B4AF221DF0EF33E2C3FDA3FA04313BFAFD
+:10D6D000E307C0DB9F049FFA2DEA327924A95C049A
+:10D6E000F0A4E5243837ED3E6FF40F00DF077AE54C
+:10D6F0004964C4B4D1A49FBEFA2E87FF0337CCCFB0
+:10D7000002FABF1FF4B76CDE4125F04B22FC113149
+:10D7100013EDDF328EA8FC13542FC272C74F5EB9CF
+:10D720007A632E211BF441F4F3CFD1050E4248EA6F
+:10D73000842BD809F83A47F6E72BC807FCC568A739
+:10D740002E67FBF1E0D8E611CD03D8A762FE1BA43B
+:10D75000684C067EF03C93EFA9E5097D3089BE9EBA
+:10D76000E6FC2D7D7FFC600EE0CD3312FAD3374905
+:10D77000A44DA270F6D06D0139B0497AEF20C88D62
+:10D780004D577B492BAD2FDF3D6DC9CB68E35A7CEC
+:10D79000109F68DC5DA56BB4E2FA999E99D2BC5DDE
+:10D7A000A6F599B7978C05FAA0EBBE7D3A7DFF2BC5
+:10D7B000BEDF5956860F9E55E1C2A5E04FDD1F58CA
+:10D7C000F232D0F5680BFAAD3229AC521DF86C0775
+:10D7D000FDD1435A2468F7401AEBDF25EB6E9F0614
+:10D7E000E5B1ACEC5821F91F42245E8FFD671AA900
+:10D7F000C9E060EF410FA6DDF977617D04F72D7375
+:10D80000627319F49739843D9D86582EF4F39AD8A3
+:10D81000EFEE2C19F8ED322E3797EDAACA74D0EF3F
+:10D820005F3B6952800FBEE6117A5CCC0A7A1C1904
+:10D830005AC2DA73F9B4AC6C6226E0AF335FDDEE46
+:10D840008CDE9F3E0EF8FC1B3A8CB7FCC5EA4FB746
+:10D85000D376971AD83AB4FBF8A70CA6D785CE4949
+:10D86000249264B787669E45FD38744E51BD3FB91A
+:10D87000D2442249767B43FDFEC9D0AE91F4AC067A
+:10D88000BC6A8CA69048129E5F6A19785C81DFA101
+:10D89000733A121E87E89B0BFEC5D7F489D5F300B7
+:10D8A0009FF64AE8070A517B389C3CAF7319249CC9
+:10D8B00031D03CDDEAF7743DAA72D7E7D88E54C662
+:10D8C000D3609CD3B6789A9DAF0FDA09B97526223A
+:10D8D00087F517617C8FC92FF0CF58997E3A0DF6E6
+:10D8E0005749A44D4FEDEB57D4437F8EA4759E9EB0
+:10D8F000692031DC97048E0B700B0F276473F727B8
+:10D90000062FC8F1EE7D0837812FC9F00B27C77BA2
+:10D910005A7B6232A5F9CC4ECBDAD21114F5F673EC
+:10D92000FA0E5BD7827FD1AD9355F49E52DE4BFF4A
+:10D93000C86E1E80E813FA2F53D7429CB9B7CCDBD0
+:10D94000F77E1F4E9B02F5E5A5ECFBC2CEF4FF5817
+:10D950000532887430BD5F49E4075293CA264DD919
+:10D960004ACBA393CA364DBD5353EFD1947359FBA1
+:10D9700093A9B17C9D8FDAB99D195314CA7F4E6665
+:10D98000C566514B94ACD3B9A7D4D072633993AB6D
+:10D990004DDD920F7D6E1C7E4D3EA6EF597D71C30D
+:10D9A0009C528043CF41E00F0D5D924DA274608D7B
+:10D9B000EE8A6119BEF3267D1795F0BB86E87BF8E9
+:10D9C000DDA0FD97C848E76B4B8EB276D10F517E34
+:10D9D000AF6EABC3B8B888FBEA48C09F23F5C57DDE
+:10D9E000059F3C9DE57F4966786D4BB68342D06FBD
+:10D9F00092BF45B47F6774F7EF413D4859F6490B34
+:10DA0000E8A17F6AFC703CE865EF7079B0418A8CD0
+:10DA100080713793E0089077DF6D1CB64FA6EDDE7E
+:10DA2000D5C7B7426C6B71E7A8290A6DF76E6A3CDF
+:10DA30004FA23CA6D15981F07CD715DF0AF07CC9F2
+:10DA400079312BE7C5F3645A5ED259C7DA0F8B6F71
+:10DA500085F226E7B5AC3C3A9EA7B38189731DC217
+:10DA60007F876D607A9EED647C44CCAFABC8FF5D70
+:10DA700027ACA781C991AD546F34517E396BD14722
+:10DA80004FEDA07098F5C314E4633B4E5E3F85E90B
+:10DA9000D5E18052017E53F687720EF9B5827A463F
+:10DAA00016C83647DF7EA4E6F778510E8C6CDE058B
+:10DAB000FA42E6AC529403A519FE0330AE78CECB01
+:10DAC000A64F0ACF034E1BE3CB3A19E3C89977A5BB
+:10DAD000A25E75BF99AD87D20DEEAF95EFC71D4E13
+:10DAE00026B7EE7032BBED868C49D8CFDB927F93A0
+:10DAF00089C2FD6D3D099B81CF2EB4A01E7CEB76C3
+:10DB0000CA3728DFEEE4F3EE5C9F158138F8AD12DA
+:10DB100009005F11FCA3D3EECF7224D9139D65B425
+:10DB20006CEDB31F3BA7F9B32C4E78BA6588970804
+:10DB3000BED459C8BE13F228B3958D9379FF888758
+:10DB4000601D290AF3FBCC9B59FC500BCAF5E9B8C0
+:10DB50007EE2F76781FFE0D8C22219FC41627FDED6
+:10DB60002AF2AF87F5DCC2FDE9629FC47E1E7032E7
+:10DB70007B788E8EEA0574BDFB5C415C3FD513C695
+:10DB800070BF13EA0907404627C19728F1F1F0FE5C
+:10DB9000FF23383DFB6DC0A97139E517F205F00B85
+:10DBA0000EBF0D524C9FC9F805DAC1F01EE4CEA697
+:10DBB0008CE07F3893F25266DDD5887AA19857CAF7
+:10DBC0001DCFD5DE44FAD399566F3B0CFBE5EAD363
+:10DBD0002F7DC27FC8C779F76D13C60BDE35449120
+:10DBE0006FBE4BED9816E02F3CDE5DF1C3C5AF81F3
+:10DBF0001D27FA9DE0D2617F6B247F16AC6F0DDD8F
+:10DC00007713CC7F9A01F57821573BED914D906FBA
+:10DC1000D079432EE61B9C212CAF23BC3C05DB5D59
+:10DC20002A1F25E08F4C5C62C37833C513ACEFBC70
+:10DC3000B918F33E283E84CD504FF109F2E33ACBB8
+:10DC4000E882A0BF9B47623DD8B9689FDE6CC2FEE8
+:10DC500006C013E6DF1DCEF21A3A0B391E2E2C42F7
+:10DC60003C74B7323F2251FC63A625C979B78BF1CA
+:10DC70008194F2F833FF0538BFCE8C7A29C8588CCE
+:10DC8000C57464627F74FFCF3B597C0BF16CEE8FDF
+:10DC900053791E99AF02E07A6F2AC3CB2D661627FF
+:10DCA000DA42F560E48B1C7F45FE5A90EB79F17AFD
+:10DCB000390DF4855457AF9FC00F763BFAA969FD23
+:10DCC000ECB8F41ED85DB3C3BA9811ECA8F649FEBF
+:10DCD00078921D027F1067BB9DF355B291A0FFEEB5
+:10DCE00076F82E0DFAB7A4415CF176F81EFCA42B51
+:10DCF00026A9E2670530E6F8BEF969F97E819857F2
+:10DD0000C783FEE47144FFDAFEA81DE975B910CEA1
+:10DD1000B174B0075A74B88FDA79C637327F737C22
+:10DD20006301E29DE86FB079FE5997F8BE44E5E0E3
+:10DD3000FC89CCBE16F6CB3C6EFF92156AFB0CFC40
+:10DD400023BD655DFFB2D6DE83B8B8BA3DD35B5262
+:10DD50004A13068C977825D5FC05BC0683C3E46F6F
+:10DD6000083721F71E34537EEA00335A42BCDD786F
+:10DD7000670ACA31A7213202F06A9ACB8BFD6E8600
+:10DD8000FC1494ABCCEEFDEC35E1AF50DBBB214B8A
+:10DD9000621BC02B646174747A6F2AD201191A9FB6
+:10DDA00005F95D67F61809E06F93142F06BA3E2D4A
+:10DDB000F9EBB05D4B8A17E8E97DB907E11D020870
+:10DDC000D27985C2FF837945A12EB5FD7B9AFE5796
+:10DDD0004FF1FDB41CAF807E043F00FA47BDA89E02
+:10DDE000C55B9A641206BBEA5279F64294FF376724
+:10DDF0009387F0FD7BC56047093E4FDB1D901C0CEF
+:10DE00006D805E1A38FC9AE4A3D8AE01F283008ECE
+:10DE1000605F815F0B2A93FCB14DEB3EC6FCA4A66C
+:10DE2000DDEA7D6EE8C303E9BC04DF25E105D271BC
+:10DE300098F301C2FC14352C5E9CCACB29B53D98E1
+:10DE4000AF14E27E0BD7FEF864E027A9E551329BC0
+:10DE50003E43C7999E31A17BFB4B600FDB6B7BF28E
+:10DE600000FD43DCAF27F659CCF392EEF5E8A7109E
+:10DE7000FA49929D3962BACA5FB00ABF03BB15C6A0
+:10DE80008BC3AB2CD87E26D73670B946E51FF2D7A8
+:10DE9000791DC351FE817C02BE24EC5EE053C01F9D
+:10DEA0004EB8AAB7009DB6B8AB1F74B9D878A8CF42
+:10DEB00083B174C9E0FE38011FD10EECDFAFF2B7B9
+:10DEC0003DC6F1D569E07C9730FFDAD2575DC2BF1D
+:10DED0008671B4A5923713F0F5035D10FD680B4809
+:10DEE00018FD3B0BC17F459F0D9CCEE773BFD07CD7
+:10DEF000EE0F02FF6C72BC0FFCA4C9E54584E12F54
+:10DF0000D969ECCB8301FF4D0D89A5D2FE1AC1BFA3
+:10DF100004CFA8FABB26926078DF75DEA88A277640
+:10DF2000B275DFCEF7DF5E13D1017FD864667E2540
+:10DF3000C13726AC60FEA7F4B1FEC27B00CF5FD52F
+:10DF4000A35FE2BFF9BE09384D71556F77D1F61660
+:10DF5000B0D3A0DD3D46E497C7A81CDEC5FD21D3A4
+:10DF6000C1FE5C191C0179DC44B1E527DBA7E2B9ED
+:10DF7000768FB91EF0E74D97ACC2AFD52E9677835A
+:10DF80007E22E4C729A86F53B63106F0ABA248C879
+:10DF9000433206FC53EFE9993FB7E9466B10FA8B21
+:10DFA000CB8CCFFC99F3B33FBB58DEE59F7BE515E7
+:10DFB000B7EF38FE88381DF86B92FDE41FF4B65FAA
+:10DFC000CFF36309AE77C3429E87DD8BC732F2A3DE
+:10DFD00094D200F2DD4BE56AE4478913562FC0A5C1
+:10DFE000F6E38685B08E4F675A08C4CBE672BFED64
+:10DFF0005948B873F5F969BF2E8E55BB7604F249BE
+:10E00000D1FE6F3027577F7FEF1ECEC7F61036DF69
+:10E01000709B91F9D7F9FCF71C1F19013CA67A6D8A
+:10E0200018F85C629799C93BAA87027FDDB37B78B9
+:10E0300004D6F39E9EE90B61CA7FD9F7C14DE00774
+:10E04000D9F34B970FF273428B3E1A03FAE39EE328
+:10E050003FFFD56FE1FD5EA30FECBD3DDCBFDE6091
+:10E060008815A3BECCF3121BD262C5E0F77981EF0D
+:10E07000578385964B4179083ADCAEBE38187C0749
+:10E08000EF8F46985E7E94303C08AF63F14A0ADF1A
+:10E090002C9847624D26C6D1605DB00FEFEF1D8D05
+:10E0A000F3DEA0E7EDEF63FADB515E3EFA7C19E6A2
+:10E0B000E99D091830AF36743FD317E7C8DE6DCB42
+:10E0C0008157BE9882FEC2799D6F605C23F4E305A0
+:10E0D00053A13EB468C575E42BFCFD205792FDD4D6
+:10E0E000A749221FEDE0FAA2688C8E7BBA7B848F51
+:10E0F00085ED3C18246AE2F99BC7287C61DE89BD66
+:10E100007A84FF85F60FEB05BB14E41BFAB593E3A5
+:10E110002A280FD47196AF2B9FD6C78BEFA4E3AFFD
+:10E1200070046BDC497A62E8C52CE477EFDFF7799D
+:10E130003EEA131D2C2E704CEF9F057462AF8919B7
+:10E140006627E95FB7B9B9DD61E47A23E583C9746D
+:10E150002FEA2BAAD574269EB7BA19BDA5F2387E30
+:10E16000FF7A91BF7ABD11E427732941BF5EECB7F6
+:10E1700080C7D7261C4FEC837CA8866819C6EF0A97
+:10E1800056C4902E29BC63A0FF1FDB94CAF8095D1A
+:10E1900026F433BF92A0DE3A5FC7F212E61BA91E37
+:10E1A000CCE438B6FF605326C2A16215D3FF12CF6C
+:10E1B00048C817459CB18EB0EF9F6B7B2FACA3ED89
+:10E1C000EB764A6594B592BAB62ACC5B58B4A510E2
+:10E1D000F77F02E7BF738CFEE24D806FCFA522BEB2
+:10E1E000D1F150DF6E80DCACB1C8970C200FEB771B
+:10E1F0004A642D498E8B6AF020A28EAB4C8832FE89
+:10E200000D728324E969420E81BC201AFD518D17DD
+:10E210006195DC6BE77015FC1F21F6157290EAD151
+:10E220006B808E2BAA19BD25764908E746D2CCE231
+:10E23000405C0EF5CE87CBB10F744C6ECE37AEC7B7
+:10E24000E73677218EBB08E225E8FF4F18802F0EB6
+:10E250008617DB06C10B810F3FE3EB68384E6297F0
+:10E26000D3F11A569058E318F64C1D837299C9677A
+:10E270001393CFF0B45C809CD6CA67AD3CD6CAE19C
+:10E280004C0393B7020F92FDF2A08F4C5811D1317D
+:10E29000FF6BAE0DF2F1C4BEDC90E17F227B7C9F70
+:10E2A000BE153A6232792F8272801459C1AF54552B
+:10E2B000914BD71FA2FC1BE82E85C2693B7DBF9501
+:10E2C000EBE54372BD081F0FCFBBD12B0152668512
+:10E2D0007DEA413B3AE12268D70AF86E4DA5DF8D11
+:10E2E00085EF183DF67E6F226D96A4EFABF798513F
+:10E2F0009E9C7D3E15F344A87C28B0D3FEDCEF50F5
+:10E30000FD9C964FEF4945F97E9AF37BA7F0579015
+:10E31000D5D8DF9BB0CF2EC0BAEA1CF0FB12694AF9
+:10E320000EB048A13736DA07F3D3F3FAC29E1B19B1
+:10E330009E1951CE9EB5C77F00653A1FCCEBFD0FED
+:10E34000BEEFA1DD13CBEE82787EC0EA63500D965E
+:10E3500081DE60D42DBB11FC4193752B1277D275F1
+:10E3600034E659315FB8A6E08F7FB899964FECD666
+:10E370001323ECFB8EEBD363F099E2F70C249F1789
+:10E3800046F4AAF3688B77AACB8D5175394492CEA7
+:10E39000AB51102CFF63D9150792F0E43377AA1321
+:10E3A000F7DF4B7C90EF4C74B7A50707E097E2F9D5
+:10E3B000F94ADF1507F4982FF6851BE9C06B00BDFD
+:10E3C0006636E0C300DFED7233BFA8D1D87C1CF203
+:10E3D000CE8D2F187D2DF4AB83EEA02ED305F64AFB
+:10E3E000E220ECA7B1E0E4189083D5057FC738D8C8
+:10E3F000D9BB890FE073D65C85FACDD94D662FD88D
+:10E40000659DF956E6AF78518A484C7F9F3ABE0227
+:10E41000E29EB80612DA78F5097648829864DC5FE5
+:10E420006ABD7880CFF8D19EFA609AC5B68A7E57C9
+:10E43000BF91C9DB06D293067CA03693E15D48F715
+:10E44000A4C144FF59D8E61FD142E7BB3860C1F3ED
+:10E4500031CA974A00F0EB5EE83249FF2FC8647278
+:10E46000A6D1143754C1F87F9F5BEB2AEAF36F19EA
+:10E47000F4CCBFA57495C572E8A70B96CF413BA716
+:10E48000378EBC89E5252DB8B30EDFBFB4C988EB44
+:10E49000FB60AF8478FEC156B6FE051BCD5EC89FFB
+:10E4A000BED2CEECD905F4BB81D77FD50958D7872A
+:10E4B0005BEEF0817FFE43C2C609DB981FEA431B77
+:10E4C0008B77435BE8E7C3DD43508FA9DFB8702A41
+:10E4D000E68B6DD5F9408F207B53D1BFB360EBF74E
+:10E4E0007F7B09F88FA6DF520E70B8D2BECC0DFE2E
+:10E4F00012DA2E10617A31CBC375543E0A7478E576
+:10E5000097137BAE047D692BA5934296E70E7AFAAA
+:10E5100081AD57A15EBA609AC50EEBF26ED9311982
+:10E52000E4C787D3B2655CCF5312B1011CECCBDDDD
+:10E53000F07E81A40406C2A777DDCCCF565560F5E6
+:10E54000C5E0BBDFEB104F285DDD08F2B371AB1EF9
+:10E55000F5DE03D3DFFEC3CDCE3EBA5AA0EBB871D1
+:10E560004292DE13DA72ADC01312AB007B8AC14453
+:10E570004B5FC68215C5301F2D9D2D58D55CCCE252
+:10E5800055DF8CDEC8164A6FA3A8BCCE94985FE313
+:10E59000C2E9AD3EF31BD01BC975A8ECA8FE7C2DCB
+:10E5A0008C7014FE7E938FF8775831AEEB9728DF8E
+:10E5B0005D9FA9603FEB33D9B920E56F4B77BE4E25
+:10E5C000E1E3CE0CFE3013F41FE22F033CF2266C85
+:10E5D000D570E6C7CAF538B285E9CDA0DFC37E6F36
+:10E5E000709147D726F91DEECB64F611A5FF56E8CA
+:10E5F000E7F45B7F3F08FBD3947F720C8B77FE05BB
+:10E60000E383D66E1657B6FA121837D73B03887FC6
+:10E6100082AF877C4CEE68D7753893D97321670237
+:10E62000FBF98587D1A1F0B76F5E6E413FE9666760
+:10E63000C4CCFC0A610272696AA58EC5C5B89E7514
+:10E640002DF73F9ACA5F22100F2397B1FCADD7CBAD
+:10E650005F523268F9B795937C786EAEFCE1F62292
+:10E6600058F7657A5E3F240CEBFE4F7F15D62FF5E9
+:10E67000E8BC40D753CB591E22A94F437FC9EBE5D5
+:10E68000EF3BE726CD3F404C5E2BC593E9D4C8490C
+:10E69000CE9BBBEE32B3D79A845F9F7648B54CDFF2
+:10E6A000F5A6CF18CDFC212887CBD5F058EA31E06C
+:10E6B000B82DEEAAA701CE575EC1F6E3A3A78C1131
+:10E6C000E07F1FF173285AF8EDCDE476E86D25AAB6
+:10E6D000F8BCD310CD07F9F8B1A4FE6E51BB0EE320
+:10E6E000E30BDB2512A1E37DF4F873F9C0C74FEC0F
+:10E6F000782E7F76D27CB4DF89E72B991C5FB91F17
+:10E7000050EBD71DCC9F2BDA9DD94882A6217DEDF9
+:10E71000CFD47F81FEDCD9DDDC1FECF70F75821DC5
+:10E72000C4DB6BFB4B70FC90BA24F477087FE6D116
+:10E73000430F43E4A477FFCCDD857272DEA1784EEF
+:10E74000E0FB763DEC1B5D8AB99D9507DBAFC1E828
+:10E75000711DC89FF17DFB76B47D483AC0D1D0646D
+:10E7600055083B0F56027AFA5662F1013D19B23D47
+:10E7700056E05FCB4D6963E09CCFE766F6745AE8DC
+:10E7800093EA6B79D925F8DD1D7200F3DB3E973BE8
+:10E79000F03CE01DBA66CC9BFE8CCBBB5C5B60D7CB
+:10E7A0007CB44FA298474DDAD5F075B732F991A8ED
+:10E7B00033A09C1270BE74F60FD04E1D607F3602DF
+:10E7C000DE6457B277A59E42AE2FC7314E60AE24AD
+:10E7D00036B0E75B2F09E37CC4FE84587322754B87
+:10E7E000A827437E4A8A03E3A161FE245607E98DE8
+:10E7F0000FA470BB9668E201946D85A19D9827B027
+:10E8000031C873B9DF1EED282EC7782AEA9FD02FB2
+:10E81000BC9F5DAAA03F1DDA19C67E3DBEF5E2256C
+:10E82000CF179C2ADED75B068C3F4C857337B47DAF
+:10E830001E9583A0FF119F5E75EE660BD59BC11ED2
+:10E8400013F15D9D1C2DF3A01DD21307FF88A1C2FB
+:10E85000E405B99AA28B96C0BE69E3BDB45D21CB35
+:10E8600033C8B5835C11E76A9A964F0C40DE7AAFE5
+:10E870009EB197D9474D7756E1FB89DDCC7F1E6A63
+:10E8800037E2B9C0509784F1AAA6802162423F8640
+:10E89000B705F62B4CF530B01B3BED2CCFA9F36A36
+:10E8A0009B2F4C92FDD7F16D77A1FFDA8A71BA7F69
+:10E8B000367E79269502E0A2A4F854BA89C911EEF1
+:10E8C000DF76737C12FB2FE859C43B534B0385A0C2
+:10E8D00071EF76DFFE1BCBF86F901742C6DEF7951F
+:10E8E000792164EFB570AECD04DA3CAF876951B9D8
+:10E8F000D97B4ECEECC5B8566F3DDC6F60EA92F81E
+:10E90000F78BAE9DA4601E282F57AE83BCEEFBCDC7
+:10E9100044355EF2FC144DFF7ADABFD5CBDB876F4E
+:10E92000BE66D2508CEFF272D78FFC747EF7EBD5B7
+:10E93000FD210A8A737DA6BEF12A72E4FBD65DD65C
+:10E9400027BFA93C5FE671F5C9F17BDF9EDA7191C3
+:10E9500017E8EB33CCAB15F238E46479225ABEB534
+:10E96000D22309FD773288D8D533EBF03E80DEF82C
+:10E970006EF7343FDC8B20E2BBA11501CCAF05F96B
+:10E98000EF41F97FF2837D04F4CB8F50FF0F9D534D
+:10E99000983F88EA1112C543537715FA3D216D144B
+:10E9A000E4A6D8FF455C2E81AE0EF81DDA72D30EB8
+:10E9B0001DAD7FC7E35F87FD723B503BDF1D1E66C9
+:10E9C000BF874AAA37013F208F4804E4F6DA924F06
+:10E9D00051CF687A7ED2F8E4FCF0855D0FB0FCE29E
+:10E9E0009DFA01D7BFC3A363F931CF3F83FECC8F1C
+:10E9F00022EC584ABD12593301FC2AF532685AA458
+:10EA00003C527733CAFF99741D745D3FE27227B49C
+:10EA1000F3FA30E4AB87E87F00B2CD81F9A8EF6F5D
+:10EA20009E69B242BC2654327B09D283CDE287F57F
+:10EA30006BE7D91B1FBED382FEC6B55DFA5AD09BC9
+:10EA40002AA89EF42B3ADF3CC7945A1FE54B39BAEB
+:10EA50005D65DFB3425C7D60395C9DCDF6B14D0AEA
+:10EA600084BF538EF98C24394FA7A08BE963DD1E38
+:10EA700083EA5E886E0FD3132F0BF74C049C7B51F7
+:10EA800089A7805E1C22FE4FC0CE2501AB17FA81FC
+:10EA90001B1540CF72AEF4A23FD7E48CFFE822D41E
+:10EAA0009B14B433841D71FA79E6FF1A9E157C1508
+:10EAB000F0B24217FFC977006E3F62E77589C2F86E
+:10EAC0004DFEF5D6B1E0AF323BE33FA9F5627E0DD6
+:10EAD000FA1FD22F6FC37D78D1496C009F89E13A2C
+:10EAE000454A9233826F4CEC3D17E3443F693567EA
+:10EAF0002FC3E86E7D6042146D3B9FD1A7171CFAAF
+:10EB0000FB0C055E0A7D413605D19EA99949ED436E
+:10EB1000C0CBD5898332F8E59D3DA82F3646251C0C
+:10EB2000A7B1E49798FFB698E759F5E63B2971CC71
+:10EB3000FF7ADF93C2E3036D4C6F253D68FF922798
+:10EB400019FCA9DCC4BCB03EBDBD05DB89FE0C3C94
+:10EB50009ED0C8FD351450587FDA23E209AB78FF08
+:10EB6000228F8D8D4B146F45B27F61C3342A49705B
+:10EB70005EDE3498EF13E6C0E7404747EB65E6CF2B
+:10EB80006E4F89C021CF0D528F1FFC8EE1B281CF15
+:10EB9000B358B3181EA5EF4F4C467FFFF383E5BB78
+:10EBA000B2FCD64DE347627E7879D72793013F4880
+:10EBB0002D417AA4FCE282F25DED595E1CEF5BCF41
+:10EBC00077F549FE87E83327CBAECE77F531B88BA2
+:10EBD00038A436CFF574564C617969F16D3B407EAF
+:10EBE000761931DF6D6AD72B47C00F39D544A2188B
+:10EBF00097D5E8012F665C3F348BAEE3CCA90FB606
+:10EC0000DD4320DFF9591FCB9F53CBF5C1F4788C3E
+:10EC10004D24D97B157C1FBE2D3D5EF0DD10B78BDA
+:10EC20003E96123F2E86F5EDD5D9063AA732314BE6
+:10EC3000E0DF20F91ADD03E76B887350B5F1425528
+:10EC40009CE95AB19E6F18B70A802F7980B895C297
+:10EC5000F3B01489B100926750C5AD147BF16071B7
+:10EC6000AB18D63F331CEBEFED17B762F9016D7BA4
+:10EC700033BDA0A737B8128F3EEA85FE0CD84FDB14
+:10EC8000F32911C83B6FE3F06FB8F0B8D5C2AC01FF
+:10EC9000E256DBB91EF67E891C3350B86E276CFE37
+:10ECA000E16E11BF92D11E4DDC9727E68FF567EE1E
+:10ECB0001B857E9F39222EF522F387CDE1F1A7F740
+:10ECC000A71763BED660709ED3AEF6EFDFC5E17CBA
+:10ECD000D65C857EF51FFCFB34F433CD077FFC90BA
+:10ECE000BE730984FBE5BCEDECBCB977A714F1B2A7
+:10ECF000F88849461DCF26C3FBC5941D6E06161A1B
+:10ED0000A65873317D2D51A8D17A6F1B2D53E55D27
+:10ED100059A3843DB4DDF62329E807BBD7E9C5F93B
+:10ED2000DEDBC6E2C4E175526418EB17EFF10AB7F7
+:10ED3000C97EE8E7A7594C5EFF2A8BF921BC9AFBF4
+:10ED400001DAF43CDECBC76B21720C9EB2C49EF795
+:10ED5000DA94DA81F400D15F9BBED95405F0CE631A
+:10ED6000F7859C35F867A29FD8518CF702B5A53678
+:10ED7000B7D7B27AA4D9B3E64400EB2F57986249CB
+:10ED8000BC0E98EFFA2CA6A768E13CAF435DD6C64F
+:10ED900069B4E7A0E690E0F0AC21FDCF09ADCF6209
+:10EDA00072ECECDA42BE2F3E8C7BB4E9BD6F1602EA
+:10EDB000BEAF61F7FEB4E432B8C979EC5964AFC1B3
+:10EDC000FBD9889DEB6384CDBFE872A704F4D066BD
+:10EDD0006778FBAFCE5B3BDF17B28A197CED8C5EA8
+:10EDE000DBD64811062F36EF0BF56FBC25F8D2B7EE
+:10EDF000C417DF977C8FC60AF13BE40BE1FBF448B4
+:10EE00007747492487E53FDA906FCEE6F6EA512E40
+:10EE1000AF36D717A5413C73CEF1D5787FCFC4EB81
+:10EE2000AD38FFA617CD688F35AE88E7033E6BE19E
+:10EE300008B355043F9521EF98B07B5FDAD5F139DF
+:10EE40006DDC7585239000F9D2541D2F86F8CF0311
+:10EE5000F2FBBB5E617C0DE563D38AC4A3E02F0E99
+:10EE600038829F43BB9377BE3D59F2E2E7C8DFCEBD
+:10EE7000EC1D8EE7FD66B7A9CF4F9175EAF81F69C3
+:10EE800077B073629DEAF7705E48F55DBF7820D376
+:10EE90004F36188223407FBCF20A96EF706AA14C6D
+:10EEA000603F4F99098FB30B3EEB2B4E9603CEEC90
+:10EEB000C1E41D6D0770E6F99DA27D23EC2BDDCF2B
+:10EEC00006BEAFA79EB9B818F6F5E4AE8B8B615FAE
+:10EED00037E83BFC4017275C414F36C597639302E8
+:10EEE000A8DF897CD60BC5B7E183CEEB7F470E97B1
+:10EEF00067FF737218FE92FD1E2FFE9DE59D86BB77
+:10EF0000D979D13E7FDB4778EFD59973B2047C780D
+:10EF1000B0FE5EF730BCF7984818FC1C15D571FCA4
+:10EF2000AEE20B99803E27F458EDFCAFE2F09B99DE
+:10EF3000EDFF15E8A3C23F5BCFFB36453E63FAF217
+:10EF40002312FA5F4DDE70DA04B48FE68DD3215FB1
+:10EF5000F9159E6720DD920DEC8C858FB460FDE97C
+:10EF6000AE39582F9B6231B0A71A693D94575FA6FE
+:10EF7000CE4FD6EF2E8B25DBAF741EBF00BB24C552
+:10EF80009930007E36817E4CA7D8A4303F7593938C
+:10EF9000A07FA4BC4B6DEF89F8EBE600BB5765730F
+:10EFA000B784F72BB90DC1C25CD8574D1C765EB63D
+:10EFB000BF0DF04EC4C3A7B8FC0BB259BC3C1FE058
+:10EFC000D494CDE617D78BF373EAF37D87F6DD880B
+:10EFD0007AD05F49207DE0BCB1882A4E3E9F9FBF1A
+:10EFE0009CCFCF5F027F8E69F87372B921296F2C95
+:10EFF0003650FC3F296F2CF9BBE4BCB1988AAF7541
+:10F00000F0F3094B313E1DA278BE7C6C1F1E3610FA
+:10F01000FEB731F13E9E4FD96944BF5803CF170D5B
+:10F02000D51F457B2304E75D183DB2BC6A7EEF40E7
+:10F0300003B5E3306F36AACE2BFD69F6B72B0F442C
+:10F04000BBC1FCDD8F0A7EC0E951AC4BACA3A15B18
+:10F0500062F4A399A7D67ED5FAAD85FD79A17C6926
+:10F06000CFB7BCEE6FCA975EF996F8523FFFFFD05C
+:10F07000449AEF5BF0FF9FF076B8C125D82E317C23
+:10F080009DACB3FA597C51C7F20FB47157EF648C41
+:10F09000270A7FABE9595D645521B6C7786AE3DE7C
+:10F0A00054CC07A8F7D6A39EAD8D332E22BB26C322
+:10F0B00016FC95BC86E7AAFED5B8FEE9ECDEB87E64
+:10F0C000E1378CEBFF35FB1BC4195FB27E96114C08
+:10F0D000C293EA52AAB0970E9E77A5CB61FB9EC25F
+:10F0E000F33F4C4A98D893BE1FECBB941C16677F25
+:10F0F00089E70BDD9F9A82E7E83D06768EC023B351
+:10F10000BCA677A8B69FE30239C0F6F167CFDF440B
+:10F11000204FF067FA289E6B0F375A7D20BF84BFBF
+:10F1200048F4DFCCFD98174A3F4539FFBB7CA33438
+:10F1300047FA6671B28D14064974A5A583C1BE1B3A
+:10F140008CAF5C9E13A8CC41BEE51F83F1860BE417
+:10F150004729E5945F837CDE6DF482BD60E2E75D64
+:10F16000C8BA2C95BD3DE7FE3C945BA7CCCC7E1085
+:10F17000E772C4FA0383C2FB9FD3EFF6B902D3014F
+:10F180004F8E55F931AFFFDE542657128FB3FC1E58
+:10F19000EDF914AD3C11E72BC47873C5FEFC1FF1EB
+:10F1A000D325023EFF223FA5F215FD2B83C653FB5C
+:10F1B0007D1F66F79154F7F8799C09CF2B887985E4
+:10F1C0007A585E5C0B9F5F2FBC38FF3F98E35F056A
+:10F1D000FB70F22D9309E297E5E58C7F3605ACE8EC
+:10F1E000FF6F8AB27C98A61504ED7C710ED59D192F
+:10F1F0005C07F878EFDB56BC07B4A96B7B7B11E6A4
+:10F20000090451AF3BFD167B7FD01DEC80FE432BE4
+:10F21000E2AA3843C5F9CF56D796E37CD14E771A88
+:10F22000D5E77B7E99C3EC6FF1FC452F7CA95D424D
+:10F23000BF3B59CFF2B0434EBFAD0AF303981F3B1B
+:10F24000C5DB83FEE7A6DD282408268542FD5DB9DF
+:10F2500088374DBBABCAF05C7FD45C86F7C1BC631A
+:10F2600045FBEAE49DD9111DF37B3F06EB4A2D8F48
+:10F270005C0DFA65011D07FCD827775D5D86FE40B1
+:10F280000DDD097AEB3DD779AB29D22AF5D1E3061A
+:10F290003D938F42AE3D08CA2CE647F0FCBEEE69B6
+:10F2A000649EB5AF6C75AAF31E67664F7A10E6F3DD
+:10F2B000608EC2E3D32C1E5E68A2D667517F3C2CC1
+:10F2C000E4F1F0693C8F81844D7DF90B455F1F0FA0
+:10F2D00017F31365110F4F39C7F4DB229B01F1229D
+:10F2E000B59DF10D42F102F4EBCB123D13E13CD59B
+:10F2F000D0CED86500AF74003FE691C67F7411C4CC
+:10F300001D3294CB20EEB06DF9D8FD2627F88F7A08
+:10F310002E87ADF176D8AAC1B47467060E039E108D
+:10F32000A5B904F0BFFAF77A966FB82605E57D67B0
+:10F330007E03E61B9E7EDBA83A47A37D86C92A0F83
+:10F34000F8898ADA7F877EFFD4DDD28079A419A07C
+:10F35000F48F67EDC1EF94DADE13AE043FCA7D127D
+:10F36000BB4B91CE5EF280FDAFC8A077CCE962E7DF
+:10F37000B1E774D8AB4DC84F251637B9CC897C524C
+:10F3800059738D0CF699D242F0DE324B2EF35B0F9F
+:10F39000EBB4C9B0EFBFFE5237603CEC6F1CBF212D
+:10F3A0007F0DC0D5684C1C8490BD88E389BCB5C175
+:10F3B000EE0317F248ABC7F6D35FB93CEAD5E335A5
+:10F3C000783CD87702BF053EFF5A4F500FFBB5641B
+:10F3D000C2735A02AFDB441EFE97CC8F5BC0F36250
+:10F3E0008EAEFD9F31EC3E3F110789B07B25F5F1D4
+:10F3F000D53908AFF8156158F76EBBDC548AFEAFFB
+:10F4000026EC670DBB7FACA07DC8AACA7278DA086B
+:10F4100080E0E89EC5054097618A07C306C0832344
+:10F42000392CFF48599382FBA6ACC79B968962771B
+:10F43000E3BE290FB0FD793387AD47C461859FF2E4
+:10F44000604EB004F26B7BCF572DB7B0F355FCDCA8
+:10F450006EEAF2B79F82734BDBB8BF78FF8BA3F0E5
+:10F460007710CEAE5124F01B9DB5D71580BD372E39
+:10F4700097E94BA94A0FB15993F1733FE6BD16EDD9
+:10F4800065F97B0ABFCF4859E3DC0EF02CCD08624A
+:10F490007EEFE56D31FC0981176DC730BE46F52260
+:10F4A0003CC7FCD1F392D08B54F250D86B5A3BEC52
+:10F4B000AADC6F572E7E9D9E343D572D072FD8BE58
+:10F4C000226A3BB3B7BDB01BB57684E6FBC1F41F1F
+:10F4D000E20FABF25BE6E57A851E87F23D9BF346D1
+:10F4E00091F7D27B0E9944CC709E017209C4FD58ED
+:10F4F00090FFB351B2F8404FD2E6FDF4E6E390E658
+:10F50000E12C1FA4F92276BF44F3C5F014794166BB
+:10F51000C80B49CE3F4D65793D66C80BA1EF5B072F
+:10F520003DB7EC6D81F13BEFB68973CBCCCF5E4B31
+:10F53000789CE1213CD79CB82117CFC94CAC65FE23
+:10F540003B47C020035E3EFB0F9D1FF86E82D22D0D
+:10F55000E8578EA1FE2CD0B7CCB41EF24D7ACF2D39
+:10F56000D79101CF2D8BBC2411A7CD1EBE4102F92E
+:10F57000D39B2F12EA3BCF0CE3762EF1A27FB83754
+:10F580007FE9BB04D7592DF88C49BD7F697ED62E03
+:10F590006DA601F50CB71C7C1CE3789B7BCC78BF77
+:10F5A000446E11EE5B6B6504EFB3759476A0FFB506
+:10F5B00025C3BF39D7D5873F627E64235BFF1938E7
+:10F5C000AF25F58D7B66E117F9A04F55771B191E06
+:10F5D0006AE6B1B9F7DE143A0E7DFE2297EDBF4F11
+:10F5E000A3DF8AE72F047D713E2CC61F6C9D021F8E
+:10F5F000BF4E6FD7E257B89AEFCFBBE608CB3B526E
+:10F60000E3D7FE95B5E38E515E726065009F67CCCF
+:10F61000525407F941E6C42CE08077E6CDBF0EEEE8
+:10F62000D338939AC887FB385AF2A77E07EEDF38A3
+:10F63000E34ABC0BE5CEBC7F63E561896D703FC7D3
+:10F64000CFF3145686B1B2097965CBB9EBC2A57870
+:10F65000AFD5EA1E904FE59A3C13CD3D02900F893D
+:10F66000F71E58D97E66F27C5452C3F577882CD1A8
+:10F67000726B56990FF208ACC4BBBB07EA738DECF2
+:10F68000BE01C2F29F5A8715B27C058EEF2497FB0C
+:10F690009F493C0CF8DB5A68C7EF7BF9F56E238F66
+:10F6A0003BB1F1DF78869D131379B684D8F240EF31
+:10F6B000B17A89AA2CEEE1208A2D0FCEDDB70ABFE0
+:10F6C0001E2F1FB1044FE426E9456F4CBAA3147FE7
+:10F6D0008FE3D9BB86C27AAF32A8EF33EEE5A7F944
+:10F6E0008C1F9EE1F7FE7558829F423F4752664D40
+:10F6F00086AB5467665419ECA8A73DAE037EE4E2DE
+:10F7000078619FC1E667AF0948F03B18E2DE3D57DC
+:10F7100050417F000976EA407EBA8E05309FAFC126
+:10F7200094C857287E7D610CFE03E8E16CDD7B3FC9
+:10F73000C03860F61BEF42FEC51BFA8E8969202F88
+:10F740000AF97D0ED4F00B3B41DE15A0DDD77B4FCF
+:10F75000E73009F9C3D419ECFCE9141255D0FF6263
+:10F7600063E7A1269717FA5AE9785379FEC6E4238E
+:10F770008134F0034CBE29AEB0784B4249CE97108D
+:10F780004FE2D17B93E9E06A6F5299C0FDBEEAF285
+:10F79000B53E75F93B955F0E4F2EA7533B206F3C4E
+:10F7A000F0AD389E270E5F426C6C5D2C2FF0E7DCCD
+:10F7B0006E1BE521A602C85B744A61B00B463D97FB
+:10F7C0008D7194E72A0996DD3B4D0F9992D7BF5E64
+:10F7D00066715AEEE716BFE3037520579F7DCB8D08
+:10F7E000F0725B65E4A7E001077CABC8315980BFCC
+:10F7F000EB389F17E7AF27A599F0FED5D625ECFE8D
+:10F800007FEDFD93AD7ADB3ED8C7D613740D749CA3
+:10F8100047520D31390DF68B1083B38F1F0BFC81CE
+:10F82000FEAE00BC1FCF7E678962F9D0E4FBBF5BF0
+:10F830005D6CAEAD772B3C3EC77EEFA1A4F7F71F02
+:10F8400028D9D1F6A05312A413161FCB13EB248A88
+:10F850001FDA67115166E7ACDCBC2CEEBD24A44A6C
+:10F86000C1FB7224D1AE05CB0FF27652F72B7F038A
+:10F87000FC189A46D7439F4BF2189F78587E632313
+:10F88000E28935E8053CF1A50C7CEEE7B63C46374D
+:10F8900093D22A3D9037D09AE5F3805E25E023DEAF
+:10F8A0008B7E45BD18CF973170BF4B78BF517E6EB0
+:10F8B000585BBF388FE96DBDE3EA69BFD6AF18D793
+:10F8C000A51EB7F7BBBC81BF13EF457BFC79A60A29
+:10F8D000A03306B7293C5F9594A8F35348A5CFC43D
+:10F8E000F8BD3A1FE52A694516D0E7D5A6C6EE3819
+:10F8F000FDFE158E2757C9C1BF40BCE19559C5070C
+:10F90000803E6BE18279DACF3524B61A90E54C550A
+:10F91000F067F621C82FDAF2E83A9A74C1E10E5A7C
+:10F920003EA5EF18BAA410E9EB9EBCF1FDE727F065
+:10F93000B0779E14FF60DF05FE69E72DF0805C174D
+:10F94000C5C4BCAD24864F0F61F9D0547EB1BC67ED
+:10F950006F5EDFBA28724E36350F05F9FE4A4B1836
+:10F96000F9CF55F69F60FED78305C1CD30AF99170B
+:10F970007D82F7DD104F1DEA5B74BE3FFDBF9C2FFB
+:10F98000A5AB2C782FF440A1EFF5CB033E6150E5F9
+:10F99000018BF969E958CC2344D83D4613BBB7A382
+:10F9A0007E179A61F5C1798D10E4B79663FC0BF36D
+:10F9B00085F770BB2C2CB1BCDD7EFAE2E0F9C2EC1D
+:10F9C0005C7FA38DDD6723EE45FA7E91B8EF86CD8F
+:10F9D0009BF22F7EDF0D963BEBBC68FFF5EA8DF3C3
+:10F9E000981E7A65B1A50DEE0FEC7FEF0DF3EF9148
+:10F9F000E78C5EAE27A2FCEE4C65E39C32B3FCF4D0
+:10FA0000243E4E2477DF7D5C1BF44C1FFC635E219B
+:10FA1000BB5F44F655C07E6C86B895AEBF1FF284BE
+:10FA20002BF867C0EB79A5FE7CF8898D3906E6676F
+:10FA3000A478B5A587409A5BF32370DFE4D5A4F9D9
+:10FA4000B03C04F1EABFA1FDCC519FB07B28FBF094
+:10FA5000EA0386576164825F47A72F6604CF40FBA5
+:10FA60004E7BF49DA67288331A11FE228F504BBF35
+:10FA700049F339A667F371C23DB7743E9F0F349FB7
+:10FA80000BC1EF643CCA240C8F07C373C8D74F1D4A
+:10FA9000DB87E7E92468C81F9F84EFAB7DEDBA21BF
+:10FAA00003CC5B67C57DBFF166168F09A5303D1598
+:10FAB000E232596EF03FB1F16F5CC3F0E346B3112F
+:10FAC000F1655A7723C65F480D8BA7F8E8FF603EC3
+:10FAD00033897F12FC54C6F5B66978FE72C6547538
+:10FAE000BC65A6E92A8CEFDC40983FEDC6197AD5B3
+:10FAF000EF000A38CC24EB3E817C8E999ADFFFD34D
+:10FB0000C2451BAF11F068ADFC6ABA1F91DF1BD76D
+:10FB100019FE0DE33ABE7C963F7741719D03FA04CE
+:10FB20009EBB7FD9B560CB124A17C37F5A8AF7664E
+:10FB30004F722F7C643D2D3FB67924965F76DFBAF5
+:10FB4000EC0DA8DF568CE51AF99359788F79C5CD5D
+:10FB500053E0BEF10366D68FC712EC84DF8FF08CC2
+:10FB6000291A0B26598D2181EDAEB9A8711CE4C16B
+:10FB7000D45858F9B5B2FF1A8BE5225E1EFBC24875
+:10FB8000281F903E9935505C6854891483DF89AAF8
+:10FB900071B0F653C73E9E0D7E829A6A561EE5AB43
+:10FBA0005A3304EAE54F670D248F67E573FB89EB51
+:10FBB0005B014EEFCFF9DF6B83735E01ABE483FC37
+:10FBC000FE40E57BEC9E2B13CB2308F8CB14B80743
+:10FBD000B1DACFFC7B13AD2D59C0FFAE0B1ACAC1F1
+:10FBE0008F6BB316B6C17DFFE99555E361BF275210
+:10FBF000350CE41FA5ABD9F94057177F929F867A41
+:10FC0000889AAE04DE4E13F454A3A61BCA0FEAD999
+:10FC10003EAAE981F6DB88FD5EAA964BBDFC5D43FA
+:10FC2000B75A7C1C54EE13351FEC954FABA3889745
+:10FC3000B9849DE3D90A78CAE8F7DF607E06B9C7C0
+:10FC40000BEF0B24DF484CAC18447F10F303B5874F
+:10FC50008CED3F2FF85384BEC86660B3B9615C5623
+:10FC60004FBFF3C38F7A8979D1F17F8CF059CDE6FC
+:10FC7000B3556AE6BF13C1F47261F73689F576A908
+:10FC8000D75B6161E7D13D84F21DF4DD978DFCAA5D
+:10FC90007987B89C9D610ADC67A46BB8C13E07F701
+:10FCA000F926127E06F49BD72CC108CC472787F78C
+:10FCB000C625F89D073FC693E93E6ECF4FD217C4C5
+:10FCC000BCB4F0681A84AF6AE7AD8543DFFEF4A0E8
+:10FCD0007E96C57F0FAE775D9AF5B4F2FBE01365B3
+:10FCE00046559EE86B752C0F56CCEB358994A09C3D
+:10FCF000942C1847EDF53B69F9DB20E7D2847C169C
+:10FD0000F3BC839F8BFA5C667CEF0E5D0CE7595069
+:10FD1000DB630638C6F38BD87DC67CFEAD95616C7F
+:10FD20006790A501E3C4F17C59E457A8F65BDC4F6A
+:10FD300026E25C02AE4E833717F33D35F09C6D3200
+:10FD40000E1C57D5C65F07692751F8E538FAC35925
+:10FD5000C4CBAED5FAE1AE66FEA96BB91F6E622DBB
+:10FD600083BF63792ADA6D8EF2371432BAEFFE64FC
+:10FD7000B11F3DCEE049C423253E1EFC04AF8F7F5A
+:10FD80000CE344E29E422D7CCE0D029FC1E861B09F
+:10FD9000F91FB104BE80714F493D789F59C263E39A
+:10FDA000CE836021D08BDD565805FE05CA57CF9F04
+:10FDB000076313AAE8FE2D770565B853EF2612985E
+:10FDC00004B9D78EDAA09EF9E709FA8797723B71DA
+:10FDD0001297EF9F3EC9CEC1D7F8473C7819E89FEC
+:10FDE00087F424E2853C6E069F4FB7E850AE2F782B
+:10FDF000759C07F4F3F739BE0DDF28AB7E2F6E44F8
+:10FE0000C4A2BA2F63D44E87AA3C3A9AAD6A7F51F6
+:10FE10005791AABE2C3652553FEED05855797CCF1B
+:10FE20000455FB8B8F54ABCA97C4A7A8DA5F7A7CC2
+:10FE3000BAAA7C79E216F57D1F617F4F891BEECB54
+:10FE400067F0B8F2DC6C55FB8FD3261F02BA9BBB60
+:10FE50008EE56D5791C5AAEF17EB1A301F9A7430D3
+:10FE60003DA699FE8F9F3757304F8CEAEF1900B7A8
+:10FE70008D6A3DA7BE7BFD6AE0B5FDEE99D0E83303
+:10FE80005AFD65B8B30EAE69269717B0F3EDE4627C
+:10FE90007231FFFD10EDBEE2B9FD4F0FEBD08E5871
+:10FEA000FA2AD3EF973EC5F2E18AC9B0743CCF7508
+:10FEB00048472212DC5FD0BCE132A94F8FD1C2C5C6
+:10FEC000E851EFB3D9ABDEE79412F53EA7FAD4FBC5
+:10FED0009C5EA9DE67BB5FBDCF19B5EA7D7605D410
+:10FEE000FB9C3953BDCF5941F53EE7D4ABF739AF51
+:10FEF00059BDCF05CBD5FB5A185EA4AA177C734811
+:10FF0000FB52D5FB56295A413925991BA8C77B1BA3
+:10FF10008675FC7040FC10FB1FA6FF63F4DC8CF9B7
+:10FF2000F5F3E9FE437EFD5FC9BA83108AD2E24150
+:10FF300053D77A8CAB7D533CB8BB80EBA762FF2FC5
+:10FF4000503FA5F2B015F802D5635617807D3D9C51
+:10FF5000DB1D8181F518C1B792F58664BB7A307ECE
+:10FF6000D64F4E723B7B5039A9B1B3DF82EC26D419
+:10FF7000C7D7A15FEB668ED79FC1AB4BC0AFFA343A
+:10FF8000CAFFB7E8442AE9BCDE8279D371DEB28CBD
+:10FF9000423FC8AD24A6C77802646EEAF0DE4BCCBF
+:10FFA000C3ACA37A393CE770FD601EF7937C610C0B
+:10FFB000EE2C60FE9102378C9BDBC3CE6FBD967139
+:10FFC00041F73BFC0EFE49DBFDA92010857E6A4C03
+:10FFD000DE650FD057FBB9FF894C65F99F44098C4A
+:10FFE0004EBE4FB1AF1F16377D410A06D1CECE327D
+:10FFF000F9C0CE1E95434C5920DF3C91228853FD19
+:020000022000DC
+:10000000BA4016712A942B23398E3C951D5D6A47A0
+:1000100078451C1827F886E3FEA6C07F10F041B48F
+:10002000FFBAF51A0CD125CC9FC07EBFE430DF9714
+:10003000876F34C6C02E1378742465D6419717FD98
+:10004000E187012E336FBA7A3594A5FD19DEA574C8
+:100050007E67EAE268DF53F81F81F11B4C14FE74DF
+:1000600089A7F282C3D301190219DC4919183DD0BE
+:100070007924319F8912C70B4BF03D1867BFDC9381
+:10008000EF0378283D78FE8E5851B921A70C03FB69
+:1000900003051CAA53F26EC3FB748D461FD817D5F7
+:1000A00012DBD76319B7CF82D8E23C39E08EE9542E
+:1000B000F33E03E335D8EA0AB28AC0AFC6E70D3F84
+:1000C000028A70F7960EE827E7F3861C128CEFDEA3
+:1000D0002D89DFCBC1F273613BC6338CF26787E1B8
+:1000E000F7FD12A3658CF76DB1D0AE29BEFF27874F
+:1000F000B7B8EF9CBE67F97916F6BD67838CF1A39C
+:10010000FF07EF54F02D0080000000001F8B080057
+:1001100000000000000BE57D097C94D5B5F8FDE6F4
+:100120009B2DC924992C6421102609598010266121
+:10013000111471588251034E006531E24C12206453
+:100140008100DAC64ACD40D854A8A122A2A20E0846
+:10015000141568B008A8D1372C527CDA8AADB52EB8
+:100160009597002A3B3168A57DBEFA3FE7DC7B33DB
+:10017000F37D244F7CCBEFD7F7FBC7D777B9DFDD13
+:10018000CF39F7DCB3DD3BEE31AF2E6043187B7E19
+:100190009ECDA92A8C7999C3CC54C6CA99CBCC32AE
+:1001A00018FB7CF4BFBFD1EA602CD2E1B13A8632B1
+:1001B000764F9C21F58334067F9E012591908C8C8F
+:1001C000632C99B1EFF1EFA6AB53C67C8CF5C074EC
+:1001D000B5810D636C929DD1DF2C180BDB4D662E23
+:1001E000138E7307F39870DC3F5C34BB5814A4067D
+:1001F000282F606C2AF3D1F7E9CC4FE95D2C40F54C
+:10020000EF66AD947F3F22AF773DCCAFE489EC4CF5
+:10021000066D2E795B8761F9DF2D9E549C6F8DD51D
+:10022000734F3C7CBFD0DBF36522D467EB60322395
+:100230007E78BE25383FA8F7591F779603F2E3ACC6
+:100240008E21F9E98C1D34B0CA661B948DEB41F305
+:1002500067467BE6A4815DF5B3943118FF58475497
+:100260001E1B8479972D19D67F335F3EBBD9555D10
+:100270008CEB2C546D2C1EE07FCCA1FA2D3066D176
+:10028000686F4F5C17FC45FAE2199BE852D9C3002E
+:10029000EFDF2E812F50EFB7F9AABF11EA4DDC3006
+:1002A000FE0CB62F1E3D795934AC7FFC77AD43026E
+:1002B0009016F5329D68CDE1637C0FFFFB866D1CC7
+:1002C0001703E9AD49BB8D0CE67F6B5F6D79712E2D
+:1002D000E4ADC1FC44660C96C3B807100EB18CD5D2
+:1002E000FF257FD4E190768C35A96E58F7AD8EC886
+:1002F000F82F0640B63FEBFF3DCE5B2D8DF6D8BA0A
+:1003000087EFB70DCE51874D304FC55582F861400C
+:100310006F6EA0A33223733577D1EEE94C45D00F31
+:10032000603781B1DBC55C3B8A2F9B2FC17A57397F
+:100330003CA5D8CFC2099FCFC4F53123FBDD608037
+:10034000DBBCDF03DCA0FC4403403E9BB1530D56F5
+:10035000E6B230F645839DF2A71B92283DDBE0A074
+:10036000F47C430E955F6C7052FED70EF72CECB701
+:100370006CD557464F2E632BC3241EF93C16093A01
+:100380005ED97BD89F9D30DECA774D94AF6C6E1AD4
+:100390001F01E9A2DE279646C0F7452F284EFC5ED6
+:1003A000DDE232DB603EB30E7B5620F9CC79B775C7
+:1003B00022808FD55E519807B690A5AF7B11D2D918
+:1003C000D03F9D4A40F87DD9309CE673A6C145F3E5
+:1003D00071B5B41D8983F6E71A8A287FD4E1BE1F60
+:1003E000E7E7625F99B1FE841D6DC614282F74295A
+:1003F0002E06E38E7231BF1FF0B7C1E4F120DD6C31
+:1004000048B63A1B213F7AE0A467EE8571DFE9E345
+:1004100069C4F677C49617C6C1F789C3BD46AC3721
+:10042000F53BC6302FE9FB87F7358747ADC0CB8555
+:10043000371582D385BD036EBF01FA7BF3A8CA547A
+:100440009857C71503CDABE3A3703F5382F516BE93
+:10045000A2125D2F1C68F6B334CC0F4864B9B84EB5
+:10046000E80CD69FA338583DD0DFB99D3F4D423CA4
+:10047000C8F1CFC536FFF513E8AFFD338373338D75
+:10048000DCFCC55390DFD72BC9F930E42E9AD83461
+:10049000DAA7AC2E6212D0D73C33F3F0BC6700E68B
+:1004A000CF85B37BDC901FB62B650CEE231CCF9160
+:1004B0001DE46B59BB9E487FC0111C6F7BF3AC4F92
+:1004C0009E82FC05BFC1678A8694355F7C0DC6F3AA
+:1004D0006DB139B7329CA7311CE7F98889CFCBB70A
+:1004E00035DCB9D581FDF9890F40B919CB6B5E7E3A
+:1004F000B227AEE37580C170C8BFBE3682F8DDEBAF
+:1005000026E7F17A6CF70CEFEF57BFB8FFC47E4CCB
+:10051000D7D416DC0F69C0114BF0AEF8E5DCFED87D
+:100520007E400AA007F8E34BFB9440581E6303D7B4
+:100530001D589A0CE30DDAD866E80969FE16A51174
+:10054000D301BD8B8EAAD0FF118783E63178479AFD
+:100550009A82DBB5A7FF939B3208700AE2AFBFC057
+:100560005FEEBAAFC6F4847467CFE6853150DE5FC4
+:10057000693EBB240DE9FCC3020FC1AF89FA79A51E
+:1005800065F21FEF62B80E5FB215E7ED353BB7A617
+:10059000F1E59A207F614FC6A687618D7B0DBE4D28
+:1005A00088775F99D5B915F1EEF63D89F8AE85FAF1
+:1005B0003EC8D7E6FBA2AE87F2DACFFA3A81A2585C
+:1005C000EF676F2E4278CCDBF3F8F89E50EFC2480D
+:1005D000E604126095AF5C1E8FED586FC690255CE7
+:1005E000D8D3983003DA3D923B6628D2975B6DA64C
+:1005F00071D87C3ECE13B01DAD0032D60AC0491072
+:10060000A40AF51E81CFF83DB625E6400A0BE26745
+:100610007ECB923423B41FE2B13A55DC3769BEE495
+:100620003A58EF7B5865049D7FA7717F269B45BF95
+:10063000F6C9A9EE1F71FE99C57926FB7BC2CC7C59
+:1006400061D04F6FF8AE40BA11FB85F2ADC057EAEA
+:10065000217D46CC1FC6BD82FB14DABB900FA7C01C
+:10066000219D0FF34C79C242E7C0B58E7FC9645B10
+:10067000A500DDCE0FE77C6C8C387FA7C535BED1D9
+:100680000AEB7D35DC634C83716689739F199D0E7F
+:10069000E4EFFE709729AD079EA3EDA9B806385781
+:1006A000C3303F4FF5F449C8A073353B1AF9BEF586
+:1006B000DACED577C35DD1D8FE5AEBEBF9EDA26F58
+:1006C0000C2C1FE860D1E316E2178DC897615D8D91
+:1006D00091C3ACC837D86143CD1138676FE42D3B67
+:1006E000FB5B1459407CA591B12EE1F526EC7F0F00
+:1006F000F09B009C131EE003A3AEB4AB9CDE8F1DE9
+:100700008A1E827C96B922817E6EBA62609E907348
+:1007100050DF0FE02B0FE1389A45304FC8B9EA623D
+:100720003166DCB7CC16FB5F5BB798FF4881BF91A1
+:100730001D1F45301BC203BEDBBA5FD71B625DFFC6
+:1007400082EB82745DA6DB85F0BFF16BBB11D777BE
+:10075000A3B12415E51A98F778FC3EEA6B8376DEA0
+:10076000DF856BF2D73AFFFB14E633E07EFCCAEC80
+:10077000C7FDD882C723C0B1656EAE1FF7FD5E33DB
+:10078000CFFBA2A01CF0D812C97CC8475A4A12FC61
+:10079000BE34E487508E7CA307E3E561A2FDF40438
+:1007A0006ADFD30220457E7057B8E8BFEE9D8158BE
+:1007B000BE2485F848A3C9BF2A1DFBFFB94A7CF8AF
+:1007C00023C1B7D7C504EE52A1DF755F25301CE702
+:1007D000231648998FE3548613DFBDC160B8A7C4C0
+:1007E00086F55CC9B100EFBDFF50E99C58970F79C1
+:1007F0001BF1ED69CDF07D5D892B391CFB2949305A
+:10080000D07C545647DFD378BB4F4CBCDE0C81AF55
+:100810008F057E605FD3BEF74C8C3022DDAE492B56
+:10082000F3A5911CE44A5660BE4F556432E49B33F5
+:10083000AA6E49237A697A82F8D7348103D91F36A0
+:10084000B00E43B999FF4D9FB5350CF17947655806
+:100850001B9CACECA3CAA5910E687F87470D5880FE
+:100860009FB22985AE4EB92E1DC775D1B8B5CDFD45
+:10087000324E85D0739905F804F4FF52986725ED40
+:10088000D3FDF954BE1F849AEF613F9DA8C8DC8553
+:10089000FB8A55C4111D3063A01CF1F066BB95E4C2
+:1008A000D4EEE8A111E13F48D029E26531C73BC849
+:1008B0006B946F9CD6DF8FED9F3371BAF1ED0E23F1
+:1008C000BC164DB2129E3BA6856FB240F93D826FB9
+:1008D000354E0B772950AFF1158BDF807C40E1F46A
+:1008E000E07B2392FAAD31F37CCDCB99444F7BCDA5
+:1008F000FE17B661F99B61440F35517CDC9AD752E3
+:1009000004BDB9D296E3B86F58880E6AC21DD1549F
+:10091000FEAF7144272EAB673BC203E8AE0EE588FD
+:100920001A73202B06E07B5CD0D5716883F8F3D571
+:1009300045D2BC69CB43DED3D87B33E2D363E6E553
+:10094000EC672A951FB7F3F18FAFE6E3973E5AFDA8
+:100950002E03BC1D778F4F9E05F3385E174172E35F
+:100960005FEAD580390AF59EF6F55950EFE2E29339
+:10097000C336C0FC5B977E9A8AF451BAB4B618DBD2
+:1009800095562D9E88E76677FBB2B406367FC83E43
+:100990007E3FCD15C0F55C48F31C423A989FDB3A88
+:1009A0001BE5E78BE663CFA2FE1115E73982DF2F47
+:1009B000BDFAE5362E57B767E17930CFC8E9439ED7
+:1009C000ABF305FDDD97EE7997CE89F0C04C3C3F47
+:1009D00022728F717EB7F8DAF8FCD996AD7B1518C4
+:1009E000A73ABC651EA5AA3F0FFB39A704A2940C29
+:1009F000829F07F7D3797B200AE1EE317079AE7AD6
+:100A0000BB765DF867847955E33FA05D75B3EA0A6C
+:100A1000435C33BF19E75FCDCCC1FA69413C413F2C
+:100A2000842766FBCBCC0700FE552FF42B40FDA19D
+:100A30003A66FF2F6EA07AD04EEE13F5EABC5CCF7B
+:100A4000D5F3E1EB3B2FE8FFBCA4FF6982FEC5F8BC
+:100A5000175F4DA4F1CF95F8B310FE171551EF05B0
+:100A60000BAF07D460C479FE9AD3D37A93CF80FCBE
+:100A7000C7F77346F45C1DD73C0CE122F910CCC1DA
+:100A80006780FAE776A5507DC9B7989B316C57BD52
+:100A90002B793397CF843E8B1385FA552FF1FE3196
+:100AA0008FFBF0EC8B29623C2E4FEBF1A75F6F447C
+:100AB000BA81E4A9F5927F47CA7DEE4C2A01F86716
+:100AC0006F306BEA5F8C34DFE3827EFBF9B5DF6564
+:100AD000FF89E95CFFEBA3C35B4FB5FD8005F7D34E
+:100AE000F38CF6AB7E5EA9A2DD8B2F76E249E5782A
+:100AF000033150D28783CBE12684F3C79DF8B83702
+:100B000005F86A35C2203D089FBDF99E14E4FF1721
+:100B1000318FE7420CE473510EE2F0967909673D9C
+:100B20009D2DFD78764A2BB4BF45C007109A88F4F6
+:100B3000D829BF98401FC9457DB472F0A94CD45341
+:100B4000EBFAC151D0B99ED91BF2ADB89FE66CCC7F
+:100B5000B79685E0A171FBE0A30E80F3F9ED46277F
+:100B6000B2E546A3FF17284F376E579B7D8CCAAD61
+:100B700008DFF3B683BFC77AB337C614A0BC2CDB3B
+:100B8000CFD9705FBF8A10B80FD8AEC5C3C0666D2D
+:100B90007ED07E6D7E32F286A13FBE5D7E409B1F81
+:100BA0007C549B67ED802DC0836AE578DA37DC7969
+:100BB000D40178EAE3579DF8A98F6DD2E409285F44
+:100BC0006C549D9950DE67B1FBB681903FBD719624
+:100BD00013D15CA9FAE63D0038ACFC74FC513C0F23
+:100BE000CFB1E60F27001E66B7AC351B1DB86E2DC2
+:100BF000DDEE35087A7D51213A98EBD7965FBDAF8F
+:100C000097083CB29C507AD2E31DC6BDD30513AA07
+:100C1000A95F34F8141C9995C540E800B311CD6B59
+:100C2000CD28B7FDF0383E2E0FDA5C0E848777387A
+:100C30002FBBBE7E2C3B3918FEB1FAFDF1386FEFA9
+:100C4000230AC90DDEDF641FC673A06DF7F45B29AC
+:100C5000BDB388D62FED79735A944024E4EDC31DBB
+:100C6000FB5BA1DD2CBFE2C479972DB304F919FC1D
+:100C7000AF62B56E1EEB42CA61FE73F61FF89B02AF
+:100C8000FD576ED4B69B0B7C16F957D596EF2DA168
+:100C9000DFA5DE787DCB2615D73D4BCEDF378AE149
+:100CA000BAAEE75559BC906F4E6106CE8D5B7BB8EE
+:100CB000D7A763BB75BC1DB04B2FAEB7D66676E029
+:100CC0007A6BAD2C1001F3381A6976D9E1FBE50D8A
+:100CD0009164479B6D0179B28052165680ED9CD18C
+:100CE000D8EE8BF7B83DAD368EE3BBF63985F4A868
+:100CF0005A347E62FE799E9FCB02B40EA41357E84D
+:100D0000FAFCDA3C6BE2FA578D317000E151C55ABA
+:100D1000B9FE04787449F801BC6A609D1FC5A2BC85
+:100D2000A56BCF9C1E1C77BE8DCB4FF3F77F6F0951
+:100D30002D977AA0D4533786733DF1B92C77388E2E
+:100D4000B35C713D6985792E17F2B56F6D18D1EFDF
+:100D50008C4DFCBC0139360BE1B26E6DB213E58CE3
+:100D600019209787E1BE991B4EF540DE25BB4C3B11
+:100D7000C8D59BD3B07E7300CF8D758FA7911C0D06
+:100D8000F22FC1A57D4D987FB38272309763D6ADA7
+:100D9000CD2639FC75794EADE1725717723195B396
+:100DA000442EC77F824B099183CFF4F07C901EB212
+:100DB000AE8AA5AE643C772A26990D68AF6295711C
+:100DC000D7243F6C1572643BAC1FD7714A711F3139
+:100DD00084C8A39FE37900E30C1BE3DA26EA39B168
+:100DE0005E85A1E4E19B70BCF506078ED7096F977D
+:100DF0002B0BE7716A6D5801D2D9B031DC5E743CBF
+:100E00009FF3F78821CCE587F4A238672E225F0F85
+:100E10004993C281FEA09F5385DC5E1D39C44D7687
+:100E20003A38AB89CFEBD7F177D14F85D9FDAF37C2
+:100E300076311F091F368ECB0BA716289BF9BC00F5
+:100E4000BF901FF6CB30B2EF9D12E78F8433D0CD29
+:100E500050B2D30B7EB556D0CB5A13A703DF5CAE8E
+:100E60003F05E985113DAC137AD60C815FB686CB80
+:100E7000B5402F1CCE6B9205BDC0DC911E0A1D5CD7
+:100E8000CEBE467D09F01E9BD1E36ABD49E29B19A7
+:100E9000FD43D1BED21DBE6BF7EDDCEB83F3B3EAAD
+:100EA000D78F4731A877C6D894E084F6355B97474B
+:100EB000B9203D6DF445D961FC337EB5C8DF05BC72
+:100EC0006FCF907665974D01FE330FFFE94079E7CC
+:100ED0009189B8BEBF6E35D99125CCDF6E21FD69F1
+:100EE000DE9EB9246743BE8DE7577EA5627EBFD6DE
+:100EF0007E5EF5ABC7131C046F5F8A2109D3400ADD
+:100F00008374DE1693338076E90F54270C037273D3
+:100F1000FB0A9C9FBE3DCEE30AE07B7EB3EA3547E9
+:100F20005F5D3E5FF097F97B1EF90AED7AF375F687
+:100F3000FA4AE1B7D0DBEB6FCA888CFF020DD3D73A
+:100F4000B1EB500E02B83803B86F613E994426DC0D
+:100F5000DEDBF8C213796D282F6C79274AC90DDAC8
+:100F6000EBA53FA3A3B9FCB9D71CDDEFC78BC26EBD
+:100F70001BC417E75B8EFD0AF20050D0795A630A52
+:100F800044DD00F0A8D964223E53B3F3F96D4F213C
+:100F90009D7D6CA1F3BC7AE75B1F5E8FF2EE6E5312
+:100FA0007C315F864D4908E269BE83DBC9245EAAB5
+:100FB0007EF396D931907F5F1C1BC44FF5EE03661C
+:100FC00036F06A388E6D3E606EB57581A7E6B6F173
+:100FD00064277AE15B33EE83336F2A2C31EDEAF636
+:100FE000959BDE8A42790CE184E792C45727FE7410
+:100FF000F5A1FF89AF0DA17A76D42BBAC39F03CF99
+:101000000ED4CBF745B21818BFF2138BBF18F1BA44
+:101010006B5114AEE34B631DA7F3679627A05C5793
+:1010200069F225D829E5DF2B9FBD8FE86F8E529797
+:1010300060CF25FA4E3690CCE04BC6F5CDDA780776
+:10104000AD6F36F310FD553EA3BAFD907E63644547
+:10105000BBBBD8276F6770BEF9E566402AACEF4B83
+:10106000B4DB20DFF8832AF4DC05747EDF27D6CAE0
+:10107000D842CA7F23E4B68D1952DE056922445F47
+:101080009CBF65E531C4CFD9DEAE449C27C0C127E3
+:10109000E0A57C0FFDAAEF172672FC3087719868D7
+:1010A00007E7E858FC8EF58F995C68F70E6927F41E
+:1010B000393EFEBD627C987738EAAB5F2670B95D39
+:1010C000BFBE6F3BF9003BC642E9ABBB7DBFE5212C
+:1010D000A2ABAF3FE07C659EBFA488CA8F9902890E
+:1010E00058EE3F304521BE606181AEF6F51693D8CB
+:1010F000D7DA7298A7510985EF9B5C0E9D0D725748
+:1011000020641F07E9C61CFC4EEBFEA558472BF9CF
+:10111000D3A41F6E8EE007FA75EBF9C3211D7F90F3
+:10112000EDD9C6AEFD4041BEE0A3716BE03C413954
+:10113000A3E6630B9D1B353B4D6E84CFB91D873EE7
+:101140009C817A68B3DCC75A7EABDFC7952F0FED61
+:10115000721F9F5B9DDFF53E86EF5DEEE3D50AF1E2
+:10116000B7FF2EBF85938EEC06DDEDD739DDF0DBC2
+:101170000B3A787EC372A36FC042BBB70FE147073B
+:1011800057094F3DFF5C9EE120F8EAF927FC7DC03E
+:1011900042E028E127E993310F8DD349C7924E25CC
+:1011A0001D77D2A97EBD5A38EACB77237F82F9B862
+:1011B0005F3571FB598B42F236B43B923284F6A90B
+:1011C0008B8E3FD67424253E34EFD7E59B75F55DB5
+:1011D000BABC5B57DFA3CBD769EAD7EC3F64E6FA2A
+:1011E000414053CF527F1BE91957CB117EEEF7D9FF
+:1011F000F395D98774D1ABDD8C7CD1B494F92251AD
+:10120000DE7D432579F792A33D0AE592E5615C6EA8
+:10121000BB6417F9189E6FEF615E817C517E6F0F82
+:10122000E376924BEEF6A898103DBDAD458D427B1E
+:101230006CAB9F1575654721CB28C0B5957557CE0A
+:10124000E5B742D5965A8FF6D026D50964C22A96BC
+:101250004C8DA2B887968CDBA7C1F7596FAB143EB3
+:1012600070299CDB1598CF65C4B883728E42769A3C
+:10127000F9D68F847595B7F0F8838AD55AFCCEB627
+:101280004D890E3890EF68E304E6A05E9781FA9EE0
+:10129000F67B155B4DF456A5DB171E61A7D5EF0B4A
+:1012A000775F112F90CFF2853D86FC1C0B05BF2E7A
+:1012B00054736F9F06F0BF74546516C877B4A86C5A
+:1012C00005AE778742FE1E7408E07E9B07FB12E79F
+:1012D00023E1731EF74D76F772C9F9573E1BF600EE
+:1012E000D2C9DE4FF39E86F4FCDE8FB35EC7FCBE30
+:1012F0003FA77ECAAEAE3FF6CDBFCD443E7CE94DA2
+:101300000B43FABEF4E66F53D12E78E9350BE9CBE7
+:1013100097965AB8BDF9CD483FFA232FF5E6726E7D
+:10132000E31BDFE6B5D2B9BB8CF0F5405F33979B8A
+:101330005AFEFD38DAAB3B5A6055284FBC1941FBC9
+:1013400067FE6B61E40FBFF4C6B7C342E326FEBB82
+:10135000EB91FEEE4B916CDACB48B742AE9FFFFAB1
+:1013600088E7D19F5BBBE780B91CCAC7FECB7FE48F
+:1013700021FFBCF43297932E9A5A9F455BE38A2D46
+:10138000CE5F9A92D13E079DF564ACCFD6BA49B8EC
+:101390004FAE860B87C3258003AE0BE052897CBF1E
+:1013A0003B783C83F0E8F1CF088FAF66727E761D04
+:1013B00043FF6F102E0AF723B444FAAD0AAD9F7FA6
+:1013C0007FF3DB3CE4373FB4DED7FF69F1FFBFB307
+:1013D000DE8FFF69F1CBE9DDDBD741F3D4D3FDD557
+:1013E00074BDEF2794DF15E9A4F95EE37EFFDBFF10
+:1013F00067F84ECCFCBF8AEFB705BE23EDE857BCBB
+:10140000F4C67FA4B21FB1EE61FF47D72DE5F531D9
+:10141000AAF3683ED47F87357FE04C23E9A34BB91C
+:10142000A33C5391FA1BE94763193FA7C75AAB493D
+:10143000DE1CDB6B0DC9C58DAC80FC10BE5E2AF9CD
+:101440006328F802E0F0DBA47C3FF9938C815E8B8B
+:10145000203F26A596E2B3F47AE3D8F00945288F19
+:101460001E5A02F3827E0E451AECE82B1ED74B0D56
+:1014700058F2286DC3F448EA6D47516E1967D3EAF4
+:101480004FB7E9F4A15B1CDAF222F6723CFACF8A7C
+:10149000724DCC0FF3198FF543F4C6D199765AE704
+:1014A0002DAC6999DDF6E3E1F49880D3D570F8CFDF
+:1014B000E176159C849E6C14F5F57033DA1E3E8639
+:1014C000ED8C0CF45EBE5ED297A5DEFB43F0644269
+:1014D0009F368AA1257C8DBDB89F34A45F828B8402
+:1014E000FB8F85B7C4931EEE12BE126E7A3CCC46BB
+:1014F00063548F20FC7B19F38DB8EF6E1472FC38A7
+:10150000630CCFF73AA6BA693FFA399D7FED34A252
+:101510007C32DA1643F19ACCD13B06E54C1431BF4C
+:101520004F61AC6C78CC3005D69B62643E0BE89B77
+:10153000E843233BEA4346FFD2341C87DB6B7B1B2B
+:10154000B95D1A76B72FBC80EABBCC90F73E3687E0
+:10155000B9A0BE378539155E9F45C752381A533139
+:101560002E0B526CE78DE6FD7A13997F29C727E190
+:10157000A52FA6E9D4AFCB10CBDB4715507B9F81BD
+:10158000B7771921ED93C1EDEBEDCB2DA47F785703
+:10159000F6CE42FE513C466B378EC8E2766699FE27
+:1015A00024CB41A96A7026A15C5CB6AC1FE9436AF2
+:1015B000B8BBF615B4F7EF8A207AF4AEB87BC25008
+:1015C0009CDFAE38274EEFECC4DDC378FDE9F7FDB4
+:1015D00009BE7BB687D1F7A7B23C473201AE67158B
+:1015E000C7CC57E043D91D87CC493084A7B9E40262
+:1015F000DAFF26FA76FF1EFD8C13A7A8547F22E39C
+:10160000718F6C5904F9A327F8BE3226417F13402D
+:10161000D9C0F2B6307BEA0298BF57D87BFF20F6DC
+:101620008B1ACE3C2F23BF5AD13B2B1DBE4F605D82
+:10163000C701DBB3B89D461DA36C44FF509FB1DCCE
+:101640001E2FEB633FD86F8280C76799DCEE24F3CF
+:101650000057AA5FB1CAD296817ACF2A53201BE3E2
+:10166000A773C6B4E13A8BD3D9F80D08F7FB55B68A
+:1016700099E6DBEE253B77648E03F1E00192A6F854
+:10168000C2A63407DABDDA463707D03FD0F6649AEF
+:10169000B3D14158A6781CA967B58D0EF445BB7C23
+:1016A0007B3EF7331CB7B746A27E586EB3527C8E92
+:1016B0008CEB9965E7FBBC4F63EB9AEB50EF7C5CDE
+:1016C000756E86FCACC7B9DFE5739BD5AFA0BEB61F
+:1016D0008EEF53B65A1BC7C3EC4EB2F794378D3614
+:1016E000A37E59617399719DC9D99EEF715DEC3BE1
+:1016F00080DF308CE364B419BC4D5E8A3351A36043
+:10170000DFE13E313AA250EFD5C701CD17713F322C
+:10171000FF5298C79A05702C8B76EC427A39519F0C
+:101720004176CF9B91EE107E18C788FE09636B321D
+:10173000CEE7D54C4E8FC5B1F62C1BD1731843386C
+:10174000B4990093906F5B1E66403F5BF1524ED799
+:10175000B0CFAC4668FF909185A3DFE043D1BE7463
+:1017600089D1BD09F2BDACCC18198B74954F74FDAD
+:10177000688EE7335CDFE99FB3E1480FE5ABD792B2
+:101780007F45D205331E1B1707E39CDE9A56807CEB
+:1017900053D2D1A33963FA6485D2C31485E800D249
+:1017A0000319440F93FA6279F19840DF85B9A88F45
+:1017B000D630179EEF49CC897242076B27FF6387AB
+:1017C000CDEC403B97E427926F005E5DD684201DF0
+:1017D0006C83F3DE68626C7B8395D2171BECCC08BC
+:1017E0003C6E474312E5773538286D6EC8A1EF2F60
+:1017F000373829BFA76138E5F736B828BFBFA188B9
+:10180000D2D71ADCF45DF225800BF121C957243FB1
+:101810002AB799DBD01F29F9929E6E660278471588
+:10182000507BE27B92DFE13A0C05417E24F19BAED6
+:10183000B87D4969C8C75AA723FE0BD5F33BF7A16A
+:101840005E5E6973929ECE38DFEB007A45B8A49A4B
+:10185000D97EB4BB362E70B5AD4C0BC2FFAE4A85F7
+:101860001943E8EAEEBA30660C3937EEA98FD1E4B5
+:101870004BEBFFF85622F43F2EDE332D0BE671FCC6
+:10188000C12F9EF9337C7FEEC1B399886F98C7D67C
+:101890002770DCC5E19DF388C5FC3213F9A3FA4833
+:1018A0003B08FC215ECA18DF6FCF3DF877DADF6DA9
+:1018B000F51607CAC39F209E00AE7F11782AABB7EA
+:1018C00010FCBCCB4FEEDC87FB7CB199F85CD932C5
+:1018D000B10F57013C43FCBB279219D923409AA66C
+:1018E00078F5133F370722A0FF130ADFBF0A080568
+:1018F000A518F7B7EAB71FE1FE57EA8F92FFDC633E
+:10190000B505480EF099CE87F6A7D41FA17AACB5DD
+:10191000570CDA11E91C43BE3FC46576C0BA91A6E4
+:10192000116F6539075932FA4D9A143B6E990AF1D5
+:10193000BD629542FE498CBB9902729F2F4B253C9C
+:10194000B6641A695FF5CC6242AE6BA2F349D26B02
+:10195000C56A6887FBA229DF3C3B840F9789EFE5C6
+:1019600039064AE5F726EC17FB5B953F0DE5899EA6
+:10197000589E8B69C134846F4FDB78A31282FF8736
+:10198000B3F8F82D997CFC9EB8D9E0FF1ECE4937FC
+:10199000CFCA45FCF0F34B8E539653B002E338CBDD
+:1019A000568F46EECB1A4DCEA478A8F718F643EB27
+:1019B000B17379C1CAE3956BBA393FA4FDEC34FE2B
+:1019C0007304AD9BECBA55BB5EDA8571FC559F5A2A
+:1019D00008BF558344FC54AE7FD86432346AEDD5D9
+:1019E000E35EFA2C8AFC0F7B785C25A4DC9EBAB8F7
+:1019F00092DB5F9DB0AFBAF0FF1CDEF569549776BD
+:101A0000EA3DEA35D9A9E72BDF45A1FC20D753F8F9
+:101A1000C63709340FE50AF97FE6BFB13CA1AB7BBD
+:101A2000377A7B75A73D5BD8EDF4E57A7BDD912CA9
+:101A30009D5FC0C8E81E97B4D73135371AEDFBDF7C
+:101A4000887B1EDDE935D2BE3D7F03741207FBD3D0
+:101A5000E888467FD5A56EE4E9A86C2E1F5C10F6D9
+:101A6000F04B3B54D2732EED88A4FD346FC763470F
+:101A7000D07F386F8B42D3A865C7086E004F660DC4
+:101A80003DC730DE2CEEEA7977F833A3F11CA97E4E
+:101A900029B20EE96C6EB3E2DA0AF3E9B03AA27B3E
+:101AA00084CCE7ACA0D76A4BF33082B3987FAB907D
+:101AB000B764BDB92D8F91FD18EA5D2439E8D711BF
+:101AC0008CDFFF68FF3DCEF3DCC6C14EF4FBCD6D6D
+:101AD000DE3D8FE4881D11761481CE8A3861D9CF1E
+:101AE0005F055DFF358BCB2FE7843FE8DC2E95F853
+:101AF00019CE13F7D759451B8FF79D68F75D1687E9
+:101B00009B1FF7778F60FDB9CD6D517DA1FE97FBCF
+:101B1000FF48A9399BAF6BAEED581E9EBF5FEE89A3
+:101B2000207FD6977B9E1EFF3A8C77A179743CEE7E
+:101B300007D97F7CB689E363A35A84F0627E1EF7DF
+:101B4000528BF01D1C3ACFB84DBEB4D07DC7E37E9A
+:101B5000CEEDF94D94213788CF5AABC79A9C8EFBB6
+:101B6000C7EB46BEF1B9C2E169DA33DA87F798E626
+:101B7000B7E433A467DA77C9547F9521A49ED9E4EA
+:101B800024A668DC5FE24A21388B7B48225E1EEF88
+:101B9000D5D1BDA2122BF927660E724CBD0BF9E40C
+:101BA0003B268E975E8E27507E9BF95E1CC54D2D81
+:101BB0004C734CC5F92F7A5FA578DF9983051F48D0
+:101BC0006A1D8A718B35AB14E68275B6A571B9A111
+:101BD000C6AF320FE47B023DF8001423B3D3053FB8
+:101BE0000D64E17DC0A72A0D2E339C7FC7CDCCA705
+:101BF000A2DDE8651ECF5C93CEE3869F42BA87B430
+:101C00002636901507FD9D17F8AC9914C8C238897F
+:101C10009A9793294EE2BC99FB2DF13BFA496B0A46
+:101C2000A03DD48B17F1B0D83E26847E6ACA9C0EA4
+:101C3000ACA7C63A1DF9369CAFFD22C9B1AF4432FC
+:101C400094630DFB22799CD3AFC2365B42F0E4CEA5
+:101C5000E67272BCC0239BC1E321D78B78ECF55BA5
+:101C600093FDA8BFC9FAEB4D9EE908075C07CAEFD0
+:101C700073CD4D5928DFCAF9CE8D6AA2799E17F42B
+:101C80003D37BC89C74B9B793C25D6C77C9B895186
+:101C90001C77FB0B168A27399B7C6C2F8E7FF68571
+:101CA0007E0CD7DF96E69FBD9FCA417E04BC55BD22
+:101CB0006809E07ACEBCC0EDCD674C5C1E3B539208
+:101CC000E440BC154DDA3093EC315B2C0AE2FD8C1C
+:101CD000C2CC4958BEB587D387ED1BEA294EBA0A54
+:101CE000D804DEC781B408EFD59CD9DA8FE2C3CE21
+:101CF000BCADE28D28FCBE0ABF7B58D3CC9F213CF3
+:101D0000B673FDE9EC8BFFDE2FF41E9A4CABB66880
+:101D1000E3E0249DC8F205D95C7F5920E07C5F3662
+:101D2000B737D44634AF4FA77572B8039E48EF0358
+:101D30000E13F9F4108C83C854906F3C0574F5347D
+:101D4000DA15B673FDEAEC0E13C58557ED8B7451A9
+:101D5000DCD9CAEB0C1407A17239BCCA00E0A35449
+:101D6000A17EAB26E5F81B49FE66A4C7B66F55C534
+:101D7000388CD970DDDB789C6F31CA8A543E90CAAA
+:101D8000CF88FC99BD0349AE83FE5D785FA9EA6701
+:101D90000F70384EAE7C97911DC34AFCB5A6D38F09
+:101DA00033321ACFBBDA953744E33D40F69ECA5032
+:101DB0003ED1C3E9B2D199887CF57036E75FD57B17
+:101DC0009F31233FA816F743AA5F54B83F19F6196D
+:101DD000DE93AC5E71C313449FBF37B14C58CFF94B
+:101DE000E6C7A242F1B14BF4D359DFECA4FAD550C7
+:101DF0001FFBA95EF14E14CD679B89E24CF478BCC1
+:101E0000E6F62FAAD7D4BE933E9AB91DE5AAF5B33C
+:101E1000633FF914FAFF7A4798D3475F9BE95ED98D
+:101E20003953F36C5CFFB99D61C48FCEC570FEF071
+:101E300025F04F5F36CEE3B647292EEB0F93E93EF0
+:101E4000DC1CBFB65F39EE6F906F63BC549C331AD5
+:101E5000E3FA6ADFE3FC0DF0723BB57FCF44EDF5AA
+:101E6000EBF8A568D7B93F7746103D9CEBC9F172F6
+:101E70006E57369D476D319CCE61BEA9787FEEDCF2
+:101E8000CEEC7CBA9786C20DD04395D06FCFC534C7
+:101E9000A7DA43CADB4C424F0B404DA41B6C0372C4
+:101EA0005F553D97ABAAADAB293E04E36A87155059
+:101EB0001AB0C45E1D1F0BF44AFA63780EDF5F0C84
+:101EC000C74B10F1DB24EF349B917F7B845C58B3CC
+:101ED000431F5FCBCBCF6477DA391DF1329E17E910
+:101EE000D0A7509C49F5B2057391CEABEBD6DE85F9
+:101EF000FB4CCEBFDAC88A500F6B53549A475B181D
+:101F0000BB67129E1BA1E384C86D5F07C761F6041F
+:101F10009257E91CBB92EDE074832726DE135DA681
+:101F2000ACA671D2A43ECBD725E104E030635C5F60
+:101F3000DB6851DECDBAE53CF5EB96F3B1E5707E9A
+:101F4000D496E6787424E2F9772ADDA7BDFCDDE0BB
+:101F5000E8D82EE4B2E0B96E0EC6B7C2FC9391F693
+:101F6000D0EE92CDE5F16A8C9F8579666DD4C67509
+:101F7000E76CD1E6FBEFD0E673F768F3792DDABCB6
+:101F8000F3B036AF887151CFC6FBBBA867638A7ABE
+:101F9000B6C3C2F56CCCA39E8D29EAD9F81DF56CA9
+:101FA000CCA39E8D79D4B3312FE18DFA36E651DF83
+:101FB000C6F25B73B83C5623E224110F48EFECD510
+:101FC00030CD7D9F4B6FF07B1C40077CDF4C37D3BF
+:101FD000BE790A6B90DEC1ED4A3D275B1D18EFBB51
+:101FE00038D633246728DEF738B62219F1666CA597
+:101FF000B8D3F9AFF1B8D39A82301BDA375A977F4A
+:10200000B902C339DDB19E1158FF92A97D1BC2B739
+:10201000B6FE10DD7B6F5DE278EF268E3FB2B3B087
+:10202000CA58929BBC78CEC5768F477DDC375BADB6
+:102030008DF3D6C77DEBE3BDF57420E5BDE74CED30
+:10204000C9C8D74FBE605D8DF33F1926EE9F4CB3D4
+:10205000EAFCFD424E5BA36CC6F37A464E2CF79F1A
+:102060001D05F9BC8B7356A6E55706931CDE995FD8
+:10207000AD18E85E5C52029D438BC49C5295F6B647
+:1020800095C8E7E61AE8DCBC0C72198E77F903955F
+:10209000E487EC0D06CD7AFAF9C335F435607BACF4
+:1020A000EE5E434F4DFD41FBD375F71AFA6BE3E843
+:1020B000A72C3980FAFDE4D58335F52ADC37E8E032
+:1020C00028E62DE4D70A383F5CB0BEA7166F484516
+:1020D000FC2E9ADBD1B612E5D357C2E85E5825FE36
+:1020E0003FE08B95D027DE67ACDC23EE03D76BCFC8
+:1020F000E172710E551A99CF1E1BA4C34A3B73C5DA
+:1021000040FBB9FD8FE50550AF78FB8FC3ECE9A824
+:10211000578C4E447E946A72511C6CCDEECC98253F
+:10212000D0EFA20CCF4339B0CF4E351DFA45299ED2
+:1021300087BBB9BE7772F56FA2284E4CD05BAAC997
+:102140001E8E78DFD4C4E3E3D03EA6C606E9625310
+:10215000535C785F5B70BD413AF88EF004F8E1762D
+:102160009CCA83E4F7E86816EB1DADF8509E96EB29
+:102170005B28CE15D697F773AFC89F12FA855CE738
+:10218000F97E07F21C78FFA2617FAA8AFCDCB063AB
+:102190005B32A4B916CF165C4FE5A6CC3F8F847195
+:1021A000AAFEC4D7F3F9BAB1512350FEDC69721606
+:1021B000437E65D3F366D4B3AB8C7E33C557BEB0D4
+:1021C000C98CF1C5376FDF44DF676FF7523CE51C00
+:1021D0005647FAE769F9EE808047E51865A31DE6E2
+:1021E0001DD68FF38FCA70EEBF03F9E82D7CF7E39D
+:1021F000F276251FE378A6B8779BBDF0FD0DC18F61
+:10220000F5FBA4E3DDC9853D081EFCBEC69F18682A
+:10221000F11957EF8BC957D2685F4CB93280F4B2CD
+:102220003B02FDB8FE9BABD37FDFE5EF2E74B4F02D
+:102230007D50690EC44FC67DF2A689E4DC5A386F22
+:102240008617A05ECDD8F590BA47AA1A7A9D3F2E80
+:102250004243CFD358C83E81FEEEC4A09190FC9477
+:10226000E20C4DFDA95306E8E8BF20584E7CE47A05
+:10227000CDFDBADAC53E874272E618ED77C6E304B3
+:1022800081436BDAD7B249C17A48DF5BB81C5CBBCB
+:10229000276633DAFB2A0D5C7F9AE6E1DFE7EDE79C
+:1022A000DFD934A6D9877D329C7FE6E7A289FC027C
+:1022B000D29E3E0DFFDD05FC4112E9BC1F8EF7E208
+:1022C000D11EA1B93F2DFC81386FC443ADB01BD5E1
+:1022D000E670BB51ADEF9819DF1D00F81BE362A952
+:1022E0009E350EE3239B14B22B62BA98E225B5719A
+:1022F00058D81FC631CE3BAA7A719FE8CB81EE78C1
+:102300001CFF6B3CAE74CE067D1CE46AF247CE43E4
+:102310007B5008DE6EE9E710FE38FF8A9E08BF6238
+:10232000259FEE45EE3860C638BB295362F271DF57
+:10233000E8E94BF275D8CFA47F77BC7B88E8ABA3E4
+:10234000D248F4FB437098E7E276543DDDCD66C792
+:10235000CC784F7CF61EC589FA28D64378F4447AA7
+:10236000D4C1232EF66A3848F874C26B8F3ECE8DE6
+:10237000C369CE7EC51FE8024EFA79770737B99E4A
+:10238000D91ECF78E40B725D7370FED83FCC1FFB73
+:10239000977E08365CBF3F33C83E35CFCDE363F54B
+:1023A000F430E90AB7BBDC79C548E99462ED7EC434
+:1023B00076B82FEEB89240E53F965EE6C13CF9FD57
+:1023C000A76BA313B90EC97783FB81DF1BF8A17735
+:1023D00081F476C73BFA09BBE3503654138F2CF8CF
+:1023E000AABEBD3E1E59CA01FAF3C51B69A0B8C9F1
+:1023F0000E5B3AC91792CF7AC4F9E159FE0DD5F3B5
+:10240000403D3E9B04CD79E311F6BF8591E9F41E72
+:1024100043EA92B804C49337CC4EF1F7DE252AC5BF
+:102420003D7BA19E23443E59B12C2315CF8B130F26
+:10243000653FEB03B9FDC4FDF109C3619C93CB4D2E
+:10244000F15647B0DE89E585A918A77172AD659A86
+:10245000BF0B7835F4E3E743ED831FD17976C1F004
+:102460006ED434685FB3FC95280CF3AF5ECECFF129
+:10247000C40CCF83FDC87FBB699B1DE167DF9487D8
+:1024800076DF35701C607B293F542D2F4C44F9A218
+:10249000E61F879EB5E33DEB25A604943FCF7C0065
+:1024A000E7A142E719C90DA7C3A00BF2A745921DEA
+:1024B000E1B4C25CE8573A6F38F0D795A817E63711
+:1024C000670520ADB578D6F443F97FF9F324B75406
+:1024D0003DBC244B55B1DFCCE8AEEC2632DD26CE38
+:1024E0006D94DF3145F91DE364507EC73CCAEF9817
+:1024F000A2FC8EDFE76FD0CA7FCF087FA1B427F799
+:10250000696CCF47FF9D6F0CCBA9A3F3D69683F2DE
+:10251000FA2225DC89FC6811CA4A98FF2C8CF458F1
+:10252000B625999FB702CFF556EE37FA56DCCFBDE8
+:10253000B11D64B210FABCE98A9585DE9B1DCD629F
+:1025400034F9B1D6644DFD427B9AA6FCE6A47E9A8E
+:10255000F25B1CF99AFC6D392334F52738476BF28E
+:10256000B70FBF4553BFC455A2C94F2E9AAEA97F1E
+:1025700087DBAB299F3A6DAEA67CBA6781267F5771
+:10258000E5FD9AFA77D72DD1947F6B008D14E8A5DD
+:1025900005F52E0BBE9F62A5F4A7AADD887C63D14A
+:1025A000EF326D88EF91630D755DD9F73F14741CA0
+:1025B00037C0F53ED24B6FF13E4E6FF1CECD293C88
+:1025C0007786A21F12A88AF4DD63C948BFFA7AFA97
+:1025D000F29111072F3B0087A35E34DF61043E3484
+:1025E000F2BA83833320FFD3176FE4F91B0EFE2664
+:1025F0001DF20D2F2EE5F941072F63B9F9A5313CE6
+:102600003F9991E8F148FF8E29184F32F2A6F4D590
+:102610004E6E27E9F29EB94C110E785F1BE180697E
+:1026200000E817D38340BF981E06FAAD00FE74047D
+:10263000E817D3A3A07FE2F77F05FD13D37741FF0F
+:10264000C4F4F7A077627A0CF44E4CFFD0308DD2F0
+:102650000F1A3CD4EEC3864A4A3F6AA8A3EF9F34C0
+:10266000D453FA97061F7D27473FB74333CDFD006C
+:10267000F433A23F71BFE97CA81F58FA2BA57FB2A3
+:10268000B18EB54620BF6835C67C610DFA1DBBB75B
+:102690000318D91721F258347345F42779A1979D6F
+:1026A000F8B7F8BEB38FC7DE1FE6F5A7B4C99983A4
+:1026B000553CB7EADE42B7EC9FC4FD7A7DBFA784E4
+:1026C000BCFC657F570F6C27FDEBD2BFDD193713BC
+:1026D000E27F3784C4EBD05F48DC8DF483CB389F36
+:1026E0001BADFC9EB1F473CB781ED95FE1D78CF89B
+:1026F000C3A85546925F228D2C80FDCBB89D51D644
+:10270000E67C8C63185563A37BB589F0DD5C40F5EE
+:102710005C2AA45BFE06F5F3827EF544317F28A790
+:10272000F9177EED213BEC28115780EDADBCDC871D
+:10273000ED47A16D6108A5C49F9EC17BBB05413FCC
+:102740003FD68FE0F503D85FDFBFC37851C17DD39B
+:102750003BB6391FF975EF7936BA17BA717480DE56
+:10276000B322A313C065B2D49FAC222FFD79DB1333
+:10277000C98E3456ECF50C87E766C4A7DB62FF2CE4
+:1027800082F659466FB44F9608F9F93FC15B31E2C2
+:102790004DC253E245E251E223247E8AF0D01D5E11
+:1027A000F5F8D4E351E2AFF0EB205E10AE57E32D25
+:1027B0008857B4E7FEB3E06D8891BF5F66A9B1D2D8
+:1027C000BB683F84C77BDAD9F868A872CAE139854B
+:1027D000E7BCF78AE308E6CBD9E8F1885A597EA12D
+:1027E0009B72CFD7EDA6E8107CDF28F01D9F06F581
+:1027F0007B5C5D5FD693EF31C8FE077753FF9D305A
+:102800001977E1B2E50F0BC63F2E2AE4F02F4A53A9
+:1028100009FE6373E7909CCC6C5CCE74C07FC89754
+:10282000C67FE7A6772DBF613BD073CBC6C76BE5EC
+:10283000D3229DDFFA562197DEAA934BF572A5BFEE
+:10284000BF902BD358DA8F7CAFF257FD89AF5EEB88
+:102850007B95FCBDD371629FA5083ACB70A86C2410
+:10286000D211F3D0397918DF3BCDC377417D94BFC6
+:1028700085F929BD8D05E87C9D008C18F3B733469A
+:10288000F7C80F454C2CC5BB7163078FED8BDF4339
+:10289000DE656BC17D3A4FF5FC9B3DE45DB683E39D
+:1028A0001C74BFF2A03583E42FDC87A6107BE0DB2D
+:1028B000703EF585F3E3109C5F98BE05E7575F58BF
+:1028C000EF6FE1FCC2FCAD394B18B61BEFD0C6ED83
+:1028D000C8F6B7D9C78262D23DFC6ECB7BB517C2B2
+:1028E000F79D98EC71683F7F27E6BA71B8DE776292
+:1028F000120D3CB598291DB8AF6F57F2A1DC07C186
+:10290000F1C6D3787AF84A78EAE128E1FB5F80E7FC
+:10291000175DC1F394909F3BAC7F8C4A4A47FF5DA3
+:102920009478C7F277792AE4CFE0D492315EF50645
+:102930009AE7A8FA11CC3898FC36B908D71A2B8731
+:1029400097DE6EC5B6241A42E377BF307BBEC5F171
+:10295000BFDCA8D2BDF10B2F87913DEAB49FDBDB32
+:102960008A14CF77488F35AA6335BE3FCADEE1EFC0
+:102970009CB1EF0EA54E8AFC1174BA85DFB7AFB1DA
+:102980008EEF128F529FFA0F878BF80813EF454A8C
+:10299000B9A29785BF4B20DF2FEC4ECE1816CEF98B
+:1029A000602F8B781741E015DA513E05FA19067C45
+:1029B0002EE5D170D22FEA7BB8E2070C0DDA113A7E
+:1029C0007A45F891DF8E0A0CA077B98A8EAA144F47
+:1029D0007C50C477DD3CA0CE960E78BA29D3933ACA
+:1029E00000D7A57EA7229F7917D61987F687A383DC
+:1029F0006DA43FFE483D346B80E017792C4F735F28
+:102A00004DD29D6AA3F89D8E0FF87DBC856FF3B8FB
+:102A1000CD853D548AFFD7C7C58D62598FA2BD7140
+:102A20006CBCC9E97704F98B7C07C89264608E108E
+:102A3000393BCC11CE1C21F389C889D5E4239D3DB7
+:102A400035F5A387A76BCA635CFD35E57145059A2B
+:102A50007C0FF7F59AFA89D3C668F2C99E5B35F503
+:102A6000532A2769F3B8EF00EEBDEB6668DAF5A9E3
+:102A70002FD3D44BF35569CA99CF752C2701F93858
+:102A8000FFCB58B55053FE7454118F1FB7CDA67BA2
+:102A90008A994D3FD3F427F19B12C7F1CB1CFC7CE4
+:102AA000F0C17FE4B710782E4CD29E1B63EDA30FCC
+:102AB000DB29D5DA35527E200E6ACE7F950E6A99D3
+:102AC000960EE2791C4FE1DB831D28C7E8F18FFEEB
+:102AD00088D075A23F22142EE88F08CDA33F22B4E0
+:102AE0003EFA2342CBD11F115A3EF8A816FF438F5E
+:102AF00069F17FDD4763FE533C8D68D5D2831E4F5D
+:102B0000379CD6D2C7284F38C1652CC86348EF120E
+:102B10004FD3E03F3AE7993B1AED06373117DD0B0B
+:102B2000F89FC2D7333A7C7DC3560FC5772E2F79D5
+:102B3000391FEFEE9C7FA28FEB79E41FEF0B3EAFC6
+:102B4000B703C87852DF188E4FDFF130E257DF1A33
+:102B50005A23F1FCF8A9DA4A76F964D6FE16BE3F8C
+:102B6000638AF7FC1AF95822460F40F95373EFCCE9
+:102B7000C7736EE6BF585251AE99D987BF27C87246
+:102B80005BE99D16399F99293CFE68DF00C1A79D2E
+:102B90003C0EE9B5015CBE8E74DA290EDA9BCB449B
+:102BA0009C274B9D3910E9F0DDB06CA4B375DCCEE9
+:102BB000D56A72505C8B0FE811FD94286FA33CDC42
+:102BC0005BC8A38D1F5BAD9CEE98E67CEFE7B76A10
+:102BD000E270076CB76BF2039B9334F507ED7768EF
+:102BE000CAF303399AF2C1479D9AFCD063C335F505
+:102BF000AFFBC8A5C98F682DD2D4BFE1B45B934F9A
+:102C000061ED4F223CBF1A90CEE3FB156107707057
+:102C1000BCCCFC6902DDA7917A848CCBF6083AD64D
+:102C2000EB237DCC1E8AF36E4C664EBA0F6215FA0A
+:102C300020D3EA291E11572DE579E6D3C655CB7866
+:102C4000EA4E7D46E82F529F0889A776E1FC653C55
+:102C50007527DEC5FB927AFAFC87C0BB7E1D7DCC52
+:102C6000FCFE57E3FD66BAC722E7A79FD7CD221E19
+:102C700070ABB5EBF7876CB9DC6EF068BADB980B1C
+:102C8000F59E85E389E079D578CE561FC0B7F1E788
+:102C900066E752C70F8F3773105F4F29BEAB9A4B51
+:102CA000EF74D2BD35396EAF5C4EDF863CA5CBF5F7
+:102CB000CD8CE6F15D2CDA4CF72EBA1F8FC335C9E7
+:102CC000CC96D13B49E21EC2DDAB9BD7606845A9DB
+:102CD000B9C9C4DFD5F79BD04E543C06E4C07CE0B4
+:102CE000135B77AEB381BCF66CBD91EC3E19B9F1C4
+:102CF000778204D979AFA40FE8694827C5887FE8AF
+:102D000077C3401EEF3C2E97AFAF50FDAEF33E8031
+:102D100045C3E7B9FED705DD113DCA75FC6FDD0F70
+:102D200090F4AB8793D4AF9938BFFA8A7949F87594
+:102D3000DA4F04FCE4FD0CC702937BB38DEE7914EB
+:102D4000615C99C4DF4B03395DFE04E13194D743E4
+:102D50007ED45DBD4235371AEDE01DCC116DFF010B
+:102D60007BF0FFD2BD09827F77F7BDBAE31357F13D
+:102D7000876EEE7F75479FF4F723EE8185F0091E7D
+:102D8000EF23F0E1EF6B20BFFACA48ED3EDE9ACBAD
+:102D9000E17BABD84F706EDBF2B57C82A15DBF7179
+:102DA000B92AF8C4ECCEDF9FC0EFB3969B48BE664D
+:102DB000CCBD1EE30C3E5F67A2B8D8512E46724CC4
+:102DC000D946C5BF49C173746412CEDFEBD39EC729
+:102DD0003731E70AF47F94AFD27E9F63E3BF53316C
+:102DE0004BFF6E8AD0D7E7FC80BEBE3E579CE34EB9
+:102DF000E624B94BF8FF2B451BBDDCD5E1E77E335C
+:102E0000D4B7556E77A2B83179BE3BD07F13F21E8E
+:102E100008C0333C07CFF165C62EE3F93AE1D94D3E
+:102E2000BCC2799B8857B0F1F88C8E3D61DCBF291C
+:102E3000FD4AA2FE79DF652AC7FAD8DB857C1E77BA
+:102E400021FD497A7F5587CD40FE968E3D91E49FC6
+:102E5000473F4E34D0C159C3EE84E169C1F9795A74
+:102E6000558D1F449F7A96BC42FA62628627908BEA
+:102E700071D846A7D509F9876C07E9FDA86261F703
+:102E8000D2CFB753EF1AC9DF77E9F07179B6A388CB
+:102E9000BFC3017C91E13E927108250CB45448BD3A
+:102EA0008111349F1FEBCF997C259FFB31AFDC4014
+:102EB000ED3DAB4650BECFB2350BF01ECC1D8D7331
+:102EC0004CE8C26E7D72716138346DEDED5F1A8E23
+:102ED000781BAD7469976F13E759AB2EBE5EA625BC
+:102EE000821FCD1B28F9B888435AA2D03E58A8307B
+:102EF0001997447C5CE62F37897C21CF2F5ACEF37B
+:102F0000ADE27DFD6DC28E82EBC614D78D7AFF0EC9
+:102F10006167C175638AEBC6EFC8B7308F7C0BF36E
+:102F2000C8B7308F7C0B53E45BF8BD8CB953F355B5
+:102F3000EE871A17BAEFAE58D9B890FD827EA8D0A6
+:102F40003CFAA142EBA31F2AB41CFD50A1E5E8877F
+:102F50000ACDA31F2AB43EFAA142F36CF82DC13C5E
+:102F6000F2395789263F19E4FC7121FB1BFD50A162
+:102F7000FDA31F4AD39F6781A6FD5DAC5ED31EFDF6
+:102F800050A1F5EFA957347EAA7BC43BA7E51BE20D
+:102F9000887E221DEED48180E77F8BF8C77DA674E2
+:102FA000C473CB5CAE97853B399E9B8A38DE0D8C13
+:102FB000E3B97D3AE179B199E70B797CB29E7ED095
+:102FC000DF33CEC4FD3D98A2BF0753F4F7608AFEFD
+:102FD0009E7199DCDF8329FA7BF03BFA7B30457FD9
+:102FE0000FA6E8EFC114FD3D98A2BF0753F4F760A8
+:102FF0003BF4F7608AFE1EFC8EFE1E4CD1DF83DFA1
+:103000008FA3DFC9149C17CAF17D35FA23D0A146DE
+:103010007FB46BF228C787D647393EB41CE5F8D099
+:103020007294E343F328C787D647393E343F33D7FA
+:1030300041FB0BE5F9D07628CF87E60736F9DE426B
+:10304000DBD9848D170F63DA1AA93CAB00CBB867C4
+:10305000E74B771A413E6B0D53526380739A94DDB0
+:10306000778E83BC47C4FFE5B17603E2DB23DE53F2
+:10307000F70418C55B0EFC5B32953F23EF87E11F19
+:10308000E03D7F0FA3DF2591FE62D9DEC9EC2AA6C1
+:10309000B27E30DF753DFDF8B21EF1CF9079E00DC4
+:1030A000608C57C95F6C2BC078CF6D0685E224B663
+:1030B0002DE571C27ABA7A6C20F78B6E33EC3E88BC
+:1030C000F740DABD0ADD07CE32B2A3A60284535D13
+:1030D000019EBF0F0C8C117EBEBAEBF1BE899CB76E
+:1030E000B46F029FA0FB7323DB8F8D8D867E3CBE69
+:1030F000D1F43B29C5662E37603BD42707F814D797
+:10310000E610FA5E3E90F34D8F8F8FFFABE726F20D
+:1031100076E1BCDDAF9E8B22384E5CA650BCD4C895
+:103120001DCC85F7737F21E63D604740C5F1BCCBE0
+:10313000F878B25FEFC654BAB7E865ADE392C84716
+:10314000A230E4DB126EB0BEC3B83E501B8EA27D2F
+:10315000FA5AEFFDDC3824A610E3E8580BA3772CCD
+:10316000270C795FB35E42FB30EA97CEB56C9F4285
+:10317000EF054FF42D598A6431C1B7E0AD1E587F79
+:103180000B73A639E828A27BB1723EFD5DBB0D70C2
+:103190002CB25C76CC10A620BED9A1B810FA819DC5
+:1031A0003F05F19DEF34D1FBBD2546BB89DE8FE89D
+:1031B00026FEE4B24DC69FE8E4055D9C49E3E28F3C
+:1031C00052D19EBC30D240F6DF85AFF0DF03F06C09
+:1031D0005088AF4939C82BE2D42E2F7BABC754841B
+:1031E000FB6E13F527E34F6A33FCA9068CABEFB9EE
+:1031F000292F562539E000F2C373BEDFDC391CEB02
+:103200002DE7EF585E5E764774807AE2FE9A0A01F7
+:10321000AF0A11C7E4C507BDD5E0EF69C9FB1DAC16
+:1032200089CB7BD29EE3FDDDE023885FEF33E25D57
+:10323000E9555EBA97AD8F239ABBCC44714773753D
+:103240007261B5900BAB7F402EFC78A04E2E94BFE0
+:103250009722DA30B5D78718B727EF25969AF8FE68
+:103260002FDDCDC80E5BBA64AC81DE417E85D34DC7
+:10327000E9122EDF94BEEAA2FB85525E7C4FC83174
+:1032800093AEA410DCFF28E4963B30BE12E05BDC7A
+:103290001A26E2B092299D7A85C75B4EB2713ED064
+:1032A000FA067F07A2C367E1F2D461C6DF31D3D14A
+:1032B0006589D16FC00B77CE914097909F80721037
+:1032C000F4370DE5A238A4F3B4428ADF2B52E8DECE
+:1032D0008B9ECE8B4D756F617C68F156E6F4B150D4
+:1032E0003A07FAC5FE7C0ABD0FE0117AADA45F3D36
+:1032F000BDCF8C10F6281BB73775DA255046C54769
+:10330000BA7DA6A918FF3A137D7B3D39C160DC590F
+:10331000642E2F8FDB659ABA0CEF2A7463A7507F57
+:1033200066267878E43B08DDD80DD05E807CF2EE2E
+:103330007BF3CD65217CF2E4A0318307F508E2BB85
+:10334000ACF3BE5F2EBD0BBAF0A14CFA3D9CEEE48F
+:10335000E172802BEE8B99D1ADF7E12FB315E431FB
+:10336000D7B824FC7D41261F210F601CE10C91BFC2
+:10337000272FEFCFAB6C0417CAE7ED8A9B8A712128
+:10338000B5D6D6F14876F3733D45788F31C89FDCCA
+:10339000AE1405F9537E0075C29BB3F83D2FBD3DB9
+:1033A000E29E3C5E5F6F9728CFE57C5BFE2ECA896C
+:1033B00087F6EDC2F34ACEFF4437BFC330358FCB1B
+:1033C000B3FF53F720F4F71F66F5F414E5C17CD77B
+:1033D0001BF87DFE9E6A1313F621F20B4B7EC1C4CF
+:1033E0003B1841BCBBE81DDDC687147BA87DCAB372
+:1033F0004AE1F7E8BBB1E3B09CF627B742BB990DB1
+:1034000066FA1DBFE7B238FD3C07F443BF97623E42
+:10341000F696352D08C74FEB7F69A2DFA561814C79
+:103420007C7F67465D9813F9F1C941EE9938EF88C2
+:103430005C27F1A1C183387D65C4BBBD7978FF6E7F
+:10344000F58167F13D81F92D69F47B25DEFDF92BCE
+:10345000F09D9393833CB3B1DC6BB3D37B1AF396AB
+:10346000C5D0F9353351DC0B65EDE46793F07F305F
+:103470008FEB89D73999F8BD2D71DF01186489A6C2
+:103480009E88EFD6ED0F6927D4DB19F4EF4B7467F4
+:103490005F90F604B41F9843EC8CD23E61CA393178
+:1034A0001DE58652B3F65EA24C7F2DE62FF5C0597E
+:1034B0009DE756EEF844948FD72A767A6FD2E69835
+:1034C0003A02F215474D18D9C98A631D667C7FA060
+:1034D0001DF08BF1D165B05F91CF948A38AD8A0D24
+:1034E0002368BF55F821EDE21D4E99DEB5F650EF89
+:1034F00057917E022EF25B56D85DE6D8907D5FDE56
+:10350000A468DE1D90F9E7F2545A672988E308BFE2
+:10351000BBEF4D33E3DB3EA5204660FCDFAF057D0E
+:10352000C876508FE2418AD3D911FE0E3CCC3B8D38
+:103530008F5710D27F5913BF372DF3509FE49F1739
+:10354000F222A93FAF1DD69D86A99DE609702038BD
+:10355000B5AF81FE1C340EE1A33CE037A1BE5D8A0D
+:103560007128909F61F79B709CB265FC1D13CF6A18
+:103570003E8E67558C7920CA4746BBB937C22F9C0F
+:103580009F57303F92232B002E781F0BEFBBE1D9C2
+:10359000A2878F57CCB7A22986DE51087E5F6B4287
+:1035A0007C4CEFE65D844F05DECB968DA6FBEB15DC
+:1035B0004617DD73F008F87EBE20EC61F40F4C5F17
+:1035C000F784290DFDF882CF7C2AE05A9C1EC8A4FE
+:1035D000F78A168439719ED3ED4DB4BE4EF83E0E77
+:1035E000F050F09D1B37C117E8C287717B15EBB413
+:1035F000F80CCE87C3B7629D97F6DB6CA3C76C0F40
+:103600009DC786039978AF6A3AEC6F7C5782D93DA3
+:10361000745FF28BC7A7A6D23A619E08D748A7630A
+:103620003CBE3F0474C2EFC188F5C87BDD72BCCBE1
+:1036300079FC1EFCE51FDC972E926B1A01BF68F720
+:10364000EE6E5F9A9171C3B8E60AFE3B12FA7D2ACC
+:10365000F7A7DC97729FCAFDFBACC91D4852827C5C
+:1036600006CED9BA97BB80D3E0411C0F33045E016C
+:10367000AE8743EF79F51AC4F15A9AAEDDEFD81F41
+:10368000F66B95E5630299F82E93AC2FC72D8DE567
+:10369000ED90EE91DEAC830C9DF517527DED3D95DE
+:1036A000F24E7EB1637902F28BDD0AF783AE39D434
+:1036B000FBA728BFEEE4F2EBB99AADF3F0BC644689
+:1036C0007F6AE8FBFEB340CE413E315B9CCF158163
+:1036D000AEF9C553599EE44121FBB9E2B19D591E93
+:1036E000CE6F02C86FFEB2F3F53F5DEF089EA77282
+:1036F0003D65ABDE37796DA1F0E37ACEC3391D7439
+:103700001FAFDC667660BC73F9322FF15F960472EE
+:10371000A112127FA6A30BEF3285EE9195D70FF37E
+:10372000ABFF837CBA7C7509BD7B20F126DF6791F6
+:10373000E7AB9CFF4831FF9B06F1F633047DCFA831
+:103740001C6D4E8E27B91BC32CD974F17D7A85F67A
+:103750007B27DE3AFDD7B92B70BFE0FD22D24F5652
+:103760009BB8BD6F07B73F9E5BB8EFF77742BDB31D
+:10377000EB37A532558B379453670B79758EB0FFB5
+:10378000758137F7A090389E39CF71BC95EFFADD7F
+:1037900067F89E5869BAE0776BF83B0065CDBB09C6
+:1037A0008FD357AD35A5213F1A94A6E1E3E575F90E
+:1037B00076B42BCF58B5C9847CC223E1A0DB0FA51A
+:1037C000224E58C219CF2525C4BF21EB237FC4F751
+:1037D000EFEF5D101685F13C729C87049D97D7C56D
+:1037E000C4E278E575DE5FA03E24CF03FD3A4F8644
+:1037F000F1FD5206FDE1BE3D39DA99BA303728CFE6
+:10380000EAEBFBC4BE7BDAC47FA72625A2F9058AB2
+:103810006B981FEE44FED1B76FAB1FC745FAC67950
+:103820009B0DFC776DFAD6B47E85F3E8CB785C0D02
+:10383000A6F83E16FA171220BFD9C0EF6FA5AB3C11
+:10384000DD26E003E5012C67F1ADF4FB1A2171B32D
+:103850001AFA35B32DF4FB89E67846EF9B497A9541
+:10386000FD487A95F4DCDDFA9EBDC6F59D4CE3F08B
+:10387000348BDF4DB9E6F559F8EFE8CA75C9F9811F
+:103880000CEFA2F73D1E1848F69E934B9CA91837E3
+:10389000D9FD7AD7152674B15EFD3AE5BE91B1F037
+:1038A0009DFEAC26EE7738A9C0F906ED4E2E08A392
+:1038B000F836B9AE1F6B0F3F382856D8775A2351C8
+:1038C000CE2C0D0FDE9747F81DAFE7BFAF2BBF4BD8
+:1038D000B940BE3327F9F7A93A716EB2D635B8BFF1
+:1038E000597D06BD7F72BCE96424BEC77272349FE5
+:1038F0009F6C77AF89DF4F66916607DE138BB8F751
+:10390000FDC244F40FAD4BCB57A0DDDDF5838FE353
+:10391000FBE3772F4B24FD7E96CDB102CFC559BE78
+:1039200034F20747ACCBFF02DFD19BB56C00FD6ED4
+:10393000EFBD0A73933E29F484D9ACF38FF4843934
+:1039400082AFCD417E89F7A5EA0FD1BB79B39D61E6
+:10395000F978BECFD9C0F58462035B85FEC43E8D85
+:10396000EEF1C8C7DA9F54F8EF3E6FD4BEC3959C02
+:10397000EDFE0CF98CFEDDBB7B4DCD2E5C07037993
+:1039800004ED4EB36C6E92EB4B05BD1C5FD746BF8A
+:103990009789F0A6DFCBD1D96FFA98F93DE2F648C6
+:1039A00003D9E300EFEFE1EF91E17BEB163A6FB45F
+:1039B000F69B3E0F0EA7DF6B93F7842A84DF49D274
+:1039C0008FF45FCDDA3499EE0FCD427BCDE0E0FD90
+:1039D000A915EBC6D2FB4E156B0BD7E3EFDCA40A9F
+:1039E000389E32B696207E4E6F4A8CC57BB915B58F
+:1039F0008D59785FA862D34ABA37747A5318DD1BA1
+:103A00001A672F1987BF1F327B23BF9F27F7A3CDCC
+:103A1000C9F76355ED58BAF7F3FF00B910AD8C0044
+:103A2000800000001F8B080000000000000BCD5636
+:103A30005B6C1465143EFF3F7BEFECA5ED527AA161
+:103A4000EDB6E5B2EAB69DA51403189834802412A9
+:103A50005D0805368176088114686B4593164364CA
+:103A600061951088711F5AA104CC52A1BEA8D986B5
+:103A70004621AE66A541A236B18117129266FB526D
+:103A80002E11BB564D69A2E039FFCC660997C44799
+:103A9000E7E5ECFFCFB97FDF39B3ED0F473EF1D457
+:103AA00000ECAA02F02C01F82B91178F3080F6431E
+:103AB000972A240E10B06A56650EC03E9EDCBCCC20
+:103AC00007708FC5074B84BE6FAE47067844CFAAF8
+:103AD000A7E5E421009F15A0E3BD9BC2CF7D3EFA80
+:103AE0007A18EDDB3B2EBAC8CFBEBE1B4B3D783FEC
+:103AF000B7462B541AC9EFB9418F0400A7CED5851C
+:103B00006A01BC0AFEC6FBF505A1CD61CC2BF3A36F
+:103B1000A40CF89E1FAFED1226DD903B6F8FBB2DDE
+:103B20001000D05260F190F480A500E51D097A12D2
+:103B300028D75743EB463977BF48417BACF38E3BE0
+:103B40005611C2FB3D83272B7C28EF3AF5F3B6C113
+:103B50002D3F810BF5CF5B2D407626B02868B7331B
+:103B6000C2D4384A682B0028C9C50F2A7922FF3DE4
+:103B7000A730A9C2DC3D405CDCDF35C13ACAA332C4
+:103B80009A09BE85F29629B50BB0CE5B5D7625828B
+:103B900058C88A4FE4732B26ADA5FBC83B0C1630E2
+:103BA0003A5F74CEC7F82D6EE8227BE792448A7B99
+:103BB000B1CFC3F98BA97DF8702802E8F4E8873506
+:103BC00092BCB60CDFEF1F621E2BBADC7FF9EA5AFB
+:103BD000D0CF00ECF9FDDCFB6005F81ECB7BEFF0ED
+:103BE00090C587F1DA3FC77A317E7B62E88752F46D
+:103BF000D3796947831E3706B014F3A09F18A773C3
+:103C000058EF4BC7F084656720E76787BFE0681906
+:103C100062BB29D1B8A50FF576106ECB910F752F29
+:103C20006C3D6C22E911FD0153A622E40438EEBF7D
+:103C30006ED1C8CFFB863FFFF5A3D5A2DE0D85F080
+:103C4000181F9A15B3B0CBDA633F845DAAC3710C19
+:103C5000EA01D44ED94432DA21BB489EE9E27E1310
+:103C6000F655650E45C27EF7D85C75E00698B1EB57
+:103C700032E9D065370F0DEDC61467F8981D90F73F
+:103C8000DD528C915C15E862D869307BB57D341FBC
+:103C9000C59060201A916294F7D4B7B71B28FECA6A
+:103CA000CAF41F802999D9CB5B57233FDE568CFA83
+:103CB00002E906E2F99C2BD04AFC3A6B8663F6C512
+:103CC00054770836D69217FC4DB8CFF2F805CC2FB2
+:103CD000C9529F92FF6CBD9F115FD14FC82A1F63CD
+:103CE00098E79F95DA41CAE30D66AE0D72C2405A5D
+:103CF00040FEA7CCFA7B889D546DC88B269D16503C
+:103D0000CE210248594B69B14CBC66AA0A3D18FF46
+:103D100048E0CA4EE2C7898C0DAC18376AF4A32973
+:103D2000E39860A8575EBA8E431DEAFBBCB00DED68
+:103D3000AF0478C48A799E005B9CF4C1B6464DFB03
+:103D4000F5188FAAD13FB7AB423F796D96A12C935E
+:103D50007E1F71A37E593753A2A8D3323D79F6173F
+:103D600094DB201EA4BEAEF66A7DB40FC6A7D74D65
+:103D70006888EF094FC2467346CFE3F9270FCCBAE4
+:103D80000A782EAFA9CCE4175F2F21695318DA35D2
+:103D900025A594B5EEE97CA68A7D268A837A294EEC
+:103DA000FA328F3346FA233729BF269B9C925C64F4
+:103DB00067FE356DCBD9C15879FEE44B20207E5487
+:103DC000065014D5715B69CC611697CB0A17B85CA5
+:103DD00036F0C9F64F248FF3B1DFA6CFC777F2E0F4
+:103DE00076E24F765EDF34EEA71F54BB69BF4C27E7
+:103DF0006BDC1078FE7CDEC0FD0A8B005EAB52BF30
+:103E0000A77EE1A3DAD07FB3D11FC41BC8AF64F88B
+:103E10006D36FAD42C73BD2F9B9EE88BC1932C0F6B
+:103E2000B2796771CEE207EF8E5D755709DC6A3FA4
+:103E30000281D7CFC4BBF1D9D10F70ACA0545227A7
+:103E4000B4AAFF235E29FB22E475A68F2B03C47F4F
+:103E50006AFC6221558EF5811FC43E68911CCAF12F
+:103E600067EC038DF6413DED839898F3199EB9CA2E
+:103E700019ED832E712E86CC61139EC779DA49F92C
+:103E8000A6EDC87A94EE60B5D8E36534D1353A4EE4
+:103E900034D7670F38078EA37E94A9FD36B48F9A66
+:103EA0008D79DF23C72FE0FD549C47CC18AF373FF7
+:103EB000DEBF1BEF7B9BE72911ECD314187A6D0E44
+:103EC000B11756702ECE9970517CA08AF471AEB1A4
+:103ED000CEDEF08BE23BFED543744E752F00FD7DA8
+:103EE00010169EA2F71BFCC2DF37D93DF3A153F891
+:103EF000EBDDA09638C4FB224EF6870B357BB091E4
+:103F000070D5F5F08F80D03B7D5A2D213C4E6FB49B
+:103F100008BD8F5928BC8BFCD4CACA05F49B0E3B44
+:103F2000BE1CD4E14831BC1FEFD1EBCDF2F7D585F3
+:103F3000FA1EAC8C4CF403B628D204FE2EE4FD38F5
+:103F4000F1B03E870F53118B821C4E593E46CC88F0
+:103F50009757C7EB087B1A2FAF8117EB41DEBA08E2
+:103F6000B784E8FF0CD771E896209D8735495C2916
+:103F7000B6A21CF36AF3F53AC74AE87D8B35DD1823
+:103F80000B109ED09678C61CD6D3929D23EA63343C
+:103F900067AD06CF5BB37C3CF8041FD3F3F227F385
+:103FA0000C3EA2FD4D472848F1EEB31B4BE972F4DD
+:103FB0001F69EBB3E22C0FEA7BE437ABB68CF4E17C
+:103FC000FC5C2EF688479FEBD1E0ED72FACEC0DFA5
+:103FD00023F3E8BBD35F187A85F4ECF333168DFA3C
+:103FE000599231533DE3E17BE5F47FA6B5E79A981A
+:103FF0009BFF9AE7BF3AB4AF4B200A0000000000D5
+:104000000000000000000000000000180000000098
+:104010000000000000000040000000000000000060
+:104020000000002800000000000000000000001058
+:104030000000000000000000000000200000000060
+:104040000000000000000010000000000000000060
+:104050000000000800000000000000000000000058
+:104060000000000000000000000000000000000050
+:104070000000000000000000000000000000000040
+:104080000000000000000000000000000000000030
+:104090000000000000000000000000000000000020
+:1040A0000000000000000000000000000000000010
+:1040B0000000000000000000000000000000000000
+:1040C00000000000000000000000000000000000F0
+:1040D00000000000000000000000000000000000E0
+:1040E00000000000000000000000000000000000D0
+:1040F00000000000000000000000000000000000C0
+:1041000000000000000000000000000000000000AF
+:10411000000000000000000000000000000000009F
+:10412000000000000000000000000000000000008F
+:10413000000000000000000000000000000000007F
+:10414000000000000000000000000000000000006F
+:10415000000000000000000000000000000000005F
+:10416000000000000000000000000000000000004F
+:104170000000332800100000000000080000333069
+:1041800000100000000000020000332800100000B2
+:104190000000001000003A78000000000000000855
+:1041A000000000000000000000000000000000000F
+:1041B00000000000000000000000000000000000FF
+:1041C0000000000000003120000000000000000896
+:1041D00000003360000100040000000100003368AB
+:1041E000000000000000000200003370000000002A
+:1041F000000000080000337400000000000000020E
+:1042000000003A70000000000000000800003A4082
+:10421000000800000000000800003D880040000089
+:104220000000004000003A500008000000000008B4
+:1042300000003A60000800000000000800003A8812
+:1042400000C800000000009800003C180098000022
+:104250000000002800003C580098000000000028E2
+:1042600000003378036000300000036000003EB0BF
+:10427000000800000000000100003EB1000800003E
+:1042800000000001000020080010000000000010E5
+:1042900000002000000000000000000800000000F6
+:1042A000000000000000000000000000000000000E
+:1042B00000000000000000000000000000000000FE
+:1042C00000000000000000000000000000000000EE
+:1042D00000000000000000000000000000000000DE
+:1042E00000000000000000000000000000000000CE
+:1042F00000000000000000000000000000000000BE
+:1043000000000000000000000000000000000000AD
+:10431000000000000000000000000000000000009D
+:10432000000000000000000000000000000000008D
+:10433000000000000000000000000000000000007D
+:10434000000000000000000000000000000000006D
+:10435000000000000000000000000000000000005D
+:10436000000000000000000000000000000000004D
+:10437000000000000000000000000000000000003D
+:10438000000000000000000000000000000000002D
+:10439000000000000000000000000000000000001D
+:1043A000000000000000000000000000000000000D
+:1043B00000000000000000000000000000000000FD
+:1043C00000000000000000000000000000000000ED
+:1043D00000000000000000000000000000000000DD
+:1043E00000000000000000000000000000000000CD
+:1043F00000000000000000000000000000000000BD
+:1044000000000000000000000000000000000000AC
+:10441000000000000000000000000000000000009C
+:10442000000000000000000000000000000000008C
+:10443000000000000000000000000000000000007C
+:10444000000000000000000000000000000012C892
+:10445000008000000000008000000001000000005B
+:1044600000000000000040000490000000000490E4
+:10447000000019C8000000000000000800004948C2
+:1044800000080000000000080000492800080000A3
+:104490000000000800004938000800000000000883
+:1044A00000002008001000000000001000002000A4
+:1044B00000000000000000080000401004900040D0
+:1044C00000000040000049980008000000000001C2
+:1044D00000004999000800000000000100000000F1
+:1044E00000000000000000000000000000000000CC
+:1044F00000000000000000000000000000000000BC
+:1045000000000000000000000000000000000000AB
+:10451000000000000000000000000000000000009B
+:10452000000000000000000000000000000000008B
+:10453000000000000000000000000000000000007B
+:10454000000000000000000000000000000000006B
+:10455000000000000000000000000000000000005B
+:10456000000000000000000000000000000000004B
+:10457000000000000000000000000000000000003B
+:10458000000000000000000000000000000000002B
+:10459000000000000000000000000000000000001B
+:1045A000000000000000000000000000000000000B
+:1045B00000000000000000000000000000000000FB
+:1045C00000000000000000000000000000000000EB
+:1045D00000000000000000000000000000000000DB
+:1045E00000000000000000000000000000000000CB
+:1045F00000000000000000000000000000000000BB
+:104600000000000000000000000040000018000052
+:1046100000000018000043000040000000000040BF
+:1046200000004300004000020000000100004301C0
+:1046300000400002000000000000300000400000C8
+:10464000000000400000000000000000000000002A
+:1046500000003000000800400000000400003004AA
+:10466000000800400000000400004B00002800008B
+:104670000000002800004B50001000000000001057
+:1046800000003800008000000000008000003800BA
+:104690000008008000000002000039000020000037
+:1046A00000000020000020080010000000000010A2
+:1046B0000000200000000000000000080000510879
+:1046C0000008000000000008000051200008000061
+:1046D0000000000800005130000800000000000841
+:1046E000000051C00008000000000001000051C19E
+:1046F0000008000000000001000039400010000424
+:1047000000000004000051D000300018000000102C
+:10471000000051D800300018000000020000000026
+:104720000000000000000000000000000000000089
+:104730000000000000000000000000000000000079
+:104740000000000000000000000000000000000069
+:104750000000000000000000000000000000000059
+:104760000000000000000000000000000000000049
+:104770000000000000000000000000000000000039
+:104780000000000000000000000000000000000029
+:104790000000000000000000000000000000000019
+:1047A0000000000000000000000000000000000009
+:1047B00000000000000000000000000000000000F9
+:1047C00000000000000000000000000000000000E9
+:1047D000000000000000000000000000000023E8CE
+:1047E00000800000000000800000000100000000C8
+:1047F0000000000000002008001000000000001071
+:1048000000002000000000000000000800002DA0B3
+:10481000000800000000000800002DB8000800009B
+:1048200000000008000024E802D00028000002D0A8
+:1048300000002E58000800000000000100002E5962
+:10484000000800000000000100002D90000800009A
+:104850000000000800000000000000000000000050
+:104860000000000000000000000000000000000048
+:104870000000000000000000000000000000000038
+:104880000000000000000000000000000000000028
+:104890000000000000000000000000000000000018
+:1048A0000000000000000000000000000000000008
+:1048B00000000000000000000000000000000000F8
+:1048C00000000000000000000000000000000000E8
+:1048D00000000000000000000000000000000000D8
+:1048E00000000000000000000000000000000000C8
+:1048F00000000000000000000000000000000000B8
+:1049000000000000000000000000000000000000A7
+:104910000000000000000000000000000000000097
+:104920000000000000000000000000000000250062
+:1049300000400000000000080000250800400000C2
+:1049400000000028000009C001200010000000083D
+:104950000000000000000000000000000000000057
+:1049600000000000000000000000402002D00028ED
+:1049700000000008000030000000000000001000EF
+:10498000000050990000000000000001000050B03D
+:104990000000000000000002000045A00090000898
+:1049A00000000008000000000000000000000000FF
+:1049B00000002960000800000000000100002961DB
+:1049C0000008000000000001000029700008000439
+:1049D0000000000200002978000800040000000424
+:1049E00000002FB0000800000000000400002FB4F9
+:1049F000000800000000000400002FC000000000BC
+:104A00000000000800002FC800000000000000089F
+:104A100000003000000000000000001000005040C6
+:104A20000001000100000001000050000000000033
+:104A30000000002000000808001000000000000432
+:104A40000000080C0010000000000001000008B782
+:104A50000000000000000001000008B60000000097
+:104A600000000001000010000030001800000004E9
+:104A700000001004003000180000000400001008BE
+:104A800000300018000000020000100A003000187A
+:104A9000000000020000100C0030001800000001AF
+:104AA0000000100D00300018000000010000100E82
+:104AB0000030001800000001000010100030001845
+:104AC0000000000400001014003000180000000472
+:104AD00000003000010000800008000400003004E5
+:104AE00001000080000800040000000A000000002F
+:104AF000000000000000306801000080000000019C
+:104B00000000306901000080000000010000306CEE
+:104B100001000080000000020000306E01000080F3
+:104B2000000000020000307001000080000000045E
+:104B300000003074010000800000000400003066B6
+:104B400001000080000000020000306401000080CD
+:104B50000000000100003060010000800000000241
+:104B600000003062010000800000000200003050B0
+:104B700001000080000000040000305401000080AB
+:104B80000000000400003058010000800000000414
+:104B90000000305C01000080000000040000307C58
+:104BA00001000080000000010000307D0100008055
+:104BB0000000000100001C180010000000000004AC
+:104BC00000001C30001000000000000400001C3831
+:104BD00000100000000000040000000000000000C1
+:104BE00000000000000000000000000000000000C5
+:104BF00000000000000000000000000000000000B5
+:104C0000000000000000000000004C100008000040
+:104C10000000000200004C1200080000000000022A
+:104C200000004C14000800000000000400004C20AC
+:104C3000000800000000000800004C3000400008A0
+:104C40000000000800004C00000800000000000206
+:104C500000004C02000800000000000100004C04AD
+:104C6000000800000000000200004CD00008000016
+:104C70000000000800004CE00008000000000004F4
+:104C800000004CE4000800000000000100004CF0AF
+:104C9000000800000000000200004CF400080000C2
+:104CA0000000000200004D000008000000000004A9
+:104CB000000050000010000000000004000050043C
+:104CC0000010000000000004000050080010000068
+:104CD00000000004000014000008000000000002B2
+:104CE000000014020008000000000001000014048D
+:104CF000000800000000000200001410000800007E
+:104D0000000000020000141400080000000000026F
+:104D1000000014160008000000000002000019B88E
+:104D20000008000000000008000014200008000037
+:104D3000000000020000142400080000000000022F
+:104D4000000019C8000800000000000800002C1036
+:104D5000000800000000000100002C110008000005
+:104D60000000000100002C120008000000000001FB
+:104D700000002C13000800000000000100002C00BF
+:104D8000000800000000000200002C0200080000E3
+:104D90000000000100002C040008000000000002D8
+:104DA00000002C30000800000000000200002C323F
+:104DB000000800000000000200002C340008000081
+:104DC0000000000200002C2000080000000000018C
+:104DD00000002C21000800000000000100002C222F
+:104DE000000800000000000100002C230008000063
+:104DF0000000000100002C24000800000000000159
+:104E000000002C25000800000000000100002C26F6
+:104E1000000800000000000100001400000800006D
+:104E20000000000200001402000800000000000161
+:104E3000000014040008000000000002000014122A
+:104E400000C00018000000020000141000C000188C
+:104E5000000000020000141C00C000180000000840
+:104E60000000141400C000180000000800001427FF
+:104E700000C00018000000010000142400C0001849
+:104E8000000000020000142600C00018000000010D
+:104E9000000015900008000000000008000015A0A8
+:104EA0000008000000000008000015B00008000025
+:104EB00000000008000000000000000000000000EA
+:104EC00000000000000000000000000000000000E2
+:104ED00000000000000000000000000000000000D2
+:104EE00000000000000000000000000000000000C2
+:104EF00000000000000000000000000000000000B2
+:104F000000000000000000000000000000000000A1
+:104F10000000000000000000000000000000000091
+:104F20000000000000000000000000000000000081
+:104F30000000000000000000000000000000000071
+:104F40000000000000000000000000000000000061
+:104F50000000000000000000000000000000000051
+:104F60000000000000000000000000000000000041
+:104F70000000000000000000000000000000000031
+:104F80000000000000000000000000000000000021
+:104F90000000000000000000000000000000000011
+:104FA0000000000000000000000000000000000001
+:104FB00000000000000000000000000000000000F1
+:104FC00000000000000000000000000000000000E1
+:104FD00000000000000000000000000000000000D1
+:104FE00000000000000000000000000000000000C1
+:104FF00000000000000000000000000000000000B1
+:105000000000000000000000060022000000000078
+:00000001FF
diff --git a/firmware/bnx2x/bnx2x-e1h-6.0.34.0.fw.ihex b/firmware/bnx2x/bnx2x-e1h-6.0.34.0.fw.ihex
new file mode 100644
index 000000000000..54f36f1d256d
--- /dev/null
+++ b/firmware/bnx2x/bnx2x-e1h-6.0.34.0.fw.ihex
@@ -0,0 +1,13178 @@
+:1000000000004F48000000680000070C00004FB8D7
+:1000100000001ED4000056C800000094000075A027
+:1000200000009EFC00007638000000CC000115386E
+:100030000000DC6400011608000000940001F2706A
+:10004000000040180001F308000000A4000233285B
+:100050000000F378000233D000000FFC00032750AB
+:100060000000000400033750020400480000000FA5
+:1000700002040054000000450204005C0000000679
+:100080000204007000000004020400780000000078
+:100090000204007C121700000204008022170000F6
+:1000A00002040084321700000604008800000005E6
+:1000B0000204009C12150000020400A0221500009A
+:1000C000020400A432150000060400A80000000489
+:1000D000020400B802100000020400BC001000007E
+:1000E000020400C010100000020400C42010000030
+:1000F000020400C830100000020400CC40100000D0
+:10010000060400D000000003020400DC0010000020
+:10011000020400E012140000020400E422140000B3
+:10012000020400E832140000020400EC4214000053
+:10013000060400F000000003010401240000000098
+:1001400001040128000000000104012C000000004F
+:100150000104013000000000020401D00000890603
+:1001600002040004000000FF02040008000000FF79
+:100170000204000C000000FF02040010000000FF59
+:10018000020400140000007F02040018000000FFB9
+:100190000204001C000000FF02040020000000FF19
+:1001A000020400240000003E0204002800000000B9
+:1001B0000204002C0000003F020400300000003F59
+:1001C000020400340000003F020400380000003F39
+:1001D0000204003C0000003F020400400000003F19
+:1001E000020400440000003F020404CC00000001AF
+:1001F00002042008000002110204200C000002008A
+:10020000020420100000020402042014000002195D
+:100210000204201C0000FFFF020420200000FFFF5A
+:10022000020420240000FFFF020420280000FFFF3A
+:1002300002042038000000200604203C0000001FBB
+:10024000020420B800000001060420BC0000005F8A
+:100250000204223807FFFFFF0204223C0000003F97
+:100260000204224007FFFFFF020422440000000FA7
+:1002700001042248000000000104224C000000009C
+:10028000010422500000000001042254000000007C
+:1002900001042258000000000104225C000000005C
+:1002A000010422600000000001042264000000003C
+:1002B00001042268000000000104226C000000001C
+:1002C00001042270000000000104227400000000FC
+:1002D00001042278000000000104227C00000000DC
+:1002E0000C042000000003E80A04200000000001C4
+:1002F0000B0420000000000A0605400000000D006D
+:100300000205004400000020020500480000003201
+:10031000020500900215002002050094021500203D
+:1003200002050098000000300205009C0810000043
+:10033000020500A000000033020500A40000003008
+:10034000020500A800000031020500AC0000000218
+:10035000020500B000000005020500B40000000620
+:10036000020500B800000002020500BC0000000207
+:10037000020500C000000000020500C400000005E6
+:10038000020500C800000002020500CC00000002C7
+:10039000020500D000000002020500D400000001A8
+:1003A00002050114000000010205011C000000010B
+:1003B0000205012000000002020502040000000105
+:1003C0000205020C0000004002050210000000407F
+:1003D0000205021C0000002002050220000000139C
+:1003E0000205022400000020060502400000000A69
+:1003F00004050280002000000205005000000007F4
+:10040000020500540000000702050058000000002B
+:100410000205005C00000008020500600000000109
+:100420000605006400000003020500D80000000675
+:1004300002050004000000010205000800000001A0
+:100440000205000C00000001020500100000000180
+:100450000205001400000001020500180000000160
+:100460000205001C00000001020500200000000140
+:100470000205002400000001020500280000000120
+:100480000205002C00000001020500300000000100
+:1004900002050034000000010205003800000001E0
+:1004A0000205003C000000010205004000000001C0
+:1004B000020500E00000000D020500E80000000059
+:1004C000020500F000000000020500F80000000036
+:1004D000020500E40000002D020500EC00000020F1
+:1004E000020500F400000020020500FC00000020CE
+:1004F000020500E00000001D020500E800000010F9
+:10050000020500F000000010020500F800000010D5
+:10051000020500E40000003D020500EC0000003090
+:10052000020500F400000030020500FC000000306D
+:10053000020500E00000004D020500E80000004058
+:10054000020500F000000040020500F80000004035
+:10055000020500E40000006D020500EC00000060F0
+:10056000020500F400000060020500FC00000060CD
+:10057000020500E00000005D020500E800000050F8
+:10058000020500F000000050020500F800000050D5
+:10059000020500E40000007D020500EC0000007090
+:1005A000020500F400000070020500FC000000706D
+:1005B0000406100002000020020600DC000000011A
+:1005C000010600D80000000004060200000302201B
+:1005D000020600DC00000000010600B80000000078
+:1005E000010600C8000000000206016C00000000C7
+:1005F000010600BC00000000010600CC0000000065
+:1006000002060170000000000718040000910000BD
+:10061000081807D800050223071C00002BDC000087
+:10062000071C80002DE90AF8071D00002F521673E1
+:10063000071D800015DB2248081DB0B049EA0225DD
+:100640000118000000000000011800040000000074
+:1006500001180008000000000118000C0000000054
+:100660000118001000000000011800140000000034
+:1006700002180020000000010218002400000002FF
+:1006800002180028000000030218002C00000000DF
+:1006900002180030000000040218003400000001BD
+:1006A00002180038000000000218003C00000001A1
+:1006B000021800400000000402180044000000007E
+:1006C00002180048000000010218004C000000035E
+:1006D0000218005000000000021800540000000141
+:1006E00002180058000000040218005C000000001E
+:1006F00002180060000000010218006400000003FE
+:1007000002180068000000000218006C00000001E0
+:1007100002180070000000040218007400000000BD
+:1007200002180078000000040218007C000000039A
+:100730000618008000000002021800A400003FFF1D
+:10074000021800A8000003FF0218022400000000A5
+:1007500002180234000000000218024C00000000E1
+:10076000021802E4000000FF061810000000040058
+:10077000021B8BC000000001021B8000000000343F
+:10078000021B804000000018021B80800000000C4B
+:10079000021B80C0000000200C1B83000007A1206A
+:1007A0000A1B8300000001380B1B83000000138824
+:1007B0000A1B8340000000000C1B8340000001F472
+:1007C0000B1B834000000005021B83800007A12053
+:1007D000021B83C0000001F4021B14800000000112
+:1007E0000A1B148000000000061A1000000003B36A
+:1007F000041A1ECC00010227061A1ED000000008B1
+:10080000061A2008000000C8061A20000000000296
+:10081000041AAF4000100228061A3718000000041E
+:10082000061A371000000002061A500000000002ED
+:10083000061A500800000004061A501800000004B0
+:10084000061A502800000004061A50380000000460
+:10085000061A504800000004061A50580000000410
+:10086000061A506800000004061A507800000002C2
+:10087000041A52C000020238061A40500000000656
+:10088000041A40680002023A041A40400004023C84
+:10089000041A800000010240061A800400000003D0
+:1008A000041A801000010241061A8014000000039F
+:1008B000041A802000010242061A8024000000036E
+:1008C000041A803000010243061A8034000000033D
+:1008D000041A804000010244061A8044000000030C
+:1008E000041A805000010245061A805400000003DB
+:1008F000041A806000010246061A806400000003AA
+:10090000041A807000010247061A80740000000378
+:10091000041A808000010248061A80840000000347
+:10092000041A809000010249061A80940000000316
+:10093000041A80A00001024A061A80A400000003E5
+:10094000041A80B00001024B061A80B400000003B4
+:10095000041A80C00001024C061A80C40000000383
+:10096000041A80D00001024D061A80D40000000352
+:10097000041A80E00001024E061A80E40000000321
+:10098000041A80F00001024F061A80F400000003F0
+:10099000041A810000010250061A810400000003BD
+:1009A000041A811000010251061A8114000000038C
+:1009B000041A812000010252061A8124000000035B
+:1009C000041A813000010253061A8134000000032A
+:1009D000041A814000010254061A814400000003F9
+:1009E000041A815000010255061A815400000003C8
+:1009F000041A816000010256061A81640000000397
+:100A0000041A817000010257061A81740000000365
+:100A1000041A818000010258061A81840000000334
+:100A2000041A819000010259061A81940000000303
+:100A3000041A81A00001025A061A81A400000003D2
+:100A4000041A81B00001025B061A81B400000003A1
+:100A5000041A81C00001025C061A81C40000000370
+:100A6000041A81D00001025D061A81D4000000033F
+:100A7000041A81E00001025E061A81E4000000030E
+:100A8000041A81F00001025F061A81F400000003DD
+:100A9000041A820000010260061A820400000003AA
+:100AA000041A821000010261061A82140000000379
+:100AB000041A822000010262061A82240000000348
+:100AC000041A823000010263061A82340000000317
+:100AD000041A824000010264061A824400000003E6
+:100AE000041A825000010265061A825400000003B5
+:100AF000041A826000010266061A82640000000384
+:100B0000041A827000010267061A82740000000352
+:100B1000041A828000010268061A82840000000321
+:100B2000041A829000010269061A829400000003F0
+:100B3000041A82A00001026A061A82A400000003BF
+:100B4000041A82B00001026B061A82B4000000038E
+:100B5000041A82C00001026C061A82C4000000035D
+:100B6000041A82D00001026D061A82D4000000032C
+:100B7000041A82E00001026E061A82E400000003FB
+:100B8000041A82F00001026F061A82F400000003CA
+:100B9000041A830000010270061A83040000000397
+:100BA000041A831000010271061A83140000000366
+:100BB000041A832000010272061A83240000000335
+:100BC000041A833000010273061A83340000000304
+:100BD000041A834000010274061A834400000003D3
+:100BE000041A835000010275061A835400000003A2
+:100BF000041A836000010276061A83640000000371
+:100C0000041A837000010277061A8374000000033F
+:100C1000041A838000010278061A8384000000030E
+:100C2000041A839000010279061A839400000003DD
+:100C3000041A83A00001027A061A83A400000003AC
+:100C4000041A83B00001027B061A83B4000000037B
+:100C5000041A83C00001027C061A83C4000000034A
+:100C6000041A83D00001027D061A83D40000000319
+:100C7000041A83E00001027E061A83E400000003E8
+:100C8000041A83F00001027F061A83F400000003B7
+:100C9000041A840000010280061A84040000000384
+:100CA000041A841000010281061A84140000000353
+:100CB000041A842000010282061A84240000000322
+:100CC000041A843000010283061A843400000003F1
+:100CD000041A844000010284061A844400000003C0
+:100CE000041A845000010285061A8454000000038F
+:100CF000041A846000010286061A8464000000035E
+:100D0000041A847000010287061A8474000000032C
+:100D1000041A848000010288061A848400000003FB
+:100D2000041A849000010289061A849400000003CA
+:100D3000041A84A00001028A061A84A40000000399
+:100D4000041A84B00001028B061A84B40000000368
+:100D5000041A84C00001028C061A84C40000000337
+:100D6000041A84D00001028D061A84D40000000306
+:100D7000041A84E00001028E061A84E400000003D5
+:100D8000041A84F00001028F061A84F400000003A4
+:100D9000041A850000010290061A85040000000371
+:100DA000041A851000010291061A85140000000340
+:100DB000041A852000010292061A8524000000030F
+:100DC000041A853000010293061A853400000003DE
+:100DD000041A854000010294061A854400000003AD
+:100DE000041A855000010295061A8554000000037C
+:100DF000041A856000010296061A8564000000034B
+:100E0000041A857000010297061A85740000000319
+:100E1000041A858000010298061A858400000003E8
+:100E2000041A859000010299061A859400000003B7
+:100E3000041A85A00001029A061A85A40000000386
+:100E4000041A85B00001029B061A85B40000000355
+:100E5000041A85C00001029C061A85C40000000324
+:100E6000041A85D00001029D061A85D400000003F3
+:100E7000041A85E00001029E061A85E400000003C2
+:100E8000041A85F00001029F061A85F40000000391
+:100E9000041A8600000102A0061A8604000000035E
+:100EA000041A8610000102A1061A8614000000032D
+:100EB000041A8620000102A2061A862400000003FC
+:100EC000041A8630000102A3061A863400000003CB
+:100ED000041A8640000102A4061A8644000000039A
+:100EE000041A8650000102A5061A86540000000369
+:100EF000041A8660000102A6061A86640000000338
+:100F0000041A8670000102A7061A86740000000306
+:100F1000041A8680000102A8061A868400000003D5
+:100F2000041A8690000102A9061A869400000003A4
+:100F3000041A86A0000102AA061A86A40000000373
+:100F4000041A86B0000102AB061A86B40000000342
+:100F5000041A86C0000102AC061A86C40000000311
+:100F6000041A86D0000102AD061A86D400000003E0
+:100F7000041A86E0000102AE061A86E400000003AF
+:100F8000041A86F0000102AF061A86F4000000037E
+:100F9000041A8700000102B0061A8704000000034B
+:100FA000041A8710000102B1061A8714000000031A
+:100FB000041A8720000102B2061A872400000003E9
+:100FC000041A8730000102B3061A873400000003B8
+:100FD000041A8740000102B4061A87440000000387
+:100FE000041A8750000102B5061A87540000000356
+:100FF000041A8760000102B6061A87640000000325
+:10100000041A8770000102B7061A877400000003F3
+:10101000041A8780000102B8061A878400000003C2
+:10102000041A8790000102B9061A87940000000391
+:10103000041A87A0000102BA061A87A40000000360
+:10104000041A87B0000102BB061A87B4000000032F
+:10105000041A87C0000102BC061A87C400000003FE
+:10106000041A87D0000102BD061A87D400000003CD
+:10107000041A87E0000102BE061A87E4000000039C
+:10108000041A87F0000102BF061A87F4000000036B
+:10109000041A8800000102C0061A88040000000338
+:1010A000041A8810000102C1061A88140000000307
+:1010B000041A8820000102C2061A882400000003D6
+:1010C000041A8830000102C3061A883400000003A5
+:1010D000041A8840000102C4061A88440000000374
+:1010E000041A8850000102C5061A88540000000343
+:1010F000041A8860000102C6061A88640000000312
+:10110000041A8870000102C7061A887400000003E0
+:10111000041A8880000102C8061A888400000003AF
+:10112000041A8890000102C9061A8894000000037E
+:10113000041A88A0000102CA061A88A4000000034D
+:10114000041A88B0000102CB061A88B4000000031C
+:10115000041A88C0000102CC061A88C400000003EB
+:10116000041A88D0000102CD061A88D400000003BA
+:10117000041A88E0000102CE061A88E40000000389
+:10118000041A88F0000102CF061A88F40000000358
+:10119000041A8900000102D0061A89040000000325
+:1011A000041A8910000102D1061A891400000003F4
+:1011B000041A8920000102D2061A892400000003C3
+:1011C000041A8930000102D3061A89340000000392
+:1011D000041A8940000102D4061A89440000000361
+:1011E000041A8950000102D5061A89540000000330
+:1011F000041A8960000102D6061A896400000003FF
+:10120000041A8970000102D7061A897400000003CD
+:10121000041A8980000102D8061A8984000000039C
+:10122000041A8990000102D9061A8994000000036B
+:10123000041A89A0000102DA061A89A4000000033A
+:10124000041A89B0000102DB061A89B40000000309
+:10125000041A89C0000102DC061A89C400000003D8
+:10126000041A89D0000102DD061A89D400000003A7
+:10127000041A89E0000102DE061A89E40000000376
+:10128000041A89F0000102DF061A89F40000000345
+:10129000041A8A00000102E0061A8A040000000312
+:1012A000041A8A10000102E1061A8A1400000003E1
+:1012B000041A8A20000102E2061A8A2400000003B0
+:1012C000041A8A30000102E3061A8A34000000037F
+:1012D000041A8A40000102E4061A8A44000000034E
+:1012E000041A8A50000102E5061A8A54000000031D
+:1012F000041A8A60000102E6061A8A6400000003EC
+:10130000041A8A70000102E7061A8A7400000003BA
+:10131000041A8A80000102E8061A8A840000000389
+:10132000041A8A90000102E9061A8A940000000358
+:10133000041A8AA0000102EA061A8AA40000000327
+:10134000041A8AB0000102EB061A8AB400000003F6
+:10135000041A8AC0000102EC061A8AC400000003C5
+:10136000041A8AD0000102ED061A8AD40000000394
+:10137000041A8AE0000102EE061A8AE40000000363
+:10138000041A8AF0000102EF061A8AF40000000332
+:10139000041A8B00000102F0061A8B0400000003FF
+:1013A000041A8B10000102F1061A8B1400000003CE
+:1013B000041A8B20000102F2061A8B24000000039D
+:1013C000041A8B30000102F3061A8B34000000036C
+:1013D000041A8B40000102F4061A8B44000000033B
+:1013E000041A8B50000102F5061A8B54000000030A
+:1013F000041A8B60000102F6061A8B6400000003D9
+:10140000041A8B70000102F7061A8B7400000003A7
+:10141000041A8B80000102F8061A8B840000000376
+:10142000041A8B90000102F9061A8B940000000345
+:10143000041A8BA0000102FA061A8BA40000000314
+:10144000041A8BB0000102FB061A8BB400000003E3
+:10145000041A8BC0000102FC061A8BC400000003B2
+:10146000041A8BD0000102FD061A8BD40000000381
+:10147000041A8BE0000102FE061A8BE40000000350
+:10148000041A8BF0000102FF061A8BF4000000031F
+:10149000041A8C0000010300061A8C0400000003EB
+:1014A000041A8C1000010301061A8C1400000003BA
+:1014B000041A8C2000010302061A8C240000000389
+:1014C000041A8C3000010303061A8C340000000358
+:1014D000041A8C4000010304061A8C440000000327
+:1014E000041A8C5000010305061A8C5400000003F6
+:1014F000041A8C6000010306061A8C6400000003C5
+:10150000041A8C7000010307061A8C740000000393
+:10151000041A8C8000010308061A8C840000000362
+:10152000041A8C9000010309061A8C940000000331
+:10153000041A8CA00001030A061A8CA40000000300
+:10154000041A8CB00001030B061A8CB400000003CF
+:10155000041A8CC00001030C061A8CC4000000039E
+:10156000041A8CD00001030D061A8CD4000000036D
+:10157000041A8CE00001030E061A8CE4000000033C
+:10158000041A8CF00001030F061A8CF4000000030B
+:10159000041A8D0000010310061A8D0400000003D8
+:1015A000041A8D1000010311061A8D1400000003A7
+:1015B000041A8D2000010312061A8D240000000376
+:1015C000041A8D3000010313061A8D340000000345
+:1015D000041A8D4000010314061A8D440000000314
+:1015E000041A8D5000010315061A8D5400000003E3
+:1015F000041A8D6000010316061A8D6400000003B2
+:10160000041A8D7000010317061A8D740000000380
+:10161000041A8D8000010318061A8D84000000034F
+:10162000041A8D9000010319061A8D94000000031E
+:10163000041A8DA00001031A061A8DA400000003ED
+:10164000041A8DB00001031B061A8DB400000003BC
+:10165000041A8DC00001031C061A8DC4000000038B
+:10166000041A8DD00001031D061A8DD4000000035A
+:10167000041A8DE00001031E061A8DE40000000329
+:10168000041A8DF00001031F061A8DF400000003F8
+:10169000041A8E0000010320061A8E0400000003C5
+:1016A000041A8E1000010321061A8E140000000394
+:1016B000041A8E2000010322061A8E240000000363
+:1016C000041A8E3000010323061A8E340000000332
+:1016D000041A8E4000010324061A8E440000000301
+:1016E000041A8E5000010325061A8E5400000003D0
+:1016F000041A8E6000010326061A8E64000000039F
+:10170000041A8E7000010327061A8E74000000036D
+:10171000041A8E8000010328061A8E84000000033C
+:10172000041A8E9000010329061A8E94000000030B
+:10173000041A8EA00001032A061A8EA400000003DA
+:10174000041A8EB00001032B061A8EB400000003A9
+:10175000041A8EC00001032C061A8EC40000000378
+:10176000041A8ED00001032D061A8ED40000000347
+:10177000041A8EE00001032E061A8EE40000000316
+:10178000041A8EF00001032F061A8EF400000003E5
+:10179000041A8F0000010330061A8F0400000003B2
+:1017A000041A8F1000010331061A8F140000000381
+:1017B000041A8F2000010332061A8F240000000350
+:1017C000041A8F3000010333061A8F34000000031F
+:1017D000041A8F4000010334061A8F4400000003EE
+:1017E000041A8F5000010335061A8F5400000003BD
+:1017F000041A8F6000010336061A8F64000000038C
+:10180000041A8F7000010337061A8F74000000035A
+:10181000041A8F8000010338061A8F840000000329
+:10182000041A8F9000010339061A8F9400000003F8
+:10183000041A8FA00001033A061A8FA400000003C7
+:10184000041A8FB00001033B061A8FB40000000396
+:10185000041A8FC00001033C061A8FC40000000365
+:10186000041A8FD00001033D061A8FD40000000334
+:10187000041A8FE00001033E061A8FE400000007FF
+:10188000041A62C00020033F061AD0000000007254
+:10189000061AD24800000010061AD6B00000002038
+:1018A000061AD47000000090061AD46800000002E6
+:1018B000061AA000000001C4061A30000000001043
+:1018C000061A308000000010061A310000000010D7
+:1018D000061A318000000010061A330000000012C2
+:1018E000061A339000000070061AD4580000000257
+:1018F000061AD34800000002061AD3580000002040
+:10190000061AA710000001C4061A3040000000109B
+:10191000061A30C000000010061A31400000001006
+:10192000061A31C000000010061A334800000012E9
+:10193000061A355000000070061AD460000000023C
+:10194000061AD35000000002061AD3D80000002067
+:10195000021AAE2000000000061A5000000000022B
+:10196000061A508000000012041A40000002035FB3
+:10197000041A63C000020361061A7000000000042C
+:10198000061A320000000008021AAE24000000000F
+:10199000061A501000000002061A50C8000000127B
+:1019A000041A400800020363041A63C800020365B6
+:1019B000061A701000000004061A32200000000809
+:1019C000021AAE2800000000061A50200000000293
+:1019D000061A511000000012041A4010000203679A
+:1019E000041A63D000020369061A70200000000484
+:1019F000061A324000000008021AAE2C0000000057
+:101A0000061A503000000002061A51580000001259
+:101A1000041A40180002036B041A63D80002036D15
+:101A2000061A703000000004061A32600000000838
+:101A3000021AAE3000000000061A504000000002FA
+:101A4000061A51A000000012041A40200002036F81
+:101A5000041A63E000020371061A704000000004DB
+:101A6000061A328000000008021AAE34000000009E
+:101A7000061A505000000002061A51E80000001239
+:101A8000041A402800020373041A63E80002037575
+:101A9000061A705000000004061A32A00000000868
+:101AA000021AAE3800000000061A50600000000262
+:101AB000061A523000000012041A40300002037768
+:101AC000041A63F000020379061A70600000000433
+:101AD000061A32C000000008021AAE3C00000000E6
+:101AE000061A507000000002061A52780000001218
+:101AF000041A40380002037B041A63F80002037DD5
+:101B0000061A707000000004061A32E00000000897
+:101B10000200A468000B01C80200A294071D29114D
+:101B20000200A298000000000200A29C009C042475
+:101B30000200A2A0000000000200A2A4000002090E
+:101B40000200A270000000000200A2740000000069
+:101B50000200A270000000000200A2740000000059
+:101B60000200A270000000000200A2740000000049
+:101B70000200A270000000000200A2740000000039
+:101B8000020160A000000001020160A400000262E6
+:101B9000020160A800000002020160AC0000001811
+:101BA0000201620400000001020100B40000000113
+:101BB000020100B800000001020100DC0000000189
+:101BC0000201010000000001020101040000000107
+:101BD0000201007C003000000201008400000028A7
+:101BE0000201008C0000000002010130000000042E
+:101BF0000201025C00000001020103280000000055
+:101C0000020160580000FFFF020160700000000741
+:101C10000201608000000001020105540000003054
+:101C2000020100C400000001020100CC000000011C
+:101C3000020100F800000001020100F000000001B4
+:101C4000020100800030000002010088000000282E
+:101C500002010090000000000201013400000004B5
+:101C6000020102DC000000010201032C0000000060
+:101C70000201605C0000FFFF0201607400000007C9
+:101C800002016084000000010201056400000030D0
+:101C9000020100C800000001020100D000000001A4
+:101CA000020100FC00000001020100F4000000013C
+:101CB000020C100000000028020C20080000021195
+:101CC000020C200C00000200020C20100000020494
+:101CD000020C201C0000FFFF020C20200000FFFF70
+:101CE000020C20240000FFFF020C20280000FFFF50
+:101CF000020C203800000020020C203C00000021D3
+:101D0000020C204000000022020C204400000023AE
+:101D1000020C204800000024020C204C000000258A
+:101D2000020C205000000026020C20540000002766
+:101D3000020C205800000028020C205C0000002942
+:101D4000020C20600000002A020C20640000002B1E
+:101D5000020C20680000002C020C206C0000002DFA
+:101D6000020C20700000002E020C20740000002FD6
+:101D7000020C207800000010060C207C00000007F8
+:101D8000020C209800000011020C209C00000012A0
+:101D9000020C20A000000013060C20A40000001D6F
+:101DA000020C211800000001020C211C000000019F
+:101DB000020C212000000001060C21240000001D5F
+:101DC000020C219800000001060C219C0000000775
+:101DD000020C21B800000001020C21BC000000012F
+:101DE000020C21C000000001020C21C4000000010F
+:101DF000020C21C800000001020C21CC00000001EF
+:101E0000020C21D000000001020C21D400000001CE
+:101E1000020C21D800000001020C21DC00000001AE
+:101E2000020C21E000000001020C21E4000000018E
+:101E3000020C21E800000001020C21EC000000016E
+:101E4000020C21F000000001020C21F4000000014E
+:101E5000020C21F800000001060C21FC0000000724
+:101E6000020C221800000001060C221C00000007D2
+:101E7000020C223807FFFFFF020C223C0000003F4B
+:101E8000020C224007FFFFFF020C22440000000F5B
+:101E9000010C224800000000010C224C0000000050
+:101EA000010C225000000000010C22540000000030
+:101EB000010C225800000000010C225C0000000010
+:101EC000010C226000000000010C226400000000F0
+:101ED000010C226800000000010C226C00000000D0
+:101EE000010C227000000000010C227400000000B0
+:101EF000010C227800000000010C227C0000000090
+:101F00000C0C2000000003E80A0C20000000000177
+:101F10000B0C20000000000A020C40080000101109
+:101F2000020C400C00001000020C401000001004D5
+:101F3000020C401400001021020C401C0000FFFFA6
+:101F4000020C40200000FFFF020C40240000FFFFB5
+:101F5000020C40280000FFFF020C40380000004641
+:101F6000020C403C00000010060C40400000000243
+:101F7000020C404800000018020C404C000000F029
+:101F8000060C40500000001F020C40CC0000000175
+:101F9000060C40D00000003A020C41B800000001DD
+:101FA000060C41BC00000003020C41C80000000107
+:101FB000020C41CC00000001060C41D00000001AC8
+:101FC000020C423807FFFFFF020C423C0000003FBA
+:101FD000020C424007FFFFFF020C42440000000FCA
+:101FE000010C424800000000010C424C00000000BF
+:101FF000010C425000000000010C4254000000009F
+:10200000010C425800000000010C425C000000007E
+:10201000010C426000000000010C4264000000005E
+:10202000010C426800000000010C426C000000003E
+:10203000010C427000000000010C4274000000001E
+:10204000010C427800000000010C427C00000000FE
+:10205000010C4280000000000C0C4000000003E86E
+:102060000A0C4000000000010B0C40000000000AB8
+:10207000060D400000000A00020D0044000000327E
+:10208000020D008C02150020020D009002150020A8
+:10209000020D009408100000020D009800000033AB
+:1020A000020D009C00000002020D00A000000000D4
+:1020B000020D00A400000005020D00A800000005AC
+:1020C000060D00AC00000002020D00B4000000028A
+:1020D000020D00B800000003020D00BC0000000269
+:1020E000020D00C000000001020D00C80000000247
+:1020F000020D00CC00000002020D015C0000000196
+:10210000020D016400000001020D016800000002E0
+:10211000020D020400000001020D020C000000206C
+:10212000020D021000000040020D021400000040E9
+:10213000020D022000000003020D0224000000181E
+:10214000060D028000000012040D03000018037F3A
+:10215000060D03600000000C020D004C00000001A1
+:10216000020D005000000002020D005400000000AB
+:10217000020D005800000008060D005C000000047D
+:10218000020D00C400000004020D00040000000164
+:10219000020D000800000001020D000C000000010B
+:1021A000020D001000000001020D001400000001EB
+:1021B000020D001800000001020D001C00000001CB
+:1021C000020D002000000001020D002400000001AB
+:1021D000020D002800000001020D002C000000018B
+:1021E000020D003000000001020D0034000000016B
+:1021F000020D003800000001020D003C000000014B
+:10220000020D011400000009020D011C0000000A6B
+:10221000020D012400000000020D012C000000004E
+:10222000020D013400000000020D013C0000000B13
+:10223000020D014400000000020D011800000029F9
+:10224000020D01200000002A020D012800000020DC
+:10225000020D013000000020020D013800000020B6
+:10226000020D01400000002B020D0148000000207B
+:10227000020D011400000019020D011C0000001ADB
+:10228000020D012400000010020D012C00000010BE
+:10229000020D013400000010020D013C0000001B83
+:1022A000020D014400000010020D01180000003969
+:1022B000020D01200000003A020D0128000000304C
+:1022C000020D013000000030020D01380000003026
+:1022D000020D01400000003B020D014800000030EB
+:1022E000020D011400000049020D011C0000004A0B
+:1022F000020D012400000040020D012C00000040EE
+:10230000020D013400000040020D013C0000004BB2
+:10231000020D014400000040020D01180000006998
+:10232000020D01200000006A020D0128000000607B
+:10233000020D013000000060020D01380000006055
+:10234000020D01400000006B020D0148000000601A
+:10235000020D011400000059020D011C0000005A7A
+:10236000020D012400000050020D012C000000505D
+:10237000020D013400000050020D013C0000005B22
+:10238000020D014400000050020D01180000007908
+:10239000020D01200000007A020D012800000070EB
+:1023A000020D013000000070020D013800000070C5
+:1023B000020D01400000007B020D0148000000708A
+:1023C000060E200000000800020E004C0000003243
+:1023D000020E009402150020020E00980215002043
+:1023E000020E009C00000030020E00A00810000049
+:1023F000020E00A400000033020E00A8000000300E
+:10240000020E00AC00000031020E00B0000000021D
+:10241000020E00B400000004020E00B8000000002C
+:10242000020E00BC00000002020E00C0000000020C
+:10243000020E00C400000000020E00C800000002EE
+:10244000020E00CC00000007020E00D000000002C7
+:10245000020E00D400000002020E00D800000001AD
+:10246000020E014400000001020E014C00000001B8
+:10247000020E015000000002020E020400000001E2
+:10248000020E020C00000040020E0210000000408C
+:10249000020E021C00000004020E022000000020B8
+:1024A000020E02240000000E020E02280000001B93
+:1024B000060E030000000012040E0280001B0397AA
+:1024C000060E02EC00000005020E00540000000C95
+:1024D000020E00580000000C020E005C000000001C
+:1024E000020E006000000010020E006400000010E8
+:1024F000060E006800000003020E00DC000000036E
+:10250000020E000400000001020E0008000000019D
+:10251000020E000C00000001020E0010000000017D
+:10252000020E001400000001020E0018000000015D
+:10253000020E001C00000001020E0020000000013D
+:10254000020E002400000001020E0028000000011D
+:10255000020E002C00000001020E003000000001FD
+:10256000020E003400000001020E003800000001DD
+:10257000020E003C00000001020E004000000001BD
+:10258000020E004400000001020E01100000000FC6
+:10259000020E011800000000020E012000000000E1
+:1025A000020E012800000000020E01140000002F9E
+:1025B000020E011C00000020020E01240000000099
+:1025C000020E012C00000000020E01100000001F8E
+:1025D000020E011800000010020E01200000000091
+:1025E000020E012800000000020E01140000003F4E
+:1025F000020E011C00000030020E01240000000049
+:10260000020E012C00000000020E01100000004F1D
+:10261000020E011800000040020E01200000000020
+:10262000020E012800000000020E01140000006FDD
+:10263000020E011C00000060020E012400000000D8
+:10264000020E012C00000000020E01100000005FCD
+:10265000020E011800000050020E012000000000D0
+:10266000020E012800000000020E01140000007F8D
+:10267000020E011C00000070020E01240000000088
+:10268000020E012C000000000730040000C800000A
+:10269000083007D8000503B207340000332C0000CF
+:1026A0000734800030AC0CCC07350000353318F807
+:1026B000073580002A7126450736000018DA30E217
+:1026C00008364670373203B40130000000000000C5
+:1026D000013000040000000001300008000000008C
+:1026E0000130000C0000000001300010000000006C
+:1026F0000130001400000000023000200000000142
+:102700000230002400000002023000280000000314
+:102710000230002C000000000230003000000004F5
+:1027200002300034000000010230003800000000D8
+:102730000230003C000000010230004000000004B4
+:102740000230004400000000023000480000000198
+:102750000230004C00000003023000500000000076
+:102760000230005400000001023000580000000454
+:102770000230005C00000000023000600000000138
+:102780000230006400000003023000680000000016
+:102790000230006C000000010230007000000004F4
+:1027A00002300074000000000230007800000004D5
+:1027B0000230007C000000030630008000000002B0
+:1027C000023000A400003FFF023000A8000003FF19
+:1027D0000230022400000000023002340000000039
+:1027E0000230024C00000000023002E40000FFFF53
+:1027F000063020000000080002338BC000000001FA
+:10280000023380000000001A023380400000004EB6
+:102810000233808000000010023380C000000020DE
+:102820000C3383000007A1200A3383000000013825
+:102830000B338300000013880A338340000000003C
+:102840000C338340000001F40B338340000000058B
+:10285000023383800007A120023383C0000001F40B
+:1028600002331480000000010A33148000000000CD
+:10287000063280000000010206322008000000C875
+:10288000063220000000000204328EA0001003B6C1
+:1028900006323EB00000000606323ED800000002BC
+:1028A00006323E800000000A04323EA8000203C641
+:1028B00006323E00000000200632500000000400F6
+:1028C0000632400000000004043274C0000203C855
+:1028D00006324110000000020632D0000000003035
+:1028E0000632DD40000000440632DA00000000D06D
+:1028F0000632DEA0000000020632E0000000080000
+:1029000006328450000001180632100000000188D1
+:102910000632500000000020063251000000002066
+:102920000632520000000020063253000000002052
+:10293000063254000000002006325500000000203E
+:10294000063256000000002006325700000000202A
+:102950000632580000000020063259000000002016
+:1029600006325A000000002006325B000000002002
+:1029700006325C000000002006325D0000000020EE
+:1029800006325E000000002006325F0000000020DA
+:1029900006328DF00000000204328E00000203CAED
+:1029A00006328E08000000020632DE9000000002AF
+:1029B00006321C4000000038063288B000000118C2
+:1029C00006321620000001880632508000000020E8
+:1029D00006325180000000200632528000000020A4
+:1029E0000632538000000020063254800000002090
+:1029F000063255800000002006325680000000207C
+:102A00000632578000000020063258800000002067
+:102A1000063259800000002006325A800000002053
+:102A200006325B800000002006325C80000000203F
+:102A300006325D800000002006325E80000000202B
+:102A400006325F800000002006328DF80000000290
+:102A500004328E10000203CC06328E1800000002F1
+:102A60000632DE980000000206321D200000003809
+:102A700002328D50000000000632401000000002BB
+:102A800002328D5400000000063240200000000297
+:102A900002328D5800000000063240300000000273
+:102AA00002328D5C0000000006324040000000024F
+:102AB00002328D600000000006324050000000022B
+:102AC00002328D6400000000063240600000000207
+:102AD00002328D68000000000632407000000002E3
+:102AE00002328D6C000000000632408000000002BF
+:102AF000072004000091000008200780001003CE8A
+:102B0000072400002B0B00000724800015080AC3CF
+:102B10000824AA10692403D001200000000000004E
+:102B20000120000400000000012000080000000057
+:102B30000120000C00000000012000100000000037
+:102B4000012000140000000002200020000000010D
+:102B500002200024000000020220002800000003E0
+:102B60000220002C000000000220003000000004C1
+:102B700002200034000000010220003800000000A4
+:102B80000220003C00000001022000400000000480
+:102B90000220004400000000022000480000000164
+:102BA0000220004C00000003022000500000000042
+:102BB0000220005400000001022000580000000420
+:102BC0000220005C00000000022000600000000104
+:102BD00002200064000000030220006800000000E2
+:102BE0000220006C000000010220007000000004C0
+:102BF00002200074000000000220007800000004A1
+:102C00000220007C0000000306200080000000027B
+:102C1000022000A400003FFF022000A8000003FFE4
+:102C20000220022400000000022002340000000004
+:102C30000220024C00000000022002E40000FFFF1E
+:102C4000062020000000080002238BC000000001C5
+:102C500002238000000000100223804000000012C8
+:102C60000223808000000030022380C00000000E9C
+:102C70000C2383000007A1200A23830000000138F1
+:102C80000B238300000013880A2383400000000008
+:102C90000C238340000001F40B2383400000000557
+:102CA000022383800007A120022383C0000001F4D7
+:102CB00002231480000000010A2314800000000099
+:102CC000062210000000004206222008000000C872
+:102CD00006222000000000020622B000000000C60C
+:102CE0000422B318000503D20622B32C0000000B07
+:102CF0000422B358000503D70622B36C0000000B72
+:102D00000422B398000503DC0622B3AC0000000BDC
+:102D10000422B3D8000503E10622B3EC0000000B47
+:102D20000422B418000503E60622B42C0000000BB0
+:102D30000422B458000503EB0622B46C0000000B1B
+:102D40000422B498000503F00622B4AC0000000B86
+:102D50000422B4D8000503F50622B4EC0000000BF1
+:102D60000422B518000503FA0622B52C0000000B5A
+:102D70000422B558000503FF0622B56C0000000BC5
+:102D80000422B598000504040622B5AC0000000B2F
+:102D90000422B5D8000504090622B5EC0000000B9A
+:102DA0000422B6180005040E0622B62C0000000B03
+:102DB0000422B658000504130622B66C0000000B6E
+:102DC0000422B698000504180622B6AC0000000BD9
+:102DD0000422B6D80005041D0622B6EC0000000B44
+:102DE0000422B718000504220622B72C0000000BAD
+:102DF0000422B758000504270622B76C0000000B18
+:102E00000422B7980005042C0622B7AC0000000B82
+:102E10000422B7D8000504310622B7EC0000000BED
+:102E20000422B818000504360622B82C0000000B56
+:102E30000422B8580005043B0622B86C0000000BC1
+:102E40000422B898000504400622B8AC0000000B2C
+:102E50000422B8D8000504450622B8EC0000000B97
+:102E60000422B9180005044A0622B92C0000000B00
+:102E70000422B9580005044F0622B96C0000000B6B
+:102E80000422B998000504540622B9AC0000000BD6
+:102E90000422B9D8000504590622B9EC0000000B41
+:102EA0000422BA180005045E0622BA2C0000000BAA
+:102EB0000422BA58000504630622BA6C0000000B15
+:102EC0000422BA98000504680622BAAC0000000B80
+:102ED0000422BAD80005046D0622BAEC00000005F1
+:102EE0000622BB00000000530422BC4C0001047207
+:102EF0000622BC50000000030422BC5C00010473E5
+:102F00000622BC60000000030422BC6C00010474B3
+:102F10000622BC70000000030422BC7C0001047582
+:102F20000622BC80000000030422BC8C0001047651
+:102F30000622BC90000000030422BC9C0001047720
+:102F40000622BCA0000000030422BCAC00010478EF
+:102F50000622BCB0000000030422BCBC00010479BE
+:102F60000622880000000100062280000000020006
+:102F7000042212700010047A06223000000000C003
+:102F800006226700000001000622900000000400F5
+:102F900004226B080020048A022212C0FFFFFFFFF8
+:102FA000062211E800000002062212C800000009F3
+:102FB000062212EC0000000906228C000000000826
+:102FC0000222114800000000062213200000000623
+:102FD000062233000000000206226040000000309C
+:102FE00006228C20000000080222114C0000000084
+:102FF00006221338000000060622330800000002F3
+:10300000062261000000003006228C40000000080B
+:10301000022211500000000006221350000000069A
+:103020000622331000000002062261C000000030BA
+:1030300006228C60000000080222115400000000EB
+:103040000622136800000006062233180000000262
+:10305000062262800000003006228C8000000008FA
+:103060000222115800000000062213800000000612
+:1030700006223320000000020622634000000030D8
+:1030800006228CA0000000080222115C0000000053
+:1030900006221398000000060622332800000002D2
+:1030A000062264000000003006228CC000000008E8
+:1030B0000222116000000000062213B0000000068A
+:1030C0000622333000000002062264C000000030F7
+:1030D00006228CE0000000080222116400000000BB
+:1030E000062213C800000006062233380000000242
+:1030F0000622658000000030021610000000002843
+:1031000002170008000000020217002C0000000354
+:103110000217003C000000040217004800000002F3
+:103120000217004C000000900217005000000090B1
+:103130000217005400800090021700580810000089
+:10314000021700600000008A02170064000000807F
+:1031500002170068000000810217006C0000008068
+:10316000021700700000000602170078000007D068
+:103170000217007C0000076C02170038007C100466
+:10318000021700040000000F061640240000000291
+:10319000021640700000001C0216420800000001E8
+:1031A0000216421000000001021642200000000139
+:1031B0000216422800000001021642300000000101
+:1031C00002164238000000010216426000000002B0
+:1031D0000C16401C0003D0900A16401C0000009CF6
+:1031E0000B16401C000009C4021640300000000805
+:1031F000021640340000000C021640380000001097
+:1032000002164044000000200216400000000001A9
+:10321000021640D80000000102164008000000011C
+:103220000216400C000000010216401000000001D0
+:103230000216424000000000021642480000000052
+:103240000616427000000002021642500000000004
+:1032500002164258000000000616428000000002DC
+:1032600002166008000012240216600C0000121002
+:1032700002166010000012140216601C0000FFFF0E
+:10328000021660200000FFFF021660240000FFFF0E
+:10329000021660280000FFFF0216603800000020C0
+:1032A0000216603C0000002006166040000000028C
+:1032B00002166048000000230216604C0000002443
+:1032C000021660500000002502166054000000261F
+:1032D00002166058000000270216605C00000029FA
+:1032E000021660600000002A021660640000002BD5
+:1032F000021660680000002C0216606C0000002DB1
+:1033000002166070000000EC0216607400000011EC
+:1033100002166078000000120616607C0000000FA4
+:10332000021660B800000001021660BC0000000137
+:10333000061660C00000000C021660F000000001DC
+:10334000061660F400000031021661B800000001AA
+:10335000061661BC0000000D021661F000000001BD
+:10336000061661F4000000110216623807FFFFFF25
+:103370000216623C0000003F0216624007FFFFFF9A
+:10338000021662440000000F0116624800000000AF
+:103390000116624C0000000001166250000000009F
+:1033A000011662540000000001166258000000007F
+:1033B0000116625C0000000001166260000000005F
+:1033C000011662640000000001166268000000003F
+:1033D0000116626C0000000001166270000000001F
+:1033E00001166274000000000116627800000000FF
+:1033F0000116627C000000000C166000000003E86B
+:103400000A166000000000010B1660000000000AB0
+:1034100002168040000000060216804400000005ED
+:10342000021680480000000A0216804C00000005C9
+:103430000216805400000002021680CC0000000436
+:10344000021680D000000004021680D400000004A0
+:10345000021680D800000004021680DC0000000480
+:10346000021680E000000004021680E40000000460
+:10347000021680E800000004021688040000000420
+:10348000021680300000007C021680340000003DEF
+:10349000021680380000003F0216803C0000009CAD
+:1034A000021680F000000007061680F400000005F8
+:1034B0000216880C010101010216810800000000BB
+:1034C0000216810C000000040216811000000004A6
+:1034D0000216811400000002021688100801200460
+:1034E00002168118000000050216811C000000056C
+:1034F000021681200000000502168124000000054C
+:103500000216882C200810010216812800000008ED
+:103510000216812C00000006021681300000000710
+:1035200002168134000000000216883001010120DB
+:1035300006168138000000040216883401010101DA
+:1035400002168148000000000216814C00000004B1
+:10355000021681500000000402168154000000028F
+:103560000216883808012004021681580000000560
+:103570000216815C00000005021681600000000553
+:1035800002168164000000050216883C2008100124
+:1035900002168168000000080216816C0000000617
+:1035A00002168170000000070216817400000001FD
+:1035B00002168840010101200216817800000001F6
+:1035C0000216817C000000010216818000000001CB
+:1035D00002168184000000010216884401010101E5
+:1035E00002168188000000010216818C0000000490
+:1035F000021681900000000402168194000000026F
+:10360000021688480801200402168198000000056F
+:103610000216819C00000005021681A00000000532
+:10362000021681A40000000502168814200810016B
+:10363000021681A800000008021681AC00000006F6
+:10364000021681B000000007021681B400000001DC
+:103650000216881801010120021681B8000000013D
+:10366000021681BC00000001021681C000000001AA
+:10367000021681C4000000010216881C010101012C
+:10368000021681C800000001021681CC000000046F
+:10369000021681D000000004021681D4000000024E
+:1036A0000216882008012004021681D800000005B7
+:1036B000021681DC00000005021681E00000000512
+:1036C000021681E40000000502168824200810017B
+:1036D000021681E800000008021681EC00000006D6
+:1036E000021681F0000000070216E40C0000000042
+:1036F00002168828010101200616E41000000004CB
+:103700000216E000010101010216E42000000000A1
+:103710000216E424000000040216E428000000045D
+:103720000216E42C000000020216E0040801200446
+:103730000216E430000000050216E4340000000523
+:103740000216E438000000050216E43C0000000503
+:103750000216E008200810010216E44000000008EC
+:103760000216E444000000060216E44800000007C8
+:103770000216E44C000000000216E00C01010120DA
+:103780000616E450000000040216E01001010101D9
+:103790000216E460000000000216E4640000000469
+:1037A0000216E468000000040216E46C0000000247
+:1037B0000216E014080120040216E470000000055F
+:1037C0000216E474000000050216E478000000050B
+:1037D0000216E47C000000050216E0182008100123
+:1037E0000216E480000000080216E48400000006CF
+:1037F0000216E488000000070216E48C00000001B5
+:103800000216E01C010101200216E49000000001F4
+:103810000216E494000000010216E4980000000182
+:103820000216E49C000000010216E02001010101E3
+:103830000216E4A0000000010216E4A40000000447
+:103840000216E4A8000000040216E4AC0000000226
+:103850000216E024080120040216E4B0000000056E
+:103860000216E4B4000000050216E4B800000005EA
+:103870000216E4BC000000050216E0282008100132
+:103880000216E4C0000000080216E4C400000006AE
+:103890000216E4C8000000070216E4CC0000000194
+:1038A0000216E02C010101200216E4D00000000104
+:1038B0000216E4D4000000010216E4D80000000162
+:1038C0000216E4DC000000010216E03001010101F3
+:1038D0000216E4E0000000010216E4E40000000427
+:1038E0000216E4E8000000040216E4EC0000000206
+:1038F0000216E034080120040216E4F0000000057E
+:103900000216E4F4000000050216E4F800000005C9
+:103910000216E4FC000000050216E0382008100141
+:103920000216E500000000080216E504000000068B
+:103930000216E508000000070216E03C0101012024
+:1039400002168240003F003F021682440000000041
+:103950000216E524003F003F0216E52800000000A3
+:1039600002168248000000000216824C003F003F11
+:103970000216E52C000000000216E530003F003F73
+:10398000021682500100010002168254010001005B
+:103990000216E534010001000216E53801000100BD
+:1039A00006168258000000020216E53C00000000E6
+:1039B0000216E540000000000216826000C000C050
+:1039C0000216826400C000C00216E54400C000C0B8
+:1039D0000216E54800C000C0021682681E001E00E4
+:1039E0000216826C1E001E000216E54C1E001E0010
+:1039F0000216E5501E001E000216827040004000B4
+:103A000002168274400040000216E5544000400057
+:103A10000216E558400040000216827880008000BF
+:103A20000216827C800080000216E55C8000800027
+:103A30000216E560800080000216828020002000CF
+:103A400002168284200020000216E5642000200077
+:103A50000216E56820002000061682880000000299
+:103A60000216E56C000000000216E5700000000080
+:103A700002168290000000000216829400000000EE
+:103A80000216E574000000000216E5780000000050
+:103A900002168298000000000216829C00000000BE
+:103AA0000216E57C000000000216E5800000000020
+:103AB000021682A000000000021682A4000000018D
+:103AC000061682A80000000A021681F400000C0805
+:103AD000021681F800000040021681FC000001007F
+:103AE0000216820000000020021682040000001767
+:103AF00002168208000000800216820C00000200FC
+:103B000002168210000000000216821801FF01FF59
+:103B10000216821401FF01FF0216E51001FF01FFEA
+:103B20000216E50C01FF01FF0216823C00000013A3
+:103B3000021680900000013F0216806000000140E4
+:103B40000216806400000140061680680000000232
+:103B500002168070000000C0061680740000000786
+:103B60000216809C00000048021680A00000004859
+:103B7000061680A400000002021680AC0000004877
+:103B8000061680B000000007021682380000800090
+:103B900002168234000025E40216809400007FFFA4
+:103BA00002168220000F000F0216821C000F000F69
+:103BB0000216E518000F000F0216E514000F000FA3
+:103BC000021682280000000002168224FFFFFFFF79
+:103BD0000216E520000000000216E51CFFFFFFFFB3
+:103BE0000216E6BC000000000216E6C0000000025B
+:103BF0000216E6C4000000010216E6C80000000339
+:103C00000216E6CC000000040216E6D00000000612
+:103C10000216E6D4000000050216E6D800000007F0
+:103C2000021680EC000000FF0214000000000001FA
+:103C30000214000C0000000102140040000000010A
+:103C40000214004400007FFF0214000C000000007A
+:103C500002140000000000000214006C00000000CC
+:103C600002140004000000010214003000000001F2
+:103C700002140004000000000214005C00000000B8
+:103C800002140008000000010214003400000001CA
+:103C90000214000800000000021400600000000090
+:103CA00006028000000020000202005800000032DE
+:103CB000020200A003150020020200A40315002048
+:103CC000020200A801000030020200AC081000004F
+:103CD000020200B000000033020200B40000003015
+:103CE000020200B800000031020200BC0000000324
+:103CF000020200C000000006020200C4000000032F
+:103D0000020200C800000003020200CC0000000212
+:103D1000020200D000000000020200D400000002F5
+:103D2000020200DC00000000020200E000000006C9
+:103D3000020200E400000004020200E800000002A9
+:103D4000020200EC00000002020200F0000000018C
+:103D5000020200FC00000006020201200000000038
+:103D60000202013400000002020201B00000000162
+:103D70000202020C00000001020202140000000115
+:103D80000202021800000002020204040000000106
+:103D90000202040C00000040020204100000004077
+:103DA0000202041C000000040202042000000020A3
+:103DB0000202042400000002020204280000002085
+:103DC000060205000000001204020480002004AA7C
+:103DD000020200600000000F020200640000000701
+:103DE00002020068000000000202006C0000000EE9
+:103DF000020200700000000E0602007400000003C2
+:103E0000020200F4000000040202000400000001AD
+:103E100002020008000000010202000C0000000184
+:103E20000202001000000001020200140000000164
+:103E300002020018000000010202001C0000000144
+:103E40000202002000000001020200240000000124
+:103E500002020028000000010202002C0000000104
+:103E600002020030000000010202003400000001E4
+:103E700002020038000000010202003C00000001C4
+:103E800002020040000000010202004400000001A4
+:103E900002020048000000010202004C0000000184
+:103EA000020200500000000102020108000000C8E8
+:103EB0000202011800000002020201C4000000001A
+:103EC000020201CC00000000020201D40000000246
+:103ED000020201DC00000002020201E4000000FF17
+:103EE000020201EC000000FF0202010000000000DD
+:103EF0000202010C000000C80202011C00000002C6
+:103F0000020201C800000000020201D0000000000F
+:103F1000020201D800000002020201E000000002DB
+:103F2000020201E8000000FF020201F0000000FFB1
+:103F3000020201040000000002020108000000C8A3
+:103F40000202011800000002020201C40000000089
+:103F5000020201CC00000000020201D400000002B5
+:103F6000020201DC00000002020201E4000000FF86
+:103F7000020201EC000000FF02020100000000004C
+:103F80000202010C000000C80202011C0000000235
+:103F9000020201C800000000020201D0000000007F
+:103FA000020201D800000002020201E0000000024B
+:103FB000020201E8000000FF020201F0000000FF21
+:103FC000020201040000000002020108000000C813
+:103FD0000202011800000002020201C400000000F9
+:103FE000020201CC00000000020201D40000000225
+:103FF000020201DC00000002020201E4000000FFF6
+:10400000020201EC000000FF0202010000000000BB
+:104010000202010C000000C80202011C00000002A4
+:10402000020201C800000000020201D000000000EE
+:10403000020201D800000002020201E000000002BA
+:10404000020201E8000000FF020201F0000000FF90
+:10405000020201040000000002020108000000C882
+:104060000202011800000002020201C40000000068
+:10407000020201CC00000000020201D40000000294
+:10408000020201DC00000002020201E4000000FF65
+:10409000020201EC000000FF02020100000000002B
+:1040A0000202010C000000C80202011C0000000214
+:1040B000020201C800000000020201D0000000005E
+:1040C000020201D800000002020201E0000000022A
+:1040D000020201E8000000FF020201F0000000FF00
+:1040E00002020104000000000728040000A10000F3
+:1040F000082807B8000904CA072C000034F700009C
+:10410000072C800039250D3E072D000037CD1B8878
+:10411000072D80003292297C072E00001AF33621E9
+:10412000082E4390378E04CC0128000000000000C8
+:104130000128000400000000012800080000000021
+:104140000128000C00000000012800100000000001
+:1041500001280014000000000228002000000001D7
+:1041600002280024000000020228002800000003AA
+:104170000228002C0000000002280030000000048B
+:10418000022800340000000102280038000000006E
+:104190000228003C0000000102280040000000044A
+:1041A000022800440000000002280048000000012E
+:1041B0000228004C0000000302280050000000000C
+:1041C00002280054000000010228005800000004EA
+:1041D0000228005C000000000228006000000001CE
+:1041E00002280064000000030228006800000000AC
+:1041F0000228006C0000000102280070000000048A
+:10420000022800740000000002280078000000046A
+:104210000228007C00000003062800800000000245
+:10422000022800A400003FFF022800A8000003FFAE
+:1042300002280224000000000228023400000000CE
+:104240000228024C00000000022802E40000FFFFE8
+:104250000628200000000800022B8BC0000000018F
+:10426000022B800000000000022B8040000000189C
+:10427000022B80800000000C022B80C00000006632
+:104280000C2B83000007A1200A2B830000000138BB
+:104290000B2B8300000013880A2B834000000000D2
+:1042A0000C2B8340000001F40B2B83400000000521
+:1042B000022B83800007A120022B83C0000001F4A1
+:1042C000022B1480000000010A2B14800000000063
+:1042D000062A9AF800000004042A9B08000204CE73
+:1042E000062A9B1000000006062A90800000004865
+:1042F000062A2008000000C8062A2000000000024C
+:10430000062A91A800000086062A900000000020DE
+:10431000062A93C800000003042A93D4000104D0A5
+:10432000062A9DA800000002042A9498000404D1E3
+:10433000042A9D58000104D5062A9D5C0000001146
+:10434000042ACB20001004D6042A3000000204E620
+:10435000062A300800000100062A40400000001034
+:10436000042A4000001004E8042A8408000204F82B
+:10437000062A9DA000000002062AB000000000509E
+:10438000062ABB7000000070062AB150000000022F
+:10439000062ABB6000000004062AD00000000800C6
+:1043A000062AC00000000150062A94A8000000322E
+:1043B000062A502000000002062A503000000002A9
+:1043C000062A500000000002062A501000000002D9
+:1043D000022A520800000001042A9B28000204FA65
+:1043E000062A963800000022042A96C0000104FC28
+:1043F000062A96C400000003062A976800000022DF
+:10440000042A97F0000104FD062A97F40000000337
+:10441000062A989800000022042A9920000104FE30
+:10442000062A992400000003062A99C800000022E9
+:10443000042A9A50000104FF062A9A54000000033F
+:10444000062AB14000000002062AC54000000150C3
+:10445000062A957000000032062A5028000000024B
+:10446000062A503800000002062A50080000000208
+:10447000062A501800000002022A520C0000000117
+:10448000042A9B3000020500062A96D00000002274
+:10449000042A975800010502062A975C00000003D1
+:1044A000062A980000000022042A988800010503CB
+:1044B000062A988C00000003062A9930000000228A
+:1044C000042A99B800010504062A99BC00000003DB
+:1044D000062A9A6000000022042A9AE800010505D5
+:1044E000062A9AEC00000003062AB14800000002E8
+:1044F000022ACA8000000000042A9B38001005062A
+:10450000062A50480000000E022ACA84000000005B
+:10451000042A9B7800100516062A50800000000E21
+:10452000022ACA8800000000042A9BB80010052651
+:10453000062A50B80000000E022ACA8C00000000B3
+:10454000042A9BF800100536062A50F00000000EE1
+:10455000022ACA9000000000042A9C380010054678
+:10456000062A51280000000E022ACA94000000000A
+:10457000042A9C7800100556062A51600000000E9F
+:10458000022ACA9800000000042A9CB800100566A0
+:10459000062A51980000000E022ACA9C0000000062
+:1045A000042A9CF800100576062A51D00000000E5F
+:1045B000021010080000000102101050000000015D
+:1045C000021010000003D000021010040000003D93
+:1045D0000910180002000586091011000010078656
+:1045E0000610114000000008091011600010079625
+:1045F000061011A00000001806102400000000E0C2
+:104600000210201C00000000021020200000000109
+:10461000021020C00000000202102004000000016F
+:10462000021020080000000109103C00000507A648
+:1046300009103800000507AB09103820000507B045
+:1046400006104C000000010002104028000000107D
+:104650000210404400003FFF0210405800280000B4
+:10466000021040840084924A02104058000000006A
+:104670000210800000001080021080AC00000000DA
+:1046800002108038000000100210810000000000BD
+:10469000061081200000000202108008000002B510
+:1046A0000210801000000000061082000000004A86
+:1046B000021081080001FFFF061081400000000287
+:1046C0000210800000001A800610900000000024F4
+:1046D000061091200000004A061093700000004A66
+:1046E000061095C00000004A0210800400001080EF
+:1046F000021080B0000000010210803C0000001099
+:104700000210810400000000061081280000000251
+:104710000210800C000002B502108014000000009E
+:10472000061084000000004A0210810C0001FFFF07
+:1047300006108148000000020210800400001A8068
+:104740000610909000000024061092480000004AD5
+:10475000061094980000004A061096E80000004AEF
+:104760000210800000001080021080AC00000002E7
+:1047700002108038000000100210810000000000CC
+:10478000061081200000000202108008000002B51F
+:104790000210801000000000061082000000004A95
+:1047A000021081080001FFFF061081400000000296
+:1047B0000210800000001A80061090000000002403
+:1047C000061091200000004A061093700000004A75
+:1047D000061095C00000004A0210800400001080FE
+:1047E000021080B0000000030210803C00000010A6
+:1047F0000210810400000000061081280000000261
+:104800000210800C000002B50210801400000000AD
+:10481000061084000000004A0210810C0001FFFF16
+:1048200006108148000000020210800400001A8077
+:104830000610909000000024061092480000004AE4
+:10484000061094980000004A061096E80000004AFE
+:104850000210800000001080021080AC00000004F4
+:1048600002108038000000100210810000000000DB
+:10487000061081200000000202108008000002B52E
+:104880000210801000000000061082000000004AA4
+:10489000021081080001FFFF0610814000000002A5
+:1048A0000210800000001A80061090000000002412
+:1048B000061091200000004A061093700000004A84
+:1048C000061095C00000004A02108004000010800D
+:1048D000021080B0000000050210803C00000010B3
+:1048E0000210810400000000061081280000000270
+:1048F0000210800C000002B50210801400000000BD
+:10490000061084000000004A0210810C0001FFFF25
+:1049100006108148000000020210800400001A8086
+:104920000610909000000024061092480000004AF3
+:10493000061094980000004A061096E80000004A0D
+:104940000210800000001080021080AC0000000601
+:1049500002108038000000100210810000000000EA
+:10496000061081200000000202108008000002B53D
+:104970000210801000000000061082000000004AB3
+:10498000021081080001FFFF0610814000000002B4
+:104990000210800000001A80061090000000002421
+:1049A000061091200000004A061093700000004A93
+:1049B000061095C00000004A02108004000010801C
+:1049C000021080B0000000070210803C00000010C0
+:1049D000021081040000000006108128000000027F
+:1049E0000210800C000002B50210801400000000CC
+:1049F000061084000000004A0210810C0001FFFF35
+:104A000006108148000000020210800400001A8095
+:104A10000610909000000024061092480000004A02
+:104A2000061094980000004A061096E80000004A1C
+:104A3000021205B0000000010212049000E383405E
+:104A40000212051400003C100212066C0000000166
+:104A5000021206700000000002120494FFFFFFFF24
+:104A600002120498FFFFFFFF0212049CFFFFFFFFEA
+:104A7000021204A0FFFFFFFF021204A4FFFFFFFFCA
+:104A8000021204A8FFFFFFFF021204ACFFFFFFFFAA
+:104A9000021204B0FFFFFFFF021204BCFFFFFFFF82
+:104AA000021204C0FFFFFFFF021204C4FFFFFFFF5A
+:104AB000021204C8FFFFFFFF021204CCFFFFFFFF3A
+:104AC000021204D0FFFFFFFF021204D8FFFFFFFF16
+:104AD000021204DCFFFFFFFF021204E0FFFFFFFFF2
+:104AE000021204E4FFFFFFFF021204E8FFFFFFFFD2
+:104AF000021204ECFFFFFFFF021204F0FFFFFFFFB2
+:104B0000021204F4FFFFFFFF021204F8FFFFFFFF91
+:104B1000021204FCFFFFFFFF02120500FFFFFFFF70
+:104B200002120504FFFFFFFF02120508FFFFFFFF4F
+:104B30000212050CFFFFFFFF02120510FFFFFFFF2F
+:104B4000021204D4FF809000021204B4F00050005E
+:104B5000021204B8F00010000212039000000008D6
+:104B60000212039C00000008021203A000000008CB
+:104B7000021203A400000002021203BC00000004A1
+:104B8000021203C000000005021203C4000000046A
+:104B9000021203D0000000000212036C00000001AA
+:104BA000021203680000003F021201BC0000004036
+:104BB000021201C000001808021201C4000008031C
+:104BC000021201C800000803021201CC00000040DC
+:104BD000021201D000000003021201D400000803F9
+:104BE000021201D800000803021201DC00000803D1
+:104BF000021201E000010003021201E400000803B8
+:104C0000021201E800000803021201EC0000000398
+:104C1000021201F000000003021201F40000000380
+:104C2000021201F800000003021201FC0000000360
+:104C3000021202000000000302120204000000033E
+:104C400002120208000000030212020C000000031E
+:104C500002120210000000030212021400000003FE
+:104C600002120218000000030212021C00000003DE
+:104C700002120220000000030212022400000003BE
+:104C800002120228000024030212022C0000002F4E
+:104C90000212023000000009021202340000001962
+:104CA00002120238000001840212023C000001835B
+:104CB0000212024000000306021202440000001922
+:104CC00002120248000000060212024C0000030615
+:104CD00002120250000003060212025400000306F2
+:104CE0000212025800000C860212025C0000030649
+:104CF00002120260000003060212026400000006B5
+:104D000002120268000000060212026C0000000697
+:104D10000212027000000006021202740000000677
+:104D200002120278000000060212027C0000000657
+:104D30000212028000000006021202840000000637
+:104D400002120288000000060212028C0000000617
+:104D500002120290000000060212029400000006F7
+:104D600002120298000000060212029C00000006D7
+:104D7000021202A000000306021202A400000013A7
+:104D8000021202A800000006021202B00000100485
+:104D9000021202B400001004021203240010644046
+:104DA0000212032800106440021205B40000000142
+:104DB000021201B0000000010600A0000000000C7B
+:104DC0000200A050000000000200A05400000000FB
+:104DD0000200A0EC555400000200A0F055555555B6
+:104DE0000200A0F4000055550200A0F8F0000000F9
+:104DF0000200A0FC555400000200A1005555555575
+:104E00000200A104000055550200A108F0000000B6
+:104E10000200A18C555400000200A1905555555533
+:104E20000200A194000055550200A198F000000076
+:104E30000200A19C000000000200A1A000010000EF
+:104E40000200A1A4000050140200A1A8000000006C
+:104E50000200A45C00000C000200A61C000000037D
+:104E60000200A06CFF5C00000200A070FFF55FFF75
+:104E70000200A0740000FFFF0200A078F00003E031
+:104E80000200A07C000000000200A0800000A00042
+:104E90000600A084000000050200A0980FE00000BA
+:104EA0000600A09C000000070200A0B8000004005B
+:104EB0000600A0BC000000030200A0C80000100013
+:104EC0000600A0CC000000030200A0D800004000B3
+:104ED0000600A0DC000000030200A0E800010000C2
+:104EE0000600A22C000000040200A10CFF5C0000E0
+:104EF0000200A110FFF55FFF0200A1140000FFFFF8
+:104F00000200A118F00003E00200A11C0000000054
+:104F10000200A1200000A0000600A124000000055E
+:104F20000200A1380FE000000600A13C00000007CD
+:104F30000200A158000008000600A15C0000000368
+:104F40000200A168000020000600A16C0000000320
+:104F50000200A178000080000600A17C0000000390
+:104F60000200A188000200000600A23C000000042C
+:104F70000200A030000000000200A0340000000089
+:104F80000200A038000000000200A03C0000000069
+:104F90000200A040000000000200A0440000000049
+:104FA0000200A048000000000200A04C0000000029
+:104FB00000000000000000000000003000000000C1
+:104FC00000000000000000000000000000000000E1
+:104FD00000000000000000000000000000000000D1
+:104FE0000000000000300031000000000000000060
+:104FF00000000000000000000000000000000000B1
+:1050000000000000000000000000000000000000A0
+:10501000003100520000000000000000000000000D
+:105020000000000000000000000000000000000080
+:105030000000000000000000000000000052008995
+:1050400000000000000000000089008D008D00912C
+:1050500000910095009500990099009D009D00A188
+:1050600000A100A500A500A900A900AE00AE00B1F6
+:1050700000B100B4000000000000000000000000CB
+:105080000000000000000000000000000000000020
+:105090000000000000B40309030903130313031DF8
+:1050A000031D03240324032B032B03320332033990
+:1050B00003390340034003470347034E034E0355A0
+:1050C00000000000000000000000000000000000E0
+:1050D00000000000000000000000000000000000D0
+:1050E00000000000000000000000000000000000C0
+:1050F00000000000000000000000000000000000B0
+:10510000000000000000000000000000000000009F
+:10511000000000000000000000000000000000008F
+:10512000000000000000000000000000000000007F
+:10513000000000000000000000000000000000006F
+:10514000000000000000000000000000000000005F
+:10515000000000000000000000000000000000004F
+:10516000000000000000000000000000000000003F
+:105170000355035B0000000000000000035B035CBC
+:10518000035C035D035D035E035E035F035F036017
+:1051900003600361036103620362036300000000B4
+:1051A00000000000000000000000000000000000FF
+:1051B00000000000000000000000000000000000EF
+:1051C00000000000000000000363036D036D037B1B
+:1051D000037B0389000000000000000000000000C5
+:1051E00000000000000000000000000000000000BF
+:1051F00000000000000000000000000000000000AF
+:10520000000000000000000000000000000000009E
+:10521000000000000000000000000000000000008E
+:105220000389038A00000000000000000000000065
+:10523000000000000000000000000000000000006E
+:10524000000000000000000000000000038A03D6F8
+:10525000000000000000000000000000000000004E
+:10526000000000000000000000000000000000003E
+:10527000000000000000000003D604010000000050
+:10528000000000000000000000000000000000001E
+:10529000000000000000000000000000000000000E
+:1052A00000000000040104330000000000000000C2
+:1052B0000433043A043A0441044104480448044FC6
+:1052C000044F04560456045D045D04640464046BD6
+:1052D000046B04A4000000000000000004A404A863
+:1052E00004A804AC04AC04B004B004B404B404B81E
+:1052F00004B804BC04BC04C004C004C404C4051342
+:105300000513052A052A05410541054305430545C1
+:1053100005450547054705490549054B054B054D1D
+:10532000054D054F054F0551055105E805E805E90F
+:1053300005E905EA05EA05EF05EF05F405F405F9C9
+:1053400005F905FE05FE0603060306080608060D18
+:10535000060D0612061206130000000000000000F1
+:10536000000000000000000000000000000000003D
+:10537000000000000000000000000000000000002D
+:1053800006130624000000000000000000000000DA
+:10539000000000000000000000000000000000000D
+:1053A0000000000000000000000000000624063994
+:1053B0000639063C063C063F0000000000000000E5
+:1053C00000000000000000000000000000000000DD
+:1053D0000000000000000000063F0675000000000D
+:1053E00000000000000000000000000000000000BD
+:1053F00000000000000000000000000000000000AD
+:1054000000000000067507780000000000000000A2
+:10541000000000000000000000000000000000008C
+:10542000000000000000000000000000000000007C
+:105430000778077F077F078307830787000000003F
+:10544000000000000000000000000000000000005C
+:10545000000000000000000000000000078707C8EF
+:10546000000000000000000007C807D107D107DADC
+:1054700007DA07E307E307EC07EC07F507F507FE94
+:1054800007FE080708070810081008670867087C67
+:10549000087C089108910894089408970897089A3E
+:1054A000089A089D089D08A008A008A308A308A6BC
+:1054B00008A608A908A908B2000000000000000022
+:1054C00000000000000000000000000000000000DC
+:1054D00000000000000000000000000000000000CC
+:1054E00008B208B800000000000000000000000042
+:1054F00000000000000000000000000000000000AC
+:1055000000000000000000000000000008B808BB18
+:10551000000000000000000000000000000000008B
+:10552000000000000000000000000000000000007B
+:10553000000000000000000008BB08C100000000DF
+:10554000000000000000000000000000000000005B
+:10555000000000000000000000000000000000004B
+:10556000000000000000000000000000000000003B
+:1055700008C108D008D008DF08DF08EE08EE08FDF3
+:1055800008FD090C090C091B091B092A092A0939FC
+:10559000093909AA00000000000000000000000016
+:1055A00000000000000000000000000000000000FB
+:1055B00000000000000000000000000009AA09BF70
+:1055C00009BF09D009D009E109E109E209E209E3CB
+:1055D00009E309E409E409E509E509E609E609E75B
+:1055E00009E709E809E809E90000000000000000F7
+:1055F00000000000000000000000000000000000AB
+:10560000000000000000000000000000000000009A
+:10561000000000000000000000000000000000008A
+:10562000000000000000000000000000000000007A
+:10563000000000000000000000000000000000006A
+:10564000000000000000000000000000000000005A
+:10565000000000000000000000000000000000004A
+:10566000000000000000000000000000000000003A
+:10567000000000000000000000000000000000002A
+:10568000000000000000000000000000000000001A
+:10569000000000000000000000000000000000000A
+:1056A00000000000000000000000000000000000FA
+:1056B00000000000000000000000000000000000EA
+:1056C000000000000000000000010000000204C013
+:1056D0000003098000040E4000051300000617C0F7
+:1056E00000071C800008214000092600000A2AC08B
+:1056F000000B2F80000C3440000D3900000E3DC01F
+:10570000000F42800010474000114C00001250C0B2
+:105710000013558000145A4000155F00001663C046
+:105720000017688000186D4000197200001A76C0DA
+:10573000001B7B80001C8040001D8500001E89C06E
+:10574000001F8E80000093400000200000004000F9
+:1057500000006000000080000000A0000000C00009
+:105760000000E000000100000001200000014000F6
+:1057700000016000000180000001A0000001C000E5
+:105780000001E000000200000002200000024000D2
+:1057900000026000000280000002A0000002C000C1
+:1057A0000002E000000300000003200000034000AE
+:1057B00000036000000380000003A0000003C0009D
+:1057C0000003E0000004000000042000000440008A
+:1057D00000046000000480000004A0000004C00079
+:1057E0000004E00000050000000520000005400066
+:1057F00000056000000580000005A0000005C00055
+:105800000005E00000060000000620000006400041
+:1058100000066000000680000006A0000006C00030
+:105820000006E0000007000000072000000740001D
+:1058300000076000000780000007A0000007C0000C
+:105840000007E000000800000008200000084000F9
+:1058500000086000000880000008A0000008C000E8
+:105860000008E000000900000009200000094000D5
+:1058700000096000000980000009A0000009C000C4
+:105880000009E000000A0000000A2000000A4000B1
+:10589000000A6000000A8000000AA000000AC000A0
+:1058A000000AE000000B0000000B2000000B40008D
+:1058B000000B6000000B8000000BA000000BC0007C
+:1058C000000BE000000C0000000C2000000C400069
+:1058D000000C6000000C8000000CA000000CC00058
+:1058E000000CE000000D0000000D2000000D400045
+:1058F000000D6000000D8000000DA000000DC00034
+:10590000000DE000000E0000000E2000000E400020
+:10591000000E6000000E8000000EA000000EC0000F
+:10592000000EE000000F0000000F2000000F4000FC
+:10593000000F6000000F8000000FA000000FC000EB
+:10594000000FE000001000000010200000104000D8
+:1059500000106000001080000010A0000010C000C7
+:105960000010E000001100000011200000114000B4
+:1059700000116000001180000011A0000011C000A3
+:105980000011E00000120000001220000012400090
+:1059900000126000001280000012A0000012C0007F
+:1059A0000012E0000013000000132000001340006C
+:1059B00000136000001380000013A0000013C0005B
+:1059C0000013E00000140000001420000014400048
+:1059D00000146000001480000014A0000014C00037
+:1059E0000014E00000150000001520000015400024
+:1059F00000156000001580000015A0000015C00013
+:105A00000015E000001600000016200000164000FF
+:105A100000166000001680000016A0000016C000EE
+:105A20000016E000001700000017200000174000DB
+:105A300000176000001780000017A0000017C000CA
+:105A40000017E000001800000018200000184000B7
+:105A500000186000001880000018A0000018C000A6
+:105A60000018E00000190000001920000019400093
+:105A700000196000001980000019A0000019C00082
+:105A80000019E000001A0000001A2000001A40006F
+:105A9000001A6000001A8000001AA000001AC0005E
+:105AA000001AE000001B0000001B2000001B40004B
+:105AB000001B6000001B8000001BA000001BC0003A
+:105AC000001BE000001C0000001C2000001C400027
+:105AD000001C6000001C8000001CA000001CC00016
+:105AE000001CE000001D0000001D2000001D400003
+:105AF000001D6000001D8000001DA000001DC000F2
+:105B0000001DE000001E0000001E2000001E4000DE
+:105B1000001E6000001E8000001EA000001EC000CD
+:105B2000001EE000001F0000001F2000001F4000BA
+:105B3000001F6000001F8000001FA000001FC000A9
+:105B4000001FE00000200000002020000020400096
+:105B500000206000002080000020A0000020C00085
+:105B60000020E00000210000002120000021400072
+:105B700000216000002180000021A0000021C00061
+:105B80000021E0000022000000222000002240004E
+:105B900000226000002280000022A0000022C0003D
+:105BA0000022E0000023000000232000002340002A
+:105BB00000236000002380000023A0000023C00019
+:105BC0000023E00000240000002420000024400006
+:105BD00000246000002480000024A0000024C000F5
+:105BE0000024E000002500000025200000254000E2
+:105BF00000256000002580000025A0000025C000D1
+:105C00000025E000002600000026200000264000BD
+:105C100000266000002680000026A0000026C000AC
+:105C20000026E00000270000002720000027400099
+:105C300000276000002780000027A0000027C00088
+:105C40000027E00000280000002820000028400075
+:105C500000286000002880000028A0000028C00064
+:105C60000028E00000290000002920000029400051
+:105C700000296000002980000029A0000029C00040
+:105C80000029E000002A0000002A2000002A40002D
+:105C9000002A6000002A8000002AA000002AC0001C
+:105CA000002AE000002B0000002B2000002B400009
+:105CB000002B6000002B8000002BA000002BC000F8
+:105CC000002BE000002C0000002C2000002C4000E5
+:105CD000002C6000002C8000002CA000002CC000D4
+:105CE000002CE000002D0000002D2000002D4000C1
+:105CF000002D6000002D8000002DA000002DC000B0
+:105D0000002DE000002E0000002E2000002E40009C
+:105D1000002E6000002E8000002EA000002EC0008B
+:105D2000002EE000002F0000002F2000002F400078
+:105D3000002F6000002F8000002FA000002FC00067
+:105D4000002FE00000300000003020000030400054
+:105D500000306000003080000030A0000030C00043
+:105D60000030E00000310000003120000031400030
+:105D700000316000003180000031A0000031C0001F
+:105D80000031E0000032000000322000003240000C
+:105D900000326000003280000032A0000032C000FB
+:105DA0000032E000003300000033200000334000E8
+:105DB00000336000003380000033A0000033C000D7
+:105DC0000033E000003400000034200000344000C4
+:105DD00000346000003480000034A0000034C000B3
+:105DE0000034E000003500000035200000354000A0
+:105DF00000356000003580000035A0000035C0008F
+:105E00000035E0000036000000362000003640007B
+:105E100000366000003680000036A0000036C0006A
+:105E20000036E00000370000003720000037400057
+:105E300000376000003780000037A0000037C00046
+:105E40000037E00000380000003820000038400033
+:105E500000386000003880000038A0000038C00022
+:105E60000038E0000039000000392000003940000F
+:105E700000396000003980000039A0000039C000FE
+:105E80000039E000003A0000003A2000003A4000EB
+:105E9000003A6000003A8000003AA000003AC000DA
+:105EA000003AE000003B0000003B2000003B4000C7
+:105EB000003B6000003B8000003BA000003BC000B6
+:105EC000003BE000003C0000003C2000003C4000A3
+:105ED000003C6000003C8000003CA000003CC00092
+:105EE000003CE000003D0000003D2000003D40007F
+:105EF000003D6000003D8000003DA000003DC0006E
+:105F0000003DE000003E0000003E2000003E40005A
+:105F1000003E6000003E8000003EA000003EC00049
+:105F2000003EE000003F0000003F2000003F400036
+:105F3000003F6000003F8000003FA000003FC00025
+:105F4000003FE000003FE00100000000000001FF12
+:105F50000000020000007FF800007FF80000014010
+:105F600000003500000000010000FF0000000000FC
+:105F70000000FF00000000000000FF000000000023
+:105F80000000FF00000000000000FF000000000013
+:105F90000000FF00000000000000FF000000000003
+:105FA0000000FF000000000000000000140AFF00D5
+:105FB00000000001000000000020100100000000AF
+:105FC0000100900000000100000090020000900419
+:105FD00000009006000090080000900A0000900C5D
+:105FE0000000900E0000901000009012000090142D
+:105FF00000009016000090180000901A0000901CFD
+:106000000000901E000090200000902200009024CC
+:1060100000009026000090280000902A0000902C9C
+:106020000000902E0000903000009032000090346C
+:1060300000009036000090380000903A0000903C3C
+:106040000000903E0000904000009042000090440C
+:1060500000009046000090480000904A0000904CDC
+:106060000000904E000090500000905200009054AC
+:1060700000009056000090580000905A0000905C7C
+:106080000000905E0000906000009062000090644C
+:1060900000009066000090680000906A0000906C1C
+:1060A0000000906E000090700000907200009074EC
+:1060B00000009076000090780000907A0000907CBC
+:1060C0000000907E0000908000009082000090848C
+:1060D00000009086000090880000908A0000908C5C
+:1060E0000000908E0000909000009092000090942C
+:1060F00000009096000090980000909A0000909CFC
+:106100000000909E000090A0000090A2000090A4CB
+:10611000000090A6000090A8000090AA000090AC9B
+:10612000000090AE000090B0000090B2000090B46B
+:10613000000090B6000090B8000090BA000090BC3B
+:10614000000090BE000090C0000090C2000090C40B
+:10615000000090C6000090C8000090CA000090CCDB
+:10616000000090CE000090D0000090D2000090D4AB
+:10617000000090D6000090D8000090DA000090DC7B
+:10618000000090DE000090E0000090E2000090E44B
+:10619000000090E6000090E8000090EA000090EC1B
+:1061A000000090EE000090F0000090F2000090F4EB
+:1061B000000090F6000090F8000090FA000090FCBB
+:1061C000000090FE00009100000091020000910488
+:1061D00000009106000091080000910A0000910C57
+:1061E0000000910E00009110000091120000911427
+:1061F00000009116000091180000911A0000911CF7
+:106200000000911E000091200000912200009124C6
+:1062100000009126000091280000912A0000912C96
+:106220000000912E00009130000091320000913466
+:1062300000009136000091380000913A0000913C36
+:106240000000913E00009140000091420000914406
+:1062500000009146000091480000914A0000914CD6
+:106260000000914E000091500000915200009154A6
+:1062700000009156000091580000915A0000915C76
+:106280000000915E00009160000091620000916446
+:1062900000009166000091680000916A0000916C16
+:1062A0000000916E000091700000917200009174E6
+:1062B00000009176000091780000917A0000917CB6
+:1062C0000000917E00009180000091820000918486
+:1062D00000009186000091880000918A0000918C56
+:1062E0000000918E00009190000091920000919426
+:1062F00000009196000091980000919A0000919CF6
+:106300000000919E000091A0000091A2000091A4C5
+:10631000000091A6000091A8000091AA000091AC95
+:10632000000091AE000091B0000091B2000091B465
+:10633000000091B6000091B8000091BA000091BC35
+:10634000000091BE000091C0000091C2000091C405
+:10635000000091C6000091C8000091CA000091CCD5
+:10636000000091CE000091D0000091D2000091D4A5
+:10637000000091D6000091D8000091DA000091DC75
+:10638000000091DE000091E0000091E2000091E445
+:10639000000091E6000091E8000091EA000091EC15
+:1063A000000091EE000091F0000091F2000091F4E5
+:1063B000000091F6000091F8000091FA000091FCB5
+:1063C000000091FEFFFFFFFFFFFFFFFFFFFFFFFF4A
+:1063D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD
+:1063E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD
+:1063F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD
+:10640000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C
+:10641000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C
+:10642000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C
+:10643000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C
+:10644000FFFFFFFF0000000300BEBC2000000000B3
+:10645000000000050000000300BEBC20000000009A
+:10646000000000050000000300BEBC20000000008A
+:10647000000000050000000300BEBC20000000007A
+:10648000000000050000000300BEBC20000000006A
+:10649000000000050000000300BEBC20000000005A
+:1064A000000000050000000300BEBC20000000004A
+:1064B000000000050000000300BEBC20000000003A
+:1064C0000000000500002000000040C000006180C6
+:1064D000000082400000A3000000C3C00000E48070
+:1064E0000001054000012600000146C00001678050
+:1064F000000188400001A9000001C9C00001EA8034
+:1065000000020B4000022C0000024CC000026D8013
+:1065100000028E400002AF000002CFC00002F080F7
+:10652000000011400000800000010380000187008E
+:1065300000020A8000028E00000311800003950013
+:106540000004188000049C0000051F800005A300C3
+:10655000000626800006AA0000072D800007B10073
+:10656000000834800008B80000093B800009BF0023
+:10657000000A4280000AC600000B4980000BCD00D3
+:10658000000C5080000CD400000D578000005B0010
+:1065900000007FF800007FF8000000D50000150023
+:1065A0000000FF00000000000000FF0000000000ED
+:1065B0000000FF00000000000000FF0000000000DD
+:1065C0000000FF00000000000000FF0000000000CD
+:1065D0000000FF00000000000000FF0000000000BD
+:1065E000000019000000000000000000FFFFFFFF96
+:1065F0000000000003938700000000000393870061
+:1066000000007FF800007FF80000069200001500EF
+:106610000000FF000FFFFFFF0000FF000FFFFFFF64
+:10662000000000FF0000FF000FFFFFFF0000FF0061
+:106630000FFFFFFF000000FF0000FF000FFFFFFF44
+:106640000000FF000FFFFFFF000000FF0000FF0041
+:106650000FFFFFFF0000FF000FFFFFFF000000FF24
+:106660000000FF000FFFFFFF0000FF000FFFFFFF14
+:10667000000000FF0000FF000FFFFFFF0000FF0011
+:106680000FFFFFFF000000FF0000FF000FFFFFFFF4
+:106690000000FF000FFFFFFF000000FF0000FF00F1
+:1066A0000FFFFFFF0000FF000FFFFFFF000000FFD4
+:1066B0000000FF000FFFFFFF0000FF000FFFFFFFC4
+:1066C000000000FF0000FF000FFFFFFF0000FF00C1
+:1066D0000FFFFFFF000000FF0000FF000FFFFFFFA4
+:1066E0000000FF000FFFFFFF000000FF0000FF00A1
+:1066F0000FFFFFFF0000FF000FFFFFFF000000FF84
+:106700000000FF000FFFFFFF0000FF000FFFFFFF73
+:10671000000000FF0000FF000FFFFFFF0000FF0070
+:106720000FFFFFFF000000FF0000FF000FFFFFFF53
+:106730000000FF000FFFFFFF000000FF0000FF0050
+:106740000FFFFFFF0000FF000FFFFFFF000000FF33
+:106750000000FF000FFFFFFF0000FF000FFFFFFF23
+:10676000000000FF0000FF000FFFFFFF0000FF0020
+:106770000FFFFFFF000000FF0000FF000FFFFFFF03
+:106780000000FF000FFFFFFF000000FF0000FF0000
+:106790000FFFFFFF0000FF000FFFFFFF000000FFE3
+:1067A0000000FF000FFFFFFF0000FF000FFFFFFFD3
+:1067B000000000FF0000FF000FFFFFFF0000FF00D0
+:1067C0000FFFFFFF000000FF0000FF000FFFFFFFB3
+:1067D0000000FF000FFFFFFF000000FF0000FF00B0
+:1067E0000FFFFFFF0000FF000FFFFFFF000000FF93
+:1067F0000000FF000FFFFFFF0000FF000FFFFFFF83
+:10680000000000FF0000FF000FFFFFFF0000FF007F
+:106810000FFFFFFF000000FF0000FF000FFFFFFF62
+:106820000000FF000FFFFFFF000000FF0000FF005F
+:106830000FFFFFFF0000FF000FFFFFFF000000FF42
+:106840000000FF000FFFFFFF0000FF000FFFFFFF32
+:10685000000000FF0000FF000FFFFFFF0000FF002F
+:106860000FFFFFFF000000FF0000FF000FFFFFFF12
+:106870000000FF000FFFFFFF000000FF0000FF000F
+:106880000FFFFFFF0000FF000FFFFFFF000000FFF2
+:10689000000000FF000000FF000000FF000000FFFC
+:1068A000000000FF000000FF000000FF000000FFEC
+:1068B0000000FF00000000000000FF0000000000DA
+:1068C0000000FF00000000000000FF0000000000CA
+:1068D0000000FF00000000000000FF0000000000BA
+:1068E0000000FF00000000000000FF0000000000AA
+:1068F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8
+:10690000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97
+:10691000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87
+:10692000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77
+:10693000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67
+:10694000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57
+:10695000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF47
+:10696000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37
+:106970000000100000002080000031000000418075
+:10698000000052000000628000007300000083805D
+:10699000000094000000A4800000B5000000C58045
+:1069A0000000D6000000E6800000F700000107802C
+:1069B0000001180000012880000139000001498011
+:1069C00000015A0000016A8000017B0000018B80F9
+:1069D00000019C000001AC800001BD000001CD80E1
+:1069E0000001DE000001EE800001FF0000000F80CA
+:1069F00000007FF800007FF8000003400000150051
+:106A000010000000000028AD000100010022000677
+:106A1000CCCCCCC5FFFFFFFFFFFFFFFF7058103C41
+:106A20000000FF00000000000000FF000000000068
+:106A30000000FF00000000000000FF000000000058
+:106A40000000FF00000000000000FF000000000048
+:106A50000000FF00000000000000FF000000000038
+:106A60000000000000000001CCCC0201CCCCCCCC5A
+:106A7000CCCC0201CCCCCCCCCCCC0201CCCCCCCC80
+:106A8000CCCC0201CCCCCCCCCCCC0201CCCCCCCC70
+:106A9000CCCC0201CCCCCCCCCCCC0201CCCCCCCC60
+:106AA000CCCC0201CCCCCCCC00000000FFFFFFFF1F
+:106AB000000E0000011600D6002625A0002625A005
+:106AC000002625A0002625A000720000012300F367
+:106AD000002625A0002625A0002625A0002625A00A
+:106AE0000000FFFF000000000000FFFF00000000AA
+:106AF0000000FFFF000000000000FFFF000000009A
+:106B00000000FFFF000000000000FFFF0000000089
+:106B10000000FFFF000000000000FFFF0000000079
+:106B20000000FFFF000000000000FFFF0000000069
+:106B30000000FFFF000000000000FFFF0000000059
+:106B40000000FFFF000000000000FFFF0000000049
+:106B50000000FFFF000000000000FFFF0000000039
+:106B60000000FFFF000000000000FFFF0000000029
+:106B70000000FFFF000000000000FFFF0000000019
+:106B80000000FFFF000000000000FFFF0000000009
+:106B90000000FFFF000000000000FFFF00000000F9
+:106BA0000000FFFF000000000000FFFF00000000E9
+:106BB0000000FFFF000000000000FFFF00000000D9
+:106BC0000000FFFF000000000000FFFF00000000C9
+:106BD0000000FFFF000000000000FFFF00000000B9
+:106BE0000000FFFF000000000000FFFF00000000A9
+:106BF0000000FFFF000000000000FFFF0000000099
+:106C00000000FFFF000000000000FFFF0000000088
+:106C10000000FFFF000000000000FFFF0000000078
+:106C20000000FFFF000000000000FFFF0000000068
+:106C30000000FFFF000000000000FFFF0000000058
+:106C40000000FFFF000000000000FFFF0000000048
+:106C50000000FFFF000000000000FFFF0000000038
+:106C60000000FFFF000000000000FFFF0000000028
+:106C70000000FFFF000000000000FFFF0000000018
+:106C80000000FFFF000000000000FFFF0000000008
+:106C90000000FFFF000000000000FFFF00000000F8
+:106CA0000000FFFF000000000000FFFF00000000E8
+:106CB0000000FFFF000000000000FFFF00000000D8
+:106CC0000000FFFF000000000000FFFF00000000C8
+:106CD0000000FFFF000000000000FFFF00000000B8
+:106CE000FFFFFFF3318FFFFF0C30C30CC30C30C329
+:106CF000CF3CF300F3CF3CF30000CF3CCDCDCDCD66
+:106D0000FFFFFFF130EFFFFF0C30C30CC30C30C3AB
+:106D1000CF3CF300F3CF3CF30001CF3CCDCDCDCD44
+:106D2000FFFFFFF6305FFFFF0C30C30CC30C30C316
+:106D3000CF3CF300F3CF3CF30002CF3CCDCDCDCD23
+:106D4000FFFFF4061CBFFFFF0C30C305C30C30C3AC
+:106D5000CF300014F3CF3CF30004CF3CCDCDCDCDEC
+:106D6000FFFFFFF2304FFFFF0C30C30CC30C30C3EA
+:106D7000CF3CF300F3CF3CF30008CF3CCDCDCDCDDD
+:106D8000FFFFFFFA302FFFFF0C30C30CC30C30C3E2
+:106D9000CF3CF300F3CF3CF30010CF3CCDCDCDCDB5
+:106DA000FFFFFFF731EFFFFF0C30C30CC30C30C304
+:106DB000CF3CF300F3CF3CF30020CF3CCDCDCDCD85
+:106DC000FFFFFFF5302FFFFF0C30C30CC30C30C3A7
+:106DD000CF3CF300F3CF3CF30040CF3CCDCDCDCD45
+:106DE000FFFFFFF3318FFFFF0C30C30CC30C30C328
+:106DF000CF3CF300F3CF3CF30000CF3CCDCDCDCD65
+:106E0000FFFFFFF1310FFFFF0C30C30CC30C30C389
+:106E1000CF3CF300F3CF3CF30001CF3CCDCDCDCD43
+:106E2000FFFFFFF6305FFFFF0C30C30CC30C30C315
+:106E3000CF3CF300F3CF3CF30002CF3CCDCDCDCD22
+:106E4000FFFFF4061CBFFFFF0C30C305C30C30C3AB
+:106E5000CF300014F3CF3CF30004CF3CCDCDCDCDEB
+:106E6000FFFFFFF2304FFFFF0C30C30CC30C30C3E9
+:106E7000CF3CF300F3CF3CF30008CF3CCDCDCDCDDC
+:106E8000FFFFFFFA302FFFFF0C30C30CC30C30C3E1
+:106E9000CF3CF300F3CF3CF30010CF3CCDCDCDCDB4
+:106EA000FFFFFFF730EFFFFF0C30C30CC30C30C304
+:106EB000CF3CF300F3CF3CF30020CF3CCDCDCDCD84
+:106EC000FFFFFFF5304FFFFF0C30C30CC30C30C386
+:106ED000CF3CF300F3CF3CF30040CF3CCDCDCDCD44
+:106EE000FFFFFFFF30CFFFFF0C30C30CC30C30C3DC
+:106EF000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD98
+:106F0000FFFFFFFF30CFFFFF0C30C30CC30C30C3BB
+:106F1000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD76
+:106F2000FFFFFFFF30CFFFFF0C30C30CC30C30C39B
+:106F3000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD55
+:106F4000FFFFFFFF30CFFFFF0C30C30CC30C30C37B
+:106F5000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD33
+:106F6000FFFFFFFF30CFFFFF0C30C30CC30C30C35B
+:106F7000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD0F
+:106F8000FFFFFFFF30CFFFFF0C30C30CC30C30C33B
+:106F9000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDE7
+:106FA000FFFFFFFF30CFFFFF0C30C30CC30C30C31B
+:106FB000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDB7
+:106FC000FFFFFFFF30CFFFFF0C30C30CC30C30C3FB
+:106FD000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD77
+:106FE000FFFFFFF3320FFFFF0C30C30CC30C30C3A5
+:106FF000CF3CF300F3CF3CF30000CF3CCDCDCDCD63
+:10700000FFFFFFF1310FFFFF0C30C30CC30C30C387
+:10701000CF3CF300F3CF3CF30001CF3CCDCDCDCD41
+:10702000FFFFFFF6305FFFFF0C30C30CC30C30C313
+:10703000CF3CF300F3CF3CF30002CF3CCDCDCDCD20
+:10704000FFFFF4061CBFFFFF0C30C305C30C30C3A9
+:10705000CF300014F3CF3CF30004CF3CCDCDCDCDE9
+:10706000FFFFFFF2304FFFFF0C30C30CC30C30C3E7
+:10707000CF3CF300F3CF3CF30008CF3CCDCDCDCDDA
+:10708000FFFFFF8A042FFFFF0C30C30CC30C30C37B
+:10709000CF3CC000F3CF3CF30010CF3CCDCDCDCDE5
+:1070A000FFFFFF9705CFFFFF0C30C30CC30C30C3AD
+:1070B000CF3CC000F3CF3CF30020CF3CCDCDCDCDB5
+:1070C000FFFFFFF5310FFFFF0C30C30CC30C30C3C3
+:1070D000CF3CF300F3CF3CF30040CF3CCDCDCDCD42
+:1070E000FFFFFFF3320FFFFF0C30C30CC30C30C3A4
+:1070F000CF3CF300F3CF3CF30000CF3CCDCDCDCD62
+:10710000FFFFFFF1302FFFFF0C30C30CC30C30C367
+:10711000CF3CF300F3CF3CF30001CF3CCDCDCDCD40
+:10712000FFFFFFF6305FFFFF0C30C30CC30C30C312
+:10713000CF3CF300F3CF3CF30002CF3CCDCDCDCD1F
+:10714000FFFFFF061CBFFFFF0C30C30CC30C30C396
+:10715000CF3CC014F3CF3CF30004CF3CCDCDCDCD1C
+:10716000FFFFFFF2304FFFFF0C30C30CC30C30C3E6
+:10717000CF3CF300F3CF3CF30008CF3CCDCDCDCDD9
+:10718000FFFFFFFA302FFFFF0C30C30CC30C30C3DE
+:10719000CF3CF300F3CF3CF30010CF3CCDCDCDCDB1
+:1071A000FFFFFFF731CFFFFF0C30C30CC30C30C320
+:1071B000CF3CF300F3CF3CF30020CF3CCDCDCDCD81
+:1071C000FFFFFFFF30CFFFFF0C30C30CC30C30C3F9
+:1071D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD75
+:1071E000FFFFFFFF30CFFFFF0C30C30CC30C30C3D9
+:1071F000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD95
+:10720000FFFFFFFF30CFFFFF0C30C30CC30C30C3B8
+:10721000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD73
+:10722000FFFFFFFF30CFFFFF0C30C30CC30C30C398
+:10723000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD52
+:10724000FFFFFFFF30CFFFFF0C30C30CC30C30C378
+:10725000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD30
+:10726000FFFFFFFF30CFFFFF0C30C30CC30C30C358
+:10727000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD0C
+:10728000FFFFFFFF30CFFFFF0C30C30CC30C30C338
+:10729000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDE4
+:1072A000FFFFFFFF30CFFFFF0C30C30CC30C30C318
+:1072B000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDB4
+:1072C000FFFFFFFF30CFFFFF0C30C30CC30C30C3F8
+:1072D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD74
+:1072E000FFFFFFFF30CFFFFF0C30C30CC30C30C3D8
+:1072F000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD94
+:10730000FFFFFFFF30CFFFFF0C30C30CC30C30C3B7
+:10731000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD72
+:10732000FFFFFFFF30CFFFFF0C30C30CC30C30C397
+:10733000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD51
+:10734000FFFFFFFF30CFFFFF0C30C30CC30C30C377
+:10735000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD2F
+:10736000FFFFFFFF30CFFFFF0C30C30CC30C30C357
+:10737000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD0B
+:10738000FFFFFFFF30CFFFFF0C30C30CC30C30C337
+:10739000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDE3
+:1073A000FFFFFFFF30CFFFFF0C30C30CC30C30C317
+:1073B000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDB3
+:1073C000FFFFFFFF30CFFFFF0C30C30CC30C30C3F7
+:1073D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD73
+:1073E000FFFFFFFF30CFFFFF0C30C30CC30C30C3D7
+:1073F000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD93
+:10740000FFFFFFFF30CFFFFF0C30C30CC30C30C3B6
+:10741000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD71
+:10742000FFFFFFFF30CFFFFF0C30C30CC30C30C396
+:10743000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD50
+:10744000FFFFFFFF30CFFFFF0C30C30CC30C30C376
+:10745000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD2E
+:10746000FFFFFFFF30CFFFFF0C30C30CC30C30C356
+:10747000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD0A
+:10748000FFFFFFFF30CFFFFF0C30C30CC30C30C336
+:10749000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDE2
+:1074A000FFFFFFFF30CFFFFF0C30C30CC30C30C316
+:1074B000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDB2
+:1074C000FFFFFFFF30CFFFFF0C30C30CC30C30C3F6
+:1074D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD72
+:1074E000000C0000000700C000028130000B815832
+:1074F0000002021000010230000F024000010330C0
+:10750000000C0000000800C000028140000B8168F0
+:10751000000202200001024000070250000202C0E7
+:10752000001000000008010000028180000B81A80B
+:107530000002026000018280000E82980008038031
+:107540000010000000010100000281100009013854
+:10755000000201C8000101E8000E01F8000002D895
+:10756000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC5B
+:1075700000002000CCCCCCCCCCCCCCCCCCCCCCCC5B
+:10758000CCCCCCCC00002000CCCCCCCCCCCCCCCC4B
+:10759000CCCCCCCCCCCCCCCC040020000000000067
+:1075A0001F8B080000000000000BFB51CFC0F00350
+:1075B0008A37B231306CE344F0E98159181818F871
+:1075C00099C8D7BF0668C01620BE0CC47B5848D7E0
+:1075D0007F5E1AC15E20C9C0700488BBC51918EA55
+:1075E000A510E296320C0C3780FCC5503109A09EE4
+:1075F00069D2E4BB79140F1E9C648ACA773586D0A1
+:10760000374D2074329ABC1B545E500F42A79862CB
+:107610003757488F38FB1354D0EC57C1AF3E5D034A
+:10762000951F8EA6DE0FCA0700DCEC914ED8030032
+:1076300000000000000000001F8B08000000000098
+:10764000000BED7D0B7815D5B9E89AC79E3DFB99E7
+:1076500049086127049C8400C1F2D84280A0142705
+:107660001030B6D46E5E12BD081B1F95872411D34F
+:10767000635A39CD401E2401243E4AE92DD50DC55B
+:10768000367A6D1B6D6A698FF66C442D9EDBD303D1
+:10769000942AADE0096A2D58A0B1A71C68BFB6DCDA
+:1076A000F5AF47F6CC64761E3EFAF57CB7F193C988
+:1076B0009A59CFFFBDFEFF5F2B0A2A443957217428
+:1076C000057EAE47C8101042D3534F744F86887260
+:1076D00010FABC8AC8CF255F7832CA40A84EA5CF21
+:1076E000FBFDE17DF06CAB4728391EBE8F4EA0300C
+:1076F0004201848AE56C68E18F3E5100CF9A29B13E
+:1077000049E439139E594844683894F3B57703B473
+:10771000EF2B12FEE764BC0CC693E82B24A3D268BF
+:1077200092B47F00A119A979A09ACF6AB1506ADEFC
+:10773000CEA7A42928C9EA5E817FA41519F160FAB1
+:10774000FA752785EFBE64A93F1685B2C9BC6424CB
+:107750009379B1F60899C83A3F673F97EAD1775FC6
+:107760001ADB176EE9C6E5706BA957C9B3B95E435A
+:10777000492F42B899D139113F83C8D837B16FBB6F
+:10778000722430F8B1F9C0383AAE8FFF4718EE8D49
+:10779000D92811001CA2B80D6E8DC1C5AAE1D21F57
+:1077A0007FA26C0CB76236E7C2BEEBF5C1BC301CE1
+:1077B0007C302F17782E87794DEF3B2F5F91735ECA
+:1077C0006B90153E439D977F024247001FB2811088
+:1077D000C1CB7DB6FE44CD30BB5DFA438C2E649D9B
+:1077E000AD6F90780A148BA9F1010EBADF465FDE07
+:1077F00048969DDE9C740DF020F86A67F0894994E4
+:107800001FCC141EF13350AA0BA890148F00DE2257
+:107810000CEE913B9BEF15315F8551A2651CE6870D
+:1078200048F7EA85C067E193379E459331FCA25340
+:10783000D579784D5A89FED002FC0C4CD404A0D7DF
+:1078400036E0B36BA1BF5BCC325C6E80CEF270D100
+:10785000BCC93009DC0C1BDC30E47419973DF06BBB
+:10786000A10BFC502F1E842BDEBEEDD3C1CF832C89
+:10787000F823FCBCD1469769F11EA7ED4CFC1FE034
+:107880002BCBD18F566EE7F330B294F1F7A7E01708
+:1078900002EF7BFF26E365A27DAA5E82D75B2C6A9E
+:1078A00009A88FF44C1997031532023996998D0E59
+:1078B000628C0C889746842A80FF11EA448B26A5A7
+:1078C000E6F7AF8CBF723FF7E8EA66CC4F174B8301
+:1078D00051E0AF8886D0B0ACBEEBD9CEE44B6F3967
+:1078E000FA2C8A4F84F1122D85785E66548C3E0105
+:1078F000F3297E518B5BF8E574AF7C71D207D2E53A
+:10790000194C1E60F848C5A2E19BFCE1E943FA80EE
+:10791000F4118C2B36BE1C2ABE2E0C913E3EEC7808
+:107920001CAF7DF96A33C36BA30AF2AC455FDCAFD1
+:10793000BEEA8BD77D08EA078A91917069F75F5696
+:107940007DE17C5AE4BB538E4A236654EEED0F6F03
+:10795000D97678F07E7D7592FECE305C9435225FCC
+:1079600015A6075A230F9B08D3DD45903D181E52DC
+:10797000FB354928A32244E810FF24055CF6458C1A
+:10798000441BA18304C10B9F9F57176DF095B3ED66
+:107990007218559A8275FEBE3A85CC4381F1B2C108
+:1079A0002EC01D6250C84194F485A1069D3FA8A435
+:1079B0002B63A06CB7335AF4A9C80D0F32C3AB20A8
+:1079C000707A7D6070F2C539DE52FB7C07DD2E28AF
+:1079D000EBEFF2362E723AD54E46EF72FC6020CEB7
+:1079E000E1761DC3D3560F3A204CC1F220FF66B09A
+:1079F00014D056F8340BDB21F0CCC5E5FCA9442E9D
+:107A0000A00E4186799221311E11D677502F20E8A1
+:107A1000A41F51AD2172450A1AE4C9BFA79F171DC3
+:107A2000BFB7ACC6AB003F6B228ADE86E7B85E32DA
+:107A3000F4CD4017D3B07CD2E1FDB872D0731E8173
+:107A4000CEEB4B422E59879CD59243ECB234F6DDF7
+:107A50001A19F3E454F8BE7D5C7FFC84129E9E6E7E
+:107A60000B3C9DF6E0DD02B6073F817F99896602F7
+:107A70001C7F1F5D9C91EC075FEFD51FD6E4B129F9
+:107A80007BD0F97DBD846ADCE440B3A052BE544D86
+:107A900005EC03BEEEF5982FBC59C0E75BE87AB35E
+:107AA000B3097CD777BCAAC916FE5B8FD58C776AE1
+:107AB000DFF57078F37E7ADB270EDBDA3BDBF5F659
+:107AC000C7E505B68781CE391D0484F83601BFF7B6
+:107AD00046179B7930FED36514FF69E6DF8BAF0F45
+:107AE000387FDE6E20BAFAFDFE8666D04FEF2AEDB3
+:107AF000375D8BE9E837CF48D12DF8EB9A3DE3CBE2
+:107B0000C16E7A97D137C7D3D9FD0D396EF4910E76
+:107B10004FAF0A3E320EA7AF35E28A7EE96120FA06
+:107B2000FA9E93BE3A977C2CF475C4495F0C1EE70D
+:107B30003AE9FAD1EE61142F0C5F4EFCA4C5CB07D5
+:107B40006DD7979E7E2160BEF6762E71A727365F91
+:107B50008EAF0F3BDF81E82847370C0D8F3F02DBEC
+:107B60003102E88F12144DEA60D745A9DE8A52BD72
+:107B7000C5E5126F7F41A0769A8C8E93F6124A9AD1
+:107B80001AB1B7ED76C67C09BFC4FD3416A384973D
+:107B9000EC8B0C95E8A9621951FD67047371FD0C1B
+:107BA000C47EA4D951587706B3FFD16CA67F056C6B
+:107BB0006FE1F5054BECF687DF619F48B05F08BBCE
+:107BC000D85B43DC1FFB44B63F0EA020D1477C7F2F
+:107BD0009C863F7BF7C50CAEC315648878DDCA610F
+:107BE0004F628B00DA0D11FD8C4E0A09EA2F40C559
+:107BF00060376F14F2A2A00FF03EAF27037F7FF72C
+:107C00009B12D10F75919A554DB0EC9BEBC677E363
+:107C1000711FAE47D38A3CA9F11E96DB5580776B66
+:107C2000D146CDBAAEAF09F102D1A2777C11655A27
+:107C3000D134184E7EAB1BC343C48004FEF3071F30
+:107C40008DBCAC03FCE8FB5E3859CB52DF7236D8F2
+:107C50003C79A498043BAE3584A89D8F460A65986C
+:107C60000E5A3DFCFBEB65B0DF6DF5D1F29E2DB3F6
+:107C7000369B501ECEEA9B95F47B2E2DDF273E517E
+:107C800006DF139978CD5380AC13953117FEBE4FA4
+:107C9000A47E95067346EC2E323D6A7F5DC5F7D90A
+:107CA0004B6E8ABE0CBF14E923C07F220563C4BE9D
+:107CB0009198BD266B26D5E36AF4F0780CEF51C796
+:107CC000256462388C6A3F5AE6057A0F723B2D8A2A
+:107CD00096E2F675CC1FA022BA3F06BFCE1542C76A
+:107CE000FA08D8B720B0CF2CFB7689D963BD78725B
+:107CF000E0ED11B986E06D6B7EEDE1023CBEB9505E
+:107D00008C02D96CCD2FCC5C6DC1E3B7D4B9952270
+:107D1000D8318DD9C42EE1FB64601828E792290080
+:107D2000683BCBC078CCC7920F613A1D1DEB29038D
+:107D300014E895DA8B648F8BCAB577895D2509576E
+:107D40003E31783B0AD62D02BD62FA7DC2B2DE61B9
+:107D5000028AB9C9DD157216C1CBB00ABCDE7EFC41
+:107D6000049FC7FA84DA677135164A3F4EBA797EA6
+:107D700008786E01BE188912044E03C1351D3C9B64
+:107D800023CF661279FD11C3355D7B273C870994AB
+:107D90005F56C8A5845F06EBDF6981FD14DEAF3650
+:107DA000811F0E3F1B981FCED9DE27B7A3A80B7EDD
+:107DB0007DBADD3FA458E91EFF5F2BEA541F049DE6
+:107DC0007E228A67A75E58C0F4425304EB052A0F4F
+:107DD00017821E0830F8374511F9AE8450C2C4DF4F
+:107DE00003A00FB09D852652F9AFE2FF80DF465415
+:107DF000DAF58132487DF08E107B99F0174621CC60
+:107E00006FB7D07EE338A09F5C6A8F476E6F89584A
+:107E1000FD05B522D5775C9F3D56D43B6F023F2FC1
+:107E20009BC36358A4023D26F2176710BFDD9D0176
+:107E30009B7C8A7C6931D9FF5AE899EC73DB997F86
+:107E4000341DFE342511779387BA249279858D9E4F
+:107E500024F8FC0821E7309721236B0A7F64DB8735
+:107E600085A7F61C1E83D7FBF83522B11BE5D97216
+:107E7000D283E12B97BE5229E0E7E3B03680C72CCE
+:107E800044E834A82F382B813E96BBD122DC5FB06A
+:107E9000C2B92FB69425E8A76725D1DF563F753FB5
+:107EA000FBB8C13E1B30BCDEB2F03F42B10AD0B3DA
+:107EB0003296E36D88B84BF3605CD9D072805E6413
+:107EC000231A24CFEEB20A5A8EB5C177DFECE8D17F
+:107ED00072E0434D26F23EA152BCF17EE74805B662
+:107EE000FD5BA6E6F08FCA6625D0814F5710D0A75C
+:107EF0002FAE180917FCD48A329377763AE1F4D181
+:107F00008F9CFB5074714AE47E6A3BDE6DF451989D
+:107F1000C22B6F17ECE3A7B2E3D559FEA8F1E99B9A
+:107F20004DF189303E99BFA40DE01C344504761113
+:107F3000AF17900A6DF8095EC61B2B6CE7EC2E4359
+:107F4000956EFA292029A43EE6FB7289DAE502D86B
+:107F5000DBF3A53D06D079A208E306F7DFE2C126F0
+:107F6000112EB76C16395E89BCADDDD252B619D769
+:107F700069392988D214A09BE5049F3EE6F7B9E44D
+:107F8000312B0A71BBB65122DAA783FEE9DFBFD5D8
+:107F9000506FF76F815F01ECEFFC1A6D2A80395D3D
+:107FA000BB5D3562859BFFEB2E89FABF76D41C6BD7
+:107FB0002766E84BF67D876785011408FB8FBBA415
+:107FC000E9A976A112EAD74071BC1E5CDFC3D733A2
+:107FD0001CD3673FF18AFFCDF4092FE7B1788EB348
+:107FE000DE4F2446873A8597CAE8F05241FFF4CF26
+:107FF000E173B9456271901E1F227A7738F1DFE98B
+:108000006C5D9279A40CFA9151F766D887EC12D185
+:108010001AEA578E117D1366E33D5EFA7B1FD4BBCF
+:1080200041A6F27294D1D30A781EB54944E0C77EC6
+:108030004AD249D72356D41CF4E0F7AD9B5134887B
+:108040005F8D867E71BB57C62A44EEABD954EEAB2A
+:10805000B59804703D15EF6B745C6E3DD88A40AFE7
+:1080600087F1C6094C5EBD1489E0E7F6D4759B30F4
+:108070006EB8344AECD0436367907DD583D928EA43
+:10808000D5537281D3D1839B161B40072D781F06D1
+:10809000E596A22D2AF8B12F16CBA48CFE8CE1C355
+:1080A000FD85F81FDDA474D35A40E72B4FEC462220
+:1080B000E15B95E053D6E8FA5B43DF34617EE65A34
+:1080C00044EC23B06F497C468EAA20CFF377CF26AD
+:1080D000FC236BED02D0C346147FCA4A27523049B5
+:1080E000E6DFFA1789D9EF2F6D06FB7D247485CB67
+:1080F000AF4AE7370FC51EE171416E8FB4C99D8449
+:108100000F4DCC63A06FB87DE22BEA24F4F9DF8C2D
+:10811000BE07DBBFAFD8EE4775DA2B4E3BA556D472
+:108120006C76A9735D973CC91B617E6DB998BF0BD6
+:10813000FA8E775CA2FB923D91C5FF51A0A7FAE1B0
+:10814000DFB97DC4CBF9971502EFC1D7C7F20DF6A1
+:108150005E06E5A3D19C4FBFD03F9F723EBA84918B
+:108160007E04F0239B2AE123A398F011E70FA9DBFB
+:108170006C1983E94CAF13C1238DC04CCFC2E5AB62
+:10818000307D2785149D8E62E3CA1313EDE35DE80D
+:10819000ECB15AD120FEEF28EE067F0F9B4788995D
+:1081A000E92F4E70BABA0874C5E92C7FF702B2AE57
+:1081B0005781A0A7835E7597233F62760ED2F61B88
+:1081C000563FAD0F35BAC7CF6B1FEF377EAE167D6A
+:1081D000B8F87948B6FBB3066A3FD4B8B9747918D1
+:1081E000A18FDE32DB873AEBC565265F4FEEB3C168
+:1081F000A50F3CA4EDD1783F74A27E487F3FD159B2
+:10820000838083138E3364E667F998E0E88C6BBF54
+:10821000CCE4FC40F2C06F1849710CF8C510F5DBD6
+:108220000411F3DBD8E9FDF14D94DEFD21712F88B7
+:10823000A870ED11D36B990FA6F725F2F014BDE7E6
+:10824000152793801FA7FE49A7770692B72B55E302
+:1082500036D925CF84EFB3537904988B5DF208D2D9
+:10826000E2B5E6A3C923182CBC7BFD962C2FE0F6C3
+:108270005246B7D8707803C365ED610FB1EFB1FE18
+:1082800093ACF1B2B56C7F773BDB1FDE896261F89E
+:10829000781E8915C02FE7D1B1F0340BDDEF9415AE
+:1082A000CA2F2D9EB7C06FCAE3E077B5D3329FCFF8
+:1082B000DDBBEDE5CFA1C539E0AFFBDCA31EF020AF
+:1082C000A0B50EBF593D10049EFFDDA8A619F0D63B
+:1082D000E4A176E8ED1A92216EBDE1075F9FB11A25
+:1082E000EC13667FBC87E5B26EB19FD605130AE03A
+:1082F000F7EDAE69375F87A07DA2390FE2D7998885
+:10830000EC479D70BEA3C53EBF81E6EF9C2F425B4C
+:10831000FA9D87DC21B8C659F7CBF6386BBA7C29B1
+:108320009E27F5924CF16FCE45C47E32DF0C241AA5
+:10833000883EA1795203B57F15DA4FFFE0ED7F3615
+:10834000C0F81BD49E05C4CECA3663E0EFE1F1BE8F
+:108350002A54638CC4BFCACF2F3281E77AEB45061B
+:1083600059AFA8FF7AE9E67D56534D714A6AFE5F20
+:1083700013E2276597F5DF2FC5ABA07F2FE0418281
+:10838000A74CF04DFCBB18BFD572B045C8803CA6C9
+:108390002EB2CFF3E9B28D1EAAE117906BC554AE91
+:1083A000058AEDDF9D7EDFDFF5E23D49F88F84969B
+:1083B00075B01F824909FC32A5F2B9DEFA78BC2AF1
+:1083C0005817EC93508CC88D5A8DD6AF42FACED93F
+:1083D0002584FFC8BEBBB6750C8997D70ED7A3E01E
+:1083E000879551D4207D38E8AEFAB28012167D58B8
+:1083F0002DF728C067D5D82EB2BEDF18916CFE5776
+:10840000E7D383543D584CFDB9C43FA4E1B265DDC8
+:10841000BF6F17585E8A9EB1B41FBFDCC608F5F364
+:10842000DEDE3A3683FA03EDF2F702DB1FFDE4E904
+:108430006F28E0BF3FFFD4E99B00DEEBFF45422AF7
+:10844000E4653C1D4249628F2514B0C7D67549AE1C
+:10845000FE0392390371CDEF8608BED63DEB4D2C5D
+:10846000C4EDD73DF7F66484E777614BCF2B23C18A
+:108470006E7E4AA07E6BB37BF212FC7E9D8C56B959
+:10848000F9058A3DD44E3DF7C34025F0B7D0717051
+:1084900025E9B773B9C76BD95F5FE5F1F07AD42EE0
+:1084A0007F52488C15DCE647F33ACE3D29D0F91DC2
+:1084B000F0247C30BF8EBD4A1CCFA3BAE37D224F8F
+:1084C000E67DF7DB618043F501C9A607AA3BA4A4BA
+:1084D0007732799E8627C483841940278C5EBA360A
+:1084E00090385055E7B6F7C14F517DC02ED7305C5C
+:1084F000A24980EBEB52742194BFF7ADB08E41F5E9
+:10850000DE9127C20057DCEF6A2503F48D9DBEA1E2
+:10851000FFCB597DFB43A887C4E1AA3B5BE9785DAB
+:108520009FF90DE8956A87FC7C0F7EC9ED6BCFC47F
+:108530003C0EBBB0637071B8F5DFBEF89889C73DDB
+:10854000F7EC6F1F33F1FCEFF9EB7F3DF600F0E73E
+:108550008F7D1AC8FFEAA77E1146167A5CE7A1FC58
+:10856000786114327371BD0BBFF4264CFCEAC20B68
+:10857000BF19ADE3755F78E68F393AAE5FFBC2FC99
+:10858000110087DAEFCF1BD1DF7E1BE835E1B5CED6
+:108590002B41F0AA1F10A811F43C7B3AF073A8EB12
+:1085A000D06898E7F913DE28D83DD5F85DDD54C0D2
+:1085B000D706A28FA1BC09C3B9EAE9ADEF839CE855
+:1085C0000B6F73A4489CF0C991E08CAFEA7A7B01F1
+:1085D000C11BEA217AD459BFFA38C6E794F4F8BB34
+:1085E00088FEAC80BCAB7EBA958ED789F117EE8B36
+:1085F000BFF3F0CBACBEF86B71E0EF22BAE7F15CF1
+:108600004868EB1A668B7FF2672AEE17CB88F52352
+:108610002FB83C1808BE6B043AAF651E63B707F865
+:10862000EAD9402F7E17027EBF7D7134C2F471C635
+:10863000D3B312E466CF0B5E6D1F7EBFEE85D70904
+:108640009F5DF8FE51452779972828E4B0FC2FFA62
+:108650007304E47015DDCBA1EAFDA1A4379CC253DD
+:10866000556251851E26EF4F93F7094AFF558983BE
+:108670004B0517BC1DF314523B2A319CC065C3FE49
+:1086800037146A5FA6F02994023E4F2F80F7E9F075
+:10869000C9D7AFC1FA675AF0BA9FF2ADB37E15E6FB
+:1086A0004FD07B7DF09B105E87E785BD5E19F4DEC1
+:1086B00005B0BF827DF19E823FB57F86BA5FF9A982
+:1086C00093BF795C98C1213D7D98CC0EE87F7D43B6
+:1086D00085DF8F3CBA8D8E381CCFFDD95DFE9F6142
+:1086E00072A30A99157916FB44F560FB04F2C65093
+:1086F000CC1C59909AEF39D84760FA3BF79444E282
+:1087000030CD9D87881C77CA8BAA34FEBF3FF2F11B
+:108710000E1C9C0C72EDDC8B3F24F459F5F46905BA
+:10872000FC63AF747C4FE99E98E207D00F098B7E03
+:1087300038F79D8393A93C70DFFF2A0AEDBFFA79D1
+:108740007BFFD54FBF6FEB7FBDD9A9D0FC84FEC79F
+:10875000794F3696C37ADF3BE241204FDFEB945CE2
+:10876000FDADBF05FD68C9336B3EBAE00D88DF97EC
+:108770001CF3EBA047BBB618237680BD76CC8340B4
+:108780007E23D9F82DC497BB8EFA75C87BE83A765C
+:10879000B3A45BFC133F70C073E671735E08F737D8
+:1087A000B33B56025B28A7DC283D2942CCA277FECA
+:1087B000B5472B4680DC6F047B7E3C8C178D90F890
+:1087C00077784105CD0B14359FABFEA6FD79589CFB
+:1087D000DCA38948B7D223DF6F31BF4F73D0DDFFF1
+:1087E0005CA670FB108F6B9183D856AD74C35B8908
+:1087F00042F741E9BE970EF07DB6C2F200D27CEF9F
+:10880000E56F861F2524C6DCE63D99F5E3F4ABA6AB
+:1088100093071ED6CF144567FDD3F502BC1759F256
+:10882000DD47A2C466F07FA160D019678EA9D63853
+:1088300073E591831057CE5EF27C2EC03F8C1AB543
+:1088400077891D8FA257FAB1639D716567BE61BAC2
+:1088500038B31AAC3A91447DFBEB1B5737485CBDEB
+:1088600031BF5CB5C6D51BB53E71F50D0A1EB729E3
+:108870000D1E3EABCCBD17BE63B333EEF6BD49A1B2
+:10888000FEABEB51F7F756C33CA3342E3FDB01AFF1
+:108890004F3278FD780C5E38563D6548973D18BEDE
+:1088A000F3961A8D2002E7AFE8597F10F88CC7E5E0
+:1088B000CDF1E295C0E0E137D47C8795EAE20795F7
+:1088C00041E43B202DCB552FA4E66132BE89907D3B
+:1088D000128FBF1C3A75B70A724B46F18A024B3CA5
+:1088E0008CE4D1E3FE72923E64E0F92A9A4EECEDFC
+:1088F0009CE4DAAFDE05F1722D9FC41FA4CBD71123
+:10890000FFA1B35F291235499E57502F932CE334B2
+:1089100067D3788CACC55CF381572AF1A761BDD2CF
+:10892000E539A45F51A5F10C141C5C1EEC5796842C
+:10893000097C550C5F908F0464B02E960FF5D09291
+:1089400030D133BEC39EBDF0DD17A4F951F78BFEC5
+:1089500028E44F39F3A3CADEA4F196E6D30289A333
+:1089600070FA6D2EA8B90AE4783FF9512F2B16BF83
+:108970007ABAFC285FF04E921FE5FBC0F951917264
+:10898000B0C79A337919AB133C8F6696EFF42BE599
+:10899000F03CD04FCD2C3F0A99AFCE23F57919D5B5
+:1089A0001C32E03BCBA7CAD9DADC00F5B347A29A68
+:1089B0004EE2CF33D0328B9CF579699CF9CB8AF1AA
+:1089C0009F8A45EE71FCFB7AE96AAB0AFA1B3F49C4
+:1089D000BCB219D315D8ED39C95664D547FCC9E9DD
+:1089E000A8B9A8FF789D7CF91AE2C7E765554B182E
+:1089F000864B7D43A57A82D32FC4D3402FA97AFC1E
+:108A0000AB77013D6707A3014A97244ED61224EEA7
+:108A1000A93EEB6829BA9DC4BD2E6AD4DBCDE9B866
+:108A2000EFFCE7B0F9179A405F1783288A5CE45F90
+:108A30006A1D25641D2B1543F55AE0987D957BBE74
+:108A4000E9762F5D4F536C45EC2E98C91A7BDC9567
+:108A5000E75FF0FA01213E1CFAF564D3B8ABA852E7
+:108A60007E4BE10BAB0A8B7FB301AD308104E41583
+:108A70009DE4C8A2AC2548FD31BEF868AF2D3ED7B5
+:108A80004DE3B88E78E27CE91ECADF03E06F07DBB6
+:108A90009F6C83B8DB7888CF45D8B93D9DC5E90C7C
+:108AA0009A2F94869E5A8AFA8F43B5D74749FB9DE1
+:108AB000F5A5340F4940CCAFFDF506A013704B501F
+:108AC000BADFDF007C1092385F3C45CA0F0AB41C45
+:108AD000DFDA45F8E6D0A9D72BEFC0F4D16CF8095E
+:108AE000FF0FB43E2D3183E075A8E3F45D2F1DB771
+:108AF000C50892FDEE40EBD69274DCC18EC3E3E371
+:108B0000A9F5A9649C667D8071DAE93803CF9FF2EC
+:108B1000C98E836B2B20AEAC62FEF7E1F7EAEC1E48
+:108B2000E4161FCA60FC73E89497C8EB966C9AC76A
+:108B3000EB290E1AD40968EFDF3331672E39C7509D
+:108B40007235C98BDF71B095C81905C6C1553CD1C6
+:108B5000E06ADA2E6EC0F9D970398A825FDF539CE1
+:108B60007307BCAF43EDB1B9A0874BE9B92D4F7185
+:108B7000F15DD04F26F0259EC73495E67D788AAF0B
+:108B8000BD1BEA1F9CFE5ABC01E0544AE9001DCE01
+:108B9000B5C1B1592FE4E771FAE57B4FA93D6E816C
+:108BA00054BF2D6F09C94B49BC1CCB856D5E8BFF33
+:108BB0001BEBC59D50F6A01213ECBD5DB7DC1CB5D8
+:108BC000F2F39795D8C3548EF03C2CCEE7EEF970B3
+:108BD000CDD93CAF2CAE4A2570FEA8374F7A61AE96
+:108BE00035AF8BE54907799E7494C6E1DAF17F6E63
+:108BF0007971CEF3891F559EF477BC6C3F1C40A35E
+:108C0000204FFA471E144DE279B7FD428A421E8C6E
+:108C1000933E9CFD39F3FB7BED9134FCFC6B008EA5
+:108C200045EEE5C61D78BBD347E2737CBC97403E5A
+:108C30004D1C984F47AEB1F733AAC67EEEEAAA3A6A
+:108C40007BBCAAC0CCB3D51FD35268FB3EB6FD6A2D
+:108C5000DBF7F1BBA7DACA1312D7DAEA7FA263AE59
+:108C6000AD3CA9F353B6FA530E2CB695AF49DE6A64
+:108C7000AB3FEDF0EDB6EFD38FACB37D9F7962A340
+:108C8000AD3CABFB8BB6FA75D83C51483E1C8D37DA
+:108C9000A1ED23452B7DB66662BD9281E1988909DD
+:108CA0008626EB937833CD314EE51938DB49458A7A
+:108CB000A161FE95F471E51AC91FBC93F09154941B
+:108CC000335727EF672C00BF132AA1E7AF7CAC3FD7
+:108CD0004F114AC2B94B39E8C0AF232EED91B6937C
+:108CE00078AA72F286C342B82F5E3D11679EE2E019
+:108CF000E2DAB2EE683744BEC854595C7B14E60B26
+:108D0000E247FCB344CE3D9787887D60D9DF1038B9
+:108D1000F2FDCD1C1535024C395F94ADE81949F2CE
+:108D2000D97BF7355E7128F9C67DF58A97D85D5CE9
+:108D3000CE0CA457A4C4345B1E82F389E5DF14155E
+:108D4000F6E1E15B893CEADD17F4CAC7D854F8EED6
+:108D500091A3443EF6CABF8E3C9B5C18AC7DE69462
+:108D6000D36D20F4C9791F77791D863C302C971E6E
+:108D70005C72138983A15A643BE79753195341EFFF
+:108D800061BBAC42B5EC9FC3A5D43EFB7BB353BDE6
+:108D90006CBDBD74CAEC550ED76105353112D70BC9
+:108DA0008908F6550DB3A311F003B64015CB3E6DFF
+:108DB000973A86C8D1C6A02282BFB4F1F07C121FB8
+:108DC000F0FA622AE4D135786215B0AE864C517360
+:108DD000CB77DAA252FF8C521798B6BF1FFA501405
+:108DE000BCEF7759EF3E95FA5D1AB5C58741CF655F
+:108DF00085141D526E9B0FCE5A04E3CA0B650DF607
+:108E0000B5086FE2DEB6C41521DF1711F88B442FC9
+:108E10002A756132FE40F3BD47A57E066F9DAFDF28
+:108E2000F97A15773F45BAF96E85F9660F3C5F6FA1
+:108E300036CD5FF5D605C9F8FF0C1759B8C0DF83EA
+:108E40008C96725CAFE9F40DED458462689EDE237A
+:108E50000BA7123AC582DA46BF7C1F81E937A10E03
+:108E60004FEDDFF939D5BB559A97C0F18A74EA8F77
+:108E7000181697C9BE372B4EF7BF29F941E928CB01
+:108E80001345E45C57BE4CE292E0A6B1FA31FECA4B
+:108E9000F671DE4F4609BE5A3F23A32D406F457839
+:108EA0003D70DEF6308D3BB57AA295B1606A3CDE4E
+:108EB000FE4D860F192DCD20F95BD2C2889BFDD9BE
+:108EC0004BE70C6E4E39FB632E6773512E95B3132F
+:108ED00097C311A174FD38ED0D7EBE67E8E74EDA49
+:108EE000093C5BF31F257634F78FA148C900FE1EAD
+:108EF0001A2F4DE179B99EC478946F9C4A9C7EAD3F
+:108F0000450CCF358EFC5D86678E5FEEB747916C62
+:108F1000C2D71CDF12C0137025CD8EF4A7AF24C6B4
+:108F2000374E789EF91F0ACF9FC31AF0336B145E39
+:108F30003FF0CDA11B11898339F891B7E374EF5C41
+:108F4000BFEAFB9FBD7E4E0FE9EB9BAEFB0F1ED72A
+:108F50000D317A5399DE7CB9F4AD1638272267D3E8
+:108F6000FD6EA8B491DCD322235303FF5A889FCB14
+:108F700061E732793E957FA27DFFC1F30B4919F37A
+:108F8000BB87ED3FFADC9BC2EC2C7E4EDF397F279E
+:108F9000BEE6F8DCF30751BEBBDFD5198FE3F10D58
+:108FA0009E07CBE300040E78FD9E59628CC8BF1269
+:108FB00064EC75914FCB7C542F74BDE8237912A1DA
+:108FC0004A85F863F34A926550CEAB4151D013D72E
+:108FD0009E3982E2B8D3B17E2AF7F34A1202F83DF5
+:108FE000F2CED1BCD85D2C5E99579B10565BC679EA
+:108FF000C047E5ECA553F713F9F8E2289A877E5F9E
+:1090000019B5DF8E446E6F2F83714B693E7908EF7F
+:1090100017216F2C74C24BF26F514937023F2AD689
+:109020000266087F3F538FA6DE3916F2BE54F23C2B
+:1090300057AF91E7A151CAC1EB71BD8D057E1DFAF5
+:109040006D2AF4D373BB2195ECF7FF3BF373C4AFE8
+:109050007AA13E42EAB77CC9207645E3C1B3C46F2A
+:109060001830A645A91FD5905029CCE788017E0E5F
+:109070002447F5C5F0FDD02F493D4989FFD204FBB7
+:10908000E45685ECEF010E104F68F0D17CB9ADBE0F
+:109090009A48263C0BD0AA452EF0BED5C7E34CAA71
+:1090A000A4E4A4F29094D2A49401FEE412D439165C
+:1090B000E46553A20CF4345AABE9304EBE9A28034F
+:1090C000FF71FE1A2D0A3E74A594DE23C2F1E1F170
+:1090D000A1D83341A89714EEC5E316FAA9DECC3B1C
+:1090E0009120F70C5D3A35D3D5FEBFFF6419F9BE68
+:1090F000BDBEE258B9859F8369E2950F14CD7DD43A
+:1091000087FBFD196C7486A7EF973F07DBEFCF7CD9
+:10911000549F1E3A357E04D8977569F2A8250DE351
+:109120006918954FE08FD838561F9119B4F643E16E
+:1091300021BDF8438AD789943E1BBE3F3E03FA7D8A
+:10914000E9D4720DFC7DBFCF2E22FB86F3CF790DC3
+:10915000B05FCE67A13524DFF2B999AFC0FEF0B79A
+:10916000F587B3648B5C3CFF9DA3333CB8BFF3CF62
+:109170001E9D2113E64AD8F6F11BAEFC7C06D809E9
+:10918000E65C545C839FD59A82A0DF6A95AE83E744
+:10919000C9EDCA519AE1393F9049DAE78C101F8432
+:1091A000B2A4FE7CF43BD3C8BA695C81C571F0FA05
+:1091B0001A8284AE35BC018178A1E91D0DF1AC5352
+:1091C0005E427F970A5071C114F00B4AA45DCF5ADA
+:1091D00094807C0A255903EC897C3F4D20E09BC09C
+:1091E00071ED20A13576CF5BABAF90D121CD23DCE3
+:1091F0007CEAFEF1001F2ED7E57988C4337A6E51E0
+:1092000013608F3E2CEB5F590176E06D3299072E8B
+:10921000FB34173C2E0F14DAE092C5E2131CAFE9C1
+:10922000E8645B3D8A166178FFB85E8DC2F8CFD7DF
+:109230006BA4FCA3FA08291FA8D7C9F3B9FA62F2F4
+:10924000ECAA8F92EF1DF5A5E4C9F3FAC8D65E2209
+:10925000F674AC0CF4D032EA87D374D1807C850CE0
+:1092600019A9C3B0A9A29DFC4925ECB741AE64641D
+:1092700011BE17A07D36CBF31B9E3BB7B54C4FC933
+:10928000572E4F1B3C48007964CEA27E8610F4878F
+:10929000DB672F45E82D8B5CBF82FF79AB98AD0F64
+:1092A000CF27C3B07F77D60FCB7801597DDB61B96B
+:1092B00048CAA97EDDE137D427F8CBDFB2D0F7AEBC
+:1092C000E978D5988E7609548E3DC8BEEF983E2336
+:1092D000E37628CF9A9141F27F67215DC370DCA9C4
+:1092E0008BA62723557F4FFDE19CF2B14C07819C53
+:1092F000AAD5F6B659F631F9265A15B3D0CBCE1AFF
+:10930000B9621FB133E2B98B27917C63E6D7DE5790
+:109310006ECC26FD927241DBA17293E915903373F6
+:109320002E533DD4AB7FFE4CDF73BDA730FC6F9F47
+:10933000BD450A039F803C057959124773F13C8370
+:109340009FA4F1EF59EF2411E4F72951FC1EEC51D1
+:1093500085E69BE4451202949FF4C5A6FA613F920C
+:10936000B53BB90FE3FB0F5D5E1DE28D5D2FFE91F6
+:10937000E46748931515F83BEFF9D3246F4912BB06
+:1093800015D8F12E6BBB7ABE0CF62C4C84DC2B80EE
+:109390001535C6B394C3D667763695031CC5F85900
+:1093A0006BFD5DFEF8BD74C78C0C3582F9C1C7DA60
+:1093B0009BE39B8C7C5CF6D0F2B2B6714DE66C28D8
+:1093C000E3FA99B4DC88ED846D999D111197839B24
+:1093D0008B9A0E8F8232AF5FD464E2F631A60F50C3
+:1093E000305E00FCDE5BD670396429CBB48C54FA55
+:1093F000E4EBDD70E88FAF8CC470A87A5EE82421BE
+:10940000BEE7F70AB0EEBC037BE9B9800422FBFE9D
+:10941000BC849080A39B1DF587B546EE5CE378C1C4
+:10942000A2614284DE1BA4243C51D85E4E60F782C8
+:1094300070BA782640F5C084046E6F8D4B3BEE0900
+:1094400099C0EEA1212403F2723B3DE7EBA4F3F1B6
+:10945000ACBF3A64B649A0B79FF668243ECEFCEC98
+:10946000E7B8DDC4FC39F730079E678BE9BF1AE423
+:10947000DF6A99F881D7172436631B0AADFF614173
+:10948000145BACA8C947E9657D6667CE544C2F4D87
+:1094900099F67203CB9F8F649A995913217FE8A1A3
+:1094A000D190DF5385DA577E11E6FB531A0F3F7BCD
+:1094B0007056C675B8BCE1A7348EB1A1EBA802F412
+:1094C000BDC3CFF28EBAAEF914ACAF6ABB48CEC5FD
+:1094D000015F1AE3F1748DF6AB654C2FFF1A383932
+:1094E000DF87F1FD64A1A189D720F4C6B6779BD4AC
+:1094F0004FE2B2A24D00FA7863DBF926A0AFF5B3D4
+:10950000F87D76E75F368A58FE2306DE8EB6D94DA3
+:10951000700E63FFAD159F02732B47A4FC8B09925D
+:10952000C4B5A5CC46727EEF774D22B19FC145BA36
+:1095300009C3BD48468765FCDCA5607C029F35CB2E
+:10954000441EE2F72D1E829776727F086AA1F751BA
+:109550008C7DDEBB1AECECA21A632DB1B7B589C4C1
+:109560000F301AF5FE903C89AB1095BFE3355426B9
+:10957000E37A2501EA2F2FAABC793DB493424BFD33
+:10958000C0EF3952C224FD7F8DCAE15D62A253054E
+:10959000B91C2E24F8DD15A674613E3C91D0C57E21
+:1095A00071EED560173509ABDB5E05BC66169273AC
+:1095B000AEF07E23AC9FE1B3418BAA80BFFD0C9F30
+:1095C000D25ED1847C4DFE7E9B70FB5A80EB3BFECD
+:1095D0008DF3550CD71CAFD1320CE3E16DFFC6A65D
+:1095E000C82C828742157F7FBBEDDE2615E365FF21
+:1095F00066234FB394C7FF054B752207EE257CDD2C
+:10960000187C741D2821FCFD65F07F3C99C5F99EEE
+:109610007E2F2AEC952306D8A50D664AAEA8582FB2
+:109620001459EA9763B9F0CDC72482D7C3783C9028
+:1096300013781D26D07DCF0499D8057E3C173F2E88
+:10964000FB2715927C5BBC6EE407BB61924CF43C3B
+:109650008FE32813446237437DA0077F6E21C99FA3
+:10966000C3F23A06E77CA4088DEB48D21E03F33020
+:109670000AB0FC7D415B44EE17F1155BF20A40FE37
+:109680003AF210244779ACB73B17CE2B659F5C2488
+:109690008CC67839ED6771996CBC8FC5EF7FEDA7EB
+:1096A000E71BEF8F993740BE0CD2BB73693C2A365B
+:1096B000159E236E2B1AD19FFFA5EF7E354AEC979E
+:1096C00047F265D77CB0E702745FE41D5544EECBEA
+:1096D000A84398FF812FF8FD2A4C7E7898BDE03C86
+:1096E00027C0E5892793AEB1B675DE88AC60EA1C69
+:1096F0009C143454900707B5A919608FEA01CAEF8A
+:109700008DC9599F05BB4566F2608F8F9E8FEDC94D
+:10971000449DFB10D8BF5164CD4BE0F2607BBD4A45
+:109720009E4FCC1947E2974FCCC9990BF18A43D78A
+:10973000BE47F6BF17F750FEBD78E465B823095D54
+:1097400034E9F95C202BE2974F3E42EE01F9861C8A
+:10975000DB49F2E5215F074F6967A63D0FF38900FA
+:10976000F59BFE89C927ACB7C9777E3F877CF91383
+:10977000C40FBC95C95D355E4EF695E0C6D3812E0B
+:10978000503BB96789C3C1792F877C793269FF273C
+:109790003F853FCF5F72E629F1F9FC80CDA7EF7DD1
+:1097A000AE767C70BF06C7036F5F2B1823B47EE8CC
+:1097B000A6FAB2841296BC90D4B90D85BCBF00E75E
+:1097C0005D32E05E9578FB7505C007096227FA8275
+:1097D0008DB6FB595144EEB19E2F0938CEBB38F9F6
+:1097E00005EE05063DADE8FD9F6BF935DEE6F2BC02
+:1097F0005C92A72EA3AF825D7B3EF0E60CF0C755CE
+:10980000633101AE72249BE43CE905B62F919FBF02
+:10981000979CE7E1F3E3FE385EAE3AB088F8E9AA38
+:10982000F707C9799EAA0495831B54F3B057B4E691
+:10983000DD1A49C8B7F51CA0FDE980038C8F3F688D
+:109840006B7261FD81BA3133E19C498E5873D568E2
+:10985000808F4CF100FBE56783E49CAE0C7A9C8F13
+:10986000FB4BB60F5CC6EC9100324580A7E48F76C7
+:10987000237A66D190B17D24F5CABDAB9B801F765B
+:1098800039ECAD5D7E5ADEBCEDEAA646AA9F895C46
+:109890005CD6F62FC41E6AF2F1F273444EEE52DA31
+:1098A000932027CDE7BC3AE83DDC9E9C63376F2DC3
+:1098B00026FA432A447900B77270B480FC7BCEBB91
+:1098C0000FFC0C4FFAE231BF65BF733E746234EC9B
+:1098D0002B5DFA336DFD8D1E5A7F78FC2EC003FF81
+:1098E0005E1EDE4DFAC7ED88BF03E51F7913DBBAB4
+:1098F00028E7392F3967B8C763B7B7F97337933398
+:109900002D8E7B39D478A3019B73CE9FCEFB9339E8
+:10991000BFCA9727D8F2A474A69F65D9005725FE21
+:109920003E917CFF939FD2410BCBC7493F4E569A45
+:1099300071EC71BBBEE3CC60720231FE97B5DEFB09
+:1099400036FBC97F75C6179DF28D3FB97CCB0E5093
+:10995000FE8A09F1AE001E675DA273819FF2E76483
+:10996000E0CF3B995E2AEE78E84550EBDF528DF769
+:10997000013F2B55636C60F8D0F9E70D369E8BFCE8
+:10998000A276D91A6AE7D6B64EFB14946B77146A9E
+:10999000A64BBC883FD75C0ED8E4D70EBFCEEE45B1
+:1099A00034891C5B73394CBE7F74E3F96CE7D9FAD8
+:1099B0008E1724DFF978F738E4F3A16BFF6D572990
+:1099C000A6E3DA673CA2D7324EED33EC1C900FCB06
+:1099D0006B3BBF1BC0EF7201EACD5304F9B053617A
+:1099E000651335835DF4A4553E9482DD966A0FF7C6
+:1099F00011EEF4F3F6BEE6F27C97FA0147FD42DE83
+:109A00007F26E9DF391F2E7FA00C769AFC172F9F47
+:109A10001F915F0F898EFEB2F8F879A43F6EAF7F79
+:109A2000A1ADF01553063A4D948DA4FE1D1DEC809A
+:109A30006FC851BFF59EAB2FF8A9DC5C73798C0D14
+:109A4000DF29B88FB3BDFF4D7DC496AF7F77BC963D
+:109A50009CD3F802F327AEC1163D69B767A42D4F1A
+:109A6000FF1FF3F8A0F3B82ECD3CE6FC8DE7516064
+:109A7000E3CFD43C8A6CEF3FE83C7EE0A3F2F805EC
+:109A8000F69CAFD17B01E6EB02F15BCFC7757D9809
+:109A9000D66FC04F153FE7CBC80C92FB6B13B43E9B
+:109AA0002E833FE0B37FB9EF9DEBC97DCF06C9C7D9
+:109AB000E1F74EF1FB1007BA9FC8F9771B9CDF0353
+:109AC00069EE5FFD6290C2E9A129372192BF1E8C29
+:109AD0009338C1C1DC0511B0D3BF32A58A3C1B73DA
+:109AE0006744401E35843E67CB37C77B04D773B0CD
+:109AF000EFB17ED1E51B44EB7994AD701EC5A53E58
+:109B00008F8B6D55F9FD801FCF7A777F4CEB2D0D34
+:109B100051FDB9558D93B86073E4E399FFB3413AB1
+:109B2000CE4353E6203ADF39491AF75174EB796096
+:109B3000FE3C189A11817536642E88003D3766CE3A
+:109B4000B0AD474AB39E957C3DDAC7BB9E7FEFC55B
+:109B5000C7075DCF02D73C5839DBFDDEF9C6101DC3
+:109B60006F6B244EE8ECE35AD7990F8DA7A1AD2B6C
+:109B70008BADEB8E20DD476CD5291F05A4D87F1453
+:109B80000803F3E1407F4F0415E9E260F2F07EC57F
+:109B9000E0958E7F6FF52486C3BC4ED4D3FDF36B66
+:109BA000EC3EA95FAD690811BFB6639CADF9FB42FD
+:109BB000FDF939FED71AFBF9F481E48619A471A0E6
+:109BC0005BE2F676CB2B03AEF79B60F8ED2C2848D2
+:109BD000C1B30FFE3F62B8A5A3C7A1C2AD393234ED
+:109BE000B80DC40777C0253783801BA7B774FDFC69
+:109BF000FF4267BB83D46E1804BC087DFDADE0F561
+:109C0000F74A5FCF0E9EBEFE012FA23707475F5C6B
+:109C10008E7528F49E45673FEF84E83D9BE3859A67
+:109C20006337427CE13312F1F71EDB53BE0189D664
+:109C30007A54BF1CAB98B781E4BBC60208EECF3A9A
+:109C40002E46FFBD04E20E8B693B67FFC7187C5EA2
+:109C50000E65B27DBE3E1CFC08C7634BFA5D1FAAB1
+:109C6000B0AC8BE4655AEEA392FAC2F718D277949F
+:109C700080BF69A1FB3C383ED38D3B547C1E8F7D59
+:109C80006348F81C68BD5DA1C1EAA504C14336EA7A
+:109C9000FD3B1857033C3B449ACF710A5ECD82FBD3
+:109CA000C910A9B4BC7204B9E76C4A98E53D29FA19
+:109CB00006F09379972CDC16C2783BBE2C53B0DEAD
+:109CC0007F2686A9DD326385BB5D9811A674906AF4
+:109CD0002FA0F17ADF7A7F65F6E3B215F45E2A24CD
+:109CE0001BA3165BCED54D08DBBF3BDB47C2613201
+:109CF000CE71C1FD7E583F9BC7F2A5FDB747B5C3E6
+:109D0000D8E16D6D92DBFD829C3FFE4F283E2C8C8E
+:109D1000EBBF26C4BFFE79A0A309411AF7905101F9
+:109D2000C4EB793FD9324A2A18EEEF78B449E0A75C
+:109D300075E927BFBF7ED2C195AF878F03AC08F707
+:109D4000B2E0FD23D92F961808CD867DA2377A2F51
+:109D50003D6C48E9208BE5CFCCAC092436839D27A8
+:109D6000E3755AE6DBF5A7799F86EF5DC7446D4B37
+:109D7000415F380C241FCAC234DE902DC5B7F8C02D
+:109D80003FB64A70BDDFECDA30FDFB23E742BD7120
+:109D9000F55130CEB847E31EB8E7E06696DF845051
+:109DA0007CD422CBF8E7189D38DB654B341E8D5EE2
+:109DB000A7FCDCB16FDD2837FEF939E3D373A1626C
+:109DC0005B1ECED2D8BD1EE0CFA50B1779F4207C48
+:109DD000D729BDB1797428F151D70453704A2B8724
+:109DE000187CBA4EC41BE07E8755750289234DDC72
+:109DF00044E96ED5A683E206FCDCCBF86F91806C5B
+:109E00007990F730BC76ECF38F86F977703F1D744C
+:109E10008CE7B17237227EAF3B1FFCF456B84BB5CE
+:109E20005B40CC4F76A002F20DBA599E8889BF6F75
+:109E300006F8950F27F31DB7E9FD5A90CF5D0A226A
+:109E4000E7E5FEB3D54BFE6E05A7975E39B1E95243
+:109E50003D24DD3DA2242701DD0C6FA8F9BC9B9FAA
+:109E6000FC0136CF3F0463196E762E7F7279CEEBFC
+:109E70002D96758F5BFD25157639C6E73DCC9B3C4D
+:109E8000EF765F432F1D26FAD77BBF60729CE3BD40
+:109E900017DF27DCF7455F6172AF2331773DD15B78
+:109EA000A6570779C8E7C3E1956D5238DDBC54B2B7
+:109EB000C9DB550B038EF34814AE9FF5EA8FC13A08
+:109EC0001ED9F76F93000F4EFDE097E20A7CBF1B8F
+:109ED000253D2027CE483A79BE566FBF47FA351444
+:109EE000DF311DF4679DE4CA57CF32BCBC5679C739
+:109EF0003232FF464983F99F5E31ECA652902F958E
+:109F00009E28E44F9E6EBC2F749765FD5CDF39E799
+:109F1000F5AB3577F4ABB79657DAF1D6A150BBC0A5
+:109F2000FC14E5C3B558DECC26F4D5BD63261EFF70
+:109F30005822EB9A365A1DC1DF695CC27E3F23C6A8
+:109F40001F9C89E5CD5991FAC3CC7FA27263E9A326
+:109F5000B12688F39EAD9BF64237AEF713A607DE17
+:109F6000ACEB5F3F3AE969DCA3F6FB29679C400A4A
+:109F7000B48FD7BAEB835B32034CBE4447837CB9C2
+:109F80006D937BBD7F86E44A0CEFB37F95D6B8E531
+:109F90006D5ED6E87C57C5DCDB5FD642F43BE82536
+:109FA00017387F2F2340E5BCAC8D0639BD2ACD7C08
+:109FB000BF9B1126FDBCDD74FF6D10EF3B23DAE57E
+:109FC000F3DE0C4A17F519543E9FDD77AB6738E096
+:109FD000A959D0801EDECA8C4E007A5BDD789AF8D3
+:109FE00011FE89D5AF0CC67E171E0EFCB278FE702E
+:109FF0008C97AE15282AE8E9E5FF25C63FD912BDA2
+:10A00000C700EBBF7740FFE1A6EF10FB433646DF0A
+:10A0100032895ED90879856745731DC943D9E7A799
+:10A020007947283ADD7ABF8C2783C2EFECFEA1E1A5
+:10A030007B592CD0AF1D7F0CB5579171F707348831
+:10A040003F1EAB9092D7E349BEBB3FB0572AE8CB47
+:10A0500017E9C61FAA1D7876FFD0ECC081D6FD890E
+:10A060008C8241D9F5172B1E79B004F848699FEC12
+:10A07000267FB99C3ECEFC564EFAE1CF998C2ECE6F
+:10A0800024FA9FD7DDBBEDF3B9ADC63E1FCE2F67D7
+:10A09000120D7EC80FC7A34FB2DAA5A87CFA00E75D
+:10A0A0001CA8FF37DD3C3F9D6197134079104F5B43
+:10A0B000CBE4CD9B758F84AD7870AEFFACC8F6074E
+:10A0C0008FD1BCADB1B1D57387EB29FAAC6470F810
+:10A0D000A8E992EB19673F7FEF74C8F5DC4074C8BC
+:10A0E000E582B3FD3988F3E3A5AF963505E232E7A3
+:10A0F000C23A2D236D011C9141A5ECDC32D247C33D
+:10A10000B99BB3FBFC08FECEA6D9E64D8CC52C70DE
+:10A1100066DF7513ACEBF90AC3CFAAA59970AD0D34
+:10A12000A693E88D23487E8144EEEB7AED44D60277
+:10A13000283F724404098D6EAB5D2DC1FA1ECDA07F
+:10A14000FBCE559B8E127B70A874BEAAC6AEFF2FA5
+:10A15000B375F4DA59724F09D04F3A383466503833
+:10A160002C8B2D9A0FF2F98E4D0291B74D193AF5BD
+:10A17000D7CA0691DBA891EA47A462786015721AE3
+:10A180001601F0F832FBFB63724CB19E4FBA6BFBC9
+:10A19000FDF3C13E74F24B0ED34F481399BC8F7F31
+:10A1A0003B637A4A3EBF25D41C1C81AB5C9BA1F16A
+:10A1B000FB61099FF2F55C9B41D787EDB46F93BFBC
+:10A1C000BBC4D687A20E7A13DBAB7E04F09FAB1222
+:10A1D000BBC0EFC5721FF2E6BEE1D768DE1CE52BFF
+:10A1E0006EEF38DBDF2CC76D76E3FF05B9373CBD7A
+:10A1F0001DF20F7DE15EFF7D06B7BF95BEF8CB4730
+:10A20000A42F8E86759B9DC5F5C6FF03C8D629333E
+:10A2100000800000000000001F8B0800000000000C
+:10A22000000BDD7D0D7854D5B5E83E73664E669221
+:10A23000996492CCE41F9C49000324780221444095
+:10A2400098240482609D408060030E081A2584A82B
+:10A250005879AFDCE684440C14BDF1E7AAB55EEF93
+:10A2600010D0F25ABC0D965A54DA8E54507BF53603
+:10A27000F88BFDA2466B292085E8AB57DB8F5BDEB0
+:10A280005AFB2773CEC94C08DAF6F2BDF0F19DEC0B
+:10A29000B3F7D93FEB7FADBDF6CE098B3A3FD34341
+:10A2A00088B655264F10423E3CF65935961FE8B504
+:10A2B000B82528AFD8B84A0E390949C692979013E5
+:10A2C000E1C529583E8F3FB3873E6F7A44269142BD
+:10A2D000427FCEC3FFEB5B920CE513DD890182E385
+:10A2E000CD7285C7FA09D9AF108D9412F2C1B6CCE0
+:10A2F000F0162857DB89E69C4CC8F4141F1DCFB319
+:10A30000F98B56F724984FF77F14937C98DF3D77AD
+:10A31000AE08150D1DF72F6E0B215361009FCF4224
+:10A320003208B9C3CEC65C9D4C02D83F81F19ED0A5
+:10A33000F52FBE7BBB9590C8E5503F06BE2B8B7EAC
+:10A3400067EE7FE975578EC675BF7DDD8CD1AB8A10
+:10A35000A2DFC583C35229F42F4B70DC365945B8B0
+:10A36000EEB937A1B13B06DCBE8D709D3A747CFC22
+:10A37000B1C23A16F3DF976CAEB8CB0520D9923450
+:10A38000EBAA508CF1DF26A17BA6C278DA66369E56
+:10A39000799C6BF8386FD7DFB004E1FFB926BB6555
+:10A3A00080477F839C5C8EDFD5DBD4B1D07FBF76C6
+:10A3B000BB6BAD6E9EBF8D039FDF36DEE08A8507E7
+:10A3C000F15C566FA4830FC8C06BD3709CDDB1E7FE
+:10A3D000B75ED09712BAF74A98DFC9AB655583F9D3
+:10A3E0009CB4C077482F8FC277BEA1DFADE2DF7D7E
+:10A3F000B07978BA5C5C639CCF92638946BAB490BA
+:10A40000C69E18EB59FF15E97E05D2BD3D5ADEA365
+:10A410000C8C72C3F71FEC3CF7DE9DB89E9D89142F
+:10A42000DEE67E9253653ADE49E41384D7F604CE25
+:10A43000275DCDCFC1771F5C93A36E2143F9839035
+:10A44000AE6F4C87FABE6E4BC976A8DAD39DD4188E
+:10A450008E31DFF1A98C0E3CB2963801DA93771871
+:10A460003E90DC906F96707A7377FFB08558A2DFCC
+:10A47000BD83749040C81BAD76FADCE1B6D3F1EB36
+:10A4800016D62A3E1867AD9504107EF407FA754F6C
+:10A49000C8DBB91D867ACBC2CADA6AE03F69E87CBC
+:10A4A000BEC7E9724F78D1B0F0AD6F900DF0AC5BE4
+:10A4B0006884AF993E8F872D35B1D62FE839DE7885
+:10A4C000D7D9C25EC4D331BEDEB7F97A7FDBD8EE0E
+:10A4D000C2F6E671F684BB87E5836F361AE9E2427D
+:10A4E000EB3CE6F653B82E0F19BF5B566F5CEF12CC
+:10A4F000D272150152594A541B3EEB484BF173007E
+:10A50000CAE38F2CA6F3798B909A1E9CEFB9DB8B54
+:10A510006B8BA3FD1FE6F0FEBCEEF66B50ECBCA30C
+:10A52000B414BB63CCE72D0E2781EFB7E2C0F379FB
+:10A530002E77DF413C23BD2E9563E2F96DCE47EFC8
+:10A54000340CCF474BEB86C7F3EFDD6EDE4F7B223B
+:10A55000AEF38418F75136EE89307B2FFAFBFDDF1E
+:10A56000887FFB89760BA5E370A21BF58807C9439A
+:10A57000A7475A53B9FE291C5E8F88E71B42AE9A43
+:10A58000DAD75903363D3E4ADC8CCF45B96EA1710E
+:10A590009EEF27BBD9B8C43D3AE8D2C90DAE5F855E
+:10A5A000BE7BE0C989EFA3FEF471FEAF0B7E6A4368
+:10A5B00078807CBDCB85EB7ADDE246F95A762C605B
+:10A5C000D3C3EFCA1406BF93BB8787DF955C1E5DBC
+:10A5D00048CE9AD7FBC13FDD3D19FBFDE09FBEB0E1
+:10A5E000E9FB5FFA652E89A447CBD7D74B81700C66
+:10A5F0003EBBDDAD8C08EEB79BE078FD97A369FF0D
+:10A600001E99B4F4C45A17CA37E87749B0C2E605B0
+:10A6100078DEB0595225E882A4B27E6E10F2CEEAFE
+:10A620001B5D0B70F7B6B7DC118CD14F3987F79FE4
+:10A630009CC194587C36C81F9C1E44BBA5D6902D47
+:10A64000567BB35EEDE77C6E6EB700E9D13B727A64
+:10A650001CB4834CED473A8FE9298C2FD313227F0A
+:10A660004479448A8C76D805C735B5378F3B1FE1CE
+:10A670003E35FEF827FF2A37C682C3B75319FD8639
+:10A6800082403F31EB5DB4FE75C2F4AB164EA2FAC8
+:10A69000F0C4EE1BEE45F3EDC6F9771C4135F972B7
+:10A6A000B29F8EDF103C5A8D6025E71E988478FF9C
+:10A6B000BCE6817B4B616A279550BB0B3E38B945A0
+:10A6C000A2768B799CD7B93E7913E5E9E5D81F616D
+:10A6D000743B077ACB06B0CB81752854C8B7137C7E
+:10A6E0007A3BD5B3E98B563209ED87E01617BC1FCC
+:10A6F000B7F9D38DA8970909D3EF3FB2A93753789B
+:10A700001366E7F6753B776E8776AF25337C10A22C
+:10A710008E0E16EBE484D54DCB23C5CF1B71F073A1
+:10A72000B1724AAC33DE380079FA7D6D95B353BA15
+:10A7300002ED1DF71D088F816A97BB1BD6539B1036
+:10A740005880EB3BFABAC5D2E6A7DD527B6511FE15
+:10A750000643FBAFF67F17ED99450BE58003CA7DF5
+:10A76000F81EC65B52E9D4A41450116F2CFC11E200
+:10A77000E781BA049F0C24513BDBFD4719DAD7CEA1
+:10A780004BF26D8172596F7E9B07EAEB6A2437F6B4
+:10A79000F7E2C229AE7E585FD226E827073B3B5E30
+:10A7A000533586901FE2AFD3099B30C0E20D22EAF9
+:10A7B000D3B6CD017930C1BBDFE204508F494BDB0A
+:10A7C000668779DED516CC72A742BBFB4E74DAAF32
+:10A7D00022242323D03B5B2524E1FE5335F651B0E0
+:10A7E000CE47797FDA279D8199A04F2D21BF04F5AF
+:10A7F00093EEB7CEB75E09F82F10FD676DC3FA254B
+:10A800007357ACDD0FF5756913E65BA1FFB2063136
+:10A810009F2BE65759E1FD4CD1BED481F3F5248935
+:10A8200032CCB79C105B7E74FED62C183F4D94CB77
+:10A83000E7CF816FDFAA68A9B242FF7BD2666D2B9A
+:10A84000721032ADA6C21D80F53C75FF92F94940E9
+:10A850003FFB09D029D4EFBB7FD97C9CBF47B6B062
+:10A86000FEB57A3ABFB2066D02D64BA4615B0DAC61
+:10A870007BBDBDFF0892EB864D9A3D037E49921841
+:10A880009DD86D2D815C80BBED404524974EA78BF4
+:10A89000D1675EA418F5D860B910CAC5BA72162B74
+:10A8A000EFDF42AE8F256F5BD299DCDB9F18BB5E7A
+:10A8B0004A63F218E046F549CA3112D81B43AF9CEF
+:10A8C0004875D276871389664F8BF2DBB5C0C3E536
+:10A8D000C097C4CEE629FA1942D75CEE10EDDA34FF
+:10A8E00094A70B399D16A812F577494B52782C3A4C
+:10A8F000D824625D8C2248B6D0F97A65E9FA5AE824
+:10A900002F239184F6C1D39B4E6819BE0FEC73467A
+:10A91000FB7B95B116A92E08EEC6FEAA33B34BDA1F
+:10A92000FDD17E60DE1DF6C986795BCBD3B07E514A
+:10A93000C9AD453A7816B175001DD0EF60981FCDAE
+:10A9400006BED8DF3B211FEDF7A7538D7C5DD65B9C
+:10A950006923F0FD92742E4F7CEC7B6F15933F03BF
+:10A96000B72685915F895D2D09EAECCEDC34068F30
+:10A97000AABB173E8CED9A7A6D2401DA6DDC5791F3
+:10A980004986D18B4D5FCE20E129BAB235A2A0DC39
+:10A9900069FA72167D5F75F7AB0AF229F6E38379DF
+:10A9A0006D74043255845B7B6CFC83434EE7DDF4AD
+:10A9B000652AD1A6E8DF333845FBF7D0FA0BAD2B7B
+:10A9C000DA9F4CC2E9C3F5A7D0FA41B85B39DC95F0
+:10A9D000D8F3ACE4F042785B74F575486F4E2AFD0D
+:10A9E000681CA5EF1B45DD28EFA3E36EA1FDEFB7C3
+:10A9F000021ED10EEC4DF4A15D5C6605F9E9C1FEC5
+:10AA0000D2DC9A14A50F411702AFFBD35A2AE87A79
+:10AA1000AF91DCDD31ECF8F9827F16327B2CB3216B
+:10AA200024AFD2D1BFE007E87F3FEFBFB49CF2CFA5
+:10AA3000BF327E00BE5981FC8B760BD2A11A295EF3
+:10AA4000E41A3AFF674076607BC02383FF35CE303F
+:10AA5000CE47C06D28FC732F80CFD1B4BEACF79029
+:10AA600082F4D614876F17A427D3EF328F4592D183
+:10AA7000AF7D8EDB1DFB7BA63866205F2CB41014E7
+:10AA800061B86EB457CB660AF9FDC42B95207F33AD
+:10AA90004519E5AD0FF130287F23767BB4FD550FC6
+:10AAA0003C31BF03E57302E0BF88DAA176A2F32749
+:10AAB00036A53139561E2231ED96DA7466B708781C
+:10AAC0007F6F5315F91DACEF502AE3CBF27E4D5A40
+:10AAD0005514E56BB39C7A98E3F141FEFCC7CB2992
+:10AAE000E90272AA96CB29F6FE3098F9D82E2323D4
+:10AAF000522C814E5CFDCA94B1E8CFDC9625FB3E1A
+:10AB000006BE5A2CA9A39E827EEBEC3E1A27137434
+:10AB10005247EC3E27C21D8CA6F312DA070E5AC626
+:10AB20001FB44B3EEB92181D125F4A5D717C3924B5
+:10AB3000E6715B9642C75BBD6D6C4A483F3FAE27EE
+:10AB4000AE4D883C450A86F2B928C3FCD75B645DEC
+:10AB5000BD93E9B33FB8024FA741F9288F43812243
+:10AB600003A72A3AFEAFB93E31DB4B8B93399FA046
+:10AB70007949F9D8429DD3CCCE8430619F68E8A74B
+:10AB800066F6303ACA6C88589A747470242D8F36E1
+:10AB90006A5806956077D5D8AB021FEBE4D8CB1284
+:10ABA000A9A7710412998A7CFA521A31CCA3410EDA
+:10ABB000E64968B76626A82867004F140E871DC4AB
+:10ABC000EA80715F8227E2AD5ABEF5059B07E94036
+:10ABD00052DB29F47772FB944450DF5C3B3B89DA0B
+:10ABE000ADE4DCED63305EE14D62740BFDD8793F7E
+:10ABF000764A275CEEFD66F4F86ED44F427E0A3C3E
+:10AC0000907332ED4FD41F966AF3DC503EECBDBC1E
+:10AC1000A45D32DA3F680F45EDA7DBB6CDB3A2BD28
+:10AC2000D313B1000BB5691BE7DF897638D84F0E17
+:10AC300058CF47694C0F1EF66B7232F63716D601A5
+:10AC4000AF8E24868A5A9C517C808D1342FC6528E5
+:10AC5000F07432FEC0675B3AE33397873D97F16744
+:10AC600046326B6FA6B79B787D00790F9EDB2B98E1
+:10AC70009C30B7FB6FCEBFEBED5A4D46BEDEBE0A31
+:10AC800012A4432B6176D65F39DE409F517855DDA3
+:10AC9000DD90827AF3F3DE2529A4282A476DF63762
+:10ACA000467F0C72244216FF33F2ABF2964CD05E14
+:10ACB000BECB067400ED94D4903B0D9EE949B1FDE6
+:10ACC000E6317C9DE9E85743BB7BB9DF63FB722229
+:10ACD000F5B733B87D969C5547E53AC2D207704E1A
+:10ACE00021039A5B87C794728BC17FB07D39897EBF
+:10ACF0007FF1F643491CFBA1D4603F8871CD76C437
+:10AD00007BAD5974FEE2FB15596F56135DFB95A49C
+:10AD1000FF2EEC6FE5C65C43BC289EFD319DC3074A
+:10AD2000ED052DE6BC14C3FBF7C05FD4F4E39F60D0
+:10AD3000E347C74D02868B8EFBD7B4C08C741A0FC5
+:10AD40009AE93E3E111E60C39F97A9DE61FA1A9EE2
+:10AD50003B9D542FD5A0DC167E12F2BF3B05F9BBFC
+:10AD6000A22ADDABD393FC3BB33C3AC8E31A07B944
+:10AD7000BE493926ECC6449F2445F5CE50BDC5EDED
+:10AD800062937CBC909D0D74ABE9ED8021FC92FE3A
+:10AD900055EDCB8238F431EE1F625F96CD0CC9C5FC
+:10ADA000283F6B2432161ED3E618F5FDB7D39D74E9
+:10ADB0005DDF0686D3FB2D8B1A8CED5AD399BFD25B
+:10ADC0008AEDBC1786A75E1F4932CA3DD65F33CADB
+:10ADD0001BC0B3FFD4EB8A0FE4F0F3DC1EDAE50905
+:10ADE0006C45BAE8484C9E847AA223717418E31229
+:10ADF0003BFFBBAA7027FAE9AFD9D46EECF600F39B
+:10AE0000F32B966F6CB7C27B5B8FE44E20D1793AFF
+:10AE100037498135404AF7737C3579D87A9A3C11A5
+:10AE2000650C8C9FD3C4E691D7F38264D5C9BBBCB3
+:10AE300046D6EEB1749B41FF8479F9F17411EF08A5
+:10AE4000B7559762FB8015F741727A241A1FCE69B5
+:10AE50000140003DE4A8AC7FA71A966E288AAEB7E1
+:10AE6000D3525B847AA2332349453D71CA137A12C7
+:10AE7000F9A8A92F1241704DEBEBB5A2BD67F506FD
+:10AE80007E807010EBF4C9EE1C94B3497D6C7E5D3E
+:10AE900026BA27E4BB3C3EDBCDE4AF4C5E268817E8
+:10AEA0009421305EC69642AAA744FB8C34AE37325A
+:10AEB00048E8696A67914E42F146E83A32B68CA397
+:10AEC000F6BEC06BD4AE1A3F19EDAA821D11EB6A13
+:10AED000B45B1F8B1DAF3FCCE50FAC2342E5C481B3
+:10AEE00091C565443B5B1CBF5AD07D524D6C7B15B0
+:10AEF0003401ADAF58EEB90ED7DDD4A19004290AC4
+:10AF00007FAB37F806CE27A767A784B031D3594760
+:10AF1000DA0FA55C58E7ED3713B74CE2CFBB699366
+:10AF20001C58A3E7E70E85E265A762DCDF137EC647
+:10AF300069AE8FCABDC1DFE1F8CD07EE5310CF3740
+:10AF4000EFFE50196E5F67A470931A99FFD2546F89
+:10AF50000FE37A2B965B291ED7752861944F4D7BA2
+:10AF6000F7452C68676F262AF27F53CFBE2339003E
+:10AF70009FDCA6C054D9A7F39F9BC212CE2703889B
+:10AF8000B1B788CA4D05F5B699BED14E467BE58866
+:10AF900083F1FFE90AA786F1B4D3B65013B63B9DFF
+:10AFA0009DA46AFE28DC5FDA37EF650958DCF5748A
+:10AFB00042049F9D96EE2C3BB4EB9CA0A8484F56B4
+:10AFC0006FC8EE8175A45983FBF1FB548F4B6D83E1
+:10AFD0006F7D096432D5D72384C334135D4CDBCC39
+:10AFE000F865BA2759D88193512EE57B5CC28EA2B1
+:10AFF000F2EA888DADA383B0F9B6A507323D48B714
+:10B00000EE343A6E4E5344423FC03C6E94AE02A3BF
+:10B010003CDE8B99678F82727E1D973715CB774BFD
+:10B02000BFD3D1419187EDCFE6ECDD29A17F08F5B3
+:10B030006DD51EDA9E24A0BCD9CBFCE27550BF565C
+:10B04000275FC43A62C89929383F675FEF8B4CCEBF
+:10B050004428FD89F99AF139DBC3ECBBB96026D0ED
+:10B06000F78A56E883FE8EE427D2FE04DF9BF9744C
+:10B07000B687D1794EFD6EC95244E382D49E14F353
+:10B0800013ED76792AAB3C140EBD140EEBEBAD2C10
+:10B09000DEC0E753AD04C7A05F56EB61FB5D87964A
+:10B0A000BDAFF443F9C19F1DA5F4B8BE4B0A507F54
+:10B0B000A1EBA8B204E376DAFF91314EBB80992868
+:10B0C000E4A19F1EA57A65C17E168F5FBF7F9FF5A5
+:10B0D0000667944EFDA70EAD443A5BDF93401C1209
+:10B0E000E28FADD74CA7206728DD134DA1FB5C2074
+:10B0F00027352A5749C88F7E8A90C36DE97C5FCE79
+:10B10000C9DEAFE1F316FD46E5A783D2BBFFD4E469
+:10B11000437680E77A5552C174023BDC47DB43FF3C
+:10B12000112A878144D15F13FD9BE1D7E5617A2D18
+:10B13000069E5B3C31F489D0B3FEC72B093E05FE69
+:10B14000AC1CEE83FADDA3D07E5B3D563A9F8E0A9F
+:10B1500016D7EEB0313DD2D1660F235FBF943AF7D8
+:10B160006509E4A52B4D89E0F3B0657513D61FCEB4
+:10B1700061F3E8B46C296C617A4CF350FC2513261A
+:10B180009F983C7AF0274C9E34694EEA3F3685EA18
+:10B19000D6D07D098F43C57D09127A5159E28AD2F2
+:10B1A0008319BFBEA75F507C50BFA087F141146ECA
+:10B1B0004C5F09BA053947F1DE26E2888037842BD7
+:10B1C000F8F56D187F107E7D72435073F986F26B2F
+:10B1D0003AF7EBA772BFDE566EFF9BFAF5EB36FD32
+:10B1E00007F5836EC97A853E05BF80FF68E0ABA78F
+:10B1F000B89F763F7FEEE7FCB9AEB487F2C3BA8F53
+:10B200005B281F396B983C71F619E52021F7F0F5A2
+:10B21000EF60F498D43317F725AAFF4D72B793F86F
+:10B22000F3BE496AF94FCC9321FB78FEC639B0F2E0
+:10B23000CB00AE0E0E03DEEE08E7FBD37B0011C899
+:10B2400097D61665387BF842FD92C89B12E27B1DAB
+:10B2500087F5E9BD5557FE1EE38C7B52683ECB2730
+:10B260007B17FFAFDFC3F7A777CF56514F7BDA834A
+:10B27000947E06BC0E15E3A7203E6B24A087B69EE5
+:10B280005F25CFC0FDB21F5D3119E5E67B7C9EA72F
+:10B290007E226F42F86CF9C18F6761FDBAB0948E5F
+:10B2A000F6E3E93DFFF657D48B8DBB37D0BCB4F63F
+:10B2B0001FFD92DAE596F04EF67E4F0AB5334FEE5B
+:10B2C000BA6F16C2BDBDA79DD69FDAB593960FFD86
+:10B2D000E0C7BFF80BDA1DC16415DB9DFAC97DDF3D
+:10B2E000F90BD2795DB28AEB680A59D97EAEA06FAC
+:10B2F000B3DCDAF702E553412F0B50EF229CEA99B9
+:10B30000FC11F4FC11DF6F5ACDF7B13EDAEE6A8C16
+:10B31000156794BC6CBD188BA172AC5EA271B64E61
+:10B32000A01A8C77742692727C261545945C186757
+:10B3300059C3BE59D4EED13EBC11DB2F3EE020DB19
+:10B34000695C0E83BAD17DB0621083C7C16F86DE9F
+:10B35000779F07BA7D1BE403D53B267F6071E72BFF
+:10B360007F46395A67EF7F0145A178DFC9E337D0BF
+:10B370009EEA9DB28DB1E3A40EAF93EB6DA6377339
+:10B38000F6D7E6F9A89C4850C7EAECD351C75AB69D
+:10B39000637A524E63EF5C5CC7D585ABA650BAC0EA
+:10B3A000F81FEA1FCD49FB5F8FF14BE0BF1C2F93C5
+:10B3B0009F196EE2990EE3575B89C7894F42DEB44D
+:10B3C0005139F204ED17EC0F6A57F97EB9EC09B464
+:10B3D000471EB285B2A7623F9D5C6FED66F386EFB4
+:10B3E000DDB88F0AFDB9A74FA6FDF4DAD2E8F71A47
+:10B3F000FB7EDEEE36293A5FA0D4D1A8B7B0BF52AB
+:10B4000027EA19AD9EE2C7A7D0759DC226D974DD83
+:10B4100093561447F9D71CF7417986FBC3E5DE8ABA
+:10B42000295E6FF429E2416678DE89F5D0CF33DEFC
+:10B43000007D923D467F3B9EBD7268D919A67F9FD5
+:10B44000FF90CA9B66A4631C3FF4B141FFDE20E875
+:10B45000F8D90F291DDF7080E9DFE603250AD2ED58
+:10B4600027AD01F23B30409B2B816E817E1F92FA0B
+:10B470006FA4F92ECF3ADC18D73BC3F5CDBA1D1F08
+:10B480001E97011EF907B2A99F7FE659473DF67343
+:10B49000D862A1F03CDC3D7167BBA49F27F30BC0D1
+:10B4A0000EA6A4DA0C762AB383D7DC877EDAFA46B6
+:10B4B000A222FF379BE8A7F9C0514A2FC20EF63FE0
+:10B4C000BE680DB33F1DAA03FDB839CC1E25608FA1
+:10B4D00062FBD439E13685D2574919D2D7A165BF6D
+:10B4E000D88A7ABC790E7163FF0F8D0A3C9B4BD7CB
+:10B4F0002311CC7379C8D6556985EF1FAAF6B90117
+:10B500009200B7DDD4EE25850AD7736BA8BDDC9C0D
+:10B51000F54D95F299591E3CDB46EDAE665F229DD6
+:10B52000CF8203D26DCC1E7112367F89D2E782F0B2
+:10B530008C30C6CFFEC8E127E078C6D6BB12E171D9
+:10B54000E6A7408850BF600EA3D7D4393D548EBCC7
+:10B55000F4EC3CAAC7055DBA9E49A0FA3CCDEA9638
+:10B5600054AAD71627E8F1DA65637A2995EB998210
+:10B570001D0CBF6D5EA697DABC16FE548CF117B792
+:10B580003609F5EE1F39FEA91841F9CEE5C9FA359D
+:10B5900011CA4F4D7B597F9E8440C9ED3AFAF5544C
+:10B5A00031BD28F603707FA03686BC7892CFC3FFEA
+:10B5B000F8EAFBD05EBE1AF08E2A25A790CB51A0E8
+:10B5C0000B845B4E6390D2C1D59E9B54CC4FF5A6A5
+:10B5D00013EA2F0EB4292456DCE7877C5DDEF46085
+:10B5E00029C6A1BD992E6AE778E50A8B03BF2B9186
+:10B5F000D46E1FDDF7A476DE80375BED36F07BB0CE
+:10B60000D402ED4E64B8189EC3BFB12E2A463EF454
+:10B61000097FDD60F70DF5BB99DDB8B04B9B847EEB
+:10B6200088D8D7107008B725D6EBE5670F976FE17C
+:10B63000F12C9E0AF6BD93C6B5DD300EFAF7DD3368
+:10B640007631FFBE9DB6FB9E97D947D5B03EB4DBA1
+:10B65000BC05C18D4C9FBAD458F028E77AE5D0B22A
+:10B660009525E85736D73955E4B7079F9756537A4B
+:10B67000C66021FADDA135140F04F080FC4042CCF5
+:10B680002F6D6E098663D37B2DE5BF66E43F89D2BB
+:10B690003B8DC303BD8719BD33FD27FC7F948FFA13
+:10B6A000BC432107847C6956FAC7211D0B7E689E26
+:10B6B000D53F0EE136527972C606FC8FFC0370400E
+:10B6C000FE11FCE27A8EF1C9F6365F05D66FAF2621
+:10B6D000EE769D3E32FB4B384FF43B855C3FE509EF
+:10B6E0007E8CF2B7D912D98AF915420E373FB76D61
+:10B6F0005CACFC372187ED5626DFECE1A470BB8EF5
+:10B70000BE70CFCF35993E693E4FD2A6D8F1912F6A
+:10B71000BC4E1EC71F59BE4406EA729437DD493439
+:10B72000AF5DC48BCCFD9EE4F426F022FC16DC77E2
+:10B73000C0F6E9198C5E940CC69F7919223E1B361F
+:10B74000F83D3E4BE843CC338AA7BFC4777FABF8C4
+:10B75000951847E85133FEC5BE09AEA7B6287EBB93
+:10B76000AE17987C32D3E3182E373EC4B5C2FF7FA4
+:10B77000E7FB5C43F1CBFA21A1F186BCB84ECBBE0E
+:10B78000C65871B0175A79BED463E3479477F7EF80
+:10B79000BCFDBD3C2F8CAC196FC8B372AABE368CF1
+:10B7A000A35E71D05722D371591CCB358B7C8A7A1A
+:10B7B00038B9BCAB10CF4D7883C6FD92CCFA44C3E8
+:10B7C0007E447628CD50CE6DCC31B41FD5926FA873
+:10B7D000BF6CD30443BD5F9B6C2817744E37B41FF6
+:10B7E000DB5569285FFEC8D586F6E3C38B0CE5ED13
+:10B7F0006D3DF58897897BAE337C7785B5DF520246
+:10B80000EF8B7B561BF3C74CF0ACFCAB1C930E6F5D
+:10B81000CAF0537C5D71C0088F9472233C305D0E7A
+:10B82000E19C42787F897F5687CB6F4D21D63FF5CB
+:10B830008BEFFD43E981D8DDA5FABC8428FD840D9A
+:10B84000798B9556D9340FED2BD15FBC798AFDB633
+:10B85000B8EB8803B7ED837CCFE062E3CB4A995520
+:10B860003F2C5C6C17820BE957470217F37EDF60B1
+:10B87000DCD9D4DF96A4669A27FC261674F6717F6D
+:10B88000ABF13CCC522D85E9A1E0E20BD8D12C0ED6
+:10B890001C4A60FB95E6FA57B85CFC03C084CE678F
+:10B8A000847CFD3EC7431FCF9F1FC2D79B3E3D9C5C
+:10B8B00089F2BB8650BFD9DDD2F629EAADEBAD11D6
+:10B8C0005202F37E90AFE7212E171E6975D37E1EBC
+:10B8D000E5FB918FB5FAE8FBC75B0BE933DCAAD235
+:10B8E000F7DDADE5F4B91BEC397C3ED95A439F7BBB
+:10B8F0005A83B4DD0F5BEBE9736F6B88CD6B08BEC9
+:10B900004819B57382E931E3A5AB347944782272E2
+:10B910005E4C7D19B71FB961D8FCF24D7DD28F5FA7
+:10B92000D4F1CDBB192E0FDDDF9C46A6E1FEE685E6
+:10B93000BEFFA295FCF8C5B123E723414FE45CFAB2
+:10B94000B8608CF85188E7553E9911FAAEE68C0F35
+:10B95000AF289DC586539DFD4C0E3AEB93D066D023
+:10B960007D2FCE9F88725D2825A6DDE0CD64F45939
+:10B970009FC0F6E3979BF8FB5BBCFE5B994CDFBD79
+:10B980001B47CE38332DC29FB7D1FDC1217C77EF45
+:10B9900055B1E0BB35D367E063F3B915733FEFDA18
+:10B9A000BA46A931F8EC42FD88F599BF5B9AC9E423
+:10B9B000D6C64CC2E4E4FF67FCF9EE5A17F51F1037
+:10B9C0006E5EDDFADF5D9B541F2B2EF39D4C1BF347
+:10B9D000B703A0B3D3A8A9AF29682B16121FDBF7B2
+:10B9E0001DE3C6F890C80B884FAF561A47A2309493
+:10B9F00087C215F0E1530AA07FEBE038112B8EA32C
+:10BA00005AA2FA0D736D88EEFC873C941EE07B4DC4
+:10BA1000A1793DFD3938BF8BA527223F3676B87D09
+:10BA2000BA21DF5FA49CB931F3EF2B67049F9373B6
+:10BA30000F8C8DA527EB51CE4C075193F9289333EA
+:10BA400017E8F762E1572FF7D3FDEB11C3EF8067DB
+:10BA50004471A92F1CC993D0B8DA6467CF3B139304
+:10BA6000BBF1F9856374982413F200CE13DA69955B
+:10BA7000849DDF7A5FF84D2DD3E8FE4A76F05F3281
+:10BA8000A17EB5C2FCC53319818732615D897C5FB7
+:10BA90003891EF0B2B99CA562C9340215DD7247017
+:10BAA00097316EB1D5E21B8DEBFA5852C7A3DFE296
+:10BAB000B684557C26934831CBCF0B87D05F4B9F04
+:10BAC00098E8437F37711C21BD343EAE3A308EA6D4
+:10BAD00024F5BF3E06FDDBE7AD345E3409F351A12A
+:10BAE0003CE97BB9618DCE3348E5453A87E376B4CE
+:10BAF000CBE1FBEF4BA1A770DE27DD76CD02F37A19
+:10BB0000A0738A230DDE47F6C89A9282F931A7EF17
+:10BB10005F00EBBDA257A671E72BC89457C6A09C47
+:10BB2000E9B5D1FDDF7556B203F9281E7C3FF95601
+:10BB3000EC3C30922519F2BBCCF51F703DF0499CCE
+:10BB40007CE3DF70392AF2676C227FC61B18367FD0
+:10BB5000C666CA9FB1598304F7856D83F9330D8496
+:10BB6000E6CF403FFAFC994F2A63CFE31D3E0FDB3F
+:10BB7000974971FA4DA6EF3FC91F7E9DB62F1D86CE
+:10BB80007CECE8F74EFA3E5EFECE001FFF9338F9DC
+:10BB90004BA707FBCF265ABAFE3B46CFD171F268BE
+:10BBA000BDCD940714AD67F93F1DA98C4E5EC872D8
+:10BBB0007B5641D7AB483F3DCF79BDD363C3785265
+:10BBC00090A8FBE8F91EAB6DA05FF0613EB6B37EB6
+:10BBD0008476B705242FDADDD76FB27DD4AF935BBF
+:10BBE000B5016399607B9D1C5E88316CE4A7098573
+:10BBF00034FFEF33E24B710F23471BEC72D0AA5B8B
+:10BC0000475F1C3BA2348BC1A72F3B36FC466559CE
+:10BC10000C79CB43BF4FE6E73ED839B4DBDDC3CB6D
+:10BC20004F846F285DDFBF190F1E5A7F21387BDBE1
+:10BC3000197F0F54482CCFFF6F0EEF549EEFC6CEE6
+:10BC40000FD84CF9EA0BB3CDF366F9EAF7A706CBA8
+:10BC5000B2D02EB3FAC6E9CF0BECB7069226C3B327
+:10BC60008FCB1D335C3667317BCFBCEEFD3CEF3EA6
+:10BC700051262DFB74F037AFB785E351B4EFB0B167
+:10BC8000FD2C147C76907B2B0893B3CBB2F2F93960
+:10BC900097542BE2AB81754156B88FD0FD2501E753
+:10BCA00021F0E37037C331487C2B31BFFB42F05C9D
+:10BCB00075345141B9BFD23E70187DD5FE5ECBDBE5
+:10BCC00063E0F9A173CCF1DD04F7E10A9F39443058
+:10BCD0003EA2B27C0A3287DA3D92962B9F9F387241
+:10BCE000BB676B72A810F9E26389C56B853EDA9A6F
+:10BCF000736A1CE6D7BF9F5651943D95C6DF03E992
+:10BD0000483F3F4F60F4F308F404E50DBF184FCFF0
+:10BD1000C12FC90E4DC8F646F3FB4860601CE623F0
+:10BD20005C2C7CE0C786F47321F8ACCD62FCDD9717
+:10BD30001C9B3E1EE37C7821BEA0E7CF4AFF7E7CA1
+:10BD400021E029F62FC4FC266433392C9E026EE6CE
+:10BD50003CA209D916DE8EE5112DC90E52389F1D61
+:10BD6000F5E97107CCBD4F897DAF434F1CFE30AF65
+:10BD70005FC0FBEF257FFB1263CFEFC5FFE1F91535
+:10BD8000E3FC008E7D9362CFEFDD11CE2F4806DEFF
+:10BD90004FFD3BE82FC07331F21DE918A072B12F9F
+:10BDA0002DF63CBF1CF13C43B6BF879E15F44DB445
+:10BDB000558D74DF3E2B31E6BEFD52F0A3D00F321D
+:10BDC000EFDF8B7D7A901F74BD75F68195E988F75A
+:10BDD000397CDD1924928AFB9ABF48A0FB0043E41A
+:10BDE0001AE77380978DC26BE1008D67F48D8B2D00
+:10BDF000176CD90C5E83ED3BD938F1CE1FB8387F74
+:10BE00005EE8FC01290DD1386085DD1991010FB77D
+:10BE1000717C28B9B7A868175664BD7A0CD709F0A9
+:10BE20003F3D084F5D5EDFA9D697DD636CF1E5F617
+:10BE30003AF9E9B29618EBF167847C280F06DBED3E
+:10BE400079C53D4687AF62D26F61E7A7072C06FF31
+:10BE500038935C947FFC3307E3E7F7D382541FA049
+:10BE60007E40BDB3F5B92B4B1099685F605ECF8003
+:10BE70002B91CAD1F69CE9853E1D3C2BB3855D29EB
+:10BE8000C7B117BFDEB980A8BD2419ECD668FF562C
+:10BE9000FA5EE0A7C2F9EB98F8F06704E6213C3FB0
+:10BEA0004F0BD4E03ACDF0D3EE9E994AFD6584DF86
+:10BEB000EC687F83F88F83E75B33028BB0BF89E93F
+:10BEC0003E16BF10F97C83710BABFBB83D0AEF91B6
+:10BED000E2E55EFC05FCD5DBB2032BB17F2581F3E7
+:10BEE0002371D2F3E3C25E2126BB8694B3FCD21544
+:10BEF00059AFFE19E33E5B9319CB6EFD8E83E6D9F5
+:10BF00005D2FB9155C37D81FEF7D1FDA8748E4BD78
+:10BF10006FD37D2D616724C9E793463E4FE1375FBC
+:10BF200028BFFA10DA61309F4A8B93EE731E02B27B
+:10BF3000C906B951A9B067C53CA02AE8AF52CE3BAB
+:10BF4000D80FF3FA9C9C4EBB0ABE4EE4F1C58D4758
+:10BF5000A73A902E2BADB6537AB9658E7BDC956DE2
+:10BF60008C7B7C4E16FE33DD0B2E64FEFF030B2B09
+:10BF700033F57197C1B8873897A6AD62F2D424E73C
+:10BF8000843CB3D8D93D2324407CEE0C1A3F627028
+:10BF900007E71AEFBDBA4A94D13981F24C8E2409D1
+:10BFA000BF87755FC59F6475280BE50CA6F3E07825
+:10BFB000E0F565E1B3FD4AD587CFD952D0CAE61185
+:10BFC00066F987A4250FDB5BECFD328E2FE214743B
+:10BFD0002619D88F1897955DBCDC51F7D9CAB5BE24
+:10BFE000A1F10CE27451BB57E1F33BE9766A165DAF
+:10BFF0009C23C1193949F356F9D31CEFB853D634F1
+:10C00000CCDB4E243D545E3A9D7FD410186EE296F0
+:10C01000B0FC7D29F433E4B7E34A17F1C3FBB33F27
+:10C02000FF8220FED2F16458013E8DFAC9EBDC4854
+:10C03000F3A1BD41AB492F8524E4A3CC7AF37BA3C4
+:10C04000BEB2933E7A6E488A04B3CEA75F388E1391
+:10C050002F7E63AB64A81FB899D9C36F27B2EFDFF7
+:10C060004E64DF1DE37AA6394D212CBE63B7A33D94
+:10C070007FC675028F6AA23EE9447D62B705285EDD
+:10C08000855E59BFFF5682786B3E504BE1F05B896D
+:10C09000ED8F6A2B249AC7B094E7DFD51791D702AA
+:10C0A00038B59C7CA6CF5E0EAD688272DDABA4383D
+:10C0B00002ED4A6607ABF15E97F662A26E8172BB33
+:10C0C00023F4D44F711D47D93D631BF8795AC0C47E
+:10C0D000BABDD0FFCEEB46A9DB714955035B314FAA
+:10C0E00068601B71635EC910FA3D07FC00F4B00B79
+:10C0F000CB30EF0D6B42FF7A07B4CF7E95A8B40D1D
+:10C10000AF471F05F12771BAC0F7B3E1FD064E47EF
+:10C11000050725B6BFEF61F77FD1CEF17E2E3BFB41
+:10C1200075C3C18A6BA7C2BC0A7AA750F21E03ED81
+:10C1300031FF093310587B6289D57E0CB6F7E17E5A
+:10C140003EC30FC951E8BD4984CBBF69263E9C114F
+:10C15000E5075A5FC2CB1BB89E32F00DF603FE7A9C
+:10C16000A08C6DF7D3EF3C8C3F54227E183F4F27B5
+:10C17000D11FECB72A3A0E95CB7378DDE1E5F36970
+:10C18000DEF7346BE405E4F719FC59C29FC8EF767B
+:10C1900080E3326BCB612FAC27751351DB709406B3
+:10C1A0005F3BF6574A8232C2B9CCBDAD1DE7776519
+:10C1B000C3D174A4AF753905949E66DAD502079091
+:10C1C000487BB9AABA0BF09E3189C26549BD3D8C46
+:10C1D000F96D4B06EFF909F99702FF2C0BB1BC661C
+:10C1E0002C37E8E2B522EF6F6902F8D531E4F7BAEF
+:10C1F0001C662789EF37F07329A2FEA61C96FF71F3
+:10C200004DCEDCD21C9A97C4F2A181FFA76159C818
+:10C21000151897E6AB2C26011BAE6B31E75FC1FF0B
+:10C220004B02B7537B7649D06897FE5662F8D69694
+:10C230004BD44E5C563FBCDD3A3747EC07E7B98F2D
+:10C240002745DF0BBA12F27C11EA7794C335A0CFF1
+:10C25000757673C39DE752E977994FAE3F7F59F4E6
+:10C260001CCC06D33998667E0E66C381365B06D237
+:10C270003B3F07B3E1E0875BF5F97F024E43CFC157
+:10C280000CD0BCC7A54AF8053C1FB4F4165823B41B
+:10C29000FF153F37F1229E9B981CA523D7758E086A
+:10C2A000CBAB0BD0FCBE3C77928AF9289D96C93463
+:10C2B0009FA833D9A5EAF377B6B7B554633B914746
+:10C2C00024CEBD2C8DB35F7C7B0EB3B71F92583E3E
+:10C2D00097B6DC4EE1ED95C931FDF97E6F4190E6F0
+:10C2E000D195E6F8447B1A5FC0BCD329F00C839942
+:10C2F000C6F0C5BE37CB07E8AF03FBAB2A5069FEDB
+:10C300004C550ACB43F3A6074B6E2B8AF65B77900E
+:10C31000E5EDD5053F3DC2F26F6B4B119EF1E4BADE
+:10C32000597F01FD75E6C488D3DF29879A91FE6C99
+:10C3300095C1E56BA1DFB3AF2934CF8E6C0E4836C3
+:10C3400068F79357DC2A9EBFEBA808D656D37A2B02
+:10C350003D1F98514F2209505FFAAAD28DF97D8D69
+:10C36000A44BC17E1A4D7AEC16E78B0AF2E92DBB7D
+:10C370006D51BA249897A816A0C06BDA3B242E42C0
+:10C38000E590904F667A26638C72A844C85D900F42
+:10C390002CAFAF81E93DF2A484F1A1B3AE1332F723
+:10C3A000AFA9DC9B2A849549DE4F3DF812B567049E
+:10C3B0003C6781BC403F4EC2F793D8116EBABFA50F
+:10C3C0004985986F3A8324527A1B6247F0F9950E9B
+:10C3D000CE9FD94D424E56943393D48C1F188FD292
+:10C3E000B9D8E79B8AF7FAC073061FFF0B4BA0284A
+:10C3F000E2477C91B005E0BC556AA17AC78EF99FEF
+:10C40000F0DC2E85A85CFC99A6C908D72B49CBE2A5
+:10C41000857E8AF72339543EF626211E8E2BAA1DCF
+:10C42000EBAB3151903E8DF89AE77CD08AF09A9729
+:10C4300065C68B6645F8CEF70DC1173D571088834A
+:10C44000AF80902BC42857FCE41C3BD7BCEDC81D23
+:10C45000E81F5FC83E793023D48FF2339E9D122FA0
+:10C460001FEF2497C723CDC73B6B637EC574D27F74
+:10C47000E35E69289D9C39BC49CED2D193A0D3E715
+:10C48000787EBEF44B9EEF5BEAA2FA2FAA2F191D0D
+:10C4900094F1D274A42F1D1D5C75C01191619D256E
+:10C4A000FCFBE9480F93A3FA326271FA947CC4BB97
+:10C4B000DA29CB43EDE48C341FC5FF144B80E27FB7
+:10C4C0002A51D3B9DDA9E4C2FACBED3DED561FC523
+:10C4D000FFF7D1BFA9203E8AFF0A93DEA972D65981
+:10C4E000914EAAEC663C0728FEABDD43DE5BBE0A3C
+:10C4F000FE2F43FC0BBD3202FB14F0EFCB1D669FF9
+:10C50000311EFEC7E73A795CE3E2F06FC6BB9003E9
+:10C51000FB1CEE2A27C6831B593EF294D7C6B46390
+:10C520003963BD9F9E93D997AAFE8AD6B7B0FAD237
+:10C53000DE808CF732166C847A28EFF307ABB0BC40
+:10C54000619344E5E8D43743ED581EB399D5976C11
+:10C5500069F915DE6FB64163DF3F77722BBDA72205
+:10C56000BC957F5FD15585E50D9DECFB3FB8EC1A7E
+:10C57000FAE565C7C2EDF87EFC0E360F61F7CDE631
+:10C58000F4B64F7AFA57F4BB2EF6DD4D47EC89CC62
+:10C590005F6276DC2CBECED98FB1757A7E77758DD1
+:10C5A0000FE0BE7640B351B961692AA372348E9F01
+:10C5B000562175E5E1731EC80942F10E749ACFF257
+:10C5C00055BB6188B5B9CC0E11799E986F5EABC32F
+:10C5D000D7DA5CA66F45BB8C34C2F2921F65F7CDEB
+:10C5E0008A3CD4C8C344C2F801AE91EADF3879A9C5
+:10C5F000F30A5AA83E9D7799C847EDB7AE86714BAE
+:10C60000CEFFDFB9B1FCF2263EEE099E3F2FDE37AA
+:10C6100086FD16F44FF621F1D0FB7F7EFE1ADA2D4F
+:10C62000FB701F5977FFC83E3F2BFFEFDC67EFE938
+:10C630000427F7264B8B554325305AA2F7A97CA334
+:10C640009744529287CE7F9E954458DE049BFF8D7F
+:10C65000ED4AF7769D1DBF44888F9963A95EA9E3D3
+:10C660007812726309C717F0793BF2C7527B0BB59A
+:10C670001B9713A6D76F26611ADFB8D9C4E7EB9CC6
+:10C680007F7ADF82F6F31E233FAF87E9B07DF58125
+:10C69000C7DF05F8373EE272A3FE5FDF636CD7F8B1
+:10C6A000C86BC798FD65E4F746C1EF6123BF8341BE
+:10C6B000C1F8FDE10974DF469C0B74D807DED7484A
+:10C6C00074BD837ADFC47F0E3C2758887E8D85E554
+:10C6D00027F2B218F7B32EA69735D0CBDC0FA222E3
+:10C6E000F7B3BE05340FBE44E8512E67043F977080
+:10C6F0003D3F448FD798FD9D07299F4CE125B3FE10
+:10C70000167A5B9C3F847EA9FE067DFD5A00E6DB1F
+:10C710006B718611DE51BD1DA67C34D90EF2DA4252
+:10C72000F1F73CCAE9A91C6FED5CAFC7F50F9C1B84
+:10C7300063FA07E06FD07D84A17E41C460EF9BF176
+:10C7400016CFFE1FC49B03ECA924F4F709E3E31CF6
+:10C7500032A2FC1090DBEFE40EA3B79543ECFDC0D2
+:10C760004E078D2F8838BBE0BFDFE4B1F8C277B346
+:10C7700003EF613F7D7CBC3EDE7FDFADF3E8BEF7BB
+:10C780009F4880EE7B631E536E8CBC0BDCF7EED0B3
+:10C79000C54BFB5263C7C13FE17260621E5BDF198C
+:10C7A0006FE034F2D50985C5D94F24F26732DBA793
+:10C7B000F82297C57B27E6B1A72B8FCB119EDF7D93
+:10C7C00022CD189F17ED52F8F3E3567BB043170FB5
+:10C7D000F73D9CD0827ACC5BC0F3E137323A3EFB26
+:10C7E0006CEA4EFDFD7039791513F3304FA420A08B
+:10C7F00064637CE659A62F9AADFD0ADEEB93E20D49
+:10C80000D9F2302EE32381A7B11F5FBFB218E07DBC
+:10C8100096EFF79FE5F7009D75B0A798574E5EED30
+:10C8200044FCEEECADFD546E0C966BFBA95CC8C9E4
+:10C830000BD271CF2E11F5BC7C0F2B13EE57567017
+:10C840003EA171E31871E2A17161E33D371B94D8F9
+:10C85000FBD424CF6588F7AE38C8E2902BED646B2B
+:10C860002ED45F7F3093FA1B8DC9DA38A487AF1BB3
+:10C87000C73D3BAA97AE6B7BC5C0E8474BE9BE30CE
+:10C880008D17AD3FF812957FEB05DFEC37F2CDB495
+:10C89000BC91EDA798E3EC23E0A78ABC61ECA0670C
+:10C8A000507FD9A278B88DE75155CB4D551857FA1E
+:10C8B0006C0DA1E76B6F7B45A67475DB5312BD6FE2
+:10C8C00042D871EB399CE3AD0BCF27F8747205CFDA
+:10C8D00027F8747E1D9E4FD097F17C82BE3D9E4FFF
+:10C8E000D0D7E3F9047D3D9E4FD0974BC80DED188E
+:10C8F000A7DBD049DC611F3BAFA0FF1ECF2BE8CBED
+:10C90000785E41FF3D9E57D0973F230C6E9F3D269A
+:10C91000D3F83F9E5BD07F7FD32B3F298BE0B21DA6
+:10C920002C3FADDD01F0473AD402BD45009F351CD8
+:10C930003E78AE41DFEF27C9735F46FCACE9BD71BD
+:10C94000213EAF38708BA15FD2C5E4710BFC433838
+:10C95000DE488229E8CF4D26034730DED11C9654AD
+:10C960001CF7A6478C727BF01E93B0F1FD3AA28BA8
+:10C97000FFFA87C6FD3BF25C9EE32CB739471FEFF9
+:10C9800089D283538D201CDE94D558F450422E4F0B
+:10C99000A1719E97658C61903F909687664ABAFD1B
+:10C9A00001133C12B28C74E1F019E922A9D04817A6
+:10C9B0002ED5481729E546BA480D4C1816BEE9355C
+:10C9C000463A59273751BE17702E877F08E7C97836
+:10C9D0003325C217D689F162337C1B0FDEB715ED04
+:10C9E000FE8B856F4F1EDF57E1F0FD9CCCAC72FAD9
+:10C9F00068759DBD2C6AC794BEDC423781CDF1536A
+:10CA000001476147883828E87F6A4F47FD7AE6EF9B
+:10CA1000817DF04B94C3C715E6E72125A1DC5C4B73
+:10CA200042543EAD35D90737391F54D03E18B25E57
+:10CA3000B0CCF0DE42F37AD1DE22BAB894D93E907F
+:10CA40000E4A11D7245CEE4121A743E7A931149087
+:10CA50004622377EE40ABC85720B1D457B99216E08
+:10CA60001CD3EE13F3107011E3279016390BE9B9BC
+:10CA7000D06C9F19FD6BE18F8B78BB886B0B7F5A55
+:10CA8000F8316638CB97F9DB91FEA7B8851FDDFB3F
+:10CA90004D7C2FFC67B3DF3A781E00218BE76D7861
+:10CAA0009CFE6EEF6A3BBB8F8FF19D78BFD5B3289C
+:10CAB00065B83CCCBB5A8DE75F60198161CF13210B
+:10CAC000C83270DF89605085ECB8E6483FDEB1B30C
+:10CAD000E31BBF1E78119EDB8B9FECDF8275E7CED8
+:10CAE000CB08D7C1783E61E78315FE9D92B7F55616
+:10CAF000D4A389AA957CA4A30B3B68AA8F0AF9B892
+:10CB0000A827B206EB7FA3DFD7FF473DBF0BF0F9A5
+:10CB100068EC30F58ADA1833AFD6042F710D86A38E
+:10CB200068EE49B44F1C44B76EAA0F7565390A2FD9
+:10CB3000AA5A657A5E4AD407F0DE92AFBB2EC4FBD8
+:10CB400047367D3972F4639B7EFE619657600D1205
+:10CB5000CCBB553C50AFD72F8374080C55A65BDF78
+:10CB600008D6854C83EE27B34B18BEFF56EBEA3050
+:10CB7000E10BFB0D665CD2F3D32EF1F9452E71FC6F
+:10CB800092DA4B1B7E81DA4B1B7EDA253EBFC8252D
+:10CB90008E5FB2E8D29E5F60D1A58D5FED129F5F80
+:10CBA000E412C72F597C69C32FB0F8D2869F7689CB
+:10CBB000CF2F7269E357A376A0B33C42F05E095FC2
+:10CBC0000751FD3E3059E135FAF3052AA1791A845F
+:10CBD000FB25F9DC2FB96F474B3DBA50BB34C54735
+:10CBE000E341E0DF6741FD78C2EA77752EA271D696
+:10CBF000B651E372F09E2A67E7DC93786E6FBCC68D
+:10CC0000FC71F3DF0BAB0D18FFEEDAB5E5E986F248
+:10CC1000D45EE3BD15DF6C2C30D42F0F4D34FDDD19
+:10CC2000BC29C6BF47169C61BA7FE156A23F0F9947
+:10CC30004F222AC657F2EFB154E2BE99157DE62B7A
+:10CC4000E1FF6E857E17807F7AFF251F3CA1C1FE24
+:10CC5000FD0837C5D0BFD3547FB1E74F9F19CDE34F
+:10CC600031A6F3A7042F978C71DEDC9C8749AC3783
+:10CC7000D3F89CC0D7DDDB2CD4E5FD7C07A1F73BC6
+:10CC800056857D167AFF39C7DB444E7A62DDE15660
+:10CC9000E339F47C8D54223E0B3A8805E36BFEDDCC
+:10CCA000440D101A17A274B24B8B4D27BB88BB12D0
+:10CCB000EFE3DA1526F4EF6309BAB8DBE6CBC17D02
+:10CCC000B5899D8C1E049DF8904E92312FC87CDF53
+:10CCD00080195F647204E6BA6B477E9A3E1F95EC3A
+:10CCE0006570B7C3BFE1F055B8DB882F1FD195BF82
+:10CCF00002BE4E7F4D7C299E6024C583F14CE2C369
+:10CD00003CA9C3A3C659101EFE4E95FAFF35D00CA0
+:10CD1000E1ECEF64F7A8093C89FE76B492C81C9D4B
+:10CD2000FFE75723018473B55C5489F9E73B4B69EE
+:10CD3000C878087E76127722C6BD77765A12E9DD6A
+:10CD4000D407002FC584FCD7B6A5298550DFED2771
+:10CD50008978BF56779B85DE57D6FDAC546FBC4FA4
+:10CD6000399260C9A2EB48B094D3A7953D03FC4922
+:10CD7000ACAC3E226379F4E621F77DC8589F5A6334
+:10CD8000FA7B812420617BEB652C8F332560BCC747
+:10CD9000C6566E940700C6DEAC328CB7707AE7F7E1
+:10CDA000A386AB4918FFCED7655CEE98E928F5AEAF
+:10CDB000459498DA467D8BCAB3EE3685C2DFC6E568
+:10CDC00015D9CCE842837F484FA9263A72A9463A42
+:10CDD000B2C979340F57F095988F18BF6D5446A299
+:10CDE00095CECB4AEFC1B699E584697E4E0C06021A
+:10CDF000EE9C1E120E43BD4D63FC41E43EFADE364E
+:10CE00008D9074FF5798E7D7944F575F16FB7CFCC3
+:10CE1000C5CA2717EFF3EEA96C9D9FABEC3EEBAABA
+:10CE20000E46EFAE1D8CDEF12437CBD70A2CCCD6C4
+:10CE3000EDABEEE772CA0C37576FA00AE979AEFC8A
+:10CE40006A00F323EE7993D17FDBA8B75FC6F28E39
+:10CE50007B18FCFD2AC333D08B1A81A9DF7397930B
+:10CE6000E6054F29057C21FE5F35CA93A9BD4638EA
+:10CE70001698E4863F0E5CCDFC1A0FAE7708B89684
+:10CE8000015C0B2E1EAE8AC6E473EA4C76BFE2E16B
+:10CE9000510AFBBBBC1A83636A40A5F277AE7C2EB5
+:10CEA0009202EDEE0B80BC8179D60418BCDD33858F
+:10CEB0001C37C253C81701FF7C0E7FB7EA7E05FFFF
+:10CEC000BE8B53B3129F84F0FDAF00DA115D538522
+:10CED000BC192088B79400A35B01E7AEAB189CF3A4
+:10CEE000031CCE9D1C6E129110CE667A35CBE79452
+:10CEF000AF09E76E01E70C52F655E07C5F12BB3FCD
+:10CF0000D93686C1D5E61C88A09CEDF45BE9BA5EF3
+:10CF1000F02BB4BEB398D53F9CB4320BF56DA77718
+:10CF20006B16D2659BFFC62C94EF8E2C2E6748C0E3
+:10CF3000995D163D77502DEFA0F78F6EF529143FC0
+:10CF40002E5F6CF995323364A7E31459894CE1F0F4
+:10CF5000981A0B0EF652C5202F731B8DF04D32C15F
+:10CF6000D7F135E5C37F7E4DF9803947D8EEEEB174
+:10CF7000E27E862E3BD54FE5B7D0B879011F6BDB3B
+:10CF80008EFBD97BAED774EF6BF2519E38AD2AC2BF
+:10CF900033DEBC859DF338BF0FE67E7E9F4B17BF07
+:10CFA000CFE55E7E9FCB0E7E9FCB76BCCF059E9D50
+:10CFB000789FCBE5684F07E853BE278DDE3BF839F5
+:10CFC00026B0FBF1DE9C3324D6FD247ECDA8FF2EB7
+:10CFD000DB64BC9F2CBDC6A8E75203463D87FB5EC1
+:10CFE000FA7A976ABCAF2DA9D0785F9BC367BCAFB4
+:10CFF0006DCF6521D907F0FD7FB1B1C61E0080005D
+:10D00000000000001F8B080000000000000BDD7D09
+:10D0100009785445B670DDBEB73B9DA4BBD3095912
+:10D0200081849B950E84D040C0A0416F16302A8326
+:10D030009D088A8A1A013140481075CC3C9D97861C
+:10D0400004081830A0A8332E34EBE0B845272A2A6C
+:10D05000321D04069FBEA1595474D4BF757C0AC802
+:10D06000480417FC9ECBAB73AA6EF7BD371D088A28
+:10D07000FFE77BF1934ADDDACF56E79C3A55313B27
+:10D08000CB88DF4AF0E747F8C7DB4D3C76CC9A48BF
+:10D090003221D9BC6CBCF8B0355840C8B2B6EA38B9
+:10D0A0005200F594402A2D8F85429990A566777F8E
+:10D0B0000FFD1EDB366B227110B2B88910FF604283
+:10D0C0005A9BAC982E4CB7B8FD89846C7853744742
+:10D0D000D12616C5A33869FDAEF42584D0EFCB9CCC
+:10D0E00084A464D2EFCEF984641122D101049A970A
+:10D0F000DA261C2185B4C1D4B9848C09CF67599B29
+:10D10000C9ED2F22242ADEE686F14981F45190965A
+:10D1100039E97F3FD2F63FC2CF45E1348AB0725C35
+:10D12000278C236BF204C6D39737BE273CBD5353DD
+:10D130003E58B6277E028B3D8F9CF7A34853715A09
+:10D140005C8D8DA6AD09848CED39DE374DE4E99D0B
+:10D15000B90850429220AD25004F89F7B934BEDAA4
+:10D160004A6C6138ABDF173B197CA30412B1DF16A0
+:10D17000806B54382F11A274003E061645ACAFA642
+:10D180001403848C26A4ADC9BFEF6373F8BBAD84D0
+:10D19000B6B7F5AC5F298B38EF29B28CED6C929F56
+:10D1A00038693DBB9BB6D7C0C5A69CDDF8F4A7285F
+:10D1B00091AED7C1E9863C214880572BCFC70A35AD
+:10D1C00053E424C09787229BD62B56484D011B4F12
+:10D1D00051DB09904AE42357185FF0E3A4E50CA45F
+:10D1E00090D272ABBE5C4E467861BF52B8BDF2A31E
+:10D1F000D0FBBC7FA914F0F851EE69CA2DEE5AE0BD
+:10D2000027E3F77F974D2A1CBB1329DC44BEDE08B9
+:10D2100070FC772D1C451B83638B90B93548F9CD85
+:10D22000AC38DC1423A43451EE00BE6C516CC897AA
+:10D230002D891D81329A3F5964724357F6DC32E4DE
+:10D24000C796FEBB0FCD04B84EDA737823424D0962
+:10D2500054A8F0A5E5765765A042C50709E32B86DB
+:10D26000FFBE7CD8E6E0229AF6BB7C1A715252B11E
+:10D27000A5588848F1129D5B61ADB185F163815F6E
+:10D28000E8F798C4094744CAF7316E0D1EE1FF1F45
+:10D29000591EE141176F19B8E41601882235546F01
+:10D2A0002FCC47923DE1F991738F2F329002298D57
+:10D2B000A6923B15E4654F7AF732BEE7F57AE70BA5
+:10D2C000566FBC3831F5460A97D637A87C04BE7035
+:10D2D00031B960B6327CB61225F546DA55EB40C955
+:10D2E000ED857CE274941F4B52AB5B417E7E95686A
+:10D2F00022A200DF1759417EC0EFDA71933C26E28B
+:10D30000D7E027656A8C4EEEB7CAD528CF7A9B67DF
+:10D310005A8DBEFD805A7DFBF4F909BABCDA2E3A6B
+:10D32000F5B20315FDC2F96592C70A726471E26A2B
+:10D33000A14643DFF1F93507E5D1E1BC397512B6F5
+:10D340008B4A2F8A382FBF4B3904F5E9FA991CB65E
+:10D350002546943FF7F17DE87EBE0F9D699D0FF253
+:10D36000FA7FE4F51F6E72621AC267CE6C1D5E967C
+:10D370002651794DFBDB0C5534E33F23D71C07FEC8
+:10D380000BE3D914860F306DC11C13F0ABDA4F4B91
+:10D39000D274C49BBA9EDEE6D7CAE5BF5ACF2A79BB
+:10D3A00089BB00F91EE57008EEB21E5F05995C6E40
+:10D3B0006C9CAD1B7767FC84A99994EE961C14496C
+:10D3C00014CA11FDFA7AD2AB7E1D4B12D9FA7BA793
+:10D3D0006FC3BAA94408CD0BF309867C7F43FD2CAB
+:10D3E00043F91043F94843FE7C43FD3243FE524368
+:10D3F000FD6A43FE1A43FDE986F23986F20586FC92
+:10D40000BFE9EB17313CDFAE7E3B8D7C01BC1AEBF4
+:10D410004B9282F8950CF8353BF5F82D4D2F3D3F9A
+:10D4200013F7855A1D7E55FAEC2B7E96521917007C
+:10D430007E926A987E523C8768E961496216EE1FC7
+:10D44000622971B3564C4E5978B998C6C6A3FA9A58
+:10D450008E8EBAD267A1FE481E4C6072F30C742106
+:10D4600090047DB9D23F5C9E05FF9E5BBA38331DA8
+:10D47000FBF8BE7BFA79AB7277CB20CFBC4C901710
+:10D480003EAA4F0F0BC3490EE9D37430CA77EB1392
+:10D49000892F8AEE77EBBD26CC7F954A07027DA5C2
+:10D4A00062B64EFF262428403F4639B00AE4144DA8
+:10D4B000EF013945D3BB9B52315DBAC2943613FAA2
+:10D4C0009B6841FDB8DFF0255E09D2B2E27CD8BF8F
+:10D4D000EF1EB64531D1BCFD9448FCA3A8BE5078E0
+:10D4E0004D312C2776FCF4D49D30DC77749C31C010
+:10D4F0009D04958C7515C4671E4EC88A1D6997BA20
+:10D5000068BF728EE48E86B202F7422911EB79C1B0
+:10D510006C90A5EE3DD9343F28C784FA85B9B8BBD5
+:10D5200009F47775DE2B2EA5844B2B6656BA4D5E1B
+:10D530000A823B07D5DC0B701AD4464C0ACDCB5E71
+:10D540005900B9F666A68CF0DEF02265C86C18A802
+:10D550003B0DF6D9AF575816C13C7BC713114DC5CB
+:10D560003F3D55FB413DB33F7E57402ECB129210BD
+:10D570005DE57FB52B346F1359FE95CC239E459AFC
+:10D58000FCE399479C906F1B9561827564263A1461
+:10D590005F04BADA0FF298AE7BC38A5983B4FBA05A
+:10D5A000319527D27E53685AC053A0B5F300FE3C94
+:10D5B00095F9F754967F0DE046FB951B7979224B40
+:10D5C000CFF538C6FE0F643A55BDB43FB71F0B6C9C
+:10D5D000C9A7D54FF783BC32EAA754D0F5073A5F05
+:10D5E0004BED4913ED7BED0A0BF1529E5A9B4ED049
+:10D5F0004EF42EB3F836017F4872FF2B357A976FC1
+:10D6000059F23580179F40A66AE5E4FD1CCE2BB386
+:10D6100004AE671DF38A947ED7D26D13C4ED5AE22F
+:10D620008C067D24846FEF098FA2C1F78559A5ABC5
+:10D63000BC30AF996CDFCC0AC9B3BC8512ED671D55
+:10D64000F443F3EB5A4D38BFB5DB28FFD2A1BEBA85
+:10D65000EB2313E8CDC388DF04EB1B4A7C98BAC8E0
+:10D660007C1300A583EB191B39FFE651FE467B07AF
+:10D67000441F2DF70CAAF91AF8228EC89897BD4EB0
+:10D68000A4A7FA6DF16591F4039265E27626A99557
+:10D69000C6703B87C199648DEE097F33998F70BF47
+:10D6A000DDE53141B96DEB3EFF005AF4DCDB7ABABF
+:10D6B00005A8546BE44E0A1F27CEED5144DACFB6CD
+:10D6C0008C9A58685F5FFBC5EE64E8DAEBC5F6A399
+:10D6D000B29C58EF1A7FC778E866B83B5806B4305A
+:10D6E000ACB26B0790CC50651D9819C4557CCB8E9D
+:10D6F0007E32CCA326318BD6CF0B044B817C6CB50C
+:10D70000FBFCC9389F0B4D4017D9301F4E1F5548A1
+:10D710005F32D2898A6FA0872A9ABFA68EC1875AA4
+:10D7200083584E24A76EFEEB17533AB1F5A4137B32
+:10D7300016D38F866485EC2B623EBD7D35242B820B
+:10D740007DA5C2A5BAD36D067781E709E762B081EE
+:10D7500026F9BA7746D3EF8B326A4640BBA2073D23
+:10D76000CD407FB66D012FD453E1642B092802D63A
+:10D77000538A00AE6BEF2A2BC37DA19DA0BDD49B25
+:10D780009E6B2E31E9FD38A41DD791DBAED7D3298E
+:10D790001DE37EDE838EEF0AD1718CD62FA1EE3F82
+:10D7A000BE36538C0BEC0C6A7F605FBDC891CD7C9C
+:10D7B0005F52E95AFD9E4322FB19A686E19D2A9EEF
+:10D7C0001EDE5323C1DB01FC918DFC320DCA9DA4EA
+:10D7D0001BCB07DDA5E797FAAD5FEC1E40E76F2B8B
+:10D7E0009247027ED4F167717AA6743C13E9F8C1BE
+:10D7F000EEDDB0AF0DBA8BD1F13CD03592C2F478EA
+:10D80000BB4BB919C651E9CCB89E9B787F8B323C93
+:10D81000F3B0DE831DBBA2B19DA701F2B60703FEE4
+:10D82000681286EF200EDFA8DF87F0EC04F9513D87
+:10D83000D1BD0BF6678FCB391ED24972770BA81674
+:10D84000D7D68A3ABDCF885F4A5FBF877514114F1C
+:10D85000B9208036DB61C6FDB317BA09EF9B5E5570
+:10D860007EDC7506B9BD2C121EFADAFF890C4F3B1F
+:10D87000B44FA8F490D3D96D3DE6D5C77AAADF2C72
+:10D88000ACC7FA747AAC4AF7CB5BABD1DE52F1A0ED
+:10D890007E5FDC5A5D9909746E93DC91EC9FD07EBB
+:10D8A000C3E9FC514EE7ABB9FED5CEF5AF954D328D
+:10D8B000CAF7B62617A6CB9BDCDC1F5A8CE9E226FA
+:10D8C00005EB89CB4E94A2FD7E1741BFD6A2D8426C
+:10D8D00021125D657AF5FAFEA0463DDEFB55EAEDC4
+:10D8E000EF78ADBE4CFF8F2BCED295DBDD4374E5D8
+:10D8F000B1AE91BA7CB47CBEAEFE964135AF015D4F
+:10D900005912CB74F548F00B9D7EABC271BC380D3B
+:10D91000F57D0A4F660F707D562D27A48668ED149D
+:10D92000759D6D063D7639C011E1CBE0D80E70448F
+:10D93000F81673785632BB89DB3D31AADD93BF7A86
+:10D94000EAF444D4A7515E2D4CB7E0FEBC3C93E909
+:10D95000DB3DE82755233F29CF2F5DC6F673551FC2
+:10D96000DF95FE5625E8B5EB534D2827D727EE70F7
+:10D970006DC07C8C9BEDA7DE7617C59FD9C5FDD504
+:10D980009462D3E87AED9C6F969A09FABF9727D9EB
+:10D99000DCE007B3BB664DC47A867109B98568EDD2
+:10D9A0003FF271AD4EEF20D26CDD3A43F32FB2B0AF
+:10D9B0007E0422403F0905161DFEAC4493CF84F936
+:10D9C0005AC278CC84F5723C19F41CA39F421DCF37
+:10D9D0003951BFDF2CCD67EDBBD23723DE8DF0751B
+:10D9E00054E8E97739A78B96A4F5C887C6FAC6FE2E
+:10D9F00049498CCEFE5BEE3ABD9F44B5A7D57A600F
+:10DA0000473B23D437DAD1E7C25E77E278FAFD2EBE
+:10DA100082BDEECED6F893547887F0A0FA17B91DE0
+:10DA2000A6FAADD5FE24C2FAC33CFAB7BD28FF1E44
+:10DA30008875A01D9963B3F84016E6D079001DB72C
+:10DA4000FC21D6B788E657C54EEA8EA3F99C8DA275
+:10DA50008CE5360F9EDB74AD99D03F48C77D48A852
+:10DA6000199FADF1C36D8CFF6D2AD307A48F822E51
+:10DA7000607201ED5CEFAA510105F4F17CE2DE4435
+:10DA8000C00A66E52A3D116D5EEC99FF3C9BEDFBFB
+:10DA9000A9D792F91D11F0DF9CCDF6D1B01CF7C4C7
+:10DAA000A0BCE6723C87C36B537B758C568E6BBEF5
+:10DAB000C745A2AB7325BF5B407E0F8671F62BB8BE
+:10DAC0006F17112EBF9F22BF46F93D27B36621D0A5
+:10DAD0009BD978DE2705517E0F939545501E07F69A
+:10DAE0001EE0E5068A9708EB7881E3EDD78A177583
+:10DAF0005FDDD4FE2CC34B818A97952492FDFB2BCE
+:10DB0000C04B27C0BDC7BE4A82780EDB3D50790EA0
+:10DB1000F8F11959791ED2107EAE8ACC379FFEC219
+:10DB2000F87994DBADAB397EDAB97F7C25C74F1B22
+:10DB3000DFAF9773FCB4F2FD7A09E027EAECF966EF
+:10DB400050A31E3FFD2A630CF8D0E327AE588F1F69
+:10DB5000BB5B8F9F58D710033EF4F889CB91991E79
+:10DB600099AAC7530FBE3983BDE2807E22F83706DB
+:10DB7000D6044AE18CABFFD48E2E3374E2692F8534
+:10DB8000545DEFC306BB544DE372983C4C2D8F8C13
+:10DB9000F7EF38DEFF98A5FCB78E8F2F8ECCC7A687
+:10DBA0001C56FF13591172B4747559E4FA565EFF8E
+:10DBB000E020252A47D33FFDB94F3C8DBD605C7FF7
+:10DBC000ACA0C4E5E03AE4AD418AFB8D0BD939E461
+:10DBD000C668B903CEF3BD0B6DEE4D32F6E4B182EB
+:10DBE0007DC4FB21DE38EC37830F33C8B6E75B38E2
+:10DBF000F7CB9C31B0FFCDB43C7341EAD11A9AE621
+:10DC0000E464239CB26ADD3B00CEA2636A7F767E29
+:10DC10003CCDF9C9504A6AFE7EC28F60703B13FA50
+:10DC2000742E47E520EA817422BE4D944EA324222F
+:10DC3000D91360BD0AAECB0C7AAC08EB6DC77C0C77
+:10DC4000E9C0D44602ECFC9ADBA3A37332115E4E0A
+:10DC5000E2447B3581B83155F9D89A48A4A491D8CB
+:10DC60007F4BD448821BFE0560AFDA06AE5B0E36F2
+:10DC70008D42A130065905E121DCB71BD74F5C442A
+:10DC800066FEB6BB9C189FF01A5DDFD0BEAFAFAF8B
+:10DC9000F5BE8976149238421AAD2CBD23C6B11E4A
+:10DCA000D26FA2337CE0B43A3FBBE63780576F199E
+:10DCB00041FDC3FB41ACAF19273BFF3C661FF4B9E4
+:10DCC0009F2BCF513F379CA37E6A813FCED4CFDDBF
+:10DCD000F0EB5838C7F4D4C1B82DF16350EF54536A
+:10DCE000235CFD2E653EF42B590F647CDC2FACB712
+:10DCF000D9DE13506F6B11FC04FC94DE0F05D4AF1A
+:10DD00004801C3934D26AECCE1E17E6CEEF98398D9
+:10DD1000BF8BF97B16BE7FC760D0BF1F889D148C58
+:10DD2000A3ED37ECA37A1EC4D194BBDFADA5F49468
+:10DD3000D4CFE25E4FE9A71FB793A3568CD95B4BB4
+:10DD40007FFD6C30932F5B9AF6385BA840B24BEEA8
+:10DD50004B46D276367E7E4BC48941D01BED632480
+:10DD600019CE38F2457F25CC97349808F0C5437515
+:10DD7000FAF3DC2579F9D89F9A1FC0CF734991D463
+:10DD80001D8AB3A17AFCEA1C1E57E3200ED00BA516
+:10DD90001F94B848710F6AAACEAF2891EE5B71E06C
+:10DDA00017A49C42D3A2363F067F94B9FD56D06398
+:10DDB000D7F888D742E1F4D874CF6CE8AFADD81368
+:10DDC0000B7AF99A83D5970DA3F30E04253780E0DB
+:10DDD000A5C10938CF8022AE88A5DFB7BE6772C261
+:10DDE000FA36F0F66D1E01F9FFA169C4E7A5F0D877
+:10DDF00050B7C32A82DE1B30915CD473A9C135862B
+:10DE0000BB4E64F0D732BEBF6370127EEC0C2C8820
+:10DE100007B8AC8ABD30A0D0FEAB2A99DF79823832
+:10DE20007017F41B68B3207E9278FC9140AA507F53
+:10DE30004E98A6D197E9FF761E0715B88D60DC5382
+:10DE4000DC681BC6013C1764E7460F5532BFB3833D
+:10DE5000F871FC09E2B66813FDDE592939819EE2AA
+:10DE60000CFAB90DFAA324D7F920EBCF3182F5676C
+:10DE700037C44159D57939E9BC28FE44BB8478764A
+:10DE800056EAE3A71C867636C3787B01CF20970637
+:10DE9000923CC0F349CF6F471DC052B71C297EA2E8
+:10DEA000AD89042A34F116B65EFC875FE431BAB559
+:10DEB000A4EDB4C2BC4E7ADE4A0477D71BDFEFFE76
+:10DEC000F81E487FF88FCE06BAAEFFFCF6D0C6A784
+:10DED000018E8D77EF473AE476550A4C81CE67572D
+:10DEE0009505E1385A61FE0152D4B5D35C84E578DA
+:10DEF000AEB5624734960F2826BE680ACF019292CB
+:10DF00007613F06B40742F94A113C5963686B0A398
+:10DF10002A9A5F713D251C2A1F92A629229C1F8CDC
+:10DF200017DF20768AEF358A20B3F8376117F05370
+:10DF30007A85807658FA414F34D0C3C9C9268C7F80
+:10DF4000595875E525B9B4FF474A25F43754569416
+:10DF50005E0DE5030E327A71DCC6F047E1E4AFA056
+:10DF6000FC907D90F9138A48D0EDA7E503DCC49CB2
+:10DF700008FBC7340A60985F1BC70FF70F1415051D
+:10DF8000BC0054BB5B8F47A7018F46BC5A73391E38
+:10DF9000F3493EB3EB98FE58C5EBACA91885F6EBF8
+:10DFA0004332F19A87F7C4D77EAA3F2A54FF0B5019
+:10DFB000FD11D2BF53FD11D24EAA3F426A574A2FDC
+:10DFC0002BA2F30D24D17E81FF268E5E04E7038F02
+:10DFD0008CBBF9CE7FD174343F67A3949F5046E148
+:10DFE0005A0D5CCCF2AB15BA671E281275F915896B
+:10DFF000927A8EE7853DD59E66E2E73CE5F7427969
+:10E000005BAAC4CFF5583EBB80E8F29D134DBAFC25
+:10E01000053B34FD0F04FC4461BE20F7B9D55E4DCD
+:10E02000F9B23C9AA7E57BB93E5735CFE4591F8139
+:10E030007EE7E432BD4AFA8178058AAF2F7308DAA9
+:10E04000E9A24941F94DF224795384F83442A81CDD
+:10E05000D4DAD73954AE6AFC23FBF3B85FDD53CA78
+:10E06000FC6C24FCF3DD181E6745E07B5B00F48844
+:10E07000256F5FEFF693DEE5AE39553AAAA5934BCF
+:10E08000543AC825B930FE97A4646F29D059FB28AB
+:10E0900009E8A188F301E17A1CAA8A947E5E3871AE
+:10E0A000FFEB8A0C765AABB32517E37EAEC8D5F8E2
+:10E0B0001B1627CD1A05FB991AF7434885F313BAA7
+:10E0C0002EC17BA509F4B6DEF514897CA2814757E1
+:10E0D000D58438D8076C5C8E1BEB2F6EDAFA168C61
+:10E0E000BFB4A903535BA207858C55F2A2FFC6EF0C
+:10E0F000AAA985795907D2728D1CB624D2763A3BEB
+:10E100006020D3BB543C3889491BA7BAA66D644C28
+:10E110001405461BDD2F403EAF095447C3386DEE52
+:10E1200091A7F55F9D894F36541C2089148ECFBF6F
+:10E130003DE9F5C934DD07FC46F7C1E738DFA41730
+:10E140003FF3CEAD3A7E399C5066D3F2CBE1D54A4F
+:10E150008E965F58BE777E29B917CA3B53255D3E20
+:10E160001DF84593DF10E217960FF30BEDBF84CA3D
+:10E1700085372D985F9D7B78B557537E67DE613D6F
+:10E18000BF8C173DEB23E801815C26EFCF35BFDC68
+:10E19000C7F7913EF3CB3FCE8E5F9ECEE57ACECFD2
+:10E1A000E7971773937E397EF1F4915F3C3DF9E573
+:10E1B000EF3F855FDA9C7E8C076C9B6CAAF445C0B0
+:10E1C0007703978FAADF7B34F753944F53AE1E0625
+:10E1D000FA2C8F5B53E369DAA6B1FD7B61D504DCD1
+:10E1E0002F37EC63FBA5BA3FF3A35DCA4FCC8F3149
+:10E1F0003AC0F6CDA46201DB4F52049F4C7F6DA361
+:10E200002A413FD8AF4B04D22EC352E757E50A61EB
+:10E21000BD898E877AD3236E16374B0E327DC74A5F
+:10E22000FF037ABABCD8ACDB57538CFA9721AF9E68
+:10E2300063AAE7978F405C0285C7D72ADD18F65B93
+:10E24000150E6B0E96A11EF2D540CB69CFABDAF856
+:10E250007A43FA5491A734923F6C7A1E8B93B8DDBF
+:10E26000A54879A3613FBE11F75D753F37EECB9DA1
+:10E270001507F472C65BD84F2767BC85F7EAE40C34
+:10E28000CFF72A6748119687F6659E0FEDCB3C1FA6
+:10E29000DA97793E2467A0FF92F0BE3C6873E1BD37
+:10E2A0005A393307F27DD897AFCBFB65E4CC5FCE0C
+:10E2B00056CE9CE5BE5C9277CEE4CC84BC5F50CE5B
+:10E2C00054819C893BB39CA9023953A09333D7E670
+:10E2D000FD043963AFEBF2C2F9FD35BDD0BDC8F521
+:10E2E000A5D939CA0CE89F4CEC5BDCB691AEBAAA52
+:10E2F000362F4E067A71333BAFB7F6F6C6BFBCD5A4
+:10E30000A2898BB64B0176BFA2F179FC7E6DDD3E12
+:10E31000F4979D69BED3F308A6C67DB4AB6AB71562
+:10E32000E9D66DC233F19F3A8FB6C98C2FDFDCF48A
+:10E3300002EAB70F80DF2FA9A79EABE2B5AFFA8F35
+:10E3400071DC865C19D7611CFF4C744BE9F421A089
+:10E35000D393036F1B0A769E68BF2F16E0F52BD868
+:10E360000F3B7E0A9D0672193EFBB0EE977EC97583
+:10E37000FF0CFEDC0BF33ADB755F97D7E775BFF355
+:10E380004BAEFB67D80B9FFF9475CFC9256ADC0D98
+:10E39000DE9771C22F944F567F9FF721F82F56FFBB
+:10E3A00030E4195867FBB7D675E0BF20DFFD283A87
+:10E3B000B5F7A708BB3763E7EDEC1E761FC659A972
+:10E3C000B91F45C2F7A5703DE8DF0895EF8D745F72
+:10E3D000EE974E411FF9C87C9A720BF3DB19BFBF51
+:10E3E0009323B07B6C425534C4C5774DDE81F10672
+:10E3F0006D9347E2B995514F51DB753629E84F6A65
+:10E400006BF260BAB2A932007E93E70F7C20403CE9
+:10E4100058D1813ADCDF568CB97400C6F18D2B8A55
+:10E4200081FC4A839EE2E07ACA90C16FEBF48A8E47
+:10E430003FD5ADF69684FD50F784F417DA4ED6D862
+:10E4400049340FE410B29320AFB393E6A15FA11358
+:10E45000F4175AFFBCC1F356471A678589D482FE68
+:10E46000B2A2CE5419497F793727B25F81E6F1DC39
+:10E470002DDA6EF52DCA047D86D468FD6A67D25FF9
+:10E48000FE34F82CFD0A6769274D1E7C6EF4971048
+:10E49000DF72BD253E5FB91E5CB2E74A4E0CE8A3B1
+:10E4A0009C18D0534EDC3AF827C8897773587CB54E
+:10E4B0004A5F1B6437FA93DB2A09FA1FDB028BFAE7
+:10E4C00015D2FC73752622D0FCED6F32BFF09A6234
+:10E4D000E2837BB46B0612CC07DC8C0E2688B6DF99
+:10E4E000801FBCB382DA4F32F8EDAEA802D8AE8AF4
+:10E4F0009D747734A597AA628980DD34412CC1715F
+:10E50000020A8B0FADB291DF44815D354E228BCE76
+:10E51000C26F6D170B04CA91943FE578E0DBDEFC17
+:10E52000D146FF3311DF70E33D27831FFA6CFDCF27
+:10E530006B07FF6CFF33F2DF179BEBAA311EFC0C5D
+:10E54000F478DD601933C67DCAC8C72A3DF5467F19
+:10E5500036D0934669F2FC1EEEBBFC7CD9067AD21B
+:10E56000A8305D74558D898B147FA5A6B18D2FBE03
+:10E57000A5BD8F172B75607FB18DDBF0FB7D10374C
+:10E5800000EB93DC284F1F2BA37238C2FCB637CDAB
+:10E590003F08F2735B5323A61749DD6202ADFF52B9
+:10E5A00093F720C06D6B532BA6CF37B5637967D334
+:10E5B0008398DED3E4C37445D3164CEF6EEAC0F4FF
+:10E5C000B12C364E89E4C77E2E3A45FBD7D0D1B860
+:10E5D0006E3A8E06DF171CF6EACAC7065B75E5E7DA
+:10E5E0001D6AD7E547071ED4D57796F874E5B3734F
+:10E5F0006A3E01BE74146DD17DB71574E8DAF5D5A5
+:10E600002E38D7F532AC4FC1313989877B1770FF6F
+:10E610000AEE0D513E4E69A4E295E61FB5733F47E1
+:10E62000073B274F25A11FA44BBC7245EB77D95957
+:10E630001C64731A6BDFFC3B967F349D9D1FA97190
+:10E640009AA23544D744480E9FE73F6AE7F7947291
+:10E65000585C6446810F3C12240302D4E03CA48839
+:10E660009D93A9E7DECDDCEFF0A8996C15A83ED903
+:10E670002CB1F9372BC4B790D66B2E60F9872A8856
+:10E68000CF04F357A8144FD69C7337EEFE56280CD0
+:10E690009F9793210A9ED788FC9C3D74EE1DFD4FE9
+:10E6A00082E7FA1C5E8B623FC738DAF8C66E01F863
+:10E6B0002BA5B1BB0BE6F7E8EF2D72247BA8EBF797
+:10E6C0005FA701DFACFDDDD769C0EC6B43F133DD43
+:10E6D000D1DAF8990C0E97B58D5918BFB0B6D6A1FE
+:10E6E000BB07A729C77886AF6AF9FB044442BB6819
+:10E6F00080330C579F1A3F2242DC1D5D7F76F8FE67
+:10E70000E9CF8DAF59DBB880C5D70C243CBE66126B
+:10E71000DA932A1ED6423ABCE7BDDE5F3ABEE68CEB
+:10E7200071358638071DFD42DE6BA46F19F112C5E5
+:10E73000E95BB88BC545A419E8468DBB50E9528DFD
+:10E74000CF50E335D4F80D0B8FEBA0C3F2B8E6C879
+:10E75000F465D9415C70EF4D34C5B8D7679E398EEA
+:10E7600060812B8B6F0EF387B37E59FCC057839566
+:10E770005B5C49E17E07B8945B5DA3C37935DD003E
+:10E78000BF8EA55DB88315A0AFE6172BCD709F2F68
+:10E79000A188E03D9DA26201D3FC832CBFD82562F5
+:10E7A000BB7F77317F939ABF5C515E85F671867629
+:10E7B0009787DA99B1DE932EA6E73DE992D8BC7926
+:10E7C0001CF2244EDF4BC78A2C3EBA426072030E05
+:10E7D00054C7F0FD90C2EF72E29C92A3F1BB5EC100
+:10E7E000B1B5B289C5F7A9F1D07F7F53C478685B12
+:10E7F000B1A71CEE9E8D0E04FC70BE5EB491381362
+:10E8000064985F50017E5C987EFF0E888778EE12D8
+:10E8100076667BF941A62F5C517C33BE37E2F84E19
+:10E82000447FACB3C4EEF6C14013CD6CFF57E3A1F7
+:10E830008BF5FA4295415FB8FC0CEF7F24906E2F68
+:10E84000EC935B5C067F2C7F07A437F91D7E078461
+:10E85000C98722DEA7ADD8190DFEEBFC8326BCEEDE
+:10E86000296E5444BC1FDBC6E23C9E0B784E7B1FD6
+:10E87000753F876380CB89BFF338C94E2E27DEE50D
+:10E8800072E210C8099ABEC5E3240FF23849E37D4D
+:10E8900089B6A6CA035A7DC798DA05BF07E3A04622
+:10E8A0004804EFDFF5F2DE87DD4DFBD1C5312E44A4
+:10E8B000FAD9197F7F29EAA31E13EA95F7952869EB
+:10E8C00091ECBBFBA6949D36FE7065D3D4032DA7B7
+:10E8D00099A7C3A2B767D4F45B977A3FAE1DEF5BED
+:10E8E000A42826027155695619EFFFADEC52CFF7F7
+:10E8F000ADBE68585F9D8DFC5313A7D23E2DE081BD
+:10E90000F2154512DECF51FB8D2BA6F3D1FAF92B70
+:10E910003FC278E995E382A9A0CFDC37F693A9B985
+:10E92000102FB24F2440063DE6ED62FE76755D295C
+:10E93000D27C21529C7A6FEBFA90B757E3C58DF0E9
+:10E94000EF55EF808880D3DFB7B2E427F58CDFEB9B
+:10E95000C33CD16EFD76CBFCC970BFB7AFEF5FC4CF
+:10E96000723A4C9B49A2819FCE448F3673379E1BCF
+:10E97000DD3333F2B951763EC3F73D25FBD9FB2297
+:10E980000591E7D1935ED97C5648B47FDA6F7B4915
+:10E99000E4FEAFC81754BA7E07E4557BA509F50A13
+:10E9A0003B159F10176F1F47F520F0E328EC9DA241
+:10E9B0002F4BD8F98C515EF418BF84C257636F1B7C
+:10E9C000E55071BE4D671F9F1C3839CE1F89AE7848
+:10E9D000AAC25195433DE148F09CA91DE088708A88
+:10E9E000CCD7617C2D540FD16ACE705F6F5224FA60
+:10E9F000E90D0F467A5831D313E70778BDFA2D9108
+:10EA0000C1B955A2E7C7DEE06784D7F5BF30BC8C3B
+:10EA1000E517E773FF481FD7D9E77A542F726AF4D6
+:10EA200062B8142DD1FC389EBFC22B041FA2724BBA
+:10EA3000D8F637D47BC6F1F40A48E9FEB84DF0FFAA
+:10EA4000F31FB4718920A703D2AA5F1A0C1E32B239
+:10EA50004498AFD37F960BEE432FA35FA8BB1FD480
+:10EA60001B4F6A2486641FAEEB6F42B01936AC2B85
+:10EA700089B218D27AD26E8176F59D7F3B04E3D4B9
+:10EA80007746FB45704E6E351FD3FA8D666BEF8F60
+:10EA900064C22B1A1D964C3A9FB95BF4E7A4752407
+:10EAA00080FDCDEBD07F37DE1F11440A18789C2003
+:10EAB00014FF5A82F1BD249A954B439C5CCE75E7B6
+:10EAC00069DF33ABE5F0AAB5DAFCF0BE10F1E9E797
+:10EAD000297139B48BCA31EB48BC0FF3A77CBAEE6D
+:10EAE000234EABD744F5E5E4849A7A80C78D44B6CB
+:10EAF000B094E90DEABA8893E173866DB205E03B04
+:10EB0000A3D5B80EC502F3B9A9FDF4EB53F1FEFF8E
+:10EB1000F209C2BD355FC6745ECCC43D0A14170548
+:10EB200032B4EF4134C0FE00FC35BF9F8E7FDF5012
+:10EB3000E99128625FD6DF13AE39E82753E1DA3B6B
+:10EB40009DEAFD642F44B37953F8ED0539A0C28FD7
+:10EB5000483585D0AFBA9E7F8D0E6CF6C3B9AA9D9D
+:10EB6000BD03F54142CD9B00EFF443C14F043A751C
+:10EB70006293F3609D9F6F3DF29698155E1F21C1D1
+:10EB8000FB213EBA76ABE85C0EEBD9FAEA21A0F79E
+:10EB9000DED6A5C6C7527A40B8D1797D14695E9F8A
+:10EBA000FD96DC007AC978B140E747798EEF276B94
+:10EBB0000A3C87617E4507063A60BEE6AC8EDDFD05
+:10EBC000E93CBA6F1730AE36512415003F351EE1CF
+:10EBD000844D423B3B31D62B3A68BEFB46E25E0F8A
+:10EBE000D370CF7703A988E905EEE5946E926F178D
+:10EBF0003D204FDEBF6D46FC0C9A26DB67C667D30F
+:10EC0000F4A228E28DA6FD250B264F073AA1A6C740
+:10EC10004FA1F3BC2E8ACE93E6337F1BEBCFA6FC2D
+:10EC2000F6570BB102BD26C6D6AC1A0FE3C48B381B
+:10EC30009FA3544F94A81C2BBDFACB51563A5EFFAC
+:10EC4000EF6C23613E698DE5E49F1494FBF3995FBB
+:10EC5000F1B327BF1905F7C0C51F6D6EBC67CEE9BC
+:10EC60002F319BC1C388EFAD9CAEDE8B61F64E7D2C
+:10EC7000926509F8DB3FE7F60F515C682FDCC6EDC3
+:10EC800085F762981DF45E9EEA5FF22769F5DBFA6C
+:10EC90006825EE2A301EA89E04F1CE5F3A95B8781A
+:10ECA000A8473CC8B7B771BBF973422A81CE6F5BE6
+:10ECB000569E9240DB2735333818E7377808DB9FBC
+:10ECC000EB4E5182D6F8CFEA24BF05F486BA53162C
+:10ECD000DDF7F7A91EEDD5DC57BFEEF0C1F130BF6F
+:10ECE000EB497031D4BFFEB658E6B8E7FCDAC9E7A5
+:10ECF000D11B5CEAE325225178D40BC473BA7A2F76
+:10ED0000FF204684EFA421AC3CA93CF2FAC60F6177
+:10ED10007A5FF9D2890F009DD507CCA8CBDFF662C8
+:10ED200069CAE9F4E7FA5317109FC6FF572F051178
+:10ED30001EF5A72EC4EFE54B8F5980EEA11F997EDB
+:10ED4000BF2D5A49017F6D6F70DECAF5A0FA53F1ED
+:10ED5000C4DB4FFB9DF177B8FF442CFF3387DB9F6B
+:10ED6000F7982A23C5772DE0EB1E92247940EF1AFD
+:10ED7000EA27CABA08E3AAF5921322EBC5EABC3A1D
+:10ED8000CB82D7C3BCCFAB204AA4F1667238AAF3BA
+:10ED9000ED4C08CEF2207D76E7C13B13A1BCB33B1E
+:10EDA00043FB8EC4235C1E745E1ACC80FE3FBF24DE
+:10EDB000F2BD1D15CF63B8BEFCB7849A4E901FD329
+:10EDC000AEA2194A1F29D3FC26763F85F15B6FF866
+:10EDD0000EC35924BE51A783B305CBD5FE8EECE7F5
+:10EDE000FC48ED708853BF91CBFF1B37CEC5B827C9
+:10EDF000554E1D795044397504F7169AFA04D45FBC
+:10EE0000A7D7509D8ACA95599BCA77C37670632A43
+:10EE1000211726B0EF7741DA62D6F9FBD5F1661CEF
+:10EE2000F2A09E35B34DBFCFD592B62F403F38B23A
+:10EE30009FC903CADF1690C7B3EED3F753BBF1B235
+:10EE40004F617EB506BB3C99EFCF463DEFA121DC7B
+:10EE5000BF3F868C391BBBBC9E92C510DC173C2281
+:10EE6000CC63B4A47F674B4DE30A199D2CD874D2B0
+:10EE7000E2907BEFF728952339B4DF63D41E87F443
+:10EE8000C521CA934368BBE3FB185C5E1B52F30CBD
+:10EE90008C777C1F5BFF89BA13B3E09D183295E92C
+:10EEA0000D5170F980FE1A75ADD5D74CD7BB948A39
+:10EEB000A968B81714C5F411550F13C55B45072D84
+:10EEC0001FFB5F33E3619D898F5F5C09FD253D1E5C
+:10EED000AB00DC96972A2340DE2FAFB2B9E1BECA61
+:10EEE0003A4A86C5B4BD95F603FB89EFCF6377C078
+:10EEF00071644EC7AA3278F7C5B9ADCB3F80AEABCF
+:10EF0000D5C4DEC968BD90B89B4978BC866D55CF25
+:10EF1000C0BC3226D3FD41807BF4CA08A7A67FC2BD
+:10EF2000F5AB7A8E93E3AF0CBEE702B897B04744D7
+:10EF3000F5F1445D16DAF54308A32735FE1EC60633
+:10EF40003D5285DF31BA5F114D9CDA900EC16FA63C
+:10EF5000EB9AD7F90CBEC751B7C89F7C2DECB78F81
+:10EF6000496C1FE5F34BFC6B5A99EC08EFBFD70ACD
+:10EF70004ED423553DF96AA2FE14A0BF702AE78340
+:10EF8000ABB97E7C6D2C83F374E2CE8076D7588942
+:10EF9000C34461766D79C7E8F9B0EFCE35C7837E9B
+:10EFA000036B8984773535EA412A1FD66FB67BC15A
+:10EFB000EFFAB9D09D079D1C35333EEB7E25CAB7CD
+:10EFC0003E33427F7CFFAACFE37A5D0E51E0FE40E4
+:10EFD000FDF6C1781F2C2A86E27124CA3F2BE0750A
+:10EFE00017ECFF74DDB35F8EF6E3BD30F5BD32275D
+:10EFF000F1DAE9380DDB53D6839E9198AD8C5840F9
+:10F00000FBFBDC1CCC407941E59B40F7D6D4A14BFF
+:10F01000A64894AFEAFB53BD8BE6C73F7EEF148949
+:10F02000D2637D56709689E6E73DFE04CB0F097EDC
+:10F0300002F93B1E7F81D51F199C25D2FCEAC777B8
+:10F04000B17238C3A684B5F6F137A680FD7F349E31
+:10F05000E90FC41DBC1EE8A7FEA5C1A6E59AF5DE12
+:10F060003D94C9D1A3D1ACDED14C724335C0DB1580
+:10F07000CCABD69CCB350C0DF96F589C165FA7DA3C
+:10F080008EA446EE7F306F37BB9CD5BB2896B44626
+:10F09000B3FB755ED0C7766E1B8C70B10D4DE0F082
+:10F0A000A2FD1485FB51E1A8F6A78E3B07F67590EB
+:10F0B000FB662AF73572A66828C31B1DA705C7295A
+:10F0C0005046C03B56F5D5034700DE28BE248E2FA0
+:10F0D000C98A8FABAD63F3A3FDC617E23E330AFCCA
+:10F0E000CA3BBFA3F533C3F336D287C2C799DDCC81
+:10F0F000EEF777C767231D5D14CBF4455244E14713
+:10F10000E5D9EAA16CFFB97B683C5B5F080F290277
+:10F11000F6DFCCE13790D53FDBF556FF42EBD5E08B
+:10F120004901FFCACEADF98827753D84ACD2F5738D
+:10F1300074A1A15D31653C98474236B65B1A4DAC6F
+:10F14000F89DAC0FB5CBA4ED2E2AEF1E05FC308F39
+:10F15000EBC3C47B21C635D4716931AF356001BFC3
+:10F16000F4BC0EE6272739747D401FD5138BF8FABF
+:10F170009C7C7D4EB63E9F8E3EC9C1EE8CC9F69EEC
+:10F18000741B827BA8BF8291BC3F1D3F47EA0FF8EA
+:10F19000A2377CB40C65FBD439C3873A4F033C4398
+:10F1A0007036CC4F8527F031B62BD0F3933ACF3B56
+:10F1B0007AE3E7CC9F385E296B37EF77148FA0FF97
+:10F1C000C87A7A9ED799699A5E106ED7DAB1D00361
+:10F1D000723E5690991FBCB3CA0BFB5FC3B652F484
+:10F1E00053CD7BE1C9E7BDB4FD9CA7D73820B8EA71
+:10F1F00088D49E0C7A70DDA6C50E781FEEB0E4753B
+:10F2000080FC3CE21323FA07FFC1F1A0EA5DF57C24
+:10F21000BF39FAE7BB27013CBEDE64C67B860D5BC7
+:10F22000A2FC51E837998DFA18CD7FC8F24BBF0088
+:10F230003BB661AB5E7F9AF3A735C9E80F23DE01C9
+:10F24000263C04F30F80C3B0FA8D663C4FA93F28DB
+:10F25000BAE930A481742F81F919DBC33C4E51BC4B
+:10F2600037748837427C9FB19C4A12D4C71A3AEF50
+:10F27000463DADA1F3924F41AF6830C453D4F6A2DE
+:10F2800087BD3194EB61FC9D74153EC49784FA4DA3
+:10F29000F3630F147E48E7756CE3EB0EA140BB6F80
+:10F2A0002E423C9DE898B1F625B9F7FDF573D00FD5
+:10F2B000A2B4ED187EE5AD023B18DAC6D23AB3DF50
+:10F2C00001FE81BA756637DD8149DD931B36FF117A
+:10F2D000ECCB77A2DC106A3AF7C95D6F9D4FF373F0
+:10F2E0009F31274E64D3B7C139B78A2788D9003DEB
+:10F2F00045C5CB9CBFECB2C8C3D877D07B55FCCCFE
+:10F300007DA6CB02F7FC8C702CEFE8B2603CAC1110
+:10F310004F1D1F4E0015A4F9B16F2C40DF47B60BEF
+:10F32000F8EEBDB17DEDBA5D0EA0438013D8A12AE1
+:10F33000BE42F8EB8137FFA4978AB01EFA43CE8411
+:10F34000BF270047A391CE9F7A09FC28EF46B90159
+:10F350000EB54FDDEA80F57C2ACD67F4FEC8E26485
+:10F36000782FAFD6EC4D7662CABED73E7A3BD2E15B
+:10F37000CDFB6E4F66EF482869EC1D4D6F1AACF35C
+:10F38000A687A7E03A67911AA4C3DA47987FE32BD0
+:10F3900089543E13815FA614B07DE4D3F551101C4F
+:10F3A000443E8573043837D92FE2BDFB1EEF22910E
+:10F3B0000598FF8AFB17F20B42EF1F5A41BF6BE023
+:10F3C000B51A362E0D009E8EA62B29E0B7A570F03B
+:10F3D00072B809F0EEBBB86F7C0AC31391E13C042C
+:10F3E000DB517DBC1CBE43FD8059892ED4B5E3EFB3
+:10F3F000DBB0F155FF069D770C9CA77F9ACCE2F21B
+:10F400008CEB6BE1EBA33F01A2A5B3DEF87FE33207
+:10F41000A4AF2F0F32FEA9F755556279C0EC4F818A
+:10F42000725FD76401E54394EEFC3C441F1BCD9C06
+:10F43000BFF5E5749E92A085EF7601DFD354E965B0
+:10F44000D67D51BAF3FA30FDE8DF8B52F955B5B3EA
+:10F450006EE6F2C0B86EA37CF01418FE8EC2C349EB
+:10F460007DF27FD7997D9BFF08FC4CF9D72B033F9A
+:10F470009BD13FF0D913AFBE750DA5FBCF3A543EDB
+:10F48000D6CB5B231FD73E3B9A44E2E3CF6C6E1290
+:10F49000918FE9F7887C6C63F7A6FF7FC9DB9B7BC4
+:10F4A00091B7FF56A097B75F9182B80B08EC337302
+:10F4B000F1BD57237C55BBD72847130AE4887294C3
+:10F4C000FE1C241A78AA7054E973CEE3F3709C10E2
+:10F4D0001DAB74AAD271884E8DEBD6C3D3587E2152
+:10F4E000CC5D1307615E44ED18D0735F117DEBE9CD
+:10F4F000D48ED3B92CA1F03FFE4426C61B2DE67650
+:10F50000C07167B703E2C71673BBA31BFC9271E11E
+:10F51000EFDDD14C5F3AEEE976C46BF4A60FB78904
+:10F520000ED0F3823E5219C99F442536CE23487A25
+:10F530002B67E762C7B93FF438F7778E176D198DDF
+:10F54000E0076E677FF764E6C2AB1C702E707C5BD1
+:10F55000F63DC07F37BD26B2773DBD8A04711233B8
+:10F560001808C861E2BDBF84AE73C6B6B918DF60C3
+:10F57000F4A3CCB26DC4F385AFC85D981AFD2773B0
+:10F58000C0CF02F4FEB0E1FBB6CB90BEE618E8AB0C
+:10F5900006E82BAD277DED56F9750419A1BD7FB6A0
+:10F5A00080CBBDF162C13DA0CF1CA7763EC61288BC
+:10F5B000057B61DFFD0AEC7E600C6F12D2EDDC9AF8
+:10F5C000C316FE8E33D2BB4A87467BDF981E7BEE86
+:10F5D000FD3177D22A75CFFFA3F0219A1E7BFE9DC5
+:10F5E000BC9721FFC2DB19FF203DEB976FFF16EDA3
+:10F5F0009BE3DBA3703EC7B7FF2DE34EC8BF148566
+:10F60000E7AFC71745615C9477BBDD07F7F98EA7B5
+:10F6100033BF5DF32BDF1462FC0569617A48818595
+:10F62000A5DBFEFB03889F3EB12D4A063F45C3F68E
+:10F6300058B4DB1B5E8AC6B897E3AF7C3346EB67F2
+:10F64000FAB9EBA9E7E7FCC7ED64EAB340CFF1CC28
+:10F65000BE6B7879EC0688979BD7D96581F381F2E8
+:10F66000BF7E5F0872E9F8B34CFFA0F6FCA3F0D2AE
+:10F67000E1F70575F79B29BC3F071D91DAE17F187B
+:10F68000F6E4956087F7840B83C3710A07581785E2
+:10F690004B2DC8D3DEE09138ECD70A8F2FD0BEA80F
+:10F6A000DB761EF251182E82C2BEDB7D5601D7CF0B
+:10F6B000BE6FFFA610F4A9CF3A16A25E70A6758F92
+:10F6C000FA3FB76EC1DF977557C3BA937E8DEB666D
+:10F6D000F47F88EF57463EE849E72FFC16F34FD9F1
+:10F6E000DD38DF3EF2FF82FF6B787F56C073F9335F
+:10F6F000E17DD5FF5ABCBFC6F16E77427CD9F15788
+:10F70000BECF209AF59F69DD1DFF4BD71DD28F44D8
+:10F710008F159EB86F23FE00DC5F5FDC8B9EF2FED0
+:10F7200030D52FC1EC10357E474C9C837A8698B833
+:10F730001CF586C584BD83EC954DFC3D3616F7DD82
+:10F740003AD0ED43BFA8E4A95D47F3E64175EEE585
+:10F75000D883DE3E13932756829FA579219D17ED0E
+:10F76000A739C9E46C96E19976933FAA10D30F218B
+:10F770005D9A7CE91E1857B2E9DFABB519EC8D989C
+:10F780001C8B3EAE98EC70C27975B45B82B7DCA975
+:10F790002AAB7FDFF6E5612CFE2386F8306EF36C32
+:10F7A000E1642FD4DB6B463819E1A3C2AD079CB8E6
+:10F7B0003DAABEC72F252E0F001F4A84DA936C3D49
+:10F7C0006887C2DF9182F31A73DC2CF772769E226F
+:10F7D00087DEF18738086E6F86DE99954D6897AAA7
+:10F7E00070D6F487EB37C2F96CE1ABE2259A54236B
+:10F7F0009EA307DADC3E3AFFC53283FB620A7778C4
+:10F800005F5C85AF0A37231E8240A34961F88753A6
+:10F810007DBC8EB78CB8E09C65BC5812F482BE5C8F
+:10F820001C8BFAF23181F8056ABF1D2B4D2E03BBEC
+:10F83000E258BA4582745C375D9366BE179DB28606
+:10F84000FE861EE44B49BC2E7F2C3D0FDB975BD31D
+:10F8500074EDF642DC36B5DB8FA5155BF13CD4992F
+:10F86000A96B3729D6B11ECAF7421C378E3F01ED6E
+:10F870009B8B53F375FD4CFAE8D8C337D2742BB782
+:10F88000ABBBC799D11F7FECB5696500C74BE411CD
+:10F89000BAFAFB883309888AAEAF02D677996BAC87
+:10F8A0006EDCBA0F77E4811FE237EE52DDF7CB8BC7
+:10F8B0002FD1F5E3B106FD40DE554A95EE7B5DE3C1
+:10F8C000D744EA47C8058DDF11691455DFFD1DBA1D
+:10F8D0007E46EDD9AAABEF0E38CB41651C79C8FD49
+:10F8E0002AA46A3CBBA59FD56BA2E9B00FCB4438D4
+:10F8F000F71CFD714D33B8A12F38465C4007E791E6
+:10F90000183C0FEC2DEEFD1B93AF06D67987E873FC
+:10F91000411A33605621ACEB486A9B08C7D20F09E5
+:10F92000355714523E1BFBA5AF19F2177DD7218224
+:10F930003DD9BC45C4FB75E3C589B1FF09F2B843A5
+:10F94000C018FF3A9B09FDF09F257414DEAAA13B65
+:10F95000356EC7C8C7FD4795DE5448E9AD255569E2
+:10F96000EF02795AF6FEF56284FBAEC4A97F97AE2A
+:10F97000FF284F2B9CD3AB714931E5220B6EBFD8CA
+:10F980008CFE9225267734170AB8EF3A2798D701CC
+:10F99000BF7FCFE546CCEB44067F504CBF1A11EE3B
+:10F9A000D9917B048C6B51C79B51CCE2ED9714AA83
+:10F9B000EF9B3893AE1B06EDED2C5E007C69D06E9C
+:10F9C000A209F594AE719FA2FD1B73B9291DEEE14A
+:10F9D000398A95D773687E4C607F3ADA59A418E368
+:10F9E0006D16F0389994B6CC077640FB3D668C3B9B
+:10F9F0009E314D399943F32B27B2FB819DC565B1EB
+:10FA0000C334F0739C1288AC892BF8BE50C6793889
+:10FA1000A420DE0F739C92B09C044730FB8F8FE3D1
+:10FA20009826BF7DAB661C22297361DECB87BC277D
+:10FA3000831C731C22FCEF8804F1EFE4413C123E6E
+:10FA400080260553AF8B70EFEEE896D1F16087F713
+:10FA50002B75E33DC17E4F8AA17BB2201657C23F72
+:10FA6000788FB6FAED0A5ABE0564232BF7134ACFF6
+:10FA7000CB2D6A39152D2EFECE2196575F55017874
+:10FA800014F5F5876785EA2BD6D470FFCF1456BFDF
+:10FA9000DD52D013AE5DE3A2707F8EA17400FAE553
+:10FAA00082FC8294D3C5E93B4EC59E01AE0E06D7BB
+:10FAB000EFE82E901CF6277E2CC819405FF7C2F5A0
+:10FAC000006A37AF8EAFD90A741C23FA87C1F7E9F1
+:10FAD0000E25651CA5B74E8B92F13BF48B4463BC9D
+:10FAE00057D52D9F3D0857C41C938EBAA866433A3C
+:10FAF00025257624F8A59C5FA31C50E3DAC270A4E8
+:10FB0000F44BC75C690AE7412E38C27055E06DE0DE
+:10FB1000E51A385B69BE8AC3F5E45333AF4238CD8A
+:10FB2000B4225DDCCA79A8259EB4435CDD49E7E6D2
+:10FB30002B811E4E6E3163F06A2714C2BEE9B2B249
+:10FB4000BFE393184C85BFDB326C9F09FD79EF5101
+:10FB5000FA50803EFC2310EE6A7F274BDE4E80FB7E
+:10FB6000122713A50480CF9CA005E1769D44FCF0EC
+:10FB70005E6A67E2CCF2525ADE7948C6F20EDECFF8
+:10FB80009051CAFB85B88FF3FBBECAF922BC8FDA4D
+:10FB90001BBE8CE7F7E00F3E3FA1773A6829B5E23C
+:10FBA0007B430DC50B0B605F58109F87F1570D15F8
+:10FBB00002EEBB0D8D5F22DCD5FEA553229135717F
+:10FBC000524F80F73049F36EFC290B96D7359E448F
+:10FBD000F94DA793097C738C9F6FB69BC90D553463
+:10FBE000ADFB41BCA1CA86E794ADB07FD4911D9610
+:10FBF000051AF9473ABE08C9FBE11477F74EDC1F36
+:10FC00000372B54A704E8147062EEDF05F05E7F7A7
+:10FC100055D1CE2970DE9FE4FEF355707E5F95EEE0
+:10FC20009C02E7FBB94FC74EC5F234E71AF84BA068
+:10FC3000D5EE5C96CF74BE09F90B8797B1BC9DD108
+:10FC400041CCD31953BDB87FDB102E275A637DA753
+:10FC50007B77E4E6C6977570E9512E0A180785810F
+:10FC60001A947EFEB56C007B073727807159E9C373
+:10FC70000535FE8B142784E37513B38902E7A98940
+:10FC80002F44B3775A3F0E6400FC6E7E21DA0F7E5C
+:10FC9000C8798FBC6A81FD67BA28E7015F8D1F5D57
+:10FCA000933D3C09FC2501CCDFDCB81DE775E74836
+:10FCB000FEF7AC9CDD05E0AFAAE571CEB58678DF36
+:10FCC00039B69DE87F9BB351EF679B4B821F009F26
+:10FCD000D63D71FA38DF8F4C6C1E1287C7743170B5
+:10FCE000BD85CD6BCC70389F49E8C23863C91948CF
+:10FCF000AE41F8D6B9D03E498DC17B344BFABF5BDB
+:10FD000018E97D988E26BADF53967BB6692BA6D26A
+:10FD10000882EB4991821637EDA79ECBE531818FA2
+:10FD20002CDA78C12B385CE3B6B2F36E631CEC15A9
+:10FD3000C3ED3CBE9D9D2BCFAB7EA304F0A2E2F3AE
+:10FD4000A258D281F1AA09C4CDF1E206BCA8F00FF5
+:10FD50009F2FD3769991E842853F61F175314C5ED2
+:10FD6000743F178DFA9471FE757CBEEA3ABCC39954
+:10FD70007DD3DBFCBD30FFA4733F7FEF7059F7DE0E
+:10FD8000ADBA0E958F43F6E0C2C87A8A3AEFB3A7B0
+:10FD9000B380A52F74A6CA997A52E3423F2C972BC1
+:10FDA0002A9CD579AAF0EAEC25BE556A7C51B71E8B
+:10FDB00029508697E31F19CEEE374A1D9760889524
+:10FDC000D4B80DEB9DED7A5479DBDBBA54396B5C1A
+:10FDD0009F2A6FD575AA72575DEF382A48501EC208
+:10FDE0005B0F02D80B353AFDB7146E2868CF7DAC97
+:10FDF000B7E8F2E39DBFD3D5BF3875A1AEFC127949
+:10FE000099AEFC32D72A5DFE37EE3F18F4F875BA8A
+:10FE1000F22AE5315D794930500E7AF6DF9B2A31BE
+:10FE20007EFBC2C3DDAF42DEDFE4C4FC8EA6544CD1
+:10FE30007736C9C8DFBB9B5C98EE6972E3F7FF6851
+:10FE40002AC6F48D2605D340930753A35C98F497F4
+:10FE5000AB24D0D38B03EDA8FF678DA83906F270D1
+:10FE6000AFC9D76CA7703AEF3DA68F139F713FFEC5
+:10FE7000E6833B615F77B27B4D2D5D630539823E42
+:10FE8000E7A0FB9DA2A117C7C42081F36407891CCA
+:10FE900067F9C570768E8BF1799436A75AD93BB63F
+:10FEA00053A70A188F3895B0FB0934F5D7D0F2491B
+:10FEB00012F1C2FE5F6593F0FC89F0FBC253D834A7
+:10FEC000E13D756F14ECDF89FDF07ED264F848E700
+:10FED0002B2A22C6B14E297E1DE3FFAEB1B1BF93DE
+:10FEE00075F59E45FFBA93969316EF6876FF417DB0
+:10FEF00027E45DD3D9E80D5FC09D02380F12DCEC1A
+:10FF0000EFA4C44B6EADFEAFA6BB8633FD7F52336C
+:10FF1000BF1FB08FA01EA7F2235D5F2BCC5FE58BC8
+:10FF20002AA7E41FEC80FD7E5539D4AF3B28235C23
+:10FF300054BE50F940B5FF543E182F3ED10CF54F3A
+:10FF40001C62EF929D77ACE6F05FE838FF03F207A2
+:10FF5000233E0080000000001F8B0800000000000E
+:10FF6000000BB53A09705455B6E7F5EB2DA4937420
+:10FF7000428084CD0E110C64EB74D210B6E1911066
+:10FF8000DC101BD42F20420332614D62C02F8EFE45
+:10FF9000EAC63018F8D69F8C5A7EFDA2D53082CCA6
+:10FFA00068151948303343B0418D30E348545090C0
+:10FFB000882D322CDF848E2C223354F9CF39F73D33
+:10FFC000BA5F2761B1BE49A54EEEF2EE3DFBF61ECB
+:10FFD0005CF95182BE002BAD00E00028EEAC2B4D49
+:10FFE000C27F0B82F560A439FCF911FF0AF7358155
+:10FFF000312B321EF343FDBBB46FB7CF0B4613C09A
+:020000021000EC
+:100000002EDF0C8641DF22300E05D8EBABE2F17B10
+:10001000BE553C6EF1F919EEF3D532FCABAF8ED77D
+:100020003FF4BDC4E38F7C0186ADBEAD3CFF96D3EB
+:100030000ED007E0426B693F6F0E409A3A06EBC460
+:10004000344F0242A38033082117422B9852531198
+:10005000CE909C35C0F37E486118F4E2FAB2B4BF8A
+:1000600080B137A3EFB122BD0F80FA93DADB08230A
+:1000700001EE0741FF03C57FBB2C25D2C09B251590
+:1000800001CC4AEB05EB258087C09F3B0FE18CF24A
+:100090003AD35889D627D94F223F24FF17861FB35A
+:1000A0009127F433A12B4444E1A4C6371960896D2C
+:1000B0008D19860020978E8790BF0690E0C70C8030
+:1000C000C5103403ADBF6E3A1E8AE2F352800CC8ED
+:1000D00044FCDF32F17E6D1EE8F9A873E552198AFF
+:1000E00053886F0EE6D37208F17916F95167958D32
+:1000F000EEAB33D339B1F72EB1BD67C64137F7B692
+:10010000F2F3D7BB57935305C03CDABF264DA9DBAA
+:1001100083E72EEFD536473674C30FBBB1F3EA79C8
+:10012000C887DAE1F8BC1BF14F9864F5229E65B2EE
+:100130000D0C28C770400E58F09C45197589742E17
+:100140002A6622E0FCE26699E50146C5988E722B8C
+:1001500057E5D60EC1CF482EE5E3CAA700CA6FD136
+:10016000063D3D4B6C2798EF176157B7F456C0B367
+:10017000DFC9895DE9AD1877FB293AAF42E51BCFAE
+:10018000235EABDAA46DEF45ED5BEA4C483D198F79
+:10019000FF8C8251C417A4C31944FD397750765A95
+:1001A000A067FD38EB03D6F74B3ED8F61EEAFFD921
+:1001B0002B38D11FEDD159F2927FDCCF273763A1C5
+:1001C00067B593EC09F584EC4893E35AD42140BC1D
+:1001D000D79658037EE467D86D37D2FD61295093D6
+:1001E0004872B90CCED5C8EF89BB3E384C7632D1B7
+:1001F0006A0B12DF9088F668B94E6817D3E34F0494
+:100200006A1270FFD836BF4C663BFAA0B7C686E3C9
+:10021000511F2A2869F433EF796492FB765F13F358
+:10022000A1DE57CF30623FB7B29D413ACE65DEB80E
+:100230009DC1235603F9B5152A4E35C9506740872D
+:1002400075DE36594E403ACE07C149F305071D35D4
+:100250008457619B2227225EEE13DE1AC27B2D8A11
+:100260004141C18D6AF7CB49386F3142D0827EC49B
+:10027000926600258AAFA32F046AC80F6A7EEDED4F
+:1002800038C1C70957EA65F25B76B377EB46E427D6
+:10029000FC39CEB9D9D115EF1D4E03EBFFB114CF08
+:1002A0000E9687CD31CC934BFAD3BEE515D29F86FF
+:1002B00078A7059F83183FADF945ED1C8D6F1A1F78
+:1002C0002BEDE751C6A807ABCEB3DF8BBDB7D2008D
+:1002D000DE7AE4BBABD451588DE7B4AF86B9D370A6
+:1002E0005C674298D375FFBBAE9216C2AF4C1ED767
+:1002F000AA105E76C335F5BA72D5777C7F8FEBEAAC
+:10030000FD95CD6EFB7C5B64DE5820093F0F46FBFC
+:10031000496B449E372AF7F19D3374716BC20F5EAF
+:100320005DDC9A889E367ABDD4FAA86E5C667F4200
+:10033000B7FFF6B4D5BAF53B1DEB74EB7767FD5606
+:1003400037BEC7F9B26EFFBDC51B75EBD394DFEBAB
+:10035000D6A7CAA0486873B952C044763613EA19C2
+:10036000CE86568673A093A1173589E07C70327CC7
+:10037000043C0CE7B8BCFF22B9844D9D7DC9EE3B1F
+:1003800076FE2B87F4A2E31763ED198E485CD6E264
+:10039000F4CDC6E35E66945337FA905860603969CD
+:1003A000FEBE47F9C4F8FB7001FA13C473BDA17314
+:1003B000CE5F508FFCBB2DF6CD51FE0435D240F1FF
+:1003C00058B3DB9EFC4B99115301B4C7AD06E781CE
+:1003D0001574CE47BDA13BFBD2E0D41F90D1A88FAE
+:1003E00049B343C621A86F1753144701E2EF7F6654
+:1003F0005CF2C96CD5BFDC8272F8DAC0FE0F164B16
+:1004000081A14857538318E72E4C0E489C07045986
+:100410001E0F43C84474CC05607F3B0F1C0C178033
+:10042000C272C193E3F3D0CF2C6C30BAD6235EF9FD
+:10043000299D43C8CE72471F4991F0FE3C742FA4FA
+:10044000FFF906A8A53C45C3734181F0074F162864
+:1004500045056E7AAE75FDF3787F67A30136E13905
+:10046000A7463FF14B888AAB2FBB4A46D3BE6D12DD
+:1004700028141FFDCD96C0E60CBABFB32FF9756DD9
+:10048000DF1C57E904DA37B900F87CA87F0788CF6A
+:10049000D3EC82A730A90FF3009F1B4CFEA7AB9DA6
+:1004A000F959DEF9141FFA839828E67B79FC60C1BC
+:1004B000E6196B72981E3FE5632FBBBC1EC6DF8C2E
+:1004C0002E8DF07FD512D8C47953D56009F12C7FD9
+:1004D000CD62A0387E04FD2CDC0670D46765F8A5DB
+:1004E000CFCEF02B5F1AC3AF7D0E86DFF8B2182E89
+:1004F000FC010940391E2E50E692FC7AA2A3677FC8
+:1005000021E8084B30A3DED6757D86AAD7790D2762
+:100510009E8E273D68929D431185DC465438C4FB6E
+:10052000ECAE510139239AAFDE6584475ED3A7CF85
+:100530008D2DA2E78C7609F79F6D3ADF97EC301688
+:10054000BFABFC68360B7EA8F86E4B6E5D4FCF6F6D
+:100550006B1C4218A23F00A187244FA93B3A56B317
+:100560001CF30B44BCB9D7D25964B745E8034A150C
+:10057000305E54ABF1A24CBE9218427CA6D1B9A316
+:1005800049AF6F3D40F7F9F7C93094F513E67AA209
+:10059000ECFC75950F1ACC6D367B0278FEB6E6CF73
+:1005A000A6DF8D7C983AE64EB71C656F2F10136856
+:1005B000DFE8CBFFF37C2AEFB7D355336163991D96
+:1005C000F73D64DDF33EB1E061FBD765C9389E9B22
+:1005D00026B5109CE7C8989CE22074034CCF82ACEF
+:1005E000892DA462539CD3CC94174C24A38AF29FE8
+:1005F000A5564CB274FEBAB76E7C7BDA00DDFE3BCA
+:100600001D99BAF5BBB3B275EBDABD539C85BA7DC3
+:1006100064AF9437231D2C77D82C07864AA407177C
+:10062000BE58CAF4CF2C22FAC3C83F332600A78B8A
+:10063000D7BDF83CB98DC6BD89649FB1F9E9B2E672
+:10064000DFB5288E9EF3D30AF02405A59EF3D29E33
+:10065000F2BA1BCD4FD18F3C477E247FE7FDF61ABF
+:10066000C463DBE8CBFD1D48DFDE02CC5BC9FFC500
+:10067000E4AD61356F8DD5A3ABFA2A3984FEEC97D2
+:10068000D9EF6AF96BAC1E013C2DFC8D0A6FD6DEEA
+:10069000A77E22E2CF3FC8EE7B47EBB70A0305BA3D
+:1006A00078916FC67880F2E9FCBB0C9B68E20AE2A5
+:1006B000A1C92133A2FFF0C8C6F7D38B78DE4FF96A
+:1006C0006905C5073CFF0AE51F84EFB23DEFA7A708
+:1006D00046D661E5D7BAFDF094D4A21BAFC9D08F3E
+:1006E0009F9DD812FD7C4FFEA87CC3A3662FFAE91C
+:1006F000F2172425D08D3FD2F029DB1BA790DF34E1
+:10070000EEB2705D54615740B151F68371A49BF80D
+:10071000ACF98799325475E7E72C2E91674DD91BB8
+:1007200007F24F38F708EA0AE1E37F5BC49B2349ED
+:100730000A78A2EE497109BC3B92EBFEE37BDCD761
+:10074000F1277012EB3B9285DFCD6B38653050FCA2
+:10075000EB25F425CF1E32A4200C2F8AF703DA53A1
+:10076000E5E204BF211FD787747E6645D1F7DF9E7F
+:10077000FCB215E5F685C1A08B3F61F27938CE74E5
+:1007800025CF5C83FFDFBD372E68F809F46462CCA7
+:10079000627F5A22EC7E0EE98DB84701743995BF0D
+:1007A00006ED5E85FC04D14FE3D9DB538FBC407965
+:1007B000EC7EE10770D9165B973E145597C206612F
+:1007C000BF56FCA53CA60202936D54FF07D1FEE183
+:1007D000E7B3FF092E5BC4CE6FEB6AD79ADD571ED5
+:1007E00012767F6ED7C54FC8CF9FC3F8176DF71A23
+:1007F000DF347BAF7C4966BBD4E6CFEE92EF087462
+:10080000C3E7E1AABE81E2647BADB68B7BABC75F79
+:100810009A4E71AEBA19252475BD478395B5323805
+:10082000A2EED9B6DBB228608BD011D6E26BF3C54D
+:1008300094893902AEA6F80B75AAFF11790DC65539
+:10084000532AC5D5699273338243CDFD4A887F8789
+:1008500024083A5C7CC4FD56C4EF3E711CCDDB28F5
+:100860003F83B42C23DD335D95EB7D6A9FE881E601
+:10087000078692BFFFAC61FE21059756B83299CE2C
+:1008800007C1CFF9E1A164CFA01588E7D41AA1E789
+:1008900087923BDBA9AF74687CBC5423F1F96BA24F
+:1008A000F3BF4326CFA02AA64BED2F2923E41FE355
+:1008B0006FA2EE55FD22CAD32F893A8DEDC098FE66
+:1008C0002CF70B1643A045C17B2B9C41CE5397823E
+:1008D000A8EF63F3F48A71DF9A293EC4D695139B7F
+:1008E000F61C96F2BAE947C4E8EDF5FA0FB1F56CDB
+:1008F0004F79FEC514CF8BAEA83E606CBE7E352FFF
+:10090000D5F2AACDF1814D88CFBBE3FFFBEC521CA1
+:10091000AFDC1C6FA7FAF9CC6B163FF9E7339B2CC1
+:100920000109D7CFA474B651DD70667BAE134F803A
+:100930007283E3CDB728CEFFC1C47A01E014F6710B
+:10094000554F1F3F46FEAE7A738204945F7BC5BA53
+:1009500056CBC96F24709EB078477AC02245E20C0E
+:10096000D98703538BD3AFC62994F49FD9775F12ED
+:10097000F5A1DA0D7F1CCC7D2DF9A9634FE0734BF7
+:10098000B724B8289F801C60B92DDA347C23E5C7D2
+:100990002F9ABC4D447FE91BF7F4CBA0F33FED0346
+:1009A000444F78D78EBE941F45F2F6EEF3BD73BB6D
+:1009B00032932027C227AD2F58FBFA6A0FC93D5E3C
+:1009C00072F0BC11AA9401A4174DD380CE75C992C0
+:1009D0004276D9B92E9EF3D458BD3BE01275CA3287
+:1009E000AD8FD01BAC69643F5E603E84D7656F5AA3
+:1009F0008F7C3AE54A51E375E7B0E9B9D1FAD956A7
+:100A000041F5DFB90D16EE6FB4C7E9F3060D1E759B
+:100A100025F3FE72EB055D3FA162D565FD38071435
+:100A2000F23BAE1A47E1A30857A8FCEF18E139E6FC
+:100A3000423C97D4FF76E787CC970DFFFE05DDBBE0
+:100A4000CF26FA2A1F0AFEC5D603E556D1BF00D825
+:100A5000C8F76BF3A75EFD3C8FF4F05463F6309259
+:100A6000E37CB9F5E42B48E7D984D6634F22DCBE9A
+:100A7000EF13964B2CBEB17D987649627A97111D83
+:100A8000385FE6F65C2039A320B88E9BBF3E97F90D
+:100A90005726E724911CC367BAAF57343CB5F335EA
+:100AA000FCB4F3B57D52A190578BDAE7EB30B79EDB
+:100AB00025F976ECCC96A8CF77753EA5352F394A27
+:100AC0005F7EAEFEFA2CB5CF71D8B0FA3133EA634F
+:100AD0007BFDF3266FB4DFBBC9BEFAD57C5001871E
+:100AE000BDAF08251CB79038238EC76B6332061C38
+:100AF0008F53D193081FB4CBF12A8425DE34EE9BAB
+:100B0000D37908E320C0E39A894E07C1099287FB95
+:100B1000175ADD3019AA06121D066B88FB7D6BA8DB
+:100B2000CF8879CB03C96BEFC9C0FBD6F481B594EC
+:100B3000CFAC3109BBF0CF8BE77A4EE3931667C099
+:100B40009EA38B2F6BECE030E239338C506B4A1153
+:100B5000FB6E413E1FDA37FF7DEA9F7E6EACEA43B3
+:100B6000F71EB1BD902B1928CF0B2450CDF8C52707
+:100B70007F70FF1DF71E05653CE515F77F6065BFBB
+:100B80001FDB9F58085E1E9743C874019FFB6AF4E1
+:100B90003F37EF85085D5F8DF9BE91EA8487929FAC
+:100BA00076D3F3FE12C8A2B874292E318FE85965A6
+:100BB00015F0F15E899B089EB1DBFCD45FBD143754
+:100BC0003840F1F415C97B6F611F7E8EEB58FFB181
+:100BD000F800C5BBC7656F05F79393CD20E1FE70A4
+:100BE0001F952F1DC07C099BD4FDDF39785C54EA2A
+:100BF000E27E235C72B05F1E1B13778AB20DA23EA9
+:100C0000FB51EC1FDF69D4C59DA27CB59FF32F0774
+:100C1000E7A9137E305E332E75148A7AB7A8B7A180
+:100C2000AABB7C718DBA5E034159F47944BE30F69B
+:100C3000AA7E2932C9B1421D57505C43BD0A275ACA
+:100C4000FD32D23B7697D0B3B1C6E01E82E8656133
+:100C500015E5174D18F7343CD0AF405A36EBC318A2
+:100C60004D4FF1ACD9B86FAD54C5758C95F21A845F
+:100C7000EBA556C6E317D0C95051E3790938194E90
+:100C8000020F43D4538677401DC3BBA09EE1146876
+:100C900015F17F44B086E31A3C65E7F71877961B99
+:100CA00028EF287AB0FBFA61CB75F9808637F2E637
+:100CB000F93019D0FE32BBE1C7C02CF623B1FC8855
+:100CC000B5D3F11092D94EC9416452FFC0C1F65A52
+:100CD0000A0A8FCB6E900FC521AF91FB37B1FC286C
+:100CE000ED5E2FB6A9FC5840BAD62722A713850E71
+:100CF0001E6BF242FB4AA33C34568EDA7C517CC90F
+:100D00007907BAE2BF157E39D388F1ABA8B0644544
+:100D1000268EBFDCD121C6634B760CC1F15785E12D
+:100D200099C674D2EF92429313AB18A973E6241CB0
+:100D30007BC93EF309A21D923FF38AFA78A59AC7B0
+:100D400078573FE6B4A3BD7807D99C44A71593FD17
+:100D500038E4A39C29DE1F0EBE23B8D784FBBE3225
+:100D6000795BC87E975B83890EE4FFCAD565FDC8B1
+:100D7000753E6316FB2D16D17FD5E8C3797F1C8E97
+:100D8000B76FCF5E210DB93E1E78FE413ADFBB7AC8
+:100D9000A89FECD7DB283985644BFACD401EB6B747
+:100DA0009A80FAA6DA7D4F8DF01EA1FDE070B2FFA9
+:100DB0001EA0E639EDDBB3B3494E270AD5F7C3A928
+:100DC0001985C4C7A3233C27687F3841E8DB098A1B
+:100DD000E5EE9EA1AD48395ED8CD7CF81F88003E77
+:100DE0007FB1D07B9AD62BE3AF70DC3F5BF0E9DAC2
+:100DF0005046446F2514DA6CA4BF46818099E3C342
+:100E000038FBD53C95FCDD423C07F951E4F1D69026
+:100E10008B1B35BB7324F9553CF73C9F6B0E0D2E95
+:100E2000C0E75EB8EF9859E8DD40A177AA5F6ADEB7
+:100E3000BDFFC90162E881283BABDC7DF9FBA3C89B
+:100E4000BFCA7336276D8FD8D7CB2BB8DE049BCEA5
+:100E50008F687637A6C9C2F9F6D85DC317D2BEF13E
+:100E60009FB665125D13DA42FC3E2CDCFCF9008172
+:100E70008756875C927E4A3C3EA5C6895356111719
+:100E8000E8FD2ED77B8DE2FD6EB5DAE7AC6E9602FB
+:100E90007EF63FA27E5EA4D2B77C7F630BF54F1631
+:100EA0006D583085F52820EA0A07FE925F5872587F
+:100EB000D4CD4BB7EAEB8D4AAA9B693F04CDA40F72
+:100EC000CBEB63D6379472DD5C19EDFFBBA99B8732
+:100ED00015A9FDB1413088E992672779BBF187B147
+:100EE00075710528B9459CF77A64BADF6DECBEFFD1
+:100EF000909427E9FAB5E5EADDC4271BF3C5CCF5E4
+:100F000044F5AB2B9C761AAB76BB1175A798F2ED26
+:100F1000DA03DC5FD69ED3EC7871ADC475076CE85C
+:100F2000CD3A98BFC5A210BDF95BFA711D82F512CA
+:100F3000E7871BB7586A695CF3EB5E7E399FFAD08E
+:100F40009DFDA90F531387F9A6E8E783E4E23E0C61
+:100F5000F745E617A97E5FCD032058A0ABE76BD419
+:100F6000F85F9D30AC1F56CE917DFBD275F5498D53
+:100F70009A6F17119E94376EED2FD6E3041D7B3EBA
+:100F8000FEB778CA7B1B8D9E78EA6B9F3B3884EB5B
+:100F9000989EF8EEC63004D778DFE8FE7C4AE6B5C6
+:100FA000E456F49251F04BD5DB3FFB14F8C6149194
+:100FB0008B465F99FC56A999FA228F809DFA24D519
+:100FC000FB7F5763A5BA701D7007E21C087D3E7752
+:100FD000DAC0EFCF4742D66FC6E1D87DDAE80CE041
+:100FE000F30DAA5FA4F7C88E283DB3A8FDDF3847EC
+:100FF0002F7044D5D1F15929BA7182B3BFEEB9A48B
+:10100000E221BA75E4F7263A1FFC4A6BCEC848DEE7
+:101010009BAC8CD03DF74CE2E47D6CF7ADBFE4BEF9
+:1010200054EF3B5C7A7CE45D32F903B820F2A562B0
+:10103000FC257B1B05FE1A92C798767D1E551CAABF
+:10104000E3BA31EEA051D707B05CA72FF59C665FDD
+:101050000361A0F01BB1FCD67F4751BD5FE67CAFBA
+:101060007A1026AA19DDF1FB561DBF357BD4F8DEB8
+:10107000C7A3E77BBF197A7EA77BF5FC1EB048CFDC
+:10108000EF41557A7EDFB24ACFD70CBF9E8F99B51C
+:101090006374FB87D695E8C6B7BD74976EFFF0C042
+:1010A00074DD387BEB2CDDFEDCFAF9BAF5FCA62505
+:1010B0003724FF8260B56E5FACFC0BF7FDEA9AF255
+:1010C000F7E3AF903FB03C8A511E41C7FF9F1E7CA3
+:1010D0001AAB0737E867DF249B15DF2584FCA407DC
+:1010E000C5F1AC2753E385DFF968DFB9830A8E0FBA
+:1010F000380A4D699467A9F98347F5435A3D135B54
+:1011000037DE5B2CC5BCB78FD3BDB7BFDEF771EE42
+:10111000D6A06E5C7010F8FB17D761E7BB04DD2723
+:10112000146E778D3C5DF52EC1D117386C77A957B9
+:10113000B5EFEC62EB2D701E64BF3F5B7B2F434627
+:1011400031B26B7F52ABC7B43A37B6FED5EADEAEEA
+:10115000759AC863BAD61BCE3423E7D15ECEAB3FB7
+:1011600090BCDCE77C65B8D7E67653118075B28118
+:10117000EAE4508D60A602F41E3A4CFF7312F2ECC2
+:101180002CEAC7879381FBE7CAEADA597E1BA36F73
+:101190000F8D14ED23FAB9D5EDEDEB46B91E97ECA2
+:1011A0006B0BF1D98FC67C3B98F29174B7F85ECC8B
+:1011B0002223A7302EF59BAD00CD5F4C51FAD3FD15
+:1011C0005ABFA427BD89FDCEA8C1176468B43BF9F6
+:1011D0003BA4D8FE62C8E0E0FCD4FF2B89BFDFF956
+:1011E00096901B1DC963CED59A388F01B59E7F5846
+:1011F000E5BFD6F798ADD2731C8F588471F9E1A67C
+:101200000F582E4BD3DAD57E4915E7E30B06DA5C8F
+:10121000FC5D9B52E8147D32AD0F3240BE99BCEBB1
+:101220007AF42F4D3BA3EB43C15BBD6FE87D79841E
+:101230006E71FEF175A29F797CDD20EE9F47CE3F57
+:10124000CBFDA887AB3ED6D9C7DC554774F630CF67
+:10125000FFB56E3D94DA69A2FE636867FAE4879091
+:101260007F1D8D9691240FD48307DD51FDB7D0BA31
+:10127000EC4974EFF5E9FC96F168F3B5B27C353AC8
+:101280008FF90EF338E40BC57C6726E8D4FA1C1AF4
+:1012900034EF852C23BD4F947A39A9AFDC53FF433B
+:1012A000B3B3F3EE21AC9F970C8E93A24F54358AC3
+:1012B000F2BFB6897D4B08EFB64166A380C3C43840
+:1012C000BDD82AC693EF201836D96AA92FD226890D
+:1012D000EF82664BCA6BF3F0DEC7867B57917E5771
+:1012E0002EE9CC23FBABCC0FCD91F0FCB37DBC4FF2
+:1012F000127F242C2FD253980EFE7EECB4C19F2770
+:10130000A1A9BCDD787416D58DA77BF9CF5286B222
+:10131000CDFDF92CAA1B4F9B853DBED3189CE5A79C
+:10132000FA090F233AFD7F92447FCA16324FC373E6
+:1013300092FA789FA1F3E9BB307ABF47F3A49F5A92
+:10134000BF346C12796258CD17FFCB2DF2D9DFB8BC
+:10135000C5FB3F0DFE9EDEC1E0DF3B04D95F3F3B96
+:101360008CFAE9E7365880F25BBC5F311445BE5F0A
+:10137000E98BB4501EFBBE59D499AE772C41F25381
+:101380005A5F75933B83CF49CD14FDD2D4FF44BF40
+:101390004576186A1D3C2D210ADF83C07DEC0EEADC
+:1013A0004747F5B137B9453F141E117EAF63DD00E5
+:1013B000EEB72FDF7FFC18F9AF32B7770BD13DDFE7
+:1013C000E018497E6F79E21EEE9B35B91D7C2FE255
+:1013D000CBF4A21F5A43725A6E0D719FED7A7DF5C0
+:1013E0009EE8EF58D8FA620EF7911D79A437DABD5E
+:1013F0008847933BAAFFADE11139E7DA76A0F5877C
+:10140000B5F1A9579F19A6F6F7E77ABA89AF07DCB5
+:1014100022BF6F3375DF8FFF5F559E5DE4731B0046
+:10142000F5FF2DBD30F6236C233ED1FBDF99480F2D
+:10143000F737940292EFF2E93627F1593B1FCFF1CB
+:10144000FEF11AF7748CF07C467ABFA44AF4EFB52B
+:10145000F5B024E4EA5F27FAA9CB771F39F624DE3A
+:10146000B2F88DDC428A07DAF3B17C46FE0EE3EF78
+:10147000E864F1FE0BF9FB0D9D1FDBB7FFA97C0DA6
+:101480000F12EF69C31B2F0F76E0F3CBE9BBB63C1D
+:10149000D20FD1FF82067D5F0BF9E5A7FE46D7F795
+:1014A0005AC0EFC72C6A3CB168CF0F34EA9E7F3335
+:1014B000C1F34FC27FA7EA37707FC080F737A8FE1D
+:1014C000A941ADBB63FB2F0DADA26FDA9066E63C80
+:1014D0009AF21F5AD7F29F951F8BBEE9CA0C9167EB
+:1014E000139E2467E9700BE70B57FBE212C67BE4FF
+:1014F0006382D99B309274D2BB82E3997C0BCA99E8
+:10150000DE87FCF52EB58F20E2A35B8D876E3A87D0
+:10151000F0CA49E23859A4DE8BF505F7EF46835748
+:10152000CD1FD4FEDBBA16EE3FFC1F5946A94AB0C8
+:1015300030000000000000001F8B080000000000C9
+:10154000000BFB51CFC0F0030947B3A3F20FA3F187
+:10155000E7B0A1F233B9D0D4B3A0F283D0F4A3E3BF
+:10156000762606064626FC6AF061116606061920F4
+:101570005601621D66F2CD0161235106866209069D
+:10158000062E20FD5F9C81C10BC82E01625F20BF2B
+:101590001D886700B11450FC029096156360782E88
+:1015A0000AD1670D647F1323CF4E4B5ECADC3C8AA1
+:1015B00029C3E6B2A87C013506064F750686891A4E
+:1015C00010BE1E92FC0AA098A01A847D481E98DEC8
+:1015D000807C5559ECE61E06CAEB02E5776AE0B757
+:1015E0007FBB0E2ADFC10C959F8B26DFE882CAD70E
+:1015F0007043E5EBB84368003560D6A4D80300001B
+:1016000000000000000000001F8B08000000000028
+:10161000000BCD7D0B7C54D599F8B98F99B93399CE
+:1016200099DC241398BCE02604881A6012121E8AE2
+:10163000781302461BC304D1E22EDB1D686B23CF57
+:1016400001ADC6C736139290204482765D162D1DDB
+:101650007C15156B4AB14BBB6A27402B55B70E164C
+:101660001FDDDA6E60FDB76A955F50A9F868F99FD3
+:10167000EF3BE74EEEBD998447BBFBDBF8B839F78B
+:101680009EC777BEF3BDCF774E9CA484A8E30939EB
+:10169000033F5710F21AA13FB9434F427A09A98676
+:1016A000E7801C9E02CF187FCF9E81A57D02ED02B0
+:1016B0008A4932839022C27E8A5A36AE13A71232EA
+:1016C00096847E31B99896079635103F2DBF75D513
+:1016D000BBF0DCB8B8B67EBE4648DE92BE2357D219
+:1016E00067201C1722E584DC474442F2A1BFD25890
+:1016F0008D97900EE8EC5242C6C4F2F45839147437
+:101700005A20E49B0A1F88889A4CCB3EFC75681EC1
+:10171000C693102749946145E18C6B787B7B7DE310
+:10172000E98376469D62F8FF7A02F33B5B3B720BDE
+:101730001B2F46FF3943F15230343EF693D76C2AC3
+:1017400013C08FF5BB9EC2FBBAFF95F1F249A55BB2
+:10175000ABA2F36D10D538D4277D59322D0756C969
+:101760002421D0EF55BD82433BFBBA6C24A4BECFED
+:101770008BF8159A7C43F05D47049CCFB83BDEDEC6
+:10178000D51520E4D4526F08E9432524277BF87C43
+:10179000FEB9959084CB545E5C2B4470BCD02F4A2C
+:1017A00069FBD86231F428C0D3B0280BDE1BF56E7C
+:1017B000E3E30CA70FA2C9148F32A70FB941D4DD00
+:1017C00053FF7AFA902F903E726F31B523E7BF5ED8
+:1017D00088F7EA73A78FBF763C635D87F3551BC21A
+:1017E00031EE8E5237A1EB7F6FFDA2CC489A7A235F
+:1017F000AF6B25F27BA081E8F134ED36C17AE23C93
+:10180000631679834FBA3E526A796FB6AC973476D5
+:10181000C6925DA3E0430A58E76BF4EB6C91B4B752
+:101820007368515645E84FE6FD6D5497C708D02DB3
+:10183000D036C587D45B9120943F4890841EE51034
+:1018400088B4EC54F5F8DD0294E2B82E067C4AA97F
+:101850006819CF51E8B1AC07591213CCF03B5B9C2F
+:1018600008870C6CC2E55D18851B831B8638330125
+:10187000CA775AD65FF692849BCAD54DA595C4BC4B
+:101880000E069D0A8241A7779E9B5CB18FB7D80A4E
+:10189000E739B7F3CADAEF8D3625A3B593C9EF0D53
+:1018A0003C51E4FD0A7E31AD7B9783EC17A611D243
+:1018B0005EB831066FBBE07FB3913E416891AEC226
+:1018C0004A15E889EC166480D36D9047301BEBED28
+:1018D000221AD2534CB895403DC91B463C19DF47EC
+:1018E000868BD35D4CEF2FA5FD5EC3BBBD86EB336E
+:1018F00052E5787BC080BB04E73154A6F3F8E0766C
+:10190000FA3F4A1FB10A21FEA830FC7B03E8432AB4
+:101910008F1AE0BD499EB804AB3C6BE0DF0E3EF38E
+:10192000C6A4E9941E93218980B8DAF08C4BAFA34A
+:10193000FD1FB95C88BB040E2FADDFC8E17C59CF19
+:101940002902FA4CD6B9907E1BAFFC2400E47B62DE
+:10195000FFAFE474FCDA38C7310407FD6FAD797E60
+:10196000F4BF313006F2651DD29101D7EA4A09E190
+:1019700048CE11E230CEA1DFFEE19ECB289C2F574E
+:1019800009219786F0FA081D2FA97F14184D4E10D3
+:10199000637C8DA8804FFBF8A9F550424B802F9BAC
+:1019A00055A776371D6FA5143A0C7A8C8C65FAA171
+:1019B000599D5407EB23098C3EE60979D8AEDDBB6F
+:1019C000610CAEBBB434ADBC6AA68A42AD84EF5B99
+:1019D000268D0A67DC313860A2EB96B78AEF39644E
+:1019E00082738AE00BFC3E83FE3293CC8475FED07A
+:1019F000BB28334146EEEFBD56A54D7610F249ABFC
+:101A000076CF21C7F0EF2B2512ED2B1FFEFE6A418A
+:101A1000E1F88839C13E33E69D9AA73780F4BD12BC
+:101A2000C42F25F595BBDD6DB259FED8E691C2EF06
+:101A300005B65302EB63F91AF05B64A100FDC8F42C
+:101A40009F1943FCB8724F13E33B1BBC9D81BF0D34
+:101A5000BC67E3E30FBD1B3682BDDAEE60F4D291C2
+:101A60002B863690E1F462AC8781C7735D8F2D823F
+:101A70001BF9C3A0A36671E9A8EB7E363ABA15E854
+:101A8000E892FF793ABA0FE8A8FAFF241D6DFFBF6C
+:101A9000484743E52BD15E58C8FBEA1FF8EF6F8338
+:101AA0007C7E5D9750EEBD3E87C9FFD7234C2E2626
+:101AB00049A4A71AF4C15109E554526FF721BCD4C7
+:101AC0002486791C81DFE8F847B9BDF46AAB42127D
+:101AD0009371FE458BE8F757AFFAA410F4D7AB74B7
+:101AE0006DC1FE266450D769FB5752656A8043D9A1
+:101AF000CDCA836DA763609F270556FE69DB693DEC
+:101B000086E36DD97825C5E742F895C271DD1C21C1
+:101B1000AD1DF6A2E06478A92316BD4AD7E545813C
+:101B2000D28BB298DAA188BF3041FFB094DA09268F
+:101B3000FBA2051418C8E57A17EA3F7BFFAFF079DE
+:101B4000DAEDB8EBE6D438405FB8169F940728FC6E
+:101B50000B170B0E660FC5886A825BD4051DF44017
+:101B6000788EEB21D07F619938D434F358A8BB2C00
+:101B700076D749AEC7285E9630BF452B6A9A325455
+:101B8000FFA4A17F6DF319892E8C7918E5C5734EDA
+:101B90001ECAA1709106213451033AD58ABEE233A0
+:101BA000F79F61D8373EC0DBEB4BAECD647410417C
+:101BB000BD6AD0D32F8E7DC33100EFEB72502E5D06
+:101BC00017962CF6E4B5F51996795D3FE7DA51EDF5
+:101BD000701231E1C144F7FE0282744AFE8BDA29A9
+:101BE000944E63B58311B45B8E0B5A3B2D67CE6D5B
+:101BF000190FFDDE2966637D616ECBE401B4B71673
+:101C000020FD67F03E339DD13F94805C9D289287F4
+:101C100034B04747F70B3A016F9387CA8E402426AA
+:101C200050BC6931B5521A05DF715DAC4F47AF1337
+:101C300044B66E9DB1456A290074C82A37B2EAA23B
+:101C400068FF19F5291D4F107361DC18BE4FD17163
+:101C5000379D176DE761B608C9BC78512619651E16
+:101C60001DB6F5A7E25F4F27675772F8C87ED6BF4B
+:101C7000219332B369FF69EA1BCF2EDEFFE990485A
+:101C80009200A71C56001E52564BCCFD10BD02CB35
+:101C90004E5E7405C34A31C5A7AB5C846990CEF231
+:101CA000877459033CC470BD37D3B52D34F1E5E6D4
+:101CB0003F4BE8E7AF144BDA406E6CEEBF89681417
+:101CC0001F9E609C6079CA8D0AE0693375B29230BC
+:101CD000BEDC47008E8C42FA3B1D274325718DF6F2
+:101CE000276B7D099196E57A12D2E9279F1A123C5B
+:101CF000D4FF3E102C6993E9FB8EA504E52301AFC8
+:101D0000DC443F1DC1577509E867090901C01D8101
+:101D1000E538CF8DE5CBBB8BE9FB530D32C60FC841
+:101D200017145EC3AFA77E86A78CE830DEE63C12B0
+:101D3000F7A21DAC237E9D2A5B3F6D7B29494CA7F2
+:101D4000DFB366F4C3F8B17F22A1896C48946B328B
+:101D5000972744A6F407E3B7A8A1BBD3D09F42229C
+:101D60003789D5A67556C3E8C7DAF196E924570333
+:101D70007E3B2A281FA4917BB78A22D2413CB468BB
+:101D800061499A71EE1435944F46593BED44F8473A
+:101D9000AA3F544F26891CE85A17002F241CC0F96B
+:101DA0006593D48F0EE51C3EDF31248AF582B37A29
+:101DB000FB81DFF2F5BE1AC0C53FFBAE3F82EB46AA
+:101DC0001E54C18EA5D0969EC9199217A073607E2D
+:101DD0001F8644F43B7C6242D569073E773288CE49
+:101DE000AF46302E97094D28C077B72A1D6097F867
+:101DF000494880EFBE901C33DBF59984962DF11491
+:101E000072B474069216E30FA2F603EBA865D169CB
+:101E100000CC7D7EFDE7E0376DF145D00FFBC4EDD2
+:101E20009F0A83DDE6F13F04CF4FDCE3E2E89F85C4
+:101E300098BFA5D07F40DE65CE922DFE4D966E2DCB
+:101E4000E7D8FCB0059217E799750DE1FE95DE30F5
+:101E500071CC105C14A226A0976D753201FFDFEBE8
+:101E600065F018F0E54877CD0478291CC7010E8A83
+:101E70001684E314F922014BEC2F23183FA5701DA3
+:101E8000B7C175DC06D771335C2D0A9BAFDD5E8C64
+:101E9000D592B22805EE3991FB1FD46E02BBF11426
+:101EA000795FAF07C2095F8D7AD6AFB2365E2589FA
+:101EB000C10A95A8480776BB91AED38716FF6B166B
+:101EC0002F6B4480795038ADDF4921D20B96259293
+:101ED0008A0B2F9F65E04BFBF26F28FFDD74D84122
+:101EE00080BF281F4BF0DDC1BFDEC4E3C3CBC1BF41
+:101EF000A6F8FB1A09FB01BE0F888871A80FC8ABB2
+:101F0000FEE926397942E4F6092CB1998F4928086F
+:101F1000725CF66E4C4A7E4483416FC2195CC710F6
+:101F200093F35E467731A2B4A13EEC66FEA7114F53
+:101F3000FD7AAFD51FFEC6766BF946B2680CC44B6E
+:101F40006FFCB683C469BF3799FD7BBA4EAF892A4F
+:101F5000C2F70D12DD0876499783D91BCB55224372
+:101F6000FC73F5BF7D67C6323A9F53200FAAC17E2E
+:101F7000A7E09BF4C88A40DCA9970F9F5FBB106A5B
+:101F8000BC4C18797E5D8E6423F8DFB11E07DA99A8
+:101F9000C41E07DD27611CD4D40EE1FD6AB7757E2F
+:101FA000679BBF7DBE84DC8BF35DB17B19DAE723D1
+:101FB000CDC7B99BDA9B69F49D57122C711F83AF73
+:101FC0000D7AB7F37795A4B1B80E558368AFFC2EA0
+:101FD00023DE8EEB1B9D09EB7BB6F6B3A17DEE8570
+:101FE000B79FFB578E3FEF2CED572B830B60BD3710
+:101FF000057AC3C09F461C6B0D89E905F457C7B32A
+:10200000EB6260BAA5EA05CFB15E21AD279D43BD65
+:10201000D2D1FB3BC1ED9217F63CEC043BF5832794
+:102020008E35821DB0F2DF25A2507A38B1C7471233
+:1020300068AFC49D60DFACA07417C77262C6B526D6
+:102040007B985234AEC3CAA77D6847ACD8EB8A37B9
+:10205000D0F62B7EF4DF5309C5C3890D833F2F00D3
+:102060007A7E426071D7D8C0D46BE9FB1532F9C7CC
+:10207000701A3A5A26317E7AFFC7194BC04E147631
+:10208000F77F05FBEDFBB2C365D2C74B24078E4B30
+:10209000EBA11F117B5C884F14187C667FC088778A
+:1020A000BFFFB8C0E0DBEF88BB01BEDDBB9C115AAF
+:1020B0006FEDEE9348D7F39E7ECA0F7858BBDF6A68
+:1020C000A7AFDD2D255C53F1790C9EA041851980C9
+:1020D0004FC6CF6BF6AD46BDB1A66FF349E0E7B58D
+:1020E000FB1D16F94FF1124A005EDF90420D50FEC3
+:1020F000E1F7FC1A45D57BC947FD8057DAEF322757
+:10210000A5AB85B3ACEDA0FFD3D9C3FBA39E21FA49
+:10211000CD6BFB36B1F1F65DF30790B76B09D35386
+:10212000063FBF07BFE40DD7339B246B7CEB1479CC
+:102130007906FA81BB73D2FACF865E31F87AE5531D
+:10214000A776C6E8F8EFEFFDE3CE189DC7AABF7CDF
+:10215000B4F34EF0979E77AB20AFD63EF19A9F989E
+:10216000F0FF88C4F6034E3CFEBDC776503E39F101
+:102170006B17DA81279EFBC3388DCEFFC40F3E1D3F
+:102180000376EA2DCFCD1F0BF8B8E599796347B3F5
+:10219000D7816EE32EF3FAC6B17F6DBF009B20841A
+:1021A0003CCB9FB6753AB84F4A4088E083375D71A3
+:1021B00017C5CF5AFAAEA512D66D35EA2B28DF45E2
+:1021C000F1BD664FD749696A3ABCC70AC4203C13BF
+:1021D000052408EB7EEDC2CBABE0E908694027643B
+:1021E00010F584BDDDDAA3747DA78DBC9ED49E70EE
+:1021F00002FED7EED9C4C6EDA3EBE91FBE9E1FC0F9
+:102200002FB387AFE741C91A673A45567D77077CF8
+:10221000DCC7FCCE91D673F533D78DEADF19F2E136
+:102220006C786E16185C5B25FD5712F0E3DE271FF5
+:10223000DB1160EBDC401173E2A953E36093F71DFF
+:10224000C7E057404E0E3EE752C1AE5EF1DC1BC800
+:1022500077279E39E2D4707F9A7805AA274F90D4C9
+:102260004F12F4E61A8115D63EE24BB8FC43EBB5AB
+:1022700026DE54AFF9F1FD317C1F67FCB026DEBFCE
+:102280005848B37E5EB984E9A7782EE265B59674A6
+:10229000AA5EEBBA0AB3603D8F2D00FA1B693D8D33
+:1022A000F9AB30FF99A6757D84F1F148FC7A62970D
+:1022B0004B163287AFF3096E57AC8D0B6FA45B776B
+:1022C0004236B0F8DE08716FE369A70BA76CE573BF
+:1022D000A3BD31FFB3F1F9D9E7757E783BC5F5B5FC
+:1022E0001D7FEF7F915E0F94C802D75BBDF5F92685
+:1022F0007DE776503D560C76673456503C04EFC669
+:102300003E09E5FBFBBB25B4F7ED7262CD087E7D8F
+:10231000C818677FFF549067EF1FF831A74746EF53
+:102320006BF61C73C6B85E889BF502F497663D2E6B
+:10233000E5FDAD7D367D7F6BF79C4CDBDF7BB2FE30
+:102340006580FFBDA483C46817EFF54969E324A540
+:10235000B2C362676DF4CD783393B693FC1E0DE67D
+:10236000DDBE417F2306F6C8AB0E82F6A31C7AC7FA
+:1023700045BFB7FB3CB8DFD2EEBF916826FDDD61FB
+:10238000C3931C0CA31F2D07C2556C2F346EF1672D
+:102390001DAA68819BC8B142D8E7FC65F11F64E8BB
+:1023A00017E2699A292EF48A4C3A73687FAFE842A3
+:1023B000A88DA4896BD9FA0FCF918866A6337DBC0E
+:1023C000688E2FFA0FDC8E718D16124D40BC891469
+:1023D00092BE474DFD3ED8AAB1B86B78BC688EFF5F
+:1023E000B9A251DD45E128BC452D01FF6DA4F18B5B
+:1023F000A2D67D5F63FCF53C1E41763FF1C413B469
+:102400003C1EBE616A45BCCD09F13795D937F3B89A
+:102410003CFC29B79F0F08E1436087E977C56490CA
+:102420007782D626839D51FF454C5E6EA2C77AED1A
+:10243000641EE8D5EFFE595A928E4EF773BA6AFBC6
+:10244000A71FE541FCEE01F76D85CC990D237C8536
+:102450007C9E878ABEE185EFFDAB6FF44EA6F8291E
+:10246000084A04E2350581655B2A60FE47A5905B5A
+:102470001BDEBFF1DCC9E37A0FB5AA28FF1F690D87
+:1024800062F9318ED7DDAD65F87CA23584DFF7B413
+:10249000CEC2725F6B3D3EF7B686F1BDFF8E17056B
+:1024A000A03BF22DD207F19A7DAD4BF0FB8F5A2362
+:1024B000F87C94CFA71EF0E2B5CC1FE331FB3BAE16
+:1024C000D800F118038F76BCD7D1A962FF9AA0017A
+:1024D0009DDF2E33F962C7EF38574208D3724B9411
+:1024E000E52BECE4716363BEFF2A337B731F87E740
+:1024F000C7EEC8F765D86FAA2F2DE7F1F110C8EF26
+:102500009D42786B05E59F178A6606CD72B8C8179D
+:10251000D9279BE8675C378BF7EC9099BC1A4F4E34
+:10252000F66752BCEB5F100DE8CE98EF811AAD1044
+:10253000E4E40141C0F5D6BF10499989EE8CFEBE96
+:10254000238B7C7F23BDDC1EA263260FB2AF92CB10
+:10255000C0AF3D453C2189C2DB9947F681DFD209F6
+:10256000740976F26F33304E6CF8375BF87A67BBDC
+:10257000D9F7536FF9E2207F46F27B36F2FA1F72E9
+:10258000B856CBE15FC9B8AF1C1758BE4302E398F9
+:10259000056C2A944E976EA56B45EEB9F4BD3721B4
+:1025A0003EF8C1336E0DE0EAA93AEE37E391AC9202
+:1025B000DF37EFEB18EFF34F17203EFF1F891C3377
+:1025C000E339BF79D009ED3B056D5B1DCCEB3509D7
+:1025D000F9AF53885F84F13399A05FD07953300EFF
+:1025E00072CF68E70B59F93BDB1D5EB20CE6DDEC00
+:1025F0000CC5D2C8A7DF666816F9E00A5ADB0741A6
+:102600006756B3B246E9B382303911927509FCB40A
+:102610006A12C1E74CA2E133CF11F90CE6319D8477
+:1026200035807343C6B8CBD8FEC1FF18DE14C7FF90
+:1026300041BC19F41ABCB46C1BE41F903B44DC6F22
+:1026400069874F263A5FE810387E1594E7053CAE5F
+:102650004FE5FF0B4501EC86C549D40C9483057CFE
+:10266000C3A065E024C67783E3088FBBC731DF6969
+:10267000C72A11FDF507DE12E290EC726A55C99186
+:1026800049B47D0DE573589FECAB4A33CDFB0C0686
+:102690007F3CA08433D551E2FC065F18E57F19FF2B
+:1026A000BC007268DBF8E7FB413FE40F08211063D0
+:1026B000F9DEE864904735BF7B3C0FBEFFC6139937
+:1026C000635E9F1DABA3E3014EAF2F3C17DE870B6C
+:1026D000E33780BC3B557F8B0B97D9CBF25E5AEE2C
+:1026E000D2B64DD6465E9F9D2DA3EFDF18F3DA7963
+:1026F0008EF332D6EB54FDE228E8713B9EECFD668A
+:102700005FB578D4F11F04BDE2C2F92F35CFBF30D9
+:10271000AA627E8BD1DE98AFBDBD7DBE43FBC0E714
+:102720009617D4E72039B0DE3FF87CDC0F5F2140FC
+:10273000126109E89FF2E71A806706894A8C1FC276
+:102740001AC87F839E778C792C0FF5821C2F4679CF
+:10275000778EE3759270B806ECB2901832DB2BC618
+:10276000B33D45E7098CABBAB81C1133EE0AA6C3DA
+:1027700073AAFF42CAFFA63CA62D84B078544241FA
+:10278000390F814295961D8749E5DDB4BF66079BE9
+:10279000478DCCE221D30F6BBB241657959A7C262C
+:1027A0003CF2FD0623BEDB49EE22AA067E45453FEC
+:1027B0005437F8F4E7CEC8B71D908717D430DFD36D
+:1027C0001188086C3F8EED0F15717E9D2F2D55C021
+:1027D0002E6921E17AB04BC85189B03C3CC6D72E56
+:1027E000631F8CF3B1CB4D783C38C8F89AF77390DF
+:1027F000FBA53FE5F6C9B3DC3EF909D827B45CF484
+:10280000F1E00180733FD8292EB03742F87D1FB721
+:1028100053FCB77812E01FEE6DD5B1FC706B333E00
+:10282000EFB9F5709B1FFA7FEE4707FD14BEEFB4BA
+:1028300010E4D71692FCC54A80372A627C63576B36
+:1028400014FBCDDF923C007B24BD2D077485BEEFC9
+:102850008AD68A6E5A6F6715C1F8C64E85E21DE4A6
+:10286000631F41F908EE12CA2F2E9F32D79522FF1F
+:10287000F654EDBD0AF051788D88DB2F06BFB9BA4A
+:10288000070656D2F283CD7BDD4086D9B9C9F52F34
+:10289000815E9F43E5AD06EB92EC5E40D7B7A06842
+:1028A00091328F96FD7D1BD7817EF6EFBBFF66F0E0
+:1028B0008FFDCF3EF14D2817D8EC59FFBEFDB7B1C3
+:1028C0007A2FDE0EF50A0ED379D0F653D563FD309C
+:1028D0007F8ABF81CDB49EA3CA9AEFF894613F74FA
+:1028E00012A4ABED3FD82FC2FC0303E11AD8AE19F6
+:1028F000F366B41FC8A7F01D86FF5DAB3A76413F73
+:10290000EF3A8A919E1E6839001175F29D6FBE8E56
+:10291000F47C70D57A02F4E05A25635CB160F52D41
+:10292000E41B2679E16A91D3C699DF75B8907E3BA6
+:10293000572D4E4EE2640A7C38EEF63A05E5C5CBDB
+:10294000D67C07637F781789BCEB40FE62FBC4B27C
+:10295000CAF6932FA148077B89AC15599E5FB8CF63
+:102960006D8E1F16AE16C3E9E0F8D421E3BC3AA27F
+:1029700075EFBC48E72BCFBC15ED52D26B1DDF18AD
+:102980008F8EFFA9C3947F22AB0C2E8D84441F1D14
+:1029900077CF5E4F3E944F470D7D95C0FDD3A72B5B
+:1029A000C4C4780ADFBDBD22E6A11CAC67FAABE760
+:1029B00016B6AFD5C3CB3BFAA801563CC44F863FF1
+:1029C000B023CAF6BFC91767D0BEF0723ECAAE7850
+:1029D00055C1FD8998EEADA1EFA71183DFC4A175A4
+:1029E00007FB658B950EC48E6C4B59A3C6BA39EFA5
+:1029F00018360D5365D4A74715F0274FF5C904ECD9
+:102A000097697C7FC88ECF1D9CAF7742DE0CF81D86
+:102A1000ABF6BA350AF7CF0C3A6989EAA0178BEE04
+:102A20000AC798DF63CDA3868C10C07311DF87229D
+:102A3000D25B15480FCFB23C5A631FD15168CDAB62
+:102A40002EB7E58317D9F2A8CF37EE52EDB4C7E31E
+:102A5000B65C84FA42F3A31CCBE7633D329BBAF920
+:102A6000D386C75F52FDF2F802E9F5E37AE673799F
+:102A700078CF1D5233F80BFE159559E638E9D54E3F
+:102A8000E6C71CFAAD0BE979679DC2F73D59BEA7B1
+:102A900083AF7B9353C37A3B7B6F55009F5D81125D
+:102AA00037F473F0D29FB8315F85E7AD1AF278033F
+:102AB0007D7F13EDEF3BB922EAA4CEC257F360BF8E
+:102AC000FEDE3A05F352FD19037D0769D97BA73372
+:102AD0000479233B6B124BC226B86E7732BDB6D455
+:102AE000C9F787B658F33A285F2C7542DE98378AC3
+:102AF000FB99A2C2F37B6D7EBF810FFF81ABC4E265
+:102B000029EC593205FC54262FE33CDF6A27D70B0A
+:102B1000867DB183FBAD5BB8DF6AEFB7B4593F8008
+:102B2000F6D92AB5124254F6F59DD06D959FC53160
+:102B30002B3F8C6FB1F2435134DF52BFA0B9C4F2C6
+:102B4000DD17BAD866B72498BE236C7DBADCDE09DF
+:102B500020472AA93EE6F607CAB791F47DB343DFC2
+:102B6000E004B9768E76883F231C85789BDDCEBE47
+:102B700087AFCF3FC8FA16E88FFA75F760BF725C6F
+:102B800060E787AC76C93038B99C1B05CE7F719E53
+:102B9000877D76B6FD37FBBEDB6D5278FB2BF439B3
+:102BA0003793E54976FA989FDF09F1555A7E8ECF23
+:102BB000EFFB4E099FFFCECB733368FD34FC6DC431
+:102BC0005D7F0A0939506F6CFAFC4BB08CF07B4189
+:102BD000FAEF3F75B27DEEB9E3471FA79F8FB3C5EC
+:102BE000A13FEB34C5F7BA9CFAF3E6F24127DB9735
+:102BF00036E8C2C8AF34ECB45B1DFA2173FDA1A75F
+:102C00005D5EB2FD915CBE9E3EC2F8EF674B966F73
+:102C10009A48F9D959E845FB277749C73AD10F793E
+:102C2000494915FC845C2EBFC96226378DFDF6EC40
+:102C300006AB5CB59FC372F17C7997FDFC0D97AF35
+:102C4000767A1C49BE1EB3C9D7545C7B04BAB2C79E
+:102C5000B55BE057667F72FB389CB968CAC8F4F868
+:102C6000CBD6C19E431387CAAFC0B99AB474C0F61D
+:102C700019FD07DE6D585C05FB795208645CB235BE
+:102C800031F7ED8943F22B3C27EB67100F0DD76529
+:102C9000A1BC690CFEA9E7500E95CB7AFFDCB74DBD
+:102CA000F34CAA14DA09A3F089EEF8CCCC5FDF0369
+:102CB000590F76111F6F2BC7A7DDBEEE12632EE8EA
+:102CC000F76332A00BC5A3CFBB03F136E0053A1B77
+:102CD00069DED35D4CBEFB67454310BF739D919089
+:102CE0000F5CE30D3B268476CC0C5716A3676F0967
+:102CF000EEEF51FF7DB01FD6C1CBF2FE0DFDF89176
+:102D00001167E57AEFE62C56DEDCCAE2CAAE83B381
+:102D1000DFD0683BDFCB0E0271CC4D54AE437CB0AC
+:102D20009BDAF9F0DD5F354020BEDE4EEB474CFE0E
+:102D3000787BA85685FDC68EF24A05EC0A694A15CD
+:102D400096E5E24AB5968E39A5EBFE79B9101F2FAC
+:102D50001531DF761A2DB79552BA76A938BF5F962E
+:102D6000BDED05FB2C1B82A9D543EBE9A88AE8122F
+:102D700085C711546B214723A5B7399DD1F70F4162
+:102D80007ED1F784C86C179DFF2FF9B9AC2E67B4BC
+:102D90006C3DF84372CC0571C01685ED4F003D7453
+:102DA0004C1F82BB96E3D7CDC74DF9477C3D3F967C
+:102DB000076290F2DA2592E674EBD3E06272AE43DA
+:102DC000D5D551E949953FB3E455CF61FCE40C50AA
+:102DD0007A32F1F548F25A728517BB7287F298E899
+:102DE000C2AAC8A784D981C6B99F3F38F52558CF54
+:102DF000CBF04A0AB3914EE9FBF99EEA0B91FBDA5C
+:102E0000D63ABA6E07E6541DC17856D2817124FFB6
+:102E100004F28F663BE4251706E3E893C52DEFA681
+:102E2000F4119FCCE21504E826832A62D89F2C1265
+:102E3000E30F1503BCBBEA27D0FEBAE489D4521FC6
+:102E4000EAA7A688F9033DB59E66B35FF0C70CB646
+:102E50002F739BB7E619171DA7DC1BAF45F30BB209
+:102E600036C7B0735540C797A8644010410E860915
+:102E7000D39B2185C54DEB543847259008399331B4
+:102E80009A7EB49EB77A428E6FF0003E022C0EE618
+:102E9000DB2E6092A0D4A7273C2012BC8BBA5CA882
+:102EA000C7C365304EFF0C0FF1D2FA7FEA77E23EDE
+:102EB000789FAF4006BC3E2F2EFFAE93CE77F0D763
+:102EC0002ECC7BECFBF3C59897DFE7BB6C01C8ED1C
+:102ED0003E811CA6CA9ED49C2EE049882403F6FF9E
+:102EE000FCF37402FB30833F2368FF39822FCD7DD2
+:102EF0007B3A4E3C439C45DBB949B79BB60B7DE61C
+:102F0000F9E80A4A577BBD95F74D2343F11623CEC6
+:102F1000529711D90974D139E63F9B816FBA299C28
+:102F200012FA137A10E0AECC15312E4972BDF18938
+:102F3000F47DCDE1401DE495D6C8159832EB9FC7CE
+:102F4000D6FB379EC86E986F9DDA549745EB571D98
+:102F5000D550CE2E08AE3B04E5196FB172A793F1A0
+:102F60000BC4918849EED69C1E87F3FB21A7938E54
+:102F7000A09ED48551F9C6761EC19A4767A603C89C
+:102F80007F37D141C461A68359940EA698E94017B2
+:102F9000CE870EDA50595F08FFE86FD40943F1BCC1
+:102FA000E17CB04EC92E1FCE2F061C775765074017
+:102FB0008E1A7CA1CEBC0BE5AA6B99330CFB2D06B7
+:102FC0009F18FCF1A9DB817C48F9A411F87DB15769
+:102FD0009B9F8E4FC00F31F3C3B523F04D23193C97
+:102FE00014A08D1A6512CBA4A2E497B3DF291D6744
+:102FF000E2033BDE1AE708E4B8459EB1B209AF6AC6
+:10300000EADCA374EEF87F55D63A03263EDC48FD91
+:10301000103096BBC51001BD52ED5DFE29D0A5DC78
+:10302000F08320F8830E57B819F36967BE9F7123A8
+:10303000A5CB3F8D1135987CA7B6FC69E4E7373303
+:1030400008D8273D3356603CF84F3745C6839ED895
+:1030500044F17F1CF5727CAC88B9990363D93EBCFE
+:103060001664CF4890BD27FC7B9C97755E6F00EB84
+:10307000D175B6C8C71E37A3F71E37D3179B9CBDA3
+:103080000AF0DB60B1A29AF3A0AF90981D5BA5F0A7
+:103090007DA92FDA35881B5629ACDD7DAD7D687F93
+:1030A0006C6ADD8FCF9C8638813C2B4F594C83FD59
+:1030B00070E52FF30407F0F1C56CDF16DEB799EC6D
+:1030C000AF710AF36395BF4811E04F65434CCB36AF
+:1030D000C959451422E9ECE8AD6E99B5DB40F0BB67
+:1030E00072E05F719F3BA734247C1DCA1B7A49881C
+:1030F000F6E34EB0F781525DF89AA9DF40439F4551
+:10310000CF35D225C8AC44EB09CFC1746A1EDC1799
+:103110006B0CD4BE2B4F1D4E47F073DC440F06FCE6
+:10312000C6FEEC2DDCFFAE2B5190FF3A5B9CBB4002
+:1031300035372ACC2EFA38503BEA3902D897A59673
+:103140001BFAB9F084FDD9D864B63F0B65D89F85CA
+:1031500027ECCFC213F667E13BECCF42F9FBAD3A67
+:1031600096619F16CAB04F1B9BCCF665632EB62F97
+:103170000BCFFDADCDF8FC496B14BF3FDBDA82E528
+:103180002B5CCCBF2165B120D8CBDDB73B75C8BF68
+:10319000E9E47470502FC909D1757507589CC0FDBA
+:1031A000F2BD780EDA1D1471DF7563F05EF255FA28
+:1031B000ECAEF675431E8CF2B4179F6EF93EA2E199
+:1031C000BE6CAC1922A7AB94E97532B5134A83EBF8
+:1031D0006AB36979BD32BB03F21127696DA1E5EAD3
+:1031E0005059F355AEF881A93CBE7C97ECA1F56F20
+:1031F000EBBEAC03E401C001FBC86DCADC3AB0E32E
+:103200001225D45001B956EC8C033D7F0DD66B22AC
+:10321000C0CFFCA92F91F620C435C66BCE4AE0433F
+:103220005A3FC1E8FFDCEA774210387778BBD1EA31
+:103230008955E7548F48A3F407DF85D1FA21ED6A59
+:1032400092C2BE196406D8476EB6FFDBED60FCDFA4
+:10325000ED66CFB739DFFFD85D3BDF4DF968BE9B28
+:10326000F161B73B5C0FE75006A788A18708EE9B8A
+:10327000C4DC7028A1A5F857705EE8D6176502FB7C
+:103280000A0F72BE9D38DEC7F4F49D0AEAE92BC727
+:103290003FD5914DCB131F0E8540EF6E26210FD0E9
+:1032A000496C8B88F9294F564DC86EA2D52FA97E3F
+:1032B000261BF4CFA70AB377E3DCDF68EBBC713CD5
+:1032C000C4FFFE7484C9BF2739BDED7224A3B89E24
+:1032D000D55EB457A8C380F6485B50C6BC22318F78
+:1032E0003D9D0EF5EFA09E932AFC1885C7F9E7993E
+:1032F0000AC63F4EBBF8BD1749B4539CEE889A45A9
+:10330000DFF7C644E4F776D51307BB7AB3B712CF1D
+:103310009BC6CA653C77B2B95C64E7657CD7C7C118
+:103320003ED9DAEF66F2C1AB605E69BC7CDFE1DA00
+:10333000003C4515F83DAE2FAA47BCABA28AF9A9BF
+:10334000F437FCDE1CC0732A1023C7EFCD2CFEDC43
+:1033500039E6B397A641BECED7D510BF8B00F3BFD9
+:10336000D1E412619F68F04006C0F30FC63D06032A
+:103370001B3268FD8EE56A08D661AA5A5B0FF90513
+:103380009D6A2DFA391953EA9465288752E734F07B
+:10339000BE8C8E7219F38BE03BF025E92087E09C10
+:1033A000BCB1FF9C915529807DD5D980613E38C73D
+:1033B00060C937EFC8BE1ACF27498DD9086727D112
+:1033C00015A81F6B9051FF15789504EE3F18E7ED97
+:1033D000E1E88529DE90B3CA7A7E23AF59B69C17FF
+:1033E0001F1BB1967379FC20D776CEE34F8AB16F5D
+:1033F00066C5937DBE398187B200DE1C38E0AB0D17
+:103400009FCF7D81CA26986781EA41B883EA861AF0
+:10341000905F6349B40DE8EEBCE1B5C139B5BC239A
+:1034200009EB3E559389A641BC7D7003F4BB99D34B
+:103430007977B1551F3FA848063F4E75E7429C512A
+:103440002431D3F810878C99C69BD09D6D294FEC01
+:10345000CDB7D49FBCBDC4F2FDA2F8C596EF97ECE2
+:10346000AEB494A7F45D6AA93F6D7FADA55C91B839
+:10347000DA527FFAE145967275F2EF2CF567BEB924
+:10348000DCF27DF6C00ACBF7CBDE596F295F3E78C0
+:1034900087A5BE61AFDBF56299FBC2EC7417DC1F38
+:1034A0006189CB5AFD00BB1DAFFCA55DDB0072CD71
+:1034B000EF44FA96418FD3F2FADB991FA5CC0D6940
+:1034C0002057C671395AE4D3AB418ED6F815D407CC
+:1034D000B297D593BD0BD0FE18B79DCAA3E9606D16
+:1034E00092D4F70C90CBADB1B9A5A678935BEDC59E
+:1034F000335B35FE7A02F179A3BDACEA2402FD40CC
+:103500001004E2E7D44B857A6E8DB637CDEB795156
+:10351000C4A3D183D4DF7BC8E4EF8DE4DFD9FDB948
+:1035200073F5DFC689C483E70D8470149EE5D1234B
+:10353000B590264CFDBA1B807E7B9CE1E65DB4DF36
+:103540009E120FEE5F1A7E5D77711FF2C560B18C1F
+:10355000FA85C85AB9391ED7C1D737437912FD4AFF
+:103560008A7794B706DE370B03F176903BB77B5032
+:103570001E8EFB2FD7ABC05F4A8952A0D0F7A18324
+:103580004E1DF6B7EFE3782D512B6A21A4541A6C27
+:103590003A00CF491AB533E8B3AC6CDB0178DEEA08
+:1035A0006679C217877E500BB24499CBEC3F79AA5B
+:1035B00033BE81F623A9148E347E85F194FCDBD9C9
+:1035C000FE45A9FC7BA037B0EACFD029D4642B7884
+:1035D000FF8C1BE840C027D28F3BE045BDE186430E
+:1035E000AF5096857886C0EC53D89FABC9DE8EEB82
+:1035F0006ED8AD60CF46989FDB01F41568B0AE770A
+:1036000086F27DC45387C0E2DEDD59DACBB574DCC7
+:10361000EEDC926C88B1425CA4C9246F7AB8DEFEFD
+:103620008A47E4F96F4CDEFC05FAAC1EB27728FD40
+:103630006F1727007CBD04E496FBAE5E02F4EE56E5
+:10364000E96AA25D1FD3C2A84F99BD7B3387A9AE9B
+:103650006409EEFB7F14A844FBD6DDF27C5AFCB96A
+:103660000724A24F1F19AFFE493B50DF9312A70654
+:1036700076458BE6D477A59107E5DC0FD934CE38B3
+:10368000E7CACEDB76737C18F1D0549C91C7D38CFB
+:1036900038A3D1CFCDB9956347B3C7DDD4BF8C98DC
+:1036A000E0DD44C701BC747ED1548F7890093BA7FC
+:1036B000FBE7F25D904765F849E5DC7EA9E2F81D7D
+:1036C000E724E827CC83B8490E78B55FAA07BE3453
+:1036D000E22CBF03638BD60BC588C4E26A0E436F2E
+:1036E0008967A621CC9A7306BBE28BE5A332BD465F
+:1036F000FFED87F36413BAADE73527F65ACB93B7DE
+:103700005BCB17C5AD656A351F05BB006C348C5BA0
+:10371000ECB67E6F32F603EAD8F932858E7C86E904
+:103720005FCB7D3984EBFF7CDE4F515FA206C46B1B
+:10373000E12D56BD9ACFF57CBE4D7F56FA248C27DD
+:10374000D41C0E1C02FBD188FBFCC6A359EE7530BD
+:10375000E2377679EE796B1BA15FD02F8FB8581CBA
+:1037600003E2C39F14F17849218F978CE3F19222F1
+:10377000162F7148DA2B4B05CC0B3DE9463B233A1B
+:103780008DC569D839AF0FEBE59F091A1B2F621A57
+:10379000EFB6B2D8950C0DF13CA867C44D8CB8803B
+:1037A000D7A7CF073EDB1C7A357A90D249EDAF5DC3
+:1037B00004FA992FBD7CB815E45B918CF9DCEACC56
+:1037C00055DFF5401C12BED3726DB13616F9E01705
+:1037D0000E8C0F7471BA36CE271A7116BF87D94571
+:1037E0001E8F60EC037978BEBE07ECDD4B76535A32
+:1037F000B4E83B16CF33E27653FAACDFFB8890A3F4
+:10380000D2759CB6242E32FB4AF7D698F21D2FE6CD
+:10381000EB367569E2DEA5B4BC87C42BE11EBA0A9B
+:103820004E1FA143D673B1638880E7A2C61C9542A0
+:10383000715A7FEAB3D6EFE5B673B317DBCFD1DAAF
+:10384000F6857C1239B98C8EB7458B0A2047B72C88
+:10385000A5B63C2D4FF6F0FDA2496412D0E17CC91B
+:103860001B4A007E5F93707FCB756CF21B90C7483C
+:103870008EB07C247502CB8B545F92504FA919A453
+:10388000A2C23BB48F74FF9910817D1123AEF50461
+:103890005D57D02B7BA85F5EEA003F5BC5721FF5CA
+:1038A000CBA1BC97FAE5F0DC47FD72780FF94850E0
+:1038B000DE4FFD7278FE84FAE5F0FE59EA9743F98F
+:1038C000366FCD7C4F2EEC1B9521BD782AF629133F
+:1038D00028BC5D8A4305FAB0CBA19A9A9B95C59402
+:1038E000A4FECEF514EE5FD4CE67F9D3F33D4FCDF1
+:1038F0006B93ADF13573FC7128BE362018F1350895
+:10390000791EE3FB0CA9385B84C5D9CEDE8F6EF43B
+:103910008371CD61FDF0F8E607B7FFE763EDF4D3FF
+:10392000EAEA7BBB3D25709E234ACCFBC7C6390F14
+:10393000637EABF7B5619E8C33EF6814D6755F95E7
+:1039400017EFFA713A222AC85BBB3F67F871767BA2
+:10395000DA78DAF59B8FDB1546DCB4C741307F3A65
+:1039600026507B02EC8BD6F8DCB71D23C7535FF7DC
+:10397000F0734536B9903A37C0E33E2EB066E93C65
+:103980009D02C707CF6747D158C2E27AE6B8AAA717
+:10399000348E87D53D5E1DED3A81DA7B68FFA991B3
+:1039A00020C4D136C2398134F37B98F37B5B9E13FC
+:1039B000ED8D8D790ADA497585A120B46FCF9B1101
+:1039C000349F1B30CE351CF2CD50064CFDADF79523
+:1039D0008CAAFF24AAAFB551F4B5E462E77ADA0FF6
+:1039E000CC56E0BC46B7777912FCE8EE6000E3EF16
+:1039F000FD793330AF27553F380BCF75485E660FE2
+:103A00004B4105ED6119E65F3E54DFA8D7EA6174CA
+:103A100042D919E38B6E6F2FD673C961BC4FC215A3
+:103A20006079772E95EDC7794A45A298E485316E85
+:103A30008B87C5A3BBCB232AC459BA8332E6E97767
+:103A40006B9588E7768EE7F622C39E08A11DF36F7B
+:103A50001CCF463FED3C0ED0DEEC447B2EDC92A525
+:103A6000C2D52F5E5F780FF073B7778302FB92CEDB
+:103A7000BCAA51FB3DC0E5F6C8FD568CA99B8EFD46
+:103A8000FE1BF4EBF42D57A15FC708E7915EE170D0
+:103A90005EA8DD6ADFC7A3D006CDF928F6A78FDBC5
+:103AA0009FF676ABCB079CB0EE9B1EB19E5F761067
+:103AB000769E6BCDFE75C8E73D7212EDA89E2F84F1
+:103AC000B4E7C2C66418FA2CE5DF5BECA002CE4F67
+:103AD00005FC3B901AE88B8A84D56E997ED85AAE45
+:103AE0004E5ACB33DFB4DB41FA6B60072DE6722F01
+:103AF00049E53D4B861994011FE158BC06E06E2252
+:103B00007D6D9027E1E071F2C55CFF2DE4FAD19B59
+:103B1000C1E2BD05CD1E8BFF49F8FD7F85BCFFA22C
+:103B2000BA43EB3A40C8860DBB4A43BFB5E8AABDCD
+:103B300035282E6DF655936E3DDFBFD0663FD9ED2B
+:103B4000AC1A7917E6E9E6DBE21AC67E2ECC13EE54
+:103B500039B08F7FBEE31AFD411E16C837E3FE174A
+:103B6000BC6F98B62F92134288E2291FCEE7507897
+:103B70000A6E21FAAE34747C395FF761788B5D810F
+:103B8000789BC7DFE57BD9BD5DF975525C2B86F369
+:103B90000E7D680F2C5A45E78376F819CC8331EAFD
+:103BA0006767F5F5C3BEE78E0681F9A53182768D8C
+:103BB000B1CE3BBCEC5C61D3E5425C84F6D1121C17
+:103BC0001FE12A195A5F8AA7E30C4F2CCFF0DA7A4B
+:103BD000EBF9C7269BFD62D0C342DBFB010FDB176D
+:103BE00037F8E083D96F4E1A47E1582DF4D6674C69
+:103BF00038777D69E20FC719E043F87D0C4B7D01F2
+:103C0000FE38A0FC50057E7F3E6BE0014249B229A0
+:103C100083C4EA28F1FDD433788940CB4B363FDDAD
+:103C2000D95D04C7BA079F0423CFD5B56F7EBDA960
+:103C3000ECB93B81E5001F07B616D97A9BEE83A14C
+:103C4000A8DB0979F360E7EA649B04B9B6A2BA2D50
+:103C5000543CD42E1BDA09A3B40B936D729A765E92
+:103C6000A31D45D746B8EF89CFCBC3BF8B1C1EF32E
+:103C7000F832E04DD5BC78BE7181AC425EC65F0BB8
+:103C8000C798B3CD3B42B639260C6F47C16E33E0BF
+:103C900017D3C31F87EFE6F11DA3C0FFB7C6C7D96F
+:103CA000FA73F2EFE70D1FADBE61CCC8F305B81C87
+:103CB000780F91E6154DFD6CEDFF14E3E2F20D0473
+:103CC000CF2FCA0E5D85FDBC72F5DBE8DFCB5975E1
+:103CD0002AD8019B6819EC804D7DBD18FF2E2FBDA1
+:103CE000B71B88BE3CE121200FA610356B0FED7786
+:103CF0008A2AC3892B225F7E4884783AB98660DE9F
+:103D00004866BF87DD1B547CE9C3E06F656529B851
+:103D10009F919135E36166F4B238B3017F46CDD10E
+:103D20005A88BFCB4D2424005C429CD400935D4450
+:103D3000707FC3A3EFBB0DCE1B1099E927BC3B07D7
+:103D4000F42A8FB78F652443BA9D6A13E6AFBC2867
+:103D5000631C6B2C5C0D4689B2BC3C7B1BC0531EA4
+:103D6000A11D08003F8B974D8988A104EDBFF22467
+:103D70006B47FE839D2BA1BEC99267BC437835E497
+:103D8000CA581E870F2EB5C6A9C9209D336D5FF98D
+:103D90001F8B1E8538C59861F29BF9ED1E0E67E6F4
+:103DA000491286FE030D56BDE1E179D71EDBBD3217
+:103DB000953E87F53E68BBFFF0AD30EA0117092953
+:103DC0004EB42F96A2DD60F8253BA022D8E34584AF
+:103DD000E5E7DBDBCF60ED4990F9292E0F51944ADE
+:103DE000FA7D8547C77C43172D533C0A4EA2E4D188
+:103DF000F7F9228BB7B4094486F2D07809CC337036
+:103E0000295FEA00FBE580321DEF4B33FCEA763593
+:103E1000847910A4ACD662371BF95EEB2B4AC6C27C
+:103E2000F7CC31A9B8930A74B93EB714ED687FCEC8
+:103E3000C0DF839CFD6CB37F81723995A39087713D
+:103E400029E523AF7B636C0E1DF77401D14CF69905
+:103E50004B8E629CCD757A9CE57DA2D57ABE5AF7D1
+:103E60008A75304E9197F1610D513BA05D0DB19E69
+:103E7000A3769DCEB3D8EB43FD175ADE27A85D632A
+:103E8000BEF767E4FE33885666EE7FC208FD4FB288
+:103E9000F5AFA6ED7FA8DF1C4BBF9D328BBFC602DE
+:103EA0009EB4F750567B6B4BBCD523EF0F5479591A
+:103EB0005CB32B18C5FD815A42199FD2CB155F1CEC
+:103EC00097D8F95E82F61B29B4EE0FD4723A162900
+:103ED00065001D5F215BEF339E4BECF71B5BEDA292
+:103EE0003720B845F125FAAA92B84FF0A957033FF9
+:103EF0006C24BB39D94A303E3D3763E066D807BFF2
+:103F000066CB7867E72CCC67467FFEEFB7542DE091
+:103F1000F781B2BCE680887809D78EC5F35B463F4F
+:103F20006127990872312CB23C08FCA1E32773F396
+:103F3000310FD13EAEFDFC7B932ECC2D35CD2B0920
+:103F40007985E6F1E615EC924CF308BB48358EC74F
+:103F5000EDDDD478632E6CBC233C9E658CD7B4C059
+:103F60003ABF26A78AF36BE27C6C8C7704E697064F
+:103F7000BF671D8FE74DA6C6BBD23ABF26978AF30F
+:103F80006BE2F7EFA6C61B7361E319719D2E6734D0
+:103F90000A7438527CC788EB5CEF7AD212D721E4DE
+:103FA000C97935A5846C1398FCD8E9ADD90874F1AA
+:103FB00051C3FA32D42BDCBEC67B56A93E5E2833F1
+:103FC000781B0BBDF136131EE1BC8D3E19CE49287E
+:103FD0004477B173133A9EA308E2F3216AAFEB98DA
+:103FE0005F5286DF1F6B0D617977EB2C7C1AFD9495
+:103FF000CD62F7815D3447486BB7BFEE65FEECB626
+:104000003CF586AF817EABF1B07CDF599711DD6462
+:104010004753C3FA009C9FEBB99E54808E9CB49D7D
+:10402000C11DA81B1387F5F7541C4AB6421C5476D1
+:104030006898EFAAA5FFFB0647BC4CDFB85CAC3D17
+:10404000B98CDD8BDA983A17D480F9478D0BB330F1
+:104050001F61D162DDA752BC2D1684D74AB9BE8339
+:10406000F350D7F1A5B6FB0B01D03C74BD02BA14D6
+:10407000877BE3AE2B7C798940FB0DFBAE453F236C
+:104080004C1B66D37EAEE3FAB6E6988B403C82CCFE
+:1040900077A2FC5ABCD8EA176C732754B073B65594
+:1040A00004481B6DB7A8C1FADDE5627C15B6DD0BCF
+:1040B000D378967B628C7C5B3B7EEC71D397BCFCA7
+:1040C0009E181E1F3D45CAF1DCB991976B6F6FC4F6
+:1040D000413700AF835C7532F9309C0F183C7FE4A8
+:1040E000727047EB9B184733E0CB97E302C8FB8223
+:1040F000E6372D79EF14B168541BFB0444DA538181
+:104100007AD8369F1DC29EBCD1EE89CA27F2EF072E
+:10411000CAF8DF331086CFFBBD61F39EF34A29490D
+:10412000C73F2C1EDC78580AB569437831F0F0BFE0
+:10413000CD47F773BCBF32EFE32AE607165AFE6E8F
+:1041400080717EEBDA545926B2899E17AE70EACCA4
+:104150005F1D2C07BA3C7A794688FDFD0B6E07255A
+:104160007E2D821DF4D7F7AF1759F29A79BF23AD90
+:10417000973D9FD2740E99A4F68D20FFA52D14446F
+:104180007B609D88FB1FF951968F07DF8F5BED5693
+:104190004B3E5E7BFFE302C40D1F80FC44D339BB62
+:1041A00082E63EA113ECBBB6388B4324683D0A7708
+:1041B000617342E8281FCAFBB2CBF5C255D67CC159
+:1041C000CE398BD53D1AE4D5D4F6C285609BB6B303
+:1041D0003897513F15EFE2E7511D244AE0FC85E492
+:1041E00065F1E620BFAFE36CF9BB9F8831B5B81825
+:1041F000F276E34A0D5DB7077322753E885F062AA3
+:10420000A3BB803EE510E6792F6DB9330C714235C2
+:10421000277D1C7C29B70F16FA585CE52D47A208AC
+:10422000E2E6C99CDA85BEEA34F55BBE85FDCD1DAC
+:10423000E11EFA66DECF03627A79B08C7FFFF26A04
+:1042400011EF1772131F9E577597F6CE027C3CB084
+:10425000664728DD39CB196A246286C75DCAEE0736
+:1042600020A46F36CC73D3E70FF63D4DE79DFDB923
+:1042700017E56CB6C4FA35B56FF6E50E6FFFFCA70F
+:10428000EC1CF2F3FCBE75424AAF04BFB1275526C1
+:1042900031B88FBD278B976302FB9E2AFFFB02F884
+:1042A0007B4A3D40A394F8FEE8FBE54688C3F60848
+:1042B0008413EB2B0B206EDFC3EF773F0CDF69FB22
+:1042C000B957BFFFF056D007339CE86FF6707BC735
+:1042D00080EF031FCBFBF9C0C7F87D247CDECDF156
+:1042E000E9057C06CE0B9F77A7C3C755017D33BC7C
+:1042F0007743260805C1FDB9720BE45BFF6B2B0900
+:104300007F8DCEE181D0BEC7E14C116D7F6FBAF6D3
+:104310003FCED1EF8375F2AE3E8EF3F3957A4380B4
+:104320008A4D3309F693068E07D2F563AC6B288B62
+:10433000C93977267B6673FB5272258390BFA056DE
+:10434000DD7FB34AF97E63717249BA38F1E37E6664
+:10435000F7678D10174F70FC5E991D7E12E0EE50CE
+:10436000EF457FCF299030D4DF346B8008A676FFED
+:10437000E567F8A670FF10E076CE66F756FB28DEFC
+:104380002141CE57C5E0DFA41D2590FFEE0B1EC5D1
+:10439000BC565FD500F23B8AC27C4657E00F2ADC50
+:1043A0007E4BF8FE7B01D04DB664D0DD37BB806E0E
+:1043B000A4A1F29550DE95CDDAFF3FFF37BBC05F79
+:1043C000DCE9A46D400EE63BD1BEB1CFEF250EAFC8
+:1043D000ACEA3F87F90DC3A76BE0E1ADB47DCF44F4
+:1043E000767FCB5C31B9E4AB4097577BD13EA3EFEE
+:1043F0009798EF1F3BCDE9ED34F7E77B3E55F0BBD7
+:104400007D3D46A2D7810BA7D78111E8F5988D5E37
+:104410003F26E9E9F59D74F283D2EBBBD0DE8E171F
+:104420007B5922FA76D857963F5BB01BFA93BF347C
+:1044300067FBD3F4297DB62586AB19122CE7998743
+:10444000E47DE4135FEED03D03C6DF2DFA27208420
+:10445000DC34FDCE9CB11DE4D839F42BFAD3F49BA7
+:10446000F43178E75EED8DA4BB376E8F9FE5C7FF13
+:10447000C8CFEA8DC4376FF9597ECA487C73D09F84
+:10448000E29B6C80E36C7CF311AF4FD721DF7F4E52
+:104490007CF36D7CBA4B19DFE0FC2F1DCE3724B6C0
+:1044A000AC0BE4F1C662C61797DCB306F922C54728
+:1044B000B156FC2E0D95517E1B7CF4E93DAD58DFC5
+:1044C000DEDE3FC23D819529FE0F57C03CF44BD440
+:1044D0000E763E6900CFE1EE2283FD2ECC13667985
+:1044E000B99E584C67E64192C07D1297723CEC042D
+:1044F0001F0DFCA0193C9E2527C922DF707EF655B2
+:1045000025AACCF7BE1CE1ED3D99E11A187F1719D9
+:10451000C0FB9A465AA7051CDE33D9FA027F1A3A25
+:104520003F9B1E5AE967E7E556F27EB23F57A2600D
+:104530009FDAF97DEE9A9FBCFBD828FD34F3F61183
+:104540000EFF05F07FC49F867F29FF2F83F726FE8D
+:10455000AF124AD2F27FB33FBDBEBAC9FFB7E5F78B
+:104560006FA6E3CB463FE3F7B3E17BBF9FE9FDFDD9
+:104570001C4F178AEFFB79FB7B2E1CDFF78C80EF3B
+:10458000ADE788EFFBD3B5A7F8FE173FCAFFBD081C
+:10459000BF4FF362BCBC7B26D92794A485E3BBE65E
+:1045A0007E148DF54379EA6381D2FDDCCFBA43E90D
+:1045B000EE45A2ED1E4BD76E815F3592CFD7E1FD60
+:1045C0005F5FF2E2BE02D58F4FFC8DE9E047E9E87C
+:1045D00060AEC8E490E2BFAC0BF4FD5FD1FF817424
+:1045E000FDDFC5E5FAD9EC82D786EC825FF8AB87B0
+:1045F000CBBF5DFC7CB2AC46927E8CDB0F5C05F2DF
+:104600006AE71DD902C4BB0AF584007EC2CFB91E79
+:10461000BB022E0DAA1E6AB7534E08F0773A7646B3
+:104620005501CE4B99FAFBCFD1FAB3C341E1FBADB3
+:104630001FE59DFE3B782EE0F33B5F3BA93F5BFF10
+:10464000BD1FF54FF81D78EA93AD72DB988718EE21
+:104650006579B6B3D2FF5DCB9FFB64AEC7C227CDF1
+:10466000F2FFDD145DB1FECE57FF50F83EF333BDCF
+:10467000F2453AF8EC78391B9C17F965434F39330A
+:10468000D3E8297B7F869F6DAC135C8B618EFBE446
+:1046900064A6F47736F4E7ED14F11C552397278DC3
+:1046A000B3B2B8DDAE7AA0FF07781CFE8155F7D60D
+:1046B000C0BEFAAEBBD40A40417E33D37BDAAA71C6
+:1046C000185F2DCA142CF933C633D5DED97711FC07
+:1046D000BD083A6E318C7BC51C9200BF3113EC06CD
+:1046E0008C57A8F8778DB35DBD4188CF6E127A974D
+:1046F0002C07BD7A95979D8B092E3ECB7D991B2C5F
+:10470000744B825567A9DF86F5D58C5EBC3FE59C6E
+:10471000EBBB7AD3DA59B599A2E14F5C9E593D0AB9
+:104720005E83018C7B19F81D3E0E5BBF9A705400AE
+:104730007CFBAA041552EF7C944EC05E124B9398FA
+:1047400037754D15A31742FD92D1EF5FD968C0159B
+:104750001E75BDCF112EA3DEC8E3F17AB6F316A9FC
+:10476000BF3FE665720C2BD2F2878773D2EE2B180F
+:10477000CFAE5655872B923F54B54CFCBB1DA9BC00
+:10478000EF507091EF7FBEDED0BCE22C3E6AAB9F53
+:10479000BA7F24A8A0FD877FD7C344479B3299DF07
+:1047A000EACC0A7F2B13E56508EF9FA5E518AC0757
+:1047B0005168D987E50DF85D4D953BB01C64F589CE
+:1047C000AA9E13DE69BBCDD84E4EF5D383656F6AC2
+:1047D000DCAD386E2055DE86E54256FF5CC71976A3
+:1047E000FF4A52C2F97F2CEB99B06F7A7DCB5731DB
+:1047F000BE7443CB4DF8EC6E556B204E67DC4372B4
+:10480000FD0D5F55C19FBEE1EBF7E1BEBED1FF429A
+:10481000F03B80FF35B91EEC2567B1187EC43BC460
+:104820007F43707460B95166F7FC2F9C75B2A7C3C3
+:1048300014BF53E0EFA5437E8D66BA07830CC9C34E
+:10484000EF09FAD399E741CFC3E749C8214ABF1F0F
+:104850007B4BE331A4E75A351DDF18F31DA97F63B5
+:10486000BE23C91B036F297A2AE57F5FD716BF7461
+:104870004FACC3FC9F850287D3C7EF8BE4F51AE9E1
+:10488000387BCB912E34A0DB46EEDFD9F58331EEB9
+:10489000F784C8EB801F8813DF55391CBFE78A37C0
+:1048A000A3FFB19118817BB93CE504F7C5023E63D3
+:1048B0005F9DC9B56F7B8D720C934BC2A5BD28E778
+:1048C000DC9A21F7989E5433FA74B1828EB3F5CCFA
+:1048D00095C18B200F3412848B0869F905B8E7392C
+:1048E0005B6265123BF3C2A142D007EAC54288D29F
+:1048F00043C7E72F1C2E22ECE822FEFDF4CF5F40D9
+:10490000FBC228C385BD65B4EC4995752548CB2508
+:10491000A9720CCA3BB9DD7766EBE72F74A03E0B9A
+:104920007F6696AB355CAE9EAF3CFDFFDA45D4E9C1
+:1049300000800000000000001F8B08000000000045
+:10494000000BE57D0B7854D5B5F03E73E6956426F3
+:1049500099BC278190131E12157012480848DB0974
+:10496000AF862B8FC1074609304978846700AD4E6A
+:104970009596810082628DAD0FBC2A0E16BDB6D50C
+:10498000DE68E92D7F8BFC83A0424B3156AB684536
+:10499000A350A56A4D04B98E56CBBFD6DA7B67CE3D
+:1049A000399909A1DAFFEFFF5DF874B3CFD9673FFA
+:1049B000D67BAFB5F69EB367E1CFB7183B6B2A192C
+:1049C0000B3396CBD80E6D8367FC28A879ADBE213A
+:1049D0001A635BF05541BCDD051E3B63158C3D98A9
+:1049E000197479A09CBEA6CBEA8476CE921C77D0AF
+:1049F000C558B1F79370357C5F3C8E310DBF1D9C5F
+:104A0000C5D818E8D77BBD62CF817218F3288CDE39
+:104A1000ADF740FB1C3763ED50326B84B1618CDD28
+:104A2000E59275980F9481D208EB80E7A91A7F6F01
+:104A3000C13A3C571D6C651BD4D34A993F02758F10
+:104A400083CD0BE0F81E0BAD63844715A542F3CD73
+:104A5000F06E601AB477D658FC112833B074E9D7D9
+:104A6000BF81DA8DF058A994F0989213BCC8837076
+:104A700061ACA60DE7C5A281525847EA853959B7FE
+:104A800042ADBAD47A3D83211F5ACB02F36D8C55C7
+:104A90007A0229081757594E6A7018D5CBF07BD780
+:104AA000464B98015CAA993BA294C4E102334F0D96
+:104AB000B893E3E395B5C1C0445BCFF7B29C758D65
+:104AC0001AD0AF439613110E308F8F6AFF7C0F2ED2
+:104AD00067B9B3CBCE06023E07DF19602AAE47A303
+:104AE000F7CE5D33A3FDE0FD8ADDAB18CE777D5AAE
+:104AF000FA38C4A379DC57BEB8D71380F7299F3999
+:104B0000026D09C65B22E0FCF2DA5AFA0EBAD7ACA3
+:104B1000798CCDC3A50C6484D00E27964C39EBA0BC
+:104B2000E5BD3C18DECF659C18AE0CD44F6300D7B2
+:104B3000865A95A925F85D777B7616EA733BEAA736
+:104B4000B2115009D94EE07327FC3D0BFD0659E622
+:104B5000640F3CAE0FF3E7D41EFE5BC07C9373E1A1
+:104B6000BBC6CDA6E76F4CF90B4BC7F7D6131DA5F7
+:104B7000F1FEAFAEAD0F4C14ED4ED3FF23B49E2B20
+:104B800035E647BC5DE94B8B8461895705AE094C1E
+:104B90002C8DF7F7EA97EA3C848B191EBFEA86470B
+:104BA000203071484F78340414BB473B375CFA0A15
+:104BB000877A6BD9E45CAD271CCCEB0788DD8E705F
+:104BC0005E0070BEB524393CA01DE1E3D56BA01D8D
+:104BD0002C65B23AD566013834CE54984321F8A6F4
+:104BE000B341D8CE3F75926EBE66389AE1D5F8349F
+:104BF000F345A1DFC6BBDD3EA070F607099F280084
+:104C0000AD12E4096FAA5FE73B387F0FFCC5755E04
+:104C10005E55F66C0ECC23B841F131BEDE77F4EB75
+:104C20006B60818CA842EB7E2709DEDFD1AFD33CDD
+:104C30003FF3FC53505881FC0BBD51F28303BA760D
+:104C4000CC1A1D1618CED8E31E77CEBB69501FC1F3
+:104C50007C6781AFCEB0711923F1FDE01CE26F33A8
+:104C60005D7CBA56FBC1019B9ECF399DCD0BCDEC2F
+:104C70001E17FB5758B0BBEE013807AE516FBF0A85
+:104C8000FEFDCAC1EC8DF86CB557D54E6423BC60EF
+:104C9000BD842F3F6392BE1896E17D2AC06F2673B4
+:104CA0006A2EE8E75B20A4CEC25AA6FB5334976E67
+:104CB0001DA75A951A94A380BC8C2B87C7D76B9ECF
+:104CC000F76AAF9DC6037AFC444F8F66B8BC523B6F
+:104CD0002803E5C80B71B88C381FB84C42660678BB
+:104CE00078B25954013C7729CEC8C330A7BAD0CD89
+:104CF000818923112E2C6C07D179C25342F251AE17
+:104D0000DBC6E49F950CE5699D9D05715D6FD858E4
+:104D1000ED932E2CA345E53AB9F55E76F50994D3CB
+:104D2000B25E17FA3EF50F84487428E979AED315C0
+:104D300055391D7ED84D3724CFEA3CEF5E4C786262
+:104D400067619D6AC6320DD7ADA6A58F60198C6DBF
+:104D5000C626B04E7B66A00BE5BF9A362082F4973C
+:104D60007ACD8F37733CFEA866960E8F290B7E1185
+:104D7000A6CEB52C03FCD304FEAA05FE524A9D66BE
+:104D8000FC31E4D370298B3CA2081040FDD4607F35
+:104D900004F93699DE90F84C29B57EDEA1A76BD6D2
+:104DA0004AF097786407467521BF06BD56762BBD3D
+:104DB0002F25F8043D123E5D36D427F342B653FA50
+:104DC0007E8205F323EBF0BB2D0E1F3E6BB068799E
+:104DD000D80EE0E4413DCE4A7D3EE41F1686EF2426
+:104DE0003D215CD198D0F5DF016B2828C7FE407AC1
+:104DF000E2779B75E30CEC396E375F99FB357DA745
+:104E0000AA603F901DE1F3F974F2BB2493DB0FA776
+:104E1000BCA3DA2C0393C3AFC199EDB766C7EBEF20
+:104E200014386B2309F480EC4FEAF32C35E8B5E035
+:104E3000DAC23B0F1E18877AD873114832769BED81
+:104E4000A183078B1892086385F8BF870EFA5D640B
+:104E500077883A1026CC7F476A77DDEFF4427D6091
+:104E6000773D8CF5ED301C1B0B764BE6430737C0C6
+:104E7000F79F1E7390FE3A55931A41E6C90E4D6096
+:104E8000C761DE5630733280D4A00863E90CF5A305
+:104E9000F52856801CC03B5BF32908EFCB3335A2C5
+:104EA00007ABC6A26E985CB6D5A720BC7E68674DDE
+:104EB000426E5C385367BF5C9EC9ED0E398EC3C924
+:104EC000C229E5F17E19F3AD433D629DCA48AF00AA
+:104ED0009F93DD26F95BF6333793EBCF6EFE3C37BD
+:104EE0003FCFCD4CC0CF872D2BDFFA1EDAB3BF5595
+:104EF000D923B09439DEEFD2F359A1462AAF092D58
+:104F0000A6B2498CF767166CC27EDA6B5F9A732380
+:104F1000D06FF32E870FD5F2F21BFEF2830A0DE15C
+:104F20000478C7EF1634DE5D01EFED432C64CF6EDD
+:104F30002E62B5484FF6750AD9475B347BCD2E28D3
+:104F4000EFCDA8BE2733373EAF7B3326529DD568C1
+:104F500016A4F3D54E4EE79F1EBBC5DB8076A5CBCE
+:104F600045FC625F57728705EAEC10CC9BA1FC60A0
+:104F70006467A80E5E6ECEB4123D6D16F415167001
+:104F800077C610C99CAE57C2F84E6B98A19DED8CA8
+:104F900059E9B95D81F925A053D99F33064C3A12DE
+:104FA000C7337F6FA7E7B82EFC5ECD6606BBE7CEA2
+:104FB0004C6E37DFD93D8F343E8F6C733FE9FCB9BF
+:104FC000E03FF33C3EF04CB81BE17F6F86FF9E4C08
+:104FD000B2C33B6C28CFE7BA7E7B5419D11779DC7A
+:104FE000A1A03C9EFE85122D06F8A554AB91F52597
+:104FF000A8D73CD346011DB06A9B0FE1D93E38C704
+:105000003D5037FE6302FF2F5A3D6E9C676012D8F9
+:10501000D544DF2CF74AEC67526325977F6070E92F
+:10502000F4EC8BDACECD0351FE866DB45F9AE70CBB
+:1050300047707E3ABB4D39CBE5B266AD8CDB7FF372
+:1050400026AAFE94F49EF61D6C430E90FD2765790A
+:1050500018EAF0DD9BA2FAD6C4D357E1323A98C7DA
+:105060003E506F0FE26EA912ED1BFE675EC868F737
+:1050700099EDC286AAB2E7000D009748CD28A4B3E7
+:105080000B2D44677DB59701D39C5E26B578705F84
+:10509000F5A09013D3271E9F887263069856D8EF09
+:1050A0008C89AA270AADB7862CCC0F133FE2572371
+:1050B0000AACED4869C7A16F21DCAA6C1AE9AD52B0
+:1050C00076FB1539F87EA407E11C107608B4E7FAE0
+:1050D000CDEB8C0C8167EDFEE3AE461DDD1DA93ADC
+:1050E0007E21EE5740EE3525A227C6D6D1BC0EDC78
+:1050F000944AFDBC75971271C0FC27A95FFC7E34F1
+:10510000DAB3DFB3F91C1A2DCB82789DEA6362E330
+:10511000EA774DD2D901C759A092ECCAB263D50E35
+:10512000B45F372AC4A712FEF342467B33B812ECB1
+:1051300032ADA77D0A9DD9919EFB6A9F9AEDABCFB8
+:1051400033C1AE023A67E5AC5C6F5725D353D2AE9C
+:10515000B232BF92457AA8C38A7A773A3C4824078C
+:10516000AECD5008AF93D40F093FA7AA540DE175F7
+:1051700024F4BE0BF7E347BE50F93ED89F6BB0E373
+:10518000F2B3B85F60BB1D0C32F86E7BA133B20E78
+:10519000BADA77D345F91D841FEDDE7188C7DFDAEF
+:1051A000480E279BAF3BA4B2C14098D3420A951248
+:1051B0007FC5A11466D5E987629678FEA5597CFE65
+:1051C000B96B9845837133C3CC9F687F2CDBC1BE1C
+:1051D00078B29551FB6826CC6FC5600BD1A7DC1F58
+:1051E000A7D8C2FE7EB07EDB9E5561DC2717C3FCCC
+:1051F000701E1ACC0FF56549288DEA0343D9540E69
+:105200000A65523938D48FDE0F090DA2F282500997
+:105210003D1F1ABA98EAA5A191545E182AA3F2A2DA
+:10522000D0A5545E0C7A13DB0D0B5553393C741921
+:105230003D1F11BA82CA4B4233A9F48566D3FBB233
+:10524000502395E5A17A7A3E32B494EAA342D7512D
+:10525000BD22B48ACACAD0CD548E0EB55059155A43
+:1052600047EDC6846EA3FAD8D08FA8BC34742795B6
+:10527000E342F7D37B69B7A40A7EBC4D9BEF417F25
+:105280000750B886749C8CEF1665713DF042A67F7E
+:10529000465645BC9DDD027ADCD5B35D6316D76307
+:1052A0009988D704FDCDCDE2F2F923DF3BF70C65F9
+:1052B00071BC6DF1F6EECF60A589F71B71F9C0D70F
+:1052C000373D4BA372BBB5DDAF22FDAE64BE303CB3
+:1052D0009A36EA4505E5CB0ECD5A93C8BEBB37CB0F
+:1052E00046DF3D98195C81EB4C2B397100E5C98C88
+:1052F000B0E7F7E3915E86E5FC763CF457BCC1422B
+:10530000DB7D8D79F6A17F4D9BC8482E4ABF12D810
+:1053100075067D7A87800B636D0707123F0D2EE7B8
+:10532000FAA7630AF297FDA681B47FDF6E8F2A5633
+:10533000B46F5633A6B7FFB76F6A7814DFC7FBB3F5
+:10534000D33C8B37B367D0C42E69D5C6A740396824
+:105350009BFF9914F8644824383E15EA431F0B3F1D
+:1053600083E5856D91F169505EBC3BFA0C6EE38676
+:10537000473BC6BBA07EC941B61FD9BFAC5D9BE011
+:1053800086FAC8A3FEFD4006ACA22338215DC3F90E
+:10539000445AD2613EDBDF04430FEA551FB6AAB080
+:1053A0001D8AE31FEC38B4DF245EDCA3DA2766C372
+:1053B0003FFB5FEF2953F17B6B474AE6B09EF8D97C
+:1053C00081EBC675821E7904D6D5DF1F553C3A3A6B
+:1053D000F98DE067C0C34328E7A45F72C7862CF24B
+:1053E0004BEE48F554E3905D9398E7610DE9D84A98
+:1053F00070B26F1C48FE384977005F833D7B87A001
+:10540000BBEDDDF66E62F8FE46C8BF7F15F8FE5BA9
+:1054100016E78764F07522AD8C39371F1F167C099B
+:105420007C7C50CFC7E6761F0B3899E1BCC3C20E17
+:1054300082AE8271814E395F31F4A37D28E8FB5C36
+:10544000707DF75F8C6EF70B39910CAE4CCB213928
+:1054500009F47A21FAC792C91BBBD8CF98DFFFADF8
+:10546000A79CE37E5B0FC8B941C9E5DCF302DF49C5
+:10547000E597903376937FC799CDF9A6D213B0679D
+:105480005724F0537B730C7EEAA9AAA71AE50D1BDB
+:10549000CAC88E4E1B1609E33EA538AC95ABD80C96
+:1054A0008532C2B1B094FC0F2560675801FFD0551A
+:1054B000144BA7E6B134A0FF5DF29BA7DEABE73744
+:1054C000A9EFE3FC28E9226BC7ADDC2FA9CD04FBD3
+:1054D000E5DBD9C2AFDFDD0FF7836CFA6EE18E5BDF
+:1054E00075727087D74B75D93E19FD2E10EF776C0A
+:1054F000584FF0748E4B6C375467F3B8C2767B9775
+:105500001FE93CFC4DE6417B2673C33B249F32419F
+:105510003E29249FF8F8FD43A98F86A1EECFCE1334
+:105520007E004FEA2CF7FF3B7ACE459B0AE5D43844
+:10553000CF3E15E334A08734E4D37130F751082F00
+:105540003BE15D631C8FDA381641BB17E016C57D61
+:105550007BD8E2263F93DDDEEA477E66F64C5A7F33
+:10556000A5273823BB17BEF0A4696588D46076DB15
+:105570001417D0DFA6124F2AD6E7407D6B158C9BFF
+:10558000D5C1447D8B6BCC3FEEF708FEE8E787364C
+:10559000C078FBB2FC73919E81AE8358FA877AACD7
+:1055A000E4AFF6F6CD1E90FC19E7274F99E4A7FA71
+:1055B00061240F9760BFB2BF64F6CDE06C2EE76E3A
+:1055C000166532FB46D2FD79DB3762BE8BB37BE7D3
+:1055D000FF570EFE68DB4EA6F33716DED36ED5D02E
+:1055E0009FC1FD3416673BF5E716FE463FFA1B8167
+:1055F0000E9C83791DFF24F21727876384E623FD21
+:105600008CD29F982EE88A599508EAF1F42A8FB532
+:1056100081FAEB6097437FDBB2B9BE917C8D72EB70
+:10562000A9612897B2ACB85F477F923B2BDE3FD68B
+:1056300033CAE3F289897DDC7562CEADEB7D19E872
+:10564000720E1FE17E94D6EF73BE9CD69F45D6A303
+:105650009CF033CD03ED5398FCE337F893A77EAE6F
+:1056600000EF821EFC5CA55219CCA26ED8EF4DF360
+:105670002951DC07DA2DCE08EAD2EA4227C3F8A680
+:105680003DDD12C1F888FD1D85D6692F4F8BA0F036
+:105690009B5858958171CCD387F7BB8209F07F75F1
+:1056A000B0DEE0FF32C3B1BBDD9C673D08C7FBCF76
+:1056B00011A77D3EBB3B4EBB0FF972FAFCAE0D76D7
+:1056C0002D1EA795F1C702EFAE2DD5A8B29671FB9E
+:1056D000B49045D6E9ED2A5D1CF477D8CFFDF138BA
+:1056E00068FB05FA386873E11EB477EFEB8E83062A
+:1056F000F712DF65B79521FDDEEFDBF5933B109EDA
+:105700000E11AF1879CCA5A19FBE627F2EAEE7F730
+:10571000A6F9CB52FAF1CCFBE03F651BE30BA77D6A
+:1057200057644489B6B213F2B7F42FCAFD30FA0FAA
+:105730003D09F9D0086F397E9DC2F7B5CCA670F946
+:1057400027F428C897BF921C8830D29B7E87F230FE
+:10575000EA9BD3BE913E8A7B269137723E00C721D9
+:1057600089E2BF305EC238AB2387EBA93A1BF79BB7
+:105770002AAB2A56E2BCEADC2EC5A1F3F79F16FA43
+:10578000CC1C175233BEA8080ABF77A2F59BE33B97
+:10579000A7515FE47278E9FDE4E782D7515B2BC53E
+:1057A0000F8F2E50D93AEC27383A9F25F85E96AFE6
+:1057B00023DD0C61EC18C2B84287CF24F1A2A36BA1
+:1057C0009B28CE6C8EA775BFAF4FA945FD5D8B7032
+:1057D000D48D5B25E0375394CC11D43CF0DEDE70E1
+:1057E000B78761FC6BC827156137FAC5BA7E89F1A6
+:1057F0000BF63D37F92B6AEBCF54AC1BAE83671524
+:10580000E3F1D9FDF77934785E3B64436ED8951C9B
+:105810008E3373381C6FC30763C81F333287FB375F
+:10582000FBE48F61C3785C88ED4FA1F869CA1F550E
+:105830001FDA0D382ED703DC9F7CBD889B98E37858
+:10584000B5A11506F9921653584417BF48B3B6913F
+:105850007F362D66A5E7667ECBCD31F29B847F3205
+:105860007C4AF89B9FFB72F87A8ED62FD6D06F6851
+:105870004F4D6C07DF22DAC9BA391F2159DC7DBED2
+:10588000C0EBE9E0987CF457D5DAC343FAC2E712DB
+:105890003EE7CA739893C3F5B8FB9A97441C4FDD53
+:1058A00080BD49BD9A66ED3D1EEB37C563D346F515
+:1058B00088E7FD53E2B1EB7284DFF03CE3B15304BF
+:1058C000DD9E2B0FE56ABBD1EE91E52C81C7D3C1DC
+:1058D000141606F9785DB54A7128A00FD28F47EFEC
+:1058E00056C8DE8CD63B482F37D6A7907FB6B14C32
+:1058F000A5F78DB7ABA43FA3201F96817CF8BD9080
+:105900001366FF6C35530CF1F3E9A3520CF56B16DB
+:10591000FCE8F76BD1BF5C65D370BC231AF73787FF
+:10592000FD2AD9AFD0872F8AFEE9BBBEE1437D2691
+:10593000E9E1885F257E0BBFACFA70D876E18F3E37
+:10594000B2B92C82792A4C89C7E9B541D87F23C5E1
+:10595000815FF36EA33867CA97F70602B47F0C6ABB
+:1059600065A43779FC3445F0E984C2AA59A8C7DF99
+:10597000DA6A63E8377A6BCD69E2E78EB52B292FB7
+:1059800042FA97A57FD8EC6736FB977BF8954DFEDA
+:10599000E464F90CCF26A10F29AF92D10788ADC3DB
+:1059A000FF881C93F2E375B1CE0985DB6E5F07704B
+:1059B000489BAF121C245DBEF6C52D0FA21C4E01E4
+:1059C000FA58CF109EFFF12CEE43D86225A11FD9C3
+:1059D0002DE53AE64F94C6F1724D7071771DD97F6F
+:1059E00076D32A43DE8759AF24976BBDCBAD3B728C
+:1059F000B8BFC2AC77CCFCF075EB9DDAFABB4BF1CB
+:105A0000FBDAFA05112CB7143A9B50FE9AE583593C
+:105A10004FCC32C9D9B87E505964A47EDE1AB58BFA
+:105A2000EB093BBDFF3485E73B849CBCBC3135FDB5
+:105A3000612C3F4DE1F90E61340AD14E7D332DD2F8
+:105A400042FBF295A3914E42CCD711C6757A53C949
+:105A50008FD0DA9FB753A7A472BBFC4035AD5795E2
+:105A600086F9866AE29B16B19607B28345B980E74C
+:105A700016BF2505E30B13DCD643E87A691D6F6179
+:105A80000E1687573C2F847914F89EDE29B8FF2C18
+:105A900073DA07919D3A2417F1F17DD81F02DD1FBB
+:105AA0003EACEEDA014B3DEC1B9991C84EEFD603AC
+:105AB000A638F2B1EFBC3A00F9F6CF2CE8CBA5F846
+:105AC00071E3ED181F6EDEAD527C69CE0DAF5D4007
+:105AD00076B7294EA9A63B4BD19FD2A2A4FA509EDD
+:105AE0004838EE73DB49CEB41C4BA3FD44CBDB8AB4
+:105AF000A8BB491E4AB81F807605A33057C94D720E
+:105B000053C21FD6E5C775493C54B3E8E171255F20
+:105B1000695D97F5BEAEFE1EB20F90CED4F83A5432
+:105B2000B795D6D7C9527D38BF90F00FB137D2683C
+:105B3000FF27F1DC2CE851E27985C073E79E333F03
+:105B4000B814DAB7FAB328EAA016318243E71B6E1D
+:105B5000A2130907B96EA08B20CE53AE7BFF9E9196
+:105B60004783F87D7A2AC5F1A5DD2DF30ECCEBAF86
+:105B700013FBF7A5B94AB7DD8BFE8BF6ECF14B733F
+:105B80002B12B417F62EC07B05C2BBDAC33E89B018
+:105B9000F83E2F597EC34DB946BEEB437EC34DB987
+:105BA000B93DC7FD0AF8DC88FDF5159FCD56D766CF
+:105BB00025230E6FB96F2696D67AF2BF99FF243E41
+:105BC000943DFB3EC338BE592EDCA8AE640A8CB3AC
+:105BD0006938E74BB68669941F64E29773C91BC0A6
+:105BE0007F04F1944CEEF415FF3FEB89FF9FF5869F
+:105BF000FFD6ECC013084F1CAA5F39ED0BFF13DB77
+:105C0000A33CB10FA4F1886EBB3219E5B3C9FC18EF
+:105C1000391F9927B317935673757938A53E05F543
+:105C2000441FE863AF7E7E5F037D1CEA9DDFA3C453
+:105C3000A7CB05FE97CBBC8C5DBDE765F4017F4724
+:105C400013E1EF46D5D7152CE93BFE8EF7C4DFF103
+:105C5000DEF1177C17F1D762679F90FD5E55EF4527
+:105C60007AA9F4F82FC77C9DBDEB84DC2901FC9553
+:105C7000A0BDA4925CFB21BB88E4F6372D169A6F79
+:105C800027C8EB87953EADF3BF73C94E095BB3A040
+:105C9000DF1BAF6014DFF36AEB14ACE76BA0A7B5B2
+:105CA000BEAF57C9EBB15E25AF777965CDCB25FA8D
+:105CB000BC1EE9D3A979ACBDC92B4FDE79CB2B4FE4
+:105CC000DED72BAFFAE59D875EED03FC87E0FC9203
+:105CD000C989BEE681029FB27E593DC7879D2EC508
+:105CE000D5AAD39D5C6F3FA9083D5E16A4BADB49D7
+:105CF000C2E280D0F3A776F1F7EAF8C476E588BC73
+:105D00002C9EAFD0B62A6035E49384E9F91DFE538A
+:105D10009EC12AE669BB683DD9D3B81F52AE5FE683
+:105D200069A78BF56417F175671FE379ED125EE9DA
+:105D300062BF91516535EC2324DC6E54030AFAD11D
+:105D4000337318A649C03E6198827EAE4CBFB1BD88
+:105D500084772EDBFAB18A295F35C6F7B9B89F1967
+:105D600081EF75CF13EC5F013FA5983F764D9EF014
+:105D70003FD89917F51153EB7AA523DDFE249847F8
+:105D80007197DEF7270BF364BCDDA8F7DA525842AF
+:105D90003FC327821FC05E217FB32AF4DCC48E126A
+:105DA000CA7759EDD6C8FFA0AA3EE7D4929EDF6716
+:105DB000FA81BD75F0C8AE49659ADEDF12C832D4EB
+:105DC000F36B0B0DED0B82030DEFFB355D64785F1C
+:105DD000B4B2DC502F0E8D35B42F01C0EAEB833600
+:105DE000FF9BA1FD90D6CB0DF5A1DBAE35B4BF3046
+:105DF000D260787FF1634B0CEF87B7AD36D42FD9E3
+:105E00007D93A17D8BF0239BE1F2AB3CBE7F6BB118
+:105E10007239B4CE554EFECD1697D1BF79A7807F8B
+:105E200075C6B852F4ABB7BC53568AF03E903E9656
+:105E3000FCECC9E8C22CD792C953F3F33631DE47E4
+:105E4000CFD82D48D72BF603DF5E0275D7EB9B70BA
+:105E50004D5B86F1F8AC8DF17C2119AF91DF77C7EE
+:105E60006BAC3EEEAF4D77B15B13D0C59D799A51C7
+:105E7000CE0AB929E92819DC243D9E0B6EBB057CAE
+:105E8000BF2ADCDE5078BEAB5E1F3C99605E1FE728
+:105E900059447C39F8873C6E0F8D4A254BDE43FC14
+:105EA00078BEFA40CE03F4C131AE0F8C79BA1FD55B
+:105EB000BEB4F05E0DDB2FE4ED2DBE52C44B327F3D
+:105EC000FAC7026E3A7F7A13F7A7A71AE0F696E4AC
+:105ED00077935FAF25FD73F2A7B7D87DA57DF1A7B6
+:105EE000BF05DF22FC77E771FAE8C6AFF0C727DB12
+:105EF0004785183B84E72198CBAAE9F74DC9F6C737
+:105F0000529EC3FEB814E3B4ADB8FF5212EA414743
+:105F10007E05ED9F491FB4821E74909F801DD2A004
+:105F20007EE3040BBB558BAF5BDAF30EE673DA55F9
+:105F3000C2AB1BBF67DF67D7A7A85FCB3ED39BDF92
+:105F4000EBBEC4AC67CF19EF233B6D1AAC7FBD6EBF
+:105F50007F2DE1638EEF49F84CF3F1F8DD46D08FE9
+:105F600018DFDB97CBF5F446D87F231C3DD901EF32
+:105F700000B4E7E1F9C3888EDC4AE21F0957739C3D
+:105F8000AFAF72676C7E0F3B6E6C7E2F769C5CFFB2
+:105F90006AB17F9EA40E6B433FE6A9989DE0A632AE
+:105FA0009E77D97CD0C62284479EBF2CF1688B6D2A
+:105FB0006A47FD6C63E67C652D03D76F3BC8CF89CC
+:105FC000B11CFE3ECC9CEBD0EEC9A832EAAF4CBF70
+:105FD000517F65D76499F499517FE5D71AF55741F8
+:105FE000D0A8BFFA35959BF499517F1587C69BF4CD
+:105FF00099517F0DDA7CB9499F19F5D7D06D46FDCF
+:106000007561C4A8BF2E7E6CB5499F19F5D725BB15
+:10601000D71BDE97456F35BC1F79F087867A45FB25
+:10602000BF1BDA2F3AF40BCAEB197DF46143BB3185
+:106030001D3F35B40380B763FEF77C420963979E2A
+:106040007CCAF07EBEB0D7BED1F56B433FAC95E7BE
+:106050007187E12FE2EB3D16B4A39162655DCFF548
+:1060600003BCAE8828BE28345BBCFBC94A9CC7076A
+:106070006F4E3988FD2CDA66CCFF5E1C31D69BD979
+:10608000C00C940BCD401711A093A59817AE936F39
+:106090004BD94A712EB06F74B6E8D0158CF249C353
+:1060A000FE76CC7B97EB94F4E617F426E727D7BB74
+:1060B00014ECBFA8165FA71FFEF2FD66871DE976E8
+:1060C000E16E85FDBBD2733D4D7BEEDCD42FC1BAB2
+:1060D000CCEB30DBA13FC937FAC727A92E8A179C22
+:1060E0007A59F5717FA3910F571FE27182D54F281E
+:1060F000E4AF33C343DAA7C9E0A286F9BEA139876A
+:1061000045223AFED3043C1C5E23FF9DC27FE07C07
+:106110001E5023986F94A2A59AE9AD32CA7AC2396B
+:10612000ADD4C8A76638BB7D8509E94A83BF388FDF
+:1061300085E2FCA199AECC705FB1FB4E3BCAC3F3C4
+:1061400085FBD1FCC47109D076A3EC09F2EB245C89
+:1061500061DFFE26CACD64FBD9F7F395F33D5FF40A
+:10616000BE5E0E7F0DFBD933BDE9B94EF4B7817D1C
+:1061700069F6B399F5B0B267FF674A3AF9B53B1CC7
+:10618000C877419F93E7C198F46469A9414F76EFBE
+:106190007BDF5168DFBB2BC36FF5C2FA0E65F86D6C
+:1061A0005EB48732FC76AFCE0E6D01B8D0B91FD089
+:1061B000534F26B013C77BA57D1420BFC9C66ADE26
+:1061C000DEDCEE222F3F27B42FB7D24BF6E7DB659C
+:1061D0005EB23FDD95BDDA9F778838D16D18871C98
+:1061E00012CF0FBA5DC46B80EDFC88B78DB68057B7
+:1061F0009F3FECF666D2BCD2C73CD58E79D42D1E1B
+:106200008B47D1B0E4F9DC1B5CD69A9DE2BB1CC382
+:10621000777C9E2AC21BE06A75593FD7D3ED782F51
+:10622000A3F7C9D639DECBED5E1B0BDE8EF6908C64
+:106230000FDBDEA976A2BC6B617E0F97933E8F3E8B
+:10624000FFC3C6783C78BC880FCBE7AAE71FCBC357
+:106250003A9211AC463C9AF3B06ECCF08FC7E7216E
+:106260006BD8817667C899785F5C23F0AA8AF5823B
+:10627000014A7445F350CF3FFE03F6E61538EE8D24
+:106280006A98F2245BDC95A54157DFFD5C73BD9CE9
+:106290006F75F6D15C3D9D9AF913ECD3CBF11C9947
+:1062A0003FA3D04ADB0EABAF14E1BD19FF3D86FC26
+:1062B000B40BF0FB1E79AFE21C2EECE37ACDE39534
+:1062C000FDECCBF22FF3F27CC3155E9E6FB841D587
+:1062D000F5937E8E7EA49FA30F7EAB35DEC4FED1E8
+:1062E00093A8DFFB0AC75BBC3DECCC5BBCBDD89977
+:1062F0009F1E1B9A81F16CE9EF32B793E722657D0F
+:1063000073A671FC4DE5BCFE4381BF3F8A7B3A1EFC
+:1063100015F3709ACE8B3AA732BAA7439E3395FDF8
+:106320003CEA7553FBB5D9E31FC5F96E2A51681FC6
+:10633000BA295331EC47EBBDD58F225E23A2FF472C
+:1063400005FDEE18C8FD39E63CCC25D8BE024BDE73
+:106350002F9E6B45396657D58470FC9997FB8B2E21
+:10636000878EB07FE9776BBC5B11FB27E3BD08C06C
+:10637000E7AFA481FC39BED546E75E17A8AE4D480D
+:106380008FC9EE39A81F16A0FCA7AF7A7E0CE19941
+:1063900096D553AFEEF776EB55DF799E23FBADF73D
+:1063A0003CE2FD1DA99C4EBBDC2EF29B9BDB9D10AD
+:1063B000F8D92AFC1A28D751BF64A96C65223D730D
+:1063C00042C8D57FFC5C33BFCF23DBE5A2EFCCE72F
+:1063D0009A3BEC1D1BF371BEDF507C787E21BFCE53
+:1063E000B32F3F07CF316AE4E3DB54C2D2ABF07D79
+:1063F0009985DE675EE9D964C3BC6F8D61E63EB303
+:10640000C1386E18C755C0E3385BC357ECCB8776ED
+:10641000195A171B388CCE7B4FF622DFD6F2FC7947
+:10642000F3FABE14FCE1DA08FB0B848796380FFD03
+:106430004B417F206FBE403AAFD6D82E7E2E8BE7E1
+:10644000C1225952BEA28FE76BA761BED3202E6F27
+:1064500048DF644DB014E4C6F94B15F0369FE7767B
+:10646000159CDF79EE197589E73BB480AFEB4F19C6
+:10647000812C1C77C6B875DC1FF6C5D9B36A251AFE
+:10648000C79C4FE07B86FE8A941C2E8753348DE494
+:1064900032F32894E7EAD47C4D584F718DF5A86803
+:1064A000273B785C92CDB730BC5F6582E8C75FCB95
+:1064B00094774BB95F96CB592B7B57D2BF2A805329
+:1064C000897A96FF01FB696B1AAC6782EB30C527AE
+:1064D0005306AFACC6730DCFCEE37DFC30C9B90116
+:1064E00079DEBDFB5C3F7BF8B0E15CFFC6070E1BAD
+:1064F000CEF5871F38FC55CEF54FBCEF81C3FFCCDE
+:1065000073FD529E1D5583476F06F85F0544152A9B
+:10651000C7D2CAEA08DF5E82DB9502CEE1CF01CEA8
+:10652000CE389CAFDA7388E077D406F386F16DE35A
+:1065300039A86D3765445A482E4668DC59CED6498D
+:10654000B8EFECB4778DC0713B9F7EB5280CF2E4B8
+:10655000D8F74EBB19D0DF5BD62E373E3FB9E625C4
+:1065600037C2EBD81A95EC353A17ADCB475A28E825
+:10657000EAD982C01CA4AB796BBFACD4DBE32C940A
+:106580004BFA777144A5D42B29FF963E9626888E28
+:10659000D797B7651BEA522F2F77243EA7FE6001DD
+:1065A00097438B1FDF61EFA7E1F8C1E60298C74967
+:1065B00091DF7072979BF661723E0D8F97D971DFF4
+:1065C000F9D61E078B921FB8DDC6C89FE59FAAE4C7
+:1065D000E13D46FC8F799ECFED4DA3FE16DCAD92DA
+:1065E000DFA91EC60A015C837B16F37DB0691D0B13
+:1065F0008E6993515E2DD8A2B0B0C6DBAFC1FB331C
+:1066000042B7501CC6BC4EB37E5994E4FE9C457BF9
+:106610006EA3EFE733FF6D68CF2E6835BF9FF21E84
+:1066200012F9A273C4737E5820F44E251B7D761098
+:10663000C58F32866BE7D63B27D772267D7FAD9319
+:10664000CA0FD77AA89C53A0111E96EEDEF75C3FC6
+:1066500062F3F64AD44BAF1C6C4CBB568BDBDD951A
+:106660003BAEDB7F3F91BC313FB34EC07DB4C8CB66
+:106670005C24CE3D541CED3D2FB30EE131A2E77CEE
+:10668000A59D5D67F2FB4ABBDB0C8F530727A42156
+:106690007DFC52C26534C045FDEA7049F6DD729555
+:1066A000DF9B667E2EF9688EA0EBF93B676E2A842D
+:1066B000F15B9E7E6F4007D129F75F54087855B88B
+:1066C00036B5E3FA2B98C96F18662F331D3D033D8D
+:1066D000A9A877CC742BE989BDCCBF770ABF463710
+:1066E000BDEEB99DE02BE90A4F3A58D0866351AF11
+:1066F000A5EADCF75C2D6835D63FB2750C4079B25F
+:10670000C8E46FF84849BC7F7BBE60202D76BEE6AA
+:106710009F8CF9170B586013F7CFF3FB714E5A5B40
+:106720009FBB19F97C27E7B3E5BF7AE2BF507E2D06
+:10673000F9CFBBD3517EFDC5DA9A87E32D7B646325
+:10674000BA1FE598359C8EDFFF25A2263C473CB852
+:106750005091F9FA2ECC535B41A406FFCD0F4F4761
+:10676000F9F9DF8FD83CE8876D7ECC1175003C5677
+:10677000ECE27084FADBBC7E0BC1AB79B7912F974A
+:10678000FCC7DD791AF903C2FD04FCFAA1085FB168
+:10679000D34679AD2B5E567D384C33EBA2F599BFCD
+:1067A000C779C4006FCD6D6ABD3DA3E77BB084ECB3
+:1067B000C86FCDBB383E9B77717C359BECD02621D2
+:1067C000B7CDF49F5328E2BA82EE013EE45793F925
+:1067D000B62CC2E577CB4FEE1DF136CCEFC39DBF93
+:1067E0004B5786C5E99F615628C0ED545BE33C7B5F
+:1067F0002FF7F57C24F8A45B2F083DA4ED8689E5EE
+:1068000043750F2F97D9A2E997025C96EDB0F9C2B4
+:10681000F078D913AADF8576D46B0EBA7F62E913BC
+:10682000CFBE3216E6B7F4495BCE54BE0C17CA6F22
+:1068300089AF66A4F3F2387E96FCE2593BE669E242
+:10684000F33559713C2D7D729F1DF33ECDF09CD0E8
+:10685000B6CFCEF9CD84AFB6B727A3DE6EF9C9A700
+:1068600076A487BFEC55587E49CFEF9B763C9B8E34
+:106870007206E184FA45E2AD1B8F3DF0179DFEEBF9
+:1068800051D4CE83719E73E1F1133C835041F4FEE9
+:10689000F35FC33C9A5E77F8100E4D3FBF2E1DD7B5
+:1068A000F39E7525A7FB0737E6A1DE6EB285F33CA4
+:1068B00054F2E74DDBBF43F4B8E8C5EFF0FB9C981A
+:1068C000BF00F919D65B80EB5CF0C055B4CE852CC7
+:1068D00048F4D8F420BFDFF08C95D524DA0F3C249F
+:1068E000F8E6BD871DB47978CFCEF87D217F50C5FD
+:1068F0007D58ABC85EF98E58334868AA9F71727C88
+:10690000AD2E94717F2EDF9A45ABE69DB7907C7BD0
+:10691000BFC89F8FFC0F7030FA675F9C942FE422F2
+:10692000DDEB42DF01FD4DC0E7D8BEDDE64F19616A
+:10693000F84EE4DFF2F1AF17E3C3BC53D1CFF75EFB
+:106940009E719F2BCB2385D2AFC6DA999ECE92C97A
+:10695000819D5B88BE3E7999CB9915919935F4BE9E
+:10696000DD16CDC7F7917D572A2427C00E49C4E70D
+:106970003B6D82CF8DEF619E56450FDFBDFCFC9EC7
+:10698000A4978577417B1D5FC7E9C71E7F5E12E72D
+:106990005799BFB1C864CFC9D22C27EE33C909F9C2
+:1069A0003D7B2037E1F988B87C0813FC96D9228F0B
+:1069B000FE3BF2F56B0E3A17B9EC091BDDEFF3C1A4
+:1069C000E3FB5FB916E8FF8336C9CF46F96BE6E70C
+:1069D000A6A7AE6289F8F9839C004BC8CFF03C2192
+:1069E0003FE7F0F306FFB7E4EFA224F2F740614F70
+:1069F000BBE352A8BEFFD3A5C5B43F33C157C2D530
+:106A00002C4F67A3B190DB539EC29F97990E9E12A5
+:106A10008E924E97FC6C398DD34DCF925E253D778B
+:106A2000D3AB79DD46789ADFDF827BA7DC38FE6D59
+:106A3000EB615F8EF1DAA755CACFEBD4BAD2B3605F
+:106A4000DC8D22BFA7D323EA99BCDE956BDF84F2ED
+:106A5000443EEF4AE1F90E9D81AEF44CDD7EE0ED5F
+:106A60003D6A3A9E07E88824CECBA08C0DF483249F
+:106A7000C9DB90E77E3B53B9BFAF3395FBF926A93D
+:106A8000AE0121DCDFB5F2F8D2FC7557A7E3FEBEFC
+:106A900073CFA019B5B81F38A4F29CA3B0DF5A0079
+:106AA000F06DE44B672759F89E7168BFEF593A15AE
+:106AB000FB99BFD5089785AE9D76ECE70C5B43E567
+:106AC000C2BB6C713A81FF9660BE16D2F903A6E78D
+:106AD0007B2E23BA5A62A2AB20D25582F32419FD31
+:106AE000045D95B132BEDF16F13121F726A9C366E8
+:106AF000D4623EE5417EDEE3D41E956DC2F53E2EA6
+:106B0000E265E15CA2D71540DF7ABFE987487743A9
+:106B100093EBF90F7F79ACF26668B2ECBFFE34E21A
+:106B20007E283FFCAFD72EF80DD67FF5EA803FB127
+:106B30009EED27ECFD6C2EE575EE75D0BDA69D7B18
+:106B40009F1F7033D67FEDA0FB453BD7F37D767852
+:106B5000AF9BF47F6711B7175B9EFE744407E92F64
+:106B60007E6FF0D87EFCBCEDA93D7F7B53C17CBE1F
+:106B70003DB02A948F62FFD6FCEB14DAA7773EFD76
+:106B8000A9617FFA55D7B3429CBBEA74B35A3C273C
+:106B9000DD99C9CFA936FF66CC8FF1DCE5F25DFB4C
+:106BA000EC8DF07EC2FFFE7204CAA1CEA7B8DD0153
+:106BB000F6F076E6033CF46BBDDD06F8FB086D44A9
+:106BC000E09937FBB54FC3F3243DE1C2E1D0097032
+:106BD000C075015C9A507E268347DDBF2C3C3E9EEB
+:106BE0008BE32FDB339AEE198EC345F1F3E76ECAC0
+:106BF000F780F5F3E77B3F1D8176D4B9D67B533F11
+:106C00007EEEE77FCA7AB7FDCBAE97D3BB864E99AF
+:106C10008A9E74DF93AE7F7503D57FEEF6D17CFB41
+:106C2000C8EFBBFF87D1F72BFFDFE2FB90C0B7DBDC
+:106C3000837199CEA7BF1CC0CE63DD67FE65F1DC12
+:106C4000FBBABBED1E8BCF390AE6F73A8B5C55AD2C
+:106C500024CF1F1DD85FFA1FF83E43DEC33D3D67BA
+:106C600021D911D3FDDC1FD3C2CA0FE239BBB05FFB
+:106C7000A5F80525EF001CDAAF2C8B509E98353C0B
+:106C8000E41ECC1B9BB5DCC7EF2B33EEBFA6E7D5CC
+:106C9000D4A03D77641DCC0BDA1D715B3C2DB08414
+:106CA000197E95EC3F28C9EEFBE3F8CB280F65462B
+:106CB00095711F72AD693F7175ADF1FD2CF6702EA7
+:106CC000E6FBCD6AB2517ED255E6FD477F0FADF3AC
+:106CD0006AB67223F7E79C1F9C2EEFCFF7633DE166
+:106CE000D03BDC7AC049EC37297748EB093747902D
+:106CF000EF3F1DF042D85B222F6F759FE0C9C4BEE5
+:106D0000D4218696F075F8F9BDA3BA7E092E12EE4D
+:106D1000E70B6F892733DC257C25DCCC781882E7EC
+:106D20003D2BE2F08F97C67BB599B01BA777DB8D23
+:106D30002E82E30B3BF9798917AA1AB79661FD7188
+:106D40007E1FFC9971239913D67BC4C676535CC809
+:106D5000EFD73C95F1FC19A5EA798A4F60FEA27E37
+:106D6000BF8AF98BFA7561FEA2BE8EF98BFAF6988E
+:106D7000BFA87F8FF98BFAF798BFA8AF63FEA2BEBA
+:106D80003DE62FEAEB98BFA86F8FF98BFA3AE62F12
+:106D9000EADB63FEA2FE3DE62FEADF63FEA2BE8EC3
+:106DA000F98BFAF698BFA87F8FF98BFAF798BFA8EE
+:106DB000AF63FEA2BE3DE62DEADF63DEA2FE3DE646
+:106DC00029EAEB989FA86FFFADD833867A35FB9DF3
+:106DD000A1FD04E74B86FA24CF9F0CEDBFED3D6E7D
+:106DE000783F45FBC0F05EE2FFB2D2D386E718FBE6
+:106DF0000857E23E86FF99E6FB9BA11F2B0B509C98
+:106E0000D4CE5652E9447F2F94A9AC8D4A17B0399D
+:106E100096EF0D0D3EDE1FE9757B781312D7913189
+:106E20009F0E40F9FFC2B82BB85F42C41766E03F1F
+:106E30003520E2B42FFAE33E57C64FD3632A8B8E38
+:106E4000043A8C29547A62692C9A0D74184BA13239
+:106E50002B964DCFB3639954E6C4FAD1F3DC5801B5
+:106E60009579B14154E6C74AA8F4C62EA6B2207659
+:106E7000219585B191F45DBF581995FD6397D2F3C3
+:106E8000A2D8182A07C426D0F3E25835955AEC3216
+:106E90002A4B6253A81C18BB82DA0D8ACDA47270EB
+:106EA0006C363D1F12BB86CA0B628D540E8DD553B6
+:106EB000591A5B4AE585B1C5545E14BB8EBEBB381A
+:106EC000B68ACA61B19BE9F9F0D877A91C116BA108
+:106ED000F292D83A2A7DB1DBA85D596C0B95E5B1E9
+:106EE0001FD1F391B13BA91C15BB9F9E57C4EEA3C4
+:106EF000B232F6632A47C776505915FB199563627B
+:106F00003FA1726CEC17F4DDA5B127A91C17FB0D8E
+:106F10003DFF46EC7F51F9CDD87E7AFEADD83E2AB2
+:106F2000FDB1DFD1F3EAD8212AC7C75EA2E7136219
+:106F30002F523931F6277A3E29F61A959363C7A95D
+:106F4000FC76EC6D2A6B621F503925F6172AFF2D4F
+:106F5000769ABEBB2CF6319553637FA3E7D3629F2D
+:106F600051D9BDFF1F97F477052C6771FFECCAEA72
+:106F7000D37D6577A6A5935C9CBE86CBC57BD33EAF
+:106F80003A4072728C437390F0DB668877D18F48F9
+:106F9000C0BE6FDF98F7FAA3BDB3A9FAF81BD7A15B
+:106FA0003E5BE560429F99E4EE172EE1EF64988F17
+:106FB0003847D0F50B55FB73D18EDA54DEB10CFD9A
+:106FC00026B79774D4615950C4ED098F28F38B7894
+:106FD0005CE9EF43B9FEAD5B3584FFBE404EDFD6C2
+:106FE000374BE8EDEEF6033C5C5FB8BA06D079BDEE
+:106FF0003EF6D3D776E7CAC3FA5BFFE0F0A2047986
+:1070000058F1F3837DEEA7F26BEAE75B7DE9E72DAC
+:1070100081F7878A02138A101E56FF087C3F7E7D07
+:10702000818ABFAB52BF55F120BD346E289B8C784E
+:107030002D677EF24BCE49924FB658E0B561A58DD3
+:10704000A17FB24163E41F6ED8C5F390D19F3A0D82
+:10705000E8A549D0CBF22D1F93DFA969E5229EF761
+:1070600014E1FE29F93B364B5B773C876EBD33EC70
+:1070700030E5C72F7DCCE8BF6A16FEA9E56DA6E70F
+:107080002BBF9DD0EF69F64B3514093FB28FE73D1A
+:1070900031B53FADFB0CAC1BF3498237B89DA83727
+:1070A000001E14879170907E4F090FD6F3DC05E522
+:1070B000AF9E3A3884F2E44E695A3EB60BA6F3DF2F
+:1070C000B352ACC1D1F81CE048F92C5DEBD2281FBB
+:1070D000EA6DD0031A265E7982A3F1FEB88ED78BB3
+:1070E00098B8BFD2188F706EA53CF17A9803E6A5C8
+:1070F000D43F924DE736A1BF11BBD1AFF9888DF2D5
+:1071000091C26CB59755F58C570436DA882E1A76ED
+:1071100067F2FCB4B0FF653C5720F1F2F68641936C
+:1071200031AFA961734919B9EB76DBC83E94715947
+:1071300089AF9EF9DB3C5FA099453661EA12E0EB2E
+:1071400044427CB5EE23BC02DE4E24C1DB89DEF076
+:10715000765F91F027FA64BEDAB08CABF1E59A6CF9
+:10716000E2E7BAF5D1212B75F469F6FFB3F963E9CB
+:10717000DE1399FF5C53287F67CC9787F83DBDB538
+:1071800082F066C657CDDF1B092FEC7537DD3B3C1F
+:1071900067109B77393C9F27FC9E735AA690FDFD94
+:1071A0005411DF17BCB016733F197B71AD93F9C151
+:1071B000F87E69AD87EA7F5CEBA5FAAB6B352A5F99
+:1071C0005B5B4AE5093BCF2B92FC058440F97DBB14
+:1071D000055FED2E92F19FEBBDE8E7AEF9FB4B1595
+:1071E00016127DC7A64F2A22BBDD902F527BA531F8
+:1071F0001FA4C326F2CDB6283EBC4FA62170A9A17C
+:107200003D2B1D19AFA3FE11F92B0D9B33E91EBBBE
+:107210006BA6661BDACFDADCCF506F2FD2F87D6A0F
+:1072200035830CCFAFADBBD850AF17BF1FC1B42A49
+:10723000E21B19FF02CDCDF1E2E16D3F59393AFF72
+:107240004618FF93C3367A6FC6C7097B98F6F3E1F9
+:10725000871D3E8CEF9DC4F36F503FF94795F28B2D
+:107260004EDA58D80322FEA4C23660C9AC9CAFCE19
+:107270001CE57C55F37795E13E9EFDD441F1C1C6F6
+:107280006D0A0BE3DD0C5D007918F7FA9F3868DDB5
+:10729000F3B7A92C48E7ABB4368C935FFFC8501FF7
+:1072A000C647E70C8A16E179C3AE5FA6F8F0DC5753
+:1072B0006307FFFE24ECCF33313F4A29A778C45F30
+:1072C000A7B52EB460BE9D7A3817F9F5AF4FF1DF40
+:1072D000355BBCEA8F951E80F392E7DA5EA9827176
+:1072E0004EB4AA34EE078F3976A8C4F7FE7CBCDF13
+:1072F00036BEEE08F929A614063E43F9FEFEC2C8C2
+:1073000008923F6BB87FBC277C60BD886FA4579DF7
+:107310003C8BEB371E7F0321548072A2D1E6A3B8C9
+:10732000EC89AD368A17823EA07C8313ADD9162E28
+:10733000879E22BA6BB06A76FDB80D5B553FFF7D24
+:107340000CCD8EF36577AA41361AEB3C3F22BC592F
+:1073500009F2F88F11BFD7AD1A4DE7A2CD795CB213
+:10736000FC08782AA88B2B2D799AC77FD9A80EAB59
+:107370003ECF5DFA6758B0CA709FD1B281F7FE6008
+:107380001C94A7FCFCEAC5333BDD24273FB43C53E7
+:107390007923941F4C0BBF6B05BCBCA806870CC09F
+:1073A000BC21CBD6ED0AC5558EFF00E3FEEF3F6151
+:1073B000F3111B8ABCB1253F5D4CF1A9E4F602F341
+:1073C000F2F875344FF1E2EDC48CF24566B336E164
+:1073D0005F88F03C039C04C0C7B38CC7C58E57B808
+:1073E0006FC5F3C38DA6F3C6C7C5398BAA01DC6E82
+:1073F00092FAFAC6015C0E345A387FB2BDFC1E4ABE
+:10740000F97B71528E4B792BE575CD009EC722E535
+:107410002C636D245F168AFB92973DE6E0E78B3480
+:10742000E641382EE668621B0770BE5E627FE21E90
+:1074300024EB45AC9DF4DEFBB6C8C2F612FC7EC759
+:10744000862CFADEE68B201F47E4EFD159498E2CBB
+:10745000627C9ECB5B954854E7EF90BF4FC2504F84
+:10746000E8E44E0FBD60D2070B84FE5BC04CF946CA
+:10747000AD463D154873D3BA96B48A3CECEE79A973
+:10748000EC2CC6BB8291E7A6D3BC155F24C13C1689
+:10749000B1AE28DE8BBCFC717E8EC93C2FF33AFA6C
+:1074A0003ACF85BE9913F17EE5EE714DF396F06605
+:1074B00078B04A870709F785610ECF857B14C2D75C
+:1074C0009F85BD25CF079AF1BF8805A6A39C5B7455
+:1074D00017EC334BE2F420E960F193113A0FF80115
+:1074E0006B4D77013F2CDBF6E4AC31F0FDA2075E7B
+:1074F000B423BDD7654587583261FF199E70474D4B
+:107500005102BD6FD2F35F179C98F05BD177009763
+:10751000053B55CAA3D0B513790461E287A630FFB5
+:107520003DC1A697555F0B3C6DC29F392A3FFFF9BD
+:107530004AB8FDB3E76DB66B760DE8DDAE31CB9B97
+:107540001E768D499FE2790ED49F5DB93C3FFD13B5
+:10755000AB3F238BE4B4490EE796D37DAC520E2F9C
+:10756000147A508EB300F51FD4DFDDF68B74F46708
+:10757000FCF9AE5FE451BE06EA9B61717D73432363
+:107580001FEF865FA550BED45FA7B58F407BB0EEDE
+:10759000C1E7D3F5F7BD7E5010FC03CA5BA91F9766
+:1075A000AB3B06E0EF1A4A397BCE7D5BB275BACFB2
+:1075B000B14EB7719D0DB84EDD399546B1CE7736D7
+:1075C000F3F51DDFCAD73BBFC73AC31457B9E1C7AC
+:1075D0000E5F98EC8E28E9F5934FAA0CF759DD76EB
+:1075E00087C90E38C35AB7233C96AF7EF54D2BD0D2
+:1075F000C5E20B003E400775773A48EF2FFE258F16
+:10760000A7BEAF54E75340FF4034FDBBF07C09D820
+:107610000B686FC4E7D16D077C3E406F07F4117EA5
+:107620002B845F6BC59EE7E977B4143FCFC75C211D
+:10763000EFB5D96DBAD7464319C0CFF93B114FFD0D
+:10764000CDF77171FFEC7F0FF978EE6AA2FFAE0BF8
+:10765000F4E7D89A53A336CC43EE7A52213B69F92A
+:10766000F5D5E9D50CCFB771BF5A7E31D76F8ADF18
+:107670004FF9350EC06B2A8C5758ACF1FBAF340F65
+:10768000CF377F80D13D3A72BEE6E7E86F77A23E02
+:107690007459481F9AD73FA598EBCDE5AA85ECEB26
+:1076A00065766E67778AFB2B868A790C2DE6796082
+:1076B000C38BB99FA113ED4A8C777FC341BF63C4CD
+:1076C000D844F2BB5B19A73FAB849BC7FA51377F05
+:1076D00093FDDCD51FE13497B5D3EF224EAF9AA9C5
+:1076E000E1798637F39C744F14FC09603FB3453F42
+:1076F000476CFCFCC29B3806AC6BB6F04FBF89D719
+:10770000A3C2F86F16D8C9AE0D3FED20BBE1965469
+:10771000EE3F64391956E4876B859C9A33CEE14776
+:10772000B93E7BDC2D012CA1BF300378D539BB36A7
+:1077300096C138EB2C5CDFAFCB62DC2FB0A1A3028B
+:10774000E1770998C998BF0FABDF7536BB373A327E
+:107750009E9F58867E86B18C135815C1D7505F66A0
+:10776000E7EFE73DF41F33EEEACFD81F306B0AF5A1
+:107770000CC208E9A23E83F6BF33F07C4116965650
+:10778000A2B7CBAD2C6CE1E56617DDABE435FC2E82
+:10779000EC55552C9A01EB8B1E329EEFB83A6A8954
+:1077A0000EC5789135BA0FE167716A360F8C13A850
+:1077B00051CA11EECBD6F76DBEAB1F7A6AC65DE338
+:1077C000A08EF779E13CBFAB50BED06C607AA4D3F9
+:1077D000B95676402DE7F8433A6CCED2C2D46E1536
+:1077E000A77379AE44E2A50CBAD7C377B6981FF455
+:1077F000B3391DBFB727F6AB7CBF58C6E3B8BDB6DB
+:1078000054F0ED5249778F1BF935827C83FC84F666
+:1078100021C06DB62893D1FD83822F1E2CE6FBCCB0
+:107820002DC5729FD9B7F1963B5894D6FDB483F01D
+:1078300028C79D21CAFB8BB9DD29E721E977215BA8
+:1078400049F93C0B859FC6029284F2835B7FCCFD95
+:1078500042A6BC23309428BF6DC94EF3739D9F4749
+:1078600035C825F29B2AF6AEF9383FE59B293EA4A0
+:10787000F7D9F636F20F98DBD9F0F75331EEB61997
+:10788000EC2A45C4CBA0EED8AAD0EF5ECCEEDF3513
+:107890001CF53948EBC9742E54D8DB0B057E1DE26C
+:1078A0007EAB85685F615C0DED2B84D7366E575AD1
+:1078B000853DDCB0D5686FCCDEA0B33B7961B81FE5
+:1078C000C061CA53B709BBE32D7BD77094FBE6FBBD
+:1078D00002DEB2F07584F318BF573387BFB70AFBD7
+:1078E00052D2D513C53643DC4D9E3BAD4379C5EF2F
+:1078F0006D30E569B9E8FE983A85DFDF29FD906FC4
+:1079000088F214D8A1745FCEB1348A839BFD939D15
+:10791000D5EEB045E7A79C9371C374844F5DBADD83
+:107920008AE51BDDF78A75D0F8C73C03C9FED95438
+:107930003D721BE627FDF9A153339C45144D11E719
+:10794000A73E7D01F3E9AFFC02D643F5D80C3F8E8C
+:10795000F36CD75C2788EEBF157F36C30A7ABEF377
+:10796000EEAEED58776B9600D56FEF1A80772EBB91
+:1079700023765E5F27FBB307304FB9F33E5E7FFF90
+:10798000217B00F39FEAC4B9A5BAB10AC9DF54C18B
+:107990005FD2CF5467798697E3F9EFA29CAB5D9EE7
+:1079A00016482DCEC5FB504FD0EF2F940CF4A716E0
+:1079B00043BBF401C133582E99A984ED78DEFFE56D
+:1079C000C80542AF25FC9D9054A1A70A4A02F4BD08
+:1079D000F4A3433F7FC7FECFD5CFFF016BCEE90AAB
+:1079E00000800000000000001F8B08000000000065
+:1079F000000BD57D0D5C5455DAF8B973E70B6606BC
+:107A0000464003F9700604B140470545A51A011127
+:107A10003FD041CD2CAD4634454341ABCDDDDC7785
+:107A20000651336B0BABB7DCB2763273ADD75A323B
+:107A3000412C3F06B5D26C6B4C6AA9D4C532BFB29B
+:107A400022D35DFAAFBBFECFF39C739939D7416D5A
+:107A500077DFFDFD5EFCF93B3CF79C7BEE739EEF10
+:107A6000E739E75E2E5DA23F371312D94B43482E0C
+:107A700021BFB7B9227B752764FAC2F46877162153
+:107A800051296E838DC2F3CA24AFBE3F21A4C5978E
+:107A9000E1B210329E1067BD99904BFCFE4BAA7963
+:107AA000EEB35F368FF59F99E74FAA79EE94E8BD64
+:107AB00043E97FE2B0C1FD77A439B360DE7BFE8B82
+:107AC000B8611E52345C43061372AF91E0CF8FD57C
+:107AD0005B338C39B4DD648825763AEEF56D29B3D5
+:107AE000E93C6431BD2981906F9A3FD3DBE83C0BC0
+:107AF0003A64E28C25A4AA43C276C196667D311D04
+:107B00005745DBC210FC2A39BE84B469275A82D794
+:107B100007D828BEDDE1FA6A6CEF79FDB4D64DC70F
+:107B2000DDA3A93FF16C1CBD3C4C72BC6CBB7C9DC1
+:107B300009FCBEA38494D4675DDE3FC426617F5DEB
+:107B4000BA7330AC339ECE01B0AC61EB558FF7F217
+:107B5000F9A64792BB5CB47FE6608BD146E99DDB1A
+:107B6000E2AEB5503C66AFB50F94E91C03520A9CD7
+:107B7000301F99354CA057494F4202B03E6D7B0FE4
+:107B800042DB1FB7E746138AD7F498C07D64002113
+:107B90000FFA32EA8CC9848C7D868EE989B7380960
+:107BA000BDB7C4C061EF8DAEA27C0AFF4346F84E5C
+:107BB000DB903A2F9D671FE043E7B963487624E9DD
+:107BC00047A9673769ACD1F4E6E4190F021E770CB8
+:107BD000B9B118AE8F30583266207D09CA8733D9C3
+:107BE00035C596CBC613BA0EB7DEDFFD56BA0EF713
+:107BF000FBB2C34BD7E1EE6772FBC2D06D32A7C3B5
+:107C000083362BCAD13E0DC57360100FE5F9845839
+:107C1000EF0BD0F98E2F4D18B08ACEF7BBE411BF11
+:107C200082E729CFFF5DB27B4EE8F32946FDE0FAFB
+:107C3000B5E2318BE3F12BE01B9DC7954FE58CD36B
+:107C4000FA12FD3FB1C824C093C7C5126766109EE3
+:107C500032395180A74E4F13C6DF3EEB06A1BFD489
+:107C600010C8A93607E55B8D8FD25246215E559626
+:107C70008D5184A27864FB854FA7513DF97EBDEC00
+:107C80009028AE7377BCFCE9703AEA1C5D702CA5B5
+:107C9000DB392705E87ACF6D917D5E3BC887535B62
+:107CA000DA83900A988A8E9FBFFF4DFD08FA6B45D4
+:107CB000F59C71C0C7B93EDD976D21785E2017F540
+:107CC0002495EAC346F17A1579F407B91F407EBDC1
+:107CD0002B9BCE53AFEAAF1E759244C138ED976D22
+:107CE000CA3AE9F3171FB63FB63764DDCFD92C7116
+:107CF000276EA0BF0C24032FC9F0BCB3EFD215929E
+:107D0000C2A666E453ED7ED901225A9B2C1189AE9E
+:107D100073D416832F82AAD6B7DB8EE96D945E7F6B
+:107D2000F5D81EDBAB03FDAF212416EE3BA66FA3F7
+:107D3000D787DB6C48A705DB7FD013CAF751DB1769
+:107D4000A25E17533B164DE527D04CB2B7D0F9BD14
+:107D5000768BE3653AFF3D2B4713328890E88E69B6
+:107D6000D856D68DC6F9E6774C4278418709E17D31
+:107D700091816242F1D8D7D88DD4523C3E92FD1900
+:107D8000CFC13C060BDA89D2C43B96C2BAF7457A1A
+:107D9000B3EEA5CF2BFDC3A812A0EB822D9213E466
+:107DA000AC5426FBA418C03702E72B953FCE5948A8
+:107DB000AF8F2DB47835D1D84F08ED97075B5611AA
+:107DC0000ACB7A6A2FC2C8E77BDCBEE8DA18DE236A
+:107DD0003BCA703EA5FF8FB654945B05D6755FAF66
+:107DE0002D3707D7A36B93B01DD37103B6555BCA6C
+:107DF000B436FA9CF7335F8A033AD1F1667758BB01
+:107E00003C249A84B15F4A6BE0F6781AD8633AEF63
+:107E1000DE54E757A087E397B4698D604FCD46EBFA
+:107E2000CB540EC6E70DB0CD0E5997BCFB3662A3FE
+:107E30007264886BD739E9FCD3681B6ABFEFEAC26A
+:107E4000DF9CEEB4DF35B85EC52F91CC2584503968
+:107E5000BFD3CAF056F4EA533E5EB93F2031FDF07D
+:107E600036187C2FD3DF8FA4BAFF06F8064690A9F8
+:107E70009BD19E0652CA2CFF3EFC297F8DC0FF2855
+:107E80006D1B89017F6657F0677A7D35FCBFB33182
+:107E9000FFFA914C16835C7C74F3CD0127C5ABF9D6
+:107EA000C14183C03F28CFEB66D7E338626DBF087E
+:107EB000F25AB5D3645B45D7574A790370FB0E83FA
+:107EC0006F9D1DAF13290E5AC33A89F65745B56702
+:107ED00080FF29DC15E107B96DDE15A1053FF24EE3
+:107EE000BABB9BBD3B5CEF532451F9766E376841BA
+:107EF0000E7AD89C3170BD2B7CAF66C7147D54CBF5
+:107F0000997B25D33F37D7C3195C6ECBB91ECED032
+:107F10003AA21FA078DFF5814CC08E972F91B2B79F
+:107F2000E4804DB338D243F450D1371DC8E52090DA
+:107F30004F2697951DDDB87EDBF9BC4C0F4AA9830F
+:107F400006FA94DED0CD07FABDA02316C729FAAAF7
+:107F5000E869629A7B04ACBBB496EA377D8E7B6994
+:107F6000420EE84B504EF45690272A27F1B343E4D3
+:107F7000A0B6F9272DC8892E5F423931D0B63044DA
+:107F80008E5C9D718AB5B807C563FC32BB66150966
+:107F9000F617DB19FFAF55DE0771F92A37FBD3352A
+:107FA000743E5D75846329C5EB5C9C0DEDD8A2879A
+:107FB000294049B048E72A843863D16F2507D85F44
+:107FC000883FC0FE0C6EADD6BB43F0BBADA31FB166
+:107FD000513A4DEAE88DED8014F7647B2EF0670A84
+:107FE000A7633F6C892D4F03F8DC67647EE67CF560
+:107FF0004377C2F3CEFB0C0E781E21798CDF1CDF99
+:108000005CA7E3BA0700BF0F74E4453AFE54845BF3
+:1080100006BD3C954CAC4F521467AEA17CA6F39EB6
+:10802000D211AF95F2731685DD007723CE6E034132
+:10803000EFE83A43FCCA056D5D0A49A3FC5DF4A76D
+:10804000A35A6A0AE76604FAF9E973A78F60FEFF8C
+:10805000EC7A1DFAFFCAE68F076B68FF19BBF33A8B
+:10806000426DEFE89EEE05C0D779137DAFEB287C1B
+:10807000CF6FDE8C1A6A0BD2B35EEB4FD7D2FBEB1D
+:10808000291DBD14AFFA47E5121F8B7B4C65D957EC
+:1080900097EB791D69481FC5DF28F67BAB279E2E1D
+:1080A0002268C7AFE68714F99ECFF5603EE8010964
+:1080B000F53765AE1120879992239D84FA1BA60F90
+:1080C0008A9DA6F28E7A539A96ECA82541BBADF60E
+:1080D000477BE4FA2787D1F52E4D75FB80DF05FF3E
+:1080E000F3B7373FA75D959B5F29023E8DB84122CC
+:1080F000B2742D76F2271DDAC9256504ED246D438F
+:10810000EDA4AE8B38FD65FBCFB3F34FF2F134BE77
+:10811000C5B811EC78E87C47520BB6C23AB6DB25FD
+:1081200036DFBF096FB57DDFDEA9AFD766DF5FE55C
+:10813000785FCDBE7FC4EDBBDA9E133A1FD8F3EF54
+:1081400077F4F581BD3F4AA8FD07FFB6DD647B9952
+:10815000DB7BF40791D1BE2BD9FBBAF4991F756173
+:10816000EF0340B77FD5DE2BF2A5D607B51EA8E5F5
+:108170007EEC2334FE023E6D9508D8D760BC455096
+:108180008EF7A5323956F42624FE423F4FF5C197AB
+:108190006EBF5C2F7FACFE538E0DF2CD1CCB002248
+:1081A00005E55DD11745DED57E644EAA5B4ACD0D4F
+:1081B000EA49E566B51FE84A9EB6E9207FD555FE37
+:1081C000C0FC006D43FD4057F18E3EF5E7E9C179F3
+:1081D000FBB5C50B09A97A9CF77F519E12804E61B1
+:1081E000E4A967EABF204F57E023FA1945CEC61E1F
+:1081F00060F241D258BC4FE505F1DEA74FF6D5DA63
+:10820000C1EE317B38F612A9067ADEC5EB098ABCCD
+:1082100016A5B96F0AE533C4F710B75F6B5C382D4C
+:10822000AE9A38E9F5BB681B6A370CC0BF30F17DE8
+:1082300061EACFF3F30352AF8DCF93399FFF8D7176
+:10824000E15DA961EC047132FF1FE48B6112C8CDBE
+:108250008F7E2D01FDEA8AAFBA358CEE0ABCDCAF09
+:1082600055FC6B2CF8572A2FEED47F21DE2C2DAC39
+:108270003F6FA4A1DF7FAD1B5EA61D4AF3F43CC295
+:10828000EB1FF9AB9D5AB02FF4F7613823D6473E68
+:108290009239ECBDF16011C563EC939DFD5EE81F62
+:1082A000991FDD594F81544219FFEB75C30E3E8A69
+:1082B00078D7313EBADBB4AEEC103887C2961038AE
+:1082C0004F05AF65E3C18F58711E1FB3F7747E6908
+:1082D00020C0CA7C5C0F487B71378817B74856A806
+:1082E00087DC9EFFBD1EF8535AD8F66E225DEFEA7A
+:1082F000754565E6BEF43AD8418AEF8BEBC6ADF61C
+:108300006AF9FD3DB03E863F867AC929533E55E65F
+:1083100049BE54FBE5747C3155F467F0A315EF2793
+:10832000FA9C9F773FE82FDE9F8AF7FB0D3FE3F92A
+:10833000B7E613A72F8C9DFC8362272F5258999F75
+:10834000D26E523DCBC3D5E3B7F2F1018D663EA1AB
+:10835000F4DAB5CEBD1AEA652309938FE6757795F1
+:1083600079991C12A76ABD57C2F7E55431BF831F24
+:108370009B78BFFF4AF4FA9FCBE8C5E5A3429497E8
+:1083800068AD6BEF8F148FE838C90A71ED0257C4DE
+:10839000A310BF97162AF23DAFCC9944D71741845A
+:1083A000FA5F50BEEF292BA274594094F1F3578322
+:1083B0005F72693AC73379DF2E75DE9F49E5074B57
+:1083C00071F4FE2FD655AEF666213FB01F61ED1554
+:1083D000E4BD5E05E7ABF483CB37EA27D86D4A9F4F
+:1083E000F43076A383D3E75B894C05BB172860F193
+:1083F0005E2095B5F1692CBE23696C9C318DF339F3
+:1084000032840E49413ED31F3FE41121EB463ADD51
+:1084100016A7ACFBD1B271745D8118922D513989C8
+:10842000495BB97A59889CC4A53D8A72129C6FD564
+:1084300041A0E36D9C4EF1698F1CE4722481DECD76
+:108440004781A072B045F2CA749DF3410EC2ACF3ED
+:10845000CBCBE5C8ABBADFA9BBC2FDA72EBFDFA956
+:10846000BA9FE8E27ECEFD9C4FE3547C2C51F1B1E3
+:1084700048054F57609F60CF143B57DEB47A798F21
+:1084800038A8374AE026C05EEBA5018464BFF4DF5C
+:1084900065E60490579B2E91DAFC012F3D73D0487E
+:1084A000ED5919D83394DF35AB9DBDA97E83BE232A
+:1084B000FCDB32677F909FEAE5F174FC90979E5D4C
+:1084C0006DA4436F5FB65A0731CDF097D6AED6D2C2
+:1084D000796FCBF9C3BB309FB6E68583E3A42BC885
+:1084E0006B9D6A1D6B55B05735FEA9ABD8F765AAD1
+:1084F000FB97A8FA1F55C16B54F04AF1FE19B3243B
+:10850000D49319947F40B8ABE94D595A679ED1E98D
+:10851000CF2433C64982DC8FAD65F0B4973695AD74
+:108520003487C069AF9781BE2B72AC23EC675A1CAD
+:10853000F182FFD07561CF46A7752147996A7FC741
+:10854000FAFF0CBF26E03E8BE097F7C822DC2C2B0D
+:10855000786F3F785F165C54E0B7CBA07ED1E5BE64
+:1085600007D95606FB1E631FE7B0B7A90CE23465B6
+:108570009DCAF8E2BF5F92E1790BD39ACAD6C3BE17
+:108580004A813F1DEAF5D363584BFD8C0C7EAC8AC3
+:10859000D73B8A77C82EF033D323FDE98BB242D67E
+:1085A00049EA33609DCD0FCAC81F6F2DCB47CA89DA
+:1085B000430FF58AE6E8E8C51BE8F83D0FCA8BC112
+:1085C000AF1D5D1CDB03F289DD692CDFDB13DDAB46
+:1085D000C7DD146E36DDA5877A6DF34323B1DD2D3B
+:1085E0003B57B453397EFCA5F7D0CF379BA2913EC1
+:1085F0008FA4ED29ABA17AF1589A0DEF77C7587B7C
+:108600003441BCBA4A47A05E4D88E305949BDF180D
+:1086100006ACA278CCA8B901F78FCAFFBBAC3881F1
+:108620008E2B5FAEC37D05FAD30FF076AF1AA98704
+:10863000FE59CB78EB1D85EDAE7FBC79A01F1DDF09
+:10864000FEB0EC584707EFEC488D2AA7787D15C19E
+:10865000ECF097677B47019E7D7ABB9F4DA37C9D85
+:1086600011658994C079586D5113E9BCBDD39DCF74
+:10867000A5E506C7EFFA878CFB606F9F2DEF01FC25
+:108680007B99DBEF9D1DE53DCA43FCFDEC6FB548D2
+:10869000E75D7ADB7D105FEE8A4C96BCA8C7F5B12A
+:1086A00050B79DC5E36B2A2F8BDF0CE3F79F4893F0
+:1086B00071DEE386C5E42B2AC4CD8F74CF073C95C9
+:1086C000FB94FD375D926D60681CBDAE57C11BB059
+:1086D0008EA09C1D3D087283713485B7BFF4F96A82
+:1086E0002FF8C23D34FE073CE29CC5E007C8925813
+:1086F000B60F1A5F9F115A8F08C6A94BB93D60E3A8
+:108700008E782D98B71ED914E1837CE688F70B4B41
+:1087100068FD5DD1933951162F38E393168B16E817
+:108720007A54EB39F14BD8377C5E877674F6F3DDFB
+:1087300097B4833DA0FC847A90FAB93D7AEB709EA1
+:10874000AEF707BF11F5847C53E63477AD279FBEA3
+:1087500074A66CBDB96B3D99C3E3F6E2E7752E9044
+:10876000F339B9162DECD3153CFFCECB208F731601
+:10877000460C3450C4E73C6F40FEB6592C5E2BECDF
+:10878000234659B4DD68FB0D9787B69A08CC53E4AD
+:108790001E7AB47BF28A5C1BD0A750265A23F52B95
+:1087A0007294C3E662F032A81B2EB7E4D980BFB141
+:1087B000BD993E74F6474F1D23F50BEE9B9D5EFC65
+:1087C000E4D343287E67886FCA10FBBFBE8F56452F
+:1087D0005CD1507FFCDFDA47D3F6B6C49DA0A97800
+:1087E000701F2D2BFA5610BFC532E22D2F8DF001D0
+:1087F0003DE514E627461109F7D18895AE3F3BB811
+:108800008F26FF6A10D2E7B887CA551F4A972823D8
+:108810008E977F25FB0CF4B985B1ACDE2A3F5D460F
+:10882000605F8DD2D56BA5F0A8B86ADC5FF3829D3E
+:1088300001FD9688AB1EF5DF910279F2ECE72390FB
+:108840008F735E98FBE96F73806FA571A1FAD48B6B
+:10885000CB1F9D8F186382F39CACF9750AE053F827
+:108860003B9A5F42DE29BB9FBE0DEDA609F7DB8870
+:10887000B5ED3743405E6A4C03A04E3EE7F9849461
+:10888000D4ACE0FD73963E98C1EEA7796B14D8ADD9
+:10889000085C4FE51603CACB8C876527FAC9643D8F
+:1088A000FAC92F9745205C999487FA3643C3F6DFBF
+:1088B000684C188FF69D919C549A89F34D33D8FBE0
+:1088C000470332E38F97F34D0FFC19D63B169F7F7A
+:1088D00017D098FAAFDB7B73BA68981C919D12EEA3
+:1088E0003711526D033B305D23A1BD53EBE5D8DE5C
+:1088F0006C9F6F468AE34EB86FFE6306C7523BC358
+:108900004156F0A179D37C4D6036EC43924603D6B4
+:1089100037AAE83A22A2D8B987CD14FF2A2DD1EA86
+:10892000A13E6563764DC1A7CA56360AE495F6B7EF
+:108930006A69FF7C0BB3CBF3BBB1BA0FB1187D2FC3
+:10894000873E0F704E63F7D9A240DF86A2BC80FE3F
+:108950006B68FFF784F51746E5D9DAB270FF7E251C
+:10896000D44B009FBEFD429E4BE1847E208F0BB511
+:10897000A916E043EC94A9F0BCD764B44F54A91EE7
+:10898000CB8338F0357910E4B3331EDE53BC06E0F8
+:10899000370658018519AF1F423F750F97B33688C8
+:1089A000FFC16F51F80DDADEDB9BD907B7CCEA398E
+:1089B000F7F69684FD50A57FFEC33AE4C7FCE54C6C
+:1089C0001EE6D7FC09E79D6F09F4007ECC6FD00D41
+:1089D00006B95EC2ED45794D727E2B958F725DB4FE
+:1089E00055A2972ABDA57A802BEB248495E7CD7FED
+:1089F000F8931E9A2C361FB4062E47C179BBA78068
+:108A00005FFB66536CCA8C10BE7FB36C6B14EC6B4F
+:108A10007F15E14FB7423D666184631DEA29E3C7D4
+:108A200037CBD2D741BD6696356081FDF059F7A5A9
+:108A3000C580BF3B6AF5EBA1FF68BD5D03B0D36A9B
+:108A4000CD07D8A9ED8FF037FC9C0AFE503E2D9043
+:108A500098DC546EDAA34FA5CF7B91D3E7DBD70E1A
+:108A60006540DD607E4A2003FC3095AB8C44E0CB52
+:108A7000AB12C60B0B36C9CE887E41B95A0072457F
+:108A8000F57F1E97AB055BB63E007ABA00E469E05D
+:108A9000E57249F3CBBD787DF38BC584DDBF17E468
+:108AA0004EF1FB145EA683FA9A9EC3F43900AFE33D
+:108AB000F4A7FD45ACDF9B85FE84B4E9212EAE9280
+:108AC00059BC40F5291EE289AA269DB72DC43E2E29
+:108AD00080FEAC607F5772B3A737DF2FAB31A05F4A
+:108AE000DAC3F5AFEDE18628908B6F5FDBF3EE30F4
+:108AF000C8B3364B56B0FB97E921A75B15D0290ABE
+:108B0000D789F15115D0252A48A74E7DE3725145EA
+:108B1000181D14BA5469399D947E7EFF5E4E874AB3
+:108B2000C2E9BAA50FD377AEDF5462D08F28EB73BA
+:108B3000C788E7072EF0F57DCCDB4A2A378E2C94C8
+:108B40002FA77E30CFFF69D7B76FBC88F523859FED
+:108B50000ADE96749B62A79DDD62827C6ED3908A4A
+:108B600070F5EA539C7E3A33B32BC76A12EF5C4C24
+:108B7000E9376F93EC40E241EE15F25C83A6CD82BB
+:108B8000F1E9AF642BACABF07FCAC6C0BA15B9D35C
+:108B90006D94B44DB04F48BA21FD15FC0AAF738DEA
+:108BA000E9C6E4CE0FF828781E93FCC82FEF1B927D
+:108BB00095C5BB6D7AA8232A7AAAC6F702C7578E35
+:108BC000928649FD011F870DF49B503F88F8985B02
+:108BD0001FC4E7798F3C68EF177CCE51AF450BE39C
+:108BE0008E12660714B93CC6EB12C7966FC578584B
+:108BF000798E29FDB2E7B817C75DFE1C65BC9CCE17
+:108C0000F453D18B7D314CFE0B97FD09C7297616A5
+:108C10007EA01EA7D053A15B885E0AF451F44BD10D
+:108C20002785AFFFAC5E9125DD316E7D88AF1B756A
+:108C3000A447D02F807C82BF33E8D939B810BF89D0
+:108C400071CDA8A41FF4EE30D7153AA9AF07F32AC7
+:108C50006B0AD07F94391EF7CBC9B2F8BDBD43E291
+:108C6000B3AFA0EE05F6F415D987F69450AD0CF12C
+:108C7000E74ADC56B370947504C8D72609CF1D297E
+:108C8000FE9BFE3CDA29A774BE8A9C8519104FAC66
+:108C90004C4F65FE2CCE791AEEAF3C15288EB205EE
+:108CA000F3971BCFFBE568A80F6EB10BF943E5D92D
+:108CB000BDA8E7F3496005E4BB331E3E543A04F80F
+:108CC000FF8A0ECF2FCCAAB3A3FF3BBD7EE6204880
+:108CD0006D672C4F4778EECB7733F86116D7CD58B8
+:108CE0009EBB01EAF35F45388B41CEDB574B56C83C
+:108CF000BF86BF9CBBE476DA3FDCD2AB1BE07B6473
+:108D0000FD57A5C3208F582CA3DE38D73F3905FA6D
+:108D10009D4DB20396388B5897DC0E72AE8D46BDD2
+:108D200053CE35D6EA98BCCD4C67FE725A3AB31B87
+:108D3000D3B8FC16D6D666C0B982F617A99F82FDB5
+:108D400075BDADDE0F79E08EEB1CEBE873AA68DA37
+:108D50001A4FE5E994C4E2F10A3D31827CEDD70572
+:108D6000EE07FCF7DF6F19500308C8170797B3BC6D
+:108D70001DED0CCDA3F0B90ABD94E797F3E72AF3F4
+:108D800028F7ED83B80AFC08C7F7F4B257A640BC31
+:108D9000707A637A0C09A1FB695817A5F75C6A1F02
+:108DA0003787C907ABD2957AAB0FDB0A5E47DCAFDA
+:108DB000AB4B82FD5C1AD71F0F8DCF4FBE186104DD
+:108DC000B9A471BD785DC7FC0A8DE785EB547F04BB
+:108DD000B833DF93A747BBC3D823A555C7FB4BD3F5
+:108DE000CDAA73732CDE57F44F7DBF12DF77D65DAB
+:108DF0007AFFBC735D673D9431542186417046EF24
+:108E00002F32FDFD4D387F39BBCE603550FA1E073D
+:108E1000FD827DC10699C58B46A66FC7770CF041D0
+:108E20005D61F661E2F05378768BECB0D1F17B575F
+:108E30003F84E73BEE5E2B91EBA490BCEBA9D553AE
+:108E400040DDCE39DC2B12E8F8731BD97914DA6DCA
+:108E500056E55BEF26D8BACEB7FE5D7996527F52C3
+:108E6000D37F733ACFB71CC421D29FE5EDBBA818BE
+:108E7000E50DBC9CFE673D6ECCABBEF354603BB4CD
+:108E8000FEC5C244BA8EEFA5638F0D073DB24463A1
+:108E9000FDE4ACA71A3707BF6B1A74713CA5D3DB8E
+:108EA000E6682BD88FEF3C8BF17AA7DC7039BD7167
+:108EB0004BB39C4870FCF6E174FC4E73346C7784C1
+:108EC000D987637C569FBFB977E190EBE0BAB2DEF9
+:108ED00033BF64FC56F03FB3716614C4ABCDCFC54D
+:108EE0006E1F0A7C36455B4114E6F0733827D63096
+:108EF0007B74CA18BD611CA5DBA9B5937A407E7846
+:108F0000B7AE5DEFA0F33A769445417DE46B6D5BBF
+:108F100094155A3ADE0F78687D32D8C1612504F77E
+:108F20000787F9B5C466C7AD7B949FA167B53EC8F6
+:108F30009BBF817D43F0E31723D9FE3DDF0FBC7B50
+:108F40001BABB375D655787D61385F6F74468CB2B4
+:108F50000F84D70BF3D8F5936BDF1C0FF39D5EAF37
+:108F6000B302BEDFADD7E1FCF3687EAFA1F2786A51
+:108F7000233B2F306F3BCD93ED60472494DF795432
+:108F80007E8D207F0B754E7DF4E57259B891E5D743
+:108F9000F3EA25CCB715F99CE7F41523DDB99C1A43
+:108FA000E9BF4BD4757423F52B801E5DC9EB3F5B85
+:108FB0000FD06784AF07A8E541A19B22174139254F
+:108FC000289F0AFF63EA078C48C41BBC484F6F0107
+:108FD000C98478A1564F32E13C945713E900BDFF94
+:108FE0006B44543FA8432D36B2F681C8A875D0FE15
+:108FF0003522C50778FF55637D07F2AC5F67D871EE
+:109000009E07649B4EA2BF4E8A6B2B423750A871BD
+:109010006AC00FD61AD08EA8ED505A06F33FDB3344
+:1090200008CAFDCD19EC9CB88E54637CA1B4341EE3
+:109030004886F8A5CC1473018E923B36F49804FB55
+:10904000BD65C363EE4FA39167DE86A4495A2AE744
+:109050006583621A52293C2C2391F5F78FC9D551AB
+:10906000B8A626795211856FCD70F6CB08798E326D
+:109070002FBD3E2083E23132C19D03FD557AF34A74
+:10908000F003DF4BED0B347270FC41891C7D5B0AF1
+:10909000C26D3A9202F1F6CD807FF7AEDB1519CEA4
+:1090A0001B33C25C2F276439D425CABDEFB54A688B
+:1090B000CF88CB48F93981CB5FB9D1EC473BB75268
+:1090C00077B6533E52C14E456B81EFE339DB2768DB
+:1090D000FDCD707F5FB2CC7AC288A1E2DA4BB15D80
+:1090E000DB7FAAA8E484321F5DDFF73ABA5ECA5775
+:1090F000C949794D554CA2449E4EED9DB4FDBD9F8E
+:1091000060DE5A2F698B403E4CB7829F92885B731A
+:1091100089B6F34D542EFA434BE5818E5BD4F0EDC6
+:109120005E508BB94A9CE5CEC378F13E2B5B0F7144
+:109130000F4379BD9FCBEB490FA98652D1844020C4
+:109140000A8EC29E1DEFCF00FB5022BB6703BD4EAF
+:10915000AEAD4D5A44E5E7DBCD06C7383AFE94EF95
+:10916000CD28F0AB953CDE271765FFCDB47F9FBDC2
+:10917000EFBA5521F25595C1FCFE59BB3FE541B010
+:10918000337696AF928B7B521EA4E34B5247E7AEE9
+:10919000422A381766E0BE05DBAF18AF0D7F7E634D
+:1091A00072128B53C87AE68F0D5AE2B5C4604BA297
+:1091B000289D46535CF2E05C2A8565DCCFF7E1F33D
+:1091C000615C14C435B699F16CBF87B8C06E29FCD8
+:1091D00055F876193F29CA10D76B8C4407EBED4B35
+:1091E000D65A41FF15BE9EE4FA78D2C8F470A46C3A
+:1091F000463BB5A881D5F51649CCDE2EDA21B1FA69
+:10920000E665FEB66105D8E48AB533D19E2976CCF1
+:1092100046FF817CCDB3BAA2FDB67FC2EFAE2DBCB6
+:10922000267BE653ECD9003200E4EF6AF19262C784
+:10923000287B7E9F11B29F7C557E01C9E8BAE770FA
+:109240001C47CAD36D5AA04B77A303ECF9A2E7D30E
+:10925000D04F92F36BB08EA28C236B63517E57D8A4
+:1092600065E46B695322B1D14B739B243C273BAE21
+:109270002916E1A88E04844B7F7F5D01ACBB731F70
+:10928000F4F77D103EBDE1408E9BD5698C80878BC5
+:10929000287864D583FF3967A678503ABBCC2BB1C8
+:1092A000EEE8229DF990744902984A0DE89D53E733
+:1092B00065FC31D6A0FEF3752DE27AB5683FF3D791
+:1092C0008B46B0FD42ADB76F34F05FB74F263E0A14
+:1092D000DFB25FCEF5D3A1B5DC9E1BE235C416C26A
+:1092E000B7085B24B185F087789D01C8B7A672796D
+:1092F000792882D97D53668C306EAA7936CA4F2080
+:10930000A5781FACD7E2E829CC4BDC2C3E56E46AAA
+:109310000AAF9B8F27EDCBC04FDE3295F687CCA7E7
+:10932000CBFF01FD862E5F8CAB295D8E5F499ECE03
+:1093300064F0F74EFA92BE284F2AFA50FD407F7F24
+:10934000AE85BD7F42A39267F2293C659F8EF86887
+:10935000FF724E17885B21FF39E7B4A0DE28721731
+:1093600000BF47ED5C749E48B76E4E916EB12522EA
+:109370007DBABB447A5C373555E84F705F2FF427D0
+:10938000560C14E0E4EA61C2F85E8B0B04D8EE1DC3
+:10939000238C4F5B395180D3EB6E17C6F759532E90
+:1093A000F4F7F5CD13FA6FD8B84880B3EB7F258C6E
+:1093B000EFDFB454E81FE05F25F40FDAF78400E72D
+:1093C000069E15C60F695D27F40F6D7B55E81F7E5D
+:1093D0006AB300DFD8FE9630FEE68EDD023C821CCA
+:1093E00010C6171A0F09F048EB17C2F851F15F09C0
+:1093F000FDA36DDF08FD63337F14E0E53CCE2975E6
+:10940000FC4DB82F4096A5831CA725B987F7C1BA94
+:10941000CF292DE85FEB1D128985FC67DF242BEA3D
+:10942000FDCFCC030BFB70BBC8E5F80231DF09E7C9
+:10943000D9AF6617ED3C9E18298FC3F7AACED5B3D6
+:109440007A87DAAF2BF15C3475CBDA90E776731A52
+:1094500069421F84634BAC02DCDD152F8CBF6EAA02
+:109460004DE84F70670AFD89150E014EAECE13C64A
+:10947000F75AEC1460BBB744189FB6D225C0E97503
+:109480005385F17DD6B885FEBEBE0AA1FF868DD577
+:10949000029C5DBF5818DFBFC92BF40FF0AF14FA60
+:1094A00007EDAB13E0DCC01A61FC90569FD03FB4CF
+:1094B0006DA3D03FFC54BD00DFD8DE248CBFB9C300
+:1094C0002FC023C87E617CA1F1A0008FB47E268CC2
+:1094D0001F157F4CE81F6D3B2DF4577EE3F0E3BE74
+:1094E000D4DBEC7D57259E1B9BF983304E1747E359
+:1094F0007DA87F9348079CF7EF2ACE57E2C052C75A
+:109500004FC273FFAA61F1F9AB7DD8FB690FC82C7C
+:109510004EACF5BAF07C5E0C1C78A57A12ED955035
+:10952000FE20C59A8EF5C838F4B7E8326D70DE8D2E
+:10953000C6411488D1D8ED90879882716CD2A5412C
+:10954000D71EC736F52188C7C93EEED7402FE7D5CD
+:10955000BF510C79CE5CE25D017850BF1B0DFB580A
+:109560001F4688F528A51D6DA4740C79DEFE88BA07
+:10957000A48157D0DFD1C6B338BE735E5EAF92E828
+:10958000FA1685CCFF18CDBFB4544FEB3C54CF68CE
+:10959000A2FD84C78AF0539E78849FF6D8B05DE31D
+:1095A000C9C4F6598F03FBD77AF2107EC1E344D8C1
+:1095B000E729C1769DC785D7D77BA622BCC1E3C664
+:1095C00076A3A702DB573DD5D8BFC9B318E1D73D75
+:1095D0005E6CEB3D2BF1FA664F1DC25B3C6B106E6F
+:1095E000F4F8B06DF26CC4F62D4F3DF66FF73421F0
+:1095F000BCD3E347D8EFD987F06E4F00E1BD9E564C
+:1096000084DFF5B461BBCF730ADBF73DEDD8FF8192
+:10961000A703E1B37C3FE1EB3EE2BE9D021352841F
+:10962000F2A0C4BFE321EF01E1C8D37D27E43DAA46
+:10963000FC43CD8F33FC39BA021AFE42FCD33363AC
+:109640005D6D485EF0037FDE4391C41B41F5A1468A
+:10965000C3EA02353104DF0F233C3E9FC3E592C4C9
+:10966000B1B87C36C76B0ED7835C90CF4C94CF0FCC
+:109670007E4E9EA5E4DB51296E2993E2312F59E3FA
+:10968000C5BA8399BD873F20C5AD85EBE7AAEF7EBC
+:10969000179F677564C0434A0DFEEEB7423D69BF30
+:1096A0008C75D8AE9E57C5DF93E8B27FE7E924F00A
+:1096B0004725FF90B15EFFA1CE3215EA2D3D32194C
+:1096C0005D7A646A84F6AD145777C0E7647AF586EC
+:1096D0007BA5E0FBFF132035A77A5E466C3A3C87FA
+:1096E0004B9CEFC0AB37B7D0800FE05B89175B674F
+:1096F000B23B25B33B9C97F421EC1E664809B71E8C
+:10970000353E99992C7ECFCCD408ED9F525C7D00DC
+:109710009FE3E94E011F732F1B3F57DFFE02E0F569
+:10972000971D3F9C90D282F456EA1B2B46F0735A49
+:109730000B25651F9CC58946A2C489D83FFD7E566E
+:10974000EF51FCE5E1CE96D9C373D53AB49BD3A5CE
+:109750004807C4DBE7AAEFEF0FFB8577D07C0FF655
+:109760004F153B3A9DC21A0A4F27ECDCC5F4C316CD
+:109770009433B57DA5F711D8EF9B4E4906F9E3A5C3
+:10978000143BAEE743D70F3A9897C4B5E37BAB548D
+:109790006E4A809EF386CAF8FD860F35BE0C494698
+:1097A00079D14B14FF3971545EC2C40B8A5C2CE032
+:1097B000EFE528D7A9BC4D047A7EB76D4826EED3D5
+:1097C000EC1C6A037AD66AD87B75DEF765762E03C1
+:1097D0004AF9706E243AEB457CBF00820BE0DF5003
+:1097E0000BBE5FD02C93C56F84B1A7F772B9FA3066
+:1097F0005E57E2C379C57DC54ACED74ACEEFD2DDEA
+:10980000FB93E1BDC105FB749817919CB62C57984A
+:109810007355558B1FF945EF1039AF6A3AC6CE63C1
+:1098200091B6ACD073588FF07915F992F516F78B85
+:10983000E650FC3AE57C11D095CAF90988FBC71BB4
+:109840006CD1B7D25BDB2869FCB475FFCE8AE7F92F
+:1098500094737DB3880BDB3994DD20D72EEF6A7CBF
+:10986000AF7E1EA9C7EB0BF266A6005C45DA8BE261
+:10987000E97CB7ACAC79279E6237A96EF548A8732E
+:109880004FF4CD7807DAB2F5D209AF0DF5A416F88A
+:10989000D026552FEF499F77FBA611CBA18E3C5EBA
+:1098A000667C2007181FA83C39E598CBD747F5629E
+:1098B00015E04FF502F157F462FA52E294E282EFBA
+:1098C0008174EA49DE3D7F4E843D166D3B9E43A97F
+:1098D000DA698881FAC93CC2FC76B00EC4FCB5A234
+:1098E0000767748CEF675E93F03D9B3312C1EF39CD
+:1098F00074153728F127D53FA677474D4CFE655E96
+:10990000D74B71C70F4C0BFAE7331ADFE0A834F4DA
+:10991000DF1B801EBA02F7A303E0BCDEEB92A39626
+:10992000E272A69B2F859D13E8F403E49229582741
+:109930007C4CC7EA76EA7857594757781AF4C40B33
+:10994000FB5952DEBB3F411C7239BEEEF8C1942E6A
+:10995000B5C022A84B16B86CE1F058C69FBFEFEF18
+:109960002C1FF726133C17A4A6A76465CFE9AABE4F
+:109970006A8864F8287E4AC1F372BC18BF0E66324A
+:109980007BA1E0478835D34A9FAFD5463A405FCBAD
+:10999000B4EE00C887527F53F2E27DF693E80FC819
+:1099A000C5DA2476FED8DF951F3EDB998FA706FD2A
+:1099B000A452C722F9E1EB912EA315EDD744E24062
+:1099C0007FD1971C56E885752C197608B1CEEBC669
+:1099D0007518C05ED33602EA28E82F7DB82E13E052
+:1099E00085EB0A404584AC3645211D86B512B4D3BB
+:1099F000C3600D74BD3B8E111F9CA76ABE30A5D0FD
+:109A000042FB777CABC53CE819D3EB89F01D891D7F
+:109A1000A73F4D847A4FCD854684079F2D3ECDEAE2
+:109A20006787A7C17C6F9FD7DB0C18072C443A28A7
+:109A300075CAB70971C03E68DE67667CCF38B7A5C6
+:109A4000DE8474E375B57CBEEEFCF3AC1EB213800D
+:109A5000A1340F68D7137F48BCACB38A701E09814C
+:109A6000EDF0480A87D4397E6EFE68EACBEB2043DE
+:109A7000C890D0BA1AE98809FB3E957A1F3147622F
+:109A8000789FC874C5F5C5B86CA2CCE8FD0F19E87D
+:109A900075B3D99700F16DF3DC0D0910EF3E63FA51
+:109AA00007D2F1D9BFEB1380AE7523FE827EA48E60
+:109AB000DE1B80FC57EB8B2058FF9A8F75E09BB91B
+:109AC0009F7DF6E297249ED2B32E8FA0FF24DC0F59
+:109AD0002BFD7517CF55003F2FE41B6D60173278B3
+:109AE0003DB4E6A6FF17DF16428F1D34AEF65306CF
+:109AF000BF4DE36A3F8DFDB7D1B81A6078EF14DA35
+:109B0000061A5743EBA37135B42FD0B81AC6415C7F
+:109B10000DEDB334AE86760D8DABA17D9AC6D530F2
+:109B2000EE291A5743FB048DABE17ADDC5F242C43E
+:109B3000A795E0FBF54B4D511AB0AF14FF48A80BA9
+:109B40007DE41C1809F4B8E9BC46E06FFED9480171
+:109B50001E763C26C85FE0FFE19E42FFE09654A1DE
+:109B6000DFEEBD5E807B2D1E28C0501F0ABD3FB1B9
+:109B7000A2408013DC6384F1D74D9D28C0DD5DB722
+:109B80000BE3634BCA85FEC7A3547CF4556A443E7D
+:109B9000B2EF2B5CC837E3F9CAAEE4F409CE17057F
+:109BA0007EF297F2D47075DBB97D35423ED093E3F7
+:109BB000B6B0AF0DAFEF3D32E4958C1CE087866DFB
+:109BC0009B3ADB4DBD295F329ED410385788270E53
+:109BD000287E567EDF9305E74C20977B4AF511C01F
+:109BE0009F5DCE8248809796EA1342E5A8CEEE1E8E
+:109BF00088EF29B8D9FA94FB1F2F9878C57DF427F0
+:109C000040FEFA5CA17FCCBC54D087CBE8482A70D8
+:109C1000BF3648C789F87D27E2AE10F057EB0581C3
+:109C20004DFA0478AE51A4A733F561A0C3B34F69D0
+:109C3000F11C56E77CFC7E65BE91F245535BD6E590
+:109C4000F8EF72B2F134FE8D00BAD06709F8C5386A
+:109C50006C23803EBFE5FAF6DF5CDF9EE17C853C4D
+:109C600016606265F7297CABAB78627406E84D1E1E
+:109C7000C36BDDE427243037B1C451630DA1EB532E
+:109C80001C8F17F8BAD6C2BC14EE3ED92901FD527A
+:109C900016BB24D0B75E4BDA107E96EB7752753B3D
+:109CA0005E4FBECF8F6DCF8A00F68F9437E13A3A80
+:109CB000E9E010E9A8E6938FAF47993778FFE6FD12
+:109CC000206F179C0CFF28AFD909FE22CA6B75B014
+:109CD000D6C65B8703EC7E94D7C9E1EA2C801BF8DB
+:109CE000BAA2BC5E847D7C5D751571FB37D882CFCE
+:109CF00023B62A4DA8BFE94A9E9A38FD1B399DD448
+:109D0000F735E8BC83AC61F44A69157F3AB44D235A
+:109D1000E8F99056D14E7D04BF303FF0495F881B73
+:109D2000BC2E99EF5F211D2775E64BD3519E569BA4
+:109D3000EE3C00F9F6E41699307F3BFE1DB09787A4
+:109D4000461BD09F368F1E951C2A77CA3AB672BA28
+:109D50000FF53A8FDC47C797B90C8021755FCEE4C9
+:109D6000FBE97CAE71B203F6A15A3AFD89CBC4CEB1
+:109D70003B307F3291E3BC7BDCA447E0F9875AA8F3
+:109D80005DB005F154FA1B4A268DCD063E06181F1C
+:109D9000BBA2CF7B9C5FEF70BCF6707E3573F9DEA3
+:109DA000C5FDC90EEE4FDE067F6200BF93C7D7C365
+:109DB000FC4903F7277F047F42DB03DC9FEC077F2E
+:109DC00042DB9CD169456837E12536F4273441C12F
+:109DD000F3040B847529789524C9027F8AE34C0229
+:109DE000FF8ACCB1427F813651809D175305F8A67A
+:109DF000F3D7ABFC94E857861D1FA6F25305023C2F
+:109E0000B8658C70FFF89C49023C2E6B9A008FE974
+:109E10003D538009DF0FCB65BF93DCC8B532E6B98F
+:109E20007CDF4989A70E95C8B86F33F413D911AAFE
+:109E3000B7B9A4739F4C03FB64347CB16995F952A4
+:109E4000857E8CA35A74AE4438BF575346E590B60E
+:109E5000F92D344EC3E223956B1AF7E6BA46611C1E
+:109E600048E3A541C88776B6DFA4EC5B0D55ED3F0E
+:109E7000B98AC4FDA9DCABEC4FDD747D1771597E46
+:109E8000EC35C56554BF30FE7AC674E71E909B6DF5
+:109E90009FD13815E2DCCF7E81F1D7073094EAEB11
+:109EA000D6AF7F81F1EDD64E7D710BFA92CBF5B630
+:109EB000B125B5A98DEA5B4E37C9C1498DFA92C764
+:109EC000D794736CD1348C775A34187F91922AECE2
+:109ED0001FCCEF6F685D6A12DF5B0A897B306E8F83
+:109EE0000CCA0BE4932446ECB786C8672A635AE889
+:109EF0007842AE57CD3750050F538D2F50C1635464
+:109F0000E327AAE0DB55E3CB85FEA6B689578CBBD9
+:109F100015BBAE8CCBD5BA644718BB3BB8458C0794
+:109F200089AB4A38FFD07C6436DACFC6C32B389F62
+:109F30002A043EED569ED342E99D75F9FD055AAFC0
+:109F4000A91F95878216ADA3C616E4A3C22702797E
+:109F500071C87C854659D0E3A656E61FBB5AE74E2A
+:109F60006EA7B7737FF3962A8E93FF7EFED0042AE6
+:109F7000278D6D1ACCB31A5B0A62F1FDC18BB31049
+:109F8000DFA6560DBE4FB6F1D5F1B7D46883F829D8
+:109F9000F8E47CB2D404E7832E507F047296A37356
+:109FA000C65AC3D05D2D5F5DCDABC82F25542CD0D4
+:109FB0006517F547787E98DB55852EBB8F3C8D74F1
+:109FC000DFD6CAF0BDB943F48737B68BFE70F8A967
+:109FD0001801CE39C6E242EA7F71DE1C7EEEEE6ADF
+:109FE00078ABF502764844B8A738FE1AE3826D5C78
+:109FF0004E1A389FB64538A6867BFFA8E1A8BE2238
+:10A00000F4FB0A27AF67F5B993D7B3B83BE79806D7
+:10A01000F35CAAF7686F875AEBE4EA30F30C3BAEC7
+:10A0200051E52D9102FD7E6EDEFAE5F57CDF53658C
+:10A030001FBBBA5FB18F05CA77541C93C29E930DA4
+:10A04000F2819FAF54D19338C2DBDFCBF9A69C4B92
+:10A0500057F1AF8BFB83F378D579F5A5EB619EB60D
+:10A0600032F43BAB4D0BB85D5F8076FD839FB85DEE
+:10A07000FFA93109AE1F18B03509F4E840AEF23D32
+:10A0800058CABD907C5AD1A3F75B3E3685C6FB63A8
+:10A0900038EE3B320F8DED1FC2CFAEF0DCC7E5E7E7
+:10A0A0005D1EF7ECE57ABE9BC73D7E887BFA803D5E
+:10A0B000C8E4F680E5D16FF1B8A789C73D8D3CEEC5
+:10A0C00039C8F3E88F20EEC13888E5D10D99F7E261
+:10A0D000F7C52E242971CF786D383E8FB689766A00
+:10A0E00054BC4990B7915631DE2934260AE3479093
+:10A0F00034A1FFE68EEB55FA2DC63BC34F8979F4A8
+:10A10000D036318F1ED22AE6D1138BC478C7952F53
+:10A11000C63BCA3EC22EAB84E7B1C6E788F1CF2E5C
+:10A12000F885F63718D9F9AC86CC4957B4C37E6E9A
+:10A1300087FFC8F5FB3DCE9F7778FEB093D37F07AE
+:10A14000D01FE3521667E69E77EF89B6817DA8603F
+:10A15000F9426615E6D537725CB67AAA597C7A411F
+:10A16000637650BEEC32B3386B57E6CCF3F0DEFFCB
+:10A1700005ABC906F599033A37C2BB32251B7C6F84
+:10A18000508D5F6EABCACFF1784191CF5D2D5FA24C
+:10A190007FDBD9716D7E5519F71E998475979B5A8F
+:10A1A000083184A92F5CCDBF5EED39EAF1E0C7C369
+:10A1B000F91FF573C674B86542F577476BE04948F7
+:10A1C0008BC6F8E7CAF05DA8C1ADEE42E0EBDE4C0D
+:10A1D000C90AFBE9745C21EC4BBC77F1E3B1707DFB
+:10A1E000E779ADC680FB4E56C11F7D7091D21FE44A
+:10A1F00025939D4FF2B77EF9487FA8F31A657C7FBF
+:10A2000064D7C58171A1747BFC0619ED4A43964160
+:10A2100003F5E686F35AE20F89F71A3B52CDD036A2
+:10A2200064CAFC7A00EDC37337B073AB3BE87CCCF7
+:10A230005ED8100F451EFCE73525E1BEBFF31C7F3D
+:10A240005EEEC53F9B20BF7CF77CB909ECD3CE56B0
+:10A25000F69CDC256D26A0DB818E7566B8BE2B735F
+:10A2600010CEDF9CFD907920C84DAB86EDE7F0F86D
+:10A270004679DEAEAC398F0E8075B7B2BC6CD7F9BB
+:10A28000CD7BA2402FD64B0E16BF307BA68C6F38ED
+:10A29000CFEB4D3E76CE2D97783FCD06FDE9F17B95
+:10A2A0003DC839F1569250FB576815ED4841ABCA8D
+:10A2B0004FB92B511F143E946A6385FE039F4D9C3A
+:10A2C0005C067C33B3F7DB769E5F1A3711F4C2ACC1
+:10A2D0006371B38FDD3F2E58AFC1F7B594EFB0D4A3
+:10A2E000643F70A814EE6F607CCD358BF81CE85B82
+:10A2F0009BB880CED7B0C5E410D67798E0FA76390F
+:10A30000DE9C8E75ED2C03EA61E185BDE6B6903AE0
+:10A3100051679CD8B2DB3C08E87C5623D04DA1C3E2
+:10A32000A83C317FDC91B907C75F38CBE89E4BAAC8
+:10A330000FF567755873E9E060FE95DBC1EAE373DA
+:10A340007D22DE43378AF9E77C557CA4AE9FE76720
+:10A35000CD1927E4573C6ECAE37193BA4E5EAA3515
+:10A3600088F509559D3C575D27FF67E3249D7B1ABF
+:10A37000BE0F17987C4DF1C3501A6BC6E3F95EEF20
+:10A380009320D76FF1F872A8BEEEDE04AA220DB2B8
+:10A390007B38EE5BF03A9D72FF55E325AB97C40D19
+:10A3A0000EC98789F604E4972B618F13F9E265E7FC
+:10A3B0005955F376156F28FB23F945CCFF3C63FA1A
+:10A3C00010E38BC6AF597C013F6D3D60BF9EA01F5F
+:10A3D0006EFE5A8FFB276F8F66FBDE4ABC328938D0
+:10A3E00071DF667CDE79ED6F6CB09F7367F67CDAA7
+:10A3F000BEFD5923E6996F77E69975429E99CFE5A0
+:10A40000725BBBC61B0BF941ABC14742F6DB95FE45
+:10A41000C6F6F247B2410E031A94C3E66FF504BEC6
+:10A42000BFD7B8DD8078379ED5633CBA6DBB89C98C
+:10A4300035AF3F2BFADACAFDE2A79C9F07B85FDC75
+:10A44000CFFDE27BBC5EF30E8F5BF6F07A4D338F6F
+:10A450005B7681DFA4ED9676AE774B4C1C4F569F12
+:10A4600055F0BCAB4FDB112DE56BD57783D7403D65
+:10A47000EA36B7A80FB74E15E3937159627C32A63E
+:10A48000B7588F29494A13EE2F8EBB41E82F320F60
+:10A4900012ED9676B8003B2F8AF1C984BCB1A23C7C
+:10A4A0003943E213CCAFC57CF796D07CD70E7C62E3
+:10A4B000F9CCB6D627D04F6C3B9E1A1DFA9DE0AD65
+:10A4C0009CCEDB8E33BFBCF5F0394B68BFD29EE229
+:10A4D000E3CE707E9CE5FC9894E0BC238BCACA85D1
+:10A4E000E3E7F470FEA32B3956EE57EE3BE5FB2A6B
+:10A4F0002AD4EF7D0DCC08393FF46DE31719684F6E
+:10A50000AE512F6A2DECBC5B831489EFE15FEDFD4A
+:10A51000962559A95C29ABFBB3FDD1EA21D06ED0B9
+:10A52000B912E13DA806C9356D3EECF3FE561FF6A3
+:10A53000EF4AD46649CA39F426F00B32D76FB249D4
+:10A54000D2827C4570F045E2AECDEA0E45B16A1C80
+:10A55000249B5D04D6B545479AC0BF1327B1597BEC
+:10A5600010B655469FF3976CF7C3404F29C0F6913C
+:10A57000A95BC5EF7EC0112DF8FE16B4B05F663042
+:10A58000B2F70F22B3DC8FC3FCF05DDBE881306FE4
+:10A59000411ADB4FF5A39D9EC6E7D598B627E3B9D0
+:10A5A00055759EC4EDB5A2779D74AD14DF4B51DB9C
+:10A5B00059A5BEBBCDEE9A162E1F7D258BE59F4D6E
+:10A5C0005F8D97E1B939C62827FB3EA45386F7C1B2
+:10A5D000B69D18639A1146CEF6F69BF10AAC4781F8
+:10A5E0007302F532FF7B151AB1CEA5F103BF2F9888
+:10A5F000F5A8D74361C13197CFA7B6CF798755F674
+:10A60000B9739FBF4E8273679DF2040C01FE1F64F5
+:10A61000DFD5B89A3CA9F7EFBFC84AE5EF4D557FA3
+:10A6200001E74CE468339EB3D972D0B84EB65F9E52
+:10A630001F36F0BA9F1AFFE6CF6627621DE993D94D
+:10A64000ACFE07861DBF9B563D05DED3EB8461FD46
+:10A65000D00F1FB4C3EF002D60FDA315B86A0AC464
+:10A66000AB5B47B0F19F6F0A3C0DDF05DB7A07EF6C
+:10A67000278FB1F10AEC5D386504C03A568FB9E511
+:10A680003536FEE2F5CE2F803F9159CEC320A7AFDD
+:10A6900082EED0B6E87AE751B8FE05C8186D3FEEF5
+:10A6A000EB6C837E05EED6D7F965687F6367DE2B9A
+:10A6B000D6FD8728F1E0E1727E5DCD77C5AF5CB94C
+:10A6C000DEFF2197D30FB89CBECFEBFDFB78DEFBFE
+:10A6D0002ECF7BF782FFE803F9B083E7C3793C1FF5
+:10A6E0006679D7769EF7BEC5EBFD4D3CEF6DE479FC
+:10A6F0006FCE271359BD1FBE3B2841DEDB2F6CDE1A
+:10A700003B214FF42BA50ED1AF8CCD14FDCA685B55
+:10A71000A22A4F4E53E5C93708FD85C641AA3C79A8
+:10A72000B82A4F16FDCA8DED635479B2B87FFC4547
+:10A73000968DEF27DDAECA97C57DE4201FBBAA47E3
+:10A740002F0ACBC7AD2D8B0E5CCBBECDBFBB7EF130
+:10A7500021E7E3079C8FEF2BFB369F7C8CF9DD858F
+:10A76000F384F3F175F9FF62FD6242DEA4B07C2C44
+:10A77000754C53C9DBCC2EF8F84FEAA3F9CA75A87B
+:10A78000FF943ED6B6C4307DD42A75A8EFE470F1AC
+:10A79000CCFF357DA471C163D9D7A08F6AFFAEBC51
+:10A7A000B7A8C40D9D71028FC7947C690BA5157C59
+:10A7B00077A22141CFBEBBA175F784B843A1D7EFE3
+:10A7C000B259BCD3F8C502D48BC1E0CFC3D0F55584
+:10A7D0003EEED56C2BB6F09E64E440382DED65F16D
+:10A7E0004FF4382B3B5F4502F01DAA2BC44DAF66DA
+:10A7F000770FC64B5A6B35013ECA068D17BEC34B49
+:10A8000064239EBF6B80380ACE59ABE2A82FB3ED0C
+:10A81000CAF7782598F70B3EAFD4F22E9EF3FE4B85
+:10A82000B6730BCE5FE868877DC8C6237ADC67699C
+:10A830008C60DF4351C75B1F6667F0F79719FDE037
+:10A840003D805F803F850FC6A2FFFD52F49F1048F8
+:10A8500050784324EB0F647F35C59B14F4D79FBF1A
+:10A8600076FE69F8BE6C86B9E74C383F20ADF1C67C
+:10A87000B07D4B3FEA973A6EEB32FE55C5697FCE0D
+:10A88000747E0472720EFC72773C5FE5D40EECFAB3
+:10A89000FE0D91AE7BD877619C323C57A153A7FD4A
+:10A8A000CD6671DC877CBE4EBA287205DFA98909A6
+:10A8B000791F5685BF42AF1507F704E028E3CF5D47
+:10A8C0008FB28E30F2E3BA4ADC7D0EE8A0961F32DA
+:10A8D000CEC1DFD70D1FF7E9781C19CAFF61B82E6A
+:10A8E0009FC27F327220BC07A3BCBFCEECA1F2EEA8
+:10A8F0004C8CB5CE6AA77A74678B8CEF1F12BE1F83
+:10A90000AEEDE467BE04F6495B2C91D890784F5DBC
+:10A910008754C7A9EAF365F9677B0AF04DE75355F9
+:10A9200079E4F5AA3C73902A0F15ED51715CA130C2
+:10A93000BE2469AC2ACFBDF239002DD12ADF1BE23B
+:10A94000FBF6920DBEC3A365140AEDE7DF0362F4C4
+:10A950005ED6451EA49CA3FD4BB60DC775EAC75A2B
+:10A960006263FCF30A7F1F4A1FCFF8FBF860C58FB4
+:10A9700039B0EE6EF0CF657FEFC921BE4FBCCE631C
+:10A98000FCBC4807EFD990CF8BD2F1FC0EB62F78E4
+:10A99000E2B15DEBB161FBAC2713C7ADF138107EBE
+:10A9A000DA9387ED531E275E7FC25382709DC78561
+:10A9B000F0A39EA9D8AEF2B8F17A6FADDB0B7F1F82
+:10A9C000B1F74A82E74BD3EBE8F342E89CB692E258
+:10A9D000114247BBD72AC0BD16C70BE393AB6D42EC
+:10A9E0007F6245A6D09FE07608F07553F384F1DDD1
+:10A9F0005D4E018E2D2911C67773BA04D8E2982ACC
+:10AA00008C3765BA85FEDD370D8B6EBB823E3FE12C
+:10AA1000711E013A3CEA711D29C2F7A44A105EE595
+:10AA2000998AEDDC7EDD50AF62B401CC8F6272ACEE
+:10AA300060B121BFC5FDBF58AD43EA16327F6C0936
+:10AA40009D4FC097CE27D4277D389FC5E13A22E29B
+:10AA50003D55B88F3E0BFDE4043E66A49C64817CAA
+:10AA6000EC607E2C7EB7F5119DB53487EAF1479FE7
+:10AA7000B0EFE4C21626096347BFE6718DA99F11A6
+:10AA8000F3C5094F4998DF11C2EE9FDD92E608FD3C
+:10AA9000BB504AFBD1AFD977874CBBB7D9403E26D4
+:10AAA000E4CF888D08D97F99E0FFA92801E71B3002
+:10AAB0003882CACD843533F433B382EB53C6CD7EAE
+:10AAC0004AACFF06E5DF67E4711CAED3C0C7AC4AF1
+:10AAD0005A87D757655E79BFE60C5FD7291EAF9DB1
+:10AAE000E071F7715E7FFB92C76B6D3C5E3BCAEB1A
+:10AAF0006F8779DCFD39AFBFB5F27DAB4F79BCD63E
+:10AB0000C2E3B58F79DCBD2A7333FE9D980B9BD8C9
+:10AB1000DF25EA0A9F7B368AF1DA5C9F18AFCD59B0
+:10AB200023C66B77D789F1DACC9562BC36C32BC6C6
+:10AB30006B772D16E3B53BAA45FB38ADA250806F6D
+:10AB4000738B75B95BA78A71B7C2A75B5CA29D9C2A
+:10AB50005422C6DD5DADF76DFF68DC7702667E15B9
+:10AB6000E20F43BE0B2F9C7BCCB13A0B61FF2697C3
+:10AB7000B86A61BFE6464DE010EC33914F65FC1EAC
+:10AB80006413DC3194EAEB85C1E326D842FC8E578E
+:10AB9000949FE987C5F311B7DF27D2B5AC52AC77E4
+:10ABA000EA4B44BA3A93C4F36793547E87707FA804
+:10ABB00067BF9322D795FD90C65489EF2DFD5C7F2A
+:10ABC000A427EA7364CC1FE17353857EF447C6FE65
+:10ABD000EC7DA5C1FC7D859A88211FC0BEDDEECF2E
+:10ABE000D87B0694EC81DEF4FE9B08A3B7DE380A1E
+:10ABF000BF23B743C7DE1FD89560762CA55D375DB0
+:10AC000064EF09900E2D9E2373C3FB23A930AF7808
+:10AC10008E2C37A015CE99E955FD89E013AF880F2A
+:10AC20003B4FF79FC3879FE3E84FFAE3F988B6F0FD
+:10AC3000EF1D74C6712AFF1CBCCEE456B147397EA5
+:10AC4000EF213B5D578E2A5E32F075694CD3F1FBE4
+:10AC500063864F09BE7F9FA7F1C6C277B6C8390D7C
+:10AC60007EF7650411EDC2E47157CEC747C58B76F8
+:10AC700061B42D4D95F7DDA0CA0B45BB6020AA3805
+:10AC8000A78D9D4F34B09585F623DD26F78F51DED5
+:10AC9000DF417AD51C5B81E7EFB625F3F751B85C4D
+:10ACA0000DE7EB1D9EC4CE2FE6F17A71DE0F8B64AB
+:10ACB0000BBD6E385ECCCF312E71601C7B96F12BB4
+:10ACC0008FFE037EE69110FE013F0F8BFC34A8FA45
+:10ACD000E7807CE586C387C9D57F1E1F7E8E529193
+:10ACE0002F73CC55F6EDC2CBD788805386F783DE21
+:10ACF000B14AB82FFD4EA03A00DF89FC319ED5271E
+:10AD00001E4A9AA865DF6D719A4752BA17F375E625
+:10AD1000F17DB1460F09405CB2C563C496906A3CB0
+:10AD20001FBD227E512CF8CBC61477229C076CECF9
+:10AD3000DE6D199C1368D0754B0AF71E41B36E087F
+:10AD4000FAD7C6E6042D7C577E84D6AA85FB462416
+:10AD500095CB90278E82F74DE20026B81FB6C5E34B
+:10AD60000F14E1B950379E1FA2EB2884F8B5C83AFA
+:10AD700003FFDE63F32754FE6D101777C37DE3BD39
+:10AD8000DDD9F96B83959D6F2D8E63FBB0390EF67F
+:10AD9000FDBE9C24B3C307D3C5B3EFF854D07F974F
+:10ADA0005283FE81EABBF07D9F212404B6237F04F9
+:10ADB000F839357F54E71157B4F273736DE1F76BCF
+:10ADC000FECCE309E57CFB611E4F7CCEEB3F0779AF
+:10ADD0003CB182C7137E1E4F1CE2F1C45E1E4FBC05
+:10ADE000CBE3897D3C9E789FC7131FF07842910B7F
+:10ADF000C34A6233C07BB4C904EBF2F1CB245F09D0
+:10AE0000ECB3BB196C98C5F64F7B25D5B90AE2A007
+:10AE10005FE718057239D53B12D6113FBDBD02C69A
+:10AE20002524E96D4E3BBC9FB40ADF2B51DE0B9B02
+:10AE3000C5E5E6367731DADD595C4F88BC3617F365
+:10AE4000D33AF1FB71096E5DF0BB49F4FF0C157D3F
+:10AE50006F537D57492F317BF1BE6277079141A136
+:10AE6000748FE7748F98C1E90E2F5D85D197359C5B
+:10AE7000EE0A5D9A6F1A6661EBA810E2C243F963AD
+:10AE80002C206F2D497C3EFEBE8C8B3F6722D70F56
+:10AE9000655E657FF6F1822B9F6FFA888FEB848168
+:10AEA0002FD121F3143CA883EF92DFEAFF6532E84B
+:10AEB00049F07D1A07C6E123E5FC3F423E1DE0EF65
+:10AEC0001F28F6720AE1B4523DEF90E7CAEFED1C7D
+:10AED0002A18AB83EF764FF6FF12FFDE83415B1D2E
+:10AEE0001F7ABEB785E3F750D9BDF877E00229EDA8
+:10AEF000F8BE9AC165B0417CDE2BC9B11CE8179F32
+:10AF0000D456C4EBA12A7FB5B6390EE4AB1FFB368D
+:10AF1000E2FF072D97429600800000001F8B08007B
+:10AF200000000000000BED7D097855D5B9E8DAE79F
+:10AF3000EC3364E484C98326B813A658194E263826
+:10AF40000987B003C1460D7002018284709230C43B
+:10AF50008A367632BD8F363B24246110F03EEB8377
+:10AF60004AF080436B3FEF355AEBEB40FB4544E53D
+:10AF7000BE673128B4D8DB62982CB7AF03566BC7D5
+:10AF80007B7DFFFFAFB5CED97B7312A085567B0BBF
+:10AF90009F2ED65E6BAFF5AF7F58EB9FD63E6DA56B
+:10AFA000255903A98C2D0DAFAB645319FB00FFCCC1
+:10AFB00066CCC354632097E11FC7070AFC3FCA341D
+:10AFC000753A3EC7279676F64136FEBF9985D3E09F
+:10AFD00079E5C7FF83A533B6983507FAE0BDFEC211
+:10AFE000C0281F8CCF6A5C67B17F2EFCFD20273EF6
+:10AFF0008F2C1733F5AC79BC9420F4F78A3AA3F977
+:10B00000E27568EFEA669A671854FE04D08D86F7F9
+:10B01000B14D83E72A4BF34D86792B3FEDD5A1CC7B
+:10B02000C974D47B605D0BB33EB5928D843EF33D15
+:10B03000BE09005757A8E8270550EFD2D769B83C9A
+:10B04000ECB70EFAFDB0ECBE2C6D721CAEAECDAC02
+:10B050003402F374657DCEBF360DFBBDDF1AC17EB1
+:10B060002E56D30BEB3A31E7FF65669BFA3F3DADB9
+:10B07000ECE6C02818B002FE3786B189EE484E6073
+:10B08000F2C5EB65CC600CBAB495263356C8D8E946
+:10B090007A25EA01406ABA017F53B1FD42133E8F1F
+:10B0A000747BB42D0820D353E7C33AD77014B0C8CB
+:10B0B000848EA23E58EF9A6E4E37F6A0EB34E2CF64
+:10B0C0000B7F11BF59CDEA6933FE224C3D6DC66F2F
+:10B0D0000D33B543DD8D7300BCE581B4916FDF0C9A
+:10B0E000FF2E60051F3839FD11BF35A26F52FDE2FA
+:10B0F000610CD6C3FC80BCE28BD7B5FC774ED6374B
+:10B100008211C3B0A2F8F337578F4B8EE07BC8375C
+:10B110005EC157D388669A1BF82A199FE460C9DB81
+:10B1200061692F105FB5B8E27C96836CE63262707D
+:10B13000E758C66308EF52731DDF37F4E3E301FEFF
+:10B14000958CF3C7CA505325F227FB0CE72F2F3CF1
+:10B1500014E3C4F90FC6A90ABBE27526E8355AC044
+:10B16000097F96943FD6FB6F30FE633BF3E7235F86
+:10B170002DF9829339A15E0DDDB05E5DA344A380FD
+:10B18000D3A5A15B889E4B6DFC9D5C6D1DFFAD0D35
+:10B190000534CEAA4A180769B1C1D44EF0ED247C1B
+:10B1A0005631DF26942789D7B7B3D97806787C61E2
+:10B1B000F7BABDC82FE71EF0300FAE1BDF05BCD6B7
+:10B1C000730AB2E3691CAE9F6E56A2FB61FCB3BB6F
+:10B1D0003DC4776FAF51A20CE9CF7C4FA0BC76077E
+:10B1E00032689E734991BD9F87F686AE9480017840
+:10B1F000EB1EDE7C4F18E63D9711A9C3711ABA6E9B
+:10B200007618D83FD9F0E6E0B80DCEC07E9862B986
+:10B210000A381D0E25FCFB0628EBBB4DF482FF8E81
+:10B220000614E2FB050E16E94DBD987F92F2149AC2
+:10B230001F11EE31C1BF20C741F09E78D043F0A668
+:10B24000E469344E7D30494F4A473A325DCD077844
+:10B2500032F5B108E75905E413F8EDCC12C540FC0E
+:10B2600030800BDF77DF70FD3E94A727C43ACFDE36
+:10B270003F632CF2F3990CDE7EDA9F1CC5759DD6D8
+:10B2800078DDF0A7461F477AA891DCA5697C1D0AE6
+:10B29000F0418380AB4173E84940DF860797DD8545
+:10B2A000746EF06FBB17CBE369469A02EFFF74B779
+:10B2B0009321BE111FDE7C6C2F5987ED76BCFC3AC2
+:10B2C0009043EB41FC8D00BCBDBDAB3D2D82FBA688
+:10B2D0008F45DCA3E378A8DFF9BFEF53F07DC6F715
+:10B2E0005FAF90138599F663E0DFE59ADBA8807184
+:10B2F000D8A1F1C4B7CB7D9CFFDDC59B46E5F06EC0
+:10B30000A931FED0A8BE0DF7F70651AF47BE05BC68
+:10B310002E4779998AF8183E1DF79B9AD5D67D79E4
+:10B32000D3C88DF72F8675AE09BA9813DAD7F855BA
+:10B330000B5F57B558F91CD66DA9FBF218D1A17B4C
+:10B34000B8E0CF4ECE9F8C85C786A7C4F9E2CB016B
+:10B3500007E107A1730D817F3B5E3F6A78388DFC62
+:10B360000AE7CD992C6D6F318C77A61EF887C3C57F
+:10B370009C2679A8EFF610DFC3CEEE463C017FBADB
+:10B38000ABA6C4F945E2A77E571BF163BDE0BB86BF
+:10B390006DC03FE9263EB2E10BD7ACCA79C6C5F90C
+:10B3A0008CDA13F0D977021C6E297FF52C5CC79CD0
+:10B3B00017CBB52C89CE2548CFBB6A8C4C1CC52039
+:10B3C000BAEE282D1946FC2EE8A1C6E9E145BAA53A
+:10B3D000CBBAC18EE17E9E26EA192DCA9BE505D027
+:10B3E0005FD0C9533E10ED83A6E12DCE37CB475039
+:10B3F0001F4D85FE23043ED881194F4F1C1D3F6F02
+:10B40000D2C479A03A33C7607B3AB3EA3D236CEBF0
+:10B410006785AA3837F839FB80CB3706F7E364B184
+:10B42000BFAF9B374EC17E0F280AED3F9E0AD5C2A3
+:10B4300027AA4D8FC9C97388FDCE90FC4DE7AD5B3F
+:10B44000E83349631C2417BFC984035589E3C3CD7E
+:10B450008760C3FBB4DE3E68AFF37B035186F0F236
+:10B46000F3A10C88D067E2AFEACA14D66782639E64
+:10B470006F84A5FE71FF0D96FEB76AE32CEDB7E76A
+:10B48000DE6C699F1F28B0D4DDCC74AE239C031CF6
+:10B49000EF6E816753BB3C97FB918E8BC53A76B8B4
+:10B4A00023FE30E06BB17F2DD1A3ADF4137ED44BDE
+:10B4B0003D7E4E57B7D0279326ACF6911E51C9E575
+:10B4C00027087F910EED38C898389FB96DE7AD5DBC
+:10B4D000FEECFA64631EE83D2950F918FB18E93DBB
+:10B4E000A9C313EA3776FD0DCE0807F26BB2A0D7D9
+:10B4F0003C672A9D1B5DD55C9FEBCA5DC4F5A5DC4E
+:10B500004F125D17887ECC7090DEBA54AC5FEA5F54
+:10B51000AFB532D60747F38E12AE672D0D5EA83653
+:10B52000EBE5B2DC82FD26C5EBC9A17DBA9E40CF1A
+:10B530006C13FC95A2F3F6A55EA6E23924DB378AEC
+:10B54000F376A938B717821C23DF86B1349DCFDB91
+:10B55000C538DB63FCCAFAF361DD4E013F7B4A511B
+:10B56000110F49A2BA8F45B6E715219E0DEAE44CAA
+:10B570000D3392EF3F0176A1DF02D1AF2C6F75CF73
+:10B5800067817F3DD56901B42D3CC1FAC7BF54889E
+:10B59000FA514AC0A1C5F99DEC0EA88FCCE5FC5E1E
+:10B5A00093E90D50B3A11F1B0FE3558BF66A21CF12
+:10B5B000A35833C9C145768C97F3E5E0760CDF7F5D
+:10B5C000E47C1EB1AF30E78600F15D98EFFB0EF82A
+:10B5D0008B7CB7A4C6CA57CB2243F3596F9ED0AF1A
+:10B5E00067B019C46791F5C4171ED167C7D88361C6
+:10B5F00092F7A09391BC0BFB46EA9D47822F12FF66
+:10B600001FC91D50F5D438BF487D7C41C8A947B13A
+:10B61000BD9825FBE01C39E21AC87C00FAB954D663
+:10B62000A7E2DE2BF4F2F4E0B2DB7CB0AED78A5FA7
+:10B63000F19D4A6583EAF3767E9F08FFC07D7EF325
+:10B6400084B7FD08C76617345D8FCDBFAA4178B6B1
+:10B6500063BD04FB9FAF2983F6ED49B2FEEE2E6C6D
+:10B660007F2299D77FF5CC1F771921A207F14D8A48
+:10B67000C0778AD4CF279BF00678F68ECCA77DC4FE
+:10B680006BC3A75D6F770A7DDB69937FFBBC67A502
+:10B69000BC0B3A0CB6EE8BE005D6FBD8D07CFF8B0A
+:10B6A0003C3A0F9B2D7C7FF1387DA49FAF10EB7649
+:10B6B000A41CC88A2490DF18FED7BB7E6EB6070094
+:10B6C000CFDF5450AFD5E1EDE99C55701C25F8F261
+:10B6D000EFF17C577619C3118F4EE880E7B80B2C39
+:10B6E000408447CA6312F28113F1DE47ED709E0E6B
+:10B6F00028E370905A1FF2A702FD3F40FC5CEE3E2B
+:10B700005861B513DDB87E18CFDDCDCA3CE9683786
+:10B7100036EEDF5C88E7983B40FA57F78532A41392
+:10B72000B4EB1E2A2FE8747EFB1D9673E585D23F8D
+:10B730009C7F1458B3B3DF19F0C07B1DD800F074A0
+:10B7400086BECD50BF7E77320BE0E2EB22BE796E33
+:10B750000DE5A1EF44C784387C275A597FB92B5E89
+:10B76000EF3F98E4D660B111E35E2FD2E5AD0DED69
+:10B77000539E433B3BE8F1A1DED6BFB1DE40649C63
+:10B780001863F4224EBBD40843FBDDBDE17FCEC37A
+:10B79000FDF384CB080C87B27BE3CEBBF1BCD2B502
+:10B7A000CA8A6C807B7FB75A114D60CF7C229FEF95
+:10B7B000AF475EB873FF66F4378C710792609E01E5
+:10B7C000F45F00FDBA5C46168E7FA2AD3D0BE5A38B
+:10B7D000ABBE2B7010FBB5790234FF6E6F0D8EDBA4
+:10B7E00095B5D6BFD634BEF70677333EEFBFDEED54
+:10B7F0001E47EB7927CD0FEBE8DE50300279B373AB
+:10B800008C7B6C23B637AC631AE8856EBFE142FED1
+:10B81000F2AA6C17EE0337FA2F7C7F06DA439A639D
+:10B82000FAC7A1FF7D8148793ED0B1A6E5D43CD8C6
+:10B830000199BB3C63139E3F9D024EB90F49FA0E1E
+:10B840008C69F062BFCE4823F7B3F81DF548E78551
+:10B85000631C61DC7F3A436BBC13C5F375E917E3E6
+:10B86000A513FD2AD3104E58D714ECF77E6B04FABB
+:10B870000D64B96B12E13122F0E86D5F97D302706D
+:10B8800077EEF6FA103F9D4A64573DE0CBC84E0D67
+:10B890003CAE5DFCDE53E23DC91F402792C34F3CE6
+:10B8A0003B7AB7311EF5514E47C08BD7653A179F8B
+:10B8B0009E56B626DFE4BFB868DE319D741E742A3A
+:10B8C0005CAE9F7A76EA6E03EA8140E46E7CAFABB1
+:10B8D0001B78791AAD732CEAF383C9CF8068EF6CBB
+:10B8E000F3D44413C8FFC06A279B348C97D74139DF
+:10B8F00071A373AC92003F03590D39D9781E40BB38
+:10B9000003C619D8EDE5253CCF81E76F0EC29F53E2
+:10B91000F2F9793E796AB81DE9CF2647C88FF772E8
+:10B920005E7813D5D94E3FDA171F01FEDDF321E112
+:10B930005F3A0F23F937137F31DF708B5E3AD8FE01
+:10B940001916FB715BE91F9AF0FCDF5AECD13C261B
+:10B95000BF9FD4939327737D243CE1B100ECDC6C52
+:10B9600071701D3F2F2BB9FFCF077F13F9FFC23630
+:10B97000FF5FB2AD2EF5CF43F9423F117A70A6B604
+:10B98000333C07ED8B579D8128D03D0B5F1889FE16
+:10B990003125DA976D82F726B78097EB6B0BC57967
+:10B9A000F4A3562F2B9FC06276DB72B18E054DEF4C
+:10B9B0003C8676F402A16732243ECC5F3D999FDF3E
+:10B9C000D26E5B849D814597E772BB002C2B7EDE97
+:10B9D000382B8B901F1632AB7EB788D9F4B9D55C63
+:10B9E0001F93F6DA0A9BFE60B70BAA6DED3B60CEA3
+:10B9F0007ED4FB54B04600CEF782053B0A00EEBA77
+:10BA0000E0A14D0309F69BE378DEC07ADF68D5DF5D
+:10BA1000EC80736753F5D7BD03F0FE56B5D78B7234
+:10BA2000B2B5F2D36928275B6B9D248F475B2BA8A7
+:10BA3000DF6BAD612AFF2B3F23E6FFEA93F601C0DF
+:10BA4000B120A0BF8FFB8AD4D3AA2BCBDEEC30D1A0
+:10BA50007751F9AD967A3854F56687DD7F897CE6B3
+:10BA600064CD89FC6E530BA47F45B7F83999F3A9CF
+:10BA70004024417F59021FBD67C6576A8155BF3DAB
+:10BA8000129C3B6C28BD46AE5BE24BE243B60F0610
+:10BA9000EF6FF2A51DF297C19B7385F0DAE194F088
+:10BAA0000FD63F8C9B5909C2DBB6DC48453A46F2BB
+:10BAB0000B00CFD515192FA14FE20D95CBD31B7AD3
+:10BAC0005AD400785E9ACCEDFD945C16453FAE9D4D
+:10BAD000CE2915F5F3705FBB14BD93430AD9A14B72
+:10BAE0007425AAC33F6F1176E996C98CECD2B6D201
+:10BAF000AF1D4E2BC478878B897DA672BEC98E4A36
+:10BB0000A9E571881D6E16E8C3F7A6A40636C2F330
+:10BB10006A944394CFB0EBB4D90F0276D069B31CCA
+:10BB2000D9F79B145BBCA1AA40E8DFD301EFE3E2A5
+:10BB3000781FCC0E198C4FC07A28C2F3CA8EA77B0F
+:10BB40006CF8B1C723C207AAACED9769FFECEF2EE2
+:10BB50007C6924EA1BE54A6002E0E3756C82F79297
+:10BB6000F56728ECB1B940F0A5B0EBAAA55DB70820
+:10BB7000EC7920C111D40B86515C692CFAA5E3EB5A
+:10BB8000E3765C20A07FBAA06870388E89F7BAAAE5
+:10BB900012EB0BC7505F98C6CBEBA09CB8686E56F3
+:10BBA000227DE1587123D717A01DF58463BB2B7844
+:10BBB00009CFCDFA02AB28B8045EDA68BD49130A92
+:10BBC000872592BBD7A7457622BFCB7A4A6E332B07
+:10BBD00037F149539EFE4001C535B8DF41CE07E736
+:10BBE000FC21B33E669FEF997C1FC773C5083A37A7
+:10BBF000647929FAA9BE66867CB6D5A5D7609CC0B3
+:10BC0000EE377AA680C727BA73F4266C67A9F9972E
+:10BC100018B74DEED7B979A34D7E4B9B5D28EDA8A3
+:10BC20007DD868B20F551FB70F93332F1CF241D345
+:10BC3000DA82C8F388AF5917A286A310E3A90AE9EC
+:10BC4000519E4CE622FFC9E5DA6397D9AF7B23DF2B
+:10BC50007FBA1AB8DFBD2C4FA57A72C4B99FE248EB
+:10BC6000C25F1316CB48D6DF217B6C01E803C23FCD
+:10BC7000437AD509E1D70AB36617DA7DA9AEA8974A
+:10BC8000E2BE36FF4C4DA6A36F22EC1F35C10BD58B
+:10BC90001AC539ADFE9D1A2DE7D028D1EE83724129
+:10BCA00098FB7B96A2BF07C7AF8E76E7E0BE165023
+:10BCB000033AE3F61E9EB7CB1AEF9BF29076F5FCA3
+:10BCC0003DD28F24F546E9AF82F3A57B04D265AE61
+:10BCD000A2910FC0E60FB2FB7FC2C21F63F713D958
+:10BCE000FD42BF2DC8267A483D4CFA6BDE2FB0EAE4
+:10BCF00063FF09E281FDB614C35106F2BDC5C5B2AA
+:10BD000076C2F8E9FAB2DB705F7EADEC151FEA1B74
+:10BD1000FF5960F3675EE6FEF663D887CEA0BEF6F5
+:10BD2000E21817EADD55CDF5E437B4CB89BF90EFC3
+:10BD300073C985A99678717F6B8B783FC9C0F3A6CC
+:10BD40006ABC3B9A046BAAD2F938972B4F1979FA3F
+:10BD5000C8C25164978CC69205C02E99827689908C
+:10BD60007BC1DFAC7C143B638E937AC15E4933C3E5
+:10BD700021D67185F3238DCDF35C0A6F3B4A4BBC12
+:10BD80006EF447002C4ECE57BE989F3E07FD3BEB0E
+:10BD900035B35E5187F18902D43F158A53C8E7262F
+:10BDA0003FB98AFC9B9C19D1C309F6D5E5850E4B9A
+:10BDB0009C34E667CF65141792E3A8CCDF46728007
+:10BDC000B22AE17126F0C70B781B259FB380D78379
+:10BDD00071DE6D4EC6F30FB89CC8B8835A1CAEC84E
+:10BDE000C6F8F02625601014358750BF5F2DE4C8D3
+:10BDF0002DFC70F678D16A2957CEF5A4A735EEB49C
+:10BE0000C6D1EC7131BB7E2EFDFA2A4C82707F5E6A
+:10BE1000D2090E78E7D078D847EBFC3BC583E4C362
+:10BE2000CA82BBFC98BFD29914D9558FF1EB1E2F53
+:10BE3000F945BAB00BCA4B1FFC457F7B4FF0D12DA3
+:10BE4000F05E77A193DEEB54783ECBA1319FA3FD4A
+:10BE500043F259B7E0B39B0A35EAE7C57D09448848
+:10BE60006572BB56E6AFBC3686EBABEE10CFFF7902
+:10BE70002AF3D0EB65042DCF63C90DC5F358CA0072
+:10BE80003F5304FE7227AC263B764A88E7B14C7ECE
+:10BE9000CE6AB7DE9EEBB2D473ED76ABADBEA750E3
+:10BEA000EC7BB6FC95783C6D11E961127EBB5C7D44
+:10BEB000B595C755BE06762B964FB5FAA8FCD75652
+:10BEC0003F95BDAD1AE969CFB6E672BFBBC0FB5660
+:10BED000D7053A17CF65B9290F42FA29A5BFFC3B10
+:10BEE00085DC0FC5421C9E85624DF39C996918E75D
+:10BEF0003A1AE2FAE160FBCCE20A6B3C6F49D81ACD
+:10BF0000CF5B56638DE77D7AAA7EA010F5AAC9BFE4
+:10BF10007BF551E479117F5A23F0B0E3211E5F9243
+:10BF2000E31FFD02A7BFAC9F1378F83EF207C68F50
+:10BF30000E8A7DF4C1AA5B681FF5E55F965E785CAA
+:10BF4000C867CA469F2B00E357F52D77E3386B7619
+:10BF5000C138A9973FCEE609A3B3ACF1864FDE8185
+:10BF6000EF1F8DC51BEEB903E30D4745BCE1FC7324
+:10BF7000CD5F467BEBA642FD27880747A17E12CB0B
+:10BF8000F308CF28AA0FE0B922EBF0E770C6E8214A
+:10BF9000FDFAE70B13F8F59D739584F6E93B85DC14
+:10BFA0009E86F3EB97F81EF3C6FC6A17789D9F53A5
+:10BFB0006A119FBFFD47AC09C769FF366B7A3681AE
+:10BFC0005EFFC742458EF73B3A0FFDF23C0CFF2166
+:10BFD000D1784E4FD558C4F73917CF83B18FA716F4
+:10BFE000B9E5788E227C2733069F5A641A6F07E0E2
+:10BFF000A01FE9A4FAD2288EC9EEA678A7E4A394DC
+:10C000003ADF7CCC53000393E13E93F2BC6F7E2178
+:10C01000E6D9FD605CE07136385D7F26F8EBBC90B8
+:10C02000B3B751CE409ECEA29C41791AE50C9E0F2B
+:10C03000A09C4179B23540CF7FDC1AA4F247AD3ADB
+:10C0400095275A2BA8FC416B98FA1D6BADA1F2F510
+:10C05000D6083D3F5AFEF55B289EF69442795583FB
+:10C06000C173D757ADF27567D42A5FEB7659E56B8C
+:10C07000CD4E6BBCBCB1DB1A2FAF37ACF1F2552DF6
+:10C08000D678F9CAE69996FE2B9AE65AEACB23B7F8
+:10C090005BFA2FAB596CA9EB455C5F5C125E617972
+:10C0A0006F7145A3A55FCA22164944FF8A22CE9F1D
+:10C0B000074305C30686D877DC2DB7FF04F59458EF
+:10C0C0005D8D30D4EBDD2D0BE8F9D6A4705D38C161
+:10C0D000F875457CBFEB2C5F1D9EC3D0FF7B8BD3D7
+:10C0E000ACFFAC9F16595464B273DD7E6E97BD3BB6
+:10C0F000FEBD17F1985854FECE4BD7E139D5CF028B
+:10C100000AF0950E6A9F1FB6EC22A3CD791DD4AB21
+:10C1100033C18E34ADBBF833FBDA47C3F399EB5F21
+:10C12000983B12CAFCBC485D11DA5115A7DAF1FD43
+:10C130003995792A8ACDD60C467AE9B9096EB27753
+:10C14000EC707FAA48B1C4B3AE749FEE6CB5C6E57F
+:10C1500073FC3CFE95E3E7F12EA853BCEBE9699133
+:10C160004F217CF09CE25E5D596B73703F192C8E01
+:10C17000F490A097F42B48B8769472788E8A78C39E
+:10C18000107E852F168D1A1CEE73220ED1F5254FC9
+:10C19000C2F8CB3911873827E3100F2D4E18873896
+:10C1A000374FF815A01DFD09E776D7F0725EE390D2
+:10C1B0007108B93ED88F1EA4FD27168710FABEF06D
+:10C1C000A3BF3E4DFF5FB88EA63C7D17F67B7F8AEE
+:10C1D000BE1BEB474DF150DF68533CB4FC154B3CA4
+:10C1E000F499FCC83E7C6F226E693064BBC1069234
+:10C1F000C6617C367C4F223EFE9722A967F7FD453B
+:10C20000F15A535CD5F1C1CDECB2E30297DD2FC8F2
+:10C21000F350EC7A4E0A620486E8C6AE70CE3E5900
+:10C22000183988EBEFC8785EE3F9568EF8FE8187FF
+:10C230009F7679F3250B3B15CF2B3CB78E81C4E05D
+:10C240003EB33DA399FC2AFD026FF6F28D22414FC9
+:10C25000E61B89F47DB230FC3AD28F3DD7AB511E3C
+:10C260009B78CE722FCF5E7DC21DFE09EEEF9D73CF
+:10C270009C1ACF1B64E4BF9894EB8BA27E2BF5B085
+:10C280005FE27E49F92803E3DDB0CE76FDC554CCEC
+:10C29000FF7E6B8F8A1930EC2B69CC8570877361B8
+:10C2A0007F8375CCF1476E1C6A5FC4041E4790F80B
+:10C2B0004271F8A91CC14B43C1E7F6FEAFED796F9F
+:10C2C00014EAE55FE9E1F1B0493DABBD0DA6F173BC
+:10C2D000A6F37DA73393C35FA72B512D1BE1B9F0C4
+:10C2E000FD19186FD11CE4EF786BC36F8E2F43FFDD
+:10C2F00063C8199840F577A9DEAF390A307EFD96FC
+:10C30000FFD7C7B1FFA42FAC194DB68EC0C7AA0D79
+:10C31000054F203EEE0B4494E9304F7FE8DDB471C9
+:10C32000A678DA2A858513E93163A673BADDA637C4
+:10C33000DF81FBE66DBA87615E737F9987F0FE95BA
+:10C34000598A86F6EE42E475680FEF51C98F0DF8F1
+:10C35000588FEDAF065218CE3B477F46C5FAFB53C8
+:10C360001476DD10E7F015E335F4EE2894C3B790AA
+:10C37000FF12C0FF4BB96F0A399AA882DCE723FE8F
+:10C380000FA59AFD95929FFEA9501F37BD08FD7F0E
+:10C3900091A630E9B98B2EC1871B093F0BBF1AA5A7
+:10C3A0001884E7B1E6EB5982FB0DAF09F9B03F2FD6
+:10C3B0009CCECFC95F0BB998D4F3DEABB7629C7942
+:10C3C000838BF2116E2A0C4F47786276D755DE3791
+:10C3D00064BE5A7F5021FB0DD4699AA71F245005D3
+:10C3E0007A2529C9014E4FEEA7F38AFD0FFAE9C35A
+:10C3F000A0DF2AD6DB87FE3EA6EA3B9DD07F73B145
+:10C400008BE8BD6CA52B0DE9128F9F052CF686BD20
+:10C410001C1071B3CE562FE56BF47738B99E0F7FA1
+:10C42000401387461EB767C6948775F8E713228FB7
+:10C43000F493C15B1FC67C9AE30E5E6F08DE7AC37D
+:10C44000468C7B8F6D3EBE04E3160F2881360DCBE4
+:10C450007DBB1A30CFA345095440BDAEEFF37E74C7
+:10C460008935747848C73FB56912E989EFFA990FA1
+:10C47000F5C46563B8DC34F6B3A8233B6EE79ECC05
+:10C48000E2F113B463E74DC76D97E3E39F5BFB08ED
+:10C490007E4F0B8F9B0C0FF0B86972BF1A884297C2
+:10C4A0008F6F7B87ECE0B0DFAD219E47301E578950
+:10C4B00064A606300E1AF4F3B84AB27EEFF125F006
+:10C4C000DEF07295E7B70D707BB809FEE2391261B4
+:10C4D0008136DC9F465458EDE4425B7C459E6F1EDE
+:10C4E000FB7315EC5178DE36DD7ACF6330FFBD2C5F
+:10C4F0009F033D02D7F7BC88E77E13F475A4D3B73A
+:10C50000415FC7F200E8EBF8FC7BA0AF63D907FA04
+:10C510003A9607415FC7F210E8EB58BE0CFA3A961C
+:10C5200087415FC7F7FE0FE8EB58BE0AFA3A3E7F35
+:10C530006E16DF473AB3DCD18D8067EF9F808B01A9
+:10C540002F9D2EF663E42FA3CCA3F17C7CDEAF2BD2
+:10C550006322EDF3FD4AE4138CE781688F633DEDC0
+:10C56000C21F7F85F54DD964873055FBE600F4EF97
+:10C57000F87C76600B54BBDDFCBC1F38CA7CA83746
+:10C580009C5EA24C45BDE9CC7CA55701FDA67FBEB3
+:10C5900042FAC44414BDFCF83E5AF29EB61FE76B43
+:10C5A0004F63821FF7F5E8C07FA71126E2D7B43AA0
+:10C5B000B48F677B643DB90EDBEB5B1461A7A6EF1C
+:10C5C00045FEED92FD8DEB7AB07F87AD7ECC21EB01
+:10C5D0004D7BB07E3C365FFD0A1CEF788E6C6FA8F9
+:10C5E000D5E1CC184892F3CD5C89FDFB15D93FAF5E
+:10C5F00007EDE43359B2FFDA15D87E2666473FB619
+:10C6000092DA47F1FE93BE3BE211B49BAFF678EDB0
+:10C6100011BE3FC33EA69BE33A2D25DCBF10F39F1E
+:10C62000EA8AC57F2AFDF68E94DAEB30EEE6D9C8A9
+:10C63000F3B406B20275785E0FE64735F9F9C98F93
+:10C640003ABB24767FC0EA2FD5159E47EF6311CB06
+:10C65000FD369127EFCE34F9ED84AC5F8EFF50C6E6
+:10C660004BA4FFB0461FDA7F5833CBEA3F947912D0
+:10C6700083F90FE57D04E93F0CAFB6FA071746AE24
+:10C68000CC7F58CBFA5C686F315D2179A9F5F5BE96
+:10C69000341AEDFAB31AF90F9976381ABB7FA0D184
+:10C6A000309A633ADE23E3F5D3772B7EB41FB6DCF2
+:10C6B000AD8CC6F2E4DDCAF5284767EF567C2857F3
+:10C6C000BF98C1EFB7149D0F1CD6705FF53B021CDD
+:10C6D0001DE12FE03E1C5E9DA16D41BADEAD0CC791
+:10C6E000FE2B3F93E1C6F303F44B21371F3C8C7CB8
+:10C6F000E54C512CF5C2B1924FF73C8C72317B84E2
+:10C70000E4C3C57BB05EE696EF7F710FCAC9F288BD
+:10C7100022FADFBB07E5F0F81CD97F782DF65F32EF
+:10C720004E8EB7770F8E3F3B45D61FA4F6EED878D6
+:10C730005FA3F97E882721D5B7EDD1C7C37C55E229
+:10C74000DC323E46E377D6CAF7EFE92983F1568813
+:10C75000738A191F2739273F33BD0F7A3AD4FF5DFB
+:10C76000EC030D337EBF02E5E68E58FBEF69BDB5E5
+:10C77000A2BE7AC6937B30DFECEF7E7D7FE5F9ECDD
+:10C78000F595AC7FDE758571B9B09F8BCB8BF9BE0B
+:10C79000126C7A068F2756DBBCCF89F2887E001197
+:10C7A0007FAA0E237F7B9D943717F687C9EF691FF9
+:10C7B000E7FD195CCFFECC0C6B3CADD3164F0B6381
+:10C7C0003C2D7BF071EA8AF938DD7312DBB34F4FF1
+:10C7D0009BD33A63545C3F4055D00D6529940E2895
+:10C7E000FF3425B26946115EE6E1FE16E9BF5E2020
+:10C7F000F288DB4ABF1C9E83F7928A5D01E1FEEE60
+:10C8000037C777D56DDCFFBF62CE05CA0B5BD3E9B6
+:10C81000D1F6631E4B87C85373A652FC41BDC1BD00
+:10C820008FF679113F8D60BE710ECE33F4BD0DFBD6
+:10C83000FD1943ACF7DDD01617EEDB35E56A9F5BDB
+:10C84000C48F79BE9835BE2CE3C56579E329AEDC8B
+:10C8500098E9A5BCE22ACC0F41D910F1EE3AD1BF3C
+:10C86000B1E58530E2BD7EA793A11E78A5F1E5FA7A
+:10C87000B091F539787F41791AD7E76CF1E69A865D
+:10C88000277517B41F055C8FC00E225E2EEF85C47E
+:10C89000EE1F883874443C5F1ADBFF2BD371FFF422
+:10C8A00074811D86EF8B38B38C4757D9CE81FAD06F
+:10C8B000DC74F2D70654B21FD54BDCB3CE29E1F9B4
+:10C8C00068321E7D7886351EBDD5C5FD7FDD3956A3
+:10C8D0007E2B29E1F6EC2471EE1E2C4DEE4B42FD31
+:10C8E0009A79C9CED882FE9A61DCDE40FF84DD6F82
+:10C8F000A3B6AC20FF22B62BC07F4AEECBBFC7FB4E
+:10C900006A582F81FE2ADE578175A8A90EBAAF2971
+:10C91000FD3BA886CCCB273FCF49E463B5A58EC6A7
+:10C9200091F7D307F3F3FC6C86D40F7A5DD86F854B
+:10C93000FFE51338DF5FECE7117696EC1FD6789EA3
+:10C94000CBF0199A8C5BBAF8FD3DE65A3485FC2190
+:10C95000EFA17CB2C9BD1AC221F7A345C5CFAEC0B5
+:10C96000FD88E9A3D819D3BD08FBBE20F78BD87C7E
+:10C970007EFE7EDDB7BEBBC2183978BC2227148B81
+:10C980002FA8419C7FA48C2FE82EACC7CF595850BC
+:10C99000D072CED636FD37386763FABD31B616DBB6
+:10C9A0003F6AF0035FCD0E52BE14F7B37DD4E07F33
+:10C9B000A5485F8A7C78ADE7F956517835CEB359F2
+:10C9C000D16B52793030A00C1D17BC0BFBDBE3821E
+:10C9D00097F257FCC33F31B47FE24B416B1CFFC35E
+:10C9E000E29FF867C029EE93204F4F923C85B83CF8
+:10C9F000FDBDEF7FB0DE57B85CF44693C75D7DFFA9
+:10CA0000C09385916388CF895A6A3D9EE3308F86B3
+:10CA1000F217F37B20DC418BDF634FD335F07BC013
+:10CA20003ACF125DCB395DFF0EE8F65F749EEB5C8A
+:10CA30009FF83BE4CBEB8B915EBD7C7D7F83F93F20
+:10CA400046F33FC5F9258E1FAE2799F053DBF4B7A7
+:10CA5000C14F29C1F74D0EDF47809ED5046F80C3BB
+:10CA60007B29FBFBCE193C7E02EFADA0F70A391FF4
+:10CA7000DC85FA35B7CBE762BE80B4CB33F2F45530
+:10CA8000D80FF4DC7A3E4F4CCF6D281E35A4DDBCA8
+:10CA9000B67868BB797DF147C86EDE2DF0168FCF72
+:10CAA00044E93E1C9CE41447AE137DB7B42CBEEDA4
+:10CAB0002680FB37807FAC7B703D4ED37AB254B278
+:10CAC0009FEDF7D48E883C08B92ED5593B0CF5085C
+:10CAD00089CF23E99A1BEF4335E84A272603CE3551
+:10CAE000DEA175BB750FE91F37FA7D9D187F5DAC20
+:10CAF000F3F5BB9B7C74EF45DE7393F74E1AFAC6D1
+:10CB0000BCEC86F7B680FD3206C65F586EBD876204
+:10CB1000D72F545BBDE5C7D9DB0F99FA3F566CCBD5
+:10CB20001F743E5541F94386427A1713F9840D620A
+:10CB30008CB6D23B92FD5C8FD3100F73773ED08FB3
+:10CB40007133B7E1A4EF30FDB655DB7E08442A69A6
+:10CB5000F3BBB4BEDFC0FAC8C8ADE4F1FA4611AF0A
+:10CB600067363F8527F9E72EF44F4B3C26DDCFF3A0
+:10CB70003CDCC153E574AFB1764D7F11EF4BFE073E
+:10CB80009543C6E47735AAC438553ACFAB5CEA770B
+:10CB900058F284EC7E0C95A9B6BCF881974620BF6C
+:10CBA000015EBF8CEC91CBFD10C94CA7EF7024B790
+:10CBB0002D1ED687DDCA5D96EFA12C0CDDCBCCF601
+:10CBC00072B28D2F3D367F839D2FEDF4F8818D1E3F
+:10CBD0008FAB5C2FED3CE6247F79E783ABBBD17F45
+:10CBE0006E3CE8207FC65999070240A23F7F198B0F
+:10CBF000E197F4E5CEE68C28FAE1255D96EDE4F9BF
+:10CC000021D4CBE477672C9399BFCFB14CF817EEC2
+:10CC100060BD74BF61251B70A11CAC4257BA13FDE7
+:10CC2000E21A958DCCD8C4087F91EE6C98EFF1E6AE
+:10CC30001101F46BF75DEFCA783B97DB1189F4D7EC
+:10CC4000785C56656F9BFCFCFFF06B5DAE5FCB695B
+:10CC5000D0F7FDFCEE287EDFEF527EAD97453C42DB
+:10CC6000FAB5CEEEE4DFD5E817F72AFA5DDAD89DFB
+:10CC7000A9D84FE3DFCBE85E761BC2FBDAE6577C30
+:10CC800003B44FB20DA387FE0EC4D4920476E1F72D
+:10CC900067309E17973D9085F999275DD6BC5B5903
+:10CCA000CE0FB9C5BDECC88C12935ECC7CB13CCD27
+:10CCB000E212F257F1FBD9D2CFB4B620528ACF6735
+:10CCC0005D60640F7A2A95A882F919A9CA4B8A1661
+:10CCD0009F9FD9F3E5FF1107E3DFB712F8E94FE2B1
+:10CCE00079B3FDD9ACE6D904F4C99EC5CFCFFEBC5B
+:10CCF000C4F493EDA097DC83F443BB299D33CBCFE1
+:10CD0000DD43FB133E5B9220CF58D2F7C9D9FA7DA1
+:10CD10009CEEBC9E941FF902D6DB23E19FD0F7EB7B
+:10CD2000B639B536C47F9F762488F2F945A70FE35C
+:10CD3000DDD73ABE377C46F665C5F77E81F81D45DE
+:10CD40007C2FF4C67FAA433D708BB4CB84DEB862DF
+:10CD5000B8A90E5B71C931DEFF1B25D3F71AEAE0D3
+:10CD60007AE6FA0377F4A01E29F54CA8AFC4BA7C82
+:10CD70009FB1DBC796815EDBD824E388B7EF453DE2
+:10CD8000373EDF92BDA8079F7559C7977AEA2B25D2
+:10CD9000E57B71BC706CFEF2BD08FF800D7EFADE93
+:10CDA00024D4DF28D1F7A2DE5BCF64BB4EF901713A
+:10CDB0007FE27AB25B8FBB65FB27285F607B361F03
+:10CDC000FFD503EB7BF03B691F3678AEF5F857DAF9
+:10CDD0007F307DFFA48BE7071AA09F615E4890F526
+:10CDE0003AB9F0E96E27F07F89AED07EF4EB109768
+:10CDF000D770AA43CCD3D2437C512AF11AA53C8FD9
+:10CE0000C1F8EECE03DF7818D71D87FB1B2B900EE1
+:10CE100031B88DF575E81792701FC5FE30DE8A7B3C
+:10CE2000EEF4239C2B627E8DB61EECD79921EB93FA
+:10CE3000F6627DB0795786B6F5E0BC2B62F8798052
+:10CE4000DE5F912CDFDF65CD4F317A565AE15A6DA6
+:10CE5000C1E7F70EF4F4205C615F74D368F2073227
+:10CE6000FAFEE71D4D6D94BF1D97A3AD592447FEF3
+:10CE700058BDC72A479F26B8AF365CB09FFA67E215
+:10CE8000F995CBEDC3ABBF6ED82771DDDB145AB774
+:10CE9000E4A35A9F89DFE19C6BD464FD9EBAA6C9C6
+:10CEA00057635E6EE7867FCEE8FC93F2C48C884DB4
+:10CEB0007E2E6FBCF6D41CCA9F00FB4A4F946F7D38
+:10CEC000D70C45FA31E7103E83D26E6652EFB86553
+:10CED000E62893DEA1C5F48E0AEA6FD33B3A451EDD
+:10CEE00055A7B86FA2438BDF94E7337E168FD3B676
+:10CEF0008B3CCDC28DE1B5663BFB89D91C9EC766D4
+:10CF0000733994DFAB3DD3A4501E58FBB611E9989A
+:10CF10003F7B2AD3B700CFB5FE6C4700AF2E9F14DE
+:10CF2000DFCBECFFBC27EB33F0FC44762AD9A927F2
+:10CF30003276A6E13D855301A738679E7B8BFC5D69
+:10CF4000717FA281E78AF417AE9ED94EFEBF3735B6
+:10CF50005E0FCC7EFE2D8AB7E5DAEF7186488F71C1
+:10CF6000DF22BED32BBEB729F5A5AA4D8F7E896CD3
+:10CF700060A1BFC8F3D37EAF13FFB8CCFA57879335
+:10CF8000EB5F7EDECFCF06DA3E30E9DDDE41BEF379
+:10CF90005A23EF11DAF429BB7ECCC4774DA57E9ECF
+:10CFA0003CB281FCFAC94DD67EA73A5EAC0CC2FAFF
+:10CFB000BA024ECAB3BA3DD7AA474B3DECB68E472C
+:10CFC000C90E05BDD0D22EF36B6F67BD1D74FF5B1C
+:10CFD0003B7CC8393A6E77B4FBAA484F69C8851ABA
+:10CFE000ACE7F8FF284B2B42FD609B13BFF0CA73E0
+:10CFF000EB4DEB807E2EC748DAA7038A62CE076A24
+:10D000007B04E5229E0FC4EB713FFC7D8FE07E1018
+:10D01000F317B37B5659FC9BC632EA1FF38719619D
+:10D020006A3FA30AFF97B1EA11DCCFE2FEB11FF617
+:10D0300058FC6346E523C84F32BECA8CFB29AF6F4C
+:10D04000A94FC2F3A31EACB7EBFC3CF9E6773C2733
+:10D05000F17B4057DA1FE4F379944316E6FB9DBD5C
+:10D06000BDE458B43D5DE875F83D0ABB9C27857862
+:10D070007E5DB99ED7314AE37E2B0FD0475FE95CD6
+:10D0800089FC1ACF5329A6EFA2350E9257322FC42E
+:10D09000E5F7F0CC548B3D6ECF4F691471E8C1C6F3
+:10D0A000A92FE571F67EC557CDCF6527C373B9ECBF
+:10D0B0008171A9783D55F62B2DE5FBC19FA6E8C7E8
+:10D0C00071FD763FDA59F4A3A1AC0A7FC722C13BB8
+:10D0D000EA4EEB774BCE64F0EF962CDA26BE935EE9
+:10D0E000F197F9CDCECFB4DEAB1F2CFFA1B894EFF2
+:10D0F0006379A55727FFE189645D477C9D83BEE87E
+:10D1000017BC281F42E439C83C08772887E76D30F0
+:10D110009E0FD16EF0EFF15DF57B2CD22E290CA77E
+:10D1200084F05CA8E1E788E4B3BE991AE7BFF30195
+:10D13000E23FC977D03F23847C5DCDFB979CE7DF3E
+:10D14000B790FA45D281933D6DE3E91CBA2E643E57
+:10D15000875263F71EC784129C4347E7EA37F0E71C
+:10D1600086C86788DC182A4AF87E762881FD3C79D3
+:10D170006A783C3D8FDDD7D42784FE91FF00D3260B
+:10D18000CE3B691C24EF44EA85F5DFFBE94A03FA4C
+:10D190007D30475F1032D9AD31FD7280EB3B31BD40
+:10D1A000D2984AFBE235D01B57854C7935D760FCC5
+:10D1B000BB88EF265BF528B4FFCDCF3F6C761CC053
+:10D1C000B791F022E2267FC6FB5B42A678CD5F01D5
+:10D1D000DE5D2193FEFF21C4E75384CF0F2F7C7DBA
+:10D1E000045F25A7F7CC99313E7D31311F5C36FFB6
+:10D1F000FFDF90296E6E1AF7083DAF1C3A2E07FD2F
+:10D20000DEB0F68BBDFF03F3B843BCFFEF047FAC89
+:10D210005FECFD93F45CF0E75590F3F366FA5E8300
+:10D220007DE43D5AEF783EFEE992D83A7E6B7EFE71
+:10D230000F7FD925F93C6B16E2AB99F3D365E8D99A
+:10D24000E366F1FC9608F7D31A52AF99289E0FE0D7
+:10D25000BDD105C8D7A3E85EDE4D38BECEB89D1B54
+:10D26000B34B8CDD7BAD76090C34D972DEEF35DB48
+:10D270001DFAAC7D7B115EE75CDEBFE8BBE9AB70FD
+:10D28000FDF63AE825336659F3328338FFA5C6C563
+:10D29000F83FBD678BFF9BDAE7CCB2E42F703D16F9
+:10D2A0008E70AF0768FCC35AE7C806A857CEE27A6B
+:10D2B0002CE82109EF6F57CE8AF9132A693E918F26
+:10D2C000712CECA47B80317D8579C9AE8AE953C687
+:10D2D000D7C84F14D7A7FE85F8A954D077D5777B48
+:10D2E000EB049CCBF8FAC53A2EDD7F25F5F7F3FE6B
+:10D2F00009DAEBA93D93C3C9520F9F755AE2156C29
+:10D30000BC6374FC7740CA5C4B668D047DE56007A6
+:10D310008F47D5770BFA1ADFDA6BB513B9FC2D17E7
+:10D32000FCDEFADDBE3AE4FFE5EF49789D7CFD3195
+:10D330007F5F1FADFF4DE19748FB5E9F84EFB30415
+:10D340009FC6E1BB06E3B711DD19C74F0D335CA3E0
+:10D3500087C8B3D82CE80FEF75D37B5E0E574D44CA
+:10D3600071F1B8CB2917F279DD3196D0DFB473961D
+:10D370005BBEBF93DE4F15F66C20F1BDDD87E2F199
+:10D380009387A8BF8FCFE780F31FEBA1C8D1B94027
+:10D390001EFCDE1CD935E17255C7EF2C84831716AD
+:10D3A00031D377E5641CBCECFEF1BD680F269727EE
+:10D3B00071BBD16BFD7D0ACFDCFB721FD4485AE9EB
+:10D3C0003BB54B041354316B5C34419CCBE27791F9
+:10D3D000FE9125B1B85426D9B9EEADFCF7A158B5E8
+:10D3E000358E99DCC2C8CFB5C050A21A8CEFD1AD32
+:10D3F000FE96C8066D3BFABB54D515D0B58BE39AA3
+:10D40000F6DFB998ED657A7A3EE5A37C6FD6A87809
+:10D410001ECAE9EE71A92887763BFAF4607674B7E4
+:10D42000D58EEE9776B47E75ECE8A3B3AC76F4DED9
+:10D4300082F01BC4EFAA4EFBDBC1D29245685FBCF1
+:10D440002BF228061E54D3110FC6367E6FE1948846
+:10D45000F3CB78FF40314BC5DF3B1868F3103E0734
+:10D46000D6644453E0BD74635D25FECE81B4A7113C
+:10D47000F3E80793DF27B6DBDDC941A0E7341233B9
+:10D48000B2B7077C3EBACFBCB0437C4742E40B48FE
+:10D490007B5BDE7B6F2CE7F7A7D17367FE7D8B8507
+:10D4A000C21E977679DFBF31C59C07B08805289FDB
+:10D4B000A09A85A95C2ABE9F58E3639B10A8F7A792
+:10D4C000447E47FCBF87F309DBAED2EF570D6C7B80
+:10D4D000807E1F6AB0FB0C6AA9BCCF60509CF61A14
+:10D4E000D8FB49A5A6FDE332F69B61D45FE572DC6B
+:10D4F00086F77C47C5BF1FD12FFCC2DB33B83F6521
+:10D500007C29F737D94BF97D882B3D3FE0FCBCB136
+:10D51000D46AD76BA597777E4EA4F7C4F7294663E4
+:10D520003C88EF4B379572BD404B27BF0A6CD14307
+:10D53000E703044A8788EBB24BE713044B13E41369
+:10D54000FC42E8236B0B22B370FC591718F1AD3D78
+:10D55000EE2FFB1D473F5582FDB659F8DBCA8045CB
+:10D560001DF917DFDBFF61AB7E1275BCE3AD15540F
+:10D570009E508D34CCDF3A22EEEDC30894CF24F3D5
+:10D58000A2E4B835B56527CF9AF6AB85F31EA33C68
+:10D59000B3F6DCFD871580F394C8F7EA4FF36D47C7
+:10D5A000BFB371947F476A69F5AD27CF9AF60F3BF9
+:10D5B000BC98176580A8DF59CABF5FF76299A76F4B
+:10D5C00036C8E1EA6D5C0E576F3BE5427F665D4B06
+:10D5D0003D8B4CA1BC2915E97B6C26FFCEC2C2A0B5
+:10D5E000931926B832F2F486528A7B845713BDE32E
+:10D5F00079816BB05EE6D2D331AF5DFA2965DCA0EC
+:10D60000B4F467A43FF767309A3FEC67518CBFCF03
+:10D61000D5B3DD03187FF1FBC8AF5A57AAF1DFABD2
+:10D62000EBD847F02487DE2178CA54C0F7F08BF19D
+:10D630002DE5A253E0DBB46EC2F760F2BB709E9A98
+:10D6400086F83D82F4827E9BC43EF09A7A21D5977B
+:10D6500080EEB1F78265167C7BFC1516BAB5EBE35C
+:10D66000D2713D92CEF5A2ED7487F3FB48C7F73037
+:10D67000AF8DE898381FE228D26B12B497727FB44E
+:10D68000A4579DC1E9556794713C056F758FA178CA
+:10D6900080D28BF7251BCBEB19DA0B6E3D83BEFFD7
+:10D6A0002FE9B7A81CE8678217E4F1E15293DEF98D
+:10D6B00067F8D91F2D35E9C1D73A0E00F33D43F382
+:10D6C000D9F372FF4A71888BBFDBC3F7DD3705BF23
+:10D6D000D84BB9EF0E9ADF6C54AE6AFA33E0907211
+:10D6E0008372DBA660FEA4E2423E0BA3FC4E417DAA
+:10D6F000EE3F36615CB4C1CF7A712F7C08E508F04B
+:10D70000E6AEC870A3FCD47767135FA0FD4FF81492
+:10D71000FBF44BA54C9E5327E97913E78BBF75FCAF
+:10D7200007E0B940F0D48AFB051FB2F854564558BB
+:10D730009D8DFE597D1F9D2F7D33E5F79A5816F775
+:10D74000935F593CD4A3F3FC3119174D1007D594BE
+:10D750003F230E6A8FAF0E16174D1007B5E8EB8307
+:10D76000C541992D5E6A8F83DED63182E2D0B765DE
+:10D770003A28FF51EAFD32FEF96AC7D7E97B47AF85
+:10D780004E565846F6C571D26DC23FC650AB33AD4A
+:10D79000FF4416FFDEF596315EFA8E28FE719AF28E
+:10D7A000F1E07CF07A60DE8E794ED24BABB2F7DBE3
+:10D7B000F1EA1676C965E155C6D9DD1D3CCEEEF11C
+:10D7C00033FA3D4D49C7F8F7749FA7DF8B642ACF22
+:10D7D000D3ABCFF5515EAB9D0E9E8EB67BE9779CA9
+:10D7E0007CD3D75129E8EFF15F9C3FA84AF812E4B7
+:10D7F0000FFED9F4BC041DDDCE0D5E14B98BE8A973
+:10D800001D4CC5EF8ADF1670FA342D4E4749D78B71
+:10D81000E9E7A3FD45C6B96F2A0CDF857223BFD3A4
+:10D8200024E97B228BE3F7CC4D2C2ABF4F66A62739
+:10D83000E05FA77B77B96C1FE11FF330A75ECC17C1
+:10D840009E5C837EC7D39D5CE927B992F8D50E1004
+:10D850005DDA9B7D0B507F3A5AEEA2BC9504FC40EA
+:10D86000BF5B7B297EB888EEDBF8EF845E29FDEE96
+:10D87000287E5CCF4EC01FD790AE15C14474C57CC6
+:10D8800086BF80AE278AF4C791AE929E3715EA5FB5
+:10D89000995D64965F83DB312CF1F76D9E16792DCF
+:10D8A00030CEBFE27BBD686391FF50EFC5FAE21B4B
+:10D8B0005973A2EF823D5BC6CFDD5AD6FBD268B466
+:10D8C000FBCE3291B71938ACA19FA6655CC2BCCD26
+:10D8D000E3F86121E8BFD0CFF639C4FEEA30E16950
+:10D8E00040E46FBE89F99B60E7BE3C3B9BD6B10527
+:10D8F000F338E1F92991E7598B63E33CA0CF627CCF
+:10D900009EA91186F7D3FB63DF6769A373379E8FE8
+:10D91000F1EB47ACDF67E1F58599B23D356A898364
+:10D92000327F04EDB6B8FD35356A39EF5830628D77
+:10D9300083F27C1D79BE6DD4E7440C731C9455D0E2
+:10D94000F8276B65FF1DD1B2C9E638E8E2A86E8EF4
+:10D95000731AF3A3E638279CAF54977EE8C7FBEE13
+:10D960008FA05E3F796AE43CD25FDE9B870348C7A5
+:10D97000DF9D73FB7DFBD10E07FB00AFE40FAA57C1
+:10D980007FD8CBFF0F02C2B069008000000000000A
+:10D990001F8B080000000000000BE53C0D7454D5FF
+:10D9A00099F7CD7BF393644226017480A02F01DCAC
+:10D9B0005843187E020109BCF9C94F157480A0B103
+:10D9C000207D842CA55D5A83959676EDE6416248CC
+:10D9D0008240E8D2EDCFE9CF88D03DAEEE69E87164
+:10D9E0002991D20E6229964A634B8EB14B75B0597C
+:10D9F000165BDBA295DAEEF194FDBEEFDE3BF3663B
+:10DA0000323128B4C7EE8EC77373DFBDF7BBDFF7C3
+:10DA1000DDEFFFDDC79DC58CB105F03FF3C60C8D72
+:10DA2000B18110FC3911FB7ED380B1955364BF22C4
+:10DA3000669433B6384FF6AB4C6321639D2EB99E86
+:10DA4000590CE6BFC09CD4DF66844C6B2A63C16569
+:10DA5000AA985F4FF05F5A2DE7EF8E0501DE2A8707
+:10DA6000E85B2B628697B10F31D95F4AFDD5C97E3D
+:10DA700094FAF732BEFF81F84ED382F58FCD894EEE
+:10DA800034C6C3B348AF1E9DFEB787FF3945E233A6
+:10DA9000C5C4F1F73BBEC0EF7AA312C1737EFF0D80
+:10DAA000E0BB86E4E330C7F77D88DFFDC4CF2738CD
+:10DAB0007EEF037CDA099F5EC027FF2FBFDF0F2BAD
+:10DAC0008D3DB8DF5F808EAFD1B997733AAE60FEFF
+:10DAD000A34477809F43E6F8C4A08F311C9FC3E125
+:10DAE000BDE8147264359B28F709D9C77383FE8299
+:10DAF0003372BFCD7A50B3E3BF99F46455119FFFE1
+:10DB0000EBF8A74DAB38D5879F81E72ED7FF06C727
+:10DB1000D3D67F8AD67767ECE712E3CAB1AD846FBC
+:10DB20008A5E8BE6F767CC6F14F4151CEB8C5936C4
+:10DB30007E306B3BF1276997AC9D6497065CB2BF62
+:10DB400083F4665709873FE1D8CE18E20FFC3B45C6
+:10DB5000FC9ECAF9F7FF9D1FBF3584BC94717E48B7
+:10DB6000397C6C8EF13B94B3F71BBE707E6A707C7F
+:10DB70004AFEFF0AFB15D27E429FDEEDFAA43E0A62
+:10DB8000BFCF9624F93B2908CF2784741AAFDA70E7
+:10DB9000307C3DFCB9BAE511D544B830878D632C93
+:10DBA0009A60B16DB0E7AD2CA632F061D180C97C2E
+:10DBB000E536BD665F243C5C5E87E87F83ECDFAAC8
+:10DBC00045E25CD8600CE38B14DEDEB5784E49BCD0
+:10DBD000D9D7D2F05E78CCFB88A03B10B4E9C9B5A8
+:10DBE00086EF0F015F6CF150B22FF8B3EA135F9E1E
+:10DBF0008C7C58552AE17E3386705E2C94700FD24F
+:10DC0000BEAB92FB7C8FF773E5FC1FD1FC145E0367
+:10DC1000661A5ED6CF28EE92783D766C80CECBE544
+:10DC20008B3D74DD1C689B958005E7F1A10D5B556C
+:10DC3000D36E1758AF1E04FF760F4BF649AE5276DF
+:10DC4000A097F6BDD6786D0A0AFE083D4DE29960B0
+:10DC5000018BD9F13BCCCFE71AEF6FB30BF7A3DC05
+:10DC60005E7BBEC79DD7DBF82EF560B52FA9DF061A
+:10DC7000F300DF7509E707E606EFD5EF0B72BED3B9
+:10DC80006E4FAE9E8EFE1AA2E3357E2E29FBF31355
+:10DC900033DDFE5C317E8F046DFEFCDDAEFFB760D0
+:10DCA000BA9ED9ECCFE348779BD7E1423E9B7E6694
+:10DCB000C400DE65FC2D4EB513420AD9A7A47E56DA
+:10DCC000F1F52B76B396DE2CF3AF0F39685EDB539C
+:10DCD0006C432FC00DBA2E36476DF3E2413E7E34C1
+:10DCE000A8500BF41D25FE6FE1F89D0AEAB45F9081
+:10DCF00069CC009D6A5831B918F16BFB398707E987
+:10DD0000125B9E9F827741C093FB1C5B96DF18F3EA
+:10DD1000A6C69F15FB9C0A723AD0FF133F1FE474FE
+:10DD2000A8051BFD085FCD5384FEFC9AF8DAE114C8
+:10DD30007DEB0DF26B03493BF43B92F7956E29970F
+:10DD40006F91FECB78FD8DE0FFC4AC85883F638E7C
+:10DD500059F675BF253B38DABA84F417EDE2BCAC4E
+:10DD6000E4799D43BC475BAF869516E29387C51562
+:10DD7000F01F2EBF6F5F3790525E61BC8A7C3E31D0
+:10DD8000D3F815B6A3C1013E5DA47379203D1FB140
+:10DD90008DBF194CCB072E6E8C221CD8D90DE7F6FF
+:10DDA000C26A755C13F0EDCF783E95941FD4DBCF3B
+:10DDB00045B67F4E9DCB9F8369F17C38BF12F488B6
+:10DDC0004D7004A6E9C3D779438A9433714EDA23A0
+:10DDD00048474752DF787F57211FCF79DAB956E895
+:10DDE000535E08F77952F097F9C6E17EACFC645CAB
+:10DDF0009D0BFE95257F8603FA6BF12FD87F207C43
+:10DE0000CE8972B0A65DB9323DE914F01F4E9EDF97
+:10DE100084D078826BB2B9C27FC06FE0235B096E99
+:10DE20006333C0CDA22F53429C7F5342493E4D21C4
+:10DE3000FC0D0ED731273A0DE1C254E69E9582BF04
+:10DE400046E01D74468F5E0F72D061293ADA557331
+:10DE5000CBDACE12E4ABE60C4C83E626E414ACEB52
+:10DE6000F0977AD1CF3D27F643782E3847F425FE38
+:10DE7000229AC73468E7D66F3A0EE0D8DBD3CD4A92
+:10DE8000C4A32ABA278C642D683C781CDB3BC04CA9
+:10DE9000639CB275D157A221D8A77FBE3380A2065A
+:10DEA000D159FF54C0AB41E0A51975AFB2319045CF
+:10DEB000B958203E07FDBA37B00D9E37347F64094C
+:10DEC000AB803951E750C283C498EC7229C2D58621
+:10DED00012659C6797C1C62DDBE24CF511371CF724
+:10DEE000A4C657DCC8EDD3AA10F0D32677DF17F409
+:10DEF0007D5FF07337E0D05F4E00F219EA0DDBE092
+:10DF000040FE991E8E67BFB5E2B69B81E04B652C43
+:10DF100080A36EA44F4DD19798AC05DC3A898B77DE
+:10DF2000E975B0AF38D7D3AD60EBFE0EC05A9C4E4A
+:10DF30004D5D5D10B7C9F1E931260B60DC56663DD9
+:10DF4000C4404EC2E61E6702F0B8B1F9F50D18F7ED
+:10DF5000AD31DD7A1DA078CF065F0DC6B52B4CC163
+:10DF60009725CE57906E0FFC877C71C55FFD810BA6
+:10DF7000F9BC50611300FE9D113E2EF9E266DA2BCA
+:10DF800076BE6819FD2D674B763D639B7F5F287FCA
+:10DF9000DCF95BE08FD96CF665A093A9DEA588CF8C
+:10DFA000A576C5A796D03407033A5D823F07DA37D6
+:10DFB0003D877ABAC6AF051CC887258CF8D728F6E6
+:10DFC00078AB55DFF50CC4AAE12D7B7A4A00CE3D33
+:10DFD000675486FCEA587D0021E1CF83F034211795
+:10DFE0008EBCAFF66B304FFBACCA703FC947E0B791
+:10DFF0006F2E3C3F3700EB61EA3D55C027D8F70E46
+:10E00000C3ADEB302F77E1EBEDC8A75CD6121F0B49
+:10E01000FDBBFC0E16F7A4E802BA2DC117C7658533
+:10E02000F6D235B9AF236D9CF892FB99306368BB8B
+:10E030002DA37F2ACC5B26E5B61DCE13CE6199C1F8
+:10E04000CF439E2B8B707995E7929B21AFEE2A6789
+:10E050004A3EB3C86BE639C432CEE180C6F52471BE
+:10E0600046A5B822B1571B53057D6BAF83F418F258
+:10E07000B4C34A01FC11579806FCBF5BE04B3FE07C
+:10E08000DB8196C2587749EA3CEE2E3BF127A58208
+:10E09000F159D7A5EC11C32416FA7789DEDD5FB2FA
+:10E0A0008A507E3FC47A9DA8D7F762C60CF87C9848
+:10E0B000F95CD86F62016AE1BC5DC8AF037B9FCE9B
+:10E0C000473B129FE82C3C5F46AAC2EC7632B34530
+:10E0D0004E9C9774C3E4B8B49F1ED34F76D90B2DD2
+:10E0E000D9698361BFB026E231B3F891F86CF38748
+:10E0F0006807655FF3B530C4E3EBB3A3CF72BBCB66
+:10E10000D74FAD307E84FD83B38C53D87E13E33D6F
+:10E11000F00F17430F525EF2F674E334DAB54C3B5E
+:10E12000760EED989E9287E519F220EDD820DA312F
+:10E13000185A8EFA0A7C63F55767C7CE4939F8003A
+:10E14000FB00F207E8F925D97F0DE801BEBC84E7A2
+:10E150003E8361F52DCE8A884CDD07F829023F7C8D
+:10E16000AE807D57B6FCF04FCA18DE5F00F3147125
+:10E17000AE9846D6A0DFF87AC0E39982F6C21C4476
+:10E18000BA33F9028ED9497999FFC420CA8D23EF99
+:10E19000BB93CD2C7E3079AE1B9DAF25E9423D82ED
+:10E1A000481EE95098E9B88CF4F8008909EF241763
+:10E1B00016C941C75285E8EB28618D68CFDB7168CD
+:10E1C0003E63DB972ABDF8FCF170118F97A6F2B879
+:10E1D000707B618B3F00F3B63B613EDAF33293AD67
+:10E1E000989E82FB7858A5F937CF31F2D07141DC87
+:10E1F00047F1928C57E53C5F98C79563C33CCE28A6
+:10E20000AF881685719F7126F11DE2A8B1D4F7C6BB
+:10E21000638EEB445D84FF74872D8E1898D4C2D032
+:10E22000BFBB0DEEDF33E9BC219CF4EB3710BCBD66
+:10E23000D2AF1B37227E8BC7FA1AD0CEB900EF7D42
+:10E2400025297F7D68E9E754D896DD122E21FCAAA6
+:10E250009AF7B45D07E71D0C4EF1A27B8F57B7F814
+:10E26000D1EF6D9FC0F996B9EF9630F783736E10BA
+:10E27000F304BFA4DFF740F8ED847D30CD77601C58
+:10E2800050CCE3807BC3A5B44EC60330DF72C1BC63
+:10E29000E04DA0A718374FE37032F7BB57F033E5D6
+:10E2A0006F030568AF196B217F1115FEE48556E3F6
+:10E2B000A52110CA81D67A6AC1FEF747C0C00D6A8F
+:10E2C000567E200B1D77D63CE041386DC54D1EF4BF
+:10E2D0009F1D4698E036AE0EBE3464B3B7DB8BD9D3
+:10E2E00064C4EFAE860FBE3464D3B7FE7C8E2FFAC3
+:10E2F00019CB9D82BB12E504F03D1E74C717034382
+:10E30000DD7E16739750EBD4314F0CEB341E35D6AF
+:10E310003213F3F1AA731AD5BF0A5972FE5638DACE
+:10E32000703123BF1EF5B7305CE7863ECE8F2E7C62
+:10E330009DE6DF59A532CB8627D89F35145065C49A
+:10E340004BBB51C0006EC77C25B60DF068F0AF27FF
+:10E35000FFB375512E3D877D09BF3BA63593DF92F4
+:10E36000F15547241220FF7495F1547C76F47EC455
+:10E37000CBE54FDAD507485E5376757398DBD54FFA
+:10E38000E173693FF61D7F81ECC77685CBE176E0CE
+:10E39000F7B7B3C8C756A107DB0BB3CBCF9785BC84
+:10E3A000BE3D3DDA86F00DF069FE59EF3DDEEC90A2
+:10E3B000F1A6E0E3D5F207F8F12F619B5D067E7CC4
+:10E3C000313C7E381FE0D78EF64295D6E2094543B0
+:10E3D000F9CF11DD47981943381ED64293546F94F4
+:10E3E000A1BF1B0E27CE70DD2A41DFBBB5C7DF8280
+:10E3F000F086DB35E38930E5853AB7A3C22E33D604
+:10E4000023FCEE7BB3DB671C604FB1DE8D8F6CF3BA
+:10E410008F8A73EEAB348F229D37E9DEB5782E5D9F
+:10E420008AE1F74EC1BAA7D9887ACACA668DB2CF37
+:10E43000568233506A6E88929D5F3ECAFC6D625F61
+:10E4400041675911F911D8F74BB96AAA3F1A5D878C
+:10E45000C2C64F11EF3633FA0BD4BBED650EDD5259
+:10E46000A8253DECAECA8929D0CF9965BE887C0528
+:10E4700011319C00BABBEC0D8A8BDC4B148AD3DCC7
+:10E480001EC8E0B2C8F979E16F20D6A07176D6F047
+:10E49000DBEB1D8511477ADE0B2261D8EB171147A4
+:10E4A00013D6E5A53FC3BAC9B7B3C8C545A14FAA9E
+:10E4B0007B539ABFCC9CF746D845F39488A84B0869
+:10E4C000FFB7D2CDF32BF663C0CFE65FFB2A437FC5
+:10E4D000203DB098A5D8FCA2F48334627BEEC6BA86
+:10E4E00013D279261D8EA4B328C2D2F605797544BD
+:10E4F000781D438D54A6C657AA8CD73DFAD3F9058B
+:10E50000F8782264A7D8D008F8ECCF8ACF603A3EDA
+:10E5100045117E2E7D954611C203FF3C16DBCE10C1
+:10E52000C85F16FE7E6B46E87AC45363566769C9B6
+:10E530003BC6AD37201CD9B7C5AD7A24DDBE9644A5
+:10E54000B87D2D8D907DCDBE6F85E0DBD5DA87F768
+:10E55000AAF73BF0CF2C7AD49D7832AF02F070BB93
+:10E56000AD4F92BE96CF1A45DFB87E7FF886FE4942
+:10E5700048E751219F68DB31DE30741E8F7C22C258
+:10E58000E53878538CE63D3542FC919C078CC1BA46
+:10E59000DC4871C8FCF71887742F1CC8A338E4CD79
+:10E5A0007D79E8EF9F1A0A658D438E16F74CCA16DF
+:10E5B00087F48D1087AC8FF078F5F87FB928AEA876
+:10E5C000BEC0FD7CF5851E15E3898D119DF83E7F4B
+:10E5D000A85F35414EAA310E01387D220EC1F914D3
+:10E5E00087BCD9A3225EF32FF4D3BA6AE8631C3246
+:10E5F0007F843804B05051EE0E5777FF0CCF2D9327
+:10E60000DE5315E666BBDC5625FAE93D895CD75D2D
+:10E61000B62DCFA4734E979BF86C8E6F6A1D97F73B
+:10E62000CC7923C9578DEA2DC3FA4017CB0D201F93
+:10E63000DECA1953C10A785E837171174E05BABBE1
+:10E64000CEE6C52CCCAB3D7CFCD3B963F6612BED9B
+:10E650008F47E8C55B3937C4441E6414C0FA4FAB1A
+:10E66000467C31F8A1AEA99FF7717A36911E6D16DE
+:10E67000BC09EDD1289FBE55C48332FE7A6EA51227
+:10E680007353D2652C590AF3E709F8AE393C3FAC15
+:10E6900055BD346F4719A379B75A17A97E313FE1A9
+:10E6A000D275E8CF4BACE7F9A2FADD937918EFDF2A
+:10E6B000A231159EAF6C8FB6917C9E75513DC38083
+:10E6C000FF503F2BCFF412DFF2865C69758E5CB091
+:10E6D00064715BDCE2CAE833757541363B24DBCC00
+:10E6E0003AC4C188C83F2BD88CCBC0974BECC14EE5
+:10E6F000A4CD3D2D74FC51367CBDAC2F6C9C617C4F
+:10E7000007E563AA33F1EFDF017EF5BDE6A2F73A34
+:10E710007D7BF7DE5E81758B1E8DEABA329F01CA62
+:10E720008A96613E8B3CA0BAF4E92694CB23F9B2D9
+:10E730000F060DF03E82092BF9BD8F3619B6FEA9E2
+:10E74000C843AFA0DF3B325ECE7F95AF977D2BD124
+:10E7500084F7358E4CE0FD4B11F5518BCE37A1512E
+:10E760001EBDE597DE6CF6F1744DBABCDE51B5897D
+:10E77000CBEB28EBC0AEBF18C9B22E67A9B9633A7C
+:10E78000F0E3C89083EA389067C5313ED838C37C3F
+:10E7900019F9B57D90F3F5C86BF7FBF09CDC6313BA
+:10E7A0000F64B3F3BF11FE285E1DA3BCAB7BA6C8EC
+:10E7B00077D990867E6BF7A2A74E55C03EA7E74F4C
+:10E7C0009BA50209C00B0FC6CB72BDBB86E77129A2
+:10E7D000FC9E579BD0FEBCF64A43367DAF8C98BF5B
+:10E7E0008FA4CDE7EF45DB7A34E27FD189BA7D781B
+:10E7F000EF275EDDD3AFC1F9F6FDC6C1304FE99B0F
+:10E80000CEE3FE11F10A005E455784D7DE7959E464
+:10E810000DF072D58C1F8ED74F6A187FEF53617839
+:10E820006A2A87E3C9441D7381B0F739AF7E9EEA37
+:10E830008E7D0907154F2E0DED5351F464FDBB7B02
+:10E84000B0142320B678C9391545CA7C504DD3BBC6
+:10E850007983B969FD7B5BC6A6F5576D9894D24361
+:10E86000F87F79644A5ADFEDFF405A3FC866A7F542
+:10E870001B96DC9A06AFC6174EEBD7F96F4F9BFF7E
+:10E88000417D455AFFF6B25569F39706D6A58D57D7
+:10E89000FBF63C84E5A368F94C6D2C23799C897CBC
+:10E8A000CD3B63903C6E1FBCDF877211AF8E521E52
+:10E8B0003D90DF5F8CF5EBE79CD9EB0B0FD6A8D230
+:10E8C0007F17A3BF3718CFD7E4FC606922AD2EBFF6
+:10E8D000AE86FBE735354AD63A41A63F967E58FAD2
+:10E8E000E5CCFD33FD6EA6BFBDF3E67D1E5EEFE712
+:10E8F0007E7FA59083B6B29F7A13485703AF2374E7
+:10E900001703BD5EBA8F41FA757CE5DD93F1BD5A00
+:10E910006E9939D65D92F2D7E1B218FB258CE7FAF1
+:10E92000626CCA741C8FB175D3A92EAD85CBF9F377
+:10E930009BC4F3F5D8829FAEB5F12DD3FF063D33CE
+:10E940007F50C052F14AC31F8D4801E0775BF3410D
+:10E950006D1CB461EF31CD6E874E57FF6ADC087EC7
+:10E96000FA633519FA84EBFA8696BFA31F78B99536
+:10E97000D7DD0FB57A581CE83BDBEAA3F6E7AD7E9E
+:10E980007AFE7CAB4E6D476B19B5F1D6008DFFACAE
+:10E99000B58ADA675A0D6A4FB4D6537BB2354AF35B
+:10E9A0007ED4DA48ED8F5B4D7ABE4BE8E9FB051F5C
+:10E9B000A34CD615A2C71D0AF1B501AFEA2EB86067
+:10E9C000A8763B0F7CFD4236BEBE577F12AFEE9D50
+:10E9D000847206FE2AAB3EF5D6C8B83E79DE84972F
+:10E9E0008C87317F413991753AC0EF31C4CF8DF5B5
+:10E9F000B9A2ABC7EF88A8DF1C29648DDF1670961B
+:10EA0000E5A33DFF4A3444F67CFC4CB2E77EA6A564
+:10EA1000DBF39261F67C2DE91D3B897552AC2FD258
+:10EA20007B8A8C3A4841AD4EEB641D64D11F791D41
+:10EA30006434FA81EE9368B7A4DDBE52BA879DC7ED
+:10EA40006CE327C83FE99F87F90F7323F98F2AA149
+:10EA5000B34C7B93E2C43C41CFEE579617A07D7137
+:10EA600023823C4F3758159E3393F701F66D281ECD
+:10EA70000EF7E5EA5EF2E73B9271CEEB14C70CF7B6
+:10EA80005FE97CC058C8EEDF810FAFA6FB45CE879B
+:10EA90001AF5BB896DE09F8F2418AF93CDE1EFEBA2
+:10EAA000A41F3C7281D7312E694A8CC1D185584B45
+:10EAB000CF3C680F7F8E8D8BC2395B931D810330F5
+:10EAC00035EFE93EDD03F38209736C0E8C57C57395
+:10EAD000685D68C9CC18F61BA2AF937D0A69E97E10
+:10EAE0001223D4A4DFA1225851467F626ABE8AE76E
+:10EAF0005B9AEA03DCF5B34DAD16CE65F9C516A6F3
+:10EB0000978B7AAA37AB7FDFA8D8EA6C1A0B7422EE
+:10EB10001DDA6776F0F77A19F226F924EB6D320FD9
+:10EB20007F8419BEDA2CF143BB78EF92F9BEE50F72
+:10EB3000D34D7F2DF05DF19DA0F72D6C03E3F723FE
+:10EB40001C909F20FFC6B862074A86CBDDC1591FC3
+:10EB50009C5C4BFA6D29D7266FEF51286F177913FC
+:10EB6000D3EF73D8F318993765E6470F0B3BBB0B10
+:10EB7000ED2CB40F3B19E55B1D4A6E609F92CA975E
+:10EB8000C06FCE40BA16D58AF72FAC651EAF177E80
+:10EB90002E2D5F1A116F91973893E75EEC3B9F978C
+:10EBA0003A77AFABC78FF71CBB667EB5B109F936B4
+:10EBB000D343EF399916D7D1EE64D2C37C161B37F5
+:10EBC0003775DE2AD3CE637DB61382197CDFBB1383
+:10EBD000BF040078F901475ADC5350951EB7DD5D3C
+:10EBE0002BEDECB5A1030580DE6F4B3C5954D45599
+:10EBF00079FCE911CFDB756E2F18DA3BDBFBF5767C
+:10EC0000AFE1F1D9CE7F3B9E8F7B647CD492761F9F
+:10EC1000D6C17BBC0ED2EF4E5DEBC2FB1E9D5E8D5E
+:10EC2000C737BAA33EDBFD95DDB58AA09BE3E513AC
+:10EC300078A9C1E514078DB45FB79017D9CF2D37E8
+:10EC40000DD2473D10C53CB9CD3B4EC1FAA81CFFC3
+:10EC500068AD22E485D797BB445C955BD61B77A053
+:10EC60009C4D583F1BD9E68138E93C3CF794F7525C
+:10EC70005CE59DE832B3E1FDCF025E9733504F79FA
+:10EC80007FBE8361DEDF5592DD8FFE632D8F33DB28
+:10EC9000F459519C6F015FA629C3E77D5CC8C1434D
+:10ECA0004E9043D8BF6BDA5D744FAC6B3223FB5D83
+:10ECB0005A37FDD1ADDE2C72A8DF47E7E7F431F912
+:10ECC000FE3DEDBE449BDED0B816F6D59E6701B47E
+:10ECD0001999FAE69CB0BC712DDEB7A8CA0DE0FC0C
+:10ECE0001AF5C716F2B123C0A8DEA115367BA8EE2F
+:10ECF0005CACD1FD08892FC4EB8FA19D1A4DBE33AA
+:10ED0000F181FD48EE463ADF4CFC28949FF50EF366
+:10ED10000BCDC66816783F4FEA55BA7C394791AF9C
+:10ED2000D1E849F3AFC529FFFA6CEDA675784F6DB0
+:10ED300027E3E3A76A4394EF67F6AF959EB7693D73
+:10ED40008D782E6D535D247F99EBBB4A385EDD27AD
+:10ED5000AAC5BE3E05E57F5755510EDA772F1A6AD0
+:10ED60001B5F9FA930CFD5DAE2A6C2482F8FDB6B9D
+:10ED700019C9AF578FFAA6825C78CFA82053C07705
+:10ED8000C7DB7F3CA7BF773EB21E83E4964C3B9720
+:10ED90005BF636F0A54088F518F6703FBF2FB299A4
+:10EDA000E6497EEDBEF1B781F83BF06DCCC2F4FAD6
+:10EDB000D4BBAD3F2975F9E388CF392C07F97C899D
+:10EDC0003DA890FF8E18A477BEA45DE5F756C6C98E
+:10EDD0002E90837D123925559762F8DE03F5CB64BA
+:10EDE00014DFD0CCEBC42B2FA2DB47EB260930136A
+:10EDF000F1428D8AF2CFEDEE25F61ADF1F96E1BDC6
+:10EE000015C572909FBD11E51AE69530F34FE7B234
+:10EE1000DCE799EC6B3EB80EDA4975A29E26E8193C
+:10EE20008D1F12EFBF94DCCAF820B38E2AEBAC1D05
+:10EE3000A2CE3A5A1D956917896F32FECDACABD27E
+:10EE40008D3AD08FB76ED25837F19DC70BA93CDFF2
+:10EE5000CAE375787EFF6E9EA0EBF0D9A45FA4E7AD
+:10EE6000D26E65D2F9E4287EB1FB4C7B1EC2694BA1
+:10EE700034517DFE907FDB2905E3DC844B67367DD2
+:10EE80003D9C9FEE373A84FDDB5627EAF0E73EA52E
+:10EE9000627D609EDF52F1DE5E5522407EA14DC94B
+:10EEA000FEDEA1BB8EFB9B617E22E3FDCC7FE6787C
+:10EEB00063AE5296F41FAAA053FA57E08F62D7BBF5
+:10EEC00043F2BE9761E8BEB9A9F8B3FBE98F321DE2
+:10EED000E323BFADEE5B9A65FF617163BA5F5006D5
+:10EEE000F9FD30C9D76E9177B7F9F979CC4102B203
+:10EEF000F801887F3F5B07F254D99F6E6FF2CAD248
+:10EF0000ED4D663CECF6302BD7060FE2E1D63A52D7
+:10EF1000DEF478B6B89E91BC1E2EB454ACFF8413B8
+:10EF200006C3F3D08A4D86E7E1F2BFF37934D6F118
+:10EF300078A1A3AC298A7993AC3FEF5E741BD957B3
+:10EF4000F0A33D75B6BC49DE7778B7F52829AF5AEE
+:10EF5000867E66D6A5BA17FE3DD5A1DAFC4D27B14F
+:10EF6000AE7408E411F5ED70BE9987F725ADE7554D
+:10EF700076401F5EBFCAA44BD6A1C6D78B7B2BE7BA
+:10EF80005CF1C5788F7290BFA7D0064DBA7F02F4AE
+:10EF9000D07BA279E23D5166DDC9ED6EA1F773F138
+:10EFA000EA9655F6BAB3E45BA390E797AB4DBA3750
+:10EFB000D43142FD4FCE7333C31A87EFC7AB3F4BFB
+:10EFC000FCC6CFCD302F97752D7D86F9BD3A98E7D9
+:10EFD000BA68AAE375CCE72C3A87BC7F6224642C1C
+:10EFE00057891D80F54F2F7A8AF2CDDF27D8587CBC
+:10EFF0007F92CC37359E6FCA3C56DA8D1AF589CE92
+:10F0000052183F7C46A33838EFE9AE5358770F9E2D
+:10F010005947399FA1ACCCC37DE43D2689F7D5E69D
+:10F02000AB9598AFDADEB748B8DF69ADFF05CAC562
+:10F0300093AD516AFB5A0D6ABB5B1BA9ADD28C30F4
+:10F04000FAA5AA7ECA00D9822118B7E1517516D651
+:10F05000DBCE7F5785F9DFC8B7CAFE68DABCBCB221
+:10F06000C6B479902FFF1AE7697ECE4FD71285EE8E
+:10F0700027DC39C81E52F42C76E1FFAE5DCAAFBF63
+:10F080003676A9A89EF29791EC1223BDAB1A14EF25
+:10F090005DA57D12FAF7789D4E7A91D4437CFF4AA4
+:10F0A000FECDA2F59DF8E77CA067CCC7B81D4BDD6F
+:10F0B000F3A0EF1B83E2BBEB9B4F2EDA8FF7803A76
+:10F0C0005E94E3CBF71BB67166D534E3F726C73001
+:10F0D0005986B873C7C9F1CDF45DB6F8AE26DC58D1
+:10F0E000583CC052F71F33F9B5AB9EC7EBF27E4DCB
+:10F0F00090F1FA9A1CFF64BDC8E3801CACE3C9FB25
+:10F1000013B9237C47F4F17A6E0F3E23F8D4E9E279
+:10F11000F71716677C2F1212FB8EF4BDC836313EEE
+:10F12000DAF721ABC47E4D62BFC7E6446FA3738B91
+:10F13000F2EF329AC5F30567626D633068F4B3ACE1
+:10F1400070960B7BFA6C3DBF97ECF21B1A9E0BC0BE
+:10F150006B20788DFCBEA61C5F702139DE48E30D64
+:10F160007C7CC10593EA4AF23BBDE5F565FBB74EF1
+:10F170004DDDD3E9C0FA8417BF57E1F79FBE26F0F3
+:10F18000CF6CE5F72A77F9C47D1F3675BF81700C07
+:10F19000FE7DE6EDF5B70CE177C7B0FF06DA5F7CE0
+:10F1A0009FB300E9ADA4E7FF40CF33FE9D81F5F5A5
+:10F1B00093F78BEF7AEE433D612D1CEFE4BF9B602C
+:10F1C000CDD96FFF4E6841FDEC66317F33C1DBC0A6
+:10F1D000E7679107218F73F7634DF60AE0B512BC1C
+:10F1E000D51CBF5BEA757EDE19728BDFFF139EE2D2
+:10F1F0007BA133D1751EB4E7C97F07C09A4EFB5D72
+:10F20000019F76121C53EEC7C4BD28AE1752FEA54F
+:10F210003C7C4BC8DFEC7A45CAD517687DF335A333
+:10F22000FF1B042FE3FBA4D1E828AF887E93D6F917
+:10F2300093F793FF95FA57898FFC9E2C532FBE2787
+:10F24000E8877DFF83CE0BE22FC413F63D742DF6C5
+:10F2500005B87182E349C23D762DE032FDCAEE99D0
+:10F26000FC2FBAA2684270460000000000000000B7
+:10F270001F8B080000000000000B93E16660F8514E
+:10F280000FC121486C62F17A76068678160686B937
+:10F29000AC0C0C3540ACC8499AFE5540FD4B81780A
+:10F2A0000110CF06E269403C11887B80B81D88655B
+:10F2B00080E68903B11010F3023107103303F13FE8
+:10F2C0000E06869F1C08736E03C51E93683708DB05
+:10F2D000F220D8E781FEDF02C437C80887513C3CE2
+:10F2E00070163F03439D00822F2C882A9FCD8F608C
+:10F2F000F38A5266971C503F008DFE9C5880030095
+:10F3000000000000000000001F8B0800000000004B
+:10F31000000BE57D0B7854D5B5F03A73CE3C333312
+:10F320003909794C20E049483055C0214004A1F505
+:10F330001010432FD78ED42AF5A2774004E49554B9
+:10F34000B1D2AB6D46264050F4060B0A0A3A50A8DB
+:10F35000D08246C4962A7A07454BFFB6365A6F7D4F
+:10F36000D4F6C6DAEBAB18E28362FBEBEFDD6BEDB4
+:10F37000BD33E79CCC24A0C5DAFB874F77F6D9AF25
+:10F38000B5D76BAFBDF6DA3B1EA884C273013EC68B
+:10F390001F96DEE60180E24C3AEAFAAF2EDA3386B7
+:10F3A000FDFE7F3DD11D46A69E4C4F0305602C2BD4
+:10F3B0000713A004E05C1FFB95D59BFCD323BF3D46
+:10F3C000AB08E020A8E0659FD2DAE401FFCCFA396F
+:10F3D000F82144B1DCF5D360796710DB25A8DD970F
+:10F3E00080B74B5718E5FA70CC800BBF9B3EFA9D57
+:10F3F000F5337473136B7FEC8320B577C22153F818
+:10F40000D00569D1E6E34AEC577BBFB346E42B80D5
+:10F410000D0E02DE29007519780FFDEE7582F77169
+:10F420008DC16B6419DFC7E02FCAC07F10BE9A0F71
+:10F43000C339FC665D06FE938587E6CFF09C6C368B
+:10F440001EA9AA0658DB0C8F54B901D634FB28BF7D
+:10F45000BA59A7FCCAE608A5498D356170247742E0
+:10F460002AC1501F8AB2FAB27FF65FA0CA67CBFBEF
+:10F47000CA755BDE53C4FAA9C9E4B5A061CB278382
+:10F48000F5BE7810C76773F7E2F83E4A1998CF4582
+:10F49000183ECEE455C16F246602A34775D063A41D
+:10F4A000D83CCE0CCE9B0E61AC7719E1CD23F07A1F
+:10F4B00075D98A4E84F77D560F58BD338253DFC409
+:10F4C0007AFFA7E2FB7C1E1B014AD9F7D5DF6EEA63
+:10F4D00054587F2BCB3CC60A36AF7BD9F8ADA75B1F
+:10F4E000F0B85BFB03E2CDC7FE211E6B36F37C66F2
+:10F4F000DEF6FC19C0F272DE15997E4EB6DF61EBC6
+:10F50000FBEEB7DA88D523BFCA7E87417C851EFC17
+:10F51000FCF67B26C3F980DA4CBF729C7EFB65EC5F
+:10F5200010636D876D86545AE93D4EB5116D4820C4
+:10F530003F6CD62055C1BF1731B9A81672D1A2CFE2
+:10F5400008205F39E101EB389519BA54177966BB89
+:10F55000189F54472E5EA4205FADB7B4AB049072E1
+:10F56000F3EFCD3A986C1EB734D750BAA3596F4712
+:10F57000B9B9E5237566FBF0DEF2F8DF425FDDEA3C
+:10F5800006E2BFC42E48ED50B0BFA61766B3FCDA42
+:10F590005125B53719989FE942FDE0177CBC5631DB
+:10F5A0002EA9C4FACFA8807AD0290FB7B8635F46D6
+:10F5B000795833CAA5AC403C577179A876A77D43EA
+:10F5C000D9F7B5EB2B473188616DF4599287EAEA98
+:10F5D00061868AF25025E461ECED3ED4873DF35F0D
+:10F5E0005ED25E3500201FE913CCD04B3F413ED0A8
+:10F5F000275AF0F519CAC3A9E3AFB63EF96B6DB44B
+:10F60000F24D2F2BDF51E53154A5375C85A7A5239B
+:10F61000B1E1BDF9ADBA4AF059B46F3E73A62B9B68
+:10F6200053F02A1BFCF6E608F1DDFA6683D29B054F
+:10F630001F7A91A7C6B3BCE043281F43F99CEB1681
+:10F64000DC487CE92E4A01CAC9EDC89FE7E0702B6F
+:10F650004D7322D3913522CF9648175B03D663F9B9
+:10F6600040CA9B508EFC29CBF7264CD6BEB8869755
+:10F6700037287B13B866DCEEE7E55F56BACDC444A5
+:10F680004BFBC4CDA6599EA9CFF2E97ACDDA1FEB88
+:10F690007FB8051E3844F5657FF39457797F7EDE89
+:10F6A000FE26E52533517EEAFBBF49698B30D30244
+:10F6B000D638FAB9A927BFCE348767C6A9BCF17E70
+:10F6C0003311B496DF6F229E64F938655D22C1EA7A
+:10F6D0006F845895C2E85038B329C24C23F0CF4A02
+:10F6E000996EC30A1FC777667EB713BC812A5E3E38
+:10F6F000E2C6E7CC6455A67CB2F2AB04C2EF2F8A17
+:10F700008321EC055C1FDD9CC5981D547ECD2F1810
+:10F71000DFBB4B3D51B23BCA59A68C7D8FC4C1AAF9
+:10F720000FDC11ED35AB3C4B3E64F09E43F0C69AC6
+:10F7300066E68037618557C2D31FFC128EDCFCCA97
+:10F74000C777F255FDA5E37E3591B1BABFC31D451C
+:10F75000B3014D282864BF7CF85D53615D965CCE93
+:10F76000686010FD66C2D0DEFD96CE1C08298BDCD9
+:10F77000FFADE95B85798EB7D94A7186CE2C7F853E
+:10F78000158FE7887A4E3E94F3F3F49ADF15B6F9B5
+:10F7900081D6168985FA9FDF7A7F7C662CD8BBDEFE
+:10F7A000D38A42E3D7CF18F715E0E381B782962CCE
+:10F7B000136A33E3155D2CC74B651DAF38766AF1CC
+:10F7C000E9944B09AFBF17BCDFB5C17B939BC96FF1
+:10F7D00016FA9F6A78034CBF9E941CD69C981C9E78
+:10F7E000AA7E8BF057C65FEF69903E97E175D98589
+:10F7F0003EB2FBA5FEFBACF15782458C9ECB7E79D9
+:10F80000C52BE7BA30C3F87C4466FC26C520B87324
+:10F81000F17BAEF900A46CFDFCBDE6930BAFA75ADB
+:10F820002F9DA8BE5DF19B00A07CADAE8214DA18BE
+:10F83000AB0F9F970FACBFD5BF985C8A70785BCF3A
+:10F84000047334C0066CC2EC8DD5D2FEB8A8F68421
+:10F85000EC8F9B9AA1BD85D9350F859BC85E5AADAB
+:10F8600000B567FB524831BB66CC33DB7DB311FE7C
+:10F87000E86D94AE76B3F2207E3FA44F66530854F1
+:10F88000178E62E883D57EF9FDB986A1ECFBCD55D4
+:10F89000EC3B638DD521DE1FFB1EC3FA79D5FC7BC3
+:10F8A0002EB8F26A183C16BCFB3DA978367D59EF9C
+:10F8B0007211FCB7A13DE6C5FD8041A93FD01647B6
+:10F8C000A60B0CF118DB2A7AB79BE5E2FB8175D514
+:10F8D0003F4AE3D67A8DB0EB1E3FEFFBD089FAA208
+:10F8E000AACD7461FB28771DDCE6B0BB82C3657EC0
+:10F8F000A03299751070E46FE9B1E32A27A11D17B2
+:10F900001676D0792BCE9D84EB6C4F398CB295CF87
+:10F910005971F624B4DB0A7D4D2F4C64E317327D18
+:10F920009A44D1D10CA509EDFF8B0AB3F2CBBA6989
+:10F93000BE992956BEEEBC61155766D9FF302AD252
+:10F940007C657E40839DAF6F1376EC2DC2AE2D4754
+:10F95000191F2BF88F098B9F57EDD16BFED3B95E22
+:10F960000BD41837225F0E688028DADFEB18FEE22E
+:10F97000163AF96BECFAAD50B3CFEB54CD67239840
+:10F9800097B9C6E6EEDF295F1B217E25D62F14EB43
+:10F9900056A026AAC487F73F7FE77C73CDFB2B02D6
+:10F9A0009F6C9CABB38DF359E1A530C8C619F3B772
+:10F9B0001F2780E358D7B113C43B2CDE6EE27E1BB9
+:10F9C0006510F7737E98124DD33EEF7AF2D35D2B1C
+:10F9D000FA84F8261DED1C82394BBF5A9527E36F38
+:10F9E000C3FFA9B3F2B3D145A6CB5F7EA7E090A534
+:10F9F000FE7657A8E835DCD49F0D677FAC66DA83C6
+:10FA0000F0076A128E60A14D9F1E6FEE2E38C4F46F
+:10FA1000C6CDFA0CD2C7B9C6FB21D3A3692657BB02
+:10FA20009A7D94DEDBAC43DA8B7E8B08A5DF63F234
+:10FA300087DFB7B27D24A6F73447E9FB96E67194D9
+:10FA4000DED56C52BAA9B981D23B9A63546F43F3A5
+:10FA50004C4A7BF0F9211BAF4EAC6FCCCE3A7366AB
+:10FA60002AE1423FEE3E885633FCAEC6EF16F8D789
+:10FA7000B9263D4E7232D34F7E8F02E1F70840CA5D
+:10FA8000ACC276CFA9B00372CF2B29E67581EAE22A
+:10FA9000E36B35347840CACB6EA075AB640A5BB7B4
+:10FAA000185DB582ED85885796A7EF056C3D43FF3D
+:10FAB000A07F0AA4FD23A98986ED8B44FBD6A08BE9
+:10FAC000EAADABD168DD73F2C508D0A75561E59802
+:10FAD0008FFCD4BE90C6EB4FE4E3159CCF143DB32E
+:10FAE000EB5B751775BA6E0C5F3FFD358C5F2C7242
+:10FAF0005130F50F486928572B691EEBC2535E64DD
+:10FB0000DD317ED4CB2A583F77B02D35AE6BBBB6F6
+:10FB1000BFABCFB6D039A8727B7DC4AC773B10BFEA
+:10FB2000233426D76C1C757B2085EB0EA3878AF0C7
+:10FB3000E60B0532C2C7E7ADB6406A9B9229D70BE8
+:10FB400038DE47E85113D7B99EEF7EF1DDE84EABC2
+:10FB5000D82E05D16D46A63C24DB99F67621D92E08
+:10FB6000018A86EDD6B37690290FCB7630CAD62E91
+:10FB70002CDBC1B3268DB7D1DECE5F207026E61F09
+:10FB80001E1775C52DFAC15F65BAB8DCD8E9948B2C
+:10FB90007F8A40D0E1F184F231E2630ACF2B8AAF51
+:10FBA000F56317FAB3EC721D1E63A71B5459F28C50
+:10FBB0007417A1EC16931DD480F6C6B6D6ECF4DA11
+:10FBC000A0C5A655E3FC266AB6F9493A6DF0093A94
+:10FBD000B606B2D269832EE8B8006C7496F4DA20C7
+:10FBE000E9B52C3BBD36E4A0D70649AFE5F67692E1
+:10FBF0005E1B72D06B83A4D7627B3B492F273DC22B
+:10FC0000E3D28A9D6E6D943F55F470EA850E97415C
+:10FC1000DF5DBB4D7D12EA871B34DA57438DAEE0C2
+:10FC20007E00CA4F70FD8026C075612DFE2AED331F
+:10FC3000368F5D788EC5ECAB39C95727A11D1E5490
+:10FC400064F9A14968876FF3F0FC75C9E393D00E9E
+:10FC50007FC4159BAB92BD93021ADF812F6F2C05D9
+:10FC60001B1948A76B4D3F43BE397DBB2B9A3032E1
+:10FC7000F07881E305B7EF1F6759BF72CF43E017F4
+:10FC8000EB0C3D2138BF45706A299A772F382F62D7
+:10FC90007032BBC240FE66FC6BB49E1A38612E5FA8
+:10FCA0002F7AD667C7FED7D9FE8CED2E1BDFD46C1A
+:10FCB0000ED8F866D8FA425BBE6AED405BBEB2A5CC
+:10FCC000D296376E38C3D6DF9065B5B67CF9E2734D
+:10FCD0006CF98173EB6DED7BF10B707ED9A9BE7C65
+:10FCE00023E2B9870E899A7AA283A8BF3B59536F42
+:10FCF000E3A71CE55FF9B666FA18FEB5220FAD431F
+:10FD000000D7107E24BEF275487850BF140553E723
+:10FD1000B3F2806E26D02FA0EA26A01DE1D2E39494
+:10FD20007747ECF275211A4A8CFE5FD9A5816F4C9A
+:10FD30009FFD9B9FA4FFFEE6E5E417B9BEAB457CA3
+:10FD40005DBD836D97D0DF9360FA71071BD7CDCC73
+:10FD50001C7F18F942F00FE367D42B459A22F6175F
+:10FD6000272767D529BBFE19BAD10E7F459B431FB4
+:10FD70009D207F7F56F2DB1FFE364034817ABC3FE8
+:10FD8000FC8DD114A1FF4E4EFE872CB3E3A77CB1AE
+:10FD9000C721277F5FFCB5AA20F8A2A91EF112DABD
+:10FDA0000C705305DA5DCFEAD9EC0AC92F77CCBACB
+:10FDB0002D60B5F7618CC776FE2EC7A1BC9A2DFFCA
+:10FDC00079E313A847FB2394E03EA46DAD39E62FF9
+:10FDD000E8BDE1A2CA80753DFFBCCF3F43E76F9FFE
+:10FDE00054FB480FBCE5FA6B7916F81DFBB2DEED4B
+:10FDF000135C5EE27E97554FB29F1AB4B7821088AB
+:10FE0000229E8FFBC323219FED0F7D3C3DD5FBB68A
+:10FE10005DB3F8FE26F1725EAA1AF189FA1DCF8D44
+:10FE20005F1E9122BA5FE482DBB17CB88BCAAF0B54
+:10FE300084B7215C5F57E3D76BC508EF9014C55FAB
+:10FE400068697D46C8324F6117C9F9E7B28F56B568
+:10FE50005C5B6F5BEFE0E27AF4634A7EBCAB654DBE
+:10FE6000BDB03B5AB5CF957D9413CE2D1AD99B9F2B
+:10FE70004FFB4885ECFDFCA3D847BFD096AEB0DB66
+:10FE8000470F733A88FA1D2D0FD79F48B9B48F02D8
+:10FE9000418FD8D73BEC971A661FE1795250D82F83
+:10FEA0003529B257FC35296EBFD4487BC6BE7E5D6E
+:10FEB0008B066871C63EEAA37FF393F4DFDFBC7262
+:10FEC000ADEFFEA0B48FDAB87DC4708DF1276A0D56
+:10FED000F77BA88EF57D9CFB7FBB7D945D7EFBC38D
+:10FEE000DF0668E3F6513FF89B990B7FFFE0F6D100
+:10FEF0006E0DA47EFFFFC43ECAC527FFBBEDA30C59
+:10FF00009DFF36768ED3AE9176C4A9B66FA47DC21E
+:10FF1000EC981A0DF51EB3B3D08E39EE6AF7DDCE2C
+:10FF2000E6739DCAB03514E356F87EE6062DB6C1D9
+:10FF30004DFE8DB48E76C666D4E763859E45B90FB7
+:10FF40008AB83D2D0A334660FDF866B7E51C420DC0
+:10FF5000A6F59E739BCF111E989D679FBFC08BC453
+:10FF6000C37E7781DCF79C1DE3F3FA31E101D2DC3B
+:10FF7000DED2D23E4CFF43AC6FB41E1759F1C1F133
+:10FF8000A3468D14EA03D6FE3FDCC536BCF86C7878
+:10FF900061EB101F0F546ECFC9EF3C0D8CD115F4DF
+:10FFA00087B36C07F2EF002C3298BC415BC330D6AC
+:10FFB000FF80D8AA6F60FC5CE8E5696F02D3BF03DD
+:10FFC0003A674FC7B46578EDE17A562F3FAA5F389C
+:10FFD000D5C07515C8AFB8063BA3F3505772D270A1
+:10FFE000718EC3E4F9D995C7853C9B60B7CB5D861C
+:10FFF00026FD4995B9E585FD281F7B7BB7CF251FD9
+:020000022000DC
+:100000006EAB5C937C5E7D62F2399DCB7582FD4365
+:100010007D51E0E827DFB4AF1321B0E459F98782BE
+:100020008F01BEF1998CA7C36D3E03E34FAA5C3AE2
+:10003000C64DE6835E80FC1798A201C659EA45DDED
+:100040000974C1F6479716E14747BBFF42CB7EA232
+:10005000C0C3E5B568C6948A95ACDF6363787CFE5F
+:10006000009DC7813AE77333CA97D7921FBE8DCEE2
+:100070004D938C9F2AF9FE86CE6FD654EDD5ADEB0D
+:10008000D4688FF47338F9832DE175C29E66F851F8
+:10009000AB5C26DA019F963FD44FC81F79D31DE78A
+:1000A0004927492F53DCBB3851FEF8B4E349BAF66F
+:1000B00096AB1B894F8B66CCF5A1DDBF2A32A3CF4F
+:1000C00073D4DE74BD8DE81AA8023395A5FFF33C06
+:1000D0004A26AEC0195F6BD91F39ED75B5B46EE60F
+:1000E000D6BEE856E4B4CB78BFFEE5AAF147545E2D
+:1000F0009A4EEB804FF4B7C6B82D81FAF318DA0C9C
+:100100000C1F6ADBA834EA4FA882E80E5E85E23F46
+:10011000FC8649FB703AEFAECBC0E72977D9C6D34E
+:100120008A02F6F3E79909C50ABF7FB987E0F0E1D3
+:1001300078A8A775D6A182F730B87FAFD7FED16176
+:1001400037AC2EAFCD1A67A0FDADF6AB17D9E13DA8
+:10015000E17641CD78CD6247E56EA7C16B167BAAEB
+:100160000DF9DDC207ABDCB05F61EB70327231C4F8
+:100170000D96C7A23280564CC7231FD6F2757DA7B5
+:1001800042E7C324D206FEC7CF892EF318D49FCBF3
+:1001900017273CA94113A8BE7162E748C707F3F8C7
+:1001A000A422056CF5EFF778A85F0D62749E7EFCC3
+:1001B00077E747A85F937DAACBC0E1ECF7324FFC0D
+:1001C0007E4F31B21D87071B903F621CF70BD0DDBD
+:1001D0001CD6EEF8BA19749F28177C9B1CF2B549FF
+:1001E000C465416C4C3FF3E2727C9C8DD981F5B5BE
+:1001F0005880EE2DB5717B68B0187FC7B219F47DB9
+:10020000C7FABEE57C8BB08FEE42FB88EC1C9DF2FA
+:100210003D708978B33B057CF27B8D97C7671D15D0
+:1002200072BFC36706E85EC013D3025F60F255F980
+:100230009C1AC523CCB2356D057D8D3F70AEDD3F78
+:1002400072B2F11D9D9E5011D9D18EF88E5CED6574
+:100250005CC7A7C5CB9D621F53E35D90A4F393F4E5
+:10026000B9249F95428F542E03B2E3062F8694C182
+:10027000EA1ACBDA47A591AF3FFC18AC7C3218A242
+:100280002E20BD600667D7D1BD094EBF36179D53DE
+:100290000FBECA93C290B661C20E838DFC3E83BC72
+:1002A00077B1C3175DE1457DD74A961F5426ECF719
+:1002B000440683E57E04D32383D0AE637A6990E35A
+:1002C000FBA7A54381F7EF43874D5A9B5FB7B42F38
+:1002D0005320966DFD3BDDCBF9B4ECCAF779FCD722
+:1002E0000D417855CEBF12E9D9568074B86BEEB384
+:1002F00093F0DE49A215A2781765C8727B1C449D55
+:10030000378FDFEB00338DF6F2CAD917773E8A7448
+:100310009D0836FD95456FD479E93E08D71B9BE6CD
+:10032000CEE0E9872AF149D53248E13DA3296D4D58
+:1003300007DD2C5FBE1CE8DCBCBC35A1A03FABF2E6
+:100340000688E23083D181C7F255B32065D2FA0521
+:10035000CF45EA68A9A39F0AE4135C775AECF773C8
+:1003600086DC60E78BAA56FB7D9C52C117A50EBEAA
+:1003700070F65369B44D4378872E73F17B3B33EDB0
+:10038000F76BAAA0FDCDEFE37C0E05A3C8EF556B7C
+:10039000EDE33AFBD720FE75C4CB434B374F3B9D73
+:1003A000D5DFB2AC7E00E265872F964FF7A2F01240
+:1003B00051967D712F7E95F6468EFA19FD99B0C53E
+:1003C000333BD3D5D525D7CC61B5D6841240E327AE
+:1003D000BE4E7ADD2DE4F589C1F3E85ED7AAA25AB4
+:1003E0008A0B3B8879B4A7CA87955AF5BD1BE3767B
+:1003F0000764F22B518F66E1F3E5822F5F077339B3
+:10040000E26194B72982E37ACA4BDE9BCDC663CB07
+:100410009F99CAD26EA137C0E7AB6B7FB5DF6F0A79
+:10042000EAAF894B6C24874527E657B8D21BBF1922
+:10043000C74FD4B36D04EE3F0B219544FA36B5098E
+:100440007F7B4FBD36512F81F73B7BEAC5DBC0BABE
+:10045000DF64F536887AA6AD5EAC57BD3B453DB04E
+:100460008D6BF61AF71E091F58FB8BF6EA6FBBB7A8
+:1004700098C307D6FE8C5EFDED92F0D9EAE9BDEA9D
+:10048000DD27FA03DBB8601FB7A77CA44794C72811
+:10049000FEFDF1E2A9C41F878AA736E07DC46B7E0A
+:1004A000E6163AE2725AAF55C1570745BD96602D20
+:1004B000D90DC966685DCCF696AD787FB81AEFF1B4
+:1004C000CEA17DBEFC2EE9C7BEEBD9BF5F4DF77E46
+:1004D000E577ADD54F71E4EC3BEDC35A3E52851F35
+:1004E0006EC0143CA76C8DB884FFFBB5A459C5E45D
+:1004F000BD4CB3E5D794F3F251ADAF2513789F48C7
+:100500008BD1FD146F041E196ED1233DE37F66F07D
+:10051000F3738C0CFCEF3BE07FDF06BFCCFB07F3F3
+:10052000F2B1BE639313ECD795A84BD97E7998AFFF
+:10053000B885D6F3CFEDFC5C2DA6669D1FCF67E690
+:10054000C7F3727E67FBD429FF58F3D31DF3D31D85
+:10055000F3D36DF31BEF2B9882FC78A2F373D6BB19
+:10056000D91D8BA0DDBAB2F84764FFAF1C0CD4EFE5
+:1005700004DF8BC91BB19CC97607F56794A2BE1F27
+:1005800005E6085F71FFED9EC62072DCA786787CC9
+:100590002A147BC439702C82FECDB7BCBA889FE385
+:1005A000707A7C3ADF37897CA523CF7EF92BAE9B0E
+:1005B000189EC8F7910E3DDFDFBA5651321AD7B5F3
+:1005C000D690A958D7354FCFBA7631AD6B2B23D9FA
+:1005D000D735DC36D3BE48AC357734F3F7043688EC
+:1005E000FBB12BCB6BA9DE06793F253195F49B5CE3
+:1005F000371FFFDABC860AA61FDF7D8EBF1F71C0C2
+:10060000C7FD3FAB9BA19DBF87E0A3F431D66F9C94
+:100610005538C0EC3D4C1F66F61EA6FB9B2394FE8E
+:10062000A8D9A0742F1B17D3FB9BA394EE691E4778
+:10063000E95DC25EDC24FCBD5F2A77D1FAF9BD66B4
+:1006400058AB55A39FD747E93DCDFA5ACD8DF665F6
+:1006500084D23F2B3316FAC85FD199CC67F47AE87D
+:10066000D92ABA373EB15C237F076869357F4CE6EB
+:10067000BBC4EB9F95FA461FA3D339868BD7F3A54E
+:1006800092E1ECF59661BD718646F04030A1868B13
+:10069000B2D6FB16C25157C4E1063D9E0C65EFEF82
+:1006A0003BD85F6D9180AFC84806B3F797C4FECEC4
+:1006B0008A08F822DD8FE765AFD78AFD8D8808F8B4
+:1006C000CA3BEAF3B28F7B0BD62B2D6CA37B3BE7A7
+:1006D0002E06E26F6FB9B1957C15A2DEB6C14DE072
+:1006E000627C5B3AA0AD09EB7DB12906952CAD2C5F
+:1006F00089818BF1BFB78895337822A29F097379DE
+:10070000F9362C0F59CA45FBF10B5839CB5796DAFD
+:10071000CBE578DE3690FA24CD8C50F0AE859EFB8A
+:10072000D5982F71F1FC1EDFBF4C41B92F11E74E58
+:100730001D22EF6DB1B72F09F07C1ACBD938256196
+:10074000DEBE53D42F2DE4F3F65FEAA338E17BBE7F
+:10075000FDCDB239C333F33DED3BCBBF30C732BF24
+:100760007BBE731395CBF99CD6BC96CA73C96B64D8
+:10077000960B4C8BDE2A691B4EF6A4B40F479D7670
+:10078000717A36A38B3BC6E1EA6EAD6C5951457068
+:1007900025E85C55C0B5E55A3B5C83BF69876BCBE8
+:1007A00037ED700DBEAE6FB80EF8B85ECB051F1BEF
+:1007B000DFB48E9FBAD13EBEB1C23E7E6A857D7CDB
+:1007C00023F9A9C74F5BE972F7B7ECE30FF937FBE1
+:1007D000F877FF9B7DFC21D77FBAF1FF56F6B8E989
+:1007E0008B7FE413F6AE6AB53B9B1236BB93D57391
+:1007F000F985BDAB5AEDD878C266C7B27A5E51CFE3
+:10080000B4D58BF5AA17F40B7BDC36AED96BDC02C2
+:10081000512FEDB2F617EDD55F8984CF65EDCFE8A6
+:10082000D5DF20D19F69ABA7F7AA6788FEC0362E17
+:10083000D8C70511FF759D88FF2AF070795D1EE706
+:10084000FBEC52882BB8DFD707C0A843B83E0FE5B2
+:10085000EF21154C5D7E1ADA27CAD4E5A7E3FAD753
+:100860005A00B67DDB343FDFAF8DF3AB348E9E078D
+:100870004D580EBE44D98596FBAE5B45BD9EF260D9
+:10088000A2ECAB96F22F8BF6ADE2BEE0F96B3A5AD2
+:1008900050CFE88358FD2CFC375DF627CAA128DA33
+:1008A0006132B8375E3663EC4D601DD7CDE13A4D0D
+:1008B0008C5B9E1DAED60A3E6E4A8CBBD52FED8D4D
+:1008C0004419E151E7A9FC7E7BE89BCA1F197E60B1
+:1008D000BBCFF61E5081A7E9DE0A064772B00BF0C7
+:1008E0007EC2EAF2BEFD392DCD76BFA7A6C7E81EAF
+:1008F000F9C0057AAD0AB9DBDDD9E06AC876EE3019
+:100900005FCCA765417D5B15C277C8EEBF650C0E55
+:10091000D67BC89779E2F391CF7AF96F5B7CB67D8D
+:100920007E4149DFF7BEE4FDA89E79B08EB2D1EDDD
+:1009300056BF38E77A8EF72FEF9B1514BA68DF7928
+:100940006C383F2F80441958EDB18281F53EEBF8A9
+:100950006B1CE3F9618689F6272E53282F9E2A48BF
+:10096000E1FDBA40519B5E81EB42A483CE0141DCA4
+:100970007393FDB64466D07EFC98B8FFAA45DA268C
+:10098000B9487E047CBAD055629C811B354833BD82
+:1009900076C81DBFD55F6CA59BA920FE8EBB53E416
+:1009A0000F4A5630FA2BBDE7BFC9CFEF8FDD69CCB8
+:1009B000F8554516FADEED376CF70D077EE081F449
+:1009C000E8DCF533F5385C3D7C1B61FC3A82F40AC7
+:1009D000F1ED368FB9CD9F2DCE42EA0771FE3D670E
+:1009E0001C881FE392DFB2795C75D80D284FF29E08
+:1009F0008D3C17BA4AF8C7E6083FEC5C8885B1F031
+:100A00006D70D1FDB1B7E1D9F0680BFD1FF3F3F3C1
+:100A10000526E0E4FF92E7BD57B6B96DFEB0F91BBD
+:100A2000EDF97930A304F5D6BCF56E48317C5EE56E
+:100A3000F097DD27E63B1F9A56A11DB0D2CDFDF2FF
+:100A40007374D006B0A565C98FB7D4CD66F92705F4
+:100A5000DEDF627C6358E46D6130E5C1B89B57F717
+:100A60008DBE780260FBD4AA81A86F0B20EB7B704F
+:100A700057B4DAE1EB0F7E27BC002B08DE5C706810
+:100A80003B95ACFEAD5FFBEDE789B9E23B64BCC5CD
+:100A900031E423AB1FE6F779A924F94779DC457FD8
+:100AA000EDFFDA4FFB25BE4E0FCA4FA3D6D4A0B838
+:100AB00032E7525E77DC1CC4E6E9DE3F293D086C74
+:100AC000F55AFBAED73D15485F32C358CDD45B0A0B
+:100AD000AC1ECAE5810B13B67A55ACDED0DCF5BA94
+:100AE000845EFDE9EEEF79701FF7F60F5EB900E561
+:100AF00072D1232AF8D8B85DBB4390A67D4CCA8337
+:100B0000FBB485FBD4ACE7B81429C0F0B0E8FE1004
+:100B1000AD970BF77A53D359FB853F7A7524303C58
+:100B200074ADE87E6A10AEBB3F50F8796AA27324B8
+:100B3000AE6B0B35F8D75896FE2201CE87477E92D2
+:100B400047F78E959D072FA77EDB2F717B2DFA220D
+:100B50003FE0A679B17ADC1FB74B495567D127F240
+:100B6000FCEBC82E85C3B7DF9DF2237C3BB77AE24E
+:100B70000C8EC69DEF105F4DBE7F4F18F1D0B85F51
+:100B8000B59DE736EE54D3DE9194BEE2A57BA9660F
+:100B900050A9437C72FDB874DF12F29F2F6DBFF92C
+:100BA0001D358CEDEDFCCDF0124D235E9F57A3D388
+:100BB00031FFE0BD6183A1EAAD8E1D61C42BEB77EF
+:100BC000B6271FCF7FED7E6FECFF83C2DEFD31CBFA
+:100BD000DD83FCD5D8BE868FB7EF9F5F47FDD2E897
+:100BE00090A3B7F097B2DEE72E66C071EEB273C085
+:100BF00009D9978BF61CBB3BC1C63DB2F74F77278F
+:100C000018FC8BFFDF7B775F8F76D0637E1DF5400E
+:100C1000E30FFE330C9675F3D2005FC7BA76DDFBA7
+:100C2000FD3B997C74BDE8A5F5A3EBD1D787E03BEC
+:100C3000295D0FFCA5C460F5973D7A1EF901963D2C
+:100C400034B9B4AFF513F935E5B5C29522BA1AFB3C
+:100C50001534CE98A12D52077D9ED8A7829FC1F949
+:100C6000F60B5EBA1FD5C8BE2DAF457A2D21BD8CBF
+:100C7000F91B189E97EE5EFD8E3A321BBE13835C05
+:100C800078D90098184690DE5FFDCA17C760EAA6BB
+:100C9000F39546E826BDEA6CD7F81CA3EB59B9E9F1
+:100CA000780C3EF4E0E15FE3EE357CDC7646C7701D
+:100CB0006F3ABE8DBF8CEF4DC76F39E8780C16DFE9
+:100CC000732716EE1B90F53C589E9F2D79E86B7D9F
+:100CD000DA5B522FF487E7050A87EBBC80B92680E0
+:100CE000F2BAF787DFBFB388D3793A434CD79E6314
+:100CF0004380F1C91BEEEECB513F763FEAD571BD83
+:100D00005FF8E8F3246F5D0F3DE331C84E87A0C262
+:100D1000EC8D2EE8F9E940FB63293FAB82C6EDA1DB
+:100D2000B4379CA1D7D2D4850D4698BEBF42DF53BD
+:100D30005C0E96A60E5EA464A1DFC100BFC70DA91C
+:100D400062C2CB92EDBFF540D04E57651CD2F395F1
+:100D5000A9F83D173DE5FC759CFFD916BA6EE7F280
+:100D60009B4B4EBBB67A358C6770D2B94BBC9BD2CD
+:100D700098529ECF4677B90E9EECB9EA01A77C8BBC
+:100D800079F727DFFDCFE7E4F0F5C38061E31B8946
+:100D9000B7231F66D7FBCF0B7DB1149A1A060EED51
+:100DA000BD0E6A6CE339A82203EF118C7364FC76E4
+:100DB000E4076A2AC1BEAF6A7F82F4B7534F2CCDD5
+:100DC0006167BF21C7DB7F7024EAB3238FFF84F8FC
+:100DD00071E9EE573CE8AF796AE7839ECEE119FEF0
+:100DE000C775C1FA7EC691FB0E8E24FD8DFD67A1ED
+:100DF000CF31D17FE3017BFF8DBBDFB1F5BF28D1C0
+:100E0000EE21FF6A3FE3BCA59997E07CDFEA70031F
+:100E1000BE97F456BBDA90CD0E7A29E0B6C553AD35
+:100E20000AD5BD80FE49B5D063A0FE6BB9D17C3E2A
+:100E300081EBE5336EFE8EA566BE80E7D7C9028FD3
+:100E400081FBDE96D0C56058F4789B039F7A913E73
+:100E500009F703FA94D818EBFE4BC25F60BA6CF046
+:100E60002F0B35941A41BE8F33F07D0A2D4AFE694F
+:100E7000353CB581EED5EB2EDD9F75DDE6FDB98302
+:100E800031DA77B975171816FE1A35F9E233D1053C
+:100E9000A78161DB0FAC9BC2CF83E5FCD70D86CD6C
+:100EA000C0F4F03AA5FB30BE439498C6E30BA57D91
+:100EB0000762DF1FC67D7F456F7B0F4CD3407D44AB
+:100EC000EAC8E0E39B96FBCD99F85D305C14C71C43
+:100ED000A54D8006718A13F26194C550DC77B55335
+:100EE0001A64EA0DD373F3B85EF24237E56F6BF81C
+:100EF000039D7394E6C5C6E41563BE50E1F348D381
+:100F00003E4F5EDF77E59597F5A50F608A76C4EAD8
+:100F10004FF2C266DACFA03BF3E30119BCC8383BFD
+:100F2000D9EF3AFF447A1F03E73908DF6BC3C78D57
+:100F30004AF8F9019FB749F96299778C8335F53AF8
+:100F4000B1049368C615F750BCA7D7467E9381D0ED
+:100F50004E693974505AE8D3158DE07B99FC5D2EAB
+:100F6000F8037C9CE780EF04EC78A7FD7D9D6ABECA
+:100F70001867744C8A7DCEFA027B1C523C8FEF13AB
+:100F800096E5B964DC73DCBA6F4BC262C281BF887C
+:100F90003F4B26DB7D372FBE20CFB29F55831D3CB4
+:100FA000AECCB15F3E4FBD81CE455647FA8EE75A73
+:100FB00029E2C27395B715FB666F05829FFBC114CA
+:100FC0001F8FEF36C1D0ADFC88B13D75D67849D3BF
+:100FD000F68E8E1BF950453C2728F5A35CB1340FE3
+:100FE000F98AD1E156C18721E8149D7493FF639B70
+:100FF00027BE0AE71BA96A52F8F7B8C2FD65A68AA0
+:10100000F32D11FDBBF21697C5FB9827CC647C62CB
+:10101000899B592FE8A269A0056A119ECD82FE4ED8
+:10102000FEB4C7BF4ABB2E28725E1187F7E49867EB
+:10103000E97D31AD2848F12FC1312DDF708DC4F924
+:1010400037E9A8578332BE25CAE315E5BEDAF9EEC3
+:101050008BD71117EB16FBF75E71E2623DBE153FB1
+:1010600064B19B9DEBF17D7939DE131A973D1E51DA
+:10107000DA699F94FFE5FE73B1AFE3290242372995
+:101080009E53137E8B4917E9E46F3FBA5BE1EF1182
+:101090003AF8E9E8DEFC91A82F519EF15DF33CF1AE
+:1010A0005DD97DF020DA572D61300B0A49FF192AEE
+:1010B000C3FF2A65944F61E9927DEF3CFD08FAF188
+:1010C0000FA880EFB91D0DCA7350B3008996076B46
+:1010D0006D74FEA4F3EA7D8EC9E5EF6A5DCA5F9088
+:1010E000DABDBB5BA17B622A9C7907BE73D578D839
+:1010F0000D2956FE2EF07EDFDDCCED86F93F7BB06C
+:101100008E49026C14F0E0FA655D67063404C0B0E5
+:10111000F04944AE0B09B303DF7F9E2BF0531C2B29
+:10112000B4D593F3FBD39C86C3E4FF89CF23FB158F
+:10113000DF11B4F60FC23F62B07FC8974E3C1C77F8
+:10114000C53D40EB4A2C3F4D7610DB4FE3FE23A517
+:1011500044116EA73F65E97E85D6B3ABD87A86EF9A
+:101160004B5F9572EC471DEF224BFC3BF9D61D14EB
+:101170007C1B84600E3C47D3FC7C96E4EEEA9FF136
+:10118000B8B4ABF728F48E93DA797A3E10DE55F2D4
+:101190004BBD0E4DB7B31526C3DF0EFC792376BCCD
+:1011A000FB0D3BDEF36AECF80D45ED7874E2397F18
+:1011B0005CA5ADFE2275B187984FE0BB86FD437CF0
+:1011C000333D49F358CAE691367AE373C18175AB72
+:1011D000D05FD22F1E1DF81BE1C0DF313870909711
+:1011E00042CC5742A24FF32ED3D224574E39947893
+:1011F0002AD73B26D1B76888FCD411D1893297B75A
+:101200001BE86BE742551B253994F1C9793DEBEAA0
+:10121000ABF0314BAFB9F0D02B7320B7DCB537FB57
+:10122000A2739950DFD70CD1B9D5785EAE53BA19F5
+:10123000EB9FD5E77A4BE3B921AAD37A22CE4D8E24
+:101240000EE7EF5AB5A7DF2F41FBEFD6DAEE0BD052
+:10125000EE6FBC92C75B7E2FC4D7DF1F8BF4FC9070
+:1012600087F4DD4D311798E82F38A0A614F443E930
+:10127000E6CFCE45BBED80DBA0F54FEF7EFA5FA851
+:101280007CB48EE7CC65AEB651382EAB4FFEFEA3D4
+:10129000075E0D5F61B18FBAF67FF70BB83E6D72D6
+:1012A000C1826CFB80F9413E7E57CD1F4A902D973D
+:1012B000F8BA695FBEBAD3EE67F3ECE37EB8A5FB7C
+:1012C0002F247BF4D03CFE0EE74347F87DD4A9EAF7
+:1012D000AC7F1AC1F2E3FF53E37A15CCE9B34BA814
+:1012E0000AD133E9677866785C8FF19B28177F74A1
+:1012F000A5F0EF1C8CFF227FE769FC8B7812C68A71
+:101300009AF8BBF18F84A71EC674CA0185FC478D6D
+:1013100047F8FA36B6C3EE273A7B0AD30BACFFBACE
+:1013200003DCBF55D7C9CF07CE7EC15E6F7CA73D1A
+:101330003FA11FFE5D1914FBC830949C4C7C6EDAF3
+:101340006DAE0D72BB8AEE9345B5ECFBAF57437C97
+:101350007FC4F041F33FDA0DD1156C1E47E70E9CB8
+:1013600084F7938EBECFCF1B8E7EA83664DB5F6D75
+:101370000D727ED9E4E1E7C79BE6055337B2793CAD
+:101380003E6FE169B8AFFAF3B7E2A7E97DD9254C22
+:1013900045B8684D34F3611CCA470BBFE7066D655D
+:1013A000D9DE51967221E544CA47D9BC403C9B5FC7
+:1013B000B45ACCAF7E5E0DC5E3763DA6D01953D7A7
+:1013C0000A06571F784CC08A41084FE3FEF7C84F02
+:1013D000E13B90DDDF7D3018E67CBB2271E30486C3
+:1013E000AF6F32E14EA03C78DA2AB2F59F80F5E487
+:1013F000BFDA19E4FCDCE5E3FB70D0DACAF0BD88A3
+:10140000AEFD93A7AD6270DEC9E40FD7EF4DEE28B5
+:10141000C19D5802F4EE1F887B85E517C0D69B2C32
+:10142000FBB59F07273D1F64F37C3EC8E39306C4CA
+:10143000A30AC21DFDE87818FB3FFA8197E83750F0
+:10144000F88B64BB7783DC0E5F1D329F217E595081
+:10145000444A311A0F47E78E06386B3FC3779638F8
+:1014600033691715C6990E1C83EF58BAF87918DB43
+:10147000A7E1FEA311E44F828C54297F78D90DEFA8
+:101480008949BDAB1C50D221A63FC7F88269F4CB75
+:10149000142E70E1DB3BCC1EF5F1FE3AEC762B6AA4
+:1014A00060D4BFA80378D03EDF1F497D2CF5784B70
+:1014B00001D77F2DEB34D28F9BB54E3FFAA52B4C35
+:1014C000A35E33E8FD568AB718BC80CB7BDED02DF7
+:1014D000053D76D10480073E52B3FA47CE10FCB4E6
+:1014E0003A14FF0BE27BE4E1EEC7D1BC8AFA61005B
+:1014F000D27BAAB07BC6BFCDF591BC5FD028F625C4
+:101500004E7DB4C92FEC1868FB359EDBFFE48F1AC3
+:10151000DD9FEED13FF3A6D27A0AEAF02790BF26EC
+:10152000FC5C6C0F84FE61BB3DC2CBD9BF88271128
+:101530000EA7BE19074C2F29FDEB1D279D9911DE23
+:1015400093C710BED187999C59DA3BF5D4C0905807
+:1015500067859E3A06134BCF3332FC54BB3CFA846A
+:10156000D7C23F524F65F829457CE81C47015F4FC1
+:101570005E1F8AFAE5172AFA518E4EE27FFFE709CD
+:101580009423468782F753D3901FD61F38DF8F7C72
+:10159000BFF7F0641F8AD5D5117EDF4C3B7851022E
+:1015A00004FB58CF95DDE0338235880F17E141D534
+:1015B00059DE32FEBB6D8AB86F69E45F94E55D6CFD
+:1015C000995E1DE1F7C9F61EAECCE7FBD134D1BD63
+:1015D00087EF85FF42CA85E477277F4B7948B2566B
+:1015E0002E8B1DA12AED62FF68F72324851D91949F
+:1015F000EFCE24CAC83E5C26ECC36470D8CD13D9A4
+:10160000AF2DE97A1DCF3D96852A29BE7A5931C77B
+:101610009F131F326DFC80D98B9638F846AD9BFC2A
+:10162000638D1F786CDF257E73E145E2F71CC4AF44
+:10163000F2C9F17B4EC820FE70E2F9D3CEBFFCEABE
+:101640007159EFF1FDA3CC7F02C41FE9247F2CBFA9
+:101650004F22F94DEA8FBA6B5A937946465FC8FB21
+:101660002052EF48FD72F6E2B627F2B2E80FA7DE8D
+:1016700088BAF52BD632FC459F0CD23B1D4E3DF26D
+:101680003EFE52467EB7BB434C2E1F78EA2D17FA1A
+:101690004D1E7A98CD9D95470F4EE17EC18E133B2E
+:1016A000EF9276ABB4579DF5A4BD2AD71D79DED451
+:1016B000118AEF09317C29FB993C313C2475BE4FDE
+:1016C000FE7930DE8E70E5319803180B5893AEE04A
+:1016D000FB59BBBCE692CF3C87FCB5A7355AFF123D
+:1016E0006CFDAB567AC321C79F1F12EF0930AE4382
+:1016F000BBA6BC0EF8604BF97B01E523218EEB33D2
+:101700005E2BC5793E2DD6995F85F8FA2CD39F07BD
+:10171000633F45F8DD1A24BCB59F1C6EE95FEC08F9
+:10172000994F229E7C0D26CD63900E51B4F7076928
+:10173000ED4A94C151B8D8507A9C3D725D67FD0D59
+:101740009A6E4C42391A84770AB03EDA4759E8F368
+:101750004A88FBC197F83A9F4213BE717A5343B847
+:101760008FF3F5CC3B0851E1E7B2C7811C7DF4F95A
+:10177000C178FEF9BB6FBF17C273ADFFD2BA430881
+:10178000E71B37FC3A84F7217E7703DF7F5CEEB0FE
+:10179000733E10F8BC241C3B8AF3FDD7E68FEA6C3D
+:1017A000EFAF2CE7E73357A554DC94F6F0FBA29D8E
+:1017B00079E4DB93F925ED036C79C9A74BBC3C6E4A
+:1017C000CB39FFB3C2FC1CFDAADD5B3D830C1C3F83
+:1017D000AE84D9F86F083BEE8D7D21F27F4878E624
+:1017E000EC1EE5413CFCD701AF38F7EF7073FC9B72
+:1017F000D3F17C2E2E48E184F3A9C7F2A8BF2B3782
+:10180000A86477CC66632D67FC1D3F7015EDC39D02
+:10181000F3B8F277C6D45246BF2BD72864AF62FD27
+:101820001B183FC497AFA6733CE73C67271CF12306
+:10183000C2AE70C699CC3FC0CFDFE78271F3C48AD5
+:101840002C712707A6D1B9DBFC7EF63D5561B1EFBF
+:10185000A983B3316EFE180CFFF7E146FFFB9E37FC
+:101860009A8182C8DE6AF6517AA459A7F428EA4F11
+:101870003C3FDF7FF029E233ADA30EE57EEFE15779
+:10188000F32E35327AFC4B5BDF7BE22E961F0DDCAC
+:10189000CF23FDEDB304DECF15FA7CBEB017467F33
+:1018A000D0B73E9F85F818D91B5EA9C767E1DF2135
+:1018B000B4E041EA75273EDE3D3C340FF9E3FCB06D
+:1018C000F3BCF9D3E12557BB256AF678462947478B
+:1018D000439CAFE76EBF70D540367EF2D1D7877498
+:1018E000723DF11CEA09C9A7004D1E9463273F4AC7
+:1018F0003EE9E1BB03B7109E247F30B98A8873CEDE
+:1019000008EE0F9DFCD75F7C5397BB7308EA052751
+:101910009F7539EE43CBF4EB61EE7F9F6B9853716B
+:10192000BFCA969B55FC3C90EBA337B4B6A7AE4715
+:1019300079DDCEE565C98FF7FC08F5D0C2FB3784A9
+:10194000510FBDA9B595E0788B77AC0CE3B9FA1BC4
+:101950005A228CEDDF4CA959E31FEF0F2BF2EF75E4
+:10196000DAE224A0357101CAF19F77B8753C076BA4
+:10197000DCE9E5E7EEFB38DE589E9FB7EFCB1E278C
+:10198000B1F0DE0D25068FA7B5C74B6C7793FF022C
+:10199000FD6B384CAEF3E29EF3E7F6BECFD31BF7F8
+:1019A00089389B7DD3B2C64BC8B804271FDFE3E05C
+:1019B0005F861FF2FB25185CE46E17E7E4C95D77CC
+:1019C0008C7C85C17764FBCFC3CA70AB3F9E9FC739
+:1019D000BFDB7EC53D3E576EFEED12FC9EB1275229
+:1019E00059E32716BBD361DC572DDEEAA67DE0E282
+:1019F0003D2AE03B78F0A297D6F3457B9EFCCD399B
+:101A00000CBE450FB88BA6F369509C84A4574F1C9D
+:101A10008BA0CFC2079FE4E7CB86886711745AF486
+:101A2000C0410FC6E538F139B9FDA0A7D311074170
+:101A3000F46A7F652ADD27DC75DC83EBEC9B8F295C
+:101A4000F4F7399DED176C7D328CFA02F144710088
+:101A5000826EB9E396D2173C3C86EA91DFAE3F3AFC
+:101A600036A32C8E257EBFEF6106C78297BC143F3C
+:101A7000B5E0BE6B28CEE875AD89F3FD969525B827
+:101A8000FE2E70274A744AF9F705775F4BFC38FF42
+:101A9000996B4BC47DA432EEEF4994E13CAFDCFC82
+:101AA000359AE73C88133F2ED8A2C6D0CF724C831C
+:101AB0008607B2C8CD17F2B9DCBCBECD8B8FE8C0AB
+:101AC000EBC2CF997856157F3FD2795EC5DF8B394F
+:101AD00026F6DF1F89F5187075B3ECC71AB7AFEE9D
+:101AE000403ABD35D82CD5299E404B08BCD1BBEB24
+:101AF000EA33E7950AFD46EFDC483B68327EC7FAD9
+:101B00001D6E7AEFC6D2CEF65ECD32313E833BA05B
+:101B10009CC5D292EC7ED099F9522F88F81BC967E8
+:101B2000B9F4C0761ECFF2FE735CCF605C0E957781
+:101B3000B8D3A5B6781CAFEDDE7526CEC42DE4DC97
+:101B40005ECEE0A478991EFC3EA6A4F0FD63C92FEA
+:101B5000F3D67BEDF1793DFCE37CAFC71E3F33DF6D
+:101B60006197C9B4D7FA9FEF38AFDB7C62F1338B52
+:101B7000DD298A7F5AFCA297F6278BF7B8638897EE
+:101B80003FED7EE2379732BEFF53BB9463BBDE75F9
+:101B9000CAF182BD63219B1CFF291885AC72CCBEA3
+:101BA0006795E360E65CC38053AF77E7E7D0BB1788
+:101BB00038F0C9EC867C8C237EEB078B4E237F8527
+:101BC00003BF52DF3AF5E86B6183F0DC3BDE8FAF99
+:101BD000FB99784C8E47C99F0B7FB884C6E9E163B7
+:101BE000C9A7928F73C48D39F1E92C2F44DFD9D85E
+:101BF000DE7E91443DD4E0DF674A7A80BFF3E60A97
+:101C000044917FFB3BEF7C36BF42BEFB7616DF176D
+:101C1000F2F3CE6850C7BF5401EE2243CD76CE1EFC
+:101C20009DECCA6AFF27F2F9B9463EFA2318DE1E78
+:101C3000CE37F8BD0735261C79ED748F81CE56114D
+:101C4000CE8230C9995BC4A9B09EE93E7A34CFF503
+:101C50009EC1FAD892FFD4F91AA36F74B4EB9AA17B
+:101C60002CFF50FE4BE76BE8AF9DE07AB092E57F2A
+:101C70009CFF5B9E3FCB35DACD587527BC7CFE14AC
+:101C8000567FA998F752E92769196BF39368AE5705
+:101C90006EC7F31CED61372459FE6626F7BEDACC19
+:101CA00039739E17127E96CFF3B094E55755FC7AA0
+:101CB000156E229F0EC4EFCA277CD51B88E723BA76
+:101CC0008FE27796FDE43C8A237D389FC7BD9FF95C
+:101CD000E004FAFB8EA7108EDDF9C5B9E16871F357
+:101CE0007E8EEC3D7332E2F9CCD3D0A796A147ADFE
+:101CF00066D0773F437B82DBFD11BCDF922CF05036
+:101D00003F0FE74BFA9D582AE35ED43CCE176ABEDC
+:101D1000ABE901961E14FCF0B8C00BFEE0BEFBE878
+:101D2000A3A5DBF8BB56DD4390DEAAFAEEEFD1DEC9
+:101D3000ECBE2C8FFE7EC84B018EB797021C6F97AE
+:101D4000E4AF759FC1BED7FA865C834CFF92B2FBAD
+:101D50005A4CB7EBF15F723C401AFBBDF47295F739
+:101D60001B6C0AE17B718AC9ED708531D32C868F9B
+:101D7000A4098667288AB03DFE43556BBBD3347EE9
+:101D8000C8363E94B37593C9F925E339BD186E6919
+:101D90001D7D7E1CCF4BF866A62A939D06C1F37B62
+:101DA000E48F51DED460DC4F5DCACC2AC8F25E7885
+:101DB00057809F6F7661FB9199F881C6FF76D17E3F
+:101DC000B611E7C0F20F1E01F1770AF9BB3BD2EF63
+:101DD00031FE975793FF7BCCFE453CCE44F8BBE4E5
+:101DE000797EDD217E3EE7F46F4D80B5A44FC73B81
+:101DF000F4E884FDFF44FAB5BFF3B9BF48BD3A101B
+:101E0000069EE4F91CE896F3B9FF01DBE0C6DF00AB
+:101E1000800000001F8B080000000000000BB55A76
+:101E20007B7054559AFF6EDF7E25DDE9F48B100838
+:101E3000869B0448421E36498010706CDE4C8C1222
+:101E400060406418695021E6D56CD6416A748B0EE7
+:101E500041459DB2326A29556BCD5E18DC45496615
+:101E60001B4934BA9D4C0710120437082830AE665F
+:101E7000DC1D44973C645670D42AF6FBCE39977E1D
+:101E80002428F3C790A24E9F7BCF3DF73BBFEFF7CF
+:101E9000BDCEB91E3D7883F900D7E9DF9D91B62A02
+:101EA0005902980EF44F0729000D66FCA5005C3915
+:101EB00091990C385EAF07909D004645865267E4C5
+:101EC000B9B66D38CE14E9BF93ACB0790ACED81F3D
+:101ED000001BB5B00E0AA3E6B5F37917CA568012F7
+:101EE0009CFF12A8A60C8069FD392FCFC1BEA1C7E7
+:101EF000002ABD979EA0FBE7746A00459BD1FBBBFF
+:101F0000E2305EDA91602B84DBF195A93A50CC6C1B
+:101F10005EB88EFF1394445072227D4B8E33A62FF1
+:101F200027DAF64032FE0878FB52518E627E0B9221
+:101F30003CE363E679C7B6A487E42EB66FAC20B95C
+:101F4000934B3363E68113FACFFAB19F837FD73384
+:101F500069A995C96194BF082ABD12CAEBF9183C5A
+:101F600061947FC6193E4E7BCE130EC83EC4B1F4B9
+:101F7000E3D8EB6510D5C779B67EFC95E348943C71
+:101F8000A5F624F7C53CFC311EC65F9747C5D113A3
+:101F9000269CCEC81E540334F4E22037B65F800A74
+:101FA00088DB34284C0686AB0C2AF6DF04DF0B7383
+:101FB000B0BDB66DD8716472044F8737164FD79293
+:101FC000583CC754C6E23976752C6EE37CB138A50F
+:101FD000554D8DB97FDBE6A298FEC4AD6531E33384
+:101FE00002F362FA593BCB63C64F6E5E1ED3CFDE5F
+:101FF000B526667CAEBA21E67EDEBEEA5BD27F41C4
+:10200000B021665CBCFE6FEFF855CCBC65F25A1986
+:1020100032233C08E01FF1A088544CFA473D84610C
+:10202000A4FE67BA03C4F8BF59FF5B49FF9628FDB9
+:10203000CB6B937DD691F6ABB59A5EFF89D63A9D70
+:10204000F48A73A070D748CF786DC860DD2961EB42
+:1020500040EEACC5EB5BCDFCFAA3029F6B09E92A0D
+:10206000ADDF113AF657095B540BB3C3C02716B561
+:102070000979F3A8AC3412AF5E942B254079D25085
+:1020800075BA2CE4910EAAC8AF3CA7D3ADAB8C9225
+:10209000EF793B0E1E43AD8EB5FF6C445BC5F7A6D2
+:1020A0005920602E62CFD1DAE89F1770DD36170312
+:1020B00005FF55EC5C3001EF3BFA731407E02DECA3
+:1020C000DF06702191CB7B2191CBB9C6A434F59367
+:1020D000FF90D5C924CF5EBBEF5FECF89E0BD2E337
+:1020E000067C3318DC0103D95D9A1902367C5F93B4
+:1020F00001D65562DF016EA901DB6478C54EF68515
+:102100006228D7911487ABF392FBF1FAFB24C23813
+:10211000B2318F0E6600DCA7F9C3AA5CE60FAFE010
+:102120001AFB48A17A2519B0BDF26016BB7EFE7E6F
+:10213000B442B4A7F3468E8786C325E127BFDC6689
+:1021400066EDE56DF618BF59B5FB852405E7399FA7
+:10215000034B8251F8750BFCBAED32D3E7A0FAE7D6
+:10216000148267E8A1EFA690D07EA9EF492B0E79E3
+:102170006AD73F5402EAC1D8B62C803A815F18155D
+:10218000365E9BC71F9A0B84033196E6BBF723D8B4
+:102190004CF2DDFB1DB651EFEBB31BD8737DE27D36
+:1021A000ABB0B1236EAB502F0E6A8FCD5944768100
+:1021B000D7C312F697F68081EC61992FC340F29C49
+:1021C00006CFD97694E78F76FEFE9F41A581E4FA8B
+:1021D000F0FEBA241A77633E6D1E14D681F1E42313
+:1021E00047C090827E6BF80EC9B34761EF33D3F5D9
+:1021F000CAB5694F5895C8FB3E04DFC059D4F77281
+:10220000F0B079B5F9D1F262FCE21B55359FBA32D4
+:10221000C91FEAC04CFEB0D3C4FCE150F5B5D69757
+:10222000F0FEBAB4FEDB8CF8DC85EAEFA6102EF7E0
+:10223000ED924141FDFF39C9F739F147C3E3FC8312
+:102240007F49A2FB6B4CEAAB2FA11DC07E93E755E3
+:10225000A0E7F6B3E7B4715FD9E75EB653FC2C454F
+:10226000A066DDDC3E35FCE7BF9E3B9678A6F1EB31
+:1022700061C1AF86D7B2C7129F1A926EF08BF75F1B
+:10228000CD1A4BFC9A21715EC6CFDB85FC52B27130
+:10229000DDC82B0579D5F5CD3C17F98983279CC579
+:1022A00024A71E7C3A47141F0EBEBF268FEEC339EB
+:1022B000F72DC94BB6194039EF052EE749611FAB21
+:1022C00043AE62D23BDA9DCD81E3D6FCC76B037F80
+:1022D000247C3AF7BFFA188D29B9353C34FF7420B5
+:1022E00091C7231071CE2370C13897A3475187201F
+:1022F000D143F9C2CDFCD601F20BC8AB6B3A747C6A
+:1023000059E4AF2A81FC82053C0AB5E865DE9B8D65
+:102310007A6CEAD6C133D8B59153D3FC4F29F66510
+:102320009DF03FE035A7621C11FE29E737EA921DB8
+:10233000CC7EBCD6F533984B6472951CA9AEA0F741
+:10234000421FFA7194B512FF281ECC86CD87135018
+:10235000CE19BB303FC07133CFF1FB9A5F9F15D6CA
+:10236000AD3726D3B85F7F25DB08A2D83830FB48CD
+:10237000F9E734EF6C887A6E94F830C711971FDC58
+:10238000627C584C0100710FE670FF1E0C27AA8179
+:102390000C366D716501BA26B43DBAFFEF6E1E476B
+:1023A0008CD2608E19FDF05DBFD9B373E71CA4C356
+:1023B000248E0BF59BF4844531E3F18DBCF1C854B8
+:1023C000E60FE17B948AF0B20B99E3E42941BBE389
+:1023D000C1D8139377868F7E6BEBC775B43A95FFA0
+:1023E000247D0D635E437E2141DF6F748CB2BE3766
+:1023F000C9BF22FF9F77E898BCE60EC9ABE2FBCDD0
+:102400008A17245C4382DD3E4D9622E3173A78BE5C
+:102410005B77F442BA11F535A03B61CBC7F96BDBB2
+:10242000DFB0E1F2618BCD57457CAE39FFC10C0ABC
+:102430005D00BBD32B9308A7CC64B2A7023D04F484
+:102440004523E5F0EFC2C520E5EB77B9589BDB21CA
+:10245000B1F5F9C37C9D831D4DCE68BF71E3B93FD3
+:10246000748E27BDED1F03ABC91F17848A37118FE8
+:10247000491603EAE2F56FF2D87CDB1C194C2FF801
+:102480007E3D5D075075CB71D07E033E87F30E7E97
+:1024900023B371DABC051D73653BF2283FDC7C88F1
+:1024A000F2C2849049213D27EC058E4B2881F945E5
+:1024B0007FD762A0FC75C8011E09EFB7260E7F42C8
+:1024C000BC18EE34297B24C2AF199C387FAB91C76E
+:1024D000CF5C348437AC91EBDAFB12422F03F92B3B
+:1024E000E48757A5FBFA66B8C31A8D7B12C35D75E6
+:1024F000705EB526867556F2FBC8C93D4CAE889C09
+:10250000C0DEABC999CBEA8056E3F0C5C7DC4C2EE0
+:102510003BF12117B89C10CA565EA5E7ED5EB68E5A
+:1025200004BBE2094823E5F217625E8C76F7DC769D
+:10253000B861E764F7FEC448DF8C36D19AC9F90D5B
+:1025400081B33B17CC89EA93C32A8D3CDFEE38B7C1
+:1025500073C704561F0564E48305DB2427AD93C7C6
+:102560003F340DEF98228E830771B298F9FD1BE37B
+:1025700091EF56EA5BF9384FB2DD522E31BB01B212
+:102580009B7AE1671E91C217EF44D57E1D3E54A889
+:10259000A02CB5C7DE61BCADD1855E2A20FF98E8CE
+:1025A000FB03F9F7B73ED6810DD7FFE56B096A0546
+:1025B000E291F3F6EE14AF75E47C4F9DDBFE7C1ADE
+:1025C000E9FB6D4941A4312F1C4E27F9EA439F1BBB
+:1025D000BDD82EEEF89391E2D32F9CBE5EB283D28B
+:1025E0008EC6F984DF2C686EB25B995FF4114F835D
+:1025F000A9DC7F5C3933654F6314DE43C2BE60D80B
+:102600003791EC2624ECB38BF21F6CDB451ED6DE33
+:102610007D5F965210792E0087D200E7DC0E47D2FC
+:1026200008E71BF3A9FA25C4A7BC0FCDEBBC517C6E
+:10263000FB42D8FB17E27D01A7EF53C2A1A6FB33F3
+:10264000A30DD7E5FF9F603AC5A720E669F61FF006
+:102650008BFE38BBF1EB878D34DE7F09981F41BDBF
+:10266000EE48463DEDFFB063EA7A2B931F9271DD91
+:10267000EDE74DCC6FB66770FB6B3C7BB590FCD63D
+:10268000D5CE9A8984D7298741E3F9BC44B2A70300
+:10269000C0FC98668FF9648F287A3EF1BC84FAB941
+:1026A0006CBE56635F39B3BF761D90FD21CF19EF25
+:1026B00091E776CA3FF2EDC87BF67C36B3E7D63EAB
+:1026C0000C78D80FA01F9FCCFAF35650BFB56F817E
+:1026D0009DD9B30EA12D22BB0C1F62F304B1A6221B
+:1026E000D54950199DA72E74D898BC9A7F5C21ECCF
+:1026F0003498A3247B703D16598EB183A878C9FB0A
+:10270000229EAE759A9E7E71025993880B222FEB02
+:10271000127930F88A99BFFF4711CB1ADE2D5BDAA8
+:1027200082EB6D382973FF2F787248E4C947B6A54C
+:10273000B23EC50B05F5341D5B2FFAD319DECDF380
+:1027400029FC942E693E4C6D596570BE81E2E2EA27
+:10275000BEC3066ECE79C4BFB6433FCDD313DFCF21
+:102760009B2001456CFB76F893D711872D5D88FF80
+:1027700028710997C3F887119DF1F166BC1992FA87
+:10278000EF99EDC1FACF39EEA7FA04B41F2206E2A1
+:1027900071BB73ECD30114A8C3E92D72227E9FB8DC
+:1027A0007CAC1D3AF56D0AF9F4F6339FD9C8DFB752
+:1027B00019BD79C4B3B64CAC1746E1E744A781F91B
+:1027C000FB12536C9EAEB52B9DBCAE9A12806789EE
+:1027D0003FF56DB25D457D0FB4C95E23E65117BD6F
+:1027E000BE143D427A0902AB66537C17F5EF431CD9
+:1027F000767888F2178C331B5F34C4D4A5B5625F3A
+:10280000231BFA9F4C439CFC7B2556D756C5E523DA
+:10281000B594BF14527DB1DB48EBA9DE1B370FE541
+:10282000318534EE87EBDC954E91C7644116E53176
+:10283000C823564F0F9F953D7B2806EAA1C784FC0D
+:10284000DDAFE338A1DF64F6A8E533896EEF22B28D
+:10285000FB450E9EB7B48ABA75B8555299FDEC4344
+:102860003F8FFDB24BCA6EE0389C499D41EBE1BC05
+:102870002CD3F3F165A10C667FA55EACE771DD1B7F
+:10288000B19E5769DD5A9EA71AD8FA31FCB23C6F47
+:1028900016A84D361CB7699FC4F67D6AF61962F218
+:1028A0003CBFC0A776D7A9A3544ED605E3EE0B7C58
+:1028B000FC71F8BC413F668DC4E9574EB11F900EC4
+:1028C000E9D1F91EF43847AD0B347CB43CFB7F0DE5
+:1028D0003CBFF840CCAF8DDBE5E47EB4DE0B6CFF93
+:1028E000A856955595E783D6F5C89707045F1E103F
+:1028F0007CF1031F57B74F52C314AF7ECDF56EC6A0
+:102900003FC2E5A1E0FA4569CA485E550B3CAA5AA8
+:102910000C2CFF05D86C24FBAC7A256E9CC0A53A24
+:102920000E977A9F14271FCFC7FF56F96A0C7CBFFA
+:10293000A606F91550FE7EF2C6EBEF0D8DE753614A
+:102940006A8CFE96B86E497FF179F281A3532DF41B
+:10295000FC959E4CB60FA1F1267E9E4522CF5EBC13
+:102960008BE7A3031DF32D05544F9DD07B249CA71B
+:10297000F8E4FFD90A108FA24E192A708AA150F1EB
+:10298000B3015CE7C19E492B148C0F4527F52CBE83
+:10299000149F2C52A9AE293A5964C94A62C6E3A2CF
+:1029A0007A01E761F179E8C4A4D3F9E4677B16946E
+:1029B00010EC8D278A2C94471C04BEAF219D2C71EE
+:1029C000F547C59BF79C325BD793A9FFFD1CE5F942
+:1029D0008B0F183C948F2C360CBF3FDB4DEFD77B11
+:1029E0001AB15F7B72C3F604D2FB6B9287D2F1A35C
+:1029F0007D0DEE9F937E4306BB89C9FBCB43743F9D
+:102A0000D0227926E3787FE7C2BC56EC17ED2EF68C
+:102A100010CCDAFB8A1CCA0B15942F8EB3B03A7E09
+:102A2000F16D0616772F8FB7FC8EF2A56AEFEE4593
+:102A3000E48F2FBF73D048FE60A85582545CC8D184
+:102A4000D4C3BF0FE03A2FBF79CA4849F9FCB65347
+:102A5000C6FE1FC827065419C2AC7E6F36521D54DD
+:102A6000B75BEBF71B494F9522BFAADFFB27D6AF19
+:102A7000A63A01DF57FD8AAC2AF8F370E75B46C23D
+:102A8000BBBE4582B11951F7F74AECBEC6FB0DC07B
+:102A900079B041F8A71AB10F5943FB90781D7672AF
+:102AA0007FA3F1FEC17DCB8E52F87EA839D60F3DB3
+:102AB0002C78BE89EA52567FFB8CA4D74DBBE2C668
+:102AC000099E3FFC233C4F76093F950BB9C4F3ABFD
+:102AD00073793CB97A2AD1928FEBBADA2B7B007EDC
+:102AE00090EF2CFE9E10F9C295B08EC5336DDC6060
+:102AF000C75F58BCF19FB862A4FC7651E82BA68F43
+:102B00008A50F702C2FB6EF0D5127E77872C76B220
+:102B1000FF8A7EEE0FCA432695F6C1EF86E00ED2FD
+:102B2000F350D7BFED70126FFE95F30684BFDB2420
+:102B300070DD2470DD840EDF852EB63ABFFB252CB8
+:102B400007A01CB81F2A0F0A3FF44A2CCE1879EEB2
+:102B5000277DD5874CF00CDEBF4BF8A3BB5AB83F9E
+:102B60008A8F93F5621F60685CDE52B6DF8AF52EAD
+:102B7000E571B52DB1F8D78B7D81FAB8389CE9E2C3
+:102B800079C28FD5FFF17A5A10A7A78A61CE9F72BA
+:102B90008A7BB8FE9EF0F67CDAB7D3F08AD7538FE3
+:102BA00092953C5A3DABB5EF8BBC5FEB2F057EFE9B
+:102BB00014B4375BA3EBF8D75D3CFE54CF9203A46B
+:102BC000E71BF5CEA4C3858A2E52EF609DB3D635A0
+:102BD0009DD73DD370EA63136470BB23F5CE53A930
+:102BE0002F541451BED2C2FDC86029CE974CF93C77
+:102BF00030FFE56F31A954A7F8913FACCE21DE60DC
+:102C00005B199216126FB07EA872218ECB68EB18FA
+:102C10007158D6C1F39E650BBE627CEB9DC4D77B19
+:102C200045AF8C1DAD9ED0EA88FA6F789EAA5DAF45
+:102C300047BBA7F1F52189D5C56D87FE9A9E81FE18
+:102C400073A8F35AFA7A6C5F76F13C4ECB53873116
+:102C50004FCD14790AE5CF1BB9CA6013A6C35B91A7
+:102C6000871B459C036907B3937A4A76896FED12F7
+:102C7000DFC7791B2FCC44FFFB4122CB63063FE427
+:102C8000E743F4FCE398470D6E081E71E2F8ABAD24
+:102C9000128B7F1B31C7FD49D1487BAF13BC6C84BD
+:102CA000EDA22EDBC1DAF29C039F3D46FEA8C5AC27
+:102CB000907F1DEC6832B2FD6535EAF9CC91F95090
+:102CC0009DE06FDD8FEC6BBD1EC74B5C07CB6F8744
+:102CD0007A65BB4962F8FD767C344E22FF693B94ED
+:102CE000C0F43C74CAAA529EFFA5E0DF65B1EFDED6
+:102CF000582A335C74B3789BD7F55626E995F4E0EF
+:102D0000A37D94AEB7A67AD93E9FCAF858B34FA612
+:102D1000C3BE88FC410BDB0BD5FA1ABE7E812FCADD
+:102D200035C5E88EC8D5AEEFB77946B11B493AC470
+:102D3000F4A69362EB5CFFDB72A51A654FB89E7533
+:102D4000E4DF42821FA01F4E21BF1C76294CBEC665
+:102D500010D7B3AE93B7F8FE557CDFC6C0DE3FE2B6
+:102D6000FEBC402DDDBF9A6101C6936F0215D4DF12
+:102D70009229333FB5E583EA6C887A3F48BC1EF759
+:102D80001B8653583D7C4AC7E4F39FBA9232C94A26
+:102D90007E70F7027B3EF937EE1F8E665AAA88DFF7
+:102DA000017AEFD8C83CE52E7E9E00B4DE54CA6698
+:102DB0005EE4F38AF56E87E50C87ED8267DD221FFE
+:102DC000C5BAE93CD9637CDD74B37C37AA7E6378ED
+:102DD0005D9DAB9CFE39F2A0A8571FA07AFDE0399B
+:102DE000EE271A3B377D4A75B0FF8209C84F6CE960
+:102DF000DA944D71187CBEDB29BFBBDAF5F0ED6CBF
+:102E0000FF52DACEE40A907CA994379D4DA17CA8AC
+:102E1000AEF36C0A8BEBEDD35FA03C09F3A2BBE8E9
+:102E20003AE62B8C7F45274B18FF0E9E2871659143
+:102E3000E0E0B1D0BC75BDFA4AC2A7AEB7E4BD0AA6
+:102E4000CA5F4ECE637992961715533D4E7952EF75
+:102E5000A4983C69D8C5F3A4A1EE04B6FF2141268D
+:102E6000E70F4C8AE14F6DDBBB2C9FA8ED90BDD1E5
+:102E70003CD29ED3BBF57C7FD42DF81394BC8C1F21
+:102E800007785BDB7190ADAFC61064FA6E6C31F001
+:102E9000FBADBC0568E6FB2CE00C101EEFD125D481
+:102EA00043B9519D40FBEBC733787D11AF8F67DD90
+:102EB000FC1CEBF879DF44E2CBF1B9BE6CFB287166
+:102EC0002300F378DD2D09BCDB0C2CAF8C1FF7B48D
+:102ED0009BEF4FD85C1073DEA8B5BF7473FE941BD4
+:102EE000F93E55FCFDB96E614F289A0E7971BAC250
+:102EF000607F46D413E3D0DFDE23FCED8ABB0D2CCC
+:102F0000EF382DCE99EED1FC6E298FDFDA7EFFB23D
+:102F100057E0092CFFE16BC867E760CBBCB17E6F5F
+:102F2000A5C8AF562C89BB2EF2A9953F924FCD7202
+:102F30008BBA610A4CE17583D542FBA25FF718ECAE
+:102F400032935B9D545930729D9ABF392ACE877A4D
+:102F5000D00F52DB98FB11DBA73ADE7DFEF70EE6C1
+:102F600047132093EF3BB2FDFABA9BECD737DEB0A4
+:102F7000D39FC5F04ED3D300E5F9F923F5B452E061
+:102F80005D67BE6C64E796B079A74E8E9C539A0C31
+:102F90003E6F1AAEC3D031374CE7978DB926962FC6
+:102FA0000D2C9454F2F72867BA29CADF0F8CE3F985
+:102FB000D7965512DB17EECEFD88C5F1BA709F91FA
+:102FC0007835A56DFD13CC7E037086EA254D9F4BA9
+:102FD000CD3C7EDED0A3B65EBAA9D0FA9C01EE97B6
+:102FE000DDACA5F1142FEF11F1716969ACFEB2A14E
+:102FF0006F11ED8FDCEB9558BE7433BD2F5F3DED47
+:103000005DA2DBADEABFD9EDDBEAA6FDA2BE2BAB2C
+:10301000687FF778EEE7E9145FEB6FC2E726C177C8
+:10302000BF859F8BF92DFC3CCC93AD34F5233E2618
+:10303000876FBB9BFC87EE7BDB54A079FA7FDB209C
+:10304000917E80E9E56676F4B498F769B79DFB6FE9
+:10305000373F1FB2529FECD9A04E203F01F9B776FF
+:10306000CED7F8F6B142D2D360776FA1314A9F979D
+:103070001BD01F507CE93C9CA258A3F9A6137CD31B
+:10308000B35692968BB819CBBFCBC43FD2FF81C346
+:10309000F7505D38D0B6C22D295171B5FDB46D72AF
+:1030A000D4BC0321998DC77A6CCACAA468399F60C1
+:1030B000720E04F97C00FD53561444DF6F123CEE8F
+:1030C000673C7E2A67333B77D778AC07CEE3FA8E2E
+:1030D00065C0E2945877D0883FA8CEE832A9744EF4
+:1030E00041FBED8E283B392EEC63261607C4CF59E1
+:1030F000109069DE9938E35AEAEB21AC77D2796017
+:1031000058E6E7DD1380783D43F07AA63EDC2D15C6
+:10311000B271EC5CAA0CFAD8B89FC0306BBD60D716
+:10312000533B0F3CAC2D3587EF2277921F0CB2EF4B
+:1031300092C2297AC745333B2A85D1F41759BF1E5D
+:103140002E6A3CC5C198F4B07DFCF8715F0B7FEF2F
+:10315000A11C8EF43C006C1FEE0EE897E925B3F538
+:10316000B084BE27BB430FE64494F7C0111DB3E7FC
+:10317000AE7E45257FE67189E7BEC0E7B03FD3CB81
+:10318000ED9642107DB7A2AD371E87329C8FF605B3
+:1031900067EAB1F2653886D9FBEE24C171DD73416F
+:1031A000D153FF923B437CEFC6EBB4F9A24ED399C7
+:1031B000030C8F418A8F63F8798E0DE7296B96E0B7
+:1031C0001C9DCF64F1F56AF39761284DA67C5AAC3B
+:1031D00097B6C2CF39F9398F8D9DCF2DB0135E527E
+:1031E000384577DD72EBB80EA50093DBF6C0F0E052
+:1031F000632591F32E4FE8D839FA2E47F27AD97722
+:103200003D1EB3354CF939B2E37274DEAD1BB30128
+:10321000C6E0FA24C5CEF0021F28947F8C8D7CEF87
+:1032200002D75D91EF6908C64B2991F37DEDFB9ABA
+:103230007DEA7245877A59ED367B482F45E6F46280
+:10324000AA07F7DA7D30867D67D332994DA657A756
+:10325000572645F86E016F29E1AD9DEB4B427F3754
+:103260003BB7275B259E5BD0EDD37741CFA2BD98BE
+:103270009DA37D7FC4CFF3D10A15FAEE081E9FAF40
+:10328000D077014F3ACC9E67C8CFD1FA2C91F53553
+:1032900099F9F7044D66FE5D00EC98CEF6CF1E114D
+:1032A000E7114D565D0ED55B4D90E8A1925E93F708
+:1032B0009124CEC747FECBC2CE47E3E5FE3ED19771
+:1032C0004FF86AF23F2A7BCE61EE1383E71C0D4F65
+:1032D0005D04CFD56A6653BFC2F02BA1E7A799D48E
+:1032E000DB685F648D897FBFA4E1860A65A4B60BA5
+:1032F0007D68F8D949DFB40E2FEA5BE34B6604BF63
+:103300006713396E06FA72228B3DABB0F3FC385C62
+:1033100034DEFD3FD45368B1102A000000000000E5
+:1033200000000000000000001F8B080000000000EB
+:10333000000B7BCFCFC0F0A31E81FDD1F8E8389100
+:103340000F534C94118257B3E0D78B0D5B3122D8C9
+:103350009EDC0C0CB29C0C0C7240DC01C49D40FC49
+:103360001288B5B81818B4813801C84E04624B20D1
+:1033700076E086E8A96567606805E25E209ECA4E31
+:10338000BAFDBF2518181A6411FC0B4036AF02E9CC
+:10339000E68CE2A1897F1BA2F245B451F9F6BAC0CE
+:1033A000F46184E08B6A9366FE36A0DEED46B8E5F4
+:1033B00079CC51F9CC96A8FC6E3354BEAA3B840656
+:1033C000009B2185B9B80300000000000000000048
+:1033D0001F8B080000000000000BC57D0B7C54D53E
+:1033E00099F8B977EEDC794F260FC20021B9794000
+:1033F00002267188E1A5A013040B886CC017B4AE37
+:103400000EE111DE44B49AAEB8B99010420861B42E
+:10341000A8C18D3841405468830D4A57AB03524BC5
+:103420006DB71B1505772D0D688358A0298A4CFFB1
+:103430006BEBFF7CDF393773EF6426E0BAFFFDA743
+:10344000BF7A38F79C7BEE39DFF79DEF7DCEC8243D
+:1034500087A4DD44C837F0474BBF891032205A9209
+:103460007255206308F9A195E09FD62FB6ACAB2129
+:10347000246C2124B290904E27ED28555949212DD6
+:10348000EF982E92744292E07D85907AA1EA686E60
+:103490002921EA5091ECA28F3664CC4E0A38138F62
+:1034A000BB978FFB931A2B96ED351E2C5FAEF16206
+:1034B000D951A390703E21AFD4146079B0C687CFA4
+:1034C000FFB5661C96AFD7F8B17CA3662A96E19A41
+:1034D000722C0FD7CCC1F2484D00DF7BBB66319612
+:1034E000476BAAF0F93B35D558FEB646C5E7BFABEA
+:1034F00069C0B2B32688E57B352D581EAB0961BF84
+:103500000F6BF66079A2A61D9FFF47CD412C3FAE01
+:1035100009637937494678DE79E725EB3CBADEFC6A
+:10352000671E7C6F5A1A215B468B3E0057FE339F05
+:103530007A0385D1756FF99B694E7B1CB8DC450415
+:103540001C678B8B60FB96431F11A58890E6D15DAD
+:103550005E95D6A7F1EF8CD875CC3AAF30DA2F76DE
+:103560009C3F12131BC74CDB69BFE1DB587FAD7D6D
+:103570001A7C6774B47D77CB7BD6F94E7D3B7BFF9D
+:10358000F9D6F7AC80BFCD11898411EF2A21B4B4EC
+:103590002B3D2D03289E6D272CC4924DF1AFB49383
+:1035A0002E3A4EF3F827C36229AC9B7653609DEF09
+:1035B0001381C2417511A40705C6181BFDCE582200
+:1035C000E23CF29F39C6BE73C7252CDFF8AB4C082E
+:1035D0007DAFF94E21E4A0E3374FBCE8F503BDA968
+:1035E0002F9880DE905C15F84F97B79C8EBD65E2F2
+:1035F000875E95C269F3DFDE9F331FE86F14F1C168
+:10360000F7361FFA3951A0BDA807E157CBD7BD79CE
+:10361000EEBC2C4F6162BAA49444C47174B94EE2FA
+:103620000FC581EF3F0210287C4C9E10AEC94EFBA7
+:10363000C5C3C33F1219FB6D76957F007051EF34FF
+:10364000FB76D179DFEC0B936E6774DE50FF84D686
+:103650009D5F8689C905F33EEB35D1F53BC6C9D7D9
+:10366000D9E86C9C3D3D27E07DE784457E587BF39F
+:10367000A82EEF22DADF5AD089EB253EE21B46C79F
+:10368000B517A8647E21C0C184788D9DCF7C80F75A
+:1036900000C0D3575EC08946871FDCF1BEB542D754
+:1036A000FF798D3E04465FA4296C9DE58AB63FA351
+:1036B000B5DB18FD10ABB17D5B0C1D938C04ED6682
+:1036C0000A68C49718DA2520DCADB38BFACEBB2983
+:1036D000FC6BDC074E5FD81A88B32EBA4FACC077AC
+:1036E000924A451FC0AB7922DD2F85D1755E69DF17
+:1036F0003570B86C2E9DED82F1AFC4B78ADA4512F1
+:103700002EE03C93FEFFDA83763AF3687D5438C5A9
+:1037100050BFEEE86043FFD19D3986F6B127461AC7
+:10372000DAC7779518EA377C76BDA1FFC49E498633
+:10373000FA4D91E986FE65E47643FD66EB0F0CFDDC
+:10374000A778E61BDABFE75D66689FA63C60A8DF46
+:103750005AF088A1FF6DBE5A43FB3F8CDB64689F23
+:10376000E5FFB1A17EFBD47F31F4BFB3FC3943FB4D
+:10377000DD735E32B4CF0DFCCC50AFB4074E027E89
+:103780007EB0F835C37BFF58F596A1FE012153E3C7
+:10379000E197088CCF500AF2745FC3FB5316E70120
+:1037A0009A033A1EC0E8B4A02D019FE4ED2FEC7CF3
+:1037B000CFBAD0C027CD8C8E07B1F63DA1F7E2BFBE
+:1037C0003F94EF13D2699DEDD2B7B3795DF357CA39
+:1037D0005FA15D52BF157F75797CD85FE3AB94BE66
+:1037E00009B99EC2571DA2AAF83D3A1EE59726B612
+:1037F00064524D189F22E4017CAEC97D9241C226DD
+:103800003A6EAD2BA3AD116042C796D2A05EB8034D
+:10381000EAA2E2275D71E06AF2C8063CC5C29738A9
+:10382000532831F7C76755849F3A851448F07DC106
+:10383000EE5B4BD72B91C060813EBF2C06BC30F9AC
+:10384000874DEAAF02D9D1FE6B27D27F42FF5342A8
+:10385000681DF657108EB545C40F72431D24877638
+:1038600065233C2DC04FB4F7E803A58BCD57FD264B
+:10387000D75067F3BD62FDEB7C635D1BF79F8CF057
+:10388000A47086FA7DBCD267DD3E394AB726E8C708
+:10389000EA8A28906F900F1ADBB5EF5CB6B98B49B6
+:1038A00012C5A395950FDBDD3BA0BC6CCB0C11378B
+:1038B00021C562609240E1A04E62F0514F3A42B59C
+:1038C000385ED5D8F222806F7C7D8190756C7F7CCC
+:1038D0003C4DD4AF2311DE3682DE961FADDB32289D
+:1038E0005DC5E1CB77094CFE511A95605C0B61B464
+:1038F000E53005EE8279CAA4DC2F225E7D04E677EE
+:1039000068D893732A28FE9A26C83EEC1BA40A277F
+:10391000D54FA55EB84EC5BA95D7E7090A8EBF3117
+:10392000F9B03587AE77B34FE47A4110C76BC8FE64
+:10393000CA0B7CDC26058907CABCF8727AA52072FE
+:103940003C3E4AAE461F8EC5CF48FA3AE32F04E10B
+:10395000A7CD6FCBD0B03507E8713CD3879BC7F5B7
+:103960002F57D673B8D6727D78B3323B8938A3EB24
+:103970009612CC6B03D7A309E99903786FC84E1749
+:1039800061DF6E1018DF3994FDB615F84793E7B084
+:1039900015C60B08D96CBD31F06D487E0FF5FA5A8B
+:1039A000977D4E280E3E03821BD7D900388375259C
+:1039B000132EB7552FE0CDAA784A1A95BE7434D984
+:1039C000F525CECB594A140BEDEF4C63EFDB3E16D9
+:1039D000420ABEEF770EA2F37070FAB02B46F9BA26
+:1039E00076E22D2AE8910FE71032109FDE6FC09328
+:1039F000A3343003E8DFF457138E4B06B17949A4A2
+:103A0000EA0FF361FC42C6A73CF47FDFD031AC790A
+:103A1000317CEBD834DCBFB2877D9F982674DE44BE
+:103A2000E72BE58B034D74AD2673A71FF4B18D5DB5
+:103A30006D3E55077F594F07C0873E9E769614C34B
+:103A40007775E3C3FBC3666FC9ED879E4C5D6E124D
+:103A5000BE0EBE7B4FBFF4E1FAB8ED9D233AB8BC71
+:103A600021B8D2BA016863C958E4135778FF724D80
+:103A7000E89D23C370BDE2D5D0797DCC3EDF90CDEB
+:103A8000F5398AEF593A3DEDB2C0F439A296211CBE
+:103A9000258EC70D13490FC895CDD9B2B20EF0517E
+:103AA0002A8781849052E9F7CDF00F809B52DFC9BD
+:103AB0009EFFD0C047D70F99E90B2B89E727A5C5F3
+:103AC000E0F10AEBAF06F8E9FA7703FCAE89C2CF62
+:103AD0004CCA93C240DBC1A948BF6E6D1E13EF52A2
+:103AE000F4F3E885E30D6C7F9AD354124F2FADE5C4
+:103AF000F0BB53F45F047E67927D2702409F39320A
+:103B0000DA27B1FD478A8C0F45E16C95004F76C2EC
+:103B1000FF668410EEF4AFDC9ACEE147FFCC196F5C
+:103B2000FF5500BAA366B3A3189FD74925747F79C0
+:103B300089EAA0F2C12E1109EA59C06C4763FB64FF
+:103B40003905F6F12D3ED477CDFC7B9E36AF5E4F26
+:103B5000CF12195EA3ED21EF9D8676338EB7C1C5D6
+:103B6000F51BCF7306BAE87D3F39BEDC192832FD5C
+:103B7000274BF470FA790EED39F3D0BB1A0E517859
+:103B8000D7E5FB7D15B0400F413868F243931754D9
+:103B90008E64890300FE010278973CE558C6CAE3AB
+:103BA000847C3C460E9B0B6403DF217AFD2607FED6
+:103BB0009BE1C1FD4662E53F2FCBA75FD5BEAA8D35
+:103BC000D95726125F2EDD2E32FD91A869B87E6D81
+:103BD0005F11AE5F68F8A7F2C140AF32CC87321CEC
+:103BE0001B09E1E00E6A6641DD45AAB07E695C49C9
+:103BF00058A0E358A4AE06E0CB96712251B3E3D8A7
+:103C0000555C0E255AC79689F1E5C4CDA29BD9C74C
+:103C1000CE2ADC1784DC837AA1A006C837A81F0649
+:103C2000B9BCF479018F1B6BAAC927743F590FCF18
+:103C3000457BDD9CA7FAC1DE075901FA23C9286537
+:103C4000A5E453F4F4D98B47B216C7333919FEE50E
+:103C500034AA17E7207D2C00FA205623FDF4D24920
+:103C6000461AC80A9887521E775C8E57DE2F211D90
+:103C7000F5D281B62E4586F162E9C35E4A2D0E115A
+:103C8000AB9D309F811C7B0303F5F78BC5809FE0C4
+:103C9000D4E1140F03BBE6A13C737179525F38FB8A
+:103CA00028A874493ECFAC5B14B0F3890070DD08DE
+:103CB000835D0FE3CD5D5B46EBEB61B0C1B4BA6EE3
+:103CC0006699EA646462D44B4545D2F430B15FBD75
+:103CD00046F8C6D2F7FD44EBB7C4C83B42565F9DD9
+:103CE0001E750FFB9E4AFF07FB2B39469E26F98D5A
+:103CF000FCDD15F39D17019608DFFBFF57BEE7219A
+:103D00008F5B154A0A963CD113A2B499443CC96012
+:103D100027D92753FB8DD63D193D2A4CE94A78A96E
+:103D2000E7762AA1FB534FCF6F727EE9ADA8CBAEE9
+:103D3000A7E35E2A75FA805E0752F6989AD2773D1D
+:103D40009BB8DED75B2FDC8174BD9ED211E8C36ABD
+:103D5000A188FEA68D792F7BF472F194C657FAD014
+:103D60000751244D2EE7C03E14FDB6E2EF4E1FE68C
+:103D700018385F2D7D38EE31E2E3DBE2EBC2B7A409
+:103D80008FEFFABDFA44FE07CE9F285E51FF6E50BA
+:103D9000FAB703FAE2F571C4AB9DDA2FF1F8ED172B
+:103DA000BDF8548DF288DBFF51B961B4FBA5AC5B63
+:103DB0004EB4F5030F29564FE6E3DAAA4DCAA7A978
+:103DC0003080C760EF6C541E5741FFBE047A34E860
+:103DD0007BC132F4FF923CE68F850144D0FB157F16
+:103DE00008FD0C209F74724DCE30EAFDA634BB5105
+:103DF0001ECF5105FDFC6DD532CEC30ADF4B437F8C
+:103E00006D08BE6BF290B0CD1DA557F814B3F71F27
+:103E1000B92A3A3069EF091ABD1ADFDB905142E244
+:103E2000E1AFCFF7EE30CE37215F8A7DCF2929DD94
+:103E30003ABD23F17B12E9D6E92F376A711D8EA7AF
+:103E40007A33392850FDAFD67B170928489F28C7F9
+:103E50001AA0A4F2B4DE5BE241F9BC4788B1CF15E9
+:103E6000464F4A0AF617AD4CBFD2EA89E7C3BE1BDC
+:103E70008D1329A81F27EA5F5B33EE0989321B7374
+:103E8000F55B5B256AFFD4ADF5CF29A7FD1B6B8ED3
+:103E90006E958645FB2D3169F639159F6340AFE17C
+:103EA000F44B683F849B48BE01FB8972684527E755
+:103EB0006DA473AB84769FC2F14884DEFD4087DC3D
+:103EC000CAD7692127B01F0C84761CE9C271E1456D
+:103ED000A8AF37FBFDE5144E8D52C8BA1AF8B98D5C
+:103EE000D7155E4FE6750FAF67F33AD98175B34CBE
+:103EF000EBB07FCD210FD6EDBC9ECDEB29BC9ECC87
+:103F0000EB39BC2EECC0FA7A998DB7496A67E3DBCE
+:103F1000795DE1F5145EF7F07A0EAF9397D9F72D3E
+:103F2000ACEE30B7B3F11DBC9ECDEBA9BC9ECCEB83
+:103F3000B9BC2EBC8CF584FCB280C13FCA1F18BC32
+:103F4000357A240057831FAB2BA69DD18B49205C6B
+:103F50000FAB42FDFFD0D0BBBCE06F5C7FAAD20BA1
+:103F6000F4537F9B464F01E49F24E356E463662DA0
+:103F7000EE98B67A0EECFFFA0C19ED49C2FD305AF4
+:103F8000FB86E4C0D46CF0577C6022F1EC2EAD6C63
+:103F9000E57CF769D07BA97EDEC2E3914FF278E43D
+:103FA000568847D23208F1485A36F37864138F475F
+:103FB00036F27864038F47FE04E291F910E79C83A0
+:103FC000E58B108FA4CFF7403C9296BB211E499FF2
+:103FD000EF8478242D77403C923E0F413C9296DB53
+:103FE000793CB23EADE428E81D97AA45D40712CD2E
+:103FF0007F6895917F0E596C8C4B0C0A18E3120365
+:10400000E718E31203CA8D718964BF312E9134CE53
+:10401000189770F98C71094781312E61538C718921
+:104020006B0FCE36D48BDABF6FE87FCD9E0A43FB91
+:1040300088D052437B7ECB6A437D58F09F0CFD7342
+:104040001BD619DA9F32E5207D65AB8D867E59D56A
+:104050008F1BEA95767FB709FD946957E5AF265F18
+:10406000AAE97A7E192B1F4C99C4EF4739C7E4118E
+:10407000FA6081FE8632BF94F5E3EF1D057BDD9289
+:10408000C7E4944589B13B63C6939DBB4FA8F43BFD
+:1040900065EEA3DE2EDD7E245EDD7B60EF488C4F77
+:1040A000363ECAECF1265EF65D473DF66BFA5B7C68
+:1040B000BBDC269962F40866D7343D2A60FFEF3AEC
+:1040C000BED61E3B6EF47B141563F4F66D48F3AF59
+:1040D000923A9DBE60EE4A9E4F50CE33FBD7C4F756
+:1040E0007B5981EF541D85F77A0FF159687DBD73B7
+:1040F000929FE925A2824276CD6D68A76BFDB579C6
+:10410000D5396733FE42D947D8C0A7EC063FC1FA7C
+:10411000B4FEF53739622261AA97982202FAF56453
+:10412000A97C6A36D5C7E56326DF5AC067027B9F44
+:1041300090C7193FF48A063AAE5BA0F13F1F9B1F60
+:10414000CFBBD0F85B6DDA247C5EE7E97F5E169822
+:1041500017CC87CFCB1C7160698AD870BEE323A9C6
+:10416000581F1749C6726C640896632283B01C1DE1
+:10417000C9C5B234928DE575916BF0BD92C8082C1B
+:104180004745AEC3E7BEC8282CAF8DDC80CF8B235C
+:10419000E3B12C8ADC8CCF0B2365585E13B9159FD5
+:1041A0008F8C4CC37244E4767C5E109985657EE406
+:1041B00007580E8FCCC57258643E9679917958E6AF
+:1041C0004696E17B3991255866471EC0E74AE47E52
+:1041D0002CB3228F609919F911964323B558664480
+:1041E000D6623924B209DF1B1CD988E5A0C88FF13B
+:1041F000B937F21896E9916D5826479EC3764FA4B9
+:104200000DCBA4C84BF8DC1D79014B57E467F8DCF3
+:1042100019D98FA523F21A3EB7477E8EA52DF21627
+:104220003EB7460E6179253C5D490F1EF7A9918F77
+:104230008FF9D8C8C74B8F19F978C96F8D7CDC7797
+:10424000C4C8C78B5F37F2F1C20E231F1FB9D7C88E
+:10425000C70B761AF9F8F056231FCFDB6AE4E3396F
+:104260004D463EAED419F978E61A231FCF78D0C850
+:10427000C7072F37F26FEF0223FF4E274F1BEDF4D6
+:10428000C93B0CEDEE092F1AC67396BE1C63D7848A
+:1042900090BFD80BFFD5F09E35EF700C5F56197F9D
+:1042A0008AF19F0348207EF930B1FBC0AE89C56713
+:1042B0000AE707A9B0EF6899C6F7DD00D877B44CD4
+:1042C000B97502C6A952678E9B07FEB8CBA7040535
+:1042D00074226166753EE841294308F32790FC9BF0
+:1042E000FDB45E3B48AB135580FA5082FE0588FC56
+:1042F000617B36ABFFB2EE91491007AE35F376B570
+:104300007612F8D56A6DAC7EACAE621DF82352927F
+:10431000FC83215169A7393E3FFF5892113E032586
+:10432000FF6F245AFEB9ACEB21F027FECA1AF877CA
+:1043300089C263B935900521B4F3E6C0F3203A721F
+:10434000047F27F42B12FCEF4AC8CF8D7ED35B404D
+:1043500070D2F6A152F987D09E3A730FDA171A1C61
+:104360006A5DFDCFE79D5EF944504E6AFE8AA71C48
+:104370006EB43F1B9F904310373717A4A37CA84D02
+:10438000262C1E0A71218C0BB3FAAEA14AA891E922
+:104390008B46B9B2B5FE7E884758413EE5EAFDA797
+:1043A0005DE83F4D024B2117FC033D99122D575AF2
+:1043B000C2F52057BE4AEE3C2998102E1761FD0F1A
+:1043C0004D0F61FF758E99E3605D142E5FC07A29F1
+:1043D0005CBE944627860BFD2BF78EE1AA05FC6791
+:1043E000AF60F05F3A4C81BFC3383229C7F115D5B1
+:1043F00087F03B2E79F07D0D8EF4EFC19431D1F82A
+:104400003F7D4F360FE83B9E36CEDF25FE7D2E1FCB
+:1044100035FAAE4E20AFB47825516FFB567EEFC310
+:10442000B218F73B66A91CE3B47DF8619A511E9A55
+:10443000D258DE83498A1F7746C7318CDF3AF3AA08
+:10444000E2D99ABF85D4DD7655FD1BB4FED44084F5
+:10445000FEB91A9E5A6F437A1CC6DFCFE57ADE5B3F
+:10446000BF7F556D02BACC2398CF11ABDF356E15E7
+:10447000911E739399BEA8C15BE2FAA1F65DA9C92A
+:10448000A827BE2673BB78EBD5C17F0F877F2EC5CB
+:10449000F3BF96F49D07D93993ADC7C3AA0545C1AB
+:1044A0007720DF64580BAB4B5BE97C8A13CF87F036
+:1044B000B884B68FA416D69FEC318EDBE7BBA61965
+:1044C000BE78F1B384DFF99671BEF966639C4F7BC9
+:1044D0009FE20BF19DC7F528524DFFE8BCF2891110
+:1044E0008E5ABC4FABBFF5FBB1184FAF0D96B078ED
+:1044F000B993C973F2351D7D0CB8BBE2E3418BA7BC
+:10450000D671FBB2DEBB03F3D9C85E239DCA831606
+:10451000E0F3C6820A0FCB4763FD2C431FC4FCC8DF
+:10452000C682D5E8CF955BFD56B06BE502D107306A
+:10453000979227F3F649D86E69657AA705DA15D000
+:104540005B77AE45D1100C35807F98A4493E086357
+:104550004AAD8106E82735101C8700EBA3F3D9C1CB
+:10456000F198E195D695D17F6604CBC3367C8FF860
+:1045700087E9FA85F87A33331E0F43BFCC6055675D
+:1045800019F8FDAA088E9F99B103CDF2C19ED96298
+:1045900099EEBDED7CFCCD7C3FD9827E0FBE1760CD
+:1045A000F98CB1FB577BAF955786A75594C1B8F6E8
+:1045B000607939BED7CADFE3FD9EE6FD86417B29DF
+:1045C0005227CEA777BFF37E2D7C1EF5DCDE1F1EA3
+:1045D00064799F75DCEED7FA3DC9C7B3589F7B0657
+:1045E000FC8EF941E68FD5DA83BC5DCBBB904B8D59
+:1045F000F9A31D66B65F3F97197FD2E826111D9378
+:10460000061DDF83F8A36A37D6AB530CF61FA91A31
+:104610006CAC2FCE31F60F8C34D6E79418FBFBAF81
+:1046200037B45FEEF5BB846C98EFCDFD2EF97CBFFF
+:104630003CDD5A827647D4DFD765D3DB27197CACC3
+:10464000ED551576787F770BDF27DC3F63D3EC974A
+:10465000BCD5D8AEAD7B3BDF271BC0FF6101BCB42E
+:1046600030BFCAA8AA7746503CEEF9C0E4DBA124CB
+:10467000865B223FCE46C027EE3F9657FE24F7E3E7
+:1046800004B91FA719FC38F9E0CFF1737FCE54AC01
+:104690001FE07E9C9FF1BCF2FDDC8FF3539E57BE62
+:1046A0008FE795BFC4FD382FF0BCF21D3CAFFC2650
+:1046B000CEA71BA6F807835F6DE794F876F14D321D
+:1046C0008BFF4CA7EA1641F9DE23A0FF7C1CD555D1
+:1046D000E87AB3AA7AD6CAB49E7E0F835B56A0A7A7
+:1046E0000CFCE99EC9AC3E83CB55901F204F8897A8
+:1046F000EB3B1974C752786FE1749E59DD13867CC9
+:10470000165B866714B8406DFCBBB4CD8BF9FC9C7E
+:104710008E6DD55561682726BF5D1E00E3B379E530
+:104720001CE99904E14DDF89CEC380CEE2CE76113B
+:10473000FA159606D7510B9B380A4322F0AB86B286
+:1047400040E388B428BEE82C0C7441E788722B53F0
+:10475000E3BF138C742147B6A37E5C5B353B09E94C
+:104760004F61FD8727907303E718EDA664BFD1FF63
+:10477000555B3DBB5F7FB4EF75E3FBC51D46BBAB2F
+:1047800036AFFFF70BF71ADF1FB933E6FD16B68E0B
+:1047900044EFE74466A27DF07C6B7CBEF00FA68AF6
+:1047A000898007ADEE8EDC88FD63F53E09F4B95CC7
+:1047B00070BFCB7ED07F25C5E3C7BC2445E1A58F64
+:1047C0003FF7F37A39D6A97E385D1E8D7831E887B8
+:1047D00026CA902116D23082703BE3EB75FE0C5A4C
+:1047E000BF93A01DE290AD37AB13807F2C34F855FA
+:1047F00052E5AA330AECD7C74494253B83FDF3BBAB
+:104800003E79114E3FC68F729B3C25A638F8D6CA1A
+:10481000AD4DE2D47871B1259CAED737CDF6A05C12
+:1048200038123F8F44EB4FD7BF44D6E5930CB88383
+:10483000E7099C63F96C83392DA52EED9F0EAE36EA
+:10484000BF63AFB6EF9C2C6F44A3FBD4E1FDD389CB
+:10485000A67F464222E9847D2155D9F148C21D3EFA
+:10486000CC770701AADF27B57F7BA011F8A6FA2332
+:1048700011F9C8803BAA443D1EB4790C56C265B0FC
+:104880007F6B0F2D1121DF3EBFA54AC4731387082C
+:10489000FF0E9570B4B42D0EF9999F8CE559DAAAE4
+:1048A00002EBE0F9F016062FB04F797F940F1BABA7
+:1048B00067FB018FBB33888FE7AF18FC75BB9DA2E8
+:1048C0000A7AE625CAAF5051F89ACE4BB3EB28F0DE
+:1048D000F25B996BB676180939A1DD3F15E1A5E5C4
+:1048E000EBD9B65D5471DE031E0AE37993514C0F88
+:1048F0003093CE30C616A4802AD0F1D7073C3EC8EC
+:104900004FCC6D29667E99BC20E651AC16037B80A6
+:10491000EE357898D3DA316FA536C179810D9C9F39
+:104920004B24BEFDD1C9F970AAEC9B0EF6E89E2778
+:1049300028FDC7F10BBCC3C7796EEBECA4114A7418
+:10494000FF6AEDC74169D3CD2B3722B33CC1966FC7
+:10495000A7EFDF6C263CBFCAF89E49F219ECAD21E7
+:104960006605FB6975C969E467573F4F09F9122964
+:104970009C6EC073AABB7FBAD6F6CDE5A1317A474B
+:104980005E01D27354EF10899BC2B5358FD30BA74C
+:10499000274D8EC805414FBED0974E5AAB4BF0BC49
+:1049A000C9A509940EE99FC5D3EE07BF816B4218D4
+:1049B000D237800ECE021D0CCA53D70A4827631087
+:1049C000DEED5CEE593DCCBF123B6F4DAF03BBCA71
+:1049D0009B0223C7D83724F81ED077EE0888190227
+:1049E000DDD0CF51BA960AFAB7EFAE365EADC58FBD
+:1049F00033E91FD8371D806FE0E39FC5F8A93C5409
+:104A00004F1DA393EF9F3D80FB2316FEB1EFD57999
+:104A10002679E2F16D620A782CA313D34BAC3D4D9D
+:104A2000FAE4AD3D88FCC332632ADAC9BD7675EB82
+:104A30004C5CB785DB8BE63C6E47F6B11BEFF1F5BE
+:104A4000274FCC19DF2D3F74A425BEDD98E8FDDE8D
+:104A5000BCD06FE977D8C8F3EC34FBA3D7EE881944
+:104A6000472C6C8F7B0EC3596884BB3DCFA877144D
+:104A70009AD9FEB4788D7E63B367707CFF26CF4FE2
+:104A8000AB18A7E149B9FB3FE97E5B72D44C1AA190
+:104A9000CAED5CCDAFB404F2D4281D5740DE1AC570
+:104AA000D30252EE86C6F344C47C98F3E43DF77516
+:104AB000BA7D1FB0F073010DE6D3709E42CBC75A8A
+:104AC0001864756D3E952DC6FA22323B1DFCAC8BE9
+:104AD000B69A09E45F2D21D2E92E6DFE940F945B06
+:104AE000981E5449AAEA81AFADE7FEC30A0F912090
+:104AF0007F6AC5ABCF8C81F33995166E8751F82B41
+:104B0000BA3C9BA5CE900CFED14F3AAEBBEB060251
+:104B1000EF87EA0797629E3BE651C5C27D7E8371AF
+:104B20007E579A7FEC7CB5731789E621ED11E29EE2
+:104B30003FFCA14530C4E7AE742EE41908820D484D
+:104B40007C2EE44AEFEFF88EEF3FFF1DDFDF6B6155
+:104B5000F49BE8FD15D69E5B30CE9F56558EFE5ACF
+:104B60009ED7B19204FCE03A37BD3E4B1DA2E8FA55
+:104B700079AFB25F06ED67BA8A7E79FD8F7781EFF4
+:104B8000F35FED7D4E86FD7BFEC55333412F58F616
+:104B90009A8958214F6DAF8B9FFF0AC920EF9676F7
+:104BA00098985F410A8FB95D971F082758018ECBEF
+:104BB0007EEAC278F2D2972DA119F4FDA5AF7C52FE
+:104BC0004C281C2EACEB797B08E83F2F0A2CDF4ADF
+:104BD000ED2ABE9D3E5F2A91FBCAE3F9D12D4C4FD1
+:104BE00039F773C71CA03361CFA17B71DCF6BBCD55
+:104BF000169D5C3864316BFDD8F9AA1784D03081DA
+:104C0000CD4F9FEFADE5B99D7B4160F33B680ED979
+:104C1000607E7BDAE400EDB76ACF5F90AE6FFEE9AD
+:104C20003E37C061D5419381FFACDA630A5B8AB13C
+:104C30003C65417EEF770A63009E04E5F7CA8E1556
+:104C40009817BBB27DD35F4C6E78DFB8BF285C7C11
+:104C50006180EB71936F06D47FF6BC1BF2893FEF46
+:104C6000DCE506B8D271E7C994AE6EFC52B70F0905
+:104C70001B3F92D2773C427A64A0AF55ED1BD9F727
+:104C80003A6E3B03FC6D55CC3EFE1CFE31A8AFFCDA
+:104C9000B818233F2E91DF8E017D83EC498D9B67F1
+:104CA000D02B3FF8BE5EB6EFD276381F7CEEE53FE4
+:104CB0006D07BD7EF9DFBFD8FE08F803DEB079804E
+:104CC0001FAD7AF10337D1C1DF65657CE1C20BCF3F
+:104CD000EF7E9AEE930B1F5950CFB9F08B33990AA0
+:104CE0005DFF85FD7F4D07BDFEC15F4C1908F07863
+:104CF000F0C0CD03FBB363806E43163D7E43885FF7
+:104D0000E5A0C092975FE7650C9EDEEA782B13E67C
+:104D100079FE8405CF71ADA2CFAA4B006F2B503E18
+:104D2000407D0D85F7CABD1BFE622A8E0777758808
+:104D3000E885323C847801EFB7FFC3C45228CD3EEA
+:104D400005C6233DC8DF63DF5B758CE2F7DAC4F884
+:104D5000BC44BE9601FEABF66E64DF6DA7F874F737
+:104D6000C5E779F8C7F8BEF82CB4C6E273F9B3E822
+:104D700063EC488D9B17A7E173C5813BFBD51B34C2
+:104D8000FE7025382F16D8BC2216FF042BECB397E3
+:104D90001DAA97E1393483B65DD8772993503AF943
+:104DA000CCDC732FF0C99E5F583C60772CFDC57139
+:104DB000DC77170EBC2B2BECFC8853A07AC505D2F0
+:104DC000FBD7097AC64A815556ED74852DEE28BE6B
+:104DD0005686664D55DCF8FC143E0FB1FDB03274BA
+:104DE000E80E210EFE1EB2E630FD333400E1B28241
+:104DF0005A449E42235E857180CF53B700FD25C281
+:104E0000A7B67E0FAC7FAC0EAF3BD93E8EEDBF9206
+:104E1000EE57E0C37DF01B128E4379A1CD22413EB7
+:104E2000E4057E9E2516EF51F8F3F390DF525FAC58
+:104E3000B226883370385C69BF5F697DDF167EF704
+:104E40005A151C37168EE7BE8E2F0F9A38FF584919
+:104E5000AAA60ED6C9338B99CAB36CD0F7CAD5218E
+:104E60004274BEF5EDECBCDDB93DA610C88B587E92
+:104E7000B132817DFCB495F9BF571E3C540C7CEDDA
+:104E8000DCE19F73BA6474BF72EF2959E5F221A483
+:104E9000970F09FC283BF9BC57BD1E7FBC557BFF13
+:104EA0001277BCCF25FFDD30FFCF3BCD44A5437C3F
+:104EB000DE6E9A1A4FDF6AB69A8D79B5AE312792B7
+:104EC000E87B26B71DCF33D6AEF31F57412F79CFDE
+:104ED0008CFE1522F93EB3E0F969BB02F1E55AF701
+:104EE000223CD7A28D57170327C95B8EFE0929AD37
+:104EF000BC94E9D421833D6DF688867953B99B0132
+:104F000072E9E4A8336658E71F62F4C73F48A47EFD
+:104F1000201DEF0FAAE05BABC4B3178DE307D69853
+:104F200088A29787969E93301FF2A68D40BE9AE97D
+:104F30000D9B0AFC64D5761BC6D5DF3A707937C065
+:104F4000EDC2B3161ECF6479B595DC5E3B73E0F21B
+:104F5000F6FFA2ED67E065FAFDCAEDB43FE8ED7B30
+:104F60001D98E4FCE797938A09E5D3956F3E3213C9
+:104F7000F84B25C4C069FFCA9F0E0C41EE42F700F2
+:104F800056EFDE3734047859FEB35FAC0479B2ECE7
+:104F9000270E0224F9D681E3F742FDC29B2ECCEF07
+:104FA000BAF0E6991B611F507D5BD1CBF525FAF372
+:104FB000DB74DC655067EDC2379CD7811DB30C4AAA
+:104FC0004AEFCB0E26E179075D3F7C6F95A5E7217F
+:104FD000BCC885A88345B489C283611F2EDB63FCEE
+:104FE000DE592BB32B56C93D8B58FFE060B65F3BB3
+:104FF000F1BDAF38DD6BEDB1EF6BFDBFE4FC333AD3
+:105000000E7B7FA58554C5A37FC1C6C65DB6E76F7D
+:10501000F9C6F118BDF6FD0E7BFE4381E5E393FD75
+:10502000368C132C97C3C353E87E7D45268B61DFF6
+:105030002E77878727D3EFBDC6F9E5723BADD3E75F
+:1050400083F93CA03FD489B5EB2780DF15AFDA08A0
+:10505000D0FB8A375DE8575EF1CAE5EE7FA1CFCF7E
+:105060001D70A0DF6FC59B0F23BE5758C2F7829FEC
+:10507000AE67BF85ECA0FDCFEDFF7526E823E7CC3A
+:10508000E1CC947EFC432BDA2DFCF217E33AA85DC9
+:10509000505045E7A33EC6F270AA09BB47A09AE765
+:1050A00079908F6DEC9C328F4BADE67EA28B0B948A
+:1050B000249CFF845BD973EE275A7D9B323059378D
+:1050C0000FC89323D751BB44AECA073E6B8ADC4A54
+:1050D000145A9722B9586AFD4C701F4321E427B037
+:1050E000B8A039CD472A69F9700A09E0F948E7F410
+:1050F000DE7DF6EF14C5ABB7290361BC9136C65F00
+:105100002AEDFEB136E433C67B14D4036C5D97F907
+:10511000FD08B1F3BD6C562DC0CFA3F13A962758C8
+:105120002D29C7C1FF4E8E72BED467FD6C9F5DF402
+:10513000A4E03ED3D6B1A9C683FC04E265506EA8B4
+:1051400029204A3EE47BF8B06EE2F0B014AA04CE07
+:10515000F7C21E843F8BB3DC2FB2F83001FFABC91E
+:105160001940FAB278ABD05760E5F7E9989C2AA9C4
+:10517000A4A5D9C9E004E7F6004E32AF4B2D331099
+:10518000AEF47D7C7E933D702FC0C59A31D2C0A70E
+:10519000E4B41243BD0FDC34BAD8F7BF0D3F82F040
+:1051A00002BF8E8271CC7108B7F5357EACFF7F806F
+:1051B0005F3D83DFF544D1ED1F396D92A19E107ED6
+:1051C000DB28FCD2A2FB2A160ED53C0F47DB4F8909
+:1051D000F6EF933504832F8FD7B460A93D4F492054
+:1051E000D7CFD8985CAF2681B566E0531EE68721FD
+:1051F000692AC9D0F99F8857C5731FE8EB87F68CD9
+:105200005BD17FA9E1D7E491BA8DFC4F390EEB79E0
+:10521000F81DB308FCCA54FD1CF92455B78F6794D8
+:10522000DB1484B30FE303B55CBEAEEFC5A7717F9B
+:105230006CAA51B0DCCCF7C916BE4F1E03BCC37DAF
+:105240000E702F05FD5ED35482F2F3095A67F67E85
+:1052500098E8FDE1C9BEF6B099E21F79928225FA7D
+:10526000ABC9094B685836C455891FE825F9C48F66
+:1052700042B856D28EE72592B57B5D5ECF499E8BB4
+:10528000F11F6266728A98581934831D150BDF5A14
+:10529000DF612BD8E189E65376728900DFBB3C974A
+:1052A000C5CCD2EE693F01F73C389B1C6857A6FB82
+:1052B000AAB23291BF5A905E9DBE8050A9C3637A54
+:1052C00002FDEF21FBB40F801E3F843C445A3EDEBA
+:1052D000926B03386F32B77B811F6EE2E7C5953959
+:1052E000140ABAFBC2DEE47CD25D6AE4031A5FF6FC
+:1052F0004C2831D0B3C67753261BE95EE3BB2FD8C9
+:10530000985FA3D25E7E06E6931A69C57D19BB0F2E
+:105310006ACDB22A5C8BF7CB30FFD32981C5D5FB90
+:10532000F2038CBB5FECCADE01E7A9B5FD13BB7EBF
+:10533000A9611A7EA7571F34C7CF07182230B9DEDC
+:1053400040E98D605E82828868A6744678DE02DB62
+:105350004FE3B0D4E8781D613C44ED10D93CB9BFAF
+:10536000563B7BB3CE5AE2073CAE6F677B68A09D8D
+:10537000C749D344905D44A2F6A4933E920E8DB7E4
+:10538000827E29997D47810FF6B8C47688E3AE778F
+:10539000CEB6421C44482E45FAF9CA5591D55F5CF9
+:1053A00007EE5303FAF3387DE474219E8745BFB0BE
+:1053B000C95342C02EDDE7ECB4633E935D34C49F15
+:1053C0002AED810CBB4E4F2D82AF73BCC3B0FB12D4
+:1053D0009CB72CE0EB21192AC9D3F189DEFB8F148D
+:1053E0009514E8F8C5BA61B7E0FD4A7DF944027E3C
+:1053F000B8EB7F861FD6668510AFE658FE93E6C7EA
+:105400003B9D68A9C2D508263274FD0F92914E27A4
+:10541000023C887347AF1E74534EDF79C6F2BFA8B3
+:105420005C53D00F46E5DA53E3809F26946B55F723
+:10543000211D370D51808E0F353FF22CD43F69B6B8
+:1054400028C0BF1645361285CEB732321ECBC52DC9
+:105450003FC6B2A2A58D6E2242D66EAE6C9E0BFDEB
+:10546000B799D0FFD31DBAEE4235AD773759507F8B
+:10547000EF6E7D200BF4BFEE268702F7AB74B78E7C
+:1054800036B63798709F75B79843261E0F36413C45
+:105490008270FE0E5E20DD7C49A9827AFCC5987878
+:1054A0004BC5168B5F7027867F454B7C7DB216FE01
+:1054B000C9CEA3E5037F2D3BF9A32CA00F8DCF3CD4
+:1054C0009C42F91EC0EFA485C48B0BDC649FB2C460
+:1054D0003E004AFFFD768CEF5FDD3D589F8854EF1C
+:1054E000463C05DCB30C7E5FE657FD84EBE5C49AD1
+:1054F000A0DDCDDFF7C46F5FD1F4A7B71FA5B50D51
+:105500008546BFB609FCD502D8E3B3F8FD196C3E59
+:1055100071E89AE9D34D16E42B0BB83F4AA3F32860
+:105520009D05DCFC9C9E810E97441E43BE276C2A81
+:105530007A6A3C85DF1794FE803E844D1307027C17
+:10554000D736DEB0E51E3AFE97BF35E1F3C5111B35
+:10555000F63FFBA8EFA97BC05EF83733E6917C7974
+:10556000740AC691CF9A8D7E8C1B1C6CDF1FE4FBE6
+:105570007F516493413F5FD4305F063FE8A24833D8
+:105580003E5F044124CC8BBFFB976579105F229866
+:10559000CF72D07EC79475284F4BD08F56B9D91291
+:1055A00037AFFFA05D31F2ABAE261C9750FD2C2D1E
+:1055B0009D8FA7E33B959154DC1FC4A312C8EF5EF7
+:1055C000C4F94FEFFC5ACD06FE73D616DF4F73D4E5
+:1055D000CEE4C2A2C80DB8EFFAAEEF467CBE48FBDF
+:1055E0006E17DBA7D1F53C353EDE7AA2EB9880FD45
+:1055F000CF26C7FFFE9FF9F7BB6B16133FE55F157C
+:1056000016DACF09DF7FA07E1CD8F9ADC929826EDA
+:105610005D952DCB885FB7AECAD679B2FEBEC928DC
+:105620001EEEFF659914C5C39F1B974F595708FA83
+:1056300042F97FC23EAAD834B1388076FE4684F360
+:1056400027665F26F0E3332D0FB8E3E50FFFD9AEF1
+:1056500018FC1C952D1C3F54EF2ED5E147C34BEC95
+:10566000FBDDBFAFFCEA51E053DB5C06BE125BF62C
+:10567000C15B767CB8D91C1ADC0A4800E1A6BC7272
+:1056800002E87AB3C307749D187ED790407FF04B31
+:10569000A03F533D4B748C86EF12665FB6303AB82C
+:1056A00012DCA2DFE57450167F3D63F97EEBAEA9F4
+:1056B000262ADDB0A7E52BD1C12344B5F6B38E5E13
+:1056C0003A78C24007631D9B910E3E03FD27BF2F12
+:1056D000FE4FCBAAFB7AD0771A4D18F73A6D57D305
+:1056E000BFCFEAA3803F9F7607675E5F1AAD2FD9D1
+:1056F00035CCADBFA7F14C0385431CF88D75C4ECC8
+:105700006F8D7EF2545238E6FF1DFD7C92E0DCCBBB
+:105710004DF6B21B009F2418DF9FAC95BDE7AA93FE
+:105720009CBD762FC8D1D3CE9CAF42B4B5C11EF874
+:105730009E83B6D7253F8472FEF46901E5F0DADF77
+:105740003F9C0F7CB88FFE5B1379FAD361E8B7FCFE
+:10575000974FCDA84FE1B884EA3F200730671CED92
+:105760008021E8674914CF5D0197F98E8EC675B523
+:10577000F8EDFA9ACE1FC3F8C4AA128FFEFC00619E
+:10578000FAD8FF8179E8FCF3B239E0F181BD2B90C2
+:1057900072A07BB3C4F2D7CDDEB451AA0ECECB1C1F
+:1057A0004C9FB41D39D2904DDFB72DFC770FF8F91F
+:1057B0002CF43B505A33A48B7A7FB996F745F27498
+:1057C000CF7320BF82D60D7E073ADF7EECE6D7048A
+:1057D000EDBE4F15EF2B9EAB5D5800A0A374F39167
+:1057E00096BF22D5B1F664ADB98EB5733FEAAA0A69
+:1057F000E6277D6B5E12C24F5BD7DCD737E07D6951
+:10580000735F1F341FFC69739DF97F0478BE06899E
+:105810003540F7C94C3EC7D2C566CE7F7ED026AA9A
+:10582000663ADE1173CF6107EC8B1F0A68577FFF62
+:1058300083236620F9FF3876DA0CF723DC078945E5
+:10584000743DF3882233253A84EFCF27ED2E566F2F
+:105850001F00F79946C7A326338C773F8B3F7FFF06
+:10586000836353408CD2F1D64379DF6F890CE3CF49
+:10587000EB50EAD9B1273EDEEB743C313A5E2FFCA7
+:10588000242BC2230A1F2BC2EBA3DE73242AEA17A0
+:105890003AF8A2BEA2C1B716E046E1373769CE7426
+:1058A000529C78BFCC750EFF23298ECE2716BE5F83
+:1058B00042D320385FE67F09F6CD3F3BFC7BA15CFD
+:1058C0006EEDC99472F0BC573BECCB95A640563AAE
+:1058D000A5ABF34303F903E0505067FC386FEC3E8F
+:1058E0003D09FBE55A28E9BE8079F07329F7F27586
+:1058F000BEF5A3332ED897F5078E6742B9C2D4B54B
+:10590000F96ED86FBF31A1FE79B123BFDFBCBA9366
+:10591000DCEF72D4A1DDA3C1D6791FD7E7EEEB701F
+:1059200084D652D2B8AFDAD46B5F015DDF57CDF2C7
+:105930004F88D4597C87419FACE3E7D4FA8E03F6B5
+:1059400042EC38DA3A0F670EBE06ECCB6747CB68FD
+:10595000471CFAEDC58F2A69DD3ED48A76C2E6641B
+:105960004EBF65CC6E7D36D9EF2802FF57638A4F54
+:10597000A5EB6CFC256917299C0E8F782834A91497
+:10598000EE7916D177B625F25C7012BC57C8EE9945
+:10599000F170BD744BE7E916A0C733272C1877F8D0
+:1059A000C465C2F9369ACB33418FFF639B1CF7FE67
+:1059B000B28F5C12CEB74DE8C23CBDF92468057EBB
+:1059C000D1D1397B20CCC7ED231E20FF33AD2691EA
+:1059D000DD6FA6F95BC212F3F7AB12ABFB79E9B14D
+:1059E000E9EF17DB387532E6792C687A17CFB1B951
+:1059F0004BE3DFEB6373B2F9BA3A53A6017C5D93D4
+:105A000045CCC376F97A04782FAB73928CEF078577
+:105A10007EDFCF5AE399067085F781CF675DE5FB9E
+:105A20008293E5693DC6EDEC36B3AF7E321DA76DBE
+:105A300073B200F8D0FA0D7632BE7266B2E64762F3
+:105A400079C299791E5B1E9D77A61F37377195061F
+:105A5000F11CD30EE8C7FCAC0887B611AF84218EC9
+:105A6000DD08FE15C0B399D153E36601FDAA147E8B
+:105A700083414EFCF109CBADB08EAC06C103B63B01
+:105A80002DE3CE7BB6CBCAE8BCE929B40BC14D0BE4
+:105A9000E366B6BE8FF3722558EF1A4E1F7FBC0225
+:105AA0007D9C77303F54667527BFDF2E8CF7D80575
+:105AB000014E50F797F2FBEAFC8A3E3F26BA7FD6AA
+:105AC000723A247E88B3558C9343E047101BDAF07A
+:105AD0009ED4F9410BF91E5D5F93C0EE1D55478BB7
+:105AE000FCFE24FF498053F36303310F6F83E8CF3B
+:105AF0000439ACFEB38C71BAC3FE8BDBE03EF8ED2B
+:105B0000E364DC1787FDEC5CE1B36B72DA204EE9ED
+:105B1000AA9ED4329F8E17F260462CA92D25EFE461
+:105B2000439C728DE81168FF60B996B7EDC17CF2B5
+:105B300051A62FA615401C6F90883EA53302BBA727
+:105B400061FD9A491EC0EB7A4F9AA0B75F66713A21
+:105B50003891523ECB49E1E37DF4710F9C85DB1215
+:105B600049BD06FC886A83ACEC62F142BCDF21953A
+:105B7000E325B5530C2F7263DDB9989ACA5B2630C2
+:105B80007FE98FA707989F1362A363D0CFC9FFBC9B
+:105B900088D7345E6B1C69C7CAD6758BB03F8C93AF
+:105BA0004EC7492D15C363207F2DD9BF1DFD7653E8
+:105BB000AC08272275B5009C425306633EF8E3E328
+:105BC00087BF0BF9E3A9477B66831C0D0DB5FF4723
+:105BD0001BF0A9F5B202FB3C754DF73DF03CD9F73F
+:105BE000E40350A6D67DF808F0E9E4AEBFD4E0F3B4
+:105BF000A9B2C1BF98FAF1D9BF417B6AB96CF05321
+:105C00007E9552FEA093C2677B613058A1B0E7FE3B
+:105C1000F4E83AF6ADED9C0AF7D89F9925B2F33235
+:105C200084F1C3AD5B3DDA39E552900B1ADC36885E
+:105C30004A7B18D635D38AF491473A915F0D826832
+:105C4000766E142FA91F6FBC1FF23562E7D3E014E4
+:105C50007ACF51C3BD80786E3107CE1F4EB6035D3B
+:105C6000EF2FE9F4823EBF39C1FD9D475DEC7D8B8E
+:105C7000C8FCACB1ED47783BB0C496122CFD455042
+:105C80003A899A046586D50FF9CFFB45E53F91CE59
+:105C90001F3729801FE86FA6F83BF4CEE7E85F3C8A
+:105CA000147C1FCBE75C05DA78E174FA7E73E9694E
+:105CB0008CD3347B188D5436307E51E9EDB242DC02
+:105CC000A4B2907876707A53353883BF8CCBAB8A88
+:105CD0003B185CD30A09C67DC11704F74BA5433FA7
+:105CE0000ABFB486B5F7231E49A79A4BFB35C3B844
+:105CF000809F3A91B071BBACB87F83268C7BD2FD7C
+:105D0000FE3BF06B55340DC4B83F1C0F86F152F8C2
+:105D10007753F8786D741CF01F9E6930E1B9004824
+:105D2000BF81BAB286D232D2674F59011D5729F5C9
+:105D3000781A353AD0F818DD1A0BA8BC00B82D50E7
+:105D4000D5FB81FE4E5B3DEFC03C1C5B2D0AAC7F5A
+:105D5000C1D6571F06FDC5E1ED6A00FE50398ECD54
+:105D600037A5893E473D47F91DF4AF6CB228EC7B5F
+:105D70001C7EA59CCE381C16F2792F6C65F3B60FED
+:105D80000D05813E2BD750B8425B80D13DB844BF52
+:105D900011715F1D85F5BBD4741C77C09C987D1173
+:105DA000437FDABA2AF8BA2AD6B07511BE9FE8B492
+:105DB000C2306E45295BE702C2DE17E1391D7F2143
+:105DC0005F4F85FA0A960B1B2C86F1B717ECEC8413
+:105DD000F96417CA8A807066F71B66F27565D6B1DA
+:105DE000EF6516BE82F022D5BAF9A25F5557A7FB20
+:105DF000EACCAFE9C682C3FF70D0808E7BFA47EC55
+:105E00009E81BCADC6759DD998FF1C9CF7FEE40928
+:105E100019E3DEFB45DFC92CB4476585F11FDFFBC5
+:105E200033804F2FACF3011FDF57C6E07FE63612F9
+:105E3000027A1876B43C05E03DEC68809755184F1F
+:105E4000A700117AF91E9D1F35991A04E09791DC7D
+:105E50009716031F18C7CEF70CD5CF9BCE2FB521B1
+:105E60007D12E443A58D4B9924E315DE31ED479F68
+:105E70009E0DF78FA61D79FA01F8CE20A25B0FD0F8
+:105E8000833B979D6739425BA15F75F7A3808F269F
+:105E90007E9FFC3098590A9647A04CA5FB7B530A7D
+:105EA000CC5322934BA2FC60D7136346015FC1948D
+:105EB000A7122CC3A4A42FDFD0F51FC1FBAB429CBB
+:105EC0007E16B762B0CF773D71CB08B0E39B414FF0
+:105ED0004C827B383D5F409E8EEA1311EECDE6B0DA
+:105EE000B5300DEEA51609E82F5B0A3E1461DF35CB
+:105EF00077101FD0476AF9DF2D7A3C96B9D8EFEDBD
+:105F00004832D904FBFFF088EEA980A7D02111AF59
+:105F10001898F42BE7D30ED0873E6279306DBFAE70
+:105F200042F9FD50A61CF73E5D72053D31B67FCAB1
+:105F3000B0D9E8CFCBDAFA18DEE7593955F27D8FC0
+:105F4000F64EDB5A56067A8C524EA96B209D77EBA3
+:105F5000A8B5F83B103358BC4C99CA9E2B9359B93D
+:105F6000A9E6E88FC16E0FEE916C7974BE2337B24B
+:105F70007BC436155EB406A85E5A5AF6B2F536FAF8
+:105F8000FCD3522A05E9F34F275CB4417CE7D9D210
+:105F900049A900CF8E06A35E47E0722B6A0F155900
+:105FA000827E179D57D30704E169B2845B2A68DDBE
+:105FB000F4AA13349C3E76CEC6A6B63940A70B0A87
+:105FC0006474DBC7AEB793CB8BF9D53D53E1DEFCF0
+:105FD0006C9530FF7EF02964CA0B39CBC8563B91D3
+:105FE000E9B8B632FB2428F9DF06BE1C2C0CC8F039
+:105FF0008AC6CF9A8655EC067E76DCC5EF0BA95A89
+:106000008CE7CA70FF9B401FEA298B6737153BED71
+:106010004C9F6DBDFD38F8A91754337D3FABF50B90
+:1060200001F141F5BE4174FCAC52BC5A902C58139E
+:10603000B416017EF244A228309F7602764290CABE
+:106040001F3D1CB471FFBBEF2F7359701DC5A03BE2
+:106050008F8EAEC7C9D793E9A3EB8923A70BE1BB0A
+:1060600090EFF3CC1787C603FCD73013292B784A5F
+:10607000B0EAE691A55EDD3C8AF83AEA5CECBC85C4
+:10608000ABB44BC0FB6B62F83BA8F3B06FB73B2ED1
+:106090008C62F6BD919FF6A973BA8A7D9E19C3AF33
+:1060A0008A2CEDD311BFFBD8BDD584D07D6BC5EB59
+:1060B0001B1576CF6748BB5FBA0AFA8D74393D402D
+:1060C000074D233E2C01F86CE6FAC2C24282F6EA82
+:1060D000C28C4ED417E6D7717D41F2D5039375B4C7
+:1060E0002613ED7E18D01F50550213BA8EEB0B9A73
+:1060F000FCE772BBD2DBD98072B58E9DF7EBD5334E
+:10610000542657B3BC4CAE5736D0EF289C98C7E8FE
+:10611000F51226C795AD5C7FE07238957F37AD816B
+:10612000C9AB54D023DC9006A1A25CC618567A54A1
+:106130006F1950C8E4656AD37E946B2F3A199F4C4F
+:10614000DBCAE4E5D0778FA900262F7DDC42F9F485
+:1061500013BCDDEBA1FA594A543FDB20F2781361FE
+:10616000FA21E6FCD3796EE6FDB5E73BF9FCF61FB4
+:1061700049B915F8EBAE600E9E2BD7F62D7A3F6924
+:106180003D93DF879059CDE2E42EDFA2DDFAF3677D
+:10619000152E76CF50858BDD07EFAA0E7B615CBC98
+:1061A0005701F9B88CFEC58D545F42FF13B7AF4A53
+:1061B0009DFC3E194E3F89E489C6875CC4EF2EA43E
+:1061C000F0FD34B41BF9B54AED2558DBA7C1DAC19F
+:1061D0004B61BF076795C2FC9BC77F85F91F5909B3
+:1061E000ECC58F343BF35BF275D7D463CC0EED1462
+:1061F000E39EEF497733FF43BB441C004F5B90DDC8
+:106200001B671B27C7ED6F7333BBEB53BE1F9BC7C9
+:10621000EFC6F39909E5B34454531C79AAC9DB26A8
+:10622000C0F3F574DDAE5FD5E3EF0849A17213F258
+:10623000578276679074A11DA916C8E8376C32079B
+:10624000AD808F2DA51CAF1E6B1B9CCBFCD678A1FF
+:10625000F0003C6FF48B21211BF01CF21431BF0EB7
+:10626000DEDB7986DAEFFA7845AE5BE47052F087D0
+:10627000F6B21A187D358F97711E8DA3D2DB4CD9DB
+:106280007AFE2B70FEC9E8AB71FCDB485F573BBF61
+:1062900045D52F3DF3A92E9ED8BDEDF91C8073F492
+:1062A000FE0B7FBFE7291655FF65EBCE387182DE06
+:1062B00076B0A39C600786BE6F886BBAD9BC6F743A
+:1062C0001BFD77C05FCD685C8406837F69DFC49067
+:1062D0001BDE236B58DC76098FDB7EBEF3763CAF8A
+:1062E0005E44C9CA1C07EF676B8CE7D5CFEE7A7E98
+:1062F00030F36B840CF1B325BB7F3ED2101FF61335
+:10630000256D0CBBB718E5F4DB3ED5628ADE3F2075
+:10631000C3EF0DE446EFD1B293762C9DB07F69E9CF
+:10632000263D587A401CE5829DE4C3328D946399E2
+:106330004EAAB0F492209683493B961960E7E68214
+:106340005CE8C152211E91E8F87E0EF1613D8F9408
+:10635000632901DE52A37109698F15F337207E018D
+:10636000FB3ED1B9B391EE8A656E8477D5B5E598D9
+:106370004FCEE21533DCFEE56E942F61E4DFF33996
+:106380002B3FFA9391ED70FE68F56676EE45E3EFEC
+:1063900068DFD0EFBC94C2E481FAB8807C6C9D6366
+:1063A000E68D08CF26F3397DBC8158AD79F0FB1E10
+:1063B000DAB8F3B99F613E9783E0EE66E7077D7830
+:1063C0003E693EF81B74EDA4B79DDD4BA38D233AC7
+:1063D000260CEF2FDEA77B1FF3A32B62ED802BC9CA
+:1063E000EF98FA82D8F7BFA6134A8FFAE35EBA5144
+:1063F000C9447AE5F29B129482EF35584EA13D16BE
+:106400009CE2D7C3E539CEE734B9B22026DF23B604
+:106410005C20F1FD11330E9580C970EF1ADE29A1C1
+:10642000DBDFDA7DA4DAEF642DF107E441EC352FF0
+:10643000E0D1C3E71D24AD9306D1F233A8EBFCFBFA
+:10644000BF4B0AEC77EBF68BC7CFEE59203C2EB151
+:106450009CEFC729A6A632E0736702C40776C41270
+:1064600052E5BE01FCF9C7D8FDC443E8BCE512B053
+:10647000E3882AA6605D85DF6B395FC3CE0975F3BB
+:10648000FB6876F37B85FFC4EF112E6A797826D0FE
+:10649000C1E7FC1E9A828E8DE5E0F7296A77CC036E
+:1064A000B95FD43EB112DA8BF658D8EFF0703EA146
+:1064B000CD0B8EB9DBE97732E8F7AC29C04F08CABB
+:1064C000DDF34DF610FC7ECFF97613BB47B550C413
+:1064D00073F770EDA089CF2F2905BEF75FF7823ED5
+:1064E000F239E727DDEE64862F4915D434484B2175
+:1064F0003ED06B1E73ACC473908B9CA1DD4FA74143
+:106500007EB8D5B78E7EFFD0FE5733E1F9538E9516
+:1065100058FE69DBF14CE05BE70F1C97E3D1ED0A15
+:10652000292C837F6A59872042FCA4AC7D9E0CF104
+:1065300091457B0FA15F79852780EDCB5BF6637D6D
+:10654000F2DE77317E323449417C9F1F14403F6F29
+:106550005E8B250C3F59B22F27B8346EDC3E89F193
+:10656000DDC71C6FE0F84F39DE781BE1B2CD82E762
+:106570003F0E6DFB158E7BEEC0AB7CBE04F305CFEA
+:10658000DBDA4FFE13C8AFFDFC3CA6B5D3ADF70771
+:10659000FF9DF375AD7E5EFB1D9D8C2BF4D37E8F2E
+:1065A000C7D9E9667CA9D30D71B345ED0C0E7F32D6
+:1065B0008765D02397B50B0AFC3E5ED9DE363C0FCB
+:1065C000B8ACC38AE72596013C006E145E08979626
+:1065D0004338FF0C80CB6858C7FB988F9FD741E1A9
+:1065E000521C5DF7326700F7ABB65E0A07B6EE7D68
+:1065F00057C253C088A7967765F0CB2CEF10107E5A
+:10660000CBF7B2792CEA60F39ABC771EE2FFDC018B
+:10661000A280BFA57BFFF1CF613DE70F58F1FE5E81
+:106620006D5E944E89BB04F60FA353D2C1F8AAA69F
+:1066300077AF08A5E3EF0CF4B6EF65BF330A20B3DC
+:10664000517A2DEA988571C162205EA0534FFB48B4
+:10665000F67B81C14C80EBBE89E14C98F739ED7730
+:106660004CA56026E065A43B509CA4DBE7674FBDCA
+:106670008A72B140ACFAC3A3B08F5F66BFBBF1F0C2
+:10668000C78F897A784C841F4A1E0D70FB9D1BE1D1
+:10669000D67B7F4B90E54B9100EEC7457C3F9E6FCC
+:1066A000A376275DFFD9969F61FBF941C6FCAA3FFF
+:1066B000B5BC950270ABE0E73148E876E447142EAC
+:1066C0000DD63872BEF75C5B889D57BC2010BC2F7E
+:1066D000537D46835B953CDB10E763FC30A335FBC1
+:1066E00008DA19A1F8E71C63F5A4D8FB5113E503F8
+:1066F0009CE6FCEC537E4F97267767B8033F481A19
+:1067000090F8BC77C5A6159900EF0A381B89F711D8
+:10671000BDF13DC823C57343EC5ED430C0A75BBB5D
+:10672000F79474B0F664565F9DF46F1BE03C58B765
+:10673000768FAA7A98B567B3F666DEBEC75DBE34BB
+:1067400009E53C11D8EFF99893E1771934B991181C
+:106750000EC6DF6568830B3706E0780FE278121DFE
+:10676000AFE8BB8FA7F1E9EF3C8EF57F761C4D7E3D
+:10677000C1FE84D447E2F38DFC9F80DF7FF77D125A
+:106780005C68D85797B7E5D6431CED9297DF03D3E3
+:10679000B496803C5FB8F531C3EF7AC4DEE354CBE6
+:1067A000F372E45CBADF74FBFA7012B3730E27095C
+:1067B000BDF794437C6B3821FC9E29AAE2A5F37BAC
+:1067C00025A9FE91CFEF2D2F2041D44F4792762C53
+:1067D0000B492796C5A4074B0C33E782ABD487E55A
+:1067E0009FCBBAC6C0E2975B03CFDA44CC3B7813A9
+:1067F000F6C9F9A181E7E1DED9758E95D7C3FC8F83
+:106800002479F83CC286DF5721FADFBF50401F9C35
+:10681000E1ED4F1F241EE95C6FDE4B0EDE5BFB9B40
+:1068200024C443A2DF41BB3FE6DE1B762E5C83C35C
+:106830000AB84987F6FF65EB6ABCC76FE95E17EADD
+:10684000C9C35BEBF0F7AF9692CE7438273C9CDF60
+:1068500023425AD8FD2DDAFD20235A2C86FB4B56B5
+:10686000C4FCFECE32FE7B59CB627F8F8A9FC3DD94
+:10687000040FE2E463C49EE33D9B14FF7715496176
+:10688000FCDF3F893DC7BBB75DC4FCA8D59077A5A9
+:10689000B32F46ECACB218E94BF94D9E5957177C13
+:1068A000CC1FE1B2FB77097DBF5394CCF4807D828D
+:1068B00010371FEF760FB7B7491D994EC7F9BFD4F0
+:1068C000AD220900800000001F8B080000000000BE
+:1068D000000BDD7D0B7894C5D5F0BCBBEF5EB349F2
+:1068E0007693CD6673DF4080201737185244AC6F23
+:1068F00042C4886817A48ADAE2060402E406A58A7C
+:106900002D2D1B122120D6F83522D0842E7829581F
+:10691000F5DBB4A848835D3022DEFA87D6B654ADE5
+:10692000DF827C8A88B06A4BEDC5FA9F7366267B4E
+:1069300021116CFDBFEF79FEF4B12FF3CEBC3367AC
+:10694000CE9CDB9C7366B6B55EB56F608CB506AD4C
+:106950009ADE094FBB2EA8143396975A655E0265DE
+:10696000E6D0D94778189BA69F72C853CE98B141FC
+:10697000BDC404E5BE1D4BFA0D506E75ABCCA440F2
+:106980007B878E3128B31C5D700494DBEC3F73CCA5
+:106990001FCBD8481BBC877E0AEC2CE8817EF76FA2
+:1069A000BF5D87E5D666C6B2711CC5DFEFA1EF54A7
+:1069B000F630C33F6D46998BB122FC278CA3B28D74
+:1069C0001FEAD318AB6E386E89D8E07DA476061B1B
+:1069D000CFD86576F87822D4BF79F57B58DEB6F249
+:1069E00098C30FE3BDB87DEDAFA7417F8620C005FA
+:1069F0005D947EDAFAFA34182FBADDC87640F9339E
+:106A0000FCBB82B1C255EAB1889906649FC17FF987
+:106A10002B12CB4606E552512E4638E2EAA13C0E37
+:106A2000C7CFC2D21C167661BD80D7A9310670329D
+:106A3000BBCDF9CE18C62EB52BECB361B1F2C5585B
+:106A40000694EC3474545901CE9D7F54BC2D507D76
+:106A500060FBC2229CDFD967FC457698C74A73DA8F
+:106A600078961E8377E099EE11E3062C3A373EC301
+:106A700016E68EB51FFD50B3C90FFDB4AD66DEE35B
+:106A800023183307FBAC63701D0F19BC50647729C2
+:106A90006C4E08EA551BD34230CE388742FD253F65
+:106AA000EF5AED79B9C4101BF7AE4FAF9F83EB1BC4
+:106AB0004DB56A3B9473E192DFA9764F00D7D7902A
+:106AC000CFBC29309EC1D99F6B87EFC63C6DF4DAED
+:106AD0000065D3FE736C7A04C61DF3DC4DCC93CAFB
+:106AE000F185F0AA2B8DDEE3998C99563ABDEA2503
+:106AF000D8CE46F4F891CD183421FE57DEDD81F56D
+:106B0000ADDB2BDC9EB1B171D7AEB67B5580B36BDC
+:106B1000B5D9ABC204D78AF925C357E0D0F982F0C2
+:106B20009D51C7FC585F0FEB80F4536F4FA1E752A4
+:106B30003B87BF5B0DCC42F8BB817E5A905E57709D
+:106B4000FA5D9E630E229D2F7F7178361B3BC8BA7B
+:106B500088E723ABDDDE1280A36BC53C37834F2B68
+:106B600097F559AE82F92F4F35DB911EF569231F3A
+:106B70009882F4FE9281215FB5A65678E6C7F5A704
+:106B80004F9BE4467CE875815C6667ACC57E4B8DA7
+:106B90009A83F412D8CABC8CADEFA8AA512F857283
+:106BA0006A205781FAFB3AA6F1FAACC05605EAB75B
+:106BB000744CE7F505815C1D94B7775CC7CB230265
+:106BC0005BB1BCAB63162F8F03187219EBE9B8A148
+:106BD0002600E3B71ABC73BC30EE1300FF58803FA9
+:106BE000249E3F177891F53FC3F780EFDDE2995C73
+:106BF000FF94F86ECF10F57B457DEF10FD3F2BBE67
+:106C00000B0FF1FD01F15DDF10DF1F14DF1D1AA274
+:106C1000FE2551FFCA10FDFF4A7CD73FC4F7BF16BF
+:106C2000DFBD36C4F7BF13DF1D19A2FE7551FF6625
+:106C300052FF6F89F611F13E3FB5FDF500D05D3E84
+:106C4000C82DFC2B4D6DCF40BAEB6A2E27FA6F9DF5
+:106C500008743E3646EFF90AF361B9D4A1527FA514
+:106C6000288FE1F9AAE8BF7259C9BD4877CB5FD533
+:106C70007B910E5B15EF113FF41F58A6F3A2DC5D6C
+:106C8000FEA29ED3F93235C8E2F8FBD524F8B70945
+:106C9000F8DA04BCCFDB87517DD14AB77786949769
+:106CA000C8F7F6C4B219F84983F1DB9C5CBF942E97
+:106CB000AB328F42FD01FA05E5E65D3663D804E3A9
+:106CC000DF6557A9BECD5965C7FA805D25FD73976D
+:106CD000B3CA3C1FE5AA0D845D058C67E77DB7D973
+:106CE000D59A20CA0F4735D54FFBCF197694A36D9F
+:106CF0002CEAA8C4F9AD02BD02DFEF6FAEA2F745E2
+:106D00008E3F39503EBF9CC1F9BF2FF5A0A518DAC0
+:106D1000A9DFD691BE186957498F0D5BA50B7AA0E4
+:106D2000499F7DB90ECB0FB6717D057FA965307E79
+:106D3000091F9EEDBCBDE2A552D467F7A85E8F8700
+:106D4000BF53E3F44109EA2BD05F398E0C2E1F8527
+:106D5000BEEA2E671AF61B709B830F43BF252A736A
+:106D60006766C4F09EE3D07339AF9FE145BD36BC82
+:106D700023513F15B7C7E92786FA32513F25EBABC0
+:106D80008266908F71DF9BDCF684B2DE914AFA094D
+:106D9000648CF733187A79CFF2ABAC2C26AF93F52D
+:106DA00051ABD00F52EEB67E7A49827E907239593D
+:106DB0003F9C5FBEFEE6EA51448720AD3CE797B3B7
+:106DC000AF221DC03A1AFC0AE90FA6FADDBED4F3C1
+:106DD000E3CB60F0D9EDB6F3E3CD90F51AD9150603
+:106DE000BF4AFD9FA357CE8357D9CE687EB0FB38EC
+:106DF000E8B53FBD7947290396590BB8A1F5CFD225
+:106E0000051F8679E7AFFC6937F69F77D0DA867879
+:106E100036BAE777B7E17C3A1E600CE8496FE6F4D2
+:106E200064CCA9B2E3F7AA4E73670C87F2AEDFDD3C
+:106E3000AC003DE9339BBD0CD6EDD0132F655C83D0
+:106E4000F87BD5407C6ED2F9EC6C388143F4B6AE59
+:106E5000C0BA7D03D1B1DF8C78CADF69263DC0029C
+:106E6000DBD76B40D4ADB01C6C32D67F7DBD06F84D
+:106E7000D9A90C94AFC6722868E4ED4144E3FFF54C
+:106E8000E81451CF341558F3714511F5FF59533DAE
+:106E900005DAABF6312AE89DFAFB7ED66EB81CEB1C
+:106EA00075F27B8D4D82F9E278A2ACC2FAFCB44F48
+:106EB000D407C2EDD5C0443D46393E0B60FB1E9D54
+:106EC0008E9703CFB463FF8F5789EF030FAED7F2CE
+:106ED000099E6BF40EC6BEE3E86BB75D1A83F7EE4E
+:106EE0008C97DA5B607E1F782269B09CAC61FB7185
+:106EF00017EAE775739A7D8837247C1FE8C414BDB0
+:106F000087E86960DD76CF0CE441ED99837F4B1B08
+:106F10000B554DFAC8C114C05FC39E66B301BE379E
+:106F2000197C81BCE2D8770DBB6BC99E69EA2DA3A1
+:106F3000E720DF1D5287FD4BDF998D1730DE07E11B
+:106F40005F373E06550DFAE6769B9EDA33BEFE832A
+:106F5000CF4F7EFFC163BFBE01C73BED89B8A643DB
+:106F6000EB7561C0CB20DFC9F68D7B66D2F3D729E4
+:106F7000DA7A07F0752DC82E92576AB317DB87CCE3
+:106F80001D762F20DA62E8F0A1DE00D40775936247
+:106F9000CF8D8E126A9FFC3E99BF4266963903E5FB
+:106FA00078BD4A7A2A640EA48C87F246D887B4004A
+:106FB000486BCA7E37612C969FB431DC97B4D6F704
+:106FC000B9C7225F798D0CEDDD8D97867290CFDB8E
+:106FD0001A8C731E027842E1E5EE0571F6D6DD19D2
+:106FE000069AD7FAE781EF2E86A721E450F0FB112D
+:106FF000A03780942D0EBF19F739969C0C1628C621
+:1070000076B68DC89FEB0DFE9A2A6C97A323FD627E
+:107010001931BBA60AE07067E9143DC1517D6421B6
+:10702000EA37BB1135283B9231EF6788A79FAADE6C
+:1070300066E4C39FDA6CF60054808CD450FEA9231A
+:107040009C412C9BF4AC19F5785E19E8F3383BF6BB
+:1070500088909F471C468277A32534B312FAB12E3D
+:10706000D7D90330DEFA864DFDD3609C1F353C75C1
+:10707000B805DE6F70A90CE1B039D5B011F48FE11D
+:107080005A8011E07EBCC56747F91ACD52D90EA8C7
+:10709000B7961899274E5ED9C642394E4E663A5574
+:1070A000CD02DF9FCDF0BFE880712F79F535337EBB
+:1070B000EF9EA8D321DB8454BECE69E589FDD8A715
+:1070C00024F693519D58EF9C9158EF9A9D58EFFEEE
+:1070D000466239F7B6C4F22C496F20736CA08FADAD
+:1070E000BC8A59231FAE467D0BF8F903E2DF3A5202
+:1070F000E745FC581A1E3AB110EAF3509EE07E684C
+:107100003C23BD7BA0F03B1EB40B4C19CD1EC7D851
+:1071100073F1915760BE06D7CB56A2DA19B4B7BD4A
+:10712000F9DEA7D8BF8DC5B52B46FC6827113FF8FF
+:10713000E7067852F11F1EC477F37F7D0FF5E261F9
+:10714000BD17F19DD7A0D2F8F7CCF604F5DC9E7000
+:10715000A33D9326DAA79937F6EB419EA7BDB97EEA
+:1071600019EE7B93F1EA62CD0AF225D007DF6FD7E3
+:1071700032D21FEB74AC0EE906F708D81F994720EE
+:107180002FAECD34129E1461EFA0E6C07A97B09F67
+:107190008C39B759908FEF3AC8E9FF2E23EF67A0DB
+:1071A0003F0F0D8A24CF504EA666E812FAD9641715
+:1071B0006D4439CBC1CB3D7D19D7205F6E9A9D318F
+:1071C00001E9C484FB2EE82F3DDFAC8D86F9595EC2
+:1071D000340614E8345D657D0658CB1E2BBBD507FD
+:1071E000706C39640DE8E1BD65C17FD8D14E1B9F3D
+:1071F000C1E9BE678DF7372807A2B52AE1D192D53C
+:10720000619F3096CF2100F02139A05EAC1CD1499E
+:10721000769EA5B283F4BBA5ACA303F1B465868EBC
+:10722000EC8D8CDB7444CF9682D0E112F4132CD019
+:10723000D9B1BF0C50FC46E8E487F91D3E1FF60BA0
+:1072400038D7557052C17E6986304EA6C0ABD3B9CF
+:10725000FB0E05FAC9C4FEC6F3F6882787C053455E
+:107260008687E0768A7E334BA0FD78DE4F5B45ACA7
+:107270001FB98E5B6A5810E193E3CA7E06FA679ADB
+:107280008272D5F032E00DD64929341370772D6122
+:10729000B43FEE59E36BDE4E7C6D233F47AE33BF08
+:1072A0000AE928F7D0D659BAF1F89D95C6312C6075
+:1072B00041A4E35C9599BF9A81F68D8FF098CCAF8D
+:1072C000397D1DD7A39D2AD725997F7354D6AECF7C
+:1072D00038978F739CCEAA91E307E1E7247EC939E2
+:1072E00014FD36127D325F6F4B395D867861F1EDAA
+:1072F000F5E72FEBF5A1C3E8E761D9A02700F585F5
+:1073000049E331F64F139615A6F37C361CE5BE43D0
+:10731000D031E82B60D69E09F6A936E4D3658CE817
+:10732000ABEAE98D37BF0CFD9D1D61B4A35E293822
+:10733000D4D18FFA91EDF18FC275E852FD3F4E81A5
+:10734000FAAE23D90CE5F67A0BDF8FA982CE93F53E
+:10735000CBDD197C3FE6413DE7FED79FD23E0C9541
+:10736000B8C6D881F7EEFE8F2B5F3467FD0FDA5970
+:10737000ECD1F51A94F3FBFA5B6C38FE7DCFB79B2A
+:1073800001BF965779FB0D500EA888BF7AF2671D92
+:1073900028584878525F3731A4D3717A2D8865F622
+:1073A0008685A1FCDDF9E437EA3C287F5CD33D28E3
+:1073B00087BA04BF6F15CFE4F9AB46CD8FF644F220
+:1073C000FBCE01B9E43B510BEB38EE4123DB0095DA
+:1073D000A5BA79EDB8BF8BAE07F90BB5F3F49EC62D
+:1073E000BBE3F6B7EDD6CA4733E0BBEED566E6079A
+:1073F0008339FF1385F981390B9CBFAE44F953C81B
+:10740000C20AEAD9C266307891AE5658993F8EDEEC
+:10741000F33F51A97DBB557B34238BBF37831C3091
+:10742000F07FB29F66F858AD93CB28B45F0C8F59AC
+:107430008FA2DC60CE6A6D603F320CE917F43E8C9F
+:10744000F7B498B70170689800FFD97461D3F873E6
+:10745000DBF70A79AE9A6D619497AAED9523245FC4
+:10746000ECEAA9F876B8EF262156CFC82F8B78A181
+:10747000F2B7EC54CE03F96B9A40767F00F7DF81C8
+:1074800034BE1F619AE671BA905F182139DFCCDAF9
+:10749000CDD08EA81DF82D87F55BC86EEE631EE477
+:1074A00007F4B0BD9342228B215EBB18AB89E70382
+:1074B000F9947E0975A59EF653639EB3103C8666CB
+:1074C00016B4A03D84B001BED5152CA816C7FC8209
+:1074D000A50E0F7D6764CD64CF3EFEE95BB928A79A
+:1074E000AD07C11EBB18D7594772CA6A4DE43FC6E3
+:1074F0005A084F27057D74AFB6D33A0FECDFFCAFC7
+:1075000089758EB4A0BE285C9191B0BEB25DFE2795
+:1075100079CC7F497CBF41EA2FBFA44F41BF4CFECD
+:10752000278554DFBDDA739EFE870DD17F0ED1D142
+:10753000D0FDE7537D77F835C775808AAE689FC365
+:10754000E789D9D7C978CE5F9128972FDE935896CF
+:1075500078B11834E74CC0B9E5DB3AEF76E8EF2BA9
+:107560004712DBD514FF96F6BFB1F661E7F5D81EDA
+:10757000F6E7DBE1ED652712DBFB2A9F77201FC7CB
+:10758000DA73F8AEF824B15DF2FA24C30B70657DAE
+:107590003D0EAEA9665342FD9CDA73E0CABA310EC5
+:1075A000AEABDC89EDFD2D83C3754DA9E973E19286
+:1075B000EDBE36E9C2DA25CFE3FA1AD31078E7ED4B
+:1075C0006F9C7361FDDE52F7F9ED6E5D993C4E8064
+:1075D000F8A551A75D9E09CF79F80AED459B95EC7A
+:1075E000DE647A7954E8A76A343CA0BF8BD2B4EA4F
+:1075F0004C785649BE137E86434F5C948D723D4F46
+:10760000F8D199F02BF4D4BBC9AF70B3680FFAA4CA
+:107610000DE545CF4EF82E8DC3156F3F65D6F37D32
+:10762000859D45899FA5BD94C1EC0ADF8F737B675B
+:10763000A87192FB5F97C1E19EBF722A7B1BF8F095
+:1076400029A3BD52C5FDD93685EC81F9D59A3E15E1
+:10765000E86372BB427EA5F977FEE687E88FB9F44E
+:10766000B8674F04DECF0F3ABC386C633FD3304E5F
+:1076700090AD5F56F63D78DE7F00EC1F515E86F4DC
+:1076800066D33CB8DFA84588A09F5386E6323BCA44
+:10769000CD6FDA34949BB5B3B53FD07CFF0156096A
+:1076A000B45BC0A7CE9EEE9C69C47847ED373C938F
+:1076B000D0EEA90D59347A9A996A8579D4823D869B
+:1076C000CF6C23532DF8B432333E2BD670FB2B6D89
+:1076D00092CF580BE3D7F6FEE4CFF8DD2235BC9FFE
+:1076E000DB93419A776DEF8B7F457B6D81E633A20B
+:1076F000BC18B3D3C86D52410FE34289659407F1BA
+:10770000E5B27062F9924389E5F771E1607D260B7D
+:107710003FD6817D2692DB4BDFB792FDB917141E51
+:10772000EE93038F9B487F4C5D6AA3F57AFFA475A7
+:107730003BFAF5F6BF6EA5F64B7E6AE1ED75A12723
+:10774000B01C782285F6D94B3343151900F72F3E2C
+:10775000D513BE715A06ECFF89D1DB3760FD25A138
+:107760000A8C8B3D751163FD58AF06C7E33C9FFA49
+:1077700027F75B477799823BA0DFF79FF9C913DFB3
+:10778000C57177E56528B03E97A15E8076931F347A
+:107790005B71BF31F9FDC786A3DC58BAD39430BF03
+:1077A0009D998A88AB79D290EE86F23B1E5BFF13DF
+:1077B000FABEF4C411A2BBBD86800EE37881F59CAD
+:1077C000CEF65AB89F74AFA53088EBF47426D73B39
+:1077D00097E976FCA811EDCB57B91D3254FFA5EE01
+:1077E000F9DDD583F81907EA61DC6258E733EF5910
+:1077F0006FD5008E519B13D7697430B1FC4B31AFFC
+:10780000792CEE7D31C2336CAD1BE1D9CE089ED20E
+:10781000136FDE5C8CF6B889DB21C9E31ECAE4F283
+:10782000E1D147A11F2E67F4DC0E078C015F2F15F5
+:10783000FCF00B85DBC1F0B7220FE87F291A10C3DB
+:1078400062EF9726C121FBFFAEC0D3C7E6B41DA8E7
+:10785000CF9D464EF727571FFA21C63165BB775695
+:107860006B5A759C5F79E1E665077360FDEB7BB24F
+:10787000689F29DFD7EF7ACE750BBC3FB553F5A2D1
+:10788000E95B7FD3233F988CED76E9430827D6A3A5
+:107890003FF354E8F9346CB7B0CB3101FD25F2FB6E
+:1078A000459BAFD4AAE3E4E917E527C9FFF5627F5A
+:1078B000FCF4A4FE697980EFA59B152F365B1AFABC
+:1078C000FAF5D7A2ADD3A5F7627CA342653EFD04CD
+:1078D000DABACFC6677DCF930773A1BE69DFC40A4A
+:1078E0009CD7069DEF9A71C82FDB0CE4074B5E1FF7
+:1078F000E6E4EB0CDF8775F0FD861B6C75181781CD
+:107900007EFBB07CA074871EFDF8692740BEF1F7AE
+:10791000477420334FF4DE351EF62C40C7B676E4AC
+:107920008FBDE8B8C0711ED7939E60613E8FC9C2FB
+:10793000FFBCF48F9D46159E274EAC49ABE4FC4737
+:10794000EB8442DD09F3AB7B701CF1EBA2CD89FC2B
+:1079500025DB4978170713EB93E9C2E394FE0A5637
+:107960001A4F5FC9ED3267048CC88FF52B419EC753
+:10797000F14DFDF10E23DA5DC9E3A005C9E4BAEAD1
+:10798000892E612C9CAF85CF174C5E33CCF724FE3B
+:107990008BFBCD15DCD72F51688A6CE945ACDA0337
+:1079A000F85C3A8BD5E053CAC3539342E3B1FD5E12
+:1079B00043E4911F911C4C257970CA1E4E43BF525F
+:1079C000AEF0EB9DF284D350CE9D11713BACC7F26B
+:1079D000925ED007C0D7EF7F6024BDD0127A2E0D03
+:1079E000D7EBD413169D0ED6E5FD9ECC2AF4079D49
+:1079F0000ABD9C86F33A19CAAC42BFDE50722259C6
+:107A0000BE497BE028FEF352C6AE746A9A13E51DA8
+:107A100006197240DF643697350FC2F7F23BA7B103
+:107A2000B90CF334A2DFB47951CE5EEBF4D0FB5A3B
+:107A300085F7877F18DFFBE850E60E5CFF43FB47C6
+:107A4000A6A39DF011F3A4A3DC9EEBF2F99CB09EDB
+:107A5000EEAA7E8AEBBBA7336F2B7CF3B6DE7BBB33
+:107A60001DF0761B03BD85CF72BF91FC2D6D5904AF
+:107A7000D77C958555A0D3F9A857C75399EC98F9A9
+:107A80005D4AB015E0B86D63E23C17769A62EB0B85
+:107A9000FF2D6620109181BAE2DA41FF8B517F02FF
+:107AA000FE9698593805FA5DF250E2774B5998E006
+:107AB000A97FEC33D36078FCB3C0E35C97B618F1D0
+:107AC000A8CC32135CDF7A5C21FDE6147EC6E8FDAB
+:107AD000E9418C872D15FA7A81693FC1D37467AD6E
+:107AE000761BD0CD9995F3B5DB3279CA08EDCB364C
+:107AF0002B44874BAB59B800E05BDAAB84C7A13DA0
+:107B0000F11A5F27D92FDBC6DBDD2CEC9D05801732
+:107B1000B41F263FA60452417E2E30C3560EE58880
+:107B2000981FD6A743B98E75D0BC1A5884E0588BDD
+:107B3000EBC8FD7904FF9F5FE3EB37B96EBB1E8195
+:107B40003AB4BF82E27F1F332FAD23D825CC927188
+:107B50002E9D20DEB5383CD5752596D94371E5615B
+:107B6000885728C7E1BB71F767266D103CDF3FA03F
+:107B70004F82A3678E63E7D8BD6F8975B8FFEB0BA3
+:107B800073500EDC8BF66BAEE86012CA4D26FD1A00
+:107B90006133F46FBD8425F839C0BEA2F283CE995B
+:107BA000D337E733B6C9E0A778C17CBDEF2086B6EE
+:107BB000FEE9F2FF04D777BE4E2B54491E682369B5
+:107BC000BFBB92AFC703139A47370FB2CF95F06F81
+:107BD0005242611DCA8367B87D905A1E35F8E3F89A
+:107BE0006CBF9073E9072207F3905E9E54C82FBFC5
+:107BF00045616D0AE0D90DCB82FA608B72F420EA00
+:107C00008F2D577B582BD497EF9EB9EC79DA2B5BED
+:107C100029AFA76177A5BEC146F3E7F66A4AF376B6
+:107C20001DD467DF5A3A01F904E67DEB2C787F50CA
+:107C3000F06D8E8DD3837B4DA07839FA650FF89661
+:107C40003D8FFC3DCE4AFEAF6C33FA7AE9D98E7691
+:107C5000A89BB528D8EEFE34DE7F964E7FEB4C2CE9
+:107C60004FE0E58C558AB68388F83EEA3FDBC46A6C
+:107C7000107E7C8FF63474A7F5507D90E69B3DB561
+:107C8000B90CFBCB1ECE9F4E63381FFB796560BDE0
+:107C9000FD3A94BB2B84FE5CB1BD2A1BE5E42BA707
+:107CA000CC2ACAC357DCD20E0CDBD00E6425A5BC8F
+:107CB000BDD0532BCAA66623FD3A0B13DB9D31685A
+:107CC000E997A0BC3FACA7B8CD9F6C5ABA03DA5D68
+:107CD00066E4F3485EC7A8D0AB4D9F282C18B7FFC9
+:107CE0006F9A7396ECECA64FD484F7A7569B593045
+:107CF0006EFF5F5F77601AB66B60FD6B91AE1A42E4
+:107D0000292C1847E79759071F57D277D3277A1698
+:107D100018745C63E2FB4F32592073B076AEC4F73F
+:107D2000308F84F29EBF0CCC03DFB3499134F487CB
+:107D3000CE40BD06E533415DC000F2E41503D757E0
+:107D4000A7ED91047D76DA13E1FA0CFD3D366E6FF6
+:107D5000CFC47556A369B35263E3C87AFC3E236E61
+:107D6000BEA7E7185998D6274A7020FE02A318DB51
+:107D7000DAFBA111F35CEA7BF713FE24DDC4E331E7
+:107D8000101F3F6AED0FEB80F7C7DCDFB961EC68CD
+:107D900058B20382CF039B36605CD8A5D725F07D0F
+:107DA0004AF9801C20B1733F46B3C81FFAC086EA67
+:107DB000FCB8B2683FF07D60F374AC2F1FCBBF9F5F
+:107DC00078FF9697D65032480797A36AB4D0971A8F
+:107DD000573627956D501E1757B627D53B93EADDCA
+:107DE00049E57CDEFE546AB850EF05E0EFEF9E8E69
+:107DF000F95CA772C27331FF6BA33E38BD1ACA0D7E
+:107E0000E55CCF36F62A5EF2E109FC357AB9FD670A
+:107E1000F3468C98779652DE7F10E544FD1EC5AE82
+:107E2000003FD8423D612AE3779EB8EF420A7D5772
+:107E30001F3A4ADF0DD97FA98EF87D43E931DE2E46
+:107E4000F42EE9F3756DCB28CE2EE3C87AE6D7F28F
+:107E500094581C59CACBD339DA73242FF72976E406
+:107E6000CF013AC57EE3FC37B2FD1BE37A7F8BE698
+:107E700042CA8A0F5BD02EFD63C3BB13D14E7B4336
+:107E8000E8854D4A70348EBB95F947A3DEFB66C387
+:107E900088FD3A68F79621D28DB1B2D5F73F49F8FF
+:107EA0007B2B355280F9742D59E1E9984FF75656DE
+:107EB000A41BF1F9FBACFDBCBE205280F97377DD49
+:107EC000FF3EAF1F11E9C6F2E359BFE7F5E3220514
+:107ED0007A3B6E758E4CAF86FA87ED83F3F5ED59DC
+:107EE0005C9E48F8869768CBB2D00EABE7FAA41B2D
+:107EF000F63666909B73979C7CFC61C0C3DCEFA454
+:107F0000903C7BF8D4F5D3B99D1DF0A915E887E521
+:107F10007FA4EF486EABB4FFCD411D97115B8FD4AA
+:107F2000C27E0FE9838B9A7BD06EC89E3B96F4C1CC
+:107F3000579DDA111C573EBF9F074F687F24CBCE59
+:107F4000E5B35E4771E9ECEFA6929D75AF85CF076B
+:107F5000F886D6D726D6E3EE2CAEBFEECEE2FBB740
+:107F600045CE2BA9BF9B855DDCB93EB8CB02F87F1F
+:107F70005DE6BBDCC7EDEC5BB6835C0139DEE9D0C6
+:107F800072509EDC22F2D7A4FCC0F71971FB8BCE95
+:107F90003228DB62FBC8CE995A8ED5894F970EE303
+:107FA0002F521E7516F3EFA45ECA6EE5E366DF3B43
+:107FB0007A07CE2345E57EA4057346EE6821FD3E93
+:107FC0008BE6CD342D4781FE8E2F1EA643FF925C9B
+:107FD0009FEA12ED61ACBF59F8E7E53AC9F53C22DA
+:107FE000E63D5F0FF601CCF3772E3FCD1FEC85F118
+:107FF000C28F45F6C2115CE3AC187E991A9988EFDE
+:10800000FF3FC2D34B5F069E1A5682BCD05D80BC38
+:1080100010F8DBA4840DD95C5ED0BE18DFA3DE7936
+:10802000CCE97F0BFB97E3CFFD6E03D98712AE94AB
+:108030003B9EAEB9919DCB67C9F6DB09B15ED2CE4E
+:10804000F44A7FA418E7ADD7CD147F78CB1822B9B6
+:10805000F916EC6B5A50BE88F879C57796BE82FB4C
+:108060003AD9EF752E9ED76791EBAEF87A16166364
+:108070003E090B98711E338DB4EE52EF763A787E3E
+:1080800048E79D79941F72864518F9352731928FFC
+:108090004007541FBDC945FC0FED03166CBFF82205
+:1080A0006A0F741120F9709395F6219D186FC6FA26
+:1080B0009B4A8398CF82FB5FA2B7C53A1A77107AA2
+:1080C000E17EE3513C5F42D28DAB95FB6798AA8D70
+:1080D0009F19A7E72F72713F514A79E4C9DFA37D49
+:1080E000BAD142F629EA588AED7464533FB0FE993A
+:1080F0002EBEBF273ABBED07A9222FCD5B81785D4D
+:1081000097CAE9B2CBC2E34E5D600F935C14F42BC7
+:10811000F3E2FCC2DE8BD4E9D2D05E28760DF80DF6
+:1081200034DCC793DF1BEAE74594A3B8FF9A17D066
+:10813000874DB89F6ABF528BC4ED47F00FE376B707
+:108140000AB9CA3633F203DE8ADFA561FFD6348C62
+:1081500053DE8ADFA3DF75D59509F1B84B5C9CBF70
+:10816000257CC972FF120957C7035AFC38B2FFE4D5
+:10817000FE605F59EECA223C87D3717D5BF4B47E0A
+:10818000C970463673FF75647311D19DEC6F283842
+:10819000FF4B1FFDB6027A70E154BEDF96FB9805D7
+:1081A000623FCC5625EED3D05F3250D69F5B4EDE79
+:1081B000F7619C3DB13DB75B52C6468DC4B71E25E5
+:1081C000017E89AFA1F070F317C49BD47B0F588058
+:1081D0000F32703BAD10FD6EBE3385F498D3181C82
+:1081E0008D74B5C0E5A1765B31DF85F42ADFFF7EB3
+:1081F000FC8AF45F24EE7B9BACD16D88AF262B23E9
+:108200007E3ABD2F95F8879544E662BED899BD2683
+:1082100086F4DBA84446A2DC3AAD68B5D4AE25C5E9
+:10822000837C24FD036F3FC5FD034D884980AF2942
+:10823000F077CA576ADA93B81F3E0DFFD501DD9F6C
+:10824000D6452AB03F290FC08ED6C83EAAE3719CFE
+:10825000461D0BE03EEB32DDBCC59CCF73D90E7AD8
+:108260007F74E4F2383B1DDAF529199C7C906FEAA3
+:10827000051E1B75C7A85D3DE61D213E71BF85FE2D
+:108280002EAC8CF3CF366E7C9FF29E1A7727AE779A
+:108290007D8C1E94CF14FC2E8E3E889F03421E3090
+:1082A000EEB7A8E671E854514EA9E9A73CA826E12B
+:1082B000C7C83A1099867225B53CC4E6C1B3E90433
+:1082C000B73726F76E7F0EF7C78E9AFE02648326B5
+:1082D000E1EF93EB2DE1BCB4F73EF25B483B256E3A
+:1082E000DF397A5682FF600D7D87FB581C2F82AFE5
+:1082F00072900CB87EDB24F41BE84192B70B3A462F
+:10830000911E443D85F249EE83515EA19CF8A7ABD6
+:10831000AA07F9755376D563AE2C3E1ED9F5B8A9D8
+:10832000BA74683F9DC48F6C87FBE1CFF3C3F5221D
+:10833000DD66C5FCE3045139E64D6749BF1BC5E75F
+:10834000962B9E6CA4DB77F47EF2AF2D6201F2F7E0
+:108350002C46BF163CEB05BF2F147EA285C23F847E
+:108360007EDBF83822FA4FE3CB4B583F971B3B4D4F
+:10837000B1FC1AF4E754B3702AF4D780FE267C8649
+:1083800012BF6B6451FAAE69CF67A6843865279F28
+:10839000F7AD62FD1DD5413DCA892D16EE6792F2FB
+:1083A00063F22AEE8F4A9FA015DF8574FEA281FC3E
+:1083B00014FF2DD66D40CFBBAA9E42BD62D5F3F30C
+:1083C00068D1BB4C24378F833EEE11FE9159B80F14
+:1083D0005DCD34CC5F67AABD307E9F2A9F1BF65AC5
+:1083E000EA907EDE75E912E8EB472E9ECF437E23AE
+:1083F00092CB29A477417C8C47FAAA1826F5221B38
+:108400008FFEAAA362DFDC7883CD8FFD45745CDE2E
+:10841000FCC9C5F7017F72F17C4E591ED8E709FAF5
+:1084200091F13FF4DFC4FBCFFF3ED0FE3E9177CB0E
+:1084300068BE9B168BFCEE013AD6915C4A19EB2381
+:10844000F97B99AE8AE452F43D9B07F152F37EFD2D
+:10845000629CC74773AC748EEF36E1CF4DC976503E
+:10846000BFD27F7BBEB858CD86D1242F65FB34DCCC
+:10847000A0649DEB07DE2BE4D85EC6E10D9CB0F254
+:108480007C13950550AEED0D8D0E22BCB5C2FF805C
+:10849000F60DCAD7E8937C1D99CAEDA1BDBDE38254
+:1084A00048EF470DFE2D0BD09FD36320FF1A538357
+:1084B000BB1EC17E9ECDF162FECF695D74DBAFA0B5
+:1084C000DDDE138FE661BC67AFF0BBD71BC323C9EA
+:1084D0006E16F98EF569E191E807FA8558AF7A2BA7
+:1084E00094E17DAAC53F2A3B2B1617C3EFF0FDB1DF
+:1084F00020B7CB8F314E07818D3CEE09F8CD5980E6
+:10850000F0AECFA6B81AAE0BAEC3DBFBC6D1BC36FD
+:108510001944FB67146AAFCC2A9D4B7A61832913F7
+:10852000F17FC667A47CDDA67BB9DD385FE7D9B6ED
+:108530001265E5B32934BF059D8729DED1F4834553
+:10854000740EB269C9AAEBD8E7C40150AFC4FBAF3F
+:108550004FB36821ED87EB8685C200C7E9DED15EA7
+:108560001EC6E3E76A1A455EE87103D310EEE83EE3
+:108570004370B0F37E43F58FF3C5FD29EA37F273FC
+:10858000C7C75B481F24C65FCE573E6D888CBC139F
+:10859000C65F9BE9BF293BCE5E6C7A3687E4DDDBA4
+:1085A000F7FCA590EC8A0E1E2F386ED0E6229F387D
+:1085B000AAC3C6797176D8B26C6E97CE3709FB1113
+:1085C000E4603CDFCBFA8AAA443E93CFE66C6E8728
+:1085D000A48AFC8073EB65FED9F526D49FDCB584B4
+:1085E000FD72795D24E26E934F44F7639E557DA83A
+:1085F0008CE27A45ABC2C49780EF30DAFFC7B7A4EC
+:10860000727902D3C47E164E6264BF2ED4F37C8787
+:108610008526B087B91EA7F6EF6CC9263C54ACE19D
+:108620007660F44985E4A28C3FD632FEFDD36D47D7
+:10863000037A685FBB532903D1CA6ADB2A291F6208
+:10864000495731ADFF64217FE79BB4915B90DE9E7B
+:10865000E6F12B188FECEE7ACCF99A4072C988FAC1
+:10866000B06EA7C2F0DCB09C7F72BC8F0513E32D07
+:1086700093435C7EA3DE6071F69AD443A82F589290
+:108680001D9948178104BDD78D789D1893FF84B13B
+:10869000CFD183604F6F43FAA9A8E2FC17ED5108D0
+:1086A000CF0DAC99C787841E1A8047E8B177F45C78
+:1086B0006F2E34DD47CF9FE321B02CD48311AE075A
+:1086C00041AFA15C1C8A2E7E3E045D487AD82DE81D
+:1086D000A3FE040B5F0EE3D5AF62E186F1FC993A8D
+:1086E0009EF432D7CF66AE9FF169BD003D9DAC9F31
+:1086F00093F571B21ECE36727D2BE920DE4F8FF6D8
+:10870000C8E455413DF7C3E6DB31CF4FAECB22A7DE
+:10871000D6979715B3B79A8E98CD9E8BB1EC63C35D
+:108720006CE85FAAF415A0FF5CE5E78D53004FDB12
+:1087300071FD847D7E79015F47B7C8E731A83E5659
+:1087400066C375EAA7FD74348B517EB6C46F772A71
+:108750007C3701BFE3FC38F0BD99B559E3BEAFDA11
+:108760006B21FD72F699543A57C6547F9103FA7300
+:10877000BD01763A944FEF4D25FD7E5AC87BA7F494
+:108780005BB0B5B41EEFE23A4F44AAABCA43FF2F29
+:1087900053A6E7313A6FCDEDC606C7507E7B515FD9
+:1087A000DC7F03A73313E9D9B38EC8ED58067828C8
+:1087B0005FF8BF04FD36ED9E5AF65D8CF3FB6C5EF0
+:1087C0008E557F19DA0D26FD8A1BCC7A3C77BF2A9D
+:1087D0007A27CCA3A1C04679C8D5456FFEEE2628DE
+:1087E000BFB7DB40E715173F7C7D7A183F5335F75D
+:1087F00060FA7971D090700E6EE9CEC4724328B1E0
+:10880000DC9474EE7DE59BDB5FEA8BAB37BB539D5D
+:10881000B4FE1EE6C53C6AA6FF46BA7F1079299FC2
+:108820007F591D7CA96F04E5A1A5BB797E8D11ED53
+:108830009A79480F837C77309BDB352653F309CC3C
+:108840006737FDC244E7E3DFC8F6BBDDE85FD64526
+:108850000FE27A9A8A4E8D473D5855F40F8A8B9DC8
+:10886000FD1EF3227ECE5A2AC9BE39BBC5E2C1FD28
+:108870005967A18DE8A0F35925A870FB7DC6C40AED
+:108880008C83D21C58D3E6ABDFE3872F98999FA740
+:1088900087DD8B1BE58C46FBA977665AED6BE0BB49
+:1088A000BACD5CDFD6B3FE349403DF748BF5D33FCF
+:1088B0006634C33F8BDBB4D12D00EF529F95CEDDE4
+:1088C000A89FAA74DE7C1D761967FF97BBB93C6828
+:1088D00030478C9538FE3F56D4A06B4CFAB94C0605
+:1088E000BF86E7BB0C7BCAC279F06AD1CAE7689F32
+:1088F00033104FDEC7E5D6A23BF7D37B65560DCDCF
+:10890000F71D982FE2E5B92D269AEF3B0536DA6779
+:10891000BED3CDF7BF8BECC6A099EC8D4F32F15C86
+:10892000EC3BDD063A8F7E2E3EAEA2F3A9EF76BD7C
+:10893000407EB877191F37B05B4FF6CABBF6684563
+:1089400018F1E8694E437BB76EF3623ADFBAA85B71
+:10895000EF4379B6A8FBDBBFBA14FD47B36E2EC751
+:10896000295DE158E1F2D862F5D24E5533263D82B9
+:108970007C78C5A753FBAF407BA91BF8A498E7CF31
+:10898000A39DDED77D15D9A58B665A1D382F4FD7ED
+:10899000C3D3507FBC3B3397CEE32E7A5C6178051E
+:1089A000C322C74A17BE5FA4A8BEC1E8E9E36C3D75
+:1089B000E1B5B2C8E60DE377BFD5139D005FDD805A
+:1089C000FAB3A1DB40766FDFACD77F779333C6571E
+:1089D000CAACCDD74DC6F63F3150FB017BA7EB5A51
+:1089E000492F2C5C81FB2A8EB7643E3315AD1A8962
+:1089F0007025F3DBA235CD2379FCEA8BF11DEBE288
+:108A0000E773EF70F3FB23BE00DF7DFF8BF01DCB20
+:108A1000CF48D84F9D2BDF02D44EFAFFCD5EA63D46
+:108A20006CA378AFA680FCFD0906AC27E2939F3BC0
+:108A300052FFBA7CE7AB809F316E7F07F26F11D394
+:108A4000CA506F7AA2F62A3C536413F61CEB32C963
+:108A50007D00D9F79BB2D8231BE2FC0F0FBAF93E79
+:108A600009E4C016ECE7F41FFE7110D7A9B1F0D4E9
+:108A700078F4FB367DF2278A17DA7A79BCD9E68D4D
+:108A8000523CDDE0F4111D4AF9DEE4E5FA27795E97
+:108A900027DD061EE77546A99F17723C54EE14F1B8
+:108AA00095AD2BADE44FDDEA0C5AB87F21C0503FA5
+:108AB000CD98A4E77132616F5D2BFC91E6F2E71867
+:108AC000C6C7D8149EDFF56AF9736A26947F35E924
+:108AD0004A2F9DCB2B7FB07D18CE7B8A41D40FA728
+:108AE0007B33FE8F5649F5CBDD7A0FF2F78C729E01
+:108AF000DFC8EAD2C86FF26AF9DBCEDBE2E0F73119
+:108B0000B3C70674330B98353E9FEEBA29168F2DE6
+:108B10008E7E3EEA506AB8DDEB499F3D8EFB4548AC
+:108B20001F9727E263B9DB48E36ECAAEEC43BAB9DC
+:108B3000E2AB7C3D4E3E6E0AA21C3C29CEB924E33A
+:108B4000EF376EE1A7534727C4ED9DC65021EAC910
+:108B5000F795C4EF96B4EB296EBEB85D614118EF8E
+:108B6000E4AEA70B519EBFF7F0D385F3E2E049FED8
+:108B70004E3EFFE816F42AFC82C97EDEA1FCBBB2A1
+:108B8000DD99CDCC6F1E1E6B7FA6EE6FE4DF9DD707
+:108B90002BFCC39A56E2C4FD90689FDC9F3997D3A3
+:108BA00087B24721BF87F46F1E3BF420465206D69A
+:108BB000CFD25BAC8BCF4B94CFC962DDAEC7758390
+:108BC000A958DA7979A8F51A8A1F77083D24D7EDD4
+:108BD00058FBF074C4A3B1D1A6327EDEAC14EDF51F
+:108BE0006E66F5223FFD45E4A73AADF0043BCD9813
+:108BF000EBB6A13C93E7FBEFB0A6EDC0E75F44FE08
+:108C0000AAD30A4FE8A720B794FAFB8BCE47FBBA4A
+:108C10003BF41D740E3145F049360B2B0A8636960F
+:108C20003EA550FE567B22BE5DAD5C8F446B8DA48D
+:108C3000BF24DE2F9B773BED5F0759AFCD4847B987
+:108C400093F8BBEA9C62E1EF88501CC13289D9716C
+:108C50007FDF7A6980E090EBD5C49B33A55721FB79
+:108C600019F3585232285E1A104F66CB6003F18315
+:108C700014B1DF6549F1826CB0BBB19D8413CA9415
+:108C80000F73AF23D43192C75BC92EC57EF1FDBCF3
+:108C9000B12AF9DBB19D71C2F9E96F804E457EE1E1
+:108CA0000CF9BECE3A687C62069EF3C17500FD8861
+:108CB0007621F31A12CEF974813D8DFB3419FFD55C
+:108CC000EB42656EDA9FF447D07F62AC307B50DFB9
+:108CD000A6E843A5B87EC9F1606857CCF310F21D31
+:108CE000A867E4399EC695537D18A702FB2360C68A
+:108CF000F59BC9D7AFF1CE4A7AAFCC2A6D41FA6A5B
+:108D00005AC5E8BE81A9BD3D94EFD454C3EDB1A6C8
+:108D10003D478D0CE8779EF0E730E17F7689753D21
+:108D200026ECEF58BC2BB20DF3B73B17E7D3B9DDF8
+:108D3000E4BC922F1AEF3C930A08B9382E8E956E38
+:108D4000E67A46ACBFE46F19D74A1DEB2B464BFCC5
+:108D5000C507DE7BD99AF545F2469EBDE773F3461B
+:108D6000D8F4EBB0DE8C56BEA84730408F0E9CCBBB
+:108D7000B37828EE35508FF72998F72822EFE4ECE6
+:108D8000B5579650DEA8E8AF6F23E67FDF6B610929
+:108D9000E3C5C3A726F56F80FE6D1ED9FEF83557D3
+:108DA000AA14FF15F04FDD88E7FAEE3524F64724C4
+:108DB00028CF119A63E3F9BA7E70CFC6FC983E07BC
+:108DC000FDBE3167624CAFAF7B7D46C7C51EE4AFC9
+:108DD0008F290F57EAE72627CF234996630FE470C0
+:108DE000790E76F13454B9EBE62CA3FB0706E2BF0B
+:108DF000BDB51ADAC332FEDBB4CA47F9B8600FFC5E
+:108E00002887EC8153EFEC6768779EA47D41D327D8
+:108E10002AF713815D81F7C9987B2BC91F8A69A640
+:108E200023E2D67F89D05368C3233F3475DDF8B081
+:108E30001EEA3FCED11EA27E0D83DF27B52F87DB32
+:108E4000F14DA5555B501EB08714BACF6943E94771
+:108E50006477343E73E5C4F87CF2C57BEEE7F9C86D
+:108E60003B0D83CE7F5F0E8F0B373EF324F93B4FD4
+:108E700006F931983A35B81EEDD0BA3A1D5A5EACB3
+:108E80003C587B13D90373601E30AF0773387E9A4A
+:108E9000765E1FC0FCF626F84F81575B7D0B695F3D
+:108EA000B0758ED986719CA6D279CB88FEED560D11
+:108EB000E79F0C672CCE6CA573C81BF6186AD08E82
+:108EC000AA00BBE9E7006F41C6F41A2FC8A53C7D94
+:108ED0004FD9B76C18771F5C2FDF92C7ED8036C56E
+:108EE00017F85A39F939597C1E4FD11E6E9FBD961D
+:108EF000C3ED43F9FEB51C6E374E09F44F459A7B1E
+:108F0000568DA4A09DDCC4B40F71FFCB7C360FF945
+:108F100077198FB33B577BC8BF6B7646EEBE98EC94
+:108F20002895E2CC727F71FA19EE17BB22D77F1415
+:108F3000D7B1421FF9E1D7106F77ABC24FCCE54CE8
+:108F4000E1F5B609E8C7B238233FACF150FE0DF9A0
+:108F500025D22F6FA37578D6C9EC889FA9815A5561
+:108F600089D333526E4C1D3887E324FF6915176B84
+:108F70006C04ACD63B6622D1B6CF326376C2A17FF9
+:108F8000CC56F1A5B41F74663FED73AAE7C0BE11BD
+:108F9000E9726DF4A00EFDF5CE7EB21F1B420A8D64
+:108FA000D350FA33CA8F5B2AF2B006F2A1D408E597
+:108FB00087FD3D2745E8C7364E0FAC9FF6C5EC311F
+:108FC0008E7FD09B943716B3E35BF8BD67A23FA3B7
+:108FD000883334083F0E208AEA8DB9C2AE137E8DE5
+:108FE000589E1B1F97A99E8A78BFC3A699A04908BF
+:108FF0002E4F1AC2DB6EF5A5E7025CC7EA7484A2A5
+:1090000063ED2974BFD426A55F437F64A08CE7C5B8
+:1090100026D351891837FD40741AEA93E83343E5A3
+:10902000C5F23CD82D132FA27CF2F23D1F4E43FA1D
+:1090300060358CF8B171CF85E5C58E16EBF1A5E7EB
+:10904000C57A156D073C2FC97524E6C57A39DE65EA
+:109050007C32391FF6744E58E5796B916D0FE3FE43
+:109060007B8F89F23D66EC79E108FA276798598889
+:10907000E2B54976C061E7F55310DF673E7867DBFC
+:109080005D0CF3A29FF2F27392897A7D28BB9E62F7
+:109090001671FBBFEBE4FA7F4976BD94BB4D629F2E
+:1090A000F4BE12FDC1489CDF3EBD7DB0732DB7E418
+:1090B000CA38D710F91CBD83E773C8735F3591E2D6
+:1090C00084F8D382017AFE62F1AC3AD48113CF8D59
+:1090D00067A9223F4B55B808600E9EBF23E3596A2B
+:1090E000CF688A539962F1AC301B249EA58AF8D0D0
+:1090F0003A83564BFE967D260FDF0FFB480EB5F5E3
+:109100006479514E352D39F9041ECD571DD3DCA895
+:10911000FFDB04FEEB2F3C9ED5923BF1DC78D6764C
+:10912000617FBD5DAA0B1B01AFDB1997A3815E199F
+:10913000D7D2D1FE347A4F01C1ADCC3213DC6F3FB0
+:109140006BDA817EA6F9325EF52CF793CD1771A903
+:10915000B7678D243FD250789EDF9EE8F7FF21E26B
+:10916000398BFC78E46FBFFD3F66929F7D21FAE961
+:1091700087C7CE2F30E1AFF3B4F3F3ED9E9D0ADD48
+:109180002F8A64A223DBD24EF78C2E0571B81545C9
+:109190006800A8E62BF05AD12968D778DAA00CC667
+:1091A000BBBA5E0DB8A1DDF62329E41F5CE7F488A5
+:1091B000FC331E3F0E6C54822378BF74AF58A04D11
+:1091C000A7613F3FCFE57EA59773B95FC293741F38
+:1091D000419B41C481C5782D0CD61D9E3A853FD751
+:1091E000897BEB92F121FB6B33349BD14F172DE040
+:1091F000F7939C356A73C87F9C3192EE216A4B6D60
+:109200006EAFE1F5C4B3672D511FD55FAE72C39247
+:10921000793210DE5DB922EF2E09CF0B3A12CBC99D
+:10922000F19BE47353F3997F54CEF073CF15ED4265
+:10923000B909FD9FDD502CD6C54BF1903683E7D799
+:10924000C51407E5F70CB5E473BCE90AF87398A3F5
+:109250009AEE8B037EE1F618E3F00FBBDCA920BF8A
+:10926000B43938DDFEBB7027C3FB9BDC91445F6DD6
+:109270000ECEAF6DEB9520C71787FB42FD1D1F4A31
+:10928000B9F425C9C5B715EF23E162FA8EE443E0CE
+:109290001E03F1DD5E0B3F0F29E51525E8E03E5288
+:1092A000EC5BFF2EF4D6FC136BE9BEA0AD75C3D208
+:1092B00030EE39F57A1BCDA3F1597EDEB66155A4A7
+:1092C00010E9BAB12A32B27910BCE200AA94AFD048
+:1092D0006E9E93F17B67DA13E378C9F1D9B5999A59
+:1092E00005E33FF7EBDEEE7901D7BBC7427AB271F7
+:1092F00055F411F403DC9CE9B7E7017D9CBAF3F562
+:10930000698A873E23BBFCCCBE51744E705E5BE223
+:10931000B92BB631313EC8DA33F8F9B2CEC4F7789A
+:10932000BE28E1BB73E285DC4ED964F48F463BF284
+:109330008AAFF27C880F16EB18AEEB0716BEFE81E3
+:109340007B5285BCF68E8CD707E3F2865A5F68376E
+:1093500016E3F23C0F54B66FC0F58575AD17EBFB05
+:10936000C1935F1989EB7BAAE72B23717D37193AEB
+:1093700034E48F7FBAFC6588AFE357FAC8CE93799F
+:10938000AF174A775ADEFFAE3EBE56E2E50BEA6300
+:10939000FC8BF77F3CFB0F7DC042FA859F338DF934
+:1093A000E14ED27D5B673ED129288F87EAEFBF85EA
+:1093B000DFC96D6601F477545445E8BB8ABFE918EC
+:1093C000DA75D29E4D86DF2FE05F96A7BD9C83F3B2
+:1093D000107EDB3AD1B739F831B79B1F52C82F6BDB
+:1093E000F604D226D33E69C1257A922F3FA7730F88
+:1093F000AC57B1E37E63F1432D547F7ACF7CAAD77B
+:1094000099C361DC5735403D96D74D49CC6336EE64
+:10941000E6711DB98F05385E4038529C5123D267E2
+:1094200023DAC90062A3CAFDD78D4EE60D30B46BB6
+:1094300013F77D323EBBD5C7EF73D9DAABD0BD4E43
+:109440002EA3BF381FD735294EFBFD3CAD3B2F2E39
+:109450005E3ED7A505B0EC34B242C4D3BA3C8ECF41
+:1094600088419EBF4A3C0F7868FF0D640FFD99F953
+:10947000D207CF2B0B26C4D1178A739B0BC5B94DCE
+:1094800094D3E124391D5FAE8FCB2B0B0F961F10A9
+:10949000975716FF5D7C5E5938419E7588730CCBDB
+:1094A000297EDD0474BE72428C0EEB99F8DB1C7DC4
+:1094B0009BCEB1EC34917FAC5EE49536D51DA37D97
+:1094C00047139E8BE1FCA8F173D1DC1EAA87FD1C1B
+:1094D000E5D78612F34F770F2937FEDFF8C17F29D2
+:1094E000E581E047392F398FFA5E85F34F129CC929
+:1094F000FBD8647FB6DC875EB0FFFF7F592E4592B4
+:10950000F0F0AFCAA573E20225D134EF97101778B7
+:10951000CFD3E142D7A0CC036EDFC7F380A7E96DBC
+:109520001A8F43EA799E42723CD6338DE28D32FE29
+:109530006B7E4A1F5C534CEDBD98BFD5B02F95F2A2
+:1095400006EA3C75647727C72197B09E69B8147FF7
+:1095500066AFD039AC7F3BFE9F2FEE09F6B0E22F0D
+:109560001AFFCFE7FBAE0B8A433E67FB38D31F479A
+:109570002F5563C1801F3B747E56413E5FFF14919F
+:1095800027625603CC11F7FD50DF8DC8E7795FCF16
+:1095900089BCA27B5353E81CBEDBC8CF1DB8753C09
+:1095A000FFE9E31CDF2884DFECE1EBF9E3676E649D
+:1095B000788EECC786109D8B0F34D8BCA8C7A4FF4B
+:1095C00048F6DF9EC3E1BA503E9A92FFE5F2D1F928
+:1095D000E4C7B47CE58BC5D136030EE2F82B991FA6
+:1095E00086FA6E28F97263BE6F16A70B6D3CC51F15
+:1095F0002E502EA59483DC463DBDDBE4C1FD03FA6D
+:1096000051483F6ECC91FB6F7E4FC0BD05A4BF3E5D
+:10961000B0F0FD843CC73380BF21F1FDAFD979BFE5
+:1096200073F9EAF3D1BEABD4E81CC0BA54AE5FA262
+:10963000BB781E50F2799664BD22CF63C8F1BEFF9D
+:1096400025D3C31795AB77CBF1FF4DB90A7A96F6C0
+:109650002F43C65BCFF93E20F231FB3591F742E74D
+:109660001A245C4DFD3C7FEE47827EE5FBEF09FD51
+:109670001BC9D7BA90AE4EFDC16CC67866793997D2
+:109680009F8D3E1BC5031A433C4FA67115A37DBF9A
+:109690003CB73AC6ED7F04D76FDDEB36BA87B471BD
+:1096A000CFF6F6619447E027FBEEF41FF8FB37B2E4
+:1096B000FD8F62BBA6559184B843C5671FAFAD2926
+:1096C000277869DFEE34259E077A259FEFC7E5F3FB
+:1096D000C501FCC2FE04BE3B55C7F3B59B9C9ABDB9
+:1096E00092F207B85F3BC5D34F7EA0C6DDA4241815
+:1096F000258F62FD77F3896E1A775796D17D002109
+:109700004B19DD27F306BF7FE9D49DB9413DF783AF
+:10971000EF477853CB8357A39D5904E3A0497AAA16
+:10972000E7EA32F20F26F19DE4B78173A0B7988380
+:10973000AD4A8C1F3719B89E94FAAD27DFC3FDCE12
+:109740004E9107D83B932DB0C5CA3667627EE4B20E
+:10975000BC2B7B707D7AF25511BFE6F1F26233ECDF
+:109760003E879D4B87C5225E3E53E439B0803996D3
+:10977000DF30ECFCF172099F2CCB7879CA27E2BE6E
+:109780007FBB91E822B59DCB0D06748176F6946877
+:10979000FF543C7F55D2199E82F84A47F453BE6964
+:1097A000E4EE8B310E91A94EC138C4B695130E600C
+:1097B0007C545DDF7F392E8DA7C35E855BCC316E17
+:1097C000DFE97CB2079B4B91FEAB7E6BE07989EBC6
+:1097D0005348DF7716D6535EE2E9D74D09E76D921D
+:1097E0009F01B6C68D7EA361EDBFA13840EA6E65CC
+:1097F000D07CD371053691B7B8C68D7EA8D4F6FE5D
+:10980000C024F4ABDCA3F0BB1C017AC58DFB7F55F3
+:109810008776C7FC3DFCFCF6FC0E479599E4A9C28F
+:10982000E328539C2427D5F5D7E8709FA6B630BA15
+:1098300037ADA480DF9B3AA2D3AEC375FFE5A7FA8C
+:1098400041E3639905B13C37445783297AD05D1CC5
+:109850008BEBC9FCB6A1EE2397FA28D99E3DC78EA3
+:1098600015FA68C09E4FA2E3A1BE93F42DE9F997C3
+:10987000064676D82F15339DEB9274DD26F3F53F1F
+:10988000E57EDD229137736CC3DFC7F373EB322EB5
+:1098900012E4F7711A226BF3085F91AF0670DEBB1A
+:1098A0001DBAC6B1E40F6BA47ED6F3FBCE8ADA876D
+:1098B000AF99548E4F3B530084637B9716215F060C
+:1098C000800E460C42071FE5F37327EAFA145A3755
+:1098D000F53EBAE999A90E17AD9B7A3F5F9F53F900
+:1098E0007C3E322E2BFD96917C7F55C1C4B87358B7
+:1098F0002BADFC1C9638E79BBAF2F5C7F17CD3364A
+:10990000E13F3EF0EC18FA9D86B3EB5505EDD4B37C
+:109910008E5AFA5DA26B0BB8BD94AAF633BB2D9E8E
+:109920003E0F507EECB07D3CCF4F15E798D5F5CE7D
+:10993000ED88CFAF3AFD94077C795B987ECAE059F9
+:10994000FB718AB7815D44E7554F3EA348BB284170
+:109950001FCA7D5BF27EACB6E07FD64EAA2F48F4DC
+:109960007B5CF03E8B25EE3707DACBFD63F27E227F
+:10997000E9FBA1EC1FA60512F25D568B3C68A9DF3E
+:1099800073856C94793003E79659D082E71EF29183
+:109990002927C6F28198C813DAAC58BD682F0D95F7
+:1099A0000F3490AFC39A2FE6FEC8E6AFE053E6133C
+:1099B000C97C210BE68D649E9B3762C1BC914CFC37
+:1099C0003D0B7EFE59E67DB41A3C944712F81EA367
+:1099D00078A032AB86FC75193E23D1DF1916DC82E4
+:1099E000F7B90766DBE89C379E0B42BA8F2A6EEA0E
+:1099F000776A8D26DBEBB0FDC0BD80B58CEA334ABB
+:109A0000B41CB4C32C508FF7150F9C7B5EC0EF4F76
+:109A10004FCE1B91F94B329E9B3BEA2905FDA2E8F4
+:109A2000F6A73C826F89EF8A793F9DDFF490DC7066
+:109A3000B5F2FCA4E8A5CC8E7EF92A297FCC89EB6F
+:109A4000BA49F117237F6EB2F273FFDDCCDBAE872C
+:109A5000F21D05C3B85F8779F6EB486077D0EF2F2A
+:109A6000743AB5A70AB262F424E1629BF9BCCFE074
+:109A7000392F2536DE99C57F2B44FBAAAAD7C4E926
+:109A80003269FCAD03F7AE042DA84F5E2E6044672B
+:109A9000DE247B573E5F96FC26E4B21C7FA8F94982
+:109AA000FA3C9F1D2FE96F287A0B5489757A2B8514
+:109AB000EC0F496F0756EFA47B01FB5687E879C688
+:109AC000A284F4783ED6129D8B92B17FDB9FAEC309
+:109AD0007B39CEA4460BF15E8F377FFCD7AFE1BD5B
+:109AE0001D67B2A26F61F954E1381FD58F886EC32C
+:109AF0007B3E743FEEE1F5B89EB960BF173CF2B50E
+:109B0000808DEEC95ADB8F7AAB3C291F25E93E8256
+:109B100014F17B3ED93623D993D922AEC7AA855DED
+:109B2000CFF8EFA2B5E694511CCFC63CBBFBB13ECB
+:109B3000DFC4EF2D6040FF583FA298E735303E6FFD
+:109B4000962FFCD32C12A0DFE72B76D0F703727C84
+:109B5000B749C4A7F8F8879FE47144999FCB98BD93
+:109B600000ED219B872594E57D1E4CB517E0F9FD9E
+:109B700056E9F713E52753FCC6C238BD7CF8CA3B4B
+:109B8000C6D2EF843CF5DD12949B571913EF59961A
+:109B9000CFE78B389D9C11F70936A5F8D30B61DD13
+:109BA0008FA4CC9D8657C3CEC9AC343AC87EDBA502
+:109BB00047399525E8C3319BC3E7A8F629F8FB1C74
+:109BC000F23EBF2CBF4A7E02E6EFD4A35ECD3AEE52
+:109BD000A3BCBF7A73B4107F47E505B33F0FE13CE8
+:109BE0005B7BF4768A17E61E7E0BF3340E1B3AA6D7
+:109BF000A6A11E2916F742604016CA07F38A683FDD
+:109C000038201F462814CF9C319B9F5F9DCE422A4F
+:109C1000AEF3343B3F4F35ADBCD8DB0AE3CD107912
+:109C20001ED38EF8D250BE4DBB31A2F27B2BA26A5E
+:109C30007C5E857C32B7C113CF0F577BE2CA0CEF35
+:109C40001D4E2C5FEB4D2C7F6DD2A7A3E2CBE3140E
+:109C5000AD02E7F90B45DCFF00F285CF8BE70F3E45
+:109C60002AF67363DCCC5C84F98D4E2580FB85314C
+:109C70004FE7529CE5E9498CCAAE9DE61DE6F8F92E
+:109C8000DFA7E37168E10797BF338475A86F9FFA78
+:109C9000838BF0E5B281BC7592F4217A3B20F8F613
+:109CA00080E0D38A3CB315E5FF0183A78BE83CD560
+:109CB000EC413FD5FE5423DDE3DABA8CFF4E8192AE
+:109CC000666646E8573F8F97A11DD80650AE3053C1
+:109CD0005EC801916FDDFA3D95FC5C588FF7EBEAA9
+:109CE0007F6025FF76755AE937B05E9F66A4F30E54
+:109CF000FB532BFC623CBA5FFEA15473187FEF202C
+:109D0000F93ECDC30817E20DE07A98C341FCA8AF35
+:109D100030921D2ECF9F433F147FD3E79A69BC0337
+:109D20000EFB7EA4BBD6F7C8D283FA491ECCE392C1
+:109D3000F45D9D36897E3F04B8AF24FEBE74BDCB72
+:109D4000EBE1E766F9EF62940EFC4E060C0BEDF0CA
+:109D5000378518F12D8FE71548BC3355C3F6394CBC
+:109D600096F9B931D740B952A5FB7F14596EA1F2CB
+:109D700003A25EDEFF79A890CB29A5F785BF22DD7F
+:109D800096A4015E609DBC29839F5B7AA090F3ED51
+:109D9000B9EB57E146BFBF82F31C1B9BFF0187D77E
+:109DA000ED8B2B0FB22E41A4B7E4753960F17AD058
+:109DB000CF76FEFE385EE53CF4B91C9F03F3C81C69
+:109DC0007C1E87C43C42E29C7572FDEE426EBF7EF3
+:109DD00089F31C94FEFEE579BA12E7F925C2195100
+:109DE000BE0438F585009F2D061FFD0C5805CA4D91
+:109DF0004E7FD3459E322B4DCC4B6293BC666E2F6B
+:109E000026E6215DA574B5A17E7D40C4B95F107CB6
+:109E10007530E5FB25686FBD3077641FC9DBF496AC
+:109E200036642E299FA5FC3F9B73B402CBA007DEAE
+:109E3000443D73FBB0C373B1F33EC70325A8AF40E5
+:109E40006EFEB170E2B9704AFE1D8017F817F9482E
+:109E5000F26F32FC928FD875214ACCEC66617ABAE7
+:109E600019CF8307BB84EE2B679E82D8FC80C9A7DD
+:109E7000999BF93C5A0204F7558E1F52FEDF598F09
+:109E8000FF23846BCEC51FD27D48CC5D3B0AF5080D
+:109E9000C0FBF1FF26BC209F72F0BDB4F393EDFA36
+:109EA000F3E5834B3893E5A1844799B593ECF82605
+:109EB000B0E379BEB842F2BEA94EC7E5F01E85EC0C
+:109EC000FA46D033A8A7E4FDBA578CB4B6E1BD8FEB
+:109ED0007B0DDC9F1A78D2E449BC2729396F5CECF2
+:109EE000275631B95FE0F74134D8F93D4842CF7485
+:109EF0007E7B98BC2789EB43D05309F724D57A128F
+:109F0000EF491A62BF00FB02B2CF58BA4EEC0BB851
+:109F10009EEEBCD4630F30F23FF3DF7BBCC928EC6C
+:109F200041C0852B768F1BEC03E87EBAAF14158BEE
+:109F30007BB282FCF73584FD9FEC8FFEA7CB3FB947
+:109F400008E87DC158AD107FEA65BE91FB9B81DEBC
+:109F5000BAFA19A63F363F84F7955ECD9A5FD30DC6
+:109F6000277AD3B0FD9C311FF27B4C63F456599491
+:109F7000C5F5122A99F3F1F161A77F7AD144C45F44
+:109F8000E80DBCCF7C6BAF89F02DF34B93F93B0E02
+:109F90009EE3060E8F53AF2778660D06CF85D07DE2
+:109FA0003C5D65334EDF43D13F9EE3489D10A3FFE8
+:109FB000718ABF16C71DE083B57CDF750EDC7A1B86
+:109FC000ADF70D37F1B85C538ADC276B33725CE870
+:109FD00087E4E3DFB09ED3C50DB53C8F68666F03A1
+:109FE000C5E158358FAB79E17F08CF0121DF663BB2
+:109FF000CB0C487A7F66DF30A09F73F68CC4F8DB09
+:10A000001CF35514EFBB61B621E1F72A251EE68843
+:10A01000DFC39E93F43B95C978498EDB0DC80331AD
+:10A02000DF3CFCFD1678E6337E7E2647FCAE585BAF
+:10A03000D1C0F9DE515F30BE7777D11788EFF519BF
+:10A04000A2744FC3F3598BBA9601DF8CFAD158BA78
+:10A050007FFD4AD7E287EE83F24FB65E44E5E75DC7
+:10A06000B7AC388CF5DB4652B95AF7E15CE483D2E1
+:10A070008A9BA6E37DF57D16DE8FDBEAEFC4DF3138
+:10A08000718F1F3601F380AB8D516A77CDC50D9767
+:10A09000603E54B595975F29FBFD042A0F13E5092F
+:10A0A000BFB808CB7DCA8773078B0F8E2955C2F8BE
+:10A0B0007B65D519BCFD8C09BB72D15F545DC5CBE6
+:10A0C00063BC95EB8763BDEEA3B983D923CF140995
+:10A0D000BF91B0AF7D82DF9FD68EB6E179409F4DB4
+:10A0E000F1E2B90FDFA4A3FC7E3433CF2BF1696515
+:10A0F0002ADE9F59A5713FEF545B4B0ECAC5EBFC9E
+:10A10000C672F4E7DB6DC56D6817A74FAA9C88EB94
+:10A110003DD5CC889E80AFF6E13ACCF9CA878569F7
+:10A1200048CCB644BE92743B53F2537522DF803C58
+:10A13000788ECB83447E807E0F11BF5E96A8AF06DB
+:10A14000E47D12DF26D3E39076014B9483313A0D00
+:10A1500029F1F4D98DFCCAF9F70F088751D7EFC15F
+:10A16000F7458AF7224AB419C2BE90F0A1DB924D9E
+:10A1700038172EFC53A53DCE21B0DB5D382EAF87BE
+:10A18000EF34FC713909178CFF1EE1672D87A75B3F
+:10A190006916BF57C2F761D2DFD128E7BB2771BE6E
+:10A1A00015567E7F811BFD3D14C329BBE8F3E06E8D
+:10A1B00012FA77B6D9778F09E6F075C77C5AE71B94
+:10A1C00041033A60FEBB52FC7F4778F4BAC0BE88B8
+:10A1D00082BF37A2513E0CACE33FF83AF275917062
+:10A1E00025E3E3FF02863CEC3E0080000000000017
+:10A1F0001F8B080000000000000BE57D097C54D592
+:10A20000D5F87DF3664B324926098484409824644E
+:10A21000830426611164712004A3020E8B028AF864
+:10A22000C21AB20B5D624B9B81B0A9684345A5166B
+:10A23000754040B0408302A2463A2C2A56ADA94B45
+:10A24000EBD2F22548658718AAE2576BFFE79C7BA3
+:10A250006F66DE4B52A45FBFDFAFDFEF0FB597FB3A
+:10A26000EE7ECEB9E79EEDDEA9B43B02EA00C698C9
+:10A2700087F5ED16CF9802FF642EF8EF80E57C732A
+:10A2800016A33FFF4865ACB7096AC44279E3EB5FA8
+:10A290002B587F5583C2D218EBC59A12314D64D525
+:10A2A000944F60EE35AA8AAD7AC57CD69F31FCE723
+:10A2B0003F6E60AC2E12FED18DB1D63C9B7F330E2B
+:10A2C0006286FF0633F6567186FF7EC85FB238D6C7
+:10A2D00028D19057589619EAF99470F7D614C6BE4B
+:10A2E0000A8B1AC0E07BB7704807323662CE0F2661
+:10A2F000B1A88EF3ADB1F37A3F0C8FDA8CE90D196A
+:10A30000E12B4CD1D83ED98FF5BB85433A2038FF9D
+:10A31000AF4C4CB3C37C7FA8C23A545C47EB32339A
+:10A320008CF704ABA7FC68172C7A08633DDAD7E3F7
+:10A3300053BCB98C594DCADD5E07AC09FFDC104C2B
+:10A3400047BB4C8C752770290CE65529E1E85298DB
+:10A350001DF27344BE52C0BB9BD5D50BFB31C279F5
+:10A360008EDDD642F05D53E869B607BFB3FAC73C4D
+:10A37000A1FD74554F01B826C576843FCC9FE637C2
+:10A38000B1A6C07B320EC717F8B83792F031F1DEB4
+:10A3900031F45D9992A534C3BC0A8A5C94C60EFE62
+:10A3A000BD99E5125E6634E404F174B2BB76B30B7A
+:10A3B000D76B6E1E321970FBF69067F234283F6E31
+:10A3C000622558CF089FDB113E433AC247C2C308FB
+:10A3D00087AEE6BF2FC23BC305FD5C509A8662A1E3
+:10A3E000BDA753C05D4B41FCC43853C6C420DCBF7D
+:10A3F00081718732360D8B00CF0FC66B1AB69BCE9C
+:10A40000BC8566586F6C9166D11C349C09E7B3D843
+:10A41000C9E753A83A882EDB762A7E1BD41BE7C9EE
+:10A420007E6C24E4AB8E59981FCADB18A7DBB68D6F
+:10A43000AADF07F4B2F08DE78706E0D3A7824E3398
+:10A440003798984BE203FECBF68733575630DF7FC1
+:10A450007BAC2E9FDBD053577FE081545D795EA0AB
+:10A460009FAE7CD0B17C5D7E48D3F5BAFAD77D38FB
+:10A4700056971FDE7CB3AEFE88D35374F951AD7787
+:10A48000E8EAD785C1FE1988E0F63465015CE60983
+:10A490003CDD70658EAEDDB9A8F1C7705FCD5BBBEA
+:10A4A0007002EEAB31AC4CD70FABB79C40BAAC8668
+:10A4B000BF88CF05CC1B1D007815B2D6D792007E81
+:10A4C000957EC58D705BB881D793ED161DB8676C0E
+:10A4D0000CA67EFDF732660EE6A19F9A3F6DFAED5F
+:10A4E000D190F271CE6213D2DF465764B7CF2210FB
+:10A4F00010ECBA7FA89DE2D71D40FCBDAFBA6DF04D
+:10A5000069F11B2AED83C5BB143F837E33587A342F
+:10A51000E6AB8EA9CC0FF83FC5AA1F1D09E957B5B8
+:10A52000FEDF1E4D0FC2C796A0C773984B8FE788FA
+:10A530002C3D9E23DD7A3C470FD3E339C6A3C77376
+:10A540005C911ECFDDBD7A3CF798A1C773A2A6C768
+:10A550007352891ECFBDABF578EE53A3C7678AAFA0
+:10A56000548F3F03FE25FF4D5BB35857AF9D0EBC84
+:10A570002513304DAFFF91AEDF32B5DC0A1868A766
+:10A58000071FFC457AC864CC1D003857021E02AE76
+:10A590008E7450D2B86E55D2BF40077F42FCF70F81
+:10A5A000C1BF3A2B5AEB845FCB54E23557F19C4044
+:10A5B0007EF6A54BFB0BA633323F4F3603DF60DE42
+:10A5C000E24C6F6490EF3116606C68907FF5C6B511
+:10A5D000E5333A8FCC4383E751577CADC3393A49D1
+:10A5E0009E3F5D9CA3AEDE413E0800F988F95E699E
+:10A5F000A641D69A701E33055D1F0EE77479198B3C
+:10A6000086433DA8330CE6F511CE1BC6F928BCFFE6
+:10A6100051DCA777B0060BF63F8B35513A9BB5520C
+:10A62000AA31A715D339CC4DE93CE6A5F475BB6634
+:10A630004B017894DB9B873298FF97C5BF3FAEE014
+:10A6400064DE8AC3C9760957C9AFDFC37F42BD91B3
+:10A6500029DEE814E0BFE3ECAEEF3D029F0EE339E4
+:10A6600081FC77421CCD9799BDB953723BEB67399A
+:10A670009D1B2F2B9A867CD79768776F85B5F54FF2
+:10A6800062F6443CE712FCA953003FC929FAF3B72C
+:10A690009FA0895D3D1B16C7201E993F16CF876B73
+:10A6A0001DB75F8A271DD72FEB5F6DBD566BC33D6E
+:10A6B00038CFD60A877B33D0E7FB021F4FDF6E0B04
+:10A6C000A851413AFA3062F66BDD016F5511DA207C
+:10A6D000EC7FC6F49B56615E391CE75A0CF3BB5401
+:10A6E0000CF0E6F0BF8EC35FEB130F4BBCD05BCB1F
+:10A6F0008C46F87B39FCE11FB9DE4EE7CFE753A06B
+:10A70000F0F1F745681EECE7B0A929D98DF0303794
+:10A710000DC576CCD19DFAB960E570E90A0E6323C8
+:10A720007ACFC275CDB3D9DC2AF43956E1783D1918
+:10A7300077F7EC2AF8E77C93373EA0EAE63D09F18B
+:10A740005DEE2CEE93087473C122E66DEF2EE0EE01
+:10A75000CAC17DD5D5BCEBB07F94037FA2F8510E62
+:10A76000A43F907FC117E3BF1FF236D3E5F7A7A23E
+:10A77000FC926B726F86A28DE1D035D0FB3B02DE7E
+:10A780004F58201F4BDFD7E0F78470DE3EE1519336
+:10A79000BF0EDA7BC7BE48787ABAD241EB29662E63
+:10A7A0002B6EB2B9CC4374FF97317F7BA519F05162
+:10A7B0009EA22D44B8DD1D674A7E9FE6A1F547792C
+:10A7C000878DFC6EF42FF7E914275FC27C01B7A9CF
+:10A7D000CC43FBEE36A65970DC772F5A3DC83FDFDD
+:10A7E00015FC643AF3D1F799CC4FE99D2C40F5EF75
+:10A7F00062CD94FF7DC480DE3530BFC98F65A6234E
+:10A800007F0D81FB4F08EE76EDEE6E9C5E4EF540BF
+:10A81000B8AFEFFE9DE877B2A017D8AF2B71DDB0CF
+:10A820005F07E7A586EC9B719C5E98D999FECFF6F1
+:10A830004D531B3F2F80313A1261FD370A14DEE879
+:10A8400029A37302E5AC6E00FF26974A7256D19891
+:10A850001633CE7FDBE79C8FBDBE8C45FAA0FCF59E
+:10A86000312A437C4DDA30FE0CB67B8B05BA0D865F
+:10A87000FA8557B4A3D1B0FE49C0DF8123B3A25EED
+:10A88000704E849C4B3727AC1B8772C4CD7DF5DF9F
+:10A890006F61F52AC26F428EFE5C9984E78AAC072D
+:10A8A000E31D4238C4763C5FB6A708F9A21FEB77D8
+:10A8B0002DE74BA5C9F36BE223406748F773CCCC77
+:10A8C000D3D97E73642A928F91DC72AB18BB6DC2B0
+:10A8D00065EB2558EFA914ED25EC67F1C4BFCC4614
+:10A8E0007E0C7AD4DB83F01CFD9DCAEE87F213B593
+:10A8F0000071385C4FD6DA9907049CCF6A9D943F6B
+:10A900005D9B40E9D95A17A5E76BB3A8FC62AD9BE4
+:10A91000F251A9DE23D8EF9C359F9B518E5A1D26FC
+:10A92000F1C7E7B144D0EFEA30AE472D895CF26160
+:10A93000318CBB840E4038AF1BEAC723584A0F3412
+:10A94000BC86297C571D58BE4E71E3F934FFA8B66A
+:10A950000AC967E15BCD9390ED0CF9E0643CC2ADB0
+:10A96000E28AC234D84A3F48F7BC8BE39FAA1D460F
+:10A97000F33A53EBA179791A5B5E8B83F6E76A8B26
+:10A98000289F99EAFD10E9DBC33EB762FB893B5B78
+:10A99000CC49505EE8513CB8BF477B98DF0FF8DBED
+:10A9A00060E1E7C506382F907EC6E44E79E27B88E9
+:10A9B000B614ED048E735BECDCC238A4AB61C566E3
+:10A9C000AC37FD1B90B95282F47DB57D72E1A04297
+:10A9D000F0B9703086E021E15421F075617FFF5BB2
+:10A9E0004740BF07418E54617E6D574C34BFB60F50
+:10A9F000C3FD282418DB2FDE97D68339709DD0D86D
+:10AA000086F9FE3D18E021C2FEF413A8979DDBF500
+:10AA1000C304C4CBB9D8862F3F46BEF767CEF7181C
+:10AA20006BF8EC71E48BBD12DCF743EEA205F43455
+:10AA3000D26BAA23F05CACB4328DE7B5FE983F1719
+:10AA4000CE487F1DBA3B692CEE271CCF9519E46BCD
+:10AA5000598A8BD500DD67EC7E2CF5C730EFED0D04
+:10AA6000F33F7E1CD20B7E93CF02E7D605D670F162
+:10AA700025E4CB5B1CEEAD0CEB9BC3B1FE03163E95
+:10AA80002FDF56D0DB5DD89F9FF800945BB1BCFCF4
+:10AA9000B95FF4C4F9BF8C7209E45F5E1741FCEE44
+:10AAA000658BFB780DB67B82F7F7CC43F79E388039
+:10AAB000E98315F9F742DA273596E03DEFE78BFA9F
+:10AAC000617B38F75922F0C75FBDA004C2006EB9A0
+:10AAD000EB0F2D4F84F1066E6C31F584346F8B5281
+:10AAE0008769FFDE45C7F0BC4D4F75D13C06ED4C84
+:10AAF00051519EECD7D3FFF10D240FE8E5849CF56E
+:10AB00009F8FEDC982F2423FA5E1EC32A087D5BD0F
+:10AB1000FF90CFF5C47AEA675FE3D4F7EE64B80E2E
+:10AB2000904470DEC556B253E0722D90BFB0376DC1
+:10AB300013DA33F69B7C9BE8FC9AC3E5950B5EDF4A
+:10AB40002F90CE2AA0BE0FF21579BEA8EBA1BCE2D1
+:10AB5000CF7DDD4051ACF7933716213C2AF73E32CA
+:10AB6000BE27D4BB3092B90115AC64DFE5F1D88EB5
+:10AB7000F586B5603F7BEBE2EF80760FE48C1D82BB
+:10AB800074E5551B681C56C5C7794C9C7BAC198075
+:10AB9000132F5809D47B003EE3F7D8C69843492CBD
+:10ABA000889FAAC66529686F19ACD9DD2AEE9B1467
+:10ABB0005F62B523788EC2F977632AD44BB48A7E5C
+:10ABC0009D5393BDD770FE59C57926FB7BCCCA7CBB
+:10ABD00061B15C6E56F07CB6F2737B2BF0979AFCF9
+:10ABE000E0B90DE34E4FE5ED495E4E82433A0FE684
+:10ABF00099F498CD4FB2C1771C5FCA5B55427F91E3
+:10AC000072CB8CB8BA579A61BD8F456873717DF36A
+:10AC1000C5B9CFCC6E17CA453F8DF0CC4B25B9AB2B
+:10AC20003519D700E76A09E62B5590C3D242E430C4
+:10AC3000FB773B577744782AB1FD77AD6FE4BB4B88
+:10AC4000BE30B13CA083258FD8484FAD13F6863A6D
+:10AC500061DFAA8B1C6A477EC18E9ACA5F83F37636
+:10AC600014EFA1BDDF2591F9C44FEA18EB146E076C
+:10AC7000810F68C07702706E68C00F465F695539F2
+:10AC8000DD371D891E8CFC9679225D680730312DD9
+:10AC9000E43C35F603787B08E1398645302DE4DC69
+:10ACA000F4B0182BEE5FE688FD97D63F52E04FAE2A
+:10ACB00063A4B0E78D6CFB3002F9E6922FF2897F36
+:10ACC00076B5BE57C4FA7E83EB83D492E9DD84F86F
+:10ACD00018F557A719D739CA3C3919E51C98FF331D
+:10ACE000F87DF45F4DFAF97F13AECB7FD7757C5FAB
+:10ACF000613E13EECFCFAD7EDC9F8D40DFB89F1B52
+:10AD000017E5F8910FEC87FD6047BD668A95E4DC96
+:10AD10004661276DECEE24FBD2CB169EF7CD14EDE9
+:10AD2000C3189D238D337B52FB9EB6EA3773B1FF68
+:10AD3000BA08E29F8D16FF9A54ECFF27716E1FE050
+:10AD40004BC5F36310E81B827FD7590277AAD8DF7F
+:10AD5000E75686E3AD8F09245541FDF58B7A52FD08
+:10AD60000F419442FBDD0893E9EEC90E2CF724C68F
+:10AD7000427EFFB72A9D1BEBF320EF203E4EF6C02C
+:10AD8000F5933D89E1DD308D37D17C54564DDF534D
+:10AD900078BB8F2DBCDE1D027F1F09FCC03E273E05
+:10ADA000A04D8A30231D5F4C9DD342FB8379121541
+:10ADB00098CFE3F3D219F2D13B4A6F4A21BAA97F67
+:10ADC0008CF8D90C8103D91F36B00F45399AFF99F9
+:10ADD000397F6B18E2F3B69230B28F7E58B23CD214
+:10ADE00005ED6FD3D4800DEDC6D30A3DA1FAF8C5A9
+:10ADF000540F8D5BD1909D763284AEE7D8806F4042
+:10AE0000FF6BC2B5D348CFEC401E951F00E1E61F93
+:10AE1000B0AF4ECC4BDF4D768D79528F0CCC45BC0C
+:10AE20001E6CB533D44FBAA2873AC403F4DB479CF7
+:10AE3000EB44AF88FF19E15CCF3103BD40BEAE21CA
+:10AE40009BF49CA72CCCA320BEF6D908FF4553EC5D
+:10AE50001EB23FCE08DF6483F2BB053FAB9B114EB1
+:10AE6000DFEB5E89F49B14D29F28EFDB63A176E5CC
+:10AE700056FF8E6DD04FF9C16C3A6FF65BC5B82F97
+:10AE800045F0F2284FCACAC158DE83E8E0658B2B33
+:10AE90009ACADF50199587073262008E91615A581D
+:10AEA000DA10A43BC0B303FBE5DF8F0BFA3A0EDDEB
+:10AEB00022FE7CD591D42F6D7DC86B75BD37233EA6
+:10AEC000352B2F673F52A9FCB8D393381FF2C7AB7D
+:10AED00093685ED2CE74DC6B25BA3F5EAE90BCF454
+:10AEE000A71A35600DB5E34FD97E5F06B4FBF4A019
+:10AEF00085EC78B37E56F6167E9FB5BC82EC91B396
+:10AF00004A97929FE0E2D24F876E80F5342FFF245C
+:10AF1000590BB14BCF2A8756A176D5344F6A1AE028
+:10AF2000E7D6342D1DD75795D3BC00E5EB8BD6A6BD
+:10AF300027515F7075D3B2F0FBA5174F6DE37277A1
+:10AF40006B069E1395664E27F2BCAD1274F85F69CE
+:10AF5000DA00EC0FE0361BCF95889C26CEFF967E5C
+:10AF600037FE7FB671EB7E05C6290B6FACA454F596
+:10AF70000FC07ECE298128258DE0A8E1BE3AEF0CD6
+:10AF80004421FC351397F3CAB6EBD7857FCCF16823
+:10AF9000376364072F6B503D61B80F98DF8AF32F3A
+:10AFA00063D660FD9420BEA01FC21773FC69F68FA4
+:10AFB000010FA53BB2F351BF288B39F0D008AA0787
+:10AFC000EDE47E513BE6E57A3ACE87AFEFBCD80799
+:10AFD000E7E18B05E965A74DEAF934FEC5177BD09B
+:10AFE000F8F1629F5C5404BDEE08E374E58675E1F8
+:10AFF0003C7FCDE9EA51C92777F07ECAE27C26E49E
+:10B000004B65B54EA22BC997602EB4BFCEED4EA2B4
+:10B0100076928F312F63547F77E2662EBF097D17BA
+:10B02000270CF54B7FC5C7C13CF2F3B3CF26C971DE
+:10B0300049DE369EC7C6752F49E3F62938A77BFC43
+:10B04000337D312B61EE13F30685AC27D22AF882CB
+:10B050003B61722EFA17ACBA7E2F465AEFF638D003
+:10B06000CFA0FF2EFBAB4DE3FA641F039E7BAAAD7E
+:10B07000876CB80F9F66746E18E7B14AB47BF6D937
+:10B0800076BCAAC29ECE5C929E5C5C9E27FC7D64D0
+:10B0900095F8FB5E12F0E33284556A108EFBF3B430
+:10B0A000243C372E0AFFD0FE18C8E7A03CC5F12289
+:10B0B000F3121F46BA5CFED18224F4473D2FE168AB
+:10B0C00080F732802B96D75940BFC9413DF7D8C38E
+:10B0D00027D383EBF9ACD6E39917925FB021CF8EDB
+:10B0E000FB71E1C63CFB9C107CD46D1F74CC0570D9
+:10B0F0003FBFDDEC46F65E67F63F84727ADD76B5DB
+:10B1000001E908CAED08EFF38EC3BFC37A0B36C658
+:10B11000E4A31C2EDB2FDC50E899178287FEDBF5B9
+:10B1200078C96DD0E7071ED0E75F4119B4FBB5B70A
+:10B13000CB0BE8F3838EE9F3AC15B03714E5018E41
+:10B14000B71786B98FB9006F7DFCAA1B3FF5714C0C
+:10B15000993A11E5888DAA3B1DCAFB2CF5DE827257
+:10B16000C5E98DF3DD88F612D557F963C069C927A3
+:10B17000E38FE1B97A8E35FC6122E06541E33AABB9
+:10B18000D985EBD6D3FB7E93A0DF67B9FD6E915FC7
+:10B190005FDE912F2C93FEC1AC50FA32D2018C7B32
+:10B1A000BB0726545EF3DEC3C8174A2600E1039DA1
+:10B1B0000D6F586745F9EFEAE3F8B87CE9F0B8108D
+:10B1C0001EC5C378D9F53505EC53D8776CEDEFC7BC
+:10B1D000E3BC8B1F5048FE287E3EF328D257CB9EFF
+:10B1E0009937537A7B11AD5FDA0917362A8148C83F
+:10B1F0003B87B90E3443BBF97E6EEF98B3C216E4B9
+:10B20000870CFD648679AC0F2987F92F3C70E86BB9
+:10B2100005FA2FD9A86FB708F8349E3FA55BFE61E9
+:10B220000BFD2EF5D1EB1B37A9B8EEF962FEF2FC4F
+:10B2300064BED1E4A7B89E376127F1FFE0DC991D19
+:10B24000AF297DBB07CFD1EBD7F3F6C0768B71DD8D
+:10B25000150EAB0BD75D6167810898CFB148ABC7BE
+:10B2600009DF2F6F88243BDD021BC8ABF994B23095
+:10B27000F47B3037F9CB3E7B4725B9A7228EE3BD5F
+:10B28000E22985F4B40A34AE62FE699E5FC402B45A
+:10B290001EA4174FE83AFDFA3CABE7FA5DB93970E6
+:10B2A00008E152CA9AB97E06F8F484F8BBCB619DD6
+:10B2B0001FC6A2FC6668CFDC1AF9F11C5C1EAB3A13
+:10B2C000F00F5B68B9D433A51E2CEDC74F6578C36A
+:10B2D000711C8B909BD7DFE7C9C0F9AEB4783210F0
+:10B2E0000EBE7561A4EFDFB1899F5FEB63408EED09
+:10B2F00046F233C9E377285C3E6733393F1C617AF5
+:10B300002E80E74DEB2331EECD2EAA4FE7D8FA077A
+:10B31000B3B9FCFFAD4AF250EB3A1E17B13E8FC3F2
+:10B320006FFD83B95CFE97E75E7746FD7594B73D88
+:10B33000196887600FF3797D8C4B0A91AFBF8DD769
+:10B340006EE81BB23E2997B392EFE6CFD82AE234DB
+:10B350005AD785F9D19F7152F1BE660A916FBD7DB2
+:10B36000F9393174AC679BA8477E8F79A6C9F7DF9E
+:10B3700000F39AF7A8C985F6B776787B3C19787EF2
+:10B380009E5C17968F7436742CB7471DCFE37C3FB5
+:10B390006230F3F8219D29FA9DD9D7A44B13C281BD
+:10B3A000FEA09F9385DC1E1E39D84B76C0AD2ECEF5
+:10B3B000F78DEB982FFA9967F5FE765427F3917085
+:10B3C00061E3B8DC71F21E65339F17E01BF2437F27
+:10B3D0001E46F6C393E25C92F005BAA1B807C9B75E
+:10B3E00062DAE9C5BF230CE8659D85D381D4DB42D1
+:10B3F000E845E0BF37E1F70E815FF66098A01713CC
+:10B40000FB6F8463A193D3C335EA5F80EF9F20BEB7
+:10B410008D7A98C43733FB87FC33BF4BC50BBBF623
+:10B42000FB40CE28FDF523510CEA9D31D7C7BBA1C7
+:10B430007DF9D695511E484F9B7D514E18FF8C5F6C
+:10B440002DF27702EF97FB4AFBB5C7A184F849CFED
+:10B450003EFBC0245CE7975B2D4E640955DB6DA471
+:10B460008F55EE5D44F23AE45B787EF5E7E837AD60
+:10B470003AA0B7CF973EF348BC8BE0ED4B32256046
+:10B480001A486290566EB1B4FB91611890BF5B5739
+:10B49000E1FC8CED711E5700DF550D6AB135BA63C2
+:10B4A0007995E02F557B1FF81CED86557B6F3A850B
+:10B4B000FCBECAE0172811FE11A35FE0577DF571AD
+:10B4C00007001F8A33F0C1BCD2895CB85DB96EC772
+:10B4D00063035A507ED8F266949213F40F48BF4922
+:10B4E0005BC3DCA75E7275BD2F2F0AFB70106F9CCB
+:10B4F0007FB90E2818AC048A3F4FCB2D81A811A824
+:10B50000EF6DB290FC5BBEEBE96D8F239D7D64A374
+:10B51000F3BD6CD7AB7FB81EE5E73D966E13F832EE
+:10B520001C4A485C4E958BDBE3247E4A9F7FD5EA1C
+:10B53000CAE5DF97C606F154B6E79015E3838CF0B1
+:10B540002C6838646D767482AF8696F16487DAF180
+:10B550009515F7C799830AEB91D2B17DC9A657A378
+:10B56000503E4338E1F924F1D68E47437DE87FD23F
+:10B570004B83A99E13F594ABE1F181BE8CE056F1AB
+:10B5800042248B8179947C6CF34F40FCEE5E1285F3
+:10B59000EB3965AEE674FFC4CA7894F74A2CBE78DE
+:10B5A00027A5FC7BC993DF277A5CA854C73B738827
+:10B5B000DE134D244BF812719DF337DE46EB5CC071
+:10B5C00034A2C7922754AF1FD22FCCAC684F27FBB1
+:10B5D000E6BA74BE6F4E6D06E4C23A4F89F82CDFAE
+:10B5E000BBAAD0A3EFA1F3FCFB62CD8C2DA6FC1768
+:10B5F000429E0B4B6F8FAFB287EAA1555B56372146
+:10B600009ECEF6F6F4C079021C7C026ECA3FA05FA3
+:10B61000F5F7853D389E980BE317A81D9CAB05F800
+:10B620001DEB37593C68670F6927F4443EFEF7C4A9
+:10B63000F830EF70D4834FC5771EFFB500D7C7E74A
+:10B64000D7141AFFD5251FD8721FD1D75FDFE77C2B
+:10B65000A6D23FB988CA9B2C811E58EE3F344D219B
+:10B660003E616381CEF6F9168BD8E7FA7298A75936
+:10B670000985EF412E9F4A7A5900725920444E089D
+:10B68000D28F35F89DD6FF73C1E79AC99F27FD80F9
+:10B690000B057F30AEDFC82FF2D23B8F53611B3BCF
+:10B6A000F73F05F9848FC62D87F31DE591F28F6C66
+:10B6B000244794EFB278114EE7761EF9C31DA8DF38
+:10B6C00036C87DADE7C3C67D5DF2DC904EF7F5B9B7
+:10B6D000B5799DEF6BF8DEE9BE5EAB10BFFB9FF264
+:10B6E0006138F9C82E71B5FDBBB00B3E3C2B5DCF68
+:10B6F00087BF6039D123B0D059DC87F06480AF8434
+:10B70000AB91AFB6F57575CA5719867484C053C22C
+:10B7100051D22B631A8DD34ED7926E255DB7D3AD20
+:10B7200071DD7A781ACB9311F73075EF8B1692177B
+:10B73000CA1B797C22B4A378BA2AB4CF53EDFAD7C6
+:10B7400092BA85E6FD867C83A1BEC790F71AEA6BA4
+:10B75000867CB5AE7EF9812356AE3F0474F56C3518
+:10B76000B7903ED251CEF073BFD3DECFAD3EA48FA3
+:10B770005EAD56E49396E5CC1709ED5B5F5149EE5B
+:10B78000B9E46A8D42B965651897EB2E39453E8656
+:10B79000E75BBB5B57219F94DF5BC3B81DE692B7A5
+:10B7A000352A26449F6F6954A3D0FEDBEC67459D84
+:10B7B000C7B7D4115C9B5957E55CBEBB14CEED0DE9
+:10B7C00097C2B9BDA1507524D7A01DB69EC711CE92
+:10B7D0005B363D8AE2301AD36E9D01DFE7BF4161DF
+:10B7E00006184767C6F887B91C95EC34F3513CE15D
+:10B7F000DC461E07316FAD1ECF0B1C5B285EEE0BC7
+:10B80000B694D205EBF5F10BA56C2DD159C946C301
+:10B81000F7C65B689F941AF68926ECC3C67D72480A
+:10B82000F29F3C96A78B9314FCBC50CDB97506E0F3
+:10B83000E3D23195D920DFD6A8B25583795C2CFAB2
+:10B840009F5021C1FD5709FB15E52609AFF3B88FBD
+:10B8500032BB965FCEEFFBF3D01F23DDECFF64C05D
+:10B860002F213DBFFFA38C9731FFC21F933F611D66
+:10B87000EB171CFC7A36F2E94B076D0CE9FDD2C1DF
+:10B88000D793D11E79E9251BE9D99796DBB89DFBA3
+:10B8900060A41F8F984BBDB95C5CF7CA57039AE947
+:10B8A0005C5E41F83B9F6EE5F255E3DF8EA33DBD44
+:10B8B000AD1156857CFF6004EDA7AA97C2C8CE7C67
+:10B8C000E995AF8686DAE7FEA7EB91FEF74B916C20
+:10B8D000C67348C7315C2FA87A79F8D3E85FAED831
+:10B8E0007BC83A17CA0B7EF3F701C8572F3DC7E54F
+:10B8F000A98B96E627D1C6F955FA999F5B86A39D39
+:10B900000F3AEB09BB3B237BAA2FA733B870385CF7
+:10B910000238E0BA002E25781E74058FA88CFF54DB
+:10B92000787C3E9BF3B7EB18FAA38370513CFC7B09
+:10B93000A4DFAED0FAF9F7835F0D40FE73B5F5E6EC
+:10B94000FC7FB6DE9BFF63D7CBE9FD5D5442867476
+:10B95000A4FB8E74FDC20F28BF3BD24DF3FD8EFBBE
+:10B96000BD14D7DFFD3F71FDFF3BF85EF31FBBDE6B
+:10B97000ABE1FB0D81EF4827FA332FBDF2F7647678
+:10B980000DEB7EE6FF289D4B397EACEA3E9607F52F
+:10B99000DF640DEFBB53481AE9540E793F43AF3FC4
+:10B9A00015307E4E17D8CB48FE2CE8F520C9CB7554
+:10B9B0002C9FFC17BE5E2AF975280804E0F07A4235
+:10B9C0001EDDB362E640AF25901F9B5441F16246F5
+:10B9D000BDB2207C6211CAA74796C1BCA09F23912B
+:10B9E0002627FAA8C7F55203B60194B660FA5AF2B0
+:10B9F0002D14F73FCEA1D7AF6E31E84937B9F4E542
+:10BA000045ECB96EE8B72BCAB1D0FD8AF1583F4476
+:10BA1000AF7C2EC349EBBC89D5AF703AAE1D4EE664
+:10BA20004C0EA78E70F8E770EB0027A1479B457D71
+:10BA300023DCCC8EFB9BB09D99815ECCD74BFAB4B6
+:10BA4000D48BAF064F26F46DB3185AC2D7DC8BFBEC
+:10BA50006743FA25B848B85F2BBC259E8C7097F0D9
+:10BA6000957033E2E18F194CE8B71CFEBDCC7966C6
+:10BA7000DC77A3845C3FCE1CC3F3BD9A542FED4703
+:10BA80003FA7F3BFBACD28D78F71C4501CA9F1FED0
+:10BA9000C29C61314315586F9299F96CA087A2EF4F
+:10BAA0008DECAEF799FDCB53701C6EDFED6DE6F6B5
+:10BAB0006BD8DDBEF07CAAEFB142BEF8E185CC03C5
+:10BAC000F58B93985BE1F559742C85C73115E3C468
+:10BAD00020C576C5D1BCDFE21ECCBF9CE393F082CB
+:10BAE000661FB46F40BF1E532C6F1F954FED7D2610
+:10BAF000DEDE6386B44F1A8F53685DC9EDF2C5ABC5
+:10BB00007B6720FF9830566F675E9AC9ED2E323DF5
+:10BB10009DE92278A9267702DDA758914DFA911A5E
+:10BB2000EEADD88776FADD3C4EA778D55D1387E079
+:10BB3000FC76C7B9717A6727ED19CAEBCFFCFE070F
+:10BB4000F05DDB1E46DF1D59DA7599180FA0B86647
+:10BB5000EF830F736E3B624D8021B486C917D04EC0
+:10BB600038C9B7E777E89F9C344DA5FA93188FC37F
+:10BB7000642B22280E73A2EF737302F43711940E14
+:10BB80002C6F097326DF03F32F16F6E102B15FD4A1
+:10BB900070A63DE7C079F5CE4885EF1359E7F1C9A6
+:10BBA000CB447CB23A56D9887EA63E05DC7E2FEB8C
+:10BBB000633FD8EFEA4C6EAF9F24529907B852FD0D
+:10BBC000796B6C2D69A8FFACB10432213D943D76B0
+:10BBD0000AAE73422A1BBF01E17EAFCA36D37C5B3B
+:10BBE0008BC9AF1099E5423C6840D2E45FA94F7120
+:10BBF000A15DAC654C4300FD092DBF4871D7B90864
+:10BC0000CB140F24F5AD963181BE68C76FCDE37EAE
+:10BC100089E3CEE648D417E73AECFCFEA4882B9AD9
+:10BC20002FEED1F4A96B7EF03AD4431F51C95F3394
+:10BC3000FF117E3FEC2F0EBB5F41BD6D3DDFA76C5A
+:10BC4000AD3E8E8839DD64079A5B3FC68AFAE63CD2
+:10BC500087C78AEB5C9BA5556722DF16F711FB218E
+:10BC600012A0CBE2FA628A5751A360DFE13E31BBFA
+:10BC7000A2500F36C6215589B823995F13AEDD8BCC
+:10BC8000709A13EDDA8DF472A2268DECA30704DD11
+:10BC90004DC0B84AF467989B13713EFDF03B8C3F52
+:10BCA00021D699E1207A0E630887168B3303E9BB0E
+:10BCB00065659809FD72139673BA867D663743FBF6
+:10BCC000FBCC2C1CFD0C378A7E672D337B3741BEA5
+:10BCD000979D99236391AEF288AECDFDB449B8BE6D
+:10BCE000D33F61C3901EE6AE5D47FE184917CCDC1A
+:10BCF000342E0EC639BD35251FF9663B9FEE37B68B
+:10BD00001EDBB5D3C33485E800D24369440F531E0C
+:10BD1000217A181BE8BB3807F5D172E6C1F33D81E3
+:10BD2000B9514E6863ADE4AF6C73585D68FF92FC27
+:10BD300044F20D795F56D2C13638EFCD16C6B6D76C
+:10BD4000DA297DB6D6C9CCE98CEDAC4DA0FCEE5A13
+:10BD500017A50DB559F4FDB95A37E5F7D60EA3FC72
+:10BD6000FE5A0FE50FD41651FA52AD97BE4BBE04E2
+:10BD700070213E24F98AE447731DD616F45F4ABE4B
+:10BD800064A49BD900DED1F9D49EF89EE477B80E66
+:10BD9000537E901F49FCA62A5E5F420AF2B1E699E3
+:10BDA00088FF42F5FCAE17502F2F71B8494F679CA2
+:10BDB000EFB501BD225C92ADEC00DA65EBEEF1B4BB
+:10BDC000AC4E09C2FFCE12859943E8EAAEEA30666E
+:10BDD0000E3937EEAE89D1E567D5BCF76A0FE87F3B
+:10BDE0004677ED0DC4DBF19F7EF6C41FE1FB533FA8
+:10BDF0003D9B8EF886796C7D0CC75D1ADE3E8F58B0
+:10BE0000CCAFB0909FAB8FB09FF411F613FC137AB8
+:10BE10009FF9A99FFE37EDF3961A9B0BE5E28F1170
+:10BE20005F00DF3F097CCDA9B1111C8B577EBAEBB7
+:10BE300005DCEF4BADC4EFE6AC10FBD1700FFA445C
+:10BE40002223BB0448D514CF7EE227D64004F47FDA
+:10BE500042E1FB5801E16016C61FAE79FD43E403E1
+:10BE60004ACD31F2BF6B786F0FE7E7B39CD7DDABFC
+:10BE7000AE798DEAB1E65E31685F94F79223067B76
+:10BE8000AC2E583FD236E26F4ED66196887E967AB7
+:10BE9000C589A2DF3CF17DDE1A85FC9A18C7330DF7
+:10BEA000E4BFB64C95F0999B69A6F4018CC127F9C3
+:10BEB000AE9ECE2949B7F3D6423BDC1FF579D605B5
+:10BEC00021FC788EF83E37CB44A9FC6ECAE2FDF621
+:10BED0005C933703E58A9E589E8369FE0C846F4FFE
+:10BEE000C778B3124207DF88F173C5F80FE0A68365
+:10BEF000FFDD9F956A9D9F43F701E91C93E3CCC941
+:10BF0000CA5F85F1A573D68E412ECCEA2CEE846EE5
+:10BF100068BFCB92FD88FBD8761E475DDEC539220F
+:10BF2000ED6AA7F19FC369DD64F72DDDFDABDD7818
+:10BF3000BFA0F4131BE1B774A088DBCAF10F9D4AC0
+:10BF40000648BD3D7BDCAFFE1C457E8ABD3CBE1372
+:10BF5000526E675D5AC2EDB26ED85F9DF88B8EEE61
+:10BF6000FE24AA533BF65EF53BD9B1AB946FA250C9
+:10BF70008E90EB297CE58B789A877285FC4455AFCF
+:10BF8000AC8CEF2CCECB68C76EB7770BBB5ED5D22F
+:10BF9000A24EEDDD46FBDDF02C83FFC0CCE89E9980
+:10BFA000B4DF3135271AFD005F88FB275DE939D200
+:10BFB000FE5DB5013A8903BA34BBA2D1BF75A90BA6
+:10BFC000F97A59163FFF2F087BF9A59D2AE93D977D
+:10BFD0007646D2BEAADCF9F06BE877ACDCA2D034AE
+:10BFE0002A5813C10FE0CAECA1E71AC6B1C5759C67
+:10BFF000779B3F3D1ACF95B25F455623BD2D6A50C2
+:10C000003C5B613E6D765774F790F9DC85F406F47D
+:10C0100053666B184AF016F39F9AC5F9A4ACB7A8FB
+:10C02000F161B22F43BD8B2417FD3A82F1FB29AD9C
+:10C03000BFC3799EDB38C88DFEC2450D7B2A49AE51
+:10C04000D819E144BBC25911B7DCDE8FA0EF4559C6
+:10C050005C8E3927FC47E776F37700709EB8CFCE29
+:10C060002ADC0EDD8E6FD1AE4AC02D368BEF3359F0
+:10C070007F51434B545FA87FEAC07B94DE2BD6B53B
+:10C08000C8D13400CFE3537B23C8FF756AEF2FC7B5
+:10C09000BF0CE35D6818D30DF785EC7F759685EAD4
+:10C0A0005FD8A81621BC989FC7CD54207C0785CEA9
+:10C0B000336E932F2574FFF1F8A1737B9F8F32E5C8
+:10C0C00004F15961AFB6279A701FDDE345FA8E403F
+:10C0D000E2817AD6BD937D78865535E631A46BDA58
+:10C0E0007F89547F8D29A49ECDE2A63853CB8162EF
+:10C0F0000FBF6722EE458938FE423587FC8AB307B9
+:10C10000BAA6DF897CF24D0BE16371B66B3AF2A7F8
+:10C11000CB4D2AC3792E4E6101944F96DC1BB90991
+:10C12000CF3139EFD983383F285FA3300FACAFDC74
+:10C13000AF320DD29E807F1FD25342F3108C936C8E
+:10C1400049E172858C1F7DBCC4E4B1C239B8272B8C
+:10C1500056F059ED17F3D17F36258BF4B9E356E647
+:10C1600053D1AEF41C8F2F2D4FE571CD8F8B78F806
+:10C17000F2D840461CF4775EE0B77C4A2003E32EF9
+:10C18000CA9F4BA4B88BF356EEF7C4EFE8672DCFE8
+:10C1900087F60E7A674393ED6342E8A97C8EDB85D0
+:10C1A000F5D458B72BCF81F3755E2439775F2443DC
+:10C1B00039D7F442248F9B7A266CB32D046FAF0AD3
+:10C1C000FA93EF77B03B789CD1A3161E97FAE8D686
+:10C1D00044BF3F045E8F5AB49908075C07CAF78BC7
+:10C1E000ACF51928FFCAF92E8AAAA7799E17F4BEC2
+:10C1F00028BC9EC7738BFBC0581FF32D220EBD7544
+:10C20000878DE280CE2636EDC7F1CFEEC866B8FE48
+:10C210009614FF8203540EF225E0B3F4595B00D765
+:10C22000736607B7479FB17079EDCCE40417E2B7A6
+:10C2300068CA86D964AFD96253D0CE774661D60436
+:10C240002CDFDA9DE2CF4B6B6B287EBB14D806DE69
+:10C250001F82B408EF019DD99A4DF16667F0DD06A3
+:10C2600085BEAFC1EF1AAB9FFD2384C776AE5F9D3D
+:10C270007DF66FD9A1F1DE322DDDA28FAF9374224E
+:10C28000CB3FCBE2FAD067595C9F3B9BC5ED1115C4
+:10C29000110D8FA6D23A39DC014FFC1D1BD61CF9BB
+:10C2A000CBC1184F91AE201F799C05327E897687CD
+:10C2B000ED5CFF3ABBD34271EBA52F447A288E6D1B
+:10C2C000F575268AA750B99C5E6A02F041AAFC74F3
+:10C2D0003BC597757B362CDF46F239233DB775ABEE
+:10C2E0002AC6015D10D7BD8DC71D4F405992CA7334
+:10C2F000A9FC8CC89FD99F4B721FF4EFC1FB55A5B9
+:10C300003FFA3187E3D492B7B8DC65277E5BDEEE77
+:10C31000E719198DE760C5EA11D1785F91BDA332A5
+:10C32000945B8C70BA6C76F7403E3B3C5BF0DDFD75
+:10C330004F907FAA4CDC23287B56E17E68D8877813
+:10C340009FB36CD588C7883E7F6761E9B09EF30DC7
+:10C350000F4785E2232D9BF3C5F6FA5637D52F8379
+:10C36000FAD84FD9AA37A3683EDB2C14AF62C4E3D6
+:10C37000776EFFACFA9DDAB7D34703B7B374583F73
+:10C380006BFAC127D0FF5F7786B97DF4B581EEC126
+:10C390009DB3342CC0F59FDB15467CEB5C0CE70F9E
+:10C3A000A7809FFA32711EB7FC8CE2BBDE9D4AF774
+:10C3B000F716FAF5FDCA71B3B22D3CFE2ACE1D8DDB
+:10C3C000F18215EF703E0878B995DABF63A1F6C621
+:10C3D00075D8B239FF6FDF9FBB22881ECEF5E47897
+:10C3E00039B73B93CEA796184EE730DF64BCEF77A2
+:10C3F0006E57661EDDA343A107E8A154E8BFE762BC
+:10C400001A929D21E52D16A1C705A026D20DB601D1
+:10C41000FE5E5AC3E5AD32FB5A8A2FC178DDA1F921
+:10C4200094066CB11DE36E815E49BFACCDE6E7209A
+:10C43000C3F1E2459C38C9410D56E4DB9A9017CB15
+:10C44000771AE37679F96CD91EAF64C83861A443D2
+:10C450009F42712A652BEE5944F1F7D5EBEEC47D6E
+:10C4600026E75F666645A8A7B5282ACDA3258CDDFB
+:10C470003D05E5CAD07142E4B945D9EDF656E68CE2
+:10C4800027399684FE8A6C17A71B3C41F19EE20A6D
+:10C49000652D8D9322F55DBE2E0927008715E304D7
+:10C4A0005BC688F22ED62DE7695C77BBDC95CDF9AB
+:10C4B000514B8AEB672311CF6FAB74FFF7F23783D1
+:10C4C000A2633B91D382E7BC35182F0BF37F289BE7
+:10C4D000D1FCA7647339BD0CE371619E191BF5F1A2
+:10C4E000E2595BF4F97E3BF5F99CBDFAFC80467D90
+:10C4F000DE7D549FFF018E3B84EBE178DF18F57001
+:10C500004C510F77D9B81E8E79D4C331453D1CBF2D
+:10C51000A31E8E79D4C3318F7A38E625BC511FC74C
+:10C520003CEAE358FE9B6C7E3E968B784BC403D26C
+:10C530003B7B314C771FE9D22BFC7E09D001DF37E2
+:10C5400033ADB46F1EC71AA48F70BB53CFA9761733
+:10C55000C60FAF8AD3766477C77B284DAB12116FB5
+:10C56000E6668A63AD7A89C7B196E78739D0FED18E
+:10C57000BCF2D42A0C0FBD234EDB8DF52F595AB7D0
+:10C58000217C2B6A8ED07DFDE665AE776EE0F823C8
+:10C590003B0C2B892539AA18CFB9D8AEF1688C2766
+:10C5A000676BF5F1E3C67872631CB9910EA4FCF7D2
+:10C5B00094A53511F9FAA73BEC6B71FE9F8689FBB8
+:10C5C0003033EC86780007F193C50F2A9BF1BC7ECF
+:10C5D000279BDFCB6E3B06F27A27E7AC4CE75E1970
+:10C5E0004472797B7EAD62A2F874CD43E7D01231FC
+:10C5F000A764A5B56535F2B945263A372F83BC4601
+:10C60000F2E0FB2AC90FF8AE56E87AF05DAD50FAB9
+:10C61000C277B5F4F7257AEAEAE3BB5AFAFB12FDD2
+:10C62000F4F1F9D3961D42BD7FEADA41BA7AF3BC40
+:10C63000230C7014F316F2EC3C383F3C285F2EDDDF
+:10C64000908CF85DB2A8AD6535E077C9BE303796FD
+:10C6500097E0FF015F2C813EF1DE65C95E717FB915
+:10C66000467F0ECF15E7508999F99CB1413A2C715C
+:10C67000324F0CB45FD4AF6900BE9FB5E88DF7862A
+:10C680003A5351CF18D303F951B2C54371B5E57B85
+:10C69000D2639641BFCD7DB56F91EE4ED61F7968BE
+:10C6A000169E877BB8FEF7E9DAE7A328BE4CD05B7D
+:10C6B000B2C5198E78DF54CFE3EBD07EA6C606E96B
+:10C6C00062537D5C785F4770BD413AF886F004F8AC
+:10C6D000E1769E92C3E417696B10EB1DA3F850CE70
+:10C6E00096EB93EF6EB115BC9FEF89FC49A16FC823
+:10C6F000759ECF3E34C085F73A6A0F24ABC8CF4D44
+:10C700003BB7A11E72C5A625F61B82F1A0E97FC426
+:10C7100077D84A3FE0EBF9CBFA82A8E1287FEEB266
+:10C72000B827407E75FDD356D42B4ACD7E2BC567E6
+:10C73000EED864C578E51BB76FA2EF0BB617533C74
+:10C74000E642564DFAE869F94E828047C95865A31A
+:10C7500013E65DDB8FF38F9270EEDF03F9E8557C13
+:10C76000A7E4F276250FE37CA679F7588BE17BBE30
+:10C77000A867DC276D6F4D2DEC4EF0E0F7403E6072
+:10C78000A0DDA775DC1753AFA4D0BE9876A53FE90E
+:10C7900069B705B2B93E9C63D087DF52B93DAF910E
+:10C7A000EF83126BA0DB54DC27072D24E75698F9A2
+:10C7B0003B4F15F0EFEB21F58E5475F45A352E42B0
+:10C7C00047CF3358ACEE3ECDED185412929F362130
+:10C7D0004D577FFAB4FE06FACF0F96131FB95E7756
+:10C7E000EFAF62A9CFA5909C3956FF9DF1F842C6E4
+:10C7F0006ED6B5AF605382F590BEB7285CEFD91BFB
+:10C80000B319ED802526AE3FCDD0F8F7CA03FC3B27
+:10C810009BC174FBB04F9AFB8FFC5CB490DF40DA95
+:10C82000DB67E0BF3B813F63E1EDF7D8F11E3FDA04
+:10C830002774F7BB85BF10E78D78A810F6A48A2C63
+:10C840006E4FAAF03559F19D0480BF392E96EAD972
+:10C85000E330AEB25E217B23A64B29CE521FA785C3
+:10C86000FD61FC63E531B518F789B1BC04DF2942ED
+:10C87000FCBEC4E3522BD12E14D5F17DB44AB413BF
+:10C88000A17DCBF01EDAA17E2E211FF957F5443889
+:10C890004E50F2E8DEE6CE43568CCF9B362D260F67
+:10C8A000F78F91CE247F877D4D71856D6F1D213A65
+:10C8B0006B2B31131D5F0D1E951E6E6735D2DF0287
+:10C8C000D664C5FB290BF62A6ED44BB11EC2A52730
+:10C8D000D2A5012E71B11DE121E1D40E3743F942F9
+:10C8E000C6E1B5F080E247FED8014E027EC6F97778
+:10C8F000053FB9AE059A361EF9845CDF425C078EAF
+:10C9000003EBC071A4DF820D33EED734B25F557AEA
+:10C91000799CAD913EA65CE17699DBAF98299D3676
+:10C9200041BF3FB11DEE93DBAEC453F9B5D24F25E5
+:10C93000CC13CF856BA51BB91EC98F83FB84DF4B3E
+:10C94000B8DA3B4746FBE4DBFD847D72081BA28B13
+:10C950006F16FCD6D8DE18DF2CE503E3B9531C694B
+:10C96000A278CB36472AC91D92FF6AE25CD1567E77
+:10C9700041F534A8C767E3D19D439AB0132E8E4C7E
+:10C98000A577249297C5C523BE8AC39C14D75FBCE4
+:10C990004CA538EA62A8E70A915B56AD484BC673CE
+:10C9A000E4C47D994FFA409E3F716FB7F86130CE75
+:10C9B000A72B2DDDECAE60BD132B0B9331BEE3D363
+:10C9C00075B619FE4EE0F59538372A7EFA219D732B
+:10C9D000174C6F45CD80F6E52BF745E1F581B29513
+:10C9E000FC7C5FDE57FBB21FF97D376D7322FC9C28
+:10C9F0009B06A09DD8C261DA2E5794AE2CEC8172B2
+:10CA000047F9B7479E74E2BDF0659678944BCFBC6A
+:10CA10000FE7A442E71CC913A7C3A00BF2C345D27A
+:10CA2000FB67A715E6417FD479D3A12F57A3BE9802
+:10CA3000D7901180F47ABB66E98F7AC1CAA7499E64
+:10CA400029BD7F5906BE43A82D4B8FEECC9E22D325
+:10CA50006DE23C47B91E5394EB31BE06E57ACCA398
+:10CA60005C8F29CAF5F8BD6A835E2E8C127E4A69F6
+:10CA700077EE53D79A877E3FDF5896554DE7B083C0
+:10CA8000DE055EA284BB913F2D41190AF37F8E2003
+:10CA9000BB037BFF261D9EE5BBC1F25DE051AD20CF
+:10CAA000AB85EC931BAED859E83DDD312C46972F72
+:10CAB000B027EAEA173A5374E5372664EBCA6F7277
+:10CAC000E5E9F2B7640DD7D59FE81EA3CBDF3AECBA
+:10CAD000265DFDC99EC9BAFCD4A299BAFAB7798B72
+:10CAE00075E5D3672CD295CFD4EED1E5EF2CB957AD
+:10CAF00057FFAEEA65BA72F94E7223EA63367CFFDD
+:10CB0000C54EA97C2FF9872AA3F7D8461698B89D59
+:10CB1000D1C6CFA3256FA73B42E9E0D6FE5C2FDD4F
+:10CB200095E3B9B9FF90E07B98F29DCBBBFA73BC5B
+:10CB300026B180C2F5E1A644A463633D63F9C888C9
+:10CB4000C3975D80CBD7FA1FB9CD8CEF475E77785E
+:10CB5000501AE4A372C26EA7FC88C3CFA7423E7EE0
+:10CB6000E7AD3C3FF0F0652CF7E744F1FC5446A2FA
+:10CB700049EACEDDB7613CCAC81B52D7BAB91DA578
+:10CB8000D3FBEE324578E03D718407A601A0634CEB
+:10CB90000F031D637A14E8789E05E605748CE9316D
+:10CBA000D04FF1FB6F413FC5F42DD04F31FD1DE853
+:10CBB000A59836815E8AE9BBB533287DBF56A3763A
+:10CBC0007FA82DA1F4C3DA6AFAFE716D0DA57FAAC4
+:10CBD000F5D1F77BFB4BFB4340F7DE6857EF8A4A02
+:10CBE0003FA7F46BD655B3E608E41BCDE698CFEC2F
+:10CBF000417F65D7760233FB2C445ECB553C2BFA44
+:10CC0000D3F8BD9C749F427C77A468F7217FF820FD
+:10CC1000656AFA2015CFB1EA5731D4E60353E7EF3E
+:10CC200047DE25E8C397E37908DB8DB2F3FBC9A3A0
+:10CC3000ECFCFEF12873531DD257DDD7CC85F13FB4
+:10CC40008722F9BB1F75F799FD680755AEF07D3E49
+:10CC5000BA1BA37CDDD7CD745F7994D39D80E79513
+:10CC6000CCB7FBFDF14F489C8FF4C3CBF89E7157B6
+:10CC70009A0A505E18EDB0BA908F84C60DA0BFFD21
+:10CC800050E467723E0CC793FEFD2D5FB380694090
+:10CC9000D08F3FCADE94827683D1DFB3BB43E39665
+:10CCA000A4BF5EB9D2ACA25D55C627C971E47C238E
+:10CCB000CDD05F7E30FE6894B3210FFD1D75150E3B
+:10CCC000EAAF077CB7E6533D8F4AED1AF2D02E3714
+:10CCD000BADC4171B0324EA0875837D4A3758EBBF1
+:10CCE000A2519CC468112781FDD879B90FFB19DDC9
+:10CCF0002D90887160A3ABF93B644F28D03E3F185C
+:10CD0000B780F52342F62DCE13FBEDFBDF305F94A9
+:10CD1000A33C1E82EF54A9D7B9445EFA1DED63C946
+:10CD2000BE552078CDF214ED1DA423AFCDF9E70850
+:10CD3000DADF69BDD16E3A59C8F5FF845EDEFFF7D0
+:10CD4000D08B87E3BB17237B9B916E245E249EBB15
+:10CD5000A22389F7903833C2737BDC98E8C7485F19
+:10CD60005DD195A4A751768E77C42BC6A9493A52B6
+:10CD7000AEF077DD4697DBE9BC937464A4838E74D0
+:10CD8000C4E9B2EEFB76EAAF231D05F18FF0F8D7C8
+:10CD9000E9A85945FFD5B5D2CFDDAD6C7C3414156B
+:10CDA000A46A77215D145F71BD86F9B96CCC7824D3
+:10CDB00029593EA18B72EDAFAD96E8103A1B25E8DC
+:10CDC0006C4917F5653DF9EE85ECFF61ACDFBD639D
+:10CDD000FD3785DCF066988C53F138F28606E34621
+:10CDE000971472FA2A4A5149EE28C8E1EF9F330797
+:10CDF00097B35DF017F9F1CD4C3B1A9D82EF947A11
+:10CE0000E97DD2F1DD0CEF930AF9BCC8E0E7BF3948
+:10CE1000E74692CF6FBECA3BD7C373C43DB71496E3
+:10CE2000728DEF907A72483FFCAEEF90F2F76BC7CD
+:10CE300089FD9E24E829CDA5B291B1F89EBB66C6B6
+:10CE4000C3E528BE5F3B00DF79F551FE26E6A7F477
+:10CE50001616203962221C4498BF154458CC1F89ED
+:10CE600098340BEF1C160C2AE88BDF43DED9BB0D80
+:10CE7000E757A96AFFE50C7967EFF03817DD5F3DEA
+:10CE80006C4F233914F7AB25C45EFA069CCF7D6145
+:10CE90007D47E0FCC6F45538BFFBC239FA3A9CDF47
+:10CEA00098BF396B19C376E35DFAB827D9FE1667C8
+:10CEB00001286A5DC3EF96012FF642F8BE19933937
+:10CEC0000EE9E2CD98EBC6E17ADF8CE961E2A9CD0B
+:10CED0004A69EE0B7D3B9393E57E088E379EC63301
+:10CEE000C257C2D3084709DF7F019EB539433AC212
+:10CEF000F32ED423D07E6B7F2F2A2115FD9B9CCF50
+:10CF00005644248BF748DF1EA0A662BCEF089AE7C0
+:10CF1000E89AE1CC8CFE763B87D3A95AE643F89E8B
+:10CF2000C125A0C1DB60DF63E6B1A6D038E83D369D
+:10CF30006D1DE2F5D44695EEEB5F782E8CEC76A76E
+:10CF4000FDDC2E5969D21EC5F272D5B5D68DF2E63A
+:10CF50009B2A7F47F49B23C95322AF815EB7F077AA
+:10CF60000ECAEDE33BC5A7D42F67A57AEEE2F20D1A
+:10CF7000D3FD1E452F1B7F0F42BE4BD995BC3534C8
+:10CF80009CF3BD5E36CEAF257E375A851C00FD0C66
+:10CF9000053E9BF4B370D2B71E8CF7EC463C801E66
+:10CFA00043EF4FB5F58AA4F3E9B0888B1B1DE84F1A
+:10CFB000EFAD1589DF1D785DBCE77E58C4CB3564C5
+:10CFC000682F62FBD75D877BA1FDE106C6FD403778
+:10CFD00039F8FBF9D7AA9F1FCA11FAF90036E09A6F
+:10CFE0007E27A1BB4AF72946B30CF2C317E07C9118
+:10CFF000CFBD31D78CE764C8EF24D0BAFEAFFD4E69
+:10D000000263AD2AAE2BC9A9B0C753AEFD77135446
+:10D01000A157C9DF4F28E2451D7E37E19751453CB6
+:10D020002EDFB1A0D3DF4D4812EF5A33173F37E45C
+:10D03000EF261426E8CF9102E798A34E4AF5769E94
+:10D04000A4ABC48F29B9E2FCB856FC5730C27F7B31
+:10D050009C69371EFF345AEBF733B4CF1774B3B85B
+:10D06000FDAE8E74F09FF6BB285DE1C9F87B2946C2
+:10D070003C197F3F25492D37D33B90024F33E02F9A
+:10D08000E2E906F1FB16E3F0F72DD8BF0F6FC30CF2
+:10D0900078FB82AD1D82EF965E2AE67CBDAB73FF06
+:10D0A0004B9767742EF0BD9B05DF97F61119976BB0
+:10D0B000FCFD24690790F1BABEB11CDFBEE311E4A8
+:10D0C000BFFAA1DA1C89E7CC7113FFBDA4C4EEDA64
+:10D0D00004ECFFEE9C6A05E191C0BC7B16C0FC67C6
+:10D0E000FFC6968CF9D97DF87B912C87FF5E909CCA
+:10D0F000DFEC241ECF352D57E8BB6E1EBF353D97A4
+:10D10000EB01916E27C59917E730113FCB9267E786
+:10D11000227DBE159689F4B79EDB039BF1BDCA6ED6
+:10D12000C1F72A514E47B9B8B7904BEB3EB2DB3945
+:10D130001D32DDF99FEDB7EBE29CFB6F77EAF2B9A8
+:10D140000D09BAFA030FB874E579812C5DF9A06373
+:10D150006E5D7E48D3305DFDEB3EF4E8F2C39B8B01
+:10D1600074F5479CF6EAF249ACF51708DF8772536D
+:10D17000091E7D14612771717CCCFE613CDD5792E4
+:10D18000FA878C7BD7043D1BF59A3E562ED7D725C0
+:10D1900032AEB7DA857ECAF4FA8D26E2D6A55CCF28
+:10D1A0007CFAB87519AFDEAE07093D47EA1321F1E5
+:10D1B000EA1E9CBF8C576FC7BB783FD448AFBF14E3
+:10D1C0007837AEA38F95DFAFABBBD74AF784E4FCCB
+:10D1D0008CF33A20E298B7DA3B7F0F6A472E971319
+:10D1E000BE4EF36ECA857A4F02BB22787618CFDD29
+:10D1F0008CBF3F50F713AB7BB9EBEAE3CD1EC8D72A
+:10D20000330BDFCDCDA1F757E95EA01CF74541DF19
+:10D210009B060A39C530DEEC681E1FC7A2AD74AF8D
+:10D22000A5EBF1385C13AC6C05BD5B25EE79DCB584
+:10D23000B6E1412C9A65ADB7F08707FC16B4A34D53
+:10D24000180B72621EE886CF2C7AC40172D1933516
+:10D2500066B28B05769DB8DDD737786FA70FE86982
+:10D2600048271310FFD0EFD0813C8EBC2597AFAF7D
+:10D2700050FDA6FDBE854DC7FF19F1FF4EE88EE8B3
+:10D2800051AEE37FEBFE85A45F239CA45ECEC4B9C0
+:10D29000D657CC4BC24FEE0B093F79FFC5758FC5F2
+:10D2A000BBD941F7688A302E4FE2EFA681DC6E1FB2
+:10D2B00087B260775E0FF95157F50AD59C68F4176D
+:10D2C000B43157B4F32A76F3FFA57B2904FFAEEE01
+:10D2D000D375C5273AF0872EEED775459FF4E71A28
+:10D2E000EED985F0091E2F25F0E1EF6BA2B884D5A9
+:10D2F00091FA7D5C3080F38753621FC3F9EDC8D388
+:10D30000F30986FE8FBA95AAE0130BDA7F6F04BF8C
+:10D31000CF5F6921B99B31EFA318A7F197F5167A72
+:10D32000E771B487917C3367A3E2DFA4047FE7ABA6
+:10D33000D86778A745FD86E4C32FD62A4EFCBD8862
+:10D34000B96BF4E50B1DFC774AE61BDFAB91FEB829
+:10D35000ABE8F5830788F3DDCDDC249789388A12A2
+:10D3600051C72897B5F9B9BF11F57295DBB128FE01
+:10D370004E9EFB2EF47785BCC302700DCFC2737C2A
+:10D3800085B9D3B8C876B87611F771DE21E23E1CB4
+:10D390003CCEA56D6F18F70F4B3F9CA87FDE7799A9
+:10D3A000CAB13EF676218FC7AF48FF9BD1BFD7E603
+:10D3B00030917FAA6D6F24C539A0DF2B1AE8E1AC4C
+:10D3C000694FFCB094E0FCB46655E73732A6DAB298
+:10D3D0007DA44F2EEFABCD1E8071FA66B7DD0DF93F
+:10D3E000FB1C87E91DAF09C20E669C6FFBEFFE8D2B
+:10D3F000E4EFEAB4F9B8BCDB56C4DF3B01FEC87009
+:10D400003FC9788EC90CA43B488B03C3693ED7EA59
+:10D41000FF9A7A258FFB7FAF8CA0F6DA9AE194EF22
+:10D42000B3E2C17BF09ED16D750B2D180AD0FC8B39
+:10D43000A585E1D0B4B9B77F7938E26D8CD2A9FF68
+:10D44000A276003F5F9A0DF716647A49EC1BC7403D
+:10D4500026F89388E75AA6D07E58AC3019DF45FCF1
+:10D460005CE62FD78B7C21CF2F59C9F3CDE27715FE
+:10D47000B6097B0BAE1B535C37DA05760A7B0CAE24
+:10D480001B535C377E47FE8579E45F9847FE8579BC
+:10D49000E45F9822FFC2EF739837394FE57EBB7186
+:10D4A00021FB03FD76E342E423F4DB85E6D16F172D
+:10D4B0005A1FFD76A1E5E8B70B2D47BF5D681EFD3D
+:10D4C00076A1F5D16F179A67C36E0AE691DF7926C8
+:10D4D000EBF25341FE1F17B2BFD16F17DA3FFAEDDF
+:10D4E00074FD69F7E8DADFC96A74EDD16F175AFF86
+:10D4F000EE1A45E7D7BB5BBC433B77431CD14F7962
+:10D500008AB711E9FEBF22BEFDBE05F545B5711112
+:10D51000D7DBC2DD1CCFF5451CEF267ECF42699DCF
+:10D5200049785E6AE5F9421EE76DA41FF48B8DB35E
+:10D5300070BF18A6E817C314FD6298A25F6C5C3A2E
+:10D54000F78B618A7E31FC8E7E314CD12F8629FA91
+:10D55000C53045BF18A6E817C314FD62D80EFD629A
+:10D5600098A25F0CBFA35F0C53F48BE1F7E3E89F35
+:10D57000B304E785F27C5F9D5E0974A8D32B9DBA46
+:10D580003CCAF3A1F5519E0F2D47793EB41CE5F935
+:10D59000D03CCAF3A1F5519E0FCDFF2DD745FB0C12
+:10D5A000E5FAD07628D787E673EB7DAFA2ED6CE283
+:10D5B000C68B47316D8E549E548065FC7DF78FA6D7
+:10D5C000A3FFB2394C498E01CE69517CD3C7415E6D
+:10D5D0001371940358AB897EAF0F95478C73083055
+:10D5E0008A5BCDFD3A91CAA3329DED71CB88F7BC21
+:10D5F000BD8C7E8F46FAD7657B3773AA98CAFAC16D
+:10D600007CE7F58CE3CB7AC43F43E68137AD31DE6E
+:10D61000276FA9231FE366B789DFCBDDB69CC75B05
+:10D620001BE92A4FC84BDB4C7B0EE37D9AD6628503
+:10D63000EE5D6798D9314B3EC2A93A1FE588C48197
+:10D6400031625DD5D7E3EF8EC9794B3B28F009BA3B
+:10D650009F38B2B5A9201AFAD17C63E8F771265831
+:10D66000B9FC80ED50AFECEF533C9B43E83B4DC819
+:10D67000E39A8F8FFFCC539378BB70DEEE99A7A20D
+:10D68000088E9356281477367227F3E03DE81C3154
+:10D69000EFFE3B032A8E57BC828F27FB2DDE984C72
+:10D6A000F7428B59F338BCD7C2062B0CF9B6841B52
+:10D6B000ACEF28AE2F03B60ADAB1BFEB7DAA5183D7
+:10D6C000630A311E9135327A5774E2E0DFEBD64BB4
+:10D6D000681F4AFDD2B996E953E81DE749BE65CBFC
+:10D6E000F1589FE8BBE7D5EE587F0B73A7B8E82841
+:10D6F000A2FBC7723EFD3C7B4C702CB21CD6640A68
+:10D700005310DFEC485C08FDC0CE9F86F8CE735BFB
+:10D71000E85DE5C966A785DEE9E8225EE7B243C6B3
+:10D72000EB18E405435C4EDDD20F93D1DEBC38D25A
+:10D73000447693C5FB22486ED03628C4D7A41C5427
+:10D740002CE2FD2EAF78B5FB7484FB1E0BF527E3AE
+:10D75000752AD2FCC926BC9FD073D3805895E4802B
+:10D76000BB07A21CE07BFEF661586F257F57F4F2E1
+:10D770008A7DFC7749857F47FECEE93C11FF559CA9
+:10D78000EB8DC67818F97B6AF29E8CFC1D5369E715
+:10D79000297E7BD06B88DFE227C4BBDF6B8AE9FE82
+:10D7A000BB31EEAA4CC87F8B5658286E6B91413E18
+:10D7B0002C13715957FB7DD39A8106F950FE4E8E7A
+:10D7C000A8C3D45E7F40BBB0BCF739CBC2F9C0ACB4
+:10D7D0003D8CFC55B3961598F0BD6AB68FD3CFAC8F
+:10D7E000655CCE99F5A287EE6F4AB9F11D21CF4C49
+:10D7F000B99244F07F4FC82FB761BC2AC0794273F9
+:10D800009888634BA474FA151EBF3AC5C1F941F359
+:10D810002BFCDD8D369F8DCB5547197F37CE409F32
+:10D8200093CD7E135E68748F04FA84FC449487A0C1
+:10D83000BF19281FC521BDA714523C649142F78827
+:10D840008CF43EC152FD2AC6DB4ED8CADC3E164AD5
+:10D85000EF40C7D89F4FA1F71834A1E74A3A36D214
+:10D86000FDEC08619F7270FB53BB9D0265557A44C5
+:10D87000FD83E9184F3C1B6D863D69191E8CDB8BBF
+:10D88000CCE1E5CF0DFC60FA0ABCFBD185DD42FDA1
+:10D890009195E0A1C97727BAB023A0FD00F9E55D15
+:10D8A000DFCBB3CE09E197CBF3C6BEEBEE1EC4F7D8
+:10D8B0001CC37DCAC5F7A5D3EF1F752517CF05B8C3
+:10D8C000E2FE981DDDFC7DA054F6FB81CC332E01D9
+:10D8D0007F5F52AE8F05301EF30E91FFF6D77FFFAC
+:10D8E000E31A07C185F26F0FFC743ABE3B57616FB4
+:10D8F0001E8F645795535D84F1D9413EA5799252AC
+:10D90000904FE505F0F7F80EC87BE006FBC4B703BF
+:10D910005DDCFF62B053CCCDE1FC9B89F7C64FDCE8
+:10D92000F7C26E3CB7E4FC4F58F4F76A65FAE5407D
+:10D93000D3BFF55E89F13EC94F93B453C83F1E353E
+:10D94000F1F7137AAAF54CD88BC8AF2CF90613EF70
+:10D950008E04F1EEB1F2B804C5196AAFD2D628FC34
+:10D96000BD822EEC3A2CABF5175BA1DDEC5A2BFDFA
+:10D970009EE353199C7E9E02FA41F96C96B5E955D7
+:10D980007B4A108E9FD4FCDCC2F958201DDF3BBAC5
+:10D99000A33ACC8D7C79799EF7EF38EF881C37F16C
+:10D9A000A377DD9CBEAEEBEE656EBCCFB8F6D09330
+:10D9B000F87EC3FF037EDA89FC00800000000000CF
+:10D9C0001F8B080000000000000BED7D0B7454D588
+:10D9D000D5F0B973672693CC244C42200F489800A9
+:10D9E000911401270981800837C82358C081100588
+:10D9F0004DC28467B46023D51A2D2D03493020DA37
+:10DA000080C120F53150A5685163B56DA8D80EE2EC
+:10DA1000BB682948F5FBDB86E18D8FD608B5DAFFB8
+:10DA2000E7ABDFDEFB9C93B9F7662680DAF5757508
+:10DA3000FDE3721DCE3DE79EC73EFBBDF7B9F9F68B
+:10DA40009E1CBB7F1863D5EDF96BD33D8CADC9F738
+:10DA5000DBBC7DA0EE72DB7D2EC66E6948B67BA076
+:10DA6000AC4A63B56DD08FB1CEECD9898C7D81BFC6
+:10DA7000098C657915C6A0FF1FF2A1A988B18F6D29
+:10DA80006C2EEFD76C9B65E867A17EACB95573F43B
+:10DA900065CCCFF82FCBCA029602C606D8FD4C4BF8
+:10DAA00065AC3E8379D7E430D60F9EC715F0F6F803
+:10DAB00014E8EFB21F5592E085C0642D9CC7DFFDCE
+:10DAC00062206376C6340BB4F783D20EFDDB877811
+:10DAD000689E2C6857E1B92DEFD83C06FD2AEC6C06
+:10DAE0003EEE47AE479633C5FAD95C8785C1BA1674
+:10DAF0003BE0DF30C46475D894B4918CADD8A8B83D
+:10DB0000E3E0D12297E7FA31505FF4BA8DAD81FAA4
+:10DB1000F4148F3D03EA9DEB14F776A82FB82DDFA0
+:10DB2000EE817D57C03619AC63D19631CCD31BCA78
+:10DB3000209485DDE795E58D1BF765ED86F958485E
+:10DB4000B3FB005E8BDC9A3D6558A47D61B3A205F2
+:10DB50005DDDEBE3BD2AADBB82B14908BFCADB7214
+:10DB6000EC0B5C587FDDB66218EE8BC341BE07FD3F
+:10DB700042D86FFA40F62AC375C3BEB6E7F0F90A79
+:10DB800074E32FC0F175F343FFF93EA8977A136948
+:10DB9000BC6A37EC3B074B37AD13E04070EABC176B
+:10DBA000C6F3D03C741E0B43419B17D7638579A104
+:10DBB0007E833B68C3791634E4DB1994FE0D7C1E2A
+:10DBC0007F53B27D38D4ABAD6E7B16C22F0160910E
+:10DBD0004AEB0B6E87A35904704971E13C6CFE6CF3
+:10DBE0005777F8548BF52E6A4EB62F363CDF68C354
+:10DBF000F39807EB698B72EE77E1B917E17A4AEC9B
+:10DC00000CDFB76A762FAE47C0F7E4ADF1EB592FC2
+:10DC100078BFA5D59603F59B05FEDE85702D42B82D
+:10DC2000847215DCF7ADF15E5CE73C7733EDAF0B4A
+:10DC3000BE9B011EF07CB1DB47F005BC083080C301
+:10DC4000A216E37946D69348E32E6AA9267A5B6248
+:10DC5000F5DBDDFA756CD99BAB005CE6D5C67B15B0
+:10DC6000803F73FBB3115F4E6DBE3E9BF609EB44E4
+:10DC7000B8267A3D53D247129E101E4B7CA92AE447
+:10DC8000F42BE7DBE4B5D27C9B705F453DD1A5F674
+:10DC90006A3AD2259CEF1A4F6CBAB433180FE6B526
+:10DCA0002F5282F54A773A95F429E952D2A9A4DF96
+:10DCB000476CBE50BA12E13355BD58EDCFA2C0E952
+:10DCC000A038871BC4B9025C5F46B8CAF617043D8A
+:10DCD000570C34D23B8E87E3FE449C7BC5C450EE88
+:10DCE000ADC322FDE5BC1529FC3DC47BC4B79F082C
+:10DCF000F860FF15D4DF62E0170BBBF8C5AEC6BEF7
+:10DD0000C82F9E55BCC82F56DCBB2FEB0E80DB8A7C
+:10DD1000A79C5E84C187CB1EBF2503E0C0AC413AFF
+:10DD200037B9AEC59FE7139F58F2F9959C5F84A25F
+:10DD3000F30B579EBFDD5B14A92FBAFFA9CBFC9C48
+:10DD4000DF8490DFFCE9A9170E8F453EC28236DFE3
+:10DD5000F0C87E1634FDDE56EDD2C38FEF777DDE40
+:10DD6000D96A3CAF852EBB4785470B1BAA89FFB2FA
+:10DD700074E6CD5522E76FC68BEA0645A3F7EA465F
+:10DD800005D5AF914F2FDC300BDE8D9C1B4CCCD8D2
+:10DD900028D827E3F095EBFFA3587F87E06F37087B
+:10DDA000FCBEA1A6C49E918AFBAD2E04CEC8E68916
+:10DDB000E7F316199F779D9BBB8BCFAF457A39DB75
+:10DDC000C6CFEDEC061BF19FB3BB12830CF6F7E157
+:10DDD0008A5FBE7D1DF4FBE0816DD94C359E1B2B07
+:10DDE000E4E786E5523837D63BEAB97DECD5F1E178
+:10DDF000A58FF2735BF8F45B7FFE9587F6CBF9DDB8
+:10DE0000BD7141E4C70BDA9EA5739CD7B4D196834C
+:10DE1000F4EACD21FCEBE2FFB5F96E06F0BDA16995
+:10DE20009B0DF9C417120E267A8052633A3A43B911
+:10DE3000A4A420FE853310FF647FE48FCFC23CB7DB
+:10DE4000DD1A9FC4AE88CC9397CFF17E616D720AC4
+:10DE5000CEB7B0B6FA3E3622220FCCFB3C1ECFE93D
+:10DE600065018C87747BBCC49BBD82F0D31255EED8
+:10DE70000EC8E7E7F82300773CE0433F67DB130871
+:10DE8000877EDF4EF022FF183C381CC47911BF7129
+:10DE9000DD76E09F0EE8377859F8135CC760C03034
+:10DEA0007C0FCBC4142A595FA86F8765174339507C
+:10DEB000E5E5E47CBE7F680F613B4B0D17E1FE2575
+:10DEC0007E9BF1D7CE1E6B1A887C2C9579EB3D1189
+:10DED0007C95E3487C95F81C6B7F575DE4FE8EE7EC
+:10DEE0007078DA13607F2997B03F40D6E294C8BEBD
+:10DEF000E4FA581EAC0BE6A9FADEF06DEB619EE386
+:10DF0000ABBDD9B5AE9EF6DB32B96F94FD9AF72959
+:10DF1000E9669183D334D04DAF30ACFB6CF3A05E97
+:10DF200028778E2B20DFE0BDE3B7C65B70FD725F04
+:10DF30003B56416758EBCE550E2A9F5C05843784CB
+:10DF4000B15DABD2A9FEF42A0F956DABF2E87975FD
+:10DF50007E0A97472C9C887A26E8039C1F84389D6C
+:10DF600074D40DA27DC9E7522FE87087135374FC57
+:10DF7000FB44AD909B2C7C2FD237AB1BC41E87A9D2
+:10DF80003A9A8F275A86217EF2F5C9F76EB3751239
+:10DF90003F648976CFE34072CEDB7E3F390DE65B8E
+:10DFA000DC9293AFC07B9575851D75D05ED990E6E8
+:10DFB00045BEB1D8E5598B72717120C78B72D1D92A
+:10DFC000927F6A0BB42F6EB8DC8BFD6F53980FE90C
+:10DFD0000BF82743B82D615D3FCD017C6DA9E06B47
+:10DFE0004B915F02BC96D4ED1BEC86F79778E3F378
+:10DFF00051BE2FDDA284E290DE2CAC4941395CEFAA
+:10E000009B827CACF341C58BFA267B08F8AB23C21C
+:10E010005F37E4F956E6E3F99F07FC83F187A20C2A
+:10E0200056715F6D1AEE83813EF238C375FB48AFBF
+:10E03000FF7F428FE968399AE819C6E18DFA3AF311
+:10E040006B16E4BB2B845C1B60EF3C7A37EA3389A8
+:10E0500016EF76CE2F7FE7C17DBEA1B2389237A2F0
+:10E06000BFE0A7037E50EC40FEB62271601AE9556E
+:10E070005B54E28F127F6AC49A176F2BEB8B78B3D5
+:10E0800018DA51DE6DC587C042D7B65CDD17F16A7C
+:10E09000D1C6C90F04408E650B389EB08667E1F982
+:10E0A0009CD99696B21AF5C2E5F59731685FB4ED42
+:10E0B000EE6C2CCF6C8B9F8BFC7E927BD6A464D8AD
+:10E0C000EF928792F3559DDCF8A9A0C79B975F9DBF
+:10E0D00086F6C0B27FEE7BC43D08E6075823DC3FDE
+:10E0E0006D730603D065D9AAF66C1568ECF338FF9A
+:10E0F0000E84E7B72C7BAE1B83FC5F09EEC8A0FE45
+:10E100009E3477147A97E529C0770FE0F3F21FBCAD
+:10E1100047E3FCC5B27FE63C787FD9F2E792709C7A
+:10E120006F6D3E34CA0DCFD70CF6FF0CC7FF40D938
+:10E13000B6C38D8269CBB61128B79F1376D4F41479
+:10E14000DF75F310EE6FA804F758F3D5B42B045F16
+:10E1500059AF0CF6227DD61F627637966E46FAF2DC
+:10E160001995D5A13E20F51AF9FCD57CAE0F9DE995
+:10E17000D59C8D7871D38ED66C942BEF27F27AC50F
+:10E180008EEBDF443EE57F2C8EEBED56467AF2C2F5
+:10E1900000D7BB590DD06B4664FE03F94E82F34D98
+:10E1A0005B0A0DF210F4129AE77D2B2BC5750CA8B3
+:10E1B000EFCC47FDEB8FD6D0623CD73F825E1BC8C9
+:10E1C000C173E27CEC8FCDEA147C1E0042427DE4F8
+:10E1D0008FCDCF250E7645F4B8C4916D21E473CB75
+:10E1E0009F4F2E50394A117EDDE296FCC935A55F5E
+:10E1F0002AE9636EC4D315BB5F99C2781D04616CB4
+:10E2000078DE2CF4B0AEFAF3CF925DB76C17D72757
+:10E2100096B53DFB6A268C734BBBD027849EB25CBF
+:10E22000D0F32DCF73B82C7FFEA87DA1DE1EC94B85
+:10E2300059DB0F34C173F9B6B99B518FC2731BCB35
+:10E240005842DBE7735783EA9CE07573FE6DED245B
+:10E25000FD707DDE41B2CB973788F1F20EAE1D48DE
+:10E26000FB9DD55BAF0FFD2DDF467095EF033CE8BE
+:10E27000BDCFE2934620FF0B2D4F6842B9AEDDE2E1
+:10E28000B26259BFDC4572FEA15A4B9E15E0AB2924
+:10E29000095ED4E3EA1CBCFF1D0949DBB1DC93C075
+:10E2A000EB9FC567939CFACCE27B7609F4BB433DB8
+:10E2B00010CF06E19177EEB3403DA38FDF5900F315
+:10E2C000A731A01E15E54748C1F68F5F3C5D88EB7E
+:10E2D000183F207C8EC1D26C4ADCBC49A82215882C
+:10E2E0007D0E0B1722BEF77989F3EB876DAC09E53C
+:10E2F0001DB3FAD86C781E42FE85E7FF0F4B10F96C
+:10E30000F11E25F463BDFE555AC0F1D617E76A52D7
+:10E31000609D6539FEFEB88E6B15DB70545D9847C5
+:10E32000CDC5F13FB6F176A9C74E144C384BD86332
+:10E33000F6CC7417EEAF5EC04BD1345607EB5833B2
+:10E34000ECA585882FF7743A581CCC3FB13381F483
+:10E35000DAACCC52926FF5022E8A2715650E7B69D6
+:10E3600098251007EBBD873982D89F394CFAAF2525
+:10E370005EC3F7943DAFFD03F97D3FF5937DBDA0EE
+:10E380007FBF3B146F3DF4A93A7BEAE1DF31B49FD4
+:10E3900083F908BFB97DFCA30A50CF3D5B7AD40F47
+:10E3A000E77D8FBBCDE11DC6C7D3EF63CF9DFF488F
+:10E3B0004AB144D6F771E7A9A77E39124B07C9A124
+:10E3C000897B549223E6F57C9CEEB1D239753A42B2
+:10E3D00016ECEFB2041505FBEF7B0FD737D1E10A3E
+:10E3E000A9A8C73B6C1FE9E50C3B90957CEA72122B
+:10E3F0002DEC0B5016FAD6F3F31BDFCB685FDE581B
+:10E40000C0EDA41B0B38DF95F09570631E8DE9E518
+:10E41000CCAF5D3B2A992542C7DF16CFCF7E3E9019
+:10E42000F48BB37B40CF88A277CAF210EA19A857C1
+:10E430000CD416161445E46CB994BA420EAB62DCE7
+:10E440007201AF729785C3678E093E026FCC786107
+:10E450003E77799EECAE03AFF4CAA1731CFE43462F
+:10E46000E7770BAEA3E31FFB1B81DC58A6AA1DF5C3
+:10E47000E7FC3B9E5F287E08EA159B2DA457A0DE93
+:10E48000877AA2E41F7EE40357D073AE07E631E239
+:10E490001B556A82777D14BE21F9853F01CA11C8D8
+:10E4A000379A891FDCA176BE6251227C624069786E
+:10E4B00038CAE10E30FDB13D6C69A3E7CF170C24DB
+:10E4C0007CE9CF0E64E073B0578A500F541D3F7E35
+:10E4D000F804889496759C3EEA6DC10797207F28C2
+:10E4E000777951AFFB386809D8609D2DC99C6FB40E
+:10E4F000DC9449F2FC6326F8C85C3BF1912B2D9625
+:10E5000000D95BF332C9DEEAEA9FEB09A2FCF9C548
+:10E510003FD5CBB660FB2C07C9DD1694C7506FB949
+:10E520007738B5BF20F9D24D9C2FB5CCD23212B07E
+:10E530007D565F0BCED792EA7F1AE936530D3E1116
+:10E540008FFAE4B712D8E3F83C47CB4079FB80E27E
+:10E550009BB718DF1FCED71D9E97F0F40E7E3C218F
+:10E56000F42775D4256E5FAF934FED4338BF1C1071
+:10E5700038FA20C22B3091E5A13EDF81F87945E4DD
+:10E58000BCC02A67752991734B359D9BC4D7800DFC
+:10E59000CE2F959FDF1A25F6F9A58AF353EA00BF1F
+:10E5A00089FFF3F3B943E5FC9DFD1A1448284FF4A5
+:10E5B000F1EF473CAFBF15CE850462F87684D7C330
+:10E5C00077266AB88F0E0BAB698B42B7EF1608BF80
+:10E5D000134A63A087F9821EE64BBC5D69C2DB70FB
+:10E5E000FFE4534E81B7F0FECF9DBEFFC279FFA27C
+:10E5F0001C1A850FF7FFB73A37DA3CC7849C78C1FD
+:10E60000E13F4A7CC13AD1A0AFEECF3F9D85728AEF
+:10E610009DDFD71FE5EEAE54DF093CBFF8C19D7604
+:10E62000F447746474DA709F1DF33EC842BD687E7F
+:10E63000DD6B445F17BBCE35CE11361C3FB934DFDE
+:10E640001686F7D34AF35F41FC393823CE131745BA
+:10E650000FD93B637416EABF87A68DCE427E77083A
+:10E660000EF000DA11566F22F241D65E497C6CB68C
+:10E6700098F35069217F2EF866E479598FFCF243B4
+:10E68000E09721D053DF07BB0CCBD3609785807F09
+:10E690009E04BB0CCBE36097E1F3A36097617964C0
+:10E6A00095979E1F2A1DD41E467DB959213B68A10E
+:10E6B000D56B8FA60F2FDBA5B290E457F0FFCD8F5F
+:10E6C000390DF59A877A1BEA4B5A40737044EA8BEE
+:10E6D000360C32D4A5FEB8A0E172C373FFCA424320
+:10E6E000FD3F16DE4D1CDEE827FF778237FE360041
+:10E6F0001CCAF01F80FF878AA6DA508E5B1D2CE0B3
+:10E70000047E928C7406EBB7CE51B85E04BF66A04F
+:10E71000BFD9F80FA02BAB8BB737CC5382C88F5023
+:10E7200017427B02E01A72027D95B92F3B89FCE803
+:10E730007AE45C2ADAF3412A6F6421A2CB4A16A656
+:10E74000FA7CD6996D87F21635B416FD76AF39FC92
+:10E75000558540C77F9FF6FB0E0589D15B3D04E9D7
+:10E760009BB952C8CE8C754EC021B97E8A5D47894F
+:10E770007DC16F0EF27D78EFA073C4EDB7C3397C15
+:10E780005C1D1E85F32F73F81F4DB5D07CCB0A910D
+:10E790001FD9FC437AC3F3B78A466721FF60BE3EA8
+:10E7A00006FB28D67C1B71B30087EA52809382F166
+:10E7B000370E9713E51C2E7B37C6D9D18F71629D1A
+:10E7C0008DFC94ADCEEC6CC4DB138D53B311EF56BE
+:10E7D0006F1C928DF83EBB69EAFBC8B727ABD3AB81
+:10E7E000F0FD63CD1CEF19BB95F4ADDBC5D91DF36E
+:10E7F000306F08DACBA7257A03B01F7F202789D690
+:10E80000CB34573EF45B28F6BDB079E9741C4FEE6B
+:10E810007FC18638C3F95F5B6CAC97337B04CF72E2
+:10E82000F09CED91763C7FB5A297BF07FBB9EE4F08
+:10E83000DBDE7C5937DE038589A9A8AFB0D16CF443
+:10E84000176AE4FD5870FD6C55F0CD9773237095F1
+:10E85000F8746BA1EF513C1F784C7136A0259203E0
+:10E86000B774F9B3F62421FC363A7F7DDF9508971B
+:10E8700077B87FA3D55945FCE3C369004758FFDE4D
+:10E8800069D76785757C41BE1F46FA067A3DFCD480
+:10E89000F5C447F695A7511CE6E0F3DCAF7C44D005
+:10E8A000FDC139D757DE0EF2F1E02E95F4BB83EDB2
+:10E8B000E75E41FFCCC136C52B406ED18F7BB07D6A
+:10E8C000D0BD23A1FD539F8DDAF7EE7A8ED669DE97
+:10E8D000F7FB62FED3380FF11537CD775CF097A3C5
+:10E8E000C85F86E03AF2A83C88FC05DAE7EC06FE51
+:10E8F00082E36FE1F32FB6FA88BF30FF5CC3FEBA44
+:10E90000ECE1C754C379D73CE434F115239F59B4E3
+:10E91000A19FA1BEA06190A1EE5F69E42F65A585CE
+:10E9200086F6C3368EA7070FABE4676301ED405E42
+:10E930005F1D7E9672FC5C5D1E47F472781AE733A9
+:10E94000B3E7001DA07ECF3C45684B7ED85ED6075E
+:10E95000CF856DB01D433DDA0DFFA1BC36C3B19C20
+:10E96000598F8575F8BBEC79E8AF5BDF6C6CD7E14C
+:10E97000B3195F3F427C7546F0F553763EDB3E901F
+:10E98000B71FE81BE17BF8D3F317C9B724FE02DFFA
+:10E99000AA42BE067CE533E463DF2DC87931ACE8DA
+:10E9A000F8CA45F2B18DCE7F921C6C75FE93F0F8DB
+:10E9B00050B9C0E3F22184C707670CC92279169CBD
+:10E9C0004BF4305FD847076DBE44F48F1E5ED93BD1
+:10E9D00009DB8F369411DD497A32CF7744E09FEC22
+:10E9E00037DFDA69F3469187FE9546FC613BE71213
+:10E9F000BEDF6EC2B358E39BFBCB79E69BE2BCE67D
+:10EA000079868C14FA665BE545CD8764D8F53EE9D6
+:10EA1000B50911BC54910F7C9618267B9CD349B93B
+:10EA200080DB91D2D189A447CC39472513F4DCD5BA
+:10EA30003EE7DC5BA391DE4A6D82DE6BE8FD32D1FE
+:10EA40006E5EC769A1379C14FCE3B8A06BD9AE6EAB
+:10EA50006BEC7B03E2FD4AD58BFCEAF0F442C2F397
+:10EA600033C1729AFFC81C95FC4CD3460EB801FD09
+:10EA70004C723D72BEB219E712D18FF629C00BFD60
+:10EA80006265366F9F68FA85191EB1C695F8B3772F
+:10EA9000DA90C3B8CF43C847B1D56F84D3217C1F68
+:10EAA000DA676F5329CE6686D3BE6943882F1DD996
+:10EAB00029F827C015F5EF9A878CE7BAA4C569E253
+:10EAC00037BD0DEDB3CBB95E26F9B55CDFA19583FB
+:10EAD000FA30D7C59FB71CE762F1E566F13E8ACDF3
+:10EAE0002F48FEA618C6030BD134DF4053FB50530A
+:10EAF0007B81B17E91787C54E08F943F47E3BD9554
+:10EB0000D1E27747AE89ABD1E7256C1AC9FD369BB8
+:10EB1000468A78F725CAED7B471AF9E085DE977CAF
+:10EB20006F61A1AF6524D269A88CE2D817CBE774D6
+:10EB300072FEA191B8DEB062C7F7A55E5523F4CF8F
+:10EB400056E77DAF22DEFD45D8037B67C4111EFE6C
+:10EB5000F529AE77FDF5E7A7499FDAB7FB8EA4B09C
+:10EB60000E6F9609BC39DD3E2409F1F0585B7D92A9
+:10EB70009EBE65FB19783E7664445EC75AF7979649
+:10EB8000D7CF0A7B602797D737599BA3DA03FF6A51
+:10EB9000393D595D497A88595E9FF67892DC041FA9
+:10EBA000417742AEC8B8CF5F6D9E24F4171E0B723A
+:10EBB000B922F9FA41131C4E201CE222F224161C41
+:10EBC0008F8BF7651DEC511BCE5FE6F0BE928AFE7F
+:10EBD000970D8A17E35E989E520CE77C604EFE8F7D
+:10EBE000D16F25FBCF2F52492EC8793EDAACB4A1A4
+:10EBF000DFEFB595FBB2BF07FDAB773989AFCAFE32
+:10EC00008BA61BED2CB33CFAA8F193B746C3BC65A9
+:10EC1000CDAAD701EF954D2FE9C3F56AB7118F043F
+:10EC20005D9ADF5F6AAD8D7A9E66BE57367D35E9A7
+:10EC3000EB87C47A0FED1D63F324767FAFCCCAE176
+:10EC4000B014F4CDD530EFD2864F48FE2C9DAE7A6D
+:10EC5000512D79ADA97E26E2FF519FCD82F471A49A
+:10EC6000ADF74C8453608EEACD85FEFB9B06111DEB
+:10EC70001C6BBABA2FCED74BC0EB747B9C05FD4FF3
+:10EC8000A77D3616227B3944E7F9514319D9C7A726
+:10EC9000114E78FE5637D149BF22EEC73A0AE370CB
+:10ECA000FBD9C3F4F1C02341B53418852FF513F314
+:10ECB0001D3FFF43C2AB5783FB08EF8EB6F1798E41
+:10ECC000AF7427619CEBB70D85248F8F4D87F1A121
+:10ECD000DCBB7BE97D98AF777A834AF2E374FBF57E
+:10ECE00033B17E688394BB5C1E558BF957EF1E3D94
+:10ECF000A318DA3FFAB98C6B72BA5E20DAAF9E7550
+:10ED0000F8BE62BD3CDB35D7B0FEC3C1E3646F9D86
+:10ED10006E80B7018ED53306D9D11E5EB4CB786E26
+:10ED2000E51B8C74083F577EDF489ECBA206D06758
+:10ED300081651D9D5E4676F4EC406F93BD6DB4E336
+:10ED4000CADBB8BDB7E0E1B2A210D269E0131B9EE6
+:10ED50005375739C619ED92B8D76DA02935D66B6EE
+:10ED6000DBCCF245C263B9ACB755D23ACC7A4B375B
+:10ED70007963ABAD8A961F5155C4F5B16AA0CB74C7
+:10ED8000F42B33EF0CB4BB8E017CD7C378D576F768
+:10ED9000DF73414F3EA2B2F1E44CF30658B1F41BCD
+:10EDA000E8E65BD0A09AFC1346F882BE7E0AF5F92D
+:10EDB000A6DE420E0740AE24A29CD1FC4528272E99
+:10EDC000D61F70D1FA7695D0B7AB0CFAF641ECA20B
+:10EDD0007B7F6FF9F5E4773A3CE37AD2BF0F77F99E
+:10EDE0009D7C06BF9384EFE1E965067D52F7BC1771
+:10EDF000EB813FC6D21F8F0AFE7A44F89DD60A39AE
+:10EE0000D320E4CCE1E9C22E4C65442F56ABC62E8C
+:10EE1000862F5D481F5BD0D0CF745E4639E32CF15E
+:10EE2000B716015EC4A50F353CB7B90B8C7463C22D
+:10EE3000CF7E8CFBC1EF46DB1EE05E5FCEF347F179
+:10EE400039E6B148BC64D01FE573F986A1C1F5BCB1
+:10EE50003DA01660DA1B43158DFA5B795D53783D52
+:10EE6000E012EDAAC85FB341FD688E772EEA519893
+:10EE70009FE34CE1ED8822FD009F935222F88FFE24
+:10EE8000F9781E220F24C17BFDE7E4BC8CF48D7958
+:10EE90003B9741FD5745398437E9E89A2FA0F14364
+:10EEA000989F13AE9F40745CE648E2717690B33D44
+:10EEB000E3DF6A6EDF94F6A6C9FA5BF97A62E2B321
+:10EEC000E877097AD56B442FCC42FE938DCE11366C
+:10EED000C4DFD92E5F16C201F0BDF276B4D35FB4A1
+:10EEE00093BCDC5BCEFDAA07A78D7EF836783EE2A8
+:10EEF000191791F1C1C580E724173A13F5787B649F
+:10EF0000E5710BE6D3FCA19D79311FF1C8AE8A579C
+:10EF1000DE8471F6AD5C786F11D2D17ECEC7CDFEA6
+:10EF2000D89267C6913CBB6E864A79DA874A55C645
+:10EF3000F97C82C1AE88F86955C28F4FF758A91D78
+:10EF4000F3AAF2308F0AFD95986F552ACE45E81541
+:10EF50006DE21C9F10FEDA1D826E5A04DD6C127485
+:10EF6000B3CEECAF7D88D3CDA1763004404EFE6E9B
+:10EF7000FAC289E487DEC2289E9C334D5D3F12F6BB
+:10EF800077799CD786F02B999ECFE13947B1601CE9
+:10EF9000A6AC34DF86F47E796F8FCD477AD62CAA63
+:10EFA0004F9A934376FBDE95658964BF277AB390C9
+:10EFB0002E074F8F0B5992D00E2C243E71E5198BE2
+:10EFC000815EF2430906BA1BFA588AA17DC8964CA5
+:10EFD00043BD8F6FA0A17FEF52233D260C2E30C979
+:10EFE00025AEE749384F56C791DFEA48445E52BB29
+:10EFF000B4EFA4FF4DF6076819F85A93D0074740BD
+:10F000001DF3E2D6CDA97760FEC3A76D562F1FBFB3
+:10F0100082E4BD23E77907D2098648314FAA49CA5D
+:10F020001FE18F671A33AD6B03C378E9915246F83D
+:10F03000143F9829182F6811E77DBF9817F86A893F
+:10F040008DFC6EFC1C7B4FF7513FE633DAA9E94893
+:10F0500067058827FCFD27C4FB3B04BE1C29FDF186
+:10F060009A04C487B98CFCF793D5656B302E78640D
+:10F070003A233A690BBD9480EBC77130CFEF57B19B
+:10F08000C699F3DC1F6FC1F5ECB4D338658F815C92
+:10F09000043C197AEDD10FDE46F06D71EF8B67DD20
+:10F0A000F5E9118F695E044EDE1916B25119D2903E
+:10F0B000FFE49D39A0615C6FE85F777EF034C3792F
+:10F0C000B95C6812F86DE6AF3F7DFC170BD663B9EB
+:10F0D000636BC17B507E63CD839975503EB1E65B17
+:10F0E0005B6FF344FC9F3B662EDDDE02F521DFFC07
+:10F0F000FE93CF235ECDFCFEFF791ED73BF31F7F2F
+:10F1000076C1FA2FAB4F6448DF727DE679D259930E
+:10F1100082F14DE4A3C497AD01AA57078C7A7759C1
+:10F12000A9D3807FD8DF0AF02BABFB29C589D3C5D3
+:10F13000FB8766DCADA830EF7BD59CAF1C5CD5D9D6
+:10F1400032C946FD43D81FF824E55DF6EB0F6C0588
+:10F15000DFB707148C6F8382E4C5B86D06B4233F14
+:10F16000671E0FE93BD9127F055FC1EB0A8CFC7B60
+:10F1700056C2B33C115744FE8BFCBE6ED440E2CB6A
+:10F18000FD5C4CC3F32D7D618382F966EFFA3D5E31
+:10F19000D20B56B1CD93C0EE1DAAF2FC89BCD2773A
+:10F1A0006FC07381AD5AFD059171778ABCA6D217E5
+:10F1B0005C947FFDEE4ED736F2EB1F9869D1EB835E
+:10F1C000137FFAD1CF7E8BF8551D4FF865D65B0EB5
+:10F1D0000AFAE8AADB3C0FDF86FAFE8B0E6E27697F
+:10F1E0009E2CB2BBBD9E2CCCC3E9EAF77D191FF360
+:10F1F000FE19F9F9EC0A27C50D649C482DFDA411F0
+:10F20000E9717E716D11EAE399780EBD23F1E8F79B
+:10F210006EB253DE404049A0FCF25871E79DA372E4
+:10F2200044FCA5F60A5A07AB1D8DE5B9B9F50FDB0D
+:10F230003DB1E5558338D758ED363BF3478B0FEF9B
+:10F240001CC5F5D07A3C079BEE1C5C7FB801E3BC83
+:10F25000B1CE81598305942FE9700CC67C8E34F1B0
+:10F26000B8D5F983B7505E751CE6F22AADEEB355FA
+:10F27000487FD20F5195CEBAE2601ABC6713EFA552
+:10F2800009FD1B6918F5EF2A11FFE9A86414FF496D
+:10F29000AB3BFDDF089F8D62FCAA77F8F8766B68C0
+:10F2A0002FE24B95CB4372A7A34F9217EF27B1F3F1
+:10F2B0003CCF2493717C4C33EBF7A809E9D69D969B
+:10F2C00050F13B541FE68E672127E28FE2A079338D
+:10F2D00057C6517EAAD4AFD2EAEEBE551D61184F73
+:10F2E00041BDFADD0A6E3FA399DB356E8E41AF2238
+:10F2F0003DCBBC0EF95E878DB5A33DA9D3B3480FB6
+:10F3000063FA790619EAC22F66ACDBD2ED063EF14C
+:10F31000EEF9B25EB55C0E785247717F1CC243EACB
+:10F3200063526FEB36AEA0779D7E19407E21F321AC
+:10F33000BAF4A41A9D1D35B0FB7B32EF4C9E83843A
+:10F3400067ACF79D25DAB951941711A271FC6218C8
+:10F350008BD3954DF035F14B605B3C2F5EE8A1A05F
+:10F36000451AF211A45E29F97387E0BBE19C30F9DC
+:10F370000165BE777F78271BDE8F1F9DDC952F8F61
+:10F380007AD091551F533CBD0AF550983FBCE643D7
+:10F39000C37D92A69292F8D1E46F33E63DE8E2A8ED
+:10F3A000B45EBFE09B935517E59F74B0042FF2AF96
+:10F3B0008E80D0C7FEE4247D4CF20B337F98E1357C
+:10F3C000F2FF6B8B8DFC7F96D6DB144732FAB3CA03
+:10F3D0007DA6F8F63BD30C7C53F29F3B542F6DC2B5
+:10F3E0000A821EE334FB05BF7C5BE88176564BCF77
+:10F3F0001D98F73908F97F1B952E7680CA24D649C7
+:10F40000A59BB9294F268579A94C653E2AFBB25A9E
+:10F410002AD319CF8BCA646D54F66707A8CC669DB2
+:10F42000547A98DB82E540E6A57230F351E9636EC9
+:10F430008A7BBF9318CE3A04F09B7E3D233F3C630A
+:10F440003FB9518373EA2897754020A4ABC94C207B
+:10F45000DFE3376A589F26EB3B78BD84F72FFDE545
+:10F460004F7F141846FC46B43FC1DBBBEA3B6F2C10
+:10F47000213AB5507D0EF687FA8323B569A3015F63
+:10F480002B4733E2A3E70BB56FEAEB0F156A33F4B2
+:10F49000F5978BB46BF5F58F0AB459883FB29E5936
+:10F4A000A895E9EB371769E5BC3FF71FBD63D34863
+:10F4B000DFC50529A338BEE1CFA9FA2B090F7729AB
+:10F4C000563CD738416F763C4715E9C8EB88C3D224
+:10F4D000C7F377C2F1AEB0D3D283FD63A2A330F2FB
+:10F4E00027C0C3E18AFF665C8F999F280191079826
+:10F4F0006A8C8300BE93FF2CBC92DBE98C456F972E
+:10F50000F35E08CF99A6F3DB0E8C8C1B6B1F66FC99
+:10F510003D20F4BC8342CF7B47F899BBF61DB6264D
+:10F520009F7244E838B67D6865A7F4FCB2DBBE3F45
+:10F53000AAB4015D87EBE2DC28EF3AE2D9DB68A7E9
+:10F54000050EAB0CF58C4B5D6F69E1940708EEACD2
+:10F55000BF9BE20A725EC1673AF09FA0E75CDE4B98
+:10F56000DA975E078737B73B92C5BAEA27A55C935F
+:10F5700047F137AED70FB31D983515D699B681FB35
+:10F58000479390BE3114F6CC9FDC18176B9E6C61CC
+:10F59000C8A71A05FF34FBDF364E5AE1D6FBA71B7E
+:10F5A00093820AC6233343F1DC0F91CA82F12847C4
+:10F5B0004BBDA594071350DDA558AF6033F3A0BE33
+:10F5C000A045F594C2BCFB5A9E5B817ED84515765A
+:10F5D0008A4BD8B42914BF96F9182902CF1BD6C577
+:10F5E000794308C73E2EF2CF0E6B2C28457BB7DE41
+:10F5F000959282B89852B184FC87F52EEFEB784F44
+:10F6000023E0B6509E21736B8E32D057B6DD662D47
+:10F61000453E9EF5ECC82455B7EEE30D67E331CFC8
+:10F62000FD51B785DA1F5D39D1B1C485F711C15ECF
+:10F6300080729FFB9886FAFB56E89306E3DD5773CA
+:10F64000ACF9B21ECE31A9D46EC05BA7D7588F33A8
+:10F65000F91F6D26BDE0F06891F7318A8DC273BE47
+:10F66000E2C9F364FFCE7779C83F3EB149A17C97E8
+:10F67000F05E6F36EA9BC7EF1D42FEF0862655F816
+:10F68000A3BDE48F0E67B16CBCB753DDAC90BEAACE
+:10F69000367CB21ADF1B90E7C9C07106783B33DCB9
+:10F6A0003AFA7BF4FBDF8D4779D78017CF088F18A4
+:10F6B0008D23ED55793FBCDA7DB692FCBBCDBFF70B
+:10F6C00021FC93350BD1CC115B301DCF7F7DC96CF4
+:10F6D000A24BBC6F857A4C377DF47358A7EE9E41E0
+:10F6E00063EAC0049C3782BF1AF9CD4F3417927E6B
+:10F6F000B4BD6922E5F59BC7B967156B43BDB5710C
+:10F7000095A32D9AFE7B4FB62F1BEF619FDC58B25D
+:10F7100096C1F99FDC7B533ADE5B5FDC1CC7E23DA0
+:10F72000DDFB9FD8389AE65B8CF7A171DEE659764F
+:10F73000942B535B4AEC08B77B56CD7D563FCFC721
+:10F74000257E6731D09FB3F959C213170B0510AE50
+:10F75000BFB94ACB46FDE2442E8B9A97D9A798C7EA
+:10F76000177F7B958FEE999CCC8ADE2FA398C71FBD
+:10F77000EF2BF6487FF1DB4B53C91E7423BD1E6F80
+:10F780002A4C42BCB5611C1DE4A2ADFDFC2AC4FF9D
+:10F7900073150BDF5B0AED8DD3AE3B83E515F65A8F
+:10F7A000D29BD91F54A207D00BE9BED7DFE638DCC5
+:10F7B000F5BABC40D41F35835FC3C7D0FEB035A9AE
+:10F7C000213BF077DB9E53A48723BE6A3AFCA5DF7A
+:10F7D00028A1CF8B7C8FF451747F8E7E8DD75C17E0
+:10F7E0000C318CA32C74443BC7D8F3EBC645FD7693
+:10F7F00012D3E275F383540C915FDBCFE7EBEA277A
+:10F80000DAC10CD5687D422F37B7CBF50FD962A48A
+:10F81000CF6FE2F91445F4F358EBFD46D0F85E4D96
+:10F8200031137916330DF432546D5B3106CE8DBD34
+:10F83000CBF93FD875CC17255E15E1B3B0F6BE0203
+:10F840007E00CFB5A9B3C93E89B50E7BF080963353
+:10F850002262BF7D23DDB82ED9AF46E05D5C908586
+:10F860006C495886E85E461CBC8FF2FBD38AEFB821
+:10F87000AF894217B234F32DFC79F0BB11F2AC4CD6
+:10F880007C02D160B0D4472CFC7D4DC7E7123773A2
+:10F89000FDF7C41685F4DFF51B795EC4A741A89374
+:10F8A00072C1CF09558B2F84B2E3D2DD1F5CF242C7
+:10F8B000D37D433D06B82D62BA78D29927EF7A1BE3
+:10F8C000DB4F3F7D970F977B77EAA224CEB78E2E32
+:10F8D000C0794E5E6E277F0CFE1C123FA0E3D26003
+:10F8E0009C010FD7EF7E72CB02943BBB1D5E4CAFE9
+:10F8F0005BBCC5D81E97AEDB17E3F81530C0293CBA
+:10F900007016D0D191EFFF84EE792720FF447A5C06
+:10F910001947F7BBCC70FE6074D7F742983E0EC70C
+:10F92000C4BD0E4957C736D49F54619CB52BED1EFC
+:10F93000FA2E82C9FE3AE299A5A5EBE2BDF695FC46
+:10F94000BE25D3DB890323FB97E31E092C74785C67
+:10F95000DDC7EB867731C65B58A2ED2A06845D567B
+:10F96000E27B1ACBE31B16D2BEEBDA571E7913FAF1
+:10F970003425F87F867CF3D88641A314BCF762F562
+:10F98000D0FDBF86064B3CF2FDE6366BFC6084770B
+:10F990008385E47C735B6AC260944B2E0BC549512E
+:10F9A000AEA83AFFFE49C12723F2C397A4D77F121E
+:10F9B000043E9ECC13FACF24AEFF28CFEC21BDA38A
+:10F9C000A191C7A9A4BEE116F8E316F1C858FA0F31
+:10F9D000321E5C7762D12237F2B5C624FE1D8D45FA
+:10F9E00093BC01BC9779B58B91DC1880972350CFDD
+:10F9F00072B1E05498477573FDC6DFCC489F4971DA
+:10FA0000B9BC08EAB4966080D6AD713A73C07F087D
+:10FA1000CF843C8DE1F856935E6137E90DAAA9DEEB
+:10FA2000512CF250841EC184FE2DBFDB90786FCF25
+:10FA3000793DD2AFDB2CFC13A03F05E8FE47310B2C
+:10FA400022DE324DF3A4F68DD801E877C4F6F462D5
+:10FA5000B6AD5E177F52B457C96F20FD92D2FF201A
+:10FA6000FD1C238AC15E4BD2F9237E0DA6A54AF167
+:10FA7000B0CF104F72801D903D398C29FC9AC597EC
+:10FA8000D4D3EB2E2EEEF3A397F83D9F064B82774F
+:10FA90007B4EF77E19E3B8DF2C611FEC0DF5DAEB36
+:10FAA0001D749F66B2BA8BEECFB78EB4F03C65760C
+:10FAB000C08DFA40F218CE776F2FF1B9C7202377A7
+:10FAC000F972106F001E011BDEC3137EDBACDB0777
+:10FAD00026A03EFC5EC6A98DA897071A2DC46F24E8
+:10FAE0001C73565B36211AEAE273216B4124CEB6B1
+:10FAF000DE773680F77ECF5FC9EF1125CC3AB1179C
+:10FB0000FDA0EB065BC8CF7E77A246713BA01F87A6
+:10FB1000CAE375AF63BCADC9939282DFCF793A99DE
+:10FB2000B733718E0F24F6DDA6CF17E9BC92EFFB39
+:10FB30000125BABEB2F74ABECF8EDD00C85EE4D75B
+:10FB4000E2F678607F85E6D2D591F6E0FD1F06B833
+:10FB50003D3D6AF7FE8AC060B29344FBF90AB2E702
+:10FB6000D1C708ED1B776FAE40FBFC919CE8F3DE3C
+:10FB70003E8ECBEB47DEF00F407D36BC1BF0A75727
+:10FB8000B4F30D314B318D9B8D71A9F09D7173A331
+:10FB90007D8FE6CD719C9FB4425B5CAF881EDB5AC3
+:10FBA00061D65383C4AFCED51C7B85D2AE817F1482
+:10FBB000013D24B3E8FCF2C2FAAA371DF5CEFA3BA8
+:10FBC00095B5C83FEA415FC5B8609ADB4EFA6A4313
+:10FBD000F2774BF05CCED53037DE5BDD0E6A1FF27C
+:10FBE0002FF4ABE27DD4A9759CCFF8DDDCCF0A768B
+:10FBF0009CEF6AC4C70C2BE1A3D45FAD159CFF5CDE
+:10FC00001EC7F38B3B925DE4374DAEE3F9C4CE00E3
+:10FC1000E8B3B8BF493C1F5883FF900F49FDD63564
+:10FC2000CC6AC80BB69BF286ADA63CE16F8F31DA89
+:10FC3000338945237BD4AB7E0DF62FAE730FF01FB7
+:10FC40002C43600763F912D8ED58BE0C763BC60D05
+:10FC50005E5D9547E5EBABBCF4FCCD55C5544EC895
+:10FC60000E535C91FCC8E4BF612185FC7812BF5E35
+:10FC7000EE3F11F1BD84B76FFFD5CC4703FDA13D29
+:10FC800055F40FE45422FE75D5D9B595D8BF2A9DF9
+:10FC9000D79D636754223E4E9AACAD1B0378D2C702
+:10FCA000E2AB6EC4BE77C579A3D9F77DC7CAFB5E48
+:10FCB000D1ED77869F3A30FA735A894FC4F0E73C0A
+:10FCC000A0F075EC7D61F343E887EA35CBEA433C6D
+:10FCD000CE1E68F4F37F3E86D3C5D4B19C2EB3DF2D
+:10FCE00004FAE801EE923E62B5D7EF061488425757
+:10FCF000B26C4D64E3E99E75A57D6EB47CA66D8201
+:10FD00006FC61CDFC53C715744E8ADDE65A6B73051
+:10FD1000C577CFD57D672FCACBAF4E6F8CECC37044
+:10FD2000A546F23A0CF486FC5CADE1F4A65AF93D26
+:10FD3000CBAAFDDC3FB21DE90BCED98FF406FF9CA8
+:10FD40001AE0F53413BDD59BE9CD65A4B730D21BBD
+:10FD50008C971CE0FA85B3A2ED6BA5B73F7F457A7F
+:10FD6000FBCD5561CA6BE8C8A9CD40F8B48AEFDA7B
+:10FD70005D2A1DDE35D6CEE5C1708DFC020D388EB4
+:10FD80008BF4F90DF8BD94A9FD575B53007ED35356
+:10FD9000F3E97B023963FB0A7A38E0427FCD024DFA
+:10FDA000FB94E8EBBA33744FB18F85D36FDFB1AFFB
+:10FDB000913CC86A3C386B2AD2DD9D2AC949F3BE02
+:10FDC0006E1A2FE25B0A9F174E2E431FD77308BA95
+:10FDD000F4DC59AF38501FAF66DEDC1CFA3E0C7DF8
+:10FDE000B7E6870D7F73E3B8378D4FA1757956BF9E
+:10FDF00093ECE7FEB574B4DFE86A7241777A845F0A
+:10FE00009BADAF819E93C7F6E09FBD10FFB84FE852
+:10FE10000F78F4A837F8C53D4C19178949CF263F0C
+:10FE20006E4CFFE1700E1FF3FB67855CAD17FE5F44
+:10FE3000B3BE27F73FA4C43F0CF7A7B85EE57EE04A
+:10FE40003DCC83EB9471B3AE3C23A91F0658B01E82
+:10FE5000F56D2BA8327DB9BA81E375E51F093DF137
+:10FE6000C512FF681C771BF3EC45F9E6F2F27C053E
+:10FE70006789564CF0FC927AE086124D1BDB035EDC
+:10FE8000BD38459B34B628763B3B0FA38C8AC4B55E
+:10FE90004A6659395FA853041F70ADB543BD351983
+:10FEA000F89907F576BE6F37F00D0FD919463B620A
+:10FEB0000A3A23916F201F21E06AD3312F32498CF7
+:10FEC0001F91D7E157502F0D036C3741535280CB10
+:10FED000EBFAFD9CAFD881AF505CBA98DB09F29E7B
+:10FEE0008F739897EC2F55EBD97EB09AECFB256376
+:10FEF000051F296023116ED916CFFD63E079E183D8
+:10FF0000930F8D81C7450F2FEE8DE274F4B6C63284
+:10FF1000FC6ED74D8F9FDC867ED231FF15C7C4F7AC
+:10FF2000D128CFE05F2867E85CB6ED79B72260455D
+:10FF30007E151D8F0BAFE2782CE3AC3DE07123E121
+:10FF4000B188735E021EBB2E80C7CD884F51F078FA
+:10FF5000E357C4E307715C0D0F01E34653B41FF58B
+:10FF600084B75B276B8FF6D4AE8B1FF0FC21564312
+:10FF7000F6B38C5F9AD7D388F235B707BFD4BAED02
+:10FF8000F168CFD6D76C7F03BFDF585FC7EDEC8E2B
+:10FF900044AF03F38D03BF57E9BB54B1DE47BB3B0E
+:10FFA00000CC72E8553C0F7ADF9D71A109304EA656
+:10FFB0008BCBDB4C97C630EFDBEA0EDBFC89A8AFBE
+:10FFC000F918DA19F6540B0BE8FC3157D80E905C8F
+:10FFD000EE00398EF401F4C9E92D998F23E5F384FD
+:10FFE0003BEFC7480EBBAA13E4A08E4EDED85D4C93
+:10FFF0007EB8C4A2E757E07B6AA5DD83F83DE173D4
+:020000023000CC
+:10000000909BBA794A4013D1D7AF766418C699EC61
+:10001000CE31B44F4DFF86A1FD1AC0173BC5B1F9D3
+:100020003D3FA9D74CF3E41BFA258B38C737F3C6FD
+:1000300018C6B3AAE7378D46FA177AC438F80FE91D
+:100040005F35E90B667DC2AC3F9C1C6BBCBF32C206
+:100050002AF2D0AC3C3FA29539E8FB12C007E9FB7D
+:100060000555913C01A29311F6F0F67BD0AF32CF4B
+:10007000E10DC0B386DDD7A4578F8CF8CF5AEBB80B
+:10008000DFAFBEDDB10DE961ABA04B495FC3128F9D
+:10009000CD6324D7ED0CE5B1995E65BE93F41748A6
+:1000A0007F8252C3FD0CADE37378DE91E03FAD1566
+:1000B000DCFEFD91128A570671BAF4A444BE339750
+:1000C000CE94C0344EDF5A8A2855918F2AF35E7140
+:1000D0001CB4B3D3F97CEC759E37B9FA7BF8BE9BA0
+:1000E00005FA0B7F46564AC44F81F909CBF87B814C
+:1000F00069E2BD0122DFB2175F7F68B2986F049496
+:100100006AAD26FCD37E2AE3301E0EE540C59B80F7
+:10011000FE8F41AA8F022D4922BE9E29E2E94E257B
+:10012000C499C797E42357001BC5BC0496C2BF13EC
+:1001300032F1A72EA6127DD8B7A33CBAFBA8F77759
+:1001400098AADB90F8DDB726C0F3A6DFAB5EF49388
+:10015000DE9D15780FE9DA0AC81020BF96AF1ACFD6
+:100160004D9DE3704F85F7D4C0B6D518DFBDC21ED4
+:10017000DC4BE7B9268EE83D0CEF213E6C4D043A8E
+:10018000457C454FD7A8483E908C6384C7781D288E
+:1001900047C3D88FFB9B0DFECF28F926E42FB58AE5
+:1001A0007A836B3BE9EF6B53EDF8E54CCCEFC9AECE
+:1001B00043BCEC93C0EFD3321E371880FF18A4E382
+:1001C0005BEEE87E4DD0D7080EE1D54BD37BD2BB9A
+:1001D00062C6515C96903DE9E2E3288D375F170CCB
+:1001E000E9D629F7BDD6B55D59C02E657E668CA3CC
+:1001F000D4302D7E4494384A38A8E03A07D4F038F9
+:10020000CB00E1AFFFB2711475FC978BA3C8FDCE94
+:1002100010FF9E0E882DEE0D533C81CECB12599FC0
+:100220000E7E8F113F22DC102802F56B45FDAD5D7F
+:10023000073F7A12FEB97FE74BBBB0947ADC2CD132
+:100240003E73C8677B30776BD6BA15228E658C3FBC
+:10025000CC00AB4EEFE7C7FBFFFAFA2CD37A265A55
+:100260008D7182492E63FF29A9C6F6D2FE71DDCEBB
+:100270000DFDF2B45FA5FB7EEF76DEC7F877A374C1
+:10028000E7A05EB8EEC0BC398CFB78BAE3893E0EBD
+:10029000E07BD1CA524622BE58482FDD1A58BAB95F
+:1002A0001CE8672DC851CE8B3D06FA8BC43D4A35FC
+:1002B000C427E9EF8F454FC75C03C9FF3FA06E6FAE
+:1002C000DBA4DEAC2B0ED094E0FFC5958037035C39
+:1002D0006715D44306D4BD4CEDD7CD2BEA118F72F0
+:1002E000EBF6B54DD27D0F30D7EAB3A0FD9C5BF79E
+:1002F0002A3D8FA9CF77E72394B7962BF042E605E6
+:100300006EC5BC40807B6E8DF8CE6F4BCFF96F52BF
+:100310001E36E8F2FB2899C1A330FDF852EE75F3C2
+:10032000A733EEF795F375E5059AE6ED927F6E2E0D
+:10033000FF9C25FE0E845FD7BD0C718F03F61D3523
+:100340000FF4E49522DE143B8F8DDB9D735E7F0FEF
+:10035000C7BF64BB33C6B813B2C395D1EE47FD4DDA
+:10036000F8AD3AE2C359E837E8B045D7EB3F9E34E1
+:10037000E51F57F660C761DE2CC232D63ABF6CDE8D
+:100380006CF6180E2F196F95F9B3322FF642F9B3A8
+:100390005FD50F3F44F8033AAF64DCCF6F8A4398D0
+:1003A000D79B33AE2BFEE019D743FC41F67F2FC31A
+:1003B0001ED52F5E3F5EE049F7FB47941F0AEB4DC9
+:1003C000D5DB41F23D99976F1E0FECA2C2713A7FC7
+:1003D000A07F752EF9FB74F696CC8725FA68157EFA
+:1003E000882E3A30EB85221E62D60B657C44A9E04C
+:1003F000FE09A08F89E3FA70BD0BF3D2A59D27F308
+:100400004965DE28E685523CEA4BEA555FBB3DB5BF
+:100410007A32E575D5BB27BEFE55ECA9E5E38DF62E
+:1004200094DFC5FD0E7EB4A78677B7A79A4AFC373E
+:10043000E13999EDAA233FF890F263C10EBD99F01E
+:10044000EAABF209937FCA3186E3B794D3D29FB661
+:1004500077B0C5E0779DA2AEDC4BF9E235DCDF92E8
+:10046000A9B5919D6677D93DE86FB14EE274641BE2
+:10047000C6821A8FF3927F45E695A5B8B83D65F61A
+:10048000CB483B312CEDC400FFAE4AC77E1EB7758A
+:10049000A2BF053B9672B926FD2DB654E16F31E53A
+:1004A000633B4DFE15B3BFA5659CB0BB84BFE51192
+:1004B000C5730F92FA735B26FF1641F1F387163B63
+:1004C000D1D4FF65B0F19BC2DFF2A00BD6B7FB3DE4
+:1004D000A3BFC51CFF8A12F722E7D59BE3B653DC06
+:1004E0004DC257D2ADF46765D6F1EF024C51772972
+:1004F000C85F5A5D1CBE2AFAB35223FE2CE5998FC1
+:10050000BAFC52981FD73D4E5EFB06AED30A0C676D
+:100510007D34FF9680AB391E9554C7FDE35F973F4E
+:100520002B34CEE8CF2A78B0F07EFC3EF1C887CBE2
+:100530000E61396ADB777ADF0065F1E3F79761F9DD
+:10054000F737C239A8779AFD58CFE0C78CFB74877C
+:10055000AF198E124FFD35124F5D76A2DB0A0E47A2
+:10056000339CD2348EA7B980A7A02274E15F4732B2
+:10057000A7CFCC49DED7D1BF3660989545C3636B12
+:100580001DBF0F2DE1B855C031A56609F909CD7819
+:100590003AA0E5D2F0F38C097E3FDB52780FC2ED32
+:1005A000F987CA7E8BE52F82DF7122DCDA1FBBFF61
+:1005B0009B027E19F45D5C13FC26C580DF042FB717
+:1005C000AF274FF4FF1DF9F335C021D01FB2BDA9ED
+:1005D000C0618C0319F969DAD7E49F0A77F153F601
+:1005E00076EE25F0D32D26FF545A80D34D5AE028BD
+:1005F000D16726D0673CFAAB6AB81E09623FE8545F
+:10060000D0E6E6FC55CA35643916103E5BDD3CEE9B
+:100610001CC54F19A2EFF69AF8303A70F4780772B9
+:1006200035FBAA3E1179B7B586C7D15E9BE4F3E0EE
+:1006300073195773966839577D35FFE337AED2F992
+:100640001F014F69FF2AE03B7EA7FC6A902768FFE5
+:100650005B6BC236942B5575B72A7E285F1CCBCFB7
+:100660003F2DDDCF30CEDADD5F174E44BD7DC2E0D9
+:100670002E7C28BE4A870F57DC79EE7EF473C5C204
+:1006800087CC18F94A17C6878906F9DADA850FB5D3
+:10069000EB2E4BBD787C68477CE8A3C30741FF691C
+:1006A00035E107917EAD021FAC6EE063000F15F1DE
+:1006B000605824EE29E9212CF20FCCF0090706C579
+:1006C000C84358A114F7B0BE8BCE3F10F1D07A11B9
+:1006D0000FF5D7F17CD98E3BE3A618F30FBCB4EE2F
+:1006E000A9AE5A459FC71F254FB616CF4FC63965CD
+:1006F0005C73F244DF0AC49F0979FC9CC3B1E34CEC
+:1007000021BCDF0AE8E736E1F9F708CFE5FD03A1F0
+:10071000C7BD36495B89E38EB00729CF19F4BDD533
+:1007200058DFBAFB49FEDD5CE1879479795FD96FC8
+:1007300096640FE27D49E9376B4DB46FC7F3AE663F
+:10074000E1C9F4BD5E8C53A0DFE9DE38CA6B5CA85A
+:1007500080E10DEF7F7BA27F33D11FF3513EAE7F4F
+:100760008EC38D7A7E43F29474E41B556B5592EBE5
+:10077000B1EC1B496F55C06F88DEEA38BF4903FCF6
+:10078000227C0B28C46F3281DF70FEA331D4EBAC26
+:100790004877AEEEFCA6B507F85F24DF790AE11CC6
+:1007A00085EF3C83CF757CA70DEB5F16EE7957196B
+:1007B000F90DC60368FF485FFAFD9BF5D9AE7D1BB6
+:1007C000E94BD2DD7F009DFD19E11A85CE8E209E7A
+:1007D0007D053A3B1383CEDE37D1D95FFF4DE9CC9F
+:1007E00032BEE8C274B659E095CCDF967AC550B5F2
+:1007F000ED6C2ECEFFBF9CBFFD1D915F77A1FC6D00
+:10080000FC5D8CFFD49CCFFDFFFDA9FFB1FE54FF22
+:10081000F83E5FDD9FFAEB2B3DA4E79AFDAA0F8E11
+:10082000D66E1EDF831F4EF269ABE4D3C08F91F703
+:1008300056013F43FE9C56D1F9975F727BD3EBF490
+:1008400090BFE10E1C2F53F06B335F06BDB36EFCFF
+:10085000D7E1978CE16FF857F90D8788BCD20BDD93
+:10086000B71F32CE23FCAED1EFDDD70BFBBE1EC6C9
+:10087000C07B7A5BEFB4071B60C1FF1CCBCF674422
+:10088000CD75D72091FDEE267B42B807BB49FE3DD2
+:1008900088E655FE174EE4EAF7C7A2CAADAEFD9949
+:1008A000F464BDDDE4B904BBE9FF8E37EAC9D61AAA
+:1008B0006EE75A41DE515C5F2B0E21BFCE0C286DD6
+:1008C000981AEC4FAD55500EA6D5F8281FFE52E3EE
+:1008D000FA663C8A15E7FFBAE3FAE6BC817F9738EF
+:1008E000FFB1F1D1E3FCD2FF6A8ECB8FB037979284
+:1008F0007CADB4E05FB2600DBB3FD87E0F9EF73C8D
+:1009000007DDD330E703C48ADB8F48B1879D0363DB
+:10091000C7EFA5BFE0115BED1B68873FB2DA42E786
+:100920006BCE1B1896C8F3C75BC7AF7A98F27FA44B
+:100930003E5C21F84C9D6247FCF7570489CFF8B51F
+:100940009DAB319E9CE6626DA867B58FE7F4A2A6C9
+:100950006BC467AC157EC22B199FA8CAE6F7E6E206
+:10096000057EA9836BDFC2F1930FA85E8C6FDF8BCE
+:100970005D816724A2AC443D628C85F2225A945A70
+:10098000F27B342B1EFA3B1EC9C3DCA41F3D9DEC39
+:10099000FDC35CCA0FE57F6F64DFB4EFA6E3FAEE38
+:1009A0005EBD3A1DF5C08C093C1F71D3B453950848
+:1009B000675B1EE87F0A9586BF4B2BCB8F26F038EE
+:1009C00009F005CA4784756FA1F8FB603BF9D9545B
+:1009D000ED81EF201F502F9B4278DDACB8E72DC092
+:1009E000F3CAB5931ED3903B6AEE22D8D7BA3EFE27
+:1009F000A61C3CD7E4C1B4CF86E4BE49A88FAECBD9
+:100A00001A48FA6793524BED812C0BBDA78AF8FC6C
+:100A1000BADCEFBEBE18FD59D9FCFE674BEEA9D774
+:100A2000B15FCB18FEC76CCCEB55DDC67B52F8E14D
+:100A300023E4DF6A7F0BDD2F54455C5C35C59537B9
+:100A4000C87D8AFB2BF1826F55E5AE994BDF4F488D
+:100A5000B5BB11C91A13C3E5586FBCD3C6304EC716
+:100A6000ACCD063DAD7E95310E617519D7D3D475E9
+:100A70003FE1D5F9C8671A15510FFC82D7B19D9295
+:100A8000FEDAE623BE34C6F3FA35BF79723EC511ED
+:100A9000C5FA6C727D7DF8DF5BF97430A3FB6D5590
+:100AA000B670D4EF0B5F685DDDC7DDA48971D9FF37
+:100AB000E6B84DB93C4E641E57F6339F9B6E1EA69A
+:100AC0005CD23CA7CA09FF0EAB0CF98C793EF3FB54
+:100AD000F2BDAA3EB349DEFDABFAC782EBF2095D77
+:100AE0007FDF8575C52DC43D3B8F2E3E563F651477
+:100AF000DD8B6D556A896E02C996A8F9BFB1E947C9
+:100B0000373E0F8E10BFB5728833B52E9EF2382453
+:100B10003DC93C0F6BBA859E33311EF0E157491F2A
+:100B2000D2BACE8BB9FB46C6552BECD4DF7C8FD81E
+:100B30004CA7323F84DECB89B45BC5BCE6FC109782
+:100B4000C6BFB7D25AF900F9F32F354FE438D22790
+:100B5000C18D915DD8F05FCD942FC5DAF9F3867C15
+:100B6000377DE770BDEC97C828BF499E83539C032F
+:100B7000137691CCBB89969783F65CBA84B9870DBE
+:100B8000C67D36CAF73D3E0DF9E53D578CC8C7EF27
+:100B9000773EB873D313680F6DD9B5E67D2CE38724
+:100BA0008DA0EFA726782D5EBC9FE5BAB1BD1D399B
+:100BB000E4DA618B9BE938F5E74AF75315CD0DFD73
+:100BC0001D2ED776E4BFCCA1D077AFD41FA605D118
+:100BD0006E4D5F64C48356C5DB17FF3E6660A3425B
+:100BE0007A177E6F40DF6EF718EBC7262842BF34B6
+:100BF000DA31CD31EE750DD5B8DEAA9AEEB56EB20A
+:100C000079E8FBB99BD6A9A40F6C1271A5F1DADDC6
+:100C1000F357036DDFDEC8FF9E706B893D88F75385
+:100C20005B13DDD7CDC5BA907F32BEDDFC8DCB82A4
+:100C3000FABFFB9439C14378B8B1A46F06E371F0F1
+:100C40000CDFF0D878F165CBFF0132DEFE59008071
+:100C5000000000001F8B080000000000000BC55BB7
+:100C60000F701CE5757F7BBBB777924EA7BDD3C9CC
+:100C70009C8C6C56B6146490E5B56C9953B0A3BDCA
+:100C8000D3BF9371E9C5FC3333B67BC6C6214D266D
+:100C9000114E494C42AA333A59F21F84AC24953381
+:100CA0006D9AB30999CC8401259DB6860073024ADA
+:100CB000288144492990690684096E483313A7C1E5
+:100CC00089D2A1A5EFBD6F5777BB3A59B6E34ECF96
+:100CD000237FF7ED7E7FDFBFEFF7DEFB6E8DDAFF60
+:100CE00072DB7A007855361ED6B104154C3FF0E71A
+:100CF0000319FFD3F06F09007D857A2AC57B052093
+:100D0000FF810470F57115F2767BFCFB6E4718A02D
+:100D10008D6A63905A8DC5E48D1ED800E0B7DA5C09
+:100D2000234FB6AEA0F95E93E1617ED20FA94AECE3
+:100D30004B9F8E42393480135C2DFA284B6855F84E
+:100D400059017030B2F54734BCBBBD5DAAB969B377
+:100D5000BE85E681FEC966805551E7FAEC76A73A72
+:100D600070F13500BE1CE4BD412AF326B450396D44
+:100D70004A589EDBFE196DB3BEF03C3E281AB79E62
+:100D8000C603DEB75C4C3F7CEE853413EFFE8A96DB
+:100D9000DB01F73D74830AB25482CE8BD455253FD4
+:100DA00025E13AC7EFBDFA468800640EC9D088E352
+:100DB00078A345EDF02FF5D47A9809887564F87911
+:100DC000D2243E053BBCBC5FFAF89730FF0088DFB9
+:100DD000FA8177641CEF4B49553F8CEBFD526AEF6B
+:100DE000576EC17AF625D990F83DFE87FCBBC79AAD
+:100DF00003C626581EAAFCA2FFFE53F7BDF922F136
+:100E000028A9BE457403AD882E2BB830FD1B0AF30C
+:100E10003D183B3DB212E9901D293DFE1DD5FAA7B4
+:100E2000885E369D171AD77E2FEF9F9AEC5A57A8E7
+:100E30008F94A77798C887D180014074D8FF1CBFD2
+:100E400087F52897B50BF31329CAF47993BE62BBD3
+:100E5000AF759A7B4CACCBA770E96B00DEAED46F5C
+:100E6000DC8AAFBA236FED20FAEF097834E2A3DD14
+:100E70007FF0A817F2012204CE8B72B70566766C5C
+:100E8000C576D0E0653997236BF9F9EECA94E2C1D3
+:100E9000F2F3E60A9617BB7F1F7C59D987CFD77824
+:100EA000B557494EB211895684CF9180B8F4CD0A16
+:100EB00098412C7BF5B8BF1EC74D3E491301748481
+:100EC000C623E0016879E2785DBA99B6614E3721B0
+:100ED0007F4216BBAEF54DA73A71BCC19765E37E64
+:100EE000AC87027BB700CA91F4182E969E8720E744
+:100EF00043BE2B819E77E9F9A6B3005D45F2D4315C
+:100F0000EB87AEA6423D8E2317D73BFDB58EF6DDAF
+:100F10005ABDE3BD0CA691473AF5465739DA55B6A6
+:100F2000ADD768BD7DFA5AC7F31B9ADA1DFDA14BF8
+:100F3000393D83F58DF88FF82E83A8F37B5C77A07D
+:100F400019EB45FD1528AAE3FBBF352B2367AEC57A
+:100F5000CA75701DE911F2E5E411B23FDBFC06F140
+:100F600065D00BA7A42A20D5CF402B11DBD4234872
+:100F70003FC992D757CC7A960B29F0FC1F580E9F89
+:100F80009CF148C4D727A0F53036FA1B4D9FF2607C
+:100F9000932B6948EC1F4541D7914F0D385E592B73
+:100FA0003F3757623D0A52A60FEBCBB05D54882203
+:100FB000BC40EDFC70E00BA21D2CA3761A64EAB0D5
+:100FC000AE19504E7CADC3713E19E67E993EABDF43
+:100FD00055A25FA62A2CC66FA179D15C76637902EF
+:100FE0000CF0C9448714C04AB222FD5C5E45ABC216
+:100FF000E70F81D14AF5469861BB84EC97A87E053E
+:101000004C6AC2C8E785DD9E514267FCC2EE97D2AA
+:101010009782DE2870C6E607CDDB61FE80F4EFD64E
+:10102000DBDBAAD28185FB29FB9F75E8AD1AD79936
+:10103000CECAFE5ED61365FFF3FCFEEA78EA551AC7
+:101040008F48EF6F9D4FEF16350F64BFB27130328E
+:101050003844F6F1CDD15DC8DFCCE37EA3112E1F5D
+:101060003F2E960F39D0CA89AE72FFA5F2013FB864
+:10107000AFC029FF89C32C8C269F937F045FFEE7B6
+:1010800052F8E2E607DC570DD0BEB81DFD6B295FB4
+:1010900026AD647A98D1D602FDB19E5965D12B6CEC
+:1010A000F14316655EB69E2BE185F942E355870B49
+:1010B000FC598C2FD114BE6F2DF047EE379978F67E
+:1010C000B9EC83B312952B2483F9B5524E79A85EFF
+:1010D00021E52DD093633B1D048DF9B314FAB98C2F
+:1010E000786776117FB2FB71229447781F4F59C2FF
+:1010F00049D6B9980D24FCF5645F9B14C383F5E6CB
+:101100004A4F2A8774BC52813CEDAF56810CD9738B
+:1011100044063C7EF6713CADF09CC9E231EDA17E07
+:10112000F7FA7359A9307F8B65B77F54F94D6DA6D7
+:10113000B940E7D364BFD6087A78D8FE4CE6A97FD9
+:101140003409C6A03EDF9E61BB8C6CD9292A77D2B8
+:101150008B76A65B26887569E4FB7F209C41E3299A
+:1011600058AF88A77BE3354C770884D92ECD5478C7
+:10117000A0142E300957ECB2E6D9F6117D790AD7C2
+:10118000B96BC4F7168D07599F1317B8FBEB1214F0
+:10119000F7B7FBCDC995BBFF25EA01ECAFB9201C21
+:1011A000107F6C6315D179419C497A525DDC4FF018
+:1011B000498DA41977A8A42FD58B8FE375E1177BF0
+:1011C0001C2F0A2E8DE3B5F08B7D4EED85B35E6549
+:1011D000A5B54EA4D76EB03F11A6E74E8B7E7F46D5
+:1011E000E75590E8A9AB44A43D9052496E3F861064
+:1011F0009A70FC8A437B828C17A04B23FA48F9EB48
+:10120000E50FAEBD083A5A74DA997FD7AB935DDA31
+:101210005F096FDBEF5714DEFF76FB4D8CDBD101EE
+:101220006820FE5658EBAB38F5FE0019F5FB2BFE97
+:10123000F2E50E5CFAD0BFC8865C4FEF11CFE23802
+:101240006520CEEF0AD2535C77C59367FE9BDADB4D
+:10125000EFC17A4F2343D1B89E8AA38C672B82AA11
+:10126000CE38DB2567368E86F7050E0E58D42B1A3E
+:101270005722BC6CFB3D3CAE347FDED5163EC757D3
+:10128000F10F2E00CFBB713ACCE173F13E105085C7
+:101290009E1888738BE9B8809ED9EBB6FBD5A8A9B8
+:1012A0007AA3B9447F8B0FCD685708EF5D5107B91A
+:1012B00003B8DE91917DF10AAC1FAB01DD87AF86EB
+:1012C0007B3E2B11DE4844842885620217D21434F9
+:1012D000BFD79A2FF40BFD7013BEDF5B173070651C
+:1012E00070C5AF4C2D8EE3DC59E7374C7C9005F18F
+:1012F0003E13F3087F3203AF101EDD63F1C7FBA47A
+:10130000C099CC1BD4C399B8C0577B4E7D720BF1EA
+:1013100077347CB391C7767BD03E55131E1BF332D6
+:101320009E435CE7C0FDBE58110EC4BF3B8F7B1DC2
+:1013300075AF0B27BE19471C48CCB470E02FE320D3
+:10134000E6C582CE93CB350F04226C4F572BD31EAC
+:10135000ADC4396BF3C3C6DF4FD5083A7BDF1374D6
+:101360004187791F3DF7BD27FC3134E081B62574F4
+:10137000FA0BFAF9DA903EF4F43D711E604F5EB755
+:1013800089FF68DD6E3CEC73E161F77A6D3EC80958
+:101390000B276F800D441FC4E78C13ECFDB8F7F1E9
+:1013A00024FAE75D28144F0FF8B9CC0F685C3E3380
+:1013B00010E5F2B9011DBA10803D3FD0C4E50B0322
+:1013C000063F7F7120C6A54D87F9F44129C4FD5E13
+:1013D00065AD59699E4ED139BAB4CBC3AA70EC3E03
+:1013E0000FD3ED1CCA27295F10BD2005977855D271
+:1013F0009333692F96FF738525AFD7FACE4EF9B098
+:10140000FD682D18F763FF2B627B59CE369DF514CE
+:10141000F404C8CF2977C409E250EDA877FAAF7475
+:10142000B4EFD6563ADE87E3336CA77AA3D73ADA1D
+:10143000D97CFE3AF959B8BE635DA735A26B9FBE51
+:10144000CED14EB90FF9DF42FECFF58E7141DE628B
+:10145000909D0E6F77CA61D0C557F5AEF3FB41364C
+:101460009FCD84530F16E2AF5B5E6DBA86E7E82A24
+:10147000FCCA2CF99548D7B026E86AEF77D4DAAFE2
+:101480003DAF1213FBBBDCFE6590FCCBFA52FEE5D0
+:10149000CF2D3A2FE25F269DFEA59BAE8BF9977F5D
+:1014A0009E70FA97174ACF9DCB45DC2DFC92CC7EDF
+:1014B0008B9CECE773B07A5A367AC9245AB8AC924E
+:1014C0006C00B6DBD9A6E608671E8399289DE70F56
+:1014D0004A485594B7EA66A396ECCCA321E3D56DB0
+:1014E000841BFB3CC649ECF26CFCD628E18EA103C0
+:1014F00027A27858C103090FCF3B163FC3F10B4514
+:10150000078E5F6069E64AE013BBFD3D435E3E0F18
+:101510001EDCA1E6246CFF60A576EB36AA5BF32007
+:10152000414C7A3FD1F6A11CF929A309DD8A336524
+:10153000A2E4AF7C69C7865A3EAC14ACAFA6E606FF
+:10154000EBC9E1322D487E74768747A37DC9EBFF56
+:10155000EA33241F0F48FD871AC87FABF1009D1F97
+:10156000D9D086DA5DD84EDE893086EA3B36BC4E6D
+:10157000367BA2463FD440FD430D4CBFA18DB7FA48
+:10158000699ED1D0923E8A8F8C767B984732E18CCF
+:10159000208FD3743EBF47D68ACE77E0B805AF53CD
+:1015A0008E78F22A9D57843F82F3E37B87432A3962
+:1015B00005F08F895B4E641AF831DBAF2B2C3F604E
+:1015C000E78E84C9F68AF004D267A777A6A6D4B9B5
+:1015D00070D08A77CE9D3B51E77A4ACCC3B8401190
+:1015E00033F247B7E3B4F8C9DED893A373741C523F
+:1015F00049B29F998087E31D0BED5F0938E7B3C7B8
+:10160000E7F1648AA395996545FBD7ACF8EFCB0960
+:1016100089F1EA0F89EF6D62199125857529490FC6
+:10162000F7B3FD5794DB6D93240F16BDD1AF78BE91
+:10163000F8BC7D2D21E2B2AFCFC911365D52B48E18
+:101640008DAA359EC1718A35AEF8B59B3F171BBF79
+:10165000FEA5B59FD7B6DF745E3F7955CED9CFD7FB
+:101660000962FF56BCDB6BF1FF1A79721FC9E3FFF9
+:1016700077BCDBD77979E3DD6F937D229C8776FE9B
+:1016800061FC9EFD698EF5054E9D7D9BF57AD51218
+:101690000BBF40B4C1C68F2BA874E90F017DE4DFF6
+:1016A000F85AC4A5581FB7EA99D5625C28D6CB155D
+:1016B000E4178838CAB2CE95C2DF227B42CC558C63
+:1016C000E544D780F29D8C86FB280F1C831096BEC4
+:1016D000C8AE0C951DCBF5D118AE6B7C9587CFAB02
+:1016E000F1CAF489215AFFAA4049BD68EE14F66F89
+:1016F00084E495FD24303DA46F92AD1C90F6209FAC
+:101700002640F0D9EC0CF17A146D2C7607CA4DCC3A
+:101710009207DC0FF7778FFF611ABFCD31FE374894
+:101720004EB3D6E034CE2E1C27DE29D97A95A1F708
+:101730007E6B3EBF3E16235C90E8D4C47B65AD4112
+:10174000FA301E2A3D5FC29A0F2814B3A1808FAED3
+:10175000D82EC601BFE8FFA07476DBE9F5CC57D6DA
+:10176000275A07BDAF309CF6C13D7E5993D3BF5178
+:10177000EB9CED5373FB70FA450F48A5D77BB7D5AB
+:10178000BE63B99033928FFB4BC8875BDF558A7B72
+:10179000E2B869E207DB0F617702CA7482FC9D4000
+:1017A0003318834CE029DE6FEAA9865333EBC9CEA8
+:1017B000070DF283143F9ACAD6829FE8DEF7627E55
+:1017C0009EA240C6DB3ADFDFC371CDAA5671CE645C
+:1017D0008AC6FB8C252772B13F584FEE887E23EDD9
+:1017E00073EC90CCF1A5B17B7DDB4A9DD3F726CE7F
+:1017F0009FD7399E423F829CD4C78E1EDA8DF5DF7B
+:101800006A1ECDC76DF492791DCDAACFE57552172A
+:1018100096D719EB0AF7355C4C5E678171E7CEE32A
+:10182000F9799DE39D48A76301915F99CBEBDC1C9F
+:10183000B9A0780E58E772D8B2CB957D961FB15FEC
+:10184000623FE299B67F3FB286E4ACCDCB720047EF
+:1018500027A0584FB66CD7BF5A4DE7CCEB3E681463
+:1018600076CDA4F16CBFD8A69F6A8D9FF8F64B0A7F
+:10187000B51FAFF56CE0F120EFF344793DAA55CAEE
+:1018800054AE51F372158D1B06439C0F79899EC788
+:101890009158C5FEC1E8EC4F3AAB284E1200834C7C
+:1018A000D0685C3B50455F280B4478A75ECF91BD64
+:1018B000EDF45738ECFF689F2AEC6B23FA4BA43FFA
+:1018C00053FA57F760FBE1FD658C9B1EA8F308FDFA
+:1018D000CA4839A99EF0B5D3EF199F5C21F0D851C1
+:1018E000AFD188ED1F9914ED77C737E464C6DD4E9C
+:1018F000BFA84F77FA45BB6B5B5F25BC08435E8E84
+:10190000C76B16AEBDA1C9E92755D6F7BF403865EC
+:10191000E790C0C307A3E125BBD1FEADEDD21D7991
+:10192000B25D437772DE684805CEA78EEE50593F10
+:1019300046BD6F1DDFCDB8B19CE938B143AD4D1741
+:10194000E9CBC7BA7C3CCEC40E813F105EA6274BC4
+:10195000BCFF589765A714E073DC96973FF9B8A0D1
+:1019600073B00E723AE1B8BE7D79F22BC7EB704FBF
+:10197000F87E28DAD03745F3BF2203EDD32D87F761
+:1019800090135CB40F5FCCE3A093D797EAA7F1E183
+:1019900006D0C9AE7525B14E7180ED2A507CC017B6
+:1019A000FD0BDE6F18EB6558F727C7320AD6FD0D21
+:1019B000E975848B9FBDF7B6917884CE3BA1DFBEDD
+:1019C000ED7B533751FBF55E28A3F5812E45697DEC
+:1019D0001909449EDFA90F07B3FFD4457C3A684834
+:1019E000CCA29D7D5BEFA2F59C8B94336E1AF3A67F
+:1019F00076B13DBAC5AF65F80C9C613FC2FB051FCF
+:101A000090DC4DDCFB4E0DE1EFABBA56B0BE95E974
+:101A10004EFFDA0F637C6E6F34A7B753BF8D3195DD
+:101A2000321EF04CFB19E6DB449BCFF0E13A26DA9C
+:101A300025A6F3EFDABC399AE769755AA6799FFEB5
+:101A40001DCE5D5F4ABF4BEB95AD47EEF6A3B1AD42
+:101A50007E928B83307D33D127332BE254EE76DFB9
+:101A6000B0E4E060F6962685E3592AE7DB95B38675
+:101A70005985A3876653DFA2D8EB2B9D0AB7BBA776
+:101A8000D6939170BCE13E95F568B8323D42F23C88
+:101A90008C72CF7E5204EBA467B511E370D17CE366
+:101AA000EDB736913D7BB9AD8CF1FD6BCFD6DE91B4
+:101AB000C12113F2AFFEEE31F2ABEA54E6E7B0B764
+:101AC000FF75F283326D65BCDEE796A9E0277B10D7
+:101AD000B9E321F2B3E191ED502CAF1349A1A71363
+:101AE0007542EFA5C7B6B31F302EC94C67B3E6A445
+:101AF0004478CC97B4E34E22CE14B7CCD9C4F6EFD9
+:101B0000721C6A699F88A3C69356BC490E64582EFE
+:101B1000AF2B7B88F4DF54BC0EFF78D359A7BFBC32
+:101B2000D4E52FBBE3515BBBAC78841577B2E532CB
+:101B300068B5998859767ABD2F27E4B0BF566B9E59
+:101B4000AFDF3FB4F0F3F4801F2502E027031AD77C
+:101B500083E66F0E54139F06A2FCFC4F379E908ABB
+:101B6000FB8DAEBFC5AFB33D9989D2B86E3BE2964F
+:101B70008B373ACB1DE789BDCECAF60410EE3D7710
+:101B8000962D326C0ACC74F2D908D38162BC9FA71F
+:101B900075FA284E26D6F91CADD3477132B1BE175F
+:101BA00006742E5F1C68E2F23B5D20F201B67DB840
+:101BB0000AED03D2A1AB4ED4C91E10FFC3913B382E
+:101BC0004EE68B2A1AE9BBBF6E2C2F15D98789CA1E
+:101BD000FE9FDE4976BF26C0F2E8DED7B1AE397C83
+:101BE000E8D8D7CEF67D6C77CEE13C447FB433772E
+:101BF000B11D42BBC0F36E576FE775986897D82E3A
+:101C0000F47FF536B60B5E203977DB817046E877D6
+:101C10005A17F13BFB9ED09C5DC0797238CF336878
+:101C2000D7A93E8C7680E6196E7FEB1334EFEFFE7A
+:101C3000500E34C4C48E57D92EBC7C0EA0FA32DAB2
+:101C4000055B0FD73DF71F27324A293E6FBDED9444
+:101C5000A0870682AEDB5225FCC48BE5339817863D
+:101C60006372CACCED22EFA8321D16CC3B663C064F
+:101C70008505062795A4957704CA3BDAF9C7A2BC67
+:101C800063B933EFA8E6B28C6F7256DEF1D6CD227F
+:101C9000EFA896CF040AEBB0F38D43F4A8B6909F5B
+:101CA000FF87AEF4CB5D6D853CA32E893CF8D571E2
+:101CB000F387F41C22613EFFDD794A3B1F89F04E19
+:101CC0004A17E5375BF0B93F5CC87FB9F399F6BDB9
+:101CD0008C1675E6E411A4CBE0ED7EC60FF6FA068D
+:101CE0001FFFF0EBE948E13E809DEFB4F39976DE0B
+:101CF00013D7FD4EF1BAE14960BB034FF84FD0F95D
+:101D0000E65E6F453CFD4B6A3F6FDD17985FDC0276
+:101D1000D6F888BB489FDFB4E838D7BE4BF89F6B36
+:101D20005411DF86A0CAFE4EE2DB0190096757AA74
+:101D300027492F76C14C37D1773024705EF6012FBA
+:101D4000DB49E8D6997F35AAC9F7216A3E5F661C50
+:101D5000C0C7D9292D48F1A7AF759AD0DD46EB1839
+:101D6000BB792BAD03713BD9BB371ABF12E17C3F66
+:101D7000DD7BAA22FFCF584E7110BDBBF47DA58E2E
+:101D8000E567B7F2BC951E20FF2C5B66BCA013BDB7
+:101D90009F5278BC3E1CC26CE5FB4B5D6A98C61135
+:101DA0007EF260E034F3ABA3D1B796E37A95A5FD5C
+:101DB000C0A5DD820E9B712C15C7792A9EAEA57534
+:101DC00053AC34CA722CFC3BBD1B6CFB759F674344
+:101DD000210E5621A7F56EB2D78F480A9D8F3E4B34
+:101DE0006E6C3FB13B61D6770B7E9834BF7D0FC8D8
+:101DF0009EFFEA6E61175FE9323F44EDDA681E929A
+:101E00004B2D13273D6C49A33C48AC3FAE3CBC90E6
+:101E10000BB7BCDAF2369787B7E450D244BE16E56A
+:101E2000AA8DF6074FEB531E89F2EDE91347A8EF91
+:101E300025E6BB3F9D3037D1BA77C7531D54BE71DD
+:101E4000EF6DC0799D0BBCC7D1B1BC3F4A79FCE1B5
+:101E500032819B1F8D1B0E7B77B7459FBBBB055EF9
+:101E6000BA1665669AF44031AA80F5F82EC6D1B646
+:101E70007D1A1B487FEFE78D85FED90198A47CD0A1
+:101E800042EBF01EDAC771DDC1BA849FEC0FDAB7FE
+:101E90002AAA0FD799D1E275642B859C679689B8D9
+:101EA00005C5D332BEC2FBBDDD32EFA7B30EF224AF
+:101EB0003BBE80C8BBF95071753C7F7C662CCFB8A7
+:101EC0002600931462F814E90FDDFF8B186092BFAF
+:101ED000599702D26F9F56E84F79D4CEBA7EBE6F23
+:101EE000B9D03872D4EE9FE6FEE3DD1A8FAB463CE4
+:101EF0008E38C0627473D36588E8D6B830DDD40BF1
+:101F0000A69BD03B37BD0E13BD909FCF863ECBFB2B
+:101F100083F73B59CF7C1AEE13CB31CBBEC80113EC
+:101F2000D29564A352882029CEDE0F9487B6E92C7F
+:101F30006B82CEB2D6CFFD7C7506A457135DD24C12
+:101F400017371DD04E00D9897F7EFC7884F0690751
+:101F5000D6A3C27E800FCB5F5BFEA0ADA75BE0C7C0
+:101F60000111FF769E17F3ECA9553E6AC59FDDCFA0
+:101F70006FE92913B84E0707DD2B2BB7323F4E8E82
+:101F8000B4323EC0F33343F7627A6A1BCBA97EB901
+:101F9000F388EEFCA13B4FE8CE0F16E4C6F4D33A2B
+:101FA0007FAB9DCE7CB484BCD8E5114BDF8606FCAC
+:101FB00025F5EE08EA3BF16FB8DDCC50DEE860684D
+:101FC00026CA7233F52EE362E525D9207CA9288242
+:101FD000CF3DCB66988FBD311328DF746460DB770B
+:101FE0008AC7FD753CFD23B26715DAA449E30420D6
+:101FF0009FA1F36773B5D95F0A37FD9B6547BA1395
+:10200000A97F257BD5A10BFEC7E2E6AB6C172FD0CD
+:102010006E2DA44F8A4DBB8BD6A7D3429F62FB582F
+:102020009F46EBFA19678DFE58262455C091963EBF
+:102030008DB69F617DB7F5EA3D4B9F3A63422F28ED
+:102040008E40E777B0CE64BBF15F963E29A827A407
+:102050004F3E4B9F825AA13DC5C73B89CEF85CA934
+:102060009BE17EC198A57FA44F01BA3F0C8C0386EB
+:1020700051EF282EE2D6AF8E06716E6A89B4A7871B
+:10208000F0C5B2AD1C971FAEFBCF6AC62F96FC17EA
+:10209000F06E2B9FE7E7463C06E9430B01E8D6824A
+:1020A0001ED8FBDE382B431E59B36956E2F223B328
+:1020B000155C76CC967169CE5673199F0D719998FF
+:1020C000BD92CBCED95A2EBB66510FD621DF67EB1E
+:1020D000B9EC99BD96CBDED9555C2667D771BBBEEE
+:1020E000D9B55C6E9EBD9ECB1B66DBC53C4D625F69
+:1020F00025F481D26097411F8C0C54921E7CFC7594
+:10210000B6EF9ACA7794B2A10D9C27F22933AC0F8F
+:102110002763C2DEF706049FDCFAD09D48AF25BADC
+:10212000BBF5610EDF2AA011FD55B03E2EFC80F8F4
+:10213000A7BDA7E83EB21A3559CE109F7CB887F4E8
+:10214000E31271C21CCE5CAE321EB571E6E832C439
+:1021500099F5059C39DC2EFCB2EC033EF6DF764B9C
+:10216000E27ED9A713E91B7BD82F1671A2F4CD7E8E
+:102170008D707336D4130D505CEFA00C142F401CDF
+:1021800092E2764A4ADC67BD407D8EC5857ED8EDF9
+:102190005BE0B4A7FF2270CC1BF4B57D61BB10BE21
+:1021A000D473D6DB29EC8226EC42B6AE7F84F3D220
+:1021B0002EBB609FB3480F875DF85C8F854B2C3D2D
+:1021C0000FD789F3324C7601E9F3C51EDB2E38CFE9
+:1021D00059C5C621491B8758762129FA216E779C5B
+:1021E000B3C86E3F14E16294A3C19EB6F9F681CFE5
+:1021F000F3A2736EB0A1314EBF25089D8538896763
+:102200007056DF6C943877B25A2BEBC194D209C563
+:10221000F1958BD6B3907DEE987CEEB8DBD9FA368B
+:102220003CD527F6699D4353B87FB348DF7A3571B3
+:102230001EE1F9F3F59E12E74FC772339D2AB1CE26
+:10224000477B84BFF1834D16EE455C690418DF9728
+:10225000C40D8FF608BB4EBFD37802ED4F77329393
+:102260005574D6F34749CE37764DCB1446F8486CB3
+:10227000EC154A89A09E3EF6C7E8E9D1B895EFDB98
+:102280005F2D2E3B5BE562F26FE3225B0FE6EDA371
+:10229000DEDC568A1E4B7B05BE1F1CF1F4D1853F48
+:1022A0005B2EA694958C7F4AD85BD3B82CF6F6C2E9
+:1022B000F0C7149E83C4F7F3E08F374BD9DB85F06A
+:1022C000C7991E912747FCF10EF5EB6816F8636974
+:1022D0002FFCDFE08AF869A6DBA5E28A0F6CFBB170
+:1022E00000AEF0F6EAE27715DA0CDB8FE025E20AC1
+:1022F000B79D40FC50DE4BF431C4B96BFFDE842F38
+:1023000050169D5F6867AA7A055ECFD3E5B19381C9
+:102310004446623D4885E8F998B982E5E872E903E8
+:10232000E2C42B7B8BEA8BE9C505B79BDCC171400E
+:102330003B9FF9FBB2600BC547F6FB45F9B9F2E0EC
+:10234000492AC707441C7A94E27E588E7B81F307A2
+:102350004352B97152A27ECB7322DEDEBF86E29E6B
+:10236000D7F786AD7872FF75FCBB1BF8A2236FBA56
+:10237000F0BAC43D5F1AEA03BE0F5EA7711CDDA26E
+:102380004B981880F31E5EE5671C78B8EF91E377F1
+:10239000505CA64FC4C140D1EB3F4AE72FC29A58C8
+:1023A000D1B920837286E2F32374B79D41C7367199
+:1023B0000FDA5A4F7512FDF722FFA32A76D7F77E60
+:1023C000EEBC37E429CE231F31B75689CBCA77F14B
+:1023D00038B69E1C094CFAB5227B7374C079FFC9CC
+:1023E0005DCA6DAFF07DC3634D0AE72F1E581F29EC
+:1023F000233D39D42082B4E58D9E54AE843E0FF443
+:102400004A8EB876C83AE7CBBAC5BA169A6F784002
+:10241000C46FEDBA4F4F9924A7E5F56329A26B79F4
+:102420006344A2F8ABFDFEF65E61370E4B46BE0379
+:102430008979B8529C17BEBA0C78080F84F6AE237F
+:102440001AFBEBFAE14C80EE6F64E06D2CC3613552
+:102450005D6ADD83D6BA0F7B7329C2538757299CE7
+:10246000E7444C55324EF609CB4E97378EF3FAA01F
+:1024700051E17C95BBDD0EBB9D3AC6F98E438DDFE5
+:10248000D4695F87E807374B914BC9871F3A40767D
+:102490006600F9EA25794E73597ECDB798FEA32DD3
+:1024A0008A46FBE8969B0FD03CC79260105E71CBCA
+:1024B000C531D0CA687CB77C54AC7E8FE34FE54110
+:1024C000CA8C901CCEF8851D157216B0F8336A8838
+:1024D000BCCF684AE4AF6CFE15DE8BFB06E7520A00
+:1024E000FB2576FE6A0940491C67EBE590158F9F36
+:1024F000F77E799ECF9DA39BF251BA2711D4FC465B
+:1025000092C67DC4B9AE837876F2BAFA44FE62CE42
+:102510003EAF15FEE1FC758AF881F2CCBBC2AE5A23
+:102520007E42B0F93DB6ABF6BDAFDE8D425FABACDF
+:102530007BF755919429E872B7C31E48D7FC224314
+:1025400079A6076BC5DD84F04671AFB65C05234FF5
+:10255000F700FA027CBF6949CCCAD76D13F72BECA0
+:10256000FBE16A4475C41322505427DCE9AA83BCFA
+:10257000FDBCF7E0F6FFECC48BCF15F1FDA55EE7DF
+:102580003DF2C5FAFF7E20F7E27368908E19E7D717
+:10259000479B6F5F1E887169CBA52DA761DA62EB3F
+:1025A000C2FDC743A992799A6052E8C362762DE2D0
+:1025B00033DBDF41BE7BAB81F3675FD9E41CEF37D0
+:1025C00096BEFEC6D22F7539D4129E1A0B093B3027
+:1025D0005606DBBE5B426F972455B61B057D70E245
+:1025E0000A5B8EE6D363115CB1BA4BE00A2D5C4600
+:1025F000B8E898917881F281EF69AA5E2CB7EEB8BD
+:10260000BB8D2BD2493BFEA74A840BB4C00CE3ED33
+:10261000395C60E108372E28F7E6B6917E94AF5218
+:102620006D7BC576E5F3DFFFFB8732BCBF8C547C46
+:102630008E8EE66FE771C3AEB83B449CBF63798B67
+:10264000F017AE27AC4F4E2728FFB84511BF6F1BC0
+:1026500033A1F81ECEB8E7FDD83BD6F7F76D1C5274
+:102660004FEF8F4EF3EF6BE01E289EFFE04D3BF9DE
+:10267000F7148BF1DF5E17DDEB2AD69F8BD50F2386
+:1026800069E9471994917E9C83FB380F0F6349C712
+:10269000F9C41989256C12C407B7A96CB0A082547B
+:1026A000D01BE8B5F2E3E9393BA9503FC3EA564BEA
+:1026B000B72C64CA37E4F9778BB6BD39073FE379A5
+:1026C00033CF48D21CEEBA12DD7FFA3DE44A5A827B
+:1026D000E6A1D2BDFE1560F0F3064871F921E8E7E6
+:1026E000B209C6B8BC0626B96C86692E5BE02C9789
+:1026F0006B419769927560CAC05737D35CBF0E3281
+:102700005CB643BA9DEE970FD5EC5D4BE7D12D2E0D
+:102710003AD9742EA1F78C2B6D7AD8742F27E35DEC
+:10272000B3385FB321618F3B6379F61F0201819B50
+:102730006D7FDB1E67211C7CB9F09A8D33FF17CFAC
+:10274000A588169043000000000000000000000073
+:102750000000001800000000000000000000004021
+:102760000000000000000000000000280000000041
+:102770000000000000000010000000000000000049
+:102780000000002000000000000000000000001019
+:102790000000000000000000000000080000000031
+:1027A0000000000000000000000000000000000029
+:1027B0000000000000000000000000000000000019
+:1027C0000000000000000000000000000000000009
+:1027D00000000000000000000000000000000000F9
+:1027E00000000000000000000000000000000000E9
+:1027F00000000000000000000000000000000000D9
+:1028000000000000000000000000000000000000C8
+:1028100000000000000000000000000000000000B8
+:1028200000000000000000000000000000000000A8
+:102830000000000000000000000000000000000098
+:102840000000000000000000000000000000000088
+:102850000000000000000000000000000000000078
+:102860000000000000000000000000000000000068
+:102870000000000000000000000000000000000058
+:102880000000000000000000000000000000000048
+:102890000000000000000000000000000000000038
+:1028A0000000000000000000000000000000000028
+:1028B0000000000000000000000090000010000078
+:1028C0000000000800009008001000000000000256
+:1028D00000009000001000000000001000009DA803
+:1028E00000000000000000080000000000000000E0
+:1028F00000000000000000000000000000000000D8
+:10290000000000000000000000000000000091A096
+:102910000000000000000008000093C00001000457
+:1029200000000001000093C8000000000000000249
+:10293000000093D00000000000000008000093D4C5
+:102940000000000000000002000094980000000059
+:1029500000000008000093D80008000000000008F4
+:1029600000009B3800400000000000400000941868
+:102970000008000000000008000094580008000053
+:1029800000000008000094A800C8000000000098A3
+:10299000000096380098000000000028000096789B
+:1029A00000980000000000280000C0000540003032
+:1029B000000005400000CB200008000000000001DE
+:1029C0000000CB21000800000000000100002008EA
+:1029D00000100000000000100000200000000000B7
+:1029E0000000000800009D600008000000000002D8
+:1029F00000009DA000000000000000010000000099
+:102A000000000000000000000000000000000000C6
+:102A100000000000000000000000000000000000B6
+:102A200000000000000000000000000000000000A6
+:102A30000000000000000000000000000000000096
+:102A40000000000000000000000000000000000086
+:102A50000000000000000000000000000000000076
+:102A60000000000000000000000000000000000066
+:102A70000000000000000000000000000000000056
+:102A80000000000000000000000000000000000046
+:102A90000000000000000000000000000000000036
+:102AA0000000000000000000000000000000000026
+:102AB0000000000000000000000000000000000016
+:102AC0000000000000000000000000000000000006
+:102AD00000000000000000000000000000000000F6
+:102AE00000000000000000000000000000000000E6
+:102AF00000000000000000000000000000000000D6
+:102B000000000000000000000000000000000000C5
+:102B100000000000000000000000000000000000B5
+:102B200000000000000000000000000000000000A5
+:102B30000000000000000000000000000000000095
+:102B40000000000000000000000000000000000085
+:102B50000000000000000000000000000000000075
+:102B60000000000000000000000000000000000065
+:102B70000000000000000000000000000000000055
+:102B80000000000000000000000000000000000045
+:102B900000000000000012C800800000000000805B
+:102BA0000000000100000000000000000000A00084
+:102BB000071000000000071000001EC80000000001
+:102BC000000000080000AEC000080000000000087F
+:102BD0000000AE4000080000000000080000AE80C9
+:102BE000000800000000000800002008001000009D
+:102BF000000000100000200000000000000000089D
+:102C00000000A01007100040000000400000AF408E
+:102C100000080000000000010000AF4100080000B3
+:102C20000000000100001ED00000000000000001B4
+:102C300000001ED8000000000000000200001EDAA4
+:102C40000000000000000002000012B000080000B8
+:102C5000000000080000000000000000000000006C
+:102C60000000000000000000000000000000000064
+:102C70000000000000000000000000000000000054
+:102C80000000000000000000000000000000000044
+:102C90000000000000000000000000000000000034
+:102CA0000000000000000000000000000000000024
+:102CB0000000000000000000000000000000000014
+:102CC0000000000000000000000000000000000004
+:102CD00000000000000000000000000000000000F4
+:102CE00000000000000000000000000000000000E4
+:102CF00000000000000000000000000000000000D4
+:102D000000000000000000000000000000000000C3
+:102D100000000000000000000000000000000000B3
+:102D200000000000000000000000000000000000A3
+:102D30000000000000000000000000000000000093
+:102D40000000000000000000000000000000000083
+:102D50000000B00000180000000000180000B300E0
+:102D600000400000000000400000B30000400002EE
+:102D7000000000010000B30100400002000000005C
+:102D80000000800000400000000000400000000043
+:102D9000000000000000000000008000000800406B
+:102DA000000000040000800400080040000000044F
+:102DB0000000BB0000280000000000280000BC400C
+:102DC00000100000000000100000880000800000DB
+:102DD0000000008000008800000800800000000261
+:102DE00000008C00002000000000002000002008EF
+:102DF0000010000000000010000020000000000093
+:102E00000000000800001108000800000000000891
+:102E1000000011680008000000000008000011A870
+:102E20000008000000000008000012700008000008
+:102E30000000000100001271000800000000000105
+:102E400000008D00001000040000000400001320AA
+:102E50000030001800000010000013280030001897
+:102E60000000000200000000000000000000000060
+:102E7000000000000000000000000000000011E859
+:102E80000000000000000001000000000000000041
+:102E90000000000000000000000000000000000032
+:102EA0000000000000000000000000000000000022
+:102EB0000000000000000000000000000000000012
+:102EC0000000000000000000000000000000000002
+:102ED00000000000000000000000000000000000F2
+:102EE00000000000000000000000000000000000E2
+:102EF00000000000000000000000000000000000D2
+:102F000000000000000000000000000000000000C1
+:102F100000000000000000000000000000000000B1
+:102F20000000000000008308008000000000008016
+:102F30000000000100000000000000000000200868
+:102F40000010000000000010000020000000000041
+:102F50000000000800008D100008000000000008BC
+:102F600000008D7000080000000000080000845080
+:102F7000046000280000046000008EA0000800002B
+:102F80000000000100008EA1000800000000000108
+:102F900000008408000800000000000800008448C9
+:102FA000000000000000000100008DF40008000097
+:102FB0000000000200008DF6000800000000000282
+:102FC00000008E040010000000000004000000005B
+:102FD00000000000000000000000000000000000F1
+:102FE00000000000000000000000000000000000E1
+:102FF00000000000000000000000000000000000D1
+:1030000000000000000000000000000000000000C0
+:1030100000000000000000000000000000000000B0
+:1030200000000000000000000000000000000000A0
+:103030000000000000000000000000000000000090
+:103040000000000000000000000000000000000080
+:103050000000000000000000000000000000000070
+:103060000000000000000000000000000000000060
+:1030700000000000000030000040000000000008D8
+:1030800000003008004000000000002800003390DD
+:1030900001C0001000000008000032000020000005
+:1030A00000000020000037200000000000000008A1
+:1030B0000000102006200038000000080000A000DA
+:1030C000000000000000200000003EA900000000F9
+:1030D0000000000100003EC80000000000000002E7
+:1030E00000001C4000E00008000000080000000094
+:1030F0000000000000000000000040000008000088
+:103100000000000100004001000800000000000174
+:103110000000404000080004000000020000406081
+:103120000008000400000004000040000008000047
+:10313000000000040000400400080000000000043B
+:10314000000040400000000000000008000040486F
+:1031500000000000000000080000800000000000E7
+:1031600000000010000050400001000400000001B9
+:103170000000500000000000000000200000500887
+:1031800000100000000000040000500C00100000BF
+:1031900000000001000052C7000000000000000114
+:1031A000000052C6000000000000000100003000D6
+:1031B0000030001800000004000030040030001847
+:1031C0000000000400003008003000180000000279
+:1031D0000000300A00300018000000020000300C2F
+:1031E00000300018000000010000300D0030001811
+:1031F000000000010000300E003000180000000147
+:1032000000003010003000180000000400003014EE
+:103210000030001800000004000050000100008091
+:1032200000080004000050040100008000080004B1
+:103230000000000A000000000000000000005068CC
+:1032400001000080000000010000506901000080C2
+:10325000000000010000506C01000080000000022E
+:103260000000506E0100008000000002000050705D
+:103270000100008000000004000050740100008084
+:103280000000000400005066010000800000000201
+:103290000000506401000080000000010000506048
+:1032A0000100008000000002000050620100008068
+:1032B00000000002000050500100008000000004E7
+:1032C000000050540100008000000004000050582D
+:1032D00001000080000000040000505C010000803C
+:1032E000000000040000507C01000080000000018C
+:1032F0000000507D01000080000000010000401827
+:1033000000100000000000040000409000100000C9
+:1033100000000004000040980010000000000004BD
+:1033200000004110000000000000000200004112F7
+:103330000000000000000002000041140000000036
+:103340000000000200004116000000000000000222
+:103350000000604000080000000000020000604221
+:1033600000080000000000020000604400080000A7
+:103370000000000400006080000800000000000859
+:10338000000060C00040000800000008000060006D
+:1033900000080000000000020000600200080000B9
+:1033A00000000001000060040008000000000002AE
+:1033B0000000634000080000000000080000638077
+:1033C0000008000000000004000063840008000002
+:1033D00000000001000063C00008000000000002BF
+:1033E000000063C400080000000000020000640048
+:1033F0000008000000000004000070000010000041
+:103400000000000400007004001000000000000430
+:1034100000007008001000000000000400007000B0
+:103420000008000000000002000070020008000018
+:10343000000000010000700400080000000000020D
+:10344000000070400008000000000002000070440E
+:1034500000080000000000020000704600080000A4
+:10346000000000020000764800080000000000088C
+:10347000000070800008000000000002000070845E
+:10348000000800000000000200007688000800002C
+:10349000000000080000804000080000000000015B
+:1034A0000000804100080000000000010000804290
+:1034B0000008000000000001000080430008000038
+:1034C0000000000100008000000800000000000271
+:1034D00000008002000800000000000100008004DD
+:1034E0000008000000000002000080C0000800008A
+:1034F00000000002000080C200080000000000027E
+:10350000000080C40008000000000002000080806D
+:103510000008000000000001000080810008000099
+:10352000000000010000808200080000000000018F
+:10353000000080830008000000000001000080847B
+:103540000008000000000001000080850008000065
+:10355000000000010000808600080000000000015B
+:10356000000060000008000000000002000060028F
+:1035700000080000000000010000600400080000D6
+:10358000000000020000604200C0001800000002BD
+:103590000000604000C00018000000020000604C05
+:1035A00000C00018000000080000604400C00018BF
+:1035B000000000080000605700C000180000000173
+:1035C0000000605400C000180000000200006056B7
+:1035D00000C0001800000001000066400008000064
+:1035E00000000008000066800008000000000008DD
+:1035F000000066C000080000000000080000D9427A
+:1036000000180000000000020000DE400000000082
+:10361000000000000000E0000000000000000004C6
+:103620000000DD4000000000000000040000DD4458
+:1036300000000000000000040000DD480000000061
+:10364000000000040000DD4C000000000000000449
+:103650000000DD5000000000000000040000DD5408
+:1036600000000000000000040000DD580000000021
+:10367000000000040000DD40000000000000002009
+:103680000000DA0000000000000000040000DA0082
+:1036900000000000000000680000BB6000000000A7
+:1036A000000000000000D000000000000000000446
+:1036B0000000B0C000000000000000040000B0C422
+:1036C00000000000000000040000B0C8000000007E
+:1036D000000000040000B0C0000000000000001066
+:1036E0000000D6B000000000000000040000D6B4C6
+:1036F00000000000000000040000D6B80000000038
+:10370000000000040000D6BC00000000000000041F
+:103710000000D6B000000000000000100000D348F8
+:1037200000000000000000080000D3580000000066
+:1037300000000080000000100000000000000000F9
+:103740000000D35800000000000000080000000046
+:08375000060022000000000049
+:00000001FF
diff --git a/firmware/bnx2x/bnx2x-e2-6.0.34.0.fw.ihex b/firmware/bnx2x/bnx2x-e2-6.0.34.0.fw.ihex
new file mode 100644
index 000000000000..78b41615e7d9
--- /dev/null
+++ b/firmware/bnx2x/bnx2x-e2-6.0.34.0.fw.ihex
@@ -0,0 +1,15442 @@
+:10000000000052D8000000680000070C00005348B0
+:100010000000318000005A58000000B000008BE062
+:100020000000C14C00008C98000000D800014DE891
+:100030000000F16400014EC800000074000240306E
+:1000400000005250000240A8000000B800029300D7
+:1000500000012110000293C000000FFC0003B4D87F
+:10006000000000040003C4D8020400480000000F90
+:1000700002040054000000450204005C0000000679
+:100080000204007000000004020400780000000078
+:100090000204007C121700000204008022170000F6
+:1000A00002040084321700000604008800000005E6
+:1000B0000204009C12150000020400A0221500009A
+:1000C000020400A432150000060400A80000000489
+:1000D000020400B802100000020400BC001000007E
+:1000E000020400C010100000020400C42010000030
+:1000F000020400C830100000020400CC40100000D0
+:10010000060400D000000003020400DC0010000020
+:10011000020400E012140000020400E422140000B3
+:10012000020400E832140000020400EC4214000053
+:10013000060400F000000003010401240000000098
+:1001400001040128000000000104012C000000004F
+:100150000104013000000000020401D00000890603
+:1001600002040258000000360204025C000000365F
+:10017000020402600810000002040264081000007B
+:1001800002040004000000FF02040008000000FF59
+:100190000204000C000000FF02040010000000FF39
+:1001A000020400140000007F02040018000000FF99
+:1001B0000204001C000000FF02040020000000FFF9
+:1001C000020400240000003E020400280000000099
+:1001D0000204002C0000003F020400300000003F39
+:1001E000020400340000003F020400380000003F19
+:1001F0000204003C0000003F020400400000003FF9
+:10020000020400440000003F020404CC000000018E
+:1002100002042008000002110204200C0000020069
+:10022000020420100000020402042014000002193D
+:100230000204201C0000FFFF020420200000FFFF3A
+:10024000020420240000FFFF020420280000FFFF1A
+:1002500002042038000000200604203C0000000FAB
+:1002600002042078000000210604207C0000000F1A
+:10027000020420B800000001060420BC0000000FAA
+:10028000020420F800000001060420FC0000003FEA
+:10029000020421F800000001060421FC0000000F08
+:1002A0000204223807FFFFFF0204223C0000007F07
+:1002B0000204224007FFFFFF020422440000003F27
+:1002C00001042248000000000104224C000000004C
+:1002D000010422500000000001042254000000002C
+:1002E00001042258000000000104225C000000000C
+:1002F00001042260000000000104226400000000EC
+:1003000001042268000000000104226C00000000CB
+:1003100001042270000000000104227400000000AB
+:1003200001042278000000000104227C000000008B
+:10033000020422C00000FFFF020422C40000FFFFED
+:10034000020422C80000FFFF020422CC0000FFFFCD
+:100350000C042000000003E80A0420000000000153
+:100360000B042000000000030605400000000D0003
+:100370000205004400000020020500480000003291
+:1003800002050090021500200205009402150020CD
+:1003900002050098000000300205009C08100000D3
+:1003A000020500A000000036020500A40000003095
+:1003B000020500A800000031020500B000000004A2
+:1003C000020500B400000005020500C000000000A6
+:1003D000020500C400000004020500D40000000172
+:1003E00002050114000000010205011C00000001CB
+:1003F00002050120000000020205020400000001C5
+:100400000205020C0000004002050210000000403E
+:100410000205021C00000020020502200000001C52
+:100420000205022400000020060502400000000A28
+:1004300004050280002000000205005000000007B3
+:1004400002050054000000070205005800000000EB
+:100450000205005C000000080205006000000001C9
+:100460000605006400000003020500D80000000635
+:100470000205000400000001020500080000000160
+:100480000205000C00000001020500100000000140
+:100490000205001400000001020500180000000120
+:1004A0000205001C00000001020500200000000100
+:1004B00002050024000000010205002800000001E0
+:1004C0000205002C000000010205003000000001C0
+:1004D00002050034000000010205003800000001A0
+:1004E0000205003C00000001020500400000000180
+:1004F000020500E00000000D020500E80000000019
+:10050000020500F000000000020500F800000000F5
+:10051000020500E40000002D020500EC00000020B0
+:10052000020500F400000020020500FC000000208D
+:10053000020500E00000001D020500E800000010B8
+:10054000020500F000000010020500F80000001095
+:10055000020500E40000003D020500EC0000003050
+:10056000020500F400000030020500FC000000302D
+:10057000020500E00000004D020500E80000004018
+:10058000020500F000000040020500F800000040F5
+:10059000020500E40000006D020500EC00000060B0
+:1005A000020500F400000060020500FC000000608D
+:1005B000020500E00000005D020500E800000050B8
+:1005C000020500F000000050020500F80000005095
+:1005D000020500E40000007D020500EC0000007050
+:1005E000020500F400000070020500FC000000702D
+:1005F0000406100002000020020600DC00000001DA
+:100600000406020000030220020600DC00000000D5
+:100610000718040000AC0000081807D800050223E2
+:10062000071C000029B30000071C8000312E0A6D52
+:10063000071D000034A816B9071D80002E6C23E4A6
+:10064000071E0000034B2F80081E07F03F02022503
+:100650000118000000000000011800040000000064
+:1006600001180008000000000118000C0000000044
+:100670000118001000000000011800140000000024
+:1006800002180020000000010218002400000002EF
+:1006900002180028000000030218002C00000000CF
+:1006A00002180030000000040218003400000001AD
+:1006B00002180038000000000218003C0000000191
+:1006C000021800400000000402180044000000006E
+:1006D00002180048000000010218004C000000034E
+:1006E0000218005000000000021800540000000131
+:1006F00002180058000000040218005C000000000E
+:1007000002180060000000010218006400000003ED
+:1007100002180068000000000218006C00000001D0
+:1007200002180070000000040218007400000000AD
+:1007300002180078000000040218007C000000038A
+:100740000618008000000002021800A400007FFFCD
+:10075000021800A8000003FF021802240000000095
+:1007600002180234000000000218024C00000000D1
+:10077000021802E4000000FF061810000000040048
+:10078000021B8BC000000001021B8000000000342F
+:10079000021B804000000018021B80800000000C3B
+:1007A000021B80C0000000200C1B83000008647046
+:1007B0000A1B8300000001570B1B83000000055F2C
+:1007C0000A1B8340000000000C1B8340000002262F
+:1007D0000B1B834000000001021B83800008647033
+:1007E000021B83C000000226021B148000000001CF
+:1007F0000A1B148000000000021B9440000000014E
+:10080000061B944800000002061A1000000002B304
+:10081000041A1ACC00010227061A1AD00000000898
+:10082000061A2008000000C8061A20000000000276
+:10083000041A1BF800900228061A3718000000045A
+:10084000061A371000000002061A500000000002CD
+:10085000061A500800000004061A50180000000490
+:10086000061A502800000004061A50380000000440
+:10087000061A504800000004061A505800000004F0
+:10088000061A506800000004061A507800000002A2
+:10089000041A52C0000202B8061A405000000006B6
+:1008A000041A4068000202BA041A4040000402BC64
+:1008B000041A8000000102C0061A80040000000330
+:1008C000041A8010000102C1061A801400000003FF
+:1008D000041A8020000102C2061A802400000003CE
+:1008E000041A8030000102C3061A8034000000039D
+:1008F000041A8040000102C4061A8044000000036C
+:10090000041A8050000102C5061A8054000000033A
+:10091000041A8060000102C6061A80640000000309
+:10092000041A8070000102C7061A807400000003D8
+:10093000041A8080000102C8061A808400000003A7
+:10094000041A8090000102C9061A80940000000376
+:10095000041A80A0000102CA061A80A40000000345
+:10096000041A80B0000102CB061A80B40000000314
+:10097000041A80C0000102CC061A80C400000003E3
+:10098000041A80D0000102CD061A80D400000003B2
+:10099000041A80E0000102CE061A80E40000000381
+:1009A000041A80F0000102CF061A80F40000000350
+:1009B000041A8100000102D0061A8104000000031D
+:1009C000041A8110000102D1061A811400000003EC
+:1009D000041A8120000102D2061A812400000003BB
+:1009E000041A8130000102D3061A8134000000038A
+:1009F000041A8140000102D4061A81440000000359
+:100A0000041A8150000102D5061A81540000000327
+:100A1000041A8160000102D6061A816400000003F6
+:100A2000041A8170000102D7061A817400000003C5
+:100A3000041A8180000102D8061A81840000000394
+:100A4000041A8190000102D9061A81940000000363
+:100A5000041A81A0000102DA061A81A40000000332
+:100A6000041A81B0000102DB061A81B40000000301
+:100A7000041A81C0000102DC061A81C400000003D0
+:100A8000041A81D0000102DD061A81D4000000039F
+:100A9000041A81E0000102DE061A81E4000000036E
+:100AA000041A81F0000102DF061A81F4000000033D
+:100AB000041A8200000102E0061A8204000000030A
+:100AC000041A8210000102E1061A821400000003D9
+:100AD000041A8220000102E2061A822400000003A8
+:100AE000041A8230000102E3061A82340000000377
+:100AF000041A8240000102E4061A82440000000346
+:100B0000041A8250000102E5061A82540000000314
+:100B1000041A8260000102E6061A826400000003E3
+:100B2000041A8270000102E7061A827400000003B2
+:100B3000041A8280000102E8061A82840000000381
+:100B4000041A8290000102E9061A82940000000350
+:100B5000041A82A0000102EA061A82A4000000031F
+:100B6000041A82B0000102EB061A82B400000003EE
+:100B7000041A82C0000102EC061A82C400000003BD
+:100B8000041A82D0000102ED061A82D4000000038C
+:100B9000041A82E0000102EE061A82E4000000035B
+:100BA000041A82F0000102EF061A82F4000000032A
+:100BB000041A8300000102F0061A830400000003F7
+:100BC000041A8310000102F1061A831400000003C6
+:100BD000041A8320000102F2061A83240000000395
+:100BE000041A8330000102F3061A83340000000364
+:100BF000041A8340000102F4061A83440000000333
+:100C0000041A8350000102F5061A83540000000301
+:100C1000041A8360000102F6061A836400000003D0
+:100C2000041A8370000102F7061A8374000000039F
+:100C3000041A8380000102F8061A8384000000036E
+:100C4000041A8390000102F9061A8394000000033D
+:100C5000041A83A0000102FA061A83A4000000030C
+:100C6000041A83B0000102FB061A83B400000003DB
+:100C7000041A83C0000102FC061A83C400000003AA
+:100C8000041A83D0000102FD061A83D40000000379
+:100C9000041A83E0000102FE061A83E40000000348
+:100CA000041A83F0000102FF061A83F40000000317
+:100CB000041A840000010300061A840400000003E3
+:100CC000041A841000010301061A841400000003B2
+:100CD000041A842000010302061A84240000000381
+:100CE000041A843000010303061A84340000000350
+:100CF000041A844000010304061A8444000000031F
+:100D0000041A845000010305061A845400000003ED
+:100D1000041A846000010306061A846400000003BC
+:100D2000041A847000010307061A8474000000038B
+:100D3000041A848000010308061A8484000000035A
+:100D4000041A849000010309061A84940000000329
+:100D5000041A84A00001030A061A84A400000003F8
+:100D6000041A84B00001030B061A84B400000003C7
+:100D7000041A84C00001030C061A84C40000000396
+:100D8000041A84D00001030D061A84D40000000365
+:100D9000041A84E00001030E061A84E40000000334
+:100DA000041A84F00001030F061A84F40000000303
+:100DB000041A850000010310061A850400000003D0
+:100DC000041A851000010311061A8514000000039F
+:100DD000041A852000010312061A8524000000036E
+:100DE000041A853000010313061A8534000000033D
+:100DF000041A854000010314061A8544000000030C
+:100E0000041A855000010315061A855400000003DA
+:100E1000041A856000010316061A856400000003A9
+:100E2000041A857000010317061A85740000000378
+:100E3000041A858000010318061A85840000000347
+:100E4000041A859000010319061A85940000000316
+:100E5000041A85A00001031A061A85A400000003E5
+:100E6000041A85B00001031B061A85B400000003B4
+:100E7000041A85C00001031C061A85C40000000383
+:100E8000041A85D00001031D061A85D40000000352
+:100E9000041A85E00001031E061A85E40000000321
+:100EA000041A85F00001031F061A85F400000003F0
+:100EB000041A860000010320061A860400000003BD
+:100EC000041A861000010321061A8614000000038C
+:100ED000041A862000010322061A8624000000035B
+:100EE000041A863000010323061A8634000000032A
+:100EF000041A864000010324061A864400000003F9
+:100F0000041A865000010325061A865400000003C7
+:100F1000041A866000010326061A86640000000396
+:100F2000041A867000010327061A86740000000365
+:100F3000041A868000010328061A86840000000334
+:100F4000041A869000010329061A86940000000303
+:100F5000041A86A00001032A061A86A400000003D2
+:100F6000041A86B00001032B061A86B400000003A1
+:100F7000041A86C00001032C061A86C40000000370
+:100F8000041A86D00001032D061A86D4000000033F
+:100F9000041A86E00001032E061A86E4000000030E
+:100FA000041A86F00001032F061A86F400000003DD
+:100FB000041A870000010330061A870400000003AA
+:100FC000041A871000010331061A87140000000379
+:100FD000041A872000010332061A87240000000348
+:100FE000041A873000010333061A87340000000317
+:100FF000041A874000010334061A874400000003E6
+:10100000041A875000010335061A875400000003B4
+:10101000041A876000010336061A87640000000383
+:10102000041A877000010337061A87740000000352
+:10103000041A878000010338061A87840000000321
+:10104000041A879000010339061A879400000003F0
+:10105000041A87A00001033A061A87A400000003BF
+:10106000041A87B00001033B061A87B4000000038E
+:10107000041A87C00001033C061A87C4000000035D
+:10108000041A87D00001033D061A87D4000000032C
+:10109000041A87E00001033E061A87E400000003FB
+:1010A000041A87F00001033F061A87F400000003CA
+:1010B000041A880000010340061A88040000000397
+:1010C000041A881000010341061A88140000000366
+:1010D000041A882000010342061A88240000000335
+:1010E000041A883000010343061A88340000000304
+:1010F000041A884000010344061A884400000003D3
+:10110000041A885000010345061A885400000003A1
+:10111000041A886000010346061A88640000000370
+:10112000041A887000010347061A8874000000033F
+:10113000041A888000010348061A8884000000030E
+:10114000041A889000010349061A889400000003DD
+:10115000041A88A00001034A061A88A400000003AC
+:10116000041A88B00001034B061A88B4000000037B
+:10117000041A88C00001034C061A88C4000000034A
+:10118000041A88D00001034D061A88D40000000319
+:10119000041A88E00001034E061A88E400000003E8
+:1011A000041A88F00001034F061A88F400000003B7
+:1011B000041A890000010350061A89040000000384
+:1011C000041A891000010351061A89140000000353
+:1011D000041A892000010352061A89240000000322
+:1011E000041A893000010353061A893400000003F1
+:1011F000041A894000010354061A894400000003C0
+:10120000041A895000010355061A8954000000038E
+:10121000041A896000010356061A8964000000035D
+:10122000041A897000010357061A8974000000032C
+:10123000041A898000010358061A898400000003FB
+:10124000041A899000010359061A899400000003CA
+:10125000041A89A00001035A061A89A40000000399
+:10126000041A89B00001035B061A89B40000000368
+:10127000041A89C00001035C061A89C40000000337
+:10128000041A89D00001035D061A89D40000000306
+:10129000041A89E00001035E061A89E400000003D5
+:1012A000041A89F00001035F061A89F400000003A4
+:1012B000041A8A0000010360061A8A040000000371
+:1012C000041A8A1000010361061A8A140000000340
+:1012D000041A8A2000010362061A8A24000000030F
+:1012E000041A8A3000010363061A8A3400000003DE
+:1012F000041A8A4000010364061A8A4400000003AD
+:10130000041A8A5000010365061A8A54000000037B
+:10131000041A8A6000010366061A8A64000000034A
+:10132000041A8A7000010367061A8A740000000319
+:10133000041A8A8000010368061A8A8400000003E8
+:10134000041A8A9000010369061A8A9400000003B7
+:10135000041A8AA00001036A061A8AA40000000386
+:10136000041A8AB00001036B061A8AB40000000355
+:10137000041A8AC00001036C061A8AC40000000324
+:10138000041A8AD00001036D061A8AD400000003F3
+:10139000041A8AE00001036E061A8AE400000003C2
+:1013A000041A8AF00001036F061A8AF40000000391
+:1013B000041A8B0000010370061A8B04000000035E
+:1013C000041A8B1000010371061A8B14000000032D
+:1013D000041A8B2000010372061A8B2400000003FC
+:1013E000041A8B3000010373061A8B3400000003CB
+:1013F000041A8B4000010374061A8B44000000039A
+:10140000041A8B5000010375061A8B540000000368
+:10141000041A8B6000010376061A8B640000000337
+:10142000041A8B7000010377061A8B740000000306
+:10143000041A8B8000010378061A8B8400000003D5
+:10144000041A8B9000010379061A8B9400000003A4
+:10145000041A8BA00001037A061A8BA40000000373
+:10146000041A8BB00001037B061A8BB40000000342
+:10147000041A8BC00001037C061A8BC40000000311
+:10148000041A8BD00001037D061A8BD400000003E0
+:10149000041A8BE00001037E061A8BE400000003AF
+:1014A000041A8BF00001037F061A8BF4000000037E
+:1014B000041A8C0000010380061A8C04000000034B
+:1014C000041A8C1000010381061A8C14000000031A
+:1014D000041A8C2000010382061A8C2400000003E9
+:1014E000041A8C3000010383061A8C3400000003B8
+:1014F000041A8C4000010384061A8C440000000387
+:10150000041A8C5000010385061A8C540000000355
+:10151000041A8C6000010386061A8C640000000324
+:10152000041A8C7000010387061A8C7400000003F3
+:10153000041A8C8000010388061A8C8400000003C2
+:10154000041A8C9000010389061A8C940000000391
+:10155000041A8CA00001038A061A8CA40000000360
+:10156000041A8CB00001038B061A8CB4000000032F
+:10157000041A8CC00001038C061A8CC400000003FE
+:10158000041A8CD00001038D061A8CD400000003CD
+:10159000041A8CE00001038E061A8CE4000000039C
+:1015A000041A8CF00001038F061A8CF4000000036B
+:1015B000041A8D0000010390061A8D040000000338
+:1015C000041A8D1000010391061A8D140000000307
+:1015D000041A8D2000010392061A8D2400000003D6
+:1015E000041A8D3000010393061A8D3400000003A5
+:1015F000041A8D4000010394061A8D440000000374
+:10160000041A8D5000010395061A8D540000000342
+:10161000041A8D6000010396061A8D640000000311
+:10162000041A8D7000010397061A8D7400000003E0
+:10163000041A8D8000010398061A8D8400000003AF
+:10164000041A8D9000010399061A8D94000000037E
+:10165000041A8DA00001039A061A8DA4000000034D
+:10166000041A8DB00001039B061A8DB4000000031C
+:10167000041A8DC00001039C061A8DC400000003EB
+:10168000041A8DD00001039D061A8DD400000003BA
+:10169000041A8DE00001039E061A8DE40000000389
+:1016A000041A8DF00001039F061A8DF40000000358
+:1016B000041A8E00000103A0061A8E040000000325
+:1016C000041A8E10000103A1061A8E1400000003F4
+:1016D000041A8E20000103A2061A8E2400000003C3
+:1016E000041A8E30000103A3061A8E340000000392
+:1016F000041A8E40000103A4061A8E440000000361
+:10170000041A8E50000103A5061A8E54000000032F
+:10171000041A8E60000103A6061A8E6400000003FE
+:10172000041A8E70000103A7061A8E7400000003CD
+:10173000041A8E80000103A8061A8E84000000039C
+:10174000041A8E90000103A9061A8E94000000036B
+:10175000041A8EA0000103AA061A8EA4000000033A
+:10176000041A8EB0000103AB061A8EB40000000309
+:10177000041A8EC0000103AC061A8EC400000003D8
+:10178000041A8ED0000103AD061A8ED400000003A7
+:10179000041A8EE0000103AE061A8EE40000000376
+:1017A000041A8EF0000103AF061A8EF40000000345
+:1017B000041A8F00000103B0061A8F040000000312
+:1017C000041A8F10000103B1061A8F1400000003E1
+:1017D000041A8F20000103B2061A8F2400000003B0
+:1017E000041A8F30000103B3061A8F34000000037F
+:1017F000041A8F40000103B4061A8F44000000034E
+:10180000041A8F50000103B5061A8F54000000031C
+:10181000041A8F60000103B6061A8F6400000003EB
+:10182000041A8F70000103B7061A8F7400000003BA
+:10183000041A8F80000103B8061A8F840000000389
+:10184000041A8F90000103B9061A8F940000000358
+:10185000041A8FA0000103BA061A8FA40000000327
+:10186000041A8FB0000103BB061A8FB400000003F6
+:10187000041A8FC0000103BC061A8FC400000003C5
+:10188000041A8FD0000103BD061A8FD40000000394
+:10189000041A8FE0000103BE061A8FE4000000075F
+:1018A000041A62C0002003BF061A1AF000000042AA
+:1018B000061AAF0000000008061AE000000005400C
+:1018C000061AD00000000072061AD248000000106C
+:1018D000061AD6B000000020061AD470000000904E
+:1018E000061AD46800000002061AA000000001C415
+:1018F000061A300000000010061A308000000010A8
+:10190000061A310000000010061A31800000001095
+:10191000061A330000000012061A3390000000700F
+:10192000061AD45800000002061AD348000000022C
+:10193000061AD35800000020061AA710000001C4A0
+:10194000061A304000000010061A30C000000010D7
+:10195000061A314000000010061A31C000000010C5
+:10196000061A334800000012061A355000000070B5
+:10197000061AD46000000002061AD35000000002CC
+:10198000061AD3D800000020021AAE200000000082
+:10199000061A500000000002061A508000000012D3
+:1019A000041A4000000203DF041A63C0000203E1CE
+:1019B000061A700000000004061A32000000000839
+:1019C000021AAE2400000000061A501000000002A7
+:1019D000061A50C800000012041A4008000203E36F
+:1019E000041A63C8000203E5061A70100000000420
+:1019F000061A322000000008021AAE28000000007B
+:101A0000061A502000000002061A511000000012B1
+:101A1000041A4010000203E7041A63D0000203E92D
+:101A2000061A702000000004061A32400000000868
+:101A3000021AAE2C00000000061A5030000000020E
+:101A4000061A515800000012041A4018000203EB55
+:101A5000041A63D8000203ED061A70300000000477
+:101A6000061A326000000008021AAE3000000000C2
+:101A7000061A504000000002061A51A00000001291
+:101A8000041A4020000203EF041A63E0000203F18D
+:101A9000061A704000000004061A32800000000898
+:101AA000021AAE3400000000061A50500000000276
+:101AB000061A51E800000012041A4028000203F33D
+:101AC000041A63E8000203F5061A705000000004CF
+:101AD000061A32A000000008021AAE38000000000A
+:101AE000061A506000000002061A52300000001270
+:101AF000041A4030000203F7041A63F0000203F9ED
+:101B0000061A706000000004061A32C000000008C7
+:101B1000021AAE3C00000000061A507000000002DD
+:101B2000061A527800000012041A4038000203FB23
+:101B3000041A63F8000203FD061A70700000000426
+:101B4000061A32E0000000080200A2A40000020908
+:101B50000200A270000000000200A2740000000059
+:101B60000200A270000000000200A2740000000049
+:101B70000200A270000000000200A2740000000039
+:101B80000200A270000000000200A2740000000029
+:101B9000020100B400000001020100B800000001D1
+:101BA000020100CC00000001020100D00000000191
+:101BB000020100DC00000001020101000000000140
+:101BC00002010104000000010201007C003000005D
+:101BD00002010084000000280201008C00000000C7
+:101BE00002010130000000040201025C000000015B
+:101BF0000201032800000000020160580000FFFFFE
+:101C0000020160700000000702010554000000306E
+:101C1000020100C400000001020100F80000000100
+:101C2000020100F00000000102010080003000000D
+:101C3000020100880000002802010090000000005E
+:101C40000201013400000004020102DC0000000176
+:101C50000201032C000000000201605C0000FFFF95
+:101C600002016074000000070201056400000030FA
+:101C7000020100C800000001020100FC0000000198
+:101C8000020100F400000001020C10000000002816
+:101C9000020C200800000211020C200C00000200BF
+:101CA000020C201000000204020C201C0000FFFFA8
+:101CB000020C20200000FFFF020C20240000FFFF88
+:101CC000020C20280000FFFF020C2038000000005A
+:101CD000020C203C00000037020C204000000021D4
+:101CE000020C204400000020060C20480000001DCB
+:101CF000020C20BC00000001060C20C00000003FC8
+:101D0000020C21BC00000001020C21C000000001F7
+:101D1000020C21C400000001060C21C80000001CB8
+:101D2000020C223807FFFFFF020C223C0000007F5C
+:101D3000020C224007FFFFFF020C22440000003F7C
+:101D4000010C224800000000010C224C00000000A1
+:101D5000010C225000000000010C22540000000081
+:101D6000010C225800000000010C225C0000000061
+:101D7000010C226000000000010C22640000000041
+:101D8000010C226800000000010C226C0000000021
+:101D9000010C227000000000010C22740000000001
+:101DA000010C227800000000010C227C00000000E1
+:101DB000020C22D80000FFFF020C22DC0000FFFF13
+:101DC000020C22E00000FFFF020C22E40000FFFFF3
+:101DD0000C0C2000000003E80A0C200000000001A9
+:101DE0000B0C200000000003020C40080000101142
+:101DF000020C400C00001000020C40100000100407
+:101E0000020C401400001021020C401C0000FFFFD7
+:101E1000020C40200000FFFF020C40240000FFFFE6
+:101E2000020C40280000FFFF020C40380000004672
+:101E3000020C403C0000000C060C40400000000278
+:101E4000020C404800000018020C404C000000F05A
+:101E5000060C40500000001F020C40CC00000001A6
+:101E6000060C40D00000003A020C41B8000000010E
+:101E7000060C41BC00000003020C41C80000000138
+:101E8000020C41CC00000001060C41D00000001AF9
+:101E9000020C423807FFFFFF020C423C0000007FAB
+:101EA000020C424007FFFFFF020C42440000003FCB
+:101EB000010C424800000000010C424C00000000F0
+:101EC000010C425000000000010C425400000000D0
+:101ED000010C425800000000010C425C00000000B0
+:101EE000010C426000000000010C42640000000090
+:101EF000010C426800000000010C426C0000000070
+:101F0000010C427000000000010C4274000000004F
+:101F1000010C427800000000010C427C000000002F
+:101F2000010C428000000000020C42D80000FFFFBC
+:101F3000020C42DC0000FFFF020C42E00000FFFF49
+:101F4000020C42E40000FFFF0C0C4000000003E81C
+:101F50000A0C4000000000010B0C400000000003D0
+:101F6000060D400000000A00020D0044000000328F
+:101F7000020D008C02150020020D009002150020B9
+:101F8000020D009408100000020D009800000036B9
+:101F9000020D00A000000000020D00A400000004DB
+:101FA000020D00A800000004060D00AC00000002B5
+:101FB000020D00B800000002020D00C00000000188
+:101FC000020D00C800000002020D00CC000000025B
+:101FD000020D015C00000001020D0164000000011F
+:101FE000020D016800000002020D02040000000161
+:101FF000020D020C00000020020D02100000004043
+:10200000020D021400000040020D02200000000337
+:10201000020D022400000018060D028000000012CC
+:10202000040D0300001803FF060D03600000000C00
+:10203000020D004C00000001020D005000000002E3
+:10204000020D005400000000020D005800000008BE
+:10205000060D005C00000004020D00C40000000436
+:10206000020D000400000001020D00080000000144
+:10207000020D000C00000001020D00100000000124
+:10208000020D001400000001020D00180000000104
+:10209000020D001C00000001020D002000000001E4
+:1020A000020D002400000001020D002800000001C4
+:1020B000020D002C00000001020D003000000001A4
+:1020C000020D003400000001020D00380000000184
+:1020D000020D003C00000001020D01140000000987
+:1020E000020D011C0000000A020D01240000000086
+:1020F000020D012C00000000020D01340000000060
+:10210000020D013C0000000B020D01440000000024
+:10211000020D011800000029020D01200000002A14
+:10212000020D012800000020020D013000000020F7
+:10213000020D013800000020020D01400000002BBC
+:10214000020D014800000020020D011400000019DA
+:10215000020D011C0000001A020D012400000010F5
+:10216000020D012C00000010020D013400000010CF
+:10217000020D013C0000001B020D01440000001094
+:10218000020D011800000039020D01200000003A84
+:10219000020D012800000030020D01300000003067
+:1021A000020D013800000030020D01400000003B2C
+:1021B000020D014800000030020D0114000000492A
+:1021C000020D011C0000004A020D01240000004025
+:1021D000020D012C00000040020D013400000040FF
+:1021E000020D013C0000004B020D014400000040C4
+:1021F000020D011800000069020D01200000006AB4
+:10220000020D012800000060020D01300000006096
+:10221000020D013800000060020D01400000006B5B
+:10222000020D014800000060020D01140000005979
+:10223000020D011C0000005A020D01240000005094
+:10224000020D012C00000050020D0134000000506E
+:10225000020D013C0000005B020D01440000005033
+:10226000020D011800000079020D01200000007A23
+:10227000020D012800000070020D01300000007006
+:10228000020D013800000070020D01400000007BCB
+:10229000020D014800000070060E2000000008003A
+:1022A000020E004C00000032020E009402150020C5
+:1022B000020E009802150020020E009C0000003063
+:1022C000020E00A008100000020E00A4000000365C
+:1022D000020E00A800000030020E00AC0000003129
+:1022E000020E00B400000003020E00B8000000005F
+:1022F000020E00C400000000020E00CC0000000628
+:10230000020E00D800000001020E0144000000018E
+:10231000020E014C00000001020E015000000002FC
+:10232000020E020400000001020E020C0000004038
+:10233000020E021000000040020E021C0000000409
+:10234000020E022000000020020E02240000000EF7
+:10235000020E02280000001B060E030000000012FF
+:10236000040E0280001B0417060E02EC000000059C
+:10237000020E00540000000C020E00580000000C79
+:10238000020E005C00000000020E00600000001061
+:10239000020E006400000010060E0068000000033A
+:1023A000020E00DC00000003020E00040000000129
+:1023B000020E000800000001020E000C00000001E7
+:1023C000020E001000000001020E001400000001C7
+:1023D000020E001800000001020E001C00000001A7
+:1023E000020E002000000001020E00240000000187
+:1023F000020E002800000001020E002C0000000167
+:10240000020E003000000001020E00340000000146
+:10241000020E003800000001020E003C0000000126
+:10242000020E004000000001020E00440000000106
+:10243000020E01100000000F020E01180000000043
+:10244000020E012000000000020E01280000000022
+:10245000020E01140000002F020E011C00000020DB
+:10246000020E012400000020020E012C00000020BA
+:10247000020E01100000001F020E011800000010E3
+:10248000020E012000000010020E012800000010C2
+:10249000020E01140000003F020E011C000000307B
+:1024A000020E012400000030020E012C000000305A
+:1024B000020E01100000004F020E01180000004043
+:1024C000020E012000000040020E01280000004022
+:1024D000020E01140000006F020E011C00000060DB
+:1024E000020E012400000060020E012C00000060BA
+:1024F000020E01100000005F020E011800000050E3
+:10250000020E012000000050020E012800000050C1
+:10251000020E01140000007F020E011C000000707A
+:10252000020E012400000070020E012C0000007059
+:102530000730040000D60000083007D80005043238
+:10254000073400003222000007348000312C0C894F
+:102550000735000038DD18D5073580002F16270D08
+:1025600007360000261532D30836711031DE0434E8
+:1025700001300000000000000130000400000000F5
+:1025800001300008000000000130000C00000000D5
+:1025900001300010000000000130001400000000B5
+:1025A0000230002000000001023000240000000280
+:1025B00002300028000000030230002C0000000060
+:1025C000023000300000000402300034000000013E
+:1025D00002300038000000000230003C0000000122
+:1025E00002300040000000040230004400000000FF
+:1025F00002300048000000010230004C00000003DF
+:1026000002300050000000000230005400000001C1
+:1026100002300058000000040230005C000000009E
+:10262000023000600000000102300064000000037E
+:1026300002300068000000000230006C0000000161
+:10264000023000700000000402300074000000003E
+:1026500002300078000000040230007C000000031B
+:102660000630008000000002023000A400007FFF5E
+:10267000023000A8000003FF023002240000000026
+:1026800002300234000000000230024C0000000062
+:10269000023002E40000FFFF0630200000000800C6
+:1026A00002338BC000000001023380000000001ADA
+:1026B000023380400000004E023380800000001092
+:1026C000023380C0000000200C33830000086470D7
+:1026D0000A338300000001570B3383000000055FBD
+:1026E0000A338340000000000C33834000000226C0
+:1026F0000B338340000000010233838000086470C4
+:10270000023383C00000022602331480000000015F
+:102710000A3314800000000006328000000001022D
+:1027200006322008000000C8063220000000000227
+:1027300004328520008F04360632875C00000009D1
+:1027400006323EB00000000606323ED00000000215
+:1027500006323E800000000A04323EA8000204C592
+:1027600006323E0000000020063250000000094002
+:102770000632400000000004043294C0000204C786
+:1027800006324110000000020632D0000000007046
+:102790000632DB00000000D40632DEA0000000029A
+:1027A0000632E00000000800063324000000011893
+:1027B00006321000000001880632500000000020A0
+:1027C00006325100000000200632520000000020B6
+:1027D00006325300000000200632540000000020A2
+:1027E000063255000000002006325600000000208E
+:1027F000063257000000002006325800000000207A
+:10280000063259000000002006325A000000002065
+:1028100006325B000000002006325C000000002051
+:1028200006325D000000002006325E00000000203D
+:1028300006325F0000000020063284F00000000233
+:1028400004328500000204C9063285080000000237
+:102850000632DE90000000020633286000000118F6
+:102860000632162000000188063250800000002049
+:102870000632518000000020063252800000002005
+:1028800006325380000000200632548000000020F1
+:1028900006325580000000200632568000000020DD
+:1028A00006325780000000200632588000000020C9
+:1028B000063259800000002006325A8000000020B5
+:1028C00006325B800000002006325C8000000020A1
+:1028D00006325D800000002006325E80000000208D
+:1028E00006325F8000000020063284F800000002FB
+:1028F00004328510000204CB063285180000000265
+:102900000632DE980000000202328450000000000F
+:102910000632401000000002023284540000000021
+:1029200006324020000000020232845800000000FD
+:1029300006324030000000020232845C00000000D9
+:1029400006324040000000020232846000000000B5
+:102950000632405000000002023284640000000091
+:10296000063240600000000202328468000000006D
+:1029700006324070000000020232846C0000000049
+:1029800006324080000000020720040000730000AF
+:1029900008200780001004CD072400002AD500007D
+:1029A0000724800027740AB60824D36063FA04CF92
+:1029B00001200000000000000120000400000000D1
+:1029C00001200008000000000120000C00000000B1
+:1029D0000120001000000000012000140000000091
+:1029E000022000200000000102200024000000025C
+:1029F00002200028000000030220002C000000003C
+:102A00000220003000000004022000340000000119
+:102A100002200038000000000220003C00000001FD
+:102A200002200040000000040220004400000000DA
+:102A300002200048000000010220004C00000003BA
+:102A4000022000500000000002200054000000019D
+:102A500002200058000000040220005C000000007A
+:102A6000022000600000000102200064000000035A
+:102A700002200068000000000220006C000000013D
+:102A8000022000700000000402200074000000001A
+:102A900002200078000000040220007C00000003F7
+:102AA0000620008000000002022000A400007FFF3A
+:102AB000022000A8000003FF022002240000000002
+:102AC00002200234000000000220024C000000003E
+:102AD000022002E40000FFFF0620200000000800A2
+:102AE00002238BC0000000010223800000000010C0
+:102AF000022380400000001202238080000000308A
+:102B0000022380C00000000E0C23830000086470C4
+:102B10000A238300000001570B2383000000055F98
+:102B20000A238340000000000C238340000002269B
+:102B30000B2383400000000102238380000864709F
+:102B4000022383C00000022602231480000000013B
+:102B50000A2314800000000006221000000000423A
+:102B600006222008000000C8062220000000000203
+:102B70000622B000000003300622F40000000053DB
+:102B80000422F54C000104D10622F5500000000398
+:102B90000422F55C000104D20622F5600000000367
+:102BA0000422F56C000104D30622F5700000000336
+:102BB0000422F57C000104D40622F5800000000305
+:102BC0000422F58C000104D50622F59000000003D4
+:102BD0000422F59C000104D60622F5A000000003A3
+:102BE0000422F5AC000104D70622F5B00000000372
+:102BF0000422F5BC000104D80622F5C000000046FE
+:102C00000622E2000000044004221240009004D991
+:102C100006223000000000C006226700000001000C
+:102C2000062290000000040004226B0800200569C1
+:102C3000062211F000000006042212080006058991
+:102C4000062212200000000206224000000005C0FB
+:102C50000622C000000000060422C0180006058FEE
+:102C60000622C0300000000A0422C0580006059564
+:102C70000622C0700000000A0422C0980006059BCE
+:102C80000622C0B00000000A0422C0D8000605A138
+:102C90000622C0F00000000A0422C118000605A7A1
+:102CA0000622C1300000000A0422C158000605AD0A
+:102CB0000622C1700000000A0422C198000605B374
+:102CC0000622C1B00000000A0422C1D8000605B9DE
+:102CD0000622C1F00000000A0422C218000605BF47
+:102CE0000622C2300000000A0422C258000605C5B0
+:102CF0000622C2700000000A0422C298000605CB1A
+:102D00000622C2B00000000A0422C2D8000605D183
+:102D10000622C2F00000000A0422C318000605D7EC
+:102D20000622C3300000000A0422C358000605DD55
+:102D30000622C3700000000A0422C398000605E3BF
+:102D40000622C3B00000000A0422C3D8000605E929
+:102D50000622C3F00000000A0422C418000605EF92
+:102D60000622C4300000000A0422C458000605F5FB
+:102D70000622C4700000000A0422C498000605FB65
+:102D80000622C4B00000000A0422C4D800060601CE
+:102D90000622C4F00000000A0422C5180006060737
+:102DA0000622C5300000000A0422C5580006060DA0
+:102DB0000622C5700000000A0422C598000606130A
+:102DC0000622C5B00000000A0422C5D80006061974
+:102DD0000622C5F00000000A0422C6180006061FDD
+:102DE0000622C6300000000A0422C6580006062546
+:102DF0000622C6700000000A0422C6980006062BB0
+:102E00000622C6B00000000A0422C6D80006063119
+:102E10000622C6F00000000A0422C7180006063782
+:102E20000622C7300000000A0422C7580006063DEB
+:102E30000622C7700000000A0422C7980006064355
+:102E40000622C7B00000000A0422C7D800060649BF
+:102E50000622C7F00000000A0422C8180006064F28
+:102E60000622C8300000000A0422C8580006065591
+:102E70000622C8700000000A0422C8980006065BFB
+:102E80000622C8B00000000A0422C8D80006066165
+:102E90000622C8F00000000A0422C91800060667CE
+:102EA0000622C9300000000A0422C9580006066D37
+:102EB0000622C9700000000A0422C99800060673A1
+:102EC0000622C9B00000000A0422C9D8000606790B
+:102ED0000622C9F00000000A0422CA180006067F74
+:102EE0000622CA300000000A0422CA5800060685DD
+:102EF0000622CA700000000A0422CA980006068B47
+:102F00000622CAB00000000A0422CAD800060691B0
+:102F10000622CAF00000000A0422CB180006069719
+:102F20000622CB300000000A0422CB580006069D82
+:102F30000622CB700000000A0422CB98000606A3EC
+:102F40000622CBB00000000A0422CBD8000606A956
+:102F50000622CBF00000000A0422CC18000606AFBF
+:102F60000622CC300000000A0422CC58000606B528
+:102F70000622CC700000000A0422CC98000606BB92
+:102F80000622CCB00000000A0422CCD8000606C1FC
+:102F90000622CCF00000000A0422CD18000606C765
+:102FA0000622CD300000000A0422CD58000606CDCE
+:102FB0000622CD700000000A0422CD98000606D338
+:102FC0000622CDB00000000A0422CDD8000606D9A2
+:102FD0000622CDF00000000A0422CE18000606DF0B
+:102FE0000622CE300000000A0422CE58000606E574
+:102FF0000622CE700000000A0422CE98000606EBDE
+:103000000622CEB00000000A0422CED8000606F147
+:103010000622CEF00000000A0422CF18000606F7B0
+:103020000622CF300000000A0422CF58000606FD19
+:103030000622CF700000000A0422CF980006070382
+:103040000622CFB00000000A0422CFD800060709EC
+:103050000622CFF00000000A0422D0180006070F55
+:103060000622D0300000000A0422D05800060715BE
+:103070000622D0700000000A0422D0980006071B28
+:103080000622D0B00000000A0422D0D80006072192
+:103090000622D0F00000000A0422D11800060727FB
+:1030A0000622D1300000000A0422D1580006072D64
+:1030B0000622D1700000000A0422D19800060733CE
+:1030C0000622D1B00000000A0422D1D80006073938
+:1030D0000622D1F00000000A0422D2180006073FA1
+:1030E0000622D2300000000A0422D258000607450A
+:1030F0000622D2700000000A0422D2980006074B74
+:103100000622D2B00000000A0422D2D800060751DD
+:103110000622D2F00000000A0422D3180006075746
+:103120000622D3300000000A0422D3580006075DAF
+:103130000622D3700000000A0422D3980006076319
+:103140000622D3B00000000A0422D3D80006076983
+:103150000622D3F00000000A0422D4180006076FEC
+:103160000622D4300000000A0422D4580006077555
+:103170000622D4700000000A0422D4980006077BBF
+:103180000622D4B00000000A0422D4D80006078129
+:103190000622D4F00000000A0422D5180006078792
+:1031A0000622D5300000000A0422D5580006078DFB
+:1031B0000622D5700000000A0422D5980006079365
+:1031C0000622D5B00000000A0422D5D800060799CF
+:1031D0000622D5F00000000A0422D6180006079F38
+:1031E0000622D6300000000A0422D658000607A5A1
+:1031F0000622D6700000000A0422D698000607AB0B
+:103200000622D6B00000000A0422D6D8000607B174
+:103210000622D6F00000000A0422D718000607B7DD
+:103220000622D7300000000A0422D758000607BD46
+:103230000622D7700000000A0422D798000607C3B0
+:103240000622D7B00000000A0422D7D8000607C91A
+:103250000622D7F00000000A0422D818000607CF83
+:103260000622D8300000000A0422D858000607D5EC
+:103270000622D8700000000A0422D898000607DB56
+:103280000622D8B00000000A0422D8D8000607E1C0
+:103290000622D8F00000000A0422D918000607E729
+:1032A0000622D9300000000A0422D958000607ED92
+:1032B0000622D9700000000A0422D998000607F3FC
+:1032C0000622D9B00000000A0422D9D8000607F966
+:1032D0000622D9F00000000A0422DA18000607FFCF
+:1032E0000622DA300000000A0422DA580006080537
+:1032F0000622DA700000000A0422DA980006080BA1
+:103300000622DAB00000000A0422DAD8000608110A
+:103310000622DAF00000000A0422DB180006081773
+:103320000622DB300000000A0422DB580006081DDC
+:103330000622DB700000000A0422DB980006082346
+:103340000622DBB00000000A0422DBD800060829B0
+:103350000622DBF00000000A0422DC180006082F19
+:103360000622DC300000000A0422DC580006083582
+:103370000622DC700000000A0422DC980006083BEC
+:103380000622DCB00000000A0422DCD80006084156
+:103390000622DCF00000000A0422DD1800060847BF
+:1033A0000622DD300000000A0422DD580006084D28
+:1033B0000622DD700000000A0422DD980006085392
+:1033C0000622DDB00000000A0422DDD800060859FC
+:1033D0000622DDF00000000A0422DE180006085F65
+:1033E0000622DE300000000A0422DE5800060865CE
+:1033F0000622DE700000000A0422DE980006086B38
+:103400000622DEB00000000A0422DED800060871A1
+:103410000622DEF00000000A0422DF18000608770A
+:103420000622DF300000000A0422DF580006087D73
+:103430000622DF700000000A0422DF9800060883DD
+:103440000622DFB00000000A0422DFD80006088947
+:103450000622DFF00000000A0422E0180006088FB0
+:103460000622E0300000000A0422E0580006089519
+:103470000622E0700000000A0422E0980006089B83
+:103480000622E0B00000000A0422E0D8000608A1ED
+:103490000622E0F00000000A0422E118000608A756
+:1034A0000622E1300000000A0422E158000608ADBF
+:1034B0000622E1700000000A0422E198000608B329
+:1034C0000622E1B00000000A0422E1D8000608B993
+:1034D0000622E1F000000004062215380000000278
+:1034E000062211E8000000020622F3000000000896
+:1034F00002221148000000000622590000000006C8
+:103500000622330000000002062260400000003066
+:103510000622F320000000080222114C00000000E7
+:103520000622591800000006062233080000000297
+:1035300006226100000000300622F340000000086F
+:10354000022211500000000006225930000000063F
+:103550000622331000000002062261C00000003085
+:103560000622F3600000000802221154000000004F
+:103570000622594800000006062233180000000207
+:1035800006226280000000300622F380000000085E
+:1035900002221158000000000622596000000006B7
+:1035A00006223320000000020622634000000030A3
+:1035B0000622F3A0000000080222115C00000000B7
+:1035C0000622597800000006062233280000000277
+:1035D00006226400000000300622F3C0000000084C
+:1035E000022211600000000006225990000000062F
+:1035F0000622333000000002062264C000000030C2
+:103600000622F3E00000000802221164000000001E
+:10361000062259A8000000060622333800000002E6
+:10362000062265800000003002161000000000280D
+:1036300002170008000000020217002C000000031F
+:103640000217003C000000040217004400000000C4
+:1036500002170048000000020217004C0000009012
+:1036600002170050000000900217005400800090E4
+:103670000217005808100000021700700000000632
+:1036800002170078000009FF0217007C0000076C99
+:10369000021701C4081000000217034400000001D3
+:1036A000021704000000008A0217040400000080D2
+:1036B00002170408000000810217040C00000080BB
+:1036C000021704100000008A021704140000008092
+:1036D00002170418000000810217041C000000807B
+:1036E000021704300000008A021704340000008032
+:1036F00002170438000000810217043C000000801B
+:10370000021704400000008A0217044400000080F1
+:1037100002170448000000810217044C00000080DA
+:10372000021704800000008A021704840000008051
+:1037300002170488000000810217048C000000803A
+:1037400002170038007C1004021700040000000F6C
+:10375000021701EC00000002021701F40000000251
+:10376000021701EC00000002021701F40000000241
+:10377000021701EC00000002021701F40000000231
+:10378000021701EC00000002021701F40000000221
+:10379000021701EC00000002021701F40000000211
+:1037A000021701EC00000002021701F40000000201
+:1037B000021701EC00000002021701F400000002F1
+:1037C000021701EC00000002021701F400000002E1
+:1037D0000616402400000002021640700000001C83
+:1037E000021642080000000102164210000000010B
+:1037F00002164220000000010216422800000001CB
+:10380000021642300000000102164238000000019A
+:1038100002164260000000020C16401C0003D0900B
+:103820000A16401C0000009C0B16401C0000027190
+:103830000216403000000028021640340000002C20
+:1038400002164038000000300216404400000020FC
+:103850000216400000000001021640D800000001DE
+:1038600002164008000000010216400C0000000192
+:103870000216401000000001021642400000000045
+:1038800002164248000000000616427000000002C6
+:1038900002164250000000000216425800000000CC
+:1038A0000616428000000002021660080000121492
+:1038B0000216600C000012000216601000001204D4
+:1038C0000216601C0000FFFF021660200000FFFFD0
+:1038D000021660240000FFFF021660280000FFFFB0
+:1038E00002166038000000200216603C0000001044
+:1038F0000616604000000002021660480000002327
+:103900000216604C000000240216605000000025E2
+:1039100002166054000000260216605800000027BE
+:103920000216605C000000110216606000000000DA
+:10393000021660640000002B021660680000002C74
+:103940000216606C0000002D02166070000000EC92
+:103950000216607400000000021660780000002962
+:103960000216607C0000002A021660800000002F12
+:10397000061660840000000D021660B80000000109
+:10398000061660BC00000008021660DC00000001A2
+:10399000061660E000000004021660F0000000015E
+:1039A000061660F40000000302166100000000012A
+:1039B000061661040000002D021661B80000000127
+:1039C000061661BC00000008021661DC0000000160
+:1039D000061661E000000004021661F0000000011C
+:1039E000061661F4000000030216620000000001E8
+:1039F000061662040000000D0216623807FFFFFF82
+:103A00000216623C0000007F0216624007FFFFFFC3
+:103A1000021662440000003F0116624800000000E8
+:103A20000116624C00000000011662500000000008
+:103A300001166254000000000116625800000000E8
+:103A40000116625C000000000116626000000000C8
+:103A500001166264000000000116626800000000A8
+:103A60000116626C00000000011662700000000088
+:103A70000116627400000000011662780000000068
+:103A80000116627C00000000011662D400000000F4
+:103A9000021662D80000FFFF021662DC0000FFFF82
+:103AA000021662E00000FFFF021662E40000FFFF62
+:103AB0000C166000000003E80A1660000000000118
+:103AC0000B16600000000003021680400000000694
+:103AD0000216804400000005021680480000000A1B
+:103AE0000216804C000000050216805400000002FF
+:103AF000021680CC00000004021680D000000004F2
+:103B0000021680D400000004021680D800000004D1
+:103B1000021680DC00000004021680E000000004B1
+:103B2000021680E400000004021680E80000000491
+:103B30000216880400000006021680300000007C97
+:103B4000021680340000003D021680380000003F5D
+:103B50000216803C0000009C0216E6E800006000AF
+:103B60000216E6EC000060000216E6F000006000BD
+:103B70000216E6F40000600002168234000025E41C
+:103B8000021682380000800002168094000025E3AF
+:103B9000021681F400000C08021681F800000040B3
+:103BA000021681FC000001000216820000000020C5
+:103BB000021682040000001702168208000000802E
+:103BC0000216820C000002000216821000000000A3
+:103BD0000216823C0000001302168220008F008F24
+:103BE0000216821C008F008F021680F00000000772
+:103BF0000216821801FF01FF0216821401FF01FF65
+:103C0000061680F4000000020216811C0000000568
+:103C10000216812000000005021681240000000524
+:103C200002168128000000080216812C0000000600
+:103C300002168130000000070616813400000004DF
+:103C4000021680FC000000000616814400000002FD
+:103C50000216814C00000004021681500000000191
+:103C6000021681540000000202168158000000056F
+:103C70000216815C0000000502168160000000054C
+:103C80000216816400000005021681680000000829
+:103C900002168100000000000216816C0000000680
+:103CA00002168170000000070616817400000006ED
+:103CB0000216818C000000040216819000000001B1
+:103CC0000216810400000000021681940000000228
+:103CD00002168198000000050216819C0000000574
+:103CE000021681A000000005021681A40000000554
+:103CF000021681A800000008021681AC0000000630
+:103D0000021681B000000007061681B40000000210
+:103D10000216810800000000061681BC00000004A5
+:103D2000021681CC00000004021681D000000001C0
+:103D3000021681D400000002021681D8000000059E
+:103D4000021681DC00000005021681E0000000057B
+:103D50000216810C00000004021681E40000000538
+:103D6000021681E800000008021681EC000000063F
+:103D7000021681F000000007021681100000000109
+:103D800002168114000000020216811800000005CE
+:103D90000216809C0000004C021680A00000004C1F
+:103DA000061680C400000002021680A40000000075
+:103DB000021680A800000000021680AC0000004C33
+:103DC000061680B0000000050216E6F800000204A6
+:103DD00002168240003F003F02168244003F003F2F
+:103DE00006168290000000040216824800800080BF
+:103DF0000216824C008000800216825001000100F1
+:103E000002168254010001000616825800000002CA
+:103E100002168260004000400216826400400040AA
+:103E2000021682681E001E000216826C1E001E0012
+:103E3000021682704000400002168274400040006A
+:103E400002168278800080000216827C800080004A
+:103E500002168280200020000216828420002000AA
+:103E60000616828800000002021680900000004BB7
+:103E700002168060000001400216806400000140CC
+:103E8000061680880000000202168068000000000C
+:103E90000216806C0000000002168070000000C056
+:103EA00006168074000000050216880C010101014D
+:103EB000021688100101200402168814200810013F
+:103EC00002168818010101200216881C0101010157
+:103ED00002168820010120040216882420081001FF
+:103EE00002168828010101200216882C20081001E2
+:103EF00002168830010101200216883401010101F7
+:103F000002168838010120040216883C200810019E
+:103F100002168840010101200216884401010101B6
+:103F200002168848010120040216E6BC00000000C9
+:103F30000216E6C0000000020216E6C400000004FB
+:103F40000216E6C8000000060216E7940000000111
+:103F5000021680EC000000FF0214000000000001C7
+:103F60000215C024000000000215C0EC0000000192
+:103F70000215C0F0000000010615C100000000029B
+:103F800002140004000000010214000800000001F7
+:103F90000214000C000000010214003000000001B7
+:103FA000021400340000000102140040000000016F
+:103FB000021400440000FFFF061400040000000388
+:103FC0000214000000000000060280000000200033
+:103FD0000202005800000032020200A00315002077
+:103FE000020200A403150020020200A80100003014
+:103FF000020200AC08100000020200B0000000360F
+:10400000020200B400000030020200B800000031DB
+:10401000020200BC00000002020200C00000000515
+:10402000020200C400000002020200C800000002F8
+:10403000020200D000000007020200DC00000000C5
+:10404000020200E000000005020200E4000000039C
+:10405000020200F000000001020200FC0000000665
+:1040600002020120000000000202013400000002F0
+:10407000020201B0000000010202020C0000000177
+:1040800002020214000000010202021800000002F5
+:1040900002020404000000010202040C00000040BF
+:1040A00002020410000000400202041C0000000490
+:1040B000020204200000002002020424000000028A
+:1040C0000202042800000020060205000000001281
+:1040D00004020480002008BF020200600000000FFC
+:1040E00002020064000000070202006800000000F5
+:1040F0000202006C0000000E020200700000000EC0
+:104100000602007400000003020200F40000000434
+:104110000202000400000001020200080000000189
+:104120000202000C00000001020200100000000169
+:104130000202001400000001020200180000000149
+:104140000202001C00000001020200200000000129
+:104150000202002400000001020200280000000109
+:104160000202002C000000010202003000000001E9
+:1041700002020034000000010202003800000001C9
+:104180000202003C000000010202004000000001A9
+:104190000202004400000001020200480000000189
+:1041A0000202004C00000001020200500000000169
+:1041B00002020108000000C802020118000000020B
+:1041C000020201C400000000020201CC0000000055
+:1041D000020201D400000002020201DC0000000221
+:1041E000020201E4000000FF020201EC000000FFF7
+:1041F00002020100000000000202010C000000C8E1
+:104200000202011C00000002020201C800000000BE
+:10421000020201D000000000020201D800000002EA
+:10422000020201E000000002020201E8000000FFBB
+:10423000020201F0000000FF020201040000002061
+:1042400002020108000000C802020118000000027A
+:10425000020201C400000000020201CC00000000C4
+:10426000020201D400000002020201DC0000000290
+:10427000020201E4000000FF020201EC000000FF66
+:1042800002020100000000100202010C000000C840
+:104290000202011C00000002020201C8000000002E
+:1042A000020201D000000000020201D8000000025A
+:1042B000020201E000000002020201E8000000FF2B
+:1042C000020201F0000000FF0202010400000030C1
+:1042D00002020108000000C80202011800000002EA
+:1042E000020201C400000000020201CC0000000034
+:1042F000020201D400000002020201DC0000000200
+:10430000020201E4000000FF020201EC000000FFD5
+:1043100002020100000000400202010C000000C87F
+:104320000202011C00000002020201C8000000009D
+:10433000020201D000000000020201D800000002C9
+:10434000020201E000000002020201E8000000FF9A
+:10435000020201F0000000FF020201040000006000
+:1043600002020108000000C8020201180000000259
+:10437000020201C400000000020201CC00000000A3
+:10438000020201D400000002020201DC000000026F
+:10439000020201E4000000FF020201EC000000FF45
+:1043A00002020100000000500202010C000000C8DF
+:1043B0000202011C00000002020201C8000000000D
+:1043C000020201D000000000020201D80000000239
+:1043D000020201E000000002020201E8000000FF0A
+:1043E000020201F0000000FF020201040000007060
+:1043F0000728040000B50000082807B8000908DFF6
+:10440000072C000028C30000072C800036720A31F8
+:10441000072D000035B617CE072D80003B00253C48
+:10442000072E0000366D33FD072E80001AA8419933
+:10443000082EBF20281C08E1012800000000000011
+:10444000012800040000000001280008000000000E
+:104450000128000C000000000128001000000000EE
+:1044600001280014000000000228002000000001C4
+:104470000228002400000002022800280000000397
+:104480000228002C00000000022800300000000478
+:10449000022800340000000102280038000000005B
+:1044A0000228003C00000001022800400000000437
+:1044B000022800440000000002280048000000011B
+:1044C0000228004C000000030228005000000000F9
+:1044D00002280054000000010228005800000004D7
+:1044E0000228005C000000000228006000000001BB
+:1044F0000228006400000003022800680000000099
+:104500000228006C00000001022800700000000476
+:104510000228007400000000022800780000000457
+:104520000228007C00000003062800800000000232
+:10453000022800A400007FFF022800A8000003FF5B
+:1045400002280224000000000228023400000000BB
+:104550000228024C00000000022802E40000FFFFD5
+:104560000628200000000800022B8BC0000000017C
+:10457000022B800000000000022B80400000001889
+:10458000022B80800000000C022B80C0000000661F
+:104590000C2B8300000864700A2B83000000015775
+:1045A0000B2B83000000055F0A2B834000000000F6
+:1045B0000C2B8340000002260B2B834000000001DF
+:1045C000022B838000086470022B83C00000022647
+:1045D000022B1480000000010A2B14800000000050
+:1045E000022B944000000001062B944800000002BA
+:1045F000062A9A7000000004042A9A80000408E346
+:10460000062A9A9000000002042A9A98000208E7FD
+:10461000062A900000000048062A2008000000C872
+:10462000062A200000000002062A912800000086C9
+:10463000062AC00000000120062A9348000000035B
+:10464000042A9354000108E9062A9FB000000002E2
+:10465000042A9418000208EA042A9CD0000108ECFD
+:10466000062A9CD400000011042A9D20008F08ED2A
+:10467000062A9F5C00000005042A30000002097C25
+:10468000062A300800000100062A40400000001001
+:10469000042A40000010097E042A84080002098EC2
+:1046A000042ACF4000040990042ACF600002099434
+:1046B000062A9FA000000004062A600000000540B2
+:1046C000062A9D1800000002062AB00000000050D3
+:1046D000062ABB7000000070062ABB6800000002BA
+:1046E000062AB94800000004062AD000000008008D
+:1046F000062AC48000000150062A942000000032DF
+:10470000062A502000000002062A50300000000255
+:10471000062A500000000002062A50100000000285
+:10472000022A520800000001042A9AA000020996F9
+:10473000062A95B000000022042A96380001099844
+:10474000062A963C00000003062A96E0000000229C
+:10475000042A976800010999062A976C0000000353
+:10476000062A981000000022042A98980001099A4D
+:10477000062A989C00000003062A994000000022A7
+:10478000042A99C80001099B062A99CC000000035D
+:10479000062ABB5800000002062AC9C000000150CA
+:1047A000062A94E800000032062A50280000000281
+:1047B000062A503800000002062A500800000002B5
+:1047C000062A501800000002022A520C00000001C4
+:1047D000042A9AA80002099C062A96480000002292
+:1047E000042A96D00001099E062A96D400000003F0
+:1047F000062A977800000022042A98000001099FE9
+:10480000062A980400000003062A98A80000002247
+:10481000042A9930000109A0062A993400000003F7
+:10482000062A99D800000022042A9A60000109A1F2
+:10483000062A9A6400000003062ABB6000000002FA
+:10484000022ACF0000000000042A9AB0001009A23A
+:10485000062A50480000000E022ACF040000000083
+:10486000042A9AF0001009B2062A50800000000EB7
+:10487000022ACF0800000000042A9B30001009C261
+:10488000062A50B80000000E022ACF0C00000000DB
+:10489000042A9B70001009D2062A50F00000000E76
+:1048A000022ACF1000000000042A9BB0001009E289
+:1048B000062A51280000000E022ACF140000000032
+:1048C000042A9BF0001009F2062A51600000000E35
+:1048D000022ACF1800000000042A9C3000100A02AF
+:1048E000062A51980000000E022ACF1C000000008A
+:1048F000042A9C7000100A12062A51D00000000EF3
+:104900000210100800000001021010500000000109
+:10491000021010000003D000021010040000003D3F
+:104920000910180002000A220910110000100C22C0
+:1049300006101140000000080910116000100C3230
+:10494000061011A00000001806102400000000E06E
+:104950000210201C000000000210202000000001B6
+:10496000021020C00000000202102004000000011C
+:104970000210200800000001021030D800000001E1
+:1049800009103C0000050C420910380000050C47D6
+:104990000910392000050C4C09103B0000050C5192
+:1049A00006104C000000010002104028000000101A
+:1049B0000210404400003FFF021040580028000051
+:1049C000021040840084924A021040580000000007
+:1049D00002104138000000010210413800000001BF
+:1049E00002104138000000010210413800000001AF
+:1049F000021041380000000102104138000000019F
+:104A0000021041380000000102104138000000018E
+:104A10000212049001F680400212051400003C10BE
+:104A200002120494FFFFFFFF02120498FFFFFFFF32
+:104A30000212049CFFFFFFFF021204A0FFFFFFFF12
+:104A4000021204A4FFFFFFFF021204A8FFFFFFFFF2
+:104A5000021204ACFFFFFFFF021204B0FFFFFFFFD2
+:104A6000021204B8FFFFFFFF021204BCFFFFFFFFAA
+:104A7000021204C0FFFFFFFF021204C4FFFFFFFF8A
+:104A8000021204C8FFFFFFFF021204CCFFFFFFFF6A
+:104A9000021204D0FFFFFFFF021204D8FFFFFFFF46
+:104AA000021204DCFFFFFFFF021204E0FFFFFFFF22
+:104AB000021204E4FFFFFFFF021204E8FFFFFFFF02
+:104AC000021204ECFFFFFFFF021204F0FFFFFFFFE2
+:104AD000021204F4FFFFFFFF021204F8FFFFFFFFC2
+:104AE000021204FCFFFFFFFF02120500FFFFFFFFA1
+:104AF00002120504FFFFFFFF02120508FFFFFFFF80
+:104B00000212050CFFFFFFFF02120510FFFFFFFF5F
+:104B1000021204D4F800C000021204B4F0005000E5
+:104B200002120390000000080212039C000000081B
+:104B3000021203A000000008021203A400000002F9
+:104B4000021203BC00000004021203C000000005B2
+:104B5000021203C400000004021203D0000000008F
+:104B60000212036C00000001021201BC00000040B0
+:104B7000021201C000001808021201C4000008035C
+:104B8000021201C800000803021201CC000000401C
+:104B9000021201D000000003021201D40000080339
+:104BA000021201D800000803021201DC0000080311
+:104BB000021201E000010003021201E400000803F8
+:104BC000021201E800000803021201EC00000003D9
+:104BD000021201F000000003021201F400000003C1
+:104BE000021201F800000003021201FC00000003A1
+:104BF000021202000000000302120204000000037F
+:104C000002120208000000030212020C000000035E
+:104C1000021202100000000302120214000000033E
+:104C200002120218000000030212021C000000031E
+:104C300002120220000000030212022400000003FE
+:104C400002120228000024030212022C0000002F8E
+:104C500002120230000000090212023400000019A2
+:104C600002120238000001840212023C000001839B
+:104C70000212024000000306021202440000001962
+:104C800002120248000000060212024C0000030655
+:104C90000212025000000306021202540000030632
+:104CA0000212025800000C860212025C0000030689
+:104CB00002120260000003060212026400000006F5
+:104CC00002120268000000060212026C00000006D8
+:104CD00002120270000000060212027400000006B8
+:104CE00002120278000000060212027C0000000698
+:104CF0000212028000000006021202840000000678
+:104D000002120288000000060212028C0000000657
+:104D10000212029000000006021202940000000637
+:104D200002120298000000060212029C0000000617
+:104D3000021202A000000306021202A400000013E7
+:104D4000021202A800000006021202B000001004C5
+:104D5000021202B400001004021203240010644086
+:104D60000212032800106440021205B40000000182
+:104D7000021205F800000040021205FC00000019B4
+:104D800002120600000000010212066C0000000181
+:104D9000021201B000000001021207D80000000357
+:104DA000021207D800000003021207D80000000317
+:104DB000021207D800000003021207D80000000307
+:104DC000021207D800000003021207D800000003F7
+:104DD000021207D8000000030600A0000000000C2B
+:104DE0000200A050000000000200A05400000000DB
+:104DF0000200A0EC555400000200A0F05555555596
+:104E00000200A0F4000055550200A0F8F0000000D8
+:104E10000200A0FC555400000200A1005555555554
+:104E20000200A104000055550200A108F000000096
+:104E30000200A19C000000000200A1A000010000EF
+:104E40000200A1A4000050140200A1A8000000006C
+:104E50000200A6A8000000000200A6AC00000000AE
+:104E60000200A6D0000000000200A45C00000C00BC
+:104E70000200A61C000000030200A070FFF55FFF07
+:104E80000200A0740000FFFF0200A078F00003E021
+:104E90000200A07C000000000200A0800000A00032
+:104EA0000600A084000000050200A0980FE00000AA
+:104EB0000600A09C000000070200A0B8000004004B
+:104EC0000600A0BC000000030200A0C80000100003
+:104ED0000600A0CC000000030200A0D800004000A3
+:104EE0000600A0DC000000030200A0E800010000B2
+:104EF0000600A22C000000040200A688000000FCAE
+:104F00000600A68C000000070200A6F400000000C6
+:104F10000200A10CFF5C00000200A110FFF55FFF82
+:104F20000200A1140000FFFF0200A118F00003E03E
+:104F30000200A11C000000000200A1200000A0004F
+:104F40000600A124000000050200A1380FE00000C7
+:104F50000600A13C000000070200A1580000080064
+:104F60000600A15C000000030200A1680000200010
+:104F70000600A16C000000030200A1780000800080
+:104F80000600A17C000000030200A18800020000CE
+:104F90000600A23C000000040200A6B0000000FCD5
+:104FA0000600A6B4000000070200A6F800000000FA
+:104FB0000200A030000000000200A0340000000049
+:104FC0000200A038000000000200A03C0000000029
+:104FD0000200A040000000000200A0440000000009
+:104FE0000200A048000000000200A04C00000000E9
+:104FF000020090C40000E000020090CC0000F3002A
+:10500000020090D400000003020091A00000000103
+:105010000600917000000003020090EC00006000A8
+:10502000020090F400007300020090FC00000003F6
+:10503000020091A800000001060091880000000312
+:10504000020091000000400002009108000053009F
+:105050000200911000000004020091AC0000000169
+:1050600006009194000000020200919C00000001E3
+:10507000020090D800006000020090E00000730081
+:10508000020090E800000003020091A4000000016B
+:105090000200917C000000010200918000000001EC
+:1050A000020091840000000002009128000003002B
+:1050B0000200916C0003F0080200912C0000030034
+:1050C0000200913000000300020091340000030050
+:1050D00002009138000003000200913C0000030030
+:1050E00002009140000003000200942C0000000127
+:1050F000020094300000000102009434000000011E
+:105100000200942C00000001020094300000000115
+:1051100002009434000000010200942C0000000101
+:1051200002009430000000010200943400000001ED
+:105130000200942C000000010200943000000001E5
+:1051400002009434000000010200942C00000001D1
+:1051500002009430000000010200943400000001BD
+:105160000200942C000000010200943000000001B5
+:1051700002009434000000010200942C00000001A1
+:10518000020094300000000102009434000000018D
+:105190000200942C00000001020094300000000185
+:1051A00002009434000000010213003C000061A8DA
+:1051B00006130108000000030213010400000000B0
+:1051C0000213013400000000061301080000000370
+:1051D000021301040000000002130134000000006B
+:1051E0000613010800000003021301040000000080
+:1051F0000213013400000000061301080000000340
+:10520000021301040000000002130134000000003A
+:10521000061301080000000302130104000000004F
+:10522000021301340000000006130108000000030F
+:10523000021301040000000002130134000000000A
+:10524000061301080000000302130104000000001F
+:1052500002130134000000000613010800000003DF
+:1052600002130104000000000213013400000000DA
+:10527000021100B8000000010216E6E8000020005C
+:105280000216E6EC000020000216E6F0000065556C
+:105290000216E6F400006555021681500000000079
+:1052A00002168174000000010216817800000001DE
+:1052B0000216817C000000010216818000000001BE
+:1052C000021681840000000102168188000000019E
+:1052D000021681B400000001021681B8000000012E
+:1052E000021681BC00000001021681C0000000010E
+:1052F000021681C400000001021681C800000001EE
+:1053000002168110000000000216824000BF00BF9C
+:1053100006168244000000020216824C00BF00BF45
+:105320000216E6C4000000010216E6C800000003F1
+:105330000216E79400000000042ACF40000A0C5631
+:105340000000000000000000000000340000000029
+:10535000000000000000000000000000000000004D
+:10536000000000000000000000000000000000003D
+:1053700000000000003400350000000000000000C4
+:10538000000000000000000000000000000000001D
+:10539000000000000000000000000000000000000D
+:1053A0000035006000000000000000000000000068
+:1053B00000000000000000000000000000000000ED
+:1053C00000000000000000000000000000600091EC
+:1053D0000000000000000000009100950095009979
+:1053E0000099009D009D00A100A100A500A500A9B5
+:1053F00000A900AD00AD00B100B100B50000000093
+:10540000000000000000000000000000000000009C
+:10541000000000000000000000000000000000008C
+:105420000000000000B503100310031A031A032440
+:105430000324032B032B03320332033903390340C4
+:10544000034003470347034E034E03550355035CD4
+:10545000000000000000000000000000000000004C
+:10546000000000000000000000000000000000003C
+:10547000000000000000000000000000000000002C
+:10548000000000000000000000000000000000001C
+:10549000000000000000000000000000000000000C
+:1054A00000000000000000000000000000000000FC
+:1054B00000000000000000000000000000000000EC
+:1054C00000000000000000000000000000000000DC
+:1054D00000000000000000000000000000000000CC
+:1054E00000000000000000000000000000000000BC
+:1054F00000000000000000000000000000000000AC
+:10550000035C035D0000000000000000035D035E1B
+:10551000035E035F035F0360036003610361036273
+:105520000362036303630364036403650000000014
+:10553000000000000000000000000000000000006B
+:10554000000000000000000000000000000000005B
+:1055500000000000000000000365036C036C03788A
+:105560000378038400000000000000000000000039
+:10557000000000000000000000000000000000002B
+:10558000000000000000000000000000000000001B
+:10559000000000000000000000000000000000000B
+:1055A00000000000000000000000000000000000FB
+:1055B00003840385000000000000000000000000DC
+:1055C00000000000000000000000000000000000DB
+:1055D000000000000000000000000000038503B090
+:1055E00000000000000000000000000000000000BB
+:1055F00000000000000000000000000000000000AB
+:10560000000000000000000003B003DF0000000005
+:10561000000000000000000000000000000000008A
+:10562000000000000000000000000000000000007A
+:105630000000000003DF040E000000000000000076
+:10564000040E04150415041C041C04230423042A5A
+:10565000042A0431043104380438043F043F04466A
+:105660000446047900000000000000000479047D75
+:10567000047D048104810485048504890489048DE2
+:10568000048D04910491049504950499049904E807
+:1056900004E804FE04FE0514051405160516051895
+:1056A0000518051A051A051C051C051E051E0520F2
+:1056B000052005220522052405240690000000008F
+:1056C00000000000069006950695069A069A069F29
+:1056D000069F06A406A406A906A906AE06AE06B352
+:1056E00006B306B806B806B90000000000000000C6
+:1056F00000000000000000000000000000000000AA
+:105700000000000000000000000000000000000099
+:1057100006B906DD000000000000000006DD06DF1F
+:1057200006DF06E106E106E306E306E506E506E731
+:1057300006E706E906E906EB06EB06ED06ED0702CD
+:105740000702070507050708000000000000000029
+:105750000000000000000000000000000000000049
+:1057600000000000000000000708074C00000000D7
+:105770000000000000000000000000000000000029
+:105780000000000000000000000000000000000019
+:1057900000000000074C07DE0000000000000000D1
+:1057A00000000000000000000000000000000000F9
+:1057B00000000000000000000000000000000000E9
+:1057C00007DE07EC00000000000000000000000001
+:1057D00000000000000000000000000000000000C9
+:1057E00000000000000000000000000007EC082995
+:1057F0000000000000000000082908320832083BC1
+:10580000083B08440844084D084D08560856085FF0
+:10581000085F086808680871087108D108D108E6AF
+:1058200008E608FB08FB08FE08FE09010901090457
+:10583000090409070907090A090A090D090D0910D0
+:10584000091009130913091C0000000000000000E2
+:105850000000000000000000000000000000000048
+:105860000000000000000000000000000000000038
+:10587000091C0922000000000000000000000000D8
+:105880000000000000000000000000000000000018
+:1058900000000000000000000000000009220927AD
+:1058A00000000000000000000000000000000000F8
+:1058B00000000000000000000000000000000000E8
+:1058C00000000000000000000927092D0000000072
+:1058D00000000000092D092E092E092F092F09307B
+:1058E00009300931093109320932093309330934E0
+:1058F000093409350000000000000000000000002D
+:105900000000000000000000000000000000000097
+:105910000000000000000000000000000000000087
+:10592000093509A6000000000000000009A609A72B
+:1059300009A709A809A809A909A909AA09AA09ABD7
+:1059400009AB09AC09AC09AD09AD09AE09AE09C294
+:1059500009C209D509D509E909E909EA09EA09EB02
+:1059600009EB09EC09EC09ED09ED09EE09EE09EF87
+:1059700009EF09F009F009F109F10A10000000002F
+:10598000000000000A100A130A130A160A160A1960
+:105990000A190A1C0A1C0A1F0A1F0A220A220A25BF
+:1059A0000A250A280A280A29000000000000000031
+:1059B0000A290A2C0A2C0A2F0A2F0A320A320A351F
+:1059C0000A350A380A380A3B0A3B0A3E0A3E0A41AF
+:1059D0000A410A4200000000000000000000000030
+:1059E00000000000000000000000000000000000B7
+:1059F0000000000000000000000000000A420A5AF7
+:105A00000000000000000000000000000000000096
+:105A10000000000000000000000000000000000086
+:105A200000000000000000000A5A0A5B00000000AD
+:105A30000000000000000000000000000000000066
+:105A40000000000000000000000000000000000056
+:105A5000000000000000000000010000000207003C
+:105A600000030E000004150000051C0000062300C2
+:105A700000072A000008310000093800000A3F0032
+:105A8000000B4600000C4D00000D5400000E5B00A2
+:105A9000000F620000106900001170000012770012
+:105AA00000137E000014850000158C000016930082
+:105AB00000179A000018A1000019A800001AAF00F2
+:105AC000001BB600001CBD00001DC400001ECB0062
+:105AD000001FD2000000D90000002000000040009C
+:105AE00000006000000080000000A0000000C00076
+:105AF0000000E00000010000000120000001400063
+:105B000000016000000180000001A0000001C00051
+:105B10000001E0000002000000022000000240003E
+:105B200000026000000280000002A0000002C0002D
+:105B30000002E0000003000000032000000340001A
+:105B400000036000000380000003A0000003C00009
+:105B50000003E000000400000004200000044000F6
+:105B600000046000000480000004A0000004C000E5
+:105B70000004E000000500000005200000054000D2
+:105B800000056000000580000005A0000005C000C1
+:105B90000005E000000600000006200000064000AE
+:105BA00000066000000680000006A0000006C0009D
+:105BB0000006E0000007000000072000000740008A
+:105BC00000076000000780000007A0000007C00079
+:105BD0000007E00000080000000820000008400066
+:105BE00000086000000880000008A0000008C00055
+:105BF0000008E00000090000000920000009400042
+:105C000000096000000980000009A0000009C00030
+:105C10000009E000000A0000000A2000000A40001D
+:105C2000000A6000000A8000000AA000000AC0000C
+:105C3000000AE000000B0000000B2000000B4000F9
+:105C4000000B6000000B8000000BA000000BC000E8
+:105C5000000BE000000C0000000C2000000C4000D5
+:105C6000000C6000000C8000000CA000000CC000C4
+:105C7000000CE000000D0000000D2000000D4000B1
+:105C8000000D6000000D8000000DA000000DC000A0
+:105C9000000DE000000E0000000E2000000E40008D
+:105CA000000E6000000E8000000EA000000EC0007C
+:105CB000000EE000000F0000000F2000000F400069
+:105CC000000F6000000F8000000FA000000FC00058
+:105CD000000FE00000100000001020000010400045
+:105CE00000106000001080000010A0000010C00034
+:105CF0000010E00000110000001120000011400021
+:105D000000116000001180000011A0000011C0000F
+:105D10000011E000001200000012200000124000FC
+:105D200000126000001280000012A0000012C000EB
+:105D30000012E000001300000013200000134000D8
+:105D400000136000001380000013A0000013C000C7
+:105D50000013E000001400000014200000144000B4
+:105D600000146000001480000014A0000014C000A3
+:105D70000014E00000150000001520000015400090
+:105D800000156000001580000015A0000015C0007F
+:105D90000015E0000016000000162000001640006C
+:105DA00000166000001680000016A0000016C0005B
+:105DB0000016E00000170000001720000017400048
+:105DC00000176000001780000017A0000017C00037
+:105DD0000017E00000180000001820000018400024
+:105DE00000186000001880000018A0000018C00013
+:105DF0000018E00000190000001920000019400000
+:105E000000196000001980000019A0000019C000EE
+:105E10000019E000001A0000001A2000001A4000DB
+:105E2000001A6000001A8000001AA000001AC000CA
+:105E3000001AE000001B0000001B2000001B4000B7
+:105E4000001B6000001B8000001BA000001BC000A6
+:105E5000001BE000001C0000001C2000001C400093
+:105E6000001C6000001C8000001CA000001CC00082
+:105E7000001CE000001D0000001D2000001D40006F
+:105E8000001D6000001D8000001DA000001DC0005E
+:105E9000001DE000001E0000001E2000001E40004B
+:105EA000001E6000001E8000001EA000001EC0003A
+:105EB000001EE000001F0000001F2000001F400027
+:105EC000001F6000001F8000001FA000001FC00016
+:105ED000001FE00000200000002020000020400003
+:105EE00000206000002080000020A0000020C000F2
+:105EF0000020E000002100000021200000214000DF
+:105F000000216000002180000021A0000021C000CD
+:105F10000021E000002200000022200000224000BA
+:105F200000226000002280000022A0000022C000A9
+:105F30000022E00000230000002320000023400096
+:105F400000236000002380000023A0000023C00085
+:105F50000023E00000240000002420000024400072
+:105F600000246000002480000024A0000024C00061
+:105F70000024E0000025000000252000002540004E
+:105F800000256000002580000025A0000025C0003D
+:105F90000025E0000026000000262000002640002A
+:105FA00000266000002680000026A0000026C00019
+:105FB0000026E00000270000002720000027400006
+:105FC00000276000002780000027A0000027C000F5
+:105FD0000027E000002800000028200000284000E2
+:105FE00000286000002880000028A0000028C000D1
+:105FF0000028E000002900000029200000294000BE
+:1060000000296000002980000029A0000029C000AC
+:106010000029E000002A0000002A2000002A400099
+:10602000002A6000002A8000002AA000002AC00088
+:10603000002AE000002B0000002B2000002B400075
+:10604000002B6000002B8000002BA000002BC00064
+:10605000002BE000002C0000002C2000002C400051
+:10606000002C6000002C8000002CA000002CC00040
+:10607000002CE000002D0000002D2000002D40002D
+:10608000002D6000002D8000002DA000002DC0001C
+:10609000002DE000002E0000002E2000002E400009
+:1060A000002E6000002E8000002EA000002EC000F8
+:1060B000002EE000002F0000002F2000002F4000E5
+:1060C000002F6000002F8000002FA000002FC000D4
+:1060D000002FE000003000000030200000304000C1
+:1060E00000306000003080000030A0000030C000B0
+:1060F0000030E0000031000000312000003140009D
+:1061000000316000003180000031A0000031C0008B
+:106110000031E00000320000003220000032400078
+:1061200000326000003280000032A0000032C00067
+:106130000032E00000330000003320000033400054
+:1061400000336000003380000033A0000033C00043
+:106150000033E00000340000003420000034400030
+:1061600000346000003480000034A0000034C0001F
+:106170000034E0000035000000352000003540000C
+:1061800000356000003580000035A0000035C000FB
+:106190000035E000003600000036200000364000E8
+:1061A00000366000003680000036A0000036C000D7
+:1061B0000036E000003700000037200000374000C4
+:1061C00000376000003780000037A0000037C000B3
+:1061D0000037E000003800000038200000384000A0
+:1061E00000386000003880000038A0000038C0008F
+:1061F0000038E0000039000000392000003940007C
+:1062000000396000003980000039A0000039C0006A
+:106210000039E000003A0000003A2000003A400057
+:10622000003A6000003A8000003AA000003AC00046
+:10623000003AE000003B0000003B2000003B400033
+:10624000003B6000003B8000003BA000003BC00022
+:10625000003BE000003C0000003C2000003C40000F
+:10626000003C6000003C8000003CA000003CC000FE
+:10627000003CE000003D0000003D2000003D4000EB
+:10628000003D6000003D8000003DA000003DC000DA
+:10629000003DE000003E0000003E2000003E4000C7
+:1062A000003E6000003E8000003EA000003EC000B6
+:1062B000003EE000003F0000003F2000003F4000A3
+:1062C000003F6000003F8000003FA000003FC00092
+:1062D000003FE000003FE00100000000000001FF7F
+:1062E0000000020000007FF800007FF800000A9420
+:1062F00000001500000000010000FF000000000089
+:106300000000FF00000000000000FF00000000008F
+:106310000000FF00000000000000FF00000000007F
+:106320000000FF00000000000000FF00000000006F
+:106330000000FF00000000000000FF00000000005F
+:106340000000FF00000000000000FF00000000004F
+:106350000000FF00000000000000FF00000000003F
+:106360000000FF00000000000000FF00000000002F
+:106370000000FF00000000000000FF00000000001F
+:106380000000FF00000000000000FF00000000000F
+:106390000000FF00000000000000FF0000000000FF
+:1063A0000000FF00000000000000FF0000000000EF
+:1063B0000000FF00000000000000FF0000000000DF
+:1063C0000000FF00000000000000FF0000000000CF
+:1063D0000000FF00000000000000FF0000000000BF
+:1063E0000000FF00000000000000FF0000000000AF
+:1063F0000000FF00000000000000FF00000000009F
+:106400000000FF00000000000000FF00000000008E
+:106410000000FF00000000000000FF00000000007E
+:106420000000FF00000000000000FF00000000006E
+:106430000000FF00000000000000FF00000000005E
+:106440000000FF00000000000000FF00000000004E
+:106450000000FF00000000000000FF00000000003E
+:106460000000FF00000000000000FF00000000002E
+:106470000000FF00000000000000FF00000000001E
+:106480000000FF00000000000000FF00000000000E
+:106490000000FF00000000000000FF0000000000FE
+:1064A0000000FF00000000000000FF0000000000EE
+:1064B0000000FF00000000000000FF0000000000DE
+:1064C0000000FF00000000000000FF0000000000CE
+:1064D0000000FF00000000000000FF0000000000BE
+:1064E0000000FF00000000000000FF0000000000AE
+:1064F0000000FF00000000000000FF00000000009E
+:106500000000FF00000000000000FF00000000008D
+:106510000000FF00000000000000FF00000000007D
+:106520000000FF00000000000000FF00000000006D
+:106530000000FF000000000000000000140AFF003F
+:106540000000000100000000002010010000000019
+:106550000100900000000100000090020000900483
+:1065600000009006000090080000900A0000900CC7
+:106570000000900E00009010000090120000901497
+:1065800000009016000090180000901A0000901C67
+:106590000000901E00009020000090220000902437
+:1065A00000009026000090280000902A0000902C07
+:1065B0000000902E000090300000903200009034D7
+:1065C00000009036000090380000903A0000903CA7
+:1065D0000000903E00009040000090420000904477
+:1065E00000009046000090480000904A0000904C47
+:1065F0000000904E00009050000090520000905417
+:1066000000009056000090580000905A0000905CE6
+:106610000000905E000090600000906200009064B6
+:1066200000009066000090680000906A0000906C86
+:106630000000906E00009070000090720000907456
+:1066400000009076000090780000907A0000907C26
+:106650000000907E000090800000908200009084F6
+:1066600000009086000090880000908A0000908CC6
+:106670000000908E00009090000090920000909496
+:1066800000009096000090980000909A0000909C66
+:106690000000909E000090A0000090A2000090A436
+:1066A000000090A6000090A8000090AA000090AC06
+:1066B000000090AE000090B0000090B2000090B4D6
+:1066C000000090B6000090B8000090BA000090BCA6
+:1066D000000090BE000090C0000090C2000090C476
+:1066E000000090C6000090C8000090CA000090CC46
+:1066F000000090CE000090D0000090D2000090D416
+:10670000000090D6000090D8000090DA000090DCE5
+:10671000000090DE000090E0000090E2000090E4B5
+:10672000000090E6000090E8000090EA000090EC85
+:10673000000090EE000090F0000090F2000090F455
+:10674000000090F6000090F8000090FA000090FC25
+:10675000000090FE000091000000910200009104F2
+:1067600000009106000091080000910A0000910CC1
+:106770000000910E00009110000091120000911491
+:1067800000009116000091180000911A0000911C61
+:106790000000911E00009120000091220000912431
+:1067A00000009126000091280000912A0000912C01
+:1067B0000000912E000091300000913200009134D1
+:1067C00000009136000091380000913A0000913CA1
+:1067D0000000913E00009140000091420000914471
+:1067E00000009146000091480000914A0000914C41
+:1067F0000000914E00009150000091520000915411
+:1068000000009156000091580000915A0000915CE0
+:106810000000915E000091600000916200009164B0
+:1068200000009166000091680000916A0000916C80
+:106830000000916E00009170000091720000917450
+:1068400000009176000091780000917A0000917C20
+:106850000000917E000091800000918200009184F0
+:1068600000009186000091880000918A0000918CC0
+:106870000000918E00009190000091920000919490
+:1068800000009196000091980000919A0000919C60
+:106890000000919E000091A0000091A2000091A430
+:1068A000000091A6000091A8000091AA000091AC00
+:1068B000000091AE000091B0000091B2000091B4D0
+:1068C000000091B6000091B8000091BA000091BCA0
+:1068D000000091BE000091C0000091C2000091C470
+:1068E000000091C6000091C8000091CA000091CC40
+:1068F000000091CE000091D0000091D2000091D410
+:10690000000091D6000091D8000091DA000091DCDF
+:10691000000091DE000091E0000091E2000091E4AF
+:10692000000091E6000091E8000091EA000091EC7F
+:10693000000091EE000091F0000091F2000091F44F
+:10694000000091F6000091F8000091FA000091FC1F
+:10695000000091FEFFFFFFFFFFFFFFFFFFFFFFFFB4
+:10696000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37
+:10697000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27
+:10698000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF17
+:10699000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07
+:1069A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7
+:1069B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7
+:1069C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7
+:1069D000FFFFFFFF0000000300BEBC20000000001E
+:1069E000000000050000000300BEBC200000000005
+:1069F000000000050000000300BEBC2000000000F5
+:106A0000000000050000000300BEBC2000000000E4
+:106A1000000000050000000300BEBC2000000000D4
+:106A2000000000050000000300BEBC2000000000C4
+:106A3000000000050000000300BEBC2000000000B4
+:106A4000000000050000000300BEBC2000000000A4
+:106A50000000000500002000000040C00000618030
+:106A6000000082400000A3000000C3C00000E480DA
+:106A70000001054000012600000146C000016780BA
+:106A8000000188400001A9000001C9C00001EA809E
+:106A900000020B4000022C0000024CC000026D807E
+:106AA00000028E400002AF000002CFC00002F08062
+:106AB00000001140000080000001038000018700F9
+:106AC00000020A8000028E0000031180000395007E
+:106AD0000004188000049C0000051F800005A3002E
+:106AE000000626800006AA0000072D800007B100DE
+:106AF000000834800008B80000093B800009BF008E
+:106B0000000A4280000AC600000B4980000BCD003D
+:106B1000000C5080000CD400000D578000005B007A
+:106B200000007FF800007FF80000022A0000350016
+:106B30000000FF00000000000000FF000000000057
+:106B40000000FF00000000000000FF000000000047
+:106B50000000FF00000000000000FF000000000037
+:106B60000000FF00000000000000FF000000000027
+:106B70000000FF00000000000000FF000000000017
+:106B80000000FF00000000000000FF000000000007
+:106B90000000FF00000000000000FF0000000000F7
+:106BA0000000FF00000000000000FF0000000000E7
+:106BB0000000FF00000000000000FF0000000000D7
+:106BC0000000FF00000000000000FF0000000000C7
+:106BD0000000FF00000000000000FF0000000000B7
+:106BE0000000FF00000000000000FF0000000000A7
+:106BF0000000FF00000000000000FF000000000097
+:106C00000000FF00000000000000FF000000000086
+:106C10000000FF00000000000000FF000000000076
+:106C20000000FF00000000000000FF000000000066
+:106C30000000FF00000000000000FF000000000056
+:106C40000000FF00000000000000FF000000000046
+:106C50000000FF00000000000000FF000000000036
+:106C60000000FF00000000000000FF000000000026
+:106C70000000FF00000000000000FF000000000016
+:106C80000000FF00000000000000FF000000000006
+:106C90000000FF00000000000000FF0000000000F6
+:106CA0000000FF00000000000000FF0000000000E6
+:106CB0000000FF00000000000000FF0000000000D6
+:106CC0000000FF00000000000000FF0000000000C6
+:106CD0000000FF00000000000000FF0000000000B6
+:106CE0000000FF00000000000000FF0000000000A6
+:106CF0000000FF00000000000000FF000000000096
+:106D00000000FF00000000000000FF000000000085
+:106D10000000FF00000000000000FF000000000075
+:106D20000000FF00000000000000FF000000000065
+:106D30000000FF00000000000000FF000000000055
+:106D40000000FF00000000000000FF000000000045
+:106D50000000FF00000000000000FF000000000035
+:106D60000000FF00000000000000FF00000019000C
+:106D70000000000000000000FFFFFFFF0000000017
+:106D800003938700000000000393870000007FF852
+:106D900000007FF800000BA700003500000000FF96
+:106DA000000000FF000000FF000000FF000000FFE7
+:106DB000000000FF000000FF000000FF0000FF00D7
+:106DC000000000000000FF00000000000000FF00C5
+:106DD000000000000000FF00000000000000FF00B5
+:106DE000000000000000FF00000000000000FF00A5
+:106DF000000000000000FF00000000000000FF0095
+:106E0000000000000000FF00000000000000FF0084
+:106E1000000000000000FF00000000000000FF0074
+:106E2000000000000000FF00000000000000FF0064
+:106E3000000000000000FF00000000000000FF0054
+:106E4000000000000000FF00000000000000FF0044
+:106E5000000000000000FF00000000000000FF0034
+:106E6000000000000000FF00000000000000FF0024
+:106E7000000000000000FF00000000000000FF0014
+:106E8000000000000000FF00000000000000FF0004
+:106E9000000000000000FF00000000000000FF00F4
+:106EA000000000000000FF00000000000000FF00E4
+:106EB000000000000000FF00000000000000FF00D4
+:106EC000000000000000FF00000000000000FF00C4
+:106ED000000000000000FF00000000000000FF00B4
+:106EE000000000000000FF00000000000000FF00A4
+:106EF000000000000000FF00000000000000FF0094
+:106F0000000000000000FF00000000000000FF0083
+:106F1000000000000000FF00000000000000FF0073
+:106F2000000000000000FF00000000000000FF0063
+:106F3000000000000000FF00000000000000FF0053
+:106F4000000000000000FF00000000000000FF0043
+:106F5000000000000000FF00000000000000FF0033
+:106F6000000000000000FF00000000000000FF0023
+:106F7000000000000000FF00000000000000FF0013
+:106F8000000000000000FF00000000000000FF0003
+:106F9000000000000000FF00000000000000FF00F3
+:106FA000000000000000FF00000000000000FF00E3
+:106FB000000000000000FF00000000000000FF00D3
+:106FC000000000000000FF00000000000000FF00C3
+:106FD000000000000000FF00000000000000FF00B3
+:106FE000000000000000FF00000000000000FF00A3
+:106FF000000000000000FF0000000000FFFFFFFF96
+:10700000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90
+:10701000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80
+:10702000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70
+:10703000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60
+:10704000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50
+:10705000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40
+:10706000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30
+:10707000FFFFFFFFFFFFFFFFFFFFFFFF000000001C
+:10708000000028AD000029180000291900000005A3
+:10709000000000070000FF000FFFFFFF0000FF00DF
+:1070A0000FFFFFFF000000FF0000FF000000FF00D7
+:1070B0000FFFFFFF0000FF000FFFFFFF000000FFBA
+:1070C0000000FF000000FF000FFFFFFF0000FF00B7
+:1070D0000FFFFFFF000000FF0000FF000000FF00A7
+:1070E0000FFFFFFF0000FF000FFFFFFF000000FF8A
+:1070F0000000FF000000FF000FFFFFFF0000FF0087
+:107100000FFFFFFF000000FF0000FF000000FF0076
+:107110000FFFFFFF0000FF000FFFFFFF000000FF59
+:107120000000FF000000FF000FFFFFFF0000FF0056
+:107130000FFFFFFF000000FF0000FF000000FF0046
+:107140000FFFFFFF0000FF000FFFFFFF000000FF29
+:107150000000FF000000FF000FFFFFFF0000FF0026
+:107160000FFFFFFF000000FF0000FF000000FF0016
+:107170000FFFFFFF0000FF000FFFFFFF000000FFF9
+:107180000000FF000000FF000FFFFFFF0000FF00F6
+:107190000FFFFFFF000000FF0000FF000000FF00E6
+:1071A0000FFFFFFF0000FF000FFFFFFF000000FFC9
+:1071B0000000FF000000FF000FFFFFFF0000FF00C6
+:1071C0000FFFFFFF000000FF0000FF000000FF00B6
+:1071D0000FFFFFFF0000FF000FFFFFFF000000FF99
+:1071E0000000FF000000FF000FFFFFFF0000FF0096
+:1071F0000FFFFFFF000000FF0000FF000000FF0086
+:107200000FFFFFFF0000FF000FFFFFFF000000FF68
+:107210000000FF000000FF000FFFFFFF0000FF0065
+:107220000FFFFFFF000000FF0000FF000000FF0055
+:107230000FFFFFFF0000FF000FFFFFFF000000FF38
+:107240000000FF000000FF000FFFFFFF0000FF0035
+:107250000FFFFFFF000000FF0000FF000000FF0025
+:107260000FFFFFFF0000FF000FFFFFFF000000FF08
+:107270000000FF000000FF000FFFFFFF0000FF0005
+:107280000FFFFFFF000000FF0000FF000000FF00F5
+:107290000FFFFFFF0000FF000FFFFFFF000000FFD8
+:1072A0000000FF000000FF000FFFFFFF0000FF00D5
+:1072B0000FFFFFFF000000FF0000FF000000FF00C5
+:1072C0000FFFFFFF0000FF000FFFFFFF000000FFA8
+:1072D0000000FF000000FF000FFFFFFF0000FF00A5
+:1072E0000FFFFFFF000000FF0000FF000000FF0095
+:1072F0000FFFFFFF0000FF000FFFFFFF000000FF78
+:107300000000FF000000FF000FFFFFFF0000FF0074
+:107310000FFFFFFF000000FF0000FF000000FF0064
+:107320000FFFFFFF0000FF000FFFFFFF000000FF47
+:107330000000FF000000FF000FFFFFFF0000FF0044
+:107340000FFFFFFF000000FF0000FF000000FF0034
+:107350000FFFFFFF0000FF000FFFFFFF000000FF17
+:107360000000FF000000FF000FFFFFFF0000FF0014
+:107370000FFFFFFF000000FF0000FF000000FF0004
+:107380000FFFFFFF0000FF000FFFFFFF000000FFE7
+:107390000000FF000000FF000FFFFFFF0000FF00E4
+:1073A0000FFFFFFF000000FF0000FF000000FF00D4
+:1073B0000FFFFFFF0000FF000FFFFFFF000000FFB7
+:1073C0000000FF000000FF000FFFFFFF0000FF00B4
+:1073D0000FFFFFFF000000FF0000FF000000FF00A4
+:1073E0000FFFFFFF0000FF000FFFFFFF000000FF87
+:1073F0000000FF000000FF000FFFFFFF0000FF0084
+:107400000FFFFFFF000000FF0000FF000000FF0073
+:107410000FFFFFFF0000FF000FFFFFFF000000FF56
+:107420000000FF000000FF000FFFFFFF0000FF0053
+:107430000FFFFFFF000000FF0000FF000000FF0043
+:107440000FFFFFFF0000FF000FFFFFFF000000FF26
+:107450000000FF000000FF000FFFFFFF0000FF0023
+:107460000FFFFFFF000000FF0000FF000000FF0013
+:107470000FFFFFFF0000FF000FFFFFFF000000FFF6
+:107480000000FF000000FF000FFFFFFF0000FF00F3
+:107490000FFFFFFF000000FF0000FF000000FF00E3
+:1074A0000FFFFFFF0000FF000FFFFFFF000000FFC6
+:1074B0000000FF000000FF000FFFFFFF0000FF00C3
+:1074C0000FFFFFFF000000FF0000FF000000FF00B3
+:1074D0000FFFFFFF0000FF000FFFFFFF000000FF96
+:1074E0000000FF000000FF000FFFFFFF0000FF0093
+:1074F0000FFFFFFF000000FF0000FF000000FF0083
+:107500000FFFFFFF0000FF000FFFFFFF000000FF65
+:107510000000FF000000FF000FFFFFFF0000FF0062
+:107520000FFFFFFF000000FF0000FF000000FF0052
+:107530000FFFFFFF0000FF000FFFFFFF000000FF35
+:107540000000FF000000FF000FFFFFFF0000FF0032
+:107550000FFFFFFF000000FF0000FF000000FF0022
+:107560000FFFFFFF0000FF000FFFFFFF000000FF05
+:107570000000FF000000FF000FFFFFFF0000FF0002
+:107580000FFFFFFF000000FF0000FF000000FF00F2
+:107590000FFFFFFF0000FF000FFFFFFF000000FFD5
+:1075A0000000FF000000FF000FFFFFFF0000FF00D2
+:1075B0000FFFFFFF000000FF0000FF000000FF00C2
+:1075C0000FFFFFFF0000FF000FFFFFFF000000FFA5
+:1075D0000000FF000000FF000FFFFFFF0000FF00A2
+:1075E0000FFFFFFF000000FF0000FF000000FF0092
+:1075F0000FFFFFFF0000FF000FFFFFFF000000FF75
+:107600000000FF000000FF000FFFFFFF0000FF0071
+:107610000FFFFFFF000000FF0000FF000000FF0061
+:107620000FFFFFFF0000FF000FFFFFFF000000FF44
+:107630000000FF000000FF000FFFFFFF0000FF0041
+:107640000FFFFFFF000000FF0000FF000000FF0031
+:107650000FFFFFFF0000FF000FFFFFFF000000FF14
+:107660000000FF000000FF000FFFFFFF0000FF0011
+:107670000FFFFFFF000000FF0000FF000000FF0001
+:107680000FFFFFFF0000FF000FFFFFFF000000FFE4
+:107690000000FF000000FF000FFFFFFF0000FF00E1
+:1076A0000FFFFFFF000000FF0000FF000000FF00D1
+:1076B0000FFFFFFF0000FF000FFFFFFF000000FFB4
+:1076C0000000FF000000FF000FFFFFFF0000FF00B1
+:1076D0000FFFFFFF000000FF0000FF000000FF00A1
+:1076E0000FFFFFFF0000FF000FFFFFFF000000FF84
+:1076F0000000FF000000FF000FFFFFFF0000FF0081
+:107700000FFFFFFF000000FF0000FF000000FF0070
+:107710000FFFFFFF0000FF000FFFFFFF000000FF53
+:107720000000FF000000FF000FFFFFFF0000FF0050
+:107730000FFFFFFF000000FF0000FF000000FF0040
+:107740000FFFFFFF0000FF000FFFFFFF000000FF23
+:107750000000FF000000FF000FFFFFFF0000FF0020
+:107760000FFFFFFF000000FF0000FF000000FF0010
+:107770000FFFFFFF0000FF000FFFFFFF000000FFF3
+:107780000000FF000000FF000FFFFFFF0000FF00F0
+:107790000FFFFFFF000000FF0000FF000000FF00E0
+:1077A0000FFFFFFF0000FF000FFFFFFF000000FFC3
+:1077B0000000FF000000FF000FFFFFFF0000FF00C0
+:1077C0000FFFFFFF000000FF0000FF000000FF00B0
+:1077D0000FFFFFFF0000FF000FFFFFFF000000FF93
+:1077E0000000FF000000FF000FFFFFFF0000FF0090
+:1077F0000FFFFFFF000000FF0000FF000000FF0080
+:107800000FFFFFFF0000FF000FFFFFFF000000FF62
+:107810000000FF000000FF000FFFFFFF0000FF005F
+:107820000FFFFFFF000000FF0000FF000000FF004F
+:107830000FFFFFFF0000FF000FFFFFFF000000FF32
+:107840000000FF000000FF000FFFFFFF0000FF002F
+:107850000FFFFFFF000000FF0000FF000000FF001F
+:107860000FFFFFFF0000FF000FFFFFFF000000FF02
+:107870000000FF000000FF000FFFFFFF0000FF00FF
+:107880000FFFFFFF000000FF0000FF000000FF00EF
+:107890000FFFFFFF0000FF000FFFFFFF000000FFD2
+:1078A0000000FF000000FF000FFFFFFF0000FF00CF
+:1078B0000FFFFFFF000000FF0000FF000000FF00BF
+:1078C0000FFFFFFF0000FF000FFFFFFF000000FFA2
+:1078D0000000FF000000FF000FFFFFFF0000FF009F
+:1078E0000FFFFFFF000000FF0000FF000000FF008F
+:1078F0000FFFFFFF0000FF000FFFFFFF000000FF72
+:107900000000FF000000FF000FFFFFFF0000FF006E
+:107910000FFFFFFF000000FF0000FF000000FF005E
+:107920000FFFFFFF0000FF000FFFFFFF000000FF41
+:107930000000FF000000FF000FFFFFFF0000FF003E
+:107940000FFFFFFF000000FF0000FF000000FF002E
+:107950000FFFFFFF0000FF000FFFFFFF000000FF11
+:107960000000FF000000FF000FFFFFFF0000FF000E
+:107970000FFFFFFF000000FF0000FF000000FF00FE
+:107980000FFFFFFF0000FF000FFFFFFF000000FFE1
+:107990000000FF000000FF000FFFFFFF0000FF00DE
+:1079A0000FFFFFFF000000FF0000FF000000FF00CE
+:1079B0000FFFFFFF0000FF000FFFFFFF000000FFB1
+:1079C0000000FF000000FF000FFFFFFF0000FF00AE
+:1079D0000FFFFFFF000000FF0000FF000000FF009E
+:1079E0000FFFFFFF0000FF000FFFFFFF000000FF81
+:1079F0000000FF000000FF000FFFFFFF0000FF007E
+:107A00000FFFFFFF000000FF0000FF000000FF006D
+:107A10000FFFFFFF0000FF000FFFFFFF000000FF50
+:107A20000000FF000000FF000FFFFFFF0000FF004D
+:107A30000FFFFFFF000000FF0000FF000000FF003D
+:107A40000FFFFFFF0000FF000FFFFFFF000000FF20
+:107A50000000FF000000FF000FFFFFFF0000FF001D
+:107A60000FFFFFFF000000FF0000FF000000FF000D
+:107A70000FFFFFFF0000FF000FFFFFFF000000FFF0
+:107A80000000FF000000FF000FFFFFFF0000FF00ED
+:107A90000FFFFFFF000000FF0000FF000000FF00DD
+:107AA0000FFFFFFF0000FF000FFFFFFF000000FFC0
+:107AB0000000FF000000FF000FFFFFFF0000FF00BD
+:107AC0000FFFFFFF000000FF0000FF000000FF00AD
+:107AD0000FFFFFFF0000FF000FFFFFFF000000FF90
+:107AE0000000FF000000FF000FFFFFFF0000FF008D
+:107AF0000FFFFFFF000000FF0000FF000000FF007D
+:107B00000FFFFFFF0000FF000FFFFFFF000000FF5F
+:107B10000000FF000000FF000FFFFFFF0000FF005C
+:107B20000FFFFFFF000000FF0000FF000000FF004C
+:107B30000FFFFFFF0000FF000FFFFFFF000000FF2F
+:107B40000000FF000000FF000FFFFFFF0000FF002C
+:107B50000FFFFFFF000000FF0000FF000000FF001C
+:107B60000FFFFFFF0000FF000FFFFFFF000000FFFF
+:107B70000000FF000000FF000FFFFFFF0000FF00FC
+:107B80000FFFFFFF000000FF0000FF000000FF00EC
+:107B90000FFFFFFF0000FF000FFFFFFF000000FFCF
+:107BA0000000FF000000FF000FFFFFFF0000FF00CC
+:107BB0000FFFFFFF000000FF0000FF000000FF00BC
+:107BC0000FFFFFFF0000FF000FFFFFFF000000FF9F
+:107BD0000000FF000000FF000FFFFFFF0000FF009C
+:107BE0000FFFFFFF000000FF0000FF000000FF008C
+:107BF0000FFFFFFF0000FF000FFFFFFF000000FF6F
+:107C00000000FF000000FF000FFFFFFF0000FF006B
+:107C10000FFFFFFF000000FF0000FF000000FF005B
+:107C20000FFFFFFF0000FF000FFFFFFF000000FF3E
+:107C30000000FF000000FF000FFFFFFF0000FF003B
+:107C40000FFFFFFF000000FF0000FF000000FF002B
+:107C50000FFFFFFF0000FF000FFFFFFF000000FF0E
+:107C60000000FF000000FF000FFFFFFF0000FF000B
+:107C70000FFFFFFF000000FF0000FF000000FF00FB
+:107C80000FFFFFFF0000FF000FFFFFFF000000FFDE
+:107C90000000FF000000FF000FFFFFFF0000FF00DB
+:107CA0000FFFFFFF000000FF0000FF000000FF00CB
+:107CB0000FFFFFFF0000FF000FFFFFFF000000FFAE
+:107CC0000000FF000000FF000FFFFFFF0000FF00AB
+:107CD0000FFFFFFF000000FF0000FF000000FF009B
+:107CE0000FFFFFFF0000FF000FFFFFFF000000FF7E
+:107CF0000000FF000000FF000FFFFFFF0000FF007B
+:107D00000FFFFFFF000000FF0000FF000000FF006A
+:107D10000FFFFFFF0000FF000FFFFFFF000000FF4D
+:107D20000000FF000000FF000FFFFFFF0000FF004A
+:107D30000FFFFFFF000000FF0000FF000000FF003A
+:107D40000FFFFFFF0000FF000FFFFFFF000000FF1D
+:107D50000000FF0000001000000020800000310043
+:107D600000004180000052000000628000007300AB
+:107D700000008380000094000000A4800000B50093
+:107D80000000C5800000D6000000E6800000F7007B
+:107D9000000107800001180000012880000139005F
+:107DA0000001498000015A0000016A8000017B0047
+:107DB00000018B8000019C000001AC800001BD002F
+:107DC0000001CD800001DE000001EE800001FF0017
+:107DD00000000F8000007FF800007FF8000005F928
+:107DE0000000350010000000000028AD0000291838
+:107DF0000000291900000005000000060001000134
+:107E000000220006CCCCCCC97058103C0000FF000A
+:107E1000000000000000FF00000000000000FF0064
+:107E2000000000000000FF00000000000000FF0054
+:107E3000000000000000FF00000000000000FF0044
+:107E4000000000000000FF00000000000000FF0034
+:107E5000000000000000FF00000000000000FF0024
+:107E6000000000000000FF00000000000000FF0014
+:107E7000000000000000FF00000000000000FF0004
+:107E8000000000000000FF00000000000000FF00F4
+:107E9000000000000000FF00000000000000FF00E4
+:107EA000000000000000FF00000000000000FF00D4
+:107EB000000000000000FF00000000000000FF00C4
+:107EC000000000000000FF00000000000000FF00B4
+:107ED000000000000000FF00000000000000FF00A4
+:107EE000000000000000FF00000000000000FF0094
+:107EF000000000000000FF00000000000000FF0084
+:107F0000000000000000FF00000000000000FF0073
+:107F1000000000000000FF00000000000000FF0063
+:107F2000000000000000FF00000000000000FF0053
+:107F3000000000000000FF00000000000000FF0043
+:107F4000000000000000FF00000000000000FF0033
+:107F5000000000000000FF00000000000000FF0023
+:107F6000000000000000FF00000000000000FF0013
+:107F7000000000000000FF00000000000000FF0003
+:107F8000000000000000FF00000000000000FF00F3
+:107F9000000000000000FF00000000000000FF00E3
+:107FA000000000000000FF00000000000000FF00D3
+:107FB000000000000000FF00000000000000FF00C3
+:107FC000000000000000FF00000000000000FF00B3
+:107FD000000000000000FF00000000000000FF00A3
+:107FE000000000000000FF00000000000000FF0093
+:107FF000000000000000FF00000000000000FF0083
+:10800000000000000000FF00000000000000FF0072
+:10801000000000000000FF00000000000000FF0062
+:10802000000000000000FF00000000000000FF0052
+:10803000000000000000FF00000000000000FF0042
+:10804000000000000000FF00000000000000000130
+:10805000CCCC0201CCCCCCCCCCCC0201CCCCCCCC8A
+:10806000CCCC0201CCCCCCCCCCCC0201CCCCCCCC7A
+:10807000CCCC0201CCCCCCCCCCCC0201CCCCCCCC6A
+:10808000CCCC0201CCCCCCCCCCCC0201CCCCCCCC5A
+:1080900000000000FFFFFFFF03030303134202027F
+:1080A0005050502070608050020002000604060408
+:1080B000000E0000011600D6002625A0002625A0EF
+:1080C000002625A0002625A000720000012300F351
+:1080D000002625A0002625A0002625A0002625A0F4
+:1080E0000000FFFF000000000000FFFF0000000094
+:1080F0000000FFFF000000000000FFFF0000000084
+:108100000000FFFF000000000000FFFF0000000073
+:108110000000FFFF000000000000FFFF0000000063
+:108120000000FFFF000000000000FFFF0000000053
+:108130000000FFFF000000000000FFFF0000000043
+:108140000000FFFF000000000000FFFF0000000033
+:108150000000FFFF000000000000FFFF0000000023
+:108160000000FFFF000000000000FFFF0000000013
+:108170000000FFFF000000000000FFFF0000000003
+:108180000000FFFF000000000000FFFF00000000F3
+:108190000000FFFF000000000000FFFF00000000E3
+:1081A0000000FFFF000000000000FFFF00000000D3
+:1081B0000000FFFF000000000000FFFF00000000C3
+:1081C0000000FFFF000000000000FFFF00000000B3
+:1081D0000000FFFF000000000000FFFF00000000A3
+:1081E0000000FFFF000000000000FFFF0000000093
+:1081F0000000FFFF000000000000FFFF0000000083
+:108200000000FFFF000000000000FFFF0000000072
+:108210000000FFFF000000000000FFFF0000000062
+:108220000000FFFF000000000000FFFF0000000052
+:108230000000FFFF000000000000FFFF0000000042
+:108240000000FFFF000000000000FFFF0000000032
+:108250000000FFFF000000000000FFFF0000000022
+:108260000000FFFF000000000000FFFF0000000012
+:108270000000FFFF000000000000FFFF0000000002
+:108280000000FFFF000000000000FFFF00000000F2
+:108290000000FFFF000000000000FFFF00000000E2
+:1082A0000000FFFF000000000000FFFF00000000D2
+:1082B0000000FFFF000000000000FFFF00000000C2
+:1082C0000000FFFF000000000000FFFF00000000B2
+:1082D0000000FFFF000000000000FFFF00000000A2
+:1082E000FFFFFFF3318FFFFF0C30C30CC30C30C313
+:1082F000CF3CF300F3CF3CF30000CF3CCDCDCDCD50
+:10830000FFFFFFF130EFFFFF0C30C30CC30C30C395
+:10831000CF3CF300F3CF3CF30001CF3CCDCDCDCD2E
+:10832000FFFFFFF6305FFFFF0C30C30CC30C30C300
+:10833000CF3CF300F3CF3CF30002CF3CCDCDCDCD0D
+:10834000FFFFF4061CBFFFFF0C30C305C30C30C396
+:10835000CF300014F3CF3CF30004CF3CCDCDCDCDD6
+:10836000FFFFFFF2304FFFFF0C30C30CC30C30C3D4
+:10837000CF3CF300F3CF3CF30008CF3CCDCDCDCDC7
+:10838000FFFFFFFA302FFFFF0C30C30CC30C30C3CC
+:10839000CF3CF300F3CF3CF30010CF3CCDCDCDCD9F
+:1083A000FFFFFFF731EFFFFF0C30C30CC30C30C3EE
+:1083B000CF3CF300F3CF3CF30020CF3CCDCDCDCD6F
+:1083C000FFFFFFF5302FFFFF0C30C30CC30C30C391
+:1083D000CF3CF300F3CF3CF30040CF3CCDCDCDCD2F
+:1083E000FFFFFFF3318FFFFF0C30C30CC30C30C312
+:1083F000CF3CF300F3CF3CF30000CF3CCDCDCDCD4F
+:10840000FFFFFFF1310FFFFF0C30C30CC30C30C373
+:10841000CF3CF300F3CF3CF30001CF3CCDCDCDCD2D
+:10842000FFFFFFF6305FFFFF0C30C30CC30C30C3FF
+:10843000CF3CF300F3CF3CF30002CF3CCDCDCDCD0C
+:10844000FFFFF4061CBFFFFF0C30C305C30C30C395
+:10845000CF300014F3CF3CF30004CF3CCDCDCDCDD5
+:10846000FFFFFFF2304FFFFF0C30C30CC30C30C3D3
+:10847000CF3CF300F3CF3CF30008CF3CCDCDCDCDC6
+:10848000FFFFFFFA302FFFFF0C30C30CC30C30C3CB
+:10849000CF3CF300F3CF3CF30010CF3CCDCDCDCD9E
+:1084A000FFFFFFF730EFFFFF0C30C30CC30C30C3EE
+:1084B000CF3CF300F3CF3CF30020CF3CCDCDCDCD6E
+:1084C000FFFFFFF5304FFFFF0C30C30CC30C30C370
+:1084D000CF3CF300F3CF3CF30040CF3CCDCDCDCD2E
+:1084E000FFFFFFFF30CFFFFF0C30C30CC30C30C3C6
+:1084F000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD82
+:10850000FFFFFFFF30CFFFFF0C30C30CC30C30C3A5
+:10851000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD60
+:10852000FFFFFFFF30CFFFFF0C30C30CC30C30C385
+:10853000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD3F
+:10854000FFFFFFFF30CFFFFF0C30C30CC30C30C365
+:10855000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD1D
+:10856000FFFFFFFF30CFFFFF0C30C30CC30C30C345
+:10857000CF3CF3CCF3CF3CF30008CF3CCDCDCDCDF9
+:10858000FFFFFFFF30CFFFFF0C30C30CC30C30C325
+:10859000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDD1
+:1085A000FFFFFFFF30CFFFFF0C30C30CC30C30C305
+:1085B000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDA1
+:1085C000FFFFFFFF30CFFFFF0C30C30CC30C30C3E5
+:1085D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD61
+:1085E000FFFFFFF3320FFFFF0C30C30CC30C30C38F
+:1085F000CF3CF300F3CF3CF30000CF3CCDCDCDCD4D
+:10860000FFFFFFF1310FFFFF0C30C30CC30C30C371
+:10861000CF3CF300F3CF3CF30001CF3CCDCDCDCD2B
+:10862000FFFFFFF6305FFFFF0C30C30CC30C30C3FD
+:10863000CF3CF300F3CF3CF30002CF3CCDCDCDCD0A
+:10864000FFFFF4061CBFFFFF0C30C305C30C30C393
+:10865000CF300014F3CF3CF30004CF3CCDCDCDCDD3
+:10866000FFFFFFF2304FFFFF0C30C30CC30C30C3D1
+:10867000CF3CF300F3CF3CF30008CF3CCDCDCDCDC4
+:10868000FFFFFF8A042FFFFF0C30C30CC30C30C365
+:10869000CF3CC000F3CF3CF30010CF3CCDCDCDCDCF
+:1086A000FFFFFF9705CFFFFF0C30C30CC30C30C397
+:1086B000CF3CC000F3CF3CF30020CF3CCDCDCDCD9F
+:1086C000FFFFFFF5310FFFFF0C30C30CC30C30C3AD
+:1086D000CF3CF300F3CF3CF30040CF3CCDCDCDCD2C
+:1086E000FFFFFFF3320FFFFF0C30C30CC30C30C38E
+:1086F000CF3CF300F3CF3CF30000CF3CCDCDCDCD4C
+:10870000FFFFFFF1302FFFFF0C30C30CC30C30C351
+:10871000CF3CF300F3CF3CF30001CF3CCDCDCDCD2A
+:10872000FFFFFFF6305FFFFF0C30C30CC30C30C3FC
+:10873000CF3CF300F3CF3CF30002CF3CCDCDCDCD09
+:10874000FFFFFF061CBFFFFF0C30C30CC30C30C380
+:10875000CF3CC014F3CF3CF30004CF3CCDCDCDCD06
+:10876000FFFFFFF2304FFFFF0C30C30CC30C30C3D0
+:10877000CF3CF300F3CF3CF30008CF3CCDCDCDCDC3
+:10878000FFFFFFFA302FFFFF0C30C30CC30C30C3C8
+:10879000CF3CF300F3CF3CF30010CF3CCDCDCDCD9B
+:1087A000FFFFFFF731CFFFFF0C30C30CC30C30C30A
+:1087B000CF3CF300F3CF3CF30020CF3CCDCDCDCD6B
+:1087C000FFFFFFFF30CFFFFF0C30C30CC30C30C3E3
+:1087D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD5F
+:1087E000FFFFFFFF30CFFFFF0C30C30CC30C30C3C3
+:1087F000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD7F
+:10880000FFFFFFFF30CFFFFF0C30C30CC30C30C3A2
+:10881000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD5D
+:10882000FFFFFFFF30CFFFFF0C30C30CC30C30C382
+:10883000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD3C
+:10884000FFFFFFFF30CFFFFF0C30C30CC30C30C362
+:10885000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD1A
+:10886000FFFFFFFF30CFFFFF0C30C30CC30C30C342
+:10887000CF3CF3CCF3CF3CF30008CF3CCDCDCDCDF6
+:10888000FFFFFFFF30CFFFFF0C30C30CC30C30C322
+:10889000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDCE
+:1088A000FFFFFFFF30CFFFFF0C30C30CC30C30C302
+:1088B000CF3CF3CCF3CF3CF30020CF3CCDCDCDCD9E
+:1088C000FFFFFFFF30CFFFFF0C30C30CC30C30C3E2
+:1088D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD5E
+:1088E000FFFFFFFF30CFFFFF0C30C30CC30C30C3C2
+:1088F000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD7E
+:10890000FFFFFFFF30CFFFFF0C30C30CC30C30C3A1
+:10891000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD5C
+:10892000FFFFFFFF30CFFFFF0C30C30CC30C30C381
+:10893000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD3B
+:10894000FFFFFFFF30CFFFFF0C30C30CC30C30C361
+:10895000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD19
+:10896000FFFFFFFF30CFFFFF0C30C30CC30C30C341
+:10897000CF3CF3CCF3CF3CF30008CF3CCDCDCDCDF5
+:10898000FFFFFFFF30CFFFFF0C30C30CC30C30C321
+:10899000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDCD
+:1089A000FFFFFFFF30CFFFFF0C30C30CC30C30C301
+:1089B000CF3CF3CCF3CF3CF30020CF3CCDCDCDCD9D
+:1089C000FFFFFFFF30CFFFFF0C30C30CC30C30C3E1
+:1089D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD5D
+:1089E000FFFFFFFF30CFFFFF0C30C30CC30C30C3C1
+:1089F000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD7D
+:108A0000FFFFFFFF30CFFFFF0C30C30CC30C30C3A0
+:108A1000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD5B
+:108A2000FFFFFFFF30CFFFFF0C30C30CC30C30C380
+:108A3000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD3A
+:108A4000FFFFFFFF30CFFFFF0C30C30CC30C30C360
+:108A5000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD18
+:108A6000FFFFFFFF30CFFFFF0C30C30CC30C30C340
+:108A7000CF3CF3CCF3CF3CF30008CF3CCDCDCDCDF4
+:108A8000FFFFFFFF30CFFFFF0C30C30CC30C30C320
+:108A9000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDCC
+:108AA000FFFFFFFF30CFFFFF0C30C30CC30C30C300
+:108AB000CF3CF3CCF3CF3CF30020CF3CCDCDCDCD9C
+:108AC000FFFFFFFF30CFFFFF0C30C30CC30C30C3E0
+:108AD000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD5C
+:108AE000000C0000000700C000028130000B81581C
+:108AF0000002021000010230000F024000010330AA
+:108B0000000C0000000800C000028140000B8168DA
+:108B1000000202200001024000070250000202C0D1
+:108B2000001000000008010000028180000B81A8F5
+:108B30000002026000018280000E8298000803801B
+:108B4000001000000001010000028110000901383E
+:108B5000000201C8000101E8000E01F8000002D87F
+:108B6000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC45
+:108B700000002000CCCCCCCCCCCCCCCCCCCCCCCC45
+:108B8000CCCCCCCC00002000CCCCCCCCCCCCCCCC35
+:108B9000CCCCCCCCCCCCCCCC04002000CCCCCCCC21
+:108BA000CCCCCCCCCCCCCCCCCCCCCCCC41002000D4
+:108BB00003030303034202025050502070608050B0
+:108BC0001313131313421212505050207060805030
+:108BD000030102000000000000000000000000008F
+:108BE0001F8B080000000000000BFB51CFC0F003FA
+:108BF0008AF7093230288920F8C4E0427606864D8B
+:108C00001C0C0C5BB849D307C32C0C0C0CDA4CE4DD
+:108C1000E905E1DBBC0C0CCF8098810F555C80131B
+:108C200042FF075A20C80AB4830DBBFEE56A08B6A6
+:108C3000A70A0343011033283130E8AB22C445D4DE
+:108C400019182602F99150B1AB403A4C8D7C378F00
+:108C5000E2C1834F1AA3F2971A426807A8F8293491
+:108C6000F96550F9621D087DDA18BBB9253AC4D9F7
+:108C7000BFCB1A953FCD1ABFFA93F6A8FC7568EAE8
+:108C80001741F900B9FAD21DD80300000000000016
+:108C900000000000000000001F8B08000000000022
+:108CA000000BED7D7F7C14D5B5F8999DD9D9D9CD30
+:108CB000EE6608096C20E024861AFAA25D20609016
+:108CC000A843401ABF8FDA15A9A62DED77B5D4E2D7
+:108CD0000F60EBF3097DCF36931092101017B1D5CA
+:108CE00056AB2B0F2DF56B25B5D4D2FAA38B581E9E
+:108CF000B6EFF3BE4869EBD7621B7FE18F228D5A36
+:108D000084B658BFF79C7B273B33D94D36407FFC58
+:108D1000F1C207863B73EEBDE79E73EEB9E79C7B1D
+:108D2000EE8D0A35F0A133003EC09F0B016E0F019E
+:108D30004045EE695C7F7E4F7F03C05188A47BCBAA
+:108D400001D62860022B5B072399FB25C09F3A853B
+:108D50009557C91F8EF75603DC51F2957B117EB5EE
+:108D6000A540803D7BDB00B267B1EFA1E816280586
+:108D70002881D476FCCE7E12F7B3F68E05276720C5
+:108D80009AEBBF027C0033F173957EA884E0E00388
+:108D900099FD73303917C601C860FFAC863ED68E88
+:108DA0007240CE60BFB2BC50FF554DAE1DEF53D6E2
+:108DB00055C86AA23DFC475E529A0C17865F7DB08B
+:108DC0007AFBD37539F8B320527EE89FD87F1450D0
+:108DD000081F7903201D8E86212357176EE7589BA5
+:108DE000B1FD693FD2F133A589B30BC3D974EA69E8
+:108DF000D3E8D9D5A6433600C05036FBEAD9330CA8
+:108E0000E696FAA1F5E68144F4D20C8BF0E90CFB6E
+:108E10003225D588751280D1D78FF491F0FD22CDFF
+:108E2000CC53DF7E4239A38F3D5E46C720F0F680EB
+:108E30008DEF7ED65E10FBCF43AFCBB07F2627C130
+:108E4000DAA1FD5B0D27DF7F682AC0BE30D2DB448C
+:108E50001CC0A7A7202EF8FD51699876049F1583A2
+:108E6000B73312DD4BEA7CB97ED9DFA01172C94954
+:108E70002056E6961BAF5C229D2A905F86F4F29402
+:108E80005CBB2AF22D0FBDAE11F41A989B684D30D1
+:108E90007AAC6D03EB25473D390666260F9D568952
+:108EA0007A767F4A3983CBD33E40BB983F960BBE40
+:108EB00058FCBE7C92F8ADFF1BE1B749C83B409A15
+:108EC0009E03739384A7B7BD7CF38B4DE2C17248B8
+:108ED000C9583E94EF7288DFCF1E7E8DCF33FBFBE7
+:108EE000C3E0A77676A2C661FDAC11F80DCCE5FA19
+:108EF0006FED3435B345227DE4C2F321D45FAC9EDF
+:108F000024097A687D80F257725C01188BF8999079
+:108F10008800ACAB6DD686D33FA02B7FEAB7E5AE19
+:108F200066A8DC7D9875837885C2F9E9F4F0A01E07
+:108F30005D62BDC4DAD182ECFD99D86E79AC6A1657
+:108F4000E0E8E8C72FBE83E4933FC0797B82C1CDC0
+:108F5000127A56A6F6498F401590BE97053CF5C388
+:108F6000E0036C58E674F6C4F775A21F6968BBDEAF
+:108F70007AC7A08CD347E063EB75191EA77606F17C
+:108F80005112442FEF7B3F7BAF874FFDFDA996FD2C
+:108F90004681FED212C9D348F57F23E465887C164A
+:108FA000E0EB7E31CF14E833E1CC9C1CD9F275B2F2
+:108FB0007274CA72C2BAA7F5A2809C5890A279C3F3
+:108FC000C0ACDE69A397973C729275C22F94C6F02D
+:108FD0007128719217868F4272AB737C2AA69753C1
+:108FE0007B12CEF1B3B00551463AB0F15E65D7873A
+:108FF00038CDD710DA398EFA6C7084AF244B42EF3B
+:1090000073B89BC43C3FBFB98AE30FA27D0FBEACCF
+:109010003DCDD99E0C551E39E7786F94B87E63F02C
+:1090200059A2A7B77F45227C6548583E566F8BE80A
+:10903000DFABBFECE70ED1DE06095AFBC27C3E2D4A
+:1090400072AC87CD92D0131A9F675EFDE447B99A40
+:1090500071F27255AC5E5F28E55F77985514BB34AA
+:109060005278DD29F5D9EB413626F8362ABE9F29FC
+:1090700095B9F85E2CBE579D24BE1387E25B949C85
+:109080004D957CA35A276F3A49FC821EFC4E975C93
+:10909000CF1072562CFEF63C182DFEF250FA163503
+:1090A0008F668F12BF2D2749DF0A9F6D2709FC0AA3
+:1090B000CCDBF305BF2DE0F2A1303B1CFD9C62F13F
+:1090C0007B7464FC00CE637FAD172D53217B0D6054
+:1090D00002C0D3ED2F5A9692C3CF04AED747DBFF21
+:1090E0009E91F927FA7FC3326B73FD1F687FC3D54A
+:1090F000BFC2E40785ADD87E7F51ECB8E16DD7B82B
+:109100005F96DE76F57BB2747FB5E8FEFFE81AF76E
+:10911000BBD21FDDE30EB3719F597CBF7F38497905
+:10912000AC16F3A559D25DEB4021FB7D86E0EBDD6B
+:1091300036BC8D6F01F8A902AFCE22E1278AF63F37
+:1091400055247C9F68BF0FE12B46863F53C0A78AFA
+:1091500084977C7C1E165A3FE74A36FDC0E57FACFB
+:10916000D1781CC45CA340F082A17113AB39F5AD7A
+:109170007EC67BAB23A0AF29A7B809C545560324FB
+:10918000306E7217241B7D187FD9F9E57B11EE1D17
+:1091900045D37B75E013927D0F1E8C6CE9ADCEF547
+:1091A000B74A4EB64A284B6BA2FAFD145F49B54A3E
+:1091B000EC596185758CDB1CAB49B45F598EE3308B
+:1091C000748BB5F3FCB2CB7661F9364DD265266A65
+:1091D0005FBD60EAA6CB0D06F7FEAEE7CE40B869EC
+:1091E000E36A3A485FC6259487B171D594CF61CFC1
+:1091F000C58BB97E07E10FB738CACC0EF864EB27F0
+:109200005CDF3F9D74973FD1F289DC7AC2FE5E91AC
+:10921000707FCF8D07B8DF3187EBED6335A9DF7243
+:10922000BC3E546DF1F8028DB7D48AD2F836BCFF3B
+:10923000452A6F68AFD73BD8B83F75CD510BC717DC
+:109240009680C6178DBF97C532B0F1AA8D00B75E64
+:10925000F04CCF2C28EC7F459B16BBF084B87B9C50
+:10926000ADD7E7C75BD5DF9DF00AB3978EED0A9ABD
+:10927000884F74AF9C0956235F07B293B07FAB341D
+:10928000C9F93300B5C8575307E463B399CCC8ECA8
+:109290007D3AA6C5032866D0AF21DD372168257B3E
+:1092A000DFF88E96ACC7F6DFA3F675F1FDD6C69A49
+:1092B000F1181F79BC6DF54485CDF71FB55913150D
+:1092C00066B4EF6CEBA1E7A36D697ABFA3ED4E7AAC
+:1092D000DAE3434D62D8E393B11FB303E5ED989F02
+:1092E00099460CAF8DE7FBC8BFDD20F44897782A7C
+:1092F0004A562EC5EF7198D60B88D7FE79584E374F
+:10930000C0346459BAE929B9948DE3864A988E6DC0
+:10931000EF7AE157FC7B154C0F30F97ACA6CA679CD
+:10932000706BA32F13A8A6E7C5D8DFADA60F98C909
+:10933000039138C3CB41D740CC5DD621B926D2406A
+:10934000FDC77B0DAC7FC36E2CDF3093194A40ED17
+:10935000CB11A223C4B1BF99074CD2E381261FC50C
+:10936000E9D24DBE20D271A47ED248D761E25573B6
+:109370005E77C3CFEE779799C6FBCDA07C70FA3E9F
+:10938000EC637A62F70BE37D5639E141E3674F1EE8
+:10939000478CF9326894DE26E86CD3FD5884EB9D47
+:1093A0008DCC3FC47860217C369E776D6CB8788216
+:1093B000DAD8958073F0994E60BC556DCC88671FE4
+:1093C000BDF7C23F8F46D1CC5CB92B367DCC95F52D
+:1093D000397CBCF0136495E4FF5805FFDE157B4A29
+:1093E000BF32EC6C4FF27ED73E5FEFFCEEA7FE8EF5
+:1093F00055DADFF76B57D6E7A93F897DCFC397A52D
+:1094000032D7C34FBF1068FE1ACAA7A0EFEE175E8F
+:10941000DB7B26D2FB800C280FE97DCD240F287F33
+:10942000A8479E62F2D0CFDA1BDBB2E137CEF91C3F
+:1094300089BBCBE946864003E71B76F55F821F3F79
+:1094400015F1DABD225EBBA72D46CFA7DB0C7A3E15
+:10945000D55647DFB36D712A3FD9D648E5C7DB4CF7
+:109460002AFFA8AD85CA3BDB12547EB4AD959E3B66
+:10947000DA92F4BCAD6D193DD34D7C9E6F684B51B3
+:10948000B9AB6D35D5B3C7FF31A6359CF2F7CF75B3
+:10949000EEF2C5C659B9F9CEFE7E34E62E5FA47F42
+:1094A000D4559EA7B9CB73E10BAEF62E3C7EB5AB7F
+:1094B0007CFE40970B7ECEEBEEF2ECFE075CF0E715
+:1094C0003EE72ECFDCB7C7551EDBE22E47E2875CB6
+:1094D000ED0562EEF256543E5C7F917C74C56AC61F
+:1094E000E495BFC1EFD3839F737D978B949FAB7A35
+:1094F000AA517E5A7C71CB40F9E1F294467D260D4B
+:1095000095139B6F23C9978DC7DF5AAEFE479E8682
+:1095100097A7A2E5A141895B30541EBC7CF7CAC75E
+:10952000103D23E4E57FE4E01F430E607E19EBA4C9
+:10953000F0BA9AC7EE23BB35B015C8EEF3A30D5DA4
+:10954000E95887276793F9F6C1AEF5CD7D4466EDFE
+:1095500004CAA10BF749034A01FF56AC73018D7F82
+:109560000FD6A67D284F1130A6CBD30096FFE096EC
+:109570000957B1F6F709B8AEFBC1923E02306E82D0
+:109580009A44FF2652EBF673F6CA3CEE613FB77D74
+:109590003FD29AA1987F830BEFA1E3E6FB38F2C498
+:1095A00059ADBF66F340DE326BDB5AF60CD5264D63
+:1095B000D9C0FAE544B7A52183E0CCC68CE563AFFA
+:1095C0008255CC6E639FE5B0096887CDF699CFCA06
+:1095D00033C93EDA8F4FDBEED9269E8F8B7978998F
+:1095E000CFFC25D287C1FD6A3838BBDF11F90549A8
+:1095F0004BE271ABF8FD0C457F79DC653FD9E35355
+:10960000948499C8C3AF23B2D8E7D1E3AD3C3EA25E
+:1096100002EA8742F0AFCBEEFD31FB59CAFC0219DA
+:10962000F188F17D2838719971E9D943F150954459
+:1096300012FBC17DEC2DAC9FCE31971B49473F9269
+:1096400022F08999848FAA737C54256E26F2C8D1A2
+:109650009F043E763BF67E9A141B80FE700EBFB5CB
+:10966000C144EB95E8B78E51894E9D11B7FD354B3E
+:10967000E17276967876FAF3DB87001DDC4F1ED711
+:10968000A861FB6B1A9B35B4AF0D886BE87F7786BA
+:1096900017950E676F6F68E3FBE3BDA80F03B84F24
+:1096A000AE8B7DF2183D3BC38FB4E0BC3B5ACFE894
+:1096B000505DB89D48DCBDDF5B5217F2ECEF6608E9
+:1096C000CFA051E6D9079EE0AAE71FA7F8ECFD6EF0
+:1096D0009046C6BF4BE06FC3752B294DCF4BA78C6F
+:1096E000CBEE0EC4DCF8FEF5E8C7EB97F8FBF47C94
+:1096F000789D2EBA15DA9FB59FEA583595E1719697
+:1097000098731E2C11F2A58ED55218C702ADD0F752
+:1097100010AF1F4E50DC4B0B270CA8C9EDD36A3895
+:109720001F1C74BA51D47B41B1F74B5331F4AB25B4
+:1097300023D58AF2A455B179240DAD673F3F27EABE
+:1097400077BFFF2FCFD13CA9D0689E48069B4779B1
+:10975000FA511473A5827151D94C29B86FF3173996
+:10976000996FBEAC10F3595B9830B41ADADAE3792A
+:10977000201E3C36287C1EBF21E0C14A513CAB581C
+:10978000FCFFBD48FCED7E18FEDD02FF1E7C16C20C
+:10979000BF4BE05306463BC5380DAE67012E359CE6
+:1097A000F918AF89FECB849E02F822F1CDFEFE921D
+:1097B000E04BB1E3F96A91E3792DC78FFB900F6C11
+:1097C0003C5B86E34746E0F19AC2D7192D9130629F
+:1097D00035B4D4E795AB1F0B7ABD6BCB95F5C5516E
+:1097E000C9D5C3A2FE48E3F8718E2F3F12E3786C0F
+:1097F00038BEFC50F0252DC3EC5730FE78A65877C4
+:1098000060918B2FC745BBE980CD971B5C7C3932BB
+:109810004ABEEC2D723CC773E33920E4EC17C3F168
+:10982000C501FFBC18FFAFC5F829AE7EBCF39A0E88
+:109830002B4CEBF26F9599B9FE185CBF6897E06E00
+:1098400054CEEDB0EA09EE157C2FB5F07590C1BD90
+:10985000EA84034874A0FDB616F74ACF03F896725F
+:1098600073B368FF77546FE160FB879DF53628F38B
+:109870006C3C06F07DFBBCBFD8706F3BE18E775E21
+:109880006FC31DA5F6128378BCE71CD78F3B9710DA
+:10989000DC907CA45871F6AABF3C49797D651049DB
+:1098A00063DCB14B49519C193721303EB92A10A7CE
+:1098B000149691E2D4158B793D5DD128CE1A80148F
+:1098C000DC89F1B97285F64D3EAE24753FDA11524E
+:1098D000D2A24D57D097B463FB630DCA0BB3F1D935
+:1098E00054F2D91E6A87E183EDDE5112DD8572756F
+:1098F000DB24D540B9DA35E9268AA76F6AE779858E
+:109900009B2E56298EB8F98508ADBF6B95F82711A7
+:10991000DE325503E3C5AB427F796E292BF7B7974B
+:10992000EAD205340EC2DBF241624D83234F91E14E
+:109930001D88539E1DC5E136B5F0FD1EF65389F511
+:1099400057CD3328CE68A01E63DFBB1B55B25F37EF
+:1099500055D5CCC5FE36376A646F6C5E58D34E71F0
+:10996000BCC610C531CBC28684F1F7E8B92A33C032
+:1099700059B9DC68477B33322B0418772AABE2FDF8
+:1099800045CE028A43F9219DA865CF688F0AD9B1D7
+:10999000D8DEA2ECE7D09E690CE832C6FD2D737FBD
+:1099A000FD384A85E33FF27F01E2E39F2803D2DDE1
+:1099B000E66F343D587FD8FCC668A648B86C717015
+:1099C000911E05B2338A804B17099729122ECBE1DD
+:1099D0000270E9B0797E10E7F9851AFBC3F31B1D0D
+:1099E000F986D5DC7E77DA2D7ECFF7D1E68B2EF7A0
+:1099F00047CA695E9E0BE7F27CD1E1EBDB79A223DB
+:109A00008D17C097C3531E197EADB0FB0A7DF78F2B
+:109A1000BB2986FAACBBE2DFC4F366FEAC14EF2BC5
+:109A200057C7CC303EC5F7CA9B5BCD3CFD7DC3CF4D
+:109A3000F5701D2486E54399C0FF10C31DF37EEA2F
+:109A400014061F290CAF96FB86CDBFD414AB99E644
+:109A5000ED421FCDDB002A039C37557C1EFB219570
+:109A6000A8253D63462B1DF3C7DFB487E6CF7F579C
+:109A7000CA2035127FE24847AF9C78E522008E72FB
+:109A8000F5A9CBC9237E91577C9AE5C4DF2317350E
+:109A90007FFCE922E13245C2658B83537BA4A2F4AB
+:109AA0008A9A2E122E53245C96C3AD9DADF2F5DC3E
+:109AB0003AD6817900FEF3345779ED7921F7F739F9
+:109AC0006157B96BA6BBBE3ACB5DBF6B96BBBE7A86
+:109AD0002EAF1F567DF3709FBFD879F2EA49CE931F
+:109AE0003A6D78F848E308F34AD38358BF4C3120E5
+:109AF0005B4EEB5546AC5B79F7C96B543EFFA7F85C
+:109B0000F9BEFD26450FA21FF98F3E4E45E5F8DA56
+:109B1000E31D095F5BFFBE260B7BAB403E38C4F8FC
+:109B2000B9083F84E268E718F3B5E6DF303AFA9FF8
+:109B3000E1F9F0DE765F54930DAAC32F66F619247F
+:109B40001D71988B2B149E87C3F880F6900A891696
+:109B50008C3BAFA9F2913DA284475837AA1C7A2BBF
+:109B60004FBE5E2E2E05269EB3A04F06C0DCD779D1
+:109B7000BFA13810DE11E82767BA1453E8CE0418E5
+:109B80000386C493C1789E0040938EFAAC3C78BAA9
+:109B9000DB5D42ED4AE626F8A06414ED2AFD944709
+:109BA00073DADB1D01DF20DC4DED322FA9FC83B120
+:109BB000B976FDB114BDC4FC59D9914787E7252872
+:109BC0000FC517CF52DEC38428F9656BCB6F70E5E4
+:109BD000897F45AD71C58754BDEB8B12EEE3565DB1
+:109BE0006FF60F23E71D4C5D517CA46AA9D95F571E
+:109BF000186E307F1FF340F3CC832E359941FBDD87
+:109C00009A1CE6FEBC92A27863B75436BDB7210712
+:109C1000A754314DCBF00AC74D0BFDBDEEB1BE3898
+:109C2000DAA90A6CD8279DC3EAC90BE3CEF8A5F7D9
+:109C3000A954296F3AC77387EAB6A7D68C20EF23B9
+:109C4000DA3D6A3C992F2EFAA0CAFD637F28FFF700
+:109C50005742CDDF522B86D2ED47485FF46FC740A5
+:109C60000FC6DBED3C5AA56ACF734887B5150B626A
+:109C7000C38D9739508707F9C258BC2F64EE5067DF
+:109C80000E8BC74E75661EFE858B8B7F03F3D374D8
+:109C9000062A8BF339681F494CDE4383F218874E3E
+:109CA000D457CCFFE8657C0BD5C7612B2BC7E66981
+:109CB0000985D94BB7346C018C5BFB99FD44FE8957
+:109CC000DCC4EDA73A6E0F99EC0F8E23DA34BC5D3D
+:109CD0002D7BCA0754B73DB4A66D2738F3DFBCE728
+:109CE0002DECE7D650F3F3F9E9519C3FBC99C90B31
+:109CF00033EE60539B46CF5BDB747ADED216A3E76C
+:109D0000FA3683F2F33BDBEAA8FC55AC3A1BCF45AD
+:109D1000A57AAA19FD7A625B9F5BCA5E6D46DA522C
+:109D20009C20330FEDE45E2C53BE1F7303B13C89BE
+:109D30007F7FAF2B3D0FE30DBD411B7EED3CD35527
+:109D4000BE73CD5C8417718648F77DF3D0DFDF3CAE
+:109D5000C9CE4333B54F38D6BD9A003FAF42BE2B74
+:109D6000D5EF5883FD0715BBFC3D6A3F570613F13D
+:109D7000096ABCFCD1C00EC2875400EBEFE381EF4F
+:109D80005379F3141EEF87C58B46A0238FEFAF5195
+:109D90000D1EEF5A5C46FB472A939B1AF66AF3188E
+:109DA000817791ED8092E4EB9D38DF5778DE8CB0BF
+:109DB000AE093C469E0F26C5D1ED736BCA2FF2AF9C
+:109DC000D3A7BBDFCDFED1D1456B4A9AD87CB4A5D1
+:109DD0002F8BACFEB19A9C13C07DA4F9FB6859513E
+:109DE00063596E3714D9FFB8809D079924BFC9A65F
+:109DF000B7A273FB6385879FFE72BE6F1714E7538C
+:109E00008AC5FB73AAE847B4030F4DAF1CCECE2A18
+:109E10005FE843636C506F94CD0FB9CA7A539908C9
+:109E2000DAF072B46182AB1CAEAF7195FDFA875D5A
+:109E3000F54F965FADC25EB4E13FE61957B3779C2C
+:109E400045B6FB6269E25F0233314E05752946D79C
+:109E50003B3EF300D13F34385F17749A4D942F2E58
+:109E6000FC8A0B7959B7BF9FD76956B1B2617F9F02
+:109E7000C9BF9BF6F7E9BC6CD9DF3FC2E1D15F6691
+:109E8000E58EEEA99D167E870E8ADF42550A1639A9
+:109E9000F44B787C7317E2377E492666B1F7BDEF45
+:109EA000CB5C6E211D73C2DDA5713FE02753BE164A
+:109EB000C3B8E5BAA90FC480F49E94775FF0D900C7
+:109EC000CF1BAB0C256E4739667A6D00F3050F3D4D
+:109ED000201B7C5D525EC275D167F17C7D15E2FB73
+:109EE0004CB48FEA78DC3A24BE131FAB73F0837C4A
+:109EF000F5943FA2F1F5FDF79864C9C6F3ED52F36E
+:109F00003EEA1732520B9BF755160CE0F92410F677
+:109F1000DF445E15CA13198AF74D62F4C47DF6C991
+:109F20008B07DAFD8CD6C612DD8753A46669DC0781
+:109F3000A4076C7B72ACF4017B7E17F9857AF9CBB0
+:109F400029C0757CEDD4075A912E81EC97C06074BE
+:109F5000FBD749293018BDDF0E70BC024BD2407AC6
+:109F6000BB364D74F6D26BDD20DD332EBAFF4CD4F8
+:109F70008F2579BD413885C19D3D14AE37989EAB84
+:109F8000A21D3785D3D1DBCFD100DF1FF1E261B74E
+:109F9000EB85DF1410FBDB5A86F6397E32F5A61806
+:109FA000C6B7BBA730FED717E6FFA600CFBB324E21
+:109FB0007C99F46FEFA4DB685F735DED16B22B8FB5
+:109FC000327B02F3367BABF3D7EF6EE3793217C205
+:109FD000DD2D358C3FDD07648AD77AE1BE1370DB57
+:109FE000CD5A95DB2F64F2F74A60E6C8F22747B6F0
+:109FF000F279394AB953698AE2BC1BDF89FCF58BD7
+:10A000003273E63A851D40EB6CE5D23438F31E8F8F
+:10A01000097E3D2DF474B08ACB47AFDF929CFC8B58
+:10A02000B1F7731DF50AF1AD903CFC58CC877795DC
+:10A03000782B19014A4ACFE7572BB17FFEF97CC72D
+:10A0400079B04E25A3E9887FDD6D92D3BEFD869958
+:10A050008C6A0E7F3614BBE4E7F3D10F52E279FD30
+:10A06000F5FF659A65DA4CB4B360462D9E5B50AC43
+:10A0700000C2AD57B22DE45FD4FA286EBEAEEA86B8
+:10A08000BDD538EE7A5F1CC1D6543DD582F6C5BA2F
+:10A09000DA4774A4DB2BFAA22A6C27105367D48EFC
+:10A0A000A5FCEF048E3B5CCFDA75F0DBEE3723E4E2
+:10A0B000FC5EDDAC417C993E3853FB1BE883772185
+:10A0C0001EE3C616A3739E7570289D79BE4077D592
+:10A0D000103ACF71D23980749E81EDC6F3C6311823
+:10A0E0009D2F74D119189DCFCED1B9B78AD3B9BBE2
+:10A0F0006E4B4F8D93CE754FEDAD36B07F4EE7076B
+:10A10000357E7E37847476E0E9A57358B2D79FBA5E
+:10A110004EB43FBD72CFE87E29E263BFF769FBC84A
+:10A12000EE0C8F4F7C82F8C0FC6594833BA482EBDD
+:10A13000D227116EA475697D80EF57DEA57139674E
+:10A14000ED5F89FD42B968DF5E6FC57A7899B66BBD
+:10A150001EAE870CEE6AC2434F913F3C0867C1B008
+:10A16000EB28ABB79CDA0F7BDA376154EB316BE746
+:10A17000266A47F3F46FC029ADF3ACDD761A97E297
+:10A1800069F734DB13AC9F8D9AF0375D74F82BDBE5
+:10A1900031B1A4471E94B44BEFD9F250B9D40D5746
+:10A1A000785D4BF3756DA85D4372FB6CF7DEDDE8FF
+:10A1B0009FBDA29BFF07F935DA7960DB8195A1E4A9
+:10A1C000A3482F6607521EA9F58D92CC1A5657F94F
+:10A1D000201DE5FBF0EEF568BC6D0FD5F27520385B
+:10A1E000CA75E98026F204C7301D55CA9EFE446B2D
+:10A1F000BE78C33302CE6B37FF56CC2705121467E7
+:10A20000EB8C5DBEB39FF1CE6C49433E3DBF3494B1
+:10A210007C16E9A3EA29939657112729D46E79C2AF
+:10A22000DAB5B781F4EE803C465418C74D6B8CCB41
+:10A230004519DD0E6914528B639CAD62B13517F57B
+:10A2400058159317841FD7BA4F4AE6DB2717F41E19
+:10A250008B48E4F15FC67D6A5692F2E216368CE0D6
+:10A26000DFF0FC3C663FFC0EC775484D5F32C541D0
+:10A27000779B4F5F9312975E84FAF47CCEA7D251FE
+:10A28000F2E9CFC2AE8685E534F80B4F5C48E77F34
+:10A2900082115F02E3F1417F5A2F73C8D1381F2426
+:10A2A000FB46817F130CECFE00FDBFB08FFCDEDEB1
+:10A2B000F055DFC6FB792C5D8D4F3172FDF6B2F59E
+:10A2C000BECCB1FE78E35683FEB4802FDC2F879B93
+:10A2D000629D4BFBFEB9FB85DC79084CB0EA307F10
+:10A2E0006895CCE3E877947C85F211565B013D508C
+:10A2F0004EEB18D97FEB445E5BB7C86B5B2BF2DA91
+:10A30000FCD6AAED08BF192081F1C9F6F353B4EFCA
+:10A310001F5534BD834E0CA5CEC575225A6ECFCFC6
+:10A32000C7E7A37D3558B6EEEE6C66E38DC6ECF25A
+:10A33000ED347F3BDBB9BEF94CF057F351DF18E247
+:10A340003CD6E6C645A5304C5C325CEFCEA30BD5BF
+:10A35000865C65ADAACC5556CB270CBB7FB10FE30D
+:10A360004515389E7E88239E05F286A70665829352
+:10A37000E5690359CC3B98A3C6B71878CEDA9DCFD0
+:10A38000D913E4F6E08F30303413DD2C21178D7CA7
+:10A390007FB564764D1FEE07C1182E17982FE894ED
+:10A3A000874272F1F7A68FAFE4700CF32F6EE98845
+:10A3B00002E6BBDC32FB97F1AC817AB53F86791AB5
+:10A3C0006B9826E960DF37CEFEA5912FAEDCAF2576
+:10A3D0009705917EE104D95F9186243DFFDEE31A63
+:10A3E000899F7705F93A3755F053417E36E4F8B93D
+:10A3F000AE91F1B32137CFD72969AD187E7E0CFB22
+:10A400009F897AE8F7E4B7AD6FF4B5A01E32A08F4C
+:10A41000F27037D6FB7CD8FEDF8B2E365EE1D94C4E
+:10A420003F129FB2095C1736C6151FEA917F383973
+:10A43000FC4B3FBD2F420E7F984F0E97D9F250B282
+:10A44000AF355FFEDDD4A0E4E2D706E417A74B0BDF
+:10A45000A78BEFEF4297C1F5424BAE40B959165367
+:10A46000C9EF56CA7ABA68DF88AD7BB86F749D6C45
+:10A470001AB8EF04FFE1E7F735E1BAED585FDE0FF8
+:10A4800006793BF2860594FFC186867E192B7F688C
+:10A49000D87DD18C7FC0798F89373FE350D0BDEF15
+:10A4A000F44ED5A252E457A1F6DE6CDBABE3395B88
+:10A4B0003B4FC3FBFD3A1952F9CE2FFAD120263A71
+:10A4C000F4A944879BD95A3B0DE9F1A1F9783EB331
+:10A4D000BBAA631CD931E27CC375DB9ED115079EF4
+:10A4E000D7296CF99B3E743C367DAFC365B2CC5125
+:10A4F0003FB3D755DF5B6FB03D519FD96DC1107B26
+:10A500009A4A6A2FEE3BDBE738D46D73B3B46C160E
+:10A51000C09BF1F194F02EF63CC73B5BD774A1BF12
+:10A520008DF6D7794C4E5EFBAE1CEF605F97DD7DFC
+:10A53000D67C3CE77A08B8BCD8FC7963EB9A71F911
+:10A54000E4A2107F2E0EFD75E46B7AC8235F7D9721
+:10A550009566E1F4CB57A2907C09FA1CEEE3F480F7
+:10A560003BC7E6E553A1F10CF2C9AE27E4CC5BBFD3
+:10A57000503D26578B433351AEB2D139C5C895C033
+:10A58000D7E6DFA9E23B925C69AB6503CF75552B3B
+:10A5900009D29B3DE51D96B8F791F23EE5F4347E75
+:10A5A000BFCC607E3B64D19ED0CA4DB2A343E2FED5
+:10A5B0009E40AD5B6F2A31F7F989586B226BB78BE0
+:10A5C000F14B6DB54AFD0EEE2387211B8C6299EF8E
+:10A5D00097A2FA43BF22007751DC93D5CB1BF7B487
+:10A5E0009F8AC85BC39C5EBAB70D3E3D429E8BBB43
+:10A5F0009FD8E2E1F36CBCF010568C430EBA17AE54
+:10A60000A7C021879F739BB877D4A6BFB9ED4ACA6C
+:10A610002F0F822F4EFE41EC260BFDBE2E319F7B6D
+:10A62000F0399BCEF3EAE4AF197CBFC592AEA638F1
+:10A63000837DFECCEECF3E7766C38DC4FF55389F39
+:10A64000F2CCEF3D21EE8F1DFB4AEAF7E887587FF9
+:10A650000203EFC97CACED38ED575F907D43C6F83F
+:10A66000FE33A1710477C140BF3CCF312F2F10E7DB
+:10A670003900FAE47CE7BDFC56E0299487270F7384
+:10A680007FECC9C3EF901DFEE41F7C1994BB278F9C
+:10A690000F9FFFF098F08B6CB8C7FEC0EDB3C79466
+:10A6A000BE927CF65DAEFF0CF7070FBBE515943E3E
+:10A6B00019E5E5D897F7C9181F78AC4D935E66FA8F
+:10A6C000E77C31CE0B0EF7CBE8378D34AEEF79F85F
+:10A6D0006B8F737B13B747B737BD13C2F8FFF6C74D
+:10A6E000F9788F8A73B285F07DAA8DE7796C7F3C0B
+:10A6F0003F3D9ACFE7FE71B3DF28CF6BD77ACE5BB1
+:10A70000CDD364F739AFD38CDFEE266E77ED56E20A
+:10A71000E193C1C77E5FD2149770BD2B85CCDE0F4D
+:10A72000551339F73BE322A507BFDE7E35E6B75E5A
+:10A730001936A51896EF9226B3B23E41067F0CF368
+:10A7400037DEC9BEC0F05FDB5A42F91B9D0DE5ED57
+:10A75000786E73ECF2DA5DB88FDC8B1115CA5BB8DA
+:10A760006B2DE62174E27F5939B03E7D119D930037
+:10A77000AE0F98456B28E3C4FE469E790EB9FC0ED9
+:10A78000E98340AE5E217AA99E7C90002C1A5E4F30
+:10A790002DE57ACD627F3EA07352EEFCDC312DAA0E
+:10A7A0008B7EA59EF6CF2EE1F23862FEF829F65395
+:10A7B000065B3483D15FADF3E9198487F818CC0FB9
+:10A7C0002C59C80C203C1F10D377F98C91E9BE1688
+:10A7D000A085C7B7FBC039BF9A4BB87D3FE1DADB34
+:10A7E00025F4238EC699144CC3F2F178BE79714BCF
+:10A7F0009BFB3E915B1A1E21BDD809991E5C4FAC94
+:10A80000061FAD67BD75FB7567FD2B4B24911F6659
+:10A81000F31F0C6516DDEB484138A5CE6706A3276C
+:10A82000CF7FC543D791F81F59EAA6FB68F9B21C40
+:10A83000F93F7364FE9F6A3F36DF86CE8F76C1B7DD
+:10A840001B35A0FD9DE1F5FA50BE6DA175AEA42E9D
+:10A850007F5EEE0D2576DCD672E95D0D521077E451
+:10A860007FC9E367B5DE0785FB95CBDDE31B8C3342
+:10A870001A9689FB7FE35919CF7733998E6701CFF9
+:10A88000F198807610337FC85F933DFEDA6D428E7B
+:10A89000343840F5D92CB0745A37785E9A9D877257
+:10A8A000911C8E637CA2470FD3BD48A81F799E0ED2
+:10A8B000CFE72FE528313B600026B37AA14A192C57
+:10A8C0008CEB35097C25267798C77FF08D83E88F40
+:10A8D000841BDCF968CAC192177DE7A09DE6390F99
+:10A8E0007270F972F25F3C7C1E6D7EFFC325229F61
+:10A8F000AD04C2641789FA85F2F46CBBDEA6AF71B1
+:10A90000224279395D0725A247C5E4C47DE87FC1AD
+:10A910002F65E0F99760E23DC6AB7E3693BE0FDD52
+:10A92000374854235FDE3858A27754179317994855
+:10A93000B633F8EA8301F29FAA416FD6B0BF7E8991
+:10A94000F8288DD3282F6BD54FFDF70586C9CBB2DC
+:10A95000F71707CB4A9AF689D7D54ED79CFB979520
+:10A96000A1E4CF4B1CFB9741B19F3874DFFD769279
+:10A97000F3D1EE6F945F76379DEB2F1F0F62FFFDD3
+:10A98000D30BD04E595701AEBCBC7595BCFCEAFA4E
+:10A99000290B701F679DC8BBD337BC73513BE9DBE4
+:10A9A00004C5F95633C1437AC25EBFB84FD2187F8F
+:10A9B000E9307AC34B870DCA3ECA8BFF6678FFC564
+:10A9C00067219FE23E8ABB7DF346BEAF6AC3BDA24C
+:10A9D00037FFA184E6ABDE89FBD0139320F234DD90
+:10A9E000FB1F1370F560E39CC418E467F43863310F
+:10A9F00074A0F8542FE9ABC4F5786DF92363F8F926
+:10AA0000FEF9FA21B2CF65DA872E84AFD71E2F3434
+:10AA10005E7B5FDD5BFFF608BF4FD5BBFFE58DFBBF
+:10AA2000DC87F465703DB8EFF411F6F467F2C6AD5B
+:10AA30005E2DE1F1E84E6341E2F3382EC59CFD2A1C
+:10AA4000A347A63C4A7EA2FFB2FA2BF08A3E1BDE49
+:10AA5000CE5B5384DFE62F4FD1BAA668A656C7C691
+:10AA6000A11D90716681966E277D65DFFF80645D14
+:10AA70007C361F2F8E2B00DCFEC5F3091F38C60D58
+:10AA80003147BC0BF58AF0D34E03BFA787670EE5AD
+:10AA9000EFDC1E9E771E5BC6CF334D54F2F37BFC7A
+:10AAA00012DDC7F7B94E2F9F0BD52FB4BF79FB2D01
+:10AAB000EA02B453A6E8ABF64E62787759A549DCB2
+:10AAC0007739E64FD13D39BDFFEA832D80E31F7E04
+:10AAD0009DEBF4AC738A9EA0FBF4AA52FA749CE638
+:10AAE00085EA7D2DC5FD1CEFFBCF87F97AB329558B
+:10AAF000B609F319CCA753BBFCE857C6B8DF6CFB0B
+:10AB0000D94B43C9CF871DFA68CC7C2E3F5392574F
+:10AB1000D0FC3F5631FC3D0BEB3D789740FEFB5D92
+:10AB20006F8B707CA618AB78BB93868FBBDAF4383A
+:10AB3000DE238BDF8B00E487F8990027187DEF3543
+:10AB4000B87C2806FC14E56CB2E503C3C0EF03ED46
+:10AB5000A877BFE68365F9F0688BF0F935D964A66C
+:10AB6000A7A887F6693A62D0FC1CBF84D3695D351B
+:10AB7000C4C3ECD519D81EEB7FCF1495E492F9BE6F
+:10AB8000742F526035D0BA1DA8838C81FB0ABBBEDE
+:10AB900094457EA9F5100FB27ABBA774D17D2BDD49
+:10ABA0000698786F92FF6636B1F07BAD2F6362BE78
+:10ABB0008975157D5FABF37BFCD6D63603D9B131F1
+:10ABC0005ED60C7EDE65DD5485F0B0EF1F27BB93AB
+:10ABD000AD0FFEFA812C5E5967C0326AC73F9BF306
+:10ABE000B5EACE263A8FB66ECC0374DFBFB51CF83B
+:10ABF0007EA6BDEFAC30B962EF3B97E979E327EF72
+:10AC00008592DF72CA83A2EF2379289407D71DE6C5
+:10AC1000F4BC4DE8B763FE2CDD6FD8BBD647F7B662
+:10AC200078E13F2BE87F77E7A28FD3F5D4629DB11F
+:10AC3000BF1F2A315CF765541D57693C0BE49B41EB
+:10AC40006778DFC3EC24BAE7052F063D931AB8A452
+:10AC5000D2716EE59E781FD945AA6D17D5737BC654
+:10AC60003EDFC8E890FD26FBAE639E3FF303C7B707
+:10AC7000E6B78FBC7E5921FBA8A7C4FC19D2AB4B09
+:10AC8000E4ED7F7DE9227E6F6581BCFD3BC5F8EF79
+:10AC900094ACEA2ED48F93F83D335EB843C25E6421
+:10ACA000F620C9CD3A8BDFC7B58EB93E8FB272CFD1
+:10ACB0008DFC3EBF1ECBC7CF7FD602C54962375D34
+:10ACC000A5E59BAFB61DBD5EDCAF5568DE95A899C6
+:10ACD00064BE75E99F227C5F6D6CA3417E1B51723F
+:10ACE0001C2E279CEEF4C4785E1D5FB7CF007D2E2E
+:10ACF000E6316E5E58534DF77CB275036DE27BAA68
+:10AD000033D9F9289712F4DD8F95948CB59495CFAB
+:10AD1000888F337A1DE7BAF5AA07B278EEFDF627D9
+:10AD200003106864E5F99EDF67E3E40F2AC83AF789
+:10AD3000EF532934BE629FB7327ABDE488370324CB
+:10AD40005B703E85D87A8AF326D894C9D2EFD3B007
+:10AD50008280E3E8D15819F9D21902BC6F36541F2A
+:10AD60000F63DC36D43FB7859EF5895E949FE8EC8F
+:10AD7000AD7ABE73312D916A97DC87EBDCF99A418D
+:10AD800071EE2858A552BE5A30A9E6BDDFF85089A9
+:10AD9000C2ED68D625CEAB1E6B783D7BAA72F1BAA8
+:10ADA0005867F49C7F4C72C14325EC59B5E00DD92E
+:10ADB00071DF66C4EB5F78F9E8299F2A1F7B3D7C31
+:10ADC0000C36713E02E323BF07C4EAA17317860F56
+:10ADD0009CE72EC6476A5CFC508E2B748EF6CEB96B
+:10ADE000F9EFE31C1FE179DD3D25894B2294570BD8
+:10ADF00012E5F70ABD7091BC81EE3162D2C1EF8FCE
+:10AE000067FDDD9F473F8E8F70FF756BC8BC3C525E
+:10AE100051785C8F4985F0E0F50F093FBF783DCB55
+:10AE2000C737C57C2D4871CF2F0DBFEEDBEBF3315B
+:10AE300036B67D686F2B29D23B4ABF019D389F6390
+:10AE4000BE0CAEABDDB145A417EEB1988C4824978B
+:10AE50005086FEADD01350DF1FC4F88B5FCCAB7BA8
+:10AE600056FBE8BED8508542F7D7066E4EB2B510F5
+:10AE7000CF350E6431965F75E702C293AD53372329
+:10AE80009DA3B1BE76D447FEF20CED0BDFADE821F9
+:10AE90005CFF8FA191C8ECB3EF86B777519EBF9945
+:10AEA000C8E29597E81639EFEFCF58EEFED800DAF2
+:10AEB00051EF7436E9646F9F71733F38E72BEB777E
+:10AEC0003DF265625D66AE64E4D647AF3D51C88E23
+:10AED00060EBA8F0CBE675A15F46262C2B3F147ED5
+:10AEE000A40BFDB07B75F3AB11F283F2FB0F4C2E7C
+:10AEF000BE7E3272F1AC98A7B65C0CC647441CF516
+:10AF0000AA46103FC615BF66785FB3D70F38FE0B51
+:10AF10004FDCBBE79B8C1EB23817C734F99E27D88D
+:10AF2000F7A5A696C0F23507CF5631CEFACB093237
+:10AF30009E0146398BA29CBD053E8AFFBC05FBA342
+:10AF4000331CF83C21E60973805EEA77C4173F9F03
+:10AF5000E6655BDF7DE14E77F96A58340EE387578B
+:10AF6000DFEE878C84BF57CAED177F27C2F3C5BFBA
+:10AF700000A92EA4F35A71EFE9F21F9CADA27D74D3
+:10AF8000CD0CBD1AF72F6D3C7E22D6B337991C1B12
+:10AF90000EFBF5DA7046C57CA79777CCB87C0E60BF
+:10AFA0003B99AE09B85E8D81BCEBF4E77ADC788E14
+:10AFB000340E2FDEF679A1427828DBA4BC71AE9F57
+:10AFC0000B7BDAE6E3A9DEBFFE7684EB03FBF7D367
+:10AFD000D97962A7DAEE7BC2AEF6B6BB5CC30BA42E
+:10AFE00001562AE916A926B76F15F4A7CC8968DFA0
+:10AFF000ED9C9BC5DC73075C4F91702DBE61E046F4
+:10B000001ACFAAD03D518C07F5337F3FDF3D3A95EB
+:10B01000A164245A31F43E1D10BF0FE8D06FEC7BC1
+:10B02000EA0716601C2F00CC6FA7A7427240F11DE3
+:10B0300009EDD17416FD80A0A1B8E4A304F74398EC
+:10B040005DBB52D88F2575EEEFDE78CF19512E07F4
+:10B050004DD04FF67D540B6771BD854677FED21DEE
+:10B06000259F253B72C53E3F1D015801C6AD4D0DC4
+:10B07000340F29CE75E3BA33699FF7C60A83EEF918
+:10B0800055206E525D8FDCAD3C2E41C6E1FFAF54C2
+:10B0900006549C6F2BD9FAE17C7F434C365EC9F392
+:10B0A000FB99ECA79F69F5701DD2C1C7CFC5EAAC6B
+:10B0B000EC18E73B69A985EFAB19A58B87F1CB6F3E
+:10B0C00088A9D4CF55EBA694F2B88F5B6F1E11EB15
+:10B0D000D47F3EF41F2AAEBF6F3DF8E2254887EBD0
+:10B0E0001E934163FD1E792802595ABF322AAE5F72
+:10B0F000D7EE90F3DA5598A9447925DB797CF2DA1A
+:10B1000047029985ACFEB58FBE7C0E30FC8E740C68
+:10B11000EC9988F3E0411E3704ABFF9CCBD8FB6B66
+:10B1200015F8DFF9ECA62BA2DC0F38FCC312BA7FAE
+:10B1300054DAB6EBB3D46EDF15FE80637FED92A8D0
+:10B14000DF86E371CE6F4B992979F6DFECB8FAE12F
+:10B150006F4B1CBF9D7EBA8FF5DA6DF7A94986C784
+:10B16000CA6D6F933E99B7FD3B51A4C3CA9DEE7D56
+:10B17000B6EBB6BFDF857924D7C930B010E5593EAC
+:10B1800041E5A3A6362093DEE7E7A557104B18DC70
+:10B19000F75E5BF06BF6FDCD980C41A67ADFDCF72D
+:10B1A000AAFA189693E1147AB02B77BAF5DECA6D35
+:10B1B0002F535E83EE8381AA39B8BFEF966B2F3C85
+:10B1C0009B3F2ADA212BFBD6BD2D33BDB172C75B65
+:10B1D000CFA3FE58E9D19F6FE27F2A87C6A1DBA2E9
+:10B1E0009E7B66B61597FF70DD778EDE63B17E0FAE
+:10B1F0003FF2BB7B304FFEFABFBC7BCFBFA3BDF09D
+:10B20000645047FDBFF2C15F44C1218F5F8F727BE5
+:10B21000EBC824B02A19DC91FF17C8E0FD57479E00
+:10B22000786D329E733BF2DD3F8E3318FC8D4F5CA0
+:10B2300044F7EBDFF8FD79E387B3C7515E330127AD
+:10B240005E197E5E6CA7C48D97C7C5D3C38FC3DF5D
+:10B250003DA6A25DFB9E0403B8CEADE87B5F457FB3
+:10B26000648F0903489FDD3B5EDEF36FACFC16E3A1
+:10B270004F200F7FD8F827FA68FD666A923D57EC99
+:10B28000787901E2BB1206683D1DC2CF038C9F0D89
+:10B29000397E7ABF1F85132AC663573EC4F8770EDE
+:10B2A000F291F1EF9CA1FC7B0BFF337B28FF7E101A
+:10B2B00075E7091D85EBEFADC48DDA1D63F3E6314B
+:10B2C000E4F61186BFCFC4D60723D17799C4F1EA3B
+:10B2D0008C9AFF19C579F548C9207F17227FBF7363
+:10B2E00074323A39AFFB073E8B74187822A0E3EF33
+:10B2F0008FB8F6895FD13C3BF2FD675583F66D2030
+:10B300002ACD626518FCD90FACBC82C7B661F9D6EC
+:10B310003F2F789ED55F8EBF204327BE51790F9B6C
+:10B3200077C487CCA52D06AE9B990A1AF78A0C9F85
+:10B330000F2B32BB16E3BD125EBA4BA5F6BD9E398C
+:10B340007EE27D4F2B76BCB800E5AE103FEDF1EB11
+:10B3500038FE73D9F7ADEEF9EA855FC1E627AD5344
+:10B360005EFE6676FD373E8FDC1750F07CC51171AE
+:10B37000DEDBCBF71CFDC5F9F751EE33FDD93BBF42
+:10B38000ED7D2641A7C2F2C1E7F948E31B2DFDDEA2
+:10B39000881ADCEFF6D0F1F089FCFA7F7C295FB7E0
+:10B3A0005740BA054D67AFBDA240D29A589DC3F72A
+:10B3B00030DA170CDFC30FCA14F7E9EADB4D7ADC89
+:10B3C000AB2F561488BFD6D9FDEDDC750EEAB5C398
+:10B3D0004FFD90E473C5432FAAE877ECD9F63DB54D
+:10B3E000BF3E371F707DC838E87DF8E15DE7707DAE
+:10B3F000903FAE3553B4BFF27177FB2B1F7ADBD58C
+:10B40000FE75561FD90B23F5F3A6625E81E37D73AB
+:10B410009F9FEE137CB34FCE1BE79E50EA77D9C1B6
+:10B420005DCF2EF8359E676DD81FA27B1477749878
+:10B43000E36F41FB6DBF5FEC1F9ABF43BB74C7B3A3
+:10B440002103EDB41DFB2FA77C1EBBBD1F78E8793F
+:10B45000EE016B5E84B5776E7FA201F345BC7AA3E3
+:10B46000F120F3F71C7270E3B32DE351EFA37F6C6F
+:10B47000A0E3ADC4E91C951C5D4079E2B2EED38334
+:10B4800079D76FDE9E3F9CA0FD1C3F134CE7BDECBF
+:10B49000179EF8BFE4BF77C5F3C7FBEF2AB5F7BD2A
+:10B4A000F9EF77B2DF6F90B8DC58CFF07D8E42F3C2
+:10B4B0006B5B5B2C5ECB4879575B631CF77396978D
+:10B4C000F2F8C7D4572C1F9E0D99DD6F4CC7F14F72
+:10B4D000843EC0F3FA3BDA74821FE4FF4266519760
+:10B4E000E37DF3104738EC17FDB5D1F67B73A17EF1
+:10B4F000EBFB882EC5F4AB9D44BFEB4BF979E953C8
+:10B50000E9377C127406DC1D2A62BCDE3C296FFF21
+:10B51000EA349EF7E5ED6F4929B733EDFD039A7ADA
+:10B52000C3C4D5FCA29DCF941A2E7902254BF74FA8
+:10B53000E7F22A32527703EECB0D9E174E688EF358
+:10B54000C2EC3B9D175E63F23C56568FE6418F88F6
+:10B550004FE03EE5550E7C9F15FA2350958AA1FDDC
+:10B56000D58DFB0D79F4D8F342CEBB23CD943FB2F9
+:10B570004B9F5EDA3FCCBAA1ACBE6B86F35CB1A246
+:10B580006725D7FEB0F932DD8355A8BE77DFD0C678
+:10B59000BF7BD797A006F35CCB13D09107CF3E219A
+:10B5A000C708578D70B124B43BE0D4181FA75DEED7
+:10B5B0007E9FDF73FBFCAD07BB515F16A2D30EC1AC
+:10B5C000CF6731116426B96F1AE663F6447CA4276D
+:10B5D0007B82F9EFA3FF45CE2EA0FA2A9E5FA478C6
+:10B5E000EB3EF21B8D132F9878BFD1ADF52AED0BF2
+:10B5F000459AF653F9A8E923EBBF107DECFB08064A
+:10B60000CB05E24F8D3AE7EF6EF311CA6FBDE16CE7
+:10B61000D5182E9F22B47A5A1CCFB36BABE7C43136
+:10B620003F2254C77F9FC2C6F3793C6D6301F998EE
+:10B63000A573F958FF453B2E992539D938CD17C444
+:10B64000E7FF075094EC5E00800000001F8B0800AD
+:10B6500000000000000BED7D0B5C14D7B9F899DDFC
+:10B66000D9D92730C002CBF21A10140D268B226ACA
+:10B6700035664134F8885915A326185763521201CC
+:10B6800037D636B4B5611010C447486349DADA7664
+:10B69000A5D892366D31A58D491F77D5E8B58FDBDA
+:10B6A000A2318937571B34DE5C494D2F7DA4F5DE6E
+:10B6B0006BEBFF7CDF996167965D3069DA5FEFFFC6
+:10B6C00077C92F999C39E77CE73BDFF9DEE7CCD9D6
+:10B6D000A3DE6909830E426EC0DF1DA39FE6862F9D
+:10B6E0004EAF981E2EB7E5C473FE224276E63C4E5E
+:10B6F00006E9D37CBD91F8687F334FBC7DF499E8AF
+:10B700002547139CB4EC9D986BCEA54F0749379401
+:10B71000D07E6513B91DB9A3E11FCDFA84EB12EDFC
+:10B7200097E625E9F06C2B13D20D1A7C3A3F1320D3
+:10B730003E3A4E6B99B016F034873E49A4384DBD61
+:10B74000682064067D5FDDE9F5D276F42FDD47EBF6
+:10B75000094FD25768DB71644D5FD1E8F1F78B1C5C
+:10B76000212984EC56EAF7CD7EFB990728FEA257E3
+:10B770002A365230FB8E0E91BCA9B41C1AF27230DC
+:10B780002F27996625A3E140BB5CDA2EDEE5271B57
+:10B7900000CFCC41E2A7E3C7170E1298BF4D22920B
+:10B7A000414238887FC2AC6122D3760973075DF2CB
+:10B7B000540D9C3F1BA3E27923C18078DA1A4A3CDE
+:10B7C000F9C984581AE679F2E9BAC4F10344A470BD
+:10B7D000E22446FFC87E6F2530FAA874E92C9B98B6
+:10B7E000E08F065F5DDFC653A9BC49532EEB5C03B7
+:10B7F000F43739FD32CC3F7E16A38B5A1F2F0D1222
+:10B800002F1D379EB0799212E23D441F712532817F
+:10B8100071E8905EED7C362AF4DE28B2F9C09F37DD
+:10B8200015DB11425FC579170E196F85324F2E1542
+:10B83000B2FA1BB90417F49245291B479763CD67E9
+:10B84000BCE7AE46422E69E66BC9A4F357E1D27F4E
+:10B850003B4D241DE8FB41E926B806911FD4F701B2
+:10B8600065FE26E720D26714FD8A18FDEC458C7E24
+:10B87000F608FAED52FAEFFA07A3DF089D38C31A6B
+:10B88000E0C3483AAAEDE78DE02DE393F623E423E5
+:10B89000505E5609F2DB6965E5FDE25D9572119334
+:10B8A000AB71E485103721A59D37DAA0BD5B14117B
+:10B8B000AE7913D5070E4DD9AFEA0736AE23D7536D
+:10B8C00049283F935C03394449DA3E5776C17A757B
+:10B8D000A0A484E1BF2A4EC0F66D9260E06EA3CFB3
+:10B8E000530BD20885DB6CE9B4C07CDB4D9D08A707
+:10B8F00039CB207647D16FC794F91A1BECD37BA6BE
+:10B90000C7A6A35120FE6872FFA6D2BFF9E8E74F91
+:10B9100019297FF092205929BE20F46FA9EB9B478B
+:10B92000FB93BE81DC5C18271EC7712878390A0C8E
+:10B93000A429777C3CBFA5F015DF601D134F1EF0D6
+:10B940008CA267543C5B004F676C3CED59E5C8A77F
+:10B950007C8303C7F99128A17E729802968D747E2C
+:10B960008EA604A9893E77F181F66A780E98884CF4
+:10B970009B9888F75439C59B9F3A8D100AA7F5E22A
+:10B980004CCB04E0FD864EE2D3E8F94D36FF05913D
+:10B99000C2E3453FF1533C7947C00B68F42A7CA0D1
+:10B9A000AE1B294C2264361DCFCF4F077D6AF70BA3
+:10B9B000F854E1A87C623779895804700CDE207D48
+:10B9C0005A00D8EC70BB8F2432BA35CF0DF908D8A5
+:10B9D000B9629E809D6B33794F6DA0E50E3A9F6EE4
+:10B9E000FA6C51F846EDE74E4C647CA88C6F2355F9
+:10B9F0000921806D7CCEE51FC31EDB806EB47DC344
+:10BA0000F9DCEFBCACD295FEFB3F629CF3ED5B90A2
+:10BA100077D3419EDF2345AB0D86D870FED4287DB9
+:10BA2000E7658DBE6A20CC7E1022A52D9F1ABBDF54
+:10BA3000EE46323DBF205CDEC3072C409F36C7D6A2
+:10BA400053B9749EB2C7E02990004C898E4E914F35
+:10BA5000429A70DD4DC403CC4B9A33CB4F954BB01B
+:10BA6000BE2B5C8F43B5D1C1535B4B4C1349D008FF
+:10BA700074919C3AB9DC64637C13B9CED6113A1E3A
+:10BA800018938E56454E22E9989FF8BF938E2265F3
+:10BA900027E4D7B8150921E8779CFA49747C92A964
+:10BAA000973FB59FCAEF91F3AFF85F3EFF483E194D
+:10BAB000DD5E56ED267F9436CDF093600787659F57
+:10BAC0002515BB5218543E2DA126304D59D57DE980
+:10BAD0002708D8E716F16D0BAA2ECF8DE4B1E0F35D
+:10BAE000E46D959EC6F0785AFA18C0EE9C32050FA8
+:10BAF00071613AC589F7BB8E920F4EA7B6CCE7C5E8
+:10BB00000D1AFB71592CDF9E48E9B213FCDA28723A
+:10BB1000B03EB15C4EA4780986E8FA7C3FE835F483
+:10BB20001B457E011DE78E613D9D6E57E8342FED6C
+:10BB3000ED4FC334A996E40955C8E53E4F05D0AD95
+:10BB4000628D0FD8820819D76FF1233F54884017B0
+:10BB50004E9E64B861BF79FAC5A2978323BE687808
+:10BB60007F455CF1259897A388D24DE37F50411023
+:10BB7000DFB66BD6C5E11C87AFD8BA1DBF90669003
+:10BB800069D336972108F18C8904DA81EEE4AC910F
+:10BB9000809F961A4AC77AB32B2F08F62E35642554
+:10BBA0005E8C13C4A095B6EF5A7B8F07F5D3B539D9
+:10BBB0002444F906751965323ED31B027F9A17A5F6
+:10BBC00032A304E33C6681F8A6CDB52281307F9B89
+:10BBD00044D35F7589FE17615DF96BF3109EC1E276
+:10BBE000453FF166E7F3F4CA78027E80F53C1734EE
+:10BBF000535C9E5C39AF7D90CEC742E23ACDF4D91A
+:10BC0000CCCB21B063F279AB04F4DE5A20DF69A01B
+:10BC1000CFB25F590B79FABE9DB379800EED0574F2
+:10BC2000C9299C3F7DDE1E24B4BC73E5B2E10480CB
+:10BC3000D36394A07EFF8DC06DE04F59AE3F81F17C
+:10BC4000A145890F091F9809EB67FD807A6237DFEC
+:10BC500089FCBF2B7F9A45EB8FA7DBFCE7812E6A1F
+:10BC6000D9EAA2FA6D3AF2D3A541CA4F0699233711
+:10BC7000287F5A1CDB5C2724982F7DAFF2476EB8D3
+:10BC80005D586EF56527A535F89994C316815FD97F
+:10BC900006FA06FD562273504E67F5BF7DF2EE455B
+:10BCA000E087B659D5FAE58BBCDAB2FC3FA7B0BF46
+:10BCB000E2F7162525ED82F6CE0C1260F4F19155CF
+:10BCC0001A7F464AE2510E7B12BD7F4C9C319A2F5F
+:10BCD000DBF3195F1EBFD05699077C4AF9D22C01BD
+:10BCE0001FEED2C5C9EA53E5C3B67CC667B1E86E9C
+:10BCF000BA564C421A3FD0E4EC447EB4387DE84753
+:10BD000047B6BF2B99E90B95FF2D2E82F26091FC6F
+:10BD10009F7F10E5C3E101F133E7070847F9C42429
+:10BD2000B27878BC79C4C24FE5FFB6FC3C19F8F58F
+:10BD30003D913A1263B4375D2BC1F9D4257A7392E1
+:10BD400034F1873387D23DCA7CBE98C4E6D3EAABD0
+:10BD5000F63D48E17A6B2419E5C6453C1D609728FD
+:10BD6000FB83DF49FDCD5B9252B4740A307954E015
+:10BD7000CB5CE0A809E4DC49FBD1B72DE487322C89
+:10BD8000BDC919D4C9F7BE647F4992867F7991C530
+:10BD9000870B8C0E03F900F47982C665A14984EC07
+:10BDA0006D14F1B9A7D185CFF646099F1D8D5E129E
+:10BDB00032D3F0875C3BF700F8D90E1BE2371E5FE9
+:10BDC000B4367AB07F4BE32C068753F9BC7017F07A
+:10BDD000B5CDA0CAC9AD584E30AAF525BB30BEE3DB
+:10BDE00058FDD6A4DB514EE87C50EFB58F33AE3111
+:10BDF000588AEBF7FEE12BFA5BA1DF13B77FA23283
+:10BE00000FF8EF7523D1E63146F14B888D77B3F00B
+:10BE1000DB330DA84F9FB87DE7A95CF05B5FA3F013
+:10BE2000C7E2C74E063F263C15DFA3BB105F335D5C
+:10BE30006F2B85671699BE8F250F91F3A54F82F260
+:10BE4000E124A8A79F38BA961C07F9A4C35A4590C5
+:10BE5000539F17F25D420BA5B107ECAD2FF455B01F
+:10BE6000B734D03944CB822237D4ECCBC7291CC19C
+:10BE70006B211DB4DFD1DBEF21D0AFED650BC589A0
+:10BE8000DA87E43CE4776B411569A6ED76565A896A
+:10BE900091BE4F98B78600BC9DBFB022FCDC539387
+:10BEA000515E77894C8EC6D5432E030969EDB8C51E
+:10BEB000162EE781BEDC447C5351AEBF90A4D18FD7
+:10BEC000D44E7E19CA02A990090776F8210FF343D0
+:10BED000587D4FA2EF206BEFC3FE61BF304044900E
+:10BEE000D7B3C66007C49BC65A74FA161A0F580611
+:10BEF00051AEBDCBD24B09713014C82E4F886403AC
+:10BF00005DD28DD417A32F3C020951BBD149FF014B
+:10BF1000FCF8F343E7C9AD84A4AD1174F3E0CFDBC3
+:10BF20002F1A6E05FC587BD50EF1E7EBEAA03D4FCA
+:10BF300034EDC13E19AB13C68A6722FDF81F2529CF
+:10BF40007EBC9D6481DD6B693C42DE3285E1F0118F
+:10BF50007925F5A9FAF39B930D7AFF4762FCFD1250
+:10BF60008DD3811F5B5F3592EE28FCFD87A45C9D1D
+:10BF7000BF9BEE3784E747FF7DF982B9BC4BC79F73
+:10BF800063AF7F468DBE7F56C0A6A3634E4392AE7D
+:10BF90009C2BBB75ED27B4E7E9EA0B3AA7E8EA2743
+:10BFA0003D334D579E1CFC88AEFD2DBDE5BAF2D445
+:10BFB000BEC5BAF6B71D59A12B1787EED5B59F7E22
+:10BFC0006AA3AE7EC6C023BAFA99E7B6EACAB30737
+:10BFD0003FA56BEFF28BC78E807C527E34527AED98
+:10BFE0004A979F01FB39D84CFDB879CC3F067B4B73
+:10BFF0003289E21F53C3940A7CC5FE5AC00E809E4C
+:10C00000DFF3E9D067D04E1A3C20BF7CFE42EF46FA
+:10C01000E8D7221A884BA347A48504DE97EF49C4CA
+:10C02000F7DE9226940F819A0D6B3CD86DFD7A1045
+:10C03000E376D207F8BDCEF0E34539AA7E1232F599
+:10C04000FC6F26F725F8C6F0FB4C92BEFDFBE5FF22
+:10C05000AC64CAFFE0706451FE378EDF5FE5FB47DA
+:10C060000CDE09C92C5F5E71D6A98B7B90AE237163
+:10C070008F85B4803895550F679C60CD95F8C66C58
+:10C08000B871CBCDC73791F2459F94E6749D5C4C57
+:10C090005FABFEFD687B385DE79F453E9BE31F413C
+:10C0A0007D47F5E2EDC93ABDE8F32643DCC77B5195
+:10C0B0002FAAEF737BA7A05E6E17999FD22651B966
+:10C0C0001C835E917AF9F34912D39F31F4B340F5A2
+:10C0D0002C18DC9D2BEF6F07BA79B711B44BD4063F
+:10C0E000A19E8D844FFDAA7B006FC1C5FC29351E22
+:10C0F00052E32D0BD51F105F592482F432537AD9A5
+:10C10000D13F7A0CFD4B3A0F09FC23B393FA9F60A1
+:10C11000EFA9FFC9FCCD0FD7BFCC56E63D4217C5EE
+:10C120005EF6D8BCB5C929B1E1FF20C67ED4CB49A3
+:10C130006ADCFDBF93FFE6264B887F241FAA7C663E
+:10C1400006A6A3E3BD27B175A7D38AE7D4FD0B09E3
+:10C15000FEE3477E3931EB8C3C1FD6CDEFF09AA938
+:10C160005DDD376B05F61326F004F44CDCE086A5A4
+:10C1700060274909D31332FD07F8CD56A4D71B9683
+:10C18000083B2A803D8E1F6D7755FDA0C6E7E3E989
+:10C19000976755FD3293CCD4EA975871B8AA5F548B
+:10C1A0003ADC71BD5144BFE33AAD57FD090AC7946B
+:10C1B000C5FB20CF2C7888F76014F9FB27C52EEF3C
+:10C1C0003D66C5F8DBB146C038CBED0995019FBA95
+:10C1D00003C403F4993518227E0AFF0527E34FB7FD
+:10C1E00027C881FFEABE1CE400CF2E13CB0BB9B7E2
+:10C1F00005396DDEE8DF93593EFB4F171EF3C0BAD9
+:10C2000097E738504E3FF620417B3DE0DAD859069B
+:10C21000E3CE221E334E97276E289F3307519F7817
+:10C2200006BD024BC1C97174E82B8D64DA261ABFB2
+:10C23000BFD368C1E7D546119FF3730E1CBD83C2FF
+:10C24000DD9A6BC37C416B9E0DC769CB16900FFFC7
+:10C2500098F5480EF805BF697461FBF6C703859031
+:10C260004F683BC6F68332BCD3711F14A9E6027C2B
+:10C27000426C7F870FB860DF37E3F84FB05D9BC932
+:10C28000FFAF1B283EF25AC17348627480F9B6585A
+:10C29000D9FCCDF680279196CD13C8FAE5D1E451AB
+:10C2A000A107E524A3900A7940C6A7C22CA909F2E8
+:10C2B00021542BF451F488A935C8C1BE077958948C
+:10C2C000202F9469091EA5311FC9AC113DCD04DA98
+:10C2D000136FD0115E0F9395F80E3BA05D887B9491
+:10C2E0008EDBEF64FB13EE736C7D7E7FFECEA35975
+:10C2F00024B61CEF69AC3C53A1C9BB3A48F4FDDF3E
+:10C300007373CAFF027A087D045CD79963DAC19B14
+:10C3100085EB75323D75FCC2A434F08B1BF8E8FE4A
+:10C32000A45154D7494A8378796B819496E8D0C256
+:10C3300061FAC278EC455C2F7B5110CF17347FEF48
+:10C34000F5FA4F53FAFE8E7684BCD4CB173E8A7131
+:10C35000E2BB49D213105FC93F351258CF77BF3FB8
+:10C36000F32449183DEEAF1B4F25F19ABCD1BBDF3A
+:10C370003E5D6AA2F0DF7DFE74298FCA26A8D353E2
+:10C3800075375E29853C95D0F07BF7658AAF5C4EAA
+:10C390000A0350A68E32C69B72DD92D01874EB4A07
+:10C3A0007DE851C80B069B1D2247FDB2A7ED7F110A
+:10C3B00080EF1A007FFADC6219DEC9D125FEEFAEEC
+:10C3C000B71757D078722B27CB0E0EE8269B217E0D
+:10C3D00020E7CD1EE09BAD05CC2E6E7D580CCAA08B
+:10C3E000AF42012FA6852CAFB82F537D6BFD79107E
+:10C3F000F6FA490BE79B1F0779BAA904F97ACED55B
+:10C40000400EEC1F2712210FF8D06430229CE10B64
+:10C41000F66037EAD9C04CD0374D171E9B04EBF5B8
+:10C42000FB64762E40CDAFA51A024F56E7427ECD73
+:10C4300083F9B5DD7C1FEE93C59AAFDDC5F60FF825
+:10C44000F944898F7FDB119A1BE60755BE22FBED6D
+:10C450006F249E7CCA5F2F355A3C30EE671B457CAB
+:10C460001E6974E1F38946099FDF6F2CC4767B1B3C
+:10C470003D58DEDD380BCBAD26B2DEA7E1B34F3839
+:10C48000D93C5627947DC2499FFD14EE65DAAE97DC
+:10C49000F687E79CB341631CA5C79C2B542F4A50D9
+:10C4A000DFEEB94CE17D91C283E7E87A4B31BC2FD6
+:10C4B0000DF685044ABFD222F6BEB7B157E977041C
+:10C4C000E1D27AA47FE955566FAF6570EC57D4F688
+:10C4D00085C5CA38C5D09E8E5BACF48B848BEF29A2
+:10C4E000DCE268F844B6A7DEBC91942AFB1410D7AE
+:10C4F00099FA38F067648E840EC17EC6F9A7CBC066
+:10C500002EEC29267906DAC894D2CF41B9B78188B2
+:10C51000C644420AD3A7759401FF98BCF85EDECBEF
+:10C52000070FE5A21D42B8AA1DCAA80D79817FE2B6
+:10C530003D24CF584CD741BA84F686D035B6CFA12A
+:10C540004353F1B9A4B1B337E87FE0BC01AE0BEDC2
+:10C550009F5EABAF1FAF3DB52711F5D1F9EE833E1E
+:10C56000BFD8A83FE7D15547B538D51B5D8A1F76A0
+:10C5700000EA61BDEA4A133642F9D187D2416E7FA3
+:10C580004F5C1CECBB8FF48BF0DB0E349E4AAD2865
+:10C590006078037D32B78907B5FE6CA64CF9552348
+:10C5A000077B037C6537E611FCE92B34F14FABC9FF
+:10C5B0009F4E8597FCF6A9D717817E00BB0C7AFAAF
+:10C5C0002357981D1FB1DF57997E54FD064159AF7F
+:10C5D000CF95FC2E04722F833D02FBE4F19372DAB7
+:10C5E0003F658681033B448AF5EF9D02C3CBED0A8C
+:10C5F00072504E76FA5E06F9E1939E21C0477FE8BD
+:10C60000374BC06F7B8FAD2D04FF790B8997ACF44E
+:10C61000BDFB871705C0A3D5302810AACF86F66FBB
+:10C620005BCC537FA75550F4243838741D5B5315E9
+:10C63000BD20FFB1A302FC0D837F08B67AD5F65D5D
+:10C6400036FFA350A67F5E0BB5DFFBADAA9E0D742F
+:10C6500078298FED37B1F2D0FE2D1D329669FB623D
+:10C66000566E4987FD296FBA81D22BBEA9AEE3541D
+:10C670001694D5F6751D72265D4BC59E12873F1721
+:10C68000F4DE4859A4E5384D9967656261CFBDC7AE
+:10C69000FE4B807DD3D6D4E1931940CF1F737DA08C
+:10C6A0005FEB8E3F7B14CAF53544823C9CFBC8414E
+:10C6B0005C87678D6543CE1490E353223AE4F0A77C
+:10C6C000AE0BF54727BB08E68D852017CC033FADA1
+:10C6D000A8D3807EDA76EA5B1703BDDB53619DE762
+:10C6E000A4323F637290C2D1C8C1649E86EFD3C0AA
+:10C6F0005C998607B57115F118005F2439FEE7DCF7
+:10C70000E210C5A777966C9B42C7DBBC81F7344922
+:10C71000607F824DE08F91231CDA89DC53E93BBEB8
+:10C7200041CB57FB92BB21AE30ED607CB039B72FC7
+:10C73000751A7DB65A997EDD9CA89413F5E516C549
+:10C740006F7425CA8949F47DFD9127B3658AC7D0E6
+:10C75000A199182FD6ABF8C87B1783BD1C3A3A3B7A
+:10C76000610E9D6FDDCF59FEB2AEBF7831CCBF6E8A
+:10C770008F8140BC56DF4FF9492B1F540EBD93E803
+:10C780003CBC9D5378CA1F8B52739758E9FA3E9B65
+:10C79000E715815E1BBAA6ECB6D020E859419C0C87
+:10C7A000F2B2A1CBB31BF869F38C4BC88F96CF794B
+:10C7B0007E569944E3AF7B2B17835A4B3530B9A48F
+:10C7C0000C877ACE98B80DE9FF9F6564D89C88E401
+:10C7D000C4FDCC1CF83F8ADF24D15B0EEDC5A53427
+:10C7E000F4013E157CC7C00F91CB2D980F2D1797E4
+:10C7F000627DF61A62E8A0F81C9492929A68576BD0
+:10C80000BED7007E4A9ECF86794E635CC50E909B54
+:10C8100043675939BC4EBFC275B21506FB2C14CE06
+:10C8200044072F42CC916AF45A60DDA82C0F1C2AD1
+:10C8300001792168BFE5CF16615EA72B9ED43C4FDE
+:10C84000E9D463D8D8F113DAAE27C949C0AF6CE593
+:10C85000B8F52BF07DF994AD146E8FB27EC6448F7F
+:10C8600008EBD593A82FEFE7363E0C72B4E5732F93
+:10C870002C86F9A59ABD9DC914BFFACFBDD0E19A07
+:10C880008D74CEB350BAD4A7BCD061A174EF69F255
+:10C89000BA454D79D29FA9B6C679BC8072CA277EA7
+:10C8A000F61190635AFF530BE5DF6793547F80D5F1
+:10C8B000E7E7A9651ABF521D6F6C1A29CB16AAFFAC
+:10C8C000F335ED2BA8DC7EEDCB46A2C20FD1B26DC5
+:10C8D000769FC566C479101BF8335379F4676C8969
+:10C8E0006C5D6D93F3D04FEAB1327A0D6719B07E6B
+:10C8F000A1F13911F200E6C9BCC18CF173C0672AFD
+:10C90000817D579EB0BCEE01EF6409D2A36C1F90ED
+:10C91000EB5C8E71A0B550B3EF47205ED5EF13F2FC
+:10C9200011E502F360BA81DA61E7F9E55C36855713
+:10C930009BA2C4854E920E79D7400AD3338FF9E477
+:10C940003B4D12F0D8203B9F4A7CD3E099B62E3F56
+:10C950006DAC7385A3F7FF43E897ED711814BA49DE
+:10C96000BB43D4476D763C2F821EA1667EC701F083
+:10C97000279D3CF24D01C83F2D6F4B64F9F6DCDE7C
+:10C98000C54FCF02FFF0748101E49F173D229CA7A1
+:10C990002B8B2B4900BF8D1FE1D357507E8D4767EE
+:10C9A000DF0DF19E00F24BDF1EB0B273A0C3E9A40D
+:10C9B0000FF2BFBCCB4BB4FB81AAFCEE6CB4E073AE
+:10C9C0006FC98A6FC03EC1D7DB09EE07082E1F96DC
+:10C9D000A516C2815C1C2FBD17C7FD2AEF4B580757
+:10C9E000FAF62CF3EB815D309F117A8A837CC67B4B
+:10C9F000165F02CC7B5FA2DE9EDE96CAE2613985BD
+:10CA0000E9CF3625DF295CBB05F337AD26551F5925
+:10CA100096807F2AF07E3C2F6BF66FF382BEB210B9
+:10CA2000591635F9704BA63EAF255CBB15E1C829F8
+:10CA30006C9CC873050E4E854FD7610C7F597D469F
+:10CA40009E4368203ED44764809D6FD8B66B7E5A63
+:10CA50009206CE36CE9B268EC11F5BAE194950730F
+:10CA60001E650B3F2CC07CB65C13F03D710DC637C4
+:10CA7000C1FE0B65B80E58C717BF8B76C9463A433F
+:10CA80007060CA0CF908CDF94FE2E28747F83F2FF2
+:10CA90002C1FB87FCE45910F495F8EDC370F808DFC
+:10CAA000A57EC50EFB6F0498E7BBF3C930F89384ED
+:10CAB0000C2E04F9AD9B6FC37CF416D269B1401EF5
+:10CAC00085EF14B579E1BAFE8BF1708E8E2EA90434
+:10CAD000FECD961F96E9F251EA3930B55C7F6403CA
+:10CAE000E609B7F45C15A694201A03261A8FD559C7
+:10CAF0003A4F99F3C2EDAD26BF9C01FCFFC347BD81
+:10CB000019F4D5D7004F383FD5306126C47F7F1048
+:10CB10006BD2814E765EB11F6B2C683F5AAC345E8F
+:10CB2000033EBD3009ED29ADE6C13EABE32F56E231
+:10CB3000E221F02F6640D73EF4D35B6DBE2B609FA1
+:10CB400080B179EAEFB426A97CB3AD03E4A74B0822
+:10CB5000EB45F09FBA6CAC6CEFDAD6D1C2EC30F397
+:10CB60006F9CDC6EF06F5A157F6968FF75F48FBAA1
+:10CB7000844EE6FF7DDF2C019E5D369F07E2417902
+:10CB8000C76409EC49459A03E7617AC1DC0DFA30C4
+:10CB9000D9E9BF047E0B7132FFE8DD94F3D9200F91
+:10CBA00051E00C733703C7A587639DCBC67F9733CE
+:10CBB000FA769484DBD1FE21DCFFBFCF82791EB5EB
+:10CBC000FD01935EAED5675E2AA327E813906BF54F
+:10CBD000BDE0DF84F26B2601945FB34BBF2FA4CA84
+:10CBE000B3706DB22E4FF9B514B63FA5EA01E15A04
+:10CBF00011D6CB0A9FEE84FDF231C7498A31CE743B
+:10CC0000D413B1C72955F40851F2BB3C9E2753E514
+:10CC100024B6BED0E76B23F59FFA54F5DF17143E18
+:10CC20003E6DF5CF4BA5E33C12EC5B68C3DEFE5BCB
+:10CC3000617DFEA4F06561EF93C780FD2E8BDE4F12
+:10CC4000A5CC807353DE6FA4A4BC7FB9D990CAE68B
+:10CC5000335A8FB1FCC3B68725B4CF5FE53D364F5D
+:10CC6000143D5673CDAED35F19296C9C1A5E463DB8
+:10CC700056732D1EEB3F387C2B094E1F0BBE03EB6A
+:10CC800047E0F731F8C74B7FDA350BE01F3619CC98
+:10CC90009A786EDBE105699097DC66A57AD9A19355
+:10CCA0005B2FC82D9F4B46E22090F37D23F5F37751
+:10CCB000837FF3AC56CE6781FF15EECFD375DEA729
+:10CCC000C83D9197446F6F8F683FE25F5561FB48A5
+:10CCD0007C543D0265F0B7F83F9B55FC500F3D6911
+:10CCE0008880A7FA637235C2DB3C83F919969407F2
+:10CCF0007F26E703FF05CB200E1A7E9848DD6434BB
+:10CD0000DD2D0A1FD65C9BA05BD730BD27EADEFF76
+:10CD100047A38B0435F2F651FFB6856897619D00F5
+:10CD20000E917762BF031924A891BBFFC3E383E28E
+:10CD30003127061EF3FECE78E4EAE4328C47BEEEDD
+:10CD4000FD07C5C368B9E6BEAC299B4492A12D1767
+:10CD5000872C1997357ECBF453A2AE3C63C0A56BEC
+:10CD60003FF39CA4AB9F3D58A8AB9F73C5A32BDF9B
+:10CD70003E3C4BD7FE8E6B5E5DB98C2CD2B59F6F5F
+:10CD800059AE2B2F10D7EADA4F54F2E477BA36E8CF
+:10CD9000DA2D921ED6B5131A92BF03FECB1DD7EF24
+:10CDA000B0407CB1D361A8847D879DBCDF921445DF
+:10CDB0003FDEA6C01DB177AE54ECBF400CB4803E40
+:10CDC0005C4043E166EAAFA555FB5AC0EE578A2C9A
+:10CDD0008FA8E6CFC9F59515F0FEEE4544EC480C5A
+:10CDE00097EFFC14215036677AF1FC9AB5C880E7BA
+:10CDF000037617AD1873FF619FE2BFEF89B0F7EAC2
+:10CE000033C1C8CE4946BE2F48637EC29377EC2318
+:10CE1000B04F607104F17B9EA39377BAA0FCF41D20
+:10CE2000DF76419CD13EF9132EE09FB6ACAFE9CE40
+:10CE3000DFD9F2097EDF110977BF0237FFDA631607
+:10CE4000B09FBB33193D23DBA9E7D0775B58DEFCED
+:10CE50006F35CFF234263F1FF63C2F2870775B8268
+:10CE600098FFEF28FCDBE05F3D82FFE384E1FB38C5
+:10CE70009E376ECF1224AD9D559FF07D28CCA72DF7
+:10CE800077A70BEC6E7BEE2774FEBF399FEDAB45A9
+:10CE9000F6E35C6CDD768B7FDBF93CF657CF67679A
+:10CEA000D4FD754B8C7915A8F3720591CFFE56F31E
+:10CEB000FAEC883CFD7DE6F5A2325E7C1AF34F77F2
+:10CEC0004B4C8E128CBE5FE6E5C696BF8459FAF3D2
+:10CED00048711E7D1C9097EF1BF39CD139853EB1A4
+:10CEE000E4758D494E013C5E6B64E769CF021DE934
+:10CEF000F39C7F42397C97F01A9CCBE2A0FF8EB85E
+:10CF0000B1D661ADDFA8C3733CFD30258D9DA75C14
+:10CF1000BD46DF6F95CFAE3F17A59C27A0747A0260
+:10CF2000F2CB2ADD46ADF38744A758FC76B374EA0A
+:10CF3000287C7F741A8FBFE3D398FD1A8F4E2A1F67
+:10CF4000C582F3FF2B1F95037D6E828F54FEF95B24
+:10CF5000D3E71F8D7FAAFF8F3E63D2E7B19BA48FDB
+:10CF6000AA877A055213ED1C48934B40399DC4059E
+:10CF7000CE2C8238FB2E239E773873A0A78EE469CF
+:10CF8000DB317B7AA6F2AB7578EEAEC68EE7BDDEFE
+:10CF90003078FEA504F2528F1831EF1609FF8C424B
+:10CFA000BF4DAE44E5BC8E9402F47EA366E598F3D3
+:10CFB00023959A79E1BE9A2D5C3652B84442FACA5A
+:10CFC00094BE90173853393D2E9A5D53D72FD6789B
+:10CFD00037BB7E6FD434BFAFF51B6F7E2B5D7937C7
+:10CFE000A51FE1C43ACB4BB17301BD8F33FFBDD751
+:10CFF00040D793C2BF0FF2DCB3210E2098FF5BBD78
+:10D0000026ED20E0FB2F2E76FEA25F90EAF01E9028
+:10D01000954B77C3B988B3AB1239486DA8787C4576
+:10D0200059D7D2EAE8FEE7734A7DB83F472645590B
+:10D03000E72F2AFECFAA6A0EFD08C27BB3B4F77CA5
+:10D04000FC73447D64FFEFBBE2B1FE6C8CF3975F31
+:10D0500057FAAFAE1ABB3FA94D510E618853B5DFE9
+:10D060009F8FF095220F8B5DFE3E176DFF1AE7FF35
+:10D07000D2C7818F263B90EF094F7261FF7F040E6C
+:10D08000EFC5731B97EB18DD23E16AE0BD3416BCD6
+:10D0900058F455E7A58E57427C18DF914A223E315D
+:10D0A0001BC737C279B6BBE793008ECF4B884FF2D0
+:10D0B0009B34AECB0DF3C7798358871FCE2870FA07
+:10D0C000FF7BFE1280D37FC620EEC88D8D772CBDEE
+:10D0D000F0A6C23F4EA37F079C2F20EBB9A8F27D9C
+:10D0E000CE65C576BB5CCC3F24BC3F0BC699B8DF90
+:10D0F0006F9228DC7B94F36784F8B3966BC6DFA548
+:10D10000CC3BB29FD3C8F6C9C9EB4C0FF5763F9222
+:10D11000154D8E5E51FCE65DAE42DD39DF2ADFA3A0
+:10D1200026D003554B979B2407D44B8CEF143C7AA5
+:10D13000057F56B1234CA798FA47A14FFF397F339B
+:10D140009CFB59DFC0E139E3A2ED8CFFD66F3F6A4B
+:10D15000A8A3CF838A1C2E57E450ED6F4F6772D37C
+:10D16000DB6DCB06FC7BB5E730281EF73F43307FF5
+:10D170006748FFE21E99276490234ABEEFC65DB060
+:10D18000EF30A8EC8FE5D0FA26C0B782E1BB7EFB7A
+:10D19000728CF72756B278BF5F20781EE8CDDBE3AC
+:10D1A000823B0086C57BF4315ABEF4E704D2E10924
+:10D1B000F3C75342682AF0474AB3EFE3BE28EBEDCA
+:10D1C00056F0FD8383EDE7C5A28BAACFD5762B78E9
+:10D1D000C914ADFDCA4ABD5E53F14F3687DE2551F5
+:10D1E000F2EA23FC181CDBEEBDAAE8E95722E2A60E
+:10D1F000AA73D1E397D274C6C7BDC1F2CD78BE5928
+:10D20000364B789658C1C729AF467ADE5842442833
+:10D21000DF6D96BE0CF8DD53658CD0C34184B37EC0
+:10D22000A95D37AFA7BA7F3A15BE43CACB67FAF7F5
+:10D23000BD42079E0B7F880404D85FAA26F23C9467
+:10D240004B229980BFCF2AF453F13B4BBC71334042
+:10D250005F3444B79FBE742627677DF357A1DD6D09
+:10D2600031E2B9848B55C9CB200F2EFB4C1E38E61A
+:10D2700074B16565DC839A7555ED9EEADF9CF3CF4A
+:10D280001FD37EADF2E9D7AB57E8C47D40B99C040B
+:10D290000E513E9BF4A5CB7B67D2F299A001EF190A
+:10D2A000C23F2C67A8E7E0099F4AD75DA91A320C54
+:10D2B000627BF90B6C5EEBAA830B606BECBE673A8A
+:10D2C000F7CDA4E587D2993FB0C33EEF7690D75F04
+:10D2D000358C632F23F869E27E9BAE5C7A8E08D092
+:10D2E000DFBF2DBA7DF88F0CBB72AEC8930DEBB0CB
+:10D2F0006E7BF476F64C07DB27FC8BB1265AFCBD1F
+:10D300003B83C9C9FA1A2EAA3EDF9D11C7EA6BA357
+:10D31000C3BFDBADE22166C3BAAC8F81EF1237B376
+:10D32000676FB5AE5E07FAE08A41AFA7E7BA195F4B
+:10D33000B8DD6CFF7BA8FBA5D654E0879D9C08E771
+:10D34000C92E257A2603FF6D68B988F17EA2D2DE48
+:10D3500098E6DB974EDBDF7BEEF913D0BEBF9A7801
+:10D360003829B61DE84A57ED80FA1DB46A0F3BAD67
+:10D37000608FE07F619F15B6FA139260DDE547F09C
+:10D380007C4CB74D64DF3D796668FDEB1E45CF0CE4
+:10D39000F5BCBFF5BEAF46EF1745FA7F4382B4B781
+:10D3A000848E3B44F9AD89CE875C7FEA56ADBD5192
+:10D3B000E521D6B837EB070EF5BC3F3F70BC799E30
+:10D3C0004ACFBD293FF0BDCAA7F6954830CFCE5B06
+:10D3D000A3E95B552FBFA1E8C5487E19D1378A3E26
+:10D3E000B9121C1BAF8F3EA3C7675D408F8F2A1FEA
+:10D3F0005782CD36B8478B8E3E15D659F54B49C569
+:10D400008C9BBA1F24169E57143C7FD560E451EFC5
+:10D41000F57098A7FE55C353F1D1FCFCC8F90F195C
+:10D42000283F007F7C9947FD5350B3E158AA14E68A
+:10D43000C7F714F87F2D1FAAFA55B52791FDFF51A4
+:10D44000F94EB567E3F19D33461E7277BA05FB6F5F
+:10D45000E04501F69176A74BAC4CC4852EF05F6792
+:10D46000B1F3EFD4EE65C33D1243DD36FCFE4BEE67
+:10D4700030070BE83A5EE99E3359BB8ED3DC8A5EF7
+:10D48000AD4DDC095BD7570C9E4569B07E2BD87D2E
+:10D490001E67CF252D4CA3FD9F1A30C08D5864DD2B
+:10D4A000B60D4698DF6DEE446697B79F46BFEFFD19
+:10D4B000F2F5FA80DE9E3F9DAE9E3F657EF8DDD49C
+:10D4C0002F80F384B1E890E3B660FBFB6A0EA33EC5
+:10D4D0007D603B87FA54724BF8FE013E887A99B41E
+:10D4E00030FF9958283DA85EBA0893007A7C8E6375
+:10D4F000E7BC799FA0BD6FE3C13DAB17C0F9CB4836
+:10D50000F9F88EA2C73FEF3628FADCBFC88DF1A12B
+:10D510008F0378973EC9F05DBFFD513CA7FC7ABAF6
+:10D52000E25F2BF2F9BAB24EEAFC9295F99DB70D83
+:10D530006F037B41E5C680E74C5E33225E435FFBB1
+:10D540006600DA89531C18EFA31F4BCBBDCBE282D8
+:10D550004D9ABC9DEAD7E479983C54F15E9D5FF802
+:10D56000903B57E7A747FA1BFF670FD8B3C3FDF7F8
+:10D57000B5075DEE0FC71E04D219BF47DA85113912
+:10D58000DEC9E4F8E2B9DF2D8072A41C7F5D91FF53
+:10D59000BF567EAF74DF8B7C2D2F2662812E3ECA54
+:10D5A0000A421C3CC2FFE1388983736E4F75FF6CE1
+:10D5B0002AE4BB2EEE5DBD2EDAF87B33989FB531A1
+:10D5C0005E32E07D90AF313E8BD41391FD46E42274
+:10D5D000469EB16AC56C8C0FCFAE98930DDFBF45E8
+:10D5E000C607A3DA73DE9455101F3729F1F13E7395
+:10D5F0004D77147C93143F352F7FF804D0FBBD5A30
+:10D600000EBF1F863FAD9F7EEF39CF8F06A5D1F8A5
+:10D610008E94D5F8643B1B2F729CCBEE88F844A601
+:10D62000F109A5F36095311ECEB3AAF1C9A0FCE1C2
+:10D63000C6276F92E17F9909EBDC131D2F3E43E172
+:10D640006BC1BF6F36C56368B1D12383BC18683F17
+:10D650004D5C12D9EF9AC2876F6E7F9FFAE89C3EAD
+:10D66000AF1C4BDE46F0FA2BE5AD5718CE02B97F62
+:10D67000F3E0F50B8FC17C0EDAF0BEB1483807330A
+:10D680008C4A7C60433950ED6FBFD059FF12EDF7E3
+:10D69000E65D6ECF0EA2910B42E582BE3FFF172AD8
+:10D6A000171ED46F28C7BDDDF69A6871CA0F143EE5
+:10D6B0008BCCDB88DDDF08405CEC251E9336EFF475
+:10D6C000BAB2EEAF2A7A292F83D9CF7BAA960B90D4
+:10D6D0002F7A70245F4430B810A7641E84F8F215C6
+:10D6E000E57B0179631CCA5D241EB729741D2F7F59
+:10D6F000B0A65A1FD7DF53A5D71F6F07F346EC48D4
+:10D70000C118FB522AFFC61AEF66ED476FF0FDED18
+:10D710000B8C37BFBA8CDC9BDA17584502B7639E77
+:10D7200083AE0F3CAB4860EA4B149FB79F59897991
+:10D73000F45709A9443FFEFAC7A66AFD927B95F506
+:10D740007EAFEA637701BBBC2E04A646B33F917956
+:10D750009A5783D1CF67F814BDFABAFA5DC53DC6B2
+:10D76000A8EBBB5959DFD7ABC7969BC8BC4DD55268
+:10D77000FDBC3F95212A709A6D7E1657B371BFC0CC
+:10D78000C605BBA5F54B3FF521C9EB20E4EF619C35
+:10D79000ED84403EA55790A768CF5FC565323AE457
+:10D7A000158EBD1FF58A4257B55DA49FF513B7A42A
+:10D7B0003B3754B5548FD76746FC4111F320436083
+:10D7C0002F9D617B79B7D9F330F001714858FFBCC8
+:10D7D000B2DEF7D6FCD604F3A7FAB315F2A1F2191C
+:10D7E0008308FAB3F45CD0A4A5CB6B3719DFBFA6CE
+:10D7F000F80BE3E9D1BCC261D46FEF051DF89DC4FD
+:10D800009B9FF993291ADCAA6B19BAF3C4EB7DD15B
+:10D81000F32AB60CB6DF158BCEB60C49E7A7AEBF20
+:10D82000968DE78363F9FF9FCD6071D07D35075BEF
+:10D83000B5FEFF530A9C07547DC633BF3F56FEF525
+:10D84000A71937977F55EDB3DA2E72FDD567A4BDC2
+:10D850001C54E439B2DDBF65DC1CDF8DF83131F8D2
+:10D860002ED6B86AFCA1E67DF38A68FF28FB32A3B6
+:10D87000C651DA458EF3AF197AFE1E1547C4C8DBD0
+:10D880005933991CFB63E4EDAC9971587F8630BB2A
+:10D890002807ED68C7AEF43CB00FDCBD87167DFCF1
+:10D8A0002498B78F2AF99AEA9AD327204E55E38A0B
+:10D8B000B03FEE6F867DB2A11D1CFA1B91E344FAC6
+:10D8C000E51F853D269047257F5068F4629E9A7C2F
+:10D8D0009A9DF37736AC46FF52CD4FF70ABE1D71C5
+:10D8E000F4FDC4EDBFDD06F6558DE32F993C0FB373
+:10D8F0003C33F377CF773BF07BD7DA1179F760BE13
+:10D900007144FE95FCE378EB31A26F62ACC778FA04
+:10D9100026565E447D8EECB308E28C97E17C2A1794
+:10D92000EF817B99979B09E67D962FE130CE5C6E67
+:10D93000F6E27ED6E9330603947317E7EE067F63BB
+:10D94000C552A3D74A51F83700359BAAF257AA0B04
+:10D9500000CE5374C210C7F6BF21BE07CF5717C4FD
+:10D9600049E0FF9F9E27353969F9F4624EDC41FB9F
+:10D97000BDBCF401E3545A7E8586CF70EF8CBD8127
+:10D9800028DF7FDCB26C7E3E21DF00B89AEF3F5E7D
+:10D99000216AFD3DFB2A281F4D49E937382849BF38
+:10D9A00075E09E7D160ABFB5C9E782EFF2EECFBCE7
+:10D9B000751F7C0F999AEA1DB883FA519D999E654F
+:10D9C000F09D5EFF175478C5FBE03BBC1F18FCB907
+:10D9D0001CAD7F2173D1321EF62326A8F0ABB17E99
+:10D9E000D5C2750FF6D3FA0B07EA97C119F6D26ABA
+:10D9F000A5BFFCB165F3794AEFB96AFB8678283B8D
+:10DA0000ED24BCCF348B1053F83B3F3CF7DE3F7224
+:10DA10008E7CFBB20ADAF7D5B2C07CF89ED3F3A5B0
+:10DA20001DFB8AAC84CCAC2C13BD743EA5595F5849
+:10DA300066877521941F69FD47B20E2C83F9388DD6
+:10DA40000605FE9710BFD26A790AD47372705F65BB
+:10DA5000227C97307812D8724B43A72555F77D4228
+:10DA6000C00BAE8970A42C9481E828FBDA99A1A997
+:10DA7000ECBB3BA55CC8F2142365172BF7EF88FEBF
+:10DA80007DC57F6531FDD56F8B5EDF91A9DFDF4EF0
+:10DA90003847BCCF4591FF8F29797F559E4E403E38
+:10DAA000C48957CC059A601FD6C2F08CB58FDBAE07
+:10DAB000E897FCA604BC976869C08EF7E84CF03084
+:10DAC0007D43A5885F09FADF68403C538C1CDE6B00
+:10DAD000926A23FEC3F49992CCEE39594AE517EEC7
+:10DAE0001F5930C1D783E77CD3D28B9BE19C5DD398
+:10DAF0002F79F0C3D4FEA3F1141F053C538C2B8A5D
+:10DB00001F2DD2D0AF88E14DD75DE9E7FDE61D209E
+:10DB1000170353F2C0AFBE3D536FEF4A07CA4DB073
+:10DB20003FF9AB2C250F26B1FE29F3995E197E54DF
+:10DB3000B9B7C2E229D6E5F5153ACF6F5BFA34B42E
+:10DB4000AB1D3011388FB8ED7099EE7EF5C8672D9A
+:10DB50009C7BD7D8ED5A3E84E7CD6BE1DCFB74802B
+:10DB6000F77301CE39021C880FE0FB0EF09B529A2E
+:10DB7000A3AFB79A57AEBD9648E4E9DAF78C5E6179
+:10DB8000F84EAC1F6F5E6178FAEFF946C353BEEBF7
+:10DB900053E9CE2B7417A2E3F933952F29BDB5BFF6
+:10DBA000AB52554D94F313EC1EDFF3CB8ABAB5F7A5
+:10DBB0001610B2839DEBE0E93A823F3960C3FB80E7
+:10DBC0004B79AA1F9D002F4994B9D17CA1AE6B7FE0
+:10DBD0005200EF231ABE8B13BBA3F8D967143E2E55
+:10DBE0005DCAF836ADDA6FDCA0E17795FFC3F007C8
+:10DBF0003EA3CAC73A94DBBD0C3FF037800F3DA16E
+:10DC0000A9DA73202AFE659904E74FD791D1FF2E38
+:10DC100047B09B0BD36D34FD33C659CF6CAC2F1D71
+:10DC2000382600BFD5C690D3B359F1386EDAB95053
+:10DC30003C9C0F58A0F07F7FDF74EB1C908BA506F7
+:10DC4000C2496CDEE06796CE55F5E73BBF28A7F6E4
+:10DC5000206DA44CF5AB04EB30A26F43164BB8FD1E
+:10DC6000C9AC7796B5803E36B3EFBCA9FF68219A60
+:10DC7000EF11B92C96BF9DE58FBE6FFD4616F34799
+:10DC8000547A7FBE613E798BCEEFAE4C66BF670D96
+:10DC9000CA785F922AD7917A29278BAD634616E31B
+:10DCA000B3BFBD5EE2C6D14BCB15BDC4EA89D35725
+:10DCB0000BF5A906E5FB0491ADFBC69F4C2F803CFC
+:10DCC000DC56975182EF1D56729EAC6FD171AA2C13
+:10DCD000526B9C14E68F2A62911C406F3A027CFFC3
+:10DCE000BA62A915CBF0077EC7EF3A39C67F444A1E
+:10DCF000A81AC3AF55F1D9EA1270BC8DBB0A12FC49
+:10DD00005A3C79DF7398DFB32B785A22EC15AF2F8A
+:10DD1000A7A686EA0C464DBD83D9AF1697774E1657
+:10DD20002D9F56F242A43659E717AD52E42ED22F5A
+:10DD3000FAAD8B287A6205C68F69347E847B02D265
+:10DD4000FA7C781E0C2E322AC0EF76D97DC6970E4B
+:10DD500093B91027A9707C59453AFD5EBD1A364D1E
+:10DD6000A8705AE67B2F6BF4D929E53E7ACA0F33A7
+:10DD7000405E9767117D3FA32F13BE2F2769660F63
+:10DD8000E89B1382EF00AEAF4812617D17181F3D6C
+:10DD9000807C612489CD784EEA20F6AFAC1E2E41FE
+:10DDA0003FF5BA310476E797D9E998CF49B133BE48
+:10DDB0003D610D603F9E4849A84714BDF7CBECC9B3
+:10DDC000780F86AA3FC3DFB5A87058FD096E792683
+:10DDD000DC0B7B2265527133A7F777C0FF09FB4B41
+:10DDE000DFDF77673EF8377D218A33D52A2F2E7BF8
+:10DDF0008CB6DF9C25317ECDF5F5C3B82712890896
+:10DE0000F8CF1AF43F07E5452E3BDEDBA6AE47AA66
+:10DE100081FD1E4CAAF27B2B2027F0B4653339EB31
+:10DE2000529E83D96C3D53E3A3FF7ECCB0D26EBF2C
+:10DE30008DD1B9A34C7F7F92FADCA9C8719DA5B39F
+:10DE4000123EA9D77CEF89DF87F384FA551C7C4FFB
+:10DE500042F03DB56748AFF96DD5F8FB61EF0DAC09
+:10DE6000C27B5C477ED703EEABA2EB1E222B9F004A
+:10DE7000BA0BAF1AF16EBD56133B772724FA45F85B
+:10DE80001E29D91E3DDEFD96824FB291DDCFAD7EBB
+:10DE9000C76052BEEBFF8AE28FC5BBAAD83D45944E
+:10DEA0008612A55F0219C6EF74D5758C3C976B522C
+:10DEB000BEE77FFFFE43710CFFA144E73FA8E346A6
+:10DEC000FA1117E0FE6D4DBE7B9DEBEC02A2697F5F
+:10DED0003F196C0578F76FCBD0E52562F91FC715A0
+:10DEE0007D0BFE821C152F41F7FE028D0365EDF8B8
+:10DEF00057D8F8E171ED44D68CDB96E57D390BFD02
+:10DF0000D4B922DE234C7D76380F4BED0EB3D77398
+:10DF1000D9FD84D42E5582FE56E322907B3101E454
+:10DF2000BAECE759291A3BA9F48BD447772AFAE8C7
+:10DF30004EC5DE249C53FD469BC47161BB33DA6E33
+:10DF4000718A1F1DA91F23ED82DEAFA67C2B6BFDFE
+:10DF50008051F292F541FDCB0931F863E2DFC5BF94
+:10DF60002C9DEBC7F892547204F6416656E8ED3DDD
+:10DF70009FEDC079F1D9769DBD5F51AD6F6751DAE4
+:10DF8000599476E3D1536B8F3823E83D06AF9E63F7
+:10DF9000FC90FBCE19BC4FA9229BF943B7E4781340
+:10DFA000B269FB837F9EDF0BBF3B31DCC4936E27DE
+:10DFB000F4F3F60E3A615E1611E2D4B2B515850798
+:10DFC00069BDE9E7260FC4CBE448F4F8DED1C07997
+:10DFD000375196CA54F460AD93CDABD61912F229DD
+:10DFE0001EEE5A864F66DF518ED7E8BDCC1AD66E2C
+:10DFF00062B649677FA628E5C26C252E21C126F8A6
+:10E00000FD93CC1A2F0FF6CEDDC711E59E4DBC1F38
+:10E01000D5ED61F01D9E20F7405178DEED86E54597
+:10E02000602FDA53ED1EB0175B72FC9E6C90D7F335
+:10E03000A110906DE6F9011EFCBE5D39DE62A0877D
+:10E040003A3FC928BA617FDC7E9EE1D719C1FF84BF
+:10E05000EC56D6A59BE1E7F015033EA9F112DE4789
+:10E0600044FFF2C0AEA62629762395F8E1DE2062B1
+:10E07000A1EDC00FB2D176DAEF3789AF04F609828D
+:10E080002953A7819D5B60F31CB3807D9D963B0D5A
+:10E09000EE177AE940F47CFA32C5AE50FC1769F10C
+:10E0A0008F251F23F7AB2BED4C31E26895EFED95F3
+:10E0B000D1FD556A09985FBFD6792FCCA7B6452008
+:10E0C000708F844AF75D39BE6AC0C7DD77900379E7
+:10E0D00075F795215FB9659E805FD162CB0EC2BD99
+:10E0E000B12D491F4903FAC7C2BBB6C1E8DDA495EB
+:10E0F000E71601D7E360C4F93535CEF87836F3B3C7
+:10E100004339BE5A58E7FA234FE239C1877B2E0ABA
+:10E1100063DDEF73B374E36A58FC52BB86DD9B5139
+:10E12000B696473EDCDC22E0BDACB5CF1D0EE17EED
+:10E13000F17682FBA0B57D874FC2BDAC19B5DE1963
+:10E14000DADF21C8A865F7C7A5521E192842BD29E4
+:10E1500080DD76F72DAF45BE168948908FFCE877B5
+:10E16000655A983FAAD2F7A410CA7E99B63B692097
+:10E170009E665A7FD52417C24F345DCDB579E01E17
+:10E18000867F3EFCBAF469A033E4C55CB01EFE276E
+:10E19000811E1D4DEC3C79C702EAF7D0760BEC648A
+:10E1A0002B9417343B08C8C7CDD26166045FCCDC22
+:10E1B000CEE4E4B8A25FE81FDEABF4CD6C16D7A4C2
+:10E1C0001AFCD5E8BFD279B4CD46BC701EB66C6FD0
+:10E1D00010F02262128EEBAE0D71DAEF50D4679818
+:10E1E000AFBC5FCB4E793F78F6E13EE36645CF9416
+:10E1F000ADEDE1DED2F0C1F7B2D97EA9FBB9831C47
+:10E20000C487B4BE698113DB637ED0FD1C8B9B3653
+:10E21000D3FA07757A6503CEA7DDC6FC47AA577EF9
+:10E2200008FC7EC2F0E871D82F39318DE07DB377DC
+:10E230009D0F9D44F5ACE07B4260EBC9533A34D16D
+:10E24000F2A96CE6DF9D14FC9B60DD4FBAD977DE46
+:10E25000ED861D78EFA92AF791727A4AE173F79A51
+:10E260001ECE50847940F42755FCD476B7E494FF51
+:10E270003C1BE9308074A85BC3B37C8382CF02C1AE
+:10E28000970F71DA1B0ABC63ABBF6D7C86E25757F0
+:10E29000C4213FEF7FE134F2655D27C77E27A8F3F5
+:10E2A000B4B04A135F757DEF34DA9525FD6CFFA598
+:10E2B000AEFF30FF8003ECCD31E4CF3ACA7FD612F7
+:10E2C000583709E97CD514CA067B19C99FF64AA6B6
+:10E2D0001721E75AC0EE83C3FDDFE05A0BFAFDAA0F
+:10E2E000FEB5652BBF5BE9F0E7827E7D5729ABF079
+:10E2F000C3F1AAD503FC9DFBCEB46370BF5B9D87C1
+:10E30000F3C079E4E1117BC2F4B544D915F4B50A40
+:10E310003F927EAE1C66CFA2D891FF8A6647543BDF
+:10E320009BFBE572FCDD3775FD7885EE23F63D87B6
+:10E33000ED4B597278051FAF0BF2D81295E78E128C
+:10E34000B8DFCF57043FA1D69262F7407EE79F1314
+:10E350005F933668E87552A0F24ECB27F36C880FB6
+:10E36000950B6B8E66FD6A8BD8EF4AEDFFEE72A4BB
+:10E370006B2DAC1DA56BAD7FD326A4B38B888740D6
+:10E38000BFF899FEAA5D730FBB075CB57FCF7348DA
+:10E39000FF5AD981F75A2FE95B8EFC499C564F01F1
+:10E3A000877A0DD7599533DB085DD9FD4334AE6FBD
+:10E3B000827C891AD7C757FBE43869B49C262B7135
+:10E3C000FD0C25AE37CDB27CA871FDE6869F61FCC1
+:10E3D000F388EB27F854E584C68D3A799AA1ACB35B
+:10E3E0003B87D9D3B9394C2E3797F421FF6FBE1C28
+:10E3F00040F97154323DE238AFD77F6A1E8C903DB0
+:10E400008C0FED7D0B611F62C1573811F4402CBC9D
+:10E410003FCA057E01E755C861768EE28EEBBF8C60
+:10E42000D7DE47BA3487F1F7D55E230901BDF980FD
+:10E430003096FF1B0B5E56A862F6BFD3F5FB756FD7
+:10E44000029E0BBAFADCCA4F4259EE49C0732459F6
+:10E45000A12AE48BABCED91EE0036733A3D3D5BE8C
+:10E46000F9C83FEFA44906B82FACA9EFA979F0FB92
+:10E47000D01B15BCDEF9AEB101E8B0E3EBDF9907C4
+:10E48000F74B6E0E72C9F0BDD9D5DEAFFC05EC5E60
+:10E490004DCF163CF7D5FCCD7F42BFDB103CC8DE2C
+:10E4A000F72688D06EE8AB4FCE03FA36F73563FD1A
+:10E4B0003B5F3D88E5635FFF8EF19992301FBFF3AC
+:10E4C000DD833FFE6F28FBE2F1BB9C5AFFFEC7A134
+:10E4D0004CAAE2D97757FE9705EDEF75751D3E8A78
+:10E4E00072A8F2C5923E4EB93F4CC0731E2AFF5E21
+:10E4F0002A2F2A05B9831B768DF368B923AE265AD5
+:10E500001E71A732DF5AE04518770D1704396817D6
+:10E51000E45ED4E7625F36E8737B5148807B5756F0
+:10E52000571F9EC77E76B009EB575AD879B1A954C8
+:10E530005EE01E290AADE706F56B56B63FBC0EE05D
+:10E540001D3012D1981EC6B75E90303EAA5FC179C9
+:10E55000A884118E6C3B9102FB5F0D4439D7C5DA5C
+:10E56000B5D3F0D29284768858E9B3745BF43CE872
+:10E57000BE1C87229F4C5EDDFDCB33417F10A7D9A7
+:10E5800053901B8697752ED001D7F9BB6B0616C228
+:10E590003C16176E980EF37042BE0FEC8BEC40F8F1
+:10E5A00075909FA4F21454E42655F4E17D2316AF30
+:10E5B0002F057E834D32FB703F4F5AEF3335819EDE
+:10E5C000E187B357A1213CA4CB7B7599FCE93300CB
+:10E5D0005EBB629F7A18FEB43FC293E67B9DD09FDC
+:10E5E000C24778966A2F8FBFF16661EBF09F3FBA02
+:10E5F000F3903E5F1E1C05BFC401F6455E83EB260B
+:10E600000938DF77A029D25BBE559BC78ECCF78037
+:10E610003E83FDDE504ED90F7266849F6A1E28929B
+:10E62000CE7F817AD01F92179FA437F9A67E0F5014
+:10E63000D5DBF57B14BBFB838BA877EAFD3CB3BB32
+:10E64000FECB68777FDDE8256F51C7B2EBC58BC87D
+:10E65000DF0F1C6176B7FE48B100FCACDE8B5C5F5F
+:10E660007E15EDAF6C24C8D7F542DF4917C0EF2007
+:10E6700089D4B327F5F3062782FEFBCD8BD635D0A0
+:10E68000FF84C180FC76A2FB9683CD9C163F1607C3
+:10E6900070354194C77AC52F285BBBE94988C7EA22
+:10E6A0006A08C685F5FD8A7CD1780CE85B7FE43486
+:10E6B000F28FEAF7E67E7905F25B22E537FC9D846E
+:10E6C0008A01C48FFE790AE833B182DD8FBBB8B00E
+:10E6D000B814F8EDD8EA1FEF04BB5D5F414480DF5A
+:10E6E00095E57D11EF017E91C37B29BB4C9DE5F043
+:10E6F0009D64D7024904F9A8F7578DD8273C5FEDF0
+:10E70000AFEA47F971AEF380FFD0D1E447BFBA2337
+:10E71000DD8E7E41D78B4D683FEB259B077EBF6426
+:10E72000C9116E2BF6971D84E1CFA19FBF24380736
+:10E73000CF6DA9F458523198CDF405C3FB37A681AB
+:10E74000FB61DEBFF99E19EEFE1EE1BFC48AC00167
+:10E75000B8AF768938CD03F76B26F1037EF077A842
+:10E7600009F634C1FEB0C967F640DCBD97C37DA889
+:10E77000FF076B233BDE0080000000001F8B0800BA
+:10E7800000000000000BDD7D0B7854D5D5E83E730A
+:10E79000CE3C924C26274F1208F14C123040124EBC
+:10E7A00020BC114F88416CA90ECA2354C4E11D201E
+:10E7B000242362C55F6F33381023BFD71BAB156AA4
+:10E7C000A91DF0516A45A38D354AE01F10107BD575
+:10E7D000466B11FDD18E4A798964E451E957AA77D5
+:10E7E000ADB5CF49E64C263C5A7B3FBF1F3FD9EC25
+:10E7F000B3DF6BAFF75E7B4FEA64A6058B192B780E
+:10E8000040D0824EC6EC8AC05826A6163DB5313699
+:10E8100082C19F669ECAFE524F09635F3468ECB3A3
+:10E82000018CFE28598C2DA37F30B67C41C8A640B0
+:10E830007FB5CFF2FE32EC5AD9ED907E837FAE8663
+:10E840007C25BBD503E599A270EB544A2D941AE5BB
+:10E85000465AACCFC3FDF8BC87AA3218FB5E0D53F5
+:10E86000136088BE45F01DF2CCC78203DC90AFF187
+:10E87000E42A589EB15815219F99CE7E88E591D5FE
+:10E8800036B659E8D9AF8AEB1A81F53CE502D4CB0C
+:10E89000EC93AC067028B1C29280EDCA0475B382C5
+:10E8A000F91B9F64E590CFCC51B11FC6823A1C3C46
+:10E8B000E516A877342B595D87DF837F906E047847
+:10E8C0008C5764A3BC0CDB292EC6D69575B7AB2A32
+:10E8D000F0507F557D12D400CC734AB3BF94E573DA
+:10E8E00038789CDD7008AE4EAC0E46C16324C20180
+:10E8F000DA0707B1EA966284BFA716FBC9B2A8E996
+:10E90000EB5221EFF497DE948CE304085E57E03C71
+:10E9100020AD82F5F9B0DF02CF4A824766B21A0F06
+:10E920001EA12B383C76CD7C4EDC00F5EA8A85A012
+:10E930001DE6F7C8B6A965B8CEBA694E9541BECEF8
+:10E940002BCDC37199DFC19E823CF32E78A80AF2C9
+:10E9500075351E759D42EB5E80E5B91909EA3A28C6
+:10E960007FF41541C37C9DDF194C80FCF7DB383EFA
+:10E97000D4B5BD20CD873409F1CE89EDFCA5534B2C
+:10E98000BAE7C3D86A9A4FDDC41379BBA1BD5F64EF
+:10E99000AA3801F2B6F04015D65F37213C10E17578
+:10E9A000F295846A6CBFC762F1E3387B360FD914E5
+:10E9B000107AF673D2EA69C5F59F84F5FBA1FCF5E0
+:10E9C00057DE0FDE0DF935800A6236ECD16AA502FA
+:10E9D000CBD7553119F7C5D8AFBD367F11E2D5DE9B
+:10E9E000FC44C20F9CA707E07C1CFF99C358FD158F
+:10E9F0009E250ACED3126A94B0DD9674C6C640FE38
+:10EA0000D5FB077A9D3DE10CED695F1C1223FC7577
+:10EA10000493828128BC7238184B1E46A9DF09690D
+:10EA2000D22A0E9FD87EEE519C547FB923BC177614
+:10EA30008ED5AF6A7664011E2D4854E87B82D5A737
+:10EA4000F583F9D8DA2A42FDA03C2B0DFEC27DDB0E
+:10EA50009C14C47DCBCA62DE17E3F45BA7D39BB1E1
+:10EA60002FCD698CF032CBC5EBFF4CA79B07F47A16
+:10EA70009BF5348A2ECC78EFF4BA914F6425326F2F
+:10EA80004B9CF18CF6303F2A37E6C51CD04F06B6BA
+:10EA9000532C84DF317417CC2C1986745795A8EE4B
+:10EAA00072203D0D730F0BB0EE710031DD53937B7F
+:10EAB000E201AE03E907D78574D65BBDE69D9C3FB6
+:10EAC000C5E2E5B33A9D2C425C87793F27003DC6FD
+:10EAD000DD67DE4F93C56D7914E6FB9FFBC5E066ED
+:10EAE00077CF7A46FA6003D0A09DB1FC8DB3523C3B
+:10EAF00025BDD7DB89F5AE84711B1C54DFA92AAB79
+:10EB000025E87FA2C35D26321C4F9988E3F9613C5A
+:10EB1000DCE7E409EC4B11E053DAD65C74AF1BF18F
+:10EB2000BCA51AD7355192A532E40B1E0B0B1571FB
+:10EB3000FEFD0DFCDFA73A91851CDDF91C6F9A29BB
+:10EB4000DFAFA6AFA97E7F5FBEA9FC8A55834DE5E6
+:10EB50006EFF3053BEA069ACA9FE80E689A6FC9585
+:10EB60001BBE67AA3F2878A3293F64CB0F4DF54B06
+:10EB70005AE699CA53BE2ED8F533C4735C7F1C3E47
+:10EB800067A4C71537EDCF444934F537B4CDBC7E03
+:10EB900089852D48EF29138E0E8B47CF465ACAA47C
+:10EBA0003361A31DF20187627914E6E17A5F0CAE4E
+:10EBB0008BB3EF063E1BF994D1E67D30F8C4C5F067
+:10EBC0002BDF7B617C31F0AAB7F294AFC5B87499A2
+:10EBD000E8E67429310FE3EBAF562FB47E6BECFA05
+:10EBE000994278FFAFAE3FDF3BA82D0CFD9CAD16E0
+:10EBF00048BEBC8745637AF6F751CC3A67AC4C21E6
+:10EC00007D86796E8A5BBF7B1EF7D23C6EB1335F27
+:10EC10003C384C7273B93BCFCDE9FD62F4F9893EC3
+:10EC20008F3F1BF4B9C64DF4C8DE138303A0AB7944
+:10EC30004DC2CE3E8017695EA72AAA909742AC2C9F
+:10EC40004ACE3FA2D3F7A3D81ED20D0D32F5F3580A
+:10EC50004336A51B1B14FAFE784311A5C10695BEC9
+:10EC60006F6E184DE993A08F61FA74C3644AB7348C
+:10EC700078A8DE330DD5943EDBE0A5EFC6FEDCA21E
+:10EC8000EF0FF3A4933C8B5DCF9C9566FA30F6852D
+:10EC900089C5D47E0ED0997801BED6A3BD383BE598
+:10ECA0004278B4EAA0FBF9DD517830DD9D9C7178A3
+:10ECB00008FC63141BF58D78F1F65F3528CFEFB6AD
+:10ECC0005E9C2E0C7C61E73F1B10AFDE2D49503659
+:10ECD00016F893FB97CD7E67EFF0E9C6A3187CF595
+:10ECE00000BEC2D75294ED39581EEE1B3DCE9FF4A4
+:10ECF0007D36F2D3A6717C8DEDF7419D0EA7237E64
+:10ED000042F98C187AFD422FFFC2CDF5F4FDBDF01B
+:10ED10008B46B745979F7CDFA7033EA2FCBC3769B3
+:10ED2000CE55DE38E3FEDDAD98E873C634F33EEE33
+:10ED3000B772FEB6FF4F6270759CFDBF587B633D96
+:10ED4000B1EDFEA0AFE773C4C911FF73E86DFFAC6E
+:10ED500064D2E7F75BBDFD33A3F667FFACA4EA78A6
+:10ED6000FB7EC66DE57456243394EF2C8D69A8079D
+:10ED7000C192FC36D4E558A17C18E9048C21A48BFF
+:10ED8000DEF15262870D7A12119E09A48F9F9D9623
+:10ED90004CFBCFBCB2C6A2FA67924C7AE9733F0033
+:10EDA0005D01C793603CD043996AE9DEBF7CFC3BC0
+:10EDB000B19B5F8BBDD3DBC5F0C0E02333908F5C8C
+:10EDC000405EF76C77797CE4E37F131F31E8989D10
+:10EDD0009F3FC093DCB37C3AF291BE8C3DECDE4F9A
+:10EDE0007CE49F869341B7EF73BA8DE527BDB66B80
+:10EDF000CBB888FCD3F9B9E46B0A035EDC2926376B
+:10EE0000AF8326F749BE5F62DEEF97D85390DA579B
+:10EE10009DEE7B6838755B2451BDC164DFD925DF69
+:10EE2000AFC2640FDA65ACB73EE9C7CF637E157039
+:10EE30004C3BA45F25E40519D80243F2397F121D2B
+:10EE4000E7FA1E8A9A9F5566FDA2F3652147BF43E4
+:10EE500051FB367C9F6CCA8FE8C836D51F75403190
+:10EE6000958F091799CAC71D554DF9AB22A34DF5CA
+:10EE7000AF3EA799F215EC3A53FD4AC75453BE4A28
+:10EE80009E65AA7F6DF65C53F975CA1253F9D84294
+:10EE90004F493EEA0F36679390C2D812B7569A0F81
+:10EEA00070484CACF3CD453B69B54B6613B076303A
+:10EEB00088706BB439E475C0A73E15B43C0678FA87
+:10EEC000B005ACEE02A82F8619A6072D6A19A6F97F
+:10EED000DA162FD269E9A04405F1217120631D28BB
+:10EEE000A7243581013FB12585DF2D44BADE06FB1D
+:10EEF00007A8559A0A8A3EDA013F480BA2FD9B9368
+:10EF0000E8ADC479ADB334BB56E33E5B98E729ACBA
+:10EF1000CFD4FB47437AF87A8B05F7B7B5C3F9C06E
+:10EF200058C80F85EE19A59FFDE4FBB8DF1DA28A26
+:10EF30006E9F87A7BC3809BFAFBC8E896259EF7836
+:10EF4000F6F98FB83D15FB7D7D3ED7AF322BB99DCD
+:10EF5000195B7E875EFEB92D7EF9C27C2E2F2AEFCB
+:10EF60009BB21ED767EDB032F45BACCCD4FAB00BD9
+:10EF7000E9ABE70A587078545EF230D989DF07D2DE
+:10EF8000F7CAFB66B3B093F7837EAC95095A1FF4BA
+:10EF90003B7C3E31FE3C96EBF3B49E4BEAA55F17FB
+:10EFA0007DFF3CFFC2EBB49E4B60C1F478ED9DF455
+:10EFB0003D3310BF7DA301A7B4F8E5F7EA70B29E18
+:10EFC000CB61FEF4E8769CEF748F934BE5D673A982
+:10EFD000CC1F771D19F49D656BD988373B81CE9185
+:10EFE0005F54A466D91890F81C16D9A301FCA7A2F7
+:10EFF000490078CA1C6A19F22926592361832E40D8
+:10F000007ECC65D2A7682F580019BF81A9DDBACA86
+:10F01000FA69388A8EA66AE63CC3FA51F2E630F6FF
+:10F020000DF34E1C5C9482F87E8A2929721CFC32F6
+:10F03000D2D90ED12345ADE7602F7AD2EF75381DB6
+:10F04000CC890FC7DFE6733D6AE46C16575FFB7D22
+:10F05000BE8BEB81456A9F0BC90D84AF373DBADF8C
+:10F06000D87DC8A0F24B8533E005C9F5C80F9C4197
+:10F07000F2537EEBF036F0A79F092F0E1728FC7B8A
+:10F08000D7BCF3A83C2FD7F3663EC9156520CAC587
+:10F09000569D7E5B252D699813F918AB8907FF8C67
+:10F0A000025D4F8D59772BD3B2E7A25F43B2AA4FCF
+:10F0B00031E487CCF7421CF8C7AEDBA1CF1BDA578F
+:10F0C00087B03D73A99CCF318F230BF47CFC172CA8
+:10F0D000A1C2FF8E15FB9FED73A9EB40053AA9CBAA
+:10F0E000ABB92C6C453EDC037ECE0C2BFA6D63E194
+:10F0F000E861CA1CA1E0E2F0B438E4ACADB0BE39BE
+:10F100007E1743FFCCADB399AB04E6E1FD41DADBFA
+:10F110001AD49977FDE0D235980E19DF2852AB6BDF
+:10F1200048DF13FCFDC46F865CBABED7E8F2162137
+:10F130005D1C129445B47E01D68F72A6EFF18173E7
+:10F14000A3E0B7B87FC5DE02F47B5999968E7EE2C4
+:10F15000ED76F257B10D8CF4CFFA1D8336A19CE900
+:10F160002CF0EEC67AA3AED1FDB65A64E08DC997F5
+:10F170000F27F86345FAB8189CCEE7733A3FE88A40
+:10F180008F2FE5057C9F2E954E320A381C22008772
+:10F19000CDE5DF3E9D00FC4C7C63B78E7F466AC0A8
+:10F1A0006DD464B35F77B7BE8EDD059C7F7416782F
+:10F1B00008CE9DFDBF3C9C8072DF06EB8F83EFD7AE
+:10F1C0005DE6FA7BA3936F8B1F1F4C8C3FCF39DF1B
+:10F1D0009179BE6ECCB334FE3C6FBFCC79C2FE2CAD
+:10F1E00072147CFBF3EC2CD05E2F403994167F9E7A
+:10F1F0003FB9CC7902935B14827A3380FF61BD6F93
+:10F200007BBECC3FB70AE5CF4D5EEEF72F014E8BAC
+:10F210007C08A6F2E437C351AF55D76E40BEB3C2E7
+:10F22000A5FA65E223AF237E031F641ACC67DA6474
+:10F2300081FC489D23BE5C2421BE67B1502AF2ABFD
+:10F240001D76F263C7AEFF67BA9C003AF925C28902
+:10F250004D890C447E7270607C3EF1CBD8FA4D1122
+:10F26000924BEB2AE2EBA5BFD2E975B9A37972966E
+:10F2700025FA5C0516282297F569FD50CE96CB6BD2
+:10F28000909FD8401E215C6DFD06F7C1FD80BC47F4
+:10F2900080B422FBCD03828BE07DA20B7EF9DDE3FF
+:10F2A0001C6FD827175A7BE7E7CBC41747FAE2ACA5
+:10F2B000E7578AF7D582287B71D99637E4C268BFB1
+:10F2C000380B5B18098E08F9AFBBFC057DD865F9D2
+:10F2D0000B0622AE64A27CF0907C40B9817673E389
+:10F2E000AB63CA707341EF6022F2D3E4449217819A
+:10F2F000BE638B9428781EECD21BC45EF4499BE954
+:10F30000FB470D0E3025BBF3B71C7DAF0AF5F8396E
+:10F310002CBC16EBCF599984478F5DEBECEAEF9C40
+:10F3200060D26BBBFB97E87B85C31912C188A970BB
+:10F33000FE3EEE7EFC4AD13EC1F5FDB8BFF629A6E1
+:10F34000B1F0F3DF373E95FC0708BFAB7BEE7B6F78
+:10F35000FB7C5AD14E607FADFD65C39FA3D2395C63
+:10F36000A2712E2CC9871DDDF0BED47D7910FF015E
+:10F37000767D52A1760EFBD758AD0FE733DBA0EFB9
+:10F3800018FD868D4E233F64A3AB63EDCE283ABCB7
+:10F39000D512C9E4723BBC169D4B7FDE9E40FCA398
+:10F3A00073FBEBFDBD748E66E81D49E23749973E5D
+:10F3B0003FC3AF604D8CAF471BE717BBACC585A4FF
+:10F3C00097E0F9EE68C80BCA02B4272599A90198FD
+:10F3D0006FC5B5804DD0DF4431B73D0CEB38CB4E17
+:10F3E000A45D85E0D3FDAA2BDF199180F39C2859F9
+:10F3F0008F47F3A758FF4F5EA1D9FF738ACD4E09FF
+:10F40000215C8AB87FA4F4956B52D00FFAF09489EE
+:10F410007D30DDD9D0244BD66E3F50ECFC2B7AB139
+:10F42000478714727CEF48D48614C2FA2A7A59BFEF
+:10F43000AAD73B94A8A98599DDFD61FD7871106F6D
+:10F440005CA9F37B1DAE37F9E792BE6571005F459D
+:10F45000FE097AAB28A37FB0D04AF4AE3145CE2264
+:10F460007F21DF7FE0EB12E4AFD2F342D307016CE0
+:10F47000B7F176179D7F33AFC2503E0060E83CA0E5
+:10F4800051F091BFC181F11E90AE13D40D22A4A200
+:10F490002592CEE922C8E3199857C2FCEB42388086
+:10F4A000F1016B1C3FFE25FABFB580C41226405EF9
+:10F4B00062E45FF41F4CA6F3389A19CCC36ECC4BB0
+:10F4C000CF27EBF9CEE993260F80F4CEC4C75D8831
+:10F4D000A76101F828F4F355E28F434437BE44D5C1
+:10F4E000DA17FD4A1F535E5891A80AD9E8777215BA
+:10F4F000A19EBA8A25AA7618477396F8715C9BC2BA
+:10F50000C80F9FC85A681D4EE7177E048ACC640155
+:10F51000F33989DEF98564A7303A1F3FFC71F26642
+:10F520005C7F827C2A74377C4A671AD54B8F918F17
+:10F5300099CE9502C56D78A418B9E81510FE7DAA7C
+:10F5400063BF9BE5A5831D94111F859027FB1BE0DE
+:10F550004F1D08B7F26EB87548DC9E33E0E69FE8B1
+:10F56000FB15C2D57FAF5D0E64F4EE6703008D42DC
+:10F570007DBC435EB415EB83C1C42CD85F365F9F5E
+:10F58000BFC6CEF741F26EC5F61F5AB365B4770C0D
+:10F590003C6B1EA8FB217AF1733C58C8F1B02EEDEC
+:10F5A000701DCA3906835AF2C05E4A3E3A12F90605
+:10F5B000C8CB26949709568DE06DC8CDE5ADB7311F
+:10F5C000A4ABBAB6B90CE9F543C13B6037D9238C7B
+:10F5D000ECB19993FD7B2C0AFAB0A6AD75427AB8CE
+:10F5E000309F9F67EC99B487D890E82CC176655717
+:10F5F0007BAA3261DC400953EF857A8104EFD6970C
+:10F60000705DEF882AFAB9EA5755B2CF86EBC80485
+:10F61000DF37CD48277F694665A411E30422F7331D
+:10F6200019E37A7AD0C77958DF48C69EA0B1A09F67
+:10F63000057208F12707F04D90BBCB9FC4F2029EE4
+:10F64000BF1AF2F57C4B59417BC50D23B85F8CA1E5
+:10F650005FACBE5D207F5BC1B4E1A4D71462794684
+:10F660007479EAB267215F587D958AE4A458BCBFDB
+:10F67000B803CBDF66B40EA6F3EF5131F43BAE9B7B
+:10F680006EA8BCAC2BEFABC4F9EEB98D91FD5AAFAF
+:10F69000CB5B13BDE162A14C1B89F8D7D50FC37EAC
+:10F6A0002AF5FC3849A67E727D4CE70B9E8D3FA55E
+:10F6B000F3018B8A7EC946A199E0C3FC3ED2F730A4
+:10F6C0005E06E9256FF6CE5D561C2C83D39DBA8F5E
+:10F6D000D35D39F38808AF91F2FD011C7FE66C37EA
+:10F6E000F199314719C185280FF257A50AB44FB9CE
+:10F6F000030A68DFC73BD42611F04814CB0A126016
+:10F70000BCEAD9029D4B4CAF760405F8E774A00F14
+:10F710008A8392BCEE1980EF33BD023FEF85FCEC8B
+:10F72000283F3C68C3745E36C3CE7C2FC4C1E7DC7F
+:10F73000019C0F1BEDEBD7D84C7E9DEC014E2AFFB0
+:10F74000BA70D261E2138CC7B3E4247A8E217F674A
+:10F750005233F1A9C316D0BF51FF651AE9DB37E96F
+:10F76000F46EF08BE9DAED64074FF798F5E80F7166
+:10F770004F900E6609A4E7CEACBEB09E7DAE50D0D1
+:10F78000CFF172E5C349DDDF15A6903D7D23EA394F
+:10F79000A5F07132E82151FAFDEC3BCFA752FD3EB6
+:10F7A0004F2FFFE60A40851ACE5FEA019EC82F2B35
+:10F7B0006649442F756B6C14F755DFB6DA9A85F8F5
+:10F7C0007C0F5339BE7ED2D80FE6D9AF561B212A03
+:10F7D000DDF0E9571B1490AEB390E710FC2336F42C
+:10F7E000C7CDB0A9B5B8AE19694CF6A7025ECEBABE
+:10F7F0006E23F6BFC6C16411E46DDFF677828857C9
+:10F80000C0CA55C449C01C8A67CB9593E85CA1C99E
+:10F81000328CE2B59A5CC96A747CD4BAD5DD78873B
+:10F82000715A8A9D0D93F5FD8D6727150CE0FCEA52
+:10F83000518191BCF0CF72109C330B789C52668A38
+:10F840006A0BA422BFE17CEA5181C7D73D6AF5E685
+:10F850000CC7383C502BF9FEF076B1749F99AEF787
+:10F8600093A4080120C669ED65E516849B3359C54C
+:10F87000B844A3DFCA44CD8A7CAB72B0302240F0DA
+:10F88000DC242D40FD34C1CCF7AD56BE2FEC23CE89
+:10F89000F763E520C801E2FBE8AF0F9493FC1A3F41
+:10F8A0006004C903EA6795E490ED2AEB21CF323C6E
+:10F8B0002C19FD5BC30064A8AF77647BA662DC9E55
+:10F8C000FF4D89FC69E5D5EACD0BA3F6F5E7037595
+:10F8D000BD7D62640EC541DDA3F6C338A83515DDD4
+:10F8E000798C77AC61CD36C4F79A18F9B8D4B99B46
+:10F8F000F4C8A54F5ABBF197617CA85A80FCA3F6C7
+:10F90000D91EFE20E253DDFC2CC6BE64F26BB89E0D
+:10F9100011C08F910F6985C922F995D96C2E47D9ED
+:10F92000D302FAC544D7AA26947B9D4272B358DE0F
+:10F93000CD2747E8FB759FE479ED6E5C37E84B4FC8
+:10F94000C9ACA71C603ED25F2680DC443D5A689F4C
+:10F9500029E2B81B1743DF788E2F852B317FE762B2
+:10F960007E3ECAFCB7D1F9D738BF5D46FAFF2A31CF
+:10F970006F8D3EAECF0ACCFA987C0FF5C7605F5012
+:10F980006F11901F4279DFC9D014E8605CFB11EA67
+:10F990006F633AA78B583D66B7C519B45890EFFA14
+:10F9A00049EE24B06036C24F2BE47CB6FC00E7B3CE
+:10F9B0002FFB4183165195F5DD34C54D7A20958F87
+:10F9C0008D308A9BD9CEBC75BABEE31F908951A2F7
+:10F9D0003ECEC7757DC1D0E3AA62F6F15AE7231285
+:10F9E000F2AD6BB37BEC9788FD4F6602E98BD729AC
+:10F9F00017E65B9AC19798992FB9D979DA3F76FFC4
+:10FA0000DE3BD04F1088D1830297A907A5BBBD1B51
+:10FA1000911E62F5A1DEE2289FD2F9FBA5C65182B4
+:10FA2000063107E5D758C3CE8AC19FBABDC7E73CA8
+:10FA3000C0BAF1AE0B9FFD9B6EC675803C97D1EEB0
+:10FA400013FE6B3DD1F51AA8278E47681E0CFC1CCF
+:10FA5000F2210BF3619C02F3CAA7114F0DB90B9C65
+:10FA600088F0A47121C7BB5112CFE782228B78198D
+:10FA7000181DABAF7BDDE887D6CA4B282ED690C7C2
+:10FA8000C32D1AE1C908A6A6633D034F46867939FE
+:10FA9000E0C76EC48F7193015FF231BE76543FD4DC
+:10FAA000BB2A9842F8511123D72A9DD324A4F34AA4
+:10FAB00047ECFE6B16ECF71A1D3FAAE47F0E3FAE33
+:10FAC00040FC30E416E8C9F7C5D817F7C5D8179732
+:10FAD000801F615CDFA5E2C7B101971767DB69BDD5
+:10FAE000E7637F39D9B33E31AF277E08ED772E7AB1
+:10FAF00000E93D90CC70DF5F48902B9D30CFFA1A23
+:10FB00001E6F3EFCADC200E6B396BB492F7C21556B
+:10FB10007D8DCA7DBCBCBC431393215FB012CA214A
+:10FB2000FF82DB5389F9FA55500EF547BCE70D60AB
+:10FB3000BEF01E5E5E76AFEFB56494F37EDEFED55A
+:10FB4000638DA20BCA838D7AFB8AE64ACCD737F144
+:10FB5000F6230F0403981FF4001FDFD03BAFD6F944
+:10FB6000E70BC2A9D7EEC2FE807F6E06FE39EE8497
+:10FB700056F61CE417C8160BE2EDC288DF8AF8704F
+:10FB8000D8523B12F187CDF366239ED9D16E15BBB7
+:10FB9000F997059D3AD06E826425BDEF0DC12761AE
+:10FBA000BDC94812286747AB0EE4EF1887BC19E4BB
+:10FBB000CD005D1E1971BB787F606AD47E0D18C8B8
+:10FBC000E5BC512F2B8DE3057B8CE38511571C5A27
+:10FBD000CF04F4B7E0DAC80FD123CED847F23BD830
+:10FBE000BF6418E2EDB5185F0CE5D78EE5F1C56589
+:10FBF000DF9C9E14CF2E2AD6C73DAADF8730BED702
+:10FC000004DD16A49F171079FA62FFFDFF88FAD26F
+:10FC10000B38D65802A99F8DC67DE4F9B103731E37
+:10FC20006E02BC586CF14988472C4F5071FED77753
+:10FC3000F8AEA1F5D43276434E9C75E8F27E51C001
+:10FC4000B699C78770FE335DDFB763F2EC3D7791FD
+:10FC5000FDEC52AD30CEC4F10388EEA7550B06DDA6
+:10FC6000570E443D184F30C89FEDA538F7252C6836
+:10FC7000C34196C4D0FD32E7998F512E2DDB62A689
+:10FC8000EBE52C64E3FEE6C8E31F40FF351B9265FD
+:10FC9000943FCB5BCCF56A36BC754028EDC9076A4A
+:10FCA0000C3E1034F3015038381F583F98CEBF56E1
+:10FCB000648BCAA174F47FF848DE27302EEFEF93EF
+:10FCC000D430D15FBB9DDB51BA7E7EA7C8F5F3046B
+:10FCD000E6509C45C8872D7A9C2ACF1BE3B398F841
+:10FCE0009653CDB711BF31E260008024EF4FF9AFDA
+:10FCF00095A3FD6C5D7C3E86DECBDAFB84F09E81B5
+:10FD0000E16701FD80EC2BB60038DD38E243B46FCB
+:10FD1000C252F87F0CAECB46EB5A9F9447FC7D1540
+:10FD20001084BD0CED62A924847D0EE6F4E4403A13
+:10FD300042FE3ED96C6F2530AEC70FEFE07E9C11BE
+:10FD4000DD72BF01F7D7CE540797FBCD0CE9AB5757
+:10FD50007BC5B932AEBD42120AFA9F3199F3F58BD9
+:10FD6000D92BBDD9235DFB99007A1BA4D3BC09CF45
+:10FD7000E3BAAF3E9F921C2F8E6A5A85E841BB6C56
+:10FD80009A55CB4C8B1727897A7666547DAF93FAB8
+:10FD900093BCE9CF63DC12F41B42FEDFF1A62D6EAB
+:10FDA0003CB2A4F72F5935395EFFD7A2532ACADFD8
+:10FDB0002E79B3A8DF6F415F7971601C7DC5B62BCA
+:10FDC000E69C92F90746C7133CA3FB0347166A6DEE
+:10FDD000D8FE60421EF13BA50CECA97E94A7FE0E56
+:10FDE000DE762DC5479C61DA45E323D644F9CF0F73
+:10FDF000A6C63F17795DE773368C7983716F57B468
+:10FE00007D8857476DFCDCE568A29EBAF8B9D51F1E
+:10FE1000BBEAF3F498C1272DBCFC689AF9BCC6A8CC
+:10FE2000F7B9EE873AD4E0F0AC89F2BF2AEBED3EA9
+:10FE300094D39905FAFD8D958CECE7CE5752374552
+:10FE4000EFEBD98115B62B33B19E66CB4138BEC2DC
+:10FE5000E55F9D14B6E1FE3E7285F7139C779DC267
+:10FE6000B417B11F256CBBA904ED061E17D269E5B6
+:10FE7000766067024F8D799D1D38D576259E23DDEE
+:10FE80001626BED8959F1A26BE7776A087C6ED9C0B
+:10FE90006E94EBF9FFCDF30A93559C6F8543B71F22
+:10FEA0008AE435E47705BD0FFD36B1E7078C8DE7B1
+:10FEB000FAB11EE7A9E5FE83CEF17AF3F35B1C1DD0
+:10FEC0007B7E0EDFE7E8FE606FDB977BEE56087FF8
+:10FED0000EE3B87383098CE2BDFF45BF7E67FF0E5A
+:10FEE0005ACFBA8A48DE63E5142F407EB5E5EDAF00
+:10FEF000135F5F6ED07DAB99EED3AEBCB473B5D853
+:10FF0000F3966F81CEAEB8320E9DFD0EE535E0570B
+:10FF1000953885F8DAA95681FC210AEB684438AF98
+:10FF200010F8BEAC78637EA50DF30B994C7CBE3502
+:10FF3000969F7903A8272C6B6224EFCA58410AC206
+:10FF4000BB7E9F883E04BA67A344F149BC67A344C3
+:10FF5000D9C578CF263A8FF76CA2EBE33D9BE872C8
+:10FF6000BC67135D8EF76CA2F378CF26BA3EDEB382
+:10FF700089CEE33D9BE8FA78CF263A8FF76CA2EB67
+:10FF80001F61BE47C70B08D7091B10AEADABED32E2
+:10FF9000C295F9B5778BB3489C11FEE17D9CE87E54
+:10FFA00096B926D996031CF6668B4C188DF76B967E
+:10FFB0009AFA5D26D6929F00D40E92233EF88FE0E7
+:10FFC0002916939D7CB64D80BD037D68438CFED081
+:10FFD000FE5023EADB4B82E6EFCB5894DFDDDDF306
+:10FFE0001CE8D62BF573A0BEAC2FE27395E85471D4
+:10FFF0009F4FBD27AA76A6BB00709FB7727F64197A
+:020000021000EC
+:10000000BB72FD78DA472B0B2A783CC2CB4F6D14BC
+:10001000837E77F7F9D0A97DBF3DEC857A8B734459
+:1000200019E9CE9E6DDEEF04C5BCDF4945E6FD4E05
+:1000300056CDFB9D32DABCDFB1704ED5CCFBCFC4C0
+:100040002904E765FDC0BC83F1D3279BF1C180EF94
+:1000500068F88FE3AB42F05D04F07D4CC073B507E8
+:10006000F6F6537AC2B9AEED211BEAAF970BE7075C
+:1000700010CE49DD703ECBC6573A09B86C9A63641E
+:10008000B7BE54BECF474102C7E4DC4AFD3E2F3F16
+:10009000DFD1E10AFA0BD90B51E7504DA248FACC57
+:1000A00063C857B58C64E203EA8624DAAF610EDEDA
+:1000B000DF42E625FEB43046AF59EC7CC4867A4D6B
+:1000C000EC3A7136E877A969E77A4DEC7A7BF8A3C8
+:1000D0008AE4503FCEB75B1E537199ED069FF6A29E
+:1000E0001F238375D8508FE98D0F7E2F5B7B1EF900
+:1000F00011703186F0E0A600FD89AB4FD6771573FD
+:10010000FFBCDDC7FDFCCC9F4AF318C5F83CA851E5
+:1001100094BF7F941424BF432EE3FE25C31E8B851A
+:1001200027CB15D6BC0BFD8AAF311D8EAA2858BA35
+:10013000FDF760056AA85F8F3CC3F5A7D18E968056
+:10014000A4F4B4CF0F17E8E7DC921EF77991734857
+:100150009C3FFA396ED2E3EEAE6A1FB507F35DE756
+:10016000923BDEE887FB357EC75BE998BE2B284FC4
+:10017000DD0DE3DF2870BC88B52B03DBC729B8FF92
+:10018000570B1EF2574C62BE5C6E8F0449CE4C700A
+:100190007849AFB538342B9D47E9FE4BC6C2935022
+:1001A0004F5FAADA681E6BE44F27A13F6619D3FDA3
+:1001B000316DE6FDEB610FC5D841B5B0FFD86FAC2E
+:1001C000DD13078F62E201CCF2FE87453A3C198FBE
+:1001D000575118BFF75DA3FB916A1C1B5DFC1C0EF9
+:1001E000E45C2EEB61374908F831745EF135E25B6F
+:1001F000561AD80374DEAFD8E2C5EB313983CED5B9
+:10020000E73BA7115F9EDFD4C3AF4378BDB0F922AF
+:10021000EBD2F58411F80DC6FDF3950AF7A3244E31
+:10022000D9A7617179475EB43E5B6FE3F772992F8E
+:10023000DD745F21BF88EBB9E5BADE54E3D0E15449
+:10024000E46F44FDB84B6FEA612FFE73F7638C785F
+:100250001780D78022FD7C677546F7F98EB18E2F07
+:1002600046743C1D027889C9D738903F2EEEEF1DA9
+:100270005204EDFA1F081F46BA614E85F4F5936DDE
+:10028000C7F68BF9DDEB023C7B741CAEA34D94F9F1
+:100290007D797FE338E8B7B38CE35DEFF6AFDF98A5
+:1002A000D7E878F332E2EBABC4E2947094DEEED49C
+:1002B000E17774B06702B62BFF63AE0BE76BCD6FCF
+:1002C000D9DB17F5E23BB85E0CFB4A7E10D1CA04BD
+:1002D000D44BABC4F3B763FE543693D1FECC48F293
+:1002E0008B2ED4F3E632F21331D5A722AA88FD8BE8
+:1002F000C94ECEBA03EC27E8F7A395F353F15E7F1E
+:1003000056F282D40227C637C15407405EB078F84F
+:10031000BDEC173FFE8F722C9F4D7EE95BECFC9C81
+:10032000D9FDA3BF2F233A604A9A7D0C8EE7A577AB
+:100330000522A922CDAF62D699E1A85FF53DEF1C59
+:1003400086FA590E9EF302488B74FAB8BA3232DC40
+:10035000E7EC865346417CFB254587C7C1C49333F0
+:10036000F03CC4B87FB13EE96D3A0F3FA99F9FE4CE
+:100370006B935310CF0F0E34CEB54299E8B2AA4B0F
+:10038000D05266E23CDF11199E9B9C91B594542893
+:100390003FC9F8FD0A7F8795CE8956DE5FD927CD04
+:1003A000D97BBCFE7F1471FBA636262EAA560AD92D
+:1003B000F03CABF65F8C8B6A058B3BDE7998B1FE27
+:1003C000BA54894943211598E742F5B67D2DC68573
+:1003D000E3A622CB05EF6D6CD0D767DCCBA8C37B3F
+:1003E00019F069E52B157DD805ECD0BA73E34CF70D
+:1003F0001FD05EC3F5D59D9B40DF2BEF3B6143FCD7
+:10040000C67EF00904E35E466F704E29E2F6461D93
+:10041000DE67488FFEAEF0EF5DFD6750F9333ADCE2
+:100420009ED96799BC39CE3CF7E870199C2991BFD9
+:10043000604888699BE28C6BD433DE35E86D5EAD35
+:1004400013C37370DE18171C6FBC97F57AC67C5BFC
+:10045000D3C28B3CFC9C7520BE5BD095972379372B
+:1004600046F1D3B3BA7FA0F57BE13C7A27E33A6E3D
+:10047000C7F6B6CF53FB7B93903F8C944277ECC981
+:1004800020B38BA11FADCFEC9005E5A44157BDED86
+:1004900077379C45D3FD979E70B65179D7BD33A66B
+:1004A000B9842C94438CF481F57F2CB5D960FC631E
+:1004B000161641BE5325E64E7A15F3603F205D1EA9
+:1004C00023D901E90691EE311D7BB2C08676D9A20F
+:1004D0000A1611816F1D7B37AF11E32E95B9A04924
+:1004E0008E0375678DF9FCB186697B93A1DDFC03F2
+:1004F0009E9410E4173C609663C7DE7DD086F6803C
+:1005000030CFE9C3B82298E7A45721BFB0CD46F752
+:10051000B2163D12DB9F590FCED2E56DAC3E7CB2D8
+:1005200048B73B46B29128675E6D68E3EFE6E8F7AF
+:100530001041FFD3E2E189A1073F9938F1AF4504AB
+:10054000AF1611F9D238297EFD5B8B39DDAD78EA23
+:10055000B4CDA5F44E67C7819F14C2F8271A644A28
+:100560005D83346110F49F37C86B1B04ED45259201
+:10057000F705F939F93928E01BE5EBF17E1ACADBFA
+:100580006AAE27D8C5DB6A481FEDC7E400E92F3EF5
+:100590001FF9D32DA09FA462FCC6EDA28BFC0DFC1D
+:1005A000DDA0317F59908AEBCDF8CDCC1710AE7815
+:1005B000C781E1FB2B155A19F2F775539D74DEBF05
+:1005C000C9E2A77E3050EB3E8067F09931BBD07D09
+:1005D0005ED8F2D044B4FBE4F69D21B4579A2C5F68
+:1005E000EEC5B884A6094C0D10B483344E7DFBD4FF
+:1005F00017B07DDE34A78AF74AD7B9B53239AA7F5A
+:1006000085453E463DF364AD85FCA6A7DA9EA0F382
+:100610002AB0EF22A87C9FAACD27BF9911F7436784
+:100620007F71FC862740BEB1A87BDCCB5B3759507D
+:100630001F1F821B15155765CCABF6DE50D6CD2893
+:10064000777F2D911CCDF8AFEB287EC02D2902C2FB
+:10065000F36641E6FAA8AE27CF62C69FE63DA89FA3
+:10066000CE433D19F0F0332148F19A16D6FE12B66A
+:10067000AFCEE6FA20535A46A0FF3A5CABBF4BB46C
+:10068000CC9A8AFA8D714ED01B3EF4E6E7819E1615
+:100690007D08E39E1418F99BEA2D913C9CDF716B59
+:1006A0007CF93A7D10C7BFBA81BE20C9F334263F1A
+:1006B00085F32AF4BA912EEB2CCA0AF27BBDE7A18E
+:1006C000F8904E414E33BDEF2237FF0EF5EE7A8B98
+:1006D000CCED9B035A199EC7744E2DA6F75E4E5A59
+:1006E000C379C44780EF615C56DDA017A649F8DEE8
+:1006F0004E5FD0BB20FFF3413B783E3FBCC802F9C0
+:100700005DBF7E7F9A0470AD1B1C3E8CF937077D60
+:10071000CAF3C3C28B707F8E0C8AF03C1A60806073
+:1007200067067D35CD0FEB3AAEFB3F991A9E83F3FA
+:10073000AC7BF54A4BB47F313C88F3CDE309BCDE9A
+:100740007137BBF546D43F8AC2741FC6A8B77B90E9
+:1007500011B7C9F17FC9B68410C6091BED5876FCE4
+:10076000FEEFD1DB2DD1DFC902FAFB2DD6DB9DAD2B
+:10077000A4D13E1F051E85707965109DF7CC1B9492
+:10078000A6BF7314CE4B2BEE39DE5294F32807AC80
+:10079000E67B6FF70FE27C9B15F3FEEBFACAA9B874
+:1007A0001F5969DCCE800D49BD8FDE2FD8A4EB55D3
+:1007B0007C7F3244B92C2093DC198E76F3EEF3B9AA
+:1007C00065643757C6C78B4775BC5812E0E344725F
+:1007D000147933DD37671AC6A3EC6E4BA07518F594
+:1007E0008F0CE2FA4578502AC78BAE7DE823D038CB
+:1007F000011D2EB900EF926EFC31DA5F6CDD5BFEFD
+:100800004DEBEEB14FE57C7EC67A187B88EF2BCCA2
+:100810002F15F4FCE3ABF576A38D7928440F4BB686
+:10082000DDB581F33F258DEC76F6133E5F87316EA3
+:10083000319D4F2ED7F560D1FFB60DED8DE54D1DE5
+:10084000F4EEDAF216FECE5637DD692BA3E92CA3BF
+:1008500080AF3343D43202448FB03EA2474D8F372E
+:1008600030E34F17BC63E9B8477F4A9AB93F85FA2E
+:10087000EB6D1F3EF8B6F721101F9E5DFC25067E2E
+:100880005DF4E8D6DB15039E95F7A4C737BBF62FBA
+:10089000868EDDFFE478FABD93E577E9F1AA8A193F
+:1008A0008F97B7BA2DF38ABBEBDFDFF290273A9E22
+:1008B000D6DE3AD78FF2AFBEBD82E26A97BFBCF5F3
+:1008C000777E68BFF4F99FBA3098FA98D49C857AFD
+:1008D00071ED536B5D1A9EB3487E17F2CD63417183
+:1008E00072BC7BABEA60415F1FD7C7EAF09FD0FFC5
+:1008F000F167FEDEF81F30FFBF0AA05F21BF6DFD6C
+:100900005B23DA6F7B354704E5F651293C09E5E8BE
+:1009100092B94EDF6A15E306CDFAD4D25FFD344BAF
+:10092000A1E06E7F3F0BE953A17ED8AEEE49AB8AC2
+:10093000F67BDD7BA20AC3B07A1669C4F9C5B6AFEF
+:100940006FF9CC867095411FCC1DD7B31C3809E1D7
+:100950007D7DEB7F7E29BA303DF6212BC5FEA2FCC2
+:100960001100F79A5EF432F760DD4FA9DF0B30E03B
+:10097000C38299A4DF047EBDBEF41398D78927FFF4
+:10098000AF4B288E9697F712BC4EB5CCFFE5AB4A1D
+:10099000EF72F524EA07F69E7A80D2267025BB9D79
+:1009A000A7B5D6900BFD02B59BACAA1F3ED76E7DB6
+:1009B000E2693C57611FD8553C7AACDD7ADA86EFA4
+:1009C0009ED50A5A44203D8BB98491DDFBB46CEB73
+:1009D0005FB8BF2A476453609F96FEF62CAFAFB155
+:1009E0004802D45FF6C227E4DFAAF53A7D8E38FBD1
+:1009F00054D9B2D31676C6D9A7964F26A11E14F89D
+:100A0000F557B40FC77608AC8FBB67FB9A4D7FB123
+:100A100021DD9C800D494FE5F042FBB4BE459C6B47
+:100A20004B89B76FA1EB51FF8372F2835C6CFF843B
+:100A3000C18CD3C5CB5B9F437BA0E643BB3A05C7C4
+:100A40007DEE761743FE2AF938BEFF626D9606E307
+:100A5000D658FD5932A5FC7BCDE377101E2E7EE7DC
+:100A60008E2CD2EB989663194DEBCDC1752EDC38E8
+:100A70009DD6B98879090F6B7EC1FD196725363976
+:100A8000DE3DE32D8339DFB2B3DB4A913ECE424FE8
+:100A9000E8873962633C9EF75DFEFE989DDD981203
+:100AA000FDBEDCDD83391FF1B3E0C7F8EE643DD84D
+:100AB000C5C817C477CE4EC27E56BA259F5DA6F52F
+:100AC000FB757809DFF0780E4532E24EF361BFDE48
+:100AD000A9EA8376B09D9DB2DD528EE7BB4C41FF03
+:100AE0006F543B82DB91CDF64401ECFC2359F1EFCE
+:100AF00011BEDF45F7EC5D16854FF55B8E103E317C
+:100B0000B0BB52B279FE31A443B08B52006E67DEA7
+:100B1000FBCCD617FD1D19163600E7DBF117CA33DB
+:100B20003553C1FA46FFF56D76D37B24F54FFE258C
+:100B3000869EED31EF9CF8089EF52C45417DF388AB
+:100B40002D32691B8E03E362BCE6A247ECA677C296
+:100B5000BAF1C5D6FDDDDD4D9F867DB558A7FFD81E
+:100B6000F5C7F2832762F801DB987949EF3ED55A41
+:100B7000834F237C6A815EFD44AF9CFE40478F0C0F
+:100B8000007AF8FCD9D7F6FF10FD742DD68C2934E5
+:100B90009A99CFD6BC08F48BFE348077828A7CF693
+:100BA0002B1BEABDD9956007C3BC3F77AA7829AD56
+:100BB00027DDC2F7B874EB6474AEF5FF8BBF2EEE81
+:100BC00085BFBE35D87CEFEA2C2B4EC13B0CC79FAE
+:100BD000597605F91562E06BD8BBB17C73F160857D
+:100BE000E01CCB37E1CF7E1605C7A5BFF982F0F632
+:100BF000AF39FC1CACEEC9BF91FC02B046EC80B72B
+:100C000075C12F29BF16E517E5774EC3F3EA9EEBB2
+:100C100036C333B6FC219D1F75DD73BB97F931EEEA
+:100C20002EB25DA4F7173A612E8DA89F3FEBA673F5
+:100C3000C2B5BABEDF29475CA89FAF4D35F2EC566E
+:100C40007C07A6D35F2AFBB17D821E7FE089B85264
+:100C5000A3F4A44FDA4517EA75E1209B1CFF3DC0C1
+:100C600000CD23CC7A2B5FCDEF6B89E79F0BEB7622
+:100C7000BD1DC60BAFFEEA393C373F2439E8DC72B4
+:100C8000C1EA992EBAFFD75EF07F102F16BE017011
+:100C9000447AF26BB61C80F37C0E02303FFC741E6B
+:100CA0002C2697EFDD06F5160180F19C24D69FB225
+:100CB00094795242EE9E7E1390833694FF8B411EB0
+:100CC00091DF7BA3B97C69FBE784674B63F0CC8B36
+:100CD0007896D313CFFA0ED1E9B68C95E9E7BA64CA
+:100CE000CF77EE13E93CFF948391BE81E7BCB063FC
+:100CF000EC54BB48FB73EA592148F186FE4CFE6E6A
+:100D00002BE03BEA59061EC6DAF7B1E989973E1A8D
+:100D100089F7C46A7FF7DFA53F87F4C4EF3E18B8B0
+:100D20000DF32FBF9FF7DFAC67FDCA1D7F233BA6E6
+:100D300073879DFCA19D3B5ECF43B9DCF9AA5D455D
+:100D4000FCEDBCD7CEE31A7624D3FB659DFDB9DF5D
+:100D50002EB0FDABD230C9AD357C1F87D868BF4FF0
+:100D6000B5FF9DE4C8A976BB82EBA8DF9144FEB134
+:100D7000FA571382E81FE8DCFED5C8E877AEFED547
+:100D8000F5D4E9F7693A935935C6CD74A6F238CB54
+:100D9000FA6D639E588DF648EB4E1BFAFF2BFFEB66
+:100DA0001FA5C8973A5FDC6943BE0576E9E30CF0FE
+:100DB000C3F39B9FFED49A83F7C518D9DB277EB374
+:100DC0007F3ABE8BD5132E1C0E9D00075C17C0A565
+:100DD00006F5B2DEE0B1F83B0B8F2FC99EA86D1F60
+:100DE0004574D40D1741E3DF93830E01D7FF8A0BBF
+:100DF000FD469DF920FF555CF757A5A83F5D6CDDCA
+:100E00008DFF53D66D6197B5EEA786F0F7C8BF7B0F
+:100E1000EBE6F83F64089757B174D013CF5FFE112B
+:100E2000E59F4B5669BE9748FF7BBEB3EBBFE47DA1
+:100E30002F45BFEDE5EEFBA1EFECBA2FB6EF6FE863
+:100E4000FB9E2CE3FDBACEEDFFC8A3F55EE2BAC56A
+:100E5000E2EF2A9D5F78DD5DFA91E871E0D35A0FE9
+:100E6000B0508702E9DA5EF414B5D86C8F88BABE48
+:100E7000B1960DD336A15D057A06DA016B3378BEE3
+:100E800009F40791EE0F52B00A6BCA55F97BB6927E
+:100E90008FC990B7BE3F9FE259D6667D8FE597E335
+:100EA0007905F7630456ABDE9DD03E906A51022A65
+:100EB0003E53B5C2BB09CAE5BEA28CF6CD5AE54683
+:100EC00047F43B1692D366B2539C31F64662A1CDED
+:100ED000649724B05D32FAE1135489E2FFEC2CAA46
+:100EE0003DD47715F373EB4416F4CBCECB87D32DDB
+:100EF000C5BADFECF2E1E4A07B95B20E27A669B893
+:100F00006EBB22911E2631B01FF93AB8DD0970542C
+:100F1000A2E0C8743B54D2412E29C3088E604028F9
+:100F20001347235C7D04C7408E28135CBBFBA3756D
+:100F3000C7EEC35A6522CBD7F57141FDF6E13CBC43
+:100F400098FF1E432C9C8DB4C05BB11AF5DF95ABA6
+:100F5000F939D78BBFFF1EE55BADA00FC37CC6A7D9
+:100F6000781715A3DFD1A30948A72BA7F27705CBE4
+:100F7000F11E58069AFA3C0E37C391CB24F25782E1
+:100F80009D41FE4A99A1FD274E642DE40FF448319E
+:100F900071BD32C53D056EE3714FAC8829FC9D16CD
+:100FA00073FC8F7F222BC2B8862AB1B619E7758AE7
+:100FB000253763DCA5CD1ACA23FF707F9085E86FC3
+:100FC000A9F8EB462C77835ECFF03E9914FA18E32C
+:100FD0001BEE145318C55545E05314DCAE3EE760D4
+:100FE00052149C2B58AA297FA2FFE156B413F2FD9C
+:100FF000761983C72A1D39A6F62772CED17801BB90
+:101000004346FBA84A769BDA8BAE7D1FA35DF37641
+:101010009A85EC826BB30799DA5FFFE9898D737566
+:101020009CC575DCF011BFA70AF6D6E36F42BB770B
+:101030001E610CFDC6D72965A6766DBA7F2552655F
+:10104000A5F766BE5F34C6346E5B7817C1A53693CC
+:1010500009781E5C6B0192807A3F502B4CF56E181C
+:101060007D9DA9DFA9DA5453BE76D55F9994CED879
+:10107000B855E719BE1B58166A31B51FBEAFCD541F
+:10108000DFF52698429096BDA704301D7590DF23AA
+:101090001D0EFB81E71B6DE1792AC6EB94E005D0BC
+:1010A000723C16F0546218F2C8A3BED730BD58FC8B
+:1010B00032D3DF634DD4CF5FD759822D73DD18FF54
+:1010C000D3FCE04E81E221B7158F40377473650A77
+:1010D000541F7BAEE5354C5B3BC6378D2DA76B436C
+:1010E0001D247F9D163A17A812DB4B05B27F92860E
+:1010F000DBA3CE5D7A7BA7F3EEB28AB7900ED664FF
+:101100006BCD3B91EF4FFC688E98DFB31E93A548E3
+:10111000349EDF5DE6F933C69D197152899522FF31
+:101120001D8A6B799C4CA3454DD09917E907F22491
+:101130002BC5F1CF2DE1726064C7E6166739DA9DE1
+:101140000E05F73531DD7CCF7BFE687E6FEF8B625D
+:10115000DD3F2FC999B79460FB64DE1E7D7C38DECD
+:10116000140BE9533BAF3A42767AE20D96FE2041EA
+:10117000996BB46A41BB7BE4BE3FD17B04AD53F2B3
+:10118000D7EF82FAADFBFEC40428EFF340D95E2B03
+:10119000D2D9688B8CC7F5ADA3279E2EC4F229EF58
+:1011A000524CA3310FD739812951710F734B141A47
+:1011B000DF2585E91D22D73989CA5DB3554B1EF657
+:1011C000B7CF4ABF5BB3E22AAEEFAD1894B815F1C2
+:1011D000D47540E37150454E6500D143389BF88289
+:1011E00014CEBE2599C753291778CFFFF89611A9B9
+:1011F00028B7D22BD454F47BA66F15BBEE99E17CB3
+:101200001FC4BFF020DDBF76FF3550BE0563D57823
+:10121000790878105B67D3CB9105413E5DD0CBFD5B
+:101220006B675CE3A477174DF587E677D5D71CD9B4
+:10123000DDFDF7D9BA76FF9A6284F7280BC69124B0
+:10124000FE5F2BBD2BB0629093F4871540BF4CE836
+:101250007D1DAE73491781A78BCA0F094ACC3BB9D4
+:10126000A112CCE7E57AF34A005FAF389F42F7FE60
+:10127000CF342590BCBBE2FC0DF42E67AB4DCBBB4D
+:101280008BFC3509145F36F5B6CF37AC423ABEFE5B
+:101290007811C62418EF54D6CB7F25FA37E2EABA84
+:1012A000E087F80A78FEA0A53B8FFCC0D50D4F0D56
+:1012B000DFE35A17055FFC6D97A93A3C676E5D3F07
+:1012C00003E1A32C989C8D74789A39298EEFB4FC95
+:1012D000F40C9CEFE92D560A9A6DD5F9A3BF487F0F
+:1012E0007F20239C8DF7F04BDEB150FCD141C0072D
+:1012F0000DF0A120F44E5A09B6CB90D2309EE1F405
+:10130000F8F7E99D84D3F7300A265E1AB611BC5A65
+:1013100033165456A07C3BA0A4A1BFC1806F8BDEC6
+:10132000CFBA326D6209C947FD7E8836F6B2DE9BC0
+:10133000DC79D557740EB0C60D7A7D2A86189F6B5E
+:10134000C4F72457B8AD248756A4FE755206E27B35
+:10135000852382EF3ED4AF3A43F0856EDCD1F7BEF1
+:10136000A4732253A2E2B5FA0CE5FB2F491AEDBF94
+:1013700074CE46E5B5AB4E139F36DA9FD0CF53F10E
+:101380001D46BC1F54FBB548F74481FF3509C330E7
+:10139000DD655B117D8ED3F265175F1F6AC1F79F14
+:1013A000DE4D44BFE454419E8EF3FB6DE99919185C
+:1013B0001F3035419E8EF105FFABF4239EEF2F4F7A
+:1013C000C77882755BAF9E89F1065373E49F5A40DC
+:1013D0005E6D7B6ED64C2A77CB7FC2FC132577F2ED
+:1013E000F264BEEF752537CDC4F8822A91D3C1A926
+:1013F000A6A4A0FD0274B078D53616FD6E6D8F726E
+:10140000FD77A35835E7735FDCDF8FDEE964851D68
+:10141000141FB6BA44D0E3D08CF35426E3796A465D
+:1014200001D3D0BF9CF17202FFFDA1431D7908BF1B
+:10143000231B6FFF11FA4F970B8CDECBAF65CA48A9
+:10144000A4AB7996F0C798FE66B8B789E34707C59D
+:10145000B72E5EB583E6F789AAC729CB9162CF3F45
+:10146000F52E04F41FF75D08735CF1A7166520F6EE
+:101470002BE970992776CCB1F179FDBC04CF87D2E6
+:1014800076525CB324776479B9DE5444F6527622FE
+:10149000BD0BDDD8F7C3D278BF77D0D200F21D489C
+:1014A000EEC586364AEB87325A4F1F296C53A19FEF
+:1014B000BA035CCE8CECF8D4161DBFF88A2EA75266
+:1014C000F4DFB58A8DBF7D459743C6F9F6F2BEA11C
+:1014D0005CD4078D7DEDDE9750AEBE2F0CE79B915F
+:1014E000FEDAB3F8BE09C6B5DE83E7172F2784D02E
+:1014F0004FDD3B9E18FBC068BCD644CE37222F255B
+:10150000909E14BB8E3F76C957BE9E233A9EF4B67A
+:101510008E23B88ECC7FDF3A8E207FCFECB91E832E
+:10152000BE8DEF067DF76CCFE77FF978C7EFB15D31
+:101530000CEF0CFE53C7BC45FC7E34E73706BC8D70
+:10154000791A706BED25FE565AF58A693D52C744EB
+:10155000347298AD349FF3B796EB18EE87B4AA9D1A
+:10156000EAF5B61E31F90C9DDB2C55980FF5DCD849
+:1015700075D5B2166AD7735D11E2C7CB15CE8F7BD6
+:10158000C6ED47883FD7813D86FAB7B1EE2E3E0DB6
+:10159000EB47FABE0A180EF14DBC3B28A03DE135E1
+:1015A000E9C315784322FA9CCA719B295F25DF6540
+:1015B000AA7F6DF66A53F975CAFDA6F2EF173D646E
+:1015C000CAFF40FD598C3EBF29469FFFB5A97C7CD0
+:1015D000B883F4EDB71B26533CFA84A311D2BB4366
+:1015E0000D32E577356453BABB4121FADFDB504455
+:1015F000E9BE0695BEFFBE6134A56F3668947634A9
+:1016000078288DE51BE51DE172F4E78FCE48A1F344
+:10161000A707867AA795E2D1C27B9162C4BFB107C2
+:101620005A5E43515010FCF263AC775AB651FCE15C
+:101630009A9D63FE703BE4D3DF1459827221BD484A
+:10164000645A14FEB8A684199E77BB187F0F2BB678
+:10165000FEAC521E4756CDC2FCFD805574E2CDAAA9
+:101660001DF21E2D83C44604EDF46AE6233DD4B278
+:101670008ABF4B53CD54568EF6AB97F91EA0F82374
+:10168000F37B021E6DEADADF42F90CBC670AED7FDC
+:10169000E86CA17BE42FEE4BBBA60CBECFF208F4A6
+:1016A0007B1E0776DC778783EC5DE3BEE98796CB0C
+:1016B000D127669572FAEA14D40E9CAF3F95BF57B6
+:1016C00014DBAE545FE7F58108E91F11D03F30BE4F
+:1016D000CCA0CBA9F2217DFD8A25650CD2C76ABAC0
+:1016E000CF50DBA1A80180F798439C2E46005DE017
+:1016F000BE8D3DCAE96024D001C941DD1E34E80039
+:10170000ECA7D7B0FDA9834C453BA271C27F8A6884
+:101710006F8D39130C607AF5F9C8CE6FA07C5C0729
+:10172000FF7DA48BD98F865EDADE504D78B4A3C1DD
+:101730004B69A8A146C74F1FE57737ACA2FCDE0670
+:101740003FA5FB1A9A74FC6CA6F2371B3650FEEDCF
+:1017500086A08EA75BE87B1F5D9EF94B653D2EA999
+:1017600042B72B78EAD1565BE95E3F7C427E528DD0
+:101770007345FCA81182C8BF1BD3FC56CC3726E2A8
+:101780001EE0ACFD54FF66270BA11CA8CDDEC6F5FC
+:10179000B0183CA9C8B889F0649A1EB77A20ADF198
+:1017A0000E1BE0C3899687ADE6F7452F0F2F963ABB
+:1017B000D7D03DBE58BEB804DF9F107BF243C6545D
+:1017C000B5BC9CDFE7C2B8BC4BE5F7B2A543BF1F71
+:1017D000C6EFBBD4E53A29AEF6DF2767645DCEB02D
+:1017E000B958BFCBDE4E3C3807DFC3EB0197187BFF
+:1017F000FBCF57F2F686BD0D7A26F9A13A8322D99E
+:101800005F35EE6617D9DBA3232EDCCF25DB4546FB
+:10181000FAA2C4CF771763470AC6F184F68F23393B
+:10182000B3722FF2A5A5FAF96EEC396D1D9EEF0A81
+:10183000F1E01DA638FA65FAF96EECBAEBC61FA105
+:10184000F3DDBA8BDC23FD53A9391E23F6BE6E6F80
+:10185000F882F103D1EFB79E3CDF4076DAC7A57777
+:10186000AEF78FFFF7EDDFC232CFE7A53C6E9AEE01
+:10187000C919FBD9A8FFFE66E34407DD5BE81C211C
+:10188000D37B379D027F6FA7F36F4C5DADE07B3A52
+:10189000F26E940B57AB36E2ABA3C3FC7D80F178BC
+:1018A0000F31CEFB00571D0A0692B1DD413FF99F73
+:1018B000C6BCE70DE03DDB516F6A229257D96E8FAF
+:1018C000887860C827435E75D3957E4F0E63300AD3
+:1018D0002E9DFE9405A3B351BFEBB25B9D93E85DD3
+:1018E000A2D32146D1A3861F6CF8414DC47B0823A7
+:1018F0000E7903286F1B753B73D409BF9802DFAFC5
+:101900003AE3233B680CD8A9F8FB31786F5A8B82F5
+:10191000AFE1C732F89CC1D78C7B7AB2CDBB05FD55
+:10192000CDECD5047AEF2576DE7943B95F68717F17
+:101930004FDE50E47BFABDBC2AF1FCCE6FD02EE81E
+:10194000E0F101579CEF7C1AED9E952F25D1BDB497
+:101950008BDA07F2E9B8FAA991D65BF8B9C9B04AAF
+:101960006538DA9BA8B7A21D6AD8A5B1F50BCB26BE
+:10197000960DCDC4798DEFD010BF65CB05F1BB7E40
+:10198000D59717B40B8DF1EBB78F90E7459D1FD41A
+:101990000F35CE57FEB977A7AF8A549BE4D8775D51
+:1019A000EF033A2C47FC429B15E5D40F7107601DED
+:1019B00037B310E92BB7E8BF5B712BA8E0D1F76212
+:1019C000E7338DF8C31ED5BB08F765218BCCC17CEE
+:1019D000BD10A9DD0620FC62C238D9ADF494D797BA
+:1019E0002B9F13F57BAFB170BF6B28D7670CFEDF61
+:1019F000EBFEC4F0FFCE3299EE3D77BE34CE82E7E7
+:101A0000369D6F89F45EEA3A0BE72BFE6136F529C5
+:101A100015DF1F997D8DE10FC0F8B258BEB2C5A287
+:101A2000FEE17628F7BF9DCEE2D195915E8FFA2830
+:101A3000E061CAECB094EFA4F7D3D721BCBADEEFD3
+:101A400040BE7205C0FF137E3EC79608E4F76C6B7C
+:101A5000E5F99285A934BF4BDD0FE839A914D6B159
+:101A6000B0551A86743A342D928FF45532E6833489
+:101A7000C189BFC3CAEF4501F89A585AF73CDFD273
+:101A8000E1F997A1DAE338BFA1691DEB1E463DF1EC
+:101A9000250B43FFDF9131772D6251F2F56B75E233
+:101AA00013C82F9E17F4F7E5B6F3DF21801659D13E
+:101AB0007EAA3D6AE5AFB15E0BEA5748579E57E8EC
+:101AC000FEFD5499C3925D93A9FFFE63242FDEEFC0
+:101AD0000119E75043513E703F22BD07F6BCEE6747
+:101AE000DC39F4C3996B90918722F9388F2309FC74
+:101AF000FEF3D7AAF7555A07FA6B711DBFE076FEC1
+:101B000091541FDDFFF800F82C9EFBFE778383D2F3
+:101B10008FC0CEC1F4CF60E760FA09D839987E064D
+:101B2000760EA60BCF41A7B08F15AAF6C6D00BAC88
+:101B3000A3773EC1D7D1D9CBEF2AEDD2E15FDA7AD4
+:101B4000E8DE24C4833691E29A4B5E9248CF3CD9BA
+:101B50003ECAF43BA24077FB711EA56D7FFC09DEF7
+:101B60008F2E6D956441C1FBD4A7B3286E30667E7D
+:101B700008073C27886CB7F1DF3FD2E7FB7C6AC7D8
+:101B80003A6CFFFC4BF938433C7FE178B8DD1EF737
+:101B9000F7818D38B99FE972FB067BA43CFADC30F3
+:101BA00036AE8CFCB963109F0BFF80E3F8F7896CAD
+:101BB00000E1A5D94F91AC723964A425DB6D145FA7
+:101BC000FCFCF6FD377E1FFABB7EEC75A67775FF31
+:101BD000819B9B8978FDB7C71ECEA0FA320E358B4C
+:101BE0006DAA92A1DECD8E9D7B70E9B7C89F54A5EA
+:101BF00042FED66C612FA67315F7A43405E71BA42B
+:101C000071E61755EC45D49AA24EB5F1771C453CC8
+:101C10006BECE28F958E247A0CFAFF01C9CDB6AA3F
+:101C200000800000000000001F8B08000000000082
+:101C3000000BED7D7B7C54D5B5F09A39F34A329395
+:101C40004CC2041220709200060830249390902019
+:101C50002721D088944E225A54D4915A44E53122F7
+:101C6000AD694B9B13122084A04191624518285AFC
+:101C7000EDF5ABA9052FF6AA77824AD55A1B149F1A
+:101C8000A576A4D66AAB9282D87A6BCB5D6BED73E6
+:101C900032732693F010BE8F3FBEF0D39D7DF63E8B
+:101CA000FBB1DE8F7D7600004EE27F33DD83001CCA
+:101CB000C03F54FF4AD630808268FD1239DFD07EA3
+:101CC00069C178433B4008A004608EB7D8D06F52FA
+:101CD000464F5ED00930E1A9CFEEA8F4E0031384AB
+:101CE00047633961EFA76FDF82E5DCA957FA241952
+:101CF000E043E8B862BC09E083B2F55BEEA6972D3D
+:101D00008A2D7B30C08DF43BB67F04E1D72BB05DCC
+:101D100072AD3C701BBE77739604921760F136EB80
+:101D20009148CC3A96813F2D8CFD6EDE6D7C0E1075
+:101D3000B1857D00B7049CC13637C09247B0DD61E4
+:101D400068E77197EEB3B9A97D1958A2EDB9000DF6
+:101D500087731F7D3666BC4919DD77DD8DE34D7ACB
+:101D60007C9EBB19D7F768F9E74365DC67A1D7E527
+:101D7000793F053B4C812927252C25A719B0DF8900
+:101D8000E7A59084EB9A297D911A29C4E73599003B
+:101D9000D9F89E49FE6D05B6AB2F48F0008EF3F7DB
+:101DA00046F9D167AD343E5CE7C77E27E9673ACD97
+:101DB000BA9AE1AB976F35E2AF1701FCAED1C1E53E
+:101DC000EF1BDD5CFEA1318BCB771B652EFFD85856
+:101DD000C0E5DC5720D089E3FDE91F930106D13827
+:101DE0002A4066B49C64F39A87E23A7A7E23857629
+:101DF000E17E8F574E49035AE717387FA98607249B
+:101E0000813ADC0394E37F37EC7C2EDBC7CF551798
+:101E10004EB5EC1F122838EE0D5E9358E792AEE7F0
+:101E2000B23DD17658F9AEA13FAC321D30D45B72D1
+:101E30008DF5F6AA03B1EFEB70882F6FDC76AB2D32
+:101E4000E0C272B3490939FBB6EBEB99B93F4931AE
+:101E5000E1789627ED213BEE6F995B0105FB5B0076
+:101E600094CEC2BEEF0134F17B574A10EC4C30EEF9
+:101E7000721A17E136677F12486731EE5B481BB470
+:101E80001EF53FEDA107F0BDB7D214F0C7CCF35D4E
+:101E90006DDD1FA7777CFF33ECF7F113404FB00ED9
+:101EA000F3693D13F7FCD96CC67252B2A09389EE68
+:101EB000883903CBA38BFFB9E5750F93A9DF743184
+:101EC000B6E7F5BCEE4094AFEE9CB9D581787BDBEC
+:101ED0006C06180A02F165D81FC7A0FA06EFCCF904
+:101EE0002DF8FBA5FB93C2E6B3D8CF06E4452A271D
+:101EF000550B7EBF96E846CCA300F2C3F235A0CFC7
+:101F0000AB907CA0FD53FD99CEDA3737D31AA0678A
+:101F10000BC9878F00C26DBC7E253596FF973FF5B4
+:101F20002DE6CF25D9C8F748EAB04DF0AF03FF9DA5
+:101F3000CC237E0DCD72E27A6F0A23FFC3F9E7FF4F
+:101F400087BDCE289F5F9490CF5FB914EBCB9F9055
+:101F5000BC766C3EF6E468C14F1ADFEB7CDE4B4F7B
+:101F60005B25E64BBDFEC993526D2801BC376974F1
+:101F700091AFF4D4D37C2B9EB2401BAE6FC5B48B13
+:101F800086C48EDF875E5B259063C67FF469FB6243
+:101F9000E217197A06D721FF4C7AEA444655A12860
+:101FA0009B681CE8D0E44DCF08FF0494D726FFEFD0
+:101FB000BF87F301E2F101844F75D6FC1C9ABFDEA6
+:101FC000094ADB6406CB3C07CA89CB0488E0B2B27D
+:101FD000AB7300E1B90DD12521DDCD53EA5EBB1A0B
+:101FE000F178B939F05592F36F79F379FC2B5C2BCA
+:101FF000AD606672CD31E178F3E7D98B693F739BB1
+:10200000055DBF96DEF3113D7F6D5A8AA919DF7B0E
+:10201000CD042D9011DDC76B567F4E90E9A7C6FD0C
+:102020003EE2C7A48C934EA6F42F2F8892DFD7F1FF
+:102030002845E5DF4CC9A9D23CC7DC66A67B4B76B8
+:10204000BB8DD67513840E2838EF326FD846F2EF69
+:1020500016705BA8C4A2A7973E88FE2AFFD9751206
+:10206000DF5FD62D854CD8BFB3B1132C88DFC71ADC
+:10207000F77139F28B912DC3101E2B27DBBC6DA499
+:10208000B734FA32AB263899405FF5A54F4BB41DF3
+:10209000D75DE57086A5547A6CFD28761D3FC85142
+:1020A000FEE945B8AAEB2AD3DF4715CDB43032BAE2
+:1020B000CF49360027C9F9075258CE7FF874A9993D
+:1020C000F0F4E18BD69089EADB2F7AE3361FD781D3
+:1020D000E4CD87195EB38DDA33F2422AB6DF6806A3
+:1020E00095E432EC1272EB9969B7BF43726CE50369
+:1020F0002E93DD24E858461340FAC9C677EEC57121
+:102100006E4266B57BA37A63C9F49F6C7904E9607B
+:1021100089B9E38E4A7C7602C213DD08CFBF9A3AB2
+:10212000C790DEFEF3FDF6B099DEFBF1D85D128EAE
+:10213000FF5C6A207B32E9A92C65482E3E5FFC4A91
+:1021400026B4E1FB337EF2AF97496FDEF46826F3E5
+:10215000974EF733890F713D47910F693DC79ECC6C
+:1021600067BE8BE25FC06129CA034038AEDFBDC9DC
+:102170004FF8BC2159667AB440501946F8DE773DD5
+:102180000490AE8A24934274DEB31EE165EA4B4F9D
+:10219000DEC9667E6F8919F52BD161402E26781C29
+:1021A00035C9451A5F00ADE7C8D36377B5E1FBB524
+:1021B0005AFF28DD1D5EF65F4477DBEC5E3B2EE1C7
+:1021C000A324A3DED7CBCAC9E9DCFF46C7A7602991
+:1021D0008E3E5FD6F0B9B15E080AC98DA266B9F825
+:1021E000562C6FD3E03E63AC7F3AC1F1E6CE4D8F03
+:1021F000BF24D3BCDBBEFD36CDFBBC93E785970483
+:10220000FC8E9A847EE9D5AF8EBFF1F8003B797ED3
+:10221000FDF99FEF7F636200C7FFF3DEF16300E922
+:102220006EA1D4FDFE7D88AF4F5CDDEF7C0FCBC788
+:102230009E7F6530C12F7EBD4B1A8E8325460E7D55
+:102240006432F17E97D03EF0F97F14FB2F9F5CC281
+:102250006CAA10DC16B64DD845F260A654984676A6
+:10226000D3D10F8DEB8B5FA73EBEBE3E7D7CBDDF25
+:1022700042823FEE63F22437971FDBBA3F21FC7E98
+:10228000FCF87813B262F47946F7C4F4C2289EFCD5
+:102290004A9395FA5D41A21E5131DF21F03A7FB198
+:1022A00029D49CCBFDB8FD6A7C4E78AFF234737DA7
+:1022B0009E13F519F65F92F55FBC2E12740ED46B67
+:1022C0009783FE53B7E617D8EFCD15A92C17E6DF95
+:1022D000D861253BB7579EA96F9B4F8E3F73798678
+:1022E000D093DD83817998F427E0E62C589FA6D51A
+:1022F0004D65BF6BFE05C9E7DB52BD129A8CB05825
+:102300008630F1F5310811BCD79A826CEF39480F4D
+:1023100060D966F26659B094CC3D8380E70909BB69
+:102320000A0216AAFFCA1469067C6F8DA73A8BE8C9
+:10233000FF4D70FAC92EBA3C7DED0492A3D5EE395B
+:10234000F3E979BD9AEA6EC3FDB658E50D8564FFE1
+:102350005C2E79C9EED5E1A2EB8FF916AF95E03B83
+:1023600038287B55A4DFE297148789E1EF5069DCB8
+:10237000372CC14C5AD75BCECD134C66B2D342AE8C
+:1023800009B8D9B75FF969C96FF0FDDF81328DEC0B
+:102390008179BF72B01CBF1E64E6F76F80C272FC09
+:1023A0009B10E0FA8D10B17E8AEFFDA1FC7F1ED854
+:1023B0000FD17DFD61EA677BC9AE9F2F7566E6622E
+:1023C000BB5A0D05A4677EE9F8C18E08AE4369B615
+:1023D0004012DA57BF243A25FBFDB02BF400F6BBC0
+:1023E0003D797B6A17D62326617FA9D5C147A9BF4E
+:1023F0006A067F3396D9C9815F101FFE30458CD3A2
+:102400006071B8493E928145E3BCFF8E8BE99DF433
+:10241000EEF558AF406C11BC8E660A7A53FF062C5D
+:10242000778F5ABDDD0A8D7B42F63E40AFCE30F34A
+:10243000FB7052E67554C4E917DF7833BF0FFF9481
+:10244000F9FD693D16837EF14D32071FC3FD4DFF37
+:10245000876540BD737991905FBE41E660227BF055
+:102460002F1A7F2184245A4FF33E53A88D8950D8C8
+:1024700007153A3D42642DD15B254090E81EF6A138
+:102480001ED3E7C9E3FD7FA2FA880EB19DEDC1CE50
+:1024900067484EDA83824FB03E83F6E3088297ECBA
+:1024A0003554C860C17A12BE28E4AE1BC88E6DAB2D
+:1024B000824EAA4F838844F89E4E9046FC5781CCAA
+:1024C000743B0314AEEB74FC1550B9BC04425C5E63
+:1024D0000A61A1EF416EF939CEFFD50F40EC675C80
+:1024E00098E91D1D1937DB8197DC6826BBC3F7F51A
+:1024F000C4FE426A910E174488E7F4E1320B025998
+:10250000627E010F3B3DF745E1E188834712C1C37D
+:102510001B8507CE21E0D107BE023ED314840FCA2B
+:10252000A78BA147A27914CDBEA9062F9735E0E766
+:102530007200B83CDBE4E90B97B248C012284C00AB
+:102540009F1989E966884657BF2E022E75F933BB5D
+:102550004866B8E97208F9338BECD178F9A43FF7F3
+:10256000A5541F97911E7C45E9575A509FF98AAB95
+:102570006FCBC7FA8CC76451AFA8FE451ED667164D
+:10258000E589FAA4EA622BC2ABC9947F650DCA99AA
+:10259000FC80690BF1E5CA26B4AB715F81A43B8274
+:1025A00044C7A60C709BB07FA0A9C45B84F500D281
+:1025B0002520DCEC526E13C1D9FE3DF036E32A52E1
+:1025C000D302138B70FD850BBAD70A7C560F998FF7
+:1025D000FD3FEAB6B2DDB2CE160C129E90DDDD4DA7
+:1025E000E5D1FD7DF4D8F716D3F3C786829BF40BB3
+:1025F00078E462BFABEF7ACC0EE0FA52941B14FF82
+:10260000C0F92A69BE00AA2799D6F5732944F05F5C
+:10261000D93493FD81DF16F8A717C58E8FFB90265E
+:10262000D3BC42CF8127B798E03679AC7F368D7323
+:10263000D485F2358DDA051EFA2B571629B5346E7E
+:10264000FC7373CA17D72EC37996238D909CBEA6B0
+:1026500028F0351A77B93932A2189FAD4E79C7C61E
+:1026600074A1207D927C207EA5FD2E467A24BADEC0
+:102670002FF81539C0DD6BBF227E3DFE9E6B17F92A
+:10268000848893F07FA5F383CFA0594DE35FCDE31A
+:102690004B3D8B882E3F497FD5F627E6CBE182EE76
+:1026A00034B9B5FCE9CF997F9E324350D2FC6388A0
+:1026B000E1BBE54F2759C83F5CFE1708A5E0FB15B5
+:1026C0004F3EDC4CFE4E39FAFFE4272FDDF373E674
+:1026D000B727495F22E896FFF753CFDC477C7A693A
+:1026E00012C7A1A6BD7A389FECA0E98723CD883612
+:1026F00038FAD41BC304FDEB7EC9DF4D67A3C7675F
+:102700004AABEE207CAF40FCDB71BE15A6A0A85BF7
+:102710001D6E95E59EF093176BFBF818BAB72C6009
+:10272000B9A21E28A7FD6449C0F23124FC0919FF93
+:1027300011FFDF7238B496D609D21736923727D0F8
+:102740002FA67DDDF250BCDFD173A09CFC6EF28B16
+:10275000719F4B3B8DEDCB63F543023FF98E222DEC
+:102760001E960339B4AF5FA23FF4C7D134EF823471
+:10277000B20FA7525C2181BCD4FDE3DDC9D55B8AD1
+:10278000D85EEE94881F2A2C89FB5F57A8C5793440
+:10279000FB7FC5FD12FB712BEE1F348EFD648D5F38
+:1027A00021EC65FE7D94F40AD199FC021A19643F6C
+:1027B0008A35C3B6414C7337B59AD88FB14BB77AC7
+:1027C00049EF4F7A70C8CDDF65BA49754316D5A772
+:1027D000CC7FC8C3F655908435FA556C673E9ADEB7
+:1027E0009347F33F9A2E838AF33527F5E4919C555E
+:1027F0009F727849EFC6AFFB454DEEE587276F8D99
+:1028000078049E89CF739F2FDF4A783E867C4EF8EE
+:102810005BE11A33049C64375C9C15C1B259B3D395
+:10282000731F1A97568F70F1D17A63ECEAAE835713
+:10283000A490BDBCD7E24F7163BF6387F20C7E509A
+:102840007C591246E4140FD0FEC69CFC4002B8EB43
+:10285000A56FAB85E1A5D3ED2F1B15F8A395F0511E
+:1028600029F6A1DADD761FD15F6806F9932BBE0940
+:10287000EE36ECBDE2851F373BA8BE1E989A8FD17D
+:10288000FFA8FF07E610D9E33F4C99786725D6F7F4
+:102890007C68117E8AAABC521863C7DAB3CC201BAD
+:1028A000E8B55B5A4AF298E81EE935494E06398682
+:1028B0001E530A320C759777A8E1FDB4B23C437BF6
+:1028C000BA32CED05E0A0D9100AEA7244B7287704B
+:1028D000C5836A8B0CED76A4EB30ADF3536147955D
+:1028E000E13FA16F836C0F5544007E847430F52363
+:1028F000A39D5516E9607F33E990C51007B09F226C
+:102900000EF53F3A7F0D87E1C45F48FF5E9263C7D3
+:102910000E89B893ACC173458ED0CF2B5E90D80E84
+:102920005CF1A199F5C431F0F6E287E4A3CE77F12A
+:1029300070CFF41BE13C64BE11AED901235C872D3E
+:1029400036C235276884EBC806235C7355231CF315
+:102950005BA71AFA8FEEA836D42FDA3ADBD07F6C59
+:10296000A8DE501FFFD05586FE133A171ADA27ED5E
+:10297000BBD9D01E4F5793C32B0CEDF6D4D799AECD
+:102980000E205D99501F143FFFDD38BAB030DC4B8C
+:10299000863BBDA118FCABF88FF05FA1E525A680B2
+:1029A000DA4CFC78AEF03FB518F13F3E8A7F5DAE61
+:1029B000F6C7A73A7E0769FA1AF93342783F569666
+:1029C000C2F4F2F2F3C70E2940F84F8522DCEFDCA7
+:1029D000E9228E22C9C156A2936E707590FDB9CEC0
+:1029E0001264FF4545B3F00152CA71FEE6D7CAD062
+:1029F000DF8C59679D92049698FD4E0E771AEAC5B2
+:102A0000CFEF33F42FE90E1BEA930F8144FAAAE8C3
+:102A10004DEF335496BCA770F8ABF483E033549673
+:102A20007F1ABC9DF46FBC9F7B99DA24A5E1A2A616
+:102A3000FEA3F319346BD03F1BA192DF1BB935D530
+:102A40006B1A8AF0487EA799FC6F403BDA8ACA0865
+:102A5000BA7F43C884050EF1FEDF932E5E43FD4D21
+:102A6000E89F13DE112E0564EF3540B297E0427601
+:102A70000BF961305BD8F36B4D2ADBA349688F9269
+:102A80003DD25CE5677B79160487D3F32B4059432D
+:102A90007C2799D17EC5E7C72F0AAC2C2E118B2538
+:102AA000FAB9FDB8CCFEF774F2A719980A90DE3B8C
+:102AB0004ABFD3FA207CA5427110D265B8FECD6D15
+:102AC0004F5EA952DCC903EE08AE3B204006EDC5BF
+:102AD000811F14A31C3E6272AF2DC6775F9EFAD78A
+:102AE00011648F34150BBBCF2E21A49006862C5079
+:102AF000809EFF2047595D9C198DB3F4473F7A3C77
+:102B0000538F6FEE690C7369717B25A2BBF8B863B4
+:102B1000C4ECAE994CFA6F8589FDCEBFD2E2CA797A
+:102B20009E5496F30EE8B6A7F392D9FFBF46C39B17
+:102B3000D9D1BDE67BF8DEB541616F2D3479D95F1F
+:102B4000BF25EB238EA3D82513F8C81F4A2BDC25FD
+:102B5000E22F7ABC6498742676D6A9F67B4BD6878A
+:102B60008678153C3228617C3D3ABECAF08DD9E7A3
+:102B7000F6AD1EA1D7C8CF3FB23EA71A5213CDF370
+:102B800009C7AFAE091E34F0C5750D6F19F8E07AAC
+:102B9000F55D437BC4D363A57865E4F1EC59145F1C
+:102BA000FF78AFBD94F080F87FBA38265E17593FA2
+:102BB000BE06269ECE7EFFCAEB38DCD8CD78D5F790
+:102BC000FB4EE39B5C8F3446B88CDFAF1E1FD14BAE
+:102BD0001487AD64CFDC2EA1BC207F97E485274607
+:102BE0005E001490FD7FBB34CE4BF46EDB1FFC09FE
+:102BF000B5F734D9DDBB7C1C1FE1B84903D205D938
+:102C00000DE014EF2FB439D80EBDDE27FCE9C35513
+:102C10009F5D4BF66B2EA47A5106127FFC9EE22636
+:102C20000B4C69ACFFD7661FE0FA7BEB41E48D16D5
+:102C300087EF277F75796AAAB08B15EC8FF5A319FA
+:102C400066AEFFFAA2C0FBCC8F8561CE6F2C1F222F
+:102C5000E279E0898C203EBC4DF67F58CC7EBC3BAF
+:102C600040ED8B33D0DF46FAFDC0AC4E34E1FBA320
+:102C7000F7645C6541BC7F90AC7E42164D8E2FF5AB
+:102C80002AF2333FB009FE9DB0E7EFCCAFEF9924B5
+:102C9000F6CFD5274C1CAF0167C456877ED8E69186
+:102CA0008113347F8715ED49A7785E3F211A973D40
+:102CB0006AC592F83F49945F148B3CE4BF8A85FD56
+:102CC000AB97430866F87C8256CE94DAC750FCED89
+:102CD000D8363B90DCC2F915F2B7D4A7441C7F70FC
+:102CE000867F0908BCB8D7E17A3DF9F271E23F8FDF
+:102CF000847E2DEEC3EDCBE571F5782E39B0A9D8E1
+:102D00007EE471FB4EC25FEF7A0F8978D8C7EBC7BC
+:102D100073BC5BA713B7862FB80140B40FDB49ED36
+:102D20004B5F38F20EC5E7FEA338E0F1E1F80BCDBA
+:102D30007229C9C9A5A95D1CA71BE393F93D5C2FA6
+:102D4000EF17E5560BFAE2B0D411E1B8DEA9E2F7CD
+:102D5000FDEDFFE36F766F29E478B53C91E48A3EA0
+:102D60002FAE638C2F26CEAEAF233ACEC0FCA3C7C6
+:102D7000A1F5FA9FEF5F3746CB235CE74FA097A7FB
+:102D8000E9746C4D1CF79FEF13F88DC74FD145C107
+:102D900010C7F3DCE06EC6FA6C0D4E1F5F89FBE1D5
+:102DA00078883299F0BBB4DEE92538EBE30FCE80AA
+:102DB000C0CF079867C6587F0DEDFFE6A0C813E89F
+:102DC000ED487F22CEB93E85E975E9D36FBDF33D6D
+:102DD0009CE5A69F4C2826FDA1BF1F0F6784EF1816
+:102DE0005ACF4249E4CF10BE75347E7C7EE06CE160
+:102DF0007A34A79BF5C2D19DDF09D1FA8E6683DBB9
+:102E000084FCB8F4C95FBD699A4874E20C4B58C29F
+:102E10001E63FC2B5E4FB9217035C9113BCA11B23C
+:102E20006FECFA7BC32D86F766672937FA585F2B5C
+:102E30001B481ED955E1AFE507AAB8BED22AFCB59A
+:102E40003DDD6699F87B8F0542A4C7571ECC50C95B
+:102E50007E5C8976077B3A05415E2F24A31F949EF2
+:102E6000C06E307965AA57A6056E277849DF98713C
+:102E7000DF23B9517F54D797259ABE570AAF6BA667
+:102E8000F17D5A3C10ED4C8E77964340B323B43815
+:102E9000DCFA031C87D0E5B60DE63B28FEB32E73A3
+:102EA000A183FC431987E5F89AA73E0D06B023D706
+:102EB00034A2A4BD285AB7F6E3C7EBE703788D83A5
+:102EC00069BB40C21ADABF7A20D24276CADC177BCD
+:102ED0009EC5B26DC28391D5D4F6C54989EC4887A9
+:102EE0006607703198D629DEB30D5F7BAB09F567B5
+:102EF000B2D7024762F4A00339FF4881362FD903C5
+:102F000059BDEDBF25BCF5B78FF3556E40F81C19C0
+:102F10003D40BBCDBB3811BFC7C32B49C36F52E186
+:102F2000AC0FC9E04D82987DB3DD135397A2F02218
+:102F3000D54DF8B746DB959309F297675A12DE8FA5
+:102F40005863EBE183EF19EC8110AFDF6AF183176F
+:102F5000F767F360BBE11C86AAC5C191804B357A47
+:102F6000603638F5BEC82EFFBFB52F1AD73FF8829E
+:102F70005E9F7A81AF2F7C81E317EA2E6CF829756A
+:102F80001736FCD40B7C7DE10B1CBF507F61AF4F2B
+:102F9000A9BFB0F1AB5EE0EB0B5FE0F885CB2E6C28
+:102FA000F829975DD8F0532FF0F5852F6CFCAA6CAB
+:102FB000073A2B81CFCDA6B7984374CE46AA0973A2
+:102FC000DE384F058E47A7AE07CE57ECF20A3F4AD0
+:102FD0008FD38FA52164F45BACEE6CF2AB77B5DCDC
+:102FE000557D038E73220B174FF9FC9CD7151A677A
+:102FF000E74CE0FC85B3E5FDC314FFCA85B0379C00
+:103000004B713509C23176E935C11408C7F813751B
+:10301000CA2043BDA47BA8A1FF8D5BF30DEDDFECBF
+:10302000186F68FF466BB1A17EBD5A61E86F87DCFF
+:10303000B602CABBB658BC9407B3D0DECAFBC20DF9
+:1030400076DBF83D05FF911F938B9E50EFB8B88F4C
+:1030500074D56618D719D77EAA7C407C3EA1A654A9
+:10306000CB27F47EBF20DE07B72761DC53CF27E8EC
+:10307000F81C6349627C6D5245BE69DD4CE147CE68
+:1030800068719B286FA9E36F3CE83F6E33F99B0F93
+:10309000350A7F5287437A48AD667F74B7A08FB1F7
+:1030A00035E6109DC39D293993699C1092B41BDBB2
+:1030B0004335F59CD7D4E9607CCDA239145F6DCA45
+:1030C000199C4DF184DC1A81F7E5FB8CF8A6B42D30
+:1030D0006D29FD90C4EB4C6FCA28A2BC5D1FF83F60
+:1030E00022E0A99F334F8F83EFD89011FEF1F8397A
+:1030F00053F8AFFC92F0B7D5CA5D69140F5541A6DD
+:10310000F8CB733963CC0C87562FE3A116BB113C67
+:10311000735B81F33AF174D7DE08E19A183ECDF57E
+:10312000861582EF4CA9B09AF909DF1D027C1A942A
+:10313000F3EC3B5B459E16CB641A1FF6C943099F0F
+:1031400021B59ED7BD6BBD2D99CEED7DD664063AD7
+:1031500017BF2B571E4AF9AF5D4F98E6C79E034233
+:10316000ECDBCD59BC0FBBB98C4B8B2815AD048B58
+:10317000680F4B541FB1CA1C874F55A2F6F4DAE40E
+:10318000B8E78A89FA6F28CD63BF344DC930E0CBE8
+:103190005A66E46B04E32B85280747D2EF32D195BA
+:1031A000A093D06B526835C7517A4C8B896EB4733B
+:1031B00015E96BEA81F24E4D39DF9ECF72AAC9C67E
+:1031C000708755822EF4FC9FB555D0613CFDB8BC8C
+:1031D00046FAB14AC34D228F25F8445FC74E459B3E
+:1031E000375B0295E59B6D28F181356E3C3B0949C3
+:1031F000922B1EC17F4EA8077ACF5966E77C3548CF
+:103200008719FFD629008362CE23C4AFF794EBFC65
+:1032100092747EF01CC9999D35E2BCEABA35E27C15
+:10322000E389E7859E98D1EA36B3BC0199E50BD2D4
+:10323000C1DCEC52717E88E0D9AEC91B3BD4A551EC
+:10324000BB4EE7B3A4E155B1748E72E44517C9B320
+:10325000172C1CCF5C6795AB6FA0F672BB7B35C398
+:10326000B3B088D6ED6B41B943F1C26E01275D5E04
+:10327000C4C3AD0862EAB9443A89E1D89F3EE893F5
+:10328000FFD7E1588A70CC3F7338DABC42DFA6978B
+:10329000097DFB5CCEB7F955F721717E265D0106ED
+:1032A000DA7155C07596F45198E4CB2605E50BB656
+:1032B000D76AEDEE32214F7438E78925F6CA934D6F
+:1032C0000B2083F8DE4D7076125CDF67FDDC512247
+:1032D000E00C10E13C67AA22F8649D15BC148FED48
+:1032E00028777A292E98A768F06DD5E065025322D9
+:1032F000F8CA71F04D8DAB9F297CC74CD1E03B18CB
+:103300004ACF06BE9B525205BF8D12F0B13A237CC4
+:103310007EB935D7E25D8D74D8958BF0C6F6D6D7D9
+:1033200004BC7FA8F55F3301B8DE9AB9368BE1950E
+:10333000BB288BE478ABB543A57C552BD11F9FF3FD
+:1033400014E7BF5C1A5DCF44FE5E88EFAF45F944D9
+:10335000F9C6D4B28083C66B2DB480C4FBDFE64DC2
+:10336000B47F87CF669083C3161BE19A1207C7A468
+:103370002FC9FF7553BE1CFFDF49BF62BF75A39104
+:10338000E538DF1872109C6C657F71101DB595EDE6
+:10339000E2BA0CA1D63CDCFF1D4E6167B595D50F96
+:1033A000780E6A972617428D0E2EB737BA51330121
+:1033B000DCD598C5F58E4699CBF6C6022EDB1ABD34
+:1033C0005CB6369671B9A651E1FE527951157F0F60
+:1033D00036876915DC8E4FC061EE3B5F7EAB518F47
+:1033E000E5AAC906B88F6C30EAAB41B5467D95AE0B
+:1033F000E419DA5DDE7186F694822243BD704AA03C
+:10340000794A099D8B9A6A78CFE6A936F4D3CFD151
+:10341000B59589EFA174B8E97AC9A9F1F73A6B2497
+:103420008BE2D8CE32C19FEB35F8B56AF04B5680AF
+:10343000CFC5D80E49DE1010DFAF65FABE03713874
+:1034400004E1D295738542F6419B2CEC742B887372
+:10345000BDB62CBFFA0D7C9E847A8BF2B6B6F929E4
+:103460002C0FEEF038BD748EB6AD6C859BD7E3158E
+:10347000E765DCF82F519C3FFEFC8C6394F1DC8DFA
+:10348000F514E7171F9C12FF3DAF46A7951909E5F4
+:10349000471FF9DA9B5FD96FC8AFB46BF9157B3F53
+:1034A0007248D74F7ADDA9E55760B82F61FFA81D94
+:1034B00025F2071B292E1F937F705526FE7EF3B938
+:1034C0002912AFF3E01499DF7359BA81E474AACFDB
+:1034D00018B7772967363FFEF83C8349FE02CBA533
+:1034E0001B92030789EE9447847D92345CE86D1B40
+:1034F000282ACB2510F90EEE6FA252E4737AE50B61
+:10350000898618BA73F6F16745DE833EA320FAB1C7
+:1035100044DF3F27FEEB99962D8D03E77F5AFAC9CA
+:10352000FF7C3E45FF3E0C7A3CA500BA6B8EF0FB5B
+:10353000BC1FF885095E2DA64DB57964E7F92C5EB0
+:10354000C4005479E57D948F5CA3A4B25E5FE395DB
+:103550003B890F8F2B4E2FE16363610D59F090343F
+:10356000FA59D63F2D74BC26060F7ADE0914A5BB86
+:10357000468733E9DB82DAEE9A18BA583F610BE7E7
+:10358000EDDABEFA20E7F3DAE6FE94F3796BB3677F
+:1035900015505E38C93BEB43CEA3424C5E8AF447DC
+:1035A00081317F77F2A4A8331C28FEA0E5F9C0631F
+:1035B000CCE359647F743D70EEF104C385FE018B4A
+:1035C000C2DF13F4A56FC1D77ABFFEF940D5BF2B78
+:1035D0005D4DE77F5B3D428EB682F7CD00D55F92B1
+:1035E000BCAA4CCF8BDEA4F3A46B875B182F6BB304
+:1035F000EA5B85FD2EFCA556CF6A961BF1FA9ACEA2
+:1036000063C6CA6B3A8F192BCF5BE5FA01F5717669
+:10361000C01CA7EF8DEFE7048D7A477F2F29EBD2EF
+:10362000576B62CE43ADB7F81D242FD678EE320526
+:1036300062E8F9474A606E5949B46ECD9ACBEFD92A
+:10364000737C09D7355B51EACB3279FF03DA019BF2
+:1036500035B9B845D32FA7DAE756ADFF8FB4FEDBF7
+:10366000489F5F14C5CF98516393583E5F22E43161
+:10367000C13C76DEC2B2C0E2D87D10D3F4C205E907
+:10368000744CE1B824B2379A2F294A223CDD3D67B9
+:10369000E0F5E87973BD9F9E278DCF9FDB3C6603E5
+:1036A000FC7795897322CFBA1655FF08417377AD21
+:1036B000A0A7E64B845E1EF388D8475F3A34AEF786
+:1036C000EEDA81ED9FF8FE1439ECA513AE67C4D590
+:1036D00087C6F5CF8B6B1F17D75E14579F1AD7BFBE
+:1036E0003AAE3E3BAE7F7D5CFDAAB8FE0BE3DA6FDF
+:1036F0008E6B5F1157FFAE119FBEABD212C1311E50
+:103700007F7ABFD3C5DF6F7D553F23FA1E03054C7B
+:103710002F3ABD9D2E1EA276AE97E9CC56366E1F6F
+:103720009D8FBB0BED2BB287EEAEAD760BFB22B0BF
+:103730007AAF461FA41F2C5F15F374E59426B13FA2
+:10374000ECF418E4C8A9F06D820C63BB12637FE649
+:103750009D7B7C9F9A3E439A7E1C78DD3A1F174ED4
+:10376000F1BF43708790F02F75BB76A72AF867A743
+:10377000BAB07A33C9DB56B3882F6BF79D64D0405B
+:103780001C070F684A3862227CB712FEEDE4070876
+:1037900079B25193271BC83FC0E749A3825B29AE8A
+:1037A0009B7C888FDFC07A5FD1DF16127ECA4B7791
+:1037B000D2F7611B26943DFC63ACBBFE2141B818D7
+:1037C000EDF3896D0AD92C1D4A46129D174A3139ED
+:1037D0003AC93F5C53DCE11F85FD36EEFFB0F319BB
+:1037E000C4B39C65F326615DB6F49888DEA0D0CBA7
+:1037F000DF9DE13A55F2FDAC953D8D89CE956E9CED
+:10380000ED369173985E2B9B557A6F4AC0548EF0BB
+:103810001BD90A663A479CA186F9AC4D75B9CCF222
+:1038200065D713C850BCDF9E6C82D767EB6DFBA9D0
+:10383000DA3F3E40D2E2736755EAE3A409D2A01F03
+:103840008EC3C816ADAE6EDB46F78F3825511FFF0D
+:10385000C48E05AB0BA3F5EC27760CA77A7BF10899
+:1038600013C9D3744F6AC27B60A6970BF9B96BFD7D
+:10387000A2918101E84B267F6D0896855A4934351F
+:1038800005CB515A296BCFB3447D0AC10DE12937CD
+:1038900068ED1E519EEB79E2C757CADDBA9D38D458
+:1038A000CFCE3F143A071BECC5E9E599FDDB8B68E9
+:1038B0001E739C7687551E4AE70477ACB701DDEF8F
+:1038C000B02307C477C66B6C7C2E142CEEA157B8BE
+:1038D000A2EB0EAD19CCE7CF432630C46F2DE5C265
+:1038E0006E3D5E6ED2EC9E2FC2F49DDE0E2D8FB328
+:1038F00003226E8AD747F1FCF0022506CF0F957F91
+:10390000BA8DE8B32B6751F5167C6F538B99E3257D
+:103910009B5AF298CE691CB28F4EAC7AC54CC1A5A9
+:1039200042E834939D3F8EBEACCEA72B8E025C76D0
+:103930006AF2F967C49F38F16850F8F908E861E065
+:10394000BC511AB89EE0924FA24D22FE91CD0E9C22
+:1039500067D993E95589F4F62DE5BDF6F8624BA9D0
+:10396000E65FC80CDF5BCA13D8E374029FE38D8A5D
+:103970007F29B53BF71D0C0FC3EADE378CF449787D
+:10398000AB8FD133AB35FA747BFD0AE1707669E019
+:10399000DBF4FEB2AD7F3B40E6A8ACBACDF4FEFD51
+:1039A0001ADE178583B3689809DE7035F51FDFB01E
+:1039B000733FC5D10A82B7560FC1F58D51EAAA3DB2
+:1039C00044434AA091C619D51DA97261DDB9F560BD
+:1039D000389BD73391C7CBD3D783F450C774E41641
+:1039E000F17B0DBF847F3A97BC689B800FB667F36D
+:1039F000FE2CEEECD8F5EF9C8974E1EC4B170DDA58
+:103A0000BE3647E10856A35FB339111C753AD5E1BC
+:103A100071ED233D6B2897B920D4FD1CC941FF5699
+:103A2000F74C2ADDA581FBE87D5F87BF99F37C7B9E
+:103A3000BAE9BAA15EF838956E4A1B613F653BE171
+:103A40007DC7AA23D51C97D907C2DF89D3877A6996
+:103A500055E2F30BE23E9C49FB8C7632D2ABB2C509
+:103A6000134BAF66CE5785347D126A45FAA5F956D9
+:103A700009FA0DA92BDC89E8EC414DAFECD6E856EC
+:103A80007F3EAA9F73954F97EBDF9343966484E73D
+:103A9000D303F17D1A78991F900FF653BF0CE20300
+:103AA000AC8F5C25333DE87CB06CDFDF0E0C637FB0
+:103AB000522EA2FBD9F4795FD2E645FA7C91DE5F03
+:103AC000B6B5E700F98A235709FA7C95EE06CB8C48
+:103AD000D219FA8FBFA17E3AFDC4EFE3D71A5DB8C1
+:103AE0004BFDAF121E176D0DF278C83FAF31FF6C62
+:103AF000ED0E2731CB29D5B49F1D1DE0A6FDD8BF03
+:103B00005FD44572E1448389E17A5D61788D19CB98
+:103B10006B468195AE13AACB42B2C9A33CAD31EF3F
+:103B200037BAC3883FA49F3FD23C259E804D04AD49
+:103B3000833696A7FDD04554EFA93AFC57C5C9DD99
+:103B40004F0694BBA739EE774B954F699CD35EC760
+:103B500069F6D3E34D7DE3A6E39289AFDB5AEBF53B
+:103B600038552DDDB7B38BE2A608D735AD03DBABF7
+:103B7000218D7EB76BF47B971637EDD0ECA23B4ED0
+:103B8000376EBAFE5815FBBFAB80E340AB53269AA5
+:103B900012D14DAE6AE4CF910DC9717152A3FF9A53
+:103BA000AE18E3A6F49DE799C44DE3E3A58553025F
+:103BB000E3A796F48D9B42E45D839DB9A655C805A5
+:103BC0001D7E636A6EE2F8E72E8F3914FB7D845EFA
+:103BD000B66B70D3EDC936821BC3B3408B3F7B35C8
+:103BE000789669F0ABE5FA18B2E23C1C471579F714
+:103BF000B177CD5F4870CC02CE1234E53C9895E8A1
+:103C00007C3D64C5D8D148FFEBD66B79B42CE0EF8E
+:103C1000439FCB79BD369FF29A59668ECFEEF2EC78
+:103C20002FF831D79399EFACA07614E07C63DE9B3C
+:103C3000AFD27CBBCAEC6E711F07A4521E48CF4B9B
+:103C4000E8F99CB64C91CF711568F99CB8F9ED7004
+:103C50007D7507CD5F20FC977EE9D9A7E523B43CAD
+:103C60005046A1315FE188CB57C4E72BD7AD5FB891
+:103C70007F9788B3B09C1E73C3D864BFABEF3CEE94
+:103C800039463F6EDD58DD9F7AD091089EA93546B2
+:103C9000BA6CD3F0DE9C29F211A71A1F2A930DFEED
+:103CA000555BC1E9C513F47EE48FBA13F48FF7476F
+:103CB000CFC6CF75F3F8C63872023F77C354115799
+:103CC0006179B26EBDD87F6F5C4DF3AFF47346FA85
+:103CD0003856CD9FE37A6E545EE9F9B0516E1BFB06
+:103CE0006BA3B47BA19AEF4D09ADCEA5FCDADC1E27
+:103CF000CA478EDA2D71DE7D94D33F94E2AA5DF738
+:103D0000CCE2FC78767260C7D498EFE076BBBE9DBB
+:103D1000C579032DEECFF7E3A0FE533715772B645B
+:103D2000F78E05BE4F27392E2F107F0F4E9FFBD8E1
+:103D30002A841ECBBA1A12DE6FF2BBA9426F46E587
+:103D4000AE3F59F8F1B3194E0F74D4270BB9ABE855
+:103D5000F501FDE073256F1FE87885BFEB39E103BE
+:103D60004DDEFE0C2E4479FBBBB2C05B09E5ADA570
+:103D700087E5ED235394B709CFD7D3851E8487EB0E
+:103D800012DFC3E3AAB850F1F098C043A18E873B7D
+:103D90002091FF7801E021B922111ED0BF2278A91D
+:103DA0003E25A52293E2A68A93FAF5E2E3EB89F990
+:103DB000A2E23CE36393868F3BB5FCED460D1F1BEF
+:103DC000081F76CA570A7CACEB838F23021F653A23
+:103DD0003E9E3E2B7C64D46418DADD95467CA4FAC2
+:103DE000F20C7567A1111FC9A38A0CE35D5F218BDB
+:103DF000FB90864F35F4EB8B0FA35F10A0F706F016
+:103E0000B38607BAABE81BABA1F33BBB483667F9F7
+:103E10003BAAA8D4F7B92DCEAFD3CBEB35FC65CDFB
+:103E2000488CDFAF69EDFF2E57E656C4F2E7571214
+:103E3000F3E7E59A1C0D9429F30CF47369E2FE573D
+:103E40006BE37F7D8A72556C7FFCD92CC5D8E5FD6C
+:103E5000EDFB8664E57A7A2F6B86CCF1D4DD4DA933
+:103E60009C3FDB9D24F2656A93D3703FDD48FA0DD9
+:103E7000EB59DFF8A24BA57376741F105A583B6FAD
+:103E80001D9CB70E9B76668C594D70FC56453EAF17
+:103E90002B7F89FF6DCAF328EA51933887B480EFEE
+:103EA0003532850799E83E2C70679C561E09E599C6
+:103EB000B8BF6D2488EF8521C87A50F2433A7D9FC0
+:103EC0006C01BFC89B537FF11D216F3E05C25C771B
+:103ED0004184EB699ABFB7AE2297C74D07D92480BA
+:103EE000E435911CD5F9D4E10932FD7B1ADCA6D565
+:103EF000E4D3599057C91F740EE7EF76A11A54CA3C
+:103F00006B99C0C1F6A669F381CF395FA77F67F8C7
+:103F1000C220F19DE169EEEF74FBB5D0FD7B9EE818
+:103F2000FD7B2D9A3DA0DFBFA75607F93B7275B503
+:103F3000DDDDECE9FB1DF9E6A9819D44877F4F1A81
+:103F40001112C9E6E0947AD7391DFFFF9CE7F19F73
+:103F500038CFE33F47FCD0DFF81BE8D772CAEFF950
+:103F60005FA07ECDAE52B63BF5321E6FB3D1FFA738
+:103F7000F54A8E5787BE37286ACF390F9BD82F6AEC
+:103F80003689F367EABB26B6BBA050D08153868240
+:103F9000DC49D1719CDEE048117F127198A6DFDF09
+:103FA0007E11D9DF3F4C991B49C3F15E3E28EC3F9F
+:103FB000CB8CC836BAC779489ACDBB0BF9EE0E6DDB
+:103FC000BDF6F22977DE86BFD64F376BE71CBC976C
+:103FD00014F1B9A53911B21F5DA516997206CEB8B4
+:103FE000FC66BBA583CF19B7EFBEAB6A1CD039E521
+:103FF000E7DD2DD6BEFB746AF9CDB1526239F89770
+:104000006949422EF98CF7061FABD0CE41A5422A52
+:10401000D991967F2B6989CE05E8A53E7F892752E5
+:1040200043DF5947E8B236C47349595D52B287CF6E
+:104030004774137CABBD6107D9BF0F2F0CDE14FB97
+:10404000DD797B19B8C88ECF9D2ECEC3DEA3482E56
+:10405000BA47E3BE8885EF17BF6FC963EB53B0BEA5
+:10406000EFB0D94DF068F7BFEB4CC6FAC3382EC994
+:10407000BB97778B7B26D505101A8DF06B27EF1237
+:10408000EB7B15E073C0EC90956A57F221FCDFB929
+:104090003853C01B8275743FE7A6948BF9DECA9C27
+:1040A00079222E3C4B3ADC45EFDF576667FCE56B27
+:1040B000E7754C6A1DDF5B99B9C0785EE7BE95DD98
+:1040C0002AE1D75D6E77D33958909CAE89F8BEEB64
+:1040D0002766905835F6F0E4B324A75897579CA369
+:1040E0007B580EAB74AF7126BED7E4E6DB110DE74B
+:1040F00082F66E15FE69DA64A717291DD71B776E45
+:10410000485F5707AE8BEE37768DE2B844C63CE386
+:10411000FAD2E2FC06675CDD5BD97B5FCF18C2F7A1
+:1041200071FFB78B5FE556AF9CC8FF6C6F84EE9A4A
+:1041300098F309CE7EE281975F2CE8DA96FDAC8396
+:10414000EC94E3FED73D848397FE75E03D3A2BF770
+:10415000D2BF5FDCB31CE1F39BCFDFDCFD28EDAF0A
+:1041600061C32B44AFBA3FC66730713DCFD5D91874
+:104170006EFE5AED3CA7AFEB59AB8FDB39CFB47174
+:104180007F12B78FAD845012B68FB528D9DF24BA0D
+:10419000EB96BC4D320D22CE23EAF8DF78ADDF047A
+:1041A00013088F7E89EEBD9829BDA4B8F0FD7B96DB
+:1041B000804CF8B72DE9E4F3EABE95E2BCBA4FA90A
+:1041C0004BE2F3A6F3CC7C4EA4A9EE8A4B46637D6A
+:1041D000CF25E21EAADA95CA953CBF22E825ADBBE1
+:1041E000D4BC92E8325BDCCBA49F372D811EFECE7F
+:1041F00063ACB7B3CB46F266010298D6D7AEE14BBB
+:104200008B1B94F8BA55B2275D5E231E33E2F0167D
+:104210008FD79B743C8E85B18447193A92491FDE33
+:104220000FD049F707DCB3F2B12BE95CDB71358DB8
+:10423000E1D51F3FBF83F6AA7211DDB7E2E0B21BE2
+:10424000ED552AF7A0BD4AA52B5875F54A5CF7E352
+:104250006FBCFCFCD771BAB94ADDA57C544BCB7F4F
+:10426000012C1A518D70BD96B857D4B72BA300FE00
+:10427000E0930CF58D1E4BF4DE7FFCD595ADFD1D56
+:1042800000F5C4764A40B66759B47C9BA8CF253F59
+:1042900024A67DEF1C63FF8AFD31E357E27A97DAAB
+:1042A000B87D63E5A2EDEAA868FBC7D3B03E1CE089
+:1042B000A0663F5EF380D9BF2B817C7BA952D87169
+:1042C000967F834A72ED5319D8BF97CC0ACB77C833
+:1042D000B3C889EECF03407918EB97CB46F95AAAB9
+:1042E000F185C55F055A9E0CBED0E30FF8F3F8EFD9
+:1042F000E6F2BD4B6BF22D7CCF10EA03EF40793B29
+:104300008BC7F297D8FBB97EAAD3C168184DF37F4B
+:104310000A95BFAD623E88B99F01D73DA3E399617D
+:10432000CB711EDFE1648EA74AAECD29344F4B63BB
+:104330002BCBF31F29813D9531718A96F445C52415
+:104340005FF4F332D1FB8DAE309FC9FDF65D75078A
+:1043500080F4C2A7485AF601E8B0A571DFEBB48E2D
+:10436000B58D9D5C3ADD0A0B1BBB25C8719FD94AF0
+:10437000E0C5CA12BA570FDB63F8C4EAC6F70C7E71
+:1043800087F1DE4DD91D7112DCEF29FBA393E66F97
+:104390003F24F8FA9E43F57C8EA1DDFB4A12F1CD55
+:1043A00071BAE0F14BF0894F39C8326CEF1BA9D7D5
+:1043B00010FD3CDE9CC676C5CB2BEFBE8AF8E7BA73
+:1043C000EF5FCEF0EEE51BF5DE11D585317CA3DE87
+:1043D000CB74DDCB375ABD7FBEF944F0452FDF8863
+:1043E000BAAF100CF597E718FBF7F20D8D8F7CF143
+:1043F00070959DDB3F7DF25E03DFFCE1A97B8D7C48
+:10440000F32DE49B0472BF789A46DFE7986FFE3184
+:104410004DE3C7F3C437E9D3B473B55F9E6F864DE0
+:104420002B391F7CF3B8E96CF866585FBE993CEDF8
+:104430002CF8A6DD1DE67375EDF3CC09FF0E487769
+:10444000A5C0FB8C0581EA0EB26B14714FDF4C697D
+:104450004EB6CF437C26D15DD1A83F853E7FF99AE9
+:10446000DEEF33583FFB353C6E2684929DB454D02A
+:10447000CDAB8D22EE3B5372CE5C4A7A97BE23A021
+:104480002BE3E698B8DF65A8F765B20BA1D3948952
+:10449000F3DC83EABD43A62D07EB46F3F861B6CF04
+:1044A000F2B53C80532A14DF3329E2EF5BE8DFC525
+:1044B000CC9B63BC4776C829EC261C2085FC18776A
+:1044C00099F87B2757EAF4D3AB7FD10EC1F5750F6E
+:1044D000B7319DDCA35C36609CA8CFF96A5F306180
+:1044E0007EF2C0349320464559342D93E4CBF664D4
+:1044F0003A2FF1B8047C4E6741F0E75712DFB95408
+:10450000216FDA57FD89D292B067E6D78D7A5A8D3E
+:1045100018F5B41A31EA69ADDEAFBC81F78D7A5A6D
+:10452000ABF7EA69ADDEABA7B57A54DE440C7A7A14
+:10453000F55391ED6A4CFBCB54AF3CB59EEE9A76A9
+:104540007EF4F490F3ACA7779C3B79F3F0F99137C4
+:10455000AF9F95BCC9E92B6FFEFB6CE48D6B5B973D
+:104560004AE99945FDF0C137353D73A042F9158DF3
+:104570000F65A717AF89A7AFAEBA456BE9EFC77C48
+:10458000EA15FE5F7FEFBB1A7EF17A4B8C1FAE7F80
+:1045900097E06A789C9FDFB8ED20C7634FB95EBA99
+:1045A0000834B3AF5E45BBC8C1F4EB35734EFC6C49
+:1045B000D7D13E4FF05BD9B4C5CC4F7FD7E28FF156
+:1045C000F66F579DCDCCF3950939DD9F3DD4DFBC07
+:1045D000DD95B2E1FB0C7DFE78FA45FAFC37C9297E
+:1045E000A4470BDDFF7DBC1BF8EF51FDE7B12DBFEC
+:1045F00056E40B4A2F7A283470A6745AACE133C1C2
+:10460000BE732E2E399FFB3E67FC597C36FBEE9A1B
+:10461000067A5C3B7EDF95E777DFE7CC7FA8BFF8C3
+:104620002CE4D24B95BDFBE6EF5232B47DDFF3AF05
+:104630002BDEA5B8C63DFFBEEAE714D7B8EBF38280
+:104640009D14D7D0EF8F4B83E88FAC7F1F8970719B
+:10465000F9C5772519F362BE2F02F6EFA3DF9F900D
+:10466000BDE1EB6DFF7F727F1CD9274712C4197B18
+:10467000DB6DC6B89E5E4EA53FAA85F4D56EDAC442
+:10468000F1887BD0AF6A42BC75CD13F18876B45304
+:1046900058EECC2B1AD03EDAD3A870DCA9BDD1CF0E
+:1046A000E59D8DB55CEE79755905C95DDFAB4B585D
+:1046B000EFF9BCFEAB7F8C407257BDE7A4E7777A79
+:1046C00074FB44D82F6964BF60BDE3E9B61DB1FE39
+:1046D000CD90E939AC0FF4785547568CDD23C7F8F7
+:1046E00051582772E9F5A3A83E2AD6AEC9613F6AA0
+:1046F0002FD93558BFFFE91C835DA3CFB3D10C8BF5
+:10470000C9AED9B8DB5C9BC8AEA9A84CEC47619D8B
+:10471000F3200E9783BFFF97B4BFF315E59781EDA4
+:104720009AB4E9E7D78FFAE5C5E726FED0CBC79A5A
+:104730003DF323457956932B5F527E6C3153FCF841
+:104740004CE5C758921F8506F9F1F6D9C88F8A4AF9
+:10475000B7212EFAB2AC0E9A4876FA6E3334C99A63
+:10476000FEF5907E05FEFB77DFAA92D8CFB9C70B86
+:10477000FC77FC66490B5E207AD8BBC4CCDFBBDF7C
+:10478000A7887322F7CF13E7AA7EBCB2A89E3E2764
+:10479000DA9472ED86248A6B575A80FACD922A39C0
+:1047A000CE7D5FADB073729C9D97D0FE5FAEB200C0
+:1047B000D1D5A9E2DC146EE778B57E9E4ADAC67ED2
+:1047C00087EBEB16379D5B8D8F5F3BCBFECCDFCD50
+:1047D00083F4127FDF7DAAF8F599C6ADEDD37BFF98
+:1047E000CEC0D9C6AD991F2FBF38E75AFE0E218E15
+:1047F0003E9FB958E64A7F7A2C9E9FBBEA66A54544
+:10480000063817E524FB29E6BE58A725CC7454A129
+:10481000D9514EB29F8AA374D155573AE0FDB329BE
+:104820000D4FBC1E9B174AB174F278290D4FF2F35D
+:10483000CD747E81F665F1B25C7DB81AE57382F1C4
+:104840009E6C0C1E22B8FCB2B1E110C5A9A759BAE2
+:1048500025FABBADFB1A55AE3FDED8CAE59EC60EA3
+:10486000EEB7B9712B97773586F8F99D8D0F717D6D
+:10487000436327D71FCE13F34CB584789C693D382A
+:104880007E0C3F547C80F3C4E0B93CA21ADAA7BC8A
+:10489000D96A682FE9EE30D433FD5B0DFD07D5866C
+:1048A0000CED072A025F9D9E49E71A1E32F473162B
+:1048B000761AEAA7EB2F9CEB7EAB53522DFF447E7A
+:1048C0001D11407A423A4B6F9055CE9B2F167C3982
+:1048D000A4C11BA6FA76978DF95BA74B3EBB6C1261
+:1048E000EB37C5DC47DBE5B2B1BC68CE14F194E62A
+:1048F000EF88FAF66C715E724C8DC88F340F17E733
+:1049000030F53CFC7697C89B9DF0897B3446144675
+:10491000F8928C11DADF7D73568AFC991BDC9C9F20
+:104920006F6E04ED3BC508E73B32C0EC15F7A82BD2
+:1049300032FFDD240B849A70BEE642B77A23C99910
+:1049400060AAD7ECE53F211B32531E91C4132761A7
+:104950003A35BDA3E5E593FE087CEEA0173E9F889F
+:10496000EF121A7AF87EA6210D3D9C8FDBFE7D7139
+:104970008F4D3C5CBBBEFF19DFABB4E33B9F6513BF
+:1049800053EFE83DB7D363F82E6DFBE254BE6F6181
+:1049900047431E9FA3D8B1587C772C83D8EFF625C8
+:1049A000363E87B1A3C16C263979628925A4C33B01
+:1049B000A49F5BA1FF158041BEE8DF73DEA59DEFDC
+:1049C000E9D0BEBFBA433B6FD5AE9D976DD3CE5BEA
+:1049D000B56AE765D7D2F91E3BE919859FEF68589C
+:1049E00021CEF70C07ED7CCF270C670BC299E2387C
+:1049F0003BACB0CF3409E80F1732FCE2BF971D542F
+:104A00009B1C77CECA78EE2A2DEE5E2197D778EEE2
+:104A10002AA5605CDC392BE3B92B7B96F1DC95D5BC
+:104A20005D6D3C271A4BA70854D3AA2D4D4407BDF2
+:104A30007FCF911E0EE6BF17C7FB53280F85FBCA19
+:104A4000AA15743948FBFE259DCE85E493FC0F33EF
+:104A5000BC5D44AFF9746E44E57A92F6FD9B7EBE70
+:104A6000A43F3A3ADBFBFEA5D589EFFBD7CF1FBCAD
+:104A7000A1D94F0BA62BAF4F2F89CEA74E57DE8C57
+:104A8000ADEB657FF2E0FF9789CBFF0532DED6778D
+:104A900000800000000000001F8B080000000000E4
+:104AA000000BB555CF6B134114FE36BB69923669C6
+:104AB0001649B5211536C668031122A6A59588D3D7
+:104AC0001A24875AA2F4E0C1430E39F9E3EE6D537C
+:104AD000158A92D218C173840A160AEDA17F40AAE2
+:104AE000C1736AAB281609B5F42CA87829C437B36A
+:104AF000D9264D36B5170792973733EFCDFBBEF762
+:104B000023CF41CB0F4462EC9AAC0123895AC549AB
+:104B10003214072B4581E92A4937ED2F1A526532A5
+:104B200029808BD98434F574AAA62864A7B6D9A5A0
+:104B30000FECECE2DE18B71BE05211F2DCAE13F022
+:104B4000016B49A9F42C08CC6DD0791CF83D269551
+:104B500010E4C1EDD7EBA3C21490F917EBF79F0453
+:104B600066F84F7AAF7FDC379021FF0B3A503ECF8B
+:104B7000EFDCF172DD9D284C6A144764AB0A85FCBA
+:104B80008D54A19E00C7F78381F6674F5F97157A12
+:104B900077691E3845FB73F65AF22EDD5B1B77A84A
+:104BA0008F62DCCF94FD019D4F0764C85C4FDB77BB
+:104BB0006A142A2448F533C44F4231745A75FADC1A
+:104BC000448B4E714F737DB8A97BF743132AC5F50B
+:104BD000703BB852196EDA852814BE7F89797C7BC8
+:104BE0007DB41141A42E3771D4F9BADA29FFE8DA7D
+:104BF0004AC5CE71C2C6F98A6FD94A417AA7FF6306
+:104C0000B197E393AB69B946F64812EA71C2B99518
+:104C1000F6E2087FDF387F0E605B770A59D55521B1
+:104C2000D7F44121F7744DC85D7D58C81D3D2664F9
+:104C30004D1F1312C8897C3A2488F7DEE8A9CD6499
+:104C4000B8FB7B1129778BE71DAF14BCE6791E8A70
+:104C50000BBB8E7B25F2D3C217D1258AA1E279390D
+:104C6000C1ED5FA46C70907D31A1F9D3D14EFBE210
+:104C70008D492F2CF64D99D76F6F3EB1773F77F75F
+:104C800020B36A61FFB851C74041C41148D8C0EB96
+:104C9000D7EF844BA5FBF97597A8EB50CC597271EF
+:104CA0007C7937BE9B38A87E16EE1704FEA54545D5
+:104CB000A59A3AF0EB89513C2D7515606F0779DEA6
+:104CC000F257CA836992C58BEF3F9F25BBDC868C68
+:104CD000303AE37ACA241197892BA0AC4AAA45DE60
+:104CE000BBE1BAD7B0C790CF980B6DFCB7DF37F3F5
+:104CF000CE112AA38D16A595EDCD2C30DA67CB9277
+:104D0000E0C13504D1DF3D60658EF718F101978968
+:104D1000E7F24826E76EC6D32D4F661C7D8DFAF369
+:104D200067355786E7E11F75E8B61BF92A646DA958
+:104D300092451CCB8D3957601F9CBC1F11B58EC38B
+:104D4000136BAF53239E7985FCF3BC31F26FC1F72F
+:104D500057CEB751CF5F646A81E2944DE33DE421C1
+:104D60006E183DE59940291714751E2BD3F92FD6DF
+:104D70001313EEDBE643C7FBACA58ECE74CE9D7558
+:104D8000E636E64D18613E6F7E0ECD78CB16F96D96
+:104D9000F689C1A339773A79D40C9C590327A2D656
+:104DA000FDDCCCD76C63A823231FAE9B4F47D54DAA
+:104DB00037FEDBEB603E9BF696E9FF01EF5C9276F7
+:104DC00081F371B8FFBAF1D6CED3DE7FE6A9FDBC80
+:104DD0006ACE9563E23CEE3D53FF0BC81D4E69F071
+:104DE00007000000000000001F8B0800000000000A
+:104DF000000BFB51CFC0F0030977F3A0F2BFA3F182
+:104E000057F1A3F2CBB851F99E68FC2634FDE7D1E7
+:104E1000E4591820B4033BAA38B15888838141165D
+:104E200088353850C5F3A1E656012DE805E265AC9A
+:104E300084CD7A27C5C0F05F9681E12890AE06E266
+:104E40004B4036931C0303AF34038307104703F131
+:104E50003B190686A940FA25106F9086E8E3048A7C
+:104E60009D9421CFFD6D42E4E91BC5D4C1B7955097
+:104E7000F993B51918AEE93030A8E941F8E791E4A3
+:104E80009D806253B421EC70550686BDBA0C0C8728
+:104E900095B09B1B0194DF07948FD0C36FBF831124
+:104EA0002A7F8B352AFF8B212AFF9A272ABFC11B15
+:104EB000955FE103A10157D509D0D8030000000098
+:104EC00000000000000000001F8B08000000000030
+:104ED000000BCD7D0B7815D5B5F09AC79933E799BE
+:104EE0004972028710601283440D3884F0147512E1
+:104EF00082C6368503A2E6B7B61EA955449023D2D2
+:104F00009AF6573379125E6D406FE5F779A0DA5261
+:104F1000AB357AB1F5B66A9340BD784B21526B6DD3
+:104F20004BDBA05EB55EB5D18ADA5E947FAFB56724
+:104F30009299C34988B5FD6CBCBD9B3DB367EFB585
+:104F4000D75E6BEDF5DAFB285002FA2480E3F877A0
+:104F50002EC0E92200CC1C2AA373A04CAE04D8209A
+:104F6000048D70312B3F94EABBC2EC1D58F1A55360
+:104F700087BEBB04046AFFB3E2F6783F7BDF31F9FA
+:104F80005B712867ED2708D4DE69E79457820450E7
+:104F90000050DAB95C4DB07E368C6B56B17D87BE61
+:104FA000AD1ED878474B159070BCE2ECDFB73702E6
+:104FB000744F01381736AB2531567F4E323642B624
+:104FC000718A691CA7EE8F8BD05D06F4779CFD6F0C
+:104FD000C3CD4948B071DB267FAB1EE156BAAF01A5
+:104FE0003D02F0957149D0D9F3E920D2BC9439162D
+:104FF00098ACAEEA56DC9A7AE2381D889772ECB526
+:1050000033BE3432F47C898317868F0CBC00CC030A
+:10501000D0A0A2DBC27A00E8FBCC7E4D7B7C2D3E8B
+:10502000BAF14F9C3F1F7F1AE88407503BE389C8C1
+:10503000103C1B7C03DD12C3B7550CC6FDAC490EFA
+:105040001BA7CAD54FE67883F3943B3DEB3F15E1B0
+:105050002CA07908B2ABBF4C7866D9ED66B19963E4
+:10506000E9CC2B673E1FE764FD7F06515C80ED3B7A
+:10507000E356C4458FB2E5C17BD06EAF99DE76C3EF
+:10508000E12784F89989F8B1E2488F0E1D4B61BD84
+:10509000A996CDA7C082012997C8C6843100F9F826
+:1050A0002FF689ACE95548AF634CD696BD1F1BB3AC
+:1050B0009A24F67CDCFCB420B332027769AF84001A
+:1050C000A1293D4E1F599CEEBB6674F433BA3D0ACC
+:1050D00091CE8DAC6C9159BF88B7C391F4FD0CA4EF
+:1050E000A6B353F7F6B37AC492A1B992C6253EBCD3
+:1050F000513ADDD8C8487AA34DFF1D8D2A95ED8D14
+:105100001A74FB015A1BE354DE1EBAE5BBD87F8339
+:10511000E5D7FCAC94BB6E7818EB2D00091C2F1260
+:10512000E3FD83AC6AF76B580713F11E29E5E5B37D
+:10513000881706E7B71826112F3FB6F1A44337F1B9
+:105140006B8BB13407B2E0D32943655E3E0BE84177
+:10515000F6E550DD1FCFF3D47D5AA1A73D4011E104
+:105160008DEA4C54AC10B83C8AC87D60209C0C5F22
+:1051700059E5822D572469FA40379B5F78B662EC77
+:10518000649F6E11BCFC354EE0F4512EA854C660ED
+:1051900060CF71C48B21A637B2B182D34BBABA6348
+:1051A00038A6624C66EB18F4A5B5BC2CFC0595F24C
+:1051B0001BFD0EDC259F3E7E24A92795C832EEBB41
+:1051C000F6FA9D7BECA08AFCAF4E1713E97284D7E8
+:1051D0004AB0C9C3665D1671DE9F1EDC23AFD711CE
+:1051E0009B9FDB41A5F632AE57E5D07A75186CBDB2
+:1051F000907F2AF97A75C8963A9AF57A00C0839713
+:10520000D0205EBA385ECA3F65BCB4F4D627B2CCB3
+:10521000A3DD5E4F190CA38CF0A0E808E7E6264E4C
+:10522000B716A3DB6CF277383C483987E3C9F21331
+:10523000F17EB1C0C75960F38983A70D86589B0ED4
+:10524000239E3A6B516E6D2E1545944B9F169E1CF6
+:10525000B8360EC295E670957DBA7049A1EEFA6C2B
+:10526000FCD89EC18F9B106E4E77B59CEEC44F95B7
+:10527000EE1CB802C80F7C9D137C9DE57F89756E7E
+:105280001F5CE7245FE7F8A7B3CECE7E0EAA518F4E
+:10529000EBB642637CC8E0B856B2942B707F0D0920
+:1052A00070BFC1E800E11FC7F4CC70F3F3BA0E7011
+:1052B0009B10E0FA8674594ED205EF0A99E92C1535
+:1052C000F87CF3A9C911E60169DF40BF0327E3DFDA
+:1052D00086C34DEBF7BAE0BC5988C408CED9301B61
+:1052E000E17C27BC34A71B86EFEFF546B549F601F4
+:1052F000BCDF68ADDFEB3BF1FDB512A4B2E99777F7
+:10530000DA7201D42E85E67F13E3C1E98887536BF7
+:1053100020CAD623DC3C06E70161F6722EEB675704
+:10532000A04976E177B8F90CE2D5F98EA93BFEBC2D
+:1053300013BF1FEEBBBF09C97B0586DFB698588334
+:1053400070A9A590C635F0EF5AD25D08C3C3DB162D
+:10535000FBC7C03BECBAD9EDDE0937B733D30B5AE4
+:105360007CC63E9DD1496B816834C3101C0EBD388C
+:10537000EBE2E071B4EBF2C741FADA7C1E909E09D1
+:10538000BA34FD93D3D53EA4AB33FEF974F5CABF4E
+:105390002E5DBD2E14FCEBD295D220E92F333BA31A
+:1053A0005836B99CD4965BB4FE3836934B52E7F42A
+:1053B0006E94971067F6191F064456573493EBBD49
+:1053C0006000EAAF6AA9574EFA8ABC72325E6F7605
+:1053D0003BFD6ED4715C85C645F308C795C3D01DEF
+:1053E00088625DA17E909C8F9FC2F00477D696F074
+:1053F000EF0CFC6EB8F9C8F81D1B0FD58FE3C5F88C
+:10540000DDE7731259ECDEA1F97BC7892F4BE42449
+:1054100022A36F0F61597FC585F7E1BF93E115079F
+:105420002F8CFECBD04F5230847F73D7F5E4BF086A
+:105430008068905D57D46EE1DBF5F8FFE6E2BECF01
+:10544000F97A7D518586FA16B0FD069F5BC2570139
+:10545000EB7F1374E25B673C299C00A21BBBDDC998
+:10546000D6FF46E4A72CFC7D99C8F58DF76F49FD62
+:1054700019ED416BA3A0DFCFF07AA0F1037889F199
+:10548000E5F2EED314F47B5C2E8EA176CBE7172BDE
+:105490000B5CFD2C076E1702F4CB4B22EE719BB810
+:1054A0001EDA25F5E2BC5F9C23A571FF7B71CE5F00
+:1054B000483F7FD194D288E4173B2ECC1949EE1C8B
+:1054C00068E4F6ACD3EE8029D1FE7E40EE0F67D3C0
+:1054D000E387C64FD3F88BE748DE7D5AEE9771FD20
+:1054E000DFBF197CA83F1F685485972633E317E771
+:1054F000C9E868F99C6205FD0E279BD705B61FCC4D
+:10550000C1AF33CFD6B048F36C0D5793DFAA557BAC
+:1055100087ECC7A3EC39CA83E1E075FC56ADDAD25B
+:10552000ACF850225CDF527CC9ECF6A63D5FA79E2A
+:10553000E9CFFAA4F0B565C0D71EE67A56BB9CCC7D
+:105540006E4F65C0A3C4448F9C885DD625E03E376E
+:10555000168C67A614131A0FA1FF64822D7BC61E3A
+:10556000FE4DD3D50CDE0357844D218EF5DF091394
+:10557000199C5AA1043E56FFB7656B7B7E8FFEBD1A
+:10558000FA10481A836BD96D4D8C5C61FCCDF7091C
+:1055900058DE8A76210A5EEBCB4DE8B76AC54EE746
+:1055A00001DC257EBE0AFD6A327039C0A49C2E8FB4
+:1055B000417F0C9033663879C0FE84E3FEA1EF860C
+:1055C000C353C4964F344F924F4B47964FEB78FFDF
+:1055D00016FB0FE5CBF8A1F1E8FB712B14CF3A8E47
+:1055E000CD78DF6BD3A11F96FC53C729848A00EACC
+:1055F00023913A514B637BE8CA45BF536C950CDD50
+:105600008C6E0A2B3B059F7E72BC333957CBFDC491
+:10561000A6E0E6AB5FDB7268E2D79F1304F4F31AEF
+:105620004C859F8EF586E9D9F8E1DF901EFDAEFA34
+:10563000B26A01DBB5327A2A4539B64C243BF7D63B
+:10564000BAA5B9EEEFDF131DFBD8597FD0E5595845
+:10565000E7EB2FD7896660DADFBFFEF2C75CFF8217
+:10566000758A872F3EEEBA88686B149C7CFD3FE9F3
+:1056700038CEBA9DC81F4DF6BA9506509E6CABCD7C
+:105680002EBF865FB70A01F7B7581D98E92CDFF9DE
+:1056900025C123679D528514186C9DA5E724D24F20
+:1056A000A4B1B3EA77C0F0E34A3125C35EB3FBB3DC
+:1056B000CC3DA56CFD3F07CE5F9F8C72A62E2EC100
+:1056C00046669F41A5EF65B73F84ADF0509DE1FE72
+:1056D000CDAFEDD97B37FA97E6FAC95F9AF9BE0EDE
+:1056E000EB2E7AA891B8FFB4F7B15F9F2AB0710E84
+:1056F0001A7EDDCF1EED17FA5E213F6F9544FB2F1A
+:10570000C2A7CEC2EF81949183A664D6B0F67D95F0
+:1057100002ED9B7E78F68BFF97BE0F517CA36FFE48
+:105720004BDF388B7DFFB9B37DC8391C13F83D932F
+:1057300095807ACCB1FE6F9CC5DAEF3F3B7F44FD8C
+:10574000AA0EE7EBA293C54F78EB9722BDB1F5E81F
+:10575000FDFDAB7577B2F10E424EC28FE51C0EDF38
+:1057600041840FE9BEFFB7AFA01E78C014C8FF7414
+:1057700070CE2F63687F579902E9878BE60B697FAC
+:1057800096792E9A7FFDA489ACBF8411D202ECFDDC
+:10579000FEAAB7379FC5E05DFC1FD2162CDF7A5CEE
+:1057A0002A48960F0FAFF37CB1E97D3EA80743D29C
+:1057B00042BC83C6E310BE981177D3EBA0DE22274C
+:1057C000CC6CFEB59512F7370A9A41FA9C1C56002C
+:1057D000E7315CFB2B87A1DF1C18E896100E47DF32
+:1057E0003E76A1BE64EA897028722289E3489A0253
+:1057F0003B71DFCEBD5877CFFF66079EB849F028D2
+:105800001A8747910D339B7FE9AB363C4E3F009D95
+:105810005417E203D01F1E82AF2D90A8473F8595F5
+:10582000CBFD85AD11AFFFEF519B8EBF6D97AD3EA8
+:10583000C81A470168A6FEABC7CC51B1FF96395CC8
+:10584000EFD0C1207F782BB31361043D6EB3AD77E9
+:105850006CC478861FE31A9A1DD788737D24FC28B0
+:10586000F9C58E968B64C70CD74FC4F0EA43A132BA
+:10587000AFDDE2E82B013D2FC3EFE3F5F3F8C6C837
+:10588000A2A34721BD9E0CFE41BDCE6EB75E4EA9C0
+:105890005A563CA547D4DFFE79F8E3DF877C5D5A92
+:1058A00036B8FE517873E82AB37F255F49A5294EA3
+:1058B0009788BBE9FFD7365D29F96A0AFD9FA00EDC
+:1058C000F73EC8BF0FB3F718BF082774D42B25E0E5
+:1058D000712015F9C0859F3FDBF45F2F8B363FA603
+:1058E00028EE29E829F2D3A9458C7F8413BF73CA17
+:1058F0003FD8E3AEFFF08617883F0A54E20F4167B6
+:10590000FC93651C4B325F9758FB5592F93F58FA50
+:105910003E9292D9F8E44F128FE7AA75095D2DA146
+:105920003822D91F9970F8653EFE950EFC568AE222
+:1059300092A385FFBD51C2EF8CC3E017E59904BF68
+:1059400084E570F00B363C79A037C928D7742E5FF8
+:105950000196E86EBD64B9DD6F9E2D9F00AE8FBBD2
+:10596000F5C02FD8FD8C763E9A3CBAF92C1F9A4F81
+:10597000913D9F0923CD67BCCCD763B9CCF73BB52C
+:1059800026A1C7D9BAE40E4357F364BEDED70DAEE5
+:10599000CBF51F8BAE4E1BE53C9C71D83C66CA9C78
+:1059A000AE668D348F4A1B9E4E09E6BE8C7AF12975
+:1059B0008E7F67A9675D6EB0C7EFF43BEBB2D6B3DD
+:1059C0002ED7D8F818ED7C168C723E370CADCB6212
+:1059D0007B5D1223CDC7D5FE227BFE17DBEDC9EE22
+:1059E000B8419ED28C768625252E95670E8DC7DA16
+:1059F0007D5E2E186AF7E796779BAC30B5BB9CDAD4
+:105A0000D5F2FD8FB54BBAFB032BD28CFE8036B49A
+:105A100015981D53D23AB7DAEEFF2AFAAE6EB0FFF0
+:105A2000ABDDFDFB5BA1D9EEFF5A7CDEB4E023A722
+:105A3000DD2A2FBCA73BED52D84EA81984E37A7714
+:105A4000BB797221CDEB8438C328FD3FBE58B20329
+:105A5000E3FA7910E9C4BC8E7639752FC6FD2D4B5B
+:105A600086FB317FC06F08E8538BCE497D17DBE59D
+:105A70005A7E8DF23FAA530F63DD1221D15249F9AC
+:105A800003941FD020AB9ADFC07C0B03B6B3BA16C9
+:105A900093D39897D326242DDC177F2E2537CB243C
+:105AA0005FB5CB9AB0FF7C9DEBE9D04FFB9603D757
+:105AB000D6D01729DF2197C185FEA7B60CB86E0F87
+:105AC0004DECC1FDF6D60285F464666095A17CB903
+:105AD000510A1AD85F4FC15709DE6D4D3C9F61DBFB
+:105AE000E7BE4AF0DE2600C5696FF3F17C86AD3E65
+:105AF000556BD6B0BFE8B82F53FE438EE6AFB4E186
+:105B000040F83E5B42F0E5835675A540E2AB07EDF9
+:105B1000DBB6390AE9CBDB621555D4DF1C95F4D42A
+:105B2000DB12154DA477CC09924F3E3F6C90DD1AE5
+:105B30009DAD8085F598D1847A66645610735E2099
+:105B4000BF083099002253208D751F747696B232AB
+:105B5000DAC1EC927CEC6F295C8976EF1C8677B415
+:105B6000232CF310DA2561B0FFA4FD26CEDB375ECF
+:105B700002C9185ADF68E7E0F723DA5DD1F428DBC1
+:105B8000758FAE5DA483D9FD3346D1AE7394EDD24B
+:105B9000A36CD7CDDB9DD4DF61707B4F65FFA1DDAA
+:105BA00016C8B067516FF7C4F332DE67C6DF32CB79
+:105BB000CCF8C76BB237AE76B2EF9DB8C7C9E68BEB
+:105BC0004E894138A593B777F4CDE1DE2B8517C711
+:105BD0004DF67DDBB84BE324D7C65DC6CB09F6F3A3
+:105BE00009F576FD52BB7E59BD9945BE17F8F83EC2
+:105BF0005486FE9011D6211FB8FEF80A83FDB880A6
+:105C0000C94A23FB4F32F5DE4C79A7CA5635F2EB71
+:105C1000B604CFEFF02333221F1601F9357D90EA49
+:105C20002C4539016674E19821FEF1994F9BC8CF4C
+:105C300007C64920CCA1F531C87F9E41279974E160
+:105C4000CFF0E77C523A99EAF3C6C9FE5174A274C8
+:105C500048A3E21FA57394EDD2A36CD73DBA76FE9C
+:105C60000E6174ED3A47D92E3DCA76DDBC5DFB5C12
+:105C700085EFE7F058B359CAE09EA77AEAEDF382C0
+:105C8000DEF767853DF5F53315DAFF9DBA7F96EAB5
+:105C9000A9AF6772DEF37E7698EAEBDB7E5ACDB66B
+:105CA000B251F3C97FFF9D7C52A69EC42F3D47CCC5
+:105CB000B0DB32F84AD503F87DBEAC03E64BE5C74E
+:105CC000F83EC5CAAC7EB9BB6DFE4FCB1A95DB64FE
+:105CD0003D80F6E3BFFA3C1B7D1C5E67BE2783D781
+:105CE00091BFAF4AB6BE355C9E470DCFC3942148E5
+:105CF0007998A53566B5C9E492FC0C8F7B65F67B77
+:105D000099927CD8E7B2F7652DC9E379767F1714AD
+:105D1000C8A497C84CAEA1DEA340A2B698E28622E2
+:105D2000F9FBE4F049F68D2297DC2A19016E3B6FEE
+:105D3000955EE90055AFF1718306907C8D403F1967
+:105D4000D339A8F59C827A9A2E007D6F08DC7F3EBD
+:105D50005F4379160BFCA3FBBD8CFA15CCAD703CF0
+:105D6000F431FA95FBC9DFF90FEFF724F006309F05
+:105D7000F70C0A21C4DCF9BCBE788A1EC2B1E3C7A5
+:105D8000A559C03FA1BF24C5D365D1207F281446A3
+:105D9000C92E6B8BAD55DDEBFA575F89378EA6B5F3
+:105DA0005F2F445959B4CAEC1F81CE3FC42018FA62
+:105DB000478AAE34FB47D84F07E397189FCFC207F7
+:105DC000ED4A328DFABB3531CCED7939457EC6F5D9
+:105DD000425EC5C64A17FD1629DD0857D8302DB4D6
+:105DE000F7D6E78B06EAA9326CEE13A6B1EFA43A18
+:105DF0002399458F18FA5E7EDD3D9F3CC5BB4FB6AB
+:105E00009C84DE9DF8E470EF7D8A91CCE60F9DAC1A
+:105E100070BBD617CCFEFEEB62758932F344BCE151
+:105E20007680DFADCF850EE14C4E3E94DF50F4F42A
+:105E30000B8887B682F3E223CD17346F9EE555A217
+:105E400079A65230221C33B2C131DAFC0F8014B370
+:105E5000D186E225A81F096330AFC3F933A015ED41
+:105E60000B667F60DC23586EC07DAC1E5FA026648D
+:105E7000A62F6DA9DC09E8AFF631FD89EC13693E68
+:105E8000D79FCAB83E64B2FF701ED1F923EBD5523A
+:105E9000467DB1E2D59B5B1A1F078CC73BF03B7E6A
+:105EA000BCCC79CD13AB2F520AB2E16374F6F0ADDE
+:105EB0008C5E9872075B1B552ABFD9A851B9A531D2
+:105EC0004EE5A64646ECE81F6D2CA3FABFE1A7738A
+:105ED00091CF531DC50C7F1DF1FB5EB812D02E056E
+:105EE000DB4FF08505A82F6FC43AE901CC0CC4FA4A
+:105EF00004FEFE7A65D102B4F337069CF6D50B504A
+:105F0000AF1EAA5FD45285EF6D3F43877239B5BF8C
+:105F10007502D8E7184CF522D7BE77B7E2A379E02F
+:105F2000DEC2BF3FB705FB0BC84E3D45F00CD63176
+:105F3000E08A7595D77BDBAFA7FE4904B0F1FEABD5
+:105F40007DED02F42FDC3A99FBF961D9D293E0910F
+:105F5000FBF53FC2A02FD2E5B23CCA5F5118DD94D9
+:105F6000B047B7E6DA708FB21F90937CBF7B2EFBF1
+:105F70007E39C43727D9D76C384ECE0FA6ED874867
+:105F80008285E3FE8AF3C53F7BDC5B7D1F0F2FEA32
+:105F9000FCA489DD476BBBBA71A9E729C91F22DDC3
+:105FA000E7D4F4D1B6A2C4BBB9DE30CAF1B72A9A9D
+:105FB0001D8F4A92DDE4E0DBD13FFE94B19EBE9896
+:105FC00049F9478130E7C3D1C2FD071F3FC7E3F45A
+:105FD000030F568C1B49CF8AD589A88C0DCA8DBC5E
+:105FE0009AA0A7AECDCF43236DB01EAD2CF4D4C381
+:105FF000E5259EBA4F3BDDF3FDDFBB5EBFB4F54543
+:10600000A7FDBE8CFA9399F31C65BF4EBDA77F8197
+:1060100058C6D6E1F9F912C5439F9FFFD26D3318D8
+:106020003D3E6FE2EEC9ECDAFA161FC633FA980A63
+:106030005289FB7052B2FDEA3001F1F92BFC171BBB
+:10604000EF97F6FEF7AC7DEE876DBC13F09CD4B3F2
+:106050000BDF2FC2F57BD607B65CEA24B97070B0AF
+:10606000CEE5C2C100AF9FE9DFDE8272A04FE075CE
+:10607000D1BF7D01F73B6E6E3F9FE92F8BF19F6C87
+:10608000FC65F305339D657F0BFB15271F32EC671D
+:1060900078326B4C5F01E6BDE9407AAB1F12A49FDA
+:1060A00035805525A2DEC3E88FE2DDB236211B7DA7
+:1060B0001C6CE4F9027EB890F4FE65F3A7FBD0A84F
+:1060C000F727DE96D14FBA3821F8C0D69B35177C1A
+:1060D000A2299848DF89F9FE9DA83F2764461259F6
+:1060E000F691C5A6DFB35F196C2C84BF4FB0F914CD
+:1060F000B409EEB893E1E7764FBC7464BBC181DBB1
+:10610000A95F38FFEDBDF9E86FAC158CC9D8ADAA11
+:106110004DF862C4DD6FC8891347B0DFE7EBBFC439
+:10612000FD1A8C2ED0AFFACC91AB7D149F5D96EF0B
+:10613000E1BF6575DEFCB6A535214FFDE2F923E729
+:10614000D741D29F21D72CFBFCA548F278E361818F
+:10615000E443CEC48134E667C2F312703DD0F1C38C
+:10616000CE233F6C74FC808EF9A2F0C79076BF4BB3
+:106170008EB666E021B37CC2CFF55B39AF96E2DC28
+:10618000EF1F1174F4A70A790D5370BEB26236E3A3
+:10619000B8ADC5621AE3DF37966C5371BD37947E94
+:1061A0003C7DD017E3717FDDD22A90FD87FB2E6DF9
+:1061B000F2BCB6CCE7D7FA79DCA1CD5AAA9522D3A6
+:1061C000ECD5AA70FE8122C87ABE94D1FFB57EF2CA
+:1061D000BB5BC0E3EC09D2AF4BD5E5947F2B178EA8
+:1061E0001CB7CDC49B6CC70333DB3D68D363E99C0C
+:1061F0009DD4EFFBA78DDCAF83970F0C11FA102E07
+:10620000A657607B15D87C18FE3795F1FCDBD6F2DB
+:106210004709CF9259457AAD4F4B99D86E53F972D1
+:10622000A2CB36D6269F0D9D5BD345E733377DC87D
+:10623000E3140FFAF7B6A05EB1A9E71AC07CCA60F2
+:106240003C0D283F364DBD4A453C6CDAC1788BF495
+:10625000992E72CE856CBF78488334B3A840D6BBE4
+:10626000BA512EC8B56098EC556FBC1A70DD365522
+:1062700072D6CC4FA79A3004B4297EC8C4F8446BB8
+:106280003D50BE4BB0CCAC2D46F8C789240E7448A7
+:106290007660BDB54EA6F9B46B1C2F68871D77F2EA
+:1062A000BD302FA694DB61A5E8EF67E32837F3F94B
+:1062B000EBDB4BC96FB42957A9473967DAF611D31D
+:1062C000532CF4F3B7366859D77DB3987CC0EF925E
+:1062D000EFB296A0FCA64CFCBCEF83CFE0BC5BA762
+:1062E0008BB0338BDEF1233FB74BD2C6D2C52559D5
+:1062F000C679C2AF7BF611FD0385E01DAEFD503BB4
+:1063000099FCFB68805CC0E65150CBFDA690717E85
+:10631000350649B273C782D584FCE89C5B1D5F9348
+:10632000F84D9295526419E5D50D778ED5C9E75C85
+:106330003E07EC3FFD92DFB1F95EB3CF0788B7733C
+:106340008FDDFB34E64D39F606DB979E7E92BDBFAE
+:1063500092A96558BFE6F05405F3809E2F9430470C
+:1063600006F9278A74F826889487F6261C8ACE7048
+:10637000D1F9FFD8FB0E4A5694232DB97C5E72B832
+:10638000BD4F8AE27ACB56BF93C747F60FCF6787D8
+:10639000307BAE52165213C9BF0E9E37E4E4497EDD
+:1063A000B9D39B4774F5766FFD2A583A06F9E6AAE9
+:1063B000DB7C9066FD5EE3CEFF62E3FFD2CFF58328
+:1063C000AB21D58EFBCF7A5BFF5BFDA3A90AD2F58B
+:1063D0003533B4623C7FE1CCE32FF6BABFCEF8543C
+:1063E00077F1FFCA589AF29233E7F7E6EE05DD49F6
+:1063F000567F499753DCDEF6CE73BDAF6F11E67D55
+:10640000595B7C8EDEE0C9775CB9ABCAC4BC31860F
+:106410003D3DDFFB3DC1FFA50EEF7C4F868FCCF9E4
+:106420003BFAE070F3517665D72382AA376FAA450D
+:10643000E57147B34586C039279E8BB6AA5374AE23
+:10644000D96AF66B2D318A53521CB081110EC6F9F0
+:1064500066A83ACF730F4C4C039D3F48CDC673E1FD
+:106460009FB4DF392AE7C37F74BF670FD3EF6AB5E4
+:106470005F41FE5C2377D60A2543E702023ECB1C30
+:10648000CFF0ED7F7C49F778F0B4EB1865BB7D78F1
+:10649000F47914ED6AC511FA7BCBDEB7FEF3C16F58
+:1064A0002BB87FBFF9C0914528E7AEFD89042A6B60
+:1064B000F7D68311E8A67D27ADA03C5EB95BA2F5B7
+:1064C00007B97BD6859E3CFB169AFFB50F47687FC0
+:1064D00058F9A83F5DC7BE5FF9C397A601E3DBB7D4
+:1064E0009A079E1E8FF87B40E0F90C56FFB40BD93B
+:1064F000F395325C9E2D1F21A972BE7AE33F42F5CF
+:10650000B8BF0BBB7ABE48FD765DE2F3BBE4EF2576
+:10651000AACF6947FAA3F53D213D59E0F065CBCFFD
+:106520007BE37B3CFEB4F2715F1AF31557EEDAA100
+:106530002459BB35BBDE26FA5EF0F04351C4C39A42
+:10654000C7BD7ADAB50F7FD83EAF92CE390DD4A150
+:10655000FC938E51FDA8A90E70CD9FFB67AE238ED4
+:1065600065EDFEFDD5F37EC7DEBF1E9720C044CA91
+:10657000EB7DFFADFC04EBC9708A8932D6BFEF45D5
+:10658000371FAED9F5129D37D24418283A0BCF41A8
+:1065900064BCCF680F30A0A03C5CD3B5E16D94978C
+:1065A0006B76BFF95BA4BB3520BFE8E6E7D7F11FE8
+:1065B000E34E8C6B75A85E3FCE51D83F0BED16D8DD
+:1065C000959FD55E74E25A0E7F5FFBD0D17B508FD2
+:1065D00078E3D1FFB907EF6558F5D15FEEC1FC56FE
+:1065E000782AA0A1DC5AF3C0AFA2E0C2FFB76DF9D0
+:1065F000F0D6F7BEFB9D3B181EDEFA8D9FB0F6D697
+:1066000093AF4EC4FB39DE7AE4AF6350FF58F7E432
+:10661000C2B14867EB1E5B3076A4F39F48B769BFF1
+:106620007B7DD3FC5E83C705DC04D9866B9719EBB1
+:1066300002FB0714D47BDF136060632E7BDEF5A1C1
+:1066400082FACBD3260C209EF6EC7EE9E9AFB3FAB2
+:106650009B6C9DFC59D689CD7FBC48FB1B631F56A4
+:106660005EB7FBC2C5675762E933B0FB353040FB0C
+:10667000C609EBFB1C5BDFCAA1F5CD7C7F148E291C
+:1066800088FF350FB2F59C86EBCAD673DA89EBF931
+:1066900026FE63EE89EBD9AB7AFDAF4761D5BD77B6
+:1066A000E0CBDDF959ED5B673D573F76D1887AB98C
+:1066B000231F4E86673AD7CBE0FA866A1E520B90AC
+:1066C0002EBEFF9D3B627C9DEB1862DE7AE8E844BB
+:1066D0003CB4F19A6FE08B88878127FD1AEA512B31
+:1066E0009FFC35F1DD5B8F3D4BE779D85F5460FB54
+:1066F000DD5B30F8770858FD3A815756EB03E7FD2C
+:1067000096F5BB9A756119B47EE7FDB612D74F1D99
+:10671000A0F5482FA9D551FEA60B68DED7A5397F75
+:106720005C97EE59867EED4CBC87034E5EE1D0BA95
+:1067300062BCF9BADD47CE43FA1B6E3D9DF96B385A
+:10674000FFD9ECFD7D5EFE1D965FEDF57D6BC7FB11
+:106750000AEA57DD3F513491D9ED6FF9069442DCD6
+:106760006F1E91343C679CB9EE43F86FCE7ADE38E9
+:10677000B3CCA40F25903D8EEDE0E964FC7EF2F9E8
+:106780007D3CFCBD6BEF9799787CE358F6FDA02427
+:10679000C0EDB9EBA0B31655CCCCFDCC07296B7C72
+:1067A000F110BCED5D12C9F9377649148FCB9417FF
+:1067B000D70D639F19CE388FF74C43B9F646EF7F5C
+:1067C000D874C9E9FEBA078F2896BD3FA45DF85D6D
+:1067D000339CDFDBEE6FCD13D9FB5BF3E0DB59FBC2
+:1067E0007B5D362F41F85FEFF3517ED2EB5D525661
+:1067F0003BB734E0F3E85DED91592FE460DC201AFB
+:10680000A4FCAB9666F3D7E82FB50EF96C3F80F188
+:106810001AE65DB5448274BEBD257A15DD93E4F4B5
+:10682000D79A8127399E20FB498E252A792C2CED79
+:10683000896FF91841B8E106D92A42BDFF40F1AB92
+:1068400032F68B7E15DD65D71F94A10DFD2A074D0D
+:10685000C168822CFE8D8CFE13F325D0DD7EC2EE46
+:1068600071E2BBEC7BFF73521A51DB00A96E3A1F39
+:1068700050045DF767E9EFAE469DECE7E2C4E5E45E
+:10688000FFF1A75226EA6B45EBB412511F7EDC09DB
+:10689000296F1CBB9051FEBB38CE3E1FE983B0EB85
+:1068A00081071E18C3B714D4CB9FC692C9BF7357B4
+:1068B000E84558BFCB9E37E3013ABF38C14AC828E4
+:1068C000E784D812F2832D4C25E4E5AEF55C18136D
+:1068D0000A713F4D0F73FFD30F037CFF6C6ABA98A8
+:1068E000F2D9EFBC5924BABE33707E11F2D9DEDC86
+:1068F000D961CC57EC593D6BFF1406E7F8B004683A
+:1069000072EE098FEC4FBAC7F62FECB4EF1DBACF79
+:10691000CE33FF8E8DB75D8D65543ED068D0FB07BA
+:106920001BE750BDABB196CA471B13F43CFAF560A8
+:1069300012E97377633D3D1F0F6F0BB8FE3F6C4C40
+:1069400052FDDB815C827FD24D2026D9F385888F72
+:10695000F0D0BC1D78D2B6DDFDC30D4FB5A21F62CD
+:10696000108F19F83E17FA0415FD573141C775BF4E
+:1069700031C0E549267E27FA07048CCF35DCC4F305
+:1069800022EE11BCE71EBE65CBFF476D3E7D3B9AF4
+:106990007C30C0E07CA7765919E943A09523DDDC63
+:1069A00023240E1AC58467CFF9939579C947032E1E
+:1069B000BA99D8C1EDFADB035C3EE9EB40447A9B1F
+:1069C00090021DE9CD99776F955E8472B15710687A
+:1069D000BD91DECA5CF4E6F4776780EBC110CFBEF0
+:1069E0008F0FD12FE7FFF8BCB2AD358897B522F9EC
+:1069F0002D5BF095EBBBBFDAF364768B68213DAF7E
+:106A000010C99F3BE9F0116122834FD7BE1F403F61
+:106A1000747C22D8FEA6AE00D2D79D2BB87FF1EEB3
+:106A2000C3FC3CD3D175254BA6B0F68B187E30281D
+:106A3000957741698E3B7EEA9C63B85B4DE46823A1
+:106A4000F8B732F3DF6E9F74CB07396C9CF1874344
+:106A50003AFAD7B74E7AAA4761F5C27E81FC4985DA
+:106A6000E1D4145CCFAA3F7C6F5CBF6B1DEE589DD8
+:106A70009A847A63FBA41F08C80785C77E2AE03E74
+:106A800032494BBE1228C0FC70FB7CB09C9A8D76BC
+:106A9000C1A57989D770DD1245E9FF83F474B47616
+:106AA000DD7F62FF4E3CB2A141CF9DE2920F99E79C
+:106AB0002AEE4A8DECCF74E67F17CE7F8476CEFC2B
+:106AC0009DF53B5A1B5B857231139F99FDE65DB0C6
+:106AD0006CC4F1EFB2EF0F63F357822EFA2C4AF534
+:106AE000CBF89DF3FD70F1D7CCF90EFA894619AFBA
+:106AF000EDF2413ED2C523FF3BF1DF0F02924E4241
+:106B000042FF544F20190F16E0BD7129AA33E948FE
+:106B100079ED67E472FEBD63CC77C611DFC9E96227
+:106B2000CAFF18E5786D904854E13E678846B67D07
+:106B3000A03CC8E5E77C48917F540CDD3472BCBFB3
+:106B4000C81BEFDF0C3409B0BA553BFE01B286FE1C
+:106B5000B07D5081FEC7BC2087BF4AE6F6E58C7D3C
+:106B6000FA0E89FBADA4251117FE6CBF9D8F77CD62
+:106B7000E0BE09341DCF7F4DEF115CFCFA7E287911
+:106B800036E24989EB744ED6174B925F72A1141608
+:106B9000C99FDBC9E57F0324D4D3785C0670DE3A55
+:106BA000C445DCEFEF5AC7CF8DEB5A88E0BE2BA669
+:106BB00053BDC1D6531EB1F5FA876CB9FF7D5BEEAC
+:106BC0007FCF96FBA55DA9056106D7776DF97FBFDD
+:106BD0002DFF77A2FC67E569F7F5C3F72A491E1B6D
+:106BE000985FF08D6DF16644C13D8D26BD7FA27129
+:106BF00005957B7EFF7C7588C177DF73DC1F7CDFAA
+:106C0000E1319FC1F859DA140D81B5BFCBCA131F0A
+:106C100067F51DEBC49D28577EDC98A2EF76A8DDB2
+:106C200012EA314799B56C2119BC66B68458FBC885
+:106C3000BB035A2D2B77B41E0AE0BCF33E2702DEBD
+:106C4000D3E7F051F40F5FED8EA21C9B290691ADA6
+:106C5000F20ABAD553D04E5F27523FDFFCD565EA22
+:106C600002C07B1B5E84D5ECFB095784293FA2E858
+:106C7000FA97CDD5ACDD9697C394AF5DB1AFBFFBAE
+:106C800021F67ED68A08D5CBBBFACD2DAC5EFA06AE
+:106C9000AF4FB0BCFC71FAAE7EF321F67D712A4A8B
+:106CA000EF67EEEE6BC2F9FA2ABDE7AF72FED031A4
+:106CB0006E0B836F22187B826C3D1E1352BD01F454
+:106CC0005B2CE1E73C0AD2C92ADC3AC66EEFEAA1A6
+:106CD000D07F0754235EE3BF7D217E0D2BB7E147B4
+:106CE0008C2E66EFE5F8B8BBF5C50BCE67EDF6ACBC
+:106CF0005B4BE715FCEBD6717D88E10DE5FF84AFBA
+:106D0000EC15AE76C989A25639ABFF6E5BD04FFC4D
+:106D1000D1B66E59620A07776F18F5BE52EEB72CDE
+:106D20006EABF1E439397192BF09C96D41D23F7937
+:106D3000BC44D652F47C06E37DF4B3C28D22D797CF
+:106D4000127D01B73F46FF0ABF9F2D138E9D4199CB
+:106D50009F77B46A5EDBCFE6B765A62207108E295F
+:106D6000F6FD2C763CD269CFC6DFE9966FB2C6E15C
+:106D70009AC00C2505E15ED537EE21D6CF072967ED
+:106D80003F3383B89FFD68AB48FBDFE64A7E2E7039
+:106D90008FF14E37DE73E1F0559B21121F6FEB83AD
+:106DA000349EB3D85659927B1AD2510C77719AAF50
+:106DB0008A782EED93C1CECFE945FFB81FFDE38C55
+:106DC0009E4A0F878E88E407F4E683175B5E7A108D
+:106DD0001BBCE7F02630E5C79DBFCC2C9F213AA312
+:106DE0007DB6A617EF51388AF728A007C532A355FC
+:106DF00063C874E2CA917493847EF8D28C73077767
+:106E0000D8FC7E8F7DAE108E5D0F28BFEEB0F38B69
+:106E1000EE5825067586979F598768FF9CD0D05DF0
+:106E2000458199C33C8FC2C9B7F6DFA435E33E5B09
+:106E30009CF2E60D5566E45D977EC2BCEBC341AFA4
+:106E40007FAAF7C74103EFC34B3F2719A8D77EE3BB
+:106E5000EB33480E5A2BB9FE925E917707C697F234
+:106E60000530F0B9D3AF63C7BE13CC23BE49CF659D
+:106E7000EF7398FC88745DB002D70B72B4E6189E6D
+:106E80008FBE117E80FDAFE0EB5F550474BF4E51A5
+:106E90000C28CECFCA8DA7227FAF1331360EC76D17
+:106EA000790F6ADF33F83CF73322DD9F53DC6A9DAC
+:106EB00086F3EC9D575888F4B139CCCFC1B4083C67
+:106EC0009FCB2AE0FCB023D24DF9A15B6A4568C68E
+:106ED0007563B833B09FE5C19D94D782F0CE24BAD4
+:106EE00023FD0B6315C88FD61541BEFF1CB34E435F
+:106EF000FF7234D4DFB587F5135EAF183B512E56C1
+:106F000079EFA99B1CE2FA5E20C4F73FC62F8110DF
+:106F1000C6F93703E531B2B9107F33BEB280F60748
+:106F20008DEC2B27CE1FEDBD402C9ECACB1217FF38
+:106F3000EEB4E56DDACE5FB8C7DE471CBDE30E7B6D
+:106F40001FD96CEF1FC5E6E26605E976054C473CA4
+:106F500095AEEA129667E1FF533ABC7235935F260D
+:106F600065F24BCA7B6E75FC8A12CFFB8871BAE75B
+:106F70003D856470DDD93E8E785E1F289750FF9B5B
+:106F80000109D32D5786D303F282E634C4DF68F5B6
+:106F900092682891423D34530F3FCB5E972F0412E5
+:106FA00073B1BFE8BC7ACAE75915489C45FDCB6967
+:106FB00001E5E97CFC2E96155E4A061B05BC351FD3
+:106FC000075E900D3ADF75A3E4DC67EB3DDF051942
+:106FD000F7D766DE4F7BCEFFDE44F7D3B6094CE130
+:106FE000C37A8E7D3FAD9FDF4FDB16E1F6579B8F57
+:106FF000E7AD5D67E3E1F210BFEF75954DA7E7845C
+:10700000B2DF7FE4F8BF52281BB0DDD8ECF78EA1C9
+:107010006685FD9D333EFBFB5448E1DF4F1A799CAA
+:10702000B5380EEB6766D05C1D2A18C2D38C90B9B8
+:10703000C65DBF2164E715C909D22F4D99EF877A44
+:10704000D05CE76EE794791754D2F9BEA3F6F93E07
+:10705000F6DD7681F02A69A3C1BB6307B409FA564D
+:107060009283BF62FA5F96F5783F18B5C49CA1B8C9
+:1070700094A327ED0A71BB97D1DB06A20F266110FE
+:10708000EE30E85BF15E88F1780FB78EF6E7E17BD2
+:10709000BE8DF2F6ECBE5AD4A356FF58A2FBED4EBD
+:1070A000C0D72A4677AEBC14E779E107E3C91E9E34
+:1070B00020256F0FB9F6E9C215030AD23BC25FC3A0
+:1070C000E1E7F9D442FA346E1700C573DAAE897B72
+:1070D000F20B33ED923CBCF780E48A42FA5D265C09
+:1070E0008E5DE1D433CF271CB0E908FFF431784F2F
+:1070F0003870A5563625E4AF9990A47236E854321C
+:10710000FBA50BD793F19F8E703687269E85F3F8EB
+:1071100027E2EDA950C1BF1EDE1C3A2E4E9E3B4811
+:10712000C7D9EEBFBE3D142579DB7038B2D34FFB13
+:10713000C9D788AE2546D7A8F73A79330D60E7D589
+:1071400087A10BFD94C5C9463A277A94D131F62B15
+:1071500069FC5CAB0C5A02E337528CF3874F2ED399
+:10716000440DE3B3961FF51EAB040C94B5E8977479
+:10717000C35B194EBEEAA6BF1B0F6F2579FB854086
+:10718000F275C4EF8DA5961F353B971C7EC32D87E6
+:107190000508EBC87FE71CE3FB65555297911E1667
+:1071A000304E47BC2F8424D5CF078BCA0B204DE52A
+:1071B00067F18A23D2E3EC730CDD9788EE730C83BE
+:1071C000E7E12A9DBC0E1EAF2AB0E9106C7BF56783
+:1071D000F54B9B16B2F1D9E29B1897FA563DCFEBCF
+:1071E000F1CF96E93C6B41FF1575182F82655C0F56
+:1071F00073F221F2EABC7ADA09F75D1DFED361FC75
+:107200002EF3DC9CA3AF65EE5B4E99A9AFE58587B5
+:10721000892F0CB3EF64C6171AF09FDC8EB5EDEB27
+:10722000448EFBDEF8CCF240E340EB5E57DEF941E2
+:10723000BCEF28EB3EC0E3BED1DE3FD52DABA4FBB7
+:10724000E50C4C9DEC6BEC3EE7E5C943F670627EC5
+:10725000EECFD02F9DA8C9AD407B7251FCBDD6BDED
+:10726000F9004BCC9E735E76CDB34F63D066D113DD
+:1072700006C7337D7F73EFBF6FE0B903F44FD8E3E8
+:1072800045EC38D97AD1F213BFDA7EB8778BB8BD26
+:10729000EED8F9D9E6DB4AF8EA0F233D0C37DF2FA9
+:1072A00085F97E3AA6DEA0FBF25BECFBF25B2638AA
+:1072B000795C8686FAE45561EE8F5D1F2EA5386BEA
+:1072C0004BCF5CF22B17ECF7915F7DCCB2A460B989
+:1072D000F645CCBF473FEC37997EA753BE7D19D505
+:1072E0007BAB66A9682FDC10A9A0B8EDC646C39396
+:1072F00037E2942DECFBA4CBCFD792A8D630EEDBAF
+:107300005A57A1A2DD217DAE92EAF269159DD58C76
+:107310009FBFB079DA7905189F28E7F7935DCEEA29
+:107320004DA500D561BECF1E305E0E239EAAC3BA06
+:10733000433FB48EBE6549D3877221AE5563CE8C70
+:10734000F31C6CFA62CF49BF7E43495E13C67EECE4
+:107350007BB2D62BA9B2B5E5784E9E091CF417ABCB
+:10736000DC5F8874D03A6308EEB5367EE7D9E33245
+:1073700081243EE25A3F25CED76FBD082BB2ADCF58
+:107380004D61AEDFB46AA636221D69F2DF3CF78795
+:1073900056C678BE7E8CD1918B9F4FA477CE4F95E9
+:1073A000E1442BCECFAA86B214CD3F4CF287BE93D8
+:1073B00086EEB18C87CD0E6CF78B5C3B4FBA88E7BD
+:1073C00043B3E7ED3924FF5224DF1D7D70BDCCF5BA
+:1073D000B9D1EA837917AC237DF01DC65A649F7D2D
+:1073E0006E1DC9ED753E5543FBB477BE4C71ADE8DB
+:1073F0002970B9DB6E91225C1F9422DCFF8DBF9354
+:10740000909EC2F51E3CE7110D4137EE0303137841
+:107410009EE97AD8517B0AC1375973EF675513B883
+:107420009F614B757085DBDF303797C7CDF6E65629
+:10743000FD29CCCAF270BA1A59F30C0DFA31AF0615
+:10744000AAF97932A1889F27F381A1727EADD1F08C
+:10745000DE500192741E6DD8F503EFFDA20FC8E94E
+:10746000E620E22DC6EF59896C1728794FEA32BB26
+:10747000F14C4F73EED21F8709DF0903F9BB675642
+:1074800090ECBDF77A14B23FDFBB067ED785755FFF
+:107490000E586CA99E12C5DF3DCCE63BC0987527FF
+:1074A000E68169FCFDF4CD02F9B39EFA5B703CD233
+:1074B000BB1105117FCF6211D32778B22084304EE3
+:1074C0001B5D00DDE7E2F73D61C29F2FFEF3735EB7
+:1074D0009E41FB4F489C83E7B7C43B71FE8FC6219A
+:1074E0000FBF9FF1D76A094A86F4A1AD5AF210C2C4
+:1074F0003B1BAC153DECFB2D0AE7AF2D794A1AE397
+:1075000095150522E921E00BA527B3F78BF6BD5CA5
+:1075100083F99D8BE64CC796383EADF7242D79183C
+:10752000E9AF465B5293CBDA573EA793FC3D2F7EE3
+:10753000FD5EACCF3ACCEB3E3FD7E3518F719F134A
+:1075400058F4C1449AD7AB61AECFB6C6CD3E5318FE
+:1075500091AF32EEE5F59E3370E8806DEB3AE6A729
+:10756000D3BF75A28BA44F1CF23FC11CC33E8FE258
+:10757000D083297C1C7AD88D3C89F217F3CE6243E4
+:107580007967EB6DFD6DB4796799FC9477814CEB6D
+:10759000F00ED3B7300FFD443EB99EEEFFCCE4278A
+:1075A00007CE8D95793194C30EDF68B36F22B9ECA5
+:1075B000BF42A1FB4C1D3E72F86756CE201F7D13C3
+:1075C000E5C5B2B0BE90A76A98E0E6930B4FC257EC
+:1075D0008B60606F8CD517C960E530117460EE6BFD
+:1075E000A5135D7C9289CF45F30578D1230779DD1A
+:1075F000856F6DF01EE02C76F270EB7248D6DB6280
+:107600002E3E6DB7CF99758806E07ED49CBBDC8892
+:10761000CCC47B277357213F6C121229E487C8EC36
+:1076200037425731BCBF37866991E83FD4973F4C0A
+:10763000FCFE4288ECB22DB356527CEABD6B9293AD
+:10764000707FD9C0F0FE22EDE7E9B122E5DCF68FCC
+:10765000E5F9137A9C97C9387F0EF6FBB45D37EDD8
+:1076600076FDD48EADAF476EEE8B723ED817E5FB3C
+:10767000D406A553457A1828563577DEF2B9F6FDBB
+:10768000C2D746ECFC97632D3AC629AE8D08F67931
+:10769000BB2ED25736343E4E657E5D1A304F2E5883
+:1076A00066E9A857A81F2D10709F85D379DC1D9F10
+:1076B00037B9F4B58B6CB9ADE2BD406CDE6AB3A5E9
+:1076C000BBEF9D554521EB7D41FF15E5FE5FB519EB
+:1076D000E8BDDAFBFF283F21BFD410BE8CF5E64E93
+:1076E000FADD9840377F1E2B35852B5DFDC6EABA43
+:1076F0003CFBA32AF6CB640F358066A17127F7D730
+:10770000A0DFAD6369B013F39633E908FF5E74D16F
+:1077100083FAD185A417C121AE97D694A844BF6D32
+:107720000DCA0EF4EBBD1BABA63CF5161B6F99F30F
+:10773000C1F83AD3F4C84F66F9799CDD9AC2E3ECFC
+:1077400058C7383B961867C712E3ECF81EE3EC58AD
+:10775000FF41A349758CB7631DE3ED58C7383BD68D
+:1077600031BE8EE5E38D2BA8C4F809BE7FA2B1819E
+:10777000EAE7DA7213CAF8EF7C757C4D31313FEAE3
+:1077800027F6FAEC3197AEF825FA01216AE07E1D62
+:10779000D8DFFCC27FD975BAFF3A5E928F7E4988E6
+:1077A0008980F184F6F836A6630ECD2F20DF0A3AE1
+:1077B000C5D5AD1598D7B83372E03C99E90FA5F15E
+:1077C000EBABF3587D57E4B976CC233D556FAADF78
+:1077D000E1AAEB918A958F6843F549E53BE4207B6C
+:1077E000FFD096E7DB510E04625CEFFB51E437E714
+:1077F000353192E82E618A0DCAB162258D748C678D
+:10780000395F9C8CF3E07ACB67A1258E797C9374E9
+:10781000A502F98FB5EFE6743FBAF63F89E8F43C6C
+:10782000F3BB91DA8995A36A47E770876B87EF8589
+:1078300011FA698316AD8FC1BEC9C7F757AB80FB7C
+:107840007F3B7C9CEF3B02BC9C98E3E42F54DF120F
+:1078500065E52D51BEBE1D017E0FC1C054917E8FC6
+:10786000071A84CF633F5F2D040DF31F2BA696E408
+:10787000A3FE7FC8A687C993227CDFFEBF2AEDDB6B
+:10788000E74F7AA8358FD5277FDB30701FDE04469F
+:1078900010EF71B5368B944FF4FDCA53F296B0E6F3
+:1078A00067CC7C2C0FF5DE0A5BEEA46DFBA4A9ED82
+:1078B000AA49681FBCF72C977B47EC7176F8FA52FF
+:1078C000B49E33C3749E02A093F492A6B84CC10C2C
+:1078D000711C2F159F7629DD93D9A6D0BD4CCA8780
+:1078E000B355F2A77EE0B7EF25EE237D450924B519
+:1078F0005CF6BCD312C9FFD0A205296EB3295C4146
+:10790000BFCB6095CB140FDB54CEE33AA1C8C5744E
+:107910004EEB9B3D016ADF1656291F385DBE7B5F2B
+:10792000750C4B51C37D3F6D2EA5FB2A2D4DD428E0
+:10793000AF98FD8BDEAF8A919F6713D8EBB28AC7F1
+:10794000217C63F753BDE5228DFA073B7F9F542FBF
+:10795000117F2722D1E3BD7F76E0E767A21F642570
+:107960003F9F324D5BDAF3247BDF6AAA8912C60F90
+:107970006DDA3BBD21AC5F06142F0D4D7DB919E3C7
+:10798000A9AD576A06CFC7E2E721C0BEEFB8B57C04
+:1079900059CFEFB1FFFA104C36B07D8D8AFC0AAD9D
+:1079A000F034DE4F5564EB33A1DC0A01F5B1B63A91
+:1079B000BA8693C1E73D47D09AF71915E9465A941C
+:1079C00047E3B481A9627BAB4EA67DB128AC76A318
+:1079D000DFA0C8F63B38F2203FE53A4FC0FE57B86B
+:1079E0004AF69C37187BA5B75E9071DFEE9936FD9D
+:1079F00064E22D739EF9B14773119EFC557432E217
+:107A000004F86F8D552CC1798DD37A851D9564D27C
+:107A100068BA86A986A926773EC62785775A796BE4
+:107A20001FD2C3345D069DE1E54C1868C6FE37D908
+:107A3000F4DF51ECDD9F0FD9760DE3D3ABA3980FA4
+:107A4000D52082E5EA1FE31D960B9E533AF23CF5E2
+:107A5000C99D859EF653B69778DE9F963EDDF3FE70
+:107A60008C5D159EFAD4AE799EF6673E5EEDA94F09
+:107A7000EFFE8CA7FD8C7D4B3DF5997D977ADACF93
+:107A80007E61B9E7FDDCFE959EF767BDB6D6533F34
+:107A90007BE0EB9EF68E5E9FB96F5E11FDFBF47985
+:107AA000FCDD1FF7B9E24C7BE1847B743E6AD13187
+:107AB000FE07517E6FAE8CFB3BABAFFD1AB7BBD45C
+:107AC000730C1DE5CD25365DAECC33AF43F95A15A9
+:107AD00055699F90C3BC9D1C3E8FF49189DB999C96
+:107AE0009A41F6D8E0FB10CAEB46EB9C5297BF2AAE
+:107AF000A07502E68155456BE9FE40E77B593301ED
+:107B0000F3E32EC12486023C766A51BB80CEBE7759
+:107B1000CD8BD97F7495C400B30F51AF1FB4FFE470
+:107B20001C8AFB32FB8FEC4323C8ED413826D17B06
+:107B3000E39B02607C9AD977641F3E1A66F6E17473
+:107B4000B4C7FA37A11C1AF8854C7144F647F65FA2
+:107B500025B3FF36E6BAFDE0FDC558A6412B247FCC
+:107B6000B8D22D8E2D267BF036A4E72FAC7B760580
+:107B7000F63BB592DFB3D731A62E8E7A72477117D6
+:107B8000F1C940B1CCF7213951E6F6EFFDD45EEFF3
+:107B900090FA7DB243D93A905C76D66193D09FC675
+:107BA000FB0CADAF05C9DF3DF18FFE43C86F6A899D
+:107BB0003A1EF3008D3D8A89E3DD6AE3B9449B5E9A
+:107BC0008D3FF3581A5FD28BE5A93AD347585956DF
+:107BD000B6B517CB47A22534DEE9C623D52863D432
+:107BE00073B8DF5A9EA6A49B05F4373338B2D81D6C
+:107BF00083FE89E8767E8EBF547E05E90FB5FEE3ED
+:107C00006C0A55792AC58D0348170295444F0139EE
+:107C100044FB4B000FA3627D8E90C65017EAAF98CD
+:107C2000175A95B79DE8C0D16B51DF4D72FBF8A78D
+:107C300088D7589D77FD43EA0F084FADF6EFBC7526
+:107C4000E4EAFBABD9B81D052579E8B3457FCA1234
+:107C500097FCD963EFBBF7E6881EF9331B731466F4
+:107C60000EE9458C1FB68BA720BC098AAF07F64BDF
+:107C700064CF076EEAA4DF570D68960EA4FF5B3A47
+:107C8000F65B53524FFEBFBFC42A480F0E343C95DB
+:107C9000156F817E09CC19C3E3337AEA1DA40FC0A6
+:107CA00098A08EFB6C432C68EEC8621F7C29C2FD35
+:107CB000671B263AFECC049D7B6D437F5B18B7366D
+:107CC000557C84F573C32F0A76BAEF87B8A180FB81
+:107CD00027871B3FC0ECCCA40BBE0DAC5F94E36DBB
+:107CE000C796D4D2FDAAB8CD54E2B9D0F21DE4A70C
+:107CF000B7EDA52FD978BD36C2F1385181053B507B
+:107D00009EE431FD88A1B4CAF6AB38FE97780E8F99
+:107D1000EB1B1648DC2FE773F62DF138DE4BA383FF
+:107D2000AECCB2AF00211598EF6BECFF7AF07CE09F
+:107D3000291DAE7D0E703FF0D6A76CF7D64F4B7B5A
+:107D4000EB4C8B7E1EF5806500DCAFB1CBFB3E0CAF
+:107D5000A60FE32885CE7DFA097E5E506510207D52
+:107D60009777A57BEE66F34B38F75E66DC9F3F7531
+:107D7000779AF497C54C7FC1F799F7BA171E5EBD85
+:107D80001AF585C28C7DB4C22791BF01FD4486CB14
+:107D90004F3449D33D7695E3EFC994EBC1C35B8182
+:107DA000BD217B3DE9C7FB51B572F42BB417DDF261
+:107DB000C7239543FE957639F5EA11F25F32FD2B24
+:107DC000C6FD1FE897BEE1175FF9F311979FF2ED2B
+:107DD00068721AFA336E9FC4BF77EE4F75CEF5BD49
+:107DE000532BFF4CD0391C49171C379659E7737534
+:107DF000254DF76738FE15C78F70699E790BF2DD48
+:107E000026E3506A0FEBB7FA377EC07E164AFBF7BF
+:107E100035A2BC9B2053BE88367BD5BD41F467E2BA
+:107E20007B56AF2ED6C7127F3CE3237FC27A9BEFEF
+:107E30009DF3A98E3FE6B3B61D707E8EA3475941D0
+:107E4000FB5C4610F5E43376B135F4EC87DC1FE8D3
+:107E5000F8FDA67679DF9F8E47BDC9EFB983F29B07
+:107E60008CB93CBF694C7DBA17D7F94C7B9D316EFC
+:107E700055356B287E3AF6B2742FEAA1D3EC3CA5B7
+:107E8000F2677E463FE50B5211E5279D3E9EDF4B94
+:107E900064EC953DE742C68040793E639E938C3406
+:107EA000EB67DA13DEF7E5E0AA17237CDE7A665C7F
+:107EB0008AA95B6F5F21E0EFA2A60494679B2F6302
+:107EC0003602ABAFC8B1F38B4E8553916E174A6142
+:107ED00003EFD15BFB2B89F214FD47A6FC1AE3A349
+:107EE000F02CCFABD44EE1F156EDE792C1242068DF
+:107EF00021983E3D3C14C7FAD67103EFD41FF48F8E
+:107F00003DC0D61DF7A10799DD5FEA433B5EA37A2A
+:107F100017B3FBB1FE28B3FBB1DCCDEC7E7CFE4396
+:107F200066F763FD7166F763F96366F7E3F3279815
+:107F3000DD8FF5BDB955E48FEFC3FB8DA6E0EFDA19
+:107F4000EEA6BCC6F5AA4F43FAC99467555537A8A3
+:107F5000CB187E378617521CA57A21CFAB6FCF592D
+:107F600048F6F4A09F2EC3CF39E4B7EB171CBF1D12
+:107F70001E718EDBF6ECA0FF3369D0FD0527EFC73D
+:107F800074FA21FFE909FDD87ED437BFF6DBEFB4E0
+:107F9000B057AB676EEB0896E0B99E147F6FE7159C
+:107FA00066FE9ED6EADD4D94E7A78C7B2E85EBBA64
+:107FB000BB324CFA06FEDE12CAED4C3BD1B10F3398
+:107FC000F571A7CCDC0F33F36022B65E72B2BC8CC5
+:107FD0002DBE14C5ADAD26265F70BF684C9FF3B2B1
+:107FE000EF44BF6DA1969771BE99E75DF9F7F17CFB
+:107FF000BC0E486AEEF93BE71FC8E62BE1FE43B72B
+:10800000DF36589AA6FB19826193F44581E991A461
+:10801000576A498A03B60FF3BBD9AFDA72A269DC9B
+:10802000C5B4DFB73FE3237DABC6CE7F6B19A75244
+:10803000BD65DCAC389D3389CC52FBB3F4B336520A
+:1080400032E2FE2AB1FD5F1F61FF97FCFCDC574B5B
+:10805000EF5C15CF47758497F7A1DDDE118F91FF97
+:10806000BF67DC2CCF3DE4527C0EDD572185B99EE5
+:108070002DC555D2B3659C7FF9507BA7DD9E1CBEF4
+:108080008F3036273F6620DC49EDFC72C2447F8B7F
+:108090003FC6F38CFD1A8F17064B4550B39CC7782B
+:1080A0002287DFE3D5519ED4D0AFD31197E95C4747
+:1080B000875E315CBC95F4A2FFCD113CF4DB62FB22
+:1080C0001D5A5628A417261A72B59A7C3A97308002
+:1080D0007CDE116E5631FEAA8CAB1CB15F45E3FD10
+:1080E000FE7FA3B2F95D0080000000001F8B080036
+:1080F00000000000000BCD7D0D6014D5B5F09D9DF6
+:10810000D99F24BBC924BB9BECE68F09241A34E019
+:1081100026240134E224048A167111D0D052D98069
+:10812000282A48405B57ABCD8604842035F853A9F4
+:1081300058BAB160ED57ADD1D296D7222F28F2FCB4
+:10814000414DD52A58D400D66A6B6D0469A9FA3E10
+:10815000BE73CE9D497626B34950FBBE872DC39D85
+:10816000B93FE79E7BFEEFB9774F9D823F1730D630
+:10817000BA27456595F05CEA88A71431168E966794
+:10818000D74F60EC1B59E1CF32FC8C393C8BE49823
+:108190009B313B636A173C4F69EDF4A75716188370
+:1081A0007AA2FCF329EF7A077FD79F62FA661681DD
+:1081B000F6AC587AAFD7C5984D61C2291B94995B2C
+:1081C0007EEF6C467F4E89F8774F20EC49DE8FC7F3
+:1081D000F58B29EF4E18DC6E7959AF4354185BBF0D
+:1081E000AD23CCA0FCA900852A843BA6E6C1BCAE89
+:1081F000DFB99245CA18DB28F5B8648063E3E7C2AB
+:10820000C270D9E0FE17E37CAAB057298670C21F5E
+:10821000DBA973E06F85298E6AC6F2F0CD687CF227
+:10822000EF30CA9E53D07F7937944B3578E0FF13F7
+:108230009E3596AB7A8CE589078C65C642F6F03898
+:10824000C65E6B864ECF646CCEA10F0EB174C6E6CF
+:10825000C642CF3CE9632C577585E33263F358E897
+:1082600099B7A09CD790C6BA4330B88D2DC57581FB
+:1082700069BE510CF035308295E52D4D65CC35D079
+:10828000FF7C3993D6A9A1B771261BCFD8F76F69A8
+:10829000650CFA89D509F1ED00FFECFA6DB3C7C0A2
+:1082A000F3FE4A5BC143D828627F17E7E782CE4ED0
+:1082B000C17C336D2B478D86FAE1A969422BD4FB33
+:1082C000FEB967AD2F8672CFF49210E21DF0F56E05
+:1082D000FF7C00FFF3C2BCBD3EFECB95C7E68E819E
+:1082E000E796CA2766E3734E627DE86FD6A4CE1682
+:1082F00007F477C932A502FB0BD71BDBE7D518CBF8
+:1083000000399F0FFCCB9B3518DEE1E0318FAFF7D2
+:10831000777FB342F8679F033D003EC3F809DA87D1
+:10832000A53E290478CEAD11D438D04D9E2AA89D03
+:1083300016FCD0AEF18319FF622C83219FD5CD139B
+:10834000E3ED5025D76527FCE7CE14E20A8C9FBBEE
+:10835000B4AFFB14942F73D9E3227CCFCAEC12F094
+:10836000FBFDCB18EB2822F0D26B13D6F77ED71A81
+:108370007B217C9F1714990DE880D58CA1F1088E84
+:10838000D1848F231C1F2EC247DEB2D0333F82F12F
+:108390002F9FE49445A87F7903FFAEC3B751023AFB
+:1083A00083EF1B81CE624467D29144FCCC39B47C0C
+:1083B00039D2E31CD3FB62A88BF3FDDBE403671423
+:1083C000025CCB858E1969004A8ABD89315C68C020
+:1083D00020D2B5CE8F3A9E96EF68217E4CE033FBDB
+:1083E00029E467FC7736A186F8EC29D72F65941B22
+:1083F000BB337BB73020E1AD328BD5E733F69FA995
+:108400007D670B50DE2E5FB66EDDF9F03DA5EFE720
+:10841000AC9C31A7F39B336624945353AFA6B24F61
+:108420001B07A610E3EBDD3F2ED1C75F650EDF060D
+:10843000956D12A12CD9E44DA1A2817659D84E1880
+:10844000A25D986D922CDAB9F57680A7B5B07EA9B9
+:10845000DABC52B5EF360D9EC4F125C49BACB8050D
+:10846000580F69BA2423BD7C5938B2879B77846D35
+:10847000B28F19DC0EC06ED1E1B759C31FC7EF89A7
+:10848000E3DB8780FFABC6C770FD39B4EFA70D1FD4
+:10849000545F9D9D7CBE08971DF595A2B86D09FDA2
+:1084A000DCB9E75F2F9C03C42BCD67A114E843B26E
+:1084B000AB7208E8BC4CBEC7859D4B99F57204F8B9
+:1084C000613D945578BFBEABC3A5C0FBB2E2BBD63D
+:1084D00021D19775A7329407E3989CF908F43B4E95
+:1084E000965837AEDAF97B6D69506617B35009F4C8
+:1084F0009BB12795E44966D1B93F1160DCCC4C971C
+:108500008AEDD332AB7FC2883E982225E023ADF6B8
+:10851000B5BA34846B360B212B4A429CD522938DFD
+:10852000051E8272E6B46DAC1ECA157FF32822F2D6
+:10853000B4C4F55D3BB6473DDDC6F6A17E096AF2DF
+:10854000679D43DE44FAE35A89A1FE481B778F807A
+:10855000F0DC0F5D89C097656559B3EBA15CB6DFB0
+:108560001652149C4F875088F30988A4B7747CEA8C
+:1085700072A4E2E36ECEF463597C3BC0DF668F7772
+:10858000A3BC8A4DBE5CDE0EF0E45E9920AFF1AF75
+:108590003EC001C2FBE2A5DBDB8B90BEA57713FBDF
+:1085A000CBF838DE8DF28CD53684B1BD6FA66490E1
+:1085B000FFA99A3C4B35E981E62C3BC9335D1F305E
+:1085C00055526498B7A0CD9B7D2F4CFAC0C9422E5E
+:1085D00007D92B0BC80E1158AF702A0DE68F151155
+:1085E000EE023E8F41EDAB797B1608B9D0CE71A675
+:1085F0003635617DF898D502C815AE4D55513F0B03
+:108600000EE60A56C0BC6D2CD20574D2223009CBBE
+:1086100003E375331CCFE94A6B43BBEB2957AB0D22
+:10862000F1D7FA2CE80F98C7ED76D6807641AB1CCF
+:10863000726541FBA866BFAD2A1F9D83E50CA0EDC6
+:108640001EB41BA4B08C74B9CA5F9CC3E07DBAB7DA
+:10865000F79B2867BF96F9AB19AE0290A37550E758
+:108660005C90FB9B1E5B17AB81F14EE63125C1CEC2
+:10867000734A4D0CED29E7C942C3FBEE6698D199C8
+:108680000365D56DABC771AECD5408AFB54C6EC3A5
+:1086900076B5800C25615D9C27834C9960D57FBEA3
+:1086A000E17D37D8498A7324FDA731A534B1FF3164
+:1086B00049FA3FC3D4BF6CD9FF40BF5E43BF6B24B0
+:1086C000467674CCE7A67537DB05AB33EB5664A270
+:1086D0003DEA644D5D1676674BA68DE0BE3DD0D475
+:1086E000A342FB3A068C0F7472C1E7474446F60C6E
+:1086F000AC14D00BCB97FAFAE97834D6E3F46B8B51
+:10870000090CE5D20592DDC0275398B16CB68B4AAF
+:1087100060AD715C9BA7B207E967953F55715AC080
+:10872000AF3F7B9AD994E212986F6A7829033EBED4
+:108730003F739F6B4D00CAE99C4E1ECEFCE30CF4C8
+:10874000177A044E7F6B7C36C24BB82EA7534CE889
+:1087500037EC60252817C348DF6E0E0F8EDFE3CF9E
+:108760007FB0DD627C10BB06FB61B62A4C294E98B7
+:10877000578F6607F78F3735AF13F9A07F3C27ABCC
+:10878000A2F144C07FE278D95F6CBCDFE3FCCA068B
+:10879000C69B3DDD38BFD90E99E6375BE35F7DBCF4
+:1087A000DFE3FC8ABEC07838BFC4F1BE669CDF6CD4
+:1087B000A74CF39B2D72FAEA1F2FFB8B8DD7D35C4E
+:1087C0004A76F0ED0E904F4027A9E53B5C6360DCF4
+:1087D000DB5D76595006DAD5D6DEE09A8BBAD73D06
+:1087E00075BA1FC6A99B069573B197A9D36B8B1950
+:1087F000DB2470BAF8EBA63FAF43BA383E73552975
+:10880000E913CDBEBE04AB823EBE44E2F0CECA77D1
+:10881000C75B12F0783FC81115E07800F85D057E5F
+:10882000DC0A7C89E57873809E0F82BD8ECF6D0057
+:108830002F7E7FA83944E5879B27D153EFA7741279
+:10884000B7DBC7D658DBED676471BF6F53509E7FAF
+:1088500025EAB5DAD410EA4536E93CA626DAD5ACE5
+:10886000E9A914F8BEF132568EBAF18CCD1C6E5FB8
+:108870007D36D9EDA9E57B7B9AA17CBB6457502F4F
+:10888000DFAEB019567E7311EA992AB457797B7618
+:108890001EF7C37CE1DEBDA8F7E6A09D0E78F5CFFC
+:1088A000EDDD8BFEDFA56097935E6687F7BE05DF83
+:1088B0005F03FFAF1DCBA29BC9509E35C74FE3C3DB
+:1088C0009FF4DA6CB4DFF99FBB671E23BF229CC202
+:1088D000F5828FCD7E660FC21B722871EA8FDD1B79
+:1088E000463E50ED4A3B8982B01DF5B41FF5347CFD
+:1088F000AF3DEC6436846F9A83E4DADCB946BF613D
+:10890000534AB78CF6CFA6721F6B81FE2F9D69FC70
+:10891000EE74727E0B9BFC8659A6324848EE778B2C
+:108920000B32D0DEBF1D5F4D1E8CB7E8A196DBF782
+:1089300026D0695E96C747718033D81928CF4EB0CC
+:10894000B23BEBF1637E16192BE6F6FF6C8EDDBEB3
+:108950001750FF32CABD2AA46F2E3706F307876768
+:10896000B256EFFEE69E29EF960CC0972BC505D4B4
+:1089700003794BE17DC27C255F5C407F87898F94C2
+:10898000A37F639EC7FDC2234166319EFECC65D2A4
+:108990007B88175C4A94E7E6F94E1E34DF9A978B82
+:1089A00099153F299BD09E9BF5AC186A5106F0A102
+:1089B000CFFF7F9AAF8E6A7A86A93ED60DF4F23247
+:1089C000D07B3BF76318DAA93ABD4205B29F2EB9B6
+:1089D00004BE235DA86A01E2F3E5D17DDBAEC27679
+:1089E000203B5AD1DFD5EDA0EE8336B483BE68BFFD
+:1089F000975CEB207B8BB17AF9BDD281FE92AD0FF3
+:108A0000F6FB5E82FEECB713F14FB526FA10C69660
+:108A10005080EC819BC13E467F3F5AFF8194CEBF80
+:108A20001F49B053F1CF9184FE5AF7FC4C5000AE71
+:108A3000CEE6AE29EFDA13E4C552D9B606EDB99603
+:108A4000B84071886EA807F6C0E8A58AAD0DF07F22
+:108A500025F683F46992EBA3DBA09F443BA566AEA9
+:108A6000FC08D0435B595D47089EEB37F378995E6D
+:108A7000BF3F6EE68B917F6E674D4C00381D29DF3E
+:108A8000FB712FCC476D9558CA1428DBB9BDC3DEE6
+:108A9000F2905C10DD4D3FC5EF8118C82D9C775DCD
+:108AA000D363588ED958B8159EF7A5F1F651C9254C
+:108AB0003B431827699B81D3CF0C46EECD02FCAD1A
+:108AC000C94E2539E878DBF320CA294766C552B478
+:108AD0007B1644BF1BC678A4EC650BC316F4B540E7
+:108AE000B31FE2593CEE72C8DE5D900970D706EB09
+:108AF000E2D8EFA0FAD1EF517F53446B3B6CA7D67D
+:108B0000CF169BB55C785CFB7EF9F2273E7808E6D1
+:108B10009356EC0E21B9AD3F87ED106C83EBEFF26D
+:108B200047BA12E1482996258A83B2AEC968CFAD0B
+:108B3000FFEC81AEC700E5599FB949CE66899EB862
+:108B4000506468BF33AB6A70FBDDFF7A3D80EBB3E6
+:108B50003B85917E65EC850BD19FDCD85F6631014A
+:108B6000E39C995A39F6F085AAA1BCF8C25A2C2385
+:108B7000ED02514EBEFBDBEB63D85EE06516FB0EEB
+:108B8000AF6FE7F573B4EF532EFAF02777A23EA844
+:108B900076901FBA51B38374F8CEF38A443FE779D5
+:108BA00087C6E3414D2EB8468EC7835678DC1D54E8
+:108BB000DFC4F729AC4B403A4EF9CC7523B6FF61C0
+:108BC000330B5F09B06F5176FCEC4E85DA1FB6C2ED
+:108BD000E35941F508B6772D3FF2933B010E8F0E16
+:108BE000C74476631238FE32D47AEEC8E6726E9EBF
+:108BF0008FEB8D2CCDDE74387A02B3E12957FEE07D
+:108C00000619E4CDDAA2AE06ABF8F309AF8DDA654A
+:108C10002689B7677839DE76E5843F4538DAE42778
+:108C20005C387EAAC0C2587FC3A45E2624F47BB6FB
+:108C30008FAF03C06DF342BBD4C94C453AF3304FFC
+:108C40009C019D792A39FC1B02AF3105DA794AE192
+:108C5000E9C6F7BDC4FFE87270A106820ECA0E8D88
+:108C60003E32EE6EBF10E9214BD4E92DAF1DE9C5B0
+:108C700061D3EBE75D84E5CE2C5E2EF7E5B5C7F258
+:108C800041CF38A00DCA855C07D93BE6F9E568F00D
+:108C9000B6FB55BFD76F814F672FADD3C6718E50CE
+:108CA0000CD6758AADA761317EBBC84DF61ABC6F74
+:108CB0008827CC7FBA4687D3BDDCDEDAF82F57434E
+:108CC000DC623D92D1E978EF69D3E978AF359D9EBA
+:108CD00083F84FA0D34F98359D565BB5073A9D68F2
+:108CE000850F735964EAE6460050FA74FAC377A216
+:108CF000B6FA7ACDE6C7E039E533B7E4853AE2194A
+:108D00008CEC449B8BCBF701B91F9986FD4B7213FA
+:108D1000BD17DD61DAAF79318BF73FA8DF89D59BCD
+:108D2000516E8DA0DF30CEDBDCEF282F8777CA4570
+:108D3000EE48DC02EF27BD12F74B7D7CFC64FC5251
+:108D4000EAE37E73527ED1E93F271C413886E397E0
+:108D50000B06F865E9C8F86507F14B5A19E797B4AF
+:108D600024FCC2624EE28FB545BC7CF3DD3EE28757
+:108D70007EFE899518F9275662E09F69F794507D29
+:108D800073FB749CB7055E625E7D1EE1669C877A0C
+:108D9000B6DC2692BDD1CB504E75B2BE3D4EE4C37B
+:108DA0001A21B41DDECE8AF5D4BB14FCDEC3668363
+:108DB000FDB14EA3FBAD080FFA43D55A3C4BEA6117
+:108DC000977A06F3B1A7B2BB349280FF020D8F975A
+:108DD000F9C277E2F89DAC772CDAA5C9D6E91E0D69
+:108DE000DE1B03EA3D56743E9CDED9897AC78F4F5D
+:108DF0000E77D667AE269403663E9F72FD6F3F786E
+:108E000068887E7EA5C1F1A8F63C0DBE7FD46BA517
+:108E1000A783EA2F4C7C5F298CB6E4FB5F59B5072A
+:108E2000BEFFB5153EBE049F3F65C5E70F7879FFCD
+:108E3000C3E159F2713C4BBE2F87E723DA3ABD7983
+:108E4000FA787E33099EFFE8F58F08CF4792C8D79E
+:108E5000A35E82C316C37D01E477F4DFD74D8CF5A2
+:108E6000E17EA8051C7F4DECC7A5F07EC0B4FF4491
+:108E7000003A9FF2E9BA50C4822FA1DDB144F8F55F
+:108E800076F77865CD8F5056A25DBDE5EB6EDA4F73
+:108E9000003DF80FEF572BE76D3E0B793CC5C6E55B
+:108EA000D065771F5E8F719A2FD17FBA55FFCF693A
+:108EB000F4359CFE2F4AD0FFD88F59DE75321E4FF5
+:108EC00069F747F27D84AFDE0B513E6DBD254B4007
+:108ED000BF2E5FED16D0FEF76BFA65A397FB337AD2
+:108EE000BBAD52B72061FD2659880986FECE18AA6F
+:108EF0003F331C00DF5884EF329F7A163EEFF1F6C5
+:108F0000DB7BA7650F5507D40A6C0F72BA12C757DF
+:108F1000CF34CA697D1EB67017EB45FD02EE77DCD3
+:108F200082AEFC9ABE847ECEA77E34795FE5D3E91B
+:108F30008AF777BAFA06E09BAEC137039F66F8CC92
+:108F400078190ECE9B104EDEDFA5897026EB4FF709
+:108F5000AFF575227D9A10D75938A0AFAFC0FE5C2F
+:108F60006B6C31E61BE05F5D5F83644AC5FEB7381A
+:108F7000781C75CBB2BB6A31DFA0F356B91C519295
+:108F8000BB94EB39655921C555AFD1FA35C3DFDF45
+:108F9000DED1357642198DBB1CC7BDA08675A3DC1A
+:108FA000C8403B81E20FB284F1852C674700E3B2F1
+:108FB000EB858E8645A8472F7493BE6581B996F1DF
+:108FC00029FDA9C79FF479B340E530F55BA8BE9CA5
+:108FD000D6D18476D288EB3B3B2CEDAAEF6B76158D
+:108FE000CC6FFD90780DF828BEA5E377F0387CFDB6
+:108FF0006AC34D02E23BB50C8604964C0D77D066F1
+:10900000ABAD38CE7AD17E2A057AA1FE5EB38CFB59
+:109010000DF4B75687EB01A4C72F0B975E2FF97895
+:10902000BC1EEE9F51BCC3CDE5167D80F2B167BD7D
+:1090300096FB07FAF3F666599540FF1C93950C8C46
+:1090400017DEAEE941C642814B3DFFFE7A03F3884D
+:10905000F378A7A97E9471BA670117D97718864F5C
+:10906000A49B577DDC1F6DCF0E3FCBE56328847436
+:109070000DE5E711FFCC05650F95F75359EE2FBFAE
+:1090800044F503BC3E93E511E119DAFD81DA49FDAF
+:10909000FDBC41FDBAFBC73D48DF7DFDE53FD2F792
+:1090A0007C5E7FA4E324AC2B9F7F8F48F3FF445268
+:1090B00033707FF4B2E8628A13CD8F5E43CF75CDF3
+:1090C000722DC6E35E6AEE6B6B83E765F317CB68C0
+:1090D000F7CF5F7237EDDFEBFD5F827E05F2BB22DB
+:1090E000CD20BBA8C816DEE61EE0B70138DAB43CD6
+:1090F000B3DE7AA42397CAFADACBA1FDA48FDBDA18
+:109100000C794E1D943F93A2489F26C6D57539F819
+:10911000A143FD94E63F723A36CD97B1BD30FE27AC
+:10912000EEE2788CE8BA4EB6E2177DDEC9FAD7E7F0
+:109130009D4CCEE8F8D3DFAF2FAE9079FE4FDC80A8
+:109140009794927ACAF7B944D0E0F4B8347EE3F544
+:1091500066C1384F94117D2848BFB3343FCEAC1759
+:10916000F4713F74448AFCD80EDEDC5A6181DF1151
+:10917000E2ED40F3D270BD1DE571570AEDDF339982
+:10918000E2FC7ABD8624F33FDFCFF50873AA349F53
+:109190000DB765C4D1EED8D0F82B19832B69E33E07
+:1091A000A98AE153E83BB108E5CB6D1ECAC76868E0
+:1091B0003C51D592D0FFC2A7FFC385F1DE8671ABCB
+:1091C000FD187759C8A44F12F31DCCE33644AF27DE
+:1091D000BA8DB5080D56FED61BD99CAF17628A8C86
+:1091E00048FD1D49DC476E542A1C189F688C19F7EE
+:1091F0007340433A903E16AF33BF4FD8CF11B17F83
+:1092000046F38EE1661EEABD3536A2B72D8037F4EF
+:10921000030B415DE2F38DEC2C8D1F7B089FFF6EED
+:1092200078DEC896F9BE9B8BC5D2B206E82627D257
+:10923000C1503F792A05DADFF479F4FC882ED25345
+:10924000F7B8F532E82DC07FB84CB3738AF9771BB5
+:1092500096D1FF49EBD96B033E5E73EF531705C6FA
+:10926000427F6591804DA6F2F3921FED2F5E66B1AD
+:10927000A79EDF4BF6AC7C961002FE6FDBFDFCB3C5
+:1092800005E4CF6BF6D8EEE7C91ED3CB8C753398C7
+:109290004F676A7F597505A03CBABF1CC3F256CD13
+:1092A0008E5F73EFEEE7DBC83E09C7FC097AB29622
+:1092B000F1F8F257AD1F3B035776603E51ACD846EC
+:1092C000FE5EAA891F1FF13BA85E514EE42EE2C745
+:1092D0005BFB248C373882AFF9500E8C2A3EA68E69
+:1092E00006FA1F55C3D36458291FB7B37815D90D93
+:1092F0009DDABAC0FF56A3DE1B589F1ED3FAF0F5C5
+:109300000857F6D0FA78CA7A68BD6C58A6B81FDF3D
+:109310008FBFB892DB1BB293EF2B6CF7737ED8E153
+:10932000E7FEED0E3FF74F338AEFA2F84ECA0C1B53
+:10933000D5CFD09E6639BEC32F69F29CE3637730E8
+:10934000D2E54FB05BE17DB8B412E59B2F0BF75926
+:109350006B8BA51B919E7FACF9A7B04E77D23A15C7
+:10936000F952237CDD7EE3F75BAC5BE9C8D6EDF513
+:10937000E608C9AB64EB76D97C316C15777B5EC3AC
+:10938000C3470D7FFA014E67B9ABCF81FB30EB8B42
+:109390003719F2AA5D3B6677632EB49E57BD3A2D0E
+:1093A000BD06E5B679DCD73FFF2F1FE277E6BF9C0D
+:1093B00096F2F1634D3EBED6DC40ED608115299BEF
+:1093C000E400E3792FFD7962C229274DEF75CC4384
+:1093D000BB82589FB1B9E1C3B45FBD282032DC1F06
+:1093E0005FC88C79652CAAE705F33CD8D725704D6A
+:1093F0000185AFC78410608A354AB375B962C80F5A
+:109400009B3777F63EDC875FACEDC3837C317C5FB6
+:1094100062CA1BBBBCA1315CAF7D3F4E7FC7094F09
+:1094200073156E37CE75BB49BFCE0BCF0FD727EC68
+:10943000C7BDF1DFA2651EFAF9D93A5EC2E1FA9220
+:10944000C1785914161CB2323C7ECCF8A89538BEAF
+:109450001A357C99F163C6C3E2B9B369FDCDF37FD8
+:10946000DD1526FCBC0EF8C17C61333E188B5C8C8C
+:1094700074FBC67C91A17D3C5D9C69C73C81C5B3F2
+:109480000586F9454B58289DE707ABB3A625C06B69
+:10949000C6A3195F8B9F64A16EE877F1BD1E5ABF0A
+:1094A0005734FC88DD7FA77985615EED7C5E477867
+:1094B000FEAA4CF3BA542D7FC607DF236D206D152D
+:1094C0002B3DC2E7B308E6D32E0FD62727584D13FE
+:1094D000D2C91253DE82193E33FC33510E4E1EBCEC
+:1094E0008F5F91ADEDE38F67216D1F3F838E3584D4
+:1094F000FC43E62D0CF039A7AF85D1D9FDE361BF60
+:10950000028BF49765C0EFCCE7BC1BE7C1BF5705E2
+:109510004405F30467CF1FB306E71F66E18CEE2214
+:10952000B4F7FBEC28472E6560C642BB0B6092A8DF
+:109530006FC3F52954D6FB3DD6F1B19DF47884353F
+:109540006DA7FD772563EEB8E4F26555C041E39958
+:10955000ED9499E52519282FCCF8D0F1340FF1922C
+:109560004678197F3A7879017515FAB318478375EB
+:10957000ECBB86B107CB07F68F59BECAEDC96C4666
+:10958000FBFFD764676A764713C51D16687AE190BA
+:109590009D353CEEE6FBC81509F2F11BC1DA6BB252
+:1095A00013EC547D1FD9CD7A097F57B8DCDDE27802
+:1095B000A2BB0FFBE983E4979EAF19A17C4D3163F9
+:1095C000994271B1B4F4F12C03EC62C6E70D7ECC84
+:1095D0008DD97E7C5F18472360E6733F59374F195A
+:1095E00058B7F5576EEF40799CB2E49731EA5CE1E9
+:1095F000F91C69DABAD56AEBD66F4797C2FB04FC4F
+:109600001EEBD0ECB0522D8E8F7FA07CAC588D0F0E
+:10961000E5BFEAEB98520AFE87218FB083F0ADAF29
+:109620002738117DC89791804439C336E622FF3828
+:109630007233CFC758C894AD981FB4306A3F96D8DC
+:109640004F2428111C91F5295ADC2444FD2C0AF2E0
+:109650007E5829F7F3FAE93E06ED13F21F6D2E301E
+:1096600025B17D260BA1FF04FD65A3BE67EB12C6E5
+:10967000193D78DC64FD99DB89DAFEADE80C8542A2
+:1096800009727ABB663F1F0B5476D94627C7DF2283
+:1096900097579512F2628F045D0D567131BD3F5D93
+:1096A0007FF7DB89ECEA1712ED44B7A3F18567CFAA
+:1096B0004FB01359E30BB8EFFF45EDC497B21B5FF2
+:1096C0006883F9FDF3ADAF51FEF8B12610988047DD
+:1096D0006F742A3BEA45F92093FE2A6C008F0A93A7
+:1096E000BF25652CD27B4A344F9512F265DFC856F0
+:1096F000087E6FB14AFB65D0B40B5D71AF141210D8
+:109700006F7769713320DCB1B33D89EDF8BCF5F1B9
+:109710009C2E99E070E8E3B1500BE5D7CF64A447E5
+:10972000F43C109DAFF57E8E661BE37523E0E7A346
+:10973000D9FEC1FC2C8A4DEFDC8672E20591FCB0AB
+:109740006F056EA6F7E678C0DFB2B97D582046FEF9
+:1097500086FDF434BCFAAD9BA0DD8A1DCE10AAE1D3
+:10976000E5DFF9E0FB550AE289AFFFFC258BEFADA1
+:10977000C279954832ED6F14F0388CA34520FF353F
+:10978000A5C811DE01CFC3BEDADC9C04B80EFBEA2B
+:10979000A93C7A0687EB18F4D9AE60BB4D0DE42FD7
+:1097A0007AF8BEF73145C960245718D913A2933F00
+:1097B000DD393C2EECCEE1F13C2987E3DB7552A08C
+:1097C0004542BA6EC27D0B294679D0AE9312BD7761
+:1097D0000882A5BDA6F7E73A09C219F195666EEFB2
+:1097E000A0F7381F6C2F7A99C1BEF1E7703BD9DF23
+:1097F0000F471A87C36BEE279DBFD7F8CF0CC78AD8
+:10980000ECA941C4CB619F9A9BC3E3285C0EBB9F2C
+:109810003F208C1F893CE6F9FA17072517C5F56E1E
+:1098200013E225209FDA4B8FAD21B955E46AC2734C
+:109830005209F693C0CFDDF0731503F669DFB43932
+:109840009518BD66CAFDA1C1F6D63B9527E6CDC1E8
+:1098500082767EE20A5DF6C6A00CF6DCDB5AB151D8
+:1098600019BD1643FD97D470FB6C31DA6721925B0A
+:1098700006BBCB6C9FB941DFCF01BA58129064A4EC
+:109880000BB39DD65E398FEC9A76B06B305F7BB0B0
+:109890009DC6E5CD1D511B53A1DE4B3522F9192F75
+:1098A00095F63E7701EA8B497685F44569DF1D73AD
+:1098B000E8FB041AC7ADF977509F9F7708A5C54B01
+:1098C000E0DDCB3547DD8B13D6FBA54947C7A25F4B
+:1098D000B035497E851EA7D97B0BCFFF7AE71E21C5
+:1098E000EE44BCDD2ADAB0DF85E51ECA5B9D26BAF0
+:1098F000699CC51BC5B89370A8A64FCB1EB01B9919
+:109900005893FD2AE2E14E3BC3F3830537F61AEC88
+:10991000DC8551A33D176902FB47397D3BD06CFFC5
+:1099200099ED98E5399AFD52C12AD07E79A9792717
+:109930003B5A3260C7CC4AB2FFADDB31E7DAEABE50
+:10994000ADD133ED1FCC92ACF7F72FD6FC5316E216
+:10995000FEE034F1435AAF63214941FCB96F7E9E6A
+:10996000CE75B8FF5B0C5B8D77478E43DF8F237915
+:10997000BBB5228DF2AEF7DC72564E2FAD97725FFB
+:109980000DAEFFF3769283C9F45B4A5464C530315F
+:109990004F54A0A7BE9EA3A2292C513F8C4A92A748
+:1099A000F0A31C3E0FFFADCC867E76668CA9567E5A
+:1099B000A95E0FFCD1E918A386FADD9900DFF5C591
+:1099C000368AFBEB7E698A9D9FF7B5EF5A1943FFF4
+:1099D0007414C0877028001FCAE1A2681A9547470F
+:1099E000BDF41C13CDA46771348FBE9744C7D0F368
+:1099F0008C6811BD3F337A36954BA313E839365A3C
+:109A00004ECFB3A2E7D1F36CD05B58AF2C5A4BCFFB
+:109A100071D1AFD3FBF1D139F43C273A9B9EA1E839
+:109A200037E97B7974313D2BA28DF47E42F43A2ADA
+:109A300057466FA0725574253DABA3DFA5E7C468F8
+:109A40002B3D27455BA8DEE4E8062A9F1BBD9B9EB5
+:109A5000E74537D1B326BA85BEEBFC9CA6D9D32FF8
+:109A600006B6C9946FCFBACB503E26E3C3439A3CA7
+:109A7000AECB51F722FDE9F5F66BE70ECCF50EE41F
+:109A80000C9D77F3AAB65E1F858EFC008FD3EAEBA0
+:109A9000B63E30741C8195F986D9B7E2F37B3A471C
+:109AA000E1F42B7590BDB1B589513E98A7B24740FE
+:109AB00079D319906658D1913BC0F3C08A7222477E
+:109AC000517FB883EFEEC5FDA84B623DBEA9482F7C
+:109AD000215FEA54E86F549B8DDC6B85C902969533
+:109AE0007A2677B381780ED85706BD260574FBAD6C
+:109AF00067E60484E7ACE20AB25FB5FDE4FDB78C2B
+:109B000066E8776C75740B12CACB558C25DAE15B6D
+:109B1000D72E7A28F19C8614E0FC396A1D7B0AE373
+:109B200064451D4A1D9E271CB3597D0A533C4BE2D8
+:109B300091BA54289FF970EC297C8EED8AD7A5C183
+:109B4000F3EC9DDD4FA1F819D7DD5BE786F239CF45
+:109B5000B2A731FC54DEA34CF54079C201F569DCB3
+:109B600026A9EA8D4C4D57109E786B3AC0B3F56D1F
+:109B700030B4A03CE9C30E11DC9281F507BBEDF1D6
+:109B800084754929EE5145F867FE8D7239CAD9AD01
+:109B9000526F4A66D9E0F5E9C479E33C41AF6CD72E
+:109BA000F6D1E584F50805043D1EE80B24C4033B0B
+:109BB000DB5EA1786067AA5C8BA1AEBE694C7E506B
+:109BC000413AE67E42EA9AD1A49F74BA03FC1AECA9
+:109BD0004929C0E96E6BBFBD698DDF10E2B7EA7F2E
+:109BE0000F7EFF3347935F49F0FB22CE23383C1FA3
+:109BF000D706385F021F9F1FA84A5EEF2A0DFF6637
+:109C00003C6F95E4B3085F6E668B950FAC5BA34623
+:109C1000DFC3E1F59BFFCBE876526068BCB24A2F08
+:109C20008F336BF969C9E4CDFE24E7449A0283E4DB
+:109C30001C8F97CA20E7C6249773358161E4579239
+:109C40007C87DB027ABE43F8BB8111C4F5EFB0C953
+:109C5000B598EF121BCFC84F00FBB20DF37746C586
+:109C6000940ADAC642A18C78AC389BFCF422B03757
+:109C7000A40A86A98EDDF8BCB832D3B6A80CF31AB4
+:109C8000347E931B0389FCA6EBFB017ED4E922AB57
+:109C900093CE5900BD623EE12E0D4F03FDF078C416
+:109CA000DA9B733BDB13E46067288FCA7AFD64F4A8
+:109CB000FBA6F61DE405EDF75F5C639D6FF2EB809C
+:109CC000A8D9397D2AD2796C0A93E9BC73DB119249
+:109CD0004F99209F84221E1EC2F1F3A3A90F619CFD
+:109CE000F657816C4D9ECBA99779FEFFD1733BF857
+:109CF000EAC44F35F21E3C57310AF4908272B20624
+:109D000060AF443DE7A07557185F47A586C5BB0502
+:109D1000C25B37FACD311B3F9FB1DFD1A592DE7117
+:109D200064CA987FB2CB1FD91BF027E70B394D29A6
+:109D3000C745FDC3E66B67BA83989723A762F915F9
+:109D400028DF3109F3847A9956BEC33DF98BC71FCA
+:109D5000FE10B8663FEE535507D457919E81AEFF73
+:109D60008070A967CA12C58747B8FFA4F3E7003F10
+:109D7000C9E53A3F3596913C7C2790B04F9ECCBECA
+:109D8000F9A1263FFB0243DB373ADD9FB67DA3C135
+:109D9000FBF630FC3FF3B957376F6303F13F4FEEEB
+:109DA000EB3D9282F6F654767402C6BD7A38DD3306
+:109DB0001EE75331FE07749052E932C56D85195A7A
+:109DC000DC65C878AD1E4FD6E37D7A5C2F5DA32B92
+:109DD000BC3000F578FA24595A44FDF5B24BA13F46
+:109DE0004F90E349E76B945BB83FEF5A93258D2E74
+:109DF0001BE8172425C9A9CE0626B767F2FDD70CA4
+:109E0000902F1DAB19F979B19744EAFFB86AFBC0EE
+:109E100009F58E570202512EA84C91B3B573084430
+:109E2000E432D1AB93B12EF4B7D9F7422E07C6B9BD
+:109E30003F15980A70EFFF54A4A784116E687471DF
+:109E4000A83C848D6B336A42B81F281E8532C059E6
+:109E50009F519381E5FDFB27849845FCEEF248A3D2
+:109E600021BE64C6537FBD6FADA17C852DC3EC7F41
+:109E70004E0A3A74BBB32288F6CE957D6D0E6560AE
+:109E8000FF53DFD70B163F7121DEB3135CC6EDCF56
+:109E90005C166F49B49B12F6176BB09F2D03FB8BBA
+:109EA0003D6724EE2FAEC8BD158FEEFFB07F7F312A
+:109EB000720ED657BD5DE5489F7A3EEC7E07DF0700
+:109EC00060135EF02916F4B1A0FC193FD1A3E64F50
+:109ED0000CFAAEC5CDCC7EF0ACA0318E7F3C3427E1
+:109EE000A31B3F2689E3EBF13CDD0FC6789D6CC9CF
+:109EF0007746FCEBE32F10B81FCBEC02C93B5D6F3C
+:109F0000823C8904FDD48CE2D1AA53A07CADE3A1AC
+:109F1000C50AF94549E44BFFBE01EB2EB1DA675D96
+:109F2000A0E59D98DFDF1CE4FA79819DC72985951E
+:109F30004B2238EE82A04B7026D8495705B9FED285
+:109F4000F75F1CB927AB10CF0E4744B19AB7791F02
+:109F5000E5AA20EB3FEF16B2D07BC9F074C0DE411A
+:109F6000FB72079688745EF7786422DDFB904C2EB6
+:109F7000BC89F453C25838978F37B08ED678D3F354
+:109F800064CCFB55FDDF1B53E8FC8D395FE6510DBA
+:109F90006FFB34BCFCBBF365F669F87B518BCFE8F3
+:109FA000F1AC8B93C8FB736D750F131D0D139739AF
+:109FB00043CFF7D1F0C39E1E4BF7726CE8B1C75385
+:109FC0000484C746FB970D7F1043687FE9EDDC26CC
+:109FD00079A1E7EFE8E5B493028B27EC23A4495D70
+:109FE00014274D3B29D17B33FFDD6EE23F7D5D922F
+:109FF000ADB3BE2EE6F79DDABA1C68FC8F009E77E3
+:10A00000D990C22CF3893E0B1AE3EFE63C8064FB47
+:10A01000DC07B576C7239373502E3738622523E1CA
+:10A020007B1D3FAF7FFE1B17F2D98693CE1956EBEF
+:10A03000F14A90FB2DA04FD725EE837AE6BFDA8652
+:10A04000BDA649C67D505D9FEAFBA06995E67D34BB
+:10A05000EB7DD00DCC5A3E26DB071DB4FFA9E9DB12
+:10A0600013C124FB9F65439F67DFADD1F370791F58
+:10A07000973BF87959F3FB17FAD7617DC10F80AF91
+:10A080006E6874D2EE5377A393F87071630AC56556
+:10A090001797F378EFE27B056DBFCE18877D11E44B
+:10A0A000C5323C5FAFE99DA32C5C8DF6E8AC4AC19C
+:10A0B000B04F1EAE493194E72FB9FB45BC37E1A53F
+:10A0C000497685E2CFD0570CED821A9EA7C894BE80
+:10A0D0003B30CEADC79FF5F57FA9E628DD8316039B
+:10A0E0003BBF2484F16791F8EBA5D726F07BE98488
+:10A0F00081FD7005EC840DE78EA17C8F8365DFA068
+:10A1000038EF068C8BC34C377CFE9B194447A094D8
+:10A1100063C8AFE3B3E2281F178FABC846BA7C7A97
+:10A12000FCA71E8C8BBE73EB713FAE536F7313E5B0
+:10A130001D98D7DD1C6736C7974F379E3C31B73F18
+:10A140004F80E8E145533C59975766F991104FBE4F
+:10A15000207704F1645D6EE97242975F07CBDADF26
+:10A160007A10FE7930E22498DED4E6DDCF971A5DCE
+:10A170001ED4F9F07327D9234F8FFF2DE55BE9F546
+:10A180009A8399C487DF288BDB697F16F3144A070B
+:10A19000D6657EE49AFE3276FBCDA52B0DF4D12F49
+:10A1A000A786956343CB293197C72792E56BEA7C55
+:10A1B0003058FF94909D9AF67B7BDC55F4C5F550A2
+:10A1C00043E3AF146C07CFCDD47EBC2312B7D04F7E
+:10A1D0006678D24E8A2C3E21F1BDC2DFF7EB010733
+:10A1E0007D8FD529AB57FBB83DDD4AFC1973D2FEF4
+:10A1F000B94F6DCE85FA3EBF1A437A78C8A7B6E448
+:10A2000026C8D3563BDF8F146D2CF2B8055E9ECC6A
+:10A21000D5F4320B07B0BF35B5C6F35CFA737B2EAD
+:10A22000DFDFDBE3AF0EA07DDD7AB83C80FCB3D787
+:10A23000534DF676B275BB53E727945F2503FEC4F2
+:10A24000466DBD814555DCC75D630F0712E38DEB9D
+:10A2500072791E47FAE4277AD06E6E956D9427D8EE
+:10A260002AF3FCEB36B734639BD6CE676827E9E761
+:10A27000A8E8BE0CC96DCCAF7E52B37792CDF3C9BE
+:10A280005C9B76BF68F73D35C2805EB11FA975D172
+:10A29000FD0F4C95797E53C8904F6DD7F44B9D2997
+:10A2A0005F4394BF98DF16F44776E55AF86D7B7CE0
+:10A2B000EA93B8DE5129E644FA88BAACF9FE696D32
+:10A2C0005DBFA7CDD77CAFAA68BAF74134DDFB10DC
+:10A2D000AB6BFA692FD2DB6AA7DCEAA37B1EE8DE50
+:10A2E00087285EB904CF7FA6F07C16F0FF26F2F334
+:10A2F00006A15E94AF2CE0A2785447BEAAE643596B
+:10A30000F4D81E5C0DFDB5AA752A1E5DE970DB3A16
+:10A31000719F2F33183988F398EA9148EF745C9451
+:10A320004A7A08BEA77039C264A19AFC41BA3405C2
+:10A330007D703C5F660F38289ED51A61BDCE31FC1A
+:10A34000FC3FF653CBBAF7D714A1BDEDAA443CEDC0
+:10A350000F4DC88858C809FD69DEFF7FEBDB6F141D
+:10A3600062BB0231F221E2BDA761F146DCD75FB1E9
+:10A37000530CE13EC2B7BE73F00C7EDEC8B8CF7C92
+:10A380005FDA945ED46751B783EAEDF15477209E8B
+:10A390005A054F07FABBAD8757FE18F1D8DAC2E36A
+:10A3A000DC663CEFF57C87EED7380ECB89F5CDF730
+:10A3B0006BB08E957C9D9C2EDAB784F9B2BC2ABE18
+:10A3C0008E141F3CE4A17BA08EEF7FDA8DF07D8997
+:10A3D00079A7E5F9879A77BE4CF68B463F4C0AAFD2
+:10A3E000C379DD247A3ADA7D784F1AAC37C2BDCB17
+:10A3F0004EFEFE7D69E9B4AE51800FD755F4D4AB63
+:10A40000E892FD7DA748EB1C959A685E2C26B1ED7D
+:10A41000F87ED789EF9F8774A066D1AE9658D04456
+:10A4200078F93BE065B5055E807E8A10DEA777DDB2
+:10A4300040FD74385C325A36AD9E6A3AAF3CD2FB6E
+:10A4400045CAF2389F24DC2F52965765515FF3B30B
+:10A45000D0DFC6716B65F6499C0DE03D59FECA79A7
+:10A460005AFFFDFD0C9FBF725EE2F8FAB85F625DB5
+:10A47000A79FCEBAB6BAFEEF74B4B354313D94522E
+:10A4800008655C27C43FAE13AE9716B72115A4200C
+:10A490001DC8DD79480737A487903E87931B12E3D8
+:10A4A000EB6E97809EC1AE73CA91037476518BF7A1
+:10A4B000E8F2C4CC67AD2EA3BC6AD5EFE53B3432DD
+:10A4C0007905F47215E2C12CB7464A272BF304F341
+:10A4D0003D342BF3FCC9E9C41E0CDF80EB8878CA3D
+:10A4E000ABA078C5B7B1FEFEFDE20EC7681C8FC7F2
+:10A4F000CDFA824C7E30212F4B87A70D37BB799C3C
+:10A500009AE21F5203639807E72D0D0972D988E874
+:10A51000A82D11BEAF808EEE1C8A8EDCAC87CE6B70
+:10A520002CD7F373760C9D9FF365F50FAC6727E28C
+:10A53000B7D5F31DA2CFB57697CCEF513BBD757D56
+:10A5400064F0BA3E32F4BA461EC3EF6A5E35DD638C
+:10A55000C4263592DDB4CBAFBE8179A44C0A19E490
+:10A56000E220FED1E4F64D672A94AFBABB4593735F
+:10A570002D4E19EDF1677C373C86F5EF624A18E302
+:10A58000A1536CAB084F7F87F93D1822B95A8AFB5B
+:10A590003E51961AD2F4E8538887194A8B9005EFFA
+:10A5A0007D0B141B5D43AA6C62B6B291E3E1C5C199
+:10A5B00072F0C561E4608F46CF37223DEBE7ED9343
+:10A5C000C9C143A72F070F7DC572F0CF79A7A1D7C7
+:10A5D000BF0279F3098E6796376E8D9FAF08B11071
+:10A5E000C6CB479ACF06F6A682FC559BEE22FA69A7
+:10A5F0007D5CA07C29B0C32354F6B848D8ECF5386C
+:10A6000078FEEF0EFE5DACE37836E3E9F3BC2C9EFA
+:10A6100077D3B5322C19F2A462C40F77AAC7E462CB
+:10A6200011F3FB6B889EBD9A3DA3E7F5A76BF2BFC4
+:10A630005FCFCFB4D178DE022EDFBD60EFA05DC466
+:10A64000A45E867EFC4D793C7F1FF881E81B46099D
+:10A65000233F644C924C795A9C5FFC12B777327D51
+:10A660004C205D837962F0FE04D813783F41A66ADE
+:10A670006C7753EA1502EAADDE46779340E7F4C300
+:10A680007B7E04E52CCCF702BEF1CE30D6F7B38446
+:10A69000B2857F1EAB63A598B75896AFF9E90E1641
+:10A6A00020FDA8F9E9FA7D81E2F0795F95F9238828
+:10A6B0002F9E9BAFE79918F571570AB38CAFFD57E2
+:10A6C0003E975BF5BDB5756857AFF230B2AB56A19A
+:10A6D000EEC472A683EEB509EDA97459DD5791A9B0
+:10A6E000DA0CF7F37A67A41AEEBDF587B30CE59C94
+:10A6F000865C43FD6064B4E17BDED2B30CDF0B9A71
+:10A700002A0CE551D1730DF58B00C189E531EB2E93
+:10A7100032D42FE9B8D4503E73F3370CF5C7C617BF
+:10A7200019BE9FFDF0B586EFE3BA5619CAE7ECBC37
+:10A73000C550BF9559DFDFB9219FCB29E0779263E0
+:10A740002DEEBA06FA1D0DD96188F32FD1EAEDC9B5
+:10A75000AC2EC57848EB91F252F287D3CF1DD21FB1
+:10A7600036CBC564F2D8FCBE4D1BEFA3A7DEAB5EB3
+:10A7700086748E421EE4D247EE37D7E29CD697F11C
+:10A78000BC04FD7731CCF7F2F7EF534A2ACD67418D
+:10A790009683599D0F5892AF58EE2FB4092117EEAA
+:10A7A0001525C39B4E8FC3E1ED0EADDE97C5DB21B2
+:10A7B000C11807427DF2B8055C7BF3FBEF3B7828BC
+:10A7C0009FEBABCA54F230F83D0EA7AB4F74384044
+:10A7D0009F3C9EEF1F9C1FFE51C3AB57DDA760FD42
+:10A7E000AB787D5BA814D725D9BED2DE7CF3BE52F0
+:10A7F000D55294730B3CA942E27DCDBFD4EAE9F176
+:10A80000ECD6F44F695FA9D5112A1DC9BED22FF12C
+:10A81000CE8D2AC4BFC2C7D3D7D5AE06644BFFCEF8
+:10A820006CC7B0E7F01E8C985BA2BC61B37F17D5F4
+:10A83000E4B6EECF497B6BC9DF6F758FA6BC8F5630
+:10A840007515E9CB8E247E2EE8CB3FE657613CE0C0
+:10A8500046833F37100F50693C684B76536B82FF3D
+:10A860008FEBA0DEC7EFD5FE0AFCE00FF34FC34E1F
+:10A870005018F7838F338EA7E3AA8DEC84E360270B
+:10A88000A0FC5D2331DAF78E550A8A955FDCB15A58
+:10A89000B30F5773BC99F7BBCD76C6C5A19584B7E6
+:10A8A00035404FAE4A8CC771FB778D9DDFBF297B4A
+:10A8B000C301D4B77D7E077B10A0DDEBE7F1391D26
+:10A8C0002F5F541E65160CB293330B86B093A78985
+:10A8D000655D786FEBB1933C2EA2E051441FDE43DF
+:10A8E000CED76FD57373622B504F15494D98BF2E3D
+:10A8F000322503F1B2E25991C5059463C6FC7C3B55
+:10A900006BFA01C6E3988FBF8F31570BDA49199361
+:10A910008C7A2C5335EA31EF8C2C935E33EAB19C60
+:10A9200006A31E0B468C7A2C6F698549AF19F5D8A2
+:10A93000A8689D49AF19F5D89875979AF49A518FE0
+:10A940009DB9D9A8C7C6C68D7AECEC875799F49AF9
+:10A95000518F9DB373B5E17B7977BBE1FB8467EFE2
+:10A960003294AB7AEE37D49F78E041C3F7C9BDFF8C
+:10A97000C7F01D10FD0A9E67C07B687111CF7BFF79
+:10A9800009E377A63A301FFF3A3C9F09EB787EDF58
+:10A990006F0DFDB10E7E6E2106FFE17AFD9945E84F
+:10A9A0001E009063FBF2A0DDF57121D4CD503F3D38
+:10A9B000FE1EEEDB5C1310C98F5B81C156A4874776
+:10A9C0003C71A487AB371BCF3F5C13379663403F86
+:10A9D0000AC615807E90BEAE33FD6E04D883446FE8
+:10A9E000D7295213DA9566FAFAB34E5F31F5153C62
+:10A9F000CFA1CF579F9F5D3F7FAAD19FAAD11F13A1
+:10AA00007711DCD7E589F4FB3BFA7C55F88F7FFFA3
+:10AA1000D081F338B153605EDCDF67B17D7916F326
+:10AA2000B97EE72607F2A7795EE6790CB2530B8C64
+:10AA3000FB8AD3447788F8EE3591F4114D01F9EC97
+:10AA4000517E5E6FD573229D8B413E447F418C3594
+:10AA5000105E56005EF0DE70DD6E3DA6B53BF68002
+:10AA600048E79B87E34745C3873360E4C71425D590
+:10AA7000444F46FCA6951AF9F3BAB72F74A0FCDA36
+:10AA800007F8162631E60919F9F53A7119EDF3E9D7
+:10AA90007856E03F1C57025317E77D3DCCBB5B194E
+:10AAA0008CDFA5BB36ADCDB3A09BE1F0FB48817137
+:10AAB0009F4EDF9FAB05EC382CF24A75FCEDF2ABF4
+:10AAC0004FA07C4CE60FEF2E30EEAB8FC01FDE9D0B
+:10AAD000286FBF027FF8B98221F55CDF2CF4A79CB8
+:10AAE0002C3DD46E11F79398DC8DF15A7B138FFBBC
+:10AAF0000DC4EFBEF238CF3B08A724733D9922E97D
+:10AB0000719ED08108DA27196785302F6AA4718E6B
+:10AB1000BF140C8A73FCA560E838C71B780E50CDB3
+:10AB2000C8ADB7213349A152BADF1941E079481FB6
+:10AB3000E3BA0CCAD72DCED2F28F9521F38F2FD640
+:10AB4000F677AB03EA498403FAFB149FFDF7B1558E
+:10AB5000FAA99FF461FA89D5717B2D66F374B472FA
+:10AB60007B8DF699BE8238467A21FAA56E8EFF5605
+:10AB7000078FDB9E6E9C2D583808EFC1C221F0FE76
+:10AB8000CFB772F8B9D5105807E5C9E95B3F87A977
+:10AB900097D7671AFDE5B5151CAE126DFC6F66738D
+:10ABA0007F607221E73F3DEF12F316532AA03C93DA
+:10ABB0009F53D2CFB5EAFD4C2EF450FD4F02759352
+:10ABC0000BFD9837CBEFDF599B69BC87E76F05B565
+:10ABD00093715E13B4FE2717329ECF3C9AC365CEA5
+:10ABE0003BFD8756FF1F0575F4C473B4E8973844DE
+:10ABF000D1129F530A799C40BFF766BA7E7EEE5E03
+:10AC00007EBECE7CEF02F0C9EBF8FB5047EFB0936D
+:10AC1000BF07FA88CECF2DC9E3E710CDF729444A04
+:10AC2000E57D285E4FB032CB7B7906E5391CBA99B9
+:10AC3000F2EF5E9ACC6421387CDEC36585C6FB11D9
+:10AC4000BEC039BA2B0A4790F7B0503B47D79BCAD2
+:10AC5000F5585FD0157FD0C2DF8D6AEB7487E6D7D9
+:10AC6000E2FE34EE93E3FDDE56FBE5D1424E3F2398
+:10AC70003D577D97231241BE359FAB4E769EBAD786
+:10AC8000D1BB2607E11DCB4268BFE72C90F7E4401B
+:10AC9000BDD47A85CE3FAE2D62E993F07BB92D8489
+:10ACA000E73A32E7CA6BEDC8A7C52C4B80726F6CD0
+:10ACB0000E8D7F4703934580ABB390EFA32FBCF578
+:10ACC000631ACF5F035353E8DCF974F4CF620D8C41
+:10ACD000EE2D34CFF32E8D5F5C6BF83D3919C5D660
+:10ACE00079F87769F408726B13F2456D31DBC1CFE7
+:10ACF000CFF2730A782D3DE56F8652695FF01258E6
+:10AD000037BE7FDE43EB776360EA7DB89E3ABF399A
+:10AD1000B43C05F379F2CEC2D33B4F9EBAC01ADEE3
+:10AD2000DF69EBDDE80FFF14E14D2DEDE0BF5FFAC9
+:10AD3000F9A95362B5F6D38E0AB68F4450FFA580A9
+:10AD4000FE13F0A9C8748E96B9043A0FEB529A8894
+:10AD5000AE522685BCF8BB68EC4A1BC37B5CA66A76
+:10AD6000EDD50626E0EF49502E20C969D3EF4BA858
+:10AD7000A1B616683F0DF7CD4298F71D5A8AFDD54A
+:10AD8000BB53658C6FA61437D5E27A3DB390F7714B
+:10AD90005792F312FA39FB81FBA796BDBCB726E1A7
+:10ADA0005E81B557BD6CBC7FEAAA97BFCCFD530747
+:10ADB000B75EF5F2FFC4BD02BA7C03356447BBFE43
+:10ADC00080C8EFD1FBFB9397DB711DD6D6B22EC4A2
+:10ADD0007BEC53C0B36B00CFF6BAF0335BD02E5987
+:10ADE000951EE2BF2712FB16C2F9761A93B1BD9EDB
+:10ADF0006F28B052D2D7731B04B21F98D4773D96F8
+:10AE0000E7EF4A93D17FF8FB936F14C4803EDFBA1B
+:10AE1000EDB807F353DF91FA3C08D7FBB7BEEA4120
+:10AE2000FCBD75AB48792874EE3B214FEC738DBEA9
+:10AE3000168C0A1F47FA5AD8FCDFD589F6198BFA07
+:10AE400049DF5F13078813EDDE87D30CBF2BBABC35
+:10AE5000CB6B28EB7A7EB9D3FADC7CE5282E97AE53
+:10AE600079A4D391A7E0F811FB2898E7FBDA39A081
+:10AE7000F77778C88ED7E159F448B903EDE17776D2
+:10AE8000395937C5057BECCCCDF507E65D44F8D0E4
+:10AE900083E0DCB73BCF817CB644607D4E626EB60A
+:10AEA0000FF1FD27CDFF33CF63C95BB203D77749DD
+:10AEB0002DEBC373678B6E14D6DE04F51745DCE407
+:10AEC000F79BE769D63757E37D3682D53D704DFB5A
+:10AED0007E07FD5C09FDA0FDB9A4C3F8FDD8B3371A
+:10AEE000ECDB02E3EED8E9207BF1EA61E2FD6347A7
+:10AEF000697AA99A4D3C3586F45FC63825B9DDA13B
+:10AF0000EBA3F79B1925A9FC057FDF179E1F36CB06
+:10AF1000F43C5EA8D07A5CB773CF3EFA6D61A9A706
+:10AF20001AE5DDCCE716A77D830DE4155577DEF035
+:10AF3000F41662053D5FB59BE27B13B5FB5FAED6B1
+:10AF4000CE7F541D30E7ABEE79E67768B7C1FC4F92
+:10AF5000E7DE9E0523BCB7E7D8B353D3E87C808EE9
+:10AF600097898017F1CBE32559BBE5497EB745E7C3
+:10AF7000A7E39ADEBD72DBECB5B9307EEB937F2E92
+:10AF8000C4F8718C71FAAE7A80FFFE4F953B9BE856
+:10AF9000CD85F41944BC9AEE7988B1D759027D5F0A
+:10AFA000BD2B8DE82400F6907312BEE1F45A85F7AC
+:10AFB00076227DBFC6DBBB34FF36B2EB365EFF7751
+:10AFC0000ED91920BE0CD8E8D91DB04DB2B867CB48
+:10AFD0007CBF5887B1FC91BDB710E5CAD5263FF4B8
+:10AFE00023C13A3FED8A51A3497E5DA9A8D3310F11
+:10AFF00060090BAFE5F15B7E6FCFFB52C7BEEF225E
+:10B00000BF6F13580CF0B4FC378FFE1AE5D8B58F1C
+:10B01000DD9B8E72EC03A9231BC75BB67D4D3ADE28
+:10B020002FF3BE144BC7F61FC4B93C1BA42F47090E
+:10B03000DABE949A2E804CBE9E480DFE7F65DFDA04
+:10B040005B609C7F009E91EFAFDFF12F2AEF535D95
+:10B050007D2C80FDF64E4738AE697437B584D0BF7D
+:10B0600034F2E7B53FBD375BA13C8F589E86BF3CAD
+:10B070006C77FD363BE5F9A21F8FC3AC607D343F92
+:10B0800073FB155D471D28AF651BEBCB3F6FF0775A
+:10B09000B0901CC86F2B766CF8584CC7E7076FE26E
+:10B0A000EF41AD30D9A74B35F96DA6FF9F9BE81E48
+:10B0B000F043F18518C0C57F8E89CBF1D69FDD376F
+:10B0C000FE30C0F7E1B617D2F1F72674FAD7EF7960
+:10B0D0003ED6B578A163887B843ED2F8A45F3F68F2
+:10B0E000FA49D90980E54071177F2EB377A79F07EA
+:10B0F000F35DD6690F21CD2F7B5454DD68571D7445
+:10B10000923DB2ECD1E344B7CB04B54F203DC7D25A
+:10B11000518EEBEB75DDA37F9A8E72FABAA0C866EA
+:10B12000022B5EFBCB13BC3ED0790AD4BFEEF1C339
+:10B13000D3BF8B6590272E8BF59ADAB5C7D1EBB6C6
+:10B1400058AFAEC3D3313EDFFAB37FD27A7CB05B67
+:10B1500060394583DB2FEDFC13C5C13E8485F16664
+:10B16000727CA1BE59D125363A32ACD6AF7BD66FB0
+:10B170002BE93BE5850FB78E1B4631AE1F7FF3E809
+:10B180002F7E0B702C7DD3199A89E3FEE28674061C
+:10B1900074F067A989D3FD8FD664A3FE5E6A8F65BC
+:10B1A000CBF4E4EF976EFD36D1E3D5BFFF76B6B6AC
+:10B1B000DF10B4913C8805719E4B1E9847F3BC8A02
+:10B1C00045881E97FE88DFB37802FC6C2B3FA152A6
+:10B1D000E172CBC9568EBFC5877213EF6C01381C64
+:10B1E0008CDFD7F50ACF7F77B24B3312ED5C87C285
+:10B1F000EDB9188BBF8D76E70A50CB28D7C4DF9FF7
+:10B20000988EFDDC58243539293E6A7D7FCDFF03B9
+:10B2100074C90FBA00800000000000001F8B0800F6
+:10B2200000000000000BE57D0B7854C5F5F8DCBD8F
+:10B23000FB0A792D79404220DCBC1309718104128C
+:10B2400040DD10C020AF0D444589B0040C0112123E
+:10B250009116ACFE9A1B0208946A50AA54D02E088C
+:10B260008ACF0604C18AB01145A8FD300AB5F8A2FC
+:10B270008B206F6441A8EBBF54FEE79CB9377BEF8E
+:10B28000261168FD7D5FFFDF3FFDEA70EECC9D3B40
+:10B2900073DE7366E66C0D83BF64C68A3E1ED6D528
+:10B2A0009BCD98855D34DF97CBD825C6A467EC8C01
+:10B2B000D530A3ECB532FABB9AC4D88975964EC284
+:10B2C000CD507661954DD0FE2AFEDD1628A74A02A4
+:10B2D0006379D4FC13D69FB1D9F82F09FAD97862D3
+:10B2E000F86AE897C5892C328EC3CFC430662B0F1D
+:10B2F000AB8DCC87EF1D3C6AEE06F5728C81A5D92B
+:10B30000A0BEE51B82993D56C2F66AFF35DB2DCC07
+:10B31000A38E07FE5FB3FE1B33C37E0CCCD77D50DC
+:10B32000DB7AC66A737E1583F38894964179C2EC02
+:10B330001BFE367E07BEBB01BE53B112DA676AFA46
+:10B34000DB72EA739683EDCD81E749F8DF057C5E19
+:10B350006259A42B8CB1E9304D56D076FEF3BFACC8
+:10B360007FF43D4D7F395278CCF150F8C70036E07C
+:10B37000AA18789FAD89652CBEEDFBDFD7C98FBEBB
+:10B3800067C2B765C6A04995C9FD02E2A9EA338B39
+:10B390005D063C56BD76D96C009809CC97D699B11C
+:10B3A00033AFEEFEF45E98CF992653CC28FAAA2349
+:10B3B00042E812C07BE5E66F86AF86F626C07B08C2
+:10B3C000D073F696EFCD06681F57C47C1618FF9908
+:10B3D000182763BD116FA6AFBD1ABC15C1736F18D6
+:10B3E0008D23C11087A5278141393B86D93DF0FEC9
+:10B3F000EC83A25D427C31DF625B58DBF76B9A8E97
+:10B4000006D1455FCF98CFECC4EF6EF9CD05314240
+:10B410008B77E3D75E0DDE553C07E3F59E20BC5EDF
+:10B4200066D991F01976FAE5593D5DD96DF1ABE237
+:10B43000F5DB3A864CDEFAFC624F89F02C6D870F03
+:10B440007585BA1D4AC9D8A74C83C799AF9C23FEFE
+:10B45000FD47BCC844E09BD9EB7F588C7C0568F560
+:10B4600059807F67BB2F10BCC861F531829B4B852B
+:10B470009CF6E6ADC767707D77446A5E80FEA605E0
+:10B480004C0E877E7DEF88EE7530B4F3922F220A42
+:10B49000E6B728844D764279DEA6C09D55984D9E2C
+:10B4A00002E33C2FE7D8647C2F844D6802FA9C7736
+:10B4B000FA223A8705E67D64871821417BAF9B1508
+:10B4C0003785B5E543C61AE8FB5ED6517D3D8D73E1
+:10B4D0009878E5752F7CEFA26C6416F89EB7FEFB9A
+:10B4E000D7BD501E335A6D88A769F5774730037C66
+:10B4F0007F47CAD809D0EEFE7D803F9A9EC31C0FBD
+:10B50000F89DCAA7CE4E32F9A9C1303F313C77CF62
+:10B51000DBF07E052056047E9DB65C8F9F99CC198A
+:10B52000E94942B93505F884FEEB367BE0BDE9AE6A
+:10B53000B0DA65F0DDCA35FAFA993BCE107FCD0C52
+:10B54000E22F17F2577C5BFEDAA0F2571FD607F9FD
+:10B550006B981866407E3EBF57745BE09D8B0B4D29
+:10B560006C31C0175F15DC0CFAB9B8031A21BC9D09
+:10B57000C34C8E25BE55F95CC5DB59E4BF8CB6F8CB
+:10B580006CADDFFA55FF87A149D59B5FE4AC86F22D
+:10B59000EC9B9FA5BF8DF0B6BF257EC1DAB62FDA32
+:10B5A000F9C3241AD74E0BC3719DDFF941E2C308DA
+:10B5B000FFC96247BE3DBFC0E260A8EF7686BBD33D
+:10B5C000B0BE07F003D0BDE19DEF7350DF33B690FE
+:10B5D000E8D82299A9BCB8E39F87059CC70E8B8445
+:10B5E000F3A8D9094880F76BFE14E266F8FE3BDF4A
+:10B5F000F77785FD7CF3996D662EE2CF7036613367
+:10B60000F26F67E6C0F9D4BC5DF07C3D7CBF7A4B3D
+:10B61000B3792AD417EDFA570EEAA3F39B9BCDA872
+:10B62000AFBE35799F63C01F5F48131B4D80E76F26
+:10B63000C3A1B36E8CCD4D5AED94C3DAC30BC7C30F
+:10B6400079C003CE0BF052E9CEEE181F17FF6BF155
+:10B650007161127EBF6AC700262669F12238F8F3AD
+:10B6600070B755A0F9F3E73BBFCF6161D79EAF2D0F
+:10B67000C94CF2FEFFCB7C7392FE5BE9CBF9FD4D2A
+:10B6800089DBA560BE6FCBD7DB7E49F0EBE1761A94
+:10B69000EF75CAFB98FFDAF9FFEFD0BBEABF76BEC1
+:10B6A000D7A2F73E85DEE1360BEAAD77FE95C86E90
+:10B6B00060DEBFF97F74DEADFE8FC16ECD85F17D9A
+:10B6C000CEDC77160AE495B4EB8F6C4F12A83D538D
+:10B6D000D61D6314BFA2817D3D740A7C57067F028C
+:10B6E000FDFD86B0AF8D07016E013F01FD0B86CEDB
+:10B6F00009E0A1A5B48F7B19DA6D632DB3016CFA53
+:10B70000742AC113CA7F30E642FB3BC1CFC3F6FBAC
+:10B71000EBBDD3EAA17E7F6783D400F058C7F8B4AD
+:10B720002D00DBBA89365CC73438FA5925CDF8C606
+:10B73000E6EBD723F706AD2BEE9EA0AFBF8BAD8B0C
+:10B7400035427F77559A981BA6746750FBA7926C79
+:10B7500034CFBB59ED225BD88DE3E978125F9F357A
+:10B76000B0BE7B25C48B43B46F606DF1C6106F888B
+:10B7700097B87E6C991DBFE2351E04D8A2F857F029
+:10B7800047F278678CF505C49385CD61BF84FE2EA2
+:10B790004BC65A6C6F61B06EE4E316AE0A6DF106EB
+:10B7A0007F92B13FB9E24482B18E0719E2199FF747
+:10B7B0008CD3BD4FF30EC6F38DE37541DA5388D7B2
+:10B7C000D270BB1BF9C2F17CAC11BED700781684D5
+:10B7D000003E553C05E3FD6DE40D8D5FAE96D9CC82
+:10B7E0003709FDCE0816615F06FD4758BB33239F1E
+:10B7F00087CF128F858DE17A4D1CC29A96C17A8DC2
+:10B80000E51BCFB6CE2B99EA3D0FC37B0D0FC0FBD6
+:10B8100088D7EE4C7212FF97D98EF7C2659E8B5D6A
+:10B820000D0DF89F1FE583FF994425F1ED47EBB916
+:10B83000BF7979F01B8BFB80283198B3DC1FFD5C4E
+:10B84000E54FF696E17B2233D871FDCB1C0EC9D6AD
+:10B850001FFB65B4AE89CC37E8D6BF9D1D9D7478BB
+:10B860008B2E8ED2C1B1CE6EBAF65D2724EBEAE301
+:10B870005D37E9EA132AFBEAE01EB50375ED7BCEDE
+:10B880001FA28393E43B74ED53968CD3C1698DF76B
+:10B89000EADA67AC2AD7D567B967EAEA7B6D9CA379
+:10B8A000837B37FD4AD7FEE6ED0B74F57D3CCB7408
+:10B8B000F5FDF63EA183F35A9ED1B51F70689DAE8B
+:10B8C000BEC0FBB2AE7ED0C9CD3AF816DF9F74ED94
+:10B8D0006FF3BFAB830BD987BAF645D6033A789896
+:10B8E000ED0B5DFBDBE38E06C53B6CF283B9A8C6AE
+:10B8F000809F40CE46486774ED618556867C6352D2
+:10B90000F86164E677BAFAD1F67FEAFA33B35A20DF
+:10B9100002B25523959D58139561AC85CA877ABBB1
+:10B920004626A33C3C272F46A6DA5FF07D22DA911B
+:10B930008F063F2823DF5D8E6336B10F8C87F98C2D
+:10B94000C8D786D02BDD5D9AB851845F649E7EC0D7
+:10B95000877E814A9B3F9479A2810FFD215446F94D
+:10B96000A3E979B4BF339531FE047A1EEB8FA7B2F9
+:10B970008B3F85CAAEFE242AE3FCBDA88CF7675135
+:10B98000D9CDDF8FDE4BF0F7A1B2BB7F103DEFE1E9
+:10B990002FA032D15F44CF7BFA0BA994FC23A94C92
+:10B9A000F28FA032D93F9EDAA5F84BA84CF54FA4F0
+:10B9B000E769FE7BA84CF74FA532C33F85CA4CFF11
+:10B9C0002C2AB3FC33A8BCC9FF20BDD7CBFF009500
+:10B9D000D9FE87E9796FFF4354E6F81BA8BCD95F0D
+:10B9E0004FA5DDFF1B6AD7C7BF94CABEFE27E97902
+:10B9F0003FFF0A2A73FDABE9799EFFF754F6F73F44
+:10BA00004FE500FF5A2AF3FDAF5059E07F89CA8104
+:10BA1000FE37E8BD41FE4D540EF6BF4DCF6FF1BF6E
+:10BA200045E5ADFEDDF4FC367F33950EFF87F4BCB3
+:10BA3000D0BF8FCA21FE03F4BCC8FF319543FD5F20
+:10BA4000D0F361FECFA81CEE3F4AE5EDFE2354166D
+:10BA5000FBCF5039C27F8ACA3BFCDFD17B23FD1765
+:10BA6000A81CE5FF273D1FEDFF81CAD678C26053B1
+:10BA7000905E6CD57F86AB50B2B0A876E36DADEF2B
+:10BA80002BFA7845E8730CE31E636A055AA73F1D3D
+:10BA9000FAED7BA4270B2C12C28BB0693CFF8EAD54
+:10BAA0000B63F7E13F24C69A0B2CB47EDFFF3FFC0B
+:10BAB000BDC58547BF7C10EDE3031686F63158FF00
+:10BAC000AADFFD287F772CFA618BFB7AAB30FEF280
+:10BAD000DB246F1996DB92B93FF27A32B7B75B93EA
+:10BAE0000D543EDEDB4665D903699114A78AB9BEC1
+:10BAF000795D56ECBEDAFEF7A90A1CE64B247B7191
+:10BB00009DFD5C6FBB45D65FFF01E33A8E06230BBC
+:10BB1000B9156023B7F7F297E1EE0D30257948EDBE
+:10BB20008B18E79117586C0D3188E75FFF11DBCF59
+:10BB300067CC6981F29964D77ED40BDF8724BAC1C0
+:10BB400038C25FED8071E13F6BFF9FFF2FF77FFCF5
+:10BB5000A7FAFFBBC247B7A7384F27A35F6074E4BB
+:10BB6000201D862C881763E0FD29CB051BF2D1D45C
+:10BB7000857D86237FF4650E8A93DE17CD263BDB19
+:10BB8000F1CBA2520C8A7F2199EF86F19C63CC8382
+:10BB9000FE44B9C4882FCB77086E99E2D08E88D145
+:10BBA00060BF2B15BE2D5F526F9E07EDAAE379BCD7
+:10BBB0008CB979BCCC0AFF43399AD5B8760F851B6E
+:10BBC000C52B141FBB8C7E2FB0CEAC8D6DE3B1F3B3
+:10BBD00030CEBCDD6C43BB51DD1414CF0D8A9B0508
+:10BBE000C7CB4253C263505E999DD9799C3BACE26E
+:10BBF0006FF83D16218931D7C68B1A9F9598D415B9
+:10BC0000F1384CCC8EC475CCC5BD69910C4B49EA5A
+:10BC10008AED5C408B162805A36B003E077CCA4862
+:10BC2000575F7DA87B1D8CEB08D813A91F0AB76B43
+:10BC30008019E3919FF760CB04A21AF96135EB45B7
+:10BC4000F2EBBD0BFEB918E3D833928CB40E988298
+:10BC500031771CDF5B9DDDB240FD12DE7DAF091444
+:10BC60007795D99C388CEB6AF643C8AF752E8A1D40
+:10BC7000938F745AD2B9AF0569253B3E4DEDA2A111
+:10BC8000CFC206C26B795C34A7CF7613F9B5409F5B
+:10BC90007AA4CF0CB7E99816CF97D91533EEC7948D
+:10BCA0002FB940F49A19A097AE5D756333D115E8AA
+:10BCB000A47B5E537B428DA31FFB297A15A628F136
+:10BCC0004D855E183FBF1B2B1F8926FD50B6C093C4
+:10BCD00056ABE1D3E07D89D46903239D200FC5DDF8
+:10BCE000383D98D1DE05E9F9DDF23CA257309D8A56
+:10BCF0007F9C4AF4609F87B30D309EFB52D8E4715D
+:10BD0000F07CB2127FBDAF614431C6CBEF49E1FA9E
+:10BD1000F223587F3A60FDF9719D953940351FA88F
+:10BD2000B311FCD7BA3882FF562751F9595D2695D1
+:10BD3000C7CCACB249235FC000661CDF6445AE26A9
+:10BD4000A7A8FB5273E330EE5EFCE3813C03AA50EC
+:10BD5000B9A964D82DB8BE002468F033A134947C0E
+:10BD60006915F69A6CC3E3507F2C15EC1B90AECE90
+:10BD700041BAF62CB35F0046FB65E4FC047CB10ECF
+:10BD8000F9EF9E51D1BAF6772D49D0C1F352241A5A
+:10BD90005F49718AEEF9BD65BD74F0143FACE7E10F
+:10BDA00053A952B14186FE2FFDC544FC7CA97640C3
+:10BDB000D7791C26BE0BC6FF31B34C7104799DC5E3
+:10BDC0008EFAEF6408E7EF937F15DD0DB4EE952949
+:10BDD000EE72D96A93709DF2CBA97222D6FF32140B
+:10BDE0005CF23E882F9161FC80BD6C21FD39759518
+:10BDF000C06494111FA3F5F2DC972C34CF69AB44D7
+:10BE0000E6EA477C9288EDE7C64AD4DF7D295213E3
+:10BE1000F2B36F83C5BE0E6AA77A95F785BEB40FDD
+:10BE2000523DE76F878D280FE92D3918DF2F4BF230
+:10BE3000C4A21E3CBBDE44FB5ED5E2DA8A3020D1D0
+:10BE4000ACDFBE11512091F8117E4F7F1CBB16E76D
+:10BE50001F98AF9BE222DE9ECE6753009FA72BDC8C
+:10BE600039B44E7E84C7E3DBE285919E920D11D2F8
+:10BE7000069CEF54D7005BB6D61EF27DBFA9267B89
+:10BE8000177B36727F6E3CEA8163CB4DC518770114
+:10BE9000BD3F06F174AC31DAB08C16559B89BFCA30
+:10BEA0008D9259FBDDF2E5A283DA837E2F417BBDC3
+:10BEB0004274B101083752FFF212C185FB4EA92C22
+:10BEC000BF2BF2ED830F0CE88AF398D4C13EE3B7A1
+:10BED00020332ECD3ED6CC7744A71BBF97EB3596AB
+:10BEE000F6D68E9FC781525D4BBACF413A6D0AB1EB
+:10BEF0002F9350AFA644E23AF5D441B01BF08D1910
+:10BF00000DCD3912B05ED583DB880E95639AD23D94
+:10BF1000F0BCC5EAFA00F17832BEE9A9411827DA87
+:10BF2000F17CA28C76703EDF5F9BF9F28C9E5A7F8B
+:10BF3000BEAD3FC1E20CF95878BA08801797C486A5
+:10BF4000237E27B226257EE1A6F149A874011FB6FB
+:10BF50002ABEFF36D5609F742017D11F6E43BAA842
+:10BF6000FD1D35F138D7E72982CE0EC7A672F99E9E
+:10BF70006AE072C7760AC4A740B04F5335F6B2865E
+:10BF80002D277B19972032DCB73B9512A5E8056E6B
+:10BF9000FF66A1FDC37D619B40F251B5D1E27603FE
+:10BFA0007FA5A472F99C697EEDA9BED83CA9D68C68
+:10BFB000DF99B14560CF40D3D32677450BEE4BD9FF
+:10BFC000D62E8CA2F74C7637F2A9A2DFADA0105086
+:10BFD0002F4CC77F427DF54AC1ED217E71921D9A9B
+:10BFE0008671135CFFA39ED7E89136FA3D48AFDF18
+:10BFF000CFF4F68835EAED8B3334DC8AE39CB992D2
+:10C00000FBB581F188EC2AE0AAC2E5DE3386C62BB7
+:10C01000505C24F8FBD3717C385E189FC77EE3E345
+:10C02000A9B07339AD6A14DCEE76C6A7E23572307A
+:10C0300093D03ECF5A2FB8911F87C53C40F89D0939
+:10C04000F88D46BCCACE88BB01AE004672537C85D3
+:10C05000E3BF660DC73FD0F913ADDDFD26C66746C9
+:10C06000BC7E03F653C6FDC0DAEF89EE7B80BE28A6
+:10C07000BF3336B9CDB811798635468421DFAFFAA2
+:10C08000780F2E0BBE59F946175CBF964579D20C36
+:10C09000A0B7A2E5A8278A6F09F05FB0BD6E6397CD
+:10C0A00083F0233327D9A13678B22E6FC17DEF36C6
+:10C0B000F453E262F7E3BF003FF7AF171D2139BA2F
+:10C0C00076CA790499F8BF52F6919F5009F36CB083
+:10C0D000E1537938E2E57E3B23BD7BA3E30D1E27C8
+:10C0E00013CB883F31AE877EC8BF3BDE60FFA32401
+:10C0F000F5A7FD8F603D12EC7F7C69721816A0DFFA
+:10C10000F731DF17BF64F4F440F9BD14936C871660
+:10C11000013D1ADBB72BEA79558F5628764BEDF7A0
+:10C120007EB457001F5FF54604D25DA5FF74B413BB
+:10C13000D9013BF1CBA9D03F7CEF97DB42A8FF733D
+:10C14000A3C14E419F65CF7E10C134FA6F414F5756
+:10C15000752AEA13D5AE896B136DC05FAABEBCD633
+:10C16000BAABC3798505CD2B5C3FAF729C57BF40FE
+:10C170007F5395797DBD84CFE7E8723EBF696DE658
+:10C18000C5EDFE2F9FB7D865F20B3CB12887273746
+:10C1900089AC81E8CBFD86CB56E0A73E18BF594E4F
+:10C1A00076FD542C9330AED3A1FD5E6121BF60C6F5
+:10C1B00056BEDF7A5A28EC4A1BFFEF79221E42B99D
+:10C1C000DE2C32B44381F1B4DAED95A9B11ABB7D0E
+:10C1D0009D78C3382BDAB3D9803AE4FBD93BBA3225
+:10C1E0003CE7B2BC903589B40FEF253D062C44F1F5
+:10C1F00069F0C375F1060BB35BAD48A70EE2AFFF64
+:10C2000048BB30690EE1C3978EF857BF5FD3C9634F
+:10C21000EA8A7ECD2681FC9AEAB98511850CBFC3D6
+:10C22000E3669B53B99DDAAAE839C1514B7131F0ED
+:10C23000696C8FE3B8D6F0F8307B9735217E11A674
+:10C24000F8B181CF43906CACAC2F8FCB5BD1AE8576
+:10C2500019C8AE05E3E16BE53BD5A281FCDF2A33CB
+:10C26000F783CF0BFCFCC7BB8A7D7C3795FBC31FD4
+:10C27000A4F238C479F403A1DFF3B758DCF502BAAD
+:10C28000AD465A271B075BDCE8CF18AD611E3107AE
+:10C29000D16BFCB6559E015F93588B09E93926FF97
+:10C2A000818D389FC3DD984DEC4CD54EDC479848C6
+:10C2B0009A81B1FDA62FDFC778A40C6D45582B4C91
+:10C2C000CC3FD103DBAF4118E67F38A4E97D8CB3C6
+:10C2D0001C4E3232DC1790DFB190FD370DF1F6A025
+:10C2E000386527C61AFA603C66F722E4A33D71D18F
+:10C2F0009936683FD9D8C92E72FD33F4028EB752F1
+:10C30000E0FB370BBD79489F9BD942DB712B6D2D2C
+:10C310006CB91AFD53FC6364C7553E8031550D81DD
+:10C320007F0C649CB1F2099F3A18F04AF0F7A973A8
+:10C33000C7ADEC8E9B26526FA47355B2CF88FB29F4
+:10C340003E81F9D6011EEECCF7191D482F076B1A56
+:10C350000BFCEBD9C704FC0E8A007EF76E4FF2305F
+:10C36000C403CB945824D48F354A04772F6651A246
+:10C37000B26F8071AC438304A283C12A9970DECE70
+:10C3800062A12FEE8B562DB8BE71866CF8F5B8956C
+:10C3900083013618F87AF621BE9E9D281F19467E25
+:10C3A000D26026201FD6443599681D0DF282E3EF36
+:10C3B00003DD68F137D1E8E5E3AB84F115A05CA4B7
+:10C3C000121FDF5B2B903F59636E3FAE119BA6EEB1
+:10C3D000CBD9246C3F0BFE857C3D6BC7B634FCDEAD
+:10C3E0007281F3C12C95CF5ED5CBE58034467CDAE3
+:10C3F000115FE72AFDE7A619F839AED6EF3591DDD2
+:10C400009DB5E38343B8AEECA8FF6A0BF3105EDE84
+:10C41000B150FC4030F852892E8848A0C344F4271C
+:10C42000C145EC9BC6FD44953F2BD0FF48C192C748
+:10C43000450CA03CD11E56363E6F46A4059F3F02D8
+:10C44000C787CE01CD5C1FFC5C135711757A87E25C
+:10C450009E82D9370DC723DC1A62477D3CD1DC446C
+:10C46000EBF2E076A646EE679996703F8BF6D50024
+:10C47000B62CE77EE6C4EEBEDE8CF49C6DB890C4AC
+:10C480005AFDE20AFE69785EA5F38B2D1847C0B805
+:10C49000D72AEE0F1A15FFB57CB9DE5F98B850E3C6
+:10C4A0002F52B7BE6A1CAFE991508ABB58D09FD0BB
+:10C4B000F8017F3794C8A887E564239DBF34B16035
+:10C4C0007FC2C9783C933F372A7EE2D034936EDF37
+:10C4D0004D1EC232110F65A8875250D53897603C67
+:10C4E000EF220B6FC4B8D930F1118AFF95D5F373E1
+:10C4F00069C1F1BF8BB5EF3F8BEDB11E9FCFEBF460
+:10C500006322EE6FC2B2D429DC0AF2DDE9F06517CE
+:10C51000CA07282A13CA7BC8FE6F10160C914CC894
+:10C52000C7EF7B9EC5FE65B3D5867AEBE9D008EAF6
+:10C5300067FE7C81E2C30B6D5CDEBEFA327C1DEAD5
+:10C540002935DEBBB8B0DF2A3CB7F4EBB45DE3AC11
+:10C550003D503D303AB70486F11307CCA7F40AC822
+:10C560000DC1EF8F7344029FBFEF9B64053CADDCB0
+:10C57000F0FE3823F0E3F9DFF99E43F8850DFB392F
+:10C58000FC5B5F6208C26907C619418ECED7ABFD5E
+:10C590001D18E7C07DF7DF73B801EA6580CB50BF97
+:10C5A000E1BC070AB4EEDF8076293610EF2933BCF0
+:10C5B000CBCB21CC83F6F35AEDFE98E6DC80F65A1D
+:10C5C0000C3F168EFEC5960C07C19B539C8FA5A1F0
+:10C5D0001F74D0DD2516E35806D68274013BE66849
+:10C5E0006F5F7A432A97DF4DE9BC3F155FD0CFD309
+:10C5F00069B137DECF6D6DFB71FF3BE3E99401FD5F
+:10C60000E4E9FA79E9DFE9A72AA81FD56F030758FB
+:10C61000423D7526D3F11ECE73D6AF1D43B6A0FEA4
+:10C62000D92F129F7E57BB2D1DEDFE77AF5AA2D199
+:10C63000FECD7AFDADC40A8C23287ED199E6CFCCFD
+:10C6400012BC3FDB2F3207E8E91ABF40E5EC2DCDE5
+:10C65000E6E1D978AEB6D95CA4195795324EE074AC
+:10C66000E3388D1FB32F4D8D3FAFA0F1CE7AFD94EF
+:10C6700011E939CBD0741CCF1FB3813CEE153CBF00
+:10C68000CDCA7B87F1BC413B71808FD2B8DF11D717
+:10C69000CBB11FE7B709F539F28B819F0F096EDF28
+:10C6A000359DF757D689EBF9BC83F68A03B4EECBF8
+:10C6B000318850F63F546B2E87E70752861C4A6B31
+:10C6C000370EE9E371C81D3C0E5916D532178C1987
+:10C6D0008B4ABFF804CADBC8A755F900D103FD5245
+:10C6E0006C51E190F14307F33817C29737189EC495
+:10C6F00073847B3BB5FCE200DA87A5E16C1DC8D9E9
+:10C700007D03C21337C338A6CA9102D84E566809B2
+:10C710004F9F02ED4E241746A5F3F327E41F9E48D2
+:10C72000769EC3F17993420DE08C309799C7B35C44
+:10C730007F16299EE5CA0975B9DBC1D719059F5136
+:10C74000E9DC3FDB6B8071F6C571F0F3BDF097B8A3
+:10C7500019E34D0B7A0AC877EAF76F4F29EC9C9ED4
+:10C7600017F8FEED29CE1FD362B5ED2319B6BFDE53
+:10C7700071FC53B1A79DD339BD9C8381BF347A7FAF
+:10C78000DCD0501D5C3A2A9A39B4F1CDD2041D3C5C
+:10C79000A12C45D7FEDE69BD74F5A32D2DB9B537A3
+:10C7A000E0EF8B119991B4FECFE3EB90AF765CFE96
+:10C7B0007422FAB1EB45BB00F39AF1CE864F0751D4
+:10C7C000EF12C5B94EEF15C91E817B6BD6EE9F9C4B
+:10C7D000632D74EED8D87921D9BF5971FC7CF70C40
+:10C7E000B77EFF438DCBB7B76F82F6AC0ACFC5B427
+:10C7F000B76F1288C7FFE4FE49BF74653DDC97F54B
+:10C80000E5EBE1B37B60A6AC687B33D1AB619F689D
+:10C8100047566DE8213001C679FB168B3B04C67D77
+:10C82000EEAD236649B37F52E30703108DEF1D3150
+:10C83000E379AA03695C6FCFDE71C1CC902F763C9F
+:10C840004072DDD2EC8A8945FB05FEEAD65CE4AF96
+:10C85000A65CB47F7B0D3627EE87CD5A3282E2CCC0
+:10C8600091FE895456358EA07EABFDE3099EED0FF7
+:10C8700025F823B165CBC7D8CFD39136B4E7D546D9
+:10C88000F955A44BB514DA0FF7AB666FF9F8D2AFD0
+:10C89000D08EDAF8BD8ED1E227B9583FBAA7CDD0F5
+:10C8A000D019C71B42FDB40CF92217ED5231AE0B63
+:10C8B000E079D5E60217CA7D6143B80DE55EC4F3A1
+:10C8C00064EDF0E9E474AE5F4C5E3EDE61FE12EAB8
+:10C8D000AF757D9F9E4CF3576153EC7A23EA0F7539
+:10C8E0001E2630F858DEE1EF4565CD9612239E8B6B
+:10C8F000FF73E6F3318827681F8665EAD041A46795
+:10C90000BEAB1D10C9DAD15B6A6951F4F044D4C3DF
+:10C91000D05F69A6E3572897631EF11AADA847C3F5
+:10C92000AC36DCFF1893DF47AAD0CC477CF71E5CFF
+:10C930004980AFE233A11F30114AADDE9EDC817D1C
+:10C9400091D30D8A5F54CFCF75AAFA7DE5130CD72A
+:10C950006193F859AD56B9AA56DAABEFB708DC1FA8
+:10C9600090B7F2B87E75A6EB491C6F4B219BB0992E
+:10C97000F4694B6249F8CF37FE08630BD139C22600
+:10C9800019705F41AD5FD53A0F2EDFD79AC722A548
+:10C99000FD47229B8F7CF1D16DB7B538A0DFE687CC
+:10C9A000FBF5133576EAA5747EAE99D97C57485FBE
+:10C9B000EC0C95500F8CC6BD87DC80DF8FE72131F2
+:10C9C000AE51B3D3B20ECF83D544C03A1FBE3FAAF7
+:10C9D00097EB25C447F3AE824B788FC6810B33901B
+:10C9E00073C78E0197F09CBDC30ADAC68E7E90E3B2
+:10C9F00065D2FF1D8CF75AFA2C75E8AC18F427BEE7
+:10CA00008321A1BD05BB9F7B90C34EC4976B099743
+:10CA10003F9722875314FE2D57E4708A91CBE1E4AF
+:10CA20009591368C77963F22F4C6F3724C0AB7A3E1
+:10CA30000A30215FF643FEE47C59E5EFACC87392FF
+:10CA4000D20FE7FF60F99CED8FA676AA9CBE9CE909
+:10CA50003AC4ED5C4BEE7C18D71D20D7A8F75C0BD1
+:10CA6000E273514E027C62B6213F019FC45568F8C3
+:10CA7000A0A1F90723F28969B0407C6281B248C362
+:10CA800047CE56FFC436BC0BFA550B930CCB58A0BF
+:10CA9000FEAB74D54FB93E7EFFB3D2BE3C0CFC0852
+:10CAA0008AFF44308CAF5D8C91284E3A67290C1276
+:10CAB0005030C7E449C338CC9C0742280E5671B0A9
+:10CAC0007671B8D4965EF7F873687F79BC3F95CAE3
+:10CAD0000329AE33888F29FEBB143CE65CD7FE5C8D
+:10CAE0009E83C7DD4C6E8B7D6D12C6DD5C22EDC76B
+:10CAF000F560B627C94EA9FB713CEE86F13C8CEF80
+:10CB000005EFAF611C0ED7D39618836E9FB04D3CD6
+:10CB1000AE50BF9F56D5FC497F03D49F4E72505CE8
+:10CB2000CEDBD365CC8079CC1CE77EDDA4DD6753FA
+:10CB3000F0D864F4A4A11D6DAAE5F8695A2E16D3A5
+:10CB40007E1363A1259AF3BAD7E2E399FE14C28F4C
+:10CB50006A5F54BDBDAD8E0E7DB6EAEF6BD99D6A9E
+:10CB600085DFAB91DFED6DED8CCAAFC1FCACEA6740
+:10CB700053EC41D24377C02BE83FA8FABAB868D04B
+:10CB800060B4F3835E4AD9F227987F74A62B3703EB
+:10CB9000F8E7B6577AE4AE06F80EA3DB680BBB1EC7
+:10CBA0007DF88389F4E123258CF421945A7D68EA89
+:10CBB000C00F2FC8B8317D9EA1B4073F96FB87A058
+:10CBC000AFB5FD55670E1985E32FC9E076F2E71A78
+:10CBD00077477ABC244395CFEBD3E3B72AEDAFA5D3
+:10CBE000C7A765703D1EACB7411B93DE3EFF4E16D6
+:10CBF000C5C90E33D0F368CF76844A1B9234E7DC84
+:10CC00003B45BAB57A3DAED7D469C8EFD7A1D7EFC7
+:10CC100047FCFDBB7A7D78C926F2ABE0CF39F656EA
+:10CC2000587FFC06D677087F04EBBBA4B6F2102C25
+:10CC300007C17C0FEB912D1FC3F8F63ED593E20E92
+:10CC40002007C4F7D5C0F72807AABCCCDED227122C
+:10CC5000F70DD85F4486FA3F580E8A8B5E31629C8E
+:10CC60000AF538E26B37C83CEA99603BE1CF70AD1A
+:10CC7000C4F9ABF2A0CAC1B5F9E82D13AE4B4D55BE
+:10CC800017B89E8752ABE73BF2677E7F83FCFF6855
+:10CC9000C6F5F901AF66F07B103F23FFBC9A717DAA
+:10CCA0007EC16B19FF915FF036F10FEA4F5CBF8DCB
+:10CCB000FCD01E398FF30F9D4B047EC8C5B8F3DE40
+:10CCC000FE3DEC18A7197995FBF5A0D3C9AF0FF677
+:10CCD000AB272AFA6FB212273890E96CC9E0F24A02
+:10CCE0007E7B614A681FB457D7EBEF4D8CA965185E
+:10CCF000679A0CA5564F58906EEDF8EB7FCDB83182
+:10CD0000FBBDFB3AE97B3CE33FF6F37CD7A30F5234
+:10CD10001DD6F188CFEF3C468678BAD67AC0B48A61
+:10CD2000E3598517798CAADD8C46BB09FC71E13F7C
+:10CD3000E18FD1454D97AC40D7C84C6329C603EF6E
+:10CD4000C2B31614CF30AD74A4A2BE61EABE00C552
+:10CD50003B3E1255D87C70288C63E4932CB06F0056
+:10CD6000F5C30647B6C6470416681F91291E5C4ED8
+:10CD7000E3E6E75598CB6BE4FB640A9C0B70B806BE
+:10CD8000CE0F82D7F0F611462FB369FB51F4CF18BE
+:10CD90001BDF1708ECE7F9867746FF6F8B60C3FD52
+:10CDA000857B079F37633C677491774F02B44BCA0A
+:10CDB0000C2F0D03137FEF1681C6DB6763CC4A3956
+:10CDC000958E6C39F0BC61553EDF37B134350F7745
+:10CDD000B4C3877D32F5760AFF8C5D283E467F9688
+:10CDE00026819973793FC949D7F73ED28FDE4FA686
+:10CDF000F73D9698EB7FFFEEC1CCE16E878F6ECB4F
+:10CE000054F421C685D5FE8126E39B04477B719BA4
+:10CE1000DB95F62D064335033C8DDD98B912E35EB4
+:10CE2000C318E78B928D19A532E73FE6089AEF4FBA
+:10CE30008D372F53BF3EC33F49FFBEE7A7F035A84C
+:10CE40000DBE14FA57EAF924D2E87CEF3B18476488
+:10CE50008C60433F75B63364398B44BA2B7C2DF715
+:10CE60002D750C86F985305D1CAF95AFE57EA5C8A4
+:10CE7000D7B399DA3E6F25D2DF69686DCFF97C8729
+:10CE8000D0FA7EA691E127E8FD591B7357629C1CDE
+:10CE9000E841F5041B7F82CF9B82E0C14172C1381B
+:10CEA0004C72897A19F093D6CEFEED1205BFE704D5
+:10CEB0007EBEA96508F7E75A9279F96226F7DF1E68
+:10CEC00057F0F8B452B674D2E0A17B80CEF0E7C13F
+:10CED000F58066DE84A77B629479CBE34B47C1BCC7
+:10CEE0005AA2586F01F864EDC6B12B176AF8E4F93D
+:10CEF0008DE34B110FADFDC92507118FF728787A07
+:10CF000071E3B883C84778E404E5AD3A9FEFBF5AB0
+:10CF1000B67CDCAEBCCD69CB3F32E657A82646C214
+:10CF2000F704872997F793DC0E7EE6B77DDF11F4CF
+:10CF30003E33C5DCC8FB0A7D4605D1AF38887E4349
+:10CF400083E0323D1CF083A167F09FCAB7AF58D48D
+:10CF500005E3671B05BA6305FAD92CC0F31D99F7E1
+:10CF60009586C5239F4AA60468EBC99C7CD09A0588
+:10CF7000F288FA8BF4AF8BF4F578947382A7943A25
+:10CF80006E46BEA95D1407EDF76496AFC47BAFF79C
+:10CF90002E5C6142A4FF3973DA4A23F47B4FEE1F03
+:10CFA000F7607F46A1E2E028E127F8B431681E6B04
+:10CFB000826039A8FDCA6BE8F38541EF3F1254BF88
+:10CFC0003C085E15042FD1BF3F651ADFBF9C02F4F9
+:10CFD00043C45D4B5EBC99ADEB8656FB25A03DFB83
+:10CFE00050CFEF231B387C6AE383A54BC23470E635
+:10CFF0002F4AB5FC6B52ECC5C418A7A33DFE3DD427
+:10D0000011FF6406DB3559772EF130633AFBBB5BC9
+:10D01000D4C3CDA22A5F0B0ECECDD6EC07CAF5A5A0
+:10D02000184FE978BF422EC5FD8A918FABEDEB4AD0
+:10D030001D9AF9A9ED87FFEBAA88DFBB9A5957BA69
+:10D040009EF6FF94FDBB285EDE76E56A04D2653865
+:10D050009E1FC5FA4E9EB439D99AF9B1A6749C5F49
+:10D06000F3C3FCBEA1DC00F400392F6776DAFF6E53
+:10D070008E8C9CFF02B4DFFDB0381FEDD7E1F9D1F3
+:10D0800074DE686C16F7B77747F6EC723FC0CDA137
+:10D0900093CD18576D7E741895EF8A8EC53E407EED
+:10D0A000F7ACC74AC3B2B03E92F012F7D2D2D27AEE
+:10D0B0009083842C89DE7745D9BA6C473F7499896F
+:10D0C000E1FE1363F6E7884F7E6B213F754A7D2FA3
+:10D0D000DAEF29FF5DC9F0786857BEC844F17FF8E0
+:10D0E000A3FB18AE65C3CC583F6DA152CAB753B964
+:10D0F000EBC7373ECCA17D1D91CEEDECF4471D076B
+:10D1000049665FCBBDE9BEC25125BFCA962C5746C2
+:10D11000168CE3EBB3A9942F85D9A48871E8B7DD09
+:10D12000E4C8CC8A0DB4DBF5A348FB556F9F2DEF07
+:10D1300082FB7B7DB338BFECF4977729D7D8F58A8B
+:10D140007346C2F32EB33417F5C6AE4E3D0499E4D0
+:10D15000B6291AE3ACD314BF19F864FE1BEDF061D5
+:10D16000CF2C91F072CC321FCFC2B2E6DFC40EC614
+:10D1700071A9EFE51D743560BE185377A9AFD63F8E
+:10D180002E481B722B8E37C05FEB499F937F0CF0AC
+:10D1900088ACB52B65B01F6C37F8F5388E18C770A2
+:10D1A000E427F53C1E8B6B4AD7C615027EE8024584
+:10D1B000FE79BBAFF070307CFFAB5743E8DCD7574C
+:10D1C000F217E15AFF58958FE911FF73B885D6C55C
+:10D1D000919290087C63AC3BFE10BC57F1AC89F493
+:10D1E00066C5B3B18FF8B01EE8895B86C1DF7D3EAE
+:10D1F0008B9F07E8583E36970EEDAE958F4DA538BC
+:10D20000DF8EE4636AD6A60EE4A3AE0BF2D1F0671C
+:10D210004D74BEBAAC53ED5D18472C33DCCC1A60AC
+:10D220007C439EFD4517DC6799FEAC85E8EA0D0F4F
+:10D230003FCEE7D53309E7D56A7FB2B8BEF2D6173D
+:10D2400090BD100DE09D81FE16179B683D22763142
+:10D2500093DE1323ECBCBE134B5A0076795178BE93
+:10D2600084F4752BF200F512F25951E4843BF05C22
+:10D27000CBE1F929B40F762A97EF83CD78E8F90846
+:10D28000F43FBF9ACBCF77CFC47C3BB8CEFD37F706
+:10D29000BD6A947C3BFF5BFB5E4F6429F7865AF7BF
+:10D2A000BDF839D0DDF3FBE572BC30C982784AECB9
+:10D2B0004378B9DDCAA410C08B18C5D251FFA8FBB2
+:10D2C0005EE2AFB87E120D02ADD38FD5C994BFA078
+:10D2D00028C2CA9FFF8ADFDB139F2A61B40F16534F
+:10D2E0004BFB60E188578CDF0ACC89F27334C49E13
+:10D2F000F84036F25F08D173FA73333EFD7D2ED2CB
+:10D300006D748C2E9EA0F09FFAFE89FA5B687C27D4
+:10D310000466437B5FF4878CA1489F66D1F5D43DBA
+:10D32000A4374369FF9CD9BCBF1D00F0F47A58674D
+:10D3300033E49BF8C4E4EC403FD3173C9C8EF42EBE
+:10D34000FA438807CFDF4C5B18B20ACF6154EDE097
+:10D35000F7BCA72CFD8ECEE3B224632DC639BF5E89
+:10D3600018C2CFA96F1940FC33C5C0CFB9B0443340
+:10D37000C597AAC214B87B3EC19AFB4B66A4877AB4
+:10D38000FF660FEA15F8FE71151FE837A2DE55CFCC
+:10D39000D1B35A09E5BFCC20B47BCEEB6F59DC3F4B
+:10D3A0009D9268A7F3A2D58F59EC0B92389DC5FECC
+:10D3B000F85D46EBA26A836FF82AECD7C0A4AD36BD
+:10D3C0005C3FB454E07A9B6DC9A03C04354666349A
+:10D3D00047C17389EB33753C3552C9EDC44F46766E
+:10D3E000C81885786CF9B405F96341B8847191EA7D
+:10D3F000CE7617F51B6EB5713BA17C17C79E827C5C
+:10D40000E03747211F7C2A182C3CFF80C300F5E73A
+:10D4100019AF6FFDCEC2A5D9346FABCD30241EF944
+:10D42000EEC2F055F0DEED4C4A8EC77B624BA3EFA7
+:10D430009A80F5AF89A49740981ECB477FEF35B10E
+:10D440001FAE53A72CDD4DF39BB5A90FDE20605313
+:10D450005E3F40F66996C25F5EE5DC5A39C09B10BC
+:10D460008F8A5E7089AC96E2610A1E5BF1ABD4577D
+:10D470002F35113DAA175988CED5F57FA37EABC3B2
+:10D480005BBA203DAAB79A287F87F5263E8FF2FA2D
+:10D490001E830FC1B8CB4D9136011E55C9A3CD08CF
+:10D4A00057350A04ABDFAB5EFAD72E866CDE1F96CB
+:10D4B0001603DF670DF41B9B88F6ECCCABD18953C8
+:10D4C00034743FB3705B04EE3B1F0DF1A4E1395F90
+:10D4D000DF0321763C57A8C6D3CE2C4CE3F7816CF2
+:10D4E0002DE1B85F3D6D6E4A14DAB9C3368F19EB82
+:10D4F0000F3725E19139E6B0D90623EC30DE4CF048
+:10D5000019E51C09FD61FE4081F34DD5ABBBCDC9CA
+:10D51000F0BDDE3771FC9C7BEDE89E81880FE02337
+:10D520001BEA9FC49674B4C3D58696F404A4CFCBEB
+:10D5300002F90BB03E7560FE91D9C8577D411F2A94
+:10D540007C357BCBB679289FD56F9E1A8E783D3778
+:10D550009A99313E56ADCC1FD68FEF19A17DF5E6D5
+:10D56000B5C3197FFF3DE43BD5DE03BCD004F05EBC
+:10D570003387736EE2FA79AFD94B79EFF6DEC518CF
+:10D58000ED9F19D9506C0794E7F7004451B99F56A5
+:10D590001B378EE7DD93B5E7E766637D76A0BE2394
+:10D5A000BE197B9341A1B385ECD258C40BC0DEA554
+:10D5B0005B23902FCEBDB67BCF40948BCD828D69FF
+:10D5C000E54195C3441FAF07FC3D81F8DB7C613822
+:10D5D000E6A19879365C421AAA7852E54DC54B0D02
+:10D5E000E37850F1526354F0A4D43B153C54311FFE
+:10D5F000F5C7CEF6963660FF6FFE40FB6DE7A630AE
+:10D60000819F13E679D1D4F9B9A2F4FBFBF5377108
+:10D61000BE9FA4CCB3CAC6ED62550C93EAFB109F23
+:10D6200039CC6A7E4968726ED311DDF8572972D001
+:10D630004A6F9C078CD36BE0F70483F5D75C85AF0A
+:10D640008ED44FF4A05E9929433FB9280FB649B84C
+:10D65000CFC95E1715FD0D3653F3DDA2578E101F8F
+:10D6600082EE92A260CD62DA08E340FFEB6C0F8A93
+:10D67000171675F5D2BC378CB23103E89323823785
+:10D680007C3BDA838744D253EA381DF287440F4744
+:10D6900013974FE4178C0FB6EA85A0F1D62BE3B5AC
+:10D6A00018EC5E3C17CC1608747F4D5C702EFC1095
+:10D6B000B77714490CF47FCB7BB81FE9B814210964
+:10D6C00054633762BBD9972292D17E1F51E20E4735
+:10D6D000166D8B28D7D0E1A98EBEB3788084F42F45
+:10D6E0000A3BF430CAD1634ABBBD66FBD0F9A80F30
+:10D6F0002E4748785E6A6F949C8D7ED45E035BC231
+:10D70000A2381F1ABB04F007F242F8837AE9495B9A
+:10D71000402ED57103DD3C483768EFE07264A77D89
+:10D720008CD9317C5FF4DAF2D4CF4BFAA95E90D673
+:10D73000E506DAA9F7F21E55E64D32D225600F90C4
+:10D740003FD1DE59943C46C179506FEFDE3911F17B
+:10D7500057136635E0122EB83E180EACA76A8DE856
+:10D76000E7B385717BB4F7D28E86C874FFCC172FD0
+:10D77000B275408FFA073EE0E77977F07B5BAA9DB0
+:10D7800086BFE5ADFC07EF55E65E188EFAF5C502DB
+:10D790000BDD6BEADC2B99BE739A35990BD1FE9F9A
+:10D7A0006C191E2105D627B75CF28891E42F24E975
+:10D7B000D6075567DF2379AE662D741F7BCAD20367
+:10D7C000A30720BD5F32D1F981698D4964E74EAD71
+:10D7D0009FDA0FE73B65511AC13336DCCFE1A53C38
+:10D7E000FFE19445792FA0FF7534C4311CF9D9B7F6
+:10D7F00042B0E1FA6AD086BC47EE85FA41E13D3B92
+:10D80000E3B8BF5A7F7434D2FDABF922E927C7FAD7
+:10D8100027EFC27AC776116F8CC17AC6F608E63553
+:10D8200065C6481BFA05EAF9C20613D7B76715BDE6
+:10D83000704CD113C714FE2B6A6848477FC9B716CE
+:10D84000EC11EE7B9B7D1574BE5BB0D9D701BF9CFC
+:10D8500014648299CD965C5F80F759D6507E9CF314
+:10D8600069161BFAC9F759981DFDDAFB76F5E88BA6
+:10D870004B0587B2AE1A1DCDBFABE24BFDFE19E5DD
+:10D88000BB4C5C5E41FB0ED15232EAB7BDCAB9F166
+:10D89000A3CA784F2D7CE92EF40B4E6D4C8B621A87
+:10D8A000BC9F52F234CD003DB8B99DF59EFF2635A0
+:10D8B000EEE0A6EF542AF1C07DA6C6EE98F733F845
+:10D8C0007ED789B52156CCCF1B7CCFEB8489DB8FEB
+:10D8D00036F7BDB6EBE1E03CB7C1E3695DCF04DFED
+:10D8E000FFEF15D6AE1FAFCA59F0FB6DEE93A75EE2
+:10D8F000DFF92ACC4B86F7BD77DFC4E8BDA1A1FFD5
+:10D900007A03F57545A3C586F7EF8F8548B41E9257
+:10D91000F398B401ED8C558AC4F5FCB17DFDE8FCAB
+:10D920005FC5978CE4AA628BE8C654C5EFADC87892
+:10D930007C30C0F76F31D9F1FD532B57DCC5C54C96
+:10D940009F67219F71F99C0EEB248F2DB02E0A5EEC
+:10D950002FCD5CB589EE11FE5CEB25358E148CEF76
+:10D96000825EFA7C0BC1F7E77601DBE4F76D8BEFA3
+:10D97000B3752E5A177D5B57496541D3DAA2040966
+:10D98000EF531C796C10CA4D7824C543CED6D5D23E
+:10D9900026DEB7DBFB5DC1FBA16F8745DA505F7CFC
+:10D9A0005B375FB95CA0F089C297B76C6916131832
+:10D9B000B5DF3108DAEF0C8BA4BB2EA98EFC48B47E
+:10D9C000F32A5D83EF37ABF33BFD10A7AB3ADED311
+:10D9D0001BA746A0DFD9BC3A7A4701F4278746DA6D
+:10D9E000D0DF9EAE9C7F39BE8AEB9B93D6C817468C
+:10D9F000E1F99935E3BBE0BAEE7E93CF6C877EED1B
+:10DA0000EF9444E07AFF1BA33702EF1B7F03ED3D49
+:10DA100068278C6E11F5DCC06246FB78033D462614
+:10DA200025D19639F145C159A31BE97AC67369F727
+:10DA300055E4A3B3068A770166765F85F6F6F09E15
+:10DA40001427BCFF2DBEDE64FFEAC4EB83EE2D3E3F
+:10DA5000D18BEBA5136BDE1843EBF3F5261B8EF38E
+:10DA6000DBF57FED82E77066327EBEFEE44681E63E
+:10DA70003113F8312409F5038F83CE04BD6F15DA15
+:10DA8000F261D1C67AE2C399C08716F4D31C3C1F59
+:10DA9000F34CCCC72CB136F93F3A2B7C370BF80E40
+:10DAA000EFEFFEDC793F96F50A3EB7CAF950A5BB09
+:10DAB0008A1795FE013E64BAFC82514D7D0A1358C7
+:10DAC000401FA8F73B98D1BB1CEF69CC13C31B3197
+:10DAD0005FD57E63ED1F286F8B6C641BC89EB34CB3
+:10DAE000CC97374FBCC98EF1C006736D6B5E17AC17
+:10DAF0000FCEEB2286F1F74B303F31CC372C3B89F0
+:10DB0000BE37CE661F86E836C578292E2016191C2A
+:10DB1000742FAFC142EBE6603DF48A42DF3BD07721
+:10DB200040BFA7173FAFADDEFB534B30343D90DF16
+:10DB30004B42A32E4BD064FB2B9FDF89FBB4258384
+:10DB4000A27E9102DF6FEE75E44EBCB751D22F6A10
+:10DB50006B32C0BB5FF93BAFBF392ACF847E80F008
+:10DB6000F59D43D16FECE578B397E63B6ABFF0FCD7
+:10DB70002D7CFE79A2EB9D5E7CDFB402E97D5E88A0
+:10DB8000E0F9DE527D140755DFFB586087DF16028F
+:10DB9000B0D7C41231AFC1DE5E5C9F7654C6643B21
+:10DBA000F6F0EFEB9F2385BEC375A6B2FF63B04AC4
+:10DBB00066F4FF9C76B39DE757644E2BF8556315CA
+:10DBC000FE2DB75E194AF6B796D92D98C06489FE26
+:10DBD0003E5656E0DEDE9A1BB9B7C7649E87AF415A
+:10DBE000C9C3D7D13D4A61C7073FA07F197C7FAA2F
+:10DBF000DF5F5ADE443E19037C85F622B785C36396
+:10DC0000153EA9DE369AF23DCFF9D8E4463F61864B
+:10DC1000E28FA5BA3A3109DA5D06F945BD70768C16
+:10DC2000271DF5C7893AD6989A86F12A970FE9B247
+:10DC300037E903CA8B76624D4304FA3DE7603D3114
+:10DC40000ABAA852FC7B7645F4DC867E7052D6BABE
+:10DC5000651A7EFBA117B7FF67933C89B8BE919305
+:10DC60002C3C5FE395DD94E7B93879441EC691F604
+:10DC7000D76D6747D302EF75741F65A06108CBD6D7
+:10DC8000EC4B8E31B67F4EE3A49A4F733DB7DF164F
+:10DC90006323E5D10252D6D613ECA4B8521CF22865
+:10DCA000C687A507095E3C83D9E81E6B609F8EEE90
+:10DCB00083AAF477D8AF0EC5766380FEA86F0C56A2
+:10DCC0009F116167313F9F920584437DA2D27F9867
+:10DCD000F8C863488739CA3DAE39422D874D563A58
+:10DCE000E71AAC1F31AE59467A53DE5380FE18E86E
+:10DCF00049CAABA0E84509FE477991F2D79AA9D95C
+:10DD0000B5F322ED29F80FF4634EB63E8FB84A27DB
+:10DD1000D5BFEA884EAA9E047AF5BF117AA979CABE
+:10DD2000E63CCBE39D739E9D1AD797F0061287FEC3
+:10DD300050DC1F29AE325D99035B134D7C6C1AE2F7
+:10DD40009450DF8EDE9EC024783463BB40E75B478F
+:10DD50006D8F2638C21FCFF32A29F67EF48B5D879C
+:10DD6000607CF2D40B5FCCC5BCF7A37EC3287E6C6D
+:10DD7000080DA37C13E210258F8318F63EDE63BDE9
+:10DD800028196BD15E39599BFC0106A2FF5E7E4EBD
+:10DD900016567932A713BFF737671FB7F3730AF91F
+:10DDA000BEE0457C03DA5F2C15294FD3D3A139E4BB
+:10DDB000BF35DC69A2FB114C767C82EBAA090A3FD5
+:10DDC00058E26061A9A1578804F2AAA1CFA3218FCC
+:10DDD000BDEF82FEBDB0EE12BA811F9B19A5AB3715
+:10DDE000CA21DF60FE58539C6873C3F8C3EDDD742D
+:10DDF000FD39C52A13C653988BFBD12A7F31F1AC6C
+:10DE000091EECD0FE6F92BEE9CA0BF27691A7C613D
+:10DE100028D99BC17AFFDB798DBC4DF3557ECA6250
+:10DE2000594A5E7AB2FF170FF2FB211273AE52E528
+:10DE300005F53F78374F237EEEDA6B626E89F0F797
+:10DE40001AD65F942D368C07B4FAE1A9F05E0C1A4D
+:10DE5000492BF139E605D5CE13F3826AF182794177
+:10DE6000B530E605D5B6C7BCA0DA7ACC0BAAADC7EB
+:10DE7000BCA05A18F3826ADB635E502D8C7941B5E1
+:10DE8000ED312FA816C6BCA0DAF69817545B8F792F
+:10DE900041B5F59817540B635E506D7BCC0BAAAD62
+:10DEA000C7BCA0DA7ACC0BAA85312FA8B63DE6050F
+:10DEB000D5D6635E506D3DE605D5C2981754DB1E7E
+:10DEC000F3826A61CC0BAA6D8F7941B530E605D536
+:10DED000B6C7BCA0DA7ACC03AAADC7BC9F5A18F368
+:10DEE0007E6ADBB7B0856968C7DE4A72EDCD8EC544
+:10DEF0007DA793C4CF87EE037E4639DC3BDE46F92F
+:10DF00000B6F709DD892ADAC5B14FEBDCCC226E108
+:10DF100039F48EDE57F9F3257C278FECC112E25FCE
+:10DF200016DE88FEDCA34607DD87929BF8FD44667B
+:10DF3000E47EC03C51F17F94BC10F34489FC00CCDA
+:10DF40001D6CD48CA7B3C3CA8C1A3C4417DB747005
+:10DF5000AC334ED7BEEB0449571FEFCAD4D5275474
+:10DF6000DA75708FDA7C5DFB9EF31D3A38492ED648
+:10DF7000B54F59E2D4C1698D1374ED3356B974F5B8
+:10DF800059EE4A5D7DAF8DB53AB877D37C5DFB9B8A
+:10DF9000B7CBBAFA3E9E25BAFA7E7B1B75705ECB74
+:10DFA0002A5DFB0187DCBAFA02EF465DFDA0934DC6
+:10DFB0003AF816DF765DFBDBFC1E1D5CC8F6E9DA7D
+:10DFC00017593FD6C1C36C9FE9DADF1E7744573F2C
+:10DFD000423AA5ABAF3AC3FD7BD600EB038C538628
+:10DFE000F1FC1AB33DAC09FD8B91991774ED4D31DD
+:10DFF000B05E00FEA9067D887EDFF79D12291F33E3
+:10E00000AB8DB0E3BD6F7948ED1FB4F7BC47DB7F44
+:10E01000D07DFFE9D0084F08AD2FAC646F6FE9CD1C
+:10E02000EF9BB5E61351EFB3331F8B8BA190900F8D
+:10E03000FD23017F6109E00807CF0B0D7E10F94F2A
+:10E0400036F08BD0DF6C5D17199292D02E8706FCCC
+:10E05000E2EE5735795EAEE5178FC46FE7519E5EED
+:10E06000476F2867366D1A8EEBAC194C5E8CFB89B6
+:10E070006A9EC5FD21FAF8965A8EB0027E35DFDB26
+:10E0800017D2D8BDEF4FC8FB08EB596ADFDAAF12E1
+:10E09000FF1260B27334FD3F06EB3F23C875631D6A
+:10E0A000C81FF8434FD4D9085E591747F05375126B
+:10E0B00095ABEA32A97CA6CE4EF56BEAF2097EAEAC
+:10E0C000CE41B0BBAE98CA75754E7ABEBE6E02C167
+:10E0D0002FD4B9A8DC585749E5CB75B554FF6ADD94
+:10E0E0007C825FAF93A96CAA5B42CF37D73512BC55
+:10E0F000A56E15C16FD6B9A9DC5EB791CA3FD535FB
+:10E1000051FD0EF0DF10DE59E721D853B797E077C5
+:10E11000EB5A087EAFEE10C17BEABC54EEAD3B4932
+:10E12000E59FEB7C54FF973A3FC167957D8879BDA9
+:10E1300005DD7D3C1536B263DCDFC3BC1598872155
+:10E14000DFF4ED4FE5C70DA6C369A57FD310709727
+:10E15000308EDC2D7D5D83665DD1D09BC72DEB0DB0
+:10E160003C7F4B7D37666B20BFDDC1F8392DEEB7A4
+:10E170004FC77F49F034A66E0FAE372A6A799EF2F8
+:10E180003CE4C74CE2C7BFDCD03A4D59176C4E7126
+:10E190003E81FCC8C2DC9F26E506EED11F4871FD1A
+:10E1A0000E9F5FACBD7F0FB69E6EB3A7E347465B85
+:10E1B0003CB198FFCBB74FB4AF933AFE5E8D72FF80
+:10E1C000A1C3FA9DA7BAA3BD2AFE51A4B8FE7E53EF
+:10E1D000F804DCE77F51C1C78BBD0DBAF2EE54E7FE
+:10E1E0000BBD717F3FADF6850785C0FDFDB1B8C49D
+:10E1F00007F92E6112E5C119CF1CEFA30B7E27385A
+:10E200008208DFCD642A4F24BBFE88F3B9071620AD
+:10E2100008BB065A12DB9B4FF078DE52C6F39632EB
+:10E220000EB59C93EADC8EFD1D4B73E8C6F3A292FB
+:10E230005F680CF33D87E3FAC73B178E0B29017C1F
+:10E24000B7C653582DE5C928633C9EF228E6C58819
+:10E2500009E4C550D70F65FBF8EF1CD11FDACF7961
+:10E2600049B4BE0DCE9BB1B87037CF8301EB31BC42
+:10E27000FF5BF6C02F48FFE2EF41E1BDDD799D0E67
+:10E28000539E19EF0CE0D504CAABC1F3DEB8008190
+:10E2900009945783EA859BE0FFF1382E6BA691C65F
+:10E2A000D789F29D3C1DBA9FF2D2604CC1D219F3BE
+:10E2B0001E27D13CF73B2F70BF3BC647F75337A70C
+:10E2C000B8BEEACDE3E44FF5C33811F2137EC7E6DA
+:10E2D000A6F36BC04F660150343D06F8A91D7F437D
+:10E2E000E59BD9CA3D1CF539F0E309C4F7B76F0DBA
+:10E2F000C844BEA9D9592021BE1B0CFC3E9DFC6719
+:10E30000655F50F93D0431327B2DDD3B40671CE9F0
+:10E310005B104EF70E9A45367F533BFAD59AC3E908
+:10E32000BC3F8EE7936C08DA9F147238DD05A5DDDB
+:10E33000E877F7511EB2D97B79BC9AE57AB39DEDA7
+:10E340009CCBAA99FF9BA75235F3A8D97E849FE75F
+:10E3500062DE6CED392E49E957E53FD11CEE5A1BC0
+:10E36000A61D5FAB1C5872F2480E8EE3BDEE31164F
+:10E3700029F26E817E1FEC5BCC2FE3FA838DCE03F6
+:10E38000AAE702A7312795D3C17222DF3BE51574B6
+:10E390007F7E266BA2E7B3F3A726225CC37C43E310
+:10E3A000707DB4A4FE7D0C078D6F5C312C1EE635AC
+:10E3B000CE3DE57D2C4BD60BC76589E4280EBFEF1B
+:10E3C000156A177583EFDDFB6AE1228C5B8F1139CB
+:10E3D0001DD8879C0E65C0CF6254DBF981DCF4CC7C
+:10E3E0008925B9A1F1AB7253B68039F0FC817A3F2F
+:10E3F000A4558EF267FD3D01F770C09F447EADD9F4
+:10E400006989A2F529E699417DA5C8CF2223F72F76
+:10E41000654C6D4AFA93FB1B268792CF8B717F6404
+:10E4200096CCD763A74D5CDE4E7F15EE46FE9ED799
+:10E43000E9F544920F932A1F3F4EA2F33D0CFC8F47
+:10E440005BDBFA1FAD7966BA33F23758A22BAE6F99
+:10E450004AC09E9F36B8FB47F0BCFC0EC4D79E381E
+:10E46000BE7E9E857968B0BEB353C278E9E9582B69
+:10E47000DD170ACE73C6989DE66752E607239B8098
+:10E48000FEB44589AB3504CDF7FB90449AAF54C830
+:10E490009A183A16469B3C15E5FE416E27E675FA3A
+:10E4A000B50BBFEF0D61366110CD87E2B1B2813996
+:10E4B0001B787C96E637DF68B5E1B99CC55344AF5D
+:10E4C000407602C689F1BC18AB9DE75555F36F073E
+:10E4D0008FD7A11F9F3591E1FC1C22F3850CE2E34D
+:10E4E000C5F1C9400FA20FC05334E3837EDD94FF12
+:10E4F0002754B2A11FB6F75F0FF2F8723DF71F6104
+:10E50000FC1B893EF130FE846B8FDF842C0AE39F75
+:10E5100093C3F55403EE208A68673B93FE2D09717F
+:10E520003E807C98EA5AD67D0EC6350A2C768CDF62
+:10E53000B12B0DDD514F853189F26A8D71F0BC5AD6
+:10E54000D0DD42E48712CC5B67233FE0AC360F1B83
+:10E550000B8AAF015928BE3A0EE36BFC2ED17B1813
+:10E560009F1DAF9C6FCE625FAAF8A3F89A88E3A3C1
+:10E5700078B58BC66941CA421982711EA2839BE697
+:10E5800011CA3C4A3CBB85FC83150A1F0E3AC4F9EC
+:10E59000705018D7773B8F30379EFB6AFEE1AEA2F2
+:10E5A00070842F18494F019E281FE0DB7FE571A979
+:10E5B0009DE78E27E03E4CFD0F7B12D04FDC697249
+:10E5C000893530EE9D0516DB027B20AEB1E3501895
+:10E5D0008FEB2871BE5B9479EE602D0D35509F1F37
+:10E5E0002F328C03E61DF484A23C0F54E2B2C1FA30
+:10E5F00070F025B3EE772D4C363D9CCF34701286EB
+:10E60000C8827EFFF306D7B9AFE574F0BB9F2763DE
+:10E61000AE6B3F147FCB87CE27E438DFCC21BB36EF
+:10E620004E54F02E20BE400F34239D9FA936D3EFC9
+:10E630001A34579BE3BD9AF135CEF847029D73FE1D
+:10E64000D73FC86EEDCA53F3E33485E073B31C4E75
+:10E6500071B767AE1828EEB6BAF26B5A9F34E6333C
+:10E66000FA1DB1C62BE5E4075C2E66B889C4EA6FD3
+:10E67000FD3F95083F7E8B95BE173CFE6DE0CF7B3E
+:10E6800080505BC19FC7D20DFEBC2703FDF4382A22
+:10E69000D7803F8FE533E0CF63FD2AF0E7117E0A94
+:10E6A000FC792C57823F8FCF9F007F1EE177C09F60
+:10E6B00047F86DF0E7117E0BFC792C1BAF7C5248BC
+:10E6C000E39ACBE8DEFE82D088A5E8677493C3C9DD
+:10E6D000DFF8C8D1B793576367F3BF34E8E8DCFFCE
+:10E6E0006027DDEF9D24C95141BF47D32DE8F76A6C
+:10E6F000F4BF6F9350A9FF7D9B7857DFA0DFC3194C
+:10E7000018F47B3943827E4F47FFFB36B75E1AA76A
+:10E71000AB1F7C56FFFB36038F95EBE0C7957C99CA
+:10E720002A1DD3A5D742902F56578E8B64EDF8172C
+:10E730006A89EB2B8F667FF5C987C409EDC59123E4
+:10E740006FE6F6FEDDAF2CFBD6033E77B14827C659
+:10E75000DD77390CA4979E59154671588B77E029BF
+:10E76000E49F5D0E2621FF3C736548271C4F2190D6
+:10E77000119F275472BDD0ED6689F839A1D227E2E6
+:10E780007DD1DBAEF8ECC88F4F46F0DFD9827EDD5D
+:10E790000BA0BF7747F7CFC238CE3361C0CF286F09
+:10E7A0001E5F682AC091570D0CF523D84ACAF32F73
+:10E7B000FF3E4C398F7A95EEC345A24E07BDB4ABF0
+:10E7C000927F3FDD7B2554EB0F3DFEE3B5F0C28821
+:10E7D000AF3AACBF6366328E378077508D50A6B3A8
+:10E7E0004AF618E2A38ACB4F63A581E4E932C81345
+:10E7F000E207664D74617838215EFB3DAB9E0E5595
+:10E80000C94B719ECFAC34D26ED930F1D57D37C3B0
+:10E810002BAB0F8AB4CD2ED97CA1EDF977EAB8578E
+:10E820003BF8FCA2ECCC80762E0AF0E9A6FD6C7BCE
+:10E83000BDF6F7AC7EAFC8E7EFF0FBF0DED30A3FE2
+:10E84000AC54E47398B866443A8E239FEB6BA0A750
+:10E8500080F7B12E4F63F43BA2BF2B4DEED45E9EEA
+:10E86000EF95CA389E53E6B54691FB67B05FBCC7CB
+:10E870002E9615623FAB9D8CF4F86AC7D7F518B792
+:10E88000BB5CCAFBEDF9885740FC76AFF509D87F31
+:10E890008FB91E2ADDCA38BB55B650BDDA9F6477E2
+:10E8A000737EAFFA9AED85F9E2215B91ECC559CA06
+:10E8B0008FBADA68646887519F217CD96AC43312A1
+:10E8C000ACDB8C630CEF33378619699F62F5ECD3B0
+:10E8D00004AFB0713842AECDC6F3176F29F38990FB
+:10E8E0006582DD41F3499726476A7FCFF55A7AF072
+:10E8F0002D93CB7011C631E06F22FD7E4747EFA903
+:10E9000076F65AFAEA4FF88F78B20B0FDD8CEB6788
+:10E91000D94976415DB76D1DC5D76D2B42277D88DE
+:10E92000EBFE52858F9E0E1DF33ED61F18C17F074A
+:10E93000A779C4ED3DB47A72BB32EE6D0ADE0B8E60
+:10E9400039BE9A0BEF8F745A189EFB18293B7AFC3C
+:10E9500002E15122E5351FC01A1BF05CC5C13C55D0
+:10E960002E9CA1287FEF8E9ACA0EE1778AB99DDF8F
+:10E970005A3C9E9E4BCC39B237BCFF498B91FC1A56
+:10E9800078FE9372B94F19CF070A1EDF57E8B05BC4
+:10E99000A14333DA132877A13D217B6157EC05B7FA
+:10E9A00027DBD09E64201DB83D69417B9281FB6FBF
+:10E9B00013A8DD5FD09E40993BA288F6232F232326
+:10E9C000913D99CD16035C08E317DBA1D71DA9A2E1
+:10E9D0008E3EC5DD4375F4191E13AD83878625E889
+:10E9E000E021C6141DECB87253903DE81B640FF48F
+:10E9F000F624FFCB21BAF6FD0FDEA1AB2F718CD729
+:10EA0000D58FCD9FA8AB1F6D9FAAAB9759635104BB
+:10EA1000CC37EF4B467E685EA73522ADAB957D3493
+:10EA2000D5DF027A923F56F05791E456C5471E6BE8
+:10EA3000DDCF33D07E9ECC243CDF495B96C9BA7AC9
+:10EA4000F2A30E9A9C09780EB1BE04F80FCF231ED4
+:10EA5000AC18C5683F1EF818E42ACF79E24BCA3BD0
+:10EA60002A96F5237FE99251B7AF5610B43F36206E
+:10EA70005BBF7F96778DFD33EFCDCAFE431BBFACE6
+:10EA8000FDDF450AF6CB40AE441CF7D3A1937623B5
+:10EA9000DF7CF819B757CD9F3DD51D9F7F824DA1D3
+:10EAA0009F7DBD9FEE8E7CBFAF553E5CA15ABF6B74
+:10EAB0006B26FF1D9A370F266FC7F546AE4920FD1E
+:10EAC0009F9BF5249D47BC7CD040BFD3995E5C13CF
+:10EAD0008A78D97A685D98FE1E95464F909FAED190
+:10EAE0001322FAF751FA7A6342004EE6C4C1F6FFE8
+:10EAF0001710600A2E008000000000001F8B080025
+:10EB000000000000000BED7D0B7C14D5BDF0D99DFD
+:10EB10007D259BC08604DD400293F030228F0D7965
+:10EB20006D42122621D0A03C36801004E384A0D090
+:10EB3000566DEA137B6933493089014B546AC1FA37
+:10EB400058B1DAC7E7FD9A5A0950B15D9E55A1B296
+:10EB500048B051515779685BDA0F155AEFFDF17DD6
+:10EB60007EFFFFFF9C4976864D88BD7DD97B939FB4
+:10EB70004ECECC9933E7FCDFAF73608CB1CF24F875
+:10EB80001F9BC0422E463FBC3DD5D42E62A1ACE8AF
+:10EB900076B9A97DB5A9FF0253FB3A53FF1586E765
+:10EBA000AF642D1CAA26C0DFF833FDE2EBB606C623
+:10EBB0004257F4F5CBB30524DFC48BFBE5775BFB51
+:10EBC000C685FF768F5B653D9FC25857B714746644
+:10EBD000C075EC2AA6E5C238DDD620B3D0D5CAE090
+:10EBE000F92B3DBCED64C10D53E1F9B66E9BAF5DF1
+:10EBF00066EC45FCAE93B1F1811B860612192BB170
+:10EC000085637EB7F49CF1BBAFF42C18CA62F4D3D1
+:10EC1000AFBF10E3BED0E0A275ED6CF0505B7F2E6D
+:10EC2000FDDF7347E7E3BCB3241FDC86F997273386
+:10EC300058F72F2FAC74E3B8305FC6463036A33395
+:10EC4000ADBA712C63320B2658A1FFB62C89B5C31F
+:10EC50003A738FF1EFE7DA95644F0CB8326635C23C
+:10EC6000FFA2F1E007E174C11AC4F1F68C5BF2D0A7
+:10EC70005418FF60B7C4703E0E75B53B3009DA3DDD
+:10EC80007C5EFAB8D33FB5F6E119FE2B3E136F80D8
+:10EC90004BD1C96186E7B9572E1C8AEF3BE4F9C90D
+:10ECA00008DF4BCD93B178131D0D33B54718FA8F9C
+:10ECB00097016F93FAC7C37681876D8807B86E8F07
+:10ECC000F3550762E06DDB78E7EA60D43A1B7C40DD
+:10ECD0002C7978B5D235F74AC91702F89CEFB6FA05
+:10ECE0001078059E7AA93E06DCFDC78D7492DF1D63
+:10ECF0006F800793960FC8076B8E37B6EE8BEAFFCF
+:10ED00000D5F62CA6937FC51C00A68FD9778FFCF72
+:10ED10000D5AEB3E3BD031634A27AC93552E64AC81
+:10ED2000B0FFFE8C35D1FA7438B2CA64C65207837C
+:10ED3000A70E7AEF227CF5F37EDF381A63C3019EBB
+:10ED4000005E9C57EBE4C0C33E1C275225E1F71F31
+:10ED500070DF2A45607DDF75DFBA17E9F3D07B0EDF
+:10ED600019F97AF77B5D6978FF60F6F634A4FB83C6
+:10ED7000F04E18DACC065883B643BBDE8DF4F54A64
+:10ED8000F76DC43F32AB3F3889CB015F3B74DB9EEC
+:10ED9000C5E9B0BF79BD24E4CF01C1AFFB04BFEE2C
+:10EDA00069F0523BD420D3F5170D59747F57838FE8
+:10EDB000DA3F6FF0537B478342EDAE864ABA1E6955
+:10EDC00008D0FDC30DD5D4FE75834AD76D59B7570A
+:10EDD000A03C3A9F0600807535B9E7D962E173B669
+:10EDE0002C19E8E64B5EB781AE667A920DED19AE4E
+:10EDF0009186FE656C8CE1F9F44F27189E979C9DD7
+:10EE00006A684FFBB0C8D0BF30526E6817F45C6DB3
+:10EE1000E8BFA062A1E179A07899717E5202C997FA
+:10EE20009D6719C9E579B97586E73BF10F94C31F52
+:10EE3000B2A09681705938A03CD5E5F45E819FDD83
+:10EE4000023FBF14F8E942F8139F571AE09D7FBCB8
+:10EE5000F39A29C0AFBF6A584DCF1D5943CF49F02F
+:10EE6000DDED67E365947BFB1BEAA9DFC1B71F24D7
+:10EE7000BAD929E671D0CECE4929D8B6C84D968BDD
+:10EE8000E793D763E4F3F1953790BCDCD9DDE44632
+:10EE90003ADB115930287DA7F7FBD5B90533902E01
+:10EEA000FCDDA0A3322EADF7747D75A9F1F57EA827
+:10EEB0004F63E909F3B857475489C13AB6F7D43FCD
+:10EEC0009488EDD0972519DAF93DEA0CC4D7AE2C19
+:10EED0008B47B250BF190ACEFBE46DD7E0FD1DC7CA
+:10EEE0006D569CF72190FFB88E9DA06F9DA87FCF97
+:10EEF0006D754F06F8BFD8F3E03593A19F76C6E64F
+:10EF00001BC72E9EC7A86C89E4C2B6894EAB650AA2
+:10EF10005C8FDB5808E5974D25787645B6D215F518
+:10EF20001FBF5F4FF8BA32DB43EF6D3FF95C32B67B
+:10EF3000ADAC9EE4C08BC7AD95C118EBBD12BF034D
+:10EF4000B223EF4283DB03FD0F1C5FE146B9B2A39E
+:10EF5000878F9FB75673239C0E46B626E0FD9D59BA
+:10EF60003FA371774FE276C5CEE356A2E79D13AF7C
+:10EF7000D8E0CBA575FA1076703F01DBDB7A6CD454
+:10EF80009699CAC2292877A460BB05D7B382BD066B
+:10EF9000CFCFFBA420F27D1ED31CC0A26CDBFF6B85
+:10EFA000599CCDC1CF6C9731760B7F994D3B6BD47B
+:10EFB000B3453D463DE2885C383A1FC6EB3AC3E5AF
+:10EFC000DB8C4F8D7AF7E01B999B028897337C3E50
+:10EFD0003B8E2F58548572E77989DA8D93563DFA26
+:10EFE000757CBECDED73C2F7BE9CFB644B327F7D5A
+:10EFF000C85C9847B19853DE19E33C0E5E59C73E92
+:10F00000C6759EB4D13AB61DE7F6D5F92CBEAE9DB5
+:10F01000BE3AF66DE42F617FCD78FBFBD74C4A41B9
+:10F02000BAB0925DF182EF67C939289F3C9281EEB8
+:10F03000004E4437E7BB198D031245BA15C629F0B7
+:10F040003B3DED1EE4C70EA29F836FDB7C4DF8585D
+:10F050003AB4F736E89F375262B8A22F074DF2F262
+:10F06000876E43FB16D9282F9DAC6A40BB61DA59E5
+:10F070008751BE7EEA308C57C0A29E133EA39E6786
+:10F08000FC0576895D5D8676090B2F1A94BE66AC09
+:10F090009EE4C50EC67CED404085574A0AC1EFB8D4
+:10F0A0008BE057F0DDAA698CF4B43A0DF981883110
+:10F0B0004A2F5FD24EF1682C255F7C0AE980D94E39
+:10F0C00047A07F1B10C967A8BB851E378FDB9FBE7B
+:10F0D0007FC03D84E47D718585F8E7BBEE5749BF6D
+:10F0E000779DE2FA1D7F224077D7E21FA8EF4F39C4
+:10F0F000881E5E986D2139A2DB0B0B996247BE9981
+:10F10000E73F67BB1FE836E0AA99740B5C5F78A302
+:10F110006B24F2EF0B6817907CE8207E7668895AA2
+:10F12000328CB3ABC7497CB813F8CA85DFDDE52460
+:10F13000FA043E5D8F76C2AE30E7A3AEB3566EE7FB
+:10F14000ED72139FECFE8383E6DDB5D6CDFD8B33E8
+:10F150000E05EDF09D6B13E9FDF17262C88676FC39
+:10F160001A3E7E8FC0EBEB02AF07859E7A19F594AD
+:10F1700013F5904CD7FDC28ED88B768413F5995F2A
+:10F18000E833AEC79E3FFBDC5B48FFE777C591BD28
+:10F19000399E6575E2BC762538689E66382F558D98
+:10F1A000F4BFA4DA682FCC9968A4FFABC78E34B43F
+:10F1B0002BD3C618DE9F957295E17945428EE17991
+:10F1C000B96D9AA1AD5C30DA0BF3FDD718E9498926
+:10F1D000B21732F1FF467FF1DA687F11E5C8D90531
+:10F1E00064AFEDEC117AF964E65075E2C5FCB3F357
+:10F1F00024D79FDB8F7F9CA8C6B01F3E14FD7E27BF
+:10F20000F07146E0E3B7A39493D94097E74F7EECC3
+:10F2100000A5D12F1DEBEFEBEF7D183C31245AAF49
+:10F22000A74B32D1B7DEFE43D75BE3F1F960F902B9
+:10F23000F4585B04F07CB794D8D10EAFB4DAEA9FEF
+:10F24000C0B6A6D9D8D3B9048E2C1B3D9FE0437B12
+:10F25000A539B1FE07F87C5BA3D3B33505F9E85BAC
+:10F260003FC1F61A6005275CFF1C372AC880D51CF1
+:10F2700053B9DFF28C3D30D2877AD31258760BF433
+:10F28000D7B6387C4FCB17CF2761AA4567F61DA8A4
+:10F290008724C1F7FF695113A6C27DE5590BF163BD
+:10F2A0001C38A2380F270B8490FED96A6519F20723
+:10F2B000B302FFC0F51B39EA30ECCF14267B601C8B
+:10F2C0001215F03D4BF8C07F58605E7656AFE138BE
+:10F2D000CED52061809F1FC85653A9BF6D018DFFF9
+:10F2E000FC5CC6DA492106A89D7B17F3B427C1FC54
+:10F2F000986AFD18DACBC0CFC7EF5BDD37931E7A73
+:10F30000EBB7D6A014C35EEA85F3CDF633119DCEDC
+:10F3100032FBEEEF1078ED1274B12323B02C965F20
+:10F320003815E182F6C5BBF324A4AF5CD71005ED18
+:10F330000A58A05405F27DC7FB57BB6B63BC37333B
+:10F34000B776EAD428BAC80D774AB509080A4DC27B
+:10F35000756D83BF715D3FEFB68610BFE7131C2448
+:10F36000B7FB5B4761C4A8870B7A8C7E3763CB3DC4
+:10F37000A7AF427877583EBB2A9ABE94F5D1F4F5F0
+:10F38000FCC5F44570BEFB6816C1B5D9C2E94B0394
+:10F39000FAC2E75A793DD197666581E65CA2377A71
+:10F3A0007F8DCDE57182845C353593E8A62B71CED7
+:10F3B0005B2199BE376601F97135C28FAB2139FFE8
+:10F3C000F23190F331ECE8DDC7168F8C00FCB68D7E
+:10F3D0005B3212F9BC0B15C0089C7EFE52B42F7B29
+:10F3E000DB802EB20367320C55C1F3DCA50AF69F11
+:10F3F000ADB7F378FF32DEFFA6A99BB668F8FC7ABA
+:10F40000F19C2DE4FDF5B656B0B40CFBDBADD47E1B
+:10F410005BF47FC8A7AC42BC3D90ADACC66B361A5E
+:10F420002B703D3D45F90AD2E9AAA98CD67BD714A9
+:10F43000E5E6E8F6CF262BB746B7B7F5FAA71DC223
+:10F440003FBD85ECD2977B16905E9259E01AD43B73
+:10F450002F87791C6ADBD881FD9F5F097B7EBFF017
+:10F460007FF6A23C223F88FB3FBF147AE545A157B7
+:10F470005E107A65A7D02BDB857FAAFB47AFA27F02
+:10F480000AD743C23F7D05FD25E8973BEE04D91519
+:10F49000E73F65C4BC4DEE5F48B1E46A659AD17E32
+:10F4A0009B9562B4B72A128CFAA6DC66D437CA855B
+:10F4B0004C43BBF4DC0443BBF88CD13F2D3A596478
+:10F4C00068FB8F971BDAF9DD579BF4CF42C3F355E6
+:10F4D0005365C2E35C9FD14FBD26ABCED0AF0F6F5B
+:10F4E00001613F3C968076DCB6B175026FDC5ED080
+:10F4F000F1D6F54F83B7BDE49F9D3FCB445CE171EE
+:10F500002996FFF9AF8FB74BF05B02B7F32EC56FAB
+:10F5100007847ED827F4C31EA1FF43C28EFB8588D3
+:10F5200007ED42BC511C88C7837620DEA2E211CFD2
+:10F5300023DE9CFDE3AD79EC439CDF4EEA78BB35DE
+:10F5400026DEBEE435DA77333D46FB6E86CB88B7E0
+:10F5500032668C074DFFD488B792B3C678D0B40F0B
+:10F560008D782B8C18E341053D46FB2E2F6C8C07C4
+:10F5700099F10676404ACE20F0067E924274EB1353
+:10F580007A3FB890F451CB5CAE1F810FC9FE7EE686
+:10F590004EB003B2FBE0F1BCC97F7ABE1FFD3D3E19
+:10F5A00087DB355D6FD5105CF3507FC7E8972DFA88
+:10F5B00065E778E8EAB4312D7E2A4D73DF08988F2D
+:10F5C0006D2CB77B6C891B18D98B406ED6FC3E3BEB
+:10F5D000494A08301C1FECA5EC9CBCBE716D9E7A9C
+:10F5E00086F253723EB81CD7C524AB8FF4AEC93E29
+:10F5F00062AB3DCA6D78FFB621BE7680C54D3949F4
+:10F60000340F2FEBB4A39DF18D1CA508C795667030
+:10F61000786C4B071F1EE0B12D8EB73580D7D3D045
+:10F6200096862E27F87501BCA46C1C3F85DD05F37A
+:10F630005A98E3E07058CA843E7DDAA80FD1608002
+:10F64000F633F1BC7D6DCE334BB5B43EFD5BF3B309
+:10F65000AE2D1A8C333E61441D9B0CE36ED686A101
+:10F660009D3911E687F2D1EADE951E4B4FF467878C
+:10F6700069939545481F7709FD3A1E20629BDAFF82
+:10F68000FBCFC407BE8AF8CD457844C5BDE6E67019
+:10F69000FB6C218E9347F6A5126D5FB2F0426AB7FC
+:10F6A0006473FA7A6AC302A2B70480979484F3E77A
+:10F6B000F05B7607A7AFCFBB0E7DFE03D04920DA03
+:10F6C0009E8EA293BB62D1099BE3F392BFDE9F3D66
+:10F6D000A7F1F9360BFB51B7939D69BADD1C147085
+:10F6E00060A1A26174653301AEC33C8CE234351E67
+:10F6F0006B3008208B4B9A6A21B95361619E0C1CB8
+:10F700005D611C8F73E468F9638E0FFA8FC79BE409
+:10F71000BB31EE547C6684A15D7A2ED3E4274E3053
+:10F72000F99139263F739A493FCD30F4AF4CBBC6AF
+:10F73000E4C72E34F9B946796363364DE0CB4A719C
+:10F740000BCD22DBF2F13E23FC443D27BFB317CEA5
+:10F750008F2AD5C4AFC2AF31F3EB37726482B3C521
+:10F76000C3FD1A9D1FF4F775F839BC1AE17563BE25
+:10F77000AE9F7CA4775CA12F338CABBA7C3C4FA3AB
+:10F78000F7DFDAE07AAB621C63DF6F606F5500F27F
+:10F79000820D1EBA3EDEE0A5EBA30D325D1F69C8E7
+:10F7A000A27E9B1B7CD47EB8C14FD74D0D0ADD7F56
+:10F7B000B0A192DA1D0D016A6F68A8A66B7B834A1F
+:10F7C000F7C7DA540DE32063DB984F83A58CEB80F9
+:10F7D000EF45C16D4C1BCC230AEE199AC7D01EBD54
+:10F7E000C66BE89F5E2F1B9E8F5C9D65789EAAFA74
+:10F7F0000CEDCBABFD86FEC3038AA19D5C5969E885
+:10F800009FA4040CED445FB5A1BF3B4B353CDF53D7
+:10F810005A343432001F773484C20887F686305D4C
+:10F820003734BC44D796869E30C2E90CCA5FC0A369
+:10F83000C7D649F2C333D1C3304FE17201BE008F46
+:10F8400049368F25296AFC2405C6CB8A9E1F8C6702
+:10F85000F0CF82442FEEACB0E1BED3DB63786FA66D
+:10F8600094508EF98923C512C5BD8E142727A2FD99
+:10F87000B2DEEE999B0BF3387C4CF26DC5F5E20BD2
+:10F8800031E4E529616FBA27BB482ECCDF64D92A61
+:10F89000115DF3F76FEA1E13337E74F89BAC1AD731
+:10F8A000E5DEB35346BA985F5C9B1C17E5AFCD0FFE
+:10F8B000FD47452A8D979D1F07F4327F73ADA36ED8
+:10F8C00062DFBAF47E376D32DA977D741F74E13AE5
+:10F8D000C66BDF74A17C6B4FDB4AEDF6AC81F32481
+:10F8E000BF13EBF950D8CFA7851D7652D861EF0B27
+:10F8F0003B2C22ECB07784FD7C5CD8CF6F0A3BAC0C
+:10F9000047D861AF0B3BAC5BD861AF093BAC3DEB7B
+:10F91000B959240F9FB53029869FAA5FBFFA43A328
+:10F920001DF6E5A0D10E5BB5D96887DDD861B4C3FB
+:10F93000EADA8C79B95AED2AC3F31BD618E36CD7EF
+:10F94000D71BE5E1B2D5330CEDA5AA31CEB6A4DACA
+:10F950006887E9F8B93660948B0B2B8D76587FEB6E
+:10F960007D21349BF23F88C413517AAF378F8B7A55
+:10F9700005E825F702E8158A83079A317FB203BBB1
+:10F9800080FE2DB1868F4E41F9F9BAC430EEB4E74E
+:10F990007CFE9CF9F2C5DFC9D78C74B3FCB831BECC
+:10F9A00071DD1D46B856DD6CF44B1C9546B82A69CE
+:10F9B00046BF64A159CF048C700529CD902ECDFA95
+:10F9C000C6EABE5946F9FD79F58E83815EE16D8305
+:10F9D000DE71E09D4CC373D23B6DB93C5E970FF373
+:10F9E0004063A131AEE010E693F6BC61A3FA109833
+:10F9F000E06B6341FF94E2DF00BF17EDAA560FF4FE
+:10FA0000FACB42A7A7094C56269DD9FB35E8EF1043
+:10FA1000F910F6A9ED248EAFC22FE22B9F413B4A8D
+:10FA2000CFE585F9F3A8F91A9E7F0F7136E07C9433
+:10FA3000D7C6E6FF3DE7939882F6109BC2A6509D7D
+:10FA40004164D8A0E2ABE6FBB9216E07E5A6713BA5
+:10FA5000C89FBE40127927E6C1B695B9289E398A5B
+:10FA6000059FC63867FC21F73C6836E390A9E85744
+:10FA700019F97FD19C81F3F25FF21AF97FB63CC687
+:10FA8000E40F19F97FAECFC8FF4E66B25F224C4635
+:10FA90007B927060353C2738BD26E8A8F1BD96659D
+:10FAA00094874DE771379D7EA6097C31D6B9B7168C
+:10FAB000F3CDE057A2BFE1645AF214AC2B0AD72B66
+:10FAC0007ADE8DF026ADF5915D7A86E3C70FBF88AB
+:10FAD0003F3F8BC217E2EFB8117F4ED3F3D3829E24
+:10FAE0002E9E17A7A37FDCBC4C749530EC12F9B79F
+:10FAF000D874551656A44498DF7E8F85F2A9FBC3AF
+:10FB0000F5E132687FE2E5F542AD690B6C345FA642
+:10FB10000C9909789825D6EB1779ADAE064676C7CD
+:10FB2000F30D2EBA32562FA13C6AF1DE968CFAB153
+:10FB30006B943A12EBD2BA8627ADC3FCFC367B52EB
+:10FB40005AAC7A96DDF602D2A75DBB536D32BC5F2C
+:10FB500066F3D8F0BDB2B41512FA7B5FEA616417A0
+:10FB600094A5F1BA8CE71B4247F8F754AABF8175F8
+:10FB7000CC40FBB4C2533B233105E3B3608BC9686F
+:10FB8000E72691FFBA6FB893F0E6F4ACAAC0FCF197
+:10FB9000ABA912B3F8013F3EE60BA11E484BF0059E
+:10FBA0007138AFFD7D84F36AF8FD2CB34F2F009FB1
+:10FBB000BF1F8D8F0216D5A6BC82B13D224FD43F08
+:10FBC00009FCC84CA53A8B961E9E1F6291D8799667
+:10FBD0007785DDA0C7F78F0BBBE14D11773B22EC9A
+:10FBE000861661378484DD7054D80DFB84DD704047
+:10FBF000D80D2F09BBE11561371C127643AFBFC08A
+:10FC0000EAC99EAE65AE08C6D95F05FF1CE58877D8
+:10FC1000A5255809EB98A17604CAA1ED5C6727F9E0
+:10FC2000393A4D6BC4F8B8B35A9B89EBF02E3FBB01
+:10FC30001AFBA7A6396405FA3796B6A746789E61DF
+:10FC4000C85CE08F95825E96AAB30E207FE870674D
+:10FC5000D2A379946FEAE0F076C12FC23B55857646
+:10FC6000941CA935C17529B6A3E48603E910E058B0
+:10FC70009927F82187E570786B7108EFB85A016F02
+:10FC80006F4A4CFED82CE0ADC36377E957AC1A74C9
+:10FC90003D9AC6EB258E167FC5FA2AACAF5B91283C
+:10FCA0006FDA9DC6C75B20E8DF3C9E9E47DD583E6D
+:10FCB000709CEEB0E8D7DB6E63B27368D438E5FFB2
+:10FCC0006697E1FD25A17BD2911F360ED1F3C33E8D
+:10FCD000B2AB674AC5BFCE80798645DDA32E271714
+:10FCE00033011BD3F78E8A75F6379FA3E5D7D86506
+:10FCF000187751E81E86DF73DAEABDD1F5A4DD621C
+:10FD00007EAD55B733E4C7F028C03BFAEF01A78CAE
+:10FD1000F6F6E834DFBD88776F9A6ABF13EECF033B
+:10FD200039287B705A1DBB53B01FBCF30843FA98A7
+:10FD3000D089FC7634DD45F2A6BFF95CA43F828C05
+:10FD4000EC90FEF407D031D941CE391F1C477F76A5
+:10FD500021ABF785E0BD70AE6F38F22FABB6935E86
+:10FD6000CE82DFE87C9A7E5D68D2DB6EBF7D40F993
+:10FD70003BFA42431BF2CD51C137AD3696887539F7
+:10FD8000E139B7BB103EF3D333F7207E58992B32BD
+:10FD90000EE0D05A7CE7F508AFD639AB3C16A4ABE1
+:10FDA0009231F43C5CE63A8D9538BF29BB3B5D8EC1
+:10FDB0008277EB7DAC544578A7DFE5BD09D69599F0
+:10FDC000F6A7067532F4B3737FA7A7FCF76919513C
+:10FDD000FD27E595FD200FF9B97238F1C378879AB0
+:10FDE00019AB1E58A7F3C6D278E2F3F76B799D02E0
+:10FDF000DCBF770DCC47C5BA155F1FFFDE28E829A9
+:10FE00006EDC39E273F53EA78C7E069396B7AC8123
+:10FE10007635DA4968376DE27CABF3717ABD515EB5
+:10FE2000AA26BEAD36F1B5CEC7BB75B9D9C7C7894D
+:10FE300088D7B85ACE4FFDF1F1D24FC1BEA142A032
+:10FE4000A0C1AF7B63E59878AEBFA2ECDA2924931A
+:10FE500064473E568132B26BE3C57320C9DD389FDB
+:10FE6000F03D3973115F5A23D8FF38B735F63E7A23
+:10FE7000CBC475B2217E587FFC5A291BF329ACDE16
+:10FE8000DE6717671ABE4775028BA3DB48AF9AF28D
+:10FE90001BB41F308C891FFDF37B47F637C3F7DA9D
+:10FEA0004724B34684E71D9CFE5CF010C703353D34
+:10FEB000C48FCFBF352E1B53F72C9A5E61FC88C6CA
+:10FEC0009FBFB36678369999A25D73CF98A9D8AED3
+:10FED0000AD84F46CB55566123FC5FBBD6B215E31B
+:10FEE0007EE3A58FCEEE85FEF157397CCD30FEB591
+:10FEF0000FACB0235C1669EAFE3AB8BF08E822E806
+:10FF0000A37518F8E4A8CD63C7718E56585807B486
+:10FF1000E31719BF53B3D6C847663BE458A23ACAA1
+:10FF20000AEF7F6071B2AD70DDBD65D5E338DEA943
+:10FF3000079C544FC870AC7CD4034CC42595C7EFC4
+:10FF400081E72B363B19C603960A3B3F313F83C6F8
+:10FF5000B5BA97D3FBB5ED89E40F9FDE72F964C49F
+:10FF60007FDBB0FA5B03C037A792D41AC4EB8AD602
+:10FF7000ABAC1A3C6F8BEF9889FD3FB032CFD66C9B
+:10FF800068CB0FDA713E3D6017609C559F676D5BD3
+:10FF9000147EE1BFEA7C1E779F67656A670C7BA6CB
+:10FFA00023DFA2C7573567D4FC1FCA97E9FEBCCC34
+:10FFB000612D0FE17700FB1E9F800BAE7B268F87A4
+:10FFC000B6A5F96A8643FBA485799A52F0AABC8348
+:10FFD000FCA9DDEF644F13FA19F5778C1CF1647BF3
+:10FFE00094DF3F497CF744127FFEBE373E88EB7CAE
+:10FFF0005FE66DCD9B10247AB6A9598B13F97A2C44
+:020000022000DC
+:1000000097E1AE073EBF6389B22393F0C1E4E76096
+:100010005E2B367D97F0BB0DE083FCD9E3915B76D8
+:10002000C33C4E83F2D6F0B9F7919908CFDBA70213
+:10003000A1A65E0CA77BF287F13CF4E6E644D2F77A
+:100040001EA63A2EEB83476DC7F6BB2D9349CF6BA7
+:100050005C7E70FEB3B028F90EF89D57F81DFB0AC0
+:100060005C6F1CEB40BC58F7AD73E13C97D6DA29C6
+:100070002E94C00295284F6B3759A80D3F1B505F37
+:10008000AC10FCD5260F3B5087F0403B9CFCBC4796
+:10009000F7635D40AD905FD52B8D747AA3D766A0D2
+:1000A000E3AA3546BA86751ADA9BF379FEA5C77FAF
+:1000B0002A05F5731B2C1BE1F2418B25B895E46BE7
+:1000C0006054745D9D9C6FD5EB56647B14FC5700A7
+:1000D000FDAD40BDE1621DE5A9B8EE71B390DE1D36
+:1000E000C7E2699E66F8FEB3C3E144BA5C331CE61E
+:1000F0007302E818EB7EDEDFD24CF60BFE4806BE3C
+:10010000F6B4207DDF04B37CC443F4E9C0FC914E17
+:100110002F3A7C6A37671CC07EDEFF932883D3C4E6
+:100120006ABD45AB30AFD34B4726F8E09A6DFA77FE
+:10013000C6F4D1193D8F4167E5D097E345237EA9E9
+:10014000ADE8CDE78D1AA86E99F05D049FEB9ABCDF
+:100150004C2B16EF03DD6F2C7D85E8E0130F0B4A67
+:10016000DC9F7D1DE57EA2989BC69410CAD721A274
+:100170005E14F512FAC9C962BD496B2C6F56E430A2
+:10018000366C8DF46605DC4CAA0887504F38BD42AA
+:10019000EFEE2AF8C9F8CBFAF4D890F839BE10ADD2
+:1001A000C6934AFB12EC9E54B47F1EB058AA315E2F
+:1001B0003F8419EDAA64133C58AEED64B43D1E2F84
+:1001C000E4FDAA99632CE4E7541AFD529BC92EFA68
+:1001D00011D2F5F0BEF5CBF827C0B105FC3694532B
+:1001E000C3421D1D489F3560B70669FD3ECAE7380A
+:1001F000407F3C62E98B5BFDA3E21617C5BF44DC80
+:10020000A2BFF8971E0758C86FB18D0ED58BF9BEE7
+:1002100085DE9BE6A01DDA58FA152FF94BDED36474
+:10022000973A845D1A376EA587E7CD38FFE87100ED
+:10023000335D99E34966FE33DBA5BFCD17F6D304E2
+:1002400036E1F3C405F4F87D6B16F77B5AB35634E8
+:1002500061DDDA79E1F778342BE171F1220BE151BC
+:10026000B7D716FBCF2E42FE7B55F81797F27BDAF5
+:100270004D7E48BCFF494589A13FED055C3EBA8BE8
+:10028000F9F3C52E667345E50D1C055CFF2E063D92
+:10029000E88225CE633CBF319F19F35249621CFDB1
+:1002A0000A3FE1A9F9863AC1A4027E9FF2A04E91CD
+:1002B0000775893AC1B2EC737B3FC3FB0AAFFF7588
+:1002C0002AB58FDD8976DFA2449F95E8577DFA3BFA
+:1002D000E81F2F7293BC4DC992A9DEB53ACDE52334
+:1002E000DAD794D7D12F5BC488B701D40AC9DB25EC
+:1002F0005817E119C0DF710D1C2F4BD0FD9D624EC8
+:1003000057BD71A50097DF56F8457ABAB6DA482F7F
+:100310004BD481E927BB40F8D162DFD6F8C885DD30
+:100320009F115D70FEDD388AE7A1CFCF813E98B77F
+:10033000EDC71ED7FDDB043BF8450968BFEE257A03
+:100340000F67317B34BE03C592A1AE215CC8E23D8C
+:1003500043713641C257D8CED21F80FE87CB3E6054
+:1003600077C0A712BE33CC82F57BFD7DD74CD7F783
+:100370008DBB89E2FCDF9E0D2082F9DE878965AAAC
+:1003800023F8E9329CC7B7B14D75753F5A8675752C
+:10039000DF8ED3DBCF7F4F89AA2BF87AC1AEEFA1D6
+:1003A0005C575DA05F613CB7CCA88E8AB14E92C706
+:1003B00012C6FD501E4F8C8227F90946F89AED7639
+:1003C00009F13719E9D1C8E7E6EFAE32E1A5BF750B
+:1003D0009BDF839FEA09467AFF5AC10075B1E6F7B1
+:1003E00013B04E22F1F3D71780E0A43CB4C4AC3E66
+:1003F000F48F5939A3EF593C9C8E50A2A0DEB3D79D
+:100400000FF111DCA01D877A20E8D6E3A734E93884
+:10041000A40309F38621D2DF309588650CF6D7EB6B
+:100420000C54F6997BF0720EE42F8D2357F23CF2B8
+:100430001B0A8BE0F7C63FB239908FFEF931D0AB83
+:1004400032EAEDAF682E689F5BCB280FE0F6A8D4A8
+:10045000864F459A61BE5E95B76B0046A8879D5E44
+:10046000639DEBEED247CA1CF0BCA582C7550F377F
+:1004700084DE588779DAE222928FEBB063D47CC3B2
+:100480007BE21C187751B5AFBBD04E7E77ADE4C090
+:100490006BB8A956C345BF91AA755A648C33A80C92
+:1004A000FD7AC7DAE69948BF6FD835DF30B8BE8726
+:1004B000715818BFAD49BB05FD1C459E539901728B
+:1004C000616B9B8DF613BD57FEFB34398AEF7E5B63
+:1004D000C0FD845777C77D1BE1D06A7145E2F06AA1
+:1004E00057B7DE9782DF73F81A618A6F343E948EB5
+:1004F000DF69BDB1D5B7079F373A7187296BDDE258
+:10050000AAC6715BD36FF2DE1435AE6BA4A31EEFE7
+:100510008747B450FE59ADF439E292705D1F257AD9
+:10052000E1FDB6B539C9488B2DA98E5175D8EFA616
+:100530003FFFBA00F12E5BF391F51CDE0E3BAE7B64
+:10054000B457D5300F7E214FDD87F4BA74CD7B339D
+:10055000A93EAE22E95EBC8EBEF0B53684FF1B22FA
+:10056000FE12495D4179D99695752E9CEFFCD4CC4D
+:10057000A6E8F84B4BF18DAEF1F05EA6D75ABB6AF8
+:10058000C8C5F4D182F19629382F58CF24ECF7A7AB
+:100590000615FA45D21DD5B1F663BD2BE0E76A5EBC
+:1005A00095897190962D2E4CC3B0168BBA19E39C89
+:1005B0005A4642CC7AF5097EFE5E8DEA99E99009A9
+:1005C0003FC46FBFDDFEFAF7B4B1684772FCB96C87
+:1005D000CC658FD27793F2CA4E1644F9CD177D378A
+:1005E000B585E47F8B85F3EF04FF1FBF87754FCF81
+:1005F000E605CE20FC5ADBD4CD082FA6B9D890D280
+:10060000FEF924721F1BC540FEB6343AAB63D59B7E
+:1006100045564AF3904F8083DE1B322A4ADE37D597
+:1006200065623C24D2780571776FFF2DAE77100F8D
+:10063000912D5949A8FF22E92B3233916E055D9A1D
+:10064000C7FFF7026E3FFE242760F5A35E9EC8F346
+:100650009BB30B02366AB30E2FDAB55F00BA1DE901
+:100660001FFE0FA55BD273EF6EFF1DD115F30C2E8D
+:10067000EF1810F2B6B1F43F29BEBBBE90E74DF4BF
+:1006800078A06EE7C68DFB7E08FDF140A19ED72ABB
+:10069000BEF7768C1FE979D3393C1EE881DF58F12B
+:1006A000C080291E18DF4F5C7F865FE83D61CFA6C2
+:1006B000C91D817294BB87241FFA0F98AEC079566A
+:1006C000052CC110E51FE25D34EF1211D714FED6E0
+:1006D0005231EF371B5C0CF3461B1DCA7E9C7FBB5F
+:1006E000C8FB5EB7FA817BD1EFC6B835CE7F1EE37B
+:1006F000761C2B8EF351BC05892095F5FA670BF01B
+:100700001EFAADD29CBC68BD083320BB653E33DA0F
+:10071000730B98C9CF5AC9ED30DDCF5A66B213CCEE
+:1007200076FE22D3F3BE7C0078174037E7FC391BF6
+:10073000B1B4ABC6BFEFDE480CB9734CE4E98E36FA
+:10074000286FA21EBA77D1CF5C48A7EB6D9D2ED43F
+:1007500027EBE7DC9E88F4B77EB9447C79A4A192AC
+:10076000FA1D6E08D0F55BFEA4DE785648CF33C084
+:100770003C5EC953EE423AD7EDB14573CADE5C1711
+:1007800085E70515B30DED4071D59BEBA2E3903ADB
+:10079000DD49AC3E561CED593FB7DB6D4097545FC9
+:1007A000283DEB1BA8EE06E8E85C349CD6FB8DE701
+:1007B00010BCEA9F3174203B465FAF0E271D0EFA36
+:1007C000F3FEE679A79FCBADBF749EC1CF394FF33F
+:1007D000FCF479F7D73F2071BD70A7BF6C39EE17D5
+:1007E00079254FED4479BAA832693FC61A8EDA38B6
+:1007F0001F1D5512695FFBFE89566ABBB378BED5D3
+:100800008C5777652DC9B54BE137BED8C2E3CCE034
+:100810003F29F0E72CB1BFBE7D2223FE6C2CFDF1F9
+:100820004B987FFE4D999D0939336F6E94BFB4D1BB
+:10083000D119BA338A4F81DFEE45BE75EB798780D7
+:10084000317F08FE8E217F6896336E53DEE1B00E55
+:10085000F77C80FB983EB8F7EFD7C4A60F407C1E0C
+:10086000E2DD0CA75B4DF031E72702BBAA8CCF0776
+:10087000E9D76C6DCBDD8F79350DECCB7100A7D747
+:10088000F011BC17AFFC94D220AE42CE37E3236701
+:1008900036A09EEC069580FA66E382DB3763FB3C6C
+:1008A000D80188DFFEF980FB6FCFE6291FFB63D4F8
+:1008B0000DE8D76EB417A6605E30B6BDD0BD72C667
+:1008C000DC98F6C282BACC3C9C5795D15EE8DE52E9
+:1008D000F9580EDE477B017EBA0BEB0CF602ABCC6F
+:1008E000B9047CB8FC8D1B971BB33E6F7E9E3AB457
+:1008F000306A3DEEAC7A165DC7F8C77CC55308EF89
+:1009000057F59E43C2BF07F6D83E7B8CBA45FD7BA8
+:1009100053FC7C3FBF7E8EC860CF13D1EBA7D7DBE3
+:10092000956AB4FBF4B897DE6F4A218F73B4652AD9
+:10093000ABF1394B987A89711BF5384756F665A2A9
+:100940005E5866BDFED17F5A647A1EC3FF639897D6
+:100950008C4F3BBBCF035D4EFAD55C8443C9D9A015
+:1009600086F910E71C0BD94FCE344676CE60FDAD2C
+:10097000C1F66B6BE2F2A775058F979765DBA81D33
+:10098000AF4A5B51FE4CBF30D4827223A04A4FE283
+:100990007CE3958F3E7C0AF535D801188709B07A3B
+:1009A000DA5F9D600F507CA27D0E8C9C8D71982625
+:1009B0007B26C5D3337E9AE8C5AF05DB305EEEF407
+:1009C000F17D50D57EED5E3C2F637EC9380B83E709
+:1009D000F3025CEF2FC6F80D8EBBE8EC6E8CFF5C6B
+:1009E000EBE7F20BFD38F4B396D4DD3DE961F92F66
+:1009F00089DB04DB9273299E2453FCC0141F7216FA
+:100A0000CFA2F8905E271128E6E7F7B0B4043A7F4A
+:100A1000C21CDF31C773CCF11E737CA7BE90EB7193
+:100A2000DDBEFA5AA1D1BEBA0BF71E0C47790B2ACC
+:100A30000AF8BADDCED23B2646C75FAC0CE32F776F
+:100A4000159AE28C83945B61902B2770217B5FB6B3
+:100A5000A3BFBB5CA9A5F89E99EE1F10F2ABB930FD
+:100A6000C150D7116E5823DE8FD310CFCBC73A8237
+:100A700071197DE30C963FB6E42BF717723F6323A1
+:100A80005E994FA57D04B30B3C06BA65F5C3D989C1
+:100A9000E8BCAEE9BBFA7CF4F13FEF3C3608780FD6
+:100AA000964F369616B91CF0FD4F00C7BC3E1A0C87
+:100AB000ECA8F8B41E3FD7DFABC1BC410EDA9316E9
+:100AC000CA1FE8F7A3E2D836A4DBF8345509C4906E
+:100AD00097E1C2DEB829E531F5EF308B4A72A14EBD
+:100AE000E46BF4F16CCCDB487C80B4ADCF4B8A1165
+:100AF00037673E97134866C50689613C2881291DE2
+:100B0000187F76B4D9A9CDB4EA0363A3EA871CC5DC
+:100B1000B30E609C4DE70B73DEC621A5CDC261EB21
+:100B20003A8CF92B737ECA6C57EBF1751B7C04E78A
+:100B3000F507C4075F6F501ADC7A9FA4F57C41D794
+:100B4000ABD3D59C9CAF7AB1FEA4254EDD5C0BF3F4
+:100B5000D21E7351FCC28D73439884E017E5E463A1
+:100B6000FEA750FE5E28E4E7D1B458783DCABED453
+:100B70003FA544EF5BB850C8EDE1A70A651E27B159
+:100B8000B110EE93621353882FF4FA93C3A9DCBE1D
+:100B90009C5F7263E87668FF2F51277955C9D37A35
+:100BA000BE7F48593EA3D20F6E0FF27AB4C357F6F8
+:100BB0009EA7B207FD4EBD5EF7AA4EA39F794D9644
+:100BC000DDD0BEC8CF34B5938ACC7564AA8BEAC891
+:100BD00052451D9998BF994F7ED8C0F31A3F16F51C
+:100BE000FECF8AFDB2FF5BD4ED758AFDB2CF89FDE1
+:100BF000B23ADCD7DB558A4F9F9A0D365D765F5C43
+:100C00007063E937BCC8C7938B2C7A7E660FEAA95C
+:100C1000BEFD15039F0BB6B0D29837BB3660CC9B98
+:100C20002DA936E6CDFE94A34C29C27CCBE4D54D4C
+:100C3000783E41D52689CE27D8F8F0271F3E85F685
+:100C400062313F7FC7FC9D2362FF85BE7F43BF5F4C
+:100C500056C4E9C3BD27D58E75F8559BAA66613C7D
+:100C60009D79A60ECA7E9B8D317858B7BBC963C7E4
+:100C70007320AA424B1D38CE8D9B619C84C18F731B
+:100C8000DFB8CB286EDD1BF7D7AEBC1EDF3FA2C797
+:100C9000FD59D6F565F0FC8888FB2FFBF984C7D099
+:100CA0003F7AAA50A94278FC5BA1B200AFCBC47CCA
+:100CB000A0BD28BA0D3F2F2519CF9D585634407C32
+:100CC0005D9A6189E93FAE2CE27216F4516D118E86
+:100CD000EBEA8D7BD5E178CCD541FBEBEE2EE2F251
+:100CE000A9F94DB61AC769FE395BFD5C0CBBFBD692
+:100CF000228B3EDE57693CAFAEDF02B7F0F18DE3E9
+:100D000049CEAA5108E753585F1663BCBB8B1CFA47
+:100D10007877D2FB69BDF3BB3B7A7E7DFB663C896D
+:100D2000C8B4EE1AD5DA03F4C31E96A82EDDDDE5AD
+:100D3000995B88ED5963A88EE548C5C0E76BFEBD99
+:100D4000F6D11CA9F8D9BFE43E9AE78A3206B58FDE
+:100D5000C6BD80A9B1F0FE7341977B8A73864606B3
+:100D6000C09363CDC130DA19BD6D9BCA30EFE7582F
+:100D7000F32ADD5F1F17A889B5CF392CE8B4A56227
+:100D800065005344ADE9B30CE736FC3E57DD57141C
+:100D9000E52F3BBCDC5FFA64ECB9BDA89A16545849
+:100DA0006C9614B2B77D16306D73D756495E993183
+:100DB0007FFD03332E87E78BD2C0BF8B5A77D1EAF2
+:100DC0009FEE057665C515479A53A0DFCE7C358C1E
+:100DD000E3977AE57DD85E14C8A67AF7F5498CECDE
+:100DE000BC53E31CE48F98E77D42CC1BE47293ED87
+:100DF00073C8E516939C6C4D1FDF84F31F5FCE22F2
+:100E0000286133BD67CB301F38294F3D817C96E97F
+:100E1000658A7332DD5758543EC73CAE6B1AD7B75C
+:100E2000E32369F7637CF9B0EEEF977E6E7FFF6C8A
+:100E3000D100FEFE29911F68FD8E33665EE4D4CAA0
+:100E400085B1F3030FD7AD40BE3FF51DA3BF7F6A49
+:100E50004B750DEEEF3B25F203A766D60D981FD01C
+:100E6000D70972C8310DE5506F7E40D8ED22CE3DD6
+:100E70003F4F89C3E7E0CFC74FCBA37DE86EBC32BD
+:100E8000CD733DED4366B1F7C7B2473D0AFA39FA73
+:100E90007EF6297E3505C7D1F7C98E47D1368CF647
+:100EA00075DF1A8B9E478BF9FDE579D3DEBCA695DD
+:100EB000F64F0F326E3FD87EB2BF93D7E3D8789DFE
+:100EC000615C6AB917F355E727BA48BFB7E1FFA2DB
+:100ED000F46A7A919A376D78F438A6F354E5C17DB7
+:100EE000375EF89BA8AF506F75335689F2E6DB4941
+:100EF000F514F79821E066BECE9A26F0CA3C290880
+:100F0000CFF4A2C04CC2E3F39D329DFB2AEEB3ACFA
+:100F1000C1F99FCF38026FD3BEFA7249E675798C5A
+:100F2000F8E28A2C0FE969DDFEAA9DC6E5A6934585
+:100F3000C63A609DCDCADE841CE8F7EEA3B66C7C91
+:100F4000ED0789CC8EF30E64819C8375947BD5D19B
+:100F500003C9473C89C88AFB1E58C862F5D2359937
+:100F60005F350BDEBF881F1F3D371CEDF11F3CC6F0
+:100F7000F355573CB6D2B5226AFC87A709B999C682
+:100F8000E75FA358827206CEE72CE5A5AA64AB4FB3
+:100F90006198473E7F6C09C609C17E1B47ED4FA88B
+:100FA0001D96AD3998E77ED7FBF131EC7FC5376FE1
+:100FB000BC8CE85FC0E386B539CF909D9FA7DE81EA
+:100FC000F80F177F92386622D9F19B91FE6FB0B06F
+:100FD000402C3B6683C0DBD54AFD754867572B4ED6
+:100FE00086FBD5C2654E82FB0F4A2C32DA95F3910F
+:100FF000E6319EF3A88DE2CD008F9BF1F9219F9BF6
+:10100000CE892E577E6AC3F69F2659D8E503E8E3BA
+:10101000CF0DD7E24F86233FBE8BF41763FEB56238
+:10102000FE3A3F01DCCB695E0AAF1FE98FAEFE5886
+:10103000A87C17E1D496A9AEA6F3103D0B06751E49
+:10104000E2FC1F06A976CFF9FDFA112C46FDD76107
+:10105000C127E6FB3F9CC6FD821BA7F17ACB2B1E66
+:101060003B776836F2F55ABB07F1FA5461E0C7D313
+:10107000A2FDAEBFB21C99292D27FC85E7C0DCF983
+:1010800041A089D89E37D646F8D3CAC5F91E773114
+:101090004F7312BD456DD75A0BF1993BA1A31A8D21
+:1010A000665B61FDB16BF1BD3289F6F347ED7319F3
+:1010B000B08E2C22F2592DB8EF0C6CF9F03A493F62
+:1010C0006F8B5940B6852B6CC2BEFFE031652CF0AA
+:1010D000BDA8CF3CFEA2F571AC6B3966E5EDF08B97
+:1010E000D6514D400791517C1EED0F587C8D325EDC
+:1010F0009FDC8C7906758DC55709ED9AD03D5E0C45
+:1011000071AD58E764E82ABC77EF15642F7EE2657D
+:1011100074AEEC9254CE37756116B466F4F9B7EF3D
+:10112000A4B3A09E3FC5FD737EA1671EC4FD6B30B6
+:10113000EF2F6DF8BA7637BC1700BF17E36AC37C90
+:101140003CBF191FB6F9820CFD5D5E1FD9D26861E4
+:101150000FE238D28666F4CF9D22FF11AFD492FF02
+:10116000380CE853C68879C466D8BFA63295E837EC
+:10117000B91238231BAF46FF38F712FBD8965C3FF5
+:101180003C09F9E5DC34A35FDC5F7C5DBFE2393705
+:10119000889F2E916FDD01763BAEF7E760B7E37570
+:1011A00017D8ED781FCFA5C62BEE63C3EB1EB0DBBF
+:1011B000F18AFBD8F08AFBD8F08AFBD8F03DDCC777
+:1011C0008657DCC746FB0E4BB4D050844F593CC306
+:1011D000FC508B9DD39996EEA03AF75009A37C7EE4
+:1011E00038DDB1B509E375168E272D893F0F27AA83
+:1011F0005FA176C64499D7C5B351B87F709D65A2EB
+:101200008CF6539B43A63AFC534D36DA9F7062AE80
+:10121000E56DCCBB308BD527817DF3CBCF6E25F828
+:10122000D72ACC8AF2A109CF0B4579FC2113E71705
+:1012300084253C57AE3991097ABC2EA880CC7E1FFC
+:10124000BF45F47A4045BF78BA536FEF55F179ED59
+:101250001A8BE8FFAB20D26FABDE5F3BF404FAAF32
+:10126000EB4CED6EABFEFE686A1FEBFDDEC81A05A7
+:10127000E93D537F9E7A03B62371FAFB7FBC01FBE5
+:10128000135CA8EEEDD413389F13E97A7FB986DAA0
+:10129000BD7573D7ABD8FFC470DE7FCB9E834F6222
+:1012A0009DC95F7BBC6655A338BEB688B1A7932E97
+:1012B000A6AF77A74BC678A86231C443F5F8BBD573
+:1012C000BDFC72DA7FD6E424B91849F7D5A0DEEE6A
+:1012D0002F2E1A15AFA7B8E88FA6EBF5CCA6F827E6
+:1012E00070168E5B8DF1401F7D558DDE9FC62CF5EF
+:1012F00021AC530F9C4994D18E74A445C5EF840C46
+:1013000018285ED85CCFE38361D54EE777E875FD9A
+:101310008E6251D72FE2857A5D83A3F86143DEC0E8
+:101320001C2F64D2CD948F0EAC34C603E7AB9F2F35
+:101330005EB89C85EC9723FD2B16AA8B58EE91DFA7
+:10134000B90CED6836819FCB28BF14ECADEB9769E3
+:101350001819CF9BAA16EDF65BDE7B1BFB079BE201
+:1013600064DC84BFECE6B2772E23D32D81617C6BE5
+:1013700059093F9731EF43DF4B32CA53AFD5C7CD41
+:10138000B4C03751FE06562651DEE4FA3B2CF4DD9C
+:101390005ACDCD104E60570A7AEF7A1CE94B725B3A
+:1013A0000CEDDC513ABD5DFB38D2FFF464BD1DFF8E
+:1013B00004F25B99437F3F8FDA4B558B789EF5841F
+:1013C00002AAE458B94EDF2FD7E0F36BC7F48E477B
+:1013D000F43DDDADB7AFB9019FB7F58E5747DFFBE1
+:1013E0000D9E6844ED194F203F9755097DA5BDF727
+:1013F000388EDFB25C1F7F7C10EB509759F5F759A0
+:1014000010C7AF63BD6D05F5E25B82FFBB8B3B6B25
+:10141000305E755DEFF34E5AEF72D17EBD587D029E
+:10142000F9E95F7E7D7FE7EF99DBD7B3F0CCCB7333
+:10143000FBF8C22CAF7E55CAE5887FF54F91CCD919
+:10144000F2FA27E95C378C07F07C56EAA200D2B7A3
+:101450004BF20167B08037302B565DFCCA123ECE8E
+:10146000E962635EACC594170B88FC547FE31C2AC9
+:10147000E5719DB6F2D87EECA4BCF28F8A319EC095
+:10148000CE4A389E470550823DDB98A3FE19EF03F4
+:10149000EB56903DC7980FEF835FACA19D390FC00D
+:1014A0008979D8C6D247284E7FA2D06E380744CF5C
+:1014B000736E7428241FDFC3BA0E908FCBCA959920
+:1014C00058CF78E308896DA57AB204CA37D8463A6E
+:1014D0009E24B92EF29EFA391CF32EB12FC2BC2FD6
+:1014E000E58F62BD9F14B7DB513E6B4C9B59914B0E
+:1014F000F23A8CF5C756F706CA033B4BED9447D03A
+:10150000F3CF75E2DC6F3DEF3BFDC250AEDFB3F4CD
+:10151000B8EEC0F9DFBA35BB03641F7448CC9A71CA
+:10152000713EB836A0A5DF85F66F4522ED17A85E9F
+:10153000F1328D7F6414A3F87BFCA27ADA1F640376
+:10154000FB50C17A17912FD6F7798FBEF035DA3775
+:10155000AAEAF5E7D29C2128279DADE067D1801C3F
+:101560002E7ABEB8CA24EF6B8BF939730CECF87184
+:1015700049F89D81F73DDF3F9D9FEF77B283D7F319
+:10158000179418F3C7EBED3CCED79669A4ABEF4F99
+:10159000E7FEEA83D3453CB1F4C7D508974F98D509
+:1015A000877931F6283F0F0E632CB4DFCA7C0E73A7
+:1015B000D662B2EB1E1D0D4B045BDBB6E62D8A2B0B
+:1015C0005A36F3F73E9CCCEAD16FB1D9781B2E1A6C
+:1015D000E6FFA7F8D53925583FB6E61DEADFACF19E
+:1015E000FAEFFEE237D525BABEE7F19B65DE033D93
+:1015F000B8AFECBF1CC731ED7B0DC8BCBE645DB19C
+:10160000ACDB17741E2110AE1DEDC5F4A2C00A9C00
+:10161000379BD829E33C7479132AFD6A0DCA1BA6AF
+:10162000C4CE4BEB7CDF62CA4B07BCFCFD43BFB8AA
+:10163000AB06FF3D88FEF2109BCA7AF306B795E031
+:10164000BC52F4BC81723BB6FBF4282CC86FD0A30B
+:1016500037ACFE6FA0477BED76ED580DCAD52FDA7B
+:10166000FC81AEFE9DE8AA92C7CFBE68F32F9AA672
+:10167000ECC3F9FFADBF73D5B4C06BF89DFB2C4A2A
+:1016800075024FEEF92CC63C5F4FC90079BE4BC5C1
+:101690001FFE27DE3070BCC15AFACF196FB0E39E2F
+:1016A000AA3CE2A3CB4A918F8A391FFDABCB3D58B0
+:1016B0006F6E29F14367307ECC5FDFDF4F2F52CB57
+:1016C0004B490FAAD63D403FF795B9B83D13E2F01C
+:1016D000ED8B67C0FCFD8678C613ABFF06F10C5896
+:1016E000EF02C26F85F8FE171F7F37137C156E4F10
+:1016F000FC0BD2671BADAF93AFEF1FF0FDCD442FB6
+:10170000CF727AE9830FB793A2E073C3EA7F0C7CB0
+:101710009E25F8ECE0F3FB02E0730FC1D3C7E77B33
+:1017200029FFFAAD629E0F81F75EA675E6723A78E0
+:101730005BD8D7E077CFB85CEEF3BBB7E42BBF2E16
+:10174000E579E4C3A586FA4F258CED01FCE2EED2E3
+:10175000D87EF19B38DF2F9A5FEC2EE170EBCBBB8C
+:1017600004F979B7ACFAEA2BE13BEF00BC31DED6E5
+:10177000BE4622FBE27C1AA3F300747BE34412AF63
+:10178000DFBB787F584508E7ED2CE4E78CE8E703FA
+:10179000D8A4E54343F2C5707D7588ECC07D482B25
+:1017A000144B0B9E133843FB88F69F391427FD3BDF
+:1017B0005BA3BD3EFB1DE847839FFB25ACBF5CEDF3
+:1017C000A1FD27FA3E337DFFC78A50EA01DC77DBB3
+:1017D0000EF4900ADF995F61DC0F62B6376CA6B633
+:1017E000F9DF314D9E6E3C8F0AE04FF6CFF9365E41
+:1017F0001FD76E637BB0FE43DD2005C164624F6B73
+:10180000163A877325C0C90AED191D19544FEE48C1
+:10181000E3E79DE9FFCE29D041079DE7744C62784C
+:101820009F897D65FAF9DE7173F9B97A11583F9E87
+:10183000DFA39F335125E8448767DCFDC90497F394
+:1018400000178671663FB747E7ADE1F9E096E537E7
+:1018500086918D6A8A3F5A17AB2E65B1D7784EBAFA
+:10186000399E613E67DCC60243F1FC8AF9C5651A00
+:10187000DAAB4E51AF19CF143AD722A23DC5CFB53E
+:10188000A8B01BCE11317F37DE44A74E53DCC14CCC
+:10189000A766BCCC32E1E5691B3FC7B1A55BF26925
+:1018A00070BB65D3CA36DCA7AF6DB2F2BA79A6D0E9
+:1018B000B94F2D60F1D27E74982CC6EB970878EA68
+:1018C00078C183BCEE49413921F6A55BEBEFC5FD3C
+:1018D000A54BC5BEF4EB5827ED33B89E45ECE80C9C
+:1018E000DC80217209E3DDB2833B071E86F3A8ABDF
+:1018F000E6E76458710D9827D864257E6DF1EEA156
+:101900007FEF2B34C29E743A8BFB13B1ECD9DEB857
+:101910000240E274541CFF7FE257FFB5F8555E09A0
+:101920003F8FAA252EE429CCE0E74DE03E87BC128C
+:10193000599C37218FEA003E397CDF071ACA617D46
+:10194000BF03FCACBDCC788EC2E6E903F87FC525A9
+:101950008C7F2723928E7595EF8873FBCCF8FD253D
+:101960003A0E5C0F3D399DF2EF60FFE6A2DCE3F634
+:10197000EFEC82C053D3A91E9DEF7BD6E34827FD31
+:10198000EA0FF17E09FEBB39B9B43F2788FB77E641
+:101990002758F65BE4BEEF33731DFB7FD3BCD5ED58
+:1019A000C51C1EE1385EDF1ACE60D5CFC5C0C74367
+:1019B000E55C1F86B363E34B7F0E76C6EB882FF49E
+:1019C000878670A238E330C6078E0F441F3A1E93F5
+:1019D000672AEF10DEF57AF002F524B69BD5C0DB5E
+:1019E000747EDB06496E44FD1A925FC5FDF5F3BEB9
+:1019F0002579108E7FEB3CDCBAE28C41E5E1962143
+:101A00009DE5F52FBFFED2EBFF0742E7FBCB008041
+:101A1000000000001F8B080000000000000BED7D9F
+:101A20000B7855D595F03EF79CFBC8931B08F42224
+:101A3000014F0268D4602FEF04089E9B9B272470FF
+:101A400041C0280F4F08626CD1466514289D9C90B8
+:101A5000104244C119ABAD75F4120CFE7FC7AFA69E
+:101A6000FDAD15E9E38268A9851A6DA8B1551A90F4
+:101A70005AFA8F9DC10A63EBE8386BADBDCFBDE765
+:101A8000DCDCCBCBD8A1DF4CF8F4649FFD5A7BEDB6
+:101A9000B5D65EAF7D72D4C9189B01FF1993EBB424
+:101AA00002C63AB07C19C31F8D4179E9504B390702
+:101AB0009AF6F2F65768FF1636C63156CF447FD1F4
+:101AC000FE37126F7F34302C6CA4337693A887B224
+:101AD0008E65B33F634A6E4081FE0D9259DEA9299F
+:101AE000D6F932776A30DF09A77DFC6562BC42ED2A
+:101AF000131A3F149DFF93B006E5FE38F897335E46
+:101B00002ED5FE42EDEB9859FF171DD77B5C32CBEB
+:101B1000E375EC7FC46596C7D6E1FC0FE4F2F1678C
+:101B2000978C0F1B97203C9FF7F817DAFEED592A88
+:101B300063C3011F0DDF0D7E017E5DD6B853D6A1B4
+:101B4000DF5167E86D960D64F6A0A476419F42D6FA
+:101B50002D3399C076C95360084D621D30D7AA1243
+:101B6000F8DF54C063BA83CF63F8C31AD0D9D2D98F
+:101B7000269DD68671DE6474F79B7D773C8EEB8E56
+:101B8000C26DDCB1C206B731BE4E9B15833BB81F98
+:101B9000DAC3784BEFB8CD87702ECD33D73783E6D5
+:101BA00069CB32FBF59F75DE57F79512BE9746E776
+:101BB000A9A2F64B53CDF1168471DE183E97D07E64
+:101BC000C4E01A6DC3A7BF6409E133E40D6F1E01C1
+:101BD000F809F998DF007CDED4D02CEB05163E32F4
+:101BE000822AF1912F5A0EDBF9A880F868B0E11A29
+:101BF0003D23B455837D62F9DD6A68C2E7B1EE88A2
+:101C0000F30BB8EE6D12ADDBA4A3655E0BBD7B607C
+:101C1000DDAA59BEB2AE217D30E6ED29A379DF03FE
+:101C20007CB3183F3163649D967EE1E3B5A4E7B9C8
+:101C300070BF566A921686FE9FE2CF75B1E7DBB39E
+:101C400024E217C0E7FF237C16023E33F03D233E1B
+:101C5000786672E8071AD4335577EC07B85C9A8730
+:101C600075000EAAA687F6507BB6C387F8070068F2
+:101C70009CB6D798827C06BCE577CC84B293D576A7
+:101C8000170C9CF7E11207B56F61ACB21BE09AB27A
+:101C900029B43A6469E72DE370658AE7918CFEE523
+:101CA000C361FE77A06A138CDFB20D98179EC71A26
+:101CB000A4B0044D8EE578E715427D4FAEC3BF0951
+:101CC000A6EF59EF1EBD16CA7DB9E97E84AE2F6B13
+:101CD000478617E639E697059DDE761CF9FA4846F1
+:101CE000949F0C3C5F7A245EFE9556D489FCF4A642
+:101CF000CACBDF2AFDF271A300E98D79D908C003B0
+:101D0000F6005E75A4CDF2B8010E57398813ECEBDE
+:101D100065BA0BEADD580F4B5CB079D7D7AFA7D1C6
+:101D20006B5F1E378DB15AFC5DC5FE8AD1EFA1797C
+:101D3000954F257A32E7B4D8B8AED696975A108F19
+:101D40003E9995206FF9787B1FEB6FFED481E343BA
+:101D5000399F2109EEFB14F65C1265FCF914969884
+:101D6000CE4295B908573EF377C07C0B74E789687B
+:101D70003D7F6C53A60938111E79636521FC9ADA00
+:101D8000606F37371FCA9E58794E6B7D0903BCCEF2
+:101D9000D1A0DB44C60EB5D647EA619E43856EAF3F
+:101DA000049876E528B6F67359772BE29DA9070FBC
+:101DB000C880971562BE16EF82B7719C95F95002E4
+:101DC000F88F7C359031351BF94DF63B441B8789E4
+:101DD0000F46ED9C8E6C92D37EDCEF9617CC7D9BEC
+:101DE000DE897C20A749B672C065D64FE8443E3CE8
+:101DF0001295ABE3566279F158936F323A91AFAED8
+:101E00004B33CBAE95C847EF284E4127C33B914E8D
+:101E1000DACDF18CED245FDE6066BD83EA4351F9D3
+:101E200057BE13CB4BBC021EE31F481EB668FC3CDA
+:101E3000B96A5FA4DFB888F6C09F570690DF425C9E
+:101E4000DEC5D7CFE80DB76422BD007EC6AB03F96F
+:101E50006D4340263E0A69EFCBC837A58D8033D845
+:101E6000BF60ADD43B15695C61A391EFDB9A60ED77
+:101E7000E3A1FC62914BCD40B91E2AD712C88D1F39
+:101E80000438FFCE08A467BF8BB89BCC2623DDB5F2
+:101E900035AD13FD530CDCDFFA71AE704A6EF27192
+:101EA0005E0D3A48CEF448DE45FC7C96199ECF8103
+:101EB00007C7A617B158BBA783FC5C6E9EAC550440
+:101EC00060DE79207E19EC61F3EC47432530CF8941
+:101ED00022A7DF8DEB30B4D791CF160A1ADAEED2F3
+:101EE000D87A941B456EEF2694DD72C14BEBA0AC03
+:101EF0008C027EC57225A76F1DFE7D9A87E32A316D
+:101F0000FA073816ACB3F383C22CF40DF53705325B
+:101F1000B2DFBD060A57B3AB71FDF739432B508EC4
+:101F2000B5E785EEB0CAB3A7825C8E85C57AF7CFD8
+:101F3000FE762DE2E703E6F0A3FCD89D1A2279F69F
+:101F4000BB4CC63A27E23E32D53B02F99AAF43CAB0
+:101F50005FC2B0FD6397C31246021CEB7ED3533AB7
+:101F600019DE7F83F73B792D6B64F85EE1657818A5
+:101F7000C6446C7794DADD1BC8A379D9E37E8F075A
+:101F8000691F9AE37EA7B36E273E1D693F1CAD27EC
+:101F900090D3E693AD71BE17C503F2129C84B86E60
+:101FA00089E98E4F71FD42FE039D6EC4FD01A94F6C
+:101FB000E7C88C93A76CF43629A0121CF17407FDB6
+:101FC0005AA8DF22B31F73EA167D7D43E09170F3B8
+:101FD000383A8FB652BB74388FB26DE7D17D810429
+:101FE000E7D19555DAFDFC3D2F43FF0793F4FFC77A
+:101FF00044FDA1FDC3F4DEA313BEAAA66B8F6079D6
+:10200000CA18539E4043109CD70D33CBA93737E4F1
+:1020100058E5CFD427505EDCA84BA23EFF09E4EF81
+:102020002325A6BCF9D90AAC8FCA23B6F809945F58
+:102030005179C4E6DE8CF551F9C3EA1F47F91595CD
+:102040003F2CF804CA8FC002598C77EC711CBF6D0D
+:102050009939FE15E100EA250EB33F0BE3F8C9F408
+:10206000C8DE59DD2BF09CBB295ADFFDB866B133C1
+:102070007E354B7F02CF45B66D387BC7E483BC818C
+:10208000FC6ECA01937E4CFDF0D517C3BA01ED1664
+:10209000566A11EBBE44F5CC7EAEF7C4F4CBDF73C9
+:1020A000FD7BF0F5C7D768FE024E6F9FC3F86F5BEC
+:1020B000C737F52978DF4FF427DE5F6AF61CC07753
+:1020C0009AE09BC2E1BB88FE1FD3BAFDFC9CFA2BB1
+:1020D000C09B5A62B1032E417C8EB9C4E19B5482ED
+:1020E000FB5DCDF7FB698D99727C2AC13D800ECED8
+:1020F0009BFE8B69DC52BE6ECBB89A75BE64F63A15
+:10210000B42BB3B78BF24F25C125C63D4BFF1A7BCD
+:10211000BB68FF5089853E0781CF6FB2EEEFE720A5
+:102120004756D3F8E3F8F8D7C7F0789BF5FDFFFAE8
+:10213000CDCE49E7DB899E1A393D9D87BEFD75C42A
+:10214000EF56A95BCF243F9161E2FD1B380EBCEF37
+:1021500077C1FB88D88F5D45A16FE17B2CFA2659AA
+:10216000EC1363E14E842F669FC04005D6F3FE86D4
+:102170009DD6F3FE7B2537ED34804EE4206FFFD4EF
+:10218000FE97EB70FDF165D04BFE2FED7F36E82515
+:1021900013482FF936CE7FAE7101FE6EC2C3F39C99
+:1021A0006E12D43F4BE33ECDEBDB5D5C8F7D63D99C
+:1021B00007A4C76977AA0ED4E3CC73FD27255C9FDB
+:1021C000057DA432917FE127C29F06E3FE84E6ED00
+:1021D000E6F8EF0DC919A86F46F51616213B28A69B
+:1021E00057AD223A8AE955B75279B6D8E7D74BBEF0
+:1021F0005427E07D85E341ACE7DCED7B080E1F6FE3
+:102200009FA0BE97C6CBE170B2F48327D06E257A2B
+:10221000E53FE31C505E89BFA900BF73717136E8CA
+:102220002DFB5B255586725DBBB9CF77135FC4F478
+:1022300036CE87370ABAFF53C906DAC71B4F9BFC55
+:10224000BF97DA4F89DAA91B08FE37857FE26BC199
+:102250000D267C27093E95C3F7398C7F9AF0C33849
+:102260007E6A99E144BD0CEDCA2E36707F3F167E22
+:102270001CE8F71FD4CFC3E1AAD525D2DF43AB8E2C
+:102280003991DE57F4B284FE2739E832FBCB41D2D4
+:10229000CB857DEBE77EA1F8F629C1283DA5507BD3
+:1022A0002F9FEFAB45A1B420BC9FA5BF161CC1F763
+:1022B000C983FA68A8540A77E4A27D935E560AE5BA
+:1022C000050ED64F761F639BD1EFEBFEA1C23AFC01
+:1022D000D45A552C7E1DE0D25FA11DB9586CFA026C
+:1022E00016F5AF38D05F63F1DF901DE80EDE9BFF7F
+:1022F000904A7E97975AD04FE693C9AE08DCBF2A22
+:10230000520FE5D442B7D78DF3C83964E7BAEE036C
+:10231000FB1365D4226E5F3AE01FEAD1A9EB18D90E
+:102320006FF30C29ACC23C6ECDEE7FD1379E6A2193
+:10233000FB6E15F36A59F02CB4D7BBE2ECD7E6C9B3
+:10234000BA1FF174BCBDDE81F80854713BEC78FB18
+:10235000D874E4BF783BFA78723BDA40BBB92766A1
+:10236000473BD70EA21D1D0CDAEDE8D145A132DCAA
+:102370004FA66824DFF6CF9EB190EC6543666E6889
+:10238000DFFF909289FE3E639BE24777C331A7B699
+:1023900082FC07604FCB63689B18FAB7E60BF8FB2B
+:1023A0008B4E9522FCDADD63FC48EFFDCD6EC273E7
+:1023B000FF2D59E134182FD3F8B03505EA5F0E8FA1
+:1023C00042275BD4BE8EB7C3C17C32906EFAD96807
+:1023D000D681FBA078D97A7C3666FA0D7FCCDE9E5A
+:1023E0009FEF3570BCFA701AC37D8FFC8C49EFE605
+:1023F000330A39201D2F60AA130BD733CD89F85F1C
+:10240000CC742ADF00FC268DC5F9F20DA203E03B57
+:10241000F4DF6D98ACDF46F8788CD3077B40D98920
+:10242000F18AFE6D0F66209FED4EB5FB1BCCE75A7F
+:10243000E16FF0A09D3F6150EDFCF5048F9013E734
+:1024400021579AF87E727E3D8DF6EF703A271B90E9
+:10245000CF7B841FF8812CEE3F7928C8E54AFC1316
+:10246000183E1BFB5FE83901E7E5F6A0DD8EDF8152
+:10247000E5F3382F1F2639F32C5F675B9099F2E75D
+:102480009B41AE07A899E44F01513C8DEF2FFE7C94
+:1024900024E94FE0F8DAD312ED578ACA480EB95949
+:1024A00028C289C910EB611B47D8FBED3E5BBF9B7F
+:1024B000037CFE1385FA3FE3FCC5A78042A19DBBC8
+:1024C0005A0A4BD06E7EBAF492A4C6DA1D413F542C
+:1024D00002397A54C85168167180BEB23D13F600B5
+:1024E000FDDB8A7F08CAEB379AB4A3A8C31D69AA8B
+:1024F000A4679FD248F2A3AF5D0E37C33CBF6862AA
+:102500003DA5E3078E5BBB2C70F484451ECD2F7B6D
+:10251000D2034291B5E4771E94D05FAFB955E4DFA2
+:102520009E0CEF0385C8AFAFC9AC0BE05DB2A8EA63
+:10253000E8098B7C881F17E66306B0EC1B41EEC7E9
+:102540007C31E08E5C07F0ACDA268571BC55DB8E01
+:1025500039D15FB9625D1DD3619F5C85C714DCCF43
+:10256000F28097D639BF50668605AE6F4ED37A8219
+:10257000DCBFF33AEDAF3FAA47FD12CB01A796E9C6
+:102580002D88F921CDB8C0D3C15DA48FF664319AEE
+:102590003FE463848FA096EBEAC7388BCF4B7ED3A2
+:1025A000434195E6AD6BDD49F0A4CE7A9FE001DDB5
+:1025B00039E2183A10DF261FBC26F0DE26F09E0C0A
+:1025C000CF7F0A727F9E599E5FA664209E5F5754FC
+:1025D0008A7324E3EF85A5F6FD71FB2A6DE516ED00
+:1025E0006E07D2D3F15639EC96E87918F7ED34EC52
+:1025F0001BFAE9CD717A3258ADF57C36F76756A9EA
+:102600004C7099FBB3C2E0FBB3C208105E569456FF
+:10261000B946F2B85A37D036AB2FAC6388179776E5
+:102620004C4139966CBF80DFDCA516FDF122FCE73A
+:10263000434A2D7AEDE7EDDF87F946D37C717AF6D0
+:102640005F2BBE60D2532FCAD582985C2D2BE5E755
+:1026500041FCD394AB167D92FC9A163856365C0436
+:102660001C269F209F3643D3E00EC9897C12427EF0
+:102670009D80FAD91F367F211BF98675A7C0308E41
+:1026800052CE37AE59592EA48BBAF6F7153CAF008F
+:102690009F15844F2187279632F31C9A4374D1C02B
+:1026A000E9E2BF3BAE03F02C23389771382FB5B861
+:1026B000D3ED35A146842FA4815C4A477FBC57ECFB
+:1026C0003F1BCDFDDE1716DF3CD67A37433D70C188
+:1026D0001F3354D4036F2AEAD272D584F14D55B218
+:1026E000C537EB4B488FD1182B19C9CE19DF8C8F0A
+:1026F0009F0E8C771A142F35F5EEF878677C5C9373
+:1027000025897F0E8C77BE588D7AE61CBFEC55D597
+:10271000583CD335EBDDB7D8B503E39D9FC07A04B1
+:102720003EB39965BD7DA3D5EE08C0D731D2E3EFA6
+:10273000E4CD993C2D864738073C6E98A7B50CE050
+:10274000477D39B793E2C6163CBA080F1788478A07
+:102750006F235E5AA5F026DC07A5D140795EC7BC81
+:10276000EAA3DED87E46C7CBBF47F341FD57EBD384
+:10277000990310B239FB2E5607E5D443294C063D88
+:10278000F6907A17EDF7A1F732548CF7BA7D967D63
+:1027900010B8544CF8E48176D25F611F3D7989F618
+:1027A00051ED2CC573F67CF76F5751E808CA150F29
+:1027B0009CD7CAA4D8FBBED11C9FEF5CC5C29DD2DA
+:1027C000C07D047C6B6477E6B39D846FD6C8D03F30
+:1027D000D02A31F551FF40BA70A46D341C682FAE79
+:1027E0004C273BAAA5B191F0FD1AE0DBF072FEC2C6
+:1027F00038D559F8CBA40B268D387FBA88DF778C73
+:10280000E3AFCBBEA4F735097FEEBAA07D9D3B5365
+:102810001B5236DCBACF5A56D9542BDF1A222FC599
+:10282000A07D341631D69535508FBA4CE4A5C078CA
+:1028300023B1FFA83226FC80DA282C5F7F396B4C4D
+:1028400094F7E2ACE076CC3250C1C9AF62A4B2AE2C
+:10285000296865ED787B04EE9771958A65A61E0C54
+:10286000235DD589F51FD9B2B30FDBCF074C621EAC
+:1028700004BE7558F0E32FCBA5718BD61C3BAC5230
+:10288000B5F7288EE702E18F76EA327C89E382BED3
+:102890008AF175A6E86C21C8FBE56BA5B771DC5A17
+:1028A000238DA15D1BCBAB782A2EAF8297E7E788FB
+:1028B0007AE3FB74FEC4E298FBE2CEB7373A6D715F
+:1028C0004CE3D84A7B1C93E7DB98E7D99197FE65E8
+:1028D000A5A158E398EFD3F8479799F315EEB2C73F
+:1028E000313FA1F14D3F35631F765AE3946049D1E2
+:1028F000F96AFA91FF5C36BD9EFB4DF585B83F72D3
+:10290000506A44FD080E184D227F8DB713ED69D033
+:10291000FFAFC7FABFF575821E727B9925FEF1B72E
+:1029200006FF31D3BF6F1C5AA9155CFAF002BEBF77
+:1029300045F8AEE4F8FE1B80F7BB6509E20097108E
+:102940007C2F117CD138C47F3B3C6F9459ECCFCFA6
+:102950007BBE1933B51338DFE7B08E536596FC8321
+:10296000F368FFEFD45EC44BE3EB6F2FF7723F9633
+:102970008813BF198DE365D6C7C5F528EE158B23DF
+:102980005E3E3630CE0AFFE5BBB0BD19479C5D9E6A
+:102990005B4F79D149E2981AD62BD6FE2AF5EF88FB
+:1029A0009BCF25EA17955F536FD8F07335B5EF8944
+:1029B0006B5F2BD6B7B27CD22EC3820FB038A97D05
+:1029C000542EB1E9F5F6B8E3D47A6BDC714DF9F425
+:1029D0005D66FCBF1CF1336E403EC4FF487C04CAF8
+:1029E00085BD29E2E5261D8E9EA195944FBDF4E09C
+:1029F00085FD5B526EA1FFBFC27CABCA2D79171754
+:102A0000DA3FCA8FE2DC37F32700BF77E03A6EAFD8
+:102A10005009FFF1F912A69D18EA676427CE646198
+:102A200019E31221BFCED00F1AE56B43AB277F5DB0
+:102A3000F47E44E52EFBFD88E65DA85FC4CEEFE79B
+:102A4000EAED790EE536B8B7BFFC9CB9EE96724B4D
+:102A50003EC3608FBFA6C28E976859E067E91DDF4D
+:102A60001C6DBF7F11DA45718CE8FD8B9B68DE58C9
+:102A70007EC7ADBBECF91D6BA91CDBAFA6B8FDFA98
+:102A80009A0DAE8FCB9B082E97C87B73AD9292DCCC
+:102A9000AFB891E48219D785B24D2E50F97380EB0F
+:102AA000804947824FA3700EC8CFABDB857EA6C19D
+:102AB0009EDF22175E42BA187CBCF3FB1D26DE9314
+:102AC000DDEFB85135CB5FA96F28F8ECF362FE5FFC
+:102AD00079C2FCA38B5D07BF2FE28ABF2FC2D6D776
+:102AE000DBE5CF79C3773AB1FC39BFFE9F24973F2E
+:102AF000FF89F2A725DDE1423CEB3EA68513D8C74E
+:102B0000B757F0B854943FC57D94EBB727B6A7BF2D
+:102B10005CC1FDD7A6BF3BE03AB5CA1A071D26EA3D
+:102B2000BD15D1BC016F058EBB8EC33706E521C62E
+:102B30007B98C234E0A945D78FCE41F85A7ECDC7E5
+:102B4000633EB0933362E3CD14E399F3EC5B9051B1
+:102B50006BCD6BC811F38CA9904CFFF4980AC4E7B5
+:102B600046BE0E79C81ABAE715B5AB8D87487EB553
+:102B7000394D3BFBB15D24CFA272E89B44178BDD3E
+:102B800026FD877759FDC6653FDDC5CF5528621CF8
+:102B90002FD6EF1BF564E79DA3DF6413CFAD62BFB3
+:102BA0008CE87E4D41B8CFD5DF624747A4EC981D35
+:102BB000FDCC646D16E219ECE9E2F31907F014A4F8
+:102BC0007D596BB7472CF51515B6BCA4536B30AEC9
+:102BD000992C2F6961C5D9F39216C6E86161854DBC
+:102BE000AF0F664C453FC94847C27B14BAD8D75887
+:102BF0007ED77768BFDA4CBE13E507B278FDF29F47
+:102C00003E532FE0BFB9C212BF30E32DACE06004E9
+:102C1000FD3C96FC22CD61F5FB048F3971BC15ADEE
+:102C2000D2F9F14BBB187F5B741F6FAFE0FE681DDC
+:102C3000FD8E378A498EDCDA4CE3D6AEE2F7C2E28B
+:102C4000F9E65EE1A7BA3746C7F7D2385A34DF66ED
+:102C50003DE20D5306DC9362E39BF77B02CED08FFF
+:102C600030AED366482ACA577D5D1DC51559256308
+:102C7000E3619F0223F3B6A1E830E7BBBC92EF17F4
+:102C8000FC5A8AED7C20218D9198275E4771E76977
+:102C90001ACF5B995EDD2C0F5729AFA503E72F5A9A
+:102CA000B4B305977DC3B2EFCA89F2597A309F0554
+:102CB0006132D8EBE346007F0BF8F05EC85A98E724
+:102CC000CD683E4B75D93DD67C96D067CB6731FD3C
+:102CD0007F4B4B00AF16FACBAAE478CDAAE4788DEF
+:102CE000C58119C56FAF60B573AEC2BC14BCB70562
+:102CF000AF7B0C7ECFED4C0E0B63FCBF79762AF9CF
+:102D0000F1FAB318C5556143326BA6611E09FF493C
+:102D1000195FCA30CFC50DEBC275605C3672250CE9
+:102D20002F2F1B124940CFBFC8D4993F1DFDFEC6AF
+:102D300066067413D41FA4F8DCE5ABDE6FC07957C8
+:102D4000E86E1549E0C6066F19E571ADF13BEF81FC
+:102D5000F7F37D32D3D09F5DED3CCEE3341EC2D37A
+:102D6000FC525E36F1E266CA712B5E94B8F2BAB7D5
+:102D70009AB71CB0B477455232302EF85285C80746
+:102D800012F78A989C4E7470C6E708631CAA4761C4
+:102D9000FB158C63E832C515BB5AEF3C8C7CBBC27B
+:102DA000A7F81DB0CEE03A89F2BF6EF4723C7DD830
+:102DB000646C39003A6CCAC83C8AC39CF17AC81B5F
+:102DC000DFB6AC8BFCF6402F3D0AB43FB69EE7174A
+:102DD00099F94F0B04BD98784CA9FB80F07206E37B
+:102DE000E18897C22CCA839A07F850BD14E76F4553
+:102DF0003CA5B2C6C830186789CFC122163F34AC93
+:102E0000DF9647066353DE99426F6CF5849FD4F5D5
+:102E1000419E8F26576BE89F3F53C8F715CA7EA483
+:102E20007756CAE9D4C47F6A1C9DBAE3F2C3E2E9CB
+:102E3000341EFFA711EF96FB5C5D0AF34790DE7A24
+:102E400065D22FA279570F3928EF8AB130DD63EAB6
+:102E50006243FD1D28372312C5096E107833F1CE69
+:102E600058E3E695E8E76ECCF4A3FF9F391A376381
+:102E70007ED48DE134CABFBB8975531ED472B49021
+:102E800061DE9B99D785E595CC4F4F8915D0FD9292
+:102E900025BA447CA1B348CD5580BFC865CE2C6B04
+:102EA0005E55D2BC2658F9BB9678C4D04A212F3D36
+:102EB000BA8FE779EAE2DE8F46F9415965A51E3DF2
+:102EC000C1B931BB481F5969C9BB50BC8D8CE2D315
+:102ED00045A151955363FD9F9AACE554C2F85F2C10
+:102EE000D446E37337EA79701E040F8E7F12CF83C6
+:102EF000E6C99A8AEDE3E5D5B1E4F9771AF2751FD0
+:102F0000CA2BCA232C203E1CACFCBBC99503F2EF94
+:102F1000A6565AF2EF8E3AF9BD32CA459EC906DE70
+:102F20004F5B7703D59BF7D3E2EFA5B1C7781916AE
+:102F30006474801C6F311A69DD26DEE3F1C3C4BD01
+:102F4000B4A5BE97FBA46B07216FCD0BCADDC8B338
+:102F5000D187C1EF2FD7DCD987F13A83299447D89D
+:102F600096CBEF2FCFC385E23AC6717D9055F1F332
+:102F70006A4B56A3CF0FF55B9C3C1F86E5EBECFA42
+:102F8000099671AB64332EB402F1097A1FE94BA69E
+:102F9000BE6AB6AB17E7C26A712E3C3339740BE1D7
+:102FA0003F96DFBD1AE988A547C20E336EC77F285A
+:102FB0000E64EA0F474635523E8D3BC97DEF3B2BF1
+:102FC000A3E7F99D34FE43E679AEDD85E35F37CCB8
+:102FD000BB08F9CC159459279E63F36F27B9FB1CE6
+:102FE000E68D824E335D6F0E8E80FD6EAA14F1A6C3
+:102FF000862C4417EBD1783E69A4B8D187E7DD96DB
+:103000009189EF7DBF2AD63965CC2919C7DD028A9F
+:10301000CEA689883F83F2D88CC5204BA00CE6FE53
+:10302000018CCB78500F28C27391B7F736401BD86C
+:10303000876EA12F04AE00FA41FD6BBC3D1FC97C19
+:103040009AEDE2F3AD409467E0BAE3F3DCCC7CABFD
+:103050003EC5C8F027807F7ED95A0FE56BE5ACF4FA
+:10306000E039D9A60569BCF8BCB72D396C34C21556
+:103070009FD766E64D99F952E6B8FFA7D29ED7E6EC
+:10308000F6F1730B9E9427F39D4A957F9742B3E721
+:10309000B799F935D89EF26B7218CFAFF13532EC93
+:1030A000E78632B60F89FCB3F8BC2A9043DFC57DB2
+:1030B000BF50BDA92DA6376DAE1B44BDE93CE4EF62
+:1030C000CF10DE04F2F7E7C41F31F97B08E91BE4F7
+:1030D000EF617C9AF2E5CF959B48BE6C91387D6E8E
+:1030E00081FDF85E8279FA049F6CC94A4C57A704A7
+:1030F0001D374F0EFD1AE7D5B2F9BD8F4B058F80F6
+:103100008F3F5AE537E0E35F13E1017E5A519E5845
+:10311000F24FFF9DD69324FF34BEFFC5DE1F5640FD
+:103120009EF0EF4B685215D989AAB0F751A8602BD1
+:10313000F31E6E9C1C17F5E792E3BD0E90AF000FD7
+:10314000EA0A56B93FAC8AEFEB3533F56155442FA7
+:10315000FC1EF0D600BF07CC221AE9034732F45A0E
+:10316000E45F963FE91CE746B3C8B3D51B4224FF92
+:10317000179EA3FD266A7FCD4C55F8C187D27AB63B
+:103180004ADA3752E558F95CEB4BABD2F2ABD0EFF1
+:10319000A187E83B0A5BF21DAA014BBB6FBA7E2DEB
+:1031A000BEDF92BF89F6AF03084E02793ACF71EACB
+:1031B000FE3C89F2849F9786C0D303965C02BA9E38
+:1031C00029F0033A08D5B3B7349FD5FFB1BA2AEA3C
+:1031D0006F11F6EFB79FB4E6092CFED9D3AB0CCB39
+:1031E000F9867E94EF25A08BB22ACE3FB2FB4EDB50
+:1031F000F919DFAEA28ADF0F595225E206E23C5CE4
+:10320000ECE6F6153B04F059CEDB6B6696CCC5F5C3
+:10321000039A0CC9724E9AE722D558DEBB7DFC5E3C
+:103220000AEBB58F63AEF35641A7E6BC40AF3770EB
+:103230007AD56AF169D62F9619F783F4D8F105F09B
+:103240002CE774C64E2481E7C984F0F4D9E1B9357E
+:103250004AB7DAADB83E38AF1B70DCF612A0BB043B
+:10326000F89D30B5640DD62BCC68CFCB3DAB3CBDC3
+:10327000BB2AB13CFDBB2ABB3E7B4F1597A7F75637
+:10328000911C493CEF2681B741FBAEC079EA6DF74E
+:10329000E1AF09F8A6A3FFD9B46B81D5DC6EE36E6C
+:1032A000E2CF8249E7E02FCECF378F69243BFB473F
+:1032B000423FF99193299877033CE64F940FF462CB
+:1032C00095A98F8447215E5E48A28F44DB25C9BB48
+:1032D000BF92ED48BB18BDA463D69134D24B4E7754
+:1032E000A6E1F9FFC28992847AC98F72768C4AA4CA
+:1032F00097EC49A297EC15FAEB8BBF73919E517C2A
+:1033000092EB25C52777C8A85FECABE272BBE84417
+:103310008FAC03DCC5A897C0387B845E82ED492F53
+:1033200039BD4346B88A4EF650BF6228A35E529418
+:10333000442F012864C4C3F3C51DBFC4FD8B5F6F58
+:10334000F514FD152BDD16F6F790FFC7ECD791BFEE
+:10335000294DA7FDB6D3CFEC22D596375FD8CFE95C
+:103360003DBE5D323A2B93ABDBFB615D5B59C60E14
+:10337000CAD7541A9FC0B2612894C7851FDE40BACD
+:10338000B9773EC09085ED1A9FEAC7F3C5707BF10F
+:10339000BB071FA6AEE076D05AE675CE8CC9235A7D
+:1033A0003A80669488F15C1E6F0BD8798FA4651201
+:1033B0001ED7794D7FCF8ECA3CE87FEF95E3E85E5C
+:1033C00050C98330109467F6CA546FFA870E8F6421
+:1033D00094BF0FFC3BAF06C69F2EC687F34EBB1BA8
+:1033E000DA2F2E747BD1EE2E97D3A9FD7DF9BCFD8B
+:1033F0004CE35403968BFA5D2ADE3F63F246F90EE6
+:10340000F4EBA25E02EDEFFB61A8CC03F5A9470047
+:10341000121CEF2D17F93734F887FC3BB5B79BF03A
+:103420009976C265F37BA482848B58F417575C9914
+:10343000C9CB8624924FE633DE4F913247F829AE4E
+:10344000655FFC14F4AD336C633BAED13DBEE4C5A7
+:103450005D6C607FD30FF12F53B42173601FC739A8
+:1034600075B26BF65402AE619FF63CF4D0DC6B1182
+:10347000EF3B14F2FB1EDD9046FBB4F7416527FAE3
+:103480009B8E029F72FFEEFA5B905EF76630334EC2
+:103490001441BFDDDEE87DE7E1B76896F2D8572634
+:1034A000FE0ECFC3BDC3CDF60FF3FE66D9D8760BA3
+:1034B000E675EC1DC9CB35AF3CD365101DF72B6409
+:1034C00077AF7B273D91FCCC9FCBF9CE2CCF2BBC8B
+:1034D00093D3F139FA81BC9F382741BF941A6E7F8C
+:1034E000ED5D06204D443CE9D3E6009FECE9BBAB23
+:1034F0007D024C3565D6861E92A3C3FAD72692FB71
+:103500006573F8F914290E933D06363EB787997214
+:1035100000F35BE7317512DAFDDB67BFF0F36B6137
+:103520009E5F148D9F2427E06B7D4E5EDCBA5E9318
+:1035300057A25C7AEFF8A24472606B953ED7BE1E2C
+:103540001E3F6DD9A110FEBF3CF7F49398F71E29DA
+:10355000DE41FEBD3D7F74B04D406F7B2670FD1F88
+:103560006FF0C9D98302DF43D313D01DC077732214
+:10357000F8AE9ACB689CEA295A1DD6C7C3ABA21FE6
+:103580001CE00535CB8F7224E50FFFD083FECE3DC6
+:10359000FD0E72BA9C39D129230976F4E595A2DA99
+:1035A0007A5DF5311949AAD8FBE0660C0DEB1B6575
+:1035B0001BFF4DEF4BB59597370EB39597368C8A19
+:1035C000F123C37B42636D65B7EF6A5B39C026DBCD
+:1035D000CA8BAA67DAC62BF3066DE50ADF5C5BFBD4
+:1035E0002AF57A5B796EFE525BFB1A7FBDAD3E54C5
+:1035F0003051C12B7E40975B115F69BD1AF1F9967E
+:10360000BEBBBC481791E210D9DB47327A72D09F1B
+:103610007D38C977E77E394716E73BA8462827E17A
+:103620003CDF94156B1FC8EBB7F9EB5F98C3F5D47B
+:10363000EFCF89F7D727BB27C7CFE7F3BD1F177F8A
+:103640000ECFBFEA2E924B1D8BE430DEB76AC97FE6
+:103650003DBD1FD7B388FB193A72609DE994AF4115
+:10366000FCF5E2E21B4663DC2D355F1F86F2DF3C92
+:10367000BF83F961F60ED4A77AC36C2CDE3F837248
+:10368000BDB887162CE0EFAF10EF57E313CEED7205
+:103690000BBEE2CFE38067E24B6036B0D97FF6D253
+:1036A000F7FD1615707F50E9E97029DEB79EABED86
+:1036B0003BC0AF5573F9F38BE2FF9F9DE4DCDE372F
+:1036C00067AA9D7F901FF69C587856F9FFDB26EE7F
+:1036D0007F7FAEC9C322B0BEB79ABCF4FC75938F8E
+:1036E000DEBFD6A4D2B3AD299F9E91263FD5FFB2AF
+:1036F000A9909E079A347ABEDC5449CF834D216A43
+:10370000F74A532D3D0F35E9F4FE777318D1C7A55D
+:10371000028F966FFA15422F3A24C2EB224CE59D98
+:10372000715293ADF21DF0FA5E22BC5EEC391229A3
+:10373000EE1E15E2E756423EF2CC35EF8D713D7933
+:103740009E4E323F0A9F0BFD77D931FF9D1B559A44
+:10375000A104A73477F8E0C1B957F871F666B1DA79
+:10376000EF717BAA55A2F3C63B91CBF347432524C7
+:10377000CF874F4C2CCF7307C8F33A3AB7D841F4F0
+:10378000AB62DA110AE3069C7F6A42BF883124F7F4
+:10379000AC78A078A68907CB7EE5CDBD88FD8A5F91
+:1037A000FFEC22ED2AC427DE53710E1D788E5CD10A
+:1037B000FFB186BEA9E70B38BCDB8F2F1C82FA8ACB
+:1037C0001B9D52A4AF80E25688FBCD843EF2685721
+:1037D000C3AC81E3FCB6B89BCEF5FBA27ACE3F9199
+:1037E0009E13DF0E7E0E101EF0DCB2E021811C283D
+:1037F00049B4FE32F987FD9BA0FFDE7E467E33157D
+:10380000756A80FF05857FC761EF4907E1F98C473D
+:1038100022F9E85E7FB7077DDFCF7F8DB7336A245B
+:10382000BADF90B67F8F8A7A6AA05F1F86DF232B6C
+:103830008C5439F1FBA125B326FA532C7450A2D82D
+:10384000CF49D454A3E70E39C586C6952F8BB597BB
+:1038500071FFF362E55CBA97BD1CD7B5F0542353F2
+:103860000B84FF35319ED64816BF9BC2FCEDD37347
+:1038700049EF3C7019C675C6B3307D1F02CC8390EA
+:10388000C59F20A787E8DE9E69A77F2469B7E17CF2
+:1038900003C66FD0282EC71C0E8ACB6D98ACDF896B
+:1038A0007432206EE37DF92F129C69ED0E1641FDF6
+:1038B000C2C87411FEE2F7EB8B8555F7E03CBECF32
+:1038C0006CD7EF90ACDF11B842BD8EECA933604FDE
+:1038D000E13D951685DF9F32DECA087711902C1FD7
+:1038E000F5B67BE5ABFDB8FF8FA4FD3DD947EBC036
+:1038F000DE42FB6B9B90C30FA01C86E73627B7B751
+:10390000DA9ADDDECE6CB4B7320D071C5C1FA68CD4
+:10391000093358E723426EB9D9F221A10967815FC3
+:10392000D827CEE8BEE778C9DE10E57497EEF81325
+:10393000DA7547E430FADDB64E7CAC7625E26FA24C
+:1039400087C7459588BA001534AFC1B22DF7FB651E
+:10395000A6BC8B7EDA76506630FE7BBFB89F9BE1BB
+:1039600077D8F49D2185767DED3B8304B70B251137
+:10397000DAADD9AE30E6E9A828B700EE769F83F835
+:10398000AB55E5F2A1355DF37813ECEF16C4B73B08
+:10399000F9FC726EAB17FDDE3BD21DC4BFEDAAB2BF
+:1039A0003517CAEDE90AFFEEABEAA84C94C7F2CE90
+:1039B0005C9EC7024D52284F2AB090F49D64F37468
+:1039C000887D37CBA905BA467CA6FA43B89E96F403
+:1039D0006C09F7C5ACFFF15C497C6F81FB95B70AB8
+:1039E000FD2935BF3B827E9DB691AB2723BA3CA013
+:1039F0000FBD0BEF3D05DDA43FA55FE6D213C1FB74
+:103A00007B31DE56A7BF12F1B935C3C10CC0DFD67A
+:103A1000DC2471AFB95C8F6C51278588BE011FE330
+:103A2000A581EDF68B7DDEECDCE1C3FB6C5BC72F83
+:103A3000A17CB1ADA3B97CFE4A755F577301F2CD8D
+:103A400057D89F906FB215DA3795F93D78CEB57992
+:103A5000152FFA05A664DFE30958E45C3C9F38475C
+:103A60002EACADA37C82543F22BD4C3E44DF1B698B
+:103A7000F383DCCDC57CA646AFF53B02A0777F84FF
+:103A8000F2E35C74AA32DD83F885F1898E92ED5FF2
+:103A90003C3CE92899269DA57D965E9BE83B16F95E
+:103AA000D50E1BDD38CF4137E782DF762EE6C4CE58
+:103AB00045DF21DF6A8C77DCCF78FD65D5EF75A116
+:103AC0005D1F5FFEACFCD9A2EC20B9DD32CE45F41F
+:103AD00014DF7F6B2E87E7E8CF7F4FF3A1FB01F761
+:103AE0002DCBC3FD4D0F140E4D492497CBA6E8FEF8
+:103AF0006A8B9E9355DA4DE76D4A3523BA4C57438E
+:103B0000DE71304E7AAF0C340AF8767CFCE763EA5B
+:103B1000C5E351D9D1C842305E66AF4CF4893F1F2E
+:103B2000831C1C22E4E096CBFF95615EC9F6B18A46
+:103B30009FE7B3BCE73FDB799239CBEE4FBA507FBA
+:103B4000D1FC6A91DF90C252783E51758942793C2E
+:103B50000E7ECE6AF0DF08212224B1FF2378C89FB1
+:103B6000CE49C6FD64D9CB18C9CD685E0B7E9706D9
+:103B7000C7D119E92378B116DB5DB686EB5B39ACAA
+:103B80005FC278E0E598DD2323BD73F97986E538D7
+:103B900028AF07A6C1BC14C970D0B9F8F0E547A595
+:103BA00000BC7DA068F544C447FC3A1A06ACE3ECBF
+:103BB0007830E11C6C3A35CFEF160F3F8F3538B8AF
+:103BC0005350598EF37F96C91BF9796CB8BD785E56
+:103BD000B7288DCF60197A87C85F1AE7FFFC308558
+:103BE000FB47A57B98572A22FF673EEED33A96EA19
+:103BF00047FFE41045F7607DDA3885FE5E03E8DDB7
+:103C0000D331DE12B3CBD5749E47B78EF20D7F82CF
+:103C1000E71AB4DBFFF1D9E5D1B3E738D73A7AC771
+:103C2000A5937FDD539F86F6F873BEBC4368DF9C87
+:103C3000F1F03C30B3DDFEB8EFA2B40939F76AB554
+:103C4000F0A3A77C2863FFEB7CAA82F976259E89E6
+:103C500024DF5BA4C4F18237847CBB427D95D3D939
+:103C60001AF37B666B48FEFF2643D06F83BE94FC3D
+:103C7000CA42DF639AA67AA7C5F43CF3BCF4295E76
+:103C8000E3761C47E4610D58E7FEDB187EA785F953
+:103C90002CFED93C9C7F4834FF8EF8394EBF4B86B2
+:103CA000CF0E611FB7F84A287FE30CCAAC04F113AA
+:103CB000F3097AEA4F514E4DEDB1CB97B47CBB7C02
+:103CC000697734523E987135F362BE08ABF6FBACAF
+:103CD0007A32E8AB87AAC93EB5EB9D6B6A18FFFE46
+:103CE0007696AAA09F26E809308C4B28393AC3FD66
+:103CF00070F9FC67DD8FAE6AAEA7B4E5AF0CA15DCD
+:103D0000B37DF697082F532A797EAAD90ECECBA37E
+:103D1000D516FBC6E5E3FAFA797F67C9EBB8A0EFE1
+:103D20002C75CCBA857F67C9B792BEB3F41CD02579
+:103D3000F2CBFE0C3D0DF5AF0BFDCED22D35E23BA7
+:103D40003E293C1F45E9E3F107A54FA7BC1297EFB9
+:103D500014C56FAE137928F1FE22B7BB91E26D91C5
+:103D6000E2C6A5567FB189BF2E41D7BF2DD6295FA8
+:103D700028D9DF8930DB21C6705D6EE10FDD52BCD2
+:103D800081F0BFB0328BFC518AF047B94EE9941FE5
+:103D90001C9EA267D658F0EFCE31E8BC4BFB7BC629
+:103DA000EFC17FC4EFC1A76D622578EFBDE4E349A1
+:103DB00014A72A89A4109FCD3EEDA7EF5897C94FAD
+:103DC000B7E741FDFE5E85F2F2F6CF4ECDC673ED4C
+:103DD000835EAEDFA6EDBFEAD017A15CDC5B8F3E51
+:103DE00001903B00CBD081EB987DDAF199ECCCA926
+:103DF00068675AE225E6B83F683A48F4F16C530F19
+:103E00003DF73445E8D9D1D447CF42450BE27A0A91
+:103E10007B2876C9669C807A0B1C856F417F0B3DA1
+:103E200078A7E8D36B88FF7A6CEDD2F2FB6CEDC01B
+:103E3000CE9D89F8557C1C9FAE6AFE7738E6F7B1B7
+:103E4000CD92FA3F4A5E2D473C0C82BC5A597356BC
+:103E500079C5E3A9257DE27B63A6DC12FCF8976AAD
+:103E6000957F37C9E44B115735CFE976FC15CED392
+:103E700096CC2F71F966E66F887B8CE6F7EAD7D788
+:103E80009CDC8DDFBD6B7BD3ACFF78B766A967C6C2
+:103E9000BFADC6FB28FBD0B8053DF4B7353F5E8DFE
+:103EA000FE8625B5598A06F00531009B15BB476390
+:103EB000E63BC6E3ED780DB7878EE479C90FDF06E0
+:103EC0007BD29900CF2FD708BB4DB5FF3D90D424AE
+:103ED000F7872262DC43026FED2E9EA790EC9EC80E
+:103EE000D745FB64F7447E5523E2F5E7B817F21D8A
+:103EF000D1EEFB38EF70CAAFFC27E423F3EF75FC7B
+:103F000040C013FD3B1D3E96709C2E217747CFE3AA
+:103F1000F9C92E9F46DF4583F19EA2F1C4DF5530DB
+:103F2000EB679C8CD6FF33D547FF7E824E7E22F313
+:103F30009E5ED7E1D776372BB1BC9CB6E8F71679F1
+:103F40009ED3FB02FEF8A7794F25F65DA9C3BB35CA
+:103F5000CB77A51E3FDCFBAEF8EED55EA25F713FCE
+:103F6000675B0C0F3FA6F771DF19D853F3F26EF1C0
+:103F70007DC5FD047763DCF7BBD8D1DDD6EF266CB9
+:103F80003BFCD66AD1FE20B517DFFB4A4017826E94
+:103F9000FB77E3BDD1F318EF75824F7CAF6B630DF8
+:103FA000E7A364F40CEDFBA87DF43BC6F51E3C577B
+:103FB00062DF317E83F0731EF83A46E3E8E6BC4CDC
+:103FC000E443717E31F3C94CBA90E7713ADD5C236A
+:103FD00099F796FE407858356878F880E089BB9F5D
+:103FE00074AE753C3339F411F5F345F394FF83CA8D
+:103FF0009F111EF35E593C7F0C9D2799F9D129F33F
+:10400000709E9CE8F73C53E725961317342F8C9B42
+:104010004DE3C6BE133A7CDE20AC87A9E7975FF27A
+:104020005FBC10FE351071000000000000000000B1
+:104030001F8B080000000000000B0B146060F8519B
+:104040008FC0DC687C5AE3BF4C0C0CFACC0C0C978C
+:10405000D81818DC38191844F8C833E7329ABE87E4
+:1040600040B366F130302C636560D809C4865CD8F3
+:10407000F5D90922D8C7817E5F05C497E91C06A33C
+:1040800078F0E03A11068629A208BE8118AA7CBD04
+:104090000882AD2745995D2E40FD00C5F694E2806B
+:1040A00003000000000000001F8B0800000000005B
+:1040B000000BD57D0D7854D5B5E83A3367CE9CF921
+:1040C0004B4E92012721E0991031D840074C145AE9
+:1040D0005A27116D14D4887FD17A7B07DB228ACAD4
+:1040E000D47A956BB199FC4F4280008A142D8C3F95
+:1040F00054B0FA9A2A5AACB577A2146DF55DD15A2C
+:10410000ABBDB42F566BAB551B5B29F415E5EDB574
+:10411000F63E99734E66328348DB173FBFCD3EFBB8
+:104120006FEDF5B7D75E7BED3D0A5441D569008749
+:10413000F18FA5F7F900A03E93CEFAC605CB1EACD1
+:1041400063FFF6B923DB5832EBE97995B1DA4CFD20
+:104150007A90002600343E7DF91F81D5FB2F70EA4E
+:104160006EF6E9C9C0882FC2F209C909D8CE0D0D73
+:1041700065E70459F94147A48FE5D3871C7E60FDAC
+:10418000CC04278DA383E66F9EC1BECB171483A9F1
+:104190007F7BFAF94D32A4CB009EBA05E46656AF98
+:1041A0002B70EAE5C37E80E75BD37F7DE304806804
+:1041B0007ABAACB37E76B73E43F91FB7EEFDEB1B80
+:1041C0002E801894D0388DF3DE9717B3764FB9A0B0
+:1041D0006590B56B8C4AAEC5A6F162623E4F7944DC
+:1041E000B9D620672D0FB072F6BD31787ED6F218A1
+:1041F0009B11D52B11FD1C1C76623D1D467C34CFD6
+:10420000438BB2CEF338D1CEC8D70DF3F93EF9EBDC
+:10421000030B900E69286E76637AA86A1FE27B48CA
+:1042200095740833FC0E9F4DF84D237E5917075E99
+:10423000E3F87EEA4347A48DE1BB51D5FC11960714
+:1042400099D1839537FA214A70C92C65702C10706A
+:104250005F2AD24598125D74A2CB90CAE8E2CF0FD4
+:10426000EF699B1482D798E710CEB38076065DD9AC
+:10427000577F7380B583EC7C30163F6CBC938F1CEA
+:104280004E03AFCDF386FEFA860AF47798FD7F865B
+:10429000F6D3BFBE5193C99F7670AF25CF381AD4DD
+:1042A0005318BCF84F1D53F98361A33CCCCB719CD0
+:1042B00064ABFE4135E3BF8156F8A09AF1DF9A5610
+:1042C00095F2FDAD1AE5FB5A43944FCAAC09A363BE
+:1042D000B21F5209D6BE24CAEA9BC62B9EC3DA99E6
+:1042E000E00B44344BDE5713B2D4F7E8BAA53CA92F
+:1042F0005FEF4831BAF7D63A524E09E16032722286
+:10430000C2A152CAC07D39C4E653CD9BC06A97FE94
+:10431000CB2A84E70527B4B37C911E755CC1F253A8
+:10432000424E4845D8F8452300ACBFE42D00EB5978
+:104330007FFDB34E715CC1F27D73DD9A530348B1CA
+:10434000FE936ED6CF4769BD03FB99A144B01F18F9
+:10435000907F8B7852D97F87AB00A6EACA6B8E22FA
+:104360008070827D37CFCF9D08A15C17CFB17E9F33
+:10437000AA2FB91658FDA960FA1ECED0D318D7C8F7
+:10438000DBC7B38F73FC0A5BFFB67EA7E8C30D5A89
+:104390006DA6DFE361A44DF3FF2BF71B6D94904EE8
+:1043A00011D053B38E1DDCFE157F2979E3E40C9EFA
+:1043B000FB5D5C0FDAE56D181CA43F409E005106C2
+:1043C00097AE3B527DAC9FBEB083F847EF8214EAB4
+:1043D000ADD593F7C631DF1756F476960FD7EC6953
+:1043E000916602AC9AAC11DFF53DE186F6088723B1
+:1043F000C8F8748AC1A71F0D3754211F4A1059CF1E
+:10440000CAC3FA9B6D585F7BD9ABBBE68C9D1FACD2
+:10441000E0F3A73C9BFF08FEA37E6CBF3FAB57A217
+:10442000CDC8B70948B9193CBDD5ED4D0936CE9672
+:10443000840C283F7DB70CBE82784E9EC0E1B5CF7C
+:104440007B8AAE2C46BE06F3F86CBC29D5172FC369
+:1044500079D9E130F4C59DAD1A4419BD36B7D6906F
+:104460005C6E69D506514F6CFED09915BF0B24AE1A
+:104470009FEF70353B12B8CE4E77A4B649D85F6C2B
+:10448000F3550CDED5F51367E33A70FD748EEF0F2C
+:10449000FA05BEA5D4A540F5159DEADBE47F8B1C8B
+:1044A0006D47795E1D2A8304C3EB14D7DEA6A99855
+:1044B0005F51352B8178AFBBFB35EC6FCAF4693A9D
+:1044C000E2636ACD9BFB502E377F9422B99D5AC37D
+:1044D000E49ACD73CA8A8983D58C4F2AF5D4D7A89C
+:1044E0007E8DA2A7A40C5F4E86483BD2EBF8161F28
+:1044F000A4B5FCFC39393E3E7F1E3B3DF08F91ABAD
+:104500004936B9BA23875C2D941CC42FA37255C3B6
+:10451000E48AE175C74956B9DA3C39F55631CACF54
+:104520000CCEA7763E0FD7BCD98074ED67F2531A34
+:1045300002A8700FFC5942399CC5EA4B542E7D9954
+:10454000E5FFF40BAF0E284FB59CAEF9E4CAE0E7E7
+:104550004C6A1D774B9DA3B19981FAB3AB36BEED82
+:10456000C6F16A151DE5AC4FDEF467C4B35EAFE873
+:1045700009C9244FB55C9EA6D431F9C92257F9C6A2
+:104580004FB6A6E0752647EB5A43245F6B5B7592E6
+:10459000AF5542CED660D5B92C2FE40CE6CCA67C24
+:1045A0002EFB13A08DE44ED5F702DAC1EB58DF5095
+:1045B00081DFD3D1E83C80D23A230F69075BDBD798
+:1045C0008E9643142A09DF009F41F0FE9888B2F6C8
+:1045D0005A1DCF3FDEF6C7440713C2751E5EFF09A2
+:1045E000A9A62131CFDC7E0FF56FD467F97463B5CE
+:1045F000A93FECDF028FA301EB1BFDBDDA56D19082
+:1046000060E3AF1579A5BD84E78F71FF4CDF841897
+:10461000D3439FAD9FD592E827F16C34EACF8C73DA
+:10462000BBF456346129FF4314F164947FB7EDD98C
+:104630004482D57F1F9ABF25313A4C9F1FAB605BE8
+:1046400018F036ED0534A5D6D9F09D99DF0B34BFAF
+:10465000400DCFDFDDF66114F16D943F2A05DA10CD
+:10466000DFC837FE89CCAEC27FB23157FDE4474B7D
+:104670009FC37FCF29052867E3E803CCD264B3AF9B
+:104680004E01EE3B7C35F29BA3FC0719BE63F03D67
+:1046900028B174FABCD865B81466812F6186CF182A
+:1046A0003F1FBC061CB9F9938F6FE7A3C633E73CE5
+:1046B0003F8FC99B77AF2BC2C480CD4393701D2819
+:1046C00045A0985E2BF9E8E721DC8A81CCF478607C
+:1046D0006CBFA5F32B206592FB4F9A9EDFC23CC7AF
+:1046E000DB4B66BAB2FCCB663C3E88F5EAC7F29D6E
+:1046F000313F8F989F67CCFCEE69C1F9E5C29B7D85
+:104700007E6B3D032DCD59F6119F7788FDEEE7E7CF
+:104710009C87FDB3F100F597471F213B5EC3F1D89D
+:1047200056B3F8A39FB720DFE71A4F9BC7C6AB3934
+:1047300076F8CCC7C701A6BF888FEB181FD7E6E66F
+:1047400063BB3C1BF3F68A797B73CC9BAD9421DC75
+:104750008FFDFF3AEFBFC87C5E37B03E127C5E5CD7
+:104760003EFE49F3FACB736512AEEF088F93F373F5
+:10477000281B7FBD2EE9967DAE9DAF73CDEB9FC507
+:10478000A763E7353E9E8FB51E2A54BFB6BFEC2502
+:104790003CF6D5B27D02EE0B9E3983FC157DCF9D94
+:1047A0007E1CFA1FBCC94F41B40C601AF6CFEC89CD
+:1047B0003EB42FB0FF4D7505D917FDAD30D8790245
+:1047C000C023450C0F7E9A27B5DFCCECCF14537075
+:1047D000752FEC5617637EE9432AFA95FA84BD5883
+:1047E000F7C2BDEBCE64F8F4CF289DE564ACD0E70A
+:1047F00031BEEFFCE934B4E36BD977C45B80F7C713
+:10480000BEBF80F50333F8F75C70F994540CEDFBF0
+:104810004084C165E207A3FC6107B74B77A09D7593
+:1048200022C2A993BDE5F30EC690BEDECD8A7E7787
+:1048300096FDD2FF16FA74FB8C3D092FC285F61A3D
+:104840009BF7937775575CCDDAF9EE04D2E7BE9A01
+:1048500054C2C150E7AB03DA0DEE7099E85E4970BF
+:1048600009BA2E924E67EBA4CF96DF3C5AFF8B64B9
+:10487000B74CAAE5E58FB6FF4743876C2A4F5CD952
+:1048800010ADCC943FDF7E6D03AEBBD3D5D8AFE681
+:10489000B1F1A733BDD7C1F03A5D1E70C4899EC186
+:1048A000ACFCB27D9BDA92627D6CBF6B63D557B373
+:1048B000AC238C8A4467237FD2BD56BEDE21F0B77D
+:1048C00059E0B39FA117EBFB6A07DA119F27DD0BB5
+:1048D000116738B7BECB49C73BADFA6EBA6C9DD7EE
+:1048E000B19ACFFBA0F1FDB6E89FADEB2F3AF87C73
+:1048F0001C284727311A384B8E7E3E69C413B723D4
+:104900007E93ADFF7FD47CA7FBD938C14F7E1C9F1F
+:104910006D9C5CFDDAF555A2112419F7FD151041C7
+:10492000784AE6C769FFE2F4EF0D25989E95B561D8
+:104930004A5DC1915082D97F4A482FC7D45D192959
+:10494000C7EFAB3F740A79EA6943BDBA6634DFDB6F
+:10495000867A742DE6497E5651F9FAD1FC6ACA6FFF
+:1049600098CCE5EB78E76D43A887AB503931B85662
+:104970000FBDDAF2650657D96E7F044D8D327F0484
+:10498000500F1BE56B86DE0AA968C7EDF68387F139
+:1049900043A9160573FBB5437F0BE19EC52FCAFDE6
+:1049A000C1664BF9FAA1E9E521D43FA2DC1B8A518B
+:1049B000F986A1B9E53AEA93DD7E0DBFFB2AE3341F
+:1049C000EEE94F5F43FC925CE820BD6EE031B970C8
+:1049D00036F9952F9762D39D8C1E0D4FF7AB68FF6C
+:1049E0002777D792BEA7358BFC49F2FF457E245D21
+:1049F0004AEB985F7BF353825ECE0C3DFAF1BC82AA
+:104A0000FCC0FC9C2229CE29128DE934F9678A3832
+:104A10009D184767FCCFD4FE998CBF9AF27B2DF985
+:104A200080968AE23E5E0E32FDC0DAFBA28928D271
+:104A30005DA9E479A73F9246FD71C75510F1EB4897
+:104A4000F72860FDB57379DE156CA6F6BDF53CAFB1
+:104A5000846209CC2767F1BCBB329EC6FCAAE93C44
+:104A60007F874167D861E503F813D1BD7734EF69DB
+:104A7000C7F2A4C137E06BC7F2559FE37AB6426E26
+:104A80007812F17FC7D063AF2E61FD17233FB0FED0
+:104A90008B97462C74D9AC5BE9B259E7749955CC25
+:104AA0003081749075A2C7ACE3AF776878DEF129E6
+:104AB000EE176B7CFA471EB4F7EEA8994DE55364E8
+:104AC000A7F00F707FF836E10FA862D285FB9F6DCB
+:104AD000C21FF0E46DD38AB1DD939B7F48F4FE3CA6
+:104AE0002A11D66E550D3FBF7990ADD3E8C7FF6E42
+:104AF000AB4AFEBA5DACBF18D3DB8FB6AA943ED4E6
+:104B0000AA418CF5FB3DA6C7313FC0CAD36E3A0F10
+:104B10008034FBFED84E47538AF5BBA9959966AC05
+:104B20009F8DAD2AA5B7B66A7F91597FEB5B439401
+:104B3000BFD2B1688593FC1A030B66B2793DF2626D
+:104B400035F9F7E63EE868C6F6A00D5C706E5DE6E6
+:104B5000BB819F2B1D8DB720BFFE60A7DC847A062A
+:104B6000E4F8B333B2D76BC77AA73E283753BD609A
+:104B7000FCE7E704B3D6EBC17A0FEFE270831A7952
+:104B8000B6367B7FFD08EFC9DF77F0FE42919F2F9D
+:104B9000CCDEDF3AAC37B84BE6FDF999CACE5E6F92
+:104BA000238E1BF9BE80AF12CA16661FF70EEC4F9C
+:104BB0002DE5F6CA9C28905F6CD235FA5D92896F1C
+:104BC0006EBF765072303AAB65A938D63B657E4AE7
+:104BD000AA62E97157A72407D3779396B272068F1A
+:104BE00007FB61E9EC39BCFC762C0F98CAB13D4B50
+:104BF0003F3D8F95B3F4B865D67263BC495F815170
+:104C0000BF103A5B27C5C0B05F283FCDC1F38F3BD3
+:104C10007FDB80FA699AC2EBFF19F3AC9F492DD66E
+:104C2000F6D3BC3CFF5BA37E116FEF90795E6566A7
+:104C30002CEDD336AB29B4BB6E3DBF3B74853F33FF
+:104C4000DFE0A264CD15A6F9DDBA6873E88ADACC94
+:104C50007C8217DC5983F95CEB8A477740D4B40E29
+:104C60004D1BA8257BF75F5DBF5C645A37705DA95B
+:104C7000C07581E1A782310A9633BC25B8BDCAF15F
+:104C8000B6FE2C2BDE4ACFB6E26DFDD956BC952E72
+:104C9000181F6F3F13E3E7C21F1B3F6A1EFFB68B4F
+:104CA000ACE34FB8D83AFE6D175BC79F70C9518F00
+:104CB0009F36F3CD8673ACE3979D6B1D7FC3B9D64A
+:104CC000F1CBCE3BBAF10DFAF40E7DCBBAAED735AF
+:104CD00083997EC9A1DE90655D8FF075DD285F3513
+:104CE000F45808D7770FAEEFE89FA9E1EBFBACD7FC
+:104CF000DF0FA1DF7EEDE7F6846298B2BA7B6B33FB
+:104D0000EBC6939FBBD1713FEBF7EBD31D74FE3322
+:104D1000F4B94755D4FFAB6A6693BE4F8AF3DCBE45
+:104D2000D6F4FE6B5C997905921E889AFCF7A3F67F
+:104D300012FCAE01F93059E310F652797B94D9A2F6
+:104D4000EA74D992EFADE5E5377796B727D0972289
+:104D50000F96E33AE4AB810F6A4D7832FA37C637E3
+:104D6000E0C93D3EDF1767C69F6A1B7FAA657C23AB
+:104D7000EF99C1CB13727523C27387D827DF20FF49
+:104D80008EF4CBB1836F467BB4DA0C1FCF67E0E3C0
+:104D90007903BE6FCA331B13D5FF48F84EB5E1EF58
+:104DA000541BFE4EB5E06F853CE788F067AFD76FC8
+:104DB000E3CF6510BD499E807204646FC6654D9C4B
+:104DC00007F1FEEA64215F383EFAF2AF55522784BC
+:104DD00079F922B6AE5D2E8B7D98A8DF64CB1BF6E9
+:104DE0002B2E4787C98F97DD7E5580EB6DB6AD8B37
+:104DF0006C23BD1E2179CAEC3BB81F43969BA3CD03
+:104E000059F4C146999F0F4B5AA405E194FD0AF944
+:104E10001373D51F9025615F272CE73BC530927631
+:104E2000221C21A0F8243874817EFE8CB170287277
+:104E3000730CC7716A0AA05EEB2CB95837C731ED05
+:104E400030E00945091E45E3F02872249ACD0F7C15
+:104E5000B7CCFD16463F0C42D17E84CE050CF8BA85
+:104E60003CCD2D8BD19E2F51084F9D01EBB9DE6FAC
+:104E7000C4BC9E1769A7884BB28F07188D81F14B70
+:104E800013E7901DDA31A75145BED421A2A29FACF1
+:104E9000D39F3D9EC848FBD1EE3C11F95E25FB3304
+:104EA000C9EC52CC7733BB14D34EFF434DB8EEEC74
+:104EB000473ECEE2A719D5731107A44DFB6D5F8D58
+:104EC00017D2E6FDA8D8AF7AF452CB7777A8C2D232
+:104ED000CE3551267BBED3EF48E13E3F1FFCDD02BD
+:104EE0007EA35E8F1C57B502F6CBEE9015DE63876E
+:104EF0003FDEDEE71AD4B2C1F549E1CDE02B7BFFFE
+:104F00004A991227FB596E0E99F9DFE9E27CAA94BF
+:104F1000A971B29BD55CE55EDEDECFCAD12EF63735
+:104F2000EB78FEC2449EE2C4549403137E26897635
+:104F30009D2E711E0D713A3792F4780BF2915AC979
+:104F4000E4471ADBCE48BDA27DCF875F7F85E4634F
+:104F5000824AF221E923E497B78FF3801C9DE8622F
+:104F6000E926397A1CA6AE8F9CB16C7232C1C5E5B8
+:104F7000586D6ED6557E249E15FE9345BF0306FCE4
+:104F80008938F99B0B85BFAA40F84FCEC03FD35557
+:104F90004FF07F1AD35CF0CF10F094416408F7ED26
+:104FA000C8A0D82FC0F9BAD91FBE46F45B26E003CB
+:104FB000F81AD1CD28EF157828743EF30A9CCF9AC1
+:104FC000CC7C9AC47CCE1A6F3E5F10F359E3E2EBBF
+:104FD00095DAD4AC87185F95E6A0CB12D1FFE651E5
+:104FE000BA7CED88F8EAA202E7B124338FC582AF1C
+:104FF000AE186F1E3101CF8013E6BE11443349ACA9
+:1050000037B0C84297AD065FB9F9BA0170BD852EB9
+:10501000B7897E0A9DCFF202E7B335339F6F08BA96
+:10502000AC1C6F3EA6FA6DA27EBB902BB25BB6BAEB
+:105030009E6847FBE301B9B9DB559F198FD5EB316A
+:10504000D79BD4D567D45B85DFA585A3F5FAC5F8D2
+:10505000C22EBA87F6635D686330FBE6DCAEE71B01
+:10506000D11E67EDD653FFCD7CDD64ED3698FB3F56
+:10507000B96B63BBA8773BD66B3BFD23A3FF4DE623
+:10508000FEB7BAD2061C77121C4DA3FD7DDB5C6F08
+:10509000896BB09D9F13566A6FFA4C764DA834CF3A
+:1050A000B90CD7BBAE602C398CFE4A080CA0DDD100
+:1050B0002DC7B70E233F30236F1BFB7E933B2A493E
+:1050C0006CFDD4A2F1FBB05E69C2AD39916E8DF179
+:1050D000EF613EE180668C8BBCDDF7CDAD985F2142
+:1050E000AB9A3B82F6964E47436B8232C5C97549EF
+:1050F000B104AE8B07E4D82E17D93DAC4B36CE4D5C
+:10510000653AC5FB94CC0789DB1D1CAE75BE2F2507
+:10511000110E37830BE383BB6C70B1F1685FDE3B2C
+:1051200081C7DB800C3532F6E7F446B0BFA1093702
+:1051300012BCC936B786ED9327DC48F0B2B2668A56
+:10514000CF73C509DE1E97AA613CDEEDBEEB36616A
+:10515000FCD68A4431D5273870FE53AB087E0FC485
+:10516000D38BC3A8BE06A2786ED3B550A1B8E464B1
+:10517000703DED6FFB16AAE4DFEFAB599FC076FBE5
+:10518000177A29BECEE31F008C032A5BA000C6C39A
+:105190007A82036467969EEDE5F94AA0714A3FCB97
+:1051A000E3655D30AC55B1B42CC9E38EFB6A1625BE
+:1051B00016A31D3387C7A34222FA22C6B79580F8EB
+:1051C00073560E61FFAE494E704632F42D1B186DBA
+:1051D0005F1CCB222FA3F55205D64B1756AF3429AF
+:1051E00017566FA0C07AA902EBA5793D379C5F9C4A
+:1051F000ED9C7594EFE72B647F18F16D45CCF21FA1
+:10520000B54FC2DC6E37DB2B2E5032F60AF299F323
+:10521000F271E158B1AF2DB8DB64DF04954090F630
+:105220001BA7C2A9249779DA1F684D0477BBF2CF78
+:1052300017252C6DF293E7ABBFAA95FB697395FB1D
+:10524000665E1C227D36E332915ECED359EC7B2D17
+:10525000A62D227F99C85FDE12CD325E83C2F57023
+:105260000D348F4B078F80FF4D3CAB674D6A645602
+:105270003F4B9C8E91FA6B1D36BBD1AAEF5439D1AE
+:1052800048E71C353C2ED78DC288721301D22F2ED1
+:10529000486B55B8178568D1E28919F9718526924E
+:1052A000FCFC77B913A439449F08E2D1CE2776BE1F
+:1052B000F0DBF8E268F9E4D263C427BEA4B320F9B6
+:1052C000F10D14582F5560BD7461F5FC49A9B07AF1
+:1052D0000305D64B15582FCDEBAD3A4711FED60539
+:1052E0001DE887F19DAB5AF2ABCEF55ACBCFF35BFD
+:1052F000F2FD6759DBFBCFB6B6EF3FDBDADEBF80EE
+:10530000B77FB8FBA2D3D1CF53A89CFCEE63CA49A8
+:105310008D3A7EFDD28579E44A4DD07ED223EB9042
+:105320000EE2FAC5D62989D2682A8B7DF75321FF70
+:10533000CFB9B81F272927685FFBAF3ECFEF2ADC24
+:105340006F64CC371FBC86FEFDBD53D85B76FB6B0C
+:10535000D4AF73E8F0E153508F00064B83A6B3A996
+:10536000A11F17BC110C15F1540FD0F9B4BDFF5E8D
+:1053700023BE0612A14526389E7373BFCA4FC2DDF5
+:10538000213AAF3D616308F7E9BD93A5AC7E968FE6
+:10539000147E2E5815F3919DD1A3ABA40F7B27F358
+:1053A0007B4CBDAE01F21FF786ADED55613F7CA48D
+:1053B000F0F17A6F8903DAFF5D276C6CC171DDE96A
+:1053C000FF049DC1FD1F93E3A0E3F86EBE0F70477D
+:1053D0001380EB82AA27E8FCDD0E4FD2884B868132
+:1053E000D022D3BC2F32E6C5E653C8BC5E57141A90
+:1053F0004F8B72FCE5C257FA08F1B5D4ADF07B6271
+:10540000210FE16BFF3CBE7E20219D8C8EE452D4A7
+:10541000292F99F9CDBE1E037805BF1DA6BC2E5FAE
+:105420003A2E3FAD12E7A7BDE88761EBB47EE76592
+:10543000E3F2738F58CFDDF045EAD7ADC7A3A8EFED
+:105440007CB569403BDE53ADCD767270A23051F031
+:105450001FC1DD197504291E25B299B1BC6F426FB9
+:10546000242DE51E47AD55AC727384EB5A9DDBBA13
+:10547000AEED877E72C6AE76C0D26CF7018C754DEC
+:105480000F5E3AEEFC57D9E6EFA88D0B3FE54A1EBA
+:1054900057C5742BDECB84502FD9EB3E89CD3752C4
+:1054A000F83C5F75733DA687C687636D2BF7A3AD88
+:1054B00016F4CB556F353AA031BED7BDAD03F76BAF
+:1054C00025F3B97C8CCA833C60E1DB830AF777F46F
+:1054D0007AF4368A730973BFC9987E057FDBE52DA0
+:1054E00099E39E8D21CF7F5374AE9FD401F247186C
+:1054F00072A7EBFF49FAAF7772BB8AFA21A9AF27EF
+:10550000FFF1FE6A05303ECBAE278CB44FE0E134AC
+:10551000E857F11E53DF4B4EBA176BAFE7C1CD9A78
+:10552000C9DFE7ABB1EAE57C7A66B39BE3E5E3EA82
+:10553000991F0ABA66D133B42E2FEDE97C0AE9D35C
+:105540002BE20C4B9B12B0D834DFB542CFFDBB5BD6
+:10555000AC17951C8E5E97D660A65309FBDE60D60D
+:10556000A739E8938BEE976190E0840C1CF6F9ED77
+:10557000107828C5F16BF3E3612C1D381F74BBB3A1
+:10558000F3C127359F2E81AF7C7CBC55CC67ABC067
+:10559000AB31AF7C7262F4FF30E2AB1EEBDBD603C3
+:1055A0003961A1BFD3C05B93AD9E6AAD67E047761A
+:1055B000733BC6583FF2F5FF6B85C363EF3F971C03
+:1055C000FE66540E13E4AF35C671C3E3E457D8CF7B
+:1055D000F474DF2C80623F48E837706A3CEE291093
+:1055E0006C06F3798F5D7F197A31973EB2EF67F2DF
+:1055F000D55782CAB8F69361EF948A7B5FAA881365
+:105600005E2F653FFFF9BBA01B53F405C5FB61F896
+:1056100008E2039A21B58DE244A3436D2C3F31A2E9
+:10562000E87DE81791CF18BA8BE527FCC80D7D11EE
+:1056300074C5CC1F1A62FCB62AAA366379851A1E75
+:10564000BD1F39700AFABBB83D06CE95AFE0FDE04C
+:105650008997C8807875C35C8ADFDEBF02EF8E8DC4
+:105660008567A20C30A994A5C26F40E78AB8D5BC63
+:10567000D08A4F5868CAB3FDE304D5B6BF2B70DE9D
+:10568000767872B5CB0B4F667FFA068EEF86F1D730
+:10569000B5239DDFA8BD5BE0BC686D36D50B1F74DC
+:1056A000828EF7DE0F4A941E7FD047E994831E4A0C
+:1056B000271F2C039D11ADF26009A5930E4EA2EF9A
+:1056C0001507CB292D3F3895D2D0C130A525073FEE
+:1056D00045A976703AA5EB841C161F3C99F250330D
+:1056E0009BC62F3A388BF281839FA5D47F702E2FD3
+:1056F00017E7ACEB6E8901FAB1155C87987C749D55
+:10570000B184D625FBBC6E55F9BAD22DE2D6BB6D5D
+:105710007AFB6151FEA048D709B900390E667F7A3D
+:105720004AE57A615D558CECF26E633D2C5F6259FF
+:105730000FEDF5BB73DCAF7CCC804BC003358BF237
+:10574000D0879FCBBA8331BA4F001023BD0472CCEF
+:10575000A277BB0DF8051E73F727F078C6A3C4C760
+:105760001E85C72D7BBE7067CBBDA877CEBC71E907
+:105770006E267723EED8CD2AF2FB17AE26A6BBE322
+:10578000BA9B43741FF18C8D74EF09CD72BC4FD15D
+:1057900073E6CAF8BDC4758C2E33A85D9B6A3A1FA8
+:1057A000ED5D7273CB77587F7AA7037413BF4E59A0
+:1057B000E905DDACBF0E959563FBCA1B4A2DDF2BB7
+:1057C000AEA9B0B4831AEE470F7DA5CA524F9B7F96
+:1057D00092A55ED1BCD9D676E2FCDC5FF7194B3BD3
+:1057E000B7DFC02B3F5F64F4B7AC1F3D52763A7E03
+:1057F0005D758CCB3797AAC22EF21746B75CFD1B9E
+:10580000F3CDAB978279E741F6EED7D573E7E3396D
+:10581000865B8BD1FD9523AF7F6CE751683DBBBEA6
+:105820002A427D5586FA44A2D48FFAAA0CF58887BD
+:1058300052A3DE6AC36E29504E56A3BEF19BF44DAF
+:105840003D93FB2CFC50EC195FDFCC14E535225D59
+:105850002DF8CACE37938C72D437B5F9F5CD24DB49
+:10586000B876B8EA3C421FFD93F54DEFEC8DB12FB1
+:10587000B39CE7D43B5BEE6169CFAC1B29CFF485C9
+:10588000DBC3CA7B4E5919BFC7A447E0D0CF395FED
+:105890000A7E289E63D51F46FF81884D8F18F2F03F
+:1058A00031E55AF270B9CD459FDF1FA55C1BFD7F26
+:1058B000D2722DF5AE3A22B91E5BFFD8CEA3D07AB4
+:1058C0008946489F86FB9269DE5407FAE31C031160
+:1058D0007EDF3346F13CBD3F75D17902AB41FBE23F
+:1058E0007A357A0EF24FBDDA7C1EA6D787F5E370C3
+:1058F0009D66F9F36DF90B3C132CF98B6CF94B6C2D
+:10590000F52FB5957FD15C9ED4F5E3D08F917CC601
+:1059100045E78649DDD194F53D0581A767D5E62F9A
+:1059200063FB1353271D877461F9AF527F1EDE1F7F
+:10593000CB5F49E365F257D9CA97D9CAAFB5E597A6
+:10594000DBEA7FCD9CEFFD68EAEDB8DE277EE682DC
+:105950006D59FC4BAF083DD273C2CDB1762E97374F
+:10596000935C4E5B19BF02882F00E176FA6DFB3F16
+:10597000C667667E7956E89B9F4CBE91F64D3D6C9E
+:10598000FF44F18DE8DFCB829FDF78C4FB5CFA55E2
+:10599000742F22597E3DF9397A2ADB297E61BFAE08
+:1059A000D0B96D329CBD7D6F2BF773F454663F5FA9
+:1059B000F88D276C89D7826AEE17443138ECC077AE
+:1059C00086B87EEF0A77937E55D25771FF46798C61
+:1059D000FC1BDB3C7CFD52FC71F22BB82BE359F72E
+:1059E000F53DA3F8B0FA3B7F22F06AEC234DF82096
+:1059F00039ECF2FC6937FA37929EEC72B6538CEFB1
+:105A00000A1536FED8F9F3F1EFC6CB2E28AFB67DD6
+:105A10006DD2C5E3E71393B91F4066E398FD0AF61C
+:105A2000F146E769DB67DF25F83CE9E1F1F7467FFE
+:105A30007678EE17F3B9DFA359E6256B7C9C7CFDE5
+:105A4000FF182F71A11F40B3FB21AC7AAE55D4775C
+:105A500005ADF572E127318A1F1EA765F06F3E7E06
+:105A600037C67916E1A2F385ECFB70FDD01C8AEBFA
+:105A7000D80F81813EDC37CBDA2BE817BE896D93D6
+:105A8000D09FDD2127C8BF90D041E3EFECF07389B0
+:105A90009B9C274550DFA922DE0230DE22688A5710
+:105AA000147ECEDB7DDFBC0FCB5724DC1ABE7BF22D
+:105AB00077CF543E9F432B28CEA297EDD471DC03C1
+:105AC0009E29297C4FC759DC4FF6BCD3392B9E2D1C
+:105AD000FED4EDE5727CDAA1B5A467BB997EC3F371
+:105AE000A56E39A696D6A2EB3A41F2DAAB8F1FD754
+:105AF000688F8F7469F6B8442BBE225E4EDFA458BF
+:105B00007F939E488B252ED0EBA1F2BF7BACF0F5A6
+:105B1000E8FCBE900E718A334D563A1C88B7630577
+:105B20009F31AE12E6F78F8210A338163524D3B812
+:105B30000E1FC76FAE714197DF31BF2B73ACF039C9
+:105B4000BAFEC6383FC9E0257ED2E7AB8DDB31FF18
+:105B50005327ADA7F6717EEF8D7DC66BD29BB21633
+:105B6000033A8717FD9D3581C77FCB95FC7EBA022E
+:105B7000CD4D6136FF8E4AFEFEA2ECCF132F516948
+:105B8000F757E43AAFE3E72554C444B4E10F7C5C33
+:105B9000AF882308C030059116A34A9F8A7104BAC2
+:105BA000C4EFF747241E6F3E8FE2CB839E4FBADFD0
+:105BB000CBA95F29BA0E0EFB8EA05F7998FC5C9F83
+:105BC00078BF79E0F5C09DD42F86AC1E2ECBF48B28
+:105BD000FA979C4A870E1FC6F334714605861D2E20
+:105BE0003BF87D2BA828A278C4AEE0F5AA99AE9D1B
+:105BF000DE2ACBFAAA68DD5FC3779494CA6BA2C38E
+:105C0000E3F06552C89152F995E870017E4C994DC8
+:105C10003F9B3FB45B89A5DAD05E9CE2E771AC7232
+:105C20009CCE477AA4D2D97D7526FEAD54D2089772
+:105C30003F124D609C634F992382F15932F4EFA5D6
+:105C400077D39C0B23E3C9AB5C29BF6D9ECFB7BD57
+:105C50008120C129FC871D79F8BD4BE8EB5CE52E5E
+:105C60002512CBA68707BD621DF3662F3FE06B7C34
+:105C7000D09B65DD490BFCF6943055FA69CE3EC8E1
+:105C80000772E59E57100F5D13CE1C5F3F6956FDEE
+:105C9000F4BA2FFA43EFF870FCD85B9F857EFE6064
+:105CA00061FB038803DEA775BEE414E7BBD122695C
+:105CB000229EDA1A7F11E864E5AE396E0DFDC9DE69
+:105CC000DA08DCCBF2A1D3D566790EBD1B47E7AC71
+:105CD000AE7227505C9E731E8F1BAAE17ED628FBF6
+:105CE0008FE2CBE68D1F4FE6B4E57F65A773EB2E01
+:105CF0007A3FC280DF885FB7CFEB07BEC6E1ECF822
+:105D0000286C1FB481F10BB8F15D3195D2B5AD1A95
+:105D1000A5AB5B4394AE6A65CC4EEB7F0DE56FC3DC
+:105D2000A673312E249E0CE37E2474EF2B78257409
+:105D300003E296EE19DD7306DA597D98E7F7421310
+:105D400012E627F3F2437D1BCEC0FD609FC7A89FDC
+:105D5000E4F547F37774A15DD827E26BCB56DD7B82
+:105D600006DAAD1B261BFEAFA87A91C9FEAAF1B9CF
+:105D7000B89F266CB4EFEAC27DAC4736F28F9E61C5
+:105D8000CD4314E1F1A83C7F8EEF07040FA9003644
+:105D9000DE45BE5D94DF7082D8975FB8280F1EB9CC
+:105DA0001FA3D7AB733BE842FEEE8AC2F8A68A7DFA
+:105DB000DA20DECD2DB41FDCFFD07AF752F6F532B3
+:105DC000233779D6B50B0B7BFF85A183EC0BD4C3AE
+:105DD000F8FEA2FC0B2E17C77ADC0DAE23C38B3A5C
+:105DE0002F16C5EE8B9A06D348EA9F78630D3ED6F0
+:105DF0004FF1FCBDB4AC28A134B71B0A1CBFD2279D
+:105E0000EE9BB179E3BA63E0DBB03F6E407A4EC8F7
+:105E1000F4E70A46E9DCCD23DE1B2E14EEABBC9A78
+:105E2000A51F786076F978E76DC1850E0C421AD50A
+:105E30001BA5F3BD96BC36AF540475F07C515D854F
+:105E400025EFAFADB2E45DDA4996F61F975E5FF2DB
+:105E50006A16FEBEC036AF26FB3C0BECD7B3C2A918
+:105E6000BFC1EC84B06CD8A5EBE9DEF27EC431EAA8
+:105E7000C98159748F17AA8D7B0A40712C1E3D4A27
+:105E80007CEA65FA9AECE34AABBD2A07ADF66AA84C
+:105E9000259136FAC5F86DCF0A85C61D5DAFFC9019
+:105EA000F6E0DD73A19769DF3E1555DE379E09F3F5
+:105EB0007611F3FD7C7B2A8B7333BA9B1FCE7FAEAA
+:105EC0006A1F2774E1F8716CF6FAE097F5374D72A6
+:105ED00098BB9D0C6F9ADEDDD886B49F90C17F740D
+:105EE000FB62F27FB881D9D30CCF1DA18B21C6E60E
+:105EF000D98D5518FD9298323EEF0ECDD6284E5FC3
+:105F0000E77475A85C4E6EF2E916BBCCE9E77262E5
+:105F1000D4CB47FF9B9C10CFB6AEBDEAE3FBE503B5
+:105F2000DF8CFF09F799891741C7F3DFC1D683F4E6
+:105F30000E665DFA2C27FA4FF6F92652BDBADD51EE
+:105F4000E7E9A67EEA80BF07CEFE9C66BFAAE127EE
+:105F500086432AC50DEF4CF3B8E19DE93F3F751824
+:105F6000F3CF38E8DDD19D7BC7B7B306859D65D4F7
+:105F70001B7C86EF5B0765F0958E67EF88FB71B33E
+:105F8000D2B6B844199C48FF03B7E84EB47B065B11
+:105F90005509D7FFD9629E75E9A813D7B17CF3DA0A
+:105FA00063A3AF314FBC9F88F3ECF4F3FB829D1ADF
+:105FB0009B2FF1357F4F3B17BCA3FB7F2D3B3E94BE
+:105FC000007FB74371C5B46CF3CE778FF168E1EB16
+:105FD000B2C1D7EDE7FB73C37F900F1E25E8B0E891
+:105FE000096F9D26E182128081A6696142E38BB828
+:105FF0001F2255C1583DB06FAEB404E3C617FBA3D2
+:106000005208F39F95A63038B50A27DBE3307BA909
+:10601000F6C5F4AF713E2D3EBA97D151FB01C517BD
+:10602000947C556EC375AA173B27BBA8BABB81C128
+:10603000D781FF642ABCBCBFFC4CB43B64E07A80CF
+:1060400049982E4F44BB11F031979CFA80FD498747
+:10605000DD9976B9F064B73FDDB0687CFD24CEF9F8
+:1060600013EC3FD42F25B6F6C551AB7D1BB0DDA791
+:10607000380DF5777D01F7328E721C0DD6AB187A8C
+:10608000E0AA766829AC0F5A09DE07F2CE9701E341
+:106090001BB5E048C2A1E7C77B275BC2B85CA52C53
+:1060A000E73017FAB9FF2774451DC5E1EC8F302E94
+:1060B0009885F957B2EEE3ECF72D56D5DE4D7AB25E
+:1060C00083F113C69B246A1DB47FECAD7E4833CBAD
+:1060D000D3D7C53819FA832E1BFB64BCBF5AED8891
+:1060E0007A667E7CFADBF71BF9E8EF5B688DFB399B
+:1060F00052BAB4FA41C4B18C4FFFA31DC7A0DB58FC
+:10610000F9681374FB0AE993EED091DD935955BBFE
+:106110009EE8E6ADCE1EEFDEE997AC7A56A42ADB08
+:106120005F464CFB4BE771A7B4DC05E3D0654C7CC4
+:1061300015EFC7E9E77EB4D592378243ADCEE1577C
+:106140009E1630E018E6717C73F784F0DCB8BFFE71
+:10615000CD109E6FACF930FBF9E382008F0FD7A30F
+:10616000AF92FDBFA69EFB03F10FF5CE4DFC9F50F5
+:1061700095786B13BE6BB67A9FCF62FF18EB42AE79
+:106180007929154BE9BDC403AF49F4BEBA54B1E255
+:1061900044846B68EE127A87A4BBEE493A7FE98F9C
+:1061A0008C4F1723BEB45BDC571F1D3FC779E1DF5F
+:1061B000045DAA12CBC89E5C53FE228DB3BA6EFC5E
+:1061C000719236FADB53D50131F213DBCE73F70946
+:1061D000B9DDE717E712AEE6F3A686318E2A4EFE4A
+:1061E000B10935D121D4FB170662AFF859F99AB934
+:1061F0004BCA691FA15BD7C15B73CC2714E0FD1AA2
+:1062000076D281AAF8FFB9A50E7FAF62DAAC848995
+:106210001EFD39E2DA6B03C6B99787F639DD780FD0
+:1062200080C1D75F5E18FE0D3A9F06CFA9F8CE7ADF
+:10623000778EF85E23B5AFEFF9F06EC7C31AD7308B
+:10624000C53FAD91B2CF674180E37BCD2D697E9E86
+:1062500036F74D3A4FF3A75FA5B889FFA8DF4BE7A4
+:10626000697A809FFF04FCC3144F5A3487BF0F988C
+:106270004B8E527E5E5FD6ACF5401EB69E0FF98DFA
+:10628000F39EF1FB33E00475989FF38C954B5A7F96
+:10629000EEEBDFB687DE5181349D2774FFC2496F74
+:1062A000C11A7818235749FE3B316B241EB7BC2016
+:1062B000D0DA8DFE9135C6F9DA2CBE4F92EBD2744E
+:1062C000BEE60DE8167BC71F31DE492C6C9E45B833
+:1062D00016D573B580EB2AFAE111BECE5917933F5C
+:1062E00037175D6FF2C5EA03F5667F3EDF67FDABEA
+:1062F000F1E1DFFCBA252EDDCE8F6EF8B723DAC7C9
+:10630000E5F22B1F10F269BCA36BB45F1C50B2E323
+:10631000F7D797E4C3EFE2C0846CF83DCB4BFB8822
+:1063200075E39FEF6CB2E9EF4D469C8D78D797F5FA
+:10633000577E7E167BC258570F048CF77C9ABD3867
+:106340004E55A2D68B78DA965C44F96DB78E4F4FD6
+:1063500063FC2D42AF6F15EF9018E55B055FA66CEF
+:10636000FAF66521D75B857C6D53A35E8C5F82A7AF
+:10637000CEF24E67F80B33BE4057E2F15D2325E3C2
+:106380008DAFAFB4DAFD477ABF652060F5D7167AD6
+:106390006FF368F1921271352F07D224F7CE743162
+:1063A000C9537829903C85632369DC37550D3852F1
+:1063B0003AC5AF347BA733928696CA3AC5B2897B79
+:1063C000B0278AF51D9C2B1DB87F09897BE48C853D
+:1063D0002FA338983BADBF07B24D8D342A78AEDC81
+:1063E00049118E104E9A7EAF8240B2FE1E4868DF81
+:1063F0005BF47B2A2130D50B1F3DDEFF2BF0F1EE45
+:10640000CB1E353FCA231EB33E3E5E82E66C7AFF4A
+:1064100017C21E3BFE969D12C9E5357E78DDE4A7C6
+:106420004949232588DF2D2BDB25C467A2132227AA
+:1064300064D1636F047C865ED88DEF2EB82A397DD7
+:10644000BBFEEDE2E12798CADAB2A211B2ED3F98A5
+:106450005E782340EB13D70B5B572EE2E92127F13F
+:1064600049751252F83B2AF307626D2EA4FB52FEC7
+:106470002E75A8333E84F9F03510D159FF55E8D474
+:1064800067E356B7402A4A7C042F8726E2EFDDF007
+:10649000BFC9C38B87BECDEAEF99E3D6F07755E04D
+:1064A000062BBF545C63FD7D95EA4E2BBF4CB4F1C7
+:1064B0008BBD7D581F390BE19D9A7400EEEB82175E
+:1064C000DAFA83E11DF7E17C76FB2369066F75BF7D
+:1064D000B5DCDEBF0C317711A3CB23371FEAAD61EA
+:1064E000F5EF4E3696215EB6A9C0EF5B342B74BF34
+:1064F00035D73BC463F8D6B0FB0B7CB7D858F77AD6
+:10650000F649FCDD8B29DA6B61F46BBECC7FC72EBC
+:10651000F38EC567E81D8BE320C6ED478852DA2964
+:10652000EC53EDF4CA30FA3F93BFF669782F4B2B4A
+:10653000B3FACFE4D2267A1F6CD4EE2E6576372BD1
+:106540004F9658EDCBD38B389FCE2EE2F6A1E6E3E3
+:10655000FD801A2F37BFABB4B148B296FBE3E51705
+:1065600098CAE71789F767C5BBE30D450B7A502F2B
+:10657000699358FD2CFC79A618D7288760642FBE34
+:106580000772FBA58BEACDFB8B8D45FC5C473B5E20
+:106590008C5B991DAE64988F7B9B18776391F10E8D
+:1065A0005C9CBF03A7F1D4F87E5B6089F406FB7C9A
+:1065B000C0058D18A7D231C141EF43DE34D1880721
+:1065C0001B5F4F187418C5B7C6E3902A96F27B97E5
+:1065D000B9DA6D6EE2FE41FBF7989847E7D2C681C3
+:1065E0006A36FFE86E203E710721EBF90F93EF58F2
+:1065F0005136BBAAB389F671074AB2FF4EA1917614
+:10660000D8D67D59F813C7D41374D25F0A118B778B
+:1066100086B87FEE4089234AF7026B81DE3B3B5010
+:10662000CEFD75F6F6BDB6713CB0288AEB349EB34C
+:10663000623CA3520D293CC8F10607B4B08EF101AB
+:106640007BC94FA303C3272BEF8E00D9779D216E03
+:10665000C7C8A1810607AE1FD0A499EDB10AF17B8E
+:106660008B1E7FACA3C812479220FD7BC095223DB4
+:10667000D21176C0DD59FC886B8AB89DBB595FF496
+:106680007C380BFD3614E916FBB9E220B7BF73D591
+:10669000CFD4E3708DF263284EE73EA0737EBC300A
+:1066A00010BDBD689C382EC3EF78C51CA17041BFDA
+:1066B000E47FD83CAE7AC64531E9A71DDABAE7DBFC
+:1066C0000C4F4E714ECD56E53D4FB0F2AFE0BD27B9
+:1066D00096BF6ADF0C650A2B7FB9C2898B30FB6BD2
+:1066E0002EC271DF054713CAD3BBF062D1C926BAE7
+:1066F0003D5224ECD0A48BF4A6E18FFBEA80CBA220
+:1067000057AFDC64CD2F814513D14FB1E45617D973
+:106710002657D9D6FB6D62FE5742BC1BD7CF2E1130
+:106720003F7EED0F66282837579DAC859DA6FB560A
+:106730004F087ABCCDF84737C9D9D5FE9482FBB84B
+:10674000D7779E7CF16701FB497557E0FA59923D76
+:10675000FEEFCB492B9CF9E66187DB38BFCB058781
+:10676000BC5D8AA6B2C8D9B34556BF5087CADF47B9
+:106770008A76C8E0F93CC6DF01C94F625F80DEF36C
+:106780004E34C6299E2ED1EED63A82145F477174DC
+:106790002B18C1F03DA23F08FE33E2E900E2A7E278
+:1067A0003EED5A7558417FF47239DE843FA5669CF0
+:1067B000C3B85DB1E82406BF6B57437A1258EA2587
+:1067C0000BACF78C545550BD26C738FDBD27F4E4FB
+:1067D000D30FDCA3E0FAF3EEFDAF9D8B72B8EC7142
+:1067E00027E095BCF71E08409AF60F2905E5FBEA5D
+:1067F0009DCEAC7E36F2D4323C2EFB5E80F4E2D5E8
+:106800000FB9530B59FBAB1F7D7D2630797AAF7DD5
+:1068100064CF24C4DFFD123F1F4C0CCFC4F5E96ADE
+:1068200019FE3DDB3B64BE62CE5FEF3CE66B41FA96
+:1068300049DB87BE44FD0E5EE232BFC7EE28E6EBC1
+:106840000FABC7E3257748A913B2E80F633FF4CE37
+:106850000E89C3B7CB95C250E0ABB7DFA5C4181CF7
+:10686000CBB7BF4FFC72FAF71E2C423C2CDFE5B4CD
+:10687000EC2F977DEFC3EECF303A2F73C2C842940E
+:1068800063E721CAEF8FAA234E926B1E9F721DA948
+:106890000056EFE1DF9FF93FACFCED901330B4F50B
+:1068A000EDBDBF531EC77CCC1FC75F1459BECBCAFA
+:1068B000D7CBB7BFAE205C9A03462A3F8BE79C56E6
+:1068C0003BC95E1F6044413DB57CB0F77D27E3B70F
+:1068D000E53BDFFD15F2DD729B7CBC8DFF281F6B55
+:1068E0009F9F5C6CB3CFB797151487B2ECC1FD5B6B
+:1068F000D01FF1CE437FDC82F767AFF9E82F5BBE94
+:1069000081F1603FF66828DFCBEFFF451198F4FE78
+:1069100039C55CCEDEDB71DF7736B3F9BFF7AA9BF2
+:10692000B0F5DE13BF9F82FE9FF7BEFFB789E80F69
+:10693000BAE189338E43FEBAE111FE7B36B9E040FD
+:106940007E4D997F6F519C13E9BBC81803F891489D
+:106950006DF480811105D7B3BF4A30D257C2BE0F44
+:106960007EA8A07DB6270A23889FA776BEBEE766CD
+:10697000967F97D1C79D853E6CFE931CA49F99D8A6
+:10698000B0F4BA9D179CF7B93A4C5D11EC7E398C86
+:1069900090DE1C43D797185DEB3274B597EF8743B1
+:1069A0000A9E1B2C7F80D17126D293D171E6583A72
+:1069B000BE8BFF983B968ED714DBDF6FB866EB6615
+:1069C0002CDC5996D5DE35F659D73E72D1B8F69300
+:1069D000A117F2E179A9F093CC298EAE2C46397C2F
+:1069E000E8BBDFD91CE4745EC810F3DE83FBA7E0CC
+:1069F000A31C7F708D7C09F130F2845BC3F5FDEA46
+:106A0000277E49F2F6DE232F283AC5B54091740A55
+:106A1000CBC3E8DF8BC0F2D7493C73EDBD7F3FF3BA
+:106A200057ACFDB5F853AA1AD18FF27B98FC113DF3
+:106A300052E737E9A877531368DED7A5B85C5C97AF
+:106A40001ABA10E3F9EC787F44E817335DF17DA9B9
+:106A5000EB76BE7626F25F2E7A1AF3D770FEA7B2D7
+:106A6000F27BAD729B534E057DDFBBEB8082F6411E
+:106A7000FA714573307BF83DD78842EBE3F79DDA36
+:106A8000B6C858BA67F02FE28E8E701F3E586CF36E
+:106A90007F08FCE493F3FCF33A32BC6D29D62DFC5D
+:106AA00063E0EF9D43D9F5FFB3C5DCDEBE0EE24DDA
+:106AB0001553C7AE5F323427268533F0BE8371632A
+:106AC0000CDE77EE77D23B7DDD834F911EB7EB8BEB
+:106AD000EB72D8D1FB8CF1760DCD44BDF6CE938F01
+:106AE000115F5EF7C06B0AEE57F66C7F5819AECD9A
+:106AF000C801AE0FE6DF297BE77F0DCD44FDB53C35
+:106B000047FCDF5BA2FFE53FB2F6BFFC81F72DFD3E
+:106B10002F4B0C2AF43BAF79C6795B8E5E82F37DF6
+:106B20007BAF0B703FFCF6A0B3299B9DF3DF627D2A
+:106B300034F0D41D38E595623CF72AE5EF3276B69D
+:106B4000457F89BF379C78C125F6B7D157D09EE9DC
+:106B50002851E81E4267E062F2D71BFD0DD8F0A96C
+:106B600005B506DC0768F39BEBCCFB2A03FE92A875
+:106B7000C302FFFF03C228CF4D00800000000000C9
+:106B80001F8B080000000000000BD57C0B7C54D547
+:106B9000B5F73A73CE3C42269393D7E4693C4978E3
+:106BA0004AC02109101ED58120A6986A50AA5CEB24
+:106BB000D50121444832292A5AEB779990885EF012
+:106BC000B3B1D28296B60317AA95C40E1034B6811B
+:106BD0000E606950B4019F7851A3D68A15C8180574
+:106BE0006DAFD6BBD6DAE730332783D0EFFEBEEFEA
+:106BF000F7FBC2CFDF769FB3CF3E7BAFF55FCFBD54
+:106C0000CEDC91529DAD3901DA560268A30040F105
+:106C1000E4D4A600C8AED9D59089AD6A519324803A
+:106C2000AFE9EFF2680B100498086075D6820F9FE9
+:106C3000B7AA16D01CC07F5F03CFD3DE8FCFDF256E
+:106C4000A7B4AFA179ACCDBFA43EB428B0B58287BC
+:106C50008D562AE8FE259E354500EB93FFED71BA6F
+:106C60007F77C0AEDAB16D4D59F11BEAFF4A825A07
+:106C700019C7B5D2F3D806AC0E75AB8AD7D3607EF0
+:106C8000C8195D4FBE2AF17AC6E33AA8C53F1F4C2A
+:106C9000C2F78A25412B34008E80A4CC60805AE351
+:106CA000B97F577D25EAC4685F76F681AF14E00AA4
+:106CB000D969A1FDDF9F6309DA8BA8BD36154A8724
+:106CC000D2C168EF5B590BE151E7BEDF9EE558B0DA
+:106CD0000978DD010BCE1B901CC1ADB4102F68AA42
+:106CE0001B786DA0E17F484347CCBA718097F6A12D
+:106CF000E8F7ADB82DBA698700B749C4076C93218E
+:106D00000C500270A55A0C90059002FDFA2411A8AF
+:106D10001D07302FC5E7A57D660FF749342E0BBC44
+:106D2000DC5640AD44F72DC937E5FABE617F304FE0
+:106D300039D13F5AE72FBEE25756417F450165588A
+:106D400019AD63A3FA97B1380FDDCFA051015EC72B
+:106D500084AAEBC7B6111C68F131747E78D6CC0CCE
+:106D6000C28D31AED551785442BA78E52435A91098
+:106D7000FB0A5286F87D2C85E9F4A3E93833DEFF5F
+:106D8000F1B194CD32F2E36149E0294078225C41CF
+:106D9000F3E3840F17E2670D3D37B3F9378C170B18
+:106DA000D4B656E8947413FDC41FE28DF174B7E2B3
+:106DB00050ED1EA2AD5753681E1B04D748B45E1F8A
+:106DC000D3D301EDDC0E8310B74EE8E37605D1791D
+:106DD00022F1C1C3FD54E86F1F8ECFD5A8B50D2A8F
+:106DE000EEE7C7D5E912EDCF09AA4EDF825C9FF32B
+:106DF0001BE83B0BE9EB88D2D74EF44C1E4A4F07F9
+:106E0000A84C87340F78D64CE079218CFB78780633
+:106E1000046506910A2AE2255BDF6786CE67C20F0A
+:106E2000ED2F6BBED89FF97D39D0CEE3F220C46D33
+:106E300001F4719BEE502585D7734CE7EF7BF0751D
+:106E400072743D466B2704E3FCA70B70FE22A6B6C6
+:106E50004B72D3FE8DBF5AC6E11F2AF679AB709CE8
+:106E6000E2737AEDB895FF5D31934008D68B15201B
+:106E7000BE3AFB17D4800B877B6C101E4DB307788E
+:106E80007D49A345DFD02F766454D8583F3E673DF7
+:106E9000F6D1317ACE0A31E3681DF24DA944F78765
+:106EA000E8C294A174BFFB584BE67331F36E5153A3
+:106EB00032699F3019267F2D479F87CA7480DCA1D5
+:106EC000CF7FBE3290F99C354A8736C7BF312EBD81
+:106ED00008E0A4CBB04F38CE8CE21871C97A2EB03E
+:106EE000CAAEB666320E19A7772381ECD87E9E54BF
+:106EF00018E4FD43F3E46B510F5B1C5E49C2EB0DDC
+:106F0000AA2B48F469748666B39E30E98D19F3D4D0
+:106F1000701E8E1B68060FD175FDCE6B8E135D073C
+:106F2000DCA0D9D3042EBC93484F187A043419F945
+:106F3000BB5A9AE090B06DECFAE4A5DFE1F8A41E2C
+:106F40001964BC3F807BEEA37D2BDE346262323C51
+:106F50001827DFAD0E213FC63ECDF2FACFEE133932
+:106F6000CFF3331F64D2BF0FFE3B3D3F0829ED3402
+:106F70007E8382AFA6F97BADC1AD4887E50765C6C4
+:106F8000DBF24E2908C467454BA5FE5D2FC820F0F3
+:106F9000077CFFAE5F96301E6518FBA3E9F8BC7F47
+:106FA000A3D5831A13D2BCF1F62AA37A1868313814
+:106FB0008080F7480ED26B914EAFF5C90F6DA2F5E8
+:106FC0006C6811F629AB363D6EFCE74957DBEA7079
+:106FD0007E2D17D7359570D3337235F697E5CBAA4A
+:106FE0008C2A227B7E5EBC7D6CB7BE47F2A7E13F58
+:106FF000C2B7A1BFEA487F911E92EF65FB771AE9FD
+:107000002593BC80B07F4DA8AFC238DF920DE279E6
+:1070100063BEFA9E8757E7637B5B30FEFA3250A26D
+:107020007DB6B3AED1A407EE86611EBB3414FF4A11
+:107030001AE29F40E204A7E083D343FA65F015D932
+:107040006317A4607925BA931E91FB47AD9F8EF319
+:10705000F97BAD10D4885FE2FEE0463918288ACA71
+:10706000C760EF4EA6C7925CA407E2D39E134FFF02
+:10707000242D9EFEC9A3D3BF911F291E133DE51ADF
+:10708000A63FD21B68FED4CAE2F8E7757A8FC67FA6
+:1070900082DE5E5E675DB7048F4944E7070FE46BED
+:1070A00043E9DAD4FDB08DE4FF7C7435D3715C9A8A
+:1070B000AE47743A9E869EBD3A2A6B1D6E5625BC1D
+:1070C0000F456D9F41382D40B9259C98E5DAA09F6A
+:1070D0003553F5DA70DC45340EF797E7080961F4AB
+:1070E00080F232E165A1D0BBADAA97ED91A16F937B
+:1070F000CFEAEDF7E16B6C33E7563C4038BA5D4AB6
+:107100006967BFCA24B76BC7AD60FD55B00AF531DA
+:10711000DBD5783F2DB4D2E15984EB796A25781616
+:107120008D00D8B152E5D6ECBF19F2BE11FD37BBC8
+:10713000B0CF3CAF82F85DA392FEF1A8B4CE876CCD
+:10714000C0723A500AC1CDF8FE50F83337F9A30F98
+:107150009545AEAE457FC4BF186A43D86E4DB7B0F3
+:107160007E7D365DF877D5E9366ED7D45AC08BEF81
+:1071700039D52307255CDF29D57BF072D23B3D56FC
+:107180008DFD2B35F2D2F7F87EB9BA06E9996B6915
+:107190009F40EFC5F1D5419C77A0E77DD7AD317613
+:1071A000F954F72363C80F7AD402F5A104FE5063A3
+:1071B0009A78FFA9D1EFB971DBD0E888D800F174D3
+:1071C0007F7F732DF95B77256B7CDFD635239CCFD2
+:1071D000F899CBFEF17375C3186FBB4E4090E46E07
+:1071E000B67CD355E3B03FE555C56367A1F25EBDFC
+:1071F00060120F61BEAFFBB27C03D1CF8FF45CC5D0
+:1072000017DB5F267E3DFB670548EE2A9A9F7EDFEF
+:1072100087FB3C908368A80498E40D958771D4ACF3
+:107220009EB41924DFFE63C0F23AB14F89C32DC862
+:107230000DFBF349AFBC21DCC3C96F98EE43402678
+:10724000FF7F4A7FFCF569E7C1FB5A03EF2E7013FD
+:10725000DE1F5BD90DEF935DD4ED671E6E30113DDF
+:107260000D7C3F933CF39134F6274026DC7A94C49E
+:10727000E3FF9C2E310ED67D294B84CB81087856B6
+:1072800021BD0616E5F1BE073E23870CDB2FE5EA9C
+:1072900050027FEB89341B3FFFA84DE0FED13A67D7
+:1072A000B005F7B3AF6EE9C5FDF8BE333FF05DAC96
+:1072B0007E931F8CAAC552C9FC4A25BADF3EB74D42
+:1072C000623984F65CA29B79BC212786DC18F29295
+:1072D0005B37CC174CF09ED1FAFE66D68D966C8447
+:1072E000DB3D12101F4FADC2757D83FF188055F92D
+:1072F000B41E7FF7A736B2D78E1EC91B4C30BE37DF
+:10730000CD25F0BB2AD0320DE9B562213E4B72612A
+:107310006B2F4A347F00D6E5A37308BF49D3785D4D
+:10732000A71C700BC92528EDB964B74F75577D9B15
+:10733000F4FA632887E4373C6AF5F0BA038D28B382
+:107340004416723CB15F70356C5A1313471E499B4B
+:10735000F1761AAEE3ED3495E7CDF079245AB7E72C
+:10736000ABCF5D34FFC01776E65F1EC9708CDF7649
+:10737000264DD0E78174EF1B8C97FA4C56A61E9FC2
+:10738000CBB3A81CE0D26EA4770C2EA37C0BF073B9
+:10739000E9BE00AF27BD0F03278EBFBC1AF9CB7E15
+:1073A0005D394358026552543F57380AC2F9227E6C
+:1073B0000865237DD3EB7FCCFA3A09F530B9E2D0EA
+:1073C000171F17B146C6E749F6492FB4AAC2CF6ABC
+:1073D0004B137AAEED6125D88AEFDDA8F4278DC076
+:1073E000B6C8ABCD5434D2F7A53C6FCE1DC0F26DFC
+:1073F000710425D243C9253F4F3BEB774D03D8FE9F
+:1074000095CCF437F3695CBA4117DF574497F1BD67
+:10741000917DE4BE79922083F83A5B76F2BEA79C18
+:1074200014FAC7AC6FE4F02F1F257D33A0C74F09B6
+:10743000F4CDAD645F0D7D0372E97EC2CFB417F465
+:107440003053D733187D301D261FF2B53A13E89715
+:107450004AA84D45129F57BF98F988CEFED97E01A4
+:1074600012A3BC17E528E679B33EBA283D5E1F9DFE
+:1074700086E9D9576851BC94DDEDD96F8FC187A1DA
+:1074800087A27809B29C98DF2381E36C5F2D21FDF0
+:1074900071484E25BD3303F98EF33FAFCB49DA6710
+:1074A000C16F13FFD7F55C9944B8DED15BE520B11D
+:1074B000599E236B7F46FF59D93B2F003A5C48DF2A
+:1074C00019EFB58243738E267A58980EB28AFD98CA
+:1074D000F70FB64BD5A4179169A9F3C69D5B1F2C76
+:1074E000CFB1F17B76F416A7128E9C80F12DF2AF0E
+:1074F000A247623FC18C6B338E5BF105168E1B6B0E
+:10750000D99F90A5909E77888F4B8B0253D84EDDE4
+:10751000817138F9AD83BD68B7B0DD81769EFC948A
+:1075200056E76CDEB7B15F637D77A4CCCC86D2A181
+:10753000FB375AFF1732043362FA4AC44638F67FE3
+:10754000618BBB6ED0F35C7430E83995E829FD9F00
+:10755000D3F35BE91AE3C14CD7FFE9FE0B96574220
+:10756000A2BCC0FF2FFB9F06BEDFF58B78EBB51CDE
+:1075700077549F142CAF9697201D26913FEE89EAF1
+:107580000707FE237C8DEF6E677D5389FA86FCCC5E
+:10759000FC8610EB97C939225E32EB8D4B7BE03ACB
+:1075A000D28F53C2E8975E80FEF88CFE2797F3389F
+:1075B000C174CA43FD71FEB20EBC345E838C1A7C6A
+:1075C000CFF83EC543760FFA3212E605CC76C3F00B
+:1075D0004B0D7FD43CCEF0470D7BD2A4D3E170BAE3
+:1075E0002F44EF07550D90BCA15C851EF330EC35A0
+:1075F000F2178EA4D5EEE4FBA343018E038A41A5C6
+:10760000BC0ECA2BFB61150E67581E3F543E934DAE
+:10761000721842BA509E20E0B404474843D781EE26
+:107620007680FC3E7C80DF5F9F2EF2A50538869930
+:10763000D604ECFF178C071FD9DD82326C719F7F57
+:10764000D2ED4A9F3EDE6871DD07D329FFAB40C013
+:107650005EF6CFAF9796985F46F4F1FE91E67154CF
+:107660007B79FDF92A78C88FCF57429207DF9FDEDA
+:10767000A049679348869DC6F9F26B34B697F9C363
+:10768000B14FE3C9DF49C097F7D2ADBCDE4647FF33
+:10769000011BD2C15FD35CEDB244FD74BBD5E7CD15
+:1076A000A7FC51B7F0D781F27D9C3FF648B41F6527
+:1076B000A6A08F5F15F1951354D69B153A1F2B1C6E
+:1076C000359CDF219B689F3274DF92E6E5C179F338
+:1076D000400B4C89EA5523FEC16980DE63D6AB03BB
+:1076E000BB5FBF2880F2F8D6FFFA3405F0FE3B4AB4
+:1076F0002485E871FCDE9753BC488FB7EE15F1CBBB
+:10770000CD26FFC89621F8539751FB15D1F59695D4
+:107710005F4D8AD52F707716CBC56D419982E1B345
+:10772000F2B3EC8964CE3D1BFDC650465CDF90830E
+:10773000463B3427F2AB2FCB10F1D96D1D9B6C1457
+:1077400047D765F85233F0FDC775FFEF78570AE762
+:10775000038CF52CEC9860237ABFD36387302BC859
+:107760003EABE0B3F76A691225EFC59F799D07F636
+:10777000E4DB2C38DF62092222AF05077E86FD0F8D
+:10778000726458E319BA8FC56FA936CAB72F9E0124
+:107790009100CAD5C23BA4D577E1F8853E27797020
+:1077A00043F6B920101FE72FD1FD955B1FB09AE279
+:1077B000A4E603942F5B84F3503CBBB83DFEFE600F
+:1077C000EFED077E4676A0DBC67660C979E2A7F2C8
+:1077D0000C3DEF3209267F5D42FE4AE98F4AB573C0
+:1077E000EB25C35F39BE12083CF0D7950E6E4FAC47
+:1077F00054B9FD4AD7D7CBBAF71E605C2B7D93C82E
+:10780000CEEEE87D3FF9462D6A372EDBF4E9FE9F88
+:1078100061BF9CF65944FA326C253C5EAEDB8D2587
+:10782000BA1F52FE85D96EECFDC3EF28CEC6FD6FA0
+:10783000E588EBC2FC919B40F92C960E861D31D356
+:1078400063B0B724997072BD41173D1FFB3FA5CBB4
+:10785000B99E6B9411D709F487214F5FE979874569
+:107860005BE6AECEC3F7B7EEFEB0B05FE8A5D7C01B
+:107870001DC52B2A7AC6DB1280C81AC4A7AFE7073A
+:1078800007884E07086F95D4BF88EFE754217E51D3
+:107890006E97F47CF4268C67F9CAB1E4501BCEA134
+:1078A000F8D28C4333FECC783B65ED2F24FD60C6C7
+:1078B000D92909E627DA577D8638BF58A479675356
+:1078C000BC8B666DB5CAFB11FAEFB8D27EE0872497
+:1078D000B75B248E0F1B9FE97C9AF4D1D2DFFCC4E6
+:1078E00045FAE823A5DD4DEF6BD87A9FCB4B7A495B
+:1078F00009B8E8F98F82422F99DFB747A7A3712E05
+:1079000070D62E3D10597D0FD2E30CCA33C96F5388
+:10791000D7DF56DF437186D711A1B8F3B8D23F9BAA
+:10792000D671DB0267738B87E2DBF87D2F7DFC2746
+:107930006E8DF3C7817C9D7E1CAF366DB17AC238E7
+:107940006FD32BB2875EE38708EFCFFCBC3FF4BE5A
+:107950008DF4B76A8148C1B4A1F7918D36921B7F2F
+:10796000D7DA4F6417B5825F7EA273CC3943BDAEC0
+:1079700087CD387E2A23FE3C01E9C3F9D400AE8BC3
+:10798000F2471014FAB8F5D7EBC7BF8BEB3BB1E564
+:107990000597541A7BAEB08AE93618BAF5970ECB24
+:1079A000B9F17B4AC77BD46F09F2735AB7240E83AF
+:1079B0007A44DB600DBB286E6BD864F504F072432B
+:1079C000A70C0EB25F47EDEC3734747ECAF86C90AA
+:1079D000BC1169026FC325C5F811CB3A3F984DFA27
+:1079E0007659AE0C3528524B779E16E3BD1049C22E
+:1079F000F1CBB6BF3BFB87D447BC3B12F0AB2AB4FC
+:107A0000D726E4C6C4AFD0BBB3C91F6EFDF5E7CC23
+:107A10008F8FF648905D34F4F9FA4D1FD8C89E9CBC
+:107A200040C664A4097A91DDF087E405B6D444FC2D
+:107A30000B5FFDDB0ABECFF9BFF3F1F1213A6BCB4F
+:107A400062BC3FF55B5C47FD9B764F0DBDF7A9DB44
+:107A50005D8038F8506916B8FFF97D6EB2C3F5D66F
+:107A6000805BE5565CAFFFC59D8CC72587EF748BA7
+:107A7000F8C69B2BF245815CDAE7E28DDFE57DD627
+:107A8000818FF158FF73B996F234A715A8DE9E4096
+:107A90006E26654AFAF9DAF7C7DF23CE0380E2F3F0
+:107AA0000FF5BC69E088CC7E9B1DAE4D9D1B937F7E
+:107AB0004ACA14F63800C1B7E95CD58FE695CF41C4
+:107AC0000E9F9E4DF3DC51A434D33911EE3FA0D369
+:107AD0004BFA9AF302A029317E56D5E12BB2292F19
+:107AE000668741DBBF56B05FAD91DF13F31CD3ED6A
+:107AF000C3CDF661D2A5D8BA13E74D17EBFBC0BFD3
+:107B000023108327FF131F329E00ED776A8EE83F14
+:107B100046F2B8D0D99C8A74FBEC95F76D74AE151B
+:107B2000C0FD8CA0F5F67DC07DF0646934DE98DF81
+:107B3000DF6D8F9E07925C6FF9C024D7F1F7D17E7D
+:107B4000333DFD90AA51DCF6A12D329BEC7900DF8C
+:107B50004BF50575EBEC71E78D51BC98CE1775F9B7
+:107B600034F29C4B4CFE98D19AF5C284CC78BB067B
+:107B70001BB3129E2F9AE390066BF057449F86A387
+:107B8000768E5F1A3A85FCA1431D1981F2F071C708
+:107B9000FED76EC47D7C1CB266D6F0DBE2F56DFDCF
+:107BA0000E945F1C2F23BD9358DF7ECEFE94618F11
+:107BB0003E76E2C57109E416AF27945B27B03EFB21
+:107BC0007FA567979C43CF7E2F73889F908AAF8154
+:107BD000BF3EB9EC62F22FCCF435F4AB596F9ECEB8
+:107BE000D012EA4DD0EDBC41C7A5DB4E326ECFE4DA
+:107BF0008AF3A6A62D7F633B86648DD811B74DC14D
+:107C00004FB87F1FD931EEEF9D278D4FB4EF787AB3
+:107C10009AEF5F4CBC65B989DC4C74962D2E8FC8E9
+:107C2000CFA97C9EDF4A7693F4B4A602F111664296
+:107C300088FC0EA9E78F7FA3F799E38AC04C18DD73
+:107C4000CCE7BAB036B63E27A4E8F51481C4F539BE
+:107C5000ADB6E8792EDD3FD779EE715DCE3D4E951C
+:107C6000CB11AC999A9CA8AEC45365491847ACCFC8
+:107C7000147ED608DA33B67FCAD4C4B9BA5CAB274F
+:107C80001A45BC443954D67F692E3E0FB6EAF51921
+:107C900038730E9F1F245B3E4592C0CE7573E72854
+:107CA000941F2EB7DC5E82FDE7D72D9AA3207E3C81
+:107CB000D32C3B8BB17F68DD6271FF524BB915A1AC
+:107CC000FF78A06ECE2CCA1B58DEFD29ED4F59A5BA
+:107CD00000D58F94B47DC0FD3BACE2FCAAE9D95D30
+:107CE000F5F4FE26091981F46F73859AB98E210780
+:107CF000D455943CD676FAE8FEEA5C8CE7911FFBFB
+:107D0000527DDB33C9AE38C22EAD98E24AEFFAEFAE
+:107D1000E17DE588956242DCA7C8838FDD392D8738
+:107D2000F4EEFF85F7EFCD9C78EEF79FD871D57C08
+:107D30001A3F560655C6F9CA14AD8AFA768CAF2991
+:107D40006E33F850A608BA973A6D1CCFB5A5797373
+:107D5000084F7FCA34F875616DAB55F8A572B2C093
+:107D6000819C6A69DE8EED6B3AFF5FD7E9417F94B3
+:107D70001718D89DBD99EB56205248FC95E5CD9D2E
+:107D8000448F488B029B29FFBAFBF14EC2E7EB36CA
+:107D900007E78F6E487DD07A092EB9CC51783B81A8
+:107DA000FF4DA9E34E6A7F9FE57B2F53D4878569FA
+:107DB000DE1B6F96C5BCCEE614B29FE045B91279C2
+:107DC0001AF6DFC18772456BDE8772358154417CBC
+:107DD0009D93791D726A07AFE306BB58C7FC6071BB
+:107DE0006B3FAE63823D7811C557F8FE41C2C18D2D
+:107DF000E86E119E0305D04B7C7BFD964B3789FDC9
+:107E000015B0BCB2FCF3F9FB89A7683E3FCE4FE743
+:107E1000A87EA99FFB3B15871A50857E5F1093773C
+:107E20007B16DA5F2E15F9FD568A3BA6E971B191F2
+:107E30007F33EA0D26F7FAAA9CA4B0E51E99F4CA8E
+:107E400069F4D7488F99F36E534CFA775AF7C7AC59
+:107E500097CF771E9892A5FBBD799047FB08D17903
+:107E60002039BCBA9DF4D0796002F98F390FCCCAA1
+:107E7000BA80F3C03B33455CA1519D1CEE631027D3
+:107E800026BE0D1E5A0865155C8FD00C69E7B6AB8F
+:107E90005D26FD6FE07CDC2BEAADA4CFC6BD02B74A
+:107EA000D07EAFD0CF4F068F03D7034EE877707DDB
+:107EB000A0B5D71A0C4A31F528472D5C8F32089EA1
+:107EC00020D7AF04EC6A80F5E578AE3F693BAA9F06
+:107ED000F7EAF50CE58264FF743D84B9FE61AAAB54
+:107EE000525E50C1E73320550EAD7F982ADF2493B0
+:107EF0005E8143829F67EB20E45299F6753A0C400D
+:107F000021DAA45762F88DFF4DCE0CC85CFE742CAC
+:107F1000FEFA54132ECCFCFF4E966E8F75FE9FB367
+:107F20008EE42391579B00E3B98EC46AAE2379C3D4
+:107F3000C2059BD13A92F220C9DBA41691373E5F6D
+:107F40001D8FB94EC75C8793EB8BA7537EFD2571C0
+:107F5000F72F6A2E8BEB5F7CF7D4B8F1456850633E
+:107F6000FB250FCC891B3FA2FDDAB8FEA80D37C652
+:107F70008D1F135C18777FEC134B13D6BD1838197F
+:107F8000175A1E777F7DF253EF13BEDA726595FCA8
+:107F9000F94BBBEF31D5C54C675C4C35F2F03AFF7D
+:107FA0008DBA3A2A03233A4F44FE3F56447ED3BD4E
+:107FB00055923614079E7080EDF83F8B83874C38BE
+:107FC00030E4FF7CF99B75BADF2327154AE4E77894
+:107FD000D1AF4A9A4675C4E2DC1EDE12F52A9F270D
+:107FE000FD83FD224D7279E0327AAB2A911F7457DE
+:107FF00095C67ED05DC30AF752FEA0FFFB2E8F947C
+:1080000037B42ED45C079AEEF04E012EA115759070
+:108010006DA8E8B95E77A683FD8C872C965B6A63B2
+:10802000D6DF9125F44F4796B05B3FB385B6931EDC
+:10803000501CA0B6E48AE7A9F801A8B207F9E2CA81
+:1080400000511F0647D7CC9A4EF6B37FB49646F53B
+:10805000B3D8BF082F2B41B62737B62A1CE7AD4A45
+:108060007E8AED499922ECC90459D80DB423BFCDBD
+:108070009A4876ED5EABF0B30256E24FBE0302AE15
+:1080800032B6AF7C4E9C0699D2F252AA4F3D6BB7E6
+:10809000B4AF114CFB974EB3109D0617C97C1EFC64
+:1080A000122D09D73B583F86EB9C07CFD6FF69A915
+:1080B000145F0F2E7AE4E49D1551B93C6A4B1CE71E
+:1080C0009D2FEF56BFE991143A47393A1AE2EA3345
+:1080D0008E6509BFF158962CEA13821FB8894C03AC
+:1080E0008BFF6B242DDA2FF5AD76E290FB377CBF4A
+:1080F00096F862EB9A1BA0BCA691C73F1B07F6CC73
+:10810000E0FA6D235EBAE17591D7BBE1BFE2F3D629
+:1081100027B3AC7CFF24BD8FFC9A5EDF44E2DB35E5
+:1081200024109C57F64D24FFA056058DECFE7CDFF5
+:10813000823B0F617FEE8312FBFB749FC65F5B8007
+:10814000F606EFBF0C9E5777E1FAFE9E25D6330F59
+:108150006AADB4CED76E6E4C213CBD9E26C6472478
+:10816000D036C7CC778D3EDFEB372FDB45713ABD7C
+:108170008FDE4FEBA1F7CF55A198FAAF81EFE4ABBB
+:108180004543DF7B1D78AD7ABD9795EC6409043BD0
+:108190009F26BD7AD0E25903DC8633D82ED9D92E5A
+:1081A0000DB4449E5A81EB7C67E9DF764948D7B726
+:1081B00017447EF5345EFF970D3268888B4FD37D70
+:1081C000567756944E47177D9A42F4447F65EB4F9D
+:1081D00049EEB6D93D54D7F1E6D26D2363FDFA548A
+:1081E000F78C616EF2AB2A2FEC3CADEAC9298CBF4B
+:1081F000E55B05FE96FF7A5436E16C79CA59DC8955
+:10820000FED6123E279D2441C2F878CF4AF1DDC246
+:108210000EC4998638DBF385A82BDF7928BD9CD660
+:10822000A780EFE2D8FDEC7CE9C6B15CCFFB46E667
+:1082300005AD93643680FAF7065695002FEA723240
+:10824000BF27A35CF727C7D2FC37FEEED727FF93E3
+:10825000E8B27BDBD61FB28C5C181D86D6D1AADBB8
+:10826000583F197118D5BD529CB6DFC276F20AF993
+:108270005E8EC3A84E83E3AE61853C1E158E6A15E3
+:10828000FA4D7C27817E70AB87EB3D595EEF5685BA
+:10829000DF62C449B2C593A3888F0C5E98C6F317FA
+:1082A00003E5C75C145819FA0AFD08976CD1F51557
+:1082B000781D189F8ED5F559B57BC2556DE2BC2649
+:1082C000CEFFC47E554702BFB316FFB1DFB9D1D789
+:1082D0009AC47669A35C4A7E87D711263B6EF63B2B
+:1082E000A7C1839C0718E27F3EF7D70BF23FFFD56B
+:1082F0001DEF7F5EA8DDA9776BE2BC77B4D073A1D8
+:10830000F0308E73F0AF9CE46B64B6B04B7D1463B9
+:10831000519D9F746AB403E5B3C15DBEF6019449F3
+:10832000C770411FEAB7E2FF97689FEEFF9AFCC053
+:108330003E85F937F8DC25DFF81D4905CA2119FB10
+:10834000F081A95CEF3CD02BE4A3335DFBD3348AEE
+:1083500033D0CFDC8C4B4C52FA6D6909F6F334E91B
+:108360005F9207B7B0478E6E712EEAD0BC40FA25F7
+:1083700049552750606E8CAF730BFBD578E0CD422A
+:108380001BF2E7A4E5908BCE571A76ED70E176E10B
+:10839000BE0CDFFD84EF65478F4C52B9CE6D532183
+:1083A000C5DFA1F09199EC9F552369279C7B3FFE87
+:1083B0000DE5F41102346DC8E0760CE555F0923FFE
+:1083C0002CF679AABB353D517EC0FFFBB7F6D17EB6
+:1083D000B7BD98C47ECBB6AC3E9683C05C80AD483A
+:1083E000EF27BF18CBF32127781D97D46A12D9FB4A
+:1083F0005FEAFBD9A6C797A7BE90799C31EFB8EE8C
+:1084000019B28AB82A0DB7EFE33AAE1EBB46FC4D4F
+:10841000DA02823E3D495C17E6DF73A5883BD3C490
+:108420007974E7B0C8DBF49EC86EBB4675AA496A8A
+:108430003BA4E3FC9D366167C720F07738A3D78D56
+:10844000F725F5ACE78F2010175C8F97A4B4C3B75E
+:108450009CB1F44FE1F586DD02579DC3C21627D9C2
+:10846000098C9536F3BAA2EB047EAFB1CE31EC178E
+:1084700077DA227FA17C3BAE4B255C8C01B14EE8C4
+:1084800019A591BF92A48A73F52455F304A4A1EB16
+:10849000F28F87203A07F0D02A382BE75C47382C38
+:1084A000DA77A02C7416EB7E4C60F1DA5905317D39
+:1084B000526495D1E75F75D7AF6D2BA07D093BA8BE
+:1084C00028213E1F77CD0795CEBF93142FC749496A
+:1084D000F3406B417E253BBC7CDF8D73B44CE17E69
+:1084E00098D6AFD27DCACBA4AAC97370DDA95FA606
+:1084F000F2734D7D56AE3B6FF8C775A9A5B8BF1393
+:10850000967D2B3AB0FD784168249DD356A6FADEBD
+:1085100021BC3E736CE1DA7138FEAF9D564F0DE918
+:10852000A5FEC08FE9DC7EE993568DECE2FD6F0C71
+:1085300086BF26FE3E2BB15E1CB08AFBD8D75AF010
+:108540007E53CF87363AD7BAB2FB5D1BE5BFEFC982
+:10855000F61D27FB56D9DD5245749B02EDAD94E71D
+:10856000447DC8F512A11CA12F065F19B9B9258653
+:10857000CEAE6CFDDC2BE2BB98E4A64797CF3DE482
+:108580001F61BB4BF7D376EDFD97122DE6FC34004F
+:10859000FB381FB80A9EE3BA4EE3FA4050A9261CE6
+:1085A0008D7DCD718B3706678E6C5DDEF5F7FD3CFA
+:1085B000DBF70F96DBBDEFD95CB87FFF9F43856487
+:1085C000AF42E8CF7D531DA9DF242F67EB8E8E03CA
+:1085D000EB916DAF75B3FFBDED1E358DE41ED70F6A
+:1085E000A9D8DF85FE05C9D1AE2221772DAF9E190E
+:1085F0004FF9E233BB975D4CF48AB8AD06BE670E07
+:108600002339DA0EACC70C392C2539C4A597AA2218
+:10861000DF534AF826B9B3F5CD61B9DB6501923B6A
+:10862000C437E31DF1AD921F52AA22DEF9F9512C95
+:10863000C79D7D472EE17A7624EF8809D4B730BEF6
+:108640003AC37382123E5F610DEFA3E72BF0FD2D5D
+:108650005A542E2BA4F8BA9E3AB7A89335F4E3EDFA
+:108660006EA1EF43A3B5540F8E4F96E538FCC7D8E3
+:1086700049D1D7EDE80FD6FF74ED3A9487126FB960
+:108680006512F93B2FCA6C07F6E87EF2F23F4CBD4B
+:10869000A6435C67FB19D671B14FF79B9F5B99C3EB
+:1086A0007DB20B1AF26522B6DE72AAF76EAEA25444
+:1086B0005C6575FB7E6AA7D686AAE8B870FAFCBE30
+:1086C000FDE21B37EF58C25BD7BE6F8FE53AE9A3D7
+:1086D00076A0EF38BBFE1E79FB49DCFF8A3D486F70
+:1086E00048E89730DED06233FECE859301A9FFEAD9
+:1086F00069A897AF59FFF8550A1AF4260202EEBF8F
+:1087000066FDD6B5E8BAC0ABD9DE6BB291DF5FE5E6
+:10871000F8AEC946BA0D1CFEBB9BECC9AE57DE7362
+:10872000911DEEB279C712AEBA8A318E4880C7E980
+:10873000D9A26EA7E21CF526CBB3C5F9D6C800AC0A
+:1087400025BC3475C96A90ECB4B7EF6AB21B7F419F
+:1087500052525EBB6E46C045F152FDAEFD5CA76F46
+:10876000C4D38B41FF936F9A4DF43F9D23E2E3BA4C
+:1087700075D6B8F87614846D748EECF7399BC3C83F
+:10878000927A93DF715BF726FE6E64E996F8E71A3A
+:10879000C84F4108359C273E5E9EADFB29255042BF
+:1087A0007E0AE286F324915765CF66E0FAAA5EAAB4
+:1087B000AFDA6611744A76405B6A7AD45F1993EB3C
+:1087C0005D4272BE44C767A75EAF14E994F87B8A26
+:1087D000314F887879EA716D137F2715F0729D5EAD
+:1087E0003D2D00D73D5509F0FEA7E6944000F75F08
+:1087F00089EA99E4A5AE470A323DF5EF5E14FC27FD
+:10880000F2451B65FECE6FA3041945346F84E9B3AE
+:1088100054CF1F2E7B22FEFCA261C3E103E42A3564
+:10882000864CE7413A7DCCE73B3BE87F129CEFACBE
+:10883000CFD6F308855018F75D5EEF857D97F7B1C9
+:10884000FEBDEA117D7E63DC2E5D6F36E9FB6E08AE
+:10885000CA62DFC80AAA8FBE5587891F3C4CA7464B
+:10886000C409E1001E14FC36EA199742AD8DEAC82E
+:108870001ABB5A0ED0F95B9DEED79AF18404657A43
+:108880002DD1EB86EA37C6DF5FAAD365A9892E4DC5
+:108890003EC9B43EE1775FE8FA50735D4F3858DA6D
+:1088A00061E57AEED37013D75F35766DE2F5D4E9E2
+:1088B000FC1BBADE00EF6709EE87E4E942D76BE6FE
+:1088C000DF9F0C9C5F0297C4F1AF3AE382F8570236
+:1088D000EA32DADF60AF886B077B8B392F61E0C546
+:1088E000FCFC6CDD8FBE7283F0374F765725933FCB
+:1088F000307048F14888FBF2173F73D1F73765BBFA
+:1089000065A073D2819EF2B501D4973B7B875FA7A8
+:10891000A11D287B5161BB51FE625930A988FA65BF
+:10892000C9255C67A265501C80F3B01D1E3834FC5D
+:10893000E552F6D367555088DA72A82C99FC859DCC
+:1089400020F21BD28B1519FD3176E5C36C91DF58EF
+:108950009DF3FE43A4A7AEDC6EE57CF095D6C84B34
+:108960001487EDEC553C2DD86F7871E1AA24E2F71D
+:10897000AF250FB9DD07FA9667D2794D638F55B5EC
+:10898000F37AEFDC47F7031D9267048EF7EFBE62C0
+:108990006C27E58936957B88BCC6FBCAD2B447A84C
+:1089A000DE157293396EBFF2222BDBD71379C9FF24
+:1089B0005183FB5AEADD349BF4F089DFEEE4BA8A96
+:1089C000814E097224CA23EF7F8AEA7D4E3C7DD80E
+:1089D00046E7C1555D87B96EE35CF6E0641071C788
+:1089E000717BBB8DE29BC64D46BF9FBF47A9D5FD9E
+:1089F000A8A62DEF727F29C50184C78D7250C3FFD1
+:108A0000DDBFFB193E1F6EEA10751F67EF6F91F80F
+:108A1000BE81F785BADE5A061AE37D998177BD3E9D
+:108A2000CAC0FB69A8E13AAD651D0F33BE17EBF86C
+:108A300036D74D0134DB4A3385BC52BECDFCFDDF59
+:108A40006D3ABE6F3B0FBEC7E6E8F81E036308DF52
+:108A50006766887ABA33878725D3FC670E72F6F586
+:108A60009B70CE76F790EE170C862D5EDBA5D1714C
+:108A7000A7BA3FE5EF10FD87066D547732BBE713C9
+:108A8000E6474DCFDE5944EFEF80AF81E8F79D9E7A
+:108A90006495FCE09A7EA1CFE6F4D8F97CE23B1025
+:108AA0006A233E0FEC79BC2D9D70F32B811B43CFC5
+:108AB0002DD1E97A55E9F76753FCBE54B78783BDDA
+:108AC000B7CF66BD33018AC8DF9BA37FE73D27A4EC
+:108AD000EBA18DF174A7736AE25B538F9DEB4DAEF2
+:108AE000827E1BD9B3AB74FB69B69303B9C9CCE7DB
+:108AF00000DAAB1138BEA1C35447A9F4F37A06BB20
+:108B00006D7CDED564B2BF97E508BFF27CF1BD99FC
+:108B10005F0B72747BA2F3AB2622EA18E6BC227BC1
+:108B2000E8FCA137BCAA94FC05836E667EF56A2535
+:108B3000A9DFF47B092FE97EBED1BF46FFFE2DA43D
+:108B4000B63B63E3F6833916FD9C33F8D372DCE75A
+:108B50001D12F4110E31BEB9A64C4A18DFDC938306
+:108B6000FAE38F05B73E382136BEF16E1A49FEDEB4
+:108B7000FDA857CA2BB87EA78FCF0B95F61A3A07D8
+:108B8000F377583D14D7F8BB65F607FC1DF6A00532
+:108B9000E7BD927084EBAAED91AE201C61DCB09A27
+:108BA000E69F4B29651C37B71BFD117C6EEEAC4F61
+:108BB000187F07878B7D0F2A5A76A238C2881F9AA2
+:108BC000BE10FEAA71BD09F5008D6FD2BF4BEBDA66
+:108BD000F7B7C2A2143AB7FDBC7001B64FE7083B25
+:108BE0006CF8AB11F4578B757F85EA2EEA04EBA085
+:108BF000EEB97B6CA4BF0ED00F5B50FDA4EA5B4DB9
+:108C0000F1B0EA83E61F91A321B5B11C35914C1157
+:108C10000E7749227FF3AC956A43A0E5C830AE0BCE
+:108C20003CF59A388732CBFBA9857DAC2FCE2C70D2
+:108C30003613DE96956E5A9D4EF2BDE775D63763B4
+:108C40007F6B532D6A745F2DF4DD1DC7696D71FE56
+:108C5000F2A9EE561BE7A163BF1B2E1EEA1F359E2D
+:108C6000278F75D0A45770FDECEF0E1C9455CA0BDE
+:108C7000211D7F91174B2FDD1FEADA97C4F66BE0B9
+:108C8000B033487EFF5F753C9ED0F3F22D9532D312
+:108C9000C33245B463F73C534CFC257EF850DF6F7C
+:108CA000DBF3CC255ECEA307451DF113F175D88DFE
+:108CB000A1F83A6B83AE7E9DAEB8AE91F4BDB2B171
+:108CC000AE5D4ABFCB93408E24691FF3CB22C5C74C
+:108CD000B9FE67E5DAD83A52DCCF2DA4F7FED3907F
+:108CE0001725E2263BFC4E8EC6EB6BE911FCB5EC7A
+:108CF000162DBEFF7A91AFB1F2FB87DC9F1968A0F9
+:108D0000FB678A92B9BE01BE08D4507F45B1F8FD19
+:108D1000801547968E8ACDD38124E271BF35C2F586
+:108D20007EFEC3165E9FFFF0A07BB893F4E2A659C7
+:108D300054477B95AE2F0E1427D713CE03F4DEECE9
+:108D4000E83C4B72C47903D07E73A2DF571AFB5DF7
+:108D500005D7321D56E9B87A4B8F73308EFA222729
+:108D6000411C752EFFF7ECBA75FFE9CC0CEDE5EF71
+:108D7000210ECA0E2A018AD777BE911424FBDFB2D6
+:108D80007BC93B140FFBDFB403F9212BF62C19C56B
+:108D900075F83EDFA5A44FCEECB9ED52AE6394C496
+:108DA000F7A5015A5F0EF953AFBAC94F6ADCFD2A25
+:108DB000D73936EE9AF808F94FE82F5D45D7D18FAD
+:108DC00061FC95BD58C1F8DB79A822A384160E9EDC
+:108DD000649AB7F1A0C2758F8D072B5EA821BFE6FC
+:108DE000C599EC3F19FE5239C5E3E43F1D1C1EE74F
+:108DF0003FA5E60AFA0DEC4DE2FC8704C5023F30C0
+:108E00003C0E3F0D5D7F603FA301F55D2C8E8CE72E
+:108E10004A72159E6754AE8E9F90E4657C6C176D08
+:108E200043F74EDEDF326B88F9DDD26115F73B4543
+:108E30006BD44907203D40F478812E211FE6D8826B
+:108E400005146F3E5F14FFFB4446DB912BF209CF04
+:108E50001F15DF193F3FC3372AD1F7C6019829E212
+:108E60007049A77797B53AD1F7BC4FEAF3B93220EA
+:108E7000EE5CD2687F922BF4EA1C9BC85399EF2FCB
+:108E8000CC35EC0FACA5F398976BACAAF1FB2DB9E0
+:108E9000A877AF06E3CFF3EABC4C3AE7127135404E
+:108EA000FF2CD287DFA53C3FF95F95C2AE1B79FE50
+:108EB000B91BE13E91E7BFC94A7AC1A82F99EB35AA
+:108EC000FB5FB557D03CD7A27DA779AEAB8EBFFF75
+:108ED000DDF3F85D37E6EA767C248C1471853399EE
+:108EE000ECC1E95EAB2AF33E82C3137D5F68E89F65
+:108EF000032BC5F9512FEA456A5BC6BCCE79ABE7B7
+:108F0000F71E7D2A8DF56A121423892FFFF21D7733
+:108F1000A2795ACECAEBBC38FC19FC3A497140E937
+:108F2000507EDDA9D3BDD171C2C6E79BD0FC804580
+:108F30003EF777492D633E6F23793AA97FF782EB9D
+:108F40002BB4C7E8FD93B99FF0FD15332112C0FB88
+:108F50007BC7D8D9FE35CE92F8FCA0312CEC61E36A
+:108F60003C610F4776CD65BE5C8F7CF17A584DBC75
+:108F70004675B906BF2FFF726096114FD2394E0B5E
+:108F8000E19CF57426B78D5DEFB6F17925DA5DF2D7
+:108F90000BAFA98CE7DB28F0DD9785F76FA8963C2F
+:108FA000684186F0FD869BE632DFAFD3BF8F391F65
+:108FB000DFB7E7FA36E492DCF70D5E3F0E49F4FCCA
+:108FC000980F0BC9BE369D03D75B0C5C0F8F3C4DD1
+:108FD000E7659EB3E7E9FF783AF63C7DB8DBF71F1B
+:108FE000B9A4572D5FBA2E019AAFFF17CB25E21314
+:108FF000F0F3E792AB2775B97A325715F9DD4C716A
+:109000003E3456EF3F6F0D16F0F714A517760ED8C5
+:10901000F2EC1FC7939E3BB5F7E0785B0C5F4F2CDB
+:1090200047FD40F666F77EFEFE308A3B8B8E3B8521
+:109030005B49BA56B7A3F1383C413824FDBC7DFFEB
+:10904000D5143F9EECBA2E53D262ECECAE975D2362
+:1090500062E63DA9FF2E06C66D23BF9B12BBCEFB69
+:10906000C4797948CC87F23FF2BA71B1F75B753CAD
+:10907000F7339EEF1FDDCCE7F4069E151078367EA1
+:109080000FE3EC779536E0EF1E037BEC5C5F31601D
+:109090008D14A6C5C8CBC73A9D314E930B32999417
+:1090A0005CEF3A19D655F1390106EF6BA7D0E77797
+:1090B0002159D4873673DDE2F466F0106E25D8C8E6
+:1090C000FD49D5E2BC7C2AF4C9B4AECB20C2AD17B1
+:1090D0005485DA995461866DA52324933AE9ECDA34
+:1090E000974CF80ABB95B4BF3844E96922FE45F7AE
+:1090F000AFC05F0CBCE2607482127EA7EFCE137526
+:109100000E9E64218F9193E2774FBE05FDBCFE69F0
+:109110004A1FAF3745D3D2E9BC64FB73CB65AA7F46
+:10912000D9035A84E4CC93D1CCF9B7C80C086D4E5E
+:109130008BEEB792F6AB46FB53E78385F62B418760
+:10914000D87F33A4D3F9D81408F37B2EA705E37E88
+:109150006780A650DF9157A4D359C46F557AFC6637
+:109160007104B8EE27354FE03A5909CAB9159CDAAF
+:109170000E3D4CE73325629F93F13A9FE3348B75A4
+:109180009FB5D77942DF4D8510F319EA417D817F84
+:109190005C61964AF492C26E0BFD9ED885D275C072
+:1091A0000DBC7ED7AD91533FAC889E7B797AB2B926
+:1091B0001EFA41C91291695D8E02510F1D86107F02
+:1091C00097198EFFBDB392BC6B8BF268BF3EF11D49
+:1091D000AEB9AEF389E066AEBB991F40F2D03C0554
+:1091E00000C7DDD13A006B7190EF5BE99C5DE53A19
+:1091F000D3728A177F9FE52BCACBE27AD3113C99B1
+:10920000129C589B12C53BAE8C7F7F271952DA49BE
+:109210001FB5EAF5B401D5A5D73315F23E34D4F322
+:10922000FC23128AA8EBBEAB4AD49FDE356C0FD765
+:10923000F9F64BA04AF974FEBF87EB80E987E1ACF1
+:10924000F9DF70FE9FA9FFEE43B1EF8DC925BA92F9
+:10925000C7E75A8FA570FDAB32D3AB511DAFB95ED6
+:10926000BCA46DE203FD1C971AEB35D5892B1EBEFD
+:109270007F97AE5F5B1DE27780A45576559A4EDFEF
+:10928000BF2FE7DFB16A25D7A082BE7B5FCECF5369
+:109290001D33158146527DDF257A997F970AE13586
+:1092A000F83CCD9B3A92F37D89F831DDE087656823
+:1092B0009D14F2E166E2AF51776BD4DB122068DFD8
+:1092C000C95EF13B782AE2847FF70F9762275C7AC8
+:1092D000CDBFE721EA7FDB74FAE3BA9EE0BA4F879D
+:1092E000F84EDBF89ED74C3703BFFF0D047C0BCE46
+:1092F00060530000000000000000000000000000BB
+:109300001F8B080000000000000B9B29C3C0F0A3C6
+:109310001E8145A451F9E8F82C9A3C0B0303C34F76
+:10932000209EC7835F1F2E1CCD82607B8A3330183E
+:109330008932301803F14C209E05C43F80D8408C00
+:1093400081C110888B80EC6220F6016207A0DA2FC1
+:109350001C0C0C138419186603F1326154739F328C
+:109360004268252E06065320FEC784DDFEC96A0C1E
+:109370000CDB7510FC385D068635FAE4F965140FD0
+:109380003DBCCD1195BFC70A95FFDC8681C1DE09C2
+:10939000C1DF6B459AF9D540BD354EB8E58FB9A10F
+:1093A000F2F779A0F22DD1E41787416800E6955CC9
+:1093B000CAB8030000000000000000000000000028
+:1093C0001F8B080000000000000BED7D0D981C5560
+:1093D00095E8ADAEEAEAEAEEEA9E9A494FD293CC1E
+:1093E00040CDA443069884CAFF04265033C130AC54
+:1093F000A84D94ECA0A89D1F312ACB6B780A01C11F
+:10940000A9F9EF9924A4F3F342F89134D12CA0AE3A
+:109410000EC87323B2CF4E88BCE0DBA711D12F6AF0
+:10942000F01B621E4FD45D67D92F4BBB06F3EE399C
+:10943000F7D64C574DFF4D02ABDF7EAFF3E1F5544D
+:10944000DD9F73CE3DF7DC73CE3D7547264D247608
+:109450000D21E7E047CB3F780921CB264BABC3C8B2
+:1094600092A5B4FC0A31FAE8A3CBB56C8740CB05D2
+:10947000EA9847D009B9229226C443486CF431E2F5
+:10948000A1F552F532196924C4AFAFAD22EA64BF29
+:10949000EEB2AF9B90ECFCE2EFC523C3513D44FB21
+:1094A0007B6A799749FB493DDDDA65B64CBEAF83EF
+:1094B00041297E4D8462534BC840C35EE28910321D
+:1094C00044C79E4FFF53EE4B90386D27678789BE88
+:1094D00000EA55637DE5D9E39EF5F4F99097748D24
+:1094E000D2523964658314EF85CF6B8B454A8F5F09
+:1094F000323DBFA5B03FEAC95840477417F67B8696
+:10950000D20543BD5BF42C017A281D6D15D2D356CC
+:109510008C9EE72D0BE8B9E290BE289F1EA59ED138
+:10952000A3D4F7E23C9D89527A1A2F849E7B909EA9
+:10953000214ECF908B9EF7717AD6D9F4D40D223D6F
+:10954000830D941EFAC8779F45E2B4BE02F484A04E
+:109550009E939E41A0A7A5003DCA9F879E4F72790A
+:109560004B023DCBCAD393047A6A2BA0474D138D8F
+:109570003EF713C11C6D998A979FF371C1B3E9A897
+:1095800045FB1D7E5BC479A62B32BA76C164BD3122
+:109590008ED7F71A07A363205FF3F64609ED6FB87D
+:1095A00041C0FAEE7E1F2232D6AFAD377BA0FFCB93
+:1095B0009E74F63FDCC0F0B5EBFF139FC77F2222FD
+:1095C000B6AB51E3C3000FCFFB1649C038DE74546D
+:1095D00083768DACDDC0BCE55D636AA1F68C9EE14F
+:1095E000FB2D9467257B0FF2EB730D69A253D8FF17
+:1095F000648200FFE528C3C76E4FF122E44A20FBD6
+:109600002ED364F811329BCE937557D6A2E3C5D200
+:10961000B72B71CA8FE1BA5E05E84EE9BBBA406F5D
+:109620009D89C9446C04BC0AF3C1968B6BC836A5EE
+:1096300089CE67DF2BA23142A6D6B340B86A276134
+:1096400049F5906C33C1DF3902F42470FE07E6ED72
+:1096500045BA65A06B01D095243A7DFE1C971FDFAB
+:10966000B31601B952742B6A2D983A4E0AF8DF02EC
+:10967000BDA6A36BF3E8FFB93DBF745E5DF38B7CC1
+:10968000798898590BF8E277CE9B5DBEC4F97E4588
+:10969000BD85FC2D37FE54FAD9F87F4F74EC87282E
+:1096A000E9683C3489CFB077AC17E49AAE49E3203F
+:1096B000ADB2908ED39EC76FF77813744A69871C3A
+:1096C0007F8BF369D83F7E24BF3F373EDFE5F5BE91
+:1096D0004B342C6DBA161E62E394EBFFC7C0E25AFE
+:1096E000A8EF5A5792E5E0FBBDBCFE15CF3BEB154A
+:1096F000E3CFE727F86345411EEDF5083F732621C8
+:109700005C64F0A72E27E452F83FB4C9EFD78FDD91
+:10971000054BEB1791C419E8E73692B8383097AE8D
+:10972000176FE20928AF95CC7F83E7B495F6FAE589
+:109730005CEE44D4036C3CDA3DA1FD87787F92D087
+:10974000490895675F2BC98C50D4DE239ECC0A94C0
+:109750009FBB0831666979FBFA29B6AFAFD432AB4B
+:10976000613FBF4AA284D0F1AA88E68712EA6769FE
+:10977000BDF032D5A023111FF94855BC80DCF89705
+:1097800012CB5F45C76F951DEBC26F2608E8855069
+:109790009464FD614234211441FC5790150C7F5DA7
+:1097A00080FE6A24BD47A2E388318F71803EAD6A96
+:1097B000232B37E4C9A12E30F9ED89793C40D7201D
+:1097C000D5FF3EBA24C30D74BDC37A88527BA380F3
+:1097D000DC4EE8F79C48B23368BF39816497505833
+:1097E000252B13B45DDA47569EC6718971A0809C03
+:1097F000AD13D8BC0AB1F173E7D02E2099EBD02E6F
+:1098000048E33A96636913F601C50C1B3E98F6B31C
+:109810003B985E93880972521D4B67ABE0BD7E4951
+:1098200023E03B2B9624AFB5B0F2541EBE8A6A45A6
+:10983000D17E6ABC44E8CDDBC70E53F93995276F5A
+:10984000A9FB991D30D038C8F5CCA7507FDAEF3F7F
+:10985000C6F9248F5164802E5DCE340953E53A2534
+:1098600014D6131B39BDF0BB76B9535EA5995C5E67
+:10987000E9103E89A07C0D3D4532802FE5E491F54D
+:1098800014BEFCA84246A87CB590E31E909F856458
+:109890001C4B836822948B8981E55212C7F2F7ED45
+:1098A00054EE69799B49E5BD09E5FF2601F68986F5
+:1098B000C4FC307DEE8F5957C2FE42E57F1D3CA7A8
+:1098C0007222803CD598A4E07E592DB0F5BA53D2CF
+:1098D000FC506FA749503FEE11FA2CD82752DC4EAE
+:1098E0004AF989631D3FC0E94EF1B23A96206330D0
+:1098F000BF745E40AF1F6EBC15D7B14F62F0209DA4
+:109900001794BB556C1F73E3A1C0BC2C38FF79586A
+:10991000F7E79F87416159C179188279582730FD4F
+:1099200029FF9A8D5F823EDCA737F63C8EFC974F6D
+:109930004FAFBE4DFF7297DE5CC1F5DC5564FC2273
+:1099400089EA91DB7D59591210EF2F02DEFFF6B341
+:10995000E31F037AC858623EEC5314EFC704E46770
+:10996000921CA7E34BAF8819F0533CC11B944409E8
+:109970003F8568549F295C9F35C1FFD66BAF07A711
+:10998000EADF4B463F7902ED0DA22446403FAD4A47
+:109990002A20177DF56B1590A3A17A0A83DC446514
+:1099A00045B882962AE904F9B3ED8F17A21B14D0AB
+:1099B000CF723431C397B7FE574713E457B0CEB5D3
+:1099C0004454A474C899EB14A067405BABE4FB5704
+:1099D000B29A88CA54DE86A05F18C79B5404D493F9
+:1099E00064462FE5CBEAFA24F67338DA81F80C687E
+:1099F0001BB0BD4EE26837BD50BFA1B311F68B5707
+:109A00003612D063C5F8E1B6A37D6A92C879FB81AE
+:109A10004F4B12316F3E7D52320B7888D1C2FAF52E
+:109A20000497738F1EC77D85A41F34152ADF5E3E01
+:109A3000D7DE28F999B0306F3E2279FB0B9D8F411C
+:109A4000BFD15568FDD19DC2D9AF21106579E5FD23
+:109A50004EEEAB7C7ED32B526338BFA134CC6F1F4C
+:109A6000D5EFB87F9E0C650E52127A5625F7C37B50
+:109A7000AF2591DE0876D30CFBD9DDE26506C8D9A7
+:109A800003C037CAD86DDD0A9623DD1A96A9EE28E1
+:109A9000960F06BFF0C4186DB7C5F2693E5ACAE901
+:109AA000BBBF01FD51EF3A3E02FD4668FFD0AFA4B7
+:109AB00068073580D9FEE28DB1F2660FE3A3EA09AB
+:109AC00020BE8B3CCCDED68989F292D64AFBE35588
+:109AD000AD4E7B36640426E59EFE176CAE71C07EEB
+:109AE0007DB6A3BE7B5DFC80EA26C0C72BC589D1AD
+:109AF0000265617D7D5610114F515C340E768634BF
+:109B00004BC6FD7F4070EAE7473C6C5FCB7814ECB6
+:109B1000374AC65F3847F9E1D53C68DF84AB9B46DE
+:109B2000B3C09F5AD998478BB0774CAB29301E8968
+:109B300048BF1BCB5BCF4F0966A3E72F804F53E88D
+:109B4000EFE970C875CAC3F6B5B37CBD883EB30BE8
+:109B5000F449948A2141F9D01F073E78826D46333B
+:109B6000E5C340B5AC83DFD3DFE329B8BFB8F92044
+:109B700056DD12053DE8E6FBF35C8E9EE27CBFE617
+:109B8000EC07505F6CD73C9D19D41FC73B419FF732
+:109B90002FF57840CEFF62F8E7A2E3735C7ECE0A31
+:109BA000137420DFFA23CC3EDEA651F981F51C6147
+:109BB000F2A3936C27BE37285DC254BADCFC7BB796
+:109BC000E9B3F95E55ED89675A00BFF138E2D7264F
+:109BD00015C4EF3F8AEF365EEA045E598697F19727
+:109BE00081D7534262BF87C20F70797D401A5340BC
+:109BF0002F34423DD03B41B68EA6EA25C1DDCF933E
+:109C0000A02776403FB4FE0E69DCD18F5D2F047C27
+:109C100060EB22CED685F4675D17365E231C6F9D00
+:109C200064985C371796EB771B2F7B3FED0D5E4DED
+:109C300040DF54AB71B4B367A9F12CF0ABAF56D68B
+:109C4000C1FEA10E11EED7D854CFF3876AD745D104
+:109C50007E09AD43FB7BC01B477BFC58EDB7CCF5C1
+:109C600094AEBEB355C46750BB3F78F5311DF4E2E6
+:109C70003111FDB2BEB37367250BCC7310E26014D3
+:109C8000FF00E087F6B33C616C03BE7D2A557CB4CF
+:109C90009F375B4806F4A95735A3605FF72D508CBA
+:109CA0005EAC1527C0DFDEE0C75A132D53DB07D5A6
+:109CB000C13BC48593E3D09F700E6C5CBA8783BFB1
+:109CC0008EF4098EF705F128077B27610DFBA7B0FD
+:109CD000AE40D782796EEE24DF292DCD12EC9B2485
+:109CE00060C0FCC7E29DBD7F043EBD24A21E74F38C
+:109CF000E75931E113F3E25EDE4802E7CDEEEFFA19
+:109D00005A09F5A8544F323E01468DA31DD957EF8D
+:109D1000C1389AA4AEAD2A695FD757665F131EDFBC
+:109D2000B0E5A1FDD76CDC80C1F477888C11889FE9
+:109D3000541116BFA826BA40B0BD21C43128D2861E
+:109D4000719388FF9DEEF716EC5730779273C169D7
+:109D5000F42BD17EE7BE0BFD96C1D74F1EC57EA961
+:109D60007A889C9B31D9AF379AC487E4ECB973E207
+:109D700072C29AE02F81F22D790C5C9F6476D838FC
+:109D8000488B81C89D0EBFE946B1C9111F95B5C169
+:109D90003B84302DEB6F33C7F2F4837B7E6F82817F
+:109DA0009641BD4DE658057A03CCEE42F1A7413904
+:109DB00091E981FDFB2215E385444A62FC7748A8BE
+:109DC000590CF6B35D4FAA97B380976A9816E88B43
+:109DD000A1191E4334A0DF6DC7C11F20E20D46A2AA
+:109DE000441C49AA977E934FCFA745673CABAF8CE5
+:109DF000BC0F74973E87F0CA46A2903F73BFC8EC71
+:109E0000176FA0F0FBEBE58E7BC56553F9B69DF3AC
+:109E100077A89ABAD65730F1013990EA5F3C017CB5
+:109E200018A85D132D452FD1A89D93E7172D93CD2D
+:109E300021B1341E5BC5DA02F3A752E15959629C85
+:109E400009F94E120DFCC557983EA2F88685994C2B
+:109E50003FB39F01361BF1B6FAB4113A6F811683F6
+:109E60007C99C2D1D54A5C6AA5F42E3D4044785F06
+:109E700027121174ACD866A0BE6A66FE9D49FF0128
+:109E80001DE136D9B16F81FE9CD8B71A41FE9DF015
+:109E90001330CFC1BC79EE3E447E356F127FFAC8D5
+:109EA0002C1417F6CB1D7F57981F3515F163379586
+:109EB0001770C87752BF11CA1DD46F84723BF51B4F
+:109EC000A1DCDA4D859DCA537F7733C2FF0D9AAE70
+:109ED0008473B264AAB111E2A25F3EB1893EDA0D89
+:109EE00038CC866EFD1D10271F01F84A44C71200AA
+:109EF000E6E7292F89FFDE0E719711BF5DFF9FDB1B
+:109F0000B1FE042CF4425C7F24C4DA8F89C10EA810
+:109F1000BFBB81F0F8B9A9DC94E7FF9F11BD287F92
+:109F20006003B1F6BFED81FEFC920DD777401C7542
+:109F300002A67C047CFC0A8367F73774C0B906AAC2
+:109F4000003A5E53FF456CBC792C6E463EB4B60CAD
+:109F50001F7B71FC7570D806347FA8060E8F894C64
+:109F6000E5A6893EDA5DCDF1AEB01F2225D87EC7C9
+:109F7000E347C5D74D997D8DE3517E3D9868BF81FC
+:109F80001EB660DC9F14DEA7DFE971777BA7C717D9
+:109F9000A52D6142F7E1CED12C4CF52E31119668FA
+:109FA0003F55D71EC76D458E6699DD50E1F86F8825
+:109FB0001A8F7F26305E68F35BD298FDD1EE9A4F00
+:109FC0006FC4C47348BFCAD661A5782F8771F2FAEF
+:109FD000215F5B5C57687FB1CBC80D9E49BB8BFE90
+:109FE00057736DC0016B6D3593761CF063E96C0798
+:109FF000ACB6343960AF7699A3FDF9CED7E52E3AE9
+:10A00000749B7F1CAE75C195CB9FA4F3FDCE627689
+:10A01000E404CCF7E572F0D9F94E98F5EB231FAEC6
+:10A0200062760EB3673E4E781D371E469E1E16A101
+:10A030001E83758F406C3B37DB3CB5FF3EE50B184C
+:10A040008F33FB24E2BF7A6ABCCEEA4862BCCDEA19
+:10A05000F5697D118CBF61BC6D0B35E87DB4BCDD4D
+:10A060009BB855A2FC7ACB7F518684A1DFE40A8895
+:10A0700053F7B9E20A6E798A3D7A73C1F331BBECCA
+:10A08000EF6671401B96EA0B9FFB6F9164A4E3257A
+:10A090006F620BAC2349234731CE43ED6C11ED6C5D
+:10A0A00013EDC7C3D56BA260C7A44C19FD1C297D55
+:10A0B0003BAE9707DA3CB85E7A241DF1EA5FD97BA4
+:10A0C0006C2EF8A3BA87737A0CED801DABE43A5876
+:10A0D00037616A8FC27949382614DCC7B64BFCFC5D
+:10A0E0009A7CB4247DEEF9F838CF234A3708786E8D
+:10A0F00067853CC8FF94EA413DBABD4D7E1CFC9F7C
+:10A10000ED4B3D37C3FB336DB2472CA1DF06B9FDE4
+:10A11000B415E2A8B0EFA91BB09F33862753497E40
+:10A12000CEE1556B30FEDD2798CA5C3C5FF690832C
+:10A13000C8B71F60FC6FC7A20ECC1FB02416F7DA99
+:10A14000BA20D09529741E2E85F1FD8EC6F6230FF8
+:10A15000015D542F1F44BF6DFCC4C6089C5F6A8B11
+:10A160004774A0DBF4BC01E3ACF4E0FB7463F20AD7
+:10A1700003E2B66D1E87FD915EC9F8B12342908E51
+:10A18000336DA7206909F653F321387F8D2C9DB0DC
+:10A1900087EAF2ECA1706B724522EF1CC1B69F8A70
+:10A1A000ED4FA26C8C59F4BD7AD287FEAB107E9233
+:10A1B0008810A79E2DA2DF7CED82A3088B6382E12D
+:10A1C000D3216E6F9904FD3D93C5F1EB0979983E5B
+:10A1D0000FFE41C4736112E2F636B7AF34FA0FF6E0
+:10A1E0001D9FEE3C079E625F9D7CE324AC2BF164D7
+:10A1F000F0350F94AD89BF21E027BFFD4D8C1F3D89
+:10A20000D07A67A047986A879D59FA4C7A6E013DCB
+:10A210006197C1B1309EF312F1969276B87AF253FB
+:10A220003F3C9A87DFAF24971DCFED3BBB9F62F683
+:10A23000DD5BDD9B7F7894CAF8062F8B17F965F3F9
+:10A24000B7A0374EF1FD330DF93779F2B3C1CBD654
+:10A25000D11FF8FA8619067F1CFC6798DFFEF67599
+:10A2600038EFC5F0A6FAE00F4C1FD87E38B3E77779
+:10A27000B495F63B26F35CCEA21E2896E7F20129A0
+:10A28000217B97E5E927579E8BBD9E075799244A66
+:10A29000E7695B35C9C0F912B9C6241B417E056266
+:10A2A000F41AACFEF872BED5417E14794F16D6C5AD
+:10A2B000195D32E05C3235EBFDD4A12C8EAFE49217
+:10A2C0009F72F3B9C5359F0D5EE77C8A245E0586D3
+:10A2D000492CAED46D02BDA3CA06AC4FEA1FE8F903
+:10A2E000FE8F3D9F64058B8B896A86141A7788EBF5
+:10A2F000F1A4D7BCD40BFB8D377902F4B0B54A4634
+:10A30000FFD85DFFE35EE6BF0D3612C962792DA866
+:10A310000749A769C2B95F4AD0920F6B887E1CCEED
+:10A32000BF4097837FEF8BBE6EC2BA7B5424C9199E
+:10A330006DD45FF63622FF77ACBA8BD9A1EF2582B8
+:10A34000580DF52DDCDFEA4C4DB0EA26F3CD88D66A
+:10A3500013BD314F5FDFE4657A6DF2BD15BDC9F104
+:10A360009ED9EB83216EFF697DD11B4305DA571718
+:10A370003EB77E1FA7F3262FB747AC3ECC83494597
+:10A380006E3804269B74CD607A3D2D4D2D89725B0D
+:10A3900040BE6F02F9F352F9663B15936FDB5E28FE
+:10A3A00036FF6E3BC1AD7F2A3DC78DEDB9B9E438AC
+:10A3B0006EFF7D90E7BB516977F0C9C7D7F942BE00
+:10A3C0005E26EDA934870DE48B0FFC7D3817075905
+:10A3D000C8B3C776733EFA02ECBD1B0FEA676F0184
+:10A3E000B9F385991F8E8B11EC3AC970CCF7047FB5
+:10A3F000F879E8418E4F2C7D358B0B87EC7CB94A80
+:10A40000F547E93C39AA3F1E28A53F4894C5016C91
+:10A41000FAA7E2C9F814E5F33ED430EDF8C42330CE
+:10A420007E09BEED3F1FBE8DF03CBBEE811F1FE1DC
+:10A4300079094EBD7DE93A8C9F15C393CAF5A8B73B
+:10A4400080DE7E17E7E1BBDEDA0B9F07BB5E51FEC5
+:10A45000F37AFE2DA27E9AEEBB8D928576D4B0BEA5
+:10A46000CB427B0E6885FD3EBD08F3CD488CA07EB7
+:10A4700084869037E5D74DE45F801818D793EB9D1D
+:10A48000784A11E77943B4CBCADAFD82FEF66F91C0
+:10A4900071DC89B896CAF2CC6C3B149615F82D3E47
+:10A4A000F2F9638DAC1DEAFD62F44884E90938FED7
+:10A4B000017BA358BEDB24FDCE71A21F8A97D65321
+:10A4C000AEFA4495F4D70B9C234E6D2791D7F3F445
+:10A4D000DB5BB08EF3F213CC27D77761BE1FF11888
+:10A4E00010EFEC8BAE23094AE720617A2505E54A97
+:10A4F000C83F59ACE13985CEFC3F8FC2E4F125AFAE
+:10A50000EE88DF8A2AF3A7ED7AE5E6FF6EBA3F15FB
+:10A51000B28F2E97D97EF1D61792BF87BC066B44B7
+:10A52000D0C10E3EDD9D43FB6A43F65219F2D716A9
+:10A53000CA33B1DE863D8DF2EA7C7B89B0BC018AEC
+:10A54000889CBF3EED7529A77D4780EE536916179D
+:10A550003995FE57CC0B38B54F443BFA54EA832566
+:10A56000D7D369BE8FDBF54EEF134DF453524266DD
+:10A570001E6D7F5A32C305F308A8994EF2F4DC270A
+:10A58000D2A2436EDFBA3F2183FE39DDAD08BFA200
+:10A5900073752BD049F1DF906E9421FE558E2E48B5
+:10A5A00067CFDF376C3AFB55E6D7F5ABCC4FE9D731
+:10A5B000DE447ACFD0E7A5FCA614A7B35F2BAC5F2F
+:10A5C00094103BBF55BC56E1BC0917BD7EDDB94EAA
+:10A5D000DF69FC8655765E3B2CA595F3C127645A4E
+:10A5E00002D8D11AC9A6203F9FB2F165883360888E
+:10A5F000918ABA76F229E19314AF1FAC574D210A24
+:10A60000F057858B28AC513FC81B05FFC373F85525
+:10A61000BA8E86BB8218471E6CDD7418CC84E83D68
+:10A620009FC5D0D33650F6183F7D5F5F7B0B5F67C9
+:10A63000B4F3CF0C76AC8678A544E23CBEE1D125DC
+:10A64000DB5F2BB0BEF3FC65E19C6FB25D313E0574
+:10A650005CFE908FAC2DAD9F36337D66D17FA05FC1
+:10A66000A2AEF6336F71C6C1359207D3F73B65C210
+:10A67000E33537BEABE3CC2247141DCFB13C5A06BD
+:10A68000EA13AB1AF2A742098980DD3EAB39D10E3D
+:10A69000FC2FC7F761C2F2EA08394EF2D7D5DF7254
+:10A6A0003D547FE79705B0A7CF18540A1601AC2C8C
+:10A6B0002A645FD8F95A1370EBCBA80F0729D61874
+:10A6C0003768F5A0DFBBCD38A5E5AFA7EFF1712660
+:10A6D000E79FE8D2723CADC5F9970D8FE95F78FE30
+:10A6E000F32F4F73FEC39B9D76F074E7E5475C0F35
+:10A6F000959BFF0B1DC79EB7A9EB83E9C3FA3B9F50
+:10A70000C57CC5AD2DA5EDA3A9F37604F7B790419F
+:10A71000CC4C81763F9505977DCE4A8524899177EB
+:10A720000E255EBE7C1FE415151B574CB8FC0DDED4
+:10A730004FEE135412F15C442FF33DDCE81E89EE1A
+:10A7400087C12D57ED919640DE9689F95FC3DD26CE
+:10A750003E9F987F9F87E32B108FED5FEB782EBA9B
+:10A760004742BBC243CE2D21C861DD963B02F53A7C
+:10A77000F7480A3EE5F905B4EA4C6847D06E5D0437
+:10A78000C19E5A3CBFC77EA023A827912E06D38620
+:10A79000006FF59A669CEBE53BE97AD8EAE7B0CE24
+:10A7A000E16A0E6B1C6EE430D9857050A630C4E9A6
+:10A7B000BD690DE100871B395CC3E16A0E37715832
+:10A7C000D885F05699F537226558FF010EEB1CAE7F
+:10A7D000E1B0C6E1260E93036C7C1F8303DE0CEB15
+:10A7E0003FC8E1460ECFE0703587E7725838807079
+:10A7F00051BD1C3391BF93F3DFC9F84608F72FE32F
+:10A800002EB86BB27E9EFF39D0AD0BF9E78ADE22FF
+:10A8100071A7C53EA667C6DBE398BF44FD52EB5463
+:10A82000FE792475A00AC52D4DDE6EE23C3D5278BE
+:10A830005DD8EBCEBD2E2AC56FCD79E2F7A1FF2002
+:10A84000FC3EECB3D73DF3C7C7DB0DC4D3DD9FBBE4
+:10A85000DD08D52F24CFFF0F48190BBEDBA0B60FA4
+:10A86000FA355EC599E77AB7CFCBBE5BF1B13CD77D
+:10A870003E8EDF783B3B8F189817C81C10A6C61772
+:10A880003FE763FEFFF76D3C9551F48F8239BA6262
+:10A89000F3FC9DE1584799FC75E9DFF3F314DD7192
+:10A8A0008F7F8577749C805A984F774FE89B5BAC7D
+:10A8B00053B4AEE2A7CFC16FD122D1FAFC7C6AFEBD
+:10A8C0009E081E11F5CB595ACFCE2311B17F3C976C
+:10A8D00020F52CEE25F2FA384E23FB8EC15C0CFBE2
+:10A8E0000C7DDECCC711A6F6EB6E97F5D5B0F9E27C
+:10A8F000F8D8792B22791EFB99C0478A23BFDCCF79
+:10A90000213F59532FFCF985C25EBDC87869763E58
+:10A9100054AEFD135C5EA6C86791797DC467DB29E0
+:10A92000A3269C23D97264CBD7F9CAD105CB096C75
+:10A93000484B8BCB894592B86E247025174D5F5ECE
+:10A940000AC84936BF7EAD52CDCFF90D94178A8F14
+:10A950008472AB317C6A1747B03F01D6389EB7701E
+:10A9600018F840E9BD5CA9E67C60F18C009C3BE6F0
+:10A97000B5A7C421BE02758698DE67F5AE51D83AF8
+:10A980005FD551CFF027BC7F17BEB43F25BF3F91A5
+:10A99000D4BBE49CE1FDD70A9B5F5A9FC55DDCE315
+:10A9A0004B02E22B92B8E5A1ED3EC3EBBBF5975D00
+:10A9B000DECFF11BF690CD2CCF234EF2BFAB0C2A8D
+:10A9C0001EFEDD235B676EFDE405B95A72FE72550B
+:10A9D000A95EAF550AEF3B54CF37437CB6D8BE7360
+:10A9E0004299D80F9AF9BC4D6BDE7F077A68D9E49B
+:10A9F0007C568AEFE57CDCE9E27B7A2ABE15C9D970
+:10AA00009B5C4F548ADF35E789DFCB2EFCDE29B90A
+:10AA10003ECBF7A34AF1FFEBF394877F9CCADF8A12
+:10AA2000D69147991E7F3F739EF8FDD28D5F917539
+:10AA30002B2B8C5F1661F221A904E33395E2D75DDD
+:10AA40001E3FEE8FAFE9376368AFA13FBE5D59D3BC
+:10AA50006F4993F89984E9F5E98EBFA3E2F1DFDF4E
+:10AA60006F4A93E37F5179BF637C89CA0F085BA566
+:10AA7000E33E56E9B8D64D0EBABF96BAC931EEF9E3
+:10AA8000F2FDEB158FFF5107DDCFA73EEAA45B3542
+:10AA9000304FA4D271FFE13CD7FB6F38BE41457304
+:10AAA000EC03C5ECF7B3DCAEFD84A239E4B858FD85
+:10AAB00037B9BDF2BE0AEB9FE6FDCFB5F12953FFD2
+:10AAC0001E8EFF3D15D6FF1DC7676585F87C9FAFBD
+:10AAD000C362FB6780F33D083A32CFAFB9D03CA6E2
+:10AAE0004DBE84E08773CD67BBF1FBC1372545833D
+:10AAF000F377D249D01EF79F0C1DC0DC4C3BCE4CE7
+:10AB00001296C0F430C6B7BC11239AEF5FD87E9777
+:10AB100024C5CD42E76BD57EA6FF04CDE862EB5D90
+:10AB200026F03D47B1FA417FE1F84B1519CF421E9F
+:10AB30002F89F2F3A2B31FD40BC6FFA57802BFAFD3
+:10AB4000D6647200E2CED5EB1CE7F9311B9FA889D1
+:10AB5000F8C81AC347960CB350FE72839FCDABDD85
+:10AB60008FED1F0AD171C2EE7160F80DF8E35D78C8
+:10AB7000DE5F2D239FFA43CEF3F09B793F7FC5E93B
+:10AB8000EBF796CE1BEB98D9AA40FF7DAD2C6EAEAD
+:10AB90001303CF05FBD5D2F71A6CEB66E78123FCD4
+:10ABA000BBD2147C573A1FF2A4A23C3FEA19FC3EE8
+:10ABB000EF4C8BA7E4FD3821C3193F0F363BCFDDA7
+:10ABC000EC78BB5F777EEFE38B3ABFF7F1CE943C36
+:10ABD000F87D91CAF2B1CAE16FE773D9F586A4A4F2
+:10ABE000A215E453C611EFF7459DF8BE7BFC63ED5B
+:10ABF00083DE51AD105EEF14DF8AC51B26E8AD92EF
+:10AC00009319A6371CE7D4DD5CBE7C554A12F4329A
+:10AC1000D5BB45DE07587B358E790A4A34AE633C96
+:10AC20009AEF030AAC873C3E3D68AFCB80C7CE436A
+:10AC3000C6FB5E04DDC4734605D69130B5DDC4BCE9
+:10AC4000DA72FFF66ACC4FB46A155C27823E8EDF5B
+:10AC50007BB9C799EF3777F96939C36FEE86D2FBB5
+:10AC600027315168BDECF4333DAADC10D79526742A
+:10AC700055D1EE71E3F10DBEFE541B7FCBC473EED4
+:10AC80004AF17FAC42FCED7128FE5F013D4BF1FFC4
+:10AC90002A94C5F07F8AEBA31AA2F7E09EAD333D5C
+:10ACA0004BC88D7A7E7C3D1060FDD6703D4548BB1B
+:10ACB00023BFC4CBE9AA949E43B65E2B438F3D2E9F
+:10ACC000A5E7289F8FEF959A8F17383D8100DBB756
+:10ACD000947D719D2E4D7249917939C5F19819E095
+:10ACE0007125AB7D5A72F5A30AE93835392FAFF2D9
+:10ACF00079F965293A4E72B94A8B64E569D84FE70C
+:10AD0000DA790A6B1DF33287F327EDB3E7A5C33178
+:10AD10002FD5D39C97DF5648CF9CC979798BCF4BE1
+:10AD2000AE949CE5D57F9BD7FF13AF8F76E29CC096
+:10AD30001FFBE1BC6CBE3FEE09D44EEE6FB49E1813
+:10AD4000583659EFC1E163763D1FD6EB9CA8A704A6
+:10AD5000F2FA23D66BFD70AE3DC0BF0BF9FE70E872
+:10AD60003DBC5D18DBDDC0E8A1EDAAF2FBFFC6F03B
+:10AD70002B76FF33A05ECFEA3FD9F522F9F5E60442
+:10AD8000FE64D78BC27361DF447F75F9789CF2FF54
+:10AD9000733FCBCF71E5776995E531782309BCE73F
+:10ADA000A18684D290073B28B17B172C6A541F845C
+:10ADB0003C595F224B2AB0BB3C0A6BE7A3F6167CDA
+:10ADC0005F36432387FD3AB82006D907F9AD11094C
+:10ADD000FD813BFD89A5815A8627C8CBC0ABCC1E1F
+:10ADE000EB5197F2380AC36B67F06329E84FA378F9
+:10ADF00041FF0F06C387A1FEAE065907F93ADC7082
+:10AE000017DA893B7B2402EF775E2FA39DB8FBD531
+:10AE100010EEC3039281F9D59629EB6037DE1DF859
+:10AE2000D3894D141EEBA9D284AB911EC4DFF290DE
+:10AE3000781FF6CFECCE2D147FC80BC6AD0BFAED04
+:10AE4000647E0CFDD541FBBB57EB984FA313767F77
+:10AE5000D350AB8CF9483BEB9BDA61BCDDAD0ADA31
+:10AE60001DBB6F68EAC13CEDD600813C801A5517C6
+:10AE700020EF31BC422616C011BD07ECCED0F20047
+:10AE8000E446929A7A365E683EC17BFEBC241D8FF2
+:10AE9000D1329C9231BF77F70D6B593E69AB4FC3EE
+:10AEA000EFBC2CF3E5D872C25295E127FE23017C5A
+:10AEB000BC734402FCB7E7399C9E685FF21C319C6E
+:10AEC000A9B05EB6B27AA19484F74E95AD97AEB0B4
+:10AED0005EA6C27A5956AFECF93DCF9F54E83F8841
+:10AEE000C3F95DE7B760C797FA5E6EBAF9B93B037D
+:10AEF000CEEFE9CAB5B7F372CBD10B879913788A35
+:10AF0000E5EB97FD1E73E65D51F83E6DA8F65E5EBB
+:10AF1000DEC7CA3AFEBC6E4B14EF8BACE3EFEBEE30
+:10AF2000C3FB23DDFDFC0FAE8F9B49BCE43CD4701A
+:10AF3000FC5FA7B8433CBB592A930F10F1B8EC4D06
+:10AF4000A7DE5324AB03D7ED0D2C2FC707CA00D6BD
+:10AF50004D3D5BC75E928CC7309E658617CD9C5C6D
+:10AF60003FDEB61771FDFCA04E24422BCE0FFB8EA8
+:10AF7000D225276EB9F0B9CEF52F544E7EFA2EC9E0
+:10AF800089372556B47EBCE90AEB652AAC97ADAC8F
+:10AF90009E9C122AD22B72BAC27A990AEB6559BDCD
+:10AFA000819532DFD7870720BEE5BD5271C00357B8
+:10AFB000069CEFAF521DF0E032677B79B9B3FDE03C
+:10AFC00072677B79056B6F04F7BCC78A55BE4EFE6E
+:10AFD000CF79AE9366A574FD506B9975A5687E68B0
+:10AFE0005F23E904EE1DA2FB5586EF5B05E33F6B93
+:10AFF000826CFD5F1FD01CF7D3FDA5D3D91C64F86C
+:10B00000DAF496C3D7D6BFFF57E47657913CFB6A74
+:10B01000D03990774DB275D0EFE13BBE550776E55C
+:10B0200023AFADC07B3DFADE67E7CD1898F7239DCF
+:10B03000F8FECDA0C71E49CA04F2711EAD368E5D62
+:10B0400012C1EFC908D8CBD48DC2FB3E1ED92CA1AA
+:10B05000FDD1775BE97B4DBED1CDF284FE8EFBFD49
+:10B060005FE5F7713DC5EFE37AA25BC7F260773326
+:10B07000965FEA36B07CBCBB15CBFDDD26EE1B5FD0
+:10B08000ECEEC4725F771CCBBDDD5D58EEE84E6020
+:10B09000B9BD7B33FF5E2D89E570F7162C87BA2D7D
+:10B0A0002C07BA5358F675A7B19CFD3707862F5960
+:10B0B0008AF99290A156147FE37967DC61E1B301CC
+:10B0C00007DCF23567BCE1B22FCF76CAC5A34D8E3F
+:10B0D000FA97ECB9CCF13EB66DB1E37D53FF950E16
+:10B0E00058BFAFC3015FF4D9BF72B4AF4BAC75BCEE
+:10B0F0009FD5F56167FE57DB06C7FBF0D24F3B607B
+:10B10000B5E54E47FD40EC5E070CF73EE7D7BF3193
+:10B11000D8C4E2819111473D49DDE5A8F7A999E638
+:10B12000FE20C443D361B42F1F3929E03E38E32207
+:10B13000E3359027F25311E5895CCBF2DE673425C5
+:10B14000AF80FBCB88945CF1C150F97BA4ED788F84
+:10B15000186E4DC03EFBD66B820EF6AE10DE323F4F
+:10B16000DF9FB3CBCD67926414E2923CCF4C9B4DF2
+:10B170004C13FC46AA4F08DAD9C9ECFD18B7F4E025
+:10B180007753692181F74E539BD9F8EF1AE4CBBB73
+:10B19000F7DF20DAE5673482EBA0BD4369ECA7ED69
+:10B1A000B72F90F17BBE29F8BABE8B7923C8FCD7A4
+:10B1B000ADF7B378A576C4DFA82C85FB321233C077
+:10B1C00055B5DBA9D997F0DE5335662C87AB01D492
+:10B1D000E60CD9A842BD2CDEBF40EB7F1396FD44A0
+:10B1E000FD4D594BA6CFEB3627E6C2773DDB79FF05
+:10B1F000DB0FFF8C5C42F91A5A7A9CDC8AFECE5E29
+:10B20000E45FA8758CACC95BBFDBDF2EFCBDD12F22
+:10B21000832CAF667B8F85F7CC29D96FE37DA8F6A9
+:10B220003C045B8E9304F4DF368EF7036FBF9F7D83
+:10B230008FB75DF85134CAE9EA71D285F8001DB7BD
+:10B24000523DA7DE9214D6B4B0E773F3FA85F71B2C
+:10B25000E17DC212205FBD127EC9F07C13E5179D0F
+:10B260000775734628C9AF58967D1FD15C845F94DB
+:10B270003FB7A29F3BE8881BDA7CDADE739C2C6F19
+:10B2800001FB9FD59FE02BE5C3AD797C9CE0C7B265
+:10B290009F627E6BC8FA1159A2B276406F88D2B70E
+:10B2A000B100DF29FFB07F9B1FF63821CA2F869798
+:10B2B000657FDF88F775DAF91F767DF8752EE7F977
+:10B2C00087941FDEB1EA8DF03D687B4B02BF131EF1
+:10B2D000503D789FD080FA4CD6C3E519EA4992D9FF
+:10B2E000FB639E67DE2B145A7F4EFB1F32A6F3BF13
+:10B2F0000BEB57D9BD990391327610BF2F58E4F765
+:10B3000005CB52BCB391AD53A3874CC64DA78EBF9E
+:10B310000BE916A3CE7DB57F93733F8B691FC6F8EB
+:10B32000745FA403E16279F976E9CB31BB51E6F8A9
+:10B33000787341768F71CE8F789AB919585E93AB36
+:10B34000C6F2EADC1C7CBF2A5787705B6E2EC257A0
+:10B35000E51AB1BC3277393E5F99BB14E1D6DC12F5
+:10B360002C57E416E1F3E5B9AB105E965B89F0D299
+:10B37000DC6A2C97E4DAB15C9C7B2FBE5F94BB1E29
+:10B380006123F7412C2FCDDD886573EE23F87E7E97
+:10B39000EE66842FC96D44785E6E3DC2B1DC6710E5
+:10B3A0009E9BFB14964DB9FF8A6563EE0E7CAFE75A
+:10B3B0003E8FF0C5B97B10BE28D7877043AE07E13A
+:10B3C000FADC5684E7E486B19C9DDB8D655D6E27D3
+:10B3D000BE9F957B08CB99B92FE1F3EADCE3586A6D
+:10B3E000B9AFF27BA09FC2329CFB2696A1DCD3F8BA
+:10B3F0005ECD7D07E160EEDB5806722F60A9E40E9A
+:10B4000063596E9EDCDF2F8911E7BE7C0D99E190B8
+:10B410008B5539E7BE7CD57893035EF96BE7BEBCEC
+:10B42000626CB1035E76C2B92F2F39DEE178BFE8D6
+:10B4300098735FBE34EBDC97E7673EEC80E7EDDBAB
+:10B44000E0A83F37FD6907DC98BAD351FF62CBB95A
+:10B450002F376C71EECB7392230EB86EF32E47FD2F
+:10B4600059E461877F58DD75C051BFCAFC8AA37E4D
+:10B47000A8F519D7B94986E979E339C773A5F94819
+:10B48000C1F395D89EEB3D6F803ED13DFC7B7A7E2B
+:10B490004F2BBF0FCD3D9F355C0FCCC831BF28C2AD
+:10B4A000D75D2DACBBBC7C266A3F3436417E08B7E5
+:10B4B0001F6634E94F1FA5F05B4DB2D14361DB7EBF
+:10B4C000B0EB97FD7B14FC3B7D1F7CA7AFA3FD80F9
+:10B4D000F7B7DF7D4AC07B1E6AE6107EFEDFD90922
+:10B4E000FB5A0A6C69767F0EDEE7936AE0EFC9FAD1
+:10B4F000EBF07D23835FD876EF1A88A3A6BC76FB9A
+:10B50000AF5E07718B949FC12F6F5B3F08EF6BAAF3
+:10B510001275B09FEE2D726EF973957DBFAEAAE6DF
+:10B520004B6AEDE4FDD1BF8824FE37C0B729898B73
+:10B53000E12A6EB8BF1EEE67BE56327F00CF3F20B5
+:10B54000993F54715F70FA05EB20A7B516FFAEC4A2
+:10B550002B2ADA4F87703FAA79EF36FCFE3315A20B
+:10B56000F8A8C5F139A68A13FB0DB1F79B268C9379
+:10B57000A29D37D840F0BEF85475DC82FBFBACEFDF
+:10B5800029E4A00174A7591212CF3B4C5DAADB72CB
+:10B59000E1D89FE09EBF0DF47D30A1EA6087A9E469
+:10B5A00038E65584C938961AD104C73DDA36FD0D00
+:10B5B0008C7ECA9771A04B26E6A1317EDECEEFA528
+:10B5C000FE17CE9737D565C5F9F21EF13EA2D1F12F
+:10B5D000F7533B11F6C5FD5081D2F17494FA9D02E8
+:10B5E000E09988B760BFEC7E08FB7E38E9E4B7F1EC
+:10B5F000DE063B8E23896D9DB83DB730BBAF93FE11
+:10B6000003BBAF36EEB423DDDF9948AEB8CE74E3AA
+:10B61000385521771C47C573E2335D1EBC57B158BE
+:10B620003F763CE7E9AED2FEDCD7F97AFA1ABF17CB
+:10B63000E42BFC1CF7497E8EFBB7E0CFD1F2CBE0C8
+:10B64000CFD1F200F873B4CC803F47CBC7C09FCBBB
+:10B65000FB6EE4B122F7BC5C526DE72B6C41BB3D45
+:10B66000C8EFD9206414ED7409EC742A574F1FED0C
+:10B670009D19A37CA7BE06D2B7F9FA0EFC8E9F0EC9
+:10B6800061C077FEB7BFF1FACCFF1281AF6FD9F777
+:10B69000C3B43EE6494A2DEEEF48CA8C2399A81759
+:10B6A00082D41F481BC5F933ED7E1513AF6C9B7E0A
+:10B6B000BFEC3E9FC975D389F924414EB78F7C07F3
+:10B6C000C739C3FD1922D6FF2FCC8FBA4222A5BE9F
+:10B6D0000F9C32CE34E5EFE365E40FEECA44BB3392
+:10B6E000C9E663E173C7EA0ADD0B61CB61CF6B3E4C
+:10B6F0008CAB0E7D8FFD1D8AA30DF21C885F8C1E06
+:10B700007EB111BF5FE4F2D877D4997F509F244275
+:10B710007EBF0F75B338445F84F5ABAB2C6FC14D62
+:10B720008FFD5D53AA4C3EC3837CDCAF07CDFB424B
+:10B73000A80FB378EFE3C2E7948F00BE8FDEA114A9
+:10B74000E4F3D78389FE50ED543CF3DBE33D14C5AD
+:10B75000DB6F0B2D2BDEBEE519E517A474FB3DA5B1
+:10B76000DA5FF615E59132F83F5A187F6B3FB4ABBC
+:10B770008FB2BF4BD653F7FA81AD14DE7B07F38748
+:10B780008FDEBC0EFFAEC3402D9BB702FD3E510ABB
+:10B79000AF85CF757595C1EB1BA5F9DAD55586AF89
+:10B7A0007F5FAA7DCB335D27CAF0F5BBA5F9DAB57B
+:10B7B000AF0CFEFFB3707BEB62D03BF53A8BC7F565
+:10B7C0003452BE523C866CBEBAD643817E5F2E2771
+:10B7D0006F65F0FA79E979292BAFA74AF3B5ACBCCC
+:10B7E000FEE602E5F5CD227CDD0F785F80BCBE7DF4
+:10B7F00081F2EA0D5F98BC86C225F5405979AD2DDE
+:10B80000D5BE02796D2884BF8F044DB0A7CFB4B0E8
+:10B8100073AFCDED1EF6F79134A6EF8327AFC37D4E
+:10B82000B49FEE53335A61BF3EB5F7F6A593FBB311
+:10B830007BFF71F7E7DE3F6FFF973544A5F022BE2F
+:10B84000EFD9F80462EE7E4ADF2F31DD7125FE77F5
+:10B8500096ECF6B337BDD3E339F777E9281B9FD0D1
+:10B86000F157E33921BB3FB7AAD51D979CEEB8A588
+:10B87000EB476FB9307B607DD8793FD49C2DDFDCFE
+:10B880007F3AEFDEB039FC3B2F2FF910DECF446E4C
+:10B8900063F940E296A7F79F5E92774F141915F26D
+:10B8A000F37FC4DB46F79FCEA33B07711F8C1F5B62
+:10B8B000989718D3AEC4FDBDDC3EFE28DFEF1FE62F
+:10B8C000F6EC3E7E3EB1979F4FA4B93DFB003F9FF3
+:10B8D000D8C6EDD9117E3E91E2E71303FC7CE279F4
+:10B8E0007EBEF05CF73E7C7FA83B83E5B7BA9FC481
+:10B8F000F2D9EE517CFF4CF7218447BBB3CC2EBE6E
+:10B90000E756CC839DA4C3E474DC8BF7BCF4D797D3
+:10B91000B6CB1B92CE78C89CCD01D73981F39C62FF
+:10B920005697332FB2DA74C643AA5A2F73DD47EF06
+:10B930003CA708365FE9BA8FDE190F9123CE78C88D
+:10B9400015879CF19005A3CE738ACB9F749E535CA0
+:10B950009A71C643E6EF739E53CC4BDFEBA83F379B
+:10B96000D5EB8C9F58CE78C8AA71E7F9C455BF7E35
+:10B97000D819FF1973C643569C70C643961D7FC6DF
+:10B98000012F39E68C837C2098C8823E5C9475C771
+:10B990004332A84F7FA2B2F33DDBCFA6F55F0CA3E5
+:10B9A000BFA966AFA2EBBE6F33BBD7BD8F687E0D5C
+:10B9B000F5F067D16FF04EDCCF1CCFDE1F99D43F7E
+:10B9C0003BAF3DF553F06BBC21764FE5EDC27559A9
+:10B9D00092EFF778DF12F2CF23A588534F94ED5FF3
+:10B9E00062F7107AC12FD18ACBDDD47EDD7EC9B556
+:10B9F00059C893F2025E06EA1B1C27CF2F1946BFD7
+:10BA00006496444AF9A753C699A61E7AD3A58726F9
+:10BA1000FC9228BB2F4597482FE0B1F7A8A7E0BDBF
+:10BA2000BFB61EDA192DBD0EED3C979D5D95E56301
+:10BA3000EF3C5ABA9E1DBFD2F97DEC5EADF0B9F76E
+:10BA40008B619657F9C12AC2FDE6FF2F3FEFA4FC98
+:10BA50005C59F59F467E78FC72E3107CCF24BB6076
+:10BA600091C3E1AA4FAF81EF9BB610760E445E61A1
+:10BA7000F7AE961B27D6F6D1CAEEF5D398BCC65AB8
+:10BA80005761FE24DE33562A2EE1BA57CDAB5AF069
+:10BA900047F726FEFEA3BBFECF6B58FC28D6F5B1B8
+:10BAA00092F6CD41BEFF7F89EFFF31B3F4BDBB8F6E
+:10BAB00071FC5F787516DAB57B6F637A5BEAFA879B
+:10BAC000C3609F8D72F9F791CFF85B80AEDB2402E3
+:10BAD000E7C373419669FD8B55928173D02DC440A5
+:10BAE000B9A63F3C5FB6FB176F73DA5B7FB0F91402
+:10BAF0002FCD57FB9E4CF7731FF94E3BF25727C9CA
+:10BB000087ABE15AF52FC4FD149E534B10AFD41EE2
+:10BB100003ED2E99E2A11558A76E7CECF5697F4FD5
+:10BB20002A6DBADA82F673043BEE1434204FE78CA8
+:10BB3000AA96BCFF6D4ABFD35C8F5F9BB21E6FE8B5
+:10BB4000FD4964F2FE2BB285FE964FDEEF596C3D47
+:10BB5000DAF00BAF0EE1772D29D5BE1FD0BE4F8B8B
+:10BB6000948C9B6EE57C1FE6F92D5B5B3A7A5F87D0
+:10BB70007353BA5EF2DB05173C8B71C77EED19BCBF
+:10BB8000C7689BC1BED756171D55C01EE8D78EE0AB
+:10BB90007D71C1FA7427DC3718A472043AD03F6F64
+:10BBA0000F7FBF0BDFABF599149C7FA8F09ED235B9
+:10BBB000D2FCCA61F89C3B50FDE6E10EA85F3F7ADB
+:10BBC0000CDEFB3582ED2575F47807C8D966827FD7
+:10BBD0006FCBE2F72A356435CC5BB858653049D075
+:10BBE000F73ABED756537876177B6FA819F4D74823
+:10BBF0003331597B8A1F85A347359CDF996A3A8E7A
+:10BC0000FD4758FB99C6B326E0311C637FCF47ED53
+:10BC1000228F031F16A90C6FF8CE8C8DC3E988B153
+:10BC200071BC6A26DD017AA6DEC693C210378DB0DC
+:10BC30007164957D0F49C7C7FBA67C2ADB0727F4F3
+:10BC40004E5718C73B13218F97FA7B01F67A7F9CDA
+:10BC5000DBF9FBB99D2F2973BE783AEF3E867EFE55
+:10BC6000F7421B55E777987FAC62EBF1C51A9667F0
+:10BC700056EE1E49F259763EFDFF00D7C62C0E0047
+:10BC8000800000001F8B080000000000000BC53D75
+:10BC90000B7854D59967EEDC796526E126992493D3
+:10BCA000D7E426241021E0000141B19D445454D42E
+:10BCB00088B6069F43409E01026A89169B9B172403
+:10BCC00021C0A02E445E99605154D0C18252ABEE87
+:10BCD0008029C5D6B6A9F54195DA08181501532A69
+:10BCE000CAEEEABAFFFF9F7B93B9934982B5BB9B2B
+:10BCF000EFD3C3B9E7FDBFCF7FFE738631C6BECD9C
+:10BD000081FFCD8B61212BA33FCAFB1258283F2C0A
+:10BD10005F9AA6CF7B72F4F98211FA7CEE587D7F90
+:10BD2000CE4B75E55F5DCF58870332A2D7CA0A2094
+:10BD300039F2A0B52496B1BA8C1A2B83EFE7EFD174
+:10BD4000CA991DF3B9528CC09C8CB5960A81260302
+:10BD500063C115350D79858CADCC10189321754DC7
+:10BD60001FE2837ADFE2DF0FFBA6DBAB180B0D6768
+:10BD7000ACA9CA4F6963550B0B59185B953170BB61
+:10BD800000B6837ADBAAAC946EA992A8FDA62A1706
+:10BD9000E55BAA644A3754E553EAAFF2505A573587
+:10BDA00091EAADADF252DA5C3595D2BD552554FE1F
+:10BDB0007C5529E583553E4A9FAD9A47DF77555517
+:10BDC00050FEE9AA4ACAAF1E23DD5E02F0D959A58A
+:10BDD00050FE89AA064AAB2558F77828BFD2E3C29D
+:10BDE000F2DA2B596930CA3AAA2503D55B23012C14
+:10BDF0009318B3318F6006B831C8EF00B80D553CC9
+:10BE00003516C827DFC1088E432B3C356680B33416
+:10BE100085E7D7E138D0AE92312FC376B92CB02365
+:10BE20009BB19C06F69601F2AE7CA9CD98DD3BDE77
+:10BE3000F5EA7850EE12A89C05B0FCB8D97B839443
+:10BE400084FD312A1F16EA1400DDECE2B742350EFC
+:10BE50001867D41B811A23E4474E56044C630BFD2C
+:10BE600082AF00F12A14E338E75608D48F5CC80487
+:10BE700001E61774713A585D04F0095BB7EDFC36C2
+:10BE8000161AC758C38AE943D800784D29157AE9AC
+:10BE900011FE8BF786D13FFCD710120E1A619C73EE
+:10BEA000406F2CBBFF7E2EDEAFEF675430A29FD2D7
+:10BEB00081E73172A7BEFD458188F640D7C81FFDD6
+:10BEC000B51F76FE065A6F7F747CCA5C56258DEFCF
+:10BED000CD8BE77FC042898CBDED90080F09D73527
+:10BEE000BB10CEF03705D72B6630822BA03B540613
+:10BEF0007913FCAB09AA8A0592978DC65456538FC5
+:10BF000097C561EA55F325947FDDE45B83781625B8
+:10BF10001FC3F920D9205FAFBE08FE9986F9AC0691
+:10BF2000EF64C8FF08FE792963374A23A62A90FFE9
+:10BF3000CAE4132A61BC3DD942603BC07B79CE582C
+:10BF40009203B58E81F9B34EE5CF9EF549255E0388
+:10BF5000F4935E2E8D453AEAAFDDA3E5CFBF3E0CEC
+:10BF6000EA294EC19327F72DDFA5D2F1A325C214EC
+:10BF700007C22193D3B1B69EC8FAB0EE5DB86E93F6
+:10BF800093AF3BE996124A73775D632D1905EB8BEE
+:10BF90001F980EB644AC2303060A46C1FB499C1702
+:10BFA0008C93FBC67C1BF53B63E07E1B55B9773E4B
+:10BFB00020B00EC4B35841F236E9161FCB85753553
+:10BFC000A40A0107ACABE19B7B1BB2111E070492D4
+:10BFD0000B49B754305F41DF71C5DCEE6A01E9F20D
+:10BFE000C07C26C3F8165705530A30AFC96B9F01B2
+:10BFF000E7932C495750CA025EEC3F79854FC171D7
+:10C00000CD2E3FC1A521B5A7BE0DBF6F080924DF06
+:10C0100057CAC06F064A9903F9BE82513E23F561A3
+:10C020001A977D0DF39900FDE0BF01C1960CBF1773
+:10C03000E541C345CC8372C496CF8ACCD928A60EDD
+:10C040001B50AED91E609E269C6FEA130ACA23E5D8
+:10C050007246F80605C7107E30BEF526C0677ACB5B
+:10C0600068E20B5B6EC880EBBEDDECEB427C6AEBFA
+:10C0700037BB3A091E0DDF184BA3E1E537AA9CCC6C
+:10C0800044BC45C1476C3C97D75F9982D7A01CDD63
+:10C090009324B0ED86BEF52C6ABDCDCEE97F94E544
+:10C0A0005EFED4CADFC64586F173FA7933CD3BF71D
+:10C0B000963B87E07AFAA383552A7DAD1BC2F540F3
+:10C0C000EEE43BBD08EF73F05F5394792C182253D4
+:10C0D000BD9EF53B059D5CBAF0F989249F724F35F2
+:10C0E000927EFF2A7B607A6D50E7F955A6DE3E10FE
+:10C0F000725B08CFAB5C804F19ED0481C5011C5BFE
+:10C1000055FA804F84DF20E8A726C07FEB8AB3B6BC
+:10C1100002C867BC6D4432017A98A7A01EB15DC405
+:10C12000E941923BBD0CEC9098FC6EA2C78C8A4E04
+:10C1300003A680F7BCF8F1480F1374F47046D59F3E
+:10C14000F057E79AA08A3299F8BE201EBE7B77C1CD
+:10C15000249CC80F7C7C13F32A669217952C08E365
+:10C16000DADF32D2779861E8A142945382A7C903FB
+:10C1700074D05E938C7C684FE2F265DE35C524BFD7
+:10C1800000049E4D30E6E24FBB929740DEE3E27240
+:10C1900019EA5B719E628159A737061D47F48670C4
+:10C1A000FD7603F3F83DFDC3FF3BF76BF532948F4B
+:10C1B000DFBD5F10A4C968DE7138323655C175DB4A
+:10C1C000D5755BD8AF689C73380EC2DE98F13B849E
+:10C1D000AF78B1C88C51E8B5DF718C770CA83F2AD5
+:10C1E0008FCEFF637B58FDD9F1B1CE2E9804BB846E
+:10C1F0005DF22D128ED12120BFA21D40F607F20064
+:10C20000CCA3BE82E363F44B8753C3E9FFABAA79A7
+:10C210007F6C07A5B947D5FBD51F5A8AB1FDAA5F28
+:10C220000B010BB46FCF34A777C2F7E08143D93845
+:10C230002F4D3ED7B6EBF57C46053384F7FB98CA05
+:10C2400017B54EDEAFECF058A3F1FB5AB55E836331
+:10C2500060BB61A33AEEB3766F753CD175C880FCC4
+:10C2600039FA25EBED38DF2D4BAD51E1FCACDDD7D4
+:10C27000189FD4779EE1ED118F03B45F3F50FB828E
+:10C28000E7ADEFB381DB3F163FBEFFF6239EB66EF0
+:10C290001E64FE6DD1C7575AB15D86CBCC90CEAB34
+:10C2A00053BBB6AF86FC86A5668F05E8B37DC68F07
+:10C2B0005D88B7FA248EB728FDEE1A685EA35F2A60
+:10C2C0002D1D645E7B076B3F085C5F1E18AEA547A3
+:10C2D00006816BFB40ED473C5DDA32C8FCDF883EEF
+:10C2E0007F250BE54E866C263D539D0D704539AE7E
+:10C2F000C135821FA2F4FBEEC07019945EFFF63DBB
+:10C30000E9F5E381C6BF007AFD7C60B80E4AAF5FF5
+:10C31000F547AF38EFEF41AF42C2807019945E63CA
+:10C3200012BE1FBD260CD4FE02E8356DA0F95F00D9
+:10C33000BDE6441BDFC2EC5E05EDA202AEC7E71509
+:10C34000095CAF4B5CDEDB8F5E4D7AB40EF454E2D9
+:10C3500044D4D7C7362C2EECD5CF91FA27B2BF489C
+:10C36000FDB9F8EF57919D3B46D57BDA7C6272238D
+:10C37000FBB97D40FBEEBB8E2BBA58C816D7DB3E0F
+:10C380006DF6BF7A3CBD7E17DBF9F80CC6BF6222A2
+:10C39000EAD5691E84F79089669D5DF9DDC71DB8F1
+:10C3A000BEEB8EEF670FCC49007B6064AF3D905EC3
+:10C3B000F98BD61389BDFDA48B254C72A0BD778B5C
+:10C3C00017E9829533CF0E2CAEDCD37A625CAF3D99
+:10C3D00000F037DC14B66F3496075B4F84ADFBFC7E
+:10C3E0006CA6EECF14B27773A54B49BF0FA6C7B5A5
+:10C3F0007DE326F44F0D477F94A4FAA35CAA3F4A3D
+:10C4000056FD50DC3FD58CFE29F2834DE47682EA5E
+:10C410009FAA57FD532FABFEB19754FFD8FEAA0039
+:10C42000A52F54EDA4746F5590CA9FAFDA4FF960F1
+:10C430005588F2DB1E9823233E7BD7E155D7A1F91F
+:10C44000F506B6FB332BF47E90F4797A3F482AFA4E
+:10C4500023C3F229E1FE4886FE9B1C5DF9908923E7
+:10C4600074E5B19EB1BABC3DFF525D7D9B5CACCB27
+:10C470009B9DD7EAF217EF9F1EE1E7B94D573E7239
+:10C480006759841F6781AE7C78CB325D3ECFFFA0B9
+:10C49000AEFED0861A5D79B6D2A42BBFBCFB615D1F
+:10C4A000FEB24F36E9EA4FEADCAE2BBFE4C8D3BA9E
+:10C4B000F2F11DCFEBF2E30EBFA4AB7FA3DDF76B70
+:10C4C000948763420723ECF400C9D310C80ADCFF49
+:10C4D000B857485778A3E0F1BF86F07D2BD8ED45DB
+:10C4E000642F833C6B1A83ED95121BE4D37F0D34CC
+:10C4F00027E396DD676043216DD7CB1F63F977E3B0
+:10C500006BF400607D37FC215FFE97B6AFDD6953A9
+:10C510007E80E3FBB83C56A4008BD64FAD6AFFE6A5
+:10C52000EE9C3184E8532A96A2C985E366DF27E1B1
+:10C530007A4674E8E934D71BCBBC385EB9E637E3FA
+:10C5400072CFC8ABB0F4A3571F36A09FACF4D57818
+:10C550009CC73675DC06955F57229F0EC7F55E16A1
+:10C56000B2A870DB04F29919277B06925391F0FA76
+:10C57000AE72CD90A8976B208F431FA1FC2E17039E
+:10C5800003EDAF347996FBD6DD03E24783AF8647F0
+:10C59000A3245D81F2C196ABB032475F3819654E76
+:10C5A0000FFFDBEB9623D67D8EBD5CE4C5F309E679
+:10C5B000894A273DEB2DBD8BD6A1E133B2DE0E5566
+:10C5C0000E3FAEE2B54D95C342B347403BAC5595E7
+:10C5D000C7C2A3DE1A84731EECA7713F686EAE0853
+:10C5E0005901EFA60C467AD2E804388CEEED77D8E4
+:10C5F000A37ABF4B6EB35E2EE6D425E8E021AF48A8
+:10C60000FB4EFAB42FDF5D46F68D468783F11F920D
+:10C61000FCB743FF99712E8CBFDB672753FF0FAA2E
+:10C62000FC0D1CCD5385BD89F4533651252026DFE2
+:10C63000FA3EC075FE611343FFCE0FBF6E3DB415C9
+:10C64000D6619C6891D0DE014D78E815289FEDB544
+:10C6500096607EFED151663794BF930644E0C2F2E5
+:10C6600092389403A7993015FD77A7D99B71E3C23F
+:10C67000F4EEB244331FB7C174ACD38AC32B748EAB
+:10C68000758F9FE7B575CD6DD1E7E7B0E9C9228C0D
+:10C6900033E751134852189789C73A353800FECB13
+:10C6A0001225EA772EAB58897644BD89917F71D1E6
+:10C6B0008BA3CC683FCF1F27651BC7F4CEE3C144D3
+:10C6C000EE673C09F42687F98B173802662FB43BD6
+:10C6D000BE77DC8F2F63D84F60651AFA3BE3C11E2B
+:10C6E00091FBC27756837E9E83AD2372DE8CD590FC
+:10C6F000BCEF6F1EE24E833710852F1B12B95F5DB2
+:10C70000C363ADF567AD9D304F6FADC86C3F80BC66
+:10C71000C8CF9994A3B1811D28BF8B2B9EEC44BF39
+:10C72000748D45AA8574A3FD67CF61FD4A4018CA80
+:10C73000CB3D8932F7ABDADC013C7F60ACE292E9B9
+:10C74000B1DFBFDF17B0DFA47F7DBFBFEA67BE8B5D
+:10C75000AC9D66E4FF2562C55483807E453EBEC520
+:10C76000E4F3A6A33F717F51289DE9EA355C60BDE3
+:10C77000C3869C0BAA375518A0BF33AA7CFBCDAE4D
+:10C78000C7CD28CF4E3FFDE10DB82F5AF82B23B36C
+:10C7900042BD33BB625988ECBE8019EDBE057B8D6E
+:10C7A000DE00E543136E8E0DE7EB5AEA7FE173B1CD
+:10C7B000B4AF5AF0BC25300DDA2F78E1F86806F2F4
+:10C7C000E04C4DF7A17484DFD306B2A399D239FAB5
+:10C7D00066F8BE4064779744B1833F48E476C7A9C2
+:10C7E0005FDA4B91DE0C3B0FDC45FD066F3559C21D
+:10C7F000F4D8DB8926AD1EF9BD95A70C813C039FBB
+:10C80000DF4DA3C2E757CDEB3DC5FDB90BF69B024B
+:10C81000369CDFCE36B30FEA2DD9F977A2EF2B9EE7
+:10C82000DB1D877058B2DFA8936B0B9FFB66E5A5F5
+:10C8300080E78546D63D8DF4F8D7943FE7B5761B63
+:10C84000490E79E30C20B71693C8827ABFF8F8AA8C
+:10C85000F7A1FCA4CBC86C200A4E767C64FE15E6DA
+:10C860007D8E0A5049D0BF9E0F97EC3C6EC6794929
+:10C8700002EBCE0046FFC117617CC9FAD667ACDB7C
+:10C880008C727649B0F1EF46A0B7257B4FBF877415
+:10C89000B724829F4FE23F52FBEA4BB333525FBE55
+:10C8A0003101FDE66C276C8226F5AF2F35FE5EB8B0
+:10C8B000FBDC3605C63FF5FC67DB144079F97FFFEA
+:10C8C00063DB4F61FEEC559B847269C9D36FC7B1BE
+:10C8D00030F8673BF939D399A79E7C6213C0E1CC4D
+:10C8E0005F2C04B533AF7CEC96D10FBFE73F92F1DC
+:10C8F000DCE9BE57AE4C413ABB6FDF152903ED2B87
+:10C90000906E039670FC0608BFF27E182705B22FC2
+:10C91000AB69045E4EEDF9CA8CE7095F1A5837CA55
+:10C92000DFC5C16FCC78FE70C8CBBA114EAFED3DFC
+:10C930007EE841C89F063C59A2E009D69F2E905E32
+:10C9400001F68174F1DE9B6FBCBC10539347463CEB
+:10C95000B16E92F77DF0FB16E0B7B017BF91E5E737
+:10C96000D8D76684FF925D80CFD18857C0E7E8BEF4
+:10C97000F83C8DFF98D4179F5EA7DEBF7D8E95B7DC
+:10C980006EC2C2BD8984FFFEF0B968DF8F06B4B302
+:10C9900034F930189CE719F8BC1C4E6F893309E94B
+:10C9A000C2AEB8389E03D3A0ECCCEE736E0674F220
+:10C9B00089A9FB2E8443F72B1609CFC916BCF22E8A
+:10C9C000F1DD997D7F3223FEE12FCE3001F2ACE71D
+:10C9D000EF4D06F9C5DC06678B58F755EF1562CAAF
+:10C9E000BA150FE18FF287800F091F819BA6CA2815
+:10C9F0007F0349B4EEC501CE1F8B03076E318CEE69
+:10CA00000BF726A7A0E9AD1EBC1A26223E3FBC0AA2
+:10CA1000E9AF3F7C6AEB9770FD9740F9CFF5FC1BBF
+:10CA2000597F31F02BEE8FFAE03770E00F989E6956
+:10CA3000B38806B085CE9878BC4724DE7BE1CFF57D
+:10CA4000F377B58FEB9C91FB02DE5E83D360FC3EF7
+:10CA5000D8FABE2BFC963965EA37128EA7BE8EAE89
+:10CA60000F02AAFC58CC2AA6A60DEDABCF4456A2C5
+:10CA7000A467F7CE7765D04872FED44EB0C70D7D5F
+:10CA8000E5C5E27ECEE19F75723B66F1FE03A351E0
+:10CA9000AE9D3AF84B952E39DD2FDEF5A15951F5B3
+:10CAA00043205C3EF7733EBC5F9DF79297A3F7B7B8
+:10CAB00064D7DFA3F67752F4DE8AF33FD961620AC6
+:10CAC000747132689C1ACDEEDAEE34E9ECE795B178
+:10CAD000138E0C8176C6B81819D75D5BE37D57417C
+:10CAE0003BE64D139DFF33D1F38905CA6B63636445
+:10CAF000F4E7D5C6CD6172981EAF8B8093E82AA16A
+:10CB0000F355D15952C8F77401DD39B00908227CB8
+:10CB1000DEA07733502F7D30E66313AEF36F1176CE
+:10CB2000E4DF44B63205FAFB9B62F054CBD1F60742
+:10CB3000FAFE7D2B8C4C0EEB7FB1A5FB03F2C7FDFB
+:10CB4000BB8DA15D667CD5664079B2649B89F65D3C
+:10CB50004B601B8570FB78AB2DA0407EE32FAAEEC7
+:10CB600042BDF4F9360B9EBDB2D7F62DEF7A00E543
+:10CB7000D26603437FFAE7BFACFA12F5F2FC2D460A
+:10CB8000DC2AB2B9F6EE27B0FDDCE7D2592DB4FFAE
+:10CB9000CC109C809BD9AEA4D004DC8774ED4EF5FC
+:10CBA00028D4CF8B8BB1DF33CFD9A9DF33FFFE2E53
+:10CBB0008D73E6DF6349AF69F3077B5B0ED7E360F4
+:10CBC0006FCB3D7C40F41A96877116629ED7377CF6
+:10CBD000ABCA3C947F0B3105BA5FB87F8817F791D9
+:10CBE00061F5A89F2596EE9F7868FFADA409B477FC
+:10CBF0000AA5213F2EDCA91FFFBF5579B7C4DC3D34
+:10CC000087D7F7A771BEEDA076F624955ED5F2C85A
+:10CC1000F65A7D5B528EAE9ED67EB1855544E38337
+:10CC200064B5DF853BBF19AEEF4F51BF478EC3BF21
+:10CC3000DF6F600AEA67B6C746F169E5E6D0B0047F
+:10CC4000E0DB17CC6C1EF26F795C68583C8CF72BDC
+:10CC5000556E96C7401EBEA7A9F3C0FA9867D6CEF8
+:10CC60003388D7452FDAE85C65D10BEF7E89F83C35
+:10CC70008530068C9D4AEAF8F2A74007A7B61A99B4
+:10CC800002F6DA224BC8BD19F5D41E0BDB8EFCFD73
+:10CC9000EAEBA4B74E3F6F11C2E3E222D34541A0B5
+:10CCA000066BDF7528C52CBF02E6A3ACF70A6DB88A
+:10CCB0006F386C0C54C3D895A2B7E6395CDF6113AA
+:10CCC000ED33CECE66F9B8AF3CCBD23C0AE15F7E05
+:10CCD0005784F2E5BF35199AA28C6B3A0F4A7F1C34
+:10CCE000F0C1F9EB983C0EE3C08652BADC5C311C13
+:10CCF000E5AE5182C51590FF81EC7693D3C3E64231
+:10CD0000BA3C81F9107ECC716D0F7FFD1150BAECE9
+:10CD1000313905DBFD2089DBD5F393BDD726917E24
+:10CD20007448A43F543A55F6F1797E6588F154630E
+:10CD30005CCEF907EF46F82EFBD02087C79DF4C6DE
+:10CD4000837A28EEAB5294DF950B69BD248F72A5D0
+:10CD50001886703D2B0974BE7076B63C243E4C2E6E
+:10CD6000AFAE92487E3456B9285D5595CF64F26BCC
+:10CD70007B286F54D76F29509811FA419EC63F8B7C
+:10CD8000A3C48B761ECE09E3828C0E1FD111C6354B
+:10CD9000A11CB33A18ED638D0E85CD453FBF83C30B
+:10CDA000C7E82821F898D5BCD8328DE009EDE9FB19
+:10CDB00094645F4512E0D39A31422797CCCEB1BA42
+:10CDC0007C1F7869F8DFFD7F053746706AACB25288
+:10CDD000BAAA6A22C1ABBECA4BF9FF07B86DE470AC
+:10CDE000BB94C75AF4C0AD5897EF176E8F01DF3868
+:10CDF000C3F906E0887CC3623C3BA2AC3F32DD5005
+:10CE0000C528F8E6E1AA164AB5EF09FDE8ED2F932B
+:10CE1000B81D50C97CD5261C47E2FE16E65458C6FC
+:10CE2000845EFF2673294CC63CF22AE2E5480CC119
+:10CE30006ED95F6DE437364A6257B85C5B76BD9C4D
+:10CE400082F2CB58F9383B9E18E6479B566293090D
+:10CE5000AE1E3AAFAC55F5667D0FFEF47CB0BA4A13
+:10CE6000A6748DCA0FEB547E588F78C6B8130F3F47
+:10CE7000DF6C9ECA482FFE1BE4F93E3EC4C2CF9D24
+:10CE8000E23DC19009F04D3252A63444F1C0472C26
+:10CE9000813C68672F605EA48FF8230F90FF1823F2
+:10CEA00074D19F16AFC28DBD9C133F23969667E247
+:10CEB0007A871979EA37A13D1E09D75ACF412BEE5F
+:10CEC000AFFB9B4FD107F30D38DE5733084DCC79BC
+:10CED00047F008C6AB3A9AEDA457933D1559E8DFE1
+:10CEE00063472D449F0E8FCF30370C7FC9FDD87517
+:10CEF00095C9D79C40FAFB086D25C0EBC32D436D47
+:10CF000008E7D5A6A00BE5DDEA78AE3FE45280C283
+:10CF100025BDEDFEA0CAC1B8423DBF6BF2559A3C9B
+:10CF20005647BF9A5C4D98A2A7734DAEEE4FE2F6FE
+:10CF3000DAFCE4922F51AE269EDF427C1849F7B905
+:10CF4000D2A5A53E27EA01E669427B0D6D46B4E312
+:10CF50003E340438BD73FFD4D9CEECED68E7C0AEE3
+:10CF600080E48A82FC4078EA7EED5B68B75B950FCF
+:10CF700035D6E9568A73043A6214B72E1380F1FC51
+:10CF800090A9F1ED9C3F2652AAD1676672B62E5E3B
+:10CF9000D0987B48407CD5831D4171C5B0BF73E0FC
+:10CFA000F9F8814956B4F74493E730CAA9EE5821FD
+:10CFB000887AB3DE31DD8AE74A86F842C2FB97B150
+:10CFC0006559039D7B82DD427E5BC9E161C7701CB0
+:10CFD000C6C86F6B94C632DC27EE7674C4E0BEC55B
+:10CFE000912CE8ECC4F9C9BE9CE4B0FC281C5DC5DA
+:10CFF0001776BB5BED2772BCD1C9AADF324361DE75
+:10D00000B0738B4A8DBE65854D09E3EF9ABCAB5872
+:10D0100067415FBEEE576EEDF87E72AB362B40F87F
+:10D020003245CA0B27C87107A58A0028352A59AB93
+:10D030006F1F4374558C70608EED3D76C80F73A2E0
+:10D04000D0D791112914B7D9A36760D75C407A660D
+:10D05000E3446E8FA87A86EBA7B3CD76D24F67678D
+:10D0600057503CD5D9E61419E9EEC0DACB46233C3B
+:10D07000E69C6F6432CC6FEEF94994CE6B7984D222
+:10D08000B296362072C6AAD7CC5D3B03DA1D7FCCA0
+:10D09000E841BEEE0A8C3B5309F9AE660B9E11B116
+:10D0A000AE2DF766A15FBC0BC641FBAA6B4B1ED130
+:10D0B0005717C08DF20DFAFA182F6C04BC9431A6E4
+:10D0C000C619CA5EAC3FE775635B343BA96C9DC56E
+:10D0D0001BED7CA7A7BC25BADD568BFF4CC5FF55C1
+:10D0E0000C4778157DF04016AE57E3FFE509208F19
+:10D0F000105E1F5858347FFC94E42B17223EA62460
+:10D100007BEFE5784988EA5FEBA57F3EEE7101ECA5
+:10D110005BC28B2FEE269D9F95FB318FABF62FB315
+:10D12000F6531EA7B697A2972F6AFEECD043905BEA
+:10D130005550518244AFEDA745C6F7D38BF7DFA416
+:10D14000C6F9F3F9809D4A74CC001F285F66ABFED8
+:10D150001E80FB8D78AFE4F8EB4603D2472F3DF9F4
+:10D16000E2D06E31ACBEBE663794FFE330DF9FCDB8
+:10D170003FBF9EE49D61F5A88D93E0FBBDAF9B484A
+:10D18000CE57375DB6EE0EC0EF176F18293FEFBCD4
+:10D190008DEA7DFA9067E31D50AFFBF726B2C3BF5F
+:10D1A000387C25C54D7C6AD2FB092E4BE17CBC5FE7
+:10D1B000E5E739E75793FDA195CF69986596894EC4
+:10D1C000D7D2F739786883C1BECAADBF2B12F13C04
+:10D1D00087D1BD85FDC9B75C57437A6D2CD9FB73E8
+:10D1E000D7583CD1E2A8F727CB3AF933B7B399FA2D
+:10D1F0006560173993D5FEC2E4C8DCF389C4074CD7
+:10D200005218C619CF51E549CFFCB69874F2E453D1
+:10D210005B743FC8E164BE8F9A73FE32E2AFBEEB2F
+:10D22000FB017D9FA38DDBC9F9B1773D1B27455BD2
+:10D230004FEF3A2653FD4FE3A38FFFB93A7E57D500
+:10D240003CE605B95466817A0E1CFFDE95130B711E
+:10D250001DF10986B075CD6D59C8BC61EB9ABB65EF
+:10D26000A6B92CACDF5E3C2CFD5D516E2F1E3EDF5F
+:10D27000507E5D0DCAA3E492F7916FCA565F3E1AC5
+:10D28000E9716E4B23C1F9B8C9E346F9FA71CBBD18
+:10D2900071BEA8F394757A6B6E8B8A1FB0770BC33F
+:10D2A000F0A3E125B27DD75FE77EF910CA9FC7B82A
+:10D2B00071D31FBCFAE02D3B3ADC6C291ADCF299E1
+:10D2C0008FE026BF7004E97A8DDD8374DD3FFC4674
+:10D2D00032DF40F0EBC77E057B474849C27119D168
+:10D2E000E9DC164E0783C1AD775C950E8AA2AFE7E5
+:10D2F0001295DFBAAA2A99020C7BCC3C181DFC942B
+:10D3000029D601D6D14307FFA6A3834B52D6101DC1
+:10D310007C82F6CAF0BEF83F6656E22EC5739F26A1
+:10D32000239D2B1D8B51926FE3F931288F8FC5F907
+:10D330006FC0731A2D3F7F475EDCCCB0713F6E002B
+:10D34000384481DF252911FCADD14FAEC20A26FC3D
+:10D35000EFD1CF71F59C38B2DE94E4A2CB52507F6E
+:10D36000F8A3FB6BB55493D7C6218E9E7D26EACFDA
+:10D37000638E9C2F0350DA94ECBB1AFBA98BFFC978
+:10D38000DD280F8E1D3390BEADFEEBF2E1A8D72253
+:10D39000ED04D87F36E0B9E77263AC9FEC50B1A2E0
+:10D3A00095CE411591ED28C47D4AC5A61379E8377D
+:10D3B000ACA494A976E872E3080FEA6123AB781273
+:10D3C000CF49814824AC2FB20A3A3705415882F937
+:10D3D0008D767EEE5A295A254B585CC252955FEAEB
+:10D3E000AB4A1E39817E68ABC2A4F0B843C6EDAF2C
+:10D3F000FFC47986E97BB3C92779701F6A6025C8A5
+:10D400001726D1D7900DFD9B5CCE314A181E96A4ED
+:10D41000F0F3765B7B7B4336B4B7DDF37B89EE1D9F
+:10D42000C138E867B3668867C3FDD5266790EE0903
+:10D43000B1DCB0EF6057390A20AFF303C07C07B00E
+:10D440000B7F65F0B8BE447AACE6F098882082F491
+:10D450002FB387B6A15C9E28D61931EE68C63D79F8
+:10D4600094DF38EBDB619D51E861C6CBAB3AD09ECF
+:10D4700099F172EA2C3C3F98E118F611A6B05DB024
+:10D48000C640FBD70C2CD804E914EBE314D7F89A68
+:10D49000EA1F6BC77C985E6C57E90DEC9CA97B205A
+:10D4A0009D61F59B9616F4FAD322C7DDA0E2A5DDB7
+:10D4B000144C1A817400E3E03AEE7C39F02350FDFD
+:10D4C000EC8E60E0FA51809FBB58B709E1E8631227
+:10D4D0009D7B687EDD32E651F38CF6A7EF979BB615
+:10D4E000239D44F6774788F777673BF407E95D8724
+:10D4F000BB7F8D6AD91794AEB2B3B0FEF67B0ED95E
+:10D5000059DFFE22E1EC11AD46250CAE8022211C34
+:10D51000EE7DE03BA4F45A36BA7F3EEB85379F4759
+:10D52000243EBEC022E0D3408AF77994C35529DE59
+:10D530005F605A6EED768B4037EF3B7D2F221F2EBA
+:10D5400036FAB292011EA7337DC393102E1DD1CFA0
+:10D550005F23F93BB7F4F456E49BBBAA4586785E9B
+:10D56000B9EFE3ADC897A74DC047B01F78ED818FE5
+:10D5700063916E16010386CB930F2AF3C87E3ABBE4
+:10D5800077F880F1A71FA8FE923FAA7CA2ADF36EA8
+:10D59000644018EFEEBD76DACFDC5D69ECD9672127
+:10D5A000BDDF5DC9E34398D831FA169DDD59A79ECA
+:10D5B000B3F5ED07F71191FD7455F95A89EF45DF81
+:10D5C00004B4BB8F57CD6B45F91239CF3C97EF1898
+:10D5D000C2756ECB4C5DDCEDECE6F9ADE17CA8D517
+:10D5E000AFED47BEBE344C5DA7958FC7E48B8B1C57
+:10D5F00013F05E35FFB385AC1F1AC2E861B0F15875
+:10D60000EE146F8F5CA07BF702EC59FBF617594FB5
+:10D61000EBDF5579053B3E0ED7E7FDCF94F183CF85
+:10D62000DFE452E599DA4EFB6EF3F919DA85B6AF0D
+:10D6300087909DF0D230EECFF80FD52E600E582F88
+:10D6400032987FA3F7FF63BD3030C5E7D9B658A243
+:10D65000C615A5B9443ECFE0A1226B94F9F5E92F98
+:10D6600024B20BA9F7D230BE7E749391BF6B580CD5
+:10D67000ED6BCA2A6B699FDD08F203F541E47C8EED
+:10D68000356DA678689BD92FA35FB4715872760D5B
+:10D69000B403A9467E1F5B8C5F16C3BFABFE205B45
+:10D6A0008D5FC6FD6D635E1A7DD7FA6B347039AB42
+:10D6B000F14523ECFB9E27BF98C7351DE0D2F856F5
+:10D6C000606A2CB4DBBE92858C6EC60EBAD346E27D
+:10D6D0003ED75F6FA6F3BDC67C217536E4E332AD5D
+:10D6E000E41F6B8B0FCDC07B078A4124FDEA8F9727
+:10D6F000AF8945FF6E4D4A07CABF834BCDB4DED517
+:10D7000093F8BD35CBA527FC5760FFF7310FEAD55D
+:10D71000EDE77FD182F7FE9423B09F45BF21760AC3
+:10D72000F268FBD4B336DCCFA5605C1DD0D91653AC
+:10D7300090E6B5A9DA42FD6E6A339746C3DFC95455
+:10D7400091EA070C9D141F9CC8823684EBC353A733
+:10D750006FCC8576D9B94CC2FDFCEA82B3DABD72D2
+:10D76000233F8FD2FC88CCA69E6759D5732ADDFD56
+:10D77000B8CDFEBDE43FB44F0BF274AA40FEE7C83B
+:10D7800079DCEBE27E37FBE48EA9A827EC85023337
+:10D79000A07F3397D1BD66692A58E19066E7B37ED2
+:10D7A000DAF3754B5E685FC8DBA34F48BAC0F60B6F
+:10D7B0005D3CCE700DFAA1A03C60F218AE817904F8
+:10D7C000AE970C8ADC5BAFCEC5F56B2BF41F22390C
+:10D7D0001AA075B9F38321A43777B940785A33F189
+:10D7E000189D0B3C5CA8F9513D348F2DD5EF1C40A2
+:10D7F000FB6BCBFD8CECA42D2843A1DD96EB59806F
+:10D800009F27B134946F9BE69BAFA3F3FC0280BFCC
+:10D8100081D2A8F3F6A55A892EDD2B1E0EE13DFE1E
+:10D82000180FA37713208D5ABF2195C369932990B0
+:10D830008AFE91FEE8E256151FEE4AD5AE627E17CB
+:10D84000E275AD0A1F76CB58EE5F10BD72781C579B
+:10D85000AF3EE17E0C581FDDAB4DAC33933E12A6BC
+:10D860008566E0BA12F2CDECEA6CE42F0E376594CF
+:10D87000C0E3CE58A005F9B3EDA2648A275D250464
+:10D880005CE86F568ACD749E7C70A230631E94AFA4
+:10D89000AB33931F02F2C42F7E6F4E1BF29B7D723F
+:10D8A00071E93CC8AF97CC12C2B7B640B2211DD7C0
+:10D8B0007A05C900F9B525DA3D091683781B63346A
+:10D8C000DAF2A1BC3555401F2D6B351888DFEBBD52
+:10D8D000C5FEA1F0BD5E721AC2FD002FB9F8BEAA46
+:10D8E00022ABE42517F28DF761FF5099E3529C407B
+:10D8F00024467FB12C340F636EDAEA9FA0FB546B91
+:10D90000C65819DAF199F7F9E97E57EC456619F12D
+:10D91000BAFD7CE2485A5F9D59467E5E6F085C8383
+:10D920007CBF65E92105FDEAB68F1CCC08F682A311
+:10D93000F3EF55183FE62834479C633101E5B836CC
+:10D94000AEE3AD10D153A7C1F7E758F2FF1434E5A9
+:10D950003BF11E46CC0484E7DA4BDFCB9F13852EC8
+:10D96000C8653B16ED6521346134CA29AEC79828D5
+:10D97000A586E3777D66DA5FD0CFB4AD08E68FE3A6
+:10D980005576DD41F3F2BEF353B4AB1C473FFD26A1
+:10D99000FA3CDF243D127BD41E124663BA681AD9C2
+:10D9A00067E1F540EEAFCDF29E70017C775773B919
+:10D9B000DF7C0FA37729F02F3F0CBECD0520A5E912
+:10D9C0006102803CD62B90C88FBE4A90832184E7A9
+:10D9D000682BD1538A7AEF2172BDF6A38D4B31EEBD
+:10D9E000C8EED1CFF32B15BFF82726D379055AA25D
+:10D9F000CC9C3ADB86F26FCF583915F7DB0FC7475F
+:10DA0000D7F3EFA572F9B0DB10DD3EFF22D5C6FBE0
+:10DA10000759199A40A86214D707792199CE6DF851
+:10DA2000FB0A02970BEC5A467A2F6E4CA7CD1336A1
+:10DA30005E501D87FEA09F216A3B267587AA61FD67
+:10DA40006D40B578AF2D2E93C3D1A1F4C211EB4B2D
+:10DA5000EABA800FAA8717221025AACF4ACC742EC3
+:10DA600002D250F956E88543AC5A7FD344D1608541
+:10DA700079E500300C503F7EAA59778E22D5BDA3A0
+:10DA800060F94F8D4C4E98D83BFED6312C5003E3B5
+:10DA90000FF1EAE11D7BDF0BCBD12E8FA4039C415C
+:10DAA0004FBF182A3E5BDF2EF98E3E7C40F0A479F2
+:10DAB00002689ADF62DBCD0094E69DA2161F4BF24E
+:10DAC00077BCB143417F28C0AA641FCC7FC4536F89
+:10DAD000797741BED9C7F92C36FF85E54897521AA8
+:10DAE000C7D311F42D039C3733E91F18B7A3540A89
+:10DAF00032E2635B2887F47823134B104F8D15EFC8
+:10DB00000828D757EF651E8301E9FFBF2DE1F39B7E
+:10DB100091CACF69982893FC13DDFCFEE8EA02C1A4
+:10DB20008EF2F5E0D21748EF6D3D2030E4FFE2DFE2
+:10DB30001C7DCC8E74FD170BE59B5FAF20B9F113F4
+:10DB400068A744F19F0FA69723EBE72EDA6EC0F388
+:10DB500089AC79417A8F25D12F7AAE467CCCEBF017
+:10DB6000D23DF7427ECEE6981652288F5A0D6C525F
+:10DB7000D9AFA6CDBC9CDD9240FBA85196CE866B5A
+:10DB8000617E9B9F1219EA4BA325983A17FA35BE7E
+:10DB9000E8404DD0677FB4795A2815E5784C058563
+:10DBA00041F7B5E352391FBAA7C9BF1D06FDC64FDD
+:10DBB000E6B0B4F9530EA0BC449B19EF35D915AEAD
+:10DBC000E7D68A012FC679AFBDCF67C6F199BA7F74
+:10DBD000695C54F604C2F91355EFB18A79F48E8961
+:10DBE0005BE5177B252B8AB6CFDAE88AE1F12D0FAA
+:10DBF0000907903FDC5E46FA43AA0C8686AB7A1989
+:10DC0000272EAD78BE11F58BA35CA075AC153BAA91
+:10DC1000F15D89B5F731A95AEEDBDF3FDB7E79AAEA
+:10DC200085E0B1D1C574EBA0F73040BEB9E7455FE0
+:10DC3000C7BFE1B8E37BD711A3AD23BF93F2DA3CB2
+:10DC40005ABDC10B9AC706B53F7F2A7FC7C85EC0C1
+:10DC5000DFEF8894F735F60FE85D9900D8EA46BA09
+:10DC60008F16BC16F3F27302E3F7B5F4FCDD27AFB1
+:10DC7000D255E47799858D938D74C7F10C74A7DA2A
+:10DC80004FC07756140182FC2DF931FC34CF487A0D
+:10DC9000FC5F978BE1F386FE631B9841BDA72A17B3
+:10DCA000A7F6958B4C958B56A68450FEFD5FCB4511
+:10DCB000908324179B61A589B053896D6F5A8A7A26
+:10DCC0005C9387E31127976227D6EB8B0B685F4441
+:10DCD000F909A9BF6FC6F8C855827ADEA5C205DD6D
+:10DCE000500897AF5D728F9EC2EF1BF01F39F89EF0
+:10DCF0004AC2750530DEC6D29C31B8BFB0F95F2488
+:10DD0000FBC05DC0E357DC95FCFCDC9E3BE789F083
+:10DD10007B714B52B99DBE44A3BF4ABF0BC7598B01
+:10DD2000FDA27CCE3593BEDCCC825C1FAAF6E95600
+:10DD3000971A47ACD255249F44CAA771BF7716A340
+:10DD40007C4F355824DCCFA17E3E98ACD7D7482FE6
+:10DD50009ABE6EE9A889477F58B6EAEFCFB6EAE3E4
+:10DD60001C26A4717926A6723FC02AA182F69B4A7E
+:10DD7000B140FB388DFE7AF478041C23E18784BA25
+:10DD80007202C5C7503EAEA89B21FF6E03925D8F05
+:10DD90007A2C5583BB44706EBB53188BF2724F7B49
+:10DDA000990DFDEB06B7F51ADC1FAE3330BAFFB89C
+:10DDB000AEE84D8A2B69AA849E61518E7C61A6795A
+:10DDC000745F3C031FD37ED5AE583AD0AF150C6DAF
+:10DDD000A7B885A6C0A1198CDBB10CE3529AF26BEF
+:10DDE000D216A07CCF2F2944FCB6D59B296E46CAFB
+:10DDF0006751FD0827711F43F3FD6E7ACCAEED2FFE
+:10DE0000CBA3EF2B6F4CE3FBDBA008A20AE69391B8
+:10DE10002F7890FF33EACC51E751ACE2292D8DDF0A
+:10DE20000F6BAB3F44EFCC00BE026C207CC1F46BA7
+:10DE300092C3F031A91F7CB8347C881A3EE2671285
+:10DE40001F7676085CDE925E5BCBA4DB503F2A1522
+:10DE500066B2631B4D7C5FBEBD40E50BC9DA86C46C
+:10DE6000F65DE93A6E9140F7703227F2F7F5ECE58E
+:10DE7000CF535CD366D6FD3ACA3BA580DFA38F6C37
+:10DE80007F679AA0C2513678683FCDF10878A5F92E
+:10DE90006CC94B6E0BE7D38DAA1DBDD1C5F9744B70
+:10DEA000FD06E2D30B9DA726B76B553B7ABED7671D
+:10DEB0004675A0184AAE4A45FDF973FE1E15333A61
+:10DEC000C82EFF049B84F9652B337C4BD2C2FC72B5
+:10DED00092B742C07A57E2BB42D0FEE320BF07FAB6
+:10DEE00071F01745F41E978F1133CF671D066272CC
+:10DEF00090A13B20EF128354EE9A077389A7DB9120
+:10DF000094B75A412FC2844E57F1FB175DF8BEE417
+:10DF1000707C2792BF2FF999FA9EE4A89655C59B6D
+:10DF2000713C59F4A1CC3889EF4BE2FDE789EF5100
+:10DF30005CF42990B54DF1180FC3EF6F4B0F3249C8
+:10DF40009884F935C518F77CEFAB16F59E64470D3C
+:10DF5000DE7B795C60F48EC46A11F4FD502C6A306B
+:10DF60005484D1F1EECB3BE2F09CEF74F0E601FD7E
+:10DF7000C7787F10E7B143A5F7F5F6C574BF6C8E7F
+:10DF800023E4C6F607F63CF9C42618EFB37D567AAB
+:10DF9000D764A37DB11BCB3F7BEC5D37EA8BD3FB12
+:10DFA000DE35473B9F5C2406AFC27B64E5CA105652
+:10DFB00003F32F0ACE3453FCC9AE03743F6D91E4D2
+:10DFC0003363FFE52D7B283F65D79FDC587E348D7A
+:10DFD000F3C7E9549F1BFD12B92D969000FA67779D
+:10DFE0008E7F41D47376951ED7DB5FA5FE37DA5F4F
+:10DFF0003D847839FD9885FC6E071EFB0DF57B6A24
+:10E00000DF8B34DFCF76BF7B17DAD3E58C79509E78
+:10E010009FB6A97E3D6B475CF8FEF615151E5AFEAD
+:10E0200074ACBA0FCE18A49E7A1EC31C007FBA3FF0
+:10E03000D01187F70B3F33F9CC088F85080F488B39
+:10E04000000E28F717060D34CF852D6D74DF6AE1B9
+:10E050005EEE1F5C08F022B8B41CA0F9BF8F7019E7
+:10E060008FEBF8B39BDE75D86BA1FDB3B6EE850ED2
+:10E070009F1BE1A3AD17E0C0D7BDFBC2F03447C37F
+:10E0800053CB9F685EE57BF9BCCA77F179CCD90B9D
+:10E090007872209E6612FE4FED6332DE83E9DAF37A
+:10E0A000EE49B4674EEFB3CA685768F3CA00711BF4
+:10E0B0003716F988EB63B6D740FA98891D749EB37A
+:10E0C0004892247C9FA0A73C600E7079DA519C0E88
+:10E0D000E5CF3C0AF62142420A8E40FFEAE934EDE0
+:10E0E000FE4F871BFD62BB2FF7137D7E1AABC25B11
+:10E0F000EC7063FCCC8674DFE9B4B07882D31FBEC9
+:10E100003802D7BDDC58F19B4C1CE7491E1FFA555D
+:10E110004EC5DF1EA2790FD59D3746A600B7383C05
+:10E12000FFCE17988FEE25EF7D2D26FC1C5A48E771
+:10E130007EB78DF60FE83EE2697CE791E613A438DE
+:10E14000AD61DE32379EF37DCA1C3E3C97FDECE7A5
+:10E15000AF51BC4D57AAE67FEAA07AA7F6BE9680DB
+:10E1600069991A0FCF0237931C03383658C7469364
+:10E170008FEAFDA200BF3776C6000213F5C4560D24
+:10E18000CE15E6E9BA731D2E4733B664B793BF25A3
+:10E1900010FDBE59A4FCCD7D74129D2B9F63D1CF81
+:10E1A00095991A27B7DC1843F1371BED3FA3FBB74E
+:10E1B000958A45C2FB2BC754B97842BD97FF554C91
+:10E1C0009C2200DDEC4FF7E5A48FEF7B0FB76CF5D9
+:10E1D0002237C2B70CCF3D28CEA0ED7A8C27EC4A6F
+:10E1E00062AADDC942043F9356BE9197C7F3FCA4CF
+:10E1F000CDC135F81E26C297D77F829767F3F21FED
+:10E20000A9E573D24AC6A473FF0EBDAFC19829BE5B
+:10E21000CBCA55783478F4C245645D9A5D0D95E7B4
+:10E22000E1E5DC24EAEF32EA4F84FE467DFFFE00A2
+:10E23000EF8A35E15FD08FF55FD54F90F492E0C360
+:10E24000B7AEE09B87EBBFC78B99D414FFFDFBFFF4
+:10E2500067DB2F377A854F910E870844F71A5F776F
+:10E260003D367C0CEEFFCD0D4B43A836BB628BCD0B
+:10E27000A9F0FD9CCCCF4FEE79743D8B164FA2BD1B
+:10E280009BD19357CFF1CC43F5E7B3ABD3B9DE596C
+:10E290009DDEEB7FC373393CAEA28D33FC35275333
+:10E2A000280CB7D3598580F187F9ED567ACFF7223C
+:10E2B000068202E63F928504D4DFA35827E52F4665
+:10E2C000100CC5F7A8647A38731CEB768B43F1FC0D
+:10E2D00039B412EDB4F79DBEC67418EFCBC73A3E01
+:10E2E0003040F94FD27C2F75A25F289DDB570EF589
+:10E2F0007D5C0953A043C13ECD154DEEF7C05312CE
+:10E300004F859FB7DD287A1F49A7F564485DF65E03
+:10E31000386BF26081FAFE92D6FEE4534FE2563734
+:10E32000ECBD70EF80F781E754CE7FF4E7E3062879
+:10E3300057E5ECEEEAC06DE1FAFEC974AE679F4E98
+:10E34000177476218C4A76DCD33771FB69F7E5DEEA
+:10E350009AC751DEB618693FFD69CB9FE9FDC773C7
+:10E36000258CECBAFEC6FD3402EF9FEE78328D9F0D
+:10E370007704F4F1CB4FFC724478BC258059764E7B
+:10E38000E0EF7010DE0F79148B91EE39923FC6CC1E
+:10E390002A789C0ACE17D218DC8F0E453C75501A8D
+:10E3A000C7BA29959844FEE904E6A1D4C94A284D84
+:10E3B0006615066EDFF9294D63414A33D03E457F2D
+:10E3C0000FEBA654C61B9F61F11B3978623A14DF2C
+:10E3D0005D2DE1DF23E28344C4E3B828F23C222E22
+:10E3E00048DC5949F21CE382F29C7DDF53D0E4F70C
+:10E3F00086F4E2F7906EF6A77BDFC7F4F0B3BFE5D3
+:10E40000F72BD618C8BE3E6E9B66960175CF247852
+:10E41000E91D104560253B40BFCFD6FCFFF8A7C5DE
+:10E420000923309B4DA7C2E37798D5918FE7C5B3F9
+:10E43000D4AAB3D4739059AA1F248631F59E9E871F
+:10E44000EEDBCF52CF1F6645F85F98DFA2F3A3281B
+:10E45000F80F58C72CBF81CE0D66C54C7BB593F520
+:10E460004F2761FDD1BDBFB2083FD4A0FEAC88FCF0
+:10E47000ECC8F65603B326E3774E4FCFFC4026BBDD
+:10E480004EF36701C1C9D4AEC1F221F985FC577AB8
+:10E49000C3E19490C1F9C4E6BF3A2EDA3BD95A3AA7
+:10E4A0001BEC335342DFF6B0238C47BED7E4B046B3
+:10E4B000E7D9B8B1453ECA3707068A4B5DADEAFBDE
+:10E4C000A687FC0CE76D0B3D40EF54DF9FA990AF92
+:10E4D000D65A10A0FB0131F9019712657E4DF8BEA6
+:10E4E00033F05753ACFEDC64A9BAAEA519DC7F7BD0
+:10E4F000E8A2E4623CCF5E250B746F7895BC8CCEAD
+:10E500005907FB3D815AF57704B4FCCAC46D0CED84
+:10E5100036DBD7AD0CED499B18FD5ECA0C75FCF5DA
+:10E520006AFD8D89DBC84FD290C7CFF723EB1FC898
+:10E53000DBE042FBBB311BF6BB983EA450FFF579F4
+:10E540001B4AB1BD35D4A8BBCFEBCBE0F6AD752FE0
+:10E55000A74763AE399083F420FA29BE40ABD7D8E1
+:10E56000CF79D2F56AFB265380EEC934A9F6D0D212
+:10E570002DB16BC92F97B1FD08BD6F95CBE8BCD10C
+:10E58000167A8ACE11ACF9666683BC55F6337C5F89
+:10E59000C3561024FCA0B329A4A3DB98DE77368CE5
+:10E5A0007DFBAFFBD6EFC2F53566FB69FCC1D65BE0
+:10E5B000ACC2B351D5AF8D36FD39DAC20CAE57AF10
+:10E5C000CDE0F2DEFA32237932005CC8DEBB3E23B6
+:10E5D000EF06B4EFACFB0785A3AE7E362B1D128D84
+:10E5E0005F22E5BFA340887847C940F33AB7D7A078
+:10E5F000BEBBC8DFB1E8B5038266ECF7D75BCA0ED5
+:10E600005E03F359E07378317EF2C92DDBE99EFE9B
+:10E61000C2174D149F30AC732697832DFC3D46EDF9
+:10E620007DA38B5A2CBAF7A416B1B0F71A61BC853A
+:10E63000473F3DCAE89EB1FEBBF66EC06AFC10259E
+:10E640004E2DF2DD81473222DF5D56DF1D2888EE38
+:10E65000A7897C7760575020BDB10CE358691FB083
+:10E66000AD18F73D95470DE437E8CB87F2D65C53FC
+:10E6700058DEE0217A546263BC3BA2F0D37B999CC4
+:10E680005E76E3A11AD9FD3F5B1BC237BB581DC3A1
+:10E69000F3A6DAFB4409CFB56B033174BFA456125D
+:10E6A00002183792195B6C45FF238B1724BC8776C1
+:10E6B000957132DD7B32DF2F8EA3775AB72FE8C0FA
+:10E6C0007B75B52E91211F67C6F33802962AD0FBC1
+:10E6D0003475D29BF1B3701FE7E0F7F4B2241690C3
+:10E6E0000D68D779199E2FC366A52204A657A6C127
+:10E6F0001BC2F7AED8248BB483BF3373C39809E42D
+:10E7000007A6BF036D57855EC171BCD612C4FF94C6
+:10E71000FB9D640F065C467CDB947D9CC1CF05CDE0
+:10E72000B1C5A1BFE2FC66D8C9B71B508404C4C3FD
+:10E73000EB6D2BA75F0DDF4D0191E21DF2BFA9BD6F
+:10E74000ED6A68DFDD66A6FB161A9CE43A51F77E97
+:10E75000837B853E6F8E78AF426461E5903FA2CEA9
+:10E7600083B152160A8FE3757AF9A1BBE4A0F729A9
+:10E770003E02FEA4F30F35FF9E9ADF69F213DE77A7
+:10E78000FED540FED5836D73B2485EDA17B7DA71F5
+:10E790005F78849F63F6279F7766C8DA3B0936F572
+:10E7A0009D0A1BFABD22E9A9AE8A7930CED01A683B
+:10E7B0008F1989F83D6CF2605873BD2A1F45079781
+:10E7C000E31ADD44A6F511F4576FF2E4FBA17EFDD8
+:10E7D000374675DF78FA86D0640C7B90695F6DCA26
+:10E7E000601E640F93B3234D82798C7CD1ECC1DF22
+:10E7F00055B8EAB9822128E747BE3683E41BC289AF
+:10E80000DE87AF347BD04EB6543A3DE238ACE720D9
+:10E81000BA3CEB30933D2456DAFD647FB54D70C9A8
+:10E8200061726F6595E4114DF47B3794AEEC47DE71
+:10E8300067C50B25E87735ABF672B2BAAEE44C3B50
+:10E84000A5496ABE5554A6233DB702DD60DCCD81E3
+:10E85000159CBE97A55A496F2E7B7D68CA40FEC1A4
+:10E8600027AA5C9E5C00ECB61565E4B72D7AE044FF
+:10E8700023D2DDB258AB8474688C1BB67132D2FDE2
+:10E880006F4D74CFB33676823C2BAC3F63DC4417BC
+:10E89000C2C328286948CF233383378893904E9486
+:10E8A0004D789F7FDCD68D3788205F76C62A6978C1
+:10E8B0005E76D9D6CDBC3C49D96480F22BB6B6F28F
+:10E8C000F24C254D80FC755B1FE7E579CA26CCDF4D
+:10E8D000BCF5495E3E8AEBA3DBB73E7303EAA35A5D
+:10E8E00093A714FDD3CFC2FC0BF2F09D549EDEA97A
+:10E8F000C2452B7F1EBF9BF05D559E4696BFA0B6BE
+:10E90000DBDF4FF94B6AF9CBFDF4FFAADA2ED44FC7
+:10E91000FB836ABBF67EDA1F52DB1DEEA7FCB76AEB
+:10E92000F91BFDF4FF07B55D473FEDDF54DBBDD5B7
+:10E930004FFB77D47647FA297F4F2D3F1AD1FF0737
+:10E940006AFD4EF5BB3BB6E13DB4D7DC20AF509E2F
+:10E95000E4C73690BF6B5B6521D17FED78AEFF35A4
+:10E960007A77ABF702DECEE471A56F6772FB66794A
+:10E9700026B70B8A1EC85D3719E9F0F7FC9E22E81E
+:10E980008F23780F57794020FFDEB2D7F9BB32CB07
+:10E990001E1075BF1FA4B5D7E61F50E759A7A64B99
+:10E9A0003273689C6CC5E59916A61F4D923E6F05A3
+:10E9B0007EC2F8FF3A27D733F90F1437E0B9492D53
+:10E9C000E8195C5FBDC31C42FF57BD2452799DB35B
+:10E9D000D88FE7FD8A24921EAA772684F0BDE6BA76
+:10E9E000BA42DD7B9F759248EFC788F153ACB31CE8
+:10E9F0002837A649283FEB98945044E76AB04F4324
+:10EA00007D52592CA1DCC98E7726A05C9E95C5E16C
+:10EA1000DE1EDB65C37B14E24302BD15304C128958
+:10EA2000DF73EB84800CF368979691FF7547B37A98
+:10EA3000A6C8F879A226E777FEEC2AD263B5A0C76C
+:10EA400064D2636CC898E4DEFB9BE2D19166D45B30
+:10EA5000529A9199402E1FCA4CA071773CCAF55624
+:10EA60001EE82D7C67ADB590F177DE5C56F2EB9633
+:10EA700089CC9518E6C73C946954DF47E2EF50E72C
+:10EA8000E17B8861F01DEAD7EBADEC41F4565625E9
+:10EA9000C8CBB0FA1697A4CB3F97A9BEABE4611ED2
+:10EAA000B46FAE7A6E0BE993B3A84F18EA973FC4E0
+:10EAB0008C44FD027AC4C2FACA414D1E6B768B2685
+:10EAC000A76B55BD511BA1370697BBFF787D38D189
+:10EAD000A7A07B87A63FF9BB1CE304005E269F81AD
+:10EAE000F40A137D74BF7F30B8994C2512DAE383A2
+:10EAF000C1CF94F4453CCA69934FF49C88724F6A25
+:10EB000030F86AF5CCD6F4ADA8D7BE38BA3C1FFDB4
+:10EB10005E2B4D1D337721DD1A86D0FD0E59F53B56
+:10EB20006CABDACF8EE7E1EFFABCBFA56E1CDE1F3F
+:10EB3000F74AE42F492D96B19D0DF6E98964C7F196
+:10EB4000FD26937CFE0568CFBF6896F15CE0F0B3CC
+:10EB5000EAFB0D990E82E7BD7BEEA3762643858BFB
+:10EB60009FF73382F7AAB404B2CBE59D56D56E3C2D
+:10EB7000BDCE0B65B542A701F5CF5BAD817556D40F
+:10EB800027EA7E8029811B71FF130C98D5A01ABC3F
+:10EB9000E8CED81EC1A0F99FBDA22BDC0E35DD3812
+:10EBA00065329E874A2345E82FD56D5B67CAC472DC
+:10EBB000416BEFC5CB4328BEB4BC087878A65D2B6B
+:10EBC0004F593705E6B3C7CCB4FE15ACBF071F835A
+:10EBD000A4BCB40EFBDF5DACB6573E5F87BFDF055C
+:10EBE000F3B9CE087BB0E1DBD2D639527BE79BD3B9
+:10EBF0002AAFABCE052A943BE3701BB7A8ED443295
+:10EC0000EAED55A5FCFEB0F6FB59DA3DE21EBCED7F
+:10EC1000BD494157ECE787FE33AE008A96183B0F9B
+:10EC2000D9016E8BF657584D02BEDFC5DFEDD2DA43
+:10EC30002DDA3B93EC9C252F17515C70947687F16D
+:10EC4000FECC3FD1CE6ABE80F14E87DE5CBC4BC6A7
+:10EC50007B33150D0E23D567DCFF157D7D5AFBD365
+:10EC6000BBDEFC318E7746EE4CBE166AAF0A015C05
+:10EC7000A2B4D3EA6BF7AB27B9BC13DCF0FD3FDCE1
+:10EC80009C0F9958E1413F53D0EAA77B6C3693BF64
+:10EC900004F509803E80710A5A3AC99D4BF523BF9D
+:10ECA00047F257D0CA12A7A1BCBC4FA473F7A05516
+:10ECB000B18F867C33EC53AA614A3563DE198BF140
+:10ECC00002CDFB1C24D76BEF6B77E1EF2B291E33B2
+:10ECD00043BBB7F9F28E5409E65177BFB9F4E74860
+:10ECE000BFA165AE7BC2ECB09C2C1EC79D19EF2F57
+:10ECF000457EB4013FA23E6E34F9ACF86E8A922A8A
+:10ED0000505CB50DCADFA0F24CB5DC33F56ADA977A
+:10ED10000912CEAB3E77F6D462D46BAE04D207B6FE
+:10ED2000BC29A573A13C20992524AF8AACB2BB11A4
+:10ED30004ECF889E0AE4BF671C0E09E3B14056928D
+:10ED40003E10F39C149F6551EF3B658EE17ABE67E0
+:10ED50005FEE56FD026E1EDFD31CDB715311B48BC8
+:10ED600079509014E8BFF1FE0D25189FB8F5FE7795
+:10ED7000FE84F1AD4DC922BD33B0BB3AE4C57ADDA6
+:10ED800006D6B11DECC83595D33B703FBA86C93263
+:10ED9000DAEBBB0DD3FDA89FBB9344B65DE6BFEF96
+:10EDA000101EAFEA28D0C74B6594EBF36BB37C0F12
+:10EDB000BAC7633C5061118E936490657C3AB8B0D9
+:10EDC00083517C7E726EAE8471DD71851171B0935A
+:10EDD000F5FD244CD1973BA745C46DDDA22FC7DFBD
+:10EDE0004F08CFE3EF4484E74F223D523C093F7F79
+:10EDF00088E145009F2718EAE9C6AF87503C2BC23F
+:10EE000011EDF69861A207CF4532CD1D33300E8E3D
+:10EE10008D88217BE9A03B86C990B72C66244F2DB5
+:10EE200009C103B85FB5085289421A2A78E0AF5089
+:10EE30006E87FD2ACADF48F8656672FFA043FD3D74
+:10EE4000B0A018223BC2F6C010A9DA835BC7083F06
+:10EE50006C79589EC77B6F77ABE7282E2D4E8DF0CF
+:10EE60000A2B43BC4D62017C8732F3FE134A08E64D
+:10EE7000B146CEAD403B6395D049E328650E1FEE09
+:10EE8000BB9330CEDB88F1DE0AA591F8D8E3E6F635
+:10EE90009FCC66FB118FAE9902C58FD41F8AA9C380
+:10EEA000C3977AF5BD062D8E4DA3CB97DCDCFEDC37
+:10EEB000D32E085EF483DF91BB1DF1ADE55B7C4E84
+:10EEC000FA1DCECC31159D4897EC7A6E87821EA034
+:10EED0007BD95A9C981657F85196999FE767093D38
+:10EEE000F80B6971446171E0747467C4A30BBF844B
+:10EEF000E73D99634A2494338F68F72F18EF179FE3
+:10EF00002FA473836982F722D59F8E765DA23A5E25
+:10EF1000A253F4D2FBEE302701EA3FCA78FDC4DCED
+:10EF2000BDCBF1DED51E241CE49F7B389C23E93643
+:10EF3000B5DD5F320AE165007D98D1978E0DEE1642
+:10EF40003A0FAC7F902558C6F4A5EBF1466EFF74DE
+:10EF5000CF9729CE72303AFFC41DCFFDD8499B24EC
+:10EF6000B46FD3721FADA67B300F3209F55D5A7BAB
+:10EF7000C74DE8F78AE487803D6E2C8F93FB6E7E49
+:10EF800078A391F3074B11096F91F1A591F1A43981
+:10EF900059F1AA9F02F4402CDE0790AEC038C1EEB2
+:10EFA0000718BD1350FC62F36DBF83FEBECC334B1C
+:10EFB00028AFB3DEF23D6987797DF94B5F16CAE968
+:10EFC0006D62A72D3ECCEF290AFCFE59A4BCCEC928
+:10EFD000E27427A3DE70FDF36926D2F710FC7DBE34
+:10EFE000E4919284FDAEFFA335E9FFD06E61563FF8
+:10EFF000DA2DEE762D9F417658D65B3C7F893B63B8
+:10F000009D928B702B277FD1C1CC39E42F12DFE387
+:10F01000FEA251466F00F3EC7D1BC5DDEDDC77C72A
+:10F020003C8C57AB4FBE5646FD3C4EDDFF8CC9D2E3
+:10F03000F85BBF7ED1ECF521DF447E1F99A5C59515
+:10F04000947C3213F037EA7133C5DDE50B65F47B50
+:10F050009CDD8D46C26799515EBC3A6C9FD6945C2C
+:10F06000549495C47F97D8071B06F9BC81F980D9C1
+:10F07000DCCE634548AF59C066285FB2146E406667
+:10F0800055C6305F189DCAE745AADF94EC2DCAE249
+:10F09000710874EE635259FA9984123613F5327C72
+:10F0A00043BD6BDA15C3CF7B9CFAFB9146238F17C8
+:10F0B000B9415DBF09CF75C6E27B6F42C832BA6FF6
+:10F0C000FD9BD57AA2D511320E413FD91B47E8DE10
+:10F0D00065C43930EE6F292EA79C911F14E142F9C7
+:10F0E0007B25FE6E77258F07A85DC10C781650AB87
+:10F0F000DE5351EEE2BF4FCCBC5E19DF57A12DA607
+:10F100008CFF0B11FFBAAC2C01EBA7B20E8A636423
+:10F11000ED4CE6F112FA73A76DFDBC03A5F901C42D
+:10F120004A23ED5346BE66A3714D958CDE09A73781
+:10F130009B70FFBB82054443AF1FEEED4C99DA692B
+:10F14000E7B1BBBFF9200DE572BEB0DDF706D90D02
+:10F15000B1D276D48F317A3ED4EEAFD5A874B2ADA9
+:10F160004A227C6BE56EE518C5DB67B1EE6ADC67A9
+:10F17000655526E8F0DCE3973D9FCE7CE3C2FB0DAE
+:10F1800070BECE15E99D2EF9BC9BCAB755C983F454
+:10F190009FD34FFFA9444FFDF79F41E5ADA12FE25B
+:10F1A0006F00506CEB3E115F22F7DAAD917076AFD5
+:10F1B000D0CBEF8BF747C69373B8D84C5EE74D00C2
+:10F1C00037DB4382A78DE1EFDEE8EB4DCD3E17CF75
+:10F1D000CFCBB5FA21E7CD581FF6BD6D32FE8E8E2E
+:10F1E000BE7E49D147F1FCDC5DABCFE7F7C3F3FA54
+:10F1F0007A91F8899C2FCC2BE94761F3BAC26AD186
+:10F200009597CEEC33AFA45BC3E675B54B5FDF5784
+:10F210001D7D5ED7E55B069C9756EFC68917562F76
+:10F22000721D374FB5F403775EFFD6D20BEBF7F6BE
+:10F230007903D7BBBB32721C85DF53377BDF46397E
+:10F2400057C6E495F84E3873C4448D0B2E52F9E33B
+:10F25000EFE8A748C27800EF516CF779268F4B3959
+:10F26000FCEC023F9EC32CDB6796F1BC2353F55B9D
+:10F2700083E05988FCBBC72AC5633CA0C52DABFB06
+:10F28000AB8E6C8CE7DBB3F39DDB48EE31BD3DC349
+:10F2900098A708F5358830BA97F1276C97141E4760
+:10F2A000E125FBAF5EF0FC99F6553FE6FB2A2D7E8B
+:10F2B0003FDCCE62137AED2C2D7E7BBD3ACE3759E2
+:10F2C000DC1F08763EFD3E6A72AE48F1CD8F583B9A
+:10F2D000D6E3FDA3479CCE78DCCFFC469DB76637CE
+:10F2E0006AF71A5266E68E3146819796FE0F29DC40
+:10F2F000A2280080000000001F8B08000000000012
+:10F30000000BDD7D0B7814559AE8A9AEEA57D2DDE3
+:10F31000A90E9D178F509D7720840A8418909126FE
+:10F3200009195486E9A022E80C360908485E181F1E
+:10F330006165C7CA431E51C7384604046CA228BE83
+:10F34000669A59D488C16DA3C3E82E8E61D7191D62
+:10F35000C7CBB6C05506105ADD41BDABC33DFF7FDC
+:10F36000AA92EE4AB7C2E8CEDDEF663EA73875EA4C
+:10F37000BCFEF3BFFFFF9CBE2B81AC0C1411FCE361
+:10F380004A0971E6E4F476B9091957E215A7D0F7EE
+:10F39000BFCD3410328D900DF44168BD9227F877BF
+:10F3A00073F4DF2221EBCBE8F7D0308B9007C44118
+:10F3B000A740EB1F7009A2C2413B09DBED7DCD6088
+:10F3C000F0B80879E82739BDBC7BB8BCC5E7DA05D9
+:10F3D000E57106E20BD8A0137135A1EFF75A446727
+:10F3E00057092D0A83EE1A3B2DEFF9C3759C8390C4
+:10F3F000CCF1F45D0A2175AD95E4D854429E378571
+:10F400005F3D0FF3D9CCF977D37E5EE829A9166862
+:10F41000FBE52708B1D24FEBD65EF5C0F151844C25
+:10F420003F2ECE86F775DB9D324FDF370E3657C342
+:10F4300038A499C8B9322169FC6CDE4EFB49BBFB8C
+:10F44000B0DC41A7FCE080D417A2E5F02E4EEE958B
+:10F45000A07E4DC91A808FCD23D9E87A97C254F186
+:10F46000BDB3DA08EDAE32C99DB49FD346B208E011
+:10F47000781EFE660D3F97FE442A2774FE4B036BF1
+:10F4800097E2B8220559062D5B449C87451293DB11
+:10F4900068392D8158AC5308296B170FDE01E3AF93
+:10F4A000B28BBD14C68E72F1E0C3B0AEE64C91973C
+:10F4B00061703FC255EB7FB9C76B2274DC897B4C0E
+:10F4C000B433B68FE7E97F9302D1E5C97DD1E592E8
+:10F4D000607479EAEBD1E57D1283F70CCB981DC7F8
+:10F4E00029BC070E9809CC77F5A904BF99C27BBF48
+:10F4F000911058BFF2AC19F1A172B5CD03F871EAC1
+:10F5000064C22E332DBFF25E027E7FD3D356F6BD8A
+:10F5100021F04B282BBF4C24F0FDEA5181B2643A14
+:10F52000EF97BEE66FF016B16519A1FF5F16EEEA20
+:10F5300082FAA9813291BE7F7E022183502FF88BFF
+:10F54000619DCFFF95C77EC34F9AFDBDB4DF532F9A
+:10F550003EF14B80D7A927C7247374CE971A7AA798
+:10F5600076417D9B5DEAA5EF679C7A26DB17B12F7C
+:10F57000ABF798A3D6D92C71B8CE56C1D3FE28ECE0
+:10F58000CF2123E253CB727F5D90B66FE1326505E8
+:10F59000FA31513C2D82B29CE6A4F83AC3C1F0B6D0
+:10F5A000C54ACB31F65D7BD66EE1896FEA70F9E82A
+:10F5B000A627703E0527DE45BCDE6F540C0900C748
+:10F5C0004D9CBC9BCE7FBFD5514C92E099E907BCC6
+:10F5D000B95332E0FCE8BA1E6E04BC7893977B49BD
+:10F5E000FCF10AD2FFB4BD6AEA37D4D371DDC58419
+:10F5F0009CFD73C20D1E3A8FFC2DD1FB5EE88F2E51
+:10F600006F00F8507CAB2511EFDD309FACF5E94879
+:10F610002704E75370E2FDEBDC74BEA3CDA419E030
+:10F62000A21FB75B627CE4A9A7683F05D80D7F9E47
+:10F6300067FD49A9745F54BA7A89637444FF6E19EF
+:10F6400043E96D35C7F88BF67EB56E1E5AFFD3D5EC
+:10F65000FE5D26F9BE10EEBF5984FD3F79E7DC0759
+:10F660008E1B47CEE7C33B3D9EAA88F7376E597382
+:10F670003083B6ABDF9B32858F806FFD93AFA65E84
+:10F680004FDF9FDE23C8C002EB173FFEF319F0DD0A
+:10F69000937C00E60BF51EBADED381DF38E0BB1B9E
+:10F6A000B73BA7F0D270FB155BE678AA0A86E17932
+:10F6B000B174FA4239E373AB0346BF05E822F0FBAD
+:10F6C000EA3180A75B3839978E5326F878A03B7BC8
+:10F6D000A9C7A84C2764D657FF7C7034AD6F3A3069
+:10F6E000ADAC8BD67719BC57FD08E86E272FEFA677
+:10F6F000CD9E7BFBE6545FC4FEFC56C5FFAE85F590
+:10F70000D88F4271239732F58182DA4A28CF282296
+:10F710009C99F263C709E2F1DB603CF2AE2199905B
+:10F7200013FD77150B06E447D7039D9C220E19E8BD
+:10F730006EBFBDF9DF71BC678D38DEAC601207FCAF
+:10F7400077FF639CDC45001ED1F477E244BB63364F
+:10F75000A3EB1BBC28070CC445FB5BF9E824E403BE
+:10F76000DA7BFDFEADF247F7A3C78B132ADE026AF0
+:10F7700046E297FEBB51F31413D0637D2B9517110E
+:10F7800074537FBCDB446C23C72164087F09E02FDE
+:10F79000C54B22E17AADC837E81F67A1787B12FE1E
+:10F7A00095CDCA848E7F13874B23AB2704F280CF7D
+:10F7B000718258D19931CC5F49B91FF9FC69FACFF0
+:10F7C0002E19F842E008D03BC8D2DD205FC4E09992
+:10F7D0006D50AF8CF7003F1A0D484A9FE45789C817
+:10F7E0007F4F4BA1C7B1FD33936485BE3E0BF462DE
+:10F7F000C3768EE408FED41678D511A2E5537B4774
+:10F8000055F00EC0DB7F75C03A4F064655981CF187
+:10F81000F9869E6FD29921DE7C00FFA47897E4F6EA
+:10F8200024B869997452A10BF26C547349738C7D9E
+:10F83000D3DAB94CCD2512F08F9FDA64E0E3C99694
+:10F84000BA47405EC39F87BEFFF4F551BDB0FFBF0E
+:10F8500050E5EA528E8DA3F533DACDE8FDF557F287
+:10F860009242749C4F899404F2E2E96CEF38377D40
+:10F870009F5E31E8E1293CD2AF2072076D7A8C9708
+:10F880006F13E97E2C23545EC2B3D46702BE423AA2
+:10F890005370BE84C8D500CF15F328FC4B5819E42B
+:10F8A000DB2AAF49EEA272B84E60F0AEDBC3F93B83
+:10F8B000E85C96DD130D8F1B7BCCC37801FFB73D51
+:10F8C000A29E8EB34AF0AF07B935968A9C51E514D3
+:10F8D0001F1E8BFE7E3509E2BCEA9F396F8E05E75D
+:10F8E000BFA8707E3ADB7309AC8F5B60C1F9B43C92
+:10F8F000CBA17C759902A84F84D7507E4CE74BDE94
+:10F9000066FB709DAA2F35AD5DEA59469F675BEB9C
+:10F910003CCB6815921AF0919E24C49FD5558183E3
+:10F92000C85788F8EBEBD3A13FE211A1BCD9CEF4C4
+:10F930003DF2D8ABC057FE42C400E0E18C951CB646
+:10F940009FF136DF4B319C5C37B47F5E8463BD44EE
+:10F950004480E37B462FAE5B5945C4DD94AFD45B56
+:10F96000BC9AFE25FE90AEE746D28CEB5EE8CEC296
+:10F97000FD5C49BAB1DC404226C2C3FE962501BEF9
+:10F980007E4664DC5FAA27116BF248BC02F87B223A
+:10F99000E0B6727B74993C1651CE0238D37204FCE7
+:10F9A0001BF79D377B62C0FDC12179E42FAC991410
+:10F9B00089C76D38DF23EABE3C78CD8D19C047EE8C
+:10F9C000038578B4DA4139F05FFAAF19580E5A68F6
+:10F9D000FF095387CA585FD6CECA2DEE17BD5B28E4
+:10F9E000726C36FA3244BA3975BCF7A081C27561BF
+:10F9F0008EEF76D8EF3A832753407EE2C9F3D2796F
+:10FA00009056B6BF0F4D692E6C8EA17F68F3DFCC88
+:10FA1000058206E0232F32FDC25E1A3646F2FFFB56
+:10FA2000DD8C4F260D8470FFC3CF7104F4DEADDC96
+:10FA3000FD19B08F5B3324AE83AEA9745FDB6CE439
+:10FA4000379417E5D27D6DD8F7C1C131B45C3A77F0
+:10FA500010B689AEDBBBE63740CFD31298DE9CD818
+:10FA6000BCCB40FB4BBBA1604A07C5CFCD6E09E7BD
+:10FA70009330B5FB15E827BC46127B693FE9ED8A58
+:10FA8000FBE62218BFB90DF1B786E0FB946BD7B542
+:10FA9000C177778F26C93C7C47DA38F8EE410741B9
+:10FAA0007D31C5C0DF5003E529AC9CBC8EF3F42248
+:10FAB00052DF8FE3A499C95C2E99BDF71721297AEB
+:10FAC000F662BD1FD79B56D95C02FDA565B3A7CBD7
+:10FAD000E433E4D0F10E1D36FADBE97C0FA9FB7E9E
+:10FAE000CBAE8AB448FE79E8B4453050FDEC50BA4C
+:10FAF000A697066DA097DE52529906449595333726
+:10FB000009F6C795195D7FD6E8499A0A7470982757
+:10FB1000B00FFF69F324811E79A989CD5FBF7FFFF4
+:10FB2000ACEE4BD3171CF147C8A5A645E750DF6FD5
+:10FB3000FA42887A7FFA4E0B01513524BF560E5493
+:10FB4000C3770D64703DE053432091F823F0FBD25E
+:10FB500084D8E36A78DDF4054F9498E39AA2DF7FB6
+:10FB6000318A28A3627D971AFD9EAE23AADCF7F99D
+:10FB7000D03AE03D290F39BCD4DE9B07F29096CFF6
+:10FB8000FA0D8A7132A8E34C8E9D11430ED0B3A9B1
+:10FB9000DC6B867D39238550AE9D25642ED45F6A4B
+:10FBA00030DC5003FB2B841D0BECC3E368F5D03E27
+:10FBB000721FCF2C329120EE4F18E701F053F2095B
+:10FBC000D9D6FF8949027DA0FF15849F862F9170A9
+:10FBD0005422F8466AC760D040E9E3FFB8BFEA2E76
+:10FBE0002AA4A837A0D1F75FBB3D33693D6F88A237
+:10FBF000F7C4D221FA4776F3A08157F9C5F9EEAAE6
+:10FC0000999165F67D44FB9A2ACA1F4A8B587B213D
+:10FC10008B3BDC9E03AFBB999E238433017E4365FF
+:10FC20008BAE6CA3E54911655157EFD2D5A7EBCA4E
+:10FC300063D9F7A7EDC14CB04393B28C3502E57B95
+:10FC4000A733824B385ABEA7C35C5345CB0DA54C96
+:10FC5000EE36F673328A0D157E8D32D31F6D72C863
+:10FC600054570470183C08FCA1BE8F13394A0FB6D4
+:10FC7000C0DE2096A19D14D12EC061BBFAC007D86A
+:10FC80002E6EFF0506A4F3AE82A3ECBBC04728DFAF
+:10FC90003774AEF102837AC3C8F88F407C9E3194EA
+:10FCA000BE1BFB6A88CF36CC27CF64785E453E7991
+:10FCB0008013813E87F014FAB50DD385F6FD9F269B
+:10FCC000F5FF1ED487C45B3E6913E8F7FFABE1A3E1
+:10FCD00069A0DFFD4995079B397F218CBB8DF80A10
+:10FCE000419EFDB421F71503FDEE8831B40378E899
+:10FCF0008FB3C6D508947F1FB187C671545ED76491
+:10FD000015B0724A6807C0F3C9AC42561E171A678D
+:10FD1000A0E56B7AAF46781FC90DED80F2CF7A6708
+:10FD2000B1FA49A1713C6D9FAD7810FEBBC5D87486
+:10FD30003D278BF1136D7EFF36D5E3C982F5D433B1
+:10FD400039B2E4A6F71603FF5D622022A1FC76F724
+:10FD5000E963CFEEA6F0D8DD9A487A193A7A05AA77
+:10FD6000D7A631D4A7FCBE1BF973D84DF9353A811B
+:10FD70000643E03F4A9C6691BADCC3FBA28D9F36E6
+:10FD8000A1792FF49FB6A408E581C5ED790AC6D7FD
+:10FD90009E6F15B2E7535922E3DFBCC183DFDF61F9
+:10FDA000F7C3F7F759D9BA28FDE03EDBD47DB95E39
+:10FDB0005DD7F5594C1F9CE69EF354560AE823AADA
+:10FDC0005EBD31903281CEAB872301B04FDE33125E
+:10FDD000C58AFA4802EA353D3077A8BF3FC3AFD0A5
+:10FDE00071AEE78817F88BC64F7A9C9E8CE408FBAF
+:10FDF000A4A784966DC3F6684F8D2723C105CF5401
+:10FE000003E8EA1A7FEA71B3769A7C4AEB60E3A4CE
+:10FE1000DD57D80BEB491408FA4B962FCAEB6D430C
+:10FE200039BF00E74D3C9E0C8EF6777C559601E07D
+:10FE3000A8EDD767533DB7017CAEE3997DADED9B4F
+:10FE400006DFA7B2989FA08EA77A02C5BBE21C1F4F
+:10FE5000C293EA0DC528A055BDE12940DA08381340
+:10FE600021340DDEFF7F08AFED8807DF115E0DAD99
+:10FE7000948F182E808FA870DCCC058D698C8FA094
+:10FE8000FD0BEF411EAD73FB025911F4B0E48E0679
+:10FE9000D417B57925DEFEC2DC6B09D0E149A4BBDD
+:10FEA00025FF9088F6AA5E9FD3EC244DEFFC451CFD
+:10FEB000BFE3CBEAFA64CDBFAACE23B128F4ECBDF0
+:10FEC000145EC9C42E021F3D620A4D9269FB2306CF
+:10FED000DFA32FC0BC47F322E52123FABB2D9B47AC
+:10FEE000BCB16A7842C28E09AE613CD944F1C40209
+:10FEF000ED6B4C6807F738FD5B6F043CB966ACAC42
+:10FF0000482887919E95D644ACBFD4709480BF3862
+:10FF10003C5D14415FA47885F53D8BF3FC0AB3FB8F
+:10FF2000152BFA4113FCBD8077251400D0DFE209C0
+:10FF3000580F7637FA2B165BD87823F18AD9C7F990
+:10FF400084D5BB55BC5D9585789BDA4198BF41F05F
+:10FF500014D744E80B85D90C6E89A5A1E7DE013BD7
+:10FF6000E51EAB9C4B9829077E0CD29D86FD517CEB
+:10FF70003995C5FC0B8897CB7E6EDFC5F89E5C0675
+:10FF800070DE60EF266BD10F65C4F96FB706519F25
+:10FF900036582427F87B97F064731EF4D761140158
+:10FFA0004FF4F0B667C7F34B866E8DF44B2E312BB2
+:10FFB000E64CA8BFD38AFABDE69F5C92C4E84AF338
+:10FFC0004F027DC6920B9A7FF20615AF46D4777D1D
+:10FFD000995B4BFBFB0F15CFE4812F7297DAD8BAF0
+:10FFE000C1CF510BFFA2E3D6AEB37E00FECC5AC503
+:10FFF00018343B808FCCF18422EC2DB285ADC3F751
+:020000023000CC
+:10000000A6D10F706A15C8E6C7617F14B6FE96E5E3
+:10001000FE5591EBDA6662EB52FEC11EB5AE6D0E77
+:1000200016AFF8EEEBFAF3B4E8759D98A6AE8B58D0
+:1000300052693B55CEDDD06AFF802BA64F58177D05
+:100040009275745D05C3EB9A93CDF8E912958F8D87
+:1000500090BB71F7F17FC87ABB1FF2C45AAF7E9D87
+:100060004F677BAAB353906E8262E9305EFBB6D2D3
+:100070007595C2BEA6F8DB705F197E12E290818F83
+:10008000B52CA7EB82675B1AFAA59698A53EF0CF30
+:10009000928793D47512E4032D5BC7215D52BC6532
+:1000A00074FB108BEBB45899BFA0658D282B22AC44
+:1000B000FFD768CF86297F45BDA4359AAF7F3B1C0B
+:1000C000AC99B5459170B0642E2D8AB1EF8A19F1C3
+:1000D00039DEBEFF071FBE95CB8EEF2F23EBA2FDAF
+:1000E0000DE0371C2AF323CB7AFF05B51FCCD1DFF7
+:1000F0002BF1F8C14F23F1E88851C5A3B556943FC1
+:100100001A1E1DB1B3F5EAF188502D1AE8585BB7F5
+:100110001E8E4B008E31E209149F72018E4754FBF4
+:100120008CE2532EC051A3831B5A193FD0C3ED89D3
+:10013000F87CEDBBAD4387C7DF751D5A7DBC756884
+:10014000FAED166ECD56C0CF2D1944EC403D383433
+:1001500009EC2497C95F08F3DA66A2F44BFBAD55AE
+:10016000C707CD01F0FBB343CCBF79541D573FAF58
+:10017000E75539A4F77F3539C23B410F694A60F230
+:10018000F0CC013BD20DC9092D01FDFBEC7E330102
+:10019000FEDAC885F2E0BB339C67297ED7962881BA
+:1001A0005CD4FC86C79E677E438550FB17FC753E7A
+:1001B000E6F76C52FE753DECC3F96CA119ECCFA6C5
+:1001C000BE683F195D9F03D67BC64006E1FB46DE55
+:1001D000BF0A4CD6CD26A60F6C369000ECDFB05D82
+:1001E0007E340FED840C91805FA7D1F041DECD11FC
+:1001F000767CA35ADF98C9FC4C1057467F390CE532
+:100200001E0997C67B4E7D0D71B1C67D7A7A89A68F
+:10021000A7FAE132779E83FE22EADDC3F484F63842
+:10022000E06115F1E772E01F63E5C4B9837E884F92
+:1002300037A9FED394815035E80BF6D200013EDA9F
+:100240007482D92133FA77BD0A7E33E7DCC171A00D
+:100250009234A97104BDFD33BDFF7E1EFC439AFD9F
+:1002600012E18F2A5C10E5576CC776E0DF82F1421D
+:10027000F00AFCD302D37337AB7A2ED587916F2E59
+:10028000EFCE477D18F455D03B34FF18E821A08FFE
+:100290002ECCA91072E83ABFCCA9380FFC1BC6437C
+:1002A000BB1F9C2ED3BF817FA9F0D1BE033FD9379E
+:1002B000FBF3993E3543E7C7BFF98D14C4F3FD71D5
+:1002C000F4D45139437EFC34F0E3DFCC496980E754
+:1002D0001FF23EF4D7AF200AFA8157817F1CF960E4
+:1002E00010FDCB373513B90BE3E1BEF5506E58491D
+:1002F000C42EF02F57F9B01EFCCB574E67F12629BC
+:10030000027F219E1359267B68398A4F0FA2BFBAFC
+:1003100091F6B04D063F42F4F74DC45F29005EF4FC
+:100320009D3747F5D3C3E074838A2F5BADCC4F3D37
+:1003300063DD2E9E44F81992A678DC77013DBC61FE
+:10034000443FE9FF56F75783C7D3D915D61C0A8F08
+:1003500004F0FBC077779951CE1E379095802FF728
+:1003600039C90D0BC09F7527F1E418012FC4CC4883
+:100370007F97F6ECDA6F5D0978362B87F111EDFD8A
+:10038000996C2396D1EF8CFA6922C6D1295B2A0693
+:100390003C2CCBD2F462520CFEEE0F54FED4B8D0FB
+:1003A000E683FE4206C6CFE6E530BB7B5E8E09FBE8
+:1003B000D3CA43FE2215CFE838D85FC2541215C7FE
+:1003C000BB2A87C901CD5F4BD4F8CAE655094C8FCB
+:1003D0001EC27703F2B3C422AFC987FCA402F95945
+:1003E000F8CF3609E032F754FD2A58C7A78B120818
+:1003F000E41D2C53E3448D394EEC578B0BC5D0BF15
+:10040000AE0FBA86E58D869F9A9CD96F67EBBED8F2
+:10041000F8BEFE39B7AB10F9B7368F193ABD241EB6
+:100420005DDC364C1751F12D0AD744E0B3FB0DCCFF
+:10043000EEDA4F110BFD560135FE48ED649003FBDB
+:10044000F7E5A39EBD54F5A7523989F65598CA0B16
+:10045000B6DFBEADCBE1BB402EC6653F30FA9F7C18
+:100460001CE4ED01664768FBB17FFF183FD0EF8CBD
+:10047000535F6502FCF79F786A0CC4BBF7ABF1C50C
+:100480007A53300FED7D13D353EB1DC13C80DF4B0E
+:100490002ADED427D0327D9F95E2EB063EA4E50705
+:1004A000403B27AE477280BFE1986A471EA576257C
+:1004B000CC8B52CB20C43DE97E674039BC298DE905
+:1004C0007B745E8017C70E4CC2F56D36323C565EAB
+:1004D000E4D03F71D418FEB0957E7F34632A69134F
+:1004E00041DE7DF1F841E87F274FCC22E45F7C7E3E
+:1004F000AE8F7E7F96DAB9E037AB3378AB33805F6F
+:100500003CCFEC75FD3E80FC8B8CC79D21E14CF40B
+:10051000EBADCC0A00FE9CE92FC4BC22E21289425A
+:10052000CB4D2F32FB461F273E6E8CC67F7DBFB062
+:100530002EF0AF35C1BF41BE47B68FD1DFB795CFE3
+:100540001843796B293CAA245F302785B163D8CF43
+:10055000A69733901F1FBBF773DC4FD2CDE29FC726
+:100560008D9E25303F6755D0541B818FEFA8FCA38B
+:10057000CECCE435E5BFA6487EA3D59755909871BB
+:10058000FA3FA87CC13EC8E4DEC87A86E7B7924746
+:1005900079E017EFE448D8DF7835DFE056F2D92B61
+:1005A00066D04F022598CF307E5D10F9009D2FE276
+:1005B000E7F1AD49C81FC93D0C5F6F7CD88CFCE3E7
+:1005C000462A3F98BDCDF2ABC83D2C8FE2C3BBDCC1
+:1005D00088CF65EDC132A4072791412F79A1F3039C
+:1005E00085A7F54BF77025903FB6B4D38D76CA4DED
+:1005F000FBDCB8BF3354BE5E67F660BE187984C5B5
+:10060000D396FD62158ED390489C3CEA7F7E13C83A
+:10061000E5957B3802743523C0F87FBD107C05F466
+:10062000487DFE03F147C789411E91083D13E40F41
+:10063000D1D905D1FBAE5C94FCD5CB1B3E37B6FCC3
+:10064000A5F69E90CBF695C989BD1CE31BAAFC6D4F
+:1006500000F90BBA9A2AF734B9B942959B1FF24CAC
+:100660006EDF68BE1F9F19B96E1CE72688EB621CFF
+:10067000336C02FD241E5E64E432BCD2F062746E00
+:10068000345ED49F081E34A39D293F0FF1EAFA750A
+:100690002468A776DA8D4233CA87D1221131AFAEF2
+:1006A000D287F34A6BA1FA39DDE71B21063BE5E26D
+:1006B000F582117A804EFE6BF3D6F044AFFFCD5831
+:1006C000E7E7219E74328FE07BED29924009CCB799
+:1006D000C6C2F4EF1A8B2DC883BD59653C1D696FE6
+:1006E000FC58F094E5A25C1DEBFC7022B20802FD00
+:1006F0004E737B664D9836AC57269686D7DF4BFBFC
+:1007000033926203F0496D7C8B7BF692220ABF26FE
+:100710006110ED15924EC4DD74BC2B8B249C4722D6
+:10072000DD875D14AE464141F8192DA2B3CD09FB1A
+:100730003F887199700A413F9DB65F3BEC44817CD4
+:10074000C52B8B187D5F5924E293B6C738AEB180B4
+:10075000B6A7FD57ECB7225D9E7BD1EE07F94CE5BD
+:10076000CE7827AD4FFD13B55368F9CC7E3BEA290F
+:10077000675479E1D2FCB5643DEEF722156F14524F
+:100780003106EC11C25D3186CE9D687A7283335E8C
+:100790001C53AD770F2E64F86B467DE19C33741BC0
+:1007A00094E97C30B7C69BCBD6DFB4AFB2E40EE0A1
+:1007B000DF5E9BCCA0EE2B01FDC7CCDFB2D0428127
+:1007C0005DCDAF0BAF05BC1F6713CDB449D5F8F7AE
+:1007D000FFB09896FFBCCF48CC803FBBAF4A0A42DF
+:1007E00033C193EE9D34723EABFCC6A3A1083A5EC2
+:1007F000BD27BADC10882E3711E1682882FFB7BE0A
+:10080000BFEAADD722F06D6DAEDD05784024229FA2
+:10081000A7F474FCCE3E720C6421FF9324E08FCBCE
+:1008200028F9C7D22B3EBF73E55BAFD1EFACA68AE8
+:10083000B65C940B9209E8AB96EA0DB1ECD0C9B95D
+:100840004C4F339B9B4FECA2F031BF6496DB68ABFF
+:1008500079B9BE2EC0C74643F820ECAB79FCE962FB
+:10086000F067578CFF0AF302CEFD2391014EE7ACEF
+:10087000B3119FCE6DB54A60A7F664DA981FF6658E
+:10088000CECF31BB65FEB454C8FBC0B5503E165E3A
+:10089000BF15F8F474B3D82EE2722D06DC6F6ABD72
+:1008A000D1678F49590F7ED51E6A40B6C960E70DE2
+:1008B0003A80180655FED0C43F63B2D07FBA3B3DA4
+:1008C000856DF4BBD5DE0402F978C2D78217F06CCF
+:1008D00003741561F73CAEF2BF46F1EDF5307ED3FF
+:1008E00057B7CC4D310CFBF9CD46E6E737F6CD0EC8
+:1008F0008EA14D57B456A27D47F92DE38B07185FA3
+:100900005CB17636BEE716CCC5F57E48D70B70795C
+:1009100075AB19D7FBE1381BDADB1FEEE0B0BC4248
+:1009200034613E1FD54F46CD76C17BA3682623E1B7
+:10093000D1B465C3FAADB4FE77193CE128FE7FB4AB
+:10094000FDB7188FF888B0F1957D3CEA3D1F89E12D
+:10095000B220C0536A7644DA932B76F05EE0972B90
+:1009600076DCFABBE900B705D795023C66396F49DA
+:10097000956CC3F59ABE2724973F0E7439EBEBCAEA
+:10098000C159A077EDA07443E72D18880FEC8FD7DD
+:1009900076FC10F5ED1535094E589FB47D7735C8B6
+:1009A000B78F6A461B705DCF72440478385B53E1A1
+:1009B000FD0A4EF0C6C2AB65B92C9E307BBC4D061D
+:1009C0007FC38ADFF3882F94CE16421CA161871162
+:1009D000F5F9D716BCF787C5AE613AE3166C993FB7
+:1009E00003BE7FC288DF0FE953DB3F7E1FFC02F0AE
+:1009F00047253BC821849F9EEECCE3D7E5C1BCF4DC
+:100A0000F4B7A2BD398FC5F72F8E0EC9764687275A
+:100A1000299D9C37FC4D74F829E3EB174687646CDD
+:100A20007294FC1EC9F714FC4E8B8F5A64E2D96D88
+:100A3000C37C180F47F9F5983C01E13E268FD96D2C
+:100A4000C29737EF7993C26947AE4FC8A3EFC71378
+:100A50004F09C867292C56802BD6A6EA8D643BCB5C
+:100A6000F306FB02F67F730A79BC2BC23F93A6F60E
+:100A700047F9821DFA39F3C7AF0EC27E35669E2E46
+:100A800006BDBAE98BFFC4BC0A5B3FCBC7B1C961E5
+:100A9000CC3732BABC888F1ADF6F92991CD2AFABB9
+:100AA0003D8FD9AD4DAE30F6F3423EA34F2D1EB96A
+:100AB000AD3501E342DB5C7E2BF3B3507D8FF63F17
+:100AC000AF94473E6329ED2020C748398FF19C59E8
+:100AD0005FBD4520FEF5BB999532E895B6D25785A6
+:100AE00051B0CE72A35AFFAB8D59B4FEAD9973D0FD
+:100AF0003EBA399D9740AF9A579AADA0FCF4B0FC2E
+:100B0000DB595F25211DCE5F351FF54A6DBE5E6244
+:100B1000916C144F1650628DCC539E3FD32AD9222C
+:100B2000F0EBD36E6E2ED3ABA5A4AB2731BF50A094
+:100B300088C9F34838DC9C6EC2F1BFCC997D09C0EE
+:100B400077D6656C1F4E3E6BF6B7D3714F5A63DB99
+:100B500091D5790C6FB284CB912FDDF2AC19E3F310
+:100B6000A7B8D8DFDFB491C7BCA2551B39E2A7E311
+:100B70009D7CF2854CE0EB7FDEFD42666DC47CE23D
+:100B8000B5AFCB63FAC0487B3BB82CD2DE9E676220
+:100B9000710132C51CE5DF9DE750F3EC2F30DEF12B
+:100BA000A3B87EFE37C6C27CDF1CF2F3BF3E3632EE
+:100BB000DE3114B792999F5F1FAFCA29FF1775BE28
+:100BC0002CAFB95550E72B9B59DC62398B8BB71C86
+:100BD00018857837CF14FE39C6B35EE64535AEE1E9
+:100BE000B160FB74561F675DC4E3C97195A1BF096D
+:100BF000E7C3F57141BBE33BAC8FB038867E7DB572
+:100C0000FD7CCCB8DC97F92C0F20B1288C76D5D19F
+:100C1000D71F85C8FB10BE5BFBDD86C87CF8217D35
+:100C200056C5EFAB00BFE9FAAC1B59391E5EC7E3EE
+:100C300057A9798C8E35FC3EBA313B09F0ED2E4B2D
+:100C400063E820859F874F22D6D1B4ACC6FF95F7C5
+:100C5000593E2A1F61E7001DEC78DF8E764E87B182
+:100C6000F91138BFA3B40964377DEF4A68F4B7D1EE
+:100C7000B264B463DED4ED09F377815D17A20A2E66
+:100C800047CB9F271CD9057A02B12411231D47A900
+:100C900050DB9B2C6207D52F1E4A74207F695D466E
+:100CA000507EA79120C75180ECCF63F9AA29AB9F52
+:100CB000E7308F98523CE87D72766C7DF4572A5D60
+:100CC000BC0B0934F42957C6FE6E7F9EE617137CD1
+:100CD000A1083B6F03274BC877E85FDB74D0EF07B1
+:100CE00017235FA67AFC5B541E8CE17F8DFED963CF
+:100CF00077FA1E8975DE6148EE56C6B6D35F55E7B2
+:100D000057D0CDF98D0EA45FC3AE28FA55E378F61F
+:100D100054994A1888DFB2385D0ED1F2DEB780DF11
+:100D20007E74399BA3C31322A05FA4775F4E7CA37C
+:100D3000809E66A4817C6B591EED4F4BAFDD988180
+:100D40007EBDDADBE683FCDE62B46DE492E019ED91
+:100D50008FDBA2F3C77D1B5F488F4B37D3D3C1BF57
+:100D6000B16538FE87F8D3B154F4F31CAE8244C6A3
+:100D7000B5533BA4833ED083665BE45E7924FD904B
+:100D800072391DFD9CF9EABEA9F4DCA4A226D7CFD6
+:100D9000A15D3A921FAAF06C188BF0B476DF8E76C4
+:100DA000536209F36327AEAAF501FF49A4FC07ECDF
+:100DB0003893A999C3FD9FC1ECB6168E955B668BDF
+:100DC000A242BF37399A6763FD152CCFBAC5EAF343
+:100DD00045C6D32E35DC3C3B32BF5624B43DF0E152
+:100DE000456CBC7996752CBFD74775A48C61385675
+:100DF000A870CC294F60F9E6B75AD0BFB5DDDA8DBF
+:100E0000F33548CCCEAEEDB222BF1BC31760DC6415
+:100E1000C0C8F043B15B905EE58177313F6CCC2573
+:100E2000E912EF8EC09F5B58BD861744975760321A
+:100E30004907C17F472722435E4A0B271DACC07577
+:100E40008961458675AB7CB93881C9116A6EA63354
+:100E5000B8B2B8986EBF28DE30BFFA241BF31B115E
+:100E60009F847A976EBD23F1E6C502E0B70343780D
+:100E7000D357108BDFDEE7940EF646E20B91D68354
+:100E80005FF56E030977C5C21F39DACED7E7C9E926
+:100E9000EDFDC6D64AAF6A7F2816DC4F13DA1F8DE8
+:100EA0006B677B99FD51D006FEA7A6755452D136CB
+:100EB00095FD9C05FA6B5AE440FBBBA96F2FC6CF8A
+:100EC0001BE71219A651ABFA87B5751E35B2381E4D
+:100ED00095590188DFF738433BE17C5DCF2A2D8FA0
+:100EE00087E5B5287D9C9AC7A3E57D858F80FFB3F4
+:100EF0008793D00F3A744E8FEE3FCBDFB9B83C30BA
+:100F00007B91D70D96F8F4DCDE7F4B98763179B47F
+:100F10001FF5409E6CDC3C5A25780DD45B602FD4C5
+:100F20007A4003AA2F6B658F5582FC9DE17A81DAA6
+:100F30009D963E4E1DAFFA9A393978BE46EDAFFF09
+:100F4000013847779F95448D17393F41D73F989691
+:100F50003649FB7EFB02E8EFC1296A59F9FA17907E
+:100F6000377C9F31BA3F4419B53D14B4F1D29E7E0F
+:100F7000ACE79E99C37A3BD5E3FF317FDAB0FEBE82
+:100F8000E1BD79DD93E95889E267789E49D3C39B37
+:100F90005C2CAF568FE71B553ED6600955836ABD62
+:100FA00061D11A2FF43B94F7D6BFD40376B096F7ED
+:100FB000D6B4CE8BE79AA8DE7F4F3EE4D1FEF1F4A3
+:100FC00087AF10B0334FA23FA0E90B81F99DA9FD77
+:100FD000C0517CB1F4DF8FF843F618FDE0DAE97117
+:100FE0002A04F0B1E700370DF08B90E6CC6B28ECCB
+:100FF0008FE77B7A601D67E2C4C79FCD67767B531E
+:1010000041C5D63C80F5631C017DBCABE053B42BDD
+:101010001A5F9C332DF21CDEAABE07D979AE3DC6FD
+:1010200098EB7E369FC7F535BEF81CC64F4EFA3991
+:10103000A4B995827F13D89B2B571AC0B222A5FE64
+:10104000A598274B169908CCFF01D50E69DA739540
+:1010500002E7029BE87F9404C836EF8DA86F6F5BB0
+:1010600064B1411CBBA9A0760DF23B31C103A69C23
+:101070007E9E43F96F6B13308FA6ABCF3817ECA46D
+:10108000324A17FF6403BE7AD8BD0BF8E7A8297C63
+:1010900087087986B1F5EF670A991CEFE4BCCA8F1F
+:1010A0004B312E4222F399C7F731FBEBB57C5354F9
+:1010B0005CF0B57C6617CE54062B01D75E164289CC
+:1010C000600F3711CF27E0F7225E9B847121124019
+:1010D0007FA0EB4E09ED268B2B74F764A89F29A007
+:1010E000DDA4F911CEBC9886FA584981EF30E0456D
+:1010F000191F7AE0C700B7BB0535BEC4F84AE655EC
+:10110000B629605F195D4C9FB1527D06CE7B5CB6FF
+:10111000E9F8BF56026F7579518F2054C8C1B9F1F3
+:101120004A0BC7E22B3ABD99887215B4AF56FDD26F
+:10113000B974B73EB4206A769E1F05FE0C9702F084
+:101140007E9D2E6014AD9F433C9DB02F5FAAFBB7E0
+:10115000D9C4F4F5CD060BEAEB9A3E9CE81A443B61
+:10116000B121C0E1380D05BFC6F302ABD5BCF4A177
+:10117000FC702184F9F2A7F313D5F86727C34F3227
+:1011800088FE30F20CDB07AA79621EBD06772DAF10
+:101190005CEBCFA4C64B1B547F2E0518D67F9EAFA9
+:1011A000C557DBA3E3ACEAB84490CA22FD8E9B6B23
+:1011B0000819C479490E986F57AA9714D0EF8F5227
+:1011C0003C063C3BBA31D10FE7B63673831E887BB1
+:1011D00028252C9EA1C7A794024E3D1F14AEC6BC65
+:1011E000AB17E39C0FEA8B3E1F44F9C39ADFD07123
+:1011F0004A4BDF9301BFEF73AAED2F27984FAE3F05
+:101200001F34BA40C271FEDBCE07C99CA7973E735C
+:101210000A9CECFC8F763E486670D7F231F4E78288
+:10122000CE64040596C71FDAB91BE59E19EDBB977E
+:101230003E3ED809FEE2B3252619CE43A45EF77AD6
+:1012400027E6C5704233C415F5727D97BBB218E02E
+:10125000FFE035CFCB98F7AB93EBF1EC798C794687
+:10126000F87B3CEA7E7C5FF6BCB5FB7307E0CD29DA
+:101270002EFC73C847550EF031F3516F28E0E2E4BD
+:101280006D791645EA999D5ADE9633212A8FB1333E
+:101290004EDE563CFD5D889BAF7539EA619D43F992
+:1012A0005A73353D2C3A1F554CF846BB571B7F6E81
+:1012B000C81D155FBFE582D7A9DA2371D617CFFE07
+:1012C000BAD87C013D1C3AE3C8C37505F1F2053C70
+:1012D00022C4D73B21BE4E9F024714F483ED1DCAA2
+:1012E0001708A2DFF7B97CF45F99E3E60BB03C3254
+:1012F000E140BE04DF6D307A3D6097287B8D2A3F48
+:10130000F73F09FE8FCE0319E82F2305A162E07392
+:1013100082B33A1DF4A34E153FEB2F3C5F6073413F
+:101320008C7C815DFE293FCF6276F06022D5AF765E
+:1013300011266F947EE69FA4F346FF5CF8DE71A849
+:1013400077720B2CB88E632F9B7BCDA84FCB18FFE9
+:10135000AF4DE74590133D35651F821C3A46155049
+:10136000A0E3BA9BD6A11D1A6F7FEA3646C763B5C4
+:10137000F717BA4FCFA9FB7414EC7414980AFA7DCE
+:10138000576EE45EC1BC5B5D3CF805E021C8EFA38D
+:10139000E3FBE7ACB331AE7ADB2F6A309EAA9DA3A4
+:1013A000D5CECF12356E226D1490DF4B7B38BFE463
+:1013B000666462401B5D34E07D1E544C6D03D1A613
+:1013C00050AAB984BEE60C1CE89B52272DA7D17504
+:1013D0006D129474FADDAE7713D18FBAC125A9E7E7
+:1013E00021981DA5DCC3A11E47FB453B58E9A47805
+:1013F00043FB79A780F9F7CF16303D83A2881FE71A
+:10140000A33E3BD57C086DBC366208C2D3C0B1E7B1
+:101410000651981B4B4FD3FAEB34365B206E121EED
+:1014200067C0B8E439936711C6F592F308D87D9D7B
+:10143000F6E68D73593DF2D073D6B017EB7F2030AE
+:10144000859F48C930DF37D5FDD0EFEBF2EEE8B22B
+:101450003E6EAFBF17A08EF8F233B2479E937F5314
+:10146000956BE7BADCEABEC818F7EE344AFFE60629
+:1014700039B7494079DA3696C1CD308E3DB39C55A7
+:101480008B509E3AA99E89F365F3CFFA818B03FABC
+:10149000EB7432FCFAAEF3D6CFF7F3823CA63F8270
+:1014A000F24FC7EBDCC4F919BCD8BC2FD4EF9C5267
+:1014B000F8FDFA9D8F71F2E341C0339BFF61F0DFCD
+:1014C000D5B59945E067A73895FE37F1C8CFB6ADD9
+:1014D0004CC6F2D18DB9E8CF19A2DB13EBD7C07D92
+:1014E00007179A7F955FC8F0E2773A7F5A6D397790
+:1014F00018FAD1C31D104AD0E40F6D5A79555135F1
+:10150000F0C7460391D2401FD8A8CBF3D0D1739532
+:10151000E49B5608FAA269F020E353A13C01F56868
+:10152000AB0C707BD0706CEF6F015FF65A316FB00F
+:10153000715DF871F03BA64ABE998514CEA7D7BE5F
+:1015400057CD49D81DDA5B670FE4E3FD19B59DBAA5
+:101550007B09EE89CE2F211B9359FE464FF47B3831
+:101560003F1FD56E44DE09D33F379B7C856027CC77
+:10157000BA8CE5EB7DBCCA40002F3EB632FC51EE82
+:10158000B5AB7246CE8BD44F1717EAF4987BAD8873
+:101590001F75EA7925FD7E34007ED07DAB57F1E3DF
+:1015A000E3E72EC903FC38BDF7923CC08FCDC66E71
+:1015B0000FDE2390E3FB29C0F1F81CEF4103E34B5E
+:1015C000791783B7F5FA79FD9DF4ABBB0BE3C54DF5
+:1015D000A49F44C64D068CCCDFA558A3CFFB0C5C62
+:1015E000A47F34BE9FAB3027DACF55901353BFB2E0
+:1015F00058BF51BFBAF875103CEFA5C55306ECE1D2
+:101600009F3F1E01AF162BCB2B69291445A504D68D
+:10161000579B8DE7C7FE68917BB9EF759D51FEBC66
+:1016200097BFCA5EDF0DF3F030FFE3CB8274F05258
+:101630003AEECB84F91FF5EBFE7D3ECB83D1EC6710
+:10164000CD9ED38FBF57DDEF8142CF4B601FCFFAC6
+:10165000EA3CFA034EC03D39745C8BFF9FD02E23C9
+:10166000FD9C88E7CF2416CF6C7C71F9A3E03F5D29
+:10167000E557E390FB38B4BB573DF609D69FE9AB7D
+:10168000C37A5B3F17847866D35803CA6D2D8F41A8
+:10169000F3E334F5CF2680A79A1F87CEE30598475A
+:1016A000A22B6C42BE0576226DD728B0386DA38B75
+:1016B000C80AB0DABE68FF8796E7B4CD6B427ADF1E
+:1016C000D6CFF9C1AE4E35F9DC63119E63C50F1359
+:1016D00087F9C65B859ECF805F6979684F677B0E0F
+:1016E00003BDBA4C2413F3DDD5FDF00DC577D879D1
+:1016F00089BFBCCDCE4B84E2F0EBF70BB5F3120BF8
+:10170000517FFE0BF126C5CE23F7B33CF2A1BC35C9
+:10171000962F5E3F8FDAC84E56867B5F1AE0DE1743
+:1017200099C9CFA04E7E4696214F2C18C137EB8524
+:1017300041CC47D7EE7981BCB1C8EF1BE1BC45363F
+:10174000CB1F8BEA47E5A769FCCD18C789113FFD80
+:1017500049A4FD7148B3B34AB4F3316113F8695A2F
+:10176000DA5C6188071CB2ABE776D5BCD8166BF89B
+:1017700018F8315A9E4CC3732043FAFDB366D50F57
+:10178000CEF0BE9EFD9334AD3C8AF67A139CCFE733
+:1017900086E9695E5CBBEC8D1C88AB1C1AB2CB5E23
+:1017A000CF8173341A9FAD9719BFA8EFE3D879AAF8
+:1017B00040F4799A3113BE5FBEAB7D17AFFDF409DB
+:1017C000F1F8EDB7C199F1DB43F1CE21A97C528349
+:1017D000A39E1F5D2CFC86E492063F4AD7C86F7516
+:1017E000F0D3FBC334BF16E914D1EF45759200E482
+:1017F000656A7EAD0B9587F3BFE77DB95079D83028
+:10180000219E1DFEDDF6279E9CB8D87D19210F6113
+:101810007F8AE3CBC39CF27F51E7ADCF2750E7AD82
+:10182000CB2738640CCF67F75150F8B847E613C49C
+:10183000C5BF6FC927F81BD6A9CB27F8E675EAF311
+:10184000091E39F09003426E70EE0CFC0E03BB8D46
+:101850001847AFE66D1E96E7C5B3BC50E2C1FB3139
+:101860009B2C56F42FE8F3E028A75ADF0CFA6539D1
+:10187000D5FBE15CCE8E0E94CB0D193CFA1C21EF0A
+:101880004F9462E4590A3549416964BE17E4B1E3F3
+:10189000F9FE8BCCF7DA336128EFD2FD37E65D062F
+:1018A000265C40BE57712EA3BB576D9F8D8ABCBF6F
+:1018B000B2A2881AEA45F1F3ED5F56E93551CDD36E
+:1018C000B5080A89F447C56B777002B3775E358532
+:1018D000DF0D805E45BB81F865BA895AD3A5C3E7A1
+:1018E000D68FE77B5F87F9537D04F7F7CC8BEFA0AA
+:1018F000DFFE910C2242FEFB234605F75949218861
+:10190000D75A5E8236CE5AD58F7DA1FCE7C8DF5903
+:101910002EFCD7FF74BE33227F89D1E3DFC06F90E6
+:10192000FE86F88991C575B47B2BBE55CE7DDF7CD4
+:10193000469777116F5D5FE613C487F113BD1913E6
+:10194000918E3CE867BC58F997584AF52180C73E0C
+:10195000B304A46651EFA720F764687E5176DFDFF9
+:101960007DE350EFFCD8CAE6ABDDBBA1AD67CAC4CE
+:10197000EFD78E2DCEF1964EA4F33E3EDB83E77774
+:1019800037D899DE167E92E5AFEBEF91A074C3EEE7
+:10199000D550EFE1D59F87AFD6CFEFEF24BF974F5C
+:1019A000FC1F4E471729BF2F7E1DD1F6EC213BCBE4
+:1019B0000F1CB667FFDBD67551F25ACB172EAB184A
+:1019C00054FDFD1C017FBF364ED3203B6FB351DD6C
+:1019D0004FEDFDEF54FFDEA1899E4D4087A5A5C1C7
+:1019E0009D70EEA49138F01EF1C6C0ED7BDE74B19F
+:1019F00073B4582E607147E2B5E139EB1DB9BE07EB
+:101A000018FD86D6037D8E779132881B74152C20A5
+:101A10007536CC277808E860FCBAD0CE374B319FBA
+:101A2000AA19E855CB272E3BFFD9FAB9A5385FF4A0
+:101A3000FFBACCD1F76FF44D64F6A0F67C4EA50347
+:101A4000BAED19309FD32BD9B9D2269747043FB2AC
+:101A500016BF4E940631FEDFB88F194565602B42E4
+:101A6000FD1D6391BE1AF7CD2E81B82609584BF0A3
+:101A7000FEDD3FB17BAF4FAF1D8DFEC69202DF2F63
+:101A8000615DF652FFE560478FA7E340FCF3F4DEAB
+:101A9000CB4B7C31F8661A9FAC407C388D27810790
+:101AA000C461BE45EDE7C5E82F5E1F463FD6CE892F
+:101AB000128B27BB985C6FEAAF21CB6DC3659B2B64
+:101AC000FA1CD540E19C9D308F9D13595C5FCBE79C
+:101AD0007453350CFC867A7C72ABF99C356ABE3245
+:101AE000512CC379CA59DF9ECFA9CD4F2B6BF99CDE
+:101AF000895F30FB3D4B3461FE877D23E3AB641D82
+:101B0000C1B8C1CCF060651285534E4F7026C02914
+:101B100009C08EF7B186EE9E4CDFBB460933C11F6C
+:101B2000B2B375CA00E8BFC2A6C11FC09648DD6245
+:101B300005B81877E47ADF033C21427301F0A58AE7
+:101B4000DF1BD979A34D89A857F664D6E379A3336F
+:101B5000EF9963DE27A03D15D29E0E7187AC8DFFF5
+:101B60008EF17DFB3E2EE6B9B44B8B6CEA79A4F680
+:101B7000748863D8370E2AE5B4FFAC7B39A29AD1BA
+:101B8000195C3AF8870503C8D7BA3E764F5D5DB752
+:101B9000B3C282F286F96BC84C17CA1161D395069D
+:101BA000E013421BD562E93AA714B1F8746E8F684E
+:101BB0000039F5CF5FF331E348E755BC6EB0844C94
+:101BC00000AE0673F860BA7B385F473BAFA2F97B83
+:101BD00086E4CFBEA5E8EFB9F8FCECF0F598FFF786
+:101BE000752AC657E639983D4205917A4F4B74FBEA
+:101BF00011F7B4A87A8B6617EBE9409FEF9C533E30
+:101C00001AE982F2D1C036318AEFC5CC7B6E1598C5
+:101C1000DE4DD7616A8179CC4E97C13F77A179E6D5
+:101C20007A7B7A48CF51F5126DDE7F6B5EB6565FD8
+:101C30000FF9D831FC1F9A5ED3A99D67FE9ADDA3E8
+:101C4000355EB5278E76FD5731BBAF50CBFFF0E345
+:101C5000533052FE89F813BA4C013CD8E73434169D
+:101C6000617CA911FBD9C4EEDB1FBF31BBBDBC1425
+:101C70009E22E128BC8FEE5F3D1EE3B7942E726377
+:101C8000D0C5918946D6FFA644C463E17E82D98C33
+:101C9000823315F1587890E1EBBB13197E69F9672F
+:101CA0005A1CF0D0449F17CE1B0EDDAFD19AC0EE68
+:101CB000D750F3B8EDADEF3D0BF756EC54E3C0034E
+:101CC0002F4F5C80F1B94D0207F6E139E7D2F1E020
+:101CD000BFBBBE88E1B95D1824A22D925E07F01C3F
+:101CE00060D601767E4950F34D854DAE5D809F16DE
+:101CF000B70FCF3BFEA033C8633E9378FC81B91287
+:101D0000D81D6113E49F9D6C13C2ED4ED49FA2FCBD
+:101D1000647ABF171102985FD354F4F7B543EE2DE0
+:101D20008AEB9FFA4EE728C8B7F8A7BE2B5EC7F329
+:101D30004F5DFC3AF4E727987D425E66794A31D6DA
+:101D400015E5BFFCDED7A5F92DF5796723E898F9ED
+:101D50003F347B488B3F108F1295173E601483A051
+:101D6000F7409EED7332E8D54F5823F3C29E57F1EA
+:101D70007EE8FE3EE2B7C2B9FB8FE1DC30CA3B79B8
+:101D800023C4416FE7EDDD60DF7540BE3EE897009C
+:101D90005F2EE2DCC2FB76CC7B6815D8B906A2B018
+:101DA00073112DCB9B9F80F62D6D6922C05FA968B2
+:101DB000FE159E7B30106F077D7EAEFEFE84361FC3
+:101DC0002D8F3F9EFC1C91C7FF2DE71032E29C43F4
+:101DD000785BC5FB826504CF21908D9E5D30AF9E00
+:101DE000368140BC37792E2B8F172CF87B2856C8AC
+:101DF000871E85E746316F394CE109F9D756C88708
+:101E00001E05E744D87D85DC82B9887FC9143EA0D1
+:101E1000177418D9FD84CA3536C4A7CAB92C7E995F
+:101E2000EC3521FF394B64CC9F57E01E3317E05946
+:101E30003BE267D89E8AF1D7E41CA6475ABD2683A9
+:101E4000C58DF9CE88AF614ECB77667CAF67A9842C
+:101E500079E843F7152E27B83F9B72AB33E0770044
+:101E6000465F65E2205EA3C9990A153F7A76A9ED1F
+:101E70001B587BB8CF10E6475A58FBA1FB0C7FCA12
+:101E8000EA5B8510DE07447518F53E3D56DFB23833
+:101E900015E98757CFAB92EBD47C7B8EDD1FD5B293
+:101EA0007834AB77303E486E4A50E5B9DAFED664F6
+:101EB000BF1A2F6079F3AB0CEA3D00DD24329EABF4
+:101EC000D159F2B79CBBF8C570FE3CD273C7E5226E
+:101ED000E6076AF73156D84CEC3C96259AAE9E2917
+:101EE0004A66785F2E5B60DC656E4FFAA498FCD181
+:101EF000BF3492AF8CD6F8CA4D269D5D96C6E0EAF7
+:101F000008EF64E7B6CC176597C58F2B3E99111D76
+:101F100057DC93111957D4F6B762A509F94A8F53C4
+:101F20007A0DF28FB651D0C2FD76FA756F1BBAA743
+:101F3000DA6F05BD546F0F1E8A9367B46812F3E71A
+:101F4000C971FC108B26C5932F71E2B425E6FFA65C
+:101F50007833E3BF0371CEE90DC14BD39B2CFAB8A4
+:101F60008772517E9F01CBCF900F7A3A0462BD8C6D
+:101F70009675E7CA281F44BEA8B49BC50E17F0D1BA
+:101F80009F215F6CA596AB39822F5273F412E0C784
+:101F9000037716E0EFCBBC76A78CCFB3562EC04F9D
+:101FA00086677809684C4B8A0F2C847B9BCFDAC3F9
+:101FB0009970CFF3BAC96F5C8BE594F01128DF51AB
+:101FC0004C16613937BC13EE7DBEBFB8FD5AB8D789
+:101FD000F92CD0D868426E7DF6B66B9522FC3D8414
+:101FE000F583A0DF97EAF2F175F7D0C2B951584FE7
+:101FF0009ACD8471DF34F5BC2EA952FD4390E905DA
+:1020000074975182797A3622ED1B84FAB14CEED264
+:10201000FA36B8E7B423D7CDE2D084F1013256CDF9
+:10202000E3202105FC511D6E27B61FD2EFF699D58E
+:102030003C3036FEE1E7D8FD3CDA396442C47160D9
+:1020400037DA241255D6EE752682380EEE61ED5041
+:10205000F1402BF7A7F91E9A1461571E9E737B114E
+:10206000ACF3E3E7EFC8017DEA87EAEF32E9F1EA92
+:10207000C6C90CBFDB13FFBA04F8F8BBBC4306FFAC
+:10208000414B9A6F17F4B7DCD536CD49F1A74A9C7E
+:102090008DBFFF324359CC015F715ECDE6E7ACF2F4
+:1020A00072CB8B867F1726C527A09F9EF87A78D0A3
+:1020B000B7538E7B45804FBD259C29D07EFEE4F230
+:1020C0003D03FD9E5BFAC16D989737FAF011B81F7A
+:1020D000F2B0B1BBD201F8E456EF03A63B06E763CA
+:1020E0000E8E19DFABFEBE0D3B2793CBA971D860D6
+:1020F00015C8852B08C35B2843FD95EA7D67D5226B
+:10210000BB3FB3BAD48DBF57369F8405C087EA77EB
+:10211000BD0E02F471B5AF34D6FD13DA93A41BA53E
+:1021200048FAB95C8A28D3FFAE2C882EFF488E2E41
+:10213000FFB8FCEBFCA8B2E07963520AC837267FEF
+:1021400094E94CFE8824D00EF2F1A966710AC6D536
+:102150005D9C02E5892F8CC6BC2492CEF2192638EC
+:10216000B2FC0C0ED9DB615D612AE77B5DF0BB47F9
+:10217000EC1EABD4774DBBE09E042249DB810E9F61
+:10218000371660DE66AAADF69FDA509FB1935CE425
+:1021900053D276C46BBB4582DF6F78C5CEF2113A5D
+:1021A000EE3760BC8973580C1EFA1DDF2B30F96FB7
+:1021B0005F5909F57C19DD102AAB079CEC77943A3E
+:1021C000A611637B09EC9BFC2EEA45760BE6ED57E6
+:1021D000390A7E02F5BCC384F73ABC622FF3A9E347
+:1021E00011E8FF31FB4A6C0F3CDA48E977C0CAFCC2
+:1021F000EB3CB58FDBD9F8F87B69FCCD441DDF42A1
+:102200004C50AE2598873FE014D97C6F35603C0474
+:10221000EA2FC3F959B05EBB8770F8DCEB6C01EFB5
+:1022200063E7881A1F6BC3F2432A1FEC308AAF00A2
+:102230009E2A7F2604F6A3CAF105D2016F70C878E2
+:102240006F8E87E4B85209F359D0EFF9543108F989
+:10225000ECFCCD0EB49B41F3817AF02110A46BC14C
+:1022600043CA54D70C8EE7390A783C9E235ED88F38
+:102270006B8BB3901F3D6A38BC05F32B6C5EB34C7F
+:10228000C7315D47707FE5C4D8E75DF38A199D8E3D
+:10229000DCBFB274C8E3E01CE5123C3BECE5129CE9
+:1022A000DF1970CAE9DE88728C7DF103DE0CEF8BDA
+:1022B00025682886FD9025D02FBEBD3F5A6F83F537
+:1022C00048382F7EB42C811D9AE3A0FD50BE2F8F7D
+:1022D0008ABD8E6BD57504D4FBF1F4F595C586EFF8
+:1022E0007B9D3AFCFB8EEB4C8D5EE7F738CF10F709
+:1022F0003DCC93CFA4F3B30DCF8FFE13EFEBBAC257
+:102300006640FCBA42BB37A920FADC85FE9C0595E5
+:10231000C05B81CFFC50CD1FAD48FC47F4E35F4E5E
+:10232000F57C906B07137F9603F99BD5496D9D8CC7
+:10233000389A4F2F077E6CE190EF5C4982EBE1FD0C
+:10234000D9D9BE479CD9C8F75717C3B931DE979F73
+:102350004CCB1F1BBB73D6B8912FD6C37B1B092355
+:10236000DD5D01BF8F067437CFDF09653A4633DE86
+:102370009F45E910E856A3C391F3A77449BF1FD343
+:10238000ECC0734D3B48100FA6A5936E8EF95B9A77
+:10239000516E1169DCF03A29D1565B9A711DBF6DFF
+:1023A00053503EFCD0F98000E587655F1BCC6BD1B4
+:1023B000E44FF0DE7B92BE341FEC4E3ADFF6FF971F
+:1023C000F31D79DEFC9BCF51FCBDECD1C78B599C32
+:1023D00043B3475D09549FA0F39438874CA8FE3857
+:1023E000649F1A2D9897307C3E375C87E780B9242C
+:1023F0002FC833ED7CAE9EEFCEBA8CF1DD8FD7388F
+:10240000E476BCAF700FDAA54D57DBB4F3BBA87F01
+:1024100035AD34A8E77739942B8DC482F7070DFDCD
+:102420007E1CFDE352877F9F633F9CE32DFDA673D7
+:10243000BC129E1356D6B138FD907DD72032FB5585
+:10244000FB9D875BB3B4FBF8999EB2865C907D1BC5
+:10245000E37C2FEA8D24C9A0DAAF4C5FE8992E897E
+:102460000AC1F82AD3C3179BB07E73821F7F37A59A
+:102470008EEF4624F963B153BD17C16FC5DF5732E4
+:10248000C979C027B438EBC21CDFFB80BFCB8B3CC3
+:10249000991C5D4A9D89C54F291D6C1FA4ADE6920C
+:1024A000E6C7E0F7B32E27CD6F1BB2910E8E221D2B
+:1024B0004CFC84FDAED6301D1C2B86FC06C2FC01F4
+:1024C00057A871A2973E7EBC13F6FD2C47D8F9AEF3
+:1024D00002FDF92EEFA9629C5F48FD5D9D68BE1369
+:1024E000318FE346360F17CFE33C3E8B358F1174A7
+:1024F00048FC383EDDDF663C47AEC323FD7CB8FEBA
+:10250000DBF1BCFFF6EB89C84F07393E6805788ED2
+:10251000058CC88675FA0C93A7A13CF7C1FD669A95
+:102520005D3D62DEBC0DF775E1E2A13C9DF91965E8
+:10253000102762E33E94D8F820F83D9AAE37227F08
+:10254000AFE99F847ADA41C52C421224A962F93599
+:1025500032FD1FCC6B11F1CC71D27EAE126BF0BE8E
+:10256000B4ABE7E9F37294BB9A69FB6BD43C9F85EB
+:10257000571B8F46EA9B678DF718010E4A9DAD9950
+:102580009F01FD09C3EDDD23E132E2BEA64EC69FE9
+:1025900008D573A0FF8EF200F2A7787C2A6FF25064
+:1025A000BE4FFEDF98EF533C19F1E29BF37D64359B
+:1025B000DFE7356318EFE1FC4DCA8AED6BE83AF3CB
+:1025C0001F2EC2DF139D93BAEAB1FB69F9896D131F
+:1025D000B0FC9BD4EB6F390CF53BF3B05C65F86451
+:1025E00009D04341D9E22BE077585FB3B27ED213D2
+:1025F0007C3D35F4BBF4E2AC2970B14B95298CDFFE
+:102600005D39B9612AF863AA1258F950C93B53B031
+:102610009CA596A7BC3401CAAF719F2C89C517270A
+:102620001670C1422A6FAB92D9F7F3A63C391AEC67
+:10263000F8AA0A569E28CFDE940DF5864F97C4D28D
+:1026400097AE9FCCF8EAACAFCE768E72415898FD2B
+:102650003EE80B9E0FF07736BC54DEC2397C6F39F2
+:102660008BC3793D2502FCAE538587952B6D6D1983
+:10267000C007E7FB4CA51077156DEE4EF8BDC2A460
+:10268000F2D9D360DF2BA9BA0D714E4A5F37009E95
+:102690002FBAE4934C07EAA51A7D8946787EC37D5C
+:1026A0008BCBD8BE45D303ED6F15F67769B4FC1C10
+:1026B00041AF3A3CBCC23296E11D958BE6F291F4F3
+:1026C000AAE7DF647D808BA4D71D80973CD2ED5AAA
+:1026D00018DF641894E0FD784E9E207E03FD9E3541
+:1026E000BEEFC638107DC15F1A836FD03F41D3F370
+:1026F000D92C443115F397595E4FFF3BD81E8E837A
+:10270000F01938FE26189FAC67F3D901F790F060F6
+:10271000EFF91E053ED198CE7EF711E2FA40A7E907
+:102720001ABFEA8B5E6F47B97C93931F395F83852D
+:10273000C1F16A551FFB7DAB37A5844E7621693602
+:10274000C27A1F4A742810CF6DAA65F74906D27C59
+:102750000FC33EF106E540889697138F89F137CF76
+:102760007698A7B62F8DEABE345ADEC77C36F8833A
+:102770007B4E46C0A34FCF47A3D73FBC2F8319F052
+:10278000CC807B54B2619DF2463EC67A88D0BC298B
+:10279000D24FFFD0B7FAE909F3B7C866F55E94F0F7
+:1027A00092487F5C87BDF991483B999A65789FD1A3
+:1027B000A1B61C120BEF343DE910A7FAB5A8DE0B49
+:1027C000FAC0E7097F45FD84528CD798097EADF9A0
+:1027D000A8C770268B08F1EBF4DA74C4D72D542FF8
+:1027E000013FBB5211C8467FF94E9EC0FD03C37026
+:1027F000A033710FE3E7F1C9CC0E4C1B8287827CBA
+:10280000D464E062EA57C7271BD47B50D9F9D2467B
+:102810008B99E57FAABF4BA1E5B1345A8AD637E33D
+:10282000FA2C8C7E74FB3422AF459F27674943FD09
+:10283000429C4264908723F360F4768282EBF8D165
+:10284000507C8130FD67AD1DF59F1FA9F1056EC15C
+:1028500017B83FC914BFCC2E8823481CD82BC9A554
+:1028600087053269F87724E1F797C09FF57C96EFEA
+:1028700093C911F1F837A73D817921470C2C0EAA95
+:1028800087CF5743F00961BE6AA3C6AFF4EB8F331D
+:10289000FFFE34EF5F61BC8FB9C132A8D4E253545C
+:1028A000ECBBA1BFFF0B8F9234BF00800000000083
+:1028B0001F8B080000000000000BE57D097C5445DB
+:1028C000B677DDBEBD25E9249D859010960E3B129E
+:1028D000B03B21618726408651C000A2A008371076
+:1028E000D6AC82CEA0E3980E0144079D38A2328A6E
+:1028F000DA202028308D02A246A70544FC74346EED
+:10290000E3FA98C40551B61844719E6FFCCEFFD40B
+:10291000BDA46F13467CCBEF37EFFBF0375339B7CD
+:10292000EADEAA3AE7D4D9EA5475923B6B5492474F
+:1029300008F1C38F3FFE982FC495F4A7E82644639F
+:1029400037CDEECD13E26A5134D6AA08913C4EB38E
+:10295000692E21C6AAF47F038468D9A6041DF47CDD
+:102960008C3FC6225285A83C640B06095EFC8A2A6D
+:10297000002F7E480D0A825B84776D23DA071CEEF8
+:102980000095F7C7F5FFFD302A3F7DC8E675A0DF4B
+:1029900080FFADDED46F09FA25B8D75A8BF0380521
+:1029A000FFFB91FED727182B3CBD5BE1BE5B924D30
+:1029B00070BF500753FB4BF77635D5FBC29798EAAB
+:1029C000730FE598E0BC8621A6F603DF2F30C183A4
+:1029D0001B2F33B51F7A74B2091EDE7C8DA9FDC88A
+:1029E000B3B34DF5A509850797D27C0FA6AB421965
+:1029F00024C428516A6A5FAA96D98585FEA8B37D4A
+:102A0000D248EF55D17F3F7625589D61059ECFEC8A
+:102A100055444A9610F3D7CA7AE3BD05F577AFCC93
+:102A2000A47261D0FCBC54585B617A6FE9C70BDFBC
+:102A30003810D15FAFD4624B1295A3BCF1A947FA0D
+:102A400062C262E08F2AD3D51B069DDE51BD0E49BE
+:102A50000AA6F3E2ED4AF00EA2634FD1E37ED08DD9
+:102A6000E82C821ED055D6B7AC538301EAE7BBEA07
+:102A7000056F1CB0117C28776D23D17F7E8DC3AD8F
+:102A800052BD23DD4CCF188F999E71BDCDF48CF7CC
+:102A90009AE99938C84CCF24BF999E29E3CCF46CAD
+:102AA0005764A667FB69667A6668667A662E30D3D5
+:102AB000B35395999E5D969AE999155864AA8FE645
+:102AC000DF6EAB169BEAEF8F7BE188467848EDA07E
+:102AD000BA1D6E217AD4DD6CFA9E50C7DB5710BE4A
+:102AE0004A3355A1BA5BF92040FF311F882A5E5F47
+:102AF000F3880F1E203A9C11AB0F667ACEE7878AC7
+:102B0000BD77DBB13E7F2E3F2C8BE203E2BB447CE2
+:102B1000E747FC1B797E69D0F90AAB7F95B79D101A
+:102B20000F7AB5DFA19CD6EBEBCE56921BA2A8B8CC
+:102B30005751BC102ED13C13FC542112BC77A07409
+:102B40007E9C057EC13F4706FD9F5F74B712DE1471
+:102B50001D6F62AFED78A3312E9AB752FF5E16E675
+:102B6000BD8E985145FB892145D0F83A8A860CC81C
+:102B7000A70C51A5A04C17DE552AC6EDE99484791F
+:102B8000E0CF1F3399309630BDFF41898DF97759D9
+:102B90005CFF6DE0CBF76B255F9E4693C1425C23E3
+:102BA00042367CE783D8073BA1BF0242B832189572
+:102BB00075D761FC33307EAF10D789461B3E3E4B44
+:102BC000083BCA62E1E1728EF0DBF1FE5C115E89C6
+:102BD000C97C94AA6D073E2A54AD4B1AF0D1B1A11D
+:102BE00073513F2A5F4BC1A02F8857505CD07B6F39
+:102BF000E34F6AF789B76837BE33DAE9B9E15EC2F5
+:102C0000CF3E8B581022BA88F1293C6E612DEA37ED
+:102C1000B95F5BDF5946424D88E7144D03BE031987
+:102C20004EEF2620393DF4A442F3BB24D9937347D9
+:102C3000526BFB035E0BB727D60B28D4FEF15DB1B8
+:102C40008CAFBEEDD727635E3FB7DF06AFFF558C75
+:102C5000DB68FF53F3B5DBBD8B6EA47E9B1551B5CE
+:102C60008106F18E4E974C07F10F8D37534DF0D6FC
+:102C7000826E71330FB6233C2C69AF7D00BD34EDFD
+:102C8000EA5FAE04ACEC4BF12CA6F19D2A6ECCC7EA
+:102C90007809FFFF86FA3227E19FA676A293D62B0A
+:102CA000114C5124F14F7FF42B6A73FC723C077472
+:102CB000FCD7B7D78EE03BFB2C0D9DBDA0A3B52163
+:102CC0009FE9E896F33A619778B9101E0AE23ACD87
+:102CD00000FE4B1C0EAF4AF82C50E4773F4B9C355E
+:102CE000B392C63DD7529416564DE3FE06782B7329
+:102CF0001577C9C0B86DFAB89DED74BC7BB2B1AEA2
+:102D00002E34EE5A7C9FF014F8AD12DC9485E7E186
+:102D1000AD809F166EF71D3E5A7316A9979B6B9454
+:102D2000E006AA7F43C7F343366A8775E914C935BD
+:102D300034BE2B86AF588F76BFD39C3CEE4DC27B02
+:102D4000C99A2CD043B0BCCFBC4D09D6123C5B789D
+:102D500099EF4B4451E75DB00F7C5ABC8FC6F1B779
+:102D6000B87FE465597819E7BD43DFD9B3ACBDF747
+:102D70000E40C32E8EFF7B93E440FF932748BD3364
+:102D800057C7DB95A288D7E955A28A4B5AF0272A64
+:102D9000A8DD34FA0BEB93E07E18DF74C0BED67565
+:102DA0003D4334703953B89F6FA46FBD55D3FEC6F1
+:102DB0009BA8CD644B7367BB8A754AEB368BF1DFFA
+:102DC0001DE3FF76EC9B8715E0FD169263A0F79A52
+:102DD0007617C5C79314894F5AB7D9BE3C5EB7035F
+:102DE0007C9688F533A69DE43FABBBC73F5B3F2491
+:102DF000181332D284F8851485E2FED3092295E6B1
+:102E0000D9D0550D3AB2A0A76FB1EEA27936903D58
+:102E1000E1C0BCFDC51D4E51FD38D2B77748F91A47
+:102E20001F2078A25F1577301F342E5F48CF5F1BBD
+:102E300044F5D4FEE51A113F80E0977D366F2DF101
+:102E4000E1D8B3DA81442A2792DC0F53EBCBD2EFDF
+:102E50001E03FB605C47D223117AE2B2EE6698163D
+:102E60004247D0E9721DDFE3B3CD7A6722F48ED1F9
+:102E7000BE0DBD43F255057E27FB74FD7389B80472
+:102E8000FA677FF55EF129E917430F8DA61986B21F
+:102E90002FAC8762EC05D7806E447F3BD6C76C2B86
+:102EA000B507BEDD5A874911EB656FBEC274F2905B
+:102EB000E2B1D0FCDF38A406811FAB3F3C14F85BC5
+:102EC000FCBCC27CFA079F3617DF3B696B9C07BED0
+:102ED0006918969B28A8FF4FAA6920BD68FD563B3C
+:102EE000859FD6C2916A37C347ABD3B9FCAADAC370
+:102EF000E5F1EADE5C7FB2DACBF0B3BEA20AF0C342
+:102F0000EC555F5BB56CF45FC5F6D1921AAB00BDB2
+:102F100096C42F96B0CDE98610BEADD3414B1CC1EF
+:102F2000B705152FF4E2C25DC1957134AED27ABFF8
+:102F3000DD05F9D72979B40BEDEF5598EBE71DAA1C
+:102F40003A88E99E7CE793AB2688D6F9969F55840C
+:102F5000464BAE5B9EFFB798CF17D583785C5F5624
+:102F6000FB795CFEFAA68329F4BD63D5E3187EC71E
+:102F700057548B767EF135DB1113B6355961678C6A
+:102F8000F52B7ED079845F048384AFB536A957D6FC
+:102F9000925E811C18D56FF2433708C87DED4ECC88
+:102FA000736AF29CB1B057270E2A66FBF5EA1F043C
+:102FB000DBAF06FFFFD43AF288869399D4DF89808D
+:102FC000C44FCBAEB7196EB1127E68C62FEC2A2D56
+:102FD00015641FB49C7D4B3EA7766CA7EE96ED164C
+:102FE000DB64BBC5BB7F97CCCF15A55944E8BB6359
+:102FF000444741788873663EF419E1E7D8F65FA745
+:103000006B11FC752C39F4ED879093FF66F16E60BF
+:103010003ED53E7D167274B99BE5CC495BE8C8038A
+:1030200090B39D48AF727D55DC64E2B30ABBD09883
+:10303000EF84D617F0B15831ABC825FBF3F492CF2B
+:10304000C18F3D77DCDFF5379ED6FEB684E67EF88D
+:1030500000E8B0E3A3844B68BC7D541152317F215A
+:10306000C711D818CBFD943D797BB29FE0AD8A683B
+:1030700051594E04595EFCCE26A6A1DFDE8AD5BE8C
+:103080003499FCAA3B9FCEC4BC7BA9A24AA5753942
+:10309000E7AE67329FA1F71E2359A4D2F89FB379F8
+:1030A0004FEEC5771FA2F153BF8FDD599E037958AC
+:1030B000F2878597000F7F81D0223A3CF1F44EB61B
+:1030C000178827BDA349AEF55BF3E2B20C6A7FE92E
+:1030D000BA264B072A7D1B955A94A5DB76BE55432D
+:1030E000FDE5BA2D55B05FDFF279785C39A1F51BAB
+:1030F00014E8811F1EED807599BDE6EB820EE2C2D9
+:1031000076C6139DDF6F29F6B05CE0F777D74F796D
+:10311000FB5A013B862C188CB7D8EE65BD46D3B65A
+:10312000013FBBBAADC7FB7B2C01D65781D9D2CEAC
+:10313000395114F823E65F4EED030497FB1A9A6E9B
+:10314000A2FAF2A4AE2240F33F1A5C321DF5031539
+:10315000E1067E2A76DD5BD881E013C38457A1FEA9
+:1031600017EC3E5DC8FAB013D9EAF8DEAEDAB46BFC
+:10317000A00FB30BF254AA2F5243DC9FA894FD5525
+:10318000D6EF740226D427ABC46749F5A3F6677A55
+:103190005AE96369BC2BCB4ADF6B47FA14E35D9BAA
+:1031A00015C8A872B5EADF645FD169AC1BE1BEA7A0
+:1031B00018DFF99CC605FBEC62F5A5DD52B590C79A
+:1031C000932EDC81C1ADDFED64092FC43C6875B876
+:1031D00003F49D4DEE86E9DC8EE0DF73BF9A9A938F
+:1031E00007FB8AB09E2AF57B2DFA754FE90C7A5DB4
+:1031F0006CFFF7C7FD83EDB44A4B82D731A0D5CE23
+:10320000999652FB7C23D12BD85E4BCC6907FB5897
+:10321000DAC9C2EAF540EE57B7F7BB73D84E233D83
+:103220006C61FD9B9A1361379FB3DB9C17A77F43AB
+:10323000EDFD1DF0BD8B6DEFD1E312E7E4F0991CBD
+:10324000931CAE8DB70B1F3DAF5DE3E03886386051
+:10325000293B48FECA707CC2D2FABD25F139EDA1E6
+:103260001F6A8568135F2FD0FAD708B761D21B1A7F
+:10327000C98111679B558DE544C3FEC40190B7C257
+:103280001FEF41DCC022B408FD18FD1DA2D760CCA1
+:103290006F9488135A849EF58B243BD6AD70255FBE
+:1032A000E4BCC38F9AF5CFBE4723E73DACE5FD38BC
+:1032B0009860848FF6282F34AFE7F579FD19F3A2D3
+:1032C00072677ED1E5A0DFF06FDC56CC6FB8755227
+:1032D000675F571EF7243C1FF18DC53CEE1F624D02
+:1032E000F0C58EFF46851C3BF0F1D7F620D65F3D3A
+:1032F0006C059A47FDC2EC20D6FB1EBB0838E1F7EF
+:103300004CB6B31D5C1F1F88875CAD57DC21C49F82
+:103310009EB3354C977E91706FF2817F5F7F10FC7A
+:103320007F4D8B5D413CAB83431C817D25D444B1F3
+:103330002935E2FBEDDC1CE750A13772091EAC3FDA
+:103340009F6EE7E7B536C17A32303D96C7B526A9FC
+:10335000EAD57E54BFA626D34B2317EF8BE0AAAE47
+:10336000A8BF4565793ED4B261D37DF07B26A5B375
+:103370009E599314CEAC44FB85977803C40F7BFE13
+:10338000A1B2FE58E3F36724BB200749CE139DD7B3
+:103390004CF267C4A6A24CB360BE1D48CEF3F32C1A
+:1033A0006A47E58736D9EE039D6E84E90CC8DB07D2
+:1033B0004A7A08963F390577F03AA10A27F1F35483
+:1033C0004902317DEEBDE226B4D3D4A09A05BCDC1F
+:1033D00075674F82AF99ADBA11A79BBA20A649E98C
+:1033E0004FA5A6861D09F4C29563FD91FEFADA1C6D
+:1033F000FF1DA07379A84FB7CF22F878FADC1EBF63
+:10340000827CF884FC68F8DD77A4697FE0FEF7FA37
+:10341000B8DD5E326E7E849E707AFAB3BD5D62F86E
+:1034200099E139C0EF0BCD4EB6632FC40F42789DA2
+:1034300097D0F7EFB38810F8B98BAED76B110000B7
+:103440009D4331CC07E3263BFD1CAF725936C08E3D
+:103450007E84E805FD16D8ED607A91A064FADDF768
+:103460004227D64BB37439563B2D96DFABDD690B43
+:103470005A406725B87533DE7B3E86F567995DB0A7
+:10348000BF52F66C5FE6833D767FD60AF4FB82433B
+:10349000EAED044F22D7FF9F1481FAE7747D5D1691
+:1034A0001BEE994474EADA4E7B0A7823BEABE2E75E
+:1034B00076F9FC70B0603DD6A520FB266E04C1C233
+:1034C000BF1EF22A4076D026AFA41FC6A5D576DA55
+:1034D00080F16A340ED059DCACF27C0ED35AC6FCB3
+:1034E0000E5775E2712993C765CCA5FA4F17C771BE
+:1034F000DCF570D1C133B0030EA7ABBCEE4942DDA1
+:103500003990EA49E736DC4170E5C24F5E1F484F0B
+:103510002B6A3FE8BCD7D38AF719CBCAC70BE28323
+:10352000198B6E9928122EBC5E679439E053B6AEA3
+:103530006F618773276192EB4D39FE06F0C17FE41E
+:10354000686FA3ACCC267B9BF8E8A4BDE161C455B1
+:103550008E7AB4BF022FA79EF962339E0B6B734F16
+:10356000E60F676321E23265161957BA2B57FB380D
+:1035700087F56C02D3AF32E460FAC5653748B97895
+:10358000CBC5E983AFEA37ED51A89FD2D8FA0A2E0E
+:10359000D5607FE8AB634A3841E9C6F8D5B0AE8E56
+:1035A000BBC309A08F6691F65EE996E879D250D345
+:1035B00010771342FAA921FB501AD72212BD0FB877
+:1035C000F1DCDEDA3EAB958EF41DA6A3707D3CF3F4
+:1035D0003768BFB54FCE1D84F7D2A4BD770DCD3A65
+:1035E0001F7FD1B0319FF3C7A3AF93A27002D6C99A
+:1035F0003145AE93E342CAAFC096183D5E20C77115
+:10360000F299F63C8E347D1D9D54F4765B1DB21DFF
+:10361000F11EEC99D23F49BEBBCFE665BD19207DB6
+:103620000279599A22E15247BA1BF656073560894A
+:10363000055F560B5E2F34365E97C77664F2FB86C5
+:103640005C13454240AE95EEC8D820ED3ADD6FC61A
+:1036500004A8FDA227647F8021FFBF7A3C53EF5F5F
+:10366000AEA768BA46E3A15BAE8C73D5C6E7B7FFD9
+:1036700067F1CDDEE91FAD8308BACF26D775205E8E
+:10368000EA11B25BD227F5C3FE84DDF4DD93F1F6D7
+:10369000597E17F629CCCF8DEF5D9AAB70BF5DA236
+:1036A000E8DE416D7E11F6927854B09C881E477E0C
+:1036B000AEF4571F7FFC1C9D554977622483BF3CA5
+:1036C0008C3F61037D3EB01B74BC2193E47A29706A
+:1036D000D5B5158F7B7C5A26F4C849C084EF3D4987
+:1036E0000467C3DE92FAC3800D7A44F3E9B20FE6B1
+:1036F0006536D2FB7372A57F501B93D05F24A2EC7A
+:103700001C841CA821BCA29EF4E0ACA26CF8C3E30C
+:10371000EEF9CCD63A9F23D57E3FA9A073F0BCB575
+:103720003E27D6E7FC753EE7EC087AD46EC93DE447
+:1037300021BC1FDF62456452D45A83770D49C5739B
+:103740003514105CEF04BE8FBBF6BD8E76F3D62524
+:10375000E5A811F269FEDAB1FE92083AF4DD62A63C
+:103760004BBF9019BE74AF192E27DD8EF9FDDCF723
+:103770007C61339C7BC80C3F3DA859FD11FAC9659B
+:10378000093A15942DEA8F90EF4135083FA3CB2DD0
+:10379000455326107C74DD1C2FC83CFFDD65F9A065
+:1037A000DF89DDB7ED29A7F78E265BBCF0AF8E89E8
+:1037B000D05F27103DE6D5DF6DB77A305F339FEFDE
+:1037C000B1E87CFBB88C032E0C9AEBCF970F357ABF
+:1037D000DC49F48EE4AB68FA53BF57F96960654B76
+:1037E000A7DC03FB67C17862781ADFE0D0DD76E101
+:1037F000BA987E028C576B8208A7D3F89A6E8BE733
+:10380000F8CB90A5A3C5A7F4BD72AB3BFF3734CF6F
+:10381000D94EC51D70B7C6D59B766654409F6E7253
+:103820005BBCE4E308F7A0AA839903E04F8890DB30
+:103830008BB8FEAD2BE1F72FA84A60FC2C14418E0B
+:10384000CBCF5EEE68958FF4BF92D551E3591351FB
+:103850004FF358B0CEDC7ED1C61F1D91B0E1970E5C
+:10386000A95FAF62BE73F571AB8189AC9787E8F150
+:103870008ACFD094F4CD13DD8A76E4D27C87AC195C
+:1038800025EBAD4E5DCFFAD9CF2B77D93D2CCFAC00
+:103890006FAEE4FD1D5A87D00F87E2E7FD0AF2EE16
+:1038A000B453B81D3EB4D7183E9222FD42DEB7A0F5
+:1038B000F6A7D729ACD7CB53245CFEA812440CB88A
+:1038C0001C415BC08FC9386D998E0FF0893F623EF5
+:1038D000A057242CEA8CF87898FDDF8A2AE1851D10
+:1038E00020888E7E036FBC1F15B61F859E0D28A1F4
+:1038F000077CB0F7CCDFA9DCFBA323123E175F26C1
+:10390000D2D5F0F7838C47D52EFC90E3EAADB16CAD
+:10391000B7930288857EB7E9F6B558156C077DB573
+:1039200006FA8ACA15BA1D1EB85BEAAB3549FE9E77
+:103930006ED4DF9DE1051EAE5174FF16767D12EC4C
+:10394000EB7DDC6FB3E2766F48427B11884965FB03
+:103950005AFA09FF5059DF3593FDBE01F6BA2F140C
+:10396000C678D6DC9BC5F6FA7386DEBB3346DAF33F
+:10397000E7DBDD6C5F897BA4FDF8A1E0BEC555DD0A
+:10398000B593B934BF396A116F46952CF367E0BB24
+:103990002593ED16D0432CB8B87D914D56D97F3381
+:1039A000CD17F1FACF94A28396483B58D70FF9056B
+:1039B000FECD7A3B2FDA9558DE643C9458841BFE8A
+:1039C000FCA6B3AAB012BCA9CE115C46AF9474F5A4
+:1039D000F75C9C8DF7647CEAB04FCAFBB801C21F4C
+:1039E000A4D239407ED739C0622AC5181967F92C8C
+:1039F00046F2E10C5154C8FB031E29EFA3E7913AAC
+:103A000040EABD127B83793C1FEF67BA90CE732FDB
+:103A1000037F8F9176C767D72BACCF693E3DDD041E
+:103A2000E7FF2186E38B9FE9FAC8C02FF14F1EE222
+:103A30006886DC4AD2F965CDEDC1AD3184EFBB6D4E
+:103A4000C437A01BF1CDA6014C77B60BD74C4F6302
+:103A5000BA5FA3D355DC19CF741B6AB1483CDF9918
+:103A6000C178A6F6E2EF786FAC47DAF317E9871171
+:103A7000DDB307E49DEF8F19F416D660DE3FDBBFA0
+:103A8000297F7AFB9E00F1FFA23FDD9B20A8DD97F6
+:103A9000D6BA342FBD5FB66945829FCAA3D640828D
+:103AA0009BFAFF32A88E0BB681EF453ABEB17FA0DC
+:103AB000A461DF55CAF1AF1EFFF79537D338BF5564
+:103AC0004433E463C5AEEF57DE4CF33BE87736434F
+:103AD0009E1EB5361642EE2E2C7655D578B17ECD8B
+:103AE00071FC458FDD9BE6617C07322DE9BCFE331E
+:103AF000F15EC5469B177E5DC53BAAD783752F9A9D
+:103B000057627CD1EF57863EB503FF6E8B68EE3867
+:103B1000B48D7AD1C872BE72D7EFBE5613507EF9FB
+:103B200021FC8BCAA8FD8305FAFE4AF43EC2350388
+:103B3000E2538F2040AEEF5F137E388F2140E3EADF
+:103B4000C1EC22E3CEB55BEFEFDF04BB61E3AB0971
+:103B50004A76EBFE81B1EFD2129AF3C8B39E0BAF57
+:103B6000CB937ADCB8956E528E79F6D2C0DA0B041C
+:103B700018B82CB3851360EF97ADB7B11C29DBFEE5
+:103B8000E8E607C06F1F38BC3D3C804FDB210FCA01
+:103B9000147FB3C2F25D2428F9ADF42ADDFE79E189
+:103BA00083B0AF3354319EE8B5E8A933B2BD5F347A
+:103BB000C750FBD29D4D85F00FCA345795B30D7A8F
+:103BC0008D0EBD686F74B541AF505321C7A9B67E45
+:103BD000C7F4F8F20545B4CF3AFFFD05EB3FB70B4C
+:103BE000E91F34A724497C41DF5586D4627BE2F982
+:103BF000EDE9FB139F1DC0F56EF82B3F45C721C0B3
+:103C000005F37BBC4882DEFED0111C0FFAEE589201
+:103C10002088FFBFB05649BE7F68451AECBC05B688
+:103C2000409A9B4BF97CC1C337323FCE57AAD2DCB6
+:103C3000D9CCEF1996413CDF0CCC73EEBAA93CCF3E
+:103C40007942637E5CF0905A14A4F28C558CDBD9D7
+:103C5000C6BAF94C5F370E717D7FAC9333F425E81B
+:103C6000F12F74BF3EF096F4A71D627262E47ED21B
+:103C70006E5D2E0644F030F44065838DE314EA9BBC
+:103C8000670AF19D1BB2AC55C8F7A0F907747C29EF
+:103C90003F4AFFC583BC874AFC45FA74F49B63DB4B
+:103CA0003766E3FB2DF6EBA8DF6FE0277A4DEF31A7
+:103CB000DEBED8E088552EA5324DDAEFD1F348C9E3
+:103CC00033D6BF784B44F053E5962F989F44BA2AD9
+:103CD00012D3258CFD0BF76C575522E1ED9B773EF7
+:103CE000B523FE1D48B5881E186FC3E70C0B6F3B4C
+:103CF0000FDA1BDFAFDCEB10E1C875BBF1F3A87581
+:103D00006DAE17A28AF15929123DD0DF5FD89B0B07
+:103D10009F433FD4EF26EA671ED95F61937DD55C50
+:103D2000F820E4C95EBB9BE30F647F8623F8E6DCE2
+:103D3000FEA8BE2F385F9707D17888960F87A3E437
+:103D400083F1BE58D7F67E54AB5C08307DCB6C2235
+:103D5000003BA3EC0307EB8FB2ED723D0A92A73D47
+:103D6000687D1CDBB6FFAFD7C09F0DD952C773AFBC
+:103D700066F9BBE0C9CF795E7308FF315EC8DFEF3B
+:103D8000ECF07FD3478B66078DFFD86A9F1D7C7F41
+:103D9000DE3AA6E76DAEE3D50ACBB7FFAADC257CF9
+:103DA000DB616FFDD47A9D7F01B91B9367CE1B3A0F
+:103DB00023B21387A2D25DDC85F70FA2F06BE0354A
+:103DC0005A8EAE1FE09171E928394AFFFE2A22F08F
+:103DD000284423F3F1B72417B10F57B1F17BD66B09
+:103DE00084D66607F17145F06B865740AF31FCE22F
+:103DF0009588579E3F6F333EA3EB5F05EF139F15EA
+:103E00003D6363BBA0AC5EE639D27BEC7754225EA7
+:103E1000CFADEB0E66A646C2C1283814D5DE1F050D
+:103E20001745B5D7A2E02A53FBB2BDFBD9CFA2718B
+:103E30009BDA39965ECE7EC8F9764590E751B9EBAC
+:103E40006B7B00FCD1B1D90EB9685B2602F1F47E20
+:103E5000F3F32ADBBDA73CCD09B05356C4483BEE73
+:103E6000945B87930C58CC2AA6719C0AF47723AFF5
+:103E7000A03946C65B4E1535272445F8ED4DF56A49
+:103E80008287DA3706C5B8B6F3626A99CE8DE24208
+:103E9000F5D29E1BABFEB043E68B5A8583FA6BAC22
+:103EA000F96E07E2499F91FF04FBA5A4E6EA04EC42
+:103EB000BF9CAAEF76C534F881AFA89CF325027E9B
+:103EC0003BF226E648528AA32270DF309A9F1A3FBF
+:103ED000E0E073F0AF8851B0FF59B23ACABE114565
+:103EE0008961F8D36BA2F31B8276D837F349CF42AE
+:103EF0001E2D5867AE5F547F8CD7CBA2A8F5A2E9E0
+:103F000071E3E8F55269AC179FF0E9F9969CD77711
+:103F1000EA90CAFCD5B2DC2656A6CABC5AE4A3B4C1
+:103F2000D4CB7C9D96BD1216013D0F485FB706DECF
+:103F30008E633DF5BAB0DD727CF7BFE5FF06FCB3DA
+:103F4000E7A3FE0F52797CCF073D9F03FCF47B9DD6
+:103F50003F12E7B71FFDC2F733795C2F3804C675EF
+:103F6000EA85973BC3DE38F5AC83F3114E2D73B071
+:103F7000BD1E78219EE316A73A497BB8F6F9EFFA01
+:103F800037B23E5ECE747C20CF2EEDAAFA7F67FD5D
+:103F9000D852EFF0601E952FC4F1BAAA7C3686F78E
+:103FA000D54E3DFF5D7E643CEEBF3A1F631FFE545D
+:103FB000BC98F624F857B7FF2B9F1BFC680DFCE557
+:103FC0005D2FDAE720AFE4CFFFD11FF2F5D4932FB6
+:103FD000B2FC3D696B7C18B1CD4D79E1076C831162
+:103FE000D7A38F75106244BEB83690DD165E241ECE
+:103FF0004E111E302FC2CB02D8E517C2473DF0D17B
+:10400000EE5F111F5FCF94726EA0C0BE4F2B5E1487
+:10401000BF7C1ECFF12A9ABF7CFEC277FD21877E2E
+:104020006ABE1FFE7F36DFB3FFB2F395FC1EC8F3F6
+:10403000F038A3F9FE7CBE7EFA570CEF88F7F278D1
+:104040002F72BDA7E7FFABAEF7FF197AE7FFCBCE24
+:10405000F7A7E8FD8A4EEF7837F6414F3DFF1F9DE9
+:10406000C5CF98F7D4FFA5F336ECF902D57BC84746
+:10407000ED5F15A177BC596C95B4698F2CD3F3050E
+:1040800085EE4F8DC65F1EB4CF591EC27A207B02CB
+:104090007E4CAD2BE7C09B04BF4C7682CAFBB2328C
+:1040A0009EF472BA2F28E3BB5502F1AC82F7E630DA
+:1040B000FC9AEF1707905752A8CA78CCFE1AEFC6A1
+:1040C000069AC7FE248BA796E0311DE77CB693EADB
+:1040D000DD1D5437FCB3DA8EB94E4FC4F8C6B8CCE8
+:1040E0007ED6E5517ED22F3DE6FA71E2C954ECD777
+:1040F0008DCBB6099CCF2944FB08BF52CB77F33C4C
+:104100007F29EA96BB5D3F1F4FA17CE977125E785D
+:10411000DF26D051D5F3E2CC7813C05B2AF092CBE6
+:10412000F67B40780FBC49B055B7AF84BEFF58E866
+:104130008CDF0C3FDA210AC24182CF78AC55686F20
+:1041400015E40FCB79B21F1D8D37A1FBD5569D0409
+:10415000633A8E0E03CF78DE25DDF43ECF3B1ACFD7
+:104160003F1FAFFB3A2E015ED3E3BD41F045C7A729
+:10417000521167AD253C2B4A2B3E0D3C45E37D0596
+:104180008D55F297C47747ABCF8A75365CB7E7C7D2
+:10419000589324DCB1412DE2F517947CFD8DD70AAC
+:1041A0007B7E942B89F349857ECE42D5F7C39161FE
+:1041B000C7E320FF1479B95758B5703EFCE6F16E9D
+:1041C0005100BFB5408410BF55EA5FFE1EFE11CE00
+:1041D0009714F1BEE6C1F701F772BAC2F007C53A0B
+:1041E000EBF1737632E2FE51E72B260EDA390AF450
+:1041F0009ABD949E218EE5F61CC47A2CBEC7E101BF
+:10420000FD3A5A1BB89E7C2D77CD60EC5687188EF0
+:104210002D214B3F03ED5E1EC5ED9708B7928474C8
+:10422000BB9002D8E596F96AE4BC7E0BD8BE3CDEB2
+:10423000532BE32602FCD41D65577C5FB64F1F430A
+:10424000DF43BE9BD0D85E8EEDCE9120D15529E2C2
+:10425000FDF72EDD645E44F30A07FB3BC5B775EA44
+:1042600009B934BEC01CB7CE1D28F7878D3238502F
+:10427000CA11D5E24DC777662FEFC3FE971A5B547C
+:10428000BE1B78DC11C77C5EBCF2BA0979F4FDE292
+:104290001D295E0CF3AB893BF365FBE937BE4BCFC1
+:1042A000B52D31FC7CFF40AD391F79068A67E66E7B
+:1042B0007A307BEA7E7B3A75A185269D40DC71626F
+:1042C00060E7EBD8E79C78A5CAED27EAF99F627909
+:1042D0001CEF9B4F087C6D4DA7EF4D20A706F54DB9
+:1042E00031EECED7D3F88BF578F30FBABC52638595
+:1042F000F6A40BE3EAD4B32B3D9F20643E74F4BADA
+:104300001D3450B6EF32DAEB49057E9418F786017A
+:10431000ADEDF11D7C77C44019E772E8A501135E8D
+:10432000392E5EB2CAD1D42D01A52DDC8BCA5F0D0A
+:104330002E881B48F5E3BB8AC2B5F8EE4DAAD8C05B
+:10434000E36D2EE6387B7C6F0FE8A0893ACE3712FA
+:104350006B7AF07E4ED328C1FCD3747796416FCE32
+:104360004F32FCB9A651DE83C8DF6A1EE5F46EF059
+:1043700022BF2514461CE5F05AB95FD3A536DC1DD3
+:1043800072B6D927F7413E5F9AEB019FCCBD774AC1
+:1043900002E4E79C356AD8017E5F6DCE5B126E2F1A
+:1043A000E78DCFA91B6587FF5AE2F2DB312FFF2093
+:1043B000AD17E6619C8BBC0463C2B99FBAE2D7E03B
+:1043C000F7A909B49EB1FEAC9E04F8D5D1794F95FA
+:1043D0007A7E9301DF91A679F1BDD9899E1DE08F88
+:1043E0004F9676E3B86AD540297F8535DC1DF8798C
+:1043F00098D602D6E7A7F992FFC627BB7BBA987F6B
+:104400006304E6D56473F7043F37AD88B1004FE32A
+:1044100097493EBEDD2AD757D0EFB10490C7A9F324
+:10442000EF8C1A6BD17AEAA7A35358E39385786A85
+:10443000B0E6C03826046A0EC3BF9EA3EBAB39AB0F
+:10444000E5F9B12EA3255D85B5614C0A3D3FBA293A
+:104450002B0779F106DF3C35B8E01703F35AE93F43
+:10446000BEC05FD88EBE33DEE269811C2EB95279A0
+:10447000B19BE483F1E867AC5ACFEBBC85E48423BD
+:1044800009E7061B248C7C55C88DBAFBFDCE08BFFE
+:10449000DD2E7671BDBD44E6A376B1876B38FFEAA9
+:1044A0007AE15E46F066B223AC3621B6543BB97C65
+:1044B000BC9AE45D0F21B655A733BCA3DAC365A847
+:1044C000BA373F7FB2DACBF0AEEA410CEFA9F63350
+:1044D000BCB77A1C97CF5617F1F368F933C7358FFD
+:1044E000E589BB27D17AF0F97C33D343E382FC71B1
+:1044F0000AF76D38AF24A4BC4BEA2DE58FD0E55107
+:10450000D73E82CFDF54811E840FDBAA51163EEFC7
+:10451000696DCC00DF8D558F6F7F1AF18E052ECE21
+:10452000CB6A118DBC4E5A84C51B1820E58F83F8C9
+:10453000AECBADE3B222F3D4AF5DA0086B047F5DD8
+:10454000571523AC11FA69D6D224133C63E9DB2F4B
+:10455000B5A7EFF7EAAAD5802E876F3DF2D07BF49E
+:10456000FC915BBFEA21CFF5FEB03E32EED2229A3B
+:10457000256C75F27EFC233767A4A57495DF03BD17
+:1045800066E30F0FE8D3FCE56358872B54EF3282C4
+:104590003F047D089F1FEBF4295ED16DE5AFB1AEFE
+:1045A000FD4EAF42DF397C73DFC241D4FE117D3F47
+:1045B0004AAC22BC46EA9974A9BF3E81FE4A92FAEF
+:1045C000AC0072342CF5D627BF4D0BDC86FAEB130A
+:1045D000BC3801A1AD6A1F984FF06A9FDDAB22AED7
+:1045E000572F56226E4338967645C066D6638D1D8A
+:1045F00093100F663D3612FB9E41279FD3A28EB0CB
+:104600001F33BBF73E9101B954A7B8B15F83739DC7
+:10461000CE64C83785F74791077425E9CBC707AA49
+:104620004CCF23F95679DE0BC97204C7082FC76730
+:104630004A56537BC8C73A9F7D5E84FC9DAD3F9F21
+:10464000D3DBC2A5F1FC197C0FFB87AB7CD3C01F69
+:104650001D509F8D32671AC6D7C155685522F67F07
+:104660009F1A68D5FB97FD1680A8F4FE1DBDBBDA26
+:10467000E766F3F92CD65B463FB37BE7ACEC0A7DEB
+:10468000BD7A14B0236A6DDEF4546A577FEE3B6E38
+:10469000195F77CAFCECB20BE80D234E77147FCA82
+:1046A00073923CDF453B9ED88173128B3E72B0FE05
+:1046B0005A74A9D44B223B983F85039AE6B8F898E0
+:1046C000274E1CBC8DC67302E79810EFDFF5A91DBD
+:1046D000F9A1B46CAA123300AB4DC8338D8ECF1E36
+:1046E000D8F151429B71F15DEAC5C5C5951F12A075
+:1046F000178CF98C7DFE4C1AECAC4AE52CEF335547
+:104700003EBF22ADADFCB0E8B8F8B9F8B958FDB578
+:104710008A38F32D47DB8C9F47C7019B0746EF473D
+:10472000B80A2027CE1C5283D84F6F09F648146D63
+:10473000F46FC4CF2BD7D24B2958979E44EC879D5A
+:10474000BA805D9E3748DAE527F478FBA96D2AFB2D
+:104750004BA7B6C507619F566CBBE720F6292B36E1
+:104760002A6C9E978B06C617E1513823F518F2DDA7
+:1047700052605C7B1221AF8CF1953E115F05BE5AF1
+:104780001852FC9B681C2D4E4F62BB8871240D9201
+:10479000EBA2D411CA67BCEAE3760C9272D068B778
+:1047A000B0FE1E8E4B53BB936CEFFC294E709EA047
+:1047B000687E1DE33BB62ED78B7DC585A19D159CDC
+:1047C000DFB12DCE8D38C4577A9EB3F19D4E7A7FDE
+:1047D0009D0649FBED98BE7F776C873C9F8E71628A
+:1047E0003D7DA598F305BB0D92FCDF6D90B4875E0F
+:1047F000D1D7B1D17E61A829A13BB5FF62EFDB5CC7
+:10480000F6D3FB59E86AE80FBDFBC5AE38DE8FFF73
+:1048100062D7838588339F088D4A05FF1BDF1F3AC7
+:10482000C826E9B04E1D077C89A0CCB329075E736A
+:1048300023C799B23E9015B9CE64BED1B15D4F2564
+:1048400058B25BE958EEAC72E27C68E5AEEB8BC027
+:10485000C7AFD8243EEDBB260570ECB992D42DF439
+:1048600004AFB30C6EBFCA12D1CE61F3B3F0B3ED97
+:104870002DF6A3BD11875EBCDBC6E70B675EEAB908
+:10488000FA5AACC3576D4C87C57D3C57733E528373
+:10489000CAF9CB8BB34418F6C7929BE2D7633FCCDF
+:1048A00018EFCC5CB9DECB5629C24FF32A0BAA42D3
+:1048B000A3B203D13D801CA5F4C63CE44F36650588
+:1048C0006FEF99CAE77DC31B525BF34C691DF7C4B8
+:1048D000B9C89241C93CEFFBA617B2BE3B6C1701A9
+:1048E000C885C093320FA7ACABCC8F7E007C8FFE07
+:1048F00092C33D5308AFC775BA964D0EF7445E4656
+:10490000D993199C9771DC2EF74BF11CFBC56539C7
+:10491000F43EB54BD5F379F17E52041F95CDF67A6E
+:10492000D04E4DF67A7C2E8CD77D92EDD6DDF102FD
+:1049300076ABE5E9783DBF2A86F3C88DF796EA7C29
+:1049400097AAD3535C23F331EFB3C97CD5FB36650B
+:10495000F0FD1846FBFB6CDA74D84F9807ECF58530
+:10496000F6BA9ED87731C6BB30A18EC7795CE7F323
+:1049700085B175322F5C3F778CF6809BF43CF6E670
+:10498000AD0ECE5FF92AA3E15B8CF7ABAD7D900352
+:10499000037CCFDBCBF5643F123D173DEE08A3FE51
+:1049A000CBAD326EFDA52DF82DE4F0970FA5F0F9F3
+:1049B000A82FDB05F3393F40715B609F7DA9E8B00C
+:1049C000CDCD7665173BC1D43E35565890BF336E7A
+:1049D000F2DA99C86F68D9E8007B8AAF36DF9FC6E4
+:1049E0007E8DF024729ECD2155806E5F3DFEEF7D61
+:1049F00022ED17A35CB4D19C77D79425ED4AA37E12
+:104A0000ADBE2ED70E927EC7BA41524F95C785EEE6
+:104A1000EBCAF393F826FAB07F470A3E9EF327B617
+:104A2000F75020371E10C15F7D3480BD6C0FF2E659
+:104A3000CB9EDCFA3AF66BBFB28806D81FCAAD5BD4
+:104A40007E85FB3952EF4A643D24C4469EDF976E53
+:104A500079AE95162CCF7F617B092F9AB2A527E0FE
+:104A600083A473145A5F8B2C0AF7BF684F3FCEB7ED
+:104A7000237A58789F6CA7AA8F876C4AE06FB3CCD3
+:104A8000571E9F1CDC0C7BAFF9A16E02E7DDC7AAA5
+:104A9000EBFA837EA737C659C04FE5B70D4D1C0A08
+:104AA000BCBDA10AD81FA7ADDEF6917184687C4514
+:104AB000E7819FD0E55319AD3B9CFF2CDDF310DF60
+:104AC0002F520ABE045E1E57781FBB74E5D0FB99B7
+:104AD0004F5FB7891ED4EFF1D03D0991F4792FFAD9
+:104AE0003B762FB72FA5F6F2FD5713789C9B6D9C54
+:104AF000D7124DD78B7EFF71F5A2DE3F37FF10D95D
+:104B000005FDCFC7C369D1F0AB8FE8FBDF6C8B61CC
+:104B10007F903C003EC776CC169A87791FDB1EC378
+:104B2000F2EB589294135F903C0DF4C2382EFF3D87
+:104B3000F3E95B53F8BCDFFCA0F9BB46BF1FEB7287
+:104B4000BC3CC59B08BFB3FC0D290F895E57F0FB29
+:104B50006FD8F8FDE8793C87F7DA45ACD3ED71CC36
+:104B600017C73A487A1CDBD18BF55353925B30DF81
+:104B70006CB5C97A5BA833ECE063DB7BF96A23BED2
+:104B80007B2C29D4D91DF1BCC9165C3950CAD36617
+:104B9000F8C5228C583CF28B04C73F8CF74A9DAB7A
+:104BA0001B60A720BF373F87CBB023F9FC3CDDF16A
+:104BB000C9D29F1C3058DA0F9CB39AA6E793B3DD95
+:104BC00013B2438E6BBA7D58B62D3ACF57D6A7187D
+:104BD000EFD3BA4B35F28A2D186FC89ECEF106E19D
+:104BE0007992C65BBAFCFA85C81F2FADBAFB5AD8BA
+:104BF0004FA55631CE4EE36A52541E47538C98351A
+:104C0000197664643F11F65BE7C1E7E2B4C29DC662
+:104C1000762BEBB7AE83A5BE035C47DF2B5BAEAC58
+:104C2000C6F70DF9C281C2B4563C21AF15F93D4D0E
+:104C3000A3F4FA0BCCBBC926EBA3E76D8C277FB09E
+:104C400094534D599EDF0F035DFEA2F2F9AED33FA0
+:104C5000E42626B761A7B5EA7B7B6B9E2D8D1F6787
+:104C60006E595F0F96F2AE94C68771F65C67CE2BD5
+:104C7000EFBDD10C5FB2CD0C67EF32C3FDEBCDB011
+:104C8000F78019EE8B7EF3A49F8D73CBF0B351C2E6
+:104C9000CFF638A49F0D187E364AF8D9780E3F1B00
+:104CA00030FC6CC0F0B3011BF886BF0D18FE36EA6D
+:104CB0006FD0F124FCE134E46B5658649E2FD1C3CD
+:104CC000CFE798A6DB4DE7524E3D2FCFA5103F48CA
+:104CD00079BFD0C5EBE401B4180CBD24D753EAB3B7
+:104CE0008EE032C4773DDACCC158AF6BBF9E07BEB1
+:104CF000ABE8DAC879AF4D2B5EEE790FB56B54E2B5
+:104D000005EC8A8AB55FCF841D95E6D14A06D37833
+:104D10002A631B560EE4B87D98E547638DE78D91B5
+:104D2000928E1C7F2956715306D52F486E337F28EB
+:104D30003AEF5CAC36E799FF54DE79341F1876E021
+:104D400023B6E60C37FBE9C31E469C77B112EF860B
+:104D50009FFE698C5886FB8302AFC83CB5964336EC
+:104D60009937B05AD92022EC93653ABE0D78CED946
+:104D70005CB6C7CFC1AB158BB85488EE5A7313FC21
+:104D8000EBD30B2C6C779F5E5050D80EF61FF96555
+:104D90005813B89F2B72BCB89FCBC43F5B92A3CE75
+:104DA0004D7430B5C7FD5CE673139798EAA7ACCE97
+:104DB00035D597140D35D57717727C4B16CAF195FA
+:104DC000907EF0A7005EC6798B4B403BB2533A2BE6
+:104DD00081952C97D72B7C6EDCB3745521F0729C97
+:104DE000D8197104836FE6E8FA45580376F0DD9927
+:104DF0005459FFA5D270E4367AEF84AF6E33AE4ECD
+:104E000039615977DF300FF2EBD77776D33ABC416F
+:104E100009A541F4FC7E80B61D7CF399B57112EFB3
+:104E200027EE6C975C03BBF350DEEB83D0DF369547
+:104E3000F3260C7EE96C9371BAF5838866644FACF7
+:104E4000AF93F9BCEBEB5262BB47ECBF18F36C01BC
+:104E50001D04CA6569A91C17120D9807D9EDCB600E
+:104E6000B79D3E24ED76633EDD97873B2EA1FA1B6E
+:104E700076C6307E3ED3FD86E37D5EECEFC1F98DD4
+:104E8000EABD9D55D803966D9BE147B852B597B0E2
+:104E90004E16ACEFF11EEEF75AF4AE2A709EE6F312
+:104EA00035A31306D377BEDA6EF38E27F8B6BA476A
+:104EB000EDF09317598376CEC3DCBADE8EBCE45F87
+:104EC0006C59CFCFE76D29E6BCCBF9A28AFDC8A308
+:104ED000FAB92C63DE0B0A94756EE2AF5E43241FB1
+:104EE0002E8895FB79C4CF2F615EA7B7283ED88F57
+:104EF0005716EDB417D3F3C33ABF7AA64D1B0BFE7A
+:104F00006B09C9FB395A5E53E5BD6357AA322FE6D8
+:104F100002F7F94C399BC5FC7DE5D9BEEC674D0D18
+:104F2000F7917E6CB6941F2DF52AEFC7B5BCB63F3E
+:104F3000750ABE576FE3DDBB05F60679FEDF22AAD0
+:104F4000708EC033AD41F25596A882FDB7E42F6F45
+:104F50001FC4BA5B92E5F4603D140D534DFC593902
+:104F600026CEC4BFD344B2E91CCD55482A8980AFB0
+:104F70001CDFCDD4FEEA2BFB46C9839CD67A96076C
+:104F800043A2CE011698E0722A6F817C129799DEB7
+:104F90002B17935BDBC11FDE28EDD6F25D491BB0FA
+:104FA0002FBEC022FDA1699A7C5EB1573E1722F642
+:104FB000DCB9749CC7477CC0746E5BDFE743BF1CE1
+:104FC0000FECD6C0719DE60C929784D1F2DE8D76FF
+:104FD000C4D3C85C6E469CB43C4030FAF58BE65AAC
+:104FE0009C1FB14AFCBABCEEAECB325AF9A2629712
+:104FF00039DFAAE2D0DBDCCEC8678CAE273B7D650B
+:10500000078C7BBCE2E37393DB9AEC88075DA975A0
+:10501000E47B29A2EF4B2B0B35F138A7EE4D7363E0
+:10502000DFB622EA9EB485433C523FE9F17FDC3390
+:1050300024ED8406BB8CDBBAF65978FDC97B79CEAA
+:10504000F1E5028BBC2F200A2FE37DEF727F1D322A
+:10505000641E1AF0628DC04B341F014FD6083CCD40
+:1050600013124FF3489A0409EE003E8BC4CFCFC40D
+:10507000D77CFC41F5F3F72A41E4BF45E3679ED6B0
+:10508000C8F89BA7B9AA82EEF3E75371CBFB0721BF
+:105090009F7664C87B0DA3F1375F34AC84DF3B9F00
+:1050A000F4463889F9C2EE643F4DF1426F7B063514
+:1050B000DA6D529E719CB7E5B5B779DDB578695563
+:1050C000832F04D5537B97DFD3BCAC8D3CDFC967FE
+:1050D00065FCE4AAB3562EAF1C6F5E7753CFA6F1E2
+:1050E000F39F8B970AE0197C8EB85E421BF7EC2188
+:1050F000CE9770FE7C8DFD10430EB7DA75E6BCE5E9
+:105100000BD97FD171C21B87E871C23C9167CA5B22
+:10511000BE80DD119DB76CE8F11697D49363D5EC92
+:10512000373C34EFE25754F6D33DD3C659F8FCF878
+:105130002BF27E3C6DC59926F0A7166F6139B83801
+:10514000BE2BDF6BA1E971BB73F6764D4A1AE27F85
+:10515000C5316ECEC72FAE518BA0BF8AA99D27A2A5
+:10516000DDCAE5DD3A432F7C727BAF8703B45E3E38
+:10517000B929350D71FF4F57D85249729E6BF7C947
+:105180008AB19D919FF1E9DD8E69C136F0F3D010AF
+:10519000195729BFF57DD65B272CAF254CA3F7CB3C
+:1051A00056EC4E40DA7FE98AB7F3DD6452F80668C0
+:1051B000EB86E421BEB77EB31BF872AFE7FB04B603
+:1051C00093B8043E8A57AC60BA2F52E47EF50D4A7C
+:1051D000F8C8486A773CE6EE8469443F8DFE87FD57
+:1051E000C3331BE3F5F368359C37743C96EC016AD6
+:1051F0007F3446E2F3E8CE782FDF89E10D7466FF55
+:10520000AD9DDCDF29B5D45F85F14C4CD5B60FE1FF
+:105210007DDEE0E67495DBF1B975ADA647625BF122
+:105220000FA3DCACEB69D8DB28616F235F06F63691
+:1052300060D8DB28616FE379E55AB3FDF6B2BE5F53
+:1052400068C483BBD436FB60EF060A44EF2AD6B3AA
+:10525000E30BFE08BDF58AB4179628DE558D6C2F3A
+:10526000C5D7C1EFACB54A3B3BF0B13C1745FF7A1F
+:10527000433EFD5ABDC48BFDFCFBE36E7D04ED9700
+:10528000627F6800EE3D25DB2B825F479E758AC8F2
+:1052900073B7A3C8088B84473B334CEDC7BAB34CF4
+:1052A000F5BF48EF63AAFFA5C767822FEF3DD8D4AB
+:1052B0007E82779409BE62D02F4DED27F92799E0C1
+:1052C00029E3A69BDA4F2D2A36D55F3D6DA1A97E35
+:1052D000BA76BD09BE76C14DA6F6D755D598EA85F2
+:1052E000A87A0CF8F107E43D6CF5F09F1CB8FFC5F7
+:1052F000C925D5FF0979CCA348D4F3BD2B7FB9F1DB
+:1053000011C0FB90D74C2B6ED8684B555B71FC1FBE
+:10531000747BE9EA61FE6F87B03FDDC0F7682276F3
+:105320000BBE8B1BEAD1FD5FF9BCA3D5885B35644E
+:10533000F07D0951ED2FD46E58DCBED31E62B92525
+:10534000431FB8CE4AF26BD8C07DB9DD08DEFDDC64
+:10535000C7121EBAEFA9AE043F3FB4C74C862FDD7B
+:10536000771AF5970F6B92F553049B262F3FB7E200
+:105370003AE4A70C1BD975B557C645DA3CDF6E94E5
+:10538000C013CE85034F28C3C4F728F711DFA33C11
+:10539000407C5F4272ED20F13DCA43E467E2F9FFD1
+:1053A000213F13E56BE467A27C9DFC4B940DE45F09
+:1053B000A27CAB7A1A97EF546BFCDE5FAB1770F9E7
+:1053C0007E75153FFFB07A29971F5707F879CFA14F
+:1053D000328EE022BD03FD5E813C18E40B44DD4BC0
+:1053E0002AAADC7CFF41ADAEB744BD9E57B38FFC0B
+:1053F00057E0B3D19A74C4D9BABF78617FDF2A8EDF
+:1054000044D86D5758FD3943998E1DDD2CF7F5E7CB
+:105410004F7AB5814389EEEF664DE991AB42DF5596
+:10542000BD944875EF5ADABE7F326EA8E497DEC3AA
+:10543000FCC3F0DE70E761DE4FF76490B53A94612B
+:1054400005F4577264FC72B8B5A116F5B5DF0B0F01
+:10545000FCE617E3FFCAFBE0B5642EE3FCB172562D
+:10546000FA2B23F4FDFBDAEFE5FEFD088C9DEA87BD
+:10547000BB657DED5CD2743ED487F8FB2370DA59AE
+:105480009E6F33E5ED8C39DB309AEB5D760FF24D94
+:105490004738C3F27B4EE1467CF9C5F83DB2FFB117
+:1054A000B2FF8DDF87F9FBF03E91973DDCD93A9E44
+:1054B000653CBE06793F5DB66C5FABB71FA151FF7F
+:1054C00049185F951C5F31B597E367393702DF4CA8
+:1054D00082B72DEB63D3E5F9E43167F57AAF9C6FC2
+:1054E0007BAB8471A604F599299AF0537F9999C2F0
+:1054F0008BF8DB88D4860C6EAFE733C45BE5F7121C
+:10550000BDF23EAEEE7FD7E47E002100E337F2929B
+:105510008C75DB29399C013BAFD3623B7F2F53DD78
+:10552000E983BCEEE3D37E0D7EB03A2D3CBF5ABF7B
+:105530003C2FFFE6F39E4EB88F74926EAFFF13FAC6
+:10554000DF82F7873B5F90F4C7256F99ADB0328F4C
+:10555000FE37B84DFA4B7C11BF60FE447FA607E8CA
+:10556000A9D35F31F0A3D3FF1CBD9645D6EBFC71E8
+:105570003EFD4392DE3A3F8D70CABC09B407FD87F9
+:105580005B253FD4C6C87C8F17E30B1FC03D5984F1
+:105590009B22C4E7871BFC5225CF0FFF6FA5FF009E
+:1055A000ABBC47CE51E6E47BEA7E8A1F66358B4270
+:1055B000DCD379CAA7C5615D179FF51C043C478CF5
+:1055C0002A84796ED49FBD40BDF64DB30DB0F1BCB9
+:1055D0004B8E6C67D45B9D6FC541EE19DF31DA8D60
+:1055E00038AF5D8E13FA62C9D8D03AE8AF7135563C
+:1055F0008E5B9365C2F021D267329FD39FE04B8BC5
+:10560000CCFFF41E583C00F78BCAF35BC225ED6A51
+:105610000FFD07B95AF843D172F427D46D56F81D1F
+:1056200067904F4BDF294C35DBE7E3A2F6D72FCB52
+:10563000FE82EDF1CB7EE29EEBBF0DD5CFDF64891C
+:10564000ACFFE43DA35F48F97C71F78CF616F5CC0E
+:1056500007638A653E17CDDF9283B88D5F54012EB4
+:10566000145556F0C1385167957EA5FF78C500F6F0
+:10567000DA193F978B303F9F400A05CAE40A621F40
+:10568000C0FBE326CEC0FDC1A3734777C7F388FBF9
+:10569000F37EC0F82A54ED6FEE88FBF3F68D91EBA4
+:1056A0006DF154196FDAE7ECD6A61DFA0AE9DBEEC4
+:1056B0003D8017C1E54BA48FBBD3BC5F267D0CF8A2
+:1056C000B2DE35BCAF5CE831E71D19EF5FEE1E2D91
+:1056D000AC2917D67797F77FA623F0FC6A52AF3133
+:1056E000A0D7AB4903C7201EFF6A527B8B2C1D76C7
+:1056F0002EFB3DDDBDADF119EBA3B5BF42EECFB83A
+:105700002F784C3B795F70345E2F1321137EC7EBEB
+:10571000F8FD1978ED352CEF7CBCC6E1B0631EF0C6
+:10572000F9F61E236F0AF1E4EECB1B18BEC126D793
+:1057300041F9D3130A9017BDF85D99DFF125860270
+:10574000BDBB74288F7FC4D2C1C29ACBFB5101E08C
+:10575000BBCC29F17822F0627FDC6BFE528A3608DE
+:10576000FD7FB14EE5F3F6279E8CE178DCD1E05366
+:1057700009C0A7C1C765AA67B517EBF05555DEB3D9
+:10578000F4C3FECEB887F4427C4DFC3C6A585E1BE5
+:10579000FCEC227EEE773E3F8B8DF21E83326761FA
+:1057A0009B7436FC4E678E3F0E7CE816E1EBC1FF22
+:1057B0001542FA4715CED7E43D9504E3DC6BB45DA2
+:1057C000951F4BEDA9DEEE94F9C206BD331DF21E06
+:1057D000CBCC38E1461C4468B997705CBE9B7F1AFD
+:1057E000C64F7EEDB6C8BCB511E1BEBCEF3CEE9035
+:1057F000CAF9EE2FC7CA7BDF1B891E0AD9A7BFE8EB
+:105800005BE5EA4A749C99AFCD198679A93FA8E86F
+:10581000F7B51E8A48E1F879AE8BFDEC9FE9AF97AA
+:105820000ED3FDF5FEA2FF3FFD3D8576F2DEE1C51C
+:10583000AFE40631EEC535A4D552F97731F89EB8FC
+:105840005AF8E759AD726784E8C9BF97313AD5C6AF
+:1058500079E6FFDB7E4F215368BCFEFEB3BFAB3061
+:105860004E3E3AEF77153213561DD0525B7F5723C9
+:10587000FA771532F5FBAC8547EA0FE3F714460AD1
+:105880003FE7E58F4D37EB95D1EE5107DC5C9AE3AE
+:105890003D993F91CFF5F8305DAFFC14DDCB854EDF
+:1058A0007779AE137CA0FF3E4A10FC69FC3E8A412A
+:1058B00077E377526ADBC9DF49F957FB5D9468FAF1
+:1058C00044FF4E4A347DA27F37658416CB781A5D3B
+:1058D000E662BE36E8348DFE637B00E77295FF7E9C
+:1058E0007A3546ADD33362751EEE293D552CE5FA67
+:1058F00085F4FF835EFF11C88B6F114FC27917A724
+:105900008C87F86BAD226684C0FD849C2FFBEB5A1C
+:10591000790F54AD55C603024457DC8BF75DEC3F5D
+:10592000E47D8E641FD93A202E53C5EF07EC4E77E5
+:10593000AD17F44E603E59BA549E073E6CA9E3DFA2
+:10594000BB98955DA560FFF268967616FDA78BA2C1
+:105950009DF3382E5F3510F27DE69F1D9D513FB3BC
+:105960008BBC3F526437E645DA233333F53CCCE158
+:10597000FA7EBC57E661A9C3655C2DDEEBE6730DCC
+:10598000C5D942CF6F159D67F6031F7FCC767C8B00
+:1059900047DAD58D36798F65E01599CFB3AEEA2D0C
+:1059A000B6FB37915DAB4AFB66ED9D1C674810D88E
+:1059B000C77D24A63909E3EFB55698EC853E41A78B
+:1059C000292FB9EF16B709EE174A37B5BF74AFC71D
+:1059D00054EF0BF736D5E71EF29AE0BC8641A6F6E7
+:1059E00003DFF79BE0C18DE34CED871E2D32C3C36F
+:1059F000BB4A3C8127693E3397B883F21E7D192745
+:105A0000E96297F654ED4DD29F30F2D7357D1D44B3
+:105A1000E7AF77B2CAFC757B95D46B9A4BFAB7EEB9
+:105A200064E156F95C4C03C3B81B82F3C603E63C41
+:105A3000F38E4EE95F59C648FFC3AEE799C7F696A5
+:105A4000E75E8CBC72F22BFCC07777D1389D7FEF7C
+:105A500040BF4F349A9F7FA1D33D7ADC5DECF23C8E
+:105A60005DED4D76DE3FD75CF62625E1FCF1540D69
+:105A700094FCBFC9D9F6BD4F53753E7B2CB768C2A5
+:105A8000702A1F26B5C5F6D779FD791B21EF6A7FED
+:105A90006BE7BCF19FEA6FE6A5723E332C965993F3
+:105AA000B2D91FE4738046BF73F57E7F39526973A4
+:105AB0007E33139BF9DE359168F7807F35D74A86B0
+:105AC000DDB122496D03EFADE732649EFE75AB4355
+:105AD00077F6A271CEB0D7D9E48503411BF8617C7B
+:105AE00001D991B43E5EDE33FC2117D1E3E1A55626
+:105AF0008E83950D7F6666A03BECCC66E60724A2FC
+:105B0000603F11F6A79AD33AEEA611328FFC4E5C95
+:105B10002CCDE7257EE071B5E8F19116113A777E3C
+:105B200022D006BF69AE837C0EC1BD58F253A78850
+:105B30007356F03FFFA7CE4B08EC90523FB63A2188
+:105B4000CF39FE04FE8C732A9EEB6D451B5C382F0B
+:105B500022C6291178F866848C5BFC79B8A437DA00
+:105B6000411E5DA81DD97D89D85F68119E44F74FFD
+:105B7000C4D5FF27E69F69957186CE4E795EA493C2
+:105B800055637961EFADDF73771EBFEB72438F937F
+:105B900075B4CA75DFD12BD7F5F972E1007FDFAE9E
+:105BA000C97BD3A2F1CBFF22E22AC6F995D83152A4
+:105BB0008E1872E1DC39941ED20FB5E9F221D8DDDE
+:105BC000C27907B7C59BD771B32E1FEE31F445805C
+:105BD000FCF87C939C10D8D7AB5DA1B29C2039799E
+:105BE00050A37116E35E1677EBEFC3CDBD57EAB154
+:105BF00011FEA2FBB06F327B8D4DACE77D05793F86
+:105C0000EC7C3D4E5E1C88BA9F45B7C7CFAC56DCD6
+:105C1000F8DD8839ABCCF5F35D473E86FF3837FABF
+:105C20009E1A63BFEE27E2008DC3757BCD2BBC7A35
+:105C3000FEFD328CEF4C50DE7B7DEEBC921EFF6988
+:105C4000093E25E15B8488FC1D09C32E30600FF6F8
+:105C5000C922EE6121FCC6F6867E5F6E6D33BFD130
+:105C6000C0EFB93C0F7D9F8ECA652BD89F91F90D6F
+:105C7000240F785FEE38D5C30E3C1E38CDED8FEF84
+:105C80008AE1BC9213BE86FED8BF35F6E9BA6B72C4
+:105C90001FAB6557BCCC6F705924BC45DE63BFE8B1
+:105CA000EFC1FEF0631B034F99CE39688DE67DBED0
+:105CB000E852ABD9CDFEA66F80163382F8EA98D5AC
+:105CC000EBF4127CBB6B1FDFD3359EFC47C835E479
+:105CD000A5AC4895E367F915382DF15725F17705FF
+:105CE000197A909FEF0A929E88630AF26AA92C0E95
+:105CF0000FE6FE7FEE3ED894B33EB9FF7B7628BF19
+:105D0000AFAD1ACC70EF60F3A8F7A9DFAB349707FB
+:105D100071A4A9B5BF1E1B0BFAFFD1B582CB4EE60D
+:105D2000F30346D97B84A44BA3ADEDFA3F8E90EBF1
+:105D300063CF08A1DF5723F97D718DC2FB6A8BC148
+:105D4000E380EF94F7731AF0E93A1D1E2BE1252B3F
+:105D5000240CD5043B78B6FE3B699BF5F80BE68F27
+:105D600012F3475C609B1E9FC1FC5162FE780E7966
+:105D70000518F20A30E41560C82B94905778FE7924
+:105D8000D268DED7C6BEDD9888F5847DBB3111EBC5
+:105D900003FB769130F6ED22DB63DF2EB21EFB763D
+:105DA00091F5D8B78B84B16F17D91EFB7691B018D7
+:105DB000F4CB561872CD3FC9044F217F604CC47A92
+:105DC000C6BE5DE4F7B16F67FA9E76BDE9FD6BC5AF
+:105DD00052D3FBD8B78B6C3F6BA962DAD72309C8C3
+:105DE0007A7DCEDA14E6A3645FD1BC1179FCBB5690
+:105DF00037DABAB27CE038C6E2F258AFA477DD38C1
+:105E0000497F8B3C1FA134F3EF0B9CBEC52EE1B143
+:105E1000E6FC6DA3C4BED7189BDCF742897D2F94A6
+:105E2000D8F742897DAF313DE4BE174AEC7BE139BA
+:105E3000F6BD5062DF0B25F6BD5062DF0B25F6BDC7
+:105E40005062DF0BEF61DF0B25F6BDF01CFB5E2817
+:105E5000B1EF85E787691C2511720CF67A77939F5D
+:105E6000497C68F233DD2618F67A647BD8EB91F52D
+:105E7000B0D723EB61AF47C2B0D723DBC35E8F84BB
+:105E80001F1BEE613D06BB3DF23DD8ED9170BFBAE0
+:105E9000C04B88AD4D5877F200CAC678E5619C3793
+:105EA0007CEC852B6659491F36C6289D9348A6DB96
+:105EB00094A9B3C640DFEAF98FFD45B305F24783E5
+:105EC000333980CF19725E69BFEF33B8FE65E35C8A
+:105ED0001CFE11DD7DBB04FFEE8CB1DF6EBCEF2537
+:105EE000B58DD268DF0AB7DD2EBA7FA31DE7564510
+:105EF0008C03279A9137E3BBC595033F64B345E113
+:105F00003C93CDCB645E74345F7DACDB479B2D3B13
+:105F1000F7E11C4C73B1E2C5B98FEE751A9F33EBF4
+:105F2000374358545FEB7C7A3D92C079B50746C839
+:105F3000389F317E233E4AF282CF0F0E6B6E189D42
+:105F400048EDB5C028FE1D9CF176693790A5310457
+:105F5000FE64DF80E2DF10C1E7AFEBDFD302721C2B
+:105F60008F3D3251BE172BDF7BEC9104EE7FE27246
+:105F700085F3CC866D137E9C537E4F97AF7DB7859E
+:105F800055F457BC5CF6677CB7785D673BCE731BF6
+:105F9000F82A168D63709FB418A0E04E59D1D3AA89
+:105FA000B15DDA7E86DB023BE862CF410D1F9034A3
+:105FB000167988A25EF0BDA11306BC699A2FA32BA7
+:105FC0001FBF832AD837D402D75BD0EF4442400AA0
+:105FD000E2C904633E9A26AAB208BF574D2B667CDD
+:105FE000F79E2114E0BBCF8CF596547AAFAFF6A2A2
+:105FF00005F65ABFBA462E8D79788725A980C7DB6A
+:10600000DC6331FEF16315961FD1793CB00F185E49
+:106010006E637D6ED80F8BE3CFE5F9BC873C9FD3D1
+:10602000876C9CE7737AF919AE2FDE1DC3793DDAD0
+:106030005A85E59A613718793B65D7BF9B0FFC7C81
+:106040009515DC9CD48DF5BC7D24F269BAEE4CC06C
+:10605000119CE3CB775F85A37BA797EF96BF57ABE8
+:10606000EFEF18BF7B2AB2FD9C0F66D88142ADB717
+:1060700047EEE318BF9F46F293DB9DDE6B77F3EFAD
+:10608000D7E9BF776AC47D8AFF927B10782D7E485E
+:10609000FEFED9EC5577174E23789EDF19C6EF62C6
+:1060A00045E7632D8CB2037FEAF74E3D23F5F84FA9
+:1060B000ABFDC7FC72E63569FF15FF65FF5469AF9C
+:1060C000D838EF7F468D8CD7899D82EF3F9A513328
+:1060D000DA827BA467ECF67B154FAB1DF8866EB7B2
+:1060E0004C3E9BC9F87D5BB753A622FF94F03BBEA4
+:1060F0003146CF57CBE0F2EAB3321F75B24BAEF761
+:10610000C66704DBD32D0187CC23AC177A7EAB990D
+:10611000EF7C82F883E873895FD98FB4E509B07B9F
+:10612000E87BD36007A5808F8B57205F96DE66BB28
+:10613000339A8F275BC357E2FB93BD36E6AF7FC62A
+:10614000C7B897E39C5C12552FE19CBFD8287FC746
+:10615000619A26F9BBAFCEDF33E3F4F8934BC697D1
+:10616000CEC59F3048C4CCC4D659C8179E89E48593
+:106170000E3C2D3FF2F5E2B365FD3523B7CE5A0E46
+:1061800067E6027109F5663BDF5FADB99CFC3B3405
+:10619000178A13203E00F978DD0D3EFBEC08F95814
+:1061A00030AA608D3F2FE2BCE3ED320F6AF1ED3D86
+:1061B000DAB775DED628E7107EB13E662636DE8871
+:1061C000F3E64B470AFF9841F27726E5BC4418797D
+:1061D00098D7E8F0C63F37FC6D958BF1C1F00D7F85
+:1061E000DE330BF7C7953B1B0BC16E95D955E3907A
+:1061F00077DD2A87347F6616E4D0A830E4D085E2C4
+:106200000E1B474A3A44C71FE6644BF92CF4FBC205
+:106210003FB9FDE91D90E7C6F83FB9C0EF63AC1B7D
+:10622000A9EB89EAFF9E731ED1E73BDEE8A3DD35CB
+:10623000B21D7E97C7DF843CFA0E6A9D9E3F2BEF0E
+:10624000F530E81B53F71DC73B4AF4FBF0499EB0FD
+:106250003F39DBEFF4D6408EF4162B715E68A62A28
+:106260009A79DFF83CBA4B3C3E32FDEF0B918FFB45
+:10627000C86F63E5791D1D7F33EC0D2F39B35AF1DB
+:10628000F7D1D23FD8A4FC0AF7C0BEDC3555319C0B
+:10629000DF5630AAE851C8BBB86C2FDF83B1C62FD8
+:1062A000F9C9DEB568339E97AF7EF161DC9750592E
+:1062B0009FC5BF2B53BCD7B712E71C0B46694F6075
+:1062C0009EC52E37DF1B52B13C89F5D3CCF67ADC64
+:1062D0005534F33E9C81F7037A7CEA9E51F2FBA78A
+:1062E000743F03827092A9DD85E27432FF06F939AA
+:1062F000883F6AAE3D1C2770DF2CEFA9B08B776416
+:10630000FC31BDEDB841A61E6FCCF0CAF89081BF3C
+:106310003B7ACF66396733E2B9E7F0673E8F69941D
+:106320006EBFD4EFB36F50D85F2D59A3F2B9F2B15D
+:10633000EA78BEC765F1DD8A87D7D7BDDD38DF7B58
+:10634000F1ED648D7970BECC53D87E00EE5B57DCE6
+:10635000B04B66801611F19D92B58379BD9504A965
+:106360006CE35E53A3BCF6EEFD9D9EF1808C7EDE59
+:10637000BF2C71FBEDC911EB7D4E9D62BA5FC180F0
+:10638000855FC6DB66085290348E19DD3D0AF6152E
+:10639000DD7E8987EB6EC8B2E3F74866D0972D396A
+:1063A00017EEFFFF95F2FF02371C2052008000001D
+:1063B000000000001F8B080000000000000BE57DBE
+:1063C000097854E5B9F077E6CC99992433E1640172
+:1063D0009200F1241088803861A72E1C1202130845
+:1063E000305940F086308120A1456F0497D04699FE
+:1063F0009085104143890D52D461F3564B352ED709
+:1064000042C57600EB525131486B1793617169DDDB
+:106410005228B5BD0FF7FABFEFFB9D93CC39990415
+:10642000B4F6FEFD9F3F3E78F29D6F7FBF777FDF22
+:10643000EF243F9DBDCC2632D6B54D90F7A4315602
+:106440002EABB6F14EC6BEC49FE98C2D6F16D4C0DC
+:10645000D89E727E3A5BE68572B4EA626C1263651E
+:10646000B2624B4EC3A76C8B87F7CBEF3822B14497
+:10647000C6568C604CC882F6F16E9B13C75F0DE365
+:106480000B8CDD2C0773B1FEE6B10AAB8983F67580
+:10649000593606F3F9B6F0797C8D71B66BA05C665F
+:1064A000956DC3A05C12CD18B687F505B07F795005
+:1064B000B5C53B715CB6ACD0C9D71B1FB6BE326D3B
+:1064C000BDE5CD71B69586F7DB2405CA4B1853DBC5
+:1064D000C2F6A73FA7AB02ED67795D416A2BACB767
+:1064E000DCEF9271DE72AB6A73E3BA705CE8B7A45A
+:1064F000A5554A0BEB7F8D6AA17ED355859EF9E9A0
+:10650000C10C01F77B7B941BD7BB446E96109EF9A0
+:106510003A9C1FE4705829073370FC950E0E077DD6
+:10652000BCF2163E4FEFF5717897B794D914A8BF17
+:10653000C5EA4D6D85FEB7C03AFDF05CB2E3488612
+:1065400080CFCA28B700E7C1645FAAD7D5D3FF833D
+:10655000076F4AA5FDC3FA11DE2EB7322B09D6B359
+:10656000A21916A3D093E62D9DC02ADBC2E0769334
+:106570006A656C203E2DF464CDADAA6310C083F132
+:106580009FAB6C2766E03E6AAF666C23ECC3E77C8A
+:106590007E06EE53FE2E63E23458EF96B7A97E4591
+:1065A000129305A8B7B1E704ACB795431F28337F12
+:1065B000AE1ACAE4637D99CED8301C19DA3B017F4C
+:1065C000FCC98C554E5168DE252CB4840D8771B6FC
+:1065D00014C01CB0CEC17C9DA50358E53311E0D595
+:1065E000A2ADF766EDBC4B2CEC2516DF537FAF76E2
+:1065F000DE2588CF61FD713C1C778D5E9F1DCCB878
+:106600007D6C4F7B7DDE9278DE0FE901F1708D8627
+:1066100007D87E2DB5E7E55CD1B9B11EF6B376ABF0
+:1066200018B00BF8DC5B3F08CB4F0B6E84FBC76BDD
+:106630007FFAE62278FEE907BB4B717FFA3A56FEF5
+:106640002D8B290970BE7FBB8E9EE5C1694C99D008
+:106650007B9FC7A6F8BEA74E0AC39FED3F19E983EB
+:10666000F93F7EF2F50C84F31F00074480F3BFFD71
+:1066700064AFC4D27BD6BFBCF16DA9CC190E2F81FB
+:10668000E0D594D94EE7B72293F75B51F7E7323C58
+:106690000FE6B4291969BDCFBFACEE69DEBECA4DA5
+:1066A000ED7DCE5FF3F34F61B2987CF9F3D6CFD78F
+:1066B0007CEE8F48DE609280E7D36CA07FF3FE1FF4
+:1066C000D6D61DD0E8EF660D8F6FAED846FD963753
+:1066D00096ED1561DD4B74FA2D37BED7CFE7FC166A
+:1066E00089CEE7FC968C86242CB7F1F3F98ED83648
+:1066F000EE6E68F7F19AFDB725A7E3AA03A9DE6B52
+:10670000F8F9B009FC7CF0B90ACE8725443C9FA774
+:10671000C2CF67D5A3FC7C563CF9C67B3F5308FF2C
+:10672000F8FEB6DA03C87F97B73D7DEA5BF07E4995
+:10673000E336290DDAFD424DA37DE9FD575466C9C4
+:106740002C16F6D7B85B423EF00B558988E73A5CC9
+:106750009995F399472438DB38AA67427C4FFB258B
+:106760004C1D8C7C84F987B2FD89BDD7FF278D8EA7
+:10677000F2D3DDB6C1C8BFEA63D81E19D751763F40
+:106780001BD7BBBDFE3C1BC5E96239CC83F47976CF
+:10679000863B15E9A2C46231D09BFE3CADD1D790B7
+:1067A00098B625B8DE21094CAE0510FF305ACDB69B
+:1067B000C0BC3FFC9643AE75637F9F82F57607931E
+:1067C000FD00F23D16653CE1276C795332C232344C
+:1067D00009F9DE8835A13FE3FA109DA2C6F3A70BA5
+:1067E000F66D9FC1F104CA6C107F1FC4E7306B1BAC
+:1067F000F1A9E82A8E7F36F60E956DC0B7106FF5B9
+:106800007E43D80901DF27C35A70FEA6CCE5747E0B
+:10681000D2084E2F7DEDEFCB2BDCDFD9345F80E447
+:10682000441493F7C4D1FED662B97B7F994CB5402E
+:10683000FFD2EF5DB3BB09863C5BA31EB541FDD91A
+:10684000F54EEAFF4DEDD7BCCF25E565867D76D3C5
+:106850004D33F0B5347C4E48C5759E77C044507FAB
+:10686000F6F6280BC2FF6C1AD717180BB90AE15CB1
+:106870001EDB00BFDA19FBD106073D9FD800C834E4
+:106880008AB1031B92A8FCE406859E6D1B32E97D4C
+:10689000FA0C8E7F25D16A2CCAE5AE1A97BC07E1A7
+:1068A00011E474D351359CE0007A02E7C79A5ED0B8
+:1068B00021875CF1617C1AE4C7569477AC6A38DBB7
+:1068C0000F5374349F7559C6225EF2F5E9EDEF90CF
+:1068D0009AD97A6CF79010D80FE3C6DCF176EE60A7
+:1068E00094D32D695902F45B5A7581F8E152E7207F
+:1068F00085A11C77FA1AA660FD8E347923748B6902
+:10690000C9EAA882FE2BEB46B9B1FD1D82D240F345
+:10691000D6086E9C177E54C764E003F81B94573961
+:106920005F1EA1F14B0BF2CB15F7AF6F4886F269F2
+:106930000BEB120134F996825958CEDF19E7AE45B8
+:10694000795BCBF7C376011F75F4F05175AAF7FA9E
+:106950001970CEEC12E01B8C3F1AD6C644DC4F9B5C
+:106960008AEB67A077EC67B85EAF0DFBBFA0F1CBF9
+:106970008E96D32E453B9F02A41B5FD7E94D78AE80
+:106980004E8BBB4941F9AEBCA520DC5F13D91E0577
+:10699000F187D7AF75F17A786EAC87FAB5BBC500D1
+:1069A000C223572C191442FD6B87487C71E5EEA277
+:1069B00041A86FAC8432CAAF9D3815E053434B0EEB
+:1069C0006FB72DF7077EE0A7A902F3223F3A670DC4
+:1069D00015203C3EDA3D38BE06F5BD5B6B4732A85C
+:1069E0002FDFBD29159F1FED8E5A8C7C7CA65C3055
+:1069F000330EF59F5D7159A2D243671533389D7DE3
+:106A0000FBD69CC128EFD6FCCFB1476490AB2B01DD
+:106A1000476518F7625B4CC00F4DD66C38982A0258
+:106A20006A39137D2B106EDFB11C5E340DE5B0109A
+:106A3000782C99DA2B83E54874ACEB5380C70AE0D5
+:106A4000E9ADF7BE4BE37C6A393E7F09F45F73EB37
+:106A5000B3B138CE771E3C395986F759137DFF8E76
+:106A6000E3FF49D8FD980C20613B768F43F95139FB
+:106A70008371BE1AEF5DB484C3D7BD47E97BBE8A7C
+:106A80008302C1532F2F0D0CB031D44B83CC26E39E
+:106A90005366A4077F24B22A94EFBA5EA2BFAFD593
+:106AA000E0F2D180E6543CFFD58FB5A6A2FCF8A356
+:106AB0008B977DFB5E59F95D5887AFC52233C03B8C
+:106AC0009F9591DEBBC2CFF5695601CC24B967FE14
+:106AD000AD336268FDAB774C30C83D908F34CF1F2B
+:106AE000ADCC83EBB8AAB62B0BF5A7DF5B832BF1FC
+:106AF0005C7F0FFAA93F0DCF89E3DFEF9BC559F803
+:106B0000DE7F87C032042C3FEB1AE1243DCC427C6F
+:106B1000FD0529B01FDABB26B60591EFDDFA5CDC76
+:106B2000780463AE387630E2CFDA43D2AC215C9F92
+:106B30009271F635D6A02DD2B97D5BD3A3BACBCF57
+:106B40003D6D43BC5F7300F401A4CFE78400EA37D6
+:106B50006BDA9E7E3905C6BBED60D9049C476F7F1A
+:106B6000DB731C0E512C642B0AD3ABCB32E31B8698
+:106B7000008F7C72C6BBCB1E842D95E1397D0BF84E
+:106B8000D7F45FFB6A46E053A67D326B17E9E3A0BA
+:106B90005FD950FEDF5AC7C7BB35B3BD219DF6553F
+:106BA00090C0C2CEFFA91912F5D3FBC3BEA95FAD39
+:106BB000E3DE4743B05EB5D6CAA26E84B295FDE16E
+:106BC00031841F8B95F7E33EACECDCCBF0BC5B1C57
+:106BD000C09AE0B9AB72ED7F50FB1ABB2CC2B3F682
+:106BE000D6EAA742309F22322F83FEFEEC4A1ACF0C
+:106BF0006FE3F2A735E6C9876E817255B1D30DE810
+:106C00000DE55882CFE1BB2CC4E79359D7310B3C3B
+:106C10000733A02200D04769BEE3C47718E7C777DF
+:106C2000AF5302C88F61E502E2F9E72F7E3801D742
+:106C30007DE355A10B885752CD87BE9940FFEFCC1D
+:106C400090B97E32363401DB0D3CAAF135EB099266
+:106C50008F5292128FFA4A10C7C2F5FDDD4278704A
+:106C60005808EEC5797538456573FDEFEF6EDF7B2B
+:106C7000B80E5590EE0C42FB0542AC1BF77B225E32
+:106C8000CC180FF4FCB9F487341CD70F682B0EE92D
+:106C9000D163B3B5A5DB52A6EE40B8CC0080B2EB11
+:106CA000C196191BCFAC50BE8F59BAECB08EECAE6A
+:106CB000DFEDAE81B2FCFD014C0451551B95CAB20B
+:106CC000617CE1286C14F67374ECD115B8CEFBBA74
+:106CD0001C0CE1C41C463DD766490E7E0FF1B9324B
+:106CE000D6CD92500EB565213F62B739DD4DD07ECD
+:106CF000E9A550C6BFA35CFAFB71D2D347A5FBBE82
+:106D00009801FB4A11D5D33EA8BF4F0E0E7F00C796
+:106D1000AF8A71D77039C2C2D77F78FDDF6313A005
+:106D2000DFE75D23AD4F41BBCF55871B3458D6F10C
+:106D3000DD312F5D07E5EB3579625ED7E7498A15CE
+:106D4000ED8ECFBB1C41D4433E775A02028034FB08
+:106D5000F0B1770590DFD90E67508CC57ED227E160
+:106D6000F2869D1816F7C1181231EC4B80E7204DC2
+:106D70002EDD38C0683FA664733B28259BF31FAB0C
+:106D8000E226389FF75B5913E2218332CE6B75C838
+:106D90004DB0BE9F3B1F5B0A94CFCEFF2D7D00CA36
+:106DA0008DF387870F6063FBE68B27519F003D6162
+:106DB000D178352D7B528F7C5DA8C125AAF9260993
+:106DC000E1510BF06802782C745A8276D8172B3672
+:106DD000C28155759522DE304BAC1BE906CF17CF2B
+:106DE0005F112C5DECBADEE73DFD921CFC1E949712
+:106DF000C279225C4BCF7F70CD038CCEED1A5C073D
+:106E00009C63FDB5ACE7FCFED5CE8B59DD8D780ECD
+:106E1000778BAE663C875A2BD7F7FC805BFBE3A8E9
+:106E2000DB63782E77D78EA0731A540B7C02ED9417
+:106E30001A2BDB93887CA59DDAEFD7F4419659494C
+:106E40007CA6B4D62E23FCBE888EA5FE0CCE554A59
+:106E500089C467385FA92A67C457968DAD14F0DCE2
+:106E6000937006D84F8725E4C27D86A2408B84E7C5
+:106E7000FAEC74A2F321C81186F373C6FE0FAF7744
+:106E8000ED417E233A863C7C0E44116BEC8A1D0D4D
+:106E9000EB6A11581BED4BD2F8C76A27E9732D71C5
+:106EA00001E26F2D0B87BA71AF9F33ADBE229AF806
+:106EB000CB75160B95BB960C227BAC250E582B8EF2
+:106EC000B76434E90DCFFF8FC8EDB50CC6EBB3D86E
+:106ED000C81D585F9049E3BDA0F3ABAD2E1AAFA516
+:106EE000404D8EA6FA4116EC5F9EE65B87F8912234
+:106EF000F276A07850BB9D3BD5643CCF9D85366A29
+:106F0000F703C1BB64258E738D93F4C6D092E82736
+:106F10001FE3C71944FF524715DFB74E0795533893
+:106F20003FBDCA7FFA21E41FFE6C381127CA8BCF00
+:106F300096225EAB62AC1B50B8D7397FD18DE7ACDF
+:106F40000B80CB12A33BC85E573218021BCE4F6694
+:106F5000D98827C7009ED0DE2FC13927F273DE986B
+:106F600088E73C7F77F839C378FEBBE1BDB036D601
+:106F70002D4CA573CEC4F1AB58B41BEDEBEEF3FB77
+:106F800079200B9FA2C59D6407583C9FEE7B307B08
+:106F9000608F1C79F83DD81FC0A5D41E9AD48CFAF6
+:106FA000B98555B445E0038F6673FB40665D12CA30
+:106FB000D7653AFE579BF03F3434EE83180DFFA19E
+:106FC000DFE1C1DEDD780E9F0A2727E3CBE3FF2D4B
+:106FD0002E8E34FEE39A7C792BD1FB235CDF08EB09
+:106FE000D1A1EB50DF586F27FD975D3A3614E7AD1E
+:106FF0004EF3FE18C78B1AD16543FF54477297842E
+:10700000FBEB58F2A761A8672DAB7A85E8F34AD766
+:10701000B731669C847233CE932585A0FF604FD62E
+:107020002FF15CDAE7D9157B043FC891795386A12B
+:107030003E74326FCA30E497278701C9933C75BB11
+:10704000908F4A07AF71E13A4F7A265059618A56BC
+:107050002EEA97BF7E0CFC35088AC01FC15EC3E7CD
+:107060008760AF0581DFBE0FF61A3ECF82BD86EF87
+:107070004F83BD86CFCE0D6E7A7FD233FC20E2C522
+:10708000C566EE4759617547D4CBD61C105950E7F9
+:107090006FF0EFDBFB620CE58A5D0986F22D2D8037
+:1070A000418E9E72F996E186B2AE7F2EAF1B637859
+:1070B000EFAB9E60286F8C2995F09CE28AD3387CD8
+:1070C0008BD308BEA7F2FA806FDE28826FFBC25115
+:1070D000C3107EED085FD48BAD8A0BE1271D5CEAFF
+:1070E000423DA6BD78389501BE5B27E2789A1DD552
+:1070F0005EDC3F9CFF88701E85F07568F095099EE8
+:107100006735389F46388F42F866D2B31DE10CF5DB
+:10711000B5C50067C0C78B7E941E805FD62E29A29E
+:10712000FEBB4F34ECBF62578C09AE4638976F19DF
+:1071300062282FAF1B6E28EB70F6551BE15CE499BB
+:10714000606AC7D816907B45F80BE0F91B9366136D
+:107150003F3D29B0CA0478C6C99C0F5ABD02F9DF69
+:10716000F0A719E47721FE02F463752AF5585F074A
+:10717000EDBF0F6DD106463B8431B75406EF177A49
+:10718000A26494EB8B5825D1DB62D64CCF9B591B64
+:107190003D4BD8097A96324E8F9F978526E3F3F7B9
+:1071A00089BEF41CA0E7350EDFA38968BF0DF38DFF
+:1071B0004A40BEE48C27FBB4AF73424D9B697CCA46
+:1071C0003959DB17FC14E3DAA15F7BCCB83BEF54F1
+:1071D0007AE6D1C787F9DC38DFA7129FE78D4953DC
+:1071E0008621FE31EF40835DD5D77CDB347959E6CB
+:1071F000E17042DF2D96CF2D14021BA17C649BDD34
+:10720000867E86739B254D6FBF97ECDDD3A7B87F35
+:10721000E65CFDEC54C4BF9A6DA35211DFCF494A1E
+:107220007D15C0FFDC34E0E36EF2E7B8514E9CF10F
+:10723000B8A83F488CD82C38B715DAFECE286EDBBC
+:107240007A68BF3059647E68EFF3A7C5E2FAF57D2E
+:107250009BD7BD7C8BDD80170BA61ACB0B99AD0796
+:107260004FD2F0BC6D3DF5A82F8925037CFDD8DFFA
+:10727000557F58FDD64B6178F66F39AE44D46FD840
+:107280001436E54BB1A77F5FF0FD6243C55B2F4924
+:107290003DF0D5F16A528EB71CCF095EDB903F02FC
+:1072A0005C2C28974F1EE470DC1673E3D6EB000EBF
+:1072B00085EF888CC3B9D4FF7BC4E743DCBF6F9EE6
+:1072C00027A4D175A7C63FCBEADE263B6E597501D0
+:1072D000F19F4267D730F43F1DB907F80BF295795B
+:1072E0009CBF1CCB1BF5F01D306E67BEE8B6033E9D
+:1072F0001DC9BFB015CB27AB4519E7ED3C7841E37D
+:10730000E35D6F4C81F57DE69188CF741EFCE7F05C
+:10731000F3C2431A9F09707EBECAEA650D30EF2A98
+:10732000800BDAF3FF6CBE7E397EDE2E7973072286
+:10733000BC6A0437FAE16AF2ECA447B4037DD83999
+:107340003ED5DF81F2682AD8C132E29B7712DA9605
+:10735000270F0E1F88F0627EB53D73720FBEAFA877
+:107360005E958F7E76B6453A83FA373A45504E178A
+:1073700032EB9950189EFA9E937ACA84D7D633A1DD
+:1073800030BC36E3699B094F2FB24BA9B6745E7FC0
+:1073900062500FDFC39F70FE729B186C60693D786E
+:1073A000FBD7BCB74B515900BEF202E2EB5DE3D311
+:1073B0005E0C09617CE50AF918E033C9BFD6981B59
+:1073C000B97EB190CBBF230B6F3AFA3B80DFC7F396
+:1073D000385E7F9CF753E21F1F839685F87A2A3F19
+:1073E0002116F1EF745D11D1994E3FE679DA357CC3
+:1073F000D3DB155A15C91D013F8B3C467CC9786EFD
+:10740000E90094A77DAD5F1F576FA78F5B88718DD3
+:10741000B17D8FFB610EB74733F695F43B3E188282
+:107420003DF885FC8445F78C03E5233FB98961DC91
+:10743000F5643187CFC903A3881EDB8B75FDCA476E
+:10744000F5A73C6200F5D893C513DE9888F4E39560
+:10745000484EF735EF396D5F67343DA053D303F4E1
+:107460007AF1C1858B96E0B81A5F38E5E1F8FB7ECA
+:10747000CB42D23B603DE47FB2CDFC9F32F43F81F2
+:107480007DED42FED59E2F325C47615E11D9D585D8
+:10749000923230929E60DEB779BC233FB1935F0E8B
+:1074A000C623BA2A9E57C41A705FC5DCFFDB8EED77
+:1074B00061BEE20779F918B69F688013F19176E012
+:1074C00023283AA4833790DEB4B2D9784E2B1A63BE
+:1074D0004CF46EE417C50B399F6BCFCF191889DFB9
+:1074E0005DEEFCF4FE577AFE15D81FCAB8E62F49A8
+:1074F0004F89378C07169D69BE7453FD6853FD781C
+:1075000043F972F8D8A9C991761D2FA294A5DE0877
+:10751000EB6F7FD25E119EAF317726B75FE6CED498
+:10752000E2F75F51AECE9A09FC2A86F592AB7DF563
+:10753000D7F9D3A81CEFBC99385FB048C27D5D294C
+:107540003F0A93C30BA97F48B061FF6D9A9CAD6859
+:10755000E378D41A73FFCB88879F6AF6D091799C21
+:10756000DF7FA6F1FBCFFE532BFF440820DF3C76E4
+:10757000E8EE58D4DF3F3C382A16EDB1336DB5B193
+:107580005C4FF7C77E0BF0F313A0CB2698EEA3B6A3
+:107590007F8E9E5EFCB4660FFD88EBE9ABADCD91AE
+:1075A000FDD4DFB09E6ED6CF73C592A3BF83757C2A
+:1075B00018E07034EBEB1F2A4AAC4CF0E170F84C49
+:1075C0005262D1AF7726C0F97D5FF8A8C3E11CC233
+:1075D000218CDFF705C7B35A7FBD0CF621D92D45A5
+:1075E0000EF72F13D19FB0457063BC8A59199B0ABF
+:1075F000E778A2386B6F53989E11972B12BE9CAE02
+:107600003B569A8CFC070C5DF4F7BE527D2C15FDA1
+:10761000AC650762883F9AE72DCF37F2994FEA0BA6
+:10762000B27F0FFD8ADE11030E84477E1CE75F4F99
+:107630008B0111CA9DD539B1E1FBF8D02477565999
+:107640002B239E63C52EE33916E5D7D038271F14A8
+:10765000DA8401F03C324D525CBDFB1559F9FE57FE
+:107660001D10C9CFBBAAEECF6F607C7115F07B54A3
+:10767000135E69AC9D8F787DDA2B5910CF3BDB12FE
+:10768000E6237CFCC5A23B03DA1F6F1C4E787EA666
+:10769000316710CEF7CB9922C9BB0F0FDA2DC2B5D7
+:1076A000F0F44A2C487E81209DE727754524AF3EA3
+:1076B00044B8903D2B135D9C98C9E30EA7611CACA8
+:1076C000B7009DA03EDC19103D8108F47162263F91
+:1076D0008FB3971E20FC7939702C16F58AD36D7CF8
+:1076E000FCB3D5722CC6A95EAF9BE0A2F5E5C3B88A
+:1076F000A8F71EE272F4C33A8E8FB84EB20F1BB9D0
+:10770000FC3859B7E2FE69008F4FB788A4777EDA5C
+:1077100058347F1A9EF71689CA39050B29CE713263
+:10772000C0E5D1A9C0D9523CBF0FEBE0F4A15C7316
+:10773000680AC9DD4FEA25C287F203C67359B82526
+:10774000C66CAFC66681DE558EBF29F83F7516DA66
+:1077500049CB93407E02E59ECE2F92D04F59E84F01
+:10776000308C63670512E21DEA97D86EF9C3459322
+:1077700082487F7E81E4DFB2E7009F603DD2BEEBAE
+:1077800049DE9535DB0DF316561BEDA3E5267BC8C8
+:107790006C2F5D4E5E9CD6F054B73B4E4B95A59139
+:1077A000F212E45C4D2E307916C2FD0C18D64D59FC
+:1077B00000CFE74415CB17EBA2887F962D3B7F8344
+:1077C000A697DE8878C0DC7E3655B7D3C3E86C79DF
+:1077D0009D6892DB46F882FEFC01EAC78D099A1C7F
+:1077E000F51791DF6E548E1A9F8BEBB852FBFB8A14
+:1077F000F5DB524DBF2D25FDF624EAB7B09F766C20
+:1078000012D61FF45DF2EF9C9A7713D95FA7BAFDE9
+:10781000675ECD7FC6F59453F9459A7FC7AD97074C
+:10782000B07EF89CCE2FDED7CEE1ACC6274F6B7C66
+:10783000B253B3B71A347951A7C98B53F99ABD958E
+:10784000C8485E58AD2ABB123E734B4B8C493E2450
+:1078500098ECA821A6F331CA8BED5EDF6C3C077B68
+:10786000D268C37B491E6FD4CFF71D263FF24585F2
+:10787000E7156D429CC0B8C9429EA7C51C6DE44780
+:107880005EE856A87E08C60BA13D9A54984FA2E325
+:10789000A7FE5E4EE4EFF5723CECBA06DBA5B551EF
+:1078A000B9762163980F33421F07C051037AC21083
+:1078B000F467C33C4960A0617B1DDF87166FA37628
+:1078C000D9154C16A0DDEADC34C28724A6127F1934
+:1078D000B486A998F7C202CF52BBBDF7C23E00EFF3
+:1078E00043B5D3C92E2F72C4F2B837C8C7FEF1AC66
+:1078F00086C7773D09A4B70CB572D4EC136FB57683
+:1079000097C3DB303DE82EA20B66217FC4B6987189
+:1079100012E269A1D34B7E03C0EBA577A27EFFA242
+:107920008DFB0916723F707BDE9487D1DE1DF794C4
+:10793000937CCAED2B757F6517E1736775911FE521
+:10794000DEAF3D5CCE8D79EA130BE6BD751E646E2D
+:107950002C1FAB7EF6FCAF486F17C81F74B23A8776
+:10796000F365C6BC98C779D293B391CA53C130CEE0
+:10797000427A50375A711D00D726AA5FB17512EAB4
+:107980003BC745C2DF242DDF48C6734DEE2927AA29
+:107990005A991DA472523ECF13FC99A61FB469E7F1
+:1079A000F9B8E6A7784CA39B168D6EBEAFD1CD6615
+:1079B000B3DF7917A79B9156F7D618288FF4BB48E9
+:1079C000CEBC957F96D60DF42F635C372D4F6C9A05
+:1079D00008701B630F119F2E02B1B711F63323BF3E
+:1079E00086F2188B7C8CE21685C535B4BE10C6981D
+:1079F000AE43BDA94610B57AE48F631282D4BED0DF
+:107A0000C164EC5FE479FA08E6E32EF40168A03C77
+:107A1000B3B84620F894C178D0FE48F5761AEF54F2
+:107A2000055F47BB8BF73F59C6643F943398E7E83F
+:107A30001D7C9D5E8C8B9EAA7EF608C1BB98C3FB05
+:107A4000BA8F2C067ACC0A461BE87AF4BE7843FD3E
+:107A5000A81D2986F2406FBAA17D82C748EFD123C5
+:107A6000C61BEA4F7A8A2C2867753B4FF78B757ACD
+:107A7000B8DC9DF194D382F058A4F90B1061D920A1
+:107A8000B4BA18F97D1B353D91350F6798C7B1F72A
+:107A9000BB16CA13D85C5CEBC0FC878B6D563A2FC3
+:107AA0001897F8C8A9C3561AD7915627A01FF33EB6
+:107AB00080B318A6FF35EAF24D8B5FE07AAC61EB3C
+:107AC000895718668E75B76FD1F069BBB60EE0DBCB
+:107AD0003324B2C7399E24E4338B04FD071673396F
+:107AE0006DA6CB36ADFFE35AFFC7347CECF4ECDD7A
+:107AF000188D7059CC481FC915D76C8CC275E433EA
+:107B0000A2C7B6E0D1E870FDF1677D8D533C2197A7
+:107B1000C6F1733E3A7A81501B85E7BA2BF4A7373A
+:107B2000E1F9C2A70D1B6361BD4F08AC0D294AE7FF
+:107B30009FBAFE7DDD678D543F7A3C986850FFC246
+:107B4000674DBCFD64A6A0BFEB679ADC69D4E8274B
+:107B500063DF58F22F5EDC6123BBE7B1F9ABF6B40B
+:107B6000C07A47CDBDE789E7105FE6DFF3BBE79456
+:107B70001E3DBF687E7207E6F18FDCE062C81FF42D
+:107B80007933F67D924DEB96AD0CF1F4C7FB9F5F18
+:107B90008EE33DFE58B44585F17FBCC74AFCE5EA5B
+:107BA000FB1EDEB383E48D492FF618EDFCC737B713
+:107BB0003E7110DF573DFBE8B9B07C9D93F3360D65
+:107BC00043BF69FB868A9699197DF3CF221BF3A1E7
+:107BD000FFC7F3C227CFBC0EF3FFC677F5F8703BA3
+:107BE00060D42CEEFF69DF50D53213ECD4D122CF14
+:107BF000576056FF4684C7E89F0E52507F0352B02D
+:107C0000FA00969E39511615F6F79B807537F1816B
+:107C1000399B33F03CB37F9C7FF4233CE7531ABE7F
+:107C2000F7A18FE87EAAEEB2A410DCFD2F3AB87D52
+:107C3000A32AC3C83E762BC30AC3F4B9F67BF43833
+:107C40009EFB3DE4E3852531145FD6E32EA2E7CF0A
+:107C5000F5C8E7974DAD9C24D3FA8DF1FC1484DF71
+:107C6000048CF7F2B8BDDF6F65941F045B433AB92B
+:107C70005B1C4D7927EFAEBE8BE2F6FE1ABB9C91E2
+:107C8000487183A7B05C057CC73E91E2B901CA3751
+:107C90009EC5F3372E2CAE7DD8A6F40DFFBACB9C33
+:107CA0008FA49D8FF9FDCDDAB9D4E2B96418CEE581
+:107CB000A86F6284738975107EE9E722C636D2B94F
+:107CC00030873313F33F067394C2FDBC8172A8E37F
+:107CD000944872EC3725EB6AEE86F2F94B0318D222
+:107CE000851E57294DE279087424C0B724ADFF6082
+:107CF0004DEF463E867A77A91677E958CA28EEA254
+:107D00008F77B16A80CCC7BB8DF4E6D24AA07F944E
+:107D100025313F27FDA27E38CF932875762DA5BC4F
+:107D200055C1E2C6F8F960935EEF6795B4DEC1EF26
+:107D300088E4CFB7C46CA1FE83013C6216B6B211D1
+:107D400010A83D0A76305A31AF24055F28617A9633
+:107D500096B73BB8EAA75C3FCA819EC986F9842FD3
+:107D600069FDB5EF8BC807AAEC0AF23DCCD142BE43
+:107D70004DF04B433C6AA5FEF2B7998CF73998CA8F
+:107D800094C4C9DC0F86F399D70FE371BD10F433A7
+:107D9000DCAF50CDE7DF3597DF07618799126EB70B
+:107DA000B0F0F50C3794353F99B12C25D90C72EA17
+:107DB00037978A0654F6EBC733F6B728DEFEFDBECA
+:107DC000156176577A4F7B3D5F4C87734A95FDB4BA
+:107DD00010DB77BFED5EF5C02CC06727F366FF0AA6
+:107DE000E0E17B4724796789394EF0084571F874E2
+:107DF000EBB38BB9BE0BDA790DE55D83BCC3F3C37E
+:107E00007CED9180EFCC6FCC17D0E7D5E34B1D1AFA
+:107E10003F0EA58522FA058F69F4DBB9E173CA2B01
+:107E20002845FD167039B4F163C33D900105338ECA
+:107E3000E1BACDF908BA5E8A7296F0D7CFE56C87C1
+:107E40007F02F19D8BCCD54CFABF99DF5819E57FA5
+:107E5000DC2D46BB9BC86F772FE58F54F9EDB21D23
+:107E60009EF3DC467FCC82A9467950A02698E48513
+:107E7000D1DFB5D06B8C138D68594FFCEB22EA4DE6
+:107E8000C4EFF87AAC5A7E9984F74C44B4D7FDF429
+:107E90003CAEF1E737353D330AF92BBC8FC1047393
+:107EA000C047170B517900A2FC704C6D5728EF3179
+:107EB00081A9541EC87C54D6F3219359809E7A9E82
+:107EC000CB3016A2F255A80F8948520A3D87A31D50
+:107ED000321CF53C7777BC87F22773D2285E50C0FE
+:107EE000D4F7B05DFE844F49EEE5DFC4C80FCFFC88
+:107EF000F52B5428772CD4CA98098FF926B98C23EE
+:107F0000A7BF96D7E7E9E5BA152AD6CFE0EDA5D900
+:107F10004D7BFD4EE25F5AFD265EDF5D6E583103FC
+:107F2000CB9285CA715AFBC299AA6D36E62DCD66F1
+:107F30008407C11CD5317B604FB92C478D0E2FAF04
+:107F4000CB559DE1E567B3D5D8F07267B62A879720
+:107F500087E6AAF1BCCCFD4EEF48EA30B477E1E702
+:107F600047C2648E87F8F39AE44BC176EA0181E058
+:107F70006507BE8DF092981A44A60464E3C07C2283
+:107F8000E033B63BA19E8DB751DE9F25C699DA9F9F
+:107F90003FD24C5F21891D443FDD02AB2F13F76DAB
+:107FA000E67B82FF95BF633E0FD04336EAF9A16AB4
+:107FB000AE0784AAB93F40A713FDBD79BECBE13D12
+:107FC00053C3FCBCE93DE3F6B57E331E9FD0F4BD40
+:107FD000764DDF7B47F34B77EF37648DFBC0D143A2
+:107FE000DF7DF34F2BFB208C7FF6DEEFD9A51297B8
+:107FF0001F32CA8B8E28B638D2FDCABED6E7CC99BE
+:1080000055309BECDBA132C51998CEF739BFE9C0DA
+:108010005F810F8E19A0DBAF6E07C2218325CDC90A
+:108020008479B77918E9AFB5338F1622FFB95802B2
+:10803000120CD675F68E7348714C788ADB13CDC35B
+:1080400018ADD7952647A1BE54AFF14D3B8BCB1B46
+:1080500081EB1F6A25796B5E777D6C40C0B8624A00
+:10806000308AFB371259200AC649F1B83D94B7E26D
+:1080700017650F964BD8FC4C282F6F11150F8C737A
+:10808000ACA58895C3B8E55381CF51663ACFA78890
+:10809000D7F0788C9D51BE45EB4027C5ABEB368FB2
+:1080A0003AB212F966B2C832A0FDD8FAF11EF47BDA
+:1080B000D63AE3E329E6A4ADA7D6E97E15EF63F847
+:1080C000650BBF4F22AB0ECC47DF7D87D583FC7C91
+:1080D000D8D31363C530F89FAD3B1F8579EE8FCAA7
+:1080E00016AA7FB43ADB718B13EF130655CA33908F
+:1080F000CFA84E987727B4190CE3DD5F71A67924D9
+:10810000EB1B1F623D36039EC6B86D263FA8D16F9C
+:108110002999F483E6D95AFC7B329B8CE77CED13DA
+:108120009724D473973915F2A367370A949F123AAC
+:10813000E24EC5733ABB7514F9CDEB1A45CD6FED20
+:1081400026BF7568184BC57B3665CD02E9C562DD73
+:108150009F6BB0DF55994A328E73D5C4AEE4707F01
+:10816000D9A3F7DC15857CB4AEC4A2F9B9198DA3E7
+:1081700028AA230DF6FF7E9DC0F3272459C0FBCC0F
+:10818000AE07C5285C57A7C4FD144DC04FF19E6EC5
+:10819000D38CC27EE950FA1BAC33CC6EA94F4C8F06
+:1081A000C6797BF05725FFFAB9E609141FD9D39891
+:1081B0004DF920E671EEDBC0DAD03EA9DFE0A06722
+:1081C000AFFA546FAA1BFABFBF6D46030829F6FE2B
+:1081D00091D549784F6865B39D4545C0E373DBA6EB
+:1081E000D07C2BF13E33CEDB5C60433931BB6586FE
+:1081F0000DE176DF06F5E9F079EE2CF0BD8C7C2FF1
+:10820000A6F969C213270BFA119EBFB8414D45FD6F
+:10821000E25C068B982F796236D7335EBFC14BF78D
+:108220004ADE1F16B9DD3BB3B9DF792E120BCA0F38
+:108230002B7B7315C0B90CE8A9065E9D6D9C108B55
+:10824000782BB135C4A47E5352E4477BEE02EAEDAD
+:10825000C0CF1BEE59B4A31CDAD5DF3BF22D64CF9F
+:10826000D7DAB8DECC7E2D125D805E5886F4F997A1
+:1082700062875C1BC67F517F540DF9825E86FA9D32
+:10828000D428066DC0CFA5C31FFC37DA3B88B76A78
+:10829000181ED3CF64CD2ED0F235922693364E3FA2
+:1082A000F5731605820CE32E2B1C789E663DBD17D8
+:1082B0009EF45A47D8F8A8E7CE646A54D83A802585
+:1082C00004C95FEEE3F376B7D3EAADC060BE0CD36A
+:1082D000DFCDF5FA3E46ED30D2ABC3C3CF0BE0DBCA
+:1082E0006FBCEEEA80B1DF480FA3731B2DAA473F96
+:1082F0004039DB2A527EF598561EFFBF3894919F75
+:10830000A8AFF174FE8B3FD6411A1C01AE0D8985D2
+:10831000749E7DF5B3054EA869E37AECC3AB938CEC
+:10832000EBD2DB8DECDED73A16CDF5C136B4CFEC0F
+:1083300001E07BE3F0794245F99DB9FB0EB9BF7DC1
+:108340009BF9D94A5669437D4D51427BEE43BED1DC
+:10835000E222F983E83062325D5D24B983FDD430D6
+:10836000BEE77A706FD36858C7B95DDC1FDAB46DA9
+:10837000EF134FA0DCD915E3E671267E4EE3982E6D
+:10838000FF78FECF2DACE74719A48D0FED3FD2E467
+:1083900029C350D5A09E78D50707967FF604FCFA2E
+:1083A0003EAB9C8A7C4CDA5DE4B819CAE36C81244C
+:1083B000E4A7B7ECB2F7AC0BFED95B8C65699FBD47
+:1083C000175E3A747C82F19A0E3DB16339CAA943B3
+:1083D0000E37A688237EF90D74124A2F007AEABC64
+:1083E000E73FE89E7EB47C7E29E5B957DBE97E97BE
+:1083F00019BEFB6673BB9F69F736747A8A6A1EC51D
+:10840000D0BF7846B39BCE6C013B15CA0DD536055F
+:10841000BF6FD0E92E5093228C67ABB69DC67365B3
+:10842000E176627ACF3EF4F13BFDDC0FD900E30B3D
+:1084300011FC7D971BEF4F5EB5C203F87FC1EBFDCA
+:10844000B607D67F76CB0ADA6FD5C1EACE5FE1F9FF
+:108450000EF2DD86F567B60C9F2CA023D2AAD0BD04
+:10846000BFBABA67489E344F857760CF37B759A3F4
+:1084700050FFF0D759287EDBDC96183D02E594D3F7
+:108480001231CE1AF070BED9234FBCB1E1FA50D3ED
+:108490004CAE0F094F95DC9F0EF0AA3BC5F3147547
+:1084A000FD43D6F0648C5D26FE2CD7F13CB71E7DD3
+:1084B00088EBD51751AF467D6952B91C2E9FEA63F0
+:1084C000F9F730CA67BAFD781F33C7C9487E5C85A3
+:1084D0009716D06FE16481D969F8BD0C37C3FCDC15
+:1084E00078D07F14C0F8C12D5CDF89763ADD2AE2AE
+:1084F000BBCAE9CA01FF213CA3335586F3584DFAA4
+:1085000085CDA43F88A6F24E8F519F50983B16E12F
+:10851000ECDADA7F1E87EECF05BD89EE9BF919C034
+:108520001FF1D4E1A7F389054302ED0AA6AA4AE2A6
+:10853000A01EBD1FEFB571FF8A4CF122416D20BF17
+:10854000FDAE09DCBF91CC78DC2B45E5F6FCB8A983
+:108550007E2A83FD407128F673168D7C79BBD7F790
+:108560000CE24D9A1020FB2F7E2C1388ECBFA65EE8
+:10857000CEAAAE2CAEF4C3A3DCFF576B897647FAC4
+:108580009EC2A1B99C1EA38FC1DEA09D789383E2F9
+:1085900079B9E28146C4A79D132DE4D7DEC94EC840
+:1085A000C84F8E7B787ED125AFF7750FC565BD6945
+:1085B00008FF242B5854A0ECDA343FEEB03BD3A391
+:1085C00051D4BF9BFC3CC1C30FB0CB807FBBAB126F
+:1085D000E333E1FD23551B09AECA40EE27D3EF9FDD
+:1085E00027C8FC9E7F93F7BC1FEFF9FE702EBF07D4
+:1085F000145D609D930EE5ABAA4302D2DD26977B06
+:1086000031E273A3F20C9D475A9662417FD9102B39
+:108610007BD53E9EB127E3783D0A4AACFFC1D241EB
+:10862000BBC3F3491ED0F6FD0321B2BEB27C2E9728
+:10863000271D87009003D03E669AFDFD7839D9CF7B
+:10864000DD65801BF47FC0CFEDE73F7B1E2FF75B1E
+:10865000C92ED2ECF7F672B2CF315E0AF573F2D6BC
+:1086600095FBA1FC485AE47913F2397C1F794DDD62
+:108670001103F0F86B0D8F63F57DCEAA6001DE5219
+:108680003B90A5E23AEB5CB6C591BE27B3329FEFB3
+:10869000B723B18DE0C5409EC75E47F7E94DFA6A42
+:1086A00080F4E00B15E3FD536877958CE2FFC04F33
+:1086B000264DA6ABFEF4E39AC4E5A8596FD5F52B79
+:1086C0007DDEFB522B9351FF6C75A9C43F5A416F5D
+:1086D000453C2BADE67A6BA9B5EB3DBC3F94729C53
+:1086E000E7BF084F8D6DC2EF1B00BC14C4BBD94E51
+:1086F0009521BF1963F7D23DA35ACC5F977BF457FE
+:10870000260E3DE283F7D21091F4C418B98DF457C8
+:108710003693E7E5AAF01FF21B5D9F758EB51AF23E
+:1087200077EDA6FC5EC994CF9B99A7E5C369FCC60B
+:10873000356962BF7AD3CFC1DEC5751D067E83CF92
+:1087400020D8BDF83C0A76393E5F02BB1CFDDD2F08
+:108750006FC8A4E7AB1BDCF4FE571BA6D2737A6A82
+:1087600048427D9BFCCEE47C644181FC773A3E0527
+:1087700046648FC5FBC7BC7EE69C94FFF05F0FF597
+:10878000895A7BFF17849FDD65A6ACC4F6A549BC5A
+:108790007C302F7525FA775E2B56B3F300CF065A3F
+:1087A000BC65F85D07F65D3BC527CCFB3996A7CBCA
+:1087B000EBC8F63AC34F1618FD35DEBC7EFC353FDC
+:1087C00010F83A96CF5DB70FD731A0C0EA457C4D7F
+:1087D0004D37C609F6E769F107ED99FAABCA878804
+:1087E0001E04A08789FDD14390213DEC74B11B91FB
+:1087F0001E5A5747A6871BF2B95C6D75727B8FCDE9
+:10880000017A1802E512B3FD16A2FC8F0B557B8F7F
+:10881000647C23F4A026A13CAD5B0DF214C6A93BF9
+:10882000B2FA5D92A3480FD07A30D203D247183DF6
+:10883000E077585AE3347A900302C681801E82782A
+:108840005FB04EBBCF11460F02CAE16E7AA8F86640
+:10885000E9A129CF287FBF2A3DFCE28610E53174CB
+:10886000A40592110E3B25EE3FFAAA74326C8E8D50
+:10887000FB8BAE7127217FA995383F9D3DF434F9DC
+:10888000E1F21D6E11E58A47E178983B71027DFFA8
+:10889000E7CD3C1BFF5EC102750FE1FFA28FC8DF71
+:1088A0003AD0C2E9EBD86B7BCB112F87D5B717CC69
+:1088B00046BC582F92DEDB6B7FF334FC11F8FA4193
+:1088C000034A0E8FE7FD671EAF57D69FE4FC368E36
+:1088D000C919B09E24BF5CE8C1F8CCF516FABEC732
+:1088E0008082F6389493FA78CC5A998CF8852AA825
+:1088F000637C6F7A819F36699081DE7EDE1FBD5D6D
+:108900008EBE676BF4053F9477EBD3EE2D7E55FF5B
+:10891000699FFEBC6B22FB07B76872AE55E27918FF
+:10892000D05AC67BFA4F797DBFCD23FFAB490F3BB1
+:108930002C07D15FC6D6C6927F37C9CAF5AE24854B
+:10894000E78F0C617E82B31E07D3F53645E5793E8D
+:10895000B905BEB338EE6EA61CC1EF1938DD6C3117
+:10896000C5B9407FC578F576AF7A8EE6FD9AFA589C
+:108970004281FA497FF874FD22B50BC7EFAB7E4602
+:10898000C15F8E7D89718B6A9ECF6CADBE9DEE738B
+:108990008960AF5830DEE969A3EF02C9B24D51C812
+:1089A000EE52E763DE62AC069F59E227A47FB7264A
+:1089B00081FEEFEEF183EE4CE6714E113DDCA077C7
+:1089C000B61E77FB6F81796CC037FC788F3D1FF442
+:1089D0007428C7A09E8E634DE5FAB87EFF2566AC6D
+:1089E000A6A7ABC638DCE5F4F4017334B9399E4D63
+:1089F00044F8A45A94EDD3E0FD8487724FE2F14C21
+:108A00007A7865028AB329BBEB8BF0FB57ABF7BFD3
+:108A1000BF1BFD92D37E6B6748A7AD87B89EA22E81
+:108A200060742FF90AF83CD1C90DF94F97FB472024
+:108A30007F898C77AF6B78D781789768C0BBCC394A
+:108A40000323E29D1FF9F13F8077E3E718F12EDF62
+:108A5000847713E6FC6378771DAEFB138CFFC03878
+:108A6000EF2D546F98D30F1EA62E5467CCE9070F35
+:108A7000C3FCEE644F8D645551E1DF15D49F0D2882
+:108A8000E7FA89FBDB379F21B9595B95E340FDADE0
+:108A9000AEE4CC1B1847F84B955D09F713819E6730
+:108AA000D083615CE60703F6683ECF633EB6DE1E08
+:108AB0009C0EFD4A65EECF2F95DD0CF3A845679718
+:108AC000E4037EB52CC9C750BFB627597AFC12F013
+:108AD000EF5AE9843707E0DC097214CE984DBF677E
+:108AE0007B22FA9B5E3B3495FC4E3A7D74C4F17157
+:108AF0006FE802F914D67FFADF406E85E1FB0C6067
+:108B0000E0E1E51C47B2A17DAE9C66A89F9D74B5CF
+:108B1000A1DE3569DF4CC40BB14C8BEB6BF7CF7426
+:108B2000FD618C5D253C6BD5F4DB3C25CBD01FF57E
+:108B30005CE47F5694EB503F37739A613E5DBE5FB5
+:108B40000FFF21DD8A26B96D96F356939CEFACBEDC
+:108B5000108FFCBE618EF1BEDA666B289BF808E3CD
+:108B6000796A575DFA05E17FA7C2F1BB4EE2F8EEE4
+:108B70009FAA7D67C5443FE36CDC6F56BBC4417E52
+:108B8000FBDA43DF7AD717E64F622CF01ADE671C58
+:108B9000171BAFA03F7E8895DBCFB2CAEDC0B1AE48
+:108BA000EFD3F86C35979F82CCBF37B90BF8027EB4
+:108BB0003F8B1D0E913DCFBE6BA3FB4EE3E6C7116D
+:108BC000DEECACB0501ED60F856094301CE9562503
+:108BD00039C392985C47F9876FF3EF1432E6DE9C55
+:108BE0008CA6B44A79826CAAA3EB352D2F15ED948F
+:108BF000280F736F9C867C90EF337E223F3FA79BAC
+:108C000097E5EB7959B75FE3925833E6990EC1F1D6
+:108C1000A06D6215936BC94F10A4FAA11E76A2969F
+:108C2000E6E7FD0797336F2394C54A55F3DFFAB49F
+:108C3000787517C591D3057734F2EDE1A297E2C8B4
+:108C4000B14CA638730AABA4678C10E44CE36BF20A
+:108C50008F6B010018AF67B136F2E766FFD8C9D055
+:108C6000EFD6EAB2EDA1FC9890427EB94DA7F8BDCF
+:108C7000B6DAA577BD3109DA37BEC1F3F3370DF3A4
+:108C8000BF8B748D3889F742456725D50F7E5574A3
+:108C9000CF56F07D33C37BC4CB9C9600860AAEB51D
+:108CA00075FD12F3EE58BC8DA13E5207FDCBA0BE60
+:108CB00073A905793143CDB4DBFF88F53778FDAF73
+:108CC000A39EFBDF03E81E3233F90D5B7D5C5F6E14
+:108CD0004DB4119DD7966427E1780D89D174DF6C6E
+:108CE000F18D956F20FFA87D5B746F14781FF4A73A
+:108CF00013EE613CDFE64D433DD4E6B4517E87D9A7
+:108D0000EF6763DEB726C1BEEAE26E49EA4F1FEAAB
+:108D100033CE506209DA62AF3CCE507FEF4D14572C
+:108D2000D0D7A9EFB3A1E4BCB45CC1DFFEC1384326
+:108D3000B51039CE10E2DFD3C8C0FA71081FEECFEC
+:108D4000FEBA71861DF3BE5E9C41DFF73CEDF77CF9
+:108D5000406C2D5F82FCED746E969EF585C1711F8F
+:108D6000AEAF147F53F87BF49F2FD0CA6F1C68FFFF
+:108D700004FDE4C77F74F4003EA75F7AB4642DE07D
+:108D800045C154EECF7FEB7B710FF2E18C7EF97918
+:108D90006EA3BF1C7F103F691D02BFE71E5E5F60B0
+:108DA0005A57B6D5E85F9FE934B69F9568ACF70C83
+:108DB0003596F5BC15F37E37C6DC4F79679BD63107
+:108DC000FA1E110B3F0FF1F265BBD21B4FC2FDE53E
+:108DD000CC9D4674DFF90EA77BEF8B7F71915D9977
+:108DE0006491D10EBDB0B87ED3EB4A783CC0A322CB
+:108DF0001E7DF193B16FA25F9BC9BE20E6F12DCF1E
+:108E0000E1DF61EAE59FD7FCE3195547DA6686C5DD
+:108E10004F9B06F96E9A0BFA4B4649A105F5878CD4
+:108E2000AA97A87ED19249FDE291AFEA98611CFC15
+:108E30009E1DDAB7BEAA97E97D5FFA8E45F1F37CF5
+:108E4000B86ABB42FE5FD3F76E7D98CF867C3E9DAD
+:108E5000CB9B5A89CB273815265EC7485909DF971F
+:108E600045E17CFDE2547E4F820117427EA58F676B
+:108E7000968FBA1C70AA5C7FF4559BF2EF4CE36F9F
+:108E8000F7FAEE990B7425381B789E5D8ED6EE307E
+:108E9000D74BD91C26A35C867D46CCBBAC9BABD9FB
+:108EA000997DE47B31DD0E2C7EF55DE4875FD90E84
+:108EB000EC63DCE9A9A1A591EE23EDCED3F4F1A8F2
+:108EC000D030E4C31D5264BDFDF6E2593BE6F6A383
+:108ED000D7629E6A78DE44AF7D7FCD3CD5DF7AB81D
+:108EE000FF4B8F3FEAF9AACC1A188FDFCFCC74FE64
+:108EF000FA668A2BF691A7BAC9E50EA1BFAAB62CCD
+:108F00008ABEF7F875FDD56734BFFB037319F78781
+:108F10009BFCF5E6751FD1FCD797BCDE20E24B5FCA
+:108F20007E7ABDFDBBC991FD64C9F3F5FBF3DAFDA3
+:108F30001F0FD7FB54C9CD22D9057A7EA2F93DD89F
+:108F400041EDB80EBD5C569F417EB65689E32DE5D6
+:108F5000740CE9C96775A2FE477A5433D5C75670B9
+:108F60007D50D7B3642D4E60A627A08FD3441F2514
+:108F70003CEED0A3276AF4B108E803E87228E37452
+:108F80006CD1F230873A784AF7D7D5A37ADB4D1EF9
+:108F900047A4BCD3CBDA4DF5931C643739C7BF8ADD
+:108FA0007A556715BFBFD6E1EA7261DE8AFF6D911F
+:108FB000BE67DB577FDD7E12E71BEDA76525DCCEA4
+:108FC0005956A2DB4F21C9E742BF30D84FE487F59D
+:108FD000D9F307F6B6A3305F14CF09EC4C47FE3740
+:108FE000C11F4C7EA263985700EB3C32E23CF93F34
+:108FF000065771FFC7E02AEEFF4841FF471AFA37CC
+:10900000B8BD56EBE6FE0CDD7EABD3F2BC747FC878
+:10901000551A1E8CB157727F88664FD51EEF22FB02
+:10902000C9A97DCF06E3758847B66A21802E4226FE
+:109030005ECA453DD83E983E6FCA58B5D10F62CE44
+:1090400043769AFC1DE6BC816BF3353B4AF37F3CCB
+:109050002228F74D83799EDD91FB3AA2ED7FEE5AEF
+:109060001983FE8F9F06EAE76AFE8F87F0BEC5A1CF
+:1090700077B9FFA3EE10F74BFB5081B92E12FEF526
+:109080008AFB90FF6365BE9FFC1FBA3F6999533B03
+:109090007727DF2FC297BEE7E9E165F4432804CFC5
+:1090A0004F7E8971C2BA6B782EB89D6511FCF4FBB6
+:1090B000AD3AFC772619E1ADFB9FC6D803AFE1FAC4
+:1090C0003B92AD6C23CA51F1138AD7889A1FFA9B41
+:1090D000F22BDD9C6FF42B8D7F68C276FC0EEFC403
+:1090E000878B4EE273F2EE750937C373EAFEED45E6
+:1090F000F864AF7238FE751EE75B98311DCEB796E7
+:10910000E729C44F7BE0CAFD4A3A3EF6F8E378BC53
+:10911000BBB482913FAE54ADA43B8C98E78DF8A3CD
+:10912000C3A7D5849FB5C3783965666510EDDE0C9D
+:1091300080A72AF7C6D7D6E36D6B89EFADB6297E37
+:1091400082DFA51AF4D3D9357BDF8C8F197EE3FD3E
+:10915000E1CBE1638D096ECFEC98701FC2EBB95D76
+:1091600045AFE3F3F9C0BA1884D7C17DDBE7F60158
+:10917000B764431E3FC26D526F7C3C5EE06BCE878E
+:10918000F7D3DD012BF1DB0A8CD961DEDBDA286352
+:109190005C45E7933F8AFA5A7C72F379BAD7585BF9
+:1091A0007D81FC4A7555FCBB101D2EB571E4C42BA6
+:1091B000E793D7CEE3F7D8753E99A2F99952E41018
+:1091C000D1E332A047CCFF5C56CDE30A78CC310026
+:1091D0000F31890563C87FE0207ADA89F9C3D7F6B1
+:1091E000E04F27B4B30F60BDE49399BF825C7C1E4F
+:1091F000E1D5599D407ED93DDAF74555AB9BECC78B
+:10920000D9C5DE8358AFC7A5B67BD543C487BFBEDB
+:10921000BFF0487E98BFB0238E75FBD76A601F39B8
+:1092200055590CE34BA2DC2529E85FABDE2DA09C51
+:10923000583A87D349CAD04A9217BDFD6D5D396847
+:109240002F74E04DF12CC283B771DD1D557B090FE2
+:10925000AE5DCDFD241D55171222E3C1DF5C5FCF4B
+:10926000CF389EF2837579B9B31B0F02AF4DF90A5F
+:10927000F272FE3CA3BC4CD1E83EA5FAF443E89759
+:1092800016353C109DDC2F8DFC13F160701FFE47DE
+:109290001D0FEA1056801775B239AEC8EFE55EA80B
+:1092A000DE4B7FBEA5AFF55D3E2F548BAF633C9187
+:1092B000C7D7DF453CB556F17862C7FAD964275E57
+:1092C000A81664F437EFA9BE5DC0F39B5D1210428F
+:1092D000CEF0797AE5833AE60DEC891FEAF1C2E334
+:1092E00005DE687C3F1D702A291EFD7F9A1F7D6860
+:1092F00064FF1FE077FC3CD43F0FCB244F743F3A10
+:109300009374FC561370BC71B6AE6132E1B72F098D
+:10931000DB771EFA2FCA0BE8F113F23CB37FD8CFEC
+:10932000556AF473ED5C6ADB43DFD763A15C8A8F17
+:10933000601C01F9F6363BE533960B0AE5FFFDB5F7
+:10934000C03796F6C1BC9467EA2B76C8E40F734D1C
+:109350004E42FC286D10496EF7659FF4A6B3D3C446
+:109360005F5200AF347E437044391D158774271057
+:109370007F1181BFC4A01C44BA1B1BCE5F024B8867
+:10938000BF328B3B36F58AF84C0EC2B91F3E933B79
+:10939000CFC86766CDFB07E212C17CC6ED3A6DDF30
+:1093A000A87FD2BE357AEADE77099733A287EFBB72
+:1093B0005B2FD5F88C998ECCFBFA7F90AED6F54119
+:1093C000577722BCBF025DDD7319BABA17EBC3E849
+:1093D000AA96CEFF5F8FAE5AAF84AEC6CE63C6FCF0
+:1093E00063ED3BCA63BE63E1F98BFF97F38F13E72D
+:1093F00072FBDC9C7F8CF92258CE87B3A1F3D1CAD3
+:10940000F3273205EFA7D977BFB465B4C2C70BF70E
+:109410007B3293BF9399FC9B66FD2E823FD4E0FF85
+:109420003CFEC4EF8E8F865F7FFCE47F915EFBC6BF
+:109430002C81E28FF3477D7118F5FD82CD6BB53C31
+:10944000F7FEFD9FFF6C7F27FE84FB57CDFBDA14F0
+:1094500073BF068FAFE6EF64EE1AFA7E7867257366
+:1094600013DC2FE3FFEC94471AF285BD2F963FB82B
+:1094700010FD9FC7F977F8CC7E4F3D0FB8B5643922
+:10948000E9F96754875B8CE0F75C9EA0DC46FEDC64
+:10949000DE7ECFBF221DFCA37ECF657315C243B312
+:1094A000FFB318D8D5FC7EE2BE1D719502F2BB9CBD
+:1094B0001237E5DBB14BEBE8EF39882521D2034BBE
+:1094C000ABB81E38A0C0E7C2715286B27107D13E58
+:1094D000A912DC16A5375F063D33767E785EC93764
+:1094E000EC2FF867F9FB5E99FBD5EEA5BF82F09EE5
+:1094F000D4CFFD7425F430E6AD3D52E3A2EF563DE6
+:10950000A2E9D11D929A84DF397F2BEE030BF2EF93
+:10951000408B85E1BD31B35EDCF7FEB8FCEACBCF12
+:1095200024A17D34B6C73EAAEDF623B91DE17EA481
+:10953000FA0D9E43E722C049D78BB7CD37DA47A54E
+:1095400025DC9E2D2D51C98F549AE861387E8A936F
+:10955000B5A15C1493BA24D4539655F8C8BE37C746
+:10956000E1CD78628ECB9BE3F0E638FDFFAF71F979
+:10957000F5F38DDF651CA7E5A1206FC7EFE998E340
+:10958000F09BADDC4ED9A9C23BDCCC578CCB5F75D0
+:10959000E9011EE757B9BF3499713D2D259FFB4B5B
+:1095A000CD7AC723526033DADD8FD458F4EF5618E2
+:1095B000E2FA635D3C3F7ADCFC05FB293F47D70BB1
+:1095C0002B402F14482FA4EF1C9556540A1CAFAA09
+:1095D0008EE03DD36532C7ABF9F339DD5887BA4920
+:1095E0000F16AB6F67FCDE959FDE97A6F2FB60D18E
+:1095F0008867D054CCE4715FF984E8C6FB095BB19D
+:10960000E934BC0FCAB81F679A85FEBE438B5099D8
+:109610008CFCF80141A627E84A748FF0C93875D050
+:1096200012F2DF58C86F7F2CB72109D7D758B32D56
+:1096300009F336DB34BFF8B6DC0FE8FB0EE2582640
+:10964000A39E02CF887FCFF39E0582F67781DA92C0
+:10965000E8FB02AC99F44931D3C6F8DFCF71075764
+:10966000201E9D73929EF08010E0F76E5C0EBADFB4
+:10967000D67CB52DB91CD6D3E4B291165177F5AC92
+:109680001369F0BE69A01C8B7180BAB474D94F7194
+:10969000EA865791BE9BD2D219E6CF37964CA67B6D
+:1096A000748D9780B140CFDAD123DF9A04EF370B66
+:1096B00021FA0E8F7F9A85E2F02D57CF4A0EBFE731
+:1096C00028CA3653DC93EB95A262A17B73A216CF16
+:1096D000167BC5B38DF1E9AB1670BD4861CD8BE942
+:1096E0005EA5D326E37E4BAF1E4F79AF179D36CADA
+:1096F000072A9518FF8EC6D58CCE2502BF337C571E
+:109700004532AD6F3306A629FFF98155A887E31DC1
+:10971000409E9F5FC3CBDDF5DF5B85F8431FDB8198
+:10972000F2D937EF5A85F9F80AE37FF7A33693E7C2
+:109730004F96BA0A89FF964AA188DFCDBDDC7A141C
+:109740001650B5F1D8FFE6789BAFB62DC67B44978F
+:109750001BAFE75C02C4BFBFEAB87A3BF3B8E67E52
+:10976000FF5BEDFBDAA76581FEBD43467910A41AC5
+:109770006AF7C3503FB66AFCB0367B7220A8603EE1
+:10978000AF9FD3459C2562BE6CDFF411363E4FCEB1
+:10979000257E4BE3E3B75CAAF2826913F9FBC2A40E
+:1097A0001EBAE9CEBFD0C683AA97514E6CD2F90536
+:1097B000560DEA19F7372513280F16EC0B25C11D96
+:1097C00081FEB43C0D6A9F46F7647F8B79E26C346E
+:1097D000233EA2B7B76AF39AF336B66BF37ED5BCD5
+:1097E0008D73B88789246BC80EACFB6D33E52F31C0
+:1097F000FCB813FA67B364BA5F769F10A07B91FE42
+:10980000951CBEFA3944B1EE1FB27BF47C9848F93E
+:109810003268BF25E9ADC3CF219DCE7204EAED9B2E
+:10982000478DA3BF136965CD8F3F01CF1D0736FE5E
+:1098300011F33EA2478CBB7FEA44BCC76E71E3F2D2
+:109840009CFFB6E36FA80A378C5DD98CC3ACD822D5
+:10985000A8E8D7B7CBCE3D681F318740768375FB2C
+:1098600060E20B49E5C6736F15D45FE377F4FC5BE8
+:1098700005E2A3516EA35D611B6A6CBF4EA33BB3AF
+:109880007DF2801039EEFDCC022E67AC686F84E962
+:109890000DDB2485BE0BBB6DB388914CB66DBD9DB1
+:1098A000F8D9CB6F15AEC2EF76DF592F11DC5B6FA5
+:1098B000B0D1DF8B6A75C98B16635993677A9CF9AF
+:1098C000816B4606C2FFAED0D39A9C6DBEC146F2F4
+:1098D0008059BB92D02F6BBE6FDDCBBE32E1DDE590
+:1098E000F02C7741BC86DF01922BDD76FD280BBF83
+:1098F000573CCAF22F71AF786E373D7CB3F78AE7D9
+:10990000A2613EB027DFCFDA2BBF2795FC7BF5B3F2
+:109910006DF4FDB5AF6AEF6E5BBF8AE485FF76E656
+:10992000CE70F7CE0BF3BE3882F0476C14C90F2708
+:109930009AECD9FDF3A56EFEE308E3937A5ED07648
+:10994000ED9EEE766F03E5CFD479F83DDDA8E655C0
+:1099500064276F033D0CF3AA74BBF8CCD4F4C9029E
+:10996000E5FDA87EFC4EC6996C2D2F48367E4789B2
+:1099700069F97DFA7CDBA6A6D37C756887F7830737
+:10998000568F766FD7345E37BF467B3BECEF6982EC
+:10999000BD7D6E01C0FF7EA71B9D7050FF12D5B329
+:1099A00089F15774AFB2137F85761945EAC7384EEF
+:1099B0005EC6243FDA7967D80086F038E772CF4276
+:1099C000B5BB43723BC2FFFE416DB3A47D8F02E67F
+:1099D0001D4BF96D4B0B11EF4748C43FC4C42C7AA3
+:1099E0005FEEF25A2DB02EC19B6E884FE6B116EB9A
+:1099F0005AB2AB023329FE5DCE648CB794B99A2972
+:109A0000CE928B0B8489672B33C8CEF31CE6DF59CB
+:109A10009C1EF7FD449443FF0700378FAE00800083
+:109A2000000000001F8B080000000000000BAD3B91
+:109A30006B705BD599DFD5BDBA926C49BEB2652318
+:109A40001313AEED189CC43137217165089BEB47A9
+:109A5000880D29556CC749769C548140C3B4D36A9C
+:109A60005BBA4D76682DC772E2386014D3D661CBED
+:109A7000B622C0B6BB74C0A52FC8D08E1CB29467E6
+:109A8000715BDAC2B643454ABDA5D31FEE23E0EEB3
+:109A90006427FB7DDFB93796642571D28881C3B90D
+:109AA000E79CEF9CF3BD1FC78DC78E54451B00205C
+:109AB0006EFEB4BE092000E2B7DC3515695B0D30DF
+:109AC000F89A6CECE32FDA643408A084641831004F
+:109AD000A4A7D686325EEC7BA77F0D7E809B6600B6
+:109AE000DADD62ED19FC77DDAC1BDAEBE7FA2D0865
+:109AF00039BBDFE6AECC99BF5EABCE1997C134D28D
+:109B000012C086D0D29C79BE35AB353A6FA7BE3233
+:109B1000E7FBADF5CD39EBA15D3999C1FE5AFCE704
+:109B20004C0DC1137D1EAF06F036603F6BBD025970
+:109B30007D1CAF8BF882D3C5D8F9107CE88C0CB0B3
+:109B4000118CAD10A45187F138E2A5E2983B53EC9B
+:109B5000C0AE69EAC10AC4070DE9007D115CBC060C
+:109B6000FBDE6907E0BC8711865C09D0A8651C9FF5
+:109B7000263C6B13127F0798184164871493E741C2
+:109B800008B404CE5B047149C3BE2F0449EA5F05E3
+:109B9000499E8FBFE483CD004BDC62BDBF0B8C07B9
+:109BA00070BCB8212E49D82FED004346785E634A39
+:109BB000A2736AB85E5E09500969EE5775C0D42079
+:109BC000C337F7D1FACA3DA00D5512D8388FA7FA7E
+:109BD000204EE779040C70C9848F08402D800A312B
+:109BE0006EAF06BD1491088F82B18AFA759021A4D8
+:109BF00022555312F5AF80098DFA006988ACC02652
+:109C0000A304A6DD3C05CEACC37FE957A0A59DA665
+:109C10006DBAE0E4AFDC667647107FBDDBD69444D6
+:109C2000BDE75EA7EC797EA2FDFAB9FE6804915FFC
+:109C30004EDF37003450FB028F3F1589EC88E0F788
+:109C40004684EF5E75F1F86F54053E131218719C4F
+:109C50009F78F696D04E1C8F3FEB36EA80F08BF85B
+:109C600024BE08BB675E6A16EB891E41A407E1BBF0
+:109C7000B40124C2C1554407FCAE221D0E321D930F
+:109C80000C77710C8C016B5FEA57221D882E29D04E
+:109C90008A08AF72ECE2E8C03F8473C533EE4746F2
+:109CA00024C22ED2A5F6B2D0653FE1F162E9924F0F
+:109CB0000FB8B70CA0F97CFBC6998E5F91D21EA994
+:109CC00096C882F4C1FB48481FC26708043D54008F
+:109CD00083F05408FFD4F7AC067D1FF7C57CA2675C
+:109CE000BC798EFF4B90FF455FC85700E920FA8290
+:109CF0004E419217EC872213BCBE741744EEAF247A
+:109D00007A988C3C2744B975C18C446D8D6430BD04
+:109D10006AE58883FAC5525A20192949FAC00F1AF0
+:109D2000D3E74A88711B74CE4C9EC17D125E472AD0
+:109D30005E4DEDD32DB4CFE046D43028B70DBEB183
+:109D400016E6CBBB41AB43BE5BAC9AEE6AE29765CD
+:109D50008A11D7B3F1B58FE1836E1E29A671870FE3
+:109D60004656CFED9B701AA124D2EB75DFF4F12893
+:109D70007E2FAA94C165CCE1F9A453DC8F60CA8B15
+:109D8000481E847C84C27896C07CFD165204DF7A1B
+:109D90007723FE101F3B6800F1240D7F9FBF3FDC3F
+:109DA00026F4DD8391E8EB24C7A49F187F2668A4DE
+:109DB0009F3403586F3AF4F8EF64FC7E6AD8A51319
+:109DC0009F4272DC74E33E3BAD7D760EBBDE91FCC0
+:109DD00059F74CB8206DEBE71A5A1F29617E3624DB
+:109DE00070372D7CDDA5F23FEC292766BB20DFB65E
+:109DF0003CB5B624D370EE792AC94759F63A4127C3
+:109E00003588FCE4A5F11778FC42709C7B2673E44E
+:109E1000CC86E30C45188E73CF09216F64B7909EF2
+:109E200077A1DD1A417C7FD4D454C19733FF45F626
+:109E3000FCF698DF207BCE28C2797724A5D408F2DF
+:109E4000E39D1053894F25581227FAED884BC60819
+:109E50004EA939B8CBCFFE02B46B841F297DA37CF9
+:109E600066F945E0D1C2D38EF47B4EDD4778F5C16B
+:109E70006FEDF19AB9F1BFF4D5BEBE4627A5EDADA1
+:109E800027FA165BF445B51D7F05CFE93C5D02233B
+:109E90001A727FF1175E5B87E71BFA996CC8D5349D
+:109EA0004F0513E11581B0E3C524A7B5C42F13E90D
+:109EB0008F13BFED29D1E8BEF63CB0E6C5216AD2CA
+:109EC0003D8B510F105C47F17DCC9FC57E55979916
+:109ED000F951E364DFC38D7C57C1A8E65FB99A4EA0
+:109EE000937C95B7BA8D815CF8D2195A8F30A1C294
+:109EF000BA87347FFF15D477F350CB196B3FD39DCE
+:109F0000B55F5EDF19CAEA83188F67CF3754486799
+:109F1000E1F5ACBC5872669FDBEB5573E5256F9D90
+:109F20004D8F06A7E08F4008520378DEE1E1D2961C
+:109F300062EC8F064077E1D0FE1B2A2440B96ED533
+:109F4000C43C7F15A45C12EDA38FD4B3DFE865FE9B
+:109F5000F1FFDE4C7F9CF831ECD274C453E08FC625
+:109F60009489FD3B436EC3C4F1419A4FF6B50AFD97
+:109F70002C9DB7FF05F9A57758E7BD82708372F86D
+:109F8000B14DC2CF927DABF7BF82F00F5C29834CFD
+:109F90007BCB1B0DE2CF3B1480B252ECDFE764BFFA
+:109FA0000FFD3BBE8F5A95EBF7DD79C439E717C239
+:109FB0007C3FF0AE4DB97E606C13F0BE749EB2551E
+:109FC0007F3F7CE80BB2FE5CA14C39B40276D5C66B
+:109FD000BFF49497F1FA8372C42BAD8388F929EC0E
+:109FE000BB108FC4AFA8A8FD6B104F84439213DF42
+:109FF0009AEF7C9AE6BB4E21FFD27CD9DBFE29DCAE
+:10A00000CAB908F1C4FADFC9E730F11F3A77BE3F99
+:10A01000ECCA3BA733CF7F962D3A8C107E50FEA121
+:10A02000099A083FE89FB37F00DE60413BFF5C3F39
+:10A030006A0EE4A51FF6BBB94DF76BDC1EEF0F717E
+:10A040007BA25F877674AC5EE8AFE7F6C57E83BF20
+:10A05000BFDC1FE6D6C6C7B9F48DAFDCC1FEC2E1D6
+:10A060007B1D291226A5417BE95AC4C3956FC8AC54
+:10A070003EFCA07B14D4077EC48182F3AEEE505226
+:10A0800026DDC58A7FAEB0F86CB96B66D245FC5D43
+:10A0900009C63E5A08B1813B56CFC53F37CD38E699
+:10A0A000E40428DE299AB33340F14E594EBFCDBDAA
+:10A0B0002867FE7AAD3667DCA6EFD79A85DC6C0898
+:10A0C0002DCF997FB8BD35FD313CAFBFD9A5119FCC
+:10A0D00077EAD7E78CDF5A7F630E3C5B0E4AFB942E
+:10A0E0001CFEF3E7D155DD7DFE38C8A6F38F6C3A30
+:10A0F0005B72702EFAE6F3AD8DD7D2B37815716529
+:10A1000082E24A9DEEDD20ED0C129E6DBFC4848874
+:10A110008FF480D85709637CD978F9E34B3FC59712
+:10A12000D585E2CB7735E2DF0BC6971DB9F1653EE9
+:10A130005E2F145FFE691E3E4B1784CF1D8B63AFED
+:10A14000ADA178EF5599FD40B923C6F6AF6C4A36FC
+:10A150003620DC72CB1FF391CCE3BC1D6B54F62F81
+:10A160000F43264476FF0109B18AFC5FD660549202
+:10A17000BE793260566CA338BFD3611CC525CFB7FA
+:10A180007C39447EC7C1814742689420D8E5607D10
+:10A19000976C99DE4E72A5E8E8C749DC9AA902FEE1
+:10A1A000893DFFB3434E8E431ED8AEA6249CFF804C
+:10A1B0004FEBDD4A7D6B1F4408DBDBF135D7A4C8CC
+:10A1C000FF2BEFD205BF403C44F47F707B53251B2F
+:10A1D0002905FB2B68BAC1767CC46798248789DF80
+:10A1E00079218E9FEE9734BF44FEEB7687F638DEFA
+:10A1F00073BC63D55BBBB07FD0AB1A24F0894053EE
+:10A2000025F197BC03DD1EEC8F758CBDC8725CE731
+:10A21000E07E62FB35AF93FB3C5EAE75D6509CB7DB
+:10A22000BE86300DF233A7FB29AF91084C8768FD3D
+:10A23000E00D62FDB9E8236B59F61C387FC1E79544
+:10A240009738D22AC2919F9BFE3F822767DB71D647
+:10A25000E3B97EC54840A52001CCAE2BFF23BE84C8
+:10A2600054B969121DC751E6094F3BB67795503C6A
+:10A27000B5C399292F642F8650BFA6AFCDF237837F
+:10A28000B97E423E7CFE35117EF1E7105DBDC20A0B
+:10A290005DF097B8EDE6549AF006C98E1AB2CB5E1F
+:10A2A000B4CB709EF8CF9B8B071B3EC3C3FFC87B0C
+:10A2B0003CA6270B0F78AD34F93BBD5D12F3CD966C
+:10A2C000B37C001C77D8E7523A1CBCCED60FC8C767
+:10A2D0005B27883F2CBC87D064901CDAE7885AF053
+:10A2E00076CEC103AD22EB1C6B550B9EC171F1758F
+:10A2F000AA902BF885CC7EC73C3A59FE1BAFAF9E87
+:10A300001B57ACF35F7B44CDD1BF9FA1FD71DF5FD5
+:10A31000F6759F375E5E9ACA5D77B80BF8DCCB6442
+:10A32000F3F834C5B5D73A528F23A8E5D73A589EEB
+:10A330004FA15F4576ED5CF06CFAB388553077A19C
+:10A34000D38EFE59B08BF9FC5CEBD4D49459DD4824
+:10A35000FB426C02F96B6928F75CF6BCC367EFF54A
+:10A360001928A2F3A0434EF6C8954A9BA4A75D08FE
+:10A3700047C2B6FE917BB4F3DDDB0559F0119FEFC8
+:10A380004A425FC503C0F74DBC9562F98167667E9E
+:10A390004BF29D585AA18FB0BC40684913F923E293
+:10A3A0005ECE3C3A8D78049CB195C24F1DB3FAF154
+:10A3B00015022E64CB29AEF7587995AF77D5F2BD4B
+:10A3C00054D2334464C55C4C7CE155BE15D7901F14
+:10A3D0008ABC872180AD2BB8334EEDBAC5FA681818
+:10A3E000CF35B6D4C1766CCC177D6488F4D0526F6B
+:10A3F00041F9F81EE945843F4C7CCBF113980E924D
+:10A400003BC91612883A905EE3CCF9002F750544DB
+:10A410003E4B4B866F473C1EB7F802EFC3EBF3E1B0
+:10A420009F980FFF31E2D784059CE0EC44382F5B06
+:10A43000720164502AACB80FF773EBC930F90BAF57
+:10A440007469425E949506DD7F2C5078BF57ACFD51
+:10A450004C474CA27957F489F5E016EB1E9066B68E
+:10A460009E14F46479A2FD69BCD8C8D50FF9703D7B
+:10A47000F5B9FA4AADCA9DFF96C57FF9F1D0FD52F4
+:10A48000E173FEAF75DF758B81ED11F1C5BE027C06
+:10A49000912FEF2AE53F11EE7B4407C697D03B5E34
+:10A4A00065AA95E21E6F0318ECA328937CDF7DC597
+:10A4B000B7719C3C74ABC873A88AD0DB555B110C98
+:10A4C000DAE3C80FDAE3D497EF01CD15988F878BC5
+:10A4D0008DF7C8DEC4B3D69F26FE2817F78867DD40
+:10A4E00023E9D46FA37D930765203F20B9D7B5B585
+:10A4F00090DD862EE7593DE9B6F52ED20D8C6A70B7
+:10A50000E0FA236FC89C173812DECF717122A2EADD
+:10A510005235E5291E86BD38FE17D3C17EEB9E67F6
+:10A52000EEFDCDCBB8EC647B4D93E46039823B719A
+:10A53000FE498C8BC96F26F9CBC9C72062DD4D73EC
+:10A54000FB25DB6B78BF04EE279D47CF29118C5B81
+:10A550001BE7C33B6B8FF3F223231551BD1BEF7732
+:10A56000D86B703E52B6F3233DC105E5757448A61D
+:10A57000F7905EE903C683AF730CF6523E2124E2E6
+:10A580008CE36B5C82BFF64A567C06ED60EB29FCDF
+:10A590006DECD31F2A23FBF2A60BEA70BCF589579A
+:10A5A00015EA8F553A9A287EBE4ECD1CBA8EC69BB0
+:10A5B0009CAC3F5A9092E91CFE48BB1C213E8F6A1E
+:10A5C000B5B268D312B56DEEE21C7DBD5ECB8D3F9A
+:10A5D00046678FCB25C49F1A1812E279B4C5304B59
+:10A5E00048F7189941FA3EBA5E374674F28773E32A
+:10A5F00094D14E55E8D36A6177C626F587C8BF3A2D
+:10A60000B0C7C3FEE7FD550E71EF2590227EE8D45A
+:10A6100073E39AB1899A834B48CE924ECE977F735B
+:10A6200042CCDF35B0324571A966F9ABBB2A5BD9A4
+:10A630000F852131EFD6FAE579F79FD2882F927BEB
+:10A640009D40F83F5075FB30E543DF4938AF277137
+:10A65000F96EB7CE726AD36DE7D09D5C271A52614E
+:10A660001B9D7F74BBCAFC3F5AFECE913B484F975F
+:10A6700017319EC7B7AB95D12C7978AFDBC570C6C3
+:10A68000B70BFFA2DC01D18902E3EF750BBDF2E14C
+:10A69000BB81EF43F90E1D3FE94A2CED227C5401AA
+:10A6A000FC2B5D27F4EE97F8FE1D0EA8C3238E0544
+:10A6B000FBD87FCBE7B30FBAEB72CEEF0A3B72F059
+:10A6C000E87445629CE7BE1574D257ED1DD8A7F813
+:10A6D000BE4F05E23757E81EBE6729F63DD87777AB
+:10A6E00024E30AF6DD4BA2D793DFFAFCDE2DC32D5F
+:10A6F00041B25F0E8DF8CDD57757A49BE6AF768239
+:10A7000007C78740974274CEB804A4AF7588769087
+:10A71000BF3E16726894B7D998D8BC9BF6DF182C48
+:10A7200002A2F38E4E07EF77CA543969554E8E0652
+:10A73000E5BF2ABC6C77DF76C61EDA82F3DF467A85
+:10A74000C561EE5E8F76D7F03D3D7A6EFCEC8624D7
+:10A75000DBE1B5E6541FEDB336AC5245038E374FFF
+:10A760001F217F7D7C8DCB70E1B9C69B25C6F7FB91
+:10A770006B9C293C2AFC509D9269DF1FBE8FBC5107
+:10A780005D487ECF2F37F9F347C35D6EE287FD301A
+:10A79000D543F889CF8A3C54FEBC253D82FEFB118F
+:10A7A0002F84E7389EB78EE2A219942B841E988DD1
+:10A7B0007C837244DBBA15D61F9FAD74C4A92E7476
+:10A7C000A053653939E08B0E57531FF99DE3A16003
+:10A7D00094F979AC32C87268EF33D6DC5B4FFCF287
+:10A7E000DA1A0FFBED7D3FFBD5DDE4B7B7CA7FFC7E
+:10A7F000F653143F55A94CCF03CE48FA65E2EB4E11
+:10A80000E12F9EB8EA9F59EE86FA6E07C21BC46319
+:10A810006F52DD6A687533C3B7F30D6357897CD215
+:10A8200050F0D3F15DD84F87457EC12C3F2A01EB14
+:10A830006791576AB1F4D87257ECA53A5A77B722A4
+:10A84000EAC2725582F4816B91C8BF998A3327EEB0
+:10A85000BD6926370EBE322F0ECECF33817B6A49BB
+:10A8600037DAD39F775B79372BAF445760395EED8A
+:10A87000E278713C2CE2A0A43356A935CC97E31FB3
+:10A880005B7EF054BF1B3900E0A7FD1AF7FDE69F81
+:10A8900006CA10D41BFD21FEFE91B58F48D9EB46A8
+:10A8A000576F76EBAC373221829BAF2FF2F9E08EF7
+:10A8B000EE22E6038CD380E83B3A038C5F5FF3AA79
+:10A8C00034F1E9A9BF02C7A1FFD03EE5859AF9EBB3
+:10A8D000D3744E17E5BFC4394FD0395D94FF12E7EA
+:10A8E0007BB15FE7F6E5FE7A6E57F680C8F3DBFAD8
+:10A8F000E06AD40788B7F62AD127F9273B5C1ABC4F
+:10A900003D42FCE50A291AC9B7BB2A9996B2F4C19F
+:10A91000B82FF616D9E503E55EE6BFFC73057A1C91
+:10A92000D6BD62DB08EE28C225BC3FBFF77FBE5410
+:10A930004BFBBC21335F95F6F5EE66BD837AC1C350
+:10A94000FE86D087C9722FE71DC6F7D64921ECEFE6
+:10A9500018108EEE05E51EF749E1BAE3A8AFA97F0E
+:10A9600000E59CEE73A0F99D8FD33EEFFFAD882AE2
+:10A970007C48EF5FB0DCBF860148D965947B5BCE35
+:10A98000BEDFFDA4157F47B63C23EECF7A70DC37DF
+:10A9900095A4FB1FF8B90C85F076A9740573617E48
+:10A9A000484A99993C132C50373445DD7070E23B8E
+:10A9B000DC8F6F04A8C3FE579DA69BF8E0AB038E07
+:10A9C000F3D60DBF3A70FEBA61EA8B0E706973E779
+:10A9D000580419CEB352084F75C0211AC2B6A92720
+:10A9E0007A5B0FFBCBA2AEA83753CE81FA5A11F98E
+:10A9F000CF4F45CC8FF4909F1914F9AE9032912629
+:10AA0000BB1EA27AB94EEF17E25CF7D4280C5B3973
+:10AA1000FFFE83CE4C2BDF0FA750BD32BF3E2979FE
+:10AA2000BF27EAFBB5A20E69D7271BD5CCD143843B
+:10AA3000A76D6EC6C3E0B337BC49F52FBB8E1FB2FE
+:10AA4000EAC0DA6ED006C43D3EC6E77C4ED443E190
+:10AA500006BCC74ADA2453B36905D7373F41E31729
+:10AA60003AFF42EB861B2DFD86CC9D2279FE8D851B
+:10AA70004F7BDE80258FD7A9226F0D7E95F57CEB6D
+:10AA8000135E90C95FF6A947494E7642663DC9D329
+:10AA90006040F86D89C34EF6DBF6F5E8BCBE5C3568
+:10AAA000F9FD42F9BF788C01049398D4FC9447AA2D
+:10AAB000EB36F7F5F039923D5D748E6199F5DDDB8B
+:10AAC00075EBE3C41F9D5209CBA3A2998BB3F5E5A7
+:10AAD000A33D3539F9F84EF8A242EF5CD62D9EE938
+:10AAE000E2FD7D0EA0782BE1315ED409DF3F5018E6
+:10AAF0006E27A4DAF9BEBB346918EF39E83DC9F412
+:10AB00005957E75A49FAE951CBBE267C85E3BA7F0B
+:10AB1000EB11F1E7FA4DD187E9DCB7C04C1BE937FF
+:10AB2000146D23CEEF5A445EE751D29722AEB9D7C7
+:10AB3000D13497D77AC9197D94D699DF14FE842B26
+:10AB400024FC7A279869C2D7AB9BCCC7888F371271
+:10AB50009FAF6645058FAF9C7F8E27AC73F4F69848
+:10AB6000FF49F08E59FAB95133B9EEDA080E633065
+:10AB7000985557D717565797B4EF897AFA8D828F21
+:10AB8000E1B9B8E0C356D0489E90FF8ED1F9ECF7FA
+:10AB9000258DC7765773DDE512EBDBEF6F328F1330
+:10ABA000BC3F442227E81E6FEFDD020C6F81EF35BA
+:10ABB000D62DCE8422642F3DC26F7EB2C5D81AC96D
+:10ABC000CAFF9CB2F8F79445D7E5C84E53942F506E
+:10ABD0000CB6E3D740D84DFA211F7EA21F26A8EE5F
+:10ABE00073AEFD9D074FBA294F3C186E75D37BB4E9
+:10ABF00084B7B584FAA3556688F61FEAEF78F6DDC8
+:10AC00003AE223C1F7F166918FD88FFA39EE9A8331
+:10AC1000F3871E99CFD5168634E5D3FD5EE117F98B
+:10AC2000315ED4918FFCC130DB73FC3E41A9833F80
+:10AC3000933C51BC1D32C0A478321C05920BBF3628
+:10AC4000B79E4C5E5B380374AE73C191AB70BD9719
+:10AC5000D6C718DFE59B353E872BE4988BE361E18F
+:10AC6000F8DA4FF8AA3B4FDE8DF0D5706E7C9DC5AB
+:10AC7000BB2577F978F26D96F9DECF07A6F95E70FD
+:10AC8000BA8DF3227E547854CF2FDB2CF48CEC3524
+:10AC900021EAA37A5994EF970864C06898C32FFA01
+:10ACA0008A8C5F59CBF03A7FD880E80AC2478CF192
+:10ACB000997FFFC663DF6827BCBDB453E8D5758AAA
+:10ACC000A53F627817E4CF7FB2F41B5876A9D3234F
+:10ACD000ECCE46F88957E4B5059F36A23BEE2E9D93
+:10ACE000AF5FEDF6492BAF9CFFFDE79B3D220FA028
+:10ACF0004FB07E1FEC10F07D3EE1871E1D5EC5FE4D
+:10AD0000C3CD957545D9FAF172D709F3EB8217AA2D
+:10AD100003CEF18DC974FF8B7632BE493F377F1C5D
+:10AD2000B2E46DA8DF5D50EE0E2D8E840C92AB6602
+:10AD3000330E48B7FD814C88F86768F23DF693956D
+:10AD4000576583FC4D458900CDBBB93CC3F4DF108A
+:10AD50003681EA4A87FACD6F65C3FDECA668F766CF
+:10AD60007A27A44D9804C70BE938D9A35BCACC58FD
+:10AD7000A4001D3EBA59E4FF5EDD14D9B699F40E65
+:10AD8000E9CE55E86B45CC7FA4FE42F5D57C79EA47
+:10AD90007093BDB87479EA72D3FD46AB22FC4E6B5A
+:10ADA000F42732795873FEA5254FA3CDD3AC276C79
+:10ADB000B9FADCE63CBD13B4F44ED064B9F8FC66D5
+:10ADC000DDCA0347583E9C244FD97A2668EB199375
+:10ADD000E55109DAF264C91FC9137EBFCE39D346E3
+:10ADE0007ECA1088778CF9F235BE299A203A5C57D2
+:10ADF000FEE7EE6A7DEEFDA7AE0B791AADB2F8BDA7
+:10AE0000F969E6FF53C8FFF45878D05B93C3EF7637
+:10AE1000BB7656863492E2A65989DB7F982DE6767A
+:10AE2000DDAC875B73B68CDB96D900B7ADB38BB85E
+:10AE30006D9BADE4B67D16F9FE7AE4FFD96A6E6FBC
+:10AE40009E5DCEED86D9A5DC76CC5ECFF33A675712
+:10AE5000727BCBEC8DDCDE3ADB2CF6A19A5069419B
+:10AE6000FEA772D665E07F234EF5D1A1C9BBDF24D2
+:10AE7000FC383595F328894013D77B9C4A86F9FF27
+:10AE80006858D8870D5E419F7CFE7F7553F4DB8543
+:10AE9000F87FD009CF90CB95EF27A0BFF32CF1B965
+:10AEA000E47DE16F9CFF740A3F07FD8F63CCFF9741
+:10AEB00068FFCFFA9515B97EE56879AE5F39D46C35
+:10AEC000FB95AE14D5C176493ABF137B7F53F4C7C7
+:10AED0009B59FF4676D278B4C7AD913F9508DC1CEC
+:10AEE000F2627FC77E1928DF87FEC514CF43FD407D
+:10AEF0007663A1F29AB6DEF7DAF31BE1A4237611AA
+:10AF0000FEC9DBF4BFCD85E4BEDE734976D4D92615
+:10AF1000E45E13729FA88A0C53BE259127F7B61DD5
+:10AF2000453CE4C8FDFBB6DC5B725C1A14EF3E4A9C
+:10AF300049EE919EA7CFCA7DAE1D55ACF9CE0E51FC
+:10AF4000DF6A0B0ABDAA74087DA168B97614F905F9
+:10AF50007A0BF8137145F04D67DD77CFDA33B2AB7A
+:10AF6000A5C18054825B6B7FCDC489FD26955A961E
+:10AF7000EF7C394A68AB98CF2795362824FF0B968B
+:10AF8000A3806D474CB623F9F36C791A9AEC64BC34
+:10AF9000D8766512EF6D66D9930D9AC003DA93AB3C
+:10AFA0007A0BC8D3BAC5663452E09C2B7A85FFFE73
+:10AFB000CA4D11E12FA29F487E4AC259D80F58D1DD
+:10AFC0002BE856DA9154086FEB758895A11EECE8D2
+:10AFD00048B7510D03E579452FC2BBC9CC0C920C83
+:10AFE0000E7AC782747E94CF463AD7A5CA67D9260F
+:10AFF000AB2EB7A78CFD16BBBD10DFDBFE8ECDFFE1
+:10B00000F9F39EAC36B716C2CB915EE1AF1F1D7E41
+:10B010003A873F924AED2D865E50AF9AC665D1AB16
+:10B020000BF32B26D1CEB15E3DB75FB183E8B050B4
+:10B03000BFE2CEDEB37EC52EA2D3BA06E1571CE92D
+:10B0400085CBEB2FB4D8F1CAA5F90B9FEF3DBFBF5D
+:10B0500030D8ABF3B8827E35E90DBFA5372ED65F69
+:10B0600028E01F1CECE5387A46A6FA1FA2DA10F990
+:10B07000105117453D733FE10DE378F6178E7A05C1
+:10B08000BF988A6D9F220FD078D214FEC2E592033A
+:10B09000F4FB1EEA2D5FB83C2C745EDD636B8733D6
+:10B0A000E4E7802F49EFA607E9BD12C58FBFF689F7
+:10B0B000770400F594F7FF9CBCCC203B375EFC8501
+:10B0C000AFD1FC3D7105E8DDE083FD22FF374AF991
+:10B0D000BF6BB1EF8C7D9DC6F70FB8B4A308EF83AB
+:10B0E000227FDC813CF58167718ADE051DB3E4CDEA
+:10B0F00005DB4B0AF1D5DCF9C4FB5C7ABA7286FF3A
+:10B10000AEA34AE33CB98D1F350271843FB2C2C180
+:10B11000F591910F7FF3C8ED74EE0FBB0DAA3F714F
+:10B12000A115FB65CB429C47476F10C25979111995
+:10B130009469CAC70FD31BF5ACFA6B7023C6D159FB
+:10B140007146493892D3D721CAFB1E0E3A18EEA198
+:10B150007611171DF24EB8B502FAE5BEFEDC774A4D
+:10B16000F9ADBCE60D7E273856AF70DDE7FED54B56
+:10B170003A494E0E2EE14A3114D53922A902727C89
+:10B18000DA92631D740FE1D1D3D95552C8AED8ED10
+:10B1900060DE39642D6A92BE2EAA4E46888F8BEAF5
+:10B1A00082523C0B0FBFB4E08F48F1F43A7E8F26F9
+:10B1B000EC04C5BBF44E65A8FC2EAE47BA31DE9F49
+:10B1C000C6EF6EB44BBFC5B6AC428D163A2F6C11AC
+:10B1D000F99011672A42741959AA709D1279AA60D0
+:10B1E000DEEBF796BD2AAA1BE3F3419DC275A7FCCF
+:10B1F00079BFB2E7A949AE631CACFB779DE4EEE0F2
+:10B2000055C0F9EDFFFEE5AE270648BFF4231D9DAE
+:10B21000C4AF1DDC162DFB06E37DB451D1E81EEB57
+:10B22000E5B5035C27DA0806F927F97C50BC62898A
+:10B2300087F39D1D0EF6EFF2F9A20819758AFC340A
+:10B2400025C376C2092FB2DE1C3544DCA463B42AC0
+:10B25000FA825FEC7A53D0E2C7FC7B8D5A72B5DF7D
+:10B26000CAAB97587F8733D6F167AEF78E2E4EB3B1
+:10B270001DB9AF251DA2BAA13FE836285439D01C0C
+:10B28000E1FCF6E84A07FBADF3E0AE147A39FF3C87
+:10B29000CEE3EF09FDA888FC85BF4191C8EE7CC9CB
+:10B2A0003AC70653C8931616FE9BD613030D0F5FBD
+:10B2B000FE869CD2711F69D9EFE34E1C4F6E136F4F
+:10B2C0008B8B54912753CD9B07C8AEFDB8520629EE
+:10B2D0004C82F70983F36D1121DFF6BBEC8A1E3532
+:10B2E00027BE2F81AC3EBF53C9ED83DC77DEF76606
+:10B2F0007B7E7DF7EB27B2E0B56EC9ADB35D68FD2F
+:10B3000007FDBB5F3F817C32669C5FAE6CFA24FB1D
+:10B31000C342FF59FC65F31B8580F428F85CEB1FE2
+:10B320000C440BFA25FBB6083D79217DA4B9A23166
+:10B330005A7FF8A65C387759F2769705C7B558ABAF
+:10B34000E479D63BA7C31ED8FA74817B8D6C517902
+:10B35000FE1C3FDB7EC08B9796875BD123E2876024
+:10B360008D87EC30E2F345D21F7F0DAA7A367F0E2F
+:10B37000F972FD50DB0FF8E9162B0F575E21D1FA59
+:10B38000806EDBF1DC3C41BE1D2F72A6382F5DB410
+:10B3900054B5F50CEB830F7AEF79224EF2933EC849
+:10B3A000FE9E8AFC4BF5BC32328805E804A1DCBF66
+:10B3B00013D9B205183F65FAC4542BDEA32CA27032
+:10B3C0003D4449829126781B8BF8EF3FE877BA8994
+:10B3D000EC1C70509B6CFB24A471FE03B58AC1EF7A
+:10B3E00008C1D9FC2ED9DD2A3FD7516DB9B810BD9F
+:10B3F000ED73D17BB1DC77F017270F8F6DB1DE6570
+:10B400007BC023E461A36388F31D8E14BF85477955
+:10B41000579AAC9202D5FB4908703C48EF8224ABA6
+:10B420008E543B272770ABF56E73B7783FC37F5FB1
+:10B43000584B7F0F9AE1BF1BBC9A5EB7CA82AE24FD
+:10B4400027A7A0CA4175E2F871493AEB1F2DA2A7C0
+:10B450008E8683D62D8108B7F9E7BE0662FCBD1E35
+:10B4600092DC2E83096E1B608ADB4698E196D41528
+:10B470009DC73821EA1DABC090E9FB6A8870DB04E8
+:10B48000316EC390E4F6CB6D9FFCD64EA4C38FE61D
+:10B49000E145E0B5805CA711E8D9FBDB78FEC21678
+:10B4A0007D41723B14107993B6709AFD7AAF1EE11C
+:10B4B000B8CF19147C6DC3719E234FFCF7FA4FF976
+:10B4C0007F5FF2FF519E9355203F00000000000077
+:10B4D0000000000000000000000000180000000054
+:10B4E000000000000000004000000000000000001C
+:10B4F0000000002800000000000000000000001014
+:10B50000000000000000000000000020000000001B
+:10B51000000000000000001000000000000000001B
+:10B520000000000800000000000000000000000013
+:10B5300000000000000000000000003900000000D2
+:10B5400000000000000000380000000000000000C3
+:10B5500000000000000000000000000000000008E3
+:10B5600000000000000000000000000000000000DB
+:10B57000000000000000000C0000000000000000BF
+:10B580000000000E000000000000000000000004A9
+:10B590000000000000000000000000180000000093
+:10B5A000000000000000001C00000000000000007F
+:10B5B0000000001C0000000000000000000000135C
+:10B5C00000000000000000000000003A0000000041
+:10B5D000000000000000000100000000000000006A
+:10B5E0000000000200000000000000000000000158
+:10B5F000000000000000000000000010000000003B
+:10B6000000000000000000500000000000000000EA
+:10B610000000000000000000000000000000000327
+:10B620000000000000000000000000AB000000006F
+:10B630000000000000000008000000000000000002
+:10B640000000C00000100000000000080000C0085A
+:10B6500000100000000000020000C0000010000008
+:10B660000000001000009FB0000000000000000873
+:10B670000000C08000100000000000040000C0882E
+:10B6800000100000000000020000C0800010000058
+:10B6900000000010000091200000000000000008E1
+:10B6A00000009340000100040000000100009348E6
+:10B6B00000000000000000020000935000000000A5
+:10B6C0000000000800009354000000000000000289
+:10B6D00000009418000000000000000800009358CB
+:10B6E000000800000000000800009AB000400000C0
+:10B6F00000000040000093980008000000000008CF
+:10B70000000093D80008000000000008000094200A
+:10B7100000C8000000000098000095B000980000EC
+:10B7200000000028000095F00098000000000028AC
+:10B730000000C480054000300000054000009D204E
+:10B74000000800000000000100009D21000800002A
+:10B7500000000001000020080010000000000010A0
+:10B7600000002000000000000000000800009CD83D
+:10B77000000800000000000200009D18000000000A
+:10B7800000000001000000010000000000000000B7
+:10B79000000000090000000000000000000000029E
+:10B7A00000000000000000000000CF2000000000AA
+:10B7B000000000200000CF46000000000000000153
+:10B7C0000000600000200000000000200000730066
+:10B7D000000800000000000800009FA0000000001A
+:10B7E0000000000100009FA8000000000000000110
+:10B7F00000009F60000000000000001000009F6338
+:10B80000000000000000000100009F610000000037
+:10B810000000000100009F66000000000000000121
+:10B8200000009F67000000000000000000009F680B
+:10B83000000000000000000400009F6C00000000F9
+:10B8400000000004000000520000000000000000A2
+:10B8500000000003000000000000000000000003E2
+:10B8600000000000000000000000000500000000D3
+:10B8700000000000000000020000000000000000C6
+:10B8800000060000000000000000002000009F7083
+:10B89000000000000000000100009F900000000078
+:10B8A000000000080000005300000000000000003D
+:10B8B00000009F98000000000000000200009F9C14
+:10B8C000000000000000000100009F9D000000003B
+:10B8D000000000010000000900000000000000005E
+:10B8E0000000000100000000000000000000004413
+:10B8F0000000000000000000000000010000000047
+:10B9000000000000000000500000000000000000E7
+:10B91000000000890000000000000000000012C8C4
+:10B920000080000000000080000000010000000016
+:10B93000000000000000A000071000000000071039
+:10B9400000001AC800000000000000080000AEC09F
+:10B9500000080000000000080000AE4000080000E1
+:10B96000000000080000AE80000800000000000891
+:10B97000000020080010000000000010000020005F
+:10B9800000000000000000080000A01007100040A8
+:10B990000000004000001BF800080000000000014B
+:10B9A00000001BF9000800000000000100001AD090
+:10B9B000000000000000000100001AD80000000094
+:10B9C0000000000200001ADA00000000000000027F
+:10B9D0000000000000000000000000000000AF00B8
+:10B9E000000000000000002000001B78002800007C
+:10B9F000000000040000E000002000000000002023
+:10BA00000000F300000800000000000800001AF029
+:10BA1000000000000000010800001B3700000000CB
+:10BA20000000000100001B0F0000000000000001EA
+:10BA300000001B70000000000000000400001B74E8
+:10BA400000000000000000040000005000000000A2
+:10BA500000000000000000030000000000000000E3
+:10BA600000000005000000000000000000000006CB
+:10BA700000000000000000000000000700000000BF
+:10BA80000000000000001BC80000000000000001D2
+:10BA900000001BE80000000000000008000000514A
+:10BAA000000000000000000000001BD000000000AB
+:10BAB0000000000400001BD400000000000000048F
+:10BAC00000001BD8000000000000000400001BDC88
+:10BAD00000000000000000080000B0000018000096
+:10BAE000000000180000C0000040000000000040FE
+:10BAF0000000C00000400002000000010000C00182
+:10BB000000400002000000000000E20000200000F1
+:10BB1000000000200000E2040002000800200002F3
+:10BB20000000000000000000000000000000E20033
+:10BB300000080020000000040000F40000280000BD
+:10BB4000000000280000F540001000000000001078
+:10BB50000000F5C000200000000000200000F5C03B
+:10BB600000020020000000020000F300002000009E
+:10BB7000000000200000200800100000000000105D
+:10BB80000000200000000000000000080000110874
+:10BB90000008000000000008000011680008000014
+:10BBA00000000008000011A80008000000000008C4
+:10BBB00000001240000800000000000100001241D7
+:10BBC0000008000000000001000040000020000408
+:10BBD00000000010000059000030001800000010A4
+:10BBE0000000590800300018000000020000570053
+:10BBF00000080000000000010000570100080000DC
+:10BC000000000001000011E8000000000000000139
+:10BC1000000011F00000000000000001000011F819
+:10BC200000000000000000100000124400080000A6
+:10BC30000000000400004000002000000000002080
+:10BC40000000530000100000000000100000153834
+:10BC500000000000000000010000000300000000E0
+:10BC600000000000000000000000000000000000D4
+:10BC700000000001000000000000000000000004BF
+:10BC80000000000000000000000015080000000097
+:10BC9000000000010000152800000000000000085E
+:10BCA00000000050000000000000000000008308B9
+:10BCB0000080000000000080000000010000000083
+:10BCC000000000000000200800100000000000102C
+:10BCD00000002000000000000000000800008410A8
+:10BCE0000008000000000008000084700008000048
+:10BCF0000000000800060000046000280000046046
+:10BD000000008520000800000000000100008521DF
+:10BD1000000800000000000100000000000000001A
+:10BD20000000000000008408000000000000000186
+:10BD3000000084F40008000000000002000084F607
+:10BD40000008000000000002000085040010000050
+:10BD500000000004000087600000000000000020D8
+:10BD600000006000002000000000002000007300C0
+:10BD700000080000000000080000000300000000B0
+:10BD800000000000000000050000000000000000AE
+:10BD90000000000600000000000000000000000796
+:10BDA0000000000000000000000088080000000003
+:10BDB00000000001000088280000000000000008CA
+:10BDC000000000500000000000000000000088108B
+:10BDD00000000000000000040000881400000000C3
+:10BDE00000000004000088180000000000000004AB
+:10BDF0000000881C00000000000000080000300067
+:10BE00000040000000000008000030080040000072
+:10BE1000000000280000339001C00010000000085E
+:10BE20000000320000200000000000200000372049
+:10BE3000000000000000000800001020062000386C
+:10BE4000000000080000A00000000000000020002A
+:10BE500000003EA9000000000000000100003EC8F4
+:10BE600000000000000000020000000000000000D0
+:10BE7000000000000000600000200000000000083A
+:10BE80000000400000080000000000010000400128
+:10BE9000000800000000000100004040000800040D
+:10BEA00000000002000040600008000400000004E0
+:10BEB00000004000000800000000000400004004F2
+:10BEC00000080000000000040000404000000000E6
+:10BED00000000008000040480000000000000008CA
+:10BEE0000000800000000000000000100000504032
+:10BEF00000010004000000010000500000000000EC
+:10BF000000000020000050080010000000000004A5
+:10BF10000000500C0010000000000001000052C79B
+:10BF20000000000000000001000052C600000000F8
+:10BF30000000000100003000003000180000000484
+:10BF40000000300400300018000000040000300839
+:10BF500000300018000000020000300A0030001815
+:10BF6000000000020000300C00300018000000014A
+:10BF70000000300D00300018000000010000300EFD
+:10BF800000300018000000010000301000300018E0
+:10BF9000000000040000301400300018000000040D
+:10BFA0000000500001000080000800040000500460
+:10BFB00001000080000800040000000A00000000EA
+:10BFC0000000000000005068010000800000000137
+:10BFD0000000506901000080000000010000506C6A
+:10BFE00001000080000000020000506E010000808F
+:10BFF00000000002000050700100008000000004FA
+:10C000000000507401000080000000040000506631
+:10C010000100008000000002000050640100008068
+:10C0200000000001000050600100008000000002DC
+:10C03000000050620100008000000002000050502B
+:10C040000100008000000004000050540100008046
+:10C0500000000004000050580100008000000004AF
+:10C060000000505C01000080000000040000507CD3
+:10C0700001000080000000010000507D01000080F0
+:10C080000000000100004018001000000000000443
+:10C0900000004090001000000000000400004098E4
+:10C0A000001000000000000400004110000000002B
+:10C0B0000000000200004112000000000000000229
+:10C0C00000004114000000000000000200004116C2
+:10C0D00000000000000000020000604000080000B6
+:10C0E00000000002000060420008000000000002A2
+:10C0F00000006044000800000000000400006080B0
+:10C100000008000000000008000060C000400008B7
+:10C1100000000008000060000008000000000002AD
+:10C120000000600200080000000000010000600440
+:10C13000000800000000000200006340000800004A
+:10C1400000000008000063800008000000000004F8
+:10C15000000063840008000000000001000063C0CC
+:10C160000008000000000002000063C40008000096
+:10C17000000000020000640000080000000000044D
+:10C1800000007000001000000000000400007004B7
+:10C190000010000000000004000070080010000003
+:10C1A00000000004000090000008000000000002F1
+:10C1B0000000900200080000000000010000900450
+:10C1C000000800000000000200009040000800008D
+:10C1D000000000020000904400080000000000027F
+:10C1E0000000904600080000000000020000964891
+:10C1F0000008000000000008000090800008000017
+:10C20000000000020000908400080000000000020E
+:10C210000000968800080000000000080000804030
+:10C22000000800000000000100008041000800003C
+:10C230000000000100008042000800000000000132
+:10C2400000008043000800000000000100008000A2
+:10C25000000800000000000200008002000800004A
+:10C26000000000010000800400080000000000023F
+:10C27000000080C00008000000000002000080C232
+:10C280000008000000000002000080C40008000058
+:10C290000000000200008080000800000000000193
+:10C2A0000000808100080000000000010000808282
+:10C2B000000800000000000100008083000800006A
+:10C2C0000000000100008084000800000000000160
+:10C2D000000080850008000000000001000080864A
+:10C2E00000080000000000010000600000080000DD
+:10C2F00000000002000060020008000000000001D1
+:10C30000000060040008000000000002000060421D
+:10C3100000C00018000000020000604000C00018CB
+:10C32000000000020000604C00C00018000000087F
+:10C330000000604400C000180000000800006057C2
+:10C3400000C00018000000010000605400C0001888
+:10C35000000000020000605600C00018000000014C
+:10C360000000664000080000000000080000668031
+:10C370000008000000000008000066C0000800007F
+:10C38000000000080000DA4200180000000000026F
+:10C390000000DE4000000000000000000000E0009F
+:10C3A00000000000000000040000D0C000000000F9
+:10C3B000000000040000D0C40000000000000004E1
+:10C3C0000000D0C800000000000000040000D0CC35
+:10C3D00000000000000000040000D0D000000000B9
+:10C3E000000000040000D0D40000000000000004A1
+:10C3F0000000D0D800000000000000040000D0C001
+:10C4000000000000000000200000DB000000000031
+:10C41000000000040000DB000000000000000068D5
+:10C420000000B94800000000000000000000D0003B
+:10C4300000000000000000040000B0C00000000088
+:10C44000000000040000B0C4000000000000000470
+:10C450000000B0C800000000000000040000B0C0F0
+:10C4600000000000000000100000D6B00000000036
+:10C47000000000040000D6B400000000000000042A
+:10C480000000D6B800000000000000040000D6BC88
+:10C4900000000000000000040000D6B00000000012
+:10C4A000000000100000D348000000000000000859
+:10C4B0000000D358000000000000008000000010C1
+:10C4C00000000000000000000000D3580000000041
+:10C4D000000000080000000006002200000000002C
+:00000001FF
diff --git a/firmware/ihex2fw.c b/firmware/ihex2fw.c
index 5a03ba8c8364..ba0cf0b601bb 100644
--- a/firmware/ihex2fw.c
+++ b/firmware/ihex2fw.c
@@ -55,6 +55,7 @@ static int output_records(int outfd);
static int sort_records = 0;
static int wide_records = 0;
+static int include_jump = 0;
static int usage(void)
{
@@ -63,6 +64,7 @@ static int usage(void)
fprintf(stderr, "usage: ihex2fw [<options>] <src.HEX> <dst.fw>\n");
fprintf(stderr, " -w: wide records (16-bit length)\n");
fprintf(stderr, " -s: sort records by address\n");
+ fprintf(stderr, " -j: include records for CS:IP/EIP address\n");
return 1;
}
@@ -73,7 +75,7 @@ int main(int argc, char **argv)
uint8_t *data;
int opt;
- while ((opt = getopt(argc, argv, "ws")) != -1) {
+ while ((opt = getopt(argc, argv, "wsj")) != -1) {
switch (opt) {
case 'w':
wide_records = 1;
@@ -81,7 +83,9 @@ int main(int argc, char **argv)
case 's':
sort_records = 1;
break;
- default:
+ case 'j':
+ include_jump = 1;
+ break;
return usage();
}
}
@@ -128,6 +132,7 @@ static int process_ihex(uint8_t *data, ssize_t size)
{
struct ihex_binrec *record;
uint32_t offset = 0;
+ uint32_t data32;
uint8_t type, crc = 0, crcbyte = 0;
int i, j;
int line = 1;
@@ -223,8 +228,14 @@ next_record:
return -EINVAL;
}
+ memcpy(&data32, &record->data[0], sizeof(data32));
+ data32 = htonl(data32);
+ memcpy(&record->data[0], &data32, sizeof(data32));
+
/* These records contain the CS/IP or EIP where execution
- * starts. Don't really know what to do with them. */
+ * starts. If requested output this as a record. */
+ if (include_jump)
+ file_record(record);
goto next_record;
default:
diff --git a/firmware/keyspan_pda/keyspan_pda.S b/firmware/keyspan_pda/keyspan_pda.S
index 418fe69aa5e0..f3acc197a5ef 100644
--- a/firmware/keyspan_pda/keyspan_pda.S
+++ b/firmware/keyspan_pda/keyspan_pda.S
@@ -74,7 +74,7 @@
* recognizes the new device ID and glues it to the real serial driver code.
*
* USEFUL DOCS:
- * EzUSB Technical Reference Manual: <http://www.anchorchips.com>
+ * EzUSB Technical Reference Manual: <http://www.cypress.com/>
* 8051 manuals: everywhere, but try www.dalsemi.com because the EzUSB is
* basically the Dallas enhanced 8051 code. Remember that the EzUSB IO ports
* use totally different registers!
diff --git a/firmware/keyspan_pda/xircom_pgs.S b/firmware/keyspan_pda/xircom_pgs.S
index 05d99dd63776..0b79bbf0ae15 100644
--- a/firmware/keyspan_pda/xircom_pgs.S
+++ b/firmware/keyspan_pda/xircom_pgs.S
@@ -74,7 +74,7 @@
* recognizes the new device ID and glues it to the real serial driver code.
*
* USEFUL DOCS:
- * EzUSB Technical Reference Manual: <http://www.anchorchips.com>
+ * EzUSB Technical Reference Manual: <http://www.cypress.com/>
* 8051 manuals: everywhere, but try www.dalsemi.com because the EzUSB is
* basically the Dallas enhanced 8051 code. Remember that the EzUSB IO ports
* use totally different registers!
diff --git a/fs/9p/Kconfig b/fs/9p/Kconfig
index 795233702a4e..7e0511476797 100644
--- a/fs/9p/Kconfig
+++ b/fs/9p/Kconfig
@@ -17,3 +17,16 @@ config 9P_FSCACHE
Choose Y here to enable persistent, read-only local
caching support for 9p clients using FS-Cache
+
+config 9P_FS_POSIX_ACL
+ bool "9P POSIX Access Control Lists"
+ depends on 9P_FS
+ select FS_POSIX_ACL
+ help
+ POSIX Access Control Lists (ACLs) support permissions for users and
+ groups beyond the owner/group/world scheme.
+
+ To learn more about Access Control Lists, visit the POSIX ACLs for
+ Linux website <http://acl.bestbits.at/>.
+
+ If you don't know what Access Control Lists are, say N
diff --git a/fs/9p/Makefile b/fs/9p/Makefile
index 91fba025fcbe..f8ba37effd1b 100644
--- a/fs/9p/Makefile
+++ b/fs/9p/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_9P_FS) := 9p.o
xattr_user.o
9p-$(CONFIG_9P_FSCACHE) += cache.o
+9p-$(CONFIG_9P_FS_POSIX_ACL) += acl.o
diff --git a/fs/9p/acl.c b/fs/9p/acl.c
new file mode 100644
index 000000000000..12d602351dbe
--- /dev/null
+++ b/fs/9p/acl.c
@@ -0,0 +1,392 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/posix_acl_xattr.h>
+#include "xattr.h"
+#include "acl.h"
+#include "v9fs_vfs.h"
+#include "v9fs.h"
+
+static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name)
+{
+ ssize_t size;
+ void *value = NULL;
+ struct posix_acl *acl = NULL;;
+
+ size = v9fs_fid_xattr_get(fid, name, NULL, 0);
+ if (size > 0) {
+ value = kzalloc(size, GFP_NOFS);
+ if (!value)
+ return ERR_PTR(-ENOMEM);
+ size = v9fs_fid_xattr_get(fid, name, value, size);
+ if (size > 0) {
+ acl = posix_acl_from_xattr(value, size);
+ if (IS_ERR(acl))
+ goto err_out;
+ }
+ } else if (size == -ENODATA || size == 0 ||
+ size == -ENOSYS || size == -EOPNOTSUPP) {
+ acl = NULL;
+ } else
+ acl = ERR_PTR(-EIO);
+
+err_out:
+ kfree(value);
+ return acl;
+}
+
+int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
+{
+ int retval = 0;
+ struct posix_acl *pacl, *dacl;
+ struct v9fs_session_info *v9ses;
+
+ v9ses = v9fs_inode2v9ses(inode);
+ if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
+ set_cached_acl(inode, ACL_TYPE_DEFAULT, NULL);
+ set_cached_acl(inode, ACL_TYPE_ACCESS, NULL);
+ return 0;
+ }
+ /* get the default/access acl values and cache them */
+ dacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_DEFAULT);
+ pacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_ACCESS);
+
+ if (!IS_ERR(dacl) && !IS_ERR(pacl)) {
+ set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl);
+ set_cached_acl(inode, ACL_TYPE_ACCESS, pacl);
+ posix_acl_release(dacl);
+ posix_acl_release(pacl);
+ } else
+ retval = -EIO;
+
+ return retval;
+}
+
+static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
+{
+ struct posix_acl *acl;
+ /*
+ * 9p Always cache the acl value when
+ * instantiating the inode (v9fs_inode_from_fid)
+ */
+ acl = get_cached_acl(inode, type);
+ BUG_ON(acl == ACL_NOT_CACHED);
+ return acl;
+}
+
+int v9fs_check_acl(struct inode *inode, int mask)
+{
+ struct posix_acl *acl;
+ struct v9fs_session_info *v9ses;
+
+ v9ses = v9fs_inode2v9ses(inode);
+ if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
+ /*
+ * On access = client mode get the acl
+ * values from the server
+ */
+ return 0;
+ }
+ acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
+
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (acl) {
+ int error = posix_acl_permission(inode, acl, mask);
+ posix_acl_release(acl);
+ return error;
+ }
+ return -EAGAIN;
+}
+
+static int v9fs_set_acl(struct dentry *dentry, int type, struct posix_acl *acl)
+{
+ int retval;
+ char *name;
+ size_t size;
+ void *buffer;
+ struct inode *inode = dentry->d_inode;
+
+ set_cached_acl(inode, type, acl);
+ /* Set a setxattr request to server */
+ size = posix_acl_xattr_size(acl->a_count);
+ buffer = kmalloc(size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ retval = posix_acl_to_xattr(acl, buffer, size);
+ if (retval < 0)
+ goto err_free_out;
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ name = POSIX_ACL_XATTR_ACCESS;
+ break;
+ case ACL_TYPE_DEFAULT:
+ name = POSIX_ACL_XATTR_DEFAULT;
+ break;
+ default:
+ BUG();
+ }
+ retval = v9fs_xattr_set(dentry, name, buffer, size, 0);
+err_free_out:
+ kfree(buffer);
+ return retval;
+}
+
+int v9fs_acl_chmod(struct dentry *dentry)
+{
+ int retval = 0;
+ struct posix_acl *acl, *clone;
+ struct inode *inode = dentry->d_inode;
+
+ if (S_ISLNK(inode->i_mode))
+ return -EOPNOTSUPP;
+ acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
+ if (acl) {
+ clone = posix_acl_clone(acl, GFP_KERNEL);
+ posix_acl_release(acl);
+ if (!clone)
+ return -ENOMEM;
+ retval = posix_acl_chmod_masq(clone, inode->i_mode);
+ if (!retval)
+ retval = v9fs_set_acl(dentry, ACL_TYPE_ACCESS, clone);
+ posix_acl_release(clone);
+ }
+ return retval;
+}
+
+int v9fs_set_create_acl(struct dentry *dentry,
+ struct posix_acl *dpacl, struct posix_acl *pacl)
+{
+ if (dpacl)
+ v9fs_set_acl(dentry, ACL_TYPE_DEFAULT, dpacl);
+ if (pacl)
+ v9fs_set_acl(dentry, ACL_TYPE_ACCESS, pacl);
+ posix_acl_release(dpacl);
+ posix_acl_release(pacl);
+ return 0;
+}
+
+int v9fs_acl_mode(struct inode *dir, mode_t *modep,
+ struct posix_acl **dpacl, struct posix_acl **pacl)
+{
+ int retval = 0;
+ mode_t mode = *modep;
+ struct posix_acl *acl = NULL;
+
+ if (!S_ISLNK(mode)) {
+ acl = v9fs_get_cached_acl(dir, ACL_TYPE_DEFAULT);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (!acl)
+ mode &= ~current_umask();
+ }
+ if (acl) {
+ struct posix_acl *clone;
+
+ if (S_ISDIR(mode))
+ *dpacl = acl;
+ clone = posix_acl_clone(acl, GFP_NOFS);
+ retval = -ENOMEM;
+ if (!clone)
+ goto cleanup;
+
+ retval = posix_acl_create_masq(clone, &mode);
+ if (retval < 0) {
+ posix_acl_release(clone);
+ goto cleanup;
+ }
+ if (retval > 0)
+ *pacl = clone;
+ }
+ *modep = mode;
+ return 0;
+cleanup:
+ posix_acl_release(acl);
+ return retval;
+
+}
+
+static int v9fs_remote_get_acl(struct dentry *dentry, const char *name,
+ void *buffer, size_t size, int type)
+{
+ char *full_name;
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ full_name = POSIX_ACL_XATTR_ACCESS;
+ break;
+ case ACL_TYPE_DEFAULT:
+ full_name = POSIX_ACL_XATTR_DEFAULT;
+ break;
+ default:
+ BUG();
+ }
+ return v9fs_xattr_get(dentry, full_name, buffer, size);
+}
+
+static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
+ void *buffer, size_t size, int type)
+{
+ struct v9fs_session_info *v9ses;
+ struct posix_acl *acl;
+ int error;
+
+ if (strcmp(name, "") != 0)
+ return -EINVAL;
+
+ v9ses = v9fs_inode2v9ses(dentry->d_inode);
+ /*
+ * We allow set/get/list of acl when access=client is not specified
+ */
+ if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
+ return v9fs_remote_get_acl(dentry, name, buffer, size, type);
+
+ acl = v9fs_get_cached_acl(dentry->d_inode, type);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (acl == NULL)
+ return -ENODATA;
+ error = posix_acl_to_xattr(acl, buffer, size);
+ posix_acl_release(acl);
+
+ return error;
+}
+
+static int v9fs_remote_set_acl(struct dentry *dentry, const char *name,
+ const void *value, size_t size,
+ int flags, int type)
+{
+ char *full_name;
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ full_name = POSIX_ACL_XATTR_ACCESS;
+ break;
+ case ACL_TYPE_DEFAULT:
+ full_name = POSIX_ACL_XATTR_DEFAULT;
+ break;
+ default:
+ BUG();
+ }
+ return v9fs_xattr_set(dentry, full_name, value, size, flags);
+}
+
+
+static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
+ const void *value, size_t size,
+ int flags, int type)
+{
+ int retval;
+ struct posix_acl *acl;
+ struct v9fs_session_info *v9ses;
+ struct inode *inode = dentry->d_inode;
+
+ if (strcmp(name, "") != 0)
+ return -EINVAL;
+
+ v9ses = v9fs_inode2v9ses(dentry->d_inode);
+ /*
+ * set the attribute on the remote. Without even looking at the
+ * xattr value. We leave it to the server to validate
+ */
+ if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
+ return v9fs_remote_set_acl(dentry, name,
+ value, size, flags, type);
+
+ if (S_ISLNK(inode->i_mode))
+ return -EOPNOTSUPP;
+ if (!is_owner_or_cap(inode))
+ return -EPERM;
+ if (value) {
+ /* update the cached acl value */
+ acl = posix_acl_from_xattr(value, size);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ else if (acl) {
+ retval = posix_acl_valid(acl);
+ if (retval)
+ goto err_out;
+ }
+ } else
+ acl = NULL;
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ name = POSIX_ACL_XATTR_ACCESS;
+ if (acl) {
+ mode_t mode = inode->i_mode;
+ retval = posix_acl_equiv_mode(acl, &mode);
+ if (retval < 0)
+ goto err_out;
+ else {
+ struct iattr iattr;
+ if (retval == 0) {
+ /*
+ * ACL can be represented
+ * by the mode bits. So don't
+ * update ACL.
+ */
+ acl = NULL;
+ value = NULL;
+ size = 0;
+ }
+ /* Updte the mode bits */
+ iattr.ia_mode = ((mode & S_IALLUGO) |
+ (inode->i_mode & ~S_IALLUGO));
+ iattr.ia_valid = ATTR_MODE;
+ /* FIXME should we update ctime ?
+ * What is the following setxattr update the
+ * mode ?
+ */
+ v9fs_vfs_setattr_dotl(dentry, &iattr);
+ }
+ }
+ break;
+ case ACL_TYPE_DEFAULT:
+ name = POSIX_ACL_XATTR_DEFAULT;
+ if (!S_ISDIR(inode->i_mode)) {
+ retval = -EINVAL;
+ goto err_out;
+ }
+ break;
+ default:
+ BUG();
+ }
+ retval = v9fs_xattr_set(dentry, name, value, size, flags);
+ if (!retval)
+ set_cached_acl(inode, type, acl);
+err_out:
+ posix_acl_release(acl);
+ return retval;
+}
+
+const struct xattr_handler v9fs_xattr_acl_access_handler = {
+ .prefix = POSIX_ACL_XATTR_ACCESS,
+ .flags = ACL_TYPE_ACCESS,
+ .get = v9fs_xattr_get_acl,
+ .set = v9fs_xattr_set_acl,
+};
+
+const struct xattr_handler v9fs_xattr_acl_default_handler = {
+ .prefix = POSIX_ACL_XATTR_DEFAULT,
+ .flags = ACL_TYPE_DEFAULT,
+ .get = v9fs_xattr_get_acl,
+ .set = v9fs_xattr_set_acl,
+};
diff --git a/fs/9p/acl.h b/fs/9p/acl.h
new file mode 100644
index 000000000000..59e18c2e8c7e
--- /dev/null
+++ b/fs/9p/acl.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+#ifndef FS_9P_ACL_H
+#define FS_9P_ACL_H
+
+#ifdef CONFIG_9P_FS_POSIX_ACL
+extern int v9fs_get_acl(struct inode *, struct p9_fid *);
+extern int v9fs_check_acl(struct inode *inode, int mask);
+extern int v9fs_acl_chmod(struct dentry *);
+extern int v9fs_set_create_acl(struct dentry *,
+ struct posix_acl *, struct posix_acl *);
+extern int v9fs_acl_mode(struct inode *dir, mode_t *modep,
+ struct posix_acl **dpacl, struct posix_acl **pacl);
+#else
+#define v9fs_check_acl NULL
+static inline int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
+{
+ return 0;
+}
+static inline int v9fs_acl_chmod(struct dentry *dentry)
+{
+ return 0;
+}
+static inline int v9fs_set_create_acl(struct dentry *dentry,
+ struct posix_acl *dpacl,
+ struct posix_acl *pacl)
+{
+ return 0;
+}
+static inline int v9fs_acl_mode(struct inode *dir, mode_t *modep,
+ struct posix_acl **dpacl,
+ struct posix_acl **pacl)
+{
+ return 0;
+}
+
+#endif
+#endif /* FS_9P_XATTR_H */
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 6406f896bf95..b00223c99d70 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -149,6 +149,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
switch (access) {
case V9FS_ACCESS_SINGLE:
case V9FS_ACCESS_USER:
+ case V9FS_ACCESS_CLIENT:
uid = current_fsuid();
any = 0;
break;
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 38dc0e067599..2f77cd33ba83 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -193,7 +193,17 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
v9ses->flags |= V9FS_ACCESS_USER;
else if (strcmp(s, "any") == 0)
v9ses->flags |= V9FS_ACCESS_ANY;
- else {
+ else if (strcmp(s, "client") == 0) {
+#ifdef CONFIG_9P_FS_POSIX_ACL
+ v9ses->flags |= V9FS_ACCESS_CLIENT;
+#else
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "access=client option not supported\n");
+ kfree(s);
+ ret = -EINVAL;
+ goto free_and_return;
+#endif
+ } else {
v9ses->flags |= V9FS_ACCESS_SINGLE;
v9ses->uid = simple_strtoul(s, &e, 10);
if (*e != '\0')
@@ -278,6 +288,16 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
+ if (!v9fs_proto_dotl(v9ses) &&
+ ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) {
+ /*
+ * We support ACCESS_CLIENT only for dotl.
+ * Fall back to ACCESS_USER
+ */
+ v9ses->flags &= ~V9FS_ACCESS_MASK;
+ v9ses->flags |= V9FS_ACCESS_USER;
+ }
+ /*FIXME !! */
/* for legacy mode, fall back to V9FS_ACCESS_ANY */
if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index 4c963c9fc41f..cb6396855e2d 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -33,13 +33,17 @@
*
* Session flags reflect options selected by users at mount time
*/
+#define V9FS_ACCESS_ANY (V9FS_ACCESS_SINGLE | \
+ V9FS_ACCESS_USER | \
+ V9FS_ACCESS_CLIENT)
+#define V9FS_ACCESS_MASK V9FS_ACCESS_ANY
+
enum p9_session_flags {
V9FS_PROTO_2000U = 0x01,
V9FS_PROTO_2000L = 0x02,
V9FS_ACCESS_SINGLE = 0x04,
V9FS_ACCESS_USER = 0x08,
- V9FS_ACCESS_ANY = 0x0C,
- V9FS_ACCESS_MASK = 0x0C,
+ V9FS_ACCESS_CLIENT = 0x10
};
/* possible values of ->cache */
@@ -113,8 +117,6 @@ void v9fs_session_close(struct v9fs_session_info *v9ses);
void v9fs_session_cancel(struct v9fs_session_info *v9ses);
void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses);
-#define V9FS_MAGIC 0x01021997
-
/* other default globals */
#define V9FS_PORT 564
#define V9FS_DEFUSER "nobody"
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 88418c419ea7..bab0eac873f4 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -64,3 +64,7 @@ int v9fs_uflags2omode(int uflags, int extended);
ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64);
void v9fs_blank_wstat(struct p9_wstat *wstat);
+int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *);
+int v9fs_file_fsync_dotl(struct file *filp, int datasync);
+
+#define P9_LOCK_TIMEOUT (30*HZ)
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index 90e38449f4b3..b7f2a8e3863e 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -154,10 +154,40 @@ static int v9fs_launder_page(struct page *page)
return 0;
}
+/**
+ * v9fs_direct_IO - 9P address space operation for direct I/O
+ * @rw: direction (read or write)
+ * @iocb: target I/O control block
+ * @iov: array of vectors that define I/O buffer
+ * @pos: offset in file to begin the operation
+ * @nr_segs: size of iovec array
+ *
+ * The presence of v9fs_direct_IO() in the address space ops vector
+ * allowes open() O_DIRECT flags which would have failed otherwise.
+ *
+ * In the non-cached mode, we shunt off direct read and write requests before
+ * the VFS gets them, so this method should never be called.
+ *
+ * Direct IO is not 'yet' supported in the cached mode. Hence when
+ * this routine is called through generic_file_aio_read(), the read/write fails
+ * with an error.
+ *
+ */
+ssize_t v9fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
+ loff_t pos, unsigned long nr_segs)
+{
+ P9_DPRINTK(P9_DEBUG_VFS, "v9fs_direct_IO: v9fs_direct_IO (%s) "
+ "off/no(%lld/%lu) EINVAL\n",
+ iocb->ki_filp->f_path.dentry->d_name.name,
+ (long long) pos, nr_segs);
+
+ return -EINVAL;
+}
const struct address_space_operations v9fs_addr_operations = {
.readpage = v9fs_vfs_readpage,
.readpages = v9fs_vfs_readpages,
.releasepage = v9fs_release_page,
.invalidatepage = v9fs_invalidate_page,
.launder_page = v9fs_launder_page,
+ .direct_IO = v9fs_direct_IO,
};
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 899f168fd19c..b84ebe8cefed 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -242,7 +242,8 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
while (rdir->head < rdir->tail) {
err = p9dirent_read(rdir->buf + rdir->head,
- buflen - rdir->head, &curdirent,
+ rdir->tail - rdir->head,
+ &curdirent,
fid->clnt->proto_version);
if (err < 0) {
P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
@@ -314,4 +315,5 @@ const struct file_operations v9fs_dir_operations_dotl = {
.readdir = v9fs_dir_readdir_dotl,
.open = v9fs_file_open,
.release = v9fs_dir_release,
+ .fsync = v9fs_file_fsync_dotl,
};
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index e97c92bd6f16..240c30674396 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -33,6 +33,7 @@
#include <linux/inet.h>
#include <linux/list.h>
#include <linux/pagemap.h>
+#include <linux/utsname.h>
#include <asm/uaccess.h>
#include <linux/idr.h>
#include <net/9p/9p.h>
@@ -44,6 +45,7 @@
#include "cache.h"
static const struct file_operations v9fs_cached_file_operations;
+static const struct file_operations v9fs_cached_file_operations_dotl;
/**
* v9fs_file_open - open a file (or directory)
@@ -92,6 +94,8 @@ int v9fs_file_open(struct inode *inode, struct file *file)
/* enable cached file options */
if(file->f_op == &v9fs_file_operations)
file->f_op = &v9fs_cached_file_operations;
+ else if (file->f_op == &v9fs_file_operations_dotl)
+ file->f_op = &v9fs_cached_file_operations_dotl;
#ifdef CONFIG_9P_FSCACHE
v9fs_cache_inode_set_cookie(inode, file);
@@ -130,6 +134,206 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
return res;
}
+static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
+{
+ struct p9_flock flock;
+ struct p9_fid *fid;
+ uint8_t status;
+ int res = 0;
+ unsigned char fl_type;
+
+ fid = filp->private_data;
+ BUG_ON(fid == NULL);
+
+ if ((fl->fl_flags & FL_POSIX) != FL_POSIX)
+ BUG();
+
+ res = posix_lock_file_wait(filp, fl);
+ if (res < 0)
+ goto out;
+
+ /* convert posix lock to p9 tlock args */
+ memset(&flock, 0, sizeof(flock));
+ flock.type = fl->fl_type;
+ flock.start = fl->fl_start;
+ if (fl->fl_end == OFFSET_MAX)
+ flock.length = 0;
+ else
+ flock.length = fl->fl_end - fl->fl_start + 1;
+ flock.proc_id = fl->fl_pid;
+ flock.client_id = utsname()->nodename;
+ if (IS_SETLKW(cmd))
+ flock.flags = P9_LOCK_FLAGS_BLOCK;
+
+ /*
+ * if its a blocked request and we get P9_LOCK_BLOCKED as the status
+ * for lock request, keep on trying
+ */
+ for (;;) {
+ res = p9_client_lock_dotl(fid, &flock, &status);
+ if (res < 0)
+ break;
+
+ if (status != P9_LOCK_BLOCKED)
+ break;
+ if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd))
+ break;
+ schedule_timeout_interruptible(P9_LOCK_TIMEOUT);
+ }
+
+ /* map 9p status to VFS status */
+ switch (status) {
+ case P9_LOCK_SUCCESS:
+ res = 0;
+ break;
+ case P9_LOCK_BLOCKED:
+ res = -EAGAIN;
+ break;
+ case P9_LOCK_ERROR:
+ case P9_LOCK_GRACE:
+ res = -ENOLCK;
+ break;
+ default:
+ BUG();
+ }
+
+ /*
+ * incase server returned error for lock request, revert
+ * it locally
+ */
+ if (res < 0 && fl->fl_type != F_UNLCK) {
+ fl_type = fl->fl_type;
+ fl->fl_type = F_UNLCK;
+ res = posix_lock_file_wait(filp, fl);
+ fl->fl_type = fl_type;
+ }
+out:
+ return res;
+}
+
+static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
+{
+ struct p9_getlock glock;
+ struct p9_fid *fid;
+ int res = 0;
+
+ fid = filp->private_data;
+ BUG_ON(fid == NULL);
+
+ posix_test_lock(filp, fl);
+ /*
+ * if we have a conflicting lock locally, no need to validate
+ * with server
+ */
+ if (fl->fl_type != F_UNLCK)
+ return res;
+
+ /* convert posix lock to p9 tgetlock args */
+ memset(&glock, 0, sizeof(glock));
+ glock.type = fl->fl_type;
+ glock.start = fl->fl_start;
+ if (fl->fl_end == OFFSET_MAX)
+ glock.length = 0;
+ else
+ glock.length = fl->fl_end - fl->fl_start + 1;
+ glock.proc_id = fl->fl_pid;
+ glock.client_id = utsname()->nodename;
+
+ res = p9_client_getlock_dotl(fid, &glock);
+ if (res < 0)
+ return res;
+ if (glock.type != F_UNLCK) {
+ fl->fl_type = glock.type;
+ 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;
+}
+
+/**
+ * v9fs_file_lock_dotl - lock a file (or directory)
+ * @filp: file to be locked
+ * @cmd: lock command
+ * @fl: file lock structure
+ *
+ */
+
+static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl)
+{
+ struct inode *inode = filp->f_path.dentry->d_inode;
+ int ret = -ENOLCK;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
+ cmd, fl, filp->f_path.dentry->d_name.name);
+
+ /* No mandatory locks */
+ if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
+ goto out_err;
+
+ if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
+ filemap_write_and_wait(inode->i_mapping);
+ invalidate_mapping_pages(&inode->i_data, 0, -1);
+ }
+
+ if (IS_SETLK(cmd) || IS_SETLKW(cmd))
+ ret = v9fs_file_do_lock(filp, cmd, fl);
+ else if (IS_GETLK(cmd))
+ ret = v9fs_file_getlock(filp, fl);
+ else
+ ret = -EINVAL;
+out_err:
+ return ret;
+}
+
+/**
+ * v9fs_file_flock_dotl - lock a file
+ * @filp: file to be locked
+ * @cmd: lock command
+ * @fl: file lock structure
+ *
+ */
+
+static int v9fs_file_flock_dotl(struct file *filp, int cmd,
+ struct file_lock *fl)
+{
+ struct inode *inode = filp->f_path.dentry->d_inode;
+ int ret = -ENOLCK;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
+ cmd, fl, filp->f_path.dentry->d_name.name);
+
+ /* No mandatory locks */
+ if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
+ goto out_err;
+
+ if (!(fl->fl_flags & FL_FLOCK))
+ goto out_err;
+
+ if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
+ filemap_write_and_wait(inode->i_mapping);
+ invalidate_mapping_pages(&inode->i_data, 0, -1);
+ }
+ /* Convert flock to posix lock */
+ fl->fl_owner = (fl_owner_t)filp;
+ fl->fl_start = 0;
+ fl->fl_end = OFFSET_MAX;
+ fl->fl_flags |= FL_POSIX;
+ fl->fl_flags ^= FL_FLOCK;
+
+ if (IS_SETLK(cmd) | IS_SETLKW(cmd))
+ ret = v9fs_file_do_lock(filp, cmd, fl);
+ else
+ ret = -EINVAL;
+out_err:
+ return ret;
+}
+
/**
* v9fs_file_readn - read from a file
* @filp: file pointer to read
@@ -219,7 +423,9 @@ static ssize_t
v9fs_file_write(struct file *filp, const char __user * data,
size_t count, loff_t * offset)
{
- int n, rsize, total = 0;
+ ssize_t retval;
+ size_t total = 0;
+ int n;
struct p9_fid *fid;
struct p9_client *clnt;
struct inode *inode = filp->f_path.dentry->d_inode;
@@ -232,14 +438,19 @@ v9fs_file_write(struct file *filp, const char __user * data,
fid = filp->private_data;
clnt = fid->clnt;
- rsize = fid->iounit ? fid->iounit : clnt->msize - P9_IOHDRSZ;
+ retval = generic_write_checks(filp, &origin, &count, 0);
+ if (retval)
+ goto out;
- do {
- if (count < rsize)
- rsize = count;
+ retval = -EINVAL;
+ if ((ssize_t) count < 0)
+ goto out;
+ retval = 0;
+ if (!count)
+ goto out;
- n = p9_client_write(fid, NULL, data+total, origin+total,
- rsize);
+ do {
+ n = p9_client_write(fid, NULL, data+total, origin+total, count);
if (n <= 0)
break;
count -= n;
@@ -258,9 +469,11 @@ v9fs_file_write(struct file *filp, const char __user * data,
}
if (n < 0)
- return n;
-
- return total;
+ retval = n;
+ else
+ retval = total;
+out:
+ return retval;
}
static int v9fs_file_fsync(struct file *filp, int datasync)
@@ -278,6 +491,20 @@ static int v9fs_file_fsync(struct file *filp, int datasync)
return retval;
}
+int v9fs_file_fsync_dotl(struct file *filp, int datasync)
+{
+ struct p9_fid *fid;
+ int retval;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n",
+ filp, datasync);
+
+ fid = filp->private_data;
+
+ retval = p9_client_fsync(fid, datasync);
+ return retval;
+}
+
static const struct file_operations v9fs_cached_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
@@ -290,6 +517,19 @@ static const struct file_operations v9fs_cached_file_operations = {
.fsync = v9fs_file_fsync,
};
+static const struct file_operations v9fs_cached_file_operations_dotl = {
+ .llseek = generic_file_llseek,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .write = v9fs_file_write,
+ .open = v9fs_file_open,
+ .release = v9fs_dir_release,
+ .lock = v9fs_file_lock_dotl,
+ .flock = v9fs_file_flock_dotl,
+ .mmap = generic_file_readonly_mmap,
+ .fsync = v9fs_file_fsync_dotl,
+};
+
const struct file_operations v9fs_file_operations = {
.llseek = generic_file_llseek,
.read = v9fs_file_read,
@@ -307,7 +547,8 @@ const struct file_operations v9fs_file_operations_dotl = {
.write = v9fs_file_write,
.open = v9fs_file_open,
.release = v9fs_dir_release,
- .lock = v9fs_file_lock,
+ .lock = v9fs_file_lock_dotl,
+ .flock = v9fs_file_flock_dotl,
.mmap = generic_file_readonly_mmap,
- .fsync = v9fs_file_fsync,
+ .fsync = v9fs_file_fsync_dotl,
};
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 9e670d527646..34bf71b56542 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -36,6 +36,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/xattr.h>
+#include <linux/posix_acl.h>
#include <net/9p/9p.h>
#include <net/9p/client.h>
@@ -44,6 +45,7 @@
#include "fid.h"
#include "cache.h"
#include "xattr.h"
+#include "acl.h"
static const struct inode_operations v9fs_dir_inode_operations;
static const struct inode_operations v9fs_dir_inode_operations_dotu;
@@ -53,6 +55,10 @@ static const struct inode_operations v9fs_file_inode_operations_dotl;
static const struct inode_operations v9fs_symlink_inode_operations;
static const struct inode_operations v9fs_symlink_inode_operations_dotl;
+static int
+v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
+ dev_t rdev);
+
/**
* unixmode2p9mode - convert unix mode bits to plan 9
* @v9ses: v9fs session information
@@ -500,6 +506,11 @@ v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
v9fs_vcookie_set_qid(ret, &st->qid);
v9fs_cache_inode_get_cookie(ret);
#endif
+ err = v9fs_get_acl(ret, fid);
+ if (err) {
+ iput(ret);
+ goto error;
+ }
kfree(st);
return ret;
error:
@@ -553,13 +564,6 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
return retval;
}
-static int
-v9fs_open_created(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-
/**
* v9fs_create - Create a file
* @v9ses: session information
@@ -655,29 +659,37 @@ error:
*/
static int
-v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode,
+v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
struct nameidata *nd)
{
int err = 0;
char *name = NULL;
gid_t gid;
int flags;
+ mode_t mode;
struct v9fs_session_info *v9ses;
struct p9_fid *fid = NULL;
struct p9_fid *dfid, *ofid;
struct file *filp;
struct p9_qid qid;
struct inode *inode;
+ struct posix_acl *pacl = NULL, *dacl = NULL;
v9ses = v9fs_inode2v9ses(dir);
if (nd && nd->flags & LOOKUP_OPEN)
flags = nd->intent.open.flags - 1;
- else
- flags = O_RDWR;
+ else {
+ /*
+ * create call without LOOKUP_OPEN is due
+ * to mknod of regular files. So use mknod
+ * operation.
+ */
+ return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
+ }
name = (char *) dentry->d_name.name;
P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x "
- "mode:0x%x\n", name, flags, mode);
+ "mode:0x%x\n", name, flags, omode);
dfid = v9fs_fid_lookup(dentry->d_parent);
if (IS_ERR(dfid)) {
@@ -695,6 +707,15 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode,
}
gid = v9fs_get_fsgid_for_create(dir);
+
+ mode = omode;
+ /* Update mode based on ACL value */
+ err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
+ if (err) {
+ P9_DPRINTK(P9_DEBUG_VFS,
+ "Failed to get acl values in creat %d\n", err);
+ goto error;
+ }
err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid);
if (err < 0) {
P9_DPRINTK(P9_DEBUG_VFS,
@@ -702,46 +723,52 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode,
err);
goto error;
}
+ /* instantiate inode and assign the unopened fid to the dentry */
+ if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE ||
+ (nd && nd->flags & LOOKUP_OPEN)) {
+ fid = p9_client_walk(dfid, 1, &name, 1);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
+ err);
+ fid = NULL;
+ goto error;
+ }
- /* No need to populate the inode if we are not opening the file AND
- * not in cached mode.
- */
- if (!v9ses->cache && !(nd && nd->flags & LOOKUP_OPEN)) {
- /* Not in cached mode. No need to populate inode with stat */
- dentry->d_op = &v9fs_dentry_operations;
- p9_client_clunk(ofid);
- d_instantiate(dentry, NULL);
- return 0;
- }
-
- /* Now walk from the parent so we can get an unopened fid. */
- fid = p9_client_walk(dfid, 1, &name, 1);
- if (IS_ERR(fid)) {
- err = PTR_ERR(fid);
- P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
- fid = NULL;
- goto error;
- }
-
- /* instantiate inode and assign the unopened fid to dentry */
- inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
- if (IS_ERR(inode)) {
- err = PTR_ERR(inode);
- P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
- goto error;
- }
- if (v9ses->cache)
+ inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
+ err);
+ goto error;
+ }
dentry->d_op = &v9fs_cached_dentry_operations;
- else
+ d_instantiate(dentry, inode);
+ err = v9fs_fid_add(dentry, fid);
+ if (err < 0)
+ goto error;
+ /* The fid would get clunked via a dput */
+ fid = NULL;
+ } else {
+ /*
+ * Not in cached mode. No need to populate
+ * 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);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ goto error;
+ }
dentry->d_op = &v9fs_dentry_operations;
- 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);
/* if we are opening a file, assign the open fid to the file */
if (nd && nd->flags & LOOKUP_OPEN) {
- filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created);
+ filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
if (IS_ERR(filp)) {
p9_client_clunk(ofid);
return PTR_ERR(filp);
@@ -800,7 +827,7 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
/* if we are opening a file, assign the open fid to the file */
if (nd && nd->flags & LOOKUP_OPEN) {
- filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created);
+ filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
if (IS_ERR(filp)) {
err = PTR_ERR(filp);
goto error;
@@ -859,23 +886,28 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
*
*/
-static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry,
- int mode)
+static int v9fs_vfs_mkdir_dotl(struct inode *dir,
+ struct dentry *dentry, int omode)
{
int err;
struct v9fs_session_info *v9ses;
struct p9_fid *fid = NULL, *dfid = NULL;
gid_t gid;
char *name;
+ mode_t mode;
struct inode *inode;
struct p9_qid qid;
struct dentry *dir_dentry;
+ struct posix_acl *dacl = NULL, *pacl = NULL;
P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
err = 0;
v9ses = v9fs_inode2v9ses(dir);
- mode |= S_IFDIR;
+ omode |= S_IFDIR;
+ if (dir->i_mode & S_ISGID)
+ omode |= S_ISGID;
+
dir_dentry = v9fs_dentry_from_dir_inode(dir);
dfid = v9fs_fid_lookup(dir_dentry);
if (IS_ERR(dfid)) {
@@ -886,11 +918,14 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry,
}
gid = v9fs_get_fsgid_for_create(dir);
- if (gid < 0) {
- P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n");
+ mode = omode;
+ /* Update mode based on ACL value */
+ err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
+ if (err) {
+ P9_DPRINTK(P9_DEBUG_VFS,
+ "Failed to get acl values in mkdir %d\n", err);
goto error;
}
-
name = (char *) dentry->d_name.name;
err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid);
if (err < 0)
@@ -920,7 +955,23 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry,
if (err < 0)
goto error;
fid = NULL;
+ } else {
+ /*
+ * Not in cached mode. No need to populate
+ * 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);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ goto error;
+ }
+ dentry->d_op = &v9fs_dentry_operations;
+ d_instantiate(dentry, inode);
}
+ /* Now set the ACL based on the default value */
+ v9fs_set_create_acl(dentry, dacl, pacl);
+
error:
if (fid)
p9_client_clunk(fid);
@@ -979,7 +1030,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
result = v9fs_fid_add(dentry, fid);
if (result < 0)
- goto error;
+ goto error_iput;
inst_out:
if (v9ses->cache)
@@ -990,6 +1041,8 @@ inst_out:
d_add(dentry, inode);
return NULL;
+error_iput:
+ iput(inode);
error:
p9_client_clunk(fid);
@@ -1237,7 +1290,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
*
*/
-static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
+int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
{
int retval;
struct v9fs_session_info *v9ses;
@@ -1279,6 +1332,12 @@ static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
setattr_copy(dentry->d_inode, iattr);
mark_inode_dirty(dentry->d_inode);
+ if (iattr->ia_valid & ATTR_MODE) {
+ /* We also want to update ACL when we update mode bits */
+ retval = v9fs_acl_chmod(dentry);
+ if (retval < 0)
+ return retval;
+ }
return 0;
}
@@ -1473,7 +1532,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
if (IS_ERR(fid))
return PTR_ERR(fid);
- if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses))
+ if (!v9fs_proto_dotu(v9ses))
return -EBADF;
st = p9_client_stat(fid);
@@ -1616,11 +1675,6 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
gid = v9fs_get_fsgid_for_create(dir);
- if (gid < 0) {
- P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_egid failed %d\n", gid);
- goto error;
- }
-
/* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */
err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid);
@@ -1789,9 +1843,10 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
kfree(st);
} else {
/* Caching disabled. No need to get upto date stat info.
- * This dentry will be released immediately. So, just i_count++
+ * This dentry will be released immediately. So, just hold the
+ * inode
*/
- atomic_inc(&old_dentry->d_inode->i_count);
+ ihold(old_dentry->d_inode);
}
dentry->d_op = old_dentry->d_op;
@@ -1854,21 +1909,23 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
*
*/
static int
-v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode,
+v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
dev_t rdev)
{
int err;
char *name;
+ mode_t mode;
struct v9fs_session_info *v9ses;
struct p9_fid *fid = NULL, *dfid = NULL;
struct inode *inode;
gid_t gid;
struct p9_qid qid;
struct dentry *dir_dentry;
+ struct posix_acl *dacl = NULL, *pacl = NULL;
P9_DPRINTK(P9_DEBUG_VFS,
" %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
- dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
+ dentry->d_name.name, omode, MAJOR(rdev), MINOR(rdev));
if (!new_valid_dev(rdev))
return -EINVAL;
@@ -1884,11 +1941,14 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode,
}
gid = v9fs_get_fsgid_for_create(dir);
- if (gid < 0) {
- P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n");
+ mode = omode;
+ /* Update mode based on ACL value */
+ err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
+ if (err) {
+ P9_DPRINTK(P9_DEBUG_VFS,
+ "Failed to get acl values in mknod %d\n", err);
goto error;
}
-
name = (char *) dentry->d_name.name;
err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid);
@@ -1932,13 +1992,68 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode,
dentry->d_op = &v9fs_dentry_operations;
d_instantiate(dentry, inode);
}
-
+ /* Now set the ACL based on the default value */
+ v9fs_set_create_acl(dentry, dacl, pacl);
error:
if (fid)
p9_client_clunk(fid);
return err;
}
+static int
+v9fs_vfs_readlink_dotl(struct dentry *dentry, char *buffer, int buflen)
+{
+ int retval;
+ struct p9_fid *fid;
+ char *target = NULL;
+
+ P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
+ retval = -EPERM;
+ fid = v9fs_fid_lookup(dentry);
+ if (IS_ERR(fid))
+ return PTR_ERR(fid);
+
+ retval = p9_client_readlink(fid, &target);
+ if (retval < 0)
+ return retval;
+
+ strncpy(buffer, target, buflen);
+ P9_DPRINTK(P9_DEBUG_VFS, "%s -> %s\n", dentry->d_name.name, buffer);
+
+ retval = strnlen(buffer, buflen);
+ return retval;
+}
+
+/**
+ * v9fs_vfs_follow_link_dotl - follow a symlink path
+ * @dentry: dentry for symlink
+ * @nd: nameidata
+ *
+ */
+
+static void *
+v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd)
+{
+ int len = 0;
+ char *link = __getname();
+
+ P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name);
+
+ if (!link)
+ link = ERR_PTR(-ENOMEM);
+ else {
+ len = v9fs_vfs_readlink_dotl(dentry, link, PATH_MAX);
+ if (len < 0) {
+ __putname(link);
+ link = ERR_PTR(len);
+ } else
+ link[min(len, PATH_MAX-1)] = 0;
+ }
+ nd_set_link(nd, link);
+
+ return NULL;
+}
+
static const struct inode_operations v9fs_dir_inode_operations_dotu = {
.create = v9fs_vfs_create,
.lookup = v9fs_vfs_lookup,
@@ -1969,7 +2084,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotl = {
.getxattr = generic_getxattr,
.removexattr = generic_removexattr,
.listxattr = v9fs_listxattr,
-
+ .check_acl = v9fs_check_acl,
};
static const struct inode_operations v9fs_dir_inode_operations = {
@@ -1996,6 +2111,7 @@ static const struct inode_operations v9fs_file_inode_operations_dotl = {
.getxattr = generic_getxattr,
.removexattr = generic_removexattr,
.listxattr = v9fs_listxattr,
+ .check_acl = v9fs_check_acl,
};
static const struct inode_operations v9fs_symlink_inode_operations = {
@@ -2007,8 +2123,8 @@ static const struct inode_operations v9fs_symlink_inode_operations = {
};
static const struct inode_operations v9fs_symlink_inode_operations_dotl = {
- .readlink = generic_readlink,
- .follow_link = v9fs_vfs_follow_link,
+ .readlink = v9fs_vfs_readlink_dotl,
+ .follow_link = v9fs_vfs_follow_link_dotl,
.put_link = v9fs_vfs_put_link,
.getattr = v9fs_vfs_getattr_dotl,
.setattr = v9fs_vfs_setattr_dotl,
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 1d12ba0ed3db..48d4215c60a8 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -39,6 +39,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/statfs.h>
+#include <linux/magic.h>
#include <net/9p/9p.h>
#include <net/9p/client.h>
@@ -46,6 +47,7 @@
#include "v9fs_vfs.h"
#include "fid.h"
#include "xattr.h"
+#include "acl.h"
static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
@@ -88,6 +90,11 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC |
MS_NOATIME;
+#ifdef CONFIG_9P_FS_POSIX_ACL
+ if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)
+ sb->s_flags |= MS_POSIXACL;
+#endif
+
save_mount_options(sb, data);
}
@@ -149,7 +156,6 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
goto release_sb;
}
sb->s_root = root;
-
if (v9fs_proto_dotl(v9ses)) {
struct p9_stat_dotl *st = NULL;
st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
@@ -174,7 +180,9 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
p9stat_free(st);
kfree(st);
}
-
+ retval = v9fs_get_acl(inode, fid);
+ if (retval)
+ goto release_sb;
v9fs_fid_add(root, fid);
P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
@@ -249,7 +257,7 @@ static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf)
if (v9fs_proto_dotl(v9ses)) {
res = p9_client_statfs(fid, &rs);
if (res == 0) {
- buf->f_type = rs.type;
+ buf->f_type = V9FS_MAGIC;
buf->f_bsize = rs.bsize;
buf->f_blocks = rs.blocks;
buf->f_bfree = rs.bfree;
diff --git a/fs/9p/xattr.c b/fs/9p/xattr.c
index f88e5c2dc873..43ec7df84336 100644
--- a/fs/9p/xattr.c
+++ b/fs/9p/xattr.c
@@ -21,30 +21,13 @@
#include "fid.h"
#include "xattr.h"
-/*
- * v9fs_xattr_get()
- *
- * Copy an extended attribute into the buffer
- * provided, or compute the buffer size required.
- * Buffer is NULL to compute the size of the buffer required.
- *
- * Returns a negative error number on failure, or the number of bytes
- * used / required on success.
- */
-ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name,
- void *buffer, size_t buffer_size)
+ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name,
+ void *buffer, size_t buffer_size)
{
ssize_t retval;
int msize, read_count;
u64 offset = 0, attr_size;
- struct p9_fid *fid, *attr_fid;
-
- P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu\n",
- __func__, name, buffer_size);
-
- fid = v9fs_fid_lookup(dentry);
- if (IS_ERR(fid))
- return PTR_ERR(fid);
+ struct p9_fid *attr_fid;
attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
if (IS_ERR(attr_fid)) {
@@ -88,6 +71,31 @@ error:
}
+
+/*
+ * v9fs_xattr_get()
+ *
+ * Copy an extended attribute into the buffer
+ * provided, or compute the buffer size required.
+ * Buffer is NULL to compute the size of the buffer required.
+ *
+ * Returns a negative error number on failure, or the number of bytes
+ * used / required on success.
+ */
+ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name,
+ void *buffer, size_t buffer_size)
+{
+ struct p9_fid *fid;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu\n",
+ __func__, name, buffer_size);
+ fid = v9fs_fid_lookup(dentry);
+ if (IS_ERR(fid))
+ return PTR_ERR(fid);
+
+ return v9fs_fid_xattr_get(fid, name, buffer, buffer_size);
+}
+
/*
* v9fs_xattr_set()
*
@@ -156,5 +164,9 @@ ssize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
const struct xattr_handler *v9fs_xattr_handlers[] = {
&v9fs_xattr_user_handler,
+#ifdef CONFIG_9P_FS_POSIX_ACL
+ &v9fs_xattr_acl_access_handler,
+ &v9fs_xattr_acl_default_handler,
+#endif
NULL
};
diff --git a/fs/9p/xattr.h b/fs/9p/xattr.h
index 9ddf672ae5c4..eaa837c53bd5 100644
--- a/fs/9p/xattr.h
+++ b/fs/9p/xattr.h
@@ -15,10 +15,16 @@
#define FS_9P_XATTR_H
#include <linux/xattr.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
extern const struct xattr_handler *v9fs_xattr_handlers[];
extern struct xattr_handler v9fs_xattr_user_handler;
+extern const struct xattr_handler v9fs_xattr_acl_access_handler;
+extern const struct xattr_handler v9fs_xattr_acl_default_handler;
+extern ssize_t v9fs_fid_xattr_get(struct p9_fid *, const char *,
+ void *, size_t);
extern ssize_t v9fs_xattr_get(struct dentry *, const char *,
void *, size_t);
extern int v9fs_xattr_set(struct dentry *, const char *,
diff --git a/fs/Kconfig b/fs/Kconfig
index 65781de44fc0..97673c955484 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -47,10 +47,12 @@ source "fs/nilfs2/Kconfig"
endif # BLOCK
+config EXPORTFS
+ tristate
+
config FILE_LOCKING
bool "Enable POSIX file locking API" if EMBEDDED
default y
- select BKL # while lockd still uses it.
help
This option enables standard file locking support, required
for filesystems like NFS and for the flock() system
@@ -222,9 +224,6 @@ config LOCKD_V4
depends on FILE_LOCKING
default y
-config EXPORTFS
- tristate
-
config NFS_ACL_SUPPORT
tristate
select FS_POSIX_ACL
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index bb4cc5b8abc8..79e2ca7973b7 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -42,7 +42,7 @@ config BINFMT_ELF_FDPIC
config CORE_DUMP_DEFAULT_ELF_HEADERS
bool "Write ELF core dumps with partial segments"
- default n
+ default y
depends on BINFMT_ELF && ELF_CORE
help
ELF core dump files describe each memory mapping of the crashed
@@ -60,7 +60,7 @@ config CORE_DUMP_DEFAULT_ELF_HEADERS
inherited. See Documentation/filesystems/proc.txt for details.
This config option changes the default setting of coredump_filter
- seen at boot time. If unsure, say N.
+ seen at boot time. If unsure, say Y.
config BINFMT_FLAT
bool "Kernel support for flat binaries"
diff --git a/fs/Makefile b/fs/Makefile
index e6ec1d309b1d..26956fcec917 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -29,10 +29,7 @@ obj-$(CONFIG_EVENTFD) += eventfd.o
obj-$(CONFIG_AIO) += aio.o
obj-$(CONFIG_FILE_LOCKING) += locks.o
obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o
-
-nfsd-$(CONFIG_NFSD) := nfsctl.o
-obj-y += $(nfsd-y) $(nfsd-m)
-
+obj-$(CONFIG_NFSD_DEPRECATED) += nfsctl.o
obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o
obj-$(CONFIG_BINFMT_EM86) += binfmt_em86.o
obj-$(CONFIG_BINFMT_MISC) += binfmt_misc.o
diff --git a/fs/affs/file.c b/fs/affs/file.c
index c4a9875bd1a6..0a90dcd46de2 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -894,9 +894,9 @@ affs_truncate(struct inode *inode)
if (AFFS_SB(sb)->s_flags & SF_OFS) {
struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0);
u32 tmp;
- if (IS_ERR(ext_bh)) {
+ if (IS_ERR(bh)) {
affs_warning(sb, "truncate", "unexpected read error for last block %u (%d)",
- ext, PTR_ERR(ext_bh));
+ ext, PTR_ERR(bh));
return;
}
tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next);
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 3a0fdec175ba..5d828903ac69 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -388,7 +388,7 @@ affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s3
affs_adjust_checksum(inode_bh, block - be32_to_cpu(chain));
mark_buffer_dirty_inode(inode_bh, inode);
inode->i_nlink = 2;
- atomic_inc(&inode->i_count);
+ ihold(inode);
}
affs_fix_checksum(sb, bh);
mark_buffer_dirty_inode(bh, inode);
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 0d38c09bd55e..5439e1bc9a86 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -1045,7 +1045,7 @@ static int afs_link(struct dentry *from, struct inode *dir,
if (ret < 0)
goto link_error;
- atomic_inc(&vnode->vfs_inode.i_count);
+ ihold(&vnode->vfs_inode);
d_instantiate(dentry, &vnode->vfs_inode);
key_put(key);
_leave(" = 0");
diff --git a/fs/afs/write.c b/fs/afs/write.c
index 722743b152d8..15690bb1d3b5 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -438,7 +438,6 @@ no_more:
*/
int afs_writepage(struct page *page, struct writeback_control *wbc)
{
- struct backing_dev_info *bdi = page->mapping->backing_dev_info;
struct afs_writeback *wb;
int ret;
@@ -455,8 +454,6 @@ int afs_writepage(struct page *page, struct writeback_control *wbc)
}
wbc->nr_to_write -= ret;
- if (wbc->nonblocking && bdi_write_congested(bdi))
- wbc->encountered_congestion = 1;
_leave(" = 0");
return 0;
@@ -469,7 +466,6 @@ static int afs_writepages_region(struct address_space *mapping,
struct writeback_control *wbc,
pgoff_t index, pgoff_t end, pgoff_t *_next)
{
- struct backing_dev_info *bdi = mapping->backing_dev_info;
struct afs_writeback *wb;
struct page *page;
int ret, n;
@@ -529,11 +525,6 @@ static int afs_writepages_region(struct address_space *mapping,
wbc->nr_to_write -= ret;
- if (wbc->nonblocking && bdi_write_congested(bdi)) {
- wbc->encountered_congestion = 1;
- break;
- }
-
cond_resched();
} while (index < end && wbc->nr_to_write > 0);
@@ -548,24 +539,16 @@ static int afs_writepages_region(struct address_space *mapping,
int afs_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{
- struct backing_dev_info *bdi = mapping->backing_dev_info;
pgoff_t start, end, next;
int ret;
_enter("");
- if (wbc->nonblocking && bdi_write_congested(bdi)) {
- wbc->encountered_congestion = 1;
- _leave(" = 0 [congest]");
- return 0;
- }
-
if (wbc->range_cyclic) {
start = mapping->writeback_index;
end = -1;
ret = afs_writepages_region(mapping, wbc, start, end, &next);
- if (start > 0 && wbc->nr_to_write > 0 && ret == 0 &&
- !(wbc->nonblocking && wbc->encountered_congestion))
+ if (start > 0 && wbc->nr_to_write > 0 && ret == 0)
ret = afs_writepages_region(mapping, wbc, 0, start,
&next);
mapping->writeback_index = next;
diff --git a/fs/aio.c b/fs/aio.c
index 250b0a73c8a8..8c8f6c5b6d79 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1543,7 +1543,19 @@ static void aio_batch_add(struct address_space *mapping,
}
abe = mempool_alloc(abe_pool, GFP_KERNEL);
- BUG_ON(!igrab(mapping->host));
+
+ /*
+ * we should be using igrab here, but
+ * we don't want to hammer on the global
+ * inode spinlock just to take an extra
+ * reference on a file that we must already
+ * have a reference to.
+ *
+ * When we're called, we always have a reference
+ * on the file, so we must always have a reference
+ * on the inode, so ihold() is safe here.
+ */
+ ihold(mapping->host);
abe->mapping = mapping;
hlist_add_head(&abe->list, &batch_hash[bucket]);
return;
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index e4b75d6eda83..5365527ca43f 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -111,10 +111,9 @@ struct file *anon_inode_getfile(const char *name,
path.mnt = mntget(anon_inode_mnt);
/*
* We know the anon_inode inode count is always greater than zero,
- * so we can avoid doing an igrab() and we can use an open-coded
- * atomic_inc().
+ * so ihold() is safe.
*/
- atomic_inc(&anon_inode_inode->i_count);
+ ihold(anon_inode_inode);
path.dentry->d_op = &anon_inodefs_dentry_operations;
d_instantiate(path.dentry, anon_inode_inode);
@@ -194,6 +193,7 @@ static struct inode *anon_inode_mkinode(void)
if (!inode)
return ERR_PTR(-ENOMEM);
+ inode->i_ino = get_next_ino();
inode->i_fop = &anon_inode_fops;
inode->i_mapping->a_ops = &anon_aops;
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 821b2b955dac..ac87e49fa706 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -398,6 +398,7 @@ struct inode *autofs4_get_inode(struct super_block *sb,
inode->i_gid = sb->s_root->d_inode->i_gid;
}
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_ino = get_next_ino();
if (S_ISDIR(inf->mode)) {
inode->i_nlink = 2;
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index d967e052b779..685ecff3ab31 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -176,7 +176,7 @@ static int bfs_link(struct dentry *old, struct inode *dir,
inc_nlink(inode);
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
- atomic_inc(&inode->i_count);
+ ihold(inode);
d_instantiate(new, inode);
mutex_unlock(&info->bfs_lock);
return 0;
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 139fc8083f53..29990f0eee0c 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -495,6 +495,7 @@ static struct inode *bm_get_inode(struct super_block *sb, int mode)
struct inode * inode = new_inode(sb);
if (inode) {
+ inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_atime = inode->i_mtime = inode->i_ctime =
current_fs_time(inode->i_sb);
diff --git a/fs/block_dev.c b/fs/block_dev.c
index b737451e2e9d..dea3b628a6ce 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -48,6 +48,21 @@ inline struct block_device *I_BDEV(struct inode *inode)
EXPORT_SYMBOL(I_BDEV);
+/*
+ * move the inode from it's current bdi to the a new bdi. if the inode is dirty
+ * we need to move it onto the dirty list of @dst so that the inode is always
+ * on the right list.
+ */
+static void bdev_inode_switch_bdi(struct inode *inode,
+ struct backing_dev_info *dst)
+{
+ spin_lock(&inode_lock);
+ inode->i_data.backing_dev_info = dst;
+ if (inode->i_state & I_DIRTY)
+ list_move(&inode->i_wb_list, &dst->wb.b_dirty);
+ spin_unlock(&inode_lock);
+}
+
static sector_t max_block(struct block_device *bdev)
{
sector_t retval = ~((sector_t)0);
@@ -550,7 +565,7 @@ EXPORT_SYMBOL(bdget);
*/
struct block_device *bdgrab(struct block_device *bdev)
{
- atomic_inc(&bdev->bd_inode->i_count);
+ ihold(bdev->bd_inode);
return bdev;
}
@@ -580,7 +595,7 @@ static struct block_device *bd_acquire(struct inode *inode)
spin_lock(&bdev_lock);
bdev = inode->i_bdev;
if (bdev) {
- atomic_inc(&bdev->bd_inode->i_count);
+ ihold(bdev->bd_inode);
spin_unlock(&bdev_lock);
return bdev;
}
@@ -591,12 +606,12 @@ static struct block_device *bd_acquire(struct inode *inode)
spin_lock(&bdev_lock);
if (!inode->i_bdev) {
/*
- * We take an additional bd_inode->i_count for inode,
+ * We take an additional reference to bd_inode,
* and it's released in clear_inode() of inode.
* So, we can access it via ->i_mapping always
* without igrab().
*/
- atomic_inc(&bdev->bd_inode->i_count);
+ ihold(bdev->bd_inode);
inode->i_bdev = bdev;
inode->i_mapping = bdev->bd_inode->i_mapping;
list_add(&inode->i_devices, &bdev->bd_inodes);
@@ -1390,7 +1405,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
bdi = blk_get_backing_dev_info(bdev);
if (bdi == NULL)
bdi = &default_backing_dev_info;
- bdev->bd_inode->i_data.backing_dev_info = bdi;
+ bdev_inode_switch_bdi(bdev->bd_inode, bdi);
}
if (bdev->bd_invalidated)
rescan_partitions(disk, bdev);
@@ -1405,8 +1420,8 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
if (ret)
goto out_clear;
bdev->bd_contains = whole;
- bdev->bd_inode->i_data.backing_dev_info =
- whole->bd_inode->i_data.backing_dev_info;
+ bdev_inode_switch_bdi(bdev->bd_inode,
+ whole->bd_inode->i_data.backing_dev_info);
bdev->bd_part = disk_get_part(disk, partno);
if (!(disk->flags & GENHD_FL_UP) ||
!bdev->bd_part || !bdev->bd_part->nr_sects) {
@@ -1439,7 +1454,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
disk_put_part(bdev->bd_part);
bdev->bd_disk = NULL;
bdev->bd_part = NULL;
- bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
+ bdev_inode_switch_bdi(bdev->bd_inode, &default_backing_dev_info);
if (bdev != bdev->bd_contains)
__blkdev_put(bdev->bd_contains, mode, 1);
bdev->bd_contains = NULL;
@@ -1533,7 +1548,8 @@ 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->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
+ 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/inode.c b/fs/btrfs/inode.c
index c03864406af3..64f99cf69ce0 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3849,7 +3849,7 @@ again:
p = &root->inode_tree.rb_node;
parent = NULL;
- if (hlist_unhashed(&inode->i_hash))
+ if (inode_unhashed(inode))
return;
spin_lock(&root->inode_lock);
@@ -4758,7 +4758,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
}
btrfs_set_trans_block_group(trans, dir);
- atomic_inc(&inode->i_count);
+ ihold(inode);
err = btrfs_add_nondir(trans, dentry, inode, 1, index);
diff --git a/fs/buffer.c b/fs/buffer.c
index 7f0b9b083f77..5930e382959b 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -905,7 +905,6 @@ try_again:
bh->b_state = 0;
atomic_set(&bh->b_count, 0);
- bh->b_private = NULL;
bh->b_size = size;
/* Link the buffer to its page */
@@ -1706,7 +1705,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page,
* and kswapd activity, but those code paths have their own
* higher-level throttling.
*/
- if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) {
+ if (wbc->sync_mode != WB_SYNC_NONE) {
lock_buffer(bh);
} else if (!trylock_buffer(bh)) {
redirty_page_for_writepage(wbc, page);
@@ -1834,9 +1833,11 @@ void page_zero_new_buffers(struct page *page, unsigned from, unsigned to)
}
EXPORT_SYMBOL(page_zero_new_buffers);
-int block_prepare_write(struct page *page, unsigned from, unsigned to,
+int __block_write_begin(struct page *page, loff_t pos, unsigned len,
get_block_t *get_block)
{
+ unsigned from = pos & (PAGE_CACHE_SIZE - 1);
+ unsigned to = from + len;
struct inode *inode = page->mapping->host;
unsigned block_start, block_end;
sector_t block;
@@ -1916,7 +1917,7 @@ int block_prepare_write(struct page *page, unsigned from, unsigned to,
}
return err;
}
-EXPORT_SYMBOL(block_prepare_write);
+EXPORT_SYMBOL(__block_write_begin);
static int __block_commit_write(struct inode *inode, struct page *page,
unsigned from, unsigned to)
@@ -1953,15 +1954,6 @@ static int __block_commit_write(struct inode *inode, struct page *page,
return 0;
}
-int __block_write_begin(struct page *page, loff_t pos, unsigned len,
- get_block_t *get_block)
-{
- unsigned start = pos & (PAGE_CACHE_SIZE - 1);
-
- return block_prepare_write(page, start, start + len, get_block);
-}
-EXPORT_SYMBOL(__block_write_begin);
-
/*
* block_write_begin takes care of the basic task of block allocation and
* bringing partial write blocks uptodate first.
@@ -2379,7 +2371,7 @@ block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
else
end = PAGE_CACHE_SIZE;
- ret = block_prepare_write(page, 0, end, get_block);
+ ret = __block_write_begin(page, 0, end, get_block);
if (!ret)
ret = block_commit_write(page, 0, end);
@@ -2466,11 +2458,10 @@ int nobh_write_begin(struct address_space *mapping,
*fsdata = NULL;
if (page_has_buffers(page)) {
- unlock_page(page);
- page_cache_release(page);
- *pagep = NULL;
- return block_write_begin(mapping, pos, len, flags, pagep,
- get_block);
+ ret = __block_write_begin(page, pos, len, get_block);
+ if (unlikely(ret))
+ goto out_release;
+ return ret;
}
if (PageMappedToDisk(page))
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 51bcc5ce3230..e9c874abc9e1 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -591,7 +591,6 @@ static int ceph_writepages_start(struct address_space *mapping,
struct writeback_control *wbc)
{
struct inode *inode = mapping->host;
- struct backing_dev_info *bdi = mapping->backing_dev_info;
struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_fs_client *fsc;
pgoff_t index, start, end;
@@ -633,13 +632,6 @@ static int ceph_writepages_start(struct address_space *mapping,
pagevec_init(&pvec, 0);
- /* ?? */
- if (wbc->nonblocking && bdi_write_congested(bdi)) {
- dout(" writepages congested\n");
- wbc->encountered_congestion = 1;
- goto out_final;
- }
-
/* where to start/end? */
if (wbc->range_cyclic) {
start = mapping->writeback_index; /* Start from prev offset */
@@ -885,7 +877,6 @@ out:
rc = 0; /* vfs expects us to return 0 */
ceph_put_snap_context(snapc);
dout("writepages done, rc = %d\n", rc);
-out_final:
return rc;
}
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 8c81e7b14d53..45af003865d2 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1303,7 +1303,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
static int cifs_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{
- struct backing_dev_info *bdi = mapping->backing_dev_info;
unsigned int bytes_to_write;
unsigned int bytes_written;
struct cifs_sb_info *cifs_sb;
@@ -1326,15 +1325,6 @@ static int cifs_writepages(struct address_space *mapping,
int scanned = 0;
int xid, long_op;
- /*
- * BB: Is this meaningful for a non-block-device file system?
- * If it is, we should test it again after we do I/O
- */
- if (wbc->nonblocking && bdi_write_congested(bdi)) {
- wbc->encountered_congestion = 1;
- return 0;
- }
-
cifs_sb = CIFS_SB(mapping->host->i_sb);
/*
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index a5bf5771a22a..9060f08e70cf 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -17,6 +17,7 @@
#include <linux/string.h>
#include <linux/list.h>
#include <linux/sched.h>
+#include <linux/spinlock.h>
#include <linux/coda.h>
#include <linux/coda_linux.h>
@@ -31,19 +32,23 @@ void coda_cache_enter(struct inode *inode, int mask)
{
struct coda_inode_info *cii = ITOC(inode);
+ spin_lock(&cii->c_lock);
cii->c_cached_epoch = atomic_read(&permission_epoch);
if (cii->c_uid != current_fsuid()) {
cii->c_uid = current_fsuid();
cii->c_cached_perm = mask;
} else
cii->c_cached_perm |= mask;
+ spin_unlock(&cii->c_lock);
}
/* remove cached acl from an inode */
void coda_cache_clear_inode(struct inode *inode)
{
struct coda_inode_info *cii = ITOC(inode);
+ spin_lock(&cii->c_lock);
cii->c_cached_epoch = atomic_read(&permission_epoch) - 1;
+ spin_unlock(&cii->c_lock);
}
/* remove all acl caches */
@@ -57,13 +62,15 @@ void coda_cache_clear_all(struct super_block *sb)
int coda_cache_check(struct inode *inode, int mask)
{
struct coda_inode_info *cii = ITOC(inode);
- int hit;
+ int hit;
- hit = (mask & cii->c_cached_perm) == mask &&
- cii->c_uid == current_fsuid() &&
- cii->c_cached_epoch == atomic_read(&permission_epoch);
+ spin_lock(&cii->c_lock);
+ hit = (mask & cii->c_cached_perm) == mask &&
+ cii->c_uid == current_fsuid() &&
+ cii->c_cached_epoch == atomic_read(&permission_epoch);
+ spin_unlock(&cii->c_lock);
- return hit;
+ return hit;
}
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index a7a780929eec..602240569c89 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -45,13 +45,15 @@ static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
static int coda_test_inode(struct inode *inode, void *data)
{
struct CodaFid *fid = (struct CodaFid *)data;
- return coda_fideq(&(ITOC(inode)->c_fid), fid);
+ struct coda_inode_info *cii = ITOC(inode);
+ return coda_fideq(&cii->c_fid, fid);
}
static int coda_set_inode(struct inode *inode, void *data)
{
struct CodaFid *fid = (struct CodaFid *)data;
- ITOC(inode)->c_fid = *fid;
+ struct coda_inode_info *cii = ITOC(inode);
+ cii->c_fid = *fid;
return 0;
}
@@ -71,6 +73,7 @@ struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid,
cii = ITOC(inode);
/* we still need to set i_ino for things like stat(2) */
inode->i_ino = hash;
+ /* inode is locked and unique, no need to grab cii->c_lock */
cii->c_mapcount = 0;
unlock_new_inode(inode);
}
@@ -107,14 +110,20 @@ int coda_cnode_make(struct inode **inode, struct CodaFid *fid, struct super_bloc
}
+/* Although we treat Coda file identifiers as immutable, there is one
+ * special case for files created during a disconnection where they may
+ * not be globally unique. When an identifier collision is detected we
+ * first try to flush the cached inode from the kernel and finally
+ * resort to renaming/rehashing in-place. Userspace remembers both old
+ * and new values of the identifier to handle any in-flight upcalls.
+ * The real solution is to use globally unique UUIDs as identifiers, but
+ * retrofitting the existing userspace code for this is non-trivial. */
void coda_replace_fid(struct inode *inode, struct CodaFid *oldfid,
struct CodaFid *newfid)
{
- struct coda_inode_info *cii;
+ struct coda_inode_info *cii = ITOC(inode);
unsigned long hash = coda_f2i(newfid);
- cii = ITOC(inode);
-
BUG_ON(!coda_fideq(&cii->c_fid, oldfid));
/* replace fid and rehash inode */
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index ccd98b0f2b0b..5d8b35539601 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -17,7 +17,7 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
#include <asm/uaccess.h>
@@ -116,15 +116,11 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struc
goto exit;
}
- lock_kernel();
-
error = venus_lookup(dir->i_sb, coda_i2f(dir), name, length,
&type, &resfid);
if (!error)
error = coda_cnode_make(&inode, &resfid, dir->i_sb);
- unlock_kernel();
-
if (error && error != -ENOENT)
return ERR_PTR(error);
@@ -140,28 +136,24 @@ exit:
int coda_permission(struct inode *inode, int mask)
{
- int error = 0;
+ int error;
mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
if (!mask)
- return 0;
+ return 0;
if ((mask & MAY_EXEC) && !execute_ok(inode))
return -EACCES;
- lock_kernel();
-
if (coda_cache_check(inode, mask))
- goto out;
+ return 0;
- error = venus_access(inode->i_sb, coda_i2f(inode), mask);
+ error = venus_access(inode->i_sb, coda_i2f(inode), mask);
if (!error)
coda_cache_enter(inode, mask);
- out:
- unlock_kernel();
return error;
}
@@ -200,41 +192,34 @@ static inline void coda_dir_drop_nlink(struct inode *dir)
/* creation routines: create, mknod, mkdir, link, symlink */
static int coda_create(struct inode *dir, struct dentry *de, int mode, struct nameidata *nd)
{
- int error=0;
+ int error;
const char *name=de->d_name.name;
int length=de->d_name.len;
struct inode *inode;
struct CodaFid newfid;
struct coda_vattr attrs;
- lock_kernel();
-
- if (coda_isroot(dir) && coda_iscontrol(name, length)) {
- unlock_kernel();
+ if (coda_isroot(dir) && coda_iscontrol(name, length))
return -EPERM;
- }
error = venus_create(dir->i_sb, coda_i2f(dir), name, length,
0, mode, &newfid, &attrs);
-
- if ( error ) {
- unlock_kernel();
- d_drop(de);
- return error;
- }
+ if (error)
+ goto err_out;
inode = coda_iget(dir->i_sb, &newfid, &attrs);
- if ( IS_ERR(inode) ) {
- unlock_kernel();
- d_drop(de);
- return PTR_ERR(inode);
+ if (IS_ERR(inode)) {
+ error = PTR_ERR(inode);
+ goto err_out;
}
/* invalidate the directory cnode's attributes */
coda_dir_update_mtime(dir);
- unlock_kernel();
d_instantiate(de, inode);
return 0;
+err_out:
+ d_drop(de);
+ return error;
}
static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
@@ -246,36 +231,29 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
int error;
struct CodaFid newfid;
- lock_kernel();
-
- if (coda_isroot(dir) && coda_iscontrol(name, len)) {
- unlock_kernel();
+ if (coda_isroot(dir) && coda_iscontrol(name, len))
return -EPERM;
- }
attrs.va_mode = mode;
error = venus_mkdir(dir->i_sb, coda_i2f(dir),
name, len, &newfid, &attrs);
-
- if ( error ) {
- unlock_kernel();
- d_drop(de);
- return error;
- }
+ if (error)
+ goto err_out;
inode = coda_iget(dir->i_sb, &newfid, &attrs);
- if ( IS_ERR(inode) ) {
- unlock_kernel();
- d_drop(de);
- return PTR_ERR(inode);
+ if (IS_ERR(inode)) {
+ error = PTR_ERR(inode);
+ goto err_out;
}
/* invalidate the directory cnode's attributes */
coda_dir_inc_nlink(dir);
coda_dir_update_mtime(dir);
- unlock_kernel();
d_instantiate(de, inode);
return 0;
+err_out:
+ d_drop(de);
+ return error;
}
/* try to make de an entry in dir_inodde linked to source_de */
@@ -287,52 +265,38 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
int len = de->d_name.len;
int error;
- lock_kernel();
-
- if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
- unlock_kernel();
+ if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
return -EPERM;
- }
error = venus_link(dir_inode->i_sb, coda_i2f(inode),
coda_i2f(dir_inode), (const char *)name, len);
-
if (error) {
d_drop(de);
- goto out;
+ return error;
}
coda_dir_update_mtime(dir_inode);
- atomic_inc(&inode->i_count);
+ ihold(inode);
d_instantiate(de, inode);
inc_nlink(inode);
-
-out:
- unlock_kernel();
- return(error);
+ return 0;
}
static int coda_symlink(struct inode *dir_inode, struct dentry *de,
const char *symname)
{
- const char *name = de->d_name.name;
+ const char *name = de->d_name.name;
int len = de->d_name.len;
int symlen;
- int error = 0;
-
- lock_kernel();
+ int error;
- if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
- unlock_kernel();
+ if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
return -EPERM;
- }
symlen = strlen(symname);
- if ( symlen > CODA_MAXPATHLEN ) {
- unlock_kernel();
+ if (symlen > CODA_MAXPATHLEN)
return -ENAMETOOLONG;
- }
/*
* This entry is now negative. Since we do not create
@@ -343,10 +307,9 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
symname, symlen);
/* mtime is no good anymore */
- if ( !error )
+ if (!error)
coda_dir_update_mtime(dir_inode);
- unlock_kernel();
return error;
}
@@ -357,17 +320,12 @@ static int coda_unlink(struct inode *dir, struct dentry *de)
const char *name = de->d_name.name;
int len = de->d_name.len;
- lock_kernel();
-
error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
- if ( error ) {
- unlock_kernel();
+ if (error)
return error;
- }
coda_dir_update_mtime(dir);
drop_nlink(de->d_inode);
- unlock_kernel();
return 0;
}
@@ -377,8 +335,6 @@ static int coda_rmdir(struct inode *dir, struct dentry *de)
int len = de->d_name.len;
int error;
- lock_kernel();
-
error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
if (!error) {
/* VFS may delete the child */
@@ -389,7 +345,6 @@ static int coda_rmdir(struct inode *dir, struct dentry *de)
coda_dir_drop_nlink(dir);
coda_dir_update_mtime(dir);
}
- unlock_kernel();
return error;
}
@@ -403,15 +358,12 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
int new_length = new_dentry->d_name.len;
int error;
- lock_kernel();
-
error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
coda_i2f(new_dir), old_length, new_length,
(const char *) old_name, (const char *)new_name);
-
- if ( !error ) {
- if ( new_dentry->d_inode ) {
- if ( S_ISDIR(new_dentry->d_inode->i_mode) ) {
+ if (!error) {
+ if (new_dentry->d_inode) {
+ if (S_ISDIR(new_dentry->d_inode->i_mode)) {
coda_dir_drop_nlink(old_dir);
coda_dir_inc_nlink(new_dir);
}
@@ -423,8 +375,6 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
coda_flag_inode(new_dir, C_VATTR);
}
}
- unlock_kernel();
-
return error;
}
@@ -594,10 +544,7 @@ static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd)
struct inode *inode = de->d_inode;
struct coda_inode_info *cii;
- if (!inode)
- return 1;
- lock_kernel();
- if (coda_isroot(inode))
+ if (!inode || coda_isroot(inode))
goto out;
if (is_bad_inode(inode))
goto bad;
@@ -617,13 +564,12 @@ static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd)
goto out;
/* clear the flags. */
+ spin_lock(&cii->c_lock);
cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
-
+ spin_unlock(&cii->c_lock);
bad:
- unlock_kernel();
return 0;
out:
- unlock_kernel();
return 1;
}
@@ -656,20 +602,19 @@ static int coda_dentry_delete(struct dentry * dentry)
int coda_revalidate_inode(struct dentry *dentry)
{
struct coda_vattr attr;
- int error = 0;
+ int error;
int old_mode;
ino_t old_ino;
struct inode *inode = dentry->d_inode;
struct coda_inode_info *cii = ITOC(inode);
- lock_kernel();
- if ( !cii->c_flags )
- goto ok;
+ if (!cii->c_flags)
+ return 0;
if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
- if ( error )
- goto return_bad;
+ if (error)
+ return -EIO;
/* this inode may be lost if:
- it's ino changed
@@ -688,17 +633,13 @@ int coda_revalidate_inode(struct dentry *dentry)
/* the following can happen when a local fid is replaced
with a global one, here we lose and declare the inode bad */
if (inode->i_ino != old_ino)
- goto return_bad;
+ return -EIO;
coda_flag_inode_children(inode, C_FLUSH);
+
+ spin_lock(&cii->c_lock);
cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
+ spin_unlock(&cii->c_lock);
}
-
-ok:
- unlock_kernel();
return 0;
-
-return_bad:
- unlock_kernel();
- return -EIO;
}
diff --git a/fs/coda/file.c b/fs/coda/file.c
index ad3cd2abeeb4..c8b50ba4366a 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -15,7 +15,7 @@
#include <linux/stat.h>
#include <linux/cred.h>
#include <linux/errno.h>
-#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
@@ -109,19 +109,24 @@ coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
coda_inode = coda_file->f_path.dentry->d_inode;
host_inode = host_file->f_path.dentry->d_inode;
+
+ cii = ITOC(coda_inode);
+ spin_lock(&cii->c_lock);
coda_file->f_mapping = host_file->f_mapping;
if (coda_inode->i_mapping == &coda_inode->i_data)
coda_inode->i_mapping = host_inode->i_mapping;
/* only allow additional mmaps as long as userspace isn't changing
* the container file on us! */
- else if (coda_inode->i_mapping != host_inode->i_mapping)
+ else if (coda_inode->i_mapping != host_inode->i_mapping) {
+ spin_unlock(&cii->c_lock);
return -EBUSY;
+ }
/* keep track of how often the coda_inode/host_file has been mmapped */
- cii = ITOC(coda_inode);
cii->c_mapcount++;
cfi->cfi_mapcount++;
+ spin_unlock(&cii->c_lock);
return host_file->f_op->mmap(host_file, vma);
}
@@ -138,8 +143,6 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
if (!cfi)
return -ENOMEM;
- lock_kernel();
-
error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
&host_file);
if (!host_file)
@@ -147,7 +150,6 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
if (error) {
kfree(cfi);
- unlock_kernel();
return error;
}
@@ -159,8 +161,6 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
BUG_ON(coda_file->private_data != NULL);
coda_file->private_data = cfi;
-
- unlock_kernel();
return 0;
}
@@ -171,9 +171,7 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
struct coda_file_info *cfi;
struct coda_inode_info *cii;
struct inode *host_inode;
- int err = 0;
-
- lock_kernel();
+ int err;
cfi = CODA_FTOC(coda_file);
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
@@ -185,18 +183,18 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
cii = ITOC(coda_inode);
/* did we mmap this file? */
+ spin_lock(&cii->c_lock);
if (coda_inode->i_mapping == &host_inode->i_data) {
cii->c_mapcount -= cfi->cfi_mapcount;
if (!cii->c_mapcount)
coda_inode->i_mapping = &coda_inode->i_data;
}
+ spin_unlock(&cii->c_lock);
fput(cfi->cfi_container);
kfree(coda_file->private_data);
coda_file->private_data = NULL;
- unlock_kernel();
-
/* VFS fput ignores the return value from file_operations->release, so
* there is no use returning an error here */
return 0;
@@ -207,7 +205,7 @@ int coda_fsync(struct file *coda_file, int datasync)
struct file *host_file;
struct inode *coda_inode = coda_file->f_path.dentry->d_inode;
struct coda_file_info *cfi;
- int err = 0;
+ int err;
if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) ||
S_ISLNK(coda_inode->i_mode)))
@@ -218,11 +216,8 @@ int coda_fsync(struct file *coda_file, int datasync)
host_file = cfi->cfi_container;
err = vfs_fsync(host_file, datasync);
- if ( !err && !datasync ) {
- lock_kernel();
+ if (!err && !datasync)
err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode));
- unlock_kernel();
- }
return err;
}
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index bfe8179b1295..7993b96ca348 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -15,7 +15,8 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/unistd.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
#include <linux/file.h>
#include <linux/vfs.h>
#include <linux/slab.h>
@@ -51,6 +52,7 @@ static struct inode *coda_alloc_inode(struct super_block *sb)
ei->c_flags = 0;
ei->c_uid = 0;
ei->c_cached_perm = 0;
+ spin_lock_init(&ei->c_lock);
return &ei->vfs_inode;
}
@@ -143,13 +145,11 @@ static int get_device_index(struct coda_mount_data *data)
static int coda_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *root = NULL;
- struct venus_comm *vc = NULL;
+ struct venus_comm *vc;
struct CodaFid fid;
int error;
int idx;
- lock_kernel();
-
idx = get_device_index((struct coda_mount_data *) data);
/* Ignore errors in data, for backward compatibility */
@@ -159,23 +159,26 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
printk(KERN_INFO "coda_read_super: device index: %i\n", idx);
vc = &coda_comms[idx];
+ mutex_lock(&vc->vc_mutex);
+
if (!vc->vc_inuse) {
printk("coda_read_super: No pseudo device\n");
- unlock_kernel();
- return -EINVAL;
+ error = -EINVAL;
+ goto unlock_out;
}
- if ( vc->vc_sb ) {
+ if (vc->vc_sb) {
printk("coda_read_super: Device already mounted\n");
- unlock_kernel();
- return -EBUSY;
+ error = -EBUSY;
+ goto unlock_out;
}
error = bdi_setup_and_register(&vc->bdi, "coda", BDI_CAP_MAP_COPY);
if (error)
- goto bdi_err;
+ goto unlock_out;
vc->vc_sb = sb;
+ mutex_unlock(&vc->vc_mutex);
sb->s_fs_info = vc;
sb->s_flags |= MS_NOATIME;
@@ -204,28 +207,33 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
printk("coda_read_super: rootinode is %ld dev %s\n",
root->i_ino, root->i_sb->s_id);
sb->s_root = d_alloc_root(root);
- if (!sb->s_root)
+ if (!sb->s_root) {
+ error = -EINVAL;
goto error;
- unlock_kernel();
+ }
return 0;
- error:
- bdi_destroy(&vc->bdi);
- bdi_err:
+error:
if (root)
iput(root);
- if (vc)
- vc->vc_sb = NULL;
- unlock_kernel();
- return -EINVAL;
+ mutex_lock(&vc->vc_mutex);
+ bdi_destroy(&vc->bdi);
+ vc->vc_sb = NULL;
+ sb->s_fs_info = NULL;
+unlock_out:
+ mutex_unlock(&vc->vc_mutex);
+ return error;
}
static void coda_put_super(struct super_block *sb)
{
- bdi_destroy(&coda_vcp(sb)->bdi);
- coda_vcp(sb)->vc_sb = NULL;
+ struct venus_comm *vcp = coda_vcp(sb);
+ mutex_lock(&vcp->vc_mutex);
+ bdi_destroy(&vcp->bdi);
+ vcp->vc_sb = NULL;
sb->s_fs_info = NULL;
+ mutex_unlock(&vcp->vc_mutex);
printk("Coda: Bye bye.\n");
}
@@ -251,8 +259,6 @@ int coda_setattr(struct dentry *de, struct iattr *iattr)
struct coda_vattr vattr;
int error;
- lock_kernel();
-
memset(&vattr, 0, sizeof(vattr));
inode->i_ctime = CURRENT_TIME_SEC;
@@ -262,13 +268,10 @@ int coda_setattr(struct dentry *de, struct iattr *iattr)
/* Venus is responsible for truncating the container-file!!! */
error = venus_setattr(inode->i_sb, coda_i2f(inode), &vattr);
- if ( !error ) {
+ if (!error) {
coda_vattr_to_iattr(inode, &vattr);
coda_cache_clear_inode(inode);
}
-
- unlock_kernel();
-
return error;
}
@@ -282,12 +285,8 @@ static int coda_statfs(struct dentry *dentry, struct kstatfs *buf)
{
int error;
- lock_kernel();
-
error = venus_statfs(dentry, buf);
- unlock_kernel();
-
if (error) {
/* fake something like AFS does */
buf->f_blocks = 9000000;
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
index 028a9a0f588b..2fd89b5c5c7b 100644
--- a/fs/coda/pioctl.c
+++ b/fs/coda/pioctl.c
@@ -23,8 +23,6 @@
#include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h>
-#include <linux/smp_lock.h>
-
/* pioctl ops */
static int coda_ioctl_permission(struct inode *inode, int mask);
static long coda_pioctl(struct file *filp, unsigned int cmd,
@@ -58,13 +56,9 @@ static long coda_pioctl(struct file *filp, unsigned int cmd,
struct inode *target_inode = NULL;
struct coda_inode_info *cnp;
- lock_kernel();
-
/* get the Pioctl data arguments from user space */
- if (copy_from_user(&data, (void __user *)user_data, sizeof(data))) {
- error = -EINVAL;
- goto out;
- }
+ if (copy_from_user(&data, (void __user *)user_data, sizeof(data)))
+ return -EINVAL;
/*
* Look up the pathname. Note that the pathname is in
@@ -76,13 +70,12 @@ static long coda_pioctl(struct file *filp, unsigned int cmd,
error = user_lpath(data.path, &path);
if (error)
- goto out;
- else
- target_inode = path.dentry->d_inode;
+ return error;
+
+ target_inode = path.dentry->d_inode;
/* return if it is not a Coda inode */
if (target_inode->i_sb != inode->i_sb) {
- path_put(&path);
error = -EINVAL;
goto out;
}
@@ -91,10 +84,7 @@ static long coda_pioctl(struct file *filp, unsigned int cmd,
cnp = ITOC(target_inode);
error = venus_pioctl(inode->i_sb, &(cnp->c_fid), cmd, &data);
-
- path_put(&path);
-
out:
- unlock_kernel();
+ path_put(&path);
return error;
}
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index fdc2f3ef7ecd..62647a8595e4 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -35,7 +35,7 @@
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/list.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -67,8 +67,10 @@ static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
unsigned int mask = POLLOUT | POLLWRNORM;
poll_wait(file, &vcp->vc_waitq, wait);
+ mutex_lock(&vcp->vc_mutex);
if (!list_empty(&vcp->vc_pending))
mask |= POLLIN | POLLRDNORM;
+ mutex_unlock(&vcp->vc_mutex);
return mask;
}
@@ -108,16 +110,9 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
return -EFAULT;
if (DOWNCALL(hdr.opcode)) {
- struct super_block *sb = NULL;
- union outputArgs *dcbuf;
+ union outputArgs *dcbuf;
int size = sizeof(*dcbuf);
- sb = vcp->vc_sb;
- if ( !sb ) {
- count = nbytes;
- goto out;
- }
-
if ( nbytes < sizeof(struct coda_out_hdr) ) {
printk("coda_downcall opc %d uniq %d, not enough!\n",
hdr.opcode, hdr.unique);
@@ -137,9 +132,7 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
}
/* what downcall errors does Venus handle ? */
- lock_kernel();
- error = coda_downcall(hdr.opcode, dcbuf, sb);
- unlock_kernel();
+ error = coda_downcall(vcp, hdr.opcode, dcbuf);
CODA_FREE(dcbuf, nbytes);
if (error) {
@@ -152,7 +145,7 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
}
/* Look for the message on the processing queue. */
- lock_kernel();
+ mutex_lock(&vcp->vc_mutex);
list_for_each(lh, &vcp->vc_processing) {
tmp = list_entry(lh, struct upc_req , uc_chain);
if (tmp->uc_unique == hdr.unique) {
@@ -161,7 +154,7 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
break;
}
}
- unlock_kernel();
+ mutex_unlock(&vcp->vc_mutex);
if (!req) {
printk("psdev_write: msg (%d, %d) not found\n",
@@ -216,7 +209,7 @@ static ssize_t coda_psdev_read(struct file * file, char __user * buf,
if (nbytes == 0)
return 0;
- lock_kernel();
+ mutex_lock(&vcp->vc_mutex);
add_wait_queue(&vcp->vc_waitq, &wait);
set_current_state(TASK_INTERRUPTIBLE);
@@ -230,7 +223,9 @@ static ssize_t coda_psdev_read(struct file * file, char __user * buf,
retval = -ERESTARTSYS;
break;
}
+ mutex_unlock(&vcp->vc_mutex);
schedule();
+ mutex_lock(&vcp->vc_mutex);
}
set_current_state(TASK_RUNNING);
@@ -263,7 +258,7 @@ static ssize_t coda_psdev_read(struct file * file, char __user * buf,
CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
kfree(req);
out:
- unlock_kernel();
+ mutex_unlock(&vcp->vc_mutex);
return (count ? count : retval);
}
@@ -276,10 +271,10 @@ static int coda_psdev_open(struct inode * inode, struct file * file)
if (idx < 0 || idx >= MAX_CODADEVS)
return -ENODEV;
- lock_kernel();
-
err = -EBUSY;
vcp = &coda_comms[idx];
+ mutex_lock(&vcp->vc_mutex);
+
if (!vcp->vc_inuse) {
vcp->vc_inuse++;
@@ -293,7 +288,7 @@ static int coda_psdev_open(struct inode * inode, struct file * file)
err = 0;
}
- unlock_kernel();
+ mutex_unlock(&vcp->vc_mutex);
return err;
}
@@ -308,7 +303,7 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
return -1;
}
- lock_kernel();
+ mutex_lock(&vcp->vc_mutex);
/* Wakeup clients so they can return. */
list_for_each_entry_safe(req, tmp, &vcp->vc_pending, uc_chain) {
@@ -333,7 +328,7 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
file->private_data = NULL;
vcp->vc_inuse--;
- unlock_kernel();
+ mutex_unlock(&vcp->vc_mutex);
return 0;
}
@@ -362,9 +357,11 @@ static int init_coda_psdev(void)
err = PTR_ERR(coda_psdev_class);
goto out_chrdev;
}
- for (i = 0; i < MAX_CODADEVS; i++)
+ for (i = 0; i < MAX_CODADEVS; i++) {
+ mutex_init(&(&coda_comms[i])->vc_mutex);
device_create(coda_psdev_class, NULL,
MKDEV(CODA_PSDEV_MAJOR, i), NULL, "cfs%d", i);
+ }
coda_sysctl_init();
goto out;
diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c
index 4513b7258458..af78f007a2b0 100644
--- a/fs/coda/symlink.c
+++ b/fs/coda/symlink.c
@@ -14,7 +14,6 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
#include <linux/coda.h>
#include <linux/coda_linux.h>
@@ -29,11 +28,9 @@ static int coda_symlink_filler(struct file *file, struct page *page)
unsigned int len = PAGE_SIZE;
char *p = kmap(page);
- lock_kernel();
cii = ITOC(inode);
error = venus_readlink(inode->i_sb, &cii->c_fid, p, &len);
- unlock_kernel();
if (error)
goto fail;
SetPageUptodate(page);
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index b8893ab6f9e6..c3563cab9758 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -27,6 +27,7 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/vfs.h>
@@ -606,7 +607,8 @@ static void coda_unblock_signals(sigset_t *old)
(r)->uc_opcode != CODA_RELEASE) || \
(r)->uc_flags & CODA_REQ_READ))
-static inline void coda_waitfor_upcall(struct upc_req *req)
+static inline void coda_waitfor_upcall(struct venus_comm *vcp,
+ struct upc_req *req)
{
DECLARE_WAITQUEUE(wait, current);
unsigned long timeout = jiffies + coda_timeout * HZ;
@@ -639,10 +641,12 @@ static inline void coda_waitfor_upcall(struct upc_req *req)
break;
}
+ mutex_unlock(&vcp->vc_mutex);
if (blocked)
schedule_timeout(HZ);
else
schedule();
+ mutex_lock(&vcp->vc_mutex);
}
if (blocked)
coda_unblock_signals(&old);
@@ -667,18 +671,23 @@ static int coda_upcall(struct venus_comm *vcp,
{
union outputArgs *out;
union inputArgs *sig_inputArgs;
- struct upc_req *req, *sig_req;
- int error = 0;
+ struct upc_req *req = NULL, *sig_req;
+ int error;
+
+ mutex_lock(&vcp->vc_mutex);
if (!vcp->vc_inuse) {
printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
- return -ENXIO;
+ error = -ENXIO;
+ goto exit;
}
/* Format the request message. */
req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
- if (!req)
- return -ENOMEM;
+ if (!req) {
+ error = -ENOMEM;
+ goto exit;
+ }
req->uc_data = (void *)buffer;
req->uc_flags = 0;
@@ -705,7 +714,7 @@ static int coda_upcall(struct venus_comm *vcp,
* ENODEV. */
/* Go to sleep. Wake up on signals only after the timeout. */
- coda_waitfor_upcall(req);
+ coda_waitfor_upcall(vcp, req);
/* Op went through, interrupt or not... */
if (req->uc_flags & CODA_REQ_WRITE) {
@@ -759,6 +768,7 @@ static int coda_upcall(struct venus_comm *vcp,
exit:
kfree(req);
+ mutex_unlock(&vcp->vc_mutex);
return error;
}
@@ -796,21 +806,24 @@ exit:
*
* CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
-int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
+int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out)
{
struct inode *inode = NULL;
- struct CodaFid *fid, *newfid;
+ struct CodaFid *fid = NULL, *newfid;
+ struct super_block *sb;
/* Handle invalidation requests. */
- if ( !sb || !sb->s_root)
- return 0;
+ mutex_lock(&vcp->vc_mutex);
+ sb = vcp->vc_sb;
+ if (!sb || !sb->s_root)
+ goto unlock_out;
switch (opcode) {
case CODA_FLUSH:
coda_cache_clear_all(sb);
shrink_dcache_sb(sb);
if (sb->s_root->d_inode)
- coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
+ coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
break;
case CODA_PURGEUSER:
@@ -819,45 +832,53 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
case CODA_ZAPDIR:
fid = &out->coda_zapdir.CodaFid;
- inode = coda_fid_to_inode(fid, sb);
- if (inode) {
- coda_flag_inode_children(inode, C_PURGE);
- coda_flag_inode(inode, C_VATTR);
- }
break;
case CODA_ZAPFILE:
fid = &out->coda_zapfile.CodaFid;
- inode = coda_fid_to_inode(fid, sb);
- if (inode)
- coda_flag_inode(inode, C_VATTR);
break;
case CODA_PURGEFID:
fid = &out->coda_purgefid.CodaFid;
+ break;
+
+ case CODA_REPLACE:
+ fid = &out->coda_replace.OldFid;
+ break;
+ }
+ if (fid)
inode = coda_fid_to_inode(fid, sb);
- if (inode) {
- coda_flag_inode_children(inode, C_PURGE);
- /* catch the dentries later if some are still busy */
- coda_flag_inode(inode, C_PURGE);
- d_prune_aliases(inode);
+unlock_out:
+ mutex_unlock(&vcp->vc_mutex);
- }
+ if (!inode)
+ return 0;
+
+ switch (opcode) {
+ case CODA_ZAPDIR:
+ coda_flag_inode_children(inode, C_PURGE);
+ coda_flag_inode(inode, C_VATTR);
+ break;
+
+ case CODA_ZAPFILE:
+ coda_flag_inode(inode, C_VATTR);
+ break;
+
+ case CODA_PURGEFID:
+ coda_flag_inode_children(inode, C_PURGE);
+
+ /* catch the dentries later if some are still busy */
+ coda_flag_inode(inode, C_PURGE);
+ d_prune_aliases(inode);
break;
case CODA_REPLACE:
- fid = &out->coda_replace.OldFid;
newfid = &out->coda_replace.NewFid;
- inode = coda_fid_to_inode(fid, sb);
- if (inode)
- coda_replace_fid(inode, fid, newfid);
+ coda_replace_fid(inode, fid, newfid);
break;
}
-
- if (inode)
- iput(inode);
-
+ iput(inode);
return 0;
}
diff --git a/fs/compat.c b/fs/compat.c
index 0644a154672b..f03abdadc401 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1963,7 +1963,7 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
}
#endif /* HAVE_SET_RESTORE_SIGMASK */
-#if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
+#if (defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)) && !defined(CONFIG_NFSD_DEPRECATED)
/* Stuff for NFS server syscalls... */
struct compat_nfsctl_svc {
u16 svc32_port;
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c
index cf78d44a8d6a..253476d78ed8 100644
--- a/fs/configfs/inode.c
+++ b/fs/configfs/inode.c
@@ -135,6 +135,7 @@ struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent * sd)
{
struct inode * inode = new_inode(configfs_sb);
if (inode) {
+ inode->i_ino = get_next_ino();
inode->i_mapping->a_ops = &configfs_aops;
inode->i_mapping->backing_dev_info = &configfs_backing_dev_info;
inode->i_op = &configfs_inode_operations;
diff --git a/fs/dcache.c b/fs/dcache.c
index 83293be48149..23702a9d4e6d 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -67,33 +67,43 @@ struct dentry_stat_t dentry_stat = {
.age_limit = 45,
};
-static void __d_free(struct dentry *dentry)
+static struct percpu_counter nr_dentry __cacheline_aligned_in_smp;
+static struct percpu_counter nr_dentry_unused __cacheline_aligned_in_smp;
+
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
+int proc_nr_dentry(ctl_table *table, int write, void __user *buffer,
+ size_t *lenp, loff_t *ppos)
+{
+ dentry_stat.nr_dentry = percpu_counter_sum_positive(&nr_dentry);
+ dentry_stat.nr_unused = percpu_counter_sum_positive(&nr_dentry_unused);
+ return proc_dointvec(table, write, buffer, lenp, ppos);
+}
+#endif
+
+static void __d_free(struct rcu_head *head)
{
+ struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
+
WARN_ON(!list_empty(&dentry->d_alias));
if (dname_external(dentry))
kfree(dentry->d_name.name);
kmem_cache_free(dentry_cache, dentry);
}
-static void d_callback(struct rcu_head *head)
-{
- struct dentry * dentry = container_of(head, struct dentry, d_u.d_rcu);
- __d_free(dentry);
-}
-
/*
- * no dcache_lock, please. The caller must decrement dentry_stat.nr_dentry
- * inside dcache_lock.
+ * no dcache_lock, please.
*/
static void d_free(struct dentry *dentry)
{
+ percpu_counter_dec(&nr_dentry);
if (dentry->d_op && dentry->d_op->d_release)
dentry->d_op->d_release(dentry);
+
/* if dentry was never inserted into hash, immediate free is OK */
if (hlist_unhashed(&dentry->d_hash))
- __d_free(dentry);
+ __d_free(&dentry->d_u.d_rcu);
else
- call_rcu(&dentry->d_u.d_rcu, d_callback);
+ call_rcu(&dentry->d_u.d_rcu, __d_free);
}
/*
@@ -123,37 +133,34 @@ static void dentry_iput(struct dentry * dentry)
}
/*
- * dentry_lru_(add|add_tail|del|del_init) must be called with dcache_lock held.
+ * dentry_lru_(add|del|move_tail) must be called with dcache_lock held.
*/
static void dentry_lru_add(struct dentry *dentry)
{
- list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
- dentry->d_sb->s_nr_dentry_unused++;
- dentry_stat.nr_unused++;
-}
-
-static void dentry_lru_add_tail(struct dentry *dentry)
-{
- list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
- dentry->d_sb->s_nr_dentry_unused++;
- dentry_stat.nr_unused++;
+ if (list_empty(&dentry->d_lru)) {
+ list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
+ dentry->d_sb->s_nr_dentry_unused++;
+ percpu_counter_inc(&nr_dentry_unused);
+ }
}
static void dentry_lru_del(struct dentry *dentry)
{
if (!list_empty(&dentry->d_lru)) {
- list_del(&dentry->d_lru);
+ list_del_init(&dentry->d_lru);
dentry->d_sb->s_nr_dentry_unused--;
- dentry_stat.nr_unused--;
+ percpu_counter_dec(&nr_dentry_unused);
}
}
-static void dentry_lru_del_init(struct dentry *dentry)
+static void dentry_lru_move_tail(struct dentry *dentry)
{
- if (likely(!list_empty(&dentry->d_lru))) {
- list_del_init(&dentry->d_lru);
- dentry->d_sb->s_nr_dentry_unused--;
- dentry_stat.nr_unused--;
+ if (list_empty(&dentry->d_lru)) {
+ list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
+ dentry->d_sb->s_nr_dentry_unused++;
+ percpu_counter_inc(&nr_dentry_unused);
+ } else {
+ list_move_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
}
}
@@ -172,7 +179,6 @@ static struct dentry *d_kill(struct dentry *dentry)
struct dentry *parent;
list_del(&dentry->d_u.d_child);
- dentry_stat.nr_dentry--; /* For d_free, below */
/*drops the locks, at that point nobody can reach this dentry */
dentry_iput(dentry);
if (IS_ROOT(dentry))
@@ -237,13 +243,15 @@ repeat:
if (dentry->d_op->d_delete(dentry))
goto unhash_it;
}
+
/* Unreachable? Get rid of it */
if (d_unhashed(dentry))
goto kill_it;
- if (list_empty(&dentry->d_lru)) {
- dentry->d_flags |= DCACHE_REFERENCED;
- dentry_lru_add(dentry);
- }
+
+ /* Otherwise leave it cached and ensure it's on the LRU */
+ dentry->d_flags |= DCACHE_REFERENCED;
+ dentry_lru_add(dentry);
+
spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);
return;
@@ -318,11 +326,10 @@ int d_invalidate(struct dentry * dentry)
EXPORT_SYMBOL(d_invalidate);
/* This should be called _only_ with dcache_lock held */
-
static inline struct dentry * __dget_locked(struct dentry *dentry)
{
atomic_inc(&dentry->d_count);
- dentry_lru_del_init(dentry);
+ dentry_lru_del(dentry);
return dentry;
}
@@ -441,73 +448,27 @@ static void prune_one_dentry(struct dentry * dentry)
if (dentry->d_op && dentry->d_op->d_delete)
dentry->d_op->d_delete(dentry);
- dentry_lru_del_init(dentry);
+ dentry_lru_del(dentry);
__d_drop(dentry);
dentry = d_kill(dentry);
spin_lock(&dcache_lock);
}
}
-/*
- * Shrink the dentry LRU on a given superblock.
- * @sb : superblock to shrink dentry LRU.
- * @count: If count is NULL, we prune all dentries on superblock.
- * @flags: If flags is non-zero, we need to do special processing based on
- * which flags are set. This means we don't need to maintain multiple
- * similar copies of this loop.
- */
-static void __shrink_dcache_sb(struct super_block *sb, int *count, int flags)
+static void shrink_dentry_list(struct list_head *list)
{
- LIST_HEAD(referenced);
- LIST_HEAD(tmp);
struct dentry *dentry;
- int cnt = 0;
- BUG_ON(!sb);
- BUG_ON((flags & DCACHE_REFERENCED) && count == NULL);
- spin_lock(&dcache_lock);
- if (count != NULL)
- /* called from prune_dcache() and shrink_dcache_parent() */
- cnt = *count;
-restart:
- if (count == NULL)
- list_splice_init(&sb->s_dentry_lru, &tmp);
- else {
- while (!list_empty(&sb->s_dentry_lru)) {
- dentry = list_entry(sb->s_dentry_lru.prev,
- struct dentry, d_lru);
- BUG_ON(dentry->d_sb != sb);
+ while (!list_empty(list)) {
+ dentry = list_entry(list->prev, struct dentry, d_lru);
+ dentry_lru_del(dentry);
- spin_lock(&dentry->d_lock);
- /*
- * If we are honouring the DCACHE_REFERENCED flag and
- * the dentry has this flag set, don't free it. Clear
- * the flag and put it back on the LRU.
- */
- if ((flags & DCACHE_REFERENCED)
- && (dentry->d_flags & DCACHE_REFERENCED)) {
- dentry->d_flags &= ~DCACHE_REFERENCED;
- list_move(&dentry->d_lru, &referenced);
- spin_unlock(&dentry->d_lock);
- } else {
- list_move_tail(&dentry->d_lru, &tmp);
- spin_unlock(&dentry->d_lock);
- cnt--;
- if (!cnt)
- break;
- }
- cond_resched_lock(&dcache_lock);
- }
- }
- while (!list_empty(&tmp)) {
- dentry = list_entry(tmp.prev, struct dentry, d_lru);
- dentry_lru_del_init(dentry);
- spin_lock(&dentry->d_lock);
/*
* We found an inuse dentry which was not removed from
* the LRU because of laziness during lookup. Do not free
* it - just keep it off the LRU list.
*/
+ spin_lock(&dentry->d_lock);
if (atomic_read(&dentry->d_count)) {
spin_unlock(&dentry->d_lock);
continue;
@@ -516,13 +477,60 @@ restart:
/* dentry->d_lock was dropped in prune_one_dentry() */
cond_resched_lock(&dcache_lock);
}
- if (count == NULL && !list_empty(&sb->s_dentry_lru))
- goto restart;
- if (count != NULL)
- *count = cnt;
+}
+
+/**
+ * __shrink_dcache_sb - shrink the dentry LRU on a given superblock
+ * @sb: superblock to shrink dentry LRU.
+ * @count: number of entries to prune
+ * @flags: flags to control the dentry processing
+ *
+ * If flags contains DCACHE_REFERENCED reference dentries will not be pruned.
+ */
+static void __shrink_dcache_sb(struct super_block *sb, int *count, int flags)
+{
+ /* called from prune_dcache() and shrink_dcache_parent() */
+ struct dentry *dentry;
+ LIST_HEAD(referenced);
+ LIST_HEAD(tmp);
+ int cnt = *count;
+
+ spin_lock(&dcache_lock);
+ while (!list_empty(&sb->s_dentry_lru)) {
+ dentry = list_entry(sb->s_dentry_lru.prev,
+ struct dentry, d_lru);
+ BUG_ON(dentry->d_sb != sb);
+
+ /*
+ * If we are honouring the DCACHE_REFERENCED flag and the
+ * dentry has this flag set, don't free it. Clear the flag
+ * and put it back on the LRU.
+ */
+ if (flags & DCACHE_REFERENCED) {
+ spin_lock(&dentry->d_lock);
+ if (dentry->d_flags & DCACHE_REFERENCED) {
+ dentry->d_flags &= ~DCACHE_REFERENCED;
+ list_move(&dentry->d_lru, &referenced);
+ spin_unlock(&dentry->d_lock);
+ cond_resched_lock(&dcache_lock);
+ continue;
+ }
+ spin_unlock(&dentry->d_lock);
+ }
+
+ list_move_tail(&dentry->d_lru, &tmp);
+ if (!--cnt)
+ break;
+ cond_resched_lock(&dcache_lock);
+ }
+
+ *count = cnt;
+ shrink_dentry_list(&tmp);
+
if (!list_empty(&referenced))
list_splice(&referenced, &sb->s_dentry_lru);
spin_unlock(&dcache_lock);
+
}
/**
@@ -538,7 +546,7 @@ static void prune_dcache(int count)
{
struct super_block *sb, *p = NULL;
int w_count;
- int unused = dentry_stat.nr_unused;
+ int unused = percpu_counter_sum_positive(&nr_dentry_unused);
int prune_ratio;
int pruned;
@@ -608,13 +616,19 @@ static void prune_dcache(int count)
* shrink_dcache_sb - shrink dcache for a superblock
* @sb: superblock
*
- * Shrink the dcache for the specified super block. This
- * is used to free the dcache before unmounting a file
- * system
+ * Shrink the dcache for the specified super block. This is used to free
+ * the dcache before unmounting a file system.
*/
-void shrink_dcache_sb(struct super_block * sb)
+void shrink_dcache_sb(struct super_block *sb)
{
- __shrink_dcache_sb(sb, NULL, 0);
+ LIST_HEAD(tmp);
+
+ spin_lock(&dcache_lock);
+ while (!list_empty(&sb->s_dentry_lru)) {
+ list_splice_init(&sb->s_dentry_lru, &tmp);
+ shrink_dentry_list(&tmp);
+ }
+ spin_unlock(&dcache_lock);
}
EXPORT_SYMBOL(shrink_dcache_sb);
@@ -632,7 +646,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
/* detach this root from the system */
spin_lock(&dcache_lock);
- dentry_lru_del_init(dentry);
+ dentry_lru_del(dentry);
__d_drop(dentry);
spin_unlock(&dcache_lock);
@@ -646,7 +660,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
spin_lock(&dcache_lock);
list_for_each_entry(loop, &dentry->d_subdirs,
d_u.d_child) {
- dentry_lru_del_init(loop);
+ dentry_lru_del(loop);
__d_drop(loop);
cond_resched_lock(&dcache_lock);
}
@@ -703,20 +717,13 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
* otherwise we ascend to the parent and move to the
* next sibling if there is one */
if (!parent)
- goto out;
-
+ return;
dentry = parent;
-
} while (list_empty(&dentry->d_subdirs));
dentry = list_entry(dentry->d_subdirs.next,
struct dentry, d_u.d_child);
}
-out:
- /* several dentries were freed, need to correct nr_dentry */
- spin_lock(&dcache_lock);
- dentry_stat.nr_dentry -= detached;
- spin_unlock(&dcache_lock);
}
/*
@@ -830,14 +837,15 @@ resume:
struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
next = tmp->next;
- dentry_lru_del_init(dentry);
/*
* move only zero ref count dentries to the end
* of the unused list for prune_dcache
*/
if (!atomic_read(&dentry->d_count)) {
- dentry_lru_add_tail(dentry);
+ dentry_lru_move_tail(dentry);
found++;
+ } else {
+ dentry_lru_del(dentry);
}
/*
@@ -900,12 +908,16 @@ EXPORT_SYMBOL(shrink_dcache_parent);
*/
static int shrink_dcache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
{
+ int nr_unused;
+
if (nr) {
if (!(gfp_mask & __GFP_FS))
return -1;
prune_dcache(nr);
}
- return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
+
+ nr_unused = percpu_counter_sum_positive(&nr_dentry_unused);
+ return (nr_unused / 100) * sysctl_vfs_cache_pressure;
}
static struct shrinker dcache_shrinker = {
@@ -972,9 +984,10 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
spin_lock(&dcache_lock);
if (parent)
list_add(&dentry->d_u.d_child, &parent->d_subdirs);
- dentry_stat.nr_dentry++;
spin_unlock(&dcache_lock);
+ percpu_counter_inc(&nr_dentry);
+
return dentry;
}
EXPORT_SYMBOL(d_alloc);
@@ -1478,33 +1491,26 @@ out:
* This is used by ncpfs in its readdir implementation.
* Zero is returned in the dentry is invalid.
*/
-
-int d_validate(struct dentry *dentry, struct dentry *dparent)
+int d_validate(struct dentry *dentry, struct dentry *parent)
{
- struct hlist_head *base;
- struct hlist_node *lhp;
+ struct hlist_head *head = d_hash(parent, dentry->d_name.hash);
+ struct hlist_node *node;
+ struct dentry *d;
/* Check whether the ptr might be valid at all.. */
if (!kmem_ptr_validate(dentry_cache, dentry))
- goto out;
-
- if (dentry->d_parent != dparent)
- goto out;
+ return 0;
+ if (dentry->d_parent != parent)
+ return 0;
- spin_lock(&dcache_lock);
- base = d_hash(dparent, dentry->d_name.hash);
- hlist_for_each(lhp,base) {
- /* hlist_for_each_entry_rcu() not required for d_hash list
- * as it is parsed under dcache_lock
- */
- if (dentry == hlist_entry(lhp, struct dentry, d_hash)) {
- __dget_locked(dentry);
- spin_unlock(&dcache_lock);
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(d, node, head, d_hash) {
+ if (d == dentry) {
+ dget(dentry);
return 1;
}
}
- spin_unlock(&dcache_lock);
-out:
+ rcu_read_unlock();
return 0;
}
EXPORT_SYMBOL(d_validate);
@@ -1994,7 +2000,7 @@ global_root:
* Returns a pointer into the buffer or an error code if the
* path was too long.
*
- * "buflen" should be positive. Caller holds the dcache_lock.
+ * "buflen" should be positive.
*
* If path is not reachable from the supplied root, then the value of
* root is changed (without modifying refcounts).
@@ -2006,10 +2012,12 @@ char *__d_path(const struct path *path, struct path *root,
int error;
prepend(&res, &buflen, "\0", 1);
+ spin_lock(&dcache_lock);
error = prepend_path(path, root, &res, &buflen);
+ spin_unlock(&dcache_lock);
+
if (error)
return ERR_PTR(error);
-
return res;
}
@@ -2419,6 +2427,9 @@ static void __init dcache_init(void)
{
int loop;
+ percpu_counter_init(&nr_dentry, 0);
+ percpu_counter_init(&nr_dentry_unused, 0);
+
/*
* A constructor could be added for stable state like the lists,
* but it is probably not worth it because of the cache nature
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 30a87b3dbcac..a4ed8380e98a 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -40,6 +40,7 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d
struct inode *inode = new_inode(sb);
if (inode) {
+ inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch (mode & S_IFMT) {
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 48d74c7391d1..85882f6ba5f7 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -218,7 +218,7 @@ static struct page *dio_get_page(struct dio *dio)
* filesystems can use it to hold additional state between get_block calls and
* dio_complete.
*/
-static int dio_complete(struct dio *dio, loff_t offset, int ret, bool is_async)
+static ssize_t dio_complete(struct dio *dio, loff_t offset, ssize_t ret, bool is_async)
{
ssize_t transferred = 0;
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index 0032a9f5a3a9..40186b959429 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -477,7 +477,7 @@ ecryptfs_lower_header_size(struct ecryptfs_crypt_stat *crypt_stat)
static inline struct ecryptfs_file_info *
ecryptfs_file_to_private(struct file *file)
{
- return (struct ecryptfs_file_info *)file->private_data;
+ return file->private_data;
}
static inline void
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 256bb7bb102a..8cf07242067d 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -77,9 +77,6 @@
/* Maximum number of nesting allowed inside epoll sets */
#define EP_MAX_NESTS 4
-/* Maximum msec timeout value storeable in a long int */
-#define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ)
-
#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
#define EP_UNACTIVE_PTR ((void *) -1L)
@@ -1117,18 +1114,22 @@ static int ep_send_events(struct eventpoll *ep,
static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
int maxevents, long timeout)
{
- int res, eavail;
+ int res, eavail, timed_out = 0;
unsigned long flags;
- long jtimeout;
+ long slack;
wait_queue_t wait;
-
- /*
- * Calculate the timeout by checking for the "infinite" value (-1)
- * and the overflow condition. The passed timeout is in milliseconds,
- * that why (t * HZ) / 1000.
- */
- jtimeout = (timeout < 0 || timeout >= EP_MAX_MSTIMEO) ?
- MAX_SCHEDULE_TIMEOUT : (timeout * HZ + 999) / 1000;
+ struct timespec end_time;
+ ktime_t expires, *to = NULL;
+
+ if (timeout > 0) {
+ ktime_get_ts(&end_time);
+ timespec_add_ns(&end_time, (u64)timeout * NSEC_PER_MSEC);
+ slack = select_estimate_accuracy(&end_time);
+ to = &expires;
+ *to = timespec_to_ktime(end_time);
+ } else if (timeout == 0) {
+ timed_out = 1;
+ }
retry:
spin_lock_irqsave(&ep->lock, flags);
@@ -1150,7 +1151,7 @@ retry:
* to TASK_INTERRUPTIBLE before doing the checks.
*/
set_current_state(TASK_INTERRUPTIBLE);
- if (!list_empty(&ep->rdllist) || !jtimeout)
+ if (!list_empty(&ep->rdllist) || timed_out)
break;
if (signal_pending(current)) {
res = -EINTR;
@@ -1158,7 +1159,9 @@ retry:
}
spin_unlock_irqrestore(&ep->lock, flags);
- jtimeout = schedule_timeout(jtimeout);
+ if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS))
+ timed_out = 1;
+
spin_lock_irqsave(&ep->lock, flags);
}
__remove_wait_queue(&ep->wq, &wait);
@@ -1176,7 +1179,7 @@ retry:
* more luck.
*/
if (!res && eavail &&
- !(res = ep_send_events(ep, events, maxevents)) && jtimeout)
+ !(res = ep_send_events(ep, events, maxevents)) && !timed_out)
goto retry;
return res;
diff --git a/fs/exec.c b/fs/exec.c
index 6d2b6f936858..99d33a1371e9 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -54,6 +54,7 @@
#include <linux/fsnotify.h>
#include <linux/fs_struct.h>
#include <linux/pipe_fs_i.h>
+#include <linux/oom.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
@@ -65,6 +66,12 @@ char core_pattern[CORENAME_MAX_SIZE] = "core";
unsigned int core_pipe_limit;
int suid_dumpable = 0;
+struct core_name {
+ char *corename;
+ int used, size;
+};
+static atomic_t call_count = ATOMIC_INIT(1);
+
/* The maximal length of core_pattern is also specified in sysctl.c */
static LIST_HEAD(formats);
@@ -759,6 +766,10 @@ static int exec_mmap(struct mm_struct *mm)
tsk->mm = mm;
tsk->active_mm = mm;
activate_mm(active_mm, mm);
+ if (old_mm && tsk->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {
+ atomic_dec(&old_mm->oom_disable_count);
+ atomic_inc(&tsk->mm->oom_disable_count);
+ }
task_unlock(tsk);
arch_pick_mmap_layout(mm);
if (old_mm) {
@@ -998,7 +1009,7 @@ int flush_old_exec(struct linux_binprm * bprm)
bprm->mm = NULL; /* We're using it now */
- current->flags &= ~PF_RANDOMIZE;
+ current->flags &= ~(PF_RANDOMIZE | PF_KTHREAD);
flush_thread();
current->personality &= ~bprm->per_clear;
@@ -1078,14 +1089,14 @@ EXPORT_SYMBOL(setup_new_exec);
*/
int prepare_bprm_creds(struct linux_binprm *bprm)
{
- if (mutex_lock_interruptible(&current->cred_guard_mutex))
+ if (mutex_lock_interruptible(&current->signal->cred_guard_mutex))
return -ERESTARTNOINTR;
bprm->cred = prepare_exec_creds();
if (likely(bprm->cred))
return 0;
- mutex_unlock(&current->cred_guard_mutex);
+ mutex_unlock(&current->signal->cred_guard_mutex);
return -ENOMEM;
}
@@ -1093,7 +1104,7 @@ void free_bprm(struct linux_binprm *bprm)
{
free_arg_pages(bprm);
if (bprm->cred) {
- mutex_unlock(&current->cred_guard_mutex);
+ mutex_unlock(&current->signal->cred_guard_mutex);
abort_creds(bprm->cred);
}
kfree(bprm);
@@ -1114,13 +1125,13 @@ void install_exec_creds(struct linux_binprm *bprm)
* credentials; any time after this it may be unlocked.
*/
security_bprm_committed_creds(bprm);
- mutex_unlock(&current->cred_guard_mutex);
+ mutex_unlock(&current->signal->cred_guard_mutex);
}
EXPORT_SYMBOL(install_exec_creds);
/*
* determine how safe it is to execute the proposed program
- * - the caller must hold current->cred_guard_mutex to protect against
+ * - the caller must hold ->cred_guard_mutex to protect against
* PTRACE_ATTACH
*/
int check_unsafe_exec(struct linux_binprm *bprm)
@@ -1401,7 +1412,6 @@ int do_execve(const char * filename,
if (retval < 0)
goto out;
- current->flags &= ~PF_KTHREAD;
retval = search_binary_handler(bprm,regs);
if (retval < 0)
goto out;
@@ -1454,127 +1464,148 @@ void set_binfmt(struct linux_binfmt *new)
EXPORT_SYMBOL(set_binfmt);
+static int expand_corename(struct core_name *cn)
+{
+ char *old_corename = cn->corename;
+
+ cn->size = CORENAME_MAX_SIZE * atomic_inc_return(&call_count);
+ cn->corename = krealloc(old_corename, cn->size, GFP_KERNEL);
+
+ if (!cn->corename) {
+ kfree(old_corename);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int cn_printf(struct core_name *cn, const char *fmt, ...)
+{
+ char *cur;
+ int need;
+ int ret;
+ va_list arg;
+
+ va_start(arg, fmt);
+ need = vsnprintf(NULL, 0, fmt, arg);
+ va_end(arg);
+
+ if (likely(need < cn->size - cn->used - 1))
+ goto out_printf;
+
+ ret = expand_corename(cn);
+ if (ret)
+ goto expand_fail;
+
+out_printf:
+ cur = cn->corename + cn->used;
+ va_start(arg, fmt);
+ vsnprintf(cur, need + 1, fmt, arg);
+ va_end(arg);
+ cn->used += need;
+ return 0;
+
+expand_fail:
+ return ret;
+}
+
/* format_corename will inspect the pattern parameter, and output a
* name into corename, which must have space for at least
* CORENAME_MAX_SIZE bytes plus one byte for the zero terminator.
*/
-static int format_corename(char *corename, long signr)
+static int format_corename(struct core_name *cn, long signr)
{
const struct cred *cred = current_cred();
const char *pat_ptr = core_pattern;
int ispipe = (*pat_ptr == '|');
- char *out_ptr = corename;
- char *const out_end = corename + CORENAME_MAX_SIZE;
- int rc;
int pid_in_pattern = 0;
+ int err = 0;
+
+ cn->size = CORENAME_MAX_SIZE * atomic_read(&call_count);
+ cn->corename = kmalloc(cn->size, GFP_KERNEL);
+ cn->used = 0;
+
+ if (!cn->corename)
+ return -ENOMEM;
/* Repeat as long as we have more pattern to process and more output
space */
while (*pat_ptr) {
if (*pat_ptr != '%') {
- if (out_ptr == out_end)
+ if (*pat_ptr == 0)
goto out;
- *out_ptr++ = *pat_ptr++;
+ err = cn_printf(cn, "%c", *pat_ptr++);
} else {
switch (*++pat_ptr) {
+ /* single % at the end, drop that */
case 0:
goto out;
/* Double percent, output one percent */
case '%':
- if (out_ptr == out_end)
- goto out;
- *out_ptr++ = '%';
+ err = cn_printf(cn, "%c", '%');
break;
/* pid */
case 'p':
pid_in_pattern = 1;
- rc = snprintf(out_ptr, out_end - out_ptr,
- "%d", task_tgid_vnr(current));
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
+ err = cn_printf(cn, "%d",
+ task_tgid_vnr(current));
break;
/* uid */
case 'u':
- rc = snprintf(out_ptr, out_end - out_ptr,
- "%d", cred->uid);
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
+ err = cn_printf(cn, "%d", cred->uid);
break;
/* gid */
case 'g':
- rc = snprintf(out_ptr, out_end - out_ptr,
- "%d", cred->gid);
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
+ err = cn_printf(cn, "%d", cred->gid);
break;
/* signal that caused the coredump */
case 's':
- rc = snprintf(out_ptr, out_end - out_ptr,
- "%ld", signr);
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
+ err = cn_printf(cn, "%ld", signr);
break;
/* UNIX time of coredump */
case 't': {
struct timeval tv;
do_gettimeofday(&tv);
- rc = snprintf(out_ptr, out_end - out_ptr,
- "%lu", tv.tv_sec);
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
+ err = cn_printf(cn, "%lu", tv.tv_sec);
break;
}
/* hostname */
case 'h':
down_read(&uts_sem);
- rc = snprintf(out_ptr, out_end - out_ptr,
- "%s", utsname()->nodename);
+ err = cn_printf(cn, "%s",
+ utsname()->nodename);
up_read(&uts_sem);
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
break;
/* executable */
case 'e':
- rc = snprintf(out_ptr, out_end - out_ptr,
- "%s", current->comm);
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
+ err = cn_printf(cn, "%s", current->comm);
break;
/* core limit size */
case 'c':
- rc = snprintf(out_ptr, out_end - out_ptr,
- "%lu", rlimit(RLIMIT_CORE));
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
+ err = cn_printf(cn, "%lu",
+ rlimit(RLIMIT_CORE));
break;
default:
break;
}
++pat_ptr;
}
+
+ if (err)
+ return err;
}
+
/* Backward compatibility with core_uses_pid:
*
* If core_pattern does not include a %p (as is the default)
* and core_uses_pid is set, then .%pid will be appended to
* the filename. Do not do this for piped commands. */
if (!ispipe && !pid_in_pattern && core_uses_pid) {
- rc = snprintf(out_ptr, out_end - out_ptr,
- ".%d", task_tgid_vnr(current));
- if (rc > out_end - out_ptr)
- goto out;
- out_ptr += rc;
+ err = cn_printf(cn, ".%d", task_tgid_vnr(current));
+ if (err)
+ return err;
}
out:
- *out_ptr = 0;
return ispipe;
}
@@ -1851,7 +1882,7 @@ static int umh_pipe_setup(struct subprocess_info *info)
void do_coredump(long signr, int exit_code, struct pt_regs *regs)
{
struct core_state core_state;
- char corename[CORENAME_MAX_SIZE + 1];
+ struct core_name cn;
struct mm_struct *mm = current->mm;
struct linux_binfmt * binfmt;
const struct cred *old_cred;
@@ -1906,7 +1937,13 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
*/
clear_thread_flag(TIF_SIGPENDING);
- ispipe = format_corename(corename, signr);
+ ispipe = format_corename(&cn, signr);
+
+ if (ispipe == -ENOMEM) {
+ printk(KERN_WARNING "format_corename failed\n");
+ printk(KERN_WARNING "Aborting core\n");
+ goto fail_corename;
+ }
if (ispipe) {
int dump_count;
@@ -1943,7 +1980,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
goto fail_dropcount;
}
- helper_argv = argv_split(GFP_KERNEL, corename+1, NULL);
+ helper_argv = argv_split(GFP_KERNEL, cn.corename+1, NULL);
if (!helper_argv) {
printk(KERN_WARNING "%s failed to allocate memory\n",
__func__);
@@ -1956,7 +1993,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
argv_free(helper_argv);
if (retval) {
printk(KERN_INFO "Core dump to %s pipe failed\n",
- corename);
+ cn.corename);
goto close_fail;
}
} else {
@@ -1965,7 +2002,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
if (cprm.limit < binfmt->min_coredump)
goto fail_unlock;
- cprm.file = filp_open(corename,
+ cprm.file = filp_open(cn.corename,
O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,
0600);
if (IS_ERR(cprm.file))
@@ -2007,6 +2044,8 @@ fail_dropcount:
if (ispipe)
atomic_dec(&core_dump_count);
fail_unlock:
+ kfree(cn.corename);
+fail_corename:
coredump_finish(mm);
revert_creds(old_cred);
fail_creds:
diff --git a/fs/exofs/dir.c b/fs/exofs/dir.c
index d91e9d829bc1..dcc941d82d67 100644
--- a/fs/exofs/dir.c
+++ b/fs/exofs/dir.c
@@ -420,7 +420,7 @@ int exofs_set_link(struct inode *dir, struct exofs_dir_entry *de,
err = exofs_write_begin(NULL, page->mapping, pos, len,
AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
if (err)
- EXOFS_ERR("exofs_set_link: exofs_write_begin FAILD => %d\n",
+ EXOFS_ERR("exofs_set_link: exofs_write_begin FAILED => %d\n",
err);
de->inode_no = cpu_to_le64(inode->i_ino);
@@ -556,7 +556,7 @@ int exofs_delete_entry(struct exofs_dir_entry *dir, struct page *page)
err = exofs_write_begin(NULL, page->mapping, pos, to - from, 0,
&page, NULL);
if (err)
- EXOFS_ERR("exofs_delete_entry: exofs_write_begin FAILD => %d\n",
+ EXOFS_ERR("exofs_delete_entry: exofs_write_begin FAILED => %d\n",
err);
if (pde)
pde->rec_len = cpu_to_le16(to - from);
diff --git a/fs/exofs/file.c b/fs/exofs/file.c
index 68cb23e3bb98..b905c79b4f0a 100644
--- a/fs/exofs/file.c
+++ b/fs/exofs/file.c
@@ -46,10 +46,6 @@ static int exofs_file_fsync(struct file *filp, int datasync)
{
int ret;
struct inode *inode = filp->f_mapping->host;
- struct writeback_control wbc = {
- .sync_mode = WB_SYNC_ALL,
- .nr_to_write = 0, /* metadata-only; caller takes care of data */
- };
struct super_block *sb;
if (!(inode->i_state & I_DIRTY))
@@ -57,7 +53,7 @@ static int exofs_file_fsync(struct file *filp, int datasync)
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
return 0;
- ret = sync_inode(inode, &wbc);
+ ret = sync_inode_metadata(inode, 1);
/* This is a good place to write the sb */
/* TODO: Sechedule an sb-sync on create */
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c
index 3eadd97324b1..42685424817b 100644
--- a/fs/exofs/inode.c
+++ b/fs/exofs/inode.c
@@ -185,7 +185,7 @@ static void update_write_page(struct page *page, int ret)
/* Called at the end of reads, to optionally unlock pages and update their
* status.
*/
-static int __readpages_done(struct page_collect *pcol, bool do_unlock)
+static int __readpages_done(struct page_collect *pcol)
{
int i;
u64 resid;
@@ -221,7 +221,7 @@ static int __readpages_done(struct page_collect *pcol, bool do_unlock)
page_stat ? "bad_bytes" : "good_bytes");
ret = update_read_page(page, page_stat);
- if (do_unlock)
+ if (!pcol->read_4_write)
unlock_page(page);
length += PAGE_SIZE;
}
@@ -236,7 +236,7 @@ static void readpages_done(struct exofs_io_state *ios, void *p)
{
struct page_collect *pcol = p;
- __readpages_done(pcol, true);
+ __readpages_done(pcol);
atomic_dec(&pcol->sbi->s_curr_pending);
kfree(pcol);
}
@@ -257,7 +257,7 @@ static void _unlock_pcol_pages(struct page_collect *pcol, int ret, int rw)
}
}
-static int read_exec(struct page_collect *pcol, bool is_sync)
+static int read_exec(struct page_collect *pcol)
{
struct exofs_i_info *oi = exofs_i(pcol->inode);
struct exofs_io_state *ios = pcol->ios;
@@ -267,17 +267,14 @@ static int read_exec(struct page_collect *pcol, bool is_sync)
if (!pcol->pages)
return 0;
- /* see comment in _readpage() about sync reads */
- WARN_ON(is_sync && (pcol->nr_pages != 1));
-
ios->pages = pcol->pages;
ios->nr_pages = pcol->nr_pages;
ios->length = pcol->length;
ios->offset = pcol->pg_first << PAGE_CACHE_SHIFT;
- if (is_sync) {
+ if (pcol->read_4_write) {
exofs_oi_read(oi, pcol->ios);
- return __readpages_done(pcol, false);
+ return __readpages_done(pcol);
}
pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL);
@@ -303,7 +300,7 @@ static int read_exec(struct page_collect *pcol, bool is_sync)
return 0;
err:
- if (!is_sync)
+ if (!pcol->read_4_write)
_unlock_pcol_pages(pcol, ret, READ);
pcol_free(pcol);
@@ -356,7 +353,7 @@ static int readpage_strip(void *data, struct page *page)
EXOFS_DBGMSG("readpage_strip(0x%lx, 0x%lx) empty page,"
" splitting\n", inode->i_ino, page->index);
- return read_exec(pcol, false);
+ return read_exec(pcol);
}
try_again:
@@ -366,7 +363,7 @@ try_again:
} else if (unlikely((pcol->pg_first + pcol->nr_pages) !=
page->index)) {
/* Discontinuity detected, split the request */
- ret = read_exec(pcol, false);
+ ret = read_exec(pcol);
if (unlikely(ret))
goto fail;
goto try_again;
@@ -391,7 +388,7 @@ try_again:
page, len, pcol->nr_pages, pcol->length);
/* split the request, and start again with current page */
- ret = read_exec(pcol, false);
+ ret = read_exec(pcol);
if (unlikely(ret))
goto fail;
@@ -420,27 +417,24 @@ static int exofs_readpages(struct file *file, struct address_space *mapping,
return ret;
}
- return read_exec(&pcol, false);
+ return read_exec(&pcol);
}
-static int _readpage(struct page *page, bool is_sync)
+static int _readpage(struct page *page, bool read_4_write)
{
struct page_collect pcol;
int ret;
_pcol_init(&pcol, 1, page->mapping->host);
- /* readpage_strip might call read_exec(,is_sync==false) at several
- * places but not if we have a single page.
- */
- pcol.read_4_write = is_sync;
+ pcol.read_4_write = read_4_write;
ret = readpage_strip(&pcol, page);
if (ret) {
EXOFS_ERR("_readpage => %d\n", ret);
return ret;
}
- return read_exec(&pcol, is_sync);
+ return read_exec(&pcol);
}
/*
@@ -511,7 +505,7 @@ static int write_exec(struct page_collect *pcol)
pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL);
if (!pcol_copy) {
- EXOFS_ERR("write_exec: Faild to kmalloc(pcol)\n");
+ EXOFS_ERR("write_exec: Failed to kmalloc(pcol)\n");
ret = -ENOMEM;
goto err;
}
@@ -527,7 +521,7 @@ static int write_exec(struct page_collect *pcol)
ret = exofs_oi_write(oi, ios);
if (unlikely(ret)) {
- EXOFS_ERR("write_exec: exofs_oi_write() Faild\n");
+ EXOFS_ERR("write_exec: exofs_oi_write() Failed\n");
goto err;
}
@@ -628,7 +622,7 @@ try_again:
/* split the request, next loop will start again */
ret = write_exec(pcol);
if (unlikely(ret)) {
- EXOFS_DBGMSG("write_exec faild => %d", ret);
+ EXOFS_DBGMSG("write_exec failed => %d", ret);
goto fail;
}
@@ -719,7 +713,7 @@ int exofs_write_begin(struct file *file, struct address_space *mapping,
ret = simple_write_begin(file, mapping, pos, len, flags, pagep,
fsdata);
if (ret) {
- EXOFS_DBGMSG("simple_write_begin faild\n");
+ EXOFS_DBGMSG("simple_write_begin failed\n");
goto out;
}
@@ -732,7 +726,7 @@ int exofs_write_begin(struct file *file, struct address_space *mapping,
if (ret) {
/*SetPageError was done by _readpage. Is it ok?*/
unlock_page(page);
- EXOFS_DBGMSG("__readpage_filler faild\n");
+ EXOFS_DBGMSG("__readpage_filler failed\n");
}
}
out:
@@ -1036,6 +1030,7 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
memcpy(oi->i_data, fcb.i_data, sizeof(fcb.i_data));
}
+ inode->i_mapping->backing_dev_info = sb->s_bdi;
if (S_ISREG(inode->i_mode)) {
inode->i_op = &exofs_file_inode_operations;
inode->i_fop = &exofs_file_operations;
@@ -1072,8 +1067,10 @@ bad_inode:
int __exofs_wait_obj_created(struct exofs_i_info *oi)
{
if (!obj_created(oi)) {
+ EXOFS_DBGMSG("!obj_created\n");
BUG_ON(!obj_2bcreated(oi));
wait_event(oi->i_wq, obj_created(oi));
+ EXOFS_DBGMSG("wait_event done\n");
}
return unlikely(is_bad_inode(&oi->vfs_inode)) ? -EIO : 0;
}
@@ -1095,7 +1092,7 @@ static void create_done(struct exofs_io_state *ios, void *p)
atomic_dec(&sbi->s_curr_pending);
if (unlikely(ret)) {
- EXOFS_ERR("object=0x%llx creation faild in pid=0x%llx",
+ EXOFS_ERR("object=0x%llx creation failed in pid=0x%llx",
_LLU(exofs_oi_objno(oi)), _LLU(sbi->layout.s_pid));
/*TODO: When FS is corrupted creation can fail, object already
* exist. Get rid of this asynchronous creation, if exist
@@ -1107,7 +1104,6 @@ static void create_done(struct exofs_io_state *ios, void *p)
set_obj_created(oi);
- atomic_dec(&inode->i_count);
wake_up(&oi->i_wq);
}
@@ -1135,6 +1131,7 @@ struct inode *exofs_new_inode(struct inode *dir, int mode)
sbi = sb->s_fs_info;
+ inode->i_mapping->backing_dev_info = sb->s_bdi;
sb->s_dirt = 1;
inode_init_owner(inode, dir, mode);
inode->i_ino = sbi->s_nextid++;
@@ -1157,17 +1154,11 @@ struct inode *exofs_new_inode(struct inode *dir, int mode)
ios->obj.id = exofs_oi_objno(oi);
exofs_make_credential(oi->i_cred, &ios->obj);
- /* increment the refcount so that the inode will still be around when we
- * reach the callback
- */
- atomic_inc(&inode->i_count);
-
ios->done = create_done;
ios->private = inode;
ios->cred = oi->i_cred;
ret = exofs_sbi_create(ios);
if (ret) {
- atomic_dec(&inode->i_count);
exofs_put_io_state(ios);
return ERR_PTR(ret);
}
@@ -1215,7 +1206,7 @@ static int exofs_update_inode(struct inode *inode, int do_sync)
args = kzalloc(sizeof(*args), GFP_KERNEL);
if (!args) {
- EXOFS_DBGMSG("Faild kzalloc of args\n");
+ EXOFS_DBGMSG("Failed kzalloc of args\n");
return -ENOMEM;
}
@@ -1257,12 +1248,7 @@ static int exofs_update_inode(struct inode *inode, int do_sync)
ios->out_attr_len = 1;
ios->out_attr = &attr;
- if (!obj_created(oi)) {
- EXOFS_DBGMSG("!obj_created\n");
- BUG_ON(!obj_2bcreated(oi));
- wait_event(oi->i_wq, obj_created(oi));
- EXOFS_DBGMSG("wait_event done\n");
- }
+ wait_obj_created(oi);
if (!do_sync) {
args->sbi = sbi;
@@ -1325,12 +1311,12 @@ void exofs_evict_inode(struct inode *inode)
inode->i_size = 0;
end_writeback(inode);
- /* if we are deleting an obj that hasn't been created yet, wait */
- if (!obj_created(oi)) {
- BUG_ON(!obj_2bcreated(oi));
- wait_event(oi->i_wq, obj_created(oi));
- /* ignore the error attempt a remove anyway */
- }
+ /* if we are deleting an obj that hasn't been created yet, wait.
+ * This also makes sure that create_done cannot be called with an
+ * already evicted inode.
+ */
+ wait_obj_created(oi);
+ /* ignore the error, attempt a remove anyway */
/* Now Remove the OSD objects */
ret = exofs_get_io_state(&sbi->layout, &ios);
diff --git a/fs/exofs/ios.c b/fs/exofs/ios.c
index 6550bf70e41d..f74a2ec027a6 100644
--- a/fs/exofs/ios.c
+++ b/fs/exofs/ios.c
@@ -55,7 +55,7 @@ int exofs_read_kern(struct osd_dev *od, u8 *cred, struct osd_obj_id *obj,
ret = osd_finalize_request(or, 0, cred, NULL);
if (unlikely(ret)) {
- EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", ret);
+ EXOFS_DBGMSG("Failed to osd_finalize_request() => %d\n", ret);
goto out;
}
@@ -79,7 +79,7 @@ int exofs_get_io_state(struct exofs_layout *layout,
*/
ios = kzalloc(exofs_io_state_size(layout->s_numdevs), GFP_KERNEL);
if (unlikely(!ios)) {
- EXOFS_DBGMSG("Faild kzalloc bytes=%d\n",
+ EXOFS_DBGMSG("Failed kzalloc bytes=%d\n",
exofs_io_state_size(layout->s_numdevs));
*pios = NULL;
return -ENOMEM;
@@ -172,7 +172,7 @@ static int exofs_io_execute(struct exofs_io_state *ios)
ret = osd_finalize_request(or, 0, ios->cred, NULL);
if (unlikely(ret)) {
- EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n",
+ EXOFS_DBGMSG("Failed to osd_finalize_request() => %d\n",
ret);
return ret;
}
@@ -361,7 +361,7 @@ static int _add_stripe_unit(struct exofs_io_state *ios, unsigned *cur_pg,
per_dev->bio = bio_kmalloc(GFP_KERNEL, bio_size);
if (unlikely(!per_dev->bio)) {
- EXOFS_DBGMSG("Faild to allocate BIO size=%u\n",
+ EXOFS_DBGMSG("Failed to allocate BIO size=%u\n",
bio_size);
return -ENOMEM;
}
@@ -564,7 +564,7 @@ static int _sbi_write_mirror(struct exofs_io_state *ios, int cur_comp)
master_dev->bio->bi_max_vecs);
if (unlikely(!bio)) {
EXOFS_DBGMSG(
- "Faild to allocate BIO size=%u\n",
+ "Failed to allocate BIO size=%u\n",
master_dev->bio->bi_max_vecs);
ret = -ENOMEM;
goto out;
diff --git a/fs/exofs/namei.c b/fs/exofs/namei.c
index b7dd0c236863..264e95d02830 100644
--- a/fs/exofs/namei.c
+++ b/fs/exofs/namei.c
@@ -153,7 +153,7 @@ static int exofs_link(struct dentry *old_dentry, struct inode *dir,
inode->i_ctime = CURRENT_TIME;
inode_inc_link_count(inode);
- atomic_inc(&inode->i_count);
+ ihold(inode);
return exofs_add_nondir(dentry, inode);
}
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index e9e175949a63..51b304056f10 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -74,21 +74,20 @@ static struct dentry *
find_disconnected_root(struct dentry *dentry)
{
dget(dentry);
- spin_lock(&dentry->d_lock);
- while (!IS_ROOT(dentry) &&
- (dentry->d_parent->d_flags & DCACHE_DISCONNECTED)) {
- struct dentry *parent = dentry->d_parent;
- dget(parent);
- spin_unlock(&dentry->d_lock);
+ while (!IS_ROOT(dentry)) {
+ struct dentry *parent = dget_parent(dentry);
+
+ if (!(parent->d_flags & DCACHE_DISCONNECTED)) {
+ dput(parent);
+ break;
+ }
+
dput(dentry);
dentry = parent;
- spin_lock(&dentry->d_lock);
}
- spin_unlock(&dentry->d_lock);
return dentry;
}
-
/*
* Make sure target_dir is fully connected to the dentry tree.
*
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index c6c684b44ea1..0d06f4e75699 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -646,10 +646,9 @@ find_next_usable_block(int start, struct buffer_head *bh, int maxblocks)
return here;
}
-/*
+/**
* ext2_try_to_allocate()
* @sb: superblock
- * @handle: handle to this transaction
* @group: given allocation block group
* @bitmap_bh: bufferhead holds the block bitmap
* @grp_goal: given target block within the group
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 764109886ec0..2709b34206ab 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -98,7 +98,7 @@ static int ext2_commit_chunk(struct page *page, loff_t pos, unsigned len)
if (IS_DIRSYNC(dir)) {
err = write_one_page(page, 1);
if (!err)
- err = ext2_sync_inode(dir);
+ err = sync_inode_metadata(dir, 1);
} else {
unlock_page(page);
}
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 416daa62242c..6346a2acf326 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -120,7 +120,6 @@ extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
extern struct inode *ext2_iget (struct super_block *, unsigned long);
extern int ext2_write_inode (struct inode *, struct writeback_control *);
extern void ext2_evict_inode(struct inode *);
-extern int ext2_sync_inode (struct inode *);
extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
extern int ext2_setattr (struct dentry *, struct iattr *);
extern void ext2_set_inode_flags(struct inode *inode);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 940c96168868..40ad210a5049 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -458,7 +458,7 @@ failed_out:
* the same format as ext2_get_branch() would do. We are calling it after
* we had read the existing part of chain and partial points to the last
* triple of that (one with zero ->key). Upon the exit we have the same
- * picture as after the successful ext2_get_block(), excpet that in one
+ * picture as after the successful ext2_get_block(), except that in one
* place chain is disconnected - *branch->p is still zero (we did not
* set the last link), but branch->key contains the number that should
* be placed into *branch->p to fill that gap.
@@ -662,7 +662,7 @@ static int ext2_get_blocks(struct inode *inode,
mutex_lock(&ei->truncate_mutex);
/*
* If the indirect block is missing while we are reading
- * the chain(ext3_get_branch() returns -EAGAIN err), or
+ * the chain(ext2_get_branch() returns -EAGAIN err), or
* if the chain has been changed after we grab the semaphore,
* (either because another process truncated this branch, or
* another get_block allocated this branch) re-grab the chain to see if
@@ -1203,7 +1203,7 @@ static int ext2_setsize(struct inode *inode, loff_t newsize)
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
if (inode_needs_sync(inode)) {
sync_mapping_buffers(inode->i_mapping);
- ext2_sync_inode (inode);
+ sync_inode_metadata(inode, 1);
} else {
mark_inode_dirty(inode);
}
@@ -1523,15 +1523,6 @@ int ext2_write_inode(struct inode *inode, struct writeback_control *wbc)
return __ext2_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
}
-int ext2_sync_inode(struct inode *inode)
-{
- struct writeback_control wbc = {
- .sync_mode = WB_SYNC_ALL,
- .nr_to_write = 0, /* sys_fsync did this */
- };
- return sync_inode(inode, &wbc);
-}
-
int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
{
struct inode *inode = dentry->d_inode;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 71efb0e9a3f2..f8aecd2e3297 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -206,7 +206,7 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir,
inode->i_ctime = CURRENT_TIME_SEC;
inode_inc_link_count(inode);
- atomic_inc(&inode->i_count);
+ ihold(inode);
err = ext2_add_link(dentry, inode);
if (!err) {
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 85df87d0f7b7..0901320671da 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -1221,9 +1221,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
}
es = sbi->s_es;
- if (((sbi->s_mount_opt & EXT2_MOUNT_XIP) !=
- (old_mount_opt & EXT2_MOUNT_XIP)) &&
- invalidate_inodes(sb)) {
+ if ((sbi->s_mount_opt ^ old_mount_opt) & EXT2_MOUNT_XIP) {
ext2_msg(sb, KERN_WARNING, "warning: refusing change of "
"xip flag with busy inodes while remounting");
sbi->s_mount_opt &= ~EXT2_MOUNT_XIP;
diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c
index 8c29ae15129e..f84700be3274 100644
--- a/fs/ext2/xattr.c
+++ b/fs/ext2/xattr.c
@@ -699,7 +699,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
EXT2_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0;
inode->i_ctime = CURRENT_TIME_SEC;
if (IS_SYNC(inode)) {
- error = ext2_sync_inode (inode);
+ error = sync_inode_metadata(inode, 1);
/* In case sync failed due to ENOSPC the inode was actually
* written (only some dirty data were not) so we just proceed
* as if nothing happened and cleanup the unused block */
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index 4a32511f4ded..b3db22649426 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -792,9 +792,9 @@ find_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh,
if (here < 0)
here = 0;
- p = ((char *)bh->b_data) + (here >> 3);
+ p = bh->b_data + (here >> 3);
r = memscan(p, 0, ((maxblocks + 7) >> 3) - (here >> 3));
- next = (r - ((char *)bh->b_data)) << 3;
+ next = (r - bh->b_data) << 3;
if (next < maxblocks && next >= start && ext3_test_allocatable(next, bh))
return next;
@@ -810,8 +810,9 @@ find_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh,
/**
* claim_block()
+ * @lock: the spin lock for this block group
* @block: the free block (group relative) to allocate
- * @bh: the bufferhead containts the block group bitmap
+ * @bh: the buffer_head contains the block group bitmap
*
* We think we can allocate this block in this bitmap. Try to set the bit.
* If that succeeds then check that nobody has allocated and then freed the
@@ -956,9 +957,11 @@ fail_access:
* but we will shift to the place where start_block is,
* then start from there, when looking for a reservable space.
*
- * @size: the target new reservation window size
+ * @my_rsv: the reservation window
*
- * @group_first_block: the first block we consider to start
+ * @sb: the super block
+ *
+ * @start_block: the first block we consider to start
* the real search from
*
* @last_block:
@@ -1084,7 +1087,7 @@ static int find_next_reservable_window(
*
* failed: we failed to find a reservation window in this group
*
- * @rsv: the reservation
+ * @my_rsv: the reservation window
*
* @grp_goal: The goal (group-relative). It is where the search for a
* free reservable space should start from.
@@ -1273,8 +1276,8 @@ static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv,
* @group: given allocation block group
* @bitmap_bh: bufferhead holds the block bitmap
* @grp_goal: given target block within the group
- * @count: target number of blocks to allocate
* @my_rsv: reservation window
+ * @count: target number of blocks to allocate
* @errp: pointer to store the error code
*
* This is the main function used to allocate a new block and its reservation
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index 4ab72db3559e..9724aef22460 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -570,9 +570,14 @@ got:
ei->i_state_flags = 0;
ext3_set_inode_state(inode, EXT3_STATE_NEW);
- ei->i_extra_isize =
- (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) ?
- sizeof(struct ext3_inode) - EXT3_GOOD_OLD_INODE_SIZE : 0;
+ /* See comment in ext3_iget for explanation */
+ if (ino >= EXT3_FIRST_INO(sb) + 1 &&
+ EXT3_INODE_SIZE(sb) > EXT3_GOOD_OLD_INODE_SIZE) {
+ ei->i_extra_isize =
+ sizeof(struct ext3_inode) - EXT3_GOOD_OLD_INODE_SIZE;
+ } else {
+ ei->i_extra_isize = 0;
+ }
ret = inode;
dquot_initialize(inode);
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 5e0faf4cda79..a9580617edd2 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -498,7 +498,7 @@ static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block,
}
/**
- * ext3_blks_to_allocate: Look up the block map and count the number
+ * ext3_blks_to_allocate - Look up the block map and count the number
* of direct blocks need to be allocated for the given branch.
*
* @branch: chain of indirect blocks
@@ -536,14 +536,18 @@ static int ext3_blks_to_allocate(Indirect *branch, int k, unsigned long blks,
}
/**
- * ext3_alloc_blocks: multiple allocate blocks needed for a branch
+ * ext3_alloc_blocks - multiple allocate blocks needed for a branch
+ * @handle: handle for this transaction
+ * @inode: owner
+ * @goal: preferred place for allocation
* @indirect_blks: the number of blocks need to allocate for indirect
* blocks
- *
+ * @blks: number of blocks need to allocated for direct blocks
* @new_blocks: on return it will store the new block numbers for
* the indirect blocks(if needed) and the first direct block,
- * @blks: on return it will store the total number of allocated
- * direct blocks
+ * @err: here we store the error value
+ *
+ * return the number of direct blocks allocated
*/
static int ext3_alloc_blocks(handle_t *handle, struct inode *inode,
ext3_fsblk_t goal, int indirect_blks, int blks,
@@ -598,9 +602,11 @@ failed_out:
/**
* ext3_alloc_branch - allocate and set up a chain of blocks.
+ * @handle: handle for this transaction
* @inode: owner
* @indirect_blks: number of allocated indirect blocks
* @blks: number of allocated direct blocks
+ * @goal: preferred place for allocation
* @offsets: offsets (in the blocks) to store the pointers to next.
* @branch: place to store the chain in.
*
@@ -700,10 +706,9 @@ failed:
/**
* ext3_splice_branch - splice the allocated branch onto inode.
+ * @handle: handle for this transaction
* @inode: owner
* @block: (logical) number of block we are adding
- * @chain: chain of indirect blocks (with a missing link - see
- * ext3_alloc_branch)
* @where: location of missing link
* @num: number of indirect blocks we are adding
* @blks: number of direct blocks we are adding
@@ -1696,8 +1701,8 @@ static int ext3_journalled_writepage(struct page *page,
* doesn't seem much point in redirtying the page here.
*/
ClearPageChecked(page);
- ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
- ext3_get_block);
+ ret = __block_write_begin(page, 0, PAGE_CACHE_SIZE,
+ ext3_get_block);
if (ret != 0) {
ext3_journal_stop(handle);
goto out_unlock;
@@ -2530,7 +2535,6 @@ void ext3_truncate(struct inode *inode)
*/
} else {
/* Shared branch grows from an indirect block */
- BUFFER_TRACE(partial->bh, "get_write_access");
ext3_free_branches(handle, inode, partial->bh,
partial->p,
partial->p+1, (chain+n-1) - partial);
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 2b35ddb70d65..bce9dce639b8 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -2260,7 +2260,7 @@ retry:
inode->i_ctime = CURRENT_TIME_SEC;
inc_nlink(inode);
- atomic_inc(&inode->i_count);
+ ihold(inode);
err = ext3_add_entry(handle, dentry, inode);
if (!err) {
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c
index 0ccd7b12b73c..e746d30b1232 100644
--- a/fs/ext3/resize.c
+++ b/fs/ext3/resize.c
@@ -977,7 +977,8 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
o_blocks_count = le32_to_cpu(es->s_blocks_count);
if (test_opt(sb, DEBUG))
- printk(KERN_DEBUG "EXT3-fs: extending last group from "E3FSBLK" uto "E3FSBLK" blocks\n",
+ printk(KERN_DEBUG "EXT3-fs: extending last group from "E3FSBLK
+ " upto "E3FSBLK" blocks\n",
o_blocks_count, n_blocks_count);
if (n_blocks_count == 0 || n_blocks_count == o_blocks_count)
@@ -985,7 +986,7 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
printk(KERN_ERR "EXT3-fs: filesystem on %s:"
- " too large to resize to %lu blocks safely\n",
+ " too large to resize to "E3FSBLK" blocks safely\n",
sb->s_id, n_blocks_count);
if (sizeof(sector_t) < 8)
ext3_warning(sb, __func__,
@@ -1065,11 +1066,11 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
es->s_blocks_count = cpu_to_le32(o_blocks_count + add);
ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);
mutex_unlock(&EXT3_SB(sb)->s_resize_lock);
- ext3_debug("freeing blocks %lu through "E3FSBLK"\n", o_blocks_count,
- o_blocks_count + add);
+ ext3_debug("freeing blocks "E3FSBLK" through "E3FSBLK"\n",
+ o_blocks_count, o_blocks_count + add);
ext3_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks);
- ext3_debug("freed blocks "E3FSBLK" through "E3FSBLK"\n", o_blocks_count,
- o_blocks_count + add);
+ ext3_debug("freed blocks "E3FSBLK" through "E3FSBLK"\n",
+ o_blocks_count, o_blocks_count + add);
if ((err = ext3_journal_stop(handle)))
goto exit_put;
if (test_opt(sb, DEBUG))
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 377768009106..db87413d3479 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -1301,9 +1301,9 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
ext3_msg(sb, KERN_WARNING,
"warning: mounting fs with errors, "
"running e2fsck is recommended");
- else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 &&
+ else if ((__s16) le16_to_cpu(es->s_max_mnt_count) > 0 &&
le16_to_cpu(es->s_mnt_count) >=
- (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count))
+ le16_to_cpu(es->s_max_mnt_count))
ext3_msg(sb, KERN_WARNING,
"warning: maximal mount count reached, "
"running e2fsck is recommended");
@@ -1320,7 +1320,7 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
valid forever! :) */
es->s_state &= cpu_to_le16(~EXT3_VALID_FS);
#endif
- if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
+ if (!le16_to_cpu(es->s_max_mnt_count))
es->s_max_mnt_count = cpu_to_le16(EXT3_DFL_MAX_MNT_COUNT);
le16_add_cpu(&es->s_mnt_count, 1);
es->s_mtime = cpu_to_le32(get_seconds());
@@ -1647,7 +1647,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
* Note: s_es must be initialized as soon as possible because
* some ext3 macro-instructions depend on its value
*/
- es = (struct ext3_super_block *) (((char *)bh->b_data) + offset);
+ es = (struct ext3_super_block *) (bh->b_data + offset);
sbi->s_es = es;
sb->s_magic = le16_to_cpu(es->s_magic);
if (sb->s_magic != EXT3_SUPER_MAGIC)
@@ -1758,7 +1758,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
"error: can't read superblock on 2nd try");
goto failed_mount;
}
- es = (struct ext3_super_block *)(((char *)bh->b_data) + offset);
+ es = (struct ext3_super_block *)(bh->b_data + offset);
sbi->s_es = es;
if (es->s_magic != cpu_to_le16(EXT3_SUPER_MAGIC)) {
ext3_msg(sb, KERN_ERR,
@@ -1857,13 +1857,13 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) -
le32_to_cpu(es->s_first_data_block) - 1)
/ EXT3_BLOCKS_PER_GROUP(sb)) + 1;
- db_count = (sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) /
- EXT3_DESC_PER_BLOCK(sb);
+ db_count = DIV_ROUND_UP(sbi->s_groups_count, EXT3_DESC_PER_BLOCK(sb));
sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *),
GFP_KERNEL);
if (sbi->s_group_desc == NULL) {
ext3_msg(sb, KERN_ERR,
"error: not enough memory");
+ ret = -ENOMEM;
goto failed_mount;
}
@@ -1951,6 +1951,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
}
if (err) {
ext3_msg(sb, KERN_ERR, "error: insufficient memory");
+ ret = err;
goto failed_mount3;
}
@@ -2159,7 +2160,7 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb,
goto out_bdev;
}
- es = (struct ext3_super_block *) (((char *)bh->b_data) + offset);
+ es = (struct ext3_super_block *) (bh->b_data + offset);
if ((le16_to_cpu(es->s_magic) != EXT3_SUPER_MAGIC) ||
!(le32_to_cpu(es->s_feature_incompat) &
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
@@ -2352,6 +2353,21 @@ static int ext3_commit_super(struct super_block *sb,
if (!sbh)
return error;
+
+ if (buffer_write_io_error(sbh)) {
+ /*
+ * Oh, dear. A previous attempt to write the
+ * superblock failed. This could happen because the
+ * USB device was yanked out. Or it could happen to
+ * be a transient write error and maybe the block will
+ * be remapped. Nothing we can do but to retry the
+ * write and hope for the best.
+ */
+ ext3_msg(sb, KERN_ERR, "previous I/O error to "
+ "superblock detected");
+ clear_buffer_write_io_error(sbh);
+ set_buffer_uptodate(sbh);
+ }
/*
* If the file system is mounted read-only, don't update the
* superblock write time. This avoids updating the superblock
@@ -2368,8 +2384,15 @@ static int ext3_commit_super(struct super_block *sb,
es->s_free_inodes_count = cpu_to_le32(ext3_count_free_inodes(sb));
BUFFER_TRACE(sbh, "marking dirty");
mark_buffer_dirty(sbh);
- if (sync)
+ if (sync) {
error = sync_dirty_buffer(sbh);
+ if (buffer_write_io_error(sbh)) {
+ ext3_msg(sb, KERN_ERR, "I/O error while writing "
+ "superblock");
+ clear_buffer_write_io_error(sbh);
+ set_buffer_uptodate(sbh);
+ }
+ }
return error;
}
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index 8867b2a1e5fe..c947e36eda6c 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -4,7 +4,7 @@
obj-$(CONFIG_EXT4_FS) += ext4.o
-ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
+ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \
ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \
ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index bd30799a43ed..14c3af26c671 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -171,7 +171,8 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
* less than the blocksize * 8 ( which is the size
* of bitmap ), set rest of the block bitmap to 1
*/
- mark_bitmap_end(group_blocks, sb->s_blocksize * 8, bh->b_data);
+ ext4_mark_bitmap_end(group_blocks, sb->s_blocksize * 8,
+ bh->b_data);
}
return free_blocks - ext4_group_used_meta_blocks(sb, block_group, gdp);
}
@@ -489,7 +490,7 @@ error_return:
* Check if filesystem has nblocks free & available for allocation.
* On success return 1, return 0 on failure.
*/
-int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks)
+static int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks)
{
s64 free_blocks, dirty_blocks, root_blocks;
struct percpu_counter *fbc = &sbi->s_freeblocks_counter;
diff --git a/fs/ext4/block_validity.c b/fs/ext4/block_validity.c
index 3db5084db9bd..fac90f3fba80 100644
--- a/fs/ext4/block_validity.c
+++ b/fs/ext4/block_validity.c
@@ -29,16 +29,15 @@ struct ext4_system_zone {
static struct kmem_cache *ext4_system_zone_cachep;
-int __init init_ext4_system_zone(void)
+int __init ext4_init_system_zone(void)
{
- ext4_system_zone_cachep = KMEM_CACHE(ext4_system_zone,
- SLAB_RECLAIM_ACCOUNT);
+ ext4_system_zone_cachep = KMEM_CACHE(ext4_system_zone, 0);
if (ext4_system_zone_cachep == NULL)
return -ENOMEM;
return 0;
}
-void exit_ext4_system_zone(void)
+void ext4_exit_system_zone(void)
{
kmem_cache_destroy(ext4_system_zone_cachep);
}
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index 374510f72baa..ece76fb6a40c 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -39,7 +39,7 @@ static int ext4_release_dir(struct inode *inode,
struct file *filp);
const struct file_operations ext4_dir_operations = {
- .llseek = generic_file_llseek,
+ .llseek = ext4_llseek,
.read = generic_read_dir,
.readdir = ext4_readdir, /* we take BKL. needed?*/
.unlocked_ioctl = ext4_ioctl,
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 889ec9d5e6ad..8b5dd6369f82 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -168,7 +168,20 @@ struct mpage_da_data {
int pages_written;
int retval;
};
-#define EXT4_IO_UNWRITTEN 0x1
+
+/*
+ * Flags for ext4_io_end->flags
+ */
+#define EXT4_IO_END_UNWRITTEN 0x0001
+#define EXT4_IO_END_ERROR 0x0002
+
+struct ext4_io_page {
+ struct page *p_page;
+ int p_count;
+};
+
+#define MAX_IO_PAGES 128
+
typedef struct ext4_io_end {
struct list_head list; /* per-file finished IO list */
struct inode *inode; /* file being written to */
@@ -179,8 +192,18 @@ typedef struct ext4_io_end {
struct work_struct work; /* data work queue */
struct kiocb *iocb; /* iocb struct for AIO */
int result; /* error value for AIO */
+ int num_io_pages;
+ struct ext4_io_page *pages[MAX_IO_PAGES];
} ext4_io_end_t;
+struct ext4_io_submit {
+ int io_op;
+ struct bio *io_bio;
+ ext4_io_end_t *io_end;
+ struct ext4_io_page *io_page;
+ sector_t io_next_block;
+};
+
/*
* Special inodes numbers
*/
@@ -205,6 +228,7 @@ typedef struct ext4_io_end {
#define EXT4_MIN_BLOCK_SIZE 1024
#define EXT4_MAX_BLOCK_SIZE 65536
#define EXT4_MIN_BLOCK_LOG_SIZE 10
+#define EXT4_MAX_BLOCK_LOG_SIZE 16
#ifdef __KERNEL__
# define EXT4_BLOCK_SIZE(s) ((s)->s_blocksize)
#else
@@ -889,6 +913,7 @@ struct ext4_inode_info {
#define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */
#define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */
#define EXT4_MOUNT_DISCARD 0x40000000 /* Issue DISCARD requests */
+#define EXT4_MOUNT_INIT_INODE_TABLE 0x80000000 /* Initialize uninitialized itables */
#define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt
#define set_opt(o, opt) o |= EXT4_MOUNT_##opt
@@ -1087,7 +1112,6 @@ struct ext4_sb_info {
struct completion s_kobj_unregister;
/* Journaling */
- struct inode *s_journal_inode;
struct journal_s *s_journal;
struct list_head s_orphan;
struct mutex s_orphan_lock;
@@ -1120,10 +1144,7 @@ struct ext4_sb_info {
/* for buddy allocator */
struct ext4_group_info ***s_group_info;
struct inode *s_buddy_cache;
- long s_blocks_reserved;
- spinlock_t s_reserve_lock;
spinlock_t s_md_lock;
- tid_t s_last_transaction;
unsigned short *s_mb_offsets;
unsigned int *s_mb_maxs;
@@ -1141,7 +1162,6 @@ struct ext4_sb_info {
unsigned long s_mb_last_start;
/* stats for buddy allocator */
- spinlock_t s_mb_pa_lock;
atomic_t s_bal_reqs; /* number of reqs with len > 1 */
atomic_t s_bal_success; /* we found long enough chunks */
atomic_t s_bal_allocated; /* in blocks */
@@ -1172,6 +1192,11 @@ struct ext4_sb_info {
/* timer for periodic error stats printing */
struct timer_list s_err_report;
+
+ /* Lazy inode table initialization info */
+ struct ext4_li_request *s_li_request;
+ /* Wait multiplier for lazy initialization thread */
+ unsigned int s_li_wait_mult;
};
static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
@@ -1533,7 +1558,42 @@ ext4_group_first_block_no(struct super_block *sb, ext4_group_t group_no)
void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
ext4_group_t *blockgrpp, ext4_grpblk_t *offsetp);
-extern struct proc_dir_entry *ext4_proc_root;
+/*
+ * Timeout and state flag for lazy initialization inode thread.
+ */
+#define EXT4_DEF_LI_WAIT_MULT 10
+#define EXT4_DEF_LI_MAX_START_DELAY 5
+#define EXT4_LAZYINIT_QUIT 0x0001
+#define EXT4_LAZYINIT_RUNNING 0x0002
+
+/*
+ * Lazy inode table initialization info
+ */
+struct ext4_lazy_init {
+ unsigned long li_state;
+
+ wait_queue_head_t li_wait_daemon;
+ wait_queue_head_t li_wait_task;
+ struct timer_list li_timer;
+ struct task_struct *li_task;
+
+ struct list_head li_request_list;
+ struct mutex li_list_mtx;
+};
+
+struct ext4_li_request {
+ struct super_block *lr_super;
+ struct ext4_sb_info *lr_sbi;
+ ext4_group_t lr_next_group;
+ struct list_head lr_request;
+ unsigned long lr_next_sched;
+ unsigned long lr_timeout;
+};
+
+struct ext4_features {
+ struct kobject f_kobj;
+ struct completion f_kobj_unregister;
+};
/*
* Function prototypes
@@ -1561,7 +1621,6 @@ extern unsigned long ext4_bg_num_gdb(struct super_block *sb,
extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
ext4_fsblk_t goal, unsigned long *count, int *errp);
extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks);
-extern int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks);
extern void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
ext4_fsblk_t block, unsigned long count);
extern ext4_fsblk_t ext4_count_free_blocks(struct super_block *);
@@ -1605,11 +1664,9 @@ extern struct inode * ext4_orphan_get(struct super_block *, unsigned long);
extern unsigned long ext4_count_free_inodes(struct super_block *);
extern unsigned long ext4_count_dirs(struct super_block *);
extern void ext4_check_inodes_bitmap(struct super_block *);
-extern unsigned ext4_init_inode_bitmap(struct super_block *sb,
- struct buffer_head *bh,
- ext4_group_t group,
- struct ext4_group_desc *desc);
-extern void mark_bitmap_end(int start_bit, int end_bit, char *bitmap);
+extern void ext4_mark_bitmap_end(int start_bit, int end_bit, char *bitmap);
+extern int ext4_init_inode_table(struct super_block *sb,
+ ext4_group_t group, int barrier);
/* mballoc.c */
extern long ext4_mb_stats;
@@ -1620,16 +1677,15 @@ extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *,
struct ext4_allocation_request *, int *);
extern int ext4_mb_reserve_blocks(struct super_block *, int);
extern void ext4_discard_preallocations(struct inode *);
-extern int __init init_ext4_mballoc(void);
-extern void exit_ext4_mballoc(void);
+extern int __init ext4_init_mballoc(void);
+extern void ext4_exit_mballoc(void);
extern void ext4_free_blocks(handle_t *handle, struct inode *inode,
struct buffer_head *bh, ext4_fsblk_t block,
unsigned long count, int flags);
extern int ext4_mb_add_groupinfo(struct super_block *sb,
ext4_group_t i, struct ext4_group_desc *desc);
-extern int ext4_mb_get_buddy_cache_lock(struct super_block *, ext4_group_t);
-extern void ext4_mb_put_buddy_cache_lock(struct super_block *,
- ext4_group_t, int);
+extern int ext4_trim_fs(struct super_block *, struct fstrim_range *);
+
/* inode.c */
struct buffer_head *ext4_getblk(handle_t *, struct inode *,
ext4_lblk_t, int, int *);
@@ -1657,13 +1713,11 @@ extern void ext4_get_inode_flags(struct ext4_inode_info *);
extern int ext4_alloc_da_blocks(struct inode *inode);
extern void ext4_set_aops(struct inode *inode);
extern int ext4_writepage_trans_blocks(struct inode *);
-extern int ext4_meta_trans_blocks(struct inode *, int nrblocks, int idxblocks);
extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks);
extern int ext4_block_truncate_page(handle_t *handle,
struct address_space *mapping, loff_t from);
extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
extern qsize_t *ext4_get_reserved_space(struct inode *inode);
-extern int flush_completed_IO(struct inode *inode);
extern void ext4_da_update_reserve_space(struct inode *inode,
int used, int quota_claim);
/* ioctl.c */
@@ -1960,6 +2014,7 @@ extern const struct file_operations ext4_dir_operations;
/* file.c */
extern const struct inode_operations ext4_file_inode_operations;
extern const struct file_operations ext4_file_operations;
+extern loff_t ext4_llseek(struct file *file, loff_t offset, int origin);
/* namei.c */
extern const struct inode_operations ext4_dir_inode_operations;
@@ -1973,8 +2028,8 @@ extern const struct inode_operations ext4_fast_symlink_inode_operations;
/* block_validity */
extern void ext4_release_system_zone(struct super_block *sb);
extern int ext4_setup_system_zone(struct super_block *sb);
-extern int __init init_ext4_system_zone(void);
-extern void exit_ext4_system_zone(void);
+extern int __init ext4_init_system_zone(void);
+extern void ext4_exit_system_zone(void);
extern int ext4_data_block_valid(struct ext4_sb_info *sbi,
ext4_fsblk_t start_blk,
unsigned int count);
@@ -2002,6 +2057,17 @@ extern int ext4_move_extents(struct file *o_filp, struct file *d_filp,
__u64 start_orig, __u64 start_donor,
__u64 len, __u64 *moved_len);
+/* page-io.c */
+extern int __init ext4_init_pageio(void);
+extern void ext4_exit_pageio(void);
+extern void ext4_free_io_end(ext4_io_end_t *io);
+extern ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags);
+extern int ext4_end_io_nolock(ext4_io_end_t *io);
+extern void ext4_io_submit(struct ext4_io_submit *io);
+extern int ext4_bio_write_page(struct ext4_io_submit *io,
+ struct page *page,
+ int len,
+ struct writeback_control *wbc);
/* BH_Uninit flag: blocks are allocated but uninitialized on disk */
enum ext4_state_bits {
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h
index bdb6ce7e2eb4..28ce70fd9cd0 100644
--- a/fs/ext4/ext4_extents.h
+++ b/fs/ext4/ext4_extents.h
@@ -225,11 +225,60 @@ static inline void ext4_ext_mark_initialized(struct ext4_extent *ext)
ext->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ext));
}
+/*
+ * ext4_ext_pblock:
+ * combine low and high parts of physical block number into ext4_fsblk_t
+ */
+static inline ext4_fsblk_t ext4_ext_pblock(struct ext4_extent *ex)
+{
+ ext4_fsblk_t block;
+
+ block = le32_to_cpu(ex->ee_start_lo);
+ block |= ((ext4_fsblk_t) le16_to_cpu(ex->ee_start_hi) << 31) << 1;
+ return block;
+}
+
+/*
+ * ext4_idx_pblock:
+ * combine low and high parts of a leaf physical block number into ext4_fsblk_t
+ */
+static inline ext4_fsblk_t ext4_idx_pblock(struct ext4_extent_idx *ix)
+{
+ ext4_fsblk_t block;
+
+ block = le32_to_cpu(ix->ei_leaf_lo);
+ block |= ((ext4_fsblk_t) le16_to_cpu(ix->ei_leaf_hi) << 31) << 1;
+ return block;
+}
+
+/*
+ * ext4_ext_store_pblock:
+ * stores a large physical block number into an extent struct,
+ * breaking it into parts
+ */
+static inline void ext4_ext_store_pblock(struct ext4_extent *ex,
+ ext4_fsblk_t pb)
+{
+ ex->ee_start_lo = cpu_to_le32((unsigned long) (pb & 0xffffffff));
+ ex->ee_start_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) &
+ 0xffff);
+}
+
+/*
+ * ext4_idx_store_pblock:
+ * stores a large physical block number into an index struct,
+ * breaking it into parts
+ */
+static inline void ext4_idx_store_pblock(struct ext4_extent_idx *ix,
+ ext4_fsblk_t pb)
+{
+ ix->ei_leaf_lo = cpu_to_le32((unsigned long) (pb & 0xffffffff));
+ ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) &
+ 0xffff);
+}
+
extern int ext4_ext_calc_metadata_amount(struct inode *inode,
sector_t lblocks);
-extern ext4_fsblk_t ext_pblock(struct ext4_extent *ex);
-extern ext4_fsblk_t idx_pblock(struct ext4_extent_idx *);
-extern void ext4_ext_store_pblock(struct ext4_extent *, ext4_fsblk_t);
extern int ext4_extent_tree_init(handle_t *, struct inode *);
extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode,
int num,
@@ -237,19 +286,9 @@ extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode,
extern int ext4_can_extents_be_merged(struct inode *inode,
struct ext4_extent *ex1,
struct ext4_extent *ex2);
-extern int ext4_ext_try_to_merge(struct inode *inode,
- struct ext4_ext_path *path,
- struct ext4_extent *);
-extern unsigned int ext4_ext_check_overlap(struct inode *, struct ext4_extent *, struct ext4_ext_path *);
extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *, int);
-extern int ext4_ext_walk_space(struct inode *, ext4_lblk_t, ext4_lblk_t,
- ext_prepare_callback, void *);
extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t,
struct ext4_ext_path *);
-extern int ext4_ext_search_left(struct inode *, struct ext4_ext_path *,
- ext4_lblk_t *, ext4_fsblk_t *);
-extern int ext4_ext_search_right(struct inode *, struct ext4_ext_path *,
- ext4_lblk_t *, ext4_fsblk_t *);
extern void ext4_ext_drop_refs(struct ext4_ext_path *);
extern int ext4_ext_check_inode(struct inode *inode);
#endif /* _EXT4_EXTENTS */
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 06328d3e5717..0554c48cb1fd 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -44,55 +44,6 @@
#include "ext4_jbd2.h"
#include "ext4_extents.h"
-
-/*
- * ext_pblock:
- * combine low and high parts of physical block number into ext4_fsblk_t
- */
-ext4_fsblk_t ext_pblock(struct ext4_extent *ex)
-{
- ext4_fsblk_t block;
-
- block = le32_to_cpu(ex->ee_start_lo);
- block |= ((ext4_fsblk_t) le16_to_cpu(ex->ee_start_hi) << 31) << 1;
- return block;
-}
-
-/*
- * idx_pblock:
- * combine low and high parts of a leaf physical block number into ext4_fsblk_t
- */
-ext4_fsblk_t idx_pblock(struct ext4_extent_idx *ix)
-{
- ext4_fsblk_t block;
-
- block = le32_to_cpu(ix->ei_leaf_lo);
- block |= ((ext4_fsblk_t) le16_to_cpu(ix->ei_leaf_hi) << 31) << 1;
- return block;
-}
-
-/*
- * ext4_ext_store_pblock:
- * stores a large physical block number into an extent struct,
- * breaking it into parts
- */
-void ext4_ext_store_pblock(struct ext4_extent *ex, ext4_fsblk_t pb)
-{
- ex->ee_start_lo = cpu_to_le32((unsigned long) (pb & 0xffffffff));
- ex->ee_start_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);
-}
-
-/*
- * ext4_idx_store_pblock:
- * stores a large physical block number into an index struct,
- * breaking it into parts
- */
-static void ext4_idx_store_pblock(struct ext4_extent_idx *ix, ext4_fsblk_t pb)
-{
- ix->ei_leaf_lo = cpu_to_le32((unsigned long) (pb & 0xffffffff));
- ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);
-}
-
static int ext4_ext_truncate_extend_restart(handle_t *handle,
struct inode *inode,
int needed)
@@ -169,7 +120,8 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
/* try to predict block placement */
ex = path[depth].p_ext;
if (ex)
- return ext_pblock(ex)+(block-le32_to_cpu(ex->ee_block));
+ return (ext4_ext_pblock(ex) +
+ (block - le32_to_cpu(ex->ee_block)));
/* it looks like index is empty;
* try to find starting block from index itself */
@@ -354,7 +306,7 @@ ext4_ext_max_entries(struct inode *inode, int depth)
static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext)
{
- ext4_fsblk_t block = ext_pblock(ext);
+ ext4_fsblk_t block = ext4_ext_pblock(ext);
int len = ext4_ext_get_actual_len(ext);
return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len);
@@ -363,7 +315,7 @@ static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext)
static int ext4_valid_extent_idx(struct inode *inode,
struct ext4_extent_idx *ext_idx)
{
- ext4_fsblk_t block = idx_pblock(ext_idx);
+ ext4_fsblk_t block = ext4_idx_pblock(ext_idx);
return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, 1);
}
@@ -463,13 +415,13 @@ static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
for (k = 0; k <= l; k++, path++) {
if (path->p_idx) {
ext_debug(" %d->%llu", le32_to_cpu(path->p_idx->ei_block),
- idx_pblock(path->p_idx));
+ ext4_idx_pblock(path->p_idx));
} else if (path->p_ext) {
ext_debug(" %d:[%d]%d:%llu ",
le32_to_cpu(path->p_ext->ee_block),
ext4_ext_is_uninitialized(path->p_ext),
ext4_ext_get_actual_len(path->p_ext),
- ext_pblock(path->p_ext));
+ ext4_ext_pblock(path->p_ext));
} else
ext_debug(" []");
}
@@ -494,7 +446,7 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path)
for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) {
ext_debug("%d:[%d]%d:%llu ", le32_to_cpu(ex->ee_block),
ext4_ext_is_uninitialized(ex),
- ext4_ext_get_actual_len(ex), ext_pblock(ex));
+ ext4_ext_get_actual_len(ex), ext4_ext_pblock(ex));
}
ext_debug("\n");
}
@@ -545,7 +497,7 @@ ext4_ext_binsearch_idx(struct inode *inode,
path->p_idx = l - 1;
ext_debug(" -> %d->%lld ", le32_to_cpu(path->p_idx->ei_block),
- idx_pblock(path->p_idx));
+ ext4_idx_pblock(path->p_idx));
#ifdef CHECK_BINSEARCH
{
@@ -614,7 +566,7 @@ ext4_ext_binsearch(struct inode *inode,
path->p_ext = l - 1;
ext_debug(" -> %d:%llu:[%d]%d ",
le32_to_cpu(path->p_ext->ee_block),
- ext_pblock(path->p_ext),
+ ext4_ext_pblock(path->p_ext),
ext4_ext_is_uninitialized(path->p_ext),
ext4_ext_get_actual_len(path->p_ext));
@@ -682,7 +634,7 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
ext4_ext_binsearch_idx(inode, path + ppos, block);
- path[ppos].p_block = idx_pblock(path[ppos].p_idx);
+ path[ppos].p_block = ext4_idx_pblock(path[ppos].p_idx);
path[ppos].p_depth = i;
path[ppos].p_ext = NULL;
@@ -721,7 +673,7 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
ext4_ext_binsearch(inode, path + ppos, block);
/* if not an empty leaf */
if (path[ppos].p_ext)
- path[ppos].p_block = ext_pblock(path[ppos].p_ext);
+ path[ppos].p_block = ext4_ext_pblock(path[ppos].p_ext);
ext4_ext_show_path(inode, path);
@@ -739,9 +691,9 @@ err:
* insert new index [@logical;@ptr] into the block at @curp;
* check where to insert: before @curp or after @curp
*/
-int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
- struct ext4_ext_path *curp,
- int logical, ext4_fsblk_t ptr)
+static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *curp,
+ int logical, ext4_fsblk_t ptr)
{
struct ext4_extent_idx *ix;
int len, err;
@@ -917,7 +869,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
EXT_MAX_EXTENT(path[depth].p_hdr)) {
ext_debug("move %d:%llu:[%d]%d in new leaf %llu\n",
le32_to_cpu(path[depth].p_ext->ee_block),
- ext_pblock(path[depth].p_ext),
+ ext4_ext_pblock(path[depth].p_ext),
ext4_ext_is_uninitialized(path[depth].p_ext),
ext4_ext_get_actual_len(path[depth].p_ext),
newblock);
@@ -1007,7 +959,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) {
ext_debug("%d: move %d:%llu in new index %llu\n", i,
le32_to_cpu(path[i].p_idx->ei_block),
- idx_pblock(path[i].p_idx),
+ ext4_idx_pblock(path[i].p_idx),
newblock);
/*memmove(++fidx, path[i].p_idx++,
sizeof(struct ext4_extent_idx));
@@ -1146,7 +1098,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
ext_debug("new root: num %d(%d), lblock %d, ptr %llu\n",
le16_to_cpu(neh->eh_entries), le16_to_cpu(neh->eh_max),
le32_to_cpu(EXT_FIRST_INDEX(neh)->ei_block),
- idx_pblock(EXT_FIRST_INDEX(neh)));
+ ext4_idx_pblock(EXT_FIRST_INDEX(neh)));
neh->eh_depth = cpu_to_le16(path->p_depth + 1);
err = ext4_ext_dirty(handle, inode, curp);
@@ -1232,9 +1184,9 @@ out:
* returns 0 at @phys
* return value contains 0 (success) or error code
*/
-int
-ext4_ext_search_left(struct inode *inode, struct ext4_ext_path *path,
- ext4_lblk_t *logical, ext4_fsblk_t *phys)
+static int ext4_ext_search_left(struct inode *inode,
+ struct ext4_ext_path *path,
+ ext4_lblk_t *logical, ext4_fsblk_t *phys)
{
struct ext4_extent_idx *ix;
struct ext4_extent *ex;
@@ -1286,7 +1238,7 @@ ext4_ext_search_left(struct inode *inode, struct ext4_ext_path *path,
}
*logical = le32_to_cpu(ex->ee_block) + ee_len - 1;
- *phys = ext_pblock(ex) + ee_len - 1;
+ *phys = ext4_ext_pblock(ex) + ee_len - 1;
return 0;
}
@@ -1297,9 +1249,9 @@ ext4_ext_search_left(struct inode *inode, struct ext4_ext_path *path,
* returns 0 at @phys
* return value contains 0 (success) or error code
*/
-int
-ext4_ext_search_right(struct inode *inode, struct ext4_ext_path *path,
- ext4_lblk_t *logical, ext4_fsblk_t *phys)
+static int ext4_ext_search_right(struct inode *inode,
+ struct ext4_ext_path *path,
+ ext4_lblk_t *logical, ext4_fsblk_t *phys)
{
struct buffer_head *bh = NULL;
struct ext4_extent_header *eh;
@@ -1342,7 +1294,7 @@ ext4_ext_search_right(struct inode *inode, struct ext4_ext_path *path,
}
}
*logical = le32_to_cpu(ex->ee_block);
- *phys = ext_pblock(ex);
+ *phys = ext4_ext_pblock(ex);
return 0;
}
@@ -1357,7 +1309,7 @@ ext4_ext_search_right(struct inode *inode, struct ext4_ext_path *path,
/* next allocated block in this leaf */
ex++;
*logical = le32_to_cpu(ex->ee_block);
- *phys = ext_pblock(ex);
+ *phys = ext4_ext_pblock(ex);
return 0;
}
@@ -1376,7 +1328,7 @@ got_index:
* follow it and find the closest allocated
* block to the right */
ix++;
- block = idx_pblock(ix);
+ block = ext4_idx_pblock(ix);
while (++depth < path->p_depth) {
bh = sb_bread(inode->i_sb, block);
if (bh == NULL)
@@ -1388,7 +1340,7 @@ got_index:
return -EIO;
}
ix = EXT_FIRST_INDEX(eh);
- block = idx_pblock(ix);
+ block = ext4_idx_pblock(ix);
put_bh(bh);
}
@@ -1402,7 +1354,7 @@ got_index:
}
ex = EXT_FIRST_EXTENT(eh);
*logical = le32_to_cpu(ex->ee_block);
- *phys = ext_pblock(ex);
+ *phys = ext4_ext_pblock(ex);
put_bh(bh);
return 0;
}
@@ -1573,7 +1525,7 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
return 0;
#endif
- if (ext_pblock(ex1) + ext1_ee_len == ext_pblock(ex2))
+ if (ext4_ext_pblock(ex1) + ext1_ee_len == ext4_ext_pblock(ex2))
return 1;
return 0;
}
@@ -1585,9 +1537,9 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
* Returns 0 if the extents (ex and ex+1) were _not_ merged and returns
* 1 if they got merged.
*/
-int ext4_ext_try_to_merge(struct inode *inode,
- struct ext4_ext_path *path,
- struct ext4_extent *ex)
+static int ext4_ext_try_to_merge(struct inode *inode,
+ struct ext4_ext_path *path,
+ struct ext4_extent *ex)
{
struct ext4_extent_header *eh;
unsigned int depth, len;
@@ -1632,9 +1584,9 @@ int ext4_ext_try_to_merge(struct inode *inode,
* such that there will be no overlap, and then returns 1.
* If there is no overlap found, it returns 0.
*/
-unsigned int ext4_ext_check_overlap(struct inode *inode,
- struct ext4_extent *newext,
- struct ext4_ext_path *path)
+static unsigned int ext4_ext_check_overlap(struct inode *inode,
+ struct ext4_extent *newext,
+ struct ext4_ext_path *path)
{
ext4_lblk_t b1, b2;
unsigned int depth, len1;
@@ -1706,11 +1658,12 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
if (ex && !(flag & EXT4_GET_BLOCKS_PRE_IO)
&& ext4_can_extents_be_merged(inode, ex, newext)) {
ext_debug("append [%d]%d block to %d:[%d]%d (from %llu)\n",
- ext4_ext_is_uninitialized(newext),
- ext4_ext_get_actual_len(newext),
- le32_to_cpu(ex->ee_block),
- ext4_ext_is_uninitialized(ex),
- ext4_ext_get_actual_len(ex), ext_pblock(ex));
+ ext4_ext_is_uninitialized(newext),
+ ext4_ext_get_actual_len(newext),
+ le32_to_cpu(ex->ee_block),
+ ext4_ext_is_uninitialized(ex),
+ ext4_ext_get_actual_len(ex),
+ ext4_ext_pblock(ex));
err = ext4_ext_get_access(handle, inode, path + depth);
if (err)
return err;
@@ -1780,7 +1733,7 @@ has_space:
/* there is no extent in this leaf, create first one */
ext_debug("first extent in the leaf: %d:%llu:[%d]%d\n",
le32_to_cpu(newext->ee_block),
- ext_pblock(newext),
+ ext4_ext_pblock(newext),
ext4_ext_is_uninitialized(newext),
ext4_ext_get_actual_len(newext));
path[depth].p_ext = EXT_FIRST_EXTENT(eh);
@@ -1794,7 +1747,7 @@ has_space:
ext_debug("insert %d:%llu:[%d]%d after: nearest 0x%p, "
"move %d from 0x%p to 0x%p\n",
le32_to_cpu(newext->ee_block),
- ext_pblock(newext),
+ ext4_ext_pblock(newext),
ext4_ext_is_uninitialized(newext),
ext4_ext_get_actual_len(newext),
nearex, len, nearex + 1, nearex + 2);
@@ -1808,7 +1761,7 @@ has_space:
ext_debug("insert %d:%llu:[%d]%d before: nearest 0x%p, "
"move %d from 0x%p to 0x%p\n",
le32_to_cpu(newext->ee_block),
- ext_pblock(newext),
+ ext4_ext_pblock(newext),
ext4_ext_is_uninitialized(newext),
ext4_ext_get_actual_len(newext),
nearex, len, nearex + 1, nearex + 2);
@@ -1819,7 +1772,7 @@ has_space:
le16_add_cpu(&eh->eh_entries, 1);
nearex = path[depth].p_ext;
nearex->ee_block = newext->ee_block;
- ext4_ext_store_pblock(nearex, ext_pblock(newext));
+ ext4_ext_store_pblock(nearex, ext4_ext_pblock(newext));
nearex->ee_len = newext->ee_len;
merge:
@@ -1845,9 +1798,9 @@ cleanup:
return err;
}
-int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block,
- ext4_lblk_t num, ext_prepare_callback func,
- void *cbdata)
+static int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block,
+ ext4_lblk_t num, ext_prepare_callback func,
+ void *cbdata)
{
struct ext4_ext_path *path = NULL;
struct ext4_ext_cache cbex;
@@ -1923,7 +1876,7 @@ int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block,
} else {
cbex.ec_block = le32_to_cpu(ex->ee_block);
cbex.ec_len = ext4_ext_get_actual_len(ex);
- cbex.ec_start = ext_pblock(ex);
+ cbex.ec_start = ext4_ext_pblock(ex);
cbex.ec_type = EXT4_EXT_CACHE_EXTENT;
}
@@ -2073,7 +2026,7 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
/* free index block */
path--;
- leaf = idx_pblock(path->p_idx);
+ leaf = ext4_idx_pblock(path->p_idx);
if (unlikely(path->p_hdr->eh_entries == 0)) {
EXT4_ERROR_INODE(inode, "path->p_hdr->eh_entries == 0");
return -EIO;
@@ -2181,7 +2134,7 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
ext4_fsblk_t start;
num = le32_to_cpu(ex->ee_block) + ee_len - from;
- start = ext_pblock(ex) + ee_len - num;
+ start = ext4_ext_pblock(ex) + ee_len - num;
ext_debug("free last %u blocks starting %llu\n", num, start);
ext4_free_blocks(handle, inode, 0, start, num, flags);
} else if (from == le32_to_cpu(ex->ee_block)
@@ -2310,7 +2263,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
goto out;
ext_debug("new extent: %u:%u:%llu\n", block, num,
- ext_pblock(ex));
+ ext4_ext_pblock(ex));
ex--;
ex_ee_block = le32_to_cpu(ex->ee_block);
ex_ee_len = ext4_ext_get_actual_len(ex);
@@ -2421,9 +2374,9 @@ again:
struct buffer_head *bh;
/* go to the next level */
ext_debug("move to level %d (block %llu)\n",
- i + 1, idx_pblock(path[i].p_idx));
+ i + 1, ext4_idx_pblock(path[i].p_idx));
memset(path + i + 1, 0, sizeof(*path));
- bh = sb_bread(sb, idx_pblock(path[i].p_idx));
+ bh = sb_bread(sb, ext4_idx_pblock(path[i].p_idx));
if (!bh) {
/* should we reset i_size? */
err = -EIO;
@@ -2535,77 +2488,21 @@ void ext4_ext_release(struct super_block *sb)
#endif
}
-static void bi_complete(struct bio *bio, int error)
-{
- complete((struct completion *)bio->bi_private);
-}
-
/* FIXME!! we need to try to merge to left or right after zero-out */
static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
{
+ ext4_fsblk_t ee_pblock;
+ unsigned int ee_len;
int ret;
- struct bio *bio;
- int blkbits, blocksize;
- sector_t ee_pblock;
- struct completion event;
- unsigned int ee_len, len, done, offset;
-
- blkbits = inode->i_blkbits;
- blocksize = inode->i_sb->s_blocksize;
ee_len = ext4_ext_get_actual_len(ex);
- ee_pblock = ext_pblock(ex);
-
- /* convert ee_pblock to 512 byte sectors */
- ee_pblock = ee_pblock << (blkbits - 9);
-
- while (ee_len > 0) {
-
- if (ee_len > BIO_MAX_PAGES)
- len = BIO_MAX_PAGES;
- else
- len = ee_len;
-
- bio = bio_alloc(GFP_NOIO, len);
- if (!bio)
- return -ENOMEM;
-
- bio->bi_sector = ee_pblock;
- bio->bi_bdev = inode->i_sb->s_bdev;
-
- done = 0;
- offset = 0;
- while (done < len) {
- ret = bio_add_page(bio, ZERO_PAGE(0),
- blocksize, offset);
- if (ret != blocksize) {
- /*
- * We can't add any more pages because of
- * hardware limitations. Start a new bio.
- */
- break;
- }
- done++;
- offset += blocksize;
- if (offset >= PAGE_CACHE_SIZE)
- offset = 0;
- }
+ ee_pblock = ext4_ext_pblock(ex);
- init_completion(&event);
- bio->bi_private = &event;
- bio->bi_end_io = bi_complete;
- submit_bio(WRITE, bio);
- wait_for_completion(&event);
+ ret = sb_issue_zeroout(inode->i_sb, ee_pblock, ee_len, GFP_NOFS);
+ if (ret > 0)
+ ret = 0;
- if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
- bio_put(bio);
- return -EIO;
- }
- bio_put(bio);
- ee_len -= done;
- ee_pblock += done << (blkbits - 9);
- }
- return 0;
+ return ret;
}
#define EXT4_EXT_ZERO_LEN 7
@@ -2651,12 +2548,12 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
ee_block = le32_to_cpu(ex->ee_block);
ee_len = ext4_ext_get_actual_len(ex);
allocated = ee_len - (map->m_lblk - ee_block);
- newblock = map->m_lblk - ee_block + ext_pblock(ex);
+ newblock = map->m_lblk - ee_block + ext4_ext_pblock(ex);
ex2 = ex;
orig_ex.ee_block = ex->ee_block;
orig_ex.ee_len = cpu_to_le16(ee_len);
- ext4_ext_store_pblock(&orig_ex, ext_pblock(ex));
+ ext4_ext_store_pblock(&orig_ex, ext4_ext_pblock(ex));
/*
* It is safe to convert extent to initialized via explicit
@@ -2675,7 +2572,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
/* update the extent length and mark as initialized */
ex->ee_block = orig_ex.ee_block;
ex->ee_len = orig_ex.ee_len;
- ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
ext4_ext_dirty(handle, inode, path + depth);
/* zeroed the full extent */
return allocated;
@@ -2710,7 +2607,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
ex->ee_block = orig_ex.ee_block;
ex->ee_len = cpu_to_le16(ee_len - allocated);
ext4_ext_mark_uninitialized(ex);
- ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
ext4_ext_dirty(handle, inode, path + depth);
ex3 = &newex;
@@ -2725,7 +2622,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
goto fix_extent_len;
ex->ee_block = orig_ex.ee_block;
ex->ee_len = orig_ex.ee_len;
- ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_store_pblock(ex,
+ ext4_ext_pblock(&orig_ex));
ext4_ext_dirty(handle, inode, path + depth);
/* blocks available from map->m_lblk */
return allocated;
@@ -2782,7 +2680,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
/* update the extent length and mark as initialized */
ex->ee_block = orig_ex.ee_block;
ex->ee_len = orig_ex.ee_len;
- ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
ext4_ext_dirty(handle, inode, path + depth);
/* zeroed the full extent */
/* blocks available from map->m_lblk */
@@ -2833,7 +2731,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
/* update the extent length and mark as initialized */
ex->ee_block = orig_ex.ee_block;
ex->ee_len = orig_ex.ee_len;
- ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
ext4_ext_dirty(handle, inode, path + depth);
/* zero out the first half */
/* blocks available from map->m_lblk */
@@ -2902,7 +2800,7 @@ insert:
/* update the extent length and mark as initialized */
ex->ee_block = orig_ex.ee_block;
ex->ee_len = orig_ex.ee_len;
- ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
ext4_ext_dirty(handle, inode, path + depth);
/* zero out the first half */
return allocated;
@@ -2915,7 +2813,7 @@ out:
fix_extent_len:
ex->ee_block = orig_ex.ee_block;
ex->ee_len = orig_ex.ee_len;
- ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
ext4_ext_mark_uninitialized(ex);
ext4_ext_dirty(handle, inode, path + depth);
return err;
@@ -2973,12 +2871,12 @@ static int ext4_split_unwritten_extents(handle_t *handle,
ee_block = le32_to_cpu(ex->ee_block);
ee_len = ext4_ext_get_actual_len(ex);
allocated = ee_len - (map->m_lblk - ee_block);
- newblock = map->m_lblk - ee_block + ext_pblock(ex);
+ newblock = map->m_lblk - ee_block + ext4_ext_pblock(ex);
ex2 = ex;
orig_ex.ee_block = ex->ee_block;
orig_ex.ee_len = cpu_to_le16(ee_len);
- ext4_ext_store_pblock(&orig_ex, ext_pblock(ex));
+ ext4_ext_store_pblock(&orig_ex, ext4_ext_pblock(ex));
/*
* It is safe to convert extent to initialized via explicit
@@ -3027,7 +2925,7 @@ static int ext4_split_unwritten_extents(handle_t *handle,
/* update the extent length and mark as initialized */
ex->ee_block = orig_ex.ee_block;
ex->ee_len = orig_ex.ee_len;
- ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
ext4_ext_dirty(handle, inode, path + depth);
/* zeroed the full extent */
/* blocks available from map->m_lblk */
@@ -3099,7 +2997,7 @@ insert:
/* update the extent length and mark as initialized */
ex->ee_block = orig_ex.ee_block;
ex->ee_len = orig_ex.ee_len;
- ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
ext4_ext_dirty(handle, inode, path + depth);
/* zero out the first half */
return allocated;
@@ -3112,7 +3010,7 @@ out:
fix_extent_len:
ex->ee_block = orig_ex.ee_block;
ex->ee_len = orig_ex.ee_len;
- ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
ext4_ext_mark_uninitialized(ex);
ext4_ext_dirty(handle, inode, path + depth);
return err;
@@ -3180,6 +3078,57 @@ static void unmap_underlying_metadata_blocks(struct block_device *bdev,
unmap_underlying_metadata(bdev, block + i);
}
+/*
+ * Handle EOFBLOCKS_FL flag, clearing it if necessary
+ */
+static int check_eofblocks_fl(handle_t *handle, struct inode *inode,
+ struct ext4_map_blocks *map,
+ struct ext4_ext_path *path,
+ unsigned int len)
+{
+ int i, depth;
+ struct ext4_extent_header *eh;
+ struct ext4_extent *ex, *last_ex;
+
+ if (!ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS))
+ return 0;
+
+ depth = ext_depth(inode);
+ eh = path[depth].p_hdr;
+ ex = path[depth].p_ext;
+
+ if (unlikely(!eh->eh_entries)) {
+ EXT4_ERROR_INODE(inode, "eh->eh_entries == 0 and "
+ "EOFBLOCKS_FL set");
+ return -EIO;
+ }
+ last_ex = EXT_LAST_EXTENT(eh);
+ /*
+ * We should clear the EOFBLOCKS_FL flag if we are writing the
+ * last block in the last extent in the file. We test this by
+ * first checking to see if the caller to
+ * ext4_ext_get_blocks() was interested in the last block (or
+ * a block beyond the last block) in the current extent. If
+ * this turns out to be false, we can bail out from this
+ * function immediately.
+ */
+ if (map->m_lblk + len < le32_to_cpu(last_ex->ee_block) +
+ ext4_ext_get_actual_len(last_ex))
+ return 0;
+ /*
+ * If the caller does appear to be planning to write at or
+ * beyond the end of the current extent, we then test to see
+ * if the current extent is the last extent in the file, by
+ * checking to make sure it was reached via the rightmost node
+ * at each level of the tree.
+ */
+ for (i = depth-1; i >= 0; i--)
+ if (path[i].p_idx != EXT_LAST_INDEX(path[i].p_hdr))
+ return 0;
+ ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
+ return ext4_mark_inode_dirty(handle, inode);
+}
+
static int
ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
struct ext4_map_blocks *map,
@@ -3206,7 +3155,7 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
* completed
*/
if (io)
- io->flag = EXT4_IO_UNWRITTEN;
+ io->flag = EXT4_IO_END_UNWRITTEN;
else
ext4_set_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN);
if (ext4_should_dioread_nolock(inode))
@@ -3217,8 +3166,12 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
if ((flags & EXT4_GET_BLOCKS_CONVERT)) {
ret = ext4_convert_unwritten_extents_endio(handle, inode,
path);
- if (ret >= 0)
+ if (ret >= 0) {
ext4_update_inode_fsync_trans(handle, inode, 1);
+ err = check_eofblocks_fl(handle, inode, map, path,
+ map->m_len);
+ } else
+ err = ret;
goto out2;
}
/* buffered IO case */
@@ -3244,8 +3197,13 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
/* buffered write, writepage time, convert*/
ret = ext4_ext_convert_to_initialized(handle, inode, map, path);
- if (ret >= 0)
+ if (ret >= 0) {
ext4_update_inode_fsync_trans(handle, inode, 1);
+ err = check_eofblocks_fl(handle, inode, map, path, map->m_len);
+ if (err < 0)
+ goto out2;
+ }
+
out:
if (ret <= 0) {
err = ret;
@@ -3292,6 +3250,7 @@ out2:
}
return err ? err : allocated;
}
+
/*
* Block allocation/map/preallocation routine for extents based files
*
@@ -3315,9 +3274,9 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
{
struct ext4_ext_path *path = NULL;
struct ext4_extent_header *eh;
- struct ext4_extent newex, *ex, *last_ex;
+ struct ext4_extent newex, *ex;
ext4_fsblk_t newblock;
- int i, err = 0, depth, ret, cache_type;
+ int err = 0, depth, ret, cache_type;
unsigned int allocated = 0;
struct ext4_allocation_request ar;
ext4_io_end_t *io = EXT4_I(inode)->cur_aio_dio;
@@ -3341,7 +3300,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
/* block is already allocated */
newblock = map->m_lblk
- le32_to_cpu(newex.ee_block)
- + ext_pblock(&newex);
+ + ext4_ext_pblock(&newex);
/* number of remaining blocks in the extent */
allocated = ext4_ext_get_actual_len(&newex) -
(map->m_lblk - le32_to_cpu(newex.ee_block));
@@ -3379,7 +3338,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
ex = path[depth].p_ext;
if (ex) {
ext4_lblk_t ee_block = le32_to_cpu(ex->ee_block);
- ext4_fsblk_t ee_start = ext_pblock(ex);
+ ext4_fsblk_t ee_start = ext4_ext_pblock(ex);
unsigned short ee_len;
/*
@@ -3488,7 +3447,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
*/
if ((flags & EXT4_GET_BLOCKS_PRE_IO)) {
if (io)
- io->flag = EXT4_IO_UNWRITTEN;
+ io->flag = EXT4_IO_END_UNWRITTEN;
else
ext4_set_inode_state(inode,
EXT4_STATE_DIO_UNWRITTEN);
@@ -3497,44 +3456,23 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
map->m_flags |= EXT4_MAP_UNINIT;
}
- if (unlikely(ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS))) {
- if (unlikely(!eh->eh_entries)) {
- EXT4_ERROR_INODE(inode,
- "eh->eh_entries == 0 and "
- "EOFBLOCKS_FL set");
- err = -EIO;
- goto out2;
- }
- last_ex = EXT_LAST_EXTENT(eh);
- /*
- * If the current leaf block was reached by looking at
- * the last index block all the way down the tree, and
- * we are extending the inode beyond the last extent
- * in the current leaf block, then clear the
- * EOFBLOCKS_FL flag.
- */
- for (i = depth-1; i >= 0; i--) {
- if (path[i].p_idx != EXT_LAST_INDEX(path[i].p_hdr))
- break;
- }
- if ((i < 0) &&
- (map->m_lblk + ar.len > le32_to_cpu(last_ex->ee_block) +
- ext4_ext_get_actual_len(last_ex)))
- ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
- }
+ err = check_eofblocks_fl(handle, inode, map, path, ar.len);
+ if (err)
+ goto out2;
+
err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
if (err) {
/* free data blocks we just allocated */
/* not a good idea to call discard here directly,
* but otherwise we'd need to call it every free() */
ext4_discard_preallocations(inode);
- ext4_free_blocks(handle, inode, 0, ext_pblock(&newex),
+ ext4_free_blocks(handle, inode, 0, ext4_ext_pblock(&newex),
ext4_ext_get_actual_len(&newex), 0);
goto out2;
}
/* previous routine could use block we allocated */
- newblock = ext_pblock(&newex);
+ newblock = ext4_ext_pblock(&newex);
allocated = ext4_ext_get_actual_len(&newex);
if (allocated > map->m_len)
allocated = map->m_len;
@@ -3729,7 +3667,7 @@ retry:
printk(KERN_ERR "%s: ext4_ext_map_blocks "
"returned error inode#%lu, block=%u, "
"max_blocks=%u", __func__,
- inode->i_ino, block, max_blocks);
+ inode->i_ino, map.m_lblk, max_blocks);
#endif
ext4_mark_inode_dirty(handle, inode);
ret2 = ext4_journal_stop(handle);
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index ee92b66d4558..5a5c55ddceef 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -130,8 +130,50 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
return dquot_file_open(inode, filp);
}
+/*
+ * ext4_llseek() copied from generic_file_llseek() to handle both
+ * block-mapped and extent-mapped maxbytes values. This should
+ * otherwise be identical with generic_file_llseek().
+ */
+loff_t ext4_llseek(struct file *file, loff_t offset, int origin)
+{
+ struct inode *inode = file->f_mapping->host;
+ loff_t maxbytes;
+
+ if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
+ maxbytes = EXT4_SB(inode->i_sb)->s_bitmap_maxbytes;
+ else
+ maxbytes = inode->i_sb->s_maxbytes;
+ mutex_lock(&inode->i_mutex);
+ switch (origin) {
+ case SEEK_END:
+ offset += inode->i_size;
+ break;
+ case SEEK_CUR:
+ if (offset == 0) {
+ mutex_unlock(&inode->i_mutex);
+ return file->f_pos;
+ }
+ offset += file->f_pos;
+ break;
+ }
+
+ if (offset < 0 || offset > maxbytes) {
+ mutex_unlock(&inode->i_mutex);
+ return -EINVAL;
+ }
+
+ if (offset != file->f_pos) {
+ file->f_pos = offset;
+ file->f_version = 0;
+ }
+ mutex_unlock(&inode->i_mutex);
+
+ return offset;
+}
+
const struct file_operations ext4_file_operations = {
- .llseek = generic_file_llseek,
+ .llseek = ext4_llseek,
.read = do_sync_read,
.write = do_sync_write,
.aio_read = generic_file_aio_read,
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
index 3f3ff5ee8f9d..c1a7bc923cf6 100644
--- a/fs/ext4/fsync.c
+++ b/fs/ext4/fsync.c
@@ -34,6 +34,89 @@
#include <trace/events/ext4.h>
+static void dump_completed_IO(struct inode * inode)
+{
+#ifdef EXT4_DEBUG
+ struct list_head *cur, *before, *after;
+ ext4_io_end_t *io, *io0, *io1;
+ unsigned long flags;
+
+ if (list_empty(&EXT4_I(inode)->i_completed_io_list)){
+ ext4_debug("inode %lu completed_io list is empty\n", inode->i_ino);
+ return;
+ }
+
+ ext4_debug("Dump inode %lu completed_io list \n", inode->i_ino);
+ spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags);
+ list_for_each_entry(io, &EXT4_I(inode)->i_completed_io_list, list){
+ cur = &io->list;
+ before = cur->prev;
+ io0 = container_of(before, ext4_io_end_t, list);
+ after = cur->next;
+ io1 = container_of(after, ext4_io_end_t, list);
+
+ ext4_debug("io 0x%p from inode %lu,prev 0x%p,next 0x%p\n",
+ io, inode->i_ino, io0, io1);
+ }
+ spin_unlock_irqrestore(&EXT4_I(inode)->i_completed_io_lock, flags);
+#endif
+}
+
+/*
+ * This function is called from ext4_sync_file().
+ *
+ * When IO is completed, the work to convert unwritten extents to
+ * written is queued on workqueue but may not get immediately
+ * scheduled. When fsync is called, we need to ensure the
+ * conversion is complete before fsync returns.
+ * The inode keeps track of a list of pending/completed IO that
+ * might needs to do the conversion. This function walks through
+ * the list and convert the related unwritten extents for completed IO
+ * to written.
+ * The function return the number of pending IOs on success.
+ */
+static int flush_completed_IO(struct inode *inode)
+{
+ ext4_io_end_t *io;
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ unsigned long flags;
+ int ret = 0;
+ int ret2 = 0;
+
+ if (list_empty(&ei->i_completed_io_list))
+ return ret;
+
+ dump_completed_IO(inode);
+ spin_lock_irqsave(&ei->i_completed_io_lock, flags);
+ while (!list_empty(&ei->i_completed_io_list)){
+ io = list_entry(ei->i_completed_io_list.next,
+ ext4_io_end_t, list);
+ /*
+ * Calling ext4_end_io_nolock() to convert completed
+ * IO to written.
+ *
+ * When ext4_sync_file() is called, run_queue() may already
+ * about to flush the work corresponding to this io structure.
+ * It will be upset if it founds the io structure related
+ * to the work-to-be schedule is freed.
+ *
+ * Thus we need to keep the io structure still valid here after
+ * convertion finished. The io structure has a flag to
+ * avoid double converting from both fsync and background work
+ * queue work.
+ */
+ spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
+ ret = ext4_end_io_nolock(io);
+ spin_lock_irqsave(&ei->i_completed_io_lock, flags);
+ if (ret < 0)
+ ret2 = ret;
+ else
+ list_del_init(&io->list);
+ }
+ spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
+ return (ret2 < 0) ? ret2 : 0;
+}
+
/*
* If we're not journaling and this is a just-created file, we have to
* sync our parent directory (if it was freshly created) since
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 45853e0d1f21..1ce240a23ebb 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -50,7 +50,7 @@
* need to use it within a single byte (to ensure we get endianness right).
* We can use memset for the rest of the bitmap as there are no other users.
*/
-void mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
+void ext4_mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
{
int i;
@@ -65,9 +65,10 @@ void mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
}
/* Initializes an uninitialized inode bitmap */
-unsigned ext4_init_inode_bitmap(struct super_block *sb, struct buffer_head *bh,
- ext4_group_t block_group,
- struct ext4_group_desc *gdp)
+static unsigned ext4_init_inode_bitmap(struct super_block *sb,
+ struct buffer_head *bh,
+ ext4_group_t block_group,
+ struct ext4_group_desc *gdp)
{
struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -85,7 +86,7 @@ unsigned ext4_init_inode_bitmap(struct super_block *sb, struct buffer_head *bh,
}
memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
- mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8,
+ ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8,
bh->b_data);
return EXT4_INODES_PER_GROUP(sb);
@@ -107,6 +108,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
desc = ext4_get_group_desc(sb, block_group, NULL);
if (!desc)
return NULL;
+
bitmap_blk = ext4_inode_bitmap(sb, desc);
bh = sb_getblk(sb, bitmap_blk);
if (unlikely(!bh)) {
@@ -123,6 +125,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
unlock_buffer(bh);
return bh;
}
+
ext4_lock_group(sb, block_group);
if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
ext4_init_inode_bitmap(sb, bh, block_group, desc);
@@ -133,6 +136,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
return bh;
}
ext4_unlock_group(sb, block_group);
+
if (buffer_uptodate(bh)) {
/*
* if not uninit if bh is uptodate,
@@ -411,8 +415,8 @@ struct orlov_stats {
* for a particular block group or flex_bg. If flex_size is 1, then g
* is a block group number; otherwise it is flex_bg number.
*/
-void get_orlov_stats(struct super_block *sb, ext4_group_t g,
- int flex_size, struct orlov_stats *stats)
+static void get_orlov_stats(struct super_block *sb, ext4_group_t g,
+ int flex_size, struct orlov_stats *stats)
{
struct ext4_group_desc *desc;
struct flex_groups *flex_group = EXT4_SB(sb)->s_flex_groups;
@@ -712,8 +716,17 @@ static int ext4_claim_inode(struct super_block *sb,
{
int free = 0, retval = 0, count;
struct ext4_sb_info *sbi = EXT4_SB(sb);
+ struct ext4_group_info *grp = ext4_get_group_info(sb, group);
struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL);
+ /*
+ * We have to be sure that new inode allocation does not race with
+ * inode table initialization, because otherwise we may end up
+ * allocating and writing new inode right before sb_issue_zeroout
+ * takes place and overwriting our new inode with zeroes. So we
+ * take alloc_sem to prevent it.
+ */
+ down_read(&grp->alloc_sem);
ext4_lock_group(sb, group);
if (ext4_set_bit(ino, inode_bitmap_bh->b_data)) {
/* not a free inode */
@@ -724,6 +737,7 @@ static int ext4_claim_inode(struct super_block *sb,
if ((group == 0 && ino < EXT4_FIRST_INO(sb)) ||
ino > EXT4_INODES_PER_GROUP(sb)) {
ext4_unlock_group(sb, group);
+ up_read(&grp->alloc_sem);
ext4_error(sb, "reserved inode or inode > inodes count - "
"block_group = %u, inode=%lu", group,
ino + group * EXT4_INODES_PER_GROUP(sb));
@@ -772,6 +786,7 @@ static int ext4_claim_inode(struct super_block *sb,
gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp);
err_ret:
ext4_unlock_group(sb, group);
+ up_read(&grp->alloc_sem);
return retval;
}
@@ -1205,3 +1220,109 @@ unsigned long ext4_count_dirs(struct super_block * sb)
}
return count;
}
+
+/*
+ * Zeroes not yet zeroed inode table - just write zeroes through the whole
+ * inode table. Must be called without any spinlock held. The only place
+ * where it is called from on active part of filesystem is ext4lazyinit
+ * thread, so we do not need any special locks, however we have to prevent
+ * inode allocation from the current group, so we take alloc_sem lock, to
+ * block ext4_claim_inode until we are finished.
+ */
+extern int ext4_init_inode_table(struct super_block *sb, ext4_group_t group,
+ int barrier)
+{
+ struct ext4_group_info *grp = ext4_get_group_info(sb, group);
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ struct ext4_group_desc *gdp = NULL;
+ struct buffer_head *group_desc_bh;
+ handle_t *handle;
+ ext4_fsblk_t blk;
+ int num, ret = 0, used_blks = 0;
+
+ /* This should not happen, but just to be sure check this */
+ if (sb->s_flags & MS_RDONLY) {
+ ret = 1;
+ goto out;
+ }
+
+ gdp = ext4_get_group_desc(sb, group, &group_desc_bh);
+ if (!gdp)
+ goto out;
+
+ /*
+ * We do not need to lock this, because we are the only one
+ * handling this flag.
+ */
+ if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))
+ goto out;
+
+ handle = ext4_journal_start_sb(sb, 1);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ goto out;
+ }
+
+ down_write(&grp->alloc_sem);
+ /*
+ * If inode bitmap was already initialized there may be some
+ * used inodes so we need to skip blocks with used inodes in
+ * inode table.
+ */
+ if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)))
+ used_blks = DIV_ROUND_UP((EXT4_INODES_PER_GROUP(sb) -
+ ext4_itable_unused_count(sb, gdp)),
+ sbi->s_inodes_per_block);
+
+ if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group)) {
+ ext4_error(sb, "Something is wrong with group %u\n"
+ "Used itable blocks: %d"
+ "itable unused count: %u\n",
+ group, used_blks,
+ ext4_itable_unused_count(sb, gdp));
+ ret = 1;
+ goto out;
+ }
+
+ blk = ext4_inode_table(sb, gdp) + used_blks;
+ num = sbi->s_itb_per_group - used_blks;
+
+ BUFFER_TRACE(group_desc_bh, "get_write_access");
+ ret = ext4_journal_get_write_access(handle,
+ group_desc_bh);
+ if (ret)
+ goto err_out;
+
+ /*
+ * Skip zeroout if the inode table is full. But we set the ZEROED
+ * flag anyway, because obviously, when it is full it does not need
+ * further zeroing.
+ */
+ if (unlikely(num == 0))
+ goto skip_zeroout;
+
+ ext4_debug("going to zero out inode table in group %d\n",
+ group);
+ ret = sb_issue_zeroout(sb, blk, num, GFP_NOFS);
+ if (ret < 0)
+ goto err_out;
+ if (barrier)
+ blkdev_issue_flush(sb->s_bdev, GFP_NOFS, NULL);
+
+skip_zeroout:
+ ext4_lock_group(sb, group);
+ gdp->bg_flags |= cpu_to_le16(EXT4_BG_INODE_ZEROED);
+ gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp);
+ ext4_unlock_group(sb, group);
+
+ BUFFER_TRACE(group_desc_bh,
+ "call ext4_handle_dirty_metadata");
+ ret = ext4_handle_dirty_metadata(handle, NULL,
+ group_desc_bh);
+
+err_out:
+ up_write(&grp->alloc_sem);
+ ext4_journal_stop(handle);
+out:
+ return ret;
+}
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 4b8debeb3965..2d6c6c8c036d 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -60,6 +60,12 @@ static inline int ext4_begin_ordered_truncate(struct inode *inode,
}
static void ext4_invalidatepage(struct page *page, unsigned long offset);
+static int noalloc_get_block_write(struct inode *inode, sector_t iblock,
+ struct buffer_head *bh_result, int create);
+static int ext4_set_bh_endio(struct buffer_head *bh, struct inode *inode);
+static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate);
+static int __ext4_journalled_writepage(struct page *page, unsigned int len);
+static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh);
/*
* Test whether an inode is a fast symlink.
@@ -755,6 +761,11 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
* parent to disk.
*/
bh = sb_getblk(inode->i_sb, new_blocks[n-1]);
+ if (unlikely(!bh)) {
+ err = -EIO;
+ goto failed;
+ }
+
branch[n].bh = bh;
lock_buffer(bh);
BUFFER_TRACE(bh, "call get_create_access");
@@ -1207,8 +1218,10 @@ static pgoff_t ext4_num_dirty_pages(struct inode *inode, pgoff_t idx,
break;
idx++;
num++;
- if (num >= max_pages)
+ if (num >= max_pages) {
+ done = 1;
break;
+ }
}
pagevec_release(&pvec);
}
@@ -1538,10 +1551,10 @@ static int do_journal_get_write_access(handle_t *handle,
if (!buffer_mapped(bh) || buffer_freed(bh))
return 0;
/*
- * __block_prepare_write() could have dirtied some buffers. Clean
+ * __block_write_begin() could have dirtied some buffers. Clean
* the dirty bit as jbd2_journal_get_write_access() could complain
* otherwise about fs integrity issues. Setting of the dirty bit
- * by __block_prepare_write() isn't a real problem here as we clear
+ * by __block_write_begin() isn't a real problem here as we clear
* the bit before releasing a page lock and thus writeback cannot
* ever write the buffer.
*/
@@ -1995,16 +2008,23 @@ static void ext4_da_page_release_reservation(struct page *page,
*
* As pages are already locked by write_cache_pages(), we can't use it
*/
-static int mpage_da_submit_io(struct mpage_da_data *mpd)
+static int mpage_da_submit_io(struct mpage_da_data *mpd,
+ struct ext4_map_blocks *map)
{
- long pages_skipped;
struct pagevec pvec;
unsigned long index, end;
int ret = 0, err, nr_pages, i;
struct inode *inode = mpd->inode;
struct address_space *mapping = inode->i_mapping;
+ loff_t size = i_size_read(inode);
+ unsigned int len, block_start;
+ struct buffer_head *bh, *page_bufs = NULL;
+ int journal_data = ext4_should_journal_data(inode);
+ sector_t pblock = 0, cur_logical = 0;
+ struct ext4_io_submit io_submit;
BUG_ON(mpd->next_page <= mpd->first_page);
+ memset(&io_submit, 0, sizeof(io_submit));
/*
* We need to start from the first_page to the next_page - 1
* to make sure we also write the mapped dirty buffer_heads.
@@ -2020,122 +2040,108 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd)
if (nr_pages == 0)
break;
for (i = 0; i < nr_pages; i++) {
+ int commit_write = 0, redirty_page = 0;
struct page *page = pvec.pages[i];
index = page->index;
if (index > end)
break;
+
+ if (index == size >> PAGE_CACHE_SHIFT)
+ len = size & ~PAGE_CACHE_MASK;
+ else
+ len = PAGE_CACHE_SIZE;
+ if (map) {
+ cur_logical = index << (PAGE_CACHE_SHIFT -
+ inode->i_blkbits);
+ pblock = map->m_pblk + (cur_logical -
+ map->m_lblk);
+ }
index++;
BUG_ON(!PageLocked(page));
BUG_ON(PageWriteback(page));
- pages_skipped = mpd->wbc->pages_skipped;
- err = mapping->a_ops->writepage(page, mpd->wbc);
- if (!err && (pages_skipped == mpd->wbc->pages_skipped))
- /*
- * have successfully written the page
- * without skipping the same
- */
- mpd->pages_written++;
/*
- * In error case, we have to continue because
- * remaining pages are still locked
- * XXX: unlock and re-dirty them?
+ * If the page does not have buffers (for
+ * whatever reason), try to create them using
+ * __block_write_begin. If this fails,
+ * redirty the page and move on.
*/
- if (ret == 0)
- ret = err;
- }
- pagevec_release(&pvec);
- }
- return ret;
-}
-
-/*
- * mpage_put_bnr_to_bhs - walk blocks and assign them actual numbers
- *
- * the function goes through all passed space and put actual disk
- * block numbers into buffer heads, dropping BH_Delay and BH_Unwritten
- */
-static void mpage_put_bnr_to_bhs(struct mpage_da_data *mpd,
- struct ext4_map_blocks *map)
-{
- struct inode *inode = mpd->inode;
- struct address_space *mapping = inode->i_mapping;
- int blocks = map->m_len;
- sector_t pblock = map->m_pblk, cur_logical;
- struct buffer_head *head, *bh;
- pgoff_t index, end;
- struct pagevec pvec;
- int nr_pages, i;
-
- index = map->m_lblk >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
- end = (map->m_lblk + blocks - 1) >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
- cur_logical = index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
-
- pagevec_init(&pvec, 0);
-
- while (index <= end) {
- /* XXX: optimize tail */
- nr_pages = pagevec_lookup(&pvec, mapping, index, PAGEVEC_SIZE);
- if (nr_pages == 0)
- break;
- for (i = 0; i < nr_pages; i++) {
- struct page *page = pvec.pages[i];
-
- index = page->index;
- if (index > end)
- break;
- index++;
-
- BUG_ON(!PageLocked(page));
- BUG_ON(PageWriteback(page));
- BUG_ON(!page_has_buffers(page));
-
- bh = page_buffers(page);
- head = bh;
-
- /* skip blocks out of the range */
- do {
- if (cur_logical >= map->m_lblk)
- break;
- cur_logical++;
- } while ((bh = bh->b_this_page) != head);
+ if (!page_has_buffers(page)) {
+ if (__block_write_begin(page, 0, len,
+ noalloc_get_block_write)) {
+ redirty_page:
+ redirty_page_for_writepage(mpd->wbc,
+ page);
+ unlock_page(page);
+ continue;
+ }
+ commit_write = 1;
+ }
+ bh = page_bufs = page_buffers(page);
+ block_start = 0;
do {
- if (cur_logical >= map->m_lblk + blocks)
- break;
-
- if (buffer_delay(bh) || buffer_unwritten(bh)) {
-
- BUG_ON(bh->b_bdev != inode->i_sb->s_bdev);
-
+ if (!bh)
+ goto redirty_page;
+ if (map && (cur_logical >= map->m_lblk) &&
+ (cur_logical <= (map->m_lblk +
+ (map->m_len - 1)))) {
if (buffer_delay(bh)) {
clear_buffer_delay(bh);
bh->b_blocknr = pblock;
- } else {
- /*
- * unwritten already should have
- * blocknr assigned. Verify that
- */
- clear_buffer_unwritten(bh);
- BUG_ON(bh->b_blocknr != pblock);
}
+ if (buffer_unwritten(bh) ||
+ buffer_mapped(bh))
+ BUG_ON(bh->b_blocknr != pblock);
+ if (map->m_flags & EXT4_MAP_UNINIT)
+ set_buffer_uninit(bh);
+ clear_buffer_unwritten(bh);
+ }
- } else if (buffer_mapped(bh))
- BUG_ON(bh->b_blocknr != pblock);
-
- if (map->m_flags & EXT4_MAP_UNINIT)
- set_buffer_uninit(bh);
+ /* redirty page if block allocation undone */
+ if (buffer_delay(bh) || buffer_unwritten(bh))
+ redirty_page = 1;
+ bh = bh->b_this_page;
+ block_start += bh->b_size;
cur_logical++;
pblock++;
- } while ((bh = bh->b_this_page) != head);
+ } while (bh != page_bufs);
+
+ if (redirty_page)
+ goto redirty_page;
+
+ if (commit_write)
+ /* mark the buffer_heads as dirty & uptodate */
+ block_commit_write(page, 0, len);
+
+ /*
+ * Delalloc doesn't support data journalling,
+ * but eventually maybe we'll lift this
+ * restriction.
+ */
+ if (unlikely(journal_data && PageChecked(page)))
+ err = __ext4_journalled_writepage(page, len);
+ else
+ err = ext4_bio_write_page(&io_submit, page,
+ len, mpd->wbc);
+
+ if (!err)
+ mpd->pages_written++;
+ /*
+ * In error case, we have to continue because
+ * remaining pages are still locked
+ */
+ if (ret == 0)
+ ret = err;
}
pagevec_release(&pvec);
}
+ ext4_io_submit(&io_submit);
+ return ret;
}
-
static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd,
sector_t logical, long blk_cnt)
{
@@ -2187,35 +2193,32 @@ static void ext4_print_free_blocks(struct inode *inode)
}
/*
- * mpage_da_map_blocks - go through given space
+ * mpage_da_map_and_submit - go through given space, map them
+ * if necessary, and then submit them for I/O
*
* @mpd - bh describing space
*
* The function skips space we know is already mapped to disk blocks.
*
*/
-static int mpage_da_map_blocks(struct mpage_da_data *mpd)
+static void mpage_da_map_and_submit(struct mpage_da_data *mpd)
{
int err, blks, get_blocks_flags;
- struct ext4_map_blocks map;
+ struct ext4_map_blocks map, *mapp = NULL;
sector_t next = mpd->b_blocknr;
unsigned max_blocks = mpd->b_size >> mpd->inode->i_blkbits;
loff_t disksize = EXT4_I(mpd->inode)->i_disksize;
handle_t *handle = NULL;
/*
- * We consider only non-mapped and non-allocated blocks
- */
- if ((mpd->b_state & (1 << BH_Mapped)) &&
- !(mpd->b_state & (1 << BH_Delay)) &&
- !(mpd->b_state & (1 << BH_Unwritten)))
- return 0;
-
- /*
- * If we didn't accumulate anything to write simply return
+ * If the blocks are mapped already, or we couldn't accumulate
+ * any blocks, then proceed immediately to the submission stage.
*/
- if (!mpd->b_size)
- return 0;
+ if ((mpd->b_size == 0) ||
+ ((mpd->b_state & (1 << BH_Mapped)) &&
+ !(mpd->b_state & (1 << BH_Delay)) &&
+ !(mpd->b_state & (1 << BH_Unwritten))))
+ goto submit_io;
handle = ext4_journal_current_handle();
BUG_ON(!handle);
@@ -2252,17 +2255,18 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
err = blks;
/*
- * If get block returns with error we simply
- * return. Later writepage will redirty the page and
- * writepages will find the dirty page again
+ * If get block returns EAGAIN or ENOSPC and there
+ * appears to be free blocks we will call
+ * ext4_writepage() for all of the pages which will
+ * just redirty the pages.
*/
if (err == -EAGAIN)
- return 0;
+ goto submit_io;
if (err == -ENOSPC &&
ext4_count_free_blocks(sb)) {
mpd->retval = err;
- return 0;
+ goto submit_io;
}
/*
@@ -2287,10 +2291,11 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
/* invalidate all the pages */
ext4_da_block_invalidatepages(mpd, next,
mpd->b_size >> mpd->inode->i_blkbits);
- return err;
+ return;
}
BUG_ON(blks == 0);
+ mapp = &map;
if (map.m_flags & EXT4_MAP_NEW) {
struct block_device *bdev = mpd->inode->i_sb->s_bdev;
int i;
@@ -2299,18 +2304,11 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
unmap_underlying_metadata(bdev, map.m_pblk + i);
}
- /*
- * If blocks are delayed marked, we need to
- * put actual blocknr and drop delayed bit
- */
- if ((mpd->b_state & (1 << BH_Delay)) ||
- (mpd->b_state & (1 << BH_Unwritten)))
- mpage_put_bnr_to_bhs(mpd, &map);
-
if (ext4_should_order_data(mpd->inode)) {
err = ext4_jbd2_file_inode(handle, mpd->inode);
if (err)
- return err;
+ /* This only happens if the journal is aborted */
+ return;
}
/*
@@ -2321,10 +2319,16 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
disksize = i_size_read(mpd->inode);
if (disksize > EXT4_I(mpd->inode)->i_disksize) {
ext4_update_i_disksize(mpd->inode, disksize);
- return ext4_mark_inode_dirty(handle, mpd->inode);
+ err = ext4_mark_inode_dirty(handle, mpd->inode);
+ if (err)
+ ext4_error(mpd->inode->i_sb,
+ "Failed to mark inode %lu dirty",
+ mpd->inode->i_ino);
}
- return 0;
+submit_io:
+ mpage_da_submit_io(mpd, mapp);
+ mpd->io_done = 1;
}
#define BH_FLAGS ((1 << BH_Uptodate) | (1 << BH_Mapped) | \
@@ -2401,9 +2405,7 @@ flush_it:
* We couldn't merge the block to our extent, so we
* need to flush current extent and start new one
*/
- if (mpage_da_map_blocks(mpd) == 0)
- mpage_da_submit_io(mpd);
- mpd->io_done = 1;
+ mpage_da_map_and_submit(mpd);
return;
}
@@ -2422,9 +2424,9 @@ static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh)
* The function finds extents of pages and scan them for all blocks.
*/
static int __mpage_da_writepage(struct page *page,
- struct writeback_control *wbc, void *data)
+ struct writeback_control *wbc,
+ struct mpage_da_data *mpd)
{
- struct mpage_da_data *mpd = data;
struct inode *inode = mpd->inode;
struct buffer_head *bh, *head;
sector_t logical;
@@ -2435,15 +2437,13 @@ static int __mpage_da_writepage(struct page *page,
if (mpd->next_page != page->index) {
/*
* Nope, we can't. So, we map non-allocated blocks
- * and start IO on them using writepage()
+ * and start IO on them
*/
if (mpd->next_page != mpd->first_page) {
- if (mpage_da_map_blocks(mpd) == 0)
- mpage_da_submit_io(mpd);
+ mpage_da_map_and_submit(mpd);
/*
* skip rest of the page in the page_vec
*/
- mpd->io_done = 1;
redirty_page_for_writepage(wbc, page);
unlock_page(page);
return MPAGE_DA_EXTENT_TAIL;
@@ -2550,8 +2550,7 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
if (buffer_delay(bh))
return 0; /* Not sure this could or should happen */
/*
- * XXX: __block_prepare_write() unmaps passed block,
- * is it OK?
+ * XXX: __block_write_begin() unmaps passed block, is it OK?
*/
ret = ext4_da_reserve_space(inode, iblock);
if (ret)
@@ -2583,7 +2582,7 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
/*
* This function is used as a standard get_block_t calback function
* when there is no desire to allocate any blocks. It is used as a
- * callback function for block_prepare_write() and block_write_full_page().
+ * callback function for block_write_begin() and block_write_full_page().
* These functions should only try to map a single block at a time.
*
* Since this function doesn't do block allocations even if the caller
@@ -2623,6 +2622,7 @@ static int __ext4_journalled_writepage(struct page *page,
int ret = 0;
int err;
+ ClearPageChecked(page);
page_bufs = page_buffers(page);
BUG_ON(!page_bufs);
walk_page_buffers(handle, page_bufs, 0, len, NULL, bget_one);
@@ -2700,7 +2700,7 @@ static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate);
static int ext4_writepage(struct page *page,
struct writeback_control *wbc)
{
- int ret = 0;
+ int ret = 0, commit_write = 0;
loff_t size;
unsigned int len;
struct buffer_head *page_bufs = NULL;
@@ -2713,71 +2713,46 @@ static int ext4_writepage(struct page *page,
else
len = PAGE_CACHE_SIZE;
- if (page_has_buffers(page)) {
- page_bufs = page_buffers(page);
- if (walk_page_buffers(NULL, page_bufs, 0, len, NULL,
- ext4_bh_delay_or_unwritten)) {
- /*
- * We don't want to do block allocation
- * So redirty the page and return
- * We may reach here when we do a journal commit
- * via journal_submit_inode_data_buffers.
- * If we don't have mapping block we just ignore
- * them. We can also reach here via shrink_page_list
- */
+ /*
+ * If the page does not have buffers (for whatever reason),
+ * try to create them using __block_write_begin. If this
+ * fails, redirty the page and move on.
+ */
+ if (!page_buffers(page)) {
+ if (__block_write_begin(page, 0, len,
+ noalloc_get_block_write)) {
+ redirty_page:
redirty_page_for_writepage(wbc, page);
unlock_page(page);
return 0;
}
- } else {
+ commit_write = 1;
+ }
+ page_bufs = page_buffers(page);
+ if (walk_page_buffers(NULL, page_bufs, 0, len, NULL,
+ ext4_bh_delay_or_unwritten)) {
/*
- * The test for page_has_buffers() is subtle:
- * We know the page is dirty but it lost buffers. That means
- * that at some moment in time after write_begin()/write_end()
- * has been called all buffers have been clean and thus they
- * must have been written at least once. So they are all
- * mapped and we can happily proceed with mapping them
- * and writing the page.
- *
- * Try to initialize the buffer_heads and check whether
- * all are mapped and non delay. We don't want to
- * do block allocation here.
+ * We don't want to do block allocation So redirty the
+ * page and return We may reach here when we do a
+ * journal commit via
+ * journal_submit_inode_data_buffers. If we don't
+ * have mapping block we just ignore them. We can also
+ * reach here via shrink_page_list
*/
- ret = block_prepare_write(page, 0, len,
- noalloc_get_block_write);
- if (!ret) {
- page_bufs = page_buffers(page);
- /* check whether all are mapped and non delay */
- if (walk_page_buffers(NULL, page_bufs, 0, len, NULL,
- ext4_bh_delay_or_unwritten)) {
- redirty_page_for_writepage(wbc, page);
- unlock_page(page);
- return 0;
- }
- } else {
- /*
- * We can't do block allocation here
- * so just redity the page and unlock
- * and return
- */
- redirty_page_for_writepage(wbc, page);
- unlock_page(page);
- return 0;
- }
+ goto redirty_page;
+ }
+ if (commit_write)
/* now mark the buffer_heads as dirty and uptodate */
block_commit_write(page, 0, len);
- }
- if (PageChecked(page) && ext4_should_journal_data(inode)) {
+ if (PageChecked(page) && ext4_should_journal_data(inode))
/*
* It's mmapped pagecache. Add buffers and journal it. There
* doesn't seem much point in redirtying the page here.
*/
- ClearPageChecked(page);
return __ext4_journalled_writepage(page, len);
- }
- if (page_bufs && buffer_uninit(page_bufs)) {
+ if (buffer_uninit(page_bufs)) {
ext4_set_bh_endio(page_bufs, inode);
ret = block_write_full_page_endio(page, noalloc_get_block_write,
wbc, ext4_end_io_buffer_write);
@@ -2824,25 +2799,32 @@ static int ext4_da_writepages_trans_blocks(struct inode *inode)
*/
static int write_cache_pages_da(struct address_space *mapping,
struct writeback_control *wbc,
- struct mpage_da_data *mpd)
+ struct mpage_da_data *mpd,
+ pgoff_t *done_index)
{
int ret = 0;
int done = 0;
struct pagevec pvec;
- int nr_pages;
+ unsigned nr_pages;
pgoff_t index;
pgoff_t end; /* Inclusive */
long nr_to_write = wbc->nr_to_write;
+ int tag;
pagevec_init(&pvec, 0);
index = wbc->range_start >> PAGE_CACHE_SHIFT;
end = wbc->range_end >> PAGE_CACHE_SHIFT;
+ if (wbc->sync_mode == WB_SYNC_ALL)
+ tag = PAGECACHE_TAG_TOWRITE;
+ else
+ tag = PAGECACHE_TAG_DIRTY;
+
+ *done_index = index;
while (!done && (index <= end)) {
int i;
- nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
- PAGECACHE_TAG_DIRTY,
+ nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag,
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
if (nr_pages == 0)
break;
@@ -2862,6 +2844,8 @@ static int write_cache_pages_da(struct address_space *mapping,
break;
}
+ *done_index = page->index + 1;
+
lock_page(page);
/*
@@ -2947,6 +2931,8 @@ static int ext4_da_writepages(struct address_space *mapping,
long desired_nr_to_write, nr_to_writebump = 0;
loff_t range_start = wbc->range_start;
struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb);
+ pgoff_t done_index = 0;
+ pgoff_t end;
trace_ext4_da_writepages(inode, wbc);
@@ -2982,8 +2968,11 @@ static int ext4_da_writepages(struct address_space *mapping,
wbc->range_start = index << PAGE_CACHE_SHIFT;
wbc->range_end = LLONG_MAX;
wbc->range_cyclic = 0;
- } else
+ end = -1;
+ } else {
index = wbc->range_start >> PAGE_CACHE_SHIFT;
+ end = wbc->range_end >> PAGE_CACHE_SHIFT;
+ }
/*
* This works around two forms of stupidity. The first is in
@@ -3002,9 +2991,12 @@ static int ext4_da_writepages(struct address_space *mapping,
* sbi->max_writeback_mb_bump whichever is smaller.
*/
max_pages = sbi->s_max_writeback_mb_bump << (20 - PAGE_CACHE_SHIFT);
- if (!range_cyclic && range_whole)
- desired_nr_to_write = wbc->nr_to_write * 8;
- else
+ if (!range_cyclic && range_whole) {
+ if (wbc->nr_to_write == LONG_MAX)
+ desired_nr_to_write = wbc->nr_to_write;
+ else
+ desired_nr_to_write = wbc->nr_to_write * 8;
+ } else
desired_nr_to_write = ext4_num_dirty_pages(inode, index,
max_pages);
if (desired_nr_to_write > max_pages)
@@ -3021,6 +3013,9 @@ static int ext4_da_writepages(struct address_space *mapping,
pages_skipped = wbc->pages_skipped;
retry:
+ if (wbc->sync_mode == WB_SYNC_ALL)
+ tag_pages_for_writeback(mapping, index, end);
+
while (!ret && wbc->nr_to_write > 0) {
/*
@@ -3059,16 +3054,14 @@ retry:
mpd.io_done = 0;
mpd.pages_written = 0;
mpd.retval = 0;
- ret = write_cache_pages_da(mapping, wbc, &mpd);
+ ret = write_cache_pages_da(mapping, wbc, &mpd, &done_index);
/*
* If we have a contiguous extent of pages and we
* haven't done the I/O yet, map the blocks and submit
* them for I/O.
*/
if (!mpd.io_done && mpd.next_page != mpd.first_page) {
- if (mpage_da_map_blocks(&mpd) == 0)
- mpage_da_submit_io(&mpd);
- mpd.io_done = 1;
+ mpage_da_map_and_submit(&mpd);
ret = MPAGE_DA_EXTENT_TAIL;
}
trace_ext4_da_write_pages(inode, &mpd);
@@ -3115,14 +3108,13 @@ retry:
__func__, wbc->nr_to_write, ret);
/* Update index */
- index += pages_written;
wbc->range_cyclic = range_cyclic;
if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
/*
* set the writeback_index so that range_cyclic
* mode will write it back later
*/
- mapping->writeback_index = index;
+ mapping->writeback_index = done_index;
out_writepages:
wbc->nr_to_write -= nr_to_writebump;
@@ -3457,15 +3449,6 @@ ext4_readpages(struct file *file, struct address_space *mapping,
return mpage_readpages(mapping, pages, nr_pages, ext4_get_block);
}
-static void ext4_free_io_end(ext4_io_end_t *io)
-{
- BUG_ON(!io);
- if (io->page)
- put_page(io->page);
- iput(io->inode);
- kfree(io);
-}
-
static void ext4_invalidatepage_free_endio(struct page *page, unsigned long offset)
{
struct buffer_head *head, *bh;
@@ -3642,173 +3625,6 @@ static int ext4_get_block_write(struct inode *inode, sector_t iblock,
EXT4_GET_BLOCKS_IO_CREATE_EXT);
}
-static void dump_completed_IO(struct inode * inode)
-{
-#ifdef EXT4_DEBUG
- struct list_head *cur, *before, *after;
- ext4_io_end_t *io, *io0, *io1;
- unsigned long flags;
-
- if (list_empty(&EXT4_I(inode)->i_completed_io_list)){
- ext4_debug("inode %lu completed_io list is empty\n", inode->i_ino);
- return;
- }
-
- ext4_debug("Dump inode %lu completed_io list \n", inode->i_ino);
- spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags);
- list_for_each_entry(io, &EXT4_I(inode)->i_completed_io_list, list){
- cur = &io->list;
- before = cur->prev;
- io0 = container_of(before, ext4_io_end_t, list);
- after = cur->next;
- io1 = container_of(after, ext4_io_end_t, list);
-
- ext4_debug("io 0x%p from inode %lu,prev 0x%p,next 0x%p\n",
- io, inode->i_ino, io0, io1);
- }
- spin_unlock_irqrestore(&EXT4_I(inode)->i_completed_io_lock, flags);
-#endif
-}
-
-/*
- * check a range of space and convert unwritten extents to written.
- */
-static int ext4_end_io_nolock(ext4_io_end_t *io)
-{
- struct inode *inode = io->inode;
- loff_t offset = io->offset;
- ssize_t size = io->size;
- int ret = 0;
-
- ext4_debug("ext4_end_io_nolock: io 0x%p from inode %lu,list->next 0x%p,"
- "list->prev 0x%p\n",
- io, inode->i_ino, io->list.next, io->list.prev);
-
- if (list_empty(&io->list))
- return ret;
-
- if (io->flag != EXT4_IO_UNWRITTEN)
- return ret;
-
- ret = ext4_convert_unwritten_extents(inode, offset, size);
- if (ret < 0) {
- printk(KERN_EMERG "%s: failed to convert unwritten"
- "extents to written extents, error is %d"
- " io is still on inode %lu aio dio list\n",
- __func__, ret, inode->i_ino);
- return ret;
- }
-
- if (io->iocb)
- aio_complete(io->iocb, io->result, 0);
- /* clear the DIO AIO unwritten flag */
- io->flag = 0;
- return ret;
-}
-
-/*
- * work on completed aio dio IO, to convert unwritten extents to extents
- */
-static void ext4_end_io_work(struct work_struct *work)
-{
- ext4_io_end_t *io = container_of(work, ext4_io_end_t, work);
- struct inode *inode = io->inode;
- struct ext4_inode_info *ei = EXT4_I(inode);
- unsigned long flags;
- int ret;
-
- mutex_lock(&inode->i_mutex);
- ret = ext4_end_io_nolock(io);
- if (ret < 0) {
- mutex_unlock(&inode->i_mutex);
- return;
- }
-
- spin_lock_irqsave(&ei->i_completed_io_lock, flags);
- if (!list_empty(&io->list))
- list_del_init(&io->list);
- spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
- mutex_unlock(&inode->i_mutex);
- ext4_free_io_end(io);
-}
-
-/*
- * This function is called from ext4_sync_file().
- *
- * When IO is completed, the work to convert unwritten extents to
- * written is queued on workqueue but may not get immediately
- * scheduled. When fsync is called, we need to ensure the
- * conversion is complete before fsync returns.
- * The inode keeps track of a list of pending/completed IO that
- * might needs to do the conversion. This function walks through
- * the list and convert the related unwritten extents for completed IO
- * to written.
- * The function return the number of pending IOs on success.
- */
-int flush_completed_IO(struct inode *inode)
-{
- ext4_io_end_t *io;
- struct ext4_inode_info *ei = EXT4_I(inode);
- unsigned long flags;
- int ret = 0;
- int ret2 = 0;
-
- if (list_empty(&ei->i_completed_io_list))
- return ret;
-
- dump_completed_IO(inode);
- spin_lock_irqsave(&ei->i_completed_io_lock, flags);
- while (!list_empty(&ei->i_completed_io_list)){
- io = list_entry(ei->i_completed_io_list.next,
- ext4_io_end_t, list);
- /*
- * Calling ext4_end_io_nolock() to convert completed
- * IO to written.
- *
- * When ext4_sync_file() is called, run_queue() may already
- * about to flush the work corresponding to this io structure.
- * It will be upset if it founds the io structure related
- * to the work-to-be schedule is freed.
- *
- * Thus we need to keep the io structure still valid here after
- * convertion finished. The io structure has a flag to
- * avoid double converting from both fsync and background work
- * queue work.
- */
- spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
- ret = ext4_end_io_nolock(io);
- spin_lock_irqsave(&ei->i_completed_io_lock, flags);
- if (ret < 0)
- ret2 = ret;
- else
- list_del_init(&io->list);
- }
- spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
- return (ret2 < 0) ? ret2 : 0;
-}
-
-static ext4_io_end_t *ext4_init_io_end (struct inode *inode, gfp_t flags)
-{
- ext4_io_end_t *io = NULL;
-
- io = kmalloc(sizeof(*io), flags);
-
- if (io) {
- igrab(inode);
- io->inode = inode;
- io->flag = 0;
- io->offset = 0;
- io->size = 0;
- io->page = NULL;
- io->iocb = NULL;
- io->result = 0;
- INIT_WORK(&io->work, ext4_end_io_work);
- INIT_LIST_HEAD(&io->list);
- }
-
- return io;
-}
-
static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
ssize_t size, void *private, int ret,
bool is_async)
@@ -3828,7 +3644,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
size);
/* if not aio dio with unwritten extents, just free io and return */
- if (io_end->flag != EXT4_IO_UNWRITTEN){
+ if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
ext4_free_io_end(io_end);
iocb->private = NULL;
out:
@@ -3845,14 +3661,14 @@ out:
}
wq = EXT4_SB(io_end->inode->i_sb)->dio_unwritten_wq;
- /* queue the work to convert unwritten extents to written */
- queue_work(wq, &io_end->work);
-
/* Add the io_end to per-inode completed aio dio list*/
ei = EXT4_I(io_end->inode);
spin_lock_irqsave(&ei->i_completed_io_lock, flags);
list_add_tail(&io_end->list, &ei->i_completed_io_list);
spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
+
+ /* queue the work to convert unwritten extents to written */
+ queue_work(wq, &io_end->work);
iocb->private = NULL;
}
@@ -3873,7 +3689,7 @@ static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate)
goto out;
}
- io_end->flag = EXT4_IO_UNWRITTEN;
+ io_end->flag = EXT4_IO_END_UNWRITTEN;
inode = io_end->inode;
/* Add the io_end to per-inode completed io list*/
@@ -5464,6 +5280,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = dentry->d_inode;
int error, rc = 0;
+ int orphan = 0;
const unsigned int ia_valid = attr->ia_valid;
error = inode_change_ok(inode, attr);
@@ -5519,8 +5336,10 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
error = PTR_ERR(handle);
goto err_out;
}
-
- error = ext4_orphan_add(handle, inode);
+ if (ext4_handle_valid(handle)) {
+ error = ext4_orphan_add(handle, inode);
+ orphan = 1;
+ }
EXT4_I(inode)->i_disksize = attr->ia_size;
rc = ext4_mark_inode_dirty(handle, inode);
if (!error)
@@ -5538,6 +5357,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
goto err_out;
}
ext4_orphan_del(handle, inode);
+ orphan = 0;
ext4_journal_stop(handle);
goto err_out;
}
@@ -5560,7 +5380,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
* If the call to ext4_truncate failed to get a transaction handle at
* all, we need to clean up the in-core orphan list manually.
*/
- if (inode->i_nlink)
+ if (orphan && inode->i_nlink)
ext4_orphan_del(NULL, inode);
if (!rc && (ia_valid & ATTR_MODE))
@@ -5643,7 +5463,7 @@ static int ext4_index_trans_blocks(struct inode *inode, int nrblocks, int chunk)
*
* Also account for superblock, inode, quota and xattr blocks
*/
-int ext4_meta_trans_blocks(struct inode *inode, int nrblocks, int chunk)
+static int ext4_meta_trans_blocks(struct inode *inode, int nrblocks, int chunk)
{
ext4_group_t groups, ngroups = ext4_get_groups_count(inode->i_sb);
int gdpblocks;
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 19aa0d44d822..c58eba34724a 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -338,6 +338,14 @@
static struct kmem_cache *ext4_pspace_cachep;
static struct kmem_cache *ext4_ac_cachep;
static struct kmem_cache *ext4_free_ext_cachep;
+
+/* We create slab caches for groupinfo data structures based on the
+ * superblock block size. There will be one per mounted filesystem for
+ * each unique s_blocksize_bits */
+#define NR_GRPINFO_CACHES \
+ (EXT4_MAX_BLOCK_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE + 1)
+static struct kmem_cache *ext4_groupinfo_caches[NR_GRPINFO_CACHES];
+
static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
ext4_group_t group);
static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
@@ -939,6 +947,85 @@ out:
}
/*
+ * lock the group_info alloc_sem of all the groups
+ * belonging to the same buddy cache page. This
+ * make sure other parallel operation on the buddy
+ * cache doesn't happen whild holding the buddy cache
+ * lock
+ */
+static int ext4_mb_get_buddy_cache_lock(struct super_block *sb,
+ ext4_group_t group)
+{
+ int i;
+ int block, pnum;
+ int blocks_per_page;
+ int groups_per_page;
+ ext4_group_t ngroups = ext4_get_groups_count(sb);
+ ext4_group_t first_group;
+ struct ext4_group_info *grp;
+
+ blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize;
+ /*
+ * the buddy cache inode stores the block bitmap
+ * and buddy information in consecutive blocks.
+ * So for each group we need two blocks.
+ */
+ block = group * 2;
+ pnum = block / blocks_per_page;
+ first_group = pnum * blocks_per_page / 2;
+
+ groups_per_page = blocks_per_page >> 1;
+ if (groups_per_page == 0)
+ groups_per_page = 1;
+ /* read all groups the page covers into the cache */
+ for (i = 0; i < groups_per_page; i++) {
+
+ if ((first_group + i) >= ngroups)
+ break;
+ grp = ext4_get_group_info(sb, first_group + i);
+ /* take all groups write allocation
+ * semaphore. This make sure there is
+ * no block allocation going on in any
+ * of that groups
+ */
+ down_write_nested(&grp->alloc_sem, i);
+ }
+ return i;
+}
+
+static void ext4_mb_put_buddy_cache_lock(struct super_block *sb,
+ ext4_group_t group, int locked_group)
+{
+ int i;
+ int block, pnum;
+ int blocks_per_page;
+ ext4_group_t first_group;
+ struct ext4_group_info *grp;
+
+ blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize;
+ /*
+ * the buddy cache inode stores the block bitmap
+ * and buddy information in consecutive blocks.
+ * So for each group we need two blocks.
+ */
+ block = group * 2;
+ pnum = block / blocks_per_page;
+ first_group = pnum * blocks_per_page / 2;
+ /* release locks on all the groups */
+ for (i = 0; i < locked_group; i++) {
+
+ grp = ext4_get_group_info(sb, first_group + i);
+ /* take all groups write allocation
+ * semaphore. This make sure there is
+ * no block allocation going on in any
+ * of that groups
+ */
+ up_write(&grp->alloc_sem);
+ }
+
+}
+
+/*
* Locking note: This routine calls ext4_mb_init_cache(), which takes the
* block group lock of all groups for this page; do not hold the BG lock when
* calling this routine!
@@ -1915,84 +2002,6 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac,
return 0;
}
-/*
- * lock the group_info alloc_sem of all the groups
- * belonging to the same buddy cache page. This
- * make sure other parallel operation on the buddy
- * cache doesn't happen whild holding the buddy cache
- * lock
- */
-int ext4_mb_get_buddy_cache_lock(struct super_block *sb, ext4_group_t group)
-{
- int i;
- int block, pnum;
- int blocks_per_page;
- int groups_per_page;
- ext4_group_t ngroups = ext4_get_groups_count(sb);
- ext4_group_t first_group;
- struct ext4_group_info *grp;
-
- blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize;
- /*
- * the buddy cache inode stores the block bitmap
- * and buddy information in consecutive blocks.
- * So for each group we need two blocks.
- */
- block = group * 2;
- pnum = block / blocks_per_page;
- first_group = pnum * blocks_per_page / 2;
-
- groups_per_page = blocks_per_page >> 1;
- if (groups_per_page == 0)
- groups_per_page = 1;
- /* read all groups the page covers into the cache */
- for (i = 0; i < groups_per_page; i++) {
-
- if ((first_group + i) >= ngroups)
- break;
- grp = ext4_get_group_info(sb, first_group + i);
- /* take all groups write allocation
- * semaphore. This make sure there is
- * no block allocation going on in any
- * of that groups
- */
- down_write_nested(&grp->alloc_sem, i);
- }
- return i;
-}
-
-void ext4_mb_put_buddy_cache_lock(struct super_block *sb,
- ext4_group_t group, int locked_group)
-{
- int i;
- int block, pnum;
- int blocks_per_page;
- ext4_group_t first_group;
- struct ext4_group_info *grp;
-
- blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize;
- /*
- * the buddy cache inode stores the block bitmap
- * and buddy information in consecutive blocks.
- * So for each group we need two blocks.
- */
- block = group * 2;
- pnum = block / blocks_per_page;
- first_group = pnum * blocks_per_page / 2;
- /* release locks on all the groups */
- for (i = 0; i < locked_group; i++) {
-
- grp = ext4_get_group_info(sb, first_group + i);
- /* take all groups write allocation
- * semaphore. This make sure there is
- * no block allocation going on in any
- * of that groups
- */
- up_write(&grp->alloc_sem);
- }
-
-}
-
static noinline_for_stack int
ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
{
@@ -2233,15 +2242,24 @@ static const struct file_operations ext4_mb_seq_groups_fops = {
.release = seq_release,
};
+static struct kmem_cache *get_groupinfo_cache(int blocksize_bits)
+{
+ int cache_index = blocksize_bits - EXT4_MIN_BLOCK_LOG_SIZE;
+ struct kmem_cache *cachep = ext4_groupinfo_caches[cache_index];
+
+ BUG_ON(!cachep);
+ return cachep;
+}
/* Create and initialize ext4_group_info data for the given group. */
int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
struct ext4_group_desc *desc)
{
- int i, len;
+ int i;
int metalen = 0;
struct ext4_sb_info *sbi = EXT4_SB(sb);
struct ext4_group_info **meta_group_info;
+ struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits);
/*
* First check if this group is the first of a reserved block.
@@ -2261,22 +2279,16 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
meta_group_info;
}
- /*
- * calculate needed size. if change bb_counters size,
- * don't forget about ext4_mb_generate_buddy()
- */
- len = offsetof(typeof(**meta_group_info),
- bb_counters[sb->s_blocksize_bits + 2]);
-
meta_group_info =
sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)];
i = group & (EXT4_DESC_PER_BLOCK(sb) - 1);
- meta_group_info[i] = kzalloc(len, GFP_KERNEL);
+ meta_group_info[i] = kmem_cache_alloc(cachep, GFP_KERNEL);
if (meta_group_info[i] == NULL) {
printk(KERN_ERR "EXT4-fs: can't allocate buddy mem\n");
goto exit_group_info;
}
+ memset(meta_group_info[i], 0, kmem_cache_size(cachep));
set_bit(EXT4_GROUP_INFO_NEED_INIT_BIT,
&(meta_group_info[i]->bb_state));
@@ -2331,6 +2343,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
int num_meta_group_infos_max;
int array_size;
struct ext4_group_desc *desc;
+ struct kmem_cache *cachep;
/* This is the number of blocks used by GDT */
num_meta_group_infos = (ngroups + EXT4_DESC_PER_BLOCK(sb) -
@@ -2373,6 +2386,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
printk(KERN_ERR "EXT4-fs: can't get new inode\n");
goto err_freesgi;
}
+ sbi->s_buddy_cache->i_ino = get_next_ino();
EXT4_I(sbi->s_buddy_cache)->i_disksize = 0;
for (i = 0; i < ngroups; i++) {
desc = ext4_get_group_desc(sb, i, NULL);
@@ -2388,8 +2402,9 @@ static int ext4_mb_init_backend(struct super_block *sb)
return 0;
err_freebuddy:
+ cachep = get_groupinfo_cache(sb->s_blocksize_bits);
while (i-- > 0)
- kfree(ext4_get_group_info(sb, i));
+ kmem_cache_free(cachep, ext4_get_group_info(sb, i));
i = num_meta_group_infos;
while (i-- > 0)
kfree(sbi->s_group_info[i]);
@@ -2406,19 +2421,48 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
unsigned offset;
unsigned max;
int ret;
+ int cache_index;
+ struct kmem_cache *cachep;
+ char *namep = NULL;
i = (sb->s_blocksize_bits + 2) * sizeof(*sbi->s_mb_offsets);
sbi->s_mb_offsets = kmalloc(i, GFP_KERNEL);
if (sbi->s_mb_offsets == NULL) {
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out;
}
i = (sb->s_blocksize_bits + 2) * sizeof(*sbi->s_mb_maxs);
sbi->s_mb_maxs = kmalloc(i, GFP_KERNEL);
if (sbi->s_mb_maxs == NULL) {
- kfree(sbi->s_mb_offsets);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cache_index = sb->s_blocksize_bits - EXT4_MIN_BLOCK_LOG_SIZE;
+ cachep = ext4_groupinfo_caches[cache_index];
+ if (!cachep) {
+ char name[32];
+ int len = offsetof(struct ext4_group_info,
+ bb_counters[sb->s_blocksize_bits + 2]);
+
+ sprintf(name, "ext4_groupinfo_%d", sb->s_blocksize_bits);
+ namep = kstrdup(name, GFP_KERNEL);
+ if (!namep) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Need to free the kmem_cache_name() when we
+ * destroy the slab */
+ cachep = kmem_cache_create(namep, len, 0,
+ SLAB_RECLAIM_ACCOUNT, NULL);
+ if (!cachep) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ext4_groupinfo_caches[cache_index] = cachep;
}
/* order 0 is regular bitmap */
@@ -2439,9 +2483,7 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
/* init file for buddy data */
ret = ext4_mb_init_backend(sb);
if (ret != 0) {
- kfree(sbi->s_mb_offsets);
- kfree(sbi->s_mb_maxs);
- return ret;
+ goto out;
}
spin_lock_init(&sbi->s_md_lock);
@@ -2456,9 +2498,8 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
sbi->s_locality_groups = alloc_percpu(struct ext4_locality_group);
if (sbi->s_locality_groups == NULL) {
- kfree(sbi->s_mb_offsets);
- kfree(sbi->s_mb_maxs);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out;
}
for_each_possible_cpu(i) {
struct ext4_locality_group *lg;
@@ -2475,7 +2516,13 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
if (sbi->s_journal)
sbi->s_journal->j_commit_callback = release_blocks_on_commit;
- return 0;
+out:
+ if (ret) {
+ kfree(sbi->s_mb_offsets);
+ kfree(sbi->s_mb_maxs);
+ kfree(namep);
+ }
+ return ret;
}
/* need to called with the ext4 group lock held */
@@ -2503,6 +2550,7 @@ int ext4_mb_release(struct super_block *sb)
int num_meta_group_infos;
struct ext4_group_info *grinfo;
struct ext4_sb_info *sbi = EXT4_SB(sb);
+ struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits);
if (sbi->s_group_info) {
for (i = 0; i < ngroups; i++) {
@@ -2513,7 +2561,7 @@ int ext4_mb_release(struct super_block *sb)
ext4_lock_group(sb, i);
ext4_mb_cleanup_pa(grinfo);
ext4_unlock_group(sb, i);
- kfree(grinfo);
+ kmem_cache_free(cachep, grinfo);
}
num_meta_group_infos = (ngroups +
EXT4_DESC_PER_BLOCK(sb) - 1) >>
@@ -2557,7 +2605,7 @@ int ext4_mb_release(struct super_block *sb)
return 0;
}
-static inline void ext4_issue_discard(struct super_block *sb,
+static inline int ext4_issue_discard(struct super_block *sb,
ext4_group_t block_group, ext4_grpblk_t block, int count)
{
int ret;
@@ -2567,10 +2615,11 @@ static inline void ext4_issue_discard(struct super_block *sb,
trace_ext4_discard_blocks(sb,
(unsigned long long) discard_block, count);
ret = sb_issue_discard(sb, discard_block, count, GFP_NOFS, 0);
- if (ret == EOPNOTSUPP) {
+ if (ret == -EOPNOTSUPP) {
ext4_warning(sb, "discard not supported, disabling");
clear_opt(EXT4_SB(sb)->s_mount_opt, DISCARD);
}
+ return ret;
}
/*
@@ -2658,28 +2707,22 @@ static void ext4_remove_debugfs_entry(void)
#endif
-int __init init_ext4_mballoc(void)
+int __init ext4_init_mballoc(void)
{
- ext4_pspace_cachep =
- kmem_cache_create("ext4_prealloc_space",
- sizeof(struct ext4_prealloc_space),
- 0, SLAB_RECLAIM_ACCOUNT, NULL);
+ ext4_pspace_cachep = KMEM_CACHE(ext4_prealloc_space,
+ SLAB_RECLAIM_ACCOUNT);
if (ext4_pspace_cachep == NULL)
return -ENOMEM;
- ext4_ac_cachep =
- kmem_cache_create("ext4_alloc_context",
- sizeof(struct ext4_allocation_context),
- 0, SLAB_RECLAIM_ACCOUNT, NULL);
+ ext4_ac_cachep = KMEM_CACHE(ext4_allocation_context,
+ SLAB_RECLAIM_ACCOUNT);
if (ext4_ac_cachep == NULL) {
kmem_cache_destroy(ext4_pspace_cachep);
return -ENOMEM;
}
- ext4_free_ext_cachep =
- kmem_cache_create("ext4_free_block_extents",
- sizeof(struct ext4_free_data),
- 0, SLAB_RECLAIM_ACCOUNT, NULL);
+ ext4_free_ext_cachep = KMEM_CACHE(ext4_free_data,
+ SLAB_RECLAIM_ACCOUNT);
if (ext4_free_ext_cachep == NULL) {
kmem_cache_destroy(ext4_pspace_cachep);
kmem_cache_destroy(ext4_ac_cachep);
@@ -2689,8 +2732,9 @@ int __init init_ext4_mballoc(void)
return 0;
}
-void exit_ext4_mballoc(void)
+void ext4_exit_mballoc(void)
{
+ int i;
/*
* Wait for completion of call_rcu()'s on ext4_pspace_cachep
* before destroying the slab cache.
@@ -2699,6 +2743,15 @@ void exit_ext4_mballoc(void)
kmem_cache_destroy(ext4_pspace_cachep);
kmem_cache_destroy(ext4_ac_cachep);
kmem_cache_destroy(ext4_free_ext_cachep);
+
+ for (i = 0; i < NR_GRPINFO_CACHES; i++) {
+ struct kmem_cache *cachep = ext4_groupinfo_caches[i];
+ if (cachep) {
+ char *name = (char *)kmem_cache_name(cachep);
+ kmem_cache_destroy(cachep);
+ kfree(name);
+ }
+ }
ext4_remove_debugfs_entry();
}
@@ -3535,8 +3588,7 @@ static int ext4_mb_new_preallocation(struct ext4_allocation_context *ac)
*/
static noinline_for_stack int
ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
- struct ext4_prealloc_space *pa,
- struct ext4_allocation_context *ac)
+ struct ext4_prealloc_space *pa)
{
struct super_block *sb = e4b->bd_sb;
struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -3554,11 +3606,6 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
BUG_ON(group != e4b->bd_group && pa->pa_len != 0);
end = bit + pa->pa_len;
- if (ac) {
- ac->ac_sb = sb;
- ac->ac_inode = pa->pa_inode;
- }
-
while (bit < end) {
bit = mb_find_next_zero_bit(bitmap_bh->b_data, end, bit);
if (bit >= end)
@@ -3569,16 +3616,9 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
(unsigned) next - bit, (unsigned) group);
free += next - bit;
- if (ac) {
- ac->ac_b_ex.fe_group = group;
- ac->ac_b_ex.fe_start = bit;
- ac->ac_b_ex.fe_len = next - bit;
- ac->ac_b_ex.fe_logical = 0;
- trace_ext4_mballoc_discard(ac);
- }
-
- trace_ext4_mb_release_inode_pa(sb, ac, pa, grp_blk_start + bit,
- next - bit);
+ trace_ext4_mballoc_discard(sb, NULL, group, bit, next - bit);
+ trace_ext4_mb_release_inode_pa(sb, pa->pa_inode, pa,
+ grp_blk_start + bit, next - bit);
mb_free_blocks(pa->pa_inode, e4b, bit, next - bit);
bit = next + 1;
}
@@ -3601,29 +3641,19 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
static noinline_for_stack int
ext4_mb_release_group_pa(struct ext4_buddy *e4b,
- struct ext4_prealloc_space *pa,
- struct ext4_allocation_context *ac)
+ struct ext4_prealloc_space *pa)
{
struct super_block *sb = e4b->bd_sb;
ext4_group_t group;
ext4_grpblk_t bit;
- trace_ext4_mb_release_group_pa(sb, ac, pa);
+ trace_ext4_mb_release_group_pa(sb, pa);
BUG_ON(pa->pa_deleted == 0);
ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit);
BUG_ON(group != e4b->bd_group && pa->pa_len != 0);
mb_free_blocks(pa->pa_inode, e4b, bit, pa->pa_len);
atomic_add(pa->pa_len, &EXT4_SB(sb)->s_mb_discarded);
-
- if (ac) {
- ac->ac_sb = sb;
- ac->ac_inode = NULL;
- ac->ac_b_ex.fe_group = group;
- ac->ac_b_ex.fe_start = bit;
- ac->ac_b_ex.fe_len = pa->pa_len;
- ac->ac_b_ex.fe_logical = 0;
- trace_ext4_mballoc_discard(ac);
- }
+ trace_ext4_mballoc_discard(sb, NULL, group, bit, pa->pa_len);
return 0;
}
@@ -3644,7 +3674,6 @@ ext4_mb_discard_group_preallocations(struct super_block *sb,
struct ext4_group_info *grp = ext4_get_group_info(sb, group);
struct buffer_head *bitmap_bh = NULL;
struct ext4_prealloc_space *pa, *tmp;
- struct ext4_allocation_context *ac;
struct list_head list;
struct ext4_buddy e4b;
int err;
@@ -3673,9 +3702,6 @@ ext4_mb_discard_group_preallocations(struct super_block *sb,
needed = EXT4_BLOCKS_PER_GROUP(sb) + 1;
INIT_LIST_HEAD(&list);
- ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
- if (ac)
- ac->ac_sb = sb;
repeat:
ext4_lock_group(sb, group);
list_for_each_entry_safe(pa, tmp,
@@ -3730,9 +3756,9 @@ repeat:
spin_unlock(pa->pa_obj_lock);
if (pa->pa_type == MB_GROUP_PA)
- ext4_mb_release_group_pa(&e4b, pa, ac);
+ ext4_mb_release_group_pa(&e4b, pa);
else
- ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa, ac);
+ ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa);
list_del(&pa->u.pa_tmp_list);
call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback);
@@ -3740,8 +3766,6 @@ repeat:
out:
ext4_unlock_group(sb, group);
- if (ac)
- kmem_cache_free(ext4_ac_cachep, ac);
ext4_mb_unload_buddy(&e4b);
put_bh(bitmap_bh);
return free;
@@ -3762,7 +3786,6 @@ void ext4_discard_preallocations(struct inode *inode)
struct super_block *sb = inode->i_sb;
struct buffer_head *bitmap_bh = NULL;
struct ext4_prealloc_space *pa, *tmp;
- struct ext4_allocation_context *ac;
ext4_group_t group = 0;
struct list_head list;
struct ext4_buddy e4b;
@@ -3778,11 +3801,6 @@ void ext4_discard_preallocations(struct inode *inode)
INIT_LIST_HEAD(&list);
- ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
- if (ac) {
- ac->ac_sb = sb;
- ac->ac_inode = inode;
- }
repeat:
/* first, collect all pa's in the inode */
spin_lock(&ei->i_prealloc_lock);
@@ -3852,7 +3870,7 @@ repeat:
ext4_lock_group(sb, group);
list_del(&pa->pa_group_list);
- ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa, ac);
+ ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa);
ext4_unlock_group(sb, group);
ext4_mb_unload_buddy(&e4b);
@@ -3861,8 +3879,6 @@ repeat:
list_del(&pa->u.pa_tmp_list);
call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback);
}
- if (ac)
- kmem_cache_free(ext4_ac_cachep, ac);
}
/*
@@ -4060,14 +4076,10 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
struct ext4_buddy e4b;
struct list_head discard_list;
struct ext4_prealloc_space *pa, *tmp;
- struct ext4_allocation_context *ac;
mb_debug(1, "discard locality group preallocation\n");
INIT_LIST_HEAD(&discard_list);
- ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
- if (ac)
- ac->ac_sb = sb;
spin_lock(&lg->lg_prealloc_lock);
list_for_each_entry_rcu(pa, &lg->lg_prealloc_list[order],
@@ -4119,15 +4131,13 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
}
ext4_lock_group(sb, group);
list_del(&pa->pa_group_list);
- ext4_mb_release_group_pa(&e4b, pa, ac);
+ ext4_mb_release_group_pa(&e4b, pa);
ext4_unlock_group(sb, group);
ext4_mb_unload_buddy(&e4b);
list_del(&pa->u.pa_tmp_list);
call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback);
}
- if (ac)
- kmem_cache_free(ext4_ac_cachep, ac);
}
/*
@@ -4491,7 +4501,6 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
{
struct buffer_head *bitmap_bh = NULL;
struct super_block *sb = inode->i_sb;
- struct ext4_allocation_context *ac = NULL;
struct ext4_group_desc *gdp;
unsigned long freed = 0;
unsigned int overflow;
@@ -4531,6 +4540,8 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
if (!bh)
tbh = sb_find_get_block(inode->i_sb,
block + i);
+ if (unlikely(!tbh))
+ continue;
ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA,
inode, tbh, block + i);
}
@@ -4546,12 +4557,6 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
if (!ext4_should_writeback_data(inode))
flags |= EXT4_FREE_BLOCKS_METADATA;
- ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
- if (ac) {
- ac->ac_inode = inode;
- ac->ac_sb = sb;
- }
-
do_more:
overflow = 0;
ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
@@ -4609,12 +4614,7 @@ do_more:
BUG_ON(!mb_test_bit(bit + i, bitmap_bh->b_data));
}
#endif
- if (ac) {
- ac->ac_b_ex.fe_group = block_group;
- ac->ac_b_ex.fe_start = bit;
- ac->ac_b_ex.fe_len = count;
- trace_ext4_mballoc_free(ac);
- }
+ trace_ext4_mballoc_free(sb, inode, block_group, bit, count);
err = ext4_mb_load_buddy(sb, block_group, &e4b);
if (err)
@@ -4640,12 +4640,12 @@ do_more:
* with group lock held. generate_buddy look at
* them with group lock_held
*/
+ if (test_opt(sb, DISCARD))
+ ext4_issue_discard(sb, block_group, bit, count);
ext4_lock_group(sb, block_group);
mb_clear_bits(bitmap_bh->b_data, bit, count);
mb_free_blocks(inode, &e4b, bit, count);
ext4_mb_return_to_preallocation(inode, &e4b, block, count);
- if (test_opt(sb, DISCARD))
- ext4_issue_discard(sb, block_group, bit, count);
}
ret = ext4_free_blks_count(sb, gdp) + count;
@@ -4685,7 +4685,190 @@ error_return:
dquot_free_block(inode, freed);
brelse(bitmap_bh);
ext4_std_error(sb, err);
- if (ac)
- kmem_cache_free(ext4_ac_cachep, ac);
return;
}
+
+/**
+ * ext4_trim_extent -- function to TRIM one single free extent in the group
+ * @sb: super block for the file system
+ * @start: starting block of the free extent in the alloc. group
+ * @count: number of blocks to TRIM
+ * @group: alloc. group we are working with
+ * @e4b: ext4 buddy for the group
+ *
+ * Trim "count" blocks starting at "start" in the "group". To assure that no
+ * one will allocate those blocks, mark it as used in buddy bitmap. This must
+ * be called with under the group lock.
+ */
+static int ext4_trim_extent(struct super_block *sb, int start, int count,
+ ext4_group_t group, struct ext4_buddy *e4b)
+{
+ struct ext4_free_extent ex;
+ int ret = 0;
+
+ assert_spin_locked(ext4_group_lock_ptr(sb, group));
+
+ ex.fe_start = start;
+ ex.fe_group = group;
+ ex.fe_len = count;
+
+ /*
+ * Mark blocks used, so no one can reuse them while
+ * being trimmed.
+ */
+ mb_mark_used(e4b, &ex);
+ ext4_unlock_group(sb, group);
+
+ ret = ext4_issue_discard(sb, group, start, count);
+ if (ret)
+ ext4_std_error(sb, ret);
+
+ ext4_lock_group(sb, group);
+ mb_free_blocks(NULL, e4b, start, ex.fe_len);
+ return ret;
+}
+
+/**
+ * ext4_trim_all_free -- function to trim all free space in alloc. group
+ * @sb: super block for file system
+ * @e4b: ext4 buddy
+ * @start: first group block to examine
+ * @max: last group block to examine
+ * @minblocks: minimum extent block count
+ *
+ * ext4_trim_all_free walks through group's buddy bitmap searching for free
+ * extents. When the free block is found, ext4_trim_extent is called to TRIM
+ * the extent.
+ *
+ *
+ * ext4_trim_all_free walks through group's block bitmap searching for free
+ * extents. When the free extent is found, mark it as used in group buddy
+ * bitmap. Then issue a TRIM command on this extent and free the extent in
+ * the group buddy bitmap. This is done until whole group is scanned.
+ */
+ext4_grpblk_t ext4_trim_all_free(struct super_block *sb, struct ext4_buddy *e4b,
+ ext4_grpblk_t start, ext4_grpblk_t max, ext4_grpblk_t minblocks)
+{
+ void *bitmap;
+ ext4_grpblk_t next, count = 0;
+ ext4_group_t group;
+ int ret = 0;
+
+ BUG_ON(e4b == NULL);
+
+ bitmap = e4b->bd_bitmap;
+ group = e4b->bd_group;
+ start = (e4b->bd_info->bb_first_free > start) ?
+ e4b->bd_info->bb_first_free : start;
+ ext4_lock_group(sb, group);
+
+ while (start < max) {
+ start = mb_find_next_zero_bit(bitmap, max, start);
+ if (start >= max)
+ break;
+ next = mb_find_next_bit(bitmap, max, start);
+
+ if ((next - start) >= minblocks) {
+ ret = ext4_trim_extent(sb, start,
+ next - start, group, e4b);
+ if (ret < 0)
+ break;
+ count += next - start;
+ }
+ start = next + 1;
+
+ if (fatal_signal_pending(current)) {
+ count = -ERESTARTSYS;
+ break;
+ }
+
+ if (need_resched()) {
+ ext4_unlock_group(sb, group);
+ cond_resched();
+ ext4_lock_group(sb, group);
+ }
+
+ if ((e4b->bd_info->bb_free - count) < minblocks)
+ break;
+ }
+ ext4_unlock_group(sb, group);
+
+ ext4_debug("trimmed %d blocks in the group %d\n",
+ count, group);
+
+ if (ret < 0)
+ count = ret;
+
+ return count;
+}
+
+/**
+ * ext4_trim_fs() -- trim ioctl handle function
+ * @sb: superblock for filesystem
+ * @range: fstrim_range structure
+ *
+ * start: First Byte to trim
+ * len: number of Bytes to trim from start
+ * minlen: minimum extent length in Bytes
+ * ext4_trim_fs goes through all allocation groups containing Bytes from
+ * start to start+len. For each such a group ext4_trim_all_free function
+ * is invoked to trim all free space.
+ */
+int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
+{
+ struct ext4_buddy e4b;
+ ext4_group_t first_group, last_group;
+ ext4_group_t group, ngroups = ext4_get_groups_count(sb);
+ ext4_grpblk_t cnt = 0, first_block, last_block;
+ uint64_t start, len, minlen, trimmed;
+ int ret = 0;
+
+ start = range->start >> sb->s_blocksize_bits;
+ len = range->len >> sb->s_blocksize_bits;
+ minlen = range->minlen >> sb->s_blocksize_bits;
+ trimmed = 0;
+
+ if (unlikely(minlen > EXT4_BLOCKS_PER_GROUP(sb)))
+ return -EINVAL;
+
+ /* Determine first and last group to examine based on start and len */
+ ext4_get_group_no_and_offset(sb, (ext4_fsblk_t) start,
+ &first_group, &first_block);
+ ext4_get_group_no_and_offset(sb, (ext4_fsblk_t) (start + len),
+ &last_group, &last_block);
+ last_group = (last_group > ngroups - 1) ? ngroups - 1 : last_group;
+ last_block = EXT4_BLOCKS_PER_GROUP(sb);
+
+ if (first_group > last_group)
+ return -EINVAL;
+
+ for (group = first_group; group <= last_group; group++) {
+ ret = ext4_mb_load_buddy(sb, group, &e4b);
+ if (ret) {
+ ext4_error(sb, "Error in loading buddy "
+ "information for %u", group);
+ break;
+ }
+
+ if (len >= EXT4_BLOCKS_PER_GROUP(sb))
+ len -= (EXT4_BLOCKS_PER_GROUP(sb) - first_block);
+ else
+ last_block = len;
+
+ if (e4b.bd_info->bb_free >= minlen) {
+ cnt = ext4_trim_all_free(sb, &e4b, first_block,
+ last_block, minlen);
+ if (cnt < 0) {
+ ret = cnt;
+ ext4_mb_unload_buddy(&e4b);
+ break;
+ }
+ }
+ ext4_mb_unload_buddy(&e4b);
+ trimmed += cnt;
+ first_block = 0;
+ }
+ range->len = trimmed * sb->s_blocksize;
+
+ return ret;
+}
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
index 1765c2c50a9b..25f3a974b725 100644
--- a/fs/ext4/migrate.c
+++ b/fs/ext4/migrate.c
@@ -412,7 +412,7 @@ static int free_ext_idx(handle_t *handle, struct inode *inode,
struct buffer_head *bh;
struct ext4_extent_header *eh;
- block = idx_pblock(ix);
+ block = ext4_idx_pblock(ix);
bh = sb_bread(inode->i_sb, block);
if (!bh)
return -EIO;
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
index 5f1ed9fc913c..b9f3e7862f13 100644
--- a/fs/ext4/move_extent.c
+++ b/fs/ext4/move_extent.c
@@ -85,7 +85,7 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path,
if (EXT_LAST_EXTENT(path[ppos].p_hdr) > path[ppos].p_ext) {
/* leaf block */
*extent = ++path[ppos].p_ext;
- path[ppos].p_block = ext_pblock(path[ppos].p_ext);
+ path[ppos].p_block = ext4_ext_pblock(path[ppos].p_ext);
return 0;
}
@@ -96,7 +96,7 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path,
/* index block */
path[ppos].p_idx++;
- path[ppos].p_block = idx_pblock(path[ppos].p_idx);
+ path[ppos].p_block = ext4_idx_pblock(path[ppos].p_idx);
if (path[ppos+1].p_bh)
brelse(path[ppos+1].p_bh);
path[ppos+1].p_bh =
@@ -111,7 +111,7 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path,
path[cur_ppos].p_idx =
EXT_FIRST_INDEX(path[cur_ppos].p_hdr);
path[cur_ppos].p_block =
- idx_pblock(path[cur_ppos].p_idx);
+ ext4_idx_pblock(path[cur_ppos].p_idx);
if (path[cur_ppos+1].p_bh)
brelse(path[cur_ppos+1].p_bh);
path[cur_ppos+1].p_bh = sb_bread(inode->i_sb,
@@ -133,7 +133,7 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path,
path[leaf_ppos].p_ext = *extent =
EXT_FIRST_EXTENT(path[leaf_ppos].p_hdr);
path[leaf_ppos].p_block =
- ext_pblock(path[leaf_ppos].p_ext);
+ ext4_ext_pblock(path[leaf_ppos].p_ext);
return 0;
}
}
@@ -249,7 +249,7 @@ mext_insert_across_blocks(handle_t *handle, struct inode *orig_inode,
*/
o_end->ee_block = end_ext->ee_block;
o_end->ee_len = end_ext->ee_len;
- ext4_ext_store_pblock(o_end, ext_pblock(end_ext));
+ ext4_ext_store_pblock(o_end, ext4_ext_pblock(end_ext));
}
o_start->ee_len = start_ext->ee_len;
@@ -276,7 +276,7 @@ mext_insert_across_blocks(handle_t *handle, struct inode *orig_inode,
*/
o_end->ee_block = end_ext->ee_block;
o_end->ee_len = end_ext->ee_len;
- ext4_ext_store_pblock(o_end, ext_pblock(end_ext));
+ ext4_ext_store_pblock(o_end, ext4_ext_pblock(end_ext));
/*
* Set 0 to the extent block if new_ext was
@@ -361,7 +361,7 @@ mext_insert_inside_block(struct ext4_extent *o_start,
/* Insert new entry */
if (new_ext->ee_len) {
o_start[i] = *new_ext;
- ext4_ext_store_pblock(&o_start[i++], ext_pblock(new_ext));
+ ext4_ext_store_pblock(&o_start[i++], ext4_ext_pblock(new_ext));
}
/* Insert end entry */
@@ -488,7 +488,7 @@ mext_leaf_block(handle_t *handle, struct inode *orig_inode,
start_ext.ee_len = end_ext.ee_len = 0;
new_ext.ee_block = cpu_to_le32(*from);
- ext4_ext_store_pblock(&new_ext, ext_pblock(dext));
+ ext4_ext_store_pblock(&new_ext, ext4_ext_pblock(dext));
new_ext.ee_len = dext->ee_len;
new_ext_alen = ext4_ext_get_actual_len(&new_ext);
new_ext_end = le32_to_cpu(new_ext.ee_block) + new_ext_alen - 1;
@@ -553,7 +553,7 @@ mext_leaf_block(handle_t *handle, struct inode *orig_inode,
copy_extent_status(oext, &end_ext);
end_ext_alen = ext4_ext_get_actual_len(&end_ext);
ext4_ext_store_pblock(&end_ext,
- (ext_pblock(o_end) + oext_alen - end_ext_alen));
+ (ext4_ext_pblock(o_end) + oext_alen - end_ext_alen));
end_ext.ee_block =
cpu_to_le32(le32_to_cpu(o_end->ee_block) +
oext_alen - end_ext_alen);
@@ -604,7 +604,7 @@ mext_calc_swap_extents(struct ext4_extent *tmp_dext,
/* When tmp_dext is too large, pick up the target range. */
diff = donor_off - le32_to_cpu(tmp_dext->ee_block);
- ext4_ext_store_pblock(tmp_dext, ext_pblock(tmp_dext) + diff);
+ ext4_ext_store_pblock(tmp_dext, ext4_ext_pblock(tmp_dext) + diff);
tmp_dext->ee_block =
cpu_to_le32(le32_to_cpu(tmp_dext->ee_block) + diff);
tmp_dext->ee_len = cpu_to_le16(le16_to_cpu(tmp_dext->ee_len) - diff);
@@ -613,7 +613,7 @@ mext_calc_swap_extents(struct ext4_extent *tmp_dext,
tmp_dext->ee_len = cpu_to_le16(max_count);
orig_diff = orig_off - le32_to_cpu(tmp_oext->ee_block);
- ext4_ext_store_pblock(tmp_oext, ext_pblock(tmp_oext) + orig_diff);
+ ext4_ext_store_pblock(tmp_oext, ext4_ext_pblock(tmp_oext) + orig_diff);
/* Adjust extent length if donor extent is larger than orig */
if (ext4_ext_get_actual_len(tmp_dext) >
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 314c0d3b3fa9..92203b8a099f 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -856,6 +856,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
struct buffer_head *bh_use[NAMEI_RA_SIZE];
struct buffer_head *bh, *ret = NULL;
ext4_lblk_t start, block, b;
+ const u8 *name = d_name->name;
int ra_max = 0; /* Number of bh's in the readahead
buffer, bh_use[] */
int ra_ptr = 0; /* Current index into readahead
@@ -870,6 +871,16 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
namelen = d_name->len;
if (namelen > EXT4_NAME_LEN)
return NULL;
+ if ((namelen <= 2) && (name[0] == '.') &&
+ (name[1] == '.' || name[1] == '0')) {
+ /*
+ * "." or ".." will only be in the first block
+ * NFS may look up ".."; "." should be handled by the VFS
+ */
+ block = start = 0;
+ nblocks = 1;
+ goto restart;
+ }
if (is_dx(dir)) {
bh = ext4_dx_find_entry(dir, d_name, res_dir, &err);
/*
@@ -960,55 +971,35 @@ cleanup_and_exit:
static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct qstr *d_name,
struct ext4_dir_entry_2 **res_dir, int *err)
{
- struct super_block * sb;
+ struct super_block * sb = dir->i_sb;
struct dx_hash_info hinfo;
- u32 hash;
struct dx_frame frames[2], *frame;
- struct ext4_dir_entry_2 *de, *top;
struct buffer_head *bh;
ext4_lblk_t block;
int retval;
- int namelen = d_name->len;
- const u8 *name = d_name->name;
- sb = dir->i_sb;
- /* NFS may look up ".." - look at dx_root directory block */
- if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){
- if (!(frame = dx_probe(d_name, dir, &hinfo, frames, err)))
- return NULL;
- } else {
- frame = frames;
- frame->bh = NULL; /* for dx_release() */
- frame->at = (struct dx_entry *)frames; /* hack for zero entry*/
- dx_set_block(frame->at, 0); /* dx_root block is 0 */
- }
- hash = hinfo.hash;
+ if (!(frame = dx_probe(d_name, dir, &hinfo, frames, err)))
+ return NULL;
do {
block = dx_get_block(frame->at);
- if (!(bh = ext4_bread (NULL,dir, block, 0, err)))
+ if (!(bh = ext4_bread(NULL, dir, block, 0, err)))
goto errout;
- de = (struct ext4_dir_entry_2 *) bh->b_data;
- top = (struct ext4_dir_entry_2 *) ((char *) de + sb->s_blocksize -
- EXT4_DIR_REC_LEN(0));
- for (; de < top; de = ext4_next_entry(de, sb->s_blocksize)) {
- int off = (block << EXT4_BLOCK_SIZE_BITS(sb))
- + ((char *) de - bh->b_data);
-
- if (!ext4_check_dir_entry(dir, de, bh, off)) {
- brelse(bh);
- *err = ERR_BAD_DX_DIR;
- goto errout;
- }
- if (ext4_match(namelen, name, de)) {
- *res_dir = de;
- dx_release(frames);
- return bh;
- }
+ retval = search_dirblock(bh, dir, d_name,
+ block << EXT4_BLOCK_SIZE_BITS(sb),
+ res_dir);
+ if (retval == 1) { /* Success! */
+ dx_release(frames);
+ return bh;
}
brelse(bh);
+ if (retval == -1) {
+ *err = ERR_BAD_DX_DIR;
+ goto errout;
+ }
+
/* Check to see if we should continue to search */
- retval = ext4_htree_next_block(dir, hash, frame,
+ retval = ext4_htree_next_block(dir, hinfo.hash, frame,
frames, NULL);
if (retval < 0) {
ext4_warning(sb,
@@ -2312,7 +2303,7 @@ retry:
inode->i_ctime = ext4_current_time(inode);
ext4_inc_count(handle, inode);
- atomic_inc(&inode->i_count);
+ ihold(inode);
err = ext4_add_entry(handle, dentry, inode);
if (!err) {
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
new file mode 100644
index 000000000000..46a7d6a9d976
--- /dev/null
+++ b/fs/ext4/page-io.c
@@ -0,0 +1,430 @@
+/*
+ * linux/fs/ext4/page-io.c
+ *
+ * This contains the new page_io functions for ext4
+ *
+ * Written by Theodore Ts'o, 2010.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/jbd2.h>
+#include <linux/highuid.h>
+#include <linux/pagemap.h>
+#include <linux/quotaops.h>
+#include <linux/string.h>
+#include <linux/buffer_head.h>
+#include <linux/writeback.h>
+#include <linux/pagevec.h>
+#include <linux/mpage.h>
+#include <linux/namei.h>
+#include <linux/uio.h>
+#include <linux/bio.h>
+#include <linux/workqueue.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "ext4_jbd2.h"
+#include "xattr.h"
+#include "acl.h"
+#include "ext4_extents.h"
+
+static struct kmem_cache *io_page_cachep, *io_end_cachep;
+
+int __init ext4_init_pageio(void)
+{
+ io_page_cachep = KMEM_CACHE(ext4_io_page, SLAB_RECLAIM_ACCOUNT);
+ if (io_page_cachep == NULL)
+ return -ENOMEM;
+ io_end_cachep = KMEM_CACHE(ext4_io_end, SLAB_RECLAIM_ACCOUNT);
+ if (io_page_cachep == NULL) {
+ kmem_cache_destroy(io_page_cachep);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void ext4_exit_pageio(void)
+{
+ kmem_cache_destroy(io_end_cachep);
+ kmem_cache_destroy(io_page_cachep);
+}
+
+void ext4_free_io_end(ext4_io_end_t *io)
+{
+ int i;
+
+ BUG_ON(!io);
+ if (io->page)
+ put_page(io->page);
+ for (i = 0; i < io->num_io_pages; i++) {
+ if (--io->pages[i]->p_count == 0) {
+ struct page *page = io->pages[i]->p_page;
+
+ end_page_writeback(page);
+ put_page(page);
+ kmem_cache_free(io_page_cachep, io->pages[i]);
+ }
+ }
+ io->num_io_pages = 0;
+ iput(io->inode);
+ kmem_cache_free(io_end_cachep, io);
+}
+
+/*
+ * check a range of space and convert unwritten extents to written.
+ */
+int ext4_end_io_nolock(ext4_io_end_t *io)
+{
+ struct inode *inode = io->inode;
+ loff_t offset = io->offset;
+ ssize_t size = io->size;
+ int ret = 0;
+
+ ext4_debug("ext4_end_io_nolock: io 0x%p from inode %lu,list->next 0x%p,"
+ "list->prev 0x%p\n",
+ io, inode->i_ino, io->list.next, io->list.prev);
+
+ if (list_empty(&io->list))
+ return ret;
+
+ if (!(io->flag & EXT4_IO_END_UNWRITTEN))
+ return ret;
+
+ ret = ext4_convert_unwritten_extents(inode, offset, size);
+ if (ret < 0) {
+ printk(KERN_EMERG "%s: failed to convert unwritten "
+ "extents to written extents, error is %d "
+ "io is still on inode %lu aio dio list\n",
+ __func__, ret, inode->i_ino);
+ return ret;
+ }
+
+ if (io->iocb)
+ aio_complete(io->iocb, io->result, 0);
+ /* clear the DIO AIO unwritten flag */
+ io->flag &= ~EXT4_IO_END_UNWRITTEN;
+ return ret;
+}
+
+/*
+ * work on completed aio dio IO, to convert unwritten extents to extents
+ */
+static void ext4_end_io_work(struct work_struct *work)
+{
+ ext4_io_end_t *io = container_of(work, ext4_io_end_t, work);
+ struct inode *inode = io->inode;
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ unsigned long flags;
+ int ret;
+
+ mutex_lock(&inode->i_mutex);
+ ret = ext4_end_io_nolock(io);
+ if (ret < 0) {
+ mutex_unlock(&inode->i_mutex);
+ return;
+ }
+
+ spin_lock_irqsave(&ei->i_completed_io_lock, flags);
+ if (!list_empty(&io->list))
+ list_del_init(&io->list);
+ spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
+ mutex_unlock(&inode->i_mutex);
+ ext4_free_io_end(io);
+}
+
+ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags)
+{
+ ext4_io_end_t *io = NULL;
+
+ io = kmem_cache_alloc(io_end_cachep, flags);
+ if (io) {
+ memset(io, 0, sizeof(*io));
+ io->inode = igrab(inode);
+ BUG_ON(!io->inode);
+ INIT_WORK(&io->work, ext4_end_io_work);
+ INIT_LIST_HEAD(&io->list);
+ }
+ return io;
+}
+
+/*
+ * Print an buffer I/O error compatible with the fs/buffer.c. This
+ * provides compatibility with dmesg scrapers that look for a specific
+ * buffer I/O error message. We really need a unified error reporting
+ * structure to userspace ala Digital Unix's uerf system, but it's
+ * probably not going to happen in my lifetime, due to LKML politics...
+ */
+static void buffer_io_error(struct buffer_head *bh)
+{
+ char b[BDEVNAME_SIZE];
+ printk(KERN_ERR "Buffer I/O error on device %s, logical block %llu\n",
+ bdevname(bh->b_bdev, b),
+ (unsigned long long)bh->b_blocknr);
+}
+
+static void ext4_end_bio(struct bio *bio, int error)
+{
+ ext4_io_end_t *io_end = bio->bi_private;
+ struct workqueue_struct *wq;
+ struct inode *inode;
+ unsigned long flags;
+ ext4_fsblk_t err_block;
+ int i;
+
+ BUG_ON(!io_end);
+ inode = io_end->inode;
+ bio->bi_private = NULL;
+ bio->bi_end_io = NULL;
+ if (test_bit(BIO_UPTODATE, &bio->bi_flags))
+ error = 0;
+ err_block = bio->bi_sector >> (inode->i_blkbits - 9);
+ bio_put(bio);
+
+ if (!(inode->i_sb->s_flags & MS_ACTIVE)) {
+ pr_err("sb umounted, discard end_io request for inode %lu\n",
+ io_end->inode->i_ino);
+ ext4_free_io_end(io_end);
+ return;
+ }
+
+ if (error) {
+ io_end->flag |= EXT4_IO_END_ERROR;
+ ext4_warning(inode->i_sb, "I/O error writing to inode %lu "
+ "(offset %llu size %ld starting block %llu)",
+ inode->i_ino,
+ (unsigned long long) io_end->offset,
+ (long) io_end->size,
+ (unsigned long long) err_block);
+ }
+
+ for (i = 0; i < io_end->num_io_pages; i++) {
+ struct page *page = io_end->pages[i]->p_page;
+ struct buffer_head *bh, *head;
+ int partial_write = 0;
+
+ head = page_buffers(page);
+ if (error)
+ SetPageError(page);
+ BUG_ON(!head);
+ if (head->b_size == PAGE_CACHE_SIZE)
+ clear_buffer_dirty(head);
+ else {
+ loff_t offset;
+ loff_t io_end_offset = io_end->offset + io_end->size;
+
+ offset = (sector_t) page->index << PAGE_CACHE_SHIFT;
+ bh = head;
+ do {
+ if ((offset >= io_end->offset) &&
+ (offset+bh->b_size <= io_end_offset)) {
+ if (error)
+ buffer_io_error(bh);
+
+ clear_buffer_dirty(bh);
+ }
+ if (buffer_delay(bh))
+ partial_write = 1;
+ else if (!buffer_mapped(bh))
+ clear_buffer_dirty(bh);
+ else if (buffer_dirty(bh))
+ partial_write = 1;
+ offset += bh->b_size;
+ bh = bh->b_this_page;
+ } while (bh != head);
+ }
+
+ if (--io_end->pages[i]->p_count == 0) {
+ struct page *page = io_end->pages[i]->p_page;
+
+ end_page_writeback(page);
+ put_page(page);
+ kmem_cache_free(io_page_cachep, io_end->pages[i]);
+ }
+
+ /*
+ * If this is a partial write which happened to make
+ * all buffers uptodate then we can optimize away a
+ * bogus readpage() for the next read(). Here we
+ * 'discover' whether the page went uptodate as a
+ * result of this (potentially partial) write.
+ */
+ if (!partial_write)
+ SetPageUptodate(page);
+ }
+
+ io_end->num_io_pages = 0;
+
+ /* Add the io_end to per-inode completed io list*/
+ spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags);
+ list_add_tail(&io_end->list, &EXT4_I(inode)->i_completed_io_list);
+ spin_unlock_irqrestore(&EXT4_I(inode)->i_completed_io_lock, flags);
+
+ wq = EXT4_SB(inode->i_sb)->dio_unwritten_wq;
+ /* queue the work to convert unwritten extents to written */
+ queue_work(wq, &io_end->work);
+}
+
+void ext4_io_submit(struct ext4_io_submit *io)
+{
+ struct bio *bio = io->io_bio;
+
+ if (bio) {
+ bio_get(io->io_bio);
+ submit_bio(io->io_op, io->io_bio);
+ BUG_ON(bio_flagged(io->io_bio, BIO_EOPNOTSUPP));
+ bio_put(io->io_bio);
+ }
+ io->io_bio = 0;
+ io->io_op = 0;
+ io->io_end = 0;
+}
+
+static int io_submit_init(struct ext4_io_submit *io,
+ struct inode *inode,
+ struct writeback_control *wbc,
+ struct buffer_head *bh)
+{
+ ext4_io_end_t *io_end;
+ struct page *page = bh->b_page;
+ int nvecs = bio_get_nr_vecs(bh->b_bdev);
+ struct bio *bio;
+
+ io_end = ext4_init_io_end(inode, GFP_NOFS);
+ if (!io_end)
+ return -ENOMEM;
+ do {
+ bio = bio_alloc(GFP_NOIO, nvecs);
+ nvecs >>= 1;
+ } while (bio == NULL);
+
+ bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
+ bio->bi_bdev = bh->b_bdev;
+ bio->bi_private = io->io_end = io_end;
+ bio->bi_end_io = ext4_end_bio;
+
+ io_end->inode = inode;
+ io_end->offset = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh);
+
+ io->io_bio = bio;
+ io->io_op = (wbc->sync_mode == WB_SYNC_ALL ?
+ WRITE_SYNC_PLUG : WRITE);
+ io->io_next_block = bh->b_blocknr;
+ return 0;
+}
+
+static int io_submit_add_bh(struct ext4_io_submit *io,
+ struct ext4_io_page *io_page,
+ struct inode *inode,
+ struct writeback_control *wbc,
+ struct buffer_head *bh)
+{
+ ext4_io_end_t *io_end;
+ int ret;
+
+ if (buffer_new(bh)) {
+ clear_buffer_new(bh);
+ unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr);
+ }
+
+ if (!buffer_mapped(bh) || buffer_delay(bh)) {
+ if (!buffer_mapped(bh))
+ clear_buffer_dirty(bh);
+ if (io->io_bio)
+ ext4_io_submit(io);
+ return 0;
+ }
+
+ if (io->io_bio && bh->b_blocknr != io->io_next_block) {
+submit_and_retry:
+ ext4_io_submit(io);
+ }
+ if (io->io_bio == NULL) {
+ ret = io_submit_init(io, inode, wbc, bh);
+ if (ret)
+ return ret;
+ }
+ io_end = io->io_end;
+ if ((io_end->num_io_pages >= MAX_IO_PAGES) &&
+ (io_end->pages[io_end->num_io_pages-1] != io_page))
+ goto submit_and_retry;
+ if (buffer_uninit(bh))
+ io->io_end->flag |= EXT4_IO_END_UNWRITTEN;
+ io->io_end->size += bh->b_size;
+ io->io_next_block++;
+ ret = bio_add_page(io->io_bio, bh->b_page, bh->b_size, bh_offset(bh));
+ if (ret != bh->b_size)
+ goto submit_and_retry;
+ if ((io_end->num_io_pages == 0) ||
+ (io_end->pages[io_end->num_io_pages-1] != io_page)) {
+ io_end->pages[io_end->num_io_pages++] = io_page;
+ io_page->p_count++;
+ }
+ return 0;
+}
+
+int ext4_bio_write_page(struct ext4_io_submit *io,
+ struct page *page,
+ int len,
+ struct writeback_control *wbc)
+{
+ struct inode *inode = page->mapping->host;
+ unsigned block_start, block_end, blocksize;
+ struct ext4_io_page *io_page;
+ struct buffer_head *bh, *head;
+ int ret = 0;
+
+ blocksize = 1 << inode->i_blkbits;
+
+ BUG_ON(PageWriteback(page));
+ set_page_writeback(page);
+ ClearPageError(page);
+
+ io_page = kmem_cache_alloc(io_page_cachep, GFP_NOFS);
+ if (!io_page) {
+ set_page_dirty(page);
+ unlock_page(page);
+ return -ENOMEM;
+ }
+ io_page->p_page = page;
+ io_page->p_count = 0;
+ get_page(page);
+
+ for (bh = head = page_buffers(page), block_start = 0;
+ bh != head || !block_start;
+ block_start = block_end, bh = bh->b_this_page) {
+ block_end = block_start + blocksize;
+ if (block_start >= len) {
+ clear_buffer_dirty(bh);
+ set_buffer_uptodate(bh);
+ continue;
+ }
+ ret = io_submit_add_bh(io, io_page, inode, wbc, bh);
+ if (ret) {
+ /*
+ * We only get here on ENOMEM. Not much else
+ * we can do but mark the page as dirty, and
+ * better luck next time.
+ */
+ set_page_dirty(page);
+ break;
+ }
+ }
+ unlock_page(page);
+ /*
+ * If the page was truncated before we could do the writeback,
+ * or we had a memory allocation error while trying to write
+ * the first buffer head, we won't have submitted any pages for
+ * I/O. In that case we need to make sure we've cleared the
+ * PageWriteback bit from the page to prevent the system from
+ * wedging later on.
+ */
+ if (io_page->p_count == 0) {
+ put_page(page);
+ end_page_writeback(page);
+ kmem_cache_free(io_page_cachep, io_page);
+ }
+ return ret;
+}
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index ca5c8aa00a2f..dc963929de65 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -226,23 +226,13 @@ static int setup_new_group_blocks(struct super_block *sb,
}
/* Zero out all of the reserved backup group descriptor table blocks */
- for (i = 0, bit = gdblocks + 1, block = start + bit;
- i < reserved_gdb; i++, block++, bit++) {
- struct buffer_head *gdb;
-
- ext4_debug("clear reserved block %#04llx (+%d)\n", block, bit);
-
- if ((err = extend_or_restart_transaction(handle, 1, bh)))
- goto exit_bh;
+ ext4_debug("clear inode table blocks %#04llx -> %#04llx\n",
+ block, sbi->s_itb_per_group);
+ err = sb_issue_zeroout(sb, gdblocks + start + 1, reserved_gdb,
+ GFP_NOFS);
+ if (err)
+ goto exit_bh;
- if (IS_ERR(gdb = bclean(handle, sb, block))) {
- err = PTR_ERR(gdb);
- goto exit_bh;
- }
- ext4_handle_dirty_metadata(handle, NULL, gdb);
- ext4_set_bit(bit, bh->b_data);
- brelse(gdb);
- }
ext4_debug("mark block bitmap %#04llx (+%llu)\n", input->block_bitmap,
input->block_bitmap - start);
ext4_set_bit(input->block_bitmap - start, bh->b_data);
@@ -251,28 +241,18 @@ static int setup_new_group_blocks(struct super_block *sb,
ext4_set_bit(input->inode_bitmap - start, bh->b_data);
/* Zero out all of the inode table blocks */
- for (i = 0, block = input->inode_table, bit = block - start;
- i < sbi->s_itb_per_group; i++, bit++, block++) {
- struct buffer_head *it;
-
- ext4_debug("clear inode block %#04llx (+%d)\n", block, bit);
-
- if ((err = extend_or_restart_transaction(handle, 1, bh)))
- goto exit_bh;
-
- if (IS_ERR(it = bclean(handle, sb, block))) {
- err = PTR_ERR(it);
- goto exit_bh;
- }
- ext4_handle_dirty_metadata(handle, NULL, it);
- brelse(it);
- ext4_set_bit(bit, bh->b_data);
- }
+ block = input->inode_table;
+ ext4_debug("clear inode table blocks %#04llx -> %#04llx\n",
+ block, sbi->s_itb_per_group);
+ err = sb_issue_zeroout(sb, block, sbi->s_itb_per_group, GFP_NOFS);
+ if (err)
+ goto exit_bh;
if ((err = extend_or_restart_transaction(handle, 2, bh)))
goto exit_bh;
- mark_bitmap_end(input->blocks_count, sb->s_blocksize * 8, bh->b_data);
+ ext4_mark_bitmap_end(input->blocks_count, sb->s_blocksize * 8,
+ bh->b_data);
ext4_handle_dirty_metadata(handle, NULL, bh);
brelse(bh);
/* Mark unused entries in inode bitmap used */
@@ -283,8 +263,8 @@ static int setup_new_group_blocks(struct super_block *sb,
goto exit_journal;
}
- mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8,
- bh->b_data);
+ ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8,
+ bh->b_data);
ext4_handle_dirty_metadata(handle, NULL, bh);
exit_bh:
brelse(bh);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 8ecc1e590303..0348ce066592 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -40,6 +40,9 @@
#include <linux/crc16.h>
#include <asm/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
#include "ext4.h"
#include "ext4_jbd2.h"
#include "xattr.h"
@@ -49,8 +52,11 @@
#define CREATE_TRACE_POINTS
#include <trace/events/ext4.h>
-struct proc_dir_entry *ext4_proc_root;
+static struct proc_dir_entry *ext4_proc_root;
static struct kset *ext4_kset;
+struct ext4_lazy_init *ext4_li_info;
+struct mutex ext4_li_mtx;
+struct ext4_features *ext4_feat;
static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
unsigned long journal_devnum);
@@ -69,6 +75,8 @@ static void ext4_write_super(struct super_block *sb);
static int ext4_freeze(struct super_block *sb);
static int ext4_get_sb(struct file_system_type *fs_type, int flags,
const char *dev_name, void *data, struct vfsmount *mnt);
+static void ext4_destroy_lazyinit_thread(void);
+static void ext4_unregister_li_request(struct super_block *sb);
#if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23)
static struct file_system_type ext3_fs_type = {
@@ -701,6 +709,7 @@ static void ext4_put_super(struct super_block *sb)
struct ext4_super_block *es = sbi->s_es;
int i, err;
+ ext4_unregister_li_request(sb);
dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
flush_workqueue(sbi->dio_unwritten_wq);
@@ -717,6 +726,7 @@ static void ext4_put_super(struct super_block *sb)
ext4_abort(sb, "Couldn't clean up the journal");
}
+ del_timer(&sbi->s_err_report);
ext4_release_system_zone(sb);
ext4_mb_release(sb);
ext4_ext_release(sb);
@@ -1042,6 +1052,12 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
!(def_mount_opts & EXT4_DEFM_BLOCK_VALIDITY))
seq_puts(seq, ",block_validity");
+ if (!test_opt(sb, INIT_INODE_TABLE))
+ seq_puts(seq, ",noinit_inode_table");
+ else if (sbi->s_li_wait_mult)
+ seq_printf(seq, ",init_inode_table=%u",
+ (unsigned) sbi->s_li_wait_mult);
+
ext4_show_quota_options(seq, sb);
return 0;
@@ -1170,6 +1186,7 @@ static const struct super_operations ext4_sops = {
.quota_write = ext4_quota_write,
#endif
.bdev_try_to_free_page = bdev_try_to_free_page,
+ .trim_fs = ext4_trim_fs
};
static const struct super_operations ext4_nojournal_sops = {
@@ -1216,6 +1233,7 @@ enum {
Opt_inode_readahead_blks, Opt_journal_ioprio,
Opt_dioread_nolock, Opt_dioread_lock,
Opt_discard, Opt_nodiscard,
+ Opt_init_inode_table, Opt_noinit_inode_table,
};
static const match_table_t tokens = {
@@ -1286,6 +1304,9 @@ static const match_table_t tokens = {
{Opt_dioread_lock, "dioread_lock"},
{Opt_discard, "discard"},
{Opt_nodiscard, "nodiscard"},
+ {Opt_init_inode_table, "init_itable=%u"},
+ {Opt_init_inode_table, "init_itable"},
+ {Opt_noinit_inode_table, "noinit_itable"},
{Opt_err, NULL},
};
@@ -1756,6 +1777,20 @@ set_qf_format:
case Opt_dioread_lock:
clear_opt(sbi->s_mount_opt, DIOREAD_NOLOCK);
break;
+ case Opt_init_inode_table:
+ set_opt(sbi->s_mount_opt, INIT_INODE_TABLE);
+ if (args[0].from) {
+ if (match_int(&args[0], &option))
+ return 0;
+ } else
+ option = EXT4_DEF_LI_WAIT_MULT;
+ if (option < 0)
+ return 0;
+ sbi->s_li_wait_mult = option;
+ break;
+ case Opt_noinit_inode_table:
+ clear_opt(sbi->s_mount_opt, INIT_INODE_TABLE);
+ break;
default:
ext4_msg(sb, KERN_ERR,
"Unrecognized mount option \"%s\" "
@@ -1939,7 +1974,8 @@ int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 block_group,
}
/* Called at mount-time, super-block is locked */
-static int ext4_check_descriptors(struct super_block *sb)
+static int ext4_check_descriptors(struct super_block *sb,
+ ext4_group_t *first_not_zeroed)
{
struct ext4_sb_info *sbi = EXT4_SB(sb);
ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
@@ -1948,7 +1984,7 @@ static int ext4_check_descriptors(struct super_block *sb)
ext4_fsblk_t inode_bitmap;
ext4_fsblk_t inode_table;
int flexbg_flag = 0;
- ext4_group_t i;
+ ext4_group_t i, grp = sbi->s_groups_count;
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
flexbg_flag = 1;
@@ -1964,6 +2000,10 @@ static int ext4_check_descriptors(struct super_block *sb)
last_block = first_block +
(EXT4_BLOCKS_PER_GROUP(sb) - 1);
+ if ((grp == sbi->s_groups_count) &&
+ !(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)))
+ grp = i;
+
block_bitmap = ext4_block_bitmap(sb, gdp);
if (block_bitmap < first_block || block_bitmap > last_block) {
ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
@@ -2001,6 +2041,8 @@ static int ext4_check_descriptors(struct super_block *sb)
if (!flexbg_flag)
first_block += EXT4_BLOCKS_PER_GROUP(sb);
}
+ if (NULL != first_not_zeroed)
+ *first_not_zeroed = grp;
ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb));
sbi->s_es->s_free_inodes_count =cpu_to_le32(ext4_count_free_inodes(sb));
@@ -2373,6 +2415,7 @@ static struct ext4_attr ext4_attr_##_name = { \
#define EXT4_ATTR(name, mode, show, store) \
static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store)
+#define EXT4_INFO_ATTR(name) EXT4_ATTR(name, 0444, NULL, NULL)
#define EXT4_RO_ATTR(name) EXT4_ATTR(name, 0444, name##_show, NULL)
#define EXT4_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store)
#define EXT4_RW_ATTR_SBI_UI(name, elname) \
@@ -2409,6 +2452,16 @@ static struct attribute *ext4_attrs[] = {
NULL,
};
+/* Features this copy of ext4 supports */
+EXT4_INFO_ATTR(lazy_itable_init);
+EXT4_INFO_ATTR(batched_discard);
+
+static struct attribute *ext4_feat_attrs[] = {
+ ATTR_LIST(lazy_itable_init),
+ ATTR_LIST(batched_discard),
+ NULL,
+};
+
static ssize_t ext4_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
@@ -2437,7 +2490,6 @@ static void ext4_sb_release(struct kobject *kobj)
complete(&sbi->s_kobj_unregister);
}
-
static const struct sysfs_ops ext4_attr_ops = {
.show = ext4_attr_show,
.store = ext4_attr_store,
@@ -2449,6 +2501,17 @@ static struct kobj_type ext4_ktype = {
.release = ext4_sb_release,
};
+static void ext4_feat_release(struct kobject *kobj)
+{
+ complete(&ext4_feat->f_kobj_unregister);
+}
+
+static struct kobj_type ext4_feat_ktype = {
+ .default_attrs = ext4_feat_attrs,
+ .sysfs_ops = &ext4_attr_ops,
+ .release = ext4_feat_release,
+};
+
/*
* Check whether this filesystem can be mounted based on
* the features present and the RDONLY/RDWR mount requested.
@@ -2539,6 +2602,372 @@ static void print_daily_error_info(unsigned long arg)
mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ); /* Once a day */
}
+static void ext4_lazyinode_timeout(unsigned long data)
+{
+ struct task_struct *p = (struct task_struct *)data;
+ wake_up_process(p);
+}
+
+/* Find next suitable group and run ext4_init_inode_table */
+static int ext4_run_li_request(struct ext4_li_request *elr)
+{
+ struct ext4_group_desc *gdp = NULL;
+ ext4_group_t group, ngroups;
+ struct super_block *sb;
+ unsigned long timeout = 0;
+ int ret = 0;
+
+ sb = elr->lr_super;
+ ngroups = EXT4_SB(sb)->s_groups_count;
+
+ for (group = elr->lr_next_group; group < ngroups; group++) {
+ gdp = ext4_get_group_desc(sb, group, NULL);
+ if (!gdp) {
+ ret = 1;
+ break;
+ }
+
+ if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)))
+ break;
+ }
+
+ if (group == ngroups)
+ ret = 1;
+
+ if (!ret) {
+ timeout = jiffies;
+ ret = ext4_init_inode_table(sb, group,
+ elr->lr_timeout ? 0 : 1);
+ if (elr->lr_timeout == 0) {
+ timeout = jiffies - timeout;
+ if (elr->lr_sbi->s_li_wait_mult)
+ timeout *= elr->lr_sbi->s_li_wait_mult;
+ else
+ timeout *= 20;
+ elr->lr_timeout = timeout;
+ }
+ elr->lr_next_sched = jiffies + elr->lr_timeout;
+ elr->lr_next_group = group + 1;
+ }
+
+ return ret;
+}
+
+/*
+ * Remove lr_request from the list_request and free the
+ * request tructure. Should be called with li_list_mtx held
+ */
+static void ext4_remove_li_request(struct ext4_li_request *elr)
+{
+ struct ext4_sb_info *sbi;
+
+ if (!elr)
+ return;
+
+ sbi = elr->lr_sbi;
+
+ list_del(&elr->lr_request);
+ sbi->s_li_request = NULL;
+ kfree(elr);
+}
+
+static void ext4_unregister_li_request(struct super_block *sb)
+{
+ struct ext4_li_request *elr = EXT4_SB(sb)->s_li_request;
+
+ if (!ext4_li_info)
+ return;
+
+ mutex_lock(&ext4_li_info->li_list_mtx);
+ ext4_remove_li_request(elr);
+ mutex_unlock(&ext4_li_info->li_list_mtx);
+}
+
+/*
+ * This is the function where ext4lazyinit thread lives. It walks
+ * through the request list searching for next scheduled filesystem.
+ * When such a fs is found, run the lazy initialization request
+ * (ext4_rn_li_request) and keep track of the time spend in this
+ * function. Based on that time we compute next schedule time of
+ * the request. When walking through the list is complete, compute
+ * next waking time and put itself into sleep.
+ */
+static int ext4_lazyinit_thread(void *arg)
+{
+ struct ext4_lazy_init *eli = (struct ext4_lazy_init *)arg;
+ struct list_head *pos, *n;
+ struct ext4_li_request *elr;
+ unsigned long next_wakeup;
+ DEFINE_WAIT(wait);
+ int ret;
+
+ BUG_ON(NULL == eli);
+
+ eli->li_timer.data = (unsigned long)current;
+ eli->li_timer.function = ext4_lazyinode_timeout;
+
+ eli->li_task = current;
+ wake_up(&eli->li_wait_task);
+
+cont_thread:
+ while (true) {
+ next_wakeup = MAX_JIFFY_OFFSET;
+
+ mutex_lock(&eli->li_list_mtx);
+ if (list_empty(&eli->li_request_list)) {
+ mutex_unlock(&eli->li_list_mtx);
+ goto exit_thread;
+ }
+
+ list_for_each_safe(pos, n, &eli->li_request_list) {
+ elr = list_entry(pos, struct ext4_li_request,
+ lr_request);
+
+ if (time_after_eq(jiffies, elr->lr_next_sched))
+ ret = ext4_run_li_request(elr);
+
+ if (ret) {
+ ret = 0;
+ ext4_remove_li_request(elr);
+ continue;
+ }
+
+ if (time_before(elr->lr_next_sched, next_wakeup))
+ next_wakeup = elr->lr_next_sched;
+ }
+ mutex_unlock(&eli->li_list_mtx);
+
+ if (freezing(current))
+ refrigerator();
+
+ if (time_after_eq(jiffies, next_wakeup)) {
+ cond_resched();
+ continue;
+ }
+
+ eli->li_timer.expires = next_wakeup;
+ add_timer(&eli->li_timer);
+ prepare_to_wait(&eli->li_wait_daemon, &wait,
+ TASK_INTERRUPTIBLE);
+ if (time_before(jiffies, next_wakeup))
+ schedule();
+ finish_wait(&eli->li_wait_daemon, &wait);
+ }
+
+exit_thread:
+ /*
+ * It looks like the request list is empty, but we need
+ * to check it under the li_list_mtx lock, to prevent any
+ * additions into it, and of course we should lock ext4_li_mtx
+ * to atomically free the list and ext4_li_info, because at
+ * this point another ext4 filesystem could be registering
+ * new one.
+ */
+ mutex_lock(&ext4_li_mtx);
+ mutex_lock(&eli->li_list_mtx);
+ if (!list_empty(&eli->li_request_list)) {
+ mutex_unlock(&eli->li_list_mtx);
+ mutex_unlock(&ext4_li_mtx);
+ goto cont_thread;
+ }
+ mutex_unlock(&eli->li_list_mtx);
+ del_timer_sync(&ext4_li_info->li_timer);
+ eli->li_task = NULL;
+ wake_up(&eli->li_wait_task);
+
+ kfree(ext4_li_info);
+ ext4_li_info = NULL;
+ mutex_unlock(&ext4_li_mtx);
+
+ return 0;
+}
+
+static void ext4_clear_request_list(void)
+{
+ struct list_head *pos, *n;
+ struct ext4_li_request *elr;
+
+ mutex_lock(&ext4_li_info->li_list_mtx);
+ if (list_empty(&ext4_li_info->li_request_list))
+ return;
+
+ list_for_each_safe(pos, n, &ext4_li_info->li_request_list) {
+ elr = list_entry(pos, struct ext4_li_request,
+ lr_request);
+ ext4_remove_li_request(elr);
+ }
+ mutex_unlock(&ext4_li_info->li_list_mtx);
+}
+
+static int ext4_run_lazyinit_thread(void)
+{
+ struct task_struct *t;
+
+ t = kthread_run(ext4_lazyinit_thread, ext4_li_info, "ext4lazyinit");
+ if (IS_ERR(t)) {
+ int err = PTR_ERR(t);
+ ext4_clear_request_list();
+ del_timer_sync(&ext4_li_info->li_timer);
+ kfree(ext4_li_info);
+ ext4_li_info = NULL;
+ printk(KERN_CRIT "EXT4: error %d creating inode table "
+ "initialization thread\n",
+ err);
+ return err;
+ }
+ ext4_li_info->li_state |= EXT4_LAZYINIT_RUNNING;
+
+ wait_event(ext4_li_info->li_wait_task, ext4_li_info->li_task != NULL);
+ return 0;
+}
+
+/*
+ * Check whether it make sense to run itable init. thread or not.
+ * If there is at least one uninitialized inode table, return
+ * corresponding group number, else the loop goes through all
+ * groups and return total number of groups.
+ */
+static ext4_group_t ext4_has_uninit_itable(struct super_block *sb)
+{
+ ext4_group_t group, ngroups = EXT4_SB(sb)->s_groups_count;
+ struct ext4_group_desc *gdp = NULL;
+
+ for (group = 0; group < ngroups; group++) {
+ gdp = ext4_get_group_desc(sb, group, NULL);
+ if (!gdp)
+ continue;
+
+ if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)))
+ break;
+ }
+
+ return group;
+}
+
+static int ext4_li_info_new(void)
+{
+ struct ext4_lazy_init *eli = NULL;
+
+ eli = kzalloc(sizeof(*eli), GFP_KERNEL);
+ if (!eli)
+ return -ENOMEM;
+
+ eli->li_task = NULL;
+ INIT_LIST_HEAD(&eli->li_request_list);
+ mutex_init(&eli->li_list_mtx);
+
+ init_waitqueue_head(&eli->li_wait_daemon);
+ init_waitqueue_head(&eli->li_wait_task);
+ init_timer(&eli->li_timer);
+ eli->li_state |= EXT4_LAZYINIT_QUIT;
+
+ ext4_li_info = eli;
+
+ return 0;
+}
+
+static struct ext4_li_request *ext4_li_request_new(struct super_block *sb,
+ ext4_group_t start)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ struct ext4_li_request *elr;
+ unsigned long rnd;
+
+ elr = kzalloc(sizeof(*elr), GFP_KERNEL);
+ if (!elr)
+ return NULL;
+
+ elr->lr_super = sb;
+ elr->lr_sbi = sbi;
+ elr->lr_next_group = start;
+
+ /*
+ * Randomize first schedule time of the request to
+ * spread the inode table initialization requests
+ * better.
+ */
+ get_random_bytes(&rnd, sizeof(rnd));
+ elr->lr_next_sched = jiffies + (unsigned long)rnd %
+ (EXT4_DEF_LI_MAX_START_DELAY * HZ);
+
+ return elr;
+}
+
+static int ext4_register_li_request(struct super_block *sb,
+ ext4_group_t first_not_zeroed)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ struct ext4_li_request *elr;
+ ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
+ int ret;
+
+ if (sbi->s_li_request != NULL)
+ return 0;
+
+ if (first_not_zeroed == ngroups ||
+ (sb->s_flags & MS_RDONLY) ||
+ !test_opt(sb, INIT_INODE_TABLE)) {
+ sbi->s_li_request = NULL;
+ return 0;
+ }
+
+ if (first_not_zeroed == ngroups) {
+ sbi->s_li_request = NULL;
+ return 0;
+ }
+
+ elr = ext4_li_request_new(sb, first_not_zeroed);
+ if (!elr)
+ return -ENOMEM;
+
+ mutex_lock(&ext4_li_mtx);
+
+ if (NULL == ext4_li_info) {
+ ret = ext4_li_info_new();
+ if (ret)
+ goto out;
+ }
+
+ mutex_lock(&ext4_li_info->li_list_mtx);
+ list_add(&elr->lr_request, &ext4_li_info->li_request_list);
+ mutex_unlock(&ext4_li_info->li_list_mtx);
+
+ sbi->s_li_request = elr;
+
+ if (!(ext4_li_info->li_state & EXT4_LAZYINIT_RUNNING)) {
+ ret = ext4_run_lazyinit_thread();
+ if (ret)
+ goto out;
+ }
+out:
+ mutex_unlock(&ext4_li_mtx);
+ if (ret)
+ kfree(elr);
+ return ret;
+}
+
+/*
+ * We do not need to lock anything since this is called on
+ * module unload.
+ */
+static void ext4_destroy_lazyinit_thread(void)
+{
+ /*
+ * If thread exited earlier
+ * there's nothing to be done.
+ */
+ if (!ext4_li_info)
+ return;
+
+ ext4_clear_request_list();
+
+ while (ext4_li_info->li_task) {
+ wake_up(&ext4_li_info->li_wait_daemon);
+ wait_event(ext4_li_info->li_wait_task,
+ ext4_li_info->li_task == NULL);
+ }
+}
+
static int ext4_fill_super(struct super_block *sb, void *data, int silent)
__releases(kernel_lock)
__acquires(kernel_lock)
@@ -2564,6 +2993,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
__u64 blocks_count;
int err;
unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
+ ext4_group_t first_not_zeroed;
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
@@ -2624,6 +3054,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
/* Set defaults before we parse the mount options */
def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
+ set_opt(sbi->s_mount_opt, INIT_INODE_TABLE);
if (def_mount_opts & EXT4_DEFM_DEBUG)
set_opt(sbi->s_mount_opt, DEBUG);
if (def_mount_opts & EXT4_DEFM_BSDGROUPS) {
@@ -2901,7 +3332,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
goto failed_mount2;
}
}
- if (!ext4_check_descriptors(sb)) {
+ if (!ext4_check_descriptors(sb, &first_not_zeroed)) {
ext4_msg(sb, KERN_ERR, "group descriptors corrupted!");
goto failed_mount2;
}
@@ -3122,6 +3553,10 @@ no_journal:
goto failed_mount4;
}
+ err = ext4_register_li_request(sb, first_not_zeroed);
+ if (err)
+ goto failed_mount4;
+
sbi->s_kobj.kset = ext4_kset;
init_completion(&sbi->s_kobj_unregister);
err = kobject_init_and_add(&sbi->s_kobj, &ext4_ktype, NULL,
@@ -3461,7 +3896,7 @@ static int ext4_load_journal(struct super_block *sb,
EXT4_SB(sb)->s_journal = journal;
ext4_clear_journal_err(sb, es);
- if (journal_devnum &&
+ if (!really_read_only && journal_devnum &&
journal_devnum != le32_to_cpu(es->s_journal_dev)) {
es->s_journal_dev = cpu_to_le32(journal_devnum);
@@ -3514,9 +3949,12 @@ static int ext4_commit_super(struct super_block *sb, int sync)
else
es->s_kbytes_written =
cpu_to_le64(EXT4_SB(sb)->s_kbytes_written);
- ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
+ if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeblocks_counter))
+ ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
&EXT4_SB(sb)->s_freeblocks_counter));
- es->s_free_inodes_count = cpu_to_le32(percpu_counter_sum_positive(
+ if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeinodes_counter))
+ es->s_free_inodes_count =
+ cpu_to_le32(percpu_counter_sum_positive(
&EXT4_SB(sb)->s_freeinodes_counter));
sb->s_dirt = 0;
BUFFER_TRACE(sbh, "marking dirty");
@@ -3835,6 +4273,19 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
enable_quota = 1;
}
}
+
+ /*
+ * Reinitialize lazy itable initialization thread based on
+ * current settings
+ */
+ if ((sb->s_flags & MS_RDONLY) || !test_opt(sb, INIT_INODE_TABLE))
+ ext4_unregister_li_request(sb);
+ else {
+ ext4_group_t first_not_zeroed;
+ first_not_zeroed = ext4_has_uninit_itable(sb);
+ ext4_register_li_request(sb, first_not_zeroed);
+ }
+
ext4_setup_system_zone(sb);
if (sbi->s_journal == NULL)
ext4_commit_super(sb, 1);
@@ -4276,23 +4727,53 @@ static struct file_system_type ext4_fs_type = {
.fs_flags = FS_REQUIRES_DEV,
};
-static int __init init_ext4_fs(void)
+int __init ext4_init_feat_adverts(void)
+{
+ struct ext4_features *ef;
+ int ret = -ENOMEM;
+
+ ef = kzalloc(sizeof(struct ext4_features), GFP_KERNEL);
+ if (!ef)
+ goto out;
+
+ ef->f_kobj.kset = ext4_kset;
+ init_completion(&ef->f_kobj_unregister);
+ ret = kobject_init_and_add(&ef->f_kobj, &ext4_feat_ktype, NULL,
+ "features");
+ if (ret) {
+ kfree(ef);
+ goto out;
+ }
+
+ ext4_feat = ef;
+ ret = 0;
+out:
+ return ret;
+}
+
+static int __init ext4_init_fs(void)
{
int err;
ext4_check_flag_values();
- err = init_ext4_system_zone();
+ err = ext4_init_pageio();
if (err)
return err;
+ err = ext4_init_system_zone();
+ if (err)
+ goto out5;
ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj);
if (!ext4_kset)
goto out4;
ext4_proc_root = proc_mkdir("fs/ext4", NULL);
- err = init_ext4_mballoc();
+
+ err = ext4_init_feat_adverts();
+
+ err = ext4_init_mballoc();
if (err)
goto out3;
- err = init_ext4_xattr();
+ err = ext4_init_xattr();
if (err)
goto out2;
err = init_inodecache();
@@ -4303,38 +4784,46 @@ static int __init init_ext4_fs(void)
err = register_filesystem(&ext4_fs_type);
if (err)
goto out;
+
+ ext4_li_info = NULL;
+ mutex_init(&ext4_li_mtx);
return 0;
out:
unregister_as_ext2();
unregister_as_ext3();
destroy_inodecache();
out1:
- exit_ext4_xattr();
+ ext4_exit_xattr();
out2:
- exit_ext4_mballoc();
+ ext4_exit_mballoc();
out3:
+ kfree(ext4_feat);
remove_proc_entry("fs/ext4", NULL);
kset_unregister(ext4_kset);
out4:
- exit_ext4_system_zone();
+ ext4_exit_system_zone();
+out5:
+ ext4_exit_pageio();
return err;
}
-static void __exit exit_ext4_fs(void)
+static void __exit ext4_exit_fs(void)
{
+ ext4_destroy_lazyinit_thread();
unregister_as_ext2();
unregister_as_ext3();
unregister_filesystem(&ext4_fs_type);
destroy_inodecache();
- exit_ext4_xattr();
- exit_ext4_mballoc();
+ ext4_exit_xattr();
+ ext4_exit_mballoc();
remove_proc_entry("fs/ext4", NULL);
kset_unregister(ext4_kset);
- exit_ext4_system_zone();
+ ext4_exit_system_zone();
+ ext4_exit_pageio();
}
MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
MODULE_DESCRIPTION("Fourth Extended Filesystem");
MODULE_LICENSE("GPL");
-module_init(init_ext4_fs)
-module_exit(exit_ext4_fs)
+module_init(ext4_init_fs)
+module_exit(ext4_exit_fs)
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 3a8cd8dff1ad..fa4b899da4b3 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -1588,7 +1588,7 @@ static void ext4_xattr_rehash(struct ext4_xattr_header *header,
#undef BLOCK_HASH_SHIFT
int __init
-init_ext4_xattr(void)
+ext4_init_xattr(void)
{
ext4_xattr_cache = mb_cache_create("ext4_xattr", 6);
if (!ext4_xattr_cache)
@@ -1597,7 +1597,7 @@ init_ext4_xattr(void)
}
void
-exit_ext4_xattr(void)
+ext4_exit_xattr(void)
{
if (ext4_xattr_cache)
mb_cache_destroy(ext4_xattr_cache);
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
index 518e96e43905..1ef16520b950 100644
--- a/fs/ext4/xattr.h
+++ b/fs/ext4/xattr.h
@@ -83,8 +83,8 @@ extern void ext4_xattr_put_super(struct super_block *);
extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
struct ext4_inode *raw_inode, handle_t *handle);
-extern int init_ext4_xattr(void);
-extern void exit_ext4_xattr(void);
+extern int __init ext4_init_xattr(void);
+extern void ext4_exit_xattr(void);
extern const struct xattr_handler *ext4_xattr_handlers[];
@@ -121,14 +121,14 @@ ext4_xattr_put_super(struct super_block *sb)
{
}
-static inline int
-init_ext4_xattr(void)
+static __init inline int
+ext4_init_xattr(void)
{
return 0;
}
static inline void
-exit_ext4_xattr(void)
+ext4_exit_xattr(void)
{
}
diff --git a/fs/fcntl.c b/fs/fcntl.c
index f8cc34f542c3..ecc8b3954ed6 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -640,7 +640,7 @@ static void fasync_free_rcu(struct rcu_head *head)
* match the state "is the filp on a fasync list".
*
*/
-static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
+int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
{
struct fasync_struct *fa, **fp;
int result = 0;
@@ -666,21 +666,31 @@ static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
return result;
}
+struct fasync_struct *fasync_alloc(void)
+{
+ return kmem_cache_alloc(fasync_cache, GFP_KERNEL);
+}
+
/*
- * Add a fasync entry. Return negative on error, positive if
- * added, and zero if did nothing but change an existing one.
+ * NOTE! This can be used only for unused fasync entries:
+ * entries that actually got inserted on the fasync list
+ * need to be released by rcu - see fasync_remove_entry.
+ */
+void fasync_free(struct fasync_struct *new)
+{
+ kmem_cache_free(fasync_cache, new);
+}
+
+/*
+ * Insert a new entry into the fasync list. Return the pointer to the
+ * old one if we didn't use the new one.
*
* NOTE! It is very important that the FASYNC flag always
* match the state "is the filp on a fasync list".
*/
-static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fapp)
+struct fasync_struct *fasync_insert_entry(int fd, struct file *filp, struct fasync_struct **fapp, struct fasync_struct *new)
{
- struct fasync_struct *new, *fa, **fp;
- int result = 0;
-
- new = kmem_cache_alloc(fasync_cache, GFP_KERNEL);
- if (!new)
- return -ENOMEM;
+ struct fasync_struct *fa, **fp;
spin_lock(&filp->f_lock);
spin_lock(&fasync_lock);
@@ -691,8 +701,6 @@ static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fa
spin_lock_irq(&fa->fa_lock);
fa->fa_fd = fd;
spin_unlock_irq(&fa->fa_lock);
-
- kmem_cache_free(fasync_cache, new);
goto out;
}
@@ -702,13 +710,39 @@ static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fa
new->fa_fd = fd;
new->fa_next = *fapp;
rcu_assign_pointer(*fapp, new);
- result = 1;
filp->f_flags |= FASYNC;
out:
spin_unlock(&fasync_lock);
spin_unlock(&filp->f_lock);
- return result;
+ return fa;
+}
+
+/*
+ * Add a fasync entry. Return negative on error, positive if
+ * added, and zero if did nothing but change an existing one.
+ */
+static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fapp)
+{
+ struct fasync_struct *new;
+
+ new = fasync_alloc();
+ if (!new)
+ return -ENOMEM;
+
+ /*
+ * fasync_insert_entry() returns the old (update) entry if
+ * it existed.
+ *
+ * So free the (unused) new entry and return 0 to let the
+ * caller know that we didn't add any new fasync entries.
+ */
+ if (fasync_insert_entry(fd, filp, fapp, new)) {
+ fasync_free(new);
+ return 0;
+ }
+
+ return 1;
}
/*
diff --git a/fs/file_table.c b/fs/file_table.c
index a04bdd81c11c..c3dee381f1b4 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -60,7 +60,7 @@ static inline void file_free(struct file *f)
/*
* Return the total number of open files in the system
*/
-static int get_nr_files(void)
+static long get_nr_files(void)
{
return percpu_counter_read_positive(&nr_files);
}
@@ -68,7 +68,7 @@ static int get_nr_files(void)
/*
* Return the maximum number of open files in the system
*/
-int get_max_files(void)
+unsigned long get_max_files(void)
{
return files_stat.max_files;
}
@@ -82,7 +82,7 @@ int proc_nr_files(ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
files_stat.nr_files = get_nr_files();
- return proc_dointvec(table, write, buffer, lenp, ppos);
+ return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
}
#else
int proc_nr_files(ctl_table *table, int write,
@@ -105,7 +105,7 @@ int proc_nr_files(ctl_table *table, int write,
struct file *get_empty_filp(void)
{
const struct cred *cred = current_cred();
- static int old_max;
+ static long old_max;
struct file * f;
/*
@@ -140,8 +140,7 @@ struct file *get_empty_filp(void)
over:
/* Ran out of filps - report that */
if (get_nr_files() > old_max) {
- printk(KERN_INFO "VFS: file-max limit %d reached\n",
- get_max_files());
+ pr_info("VFS: file-max limit %lu reached\n", get_max_files());
old_max = get_nr_files();
}
goto fail;
@@ -487,7 +486,7 @@ retry:
void __init files_init(unsigned long mempages)
{
- int n;
+ unsigned long n;
filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
@@ -498,9 +497,7 @@ void __init files_init(unsigned long mempages)
*/
n = (mempages * (PAGE_SIZE / 1024)) / 10;
- files_stat.max_files = n;
- if (files_stat.max_files < NR_FILE)
- files_stat.max_files = NR_FILE;
+ files_stat.max_files = max_t(unsigned long, n, NR_FILE);
files_defer_init();
lg_lock_init(files_lglock);
percpu_counter_init(&nr_files, 0);
diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
index 79d1b4ea13e7..8c04eac5079d 100644
--- a/fs/freevxfs/vxfs_inode.c
+++ b/fs/freevxfs/vxfs_inode.c
@@ -260,6 +260,7 @@ vxfs_get_fake_inode(struct super_block *sbp, struct vxfs_inode_info *vip)
struct inode *ip = NULL;
if ((ip = new_inode(sbp))) {
+ ip->i_ino = get_next_ino();
vxfs_iinit(ip, vip);
ip->i_mapping->a_ops = &vxfs_aops;
}
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index ab38fef1c9a1..aed881a76b22 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -79,6 +79,11 @@ static inline struct backing_dev_info *inode_to_bdi(struct inode *inode)
return sb->s_bdi;
}
+static inline struct inode *wb_inode(struct list_head *head)
+{
+ return list_entry(head, struct inode, i_wb_list);
+}
+
static void bdi_queue_work(struct backing_dev_info *bdi,
struct wb_writeback_work *work)
{
@@ -172,11 +177,11 @@ static void redirty_tail(struct inode *inode)
if (!list_empty(&wb->b_dirty)) {
struct inode *tail;
- tail = list_entry(wb->b_dirty.next, struct inode, i_list);
+ tail = wb_inode(wb->b_dirty.next);
if (time_before(inode->dirtied_when, tail->dirtied_when))
inode->dirtied_when = jiffies;
}
- list_move(&inode->i_list, &wb->b_dirty);
+ list_move(&inode->i_wb_list, &wb->b_dirty);
}
/*
@@ -186,7 +191,7 @@ static void requeue_io(struct inode *inode)
{
struct bdi_writeback *wb = &inode_to_bdi(inode)->wb;
- list_move(&inode->i_list, &wb->b_more_io);
+ list_move(&inode->i_wb_list, &wb->b_more_io);
}
static void inode_sync_complete(struct inode *inode)
@@ -227,14 +232,14 @@ static void move_expired_inodes(struct list_head *delaying_queue,
int do_sb_sort = 0;
while (!list_empty(delaying_queue)) {
- inode = list_entry(delaying_queue->prev, struct inode, i_list);
+ inode = wb_inode(delaying_queue->prev);
if (older_than_this &&
inode_dirtied_after(inode, *older_than_this))
break;
if (sb && sb != inode->i_sb)
do_sb_sort = 1;
sb = inode->i_sb;
- list_move(&inode->i_list, &tmp);
+ list_move(&inode->i_wb_list, &tmp);
}
/* just one sb in list, splice to dispatch_queue and we're done */
@@ -245,12 +250,11 @@ static void move_expired_inodes(struct list_head *delaying_queue,
/* Move inodes from one superblock together */
while (!list_empty(&tmp)) {
- inode = list_entry(tmp.prev, struct inode, i_list);
- sb = inode->i_sb;
+ sb = wb_inode(tmp.prev)->i_sb;
list_for_each_prev_safe(pos, node, &tmp) {
- inode = list_entry(pos, struct inode, i_list);
+ inode = wb_inode(pos);
if (inode->i_sb == sb)
- list_move(&inode->i_list, dispatch_queue);
+ list_move(&inode->i_wb_list, dispatch_queue);
}
}
}
@@ -408,16 +412,13 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
* completion.
*/
redirty_tail(inode);
- } else if (atomic_read(&inode->i_count)) {
- /*
- * The inode is clean, inuse
- */
- list_move(&inode->i_list, &inode_in_use);
} else {
/*
- * The inode is clean, unused
+ * The inode is clean. At this point we either have
+ * a reference to the inode or it's on it's way out.
+ * No need to add it back to the LRU.
*/
- list_move(&inode->i_list, &inode_unused);
+ list_del_init(&inode->i_wb_list);
}
}
inode_sync_complete(inode);
@@ -465,8 +466,7 @@ static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb,
{
while (!list_empty(&wb->b_io)) {
long pages_skipped;
- struct inode *inode = list_entry(wb->b_io.prev,
- struct inode, i_list);
+ struct inode *inode = wb_inode(wb->b_io.prev);
if (inode->i_sb != sb) {
if (only_this_sb) {
@@ -487,10 +487,16 @@ static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb,
return 0;
}
- if (inode->i_state & (I_NEW | I_WILL_FREE)) {
+ /*
+ * Don't bother with new inodes or inodes beeing freed, first
+ * kind does not need peridic writeout yet, and for the latter
+ * kind writeout is handled by the freer.
+ */
+ if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
requeue_io(inode);
continue;
}
+
/*
* Was this inode dirtied after sync_sb_inodes was called?
* This keeps sync from extra jobs and livelock.
@@ -498,7 +504,6 @@ static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb,
if (inode_dirtied_after(inode, wbc->wb_start))
return 1;
- BUG_ON(inode->i_state & I_FREEING);
__iget(inode);
pages_skipped = wbc->pages_skipped;
writeback_single_inode(inode, wbc);
@@ -536,8 +541,7 @@ void writeback_inodes_wb(struct bdi_writeback *wb,
queue_io(wb, wbc->older_than_this);
while (!list_empty(&wb->b_io)) {
- struct inode *inode = list_entry(wb->b_io.prev,
- struct inode, i_list);
+ struct inode *inode = wb_inode(wb->b_io.prev);
struct super_block *sb = inode->i_sb;
if (!pin_sb_for_writeback(sb)) {
@@ -582,7 +586,7 @@ static inline bool over_bground_thresh(void)
global_dirty_limits(&background_thresh, &dirty_thresh);
return (global_page_state(NR_FILE_DIRTY) +
- global_page_state(NR_UNSTABLE_NFS) >= background_thresh);
+ global_page_state(NR_UNSTABLE_NFS) > background_thresh);
}
/*
@@ -675,8 +679,7 @@ static long wb_writeback(struct bdi_writeback *wb,
*/
spin_lock(&inode_lock);
if (!list_empty(&wb->b_more_io)) {
- inode = list_entry(wb->b_more_io.prev,
- struct inode, i_list);
+ inode = wb_inode(wb->b_more_io.prev);
trace_wbc_writeback_wait(&wbc, wb->bdi);
inode_wait_for_writeback(inode);
}
@@ -721,9 +724,13 @@ static long wb_check_old_data_flush(struct bdi_writeback *wb)
return 0;
wb->last_old_flush = jiffies;
+ /*
+ * Add in the number of potentially dirty inodes, because each inode
+ * write can dirty pagecache in the underlying blockdev.
+ */
nr_pages = global_page_state(NR_FILE_DIRTY) +
global_page_state(NR_UNSTABLE_NFS) +
- (inodes_stat.nr_inodes - inodes_stat.nr_unused);
+ get_nr_dirty_inodes();
if (nr_pages) {
struct wb_writeback_work work = {
@@ -790,7 +797,7 @@ int bdi_writeback_thread(void *data)
struct backing_dev_info *bdi = wb->bdi;
long pages_written;
- current->flags |= PF_FLUSHER | PF_SWAPWRITE;
+ current->flags |= PF_SWAPWRITE;
set_freezable();
wb->last_active = jiffies;
@@ -962,7 +969,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
* dirty list. Add blockdev inodes as well.
*/
if (!S_ISBLK(inode->i_mode)) {
- if (hlist_unhashed(&inode->i_hash))
+ if (inode_unhashed(inode))
goto out;
}
if (inode->i_state & I_FREEING)
@@ -990,7 +997,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
}
inode->dirtied_when = jiffies;
- list_move(&inode->i_list, &bdi->wb.b_dirty);
+ list_move(&inode->i_wb_list, &bdi->wb.b_dirty);
}
}
out:
@@ -1090,8 +1097,7 @@ void writeback_inodes_sb(struct super_block *sb)
WARN_ON(!rwsem_is_locked(&sb->s_umount));
- work.nr_pages = nr_dirty + nr_unstable +
- (inodes_stat.nr_inodes - inodes_stat.nr_unused);
+ work.nr_pages = nr_dirty + nr_unstable + get_nr_dirty_inodes();
bdi_queue_work(sb->s_bdi, &work);
wait_for_completion(&done);
@@ -1198,3 +1204,23 @@ int sync_inode(struct inode *inode, struct writeback_control *wbc)
return ret;
}
EXPORT_SYMBOL(sync_inode);
+
+/**
+ * sync_inode - write an inode to disk
+ * @inode: the inode to sync
+ * @wait: wait for I/O to complete.
+ *
+ * Write an inode to disk and adjust it's dirty state after completion.
+ *
+ * Note: only writes the actual inode, no associated data or other metadata.
+ */
+int sync_inode_metadata(struct inode *inode, int wait)
+{
+ struct writeback_control wbc = {
+ .sync_mode = wait ? WB_SYNC_ALL : WB_SYNC_NONE,
+ .nr_to_write = 0, /* metadata-only */
+ };
+
+ return sync_inode(inode, &wbc);
+}
+EXPORT_SYMBOL(sync_inode_metadata);
diff --git a/fs/fuse/control.c b/fs/fuse/control.c
index 7367e177186f..4eba07661e5c 100644
--- a/fs/fuse/control.c
+++ b/fs/fuse/control.c
@@ -222,6 +222,7 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent,
if (!inode)
return NULL;
+ inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_uid = fc->user_id;
inode->i_gid = fc->group_id;
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index cde755cca564..6e07696308dc 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -809,11 +809,9 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
int err;
struct page *page = *pagep;
- if (page && zeroing && count < PAGE_SIZE) {
- void *mapaddr = kmap_atomic(page, KM_USER1);
- memset(mapaddr, 0, PAGE_SIZE);
- kunmap_atomic(mapaddr, KM_USER1);
- }
+ if (page && zeroing && count < PAGE_SIZE)
+ clear_highpage(page);
+
while (count) {
if (cs->write && cs->pipebufs && page) {
return fuse_ref_page(cs, page, offset, count);
@@ -830,10 +828,10 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
}
}
if (page) {
- void *mapaddr = kmap_atomic(page, KM_USER1);
+ void *mapaddr = kmap_atomic(page, KM_USER0);
void *buf = mapaddr + offset;
offset += fuse_copy_do(cs, &buf, &count);
- kunmap_atomic(mapaddr, KM_USER1);
+ kunmap_atomic(mapaddr, KM_USER0);
} else
offset += fuse_copy_do(cs, NULL, &count);
}
@@ -1336,12 +1334,7 @@ out_finish:
static void fuse_retrieve_end(struct fuse_conn *fc, struct fuse_req *req)
{
- int i;
-
- for (i = 0; i < req->num_pages; i++) {
- struct page *page = req->pages[i];
- page_cache_release(page);
- }
+ release_pages(req->pages, req->num_pages, 0);
}
static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode,
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 6b24afb96aae..4f36f8832b9b 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -618,7 +618,6 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
struct gfs2_alloc *al = NULL;
pgoff_t index = pos >> PAGE_CACHE_SHIFT;
unsigned from = pos & (PAGE_CACHE_SIZE - 1);
- unsigned to = from + len;
struct page *page;
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh);
@@ -691,7 +690,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
}
prepare_write:
- error = block_prepare_write(page, from, to, gfs2_block_map);
+ error = __block_write_begin(page, from, len, gfs2_block_map);
out:
if (error == 0)
return 0;
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
index f3b071f921aa..939739c7b3f9 100644
--- a/fs/gfs2/meta_io.c
+++ b/fs/gfs2/meta_io.c
@@ -55,7 +55,7 @@ static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wb
* activity, but those code paths have their own higher-level
* throttling.
*/
- if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) {
+ if (wbc->sync_mode != WB_SYNC_NONE) {
lock_buffer(bh);
} else if (!trylock_buffer(bh)) {
redirty_page_for_writepage(wbc, page);
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index aeafc233dc89..cade1acbcea9 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1219,7 +1219,6 @@ fail_sb:
fail_locking:
init_locking(sdp, &mount_gh, UNDO);
fail_lm:
- invalidate_inodes(sb);
gfs2_gl_hash_clear(sdp);
gfs2_lm_unmount(sdp);
fail_sys:
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index 0534510200d5..12cbea7502c2 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -255,7 +255,7 @@ out_parent:
gfs2_holder_uninit(ghs);
gfs2_holder_uninit(ghs + 1);
if (!error) {
- atomic_inc(&inode->i_count);
+ ihold(inode);
d_instantiate(dentry, inode);
mark_inode_dirty(inode);
}
@@ -1294,7 +1294,7 @@ static int write_empty_blocks(struct page *page, unsigned from, unsigned to)
int error;
if (!page_has_buffers(page)) {
- error = block_prepare_write(page, from, to, gfs2_block_map);
+ error = __block_write_begin(page, from, to - from, gfs2_block_map);
if (unlikely(error))
return error;
@@ -1313,7 +1313,7 @@ static int write_empty_blocks(struct page *page, unsigned from, unsigned to)
next += bh->b_size;
if (buffer_mapped(bh)) {
if (end) {
- error = block_prepare_write(page, start, end,
+ error = __block_write_begin(page, start, end - start,
gfs2_block_map);
if (unlikely(error))
return error;
@@ -1328,7 +1328,7 @@ static int write_empty_blocks(struct page *page, unsigned from, unsigned to)
} while (next < to);
if (end) {
- error = block_prepare_write(page, start, end, gfs2_block_map);
+ error = __block_write_begin(page, start, end - start, gfs2_block_map);
if (unlikely(error))
return error;
empty_write_end(page, start, end);
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 047d1176096c..2b2c4997430b 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -857,7 +857,6 @@ restart:
gfs2_clear_rgrpd(sdp);
gfs2_jindex_free(sdp);
/* Take apart glock structures and buffer lists */
- invalidate_inodes(sdp->sd_vfs);
gfs2_gl_hash_clear(sdp);
/* Unmount the locking protocol */
gfs2_lm_unmount(sdp);
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
index 4f55651aaa51..c8cffb81e849 100644
--- a/fs/hfs/hfs_fs.h
+++ b/fs/hfs/hfs_fs.h
@@ -147,8 +147,6 @@ struct hfs_sb_info {
u16 blockoffset;
int fs_div;
-
- struct hlist_head rsrc_inodes;
};
#define HFS_FLG_BITMAP_DIRTY 0
@@ -254,17 +252,6 @@ static inline void hfs_bitmap_dirty(struct super_block *sb)
sb->s_dirt = 1;
}
-static inline void hfs_buffer_sync(struct buffer_head *bh)
-{
- while (buffer_locked(bh)) {
- wait_on_buffer(bh);
- }
- if (buffer_dirty(bh)) {
- ll_rw_block(WRITE, 1, &bh);
- wait_on_buffer(bh);
- }
-}
-
#define sb_bread512(sb, sec, data) ({ \
struct buffer_head *__bh; \
sector_t __block; \
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 397b7adc7ce6..dffb4e996643 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -524,7 +524,7 @@ static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
HFS_I(inode)->rsrc_inode = dir;
HFS_I(dir)->rsrc_inode = inode;
igrab(dir);
- hlist_add_head(&inode->i_hash, &HFS_SB(dir->i_sb)->rsrc_inodes);
+ hlist_add_fake(&inode->i_hash);
mark_inode_dirty(inode);
out:
d_add(dentry, inode);
diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c
index 86428f5ac991..1563d5ce5764 100644
--- a/fs/hfs/mdb.c
+++ b/fs/hfs/mdb.c
@@ -220,7 +220,7 @@ int hfs_mdb_get(struct super_block *sb)
mdb->drLsMod = hfs_mtime();
mark_buffer_dirty(HFS_SB(sb)->mdb_bh);
- hfs_buffer_sync(HFS_SB(sb)->mdb_bh);
+ sync_dirty_buffer(HFS_SB(sb)->mdb_bh);
}
return 0;
@@ -287,7 +287,7 @@ void hfs_mdb_commit(struct super_block *sb)
HFS_SB(sb)->alt_mdb->drAtrb |= cpu_to_be16(HFS_SB_ATTRIB_UNMNT);
HFS_SB(sb)->alt_mdb->drAtrb &= cpu_to_be16(~HFS_SB_ATTRIB_INCNSTNT);
mark_buffer_dirty(HFS_SB(sb)->alt_mdb_bh);
- hfs_buffer_sync(HFS_SB(sb)->alt_mdb_bh);
+ sync_dirty_buffer(HFS_SB(sb)->alt_mdb_bh);
}
if (test_and_clear_bit(HFS_FLG_BITMAP_DIRTY, &HFS_SB(sb)->flags)) {
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 33254160f650..6ee1586f2334 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -382,7 +382,6 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent)
return -ENOMEM;
sb->s_fs_info = sbi;
- INIT_HLIST_HEAD(&sbi->rsrc_inodes);
res = -EINVAL;
if (!parse_options((char *)data, sbi)) {
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index d236d85ec9d7..9d59c0571f59 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -286,7 +286,7 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
inc_nlink(inode);
hfsplus_instantiate(dst_dentry, inode, cnid);
- atomic_inc(&inode->i_count);
+ ihold(inode);
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
sbi->file_count++;
@@ -317,8 +317,10 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
res = hfsplus_rename_cat(inode->i_ino,
dir, &dentry->d_name,
sbi->hidden_dir, &str);
- if (!res)
+ if (!res) {
inode->i_flags |= S_DEAD;
+ drop_nlink(inode);
+ }
goto out;
}
res = hfsplus_delete_cat(cnid, dir, &dentry->d_name);
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 78449280dae0..8afd7e84f98d 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -211,7 +211,7 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent
* appear hashed, but do not put on any lists. hlist_del()
* will work fine and require no locking.
*/
- inode->i_hash.pprev = &inode->i_hash.next;
+ hlist_add_fake(&inode->i_hash);
mark_inode_dirty(inode);
out:
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c
index 5b4667e08ef7..40a85a3ded6e 100644
--- a/fs/hfsplus/ioctl.c
+++ b/fs/hfsplus/ioctl.c
@@ -92,7 +92,7 @@ static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
mark_inode_dirty(inode);
out_unlock_inode:
- mutex_lock(&inode->i_mutex);
+ mutex_unlock(&inode->i_mutex);
out_drop_write:
mnt_drop_write(file->f_path.mnt);
out:
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
index 6bbd75c5589b..bf15a43016b9 100644
--- a/fs/hostfs/hostfs.h
+++ b/fs/hostfs/hostfs.h
@@ -28,12 +28,7 @@
* #define ATTR_KILL_SUID 2048
* #define ATTR_KILL_SGID 4096
*
- * and this is because they were added in 2.5 development in this patch:
- *
- * http://linux.bkbits.net:8080/linux-2.5/
- * cset@3caf4a12k4XgDzK7wyK-TGpSZ9u2Ww?nav=index.html
- * |src/.|src/include|src/include/linux|related/include/linux/fs.h
- *
+ * and this is because they were added in 2.5 development.
* Actually, they are not needed by most ->setattr() methods - they are set by
* callers of notify_change() to notify that the setuid/setgid bits must be
* dropped.
@@ -96,7 +91,6 @@ extern int rename_file(char *from, char *to);
extern int do_statfs(char *root, long *bsize_out, long long *blocks_out,
long long *bfree_out, long long *bavail_out,
long long *files_out, long long *ffree_out,
- void *fsid_out, int fsid_size, long *namelen_out,
- long *spare_out);
+ void *fsid_out, int fsid_size, long *namelen_out);
#endif
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index f7dc9b5f9ef8..cd7c93917cc7 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -217,7 +217,7 @@ int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
err = do_statfs(dentry->d_sb->s_fs_info,
&sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
&f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
- &sf->f_namelen, sf->f_spare);
+ &sf->f_namelen);
if (err)
return err;
sf->f_blocks = f_blocks;
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
index 6777aa06ce2c..d51a98384bc0 100644
--- a/fs/hostfs/hostfs_user.c
+++ b/fs/hostfs/hostfs_user.c
@@ -94,8 +94,7 @@ void *open_dir(char *path, int *err_out)
dir = opendir(path);
*err_out = errno;
- if (dir == NULL)
- return NULL;
+
return dir;
}
@@ -205,7 +204,7 @@ int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
if (attrs->ia_valid & HOSTFS_ATTR_MODE) {
if (fd >= 0) {
if (fchmod(fd, attrs->ia_mode) != 0)
- return (-errno);
+ return -errno;
} else if (chmod(file, attrs->ia_mode) != 0) {
return -errno;
}
@@ -364,8 +363,7 @@ int rename_file(char *from, char *to)
int do_statfs(char *root, long *bsize_out, long long *blocks_out,
long long *bfree_out, long long *bavail_out,
long long *files_out, long long *ffree_out,
- void *fsid_out, int fsid_size, long *namelen_out,
- long *spare_out)
+ void *fsid_out, int fsid_size, long *namelen_out)
{
struct statfs64 buf;
int err;
@@ -384,10 +382,6 @@ int do_statfs(char *root, long *bsize_out, long long *blocks_out,
sizeof(buf.f_fsid) > fsid_size ? fsid_size :
sizeof(buf.f_fsid));
*namelen_out = buf.f_namelen;
- spare_out[0] = buf.f_spare[0];
- spare_out[1] = buf.f_spare[1];
- spare_out[2] = buf.f_spare[2];
- spare_out[3] = buf.f_spare[3];
- spare_out[4] = buf.f_spare[4];
+
return 0;
}
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 113eba3d3c38..b14be3f781c7 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -31,6 +31,7 @@
#include <linux/statfs.h>
#include <linux/security.h>
#include <linux/magic.h>
+#include <linux/migrate.h>
#include <asm/uaccess.h>
@@ -455,6 +456,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid,
inode = new_inode(sb);
if (inode) {
struct hugetlbfs_inode_info *info;
+ inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_uid = uid;
inode->i_gid = gid;
@@ -573,6 +575,19 @@ static int hugetlbfs_set_page_dirty(struct page *page)
return 0;
}
+static int hugetlbfs_migrate_page(struct address_space *mapping,
+ struct page *newpage, struct page *page)
+{
+ int rc;
+
+ rc = migrate_huge_page_move_mapping(mapping, newpage, page);
+ if (rc)
+ return rc;
+ migrate_page_copy(newpage, page);
+
+ return 0;
+}
+
static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(dentry->d_sb);
@@ -659,6 +674,7 @@ static const struct address_space_operations hugetlbfs_aops = {
.write_begin = hugetlbfs_write_begin,
.write_end = hugetlbfs_write_end,
.set_page_dirty = hugetlbfs_set_page_dirty,
+ .migratepage = hugetlbfs_migrate_page,
};
diff --git a/fs/inode.c b/fs/inode.c
index 86464332e590..ae2727ab0c3a 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -24,11 +24,11 @@
#include <linux/mount.h>
#include <linux/async.h>
#include <linux/posix_acl.h>
+#include <linux/ima.h>
/*
* This is needed for the following functions:
* - inode_has_buffers
- * - invalidate_inode_buffers
* - invalidate_bdev
*
* FIXME: remove all knowledge of the buffer layer from this file
@@ -72,8 +72,7 @@ static unsigned int i_hash_shift __read_mostly;
* allowing for low-overhead inode sync() operations.
*/
-LIST_HEAD(inode_in_use);
-LIST_HEAD(inode_unused);
+static LIST_HEAD(inode_lru);
static struct hlist_head *inode_hashtable __read_mostly;
/*
@@ -103,8 +102,41 @@ static DECLARE_RWSEM(iprune_sem);
*/
struct inodes_stat_t inodes_stat;
+static struct percpu_counter nr_inodes __cacheline_aligned_in_smp;
+static struct percpu_counter nr_inodes_unused __cacheline_aligned_in_smp;
+
static struct kmem_cache *inode_cachep __read_mostly;
+static inline int get_nr_inodes(void)
+{
+ return percpu_counter_sum_positive(&nr_inodes);
+}
+
+static inline int get_nr_inodes_unused(void)
+{
+ return percpu_counter_sum_positive(&nr_inodes_unused);
+}
+
+int get_nr_dirty_inodes(void)
+{
+ int nr_dirty = get_nr_inodes() - get_nr_inodes_unused();
+ return nr_dirty > 0 ? nr_dirty : 0;
+
+}
+
+/*
+ * Handle nr_inode sysctl
+ */
+#ifdef CONFIG_SYSCTL
+int proc_nr_inodes(ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ inodes_stat.nr_inodes = get_nr_inodes();
+ inodes_stat.nr_unused = get_nr_inodes_unused();
+ return proc_dointvec(table, write, buffer, lenp, ppos);
+}
+#endif
+
static void wake_up_inode(struct inode *inode)
{
/*
@@ -192,6 +224,8 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
inode->i_fsnotify_mask = 0;
#endif
+ percpu_counter_inc(&nr_inodes);
+
return 0;
out:
return -ENOMEM;
@@ -232,11 +266,13 @@ void __destroy_inode(struct inode *inode)
if (inode->i_default_acl && inode->i_default_acl != ACL_NOT_CACHED)
posix_acl_release(inode->i_default_acl);
#endif
+ percpu_counter_dec(&nr_inodes);
}
EXPORT_SYMBOL(__destroy_inode);
-void destroy_inode(struct inode *inode)
+static void destroy_inode(struct inode *inode)
{
+ BUG_ON(!list_empty(&inode->i_lru));
__destroy_inode(inode);
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
@@ -255,6 +291,8 @@ void inode_init_once(struct inode *inode)
INIT_HLIST_NODE(&inode->i_hash);
INIT_LIST_HEAD(&inode->i_dentry);
INIT_LIST_HEAD(&inode->i_devices);
+ INIT_LIST_HEAD(&inode->i_wb_list);
+ INIT_LIST_HEAD(&inode->i_lru);
INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
spin_lock_init(&inode->i_data.tree_lock);
spin_lock_init(&inode->i_data.i_mmap_lock);
@@ -281,14 +319,109 @@ static void init_once(void *foo)
*/
void __iget(struct inode *inode)
{
- if (atomic_inc_return(&inode->i_count) != 1)
- return;
+ atomic_inc(&inode->i_count);
+}
+
+/*
+ * get additional reference to inode; caller must already hold one.
+ */
+void ihold(struct inode *inode)
+{
+ WARN_ON(atomic_inc_return(&inode->i_count) < 2);
+}
+EXPORT_SYMBOL(ihold);
+
+static void inode_lru_list_add(struct inode *inode)
+{
+ if (list_empty(&inode->i_lru)) {
+ list_add(&inode->i_lru, &inode_lru);
+ percpu_counter_inc(&nr_inodes_unused);
+ }
+}
- if (!(inode->i_state & (I_DIRTY|I_SYNC)))
- list_move(&inode->i_list, &inode_in_use);
- inodes_stat.nr_unused--;
+static void inode_lru_list_del(struct inode *inode)
+{
+ if (!list_empty(&inode->i_lru)) {
+ list_del_init(&inode->i_lru);
+ percpu_counter_dec(&nr_inodes_unused);
+ }
+}
+
+static inline void __inode_sb_list_add(struct inode *inode)
+{
+ list_add(&inode->i_sb_list, &inode->i_sb->s_inodes);
}
+/**
+ * inode_sb_list_add - add inode to the superblock list of inodes
+ * @inode: inode to add
+ */
+void inode_sb_list_add(struct inode *inode)
+{
+ spin_lock(&inode_lock);
+ __inode_sb_list_add(inode);
+ spin_unlock(&inode_lock);
+}
+EXPORT_SYMBOL_GPL(inode_sb_list_add);
+
+static inline void __inode_sb_list_del(struct inode *inode)
+{
+ list_del_init(&inode->i_sb_list);
+}
+
+static unsigned long hash(struct super_block *sb, unsigned long hashval)
+{
+ unsigned long tmp;
+
+ tmp = (hashval * (unsigned long)sb) ^ (GOLDEN_RATIO_PRIME + hashval) /
+ L1_CACHE_BYTES;
+ tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> I_HASHBITS);
+ return tmp & I_HASHMASK;
+}
+
+/**
+ * __insert_inode_hash - hash an inode
+ * @inode: unhashed inode
+ * @hashval: unsigned long value used to locate this object in the
+ * inode_hashtable.
+ *
+ * Add an inode to the inode hash for this superblock.
+ */
+void __insert_inode_hash(struct inode *inode, unsigned long hashval)
+{
+ struct hlist_head *b = inode_hashtable + hash(inode->i_sb, hashval);
+
+ spin_lock(&inode_lock);
+ hlist_add_head(&inode->i_hash, b);
+ spin_unlock(&inode_lock);
+}
+EXPORT_SYMBOL(__insert_inode_hash);
+
+/**
+ * __remove_inode_hash - remove an inode from the hash
+ * @inode: inode to unhash
+ *
+ * Remove an inode from the superblock.
+ */
+static void __remove_inode_hash(struct inode *inode)
+{
+ hlist_del_init(&inode->i_hash);
+}
+
+/**
+ * remove_inode_hash - remove an inode from the hash
+ * @inode: inode to unhash
+ *
+ * Remove an inode from the superblock.
+ */
+void remove_inode_hash(struct inode *inode)
+{
+ spin_lock(&inode_lock);
+ hlist_del_init(&inode->i_hash);
+ spin_unlock(&inode_lock);
+}
+EXPORT_SYMBOL(remove_inode_hash);
+
void end_writeback(struct inode *inode)
{
might_sleep();
@@ -327,101 +460,113 @@ static void evict(struct inode *inode)
*/
static void dispose_list(struct list_head *head)
{
- int nr_disposed = 0;
-
while (!list_empty(head)) {
struct inode *inode;
- inode = list_first_entry(head, struct inode, i_list);
- list_del(&inode->i_list);
+ inode = list_first_entry(head, struct inode, i_lru);
+ list_del_init(&inode->i_lru);
evict(inode);
spin_lock(&inode_lock);
- hlist_del_init(&inode->i_hash);
- list_del_init(&inode->i_sb_list);
+ __remove_inode_hash(inode);
+ __inode_sb_list_del(inode);
spin_unlock(&inode_lock);
wake_up_inode(inode);
destroy_inode(inode);
- nr_disposed++;
}
- spin_lock(&inode_lock);
- inodes_stat.nr_inodes -= nr_disposed;
- spin_unlock(&inode_lock);
}
-/*
- * Invalidate all inodes for a device.
+/**
+ * evict_inodes - evict all evictable inodes for a superblock
+ * @sb: superblock to operate on
+ *
+ * Make sure that no inodes with zero refcount are retained. This is
+ * called by superblock shutdown after having MS_ACTIVE flag removed,
+ * so any inode reaching zero refcount during or after that call will
+ * be immediately evicted.
*/
-static int invalidate_list(struct list_head *head, struct list_head *dispose)
+void evict_inodes(struct super_block *sb)
{
- struct list_head *next;
- int busy = 0, count = 0;
-
- next = head->next;
- for (;;) {
- struct list_head *tmp = next;
- struct inode *inode;
+ struct inode *inode, *next;
+ LIST_HEAD(dispose);
- /*
- * We can reschedule here without worrying about the list's
- * consistency because the per-sb list of inodes must not
- * change during umount anymore, and because iprune_sem keeps
- * shrink_icache_memory() away.
- */
- cond_resched_lock(&inode_lock);
+ down_write(&iprune_sem);
- next = next->next;
- if (tmp == head)
- break;
- inode = list_entry(tmp, struct inode, i_sb_list);
- if (inode->i_state & I_NEW)
+ spin_lock(&inode_lock);
+ list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
+ if (atomic_read(&inode->i_count))
continue;
- invalidate_inode_buffers(inode);
- if (!atomic_read(&inode->i_count)) {
- list_move(&inode->i_list, dispose);
- WARN_ON(inode->i_state & I_NEW);
- inode->i_state |= I_FREEING;
- count++;
+
+ if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
+ WARN_ON(1);
continue;
}
- busy = 1;
+
+ inode->i_state |= I_FREEING;
+
+ /*
+ * Move the inode off the IO lists and LRU once I_FREEING is
+ * set so that it won't get moved back on there if it is dirty.
+ */
+ list_move(&inode->i_lru, &dispose);
+ list_del_init(&inode->i_wb_list);
+ if (!(inode->i_state & (I_DIRTY | I_SYNC)))
+ percpu_counter_dec(&nr_inodes_unused);
}
- /* only unused inodes may be cached with i_count zero */
- inodes_stat.nr_unused -= count;
- return busy;
+ spin_unlock(&inode_lock);
+
+ dispose_list(&dispose);
+ up_write(&iprune_sem);
}
/**
- * invalidate_inodes - discard the inodes on a device
- * @sb: superblock
+ * invalidate_inodes - attempt to free all inodes on a superblock
+ * @sb: superblock to operate on
*
- * Discard all of the inodes for a given superblock. If the discard
- * fails because there are busy inodes then a non zero value is returned.
- * If the discard is successful all the inodes have been discarded.
+ * Attempts to free all inodes for a given superblock. If there were any
+ * busy inodes return a non-zero value, else zero.
*/
int invalidate_inodes(struct super_block *sb)
{
- int busy;
- LIST_HEAD(throw_away);
+ int busy = 0;
+ struct inode *inode, *next;
+ LIST_HEAD(dispose);
down_write(&iprune_sem);
+
spin_lock(&inode_lock);
- fsnotify_unmount_inodes(&sb->s_inodes);
- busy = invalidate_list(&sb->s_inodes, &throw_away);
+ list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
+ if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE))
+ continue;
+ if (atomic_read(&inode->i_count)) {
+ busy = 1;
+ continue;
+ }
+
+ inode->i_state |= I_FREEING;
+
+ /*
+ * Move the inode off the IO lists and LRU once I_FREEING is
+ * set so that it won't get moved back on there if it is dirty.
+ */
+ list_move(&inode->i_lru, &dispose);
+ list_del_init(&inode->i_wb_list);
+ if (!(inode->i_state & (I_DIRTY | I_SYNC)))
+ percpu_counter_dec(&nr_inodes_unused);
+ }
spin_unlock(&inode_lock);
- dispose_list(&throw_away);
+ dispose_list(&dispose);
up_write(&iprune_sem);
return busy;
}
-EXPORT_SYMBOL(invalidate_inodes);
static int can_unuse(struct inode *inode)
{
- if (inode->i_state)
+ if (inode->i_state & ~I_REFERENCED)
return 0;
if (inode_has_buffers(inode))
return 0;
@@ -433,22 +578,24 @@ static int can_unuse(struct inode *inode)
}
/*
- * Scan `goal' inodes on the unused list for freeable ones. They are moved to
- * a temporary list and then are freed outside inode_lock by dispose_list().
+ * Scan `goal' inodes on the unused list for freeable ones. They are moved to a
+ * temporary list and then are freed outside inode_lock by dispose_list().
*
* Any inodes which are pinned purely because of attached pagecache have their
- * pagecache removed. We expect the final iput() on that inode to add it to
- * the front of the inode_unused list. So look for it there and if the
- * inode is still freeable, proceed. The right inode is found 99.9% of the
- * time in testing on a 4-way.
+ * pagecache removed. If the inode has metadata buffers attached to
+ * mapping->private_list then try to remove them.
*
- * If the inode has metadata buffers attached to mapping->private_list then
- * try to remove them.
+ * If the inode has the I_REFERENCED flag set, then it means that it has been
+ * used recently - the flag is set in iput_final(). When we encounter such an
+ * inode, clear the flag and move it to the back of the LRU so it gets another
+ * pass through the LRU before it gets reclaimed. This is necessary because of
+ * the fact we are doing lazy LRU updates to minimise lock contention so the
+ * LRU does not have strict ordering. Hence we don't want to reclaim inodes
+ * with this flag set because they are the inodes that are out of order.
*/
static void prune_icache(int nr_to_scan)
{
LIST_HEAD(freeable);
- int nr_pruned = 0;
int nr_scanned;
unsigned long reap = 0;
@@ -457,13 +604,26 @@ static void prune_icache(int nr_to_scan)
for (nr_scanned = 0; nr_scanned < nr_to_scan; nr_scanned++) {
struct inode *inode;
- if (list_empty(&inode_unused))
+ if (list_empty(&inode_lru))
break;
- inode = list_entry(inode_unused.prev, struct inode, i_list);
+ inode = list_entry(inode_lru.prev, struct inode, i_lru);
- if (inode->i_state || atomic_read(&inode->i_count)) {
- list_move(&inode->i_list, &inode_unused);
+ /*
+ * Referenced or dirty inodes are still in use. Give them
+ * another pass through the LRU as we canot reclaim them now.
+ */
+ if (atomic_read(&inode->i_count) ||
+ (inode->i_state & ~I_REFERENCED)) {
+ list_del_init(&inode->i_lru);
+ percpu_counter_dec(&nr_inodes_unused);
+ continue;
+ }
+
+ /* recently referenced inodes get one more pass */
+ if (inode->i_state & I_REFERENCED) {
+ list_move(&inode->i_lru, &inode_lru);
+ inode->i_state &= ~I_REFERENCED;
continue;
}
if (inode_has_buffers(inode) || inode->i_data.nrpages) {
@@ -475,18 +635,23 @@ static void prune_icache(int nr_to_scan)
iput(inode);
spin_lock(&inode_lock);
- if (inode != list_entry(inode_unused.next,
- struct inode, i_list))
+ if (inode != list_entry(inode_lru.next,
+ struct inode, i_lru))
continue; /* wrong inode or list_empty */
if (!can_unuse(inode))
continue;
}
- list_move(&inode->i_list, &freeable);
WARN_ON(inode->i_state & I_NEW);
inode->i_state |= I_FREEING;
- nr_pruned++;
+
+ /*
+ * Move the inode off the IO lists and LRU once I_FREEING is
+ * set so that it won't get moved back on there if it is dirty.
+ */
+ list_move(&inode->i_lru, &freeable);
+ list_del_init(&inode->i_wb_list);
+ percpu_counter_dec(&nr_inodes_unused);
}
- inodes_stat.nr_unused -= nr_pruned;
if (current_is_kswapd())
__count_vm_events(KSWAPD_INODESTEAL, reap);
else
@@ -518,7 +683,7 @@ static int shrink_icache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
return -1;
prune_icache(nr);
}
- return (inodes_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
+ return (get_nr_inodes_unused() / 100) * sysctl_vfs_cache_pressure;
}
static struct shrinker icache_shrinker = {
@@ -529,9 +694,6 @@ static struct shrinker icache_shrinker = {
static void __wait_on_freeing_inode(struct inode *inode);
/*
* Called with the inode lock held.
- * NOTE: we are not increasing the inode-refcount, you must call __iget()
- * by hand after calling find_inode now! This simplifies iunique and won't
- * add any additional branch in the common code.
*/
static struct inode *find_inode(struct super_block *sb,
struct hlist_head *head,
@@ -551,9 +713,10 @@ repeat:
__wait_on_freeing_inode(inode);
goto repeat;
}
- break;
+ __iget(inode);
+ return inode;
}
- return node ? inode : NULL;
+ return NULL;
}
/*
@@ -576,53 +739,49 @@ repeat:
__wait_on_freeing_inode(inode);
goto repeat;
}
- break;
+ __iget(inode);
+ return inode;
}
- return node ? inode : NULL;
-}
-
-static unsigned long hash(struct super_block *sb, unsigned long hashval)
-{
- unsigned long tmp;
-
- tmp = (hashval * (unsigned long)sb) ^ (GOLDEN_RATIO_PRIME + hashval) /
- L1_CACHE_BYTES;
- tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> I_HASHBITS);
- return tmp & I_HASHMASK;
-}
-
-static inline void
-__inode_add_to_lists(struct super_block *sb, struct hlist_head *head,
- struct inode *inode)
-{
- inodes_stat.nr_inodes++;
- list_add(&inode->i_list, &inode_in_use);
- list_add(&inode->i_sb_list, &sb->s_inodes);
- if (head)
- hlist_add_head(&inode->i_hash, head);
+ return NULL;
}
-/**
- * inode_add_to_lists - add a new inode to relevant lists
- * @sb: superblock inode belongs to
- * @inode: inode to mark in use
+/*
+ * Each cpu owns a range of LAST_INO_BATCH numbers.
+ * 'shared_last_ino' is dirtied only once out of LAST_INO_BATCH allocations,
+ * to renew the exhausted range.
*
- * When an inode is allocated it needs to be accounted for, added to the in use
- * list, the owning superblock and the inode hash. This needs to be done under
- * the inode_lock, so export a function to do this rather than the inode lock
- * itself. We calculate the hash list to add to here so it is all internal
- * which requires the caller to have already set up the inode number in the
- * inode to add.
+ * This does not significantly increase overflow rate because every CPU can
+ * consume at most LAST_INO_BATCH-1 unused inode numbers. So there is
+ * NR_CPUS*(LAST_INO_BATCH-1) wastage. At 4096 and 1024, this is ~0.1% of the
+ * 2^32 range, and is a worst-case. Even a 50% wastage would only increase
+ * overflow rate by 2x, which does not seem too significant.
+ *
+ * On a 32bit, non LFS stat() call, glibc will generate an EOVERFLOW
+ * error if st_ino won't fit in target struct field. Use 32bit counter
+ * here to attempt to avoid that.
*/
-void inode_add_to_lists(struct super_block *sb, struct inode *inode)
+#define LAST_INO_BATCH 1024
+static DEFINE_PER_CPU(unsigned int, last_ino);
+
+unsigned int get_next_ino(void)
{
- struct hlist_head *head = inode_hashtable + hash(sb, inode->i_ino);
+ unsigned int *p = &get_cpu_var(last_ino);
+ unsigned int res = *p;
- spin_lock(&inode_lock);
- __inode_add_to_lists(sb, head, inode);
- spin_unlock(&inode_lock);
+#ifdef CONFIG_SMP
+ if (unlikely((res & (LAST_INO_BATCH-1)) == 0)) {
+ static atomic_t shared_last_ino;
+ int next = atomic_add_return(LAST_INO_BATCH, &shared_last_ino);
+
+ res = next - LAST_INO_BATCH;
+ }
+#endif
+
+ *p = ++res;
+ put_cpu_var(last_ino);
+ return res;
}
-EXPORT_SYMBOL_GPL(inode_add_to_lists);
+EXPORT_SYMBOL(get_next_ino);
/**
* new_inode - obtain an inode
@@ -638,12 +797,6 @@ EXPORT_SYMBOL_GPL(inode_add_to_lists);
*/
struct inode *new_inode(struct super_block *sb)
{
- /*
- * On a 32bit, non LFS stat() call, glibc will generate an EOVERFLOW
- * error if st_ino won't fit in target struct field. Use 32bit counter
- * here to attempt to avoid that.
- */
- static unsigned int last_ino;
struct inode *inode;
spin_lock_prefetch(&inode_lock);
@@ -651,8 +804,7 @@ struct inode *new_inode(struct super_block *sb)
inode = alloc_inode(sb);
if (inode) {
spin_lock(&inode_lock);
- __inode_add_to_lists(sb, NULL, inode);
- inode->i_ino = ++last_ino;
+ __inode_sb_list_add(inode);
inode->i_state = 0;
spin_unlock(&inode_lock);
}
@@ -663,7 +815,7 @@ EXPORT_SYMBOL(new_inode);
void unlock_new_inode(struct inode *inode)
{
#ifdef CONFIG_DEBUG_LOCK_ALLOC
- if (inode->i_mode & S_IFDIR) {
+ if (S_ISDIR(inode->i_mode)) {
struct file_system_type *type = inode->i_sb->s_type;
/* Set new key only if filesystem hasn't already changed it */
@@ -720,7 +872,8 @@ static struct inode *get_new_inode(struct super_block *sb,
if (set(inode, data))
goto set_failed;
- __inode_add_to_lists(sb, head, inode);
+ hlist_add_head(&inode->i_hash, head);
+ __inode_sb_list_add(inode);
inode->i_state = I_NEW;
spin_unlock(&inode_lock);
@@ -735,7 +888,6 @@ static struct inode *get_new_inode(struct super_block *sb,
* us. Use the old inode instead of the one we just
* allocated.
*/
- __iget(old);
spin_unlock(&inode_lock);
destroy_inode(inode);
inode = old;
@@ -767,7 +919,8 @@ static struct inode *get_new_inode_fast(struct super_block *sb,
old = find_inode_fast(sb, head, ino);
if (!old) {
inode->i_ino = ino;
- __inode_add_to_lists(sb, head, inode);
+ hlist_add_head(&inode->i_hash, head);
+ __inode_sb_list_add(inode);
inode->i_state = I_NEW;
spin_unlock(&inode_lock);
@@ -782,7 +935,6 @@ static struct inode *get_new_inode_fast(struct super_block *sb,
* us. Use the old inode instead of the one we just
* allocated.
*/
- __iget(old);
spin_unlock(&inode_lock);
destroy_inode(inode);
inode = old;
@@ -791,6 +943,27 @@ static struct inode *get_new_inode_fast(struct super_block *sb,
return inode;
}
+/*
+ * search the inode cache for a matching inode number.
+ * If we find one, then the inode number we are trying to
+ * allocate is not unique and so we should not use it.
+ *
+ * Returns 1 if the inode number is unique, 0 if it is not.
+ */
+static int test_inode_iunique(struct super_block *sb, unsigned long ino)
+{
+ struct hlist_head *b = inode_hashtable + hash(sb, ino);
+ struct hlist_node *node;
+ struct inode *inode;
+
+ hlist_for_each_entry(inode, node, b, i_hash) {
+ if (inode->i_ino == ino && inode->i_sb == sb)
+ return 0;
+ }
+
+ return 1;
+}
+
/**
* iunique - get a unique inode number
* @sb: superblock
@@ -812,19 +985,18 @@ ino_t iunique(struct super_block *sb, ino_t max_reserved)
* error if st_ino won't fit in target struct field. Use 32bit counter
* here to attempt to avoid that.
*/
+ static DEFINE_SPINLOCK(iunique_lock);
static unsigned int counter;
- struct inode *inode;
- struct hlist_head *head;
ino_t res;
spin_lock(&inode_lock);
+ spin_lock(&iunique_lock);
do {
if (counter <= max_reserved)
counter = max_reserved + 1;
res = counter++;
- head = inode_hashtable + hash(sb, res);
- inode = find_inode_fast(sb, head, res);
- } while (inode != NULL);
+ } while (!test_inode_iunique(sb, res));
+ spin_unlock(&iunique_lock);
spin_unlock(&inode_lock);
return res;
@@ -876,7 +1048,6 @@ static struct inode *ifind(struct super_block *sb,
spin_lock(&inode_lock);
inode = find_inode(sb, head, test, data);
if (inode) {
- __iget(inode);
spin_unlock(&inode_lock);
if (likely(wait))
wait_on_inode(inode);
@@ -909,7 +1080,6 @@ static struct inode *ifind_fast(struct super_block *sb,
spin_lock(&inode_lock);
inode = find_inode_fast(sb, head, ino);
if (inode) {
- __iget(inode);
spin_unlock(&inode_lock);
wait_on_inode(inode);
return inode;
@@ -1095,7 +1265,7 @@ int insert_inode_locked(struct inode *inode)
__iget(old);
spin_unlock(&inode_lock);
wait_on_inode(old);
- if (unlikely(!hlist_unhashed(&old->i_hash))) {
+ if (unlikely(!inode_unhashed(old))) {
iput(old);
return -EBUSY;
}
@@ -1134,7 +1304,7 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval,
__iget(old);
spin_unlock(&inode_lock);
wait_on_inode(old);
- if (unlikely(!hlist_unhashed(&old->i_hash))) {
+ if (unlikely(!inode_unhashed(old))) {
iput(old);
return -EBUSY;
}
@@ -1143,36 +1313,6 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval,
}
EXPORT_SYMBOL(insert_inode_locked4);
-/**
- * __insert_inode_hash - hash an inode
- * @inode: unhashed inode
- * @hashval: unsigned long value used to locate this object in the
- * inode_hashtable.
- *
- * Add an inode to the inode hash for this superblock.
- */
-void __insert_inode_hash(struct inode *inode, unsigned long hashval)
-{
- struct hlist_head *head = inode_hashtable + hash(inode->i_sb, hashval);
- spin_lock(&inode_lock);
- hlist_add_head(&inode->i_hash, head);
- spin_unlock(&inode_lock);
-}
-EXPORT_SYMBOL(__insert_inode_hash);
-
-/**
- * remove_inode_hash - remove an inode from the hash
- * @inode: inode to unhash
- *
- * Remove an inode from the superblock.
- */
-void remove_inode_hash(struct inode *inode)
-{
- spin_lock(&inode_lock);
- hlist_del_init(&inode->i_hash);
- spin_unlock(&inode_lock);
-}
-EXPORT_SYMBOL(remove_inode_hash);
int generic_delete_inode(struct inode *inode)
{
@@ -1187,7 +1327,7 @@ EXPORT_SYMBOL(generic_delete_inode);
*/
int generic_drop_inode(struct inode *inode)
{
- return !inode->i_nlink || hlist_unhashed(&inode->i_hash);
+ return !inode->i_nlink || inode_unhashed(inode);
}
EXPORT_SYMBOL_GPL(generic_drop_inode);
@@ -1213,10 +1353,11 @@ static void iput_final(struct inode *inode)
drop = generic_drop_inode(inode);
if (!drop) {
- if (!(inode->i_state & (I_DIRTY|I_SYNC)))
- list_move(&inode->i_list, &inode_unused);
- inodes_stat.nr_unused++;
if (sb->s_flags & MS_ACTIVE) {
+ inode->i_state |= I_REFERENCED;
+ if (!(inode->i_state & (I_DIRTY|I_SYNC))) {
+ inode_lru_list_add(inode);
+ }
spin_unlock(&inode_lock);
return;
}
@@ -1227,19 +1368,23 @@ static void iput_final(struct inode *inode)
spin_lock(&inode_lock);
WARN_ON(inode->i_state & I_NEW);
inode->i_state &= ~I_WILL_FREE;
- inodes_stat.nr_unused--;
- hlist_del_init(&inode->i_hash);
+ __remove_inode_hash(inode);
}
- list_del_init(&inode->i_list);
- list_del_init(&inode->i_sb_list);
+
WARN_ON(inode->i_state & I_NEW);
inode->i_state |= I_FREEING;
- inodes_stat.nr_inodes--;
+
+ /*
+ * Move the inode off the IO lists and LRU once I_FREEING is
+ * set so that it won't get moved back on there if it is dirty.
+ */
+ inode_lru_list_del(inode);
+ list_del_init(&inode->i_wb_list);
+
+ __inode_sb_list_del(inode);
spin_unlock(&inode_lock);
evict(inode);
- spin_lock(&inode_lock);
- hlist_del_init(&inode->i_hash);
- spin_unlock(&inode_lock);
+ remove_inode_hash(inode);
wake_up_inode(inode);
BUG_ON(inode->i_state != (I_FREEING | I_CLEAR));
destroy_inode(inode);
@@ -1503,6 +1648,8 @@ void __init inode_init(void)
SLAB_MEM_SPREAD),
init_once);
register_shrinker(&icache_shrinker);
+ percpu_counter_init(&nr_inodes, 0);
+ percpu_counter_init(&nr_inodes_unused, 0);
/* Hash may have been set up in inode_init_early */
if (!hashdist)
diff --git a/fs/internal.h b/fs/internal.h
index a6910e91cee8..ebad3b90752d 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -101,3 +101,10 @@ extern void put_super(struct super_block *sb);
struct nameidata;
extern struct file *nameidata_to_filp(struct nameidata *);
extern void release_open_intent(struct nameidata *);
+
+/*
+ * inode.c
+ */
+extern int get_nr_dirty_inodes(void);
+extern int evict_inodes(struct super_block *);
+extern int invalidate_inodes(struct super_block *);
diff --git a/fs/ioctl.c b/fs/ioctl.c
index f855ea4fc888..e92fdbb3bc3a 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -530,6 +530,41 @@ static int ioctl_fsthaw(struct file *filp)
return thaw_super(sb);
}
+static int ioctl_fstrim(struct file *filp, void __user *argp)
+{
+ struct super_block *sb = filp->f_path.dentry->d_inode->i_sb;
+ struct fstrim_range range;
+ int ret = 0;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ /* If filesystem doesn't support trim feature, return. */
+ if (sb->s_op->trim_fs == NULL)
+ return -EOPNOTSUPP;
+
+ /* If a blockdevice-backed filesystem isn't specified, return EINVAL. */
+ if (sb->s_bdev == NULL)
+ return -EINVAL;
+
+ if (argp == NULL) {
+ range.start = 0;
+ range.len = ULLONG_MAX;
+ range.minlen = 0;
+ } else if (copy_from_user(&range, argp, sizeof(range)))
+ return -EFAULT;
+
+ ret = sb->s_op->trim_fs(sb, &range);
+ if (ret < 0)
+ return ret;
+
+ if ((argp != NULL) &&
+ (copy_to_user(argp, &range, sizeof(range))))
+ return -EFAULT;
+
+ return 0;
+}
+
/*
* When you add any new common ioctls to the switches above and below
* please update compat_sys_ioctl() too.
@@ -580,6 +615,10 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
error = ioctl_fsthaw(filp);
break;
+ case FITRIM:
+ error = ioctl_fstrim(filp, argp);
+ break;
+
case FS_IOC_FIEMAP:
return ioctl_fiemap(filp, arg);
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 09ff41a752a0..79cf7f616bbe 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -544,6 +544,34 @@ static unsigned int isofs_get_last_session(struct super_block *sb, s32 session)
}
/*
+ * Check if root directory is empty (has less than 3 files).
+ *
+ * Used to detect broken CDs where ISO root directory is empty but Joliet root
+ * directory is OK. If such CD has Rock Ridge extensions, they will be disabled
+ * (and Joliet used instead) or else no files would be visible.
+ */
+static bool rootdir_empty(struct super_block *sb, unsigned long block)
+{
+ int offset = 0, files = 0, de_len;
+ struct iso_directory_record *de;
+ struct buffer_head *bh;
+
+ bh = sb_bread(sb, block);
+ if (!bh)
+ return true;
+ while (files < 3) {
+ de = (struct iso_directory_record *) (bh->b_data + offset);
+ de_len = *(unsigned char *) de;
+ if (de_len == 0)
+ break;
+ files++;
+ offset += de_len;
+ }
+ brelse(bh);
+ return files < 3;
+}
+
+/*
* Initialize the superblock and read the root inode.
*
* Note: a check_disk_change() has been done immediately prior
@@ -843,6 +871,18 @@ root_found:
goto out_no_root;
/*
+ * Fix for broken CDs with Rock Ridge and empty ISO root directory but
+ * correct Joliet root directory.
+ */
+ if (sbi->s_rock == 1 && joliet_level &&
+ rootdir_empty(s, sbi->s_firstdatazone)) {
+ printk(KERN_NOTICE
+ "ISOFS: primary root directory is empty. "
+ "Disabling Rock Ridge and switching to Joliet.");
+ sbi->s_rock = 0;
+ }
+
+ /*
* If this disk has both Rock Ridge and Joliet on it, then we
* want to use Rock Ridge by default. This can be overridden
* by using the norock mount option. There is still one other
@@ -962,25 +1002,23 @@ static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
* or getblk() if they are not. Returns the number of blocks inserted
* (-ve == error.)
*/
-int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
+int isofs_get_blocks(struct inode *inode, sector_t iblock,
struct buffer_head **bh, unsigned long nblocks)
{
- unsigned long b_off;
+ unsigned long b_off = iblock;
unsigned offset, sect_size;
unsigned int firstext;
unsigned long nextblk, nextoff;
- long iblock = (long)iblock_s;
int section, rv, error;
struct iso_inode_info *ei = ISOFS_I(inode);
error = -EIO;
rv = 0;
- if (iblock < 0 || iblock != iblock_s) {
+ if (iblock != b_off) {
printk(KERN_DEBUG "%s: block number too large\n", __func__);
goto abort;
}
- b_off = iblock;
offset = 0;
firstext = ei->i_first_extent;
@@ -998,8 +1036,9 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
* I/O errors.
*/
if (b_off > ((inode->i_size + PAGE_CACHE_SIZE - 1) >> ISOFS_BUFFER_BITS(inode))) {
- printk(KERN_DEBUG "%s: block >= EOF (%ld, %ld)\n",
- __func__, iblock, (unsigned long) inode->i_size);
+ printk(KERN_DEBUG "%s: block >= EOF (%lu, %llu)\n",
+ __func__, b_off,
+ (unsigned long long)inode->i_size);
goto abort;
}
@@ -1025,9 +1064,9 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
if (++section > 100) {
printk(KERN_DEBUG "%s: More than 100 file sections ?!?"
" aborting...\n", __func__);
- printk(KERN_DEBUG "%s: block=%ld firstext=%u sect_size=%u "
+ printk(KERN_DEBUG "%s: block=%lu firstext=%u sect_size=%u "
"nextblk=%lu nextoff=%lu\n", __func__,
- iblock, firstext, (unsigned) sect_size,
+ b_off, firstext, (unsigned) sect_size,
nextblk, nextoff);
goto abort;
}
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c
index 05a38b9c4c0e..e4b87bc1fa56 100644
--- a/fs/jbd/checkpoint.c
+++ b/fs/jbd/checkpoint.c
@@ -221,7 +221,7 @@ restart:
goto restart;
}
if (buffer_locked(bh)) {
- atomic_inc(&bh->b_count);
+ get_bh(bh);
spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh);
wait_on_buffer(bh);
@@ -283,7 +283,7 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
int ret = 0;
if (buffer_locked(bh)) {
- atomic_inc(&bh->b_count);
+ get_bh(bh);
spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh);
wait_on_buffer(bh);
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
index 85a6883c0aca..34a4861c14b8 100644
--- a/fs/jbd/commit.c
+++ b/fs/jbd/commit.c
@@ -587,13 +587,13 @@ void journal_commit_transaction(journal_t *journal)
/* Bump b_count to prevent truncate from stumbling over
the shadowed buffer! @@@ This can go if we ever get
rid of the BJ_IO/BJ_Shadow pairing of buffers. */
- atomic_inc(&jh2bh(jh)->b_count);
+ get_bh(jh2bh(jh));
/* Make a temporary IO buffer with which to write it out
(this will requeue both the metadata buffer and the
temporary IO buffer). new_bh goes on BJ_IO*/
- set_bit(BH_JWrite, &jh2bh(jh)->b_state);
+ set_buffer_jwrite(jh2bh(jh));
/*
* akpm: journal_write_metadata_buffer() sets
* new_bh->b_transaction to commit_transaction.
@@ -603,7 +603,7 @@ void journal_commit_transaction(journal_t *journal)
JBUFFER_TRACE(jh, "ph3: write metadata");
flags = journal_write_metadata_buffer(commit_transaction,
jh, &new_jh, blocknr);
- set_bit(BH_JWrite, &jh2bh(new_jh)->b_state);
+ set_buffer_jwrite(jh2bh(new_jh));
wbuf[bufs++] = jh2bh(new_jh);
/* Record the new block's tag in the current descriptor
@@ -713,7 +713,7 @@ wait_for_iobuf:
shadowed buffer */
jh = commit_transaction->t_shadow_list->b_tprev;
bh = jh2bh(jh);
- clear_bit(BH_JWrite, &bh->b_state);
+ clear_buffer_jwrite(bh);
J_ASSERT_BH(bh, buffer_jbddirty(bh));
/* The metadata is now released for reuse, but we need
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index 2c4b1f109da9..da1b5e4ffce1 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -36,6 +36,7 @@
#include <linux/poison.h>
#include <linux/proc_fs.h>
#include <linux/debugfs.h>
+#include <linux/ratelimit.h>
#include <asm/uaccess.h>
#include <asm/page.h>
@@ -84,6 +85,7 @@ EXPORT_SYMBOL(journal_force_commit);
static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
static void __journal_abort_soft (journal_t *journal, int errno);
+static const char *journal_dev_name(journal_t *journal, char *buffer);
/*
* Helper function used to manage commit timeouts
@@ -439,7 +441,7 @@ int __log_start_commit(journal_t *journal, tid_t target)
*/
if (!tid_geq(journal->j_commit_request, target)) {
/*
- * We want a new commit: OK, mark the request and wakup the
+ * We want a new commit: OK, mark the request and wakeup the
* commit thread. We do _not_ do the commit ourselves.
*/
@@ -950,6 +952,8 @@ int journal_create(journal_t *journal)
if (err)
return err;
bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
+ if (unlikely(!bh))
+ return -ENOMEM;
lock_buffer(bh);
memset (bh->b_data, 0, journal->j_blocksize);
BUFFER_TRACE(bh, "marking dirty");
@@ -1010,6 +1014,23 @@ void journal_update_superblock(journal_t *journal, int wait)
goto out;
}
+ if (buffer_write_io_error(bh)) {
+ char b[BDEVNAME_SIZE];
+ /*
+ * Oh, dear. A previous attempt to write the journal
+ * superblock failed. This could happen because the
+ * USB device was yanked out. Or it could happen to
+ * be a transient write error and maybe the block will
+ * be remapped. Nothing we can do but to retry the
+ * write and hope for the best.
+ */
+ printk(KERN_ERR "JBD: previous I/O error detected "
+ "for journal superblock update for %s.\n",
+ journal_dev_name(journal, b));
+ clear_buffer_write_io_error(bh);
+ set_buffer_uptodate(bh);
+ }
+
spin_lock(&journal->j_state_lock);
jbd_debug(1,"JBD: updating superblock (start %u, seq %d, errno %d)\n",
journal->j_tail, journal->j_tail_sequence, journal->j_errno);
@@ -1021,9 +1042,17 @@ void journal_update_superblock(journal_t *journal, int wait)
BUFFER_TRACE(bh, "marking dirty");
mark_buffer_dirty(bh);
- if (wait)
+ if (wait) {
sync_dirty_buffer(bh);
- else
+ if (buffer_write_io_error(bh)) {
+ char b[BDEVNAME_SIZE];
+ printk(KERN_ERR "JBD: I/O error detected "
+ "when updating journal superblock for %s.\n",
+ journal_dev_name(journal, b));
+ clear_buffer_write_io_error(bh);
+ set_buffer_uptodate(bh);
+ }
+ } else
write_dirty_buffer(bh, WRITE);
out:
@@ -1719,7 +1748,6 @@ static void journal_destroy_journal_head_cache(void)
static struct journal_head *journal_alloc_journal_head(void)
{
struct journal_head *ret;
- static unsigned long last_warning;
#ifdef CONFIG_JBD_DEBUG
atomic_inc(&nr_journal_heads);
@@ -1727,11 +1755,9 @@ static struct journal_head *journal_alloc_journal_head(void)
ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS);
if (ret == NULL) {
jbd_debug(1, "out of memory for journal_head\n");
- if (time_after(jiffies, last_warning + 5*HZ)) {
- printk(KERN_NOTICE "ENOMEM in %s, retrying.\n",
- __func__);
- last_warning = jiffies;
- }
+ printk_ratelimited(KERN_NOTICE "ENOMEM in %s, retrying.\n",
+ __func__);
+
while (ret == NULL) {
yield();
ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS);
diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c
index 81051dafebf5..5b43e96788e6 100644
--- a/fs/jbd/recovery.c
+++ b/fs/jbd/recovery.c
@@ -296,10 +296,10 @@ int journal_skip_recovery(journal_t *journal)
#ifdef CONFIG_JBD_DEBUG
int dropped = info.end_transaction -
be32_to_cpu(journal->j_superblock->s_sequence);
-#endif
jbd_debug(1,
"JBD: ignoring %d transaction%s from the journal.\n",
dropped, (dropped == 1) ? "" : "s");
+#endif
journal->j_transaction_sequence = ++info.end_transaction;
}
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index 5ae71e75a491..846a3f314111 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -293,9 +293,7 @@ handle_t *journal_start(journal_t *journal, int nblocks)
jbd_free_handle(handle);
current->journal_info = NULL;
handle = ERR_PTR(err);
- goto out;
}
-out:
return handle;
}
@@ -528,7 +526,7 @@ do_get_write_access(handle_t *handle, struct journal_head *jh,
transaction = handle->h_transaction;
journal = transaction->t_journal;
- jbd_debug(5, "buffer_head %p, force_copy %d\n", jh, force_copy);
+ jbd_debug(5, "journal_head %p, force_copy %d\n", jh, force_copy);
JBUFFER_TRACE(jh, "entry");
repeat:
@@ -713,7 +711,7 @@ done:
J_EXPECT_JH(jh, buffer_uptodate(jh2bh(jh)),
"Possible IO failure.\n");
page = jh2bh(jh)->b_page;
- offset = ((unsigned long) jh2bh(jh)->b_data) & ~PAGE_MASK;
+ offset = offset_in_page(jh2bh(jh)->b_data);
source = kmap_atomic(page, KM_USER0);
memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size);
kunmap_atomic(source, KM_USER0);
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
index 6571a056e55d..6a79fd0a1a32 100644
--- a/fs/jbd2/checkpoint.c
+++ b/fs/jbd2/checkpoint.c
@@ -299,6 +299,16 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
transaction->t_chp_stats.cs_forced_to_close++;
spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh);
+ if (unlikely(journal->j_flags & JBD2_UNMOUNT))
+ /*
+ * The journal thread is dead; so starting and
+ * waiting for a commit to finish will cause
+ * us to wait for a _very_ long time.
+ */
+ printk(KERN_ERR "JBD2: %s: "
+ "Waiting for Godot: block %llu\n",
+ journal->j_devname,
+ (unsigned long long) bh->b_blocknr);
jbd2_log_start_commit(journal, tid);
jbd2_log_wait_commit(journal, tid);
ret = 1;
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index bc6be8bda1cc..f3ad1598b201 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -26,7 +26,9 @@
#include <linux/backing-dev.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
+#include <linux/bitops.h>
#include <trace/events/jbd2.h>
+#include <asm/system.h>
/*
* Default IO end handler for temporary BJ_IO buffer_heads.
@@ -201,7 +203,7 @@ static int journal_submit_data_buffers(journal_t *journal,
spin_lock(&journal->j_list_lock);
list_for_each_entry(jinode, &commit_transaction->t_inode_list, i_list) {
mapping = jinode->i_vfs_inode->i_mapping;
- jinode->i_flags |= JI_COMMIT_RUNNING;
+ set_bit(__JI_COMMIT_RUNNING, &jinode->i_flags);
spin_unlock(&journal->j_list_lock);
/*
* submit the inode data buffers. We use writepage
@@ -216,7 +218,8 @@ static int journal_submit_data_buffers(journal_t *journal,
spin_lock(&journal->j_list_lock);
J_ASSERT(jinode->i_transaction == commit_transaction);
commit_transaction->t_flushed_data_blocks = 1;
- jinode->i_flags &= ~JI_COMMIT_RUNNING;
+ clear_bit(__JI_COMMIT_RUNNING, &jinode->i_flags);
+ smp_mb__after_clear_bit();
wake_up_bit(&jinode->i_flags, __JI_COMMIT_RUNNING);
}
spin_unlock(&journal->j_list_lock);
@@ -237,7 +240,7 @@ static int journal_finish_inode_data_buffers(journal_t *journal,
/* For locking, see the comment in journal_submit_data_buffers() */
spin_lock(&journal->j_list_lock);
list_for_each_entry(jinode, &commit_transaction->t_inode_list, i_list) {
- jinode->i_flags |= JI_COMMIT_RUNNING;
+ set_bit(__JI_COMMIT_RUNNING, &jinode->i_flags);
spin_unlock(&journal->j_list_lock);
err = filemap_fdatawait(jinode->i_vfs_inode->i_mapping);
if (err) {
@@ -253,7 +256,8 @@ static int journal_finish_inode_data_buffers(journal_t *journal,
ret = err;
}
spin_lock(&journal->j_list_lock);
- jinode->i_flags &= ~JI_COMMIT_RUNNING;
+ clear_bit(__JI_COMMIT_RUNNING, &jinode->i_flags);
+ smp_mb__after_clear_bit();
wake_up_bit(&jinode->i_flags, __JI_COMMIT_RUNNING);
}
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 262419f83d80..538417c1fdbb 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -42,12 +42,14 @@
#include <linux/log2.h>
#include <linux/vmalloc.h>
#include <linux/backing-dev.h>
+#include <linux/bitops.h>
#define CREATE_TRACE_POINTS
#include <trace/events/jbd2.h>
#include <asm/uaccess.h>
#include <asm/page.h>
+#include <asm/system.h>
EXPORT_SYMBOL(jbd2_journal_extend);
EXPORT_SYMBOL(jbd2_journal_stop);
@@ -478,7 +480,7 @@ int __jbd2_log_start_commit(journal_t *journal, tid_t target)
*/
if (!tid_geq(journal->j_commit_request, target)) {
/*
- * We want a new commit: OK, mark the request and wakup the
+ * We want a new commit: OK, mark the request and wakeup the
* commit thread. We do _not_ do the commit ourselves.
*/
@@ -2210,7 +2212,7 @@ void jbd2_journal_release_jbd_inode(journal_t *journal,
restart:
spin_lock(&journal->j_list_lock);
/* Is commit writing out inode - we have to wait */
- if (jinode->i_flags & JI_COMMIT_RUNNING) {
+ if (test_bit(__JI_COMMIT_RUNNING, &jinode->i_flags)) {
wait_queue_head_t *wq;
DEFINE_WAIT_BIT(wait, &jinode->i_flags, __JI_COMMIT_RUNNING);
wq = bit_waitqueue(&jinode->i_flags, __JI_COMMIT_RUNNING);
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index f3479d6e0a83..6bf0a242613e 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -156,6 +156,7 @@ alloc_transaction:
*/
repeat:
read_lock(&journal->j_state_lock);
+ BUG_ON(journal->j_flags & JBD2_UNMOUNT);
if (is_journal_aborted(journal) ||
(journal->j_errno != 0 && !(journal->j_flags & JBD2_ACK_ERR))) {
read_unlock(&journal->j_state_lock);
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index ed78a3cf3cb0..79121aa5858b 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -289,7 +289,7 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
mutex_unlock(&f->sem);
d_instantiate(dentry, old_dentry->d_inode);
dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
- atomic_inc(&old_dentry->d_inode->i_count);
+ ihold(old_dentry->d_inode);
}
return ret;
}
@@ -864,7 +864,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
/* Might as well let the VFS know */
d_instantiate(new_dentry, old_dentry->d_inode);
- atomic_inc(&old_dentry->d_inode->i_count);
+ ihold(old_dentry->d_inode);
new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now);
return ret;
}
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
index f8332dc8eeb2..3a09423b6c22 100644
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -497,7 +497,7 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
* appear hashed, but do not put on any lists. hlist_del()
* will work fine and require no locking.
*/
- ip->i_hash.pprev = &ip->i_hash.next;
+ hlist_add_fake(&ip->i_hash);
return (ip);
}
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index c51af2a14516..e1b8493b9aaa 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -1010,15 +1010,13 @@ static int lmLogSync(struct jfs_log * log, int hard_sync)
* option 2 - shutdown file systems
* associated with log ?
* option 3 - extend log ?
- */
- /*
* option 4 - second chance
*
* mark log wrapped, and continue.
* when all active transactions are completed,
- * mark log vaild for recovery.
+ * mark log valid for recovery.
* if crashed during invalid state, log state
- * implies invald log, forcing fsck().
+ * implies invalid log, forcing fsck().
*/
/* mark log state log wrap in log superblock */
/* log->state = LOGWRAP; */
diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
index 7b698f2ec45a..9895595fd2f2 100644
--- a/fs/jfs/jfs_mount.c
+++ b/fs/jfs/jfs_mount.c
@@ -97,7 +97,7 @@ int jfs_mount(struct super_block *sb)
ipaimap = diReadSpecial(sb, AGGREGATE_I, 0);
if (ipaimap == NULL) {
- jfs_err("jfs_mount: Faild to read AGGREGATE_I");
+ jfs_err("jfs_mount: Failed to read AGGREGATE_I");
rc = -EIO;
goto errout20;
}
@@ -148,7 +148,7 @@ int jfs_mount(struct super_block *sb)
if ((sbi->mntflag & JFS_BAD_SAIT) == 0) {
ipaimap2 = diReadSpecial(sb, AGGREGATE_I, 1);
if (!ipaimap2) {
- jfs_err("jfs_mount: Faild to read AGGREGATE_I");
+ jfs_err("jfs_mount: Failed to read AGGREGATE_I");
rc = -EIO;
goto errout35;
}
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index d945ea76b445..9466957ec841 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -1279,7 +1279,7 @@ int txCommit(tid_t tid, /* transaction identifier */
* lazy commit thread finishes processing
*/
if (tblk->xflag & COMMIT_DELETE) {
- atomic_inc(&tblk->u.ip->i_count);
+ ihold(tblk->u.ip);
/*
* Avoid a rare deadlock
*
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index a9cf8e8675be..231ca4af9bce 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -839,7 +839,7 @@ static int jfs_link(struct dentry *old_dentry,
ip->i_ctime = CURRENT_TIME;
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
- atomic_inc(&ip->i_count);
+ ihold(ip);
iplist[0] = ip;
iplist[1] = dir;
diff --git a/fs/libfs.c b/fs/libfs.c
index 62baa0387d6e..304a5132ca27 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -255,7 +255,7 @@ int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *den
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
inc_nlink(inode);
- atomic_inc(&inode->i_count);
+ ihold(inode);
dget(dentry);
d_instantiate(dentry, inode);
return 0;
@@ -892,10 +892,6 @@ EXPORT_SYMBOL_GPL(generic_fh_to_parent);
*/
int generic_file_fsync(struct file *file, int datasync)
{
- struct writeback_control wbc = {
- .sync_mode = WB_SYNC_ALL,
- .nr_to_write = 0, /* metadata-only; caller takes care of data */
- };
struct inode *inode = file->f_mapping->host;
int err;
int ret;
@@ -906,7 +902,7 @@ int generic_file_fsync(struct file *file, int datasync)
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
return ret;
- err = sync_inode(inode, &wbc);
+ err = sync_inode_metadata(inode, 1);
if (ret == 0)
ret = err;
return ret;
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 64fd427c993c..d5bb86866e6c 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -42,6 +42,7 @@ struct nlm_wait {
};
static LIST_HEAD(nlm_blocked);
+static DEFINE_SPINLOCK(nlm_blocked_lock);
/**
* nlmclnt_init - Set up per-NFS mount point lockd data structures
@@ -97,7 +98,10 @@ struct nlm_wait *nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *
block->b_lock = fl;
init_waitqueue_head(&block->b_wait);
block->b_status = nlm_lck_blocked;
+
+ spin_lock(&nlm_blocked_lock);
list_add(&block->b_list, &nlm_blocked);
+ spin_unlock(&nlm_blocked_lock);
}
return block;
}
@@ -106,7 +110,9 @@ void nlmclnt_finish_block(struct nlm_wait *block)
{
if (block == NULL)
return;
+ spin_lock(&nlm_blocked_lock);
list_del(&block->b_list);
+ spin_unlock(&nlm_blocked_lock);
kfree(block);
}
@@ -154,6 +160,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
* Look up blocked request based on arguments.
* Warning: must not use cookie to match it!
*/
+ spin_lock(&nlm_blocked_lock);
list_for_each_entry(block, &nlm_blocked, b_list) {
struct file_lock *fl_blocked = block->b_lock;
@@ -178,6 +185,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
wake_up(&block->b_wait);
res = nlm_granted;
}
+ spin_unlock(&nlm_blocked_lock);
return res;
}
@@ -216,10 +224,6 @@ reclaimer(void *ptr)
allow_signal(SIGKILL);
down_write(&host->h_rwsem);
-
- /* This one ensures that our parent doesn't terminate while the
- * reclaim is in progress */
- lock_kernel();
lockd_up(); /* note: this cannot fail as lockd is already running */
dprintk("lockd: reclaiming locks for host %s\n", host->h_name);
@@ -260,16 +264,17 @@ restart:
dprintk("NLM: done reclaiming locks for host %s\n", host->h_name);
/* Now, wake up all processes that sleep on a blocked lock */
+ spin_lock(&nlm_blocked_lock);
list_for_each_entry(block, &nlm_blocked, b_list) {
if (block->b_host == host) {
block->b_status = nlm_lck_denied_grace_period;
wake_up(&block->b_wait);
}
}
+ spin_unlock(&nlm_blocked_lock);
/* Release host handle after use */
nlm_release_host(host);
lockd_down();
- unlock_kernel();
return 0;
}
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 7932c399fab4..47ea1e1925b8 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -166,7 +166,6 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
/* Set up the argument struct */
nlmclnt_setlockargs(call, fl);
- lock_kernel();
if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
if (fl->fl_type != F_UNLCK) {
call->a_args.block = IS_SETLKW(cmd) ? 1 : 0;
@@ -177,10 +176,8 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
status = nlmclnt_test(call, fl);
else
status = -EINVAL;
-
fl->fl_ops->fl_release_private(fl);
fl->fl_ops = NULL;
- unlock_kernel();
dprintk("lockd: clnt proc returns %d\n", status);
return status;
@@ -226,9 +223,7 @@ void nlm_release_call(struct nlm_rqst *call)
static void nlmclnt_rpc_release(void *data)
{
- lock_kernel();
nlm_release_call(data);
- unlock_kernel();
}
static int nlm_wait_on_grace(wait_queue_head_t *queue)
@@ -448,14 +443,18 @@ out:
static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl)
{
+ spin_lock(&fl->fl_u.nfs_fl.owner->host->h_lock);
new->fl_u.nfs_fl.state = fl->fl_u.nfs_fl.state;
new->fl_u.nfs_fl.owner = nlm_get_lockowner(fl->fl_u.nfs_fl.owner);
list_add_tail(&new->fl_u.nfs_fl.list, &fl->fl_u.nfs_fl.owner->host->h_granted);
+ spin_unlock(&fl->fl_u.nfs_fl.owner->host->h_lock);
}
static void nlmclnt_locks_release_private(struct file_lock *fl)
{
+ spin_lock(&fl->fl_u.nfs_fl.owner->host->h_lock);
list_del(&fl->fl_u.nfs_fl.list);
+ spin_unlock(&fl->fl_u.nfs_fl.owner->host->h_lock);
nlm_put_lockowner(fl->fl_u.nfs_fl.owner);
}
@@ -721,9 +720,7 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
die:
return;
retry_rebind:
- lock_kernel();
nlm_rebind_host(req->a_host);
- unlock_kernel();
retry_unlock:
rpc_restart_call(task);
}
@@ -801,9 +798,7 @@ retry_cancel:
/* Don't ever retry more than 3 times */
if (req->a_retries++ >= NLMCLNT_MAX_RETRIES)
goto die;
- lock_kernel();
nlm_rebind_host(req->a_host);
- unlock_kernel();
rpc_restart_call(task);
rpc_delay(task, 30 * HZ);
}
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index bb464d12104c..25e21e4023b2 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -353,6 +353,7 @@ nlm_bind_host(struct nlm_host *host)
.to_retries = 5U,
};
struct rpc_create_args args = {
+ .net = &init_net,
.protocol = host->h_proto,
.address = nlm_addr(host),
.addrsize = host->h_addrlen,
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index e3015464fbab..e0c918949644 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -69,6 +69,7 @@ static struct rpc_clnt *nsm_create(void)
.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
};
struct rpc_create_args args = {
+ .net = &init_net,
.protocol = XPRT_TRANSPORT_UDP,
.address = (struct sockaddr *)&sin,
.addrsize = sizeof(sin),
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index f1bacf1a0391..abfff9d7979d 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -22,7 +22,6 @@
#include <linux/in.h>
#include <linux/uio.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
@@ -130,15 +129,6 @@ lockd(void *vrqstp)
dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
- /*
- * FIXME: it would be nice if lockd didn't spend its entire life
- * running under the BKL. At the very least, it would be good to
- * have someone clarify what it's intended to protect here. I've
- * seen some handwavy posts about posix locking needing to be
- * done under the BKL, but it's far from clear.
- */
- lock_kernel();
-
if (!nlm_timeout)
nlm_timeout = LOCKD_DFLT_TIMEO;
nlmsvc_timeout = nlm_timeout * HZ;
@@ -195,7 +185,6 @@ lockd(void *vrqstp)
if (nlmsvc_ops)
nlmsvc_invalidate_all();
nlm_shutdown_hosts();
- unlock_kernel();
return 0;
}
@@ -206,7 +195,7 @@ static int create_lockd_listener(struct svc_serv *serv, const char *name,
xprt = svc_find_xprt(serv, name, family, 0);
if (xprt == NULL)
- return svc_create_xprt(serv, name, family, port,
+ return svc_create_xprt(serv, name, &init_net, family, port,
SVC_SOCK_DEFAULTS);
svc_xprt_put(xprt);
return 0;
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 031c6569a134..a336e832475d 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -230,9 +230,7 @@ static void nlm4svc_callback_exit(struct rpc_task *task, void *data)
static void nlm4svc_callback_release(void *data)
{
- lock_kernel();
nlm_release_call(data);
- unlock_kernel();
}
static const struct rpc_call_ops nlm4svc_callback_ops = {
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 84055d31bfc5..c462d346acbd 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -52,12 +52,13 @@ static const struct rpc_call_ops nlmsvc_grant_ops;
* The list of blocked locks to retry
*/
static LIST_HEAD(nlm_blocked);
+static DEFINE_SPINLOCK(nlm_blocked_lock);
/*
* Insert a blocked lock into the global list
*/
static void
-nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
+nlmsvc_insert_block_locked(struct nlm_block *block, unsigned long when)
{
struct nlm_block *b;
struct list_head *pos;
@@ -87,6 +88,13 @@ nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
block->b_when = when;
}
+static void nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
+{
+ spin_lock(&nlm_blocked_lock);
+ nlmsvc_insert_block_locked(block, when);
+ spin_unlock(&nlm_blocked_lock);
+}
+
/*
* Remove a block from the global list
*/
@@ -94,7 +102,9 @@ static inline void
nlmsvc_remove_block(struct nlm_block *block)
{
if (!list_empty(&block->b_list)) {
+ spin_lock(&nlm_blocked_lock);
list_del_init(&block->b_list);
+ spin_unlock(&nlm_blocked_lock);
nlmsvc_release_block(block);
}
}
@@ -651,7 +661,7 @@ static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf,
struct nlm_block *block;
int rc = -ENOENT;
- lock_kernel();
+ spin_lock(&nlm_blocked_lock);
list_for_each_entry(block, &nlm_blocked, b_list) {
if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
dprintk("lockd: nlmsvc_notify_blocked block %p flags %d\n",
@@ -665,13 +675,13 @@ static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf,
} else if (result == 0)
block->b_granted = 1;
- nlmsvc_insert_block(block, 0);
+ nlmsvc_insert_block_locked(block, 0);
svc_wake_up(block->b_daemon);
rc = 0;
break;
}
}
- unlock_kernel();
+ spin_unlock(&nlm_blocked_lock);
if (rc == -ENOENT)
printk(KERN_WARNING "lockd: grant for unknown block\n");
return rc;
@@ -690,14 +700,16 @@ nlmsvc_notify_blocked(struct file_lock *fl)
struct nlm_block *block;
dprintk("lockd: VFS unblock notification for block %p\n", fl);
+ spin_lock(&nlm_blocked_lock);
list_for_each_entry(block, &nlm_blocked, b_list) {
if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
- nlmsvc_insert_block(block, 0);
+ nlmsvc_insert_block_locked(block, 0);
+ spin_unlock(&nlm_blocked_lock);
svc_wake_up(block->b_daemon);
return;
}
}
-
+ spin_unlock(&nlm_blocked_lock);
printk(KERN_WARNING "lockd: notification for unknown block!\n");
}
@@ -803,7 +815,7 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
dprintk("lockd: GRANT_MSG RPC callback\n");
- lock_kernel();
+ spin_lock(&nlm_blocked_lock);
/* if the block is not on a list at this point then it has
* been invalidated. Don't try to requeue it.
*
@@ -825,19 +837,20 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
/* Call was successful, now wait for client callback */
timeout = 60 * HZ;
}
- nlmsvc_insert_block(block, timeout);
+ nlmsvc_insert_block_locked(block, timeout);
svc_wake_up(block->b_daemon);
out:
- unlock_kernel();
+ spin_unlock(&nlm_blocked_lock);
}
+/*
+ * FIXME: nlmsvc_release_block() grabs a mutex. This is not allowed for an
+ * .rpc_release rpc_call_op
+ */
static void nlmsvc_grant_release(void *data)
{
struct nlm_rqst *call = data;
-
- lock_kernel();
nlmsvc_release_block(call->a_block);
- unlock_kernel();
}
static const struct rpc_call_ops nlmsvc_grant_ops = {
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 0f2ab741ae7c..c3069f38d602 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -260,9 +260,7 @@ static void nlmsvc_callback_exit(struct rpc_task *task, void *data)
static void nlmsvc_callback_release(void *data)
{
- lock_kernel();
nlm_release_call(data);
- unlock_kernel();
}
static const struct rpc_call_ops nlmsvc_callback_ops = {
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index d0ef94cfb3da..1ca0679c80bf 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -170,6 +170,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
again:
file->f_locks = 0;
+ lock_flocks(); /* protects i_flock list */
for (fl = inode->i_flock; fl; fl = fl->fl_next) {
if (fl->fl_lmops != &nlmsvc_lock_operations)
continue;
@@ -181,6 +182,7 @@ again:
if (match(lockhost, host)) {
struct file_lock lock = *fl;
+ unlock_flocks();
lock.fl_type = F_UNLCK;
lock.fl_start = 0;
lock.fl_end = OFFSET_MAX;
@@ -192,6 +194,7 @@ again:
goto again;
}
}
+ unlock_flocks();
return 0;
}
@@ -226,10 +229,14 @@ nlm_file_inuse(struct nlm_file *file)
if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
return 1;
+ lock_flocks();
for (fl = inode->i_flock; fl; fl = fl->fl_next) {
- if (fl->fl_lmops == &nlmsvc_lock_operations)
+ if (fl->fl_lmops == &nlmsvc_lock_operations) {
+ unlock_flocks();
return 1;
+ }
}
+ unlock_flocks();
file->f_locks = 0;
return 0;
}
diff --git a/fs/locks.c b/fs/locks.c
index 8b2b6ad56a09..50ec15927aab 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -142,6 +142,7 @@ int lease_break_time = 45;
static LIST_HEAD(file_lock_list);
static LIST_HEAD(blocked_list);
+static DEFINE_SPINLOCK(file_lock_lock);
/*
* Protects the two list heads above, plus the inode->i_flock list
@@ -149,23 +150,24 @@ static LIST_HEAD(blocked_list);
*/
void lock_flocks(void)
{
- lock_kernel();
+ spin_lock(&file_lock_lock);
}
EXPORT_SYMBOL_GPL(lock_flocks);
void unlock_flocks(void)
{
- unlock_kernel();
+ spin_unlock(&file_lock_lock);
}
EXPORT_SYMBOL_GPL(unlock_flocks);
static struct kmem_cache *filelock_cache __read_mostly;
/* Allocate an empty lock structure. */
-static struct file_lock *locks_alloc_lock(void)
+struct file_lock *locks_alloc_lock(void)
{
return kmem_cache_alloc(filelock_cache, GFP_KERNEL);
}
+EXPORT_SYMBOL_GPL(locks_alloc_lock);
void locks_release_private(struct file_lock *fl)
{
@@ -1365,7 +1367,6 @@ int fcntl_getlease(struct file *filp)
int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
{
struct file_lock *fl, **before, **my_before = NULL, *lease;
- struct file_lock *new_fl = NULL;
struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
int error, rdlease_count = 0, wrlease_count = 0;
@@ -1385,11 +1386,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
lease = *flp;
if (arg != F_UNLCK) {
- error = -ENOMEM;
- new_fl = locks_alloc_lock();
- if (new_fl == NULL)
- goto out;
-
error = -EAGAIN;
if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
goto out;
@@ -1434,7 +1430,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
goto out;
}
- error = 0;
if (arg == F_UNLCK)
goto out;
@@ -1442,15 +1437,11 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
if (!leases_enable)
goto out;
- locks_copy_lock(new_fl, lease);
- locks_insert_lock(before, new_fl);
-
- *flp = new_fl;
+ locks_insert_lock(before, lease);
return 0;
out:
- if (new_fl != NULL)
- locks_free_lock(new_fl);
+ locks_free_lock(lease);
return error;
}
EXPORT_SYMBOL(generic_setlease);
@@ -1514,26 +1505,38 @@ EXPORT_SYMBOL_GPL(vfs_setlease);
*/
int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
{
- struct file_lock fl, *flp = &fl;
+ struct file_lock *fl;
+ struct fasync_struct *new;
struct inode *inode = filp->f_path.dentry->d_inode;
int error;
- locks_init_lock(&fl);
- error = lease_init(filp, arg, &fl);
- if (error)
- return error;
+ fl = lease_alloc(filp, arg);
+ if (IS_ERR(fl))
+ return PTR_ERR(fl);
+ new = fasync_alloc();
+ if (!new) {
+ locks_free_lock(fl);
+ return -ENOMEM;
+ }
lock_flocks();
-
- error = __vfs_setlease(filp, arg, &flp);
+ error = __vfs_setlease(filp, arg, &fl);
if (error || arg == F_UNLCK)
goto out_unlock;
- error = fasync_helper(fd, filp, 1, &flp->fl_fasync);
+ /*
+ * fasync_insert_entry() returns the old entry if any.
+ * If there was no old entry, then it used 'new' and
+ * inserted it into the fasync list. Clear new so that
+ * we don't release it here.
+ */
+ if (!fasync_insert_entry(fd, filp, &fl->fl_fasync, new))
+ new = NULL;
+
if (error < 0) {
/* remove lease just inserted by setlease */
- flp->fl_type = F_UNLCK | F_INPROGRESS;
- flp->fl_break_time = jiffies - 10;
+ fl->fl_type = F_UNLCK | F_INPROGRESS;
+ fl->fl_break_time = jiffies - 10;
time_out_leases(inode);
goto out_unlock;
}
@@ -1541,6 +1544,8 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
out_unlock:
unlock_flocks();
+ if (new)
+ fasync_free(new);
return error;
}
@@ -2109,7 +2114,7 @@ EXPORT_SYMBOL_GPL(vfs_cancel_lock);
#include <linux/seq_file.h>
static void lock_get_status(struct seq_file *f, struct file_lock *fl,
- int id, char *pfx)
+ loff_t id, char *pfx)
{
struct inode *inode = NULL;
unsigned int fl_pid;
@@ -2122,7 +2127,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
if (fl->fl_file != NULL)
inode = fl->fl_file->f_path.dentry->d_inode;
- seq_printf(f, "%d:%s ", id, pfx);
+ seq_printf(f, "%lld:%s ", id, pfx);
if (IS_POSIX(fl)) {
seq_printf(f, "%6s %s ",
(fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ",
@@ -2185,24 +2190,27 @@ static int locks_show(struct seq_file *f, void *v)
fl = list_entry(v, struct file_lock, fl_link);
- lock_get_status(f, fl, (long)f->private, "");
+ lock_get_status(f, fl, *((loff_t *)f->private), "");
list_for_each_entry(bfl, &fl->fl_block, fl_block)
- lock_get_status(f, bfl, (long)f->private, " ->");
+ lock_get_status(f, bfl, *((loff_t *)f->private), " ->");
- f->private++;
return 0;
}
static void *locks_start(struct seq_file *f, loff_t *pos)
{
+ loff_t *p = f->private;
+
lock_flocks();
- f->private = (void *)1;
+ *p = (*pos + 1);
return seq_list_start(&file_lock_list, *pos);
}
static void *locks_next(struct seq_file *f, void *v, loff_t *pos)
{
+ loff_t *p = f->private;
+ ++*p;
return seq_list_next(v, &file_lock_list, pos);
}
@@ -2220,14 +2228,14 @@ static const struct seq_operations locks_seq_operations = {
static int locks_open(struct inode *inode, struct file *filp)
{
- return seq_open(filp, &locks_seq_operations);
+ return seq_open_private(filp, &locks_seq_operations, sizeof(loff_t));
}
static const struct file_operations proc_locks_operations = {
.open = locks_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = seq_release_private,
};
static int __init proc_locks_init(void)
diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c
index 1eb4e89e045b..409dfd65e9a1 100644
--- a/fs/logfs/dir.c
+++ b/fs/logfs/dir.c
@@ -569,7 +569,7 @@ static int logfs_link(struct dentry *old_dentry, struct inode *dir,
return -EMLINK;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- atomic_inc(&inode->i_count);
+ ihold(inode);
inode->i_nlink++;
mark_inode_dirty_sync(inode);
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index f3f3578393a4..c0d35a3accef 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -101,7 +101,7 @@ static int minix_link(struct dentry * old_dentry, struct inode * dir,
inode->i_ctime = CURRENT_TIME_SEC;
inode_inc_link_count(inode);
- atomic_inc(&inode->i_count);
+ ihold(inode);
return add_nondir(dentry, inode);
}
diff --git a/fs/namei.c b/fs/namei.c
index 24896e833565..f7dbc06857ab 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1121,11 +1121,13 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
static struct dentry *__lookup_hash(struct qstr *name,
struct dentry *base, struct nameidata *nd)
{
+ struct inode *inode = base->d_inode;
struct dentry *dentry;
- struct inode *inode;
int err;
- inode = base->d_inode;
+ err = exec_permission(inode);
+ if (err)
+ return ERR_PTR(err);
/*
* See if the low-level filesystem might want
@@ -1161,11 +1163,6 @@ out:
*/
static struct dentry *lookup_hash(struct nameidata *nd)
{
- int err;
-
- err = exec_permission(nd->path.dentry->d_inode);
- if (err)
- return ERR_PTR(err);
return __lookup_hash(&nd->last, nd->path.dentry, nd);
}
@@ -1213,9 +1210,6 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
if (err)
return ERR_PTR(err);
- err = exec_permission(base->d_inode);
- if (err)
- return ERR_PTR(err);
return __lookup_hash(&this, base, NULL);
}
@@ -2291,7 +2285,7 @@ static long do_unlinkat(int dfd, const char __user *pathname)
goto slashes;
inode = dentry->d_inode;
if (inode)
- atomic_inc(&inode->i_count);
+ ihold(inode);
error = mnt_want_write(nd.path.mnt);
if (error)
goto exit2;
diff --git a/fs/namespace.c b/fs/namespace.c
index 7ca5182c0bed..8a415c9c5e55 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -595,7 +595,7 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
goto out_free;
}
- mnt->mnt_flags = old->mnt_flags;
+ mnt->mnt_flags = old->mnt_flags & ~MNT_WRITE_HOLD;
atomic_inc(&sb->s_active);
mnt->mnt_sb = sb;
mnt->mnt_root = dget(root);
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index b950415d7c43..ba306658a6db 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -1,7 +1,6 @@
config NFS_FS
tristate "NFS client support"
depends on INET && FILE_LOCKING
- depends on BKL # fix as soon as lockd is done
select LOCKD
select SUNRPC
select NFS_ACL_SUPPORT if NFS_V3_ACL
@@ -77,13 +76,17 @@ config NFS_V4
config NFS_V4_1
bool "NFS client support for NFSv4.1 (EXPERIMENTAL)"
- depends on NFS_V4 && EXPERIMENTAL
+ depends on NFS_FS && NFS_V4 && EXPERIMENTAL
+ select PNFS_FILE_LAYOUT
help
This option enables support for minor version 1 of the NFSv4 protocol
- (draft-ietf-nfsv4-minorversion1) in the kernel's NFS client.
+ (RFC 5661) in the kernel's NFS client.
If unsure, say N.
+config PNFS_FILE_LAYOUT
+ tristate
+
config ROOT_NFS
bool "Root file system on NFS"
depends on NFS_FS=y && IP_PNP
@@ -118,3 +121,14 @@ config NFS_USE_KERNEL_DNS
select DNS_RESOLVER
select KEYS
default y
+
+config NFS_USE_NEW_IDMAPPER
+ bool "Use the new idmapper upcall routine"
+ depends on NFS_V4 && KEYS
+ help
+ Say Y here if you want NFS to use the new idmapper upcall functions.
+ You will need /sbin/request-key (usually provided by the keyutils
+ package). For details, read
+ <file:Documentation/filesystems/nfs/idmapper.txt>.
+
+ If you are unsure, say N.
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index da7fda639eac..4776ff9e3814 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -15,5 +15,9 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
delegation.o idmap.o \
callback.o callback_xdr.o callback_proc.o \
nfs4namespace.o
+nfs-$(CONFIG_NFS_V4_1) += pnfs.o
nfs-$(CONFIG_SYSCTL) += sysctl.o
nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
+
+obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o
+nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index e17b49e2eabd..aeec017fe814 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -109,7 +109,7 @@ nfs4_callback_up(struct svc_serv *serv)
{
int ret;
- ret = svc_create_xprt(serv, "tcp", PF_INET,
+ ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET,
nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
if (ret <= 0)
goto out_err;
@@ -117,7 +117,7 @@ nfs4_callback_up(struct svc_serv *serv)
dprintk("NFS: Callback listener port = %u (af %u)\n",
nfs_callback_tcpport, PF_INET);
- ret = svc_create_xprt(serv, "tcp", PF_INET6,
+ ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET6,
nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
if (ret > 0) {
nfs_callback_tcpport6 = ret;
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 930d10fecdaf..2950fca0c61b 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -118,11 +118,11 @@ int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const n
if (delegation == NULL)
return 0;
- /* seqid is 4-bytes long */
- if (((u32 *) &stateid->data)[0] != 0)
+ if (stateid->stateid.seqid != 0)
return 0;
- if (memcmp(&delegation->stateid.data[4], &stateid->data[4],
- sizeof(stateid->data)-4))
+ if (memcmp(&delegation->stateid.stateid.other,
+ &stateid->stateid.other,
+ NFS4_STATEID_OTHER_SIZE))
return 0;
return 1;
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index e7340729af89..0870d0d4efc0 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -48,6 +48,7 @@
#include "iostat.h"
#include "internal.h"
#include "fscache.h"
+#include "pnfs.h"
#define NFSDBG_FACILITY NFSDBG_CLIENT
@@ -155,7 +156,9 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
cred = rpc_lookup_machine_cred();
if (!IS_ERR(cred))
clp->cl_machine_cred = cred;
-
+#if defined(CONFIG_NFS_V4_1)
+ INIT_LIST_HEAD(&clp->cl_layouts);
+#endif
nfs_fscache_get_client_cookie(clp);
return clp;
@@ -252,6 +255,7 @@ void nfs_put_client(struct nfs_client *clp)
nfs_free_client(clp);
}
}
+EXPORT_SYMBOL_GPL(nfs_put_client);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
/*
@@ -601,6 +605,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp,
{
struct rpc_clnt *clnt = NULL;
struct rpc_create_args args = {
+ .net = &init_net,
.protocol = clp->cl_proto,
.address = (struct sockaddr *)&clp->cl_addr,
.addrsize = clp->cl_addrlen,
@@ -635,7 +640,8 @@ static int nfs_create_rpc_client(struct nfs_client *clp,
*/
static void nfs_destroy_server(struct nfs_server *server)
{
- if (!(server->flags & NFS_MOUNT_NONLM))
+ if (!(server->flags & NFS_MOUNT_LOCAL_FLOCK) ||
+ !(server->flags & NFS_MOUNT_LOCAL_FCNTL))
nlmclnt_done(server->nlm_host);
}
@@ -657,7 +663,8 @@ static int nfs_start_lockd(struct nfs_server *server)
if (nlm_init.nfs_version > 3)
return 0;
- if (server->flags & NFS_MOUNT_NONLM)
+ if ((server->flags & NFS_MOUNT_LOCAL_FLOCK) &&
+ (server->flags & NFS_MOUNT_LOCAL_FCNTL))
return 0;
switch (clp->cl_proto) {
@@ -898,11 +905,13 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *
if (server->wsize > NFS_MAX_FILE_IO_SIZE)
server->wsize = NFS_MAX_FILE_IO_SIZE;
server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ set_pnfs_layoutdriver(server, fsinfo->layouttype);
+
server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
- if (server->dtsize > PAGE_CACHE_SIZE)
- server->dtsize = PAGE_CACHE_SIZE;
+ if (server->dtsize > PAGE_CACHE_SIZE * NFS_MAX_READDIR_PAGES)
+ server->dtsize = PAGE_CACHE_SIZE * NFS_MAX_READDIR_PAGES;
if (server->dtsize > server->rsize)
server->dtsize = server->rsize;
@@ -913,6 +922,8 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *
server->maxfilesize = fsinfo->maxfilesize;
+ server->time_delta = fsinfo->time_delta;
+
/* We're airborne Set socket buffersize */
rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
}
@@ -935,6 +946,7 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str
}
fsinfo.fattr = fattr;
+ fsinfo.layouttype = 0;
error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo);
if (error < 0)
goto out_error;
@@ -1017,6 +1029,7 @@ void nfs_free_server(struct nfs_server *server)
{
dprintk("--> nfs_free_server()\n");
+ unset_pnfs_layoutdriver(server);
spin_lock(&nfs_client_lock);
list_del(&server->client_link);
list_del(&server->master_link);
@@ -1356,8 +1369,9 @@ static int nfs4_init_server(struct nfs_server *server,
/* Initialise the client representation from the mount data */
server->flags = data->flags;
- server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|
- NFS_CAP_POSIX_LOCK;
+ server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|NFS_CAP_POSIX_LOCK;
+ if (!(data->flags & NFS_MOUNT_NORDIRPLUS))
+ server->caps |= NFS_CAP_READDIRPLUS;
server->options = data->options;
/* Get a client record */
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index e257172d438c..07ac3847e562 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -33,11 +33,12 @@
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/sched.h>
+#include <linux/vmalloc.h>
-#include "nfs4_fs.h"
#include "delegation.h"
#include "iostat.h"
#include "internal.h"
+#include "fscache.h"
/* #define NFS_DEBUG_VERBOSE 1 */
@@ -55,6 +56,7 @@ static int nfs_rename(struct inode *, struct dentry *,
struct inode *, struct dentry *);
static int nfs_fsync_dir(struct file *, int);
static loff_t nfs_llseek_dir(struct file *, loff_t, int);
+static int nfs_readdir_clear_array(struct page*, gfp_t);
const struct file_operations nfs_dir_operations = {
.llseek = nfs_llseek_dir,
@@ -80,6 +82,10 @@ const struct inode_operations nfs_dir_inode_operations = {
.setattr = nfs_setattr,
};
+const struct address_space_operations nfs_dir_addr_space_ops = {
+ .releasepage = nfs_readdir_clear_array,
+};
+
#ifdef CONFIG_NFS_V3
const struct inode_operations nfs3_dir_inode_operations = {
.create = nfs_create,
@@ -104,8 +110,9 @@ const struct inode_operations nfs3_dir_inode_operations = {
#ifdef CONFIG_NFS_V4
static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *);
+static int nfs_open_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd);
const struct inode_operations nfs4_dir_inode_operations = {
- .create = nfs_create,
+ .create = nfs_open_create,
.lookup = nfs_atomic_lookup,
.link = nfs_link,
.unlink = nfs_unlink,
@@ -150,51 +157,197 @@ nfs_opendir(struct inode *inode, struct file *filp)
return res;
}
-typedef __be32 * (*decode_dirent_t)(__be32 *, struct nfs_entry *, int);
+struct nfs_cache_array_entry {
+ u64 cookie;
+ u64 ino;
+ struct qstr string;
+};
+
+struct nfs_cache_array {
+ unsigned int size;
+ int eof_index;
+ u64 last_cookie;
+ struct nfs_cache_array_entry array[0];
+};
+
+#define MAX_READDIR_ARRAY ((PAGE_SIZE - sizeof(struct nfs_cache_array)) / sizeof(struct nfs_cache_array_entry))
+
+typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
typedef struct {
struct file *file;
struct page *page;
unsigned long page_index;
- __be32 *ptr;
u64 *dir_cookie;
loff_t current_index;
- struct nfs_entry *entry;
decode_dirent_t decode;
- int plus;
+
unsigned long timestamp;
unsigned long gencount;
- int timestamp_valid;
+ unsigned int cache_entry_index;
+ unsigned int plus:1;
+ unsigned int eof:1;
} nfs_readdir_descriptor_t;
-/* Now we cache directories properly, by stuffing the dirent
- * data directly in the page cache.
- *
- * Inode invalidation due to refresh etc. takes care of
- * _everything_, no sloppy entry flushing logic, no extraneous
- * copying, network direct to page cache, the way it was meant
- * to be.
- *
- * NOTE: Dirent information verification is done always by the
- * page-in of the RPC reply, nowhere else, this simplies
- * things substantially.
+/*
+ * The caller is responsible for calling nfs_readdir_release_array(page)
*/
static
-int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
+struct nfs_cache_array *nfs_readdir_get_array(struct page *page)
+{
+ if (page == NULL)
+ return ERR_PTR(-EIO);
+ return (struct nfs_cache_array *)kmap(page);
+}
+
+static
+void nfs_readdir_release_array(struct page *page)
+{
+ kunmap(page);
+}
+
+/*
+ * we are freeing strings created by nfs_add_to_readdir_array()
+ */
+static
+int nfs_readdir_clear_array(struct page *page, gfp_t mask)
+{
+ struct nfs_cache_array *array = nfs_readdir_get_array(page);
+ int i;
+ for (i = 0; i < array->size; i++)
+ kfree(array->array[i].string.name);
+ nfs_readdir_release_array(page);
+ return 0;
+}
+
+/*
+ * the caller is responsible for freeing qstr.name
+ * when called by nfs_readdir_add_to_array, the strings will be freed in
+ * nfs_clear_readdir_array()
+ */
+static
+int nfs_readdir_make_qstr(struct qstr *string, const char *name, unsigned int len)
+{
+ string->len = len;
+ string->name = kmemdup(name, len, GFP_KERNEL);
+ if (string->name == NULL)
+ return -ENOMEM;
+ string->hash = full_name_hash(name, len);
+ return 0;
+}
+
+static
+int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)
+{
+ struct nfs_cache_array *array = nfs_readdir_get_array(page);
+ struct nfs_cache_array_entry *cache_entry;
+ int ret;
+
+ if (IS_ERR(array))
+ return PTR_ERR(array);
+ ret = -EIO;
+ if (array->size >= MAX_READDIR_ARRAY)
+ goto out;
+
+ cache_entry = &array->array[array->size];
+ cache_entry->cookie = entry->prev_cookie;
+ cache_entry->ino = entry->ino;
+ ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len);
+ if (ret)
+ goto out;
+ array->last_cookie = entry->cookie;
+ if (entry->eof == 1)
+ array->eof_index = array->size;
+ array->size++;
+out:
+ nfs_readdir_release_array(page);
+ return ret;
+}
+
+static
+int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc)
+{
+ loff_t diff = desc->file->f_pos - desc->current_index;
+ unsigned int index;
+
+ if (diff < 0)
+ goto out_eof;
+ if (diff >= array->size) {
+ if (array->eof_index > 0)
+ goto out_eof;
+ desc->current_index += array->size;
+ return -EAGAIN;
+ }
+
+ index = (unsigned int)diff;
+ *desc->dir_cookie = array->array[index].cookie;
+ desc->cache_entry_index = index;
+ if (index == array->eof_index)
+ desc->eof = 1;
+ return 0;
+out_eof:
+ desc->eof = 1;
+ return -EBADCOOKIE;
+}
+
+static
+int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc)
+{
+ int i;
+ int status = -EAGAIN;
+
+ for (i = 0; i < array->size; i++) {
+ if (i == array->eof_index) {
+ desc->eof = 1;
+ status = -EBADCOOKIE;
+ }
+ if (array->array[i].cookie == *desc->dir_cookie) {
+ desc->cache_entry_index = i;
+ status = 0;
+ break;
+ }
+ }
+
+ return status;
+}
+
+static
+int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc)
+{
+ struct nfs_cache_array *array;
+ int status = -EBADCOOKIE;
+
+ if (desc->dir_cookie == NULL)
+ goto out;
+
+ array = nfs_readdir_get_array(desc->page);
+ if (IS_ERR(array)) {
+ status = PTR_ERR(array);
+ goto out;
+ }
+
+ if (*desc->dir_cookie == 0)
+ status = nfs_readdir_search_for_pos(array, desc);
+ else
+ status = nfs_readdir_search_for_cookie(array, desc);
+
+ nfs_readdir_release_array(desc->page);
+out:
+ return status;
+}
+
+/* Fill a page with xdr information before transferring to the cache page */
+static
+int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc,
+ struct nfs_entry *entry, struct file *file, struct inode *inode)
{
- struct file *file = desc->file;
- struct inode *inode = file->f_path.dentry->d_inode;
struct rpc_cred *cred = nfs_file_cred(file);
unsigned long timestamp, gencount;
int error;
- dfprintk(DIRCACHE, "NFS: %s: reading cookie %Lu into page %lu\n",
- __func__, (long long)desc->entry->cookie,
- page->index);
-
again:
timestamp = jiffies;
gencount = nfs_inc_attr_generation_counter();
- error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, desc->entry->cookie, page,
+ error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, entry->cookie, pages,
NFS_SERVER(inode)->dtsize, desc->plus);
if (error < 0) {
/* We requested READDIRPLUS, but the server doesn't grok it */
@@ -208,190 +361,292 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
}
desc->timestamp = timestamp;
desc->gencount = gencount;
- desc->timestamp_valid = 1;
- SetPageUptodate(page);
- /* Ensure consistent page alignment of the data.
- * Note: assumes we have exclusive access to this mapping either
- * through inode->i_mutex or some other mechanism.
- */
- if (invalidate_inode_pages2_range(inode->i_mapping, page->index + 1, -1) < 0) {
- /* Should never happen */
- nfs_zap_mapping(inode, inode->i_mapping);
- }
- unlock_page(page);
- return 0;
- error:
- unlock_page(page);
- return -EIO;
+error:
+ return error;
}
-static inline
-int dir_decode(nfs_readdir_descriptor_t *desc)
+/* Fill in an entry based on the xdr code stored in desc->page */
+static
+int xdr_decode(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, struct xdr_stream *stream)
{
- __be32 *p = desc->ptr;
- p = desc->decode(p, desc->entry, desc->plus);
+ __be32 *p = desc->decode(stream, entry, NFS_SERVER(desc->file->f_path.dentry->d_inode), desc->plus);
if (IS_ERR(p))
return PTR_ERR(p);
- desc->ptr = p;
- if (desc->timestamp_valid) {
- desc->entry->fattr->time_start = desc->timestamp;
- desc->entry->fattr->gencount = desc->gencount;
- } else
- desc->entry->fattr->valid &= ~NFS_ATTR_FATTR;
+
+ entry->fattr->time_start = desc->timestamp;
+ entry->fattr->gencount = desc->gencount;
return 0;
}
-static inline
-void dir_page_release(nfs_readdir_descriptor_t *desc)
+static
+int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
{
- kunmap(desc->page);
- page_cache_release(desc->page);
- desc->page = NULL;
- desc->ptr = NULL;
+ struct nfs_inode *node;
+ if (dentry->d_inode == NULL)
+ goto different;
+ node = NFS_I(dentry->d_inode);
+ if (node->fh.size != entry->fh->size)
+ goto different;
+ if (strncmp(node->fh.data, entry->fh->data, node->fh.size) != 0)
+ goto different;
+ return 1;
+different:
+ return 0;
}
-/*
- * Given a pointer to a buffer that has already been filled by a call
- * to readdir, find the next entry with cookie '*desc->dir_cookie'.
- *
- * If the end of the buffer has been reached, return -EAGAIN, if not,
- * return the offset within the buffer of the next entry to be
- * read.
- */
-static inline
-int find_dirent(nfs_readdir_descriptor_t *desc)
+static
+void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
{
- struct nfs_entry *entry = desc->entry;
- int loop_count = 0,
- status;
+ struct qstr filename = {
+ .len = entry->len,
+ .name = entry->name,
+ };
+ struct dentry *dentry;
+ struct dentry *alias;
+ struct inode *dir = parent->d_inode;
+ struct inode *inode;
- while((status = dir_decode(desc)) == 0) {
- dfprintk(DIRCACHE, "NFS: %s: examining cookie %Lu\n",
- __func__, (unsigned long long)entry->cookie);
- if (entry->prev_cookie == *desc->dir_cookie)
- break;
- if (loop_count++ > 200) {
- loop_count = 0;
- schedule();
+ if (filename.name[0] == '.') {
+ if (filename.len == 1)
+ return;
+ if (filename.len == 2 && filename.name[1] == '.')
+ return;
+ }
+ filename.hash = full_name_hash(filename.name, filename.len);
+
+ dentry = d_lookup(parent, &filename);
+ if (dentry != NULL) {
+ if (nfs_same_file(dentry, entry)) {
+ nfs_refresh_inode(dentry->d_inode, entry->fattr);
+ goto out;
+ } else {
+ d_drop(dentry);
+ dput(dentry);
}
}
- return status;
+
+ dentry = d_alloc(parent, &filename);
+ if (dentry == NULL)
+ return;
+
+ dentry->d_op = NFS_PROTO(dir)->dentry_ops;
+ inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr);
+ if (IS_ERR(inode))
+ goto out;
+
+ alias = d_materialise_unique(dentry, inode);
+ if (IS_ERR(alias))
+ goto out;
+ else if (alias) {
+ nfs_set_verifier(alias, nfs_save_change_attribute(dir));
+ dput(alias);
+ } else
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+
+out:
+ dput(dentry);
+}
+
+/* Perform conversion from xdr to cache array */
+static
+void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry,
+ void *xdr_page, struct page *page, unsigned int buflen)
+{
+ struct xdr_stream stream;
+ struct xdr_buf buf;
+ __be32 *ptr = xdr_page;
+ int status;
+ struct nfs_cache_array *array;
+
+ buf.head->iov_base = xdr_page;
+ buf.head->iov_len = buflen;
+ buf.tail->iov_len = 0;
+ buf.page_base = 0;
+ buf.page_len = 0;
+ buf.buflen = buf.head->iov_len;
+ buf.len = buf.head->iov_len;
+
+ xdr_init_decode(&stream, &buf, ptr);
+
+
+ do {
+ status = xdr_decode(desc, entry, &stream);
+ if (status != 0)
+ break;
+
+ if (nfs_readdir_add_to_array(entry, page) == -1)
+ break;
+ if (desc->plus == 1)
+ nfs_prime_dcache(desc->file->f_path.dentry, entry);
+ } while (!entry->eof);
+
+ if (status == -EBADCOOKIE && entry->eof) {
+ array = nfs_readdir_get_array(page);
+ array->eof_index = array->size - 1;
+ status = 0;
+ nfs_readdir_release_array(page);
+ }
+}
+
+static
+void nfs_readdir_free_pagearray(struct page **pages, unsigned int npages)
+{
+ unsigned int i;
+ for (i = 0; i < npages; i++)
+ put_page(pages[i]);
+}
+
+static
+void nfs_readdir_free_large_page(void *ptr, struct page **pages,
+ unsigned int npages)
+{
+ vm_unmap_ram(ptr, npages);
+ nfs_readdir_free_pagearray(pages, npages);
}
/*
- * Given a pointer to a buffer that has already been filled by a call
- * to readdir, find the entry at offset 'desc->file->f_pos'.
- *
- * If the end of the buffer has been reached, return -EAGAIN, if not,
- * return the offset within the buffer of the next entry to be
- * read.
+ * nfs_readdir_large_page will allocate pages that must be freed with a call
+ * to nfs_readdir_free_large_page
*/
-static inline
-int find_dirent_index(nfs_readdir_descriptor_t *desc)
+static
+void *nfs_readdir_large_page(struct page **pages, unsigned int npages)
{
- struct nfs_entry *entry = desc->entry;
- int loop_count = 0,
- status;
+ void *ptr;
+ unsigned int i;
+
+ for (i = 0; i < npages; i++) {
+ struct page *page = alloc_page(GFP_KERNEL);
+ if (page == NULL)
+ goto out_freepages;
+ pages[i] = page;
+ }
- for(;;) {
- status = dir_decode(desc);
- if (status)
- break;
+ ptr = vm_map_ram(pages, npages, 0, PAGE_KERNEL);
+ if (!IS_ERR_OR_NULL(ptr))
+ return ptr;
+out_freepages:
+ nfs_readdir_free_pagearray(pages, i);
+ return NULL;
+}
+
+static
+int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, struct inode *inode)
+{
+ struct page *pages[NFS_MAX_READDIR_PAGES];
+ void *pages_ptr = NULL;
+ struct nfs_entry entry;
+ struct file *file = desc->file;
+ struct nfs_cache_array *array;
+ int status = 0;
+ unsigned int array_size = ARRAY_SIZE(pages);
+
+ entry.prev_cookie = 0;
+ entry.cookie = *desc->dir_cookie;
+ entry.eof = 0;
+ entry.fh = nfs_alloc_fhandle();
+ entry.fattr = nfs_alloc_fattr();
+ if (entry.fh == NULL || entry.fattr == NULL)
+ goto out;
- dfprintk(DIRCACHE, "NFS: found cookie %Lu at index %Ld\n",
- (unsigned long long)entry->cookie, desc->current_index);
+ array = nfs_readdir_get_array(page);
+ memset(array, 0, sizeof(struct nfs_cache_array));
+ array->eof_index = -1;
- if (desc->file->f_pos == desc->current_index) {
- *desc->dir_cookie = entry->cookie;
+ pages_ptr = nfs_readdir_large_page(pages, array_size);
+ if (!pages_ptr)
+ goto out_release_array;
+ do {
+ status = nfs_readdir_xdr_filler(pages, desc, &entry, file, inode);
+
+ if (status < 0)
break;
- }
- desc->current_index++;
- if (loop_count++ > 200) {
- loop_count = 0;
- schedule();
- }
- }
+ nfs_readdir_page_filler(desc, &entry, pages_ptr, page, array_size * PAGE_SIZE);
+ } while (array->eof_index < 0 && array->size < MAX_READDIR_ARRAY);
+
+ nfs_readdir_free_large_page(pages_ptr, pages, array_size);
+out_release_array:
+ nfs_readdir_release_array(page);
+out:
+ nfs_free_fattr(entry.fattr);
+ nfs_free_fhandle(entry.fh);
return status;
}
/*
- * Find the given page, and call find_dirent() or find_dirent_index in
- * order to try to return the next entry.
+ * Now we cache directories properly, by converting xdr information
+ * to an array that can be used for lookups later. This results in
+ * fewer cache pages, since we can store more information on each page.
+ * We only need to convert from xdr once so future lookups are much simpler
*/
-static inline
-int find_dirent_page(nfs_readdir_descriptor_t *desc)
+static
+int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page)
{
struct inode *inode = desc->file->f_path.dentry->d_inode;
- struct page *page;
- int status;
- dfprintk(DIRCACHE, "NFS: %s: searching page %ld for target %Lu\n",
- __func__, desc->page_index,
- (long long) *desc->dir_cookie);
+ if (nfs_readdir_xdr_to_array(desc, page, inode) < 0)
+ goto error;
+ SetPageUptodate(page);
- /* If we find the page in the page_cache, we cannot be sure
- * how fresh the data is, so we will ignore readdir_plus attributes.
- */
- desc->timestamp_valid = 0;
- page = read_cache_page(inode->i_mapping, desc->page_index,
- (filler_t *)nfs_readdir_filler, desc);
- if (IS_ERR(page)) {
- status = PTR_ERR(page);
- goto out;
+ if (invalidate_inode_pages2_range(inode->i_mapping, page->index + 1, -1) < 0) {
+ /* Should never happen */
+ nfs_zap_mapping(inode, inode->i_mapping);
}
+ unlock_page(page);
+ return 0;
+ error:
+ unlock_page(page);
+ return -EIO;
+}
- /* NOTE: Someone else may have changed the READDIRPLUS flag */
- desc->page = page;
- desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */
- if (*desc->dir_cookie != 0)
- status = find_dirent(desc);
- else
- status = find_dirent_index(desc);
- if (status < 0)
- dir_page_release(desc);
- out:
- dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __func__, status);
- return status;
+static
+void cache_page_release(nfs_readdir_descriptor_t *desc)
+{
+ page_cache_release(desc->page);
+ desc->page = NULL;
+}
+
+static
+struct page *get_cache_page(nfs_readdir_descriptor_t *desc)
+{
+ struct page *page;
+ page = read_cache_page(desc->file->f_path.dentry->d_inode->i_mapping,
+ desc->page_index, (filler_t *)nfs_readdir_filler, desc);
+ if (IS_ERR(page))
+ desc->eof = 1;
+ return page;
}
/*
- * Recurse through the page cache pages, and return a
- * filled nfs_entry structure of the next directory entry if possible.
- *
- * The target for the search is '*desc->dir_cookie' if non-0,
- * 'desc->file->f_pos' otherwise
+ * Returns 0 if desc->dir_cookie was found on page desc->page_index
*/
+static
+int find_cache_page(nfs_readdir_descriptor_t *desc)
+{
+ int res;
+
+ desc->page = get_cache_page(desc);
+ if (IS_ERR(desc->page))
+ return PTR_ERR(desc->page);
+
+ res = nfs_readdir_search_array(desc);
+ if (res == 0)
+ return 0;
+ cache_page_release(desc);
+ return res;
+}
+
+/* Search for desc->dir_cookie from the beginning of the page cache */
static inline
int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
{
- int loop_count = 0;
- int res;
-
- /* Always search-by-index from the beginning of the cache */
- if (*desc->dir_cookie == 0) {
- dfprintk(DIRCACHE, "NFS: readdir_search_pagecache() searching for offset %Ld\n",
- (long long)desc->file->f_pos);
- desc->page_index = 0;
- desc->entry->cookie = desc->entry->prev_cookie = 0;
- desc->entry->eof = 0;
- desc->current_index = 0;
- } else
- dfprintk(DIRCACHE, "NFS: readdir_search_pagecache() searching for cookie %Lu\n",
- (unsigned long long)*desc->dir_cookie);
+ int res = -EAGAIN;
- for (;;) {
- res = find_dirent_page(desc);
+ while (1) {
+ res = find_cache_page(desc);
if (res != -EAGAIN)
break;
- /* Align to beginning of next page */
- desc->page_index ++;
- if (loop_count++ > 200) {
- loop_count = 0;
- schedule();
- }
+ desc->page_index++;
}
-
- dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __func__, res);
return res;
}
@@ -400,8 +655,6 @@ static inline unsigned int dt_type(struct inode *inode)
return (inode->i_mode >> 12) & 15;
}
-static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc);
-
/*
* Once we've found the start of the dirent within a page: fill 'er up...
*/
@@ -410,49 +663,36 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
filldir_t filldir)
{
struct file *file = desc->file;
- struct nfs_entry *entry = desc->entry;
- struct dentry *dentry = NULL;
- u64 fileid;
- int loop_count = 0,
- res;
-
- dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n",
- (unsigned long long)entry->cookie);
-
- for(;;) {
- unsigned d_type = DT_UNKNOWN;
- /* Note: entry->prev_cookie contains the cookie for
- * retrieving the current dirent on the server */
- fileid = entry->ino;
-
- /* Get a dentry if we have one */
- if (dentry != NULL)
- dput(dentry);
- dentry = nfs_readdir_lookup(desc);
+ int i = 0;
+ int res = 0;
+ struct nfs_cache_array *array = NULL;
+ unsigned int d_type = DT_UNKNOWN;
+ struct dentry *dentry = NULL;
- /* Use readdirplus info */
- if (dentry != NULL && dentry->d_inode != NULL) {
- d_type = dt_type(dentry->d_inode);
- fileid = NFS_FILEID(dentry->d_inode);
- }
+ array = nfs_readdir_get_array(desc->page);
- res = filldir(dirent, entry->name, entry->len,
- file->f_pos, nfs_compat_user_ino64(fileid),
- d_type);
+ for (i = desc->cache_entry_index; i < array->size; i++) {
+ d_type = DT_UNKNOWN;
+
+ res = filldir(dirent, array->array[i].string.name,
+ array->array[i].string.len, file->f_pos,
+ nfs_compat_user_ino64(array->array[i].ino), d_type);
if (res < 0)
break;
file->f_pos++;
- *desc->dir_cookie = entry->cookie;
- if (dir_decode(desc) != 0) {
- desc->page_index ++;
+ desc->cache_entry_index = i;
+ if (i < (array->size-1))
+ *desc->dir_cookie = array->array[i+1].cookie;
+ else
+ *desc->dir_cookie = array->last_cookie;
+ if (i == array->eof_index) {
+ desc->eof = 1;
break;
}
- if (loop_count++ > 200) {
- loop_count = 0;
- schedule();
- }
}
- dir_page_release(desc);
+
+ nfs_readdir_release_array(desc->page);
+ cache_page_release(desc);
if (dentry != NULL)
dput(dentry);
dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n",
@@ -476,12 +716,9 @@ static inline
int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
filldir_t filldir)
{
- struct file *file = desc->file;
- struct inode *inode = file->f_path.dentry->d_inode;
- struct rpc_cred *cred = nfs_file_cred(file);
struct page *page = NULL;
int status;
- unsigned long timestamp, gencount;
+ struct inode *inode = desc->file->f_path.dentry->d_inode;
dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
(unsigned long long)*desc->dir_cookie);
@@ -491,38 +728,22 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
status = -ENOMEM;
goto out;
}
- timestamp = jiffies;
- gencount = nfs_inc_attr_generation_counter();
- status = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred,
- *desc->dir_cookie, page,
- NFS_SERVER(inode)->dtsize,
- desc->plus);
- desc->page = page;
- desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */
- if (status >= 0) {
- desc->timestamp = timestamp;
- desc->gencount = gencount;
- desc->timestamp_valid = 1;
- if ((status = dir_decode(desc)) == 0)
- desc->entry->prev_cookie = *desc->dir_cookie;
- } else
+
+ if (nfs_readdir_xdr_to_array(desc, page, inode) == -1) {
status = -EIO;
- if (status < 0)
goto out_release;
+ }
+ desc->page_index = 0;
+ desc->page = page;
status = nfs_do_filldir(desc, dirent, filldir);
- /* Reset read descriptor so it searches the page cache from
- * the start upon the next call to readdir_search_pagecache() */
- desc->page_index = 0;
- desc->entry->cookie = desc->entry->prev_cookie = 0;
- desc->entry->eof = 0;
out:
dfprintk(DIRCACHE, "NFS: %s: returns %d\n",
__func__, status);
return status;
out_release:
- dir_page_release(desc);
+ cache_page_release(desc);
goto out;
}
@@ -536,7 +757,6 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct inode *inode = dentry->d_inode;
nfs_readdir_descriptor_t my_desc,
*desc = &my_desc;
- struct nfs_entry my_entry;
int res = -ENOMEM;
dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n",
@@ -557,26 +777,17 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
desc->decode = NFS_PROTO(inode)->decode_dirent;
desc->plus = NFS_USE_READDIRPLUS(inode);
- my_entry.cookie = my_entry.prev_cookie = 0;
- my_entry.eof = 0;
- my_entry.fh = nfs_alloc_fhandle();
- my_entry.fattr = nfs_alloc_fattr();
- if (my_entry.fh == NULL || my_entry.fattr == NULL)
- goto out_alloc_failed;
-
- desc->entry = &my_entry;
-
nfs_block_sillyrename(dentry);
res = nfs_revalidate_mapping(inode, filp->f_mapping);
if (res < 0)
goto out;
- while(!desc->entry->eof) {
+ while (desc->eof != 1) {
res = readdir_search_pagecache(desc);
if (res == -EBADCOOKIE) {
/* This means either end of directory */
- if (*desc->dir_cookie && desc->entry->cookie != *desc->dir_cookie) {
+ if (*desc->dir_cookie && desc->eof == 0) {
/* Or that the server has 'lost' a cookie */
res = uncached_readdir(desc, dirent, filldir);
if (res >= 0)
@@ -588,8 +799,9 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (res == -ETOOSMALL && desc->plus) {
clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
nfs_zap_caches(inode);
+ desc->page_index = 0;
desc->plus = 0;
- desc->entry->eof = 0;
+ desc->eof = 0;
continue;
}
if (res < 0)
@@ -605,9 +817,6 @@ out:
nfs_unblock_sillyrename(dentry);
if (res > 0)
res = 0;
-out_alloc_failed:
- nfs_free_fattr(my_entry.fattr);
- nfs_free_fhandle(my_entry.fh);
dfprintk(FILE, "NFS: readdir(%s/%s) returns %d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
res);
@@ -1029,10 +1238,63 @@ static int is_atomic_open(struct nameidata *nd)
return 1;
}
+static struct nfs_open_context *nameidata_to_nfs_open_context(struct dentry *dentry, struct nameidata *nd)
+{
+ struct path path = {
+ .mnt = nd->path.mnt,
+ .dentry = dentry,
+ };
+ struct nfs_open_context *ctx;
+ struct rpc_cred *cred;
+ fmode_t fmode = nd->intent.open.flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC);
+
+ cred = rpc_lookup_cred();
+ if (IS_ERR(cred))
+ return ERR_CAST(cred);
+ ctx = alloc_nfs_open_context(&path, cred, fmode);
+ put_rpccred(cred);
+ if (ctx == NULL)
+ return ERR_PTR(-ENOMEM);
+ return ctx;
+}
+
+static int do_open(struct inode *inode, struct file *filp)
+{
+ nfs_fscache_set_inode_cookie(inode, filp);
+ return 0;
+}
+
+static int nfs_intent_set_file(struct nameidata *nd, struct nfs_open_context *ctx)
+{
+ struct file *filp;
+ int ret = 0;
+
+ /* If the open_intent is for execute, we have an extra check to make */
+ if (ctx->mode & FMODE_EXEC) {
+ ret = nfs_may_open(ctx->path.dentry->d_inode,
+ ctx->cred,
+ nd->intent.open.flags);
+ if (ret < 0)
+ goto out;
+ }
+ filp = lookup_instantiate_filp(nd, ctx->path.dentry, do_open);
+ if (IS_ERR(filp))
+ ret = PTR_ERR(filp);
+ else
+ nfs_file_set_open_context(filp, ctx);
+out:
+ put_nfs_open_context(ctx);
+ return ret;
+}
+
static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{
+ struct nfs_open_context *ctx;
+ struct iattr attr;
struct dentry *res = NULL;
- int error;
+ struct inode *inode;
+ int open_flags;
+ int err;
dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n",
dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
@@ -1054,13 +1316,32 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
goto out;
}
+ ctx = nameidata_to_nfs_open_context(dentry, nd);
+ res = ERR_CAST(ctx);
+ if (IS_ERR(ctx))
+ goto out;
+
+ open_flags = nd->intent.open.flags;
+ if (nd->flags & LOOKUP_CREATE) {
+ attr.ia_mode = nd->intent.open.create_mode;
+ attr.ia_valid = ATTR_MODE;
+ if (!IS_POSIXACL(dir))
+ attr.ia_mode &= ~current_umask();
+ } else {
+ open_flags &= ~(O_EXCL | O_CREAT);
+ attr.ia_valid = 0;
+ }
+
/* Open the file on the server */
- res = nfs4_atomic_open(dir, dentry, nd);
- if (IS_ERR(res)) {
- error = PTR_ERR(res);
- switch (error) {
+ nfs_block_sillyrename(dentry->d_parent);
+ inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr);
+ if (IS_ERR(inode)) {
+ nfs_unblock_sillyrename(dentry->d_parent);
+ put_nfs_open_context(ctx);
+ switch (PTR_ERR(inode)) {
/* Make a negative dentry */
case -ENOENT:
+ d_add(dentry, NULL);
res = NULL;
goto out;
/* This turned out not to be a regular file */
@@ -1072,11 +1353,25 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
goto no_open;
/* case -EINVAL: */
default:
+ res = ERR_CAST(inode);
goto out;
}
- } else if (res != NULL)
+ }
+ res = d_add_unique(dentry, inode);
+ nfs_unblock_sillyrename(dentry->d_parent);
+ if (res != NULL) {
+ dput(ctx->path.dentry);
+ ctx->path.dentry = dget(res);
dentry = res;
+ }
+ err = nfs_intent_set_file(nd, ctx);
+ if (err < 0) {
+ if (res != NULL)
+ dput(res);
+ return ERR_PTR(err);
+ }
out:
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
return res;
no_open:
return nfs_lookup(dir, dentry, nd);
@@ -1087,12 +1382,15 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
struct dentry *parent = NULL;
struct inode *inode = dentry->d_inode;
struct inode *dir;
+ struct nfs_open_context *ctx;
int openflags, ret = 0;
if (!is_atomic_open(nd) || d_mountpoint(dentry))
goto no_open;
+
parent = dget_parent(dentry);
dir = parent->d_inode;
+
/* We can't create new files in nfs_open_revalidate(), so we
* optimize away revalidation of negative dentries.
*/
@@ -1112,99 +1410,96 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
/* We can't create new files, or truncate existing ones here */
openflags &= ~(O_CREAT|O_EXCL|O_TRUNC);
+ ctx = nameidata_to_nfs_open_context(dentry, nd);
+ ret = PTR_ERR(ctx);
+ if (IS_ERR(ctx))
+ goto out;
/*
* Note: we're not holding inode->i_mutex and so may be racing with
* operations that change the directory. We therefore save the
* change attribute *before* we do the RPC call.
*/
- ret = nfs4_open_revalidate(dir, dentry, openflags, nd);
+ inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, NULL);
+ if (IS_ERR(inode)) {
+ ret = PTR_ERR(inode);
+ switch (ret) {
+ case -EPERM:
+ case -EACCES:
+ case -EDQUOT:
+ case -ENOSPC:
+ case -EROFS:
+ goto out_put_ctx;
+ default:
+ goto out_drop;
+ }
+ }
+ iput(inode);
+ if (inode != dentry->d_inode)
+ goto out_drop;
+
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+ ret = nfs_intent_set_file(nd, ctx);
+ if (ret >= 0)
+ ret = 1;
out:
dput(parent);
- if (!ret)
- d_drop(dentry);
return ret;
+out_drop:
+ d_drop(dentry);
+ ret = 0;
+out_put_ctx:
+ put_nfs_open_context(ctx);
+ goto out;
+
no_open_dput:
dput(parent);
no_open:
return nfs_lookup_revalidate(dentry, nd);
}
-#endif /* CONFIG_NFSV4 */
-static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
+static int nfs_open_create(struct inode *dir, struct dentry *dentry, int mode,
+ struct nameidata *nd)
{
- struct dentry *parent = desc->file->f_path.dentry;
- struct inode *dir = parent->d_inode;
- struct nfs_entry *entry = desc->entry;
- struct dentry *dentry, *alias;
- struct qstr name = {
- .name = entry->name,
- .len = entry->len,
- };
- struct inode *inode;
- unsigned long verf = nfs_save_change_attribute(dir);
+ struct nfs_open_context *ctx = NULL;
+ struct iattr attr;
+ int error;
+ int open_flags = 0;
- switch (name.len) {
- case 2:
- if (name.name[0] == '.' && name.name[1] == '.')
- return dget_parent(parent);
- break;
- case 1:
- if (name.name[0] == '.')
- return dget(parent);
- }
+ dfprintk(VFS, "NFS: create(%s/%ld), %s\n",
+ dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
- spin_lock(&dir->i_lock);
- if (NFS_I(dir)->cache_validity & NFS_INO_INVALID_DATA) {
- spin_unlock(&dir->i_lock);
- return NULL;
- }
- spin_unlock(&dir->i_lock);
+ attr.ia_mode = mode;
+ attr.ia_valid = ATTR_MODE;
- name.hash = full_name_hash(name.name, name.len);
- dentry = d_lookup(parent, &name);
- if (dentry != NULL) {
- /* Is this a positive dentry that matches the readdir info? */
- if (dentry->d_inode != NULL &&
- (NFS_FILEID(dentry->d_inode) == entry->ino ||
- d_mountpoint(dentry))) {
- if (!desc->plus || entry->fh->size == 0)
- return dentry;
- if (nfs_compare_fh(NFS_FH(dentry->d_inode),
- entry->fh) == 0)
- goto out_renew;
- }
- /* No, so d_drop to allow one to be created */
- d_drop(dentry);
- dput(dentry);
- }
- if (!desc->plus || !(entry->fattr->valid & NFS_ATTR_FATTR))
- return NULL;
- if (name.len > NFS_SERVER(dir)->namelen)
- return NULL;
- /* Note: caller is already holding the dir->i_mutex! */
- dentry = d_alloc(parent, &name);
- if (dentry == NULL)
- return NULL;
- dentry->d_op = NFS_PROTO(dir)->dentry_ops;
- inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr);
- if (IS_ERR(inode)) {
- dput(dentry);
- return NULL;
- }
+ if ((nd->flags & LOOKUP_CREATE) != 0) {
+ open_flags = nd->intent.open.flags;
- alias = d_materialise_unique(dentry, inode);
- if (alias != NULL) {
- dput(dentry);
- if (IS_ERR(alias))
- return NULL;
- dentry = alias;
+ ctx = nameidata_to_nfs_open_context(dentry, nd);
+ error = PTR_ERR(ctx);
+ if (IS_ERR(ctx))
+ goto out_err_drop;
}
-out_renew:
- nfs_set_verifier(dentry, verf);
- return dentry;
+ error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, ctx);
+ if (error != 0)
+ goto out_put_ctx;
+ if (ctx != NULL) {
+ error = nfs_intent_set_file(nd, ctx);
+ if (error < 0)
+ goto out_err;
+ }
+ return 0;
+out_put_ctx:
+ if (ctx != NULL)
+ put_nfs_open_context(ctx);
+out_err_drop:
+ d_drop(dentry);
+out_err:
+ return error;
}
+#endif /* CONFIG_NFSV4 */
+
/*
* Code common to create, mkdir, and mknod.
*/
@@ -1258,7 +1553,6 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
{
struct iattr attr;
int error;
- int open_flags = 0;
dfprintk(VFS, "NFS: create(%s/%ld), %s\n",
dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
@@ -1266,10 +1560,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
- if ((nd->flags & LOOKUP_CREATE) != 0)
- open_flags = nd->intent.open.flags;
-
- error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd);
+ error = NFS_PROTO(dir)->create(dir, dentry, &attr, 0, NULL);
if (error != 0)
goto out_err;
return 0;
@@ -1351,76 +1642,6 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
return error;
}
-static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
-{
- static unsigned int sillycounter;
- const int fileidsize = sizeof(NFS_FILEID(dentry->d_inode))*2;
- const int countersize = sizeof(sillycounter)*2;
- const int slen = sizeof(".nfs")+fileidsize+countersize-1;
- char silly[slen+1];
- struct qstr qsilly;
- struct dentry *sdentry;
- int error = -EIO;
-
- dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
- dentry->d_parent->d_name.name, dentry->d_name.name,
- atomic_read(&dentry->d_count));
- nfs_inc_stats(dir, NFSIOS_SILLYRENAME);
-
- /*
- * We don't allow a dentry to be silly-renamed twice.
- */
- error = -EBUSY;
- if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
- goto out;
-
- sprintf(silly, ".nfs%*.*Lx",
- fileidsize, fileidsize,
- (unsigned long long)NFS_FILEID(dentry->d_inode));
-
- /* Return delegation in anticipation of the rename */
- nfs_inode_return_delegation(dentry->d_inode);
-
- sdentry = NULL;
- do {
- char *suffix = silly + slen - countersize;
-
- dput(sdentry);
- sillycounter++;
- sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);
-
- dfprintk(VFS, "NFS: trying to rename %s to %s\n",
- dentry->d_name.name, silly);
-
- sdentry = lookup_one_len(silly, dentry->d_parent, slen);
- /*
- * N.B. Better to return EBUSY here ... it could be
- * dangerous to delete the file while it's in use.
- */
- if (IS_ERR(sdentry))
- goto out;
- } while(sdentry->d_inode != NULL); /* need negative lookup */
-
- qsilly.name = silly;
- qsilly.len = strlen(silly);
- if (dentry->d_inode) {
- error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
- dir, &qsilly);
- nfs_mark_for_revalidate(dentry->d_inode);
- } else
- error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
- dir, &qsilly);
- if (!error) {
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
- d_move(dentry, sdentry);
- error = nfs_async_unlink(dir, dentry);
- /* If we return 0 we don't unlink */
- }
- dput(sdentry);
-out:
- return error;
-}
-
/*
* Remove a file after making sure there are no pending writes,
* and after checking that the file has only one user.
@@ -1580,7 +1801,7 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
d_drop(dentry);
error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
if (error == 0) {
- atomic_inc(&inode->i_count);
+ ihold(inode);
d_add(dentry, inode);
}
return error;
@@ -1711,14 +1932,14 @@ static void nfs_access_free_list(struct list_head *head)
int nfs_access_cache_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
{
LIST_HEAD(head);
- struct nfs_inode *nfsi;
+ struct nfs_inode *nfsi, *next;
struct nfs_access_entry *cache;
if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL)
return (nr_to_scan == 0) ? 0 : -1;
spin_lock(&nfs_access_lru_lock);
- list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) {
+ list_for_each_entry_safe(nfsi, next, &nfs_access_lru_list, access_cache_inode_lru) {
struct inode *inode;
if (nr_to_scan-- == 0)
diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c
index dba50a5625db..a6e711ad130f 100644
--- a/fs/nfs/dns_resolve.c
+++ b/fs/nfs/dns_resolve.c
@@ -167,7 +167,7 @@ static int nfs_dns_show(struct seq_file *m, struct cache_detail *cd,
return 0;
}
item = container_of(h, struct nfs_dns_ent, h);
- ttl = (long)item->h.expiry_time - (long)get_seconds();
+ ttl = item->h.expiry_time - seconds_since_boot();
if (ttl < 0)
ttl = 0;
@@ -239,7 +239,7 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
ttl = get_expiry(&buf);
if (ttl == 0)
goto out;
- key.h.expiry_time = ttl + get_seconds();
+ key.h.expiry_time = ttl + seconds_since_boot();
ret = -ENOMEM;
item = nfs_dns_lookup(cd, &key);
@@ -301,7 +301,7 @@ static int do_cache_lookup_nowait(struct cache_detail *cd,
goto out_err;
ret = -ETIMEDOUT;
if (!test_bit(CACHE_VALID, &(*item)->h.flags)
- || (*item)->h.expiry_time < get_seconds()
+ || (*item)->h.expiry_time < seconds_since_boot()
|| cd->flush_time > (*item)->h.last_refresh)
goto out_put;
ret = -ENOENT;
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 05bf3c0dc751..e756075637b0 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -36,6 +36,7 @@
#include "internal.h"
#include "iostat.h"
#include "fscache.h"
+#include "pnfs.h"
#define NFSDBG_FACILITY NFSDBG_FILE
@@ -386,6 +387,10 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
file->f_path.dentry->d_name.name,
mapping->host->i_ino, len, (long long) pos);
+ pnfs_update_layout(mapping->host,
+ nfs_file_open_context(file),
+ IOMODE_RW);
+
start:
/*
* Prevent starvation issues if someone is doing a consistency
@@ -551,7 +556,7 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
struct file *filp = vma->vm_file;
struct dentry *dentry = filp->f_path.dentry;
unsigned pagelen;
- int ret = -EINVAL;
+ int ret = VM_FAULT_NOPAGE;
struct address_space *mapping;
dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%s/%s(%ld), offset %lld)\n",
@@ -567,21 +572,20 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
if (mapping != dentry->d_inode->i_mapping)
goto out_unlock;
- ret = 0;
pagelen = nfs_page_length(page);
if (pagelen == 0)
goto out_unlock;
- ret = nfs_flush_incompatible(filp, page);
- if (ret != 0)
- goto out_unlock;
+ ret = VM_FAULT_LOCKED;
+ if (nfs_flush_incompatible(filp, page) == 0 &&
+ nfs_updatepage(filp, page, 0, pagelen) == 0)
+ goto out;
- ret = nfs_updatepage(filp, page, 0, pagelen);
+ ret = VM_FAULT_SIGBUS;
out_unlock:
- if (!ret)
- return VM_FAULT_LOCKED;
unlock_page(page);
- return VM_FAULT_SIGBUS;
+out:
+ return ret;
}
static const struct vm_operations_struct nfs_file_vm_ops = {
@@ -684,7 +688,8 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
return ret;
}
-static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
+static int
+do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
{
struct inode *inode = filp->f_mapping->host;
int status = 0;
@@ -699,7 +704,7 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
if (nfs_have_delegation(inode, FMODE_READ))
goto out_noconflict;
- if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)
+ if (is_local)
goto out_noconflict;
status = NFS_PROTO(inode)->lock(filp, cmd, fl);
@@ -726,7 +731,8 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl)
return res;
}
-static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
+static int
+do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
{
struct inode *inode = filp->f_mapping->host;
int status;
@@ -741,15 +747,24 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
* If we're signalled while cleaning up locks on process exit, we
* still need to complete the unlock.
*/
- /* Use local locking if mounted with "-onolock" */
- if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
+ /*
+ * Use local locking if mounted with "-onolock" or with appropriate
+ * "-olocal_lock="
+ */
+ if (!is_local)
status = NFS_PROTO(inode)->lock(filp, cmd, fl);
else
status = do_vfs_lock(filp, fl);
return status;
}
-static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
+static int
+is_time_granular(struct timespec *ts) {
+ return ((ts->tv_sec == 0) && (ts->tv_nsec <= 1000));
+}
+
+static int
+do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
{
struct inode *inode = filp->f_mapping->host;
int status;
@@ -762,20 +777,31 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
if (status != 0)
goto out;
- /* Use local locking if mounted with "-onolock" */
- if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
+ /*
+ * Use local locking if mounted with "-onolock" or with appropriate
+ * "-olocal_lock="
+ */
+ if (!is_local)
status = NFS_PROTO(inode)->lock(filp, cmd, fl);
else
status = do_vfs_lock(filp, fl);
if (status < 0)
goto out;
+
/*
- * Make sure we clear the cache whenever we try to get the lock.
+ * Revalidate the cache if the server has time stamps granular
+ * enough to detect subsecond changes. Otherwise, clear the
+ * cache to prevent missing any changes.
+ *
* This makes locking act as a cache coherency point.
*/
nfs_sync_mapping(filp->f_mapping);
- if (!nfs_have_delegation(inode, FMODE_READ))
- nfs_zap_caches(inode);
+ if (!nfs_have_delegation(inode, FMODE_READ)) {
+ if (is_time_granular(&NFS_SERVER(inode)->time_delta))
+ __nfs_revalidate_inode(NFS_SERVER(inode), inode);
+ else
+ nfs_zap_caches(inode);
+ }
out:
return status;
}
@@ -787,6 +813,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
{
struct inode *inode = filp->f_mapping->host;
int ret = -ENOLCK;
+ int is_local = 0;
dprintk("NFS: lock(%s/%s, t=%x, fl=%x, r=%lld:%lld)\n",
filp->f_path.dentry->d_parent->d_name.name,
@@ -800,6 +827,9 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
goto out_err;
+ if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FCNTL)
+ is_local = 1;
+
if (NFS_PROTO(inode)->lock_check_bounds != NULL) {
ret = NFS_PROTO(inode)->lock_check_bounds(fl);
if (ret < 0)
@@ -807,11 +837,11 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
}
if (IS_GETLK(cmd))
- ret = do_getlk(filp, cmd, fl);
+ ret = do_getlk(filp, cmd, fl, is_local);
else if (fl->fl_type == F_UNLCK)
- ret = do_unlk(filp, cmd, fl);
+ ret = do_unlk(filp, cmd, fl, is_local);
else
- ret = do_setlk(filp, cmd, fl);
+ ret = do_setlk(filp, cmd, fl, is_local);
out_err:
return ret;
}
@@ -821,6 +851,9 @@ out_err:
*/
static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
{
+ struct inode *inode = filp->f_mapping->host;
+ int is_local = 0;
+
dprintk("NFS: flock(%s/%s, t=%x, fl=%x)\n",
filp->f_path.dentry->d_parent->d_name.name,
filp->f_path.dentry->d_name.name,
@@ -829,14 +862,17 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
if (!(fl->fl_flags & FL_FLOCK))
return -ENOLCK;
+ if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FLOCK)
+ is_local = 1;
+
/* We're simulating flock() locks using posix locks on the server */
fl->fl_owner = (fl_owner_t)filp;
fl->fl_start = 0;
fl->fl_end = OFFSET_MAX;
if (fl->fl_type == F_UNLCK)
- return do_unlk(filp, cmd, fl);
- return do_setlk(filp, cmd, fl);
+ return do_unlk(filp, cmd, fl, is_local);
+ return do_setlk(filp, cmd, fl, is_local);
}
/*
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index a70e446e1605..ac7b814ce162 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -54,8 +54,7 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
iput(inode);
return -ENOMEM;
}
- /* Circumvent igrab(): we know the inode is not being freed */
- atomic_inc(&inode->i_count);
+ ihold(inode);
/*
* Ensure that this dentry is invisible to d_find_alias().
* Otherwise, it may be spliced into the tree by
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index 21a84d45916f..dec47ed8b6b9 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -34,6 +34,212 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#ifdef CONFIG_NFS_USE_NEW_IDMAPPER
+
+#include <linux/slab.h>
+#include <linux/cred.h>
+#include <linux/nfs_idmap.h>
+#include <linux/keyctl.h>
+#include <linux/key-type.h>
+#include <linux/rcupdate.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+
+#include <keys/user-type.h>
+
+#define NFS_UINT_MAXLEN 11
+
+const struct cred *id_resolver_cache;
+
+struct key_type key_type_id_resolver = {
+ .name = "id_resolver",
+ .instantiate = user_instantiate,
+ .match = user_match,
+ .revoke = user_revoke,
+ .destroy = user_destroy,
+ .describe = user_describe,
+ .read = user_read,
+};
+
+int nfs_idmap_init(void)
+{
+ struct cred *cred;
+ struct key *keyring;
+ int ret = 0;
+
+ printk(KERN_NOTICE "Registering the %s key type\n", key_type_id_resolver.name);
+
+ cred = prepare_kernel_cred(NULL);
+ if (!cred)
+ return -ENOMEM;
+
+ keyring = key_alloc(&key_type_keyring, ".id_resolver", 0, 0, cred,
+ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+ KEY_USR_VIEW | KEY_USR_READ,
+ KEY_ALLOC_NOT_IN_QUOTA);
+ if (IS_ERR(keyring)) {
+ ret = PTR_ERR(keyring);
+ goto failed_put_cred;
+ }
+
+ ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
+ if (ret < 0)
+ goto failed_put_key;
+
+ ret = register_key_type(&key_type_id_resolver);
+ if (ret < 0)
+ goto failed_put_key;
+
+ cred->thread_keyring = keyring;
+ cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
+ id_resolver_cache = cred;
+ return 0;
+
+failed_put_key:
+ key_put(keyring);
+failed_put_cred:
+ put_cred(cred);
+ return ret;
+}
+
+void nfs_idmap_quit(void)
+{
+ key_revoke(id_resolver_cache->thread_keyring);
+ unregister_key_type(&key_type_id_resolver);
+ put_cred(id_resolver_cache);
+}
+
+/*
+ * Assemble the description to pass to request_key()
+ * This function will allocate a new string and update dest to point
+ * at it. The caller is responsible for freeing dest.
+ *
+ * On error 0 is returned. Otherwise, the length of dest is returned.
+ */
+static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen,
+ const char *type, size_t typelen, char **desc)
+{
+ char *cp;
+ size_t desclen = typelen + namelen + 2;
+
+ *desc = kmalloc(desclen, GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ cp = *desc;
+ memcpy(cp, type, typelen);
+ cp += typelen;
+ *cp++ = ':';
+
+ memcpy(cp, name, namelen);
+ cp += namelen;
+ *cp = '\0';
+ return desclen;
+}
+
+static ssize_t nfs_idmap_request_key(const char *name, size_t namelen,
+ const char *type, void *data, size_t data_size)
+{
+ const struct cred *saved_cred;
+ struct key *rkey;
+ char *desc;
+ struct user_key_payload *payload;
+ ssize_t ret;
+
+ ret = nfs_idmap_get_desc(name, namelen, type, strlen(type), &desc);
+ if (ret <= 0)
+ goto out;
+
+ saved_cred = override_creds(id_resolver_cache);
+ rkey = request_key(&key_type_id_resolver, desc, "");
+ revert_creds(saved_cred);
+ kfree(desc);
+ if (IS_ERR(rkey)) {
+ ret = PTR_ERR(rkey);
+ goto out;
+ }
+
+ rcu_read_lock();
+ rkey->perm |= KEY_USR_VIEW;
+
+ ret = key_validate(rkey);
+ if (ret < 0)
+ goto out_up;
+
+ payload = rcu_dereference(rkey->payload.data);
+ if (IS_ERR_OR_NULL(payload)) {
+ ret = PTR_ERR(payload);
+ goto out_up;
+ }
+
+ ret = payload->datalen;
+ if (ret > 0 && ret <= data_size)
+ memcpy(data, payload->data, ret);
+ else
+ ret = -EINVAL;
+
+out_up:
+ rcu_read_unlock();
+ key_put(rkey);
+out:
+ return ret;
+}
+
+
+/* ID -> Name */
+static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, size_t buflen)
+{
+ char id_str[NFS_UINT_MAXLEN];
+ int id_len;
+ ssize_t ret;
+
+ id_len = snprintf(id_str, sizeof(id_str), "%u", id);
+ ret = nfs_idmap_request_key(id_str, id_len, type, buf, buflen);
+ if (ret < 0)
+ return -EINVAL;
+ return ret;
+}
+
+/* Name -> ID */
+static int nfs_idmap_lookup_id(const char *name, size_t namelen,
+ const char *type, __u32 *id)
+{
+ char id_str[NFS_UINT_MAXLEN];
+ long id_long;
+ ssize_t data_size;
+ int ret = 0;
+
+ data_size = nfs_idmap_request_key(name, namelen, type, id_str, NFS_UINT_MAXLEN);
+ if (data_size <= 0) {
+ ret = -EINVAL;
+ } else {
+ ret = strict_strtol(id_str, 10, &id_long);
+ *id = (__u32)id_long;
+ }
+ return ret;
+}
+
+int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid)
+{
+ return nfs_idmap_lookup_id(name, namelen, "uid", uid);
+}
+
+int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *gid)
+{
+ return nfs_idmap_lookup_id(name, namelen, "gid", gid);
+}
+
+int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen)
+{
+ return nfs_idmap_lookup_name(uid, "user", buf, buflen);
+}
+int nfs_map_gid_to_group(struct nfs_client *clp, __u32 gid, char *buf, size_t buflen)
+{
+ return nfs_idmap_lookup_name(gid, "group", buf, buflen);
+}
+
+#else /* CONFIG_NFS_USE_IDMAPPER not defined */
+
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/init.h>
@@ -503,16 +709,17 @@ int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namele
return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid);
}
-int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf)
+int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen)
{
struct idmap *idmap = clp->cl_idmap;
return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
}
-int nfs_map_gid_to_group(struct nfs_client *clp, __u32 uid, char *buf)
+int nfs_map_gid_to_group(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen)
{
struct idmap *idmap = clp->cl_idmap;
return nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf);
}
+#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 7d2d6c72aa78..314f57164602 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -48,6 +48,7 @@
#include "internal.h"
#include "fscache.h"
#include "dns_resolve.h"
+#include "pnfs.h"
#define NFSDBG_FACILITY NFSDBG_VFS
@@ -234,9 +235,6 @@ nfs_init_locked(struct inode *inode, void *opaque)
return 0;
}
-/* Don't use READDIRPLUS on directories that we believe are too large */
-#define NFS_LIMIT_READDIRPLUS (8*PAGE_SIZE)
-
/*
* This is our front-end to iget that looks up inodes by file handle
* instead of inode number.
@@ -291,8 +289,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops;
inode->i_fop = &nfs_dir_operations;
- if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)
- && fattr->size <= NFS_LIMIT_READDIRPLUS)
+ if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS))
set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
/* Deal with crossing mountpoints */
if ((fattr->valid & NFS_ATTR_FATTR_FSID)
@@ -623,7 +620,7 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
nfs_revalidate_inode(server, inode);
}
-static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred)
+struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred, fmode_t f_mode)
{
struct nfs_open_context *ctx;
@@ -633,11 +630,13 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct
path_get(&ctx->path);
ctx->cred = get_rpccred(cred);
ctx->state = NULL;
+ ctx->mode = f_mode;
ctx->flags = 0;
ctx->error = 0;
ctx->dir_cookie = 0;
nfs_init_lock_context(&ctx->lock_context);
ctx->lock_context.open_context = ctx;
+ INIT_LIST_HEAD(&ctx->list);
}
return ctx;
}
@@ -653,11 +652,15 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
{
struct inode *inode = ctx->path.dentry->d_inode;
- if (!atomic_dec_and_lock(&ctx->lock_context.count, &inode->i_lock))
+ if (!list_empty(&ctx->list)) {
+ if (!atomic_dec_and_lock(&ctx->lock_context.count, &inode->i_lock))
+ return;
+ list_del(&ctx->list);
+ spin_unlock(&inode->i_lock);
+ } else if (!atomic_dec_and_test(&ctx->lock_context.count))
return;
- list_del(&ctx->list);
- spin_unlock(&inode->i_lock);
- NFS_PROTO(inode)->close_context(ctx, is_sync);
+ if (inode != NULL)
+ NFS_PROTO(inode)->close_context(ctx, is_sync);
if (ctx->cred != NULL)
put_rpccred(ctx->cred);
path_put(&ctx->path);
@@ -673,7 +676,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx)
* Ensure that mmap has a recent RPC credential for use when writing out
* shared pages
*/
-static void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
+void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
{
struct inode *inode = filp->f_path.dentry->d_inode;
struct nfs_inode *nfsi = NFS_I(inode);
@@ -730,11 +733,10 @@ int nfs_open(struct inode *inode, struct file *filp)
cred = rpc_lookup_cred();
if (IS_ERR(cred))
return PTR_ERR(cred);
- ctx = alloc_nfs_open_context(&filp->f_path, cred);
+ ctx = alloc_nfs_open_context(&filp->f_path, cred, filp->f_mode);
put_rpccred(cred);
if (ctx == NULL)
return -ENOMEM;
- ctx->mode = filp->f_mode;
nfs_file_set_open_context(filp, ctx);
put_nfs_open_context(ctx);
nfs_fscache_set_inode_cookie(inode, filp);
@@ -1409,6 +1411,7 @@ void nfs4_evict_inode(struct inode *inode)
{
truncate_inode_pages(&inode->i_data, 0);
end_writeback(inode);
+ pnfs_destroy_layout(NFS_I(inode));
/* If we are holding a delegation, return it! */
nfs_inode_return_delegation_noreclaim(inode);
/* First call standard NFS clear_inode() code */
@@ -1446,6 +1449,7 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi)
nfsi->delegation = NULL;
nfsi->delegation_state = 0;
init_rwsem(&nfsi->rwsem);
+ nfsi->layout = NULL;
#endif
}
@@ -1493,7 +1497,7 @@ static int nfsiod_start(void)
{
struct workqueue_struct *wq;
dprintk("RPC: creating workqueue nfsiod\n");
- wq = create_singlethread_workqueue("nfsiod");
+ wq = alloc_workqueue("nfsiod", WQ_RESCUER, 0);
if (wq == NULL)
return -ENOMEM;
nfsiod_workqueue = wq;
@@ -1521,6 +1525,10 @@ static int __init init_nfs_fs(void)
{
int err;
+ err = nfs_idmap_init();
+ if (err < 0)
+ goto out9;
+
err = nfs_dns_resolver_init();
if (err < 0)
goto out8;
@@ -1585,6 +1593,8 @@ out6:
out7:
nfs_dns_resolver_destroy();
out8:
+ nfs_idmap_quit();
+out9:
return err;
}
@@ -1597,6 +1607,7 @@ static void __exit exit_nfs_fs(void)
nfs_destroy_nfspagecache();
nfs_fscache_unregister();
nfs_dns_resolver_destroy();
+ nfs_idmap_quit();
#ifdef CONFIG_PROC_FS
rpc_proc_unregister("nfs");
#endif
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index c961bc92c107..db08ff3ff454 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -63,6 +63,12 @@ struct nfs_clone_mount {
#define NFS_UNSPEC_PORT (-1)
/*
+ * Maximum number of pages that readdir can use for creating
+ * a vmapped array of pages.
+ */
+#define NFS_MAX_READDIR_PAGES 8
+
+/*
* In-kernel mount arguments
*/
struct nfs_parsed_mount_data {
@@ -181,15 +187,15 @@ extern void nfs_destroy_directcache(void);
/* nfs2xdr.c */
extern int nfs_stat_to_errno(int);
extern struct rpc_procinfo nfs_procedures[];
-extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int);
+extern __be32 *nfs_decode_dirent(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
/* nfs3xdr.c */
extern struct rpc_procinfo nfs3_procedures[];
-extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int);
+extern __be32 *nfs3_decode_dirent(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
/* nfs4xdr.c */
#ifdef CONFIG_NFS_V4
-extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
+extern __be32 *nfs4_decode_dirent(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
#endif
#ifdef CONFIG_NFS_V4_1
extern const u32 nfs41_maxread_overhead;
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
index 59047f8d7d72..eceafe74f473 100644
--- a/fs/nfs/mount_clnt.c
+++ b/fs/nfs/mount_clnt.c
@@ -153,6 +153,7 @@ int nfs_mount(struct nfs_mount_request *info)
.rpc_resp = &result,
};
struct rpc_create_args args = {
+ .net = &init_net,
.protocol = info->protocol,
.address = info->sap,
.addrsize = info->salen,
@@ -224,6 +225,7 @@ void nfs_umount(const struct nfs_mount_request *info)
.to_retries = 2,
};
struct rpc_create_args args = {
+ .net = &init_net,
.protocol = IPPROTO_UDP,
.address = info->sap,
.addrsize = info->salen,
@@ -436,7 +438,7 @@ static int decode_auth_flavors(struct xdr_stream *xdr, struct mountres *res)
for (i = 0; i < entries; i++) {
flavors[i] = ntohl(*p++);
- dprintk("NFS:\tflavor %u: %d\n", i, flavors[i]);
+ dprintk("NFS: auth flavor[%u]: %d\n", i, flavors[i]);
}
*count = i;
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index db8846a0e82e..e6bf45710cc7 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -337,10 +337,10 @@ nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args)
static int
nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
{
- p = xdr_encode_fhandle(p, args->fromfh);
- p = xdr_encode_array(p, args->fromname, args->fromlen);
- p = xdr_encode_fhandle(p, args->tofh);
- p = xdr_encode_array(p, args->toname, args->tolen);
+ p = xdr_encode_fhandle(p, args->old_dir);
+ p = xdr_encode_array(p, args->old_name->name, args->old_name->len);
+ p = xdr_encode_fhandle(p, args->new_dir);
+ p = xdr_encode_array(p, args->new_name->name, args->new_name->len);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
}
@@ -423,9 +423,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
struct page **page;
size_t hdrlen;
unsigned int pglen, recvd;
- u32 len;
int status, nr = 0;
- __be32 *end, *entry, *kaddr;
if ((status = ntohl(*p++)))
return nfs_stat_to_errno(status);
@@ -445,80 +443,59 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
if (pglen > recvd)
pglen = recvd;
page = rcvbuf->pages;
- kaddr = p = kmap_atomic(*page, KM_USER0);
- end = (__be32 *)((char *)p + pglen);
- entry = p;
-
- /* Make sure the packet actually has a value_follows and EOF entry */
- if ((entry + 1) > end)
- goto short_pkt;
-
- for (; *p++; nr++) {
- if (p + 2 > end)
- goto short_pkt;
- p++; /* fileid */
- len = ntohl(*p++);
- p += XDR_QUADLEN(len) + 1; /* name plus cookie */
- if (len > NFS2_MAXNAMLEN) {
- dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
- len);
- goto err_unmap;
- }
- if (p + 2 > end)
- goto short_pkt;
- entry = p;
- }
-
- /*
- * Apparently some server sends responses that are a valid size, but
- * contain no entries, and have value_follows==0 and EOF==0. For
- * those, just set the EOF marker.
- */
- if (!nr && entry[1] == 0) {
- dprintk("NFS: readdir reply truncated!\n");
- entry[1] = 1;
- }
- out:
- kunmap_atomic(kaddr, KM_USER0);
return nr;
- short_pkt:
- /*
- * When we get a short packet there are 2 possibilities. We can
- * return an error, or fix up the response to look like a valid
- * response and return what we have so far. If there are no
- * entries and the packet was short, then return -EIO. If there
- * are valid entries in the response, return them and pretend that
- * the call was successful, but incomplete. The caller can retry the
- * readdir starting at the last cookie.
- */
- entry[0] = entry[1] = 0;
- if (!nr)
- nr = -errno_NFSERR_IO;
- goto out;
-err_unmap:
- nr = -errno_NFSERR_IO;
- goto out;
+}
+
+static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
+{
+ dprintk("nfs: %s: prematurely hit end of receive buffer. "
+ "Remaining buffer length is %tu words.\n",
+ func, xdr->end - xdr->p);
}
__be32 *
-nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
+nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
{
- if (!*p++) {
- if (!*p)
+ __be32 *p;
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ if (!ntohl(*p++)) {
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ if (!ntohl(*p++))
return ERR_PTR(-EAGAIN);
entry->eof = 1;
return ERR_PTR(-EBADCOOKIE);
}
+ p = xdr_inline_decode(xdr, 8);
+ if (unlikely(!p))
+ goto out_overflow;
+
entry->ino = ntohl(*p++);
entry->len = ntohl(*p++);
+
+ p = xdr_inline_decode(xdr, entry->len + 4);
+ if (unlikely(!p))
+ goto out_overflow;
entry->name = (const char *) p;
p += XDR_QUADLEN(entry->len);
entry->prev_cookie = entry->cookie;
entry->cookie = ntohl(*p++);
- entry->eof = !p[0] && p[1];
+
+ p = xdr_inline_peek(xdr, 8);
+ if (p != NULL)
+ entry->eof = !p[0] && p[1];
+ else
+ entry->eof = 0;
return p;
+
+out_overflow:
+ print_overflow_msg(__func__, xdr);
+ return ERR_PTR(-EIO);
}
/*
@@ -596,7 +573,6 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
struct kvec *iov = rcvbuf->head;
size_t hdrlen;
u32 len, recvd;
- char *kaddr;
int status;
if ((status = ntohl(*p++)))
@@ -623,10 +599,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
return -EIO;
}
- /* NULL terminate the string we got */
- kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
- kaddr[len+rcvbuf->page_base] = '\0';
- kunmap_atomic(kaddr, KM_USER0);
+ xdr_terminate_string(rcvbuf, len);
return 0;
}
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index fabb4f2849a1..ce939c062a52 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -313,7 +313,7 @@ static void nfs3_free_createdata(struct nfs3_createdata *data)
*/
static int
nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
- int flags, struct nameidata *nd)
+ int flags, struct nfs_open_context *ctx)
{
struct nfs3_createdata *data;
mode_t mode = sattr->ia_mode;
@@ -438,19 +438,38 @@ nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
return 1;
}
+static void
+nfs3_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
+{
+ msg->rpc_proc = &nfs3_procedures[NFS3PROC_RENAME];
+}
+
+static int
+nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
+ struct inode *new_dir)
+{
+ struct nfs_renameres *res;
+
+ if (nfs3_async_handle_jukebox(task, old_dir))
+ return 0;
+ res = task->tk_msg.rpc_resp;
+
+ nfs_post_op_update_inode(old_dir, res->old_fattr);
+ nfs_post_op_update_inode(new_dir, res->new_fattr);
+ return 1;
+}
+
static int
nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name,
struct inode *new_dir, struct qstr *new_name)
{
- struct nfs3_renameargs arg = {
- .fromfh = NFS_FH(old_dir),
- .fromname = old_name->name,
- .fromlen = old_name->len,
- .tofh = NFS_FH(new_dir),
- .toname = new_name->name,
- .tolen = new_name->len
+ struct nfs_renameargs arg = {
+ .old_dir = NFS_FH(old_dir),
+ .old_name = old_name,
+ .new_dir = NFS_FH(new_dir),
+ .new_name = new_name,
};
- struct nfs3_renameres res;
+ struct nfs_renameres res;
struct rpc_message msg = {
.rpc_proc = &nfs3_procedures[NFS3PROC_RENAME],
.rpc_argp = &arg,
@@ -460,17 +479,17 @@ nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name,
dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name);
- res.fromattr = nfs_alloc_fattr();
- res.toattr = nfs_alloc_fattr();
- if (res.fromattr == NULL || res.toattr == NULL)
+ res.old_fattr = nfs_alloc_fattr();
+ res.new_fattr = nfs_alloc_fattr();
+ if (res.old_fattr == NULL || res.new_fattr == NULL)
goto out;
status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0);
- nfs_post_op_update_inode(old_dir, res.fromattr);
- nfs_post_op_update_inode(new_dir, res.toattr);
+ nfs_post_op_update_inode(old_dir, res.old_fattr);
+ nfs_post_op_update_inode(new_dir, res.new_fattr);
out:
- nfs_free_fattr(res.toattr);
- nfs_free_fattr(res.fromattr);
+ nfs_free_fattr(res.old_fattr);
+ nfs_free_fattr(res.new_fattr);
dprintk("NFS reply rename: %d\n", status);
return status;
}
@@ -611,7 +630,7 @@ out:
*/
static int
nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
- u64 cookie, struct page *page, unsigned int count, int plus)
+ u64 cookie, struct page **pages, unsigned int count, int plus)
{
struct inode *dir = dentry->d_inode;
__be32 *verf = NFS_COOKIEVERF(dir);
@@ -621,7 +640,7 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
.verf = {verf[0], verf[1]},
.plus = plus,
.count = count,
- .pages = &page
+ .pages = pages
};
struct nfs3_readdirres res = {
.verf = verf,
@@ -652,7 +671,8 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
nfs_free_fattr(res.dir_attr);
out:
- dprintk("NFS reply readdir: %d\n", status);
+ dprintk("NFS reply readdir%s: %d\n",
+ plus? "plus" : "", status);
return status;
}
@@ -722,7 +742,7 @@ nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
dprintk("NFS call fsstat\n");
nfs_fattr_init(stat->fattr);
status = rpc_call_sync(server->client, &msg, 0);
- dprintk("NFS reply statfs: %d\n", status);
+ dprintk("NFS reply fsstat: %d\n", status);
return status;
}
@@ -844,6 +864,8 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
.unlink_setup = nfs3_proc_unlink_setup,
.unlink_done = nfs3_proc_unlink_done,
.rename = nfs3_proc_rename,
+ .rename_setup = nfs3_proc_rename_setup,
+ .rename_done = nfs3_proc_rename_done,
.link = nfs3_proc_link,
.symlink = nfs3_proc_symlink,
.mkdir = nfs3_proc_mkdir,
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 9769704f8ce6..d9a5e832c257 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -100,6 +100,13 @@ static const umode_t nfs_type2fmt[] = {
[NF3FIFO] = S_IFIFO,
};
+static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
+{
+ dprintk("nfs: %s: prematurely hit end of receive buffer. "
+ "Remaining buffer length is %tu words.\n",
+ func, xdr->end - xdr->p);
+}
+
/*
* Common NFS XDR functions as inlines
*/
@@ -119,6 +126,29 @@ xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
return NULL;
}
+static inline __be32 *
+xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh)
+{
+ __be32 *p;
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ fh->size = ntohl(*p++);
+
+ if (fh->size <= NFS3_FHSIZE) {
+ p = xdr_inline_decode(xdr, fh->size);
+ if (unlikely(!p))
+ goto out_overflow;
+ memcpy(fh->data, p, fh->size);
+ return p + XDR_QUADLEN(fh->size);
+ }
+ return NULL;
+
+out_overflow:
+ print_overflow_msg(__func__, xdr);
+ return ERR_PTR(-EIO);
+}
+
/*
* Encode/decode time.
*/
@@ -241,6 +271,26 @@ xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
}
static inline __be32 *
+xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr)
+{
+ __be32 *p;
+
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ if (ntohl(*p++)) {
+ p = xdr_inline_decode(xdr, 84);
+ if (unlikely(!p))
+ goto out_overflow;
+ p = xdr_decode_fattr(p, fattr);
+ }
+ return p;
+out_overflow:
+ print_overflow_msg(__func__, xdr);
+ return ERR_PTR(-EIO);
+}
+
+static inline __be32 *
xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
{
if (*p++)
@@ -442,12 +492,12 @@ nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
* Encode RENAME arguments
*/
static int
-nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
+nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
{
- p = xdr_encode_fhandle(p, args->fromfh);
- p = xdr_encode_array(p, args->fromname, args->fromlen);
- p = xdr_encode_fhandle(p, args->tofh);
- p = xdr_encode_array(p, args->toname, args->tolen);
+ p = xdr_encode_fhandle(p, args->old_dir);
+ p = xdr_encode_array(p, args->old_name->name, args->old_name->len);
+ p = xdr_encode_fhandle(p, args->new_dir);
+ p = xdr_encode_array(p, args->new_name->name, args->new_name->len);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
}
@@ -504,9 +554,8 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
struct kvec *iov = rcvbuf->head;
struct page **page;
size_t hdrlen;
- u32 len, recvd, pglen;
+ u32 recvd, pglen;
int status, nr = 0;
- __be32 *entry, *end, *kaddr;
status = ntohl(*p++);
/* Decode post_op_attrs */
@@ -536,99 +585,38 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
if (pglen > recvd)
pglen = recvd;
page = rcvbuf->pages;
- kaddr = p = kmap_atomic(*page, KM_USER0);
- end = (__be32 *)((char *)p + pglen);
- entry = p;
-
- /* Make sure the packet actually has a value_follows and EOF entry */
- if ((entry + 1) > end)
- goto short_pkt;
-
- for (; *p++; nr++) {
- if (p + 3 > end)
- goto short_pkt;
- p += 2; /* inode # */
- len = ntohl(*p++); /* string length */
- p += XDR_QUADLEN(len) + 2; /* name + cookie */
- if (len > NFS3_MAXNAMLEN) {
- dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
- len);
- goto err_unmap;
- }
- if (res->plus) {
- /* post_op_attr */
- if (p + 2 > end)
- goto short_pkt;
- if (*p++) {
- p += 21;
- if (p + 1 > end)
- goto short_pkt;
- }
- /* post_op_fh3 */
- if (*p++) {
- if (p + 1 > end)
- goto short_pkt;
- len = ntohl(*p++);
- if (len > NFS3_FHSIZE) {
- dprintk("NFS: giant filehandle in "
- "readdir (len 0x%x)!\n", len);
- goto err_unmap;
- }
- p += XDR_QUADLEN(len);
- }
- }
-
- if (p + 2 > end)
- goto short_pkt;
- entry = p;
- }
-
- /*
- * Apparently some server sends responses that are a valid size, but
- * contain no entries, and have value_follows==0 and EOF==0. For
- * those, just set the EOF marker.
- */
- if (!nr && entry[1] == 0) {
- dprintk("NFS: readdir reply truncated!\n");
- entry[1] = 1;
- }
- out:
- kunmap_atomic(kaddr, KM_USER0);
return nr;
- short_pkt:
- /*
- * When we get a short packet there are 2 possibilities. We can
- * return an error, or fix up the response to look like a valid
- * response and return what we have so far. If there are no
- * entries and the packet was short, then return -EIO. If there
- * are valid entries in the response, return them and pretend that
- * the call was successful, but incomplete. The caller can retry the
- * readdir starting at the last cookie.
- */
- entry[0] = entry[1] = 0;
- if (!nr)
- nr = -errno_NFSERR_IO;
- goto out;
-err_unmap:
- nr = -errno_NFSERR_IO;
- goto out;
}
__be32 *
-nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
+nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
{
+ __be32 *p;
struct nfs_entry old = *entry;
- if (!*p++) {
- if (!*p)
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ if (!ntohl(*p++)) {
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ if (!ntohl(*p++))
return ERR_PTR(-EAGAIN);
entry->eof = 1;
return ERR_PTR(-EBADCOOKIE);
}
+ p = xdr_inline_decode(xdr, 12);
+ if (unlikely(!p))
+ goto out_overflow;
p = xdr_decode_hyper(p, &entry->ino);
entry->len = ntohl(*p++);
+
+ p = xdr_inline_decode(xdr, entry->len + 8);
+ if (unlikely(!p))
+ goto out_overflow;
entry->name = (const char *) p;
p += XDR_QUADLEN(entry->len);
entry->prev_cookie = entry->cookie;
@@ -636,10 +624,17 @@ nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
if (plus) {
entry->fattr->valid = 0;
- p = xdr_decode_post_op_attr(p, entry->fattr);
+ p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
+ if (IS_ERR(p))
+ goto out_overflow_exit;
/* In fact, a post_op_fh3: */
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
if (*p++) {
- p = xdr_decode_fhandle(p, entry->fh);
+ p = xdr_decode_fhandle_stream(xdr, entry->fh);
+ if (IS_ERR(p))
+ goto out_overflow_exit;
/* Ugh -- server reply was truncated */
if (p == NULL) {
dprintk("NFS: FH truncated\n");
@@ -650,8 +645,18 @@ nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
}
- entry->eof = !p[0] && p[1];
+ p = xdr_inline_peek(xdr, 8);
+ if (p != NULL)
+ entry->eof = !p[0] && p[1];
+ else
+ entry->eof = 0;
+
return p;
+
+out_overflow:
+ print_overflow_msg(__func__, xdr);
+out_overflow_exit:
+ return ERR_PTR(-EIO);
}
/*
@@ -824,7 +829,6 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
struct kvec *iov = rcvbuf->head;
size_t hdrlen;
u32 len, recvd;
- char *kaddr;
int status;
status = ntohl(*p++);
@@ -857,10 +861,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
return -EIO;
}
- /* NULL terminate the string we got */
- kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
- kaddr[len+rcvbuf->page_base] = '\0';
- kunmap_atomic(kaddr, KM_USER0);
+ xdr_terminate_string(rcvbuf, len);
return 0;
}
@@ -970,14 +971,14 @@ nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
* Decode RENAME reply
*/
static int
-nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
+nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res)
{
int status;
if ((status = ntohl(*p++)) != 0)
status = nfs_stat_to_errno(status);
- p = xdr_decode_wcc_data(p, res->fromattr);
- p = xdr_decode_wcc_data(p, res->toattr);
+ p = xdr_decode_wcc_data(p, res->old_fattr);
+ p = xdr_decode_wcc_data(p, res->new_fattr);
return status;
}
@@ -1043,8 +1044,9 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
res->wtmult = ntohl(*p++);
res->dtpref = ntohl(*p++);
p = xdr_decode_hyper(p, &res->maxfilesize);
+ p = xdr_decode_time3(p, &res->time_delta);
- /* ignore time_delta and properties */
+ /* ignore properties */
res->lease_time = 0;
return 0;
}
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 311e15cc8af0..9fa496387fdf 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -242,8 +242,6 @@ 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 path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait);
-extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
-extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
struct nfs4_fs_locations *fs_locations, struct page *page);
@@ -333,7 +331,7 @@ extern void nfs_free_seqid(struct nfs_seqid *seqid);
extern const nfs4_stateid zero_stateid;
/* nfs4xdr.c */
-extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
+extern __be32 *nfs4_decode_dirent(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
extern struct rpc_procinfo nfs4_procedures[];
struct nfs4_mount_data;
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
new file mode 100644
index 000000000000..2e92f0d8d654
--- /dev/null
+++ b/fs/nfs/nfs4filelayout.c
@@ -0,0 +1,280 @@
+/*
+ * Module for the pnfs nfs4 file layout driver.
+ * Defines all I/O and Policy interface operations, plus code
+ * to register itself with the pNFS client.
+ *
+ * Copyright (c) 2002
+ * The Regents of the University of Michigan
+ * All Rights Reserved
+ *
+ * Dean Hildebrand <dhildebz@umich.edu>
+ *
+ * Permission is granted to use, copy, create derivative works, and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the University of Michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. If
+ * the above copyright notice or any other identification of the
+ * University of Michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * This software is provided as is, without representation or warranty
+ * of any kind either express or implied, including without limitation
+ * the implied warranties of merchantability, fitness for a particular
+ * purpose, or noninfringement. The Regents of the University of
+ * Michigan shall not be liable for any damages, including special,
+ * indirect, incidental, or consequential damages, with respect to any
+ * claim arising out of or in connection with the use of the software,
+ * even if it has been or is hereafter advised of the possibility of
+ * such damages.
+ */
+
+#include <linux/nfs_fs.h>
+
+#include "internal.h"
+#include "nfs4filelayout.h"
+
+#define NFSDBG_FACILITY NFSDBG_PNFS_LD
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dean Hildebrand <dhildebz@umich.edu>");
+MODULE_DESCRIPTION("The NFSv4 file layout driver");
+
+static int
+filelayout_set_layoutdriver(struct nfs_server *nfss)
+{
+ int status = pnfs_alloc_init_deviceid_cache(nfss->nfs_client,
+ nfs4_fl_free_deviceid_callback);
+ if (status) {
+ printk(KERN_WARNING "%s: deviceid cache could not be "
+ "initialized\n", __func__);
+ return status;
+ }
+ dprintk("%s: deviceid cache has been initialized successfully\n",
+ __func__);
+ return 0;
+}
+
+/* Clear out the layout by destroying its device list */
+static int
+filelayout_clear_layoutdriver(struct nfs_server *nfss)
+{
+ dprintk("--> %s\n", __func__);
+
+ if (nfss->nfs_client->cl_devid_cache)
+ pnfs_put_deviceid_cache(nfss->nfs_client);
+ return 0;
+}
+
+/*
+ * filelayout_check_layout()
+ *
+ * Make sure layout segment parameters are sane WRT the device.
+ * At this point no generic layer initialization of the lseg has occurred,
+ * and nothing has been added to the layout_hdr cache.
+ *
+ */
+static int
+filelayout_check_layout(struct pnfs_layout_hdr *lo,
+ struct nfs4_filelayout_segment *fl,
+ struct nfs4_layoutget_res *lgr,
+ struct nfs4_deviceid *id)
+{
+ struct nfs4_file_layout_dsaddr *dsaddr;
+ int status = -EINVAL;
+ struct nfs_server *nfss = NFS_SERVER(lo->inode);
+
+ dprintk("--> %s\n", __func__);
+
+ if (fl->pattern_offset > lgr->range.offset) {
+ dprintk("%s pattern_offset %lld to large\n",
+ __func__, fl->pattern_offset);
+ goto out;
+ }
+
+ if (fl->stripe_unit % PAGE_SIZE) {
+ dprintk("%s Stripe unit (%u) not page aligned\n",
+ __func__, fl->stripe_unit);
+ goto out;
+ }
+
+ /* find and reference the deviceid */
+ dsaddr = nfs4_fl_find_get_deviceid(nfss->nfs_client, id);
+ if (dsaddr == NULL) {
+ dsaddr = get_device_info(lo->inode, id);
+ if (dsaddr == NULL)
+ goto out;
+ }
+ fl->dsaddr = dsaddr;
+
+ if (fl->first_stripe_index < 0 ||
+ fl->first_stripe_index >= dsaddr->stripe_count) {
+ dprintk("%s Bad first_stripe_index %d\n",
+ __func__, fl->first_stripe_index);
+ goto out_put;
+ }
+
+ if ((fl->stripe_type == STRIPE_SPARSE &&
+ fl->num_fh > 1 && fl->num_fh != dsaddr->ds_num) ||
+ (fl->stripe_type == STRIPE_DENSE &&
+ fl->num_fh != dsaddr->stripe_count)) {
+ dprintk("%s num_fh %u not valid for given packing\n",
+ __func__, fl->num_fh);
+ goto out_put;
+ }
+
+ if (fl->stripe_unit % nfss->rsize || fl->stripe_unit % nfss->wsize) {
+ dprintk("%s Stripe unit (%u) not aligned with rsize %u "
+ "wsize %u\n", __func__, fl->stripe_unit, nfss->rsize,
+ nfss->wsize);
+ }
+
+ status = 0;
+out:
+ dprintk("--> %s returns %d\n", __func__, status);
+ return status;
+out_put:
+ pnfs_put_deviceid(nfss->nfs_client->cl_devid_cache, &dsaddr->deviceid);
+ goto out;
+}
+
+static void filelayout_free_fh_array(struct nfs4_filelayout_segment *fl)
+{
+ int i;
+
+ for (i = 0; i < fl->num_fh; i++) {
+ if (!fl->fh_array[i])
+ break;
+ kfree(fl->fh_array[i]);
+ }
+ kfree(fl->fh_array);
+ fl->fh_array = NULL;
+}
+
+static void
+_filelayout_free_lseg(struct nfs4_filelayout_segment *fl)
+{
+ filelayout_free_fh_array(fl);
+ kfree(fl);
+}
+
+static int
+filelayout_decode_layout(struct pnfs_layout_hdr *flo,
+ struct nfs4_filelayout_segment *fl,
+ struct nfs4_layoutget_res *lgr,
+ struct nfs4_deviceid *id)
+{
+ uint32_t *p = (uint32_t *)lgr->layout.buf;
+ uint32_t nfl_util;
+ int i;
+
+ dprintk("%s: set_layout_map Begin\n", __func__);
+
+ memcpy(id, p, sizeof(*id));
+ p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
+ print_deviceid(id);
+
+ nfl_util = be32_to_cpup(p++);
+ if (nfl_util & NFL4_UFLG_COMMIT_THRU_MDS)
+ fl->commit_through_mds = 1;
+ if (nfl_util & NFL4_UFLG_DENSE)
+ fl->stripe_type = STRIPE_DENSE;
+ else
+ fl->stripe_type = STRIPE_SPARSE;
+ fl->stripe_unit = nfl_util & ~NFL4_UFLG_MASK;
+
+ fl->first_stripe_index = be32_to_cpup(p++);
+ p = xdr_decode_hyper(p, &fl->pattern_offset);
+ fl->num_fh = be32_to_cpup(p++);
+
+ dprintk("%s: nfl_util 0x%X num_fh %u fsi %u po %llu\n",
+ __func__, nfl_util, fl->num_fh, fl->first_stripe_index,
+ fl->pattern_offset);
+
+ fl->fh_array = kzalloc(fl->num_fh * sizeof(struct nfs_fh *),
+ GFP_KERNEL);
+ if (!fl->fh_array)
+ return -ENOMEM;
+
+ for (i = 0; i < fl->num_fh; i++) {
+ /* Do we want to use a mempool here? */
+ fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
+ if (!fl->fh_array[i]) {
+ filelayout_free_fh_array(fl);
+ return -ENOMEM;
+ }
+ fl->fh_array[i]->size = be32_to_cpup(p++);
+ if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) {
+ printk(KERN_ERR "Too big fh %d received %d\n",
+ i, fl->fh_array[i]->size);
+ filelayout_free_fh_array(fl);
+ return -EIO;
+ }
+ memcpy(fl->fh_array[i]->data, p, fl->fh_array[i]->size);
+ p += XDR_QUADLEN(fl->fh_array[i]->size);
+ dprintk("DEBUG: %s: fh len %d\n", __func__,
+ fl->fh_array[i]->size);
+ }
+
+ return 0;
+}
+
+static struct pnfs_layout_segment *
+filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
+ struct nfs4_layoutget_res *lgr)
+{
+ struct nfs4_filelayout_segment *fl;
+ int rc;
+ struct nfs4_deviceid id;
+
+ dprintk("--> %s\n", __func__);
+ fl = kzalloc(sizeof(*fl), GFP_KERNEL);
+ if (!fl)
+ return NULL;
+
+ rc = filelayout_decode_layout(layoutid, fl, lgr, &id);
+ if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, &id)) {
+ _filelayout_free_lseg(fl);
+ return NULL;
+ }
+ return &fl->generic_hdr;
+}
+
+static void
+filelayout_free_lseg(struct pnfs_layout_segment *lseg)
+{
+ struct nfs_server *nfss = NFS_SERVER(lseg->layout->inode);
+ struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
+
+ dprintk("--> %s\n", __func__);
+ pnfs_put_deviceid(nfss->nfs_client->cl_devid_cache,
+ &fl->dsaddr->deviceid);
+ _filelayout_free_lseg(fl);
+}
+
+static struct pnfs_layoutdriver_type filelayout_type = {
+ .id = LAYOUT_NFSV4_1_FILES,
+ .name = "LAYOUT_NFSV4_1_FILES",
+ .owner = THIS_MODULE,
+ .set_layoutdriver = filelayout_set_layoutdriver,
+ .clear_layoutdriver = filelayout_clear_layoutdriver,
+ .alloc_lseg = filelayout_alloc_lseg,
+ .free_lseg = filelayout_free_lseg,
+};
+
+static int __init nfs4filelayout_init(void)
+{
+ printk(KERN_INFO "%s: NFSv4 File Layout Driver Registering...\n",
+ __func__);
+ return pnfs_register_layoutdriver(&filelayout_type);
+}
+
+static void __exit nfs4filelayout_exit(void)
+{
+ printk(KERN_INFO "%s: NFSv4 File Layout Driver Unregistering...\n",
+ __func__);
+ pnfs_unregister_layoutdriver(&filelayout_type);
+}
+
+module_init(nfs4filelayout_init);
+module_exit(nfs4filelayout_exit);
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h
new file mode 100644
index 000000000000..bbf60dd2ab9d
--- /dev/null
+++ b/fs/nfs/nfs4filelayout.h
@@ -0,0 +1,94 @@
+/*
+ * NFSv4 file layout driver data structures.
+ *
+ * Copyright (c) 2002
+ * The Regents of the University of Michigan
+ * All Rights Reserved
+ *
+ * Dean Hildebrand <dhildebz@umich.edu>
+ *
+ * Permission is granted to use, copy, create derivative works, and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the University of Michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. If
+ * the above copyright notice or any other identification of the
+ * University of Michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * This software is provided as is, without representation or warranty
+ * of any kind either express or implied, including without limitation
+ * the implied warranties of merchantability, fitness for a particular
+ * purpose, or noninfringement. The Regents of the University of
+ * Michigan shall not be liable for any damages, including special,
+ * indirect, incidental, or consequential damages, with respect to any
+ * claim arising out of or in connection with the use of the software,
+ * even if it has been or is hereafter advised of the possibility of
+ * such damages.
+ */
+
+#ifndef FS_NFS_NFS4FILELAYOUT_H
+#define FS_NFS_NFS4FILELAYOUT_H
+
+#include "pnfs.h"
+
+/*
+ * Field testing shows we need to support upto 4096 stripe indices.
+ * We store each index as a u8 (u32 on the wire) to keep the memory footprint
+ * reasonable. This in turn means we support a maximum of 256
+ * RFC 5661 multipath_list4 structures.
+ */
+#define NFS4_PNFS_MAX_STRIPE_CNT 4096
+#define NFS4_PNFS_MAX_MULTI_CNT 256 /* 256 fit into a u8 stripe_index */
+
+enum stripetype4 {
+ STRIPE_SPARSE = 1,
+ STRIPE_DENSE = 2
+};
+
+/* Individual ip address */
+struct nfs4_pnfs_ds {
+ struct list_head ds_node; /* nfs4_pnfs_dev_hlist dev_dslist */
+ u32 ds_ip_addr;
+ u32 ds_port;
+ struct nfs_client *ds_clp;
+ atomic_t ds_count;
+};
+
+struct nfs4_file_layout_dsaddr {
+ struct pnfs_deviceid_node deviceid;
+ u32 stripe_count;
+ u8 *stripe_indices;
+ u32 ds_num;
+ struct nfs4_pnfs_ds *ds_list[1];
+};
+
+struct nfs4_filelayout_segment {
+ struct pnfs_layout_segment generic_hdr;
+ u32 stripe_type;
+ u32 commit_through_mds;
+ u32 stripe_unit;
+ u32 first_stripe_index;
+ u64 pattern_offset;
+ struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */
+ unsigned int num_fh;
+ struct nfs_fh **fh_array;
+};
+
+static inline struct nfs4_filelayout_segment *
+FILELAYOUT_LSEG(struct pnfs_layout_segment *lseg)
+{
+ return container_of(lseg,
+ struct nfs4_filelayout_segment,
+ generic_hdr);
+}
+
+extern void nfs4_fl_free_deviceid_callback(struct pnfs_deviceid_node *);
+extern void print_ds(struct nfs4_pnfs_ds *ds);
+extern void print_deviceid(struct nfs4_deviceid *dev_id);
+extern struct nfs4_file_layout_dsaddr *
+nfs4_fl_find_get_deviceid(struct nfs_client *, struct nfs4_deviceid *dev_id);
+struct nfs4_file_layout_dsaddr *
+get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id);
+
+#endif /* FS_NFS_NFS4FILELAYOUT_H */
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c
new file mode 100644
index 000000000000..51fe64ace55a
--- /dev/null
+++ b/fs/nfs/nfs4filelayoutdev.c
@@ -0,0 +1,448 @@
+/*
+ * Device operations for the pnfs nfs4 file layout driver.
+ *
+ * Copyright (c) 2002
+ * The Regents of the University of Michigan
+ * All Rights Reserved
+ *
+ * Dean Hildebrand <dhildebz@umich.edu>
+ * Garth Goodson <Garth.Goodson@netapp.com>
+ *
+ * Permission is granted to use, copy, create derivative works, and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the University of Michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. If
+ * the above copyright notice or any other identification of the
+ * University of Michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * This software is provided as is, without representation or warranty
+ * of any kind either express or implied, including without limitation
+ * the implied warranties of merchantability, fitness for a particular
+ * purpose, or noninfringement. The Regents of the University of
+ * Michigan shall not be liable for any damages, including special,
+ * indirect, incidental, or consequential damages, with respect to any
+ * claim arising out of or in connection with the use of the software,
+ * even if it has been or is hereafter advised of the possibility of
+ * such damages.
+ */
+
+#include <linux/nfs_fs.h>
+#include <linux/vmalloc.h>
+
+#include "internal.h"
+#include "nfs4filelayout.h"
+
+#define NFSDBG_FACILITY NFSDBG_PNFS_LD
+
+/*
+ * Data server cache
+ *
+ * Data servers can be mapped to different device ids.
+ * nfs4_pnfs_ds reference counting
+ * - set to 1 on allocation
+ * - incremented when a device id maps a data server already in the cache.
+ * - decremented when deviceid is removed from the cache.
+ */
+DEFINE_SPINLOCK(nfs4_ds_cache_lock);
+static LIST_HEAD(nfs4_data_server_cache);
+
+/* Debug routines */
+void
+print_ds(struct nfs4_pnfs_ds *ds)
+{
+ if (ds == NULL) {
+ printk("%s NULL device\n", __func__);
+ return;
+ }
+ printk(" ip_addr %x port %hu\n"
+ " ref count %d\n"
+ " client %p\n"
+ " cl_exchange_flags %x\n",
+ ntohl(ds->ds_ip_addr), ntohs(ds->ds_port),
+ atomic_read(&ds->ds_count), ds->ds_clp,
+ ds->ds_clp ? ds->ds_clp->cl_exchange_flags : 0);
+}
+
+void
+print_ds_list(struct nfs4_file_layout_dsaddr *dsaddr)
+{
+ int i;
+
+ ifdebug(FACILITY) {
+ printk("%s dsaddr->ds_num %d\n", __func__,
+ dsaddr->ds_num);
+ for (i = 0; i < dsaddr->ds_num; i++)
+ print_ds(dsaddr->ds_list[i]);
+ }
+}
+
+void print_deviceid(struct nfs4_deviceid *id)
+{
+ u32 *p = (u32 *)id;
+
+ dprintk("%s: device id= [%x%x%x%x]\n", __func__,
+ p[0], p[1], p[2], p[3]);
+}
+
+/* nfs4_ds_cache_lock is held */
+static struct nfs4_pnfs_ds *
+_data_server_lookup_locked(u32 ip_addr, u32 port)
+{
+ struct nfs4_pnfs_ds *ds;
+
+ dprintk("_data_server_lookup: ip_addr=%x port=%hu\n",
+ ntohl(ip_addr), ntohs(port));
+
+ list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) {
+ if (ds->ds_ip_addr == ip_addr &&
+ ds->ds_port == port) {
+ return ds;
+ }
+ }
+ return NULL;
+}
+
+static void
+destroy_ds(struct nfs4_pnfs_ds *ds)
+{
+ dprintk("--> %s\n", __func__);
+ ifdebug(FACILITY)
+ print_ds(ds);
+
+ if (ds->ds_clp)
+ nfs_put_client(ds->ds_clp);
+ kfree(ds);
+}
+
+static void
+nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
+{
+ struct nfs4_pnfs_ds *ds;
+ int i;
+
+ print_deviceid(&dsaddr->deviceid.de_id);
+
+ for (i = 0; i < dsaddr->ds_num; i++) {
+ ds = dsaddr->ds_list[i];
+ if (ds != NULL) {
+ if (atomic_dec_and_lock(&ds->ds_count,
+ &nfs4_ds_cache_lock)) {
+ list_del_init(&ds->ds_node);
+ spin_unlock(&nfs4_ds_cache_lock);
+ destroy_ds(ds);
+ }
+ }
+ }
+ kfree(dsaddr->stripe_indices);
+ kfree(dsaddr);
+}
+
+void
+nfs4_fl_free_deviceid_callback(struct pnfs_deviceid_node *device)
+{
+ struct nfs4_file_layout_dsaddr *dsaddr =
+ container_of(device, struct nfs4_file_layout_dsaddr, deviceid);
+
+ nfs4_fl_free_deviceid(dsaddr);
+}
+
+static struct nfs4_pnfs_ds *
+nfs4_pnfs_ds_add(struct inode *inode, u32 ip_addr, u32 port)
+{
+ struct nfs4_pnfs_ds *tmp_ds, *ds;
+
+ ds = kzalloc(sizeof(*tmp_ds), GFP_KERNEL);
+ if (!ds)
+ goto out;
+
+ spin_lock(&nfs4_ds_cache_lock);
+ tmp_ds = _data_server_lookup_locked(ip_addr, port);
+ if (tmp_ds == NULL) {
+ ds->ds_ip_addr = ip_addr;
+ ds->ds_port = port;
+ atomic_set(&ds->ds_count, 1);
+ INIT_LIST_HEAD(&ds->ds_node);
+ ds->ds_clp = NULL;
+ list_add(&ds->ds_node, &nfs4_data_server_cache);
+ dprintk("%s add new data server ip 0x%x\n", __func__,
+ ds->ds_ip_addr);
+ } else {
+ kfree(ds);
+ atomic_inc(&tmp_ds->ds_count);
+ dprintk("%s data server found ip 0x%x, inc'ed ds_count to %d\n",
+ __func__, tmp_ds->ds_ip_addr,
+ atomic_read(&tmp_ds->ds_count));
+ ds = tmp_ds;
+ }
+ spin_unlock(&nfs4_ds_cache_lock);
+out:
+ return ds;
+}
+
+/*
+ * Currently only support ipv4, and one multi-path address.
+ */
+static struct nfs4_pnfs_ds *
+decode_and_add_ds(__be32 **pp, struct inode *inode)
+{
+ struct nfs4_pnfs_ds *ds = NULL;
+ char *buf;
+ const char *ipend, *pstr;
+ u32 ip_addr, port;
+ int nlen, rlen, i;
+ int tmp[2];
+ __be32 *r_netid, *r_addr, *p = *pp;
+
+ /* r_netid */
+ nlen = be32_to_cpup(p++);
+ r_netid = p;
+ p += XDR_QUADLEN(nlen);
+
+ /* r_addr */
+ rlen = be32_to_cpup(p++);
+ r_addr = p;
+ p += XDR_QUADLEN(rlen);
+ *pp = p;
+
+ /* Check that netid is "tcp" */
+ if (nlen != 3 || memcmp((char *)r_netid, "tcp", 3)) {
+ dprintk("%s: ERROR: non ipv4 TCP r_netid\n", __func__);
+ goto out_err;
+ }
+
+ /* ipv6 length plus port is legal */
+ if (rlen > INET6_ADDRSTRLEN + 8) {
+ dprintk("%s Invalid address, length %d\n", __func__,
+ rlen);
+ goto out_err;
+ }
+ buf = kmalloc(rlen + 1, GFP_KERNEL);
+ buf[rlen] = '\0';
+ memcpy(buf, r_addr, rlen);
+
+ /* replace the port dots with dashes for the in4_pton() delimiter*/
+ for (i = 0; i < 2; i++) {
+ char *res = strrchr(buf, '.');
+ *res = '-';
+ }
+
+ /* Currently only support ipv4 address */
+ if (in4_pton(buf, rlen, (u8 *)&ip_addr, '-', &ipend) == 0) {
+ dprintk("%s: Only ipv4 addresses supported\n", __func__);
+ goto out_free;
+ }
+
+ /* port */
+ pstr = ipend;
+ sscanf(pstr, "-%d-%d", &tmp[0], &tmp[1]);
+ port = htons((tmp[0] << 8) | (tmp[1]));
+
+ ds = nfs4_pnfs_ds_add(inode, ip_addr, port);
+ dprintk("%s Decoded address and port %s\n", __func__, buf);
+out_free:
+ kfree(buf);
+out_err:
+ return ds;
+}
+
+/* Decode opaque device data and return the result */
+static struct nfs4_file_layout_dsaddr*
+decode_device(struct inode *ino, struct pnfs_device *pdev)
+{
+ int i, dummy;
+ u32 cnt, num;
+ u8 *indexp;
+ __be32 *p = (__be32 *)pdev->area, *indicesp;
+ struct nfs4_file_layout_dsaddr *dsaddr;
+
+ /* Get the stripe count (number of stripe index) */
+ cnt = be32_to_cpup(p++);
+ dprintk("%s stripe count %d\n", __func__, cnt);
+ if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) {
+ printk(KERN_WARNING "%s: stripe count %d greater than "
+ "supported maximum %d\n", __func__,
+ cnt, NFS4_PNFS_MAX_STRIPE_CNT);
+ goto out_err;
+ }
+
+ /* Check the multipath list count */
+ indicesp = p;
+ p += XDR_QUADLEN(cnt << 2);
+ num = be32_to_cpup(p++);
+ dprintk("%s ds_num %u\n", __func__, num);
+ if (num > NFS4_PNFS_MAX_MULTI_CNT) {
+ printk(KERN_WARNING "%s: multipath count %d greater than "
+ "supported maximum %d\n", __func__,
+ num, NFS4_PNFS_MAX_MULTI_CNT);
+ goto out_err;
+ }
+ dsaddr = kzalloc(sizeof(*dsaddr) +
+ (sizeof(struct nfs4_pnfs_ds *) * (num - 1)),
+ GFP_KERNEL);
+ if (!dsaddr)
+ goto out_err;
+
+ dsaddr->stripe_indices = kzalloc(sizeof(u8) * cnt, GFP_KERNEL);
+ if (!dsaddr->stripe_indices)
+ goto out_err_free;
+
+ dsaddr->stripe_count = cnt;
+ dsaddr->ds_num = num;
+
+ memcpy(&dsaddr->deviceid.de_id, &pdev->dev_id, sizeof(pdev->dev_id));
+
+ /* Go back an read stripe indices */
+ p = indicesp;
+ indexp = &dsaddr->stripe_indices[0];
+ for (i = 0; i < dsaddr->stripe_count; i++) {
+ *indexp = be32_to_cpup(p++);
+ if (*indexp >= num)
+ goto out_err_free;
+ indexp++;
+ }
+ /* Skip already read multipath list count */
+ p++;
+
+ for (i = 0; i < dsaddr->ds_num; i++) {
+ int j;
+
+ dummy = be32_to_cpup(p++); /* multipath count */
+ if (dummy > 1) {
+ printk(KERN_WARNING
+ "%s: Multipath count %d not supported, "
+ "skipping all greater than 1\n", __func__,
+ dummy);
+ }
+ for (j = 0; j < dummy; j++) {
+ if (j == 0) {
+ dsaddr->ds_list[i] = decode_and_add_ds(&p, ino);
+ if (dsaddr->ds_list[i] == NULL)
+ goto out_err_free;
+ } else {
+ u32 len;
+ /* skip extra multipath */
+ len = be32_to_cpup(p++);
+ p += XDR_QUADLEN(len);
+ len = be32_to_cpup(p++);
+ p += XDR_QUADLEN(len);
+ continue;
+ }
+ }
+ }
+ return dsaddr;
+
+out_err_free:
+ nfs4_fl_free_deviceid(dsaddr);
+out_err:
+ dprintk("%s ERROR: returning NULL\n", __func__);
+ return NULL;
+}
+
+/*
+ * Decode the opaque device specified in 'dev'
+ * and add it to the list of available devices.
+ * If the deviceid is already cached, nfs4_add_deviceid will return
+ * a pointer to the cached struct and throw away the new.
+ */
+static struct nfs4_file_layout_dsaddr*
+decode_and_add_device(struct inode *inode, struct pnfs_device *dev)
+{
+ struct nfs4_file_layout_dsaddr *dsaddr;
+ struct pnfs_deviceid_node *d;
+
+ dsaddr = decode_device(inode, dev);
+ if (!dsaddr) {
+ printk(KERN_WARNING "%s: Could not decode or add device\n",
+ __func__);
+ return NULL;
+ }
+
+ d = pnfs_add_deviceid(NFS_SERVER(inode)->nfs_client->cl_devid_cache,
+ &dsaddr->deviceid);
+
+ return container_of(d, struct nfs4_file_layout_dsaddr, deviceid);
+}
+
+/*
+ * Retrieve the information for dev_id, add it to the list
+ * of available devices, and return it.
+ */
+struct nfs4_file_layout_dsaddr *
+get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id)
+{
+ struct pnfs_device *pdev = NULL;
+ u32 max_resp_sz;
+ int max_pages;
+ struct page **pages = NULL;
+ struct nfs4_file_layout_dsaddr *dsaddr = NULL;
+ int rc, i;
+ struct nfs_server *server = NFS_SERVER(inode);
+
+ /*
+ * Use the session max response size as the basis for setting
+ * GETDEVICEINFO's maxcount
+ */
+ max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
+ max_pages = max_resp_sz >> PAGE_SHIFT;
+ dprintk("%s inode %p max_resp_sz %u max_pages %d\n",
+ __func__, inode, max_resp_sz, max_pages);
+
+ pdev = kzalloc(sizeof(struct pnfs_device), GFP_KERNEL);
+ if (pdev == NULL)
+ return NULL;
+
+ pages = kzalloc(max_pages * sizeof(struct page *), GFP_KERNEL);
+ if (pages == NULL) {
+ kfree(pdev);
+ return NULL;
+ }
+ for (i = 0; i < max_pages; i++) {
+ pages[i] = alloc_page(GFP_KERNEL);
+ if (!pages[i])
+ goto out_free;
+ }
+
+ /* set pdev->area */
+ pdev->area = vmap(pages, max_pages, VM_MAP, PAGE_KERNEL);
+ if (!pdev->area)
+ goto out_free;
+
+ memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id));
+ pdev->layout_type = LAYOUT_NFSV4_1_FILES;
+ pdev->pages = pages;
+ pdev->pgbase = 0;
+ pdev->pglen = PAGE_SIZE * max_pages;
+ pdev->mincount = 0;
+
+ rc = nfs4_proc_getdeviceinfo(server, pdev);
+ dprintk("%s getdevice info returns %d\n", __func__, rc);
+ if (rc)
+ goto out_free;
+
+ /*
+ * Found new device, need to decode it and then add it to the
+ * list of known devices for this mountpoint.
+ */
+ dsaddr = decode_and_add_device(inode, pdev);
+out_free:
+ if (pdev->area != NULL)
+ vunmap(pdev->area);
+ for (i = 0; i < max_pages; i++)
+ __free_page(pages[i]);
+ kfree(pages);
+ kfree(pdev);
+ dprintk("<-- %s dsaddr %p\n", __func__, dsaddr);
+ return dsaddr;
+}
+
+struct nfs4_file_layout_dsaddr *
+nfs4_fl_find_get_deviceid(struct nfs_client *clp, struct nfs4_deviceid *id)
+{
+ struct pnfs_deviceid_node *d;
+
+ d = pnfs_find_get_deviceid(clp->cl_devid_cache, id);
+ return (d == NULL) ? NULL :
+ container_of(d, struct nfs4_file_layout_dsaddr, deviceid);
+}
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 089da5b5d20a..32c8758c99fd 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -55,6 +55,7 @@
#include "internal.h"
#include "iostat.h"
#include "callback.h"
+#include "pnfs.h"
#define NFSDBG_FACILITY NFSDBG_PROC
@@ -129,7 +130,8 @@ const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE
| FATTR4_WORD0_MAXREAD
| FATTR4_WORD0_MAXWRITE
| FATTR4_WORD0_LEASE_TIME,
- 0
+ FATTR4_WORD1_TIME_DELTA
+ | FATTR4_WORD1_FS_LAYOUT_TYPES
};
const u32 nfs4_fs_locations_bitmap[2] = {
@@ -255,9 +257,6 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
nfs4_state_mark_reclaim_nograce(clp, state);
goto do_state_recovery;
case -NFS4ERR_STALE_STATEID:
- if (state == NULL)
- break;
- nfs4_state_mark_reclaim_reboot(clp, state);
case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_EXPIRED:
goto do_state_recovery;
@@ -334,10 +333,12 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp
* Must be called while holding tbl->slot_tbl_lock
*/
static void
-nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid)
+nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *free_slot)
{
+ int free_slotid = free_slot - tbl->slots;
int slotid = free_slotid;
+ BUG_ON(slotid < 0 || slotid >= NFS4_MAX_SLOT_TABLE);
/* clear used bit in bitmap */
__clear_bit(slotid, tbl->used_slots);
@@ -379,7 +380,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
struct nfs4_slot_table *tbl;
tbl = &res->sr_session->fc_slot_table;
- if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) {
+ if (!res->sr_slot) {
/* just wake up the next guy waiting since
* we may have not consumed a slot after all */
dprintk("%s: No slot\n", __func__);
@@ -387,17 +388,15 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
}
spin_lock(&tbl->slot_tbl_lock);
- nfs4_free_slot(tbl, res->sr_slotid);
+ nfs4_free_slot(tbl, res->sr_slot);
nfs41_check_drain_session_complete(res->sr_session);
spin_unlock(&tbl->slot_tbl_lock);
- res->sr_slotid = NFS4_MAX_SLOT_TABLE;
+ res->sr_slot = NULL;
}
static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
{
unsigned long timestamp;
- struct nfs4_slot_table *tbl;
- struct nfs4_slot *slot;
struct nfs_client *clp;
/*
@@ -410,17 +409,14 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *
res->sr_status = NFS_OK;
/* -ERESTARTSYS can result in skipping nfs41_sequence_setup */
- if (res->sr_slotid == NFS4_MAX_SLOT_TABLE)
+ if (!res->sr_slot)
goto out;
- tbl = &res->sr_session->fc_slot_table;
- slot = tbl->slots + res->sr_slotid;
-
/* Check the SEQUENCE operation status */
switch (res->sr_status) {
case 0:
/* Update the slot's sequence and clientid lease timer */
- ++slot->seq_nr;
+ ++res->sr_slot->seq_nr;
timestamp = res->sr_renewal_time;
clp = res->sr_session->clp;
do_renew_lease(clp, timestamp);
@@ -433,12 +429,14 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *
* returned NFS4ERR_DELAY as per Section 2.10.6.2
* of RFC5661.
*/
- dprintk("%s: slot=%d seq=%d: Operation in progress\n",
- __func__, res->sr_slotid, slot->seq_nr);
+ dprintk("%s: slot=%ld seq=%d: Operation in progress\n",
+ __func__,
+ res->sr_slot - res->sr_session->fc_slot_table.slots,
+ res->sr_slot->seq_nr);
goto out_retry;
default:
/* Just update the slot sequence no. */
- ++slot->seq_nr;
+ ++res->sr_slot->seq_nr;
}
out:
/* The session may be reset by one of the error handlers. */
@@ -505,10 +503,9 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
dprintk("--> %s\n", __func__);
/* slot already allocated? */
- if (res->sr_slotid != NFS4_MAX_SLOT_TABLE)
+ if (res->sr_slot != NULL)
return 0;
- res->sr_slotid = NFS4_MAX_SLOT_TABLE;
tbl = &session->fc_slot_table;
spin_lock(&tbl->slot_tbl_lock);
@@ -550,7 +547,7 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr);
res->sr_session = session;
- res->sr_slotid = slotid;
+ res->sr_slot = slot;
res->sr_renewal_time = jiffies;
res->sr_status_flags = 0;
/*
@@ -576,8 +573,9 @@ int nfs4_setup_sequence(const struct nfs_server *server,
goto out;
}
- dprintk("--> %s clp %p session %p sr_slotid %d\n",
- __func__, session->clp, session, res->sr_slotid);
+ dprintk("--> %s clp %p session %p sr_slot %ld\n",
+ __func__, session->clp, session, res->sr_slot ?
+ res->sr_slot - session->fc_slot_table.slots : -1);
ret = nfs41_setup_sequence(session, args, res, cache_reply,
task);
@@ -650,7 +648,7 @@ static int nfs4_call_sync_sequence(struct nfs_server *server,
.callback_data = &data
};
- res->sr_slotid = NFS4_MAX_SLOT_TABLE;
+ res->sr_slot = NULL;
if (privileged)
task_setup.callback_ops = &nfs41_call_priv_sync_ops;
task = rpc_run_task(&task_setup);
@@ -735,7 +733,6 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
p->o_res.server = p->o_arg.server;
nfs_fattr_init(&p->f_attr);
nfs_fattr_init(&p->dir_attr);
- p->o_res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
}
static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
@@ -1120,6 +1117,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
clear_bit(NFS_DELEGATED_STATE, &state->flags);
smp_rmb();
if (state->n_rdwr != 0) {
+ clear_bit(NFS_O_RDWR_STATE, &state->flags);
ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate);
if (ret != 0)
return ret;
@@ -1127,6 +1125,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
return -ESTALE;
}
if (state->n_wronly != 0) {
+ clear_bit(NFS_O_WRONLY_STATE, &state->flags);
ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate);
if (ret != 0)
return ret;
@@ -1134,6 +1133,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
return -ESTALE;
}
if (state->n_rdonly != 0) {
+ clear_bit(NFS_O_RDONLY_STATE, &state->flags);
ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate);
if (ret != 0)
return ret;
@@ -1188,7 +1188,7 @@ static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state
int err;
do {
err = _nfs4_do_open_reclaim(ctx, state);
- if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED)
+ if (err != -NFS4ERR_DELAY)
break;
nfs4_handle_exception(server, err, &exception);
} while (exception.retry);
@@ -1258,6 +1258,13 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_BAD_STATEID:
nfs4_state_mark_reclaim_nograce(server->nfs_client, state);
+ case -EKEYEXPIRED:
+ /*
+ * User RPCSEC_GSS context has expired.
+ * We cannot recover this stateid now, so
+ * skip it and allow recovery thread to
+ * proceed.
+ */
case -ENOMEM:
err = 0;
goto out;
@@ -1605,7 +1612,6 @@ static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state
goto out;
case -NFS4ERR_GRACE:
case -NFS4ERR_DELAY:
- case -EKEYEXPIRED:
nfs4_handle_exception(server, err, &exception);
err = 0;
}
@@ -1975,7 +1981,6 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, i
calldata->res.fattr = &calldata->fattr;
calldata->res.seqid = calldata->arg.seqid;
calldata->res.server = server;
- calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
path_get(path);
calldata->path = *path;
@@ -1998,120 +2003,17 @@ out:
return status;
}
-static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state, fmode_t fmode)
+static struct inode *
+nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr)
{
- struct file *filp;
- int ret;
-
- /* If the open_intent is for execute, we have an extra check to make */
- if (fmode & FMODE_EXEC) {
- ret = nfs_may_open(state->inode,
- state->owner->so_cred,
- nd->intent.open.flags);
- if (ret < 0)
- goto out_close;
- }
- filp = lookup_instantiate_filp(nd, path->dentry, NULL);
- if (!IS_ERR(filp)) {
- struct nfs_open_context *ctx;
- ctx = nfs_file_open_context(filp);
- ctx->state = state;
- return 0;
- }
- ret = PTR_ERR(filp);
-out_close:
- nfs4_close_sync(path, state, fmode & (FMODE_READ|FMODE_WRITE));
- return ret;
-}
-
-struct dentry *
-nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
-{
- struct path path = {
- .mnt = nd->path.mnt,
- .dentry = dentry,
- };
- struct dentry *parent;
- struct iattr attr;
- struct rpc_cred *cred;
struct nfs4_state *state;
- struct dentry *res;
- int open_flags = nd->intent.open.flags;
- fmode_t fmode = open_flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC);
-
- if (nd->flags & LOOKUP_CREATE) {
- attr.ia_mode = nd->intent.open.create_mode;
- attr.ia_valid = ATTR_MODE;
- if (!IS_POSIXACL(dir))
- attr.ia_mode &= ~current_umask();
- } else {
- open_flags &= ~O_EXCL;
- attr.ia_valid = 0;
- BUG_ON(open_flags & O_CREAT);
- }
- cred = rpc_lookup_cred();
- if (IS_ERR(cred))
- return (struct dentry *)cred;
- parent = dentry->d_parent;
/* Protect against concurrent sillydeletes */
- nfs_block_sillyrename(parent);
- state = nfs4_do_open(dir, &path, fmode, open_flags, &attr, cred);
- put_rpccred(cred);
- if (IS_ERR(state)) {
- if (PTR_ERR(state) == -ENOENT) {
- d_add(dentry, NULL);
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
- }
- nfs_unblock_sillyrename(parent);
- return (struct dentry *)state;
- }
- res = d_add_unique(dentry, igrab(state->inode));
- if (res != NULL)
- path.dentry = res;
- nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir));
- nfs_unblock_sillyrename(parent);
- nfs4_intent_set_file(nd, &path, state, fmode);
- return res;
-}
-
-int
-nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd)
-{
- struct path path = {
- .mnt = nd->path.mnt,
- .dentry = dentry,
- };
- struct rpc_cred *cred;
- struct nfs4_state *state;
- fmode_t fmode = openflags & (FMODE_READ | FMODE_WRITE);
-
- cred = rpc_lookup_cred();
- if (IS_ERR(cred))
- return PTR_ERR(cred);
- state = nfs4_do_open(dir, &path, fmode, openflags, NULL, cred);
- put_rpccred(cred);
- if (IS_ERR(state)) {
- switch (PTR_ERR(state)) {
- case -EPERM:
- case -EACCES:
- case -EDQUOT:
- case -ENOSPC:
- case -EROFS:
- return PTR_ERR(state);
- default:
- goto out_drop;
- }
- }
- if (state->inode == dentry->d_inode) {
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
- nfs4_intent_set_file(nd, &path, state, fmode);
- return 1;
- }
- nfs4_close_sync(&path, state, fmode);
-out_drop:
- d_drop(dentry);
- return 0;
+ state = nfs4_do_open(dir, &ctx->path, ctx->mode, open_flags, attr, ctx->cred);
+ if (IS_ERR(state))
+ return ERR_CAST(state);
+ ctx->state = state;
+ return igrab(state->inode);
}
static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
@@ -2568,36 +2470,34 @@ static int nfs4_proc_readlink(struct inode *inode, struct page *page,
static int
nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
- int flags, struct nameidata *nd)
+ int flags, struct nfs_open_context *ctx)
{
- struct path path = {
- .mnt = nd->path.mnt,
+ struct path my_path = {
.dentry = dentry,
};
+ struct path *path = &my_path;
struct nfs4_state *state;
- struct rpc_cred *cred;
- fmode_t fmode = flags & (FMODE_READ | FMODE_WRITE);
+ struct rpc_cred *cred = NULL;
+ fmode_t fmode = 0;
int status = 0;
- cred = rpc_lookup_cred();
- if (IS_ERR(cred)) {
- status = PTR_ERR(cred);
- goto out;
+ if (ctx != NULL) {
+ cred = ctx->cred;
+ path = &ctx->path;
+ fmode = ctx->mode;
}
- state = nfs4_do_open(dir, &path, fmode, flags, sattr, cred);
+ state = nfs4_do_open(dir, path, fmode, flags, sattr, cred);
d_drop(dentry);
if (IS_ERR(state)) {
status = PTR_ERR(state);
- goto out_putcred;
+ goto out;
}
d_add(dentry, igrab(state->inode));
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
- if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
- status = nfs4_intent_set_file(nd, &path, state, fmode);
+ if (ctx != NULL)
+ ctx->state = state;
else
- nfs4_close_sync(&path, state, fmode);
-out_putcred:
- put_rpccred(cred);
+ nfs4_close_sync(path, state, fmode);
out:
return status;
}
@@ -2655,6 +2555,7 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
args->bitmask = server->cache_consistency_bitmask;
res->server = server;
+ res->seq_res.sr_slot = NULL;
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
}
@@ -2671,18 +2572,46 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
return 1;
}
+static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
+{
+ struct nfs_server *server = NFS_SERVER(dir);
+ struct nfs_renameargs *arg = msg->rpc_argp;
+ struct nfs_renameres *res = msg->rpc_resp;
+
+ msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
+ arg->bitmask = server->attr_bitmask;
+ res->server = server;
+}
+
+static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
+ struct inode *new_dir)
+{
+ struct nfs_renameres *res = task->tk_msg.rpc_resp;
+
+ if (!nfs4_sequence_done(task, &res->seq_res))
+ return 0;
+ if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
+ return 0;
+
+ update_changeattr(old_dir, &res->old_cinfo);
+ nfs_post_op_update_inode(old_dir, res->old_fattr);
+ update_changeattr(new_dir, &res->new_cinfo);
+ nfs_post_op_update_inode(new_dir, res->new_fattr);
+ return 1;
+}
+
static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
struct inode *new_dir, struct qstr *new_name)
{
struct nfs_server *server = NFS_SERVER(old_dir);
- struct nfs4_rename_arg arg = {
+ struct nfs_renameargs arg = {
.old_dir = NFS_FH(old_dir),
.new_dir = NFS_FH(new_dir),
.old_name = old_name,
.new_name = new_name,
.bitmask = server->attr_bitmask,
};
- struct nfs4_rename_res res = {
+ struct nfs_renameres res = {
.server = server,
};
struct rpc_message msg = {
@@ -2896,15 +2825,16 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
}
static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
- u64 cookie, struct page *page, unsigned int count, int plus)
+ u64 cookie, struct page **pages, unsigned int count, int plus)
{
struct inode *dir = dentry->d_inode;
struct nfs4_readdir_arg args = {
.fh = NFS_FH(dir),
- .pages = &page,
+ .pages = pages,
.pgbase = 0,
.count = count,
.bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask,
+ .plus = plus,
};
struct nfs4_readdir_res res;
struct rpc_message msg = {
@@ -2932,14 +2862,14 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
}
static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
- u64 cookie, struct page *page, unsigned int count, int plus)
+ u64 cookie, struct page **pages, unsigned int count, int plus)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode),
_nfs4_proc_readdir(dentry, cred, cookie,
- page, count, plus),
+ pages, count, plus),
&exception);
} while (exception.retry);
return err;
@@ -3490,9 +3420,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
nfs4_state_mark_reclaim_nograce(clp, state);
goto do_state_recovery;
case -NFS4ERR_STALE_STATEID:
- if (state == NULL)
- break;
- nfs4_state_mark_reclaim_reboot(clp, state);
case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_EXPIRED:
goto do_state_recovery;
@@ -3626,7 +3553,6 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
case -NFS4ERR_RESOURCE:
/* The IBM lawyers misread another document! */
case -NFS4ERR_DELAY:
- case -EKEYEXPIRED:
err = nfs4_delay(clp->cl_rpcclient, &timeout);
}
} while (err == 0);
@@ -3721,7 +3647,6 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
memcpy(&data->stateid, stateid, sizeof(data->stateid));
data->res.fattr = &data->fattr;
data->res.server = server;
- data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
nfs_fattr_init(data->res.fattr);
data->timestamp = jiffies;
data->rpc_status = 0;
@@ -3874,7 +3799,6 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
p->arg.fl = &p->fl;
p->arg.seqid = seqid;
p->res.seqid = seqid;
- p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
p->arg.stateid = &lsp->ls_stateid;
p->lsp = lsp;
atomic_inc(&lsp->ls_count);
@@ -4054,7 +3978,6 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
p->arg.lock_owner.id = lsp->ls_id.id;
p->res.lock_seqid = p->arg.lock_seqid;
- p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
p->lsp = lsp;
p->server = server;
atomic_inc(&lsp->ls_count);
@@ -4241,7 +4164,7 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
return 0;
err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM);
- if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED)
+ if (err != -NFS4ERR_DELAY)
break;
nfs4_handle_exception(server, err, &exception);
} while (exception.retry);
@@ -4266,7 +4189,6 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
goto out;
case -NFS4ERR_GRACE:
case -NFS4ERR_DELAY:
- case -EKEYEXPIRED:
nfs4_handle_exception(server, err, &exception);
err = 0;
}
@@ -4412,13 +4334,21 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
nfs4_state_mark_reclaim_nograce(server->nfs_client, state);
err = 0;
goto out;
+ case -EKEYEXPIRED:
+ /*
+ * User RPCSEC_GSS context has expired.
+ * We cannot recover this stateid now, so
+ * skip it and allow recovery thread to
+ * proceed.
+ */
+ err = 0;
+ goto out;
case -ENOMEM:
case -NFS4ERR_DENIED:
/* kill_proc(fl->fl_pid, SIGLOST, 1); */
err = 0;
goto out;
case -NFS4ERR_DELAY:
- case -EKEYEXPIRED:
break;
}
err = nfs4_handle_exception(server, err, &exception);
@@ -4647,7 +4577,6 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
switch (task->tk_status) {
case -NFS4ERR_DELAY:
case -NFS4ERR_GRACE:
- case -EKEYEXPIRED:
dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status);
rpc_delay(task, NFS4_POLL_RETRY_MIN);
task->tk_status = 0;
@@ -4687,7 +4616,6 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
};
int status;
- res.lr_seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
dprintk("--> %s\n", __func__);
task = rpc_run_task(&task_setup);
@@ -4914,49 +4842,56 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args)
args->bc_attrs.max_reqs);
}
-static int _verify_channel_attr(char *chan, char *attr_name, u32 sent, u32 rcvd)
+static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session)
{
- if (rcvd <= sent)
- return 0;
- printk(KERN_WARNING "%s: Session INVALID: %s channel %s increased. "
- "sent=%u rcvd=%u\n", __func__, chan, attr_name, sent, rcvd);
- return -EINVAL;
+ struct nfs4_channel_attrs *sent = &args->fc_attrs;
+ struct nfs4_channel_attrs *rcvd = &session->fc_attrs;
+
+ if (rcvd->headerpadsz > sent->headerpadsz)
+ return -EINVAL;
+ if (rcvd->max_resp_sz > sent->max_resp_sz)
+ return -EINVAL;
+ /*
+ * Our requested max_ops is the minimum we need; we're not
+ * prepared to break up compounds into smaller pieces than that.
+ * So, no point even trying to continue if the server won't
+ * cooperate:
+ */
+ if (rcvd->max_ops < sent->max_ops)
+ return -EINVAL;
+ if (rcvd->max_reqs == 0)
+ return -EINVAL;
+ return 0;
}
-#define _verify_fore_channel_attr(_name_) \
- _verify_channel_attr("fore", #_name_, \
- args->fc_attrs._name_, \
- session->fc_attrs._name_)
+static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session)
+{
+ struct nfs4_channel_attrs *sent = &args->bc_attrs;
+ struct nfs4_channel_attrs *rcvd = &session->bc_attrs;
-#define _verify_back_channel_attr(_name_) \
- _verify_channel_attr("back", #_name_, \
- args->bc_attrs._name_, \
- session->bc_attrs._name_)
+ if (rcvd->max_rqst_sz > sent->max_rqst_sz)
+ return -EINVAL;
+ if (rcvd->max_resp_sz < sent->max_resp_sz)
+ return -EINVAL;
+ if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached)
+ return -EINVAL;
+ /* These would render the backchannel useless: */
+ if (rcvd->max_ops == 0)
+ return -EINVAL;
+ if (rcvd->max_reqs == 0)
+ return -EINVAL;
+ return 0;
+}
-/*
- * The server is not allowed to increase the fore channel header pad size,
- * maximum response size, or maximum number of operations.
- *
- * The back channel attributes are only negotiatied down: We send what the
- * (back channel) server insists upon.
- */
static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args,
struct nfs4_session *session)
{
- int ret = 0;
-
- ret |= _verify_fore_channel_attr(headerpadsz);
- ret |= _verify_fore_channel_attr(max_resp_sz);
- ret |= _verify_fore_channel_attr(max_ops);
-
- ret |= _verify_back_channel_attr(headerpadsz);
- ret |= _verify_back_channel_attr(max_rqst_sz);
- ret |= _verify_back_channel_attr(max_resp_sz);
- ret |= _verify_back_channel_attr(max_resp_sz_cached);
- ret |= _verify_back_channel_attr(max_ops);
- ret |= _verify_back_channel_attr(max_reqs);
+ int ret;
- return ret;
+ ret = nfs4_verify_fore_channel_attrs(args, session);
+ if (ret)
+ return ret;
+ return nfs4_verify_back_channel_attrs(args, session);
}
static int _nfs4_proc_create_session(struct nfs_client *clp)
@@ -5111,7 +5046,6 @@ static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client
{
switch(task->tk_status) {
case -NFS4ERR_DELAY:
- case -EKEYEXPIRED:
rpc_delay(task, NFS4_POLL_RETRY_MAX);
return -EAGAIN;
default:
@@ -5180,12 +5114,11 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_
if (!atomic_inc_not_zero(&clp->cl_count))
return ERR_PTR(-EIO);
- calldata = kmalloc(sizeof(*calldata), GFP_NOFS);
+ calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
if (calldata == NULL) {
nfs_put_client(clp);
return ERR_PTR(-ENOMEM);
}
- calldata->res.sr_slotid = NFS4_MAX_SLOT_TABLE;
msg.rpc_argp = &calldata->args;
msg.rpc_resp = &calldata->res;
calldata->clp = clp;
@@ -5254,7 +5187,6 @@ static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nf
case -NFS4ERR_WRONG_CRED: /* What to do here? */
break;
case -NFS4ERR_DELAY:
- case -EKEYEXPIRED:
rpc_delay(task, NFS4_POLL_RETRY_MAX);
return -EAGAIN;
default:
@@ -5317,7 +5249,6 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp)
goto out;
calldata->clp = clp;
calldata->arg.one_fs = 0;
- calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
msg.rpc_argp = &calldata->arg;
msg.rpc_resp = &calldata->res;
@@ -5333,6 +5264,147 @@ out:
dprintk("<-- %s status=%d\n", __func__, status);
return status;
}
+
+static void
+nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
+{
+ struct nfs4_layoutget *lgp = calldata;
+ struct inode *ino = lgp->args.inode;
+ struct nfs_server *server = NFS_SERVER(ino);
+
+ dprintk("--> %s\n", __func__);
+ if (nfs4_setup_sequence(server, &lgp->args.seq_args,
+ &lgp->res.seq_res, 0, task))
+ return;
+ rpc_call_start(task);
+}
+
+static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
+{
+ struct nfs4_layoutget *lgp = calldata;
+ struct nfs_server *server = NFS_SERVER(lgp->args.inode);
+
+ dprintk("--> %s\n", __func__);
+
+ if (!nfs4_sequence_done(task, &lgp->res.seq_res))
+ return;
+
+ switch (task->tk_status) {
+ case 0:
+ break;
+ case -NFS4ERR_LAYOUTTRYLATER:
+ case -NFS4ERR_RECALLCONFLICT:
+ task->tk_status = -NFS4ERR_DELAY;
+ /* Fall through */
+ default:
+ if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
+ rpc_restart_call_prepare(task);
+ return;
+ }
+ }
+ lgp->status = task->tk_status;
+ dprintk("<-- %s\n", __func__);
+}
+
+static void nfs4_layoutget_release(void *calldata)
+{
+ struct nfs4_layoutget *lgp = calldata;
+
+ dprintk("--> %s\n", __func__);
+ put_layout_hdr(lgp->args.inode);
+ if (lgp->res.layout.buf != NULL)
+ free_page((unsigned long) lgp->res.layout.buf);
+ put_nfs_open_context(lgp->args.ctx);
+ kfree(calldata);
+ dprintk("<-- %s\n", __func__);
+}
+
+static const struct rpc_call_ops nfs4_layoutget_call_ops = {
+ .rpc_call_prepare = nfs4_layoutget_prepare,
+ .rpc_call_done = nfs4_layoutget_done,
+ .rpc_release = nfs4_layoutget_release,
+};
+
+int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
+{
+ struct nfs_server *server = NFS_SERVER(lgp->args.inode);
+ struct rpc_task *task;
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET],
+ .rpc_argp = &lgp->args,
+ .rpc_resp = &lgp->res,
+ };
+ struct rpc_task_setup task_setup_data = {
+ .rpc_client = server->client,
+ .rpc_message = &msg,
+ .callback_ops = &nfs4_layoutget_call_ops,
+ .callback_data = lgp,
+ .flags = RPC_TASK_ASYNC,
+ };
+ int status = 0;
+
+ dprintk("--> %s\n", __func__);
+
+ lgp->res.layout.buf = (void *)__get_free_page(GFP_NOFS);
+ if (lgp->res.layout.buf == NULL) {
+ nfs4_layoutget_release(lgp);
+ return -ENOMEM;
+ }
+
+ lgp->res.seq_res.sr_slot = NULL;
+ task = rpc_run_task(&task_setup_data);
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+ status = nfs4_wait_for_completion_rpc_task(task);
+ if (status != 0)
+ goto out;
+ status = lgp->status;
+ if (status != 0)
+ goto out;
+ status = pnfs_layout_process(lgp);
+out:
+ rpc_put_task(task);
+ dprintk("<-- %s status=%d\n", __func__, status);
+ return status;
+}
+
+static int
+_nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
+{
+ struct nfs4_getdeviceinfo_args args = {
+ .pdev = pdev,
+ };
+ struct nfs4_getdeviceinfo_res res = {
+ .pdev = pdev,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICEINFO],
+ .rpc_argp = &args,
+ .rpc_resp = &res,
+ };
+ int status;
+
+ dprintk("--> %s\n", __func__);
+ status = nfs4_call_sync(server, &msg, &args, &res, 0);
+ dprintk("<-- %s status=%d\n", __func__, status);
+
+ return status;
+}
+
+int nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
+{
+ struct nfs4_exception exception = { };
+ int err;
+
+ do {
+ err = nfs4_handle_exception(server,
+ _nfs4_proc_getdeviceinfo(server, pdev),
+ &exception);
+ } while (exception.retry);
+ return err;
+}
+EXPORT_SYMBOL_GPL(nfs4_proc_getdeviceinfo);
+
#endif /* CONFIG_NFS_V4_1 */
struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
@@ -5443,6 +5515,8 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
.unlink_setup = nfs4_proc_unlink_setup,
.unlink_done = nfs4_proc_unlink_done,
.rename = nfs4_proc_rename,
+ .rename_setup = nfs4_proc_rename_setup,
+ .rename_done = nfs4_proc_rename_done,
.link = nfs4_proc_link,
.symlink = nfs4_proc_symlink,
.mkdir = nfs4_proc_mkdir,
@@ -5463,6 +5537,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
.lock = nfs4_proc_lock,
.clear_acl_cache = nfs4_zap_acl_attr,
.close_context = nfs4_close_context,
+ .open_context = nfs4_atomic_open,
};
/*
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 96524c5dca6b..f575a3126737 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -46,6 +46,7 @@
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/random.h>
+#include <linux/ratelimit.h>
#include <linux/workqueue.h>
#include <linux/bitops.h>
@@ -53,6 +54,7 @@
#include "callback.h"
#include "delegation.h"
#include "internal.h"
+#include "pnfs.h"
#define OPENOWNER_POOL_SIZE 8
@@ -1063,6 +1065,14 @@ restart:
/* Mark the file as being 'closed' */
state->state = 0;
break;
+ case -EKEYEXPIRED:
+ /*
+ * User RPCSEC_GSS context has expired.
+ * We cannot recover this stateid now, so
+ * skip it and allow recovery thread to
+ * proceed.
+ */
+ break;
case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_BAD_STATEID:
@@ -1138,16 +1148,14 @@ static void nfs4_reclaim_complete(struct nfs_client *clp,
(void)ops->reclaim_complete(clp);
}
-static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
+static int nfs4_state_clear_reclaim_reboot(struct nfs_client *clp)
{
struct nfs4_state_owner *sp;
struct rb_node *pos;
struct nfs4_state *state;
if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
- return;
-
- nfs4_reclaim_complete(clp, clp->cl_mvops->reboot_recovery_ops);
+ return 0;
for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
@@ -1161,6 +1169,14 @@ static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
}
nfs_delegation_reap_unclaimed(clp);
+ return 1;
+}
+
+static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
+{
+ if (!nfs4_state_clear_reclaim_reboot(clp))
+ return;
+ nfs4_reclaim_complete(clp, clp->cl_mvops->reboot_recovery_ops);
}
static void nfs_delegation_clear_all(struct nfs_client *clp)
@@ -1175,6 +1191,14 @@ static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
}
+static void nfs4_warn_keyexpired(const char *s)
+{
+ printk_ratelimited(KERN_WARNING "Error: state manager"
+ " encountered RPCSEC_GSS session"
+ " expired against NFSv4 server %s.\n",
+ s);
+}
+
static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
{
switch (error) {
@@ -1187,7 +1211,7 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_LEASE_MOVED:
set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
- nfs4_state_end_reclaim_reboot(clp);
+ nfs4_state_clear_reclaim_reboot(clp);
nfs4_state_start_reclaim_reboot(clp);
break;
case -NFS4ERR_EXPIRED:
@@ -1204,6 +1228,10 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
/* Zero session reset errors */
return 0;
+ case -EKEYEXPIRED:
+ /* Nothing we can do */
+ nfs4_warn_keyexpired(clp->cl_hostname);
+ return 0;
}
return error;
}
@@ -1414,9 +1442,10 @@ static void nfs4_set_lease_expired(struct nfs_client *clp, int status)
case -NFS4ERR_DELAY:
case -NFS4ERR_CLID_INUSE:
case -EAGAIN:
- case -EKEYEXPIRED:
break;
+ case -EKEYEXPIRED:
+ nfs4_warn_keyexpired(clp->cl_hostname);
case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
* in nfs4_exchange_id */
default:
@@ -1447,6 +1476,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
}
clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
+ pnfs_destroy_all_layouts(clp);
}
if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 08ef91291132..f313c4cce7e4 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -52,6 +52,7 @@
#include <linux/nfs_idmap.h>
#include "nfs4_fs.h"
#include "internal.h"
+#include "pnfs.h"
#define NFSDBG_FACILITY NFSDBG_XDR
@@ -310,6 +311,19 @@ static int nfs4_stat_to_errno(int);
XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5)
#define encode_reclaim_complete_maxsz (op_encode_hdr_maxsz + 4)
#define decode_reclaim_complete_maxsz (op_decode_hdr_maxsz + 4)
+#define encode_getdeviceinfo_maxsz (op_encode_hdr_maxsz + 4 + \
+ XDR_QUADLEN(NFS4_DEVICEID4_SIZE))
+#define decode_getdeviceinfo_maxsz (op_decode_hdr_maxsz + \
+ 1 /* layout type */ + \
+ 1 /* opaque devaddr4 length */ + \
+ /* devaddr4 payload is read into page */ \
+ 1 /* notification bitmap length */ + \
+ 1 /* notification bitmap */)
+#define encode_layoutget_maxsz (op_encode_hdr_maxsz + 10 + \
+ encode_stateid_maxsz)
+#define decode_layoutget_maxsz (op_decode_hdr_maxsz + 8 + \
+ decode_stateid_maxsz + \
+ XDR_QUADLEN(PNFS_LAYOUT_MAXSIZE))
#else /* CONFIG_NFS_V4_1 */
#define encode_sequence_maxsz 0
#define decode_sequence_maxsz 0
@@ -699,6 +713,20 @@ static int nfs4_stat_to_errno(int);
#define NFS4_dec_reclaim_complete_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_reclaim_complete_maxsz)
+#define NFS4_enc_getdeviceinfo_sz (compound_encode_hdr_maxsz + \
+ encode_sequence_maxsz +\
+ encode_getdeviceinfo_maxsz)
+#define NFS4_dec_getdeviceinfo_sz (compound_decode_hdr_maxsz + \
+ decode_sequence_maxsz + \
+ decode_getdeviceinfo_maxsz)
+#define NFS4_enc_layoutget_sz (compound_encode_hdr_maxsz + \
+ encode_sequence_maxsz + \
+ encode_putfh_maxsz + \
+ encode_layoutget_maxsz)
+#define NFS4_dec_layoutget_sz (compound_decode_hdr_maxsz + \
+ decode_sequence_maxsz + \
+ decode_putfh_maxsz + \
+ decode_layoutget_maxsz)
const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
compound_encode_hdr_maxsz +
@@ -816,7 +844,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
if (iap->ia_valid & ATTR_MODE)
len += 4;
if (iap->ia_valid & ATTR_UID) {
- owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
+ owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name, IDMAP_NAMESZ);
if (owner_namelen < 0) {
dprintk("nfs: couldn't resolve uid %d to string\n",
iap->ia_uid);
@@ -828,7 +856,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
}
if (iap->ia_valid & ATTR_GID) {
- owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
+ owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group, IDMAP_NAMESZ);
if (owner_grouplen < 0) {
dprintk("nfs: couldn't resolve gid %d to string\n",
iap->ia_gid);
@@ -1385,24 +1413,35 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
{
- uint32_t attrs[2] = {
- FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
- FATTR4_WORD1_MOUNTED_ON_FILEID,
- };
+ uint32_t attrs[2] = {0, 0};
+ uint32_t dircount = readdir->count >> 1;
__be32 *p;
+ if (readdir->plus) {
+ attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
+ FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE;
+ attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER|
+ FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|
+ FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
+ FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
+ dircount >>= 1;
+ }
+ attrs[0] |= FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID;
+ attrs[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID;
+ /* Switch to mounted_on_fileid if the server supports it */
+ if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
+ attrs[0] &= ~FATTR4_WORD0_FILEID;
+ else
+ attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
+
p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
*p++ = cpu_to_be32(OP_READDIR);
p = xdr_encode_hyper(p, readdir->cookie);
p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE);
- *p++ = cpu_to_be32(readdir->count >> 1); /* We're not doing readdirplus */
+ *p++ = cpu_to_be32(dircount);
*p++ = cpu_to_be32(readdir->count);
*p++ = cpu_to_be32(2);
- /* Switch to mounted_on_fileid if the server supports it */
- if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
- attrs[0] &= ~FATTR4_WORD0_FILEID;
- else
- attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
+
*p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]);
*p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
hdr->nops++;
@@ -1726,6 +1765,58 @@ static void encode_sequence(struct xdr_stream *xdr,
#endif /* CONFIG_NFS_V4_1 */
}
+#ifdef CONFIG_NFS_V4_1
+static void
+encode_getdeviceinfo(struct xdr_stream *xdr,
+ const struct nfs4_getdeviceinfo_args *args,
+ struct compound_hdr *hdr)
+{
+ __be32 *p;
+
+ p = reserve_space(xdr, 16 + NFS4_DEVICEID4_SIZE);
+ *p++ = cpu_to_be32(OP_GETDEVICEINFO);
+ p = xdr_encode_opaque_fixed(p, args->pdev->dev_id.data,
+ NFS4_DEVICEID4_SIZE);
+ *p++ = cpu_to_be32(args->pdev->layout_type);
+ *p++ = cpu_to_be32(args->pdev->pglen); /* gdia_maxcount */
+ *p++ = cpu_to_be32(0); /* bitmap length 0 */
+ hdr->nops++;
+ hdr->replen += decode_getdeviceinfo_maxsz;
+}
+
+static void
+encode_layoutget(struct xdr_stream *xdr,
+ const struct nfs4_layoutget_args *args,
+ struct compound_hdr *hdr)
+{
+ nfs4_stateid stateid;
+ __be32 *p;
+
+ p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE);
+ *p++ = cpu_to_be32(OP_LAYOUTGET);
+ *p++ = cpu_to_be32(0); /* Signal layout available */
+ *p++ = cpu_to_be32(args->type);
+ *p++ = cpu_to_be32(args->range.iomode);
+ p = xdr_encode_hyper(p, args->range.offset);
+ p = xdr_encode_hyper(p, args->range.length);
+ p = xdr_encode_hyper(p, args->minlength);
+ pnfs_get_layout_stateid(&stateid, NFS_I(args->inode)->layout,
+ args->ctx->state);
+ p = xdr_encode_opaque_fixed(p, &stateid.data, NFS4_STATEID_SIZE);
+ *p = cpu_to_be32(args->maxcount);
+
+ dprintk("%s: 1st type:0x%x iomode:%d off:%lu len:%lu mc:%d\n",
+ __func__,
+ args->type,
+ args->range.iomode,
+ (unsigned long)args->range.offset,
+ (unsigned long)args->range.length,
+ args->maxcount);
+ hdr->nops++;
+ hdr->replen += decode_layoutget_maxsz;
+}
+#endif /* CONFIG_NFS_V4_1 */
+
/*
* END OF "GENERIC" ENCODE ROUTINES.
*/
@@ -1823,7 +1914,7 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs
/*
* Encode RENAME request
*/
-static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args)
+static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs_renameargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -2543,6 +2634,51 @@ static int nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req, uint32_t *p,
return 0;
}
+/*
+ * Encode GETDEVICEINFO request
+ */
+static int nfs4_xdr_enc_getdeviceinfo(struct rpc_rqst *req, uint32_t *p,
+ struct nfs4_getdeviceinfo_args *args)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+ };
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, req, &hdr);
+ encode_sequence(&xdr, &args->seq_args, &hdr);
+ encode_getdeviceinfo(&xdr, args, &hdr);
+
+ /* set up reply kvec. Subtract notification bitmap max size (2)
+ * so that notification bitmap is put in xdr_buf tail */
+ xdr_inline_pages(&req->rq_rcv_buf, (hdr.replen - 2) << 2,
+ args->pdev->pages, args->pdev->pgbase,
+ args->pdev->pglen);
+
+ encode_nops(&hdr);
+ return 0;
+}
+
+/*
+ * Encode LAYOUTGET request
+ */
+static int nfs4_xdr_enc_layoutget(struct rpc_rqst *req, uint32_t *p,
+ struct nfs4_layoutget_args *args)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+ };
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, req, &hdr);
+ encode_sequence(&xdr, &args->seq_args, &hdr);
+ encode_putfh(&xdr, NFS_FH(args->inode), &hdr);
+ encode_layoutget(&xdr, args, &hdr);
+ encode_nops(&hdr);
+ return 0;
+}
#endif /* CONFIG_NFS_V4_1 */
static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
@@ -2676,7 +2812,10 @@ out_overflow:
static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask)
{
if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) {
- decode_attr_bitmap(xdr, bitmask);
+ int ret;
+ ret = decode_attr_bitmap(xdr, bitmask);
+ if (unlikely(ret < 0))
+ return ret;
bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS;
} else
bitmask[0] = bitmask[1] = 0;
@@ -2848,6 +2987,56 @@ out_overflow:
return -EIO;
}
+static int decode_attr_error(struct xdr_stream *xdr, uint32_t *bitmap)
+{
+ __be32 *p;
+
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_RDATTR_ERROR - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_RDATTR_ERROR)) {
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR;
+ }
+ return 0;
+out_overflow:
+ print_overflow_msg(__func__, xdr);
+ return -EIO;
+}
+
+static int decode_attr_filehandle(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fh *fh)
+{
+ __be32 *p;
+ int len;
+
+ if (fh != NULL)
+ memset(fh, 0, sizeof(*fh));
+
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEHANDLE - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_FILEHANDLE)) {
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ len = be32_to_cpup(p);
+ if (len > NFS4_FHSIZE)
+ return -EIO;
+ p = xdr_inline_decode(xdr, len);
+ if (unlikely(!p))
+ goto out_overflow;
+ if (fh != NULL) {
+ memcpy(fh->data, p, len);
+ fh->size = len;
+ }
+ bitmap[0] &= ~FATTR4_WORD0_FILEHANDLE;
+ }
+ return 0;
+out_overflow:
+ print_overflow_msg(__func__, xdr);
+ return -EIO;
+}
+
static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
__be32 *p;
@@ -3521,6 +3710,24 @@ static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, s
return status;
}
+static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap,
+ struct timespec *time)
+{
+ int status = 0;
+
+ time->tv_sec = 0;
+ time->tv_nsec = 0;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_DELTA - 1U)))
+ return -EIO;
+ if (likely(bitmap[1] & FATTR4_WORD1_TIME_DELTA)) {
+ status = decode_attr_time(xdr, time);
+ bitmap[1] &= ~FATTR4_WORD1_TIME_DELTA;
+ }
+ dprintk("%s: time_delta=%ld %ld\n", __func__, (long)time->tv_sec,
+ (long)time->tv_nsec);
+ return status;
+}
+
static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
{
int status = 0;
@@ -3744,29 +3951,14 @@ xdr_error:
return status;
}
-static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
+static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
+ struct nfs_fattr *fattr, struct nfs_fh *fh,
const struct nfs_server *server, int may_sleep)
{
- __be32 *savep;
- uint32_t attrlen,
- bitmap[2] = {0},
- type;
int status;
umode_t fmode = 0;
uint64_t fileid;
-
- status = decode_op_hdr(xdr, OP_GETATTR);
- if (status < 0)
- goto xdr_error;
-
- status = decode_attr_bitmap(xdr, bitmap);
- if (status < 0)
- goto xdr_error;
-
- status = decode_attr_length(xdr, &attrlen, &savep);
- if (status < 0)
- goto xdr_error;
-
+ uint32_t type;
status = decode_attr_type(xdr, bitmap, &type);
if (status < 0)
@@ -3792,6 +3984,14 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
goto xdr_error;
fattr->valid |= status;
+ status = decode_attr_error(xdr, bitmap);
+ if (status < 0)
+ goto xdr_error;
+
+ status = decode_attr_filehandle(xdr, bitmap, fh);
+ if (status < 0)
+ goto xdr_error;
+
status = decode_attr_fileid(xdr, bitmap, &fattr->fileid);
if (status < 0)
goto xdr_error;
@@ -3862,12 +4062,101 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
fattr->valid |= status;
}
+xdr_error:
+ dprintk("%s: xdr returned %d\n", __func__, -status);
+ return status;
+}
+
+static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr,
+ struct nfs_fh *fh, const struct nfs_server *server, int may_sleep)
+{
+ __be32 *savep;
+ uint32_t attrlen,
+ bitmap[2] = {0};
+ int status;
+
+ status = decode_op_hdr(xdr, OP_GETATTR);
+ if (status < 0)
+ goto xdr_error;
+
+ status = decode_attr_bitmap(xdr, bitmap);
+ if (status < 0)
+ goto xdr_error;
+
+ status = decode_attr_length(xdr, &attrlen, &savep);
+ if (status < 0)
+ goto xdr_error;
+
+ status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server, may_sleep);
+ if (status < 0)
+ goto xdr_error;
+
status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
dprintk("%s: xdr returned %d\n", __func__, -status);
return status;
}
+static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
+ const struct nfs_server *server, int may_sleep)
+{
+ return decode_getfattr_generic(xdr, fattr, NULL, server, may_sleep);
+}
+
+/*
+ * Decode potentially multiple layout types. Currently we only support
+ * one layout driver per file system.
+ */
+static int decode_first_pnfs_layout_type(struct xdr_stream *xdr,
+ uint32_t *layouttype)
+{
+ uint32_t *p;
+ int num;
+
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ num = be32_to_cpup(p);
+
+ /* pNFS is not supported by the underlying file system */
+ if (num == 0) {
+ *layouttype = 0;
+ return 0;
+ }
+ if (num > 1)
+ printk(KERN_INFO "%s: Warning: Multiple pNFS layout drivers "
+ "per filesystem not supported\n", __func__);
+
+ /* Decode and set first layout type, move xdr->p past unused types */
+ p = xdr_inline_decode(xdr, num * 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ *layouttype = be32_to_cpup(p);
+ return 0;
+out_overflow:
+ print_overflow_msg(__func__, xdr);
+ return -EIO;
+}
+
+/*
+ * The type of file system exported.
+ * Note we must ensure that layouttype is set in any non-error case.
+ */
+static int decode_attr_pnfstype(struct xdr_stream *xdr, uint32_t *bitmap,
+ uint32_t *layouttype)
+{
+ int status = 0;
+
+ dprintk("%s: bitmap is %x\n", __func__, bitmap[1]);
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_FS_LAYOUT_TYPES - 1U)))
+ return -EIO;
+ if (bitmap[1] & FATTR4_WORD1_FS_LAYOUT_TYPES) {
+ status = decode_first_pnfs_layout_type(xdr, layouttype);
+ bitmap[1] &= ~FATTR4_WORD1_FS_LAYOUT_TYPES;
+ } else
+ *layouttype = 0;
+ return status;
+}
static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
{
@@ -3894,6 +4183,12 @@ static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0)
goto xdr_error;
fsinfo->wtpref = fsinfo->wtmax;
+ status = decode_attr_time_delta(xdr, bitmap, &fsinfo->time_delta);
+ if (status != 0)
+ goto xdr_error;
+ status = decode_attr_pnfstype(xdr, bitmap, &fsinfo->layouttype);
+ if (status != 0)
+ goto xdr_error;
status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
@@ -3950,13 +4245,13 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
__be32 *p;
uint32_t namelen, type;
- p = xdr_inline_decode(xdr, 32);
+ p = xdr_inline_decode(xdr, 32); /* read 32 bytes */
if (unlikely(!p))
goto out_overflow;
- p = xdr_decode_hyper(p, &offset);
+ p = xdr_decode_hyper(p, &offset); /* read 2 8-byte long words */
p = xdr_decode_hyper(p, &length);
- type = be32_to_cpup(p++);
- if (fl != NULL) {
+ type = be32_to_cpup(p++); /* 4 byte read */
+ if (fl != NULL) { /* manipulate file lock */
fl->fl_start = (loff_t)offset;
fl->fl_end = fl->fl_start + (loff_t)length - 1;
if (length == ~(uint64_t)0)
@@ -3966,9 +4261,9 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
fl->fl_type = F_RDLCK;
fl->fl_pid = 0;
}
- p = xdr_decode_hyper(p, &clientid);
- namelen = be32_to_cpup(p);
- p = xdr_inline_decode(xdr, namelen);
+ p = xdr_decode_hyper(p, &clientid); /* read 8 bytes */
+ namelen = be32_to_cpup(p); /* read 4 bytes */ /* have read all 32 bytes now */
+ p = xdr_inline_decode(xdr, namelen); /* variable size field */
if (likely(p))
return -NFS4ERR_DENIED;
out_overflow:
@@ -4200,12 +4495,9 @@ out_overflow:
static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
{
struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
- struct page *page = *rcvbuf->pages;
struct kvec *iov = rcvbuf->head;
size_t hdrlen;
u32 recvd, pglen = rcvbuf->page_len;
- __be32 *end, *entry, *p, *kaddr;
- unsigned int nr = 0;
int status;
status = decode_op_hdr(xdr, OP_READDIR);
@@ -4225,71 +4517,8 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
pglen = recvd;
xdr_read_pages(xdr, pglen);
- BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
- kaddr = p = kmap_atomic(page, KM_USER0);
- end = p + ((pglen + readdir->pgbase) >> 2);
- entry = p;
-
- /* Make sure the packet actually has a value_follows and EOF entry */
- if ((entry + 1) > end)
- goto short_pkt;
-
- for (; *p++; nr++) {
- u32 len, attrlen, xlen;
- if (end - p < 3)
- goto short_pkt;
- dprintk("cookie = %Lu, ", *((unsigned long long *)p));
- p += 2; /* cookie */
- len = ntohl(*p++); /* filename length */
- if (len > NFS4_MAXNAMLEN) {
- dprintk("NFS: giant filename in readdir (len 0x%x)\n",
- len);
- goto err_unmap;
- }
- xlen = XDR_QUADLEN(len);
- if (end - p < xlen + 1)
- goto short_pkt;
- dprintk("filename = %*s\n", len, (char *)p);
- p += xlen;
- len = ntohl(*p++); /* bitmap length */
- if (end - p < len + 1)
- goto short_pkt;
- p += len;
- attrlen = XDR_QUADLEN(ntohl(*p++));
- if (end - p < attrlen + 2)
- goto short_pkt;
- p += attrlen; /* attributes */
- entry = p;
- }
- /*
- * Apparently some server sends responses that are a valid size, but
- * contain no entries, and have value_follows==0 and EOF==0. For
- * those, just set the EOF marker.
- */
- if (!nr && entry[1] == 0) {
- dprintk("NFS: readdir reply truncated!\n");
- entry[1] = 1;
- }
-out:
- kunmap_atomic(kaddr, KM_USER0);
+
return 0;
-short_pkt:
- /*
- * When we get a short packet there are 2 possibilities. We can
- * return an error, or fix up the response to look like a valid
- * response and return what we have so far. If there are no
- * entries and the packet was short, then return -EIO. If there
- * are valid entries in the response, return them and pretend that
- * the call was successful, but incomplete. The caller can retry the
- * readdir starting at the last cookie.
- */
- dprintk("%s: short packet at entry %d\n", __func__, nr);
- entry[0] = entry[1] = 0;
- if (nr)
- goto out;
-err_unmap:
- kunmap_atomic(kaddr, KM_USER0);
- return -errno_NFSERR_IO;
}
static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
@@ -4299,7 +4528,6 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
size_t hdrlen;
u32 len, recvd;
__be32 *p;
- char *kaddr;
int status;
status = decode_op_hdr(xdr, OP_READLINK);
@@ -4330,9 +4558,7 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
* and and null-terminate the text (the VFS expects
* null-termination).
*/
- kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
- kaddr[len+rcvbuf->page_base] = '\0';
- kunmap_atomic(kaddr, KM_USER0);
+ xdr_terminate_string(rcvbuf, len);
return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
@@ -4668,7 +4894,6 @@ static int decode_sequence(struct xdr_stream *xdr,
struct rpc_rqst *rqstp)
{
#if defined(CONFIG_NFS_V4_1)
- struct nfs4_slot *slot;
struct nfs4_sessionid id;
u32 dummy;
int status;
@@ -4700,15 +4925,14 @@ static int decode_sequence(struct xdr_stream *xdr,
goto out_overflow;
/* seqid */
- slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid];
dummy = be32_to_cpup(p++);
- if (dummy != slot->seq_nr) {
+ if (dummy != res->sr_slot->seq_nr) {
dprintk("%s Invalid sequence number\n", __func__);
goto out_err;
}
/* slot id */
dummy = be32_to_cpup(p++);
- if (dummy != res->sr_slotid) {
+ if (dummy != res->sr_slot - res->sr_session->fc_slot_table.slots) {
dprintk("%s Invalid slot id\n", __func__);
goto out_err;
}
@@ -4731,6 +4955,134 @@ out_overflow:
#endif /* CONFIG_NFS_V4_1 */
}
+#if defined(CONFIG_NFS_V4_1)
+
+static int decode_getdeviceinfo(struct xdr_stream *xdr,
+ struct pnfs_device *pdev)
+{
+ __be32 *p;
+ uint32_t len, type;
+ int status;
+
+ status = decode_op_hdr(xdr, OP_GETDEVICEINFO);
+ if (status) {
+ if (status == -ETOOSMALL) {
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ pdev->mincount = be32_to_cpup(p);
+ dprintk("%s: Min count too small. mincnt = %u\n",
+ __func__, pdev->mincount);
+ }
+ return status;
+ }
+
+ p = xdr_inline_decode(xdr, 8);
+ if (unlikely(!p))
+ goto out_overflow;
+ type = be32_to_cpup(p++);
+ if (type != pdev->layout_type) {
+ dprintk("%s: layout mismatch req: %u pdev: %u\n",
+ __func__, pdev->layout_type, type);
+ return -EINVAL;
+ }
+ /*
+ * Get the length of the opaque device_addr4. xdr_read_pages places
+ * the opaque device_addr4 in the xdr_buf->pages (pnfs_device->pages)
+ * and places the remaining xdr data in xdr_buf->tail
+ */
+ pdev->mincount = be32_to_cpup(p);
+ xdr_read_pages(xdr, pdev->mincount); /* include space for the length */
+
+ /* Parse notification bitmap, verifying that it is zero. */
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ len = be32_to_cpup(p);
+ if (len) {
+ int i;
+
+ p = xdr_inline_decode(xdr, 4 * len);
+ if (unlikely(!p))
+ goto out_overflow;
+ for (i = 0; i < len; i++, p++) {
+ if (be32_to_cpup(p)) {
+ dprintk("%s: notifications not supported\n",
+ __func__);
+ return -EIO;
+ }
+ }
+ }
+ return 0;
+out_overflow:
+ print_overflow_msg(__func__, xdr);
+ return -EIO;
+}
+
+static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
+ struct nfs4_layoutget_res *res)
+{
+ __be32 *p;
+ int status;
+ u32 layout_count;
+
+ status = decode_op_hdr(xdr, OP_LAYOUTGET);
+ if (status)
+ return status;
+ p = xdr_inline_decode(xdr, 8 + NFS4_STATEID_SIZE);
+ if (unlikely(!p))
+ goto out_overflow;
+ res->return_on_close = be32_to_cpup(p++);
+ p = xdr_decode_opaque_fixed(p, res->stateid.data, NFS4_STATEID_SIZE);
+ layout_count = be32_to_cpup(p);
+ if (!layout_count) {
+ dprintk("%s: server responded with empty layout array\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ p = xdr_inline_decode(xdr, 24);
+ if (unlikely(!p))
+ goto out_overflow;
+ p = xdr_decode_hyper(p, &res->range.offset);
+ p = xdr_decode_hyper(p, &res->range.length);
+ res->range.iomode = be32_to_cpup(p++);
+ res->type = be32_to_cpup(p++);
+
+ status = decode_opaque_inline(xdr, &res->layout.len, (char **)&p);
+ if (unlikely(status))
+ return status;
+
+ dprintk("%s roff:%lu rlen:%lu riomode:%d, lo_type:0x%x, lo.len:%d\n",
+ __func__,
+ (unsigned long)res->range.offset,
+ (unsigned long)res->range.length,
+ res->range.iomode,
+ res->type,
+ res->layout.len);
+
+ /* nfs4_proc_layoutget allocated a single page */
+ if (res->layout.len > PAGE_SIZE)
+ return -ENOMEM;
+ memcpy(res->layout.buf, p, res->layout.len);
+
+ if (layout_count > 1) {
+ /* We only handle a length one array at the moment. Any
+ * further entries are just ignored. Note that this means
+ * the client may see a response that is less than the
+ * minimum it requested.
+ */
+ dprintk("%s: server responded with %d layouts, dropping tail\n",
+ __func__, layout_count);
+ }
+
+ return 0;
+out_overflow:
+ print_overflow_msg(__func__, xdr);
+ return -EIO;
+}
+#endif /* CONFIG_NFS_V4_1 */
+
/*
* END OF "GENERIC" DECODE ROUTINES.
*/
@@ -4873,7 +5225,7 @@ out:
/*
* Decode RENAME response
*/
-static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res)
+static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs_renameres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -5758,25 +6110,84 @@ static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp, uint32_t *p,
status = decode_reclaim_complete(&xdr, (void *)NULL);
return status;
}
+
+/*
+ * Decode GETDEVINFO response
+ */
+static int nfs4_xdr_dec_getdeviceinfo(struct rpc_rqst *rqstp, uint32_t *p,
+ struct nfs4_getdeviceinfo_res *res)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ status = decode_compound_hdr(&xdr, &hdr);
+ if (status != 0)
+ goto out;
+ status = decode_sequence(&xdr, &res->seq_res, rqstp);
+ if (status != 0)
+ goto out;
+ status = decode_getdeviceinfo(&xdr, res->pdev);
+out:
+ return status;
+}
+
+/*
+ * Decode LAYOUTGET response
+ */
+static int nfs4_xdr_dec_layoutget(struct rpc_rqst *rqstp, uint32_t *p,
+ struct nfs4_layoutget_res *res)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ status = decode_compound_hdr(&xdr, &hdr);
+ if (status)
+ goto out;
+ status = decode_sequence(&xdr, &res->seq_res, rqstp);
+ if (status)
+ goto out;
+ status = decode_putfh(&xdr);
+ if (status)
+ goto out;
+ status = decode_layoutget(&xdr, rqstp, res);
+out:
+ return status;
+}
#endif /* CONFIG_NFS_V4_1 */
-__be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
+__be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
+ struct nfs_server *server, int plus)
{
uint32_t bitmap[2] = {0};
uint32_t len;
-
- if (!*p++) {
- if (!*p)
+ __be32 *p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ if (!ntohl(*p++)) {
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ if (!ntohl(*p++))
return ERR_PTR(-EAGAIN);
entry->eof = 1;
return ERR_PTR(-EBADCOOKIE);
}
+ p = xdr_inline_decode(xdr, 12);
+ if (unlikely(!p))
+ goto out_overflow;
entry->prev_cookie = entry->cookie;
p = xdr_decode_hyper(p, &entry->cookie);
entry->len = ntohl(*p++);
+
+ p = xdr_inline_decode(xdr, entry->len);
+ if (unlikely(!p))
+ goto out_overflow;
entry->name = (const char *) p;
- p += XDR_QUADLEN(entry->len);
/*
* In case the server doesn't return an inode number,
@@ -5784,32 +6195,33 @@ __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
* since glibc seems to choke on it...)
*/
entry->ino = 1;
+ entry->fattr->valid = 0;
- len = ntohl(*p++); /* bitmap length */
- if (len-- > 0) {
- bitmap[0] = ntohl(*p++);
- if (len-- > 0) {
- bitmap[1] = ntohl(*p++);
- p += len;
- }
- }
- len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */
- if (len > 0) {
- if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) {
- bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR;
- /* Ignore the return value of rdattr_error for now */
- p++;
- len--;
- }
- if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID)
- xdr_decode_hyper(p, &entry->ino);
- else if (bitmap[0] == FATTR4_WORD0_FILEID)
- xdr_decode_hyper(p, &entry->ino);
- p += len;
- }
+ if (decode_attr_bitmap(xdr, bitmap) < 0)
+ goto out_overflow;
+
+ if (decode_attr_length(xdr, &len, &p) < 0)
+ goto out_overflow;
+
+ if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, server, 1) < 0)
+ goto out_overflow;
+ if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID)
+ entry->ino = entry->fattr->fileid;
+
+ if (verify_attr_len(xdr, p, len) < 0)
+ goto out_overflow;
+
+ p = xdr_inline_peek(xdr, 8);
+ if (p != NULL)
+ entry->eof = !p[0] && p[1];
+ else
+ entry->eof = 0;
- entry->eof = !p[0] && p[1];
return p;
+
+out_overflow:
+ print_overflow_msg(__func__, xdr);
+ return ERR_PTR(-EIO);
}
/*
@@ -5936,6 +6348,8 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(SEQUENCE, enc_sequence, dec_sequence),
PROC(GET_LEASE_TIME, enc_get_lease_time, dec_get_lease_time),
PROC(RECLAIM_COMPLETE, enc_reclaim_complete, dec_reclaim_complete),
+ PROC(GETDEVICEINFO, enc_getdeviceinfo, dec_getdeviceinfo),
+ PROC(LAYOUTGET, enc_layoutget, dec_layoutget),
#endif /* CONFIG_NFS_V4_1 */
};
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index df101d9f546a..903908a20023 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -3,9 +3,10 @@
*
* Allow an NFS filesystem to be mounted as root. The way this works is:
* (1) Use the IP autoconfig mechanism to set local IP addresses and routes.
- * (2) Handle RPC negotiation with the system which replied to RARP or
- * was reported as a boot server by BOOTP or manually.
- * (3) The actual mounting is done later, when init() is running.
+ * (2) Construct the device string and the options string using DHCP
+ * option 17 and/or kernel command line options.
+ * (3) When mount_root() sets up the root file system, pass these strings
+ * to the NFS client's regular mount interface via sys_mount().
*
*
* Changes:
@@ -65,470 +66,245 @@
* Hua Qin : Support for mounting root file system via
* NFS over TCP.
* Fabian Frederick: Option parser rebuilt (using parser lib)
-*/
+ * Chuck Lever : Use super.c's text-based mount option parsing
+ * Chuck Lever : Add "nfsrootdebug".
+ */
#include <linux/types.h>
#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/time.h>
-#include <linux/fs.h>
#include <linux/init.h>
-#include <linux/sunrpc/clnt.h>
-#include <linux/sunrpc/xprtsock.h>
#include <linux/nfs.h>
#include <linux/nfs_fs.h>
-#include <linux/nfs_mount.h>
-#include <linux/in.h>
-#include <linux/major.h>
#include <linux/utsname.h>
-#include <linux/inet.h>
#include <linux/root_dev.h>
#include <net/ipconfig.h>
-#include <linux/parser.h>
#include "internal.h"
-/* Define this to allow debugging output */
-#undef NFSROOT_DEBUG
#define NFSDBG_FACILITY NFSDBG_ROOT
-/* Default port to use if server is not running a portmapper */
-#define NFS_MNT_PORT 627
-
/* Default path we try to mount. "%s" gets replaced by our IP address */
#define NFS_ROOT "/tftpboot/%s"
/* Parameters passed from the kernel command line */
-static char nfs_root_name[256] __initdata = "";
+static char nfs_root_parms[256] __initdata = "";
+
+/* Text-based mount options passed to super.c */
+static char nfs_root_options[256] __initdata = "";
/* Address of NFS server */
-static __be32 servaddr __initdata = 0;
+static __be32 servaddr __initdata = htonl(INADDR_NONE);
/* Name of directory to mount */
-static char nfs_export_path[NFS_MAXPATHLEN + 1] __initdata = { 0, };
-
-/* NFS-related data */
-static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */
-static int nfs_port __initdata = 0; /* Port to connect to for NFS */
-static int mount_port __initdata = 0; /* Mount daemon port number */
-
-
-/***************************************************************************
-
- Parsing of options
-
- ***************************************************************************/
-
-enum {
- /* Options that take integer arguments */
- Opt_port, Opt_rsize, Opt_wsize, Opt_timeo, Opt_retrans, Opt_acregmin,
- Opt_acregmax, Opt_acdirmin, Opt_acdirmax,
- /* Options that take no arguments */
- Opt_soft, Opt_hard, Opt_intr,
- Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac,
- Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp,
- Opt_acl, Opt_noacl,
- /* Error token */
- Opt_err
-};
-
-static const match_table_t tokens __initconst = {
- {Opt_port, "port=%u"},
- {Opt_rsize, "rsize=%u"},
- {Opt_wsize, "wsize=%u"},
- {Opt_timeo, "timeo=%u"},
- {Opt_retrans, "retrans=%u"},
- {Opt_acregmin, "acregmin=%u"},
- {Opt_acregmax, "acregmax=%u"},
- {Opt_acdirmin, "acdirmin=%u"},
- {Opt_acdirmax, "acdirmax=%u"},
- {Opt_soft, "soft"},
- {Opt_hard, "hard"},
- {Opt_intr, "intr"},
- {Opt_nointr, "nointr"},
- {Opt_posix, "posix"},
- {Opt_noposix, "noposix"},
- {Opt_cto, "cto"},
- {Opt_nocto, "nocto"},
- {Opt_ac, "ac"},
- {Opt_noac, "noac"},
- {Opt_lock, "lock"},
- {Opt_nolock, "nolock"},
- {Opt_v2, "nfsvers=2"},
- {Opt_v2, "v2"},
- {Opt_v3, "nfsvers=3"},
- {Opt_v3, "v3"},
- {Opt_udp, "proto=udp"},
- {Opt_udp, "udp"},
- {Opt_tcp, "proto=tcp"},
- {Opt_tcp, "tcp"},
- {Opt_acl, "acl"},
- {Opt_noacl, "noacl"},
- {Opt_err, NULL}
-
-};
+static char nfs_export_path[NFS_MAXPATHLEN + 1] __initdata = "";
+/* server:export path string passed to super.c */
+static char nfs_root_device[NFS_MAXPATHLEN + 1] __initdata = "";
+
+#ifdef RPC_DEBUG
/*
- * Parse option string.
+ * When the "nfsrootdebug" kernel command line option is specified,
+ * enable debugging messages for NFSROOT.
*/
-
-static int __init root_nfs_parse(char *name, char *buf)
+static int __init nfs_root_debug(char *__unused)
{
-
- char *p;
- substring_t args[MAX_OPT_ARGS];
- int option;
-
- if (!name)
- return 1;
-
- /* Set the NFS remote path */
- p = strsep(&name, ",");
- if (p[0] != '\0' && strcmp(p, "default") != 0)
- strlcpy(buf, p, NFS_MAXPATHLEN);
-
- while ((p = strsep (&name, ",")) != NULL) {
- int token;
- if (!*p)
- continue;
- token = match_token(p, tokens, args);
-
- /* %u tokens only. Beware if you add new tokens! */
- if (token < Opt_soft && match_int(&args[0], &option))
- return 0;
- switch (token) {
- case Opt_port:
- nfs_port = option;
- break;
- case Opt_rsize:
- nfs_data.rsize = option;
- break;
- case Opt_wsize:
- nfs_data.wsize = option;
- break;
- case Opt_timeo:
- nfs_data.timeo = option;
- break;
- case Opt_retrans:
- nfs_data.retrans = option;
- break;
- case Opt_acregmin:
- nfs_data.acregmin = option;
- break;
- case Opt_acregmax:
- nfs_data.acregmax = option;
- break;
- case Opt_acdirmin:
- nfs_data.acdirmin = option;
- break;
- case Opt_acdirmax:
- nfs_data.acdirmax = option;
- break;
- case Opt_soft:
- nfs_data.flags |= NFS_MOUNT_SOFT;
- break;
- case Opt_hard:
- nfs_data.flags &= ~NFS_MOUNT_SOFT;
- break;
- case Opt_intr:
- case Opt_nointr:
- break;
- case Opt_posix:
- nfs_data.flags |= NFS_MOUNT_POSIX;
- break;
- case Opt_noposix:
- nfs_data.flags &= ~NFS_MOUNT_POSIX;
- break;
- case Opt_cto:
- nfs_data.flags &= ~NFS_MOUNT_NOCTO;
- break;
- case Opt_nocto:
- nfs_data.flags |= NFS_MOUNT_NOCTO;
- break;
- case Opt_ac:
- nfs_data.flags &= ~NFS_MOUNT_NOAC;
- break;
- case Opt_noac:
- nfs_data.flags |= NFS_MOUNT_NOAC;
- break;
- case Opt_lock:
- nfs_data.flags &= ~NFS_MOUNT_NONLM;
- break;
- case Opt_nolock:
- nfs_data.flags |= NFS_MOUNT_NONLM;
- break;
- case Opt_v2:
- nfs_data.flags &= ~NFS_MOUNT_VER3;
- break;
- case Opt_v3:
- nfs_data.flags |= NFS_MOUNT_VER3;
- break;
- case Opt_udp:
- nfs_data.flags &= ~NFS_MOUNT_TCP;
- break;
- case Opt_tcp:
- nfs_data.flags |= NFS_MOUNT_TCP;
- break;
- case Opt_acl:
- nfs_data.flags &= ~NFS_MOUNT_NOACL;
- break;
- case Opt_noacl:
- nfs_data.flags |= NFS_MOUNT_NOACL;
- break;
- default:
- printk(KERN_WARNING "Root-NFS: unknown "
- "option: %s\n", p);
- return 0;
- }
- }
-
+ nfs_debug |= NFSDBG_ROOT | NFSDBG_MOUNT;
return 1;
}
+__setup("nfsrootdebug", nfs_root_debug);
+#endif
+
/*
- * Prepare the NFS data structure and parse all options.
+ * Parse NFS server and directory information passed on the kernel
+ * command line.
+ *
+ * nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>]
+ *
+ * If there is a "%s" token in the <root-dir> string, it is replaced
+ * by the ASCII-representation of the client's IP address.
*/
-static int __init root_nfs_name(char *name)
+static int __init nfs_root_setup(char *line)
{
- static char buf[NFS_MAXPATHLEN] __initdata;
- char *cp;
-
- /* Set some default values */
- memset(&nfs_data, 0, sizeof(nfs_data));
- nfs_port = -1;
- nfs_data.version = NFS_MOUNT_VERSION;
- nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */
- nfs_data.rsize = NFS_DEF_FILE_IO_SIZE;
- nfs_data.wsize = NFS_DEF_FILE_IO_SIZE;
- nfs_data.acregmin = NFS_DEF_ACREGMIN;
- nfs_data.acregmax = NFS_DEF_ACREGMAX;
- nfs_data.acdirmin = NFS_DEF_ACDIRMIN;
- nfs_data.acdirmax = NFS_DEF_ACDIRMAX;
- strcpy(buf, NFS_ROOT);
-
- /* Process options received from the remote server */
- root_nfs_parse(root_server_path, buf);
-
- /* Override them by options set on kernel command-line */
- root_nfs_parse(name, buf);
-
- cp = utsname()->nodename;
- if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) {
- printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n");
- return -1;
+ ROOT_DEV = Root_NFS;
+
+ if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) {
+ strlcpy(nfs_root_parms, line, sizeof(nfs_root_parms));
+ } else {
+ size_t n = strlen(line) + sizeof(NFS_ROOT) - 1;
+ if (n >= sizeof(nfs_root_parms))
+ line[sizeof(nfs_root_parms) - sizeof(NFS_ROOT) - 2] = '\0';
+ sprintf(nfs_root_parms, NFS_ROOT, line);
}
- sprintf(nfs_export_path, buf, cp);
+
+ /*
+ * Extract the IP address of the NFS server containing our
+ * root file system, if one was specified.
+ *
+ * Note: root_nfs_parse_addr() removes the server-ip from
+ * nfs_root_parms, if it exists.
+ */
+ root_server_addr = root_nfs_parse_addr(nfs_root_parms);
return 1;
}
+__setup("nfsroot=", nfs_root_setup);
-/*
- * Get NFS server address.
- */
-static int __init root_nfs_addr(void)
+static int __init root_nfs_copy(char *dest, const char *src,
+ const size_t destlen)
{
- if ((servaddr = root_server_addr) == htonl(INADDR_NONE)) {
- printk(KERN_ERR "Root-NFS: No NFS server available, giving up.\n");
+ if (strlcpy(dest, src, destlen) > destlen)
return -1;
- }
+ return 0;
+}
- snprintf(nfs_data.hostname, sizeof(nfs_data.hostname),
- "%pI4", &servaddr);
+static int __init root_nfs_cat(char *dest, const char *src,
+ const size_t destlen)
+{
+ if (strlcat(dest, src, destlen) > destlen)
+ return -1;
return 0;
}
/*
- * Tell the user what's going on.
+ * Parse out root export path and mount options from
+ * passed-in string @incoming.
+ *
+ * Copy the export path into @exppath.
*/
-#ifdef NFSROOT_DEBUG
-static void __init root_nfs_print(void)
+static int __init root_nfs_parse_options(char *incoming, char *exppath,
+ const size_t exppathlen)
{
- printk(KERN_NOTICE "Root-NFS: Mounting %s on server %s as root\n",
- nfs_export_path, nfs_data.hostname);
- printk(KERN_NOTICE "Root-NFS: rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
- nfs_data.rsize, nfs_data.wsize, nfs_data.timeo, nfs_data.retrans);
- printk(KERN_NOTICE "Root-NFS: acreg (min,max) = (%d,%d), acdir (min,max) = (%d,%d)\n",
- nfs_data.acregmin, nfs_data.acregmax,
- nfs_data.acdirmin, nfs_data.acdirmax);
- printk(KERN_NOTICE "Root-NFS: nfsd port = %d, mountd port = %d, flags = %08x\n",
- nfs_port, mount_port, nfs_data.flags);
-}
-#endif
-
+ char *p;
-static int __init root_nfs_init(void)
-{
-#ifdef NFSROOT_DEBUG
- nfs_debug |= NFSDBG_ROOT;
-#endif
+ /*
+ * Set the NFS remote path
+ */
+ p = strsep(&incoming, ",");
+ if (*p != '\0' && strcmp(p, "default") != 0)
+ if (root_nfs_copy(exppath, p, exppathlen))
+ return -1;
/*
- * Decode the root directory path name and NFS options from
- * the kernel command line. This has to go here in order to
- * be able to use the client IP address for the remote root
- * directory (necessary for pure RARP booting).
+ * @incoming now points to the rest of the string; if it
+ * contains something, append it to our root options buffer
*/
- if (root_nfs_name(nfs_root_name) < 0 ||
- root_nfs_addr() < 0)
- return -1;
+ if (incoming != NULL && *incoming != '\0')
+ if (root_nfs_cat(nfs_root_options, incoming,
+ sizeof(nfs_root_options)))
+ return -1;
-#ifdef NFSROOT_DEBUG
- root_nfs_print();
-#endif
+ /*
+ * Possibly prepare for more options to be appended
+ */
+ if (nfs_root_options[0] != '\0' &&
+ nfs_root_options[strlen(nfs_root_options)] != ',')
+ if (root_nfs_cat(nfs_root_options, ",",
+ sizeof(nfs_root_options)))
+ return -1;
return 0;
}
-
/*
- * Parse NFS server and directory information passed on the kernel
- * command line.
+ * Decode the export directory path name and NFS options from
+ * the kernel command line. This has to be done late in order to
+ * use a dynamically acquired client IP address for the remote
+ * root directory path.
+ *
+ * Returns zero if successful; otherwise -1 is returned.
*/
-static int __init nfs_root_setup(char *line)
+static int __init root_nfs_data(char *cmdline)
{
- ROOT_DEV = Root_NFS;
- if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) {
- strlcpy(nfs_root_name, line, sizeof(nfs_root_name));
- } else {
- int n = strlen(line) + sizeof(NFS_ROOT) - 1;
- if (n >= sizeof(nfs_root_name))
- line[sizeof(nfs_root_name) - sizeof(NFS_ROOT) - 2] = '\0';
- sprintf(nfs_root_name, NFS_ROOT, line);
+ char addr_option[sizeof("nolock,addr=") + INET_ADDRSTRLEN + 1];
+ int len, retval = -1;
+ char *tmp = NULL;
+ const size_t tmplen = sizeof(nfs_export_path);
+
+ tmp = kzalloc(tmplen, GFP_KERNEL);
+ if (tmp == NULL)
+ goto out_nomem;
+ strcpy(tmp, NFS_ROOT);
+
+ if (root_server_path[0] != '\0') {
+ dprintk("Root-NFS: DHCPv4 option 17: %s\n",
+ root_server_path);
+ if (root_nfs_parse_options(root_server_path, tmp, tmplen))
+ goto out_optionstoolong;
}
- root_server_addr = root_nfs_parse_addr(nfs_root_name);
- return 1;
-}
-
-__setup("nfsroot=", nfs_root_setup);
-
-/***************************************************************************
- Routines to actually mount the root directory
+ if (cmdline[0] != '\0') {
+ dprintk("Root-NFS: nfsroot=%s\n", cmdline);
+ if (root_nfs_parse_options(cmdline, tmp, tmplen))
+ goto out_optionstoolong;
+ }
- ***************************************************************************/
+ /*
+ * Append mandatory options for nfsroot so they override
+ * what has come before
+ */
+ snprintf(addr_option, sizeof(addr_option), "nolock,addr=%pI4",
+ &servaddr);
+ if (root_nfs_cat(nfs_root_options, addr_option,
+ sizeof(nfs_root_options)))
+ goto out_optionstoolong;
-/*
- * Construct sockaddr_in from address and port number.
- */
-static inline void
-set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port)
-{
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = addr;
- sin->sin_port = port;
-}
+ /*
+ * Set up nfs_root_device. For NFS mounts, this looks like
+ *
+ * server:/path
+ *
+ * At this point, utsname()->nodename contains our local
+ * IP address or hostname, set by ipconfig. If "%s" exists
+ * in tmp, substitute the nodename, then shovel the whole
+ * mess into nfs_root_device.
+ */
+ len = snprintf(nfs_export_path, sizeof(nfs_export_path),
+ tmp, utsname()->nodename);
+ if (len > (int)sizeof(nfs_export_path))
+ goto out_devnametoolong;
+ len = snprintf(nfs_root_device, sizeof(nfs_root_device),
+ "%pI4:%s", &servaddr, nfs_export_path);
+ if (len > (int)sizeof(nfs_root_device))
+ goto out_devnametoolong;
-/*
- * Query server portmapper for the port of a daemon program.
- */
-static int __init root_nfs_getport(int program, int version, int proto)
-{
- struct sockaddr_in sin;
+ retval = 0;
- printk(KERN_NOTICE "Looking up port of RPC %d/%d on %pI4\n",
- program, version, &servaddr);
- set_sockaddr(&sin, servaddr, 0);
- return rpcb_getport_sync(&sin, program, version, proto);
+out:
+ kfree(tmp);
+ return retval;
+out_nomem:
+ printk(KERN_ERR "Root-NFS: could not allocate memory\n");
+ goto out;
+out_optionstoolong:
+ printk(KERN_ERR "Root-NFS: mount options string too long\n");
+ goto out;
+out_devnametoolong:
+ printk(KERN_ERR "Root-NFS: root device name too long.\n");
+ goto out;
}
-
-/*
- * Use portmapper to find mountd and nfsd port numbers if not overriden
- * by the user. Use defaults if portmapper is not available.
- * XXX: Is there any nfs server with no portmapper?
+/**
+ * nfs_root_data - Return prepared 'data' for NFSROOT mount
+ * @root_device: OUT: address of string containing NFSROOT device
+ * @root_data: OUT: address of string containing NFSROOT mount options
+ *
+ * Returns zero and sets @root_device and @root_data if successful,
+ * otherwise -1 is returned.
*/
-static int __init root_nfs_ports(void)
+int __init nfs_root_data(char **root_device, char **root_data)
{
- int port;
- int nfsd_ver, mountd_ver;
- int nfsd_port, mountd_port;
- int proto;
-
- if (nfs_data.flags & NFS_MOUNT_VER3) {
- nfsd_ver = NFS3_VERSION;
- mountd_ver = NFS_MNT3_VERSION;
- nfsd_port = NFS_PORT;
- mountd_port = NFS_MNT_PORT;
- } else {
- nfsd_ver = NFS2_VERSION;
- mountd_ver = NFS_MNT_VERSION;
- nfsd_port = NFS_PORT;
- mountd_port = NFS_MNT_PORT;
- }
-
- proto = (nfs_data.flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
-
- if (nfs_port < 0) {
- if ((port = root_nfs_getport(NFS_PROGRAM, nfsd_ver, proto)) < 0) {
- printk(KERN_ERR "Root-NFS: Unable to get nfsd port "
- "number from server, using default\n");
- port = nfsd_port;
- }
- nfs_port = port;
- dprintk("Root-NFS: Portmapper on server returned %d "
- "as nfsd port\n", port);
+ servaddr = root_server_addr;
+ if (servaddr == htonl(INADDR_NONE)) {
+ printk(KERN_ERR "Root-NFS: no NFS server address\n");
+ return -1;
}
- if ((port = root_nfs_getport(NFS_MNT_PROGRAM, mountd_ver, proto)) < 0) {
- printk(KERN_ERR "Root-NFS: Unable to get mountd port "
- "number from server, using default\n");
- port = mountd_port;
- }
- mount_port = port;
- dprintk("Root-NFS: mountd port is %d\n", port);
+ if (root_nfs_data(nfs_root_parms) < 0)
+ return -1;
+ *root_device = nfs_root_device;
+ *root_data = nfs_root_options;
return 0;
}
-
-
-/*
- * Get a file handle from the server for the directory which is to be
- * mounted.
- */
-static int __init root_nfs_get_handle(void)
-{
- struct sockaddr_in sin;
- unsigned int auth_flav_len = 0;
- struct nfs_mount_request request = {
- .sap = (struct sockaddr *)&sin,
- .salen = sizeof(sin),
- .dirpath = nfs_export_path,
- .version = (nfs_data.flags & NFS_MOUNT_VER3) ?
- NFS_MNT3_VERSION : NFS_MNT_VERSION,
- .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ?
- XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP,
- .auth_flav_len = &auth_flav_len,
- };
- int status = -ENOMEM;
-
- request.fh = nfs_alloc_fhandle();
- if (!request.fh)
- goto out;
- set_sockaddr(&sin, servaddr, htons(mount_port));
- status = nfs_mount(&request);
- if (status < 0)
- printk(KERN_ERR "Root-NFS: Server returned error %d "
- "while mounting %s\n", status, nfs_export_path);
- else {
- nfs_data.root.size = request.fh->size;
- memcpy(&nfs_data.root.data, request.fh->data, request.fh->size);
- }
- nfs_free_fhandle(request.fh);
-out:
- return status;
-}
-
-/*
- * Get the NFS port numbers and file handle, and return the prepared 'data'
- * argument for mount() if everything went OK. Return NULL otherwise.
- */
-void * __init nfs_root_data(void)
-{
- if (root_nfs_init() < 0
- || root_nfs_ports() < 0
- || root_nfs_get_handle() < 0)
- return NULL;
- set_sockaddr((struct sockaddr_in *) &nfs_data.addr, servaddr, htons(nfs_port));
- return (void*)&nfs_data;
-}
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
new file mode 100644
index 000000000000..db773428f95f
--- /dev/null
+++ b/fs/nfs/pnfs.c
@@ -0,0 +1,783 @@
+/*
+ * pNFS functions to call and manage layout drivers.
+ *
+ * Copyright (c) 2002 [year of first publication]
+ * The Regents of the University of Michigan
+ * All Rights Reserved
+ *
+ * Dean Hildebrand <dhildebz@umich.edu>
+ *
+ * Permission is granted to use, copy, create derivative works, and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the University of Michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. If
+ * the above copyright notice or any other identification of the
+ * University of Michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * This software is provided as is, without representation or warranty
+ * of any kind either express or implied, including without limitation
+ * the implied warranties of merchantability, fitness for a particular
+ * purpose, or noninfringement. The Regents of the University of
+ * Michigan shall not be liable for any damages, including special,
+ * indirect, incidental, or consequential damages, with respect to any
+ * claim arising out of or in connection with the use of the software,
+ * even if it has been or is hereafter advised of the possibility of
+ * such damages.
+ */
+
+#include <linux/nfs_fs.h>
+#include "internal.h"
+#include "pnfs.h"
+
+#define NFSDBG_FACILITY NFSDBG_PNFS
+
+/* Locking:
+ *
+ * pnfs_spinlock:
+ * protects pnfs_modules_tbl.
+ */
+static DEFINE_SPINLOCK(pnfs_spinlock);
+
+/*
+ * pnfs_modules_tbl holds all pnfs modules
+ */
+static LIST_HEAD(pnfs_modules_tbl);
+
+/* Return the registered pnfs layout driver module matching given id */
+static struct pnfs_layoutdriver_type *
+find_pnfs_driver_locked(u32 id)
+{
+ struct pnfs_layoutdriver_type *local;
+
+ list_for_each_entry(local, &pnfs_modules_tbl, pnfs_tblid)
+ if (local->id == id)
+ goto out;
+ local = NULL;
+out:
+ dprintk("%s: Searching for id %u, found %p\n", __func__, id, local);
+ return local;
+}
+
+static struct pnfs_layoutdriver_type *
+find_pnfs_driver(u32 id)
+{
+ struct pnfs_layoutdriver_type *local;
+
+ spin_lock(&pnfs_spinlock);
+ local = find_pnfs_driver_locked(id);
+ spin_unlock(&pnfs_spinlock);
+ return local;
+}
+
+void
+unset_pnfs_layoutdriver(struct nfs_server *nfss)
+{
+ if (nfss->pnfs_curr_ld) {
+ nfss->pnfs_curr_ld->clear_layoutdriver(nfss);
+ module_put(nfss->pnfs_curr_ld->owner);
+ }
+ nfss->pnfs_curr_ld = NULL;
+}
+
+/*
+ * Try to set the server's pnfs module to the pnfs layout type specified by id.
+ * Currently only one pNFS layout driver per filesystem is supported.
+ *
+ * @id layout type. Zero (illegal layout type) indicates pNFS not in use.
+ */
+void
+set_pnfs_layoutdriver(struct nfs_server *server, u32 id)
+{
+ struct pnfs_layoutdriver_type *ld_type = NULL;
+
+ if (id == 0)
+ goto out_no_driver;
+ if (!(server->nfs_client->cl_exchange_flags &
+ (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))) {
+ printk(KERN_ERR "%s: id %u cl_exchange_flags 0x%x\n", __func__,
+ id, server->nfs_client->cl_exchange_flags);
+ goto out_no_driver;
+ }
+ ld_type = find_pnfs_driver(id);
+ if (!ld_type) {
+ request_module("%s-%u", LAYOUT_NFSV4_1_MODULE_PREFIX, id);
+ ld_type = find_pnfs_driver(id);
+ if (!ld_type) {
+ dprintk("%s: No pNFS module found for %u.\n",
+ __func__, id);
+ goto out_no_driver;
+ }
+ }
+ if (!try_module_get(ld_type->owner)) {
+ dprintk("%s: Could not grab reference on module\n", __func__);
+ goto out_no_driver;
+ }
+ server->pnfs_curr_ld = ld_type;
+ if (ld_type->set_layoutdriver(server)) {
+ printk(KERN_ERR
+ "%s: Error initializing mount point for layout driver %u.\n",
+ __func__, id);
+ module_put(ld_type->owner);
+ goto out_no_driver;
+ }
+ dprintk("%s: pNFS module for %u set\n", __func__, id);
+ return;
+
+out_no_driver:
+ dprintk("%s: Using NFSv4 I/O\n", __func__);
+ server->pnfs_curr_ld = NULL;
+}
+
+int
+pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *ld_type)
+{
+ int status = -EINVAL;
+ struct pnfs_layoutdriver_type *tmp;
+
+ if (ld_type->id == 0) {
+ printk(KERN_ERR "%s id 0 is reserved\n", __func__);
+ return status;
+ }
+ if (!ld_type->alloc_lseg || !ld_type->free_lseg) {
+ printk(KERN_ERR "%s Layout driver must provide "
+ "alloc_lseg and free_lseg.\n", __func__);
+ return status;
+ }
+
+ spin_lock(&pnfs_spinlock);
+ tmp = find_pnfs_driver_locked(ld_type->id);
+ if (!tmp) {
+ list_add(&ld_type->pnfs_tblid, &pnfs_modules_tbl);
+ status = 0;
+ dprintk("%s Registering id:%u name:%s\n", __func__, ld_type->id,
+ ld_type->name);
+ } else {
+ printk(KERN_ERR "%s Module with id %d already loaded!\n",
+ __func__, ld_type->id);
+ }
+ spin_unlock(&pnfs_spinlock);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(pnfs_register_layoutdriver);
+
+void
+pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *ld_type)
+{
+ dprintk("%s Deregistering id:%u\n", __func__, ld_type->id);
+ spin_lock(&pnfs_spinlock);
+ list_del(&ld_type->pnfs_tblid);
+ spin_unlock(&pnfs_spinlock);
+}
+EXPORT_SYMBOL_GPL(pnfs_unregister_layoutdriver);
+
+/*
+ * pNFS client layout cache
+ */
+
+static void
+get_layout_hdr_locked(struct pnfs_layout_hdr *lo)
+{
+ assert_spin_locked(&lo->inode->i_lock);
+ lo->refcount++;
+}
+
+static void
+put_layout_hdr_locked(struct pnfs_layout_hdr *lo)
+{
+ assert_spin_locked(&lo->inode->i_lock);
+ BUG_ON(lo->refcount == 0);
+
+ lo->refcount--;
+ if (!lo->refcount) {
+ dprintk("%s: freeing layout cache %p\n", __func__, lo);
+ BUG_ON(!list_empty(&lo->layouts));
+ NFS_I(lo->inode)->layout = NULL;
+ kfree(lo);
+ }
+}
+
+void
+put_layout_hdr(struct inode *inode)
+{
+ spin_lock(&inode->i_lock);
+ put_layout_hdr_locked(NFS_I(inode)->layout);
+ spin_unlock(&inode->i_lock);
+}
+
+static void
+init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg)
+{
+ INIT_LIST_HEAD(&lseg->fi_list);
+ kref_init(&lseg->kref);
+ lseg->layout = lo;
+}
+
+/* Called without i_lock held, as the free_lseg call may sleep */
+static void
+destroy_lseg(struct kref *kref)
+{
+ struct pnfs_layout_segment *lseg =
+ container_of(kref, struct pnfs_layout_segment, kref);
+ struct inode *ino = lseg->layout->inode;
+
+ dprintk("--> %s\n", __func__);
+ NFS_SERVER(ino)->pnfs_curr_ld->free_lseg(lseg);
+ /* Matched by get_layout_hdr_locked in pnfs_insert_layout */
+ put_layout_hdr(ino);
+}
+
+static void
+put_lseg(struct pnfs_layout_segment *lseg)
+{
+ if (!lseg)
+ return;
+
+ dprintk("%s: lseg %p ref %d\n", __func__, lseg,
+ atomic_read(&lseg->kref.refcount));
+ kref_put(&lseg->kref, destroy_lseg);
+}
+
+static void
+pnfs_clear_lseg_list(struct pnfs_layout_hdr *lo, struct list_head *tmp_list)
+{
+ struct pnfs_layout_segment *lseg, *next;
+ struct nfs_client *clp;
+
+ dprintk("%s:Begin lo %p\n", __func__, lo);
+
+ assert_spin_locked(&lo->inode->i_lock);
+ list_for_each_entry_safe(lseg, next, &lo->segs, fi_list) {
+ dprintk("%s: freeing lseg %p\n", __func__, lseg);
+ list_move(&lseg->fi_list, tmp_list);
+ }
+ clp = NFS_SERVER(lo->inode)->nfs_client;
+ spin_lock(&clp->cl_lock);
+ /* List does not take a reference, so no need for put here */
+ list_del_init(&lo->layouts);
+ spin_unlock(&clp->cl_lock);
+ write_seqlock(&lo->seqlock);
+ clear_bit(NFS_LAYOUT_STATEID_SET, &lo->state);
+ write_sequnlock(&lo->seqlock);
+
+ dprintk("%s:Return\n", __func__);
+}
+
+static void
+pnfs_free_lseg_list(struct list_head *tmp_list)
+{
+ struct pnfs_layout_segment *lseg;
+
+ while (!list_empty(tmp_list)) {
+ lseg = list_entry(tmp_list->next, struct pnfs_layout_segment,
+ fi_list);
+ dprintk("%s calling put_lseg on %p\n", __func__, lseg);
+ list_del(&lseg->fi_list);
+ put_lseg(lseg);
+ }
+}
+
+void
+pnfs_destroy_layout(struct nfs_inode *nfsi)
+{
+ struct pnfs_layout_hdr *lo;
+ LIST_HEAD(tmp_list);
+
+ spin_lock(&nfsi->vfs_inode.i_lock);
+ lo = nfsi->layout;
+ if (lo) {
+ pnfs_clear_lseg_list(lo, &tmp_list);
+ /* Matched by refcount set to 1 in alloc_init_layout_hdr */
+ put_layout_hdr_locked(lo);
+ }
+ spin_unlock(&nfsi->vfs_inode.i_lock);
+ pnfs_free_lseg_list(&tmp_list);
+}
+
+/*
+ * Called by the state manger to remove all layouts established under an
+ * expired lease.
+ */
+void
+pnfs_destroy_all_layouts(struct nfs_client *clp)
+{
+ struct pnfs_layout_hdr *lo;
+ LIST_HEAD(tmp_list);
+
+ spin_lock(&clp->cl_lock);
+ list_splice_init(&clp->cl_layouts, &tmp_list);
+ spin_unlock(&clp->cl_lock);
+
+ while (!list_empty(&tmp_list)) {
+ lo = list_entry(tmp_list.next, struct pnfs_layout_hdr,
+ layouts);
+ dprintk("%s freeing layout for inode %lu\n", __func__,
+ lo->inode->i_ino);
+ pnfs_destroy_layout(NFS_I(lo->inode));
+ }
+}
+
+/* update lo->stateid with new if is more recent
+ *
+ * lo->stateid could be the open stateid, in which case we just use what given.
+ */
+static void
+pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo,
+ const nfs4_stateid *new)
+{
+ nfs4_stateid *old = &lo->stateid;
+ bool overwrite = false;
+
+ write_seqlock(&lo->seqlock);
+ if (!test_bit(NFS_LAYOUT_STATEID_SET, &lo->state) ||
+ memcmp(old->stateid.other, new->stateid.other, sizeof(new->stateid.other)))
+ overwrite = true;
+ else {
+ u32 oldseq, newseq;
+
+ oldseq = be32_to_cpu(old->stateid.seqid);
+ newseq = be32_to_cpu(new->stateid.seqid);
+ if ((int)(newseq - oldseq) > 0)
+ overwrite = true;
+ }
+ if (overwrite)
+ memcpy(&old->stateid, &new->stateid, sizeof(new->stateid));
+ write_sequnlock(&lo->seqlock);
+}
+
+static void
+pnfs_layout_from_open_stateid(struct pnfs_layout_hdr *lo,
+ struct nfs4_state *state)
+{
+ int seq;
+
+ dprintk("--> %s\n", __func__);
+ write_seqlock(&lo->seqlock);
+ do {
+ seq = read_seqbegin(&state->seqlock);
+ memcpy(lo->stateid.data, state->stateid.data,
+ sizeof(state->stateid.data));
+ } while (read_seqretry(&state->seqlock, seq));
+ set_bit(NFS_LAYOUT_STATEID_SET, &lo->state);
+ write_sequnlock(&lo->seqlock);
+ dprintk("<-- %s\n", __func__);
+}
+
+void
+pnfs_get_layout_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
+ struct nfs4_state *open_state)
+{
+ int seq;
+
+ dprintk("--> %s\n", __func__);
+ do {
+ seq = read_seqbegin(&lo->seqlock);
+ if (!test_bit(NFS_LAYOUT_STATEID_SET, &lo->state)) {
+ /* This will trigger retry of the read */
+ pnfs_layout_from_open_stateid(lo, open_state);
+ } else
+ memcpy(dst->data, lo->stateid.data,
+ sizeof(lo->stateid.data));
+ } while (read_seqretry(&lo->seqlock, seq));
+ dprintk("<-- %s\n", __func__);
+}
+
+/*
+* Get layout from server.
+* for now, assume that whole file layouts are requested.
+* arg->offset: 0
+* arg->length: all ones
+*/
+static struct pnfs_layout_segment *
+send_layoutget(struct pnfs_layout_hdr *lo,
+ struct nfs_open_context *ctx,
+ u32 iomode)
+{
+ struct inode *ino = lo->inode;
+ struct nfs_server *server = NFS_SERVER(ino);
+ struct nfs4_layoutget *lgp;
+ struct pnfs_layout_segment *lseg = NULL;
+
+ dprintk("--> %s\n", __func__);
+
+ BUG_ON(ctx == NULL);
+ lgp = kzalloc(sizeof(*lgp), GFP_KERNEL);
+ if (lgp == NULL) {
+ put_layout_hdr(lo->inode);
+ return NULL;
+ }
+ lgp->args.minlength = NFS4_MAX_UINT64;
+ lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE;
+ lgp->args.range.iomode = iomode;
+ lgp->args.range.offset = 0;
+ lgp->args.range.length = NFS4_MAX_UINT64;
+ lgp->args.type = server->pnfs_curr_ld->id;
+ lgp->args.inode = ino;
+ lgp->args.ctx = get_nfs_open_context(ctx);
+ lgp->lsegpp = &lseg;
+
+ /* Synchronously retrieve layout information from server and
+ * store in lseg.
+ */
+ nfs4_proc_layoutget(lgp);
+ if (!lseg) {
+ /* remember that LAYOUTGET failed and suspend trying */
+ set_bit(lo_fail_bit(iomode), &lo->state);
+ }
+ return lseg;
+}
+
+/*
+ * Compare two layout segments for sorting into layout cache.
+ * We want to preferentially return RW over RO layouts, so ensure those
+ * are seen first.
+ */
+static s64
+cmp_layout(u32 iomode1, u32 iomode2)
+{
+ /* read > read/write */
+ return (int)(iomode2 == IOMODE_READ) - (int)(iomode1 == IOMODE_READ);
+}
+
+static void
+pnfs_insert_layout(struct pnfs_layout_hdr *lo,
+ struct pnfs_layout_segment *lseg)
+{
+ struct pnfs_layout_segment *lp;
+ int found = 0;
+
+ dprintk("%s:Begin\n", __func__);
+
+ assert_spin_locked(&lo->inode->i_lock);
+ if (list_empty(&lo->segs)) {
+ struct nfs_client *clp = NFS_SERVER(lo->inode)->nfs_client;
+
+ spin_lock(&clp->cl_lock);
+ BUG_ON(!list_empty(&lo->layouts));
+ list_add_tail(&lo->layouts, &clp->cl_layouts);
+ spin_unlock(&clp->cl_lock);
+ }
+ list_for_each_entry(lp, &lo->segs, fi_list) {
+ if (cmp_layout(lp->range.iomode, lseg->range.iomode) > 0)
+ continue;
+ list_add_tail(&lseg->fi_list, &lp->fi_list);
+ dprintk("%s: inserted lseg %p "
+ "iomode %d offset %llu length %llu before "
+ "lp %p iomode %d offset %llu length %llu\n",
+ __func__, lseg, lseg->range.iomode,
+ lseg->range.offset, lseg->range.length,
+ lp, lp->range.iomode, lp->range.offset,
+ lp->range.length);
+ found = 1;
+ break;
+ }
+ if (!found) {
+ list_add_tail(&lseg->fi_list, &lo->segs);
+ dprintk("%s: inserted lseg %p "
+ "iomode %d offset %llu length %llu at tail\n",
+ __func__, lseg, lseg->range.iomode,
+ lseg->range.offset, lseg->range.length);
+ }
+ get_layout_hdr_locked(lo);
+
+ dprintk("%s:Return\n", __func__);
+}
+
+static struct pnfs_layout_hdr *
+alloc_init_layout_hdr(struct inode *ino)
+{
+ struct pnfs_layout_hdr *lo;
+
+ lo = kzalloc(sizeof(struct pnfs_layout_hdr), GFP_KERNEL);
+ if (!lo)
+ return NULL;
+ lo->refcount = 1;
+ INIT_LIST_HEAD(&lo->layouts);
+ INIT_LIST_HEAD(&lo->segs);
+ seqlock_init(&lo->seqlock);
+ lo->inode = ino;
+ return lo;
+}
+
+static struct pnfs_layout_hdr *
+pnfs_find_alloc_layout(struct inode *ino)
+{
+ struct nfs_inode *nfsi = NFS_I(ino);
+ struct pnfs_layout_hdr *new = NULL;
+
+ dprintk("%s Begin ino=%p layout=%p\n", __func__, ino, nfsi->layout);
+
+ assert_spin_locked(&ino->i_lock);
+ if (nfsi->layout)
+ return nfsi->layout;
+
+ spin_unlock(&ino->i_lock);
+ new = alloc_init_layout_hdr(ino);
+ spin_lock(&ino->i_lock);
+
+ if (likely(nfsi->layout == NULL)) /* Won the race? */
+ nfsi->layout = new;
+ else
+ kfree(new);
+ return nfsi->layout;
+}
+
+/*
+ * iomode matching rules:
+ * iomode lseg match
+ * ----- ----- -----
+ * ANY READ true
+ * ANY RW true
+ * RW READ false
+ * RW RW true
+ * READ READ true
+ * READ RW true
+ */
+static int
+is_matching_lseg(struct pnfs_layout_segment *lseg, u32 iomode)
+{
+ return (iomode != IOMODE_RW || lseg->range.iomode == IOMODE_RW);
+}
+
+/*
+ * lookup range in layout
+ */
+static struct pnfs_layout_segment *
+pnfs_has_layout(struct pnfs_layout_hdr *lo, u32 iomode)
+{
+ struct pnfs_layout_segment *lseg, *ret = NULL;
+
+ dprintk("%s:Begin\n", __func__);
+
+ assert_spin_locked(&lo->inode->i_lock);
+ list_for_each_entry(lseg, &lo->segs, fi_list) {
+ if (is_matching_lseg(lseg, iomode)) {
+ ret = lseg;
+ break;
+ }
+ if (cmp_layout(iomode, lseg->range.iomode) > 0)
+ break;
+ }
+
+ dprintk("%s:Return lseg %p ref %d\n",
+ __func__, ret, ret ? atomic_read(&ret->kref.refcount) : 0);
+ return ret;
+}
+
+/*
+ * Layout segment is retreived from the server if not cached.
+ * The appropriate layout segment is referenced and returned to the caller.
+ */
+struct pnfs_layout_segment *
+pnfs_update_layout(struct inode *ino,
+ struct nfs_open_context *ctx,
+ enum pnfs_iomode iomode)
+{
+ struct nfs_inode *nfsi = NFS_I(ino);
+ struct pnfs_layout_hdr *lo;
+ struct pnfs_layout_segment *lseg = NULL;
+
+ if (!pnfs_enabled_sb(NFS_SERVER(ino)))
+ return NULL;
+ spin_lock(&ino->i_lock);
+ lo = pnfs_find_alloc_layout(ino);
+ if (lo == NULL) {
+ dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__);
+ goto out_unlock;
+ }
+
+ /* Check to see if the layout for the given range already exists */
+ lseg = pnfs_has_layout(lo, iomode);
+ if (lseg) {
+ dprintk("%s: Using cached lseg %p for iomode %d)\n",
+ __func__, lseg, iomode);
+ goto out_unlock;
+ }
+
+ /* if LAYOUTGET already failed once we don't try again */
+ if (test_bit(lo_fail_bit(iomode), &nfsi->layout->state))
+ goto out_unlock;
+
+ get_layout_hdr_locked(lo); /* Matched in nfs4_layoutget_release */
+ spin_unlock(&ino->i_lock);
+
+ lseg = send_layoutget(lo, ctx, iomode);
+out:
+ dprintk("%s end, state 0x%lx lseg %p\n", __func__,
+ nfsi->layout->state, lseg);
+ return lseg;
+out_unlock:
+ spin_unlock(&ino->i_lock);
+ goto out;
+}
+
+int
+pnfs_layout_process(struct nfs4_layoutget *lgp)
+{
+ struct pnfs_layout_hdr *lo = NFS_I(lgp->args.inode)->layout;
+ struct nfs4_layoutget_res *res = &lgp->res;
+ struct pnfs_layout_segment *lseg;
+ struct inode *ino = lo->inode;
+ int status = 0;
+
+ /* Inject layout blob into I/O device driver */
+ lseg = NFS_SERVER(ino)->pnfs_curr_ld->alloc_lseg(lo, res);
+ if (!lseg || IS_ERR(lseg)) {
+ if (!lseg)
+ status = -ENOMEM;
+ else
+ status = PTR_ERR(lseg);
+ dprintk("%s: Could not allocate layout: error %d\n",
+ __func__, status);
+ goto out;
+ }
+
+ spin_lock(&ino->i_lock);
+ init_lseg(lo, lseg);
+ lseg->range = res->range;
+ *lgp->lsegpp = lseg;
+ pnfs_insert_layout(lo, lseg);
+
+ /* Done processing layoutget. Set the layout stateid */
+ pnfs_set_layout_stateid(lo, &res->stateid);
+ spin_unlock(&ino->i_lock);
+out:
+ return status;
+}
+
+/*
+ * Device ID cache. Currently supports one layout type per struct nfs_client.
+ * Add layout type to the lookup key to expand to support multiple types.
+ */
+int
+pnfs_alloc_init_deviceid_cache(struct nfs_client *clp,
+ void (*free_callback)(struct pnfs_deviceid_node *))
+{
+ struct pnfs_deviceid_cache *c;
+
+ c = kzalloc(sizeof(struct pnfs_deviceid_cache), GFP_KERNEL);
+ if (!c)
+ return -ENOMEM;
+ spin_lock(&clp->cl_lock);
+ if (clp->cl_devid_cache != NULL) {
+ atomic_inc(&clp->cl_devid_cache->dc_ref);
+ dprintk("%s [kref [%d]]\n", __func__,
+ atomic_read(&clp->cl_devid_cache->dc_ref));
+ kfree(c);
+ } else {
+ /* kzalloc initializes hlists */
+ spin_lock_init(&c->dc_lock);
+ atomic_set(&c->dc_ref, 1);
+ c->dc_free_callback = free_callback;
+ clp->cl_devid_cache = c;
+ dprintk("%s [new]\n", __func__);
+ }
+ spin_unlock(&clp->cl_lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pnfs_alloc_init_deviceid_cache);
+
+/*
+ * Called from pnfs_layoutdriver_type->free_lseg
+ * last layout segment reference frees deviceid
+ */
+void
+pnfs_put_deviceid(struct pnfs_deviceid_cache *c,
+ struct pnfs_deviceid_node *devid)
+{
+ struct nfs4_deviceid *id = &devid->de_id;
+ struct pnfs_deviceid_node *d;
+ struct hlist_node *n;
+ long h = nfs4_deviceid_hash(id);
+
+ dprintk("%s [%d]\n", __func__, atomic_read(&devid->de_ref));
+ if (!atomic_dec_and_lock(&devid->de_ref, &c->dc_lock))
+ return;
+
+ hlist_for_each_entry_rcu(d, n, &c->dc_deviceids[h], de_node)
+ if (!memcmp(&d->de_id, id, sizeof(*id))) {
+ hlist_del_rcu(&d->de_node);
+ spin_unlock(&c->dc_lock);
+ synchronize_rcu();
+ c->dc_free_callback(devid);
+ return;
+ }
+ spin_unlock(&c->dc_lock);
+ /* Why wasn't it found in the list? */
+ BUG();
+}
+EXPORT_SYMBOL_GPL(pnfs_put_deviceid);
+
+/* Find and reference a deviceid */
+struct pnfs_deviceid_node *
+pnfs_find_get_deviceid(struct pnfs_deviceid_cache *c, struct nfs4_deviceid *id)
+{
+ struct pnfs_deviceid_node *d;
+ struct hlist_node *n;
+ long hash = nfs4_deviceid_hash(id);
+
+ dprintk("--> %s hash %ld\n", __func__, hash);
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(d, n, &c->dc_deviceids[hash], de_node) {
+ if (!memcmp(&d->de_id, id, sizeof(*id))) {
+ if (!atomic_inc_not_zero(&d->de_ref)) {
+ goto fail;
+ } else {
+ rcu_read_unlock();
+ return d;
+ }
+ }
+ }
+fail:
+ rcu_read_unlock();
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(pnfs_find_get_deviceid);
+
+/*
+ * Add a deviceid to the cache.
+ * GETDEVICEINFOs for same deviceid can race. If deviceid is found, discard new
+ */
+struct pnfs_deviceid_node *
+pnfs_add_deviceid(struct pnfs_deviceid_cache *c, struct pnfs_deviceid_node *new)
+{
+ struct pnfs_deviceid_node *d;
+ long hash = nfs4_deviceid_hash(&new->de_id);
+
+ dprintk("--> %s hash %ld\n", __func__, hash);
+ spin_lock(&c->dc_lock);
+ d = pnfs_find_get_deviceid(c, &new->de_id);
+ if (d) {
+ spin_unlock(&c->dc_lock);
+ dprintk("%s [discard]\n", __func__);
+ c->dc_free_callback(new);
+ return d;
+ }
+ INIT_HLIST_NODE(&new->de_node);
+ atomic_set(&new->de_ref, 1);
+ hlist_add_head_rcu(&new->de_node, &c->dc_deviceids[hash]);
+ spin_unlock(&c->dc_lock);
+ dprintk("%s [new]\n", __func__);
+ return new;
+}
+EXPORT_SYMBOL_GPL(pnfs_add_deviceid);
+
+void
+pnfs_put_deviceid_cache(struct nfs_client *clp)
+{
+ struct pnfs_deviceid_cache *local = clp->cl_devid_cache;
+
+ dprintk("--> %s cl_devid_cache %p\n", __func__, clp->cl_devid_cache);
+ if (atomic_dec_and_lock(&local->dc_ref, &clp->cl_lock)) {
+ int i;
+ /* Verify cache is empty */
+ for (i = 0; i < NFS4_DEVICE_ID_HASH_SIZE; i++)
+ BUG_ON(!hlist_empty(&local->dc_deviceids[i]));
+ clp->cl_devid_cache = NULL;
+ spin_unlock(&clp->cl_lock);
+ kfree(local);
+ }
+}
+EXPORT_SYMBOL_GPL(pnfs_put_deviceid_cache);
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
new file mode 100644
index 000000000000..e12367d50489
--- /dev/null
+++ b/fs/nfs/pnfs.h
@@ -0,0 +1,189 @@
+/*
+ * pNFS client data structures.
+ *
+ * Copyright (c) 2002
+ * The Regents of the University of Michigan
+ * All Rights Reserved
+ *
+ * Dean Hildebrand <dhildebz@umich.edu>
+ *
+ * Permission is granted to use, copy, create derivative works, and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the University of Michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. If
+ * the above copyright notice or any other identification of the
+ * University of Michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * This software is provided as is, without representation or warranty
+ * of any kind either express or implied, including without limitation
+ * the implied warranties of merchantability, fitness for a particular
+ * purpose, or noninfringement. The Regents of the University of
+ * Michigan shall not be liable for any damages, including special,
+ * indirect, incidental, or consequential damages, with respect to any
+ * claim arising out of or in connection with the use of the software,
+ * even if it has been or is hereafter advised of the possibility of
+ * such damages.
+ */
+
+#ifndef FS_NFS_PNFS_H
+#define FS_NFS_PNFS_H
+
+struct pnfs_layout_segment {
+ struct list_head fi_list;
+ struct pnfs_layout_range range;
+ struct kref kref;
+ struct pnfs_layout_hdr *layout;
+};
+
+#ifdef CONFIG_NFS_V4_1
+
+#define LAYOUT_NFSV4_1_MODULE_PREFIX "nfs-layouttype4"
+
+enum {
+ NFS_LAYOUT_RO_FAILED = 0, /* get ro layout failed stop trying */
+ NFS_LAYOUT_RW_FAILED, /* get rw layout failed stop trying */
+ NFS_LAYOUT_STATEID_SET, /* have a valid layout stateid */
+};
+
+/* Per-layout driver specific registration structure */
+struct pnfs_layoutdriver_type {
+ struct list_head pnfs_tblid;
+ const u32 id;
+ const char *name;
+ struct module *owner;
+ int (*set_layoutdriver) (struct nfs_server *);
+ int (*clear_layoutdriver) (struct nfs_server *);
+ struct pnfs_layout_segment * (*alloc_lseg) (struct pnfs_layout_hdr *layoutid, struct nfs4_layoutget_res *lgr);
+ void (*free_lseg) (struct pnfs_layout_segment *lseg);
+};
+
+struct pnfs_layout_hdr {
+ unsigned long refcount;
+ struct list_head layouts; /* other client layouts */
+ struct list_head segs; /* layout segments list */
+ seqlock_t seqlock; /* Protects the stateid */
+ nfs4_stateid stateid;
+ unsigned long state;
+ struct inode *inode;
+};
+
+struct pnfs_device {
+ struct nfs4_deviceid dev_id;
+ unsigned int layout_type;
+ unsigned int mincount;
+ struct page **pages;
+ void *area;
+ unsigned int pgbase;
+ unsigned int pglen;
+};
+
+/*
+ * Device ID RCU cache. A device ID is unique per client ID and layout type.
+ */
+#define NFS4_DEVICE_ID_HASH_BITS 5
+#define NFS4_DEVICE_ID_HASH_SIZE (1 << NFS4_DEVICE_ID_HASH_BITS)
+#define NFS4_DEVICE_ID_HASH_MASK (NFS4_DEVICE_ID_HASH_SIZE - 1)
+
+static inline u32
+nfs4_deviceid_hash(struct nfs4_deviceid *id)
+{
+ unsigned char *cptr = (unsigned char *)id->data;
+ unsigned int nbytes = NFS4_DEVICEID4_SIZE;
+ u32 x = 0;
+
+ while (nbytes--) {
+ x *= 37;
+ x += *cptr++;
+ }
+ return x & NFS4_DEVICE_ID_HASH_MASK;
+}
+
+struct pnfs_deviceid_node {
+ struct hlist_node de_node;
+ struct nfs4_deviceid de_id;
+ atomic_t de_ref;
+};
+
+struct pnfs_deviceid_cache {
+ spinlock_t dc_lock;
+ atomic_t dc_ref;
+ void (*dc_free_callback)(struct pnfs_deviceid_node *);
+ struct hlist_head dc_deviceids[NFS4_DEVICE_ID_HASH_SIZE];
+};
+
+extern int pnfs_alloc_init_deviceid_cache(struct nfs_client *,
+ void (*free_callback)(struct pnfs_deviceid_node *));
+extern void pnfs_put_deviceid_cache(struct nfs_client *);
+extern struct pnfs_deviceid_node *pnfs_find_get_deviceid(
+ struct pnfs_deviceid_cache *,
+ struct nfs4_deviceid *);
+extern struct pnfs_deviceid_node *pnfs_add_deviceid(
+ struct pnfs_deviceid_cache *,
+ struct pnfs_deviceid_node *);
+extern void pnfs_put_deviceid(struct pnfs_deviceid_cache *c,
+ struct pnfs_deviceid_node *devid);
+
+extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *);
+extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *);
+
+/* nfs4proc.c */
+extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
+ struct pnfs_device *dev);
+extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp);
+
+/* pnfs.c */
+struct pnfs_layout_segment *
+pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
+ enum pnfs_iomode access_type);
+void set_pnfs_layoutdriver(struct nfs_server *, u32 id);
+void unset_pnfs_layoutdriver(struct nfs_server *);
+int pnfs_layout_process(struct nfs4_layoutget *lgp);
+void pnfs_destroy_layout(struct nfs_inode *);
+void pnfs_destroy_all_layouts(struct nfs_client *);
+void put_layout_hdr(struct inode *inode);
+void pnfs_get_layout_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
+ struct nfs4_state *open_state);
+
+
+static inline int lo_fail_bit(u32 iomode)
+{
+ return iomode == IOMODE_RW ?
+ NFS_LAYOUT_RW_FAILED : NFS_LAYOUT_RO_FAILED;
+}
+
+/* Return true if a layout driver is being used for this mountpoint */
+static inline int pnfs_enabled_sb(struct nfs_server *nfss)
+{
+ return nfss->pnfs_curr_ld != NULL;
+}
+
+#else /* CONFIG_NFS_V4_1 */
+
+static inline void pnfs_destroy_all_layouts(struct nfs_client *clp)
+{
+}
+
+static inline void pnfs_destroy_layout(struct nfs_inode *nfsi)
+{
+}
+
+static inline struct pnfs_layout_segment *
+pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
+ enum pnfs_iomode access_type)
+{
+ return NULL;
+}
+
+static inline void set_pnfs_layoutdriver(struct nfs_server *s, u32 id)
+{
+}
+
+static inline void unset_pnfs_layoutdriver(struct nfs_server *s)
+{
+}
+
+#endif /* CONFIG_NFS_V4_1 */
+
+#endif /* FS_NFS_PNFS_H */
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 611bec22f552..58e7f84fc1fd 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -258,7 +258,7 @@ static void nfs_free_createdata(const struct nfs_createdata *data)
static int
nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
- int flags, struct nameidata *nd)
+ int flags, struct nfs_open_context *ctx)
{
struct nfs_createdata *data;
struct rpc_message msg = {
@@ -365,17 +365,32 @@ static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
return 1;
}
+static void
+nfs_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
+{
+ msg->rpc_proc = &nfs_procedures[NFSPROC_RENAME];
+}
+
+static int
+nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
+ struct inode *new_dir)
+{
+ if (nfs_async_handle_expired_key(task))
+ return 0;
+ nfs_mark_for_revalidate(old_dir);
+ nfs_mark_for_revalidate(new_dir);
+ return 1;
+}
+
static int
nfs_proc_rename(struct inode *old_dir, struct qstr *old_name,
struct inode *new_dir, struct qstr *new_name)
{
struct nfs_renameargs arg = {
- .fromfh = NFS_FH(old_dir),
- .fromname = old_name->name,
- .fromlen = old_name->len,
- .tofh = NFS_FH(new_dir),
- .toname = new_name->name,
- .tolen = new_name->len
+ .old_dir = NFS_FH(old_dir),
+ .old_name = old_name,
+ .new_dir = NFS_FH(new_dir),
+ .new_name = new_name,
};
struct rpc_message msg = {
.rpc_proc = &nfs_procedures[NFSPROC_RENAME],
@@ -519,14 +534,14 @@ nfs_proc_rmdir(struct inode *dir, struct qstr *name)
*/
static int
nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
- u64 cookie, struct page *page, unsigned int count, int plus)
+ u64 cookie, struct page **pages, unsigned int count, int plus)
{
struct inode *dir = dentry->d_inode;
struct nfs_readdirargs arg = {
.fh = NFS_FH(dir),
.cookie = cookie,
.count = count,
- .pages = &page,
+ .pages = pages,
};
struct rpc_message msg = {
.rpc_proc = &nfs_procedures[NFSPROC_READDIR],
@@ -705,6 +720,8 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
.unlink_setup = nfs_proc_unlink_setup,
.unlink_done = nfs_proc_unlink_done,
.rename = nfs_proc_rename,
+ .rename_setup = nfs_proc_rename_setup,
+ .rename_done = nfs_proc_rename_done,
.link = nfs_proc_link,
.symlink = nfs_proc_symlink,
.mkdir = nfs_proc_mkdir,
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 87adc2744246..e4b62c6f5a6e 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -25,6 +25,7 @@
#include "internal.h"
#include "iostat.h"
#include "fscache.h"
+#include "pnfs.h"
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
@@ -46,7 +47,6 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->pages);
p->npages = pagecount;
- p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
if (pagecount <= ARRAY_SIZE(p->page_array))
p->pagevec = p->page_array;
else {
@@ -121,6 +121,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
len = nfs_page_length(page);
if (len == 0)
return nfs_return_empty_page(page);
+ pnfs_update_layout(inode, ctx, IOMODE_READ);
new = nfs_create_request(ctx, inode, page, 0, len);
if (IS_ERR(new)) {
unlock_page(page);
@@ -625,6 +626,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
if (ret == 0)
goto read_complete; /* all pages were read */
+ pnfs_update_layout(inode, desc.ctx, IOMODE_READ);
if (rsize < PAGE_CACHE_SIZE)
nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0);
else
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index f4cbf0c306c6..3600ec700d58 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -100,6 +100,7 @@ enum {
Opt_addr, Opt_mountaddr, Opt_clientaddr,
Opt_lookupcache,
Opt_fscache_uniq,
+ Opt_local_lock,
/* Special mount options */
Opt_userspace, Opt_deprecated, Opt_sloppy,
@@ -171,6 +172,7 @@ static const match_table_t nfs_mount_option_tokens = {
{ Opt_lookupcache, "lookupcache=%s" },
{ Opt_fscache_uniq, "fsc=%s" },
+ { Opt_local_lock, "local_lock=%s" },
{ Opt_err, NULL }
};
@@ -236,6 +238,22 @@ static match_table_t nfs_lookupcache_tokens = {
{ Opt_lookupcache_err, NULL }
};
+enum {
+ Opt_local_lock_all, Opt_local_lock_flock, Opt_local_lock_posix,
+ Opt_local_lock_none,
+
+ Opt_local_lock_err
+};
+
+static match_table_t nfs_local_lock_tokens = {
+ { Opt_local_lock_all, "all" },
+ { Opt_local_lock_flock, "flock" },
+ { Opt_local_lock_posix, "posix" },
+ { Opt_local_lock_none, "none" },
+
+ { Opt_local_lock_err, NULL }
+};
+
static void nfs_umount_begin(struct super_block *);
static int nfs_statfs(struct dentry *, struct kstatfs *);
@@ -622,6 +640,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
const struct proc_nfs_info *nfs_infop;
struct nfs_client *clp = nfss->nfs_client;
u32 version = clp->rpc_ops->version;
+ int local_flock, local_fcntl;
seq_printf(m, ",vers=%u", version);
seq_printf(m, ",rsize=%u", nfss->rsize);
@@ -670,6 +689,18 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
else
seq_printf(m, ",lookupcache=pos");
}
+
+ local_flock = nfss->flags & NFS_MOUNT_LOCAL_FLOCK;
+ local_fcntl = nfss->flags & NFS_MOUNT_LOCAL_FCNTL;
+
+ if (!local_flock && !local_fcntl)
+ seq_printf(m, ",local_lock=none");
+ else if (local_flock && local_fcntl)
+ seq_printf(m, ",local_lock=all");
+ else if (local_flock)
+ seq_printf(m, ",local_lock=flock");
+ else
+ seq_printf(m, ",local_lock=posix");
}
/*
@@ -1017,9 +1048,13 @@ static int nfs_parse_mount_options(char *raw,
break;
case Opt_lock:
mnt->flags &= ~NFS_MOUNT_NONLM;
+ mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
+ NFS_MOUNT_LOCAL_FCNTL);
break;
case Opt_nolock:
mnt->flags |= NFS_MOUNT_NONLM;
+ mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
+ NFS_MOUNT_LOCAL_FCNTL);
break;
case Opt_v2:
mnt->flags &= ~NFS_MOUNT_VER3;
@@ -1420,6 +1455,34 @@ static int nfs_parse_mount_options(char *raw,
mnt->fscache_uniq = string;
mnt->options |= NFS_OPTION_FSCACHE;
break;
+ case Opt_local_lock:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ token = match_token(string, nfs_local_lock_tokens,
+ args);
+ kfree(string);
+ switch (token) {
+ case Opt_local_lock_all:
+ mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
+ NFS_MOUNT_LOCAL_FCNTL);
+ break;
+ case Opt_local_lock_flock:
+ mnt->flags |= NFS_MOUNT_LOCAL_FLOCK;
+ break;
+ case Opt_local_lock_posix:
+ mnt->flags |= NFS_MOUNT_LOCAL_FCNTL;
+ break;
+ case Opt_local_lock_none:
+ mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
+ NFS_MOUNT_LOCAL_FCNTL);
+ break;
+ default:
+ dfprintk(MOUNT, "NFS: invalid "
+ "local_lock argument\n");
+ return 0;
+ };
+ break;
/*
* Special options
@@ -1825,6 +1888,12 @@ static int nfs_validate_mount_data(void *options,
if (!args->nfs_server.hostname)
goto out_nomem;
+ if (!(data->flags & NFS_MOUNT_NONLM))
+ args->flags &= ~(NFS_MOUNT_LOCAL_FLOCK|
+ NFS_MOUNT_LOCAL_FCNTL);
+ else
+ args->flags |= (NFS_MOUNT_LOCAL_FLOCK|
+ NFS_MOUNT_LOCAL_FCNTL);
/*
* The legacy version 6 binary mount data from userspace has a
* field used only to transport selinux information into the
@@ -2441,7 +2510,8 @@ static void nfs4_fill_super(struct super_block *sb)
static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
{
- args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3);
+ args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
+ NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL);
}
static int nfs4_validate_text_mount_data(void *options,
diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c
index ad4d2e787b20..978aaeb8a093 100644
--- a/fs/nfs/sysctl.c
+++ b/fs/nfs/sysctl.c
@@ -32,6 +32,7 @@ static ctl_table nfs_cb_sysctls[] = {
.extra1 = (int *)&nfs_set_port_min,
.extra2 = (int *)&nfs_set_port_max,
},
+#ifndef CONFIG_NFS_USE_NEW_IDMAPPER
{
.procname = "idmap_cache_timeout",
.data = &nfs_idmap_cache_timeout,
@@ -39,6 +40,7 @@ static ctl_table nfs_cb_sysctls[] = {
.mode = 0644,
.proc_handler = proc_dointvec_jiffies,
},
+#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
#endif
{
.procname = "nfs_mountpoint_timeout",
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c
index 2f84adaad427..9a16bad5d2ea 100644
--- a/fs/nfs/unlink.c
+++ b/fs/nfs/unlink.c
@@ -13,9 +13,12 @@
#include <linux/nfs_fs.h>
#include <linux/sched.h>
#include <linux/wait.h>
+#include <linux/namei.h>
#include "internal.h"
#include "nfs4_fs.h"
+#include "iostat.h"
+#include "delegation.h"
struct nfs_unlinkdata {
struct hlist_node list;
@@ -244,7 +247,7 @@ void nfs_unblock_sillyrename(struct dentry *dentry)
* @dir: parent directory of dentry
* @dentry: dentry to unlink
*/
-int
+static int
nfs_async_unlink(struct inode *dir, struct dentry *dentry)
{
struct nfs_unlinkdata *data;
@@ -259,7 +262,6 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry)
status = PTR_ERR(data->cred);
goto out_free;
}
- data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
data->res.dir_attr = &data->dir_attr;
status = -EBUSY;
@@ -303,3 +305,256 @@ nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)))
nfs_free_unlinkdata(data);
}
+
+/* Cancel a queued async unlink. Called when a sillyrename run fails. */
+static void
+nfs_cancel_async_unlink(struct dentry *dentry)
+{
+ spin_lock(&dentry->d_lock);
+ if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+ struct nfs_unlinkdata *data = dentry->d_fsdata;
+
+ dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+ spin_unlock(&dentry->d_lock);
+ nfs_free_unlinkdata(data);
+ return;
+ }
+ spin_unlock(&dentry->d_lock);
+}
+
+struct nfs_renamedata {
+ struct nfs_renameargs args;
+ struct nfs_renameres res;
+ struct rpc_cred *cred;
+ struct inode *old_dir;
+ struct dentry *old_dentry;
+ struct nfs_fattr old_fattr;
+ struct inode *new_dir;
+ struct dentry *new_dentry;
+ struct nfs_fattr new_fattr;
+};
+
+/**
+ * nfs_async_rename_done - Sillyrename post-processing
+ * @task: rpc_task of the sillyrename
+ * @calldata: nfs_renamedata for the sillyrename
+ *
+ * Do the directory attribute updates and the d_move
+ */
+static void nfs_async_rename_done(struct rpc_task *task, void *calldata)
+{
+ struct nfs_renamedata *data = calldata;
+ struct inode *old_dir = data->old_dir;
+ struct inode *new_dir = data->new_dir;
+
+ if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) {
+ nfs_restart_rpc(task, NFS_SERVER(old_dir)->nfs_client);
+ return;
+ }
+
+ if (task->tk_status != 0) {
+ nfs_cancel_async_unlink(data->old_dentry);
+ return;
+ }
+
+ nfs_set_verifier(data->old_dentry, nfs_save_change_attribute(old_dir));
+ d_move(data->old_dentry, data->new_dentry);
+}
+
+/**
+ * nfs_async_rename_release - Release the sillyrename data.
+ * @calldata: the struct nfs_renamedata to be released
+ */
+static void nfs_async_rename_release(void *calldata)
+{
+ struct nfs_renamedata *data = calldata;
+ struct super_block *sb = data->old_dir->i_sb;
+
+ if (data->old_dentry->d_inode)
+ nfs_mark_for_revalidate(data->old_dentry->d_inode);
+
+ dput(data->old_dentry);
+ dput(data->new_dentry);
+ iput(data->old_dir);
+ iput(data->new_dir);
+ nfs_sb_deactive(sb);
+ put_rpccred(data->cred);
+ kfree(data);
+}
+
+#if defined(CONFIG_NFS_V4_1)
+static void nfs_rename_prepare(struct rpc_task *task, void *calldata)
+{
+ struct nfs_renamedata *data = calldata;
+ struct nfs_server *server = NFS_SERVER(data->old_dir);
+
+ if (nfs4_setup_sequence(server, &data->args.seq_args,
+ &data->res.seq_res, 1, task))
+ return;
+ rpc_call_start(task);
+}
+#endif /* CONFIG_NFS_V4_1 */
+
+static const struct rpc_call_ops nfs_rename_ops = {
+ .rpc_call_done = nfs_async_rename_done,
+ .rpc_release = nfs_async_rename_release,
+#if defined(CONFIG_NFS_V4_1)
+ .rpc_call_prepare = nfs_rename_prepare,
+#endif /* CONFIG_NFS_V4_1 */
+};
+
+/**
+ * nfs_async_rename - perform an asynchronous rename operation
+ * @old_dir: directory that currently holds the dentry to be renamed
+ * @new_dir: target directory for the rename
+ * @old_dentry: original dentry to be renamed
+ * @new_dentry: dentry to which the old_dentry should be renamed
+ *
+ * It's expected that valid references to the dentries and inodes are held
+ */
+static struct rpc_task *
+nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
+ struct dentry *old_dentry, struct dentry *new_dentry)
+{
+ struct nfs_renamedata *data;
+ struct rpc_message msg = { };
+ struct rpc_task_setup task_setup_data = {
+ .rpc_message = &msg,
+ .callback_ops = &nfs_rename_ops,
+ .workqueue = nfsiod_workqueue,
+ .rpc_client = NFS_CLIENT(old_dir),
+ .flags = RPC_TASK_ASYNC,
+ };
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (data == NULL)
+ return ERR_PTR(-ENOMEM);
+ task_setup_data.callback_data = data,
+
+ data->cred = rpc_lookup_cred();
+ if (IS_ERR(data->cred)) {
+ struct rpc_task *task = ERR_CAST(data->cred);
+ kfree(data);
+ return task;
+ }
+
+ msg.rpc_argp = &data->args;
+ msg.rpc_resp = &data->res;
+ msg.rpc_cred = data->cred;
+
+ /* set up nfs_renamedata */
+ data->old_dir = old_dir;
+ atomic_inc(&old_dir->i_count);
+ data->new_dir = new_dir;
+ atomic_inc(&new_dir->i_count);
+ data->old_dentry = dget(old_dentry);
+ data->new_dentry = dget(new_dentry);
+ nfs_fattr_init(&data->old_fattr);
+ nfs_fattr_init(&data->new_fattr);
+
+ /* set up nfs_renameargs */
+ data->args.old_dir = NFS_FH(old_dir);
+ data->args.old_name = &old_dentry->d_name;
+ data->args.new_dir = NFS_FH(new_dir);
+ data->args.new_name = &new_dentry->d_name;
+
+ /* set up nfs_renameres */
+ data->res.old_fattr = &data->old_fattr;
+ data->res.new_fattr = &data->new_fattr;
+
+ nfs_sb_active(old_dir->i_sb);
+
+ NFS_PROTO(data->old_dir)->rename_setup(&msg, old_dir);
+
+ return rpc_run_task(&task_setup_data);
+}
+
+/**
+ * nfs_sillyrename - Perform a silly-rename of a dentry
+ * @dir: inode of directory that contains dentry
+ * @dentry: dentry to be sillyrenamed
+ *
+ * NFSv2/3 is stateless and the server doesn't know when the client is
+ * holding a file open. To prevent application problems when a file is
+ * unlinked while it's still open, the client performs a "silly-rename".
+ * That is, it renames the file to a hidden file in the same directory,
+ * and only performs the unlink once the last reference to it is put.
+ *
+ * The final cleanup is done during dentry_iput.
+ */
+int
+nfs_sillyrename(struct inode *dir, struct dentry *dentry)
+{
+ static unsigned int sillycounter;
+ const int fileidsize = sizeof(NFS_FILEID(dentry->d_inode))*2;
+ const int countersize = sizeof(sillycounter)*2;
+ const int slen = sizeof(".nfs")+fileidsize+countersize-1;
+ char silly[slen+1];
+ struct dentry *sdentry;
+ struct rpc_task *task;
+ int error = -EIO;
+
+ dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ atomic_read(&dentry->d_count));
+ nfs_inc_stats(dir, NFSIOS_SILLYRENAME);
+
+ /*
+ * We don't allow a dentry to be silly-renamed twice.
+ */
+ error = -EBUSY;
+ if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
+ goto out;
+
+ sprintf(silly, ".nfs%*.*Lx",
+ fileidsize, fileidsize,
+ (unsigned long long)NFS_FILEID(dentry->d_inode));
+
+ /* Return delegation in anticipation of the rename */
+ nfs_inode_return_delegation(dentry->d_inode);
+
+ sdentry = NULL;
+ do {
+ char *suffix = silly + slen - countersize;
+
+ dput(sdentry);
+ sillycounter++;
+ sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);
+
+ dfprintk(VFS, "NFS: trying to rename %s to %s\n",
+ dentry->d_name.name, silly);
+
+ sdentry = lookup_one_len(silly, dentry->d_parent, slen);
+ /*
+ * N.B. Better to return EBUSY here ... it could be
+ * dangerous to delete the file while it's in use.
+ */
+ if (IS_ERR(sdentry))
+ goto out;
+ } while (sdentry->d_inode != NULL); /* need negative lookup */
+
+ /* queue unlink first. Can't do this from rpc_release as it
+ * has to allocate memory
+ */
+ error = nfs_async_unlink(dir, dentry);
+ if (error)
+ goto out_dput;
+
+ /* run the rename task, undo unlink if it fails */
+ task = nfs_async_rename(dir, dir, dentry, sdentry);
+ if (IS_ERR(task)) {
+ error = -EBUSY;
+ nfs_cancel_async_unlink(dentry);
+ goto out_dput;
+ }
+
+ /* wait for the RPC task to complete, unless a SIGKILL intervenes */
+ error = rpc_wait_for_completion_task(task);
+ if (error == 0)
+ error = task->tk_status;
+ rpc_put_task(task);
+out_dput:
+ dput(sdentry);
+out:
+ return error;
+}
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 874972d9427c..4c14c17a5276 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -55,7 +55,6 @@ struct nfs_write_data *nfs_commitdata_alloc(void)
if (p) {
memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->pages);
- p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
}
return p;
}
@@ -75,7 +74,6 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->pages);
p->npages = pagecount;
- p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
if (pagecount <= ARRAY_SIZE(p->page_array))
p->pagevec = p->page_array;
else {
@@ -292,9 +290,7 @@ static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, st
nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
nfs_pageio_cond_complete(pgio, page->index);
- ret = nfs_page_async_flush(pgio, page,
- wbc->sync_mode == WB_SYNC_NONE ||
- wbc->nonblocking != 0);
+ ret = nfs_page_async_flush(pgio, page, wbc->sync_mode == WB_SYNC_NONE);
if (ret == -EAGAIN) {
redirty_page_for_writepage(wbc, page);
ret = 0;
@@ -1433,15 +1429,17 @@ static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_contr
int flags = FLUSH_SYNC;
int ret = 0;
- /* Don't commit yet if this is a non-blocking flush and there are
- * lots of outstanding writes for this mapping.
- */
- if (wbc->sync_mode == WB_SYNC_NONE &&
- nfsi->ncommit <= (nfsi->npages >> 1))
- goto out_mark_dirty;
+ 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.
+ */
+ if (nfsi->ncommit <= (nfsi->npages >> 1))
+ goto out_mark_dirty;
- if (wbc->nonblocking || wbc->for_background)
+ /* don't wait for the COMMIT response */
flags = 0;
+ }
+
ret = nfs_commit_inode(inode, flags);
if (ret >= 0) {
if (wbc->sync_mode == WB_SYNC_NONE) {
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
index 7cf4ddafb4ab..18b3e8975fe0 100644
--- a/fs/nfsd/Kconfig
+++ b/fs/nfsd/Kconfig
@@ -2,7 +2,6 @@ config NFSD
tristate "NFS server support"
depends on INET
depends on FILE_LOCKING
- depends on BKL # fix as soon as lockd is done
select LOCKD
select SUNRPC
select EXPORTFS
@@ -29,6 +28,18 @@ config NFSD
If unsure, say N.
+config NFSD_DEPRECATED
+ bool "Include support for deprecated syscall interface to NFSD"
+ depends on NFSD
+ default y
+ help
+ The syscall interface to nfsd was obsoleted in 2.6.0 by a new
+ filesystem based interface. The old interface is due for removal
+ in 2.6.40. If you wish to remove the interface before then
+ say N.
+
+ In unsure, say Y.
+
config NFSD_V2_ACL
bool
depends on NFSD
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index c2a4f71d87dd..c0fcb7ab7f6d 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -28,9 +28,6 @@
typedef struct auth_domain svc_client;
typedef struct svc_export svc_export;
-static void exp_do_unexport(svc_export *unexp);
-static int exp_verify_string(char *cp, int max);
-
/*
* We have two caches.
* One maps client+vfsmnt+dentry to export options - the export map
@@ -802,6 +799,7 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
return ek;
}
+#ifdef CONFIG_NFSD_DEPRECATED
static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv,
struct svc_export *exp)
{
@@ -852,6 +850,7 @@ exp_get_fsid_key(svc_client *clp, int fsid)
return exp_find_key(clp, FSID_NUM, fsidv, NULL);
}
+#endif
static svc_export *exp_get_by_name(svc_client *clp, const struct path *path,
struct cache_req *reqp)
@@ -893,6 +892,7 @@ static struct svc_export *exp_parent(svc_client *clp, struct path *path)
return exp;
}
+#ifdef CONFIG_NFSD_DEPRECATED
/*
* Hashtable locking. Write locks are placed only by user processes
* wanting to modify export information.
@@ -925,6 +925,19 @@ exp_writeunlock(void)
{
up_write(&hash_sem);
}
+#else
+
+/* hash_sem not needed once deprecated interface is removed */
+void exp_readlock(void) {}
+static inline void exp_writelock(void){}
+void exp_readunlock(void) {}
+static inline void exp_writeunlock(void){}
+
+#endif
+
+#ifdef CONFIG_NFSD_DEPRECATED
+static void exp_do_unexport(svc_export *unexp);
+static int exp_verify_string(char *cp, int max);
static void exp_fsid_unhash(struct svc_export *exp)
{
@@ -935,10 +948,9 @@ static void exp_fsid_unhash(struct svc_export *exp)
ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
if (!IS_ERR(ek)) {
- ek->h.expiry_time = get_seconds()-1;
+ sunrpc_invalidate(&ek->h, &svc_expkey_cache);
cache_put(&ek->h, &svc_expkey_cache);
}
- svc_expkey_cache.nextcheck = get_seconds();
}
static int exp_fsid_hash(svc_client *clp, struct svc_export *exp)
@@ -973,10 +985,9 @@ static void exp_unhash(struct svc_export *exp)
ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
if (!IS_ERR(ek)) {
- ek->h.expiry_time = get_seconds()-1;
+ sunrpc_invalidate(&ek->h, &svc_expkey_cache);
cache_put(&ek->h, &svc_expkey_cache);
}
- svc_expkey_cache.nextcheck = get_seconds();
}
/*
@@ -1097,8 +1108,7 @@ out:
static void
exp_do_unexport(svc_export *unexp)
{
- unexp->h.expiry_time = get_seconds()-1;
- svc_export_cache.nextcheck = get_seconds();
+ sunrpc_invalidate(&unexp->h, &svc_export_cache);
exp_unhash(unexp);
exp_fsid_unhash(unexp);
}
@@ -1150,6 +1160,7 @@ out_unlock:
exp_writeunlock();
return err;
}
+#endif /* CONFIG_NFSD_DEPRECATED */
/*
* Obtain the root fh on behalf of a client.
@@ -1459,25 +1470,43 @@ static void show_secinfo_flags(struct seq_file *m, int flags)
show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
}
+static bool secinfo_flags_equal(int f, int g)
+{
+ f &= NFSEXP_SECINFO_FLAGS;
+ g &= NFSEXP_SECINFO_FLAGS;
+ return f == g;
+}
+
+static int show_secinfo_run(struct seq_file *m, struct exp_flavor_info **fp, struct exp_flavor_info *end)
+{
+ int flags;
+
+ flags = (*fp)->flags;
+ seq_printf(m, ",sec=%d", (*fp)->pseudoflavor);
+ (*fp)++;
+ while (*fp != end && secinfo_flags_equal(flags, (*fp)->flags)) {
+ seq_printf(m, ":%d", (*fp)->pseudoflavor);
+ (*fp)++;
+ }
+ return flags;
+}
+
static void show_secinfo(struct seq_file *m, struct svc_export *exp)
{
struct exp_flavor_info *f;
struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
- int lastflags = 0, first = 0;
+ int flags;
if (exp->ex_nflavors == 0)
return;
- for (f = exp->ex_flavors; f < end; f++) {
- if (first || f->flags != lastflags) {
- if (!first)
- show_secinfo_flags(m, lastflags);
- seq_printf(m, ",sec=%d", f->pseudoflavor);
- lastflags = f->flags;
- } else {
- seq_printf(m, ":%d", f->pseudoflavor);
- }
+ f = exp->ex_flavors;
+ flags = show_secinfo_run(m, &f, end);
+ if (!secinfo_flags_equal(flags, exp->ex_flags))
+ show_secinfo_flags(m, flags);
+ while (f != end) {
+ flags = show_secinfo_run(m, &f, end);
+ show_secinfo_flags(m, flags);
}
- show_secinfo_flags(m, lastflags);
}
static void exp_flags(struct seq_file *m, int flag, int fsid,
@@ -1532,6 +1561,7 @@ const struct seq_operations nfs_exports_op = {
.show = e_show,
};
+#ifdef CONFIG_NFSD_DEPRECATED
/*
* Add or modify a client.
* Change requests may involve the list of host addresses. The list of
@@ -1563,7 +1593,7 @@ exp_addclient(struct nfsctl_client *ncp)
/* Insert client into hashtable. */
for (i = 0; i < ncp->cl_naddr; i++) {
ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &addr6);
- auth_unix_add_addr(&addr6, dom);
+ auth_unix_add_addr(&init_net, &addr6, dom);
}
auth_unix_forget_old(dom);
auth_domain_put(dom);
@@ -1621,6 +1651,7 @@ exp_verify_string(char *cp, int max)
printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp);
return 0;
}
+#endif /* CONFIG_NFSD_DEPRECATED */
/*
* Initialize the exports module.
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 988cbb3a19b6..143da2eecd7b 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -41,7 +41,6 @@
#define NFSPROC4_CB_NULL 0
#define NFSPROC4_CB_COMPOUND 1
-#define NFS4_STATEID_SIZE 16
/* Index of predefined Linux callback client operations */
@@ -248,10 +247,11 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp,
}
static void
-encode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_cb_sequence *args,
+encode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_callback *cb,
struct nfs4_cb_compound_hdr *hdr)
{
__be32 *p;
+ struct nfsd4_session *ses = cb->cb_clp->cl_cb_session;
if (hdr->minorversion == 0)
return;
@@ -259,8 +259,8 @@ encode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_cb_sequence *args,
RESERVE_SPACE(1 + NFS4_MAX_SESSIONID_LEN + 20);
WRITE32(OP_CB_SEQUENCE);
- WRITEMEM(args->cbs_clp->cl_sessionid.data, NFS4_MAX_SESSIONID_LEN);
- WRITE32(args->cbs_clp->cl_cb_seq_nr);
+ WRITEMEM(ses->se_sessionid.data, NFS4_MAX_SESSIONID_LEN);
+ WRITE32(ses->se_cb_seq_nr);
WRITE32(0); /* slotid, always 0 */
WRITE32(0); /* highest slotid always 0 */
WRITE32(0); /* cachethis always 0 */
@@ -280,18 +280,18 @@ nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p)
static int
nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p,
- struct nfs4_rpc_args *rpc_args)
+ struct nfsd4_callback *cb)
{
struct xdr_stream xdr;
- struct nfs4_delegation *args = rpc_args->args_op;
+ struct nfs4_delegation *args = cb->cb_op;
struct nfs4_cb_compound_hdr hdr = {
- .ident = args->dl_ident,
- .minorversion = rpc_args->args_seq.cbs_minorversion,
+ .ident = cb->cb_clp->cl_cb_ident,
+ .minorversion = cb->cb_minorversion,
};
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_cb_compound_hdr(&xdr, &hdr);
- encode_cb_sequence(&xdr, &rpc_args->args_seq, &hdr);
+ encode_cb_sequence(&xdr, cb, &hdr);
encode_cb_recall(&xdr, args, &hdr);
encode_cb_nops(&hdr);
return 0;
@@ -339,15 +339,16 @@ decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
* with a single slot.
*/
static int
-decode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_cb_sequence *res,
+decode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_callback *cb,
struct rpc_rqst *rqstp)
{
+ struct nfsd4_session *ses = cb->cb_clp->cl_cb_session;
struct nfs4_sessionid id;
int status;
u32 dummy;
__be32 *p;
- if (res->cbs_minorversion == 0)
+ if (cb->cb_minorversion == 0)
return 0;
status = decode_cb_op_hdr(xdr, OP_CB_SEQUENCE);
@@ -363,13 +364,12 @@ decode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_cb_sequence *res,
READ_BUF(NFS4_MAX_SESSIONID_LEN + 16);
memcpy(id.data, p, NFS4_MAX_SESSIONID_LEN);
p += XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN);
- if (memcmp(id.data, res->cbs_clp->cl_sessionid.data,
- NFS4_MAX_SESSIONID_LEN)) {
+ if (memcmp(id.data, ses->se_sessionid.data, NFS4_MAX_SESSIONID_LEN)) {
dprintk("%s Invalid session id\n", __func__);
goto out;
}
READ32(dummy);
- if (dummy != res->cbs_clp->cl_cb_seq_nr) {
+ if (dummy != ses->se_cb_seq_nr) {
dprintk("%s Invalid sequence number\n", __func__);
goto out;
}
@@ -393,7 +393,7 @@ nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p)
static int
nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p,
- struct nfsd4_cb_sequence *seq)
+ struct nfsd4_callback *cb)
{
struct xdr_stream xdr;
struct nfs4_cb_compound_hdr hdr;
@@ -403,8 +403,8 @@ nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p,
status = decode_cb_compound_hdr(&xdr, &hdr);
if (status)
goto out;
- if (seq) {
- status = decode_cb_sequence(&xdr, seq, rqstp);
+ if (cb) {
+ status = decode_cb_sequence(&xdr, cb, rqstp);
if (status)
goto out;
}
@@ -473,30 +473,34 @@ static int max_cb_time(void)
/* Reference counting, callback cleanup, etc., all look racy as heck.
* And why is cl_cb_set an atomic? */
-int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *cb)
+int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
{
struct rpc_timeout timeparms = {
.to_initval = max_cb_time(),
.to_retries = 0,
};
struct rpc_create_args args = {
- .protocol = XPRT_TRANSPORT_TCP,
- .address = (struct sockaddr *) &cb->cb_addr,
- .addrsize = cb->cb_addrlen,
+ .net = &init_net,
+ .address = (struct sockaddr *) &conn->cb_addr,
+ .addrsize = conn->cb_addrlen,
.timeout = &timeparms,
.program = &cb_program,
- .prognumber = cb->cb_prog,
.version = 0,
.authflavor = clp->cl_flavor,
.flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
- .client_name = clp->cl_principal,
};
struct rpc_clnt *client;
- if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
- return -EINVAL;
- if (cb->cb_minorversion) {
- args.bc_xprt = cb->cb_xprt;
+ if (clp->cl_minorversion == 0) {
+ if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
+ return -EINVAL;
+ args.client_name = clp->cl_principal;
+ args.prognumber = conn->cb_prog,
+ args.protocol = XPRT_TRANSPORT_TCP;
+ clp->cl_cb_ident = conn->cb_ident;
+ } else {
+ args.bc_xprt = conn->cb_xprt;
+ args.prognumber = clp->cl_cb_session->se_cb_prog;
args.protocol = XPRT_TRANSPORT_BC_TCP;
}
/* Create RPC client */
@@ -506,7 +510,7 @@ int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *cb)
PTR_ERR(client));
return PTR_ERR(client);
}
- nfsd4_set_callback_client(clp, client);
+ clp->cl_cb_client = client;
return 0;
}
@@ -519,7 +523,7 @@ static void warn_no_callback_path(struct nfs4_client *clp, int reason)
static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
{
- struct nfs4_client *clp = calldata;
+ struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null);
if (task->tk_status)
warn_no_callback_path(clp, task->tk_status);
@@ -528,6 +532,8 @@ static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
}
static const struct rpc_call_ops nfsd4_cb_probe_ops = {
+ /* XXX: release method to ensure we set the cb channel down if
+ * necessary on early failure? */
.rpc_call_done = nfsd4_cb_probe_done,
};
@@ -543,38 +549,42 @@ int set_callback_cred(void)
return 0;
}
+static struct workqueue_struct *callback_wq;
-void do_probe_callback(struct nfs4_client *clp)
+static void do_probe_callback(struct nfs4_client *clp)
{
- struct rpc_message msg = {
- .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
- .rpc_argp = clp,
- .rpc_cred = callback_cred
- };
- int status;
+ struct nfsd4_callback *cb = &clp->cl_cb_null;
- status = rpc_call_async(clp->cl_cb_client, &msg,
- RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
- &nfsd4_cb_probe_ops, (void *)clp);
- if (status)
- warn_no_callback_path(clp, status);
+ cb->cb_op = NULL;
+ cb->cb_clp = clp;
+
+ cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL];
+ cb->cb_msg.rpc_argp = NULL;
+ cb->cb_msg.rpc_resp = NULL;
+ cb->cb_msg.rpc_cred = callback_cred;
+
+ cb->cb_ops = &nfsd4_cb_probe_ops;
+
+ queue_work(callback_wq, &cb->cb_work);
}
/*
- * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
+ * Poke the callback thread to process any updates to the callback
+ * parameters, and send a null probe.
*/
-void nfsd4_probe_callback(struct nfs4_client *clp, struct nfs4_cb_conn *cb)
+void nfsd4_probe_callback(struct nfs4_client *clp)
{
- int status;
+ set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
+ do_probe_callback(clp);
+}
+void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
+{
BUG_ON(atomic_read(&clp->cl_cb_set));
- status = setup_callback_client(clp, cb);
- if (status) {
- warn_no_callback_path(clp, status);
- return;
- }
- do_probe_callback(clp);
+ spin_lock(&clp->cl_lock);
+ memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn));
+ spin_unlock(&clp->cl_lock);
}
/*
@@ -585,8 +595,7 @@ void nfsd4_probe_callback(struct nfs4_client *clp, struct nfs4_cb_conn *cb)
static int nfsd41_cb_setup_sequence(struct nfs4_client *clp,
struct rpc_task *task)
{
- struct nfs4_rpc_args *args = task->tk_msg.rpc_argp;
- u32 *ptr = (u32 *)clp->cl_sessionid.data;
+ u32 *ptr = (u32 *)clp->cl_cb_session->se_sessionid.data;
int status = 0;
dprintk("%s: %u:%u:%u:%u\n", __func__,
@@ -598,14 +607,6 @@ static int nfsd41_cb_setup_sequence(struct nfs4_client *clp,
status = -EAGAIN;
goto out;
}
-
- /*
- * We'll need the clp during XDR encoding and decoding,
- * and the sequence during decoding to verify the reply
- */
- args->args_seq.cbs_clp = clp;
- task->tk_msg.rpc_resp = &args->args_seq;
-
out:
dprintk("%s status=%d\n", __func__, status);
return status;
@@ -617,13 +618,13 @@ out:
*/
static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
{
- struct nfs4_delegation *dp = 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_rpc_args *args = task->tk_msg.rpc_argp;
- u32 minorversion = clp->cl_cb_conn.cb_minorversion;
+ u32 minorversion = clp->cl_minorversion;
int status = 0;
- args->args_seq.cbs_minorversion = minorversion;
+ cb->cb_minorversion = minorversion;
if (minorversion) {
status = nfsd41_cb_setup_sequence(clp, task);
if (status) {
@@ -640,19 +641,20 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
{
- struct nfs4_delegation *dp = 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;
dprintk("%s: minorversion=%d\n", __func__,
- clp->cl_cb_conn.cb_minorversion);
+ clp->cl_minorversion);
- if (clp->cl_cb_conn.cb_minorversion) {
+ if (clp->cl_minorversion) {
/* No need for lock, access serialized in nfsd4_cb_prepare */
- ++clp->cl_cb_seq_nr;
+ ++clp->cl_cb_session->se_cb_seq_nr;
clear_bit(0, &clp->cl_cb_slot_busy);
rpc_wake_up_next(&clp->cl_cb_waitq);
dprintk("%s: freed slot, new seqid=%d\n", __func__,
- clp->cl_cb_seq_nr);
+ clp->cl_cb_session->se_cb_seq_nr);
/* We're done looking into the sequence information */
task->tk_msg.rpc_resp = NULL;
@@ -662,7 +664,8 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
{
- struct nfs4_delegation *dp = 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 rpc_clnt *current_rpc_client = clp->cl_cb_client;
@@ -707,7 +710,8 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
static void nfsd4_cb_recall_release(void *calldata)
{
- struct nfs4_delegation *dp = calldata;
+ struct nfsd4_callback *cb = calldata;
+ struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
nfs4_put_delegation(dp);
}
@@ -718,8 +722,6 @@ static const struct rpc_call_ops nfsd4_cb_recall_ops = {
.rpc_release = nfsd4_cb_recall_release,
};
-static struct workqueue_struct *callback_wq;
-
int nfsd4_create_callback_queue(void)
{
callback_wq = create_singlethread_workqueue("nfsd4_callbacks");
@@ -734,57 +736,88 @@ void nfsd4_destroy_callback_queue(void)
}
/* must be called under the state lock */
-void nfsd4_set_callback_client(struct nfs4_client *clp, struct rpc_clnt *new)
+void nfsd4_shutdown_callback(struct nfs4_client *clp)
{
- struct rpc_clnt *old = clp->cl_cb_client;
-
- clp->cl_cb_client = new;
+ set_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags);
/*
- * After this, any work that saw the old value of cl_cb_client will
- * be gone:
+ * Note this won't actually result in a null callback;
+ * instead, nfsd4_do_callback_rpc() will detect the killed
+ * client, destroy the rpc client, and stop:
*/
+ do_probe_callback(clp);
flush_workqueue(callback_wq);
- /* So we can safely shut it down: */
- if (old)
- rpc_shutdown_client(old);
}
-/*
- * called with dp->dl_count inc'ed.
- */
-static void _nfsd4_cb_recall(struct nfs4_delegation *dp)
+void nfsd4_release_cb(struct nfsd4_callback *cb)
{
- struct nfs4_client *clp = dp->dl_client;
- struct rpc_clnt *clnt = clp->cl_cb_client;
- struct nfs4_rpc_args *args = &dp->dl_recall.cb_args;
- struct rpc_message msg = {
- .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
- .rpc_cred = callback_cred
- };
+ if (cb->cb_ops->rpc_release)
+ cb->cb_ops->rpc_release(cb);
+}
- if (clnt == NULL) {
- nfs4_put_delegation(dp);
- return; /* Client is shutting down; give up. */
+void nfsd4_process_cb_update(struct nfsd4_callback *cb)
+{
+ struct nfs4_cb_conn conn;
+ struct nfs4_client *clp = cb->cb_clp;
+ int err;
+
+ /*
+ * This is either an update, or the client dying; in either case,
+ * kill the old client:
+ */
+ if (clp->cl_cb_client) {
+ rpc_shutdown_client(clp->cl_cb_client);
+ clp->cl_cb_client = NULL;
}
+ if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags))
+ return;
+ spin_lock(&clp->cl_lock);
+ /*
+ * Only serialized callback code is allowed to clear these
+ * flags; main nfsd code can only set them:
+ */
+ BUG_ON(!clp->cl_cb_flags);
+ clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
+ memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn));
+ spin_unlock(&clp->cl_lock);
- args->args_op = dp;
- msg.rpc_argp = args;
- dp->dl_retries = 1;
- rpc_call_async(clnt, &msg, RPC_TASK_SOFT, &nfsd4_cb_recall_ops, dp);
+ err = setup_callback_client(clp, &conn);
+ if (err)
+ warn_no_callback_path(clp, err);
}
void nfsd4_do_callback_rpc(struct work_struct *w)
{
- /* XXX: for now, just send off delegation recall. */
- /* In future, generalize to handle any sort of callback. */
- struct nfsd4_callback *c = container_of(w, struct nfsd4_callback, cb_work);
- struct nfs4_delegation *dp = container_of(c, struct nfs4_delegation, dl_recall);
+ struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
+ struct nfs4_client *clp = cb->cb_clp;
+ struct rpc_clnt *clnt;
- _nfsd4_cb_recall(dp);
-}
+ if (clp->cl_cb_flags)
+ nfsd4_process_cb_update(cb);
+ clnt = clp->cl_cb_client;
+ if (!clnt) {
+ /* Callback channel broken, or client killed; give up: */
+ nfsd4_release_cb(cb);
+ return;
+ }
+ rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
+ cb->cb_ops, cb);
+}
void nfsd4_cb_recall(struct nfs4_delegation *dp)
{
+ struct nfsd4_callback *cb = &dp->dl_recall;
+
+ dp->dl_retries = 1;
+ cb->cb_op = dp;
+ cb->cb_clp = dp->dl_client;
+ cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL];
+ cb->cb_msg.rpc_argp = cb;
+ cb->cb_msg.rpc_resp = cb;
+ cb->cb_msg.rpc_cred = callback_cred;
+
+ cb->cb_ops = &nfsd4_cb_recall_ops;
+ dp->dl_retries = 1;
+
queue_work(callback_wq, &dp->dl_recall.cb_work);
}
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index c78dbf493424..f0695e815f0e 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -482,109 +482,26 @@ nfsd_idmap_shutdown(void)
cache_unregister(&nametoid_cache);
}
-/*
- * Deferred request handling
- */
-
-struct idmap_defer_req {
- struct cache_req req;
- struct cache_deferred_req deferred_req;
- wait_queue_head_t waitq;
- atomic_t count;
-};
-
-static inline void
-put_mdr(struct idmap_defer_req *mdr)
-{
- if (atomic_dec_and_test(&mdr->count))
- kfree(mdr);
-}
-
-static inline void
-get_mdr(struct idmap_defer_req *mdr)
-{
- atomic_inc(&mdr->count);
-}
-
-static void
-idmap_revisit(struct cache_deferred_req *dreq, int toomany)
-{
- struct idmap_defer_req *mdr =
- container_of(dreq, struct idmap_defer_req, deferred_req);
-
- wake_up(&mdr->waitq);
- put_mdr(mdr);
-}
-
-static struct cache_deferred_req *
-idmap_defer(struct cache_req *req)
-{
- struct idmap_defer_req *mdr =
- container_of(req, struct idmap_defer_req, req);
-
- mdr->deferred_req.revisit = idmap_revisit;
- get_mdr(mdr);
- return (&mdr->deferred_req);
-}
-
-static inline int
-do_idmap_lookup(struct ent *(*lookup_fn)(struct ent *), struct ent *key,
- struct cache_detail *detail, struct ent **item,
- struct idmap_defer_req *mdr)
-{
- *item = lookup_fn(key);
- if (!*item)
- return -ENOMEM;
- return cache_check(detail, &(*item)->h, &mdr->req);
-}
-
-static inline int
-do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *),
- struct ent *key, struct cache_detail *detail,
- struct ent **item)
-{
- int ret = -ENOMEM;
-
- *item = lookup_fn(key);
- if (!*item)
- goto out_err;
- ret = -ETIMEDOUT;
- if (!test_bit(CACHE_VALID, &(*item)->h.flags)
- || (*item)->h.expiry_time < get_seconds()
- || detail->flush_time > (*item)->h.last_refresh)
- goto out_put;
- ret = -ENOENT;
- if (test_bit(CACHE_NEGATIVE, &(*item)->h.flags))
- goto out_put;
- return 0;
-out_put:
- cache_put(&(*item)->h, detail);
-out_err:
- *item = NULL;
- return ret;
-}
-
static int
idmap_lookup(struct svc_rqst *rqstp,
struct ent *(*lookup_fn)(struct ent *), struct ent *key,
struct cache_detail *detail, struct ent **item)
{
- struct idmap_defer_req *mdr;
int ret;
- mdr = kzalloc(sizeof(*mdr), GFP_KERNEL);
- if (!mdr)
+ *item = lookup_fn(key);
+ if (!*item)
return -ENOMEM;
- atomic_set(&mdr->count, 1);
- init_waitqueue_head(&mdr->waitq);
- mdr->req.defer = idmap_defer;
- ret = do_idmap_lookup(lookup_fn, key, detail, item, mdr);
- if (ret == -EAGAIN) {
- wait_event_interruptible_timeout(mdr->waitq,
- test_bit(CACHE_VALID, &(*item)->h.flags), 1 * HZ);
- ret = do_idmap_lookup_nowait(lookup_fn, key, detail, item);
+ retry:
+ ret = cache_check(detail, &(*item)->h, &rqstp->rq_chandle);
+
+ if (ret == -ETIMEDOUT) {
+ struct ent *prev_item = *item;
+ *item = lookup_fn(key);
+ if (*item != prev_item)
+ goto retry;
+ cache_put(&(*item)->h, detail);
}
- put_mdr(mdr);
return ret;
}
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 59ec449b0c7f..0cdfd022bb7b 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1031,8 +1031,11 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
resp->cstate.session = NULL;
fh_init(&resp->cstate.current_fh, NFS4_FHSIZE);
fh_init(&resp->cstate.save_fh, NFS4_FHSIZE);
- /* Use the deferral mechanism only for NFSv4.0 compounds */
- rqstp->rq_usedeferral = (args->minorversion == 0);
+ /*
+ * Don't use the deferral mechanism for NFSv4; compounds make it
+ * too hard to avoid non-idempotency problems.
+ */
+ rqstp->rq_usedeferral = 0;
/*
* According to RFC3010, this takes precedence over all other errors.
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a7292fcf7718..56347e0ac88d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -207,7 +207,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
{
struct nfs4_delegation *dp;
struct nfs4_file *fp = stp->st_file;
- struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn;
dprintk("NFSD alloc_init_deleg\n");
/*
@@ -234,7 +233,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
nfs4_file_get_access(fp, O_RDONLY);
dp->dl_flock = NULL;
dp->dl_type = type;
- dp->dl_ident = cb->cb_ident;
dp->dl_stateid.si_boot = boot_time;
dp->dl_stateid.si_stateownerid = current_delegid++;
dp->dl_stateid.si_fileid = 0;
@@ -535,171 +533,258 @@ gen_sessionid(struct nfsd4_session *ses)
*/
#define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44)
+static void
+free_session_slots(struct nfsd4_session *ses)
+{
+ int i;
+
+ for (i = 0; i < ses->se_fchannel.maxreqs; i++)
+ kfree(ses->se_slots[i]);
+}
+
/*
- * Give the client the number of ca_maxresponsesize_cached slots it
- * requests, of size bounded by NFSD_SLOT_CACHE_SIZE,
- * NFSD_MAX_MEM_PER_SESSION, and nfsd_drc_max_mem. Do not allow more
- * than NFSD_MAX_SLOTS_PER_SESSION.
- *
- * If we run out of reserved DRC memory we should (up to a point)
+ * We don't actually need to cache the rpc and session headers, so we
+ * can allocate a little less for each slot:
+ */
+static inline int slot_bytes(struct nfsd4_channel_attrs *ca)
+{
+ return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
+}
+
+static int nfsd4_sanitize_slot_size(u32 size)
+{
+ size -= NFSD_MIN_HDR_SEQ_SZ; /* We don't cache the rpc header */
+ size = min_t(u32, size, NFSD_SLOT_CACHE_SIZE);
+
+ return size;
+}
+
+/*
+ * XXX: If we run out of reserved DRC memory we could (up to a point)
* re-negotiate active sessions and reduce their slot usage to make
* rooom for new connections. For now we just fail the create session.
*/
-static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan)
+static int nfsd4_get_drc_mem(int slotsize, u32 num)
{
- int mem, size = fchan->maxresp_cached;
+ int avail;
- if (fchan->maxreqs < 1)
- return nfserr_inval;
+ num = min_t(u32, num, NFSD_MAX_SLOTS_PER_SESSION);
- if (size < NFSD_MIN_HDR_SEQ_SZ)
- size = NFSD_MIN_HDR_SEQ_SZ;
- size -= NFSD_MIN_HDR_SEQ_SZ;
- if (size > NFSD_SLOT_CACHE_SIZE)
- size = NFSD_SLOT_CACHE_SIZE;
-
- /* bound the maxreqs by NFSD_MAX_MEM_PER_SESSION */
- mem = fchan->maxreqs * size;
- if (mem > NFSD_MAX_MEM_PER_SESSION) {
- fchan->maxreqs = NFSD_MAX_MEM_PER_SESSION / size;
- if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION)
- fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION;
- mem = fchan->maxreqs * size;
- }
+ spin_lock(&nfsd_drc_lock);
+ avail = min_t(int, NFSD_MAX_MEM_PER_SESSION,
+ nfsd_drc_max_mem - nfsd_drc_mem_used);
+ num = min_t(int, num, avail / slotsize);
+ nfsd_drc_mem_used += num * slotsize;
+ spin_unlock(&nfsd_drc_lock);
+ return num;
+}
+
+static void nfsd4_put_drc_mem(int slotsize, int num)
+{
spin_lock(&nfsd_drc_lock);
- /* bound the total session drc memory ussage */
- if (mem + nfsd_drc_mem_used > nfsd_drc_max_mem) {
- fchan->maxreqs = (nfsd_drc_max_mem - nfsd_drc_mem_used) / size;
- mem = fchan->maxreqs * size;
- }
- nfsd_drc_mem_used += mem;
+ nfsd_drc_mem_used -= slotsize * num;
spin_unlock(&nfsd_drc_lock);
+}
- if (fchan->maxreqs == 0)
- return nfserr_jukebox;
+static struct nfsd4_session *alloc_session(int slotsize, int numslots)
+{
+ struct nfsd4_session *new;
+ int mem, i;
- fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ;
- return 0;
+ BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
+ + sizeof(struct nfsd4_session) > PAGE_SIZE);
+ mem = numslots * sizeof(struct nfsd4_slot *);
+
+ new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
+ if (!new)
+ return NULL;
+ /* allocate each struct nfsd4_slot and data cache in one piece */
+ for (i = 0; i < numslots; i++) {
+ mem = sizeof(struct nfsd4_slot) + slotsize;
+ new->se_slots[i] = kzalloc(mem, GFP_KERNEL);
+ if (!new->se_slots[i])
+ goto out_free;
+ }
+ return new;
+out_free:
+ while (i--)
+ kfree(new->se_slots[i]);
+ kfree(new);
+ return NULL;
}
-/*
- * fchan holds the client values on input, and the server values on output
- * sv_max_mesg is the maximum payload plus one page for overhead.
- */
-static int init_forechannel_attrs(struct svc_rqst *rqstp,
- struct nfsd4_channel_attrs *session_fchan,
- struct nfsd4_channel_attrs *fchan)
+static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4_channel_attrs *req, int numslots, int slotsize)
{
- int status = 0;
- __u32 maxcount = nfsd_serv->sv_max_mesg;
+ u32 maxrpc = nfsd_serv->sv_max_mesg;
- /* headerpadsz set to zero in encode routine */
+ new->maxreqs = numslots;
+ new->maxresp_cached = slotsize + NFSD_MIN_HDR_SEQ_SZ;
+ new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc);
+ new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc);
+ new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND);
+}
- /* Use the client's max request and max response size if possible */
- if (fchan->maxreq_sz > maxcount)
- fchan->maxreq_sz = maxcount;
- session_fchan->maxreq_sz = fchan->maxreq_sz;
+static void free_conn(struct nfsd4_conn *c)
+{
+ svc_xprt_put(c->cn_xprt);
+ kfree(c);
+}
- if (fchan->maxresp_sz > maxcount)
- fchan->maxresp_sz = maxcount;
- session_fchan->maxresp_sz = fchan->maxresp_sz;
+static void nfsd4_conn_lost(struct svc_xpt_user *u)
+{
+ struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user);
+ struct nfs4_client *clp = c->cn_session->se_client;
- /* Use the client's maxops if possible */
- if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND)
- fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND;
- session_fchan->maxops = fchan->maxops;
+ spin_lock(&clp->cl_lock);
+ if (!list_empty(&c->cn_persession)) {
+ list_del(&c->cn_persession);
+ free_conn(c);
+ }
+ spin_unlock(&clp->cl_lock);
+}
- /* FIXME: Error means no more DRC pages so the server should
- * recover pages from existing sessions. For now fail session
- * creation.
- */
- status = set_forechannel_drc_size(fchan);
+static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
+{
+ struct nfsd4_conn *conn;
- session_fchan->maxresp_cached = fchan->maxresp_cached;
- session_fchan->maxreqs = fchan->maxreqs;
+ conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL);
+ if (!conn)
+ return NULL;
+ svc_xprt_get(rqstp->rq_xprt);
+ conn->cn_xprt = rqstp->rq_xprt;
+ conn->cn_flags = flags;
+ INIT_LIST_HEAD(&conn->cn_xpt_user.list);
+ return conn;
+}
- dprintk("%s status %d\n", __func__, status);
- return status;
+static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
+{
+ conn->cn_session = ses;
+ list_add(&conn->cn_persession, &ses->se_conns);
}
-static void
-free_session_slots(struct nfsd4_session *ses)
+static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
{
- int i;
+ struct nfs4_client *clp = ses->se_client;
- for (i = 0; i < ses->se_fchannel.maxreqs; i++)
- kfree(ses->se_slots[i]);
+ spin_lock(&clp->cl_lock);
+ __nfsd4_hash_conn(conn, ses);
+ spin_unlock(&clp->cl_lock);
}
-/*
- * We don't actually need to cache the rpc and session headers, so we
- * can allocate a little less for each slot:
- */
-static inline int slot_bytes(struct nfsd4_channel_attrs *ca)
+static void nfsd4_register_conn(struct nfsd4_conn *conn)
{
- return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
+ conn->cn_xpt_user.callback = nfsd4_conn_lost;
+ register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
}
-static int
-alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp,
- struct nfsd4_create_session *cses)
+static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
{
- struct nfsd4_session *new, tmp;
- struct nfsd4_slot *sp;
- int idx, slotsize, cachesize, i;
- int status;
+ struct nfsd4_conn *conn;
+ u32 flags = NFS4_CDFC4_FORE;
- memset(&tmp, 0, sizeof(tmp));
+ if (ses->se_flags & SESSION4_BACK_CHAN)
+ flags |= NFS4_CDFC4_BACK;
+ conn = alloc_conn(rqstp, flags);
+ if (!conn)
+ return nfserr_jukebox;
+ nfsd4_hash_conn(conn, ses);
+ nfsd4_register_conn(conn);
+ return nfs_ok;
+}
- /* FIXME: For now, we just accept the client back channel attributes. */
- tmp.se_bchannel = cses->back_channel;
- status = init_forechannel_attrs(rqstp, &tmp.se_fchannel,
- &cses->fore_channel);
- if (status)
- goto out;
+static void nfsd4_del_conns(struct nfsd4_session *s)
+{
+ struct nfs4_client *clp = s->se_client;
+ struct nfsd4_conn *c;
- BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot)
- + sizeof(struct nfsd4_session) > PAGE_SIZE);
+ spin_lock(&clp->cl_lock);
+ while (!list_empty(&s->se_conns)) {
+ c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession);
+ list_del_init(&c->cn_persession);
+ spin_unlock(&clp->cl_lock);
- status = nfserr_jukebox;
- /* allocate struct nfsd4_session and slot table pointers in one piece */
- slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *);
- new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL);
- if (!new)
- goto out;
+ unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user);
+ free_conn(c);
- memcpy(new, &tmp, sizeof(*new));
+ spin_lock(&clp->cl_lock);
+ }
+ spin_unlock(&clp->cl_lock);
+}
- /* allocate each struct nfsd4_slot and data cache in one piece */
- cachesize = slot_bytes(&new->se_fchannel);
- for (i = 0; i < new->se_fchannel.maxreqs; i++) {
- sp = kzalloc(sizeof(*sp) + cachesize, GFP_KERNEL);
- if (!sp)
- goto out_free;
- new->se_slots[i] = sp;
+void free_session(struct kref *kref)
+{
+ struct nfsd4_session *ses;
+ int mem;
+
+ ses = container_of(kref, struct nfsd4_session, se_ref);
+ nfsd4_del_conns(ses);
+ spin_lock(&nfsd_drc_lock);
+ mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel);
+ nfsd_drc_mem_used -= mem;
+ spin_unlock(&nfsd_drc_lock);
+ free_session_slots(ses);
+ kfree(ses);
+}
+
+static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses)
+{
+ struct nfsd4_session *new;
+ struct nfsd4_channel_attrs *fchan = &cses->fore_channel;
+ int numslots, slotsize;
+ int status;
+ int idx;
+
+ /*
+ * Note decreasing slot size below client's request may
+ * make it difficult for client to function correctly, whereas
+ * decreasing the number of slots will (just?) affect
+ * performance. When short on memory we therefore prefer to
+ * decrease number of slots instead of their size.
+ */
+ slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached);
+ numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs);
+
+ new = alloc_session(slotsize, numslots);
+ if (!new) {
+ nfsd4_put_drc_mem(slotsize, fchan->maxreqs);
+ return NULL;
}
+ init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize);
new->se_client = clp;
gen_sessionid(new);
- idx = hash_sessionid(&new->se_sessionid);
- memcpy(clp->cl_sessionid.data, new->se_sessionid.data,
- NFS4_MAX_SESSIONID_LEN);
+ INIT_LIST_HEAD(&new->se_conns);
+
+ new->se_cb_seq_nr = 1;
new->se_flags = cses->flags;
+ new->se_cb_prog = cses->callback_prog;
kref_init(&new->se_ref);
+ idx = hash_sessionid(&new->se_sessionid);
spin_lock(&client_lock);
list_add(&new->se_hash, &sessionid_hashtbl[idx]);
list_add(&new->se_perclnt, &clp->cl_sessions);
spin_unlock(&client_lock);
- status = nfs_ok;
-out:
- return status;
-out_free:
- free_session_slots(new);
- kfree(new);
- goto out;
+ status = nfsd4_new_conn(rqstp, new);
+ /* whoops: benny points out, status is ignored! (err, or bogus) */
+ if (status) {
+ free_session(&new->se_ref);
+ return NULL;
+ }
+ if (!clp->cl_cb_session && (cses->flags & SESSION4_BACK_CHAN)) {
+ struct sockaddr *sa = svc_addr(rqstp);
+
+ clp->cl_cb_session = new;
+ clp->cl_cb_conn.cb_xprt = rqstp->rq_xprt;
+ svc_xprt_get(rqstp->rq_xprt);
+ rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
+ clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
+ nfsd4_probe_callback(clp);
+ }
+ return new;
}
/* caller must hold client_lock */
@@ -731,21 +816,6 @@ unhash_session(struct nfsd4_session *ses)
list_del(&ses->se_perclnt);
}
-void
-free_session(struct kref *kref)
-{
- struct nfsd4_session *ses;
- int mem;
-
- ses = container_of(kref, struct nfsd4_session, se_ref);
- spin_lock(&nfsd_drc_lock);
- mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel);
- nfsd_drc_mem_used -= mem;
- spin_unlock(&nfsd_drc_lock);
- free_session_slots(ses);
- kfree(ses);
-}
-
/* must be called under the client_lock */
static inline void
renew_client_locked(struct nfs4_client *clp)
@@ -812,6 +882,13 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
static inline void
free_client(struct nfs4_client *clp)
{
+ while (!list_empty(&clp->cl_sessions)) {
+ struct nfsd4_session *ses;
+ ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
+ se_perclnt);
+ list_del(&ses->se_perclnt);
+ nfsd4_put_session(ses);
+ }
if (clp->cl_cred.cr_group_info)
put_group_info(clp->cl_cred.cr_group_info);
kfree(clp->cl_principal);
@@ -838,15 +915,12 @@ release_session_client(struct nfsd4_session *session)
static inline void
unhash_client_locked(struct nfs4_client *clp)
{
+ struct nfsd4_session *ses;
+
mark_client_expired(clp);
list_del(&clp->cl_lru);
- while (!list_empty(&clp->cl_sessions)) {
- struct nfsd4_session *ses;
- ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
- se_perclnt);
- unhash_session(ses);
- nfsd4_put_session(ses);
- }
+ list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
+ list_del_init(&ses->se_hash);
}
static void
@@ -875,7 +949,7 @@ expire_client(struct nfs4_client *clp)
sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient);
release_openowner(sop);
}
- nfsd4_set_callback_client(clp, NULL);
+ nfsd4_shutdown_callback(clp);
if (clp->cl_cb_conn.cb_xprt)
svc_xprt_put(clp->cl_cb_conn.cb_xprt);
list_del(&clp->cl_idhash);
@@ -960,6 +1034,8 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
if (clp == NULL)
return NULL;
+ INIT_LIST_HEAD(&clp->cl_sessions);
+
princ = svc_gss_principal(rqstp);
if (princ) {
clp->cl_principal = kstrdup(princ, GFP_KERNEL);
@@ -976,8 +1052,9 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
INIT_LIST_HEAD(&clp->cl_strhash);
INIT_LIST_HEAD(&clp->cl_openowners);
INIT_LIST_HEAD(&clp->cl_delegations);
- INIT_LIST_HEAD(&clp->cl_sessions);
INIT_LIST_HEAD(&clp->cl_lru);
+ spin_lock_init(&clp->cl_lock);
+ INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
clp->cl_time = get_seconds();
clear_bit(0, &clp->cl_cb_slot_busy);
rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
@@ -986,7 +1063,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
clp->cl_flavor = rqstp->rq_flavor;
copy_cred(&clp->cl_cred, &rqstp->rq_cred);
gen_confirm(clp);
-
+ clp->cl_cb_session = NULL;
return clp;
}
@@ -1098,7 +1175,7 @@ find_unconfirmed_client_by_str(const char *dname, unsigned int hashval,
static void
gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid)
{
- struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
+ struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
unsigned short expected_family;
/* Currently, we only support tcp and tcp6 for the callback channel */
@@ -1111,24 +1188,23 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid)
else
goto out_err;
- cb->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val,
+ conn->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val,
se->se_callback_addr_len,
- (struct sockaddr *) &cb->cb_addr,
- sizeof(cb->cb_addr));
+ (struct sockaddr *)&conn->cb_addr,
+ sizeof(conn->cb_addr));
- if (!cb->cb_addrlen || cb->cb_addr.ss_family != expected_family)
+ if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family)
goto out_err;
- if (cb->cb_addr.ss_family == AF_INET6)
- ((struct sockaddr_in6 *) &cb->cb_addr)->sin6_scope_id = scopeid;
+ if (conn->cb_addr.ss_family == AF_INET6)
+ ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid;
- cb->cb_minorversion = 0;
- cb->cb_prog = se->se_callback_prog;
- cb->cb_ident = se->se_callback_ident;
+ conn->cb_prog = se->se_callback_prog;
+ conn->cb_ident = se->se_callback_ident;
return;
out_err:
- cb->cb_addr.ss_family = AF_UNSPEC;
- cb->cb_addrlen = 0;
+ conn->cb_addr.ss_family = AF_UNSPEC;
+ conn->cb_addrlen = 0;
dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
"will not receive delegations\n",
clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
@@ -1415,7 +1491,9 @@ nfsd4_create_session(struct svc_rqst *rqstp,
{
struct sockaddr *sa = svc_addr(rqstp);
struct nfs4_client *conf, *unconf;
+ struct nfsd4_session *new;
struct nfsd4_clid_slot *cs_slot = NULL;
+ bool confirm_me = false;
int status = 0;
nfs4_lock_state();
@@ -1438,7 +1516,6 @@ nfsd4_create_session(struct svc_rqst *rqstp,
cs_slot->sl_seqid, cr_ses->seqid);
goto out;
}
- cs_slot->sl_seqid++;
} else if (unconf) {
if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
!rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
@@ -1451,25 +1528,10 @@ nfsd4_create_session(struct svc_rqst *rqstp,
if (status) {
/* an unconfirmed replay returns misordered */
status = nfserr_seq_misordered;
- goto out_cache;
+ goto out;
}
- cs_slot->sl_seqid++; /* from 0 to 1 */
- move_to_confirmed(unconf);
-
- if (cr_ses->flags & SESSION4_BACK_CHAN) {
- unconf->cl_cb_conn.cb_xprt = rqstp->rq_xprt;
- svc_xprt_get(rqstp->rq_xprt);
- rpc_copy_addr(
- (struct sockaddr *)&unconf->cl_cb_conn.cb_addr,
- sa);
- unconf->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
- unconf->cl_cb_conn.cb_minorversion =
- cstate->minorversion;
- unconf->cl_cb_conn.cb_prog = cr_ses->callback_prog;
- unconf->cl_cb_seq_nr = 1;
- nfsd4_probe_callback(unconf, &unconf->cl_cb_conn);
- }
+ confirm_me = true;
conf = unconf;
} else {
status = nfserr_stale_clientid;
@@ -1477,22 +1539,30 @@ nfsd4_create_session(struct svc_rqst *rqstp,
}
/*
+ * XXX: we should probably set this at creation time, and check
+ * for consistent minorversion use throughout:
+ */
+ conf->cl_minorversion = 1;
+ /*
* We do not support RDMA or persistent sessions
*/
cr_ses->flags &= ~SESSION4_PERSIST;
cr_ses->flags &= ~SESSION4_RDMA;
- status = alloc_init_session(rqstp, conf, cr_ses);
- if (status)
+ status = nfserr_jukebox;
+ new = alloc_init_session(rqstp, conf, cr_ses);
+ if (!new)
goto out;
-
- memcpy(cr_ses->sessionid.data, conf->cl_sessionid.data,
+ status = nfs_ok;
+ memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
NFS4_MAX_SESSIONID_LEN);
+ cs_slot->sl_seqid++;
cr_ses->seqid = cs_slot->sl_seqid;
-out_cache:
/* cache solo and embedded create sessions under the state lock */
nfsd4_cache_create_session(cr_ses, cs_slot, status);
+ if (confirm_me)
+ move_to_confirmed(conf);
out:
nfs4_unlock_state();
dprintk("%s returns %d\n", __func__, ntohl(status));
@@ -1546,8 +1616,11 @@ nfsd4_destroy_session(struct svc_rqst *r,
nfs4_lock_state();
/* wait for callbacks */
- nfsd4_set_callback_client(ses->se_client, NULL);
+ nfsd4_shutdown_callback(ses->se_client);
nfs4_unlock_state();
+
+ nfsd4_del_conns(ses);
+
nfsd4_put_session(ses);
status = nfs_ok;
out:
@@ -1555,6 +1628,36 @@ out:
return status;
}
+static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s)
+{
+ struct nfsd4_conn *c;
+
+ list_for_each_entry(c, &s->se_conns, cn_persession) {
+ if (c->cn_xprt == xpt) {
+ return c;
+ }
+ }
+ return NULL;
+}
+
+static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
+{
+ struct nfs4_client *clp = ses->se_client;
+ struct nfsd4_conn *c;
+
+ spin_lock(&clp->cl_lock);
+ c = __nfsd4_find_conn(new->cn_xprt, ses);
+ if (c) {
+ spin_unlock(&clp->cl_lock);
+ free_conn(new);
+ return;
+ }
+ __nfsd4_hash_conn(new, ses);
+ spin_unlock(&clp->cl_lock);
+ nfsd4_register_conn(new);
+ return;
+}
+
__be32
nfsd4_sequence(struct svc_rqst *rqstp,
struct nfsd4_compound_state *cstate,
@@ -1563,11 +1666,20 @@ nfsd4_sequence(struct svc_rqst *rqstp,
struct nfsd4_compoundres *resp = rqstp->rq_resp;
struct nfsd4_session *session;
struct nfsd4_slot *slot;
+ struct nfsd4_conn *conn;
int status;
if (resp->opcnt != 1)
return nfserr_sequence_pos;
+ /*
+ * Will be either used or freed by nfsd4_sequence_check_conn
+ * below.
+ */
+ conn = alloc_conn(rqstp, NFS4_CDFC4_FORE);
+ if (!conn)
+ return nfserr_jukebox;
+
spin_lock(&client_lock);
status = nfserr_badsession;
session = find_in_sessionid_hashtbl(&seq->sessionid);
@@ -1599,6 +1711,9 @@ nfsd4_sequence(struct svc_rqst *rqstp,
if (status)
goto out;
+ nfsd4_sequence_check_conn(conn, session);
+ conn = NULL;
+
/* Success! bump slot seqid */
slot->sl_inuse = true;
slot->sl_seqid = seq->seqid;
@@ -1613,6 +1728,7 @@ out:
nfsd4_get_session(cstate->session);
atomic_inc(&session->se_client->cl_refcount);
}
+ kfree(conn);
spin_unlock(&client_lock);
dprintk("%s: return %d\n", __func__, ntohl(status));
return status;
@@ -1747,6 +1863,11 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
gen_clid(new);
}
+ /*
+ * XXX: we should probably set this at creation time, and check
+ * for consistent minorversion use throughout:
+ */
+ new->cl_minorversion = 0;
gen_callback(new, setclid, rpc_get_scope_id(sa));
add_to_unconfirmed(new, strhashval);
setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
@@ -1807,7 +1928,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
status = nfserr_clid_inuse;
else {
atomic_set(&conf->cl_cb_set, 0);
- nfsd4_probe_callback(conf, &unconf->cl_cb_conn);
+ nfsd4_change_callback(conf, &unconf->cl_cb_conn);
+ nfsd4_probe_callback(conf);
expire_client(unconf);
status = nfs_ok;
@@ -1841,7 +1963,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
}
move_to_confirmed(unconf);
conf = unconf;
- nfsd4_probe_callback(conf, &conf->cl_cb_conn);
+ nfsd4_probe_callback(conf);
status = nfs_ok;
}
} else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))
@@ -2492,7 +2614,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
struct nfs4_delegation *dp;
struct nfs4_stateowner *sop = stp->st_stateowner;
int cb_up = atomic_read(&sop->so_client->cl_cb_set);
- struct file_lock fl, *flp = &fl;
+ struct file_lock *fl;
int status, flag = 0;
flag = NFS4_OPEN_DELEGATE_NONE;
@@ -2526,20 +2648,24 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
flag = NFS4_OPEN_DELEGATE_NONE;
goto out;
}
- locks_init_lock(&fl);
- fl.fl_lmops = &nfsd_lease_mng_ops;
- fl.fl_flags = FL_LEASE;
- fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
- fl.fl_end = OFFSET_MAX;
- fl.fl_owner = (fl_owner_t)dp;
- fl.fl_file = find_readable_file(stp->st_file);
- BUG_ON(!fl.fl_file);
- fl.fl_pid = current->tgid;
+ status = -ENOMEM;
+ fl = locks_alloc_lock();
+ if (!fl)
+ goto out;
+ locks_init_lock(fl);
+ fl->fl_lmops = &nfsd_lease_mng_ops;
+ fl->fl_flags = FL_LEASE;
+ fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
+ fl->fl_end = OFFSET_MAX;
+ fl->fl_owner = (fl_owner_t)dp;
+ fl->fl_file = find_readable_file(stp->st_file);
+ BUG_ON(!fl->fl_file);
+ fl->fl_pid = current->tgid;
/* vfs_setlease checks to see if delegation should be handed out.
* the lock_manager callbacks fl_mylease and fl_change are used
*/
- if ((status = vfs_setlease(fl.fl_file, fl.fl_type, &flp))) {
+ if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) {
dprintk("NFSD: setlease failed [%d], no delegation\n", status);
unhash_delegation(dp);
flag = NFS4_OPEN_DELEGATE_NONE;
@@ -2944,7 +3070,11 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
if (STALE_STATEID(stateid))
goto out;
- status = nfserr_bad_stateid;
+ /*
+ * 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)
@@ -2964,6 +3094,7 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
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)
@@ -3038,8 +3169,9 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
* 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_bad_stateid;
+ return nfserr_expired;
*sopp = sop;
goto check_replay;
}
@@ -3304,6 +3436,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfserr_bad_stateid;
if (!is_delegation_stateid(stateid))
goto out;
+ status = nfserr_expired;
dp = find_delegation_stateid(inode, stateid);
if (!dp)
goto out;
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 1a468bbd330f..f35a94a04026 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1805,19 +1805,23 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
goto out_nfserr;
}
}
- if ((buflen -= 16) < 0)
- goto out_resource;
- if (unlikely(bmval2)) {
+ if (bmval2) {
+ if ((buflen -= 16) < 0)
+ goto out_resource;
WRITE32(3);
WRITE32(bmval0);
WRITE32(bmval1);
WRITE32(bmval2);
- } else if (likely(bmval1)) {
+ } else if (bmval1) {
+ if ((buflen -= 12) < 0)
+ goto out_resource;
WRITE32(2);
WRITE32(bmval0);
WRITE32(bmval1);
} else {
+ if ((buflen -= 8) < 0)
+ goto out_resource;
WRITE32(1);
WRITE32(bmval0);
}
@@ -1828,15 +1832,17 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
u32 word1 = nfsd_suppattrs1(minorversion);
u32 word2 = nfsd_suppattrs2(minorversion);
- if ((buflen -= 12) < 0)
- goto out_resource;
if (!aclsupport)
word0 &= ~FATTR4_WORD0_ACL;
if (!word2) {
+ if ((buflen -= 12) < 0)
+ goto out_resource;
WRITE32(2);
WRITE32(word0);
WRITE32(word1);
} else {
+ if ((buflen -= 16) < 0)
+ goto out_resource;
WRITE32(3);
WRITE32(word0);
WRITE32(word1);
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 06fa87e52e82..d6dc3f61f8ba 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -22,6 +22,7 @@
*/
enum {
NFSD_Root = 1,
+#ifdef CONFIG_NFSD_DEPRECATED
NFSD_Svc,
NFSD_Add,
NFSD_Del,
@@ -29,6 +30,7 @@ enum {
NFSD_Unexport,
NFSD_Getfd,
NFSD_Getfs,
+#endif
NFSD_List,
NFSD_Export_features,
NFSD_Fh,
@@ -54,6 +56,7 @@ enum {
/*
* write() for these nodes.
*/
+#ifdef CONFIG_NFSD_DEPRECATED
static ssize_t write_svc(struct file *file, char *buf, size_t size);
static ssize_t write_add(struct file *file, char *buf, size_t size);
static ssize_t write_del(struct file *file, char *buf, size_t size);
@@ -61,6 +64,7 @@ static ssize_t write_export(struct file *file, char *buf, size_t size);
static ssize_t write_unexport(struct file *file, char *buf, size_t size);
static ssize_t write_getfd(struct file *file, char *buf, size_t size);
static ssize_t write_getfs(struct file *file, char *buf, size_t size);
+#endif
static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
@@ -76,6 +80,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
#endif
static ssize_t (*write_op[])(struct file *, char *, size_t) = {
+#ifdef CONFIG_NFSD_DEPRECATED
[NFSD_Svc] = write_svc,
[NFSD_Add] = write_add,
[NFSD_Del] = write_del,
@@ -83,6 +88,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
[NFSD_Unexport] = write_unexport,
[NFSD_Getfd] = write_getfd,
[NFSD_Getfs] = write_getfs,
+#endif
[NFSD_Fh] = write_filehandle,
[NFSD_FO_UnlockIP] = write_unlock_ip,
[NFSD_FO_UnlockFS] = write_unlock_fs,
@@ -121,6 +127,14 @@ static ssize_t nfsctl_transaction_write(struct file *file, const char __user *bu
static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
{
+ static int warned;
+ if (file->f_dentry->d_name.name[0] == '.' && !warned) {
+ printk(KERN_INFO
+ "Warning: \"%s\" uses deprecated NFSD interface: %s."
+ " This will be removed in 2.6.40\n",
+ current->comm, file->f_dentry->d_name.name);
+ warned = 1;
+ }
if (! file->private_data) {
/* An attempt to read a transaction file without writing
* causes a 0-byte write so that the file can return
@@ -187,6 +201,7 @@ static const struct file_operations pool_stats_operations = {
* payload - write methods
*/
+#ifdef CONFIG_NFSD_DEPRECATED
/**
* write_svc - Start kernel's NFSD server
*
@@ -402,7 +417,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size)
ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
- clp = auth_unix_lookup(&in6);
+ clp = auth_unix_lookup(&init_net, &in6);
if (!clp)
err = -EPERM;
else {
@@ -465,7 +480,7 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
- clp = auth_unix_lookup(&in6);
+ clp = auth_unix_lookup(&init_net, &in6);
if (!clp)
err = -EPERM;
else {
@@ -482,6 +497,7 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
out:
return err;
}
+#endif /* CONFIG_NFSD_DEPRECATED */
/**
* write_unlock_ip - Release all locks used by a client
@@ -1000,12 +1016,12 @@ static ssize_t __write_ports_addxprt(char *buf)
if (err != 0)
return err;
- err = svc_create_xprt(nfsd_serv, transport,
+ err = svc_create_xprt(nfsd_serv, transport, &init_net,
PF_INET, port, SVC_SOCK_ANONYMOUS);
if (err < 0)
goto out_err;
- err = svc_create_xprt(nfsd_serv, transport,
+ err = svc_create_xprt(nfsd_serv, transport, &init_net,
PF_INET6, port, SVC_SOCK_ANONYMOUS);
if (err < 0 && err != -EAFNOSUPPORT)
goto out_close;
@@ -1356,6 +1372,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
{
static struct tree_descr nfsd_files[] = {
+#ifdef CONFIG_NFSD_DEPRECATED
[NFSD_Svc] = {".svc", &transaction_ops, S_IWUSR},
[NFSD_Add] = {".add", &transaction_ops, S_IWUSR},
[NFSD_Del] = {".del", &transaction_ops, S_IWUSR},
@@ -1363,6 +1380,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
[NFSD_Unexport] = {".unexport", &transaction_ops, S_IWUSR},
[NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR},
+#endif
[NFSD_List] = {"exports", &exports_operations, S_IRUGO},
[NFSD_Export_features] = {"export_features",
&export_features_operations, S_IRUGO},
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index b76ac3a82e39..6b641cf2c19a 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -249,7 +249,7 @@ extern time_t nfsd4_grace;
#define COMPOUND_SLACK_SPACE 140 /* OP_GETFH */
#define COMPOUND_ERR_SLACK_SPACE 12 /* OP_SETATTR */
-#define NFSD_LAUNDROMAT_MINTIMEOUT 10 /* seconds */
+#define NFSD_LAUNDROMAT_MINTIMEOUT 1 /* seconds */
/*
* The following attributes are currently not supported by the NFSv4 server:
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index e2c43464f237..2bae1d86f5f2 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -16,6 +16,7 @@
#include <linux/lockd/bind.h>
#include <linux/nfsacl.h>
#include <linux/seq_file.h>
+#include <net/net_namespace.h>
#include "nfsd.h"
#include "cache.h"
#include "vfs.h"
@@ -186,12 +187,12 @@ static int nfsd_init_socks(int port)
if (!list_empty(&nfsd_serv->sv_permsocks))
return 0;
- error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port,
+ error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, port,
SVC_SOCK_DEFAULTS);
if (error < 0)
return error;
- error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port,
+ error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, port,
SVC_SOCK_DEFAULTS);
if (error < 0)
return error;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 322518c88e4b..39adc27b0685 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/sunrpc/svc_xprt.h>
#include <linux/nfsd/nfsfh.h>
#include "nfsfh.h"
@@ -64,19 +65,12 @@ typedef struct {
(s)->si_fileid, \
(s)->si_generation
-struct nfsd4_cb_sequence {
- /* args/res */
- u32 cbs_minorversion;
- struct nfs4_client *cbs_clp;
-};
-
-struct nfs4_rpc_args {
- void *args_op;
- struct nfsd4_cb_sequence args_seq;
-};
-
struct nfsd4_callback {
- struct nfs4_rpc_args cb_args;
+ void *cb_op;
+ struct nfs4_client *cb_clp;
+ u32 cb_minorversion;
+ struct rpc_message cb_msg;
+ const struct rpc_call_ops *cb_ops;
struct work_struct cb_work;
};
@@ -91,7 +85,6 @@ struct nfs4_delegation {
u32 dl_type;
time_t dl_time;
/* For recall: */
- u32 dl_ident;
stateid_t dl_stateid;
struct knfsd_fh dl_fh;
int dl_retries;
@@ -103,8 +96,8 @@ struct nfs4_cb_conn {
/* SETCLIENTID info */
struct sockaddr_storage cb_addr;
size_t cb_addrlen;
- u32 cb_prog;
- u32 cb_minorversion;
+ u32 cb_prog; /* used only in 4.0 case;
+ per-session otherwise */
u32 cb_ident; /* minorversion 0 only */
struct svc_xprt *cb_xprt; /* minorversion 1 only */
};
@@ -160,6 +153,15 @@ struct nfsd4_clid_slot {
struct nfsd4_create_session sl_cr_ses;
};
+struct nfsd4_conn {
+ struct list_head cn_persession;
+ struct svc_xprt *cn_xprt;
+ struct svc_xpt_user cn_xpt_user;
+ struct nfsd4_session *cn_session;
+/* CDFC4_FORE, CDFC4_BACK: */
+ unsigned char cn_flags;
+};
+
struct nfsd4_session {
struct kref se_ref;
struct list_head se_hash; /* hash by sessionid */
@@ -169,6 +171,9 @@ struct nfsd4_session {
struct nfs4_sessionid se_sessionid;
struct nfsd4_channel_attrs se_fchannel;
struct nfsd4_channel_attrs se_bchannel;
+ struct list_head se_conns;
+ u32 se_cb_prog;
+ u32 se_cb_seq_nr;
struct nfsd4_slot *se_slots[]; /* forward channel slots */
};
@@ -221,24 +226,32 @@ struct nfs4_client {
clientid_t cl_clientid; /* generated by server */
nfs4_verifier cl_confirm; /* generated by server */
u32 cl_firststate; /* recovery dir creation */
+ u32 cl_minorversion;
/* for v4.0 and v4.1 callbacks: */
struct nfs4_cb_conn cl_cb_conn;
+#define NFSD4_CLIENT_CB_UPDATE 1
+#define NFSD4_CLIENT_KILL 2
+ unsigned long cl_cb_flags;
struct rpc_clnt *cl_cb_client;
+ u32 cl_cb_ident;
atomic_t cl_cb_set;
+ struct nfsd4_callback cl_cb_null;
+ struct nfsd4_session *cl_cb_session;
+
+ /* for all client information that callback code might need: */
+ spinlock_t cl_lock;
/* for nfs41 */
struct list_head cl_sessions;
struct nfsd4_clid_slot cl_cs_slot; /* create_session slot */
u32 cl_exchange_flags;
- struct nfs4_sessionid cl_sessionid;
/* number of rpc's in progress over an associated session: */
atomic_t cl_refcount;
/* for nfs41 callbacks */
/* We currently support a single back channel with a single slot */
unsigned long cl_cb_slot_busy;
- u32 cl_cb_seq_nr;
struct rpc_wait_queue cl_cb_waitq; /* backchannel callers may */
/* wait here for slots */
};
@@ -440,12 +453,13 @@ extern int nfs4_in_grace(void);
extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
extern void nfs4_free_stateowner(struct kref *kref);
extern int set_callback_cred(void);
-extern void nfsd4_probe_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
+extern void nfsd4_probe_callback(struct nfs4_client *clp);
+extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
extern void nfsd4_do_callback_rpc(struct work_struct *);
extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
extern int nfsd4_create_callback_queue(void);
extern void nfsd4_destroy_callback_queue(void);
-extern void nfsd4_set_callback_client(struct nfs4_client *, struct rpc_clnt *);
+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);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 661a6cf8e826..184938fcff04 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -281,23 +281,13 @@ commit_metadata(struct svc_fh *fhp)
{
struct inode *inode = fhp->fh_dentry->d_inode;
const struct export_operations *export_ops = inode->i_sb->s_export_op;
- int error = 0;
if (!EX_ISSYNC(fhp->fh_export))
return 0;
- if (export_ops->commit_metadata) {
- error = export_ops->commit_metadata(inode);
- } else {
- struct writeback_control wbc = {
- .sync_mode = WB_SYNC_ALL,
- .nr_to_write = 0, /* metadata only */
- };
-
- error = sync_inode(inode, &wbc);
- }
-
- return error;
+ if (export_ops->commit_metadata)
+ return export_ops->commit_metadata(inode);
+ return sync_inode_metadata(inode, 1);
}
/*
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
index 185d1607cb00..6e9557ecf161 100644
--- a/fs/nilfs2/namei.c
+++ b/fs/nilfs2/namei.c
@@ -207,7 +207,7 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir,
inode->i_ctime = CURRENT_TIME;
inode_inc_link_count(inode);
- atomic_inc(&inode->i_count);
+ ihold(inode);
err = nilfs_add_nondir(dentry, inode);
if (!err)
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
index d926af626177..687d090cea34 100644
--- a/fs/nilfs2/segment.c
+++ b/fs/nilfs2/segment.c
@@ -1609,7 +1609,7 @@ nilfs_copy_replace_page_buffers(struct page *page, struct list_head *out)
kunmap_atomic(kaddr, KM_USER0);
if (!TestSetPageWriteback(clone_page))
- inc_zone_page_state(clone_page, NR_WRITEBACK);
+ account_page_writeback(clone_page);
unlock_page(clone_page);
return 0;
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 36802420d69a..4498a208df94 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -88,8 +88,6 @@ void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
{
struct dentry *parent;
struct inode *p_inode;
- bool send = false;
- bool should_update_children = false;
if (!dentry)
dentry = path->dentry;
@@ -97,29 +95,12 @@ void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED))
return;
- spin_lock(&dentry->d_lock);
- parent = dentry->d_parent;
+ parent = dget_parent(dentry);
p_inode = parent->d_inode;
- if (fsnotify_inode_watches_children(p_inode)) {
- if (p_inode->i_fsnotify_mask & mask) {
- dget(parent);
- send = true;
- }
- } else {
- /*
- * The parent doesn't care about events on it's children but
- * at least one child thought it did. We need to run all the
- * children and update their d_flags to let them know p_inode
- * doesn't care about them any more.
- */
- dget(parent);
- should_update_children = true;
- }
-
- spin_unlock(&dentry->d_lock);
-
- if (send) {
+ if (unlikely(!fsnotify_inode_watches_children(p_inode)))
+ __fsnotify_update_child_dentry_flags(p_inode);
+ else if (p_inode->i_fsnotify_mask & mask) {
/* we are notifying a parent so come up with the new mask which
* specifies these are events which came from a child. */
mask |= FS_EVENT_ON_CHILD;
@@ -130,13 +111,9 @@ void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
else
fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
dentry->d_name.name, 0);
- dput(parent);
}
- if (unlikely(should_update_children)) {
- __fsnotify_update_child_dentry_flags(p_inode);
- dput(parent);
- }
+ dput(parent);
}
EXPORT_SYMBOL_GPL(__fsnotify_parent);
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c
index 33297c005060..21ed10660b80 100644
--- a/fs/notify/inode_mark.c
+++ b/fs/notify/inode_mark.c
@@ -240,6 +240,7 @@ void fsnotify_unmount_inodes(struct list_head *list)
{
struct inode *inode, *next_i, *need_iput = NULL;
+ spin_lock(&inode_lock);
list_for_each_entry_safe(inode, next_i, list, i_sb_list) {
struct inode *need_iput_tmp;
@@ -297,4 +298,5 @@ void fsnotify_unmount_inodes(struct list_head *list)
spin_lock(&inode_lock);
}
+ spin_unlock(&inode_lock);
}
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 19c5180f8a28..d3fbe5730bfc 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -2911,8 +2911,8 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
goto unl_upcase_iput_tmp_ino_err_out_now;
}
if ((sb->s_root = d_alloc_root(vol->root_ino))) {
- /* We increment i_count simulating an ntfs_iget(). */
- atomic_inc(&vol->root_ino->i_count);
+ /* We grab a reference, simulating an ntfs_iget(). */
+ ihold(vol->root_ino);
ntfs_debug("Exiting, status successful.");
/* Release the default upcase if it has no users. */
mutex_lock(&ntfs_lock);
@@ -3021,21 +3021,6 @@ iput_tmp_ino_err_out_now:
if (vol->mft_ino && vol->mft_ino != tmp_ino)
iput(vol->mft_ino);
vol->mft_ino = NULL;
- /*
- * This is needed to get ntfs_clear_extent_inode() called for each
- * inode we have ever called ntfs_iget()/iput() on, otherwise we A)
- * leak resources and B) a subsequent mount fails automatically due to
- * ntfs_iget() never calling down into our ntfs_read_locked_inode()
- * method again... FIXME: Do we need to do this twice now because of
- * attribute inodes? I think not, so leave as is for now... (AIA)
- */
- if (invalidate_inodes(sb)) {
- ntfs_error(sb, "Busy inodes left. This is most likely a NTFS "
- "driver bug.");
- /* Copied from fs/super.c. I just love this message. (-; */
- printk("NTFS: Busy inodes after umount. Self-destruct in 5 "
- "seconds. Have a nice day...\n");
- }
/* Errors at this stage are irrelevant. */
err_out_now:
sb->s_fs_info = NULL;
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 5cfeee118158..f1e962cb3b73 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -165,7 +165,7 @@ int ocfs2_get_block(struct inode *inode, sector_t iblock,
* ocfs2 never allocates in this function - the only time we
* need to use BH_New is when we're extending i_size on a file
* system which doesn't support holes, in which case BH_New
- * allows block_prepare_write() to zero.
+ * allows __block_write_begin() to zero.
*
* If we see this on a sparse file system, then a truncate has
* raced us and removed the cluster. In this case, we clear
@@ -407,21 +407,6 @@ static int ocfs2_writepage(struct page *page, struct writeback_control *wbc)
return ret;
}
-/*
- * This is called from ocfs2_write_zero_page() which has handled it's
- * own cluster locking and has ensured allocation exists for those
- * blocks to be written.
- */
-int ocfs2_prepare_write_nolock(struct inode *inode, struct page *page,
- unsigned from, unsigned to)
-{
- int ret;
-
- ret = block_prepare_write(page, from, to, ocfs2_get_block);
-
- return ret;
-}
-
/* Taken from ext3. We don't necessarily need the full blown
* functionality yet, but IMHO it's better to cut and paste the whole
* thing so we can avoid introducing our own bugs (and easily pick up
@@ -732,7 +717,7 @@ static int ocfs2_should_read_blk(struct inode *inode, struct page *page,
}
/*
- * Some of this taken from block_prepare_write(). We already have our
+ * Some of this taken from __block_write_begin(). We already have our
* mapping by now though, and the entire write will be allocating or
* it won't, so not much need to use BH_New.
*
diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h
index 7606f663da6d..76bfdfda691a 100644
--- a/fs/ocfs2/aops.h
+++ b/fs/ocfs2/aops.h
@@ -22,9 +22,6 @@
#ifndef OCFS2_AOPS_H
#define OCFS2_AOPS_H
-int ocfs2_prepare_write_nolock(struct inode *inode, struct page *page,
- unsigned from, unsigned to);
-
handle_t *ocfs2_start_walk_page_trans(struct inode *inode,
struct page *page,
unsigned from,
diff --git a/fs/ocfs2/cluster/tcp_internal.h b/fs/ocfs2/cluster/tcp_internal.h
index 96fa7ebc530c..15fdbdf9eb4b 100644
--- a/fs/ocfs2/cluster/tcp_internal.h
+++ b/fs/ocfs2/cluster/tcp_internal.h
@@ -129,7 +129,7 @@ struct o2net_node {
struct o2net_sock_container {
struct kref sc_kref;
- /* the next two are vaild for the life time of the sc */
+ /* the next two are valid for the life time of the sc */
struct socket *sc_sock;
struct o2nm_node *sc_node;
diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c
index a7ebd9d42dc8..75e115f1bd73 100644
--- a/fs/ocfs2/dlmfs/dlmfs.c
+++ b/fs/ocfs2/dlmfs/dlmfs.c
@@ -400,6 +400,7 @@ static struct inode *dlmfs_get_root_inode(struct super_block *sb)
if (inode) {
ip = DLMFS_I(inode);
+ inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
@@ -425,6 +426,7 @@ static struct inode *dlmfs_get_inode(struct inode *parent,
if (!inode)
return NULL;
+ inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 1ca6867935bb..77b4c04a2809 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -796,13 +796,12 @@ static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from,
block_end = block_start + (1 << inode->i_blkbits);
/*
- * block_start is block-aligned. Bump it by one to
- * force ocfs2_{prepare,commit}_write() to zero the
+ * block_start is block-aligned. Bump it by one to force
+ * __block_write_begin and block_commit_write to zero the
* whole block.
*/
- ret = ocfs2_prepare_write_nolock(inode, page,
- block_start + 1,
- block_start + 1);
+ ret = __block_write_begin(page, block_start + 1, 0,
+ ocfs2_get_block);
if (ret < 0) {
mlog_errno(ret);
goto out_unlock;
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index e7bde21149ae..ff5744e1e36f 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -742,7 +742,7 @@ static int ocfs2_link(struct dentry *old_dentry,
goto out_commit;
}
- atomic_inc(&inode->i_count);
+ ihold(inode);
dentry->d_op = &ocfs2_dentry_ops;
d_instantiate(dentry, inode);
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index b81bfc016a05..0a8b0ad0c7e2 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -365,25 +365,17 @@ struct device_type part_type = {
static void delete_partition_rcu_cb(struct rcu_head *head)
{
struct hd_struct *part = container_of(head, struct hd_struct, rcu_head);
- struct gendisk *disk = part_to_disk(part);
- struct request_queue *q = disk->queue;
- unsigned long flags;
part->start_sect = 0;
part->nr_sects = 0;
part_stat_set_all(part, 0);
put_device(part_to_dev(part));
-
- spin_lock_irqsave(q->queue_lock, flags);
- elv_quiesce_end(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
}
void delete_partition(struct gendisk *disk, int partno)
{
struct disk_part_tbl *ptbl = disk->part_tbl;
struct hd_struct *part;
- struct request_queue *q = disk->queue;
if (partno >= ptbl->len)
return;
@@ -398,10 +390,6 @@ void delete_partition(struct gendisk *disk, int partno)
kobject_put(part->holder_dir);
device_del(part_to_dev(part));
- spin_lock_irq(q->queue_lock);
- elv_quiesce_start(q);
- spin_unlock_irq(q->queue_lock);
-
call_rcu(&part->rcu_head, delete_partition_rcu_cb);
}
diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c
index 5bf8a04b5d9b..789c625c7aa5 100644
--- a/fs/partitions/ldm.c
+++ b/fs/partitions/ldm.c
@@ -5,7 +5,7 @@
* Copyright (c) 2001-2007 Anton Altaparmakov
* Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
*
- * Documentation is available at http://www.linux-ntfs.org/content/view/19/37/
+ * Documentation is available at http://www.linux-ntfs.org/doku.php?id=downloads
*
* 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
diff --git a/fs/partitions/ldm.h b/fs/partitions/ldm.h
index d1fb50b28d86..374242c0971a 100644
--- a/fs/partitions/ldm.h
+++ b/fs/partitions/ldm.h
@@ -5,7 +5,7 @@
* Copyright (c) 2001-2007 Anton Altaparmakov
* Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
*
- * Documentation is available at http://www.linux-ntfs.org/content/view/19/37/
+ * Documentation is available at http://www.linux-ntfs.org/doku.php?id=downloads
*
* 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
diff --git a/fs/pipe.c b/fs/pipe.c
index 37eb1ebeaa90..d2d7566ce68e 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -954,6 +954,8 @@ static struct inode * get_pipe_inode(void)
if (!inode)
goto fail_inode;
+ inode->i_ino = get_next_ino();
+
pipe = alloc_pipe_info(inode);
if (!pipe)
goto fail_iput;
diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig
index 50f8f0600f06..6a0068841d96 100644
--- a/fs/proc/Kconfig
+++ b/fs/proc/Kconfig
@@ -33,8 +33,8 @@ config PROC_KCORE
depends on PROC_FS && MMU
config PROC_VMCORE
- bool "/proc/vmcore support (EXPERIMENTAL)"
- depends on PROC_FS && CRASH_DUMP
+ bool "/proc/vmcore support"
+ depends on PROC_FS && CRASH_DUMP
default y
help
Exports the dump image of crashed kernel in ELF format.
diff --git a/fs/proc/base.c b/fs/proc/base.c
index dc5d5f51f3fe..f3d02ca461ec 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -226,7 +226,7 @@ struct mm_struct *mm_for_maps(struct task_struct *task)
{
struct mm_struct *mm;
- if (mutex_lock_killable(&task->cred_guard_mutex))
+ if (mutex_lock_killable(&task->signal->cred_guard_mutex))
return NULL;
mm = get_task_mm(task);
@@ -235,7 +235,7 @@ struct mm_struct *mm_for_maps(struct task_struct *task)
mmput(mm);
mm = NULL;
}
- mutex_unlock(&task->cred_guard_mutex);
+ mutex_unlock(&task->signal->cred_guard_mutex);
return mm;
}
@@ -771,6 +771,8 @@ static const struct file_operations proc_single_file_operations = {
static int mem_open(struct inode* inode, struct file* file)
{
file->private_data = (void*)((long)current->self_exec_id);
+ /* OK to pass negative loff_t, we can catch out-of-range */
+ file->f_mode |= FMODE_UNSIGNED_OFFSET;
return 0;
}
@@ -1023,28 +1025,47 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
memset(buffer, 0, sizeof(buffer));
if (count > sizeof(buffer) - 1)
count = sizeof(buffer) - 1;
- if (copy_from_user(buffer, buf, count))
- return -EFAULT;
+ if (copy_from_user(buffer, buf, count)) {
+ err = -EFAULT;
+ goto out;
+ }
err = strict_strtol(strstrip(buffer), 0, &oom_adjust);
if (err)
- return -EINVAL;
+ goto out;
if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) &&
- oom_adjust != OOM_DISABLE)
- return -EINVAL;
+ oom_adjust != OOM_DISABLE) {
+ err = -EINVAL;
+ goto out;
+ }
task = get_proc_task(file->f_path.dentry->d_inode);
- if (!task)
- return -ESRCH;
+ if (!task) {
+ err = -ESRCH;
+ goto out;
+ }
+
+ task_lock(task);
+ if (!task->mm) {
+ err = -EINVAL;
+ goto err_task_lock;
+ }
+
if (!lock_task_sighand(task, &flags)) {
- put_task_struct(task);
- return -ESRCH;
+ err = -ESRCH;
+ goto err_task_lock;
}
if (oom_adjust < task->signal->oom_adj && !capable(CAP_SYS_RESOURCE)) {
- unlock_task_sighand(task, &flags);
- put_task_struct(task);
- return -EACCES;
+ err = -EACCES;
+ goto err_sighand;
+ }
+
+ if (oom_adjust != task->signal->oom_adj) {
+ if (oom_adjust == OOM_DISABLE)
+ atomic_inc(&task->mm->oom_disable_count);
+ if (task->signal->oom_adj == OOM_DISABLE)
+ atomic_dec(&task->mm->oom_disable_count);
}
/*
@@ -1065,10 +1086,13 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
else
task->signal->oom_score_adj = (oom_adjust * OOM_SCORE_ADJ_MAX) /
-OOM_DISABLE;
+err_sighand:
unlock_task_sighand(task, &flags);
+err_task_lock:
+ task_unlock(task);
put_task_struct(task);
-
- return count;
+out:
+ return err < 0 ? err : count;
}
static const struct file_operations proc_oom_adjust_operations = {
@@ -1109,30 +1133,49 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
memset(buffer, 0, sizeof(buffer));
if (count > sizeof(buffer) - 1)
count = sizeof(buffer) - 1;
- if (copy_from_user(buffer, buf, count))
- return -EFAULT;
+ if (copy_from_user(buffer, buf, count)) {
+ err = -EFAULT;
+ goto out;
+ }
err = strict_strtol(strstrip(buffer), 0, &oom_score_adj);
if (err)
- return -EINVAL;
+ goto out;
if (oom_score_adj < OOM_SCORE_ADJ_MIN ||
- oom_score_adj > OOM_SCORE_ADJ_MAX)
- return -EINVAL;
+ oom_score_adj > OOM_SCORE_ADJ_MAX) {
+ err = -EINVAL;
+ goto out;
+ }
task = get_proc_task(file->f_path.dentry->d_inode);
- if (!task)
- return -ESRCH;
+ if (!task) {
+ err = -ESRCH;
+ goto out;
+ }
+
+ task_lock(task);
+ if (!task->mm) {
+ err = -EINVAL;
+ goto err_task_lock;
+ }
+
if (!lock_task_sighand(task, &flags)) {
- put_task_struct(task);
- return -ESRCH;
+ err = -ESRCH;
+ goto err_task_lock;
}
+
if (oom_score_adj < task->signal->oom_score_adj &&
!capable(CAP_SYS_RESOURCE)) {
- unlock_task_sighand(task, &flags);
- put_task_struct(task);
- return -EACCES;
+ err = -EACCES;
+ goto err_sighand;
}
+ if (oom_score_adj != task->signal->oom_score_adj) {
+ if (oom_score_adj == OOM_SCORE_ADJ_MIN)
+ atomic_inc(&task->mm->oom_disable_count);
+ if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
+ atomic_dec(&task->mm->oom_disable_count);
+ }
task->signal->oom_score_adj = oom_score_adj;
/*
* Scale /proc/pid/oom_adj appropriately ensuring that OOM_DISABLE is
@@ -1143,9 +1186,13 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
else
task->signal->oom_adj = (oom_score_adj * OOM_ADJUST_MAX) /
OOM_SCORE_ADJ_MAX;
+err_sighand:
unlock_task_sighand(task, &flags);
+err_task_lock:
+ task_unlock(task);
put_task_struct(task);
- return count;
+out:
+ return err < 0 ? err : count;
}
static const struct file_operations proc_oom_score_adj_operations = {
@@ -1601,6 +1648,7 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st
/* Common stuff */
ei = PROC_I(inode);
+ inode->i_ino = get_next_ino();
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_op = &proc_def_inode_operations;
@@ -2306,14 +2354,14 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
goto out_free;
/* Guard against adverse ptrace interaction */
- length = mutex_lock_interruptible(&task->cred_guard_mutex);
+ length = mutex_lock_interruptible(&task->signal->cred_guard_mutex);
if (length < 0)
goto out_free;
length = security_setprocattr(task,
(char*)file->f_path.dentry->d_name.name,
(void*)page, count);
- mutex_unlock(&task->cred_guard_mutex);
+ mutex_unlock(&task->signal->cred_guard_mutex);
out_free:
free_page((unsigned long) page);
out:
@@ -2547,6 +2595,7 @@ static struct dentry *proc_base_instantiate(struct inode *dir,
/* Initialize the inode */
ei = PROC_I(inode);
+ inode->i_ino = get_next_ino();
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
/*
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 2fc52552271d..b652cb00906b 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -23,6 +23,8 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
if (!inode)
goto out;
+ inode->i_ino = get_next_ino();
+
sysctl_head_get(head);
ei = PROC_I(inode);
ei->sysctl = head;
diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c
index dc44f94022f1..83adcc869437 100644
--- a/fs/proc/proc_tty.c
+++ b/fs/proc/proc_tty.c
@@ -12,10 +12,7 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/console.h>
#include <linux/seq_file.h>
-#include <linux/fdtable.h>
#include <linux/bitops.h>
/*
@@ -140,160 +137,6 @@ static const struct file_operations proc_tty_drivers_operations = {
};
/*
- * The device ID of file descriptor 0 of the current reading
- * task if a character device...
- */
-static dev_t current_dev;
-
-/*
- * This is the handler for /proc/tty/consoles
- */
-static int show_console_dev(struct seq_file *m, void *v)
-{
- const struct tty_driver *driver;
- struct console *con;
- int index, len;
- char flags[10];
- dev_t dev;
-
- if (v == SEQ_START_TOKEN)
- return 0;
- con = (struct console *)v;
- if (!con)
- return 0;
- driver = con->device(con, &index);
- if (!driver)
- return 0;
- dev = MKDEV(driver->major, driver->minor_start) + index;
-
- index = 0;
- if (con->flags & CON_ENABLED)
- flags[index++] = 'E';
- if (con->flags & CON_CONSDEV)
- flags[index++] = 'C';
- if (con->flags & CON_BOOT)
- flags[index++] = 'B';
- if (con->flags & CON_PRINTBUFFER)
- flags[index++] = 'p';
- if (con->flags & CON_BRL)
- flags[index++] = 'b';
- if (con->flags & CON_ANYTIME)
- flags[index++] = 'a';
- if (current_dev == dev)
- flags[index++] = '*';
- flags[index] = 0;
-
- seq_printf(m, "%s%d%n", con->name, con->index, &len);
- len = 21 - len;
- if (len < 1)
- len = 1;
- seq_printf(m, "%*c", len, ' ');
- seq_printf(m, "%c%c%c (%s)%n", con->read ? 'R' : '-',
- con->write ? 'W' : '-', con->unblank ? 'U' : '-',
- flags, &len);
- len = 13 - len;
- if (len < 1)
- len = 1;
- seq_printf(m, "%*c%4d:%d\n", len, ' ', MAJOR(dev), MINOR(dev));
-
- return 0;
-}
-
-/* iterator for consoles */
-static void *c_start(struct seq_file *m, loff_t *pos)
-{
- struct console *con;
- loff_t off = 0;
-
- if (*pos == 0)
- return SEQ_START_TOKEN;
-
- acquire_console_sem();
- for (con = console_drivers; con; con = con->next) {
- if (!con->device)
- continue;
- if (++off == *pos)
- break;
- }
- release_console_sem();
-
- return con;
-}
-
-static void *c_next(struct seq_file *m, void *v, loff_t *pos)
-{
- struct console *con;
-
- acquire_console_sem();
- if (v == SEQ_START_TOKEN)
- con = console_drivers;
- else
- con = ((struct console *)v)->next;
- for (; con; con = con->next) {
- if (!con->device)
- continue;
- ++*pos;
- break;
- }
- release_console_sem();
-
- return con;
-}
-
-static void c_stop(struct seq_file *m, void *v)
-{
-}
-
-static const struct seq_operations tty_consoles_op = {
- .start = c_start,
- .next = c_next,
- .stop = c_stop,
- .show = show_console_dev
-};
-
-/*
- * Used for open /proc/tty/consoles. Before this detect
- * the device ID of file descriptor 0 of the current
- * reading task if a character device...
- */
-static int tty_consoles_open(struct inode *inode, struct file *file)
-{
- struct files_struct *curfiles;
-
- current_dev = 0;
- curfiles = get_files_struct(current);
- if (curfiles) {
- const struct file *curfp;
- spin_lock(&curfiles->file_lock);
- curfp = fcheck_files(curfiles, 0);
- if (curfp && curfp->private_data) {
- const struct inode *inode;
- dget(curfp->f_dentry);
- inode = curfp->f_dentry->d_inode;
- if (S_ISCHR(inode->i_mode)) {
- struct tty_struct *tty;
- tty = (struct tty_struct *)curfp->private_data;
- if (tty && tty->magic == TTY_MAGIC) {
- tty = tty_pair_get_tty(tty);
- current_dev = tty_devnum(tty);
- }
- }
- dput(curfp->f_dentry);
- }
- spin_unlock(&curfiles->file_lock);
- put_files_struct(curfiles);
- }
- return seq_open(file, &tty_consoles_op);
-}
-
-static const struct file_operations proc_tty_consoles_operations = {
- .open = tty_consoles_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-/*
* This function is called by tty_register_driver() to handle
* registering the driver's /proc handler into /proc/tty/driver/<foo>
*/
@@ -343,5 +186,4 @@ void __init proc_tty_init(void)
proc_tty_driver = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL);
proc_create("tty/ldiscs", 0, NULL, &tty_ldiscs_proc_fops);
proc_create("tty/drivers", 0, NULL, &proc_tty_drivers_operations);
- proc_create("tty/consoles", 0, NULL, &proc_tty_consoles_operations);
}
diff --git a/fs/proc/softirqs.c b/fs/proc/softirqs.c
index 1807c2419f17..37994737c983 100644
--- a/fs/proc/softirqs.c
+++ b/fs/proc/softirqs.c
@@ -10,13 +10,13 @@ static int show_softirqs(struct seq_file *p, void *v)
{
int i, j;
- seq_printf(p, " ");
+ seq_printf(p, " ");
for_each_possible_cpu(i)
seq_printf(p, "CPU%-8d", i);
seq_printf(p, "\n");
for (i = 0; i < NR_SOFTIRQS; i++) {
- seq_printf(p, "%8s:", softirq_to_name[i]);
+ seq_printf(p, "%12s:", softirq_to_name[i]);
for_each_possible_cpu(j)
seq_printf(p, " %10u", kstat_softirqs_cpu(i, j));
seq_printf(p, "\n");
diff --git a/fs/proc/stat.c b/fs/proc/stat.c
index bf31b03fc275..e15a19c93bae 100644
--- a/fs/proc/stat.c
+++ b/fs/proc/stat.c
@@ -31,7 +31,6 @@ static int show_stat(struct seq_file *p, void *v)
u64 sum_softirq = 0;
unsigned int per_softirq_sums[NR_SOFTIRQS] = {0};
struct timespec boottime;
- unsigned int per_irq_sum;
user = nice = system = idle = iowait =
irq = softirq = steal = cputime64_zero;
@@ -52,9 +51,7 @@ static int show_stat(struct seq_file *p, void *v)
guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
guest_nice = cputime64_add(guest_nice,
kstat_cpu(i).cpustat.guest_nice);
- for_each_irq_nr(j) {
- sum += kstat_irqs_cpu(j, i);
- }
+ sum += kstat_cpu_irqs_sum(i);
sum += arch_irq_stat_cpu(i);
for (j = 0; j < NR_SOFTIRQS; j++) {
@@ -110,13 +107,8 @@ static int show_stat(struct seq_file *p, void *v)
seq_printf(p, "intr %llu", (unsigned long long)sum);
/* sum again ? it could be updated? */
- for_each_irq_nr(j) {
- per_irq_sum = 0;
- for_each_possible_cpu(i)
- per_irq_sum += kstat_irqs_cpu(j, i);
-
- seq_printf(p, " %u", per_irq_sum);
- }
+ for_each_irq_nr(j)
+ seq_printf(p, " %u", kstat_irqs(j));
seq_printf(p,
"\nctxt %llu\n"
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 871e25ed0069..da6b01d70f01 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -327,6 +327,7 @@ struct mem_size_stats {
unsigned long private_clean;
unsigned long private_dirty;
unsigned long referenced;
+ unsigned long anonymous;
unsigned long swap;
u64 pss;
};
@@ -357,6 +358,9 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
if (!page)
continue;
+ if (PageAnon(page))
+ mss->anonymous += PAGE_SIZE;
+
mss->resident += PAGE_SIZE;
/* Accumulate the size in pages that have been accessed. */
if (pte_young(ptent) || PageReferenced(page))
@@ -410,6 +414,7 @@ static int show_smap(struct seq_file *m, void *v)
"Private_Clean: %8lu kB\n"
"Private_Dirty: %8lu kB\n"
"Referenced: %8lu kB\n"
+ "Anonymous: %8lu kB\n"
"Swap: %8lu kB\n"
"KernelPageSize: %8lu kB\n"
"MMUPageSize: %8lu kB\n",
@@ -421,6 +426,7 @@ static int show_smap(struct seq_file *m, void *v)
mss.private_clean >> 10,
mss.private_dirty >> 10,
mss.referenced >> 10,
+ mss.anonymous >> 10,
mss.swap >> 10,
vma_kernel_pagesize(vma) >> 10,
vma_mmu_pagesize(vma) >> 10);
diff --git a/fs/quota/Kconfig b/fs/quota/Kconfig
index 3e21b1e2ad3a..880fd9884366 100644
--- a/fs/quota/Kconfig
+++ b/fs/quota/Kconfig
@@ -4,6 +4,7 @@
config QUOTA
bool "Quota support"
+ select QUOTACTL
help
If you say Y here, you will be able to set per user limits for disk
usage (also called disk quotas). Currently, it works for the
@@ -65,8 +66,7 @@ config QFMT_V2
config QUOTACTL
bool
- depends on XFS_QUOTA || QUOTA
- default y
+ default n
config QUOTACTL_COMPAT
bool
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index aad1316a977f..0fed41e6efcd 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -1386,6 +1386,9 @@ static void __dquot_initialize(struct inode *inode, int type)
/* Avoid races with quotaoff() */
if (!sb_has_quota_active(sb, cnt))
continue;
+ /* We could race with quotaon or dqget() could have failed */
+ if (!got[cnt])
+ continue;
if (!inode->i_dquot[cnt]) {
inode->i_dquot[cnt] = got[cnt];
got[cnt] = NULL;
@@ -1736,6 +1739,7 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
qsize_t rsv_space = 0;
struct dquot *transfer_from[MAXQUOTAS] = {};
int cnt, ret = 0;
+ char is_valid[MAXQUOTAS] = {};
char warntype_to[MAXQUOTAS];
char warntype_from_inodes[MAXQUOTAS], warntype_from_space[MAXQUOTAS];
@@ -1757,8 +1761,15 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
space = cur_space + rsv_space;
/* Build the transfer_from list and check the limits */
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+ /*
+ * Skip changes for same uid or gid or for turned off quota-type.
+ */
if (!transfer_to[cnt])
continue;
+ /* Avoid races with quotaoff() */
+ if (!sb_has_quota_active(inode->i_sb, cnt))
+ continue;
+ is_valid[cnt] = 1;
transfer_from[cnt] = inode->i_dquot[cnt];
ret = check_idq(transfer_to[cnt], 1, warntype_to + cnt);
if (ret)
@@ -1772,12 +1783,8 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
* Finally perform the needed transfer from transfer_from to transfer_to
*/
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
- /*
- * Skip changes for same uid or gid or for turned off quota-type.
- */
- if (!transfer_to[cnt])
+ if (!is_valid[cnt])
continue;
-
/* Due to IO error we might not have transfer_from[] structure */
if (transfer_from[cnt]) {
warntype_from_inodes[cnt] =
@@ -1801,18 +1808,19 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
mark_all_dquot_dirty(transfer_from);
mark_all_dquot_dirty(transfer_to);
- /* Pass back references to put */
- for (cnt = 0; cnt < MAXQUOTAS; cnt++)
- transfer_to[cnt] = transfer_from[cnt];
-warn:
flush_warnings(transfer_to, warntype_to);
flush_warnings(transfer_from, warntype_from_inodes);
flush_warnings(transfer_from, warntype_from_space);
- return ret;
+ /* Pass back references to put */
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+ if (is_valid[cnt])
+ transfer_to[cnt] = transfer_from[cnt];
+ return 0;
over_quota:
spin_unlock(&dq_data_lock);
up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
- goto warn;
+ flush_warnings(transfer_to, warntype_to);
+ return ret;
}
EXPORT_SYMBOL(__dquot_transfer);
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index a5ebae70dc6d..67fadb1ad2c1 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -58,6 +58,7 @@ struct inode *ramfs_get_inode(struct super_block *sb,
struct inode * inode = new_inode(sb);
if (inode) {
+ inode->i_ino = get_next_ino();
inode_init_owner(inode, dir, mode);
inode->i_mapping->a_ops = &ramfs_aops;
inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
diff --git a/fs/read_write.c b/fs/read_write.c
index e757ef26e4ce..9cd9d148105d 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -31,6 +31,20 @@ const struct file_operations generic_ro_fops = {
EXPORT_SYMBOL(generic_ro_fops);
+static int
+__negative_fpos_check(struct file *file, loff_t pos, size_t count)
+{
+ /*
+ * pos or pos+count is negative here, check overflow.
+ * too big "count" will be caught in rw_verify_area().
+ */
+ if ((pos < 0) && (pos + count < pos))
+ return -EOVERFLOW;
+ if (file->f_mode & FMODE_UNSIGNED_OFFSET)
+ return 0;
+ return -EINVAL;
+}
+
/**
* generic_file_llseek_unlocked - lockless generic llseek implementation
* @file: file structure to seek on
@@ -62,7 +76,9 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin)
break;
}
- if (offset < 0 || offset > inode->i_sb->s_maxbytes)
+ if (offset < 0 && __negative_fpos_check(file, offset, 0))
+ return -EINVAL;
+ if (offset > inode->i_sb->s_maxbytes)
return -EINVAL;
/* Special lock needed here? */
@@ -137,7 +153,7 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin)
offset += file->f_pos;
}
retval = -EINVAL;
- if (offset >= 0) {
+ if (offset >= 0 || !__negative_fpos_check(file, offset, 0)) {
if (offset != file->f_pos) {
file->f_pos = offset;
file->f_version = 0;
@@ -221,6 +237,7 @@ bad:
}
#endif
+
/*
* rw_verify_area doesn't like huge counts. We limit
* them to something that fits in "int" so that others
@@ -238,8 +255,11 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count
if (unlikely((ssize_t) count < 0))
return retval;
pos = *ppos;
- if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
- return retval;
+ if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) {
+ retval = __negative_fpos_check(file, pos, count);
+ if (retval)
+ return retval;
+ }
if (unlikely(inode->i_flock && mandatory_lock(inode))) {
retval = locks_mandatory_area(
diff --git a/fs/reiserfs/Kconfig b/fs/reiserfs/Kconfig
index 513f431038f9..7cd46666ba2c 100644
--- a/fs/reiserfs/Kconfig
+++ b/fs/reiserfs/Kconfig
@@ -10,7 +10,8 @@ config REISERFS_FS
In general, ReiserFS is as fast as ext2, but is very efficient with
large directories and small files. Additional patches are needed
- for NFS and quotas, please see <http://www.namesys.com/> for links.
+ for NFS and quotas, please see
+ <https://reiser4.wiki.kernel.org/index.php/Main_Page> for links.
It is more easily extended to have features currently found in
database and keyword search systems than block allocation based file
@@ -18,7 +19,8 @@ config REISERFS_FS
plugins consistent with our motto ``It takes more than a license to
make source code open.''
- Read <http://www.namesys.com/> to learn more about reiserfs.
+ Read <https://reiser4.wiki.kernel.org/index.php/Main_Page>
+ to learn more about reiserfs.
Sponsored by Threshold Networks, Emusic.com, and Bigstorage.com.
diff --git a/fs/reiserfs/README b/fs/reiserfs/README
index 14e8c9d460e5..e2f7a264e3ff 100644
--- a/fs/reiserfs/README
+++ b/fs/reiserfs/README
@@ -43,7 +43,7 @@ to address the fair crediting issue in the next GPL version.)
[END LICENSING]
Reiserfs is a file system based on balanced tree algorithms, which is
-described at http://devlinux.com/namesys.
+described at https://reiser4.wiki.kernel.org/index.php/Main_Page
Stop reading here. Go there, then return.
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index caa758377d66..41656d40dc5c 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -22,8 +22,6 @@
int reiserfs_commit_write(struct file *f, struct page *page,
unsigned from, unsigned to);
-int reiserfs_prepare_write(struct file *f, struct page *page,
- unsigned from, unsigned to);
void reiserfs_evict_inode(struct inode *inode)
{
@@ -165,7 +163,7 @@ inline void make_le_item_head(struct item_head *ih, const struct cpu_key *key,
** but tail is still sitting in a direct item, and we can't write to
** it. So, look through this page, and check all the mapped buffers
** to make sure they have valid block numbers. Any that don't need
-** to be unmapped, so that block_prepare_write will correctly call
+** to be unmapped, so that __block_write_begin will correctly call
** reiserfs_get_block to convert the tail into an unformatted node
*/
static inline void fix_tail_page_for_writing(struct page *page)
@@ -439,13 +437,13 @@ static int reiserfs_bmap(struct inode *inode, sector_t block,
}
/* special version of get_block that is only used by grab_tail_page right
-** now. It is sent to block_prepare_write, and when you try to get a
+** now. It is sent to __block_write_begin, and when you try to get a
** block past the end of the file (or a block from a hole) it returns
-** -ENOENT instead of a valid buffer. block_prepare_write expects to
+** -ENOENT instead of a valid buffer. __block_write_begin expects to
** be able to do i/o on the buffers returned, unless an error value
** is also returned.
**
-** So, this allows block_prepare_write to be used for reading a single block
+** So, this allows __block_write_begin to be used for reading a single block
** in a page. Where it does not produce a valid page for holes, or past the
** end of the file. This turns out to be exactly what we need for reading
** tails for conversion.
@@ -558,11 +556,12 @@ static int convert_tail_for_hole(struct inode *inode,
**
** We must fix the tail page for writing because it might have buffers
** that are mapped, but have a block number of 0. This indicates tail
- ** data that has been read directly into the page, and block_prepare_write
- ** won't trigger a get_block in this case.
+ ** data that has been read directly into the page, and
+ ** __block_write_begin won't trigger a get_block in this case.
*/
fix_tail_page_for_writing(tail_page);
- retval = reiserfs_prepare_write(NULL, tail_page, tail_start, tail_end);
+ retval = __reiserfs_write_begin(tail_page, tail_start,
+ tail_end - tail_start);
if (retval)
goto unlock;
@@ -2033,7 +2032,7 @@ static int grab_tail_page(struct inode *inode,
/* start within the page of the last block in the file */
start = (offset / blocksize) * blocksize;
- error = block_prepare_write(page, start, offset,
+ error = __block_write_begin(page, start, offset - start,
reiserfs_get_block_create_0);
if (error)
goto unlock;
@@ -2438,7 +2437,7 @@ static int reiserfs_write_full_page(struct page *page,
/* from this point on, we know the buffer is mapped to a
* real block and not a direct item
*/
- if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) {
+ if (wbc->sync_mode != WB_SYNC_NONE) {
lock_buffer(bh);
} else {
if (!trylock_buffer(bh)) {
@@ -2628,8 +2627,7 @@ static int reiserfs_write_begin(struct file *file,
return ret;
}
-int reiserfs_prepare_write(struct file *f, struct page *page,
- unsigned from, unsigned to)
+int __reiserfs_write_begin(struct page *page, unsigned from, unsigned len)
{
struct inode *inode = page->mapping->host;
int ret;
@@ -2650,7 +2648,7 @@ int reiserfs_prepare_write(struct file *f, struct page *page,
th->t_refcount++;
}
- ret = block_prepare_write(page, from, to, reiserfs_get_block);
+ ret = __block_write_begin(page, from, len, reiserfs_get_block);
if (ret && reiserfs_transaction_running(inode->i_sb)) {
struct reiserfs_transaction_handle *th = current->journal_info;
/* this gets a little ugly. If reiserfs_get_block returned an
diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
index 5cbb81e134ac..adf22b485cea 100644
--- a/fs/reiserfs/ioctl.c
+++ b/fs/reiserfs/ioctl.c
@@ -160,8 +160,6 @@ long reiserfs_compat_ioctl(struct file *file, unsigned int cmd,
int reiserfs_commit_write(struct file *f, struct page *page,
unsigned from, unsigned to);
-int reiserfs_prepare_write(struct file *f, struct page *page,
- unsigned from, unsigned to);
/*
** reiserfs_unpack
** Function try to convert tail from direct item into indirect.
@@ -200,7 +198,7 @@ int reiserfs_unpack(struct inode *inode, struct file *filp)
}
/* we unpack by finding the page with the tail, and calling
- ** reiserfs_prepare_write on that page. This will force a
+ ** __reiserfs_write_begin on that page. This will force a
** reiserfs_get_block to unpack the tail for us.
*/
index = inode->i_size >> PAGE_CACHE_SHIFT;
@@ -210,7 +208,7 @@ int reiserfs_unpack(struct inode *inode, struct file *filp)
if (!page) {
goto out;
}
- retval = reiserfs_prepare_write(NULL, page, write_from, write_from);
+ retval = __reiserfs_write_begin(page, write_from, 0);
if (retval)
goto out_unlock;
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index ee78d4a0086a..ba5f51ec3458 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -1156,7 +1156,7 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir,
inode->i_ctime = CURRENT_TIME_SEC;
reiserfs_update_sd(&th, inode);
- atomic_inc(&inode->i_count);
+ ihold(inode);
d_instantiate(dentry, inode);
retval = journal_end(&th, dir->i_sb, jbegin_count);
reiserfs_write_unlock(dir->i_sb);
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index 8c4cf273c672..5d04a7828e7a 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -418,13 +418,11 @@ static inline __u32 xattr_hash(const char *msg, int len)
int reiserfs_commit_write(struct file *f, struct page *page,
unsigned from, unsigned to);
-int reiserfs_prepare_write(struct file *f, struct page *page,
- unsigned from, unsigned to);
static void update_ctime(struct inode *inode)
{
struct timespec now = current_fs_time(inode->i_sb);
- if (hlist_unhashed(&inode->i_hash) || !inode->i_nlink ||
+ if (inode_unhashed(inode) || !inode->i_nlink ||
timespec_equal(&inode->i_ctime, &now))
return;
@@ -532,8 +530,7 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th,
rxh->h_hash = cpu_to_le32(xahash);
}
- err = reiserfs_prepare_write(NULL, page, page_offset,
- page_offset + chunk + skip);
+ err = __reiserfs_write_begin(page, page_offset, chunk + skip);
if (!err) {
if (buffer)
memcpy(data + skip, buffer + buffer_pos, chunk);
diff --git a/fs/select.c b/fs/select.c
index 500a669f7790..b7b10aa30861 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -67,7 +67,7 @@ static long __estimate_accuracy(struct timespec *tv)
return slack;
}
-static long estimate_accuracy(struct timespec *tv)
+long select_estimate_accuracy(struct timespec *tv)
{
unsigned long ret;
struct timespec now;
@@ -417,7 +417,7 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
}
if (end_time && !timed_out)
- slack = estimate_accuracy(end_time);
+ slack = select_estimate_accuracy(end_time);
retval = 0;
for (;;) {
@@ -769,7 +769,7 @@ static int do_poll(unsigned int nfds, struct poll_list *list,
}
if (end_time && !timed_out)
- slack = estimate_accuracy(end_time);
+ slack = select_estimate_accuracy(end_time);
for (;;) {
struct poll_list *walk;
diff --git a/fs/seq_file.c b/fs/seq_file.c
index e1f437be6c3c..05d6b0e78c95 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -131,7 +131,7 @@ Eoverflow:
*/
ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
- struct seq_file *m = (struct seq_file *)file->private_data;
+ struct seq_file *m = file->private_data;
size_t copied = 0;
loff_t pos;
size_t n;
@@ -280,7 +280,7 @@ EXPORT_SYMBOL(seq_read);
*/
loff_t seq_lseek(struct file *file, loff_t offset, int origin)
{
- struct seq_file *m = (struct seq_file *)file->private_data;
+ struct seq_file *m = file->private_data;
loff_t retval = -EINVAL;
mutex_lock(&m->lock);
@@ -324,7 +324,7 @@ EXPORT_SYMBOL(seq_lseek);
*/
int seq_release(struct inode *inode, struct file *file)
{
- struct seq_file *m = (struct seq_file *)file->private_data;
+ struct seq_file *m = file->private_data;
kfree(m->buf);
kfree(m);
return 0;
@@ -462,9 +462,7 @@ int seq_path_root(struct seq_file *m, struct path *path, struct path *root,
if (size) {
char *p;
- spin_lock(&dcache_lock);
p = __d_path(path, root, buf, size);
- spin_unlock(&dcache_lock);
res = PTR_ERR(p);
if (!IS_ERR(p)) {
char *end = mangle_path(buf, p, esc);
diff --git a/fs/signalfd.c b/fs/signalfd.c
index 74047304b01a..492465b451dd 100644
--- a/fs/signalfd.c
+++ b/fs/signalfd.c
@@ -99,6 +99,16 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
#ifdef __ARCH_SI_TRAPNO
err |= __put_user(kinfo->si_trapno, &uinfo->ssi_trapno);
#endif
+#ifdef BUS_MCEERR_AO
+ /*
+ * Other callers might not initialize the si_lsb field,
+ * so check explicitly for the right codes here.
+ */
+ if (kinfo->si_code == BUS_MCEERR_AR ||
+ kinfo->si_code == BUS_MCEERR_AO)
+ err |= __put_user((short) kinfo->si_addr_lsb,
+ &uinfo->ssi_addr_lsb);
+#endif
break;
case __SI_CHLD:
err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid);
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 00a70cab1f36..f678d421e541 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -406,21 +406,15 @@ void
smb_renew_times(struct dentry * dentry)
{
dget(dentry);
- spin_lock(&dentry->d_lock);
- for (;;) {
- struct dentry *parent;
+ dentry->d_time = jiffies;
- dentry->d_time = jiffies;
- if (IS_ROOT(dentry))
- break;
- parent = dentry->d_parent;
- dget(parent);
- spin_unlock(&dentry->d_lock);
+ while (!IS_ROOT(dentry)) {
+ struct dentry *parent = dget_parent(dentry);
dput(dentry);
dentry = parent;
- spin_lock(&dentry->d_lock);
+
+ dentry->d_time = jiffies;
}
- spin_unlock(&dentry->d_lock);
dput(dentry);
}
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 8fc5e50e142f..f6e9ee59757e 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -229,7 +229,6 @@ smb_invalidate_inodes(struct smb_sb_info *server)
{
VERBOSE("\n");
shrink_dcache_sb(SB_of(server));
- invalidate_inodes(SB_of(server));
}
/*
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index 71c29b6670b4..3dcf638d4d3a 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -332,16 +332,15 @@ static int smb_build_path(struct smb_sb_info *server, unsigned char *buf,
* and store it in reversed order [see reverse_string()]
*/
dget(entry);
- spin_lock(&entry->d_lock);
while (!IS_ROOT(entry)) {
struct dentry *parent;
if (maxlen < (3<<unicode)) {
- spin_unlock(&entry->d_lock);
dput(entry);
return -ENAMETOOLONG;
}
+ spin_lock(&entry->d_lock);
len = server->ops->convert(path, maxlen-2,
entry->d_name.name, entry->d_name.len,
server->local_nls, server->remote_nls);
@@ -359,15 +358,12 @@ static int smb_build_path(struct smb_sb_info *server, unsigned char *buf,
}
*path++ = '\\';
maxlen -= len+1;
-
- parent = entry->d_parent;
- dget(parent);
spin_unlock(&entry->d_lock);
+
+ parent = dget_parent(entry);
dput(entry);
entry = parent;
- spin_lock(&entry->d_lock);
}
- spin_unlock(&entry->d_lock);
dput(entry);
reverse_string(buf, path-buf);
diff --git a/fs/super.c b/fs/super.c
index 8819e3a7ff20..b9c9869165db 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -273,14 +273,14 @@ void generic_shutdown_super(struct super_block *sb)
get_fs_excl();
sb->s_flags &= ~MS_ACTIVE;
- /* bad name - it should be evict_inodes() */
- invalidate_inodes(sb);
+ fsnotify_unmount_inodes(&sb->s_inodes);
+
+ evict_inodes(sb);
if (sop->put_super)
sop->put_super(sb);
- /* Forget any remaining inodes */
- if (invalidate_inodes(sb)) {
+ if (!list_empty(&sb->s_inodes)) {
printk("VFS: Busy inodes after unmount of %s. "
"Self-destruct in 5 seconds. Have a nice day...\n",
sb->s_id);
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index 33e047b59b8d..11e7f7d11cd0 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -126,7 +126,7 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir,
inode->i_ctime = CURRENT_TIME_SEC;
inode_inc_link_count(inode);
- atomic_inc(&inode->i_count);
+ ihold(inode);
return add_nondir(dentry, inode);
}
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 87ebcce72213..14f64b689d7f 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -550,7 +550,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
lock_2_inodes(dir, inode);
inc_nlink(inode);
- atomic_inc(&inode->i_count);
+ ihold(inode);
inode->i_ctime = ubifs_current_time(inode);
dir->i_size += sz_change;
dir_ui->ui_size = dir->i_size;
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index bf5fc674193c..6d8dc02baebb 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -1101,7 +1101,7 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir,
inc_nlink(inode);
inode->i_ctime = current_fs_time(inode->i_sb);
mark_inode_dirty(inode);
- atomic_inc(&inode->i_count);
+ ihold(inode);
d_instantiate(dentry, inode);
unlock_kernel();
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index b056f02b1fb3..12f39b9e4437 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -180,7 +180,7 @@ static int ufs_link (struct dentry * old_dentry, struct inode * dir,
inode->i_ctime = CURRENT_TIME_SEC;
inode_inc_link_count(inode);
- atomic_inc(&inode->i_count);
+ ihold(inode);
error = ufs_add_nondir(dentry, inode);
unlock_kernel();
diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
index 480f28127f09..6100ec0fa1d4 100644
--- a/fs/xfs/Kconfig
+++ b/fs/xfs/Kconfig
@@ -22,6 +22,7 @@ config XFS_FS
config XFS_QUOTA
bool "XFS Quota support"
depends on XFS_FS
+ select QUOTACTL
help
If you say Y here, you will be able to set limits for disk usage on
a per user and/or a per group basis under XFS. XFS considers quota
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index b552f816de15..c9af48fffcd7 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -1139,8 +1139,7 @@ xfs_vm_writepage(
type = IO_DELAY;
flags = BMAPI_ALLOCATE;
- if (wbc->sync_mode == WB_SYNC_NONE &&
- wbc->nonblocking)
+ if (wbc->sync_mode == WB_SYNC_NONE)
flags |= BMAPI_TRYLOCK;
}
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index ba5312802aa9..63fd2c07cb57 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -1580,6 +1580,7 @@ xfs_mapping_buftarg(
XFS_BUFTARG_NAME(btp));
return ENOMEM;
}
+ inode->i_ino = get_next_ino();
inode->i_mode = S_IFBLK;
inode->i_bdev = bdev;
inode->i_rdev = bdev->bd_dev;
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index ec858e09d546..96107efc0c61 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -317,7 +317,7 @@ xfs_vn_link(
if (unlikely(error))
return -error;
- atomic_inc(&inode->i_count);
+ ihold(inode);
d_instantiate(dentry, inode);
return 0;
}
@@ -760,7 +760,9 @@ xfs_setup_inode(
inode->i_ino = ip->i_ino;
inode->i_state = I_NEW;
- inode_add_to_lists(ip->i_mount->m_super, inode);
+
+ inode_sb_list_add(inode);
+ insert_inode_hash(inode);
inode->i_mode = ip->i_d.di_mode;
inode->i_nlink = ip->i_d.di_nlink;
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index ab31ce5aeaf9..cf808782c065 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -576,7 +576,7 @@ xfs_max_file_offset(
/* Figure out maximum filesize, on Linux this can depend on
* the filesystem blocksize (on 32 bit platforms).
- * __block_prepare_write does this in an [unsigned] long...
+ * __block_write_begin does this in an [unsigned] long...
* page->index << (PAGE_CACHE_SHIFT - bbits)
* So, for page sized blocks (4K on 32 bit platforms),
* this wraps at around 8Tb (hence MAX_LFS_FILESIZE which is
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index fac52290de90..fb2ca2e4cdc9 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -500,7 +500,7 @@ void xfs_mark_inode_dirty_sync(xfs_inode_t *);
#define IHOLD(ip) \
do { \
ASSERT(atomic_read(&VFS_I(ip)->i_count) > 0) ; \
- atomic_inc(&(VFS_I(ip)->i_count)); \
+ ihold(VFS_I(ip)); \
trace_xfs_ihold(ip, _THIS_IP_); \
} while (0)
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 4de84ce3a927..359ef11725a6 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -184,7 +184,7 @@ struct acpi_device_pnp {
#define acpi_device_bid(d) ((d)->pnp.bus_id)
#define acpi_device_adr(d) ((d)->pnp.bus_address)
-char *acpi_device_hid(struct acpi_device *device);
+const char *acpi_device_hid(struct acpi_device *device);
#define acpi_device_name(d) ((d)->pnp.device_name)
#define acpi_device_class(d) ((d)->pnp.device_class)
@@ -389,21 +389,25 @@ struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle);
int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state);
int acpi_disable_wakeup_device_power(struct acpi_device *dev);
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM_OPS
int acpi_pm_device_sleep_state(struct device *, int *);
-int acpi_pm_device_sleep_wake(struct device *, bool);
-#else /* !CONFIG_PM_SLEEP */
+#else
static inline int acpi_pm_device_sleep_state(struct device *d, int *p)
{
if (p)
*p = ACPI_STATE_D0;
return ACPI_STATE_D3;
}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+int acpi_pm_device_sleep_wake(struct device *, bool);
+#else
static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
{
return -ENODEV;
}
-#endif /* !CONFIG_PM_SLEEP */
+#endif
#endif /* CONFIG_ACPI */
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index 23d78b4d088b..3090471b2a5e 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -115,8 +115,6 @@ void pci_acpi_crs_quirks(void);
#define ACPI_PROCESSOR_LIMIT_INCREMENT 0x01
#define ACPI_PROCESSOR_LIMIT_DECREMENT 0x02
-int acpi_processor_set_thermal_limit(acpi_handle handle, int type);
-
/*--------------------------------------------------------------------------
Dock Station
-------------------------------------------------------------------------- */
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 29bf945143e8..65b3f5888f42 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -98,8 +98,6 @@ acpi_os_table_override(struct acpi_table_header *existing_table,
/*
* Spinlock primitives
*/
-acpi_status acpi_os_create_lock(acpi_spinlock * out_handle);
-
void acpi_os_delete_lock(acpi_spinlock handle);
acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock handle);
@@ -223,25 +221,15 @@ acpi_os_write_memory(acpi_physical_address address, u32 value, u32 width);
*/
acpi_status
acpi_os_read_pci_configuration(struct acpi_pci_id *pci_id,
- u32 reg, u32 *value, u32 width);
+ u32 reg, u64 *value, u32 width);
acpi_status
acpi_os_write_pci_configuration(struct acpi_pci_id *pci_id,
u32 reg, u64 value, u32 width);
/*
- * Interim function needed for PCI IRQ routing
- */
-void
-acpi_os_derive_pci_id(acpi_handle device,
- acpi_handle region, struct acpi_pci_id **pci_id);
-
-/*
* Miscellaneous
*/
-acpi_status acpi_os_validate_interface(char *interface);
-acpi_status acpi_osi_invalidate(char* interface);
-
acpi_status
acpi_os_validate_address(u8 space_id, acpi_physical_address address,
acpi_size length, char *name);
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 984cdc62e30b..53b7cfd924a3 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -47,7 +47,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20100702
+#define ACPI_CA_VERSION 0x20101013
#include "actypes.h"
#include "actbl.h"
@@ -72,6 +72,7 @@ extern u8 acpi_gbl_truncate_io_addresses;
extern u32 acpi_current_gpe_count;
extern struct acpi_table_fadt acpi_gbl_FADT;
+extern u8 acpi_gbl_system_awake_and_running;
extern u32 acpi_rsdt_forced;
/*
@@ -105,6 +106,10 @@ const char *acpi_format_exception(acpi_status exception);
acpi_status acpi_purge_cached_objects(void);
+acpi_status acpi_install_interface(acpi_string interface_name);
+
+acpi_status acpi_remove_interface(acpi_string interface_name);
+
/*
* ACPI Memory management
*/
@@ -263,6 +268,8 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
acpi_status acpi_install_exception_handler(acpi_exception_handler handler);
#endif
+acpi_status acpi_install_interface_handler(acpi_interface_handler handler);
+
/*
* Event interfaces
*/
@@ -308,6 +315,8 @@ acpi_install_gpe_block(acpi_handle gpe_device,
acpi_status acpi_remove_gpe_block(acpi_handle gpe_device);
+acpi_status acpi_update_gpes(void);
+
/*
* Resource interfaces
*/
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index 5db8f472fec9..2b134b691e34 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -115,7 +115,6 @@
*
* ACPI_SIZE 16/32/64-bit unsigned value
* ACPI_NATIVE_INT 16/32/64-bit signed value
- *
*/
/*******************************************************************************
@@ -132,6 +131,16 @@ typedef COMPILER_DEPENDENT_INT64 INT64;
/*! [End] no source code translation !*/
+/*
+ * Value returned by acpi_os_get_thread_id. There is no standard "thread_id"
+ * across operating systems or even the various UNIX systems. Since ACPICA
+ * only needs the thread ID as a unique thread identifier, we use a u64
+ * as the only common data type - it will accommodate any type of pointer or
+ * any type of integer. It is up to the host-dependent OSL to cast the
+ * native thread ID type to a u64 (in acpi_os_get_thread_id).
+ */
+#define acpi_thread_id u64
+
/*******************************************************************************
*
* Types specific to 64-bit targets
@@ -211,12 +220,6 @@ typedef u32 acpi_physical_address;
*
******************************************************************************/
-/* Value returned by acpi_os_get_thread_id */
-
-#ifndef acpi_thread_id
-#define acpi_thread_id acpi_size
-#endif
-
/* Flags for acpi_os_acquire_lock/acpi_os_release_lock */
#ifndef acpi_cpu_flags
@@ -375,16 +378,6 @@ typedef void *acpi_handle; /* Actually a ptr to a NS Node */
typedef u8 acpi_owner_id;
#define ACPI_OWNER_ID_MAX 0xFF
-struct uint64_struct {
- u32 lo;
- u32 hi;
-};
-
-union uint64_overlay {
- u64 full;
- struct uint64_struct part;
-};
-
#define ACPI_INTEGER_BIT_SIZE 64
#define ACPI_MAX_DECIMAL_DIGITS 20 /* 2^64 = 18,446,744,073,709,551,616 */
@@ -950,6 +943,9 @@ acpi_status(*acpi_walk_callback) (acpi_handle object,
u32 nesting_level,
void *context, void **return_value);
+typedef
+u32 (*acpi_interface_handler) (acpi_string interface_name, u32 supported);
+
/* Interrupt handler return values */
#define ACPI_INTERRUPT_NOT_HANDLED 0x00
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index c05aeba9e8f0..a3e334ab1119 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -193,6 +193,12 @@
#define ACPI_MUTEX_TYPE ACPI_BINARY_SEMAPHORE
#endif
+/* "inline" keywords - configurable since inline is not standardized */
+
+#ifndef ACPI_INLINE
+#define ACPI_INLINE
+#endif
+
/*
* Debugger threading model
* Use single threaded if the entire subsystem is contained in an application
diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h
index 0cd53e3cd1a3..5dcb9537343c 100644
--- a/include/acpi/platform/acgcc.h
+++ b/include/acpi/platform/acgcc.h
@@ -44,6 +44,8 @@
#ifndef __ACGCC_H__
#define __ACGCC_H__
+#define ACPI_INLINE __inline__
+
/* Function name is used for debug output. Non-ANSI, compiler-dependent */
#define ACPI_GET_FUNCTION_NAME __func__
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 103f08aca764..572189e37133 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -75,7 +75,6 @@
#define acpi_cache_t struct kmem_cache
#define acpi_spinlock spinlock_t *
#define acpi_cpu_flags unsigned long
-#define acpi_thread_id struct task_struct *
#else /* !__KERNEL__ */
@@ -88,7 +87,7 @@
/* Host-dependent types and defines for user-space ACPICA */
#define ACPI_FLUSH_CPU_CACHE()
-#define acpi_thread_id pthread_t
+#define ACPI_CAST_PTHREAD_T(pthread) ((acpi_thread_id) (pthread))
#if defined(__ia64__) || defined(__x86_64__)
#define ACPI_MACHINE_WIDTH 64
@@ -113,12 +112,13 @@
#ifdef __KERNEL__
+#include <acpi/actypes.h>
/*
* Overrides for in-kernel ACPICA
*/
static inline acpi_thread_id acpi_os_get_thread_id(void)
{
- return current;
+ return (acpi_thread_id)(unsigned long)current;
}
/*
@@ -127,7 +127,6 @@ static inline acpi_thread_id acpi_os_get_thread_id(void)
* However, boot has (system_state != SYSTEM_RUNNING)
* to quiet __might_sleep() in kmalloc() and resume does not.
*/
-#include <acpi/actypes.h>
static inline void *acpi_os_allocate(acpi_size size)
{
return kmalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
diff --git a/include/asm-generic/cputime.h b/include/asm-generic/cputime.h
index ca0f239f0e13..2bcc5c7c22a6 100644
--- a/include/asm-generic/cputime.h
+++ b/include/asm-generic/cputime.h
@@ -33,10 +33,10 @@ typedef u64 cputime64_t;
/*
- * Convert cputime to milliseconds and back.
+ * Convert cputime to microseconds and back.
*/
-#define cputime_to_msecs(__ct) jiffies_to_msecs(__ct)
-#define msecs_to_cputime(__msecs) msecs_to_jiffies(__msecs)
+#define cputime_to_usecs(__ct) jiffies_to_usecs(__ct);
+#define usecs_to_cputime(__msecs) usecs_to_jiffies(__msecs);
/*
* Convert cputime to seconds and back.
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 8ca18e26d7e3..ff5c66080c8c 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -210,7 +210,7 @@ extern void gpio_unexport(unsigned gpio);
#endif /* CONFIG_GPIO_SYSFS */
-#else /* !CONFIG_HAVE_GPIO_LIB */
+#else /* !CONFIG_GPIOLIB */
static inline int gpio_is_valid(int number)
{
@@ -239,7 +239,7 @@ static inline void gpio_set_value_cansleep(unsigned gpio, int value)
gpio_set_value(gpio, value);
}
-#endif /* !CONFIG_HAVE_GPIO_LIB */
+#endif /* !CONFIG_GPIOLIB */
#ifndef CONFIG_GPIO_SYSFS
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index f4d4120e5128..6f3c6ae4fe03 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -108,7 +108,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addres
#endif
#ifndef __HAVE_ARCH_PAGE_CLEAR_DIRTY
-#define page_clear_dirty(page) do { } while (0)
+#define page_clear_dirty(page, mapped) do { } while (0)
#endif
#ifndef __HAVE_ARCH_PAGE_TEST_DIRTY
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index f4229fb315e1..2c0fc10956ba 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -150,6 +150,7 @@
#define DATA_DATA \
*(.data) \
*(.ref.data) \
+ *(.data..shared_aligned) /* percpu related */ \
DEV_KEEP(init.data) \
DEV_KEEP(exit.data) \
CPU_KEEP(init.data) \
@@ -636,7 +637,7 @@
#ifdef CONFIG_BLK_DEV_INITRD
#define INIT_RAM_FS \
- . = ALIGN(PAGE_SIZE); \
+ . = ALIGN(4); \
VMLINUX_SYMBOL(__initramfs_start) = .; \
*(.init.ramfs) \
VMLINUX_SYMBOL(__initramfs_end) = .;
diff --git a/include/crypto/cryptd.h b/include/crypto/cryptd.h
index 1c96b255017c..ba98918bbd9b 100644
--- a/include/crypto/cryptd.h
+++ b/include/crypto/cryptd.h
@@ -1,5 +1,12 @@
/*
* Software async crypto daemon
+ *
+ * Added AEAD support to cryptd.
+ * Authors: Tadeusz Struk (tadeusz.struk@intel.com)
+ * Adrian Hoban <adrian.hoban@intel.com>
+ * Gabriele Paoloni <gabriele.paoloni@intel.com>
+ * Aidan O'Mahony (aidan.o.mahony@intel.com)
+ * Copyright (c) 2010, Intel Corporation.
*/
#ifndef _CRYPTO_CRYPT_H
@@ -42,4 +49,21 @@ struct crypto_shash *cryptd_ahash_child(struct cryptd_ahash *tfm);
struct shash_desc *cryptd_shash_desc(struct ahash_request *req);
void cryptd_free_ahash(struct cryptd_ahash *tfm);
+struct cryptd_aead {
+ struct crypto_aead base;
+};
+
+static inline struct cryptd_aead *__cryptd_aead_cast(
+ struct crypto_aead *tfm)
+{
+ return (struct cryptd_aead *)tfm;
+}
+
+struct cryptd_aead *cryptd_alloc_aead(const char *alg_name,
+ u32 type, u32 mask);
+
+struct crypto_aead *cryptd_aead_child(struct cryptd_aead *tfm);
+
+void cryptd_free_aead(struct cryptd_aead *tfm);
+
#endif
diff --git a/include/crypto/gf128mul.h b/include/crypto/gf128mul.h
index 4086b8ebfafe..da2530e34b26 100644
--- a/include/crypto/gf128mul.h
+++ b/include/crypto/gf128mul.h
@@ -54,8 +54,8 @@
/* Comment by Rik:
*
- * For some background on GF(2^128) see for example: http://-
- * csrc.nist.gov/CryptoToolkit/modes/proposedmodes/gcm/gcm-revised-spec.pdf
+ * For some background on GF(2^128) see for example:
+ * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf
*
* The elements of GF(2^128) := GF(2)[X]/(X^128-X^7-X^2-X^1-1) can
* be mapped to computer memory in a variety of ways. Let's examine
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 4c9461a4f9e6..274eaaa15c36 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -699,13 +699,8 @@ struct drm_driver {
int (*suspend) (struct drm_device *, pm_message_t state);
int (*resume) (struct drm_device *);
int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
- void (*dma_ready) (struct drm_device *);
int (*dma_quiescent) (struct drm_device *);
- int (*context_ctor) (struct drm_device *dev, int context);
int (*context_dtor) (struct drm_device *dev, int context);
- int (*kernel_context_switch) (struct drm_device *dev, int old,
- int new);
- void (*kernel_context_switch_unlock) (struct drm_device *dev);
/**
* get_vblank_counter - get raw hardware vblank counter
@@ -777,8 +772,6 @@ struct drm_driver {
struct drm_file *file_priv);
void (*reclaim_buffers_idlelocked) (struct drm_device *dev,
struct drm_file *file_priv);
- resource_size_t (*get_map_ofs) (struct drm_local_map * map);
- resource_size_t (*get_reg_ofs) (struct drm_device *dev);
void (*set_version) (struct drm_device *dev,
struct drm_set_version *sv);
@@ -795,8 +788,6 @@ struct drm_driver {
void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv,
bool from_release);
- int (*proc_init)(struct drm_minor *minor);
- void (*proc_cleanup)(struct drm_minor *minor);
int (*debugfs_init)(struct drm_minor *minor);
void (*debugfs_cleanup)(struct drm_minor *minor);
@@ -972,7 +963,6 @@ struct drm_device {
__volatile__ long context_flag; /**< Context swapping flag */
__volatile__ long interrupt_flag; /**< Interruption handler flag */
__volatile__ long dma_flag; /**< DMA dispatch flag */
- struct timer_list timer; /**< Timer for delaying ctx switch */
wait_queue_head_t context_wait; /**< Processes waiting on ctx switch */
int last_checked; /**< Last context checked for DMA */
int last_context; /**< Last current context */
@@ -1045,25 +1035,12 @@ struct drm_device {
struct drm_minor *control; /**< Control node for card */
struct drm_minor *primary; /**< render type primary screen head */
- /** \name Drawable information */
- /*@{ */
- spinlock_t drw_lock;
- struct idr drw_idr;
- /*@} */
-
struct drm_mode_config mode_config; /**< Current mode config */
/** \name GEM information */
/*@{ */
spinlock_t object_name_lock;
struct idr object_name_idr;
- atomic_t object_count;
- atomic_t object_memory;
- atomic_t pin_count;
- atomic_t pin_memory;
- atomic_t gtt_count;
- atomic_t gtt_memory;
- uint32_t gtt_total;
uint32_t invalidate_domains; /* domains pending invalidation */
uint32_t flush_domains; /* domains pending flush */
/*@} */
@@ -1175,8 +1152,6 @@ extern int drm_mmap(struct file *filp, struct vm_area_struct *vma);
extern int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma);
extern void drm_vm_open_locked(struct vm_area_struct *vma);
extern void drm_vm_close_locked(struct vm_area_struct *vma);
-extern resource_size_t drm_core_get_map_ofs(struct drm_local_map * map);
-extern resource_size_t drm_core_get_reg_ofs(struct drm_device *dev);
extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
/* Memory management support (drm_memory.h) */
@@ -1186,8 +1161,7 @@ extern int drm_mem_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area);
-extern DRM_AGP_MEM *drm_alloc_agp(struct drm_device *dev, int pages, u32 type);
-extern int drm_free_agp(DRM_AGP_MEM * handle, int pages);
+extern void drm_free_agp(DRM_AGP_MEM * handle, int pages);
extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start);
extern DRM_AGP_MEM *drm_agp_bind_pages(struct drm_device *dev,
struct page **pages,
@@ -1239,17 +1213,6 @@ extern int drm_setsareactx(struct drm_device *dev, void *data,
extern int drm_getsareactx(struct drm_device *dev, void *data,
struct drm_file *file_priv);
- /* Drawable IOCTL support (drm_drawable.h) */
-extern int drm_adddraw(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int drm_rmdraw(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int drm_update_drawable_info(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev,
- drm_drawable_t id);
-extern void drm_drawable_free_all(struct drm_device *dev);
-
/* Authentication IOCTL support (drm_auth.h) */
extern int drm_getmagic(struct drm_device *dev, void *data,
struct drm_file *file_priv);
@@ -1264,7 +1227,6 @@ extern int drm_lock(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int drm_unlock(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-extern int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context);
extern int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context);
extern void drm_idlelock_take(struct drm_lock_data *lock_data);
extern void drm_idlelock_release(struct drm_lock_data *lock_data);
@@ -1359,10 +1321,6 @@ extern int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
extern int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request);
extern int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, size_t pages, u32 type);
-extern int drm_agp_free_memory(DRM_AGP_MEM * handle);
-extern int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start);
-extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle);
extern void drm_agp_chipset_flush(struct drm_device *dev);
/* Stub support (drm_stub.h) */
@@ -1414,7 +1372,6 @@ extern int drm_bufs_info(struct seq_file *m, void *data);
extern int drm_vblank_info(struct seq_file *m, void *data);
extern int drm_clients_info(struct seq_file *m, void* data);
extern int drm_gem_name_info(struct seq_file *m, void *data);
-extern int drm_gem_object_info(struct seq_file *m, void* data);
#if DRM_DEBUG_CODE
extern int drm_vma_info(struct seq_file *m, void *data);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3e5a51af757c..029aa688e787 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -221,7 +221,8 @@ struct drm_framebuffer_funcs {
* the semantics and arguments have a one to one mapping
* on this function.
*/
- int (*dirty)(struct drm_framebuffer *framebuffer, unsigned flags,
+ int (*dirty)(struct drm_framebuffer *framebuffer,
+ struct drm_file *file_priv, unsigned flags,
unsigned color, struct drm_clip_rect *clips,
unsigned num_clips);
};
@@ -762,6 +763,7 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev,
extern int drm_mode_gamma_set_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
extern bool drm_detect_hdmi_monitor(struct edid *edid);
+extern bool drm_detect_monitor_audio(struct edid *edid);
extern int drm_mode_page_flip_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index 59b7073b13fe..73b071203dcc 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -39,6 +39,11 @@
#include <linux/fb.h>
+enum mode_set_atomic {
+ LEAVE_ATOMIC_MODE_SET,
+ ENTER_ATOMIC_MODE_SET,
+};
+
struct drm_crtc_helper_funcs {
/*
* Control power levels on the CRTC. If the mode passed in is
@@ -61,7 +66,8 @@ struct drm_crtc_helper_funcs {
int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb);
int (*mode_set_base_atomic)(struct drm_crtc *crtc,
- struct drm_framebuffer *fb, int x, int y);
+ struct drm_framebuffer *fb, int x, int y,
+ enum mode_set_atomic);
/* reload the current crtc LUT */
void (*load_lut)(struct drm_crtc *crtc);
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index a49e791db0b0..83a389e44543 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -23,6 +23,9 @@
#ifndef _DRM_DP_HELPER_H_
#define _DRM_DP_HELPER_H_
+#include <linux/types.h>
+#include <linux/i2c.h>
+
/* From the VESA DisplayPort spec */
#define AUX_NATIVE_WRITE 0x8
diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h
index e41c74facb6a..8c641bed9bbd 100644
--- a/include/drm/i915_drm.h
+++ b/include/drm/i915_drm.h
@@ -286,6 +286,7 @@ typedef struct drm_i915_irq_wait {
#define I915_PARAM_HAS_PAGEFLIPPING 8
#define I915_PARAM_HAS_EXECBUF2 9
#define I915_PARAM_HAS_BSD 10
+#define I915_PARAM_HAS_BLT 11
typedef struct drm_i915_getparam {
int param;
@@ -627,8 +628,11 @@ struct drm_i915_gem_execbuffer2 {
__u32 num_cliprects;
/** This is a struct drm_clip_rect *cliprects */
__u64 cliprects_ptr;
+#define I915_EXEC_RING_MASK (7<<0)
+#define I915_EXEC_DEFAULT (0<<0)
#define I915_EXEC_RENDER (1<<0)
-#define I915_EXEC_BSD (1<<1)
+#define I915_EXEC_BSD (2<<0)
+#define I915_EXEC_BLT (3<<0)
__u64 flags;
__u64 rsvd1;
__u64 rsvd2;
diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h
new file mode 100644
index 000000000000..d3c81946f613
--- /dev/null
+++ b/include/drm/intel-gtt.h
@@ -0,0 +1,18 @@
+/* Common header for intel-gtt.ko and i915.ko */
+
+#ifndef _DRM_INTEL_GTT_H
+#define _DRM_INTEL_GTT_H
+struct intel_gtt {
+ /* Number of stolen gtt entries at the beginning. */
+ unsigned int gtt_stolen_entries;
+ /* Total number of gtt entries. */
+ unsigned int gtt_total_entries;
+ /* Part of the gtt that is mappable by the cpu, for those chips where
+ * this is not the full gtt. */
+ unsigned int gtt_mappable_entries;
+};
+
+struct intel_gtt *intel_gtt_get(void);
+
+#endif
+
diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h
index 2040e6c4f172..5afa5b52063e 100644
--- a/include/drm/ttm/ttm_bo_api.h
+++ b/include/drm/ttm/ttm_bo_api.h
@@ -102,7 +102,8 @@ struct ttm_bus_placement {
*/
struct ttm_mem_reg {
- struct drm_mm_node *mm_node;
+ void *mm_node;
+ unsigned long start;
unsigned long size;
unsigned long num_pages;
uint32_t page_alignment;
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
index b87504235f18..d01b4ddbdc56 100644
--- a/include/drm/ttm/ttm_bo_driver.h
+++ b/include/drm/ttm/ttm_bo_driver.h
@@ -203,7 +203,22 @@ struct ttm_tt {
* It's set up by the ttm_bo_driver::init_mem_type method.
*/
+struct ttm_mem_type_manager;
+
+struct ttm_mem_type_manager_func {
+ int (*init)(struct ttm_mem_type_manager *man, unsigned long p_size);
+ int (*takedown)(struct ttm_mem_type_manager *man);
+ int (*get_node)(struct ttm_mem_type_manager *man,
+ struct ttm_buffer_object *bo,
+ struct ttm_placement *placement,
+ struct ttm_mem_reg *mem);
+ void (*put_node)(struct ttm_mem_type_manager *man,
+ struct ttm_mem_reg *mem);
+ void (*debug)(struct ttm_mem_type_manager *man, const char *prefix);
+};
+
struct ttm_mem_type_manager {
+ struct ttm_bo_device *bdev;
/*
* No protection. Constant from start.
@@ -222,8 +237,8 @@ struct ttm_mem_type_manager {
* TODO: Consider one lru_lock per ttm_mem_type_manager.
* Plays ill with list removal, though.
*/
-
- struct drm_mm manager;
+ const struct ttm_mem_type_manager_func *func;
+ void *priv;
struct list_head lru;
};
@@ -649,6 +664,12 @@ extern int ttm_bo_mem_space(struct ttm_buffer_object *bo,
struct ttm_mem_reg *mem,
bool interruptible,
bool no_wait_reserve, bool no_wait_gpu);
+
+extern void ttm_bo_mem_put(struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *mem);
+extern void ttm_bo_mem_put_locked(struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *mem);
+
/**
* ttm_bo_wait_for_cpu
*
@@ -891,6 +912,8 @@ extern int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
*/
extern pgprot_t ttm_io_prot(uint32_t caching_flags, pgprot_t tmp);
+extern const struct ttm_mem_type_manager_func ttm_bo_manager_func;
+
#if (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE)))
#define TTM_HAS_AGP
#include <linux/agp_backend.h>
diff --git a/include/drm/vmwgfx_drm.h b/include/drm/vmwgfx_drm.h
index 4d0842391edc..650e6bf6f69f 100644
--- a/include/drm/vmwgfx_drm.h
+++ b/include/drm/vmwgfx_drm.h
@@ -72,6 +72,7 @@
#define DRM_VMW_PARAM_FIFO_OFFSET 3
#define DRM_VMW_PARAM_HW_CAPS 4
#define DRM_VMW_PARAM_FIFO_CAPS 5
+#define DRM_VMW_PARAM_MAX_FB_SIZE 6
/**
* struct drm_vmw_getparam_arg
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 4e8ea8c8ec1e..831c4634162c 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -301,6 +301,7 @@ header-y += quota.h
header-y += radeonfb.h
header-y += random.h
header-y += raw.h
+header-y += rds.h
header-y += reboot.h
header-y += reiserfs_fs.h
header-y += reiserfs_xattr.h
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index c227757feb06..050a7bccb836 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -245,8 +245,6 @@ int acpi_check_resource_conflict(const struct resource *res);
int acpi_check_region(resource_size_t start, resource_size_t n,
const char *name);
-int acpi_check_mem_region(resource_size_t start, resource_size_t n,
- const char *name);
int acpi_resources_are_enforced(void);
@@ -308,6 +306,9 @@ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
u32 *mask, u32 req);
extern void acpi_early_init(void);
+int acpi_os_map_generic_address(struct acpi_generic_address *addr);
+void acpi_os_unmap_generic_address(struct acpi_generic_address *addr);
+
#else /* !CONFIG_ACPI */
#define acpi_disabled 1
@@ -344,12 +345,6 @@ static inline int acpi_check_region(resource_size_t start, resource_size_t n,
return 0;
}
-static inline int acpi_check_mem_region(resource_size_t start,
- resource_size_t n, const char *name)
-{
- return 0;
-}
-
struct acpi_table_header;
static inline int acpi_table_parse(char *id,
int (*handler)(struct acpi_table_header *))
diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h
new file mode 100644
index 000000000000..521a0f8974ac
--- /dev/null
+++ b/include/linux/amba/pl08x.h
@@ -0,0 +1,222 @@
+/*
+ * linux/amba/pl08x.h - ARM PrimeCell DMA Controller driver
+ *
+ * Copyright (C) 2005 ARM Ltd
+ * Copyright (C) 2010 ST-Ericsson SA
+ *
+ * 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.
+ *
+ * pl08x information required by platform code
+ *
+ * Please credit ARM.com
+ * Documentation: ARM DDI 0196D
+ *
+ */
+
+#ifndef AMBA_PL08X_H
+#define AMBA_PL08X_H
+
+/* We need sizes of structs from this header */
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+
+/**
+ * struct pl08x_channel_data - data structure to pass info between
+ * platform and PL08x driver regarding channel configuration
+ * @bus_id: name of this device channel, not just a device name since
+ * devices may have more than one channel e.g. "foo_tx"
+ * @min_signal: the minimum DMA signal number to be muxed in for this
+ * channel (for platforms supporting muxed signals). If you have
+ * static assignments, make sure this is set to the assigned signal
+ * number, PL08x have 16 possible signals in number 0 thru 15 so
+ * when these are not enough they often get muxed (in hardware)
+ * disabling simultaneous use of the same channel for two devices.
+ * @max_signal: the maximum DMA signal number to be muxed in for
+ * the channel. Set to the same as min_signal for
+ * devices with static assignments
+ * @muxval: a number usually used to poke into some mux regiser to
+ * mux in the signal to this channel
+ * @cctl_opt: default options for the channel control register
+ * @addr: source/target address in physical memory for this DMA channel,
+ * can be the address of a FIFO register for burst requests for example.
+ * This can be left undefined if the PrimeCell API is used for configuring
+ * this.
+ * @circular_buffer: whether the buffer passed in is circular and
+ * shall simply be looped round round (like a record baby round
+ * round round round)
+ * @single: the device connected to this channel will request single
+ * DMA transfers, not bursts. (Bursts are default.)
+ */
+struct pl08x_channel_data {
+ char *bus_id;
+ int min_signal;
+ int max_signal;
+ u32 muxval;
+ u32 cctl;
+ u32 ccfg;
+ dma_addr_t addr;
+ bool circular_buffer;
+ bool single;
+};
+
+/**
+ * Struct pl08x_bus_data - information of source or destination
+ * busses for a transfer
+ * @addr: current address
+ * @maxwidth: the maximum width of a transfer on this bus
+ * @buswidth: the width of this bus in bytes: 1, 2 or 4
+ * @fill_bytes: bytes required to fill to the next bus memory
+ * boundary
+ */
+struct pl08x_bus_data {
+ dma_addr_t addr;
+ u8 maxwidth;
+ u8 buswidth;
+ u32 fill_bytes;
+};
+
+/**
+ * struct pl08x_phy_chan - holder for the physical channels
+ * @id: physical index to this channel
+ * @lock: a lock to use when altering an instance of this struct
+ * @signal: the physical signal (aka channel) serving this
+ * physical channel right now
+ * @serving: the virtual channel currently being served by this
+ * physical channel
+ */
+struct pl08x_phy_chan {
+ unsigned int id;
+ void __iomem *base;
+ spinlock_t lock;
+ int signal;
+ struct pl08x_dma_chan *serving;
+ u32 csrc;
+ u32 cdst;
+ u32 clli;
+ u32 cctl;
+ u32 ccfg;
+};
+
+/**
+ * struct pl08x_txd - wrapper for struct dma_async_tx_descriptor
+ * @llis_bus: DMA memory address (physical) start for the LLIs
+ * @llis_va: virtual memory address start for the LLIs
+ */
+struct pl08x_txd {
+ struct dma_async_tx_descriptor tx;
+ struct list_head node;
+ enum dma_data_direction direction;
+ struct pl08x_bus_data srcbus;
+ struct pl08x_bus_data dstbus;
+ int len;
+ dma_addr_t llis_bus;
+ void *llis_va;
+ struct pl08x_channel_data *cd;
+ bool active;
+ /*
+ * Settings to be put into the physical channel when we
+ * trigger this txd
+ */
+ u32 csrc;
+ u32 cdst;
+ u32 clli;
+ u32 cctl;
+};
+
+/**
+ * struct pl08x_dma_chan_state - holds the PL08x specific virtual
+ * channel states
+ * @PL08X_CHAN_IDLE: the channel is idle
+ * @PL08X_CHAN_RUNNING: the channel has allocated a physical transport
+ * channel and is running a transfer on it
+ * @PL08X_CHAN_PAUSED: the channel has allocated a physical transport
+ * channel, but the transfer is currently paused
+ * @PL08X_CHAN_WAITING: the channel is waiting for a physical transport
+ * channel to become available (only pertains to memcpy channels)
+ */
+enum pl08x_dma_chan_state {
+ PL08X_CHAN_IDLE,
+ PL08X_CHAN_RUNNING,
+ PL08X_CHAN_PAUSED,
+ PL08X_CHAN_WAITING,
+};
+
+/**
+ * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel
+ * @chan: wrappped abstract channel
+ * @phychan: the physical channel utilized by this channel, if there is one
+ * @tasklet: tasklet scheduled by the IRQ to handle actual work etc
+ * @name: name of channel
+ * @cd: channel platform data
+ * @runtime_addr: address for RX/TX according to the runtime config
+ * @runtime_direction: current direction of this channel according to
+ * runtime config
+ * @lc: last completed transaction on this channel
+ * @desc_list: queued transactions pending on this channel
+ * @at: active transaction on this channel
+ * @lockflags: sometimes we let a lock last between two function calls,
+ * especially prep/submit, and then we need to store the IRQ flags
+ * in the channel state, here
+ * @lock: a lock for this channel data
+ * @host: a pointer to the host (internal use)
+ * @state: whether the channel is idle, paused, running etc
+ * @slave: whether this channel is a device (slave) or for memcpy
+ * @waiting: a TX descriptor on this channel which is waiting for
+ * a physical channel to become available
+ */
+struct pl08x_dma_chan {
+ struct dma_chan chan;
+ struct pl08x_phy_chan *phychan;
+ struct tasklet_struct tasklet;
+ char *name;
+ struct pl08x_channel_data *cd;
+ dma_addr_t runtime_addr;
+ enum dma_data_direction runtime_direction;
+ atomic_t last_issued;
+ dma_cookie_t lc;
+ struct list_head desc_list;
+ struct pl08x_txd *at;
+ unsigned long lockflags;
+ spinlock_t lock;
+ void *host;
+ enum pl08x_dma_chan_state state;
+ bool slave;
+ struct pl08x_txd *waiting;
+};
+
+/**
+ * struct pl08x_platform_data - the platform configuration for the
+ * PL08x PrimeCells.
+ * @slave_channels: the channels defined for the different devices on the
+ * platform, all inclusive, including multiplexed channels. The available
+ * physical channels will be multiplexed around these signals as they
+ * are requested, just enumerate all possible channels.
+ * @get_signal: request a physical signal to be used for a DMA
+ * transfer immediately: if there is some multiplexing or similar blocking
+ * the use of the channel the transfer can be denied by returning
+ * less than zero, else it returns the allocated signal number
+ * @put_signal: indicate to the platform that this physical signal is not
+ * running any DMA transfer and multiplexing can be recycled
+ * @bus_bit_lli: Bit[0] of the address indicated which AHB bus master the
+ * LLI addresses are on 0/1 Master 1/2.
+ */
+struct pl08x_platform_data {
+ struct pl08x_channel_data *slave_channels;
+ unsigned int num_slave_channels;
+ struct pl08x_channel_data memcpy_channel;
+ int (*get_signal)(struct pl08x_dma_chan *);
+ void (*put_signal)(struct pl08x_dma_chan *);
+};
+
+#ifdef CONFIG_AMBA_PL08X
+bool pl08x_filter_id(struct dma_chan *chan, void *chan_id);
+#else
+static inline bool pl08x_filter_id(struct dma_chan *chan, void *chan_id)
+{
+ return false;
+}
+#endif
+
+#endif /* AMBA_PL08X_H */
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
index f6481daf6e52..a8e4e832cdbb 100644
--- a/include/linux/atmdev.h
+++ b/include/linux/atmdev.h
@@ -449,7 +449,7 @@ void vcc_insert_socket(struct sock *sk);
static inline int atm_guess_pdu2truesize(int size)
{
- return (SKB_DATA_ALIGN(size) + sizeof(struct skb_shared_info));
+ return SKB_DATA_ALIGN(size) + sizeof(struct skb_shared_info);
}
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index 35b00746c712..4ce34fa937d4 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -111,6 +111,7 @@ void bdi_wakeup_thread_delayed(struct backing_dev_info *bdi);
extern spinlock_t bdi_lock;
extern struct list_head bdi_list;
+extern struct list_head bdi_pending_list;
static inline int wb_has_dirty_io(struct bdi_writeback *wb)
{
@@ -285,7 +286,7 @@ enum {
void clear_bdi_congested(struct backing_dev_info *bdi, int sync);
void set_bdi_congested(struct backing_dev_info *bdi, int sync);
long congestion_wait(int sync, long timeout);
-
+long wait_iff_congested(struct zone *zone, int sync, long timeout);
static inline bool bdi_cap_writeback_dirty(struct backing_dev_info *bdi)
{
diff --git a/include/linux/basic_mmio_gpio.h b/include/linux/basic_mmio_gpio.h
new file mode 100644
index 000000000000..198087a16fc4
--- /dev/null
+++ b/include/linux/basic_mmio_gpio.h
@@ -0,0 +1,20 @@
+/*
+ * Basic memory-mapped GPIO controllers.
+ *
+ * Copyright 2008 MontaVista Software, Inc.
+ * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@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 (at your
+ * option) any later version.
+ */
+
+#ifndef __BASIC_MMIO_GPIO_H
+#define __BASIC_MMIO_GPIO_H
+
+struct bgpio_pdata {
+ int base;
+};
+
+#endif /* __BASIC_MMIO_GPIO_H */
diff --git a/include/linux/bfin_mac.h b/include/linux/bfin_mac.h
new file mode 100644
index 000000000000..904dec7d03a1
--- /dev/null
+++ b/include/linux/bfin_mac.h
@@ -0,0 +1,29 @@
+/*
+ * Blackfin On-Chip MAC Driver
+ *
+ * Copyright 2004-2010 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _LINUX_BFIN_MAC_H_
+#define _LINUX_BFIN_MAC_H_
+
+#include <linux/phy.h>
+
+struct bfin_phydev_platform_data {
+ unsigned short addr;
+ int irq;
+};
+
+struct bfin_mii_bus_platform_data {
+ int phydev_number;
+ struct bfin_phydev_platform_data *phydev_data;
+ const unsigned short *mac_peripherals;
+ int phy_mode;
+ unsigned int phy_mask;
+};
+
+#endif
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 009b80e49f53..5027a599077d 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -115,7 +115,6 @@ struct request {
void *elevator_private3;
struct gendisk *rq_disk;
- struct hd_struct *part;
unsigned long start_time;
#ifdef CONFIG_BLK_CGROUP
unsigned long long start_time_ns;
@@ -892,6 +891,14 @@ static inline int sb_issue_discard(struct super_block *sb, sector_t block,
nr_blocks << (sb->s_blocksize_bits - 9),
gfp_mask, flags);
}
+static inline int sb_issue_zeroout(struct super_block *sb, sector_t block,
+ sector_t nr_blocks, gfp_t gfp_mask)
+{
+ return blkdev_issue_zeroout(sb->s_bdev,
+ block << (sb->s_blocksize_bits - 9),
+ nr_blocks << (sb->s_blocksize_bits - 9),
+ gfp_mask);
+}
extern int blk_verify_command(unsigned char *cmd, fmode_t has_write_perm);
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index dd1b25b2641c..68d1fe7b877c 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -212,7 +212,6 @@ int generic_write_end(struct file *, struct address_space *,
loff_t, unsigned, unsigned,
struct page *, void *);
void page_zero_new_buffers(struct page *page, unsigned from, unsigned to);
-int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
int cont_write_begin(struct file *, struct address_space *, loff_t,
unsigned, unsigned, struct page **, void **,
get_block_t *, loff_t *);
diff --git a/include/linux/can/platform/mcp251x.h b/include/linux/can/platform/mcp251x.h
index dba28268e651..8e20540043f5 100644
--- a/include/linux/can/platform/mcp251x.h
+++ b/include/linux/can/platform/mcp251x.h
@@ -12,7 +12,6 @@
/**
* struct mcp251x_platform_data - MCP251X SPI CAN controller platform data
* @oscillator_frequency: - oscillator frequency in Hz
- * @model: - actual type of chip
* @board_specific_setup: - called before probing the chip (power,reset)
* @transceiver_enable: - called to power on/off the transceiver
* @power_enable: - called to power on/off the mcp *and* the
@@ -25,9 +24,6 @@
struct mcp251x_platform_data {
unsigned long oscillator_frequency;
- int model;
-#define CAN_MCP251X_MCP2510 0x2510
-#define CAN_MCP251X_MCP2515 0x2515
int (*board_specific_setup)(struct spi_device *spi);
int (*transceiver_enable)(int enable);
int (*power_enable) (int enable);
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 709dfb901d11..ed4ba111bc8d 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -154,6 +154,10 @@ enum {
* A thread in rmdir() is wating for this cgroup.
*/
CGRP_WAIT_ON_RMDIR,
+ /*
+ * Clone cgroup values when creating a new child cgroup
+ */
+ CGRP_CLONE_CHILDREN,
};
/* which pidlist file are we talking about? */
diff --git a/include/linux/coda_fs_i.h b/include/linux/coda_fs_i.h
index b3ef0c461578..e35071b1de0e 100644
--- a/include/linux/coda_fs_i.h
+++ b/include/linux/coda_fs_i.h
@@ -10,19 +10,24 @@
#include <linux/types.h>
#include <linux/list.h>
+#include <linux/spinlock.h>
#include <linux/coda.h>
/*
* coda fs inode data
+ * c_lock protects accesses to c_flags, c_mapcount, c_cached_epoch, c_uid and
+ * c_cached_perm.
+ * vfs_inode is set only when the inode is created and never changes.
+ * c_fid is set when the inode is created and should be considered immutable.
*/
struct coda_inode_info {
- struct CodaFid c_fid; /* Coda identifier */
- u_short c_flags; /* flags (see below) */
- struct list_head c_cilist; /* list of all coda inodes */
+ struct CodaFid c_fid; /* Coda identifier */
+ u_short c_flags; /* flags (see below) */
unsigned int c_mapcount; /* nr of times this inode is mapped */
unsigned int c_cached_epoch; /* epoch for cached permissions */
vuid_t c_uid; /* fsuid for cached permissions */
- unsigned int c_cached_perm; /* cached access permissions */
+ unsigned int c_cached_perm; /* cached access permissions */
+ spinlock_t c_lock;
struct inode vfs_inode;
};
diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h
index dcc228aa335a..2e914d0771b9 100644
--- a/include/linux/coda_linux.h
+++ b/include/linux/coda_linux.h
@@ -89,7 +89,11 @@ static __inline__ char *coda_i2s(struct inode *inode)
/* this will not zap the inode away */
static __inline__ void coda_flag_inode(struct inode *inode, int flag)
{
- ITOC(inode)->c_flags |= flag;
+ struct coda_inode_info *cii = ITOC(inode);
+
+ spin_lock(&cii->c_lock);
+ cii->c_flags |= flag;
+ spin_unlock(&cii->c_lock);
}
#endif
diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h
index 284b520934a0..72f2d2f0af91 100644
--- a/include/linux/coda_psdev.h
+++ b/include/linux/coda_psdev.h
@@ -8,6 +8,7 @@
#ifdef __KERNEL__
#include <linux/backing-dev.h>
+#include <linux/mutex.h>
struct kstatfs;
@@ -20,6 +21,7 @@ struct venus_comm {
int vc_inuse;
struct super_block *vc_sb;
struct backing_dev_info bdi;
+ struct mutex vc_mutex;
};
@@ -63,7 +65,7 @@ int venus_symlink(struct super_block *sb, struct CodaFid *fid,
int venus_access(struct super_block *sb, struct CodaFid *fid, int mask);
int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
unsigned int cmd, struct PioctlData *data);
-int coda_downcall(int opcode, union outputArgs *out, struct super_block *sb);
+int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out);
int venus_fsync(struct super_block *sb, struct CodaFid *fid);
int venus_statfs(struct dentry *dentry, struct kstatfs *sfs);
diff --git a/include/linux/completion.h b/include/linux/completion.h
index 51e3145196f6..36d57f74cd01 100644
--- a/include/linux/completion.h
+++ b/include/linux/completion.h
@@ -10,7 +10,7 @@
#include <linux/wait.h>
-/**
+/*
* struct completion - structure used to maintain state for a "completion"
*
* This is the opaque structure used to maintain the state for a "completion".
@@ -34,7 +34,7 @@ struct completion {
({ init_completion(&work); work; })
/**
- * DECLARE_COMPLETION: - declare and initialize a completion structure
+ * DECLARE_COMPLETION - declare and initialize a completion structure
* @work: identifier for the completion structure
*
* This macro declares and initializes a completion structure. Generally used
@@ -50,7 +50,7 @@ struct completion {
* are on the kernel stack:
*/
/**
- * DECLARE_COMPLETION_ONSTACK: - declare and initialize a completion structure
+ * DECLARE_COMPLETION_ONSTACK - declare and initialize a completion structure
* @work: identifier for the completion structure
*
* This macro declares and initializes a completion structure on the kernel
@@ -64,7 +64,7 @@ struct completion {
#endif
/**
- * init_completion: - Initialize a dynamically allocated completion
+ * init_completion - Initialize a dynamically allocated completion
* @x: completion structure that is to be initialized
*
* This inline function will initialize a dynamically created completion
@@ -92,7 +92,7 @@ extern void complete(struct completion *);
extern void complete_all(struct completion *);
/**
- * INIT_COMPLETION: - reinitialize a completion structure
+ * INIT_COMPLETION - reinitialize a completion structure
* @x: completion structure to be reinitialized
*
* This macro should be used to reinitialize a completion structure so it can
diff --git a/include/linux/connector.h b/include/linux/connector.h
index 3a779ffba60b..7e8ca75d2dad 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -88,12 +88,6 @@ struct cn_queue_dev {
unsigned char name[CN_CBQ_NAMELEN];
struct workqueue_struct *cn_queue;
- /* Sent to kevent to create cn_queue only when needed */
- struct work_struct wq_creation;
- /* Tell if the wq_creation job is pending/completed */
- atomic_t wq_requested;
- /* Wait for cn_queue to be created */
- wait_queue_head_t wq_created;
struct list_head queue_list;
spinlock_t queue_lock;
@@ -141,8 +135,6 @@ int cn_netlink_send(struct cn_msg *, u32, gfp_t);
int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(struct cn_msg *, struct netlink_skb_parms *));
void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id);
-int queue_cn_work(struct cn_callback_entry *cbq, struct work_struct *work);
-
struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *);
void cn_queue_free_dev(struct cn_queue_dev *dev);
diff --git a/include/linux/davinci_emac.h b/include/linux/davinci_emac.h
index 7c930dba477c..5dd428532f79 100644
--- a/include/linux/davinci_emac.h
+++ b/include/linux/davinci_emac.h
@@ -14,16 +14,26 @@
#include <linux/if_ether.h>
#include <linux/memory.h>
+struct mdio_platform_data {
+ unsigned long bus_freq;
+};
+
struct emac_platform_data {
char mac_addr[ETH_ALEN];
u32 ctrl_reg_offset;
u32 ctrl_mod_reg_offset;
u32 ctrl_ram_offset;
u32 hw_ram_addr;
- u32 mdio_reg_offset;
u32 ctrl_ram_size;
- u32 phy_mask;
- u32 mdio_max_freq;
+
+ /*
+ * phy_id can be one of the following:
+ * - NULL : use the first phy on the bus,
+ * - "" : force to 100/full, no mdio control
+ * - "<bus>:<addr>" : use the specified bus and phy
+ */
+ const char *phy_id;
+
u8 rmii_en;
u8 version;
void (*interrupt_enable) (void);
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index 7434a8353e23..7187bd8a75f6 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -165,8 +165,10 @@ enum {
DCCPO_TIMESTAMP_ECHO = 42,
DCCPO_ELAPSED_TIME = 43,
DCCPO_MAX = 45,
- DCCPO_MIN_CCID_SPECIFIC = 128,
- DCCPO_MAX_CCID_SPECIFIC = 255,
+ DCCPO_MIN_RX_CCID_SPECIFIC = 128, /* from sender to receiver */
+ DCCPO_MAX_RX_CCID_SPECIFIC = 191,
+ DCCPO_MIN_TX_CCID_SPECIFIC = 192, /* from receiver to sender */
+ DCCPO_MAX_TX_CCID_SPECIFIC = 255,
};
/* maximum size of a single TLV-encoded DCCP option (sans type/len bytes) */
#define DCCP_SINGLE_OPT_MAXLEN 253
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index e2106495cc11..9d8688b92d8b 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -64,13 +64,15 @@ enum dma_transaction_type {
DMA_PQ_VAL,
DMA_MEMSET,
DMA_INTERRUPT,
+ DMA_SG,
DMA_PRIVATE,
DMA_ASYNC_TX,
DMA_SLAVE,
+ DMA_CYCLIC,
};
/* last transaction type for creation of the capabilities mask */
-#define DMA_TX_TYPE_END (DMA_SLAVE + 1)
+#define DMA_TX_TYPE_END (DMA_CYCLIC + 1)
/**
@@ -119,12 +121,15 @@ enum dma_ctrl_flags {
* configuration data in statically from the platform). An additional
* argument of struct dma_slave_config must be passed in with this
* command.
+ * @FSLDMA_EXTERNAL_START: this command will put the Freescale DMA controller
+ * into external start mode.
*/
enum dma_ctrl_cmd {
DMA_TERMINATE_ALL,
DMA_PAUSE,
DMA_RESUME,
DMA_SLAVE_CONFIG,
+ FSLDMA_EXTERNAL_START,
};
/**
@@ -316,14 +321,14 @@ struct dma_async_tx_descriptor {
dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);
dma_async_tx_callback callback;
void *callback_param;
-#ifndef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH
+#ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
struct dma_async_tx_descriptor *next;
struct dma_async_tx_descriptor *parent;
spinlock_t lock;
#endif
};
-#ifdef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH
+#ifndef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
static inline void txd_lock(struct dma_async_tx_descriptor *txd)
{
}
@@ -422,6 +427,9 @@ struct dma_tx_state {
* @device_prep_dma_memset: prepares a memset operation
* @device_prep_dma_interrupt: prepares an end of chain interrupt operation
* @device_prep_slave_sg: prepares a slave dma operation
+ * @device_prep_dma_cyclic: prepare a cyclic dma operation suitable for audio.
+ * The function takes a buffer of size buf_len. The callback function will
+ * be called after period_len bytes have been transferred.
* @device_control: manipulate all pending operations on a channel, returns
* zero or error code
* @device_tx_status: poll for transaction completion, the optional
@@ -473,11 +481,19 @@ struct dma_device {
unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)(
struct dma_chan *chan, unsigned long flags);
+ struct dma_async_tx_descriptor *(*device_prep_dma_sg)(
+ struct dma_chan *chan,
+ struct scatterlist *dst_sg, unsigned int dst_nents,
+ struct scatterlist *src_sg, unsigned int src_nents,
+ unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_slave_sg)(
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_data_direction direction,
unsigned long flags);
+ struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)(
+ struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+ size_t period_len, enum dma_data_direction direction);
int (*device_control)(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
unsigned long arg);
@@ -487,6 +503,40 @@ struct dma_device {
void (*device_issue_pending)(struct dma_chan *chan);
};
+static inline int dmaengine_device_control(struct dma_chan *chan,
+ enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ return chan->device->device_control(chan, cmd, arg);
+}
+
+static inline int dmaengine_slave_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ return dmaengine_device_control(chan, DMA_SLAVE_CONFIG,
+ (unsigned long)config);
+}
+
+static inline int dmaengine_terminate_all(struct dma_chan *chan)
+{
+ return dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
+}
+
+static inline int dmaengine_pause(struct dma_chan *chan)
+{
+ return dmaengine_device_control(chan, DMA_PAUSE, 0);
+}
+
+static inline int dmaengine_resume(struct dma_chan *chan)
+{
+ return dmaengine_device_control(chan, DMA_RESUME, 0);
+}
+
+static inline int dmaengine_submit(struct dma_async_tx_descriptor *desc)
+{
+ return desc->tx_submit(desc);
+}
+
static inline bool dmaengine_check_align(u8 align, size_t off1, size_t off2, size_t len)
{
size_t mask;
@@ -606,11 +656,11 @@ static inline void net_dmaengine_put(void)
#ifdef CONFIG_ASYNC_TX_DMA
#define async_dmaengine_get() dmaengine_get()
#define async_dmaengine_put() dmaengine_put()
-#ifdef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH
+#ifndef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
#define async_dma_find_channel(type) dma_find_channel(DMA_ASYNC_TX)
#else
#define async_dma_find_channel(type) dma_find_channel(type)
-#endif /* CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH */
+#endif /* CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH */
#else
static inline void async_dmaengine_get(void)
{
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index 80a0ece8f7e4..4fd978e7eb83 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -122,8 +122,6 @@ extern void elv_completed_request(struct request_queue *, struct request *);
extern int elv_set_request(struct request_queue *, struct request *, gfp_t);
extern void elv_put_request(struct request_queue *, struct request *);
extern void elv_drain_elevator(struct request_queue *);
-extern void elv_quiesce_start(struct request_queue *);
-extern void elv_quiesce_end(struct request_queue *);
/*
* io scheduler registration
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index 2308fbb4523a..f16a01081e15 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -71,7 +71,7 @@ static inline int is_zero_ether_addr(const u8 *addr)
*/
static inline int is_multicast_ether_addr(const u8 *addr)
{
- return (0x01 & addr[0]);
+ return 0x01 & addr[0];
}
/**
@@ -82,7 +82,7 @@ static inline int is_multicast_ether_addr(const u8 *addr)
*/
static inline int is_local_ether_addr(const u8 *addr)
{
- return (0x02 & addr[0]);
+ return 0x02 & addr[0];
}
/**
@@ -237,13 +237,29 @@ static inline bool is_etherdev_addr(const struct net_device *dev,
* entry points.
*/
-static inline int compare_ether_header(const void *a, const void *b)
+static inline unsigned long compare_ether_header(const void *a, const void *b)
{
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+ unsigned long fold;
+
+ /*
+ * We want to compare 14 bytes:
+ * [a0 ... a13] ^ [b0 ... b13]
+ * Use two long XOR, ORed together, with an overlap of two bytes.
+ * [a0 a1 a2 a3 a4 a5 a6 a7 ] ^ [b0 b1 b2 b3 b4 b5 b6 b7 ] |
+ * [a6 a7 a8 a9 a10 a11 a12 a13] ^ [b6 b7 b8 b9 b10 b11 b12 b13]
+ * This means the [a6 a7] ^ [b6 b7] part is done two times.
+ */
+ fold = *(unsigned long *)a ^ *(unsigned long *)b;
+ fold |= *(unsigned long *)(a + 6) ^ *(unsigned long *)(b + 6);
+ return fold;
+#else
u32 *a32 = (u32 *)((u8 *)a + 2);
u32 *b32 = (u32 *)((u8 *)b + 2);
return (*(u16 *)a ^ *(u16 *)b) | (a32[0] ^ b32[0]) |
(a32[1] ^ b32[1]) | (a32[2] ^ b32[2]);
+#endif
}
#endif /* _LINUX_ETHERDEVICE_H */
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 991269e5b152..6628a507fd3b 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -14,6 +14,7 @@
#define _LINUX_ETHTOOL_H
#include <linux/types.h>
+#include <linux/if_ether.h>
/* This should work for both 32 and 64 bit userland. */
struct ethtool_cmd {
@@ -308,15 +309,28 @@ struct ethtool_perm_addr {
* flag differs from the read-only value.
*/
enum ethtool_flags {
+ ETH_FLAG_TXVLAN = (1 << 7), /* TX VLAN offload enabled */
+ ETH_FLAG_RXVLAN = (1 << 8), /* RX VLAN offload enabled */
ETH_FLAG_LRO = (1 << 15), /* LRO is enabled */
ETH_FLAG_NTUPLE = (1 << 27), /* N-tuple filters enabled */
ETH_FLAG_RXHASH = (1 << 28),
};
/* The following structures are for supporting RX network flow
- * classification configuration. Note, all multibyte fields, e.g.,
- * ip4src, ip4dst, psrc, pdst, spi, etc. are expected to be in network
- * byte order.
+ * classification and RX n-tuple configuration. Note, all multibyte
+ * fields, e.g., ip4src, ip4dst, psrc, pdst, spi, etc. are expected to
+ * be in network byte order.
+ */
+
+/**
+ * struct ethtool_tcpip4_spec - flow specification for TCP/IPv4 etc.
+ * @ip4src: Source host
+ * @ip4dst: Destination host
+ * @psrc: Source port
+ * @pdst: Destination port
+ * @tos: Type-of-service
+ *
+ * This can be used to specify a TCP/IPv4, UDP/IPv4 or SCTP/IPv4 flow.
*/
struct ethtool_tcpip4_spec {
__be32 ip4src;
@@ -326,6 +340,15 @@ struct ethtool_tcpip4_spec {
__u8 tos;
};
+/**
+ * struct ethtool_ah_espip4_spec - flow specification for IPsec/IPv4
+ * @ip4src: Source host
+ * @ip4dst: Destination host
+ * @spi: Security parameters index
+ * @tos: Type-of-service
+ *
+ * This can be used to specify an IPsec transport or tunnel over IPv4.
+ */
struct ethtool_ah_espip4_spec {
__be32 ip4src;
__be32 ip4dst;
@@ -333,21 +356,17 @@ struct ethtool_ah_espip4_spec {
__u8 tos;
};
-struct ethtool_rawip4_spec {
- __be32 ip4src;
- __be32 ip4dst;
- __u8 hdata[64];
-};
-
-struct ethtool_ether_spec {
- __be16 ether_type;
- __u8 frame_size;
- __u8 eframe[16];
-};
-
#define ETH_RX_NFC_IP4 1
-#define ETH_RX_NFC_IP6 2
+/**
+ * struct ethtool_usrip4_spec - general flow specification for IPv4
+ * @ip4src: Source host
+ * @ip4dst: Destination host
+ * @l4_4_bytes: First 4 bytes of transport (layer 4) header
+ * @tos: Type-of-service
+ * @ip_ver: Value must be %ETH_RX_NFC_IP4; mask must be 0
+ * @proto: Transport protocol number; mask must be 0
+ */
struct ethtool_usrip4_spec {
__be32 ip4src;
__be32 ip4dst;
@@ -357,6 +376,15 @@ struct ethtool_usrip4_spec {
__u8 proto;
};
+/**
+ * struct ethtool_rx_flow_spec - specification for RX flow filter
+ * @flow_type: Type of match to perform, e.g. %TCP_V4_FLOW
+ * @h_u: Flow fields to match (dependent on @flow_type)
+ * @m_u: Masks for flow field bits to be ignored
+ * @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
+ */
struct ethtool_rx_flow_spec {
__u32 flow_type;
union {
@@ -365,36 +393,91 @@ struct ethtool_rx_flow_spec {
struct ethtool_tcpip4_spec sctp_ip4_spec;
struct ethtool_ah_espip4_spec ah_ip4_spec;
struct ethtool_ah_espip4_spec esp_ip4_spec;
- struct ethtool_rawip4_spec raw_ip4_spec;
- struct ethtool_ether_spec ether_spec;
struct ethtool_usrip4_spec usr_ip4_spec;
- __u8 hdata[64];
- } h_u, m_u; /* entry, mask */
+ struct ethhdr ether_spec;
+ __u8 hdata[72];
+ } h_u, m_u;
__u64 ring_cookie;
__u32 location;
};
+/**
+ * struct ethtool_rxnfc - command to get or set RX flow classification rules
+ * @cmd: Specific command number - %ETHTOOL_GRXFH, %ETHTOOL_SRXFH,
+ * %ETHTOOL_GRXRINGS, %ETHTOOL_GRXCLSRLCNT, %ETHTOOL_GRXCLSRULE,
+ * %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
+ * @rule_cnt: Number of rules to be affected
+ * @rule_locs: Array of valid rule indices
+ *
+ * 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
+ * structure fields must not be used.
+ *
+ * For %ETHTOOL_GRXRINGS, @data is set to the number of RX rings/queues
+ * on return.
+ *
+ * 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_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.
+ *
+ * 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_SRXCLSRLDEL, @fs.@location specifies the index of an
+ * existing filter rule on entry.
+ *
+ * Implementation of indexed classification rules generally requires a
+ * TCAM.
+ */
struct ethtool_rxnfc {
__u32 cmd;
__u32 flow_type;
- /* The rx flow hash value or the rule DB size */
__u64 data;
- /* The following fields are not valid and must not be used for
- * the ETHTOOL_{G,X}RXFH commands. */
struct ethtool_rx_flow_spec fs;
__u32 rule_cnt;
__u32 rule_locs[0];
};
+/**
+ * struct ethtool_rxfh_indir - command to get or set RX flow hash indirection
+ * @cmd: Specific command number - %ETHTOOL_GRXFHINDIR or %ETHTOOL_SRXFHINDIR
+ * @size: On entry, the array size of the user buffer. On return from
+ * %ETHTOOL_GRXFHINDIR, the array size of the hardware indirection table.
+ * @ring_index: RX ring/queue index for each hash value
+ */
struct ethtool_rxfh_indir {
__u32 cmd;
- /* On entry, this is the array size of the user buffer. On
- * return from ETHTOOL_GRXFHINDIR, this is the array size of
- * the hardware indirection table. */
__u32 size;
- __u32 ring_index[0]; /* ring/queue index for each hash value */
+ __u32 ring_index[0];
};
+/**
+ * struct ethtool_rx_ntuple_flow_spec - specification for RX flow filter
+ * @flow_type: Type of match to perform, e.g. %TCP_V4_FLOW
+ * @h_u: Flow field values to match (dependent on @flow_type)
+ * @m_u: Masks for flow field value bits to be ignored
+ * @vlan_tag: VLAN tag to match
+ * @vlan_tag_mask: Mask for VLAN tag bits to be ignored
+ * @data: Driver-dependent data to match
+ * @data_mask: Mask for driver-dependent data bits to be ignored
+ * @action: RX ring/queue index to deliver to (non-negative) or other action
+ * (negative, e.g. %ETHTOOL_RXNTUPLE_ACTION_DROP)
+ *
+ * For flow types %TCP_V4_FLOW, %UDP_V4_FLOW and %SCTP_V4_FLOW, where
+ * a field value and mask are both zero this is treated as if all mask
+ * bits are set i.e. the field is ignored.
+ */
struct ethtool_rx_ntuple_flow_spec {
__u32 flow_type;
union {
@@ -403,22 +486,26 @@ struct ethtool_rx_ntuple_flow_spec {
struct ethtool_tcpip4_spec sctp_ip4_spec;
struct ethtool_ah_espip4_spec ah_ip4_spec;
struct ethtool_ah_espip4_spec esp_ip4_spec;
- struct ethtool_rawip4_spec raw_ip4_spec;
- struct ethtool_ether_spec ether_spec;
struct ethtool_usrip4_spec usr_ip4_spec;
- __u8 hdata[64];
- } h_u, m_u; /* entry, mask */
+ struct ethhdr ether_spec;
+ __u8 hdata[72];
+ } h_u, m_u;
__u16 vlan_tag;
__u16 vlan_tag_mask;
- __u64 data; /* user-defined flow spec data */
- __u64 data_mask; /* user-defined flow spec mask */
+ __u64 data;
+ __u64 data_mask;
- /* signed to distinguish between queue and actions (DROP) */
__s32 action;
-#define ETHTOOL_RXNTUPLE_ACTION_DROP -1
+#define ETHTOOL_RXNTUPLE_ACTION_DROP (-1) /* drop packet */
+#define ETHTOOL_RXNTUPLE_ACTION_CLEAR (-2) /* clear filter */
};
+/**
+ * struct ethtool_rx_ntuple - command to set or clear RX flow filter
+ * @cmd: Command number - %ETHTOOL_SRXNTUPLE
+ * @fs: Flow filter specification
+ */
struct ethtool_rx_ntuple {
__u32 cmd;
struct ethtool_rx_ntuple_flow_spec fs;
@@ -759,22 +846,23 @@ struct ethtool_ops {
#define WAKE_MAGIC (1 << 5)
#define WAKE_MAGICSECURE (1 << 6) /* only meaningful if WAKE_MAGIC */
-/* L3-L4 network traffic flow types */
-#define TCP_V4_FLOW 0x01
-#define UDP_V4_FLOW 0x02
-#define SCTP_V4_FLOW 0x03
-#define AH_ESP_V4_FLOW 0x04
-#define TCP_V6_FLOW 0x05
-#define UDP_V6_FLOW 0x06
-#define SCTP_V6_FLOW 0x07
-#define AH_ESP_V6_FLOW 0x08
-#define AH_V4_FLOW 0x09
-#define ESP_V4_FLOW 0x0a
-#define AH_V6_FLOW 0x0b
-#define ESP_V6_FLOW 0x0c
-#define IP_USER_FLOW 0x0d
-#define IPV4_FLOW 0x10
-#define IPV6_FLOW 0x11
+/* L2-L4 network traffic flow types */
+#define TCP_V4_FLOW 0x01 /* hash or spec (tcp_ip4_spec) */
+#define UDP_V4_FLOW 0x02 /* hash or spec (udp_ip4_spec) */
+#define SCTP_V4_FLOW 0x03 /* hash or spec (sctp_ip4_spec) */
+#define AH_ESP_V4_FLOW 0x04 /* hash only */
+#define TCP_V6_FLOW 0x05 /* hash only */
+#define UDP_V6_FLOW 0x06 /* hash only */
+#define SCTP_V6_FLOW 0x07 /* hash only */
+#define AH_ESP_V6_FLOW 0x08 /* hash only */
+#define AH_V4_FLOW 0x09 /* hash or spec (ah_ip4_spec) */
+#define ESP_V4_FLOW 0x0a /* hash or spec (esp_ip4_spec) */
+#define AH_V6_FLOW 0x0b /* hash only */
+#define ESP_V6_FLOW 0x0c /* hash only */
+#define IP_USER_FLOW 0x0d /* spec only (usr_ip4_spec) */
+#define IPV4_FLOW 0x10 /* hash only */
+#define IPV6_FLOW 0x11 /* hash only */
+#define ETHER_FLOW 0x12 /* spec only (ether_spec) */
/* L3-L4 network traffic flow hash options */
#define RXH_L2DA (1 << 1)
diff --git a/include/linux/fb.h b/include/linux/fb.h
index f0268deca658..7fca3dc4e475 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -931,6 +931,8 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {
#define fb_writel sbus_writel
#define fb_writeq sbus_writeq
#define fb_memset sbus_memset_io
+#define fb_memcpy_fromfb sbus_memcpy_fromio
+#define fb_memcpy_tofb sbus_memcpy_toio
#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) || defined(__powerpc__) || defined(__avr32__) || defined(__bfin__)
@@ -943,6 +945,8 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {
#define fb_writel __raw_writel
#define fb_writeq __raw_writeq
#define fb_memset memset_io
+#define fb_memcpy_fromfb memcpy_fromio
+#define fb_memcpy_tofb memcpy_toio
#else
@@ -955,6 +959,8 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {
#define fb_writel(b,addr) (*(volatile u32 *) (addr) = (b))
#define fb_writeq(b,addr) (*(volatile u64 *) (addr) = (b))
#define fb_memset memset
+#define fb_memcpy_fromfb memcpy
+#define fb_memcpy_tofb memcpy
#endif
diff --git a/include/linux/fdreg.h b/include/linux/fdreg.h
index c2eeb63b72db..61ce64169004 100644
--- a/include/linux/fdreg.h
+++ b/include/linux/fdreg.h
@@ -89,7 +89,7 @@
/* the following commands are new in the 82078. They are not used in the
* floppy driver, except the first three. These commands may be useful for apps
* which use the FDRAWCMD interface. For doc, get the 82078 spec sheets at
- * http://www-techdoc.intel.com/docs/periph/fd_contr/datasheets/ */
+ * http://www.intel.com/design/archives/periphrl/docs/29046803.htm */
#define FD_PARTID 0x18 /* part id ("extended" version cmd) */
#define FD_SAVE 0x2e /* save fdc regs for later restore */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 4f34ff6e5558..1c73b50e81ff 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -9,6 +9,7 @@
#include <linux/limits.h>
#include <linux/ioctl.h>
#include <linux/blk_types.h>
+#include <linux/types.h>
/*
* It's silly to have NR_OPEN bigger than NR_FILE, but you can change
@@ -32,11 +33,17 @@
#define SEEK_END 2 /* seek relative to end of file */
#define SEEK_MAX SEEK_END
+struct fstrim_range {
+ uint64_t start;
+ uint64_t len;
+ uint64_t minlen;
+};
+
/* And dynamically-tunable limits and defaults: */
struct files_stat_struct {
- int nr_files; /* read only */
- int nr_free_files; /* read only */
- int max_files; /* tunable */
+ unsigned long nr_files; /* read only */
+ unsigned long nr_free_files; /* read only */
+ unsigned long max_files; /* tunable */
};
struct inodes_stat_t {
@@ -92,6 +99,9 @@ struct inodes_stat_t {
/* Expect random access pattern */
#define FMODE_RANDOM ((__force fmode_t)0x1000)
+/* File is huge (eg. /dev/kmem): treat loff_t as unsigned */
+#define FMODE_UNSIGNED_OFFSET ((__force fmode_t)0x2000)
+
/* File was opened by fanotify and shouldn't generate fanotify events */
#define FMODE_NONOTIFY ((__force fmode_t)0x1000000)
@@ -231,6 +241,7 @@ struct inodes_stat_t {
#define S_NOCMTIME 128 /* Do not update file c/mtime */
#define S_SWAPFILE 256 /* Do not truncate: swapon got its bmaps */
#define S_PRIVATE 512 /* Inode is fs-internal */
+#define S_IMA 1024 /* Inode has an associated IMA struct */
/*
* Note that nosuid etc flags are inode-specific: setting some file-system
@@ -265,6 +276,7 @@ struct inodes_stat_t {
#define IS_NOCMTIME(inode) ((inode)->i_flags & S_NOCMTIME)
#define IS_SWAPFILE(inode) ((inode)->i_flags & S_SWAPFILE)
#define IS_PRIVATE(inode) ((inode)->i_flags & S_PRIVATE)
+#define IS_IMA(inode) ((inode)->i_flags & S_IMA)
/* the read-only stuff doesn't really belong here, but any other place is
probably as bad and I don't want to create yet another include file. */
@@ -312,6 +324,7 @@ struct inodes_stat_t {
#define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */
#define FIFREEZE _IOWR('X', 119, int) /* Freeze */
#define FITHAW _IOWR('X', 120, int) /* Thaw */
+#define FITRIM _IOWR('X', 121, struct fstrim_range) /* Trim */
#define FS_IOC_GETFLAGS _IOR('f', 1, long)
#define FS_IOC_SETFLAGS _IOW('f', 2, long)
@@ -400,7 +413,7 @@ extern void __init inode_init_early(void);
extern void __init files_init(unsigned long);
extern struct files_stat_struct files_stat;
-extern int get_max_files(void);
+extern unsigned long get_max_files(void);
extern int sysctl_nr_open;
extern struct inodes_stat_t inodes_stat;
extern int leases_enable, lease_break_time;
@@ -720,7 +733,8 @@ struct posix_acl;
struct inode {
struct hlist_node i_hash;
- struct list_head i_list; /* backing dev IO list */
+ struct list_head i_wb_list; /* backing dev IO list */
+ struct list_head i_lru; /* inode LRU list */
struct list_head i_sb_list;
struct list_head i_dentry;
unsigned long i_ino;
@@ -772,6 +786,10 @@ struct inode {
unsigned int i_flags;
+#ifdef CONFIG_IMA
+ /* protected by i_lock */
+ unsigned int i_readcount; /* struct files open RO */
+#endif
atomic_t i_writecount;
#ifdef CONFIG_SECURITY
void *i_security;
@@ -783,6 +801,11 @@ struct inode {
void *i_private; /* fs or device private pointer */
};
+static inline int inode_unhashed(struct inode *inode)
+{
+ return hlist_unhashed(&inode->i_hash);
+}
+
/*
* inode->i_mutex nesting subclasses for the lock validator:
*
@@ -1107,6 +1130,7 @@ extern int fcntl_getlease(struct file *filp);
/* fs/locks.c */
extern void locks_init_lock(struct file_lock *);
+extern struct file_lock * locks_alloc_lock(void);
extern void locks_copy_lock(struct file_lock *, struct file_lock *);
extern void __locks_copy_lock(struct file_lock *, const struct file_lock *);
extern void locks_remove_posix(struct file *, fl_owner_t);
@@ -1295,6 +1319,11 @@ struct fasync_struct {
/* SMP safe fasync helpers: */
extern int fasync_helper(int, struct file *, int, struct fasync_struct **);
+extern struct fasync_struct *fasync_insert_entry(int, struct file *, struct fasync_struct **, struct fasync_struct *);
+extern int fasync_remove_entry(struct file *, struct fasync_struct **);
+extern struct fasync_struct *fasync_alloc(void);
+extern void fasync_free(struct fasync_struct *);
+
/* can be called from interrupts */
extern void kill_fasync(struct fasync_struct **, int, int);
@@ -1583,6 +1612,7 @@ struct super_operations {
ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
#endif
int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
+ int (*trim_fs) (struct super_block *, struct fstrim_range *);
};
/*
@@ -1633,16 +1663,17 @@ struct super_operations {
*
* Q: What is the difference between I_WILL_FREE and I_FREEING?
*/
-#define I_DIRTY_SYNC 1
-#define I_DIRTY_DATASYNC 2
-#define I_DIRTY_PAGES 4
+#define I_DIRTY_SYNC (1 << 0)
+#define I_DIRTY_DATASYNC (1 << 1)
+#define I_DIRTY_PAGES (1 << 2)
#define __I_NEW 3
#define I_NEW (1 << __I_NEW)
-#define I_WILL_FREE 16
-#define I_FREEING 32
-#define I_CLEAR 64
+#define I_WILL_FREE (1 << 4)
+#define I_FREEING (1 << 5)
+#define I_CLEAR (1 << 6)
#define __I_SYNC 7
#define I_SYNC (1 << __I_SYNC)
+#define I_REFERENCED (1 << 8)
#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
@@ -1734,6 +1765,7 @@ static inline void file_accessed(struct file *file)
}
int sync_inode(struct inode *inode, struct writeback_control *wbc);
+int sync_inode_metadata(struct inode *inode, int wait);
struct file_system_type {
const char *name;
@@ -2078,7 +2110,6 @@ extern int check_disk_change(struct block_device *);
extern int __invalidate_device(struct block_device *);
extern int invalidate_partition(struct gendisk *, int);
#endif
-extern int invalidate_inodes(struct super_block *);
unsigned long invalidate_mapping_pages(struct address_space *mapping,
pgoff_t start, pgoff_t end);
@@ -2162,7 +2193,7 @@ extern loff_t vfs_llseek(struct file *file, loff_t offset, int origin);
extern int inode_init_always(struct super_block *, struct inode *);
extern void inode_init_once(struct inode *);
-extern void inode_add_to_lists(struct super_block *, struct inode *);
+extern void ihold(struct inode * inode);
extern void iput(struct inode *);
extern struct inode * igrab(struct inode *);
extern ino_t iunique(struct super_block *, ino_t);
@@ -2182,11 +2213,11 @@ 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 *);
extern void unlock_new_inode(struct inode *);
+extern unsigned int get_next_ino(void);
extern void __iget(struct inode * inode);
extern void iget_failed(struct inode *);
extern void end_writeback(struct inode *);
-extern void destroy_inode(struct inode *);
extern void __destroy_inode(struct inode *);
extern struct inode *new_inode(struct super_block *);
extern int should_remove_suid(struct dentry *);
@@ -2194,9 +2225,11 @@ extern int file_remove_suid(struct file *);
extern void __insert_inode_hash(struct inode *, unsigned long hashval);
extern void remove_inode_hash(struct inode *);
-static inline void insert_inode_hash(struct inode *inode) {
+static inline void insert_inode_hash(struct inode *inode)
+{
__insert_inode_hash(inode, inode->i_ino);
}
+extern void inode_sb_list_add(struct inode *inode);
#ifdef CONFIG_BLOCK
extern void submit_bio(int, struct bio *);
@@ -2479,7 +2512,10 @@ ssize_t simple_attr_write(struct file *file, const char __user *buf,
struct ctl_table;
int proc_nr_files(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos);
-
+int proc_nr_dentry(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+int proc_nr_inodes(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
int __init get_filesystem_list(char *buf);
#define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE])
diff --git a/include/linux/gameport.h b/include/linux/gameport.h
index 361d1cc288d0..b65a6f472775 100644
--- a/include/linux/gameport.h
+++ b/include/linux/gameport.h
@@ -53,9 +53,7 @@ struct gameport {
#define to_gameport_port(d) container_of(d, struct gameport, dev)
struct gameport_driver {
-
- void *private;
- char *description;
+ const char *description;
int (*connect)(struct gameport *, struct gameport_driver *drv);
int (*reconnect)(struct gameport *);
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 557c3927e70f..7a7b9c1644e4 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -140,7 +140,6 @@ struct disk_part_tbl {
struct rcu_head rcu_head;
int len;
struct hd_struct __rcu *last_lookup;
- struct gendisk *disk;
struct hd_struct __rcu *part[];
};
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 975609cb8548..e8713d55360a 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -9,6 +9,32 @@
struct vm_area_struct;
+/* Plain integer GFP bitmasks. Do not use this directly. */
+#define ___GFP_DMA 0x01u
+#define ___GFP_HIGHMEM 0x02u
+#define ___GFP_DMA32 0x04u
+#define ___GFP_MOVABLE 0x08u
+#define ___GFP_WAIT 0x10u
+#define ___GFP_HIGH 0x20u
+#define ___GFP_IO 0x40u
+#define ___GFP_FS 0x80u
+#define ___GFP_COLD 0x100u
+#define ___GFP_NOWARN 0x200u
+#define ___GFP_REPEAT 0x400u
+#define ___GFP_NOFAIL 0x800u
+#define ___GFP_NORETRY 0x1000u
+#define ___GFP_COMP 0x4000u
+#define ___GFP_ZERO 0x8000u
+#define ___GFP_NOMEMALLOC 0x10000u
+#define ___GFP_HARDWALL 0x20000u
+#define ___GFP_THISNODE 0x40000u
+#define ___GFP_RECLAIMABLE 0x80000u
+#ifdef CONFIG_KMEMCHECK
+#define ___GFP_NOTRACK 0x200000u
+#else
+#define ___GFP_NOTRACK 0
+#endif
+
/*
* GFP bitmasks..
*
@@ -18,10 +44,10 @@ struct vm_area_struct;
* without the underscores and use them consistently. The definitions here may
* be used in bit comparisons.
*/
-#define __GFP_DMA ((__force gfp_t)0x01u)
-#define __GFP_HIGHMEM ((__force gfp_t)0x02u)
-#define __GFP_DMA32 ((__force gfp_t)0x04u)
-#define __GFP_MOVABLE ((__force gfp_t)0x08u) /* Page is movable */
+#define __GFP_DMA ((__force gfp_t)___GFP_DMA)
+#define __GFP_HIGHMEM ((__force gfp_t)___GFP_HIGHMEM)
+#define __GFP_DMA32 ((__force gfp_t)___GFP_DMA32)
+#define __GFP_MOVABLE ((__force gfp_t)___GFP_MOVABLE) /* Page is movable */
#define GFP_ZONEMASK (__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE)
/*
* Action modifiers - doesn't change the zoning
@@ -38,27 +64,22 @@ struct vm_area_struct;
* __GFP_MOVABLE: Flag that this page will be movable by the page migration
* mechanism or reclaimed
*/
-#define __GFP_WAIT ((__force gfp_t)0x10u) /* Can wait and reschedule? */
-#define __GFP_HIGH ((__force gfp_t)0x20u) /* Should access emergency pools? */
-#define __GFP_IO ((__force gfp_t)0x40u) /* Can start physical IO? */
-#define __GFP_FS ((__force gfp_t)0x80u) /* Can call down to low-level FS? */
-#define __GFP_COLD ((__force gfp_t)0x100u) /* Cache-cold page required */
-#define __GFP_NOWARN ((__force gfp_t)0x200u) /* Suppress page allocation failure warning */
-#define __GFP_REPEAT ((__force gfp_t)0x400u) /* See above */
-#define __GFP_NOFAIL ((__force gfp_t)0x800u) /* See above */
-#define __GFP_NORETRY ((__force gfp_t)0x1000u)/* See above */
-#define __GFP_COMP ((__force gfp_t)0x4000u)/* Add compound page metadata */
-#define __GFP_ZERO ((__force gfp_t)0x8000u)/* Return zeroed page on success */
-#define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */
-#define __GFP_HARDWALL ((__force gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */
-#define __GFP_THISNODE ((__force gfp_t)0x40000u)/* No fallback, no policies */
-#define __GFP_RECLAIMABLE ((__force gfp_t)0x80000u) /* Page is reclaimable */
-
-#ifdef CONFIG_KMEMCHECK
-#define __GFP_NOTRACK ((__force gfp_t)0x200000u) /* Don't track with kmemcheck */
-#else
-#define __GFP_NOTRACK ((__force gfp_t)0)
-#endif
+#define __GFP_WAIT ((__force gfp_t)___GFP_WAIT) /* Can wait and reschedule? */
+#define __GFP_HIGH ((__force gfp_t)___GFP_HIGH) /* Should access emergency pools? */
+#define __GFP_IO ((__force gfp_t)___GFP_IO) /* Can start physical IO? */
+#define __GFP_FS ((__force gfp_t)___GFP_FS) /* Can call down to low-level FS? */
+#define __GFP_COLD ((__force gfp_t)___GFP_COLD) /* Cache-cold page required */
+#define __GFP_NOWARN ((__force gfp_t)___GFP_NOWARN) /* Suppress page allocation failure warning */
+#define __GFP_REPEAT ((__force gfp_t)___GFP_REPEAT) /* See above */
+#define __GFP_NOFAIL ((__force gfp_t)___GFP_NOFAIL) /* See above */
+#define __GFP_NORETRY ((__force gfp_t)___GFP_NORETRY) /* See above */
+#define __GFP_COMP ((__force gfp_t)___GFP_COMP) /* Add compound page metadata */
+#define __GFP_ZERO ((__force gfp_t)___GFP_ZERO) /* Return zeroed page on success */
+#define __GFP_NOMEMALLOC ((__force gfp_t)___GFP_NOMEMALLOC) /* Don't use emergency reserves */
+#define __GFP_HARDWALL ((__force gfp_t)___GFP_HARDWALL) /* Enforce hardwall cpuset memory allocs */
+#define __GFP_THISNODE ((__force gfp_t)___GFP_THISNODE)/* No fallback, no policies */
+#define __GFP_RECLAIMABLE ((__force gfp_t)___GFP_RECLAIMABLE) /* Page is reclaimable */
+#define __GFP_NOTRACK ((__force gfp_t)___GFP_NOTRACK) /* Don't track with kmemcheck */
/*
* This may seem redundant, but it's a way of annotating false positives vs.
@@ -186,14 +207,14 @@ static inline int allocflags_to_migratetype(gfp_t gfp_flags)
#endif
#define GFP_ZONE_TABLE ( \
- (ZONE_NORMAL << 0 * ZONES_SHIFT) \
- | (OPT_ZONE_DMA << __GFP_DMA * ZONES_SHIFT) \
- | (OPT_ZONE_HIGHMEM << __GFP_HIGHMEM * ZONES_SHIFT) \
- | (OPT_ZONE_DMA32 << __GFP_DMA32 * ZONES_SHIFT) \
- | (ZONE_NORMAL << __GFP_MOVABLE * ZONES_SHIFT) \
- | (OPT_ZONE_DMA << (__GFP_MOVABLE | __GFP_DMA) * ZONES_SHIFT) \
- | (ZONE_MOVABLE << (__GFP_MOVABLE | __GFP_HIGHMEM) * ZONES_SHIFT)\
- | (OPT_ZONE_DMA32 << (__GFP_MOVABLE | __GFP_DMA32) * ZONES_SHIFT)\
+ (ZONE_NORMAL << 0 * ZONES_SHIFT) \
+ | (OPT_ZONE_DMA << ___GFP_DMA * ZONES_SHIFT) \
+ | (OPT_ZONE_HIGHMEM << ___GFP_HIGHMEM * ZONES_SHIFT) \
+ | (OPT_ZONE_DMA32 << ___GFP_DMA32 * ZONES_SHIFT) \
+ | (ZONE_NORMAL << ___GFP_MOVABLE * ZONES_SHIFT) \
+ | (OPT_ZONE_DMA << (___GFP_MOVABLE | ___GFP_DMA) * ZONES_SHIFT) \
+ | (ZONE_MOVABLE << (___GFP_MOVABLE | ___GFP_HIGHMEM) * ZONES_SHIFT) \
+ | (OPT_ZONE_DMA32 << (___GFP_MOVABLE | ___GFP_DMA32) * ZONES_SHIFT) \
)
/*
@@ -203,20 +224,20 @@ static inline int allocflags_to_migratetype(gfp_t gfp_flags)
* allowed.
*/
#define GFP_ZONE_BAD ( \
- 1 << (__GFP_DMA | __GFP_HIGHMEM) \
- | 1 << (__GFP_DMA | __GFP_DMA32) \
- | 1 << (__GFP_DMA32 | __GFP_HIGHMEM) \
- | 1 << (__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM) \
- | 1 << (__GFP_MOVABLE | __GFP_HIGHMEM | __GFP_DMA) \
- | 1 << (__GFP_MOVABLE | __GFP_DMA32 | __GFP_DMA) \
- | 1 << (__GFP_MOVABLE | __GFP_DMA32 | __GFP_HIGHMEM) \
- | 1 << (__GFP_MOVABLE | __GFP_DMA32 | __GFP_DMA | __GFP_HIGHMEM)\
+ 1 << (___GFP_DMA | ___GFP_HIGHMEM) \
+ | 1 << (___GFP_DMA | ___GFP_DMA32) \
+ | 1 << (___GFP_DMA32 | ___GFP_HIGHMEM) \
+ | 1 << (___GFP_DMA | ___GFP_DMA32 | ___GFP_HIGHMEM) \
+ | 1 << (___GFP_MOVABLE | ___GFP_HIGHMEM | ___GFP_DMA) \
+ | 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_DMA) \
+ | 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_HIGHMEM) \
+ | 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_DMA | ___GFP_HIGHMEM) \
)
static inline enum zone_type gfp_zone(gfp_t flags)
{
enum zone_type z;
- int bit = flags & GFP_ZONEMASK;
+ int bit = (__force int) (flags & GFP_ZONEMASK);
z = (GFP_ZONE_TABLE >> (bit * ZONES_SHIFT)) &
((1 << ZONES_SHIFT) - 1);
diff --git a/include/linux/gpio-fan.h b/include/linux/gpio-fan.h
new file mode 100644
index 000000000000..096659169215
--- /dev/null
+++ b/include/linux/gpio-fan.h
@@ -0,0 +1,36 @@
+/*
+ * include/linux/gpio-fan.h
+ *
+ * Platform data structure for GPIO fan driver
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_GPIO_FAN_H
+#define __LINUX_GPIO_FAN_H
+
+struct gpio_fan_alarm {
+ unsigned gpio;
+ unsigned active_low;
+};
+
+struct gpio_fan_speed {
+ int rpm;
+ int ctrl_val;
+};
+
+struct gpio_fan_platform_data {
+ int num_ctrl;
+ unsigned *ctrl; /* fan control GPIOs. */
+ struct gpio_fan_alarm *alarm; /* fan alarm GPIO. */
+ /*
+ * Speed conversion array: rpm from/to GPIO bit field.
+ * This array _must_ be sorted in ascending rpm order.
+ */
+ int num_speed;
+ struct gpio_fan_speed *speed;
+};
+
+#endif /* __LINUX_GPIO_FAN_H */
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 42a0f1d11365..bb0f56f5c01e 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -316,6 +316,7 @@ struct hid_item {
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
#define HID_QUIRK_NO_INIT_REPORTS 0x20000000
#define HID_QUIRK_NO_IGNORE 0x40000000
+#define HID_QUIRK_NO_INPUT_SYNC 0x80000000
/*
* This is the global environment of the parser. This information is
@@ -626,8 +627,8 @@ struct hid_driver {
int (*event)(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value);
- void (*report_fixup)(struct hid_device *hdev, __u8 *buf,
- unsigned int size);
+ __u8 *(*report_fixup)(struct hid_device *hdev, __u8 *buf,
+ unsigned int *size);
int (*input_mapping)(struct hid_device *hdev,
struct hid_input *hidinput, struct hid_field *field,
diff --git a/include/linux/hiddev.h b/include/linux/hiddev.h
index bb6f58baf319..a3f481a3063b 100644
--- a/include/linux/hiddev.h
+++ b/include/linux/hiddev.h
@@ -226,8 +226,6 @@ void hiddev_disconnect(struct hid_device *);
void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value);
void hiddev_report_event(struct hid_device *hid, struct hid_report *report);
-int __init hiddev_init(void);
-void hiddev_exit(void);
#else
static inline int hiddev_connect(struct hid_device *hid,
unsigned int force)
@@ -236,8 +234,6 @@ static inline void hiddev_disconnect(struct hid_device *hid) { }
static inline void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value) { }
static inline void hiddev_report_event(struct hid_device *hid, struct hid_report *report) { }
-static inline int hiddev_init(void) { return 0; }
-static inline void hiddev_exit(void) { }
#endif
#endif
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index e3060ef85b6d..e9138198e823 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -28,18 +28,6 @@ static inline void invalidate_kernel_vmap_range(void *vaddr, int size)
#include <asm/kmap_types.h>
-#ifdef CONFIG_DEBUG_HIGHMEM
-
-void debug_kmap_atomic(enum km_type type);
-
-#else
-
-static inline void debug_kmap_atomic(enum km_type type)
-{
-}
-
-#endif
-
#ifdef CONFIG_HIGHMEM
#include <asm/highmem.h>
@@ -66,19 +54,19 @@ static inline void kunmap(struct page *page)
{
}
-static inline void *kmap_atomic(struct page *page, enum km_type idx)
+static inline void *__kmap_atomic(struct page *page)
{
pagefault_disable();
return page_address(page);
}
-#define kmap_atomic_prot(page, idx, prot) kmap_atomic(page, idx)
+#define kmap_atomic_prot(page, prot) __kmap_atomic(page)
-static inline void kunmap_atomic_notypecheck(void *addr, enum km_type idx)
+static inline void __kunmap_atomic(void *addr)
{
pagefault_enable();
}
-#define kmap_atomic_pfn(pfn, idx) kmap_atomic(pfn_to_page(pfn), (idx))
+#define kmap_atomic_pfn(pfn) kmap_atomic(pfn_to_page(pfn))
#define kmap_atomic_to_page(ptr) virt_to_page(ptr)
#define kmap_flush_unused() do {} while(0)
@@ -86,12 +74,50 @@ static inline void kunmap_atomic_notypecheck(void *addr, enum km_type idx)
#endif /* CONFIG_HIGHMEM */
-/* Prevent people trying to call kunmap_atomic() as if it were kunmap() */
-/* kunmap_atomic() should get the return value of kmap_atomic, not the page. */
-#define kunmap_atomic(addr, idx) do { \
- BUILD_BUG_ON(__same_type((addr), struct page *)); \
- kunmap_atomic_notypecheck((addr), (idx)); \
- } while (0)
+#if defined(CONFIG_HIGHMEM) || defined(CONFIG_X86_32)
+
+DECLARE_PER_CPU(int, __kmap_atomic_idx);
+
+static inline int kmap_atomic_idx_push(void)
+{
+ int idx = __get_cpu_var(__kmap_atomic_idx)++;
+#ifdef CONFIG_DEBUG_HIGHMEM
+ WARN_ON_ONCE(in_irq() && !irqs_disabled());
+ BUG_ON(idx > KM_TYPE_NR);
+#endif
+ return idx;
+}
+
+static inline int kmap_atomic_idx(void)
+{
+ return __get_cpu_var(__kmap_atomic_idx) - 1;
+}
+
+static inline int kmap_atomic_idx_pop(void)
+{
+ int idx = --__get_cpu_var(__kmap_atomic_idx);
+#ifdef CONFIG_DEBUG_HIGHMEM
+ BUG_ON(idx < 0);
+#endif
+ return idx;
+}
+
+#endif
+
+/*
+ * Make both: kmap_atomic(page, idx) and kmap_atomic(page) work.
+ */
+#define kmap_atomic(page, args...) __kmap_atomic(page)
+
+/*
+ * Prevent people trying to call kunmap_atomic() as if it were kunmap()
+ * kunmap_atomic() should get the return value of kmap_atomic, not the page.
+ */
+#define kunmap_atomic(addr, args...) \
+do { \
+ BUILD_BUG_ON(__same_type((addr), struct page *)); \
+ __kunmap_atomic(addr); \
+} while (0)
/* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */
#ifndef clear_user_highpage
@@ -201,8 +227,8 @@ static inline void copy_user_highpage(struct page *to, struct page *from,
vfrom = kmap_atomic(from, KM_USER0);
vto = kmap_atomic(to, KM_USER1);
copy_user_page(vto, vfrom, vaddr, to);
- kunmap_atomic(vfrom, KM_USER0);
kunmap_atomic(vto, KM_USER1);
+ kunmap_atomic(vfrom, KM_USER0);
}
#endif
@@ -214,8 +240,8 @@ static inline void copy_highpage(struct page *to, struct page *from)
vfrom = kmap_atomic(from, KM_USER0);
vto = kmap_atomic(to, KM_USER1);
copy_page(vto, vfrom);
- kunmap_atomic(vfrom, KM_USER0);
kunmap_atomic(vto, KM_USER1);
+ kunmap_atomic(vfrom, KM_USER0);
}
#endif /* _LINUX_HIGHMEM_H */
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index f479700df61b..943c76b3d4bb 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -43,7 +43,8 @@ int hugetlb_reserve_pages(struct inode *inode, long from, long to,
struct vm_area_struct *vma,
int acctflags);
void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed);
-void __isolate_hwpoisoned_huge_page(struct page *page);
+int dequeue_hwpoisoned_huge_page(struct page *page);
+void copy_huge_page(struct page *dst, struct page *src);
extern unsigned long hugepages_treat_as_movable;
extern const unsigned long hugetlb_zero, hugetlb_infinity;
@@ -101,7 +102,10 @@ static inline void hugetlb_report_meminfo(struct seq_file *m)
#define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) ({BUG(); 0; })
#define hugetlb_fault(mm, vma, addr, flags) ({ BUG(); 0; })
#define huge_pte_offset(mm, address) 0
-#define __isolate_hwpoisoned_huge_page(page) 0
+#define dequeue_hwpoisoned_huge_page(page) 0
+static inline void copy_huge_page(struct page *dst, struct page *src)
+{
+}
#define hugetlb_change_protection(vma, address, end, newprot)
@@ -228,6 +232,8 @@ struct huge_bootmem_page {
struct hstate *hstate;
};
+struct page *alloc_huge_page_node(struct hstate *h, int nid);
+
/* arch callback */
int __init alloc_bootmem_huge_page(struct hstate *h);
@@ -301,8 +307,14 @@ static inline struct hstate *page_hstate(struct page *page)
return size_to_hstate(PAGE_SIZE << compound_order(page));
}
+static inline unsigned hstate_index_to_shift(unsigned index)
+{
+ return hstates[index].order + PAGE_SHIFT;
+}
+
#else
struct hstate {};
+#define alloc_huge_page_node(h, nid) NULL
#define alloc_bootmem_huge_page(h) NULL
#define hstate_file(f) NULL
#define hstate_vma(v) NULL
@@ -317,6 +329,7 @@ static inline unsigned int pages_per_huge_page(struct hstate *h)
{
return 1;
}
+#define hstate_index_to_shift(index) 0
#endif
#endif /* _LINUX_HUGETLB_H */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 4bae0b72ed3c..1f66fa06a97c 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -384,11 +384,15 @@ static inline void i2c_set_adapdata(struct i2c_adapter *dev, void *data)
dev_set_drvdata(&dev->dev, data);
}
-static inline int i2c_parent_is_i2c_adapter(const struct i2c_adapter *adapter)
+static inline struct i2c_adapter *
+i2c_parent_is_i2c_adapter(const struct i2c_adapter *adapter)
{
- return adapter->dev.parent != NULL
- && adapter->dev.parent->bus == &i2c_bus_type
- && adapter->dev.parent->type == &i2c_adapter_type;
+ struct device *parent = adapter->dev.parent;
+
+ if (parent != NULL && parent->type == &i2c_adapter_type)
+ return to_i2c_adapter(parent);
+ else
+ return NULL;
}
/* Adapter locking functions, exported for shared pin cases */
diff --git a/include/linux/i2c/adp5588.h b/include/linux/i2c/adp5588.h
index 269181b8f623..3c5d6b6e765c 100644
--- a/include/linux/i2c/adp5588.h
+++ b/include/linux/i2c/adp5588.h
@@ -74,6 +74,20 @@
#define ADP5588_DEVICE_ID_MASK 0xF
+ /* Configuration Register1 */
+#define ADP5588_AUTO_INC (1 << 7)
+#define ADP5588_GPIEM_CFG (1 << 6)
+#define ADP5588_INT_CFG (1 << 4)
+#define ADP5588_GPI_IEN (1 << 1)
+
+/* Interrupt Status Register */
+#define ADP5588_GPI_INT (1 << 1)
+#define ADP5588_KE_INT (1 << 0)
+
+#define ADP5588_MAXGPIO 18
+#define ADP5588_BANK(offs) ((offs) >> 3)
+#define ADP5588_BIT(offs) (1u << ((offs) & 0x7))
+
/* Put one of these structures in i2c_board_info platform_data */
#define ADP5588_KEYMAPSIZE 80
@@ -126,9 +140,12 @@ struct adp5588_kpad_platform_data {
const struct adp5588_gpio_platform_data *gpio_data;
};
+struct i2c_client; /* forward declaration */
+
struct adp5588_gpio_platform_data {
- unsigned gpio_start; /* GPIO Chip base # */
- unsigned pullup_dis_mask; /* Pull-Up Disable Mask */
+ int gpio_start; /* GPIO Chip base # */
+ unsigned irq_base; /* interrupt base # */
+ unsigned pullup_dis_mask; /* Pull-Up Disable Mask */
int (*setup)(struct i2c_client *client,
int gpio, unsigned ngpio,
void *context);
diff --git a/include/linux/i2c/apds990x.h b/include/linux/i2c/apds990x.h
new file mode 100644
index 000000000000..d186fcc5d257
--- /dev/null
+++ b/include/linux/i2c/apds990x.h
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the APDS990x sensor driver.
+ * Chip is combined proximity and ambient light sensor.
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __APDS990X_H__
+#define __APDS990X_H__
+
+
+#define APDS_IRLED_CURR_12mA 0x3
+#define APDS_IRLED_CURR_25mA 0x2
+#define APDS_IRLED_CURR_50mA 0x1
+#define APDS_IRLED_CURR_100mA 0x0
+
+/**
+ * struct apds990x_chip_factors - defines effect of the cover window
+ * @ga: Total glass attenuation
+ * @cf1: clear channel factor 1 for raw to lux conversion
+ * @irf1: IR channel factor 1 for raw to lux conversion
+ * @cf2: clear channel factor 2 for raw to lux conversion
+ * @irf2: IR channel factor 2 for raw to lux conversion
+ * @df: device factor for conversion formulas
+ *
+ * Structure for tuning ALS calculation to match with environment.
+ * Values depend on the material above the sensor and the sensor
+ * itself. If the GA is zero, driver will use uncovered sensor default values
+ * format: decimal value * APDS_PARAM_SCALE except df which is plain integer.
+ */
+#define APDS_PARAM_SCALE 4096
+struct apds990x_chip_factors {
+ int ga;
+ int cf1;
+ int irf1;
+ int cf2;
+ int irf2;
+ int df;
+};
+
+/**
+ * struct apds990x_platform_data - platform data for apsd990x.c driver
+ * @cf: chip factor data
+ * @pddrive: IR-led driving current
+ * @ppcount: number of IR pulses used for proximity estimation
+ * @setup_resources: interrupt line setup call back function
+ * @release_resources: interrupt line release call back function
+ *
+ * Proximity detection result depends heavily on correct ppcount, pdrive
+ * and cover window.
+ *
+ */
+
+struct apds990x_platform_data {
+ struct apds990x_chip_factors cf;
+ u8 pdrive;
+ u8 ppcount;
+ int (*setup_resources)(void);
+ int (*release_resources)(void);
+};
+
+#endif
diff --git a/include/linux/i2c/bh1770glc.h b/include/linux/i2c/bh1770glc.h
new file mode 100644
index 000000000000..8b5e2df36c72
--- /dev/null
+++ b/include/linux/i2c/bh1770glc.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the ROHM BH1770GLC / OSRAM SFH7770 sensor driver.
+ * Chip is combined proximity and ambient light sensor.
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __BH1770_H__
+#define __BH1770_H__
+
+/**
+ * struct bh1770_platform_data - platform data for bh1770glc driver
+ * @led_def_curr: IR led driving current.
+ * @glass_attenuation: Attenuation factor for covering window.
+ * @setup_resources: Call back for interrupt line setup function
+ * @release_resources: Call back for interrupte line release function
+ *
+ * Example of glass attenuation: 16384 * 385 / 100 means attenuation factor
+ * of 3.85. i.e. light_above_sensor = light_above_cover_window / 3.85
+ */
+
+struct bh1770_platform_data {
+#define BH1770_LED_5mA 0
+#define BH1770_LED_10mA 1
+#define BH1770_LED_20mA 2
+#define BH1770_LED_50mA 3
+#define BH1770_LED_100mA 4
+#define BH1770_LED_150mA 5
+#define BH1770_LED_200mA 6
+ __u8 led_def_curr;
+#define BH1770_NEUTRAL_GA 16384 /* 16384 / 16384 = 1 */
+ __u32 glass_attenuation;
+ int (*setup_resources)(void);
+ int (*release_resources)(void);
+};
+#endif
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index 6de90bfc6acd..4793d8a7f480 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -553,8 +553,12 @@ extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
extern int twl4030_remove_script(u8 flags);
struct twl4030_codec_audio_data {
- unsigned int audio_mclk;
+ unsigned int audio_mclk; /* not used, will be removed */
+ unsigned int digimic_delay; /* in ms */
unsigned int ramp_delay_value;
+ unsigned int offset_cncl_path;
+ unsigned int check_defaults:1;
+ unsigned int reset_registers:1;
unsigned int hs_extmute:1;
void (*set_hs_extmute)(int mute);
};
diff --git a/include/linux/idr.h b/include/linux/idr.h
index cdb715e58e3e..13a801f3d028 100644
--- a/include/linux/idr.h
+++ b/include/linux/idr.h
@@ -81,6 +81,7 @@ struct idr {
#define _idr_rc_to_errno(rc) ((rc) == -1 ? -EAGAIN : -ENOSPC)
/**
+ * DOC: idr sync
* idr synchronization (stolen from radix-tree.h)
*
* idr_find() is able to be called locklessly, using RCU. The caller must
@@ -117,10 +118,13 @@ void idr_init(struct idr *idp);
/*
* IDA - IDR based id allocator, use when translation from id to
* pointer isn't necessary.
+ *
+ * IDA_BITMAP_LONGS is calculated to be one less to accommodate
+ * ida_bitmap->nr_busy so that the whole struct fits in 128 bytes.
*/
#define IDA_CHUNK_SIZE 128 /* 128 bytes per chunk */
-#define IDA_BITMAP_LONGS (128 / sizeof(long) - 1)
-#define IDA_BITMAP_BITS (IDA_BITMAP_LONGS * sizeof(long) * 8)
+#define IDA_BITMAP_LONGS (IDA_CHUNK_SIZE / sizeof(long) - 1)
+#define IDA_BITMAP_BITS (IDA_BITMAP_LONGS * sizeof(long) * 8)
struct ida_bitmap {
long nr_busy;
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 97b2eae6a22c..ed5a03cbe184 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -986,6 +986,7 @@ struct ieee80211_ht_info {
#define WLAN_AUTH_OPEN 0
#define WLAN_AUTH_SHARED_KEY 1
#define WLAN_AUTH_FT 2
+#define WLAN_AUTH_SAE 3
#define WLAN_AUTH_LEAP 128
#define WLAN_AUTH_CHALLENGE_LEN 128
@@ -1072,6 +1073,10 @@ enum ieee80211_statuscode {
WLAN_STATUS_NO_DIRECT_LINK = 48,
WLAN_STATUS_STA_NOT_PRESENT = 49,
WLAN_STATUS_STA_NOT_QSTA = 50,
+ /* 802.11s */
+ WLAN_STATUS_ANTI_CLOG_REQUIRED = 76,
+ WLAN_STATUS_FCG_NOT_SUPP = 78,
+ WLAN_STATUS_STA_NO_TBTT = 78,
};
@@ -1112,6 +1117,22 @@ enum ieee80211_reasoncode {
WLAN_REASON_QSTA_REQUIRE_SETUP = 38,
WLAN_REASON_QSTA_TIMEOUT = 39,
WLAN_REASON_QSTA_CIPHER_NOT_SUPP = 45,
+ /* 802.11s */
+ WLAN_REASON_MESH_PEER_CANCELED = 52,
+ WLAN_REASON_MESH_MAX_PEERS = 53,
+ WLAN_REASON_MESH_CONFIG = 54,
+ WLAN_REASON_MESH_CLOSE = 55,
+ WLAN_REASON_MESH_MAX_RETRIES = 56,
+ WLAN_REASON_MESH_CONFIRM_TIMEOUT = 57,
+ WLAN_REASON_MESH_INVALID_GTK = 58,
+ WLAN_REASON_MESH_INCONSISTENT_PARAM = 59,
+ WLAN_REASON_MESH_INVALID_SECURITY = 60,
+ WLAN_REASON_MESH_PATH_ERROR = 61,
+ WLAN_REASON_MESH_PATH_NOFORWARD = 62,
+ WLAN_REASON_MESH_PATH_DEST_UNREACHABLE = 63,
+ WLAN_REASON_MAC_EXISTS_IN_MBSS = 64,
+ WLAN_REASON_MESH_CHAN_REGULATORY = 65,
+ WLAN_REASON_MESH_CHAN = 66,
};
@@ -1139,20 +1160,33 @@ enum ieee80211_eid {
WLAN_EID_TS_DELAY = 43,
WLAN_EID_TCLAS_PROCESSING = 44,
WLAN_EID_QOS_CAPA = 46,
- /* 802.11s
- *
- * All mesh EID numbers are pending IEEE 802.11 ANA approval.
- * The numbers have been incremented from those suggested in
- * 802.11s/D2.0 so that MESH_CONFIG does not conflict with
- * EXT_SUPP_RATES.
+ /* 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_MESH_CONFIG = 51,
- WLAN_EID_MESH_ID = 52,
- WLAN_EID_PEER_LINK = 55,
- WLAN_EID_PREQ = 68,
- WLAN_EID_PREP = 69,
- WLAN_EID_PERR = 70,
- WLAN_EID_RANN = 49, /* compatible with FreeBSD */
+ 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,
+ WLAN_EID_BEACON_TIMING = 120,
+ WLAN_EID_MCCAOP_SETUP_REQ = 121,
+ WLAN_EID_MCCAOP_SETUP_RESP = 122,
+ WLAN_EID_MCCAOP_ADVERT = 123,
+ WLAN_EID_MCCAOP_TEARDOWN = 124,
+ WLAN_EID_GANN = 125,
+ WLAN_EID_RANN = 126,
+ WLAN_EID_PREQ = 130,
+ WLAN_EID_PREP = 131,
+ WLAN_EID_PERR = 132,
+ WLAN_EID_PXU = 137,
+ WLAN_EID_PXUC = 138,
+ WLAN_EID_AUTH_MESH_PEER_EXCH = 139,
+ WLAN_EID_MIC = 140,
WLAN_EID_PWR_CONSTRAINT = 32,
WLAN_EID_PWR_CAPABILITY = 33,
@@ -1211,9 +1245,14 @@ enum ieee80211_category {
WLAN_CATEGORY_HT = 7,
WLAN_CATEGORY_SA_QUERY = 8,
WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9,
+ WLAN_CATEGORY_MESH_ACTION = 13,
+ WLAN_CATEGORY_MULTIHOP_ACTION = 14,
+ WLAN_CATEGORY_SELF_PROTECTED = 15,
WLAN_CATEGORY_WMM = 17,
- WLAN_CATEGORY_MESH_PLINK = 30, /* Pending ANA approval */
- WLAN_CATEGORY_MESH_PATH_SEL = 32, /* Pending ANA approval */
+ /* TODO: remove MESH_PLINK and MESH_PATH_SEL after */
+ /* mesh is updated to current 802.11s draft */
+ WLAN_CATEGORY_MESH_PLINK = 30,
+ WLAN_CATEGORY_MESH_PATH_SEL = 32,
WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126,
WLAN_CATEGORY_VENDOR_SPECIFIC = 127,
};
@@ -1351,6 +1390,8 @@ enum ieee80211_sa_query_action {
/* AKM suite selectors */
#define WLAN_AKM_SUITE_8021X 0x000FAC01
#define WLAN_AKM_SUITE_PSK 0x000FAC02
+#define WLAN_AKM_SUITE_SAE 0x000FAC08
+#define WLAN_AKM_SUITE_FT_OVER_SAE 0x000FAC09
#define WLAN_MAX_KEY_LEN 32
diff --git a/include/linux/if.h b/include/linux/if.h
index 53558ec59e1b..123959927745 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -75,6 +75,8 @@
#define IFF_DISABLE_NETPOLL 0x2000 /* disable netpoll at run-time */
#define IFF_MACVLAN_PORT 0x4000 /* device used as macvlan port */
#define IFF_BRIDGE_PORT 0x8000 /* device used as bridge port */
+#define IFF_OVS_DATAPATH 0x10000 /* device used as Open vSwitch
+ * datapath port */
#define IF_GET_IFACE 0x0001 /* for querying only */
#define IF_GET_PROTO 0x0002
diff --git a/include/linux/if_bonding.h b/include/linux/if_bonding.h
index 2c7994372bde..a17edda8a781 100644
--- a/include/linux/if_bonding.h
+++ b/include/linux/if_bonding.h
@@ -84,6 +84,9 @@
#define BOND_DEFAULT_MAX_BONDS 1 /* Default maximum number of devices to support */
#define BOND_DEFAULT_TX_QUEUES 16 /* Default number of tx queues per device */
+
+#define BOND_DEFAULT_RESEND_IGMP 1 /* Default number of IGMP membership reports */
+
/* hashing types */
#define BOND_XMIT_POLICY_LAYER2 0 /* layer 2 (MAC only), default */
#define BOND_XMIT_POLICY_LAYER34 1 /* layer 3+4 (IP ^ (TCP || UDP)) */
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index bed7a4682b90..f9c3df03db0f 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -137,8 +137,6 @@ extern struct ctl_table ether_table[];
extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len);
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-
#endif
#endif /* _LINUX_IF_ETHER_H */
diff --git a/include/linux/if_infiniband.h b/include/linux/if_infiniband.h
index 3e659ec7dfdd..7d958475d4ac 100644
--- a/include/linux/if_infiniband.h
+++ b/include/linux/if_infiniband.h
@@ -5,7 +5,7 @@
* <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
* license, available in the LICENSE.TXT file accompanying this
* software. These details are also available at
- * <http://openib.org/license.html>.
+ * <http://www.openfabrics.org/software_license.htm>.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h
index 35280b302290..8a2fd66a8b5f 100644
--- a/include/linux/if_macvlan.h
+++ b/include/linux/if_macvlan.h
@@ -40,6 +40,12 @@ struct macvlan_rx_stats {
unsigned long rx_errors;
};
+/*
+ * Maximum times a macvtap device can be opened. This can be used to
+ * configure the number of receive queue, e.g. for multiqueue virtio.
+ */
+#define MAX_MACVTAP_QUEUES (NR_CPUS < 16 ? NR_CPUS : 16)
+
struct macvlan_dev {
struct net_device *dev;
struct list_head list;
@@ -50,7 +56,8 @@ struct macvlan_dev {
enum macvlan_mode mode;
int (*receive)(struct sk_buff *skb);
int (*forward)(struct net_device *dev, struct sk_buff *skb);
- struct macvtap_queue *tap;
+ struct macvtap_queue *taps[MAX_MACVTAP_QUEUES];
+ int numvtaps;
};
static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index 27741e05446f..397921b09ef9 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -40,25 +40,35 @@
* PPPoE addressing definition
*/
typedef __be16 sid_t;
-struct pppoe_addr{
- sid_t sid; /* Session identifier */
- unsigned char remote[ETH_ALEN]; /* Remote address */
- char dev[IFNAMSIZ]; /* Local device to use */
+struct pppoe_addr {
+ sid_t sid; /* Session identifier */
+ unsigned char remote[ETH_ALEN]; /* Remote address */
+ char dev[IFNAMSIZ]; /* Local device to use */
};
/************************************************************************
- * Protocols supported by AF_PPPOX
- */
+ * PPTP addressing definition
+ */
+struct pptp_addr {
+ __be16 call_id;
+ struct in_addr sin_addr;
+};
+
+/************************************************************************
+ * Protocols supported by AF_PPPOX
+ */
#define PX_PROTO_OE 0 /* Currently just PPPoE */
#define PX_PROTO_OL2TP 1 /* Now L2TP also */
-#define PX_MAX_PROTO 2
-
-struct sockaddr_pppox {
- sa_family_t sa_family; /* address family, AF_PPPOX */
- unsigned int sa_protocol; /* protocol identifier */
- union{
- struct pppoe_addr pppoe;
- }sa_addr;
+#define PX_PROTO_PPTP 2
+#define PX_MAX_PROTO 3
+
+struct sockaddr_pppox {
+ sa_family_t sa_family; /* address family, AF_PPPOX */
+ unsigned int sa_protocol; /* protocol identifier */
+ union {
+ struct pppoe_addr pppoe;
+ struct pptp_addr pptp;
+ } sa_addr;
} __attribute__((packed));
/* The use of the above union isn't viable because the size of this
@@ -150,15 +160,23 @@ struct pppoe_opt {
relayed to (PPPoE relaying) */
};
+struct pptp_opt {
+ struct pptp_addr src_addr;
+ struct pptp_addr dst_addr;
+ u32 ack_sent, ack_recv;
+ u32 seq_sent, seq_recv;
+ int ppp_flags;
+};
#include <net/sock.h>
struct pppox_sock {
/* struct sock must be the first member of pppox_sock */
- struct sock sk;
- struct ppp_channel chan;
+ struct sock sk;
+ struct ppp_channel chan;
struct pppox_sock *next; /* for hash table */
union {
struct pppoe_opt pppoe;
+ struct pptp_opt pptp;
} proto;
__be16 num;
};
@@ -186,7 +204,7 @@ struct pppox_proto {
struct module *owner;
};
-extern int register_pppox_proto(int proto_num, struct pppox_proto *pp);
+extern int register_pppox_proto(int proto_num, const struct pppox_proto *pp);
extern void unregister_pppox_proto(int proto_num);
extern void pppox_unbind_sock(struct sock *sk);/* delete ppp-channel binding */
extern int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 3d870fda8c4f..c2f3a72712ce 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -16,6 +16,7 @@
#ifdef __KERNEL__
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
#define VLAN_HLEN 4 /* The additional bytes (on top of the Ethernet header)
* that VLAN requires.
@@ -68,6 +69,7 @@ static inline struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *skb)
#define VLAN_CFI_MASK 0x1000 /* Canonical Format Indicator */
#define VLAN_TAG_PRESENT VLAN_CFI_MASK
#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */
+#define VLAN_N_VID 4096
/* found in socket.c */
extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *));
@@ -76,9 +78,8 @@ extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *));
* depends on completely exhausting the VLAN identifier space. Thus
* it gives constant time look-up, but in many cases it wastes memory.
*/
-#define VLAN_GROUP_ARRAY_LEN 4096
#define VLAN_GROUP_ARRAY_SPLIT_PARTS 8
-#define VLAN_GROUP_ARRAY_PART_LEN (VLAN_GROUP_ARRAY_LEN/VLAN_GROUP_ARRAY_SPLIT_PARTS)
+#define VLAN_GROUP_ARRAY_PART_LEN (VLAN_N_VID/VLAN_GROUP_ARRAY_SPLIT_PARTS)
struct vlan_group {
struct net_device *real_dev; /* The ethernet(like) device
@@ -114,12 +115,24 @@ static inline void vlan_group_set_device(struct vlan_group *vg,
#define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT)
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+/* Must be invoked with rcu_read_lock or with RTNL. */
+static inline struct net_device *vlan_find_dev(struct net_device *real_dev,
+ u16 vlan_id)
+{
+ struct vlan_group *grp = rcu_dereference_rtnl(real_dev->vlgrp);
+
+ if (grp)
+ return vlan_group_get_device(grp, vlan_id);
+
+ return NULL;
+}
+
extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
extern u16 vlan_dev_vlan_id(const struct net_device *dev);
extern int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
u16 vlan_tci, int polling);
-extern int vlan_hwaccel_do_receive(struct sk_buff *skb);
+extern bool vlan_hwaccel_do_receive(struct sk_buff **skb);
extern gro_result_t
vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
unsigned int vlan_tci, struct sk_buff *skb);
@@ -128,6 +141,12 @@ vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp,
unsigned int vlan_tci);
#else
+static inline struct net_device *vlan_find_dev(struct net_device *real_dev,
+ u16 vlan_id)
+{
+ return NULL;
+}
+
static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev)
{
BUG();
@@ -147,9 +166,11 @@ static inline int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
return NET_XMIT_SUCCESS;
}
-static inline int vlan_hwaccel_do_receive(struct sk_buff *skb)
+static inline bool vlan_hwaccel_do_receive(struct sk_buff **skb)
{
- return 0;
+ if ((*skb)->vlan_tci & VLAN_VID_MASK)
+ (*skb)->pkt_type = PACKET_OTHERHOST;
+ return false;
}
static inline gro_result_t
diff --git a/include/linux/in.h b/include/linux/in.h
index 41d88a4689af..beeb6dee2b49 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -250,6 +250,25 @@ struct sockaddr_in {
#ifdef __KERNEL__
+#include <linux/errno.h>
+
+static inline int proto_ports_offset(int proto)
+{
+ switch (proto) {
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ case IPPROTO_DCCP:
+ case IPPROTO_ESP: /* SPI */
+ case IPPROTO_SCTP:
+ case IPPROTO_UDPLITE:
+ return 0;
+ case IPPROTO_AH: /* SPI */
+ return 4;
+ default:
+ return -EINVAL;
+ }
+}
+
static inline bool ipv4_is_loopback(__be32 addr)
{
return (addr & htonl(0xff000000)) == htonl(0x7f000000);
diff --git a/include/linux/in6.h b/include/linux/in6.h
index c4bf46f764bf..097a34b55560 100644
--- a/include/linux/in6.h
+++ b/include/linux/in6.h
@@ -268,6 +268,10 @@ struct in6_flowlabel_req {
/* RFC5082: Generalized Ttl Security Mechanism */
#define IPV6_MINHOPCOUNT 73
+#define IPV6_ORIGDSTADDR 74
+#define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR
+#define IPV6_TRANSPARENT 75
+
/*
* Multicast Routing:
* see include/linux/mroute6.h.
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index 2be1a1a2beb9..ccd5b07d678d 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -9,6 +9,7 @@
#include <linux/rcupdate.h>
#include <linux/timer.h>
#include <linux/sysctl.h>
+#include <linux/rtnetlink.h>
enum
{
@@ -158,7 +159,12 @@ struct in_ifaddr {
extern int register_inetaddr_notifier(struct notifier_block *nb);
extern int unregister_inetaddr_notifier(struct notifier_block *nb);
-extern struct net_device *ip_dev_find(struct net *net, __be32 addr);
+extern struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref);
+static inline struct net_device *ip_dev_find(struct net *net, __be32 addr)
+{
+ return __ip_dev_find(net, addr, true);
+}
+
extern int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b);
extern int devinet_ioctl(struct net *net, unsigned int cmd, void __user *);
extern void devinet_init(void);
@@ -198,14 +204,10 @@ static __inline__ int bad_mask(__be32 mask, __be32 addr)
static inline struct in_device *__in_dev_get_rcu(const struct net_device *dev)
{
- struct in_device *in_dev = dev->ip_ptr;
- if (in_dev)
- in_dev = rcu_dereference(in_dev);
- return in_dev;
+ return rcu_dereference(dev->ip_ptr);
}
-static __inline__ struct in_device *
-in_dev_get(const struct net_device *dev)
+static inline struct in_device *in_dev_get(const struct net_device *dev)
{
struct in_device *in_dev;
@@ -217,10 +219,9 @@ in_dev_get(const struct net_device *dev)
return in_dev;
}
-static __inline__ struct in_device *
-__in_dev_get_rtnl(const struct net_device *dev)
+static inline struct in_device *__in_dev_get_rtnl(const struct net_device *dev)
{
- return (struct in_device*)dev->ip_ptr;
+ return rcu_dereference_check(dev->ip_ptr, lockdep_rtnl_is_held());
}
extern void in_dev_finish_destroy(struct in_device *idev);
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 2fea6c8ef6ba..1f8c06ce0fa6 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -29,6 +29,8 @@ extern struct fs_struct init_fs;
.running = 0, \
.lock = __SPIN_LOCK_UNLOCKED(sig.cputimer.lock), \
}, \
+ .cred_guard_mutex = \
+ __MUTEX_INITIALIZER(sig.cred_guard_mutex), \
}
extern struct nsproxy init_nsproxy;
@@ -145,8 +147,6 @@ extern struct cred init_cred;
.group_leader = &tsk, \
RCU_INIT_POINTER(.real_cred, &init_cred), \
RCU_INIT_POINTER(.cred, &init_cred), \
- .cred_guard_mutex = \
- __MUTEX_INITIALIZER(tsk.cred_guard_mutex), \
.comm = "swapper", \
.thread = INIT_THREAD, \
.fs = &init_fs, \
diff --git a/include/linux/input.h b/include/linux/input.h
index d6ae1761be97..51af441f3a21 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -34,7 +34,7 @@ struct input_event {
* Protocol version.
*/
-#define EV_VERSION 0x010000
+#define EV_VERSION 0x010001
/*
* IOCTLs (0x00 - 0x7f)
@@ -56,25 +56,50 @@ struct input_absinfo {
__s32 resolution;
};
+/**
+ * struct input_keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls
+ * @scancode: scancode represented in machine-endian form.
+ * @len: length of the scancode that resides in @scancode buffer.
+ * @index: index in the keymap, may be used instead of scancode
+ * @flags: allows to specify how kernel should handle the request. For
+ * example, setting INPUT_KEYMAP_BY_INDEX flag indicates that kernel
+ * should perform lookup in keymap by @index instead of @scancode
+ * @keycode: key code assigned to this scancode
+ *
+ * The structure is used to retrieve and modify keymap data. Users have
+ * option of performing lookup either by @scancode itself or by @index
+ * in keymap entry. EVIOCGKEYCODE will also return scancode or index
+ * (depending on which element was used to perform lookup).
+ */
+struct input_keymap_entry {
+#define INPUT_KEYMAP_BY_INDEX (1 << 0)
+ __u8 flags;
+ __u8 len;
+ __u16 index;
+ __u32 keycode;
+ __u8 scancode[32];
+};
+
#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */
#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */
#define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) /* get repeat settings */
#define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) /* set repeat settings */
-#define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) /* get keycode */
-#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) /* set keycode */
+
+#define EVIOCGKEYCODE _IOR('E', 0x04, struct input_keymap_entry) /* get keycode */
+#define EVIOCSKEYCODE _IOW('E', 0x04, struct input_keymap_entry) /* set keycode */
#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */
#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */
-#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */
+#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global key state */
#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */
-#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */
-#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */
+#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */
+#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */
#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */
#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
@@ -1088,13 +1113,13 @@ struct input_mt_slot {
* @keycodemax: size of keycode table
* @keycodesize: size of elements in keycode table
* @keycode: map of scancodes to keycodes for this device
+ * @getkeycode: optional legacy method to retrieve current keymap.
* @setkeycode: optional method to alter current keymap, used to implement
* sparse keymaps. If not supplied default mechanism will be used.
* The method is being called while holding event_lock and thus must
* not sleep
- * @getkeycode: optional method to retrieve current keymap. If not supplied
- * default mechanism will be used. The method is being called while
- * holding event_lock and thus must not sleep
+ * @getkeycode_new: transition method
+ * @setkeycode_new: transition method
* @ff: force feedback structure associated with the device if device
* supports force feedback effects
* @repeat_key: stores key code of the last key pressed; used to implement
@@ -1168,10 +1193,16 @@ struct input_dev {
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
+
int (*setkeycode)(struct input_dev *dev,
unsigned int scancode, unsigned int keycode);
int (*getkeycode)(struct input_dev *dev,
unsigned int scancode, unsigned int *keycode);
+ int (*setkeycode_new)(struct input_dev *dev,
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode);
+ int (*getkeycode_new)(struct input_dev *dev,
+ struct input_keymap_entry *ke);
struct ff_device *ff;
@@ -1478,10 +1509,12 @@ INPUT_GENERATE_ABS_ACCESSORS(fuzz, fuzz)
INPUT_GENERATE_ABS_ACCESSORS(flat, flat)
INPUT_GENERATE_ABS_ACCESSORS(res, resolution)
-int input_get_keycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode);
+int input_scancode_to_scalar(const struct input_keymap_entry *ke,
+ unsigned int *scancode);
+
+int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke);
int input_set_keycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode);
+ const struct input_keymap_entry *ke);
extern struct class input_class;
diff --git a/include/linux/input/bu21013.h b/include/linux/input/bu21013.h
new file mode 100644
index 000000000000..e470d387dd49
--- /dev/null
+++ b/include/linux/input/bu21013.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * License terms:GNU General Public License (GPL) version 2
+ */
+
+#ifndef _BU21013_H
+#define _BU21013_H
+
+/**
+ * struct bu21013_platform_device - Handle the platform data
+ * @cs_en: pointer to the cs enable function
+ * @cs_dis: pointer to the cs disable function
+ * @irq_read_val: pointer to read the pen irq value function
+ * @x_max_res: xmax resolution
+ * @y_max_res: ymax resolution
+ * @touch_x_max: touch x max
+ * @touch_y_max: touch y max
+ * @cs_pin: chip select pin
+ * @irq: irq pin
+ * @ext_clk: external clock flag
+ * @x_flip: x flip flag
+ * @y_flip: y flip flag
+ * @wakeup: wakeup flag
+ *
+ * This is used to handle the platform data
+ */
+struct bu21013_platform_device {
+ int (*cs_en)(int reset_pin);
+ int (*cs_dis)(int reset_pin);
+ int (*irq_read_val)(void);
+ int x_max_res;
+ int y_max_res;
+ int touch_x_max;
+ int touch_y_max;
+ unsigned int cs_pin;
+ unsigned int irq;
+ bool ext_clk;
+ bool x_flip;
+ bool y_flip;
+ bool wakeup;
+};
+
+#endif
diff --git a/include/linux/intel_mid_dma.h b/include/linux/intel_mid_dma.h
index d9d08b6269b6..10496bd24c5c 100644
--- a/include/linux/intel_mid_dma.h
+++ b/include/linux/intel_mid_dma.h
@@ -27,14 +27,7 @@
#include <linux/dmaengine.h>
-/*DMA transaction width, src and dstn width would be same
-The DMA length must be width aligned,
-for 32 bit width the length must be 32 bit (4bytes) aligned only*/
-enum intel_mid_dma_width {
- LNW_DMA_WIDTH_8BIT = 0x0,
- LNW_DMA_WIDTH_16BIT = 0x1,
- LNW_DMA_WIDTH_32BIT = 0x2,
-};
+#define DMA_PREP_CIRCULAR_LIST (1 << 10)
/*DMA mode configurations*/
enum intel_mid_dma_mode {
@@ -69,18 +62,15 @@ enum intel_mid_dma_msize {
* @cfg_mode: DMA data transfer mode (per-per/mem-per/mem-mem)
* @src_msize: Source DMA burst size
* @dst_msize: Dst DMA burst size
+ * @per_addr: Periphral address
* @device_instance: DMA peripheral device instance, we can have multiple
* peripheral device connected to single DMAC
*/
struct intel_mid_dma_slave {
- enum dma_data_direction dirn;
- enum intel_mid_dma_width src_width; /*width of DMA src txn*/
- enum intel_mid_dma_width dst_width; /*width of DMA dst txn*/
enum intel_mid_dma_hs_mode hs_mode; /*handshaking*/
enum intel_mid_dma_mode cfg_mode; /*mode configuration*/
- enum intel_mid_dma_msize src_msize; /*size if src burst*/
- enum intel_mid_dma_msize dst_msize; /*size of dst burst*/
unsigned int device_instance; /*0, 1 for periphral instance*/
+ struct dma_slave_config dma_slave;
};
#endif /*__INTEL_MID_DMA_H__*/
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 414328577ced..79d0c4f6d071 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -410,13 +410,12 @@ extern void open_softirq(int nr, void (*action)(struct softirq_action *));
extern void softirq_init(void);
static inline void __raise_softirq_irqoff(unsigned int nr)
{
- trace_softirq_raise((struct softirq_action *)(unsigned long)nr, NULL);
+ trace_softirq_raise(nr);
or_softirq_pending(1UL << nr);
}
extern void raise_softirq_irqoff(unsigned int nr);
extern void raise_softirq(unsigned int nr);
-extern void wakeup_softirqd(void);
/* This is the worklist that queues up per-cpu softirq work.
*
diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h
index 7fb592793738..8cdcc2a199ad 100644
--- a/include/linux/io-mapping.h
+++ b/include/linux/io-mapping.h
@@ -81,8 +81,7 @@ io_mapping_free(struct io_mapping *mapping)
/* Atomic map/unmap */
static inline void __iomem *
io_mapping_map_atomic_wc(struct io_mapping *mapping,
- unsigned long offset,
- int slot)
+ unsigned long offset)
{
resource_size_t phys_addr;
unsigned long pfn;
@@ -90,13 +89,13 @@ io_mapping_map_atomic_wc(struct io_mapping *mapping,
BUG_ON(offset >= mapping->size);
phys_addr = mapping->base + offset;
pfn = (unsigned long) (phys_addr >> PAGE_SHIFT);
- return iomap_atomic_prot_pfn(pfn, slot, mapping->prot);
+ return iomap_atomic_prot_pfn(pfn, mapping->prot);
}
static inline void
-io_mapping_unmap_atomic(void __iomem *vaddr, int slot)
+io_mapping_unmap_atomic(void __iomem *vaddr)
{
- iounmap_atomic(vaddr, slot);
+ iounmap_atomic(vaddr);
}
static inline void __iomem *
@@ -137,14 +136,13 @@ io_mapping_free(struct io_mapping *mapping)
/* Atomic map/unmap */
static inline void __iomem *
io_mapping_map_atomic_wc(struct io_mapping *mapping,
- unsigned long offset,
- int slot)
+ unsigned long offset)
{
return ((char __force __iomem *) mapping) + offset;
}
static inline void
-io_mapping_unmap_atomic(void __iomem *vaddr, int slot)
+io_mapping_unmap_atomic(void __iomem *vaddr)
{
}
diff --git a/include/linux/ip_vs.h b/include/linux/ip_vs.h
index 9708de265bb1..5f43a3b2e3ad 100644
--- a/include/linux/ip_vs.h
+++ b/include/linux/ip_vs.h
@@ -70,6 +70,7 @@
/*
* IPVS Connection Flags
+ * Only flags 0..15 are sent to backup server
*/
#define IP_VS_CONN_F_FWD_MASK 0x0007 /* mask for the fwd methods */
#define IP_VS_CONN_F_MASQ 0x0000 /* masquerading/NAT */
@@ -88,9 +89,20 @@
#define IP_VS_CONN_F_TEMPLATE 0x1000 /* template, not connection */
#define IP_VS_CONN_F_ONE_PACKET 0x2000 /* forward only one packet */
+/* Flags that are not sent to backup server start from bit 16 */
+#define IP_VS_CONN_F_NFCT (1 << 16) /* use netfilter conntrack */
+
+/* Connection flags from destination that can be changed by user space */
+#define IP_VS_CONN_F_DEST_MASK (IP_VS_CONN_F_FWD_MASK | \
+ IP_VS_CONN_F_ONE_PACKET | \
+ IP_VS_CONN_F_NFCT | \
+ 0)
+
#define IP_VS_SCHEDNAME_MAXLEN 16
+#define IP_VS_PENAME_MAXLEN 16
#define IP_VS_IFNAME_MAXLEN 16
+#define IP_VS_PEDATA_MAXLEN 255
/*
* The struct ip_vs_service_user and struct ip_vs_dest_user are
@@ -324,6 +336,9 @@ enum {
IPVS_SVC_ATTR_NETMASK, /* persistent netmask */
IPVS_SVC_ATTR_STATS, /* nested attribute for service stats */
+
+ IPVS_SVC_ATTR_PE_NAME, /* name of ct retriever */
+
__IPVS_SVC_ATTR_MAX,
};
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index e62683ba88e6..8e429d0e0405 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -341,7 +341,9 @@ struct ipv6_pinfo {
odstopts:1,
rxflow:1,
rxtclass:1,
- rxpmtu:1;
+ rxpmtu:1,
+ rxorigdstaddr:1;
+ /* 2 bits hole */
} bits;
__u16 all;
} rxopt;
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index 0b52924a0cb6..2ae86aa21fce 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -395,7 +395,7 @@ struct jbd2_inode {
struct inode *i_vfs_inode;
/* Flags of inode [j_list_lock] */
- unsigned int i_flags;
+ unsigned long i_flags;
};
struct jbd2_revoke_table_s;
diff --git a/include/linux/jhash.h b/include/linux/jhash.h
index 2a2f99fbcb16..ced1159fa4f2 100644
--- a/include/linux/jhash.h
+++ b/include/linux/jhash.h
@@ -116,7 +116,7 @@ static inline u32 jhash2(const u32 *k, u32 length, u32 initval)
/* A special ultra-optimized versions that knows they are hashing exactly
* 3, 2 or 1 word(s).
*
- * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
+ * NOTE: In particular the "c += length; __jhash_mix(a,b,c);" normally
* done at the end is not done here.
*/
static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index edef168a0406..450092c1e35f 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -173,6 +173,11 @@ extern int _cond_resched(void);
(__x < 0) ? -__x : __x; \
})
+#define abs64(x) ({ \
+ s64 __x = (x); \
+ (__x < 0) ? -__x : __x; \
+ })
+
#ifdef CONFIG_PROVE_LOCKING
void might_fault(void);
#else
@@ -203,10 +208,10 @@ extern unsigned long simple_strtoul(const char *,char **,unsigned int);
extern long simple_strtol(const char *,char **,unsigned int);
extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
extern long long simple_strtoll(const char *,char **,unsigned int);
-extern int strict_strtoul(const char *, unsigned int, unsigned long *);
-extern int strict_strtol(const char *, unsigned int, long *);
-extern int strict_strtoull(const char *, unsigned int, unsigned long long *);
-extern int strict_strtoll(const char *, unsigned int, long long *);
+extern int __must_check strict_strtoul(const char *, unsigned int, unsigned long *);
+extern int __must_check strict_strtol(const char *, unsigned int, long *);
+extern int __must_check strict_strtoull(const char *, unsigned int, unsigned long long *);
+extern int __must_check strict_strtoll(const char *, unsigned int, long long *);
extern int sprintf(char * buf, const char * fmt, ...)
__attribute__ ((format (printf, 2, 3)));
extern int vsprintf(char *buf, const char *, va_list)
@@ -277,6 +282,11 @@ asmlinkage int vprintk(const char *fmt, va_list args)
asmlinkage int printk(const char * fmt, ...)
__attribute__ ((format (printf, 1, 2))) __cold;
+/*
+ * Please don't use printk_ratelimit(), because it shares ratelimiting state
+ * with all other unrelated printk_ratelimit() callsites. Instead use
+ * printk_ratelimited() or plain old __ratelimit().
+ */
extern int __printk_ratelimit(const char *func);
#define printk_ratelimit() __printk_ratelimit(__func__)
extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
@@ -651,6 +661,24 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
(void) (&_max1 == &_max2); \
_max1 > _max2 ? _max1 : _max2; })
+#define min3(x, y, z) ({ \
+ typeof(x) _min1 = (x); \
+ typeof(y) _min2 = (y); \
+ typeof(z) _min3 = (z); \
+ (void) (&_min1 == &_min2); \
+ (void) (&_min1 == &_min3); \
+ _min1 < _min2 ? (_min1 < _min3 ? _min1 : _min3) : \
+ (_min2 < _min3 ? _min2 : _min3); })
+
+#define max3(x, y, z) ({ \
+ typeof(x) _max1 = (x); \
+ typeof(y) _max2 = (y); \
+ typeof(z) _max3 = (z); \
+ (void) (&_max1 == &_max2); \
+ (void) (&_max1 == &_max3); \
+ _max1 > _max2 ? (_max1 > _max3 ? _max1 : _max3) : \
+ (_max2 > _max3 ? _max2 : _max3); })
+
/**
* min_not_zero - return the minimum that is _not_ zero, unless both are zero
* @x: value1
diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h
index c059044bc6dc..ad54c846911b 100644
--- a/include/linux/kernel_stat.h
+++ b/include/linux/kernel_stat.h
@@ -33,6 +33,7 @@ struct kernel_stat {
#ifndef CONFIG_GENERIC_HARDIRQS
unsigned int irqs[NR_IRQS];
#endif
+ unsigned long irqs_sum;
unsigned int softirqs[NR_SOFTIRQS];
};
@@ -54,6 +55,7 @@ static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
struct irq_desc *desc)
{
kstat_this_cpu.irqs[irq]++;
+ kstat_this_cpu.irqs_sum++;
}
static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
@@ -65,8 +67,9 @@ static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu);
#define kstat_irqs_this_cpu(DESC) \
((DESC)->kstat_irqs[smp_processor_id()])
-#define kstat_incr_irqs_this_cpu(irqno, DESC) \
- ((DESC)->kstat_irqs[smp_processor_id()]++)
+#define kstat_incr_irqs_this_cpu(irqno, DESC) do {\
+ ((DESC)->kstat_irqs[smp_processor_id()]++);\
+ kstat_this_cpu.irqs_sum++; } while (0)
#endif
@@ -83,6 +86,7 @@ static inline unsigned int kstat_softirqs_cpu(unsigned int irq, int cpu)
/*
* Number of interrupts per specific IRQ source, since bootup
*/
+#ifndef CONFIG_GENERIC_HARDIRQS
static inline unsigned int kstat_irqs(unsigned int irq)
{
unsigned int sum = 0;
@@ -93,7 +97,17 @@ static inline unsigned int kstat_irqs(unsigned int irq)
return sum;
}
+#else
+extern unsigned int kstat_irqs(unsigned int irq);
+#endif
+/*
+ * Number of interrupts per cpu, since bootup
+ */
+static inline unsigned int kstat_cpu_irqs_sum(unsigned int cpu)
+{
+ return kstat_cpu(cpu).irqs_sum;
+}
/*
* Lock/unlock the current runqueue - to extract task statistics:
diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h
index 62dbee554f60..10308c6a3d1c 100644
--- a/include/linux/kfifo.h
+++ b/include/linux/kfifo.h
@@ -172,7 +172,13 @@ struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void);
static inline unsigned int __must_check
-__kfifo_must_check_helper(unsigned int val)
+__kfifo_uint_must_check_helper(unsigned int val)
+{
+ return val;
+}
+
+static inline int __must_check
+__kfifo_int_must_check_helper(int val)
{
return val;
}
@@ -267,7 +273,7 @@ __kfifo_must_check_helper(unsigned int val)
* @fifo: address of the fifo to be used
*/
#define kfifo_avail(fifo) \
-__kfifo_must_check_helper( \
+__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmpq = (fifo); \
const size_t __recsize = sizeof(*__tmpq->rectype); \
@@ -300,7 +306,7 @@ __kfifo_must_check_helper( \
* This function returns the size of the next fifo record in number of bytes.
*/
#define kfifo_peek_len(fifo) \
-__kfifo_must_check_helper( \
+__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
const size_t __recsize = sizeof(*__tmp->rectype); \
@@ -323,7 +329,7 @@ __kfifo_must_check_helper( \
* Return 0 if no error, otherwise an error code.
*/
#define kfifo_alloc(fifo, size, gfp_mask) \
-__kfifo_must_check_helper( \
+__kfifo_int_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
@@ -419,7 +425,7 @@ __kfifo_must_check_helper( \
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_get(fifo, val) \
-__kfifo_must_check_helper( \
+__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
typeof((val) + 1) __val = (val); \
@@ -460,7 +466,7 @@ __kfifo_must_check_helper( \
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_peek(fifo, val) \
-__kfifo_must_check_helper( \
+__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
typeof((val) + 1) __val = (val); \
@@ -552,7 +558,7 @@ __kfifo_must_check_helper( \
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_out(fifo, buf, n) \
-__kfifo_must_check_helper( \
+__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
typeof((buf) + 1) __buf = (buf); \
@@ -580,7 +586,7 @@ __kfifo_must_check_helper( \
* copied.
*/
#define kfifo_out_spinlocked(fifo, buf, n, lock) \
-__kfifo_must_check_helper( \
+__kfifo_uint_must_check_helper( \
({ \
unsigned long __flags; \
unsigned int __ret; \
@@ -609,7 +615,7 @@ __kfifo_must_check_helper( \
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_from_user(fifo, from, len, copied) \
-__kfifo_must_check_helper( \
+__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
const void __user *__from = (from); \
@@ -637,7 +643,7 @@ __kfifo_must_check_helper( \
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_to_user(fifo, to, len, copied) \
-__kfifo_must_check_helper( \
+__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
void __user *__to = (to); \
@@ -764,7 +770,7 @@ __kfifo_must_check_helper( \
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_out_peek(fifo, buf, n) \
-__kfifo_must_check_helper( \
+__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
typeof((buf) + 1) __buf = (buf); \
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 636fc381c897..919ae53adc5c 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -414,6 +414,14 @@ struct kvm_enable_cap {
__u8 pad[64];
};
+/* for KVM_PPC_GET_PVINFO */
+struct kvm_ppc_pvinfo {
+ /* out */
+ __u32 flags;
+ __u32 hcall[4];
+ __u8 pad[108];
+};
+
#define KVMIO 0xAE
/*
@@ -530,6 +538,8 @@ struct kvm_enable_cap {
#ifdef __KVM_HAVE_XCRS
#define KVM_CAP_XCRS 56
#endif
+#define KVM_CAP_PPC_GET_PVINFO 57
+#define KVM_CAP_PPC_IRQ_LEVEL 58
#ifdef KVM_CAP_IRQ_ROUTING
@@ -664,6 +674,8 @@ struct kvm_clock_data {
/* Available with KVM_CAP_PIT_STATE2 */
#define KVM_GET_PIT2 _IOR(KVMIO, 0x9f, struct kvm_pit_state2)
#define KVM_SET_PIT2 _IOW(KVMIO, 0xa0, struct kvm_pit_state2)
+/* Available with KVM_CAP_PPC_GET_PVINFO */
+#define KVM_PPC_GET_PVINFO _IOW(KVMIO, 0xa1, struct kvm_ppc_pvinfo)
/*
* ioctls for vcpu fds
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index ac740b26eb10..a0557422715e 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -36,9 +36,10 @@
#define KVM_REQ_PENDING_TIMER 5
#define KVM_REQ_UNHALT 6
#define KVM_REQ_MMU_SYNC 7
-#define KVM_REQ_KVMCLOCK_UPDATE 8
+#define KVM_REQ_CLOCK_UPDATE 8
#define KVM_REQ_KICK 9
#define KVM_REQ_DEACTIVATE_FPU 10
+#define KVM_REQ_EVENT 11
#define KVM_USERSPACE_IRQ_SOURCE_ID 0
@@ -289,6 +290,9 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
void kvm_disable_largepages(void);
void kvm_arch_flush_shadow(struct kvm *kvm);
+int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages,
+ int nr_pages);
+
struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn);
void kvm_release_page_clean(struct page *page);
@@ -296,6 +300,8 @@ void kvm_release_page_dirty(struct page *page);
void kvm_set_page_dirty(struct page *page);
void kvm_set_page_accessed(struct page *page);
+pfn_t hva_to_pfn_atomic(struct kvm *kvm, unsigned long addr);
+pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn);
pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn);
pfn_t gfn_to_pfn_memslot(struct kvm *kvm,
struct kvm_memory_slot *slot, gfn_t gfn);
@@ -477,8 +483,7 @@ int kvm_deassign_device(struct kvm *kvm,
struct kvm_assigned_dev_kernel *assigned_dev);
#else /* CONFIG_IOMMU_API */
static inline int kvm_iommu_map_pages(struct kvm *kvm,
- gfn_t base_gfn,
- unsigned long npages)
+ struct kvm_memory_slot *slot)
{
return 0;
}
@@ -518,11 +523,22 @@ static inline void kvm_guest_exit(void)
current->flags &= ~PF_VCPU;
}
+static inline unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot,
+ gfn_t gfn)
+{
+ return slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE;
+}
+
static inline gpa_t gfn_to_gpa(gfn_t gfn)
{
return (gpa_t)gfn << PAGE_SHIFT;
}
+static inline gfn_t gpa_to_gfn(gpa_t gpa)
+{
+ return (gfn_t)(gpa >> PAGE_SHIFT);
+}
+
static inline hpa_t pfn_to_hpa(pfn_t pfn)
{
return (hpa_t)pfn << PAGE_SHIFT;
diff --git a/include/linux/kvm_para.h b/include/linux/kvm_para.h
index d73109243fda..47a070b0520e 100644
--- a/include/linux/kvm_para.h
+++ b/include/linux/kvm_para.h
@@ -17,6 +17,8 @@
#define KVM_HC_VAPIC_POLL_IRQ 1
#define KVM_HC_MMU_OP 2
+#define KVM_HC_FEATURES 3
+#define KVM_HC_PPC_MAP_MAGIC_PAGE 4
/*
* hypercalls use architecture specific
@@ -24,11 +26,6 @@
#include <asm/kvm_para.h>
#ifdef __KERNEL__
-#ifdef CONFIG_KVM_GUEST
-void __init kvm_guest_init(void);
-#else
-#define kvm_guest_init() do { } while (0)
-#endif
static inline int kvm_para_has_feature(unsigned int feature)
{
diff --git a/include/linux/lis3lv02d.h b/include/linux/lis3lv02d.h
index 0e8a346424bb..d4292c8431e0 100644
--- a/include/linux/lis3lv02d.h
+++ b/include/linux/lis3lv02d.h
@@ -1,6 +1,52 @@
#ifndef __LIS3LV02D_H_
#define __LIS3LV02D_H_
+/**
+ * struct lis3lv02d_platform_data - lis3 chip family platform data
+ * @click_flags: Click detection unit configuration
+ * @click_thresh_x: Click detection unit x axis threshold
+ * @click_thresh_y: Click detection unit y axis threshold
+ * @click_thresh_z: Click detection unit z axis threshold
+ * @click_time_limit: Click detection unit time parameter
+ * @click_latency: Click detection unit latency parameter
+ * @click_window: Click detection unit window parameter
+ * @irq_cfg: On chip irq source and type configuration (click /
+ * data available / wake up, open drain, polarity)
+ * @irq_flags1: Additional irq triggering flags for irq channel 0
+ * @irq_flags2: Additional irq triggering flags for irq channel 1
+ * @duration1: Wake up unit 1 duration parameter
+ * @duration2: Wake up unit 2 duration parameter
+ * @wakeup_flags: Wake up unit 1 flags
+ * @wakeup_thresh: Wake up unit 1 threshold value
+ * @wakeup_flags2: Wake up unit 2 flags
+ * @wakeup_thresh2: Wake up unit 2 threshold value
+ * @hipass_ctrl: High pass filter control (enable / disable, cut off
+ * frequency)
+ * @axis_x: Sensor orientation remapping for x-axis
+ * @axis_y: Sensor orientation remapping for y-axis
+ * @axis_z: Sensor orientation remapping for z-axis
+ * @driver_features: Enable bits for different features. Disabled by default
+ * @default_rate: Default sampling rate. 0 means reset default
+ * @setup_resources: Interrupt line setup call back function
+ * @release_resources: Interrupt line release call back function
+ * @st_min_limits[3]: Selftest acceptance minimum values
+ * @st_max_limits[3]: Selftest acceptance maximum values
+ * @irq2: Irq line 2 number
+ *
+ * Platform data is used to setup the sensor chip. Meaning of the different
+ * chip features can be found from the data sheet. It is publicly available
+ * at www.st.com web pages. Currently the platform data is used
+ * only for the 8 bit device. The 8 bit device has two wake up / free fall
+ * detection units and click detection unit. There are plenty of ways to
+ * configure the chip which makes is quite hard to explain deeper meaning of
+ * the fields here. Behaviour of the detection blocks varies heavily depending
+ * on the configuration. For example, interrupt detection block can use high
+ * pass filtered data which makes it react to the changes in the acceleration.
+ * Irq_flags can be used to enable interrupt detection on the both edges.
+ * With proper chip configuration this produces interrupt when some trigger
+ * starts and when it goes away.
+ */
+
struct lis3lv02d_platform_data {
/* please note: the 'click' feature is only supported for
* LIS[32]02DL variants of the chip and will be ignored for
@@ -36,7 +82,10 @@ struct lis3lv02d_platform_data {
#define LIS3_IRQ_OPEN_DRAIN (1 << 6)
#define LIS3_IRQ_ACTIVE_LOW (1 << 7)
unsigned char irq_cfg;
-
+ unsigned char irq_flags1; /* Additional irq edge / level flags */
+ unsigned char irq_flags2; /* Additional irq edge / level flags */
+ unsigned char duration1;
+ unsigned char duration2;
#define LIS3_WAKEUP_X_LO (1 << 0)
#define LIS3_WAKEUP_X_HI (1 << 1)
#define LIS3_WAKEUP_Y_LO (1 << 2)
@@ -64,6 +113,10 @@ struct lis3lv02d_platform_data {
s8 axis_x;
s8 axis_y;
s8 axis_z;
+#define LIS3_USE_REGULATOR_CTRL 0x01
+#define LIS3_USE_BLOCK_READ 0x02
+ u16 driver_features;
+ int default_rate;
int (*setup_resources)(void);
int (*release_resources)(void);
/* Limits for selftest are specified in chip data sheet */
diff --git a/include/linux/list.h b/include/linux/list.h
index 88a000617d77..9a5f8a71810c 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -636,6 +636,12 @@ static inline void hlist_add_after(struct hlist_node *n,
next->next->pprev = &next->next;
}
+/* after that we'll appear to be on some hlist and hlist_del will work */
+static inline void hlist_add_fake(struct hlist_node *n)
+{
+ n->pprev = &n->next;
+}
+
/*
* Move a list from one list head to another. Fixup the pprev
* reference of the first entry if it exists.
diff --git a/include/linux/magic.h b/include/linux/magic.h
index eb9800f05782..ff690d05f129 100644
--- a/include/linux/magic.h
+++ b/include/linux/magic.h
@@ -57,5 +57,6 @@
#define DEVPTS_SUPER_MAGIC 0x1cd1
#define SOCKFS_MAGIC 0x534F434B
+#define V9FS_MAGIC 0x01021997
#endif /* __LINUX_MAGIC_H__ */
diff --git a/include/linux/math64.h b/include/linux/math64.h
index c87f1528703a..23fcdfcba81b 100644
--- a/include/linux/math64.h
+++ b/include/linux/math64.h
@@ -35,6 +35,14 @@ static inline u64 div64_u64(u64 dividend, u64 divisor)
return dividend / divisor;
}
+/**
+ * div64_s64 - signed 64bit divide with 64bit divisor
+ */
+static inline s64 div64_s64(s64 dividend, s64 divisor)
+{
+ return dividend / divisor;
+}
+
#elif BITS_PER_LONG == 32
#ifndef div_u64_rem
@@ -53,6 +61,10 @@ extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder);
extern u64 div64_u64(u64 dividend, u64 divisor);
#endif
+#ifndef div64_s64
+extern s64 div64_s64(s64 dividend, s64 divisor);
+#endif
+
#endif /* BITS_PER_LONG */
/**
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index 864035fb8f8a..4307231bd22f 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -70,6 +70,10 @@ extern void online_page(struct page *page);
extern int online_pages(unsigned long, unsigned long);
extern void __offline_isolated_pages(unsigned long, unsigned long);
+#ifdef CONFIG_MEMORY_HOTREMOVE
+extern bool is_pageblock_removable_nolock(struct page *page);
+#endif /* CONFIG_MEMORY_HOTREMOVE */
+
/* reasonably generic interface to expand the physical pages in a zone */
extern int __add_pages(int nid, struct zone *zone, unsigned long start_pfn,
unsigned long nr_pages);
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 7238231b8dd4..085527fb8261 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -14,6 +14,8 @@ extern int migrate_page(struct address_space *,
struct page *, struct page *);
extern int migrate_pages(struct list_head *l, new_page_t x,
unsigned long private, int offlining);
+extern int migrate_huge_pages(struct list_head *l, new_page_t x,
+ unsigned long private, int offlining);
extern int fail_migrate_page(struct address_space *,
struct page *, struct page *);
@@ -23,12 +25,17 @@ extern int migrate_prep_local(void);
extern int migrate_vmas(struct mm_struct *mm,
const nodemask_t *from, const nodemask_t *to,
unsigned long flags);
+extern void migrate_page_copy(struct page *newpage, struct page *page);
+extern int migrate_huge_page_move_mapping(struct address_space *mapping,
+ struct page *newpage, struct page *page);
#else
#define PAGE_MIGRATION 0
static inline void putback_lru_pages(struct list_head *l) {}
static inline int migrate_pages(struct list_head *l, new_page_t x,
unsigned long private, int offlining) { return -ENOSYS; }
+static inline int migrate_huge_pages(struct list_head *l, new_page_t x,
+ unsigned long private, int offlining) { return -ENOSYS; }
static inline int migrate_prep(void) { return -ENOSYS; }
static inline int migrate_prep_local(void) { return -ENOSYS; }
@@ -40,6 +47,15 @@ static inline int migrate_vmas(struct mm_struct *mm,
return -ENOSYS;
}
+static inline void migrate_page_copy(struct page *newpage,
+ struct page *page) {}
+
+static inline int migrate_huge_page_move_mapping(struct address_space *mapping,
+ struct page *newpage, struct page *page)
+{
+ return -ENOSYS;
+}
+
/* Possible settings for the migrate_page() method in address_operations */
#define migrate_page NULL
#define fail_migrate_page NULL
diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h
index 0f82293a82ed..9a18667c13cc 100644
--- a/include/linux/mlx4/cmd.h
+++ b/include/linux/mlx4/cmd.h
@@ -56,7 +56,9 @@ enum {
MLX4_CMD_QUERY_HCA = 0xb,
MLX4_CMD_QUERY_PORT = 0x43,
MLX4_CMD_SENSE_PORT = 0x4d,
+ MLX4_CMD_HW_HEALTH_CHECK = 0x50,
MLX4_CMD_SET_PORT = 0xc,
+ MLX4_CMD_SET_NODE = 0x5a,
MLX4_CMD_ACCESS_DDR = 0x2e,
MLX4_CMD_MAP_ICM = 0xffa,
MLX4_CMD_UNMAP_ICM = 0xff9,
@@ -140,6 +142,7 @@ enum {
MLX4_SET_PORT_MAC_TABLE = 0x2,
MLX4_SET_PORT_VLAN_TABLE = 0x3,
MLX4_SET_PORT_PRIO_MAP = 0x4,
+ MLX4_SET_PORT_GID_TABLE = 0x5,
};
struct mlx4_dev;
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 7a7f9c1e679a..a7b15bc7648e 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -67,7 +67,8 @@ enum {
MLX4_DEV_CAP_FLAG_ATOMIC = 1 << 18,
MLX4_DEV_CAP_FLAG_RAW_MCAST = 1 << 19,
MLX4_DEV_CAP_FLAG_UD_AV_PORT = 1 << 20,
- MLX4_DEV_CAP_FLAG_UD_MCAST = 1 << 21
+ MLX4_DEV_CAP_FLAG_UD_MCAST = 1 << 21,
+ MLX4_DEV_CAP_FLAG_IBOE = 1 << 30
};
enum {
@@ -171,6 +172,10 @@ enum {
MLX4_NUM_FEXCH = 64 * 1024,
};
+enum {
+ MLX4_MAX_FAST_REG_PAGES = 511,
+};
+
static inline u64 mlx4_fw_ver(u64 major, u64 minor, u64 subminor)
{
return (major << 32) | (minor << 16) | subminor;
@@ -186,6 +191,10 @@ struct mlx4_caps {
int eth_mtu_cap[MLX4_MAX_PORTS + 1];
int gid_table_len[MLX4_MAX_PORTS + 1];
int pkey_table_len[MLX4_MAX_PORTS + 1];
+ int trans_type[MLX4_MAX_PORTS + 1];
+ int vendor_oui[MLX4_MAX_PORTS + 1];
+ int wavelength[MLX4_MAX_PORTS + 1];
+ u64 trans_code[MLX4_MAX_PORTS + 1];
int local_ca_ack_delay;
int num_uars;
int bf_reg_size;
@@ -229,6 +238,8 @@ struct mlx4_caps {
u32 bmme_flags;
u32 reserved_lkey;
u16 stat_rate_support;
+ int udp_rss;
+ int loopback_support;
u8 port_width_cap[MLX4_MAX_PORTS + 1];
int max_gso_sz;
int reserved_qps_cnt[MLX4_NUM_QP_REGION];
@@ -373,6 +384,27 @@ struct mlx4_av {
u8 dgid[16];
};
+struct mlx4_eth_av {
+ __be32 port_pd;
+ u8 reserved1;
+ u8 smac_idx;
+ u16 reserved2;
+ u8 reserved3;
+ u8 gid_index;
+ u8 stat_rate;
+ u8 hop_limit;
+ __be32 sl_tclass_flowlabel;
+ u8 dgid[16];
+ u32 reserved4[2];
+ __be16 vlan;
+ u8 mac[6];
+};
+
+union mlx4_ext_av {
+ struct mlx4_av ib;
+ struct mlx4_eth_av eth;
+};
+
struct mlx4_dev {
struct pci_dev *pdev;
unsigned long flags;
@@ -401,6 +433,12 @@ struct mlx4_init_port_param {
if (((type) == MLX4_PORT_TYPE_IB ? (dev)->caps.port_mask : \
~(dev)->caps.port_mask) & 1 << ((port) - 1))
+#define mlx4_foreach_ib_transport_port(port, dev) \
+ for ((port) = 1; (port) <= (dev)->caps.num_ports; (port)++) \
+ if (((dev)->caps.port_mask & 1 << ((port) - 1)) || \
+ ((dev)->caps.flags & MLX4_DEV_CAP_FLAG_IBOE))
+
+
int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
struct mlx4_buf *buf);
void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf);
@@ -468,6 +506,7 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]);
int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index);
void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index);
+int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx);
int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index);
void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index);
@@ -480,5 +519,6 @@ void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr,
u32 *lkey, u32 *rkey);
int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr);
int mlx4_SYNC_TPT(struct mlx4_dev *dev);
+int mlx4_test_interrupts(struct mlx4_dev *dev);
#endif /* MLX4_DEVICE_H */
diff --git a/include/linux/mlx4/driver.h b/include/linux/mlx4/driver.h
index 53c5fdb6eac4..f407cd4bfb34 100644
--- a/include/linux/mlx4/driver.h
+++ b/include/linux/mlx4/driver.h
@@ -44,15 +44,24 @@ enum mlx4_dev_event {
MLX4_DEV_EVENT_PORT_REINIT,
};
+enum mlx4_protocol {
+ MLX4_PROTOCOL_IB,
+ MLX4_PROTOCOL_EN,
+};
+
struct mlx4_interface {
void * (*add) (struct mlx4_dev *dev);
void (*remove)(struct mlx4_dev *dev, void *context);
void (*event) (struct mlx4_dev *dev, void *context,
enum mlx4_dev_event event, int port);
+ void * (*get_dev)(struct mlx4_dev *dev, void *context, u8 port);
struct list_head list;
+ enum mlx4_protocol protocol;
};
int mlx4_register_interface(struct mlx4_interface *intf);
void mlx4_unregister_interface(struct mlx4_interface *intf);
+void *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, int port);
+
#endif /* MLX4_DRIVER_H */
diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h
index 7abe64326f72..0eeb2a1a867c 100644
--- a/include/linux/mlx4/qp.h
+++ b/include/linux/mlx4/qp.h
@@ -109,10 +109,11 @@ struct mlx4_qp_path {
__be32 tclass_flowlabel;
u8 rgid[16];
u8 sched_queue;
- u8 snooper_flags;
+ u8 vlan_index;
u8 reserved3[2];
u8 counter_index;
- u8 reserved4[7];
+ u8 reserved4;
+ u8 dmac[6];
};
struct mlx4_qp_context {
@@ -166,6 +167,7 @@ enum {
MLX4_WQE_CTRL_TCP_UDP_CSUM = 1 << 5,
MLX4_WQE_CTRL_INS_VLAN = 1 << 6,
MLX4_WQE_CTRL_STRONG_ORDER = 1 << 7,
+ MLX4_WQE_CTRL_FORCE_LOOPBACK = 1 << 0,
};
struct mlx4_wqe_ctrl_seg {
@@ -219,7 +221,8 @@ struct mlx4_wqe_datagram_seg {
__be32 av[8];
__be32 dqpn;
__be32 qkey;
- __be32 reservd[2];
+ __be16 vlan;
+ u8 mac[6];
};
struct mlx4_wqe_lso_seg {
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 7687228dd3b7..721f451c3029 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -144,6 +144,7 @@ extern pgprot_t protection_map[16];
#define FAULT_FLAG_WRITE 0x01 /* Fault was a write access */
#define FAULT_FLAG_NONLINEAR 0x02 /* Fault was via a nonlinear mapping */
#define FAULT_FLAG_MKWRITE 0x04 /* Fault was mkwrite of existing pte */
+#define FAULT_FLAG_ALLOW_RETRY 0x08 /* Retry fault if blocking */
/*
* This interface is used by x86 PAT code to identify a pfn mapping that is
@@ -497,8 +498,8 @@ static inline void set_compound_order(struct page *page, unsigned long order)
#define NODES_PGSHIFT (NODES_PGOFF * (NODES_WIDTH != 0))
#define ZONES_PGSHIFT (ZONES_PGOFF * (ZONES_WIDTH != 0))
-/* NODE:ZONE or SECTION:ZONE is used to ID a zone for the buddy allcator */
-#ifdef NODE_NOT_IN_PAGEFLAGS
+/* NODE:ZONE or SECTION:ZONE is used to ID a zone for the buddy allocator */
+#ifdef NODE_NOT_IN_PAGE_FLAGS
#define ZONEID_SHIFT (SECTIONS_SHIFT + ZONES_SHIFT)
#define ZONEID_PGOFF ((SECTIONS_PGOFF < ZONES_PGOFF)? \
SECTIONS_PGOFF : ZONES_PGOFF)
@@ -718,12 +719,21 @@ static inline int page_mapped(struct page *page)
#define VM_FAULT_SIGBUS 0x0002
#define VM_FAULT_MAJOR 0x0004
#define VM_FAULT_WRITE 0x0008 /* Special case for get_user_pages */
-#define VM_FAULT_HWPOISON 0x0010 /* Hit poisoned page */
+#define VM_FAULT_HWPOISON 0x0010 /* Hit poisoned small page */
+#define VM_FAULT_HWPOISON_LARGE 0x0020 /* Hit poisoned large page. Index encoded in upper bits */
#define VM_FAULT_NOPAGE 0x0100 /* ->fault installed the pte, not return page */
#define VM_FAULT_LOCKED 0x0200 /* ->fault locked the returned page */
+#define VM_FAULT_RETRY 0x0400 /* ->fault blocked, must retry */
+
+#define VM_FAULT_HWPOISON_LARGE_MASK 0xf000 /* encodes hpage index for large hwpoison */
+
+#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_HWPOISON | \
+ VM_FAULT_HWPOISON_LARGE)
-#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_HWPOISON)
+/* Encode hstate index for a hwpoisoned large page */
+#define VM_FAULT_SET_HINDEX(x) ((x) << 12)
+#define VM_FAULT_GET_HINDEX(x) (((x) >> 12) & 0xf)
/*
* Can be called by the pagefault handler when it gets a VM_FAULT_OOM.
@@ -860,6 +870,7 @@ int __set_page_dirty_no_writeback(struct page *page);
int redirty_page_for_writepage(struct writeback_control *wbc,
struct page *page);
void account_page_dirtied(struct page *page, struct address_space *mapping);
+void account_page_writeback(struct page *page);
int set_page_dirty(struct page *page);
int set_page_dirty_lock(struct page *page);
int clear_page_dirty_for_io(struct page *page);
@@ -1023,7 +1034,15 @@ extern void unregister_shrinker(struct shrinker *);
int vma_wants_writenotify(struct vm_area_struct *vma);
-extern pte_t *get_locked_pte(struct mm_struct *mm, unsigned long addr, spinlock_t **ptl);
+extern pte_t *__get_locked_pte(struct mm_struct *mm, unsigned long addr,
+ spinlock_t **ptl);
+static inline pte_t *get_locked_pte(struct mm_struct *mm, unsigned long addr,
+ spinlock_t **ptl)
+{
+ pte_t *ptep;
+ __cond_lock(*ptl, ptep = __get_locked_pte(mm, addr, ptl));
+ return ptep;
+}
#ifdef __PAGETABLE_PUD_FOLDED
static inline int __pud_alloc(struct mm_struct *mm, pgd_t *pgd,
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index cb57d657ce4d..bb7288a782fd 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -310,6 +310,8 @@ struct mm_struct {
#ifdef CONFIG_MMU_NOTIFIER
struct mmu_notifier_mm *mmu_notifier_mm;
#endif
+ /* How many tasks sharing this mm are OOM_DISABLE */
+ atomic_t oom_disable_count;
};
/* Future-safe accessor for struct mm_struct's cpu_vm_mask. */
diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h
index 33b2ea09a4ad..a36ab3bc7b03 100644
--- a/include/linux/mmc/sdio_ids.h
+++ b/include/linux/mmc/sdio_ids.h
@@ -18,6 +18,7 @@
#define SDIO_CLASS_PHS 0x06 /* PHS standard interface */
#define SDIO_CLASS_WLAN 0x07 /* WLAN interface */
#define SDIO_CLASS_ATA 0x08 /* Embedded SDIO-ATA std interface */
+#define SDIO_CLASS_BT_AMP 0x09 /* Type-A Bluetooth AMP interface */
/*
* Vendors and devices. Sort key: vendor first, device next.
diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
index 4e02ee2b071e..43dcfbdc39de 100644
--- a/include/linux/mmu_notifier.h
+++ b/include/linux/mmu_notifier.h
@@ -227,7 +227,7 @@ static inline void mmu_notifier_mm_destroy(struct mm_struct *mm)
/*
* These two macros will sometime replace ptep_clear_flush.
- * ptep_clear_flush is impleemnted as macro itself, so this also is
+ * ptep_clear_flush is implemented as macro itself, so this also is
* implemented as a macro until ptep_clear_flush will converted to an
* inline function, to diminish the risk of compilation failure. The
* invalidate_page method over time can be moved outside the PT lock
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 3984c4eb41fd..39c24ebe9cfd 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -104,6 +104,8 @@ enum zone_stat_item {
NR_ISOLATED_ANON, /* Temporary isolated pages from anon lru */
NR_ISOLATED_FILE, /* Temporary isolated pages from file lru */
NR_SHMEM, /* shmem pages (included tmpfs/GEM pages) */
+ NR_DIRTIED, /* page dirtyings since bootup */
+ NR_WRITTEN, /* page writings since bootup */
#ifdef CONFIG_NUMA
NUMA_HIT, /* allocated in intended node */
NUMA_MISS, /* allocated in non intended node */
@@ -421,6 +423,9 @@ struct zone {
typedef enum {
ZONE_RECLAIM_LOCKED, /* prevents concurrent reclaim */
ZONE_OOM_LOCKED, /* zone is in OOM killer zonelist */
+ ZONE_CONGESTED, /* zone has many dirty pages backed by
+ * a congested BDI
+ */
} zone_flags_t;
static inline void zone_set_flag(struct zone *zone, zone_flags_t flag)
@@ -438,6 +443,11 @@ static inline void zone_clear_flag(struct zone *zone, zone_flags_t flag)
clear_bit(flag, &zone->flags);
}
+static inline int zone_is_reclaim_congested(const struct zone *zone)
+{
+ return test_bit(ZONE_CONGESTED, &zone->flags);
+}
+
static inline int zone_is_reclaim_locked(const struct zone *zone)
{
return test_bit(ZONE_RECLAIM_LOCKED, &zone->flags);
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index 9d2f1837b3d8..112adf8bd47d 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -21,8 +21,8 @@
#define __module_cat(a,b) ___module_cat(a,b)
#define __MODULE_INFO(tag, name, info) \
static const char __module_cat(name,__LINE__)[] \
- __used \
- __attribute__((section(".modinfo"),unused)) = __stringify(tag) "=" info
+ __used __attribute__((section(".modinfo"), unused, aligned(1))) \
+ = __stringify(tag) "=" info
#else /* !MODULE */
#define __MODULE_INFO(tag, name, info)
#endif
diff --git a/include/linux/mroute.h b/include/linux/mroute.h
index fa04b246c9ae..0fa7a3a874c8 100644
--- a/include/linux/mroute.h
+++ b/include/linux/mroute.h
@@ -213,6 +213,7 @@ struct mfc_cache {
unsigned char ttls[MAXVIFS]; /* TTL thresholds */
} res;
} mfc_un;
+ struct rcu_head rcu;
};
#define MFC_STATIC 1
diff --git a/include/linux/n_r3964.h b/include/linux/n_r3964.h
index de24af79ebd3..54b8e0d8d916 100644
--- a/include/linux/n_r3964.h
+++ b/include/linux/n_r3964.h
@@ -4,7 +4,6 @@
* Copyright by
* Philips Automation Projects
* Kassel (Germany)
- * http://www.pap-philips.de
* -----------------------------------------------------------
* This software may be used and distributed according to the terms of
* the GNU General Public License, incorporated herein by reference.
diff --git a/include/linux/net.h b/include/linux/net.h
index dee0b11a8759..16faa130088c 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -229,6 +229,8 @@ enum {
extern int sock_wake_async(struct socket *sk, int how, int band);
extern int sock_register(const struct net_proto_family *fam);
extern void sock_unregister(int family);
+extern int __sock_create(struct net *net, int family, int type, int proto,
+ struct socket **res, int kern);
extern int sock_create(int family, int type, int proto,
struct socket **res);
extern int sock_create_kern(int family, int type, int proto,
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 46c36ffe20ee..072652d94d9f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -228,9 +228,9 @@ struct netdev_hw_addr {
#define NETDEV_HW_ADDR_T_SLAVE 3
#define NETDEV_HW_ADDR_T_UNICAST 4
#define NETDEV_HW_ADDR_T_MULTICAST 5
- int refcount;
bool synced;
bool global_use;
+ int refcount;
struct rcu_head rcu_head;
};
@@ -281,6 +281,12 @@ struct hh_cache {
unsigned long hh_data[HH_DATA_ALIGN(LL_MAX_HEADER) / sizeof(long)];
};
+static inline void hh_cache_put(struct hh_cache *hh)
+{
+ if (atomic_dec_and_test(&hh->hh_refcnt))
+ kfree(hh);
+}
+
/* Reserve HH_DATA_MOD byte aligned hard_header_len, but at least that much.
* Alternative is:
* dev->hard_header_len ? (dev->hard_header_len +
@@ -579,15 +585,15 @@ static inline void rps_reset_sock_flow(struct rps_sock_flow_table *table,
table->ents[hash & table->mask] = RPS_NO_CPU;
}
-extern struct rps_sock_flow_table *rps_sock_flow_table;
+extern struct rps_sock_flow_table __rcu *rps_sock_flow_table;
/* This structure contains an instance of an RX queue. */
struct netdev_rx_queue {
- struct rps_map *rps_map;
- struct rps_dev_flow_table *rps_flow_table;
- struct kobject kobj;
- struct netdev_rx_queue *first;
- atomic_t count;
+ struct rps_map __rcu *rps_map;
+ struct rps_dev_flow_table __rcu *rps_flow_table;
+ struct kobject kobj;
+ struct netdev_rx_queue *first;
+ atomic_t count;
} ____cacheline_aligned_in_smp;
#endif /* CONFIG_RPS */
@@ -884,6 +890,9 @@ struct net_device {
int iflink;
struct net_device_stats stats;
+ atomic_long_t rx_dropped; /* dropped packets by core network
+ * Do not use this in drivers.
+ */
#ifdef CONFIG_WIRELESS_EXT
/* List of functions to handle Wireless Extensions (instead of ioctl).
@@ -901,7 +910,7 @@ struct net_device {
unsigned int flags; /* interface flags (a la BSD) */
unsigned short gflags;
- unsigned short priv_flags; /* Like 'flags' but invisible to userspace. */
+ unsigned int priv_flags; /* Like 'flags' but invisible to userspace. */
unsigned short padded; /* How much padding added by alloc_netdev() */
unsigned char operstate; /* RFC2863 operstate */
@@ -918,10 +927,6 @@ struct net_device {
unsigned short needed_headroom;
unsigned short needed_tailroom;
- struct net_device *master; /* Pointer to master device of a group,
- * which this device is member of.
- */
-
/* Interface address info. */
unsigned char perm_addr[MAX_ADDR_LEN]; /* permanent hw address */
unsigned char addr_assign_type; /* hw address assignment type */
@@ -937,23 +942,37 @@ struct net_device {
/* Protocol specific pointers */
-
+
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+ struct vlan_group __rcu *vlgrp; /* VLAN group */
+#endif
#ifdef CONFIG_NET_DSA
void *dsa_ptr; /* dsa specific data */
#endif
void *atalk_ptr; /* AppleTalk link */
- void *ip_ptr; /* IPv4 specific data */
+ struct in_device __rcu *ip_ptr; /* IPv4 specific data */
void *dn_ptr; /* DECnet specific data */
- void *ip6_ptr; /* IPv6 specific data */
+ struct inet6_dev __rcu *ip6_ptr; /* IPv6 specific data */
void *ec_ptr; /* Econet specific data */
void *ax25_ptr; /* AX.25 specific data */
struct wireless_dev *ieee80211_ptr; /* IEEE 802.11 specific data,
assign before registering */
/*
- * Cache line mostly used on receive path (including eth_type_trans())
+ * Cache lines mostly used on receive path (including eth_type_trans())
*/
- unsigned long last_rx; /* Time of last Rx */
+ unsigned long last_rx; /* Time of last Rx
+ * This should not be set in
+ * drivers, unless really needed,
+ * because network stack (bonding)
+ * use it if/when necessary, to
+ * avoid dirtying this cache line.
+ */
+
+ struct net_device *master; /* Pointer to master device of a group,
+ * which this device is member of.
+ */
+
/* Interface address info used in eth_type_trans() */
unsigned char *dev_addr; /* hw address, (before bcast
because most packets are
@@ -969,14 +988,21 @@ struct net_device {
struct netdev_rx_queue *_rx;
- /* Number of RX queues allocated at alloc_netdev_mq() time */
+ /* Number of RX queues allocated at register_netdev() time */
unsigned int num_rx_queues;
+
+ /* Number of RX queues currently active in device */
+ unsigned int real_num_rx_queues;
#endif
- struct netdev_queue rx_queue;
rx_handler_func_t *rx_handler;
void *rx_handler_data;
+ struct netdev_queue __rcu *ingress_queue;
+
+/*
+ * Cache lines mostly used on transmit path
+ */
struct netdev_queue *_tx ____cacheline_aligned_in_smp;
/* Number of TX queues allocated at alloc_netdev_mq() time */
@@ -990,9 +1016,7 @@ struct net_device {
unsigned long tx_queue_len; /* Max frames per queue allowed */
spinlock_t tx_global_lock;
-/*
- * One part is mostly used on xmit path (device)
- */
+
/* These may be needed for future network-power-down code. */
/*
@@ -1005,7 +1029,7 @@ struct net_device {
struct timer_list watchdog_timer;
/* Number of references to this device */
- atomic_t refcnt ____cacheline_aligned_in_smp;
+ int __percpu *pcpu_refcnt;
/* delayed register/unregister */
struct list_head todo_list;
@@ -1041,10 +1065,14 @@ struct net_device {
#endif
/* mid-layer private */
- void *ml_priv;
-
+ union {
+ void *ml_priv;
+ struct pcpu_lstats __percpu *lstats; /* loopback stats */
+ struct pcpu_tstats __percpu *tstats; /* tunnel stats */
+ struct pcpu_dstats __percpu *dstats; /* dummy stats */
+ };
/* GARP */
- struct garp_port *garp_port;
+ struct garp_port __rcu *garp_port;
/* class/net/name entry */
struct device dev;
@@ -1305,6 +1333,7 @@ static inline void unregister_netdevice(struct net_device *dev)
unregister_netdevice_queue(dev, NULL);
}
+extern int netdev_refcnt_read(const struct net_device *dev);
extern void free_netdev(struct net_device *dev);
extern void synchronize_net(void);
extern int register_netdevice_notifier(struct notifier_block *nb);
@@ -1667,11 +1696,34 @@ static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index)
*/
static inline int netif_is_multiqueue(const struct net_device *dev)
{
- return (dev->num_tx_queues > 1);
+ return dev->num_tx_queues > 1;
}
-extern void netif_set_real_num_tx_queues(struct net_device *dev,
- unsigned int txq);
+extern int netif_set_real_num_tx_queues(struct net_device *dev,
+ unsigned int txq);
+
+#ifdef CONFIG_RPS
+extern int netif_set_real_num_rx_queues(struct net_device *dev,
+ unsigned int rxq);
+#else
+static inline int netif_set_real_num_rx_queues(struct net_device *dev,
+ unsigned int rxq)
+{
+ return 0;
+}
+#endif
+
+static inline int netif_copy_real_num_queues(struct net_device *to_dev,
+ const struct net_device *from_dev)
+{
+ netif_set_real_num_tx_queues(to_dev, from_dev->real_num_tx_queues);
+#ifdef CONFIG_RPS
+ return netif_set_real_num_rx_queues(to_dev,
+ from_dev->real_num_rx_queues);
+#else
+ return 0;
+#endif
+}
/* Use this variant when it is known for sure that it
* is executing from hardware interrupt context or with hardware interrupts
@@ -1695,8 +1747,7 @@ extern gro_result_t dev_gro_receive(struct napi_struct *napi,
extern gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb);
extern gro_result_t napi_gro_receive(struct napi_struct *napi,
struct sk_buff *skb);
-extern void napi_reuse_skb(struct napi_struct *napi,
- struct sk_buff *skb);
+extern void napi_gro_flush(struct napi_struct *napi);
extern struct sk_buff * napi_get_frags(struct napi_struct *napi);
extern gro_result_t napi_frags_finish(struct napi_struct *napi,
struct sk_buff *skb,
@@ -1715,7 +1766,6 @@ extern int netdev_rx_handler_register(struct net_device *dev,
void *rx_handler_data);
extern void netdev_rx_handler_unregister(struct net_device *dev);
-extern void netif_nit_deliver(struct sk_buff *skb);
extern int dev_valid_name(const char *name);
extern int dev_ioctl(struct net *net, unsigned int cmd, void __user *);
extern int dev_ethtool(struct net *net, struct ifreq *);
@@ -1749,7 +1799,7 @@ extern void netdev_run_todo(void);
*/
static inline void dev_put(struct net_device *dev)
{
- atomic_dec(&dev->refcnt);
+ irqsafe_cpu_dec(*dev->pcpu_refcnt);
}
/**
@@ -1760,7 +1810,7 @@ static inline void dev_put(struct net_device *dev)
*/
static inline void dev_hold(struct net_device *dev)
{
- atomic_inc(&dev->refcnt);
+ irqsafe_cpu_inc(*dev->pcpu_refcnt);
}
/* Carrier loss detection, dial on demand. The functions netif_carrier_on
@@ -2171,6 +2221,8 @@ extern void dev_seq_stop(struct seq_file *seq, void *v);
extern int netdev_class_create_file(struct class_attribute *class_attr);
extern void netdev_class_remove_file(struct class_attribute *class_attr);
+extern struct kobj_ns_type_operations net_ns_type_operations;
+
extern char *netdev_drivername(const struct net_device *dev, char *buffer, int len);
extern void linkwatch_run_queue(void);
@@ -2191,14 +2243,22 @@ static inline int net_gso_ok(int features, int gso_type)
static inline int skb_gso_ok(struct sk_buff *skb, int features)
{
return net_gso_ok(features, skb_shinfo(skb)->gso_type) &&
- (!skb_has_frags(skb) || (features & NETIF_F_FRAGLIST));
+ (!skb_has_frag_list(skb) || (features & NETIF_F_FRAGLIST));
}
static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
{
- return skb_is_gso(skb) &&
- (!skb_gso_ok(skb, dev->features) ||
- unlikely(skb->ip_summed != CHECKSUM_PARTIAL));
+ if (skb_is_gso(skb)) {
+ int features = dev->features;
+
+ if (skb->protocol == htons(ETH_P_8021Q) || skb->vlan_tci)
+ features &= dev->vlan_features;
+
+ return (!skb_gso_ok(skb, features) ||
+ unlikely(skb->ip_summed != CHECKSUM_PARTIAL));
+ }
+
+ return 0;
}
static inline void netif_set_gso_max_size(struct net_device *dev,
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h
index 1afd18c855ec..50cdc2559a5a 100644
--- a/include/linux/netfilter/nf_conntrack_common.h
+++ b/include/linux/netfilter/nf_conntrack_common.h
@@ -98,8 +98,14 @@ enum ip_conntrack_events {
enum ip_conntrack_expect_events {
IPEXP_NEW, /* new expectation */
+ IPEXP_DESTROY, /* destroyed expectation */
};
+/* expectation flags */
+#define NF_CT_EXPECT_PERMANENT 0x1
+#define NF_CT_EXPECT_INACTIVE 0x2
+#define NF_CT_EXPECT_USERSPACE 0x4
+
#ifdef __KERNEL__
struct ip_conntrack_stat {
unsigned int searched;
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index ff8cfbcf3b81..0ce91d56a5f2 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -89,6 +89,7 @@ enum sip_header_types {
SIP_HDR_VIA_TCP,
SIP_HDR_EXPIRES,
SIP_HDR_CONTENT_LENGTH,
+ SIP_HDR_CALL_ID,
};
enum sdp_header_types {
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h
index 70cd0603911c..19711e3ffd42 100644
--- a/include/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/linux/netfilter/nfnetlink_conntrack.h
@@ -162,6 +162,7 @@ enum ctattr_expect {
CTA_EXPECT_ID,
CTA_EXPECT_HELP_NAME,
CTA_EXPECT_ZONE,
+ CTA_EXPECT_FLAGS,
__CTA_EXPECT_MAX
};
#define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 24e5d01d27d0..742bec051440 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -66,6 +66,11 @@ struct xt_standard_target {
int verdict;
};
+struct xt_error_target {
+ struct xt_entry_target target;
+ char errorname[XT_FUNCTION_MAXNAMELEN];
+};
+
/* The argument to IPT_SO_GET_REVISION_*. Returns highest revision
* kernel supports, if >= revision. */
struct xt_get_revision {
diff --git a/include/linux/netfilter/xt_TPROXY.h b/include/linux/netfilter/xt_TPROXY.h
index 152e8f97132b..3f3d69361289 100644
--- a/include/linux/netfilter/xt_TPROXY.h
+++ b/include/linux/netfilter/xt_TPROXY.h
@@ -1,5 +1,5 @@
-#ifndef _XT_TPROXY_H_target
-#define _XT_TPROXY_H_target
+#ifndef _XT_TPROXY_H
+#define _XT_TPROXY_H
/* TPROXY target is capable of marking the packet to perform
* redirection. We can get rid of that whenever we get support for
@@ -11,4 +11,11 @@ struct xt_tproxy_target_info {
__be16 lport;
};
-#endif /* _XT_TPROXY_H_target */
+struct xt_tproxy_target_info_v1 {
+ u_int32_t mark_mask;
+ u_int32_t mark_value;
+ union nf_inet_addr laddr;
+ __be16 lport;
+};
+
+#endif /* _XT_TPROXY_H */
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h
index e9948c0560f6..adbf4bff87ed 100644
--- a/include/linux/netfilter_arp/arp_tables.h
+++ b/include/linux/netfilter_arp/arp_tables.h
@@ -21,8 +21,21 @@
#include <linux/netfilter/x_tables.h>
+#ifndef __KERNEL__
#define ARPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
#define ARPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
+#define arpt_entry_target xt_entry_target
+#define arpt_standard_target xt_standard_target
+#define arpt_error_target xt_error_target
+#define ARPT_CONTINUE XT_CONTINUE
+#define ARPT_RETURN XT_RETURN
+#define arpt_counters_info xt_counters_info
+#define arpt_counters xt_counters
+#define ARPT_STANDARD_TARGET XT_STANDARD_TARGET
+#define ARPT_ERROR_TARGET XT_ERROR_TARGET
+#define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \
+ XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args)
+#endif
#define ARPT_DEV_ADDR_LEN_MAX 16
@@ -63,9 +76,6 @@ struct arpt_arp {
u_int16_t invflags;
};
-#define arpt_entry_target xt_entry_target
-#define arpt_standard_target xt_standard_target
-
/* Values for "flag" field in struct arpt_ip (general arp structure).
* No flags defined yet.
*/
@@ -125,16 +135,10 @@ struct arpt_entry
#define ARPT_SO_GET_REVISION_TARGET (ARPT_BASE_CTL + 3)
#define ARPT_SO_GET_MAX (ARPT_SO_GET_REVISION_TARGET)
-/* CONTINUE verdict for targets */
-#define ARPT_CONTINUE XT_CONTINUE
-
-/* For standard target */
-#define ARPT_RETURN XT_RETURN
-
/* The argument to ARPT_SO_GET_INFO */
struct arpt_getinfo {
/* Which table: caller fills this in. */
- char name[ARPT_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
/* Kernel fills these in. */
/* Which hook entry points are valid: bitmask */
@@ -156,7 +160,7 @@ struct arpt_getinfo {
/* The argument to ARPT_SO_SET_REPLACE. */
struct arpt_replace {
/* Which table. */
- char name[ARPT_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
/* Which hook entry points are valid: bitmask. You can't
change this. */
@@ -184,14 +188,10 @@ struct arpt_replace {
struct arpt_entry entries[0];
};
-/* The argument to ARPT_SO_ADD_COUNTERS. */
-#define arpt_counters_info xt_counters_info
-#define arpt_counters xt_counters
-
/* The argument to ARPT_SO_GET_ENTRIES. */
struct arpt_get_entries {
/* Which table: user fills this in. */
- char name[ARPT_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
/* User fills this in: total entry size. */
unsigned int size;
@@ -200,23 +200,12 @@ struct arpt_get_entries {
struct arpt_entry entrytable[0];
};
-/* Standard return verdict, or do jump. */
-#define ARPT_STANDARD_TARGET XT_STANDARD_TARGET
-/* Error verdict. */
-#define ARPT_ERROR_TARGET XT_ERROR_TARGET
-
/* Helper functions */
-static __inline__ struct arpt_entry_target *arpt_get_target(struct arpt_entry *e)
+static __inline__ struct xt_entry_target *arpt_get_target(struct arpt_entry *e)
{
return (void *)e + e->target_offset;
}
-#ifndef __KERNEL__
-/* fn returns 0 to continue iteration */
-#define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \
- XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args)
-#endif
-
/*
* Main firewall chains definitions and global var's definitions.
*/
@@ -225,17 +214,12 @@ static __inline__ struct arpt_entry_target *arpt_get_target(struct arpt_entry *e
/* Standard entry. */
struct arpt_standard {
struct arpt_entry entry;
- struct arpt_standard_target target;
-};
-
-struct arpt_error_target {
- struct arpt_entry_target target;
- char errorname[ARPT_FUNCTION_MAXNAMELEN];
+ struct xt_standard_target target;
};
struct arpt_error {
struct arpt_entry entry;
- struct arpt_error_target target;
+ struct xt_error_target target;
};
#define ARPT_ENTRY_INIT(__size) \
@@ -247,16 +231,16 @@ struct arpt_error {
#define ARPT_STANDARD_INIT(__verdict) \
{ \
.entry = ARPT_ENTRY_INIT(sizeof(struct arpt_standard)), \
- .target = XT_TARGET_INIT(ARPT_STANDARD_TARGET, \
- sizeof(struct arpt_standard_target)), \
+ .target = XT_TARGET_INIT(XT_STANDARD_TARGET, \
+ sizeof(struct xt_standard_target)), \
.target.verdict = -(__verdict) - 1, \
}
#define ARPT_ERROR_INIT \
{ \
.entry = ARPT_ENTRY_INIT(sizeof(struct arpt_error)), \
- .target = XT_TARGET_INIT(ARPT_ERROR_TARGET, \
- sizeof(struct arpt_error_target)), \
+ .target = XT_TARGET_INIT(XT_ERROR_TARGET, \
+ sizeof(struct xt_error_target)), \
.target.errorname = "ERROR", \
}
@@ -271,8 +255,6 @@ extern unsigned int arpt_do_table(struct sk_buff *skb,
const struct net_device *out,
struct xt_table *table);
-#define ARPT_ALIGN(s) XT_ALIGN(s)
-
#ifdef CONFIG_COMPAT
#include <net/compat.h>
@@ -285,14 +267,12 @@ struct compat_arpt_entry {
unsigned char elems[0];
};
-static inline struct arpt_entry_target *
+static inline struct xt_entry_target *
compat_arpt_get_target(struct compat_arpt_entry *e)
{
return (void *)e + e->target_offset;
}
-#define COMPAT_ARPT_ALIGN(s) COMPAT_XT_ALIGN(s)
-
#endif /* CONFIG_COMPAT */
#endif /*__KERNEL__*/
#endif /* _ARPTABLES_H */
diff --git a/include/linux/netfilter_bridge/Kbuild b/include/linux/netfilter_bridge/Kbuild
index d4d78672873e..e48f1a3f5a4a 100644
--- a/include/linux/netfilter_bridge/Kbuild
+++ b/include/linux/netfilter_bridge/Kbuild
@@ -3,11 +3,13 @@ header-y += ebt_among.h
header-y += ebt_arp.h
header-y += ebt_arpreply.h
header-y += ebt_ip.h
+header-y += ebt_ip6.h
header-y += ebt_limit.h
header-y += ebt_log.h
header-y += ebt_mark_m.h
header-y += ebt_mark_t.h
header-y += ebt_nat.h
+header-y += ebt_nflog.h
header-y += ebt_pkttype.h
header-y += ebt_redirect.h
header-y += ebt_stp.h
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
index 704a7b6e8169..64a5d95c58e8 100644
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -27,12 +27,49 @@
#include <linux/netfilter/x_tables.h>
+#ifndef __KERNEL__
#define IPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
#define IPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
#define ipt_match xt_match
#define ipt_target xt_target
#define ipt_table xt_table
#define ipt_get_revision xt_get_revision
+#define ipt_entry_match xt_entry_match
+#define ipt_entry_target xt_entry_target
+#define ipt_standard_target xt_standard_target
+#define ipt_error_target xt_error_target
+#define ipt_counters xt_counters
+#define IPT_CONTINUE XT_CONTINUE
+#define IPT_RETURN XT_RETURN
+
+/* This group is older than old (iptables < v1.4.0-rc1~89) */
+#include <linux/netfilter/xt_tcpudp.h>
+#define ipt_udp xt_udp
+#define ipt_tcp xt_tcp
+#define IPT_TCP_INV_SRCPT XT_TCP_INV_SRCPT
+#define IPT_TCP_INV_DSTPT XT_TCP_INV_DSTPT
+#define IPT_TCP_INV_FLAGS XT_TCP_INV_FLAGS
+#define IPT_TCP_INV_OPTION XT_TCP_INV_OPTION
+#define IPT_TCP_INV_MASK XT_TCP_INV_MASK
+#define IPT_UDP_INV_SRCPT XT_UDP_INV_SRCPT
+#define IPT_UDP_INV_DSTPT XT_UDP_INV_DSTPT
+#define IPT_UDP_INV_MASK XT_UDP_INV_MASK
+
+/* The argument to IPT_SO_ADD_COUNTERS. */
+#define ipt_counters_info xt_counters_info
+/* Standard return verdict, or do jump. */
+#define IPT_STANDARD_TARGET XT_STANDARD_TARGET
+/* Error verdict. */
+#define IPT_ERROR_TARGET XT_ERROR_TARGET
+
+/* fn returns 0 to continue iteration */
+#define IPT_MATCH_ITERATE(e, fn, args...) \
+ XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args)
+
+/* fn returns 0 to continue iteration */
+#define IPT_ENTRY_ITERATE(entries, size, fn, args...) \
+ XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args)
+#endif
/* Yes, Virginia, you have to zero the padding. */
struct ipt_ip {
@@ -52,12 +89,6 @@ struct ipt_ip {
u_int8_t invflags;
};
-#define ipt_entry_match xt_entry_match
-#define ipt_entry_target xt_entry_target
-#define ipt_standard_target xt_standard_target
-
-#define ipt_counters xt_counters
-
/* Values for "flag" field in struct ipt_ip (general ip structure). */
#define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */
#define IPT_F_GOTO 0x02 /* Set if jump is a goto */
@@ -116,23 +147,6 @@ struct ipt_entry {
#define IPT_SO_GET_REVISION_TARGET (IPT_BASE_CTL + 3)
#define IPT_SO_GET_MAX IPT_SO_GET_REVISION_TARGET
-#define IPT_CONTINUE XT_CONTINUE
-#define IPT_RETURN XT_RETURN
-
-#include <linux/netfilter/xt_tcpudp.h>
-#define ipt_udp xt_udp
-#define ipt_tcp xt_tcp
-
-#define IPT_TCP_INV_SRCPT XT_TCP_INV_SRCPT
-#define IPT_TCP_INV_DSTPT XT_TCP_INV_DSTPT
-#define IPT_TCP_INV_FLAGS XT_TCP_INV_FLAGS
-#define IPT_TCP_INV_OPTION XT_TCP_INV_OPTION
-#define IPT_TCP_INV_MASK XT_TCP_INV_MASK
-
-#define IPT_UDP_INV_SRCPT XT_UDP_INV_SRCPT
-#define IPT_UDP_INV_DSTPT XT_UDP_INV_DSTPT
-#define IPT_UDP_INV_MASK XT_UDP_INV_MASK
-
/* ICMP matching stuff */
struct ipt_icmp {
u_int8_t type; /* type to match */
@@ -146,7 +160,7 @@ struct ipt_icmp {
/* The argument to IPT_SO_GET_INFO */
struct ipt_getinfo {
/* Which table: caller fills this in. */
- char name[IPT_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
/* Kernel fills these in. */
/* Which hook entry points are valid: bitmask */
@@ -168,7 +182,7 @@ struct ipt_getinfo {
/* The argument to IPT_SO_SET_REPLACE. */
struct ipt_replace {
/* Which table. */
- char name[IPT_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
/* Which hook entry points are valid: bitmask. You can't
change this. */
@@ -196,13 +210,10 @@ struct ipt_replace {
struct ipt_entry entries[0];
};
-/* The argument to IPT_SO_ADD_COUNTERS. */
-#define ipt_counters_info xt_counters_info
-
/* The argument to IPT_SO_GET_ENTRIES. */
struct ipt_get_entries {
/* Which table: user fills this in. */
- char name[IPT_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
/* User fills this in: total entry size. */
unsigned int size;
@@ -211,28 +222,13 @@ struct ipt_get_entries {
struct ipt_entry entrytable[0];
};
-/* Standard return verdict, or do jump. */
-#define IPT_STANDARD_TARGET XT_STANDARD_TARGET
-/* Error verdict. */
-#define IPT_ERROR_TARGET XT_ERROR_TARGET
-
/* Helper functions */
-static __inline__ struct ipt_entry_target *
+static __inline__ struct xt_entry_target *
ipt_get_target(struct ipt_entry *e)
{
return (void *)e + e->target_offset;
}
-#ifndef __KERNEL__
-/* fn returns 0 to continue iteration */
-#define IPT_MATCH_ITERATE(e, fn, args...) \
- XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args)
-
-/* fn returns 0 to continue iteration */
-#define IPT_ENTRY_ITERATE(entries, size, fn, args...) \
- XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args)
-#endif
-
/*
* Main firewall chains definitions and global var's definitions.
*/
@@ -249,17 +245,12 @@ extern void ipt_unregister_table(struct net *net, struct xt_table *table);
/* Standard entry. */
struct ipt_standard {
struct ipt_entry entry;
- struct ipt_standard_target target;
-};
-
-struct ipt_error_target {
- struct ipt_entry_target target;
- char errorname[IPT_FUNCTION_MAXNAMELEN];
+ struct xt_standard_target target;
};
struct ipt_error {
struct ipt_entry entry;
- struct ipt_error_target target;
+ struct xt_error_target target;
};
#define IPT_ENTRY_INIT(__size) \
@@ -271,7 +262,7 @@ struct ipt_error {
#define IPT_STANDARD_INIT(__verdict) \
{ \
.entry = IPT_ENTRY_INIT(sizeof(struct ipt_standard)), \
- .target = XT_TARGET_INIT(IPT_STANDARD_TARGET, \
+ .target = XT_TARGET_INIT(XT_STANDARD_TARGET, \
sizeof(struct xt_standard_target)), \
.target.verdict = -(__verdict) - 1, \
}
@@ -279,8 +270,8 @@ struct ipt_error {
#define IPT_ERROR_INIT \
{ \
.entry = IPT_ENTRY_INIT(sizeof(struct ipt_error)), \
- .target = XT_TARGET_INIT(IPT_ERROR_TARGET, \
- sizeof(struct ipt_error_target)), \
+ .target = XT_TARGET_INIT(XT_ERROR_TARGET, \
+ sizeof(struct xt_error_target)), \
.target.errorname = "ERROR", \
}
@@ -291,8 +282,6 @@ extern unsigned int ipt_do_table(struct sk_buff *skb,
const struct net_device *out,
struct xt_table *table);
-#define IPT_ALIGN(s) XT_ALIGN(s)
-
#ifdef CONFIG_COMPAT
#include <net/compat.h>
@@ -307,14 +296,12 @@ struct compat_ipt_entry {
};
/* Helper functions */
-static inline struct ipt_entry_target *
+static inline struct xt_entry_target *
compat_ipt_get_target(struct compat_ipt_entry *e)
{
return (void *)e + e->target_offset;
}
-#define COMPAT_IPT_ALIGN(s) COMPAT_XT_ALIGN(s)
-
#endif /* CONFIG_COMPAT */
#endif /*__KERNEL__*/
#endif /* _IPTABLES_H */
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index 18442ff19c07..c9784f7a9c1f 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -27,13 +27,42 @@
#include <linux/netfilter/x_tables.h>
+#ifndef __KERNEL__
#define IP6T_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
#define IP6T_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
-
#define ip6t_match xt_match
#define ip6t_target xt_target
#define ip6t_table xt_table
#define ip6t_get_revision xt_get_revision
+#define ip6t_entry_match xt_entry_match
+#define ip6t_entry_target xt_entry_target
+#define ip6t_standard_target xt_standard_target
+#define ip6t_error_target xt_error_target
+#define ip6t_counters xt_counters
+#define IP6T_CONTINUE XT_CONTINUE
+#define IP6T_RETURN XT_RETURN
+
+/* Pre-iptables-1.4.0 */
+#include <linux/netfilter/xt_tcpudp.h>
+#define ip6t_tcp xt_tcp
+#define ip6t_udp xt_udp
+#define IP6T_TCP_INV_SRCPT XT_TCP_INV_SRCPT
+#define IP6T_TCP_INV_DSTPT XT_TCP_INV_DSTPT
+#define IP6T_TCP_INV_FLAGS XT_TCP_INV_FLAGS
+#define IP6T_TCP_INV_OPTION XT_TCP_INV_OPTION
+#define IP6T_TCP_INV_MASK XT_TCP_INV_MASK
+#define IP6T_UDP_INV_SRCPT XT_UDP_INV_SRCPT
+#define IP6T_UDP_INV_DSTPT XT_UDP_INV_DSTPT
+#define IP6T_UDP_INV_MASK XT_UDP_INV_MASK
+
+#define ip6t_counters_info xt_counters_info
+#define IP6T_STANDARD_TARGET XT_STANDARD_TARGET
+#define IP6T_ERROR_TARGET XT_ERROR_TARGET
+#define IP6T_MATCH_ITERATE(e, fn, args...) \
+ XT_MATCH_ITERATE(struct ip6t_entry, e, fn, ## args)
+#define IP6T_ENTRY_ITERATE(entries, size, fn, args...) \
+ XT_ENTRY_ITERATE(struct ip6t_entry, entries, size, fn, ## args)
+#endif
/* Yes, Virginia, you have to zero the padding. */
struct ip6t_ip6 {
@@ -62,12 +91,6 @@ struct ip6t_ip6 {
u_int8_t invflags;
};
-#define ip6t_entry_match xt_entry_match
-#define ip6t_entry_target xt_entry_target
-#define ip6t_standard_target xt_standard_target
-
-#define ip6t_counters xt_counters
-
/* Values for "flag" field in struct ip6t_ip6 (general ip6 structure). */
#define IP6T_F_PROTO 0x01 /* Set if rule cares about upper
protocols */
@@ -112,17 +135,12 @@ struct ip6t_entry {
/* Standard entry */
struct ip6t_standard {
struct ip6t_entry entry;
- struct ip6t_standard_target target;
-};
-
-struct ip6t_error_target {
- struct ip6t_entry_target target;
- char errorname[IP6T_FUNCTION_MAXNAMELEN];
+ struct xt_standard_target target;
};
struct ip6t_error {
struct ip6t_entry entry;
- struct ip6t_error_target target;
+ struct xt_error_target target;
};
#define IP6T_ENTRY_INIT(__size) \
@@ -134,16 +152,16 @@ struct ip6t_error {
#define IP6T_STANDARD_INIT(__verdict) \
{ \
.entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_standard)), \
- .target = XT_TARGET_INIT(IP6T_STANDARD_TARGET, \
- sizeof(struct ip6t_standard_target)), \
+ .target = XT_TARGET_INIT(XT_STANDARD_TARGET, \
+ sizeof(struct xt_standard_target)), \
.target.verdict = -(__verdict) - 1, \
}
#define IP6T_ERROR_INIT \
{ \
.entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_error)), \
- .target = XT_TARGET_INIT(IP6T_ERROR_TARGET, \
- sizeof(struct ip6t_error_target)), \
+ .target = XT_TARGET_INIT(XT_ERROR_TARGET, \
+ sizeof(struct xt_error_target)), \
.target.errorname = "ERROR", \
}
@@ -166,30 +184,6 @@ struct ip6t_error {
#define IP6T_SO_GET_REVISION_TARGET (IP6T_BASE_CTL + 5)
#define IP6T_SO_GET_MAX IP6T_SO_GET_REVISION_TARGET
-/* CONTINUE verdict for targets */
-#define IP6T_CONTINUE XT_CONTINUE
-
-/* For standard target */
-#define IP6T_RETURN XT_RETURN
-
-/* TCP/UDP matching stuff */
-#include <linux/netfilter/xt_tcpudp.h>
-
-#define ip6t_tcp xt_tcp
-#define ip6t_udp xt_udp
-
-/* Values for "inv" field in struct ipt_tcp. */
-#define IP6T_TCP_INV_SRCPT XT_TCP_INV_SRCPT
-#define IP6T_TCP_INV_DSTPT XT_TCP_INV_DSTPT
-#define IP6T_TCP_INV_FLAGS XT_TCP_INV_FLAGS
-#define IP6T_TCP_INV_OPTION XT_TCP_INV_OPTION
-#define IP6T_TCP_INV_MASK XT_TCP_INV_MASK
-
-/* Values for "invflags" field in struct ipt_udp. */
-#define IP6T_UDP_INV_SRCPT XT_UDP_INV_SRCPT
-#define IP6T_UDP_INV_DSTPT XT_UDP_INV_DSTPT
-#define IP6T_UDP_INV_MASK XT_UDP_INV_MASK
-
/* ICMP matching stuff */
struct ip6t_icmp {
u_int8_t type; /* type to match */
@@ -203,7 +197,7 @@ struct ip6t_icmp {
/* The argument to IP6T_SO_GET_INFO */
struct ip6t_getinfo {
/* Which table: caller fills this in. */
- char name[IP6T_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
/* Kernel fills these in. */
/* Which hook entry points are valid: bitmask */
@@ -225,7 +219,7 @@ struct ip6t_getinfo {
/* The argument to IP6T_SO_SET_REPLACE. */
struct ip6t_replace {
/* Which table. */
- char name[IP6T_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
/* Which hook entry points are valid: bitmask. You can't
change this. */
@@ -253,13 +247,10 @@ struct ip6t_replace {
struct ip6t_entry entries[0];
};
-/* The argument to IP6T_SO_ADD_COUNTERS. */
-#define ip6t_counters_info xt_counters_info
-
/* The argument to IP6T_SO_GET_ENTRIES. */
struct ip6t_get_entries {
/* Which table: user fills this in. */
- char name[IP6T_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
/* User fills this in: total entry size. */
unsigned int size;
@@ -268,28 +259,13 @@ struct ip6t_get_entries {
struct ip6t_entry entrytable[0];
};
-/* Standard return verdict, or do jump. */
-#define IP6T_STANDARD_TARGET XT_STANDARD_TARGET
-/* Error verdict. */
-#define IP6T_ERROR_TARGET XT_ERROR_TARGET
-
/* Helper functions */
-static __inline__ struct ip6t_entry_target *
+static __inline__ struct xt_entry_target *
ip6t_get_target(struct ip6t_entry *e)
{
return (void *)e + e->target_offset;
}
-#ifndef __KERNEL__
-/* fn returns 0 to continue iteration */
-#define IP6T_MATCH_ITERATE(e, fn, args...) \
- XT_MATCH_ITERATE(struct ip6t_entry, e, fn, ## args)
-
-/* fn returns 0 to continue iteration */
-#define IP6T_ENTRY_ITERATE(entries, size, fn, args...) \
- XT_ENTRY_ITERATE(struct ip6t_entry, entries, size, fn, ## args)
-#endif
-
/*
* Main firewall chains definitions and global var's definitions.
*/
@@ -316,8 +292,6 @@ extern int ip6t_ext_hdr(u8 nexthdr);
extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
int target, unsigned short *fragoff);
-#define IP6T_ALIGN(s) XT_ALIGN(s)
-
#ifdef CONFIG_COMPAT
#include <net/compat.h>
@@ -331,14 +305,12 @@ struct compat_ip6t_entry {
unsigned char elems[0];
};
-static inline struct ip6t_entry_target *
+static inline struct xt_entry_target *
compat_ip6t_get_target(struct compat_ip6t_entry *e)
{
return (void *)e + e->target_offset;
}
-#define COMPAT_IP6T_ALIGN(s) COMPAT_XT_ALIGN(s)
-
#endif /* CONFIG_COMPAT */
#endif /*__KERNEL__*/
#endif /* _IP6_TABLES_H */
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 50d8009be86c..79358bb712c6 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -14,7 +14,6 @@
struct netpoll {
struct net_device *dev;
- struct net_device *real_dev;
char dev_name[IFNAMSIZ];
const char *name;
void (*rx_hook)(struct netpoll *, int, char *, int);
@@ -53,7 +52,13 @@ void netpoll_set_trap(int trap);
void __netpoll_cleanup(struct netpoll *np);
void netpoll_cleanup(struct netpoll *np);
int __netpoll_rx(struct sk_buff *skb);
-void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb);
+void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
+ struct net_device *dev);
+static inline void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
+{
+ netpoll_send_skb_on_dev(np, skb, np->dev);
+}
+
#ifdef CONFIG_NETPOLL
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 07e40c625972..4925b22219d2 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -17,7 +17,9 @@
#define NFS4_BITMAP_SIZE 2
#define NFS4_VERIFIER_SIZE 8
-#define NFS4_STATEID_SIZE 16
+#define NFS4_STATEID_SEQID_SIZE 4
+#define NFS4_STATEID_OTHER_SIZE 12
+#define NFS4_STATEID_SIZE (NFS4_STATEID_SEQID_SIZE + NFS4_STATEID_OTHER_SIZE)
#define NFS4_FHSIZE 128
#define NFS4_MAXPATHLEN PATH_MAX
#define NFS4_MAXNAMLEN NAME_MAX
@@ -61,6 +63,9 @@
#define NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL 0x10000
#define NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED 0x20000
+#define NFS4_CDFC4_FORE 0x1
+#define NFS4_CDFC4_BACK 0x2
+
#define NFS4_SET_TO_SERVER_TIME 0
#define NFS4_SET_TO_CLIENT_TIME 1
@@ -167,7 +172,16 @@ struct nfs4_acl {
};
typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
-typedef struct { char data[NFS4_STATEID_SIZE]; } nfs4_stateid;
+
+struct nfs41_stateid {
+ __be32 seqid;
+ char other[NFS4_STATEID_OTHER_SIZE];
+} __attribute__ ((packed));
+
+typedef union {
+ char data[NFS4_STATEID_SIZE];
+ struct nfs41_stateid stateid;
+} nfs4_stateid;
enum nfs_opnum4 {
OP_ACCESS = 3,
@@ -471,6 +485,8 @@ enum lock_type4 {
#define FATTR4_WORD1_TIME_MODIFY (1UL << 21)
#define FATTR4_WORD1_TIME_MODIFY_SET (1UL << 22)
#define FATTR4_WORD1_MOUNTED_ON_FILEID (1UL << 23)
+#define FATTR4_WORD1_FS_LAYOUT_TYPES (1UL << 30)
+#define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1)
#define NFSPROC4_NULL 0
#define NFSPROC4_COMPOUND 1
@@ -532,6 +548,8 @@ enum {
NFSPROC4_CLNT_SEQUENCE,
NFSPROC4_CLNT_GET_LEASE_TIME,
NFSPROC4_CLNT_RECLAIM_COMPLETE,
+ NFSPROC4_CLNT_LAYOUTGET,
+ NFSPROC4_CLNT_GETDEVICEINFO,
};
/* nfs41 types */
@@ -550,6 +568,49 @@ enum state_protect_how4 {
SP4_SSV = 2
};
+enum pnfs_layouttype {
+ LAYOUT_NFSV4_1_FILES = 1,
+ LAYOUT_OSD2_OBJECTS = 2,
+ LAYOUT_BLOCK_VOLUME = 3,
+};
+
+/* used for both layout return and recall */
+enum pnfs_layoutreturn_type {
+ RETURN_FILE = 1,
+ RETURN_FSID = 2,
+ RETURN_ALL = 3
+};
+
+enum pnfs_iomode {
+ IOMODE_READ = 1,
+ IOMODE_RW = 2,
+ IOMODE_ANY = 3,
+};
+
+enum pnfs_notify_deviceid_type4 {
+ NOTIFY_DEVICEID4_CHANGE = 1 << 1,
+ NOTIFY_DEVICEID4_DELETE = 1 << 2,
+};
+
+#define NFL4_UFLG_MASK 0x0000003F
+#define NFL4_UFLG_DENSE 0x00000001
+#define NFL4_UFLG_COMMIT_THRU_MDS 0x00000002
+#define NFL4_UFLG_STRIPE_UNIT_SIZE_MASK 0xFFFFFFC0
+
+/* Encoded in the loh_body field of type layouthint4 */
+enum filelayout_hint_care4 {
+ NFLH4_CARE_DENSE = NFL4_UFLG_DENSE,
+ NFLH4_CARE_COMMIT_THRU_MDS = NFL4_UFLG_COMMIT_THRU_MDS,
+ NFLH4_CARE_STRIPE_UNIT_SIZE = 0x00000040,
+ NFLH4_CARE_STRIPE_COUNT = 0x00000080
+};
+
+#define NFS4_DEVICEID4_SIZE 16
+
+struct nfs4_deviceid {
+ char data[NFS4_DEVICEID4_SIZE];
+};
+
#endif
#endif
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index d0edf7d823ae..bba26684acdc 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -188,6 +188,9 @@ struct nfs_inode {
struct nfs_delegation __rcu *delegation;
fmode_t delegation_state;
struct rw_semaphore rwsem;
+
+ /* pNFS layout information */
+ struct pnfs_layout_hdr *layout;
#endif /* CONFIG_NFS_V4*/
#ifdef CONFIG_NFS_FSCACHE
struct fscache_cookie *fscache;
@@ -360,10 +363,13 @@ extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
extern void put_nfs_open_context(struct nfs_open_context *ctx);
extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode);
+extern struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred, fmode_t f_mode);
+extern void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx);
extern struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx);
extern void nfs_put_lock_context(struct nfs_lock_context *l_ctx);
extern u64 nfs_compat_user_ino64(u64 fileid);
extern void nfs_fattr_init(struct nfs_fattr *fattr);
+extern unsigned long nfs_inc_attr_generation_counter(void);
extern struct nfs_fattr *nfs_alloc_fattr(void);
@@ -379,9 +385,12 @@ static inline void nfs_free_fhandle(const struct nfs_fh *fh)
kfree(fh);
}
+/*
+ * linux/fs/nfs/nfsroot.c
+ */
+extern int nfs_root_data(char **root_device, char **root_data); /*__init*/
/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
extern __be32 root_nfs_parse_addr(char *name); /*__init*/
-extern unsigned long nfs_inc_attr_generation_counter(void);
/*
* linux/fs/nfs/file.c
@@ -479,10 +488,10 @@ extern void nfs_release_automount_timer(void);
/*
* linux/fs/nfs/unlink.c
*/
-extern int nfs_async_unlink(struct inode *dir, struct dentry *dentry);
extern void nfs_complete_unlink(struct dentry *dentry, struct inode *);
extern void nfs_block_sillyrename(struct dentry *dentry);
extern void nfs_unblock_sillyrename(struct dentry *dentry);
+extern int nfs_sillyrename(struct inode *dir, struct dentry *dentry);
/*
* linux/fs/nfs/write.c
@@ -584,10 +593,6 @@ nfs_fileid_to_ino_t(u64 fileid)
return ino;
}
-/* NFS root */
-
-extern void * nfs_root_data(void);
-
#define nfs_wait_event(clnt, wq, condition) \
({ \
int __retval = wait_event_killable(wq, condition); \
@@ -613,6 +618,8 @@ extern void * nfs_root_data(void);
#define NFSDBG_CLIENT 0x0200
#define NFSDBG_MOUNT 0x0400
#define NFSDBG_FSCACHE 0x0800
+#define NFSDBG_PNFS 0x1000
+#define NFSDBG_PNFS_LD 0x2000
#define NFSDBG_ALL 0xFFFF
#ifdef __KERNEL__
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index c82ee7cd6288..452d96436d26 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -82,6 +82,8 @@ struct nfs_client {
/* The flags used for obtaining the clientid during EXCHANGE_ID */
u32 cl_exchange_flags;
struct nfs4_session *cl_session; /* sharred session */
+ struct list_head cl_layouts;
+ struct pnfs_deviceid_cache *cl_devid_cache; /* pNFS deviceid cache */
#endif /* CONFIG_NFS_V4_1 */
#ifdef CONFIG_NFS_FSCACHE
@@ -124,6 +126,7 @@ struct nfs_server {
struct nfs_fsid fsid;
__u64 maxfilesize; /* maximum file size */
+ struct timespec time_delta; /* smallest time granularity */
unsigned long mount_time; /* when this fs was mounted */
dev_t s_dev; /* superblock dev numbers */
@@ -144,6 +147,7 @@ struct nfs_server {
u32 acl_bitmask; /* V4 bitmask representing the ACEs
that are supported on this
filesystem */
+ struct pnfs_layoutdriver_type *pnfs_curr_ld; /* Active layout driver */
#endif
void (*destroy)(struct nfs_server *);
diff --git a/include/linux/nfs_idmap.h b/include/linux/nfs_idmap.h
index 91a1c24e0cbf..e8352dc5afb5 100644
--- a/include/linux/nfs_idmap.h
+++ b/include/linux/nfs_idmap.h
@@ -66,13 +66,40 @@ struct idmap_msg {
/* Forward declaration to make this header independent of others */
struct nfs_client;
+#ifdef CONFIG_NFS_USE_NEW_IDMAPPER
+
+int nfs_idmap_init(void);
+void nfs_idmap_quit(void);
+
+static inline int nfs_idmap_new(struct nfs_client *clp)
+{
+ return 0;
+}
+
+static inline void nfs_idmap_delete(struct nfs_client *clp)
+{
+}
+
+#else /* CONFIG_NFS_USE_NEW_IDMAPPER not set */
+
+static inline int nfs_idmap_init(void)
+{
+ return 0;
+}
+
+static inline void nfs_idmap_quit(void)
+{
+}
+
int nfs_idmap_new(struct nfs_client *);
void nfs_idmap_delete(struct nfs_client *);
+#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
+
int nfs_map_name_to_uid(struct nfs_client *, const char *, size_t, __u32 *);
int nfs_map_group_to_gid(struct nfs_client *, const char *, size_t, __u32 *);
-int nfs_map_uid_to_name(struct nfs_client *, __u32, char *);
-int nfs_map_gid_to_group(struct nfs_client *, __u32, char *);
+int nfs_map_uid_to_name(struct nfs_client *, __u32, char *, size_t);
+int nfs_map_gid_to_group(struct nfs_client *, __u32, char *, size_t);
extern unsigned int nfs_idmap_cache_timeout;
#endif /* __KERNEL__ */
diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h
index 5d59ae861aa6..576bddd72e04 100644
--- a/include/linux/nfs_mount.h
+++ b/include/linux/nfs_mount.h
@@ -71,4 +71,7 @@ struct nfs_mount_data {
#define NFS_MOUNT_NORESVPORT 0x40000
#define NFS_MOUNT_LEGACY_INTERFACE 0x80000
+#define NFS_MOUNT_LOCAL_FLOCK 0x100000
+#define NFS_MOUNT_LOCAL_FCNTL 0x200000
+
#endif
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index fc461926c412..ba6cc8f223c9 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -112,7 +112,9 @@ struct nfs_fsinfo {
__u32 wtmult; /* writes should be multiple of this */
__u32 dtpref; /* pref. readdir transfer size */
__u64 maxfilesize;
+ struct timespec time_delta; /* server time granularity */
__u32 lease_time; /* in seconds */
+ __u32 layouttype; /* supported pnfs layout driver */
};
struct nfs_fsstat {
@@ -170,7 +172,7 @@ struct nfs4_sequence_args {
struct nfs4_sequence_res {
struct nfs4_session *sr_session;
- u8 sr_slotid; /* slot used to send request */
+ struct nfs4_slot *sr_slot; /* slot used to send request */
int sr_status; /* sequence operation status */
unsigned long sr_renewal_time;
u32 sr_status_flags;
@@ -185,6 +187,55 @@ struct nfs4_get_lease_time_res {
struct nfs4_sequence_res lr_seq_res;
};
+#define PNFS_LAYOUT_MAXSIZE 4096
+
+struct nfs4_layoutdriver_data {
+ __u32 len;
+ void *buf;
+};
+
+struct pnfs_layout_range {
+ u32 iomode;
+ u64 offset;
+ u64 length;
+};
+
+struct nfs4_layoutget_args {
+ __u32 type;
+ struct pnfs_layout_range range;
+ __u64 minlength;
+ __u32 maxcount;
+ struct inode *inode;
+ struct nfs_open_context *ctx;
+ struct nfs4_sequence_args seq_args;
+};
+
+struct nfs4_layoutget_res {
+ __u32 return_on_close;
+ struct pnfs_layout_range range;
+ __u32 type;
+ nfs4_stateid stateid;
+ struct nfs4_layoutdriver_data layout;
+ struct nfs4_sequence_res seq_res;
+};
+
+struct nfs4_layoutget {
+ struct nfs4_layoutget_args args;
+ struct nfs4_layoutget_res res;
+ struct pnfs_layout_segment **lsegpp;
+ int status;
+};
+
+struct nfs4_getdeviceinfo_args {
+ struct pnfs_device *pdev;
+ struct nfs4_sequence_args seq_args;
+};
+
+struct nfs4_getdeviceinfo_res {
+ struct pnfs_device *pdev;
+ struct nfs4_sequence_res seq_res;
+};
+
/*
* Arguments to the open call.
*/
@@ -400,6 +451,27 @@ struct nfs_removeres {
};
/*
+ * Common arguments to the rename call
+ */
+struct nfs_renameargs {
+ const struct nfs_fh *old_dir;
+ const struct nfs_fh *new_dir;
+ const struct qstr *old_name;
+ const struct qstr *new_name;
+ const u32 *bitmask;
+ struct nfs4_sequence_args seq_args;
+};
+
+struct nfs_renameres {
+ const struct nfs_server *server;
+ struct nfs4_change_info old_cinfo;
+ struct nfs_fattr *old_fattr;
+ struct nfs4_change_info new_cinfo;
+ struct nfs_fattr *new_fattr;
+ struct nfs4_sequence_res seq_res;
+};
+
+/*
* Argument struct for decode_entry function
*/
struct nfs_entry {
@@ -434,15 +506,6 @@ struct nfs_createargs {
struct iattr * sattr;
};
-struct nfs_renameargs {
- struct nfs_fh * fromfh;
- const char * fromname;
- unsigned int fromlen;
- struct nfs_fh * tofh;
- const char * toname;
- unsigned int tolen;
-};
-
struct nfs_setattrargs {
struct nfs_fh * fh;
nfs4_stateid stateid;
@@ -586,15 +649,6 @@ struct nfs3_mknodargs {
dev_t rdev;
};
-struct nfs3_renameargs {
- struct nfs_fh * fromfh;
- const char * fromname;
- unsigned int fromlen;
- struct nfs_fh * tofh;
- const char * toname;
- unsigned int tolen;
-};
-
struct nfs3_linkargs {
struct nfs_fh * fromfh;
struct nfs_fh * tofh;
@@ -629,11 +683,6 @@ struct nfs3_readlinkargs {
struct page ** pages;
};
-struct nfs3_renameres {
- struct nfs_fattr * fromattr;
- struct nfs_fattr * toattr;
-};
-
struct nfs3_linkres {
struct nfs_fattr * dir_attr;
struct nfs_fattr * fattr;
@@ -780,6 +829,7 @@ struct nfs4_readdir_arg {
struct page ** pages; /* zero-copy data */
unsigned int pgbase; /* zero-copy data */
const u32 * bitmask;
+ int plus;
struct nfs4_sequence_args seq_args;
};
@@ -801,24 +851,6 @@ struct nfs4_readlink_res {
struct nfs4_sequence_res seq_res;
};
-struct nfs4_rename_arg {
- const struct nfs_fh * old_dir;
- const struct nfs_fh * new_dir;
- const struct qstr * old_name;
- const struct qstr * new_name;
- const u32 * bitmask;
- struct nfs4_sequence_args seq_args;
-};
-
-struct nfs4_rename_res {
- const struct nfs_server * server;
- struct nfs4_change_info old_cinfo;
- struct nfs_fattr * old_fattr;
- struct nfs4_change_info new_cinfo;
- struct nfs_fattr * new_fattr;
- struct nfs4_sequence_res seq_res;
-};
-
#define NFS4_SETCLIENTID_NAMELEN (127)
struct nfs4_setclientid {
const nfs4_verifier * sc_verifier;
@@ -1032,19 +1064,21 @@ struct nfs_rpc_ops {
int (*readlink)(struct inode *, struct page *, unsigned int,
unsigned int);
int (*create) (struct inode *, struct dentry *,
- struct iattr *, int, struct nameidata *);
+ struct iattr *, int, struct nfs_open_context *);
int (*remove) (struct inode *, struct qstr *);
void (*unlink_setup) (struct rpc_message *, struct inode *dir);
int (*unlink_done) (struct rpc_task *, struct inode *);
int (*rename) (struct inode *, struct qstr *,
struct inode *, struct qstr *);
+ void (*rename_setup) (struct rpc_message *msg, struct inode *dir);
+ int (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir);
int (*link) (struct inode *, struct inode *, struct qstr *);
int (*symlink) (struct inode *, struct dentry *, struct page *,
unsigned int, struct iattr *);
int (*mkdir) (struct inode *, struct dentry *, struct iattr *);
int (*rmdir) (struct inode *, struct qstr *);
int (*readdir) (struct dentry *, struct rpc_cred *,
- u64, struct page *, unsigned int, int);
+ u64, struct page **, unsigned int, int);
int (*mknod) (struct inode *, struct dentry *, struct iattr *,
dev_t);
int (*statfs) (struct nfs_server *, struct nfs_fh *,
@@ -1054,7 +1088,7 @@ struct nfs_rpc_ops {
int (*pathconf) (struct nfs_server *, struct nfs_fh *,
struct nfs_pathconf *);
int (*set_capabilities)(struct nfs_server *, struct nfs_fh *);
- __be32 *(*decode_dirent)(__be32 *, struct nfs_entry *, int plus);
+ __be32 *(*decode_dirent)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int plus);
void (*read_setup) (struct nfs_read_data *, struct rpc_message *);
int (*read_done) (struct rpc_task *, struct nfs_read_data *);
void (*write_setup) (struct nfs_write_data *, struct rpc_message *);
@@ -1065,6 +1099,10 @@ struct nfs_rpc_ops {
int (*lock_check_bounds)(const struct file_lock *);
void (*clear_acl_cache)(struct inode *);
void (*close_context)(struct nfs_open_context *ctx, int);
+ struct inode * (*open_context) (struct inode *dir,
+ struct nfs_open_context *ctx,
+ int open_flags,
+ struct iattr *iattr);
};
/*
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 2c8701687336..0edb2566c14c 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -40,6 +40,43 @@
*/
/**
+ * DOC: Frame transmission/registration support
+ *
+ * Frame transmission and registration support exists to allow userspace
+ * management entities such as wpa_supplicant react to management frames
+ * that are not being handled by the kernel. This includes, for example,
+ * certain classes of action frames that cannot be handled in the kernel
+ * for various reasons.
+ *
+ * Frame registration is done on a per-interface basis and registrations
+ * cannot be removed other than by closing the socket. It is possible to
+ * specify a registration filter to register, for example, only for a
+ * certain type of action frame. In particular with action frames, those
+ * that userspace registers for will not be returned as unhandled by the
+ * driver, so that the registered application has to take responsibility
+ * for doing that.
+ *
+ * The type of frame that can be registered for is also dependent on the
+ * driver and interface type. The frame types are advertised in wiphy
+ * attributes so applications know what to expect.
+ *
+ * NOTE: When an interface changes type while registrations are active,
+ * these registrations are ignored until the interface type is
+ * changed again. This means that changing the interface type can
+ * lead to a situation that couldn't otherwise be produced, but
+ * any such registrations will be dormant in the sense that they
+ * will not be serviced, i.e. they will not receive any frames.
+ *
+ * Frame transmission allows userspace to send for example the required
+ * responses to action frames. It is subject to some sanity checking,
+ * but many frames can be transmitted. When a frame was transmitted, its
+ * status is indicated to the sending socket.
+ *
+ * For more technical details, see the corresponding command descriptions
+ * below.
+ */
+
+/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -258,7 +295,9 @@
* auth and assoc steps. For this, you need to specify the SSID in a
* %NL80211_ATTR_SSID attribute, and can optionally specify the association
* IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
- * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_CONTROL_PORT.
+ * %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
+ * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
* It is also sent as an event, with the BSSID and response IEs when the
* connection is established or failed to be established. This can be
* determined by the STATUS_CODE attribute.
@@ -276,8 +315,8 @@
* channel for the specified amount of time. This can be used to do
* off-channel operations like transmit a Public Action frame and wait for
* a response while being associated to an AP on another channel.
- * %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify which
- * radio is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
+ * %NL80211_ATTR_IFINDEX is used to specify which interface (and thus
+ * radio) is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
* frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be
* optionally used to specify additional channel parameters.
* %NL80211_ATTR_DURATION is used to specify the duration in milliseconds
@@ -301,16 +340,20 @@
* rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface
* and @NL80211_ATTR_TX_RATES the set of allowed rates.
*
- * @NL80211_CMD_REGISTER_ACTION: Register for receiving certain action frames
- * (via @NL80211_CMD_ACTION) for processing in userspace. This command
- * requires an interface index and a match attribute containing the first
- * few bytes of the frame that should match, e.g. a single byte for only
- * a category match or four bytes for vendor frames including the OUI.
- * The registration cannot be dropped, but is removed automatically
- * when the netlink socket is closed. Multiple registrations can be made.
- * @NL80211_CMD_ACTION: Action frame TX request and RX notification. This
- * command is used both as a request to transmit an Action frame and as an
- * event indicating reception of an Action frame that was not processed in
+ * @NL80211_CMD_REGISTER_FRAME: Register for receiving certain mgmt frames
+ * (via @NL80211_CMD_FRAME) for processing in userspace. This command
+ * requires an interface index, a frame type attribute (optional for
+ * backward compatibility reasons, if not given assumes action frames)
+ * and a match attribute containing the first few bytes of the frame
+ * that should match, e.g. a single byte for only a category match or
+ * four bytes for vendor frames including the OUI. The registration
+ * cannot be dropped, but is removed automatically when the netlink
+ * socket is closed. Multiple registrations can be made.
+ * @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for
+ * backward compatibility
+ * @NL80211_CMD_FRAME: Management frame TX request and RX notification. This
+ * command is used both as a request to transmit a management frame and
+ * as an event indicating reception of a frame that was not processed in
* kernel code, but is for us (i.e., which may need to be processed in a
* user space application). %NL80211_ATTR_FRAME is used to specify the
* frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and
@@ -320,11 +363,14 @@
* operational channel). 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_CMD_ACTION_TX_STATUS: Report TX status of an Action frame
- * transmitted with %NL80211_CMD_ACTION. %NL80211_ATTR_COOKIE identifies
+ * @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility.
+ * @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame
+ * transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies
* the TX command and %NL80211_ATTR_FRAME includes the contents of the
* frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
* the frame.
+ * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for
+ * backward compatibility.
* @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command
* is used to configure connection quality monitoring notification trigger
* levels.
@@ -341,6 +387,8 @@
* of any other interfaces, and other interfaces will again take
* precedence when they are used.
*
+ * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -429,9 +477,12 @@ enum nl80211_commands {
NL80211_CMD_SET_TX_BITRATE_MASK,
- NL80211_CMD_REGISTER_ACTION,
- NL80211_CMD_ACTION,
- NL80211_CMD_ACTION_TX_STATUS,
+ NL80211_CMD_REGISTER_FRAME,
+ NL80211_CMD_REGISTER_ACTION = NL80211_CMD_REGISTER_FRAME,
+ NL80211_CMD_FRAME,
+ NL80211_CMD_ACTION = NL80211_CMD_FRAME,
+ NL80211_CMD_FRAME_TX_STATUS,
+ NL80211_CMD_ACTION_TX_STATUS = NL80211_CMD_FRAME_TX_STATUS,
NL80211_CMD_SET_POWER_SAVE,
NL80211_CMD_GET_POWER_SAVE,
@@ -440,6 +491,7 @@ enum nl80211_commands {
NL80211_CMD_NOTIFY_CQM,
NL80211_CMD_SET_CHANNEL,
+ NL80211_CMD_SET_WDS_PEER,
/* add new commands above here */
@@ -639,6 +691,15 @@ enum nl80211_commands {
* request, the driver will assume that the port is unauthorized until
* authorized by user space. Otherwise, port is marked authorized by
* default in station mode.
+ * @NL80211_ATTR_CONTROL_PORT_ETHERTYPE: A 16-bit value indicating the
+ * ethertype that will be used for key negotiation. It can be
+ * specified with the associate and connect commands. If it is not
+ * specified, the value defaults to 0x888E (PAE, 802.1X). This
+ * attribute is also used as a flag in the wiphy information to
+ * indicate that protocols other than PAE are supported.
+ * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with
+ * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom
+ * ethertype frames used for key negotiation must not be encrypted.
*
* @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
* We recommend using nested, driver-specific attributes within this.
@@ -708,7 +769,16 @@ enum nl80211_commands {
* is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
*
* @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
- * at least one byte, currently used with @NL80211_CMD_REGISTER_ACTION.
+ * at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME.
+ * @NL80211_ATTR_FRAME_TYPE: A u16 indicating the frame type/subtype for the
+ * @NL80211_CMD_REGISTER_FRAME command.
+ * @NL80211_ATTR_TX_FRAME_TYPES: wiphy capability attribute, which is a
+ * nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing
+ * information about which frame types can be transmitted with
+ * %NL80211_CMD_FRAME.
+ * @NL80211_ATTR_RX_FRAME_TYPES: wiphy capability attribute, which is a
+ * nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing
+ * information about which frame types can be registered for RX.
*
* @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
* acknowledged by the recipient.
@@ -731,6 +801,9 @@ enum nl80211_commands {
* This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING
* for non-automatic settings.
*
+ * @NL80211_ATTR_SUPPORT_IBSS_RSN: The device supports IBSS RSN, which mostly
+ * means support for per-station GTKs.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -891,6 +964,15 @@ enum nl80211_attrs {
NL80211_ATTR_WIPHY_TX_POWER_SETTING,
NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
+ NL80211_ATTR_TX_FRAME_TYPES,
+ NL80211_ATTR_RX_FRAME_TYPES,
+ NL80211_ATTR_FRAME_TYPE,
+
+ NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+ NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
+
+ NL80211_ATTR_SUPPORT_IBSS_RSN,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -946,8 +1028,10 @@ enum nl80211_attrs {
* @NL80211_IFTYPE_WDS: wireless distribution interface
* @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
* @NL80211_IFTYPE_MESH_POINT: mesh point
+ * @NL80211_IFTYPE_P2P_CLIENT: P2P client
+ * @NL80211_IFTYPE_P2P_GO: P2P group owner
* @NL80211_IFTYPE_MAX: highest interface type number currently defined
- * @__NL80211_IFTYPE_AFTER_LAST: internal use
+ * @NUM_NL80211_IFTYPES: number of defined interface types
*
* These values are used with the %NL80211_ATTR_IFTYPE
* to set the type of an interface.
@@ -962,10 +1046,12 @@ enum nl80211_iftype {
NL80211_IFTYPE_WDS,
NL80211_IFTYPE_MONITOR,
NL80211_IFTYPE_MESH_POINT,
+ NL80211_IFTYPE_P2P_CLIENT,
+ NL80211_IFTYPE_P2P_GO,
/* keep last */
- __NL80211_IFTYPE_AFTER_LAST,
- NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
+ NUM_NL80211_IFTYPES,
+ NL80211_IFTYPE_MAX = NUM_NL80211_IFTYPES - 1
};
/**
@@ -974,11 +1060,14 @@ enum nl80211_iftype {
* Station flags. When a station is added to an AP interface, it is
* assumed to be already associated (and hence authenticated.)
*
+ * @__NL80211_STA_FLAG_INVALID: attribute number 0 is reserved
* @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
* @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
* with short barker preamble
* @NL80211_STA_FLAG_WME: station is WME/QoS capable
* @NL80211_STA_FLAG_MFP: station uses management frame protection
+ * @NL80211_STA_FLAG_MAX: highest station flag number currently defined
+ * @__NL80211_STA_FLAG_AFTER_LAST: internal use
*/
enum nl80211_sta_flags {
__NL80211_STA_FLAG_INVALID,
@@ -1048,6 +1137,8 @@ enum nl80211_rate_info {
* @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
* @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
* station)
+ * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station)
+ * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station)
*/
enum nl80211_sta_info {
__NL80211_STA_INFO_INVALID,
@@ -1061,6 +1152,8 @@ enum nl80211_sta_info {
NL80211_STA_INFO_TX_BITRATE,
NL80211_STA_INFO_RX_PACKETS,
NL80211_STA_INFO_TX_PACKETS,
+ NL80211_STA_INFO_TX_RETRIES,
+ NL80211_STA_INFO_TX_FAILED,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -1091,14 +1184,17 @@ enum nl80211_mpath_flags {
* information about a mesh path.
*
* @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved
- * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination
- * @NL80211_ATTR_MPATH_SN: destination sequence number
- * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path
- * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now
- * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in
+ * @NL80211_MPATH_INFO_FRAME_QLEN: number of queued frames for this destination
+ * @NL80211_MPATH_INFO_SN: destination sequence number
+ * @NL80211_MPATH_INFO_METRIC: metric (cost) of this mesh path
+ * @NL80211_MPATH_INFO_EXPTIME: expiration time for the path, in msec from now
+ * @NL80211_MPATH_INFO_FLAGS: mesh path flags, enumerated in
* &enum nl80211_mpath_flags;
- * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
- * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries
+ * @NL80211_MPATH_INFO_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
+ * @NL80211_MPATH_INFO_DISCOVERY_RETRIES: mesh path discovery retries
+ * @NL80211_MPATH_INFO_MAX: highest mesh path information attribute number
+ * currently defind
+ * @__NL80211_MPATH_INFO_AFTER_LAST: internal use
*/
enum nl80211_mpath_info {
__NL80211_MPATH_INFO_INVALID,
@@ -1127,6 +1223,8 @@ enum nl80211_mpath_info {
* @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE
* @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n
* @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n
+ * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
+ * @__NL80211_BAND_ATTR_AFTER_LAST: internal use
*/
enum nl80211_band_attr {
__NL80211_BAND_ATTR_INVALID,
@@ -1147,6 +1245,7 @@ enum nl80211_band_attr {
/**
* enum nl80211_frequency_attr - frequency attributes
+ * @__NL80211_FREQUENCY_ATTR_INVALID: attribute number 0 is reserved
* @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
* @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
* regulatory domain.
@@ -1158,6 +1257,9 @@ enum nl80211_band_attr {
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
* (100 * dBm).
+ * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
+ * currently defined
+ * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
*/
enum nl80211_frequency_attr {
__NL80211_FREQUENCY_ATTR_INVALID,
@@ -1177,9 +1279,13 @@ enum nl80211_frequency_attr {
/**
* enum nl80211_bitrate_attr - bitrate attributes
+ * @__NL80211_BITRATE_ATTR_INVALID: attribute number 0 is reserved
* @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
* @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported
* in 2.4 GHz band.
+ * @NL80211_BITRATE_ATTR_MAX: highest bitrate attribute number
+ * currently defined
+ * @__NL80211_BITRATE_ATTR_AFTER_LAST: internal use
*/
enum nl80211_bitrate_attr {
__NL80211_BITRATE_ATTR_INVALID,
@@ -1235,6 +1341,7 @@ enum nl80211_reg_type {
/**
* enum nl80211_reg_rule_attr - regulatory rule attributes
+ * @__NL80211_REG_RULE_ATTR_INVALID: attribute number 0 is reserved
* @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional
* considerations for a given frequency range. These are the
* &enum nl80211_reg_rule_flags.
@@ -1251,6 +1358,9 @@ enum nl80211_reg_type {
* If you don't have one then don't send this.
* @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
* a given frequency range. The value is in mBm (100 * dBm).
+ * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number
+ * currently defined
+ * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use
*/
enum nl80211_reg_rule_attr {
__NL80211_REG_RULE_ATTR_INVALID,
@@ -1302,11 +1412,31 @@ enum nl80211_reg_rule_flags {
* @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved
* @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
* @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
+ * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio
+ * spent on this channel
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary
+ * channel was sensed busy (either due to activity or energy detect)
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: amount of time the extension
+ * channel was sensed busy
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent
+ * receiving data
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent
+ * transmitting data
+ * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
+ * currently defined
+ * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
*/
enum nl80211_survey_info {
__NL80211_SURVEY_INFO_INVALID,
NL80211_SURVEY_INFO_FREQUENCY,
NL80211_SURVEY_INFO_NOISE,
+ NL80211_SURVEY_INFO_IN_USE,
+ NL80211_SURVEY_INFO_CHANNEL_TIME,
+ NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
+ NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
+ NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
+ NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
/* keep last */
__NL80211_SURVEY_INFO_AFTER_LAST,
@@ -1466,6 +1596,7 @@ enum nl80211_channel_type {
* enum nl80211_bss - netlink attributes for a BSS
*
* @__NL80211_BSS_INVALID: invalid
+ * @NL80211_BSS_BSSID: BSSID of the BSS (6 octets)
* @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
* @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
* @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
@@ -1509,6 +1640,12 @@ enum nl80211_bss {
/**
* enum nl80211_bss_status - BSS "status"
+ * @NL80211_BSS_STATUS_AUTHENTICATED: Authenticated with this BSS.
+ * @NL80211_BSS_STATUS_ASSOCIATED: Associated with this BSS.
+ * @NL80211_BSS_STATUS_IBSS_JOINED: Joined to this IBSS.
+ *
+ * The BSS status is a BSS attribute in scan dumps, which
+ * indicates the status the interface has wrt. this BSS.
*/
enum nl80211_bss_status {
NL80211_BSS_STATUS_AUTHENTICATED,
@@ -1546,11 +1683,14 @@ enum nl80211_auth_type {
* @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
* @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
* @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
+ * @NUM_NL80211_KEYTYPES: number of defined key types
*/
enum nl80211_key_type {
NL80211_KEYTYPE_GROUP,
NL80211_KEYTYPE_PAIRWISE,
NL80211_KEYTYPE_PEERKEY,
+
+ NUM_NL80211_KEYTYPES
};
/**
@@ -1581,6 +1721,9 @@ enum nl80211_wpa_versions {
* CCMP keys, each six bytes in little endian
* @NL80211_KEY_DEFAULT: flag indicating default key
* @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
+ * @NL80211_KEY_TYPE: the key type from enum nl80211_key_type, if not
+ * specified the default depends on whether a MAC address was
+ * given with the command using the key or not (u32)
* @__NL80211_KEY_AFTER_LAST: internal
* @NL80211_KEY_MAX: highest key attribute
*/
@@ -1592,6 +1735,7 @@ enum nl80211_key_attributes {
NL80211_KEY_SEQ,
NL80211_KEY_DEFAULT,
NL80211_KEY_DEFAULT_MGMT,
+ NL80211_KEY_TYPE,
/* keep last */
__NL80211_KEY_AFTER_LAST,
@@ -1619,8 +1763,8 @@ enum nl80211_tx_rate_attributes {
/**
* enum nl80211_band - Frequency band
- * @NL80211_BAND_2GHZ - 2.4 GHz ISM band
- * @NL80211_BAND_5GHZ - around 5 GHz band (4.9 - 5.7 GHz)
+ * @NL80211_BAND_2GHZ: 2.4 GHz ISM band
+ * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
*/
enum nl80211_band {
NL80211_BAND_2GHZ,
@@ -1658,9 +1802,9 @@ enum nl80211_attr_cqm {
/**
* enum nl80211_cqm_rssi_threshold_event - RSSI threshold event
- * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW - The RSSI level is lower than the
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW: The RSSI level is lower than the
* configured threshold
- * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH - The RSSI is higher than the
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
* configured threshold
*/
enum nl80211_cqm_rssi_threshold_event {
diff --git a/include/linux/of_device.h b/include/linux/of_device.h
index 835f85ecd2de..975d347079d9 100644
--- a/include/linux/of_device.h
+++ b/include/linux/of_device.h
@@ -27,20 +27,19 @@ static inline int of_driver_match_device(const struct device *dev,
extern struct platform_device *of_dev_get(struct platform_device *dev);
extern void of_dev_put(struct platform_device *dev);
+extern int of_device_add(struct platform_device *pdev);
extern int of_device_register(struct platform_device *ofdev);
extern void of_device_unregister(struct platform_device *ofdev);
-extern void of_release_dev(struct device *dev);
-
-static inline void of_device_free(struct platform_device *dev)
-{
- of_release_dev(&dev->dev);
-}
extern ssize_t of_device_get_modalias(struct device *dev,
char *str, ssize_t len);
extern int of_device_uevent(struct device *dev, struct kobj_uevent_env *env);
+static inline void of_device_node_put(struct device *dev)
+{
+ of_node_put(dev->of_node);
+}
#else /* CONFIG_OF_DEVICE */
@@ -56,6 +55,8 @@ static inline int of_device_uevent(struct device *dev,
return -ENODEV;
}
+static inline void of_device_node_put(struct device *dev) { }
+
#endif /* CONFIG_OF_DEVICE */
#endif /* _LINUX_OF_DEVICE_H */
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index 71e1a916d3fa..7bbf5b328438 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -72,7 +72,7 @@ extern void *of_get_flat_dt_prop(unsigned long node, const char *name,
unsigned long *size);
extern int of_flat_dt_is_compatible(unsigned long node, const char *name);
extern unsigned long of_get_flat_dt_root(void);
-extern void early_init_dt_scan_chosen_arch(unsigned long node);
+
extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
int depth, void *data);
extern void early_init_dt_check_for_initrd(unsigned long node);
diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
index 5929781c104d..109e013b1772 100644
--- a/include/linux/of_irq.h
+++ b/include/linux/of_irq.h
@@ -5,6 +5,7 @@
struct of_irq;
#include <linux/types.h>
#include <linux/errno.h>
+#include <linux/irq.h>
#include <linux/ioport.h>
#include <linux/of.h>
@@ -64,6 +65,9 @@ extern unsigned int irq_create_of_mapping(struct device_node *controller,
unsigned int intsize);
extern int of_irq_to_resource(struct device_node *dev, int index,
struct resource *r);
+extern int of_irq_count(struct device_node *dev);
+extern int of_irq_to_resource_table(struct device_node *dev,
+ struct resource *res, int nr_irqs);
#endif /* CONFIG_OF_IRQ */
#endif /* CONFIG_OF */
diff --git a/include/linux/of_pdt.h b/include/linux/of_pdt.h
new file mode 100644
index 000000000000..c65a18a0cfdf
--- /dev/null
+++ b/include/linux/of_pdt.h
@@ -0,0 +1,45 @@
+/*
+ * Definitions for building a device tree by calling into the
+ * Open Firmware PROM.
+ *
+ * Copyright (C) 2010 Andres Salomon <dilinger@queued.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_OF_PDT_H
+#define _LINUX_OF_PDT_H
+
+/* overridable operations for calling into the PROM */
+struct of_pdt_ops {
+ /*
+ * buf should be 32 bytes; return 0 on success.
+ * If prev is NULL, the first property will be returned.
+ */
+ int (*nextprop)(phandle node, char *prev, char *buf);
+
+ /* for both functions, return proplen on success; -1 on error */
+ int (*getproplen)(phandle node, const char *prop);
+ int (*getproperty)(phandle node, const char *prop, char *buf,
+ int bufsize);
+
+ /* phandles are 0 if no child or sibling exists */
+ phandle (*getchild)(phandle parent);
+ phandle (*getsibling)(phandle node);
+
+ /* return 0 on success; fill in 'len' with number of bytes in path */
+ int (*pkg2path)(phandle node, char *buf, const int buflen, int *len);
+};
+
+extern void *prom_early_alloc(unsigned long size);
+
+/* for building the device tree */
+extern void of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops);
+
+extern void (*of_pdt_build_more)(struct device_node *dp,
+ struct device_node ***nextp);
+
+#endif /* _LINUX_OF_PDT_H */
diff --git a/include/linux/padata.h b/include/linux/padata.h
index bdcd1e9eacea..4633b2f726b6 100644
--- a/include/linux/padata.h
+++ b/include/linux/padata.h
@@ -127,8 +127,8 @@ struct padata_cpumask {
*/
struct parallel_data {
struct padata_instance *pinst;
- struct padata_parallel_queue *pqueue;
- struct padata_serial_queue *squeue;
+ struct padata_parallel_queue __percpu *pqueue;
+ struct padata_serial_queue __percpu *squeue;
atomic_t seq_nr;
atomic_t reorder_objects;
atomic_t refcnt;
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 6fa317801e1c..5f38c460367e 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -310,7 +310,7 @@ static inline void SetPageUptodate(struct page *page)
{
#ifdef CONFIG_S390
if (!test_and_set_bit(PG_uptodate, &page->flags))
- page_clear_dirty(page);
+ page_clear_dirty(page, 0);
#else
/*
* Memory barrier must be issued before setting the PG_uptodate bit,
diff --git a/include/linux/pageblock-flags.h b/include/linux/pageblock-flags.h
index e8c06122be36..19ef95d293ae 100644
--- a/include/linux/pageblock-flags.h
+++ b/include/linux/pageblock-flags.h
@@ -67,7 +67,8 @@ void set_pageblock_flags_group(struct page *page, unsigned long flags,
#define get_pageblock_flags(page) \
get_pageblock_flags_group(page, 0, NR_PAGEBLOCK_BITS-1)
-#define set_pageblock_flags(page) \
- set_pageblock_flags_group(page, 0, NR_PAGEBLOCK_BITS-1)
+#define set_pageblock_flags(page, flags) \
+ set_pageblock_flags_group(page, flags, \
+ 0, NR_PAGEBLOCK_BITS-1)
#endif /* PAGEBLOCK_FLAGS_H */
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index e12cdc6d79ee..2d1ffe3cf1ee 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -299,6 +299,8 @@ static inline pgoff_t linear_page_index(struct vm_area_struct *vma,
extern void __lock_page(struct page *page);
extern int __lock_page_killable(struct page *page);
extern void __lock_page_nosync(struct page *page);
+extern int __lock_page_or_retry(struct page *page, struct mm_struct *mm,
+ unsigned int flags);
extern void unlock_page(struct page *page);
static inline void __set_page_locked(struct page *page)
@@ -351,6 +353,17 @@ static inline void lock_page_nosync(struct page *page)
}
/*
+ * lock_page_or_retry - Lock the page, unless this would block and the
+ * caller indicated that it can handle a retry.
+ */
+static inline int lock_page_or_retry(struct page *page, struct mm_struct *mm,
+ unsigned int flags)
+{
+ might_sleep();
+ return trylock_page(page) || __lock_page_or_retry(page, mm, flags);
+}
+
+/*
* This is exported only for wait_on_page_locked/wait_on_page_writeback.
* Never use this directly!
*/
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 1196d429f182..30d91838a198 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -820,7 +820,7 @@
#define PCI_VENDOR_ID_ANIGMA 0x1051
#define PCI_DEVICE_ID_ANIGMA_MC145575 0x0100
-
+
#define PCI_VENDOR_ID_EFAR 0x1055
#define PCI_DEVICE_ID_EFAR_SLC90E66_1 0x9130
#define PCI_DEVICE_ID_EFAR_SLC90E66_3 0x9463
@@ -1451,7 +1451,7 @@
#define PCI_VENDOR_ID_ZIATECH 0x1138
#define PCI_DEVICE_ID_ZIATECH_5550_HC 0x5550
-
+
#define PCI_VENDOR_ID_SYSKONNECT 0x1148
#define PCI_DEVICE_ID_SYSKONNECT_TR 0x4200
@@ -1605,8 +1605,8 @@
#define PCI_DEVICE_ID_RP8OCTA 0x0005
#define PCI_DEVICE_ID_RP8J 0x0006
#define PCI_DEVICE_ID_RP4J 0x0007
-#define PCI_DEVICE_ID_RP8SNI 0x0008
-#define PCI_DEVICE_ID_RP16SNI 0x0009
+#define PCI_DEVICE_ID_RP8SNI 0x0008
+#define PCI_DEVICE_ID_RP16SNI 0x0009
#define PCI_DEVICE_ID_RPP4 0x000A
#define PCI_DEVICE_ID_RPP8 0x000B
#define PCI_DEVICE_ID_RP4M 0x000D
@@ -1616,9 +1616,9 @@
#define PCI_DEVICE_ID_URP8INTF 0x0802
#define PCI_DEVICE_ID_URP16INTF 0x0803
#define PCI_DEVICE_ID_URP8OCTA 0x0805
-#define PCI_DEVICE_ID_UPCI_RM3_8PORT 0x080C
+#define PCI_DEVICE_ID_UPCI_RM3_8PORT 0x080C
#define PCI_DEVICE_ID_UPCI_RM3_4PORT 0x080D
-#define PCI_DEVICE_ID_CRP16INTF 0x0903
+#define PCI_DEVICE_ID_CRP16INTF 0x0903
#define PCI_VENDOR_ID_CYCLADES 0x120e
#define PCI_DEVICE_ID_CYCLOM_Y_Lo 0x0100
@@ -2144,7 +2144,7 @@
#define PCI_DEVICE_ID_RASTEL_2PORT 0x2000
#define PCI_VENDOR_ID_ZOLTRIX 0x15b0
-#define PCI_DEVICE_ID_ZOLTRIX_2BD0 0x2bd0
+#define PCI_DEVICE_ID_ZOLTRIX_2BD0 0x2bd0
#define PCI_VENDOR_ID_MELLANOX 0x15b3
#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44
@@ -2194,6 +2194,9 @@
#define PCI_VENDOR_ID_ARIMA 0x161f
#define PCI_VENDOR_ID_BROCADE 0x1657
+#define PCI_DEVICE_ID_BROCADE_CT 0x0014
+#define PCI_DEVICE_ID_BROCADE_FC_8G1P 0x0017
+#define PCI_DEVICE_ID_BROCADE_CT_FC 0x0021
#define PCI_VENDOR_ID_SIBYTE 0x166d
#define PCI_DEVICE_ID_BCM1250_PCI 0x0001
@@ -2265,6 +2268,13 @@
#define PCI_VENDOR_ID_SILAN 0x1904
+#define PCI_VENDOR_ID_RENESAS 0x1912
+#define PCI_DEVICE_ID_RENESAS_SH7781 0x0001
+#define PCI_DEVICE_ID_RENESAS_SH7780 0x0002
+#define PCI_DEVICE_ID_RENESAS_SH7763 0x0004
+#define PCI_DEVICE_ID_RENESAS_SH7785 0x0007
+#define PCI_DEVICE_ID_RENESAS_SH7786 0x0010
+
#define PCI_VENDOR_ID_TDI 0x192E
#define PCI_DEVICE_ID_TDI_EHCI 0x0101
@@ -2435,7 +2445,7 @@
#define PCI_DEVICE_ID_INTEL_82815_MC 0x1130
#define PCI_DEVICE_ID_INTEL_82815_CGC 0x1132
#define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221
-#define PCI_DEVICE_ID_INTEL_7505_0 0x2550
+#define PCI_DEVICE_ID_INTEL_7505_0 0x2550
#define PCI_DEVICE_ID_INTEL_7205_0 0x255d
#define PCI_DEVICE_ID_INTEL_82437 0x122d
#define PCI_DEVICE_ID_INTEL_82371FB_0 0x122e
@@ -2638,6 +2648,9 @@
#define PCI_DEVICE_ID_INTEL_MCH_PC 0x3599
#define PCI_DEVICE_ID_INTEL_MCH_PC1 0x359a
#define PCI_DEVICE_ID_INTEL_E7525_MCH 0x359e
+#define PCI_DEVICE_ID_INTEL_I7300_MCH_ERR 0x360c
+#define PCI_DEVICE_ID_INTEL_I7300_MCH_FB0 0x360f
+#define PCI_DEVICE_ID_INTEL_I7300_MCH_FB1 0x3610
#define PCI_DEVICE_ID_INTEL_IOAT_CNB 0x360b
#define PCI_DEVICE_ID_INTEL_FBD_CNB 0x360c
#define PCI_DEVICE_ID_INTEL_IOAT_JSF0 0x3710
diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h
index 018db9a62ffe..27ef6b190ea6 100644
--- a/include/linux/percpu-defs.h
+++ b/include/linux/percpu-defs.h
@@ -148,18 +148,6 @@
DEFINE_PER_CPU_SECTION(type, name, "..readmostly")
/*
- * Declaration/definition used for large per-CPU variables that must be
- * aligned to something larger than the pagesize.
- */
-#define DECLARE_PER_CPU_MULTIPAGE_ALIGNED(type, name, size) \
- DECLARE_PER_CPU_SECTION(type, name, "..page_aligned") \
- __aligned(size)
-
-#define DEFINE_PER_CPU_MULTIPAGE_ALIGNED(type, name, size) \
- DEFINE_PER_CPU_SECTION(type, name, "..page_aligned") \
- __aligned(size)
-
-/*
* Intermodule exports for per-CPU variables. sparse forgets about
* address space across EXPORT_SYMBOL(), change EXPORT_SYMBOL() to
* noop if __CHECKER__.
diff --git a/include/linux/percpu_counter.h b/include/linux/percpu_counter.h
index 8a7d510ffa9c..46f6ba56fa91 100644
--- a/include/linux/percpu_counter.h
+++ b/include/linux/percpu_counter.h
@@ -78,6 +78,11 @@ static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
return 1;
}
+static inline int percpu_counter_initialized(struct percpu_counter *fbc)
+{
+ return (fbc->counters != NULL);
+}
+
#else
struct percpu_counter {
@@ -143,6 +148,11 @@ static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
return percpu_counter_read(fbc);
}
+static inline int percpu_counter_initialized(struct percpu_counter *fbc)
+{
+ return 1;
+}
+
#endif /* CONFIG_SMP */
static inline void percpu_counter_inc(struct percpu_counter *fbc)
diff --git a/include/linux/phonet.h b/include/linux/phonet.h
index 76edadf046d3..26c8df786918 100644
--- a/include/linux/phonet.h
+++ b/include/linux/phonet.h
@@ -36,6 +36,9 @@
/* Socket options for SOL_PNPIPE level */
#define PNPIPE_ENCAP 1
#define PNPIPE_IFINDEX 2
+#define PNPIPE_PIPE_HANDLE 3
+#define PNPIPE_ENABLE 4
+/* unused slot */
#define PNADDR_ANY 0
#define PNADDR_BROADCAST 0xFC
@@ -47,6 +50,8 @@
/* ioctls */
#define SIOCPNGETOBJECT (SIOCPROTOPRIVATE + 0)
+#define SIOCPNADDRESOURCE (SIOCPROTOPRIVATE + 14)
+#define SIOCPNDELRESOURCE (SIOCPROTOPRIVATE + 15)
/* Phonet protocol header */
struct phonethdr {
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 6b0a782c6224..7da5fa845959 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -116,7 +116,7 @@ struct mii_bus {
/* list of all PHYs on bus */
struct phy_device *phy_map[PHY_MAX_ADDR];
- /* Phy addresses to be ignored when probing */
+ /* PHY addresses to be ignored when probing */
u32 phy_mask;
/*
@@ -283,7 +283,7 @@ struct phy_device {
phy_interface_t interface;
- /* Bus address of the PHY (0-32) */
+ /* Bus address of the PHY (0-31) */
int addr;
/*
@@ -472,11 +472,7 @@ static inline int phy_write(struct phy_device *phydev, u32 regnum, u16 val)
int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id);
struct phy_device* get_phy_device(struct mii_bus *bus, int addr);
int phy_device_register(struct phy_device *phy);
-int phy_clear_interrupt(struct phy_device *phydev);
-int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
int phy_init_hw(struct phy_device *phydev);
-int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
- u32 flags, phy_interface_t interface);
struct phy_device * phy_attach(struct net_device *dev,
const char *bus_id, u32 flags, phy_interface_t interface);
struct phy_device *phy_find_first(struct mii_bus *bus);
@@ -492,17 +488,12 @@ void phy_start(struct phy_device *phydev);
void phy_stop(struct phy_device *phydev);
int phy_start_aneg(struct phy_device *phydev);
-void phy_sanitize_settings(struct phy_device *phydev);
int phy_stop_interrupts(struct phy_device *phydev);
-int phy_enable_interrupts(struct phy_device *phydev);
-int phy_disable_interrupts(struct phy_device *phydev);
static inline int phy_read_status(struct phy_device *phydev) {
return phydev->drv->read_status(phydev);
}
-int genphy_config_advert(struct phy_device *phydev);
-int genphy_setup_forced(struct phy_device *phydev);
int genphy_restart_aneg(struct phy_device *phydev);
int genphy_config_aneg(struct phy_device *phydev);
int genphy_update_link(struct phy_device *phydev);
@@ -511,8 +502,6 @@ int genphy_suspend(struct phy_device *phydev);
int genphy_resume(struct phy_device *phydev);
void phy_driver_unregister(struct phy_driver *drv);
int phy_driver_register(struct phy_driver *new_driver);
-void phy_prepare_link(struct phy_device *phydev,
- void (*adjust_link)(struct net_device *));
void phy_state_machine(struct work_struct *work);
void phy_start_machine(struct phy_device *phydev,
void (*handler)(struct net_device *));
@@ -523,7 +512,6 @@ int phy_mii_ioctl(struct phy_device *phydev,
struct ifreq *ifr, int cmd);
int phy_start_interrupts(struct phy_device *phydev);
void phy_print_status(struct phy_device *phydev);
-struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id);
void phy_device_free(struct phy_device *phydev);
int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask,
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
index 7f6ba8658abe..defbde203d07 100644
--- a/include/linux/pkt_cls.h
+++ b/include/linux/pkt_cls.h
@@ -332,6 +332,7 @@ enum {
FLOW_KEY_SKUID,
FLOW_KEY_SKGID,
FLOW_KEY_VLAN_TAG,
+ FLOW_KEY_RXHASH,
__FLOW_KEY_MAX,
};
diff --git a/include/linux/poll.h b/include/linux/poll.h
index 600cc1fde64d..56e76af78102 100644
--- a/include/linux/poll.h
+++ b/include/linux/poll.h
@@ -73,6 +73,8 @@ extern void poll_initwait(struct poll_wqueues *pwq);
extern void poll_freewait(struct poll_wqueues *pwq);
extern int poll_schedule_timeout(struct poll_wqueues *pwq, int state,
ktime_t *expires, unsigned long slack);
+extern long select_estimate_accuracy(struct timespec *tv);
+
static inline int poll_schedule(struct poll_wqueues *pwq, int state)
{
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 30083a896f36..7d7325685c42 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -89,6 +89,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG,
POWER_SUPPLY_PROP_POWER_NOW,
@@ -125,7 +126,10 @@ enum power_supply_type {
POWER_SUPPLY_TYPE_BATTERY = 0,
POWER_SUPPLY_TYPE_UPS,
POWER_SUPPLY_TYPE_MAINS,
- POWER_SUPPLY_TYPE_USB,
+ POWER_SUPPLY_TYPE_USB, /* Standard Downstream Port */
+ POWER_SUPPLY_TYPE_USB_DCP, /* Dedicated Charging Port */
+ POWER_SUPPLY_TYPE_USB_CDP, /* Charging Downstream Port */
+ POWER_SUPPLY_TYPE_USB_ACA, /* Accessory Charger Adapters */
};
union power_supply_propval {
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index 4272521e29e9..092a04f874a8 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -100,7 +100,8 @@
#include <linux/sched.h> /* For struct task_struct. */
-extern long arch_ptrace(struct task_struct *child, long request, long addr, long data);
+extern long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data);
extern int ptrace_traceme(void);
extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len);
@@ -108,7 +109,8 @@ extern int ptrace_attach(struct task_struct *tsk);
extern int ptrace_detach(struct task_struct *, unsigned int);
extern void ptrace_disable(struct task_struct *);
extern int ptrace_check_attach(struct task_struct *task, int kill);
-extern int ptrace_request(struct task_struct *child, long request, long addr, long data);
+extern int ptrace_request(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data);
extern void ptrace_notify(int exit_code);
extern void __ptrace_link(struct task_struct *child,
struct task_struct *new_parent);
@@ -132,8 +134,10 @@ static inline void ptrace_unlink(struct task_struct *child)
__ptrace_unlink(child);
}
-int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data);
-int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data);
+int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr,
+ unsigned long data);
+int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr,
+ unsigned long data);
/**
* task_ptrace - return %PT_* flags that apply to a task
diff --git a/include/linux/ramoops.h b/include/linux/ramoops.h
new file mode 100644
index 000000000000..0ae68a2c1212
--- /dev/null
+++ b/include/linux/ramoops.h
@@ -0,0 +1,15 @@
+#ifndef __RAMOOPS_H
+#define __RAMOOPS_H
+
+/*
+ * Ramoops platform data
+ * @mem_size memory size for ramoops
+ * @mem_address physical memory address to contain ramoops
+ */
+
+struct ramoops_platform_data {
+ unsigned long mem_size;
+ unsigned long mem_address;
+};
+
+#endif
diff --git a/include/linux/ratelimit.h b/include/linux/ratelimit.h
index 8f69d09a41a5..03ff67b0cdf5 100644
--- a/include/linux/ratelimit.h
+++ b/include/linux/ratelimit.h
@@ -36,6 +36,8 @@ static inline void ratelimit_state_init(struct ratelimit_state *rs,
rs->begin = 0;
}
+extern struct ratelimit_state printk_ratelimit_state;
+
extern int ___ratelimit(struct ratelimit_state *rs, const char *func);
#define __ratelimit(state) ___ratelimit(state, __func__)
diff --git a/include/linux/rds.h b/include/linux/rds.h
index 24bce3ded9ea..91950950aa59 100644
--- a/include/linux/rds.h
+++ b/include/linux/rds.h
@@ -36,15 +36,6 @@
#include <linux/types.h>
-/* These sparse annotated types shouldn't be in any user
- * visible header file. We should clean this up rather
- * than kludging around them. */
-#ifndef __KERNEL__
-#define __be16 u_int16_t
-#define __be32 u_int32_t
-#define __be64 u_int64_t
-#endif
-
#define RDS_IB_ABI_VERSION 0x301
/*
@@ -82,6 +73,10 @@
#define RDS_CMSG_RDMA_MAP 3
#define RDS_CMSG_RDMA_STATUS 4
#define RDS_CMSG_CONG_UPDATE 5
+#define RDS_CMSG_ATOMIC_FADD 6
+#define RDS_CMSG_ATOMIC_CSWP 7
+#define RDS_CMSG_MASKED_ATOMIC_FADD 8
+#define RDS_CMSG_MASKED_ATOMIC_CSWP 9
#define RDS_INFO_FIRST 10000
#define RDS_INFO_COUNTERS 10000
@@ -98,9 +93,9 @@
#define RDS_INFO_LAST 10010
struct rds_info_counter {
- u_int8_t name[32];
- u_int64_t value;
-} __packed;
+ uint8_t name[32];
+ uint64_t value;
+} __attribute__((packed));
#define RDS_INFO_CONNECTION_FLAG_SENDING 0x01
#define RDS_INFO_CONNECTION_FLAG_CONNECTING 0x02
@@ -109,56 +104,48 @@ struct rds_info_counter {
#define TRANSNAMSIZ 16
struct rds_info_connection {
- u_int64_t next_tx_seq;
- u_int64_t next_rx_seq;
- __be32 laddr;
- __be32 faddr;
- u_int8_t transport[TRANSNAMSIZ]; /* null term ascii */
- u_int8_t flags;
-} __packed;
-
-struct rds_info_flow {
+ uint64_t next_tx_seq;
+ uint64_t next_rx_seq;
__be32 laddr;
__be32 faddr;
- u_int32_t bytes;
- __be16 lport;
- __be16 fport;
-} __packed;
+ uint8_t transport[TRANSNAMSIZ]; /* null term ascii */
+ uint8_t flags;
+} __attribute__((packed));
#define RDS_INFO_MESSAGE_FLAG_ACK 0x01
#define RDS_INFO_MESSAGE_FLAG_FAST_ACK 0x02
struct rds_info_message {
- u_int64_t seq;
- u_int32_t len;
+ uint64_t seq;
+ uint32_t len;
__be32 laddr;
__be32 faddr;
__be16 lport;
__be16 fport;
- u_int8_t flags;
-} __packed;
+ uint8_t flags;
+} __attribute__((packed));
struct rds_info_socket {
- u_int32_t sndbuf;
+ uint32_t sndbuf;
__be32 bound_addr;
__be32 connected_addr;
__be16 bound_port;
__be16 connected_port;
- u_int32_t rcvbuf;
- u_int64_t inum;
-} __packed;
+ uint32_t rcvbuf;
+ uint64_t inum;
+} __attribute__((packed));
struct rds_info_tcp_socket {
__be32 local_addr;
__be16 local_port;
__be32 peer_addr;
__be16 peer_port;
- u_int64_t hdr_rem;
- u_int64_t data_rem;
- u_int32_t last_sent_nxt;
- u_int32_t last_expected_una;
- u_int32_t last_seen_una;
-} __packed;
+ uint64_t hdr_rem;
+ uint64_t data_rem;
+ uint32_t last_sent_nxt;
+ uint32_t last_expected_una;
+ uint32_t last_seen_una;
+} __attribute__((packed));
#define RDS_IB_GID_LEN 16
struct rds_info_rdma_connection {
@@ -212,42 +199,69 @@ struct rds_info_rdma_connection {
* (so that the application does not have to worry about
* alignment).
*/
-typedef u_int64_t rds_rdma_cookie_t;
+typedef uint64_t rds_rdma_cookie_t;
struct rds_iovec {
- u_int64_t addr;
- u_int64_t bytes;
+ uint64_t addr;
+ uint64_t bytes;
};
struct rds_get_mr_args {
struct rds_iovec vec;
- u_int64_t cookie_addr;
+ uint64_t cookie_addr;
uint64_t flags;
};
struct rds_get_mr_for_dest_args {
struct sockaddr_storage dest_addr;
struct rds_iovec vec;
- u_int64_t cookie_addr;
+ uint64_t cookie_addr;
uint64_t flags;
};
struct rds_free_mr_args {
rds_rdma_cookie_t cookie;
- u_int64_t flags;
+ uint64_t flags;
};
struct rds_rdma_args {
rds_rdma_cookie_t cookie;
struct rds_iovec remote_vec;
- u_int64_t local_vec_addr;
- u_int64_t nr_local;
- u_int64_t flags;
- u_int64_t user_token;
+ uint64_t local_vec_addr;
+ uint64_t nr_local;
+ uint64_t flags;
+ uint64_t user_token;
+};
+
+struct rds_atomic_args {
+ rds_rdma_cookie_t cookie;
+ uint64_t local_addr;
+ uint64_t remote_addr;
+ union {
+ struct {
+ uint64_t compare;
+ uint64_t swap;
+ } cswp;
+ struct {
+ uint64_t add;
+ } fadd;
+ struct {
+ uint64_t compare;
+ uint64_t swap;
+ uint64_t compare_mask;
+ uint64_t swap_mask;
+ } m_cswp;
+ struct {
+ uint64_t add;
+ uint64_t nocarry_mask;
+ } m_fadd;
+ };
+ uint64_t flags;
+ uint64_t user_token;
};
struct rds_rdma_notify {
- u_int64_t user_token;
+ uint64_t user_token;
int32_t status;
};
@@ -266,5 +280,6 @@ struct rds_rdma_notify {
#define RDS_RDMA_USE_ONCE 0x0008 /* free MR after use */
#define RDS_RDMA_DONTWAIT 0x0010 /* Don't wait in SET_BARRIER */
#define RDS_RDMA_NOTIFY_ME 0x0020 /* Notify when operation completes */
+#define RDS_RDMA_SILENT 0x0040 /* Do not interrupt remote */
#endif /* IB_RDS_H */
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
index 91a4177e60ce..5ca47e59b727 100644
--- a/include/linux/reiserfs_fs.h
+++ b/include/linux/reiserfs_fs.h
@@ -2072,6 +2072,8 @@ void sd_attrs_to_i_attrs(__u16 sd_attrs, struct inode *inode);
void i_attrs_to_sd_attrs(struct inode *inode, __u16 * sd_attrs);
int reiserfs_setattr(struct dentry *dentry, struct iattr *attr);
+int __reiserfs_write_begin(struct page *page, unsigned from, unsigned len);
+
/* namei.c */
void set_de_name_and_namelen(struct reiserfs_dir_entry *de);
int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index 25b4f686d918..8d3a2486544d 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -62,18 +62,6 @@ enum ring_buffer_type {
unsigned ring_buffer_event_length(struct ring_buffer_event *event);
void *ring_buffer_event_data(struct ring_buffer_event *event);
-/**
- * ring_buffer_event_time_delta - return the delta timestamp of the event
- * @event: the event to get the delta timestamp of
- *
- * The delta timestamp is the 27 bit timestamp since the last event.
- */
-static inline unsigned
-ring_buffer_event_time_delta(struct ring_buffer_event *event)
-{
- return event->time_delta;
-}
-
/*
* ring_buffer_discard_commit will remove an event that has not
* ben committed yet. If this is used, then ring_buffer_unlock_commit
diff --git a/include/linux/rio.h b/include/linux/rio.h
index bd6eb0ed34a7..0bed941f9b13 100644
--- a/include/linux/rio.h
+++ b/include/linux/rio.h
@@ -67,6 +67,7 @@
#define RIO_PW_MSG_SIZE 64
extern struct bus_type rio_bus_type;
+extern struct device rio_bus;
extern struct list_head rio_devices; /* list of all devices */
struct rio_mport;
@@ -98,6 +99,7 @@ union rio_pw_msg;
* @riores: RIO resources this device owns
* @pwcback: port-write callback function for this device
* @destid: Network destination ID
+ * @prev: Previous RIO device connected to the current one
*/
struct rio_dev {
struct list_head global_list; /* node in list of all RIO devices */
@@ -111,7 +113,7 @@ struct rio_dev {
u16 asm_rev;
u16 efptr;
u32 pef;
- u32 swpinfo; /* Only used for switches */
+ u32 swpinfo;
u32 src_ops;
u32 dst_ops;
u32 comp_tag;
@@ -124,6 +126,7 @@ struct rio_dev {
struct resource riores[RIO_MAX_DEV_RESOURCES];
int (*pwcback) (struct rio_dev *rdev, union rio_pw_msg *msg, int step);
u16 destid;
+ struct rio_dev *prev;
};
#define rio_dev_g(n) list_entry(n, struct rio_dev, global_list)
@@ -174,6 +177,7 @@ enum rio_phy_type {
* @index: Port index, unique among all port interfaces of the same type
* @sys_size: RapidIO common transport system size
* @phy_type: RapidIO phy type
+ * @phys_efptr: RIO port extended features pointer
* @name: Port name string
* @priv: Master port private data
*/
@@ -195,6 +199,7 @@ struct rio_mport {
* 1 - Large size, 65536 devices.
*/
enum rio_phy_type phy_type; /* RapidIO phy type */
+ u32 phys_efptr;
unsigned char name[40];
void *priv; /* Master port private data */
};
@@ -215,9 +220,14 @@ struct rio_net {
unsigned char id; /* RIO network ID */
};
+/* Definitions used by switch sysfs initialization callback */
+#define RIO_SW_SYSFS_CREATE 1 /* Create switch attributes */
+#define RIO_SW_SYSFS_REMOVE 0 /* Remove switch attributes */
+
/**
* struct rio_switch - RIO switch info
* @node: Node in global list of switches
+ * @rdev: Associated RIO device structure
* @switchid: Switch ID that is unique across a network
* @hopcount: Hopcount to this switch
* @destid: Associated destid in the path
@@ -230,9 +240,12 @@ struct rio_net {
* @get_domain: Callback for switch-specific domain get function
* @em_init: Callback for switch-specific error management initialization function
* @em_handle: Callback for switch-specific error management handler function
+ * @sw_sysfs: Callback that initializes switch-specific sysfs attributes
+ * @nextdev: Array of per-port pointers to the next attached device
*/
struct rio_switch {
struct list_head node;
+ struct rio_dev *rdev;
u16 switchid;
u16 hopcount;
u16 destid;
@@ -250,6 +263,8 @@ struct rio_switch {
u8 *sw_domain);
int (*em_init) (struct rio_dev *dev);
int (*em_handle) (struct rio_dev *dev, u8 swport);
+ int (*sw_sysfs) (struct rio_dev *dev, int create);
+ struct rio_dev *nextdev[0];
};
/* Low-level architecture-dependent routines */
diff --git a/include/linux/rio_ids.h b/include/linux/rio_ids.h
index db50e1c288b7..ee7b6ada188f 100644
--- a/include/linux/rio_ids.h
+++ b/include/linux/rio_ids.h
@@ -34,5 +34,7 @@
#define RIO_DID_IDTCPS16 0x035b
#define RIO_DID_IDTCPS6Q 0x035f
#define RIO_DID_IDTCPS10Q 0x035e
+#define RIO_DID_IDTCPS1848 0x0374
+#define RIO_DID_IDTCPS1616 0x0379
#endif /* LINUX_RIO_IDS_H */
diff --git a/include/linux/rio_regs.h b/include/linux/rio_regs.h
index aedee0489fb4..d63dcbaea169 100644
--- a/include/linux/rio_regs.h
+++ b/include/linux/rio_regs.h
@@ -33,6 +33,7 @@
#define RIO_PEF_MEMORY 0x40000000 /* [I] MMIO */
#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 */
@@ -51,6 +52,7 @@
#define RIO_SWP_INFO_PORT_TOTAL_MASK 0x0000ff00 /* [I] Total number of ports */
#define RIO_SWP_INFO_PORT_NUM_MASK 0x000000ff /* [I] Maintenance transaction port number */
#define RIO_GET_TOTAL_PORTS(x) ((x & RIO_SWP_INFO_PORT_TOTAL_MASK) >> 8)
+#define RIO_GET_PORT_NUM(x) (x & RIO_SWP_INFO_PORT_NUM_MASK)
#define RIO_SRC_OPS_CAR 0x18 /* [I] Source Operations CAR */
#define RIO_SRC_OPS_READ 0x00008000 /* [I] Read op */
@@ -159,6 +161,7 @@
#define RIO_COMPONENT_TAG_CSR 0x6c /* [III] Component Tag CSR */
#define RIO_STD_RTE_CONF_DESTID_SEL_CSR 0x70
+#define RIO_STD_RTE_CONF_EXTCFGEN 0x80000000
#define RIO_STD_RTE_CONF_PORT_SEL_CSR 0x74
#define RIO_STD_RTE_DEFAULT_PORT 0x78
@@ -222,15 +225,17 @@
#define RIO_PORT_GEN_MASTER 0x40000000
#define RIO_PORT_GEN_DISCOVERED 0x20000000
#define RIO_PORT_N_MNT_REQ_CSR(x) (0x0040 + x*0x20) /* 0x0002 */
+#define RIO_MNT_REQ_CMD_RD 0x03 /* Reset-device command */
+#define RIO_MNT_REQ_CMD_IS 0x04 /* Input-status command */
#define RIO_PORT_N_MNT_RSP_CSR(x) (0x0044 + x*0x20) /* 0x0002 */
#define RIO_PORT_N_MNT_RSP_RVAL 0x80000000 /* Response Valid */
-#define RIO_PORT_N_MNT_RSP_ASTAT 0x000003e0 /* ackID Status */
+#define RIO_PORT_N_MNT_RSP_ASTAT 0x000007e0 /* ackID Status */
#define RIO_PORT_N_MNT_RSP_LSTAT 0x0000001f /* Link Status */
#define RIO_PORT_N_ACK_STS_CSR(x) (0x0048 + x*0x20) /* 0x0002 */
#define RIO_PORT_N_ACK_CLEAR 0x80000000
-#define RIO_PORT_N_ACK_INBOUND 0x1f000000
-#define RIO_PORT_N_ACK_OUTSTAND 0x00001f00
-#define RIO_PORT_N_ACK_OUTBOUND 0x0000001f
+#define RIO_PORT_N_ACK_INBOUND 0x3f000000
+#define RIO_PORT_N_ACK_OUTSTAND 0x00003f00
+#define RIO_PORT_N_ACK_OUTBOUND 0x0000003f
#define RIO_PORT_N_ERR_STS_CSR(x) (0x0058 + x*0x20)
#define RIO_PORT_N_ERR_STS_PW_OUT_ES 0x00010000 /* Output Error-stopped */
#define RIO_PORT_N_ERR_STS_PW_INP_ES 0x00000100 /* Input Error-stopped */
@@ -238,7 +243,6 @@
#define RIO_PORT_N_ERR_STS_PORT_ERR 0x00000004
#define RIO_PORT_N_ERR_STS_PORT_OK 0x00000002
#define RIO_PORT_N_ERR_STS_PORT_UNINIT 0x00000001
-#define RIO_PORT_N_ERR_STS_CLR_MASK 0x07120204
#define RIO_PORT_N_CTL_CSR(x) (0x005c + x*0x20)
#define RIO_PORT_N_CTL_PWIDTH 0xc0000000
#define RIO_PORT_N_CTL_PWIDTH_1 0x00000000
@@ -261,6 +265,10 @@
#define RIO_EM_EFB_HEADER 0x000 /* Error Management Extensions Block Header */
#define RIO_EM_LTL_ERR_DETECT 0x008 /* Logical/Transport Layer Error Detect CSR */
#define RIO_EM_LTL_ERR_EN 0x00c /* Logical/Transport Layer Error Enable CSR */
+#define REM_LTL_ERR_ILLTRAN 0x08000000 /* Illegal Transaction decode */
+#define REM_LTL_ERR_UNSOLR 0x00800000 /* Unsolicited Response */
+#define REM_LTL_ERR_UNSUPTR 0x00400000 /* Unsupported Transaction */
+#define REM_LTL_ERR_IMPSPEC 0x000000ff /* Implementation Specific */
#define RIO_EM_LTL_HIADDR_CAP 0x010 /* Logical/Transport Layer High Address Capture CSR */
#define RIO_EM_LTL_ADDR_CAP 0x014 /* Logical/Transport Layer Address Capture CSR */
#define RIO_EM_LTL_DEVID_CAP 0x018 /* Logical/Transport Layer Device ID Capture CSR */
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index 31b2fd75dcba..bb83c0da2071 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -25,8 +25,8 @@
* pointing to this anon_vma once its vma list is empty.
*/
struct anon_vma {
- spinlock_t lock; /* Serialize access to vma list */
struct anon_vma *root; /* Root of this anon_vma tree */
+ spinlock_t lock; /* Serialize access to vma list */
#if defined(CONFIG_KSM) || defined(CONFIG_MIGRATION)
/*
@@ -205,9 +205,20 @@ int try_to_unmap_one(struct page *, struct vm_area_struct *,
/*
* Called from mm/filemap_xip.c to unmap empty zero page
*/
-pte_t *page_check_address(struct page *, struct mm_struct *,
+pte_t *__page_check_address(struct page *, struct mm_struct *,
unsigned long, spinlock_t **, int);
+static inline pte_t *page_check_address(struct page *page, struct mm_struct *mm,
+ unsigned long address,
+ spinlock_t **ptlp, int sync)
+{
+ pte_t *ptep;
+
+ __cond_lock(*ptlp, ptep = __page_check_address(page, mm, address,
+ ptlp, sync));
+ return ptep;
+}
+
/*
* Used by swapoff to help locate where page is expected in vma.
*/
@@ -230,7 +241,20 @@ int try_to_munlock(struct page *);
/*
* Called by memory-failure.c to kill processes.
*/
-struct anon_vma *page_lock_anon_vma(struct page *page);
+struct anon_vma *__page_lock_anon_vma(struct page *page);
+
+static inline struct anon_vma *page_lock_anon_vma(struct page *page)
+{
+ struct anon_vma *anon_vma;
+
+ __cond_lock(RCU, anon_vma = __page_lock_anon_vma(page));
+
+ /* (void) is needed to make gcc happy */
+ (void) __cond_lock(&anon_vma->root->lock, anon_vma);
+
+ return anon_vma;
+}
+
void page_unlock_anon_vma(struct anon_vma *anon_vma);
int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma);
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 58d44491880f..d42f274418b8 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -6,6 +6,7 @@
#include <linux/if_link.h>
#include <linux/if_addr.h>
#include <linux/neighbour.h>
+#include <linux/netdevice.h>
/* rtnetlink families. Values up to 127 are reserved for real address
* families, values above 128 may be used arbitrarily.
@@ -749,6 +750,35 @@ extern int rtnl_is_locked(void);
extern int lockdep_rtnl_is_held(void);
#endif /* #ifdef CONFIG_PROVE_LOCKING */
+/**
+ * rcu_dereference_rtnl - rcu_dereference with debug checking
+ * @p: The pointer to read, prior to dereferencing
+ *
+ * Do an rcu_dereference(p), but check caller either holds rcu_read_lock()
+ * or RTNL. Note : Please prefer rtnl_dereference() or rcu_dereference()
+ */
+#define rcu_dereference_rtnl(p) \
+ rcu_dereference_check(p, rcu_read_lock_held() || \
+ lockdep_rtnl_is_held())
+
+/**
+ * rtnl_dereference - fetch RCU pointer when updates are prevented by RTNL
+ * @p: The pointer to read, prior to dereferencing
+ *
+ * Return the value of the specified RCU-protected pointer, but omit
+ * both the smp_read_barrier_depends() and the ACCESS_ONCE(), because
+ * caller holds RTNL.
+ */
+#define rtnl_dereference(p) \
+ rcu_dereference_protected(p, lockdep_rtnl_is_held())
+
+static inline struct netdev_queue *dev_ingress_queue(struct net_device *dev)
+{
+ return rtnl_dereference(dev->ingress_queue);
+}
+
+extern struct netdev_queue *dev_ingress_queue_create(struct net_device *dev);
+
extern void rtnetlink_init(void);
extern void __rtnl_unlock(void);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 56154bbb8da9..be7adb7588e5 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -626,6 +626,10 @@ struct signal_struct {
int oom_adj; /* OOM kill score adjustment (bit shift) */
int oom_score_adj; /* OOM kill score adjustment */
+
+ struct mutex cred_guard_mutex; /* guard against foreign influences on
+ * credential calculations
+ * (notably. ptrace) */
};
/* Context switch must be unlocked if interrupts are to be enabled */
@@ -1305,9 +1309,6 @@ struct task_struct {
* credentials (COW) */
const struct cred __rcu *cred; /* effective (overridable) subjective task
* credentials (COW) */
- struct mutex cred_guard_mutex; /* guard against foreign influences on
- * credential calculations
- * (notably. ptrace) */
struct cred *replacement_session_keyring; /* for KEYCTL_SESSION_TO_PARENT */
char comm[TASK_COMM_LEN]; /* executable name excluding path
@@ -1706,7 +1707,6 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
#define PF_DUMPCORE 0x00000200 /* dumped core */
#define PF_SIGNALED 0x00000400 /* killed by a signal */
#define PF_MEMALLOC 0x00000800 /* Allocating memory */
-#define PF_FLUSHER 0x00001000 /* responsible for disk writeback */
#define PF_USED_MATH 0x00002000 /* if unset the fpu must be initialized before use */
#define PF_FREEZING 0x00004000 /* freeze in progress. do not account to load */
#define PF_NOFREEZE 0x00008000 /* this thread should not be frozen */
@@ -2237,9 +2237,16 @@ static inline void task_unlock(struct task_struct *p)
spin_unlock(&p->alloc_lock);
}
-extern struct sighand_struct *lock_task_sighand(struct task_struct *tsk,
+extern struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
unsigned long *flags);
+#define lock_task_sighand(tsk, flags) \
+({ struct sighand_struct *__ss; \
+ __cond_lock(&(tsk)->sighand->siglock, \
+ (__ss = __lock_task_sighand(tsk, flags))); \
+ __ss; \
+}) \
+
static inline void unlock_task_sighand(struct task_struct *tsk,
unsigned long *flags)
{
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 99e5994e6f84..212eb4c67797 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -196,6 +196,9 @@
/* High Speed UART for Medfield */
#define PORT_MFD 95
+/* TI OMAP-UART */
+#define PORT_OMAP 96
+
#ifdef __KERNEL__
#include <linux/compiler.h>
diff --git a/include/linux/serio.h b/include/linux/serio.h
index b5552568178d..e26f4788845f 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -41,7 +41,9 @@ struct serio {
int (*start)(struct serio *);
void (*stop)(struct serio *);
- struct serio *parent, *child;
+ struct serio *parent;
+ struct list_head child_node; /* Entry in parent->children list */
+ struct list_head children;
unsigned int depth; /* level of nesting in serio hierarchy */
struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */
@@ -54,10 +56,9 @@ struct serio {
#define to_serio_port(d) container_of(d, struct serio, dev)
struct serio_driver {
- void *private;
- char *description;
+ const char *description;
- struct serio_device_id *id_table;
+ const struct serio_device_id *id_table;
bool manual_bind;
void (*write_wakeup)(struct serio *);
@@ -197,5 +198,6 @@ static inline void serio_continue_rx(struct serio *serio)
#define SERIO_W8001 0x39
#define SERIO_DYNAPRO 0x3a
#define SERIO_HAMPSHIRE 0x3b
+#define SERIO_PS2MULT 0x3c
#endif
diff --git a/include/linux/sfi.h b/include/linux/sfi.h
index 0299b4ce63db..7f770c638e99 100644
--- a/include/linux/sfi.h
+++ b/include/linux/sfi.h
@@ -70,9 +70,6 @@
#define SFI_SIG_APIC "APIC"
#define SFI_SIG_XSDT "XSDT"
#define SFI_SIG_WAKE "WAKE"
-#define SFI_SIG_SPIB "SPIB"
-#define SFI_SIG_I2CB "I2CB"
-#define SFI_SIG_GPEM "GPEM"
#define SFI_SIG_DEVS "DEVS"
#define SFI_SIG_GPIO "GPIO"
@@ -168,27 +165,6 @@ struct sfi_gpio_table_entry {
char pin_name[16];
} __packed;
-struct sfi_spi_table_entry {
- u16 host_num; /* attached to host 0, 1...*/
- u16 cs; /* chip select */
- u16 irq_info;
- char name[16];
- u8 dev_info[10];
-} __packed;
-
-struct sfi_i2c_table_entry {
- u16 host_num;
- u16 addr; /* slave addr */
- u16 irq_info;
- char name[16];
- u8 dev_info[10];
-} __packed;
-
-struct sfi_gpe_table_entry {
- u16 logical_id; /* logical id */
- u16 phys_id; /* physical GPE id */
-} __packed;
-
typedef int (*sfi_table_handler) (struct sfi_table_header *table);
#ifdef CONFIG_SFI
diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h
index 875ce50719a9..4dca992f3093 100644
--- a/include/linux/sh_clk.h
+++ b/include/linux/sh_clk.h
@@ -4,11 +4,20 @@
#include <linux/list.h>
#include <linux/seq_file.h>
#include <linux/cpufreq.h>
+#include <linux/types.h>
+#include <linux/kref.h>
#include <linux/clk.h>
#include <linux/err.h>
struct clk;
+struct clk_mapping {
+ phys_addr_t phys;
+ void __iomem *base;
+ unsigned long len;
+ struct kref ref;
+};
+
struct clk_ops {
void (*init)(struct clk *clk);
int (*enable)(struct clk *clk);
@@ -21,9 +30,6 @@ struct clk_ops {
struct clk {
struct list_head node;
- const char *name;
- int id;
-
struct clk *parent;
struct clk **parent_table; /* list of parents to */
unsigned short parent_num; /* choose between */
@@ -45,7 +51,9 @@ struct clk {
unsigned long arch_flags;
void *priv;
struct dentry *dentry;
+ struct clk_mapping *mapping;
struct cpufreq_frequency_table *freq_table;
+ unsigned int nr_freqs;
};
#define CLK_ENABLE_ON_INIT (1 << 0)
@@ -111,6 +119,9 @@ int clk_rate_table_find(struct clk *clk,
struct cpufreq_frequency_table *freq_table,
unsigned long rate);
+long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,
+ unsigned int div_max, unsigned long rate);
+
#define SH_CLK_MSTP32(_parent, _enable_reg, _enable_bit, _flags) \
{ \
.parent = _parent, \
diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h
index 0d6cd38e673d..b4f183a31f13 100644
--- a/include/linux/sh_intc.h
+++ b/include/linux/sh_intc.h
@@ -20,6 +20,12 @@ struct intc_group {
#define INTC_GROUP(enum_id, ids...) { enum_id, { ids } }
+struct intc_subgroup {
+ unsigned long reg, reg_width;
+ intc_enum parent_id;
+ intc_enum enum_ids[32];
+};
+
struct intc_mask_reg {
unsigned long set_reg, clr_reg, reg_width;
intc_enum enum_ids[32];
@@ -69,9 +75,12 @@ struct intc_hw_desc {
unsigned int nr_sense_regs;
struct intc_mask_reg *ack_regs;
unsigned int nr_ack_regs;
+ struct intc_subgroup *subgroups;
+ unsigned int nr_subgroups;
};
-#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a)
+#define _INTC_ARRAY(a) a, a == NULL ? 0 : sizeof(a)/sizeof(*a)
+
#define INTC_HW_DESC(vectors, groups, mask_regs, \
prio_regs, sense_regs, ack_regs) \
{ \
@@ -105,8 +114,11 @@ struct intc_desc symbol __initdata = { \
prio_regs, sense_regs, ack_regs), \
}
-int __init register_intc_controller(struct intc_desc *desc);
+int register_intc_controller(struct intc_desc *desc);
+void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs);
int intc_set_priority(unsigned int irq, unsigned int prio);
+int intc_irq_lookup(const char *chipname, intc_enum enum_id);
+void intc_finalize(void);
#ifdef CONFIG_INTC_USERIMASK
int register_intc_userimask(unsigned long addr);
diff --git a/include/linux/sh_pfc.h b/include/linux/sh_pfc.h
index 07c08af9f8f6..30cae70874f4 100644
--- a/include/linux/sh_pfc.h
+++ b/include/linux/sh_pfc.h
@@ -92,5 +92,6 @@ struct pinmux_info {
};
int register_pinmux(struct pinmux_info *pip);
+int unregister_pinmux(struct pinmux_info *pip);
#endif /* __SH_PFC_H */
diff --git a/include/linux/signalfd.h b/include/linux/signalfd.h
index b363b916c909..3ff4961da9b5 100644
--- a/include/linux/signalfd.h
+++ b/include/linux/signalfd.h
@@ -33,6 +33,7 @@ struct signalfd_siginfo {
__u64 ssi_utime;
__u64 ssi_stime;
__u64 ssi_addr;
+ __u16 ssi_addr_lsb;
/*
* Pad strcture to 128 bytes. Remember to update the
@@ -43,7 +44,7 @@ struct signalfd_siginfo {
* comes out of a read(2) and we really don't want to have
* a compat on read(2).
*/
- __u8 __pad[48];
+ __u8 __pad[46];
};
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 77eb60d2b496..e6ba898de61c 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -129,8 +129,13 @@ typedef struct skb_frag_struct skb_frag_t;
struct skb_frag_struct {
struct page *page;
+#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
__u32 page_offset;
__u32 size;
+#else
+ __u16 page_offset;
+ __u16 size;
+#endif
};
#define HAVE_HW_TIME_STAMP
@@ -163,26 +168,19 @@ struct skb_shared_hwtstamps {
ktime_t syststamp;
};
-/**
- * struct skb_shared_tx - instructions for time stamping of outgoing packets
- * @hardware: generate hardware time stamp
- * @software: generate software time stamp
- * @in_progress: device driver is going to provide
- * hardware time stamp
- * @prevent_sk_orphan: make sk reference available on driver level
- * @flags: all shared_tx flags
- *
- * These flags are attached to packets as part of the
- * &skb_shared_info. Use skb_tx() to get a pointer.
- */
-union skb_shared_tx {
- struct {
- __u8 hardware:1,
- software:1,
- in_progress:1,
- prevent_sk_orphan:1;
- };
- __u8 flags;
+/* Definitions for tx_flags in struct skb_shared_info */
+enum {
+ /* generate hardware time stamp */
+ SKBTX_HW_TSTAMP = 1 << 0,
+
+ /* generate software time stamp */
+ SKBTX_SW_TSTAMP = 1 << 1,
+
+ /* device driver is going to provide hardware time stamp */
+ SKBTX_IN_PROGRESS = 1 << 2,
+
+ /* ensure the originating sk reference is available on driver level */
+ SKBTX_DRV_NEEDS_SK_REF = 1 << 3,
};
/* This data is invariant across clones and lives at
@@ -195,7 +193,7 @@ struct skb_shared_info {
unsigned short gso_segs;
unsigned short gso_type;
__be32 ip6_frag_id;
- union skb_shared_tx tx_flags;
+ __u8 tx_flags;
struct sk_buff *frag_list;
struct skb_shared_hwtstamps hwtstamps;
@@ -462,19 +460,7 @@ static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
skb->_skb_refdst = (unsigned long)dst;
}
-/**
- * skb_dst_set_noref - sets skb dst, without a reference
- * @skb: buffer
- * @dst: dst entry
- *
- * Sets skb dst, assuming a reference was not taken on dst
- * skb_dst_drop() should not dst_release() this dst
- */
-static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
-{
- WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
- skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF;
-}
+extern void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst);
/**
* skb_dst_is_noref - Test if skb dst isnt refcounted
@@ -498,13 +484,13 @@ extern struct sk_buff *__alloc_skb(unsigned int size,
static inline struct sk_buff *alloc_skb(unsigned int size,
gfp_t priority)
{
- return __alloc_skb(size, priority, 0, -1);
+ return __alloc_skb(size, priority, 0, NUMA_NO_NODE);
}
static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
gfp_t priority)
{
- return __alloc_skb(size, priority, 1, -1);
+ return __alloc_skb(size, priority, 1, NUMA_NO_NODE);
}
extern bool skb_recycle_check(struct sk_buff *skb, int skb_size);
@@ -558,6 +544,15 @@ 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);
+static inline __u32 skb_get_rxhash(struct sk_buff *skb)
+{
+ if (!skb->rxhash)
+ skb->rxhash = __skb_get_rxhash(skb);
+
+ return skb->rxhash;
+}
+
#ifdef NET_SKBUFF_DATA_USES_OFFSET
static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
{
@@ -578,11 +573,6 @@ static inline struct skb_shared_hwtstamps *skb_hwtstamps(struct sk_buff *skb)
return &skb_shinfo(skb)->hwtstamps;
}
-static inline union skb_shared_tx *skb_tx(struct sk_buff *skb)
-{
- return &skb_shinfo(skb)->tx_flags;
-}
-
/**
* skb_queue_empty - check if a queue is empty
* @list: queue head
@@ -604,7 +594,7 @@ static inline int skb_queue_empty(const struct sk_buff_head *list)
static inline bool skb_queue_is_last(const struct sk_buff_head *list,
const struct sk_buff *skb)
{
- return (skb->next == (struct sk_buff *) list);
+ return skb->next == (struct sk_buff *)list;
}
/**
@@ -617,7 +607,7 @@ static inline bool skb_queue_is_last(const struct sk_buff_head *list,
static inline bool skb_queue_is_first(const struct sk_buff_head *list,
const struct sk_buff *skb)
{
- return (skb->prev == (struct sk_buff *) list);
+ return skb->prev == (struct sk_buff *)list;
}
/**
@@ -1123,7 +1113,7 @@ extern void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page,
int off, int size);
#define SKB_PAGE_ASSERT(skb) BUG_ON(skb_shinfo(skb)->nr_frags)
-#define SKB_FRAG_ASSERT(skb) BUG_ON(skb_has_frags(skb))
+#define SKB_FRAG_ASSERT(skb) BUG_ON(skb_has_frag_list(skb))
#define SKB_LINEAR_ASSERT(skb) BUG_ON(skb_is_nonlinear(skb))
#ifdef NET_SKBUFF_DATA_USES_OFFSET
@@ -1561,13 +1551,25 @@ static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
return skb;
}
-extern struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask);
+/**
+ * __netdev_alloc_page - allocate a page for ps-rx on a specific device
+ * @dev: network device to receive on
+ * @gfp_mask: alloc_pages_node mask
+ *
+ * Allocate a new page. dev currently unused.
+ *
+ * %NULL is returned if there is no free memory.
+ */
+static inline struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask)
+{
+ return alloc_pages_node(NUMA_NO_NODE, gfp_mask, 0);
+}
/**
* netdev_alloc_page - allocate a page for ps-rx on a specific device
* @dev: network device to receive on
*
- * Allocate a new page node local to the specified device.
+ * Allocate a new page. dev currently unused.
*
* %NULL is returned if there is no free memory.
*/
@@ -1787,7 +1789,7 @@ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len)
skb = skb->prev)
-static inline bool skb_has_frags(const struct sk_buff *skb)
+static inline bool skb_has_frag_list(const struct sk_buff *skb)
{
return skb_shinfo(skb)->frag_list != NULL;
}
@@ -1987,8 +1989,8 @@ extern void skb_tstamp_tx(struct sk_buff *orig_skb,
static inline void sw_tx_timestamp(struct sk_buff *skb)
{
- union skb_shared_tx *shtx = skb_tx(skb);
- if (shtx->software && !shtx->in_progress)
+ if (skb_shinfo(skb)->tx_flags & SKBTX_SW_TSTAMP &&
+ !(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS))
skb_tstamp_tx(skb, NULL);
}
@@ -2159,7 +2161,7 @@ static inline u16 skb_get_rx_queue(const struct sk_buff *skb)
static inline bool skb_rx_queue_recorded(const struct sk_buff *skb)
{
- return (skb->queue_mapping != 0);
+ return skb->queue_mapping != 0;
}
extern u16 skb_tx_hash(const struct net_device *dev,
@@ -2209,6 +2211,21 @@ static inline void skb_forward_csum(struct sk_buff *skb)
skb->ip_summed = CHECKSUM_NONE;
}
+/**
+ * skb_checksum_none_assert - make sure skb ip_summed is CHECKSUM_NONE
+ * @skb: skb to check
+ *
+ * fresh skbs have their ip_summed set to CHECKSUM_NONE.
+ * 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)
+{
+#ifdef DEBUG
+ BUG_ON(skb->ip_summed != CHECKSUM_NONE);
+#endif
+}
+
bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
#endif /* __KERNEL__ */
#endif /* _LINUX_SKBUFF_H */
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
index 9f63538928c0..e4f5ed180b9b 100644
--- a/include/linux/slub_def.h
+++ b/include/linux/slub_def.h
@@ -87,7 +87,7 @@ struct kmem_cache {
unsigned long min_partial;
const char *name; /* Name (only for display!) */
struct list_head list; /* List of slab caches */
-#ifdef CONFIG_SLUB_DEBUG
+#ifdef CONFIG_SYSFS
struct kobject kobj; /* For sysfs */
#endif
@@ -96,11 +96,8 @@ struct kmem_cache {
* Defragmentation by allocating from a remote node.
*/
int remote_node_defrag_ratio;
- struct kmem_cache_node *node[MAX_NUMNODES];
-#else
- /* Avoid an extra cache line for UP */
- struct kmem_cache_node local_node;
#endif
+ struct kmem_cache_node *node[MAX_NUMNODES];
};
/*
@@ -139,19 +136,16 @@ struct kmem_cache {
#ifdef CONFIG_ZONE_DMA
#define SLUB_DMA __GFP_DMA
-/* Reserve extra caches for potential DMA use */
-#define KMALLOC_CACHES (2 * SLUB_PAGE_SHIFT)
#else
/* Disable DMA functionality */
#define SLUB_DMA (__force gfp_t)0
-#define KMALLOC_CACHES SLUB_PAGE_SHIFT
#endif
/*
* We keep the general caches in an array of slab caches that are used for
* 2^x bytes of allocations.
*/
-extern struct kmem_cache kmalloc_caches[KMALLOC_CACHES];
+extern struct kmem_cache *kmalloc_caches[SLUB_PAGE_SHIFT];
/*
* Sorry that the following has to be that ugly but some versions of GCC
@@ -216,7 +210,7 @@ static __always_inline struct kmem_cache *kmalloc_slab(size_t size)
if (index == 0)
return NULL;
- return &kmalloc_caches[index];
+ return kmalloc_caches[index];
}
void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
diff --git a/include/linux/smp.h b/include/linux/smp.h
index cfa2d20e35f1..6dc95cac6b3d 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -13,9 +13,10 @@
extern void cpu_idle(void);
+typedef void (*smp_call_func_t)(void *info);
struct call_single_data {
struct list_head list;
- void (*func) (void *info);
+ smp_call_func_t func;
void *info;
u16 flags;
u16 priv;
@@ -24,8 +25,8 @@ struct call_single_data {
/* total number of cpus in this system (may exceed NR_CPUS) */
extern unsigned int total_cpus;
-int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
- int wait);
+int smp_call_function_single(int cpuid, smp_call_func_t func, void *info,
+ int wait);
#ifdef CONFIG_SMP
@@ -69,15 +70,15 @@ extern void smp_cpus_done(unsigned int max_cpus);
/*
* Call a function on all other processors
*/
-int smp_call_function(void(*func)(void *info), void *info, int wait);
+int smp_call_function(smp_call_func_t func, void *info, int wait);
void smp_call_function_many(const struct cpumask *mask,
- void (*func)(void *info), void *info, bool wait);
+ smp_call_func_t func, void *info, bool wait);
void __smp_call_function_single(int cpuid, struct call_single_data *data,
int wait);
int smp_call_function_any(const struct cpumask *mask,
- void (*func)(void *info), void *info, int wait);
+ smp_call_func_t func, void *info, int wait);
/*
* Generic and arch helpers
@@ -94,7 +95,7 @@ void ipi_call_unlock_irq(void);
/*
* Call a function on all processors
*/
-int on_each_cpu(void (*func) (void *info), void *info, int wait);
+int on_each_cpu(smp_call_func_t func, void *info, int wait);
#define MSG_ALL_BUT_SELF 0x8000 /* Assume <32768 CPU's */
#define MSG_ALL 0x8001
@@ -122,7 +123,7 @@ static inline void smp_send_stop(void) { }
* These macros fold the SMP functionality into a single CPU system
*/
#define raw_smp_processor_id() 0
-static inline int up_smp_call_function(void (*func)(void *), void *info)
+static inline int up_smp_call_function(smp_call_func_t func, void *info)
{
return 0;
}
@@ -143,7 +144,7 @@ static inline void smp_send_reschedule(int cpu) { }
static inline void init_call_single_data(void) { }
static inline int
-smp_call_function_any(const struct cpumask *mask, void (*func)(void *info),
+smp_call_function_any(const struct cpumask *mask, smp_call_func_t func,
void *info, int wait)
{
return smp_call_function_single(0, func, info, wait);
diff --git a/include/linux/socket.h b/include/linux/socket.h
index a8f56e1ec760..5146b50202ce 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -326,7 +326,6 @@ extern long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *a
extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len);
extern int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
int offset, int len);
-extern int move_addr_to_user(struct sockaddr *kaddr, int klen, void __user *uaddr, int __user *ulen);
extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr *kaddr);
extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
diff --git a/include/linux/spi/74x164.h b/include/linux/spi/74x164.h
new file mode 100644
index 000000000000..d85c52f294a0
--- /dev/null
+++ b/include/linux/spi/74x164.h
@@ -0,0 +1,11 @@
+#ifndef LINUX_SPI_74X164_H
+#define LINUX_SPI_74X164_H
+
+#define GEN_74X164_DRIVER_NAME "74x164"
+
+struct gen_74x164_chip_platform_data {
+ /* number assigned to the first GPIO */
+ unsigned base;
+};
+
+#endif
diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h
index a6d5225b9275..11daf9c140e7 100644
--- a/include/linux/ssb/ssb_regs.h
+++ b/include/linux/ssb/ssb_regs.h
@@ -97,6 +97,7 @@
#define SSB_TMSLOW_RESET 0x00000001 /* Reset */
#define SSB_TMSLOW_REJECT_22 0x00000002 /* Reject (Backplane rev 2.2) */
#define SSB_TMSLOW_REJECT_23 0x00000004 /* Reject (Backplane rev 2.3) */
+#define SSB_TMSLOW_PHYCLK 0x00000010 /* MAC PHY Clock Control Enable */
#define SSB_TMSLOW_CLOCK 0x00010000 /* Clock Enable */
#define SSB_TMSLOW_FGC 0x00020000 /* Force Gated Clocks On */
#define SSB_TMSLOW_PE 0x40000000 /* Power Management Enable */
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 632ff7c03280..d66c61774d95 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -32,10 +32,14 @@
struct plat_stmmacenet_data {
int bus_id;
int pbl;
+ int clk_csr;
int has_gmac;
int enh_desc;
+ int tx_coe;
+ int bugged_jumbo;
+ int pmt;
void (*fix_mac_speed)(void *priv, unsigned int speed);
- void (*bus_setup)(unsigned long ioaddr);
+ void (*bus_setup)(void __iomem *ioaddr);
#ifdef CONFIG_STM_DRIVERS
struct stm_pad_config *pad_config;
#endif
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index 5bbc447175dc..b2024757edd5 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -122,8 +122,8 @@ extern const struct rpc_authops authnull_ops;
int __init rpc_init_authunix(void);
int __init rpc_init_generic_auth(void);
int __init rpcauth_init_module(void);
-void __exit rpcauth_remove_module(void);
-void __exit rpc_destroy_generic_auth(void);
+void rpcauth_remove_module(void);
+void rpc_destroy_generic_auth(void);
void rpc_destroy_authunix(void);
struct rpc_cred * rpc_lookup_cred(void);
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index 7bf3e84b92f4..6950c981882d 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -125,12 +125,15 @@ struct cache_detail {
*/
struct cache_req {
struct cache_deferred_req *(*defer)(struct cache_req *req);
+ int thread_wait; /* How long (jiffies) we can block the
+ * current thread to wait for updates.
+ */
};
/* this must be embedded in a deferred_request that is being
* delayed awaiting cache-fill
*/
struct cache_deferred_req {
- struct list_head hash; /* on hash chain */
+ struct hlist_node hash; /* on hash chain */
struct list_head recent; /* on fifo */
struct cache_head *item; /* cache item we wait on */
void *owner; /* we might need to discard all defered requests
@@ -194,7 +197,9 @@ extern void cache_purge(struct cache_detail *detail);
#define NEVER (0x7FFFFFFF)
extern void __init cache_initialize(void);
extern int cache_register(struct cache_detail *cd);
+extern int cache_register_net(struct cache_detail *cd, struct net *net);
extern void cache_unregister(struct cache_detail *cd);
+extern void cache_unregister_net(struct cache_detail *cd, struct net *net);
extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *,
mode_t, struct cache_detail *);
@@ -218,14 +223,42 @@ static inline int get_int(char **bpp, int *anint)
return 0;
}
+/*
+ * timestamps kept in the cache are expressed in seconds
+ * since boot. This is the best for measuring differences in
+ * real time.
+ */
+static inline time_t seconds_since_boot(void)
+{
+ struct timespec boot;
+ getboottime(&boot);
+ return get_seconds() - boot.tv_sec;
+}
+
+static inline time_t convert_to_wallclock(time_t sinceboot)
+{
+ struct timespec boot;
+ getboottime(&boot);
+ return boot.tv_sec + sinceboot;
+}
+
static inline time_t get_expiry(char **bpp)
{
int rv;
+ struct timespec boot;
+
if (get_int(bpp, &rv))
return 0;
if (rv < 0)
return 0;
- return rv;
+ getboottime(&boot);
+ return rv - boot.tv_sec;
}
+static inline void sunrpc_invalidate(struct cache_head *h,
+ struct cache_detail *detail)
+{
+ h->expiry_time = seconds_since_boot() - 1;
+ detail->nextcheck = seconds_since_boot();
+}
#endif /* _LINUX_SUNRPC_CACHE_H_ */
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 85f38a63f098..a5a55f284b7d 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -102,6 +102,7 @@ struct rpc_procinfo {
#ifdef __KERNEL__
struct rpc_create_args {
+ struct net *net;
int protocol;
struct sockaddr *address;
size_t addrsize;
@@ -137,7 +138,6 @@ int rpcb_register(u32, u32, int, unsigned short);
int rpcb_v4_register(const u32 program, const u32 version,
const struct sockaddr *address,
const char *netid);
-int rpcb_getport_sync(struct sockaddr_in *, u32, u32, int);
void rpcb_getport_async(struct rpc_task *);
void rpc_call_start(struct rpc_task *);
diff --git a/include/linux/sunrpc/gss_spkm3.h b/include/linux/sunrpc/gss_spkm3.h
deleted file mode 100644
index e3e6a3437f8b..000000000000
--- a/include/linux/sunrpc/gss_spkm3.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * linux/include/linux/sunrpc/gss_spkm3.h
- *
- * Copyright (c) 2000 The Regents of the University of Michigan.
- * All rights reserved.
- *
- * Andy Adamson <andros@umich.edu>
- */
-
-#include <linux/sunrpc/auth_gss.h>
-#include <linux/sunrpc/gss_err.h>
-#include <linux/sunrpc/gss_asn1.h>
-
-struct spkm3_ctx {
- struct xdr_netobj ctx_id; /* per message context id */
- int endtime; /* endtime of the context */
- struct xdr_netobj mech_used;
- unsigned int ret_flags ;
- struct xdr_netobj conf_alg;
- struct xdr_netobj derived_conf_key;
- struct xdr_netobj intg_alg;
- struct xdr_netobj derived_integ_key;
-};
-
-/* OIDs declarations for K-ALG, I-ALG, C-ALG, and OWF-ALG */
-extern const struct xdr_netobj hmac_md5_oid;
-extern const struct xdr_netobj cast5_cbc_oid;
-
-/* SPKM InnerContext Token types */
-
-#define SPKM_ERROR_TOK 3
-#define SPKM_MIC_TOK 4
-#define SPKM_WRAP_TOK 5
-#define SPKM_DEL_TOK 6
-
-u32 spkm3_make_token(struct spkm3_ctx *ctx, struct xdr_buf * text, struct xdr_netobj * token, int toktype);
-
-u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, struct xdr_buf *message_buffer, int toktype);
-
-#define CKSUMTYPE_RSA_MD5 0x0007
-#define CKSUMTYPE_HMAC_MD5 0x0008
-
-s32 make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header,
- unsigned int hdrlen, struct xdr_buf *body,
- unsigned int body_offset, struct xdr_netobj *cksum);
-void asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits);
-int decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen,
- int explen);
-void spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen,
- unsigned char *ctxhdr, int elen, int zbit);
-void spkm3_make_mic_token(unsigned char **tokp, int toklen,
- struct xdr_netobj *mic_hdr,
- struct xdr_netobj *md5cksum, int md5elen, int md5zbit);
-u32 spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen,
- unsigned char **cksum);
diff --git a/include/linux/sunrpc/stats.h b/include/linux/sunrpc/stats.h
index 5fa0f2084307..680471d1f28a 100644
--- a/include/linux/sunrpc/stats.h
+++ b/include/linux/sunrpc/stats.h
@@ -38,8 +38,21 @@ struct svc_stat {
rpcbadclnt;
};
-void rpc_proc_init(void);
-void rpc_proc_exit(void);
+struct net;
+#ifdef CONFIG_PROC_FS
+int rpc_proc_init(struct net *);
+void rpc_proc_exit(struct net *);
+#else
+static inline int rpc_proc_init(struct net *net)
+{
+ return 0;
+}
+
+static inline void rpc_proc_exit(struct net *net)
+{
+}
+#endif
+
#ifdef MODULE
void rpc_modcount(struct inode *, int);
#endif
@@ -54,9 +67,6 @@ void svc_proc_unregister(const char *);
void svc_seq_show(struct seq_file *,
const struct svc_stat *);
-
-extern struct proc_dir_entry *proc_net_rpc;
-
#else
static inline struct proc_dir_entry *rpc_proc_register(struct rpc_stat *s) { return NULL; }
@@ -69,9 +79,6 @@ static inline void svc_proc_unregister(const char *p) {}
static inline void svc_seq_show(struct seq_file *seq,
const struct svc_stat *st) {}
-
-#define proc_net_rpc NULL
-
#endif
#endif /* _LINUX_SUNRPC_STATS_H */
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
index 5f4e18b3ce73..bbdb680ffbe9 100644
--- a/include/linux/sunrpc/svc_xprt.h
+++ b/include/linux/sunrpc/svc_xprt.h
@@ -12,6 +12,7 @@
struct svc_xprt_ops {
struct svc_xprt *(*xpo_create)(struct svc_serv *,
+ struct net *net,
struct sockaddr *, int,
int);
struct svc_xprt *(*xpo_accept)(struct svc_xprt *);
@@ -32,6 +33,16 @@ struct svc_xprt_class {
u32 xcl_max_payload;
};
+/*
+ * This is embedded in an object that wants a callback before deleting
+ * an xprt; intended for use by NFSv4.1, which needs to know when a
+ * client's tcp connection (and hence possibly a backchannel) goes away.
+ */
+struct svc_xpt_user {
+ struct list_head list;
+ void (*callback)(struct svc_xpt_user *);
+};
+
struct svc_xprt {
struct svc_xprt_class *xpt_class;
struct svc_xprt_ops *xpt_ops;
@@ -66,14 +77,31 @@ struct svc_xprt {
struct sockaddr_storage xpt_remote; /* remote peer's address */
size_t xpt_remotelen; /* length of address */
struct rpc_wait_queue xpt_bc_pending; /* backchannel wait queue */
+ struct list_head xpt_users; /* callbacks on free */
+
+ struct net *xpt_net;
};
+static inline void register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
+{
+ spin_lock(&xpt->xpt_lock);
+ list_add(&u->list, &xpt->xpt_users);
+ spin_unlock(&xpt->xpt_lock);
+}
+
+static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
+{
+ spin_lock(&xpt->xpt_lock);
+ list_del_init(&u->list);
+ spin_unlock(&xpt->xpt_lock);
+}
+
int svc_reg_xprt_class(struct svc_xprt_class *);
void svc_unreg_xprt_class(struct svc_xprt_class *);
void svc_xprt_init(struct svc_xprt_class *, struct svc_xprt *,
struct svc_serv *);
-int svc_create_xprt(struct svc_serv *, const char *, const int,
- const unsigned short, int);
+int svc_create_xprt(struct svc_serv *, const char *, struct net *,
+ const int, const unsigned short, int);
void svc_xprt_enqueue(struct svc_xprt *xprt);
void svc_xprt_received(struct svc_xprt *);
void svc_xprt_put(struct svc_xprt *xprt);
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index d39dbdc7b10f..25d333c1b571 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -108,10 +108,15 @@ struct auth_ops {
#define SVC_NEGATIVE 4
#define SVC_OK 5
#define SVC_DROP 6
-#define SVC_DENIED 7
-#define SVC_PENDING 8
-#define SVC_COMPLETE 9
+#define SVC_CLOSE 7 /* Like SVC_DROP, but request is definitely
+ * lost so if there is a tcp connection, it
+ * should be closed
+ */
+#define SVC_DENIED 8
+#define SVC_PENDING 9
+#define SVC_COMPLETE 10
+struct svc_xprt;
extern int svc_authenticate(struct svc_rqst *rqstp, __be32 *authp);
extern int svc_authorise(struct svc_rqst *rqstp);
@@ -121,13 +126,13 @@ extern void svc_auth_unregister(rpc_authflavor_t flavor);
extern struct auth_domain *unix_domain_find(char *name);
extern void auth_domain_put(struct auth_domain *item);
-extern int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom);
+extern int auth_unix_add_addr(struct net *net, struct in6_addr *addr, struct auth_domain *dom);
extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new);
extern struct auth_domain *auth_domain_find(char *name);
-extern struct auth_domain *auth_unix_lookup(struct in6_addr *addr);
+extern struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr);
extern int auth_unix_forget_old(struct auth_domain *dom);
extern void svcauth_unix_purge(void);
-extern void svcauth_unix_info_release(void *);
+extern void svcauth_unix_info_release(struct svc_xprt *xpt);
extern int svcauth_unix_set_client(struct svc_rqst *rqstp);
static inline unsigned long hash_str(char *name, int bits)
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index 35cf2e8cd7c6..498ab93a81e4 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -108,6 +108,7 @@ void xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int,
unsigned int);
void xdr_inline_pages(struct xdr_buf *, unsigned int,
struct page **, unsigned int, unsigned int);
+void xdr_terminate_string(struct xdr_buf *, const u32);
static inline __be32 *xdr_encode_array(__be32 *p, const void *s, unsigned int len)
{
@@ -131,6 +132,13 @@ xdr_decode_hyper(__be32 *p, __u64 *valp)
return p + 2;
}
+static inline __be32 *
+xdr_decode_opaque_fixed(__be32 *p, void *ptr, unsigned int len)
+{
+ memcpy(ptr, p, len);
+ return p + XDR_QUADLEN(len);
+}
+
/*
* Adjust kvec to reflect end of xdr'ed data (RPC client XDR)
*/
@@ -200,6 +208,7 @@ extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
unsigned int base, unsigned int len);
extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
+extern __be32 *xdr_inline_peek(struct xdr_stream *xdr, size_t nbytes);
extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index ff5a77b28c50..89d10d279a20 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -224,6 +224,7 @@ struct rpc_xprt {
bklog_u; /* backlog queue utilization */
} stat;
+ struct net *xprt_net;
const char *address_strings[RPC_DISPLAY_MAX];
};
@@ -249,6 +250,7 @@ static inline int bc_prealloc(struct rpc_rqst *req)
struct xprt_create {
int ident; /* XPRT_TRANSPORT identifier */
+ struct net * net;
struct sockaddr * srcaddr; /* optional local address */
struct sockaddr * dstaddr; /* remote peer address */
size_t addrlen;
@@ -280,6 +282,8 @@ void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
void xprt_release(struct rpc_task *task);
struct rpc_xprt * xprt_get(struct rpc_xprt *xprt);
void xprt_put(struct rpc_xprt *xprt);
+struct rpc_xprt * xprt_alloc(struct net *net, int size, int max_req);
+void xprt_free(struct rpc_xprt *);
static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *p)
{
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 7cdd63366f88..eba53e71d2cc 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -271,8 +271,18 @@ extern void scan_mapping_unevictable_pages(struct address_space *);
extern unsigned long scan_unevictable_pages;
extern int scan_unevictable_handler(struct ctl_table *, int,
void __user *, size_t *, loff_t *);
+#ifdef CONFIG_NUMA
extern int scan_unevictable_register_node(struct node *node);
extern void scan_unevictable_unregister_node(struct node *node);
+#else
+static inline int scan_unevictable_register_node(struct node *node)
+{
+ return 0;
+}
+static inline void scan_unevictable_unregister_node(struct node *node)
+{
+}
+#endif
extern int kswapd_run(int nid);
extern void kswapd_stop(int nid);
diff --git a/include/linux/synclink.h b/include/linux/synclink.h
index 0ff2779c44d0..2e7d81c4e5ad 100644
--- a/include/linux/synclink.h
+++ b/include/linux/synclink.h
@@ -126,6 +126,7 @@
#define MGSL_MODE_BISYNC 4
#define MGSL_MODE_RAW 6
#define MGSL_MODE_BASE_CLOCK 7
+#define MGSL_MODE_XSYNC 8
#define MGSL_BUS_TYPE_ISA 1
#define MGSL_BUS_TYPE_EISA 2
@@ -290,6 +291,10 @@ struct gpio_desc {
#define MGSL_IOCSGPIO _IOW(MGSL_MAGIC_IOC,16,struct gpio_desc)
#define MGSL_IOCGGPIO _IOR(MGSL_MAGIC_IOC,17,struct gpio_desc)
#define MGSL_IOCWAITGPIO _IOWR(MGSL_MAGIC_IOC,18,struct gpio_desc)
+#define MGSL_IOCSXSYNC _IO(MGSL_MAGIC_IOC, 19)
+#define MGSL_IOCGXSYNC _IO(MGSL_MAGIC_IOC, 20)
+#define MGSL_IOCSXCTRL _IO(MGSL_MAGIC_IOC, 21)
+#define MGSL_IOCGXCTRL _IO(MGSL_MAGIC_IOC, 22)
#ifdef __KERNEL__
/* provide 32 bit ioctl compatibility on 64 bit systems */
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index e6319d18a55d..cacc27a0e285 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -701,7 +701,8 @@ asmlinkage long sys_nfsservctl(int cmd,
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);
-asmlinkage long sys_ptrace(long request, long pid, long addr, long data);
+asmlinkage long sys_ptrace(long request, long pid, unsigned long addr,
+ unsigned long data);
asmlinkage long sys_add_key(const char __user *_type,
const char __user *_description,
diff --git a/include/linux/tc_act/Kbuild b/include/linux/tc_act/Kbuild
index 76990937f4c9..67b501c302b2 100644
--- a/include/linux/tc_act/Kbuild
+++ b/include/linux/tc_act/Kbuild
@@ -4,3 +4,4 @@ header-y += tc_mirred.h
header-y += tc_pedit.h
header-y += tc_nat.h
header-y += tc_skbedit.h
+header-y += tc_csum.h
diff --git a/include/linux/tc_act/tc_csum.h b/include/linux/tc_act/tc_csum.h
new file mode 100644
index 000000000000..a047c49a3153
--- /dev/null
+++ b/include/linux/tc_act/tc_csum.h
@@ -0,0 +1,32 @@
+#ifndef __LINUX_TC_CSUM_H
+#define __LINUX_TC_CSUM_H
+
+#include <linux/types.h>
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_CSUM 16
+
+enum {
+ TCA_CSUM_UNSPEC,
+ TCA_CSUM_PARMS,
+ TCA_CSUM_TM,
+ __TCA_CSUM_MAX
+};
+#define TCA_CSUM_MAX (__TCA_CSUM_MAX - 1)
+
+enum {
+ TCA_CSUM_UPDATE_FLAG_IPV4HDR = 1,
+ TCA_CSUM_UPDATE_FLAG_ICMP = 2,
+ TCA_CSUM_UPDATE_FLAG_IGMP = 4,
+ TCA_CSUM_UPDATE_FLAG_TCP = 8,
+ TCA_CSUM_UPDATE_FLAG_UDP = 16,
+ TCA_CSUM_UPDATE_FLAG_UDPLITE = 32
+};
+
+struct tc_csum {
+ tc_gen;
+
+ __u32 update_flags;
+};
+
+#endif /* __LINUX_TC_CSUM_H */
diff --git a/include/linux/tc_ematch/tc_em_meta.h b/include/linux/tc_ematch/tc_em_meta.h
index 0864206ec1a3..7138962664f8 100644
--- a/include/linux/tc_ematch/tc_em_meta.h
+++ b/include/linux/tc_ematch/tc_em_meta.h
@@ -79,6 +79,7 @@ enum {
TCF_META_ID_SK_SENDMSG_OFF,
TCF_META_ID_SK_WRITE_PENDING,
TCF_META_ID_VLAN_TAG,
+ TCF_META_ID_RXHASH,
__TCF_META_ID_MAX
};
#define TCF_META_ID_MAX (__TCF_META_ID_MAX - 1)
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index a778ee024590..e64f4c67d0ef 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -105,6 +105,7 @@ enum {
#define TCP_COOKIE_TRANSACTIONS 15 /* TCP Cookie Transactions */
#define TCP_THIN_LINEAR_TIMEOUTS 16 /* Use linear timeouts for thin streams*/
#define TCP_THIN_DUPACK 17 /* Fast retrans. after 1 dupack */
+#define TCP_USER_TIMEOUT 18 /* How long for loss retry before timeout */
/* for TCP_INFO socket option */
#define TCPI_OPT_TIMESTAMPS 1
diff --git a/include/linux/tipc.h b/include/linux/tipc.h
index 181c8d0e6f73..d10614b29d59 100644
--- a/include/linux/tipc.h
+++ b/include/linux/tipc.h
@@ -127,17 +127,23 @@ static inline unsigned int tipc_node(__u32 addr)
* TIPC topology subscription service definitions
*/
-#define TIPC_SUB_SERVICE 0x00 /* Filter for service availability */
-#define TIPC_SUB_PORTS 0x01 /* Filter for port availability */
-#define TIPC_SUB_CANCEL 0x04 /* Cancel a subscription */
+#define TIPC_SUB_PORTS 0x01 /* filter for port availability */
+#define TIPC_SUB_SERVICE 0x02 /* filter for service availability */
+#define TIPC_SUB_CANCEL 0x04 /* cancel a subscription */
+#if 0
+/* The following filter options are not currently implemented */
+#define TIPC_SUB_NO_BIND_EVTS 0x04 /* filter out "publish" events */
+#define TIPC_SUB_NO_UNBIND_EVTS 0x08 /* filter out "withdraw" events */
+#define TIPC_SUB_SINGLE_EVT 0x10 /* expire after first event */
+#endif
#define TIPC_WAIT_FOREVER ~0 /* timeout for permanent subscription */
struct tipc_subscr {
- struct tipc_name_seq seq; /* NBO. Name sequence of interest */
- __u32 timeout; /* NBO. Subscription duration (in ms) */
- __u32 filter; /* NBO. Bitmask of filter options */
- char usr_handle[8]; /* Opaque. Available for subscriber use */
+ struct tipc_name_seq seq; /* name sequence of interest */
+ __u32 timeout; /* subscription duration (in ms) */
+ __u32 filter; /* bitmask of filter options */
+ char usr_handle[8]; /* available for subscriber use */
};
#define TIPC_PUBLISHED 1 /* publication event */
@@ -145,11 +151,11 @@ struct tipc_subscr {
#define TIPC_SUBSCR_TIMEOUT 3 /* subscription timeout event */
struct tipc_event {
- __u32 event; /* NBO. Event type, as defined above */
- __u32 found_lower; /* NBO. Matching name seq instances */
- __u32 found_upper; /* " " " " " */
- struct tipc_portid port; /* NBO. Associated port */
- struct tipc_subscr s; /* Original, associated subscription */
+ __u32 event; /* event type */
+ __u32 found_lower; /* matching name seq instances */
+ __u32 found_upper; /* " " " " */
+ struct tipc_portid port; /* associated port */
+ struct tipc_subscr s; /* associated subscription */
};
/*
diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
index 10db0102a890..3a2e66d88a32 100644
--- a/include/linux/tracehook.h
+++ b/include/linux/tracehook.h
@@ -150,7 +150,7 @@ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step)
*
* Return %LSM_UNSAFE_* bits applied to an exec because of tracing.
*
- * @task->cred_guard_mutex is held by the caller through the do_execve().
+ * @task->signal->cred_guard_mutex is held by the caller through the do_execve().
*/
static inline int tracehook_unsafe_exec(struct task_struct *task)
{
diff --git a/include/linux/types.h b/include/linux/types.h
index 357dbc19606f..c2a9eb44f2fa 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -121,15 +121,7 @@ typedef __u64 u_int64_t;
typedef __s64 int64_t;
#endif
-/*
- * aligned_u64 should be used in defining kernel<->userspace ABIs to avoid
- * common 32/64-bit compat problems.
- * 64-bit values align to 4-byte boundaries on x86_32 (and possibly other
- * architectures) and to 8-byte boundaries on 64-bit architetures. The new
- * aligned_64 type enforces 8-byte alignment so that structs containing
- * aligned_64 values have the same alignment on 32-bit and 64-bit architectures.
- * No conversions are necessary between 32-bit user-space and a 64-bit kernel.
- */
+/* this is a special 64bit data type that is 8-byte aligned */
#define aligned_u64 __u64 __attribute__((aligned(8)))
#define aligned_be64 __be64 __attribute__((aligned(8)))
#define aligned_le64 __le64 __attribute__((aligned(8)))
@@ -186,7 +178,15 @@ typedef __u64 __bitwise __be64;
typedef __u16 __bitwise __sum16;
typedef __u32 __bitwise __wsum;
-/* this is a special 64bit data type that is 8-byte aligned */
+/*
+ * aligned_u64 should be used in defining kernel<->userspace ABIs to avoid
+ * common 32/64-bit compat problems.
+ * 64-bit values align to 4-byte boundaries on x86_32 (and possibly other
+ * architectures) and to 8-byte boundaries on 64-bit architetures. The new
+ * aligned_64 type enforces 8-byte alignment so that structs containing
+ * aligned_64 values have the same alignment on 32-bit and 64-bit architectures.
+ * No conversions are necessary between 32-bit user-space and a 64-bit kernel.
+ */
#define __aligned_u64 __u64 __attribute__((aligned(8)))
#define __aligned_be64 __be64 __attribute__((aligned(8)))
#define __aligned_le64 __le64 __attribute__((aligned(8)))
diff --git a/include/linux/virtio_9p.h b/include/linux/virtio_9p.h
index 1faa80d92f05..e68b439b2860 100644
--- a/include/linux/virtio_9p.h
+++ b/include/linux/virtio_9p.h
@@ -5,7 +5,6 @@
#include <linux/types.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
-#include <linux/types.h>
/* The feature bitmap for virtio 9P */
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 63a4fe6d51bd..a03dcf62ca9d 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -53,8 +53,10 @@ static inline void vmalloc_init(void)
#endif
extern void *vmalloc(unsigned long size);
+extern void *vzalloc(unsigned long size);
extern void *vmalloc_user(unsigned long size);
extern void *vmalloc_node(unsigned long size, int node);
+extern void *vzalloc_node(unsigned long size, int node);
extern void *vmalloc_exec(unsigned long size);
extern void *vmalloc_32(unsigned long size);
extern void *vmalloc_32_user(unsigned long size);
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index e6827eedf18b..4395b28bb86c 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -1157,6 +1157,6 @@ struct __compat_iw_event {
#define IW_EV_PARAM_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_param))
#define IW_EV_ADDR_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct sockaddr))
#define IW_EV_QUAL_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_quality))
-#define IW_EV_POINT_PK_LEN (IW_EV_LCP_LEN + 4)
+#define IW_EV_POINT_PK_LEN (IW_EV_LCP_PK_LEN + 4)
#endif /* _LINUX_WIRELESS_H */
diff --git a/include/linux/spi/wl12xx.h b/include/linux/wl12xx.h
index a223ecbc71ef..4f902e1908aa 100644
--- a/include/linux/spi/wl12xx.h
+++ b/include/linux/wl12xx.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2009 Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -21,14 +21,31 @@
*
*/
-#ifndef _LINUX_SPI_WL12XX_H
-#define _LINUX_SPI_WL12XX_H
+#ifndef _LINUX_WL12XX_H
+#define _LINUX_WL12XX_H
struct wl12xx_platform_data {
void (*set_power)(bool enable);
/* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */
int irq;
bool use_eeprom;
+ int board_ref_clock;
};
+#ifdef CONFIG_WL12XX_PLATFORM_DATA
+
+int wl12xx_set_platform_data(const struct wl12xx_platform_data *data);
+
+#else
+
+static inline
+int wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
+{
+ return -ENOSYS;
+}
+
+#endif
+
+const struct wl12xx_platform_data *wl12xx_get_platform_data(void);
+
#endif
diff --git a/include/linux/wlp.h b/include/linux/wlp.h
deleted file mode 100644
index c76fe2392506..000000000000
--- a/include/linux/wlp.h
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * WiMedia Logical Link Control Protocol (WLP)
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- *
- * - Does not (yet) include support for WLP control frames
- * WLP Draft 0.99 [6.5].
- *
- * A visual representation of the data structures.
- *
- * wssidB wssidB
- * ^ ^
- * | |
- * wssidA wssidA
- * wlp interface { ^ ^
- * ... | |
- * ... ... wssid wssid ...
- * wlp --- ... | |
- * }; neighbors --> neighbA --> neighbB
- * ...
- * wss
- * ...
- * eda cache --> neighborA --> neighborB --> neighborC ...
- */
-
-#ifndef __LINUX__WLP_H_
-#define __LINUX__WLP_H_
-
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/list.h>
-#include <linux/uwb.h>
-
-/**
- * WLP Protocol ID
- * WLP Draft 0.99 [6.2]
- *
- * The MUX header for all WLP frames
- */
-#define WLP_PROTOCOL_ID 0x0100
-
-/**
- * WLP Version
- * WLP version placed in the association frames (WLP 0.99 [6.6])
- */
-#define WLP_VERSION 0x10
-
-/**
- * Bytes needed to print UUID as string
- */
-#define WLP_WSS_UUID_STRSIZE 48
-
-/**
- * Bytes needed to print nonce as string
- */
-#define WLP_WSS_NONCE_STRSIZE 48
-
-
-/**
- * Size used for WLP name size
- *
- * The WSS name is set to 65 bytes, 1 byte larger than the maximum
- * allowed by the WLP spec. This is to have a null terminated string
- * for display to the user. A maximum of 64 bytes will still be used
- * when placing the WSS name field in association frames.
- */
-#define WLP_WSS_NAME_SIZE 65
-
-/**
- * Number of bytes added by WLP to data frame
- *
- * A data frame transmitted from a host will be placed in a Standard or
- * Abbreviated WLP frame. These have an extra 4 bytes of header (struct
- * wlp_frame_std_abbrv_hdr).
- * When the stack sends this data frame for transmission it needs to ensure
- * there is enough headroom for this header.
- */
-#define WLP_DATA_HLEN 4
-
-/**
- * State of device regarding WLP Service Set
- *
- * WLP_WSS_STATE_NONE: the host does not participate in any WSS
- * WLP_WSS_STATE_PART_ENROLLED: used as part of the enrollment sequence
- * ("Partial Enroll"). This state is used to
- * indicate the first part of enrollment that is
- * unsecure. If the WSS is unsecure then the
- * state will promptly go to WLP_WSS_STATE_ENROLLED,
- * if the WSS is not secure then the enrollment
- * procedure is a few more steps before we are
- * enrolled.
- * WLP_WSS_STATE_ENROLLED: the host is enrolled in a WSS
- * WLP_WSS_STATE_ACTIVE: WSS is activated
- * WLP_WSS_STATE_CONNECTED: host is connected to neighbor in WSS
- *
- */
-enum wlp_wss_state {
- WLP_WSS_STATE_NONE = 0,
- WLP_WSS_STATE_PART_ENROLLED,
- WLP_WSS_STATE_ENROLLED,
- WLP_WSS_STATE_ACTIVE,
- WLP_WSS_STATE_CONNECTED,
-};
-
-/**
- * WSS Secure status
- * WLP 0.99 Table 6
- *
- * Set to one if the WSS is secure, zero if it is not secure
- */
-enum wlp_wss_sec_status {
- WLP_WSS_UNSECURE = 0,
- WLP_WSS_SECURE,
-};
-
-/**
- * WLP frame type
- * WLP Draft 0.99 [6.2 Table 1]
- */
-enum wlp_frame_type {
- WLP_FRAME_STANDARD = 0,
- WLP_FRAME_ABBREVIATED,
- WLP_FRAME_CONTROL,
- WLP_FRAME_ASSOCIATION,
-};
-
-/**
- * WLP Association Message Type
- * WLP Draft 0.99 [6.6.1.2 Table 8]
- */
-enum wlp_assoc_type {
- WLP_ASSOC_D1 = 2,
- WLP_ASSOC_D2 = 3,
- WLP_ASSOC_M1 = 4,
- WLP_ASSOC_M2 = 5,
- WLP_ASSOC_M3 = 7,
- WLP_ASSOC_M4 = 8,
- WLP_ASSOC_M5 = 9,
- WLP_ASSOC_M6 = 10,
- WLP_ASSOC_M7 = 11,
- WLP_ASSOC_M8 = 12,
- WLP_ASSOC_F0 = 14,
- WLP_ASSOC_E1 = 32,
- WLP_ASSOC_E2 = 33,
- WLP_ASSOC_C1 = 34,
- WLP_ASSOC_C2 = 35,
- WLP_ASSOC_C3 = 36,
- WLP_ASSOC_C4 = 37,
-};
-
-/**
- * WLP Attribute Type
- * WLP Draft 0.99 [6.6.1 Table 6]
- */
-enum wlp_attr_type {
- WLP_ATTR_AUTH = 0x1005, /* Authenticator */
- WLP_ATTR_DEV_NAME = 0x1011, /* Device Name */
- WLP_ATTR_DEV_PWD_ID = 0x1012, /* Device Password ID */
- WLP_ATTR_E_HASH1 = 0x1014, /* E-Hash1 */
- WLP_ATTR_E_HASH2 = 0x1015, /* E-Hash2 */
- WLP_ATTR_E_SNONCE1 = 0x1016, /* E-SNonce1 */
- WLP_ATTR_E_SNONCE2 = 0x1017, /* E-SNonce2 */
- WLP_ATTR_ENCR_SET = 0x1018, /* Encrypted Settings */
- WLP_ATTR_ENRL_NONCE = 0x101A, /* Enrollee Nonce */
- WLP_ATTR_KEYWRAP_AUTH = 0x101E, /* Key Wrap Authenticator */
- WLP_ATTR_MANUF = 0x1021, /* Manufacturer */
- WLP_ATTR_MSG_TYPE = 0x1022, /* Message Type */
- WLP_ATTR_MODEL_NAME = 0x1023, /* Model Name */
- WLP_ATTR_MODEL_NR = 0x1024, /* Model Number */
- WLP_ATTR_PUB_KEY = 0x1032, /* Public Key */
- WLP_ATTR_REG_NONCE = 0x1039, /* Registrar Nonce */
- WLP_ATTR_R_HASH1 = 0x103D, /* R-Hash1 */
- WLP_ATTR_R_HASH2 = 0x103E, /* R-Hash2 */
- WLP_ATTR_R_SNONCE1 = 0x103F, /* R-SNonce1 */
- WLP_ATTR_R_SNONCE2 = 0x1040, /* R-SNonce2 */
- WLP_ATTR_SERIAL = 0x1042, /* Serial number */
- WLP_ATTR_UUID_E = 0x1047, /* UUID-E */
- WLP_ATTR_UUID_R = 0x1048, /* UUID-R */
- WLP_ATTR_PRI_DEV_TYPE = 0x1054, /* Primary Device Type */
- WLP_ATTR_SEC_DEV_TYPE = 0x1055, /* Secondary Device Type */
- WLP_ATTR_PORT_DEV = 0x1056, /* Portable Device */
- WLP_ATTR_APP_EXT = 0x1058, /* Application Extension */
- WLP_ATTR_WLP_VER = 0x2000, /* WLP Version */
- WLP_ATTR_WSSID = 0x2001, /* WSSID */
- WLP_ATTR_WSS_NAME = 0x2002, /* WSS Name */
- WLP_ATTR_WSS_SEC_STAT = 0x2003, /* WSS Secure Status */
- WLP_ATTR_WSS_BCAST = 0x2004, /* WSS Broadcast Address */
- WLP_ATTR_WSS_M_KEY = 0x2005, /* WSS Master Key */
- WLP_ATTR_ACC_ENRL = 0x2006, /* Accepting Enrollment */
- WLP_ATTR_WSS_INFO = 0x2007, /* WSS Information */
- WLP_ATTR_WSS_SEL_MTHD = 0x2008, /* WSS Selection Method */
- WLP_ATTR_ASSC_MTHD_LIST = 0x2009, /* Association Methods List */
- WLP_ATTR_SEL_ASSC_MTHD = 0x200A, /* Selected Association Method */
- WLP_ATTR_ENRL_HASH_COMM = 0x200B, /* Enrollee Hash Commitment */
- WLP_ATTR_WSS_TAG = 0x200C, /* WSS Tag */
- WLP_ATTR_WSS_VIRT = 0x200D, /* WSS Virtual EUI-48 */
- WLP_ATTR_WLP_ASSC_ERR = 0x200E, /* WLP Association Error */
- WLP_ATTR_VNDR_EXT = 0x200F, /* Vendor Extension */
-};
-
-/**
- * WLP Category ID of primary/secondary device
- * WLP Draft 0.99 [6.6.1.8 Table 12]
- */
-enum wlp_dev_category_id {
- WLP_DEV_CAT_COMPUTER = 1,
- WLP_DEV_CAT_INPUT,
- WLP_DEV_CAT_PRINT_SCAN_FAX_COPIER,
- WLP_DEV_CAT_CAMERA,
- WLP_DEV_CAT_STORAGE,
- WLP_DEV_CAT_INFRASTRUCTURE,
- WLP_DEV_CAT_DISPLAY,
- WLP_DEV_CAT_MULTIM,
- WLP_DEV_CAT_GAMING,
- WLP_DEV_CAT_TELEPHONE,
- WLP_DEV_CAT_OTHER = 65535,
-};
-
-/**
- * WLP WSS selection method
- * WLP Draft 0.99 [6.6.1.6 Table 10]
- */
-enum wlp_wss_sel_mthd {
- WLP_WSS_ENRL_SELECT = 1, /* Enrollee selects */
- WLP_WSS_REG_SELECT, /* Registrar selects */
-};
-
-/**
- * WLP association error values
- * WLP Draft 0.99 [6.6.1.5 Table 9]
- */
-enum wlp_assc_error {
- WLP_ASSOC_ERROR_NONE,
- WLP_ASSOC_ERROR_AUTH, /* Authenticator Failure */
- WLP_ASSOC_ERROR_ROGUE, /* Rogue activity suspected */
- WLP_ASSOC_ERROR_BUSY, /* Device busy */
- WLP_ASSOC_ERROR_LOCK, /* Setup Locked */
- WLP_ASSOC_ERROR_NOT_READY, /* Registrar not ready */
- WLP_ASSOC_ERROR_INV, /* Invalid WSS selection */
- WLP_ASSOC_ERROR_MSG_TIME, /* Message timeout */
- WLP_ASSOC_ERROR_ENR_TIME, /* Enrollment session timeout */
- WLP_ASSOC_ERROR_PW, /* Device password invalid */
- WLP_ASSOC_ERROR_VER, /* Unsupported version */
- WLP_ASSOC_ERROR_INT, /* Internal error */
- WLP_ASSOC_ERROR_UNDEF, /* Undefined error */
- WLP_ASSOC_ERROR_NUM, /* Numeric comparison failure */
- WLP_ASSOC_ERROR_WAIT, /* Waiting for user input */
-};
-
-/**
- * WLP Parameters
- * WLP 0.99 [7.7]
- */
-enum wlp_parameters {
- WLP_PER_MSG_TIMEOUT = 15, /* Seconds to wait for response to
- association message. */
-};
-
-/**
- * WLP IE
- *
- * The WLP IE should be included in beacons by all devices.
- *
- * The driver can set only a few of the fields in this information element,
- * most fields are managed by the device self. When the driver needs to set
- * a field it will only provide values for the fields of interest, the rest
- * will be filled with zeroes. The fields of interest are:
- *
- * Element ID
- * Length
- * Capabilities (only to include WSSID Hash list length)
- * WSSID Hash List fields
- *
- * WLP 0.99 [6.7]
- *
- * Only the fields that will be used are detailed in this structure, rest
- * are not detailed or marked as "notused".
- */
-struct wlp_ie {
- struct uwb_ie_hdr hdr;
- __le16 capabilities;
- __le16 cycle_param;
- __le16 acw_anchor_addr;
- u8 wssid_hash_list[];
-} __packed;
-
-static inline int wlp_ie_hash_length(struct wlp_ie *ie)
-{
- return (le16_to_cpu(ie->capabilities) >> 12) & 0xf;
-}
-
-static inline void wlp_ie_set_hash_length(struct wlp_ie *ie, int hash_length)
-{
- u16 caps = le16_to_cpu(ie->capabilities);
- caps = (caps & ~(0xf << 12)) | (hash_length << 12);
- ie->capabilities = cpu_to_le16(caps);
-}
-
-/**
- * WLP nonce
- * WLP Draft 0.99 [6.6.1 Table 6]
- *
- * A 128-bit random number often used (E-SNonce1, E-SNonce2, Enrollee
- * Nonce, Registrar Nonce, R-SNonce1, R-SNonce2). It is passed to HW so
- * it is packed.
- */
-struct wlp_nonce {
- u8 data[16];
-} __packed;
-
-/**
- * WLP UUID
- * WLP Draft 0.99 [6.6.1 Table 6]
- *
- * Universally Unique Identifier (UUID) encoded as an octet string in the
- * order the octets are shown in string representation in RFC4122. A UUID
- * is often used (UUID-E, UUID-R, WSSID). It is passed to HW so it is packed.
- */
-struct wlp_uuid {
- u8 data[16];
-} __packed;
-
-
-/**
- * Primary and secondary device type attributes
- * WLP Draft 0.99 [6.6.1.8]
- */
-struct wlp_dev_type {
- enum wlp_dev_category_id category:16;
- u8 OUI[3];
- u8 OUIsubdiv;
- __le16 subID;
-} __packed;
-
-/**
- * WLP frame header
- * WLP Draft 0.99 [6.2]
- */
-struct wlp_frame_hdr {
- __le16 mux_hdr; /* WLP_PROTOCOL_ID */
- enum wlp_frame_type type:8;
-} __packed;
-
-/**
- * WLP attribute field header
- * WLP Draft 0.99 [6.6.1]
- *
- * Header of each attribute found in an association frame
- */
-struct wlp_attr_hdr {
- __le16 type;
- __le16 length;
-} __packed;
-
-/**
- * Device information commonly used together
- *
- * Each of these device information elements has a specified range in which it
- * should fit (WLP 0.99 [Table 6]). This range provided in the spec does not
- * include the termination null '\0' character (when used in the
- * association protocol the attribute fields are accompanied
- * with a "length" field so the full range from the spec can be used for
- * the value). We thus allocate an extra byte to be able to store a string
- * of max length with a terminating '\0'.
- */
-struct wlp_device_info {
- char name[33];
- char model_name[33];
- char manufacturer[65];
- char model_nr[33];
- char serial[33];
- struct wlp_dev_type prim_dev_type;
-};
-
-/**
- * Macros for the WLP attributes
- *
- * There are quite a few attributes (total is 43). The attribute layout can be
- * in one of three categories: one value, an array, an enum forced to 8 bits.
- * These macros help with their definitions.
- */
-#define wlp_attr(type, name) \
-struct wlp_attr_##name { \
- struct wlp_attr_hdr hdr; \
- type name; \
-} __packed;
-
-#define wlp_attr_array(type, name) \
-struct wlp_attr_##name { \
- struct wlp_attr_hdr hdr; \
- type name[]; \
-} __packed;
-
-/**
- * WLP association attribute fields
- * WLP Draft 0.99 [6.6.1 Table 6]
- *
- * Attributes appear in same order as the Table in the spec
- * FIXME Does not define all attributes yet
- */
-
-/* Device name: Friendly name of sending device */
-wlp_attr_array(u8, dev_name)
-
-/* Enrollee Nonce: Random number generated by enrollee for an enrollment
- * session */
-wlp_attr(struct wlp_nonce, enonce)
-
-/* Manufacturer name: Name of manufacturer of the sending device */
-wlp_attr_array(u8, manufacturer)
-
-/* WLP Message Type */
-wlp_attr(u8, msg_type)
-
-/* WLP Model name: Model name of sending device */
-wlp_attr_array(u8, model_name)
-
-/* WLP Model number: Model number of sending device */
-wlp_attr_array(u8, model_nr)
-
-/* Registrar Nonce: Random number generated by registrar for an enrollment
- * session */
-wlp_attr(struct wlp_nonce, rnonce)
-
-/* Serial number of device */
-wlp_attr_array(u8, serial)
-
-/* UUID of enrollee */
-wlp_attr(struct wlp_uuid, uuid_e)
-
-/* UUID of registrar */
-wlp_attr(struct wlp_uuid, uuid_r)
-
-/* WLP Primary device type */
-wlp_attr(struct wlp_dev_type, prim_dev_type)
-
-/* WLP Secondary device type */
-wlp_attr(struct wlp_dev_type, sec_dev_type)
-
-/* WLP protocol version */
-wlp_attr(u8, version)
-
-/* WLP service set identifier */
-wlp_attr(struct wlp_uuid, wssid)
-
-/* WLP WSS name */
-wlp_attr_array(u8, wss_name)
-
-/* WLP WSS Secure Status */
-wlp_attr(u8, wss_sec_status)
-
-/* WSS Broadcast Address */
-wlp_attr(struct uwb_mac_addr, wss_bcast)
-
-/* WLP Accepting Enrollment */
-wlp_attr(u8, accept_enrl)
-
-/**
- * WSS information attributes
- * WLP Draft 0.99 [6.6.3 Table 15]
- */
-struct wlp_wss_info {
- struct wlp_attr_wssid wssid;
- struct wlp_attr_wss_name name;
- struct wlp_attr_accept_enrl accept;
- struct wlp_attr_wss_sec_status sec_stat;
- struct wlp_attr_wss_bcast bcast;
-} __packed;
-
-/* WLP WSS Information */
-wlp_attr_array(struct wlp_wss_info, wss_info)
-
-/* WLP WSS Selection method */
-wlp_attr(u8, wss_sel_mthd)
-
-/* WLP WSS tag */
-wlp_attr(u8, wss_tag)
-
-/* WSS Virtual Address */
-wlp_attr(struct uwb_mac_addr, wss_virt)
-
-/* WLP association error */
-wlp_attr(u8, wlp_assc_err)
-
-/**
- * WLP standard and abbreviated frames
- *
- * WLP Draft 0.99 [6.3] and [6.4]
- *
- * The difference between the WLP standard frame and the WLP
- * abbreviated frame is that the standard frame includes the src
- * and dest addresses from the Ethernet header, the abbreviated frame does
- * not.
- * The src/dest (as well as the type/length and client data) are already
- * defined as part of the Ethernet header, we do not do this here.
- * From this perspective the standard and abbreviated frames appear the
- * same - they will be treated differently though.
- *
- * The size of this header is also captured in WLP_DATA_HLEN to enable
- * interfaces to prepare their headroom.
- */
-struct wlp_frame_std_abbrv_hdr {
- struct wlp_frame_hdr hdr;
- u8 tag;
-} __packed;
-
-/**
- * WLP association frames
- *
- * WLP Draft 0.99 [6.6]
- */
-struct wlp_frame_assoc {
- struct wlp_frame_hdr hdr;
- enum wlp_assoc_type type:8;
- struct wlp_attr_version version;
- struct wlp_attr_msg_type msg_type;
- u8 attr[];
-} __packed;
-
-/* Ethernet to dev address mapping */
-struct wlp_eda {
- spinlock_t lock;
- struct list_head cache; /* Eth<->Dev Addr cache */
-};
-
-/**
- * WSS information temporary storage
- *
- * This information is only stored temporarily during discovery. It should
- * not be stored unless the device is enrolled in the advertised WSS. This
- * is done mainly because we follow the letter of the spec in this regard.
- * See WLP 0.99 [7.2.3].
- * When the device does become enrolled in a WSS the WSS information will
- * be stored as part of the more comprehensive struct wlp_wss.
- */
-struct wlp_wss_tmp_info {
- char name[WLP_WSS_NAME_SIZE];
- u8 accept_enroll;
- u8 sec_status;
- struct uwb_mac_addr bcast;
-};
-
-struct wlp_wssid_e {
- struct list_head node;
- struct wlp_uuid wssid;
- struct wlp_wss_tmp_info *info;
-};
-
-/**
- * A cache entry of WLP neighborhood
- *
- * @node: head of list is wlp->neighbors
- * @wssid: list of wssids of this neighbor, element is wlp_wssid_e
- * @info: temporary storage for information learned during discovery. This
- * storage is used together with the wssid_e temporary storage
- * during discovery.
- */
-struct wlp_neighbor_e {
- struct list_head node;
- struct wlp_uuid uuid;
- struct uwb_dev *uwb_dev;
- struct list_head wssid; /* Elements are wlp_wssid_e */
- struct wlp_device_info *info;
-};
-
-struct wlp;
-/**
- * Information for an association session in progress.
- *
- * @exp_message: The type of the expected message. Both this message and a
- * F0 message (which can be sent in response to any
- * association frame) will be accepted as a valid message for
- * this session.
- * @cb: The function that will be called upon receipt of this
- * message.
- * @cb_priv: Private data of callback
- * @data: Data used in association process (always a sk_buff?)
- * @neighbor: Address of neighbor with which association session is in
- * progress.
- */
-struct wlp_session {
- enum wlp_assoc_type exp_message;
- void (*cb)(struct wlp *);
- void *cb_priv;
- void *data;
- struct uwb_dev_addr neighbor_addr;
-};
-
-/**
- * WLP Service Set
- *
- * @mutex: used to protect entire WSS structure.
- *
- * @name: The WSS name is set to 65 bytes, 1 byte larger than the maximum
- * allowed by the WLP spec. This is to have a null terminated string
- * for display to the user. A maximum of 64 bytes will still be used
- * when placing the WSS name field in association frames.
- *
- * @accept_enroll: Accepting enrollment: Set to one if registrar is
- * accepting enrollment in WSS, or zero otherwise.
- *
- * Global and local information for each WSS in which we are enrolled.
- * WLP 0.99 Section 7.2.1 and Section 7.2.2
- */
-struct wlp_wss {
- struct mutex mutex;
- struct kobject kobj;
- /* Global properties. */
- struct wlp_uuid wssid;
- u8 hash;
- char name[WLP_WSS_NAME_SIZE];
- struct uwb_mac_addr bcast;
- u8 secure_status:1;
- u8 master_key[16];
- /* Local properties. */
- u8 tag;
- struct uwb_mac_addr virtual_addr;
- /* Extra */
- u8 accept_enroll:1;
- enum wlp_wss_state state;
-};
-
-/**
- * WLP main structure
- * @mutex: protect changes to WLP structure. We only allow changes to the
- * uuid, so currently this mutex only protects this field.
- */
-struct wlp {
- struct mutex mutex;
- struct uwb_rc *rc; /* UWB radio controller */
- struct net_device *ndev;
- struct uwb_pal pal;
- struct wlp_eda eda;
- struct wlp_uuid uuid;
- struct wlp_session *session;
- struct wlp_wss wss;
- struct mutex nbmutex; /* Neighbor mutex protects neighbors list */
- struct list_head neighbors; /* Elements are wlp_neighbor_e */
- struct uwb_notifs_handler uwb_notifs_handler;
- struct wlp_device_info *dev_info;
- void (*fill_device_info)(struct wlp *wlp, struct wlp_device_info *info);
- int (*xmit_frame)(struct wlp *, struct sk_buff *,
- struct uwb_dev_addr *);
- void (*stop_queue)(struct wlp *);
- void (*start_queue)(struct wlp *);
-};
-
-/* sysfs */
-
-
-struct wlp_wss_attribute {
- struct attribute attr;
- ssize_t (*show)(struct wlp_wss *wss, char *buf);
- ssize_t (*store)(struct wlp_wss *wss, const char *buf, size_t count);
-};
-
-#define WSS_ATTR(_name, _mode, _show, _store) \
-static struct wlp_wss_attribute wss_attr_##_name = __ATTR(_name, _mode, \
- _show, _store)
-
-extern int wlp_setup(struct wlp *, struct uwb_rc *, struct net_device *ndev);
-extern void wlp_remove(struct wlp *);
-extern ssize_t wlp_neighborhood_show(struct wlp *, char *);
-extern int wlp_wss_setup(struct net_device *, struct wlp_wss *);
-extern void wlp_wss_remove(struct wlp_wss *);
-extern ssize_t wlp_wss_activate_show(struct wlp_wss *, char *);
-extern ssize_t wlp_wss_activate_store(struct wlp_wss *, const char *, size_t);
-extern ssize_t wlp_eda_show(struct wlp *, char *);
-extern ssize_t wlp_eda_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_uuid_show(struct wlp *, char *);
-extern ssize_t wlp_uuid_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_dev_name_show(struct wlp *, char *);
-extern ssize_t wlp_dev_name_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_dev_manufacturer_show(struct wlp *, char *);
-extern ssize_t wlp_dev_manufacturer_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_dev_model_name_show(struct wlp *, char *);
-extern ssize_t wlp_dev_model_name_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_dev_model_nr_show(struct wlp *, char *);
-extern ssize_t wlp_dev_model_nr_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_dev_serial_show(struct wlp *, char *);
-extern ssize_t wlp_dev_serial_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_dev_prim_category_show(struct wlp *, char *);
-extern ssize_t wlp_dev_prim_category_store(struct wlp *, const char *,
- size_t);
-extern ssize_t wlp_dev_prim_OUI_show(struct wlp *, char *);
-extern ssize_t wlp_dev_prim_OUI_store(struct wlp *, const char *, size_t);
-extern ssize_t wlp_dev_prim_OUI_sub_show(struct wlp *, char *);
-extern ssize_t wlp_dev_prim_OUI_sub_store(struct wlp *, const char *,
- size_t);
-extern ssize_t wlp_dev_prim_subcat_show(struct wlp *, char *);
-extern ssize_t wlp_dev_prim_subcat_store(struct wlp *, const char *,
- size_t);
-extern int wlp_receive_frame(struct device *, struct wlp *, struct sk_buff *,
- struct uwb_dev_addr *);
-extern int wlp_prepare_tx_frame(struct device *, struct wlp *,
- struct sk_buff *, struct uwb_dev_addr *);
-void wlp_reset_all(struct wlp *wlp);
-
-/**
- * Initialize WSS
- */
-static inline
-void wlp_wss_init(struct wlp_wss *wss)
-{
- mutex_init(&wss->mutex);
-}
-
-static inline
-void wlp_init(struct wlp *wlp)
-{
- INIT_LIST_HEAD(&wlp->neighbors);
- mutex_init(&wlp->mutex);
- mutex_init(&wlp->nbmutex);
- wlp_wss_init(&wlp->wss);
-}
-
-
-#endif /* #ifndef __LINUX__WLP_H_ */
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 070bb7a88936..0c0771f06bfa 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -190,7 +190,7 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
__INIT_WORK((_work), (_func), 0); \
} while (0)
-#define INIT_WORK_ON_STACK(_work, _func) \
+#define INIT_WORK_ONSTACK(_work, _func) \
do { \
__INIT_WORK((_work), (_func), 1); \
} while (0)
@@ -201,9 +201,9 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
init_timer(&(_work)->timer); \
} while (0)
-#define INIT_DELAYED_WORK_ON_STACK(_work, _func) \
+#define INIT_DELAYED_WORK_ONSTACK(_work, _func) \
do { \
- INIT_WORK_ON_STACK(&(_work)->work, (_func)); \
+ INIT_WORK_ONSTACK(&(_work)->work, (_func)); \
init_timer_on_stack(&(_work)->timer); \
} while (0)
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 72a5d647a5f2..09eec350054d 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -10,8 +10,6 @@
struct backing_dev_info;
extern spinlock_t inode_lock;
-extern struct list_head inode_in_use;
-extern struct list_head inode_unused;
/*
* fs/fs-writeback.c
@@ -143,12 +141,16 @@ typedef int (*writepage_t)(struct page *page, struct writeback_control *wbc,
int generic_writepages(struct address_space *mapping,
struct writeback_control *wbc);
+void tag_pages_for_writeback(struct address_space *mapping,
+ pgoff_t start, pgoff_t end);
int write_cache_pages(struct address_space *mapping,
struct writeback_control *wbc, writepage_t writepage,
void *data);
int do_writepages(struct address_space *mapping, struct writeback_control *wbc);
void set_page_dirty_balance(struct page *page, int page_mkwrite);
void writeback_set_ratelimit(void);
+void tag_pages_for_writeback(struct address_space *mapping,
+ pgoff_t start, pgoff_t end);
/* pdflush.c */
extern int nr_pdflush_threads; /* Global so it can be exported to sysctl
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index a9c041d49662..9b201ec8dc7f 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -35,7 +35,7 @@ struct ir_scancode_table {
unsigned int len; /* Used number of entries */
unsigned int alloc; /* Size of *scan in bytes */
u64 ir_type;
- char *name;
+ const char *name;
spinlock_t lock;
};
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index a8de812ccbc8..071fd7a8d781 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -86,6 +86,8 @@ do { \
/**
* enum p9_msg_t - 9P message types
+ * @P9_TLERROR: not used
+ * @P9_RLERROR: response for any failed request for 9P2000.L
* @P9_TSTATFS: file system status request
* @P9_RSTATFS: file system status response
* @P9_TSYMLINK: make symlink request
@@ -137,6 +139,8 @@ do { \
*/
enum p9_msg_t {
+ P9_TLERROR = 6,
+ P9_RLERROR,
P9_TSTATFS = 8,
P9_RSTATFS,
P9_TLOPEN = 12,
@@ -149,6 +153,8 @@ enum p9_msg_t {
P9_RMKNOD,
P9_TRENAME = 20,
P9_RRENAME,
+ P9_TREADLINK = 22,
+ P9_RREADLINK,
P9_TGETATTR = 24,
P9_RGETATTR,
P9_TSETATTR = 26,
@@ -159,6 +165,12 @@ enum p9_msg_t {
P9_RXATTRCREATE,
P9_TREADDIR = 40,
P9_RREADDIR,
+ P9_TFSYNC = 50,
+ P9_RFSYNC,
+ P9_TLOCK = 52,
+ P9_RLOCK,
+ P9_TGETLOCK = 54,
+ P9_RGETLOCK,
P9_TLINK = 70,
P9_RLINK,
P9_TMKDIR = 72,
@@ -458,6 +470,48 @@ struct p9_iattr_dotl {
u64 mtime_nsec;
};
+#define P9_LOCK_SUCCESS 0
+#define P9_LOCK_BLOCKED 1
+#define P9_LOCK_ERROR 2
+#define P9_LOCK_GRACE 3
+
+#define P9_LOCK_FLAGS_BLOCK 1
+#define P9_LOCK_FLAGS_RECLAIM 2
+
+/* struct p9_flock: POSIX lock structure
+ * @type - type of lock
+ * @flags - lock flags
+ * @start - starting offset of the lock
+ * @length - number of bytes
+ * @proc_id - process id which wants to take lock
+ * @client_id - client id
+ */
+
+struct p9_flock {
+ u8 type;
+ u32 flags;
+ u64 start;
+ u64 length;
+ u32 proc_id;
+ char *client_id;
+};
+
+/* struct p9_getlock: getlock structure
+ * @type - type of lock
+ * @start - starting offset of the lock
+ * @length - number of bytes
+ * @proc_id - process id which wants to take lock
+ * @client_id - client id
+ */
+
+struct p9_getlock {
+ u8 type;
+ u64 start;
+ u64 length;
+ u32 proc_id;
+ char *client_id;
+};
+
/* Structures for Protocol Operations */
struct p9_tstatfs {
u32 fid;
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index d1aa2cfb30f0..83ba6a4d58a3 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -212,15 +212,12 @@ struct p9_dirent {
int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb);
int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name);
-int p9_client_version(struct p9_client *);
struct p9_client *p9_client_create(const char *dev_name, char *options);
void p9_client_destroy(struct p9_client *clnt);
void p9_client_disconnect(struct p9_client *clnt);
void p9_client_begin_disconnect(struct p9_client *clnt);
struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
char *uname, u32 n_uname, char *aname);
-struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname,
- u32 n_uname, char *aname);
struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
int clone);
int p9_client_open(struct p9_fid *fid, int mode);
@@ -232,6 +229,7 @@ int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid,
int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
gid_t gid, struct p9_qid *qid);
int p9_client_clunk(struct p9_fid *fid);
+int p9_client_fsync(struct p9_fid *fid, int datasync);
int p9_client_remove(struct p9_fid *fid);
int p9_client_read(struct p9_fid *fid, char *data, char __user *udata,
u64 offset, u32 count);
@@ -251,6 +249,8 @@ int p9_client_mknod_dotl(struct p9_fid *oldfid, char *name, int mode,
dev_t rdev, gid_t gid, struct p9_qid *);
int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,
gid_t gid, struct p9_qid *);
+int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status);
+int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl);
struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
void p9_client_cb(struct p9_client *c, struct p9_req_t *req);
@@ -262,5 +262,6 @@ int p9_is_proto_dotu(struct p9_client *clnt);
int p9_is_proto_dotl(struct p9_client *clnt);
struct p9_fid *p9_client_xattrwalk(struct p9_fid *, const char *, u64 *);
int p9_client_xattrcreate(struct p9_fid *, const char *, u64, int);
+int p9_client_readlink(struct p9_fid *fid, char **target);
#endif /* NET_9P_CLIENT_H */
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 4d40c4d0230b..a9441249306c 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -175,20 +175,32 @@ extern int ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
extern int register_inet6addr_notifier(struct notifier_block *nb);
extern int unregister_inet6addr_notifier(struct notifier_block *nb);
-static inline struct inet6_dev *
-__in6_dev_get(struct net_device *dev)
+/**
+ * __in6_dev_get - get inet6_dev pointer from netdevice
+ * @dev: network device
+ *
+ * Caller must hold rcu_read_lock or RTNL, because this function
+ * does not take a reference on the inet6_dev.
+ */
+static inline struct inet6_dev *__in6_dev_get(const struct net_device *dev)
{
- return rcu_dereference_check(dev->ip6_ptr,
- rcu_read_lock_held() ||
- lockdep_rtnl_is_held());
+ return rcu_dereference_rtnl(dev->ip6_ptr);
}
-static inline struct inet6_dev *
-in6_dev_get(struct net_device *dev)
+/**
+ * in6_dev_get - get inet6_dev pointer from netdevice
+ * @dev: network device
+ *
+ * This version can be used in any context, and takes a reference
+ * on the inet6_dev. Callers must use in6_dev_put() later to
+ * release this reference.
+ */
+static inline struct inet6_dev *in6_dev_get(const struct net_device *dev)
{
- struct inet6_dev *idev = NULL;
+ struct inet6_dev *idev;
+
rcu_read_lock();
- idev = __in6_dev_get(dev);
+ idev = rcu_dereference(dev->ip6_ptr);
if (idev)
atomic_inc(&idev->refcnt);
rcu_read_unlock();
@@ -197,16 +209,21 @@ in6_dev_get(struct net_device *dev)
extern void in6_dev_finish_destroy(struct inet6_dev *idev);
-static inline void
-in6_dev_put(struct inet6_dev *idev)
+static inline void in6_dev_put(struct inet6_dev *idev)
{
if (atomic_dec_and_test(&idev->refcnt))
in6_dev_finish_destroy(idev);
}
-#define __in6_dev_put(idev) atomic_dec(&(idev)->refcnt)
-#define in6_dev_hold(idev) atomic_inc(&(idev)->refcnt)
+static inline void __in6_dev_put(struct inet6_dev *idev)
+{
+ atomic_dec(&idev->refcnt);
+}
+static inline void in6_dev_hold(struct inet6_dev *idev)
+{
+ atomic_inc(&idev->refcnt);
+}
extern void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp);
@@ -216,9 +233,15 @@ static inline void in6_ifa_put(struct inet6_ifaddr *ifp)
inet6_ifa_finish_destroy(ifp);
}
-#define __in6_ifa_put(ifp) atomic_dec(&(ifp)->refcnt)
-#define in6_ifa_hold(ifp) atomic_inc(&(ifp)->refcnt)
+static inline void __in6_ifa_put(struct inet6_ifaddr *ifp)
+{
+ atomic_dec(&ifp->refcnt);
+}
+static inline void in6_ifa_hold(struct inet6_ifaddr *ifp)
+{
+ atomic_inc(&ifp->refcnt);
+}
/*
@@ -241,23 +264,21 @@ static inline int ipv6_addr_is_multicast(const struct in6_addr *addr)
static inline int ipv6_addr_is_ll_all_nodes(const struct in6_addr *addr)
{
- return (((addr->s6_addr32[0] ^ htonl(0xff020000)) |
+ return ((addr->s6_addr32[0] ^ htonl(0xff020000)) |
addr->s6_addr32[1] | addr->s6_addr32[2] |
- (addr->s6_addr32[3] ^ htonl(0x00000001))) == 0);
+ (addr->s6_addr32[3] ^ htonl(0x00000001))) == 0;
}
static inline int ipv6_addr_is_ll_all_routers(const struct in6_addr *addr)
{
- return (((addr->s6_addr32[0] ^ htonl(0xff020000)) |
+ return ((addr->s6_addr32[0] ^ htonl(0xff020000)) |
addr->s6_addr32[1] | addr->s6_addr32[2] |
- (addr->s6_addr32[3] ^ htonl(0x00000002))) == 0);
+ (addr->s6_addr32[3] ^ htonl(0x00000002))) == 0;
}
-extern int __ipv6_isatap_ifid(u8 *eui, __be32 addr);
-
static inline int ipv6_addr_is_isatap(const struct in6_addr *addr)
{
- return ((addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE));
+ return (addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE);
}
#ifdef CONFIG_PROC_FS
diff --git a/include/net/arp.h b/include/net/arp.h
index 716f43c5c98e..f4cf6ce66586 100644
--- a/include/net/arp.h
+++ b/include/net/arp.h
@@ -26,6 +26,4 @@ extern struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
const unsigned char *target_hw);
extern void arp_xmit(struct sk_buff *skb);
-extern const struct neigh_ops arp_broken_ops;
-
#endif /* _ARP_H */
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 30fce0128dd7..d81ea7997701 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -126,6 +126,8 @@ int bt_sock_unregister(int proto);
void bt_sock_link(struct bt_sock_list *l, struct sock *s);
void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags);
+int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t len, int flags);
uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index bcbdd6d4e6dd..e30e00834340 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -54,7 +54,7 @@
/* HCI controller types */
#define HCI_BREDR 0x00
-#define HCI_80211 0x01
+#define HCI_AMP 0x01
/* HCI device quirks */
enum {
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 4568b938ca35..ebec8c9a929d 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -233,7 +233,7 @@ static inline void inquiry_cache_init(struct hci_dev *hdev)
static inline int inquiry_cache_empty(struct hci_dev *hdev)
{
struct inquiry_cache *c = &hdev->inq_cache;
- return (c->list == NULL);
+ return c->list == NULL;
}
static inline long inquiry_cache_age(struct hci_dev *hdev)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 6c241444f902..c819c8bf9b68 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -414,7 +414,7 @@ static inline int l2cap_tx_window_full(struct sock *sk)
if (sub < 0)
sub += 64;
- return (sub == pi->remote_tx_win);
+ return sub == pi->remote_tx_win;
}
#define __get_txseq(ctrl) ((ctrl) & L2CAP_CTRL_TXSEQ) >> 1
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
index a140847d622c..71047bc0af84 100644
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -213,11 +213,6 @@ struct rfcomm_dlc {
#define RFCOMM_DEFER_SETUP 8
/* Scheduling flags and events */
-#define RFCOMM_SCHED_STATE 0
-#define RFCOMM_SCHED_RX 1
-#define RFCOMM_SCHED_TX 2
-#define RFCOMM_SCHED_TIMEO 3
-#define RFCOMM_SCHED_AUTH 4
#define RFCOMM_SCHED_WAKEUP 31
/* MSC exchange flags */
diff --git a/include/net/caif/caif_shm.h b/include/net/caif/caif_shm.h
new file mode 100644
index 000000000000..5bcce55438cf
--- /dev/null
+++ b/include/net/caif/caif_shm.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author: Amarnath Revanna / amarnath.bangalore.revanna@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_SHM_H_
+#define CAIF_SHM_H_
+
+struct shmdev_layer {
+ u32 shm_base_addr;
+ u32 shm_total_sz;
+ u32 shm_id;
+ u32 shm_loopback;
+ void *hmbx;
+ int (*pshmdev_mbxsend) (u32 shm_id, u32 mbx_msg);
+ int (*pshmdev_mbxsetup) (void *pshmdrv_cb,
+ struct shmdev_layer *pshm_dev, void *pshm_drv);
+ struct net_device *pshm_netdev;
+};
+
+extern int caif_shmcore_probe(struct shmdev_layer *pshm_dev);
+extern void caif_shmcore_remove(struct net_device *pshm_netdev);
+
+#endif
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 2fd06c60ffbb..2a7936d7851d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -25,6 +25,43 @@
#include <linux/wireless.h>
+/**
+ * DOC: Introduction
+ *
+ * cfg80211 is the configuration API for 802.11 devices in Linux. It bridges
+ * userspace and drivers, and offers some utility functionality associated
+ * with 802.11. cfg80211 must, directly or indirectly via mac80211, be used
+ * by all modern wireless drivers in Linux, so that they offer a consistent
+ * API through nl80211. For backward compatibility, cfg80211 also offers
+ * wireless extensions to userspace, but hides them from drivers completely.
+ *
+ * Additionally, cfg80211 contains code to help enforce regulatory spectrum
+ * use restrictions.
+ */
+
+
+/**
+ * DOC: Device registration
+ *
+ * In order for a driver to use cfg80211, it must register the hardware device
+ * with cfg80211. This happens through a number of hardware capability structs
+ * described below.
+ *
+ * The fundamental structure for each device is the 'wiphy', of which each
+ * instance describes a physical wireless device connected to the system. Each
+ * such wiphy can have zero, one, or many virtual interfaces associated with
+ * it, which need to be identified as such by pointing the network interface's
+ * @ieee80211_ptr pointer to a &struct wireless_dev which further describes
+ * the wireless part of the interface, normally this struct is embedded in the
+ * network interface's private data area. Drivers can optionally allow creating
+ * or destroying virtual interfaces on the fly, but without at least one or the
+ * ability to create some the wireless device isn't useful.
+ *
+ * Each wiphy structure contains device capability information, and also has
+ * a pointer to the various operations the driver offers. The definitions and
+ * structures here describe these capabilities in detail.
+ */
+
/*
* wireless hardware capability structures
*/
@@ -205,6 +242,21 @@ struct ieee80211_supported_band {
*/
/**
+ * DOC: Actions and configuration
+ *
+ * Each wireless device and each virtual interface offer a set of configuration
+ * operations and other actions that are invoked by userspace. Each of these
+ * actions is described in the operations structure, and the parameters these
+ * operations use are described separately.
+ *
+ * Additionally, some operations are asynchronous and expect to get status
+ * information via some functions that drivers need to call.
+ *
+ * Scanning and BSS list handling with its associated functionality is described
+ * in a separate chapter.
+ */
+
+/**
* struct vif_params - describes virtual interface parameters
* @mesh_id: mesh ID to use
* @mesh_id_len: length of the mesh ID
@@ -241,12 +293,24 @@ struct key_params {
* enum survey_info_flags - survey information flags
*
* @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in
+ * @SURVEY_INFO_IN_USE: channel is currently being used
+ * @SURVEY_INFO_CHANNEL_TIME: channel active time (in ms) was filled in
+ * @SURVEY_INFO_CHANNEL_TIME_BUSY: channel busy time was filled in
+ * @SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: extension channel busy time was filled in
+ * @SURVEY_INFO_CHANNEL_TIME_RX: channel receive time was filled in
+ * @SURVEY_INFO_CHANNEL_TIME_TX: channel transmit time was filled in
*
* Used by the driver to indicate which info in &struct survey_info
* it has filled in during the get_survey().
*/
enum survey_info_flags {
SURVEY_INFO_NOISE_DBM = 1<<0,
+ SURVEY_INFO_IN_USE = 1<<1,
+ SURVEY_INFO_CHANNEL_TIME = 1<<2,
+ SURVEY_INFO_CHANNEL_TIME_BUSY = 1<<3,
+ SURVEY_INFO_CHANNEL_TIME_EXT_BUSY = 1<<4,
+ SURVEY_INFO_CHANNEL_TIME_RX = 1<<5,
+ SURVEY_INFO_CHANNEL_TIME_TX = 1<<6,
};
/**
@@ -256,6 +320,11 @@ enum survey_info_flags {
* @filled: bitflag of flags from &enum survey_info_flags
* @noise: channel noise in dBm. This and all following fields are
* optional
+ * @channel_time: amount of time in ms the radio spent on the channel
+ * @channel_time_busy: amount of time the primary channel was sensed busy
+ * @channel_time_ext_busy: amount of time the extension channel was sensed busy
+ * @channel_time_rx: amount of time the radio spent receiving data
+ * @channel_time_tx: amount of time the radio spent transmitting data
*
* Used by dump_survey() to report back per-channel survey information.
*
@@ -264,6 +333,11 @@ enum survey_info_flags {
*/
struct survey_info {
struct ieee80211_channel *channel;
+ u64 channel_time;
+ u64 channel_time_busy;
+ u64 channel_time_ext_busy;
+ u64 channel_time_rx;
+ u64 channel_time_tx;
u32 filled;
s8 noise;
};
@@ -347,6 +421,9 @@ struct station_parameters {
* (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
* @STATION_INFO_RX_PACKETS: @rx_packets filled
* @STATION_INFO_TX_PACKETS: @tx_packets filled
+ * @STATION_INFO_TX_RETRIES: @tx_retries filled
+ * @STATION_INFO_TX_FAILED: @tx_failed filled
+ * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled
*/
enum station_info_flags {
STATION_INFO_INACTIVE_TIME = 1<<0,
@@ -359,6 +436,9 @@ enum station_info_flags {
STATION_INFO_TX_BITRATE = 1<<7,
STATION_INFO_RX_PACKETS = 1<<8,
STATION_INFO_TX_PACKETS = 1<<9,
+ STATION_INFO_TX_RETRIES = 1<<10,
+ STATION_INFO_TX_FAILED = 1<<11,
+ STATION_INFO_RX_DROP_MISC = 1<<12,
};
/**
@@ -408,6 +488,9 @@ struct rate_info {
* @txrate: current unicast bitrate to this station
* @rx_packets: packets received from this station
* @tx_packets: packets transmitted to this station
+ * @tx_retries: cumulative retry counts
+ * @tx_failed: number of failed transmissions (retries exceeded, no ACK)
+ * @rx_dropped_misc: Dropped for un-specified reason.
* @generation: generation number for nl80211 dumps.
* This number should increase every time the list of stations
* changes, i.e. when a station is added or removed, so that
@@ -425,6 +508,9 @@ struct station_info {
struct rate_info txrate;
u32 rx_packets;
u32 tx_packets;
+ u32 tx_retries;
+ u32 tx_failed;
+ u32 rx_dropped_misc;
int generation;
};
@@ -570,8 +656,28 @@ struct ieee80211_txq_params {
/* from net/wireless.h */
struct wiphy;
-/* from net/ieee80211.h */
-struct ieee80211_channel;
+/**
+ * DOC: Scanning and BSS list handling
+ *
+ * The scanning process itself is fairly simple, but cfg80211 offers quite
+ * a bit of helper functionality. To start a scan, the scan operation will
+ * be invoked with a scan definition. This scan definition contains the
+ * channels to scan, and the SSIDs to send probe requests for (including the
+ * wildcard, if desired). A passive scan is indicated by having no SSIDs to
+ * probe. Additionally, a scan request may contain extra information elements
+ * that should be added to the probe request. The IEs are guaranteed to be
+ * well-formed, and will not exceed the maximum length the driver advertised
+ * in the wiphy structure.
+ *
+ * When scanning finds a BSS, cfg80211 needs to be notified of that, because
+ * it is responsible for maintaining the BSS list; the driver should not
+ * maintain a list itself. For this notification, various functions exist.
+ *
+ * Since drivers do not maintain a BSS list, there are also a number of
+ * functions to search for a BSS and obtain information about it from the
+ * BSS structure cfg80211 maintains. The BSS list is also made available
+ * to userspace.
+ */
/**
* struct cfg80211_ssid - SSID description
@@ -691,6 +797,10 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
* 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;
@@ -700,6 +810,8 @@ struct cfg80211_crypto_settings {
int n_akm_suites;
u32 akm_suites[NL80211_MAX_NR_AKM_SUITES];
bool control_port;
+ __be16 control_port_ethertype;
+ bool control_port_no_encrypt;
};
/**
@@ -1020,7 +1132,7 @@ struct cfg80211_pmksa {
* @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation.
* This allows the operation to be terminated prior to timeout based on
* the duration value.
- * @action: Transmit an action frame
+ * @mgmt_tx: Transmit a management frame
*
* @testmode_cmd: run a test mode command
*
@@ -1035,6 +1147,9 @@ struct cfg80211_pmksa {
* allows the driver to adjust the dynamic ps timeout value.
* @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold.
*
+ * @mgmt_frame_register: Notify driver that a management frame type was
+ * registered. Note that this callback may not sleep, and cannot run
+ * concurrently with itself.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy);
@@ -1050,13 +1165,14 @@ struct cfg80211_ops {
struct vif_params *params);
int (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
- u8 key_index, const u8 *mac_addr,
+ u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params);
int (*get_key)(struct wiphy *wiphy, struct net_device *netdev,
- u8 key_index, const u8 *mac_addr, void *cookie,
+ u8 key_index, bool pairwise, const u8 *mac_addr,
+ void *cookie,
void (*callback)(void *cookie, struct key_params*));
int (*del_key)(struct wiphy *wiphy, struct net_device *netdev,
- u8 key_index, const u8 *mac_addr);
+ u8 key_index, bool pairwise, const u8 *mac_addr);
int (*set_default_key)(struct wiphy *wiphy,
struct net_device *netdev,
u8 key_index);
@@ -1140,7 +1256,7 @@ struct cfg80211_ops {
int (*get_tx_power)(struct wiphy *wiphy, int *dbm);
int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
- u8 *addr);
+ const u8 *addr);
void (*rfkill_poll)(struct wiphy *wiphy);
@@ -1172,7 +1288,7 @@ struct cfg80211_ops {
struct net_device *dev,
u64 cookie);
- int (*action)(struct wiphy *wiphy, struct net_device *dev,
+ int (*mgmt_tx)(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
bool channel_type_valid,
@@ -1184,6 +1300,10 @@ struct cfg80211_ops {
int (*set_cqm_rssi_config)(struct wiphy *wiphy,
struct net_device *dev,
s32 rssi_thold, u32 rssi_hyst);
+
+ void (*mgmt_frame_register)(struct wiphy *wiphy,
+ struct net_device *dev,
+ u16 frame_type, bool reg);
};
/*
@@ -1221,21 +1341,31 @@ struct cfg80211_ops {
* @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station
* on a VLAN interface)
* @WIPHY_FLAG_4ADDR_STATION: supports 4addr mode even as a station
+ * @WIPHY_FLAG_CONTROL_PORT_PROTOCOL: This device supports setting the
+ * control port protocol ethertype. The device also honours the
+ * control_port_no_encrypt flag.
+ * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN.
*/
enum wiphy_flags {
- WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
- WIPHY_FLAG_STRICT_REGULATORY = BIT(1),
- WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2),
- WIPHY_FLAG_NETNS_OK = BIT(3),
- WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4),
- WIPHY_FLAG_4ADDR_AP = BIT(5),
- WIPHY_FLAG_4ADDR_STATION = BIT(6),
+ WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
+ WIPHY_FLAG_STRICT_REGULATORY = BIT(1),
+ WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2),
+ WIPHY_FLAG_NETNS_OK = BIT(3),
+ WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4),
+ WIPHY_FLAG_4ADDR_AP = BIT(5),
+ WIPHY_FLAG_4ADDR_STATION = BIT(6),
+ WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7),
+ WIPHY_FLAG_IBSS_RSN = BIT(7),
};
struct mac_address {
u8 addr[ETH_ALEN];
};
+struct ieee80211_txrx_stypes {
+ u16 tx, rx;
+};
+
/**
* struct wiphy - wireless hardware description
* @reg_notifier: the driver's regulatory notification callback
@@ -1286,6 +1416,10 @@ struct mac_address {
* @privid: a pointer that drivers can use to identify if an arbitrary
* wiphy is theirs, e.g. in global notifiers
* @bands: information about bands/channels supported by this device
+ *
+ * @mgmt_stypes: bitmasks of frame subtypes that can be subscribed to or
+ * transmitted through nl80211, points to an array indexed by interface
+ * type
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -1294,9 +1428,12 @@ struct wiphy {
u8 perm_addr[ETH_ALEN];
u8 addr_mask[ETH_ALEN];
- u16 n_addresses;
struct mac_address *addresses;
+ const struct ieee80211_txrx_stypes *mgmt_stypes;
+
+ u16 n_addresses;
+
/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
u16 interface_modes;
@@ -1492,8 +1629,8 @@ struct cfg80211_cached_keys;
* set by driver (if supported) on add_interface BEFORE registering the
* netdev and may otherwise be used by driver read-only, will be update
* by cfg80211 on change_interface
- * @action_registrations: list of registrations for action frames
- * @action_registrations_lock: lock for the list
+ * @mgmt_registrations: list of registrations for management frames
+ * @mgmt_registrations_lock: lock for the list
* @mtx: mutex used to lock data in this struct
* @cleanup_work: work struct used for cleanup that can't be done directly
*/
@@ -1505,8 +1642,8 @@ struct wireless_dev {
struct list_head list;
struct net_device *netdev;
- struct list_head action_registrations;
- spinlock_t action_registrations_lock;
+ struct list_head mgmt_registrations;
+ spinlock_t mgmt_registrations_lock;
struct mutex mtx;
@@ -1563,8 +1700,10 @@ static inline void *wdev_priv(struct wireless_dev *wdev)
return wiphy_priv(wdev->wiphy);
}
-/*
- * Utility functions
+/**
+ * DOC: Utility functions
+ *
+ * cfg80211 offers a number of utility functions that can be useful.
*/
/**
@@ -1715,7 +1854,15 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb);
* ieee80211_hdrlen - get header length in bytes from frame control
* @fc: frame control field in little-endian format
*/
-unsigned int ieee80211_hdrlen(__le16 fc);
+unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc);
+
+/**
+ * DOC: Data path helpers
+ *
+ * In addition to generic utilities, cfg80211 also offers
+ * functions that help implement the data path for devices
+ * that do not do the 802.11/802.3 conversion on the device.
+ */
/**
* ieee80211_data_to_8023 - convert an 802.11 data frame to 802.3
@@ -1777,8 +1924,10 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb);
*/
const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len);
-/*
- * Regulatory helper functions for wiphys
+/**
+ * DOC: Regulatory enforcement infrastructure
+ *
+ * TODO
*/
/**
@@ -2181,6 +2330,20 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp);
/**
+ * DOC: RFkill integration
+ *
+ * RFkill integration in cfg80211 is almost invisible to drivers,
+ * as cfg80211 automatically registers an rfkill instance for each
+ * wireless device it knows about. Soft kill is also translated
+ * into disconnecting and turning all interfaces off, drivers are
+ * expected to turn off the device when all interfaces are down.
+ *
+ * However, devices may have a hard RFkill line, in which case they
+ * also need to interact with the rfkill subsystem, via cfg80211.
+ * They can do this with a few helper functions documented here.
+ */
+
+/**
* wiphy_rfkill_set_hw_state - notify cfg80211 about hw block state
* @wiphy: the wiphy
* @blocked: block status
@@ -2201,6 +2364,17 @@ void wiphy_rfkill_stop_polling(struct wiphy *wiphy);
#ifdef CONFIG_NL80211_TESTMODE
/**
+ * DOC: Test mode
+ *
+ * Test mode is a set of utility functions to allow drivers to
+ * interact with driver-specific tools to aid, for instance,
+ * factory programming.
+ *
+ * This chapter describes how drivers interact with it, for more
+ * information see the nl80211 book's chapter on it.
+ */
+
+/**
* cfg80211_testmode_alloc_reply_skb - allocate testmode reply
* @wiphy: the wiphy
* @approxlen: an upper bound of the length of the data that will
@@ -2373,38 +2547,39 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
struct station_info *sinfo, gfp_t gfp);
/**
- * cfg80211_rx_action - notification of received, unprocessed Action frame
+ * cfg80211_rx_mgmt - notification of received, unprocessed management frame
* @dev: network device
* @freq: Frequency on which the frame was received in MHz
- * @buf: Action frame (header + body)
+ * @buf: Management frame (header + body)
* @len: length of the frame data
* @gfp: context flags
- * Returns %true if a user space application is responsible for rejecting the
- * unrecognized Action frame; %false if no such application is registered
- * (i.e., the driver is responsible for rejecting the unrecognized Action
- * frame)
+ *
+ * Returns %true if a user space application has registered for this frame.
+ * For action frames, that makes it responsible for rejecting unrecognized
+ * action frames; %false otherwise, in which case for action frames the
+ * driver is responsible for rejecting the frame.
*
* This function is called whenever an Action frame is received for a station
* mode interface, but is not processed in kernel.
*/
-bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
- size_t len, gfp_t gfp);
+bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
+ size_t len, gfp_t gfp);
/**
- * cfg80211_action_tx_status - notification of TX status for Action frame
+ * cfg80211_mgmt_tx_status - notification of TX status for management frame
* @dev: network device
- * @cookie: Cookie returned by cfg80211_ops::action()
- * @buf: Action frame (header + body)
+ * @cookie: Cookie returned by cfg80211_ops::mgmt_tx()
+ * @buf: Management frame (header + body)
* @len: length of the frame data
* @ack: Whether frame was acknowledged
* @gfp: context flags
*
- * This function is called whenever an Action frame was requested to be
- * transmitted with cfg80211_ops::action() to report the TX status of the
+ * This function is called whenever a management frame was requested to be
+ * transmitted with cfg80211_ops::mgmt_tx() to report the TX status of the
* transmission attempt.
*/
-void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
- const u8 *buf, size_t len, bool ack, gfp_t gfp);
+void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie,
+ const u8 *buf, size_t len, bool ack, gfp_t gfp);
/**
@@ -2420,56 +2595,41 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
enum nl80211_cqm_rssi_threshold_event rssi_event,
gfp_t gfp);
-#ifdef __KERNEL__
-
/* Logging, debugging and troubleshooting/diagnostic helpers. */
/* wiphy_printk helpers, similar to dev_printk */
#define wiphy_printk(level, wiphy, format, args...) \
- printk(level "%s: " format, wiphy_name(wiphy), ##args)
+ dev_printk(level, &(wiphy)->dev, format, ##args)
#define wiphy_emerg(wiphy, format, args...) \
- wiphy_printk(KERN_EMERG, wiphy, format, ##args)
+ dev_emerg(&(wiphy)->dev, format, ##args)
#define wiphy_alert(wiphy, format, args...) \
- wiphy_printk(KERN_ALERT, wiphy, format, ##args)
+ dev_alert(&(wiphy)->dev, format, ##args)
#define wiphy_crit(wiphy, format, args...) \
- wiphy_printk(KERN_CRIT, wiphy, format, ##args)
+ dev_crit(&(wiphy)->dev, format, ##args)
#define wiphy_err(wiphy, format, args...) \
- wiphy_printk(KERN_ERR, wiphy, format, ##args)
+ dev_err(&(wiphy)->dev, format, ##args)
#define wiphy_warn(wiphy, format, args...) \
- wiphy_printk(KERN_WARNING, wiphy, format, ##args)
+ dev_warn(&(wiphy)->dev, format, ##args)
#define wiphy_notice(wiphy, format, args...) \
- wiphy_printk(KERN_NOTICE, wiphy, format, ##args)
+ dev_notice(&(wiphy)->dev, format, ##args)
#define wiphy_info(wiphy, format, args...) \
- wiphy_printk(KERN_INFO, wiphy, format, ##args)
+ dev_info(&(wiphy)->dev, format, ##args)
-int wiphy_debug(const struct wiphy *wiphy, const char *format, ...)
- __attribute__ ((format (printf, 2, 3)));
-
-#if defined(DEBUG)
-#define wiphy_dbg(wiphy, format, args...) \
+#define wiphy_debug(wiphy, format, args...) \
wiphy_printk(KERN_DEBUG, wiphy, format, ##args)
-#elif defined(CONFIG_DYNAMIC_DEBUG)
+
#define wiphy_dbg(wiphy, format, args...) \
- dynamic_pr_debug("%s: " format, wiphy_name(wiphy), ##args)
-#else
-#define wiphy_dbg(wiphy, format, args...) \
-({ \
- if (0) \
- wiphy_printk(KERN_DEBUG, wiphy, format, ##args); \
- 0; \
-})
-#endif
+ dev_dbg(&(wiphy)->dev, format, ##args)
#if defined(VERBOSE_DEBUG)
#define wiphy_vdbg wiphy_dbg
#else
-
#define wiphy_vdbg(wiphy, format, args...) \
({ \
if (0) \
wiphy_printk(KERN_DEBUG, wiphy, format, ##args); \
- 0; \
+ 0; \
})
#endif
@@ -2481,6 +2641,4 @@ int wiphy_debug(const struct wiphy *wiphy, const char *format, ...)
#define wiphy_WARN(wiphy, format, args...) \
WARN(1, "wiphy: %s\n" format, wiphy_name(wiphy), ##args);
-#endif
-
#endif /* __NET_CFG80211_H */
diff --git a/include/net/dst.h b/include/net/dst.h
index 02386505033d..ffe9cb719c0e 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -43,10 +43,11 @@ struct dst_entry {
short error;
short obsolete;
int flags;
-#define DST_HOST 1
-#define DST_NOXFRM 2
-#define DST_NOPOLICY 4
-#define DST_NOHASH 8
+#define DST_HOST 0x0001
+#define DST_NOXFRM 0x0002
+#define DST_NOPOLICY 0x0004
+#define DST_NOHASH 0x0008
+#define DST_NOCACHE 0x0010
unsigned long expires;
unsigned short header_len; /* more space at head required */
@@ -94,7 +95,7 @@ struct dst_entry {
unsigned long lastuse;
union {
struct dst_entry *next;
- struct rtable *rt_next;
+ struct rtable __rcu *rt_next;
struct rt6_info *rt6_next;
struct dn_route *dn_next;
};
@@ -228,23 +229,37 @@ static inline void skb_dst_force(struct sk_buff *skb)
/**
+ * __skb_tunnel_rx - prepare skb for rx reinsert
+ * @skb: buffer
+ * @dev: tunnel device
+ *
+ * After decapsulation, packet is going to re-enter (netif_rx()) our stack,
+ * so make some cleanups. (no accounting done)
+ */
+static inline void __skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev)
+{
+ skb->dev = dev;
+ skb->rxhash = 0;
+ skb_set_queue_mapping(skb, 0);
+ skb_dst_drop(skb);
+ nf_reset(skb);
+}
+
+/**
* skb_tunnel_rx - prepare skb for rx reinsert
* @skb: buffer
* @dev: tunnel device
*
* After decapsulation, packet is going to re-enter (netif_rx()) our stack,
* so make some cleanups, and perform accounting.
+ * Note: this accounting is not SMP safe.
*/
static inline void skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev)
{
- skb->dev = dev;
/* TODO : stats should be SMP safe */
dev->stats.rx_packets++;
dev->stats.rx_bytes += skb->len;
- skb->rxhash = 0;
- skb_set_queue_mapping(skb, 0);
- skb_dst_drop(skb);
- nf_reset(skb);
+ __skb_tunnel_rx(skb, dev);
}
/* Children define the path of the packet through the
diff --git a/include/net/dst_ops.h b/include/net/dst_ops.h
index d1ff9b7e99b8..1fa5306e3e23 100644
--- a/include/net/dst_ops.h
+++ b/include/net/dst_ops.h
@@ -1,6 +1,7 @@
#ifndef _NET_DST_OPS_H
#define _NET_DST_OPS_H
#include <linux/types.h>
+#include <linux/percpu_counter.h>
struct dst_entry;
struct kmem_cachep;
@@ -22,7 +23,41 @@ struct dst_ops {
void (*update_pmtu)(struct dst_entry *dst, u32 mtu);
int (*local_out)(struct sk_buff *skb);
- atomic_t entries;
struct kmem_cache *kmem_cachep;
+
+ struct percpu_counter pcpuc_entries ____cacheline_aligned_in_smp;
};
+
+static inline int dst_entries_get_fast(struct dst_ops *dst)
+{
+ return percpu_counter_read_positive(&dst->pcpuc_entries);
+}
+
+static inline int dst_entries_get_slow(struct dst_ops *dst)
+{
+ int res;
+
+ local_bh_disable();
+ res = percpu_counter_sum_positive(&dst->pcpuc_entries);
+ local_bh_enable();
+ return res;
+}
+
+static inline void dst_entries_add(struct dst_ops *dst, int val)
+{
+ local_bh_disable();
+ percpu_counter_add(&dst->pcpuc_entries, val);
+ local_bh_enable();
+}
+
+static inline int dst_entries_init(struct dst_ops *dst)
+{
+ return percpu_counter_init(&dst->pcpuc_entries, 0);
+}
+
+static inline void dst_entries_destroy(struct dst_ops *dst)
+{
+ percpu_counter_destroy(&dst->pcpuc_entries);
+}
+
#endif
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
index e8923bc20f9f..075f1e3a0fed 100644
--- a/include/net/fib_rules.h
+++ b/include/net/fib_rules.h
@@ -20,7 +20,7 @@ struct fib_rule {
u32 table;
u8 action;
u32 target;
- struct fib_rule * ctarget;
+ struct fib_rule __rcu *ctarget;
char iifname[IFNAMSIZ];
char oifname[IFNAMSIZ];
struct rcu_head rcu;
@@ -31,6 +31,8 @@ struct fib_lookup_arg {
void *lookup_ptr;
void *result;
struct fib_rule *rule;
+ int flags;
+#define FIB_LOOKUP_NOREF 1
};
struct fib_rules_ops {
@@ -106,7 +108,6 @@ static inline u32 frh_get_table(struct fib_rule_hdr *frh, struct nlattr **nla)
extern struct fib_rules_ops *fib_rules_register(const struct fib_rules_ops *, struct net *);
extern void fib_rules_unregister(struct fib_rules_ops *);
-extern void fib_rules_cleanup_ops(struct fib_rules_ops *);
extern int fib_rules_lookup(struct fib_rules_ops *,
struct flowi *, int flags,
diff --git a/include/net/flow.h b/include/net/flow.h
index bb08692a20b0..0ac3fb5e0973 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -49,6 +49,7 @@ struct flowi {
__u8 proto;
__u8 flags;
#define FLOWI_FLAG_ANYSRC 0x01
+#define FLOWI_FLAG_MATCH_ANY_IIF 0x02
union {
struct {
__be16 sport;
diff --git a/include/net/garp.h b/include/net/garp.h
index 825f172caba9..f4c295984c45 100644
--- a/include/net/garp.h
+++ b/include/net/garp.h
@@ -107,7 +107,7 @@ struct garp_applicant {
};
struct garp_port {
- struct garp_applicant *applicants[GARP_APPLICATION_MAX + 1];
+ struct garp_applicant __rcu *applicants[GARP_APPLICATION_MAX + 1];
};
extern int garp_register_application(struct garp_application *app);
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index f7dcd2c70412..8a64b811a39a 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -20,6 +20,9 @@ struct genl_multicast_group {
u32 id;
};
+struct genl_ops;
+struct genl_info;
+
/**
* struct genl_family - generic netlink family
* @id: protocol family idenfitier
@@ -29,6 +32,10 @@ struct genl_multicast_group {
* @maxattr: maximum number of attributes supported
* @netnsok: set to true if the family can handle network
* namespaces and should be presented in all of them
+ * @pre_doit: called before an operation's doit callback, it may
+ * do additional, common, filtering and return an error
+ * @post_doit: called after an operation's doit callback, it may
+ * undo operations done by pre_doit, for example release locks
* @attrbuf: buffer to store parsed attributes
* @ops_list: list of all assigned operations
* @family_list: family list
@@ -41,6 +48,12 @@ struct genl_family {
unsigned int version;
unsigned int maxattr;
bool netnsok;
+ int (*pre_doit)(struct genl_ops *ops,
+ struct sk_buff *skb,
+ struct genl_info *info);
+ void (*post_doit)(struct genl_ops *ops,
+ struct sk_buff *skb,
+ struct genl_info *info);
struct nlattr ** attrbuf; /* private */
struct list_head ops_list; /* private */
struct list_head family_list; /* private */
@@ -55,6 +68,8 @@ struct genl_family {
* @genlhdr: generic netlink message header
* @userhdr: user specific header
* @attrs: netlink attributes
+ * @_net: network namespace
+ * @user_ptr: user pointers
*/
struct genl_info {
u32 snd_seq;
@@ -66,6 +81,7 @@ struct genl_info {
#ifdef CONFIG_NET_NS
struct net * _net;
#endif
+ void * user_ptr[2];
};
static inline struct net *genl_info_net(struct genl_info *info)
@@ -81,6 +97,7 @@ static inline void genl_info_net_set(struct genl_info *info, struct net *net)
/**
* struct genl_ops - generic netlink operations
* @cmd: command identifier
+ * @internal_flags: flags used by the family
* @flags: flags
* @policy: attribute validation policy
* @doit: standard command callback
@@ -90,6 +107,7 @@ static inline void genl_info_net_set(struct genl_info *info, struct net *net)
*/
struct genl_ops {
u8 cmd;
+ u8 internal_flags;
unsigned int flags;
const struct nla_policy *policy;
int (*doit)(struct sk_buff *skb,
diff --git a/include/net/gre.h b/include/net/gre.h
new file mode 100644
index 000000000000..82665474bcb7
--- /dev/null
+++ b/include/net/gre.h
@@ -0,0 +1,18 @@
+#ifndef __LINUX_GRE_H
+#define __LINUX_GRE_H
+
+#include <linux/skbuff.h>
+
+#define GREPROTO_CISCO 0
+#define GREPROTO_PPTP 1
+#define GREPROTO_MAX 2
+
+struct gre_protocol {
+ int (*handler)(struct sk_buff *skb);
+ void (*err_handler)(struct sk_buff *skb, u32 info);
+};
+
+int gre_add_protocol(const struct gre_protocol *proto, u8 version);
+int gre_del_protocol(const struct gre_protocol *proto, u8 version);
+
+#endif
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
index b6d3b55da19b..e4f494b42e06 100644
--- a/include/net/inet_connection_sock.h
+++ b/include/net/inet_connection_sock.h
@@ -125,6 +125,7 @@ struct inet_connection_sock {
int probe_size;
} icsk_mtup;
u32 icsk_ca_priv[16];
+ u32 icsk_user_timeout;
#define ICSK_CA_PRIV_SIZE (16 * sizeof(u32))
};
diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h
index 9b5d08f4f6e8..88bdd010d65d 100644
--- a/include/net/inet_ecn.h
+++ b/include/net/inet_ecn.h
@@ -27,7 +27,7 @@ static inline int INET_ECN_is_not_ect(__u8 dsfield)
static inline int INET_ECN_is_capable(__u8 dsfield)
{
- return (dsfield & INET_ECN_ECT_0);
+ return dsfield & INET_ECN_ECT_0;
}
static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner)
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index 74358d1b3f43..e9c2ed8af864 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -245,7 +245,7 @@ static inline int inet_sk_listen_hashfn(const struct sock *sk)
}
/* Caller must disable local BH processing. */
-extern void __inet_inherit_port(struct sock *sk, struct sock *child);
+extern int __inet_inherit_port(struct sock *sk, struct sock *child);
extern void inet_put_port(struct sock *sk);
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
index 417d0c894f29..fe239bfe5f7f 100644
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -15,7 +15,7 @@
struct inet_peer {
/* group together avl_left,avl_right,v4daddr to speedup lookups */
- struct inet_peer *avl_left, *avl_right;
+ struct inet_peer __rcu *avl_left, *avl_right;
__be32 v4daddr; /* peer's address */
__u32 avl_height;
struct list_head unused;
diff --git a/include/net/ip.h b/include/net/ip.h
index 890f9725d681..86e2b182a0c0 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -53,13 +53,13 @@ struct ipcm_cookie {
__be32 addr;
int oif;
struct ip_options *opt;
- union skb_shared_tx shtx;
+ __u8 tx_flags;
};
#define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb))
struct ip_ra_chain {
- struct ip_ra_chain *next;
+ struct ip_ra_chain __rcu *next;
struct sock *sk;
union {
void (*destructor)(struct sock *);
@@ -68,7 +68,7 @@ struct ip_ra_chain {
struct rcu_head rcu;
};
-extern struct ip_ra_chain *ip_ra_chain;
+extern struct ip_ra_chain __rcu *ip_ra_chain;
/* IP flags. */
#define IP_CE 0x8000 /* Flag: "Congestion" */
@@ -238,9 +238,9 @@ int ip_decrease_ttl(struct iphdr *iph)
static inline
int ip_dont_fragment(struct sock *sk, struct dst_entry *dst)
{
- return (inet_sk(sk)->pmtudisc == IP_PMTUDISC_DO ||
+ return inet_sk(sk)->pmtudisc == IP_PMTUDISC_DO ||
(inet_sk(sk)->pmtudisc == IP_PMTUDISC_WANT &&
- !(dst_metric_locked(dst, RTAX_MTU))));
+ !(dst_metric_locked(dst, RTAX_MTU)));
}
extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more);
diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index fc94ec568a50..fc73e667b50e 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -13,7 +13,7 @@
/* IPv6 tunnel */
struct ip6_tnl {
- struct ip6_tnl *next; /* next tunnel in list */
+ struct ip6_tnl __rcu *next; /* next tunnel in list */
struct net_device *dev; /* virtual device associated with tunnel */
struct ip6_tnl_parm parms; /* tunnel configuration parameters */
struct flowi fl; /* flowi template for xmit */
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index c93f94edc610..ba3666d31766 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -86,6 +86,7 @@ struct fib_info {
#ifdef CONFIG_IP_ROUTE_MULTIPATH
int fib_power;
#endif
+ struct rcu_head rcu;
struct fib_nh fib_nh[0];
#define fib_dev fib_nh[0].nh_dev
};
@@ -148,7 +149,7 @@ struct fib_table {
};
extern int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
- struct fib_result *res);
+ struct fib_result *res, int fib_flags);
extern int fib_table_insert(struct fib_table *, struct fib_config *);
extern int fib_table_delete(struct fib_table *, struct fib_config *);
extern int fib_table_dump(struct fib_table *table, struct sk_buff *skb,
@@ -185,11 +186,11 @@ static inline int fib_lookup(struct net *net, const struct flowi *flp,
struct fib_table *table;
table = fib_get_table(net, RT_TABLE_LOCAL);
- if (!fib_table_lookup(table, flp, res))
+ if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))
return 0;
table = fib_get_table(net, RT_TABLE_MAIN);
- if (!fib_table_lookup(table, flp, res))
+ if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))
return 0;
return -ENETUNREACH;
}
@@ -254,16 +255,6 @@ static inline void fib_info_put(struct fib_info *fi)
free_fib_info(fi);
}
-static inline void fib_res_put(struct fib_result *res)
-{
- if (res->fi)
- fib_info_put(res->fi);
-#ifdef CONFIG_IP_MULTIPLE_TABLES
- if (res->r)
- fib_rule_put(res->r);
-#endif
-}
-
#ifdef CONFIG_PROC_FS
extern int __net_init fib_proc_init(struct net *net);
extern void __net_exit fib_proc_exit(struct net *net);
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index f976885f686f..b7bbd6c28cfa 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -25,7 +25,9 @@
#include <linux/ip.h>
#include <linux/ipv6.h> /* for struct ipv6hdr */
#include <net/ipv6.h> /* for ipv6_addr_copy */
-
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+#include <net/netfilter/nf_conntrack.h>
+#endif
/* Connections' size value needed by ip_vs_ctl.c */
extern int ip_vs_conn_tab_size;
@@ -134,24 +136,24 @@ static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len,
if (net_ratelimit()) \
printk(KERN_DEBUG pr_fmt(msg), ##__VA_ARGS__); \
} while (0)
-#define IP_VS_DBG_PKT(level, pp, skb, ofs, msg) \
+#define IP_VS_DBG_PKT(level, af, pp, skb, ofs, msg) \
do { \
if (level <= ip_vs_get_debug_level()) \
- pp->debug_packet(pp, skb, ofs, msg); \
+ pp->debug_packet(af, pp, skb, ofs, msg); \
} while (0)
-#define IP_VS_DBG_RL_PKT(level, pp, skb, ofs, msg) \
+#define IP_VS_DBG_RL_PKT(level, af, pp, skb, ofs, msg) \
do { \
if (level <= ip_vs_get_debug_level() && \
net_ratelimit()) \
- pp->debug_packet(pp, skb, ofs, msg); \
+ pp->debug_packet(af, pp, skb, ofs, msg); \
} while (0)
#else /* NO DEBUGGING at ALL */
#define IP_VS_DBG_BUF(level, msg...) do {} while (0)
#define IP_VS_ERR_BUF(msg...) do {} while (0)
#define IP_VS_DBG(level, msg...) do {} while (0)
#define IP_VS_DBG_RL(msg...) do {} while (0)
-#define IP_VS_DBG_PKT(level, pp, skb, ofs, msg) do {} while (0)
-#define IP_VS_DBG_RL_PKT(level, pp, skb, ofs, msg) do {} while (0)
+#define IP_VS_DBG_PKT(level, af, pp, skb, ofs, msg) do {} while (0)
+#define IP_VS_DBG_RL_PKT(level, af, pp, skb, ofs, msg) do {} while (0)
#endif
#define IP_VS_BUG() BUG()
@@ -343,7 +345,7 @@ struct ip_vs_protocol {
int (*app_conn_bind)(struct ip_vs_conn *cp);
- void (*debug_packet)(struct ip_vs_protocol *pp,
+ void (*debug_packet)(int af, struct ip_vs_protocol *pp,
const struct sk_buff *skb,
int offset,
const char *msg);
@@ -355,6 +357,19 @@ struct ip_vs_protocol {
extern struct ip_vs_protocol * ip_vs_proto_get(unsigned short proto);
+struct ip_vs_conn_param {
+ const union nf_inet_addr *caddr;
+ const union nf_inet_addr *vaddr;
+ __be16 cport;
+ __be16 vport;
+ __u16 protocol;
+ u16 af;
+
+ const struct ip_vs_pe *pe;
+ char *pe_data;
+ __u8 pe_data_len;
+};
+
/*
* IP_VS structure allocated for each dynamically scheduled connection
*/
@@ -366,6 +381,7 @@ struct ip_vs_conn {
union nf_inet_addr caddr; /* client address */
union nf_inet_addr vaddr; /* virtual address */
union nf_inet_addr daddr; /* destination address */
+ volatile __u32 flags; /* status flags */
__be16 cport;
__be16 vport;
__be16 dport;
@@ -378,7 +394,6 @@ struct ip_vs_conn {
/* Flags and state transition */
spinlock_t lock; /* lock for state transition */
- volatile __u16 flags; /* status flags */
volatile __u16 state; /* state info */
volatile __u16 old_state; /* old state, to be used for
* state transition triggerd
@@ -394,6 +409,7 @@ struct ip_vs_conn {
/* packet transmitter for different forwarding methods. If it
mangles the packet, it must return NF_DROP or better NF_STOLEN,
otherwise this must be changed to a sk_buff **.
+ NF_ACCEPT can be returned when destination is local.
*/
int (*packet_xmit)(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp);
@@ -405,6 +421,9 @@ struct ip_vs_conn {
void *app_data; /* Application private data */
struct ip_vs_seq in_seq; /* incoming seq. struct */
struct ip_vs_seq out_seq; /* outgoing seq. struct */
+
+ char *pe_data;
+ __u8 pe_data_len;
};
@@ -426,6 +445,7 @@ struct ip_vs_service_user_kern {
/* virtual service options */
char *sched_name;
+ char *pe_name;
unsigned flags; /* virtual service flags */
unsigned timeout; /* persistent timeout in sec */
u32 netmask; /* persistent netmask */
@@ -475,6 +495,9 @@ struct ip_vs_service {
struct ip_vs_scheduler *scheduler; /* bound scheduler object */
rwlock_t sched_lock; /* lock sched_data */
void *sched_data; /* scheduler application data */
+
+ /* alternate persistence engine */
+ struct ip_vs_pe *pe;
};
@@ -507,6 +530,10 @@ struct ip_vs_dest {
spinlock_t dst_lock; /* lock of dst_cache */
struct dst_entry *dst_cache; /* destination cache entry */
u32 dst_rtos; /* RT_TOS(tos) for dst */
+ u32 dst_cookie;
+#ifdef CONFIG_IP_VS_IPV6
+ struct in6_addr dst_saddr;
+#endif
/* for virtual service */
struct ip_vs_service *svc; /* service it belongs to */
@@ -538,6 +565,21 @@ struct ip_vs_scheduler {
const struct sk_buff *skb);
};
+/* The persistence engine object */
+struct ip_vs_pe {
+ struct list_head n_list; /* d-linked list head */
+ char *name; /* scheduler name */
+ atomic_t refcnt; /* reference counter */
+ struct module *module; /* THIS_MODULE/NULL */
+
+ /* get the connection template, if any */
+ int (*fill_param)(struct ip_vs_conn_param *p, struct sk_buff *skb);
+ bool (*ct_match)(const struct ip_vs_conn_param *p,
+ struct ip_vs_conn *ct);
+ u32 (*hashkey_raw)(const struct ip_vs_conn_param *p, u32 initval,
+ bool inverse);
+ int (*show_pe_data)(const struct ip_vs_conn *cp, char *buf);
+};
/*
* The application module object (a.k.a. app incarnation)
@@ -556,11 +598,19 @@ struct ip_vs_app {
__be16 port; /* port number in net order */
atomic_t usecnt; /* usage counter */
- /* output hook: return false if can't linearize. diff set for TCP. */
+ /*
+ * output hook: Process packet in inout direction, diff set for TCP.
+ * Return: 0=Error, 1=Payload Not Mangled/Mangled but checksum is ok,
+ * 2=Mangled but checksum was not updated
+ */
int (*pkt_out)(struct ip_vs_app *, struct ip_vs_conn *,
struct sk_buff *, int *diff);
- /* input hook: return false if can't linearize. diff set for TCP. */
+ /*
+ * input hook: Process packet in outin direction, diff set for TCP.
+ * Return: 0=Error, 1=Payload Not Mangled/Mangled but checksum is ok,
+ * 2=Mangled but checksum was not updated
+ */
int (*pkt_in)(struct ip_vs_app *, struct ip_vs_conn *,
struct sk_buff *, int *diff);
@@ -624,13 +674,25 @@ enum {
IP_VS_DIR_LAST,
};
-extern struct ip_vs_conn *ip_vs_conn_in_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port);
+static inline void ip_vs_conn_fill_param(int af, int protocol,
+ const union nf_inet_addr *caddr,
+ __be16 cport,
+ const union nf_inet_addr *vaddr,
+ __be16 vport,
+ struct ip_vs_conn_param *p)
+{
+ p->af = af;
+ p->protocol = protocol;
+ p->caddr = caddr;
+ p->cport = cport;
+ p->vaddr = vaddr;
+ p->vport = vport;
+ p->pe = NULL;
+ p->pe_data = NULL;
+}
-extern struct ip_vs_conn *ip_vs_ct_in_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port);
+struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p);
+struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p);
struct ip_vs_conn * ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,
struct ip_vs_protocol *pp,
@@ -638,9 +700,7 @@ struct ip_vs_conn * ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,
unsigned int proto_off,
int inverse);
-extern struct ip_vs_conn *ip_vs_conn_out_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port);
+struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p);
struct ip_vs_conn * ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb,
struct ip_vs_protocol *pp,
@@ -656,11 +716,10 @@ static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
extern void ip_vs_conn_put(struct ip_vs_conn *cp);
extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport);
-extern struct ip_vs_conn *
-ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
- const union nf_inet_addr *vaddr, __be16 vport,
- const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
- struct ip_vs_dest *dest);
+struct ip_vs_conn *ip_vs_conn_new(const struct ip_vs_conn_param *p,
+ const union nf_inet_addr *daddr,
+ __be16 dport, unsigned flags,
+ struct ip_vs_dest *dest);
extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp);
extern const char * ip_vs_state_name(__u16 proto, int state);
@@ -751,6 +810,12 @@ extern int ip_vs_app_pkt_in(struct ip_vs_conn *, struct sk_buff *skb);
extern int ip_vs_app_init(void);
extern void ip_vs_app_cleanup(void);
+void ip_vs_bind_pe(struct ip_vs_service *svc, struct ip_vs_pe *pe);
+void ip_vs_unbind_pe(struct ip_vs_service *svc);
+int register_ip_vs_pe(struct ip_vs_pe *pe);
+int unregister_ip_vs_pe(struct ip_vs_pe *pe);
+extern struct ip_vs_pe *ip_vs_pe_get(const char *name);
+extern void ip_vs_pe_put(struct ip_vs_pe *pe);
/*
* IPVS protocol functions (from ip_vs_proto.c)
@@ -763,7 +828,8 @@ extern int
ip_vs_set_state_timeout(int *table, int num, const char *const *names,
const char *name, int to);
extern void
-ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb,
+ip_vs_tcpudp_debug_packet(int af, struct ip_vs_protocol *pp,
+ const struct sk_buff *skb,
int offset, const char *msg);
extern struct ip_vs_protocol ip_vs_protocol_tcp;
@@ -785,7 +851,8 @@ extern int ip_vs_unbind_scheduler(struct ip_vs_service *svc);
extern struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name);
extern void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler);
extern struct ip_vs_conn *
-ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb);
+ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
+ struct ip_vs_protocol *pp, int *ignored);
extern int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
struct ip_vs_protocol *pp);
@@ -798,6 +865,8 @@ extern int sysctl_ip_vs_expire_nodest_conn;
extern int sysctl_ip_vs_expire_quiescent_template;
extern int sysctl_ip_vs_sync_threshold[2];
extern int sysctl_ip_vs_nat_icmp_send;
+extern int sysctl_ip_vs_conntrack;
+extern int sysctl_ip_vs_snat_reroute;
extern struct ip_vs_stats ip_vs_stats;
extern const struct ctl_path net_vs_ctl_path[];
@@ -955,8 +1024,65 @@ static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum)
return csum_partial(diff, sizeof(diff), oldsum);
}
+/*
+ * Forget current conntrack (unconfirmed) and attach notrack entry
+ */
+static inline void ip_vs_notrack(struct sk_buff *skb)
+{
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo);
+
+ if (!ct || !nf_ct_is_untracked(ct)) {
+ nf_reset(skb);
+ skb->nfct = &nf_ct_untracked_get()->ct_general;
+ skb->nfctinfo = IP_CT_NEW;
+ nf_conntrack_get(skb->nfct);
+ }
+#endif
+}
+
+#ifdef CONFIG_IP_VS_NFCT
+/*
+ * Netfilter connection tracking
+ * (from ip_vs_nfct.c)
+ */
+static inline int ip_vs_conntrack_enabled(void)
+{
+ return sysctl_ip_vs_conntrack;
+}
+
extern void ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp,
int outin);
+extern int ip_vs_confirm_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp);
+extern void ip_vs_nfct_expect_related(struct sk_buff *skb, struct nf_conn *ct,
+ struct ip_vs_conn *cp, u_int8_t proto,
+ const __be16 port, int from_rs);
+extern void ip_vs_conn_drop_conntrack(struct ip_vs_conn *cp);
+
+#else
+
+static inline int ip_vs_conntrack_enabled(void)
+{
+ return 0;
+}
+
+static inline void ip_vs_update_conntrack(struct sk_buff *skb,
+ struct ip_vs_conn *cp, int outin)
+{
+}
+
+static inline int ip_vs_confirm_conntrack(struct sk_buff *skb,
+ struct ip_vs_conn *cp)
+{
+ return NF_ACCEPT;
+}
+
+static inline void ip_vs_conn_drop_conntrack(struct ip_vs_conn *cp)
+{
+}
+/* CONFIG_IP_VS_NFCT */
+#endif
#endif /* __KERNEL__ */
diff --git a/include/net/ipip.h b/include/net/ipip.h
index 65caea8b414f..a32654d52730 100644
--- a/include/net/ipip.h
+++ b/include/net/ipip.h
@@ -16,7 +16,7 @@ struct ip_tunnel_6rd_parm {
};
struct ip_tunnel {
- struct ip_tunnel *next;
+ struct ip_tunnel __rcu *next;
struct net_device *dev;
int err_count; /* Number of arrived ICMP errors */
@@ -34,18 +34,18 @@ struct ip_tunnel {
#ifdef CONFIG_IPV6_SIT_6RD
struct ip_tunnel_6rd_parm ip6rd;
#endif
- struct ip_tunnel_prl_entry *prl; /* potential router list */
+ struct ip_tunnel_prl_entry __rcu *prl; /* potential router list */
unsigned int prl_count; /* # of entries in PRL */
};
struct ip_tunnel_prl_entry {
- struct ip_tunnel_prl_entry *next;
+ struct ip_tunnel_prl_entry __rcu *next;
__be32 addr;
u16 flags;
struct rcu_head rcu_head;
};
-#define IPTUNNEL_XMIT() do { \
+#define __IPTUNNEL_XMIT(stats1, stats2) do { \
int err; \
int pkt_len = skb->len - skb_transport_offset(skb); \
\
@@ -54,12 +54,14 @@ struct ip_tunnel_prl_entry {
\
err = ip_local_out(skb); \
if (likely(net_xmit_eval(err) == 0)) { \
- txq->tx_bytes += pkt_len; \
- txq->tx_packets++; \
+ (stats1)->tx_bytes += pkt_len; \
+ (stats1)->tx_packets++; \
} else { \
- stats->tx_errors++; \
- stats->tx_aborted_errors++; \
+ (stats2)->tx_errors++; \
+ (stats2)->tx_aborted_errors++; \
} \
} while (0)
+#define IPTUNNEL_XMIT() __IPTUNNEL_XMIT(txq, stats)
+
#endif
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 1f8412410998..4a3cd2cd2f5e 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -262,7 +262,7 @@ static inline int ipv6_addr_scope(const struct in6_addr *addr)
static inline int __ipv6_addr_src_scope(int type)
{
- return (type == IPV6_ADDR_ANY ? __IPV6_ADDR_SCOPE_INVALID : (type >> 16));
+ return (type == IPV6_ADDR_ANY) ? __IPV6_ADDR_SCOPE_INVALID : (type >> 16);
}
static inline int ipv6_addr_src_scope(const struct in6_addr *addr)
@@ -279,10 +279,10 @@ static inline int
ipv6_masked_addr_cmp(const struct in6_addr *a1, const struct in6_addr *m,
const struct in6_addr *a2)
{
- return (!!(((a1->s6_addr32[0] ^ a2->s6_addr32[0]) & m->s6_addr32[0]) |
- ((a1->s6_addr32[1] ^ a2->s6_addr32[1]) & m->s6_addr32[1]) |
- ((a1->s6_addr32[2] ^ a2->s6_addr32[2]) & m->s6_addr32[2]) |
- ((a1->s6_addr32[3] ^ a2->s6_addr32[3]) & m->s6_addr32[3])));
+ return !!(((a1->s6_addr32[0] ^ a2->s6_addr32[0]) & m->s6_addr32[0]) |
+ ((a1->s6_addr32[1] ^ a2->s6_addr32[1]) & m->s6_addr32[1]) |
+ ((a1->s6_addr32[2] ^ a2->s6_addr32[2]) & m->s6_addr32[2]) |
+ ((a1->s6_addr32[3] ^ a2->s6_addr32[3]) & m->s6_addr32[3]));
}
static inline void ipv6_addr_copy(struct in6_addr *a1, const struct in6_addr *a2)
@@ -317,10 +317,10 @@ static inline void ipv6_addr_set(struct in6_addr *addr,
static inline int ipv6_addr_equal(const struct in6_addr *a1,
const struct in6_addr *a2)
{
- return (((a1->s6_addr32[0] ^ a2->s6_addr32[0]) |
- (a1->s6_addr32[1] ^ a2->s6_addr32[1]) |
- (a1->s6_addr32[2] ^ a2->s6_addr32[2]) |
- (a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0);
+ return ((a1->s6_addr32[0] ^ a2->s6_addr32[0]) |
+ (a1->s6_addr32[1] ^ a2->s6_addr32[1]) |
+ (a1->s6_addr32[2] ^ a2->s6_addr32[2]) |
+ (a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0;
}
static inline int __ipv6_prefix_equal(const __be32 *a1, const __be32 *a2,
@@ -373,20 +373,20 @@ int ip6_frag_match(struct inet_frag_queue *q, void *a);
static inline int ipv6_addr_any(const struct in6_addr *a)
{
- return ((a->s6_addr32[0] | a->s6_addr32[1] |
- a->s6_addr32[2] | a->s6_addr32[3] ) == 0);
+ return (a->s6_addr32[0] | a->s6_addr32[1] |
+ a->s6_addr32[2] | a->s6_addr32[3]) == 0;
}
static inline int ipv6_addr_loopback(const struct in6_addr *a)
{
- return ((a->s6_addr32[0] | a->s6_addr32[1] |
- a->s6_addr32[2] | (a->s6_addr32[3] ^ htonl(1))) == 0);
+ return (a->s6_addr32[0] | a->s6_addr32[1] |
+ a->s6_addr32[2] | (a->s6_addr32[3] ^ htonl(1))) == 0;
}
static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
{
- return ((a->s6_addr32[0] | a->s6_addr32[1] |
- (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0);
+ return (a->s6_addr32[0] | a->s6_addr32[1] |
+ (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0;
}
/*
@@ -395,8 +395,7 @@ static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
*/
static inline int ipv6_addr_orchid(const struct in6_addr *a)
{
- return ((a->s6_addr32[0] & htonl(0xfffffff0))
- == htonl(0x20010010));
+ return (a->s6_addr32[0] & htonl(0xfffffff0)) == htonl(0x20010010);
}
static inline void ipv6_addr_set_v4mapped(const __be32 addr,
@@ -441,7 +440,7 @@ static inline int __ipv6_addr_diff(const void *token1, const void *token2, int a
* if returned value is greater than prefix length.
* --ANK (980803)
*/
- return (addrlen << 5);
+ return addrlen << 5;
}
static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_addr *a2)
diff --git a/include/net/irda/irlan_common.h b/include/net/irda/irlan_common.h
index 73cacb3ac16c..0af8b8dfbc22 100644
--- a/include/net/irda/irlan_common.h
+++ b/include/net/irda/irlan_common.h
@@ -171,7 +171,6 @@ struct irlan_cb {
int magic;
struct list_head dev_list;
struct net_device *dev; /* Ethernet device structure*/
- struct net_device_stats stats;
__u32 saddr; /* Source device address */
__u32 daddr; /* Destination device address */
diff --git a/include/net/irda/irlan_event.h b/include/net/irda/irlan_event.h
index 6d9539f05806..018b5a77e610 100644
--- a/include/net/irda/irlan_event.h
+++ b/include/net/irda/irlan_event.h
@@ -67,7 +67,7 @@ typedef enum {
IRLAN_WATCHDOG_TIMEOUT,
} IRLAN_EVENT;
-extern char *irlan_state[];
+extern const char * const irlan_state[];
void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb);
diff --git a/include/net/irda/irlap.h b/include/net/irda/irlap.h
index 9d0c78ea92f5..17fcd964f9d9 100644
--- a/include/net/irda/irlap.h
+++ b/include/net/irda/irlap.h
@@ -282,7 +282,7 @@ static inline int irlap_is_primary(struct irlap_cb *self)
default:
ret = -1;
}
- return(ret);
+ return ret;
}
/* Clear a pending IrLAP disconnect. - Jean II */
diff --git a/include/net/irda/irlmp.h b/include/net/irda/irlmp.h
index 3ffc1d0f93d6..fff11b7fe8a4 100644
--- a/include/net/irda/irlmp.h
+++ b/include/net/irda/irlmp.h
@@ -274,7 +274,7 @@ static inline int irlmp_lap_tx_queue_full(struct lsap_cb *self)
if (self->lap->irlap == NULL)
return 0;
- return(IRLAP_GET_TX_QUEUE_LEN(self->lap->irlap) >= LAP_HIGH_THRESHOLD);
+ return IRLAP_GET_TX_QUEUE_LEN(self->lap->irlap) >= LAP_HIGH_THRESHOLD;
}
/* After doing a irlmp_dup(), this get one of the two socket back into
diff --git a/include/net/irda/irttp.h b/include/net/irda/irttp.h
index 11aee7a2972a..af4b87721d13 100644
--- a/include/net/irda/irttp.h
+++ b/include/net/irda/irttp.h
@@ -204,7 +204,7 @@ static inline int irttp_is_primary(struct tsap_cb *self)
(self->lsap->lap == NULL) ||
(self->lsap->lap->irlap == NULL))
return -2;
- return(irlap_is_primary(self->lsap->lap->irlap));
+ return irlap_is_primary(self->lsap->lap->irlap);
}
#endif /* IRTTP_H */
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index b0787a1dea90..9fdf982d1286 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -149,6 +149,7 @@ struct ieee80211_low_level_stats {
* @BSS_CHANGED_ARP_FILTER: Hardware ARP filter address list or state changed.
* @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.
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
@@ -165,6 +166,7 @@ enum ieee80211_bss_change {
BSS_CHANGED_IBSS = 1<<11,
BSS_CHANGED_ARP_FILTER = 1<<12,
BSS_CHANGED_QOS = 1<<13,
+ BSS_CHANGED_IDLE = 1<<14,
/* when adding here, make sure to change ieee80211_reconfig */
};
@@ -223,6 +225,9 @@ enum ieee80211_bss_change {
* hardware must not perform any ARP filtering. Note, that the filter will
* be enabled also in promiscuous mode.
* @qos: This is a QoS-enabled BSS.
+ * @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.
*/
struct ieee80211_bss_conf {
const u8 *bssid;
@@ -247,6 +252,7 @@ struct ieee80211_bss_conf {
u8 arp_addr_cnt;
bool arp_filter_enabled;
bool qos;
+ bool idle;
};
/**
@@ -315,6 +321,9 @@ struct ieee80211_bss_conf {
* @IEEE80211_TX_CTL_LDPC: tells the driver to use LDPC for this frame
* @IEEE80211_TX_CTL_STBC: Enables Space-Time Block Coding (STBC) for this
* frame and selects the maximum number of streams that it can use.
+ *
+ * Note: If you have to add new flags to the enumeration, then don't
+ * forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
*/
enum mac80211_tx_control_flags {
IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0),
@@ -344,6 +353,19 @@ enum mac80211_tx_control_flags {
#define IEEE80211_TX_CTL_STBC_SHIFT 23
+/*
+ * This definition is used as a mask to clear all temporary flags, which are
+ * set by the tx handlers for each transmission attempt by the mac80211 stack.
+ */
+#define IEEE80211_TX_TEMPORARY_FLAGS (IEEE80211_TX_CTL_NO_ACK | \
+ IEEE80211_TX_CTL_CLEAR_PS_FILT | IEEE80211_TX_CTL_FIRST_FRAGMENT | \
+ 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_MORE_FRAMES | IEEE80211_TX_CTL_LDPC | \
+ IEEE80211_TX_CTL_STBC)
+
/**
* enum mac80211_rate_control_flags - per-rate flags set by the
* Rate Control algorithm.
@@ -559,9 +581,6 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
* @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index
* @RX_FLAG_40MHZ: HT40 (40 MHz) was used
* @RX_FLAG_SHORT_GI: Short guard interval was used
- * @RX_FLAG_INTERNAL_CMTR: set internally after frame was reported
- * on cooked monitor to avoid double-reporting it for multiple
- * virtual interfaces
*/
enum mac80211_rx_flags {
RX_FLAG_MMIC_ERROR = 1<<0,
@@ -575,7 +594,6 @@ enum mac80211_rx_flags {
RX_FLAG_HT = 1<<9,
RX_FLAG_40MHZ = 1<<10,
RX_FLAG_SHORT_GI = 1<<11,
- RX_FLAG_INTERNAL_CMTR = 1<<12,
};
/**
@@ -596,6 +614,7 @@ enum mac80211_rx_flags {
* @rate_idx: index of data rate into band's supported rates or MCS index if
* HT rates are use (RX_FLAG_HT)
* @flag: %RX_FLAG_*
+ * @rx_flags: internal RX flags for mac80211
*/
struct ieee80211_rx_status {
u64 mactime;
@@ -605,6 +624,7 @@ struct ieee80211_rx_status {
int antenna;
int rate_idx;
int flag;
+ unsigned int rx_flags;
};
/**
@@ -763,6 +783,8 @@ struct ieee80211_channel_switch {
* @bss_conf: BSS configuration for this interface, either our own
* or the BSS we're associated to
* @addr: address of this interface
+ * @p2p: indicates whether this AP or STA interface is a p2p
+ * interface, i.e. a GO or p2p-sta respectively
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *).
*/
@@ -770,6 +792,7 @@ struct ieee80211_vif {
enum nl80211_iftype type;
struct ieee80211_bss_conf bss_conf;
u8 addr[ETH_ALEN];
+ bool p2p;
/* must be last */
u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
};
@@ -783,20 +806,6 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
}
/**
- * enum ieee80211_key_alg - key algorithm
- * @ALG_WEP: WEP40 or WEP104
- * @ALG_TKIP: TKIP
- * @ALG_CCMP: CCMP (AES)
- * @ALG_AES_CMAC: AES-128-CMAC
- */
-enum ieee80211_key_alg {
- ALG_WEP,
- ALG_TKIP,
- ALG_CCMP,
- ALG_AES_CMAC,
-};
-
-/**
* enum ieee80211_key_flags - key flags
*
* These flags are used for communication about keys between the driver
@@ -833,7 +842,7 @@ enum ieee80211_key_flags {
* @hw_key_idx: To be set by the driver, this is the key index the driver
* wants to be given when a frame is transmitted and needs to be
* encrypted in hardware.
- * @alg: The key algorithm.
+ * @cipher: The key's cipher suite selector.
* @flags: key flags, see &enum ieee80211_key_flags.
* @keyidx: the key index (0-3)
* @keylen: key material length
@@ -846,7 +855,7 @@ enum ieee80211_key_flags {
* @iv_len: The IV length for this key type
*/
struct ieee80211_key_conf {
- enum ieee80211_key_alg alg;
+ u32 cipher;
u8 icv_len;
u8 iv_len;
u8 hw_key_idx;
@@ -1032,6 +1041,13 @@ enum ieee80211_tkip_key_type {
* @IEEE80211_HW_NEED_DTIM_PERIOD:
* This device needs to know the DTIM period for the BSS before
* associating.
+ *
+ * @IEEE80211_HW_SUPPORTS_PER_STA_GTK: The device's crypto engine supports
+ * per-station GTKs as used by IBSS RSN or during fast transition. If
+ * the device doesn't support per-station GTKs, but can be asked not
+ * to decrypt group addressed frames, then IBSS RSN support is still
+ * possible but software crypto will be used. Advertise the wiphy flag
+ * only in that case.
*/
enum ieee80211_hw_flags {
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
@@ -1055,6 +1071,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18,
IEEE80211_HW_CONNECTION_MONITOR = 1<<19,
IEEE80211_HW_SUPPORTS_CQM_RSSI = 1<<20,
+ IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21,
};
/**
@@ -1100,8 +1117,15 @@ enum ieee80211_hw_flags {
* @sta_data_size: size (in bytes) of the drv_priv data area
* within &struct ieee80211_sta.
*
- * @max_rates: maximum number of alternate rate retry stages
+ * @max_rates: maximum number of alternate rate retry stages the hw
+ * can handle.
+ * @max_report_rates: maximum number of alternate rate retry stages
+ * the hw can report back.
* @max_rate_tries: maximum number of tries for each stage
+ *
+ * @napi_weight: weight used for NAPI polling. You must specify an
+ * appropriate value here if a napi_poll operation is provided
+ * by your driver.
*/
struct ieee80211_hw {
struct ieee80211_conf conf;
@@ -1113,10 +1137,12 @@ struct ieee80211_hw {
int channel_change_time;
int vif_data_size;
int sta_data_size;
+ int napi_weight;
u16 queues;
u16 max_listen_interval;
s8 max_signal;
u8 max_rates;
+ u8 max_report_rates;
u8 max_rate_tries;
};
@@ -1245,8 +1271,8 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
* %IEEE80211_CONF_PS flag enabled means that the powersave mode defined in
* IEEE 802.11-2007 section 11.2 is enabled. This is not to be confused
* with hardware wakeup and sleep states. Driver is responsible for waking
- * up the hardware before issueing commands to the hardware and putting it
- * back to sleep at approriate times.
+ * up the hardware before issuing commands to the hardware and putting it
+ * back to sleep at appropriate times.
*
* When PS is enabled, hardware needs to wakeup for beacons and receive the
* buffered multicast/broadcast frames after the beacon. Also it must be
@@ -1267,7 +1293,7 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
* there's data traffic and still saving significantly power in idle
* periods.
*
- * Dynamic powersave is supported by simply mac80211 enabling and disabling
+ * Dynamic powersave is simply supported by mac80211 enabling and disabling
* PS based on traffic. Driver needs to only set %IEEE80211_HW_SUPPORTS_PS
* flag and mac80211 will handle everything automatically. Additionally,
* hardware having support for the dynamic PS feature may set the
@@ -1452,12 +1478,14 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
* honour this flag if possible.
*
* @FIF_CONTROL: pass control frames (except for PS Poll), if PROMISC_IN_BSS
- * is not set then only those addressed to this station.
+ * is not set then only those addressed to this station.
*
* @FIF_OTHER_BSS: pass frames destined to other BSSes
*
- * @FIF_PSPOLL: pass PS Poll frames, if PROMISC_IN_BSS is not set then only
- * those addressed to this station.
+ * @FIF_PSPOLL: pass PS Poll frames, if PROMISC_IN_BSS is not set then only
+ * those addressed to this station.
+ *
+ * @FIF_PROBE_REQ: pass probe request frames
*/
enum ieee80211_filter_flags {
FIF_PROMISC_IN_BSS = 1<<0,
@@ -1468,6 +1496,7 @@ enum ieee80211_filter_flags {
FIF_CONTROL = 1<<5,
FIF_OTHER_BSS = 1<<6,
FIF_PSPOLL = 1<<7,
+ FIF_PROBE_REQ = 1<<8,
};
/**
@@ -1540,6 +1569,12 @@ enum ieee80211_ampdu_mlme_action {
* negative error code (which will be seen in userspace.)
* Must be implemented and can sleep.
*
+ * @change_interface: Called when a netdevice changes type. This callback
+ * is optional, but only if it is supported can interface types be
+ * switched while the interface is UP. The callback may sleep.
+ * Note that while an interface is being switched, it will not be
+ * found by the interface iteration callbacks.
+ *
* @remove_interface: Notifies a driver that an interface is going down.
* The @stop callback is called after this if it is the last interface
* and no monitor interfaces are present.
@@ -1687,6 +1722,8 @@ enum ieee80211_ampdu_mlme_action {
* switch operation for CSAs received from the AP may implement this
* callback. They must then call ieee80211_chswitch_done() to indicate
* completion of the channel switch.
+ *
+ * @napi_poll: Poll Rx queue for incoming data frames.
*/
struct ieee80211_ops {
int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1694,6 +1731,9 @@ struct ieee80211_ops {
void (*stop)(struct ieee80211_hw *hw);
int (*add_interface)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
+ int (*change_interface)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum nl80211_iftype new_type, bool p2p);
void (*remove_interface)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int (*config)(struct ieee80211_hw *hw, u32 changed);
@@ -1752,6 +1792,7 @@ struct ieee80211_ops {
void (*flush)(struct ieee80211_hw *hw, bool drop);
void (*channel_switch)(struct ieee80211_hw *hw,
struct ieee80211_channel_switch *ch_switch);
+ int (*napi_poll)(struct ieee80211_hw *hw, int budget);
};
/**
@@ -1897,6 +1938,22 @@ void ieee80211_free_hw(struct ieee80211_hw *hw);
*/
void ieee80211_restart_hw(struct ieee80211_hw *hw);
+/** ieee80211_napi_schedule - schedule NAPI poll
+ *
+ * Use this function to schedule NAPI polling on a device.
+ *
+ * @hw: the hardware to start polling
+ */
+void ieee80211_napi_schedule(struct ieee80211_hw *hw);
+
+/** ieee80211_napi_complete - complete NAPI polling
+ *
+ * Use this function to finish NAPI polling on a device.
+ *
+ * @hw: the hardware to stop polling
+ */
+void ieee80211_napi_complete(struct ieee80211_hw *hw);
+
/**
* ieee80211_rx - receive frame
*
@@ -2252,7 +2309,8 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw);
*
* When hardware scan offload is used (i.e. the hw_scan() callback is
* assigned) this function needs to be called by the driver to notify
- * mac80211 that the scan finished.
+ * mac80211 that the scan finished. This function can be called from
+ * any context, including hardirq context.
*
* @hw: the hardware that finished the scan
* @aborted: set to true if scan was aborted
@@ -2267,6 +2325,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted);
* This function allows the iterator function to sleep, when the iterator
* function is atomic @ieee80211_iterate_active_interfaces_atomic can
* be used.
+ * Does not iterate over a new interface during add_interface()
*
* @hw: the hardware struct of which the interfaces should be iterated over
* @iterator: the iterator function to call
@@ -2284,6 +2343,7 @@ void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw,
* hardware that are currently active and calls the callback for them.
* This function requires the iterator callback function to be atomic,
* if that is not desired, use @ieee80211_iterate_active_interfaces instead.
+ * Does not iterate over a new interface during add_interface()
*
* @hw: the hardware struct of which the interfaces should be iterated over
* @iterator: the iterator function to call, cannot sleep
@@ -2385,25 +2445,28 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
const u8 *addr);
/**
- * ieee80211_find_sta_by_hw - find a station on hardware
+ * ieee80211_find_sta_by_ifaddr - find a station on hardware
*
* @hw: pointer as obtained from ieee80211_alloc_hw()
- * @addr: station's address
+ * @addr: remote station's address
+ * @localaddr: local address (vif->sdata->vif.addr). Use NULL for 'any'.
*
* This function must be called under RCU lock and the
* resulting pointer is only valid under RCU lock as well.
*
- * NOTE: This function should not be used! When mac80211 is converted
- * internally to properly keep track of stations on multiple
- * virtual interfaces, it will not always know which station to
- * return here since a single address might be used by multiple
- * logical stations (e.g. consider a station connecting to another
- * BSSID on the same AP hardware without disconnecting first).
+ * NOTE: You may pass NULL for localaddr, but then you will just get
+ * the first STA that matches the remote address 'addr'.
+ * We can have multiple STA associated with multiple
+ * logical stations (e.g. consider a station connecting to another
+ * BSSID on the same AP hardware without disconnecting first).
+ * In this case, the result of this method with localaddr NULL
+ * is not reliable.
*
- * DO NOT USE THIS FUNCTION.
+ * DO NOT USE THIS FUNCTION with localaddr NULL if at all possible.
*/
-struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw,
- const u8 *addr);
+struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw,
+ const u8 *addr,
+ const u8 *localaddr);
/**
* ieee80211_sta_block_awake - block station from waking up
@@ -2442,7 +2505,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
*
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
*
- * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTERING and
+ * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTER and
* %IEEE80211_CONF_PS is set, the driver needs to inform whenever the
* hardware is not receiving beacons with this function.
*/
@@ -2453,7 +2516,7 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif);
*
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
*
- * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTERING, and
+ * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTER, and
* %IEEE80211_CONF_PS and %IEEE80211_HW_CONNECTION_MONITOR are set, the driver
* needs to inform if the connection to the AP has been lost.
*
@@ -2518,6 +2581,34 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
*/
void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success);
+/**
+ * ieee80211_request_smps - request SM PS transition
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @smps_mode: new SM PS mode
+ *
+ * This allows the driver to request an SM PS transition in managed
+ * mode. This is useful when the driver has more information than
+ * the stack about possible interference, for example by bluetooth.
+ */
+void ieee80211_request_smps(struct ieee80211_vif *vif,
+ enum ieee80211_smps_mode smps_mode);
+
+/**
+ * ieee80211_key_removed - disable hw acceleration for key
+ * @key_conf: The key hw acceleration should be disabled for
+ *
+ * This allows drivers to indicate that the given key has been
+ * removed from hardware acceleration, due to a new key that
+ * was added. Don't use this if the key can continue to be used
+ * for TX, if the key restriction is on RX only it is permitted
+ * to keep the key for TX only and not call this function.
+ *
+ * Due to locking constraints, it may only be called during
+ * @set_key. This function must be allowed to sleep, and the
+ * key it tries to disable may still be used until it returns.
+ */
+void ieee80211_key_removed(struct ieee80211_key_conf *key_conf);
+
/* Rate control API */
/**
@@ -2681,4 +2772,26 @@ conf_is_ht(struct ieee80211_conf *conf)
return conf->channel_type != NL80211_CHAN_NO_HT;
}
+static inline enum nl80211_iftype
+ieee80211_iftype_p2p(enum nl80211_iftype type, bool p2p)
+{
+ if (p2p) {
+ switch (type) {
+ case NL80211_IFTYPE_STATION:
+ return NL80211_IFTYPE_P2P_CLIENT;
+ case NL80211_IFTYPE_AP:
+ return NL80211_IFTYPE_P2P_GO;
+ default:
+ break;
+ }
+ }
+ return type;
+}
+
+static inline enum nl80211_iftype
+ieee80211_vif_type_p2p(struct ieee80211_vif *vif)
+{
+ return ieee80211_iftype_p2p(vif->type, vif->p2p);
+}
+
#endif /* MAC80211_H */
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 242879b6c4df..55590ab16b3e 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -91,26 +91,28 @@ struct neigh_statistics {
#define NEIGH_CACHE_STAT_INC(tbl, field) this_cpu_inc((tbl)->stats->field)
struct neighbour {
- struct neighbour *next;
+ struct neighbour __rcu *next;
struct neigh_table *tbl;
struct neigh_parms *parms;
- struct net_device *dev;
- unsigned long used;
unsigned long confirmed;
unsigned long updated;
__u8 flags;
__u8 nud_state;
__u8 type;
__u8 dead;
+ atomic_t refcnt;
+ struct sk_buff_head arp_queue;
+ struct timer_list timer;
+ unsigned long used;
atomic_t probes;
rwlock_t lock;
+ seqlock_t ha_lock;
unsigned char ha[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))];
struct hh_cache *hh;
- atomic_t refcnt;
int (*output)(struct sk_buff *skb);
- struct sk_buff_head arp_queue;
- struct timer_list timer;
const struct neigh_ops *ops;
+ struct rcu_head rcu;
+ struct net_device *dev;
u8 primary_key[0];
};
@@ -138,13 +140,22 @@ struct pneigh_entry {
* neighbour table manipulation
*/
+struct neigh_hash_table {
+ struct neighbour __rcu **hash_buckets;
+ unsigned int hash_mask;
+ __u32 hash_rnd;
+ struct rcu_head rcu;
+};
+
struct neigh_table {
struct neigh_table *next;
int family;
int entry_size;
int key_len;
- __u32 (*hash)(const void *pkey, const struct net_device *);
+ __u32 (*hash)(const void *pkey,
+ const struct net_device *dev,
+ __u32 hash_rnd);
int (*constructor)(struct neighbour *);
int (*pconstructor)(struct pneigh_entry *);
void (*pdestructor)(struct pneigh_entry *);
@@ -163,11 +174,9 @@ struct neigh_table {
atomic_t entries;
rwlock_t lock;
unsigned long last_rand;
- struct kmem_cache *kmem_cachep;
+ struct kmem_cache *kmem_cachep;
struct neigh_statistics __percpu *stats;
- struct neighbour **hash_buckets;
- unsigned int hash_mask;
- __u32 hash_rnd;
+ struct neigh_hash_table __rcu *nht;
struct pneigh_entry **phash_buckets;
};
@@ -237,6 +246,7 @@ extern void pneigh_for_each(struct neigh_table *tbl, void (*cb)(struct pneigh_en
struct neigh_seq_state {
struct seq_net_private p;
struct neigh_table *tbl;
+ struct neigh_hash_table *nht;
void *(*neigh_sub_iter)(struct neigh_seq_state *state,
struct neighbour *n, loff_t *pos);
unsigned int bucket;
@@ -293,7 +303,10 @@ static inline void neigh_confirm(struct neighbour *neigh)
static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
{
- neigh->used = jiffies;
+ unsigned long now = ACCESS_ONCE(jiffies);
+
+ if (neigh->used != now)
+ neigh->used = now;
if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE)))
return __neigh_event_send(neigh, skb);
return 0;
@@ -364,4 +377,14 @@ struct neighbour_cb {
#define NEIGH_CB(skb) ((struct neighbour_cb *)(skb)->cb)
+static inline void neigh_ha_snapshot(char *dst, const struct neighbour *n,
+ const struct net_device *dev)
+{
+ unsigned int seq;
+
+ do {
+ seq = read_seqbegin(&n->ha_lock);
+ memcpy(dst, n->ha, dev->addr_len);
+ } while (read_seqretry(&n->ha_lock, seq));
+}
#endif
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index bd10a7908993..1bf812b21fb7 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -41,6 +41,8 @@ struct net {
* destroy on demand
*/
#endif
+ spinlock_t rules_mod_lock;
+
struct list_head list; /* list of network namespaces */
struct list_head cleanup_list; /* namespaces on death row */
struct list_head exit_list; /* Use only net_mutex */
@@ -52,7 +54,8 @@ struct net {
struct ctl_table_set sysctls;
#endif
- struct net_device *loopback_dev; /* The loopback */
+ struct sock *rtnl; /* rtnetlink socket */
+ struct sock *genl_sock;
struct list_head dev_base_head;
struct hlist_head *dev_name_head;
@@ -60,11 +63,9 @@ struct net {
/* core fib_rules */
struct list_head rules_ops;
- spinlock_t rules_mod_lock;
- struct sock *rtnl; /* rtnetlink socket */
- struct sock *genl_sock;
+ struct net_device *loopback_dev; /* The loopback */
struct netns_core core;
struct netns_mib mib;
struct netns_packet packet;
@@ -84,13 +85,15 @@ struct net {
struct sock *nfnl;
struct sock *nfnl_stash;
#endif
-#ifdef CONFIG_XFRM
- struct netns_xfrm xfrm;
-#endif
#ifdef CONFIG_WEXT_CORE
struct sk_buff_head wext_nlevents;
#endif
- struct net_generic *gen;
+ struct net_generic __rcu *gen;
+
+ /* Note : following structs are cache line aligned */
+#ifdef CONFIG_XFRM
+ struct netns_xfrm xfrm;
+#endif
};
diff --git a/include/net/netfilter/ipv6/nf_defrag_ipv6.h b/include/net/netfilter/ipv6/nf_defrag_ipv6.h
new file mode 100644
index 000000000000..94dd54d76b48
--- /dev/null
+++ b/include/net/netfilter/ipv6/nf_defrag_ipv6.h
@@ -0,0 +1,6 @@
+#ifndef _NF_DEFRAG_IPV6_H
+#define _NF_DEFRAG_IPV6_H
+
+extern void nf_defrag_ipv6_enable(void);
+
+#endif /* _NF_DEFRAG_IPV6_H */
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index 11e815084fcf..0f8a8c587532 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -67,9 +67,6 @@ struct nf_conntrack_expect_policy {
#define NF_CT_EXPECT_CLASS_DEFAULT 0
-#define NF_CT_EXPECT_PERMANENT 0x1
-#define NF_CT_EXPECT_INACTIVE 0x2
-
int nf_conntrack_expect_init(struct net *net);
void nf_conntrack_expect_fini(struct net *net);
@@ -85,9 +82,16 @@ struct nf_conntrack_expect *
nf_ct_find_expectation(struct net *net, u16 zone,
const struct nf_conntrack_tuple *tuple);
-void nf_ct_unlink_expect(struct nf_conntrack_expect *exp);
+void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
+ u32 pid, int report);
+static inline void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
+{
+ nf_ct_unlink_expect_report(exp, 0, 0);
+}
+
void nf_ct_remove_expectations(struct nf_conn *ct);
void nf_ct_unexpect_related(struct nf_conntrack_expect *exp);
+void nf_ct_remove_userspace_expectations(void);
/* Allocate space for an expectation: this is mandatory before calling
nf_ct_expect_related. You will have to call put afterwards. */
diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h
index df17bac46bf5..93cc90d28e66 100644
--- a/include/net/netfilter/nf_nat_protocol.h
+++ b/include/net/netfilter/nf_nat_protocol.h
@@ -45,9 +45,6 @@ struct nf_nat_protocol {
extern int nf_nat_protocol_register(const struct nf_nat_protocol *proto);
extern void nf_nat_protocol_unregister(const struct nf_nat_protocol *proto);
-extern const struct nf_nat_protocol *nf_nat_proto_find_get(u_int8_t protocol);
-extern void nf_nat_proto_put(const struct nf_nat_protocol *proto);
-
/* Built-in protocols. */
extern const struct nf_nat_protocol nf_nat_protocol_tcp;
extern const struct nf_nat_protocol nf_nat_protocol_udp;
diff --git a/include/net/netfilter/nf_tproxy_core.h b/include/net/netfilter/nf_tproxy_core.h
index 208b46f4d6d2..cd85b3bc8327 100644
--- a/include/net/netfilter/nf_tproxy_core.h
+++ b/include/net/netfilter/nf_tproxy_core.h
@@ -5,15 +5,201 @@
#include <linux/in.h>
#include <linux/skbuff.h>
#include <net/sock.h>
-#include <net/inet_sock.h>
+#include <net/inet_hashtables.h>
+#include <net/inet6_hashtables.h>
#include <net/tcp.h>
+#define NFT_LOOKUP_ANY 0
+#define NFT_LOOKUP_LISTENER 1
+#define NFT_LOOKUP_ESTABLISHED 2
+
/* look up and get a reference to a matching socket */
-extern struct sock *
+
+
+/* This function is used by the 'TPROXY' target and the 'socket'
+ * match. The following lookups are supported:
+ *
+ * Explicit TProxy target rule
+ * ===========================
+ *
+ * This is used when the user wants to intercept a connection matching
+ * an explicit iptables rule. In this case the sockets are assumed
+ * matching in preference order:
+ *
+ * - match: if there's a fully established connection matching the
+ * _packet_ tuple, it is returned, assuming the redirection
+ * already took place and we process a packet belonging to an
+ * established connection
+ *
+ * - match: if there's a listening socket matching the redirection
+ * (e.g. on-port & on-ip of the connection), it is returned,
+ * regardless if it was bound to 0.0.0.0 or an explicit
+ * address. The reasoning is that if there's an explicit rule, it
+ * does not really matter if the listener is bound to an interface
+ * or to 0. The user already stated that he wants redirection
+ * (since he added the rule).
+ *
+ * "socket" match based redirection (no specific rule)
+ * ===================================================
+ *
+ * There are connections with dynamic endpoints (e.g. FTP data
+ * connection) that the user is unable to add explicit rules
+ * for. These are taken care of by a generic "socket" rule. It is
+ * assumed that the proxy application is trusted to open such
+ * connections without explicit iptables rule (except of course the
+ * generic 'socket' rule). In this case the following sockets are
+ * matched in preference order:
+ *
+ * - match: if there's a fully established connection matching the
+ * _packet_ tuple
+ *
+ * - match: if there's a non-zero bound listener (possibly with a
+ * non-local address) We don't accept zero-bound listeners, since
+ * then local services could intercept traffic going through the
+ * box.
+ *
+ * Please note that there's an overlap between what a TPROXY target
+ * and a socket match will match. Normally if you have both rules the
+ * "socket" match will be the first one, effectively all packets
+ * belonging to established connections going through that one.
+ */
+static inline struct sock *
nf_tproxy_get_sock_v4(struct net *net, const u8 protocol,
const __be32 saddr, const __be32 daddr,
const __be16 sport, const __be16 dport,
- const struct net_device *in, bool listening);
+ const struct net_device *in, int lookup_type)
+{
+ struct sock *sk;
+
+ /* look up socket */
+ switch (protocol) {
+ case IPPROTO_TCP:
+ switch (lookup_type) {
+ case NFT_LOOKUP_ANY:
+ sk = __inet_lookup(net, &tcp_hashinfo,
+ saddr, sport, daddr, dport,
+ in->ifindex);
+ break;
+ case NFT_LOOKUP_LISTENER:
+ sk = inet_lookup_listener(net, &tcp_hashinfo,
+ daddr, dport,
+ in->ifindex);
+
+ /* NOTE: we return listeners even if bound to
+ * 0.0.0.0, those are filtered out in
+ * xt_socket, since xt_TPROXY needs 0 bound
+ * listeners too */
+
+ break;
+ case NFT_LOOKUP_ESTABLISHED:
+ sk = inet_lookup_established(net, &tcp_hashinfo,
+ saddr, sport, daddr, dport,
+ in->ifindex);
+ break;
+ default:
+ WARN_ON(1);
+ sk = NULL;
+ break;
+ }
+ break;
+ case IPPROTO_UDP:
+ sk = udp4_lib_lookup(net, saddr, sport, daddr, dport,
+ in->ifindex);
+ if (sk && lookup_type != NFT_LOOKUP_ANY) {
+ int connected = (sk->sk_state == TCP_ESTABLISHED);
+ int wildcard = (inet_sk(sk)->inet_rcv_saddr == 0);
+
+ /* NOTE: we return listeners even if bound to
+ * 0.0.0.0, those are filtered out in
+ * xt_socket, since xt_TPROXY needs 0 bound
+ * listeners too */
+ if ((lookup_type == NFT_LOOKUP_ESTABLISHED && (!connected || wildcard)) ||
+ (lookup_type == NFT_LOOKUP_LISTENER && connected)) {
+ sock_put(sk);
+ sk = NULL;
+ }
+ }
+ break;
+ default:
+ WARN_ON(1);
+ sk = NULL;
+ }
+
+ pr_debug("tproxy socket lookup: proto %u %08x:%u -> %08x:%u, lookup type: %d, sock %p\n",
+ protocol, ntohl(saddr), ntohs(sport), ntohl(daddr), ntohs(dport), lookup_type, sk);
+
+ return sk;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static inline struct sock *
+nf_tproxy_get_sock_v6(struct net *net, const u8 protocol,
+ const struct in6_addr *saddr, const struct in6_addr *daddr,
+ const __be16 sport, const __be16 dport,
+ const struct net_device *in, int lookup_type)
+{
+ struct sock *sk;
+
+ /* look up socket */
+ switch (protocol) {
+ case IPPROTO_TCP:
+ switch (lookup_type) {
+ case NFT_LOOKUP_ANY:
+ sk = inet6_lookup(net, &tcp_hashinfo,
+ saddr, sport, daddr, dport,
+ in->ifindex);
+ break;
+ case NFT_LOOKUP_LISTENER:
+ sk = inet6_lookup_listener(net, &tcp_hashinfo,
+ daddr, ntohs(dport),
+ in->ifindex);
+
+ /* NOTE: we return listeners even if bound to
+ * 0.0.0.0, those are filtered out in
+ * xt_socket, since xt_TPROXY needs 0 bound
+ * listeners too */
+
+ break;
+ case NFT_LOOKUP_ESTABLISHED:
+ sk = __inet6_lookup_established(net, &tcp_hashinfo,
+ saddr, sport, daddr, ntohs(dport),
+ in->ifindex);
+ break;
+ default:
+ WARN_ON(1);
+ sk = NULL;
+ break;
+ }
+ break;
+ case IPPROTO_UDP:
+ sk = udp6_lib_lookup(net, saddr, sport, daddr, dport,
+ in->ifindex);
+ if (sk && lookup_type != NFT_LOOKUP_ANY) {
+ int connected = (sk->sk_state == TCP_ESTABLISHED);
+ int wildcard = ipv6_addr_any(&inet6_sk(sk)->rcv_saddr);
+
+ /* NOTE: we return listeners even if bound to
+ * 0.0.0.0, those are filtered out in
+ * xt_socket, since xt_TPROXY needs 0 bound
+ * listeners too */
+ if ((lookup_type == NFT_LOOKUP_ESTABLISHED && (!connected || wildcard)) ||
+ (lookup_type == NFT_LOOKUP_LISTENER && connected)) {
+ sock_put(sk);
+ sk = NULL;
+ }
+ }
+ break;
+ default:
+ WARN_ON(1);
+ sk = NULL;
+ }
+
+ pr_debug("tproxy socket lookup: proto %u %pI6:%u -> %pI6:%u, lookup type: %d, sock %p\n",
+ protocol, saddr, ntohs(sport), daddr, ntohs(dport), lookup_type, sk);
+
+ return sk;
+}
+#endif
static inline void
nf_tproxy_put_sock(struct sock *sk)
diff --git a/include/net/netfilter/xt_log.h b/include/net/netfilter/xt_log.h
new file mode 100644
index 000000000000..0dfb34a5b53c
--- /dev/null
+++ b/include/net/netfilter/xt_log.h
@@ -0,0 +1,54 @@
+#define S_SIZE (1024 - (sizeof(unsigned int) + 1))
+
+struct sbuff {
+ unsigned int count;
+ char buf[S_SIZE + 1];
+};
+static struct sbuff emergency, *emergency_ptr = &emergency;
+
+static int sb_add(struct sbuff *m, const char *f, ...)
+{
+ va_list args;
+ int len;
+
+ if (likely(m->count < S_SIZE)) {
+ va_start(args, f);
+ len = vsnprintf(m->buf + m->count, S_SIZE - m->count, f, args);
+ va_end(args);
+ if (likely(m->count + len < S_SIZE)) {
+ m->count += len;
+ return 0;
+ }
+ }
+ m->count = S_SIZE;
+ printk_once(KERN_ERR KBUILD_MODNAME " please increase S_SIZE\n");
+ return -1;
+}
+
+static struct sbuff *sb_open(void)
+{
+ struct sbuff *m = kmalloc(sizeof(*m), GFP_ATOMIC);
+
+ if (unlikely(!m)) {
+ local_bh_disable();
+ do {
+ m = xchg(&emergency_ptr, NULL);
+ } while (!m);
+ }
+ m->count = 0;
+ return m;
+}
+
+static void sb_close(struct sbuff *m)
+{
+ m->buf[m->count] = 0;
+ printk("%s\n", m->buf);
+
+ if (likely(m != &emergency))
+ kfree(m);
+ else {
+ xchg(&emergency_ptr, m);
+ local_bh_enable();
+ }
+}
+
diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h
index 74f119a2829a..748f91f87cd5 100644
--- a/include/net/netns/xfrm.h
+++ b/include/net/netns/xfrm.h
@@ -43,10 +43,6 @@ struct netns_xfrm {
unsigned int policy_count[XFRM_POLICY_MAX * 2];
struct work_struct policy_hash_work;
- struct dst_ops xfrm4_dst_ops;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct dst_ops xfrm6_dst_ops;
-#endif
struct sock *nlsk;
struct sock *nlsk_stash;
@@ -58,6 +54,11 @@ struct netns_xfrm {
#ifdef CONFIG_SYSCTL
struct ctl_table_header *sysctl_hdr;
#endif
+
+ struct dst_ops xfrm4_dst_ops;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ struct dst_ops xfrm6_dst_ops;
+#endif
};
#endif
diff --git a/include/net/phonet/pep.h b/include/net/phonet/pep.h
index 35672b1cf44a..b60b28c99e87 100644
--- a/include/net/phonet/pep.h
+++ b/include/net/phonet/pep.h
@@ -45,6 +45,10 @@ struct pep_sock {
u8 tx_fc; /* TX flow control */
u8 init_enable; /* auto-enable at creation */
u8 aligned;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ u8 pipe_state;
+ struct sockaddr_pn remote_pep;
+#endif
};
static inline struct pep_sock *pep_sk(struct sock *sk)
@@ -77,6 +81,11 @@ static inline struct pnpipehdr *pnp_hdr(struct sk_buff *skb)
#define MAX_PNPIPE_HEADER (MAX_PHONET_HEADER + 4)
enum {
+ PNS_PIPE_CREATE_REQ = 0x00,
+ PNS_PIPE_CREATE_RESP,
+ PNS_PIPE_REMOVE_REQ,
+ PNS_PIPE_REMOVE_RESP,
+
PNS_PIPE_DATA = 0x20,
PNS_PIPE_ALIGNED_DATA,
@@ -160,4 +169,21 @@ enum {
PEP_IND_READY,
};
+#ifdef CONFIG_PHONET_PIPECTRLR
+#define PNS_PEP_CONNECT_UTID 0x02
+#define PNS_PIPE_CREATED_IND_UTID 0x04
+#define PNS_PIPE_ENABLE_UTID 0x0A
+#define PNS_PIPE_ENABLED_IND_UTID 0x0C
+#define PNS_PIPE_DISABLE_UTID 0x0F
+#define PNS_PIPE_DISABLED_IND_UTID 0x11
+#define PNS_PEP_DISCONNECT_UTID 0x06
+
+/* Used for tracking state of a pipe */
+enum {
+ PIPE_IDLE,
+ PIPE_DISABLED,
+ PIPE_ENABLED,
+};
+#endif /* CONFIG_PHONET_PIPECTRLR */
+
#endif
diff --git a/include/net/phonet/phonet.h b/include/net/phonet/phonet.h
index 7b114079a51b..d5df797f9540 100644
--- a/include/net/phonet/phonet.h
+++ b/include/net/phonet/phonet.h
@@ -54,6 +54,11 @@ void pn_sock_hash(struct sock *sk);
void pn_sock_unhash(struct sock *sk);
int pn_sock_get_port(struct sock *sk, unsigned short sport);
+struct sock *pn_find_sock_by_res(struct net *net, u8 res);
+int pn_sock_bind_res(struct sock *sock, u8 res);
+int pn_sock_unbind_res(struct sock *sk, u8 res);
+void pn_sock_unbind_all_res(struct sock *sk);
+
int pn_skb_send(struct sock *sk, struct sk_buff *skb,
const struct sockaddr_pn *target);
diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h
index 2d16783d5e20..13649eb57413 100644
--- a/include/net/phonet/pn_dev.h
+++ b/include/net/phonet/pn_dev.h
@@ -57,5 +57,6 @@ struct net_device *phonet_route_output(struct net *net, u8 daddr);
#define PN_NO_ADDR 0xff
extern const struct file_operations pn_sock_seq_fops;
+extern const struct file_operations pn_res_seq_fops;
#endif
diff --git a/include/net/protocol.h b/include/net/protocol.h
index f1effdd3c265..dc07495bce4c 100644
--- a/include/net/protocol.h
+++ b/include/net/protocol.h
@@ -89,10 +89,10 @@ struct inet_protosw {
#define INET_PROTOSW_PERMANENT 0x02 /* Permanent protocols are unremovable. */
#define INET_PROTOSW_ICSK 0x04 /* Is this an inet_connection_sock? */
-extern const struct net_protocol *inet_protos[MAX_INET_PROTOS];
+extern const struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS];
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-extern const struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
+extern const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS];
#endif
extern int inet_add_protocol(const struct net_protocol *prot, unsigned char num);
diff --git a/include/net/raw.h b/include/net/raw.h
index 43c57502659b..42ce6fe7a2d5 100644
--- a/include/net/raw.h
+++ b/include/net/raw.h
@@ -45,7 +45,10 @@ struct raw_iter_state {
struct raw_hashinfo *h;
};
-#define raw_seq_private(seq) ((struct raw_iter_state *)(seq)->private)
+static inline struct raw_iter_state *raw_seq_private(struct seq_file *seq)
+{
+ return seq->private;
+}
void *raw_seq_start(struct seq_file *seq, loff_t *pos);
void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos);
void raw_seq_stop(struct seq_file *seq, void *v);
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h
index af60fd050844..e013c68bfb00 100644
--- a/include/net/rtnetlink.h
+++ b/include/net/rtnetlink.h
@@ -79,7 +79,6 @@ struct rtnl_link_ops {
extern int __rtnl_link_register(struct rtnl_link_ops *ops);
extern void __rtnl_link_unregister(struct rtnl_link_ops *ops);
-extern void rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops);
extern int rtnl_link_register(struct rtnl_link_ops *ops);
extern void rtnl_link_unregister(struct rtnl_link_ops *ops);
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 3c8728aaab4e..ea1f8a83160d 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -328,8 +328,7 @@ extern void qdisc_destroy(struct Qdisc *qdisc);
extern void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n);
extern struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
struct Qdisc_ops *ops);
-extern struct Qdisc *qdisc_create_dflt(struct net_device *dev,
- struct netdev_queue *dev_queue,
+extern struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
struct Qdisc_ops *ops, u32 parentid);
extern void qdisc_calculate_pkt_len(struct sk_buff *skb,
struct qdisc_size_table *stab);
@@ -601,7 +600,7 @@ static inline u32 qdisc_l2t(struct qdisc_rate_table* rtab, unsigned int pktlen)
slot = 0;
slot >>= rtab->rate.cell_log;
if (slot > 255)
- return (rtab->data[255]*(slot >> 8) + rtab->data[slot & 0xFF]);
+ return rtab->data[255]*(slot >> 8) + rtab->data[slot & 0xFF];
return rtab->data[slot];
}
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 65946bc43d00..505845ddb0be 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -275,24 +275,35 @@ struct sctp_mib {
/* Print debugging messages. */
#if SCTP_DEBUG
extern int sctp_debug_flag;
-#define SCTP_DEBUG_PRINTK(whatever...) \
- ((void) (sctp_debug_flag && printk(KERN_DEBUG whatever)))
-#define SCTP_DEBUG_PRINTK_IPADDR(lead, trail, leadparm, saddr, otherparms...) \
- if (sctp_debug_flag) { \
- if (saddr->sa.sa_family == AF_INET6) { \
- printk(KERN_DEBUG \
- lead "%pI6" trail, \
- leadparm, \
- &saddr->v6.sin6_addr, \
- otherparms); \
- } else { \
- printk(KERN_DEBUG \
- lead "%pI4" trail, \
- leadparm, \
- &saddr->v4.sin_addr.s_addr, \
- otherparms); \
- } \
- }
+#define SCTP_DEBUG_PRINTK(fmt, args...) \
+do { \
+ if (sctp_debug_flag) \
+ printk(KERN_DEBUG pr_fmt(fmt), ##args); \
+} while (0)
+#define SCTP_DEBUG_PRINTK_CONT(fmt, args...) \
+do { \
+ if (sctp_debug_flag) \
+ pr_cont(fmt, ##args); \
+} while (0)
+#define SCTP_DEBUG_PRINTK_IPADDR(fmt_lead, fmt_trail, \
+ args_lead, saddr, args_trail...) \
+do { \
+ if (sctp_debug_flag) { \
+ if (saddr->sa.sa_family == AF_INET6) { \
+ printk(KERN_DEBUG \
+ pr_fmt(fmt_lead "%pI6" fmt_trail), \
+ args_lead, \
+ &saddr->v6.sin6_addr, \
+ args_trail); \
+ } else { \
+ printk(KERN_DEBUG \
+ pr_fmt(fmt_lead "%pI4" fmt_trail), \
+ args_lead, \
+ &saddr->v4.sin_addr.s_addr, \
+ args_trail); \
+ } \
+ } \
+} while (0)
#define SCTP_ENABLE_DEBUG { sctp_debug_flag = 1; }
#define SCTP_DISABLE_DEBUG { sctp_debug_flag = 0; }
@@ -306,6 +317,7 @@ extern int sctp_debug_flag;
#else /* SCTP_DEBUG */
#define SCTP_DEBUG_PRINTK(whatever...)
+#define SCTP_DEBUG_PRINTK_CONT(fmt, args...)
#define SCTP_DEBUG_PRINTK_IPADDR(whatever...)
#define SCTP_ENABLE_DEBUG
#define SCTP_DISABLE_DEBUG
@@ -393,7 +405,7 @@ static inline void sctp_v6_del_protocol(void) { return; }
/* Map an association to an assoc_id. */
static inline sctp_assoc_t sctp_assoc2id(const struct sctp_association *asoc)
{
- return (asoc?asoc->assoc_id:0);
+ return asoc ? asoc->assoc_id : 0;
}
/* Look up the association by its id. */
@@ -461,7 +473,7 @@ static inline void sctp_skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
/* Tests if the list has one and only one entry. */
static inline int sctp_list_single_entry(struct list_head *head)
{
- return ((head->next != head) && (head->next == head->prev));
+ return (head->next != head) && (head->next == head->prev);
}
/* Generate a random jitter in the range of -50% ~ +50% of input RTO. */
@@ -619,13 +631,13 @@ static inline int sctp_sanity_check(void)
/* This is the hash function for the SCTP port hash table. */
static inline int sctp_phashfn(__u16 lport)
{
- return (lport & (sctp_port_hashsize - 1));
+ return lport & (sctp_port_hashsize - 1);
}
/* This is the hash function for the endpoint hash table. */
static inline int sctp_ep_hashfn(__u16 lport)
{
- return (lport & (sctp_ep_hashsize - 1));
+ return lport & (sctp_ep_hashsize - 1);
}
/* This is the hash function for the association hash table. */
@@ -633,7 +645,7 @@ static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport)
{
int h = (lport << 16) + rport;
h ^= h>>8;
- return (h & (sctp_assoc_hashsize - 1));
+ return h & (sctp_assoc_hashsize - 1);
}
/* This is the hash function for the association hash table. This is
@@ -644,7 +656,7 @@ static inline int sctp_vtag_hashfn(__u16 lport, __u16 rport, __u32 vtag)
{
int h = (lport << 16) + rport;
h ^= vtag;
- return (h & (sctp_assoc_hashsize-1));
+ return h & (sctp_assoc_hashsize - 1);
}
#define sctp_for_each_hentry(epb, node, head) \
diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h
index 4088c89a9055..9352d12f02de 100644
--- a/include/net/sctp/sm.h
+++ b/include/net/sctp/sm.h
@@ -345,12 +345,12 @@ enum {
static inline int TSN_lt(__u32 s, __u32 t)
{
- return (((s) - (t)) & TSN_SIGN_BIT);
+ return ((s) - (t)) & TSN_SIGN_BIT;
}
static inline int TSN_lte(__u32 s, __u32 t)
{
- return (((s) == (t)) || (((s) - (t)) & TSN_SIGN_BIT));
+ return ((s) == (t)) || (((s) - (t)) & TSN_SIGN_BIT);
}
/* Compare two SSNs */
@@ -369,12 +369,12 @@ enum {
static inline int SSN_lt(__u16 s, __u16 t)
{
- return (((s) - (t)) & SSN_SIGN_BIT);
+ return ((s) - (t)) & SSN_SIGN_BIT;
}
static inline int SSN_lte(__u16 s, __u16 t)
{
- return (((s) == (t)) || (((s) - (t)) & SSN_SIGN_BIT));
+ return ((s) == (t)) || (((s) - (t)) & SSN_SIGN_BIT);
}
/*
@@ -388,7 +388,7 @@ enum {
static inline int ADDIP_SERIAL_gte(__u16 s, __u16 t)
{
- return (((s) == (t)) || (((t) - (s)) & ADDIP_SERIAL_SIGN_BIT));
+ return ((s) == (t)) || (((t) - (s)) & ADDIP_SERIAL_SIGN_BIT);
}
/* Check VTAG of the packet matches the sender's own tag. */
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index f9e7473613bd..69fef4fb79c0 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -847,7 +847,7 @@ void sctp_packet_free(struct sctp_packet *);
static inline int sctp_packet_empty(struct sctp_packet *packet)
{
- return (packet->size == packet->overhead);
+ return packet->size == packet->overhead;
}
/* This represents a remote transport address.
diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
index 4aabc5a96cf6..e7728bc14ccf 100644
--- a/include/net/sctp/tsnmap.h
+++ b/include/net/sctp/tsnmap.h
@@ -157,7 +157,7 @@ __u16 sctp_tsnmap_pending(struct sctp_tsnmap *map);
/* Is there a gap in the TSN map? */
static inline int sctp_tsnmap_has_gap(const struct sctp_tsnmap *map)
{
- return (map->cumulative_tsn_ack_point != map->max_tsn_seen);
+ return map->cumulative_tsn_ack_point != map->max_tsn_seen;
}
/* Mark a duplicate TSN. Note: limit the storage of duplicate TSN
diff --git a/include/net/sock.h b/include/net/sock.h
index adab9dc58183..c7a736228ca2 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -301,7 +301,7 @@ struct sock {
const struct cred *sk_peer_cred;
long sk_rcvtimeo;
long sk_sndtimeo;
- struct sk_filter *sk_filter;
+ struct sk_filter __rcu *sk_filter;
void *sk_protinfo;
struct timer_list sk_timer;
ktime_t sk_stamp;
@@ -1558,7 +1558,11 @@ static inline void sk_wake_async(struct sock *sk, int how, int band)
}
#define SOCK_MIN_SNDBUF 2048
-#define SOCK_MIN_RCVBUF 256
+/*
+ * Since sk_rmem_alloc sums skb->truesize, even a small frame might need
+ * sizeof(sk_buff) + MTU + padding, unless net driver perform copybreak
+ */
+#define SOCK_MIN_RCVBUF (2048 + sizeof(struct sk_buff))
static inline void sk_stream_moderate_sndbuf(struct sock *sk)
{
@@ -1670,17 +1674,13 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
/**
* sock_tx_timestamp - checks whether the outgoing packet is to be time stamped
- * @msg: outgoing packet
* @sk: socket sending this packet
- * @shtx: filled with instructions for time stamping
+ * @tx_flags: filled with instructions for time stamping
*
* Currently only depends on SOCK_TIMESTAMPING* flags. Returns error code if
* parameters are invalid.
*/
-extern int sock_tx_timestamp(struct msghdr *msg,
- struct sock *sk,
- union skb_shared_tx *shtx);
-
+extern int sock_tx_timestamp(struct sock *sk, __u8 *tx_flags);
/**
* sk_eat_skb - Release a skb if it is no longer needed
diff --git a/include/net/tc_act/tc_csum.h b/include/net/tc_act/tc_csum.h
new file mode 100644
index 000000000000..9e8710be7a04
--- /dev/null
+++ b/include/net/tc_act/tc_csum.h
@@ -0,0 +1,15 @@
+#ifndef __NET_TC_CSUM_H
+#define __NET_TC_CSUM_H
+
+#include <linux/types.h>
+#include <net/act_api.h>
+
+struct tcf_csum {
+ struct tcf_common common;
+
+ u32 update_flags;
+};
+#define to_tcf_csum(pc) \
+ container_of(pc,struct tcf_csum,common)
+
+#endif /* __NET_TC_CSUM_H */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 3e4b33e36602..4fee0424af7e 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -346,8 +346,6 @@ static inline void tcp_dec_quickack_mode(struct sock *sk,
}
}
-extern void tcp_enter_quickack_mode(struct sock *sk);
-
#define TCP_ECN_OK 1
#define TCP_ECN_QUEUE_CWR 2
#define TCP_ECN_DEMAND_CWR 4
@@ -803,6 +801,15 @@ static inline __u32 tcp_current_ssthresh(const struct sock *sk)
/* Use define here intentionally to get WARN_ON location shown at the caller */
#define tcp_verify_left_out(tp) WARN_ON(tcp_left_out(tp) > tp->packets_out)
+/*
+ * Convert RFC 3390 larger initial window into an equivalent number of packets.
+ * This is based on the numbers specified in RFC 5681, 3.1.
+ */
+static inline u32 rfc3390_bytes_to_packets(const u32 smss)
+{
+ return smss <= 1095 ? 4 : (smss > 2190 ? 2 : 3);
+}
+
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);
diff --git a/include/net/tipc/tipc.h b/include/net/tipc/tipc.h
index 15af6dca0b49..1e0645e1eed2 100644
--- a/include/net/tipc/tipc.h
+++ b/include/net/tipc/tipc.h
@@ -50,8 +50,6 @@
* TIPC operating mode routines
*/
-u32 tipc_get_addr(void);
-
#define TIPC_NOT_RUNNING 0
#define TIPC_NODE_MODE 1
#define TIPC_NET_MODE 2
@@ -62,8 +60,6 @@ int tipc_attach(unsigned int *userref, tipc_mode_event, void *usr_handle);
void tipc_detach(unsigned int userref);
-int tipc_get_mode(void);
-
/*
* TIPC port manipulation routines
*/
@@ -153,12 +149,6 @@ int tipc_disconnect(u32 portref);
int tipc_shutdown(u32 ref);
-int tipc_isconnected(u32 portref, int *isconnected);
-
-int tipc_peer(u32 portref, struct tipc_portid *peer);
-
-int tipc_ref_valid(u32 portref);
-
/*
* TIPC messaging routines
*/
@@ -170,38 +160,12 @@ int tipc_send(u32 portref,
unsigned int num_sect,
struct iovec const *msg_sect);
-int tipc_send_buf(u32 portref,
- struct sk_buff *buf,
- unsigned int dsz);
-
int tipc_send2name(u32 portref,
struct tipc_name const *name,
u32 domain,
unsigned int num_sect,
struct iovec const *msg_sect);
-int tipc_send_buf2name(u32 portref,
- struct tipc_name const *name,
- u32 domain,
- struct sk_buff *buf,
- unsigned int dsz);
-
-int tipc_forward2name(u32 portref,
- struct tipc_name const *name,
- u32 domain,
- unsigned int section_count,
- struct iovec const *msg_sect,
- struct tipc_portid const *origin,
- unsigned int importance);
-
-int tipc_forward_buf2name(u32 portref,
- struct tipc_name const *name,
- u32 domain,
- struct sk_buff *buf,
- unsigned int dsz,
- struct tipc_portid const *orig,
- unsigned int importance);
-
int tipc_send2port(u32 portref,
struct tipc_portid const *dest,
unsigned int num_sect,
@@ -212,46 +176,11 @@ int tipc_send_buf2port(u32 portref,
struct sk_buff *buf,
unsigned int dsz);
-int tipc_forward2port(u32 portref,
- struct tipc_portid const *dest,
- unsigned int num_sect,
- struct iovec const *msg_sect,
- struct tipc_portid const *origin,
- unsigned int importance);
-
-int tipc_forward_buf2port(u32 portref,
- struct tipc_portid const *dest,
- struct sk_buff *buf,
- unsigned int dsz,
- struct tipc_portid const *orig,
- unsigned int importance);
-
int tipc_multicast(u32 portref,
struct tipc_name_seq const *seq,
u32 domain, /* currently unused */
unsigned int section_count,
struct iovec const *msg);
-
-#if 0
-int tipc_multicast_buf(u32 portref,
- struct tipc_name_seq const *seq,
- u32 domain,
- void *buf,
- unsigned int size);
-#endif
-
-/*
- * TIPC subscription routines
- */
-
-int tipc_ispublished(struct tipc_name const *name);
-
-/*
- * Get number of available nodes within specified domain (excluding own node)
- */
-
-unsigned int tipc_available_nodes(const u32 domain);
-
#endif
#endif
diff --git a/include/net/tipc/tipc_msg.h b/include/net/tipc/tipc_msg.h
index 2e159a812f83..ffe50b4e7b93 100644
--- a/include/net/tipc/tipc_msg.h
+++ b/include/net/tipc/tipc_msg.h
@@ -107,7 +107,7 @@ static inline u32 msg_hdr_sz(struct tipc_msg *m)
static inline int msg_short(struct tipc_msg *m)
{
- return (msg_hdr_sz(m) == 24);
+ return msg_hdr_sz(m) == 24;
}
static inline u32 msg_size(struct tipc_msg *m)
@@ -117,7 +117,7 @@ static inline u32 msg_size(struct tipc_msg *m)
static inline u32 msg_data_sz(struct tipc_msg *m)
{
- return (msg_size(m) - msg_hdr_sz(m));
+ return msg_size(m) - msg_hdr_sz(m);
}
static inline unchar *msg_data(struct tipc_msg *m)
@@ -132,17 +132,17 @@ static inline u32 msg_type(struct tipc_msg *m)
static inline u32 msg_named(struct tipc_msg *m)
{
- return (msg_type(m) == TIPC_NAMED_MSG);
+ return msg_type(m) == TIPC_NAMED_MSG;
}
static inline u32 msg_mcast(struct tipc_msg *m)
{
- return (msg_type(m) == TIPC_MCAST_MSG);
+ return msg_type(m) == TIPC_MCAST_MSG;
}
static inline u32 msg_connected(struct tipc_msg *m)
{
- return (msg_type(m) == TIPC_CONN_MSG);
+ return msg_type(m) == TIPC_CONN_MSG;
}
static inline u32 msg_errcode(struct tipc_msg *m)
diff --git a/include/net/tipc/tipc_port.h b/include/net/tipc/tipc_port.h
index c54917cbfa48..1893aaf49426 100644
--- a/include/net/tipc/tipc_port.h
+++ b/include/net/tipc/tipc_port.h
@@ -88,8 +88,6 @@ void tipc_acknowledge(u32 port_ref,u32 ack);
struct tipc_port *tipc_get_port(const u32 ref);
-void *tipc_get_handle(const u32 ref);
-
/*
* The following routines require that the port be locked on entry
*/
diff --git a/include/net/udp.h b/include/net/udp.h
index a184d3496b13..200b82848c9a 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -183,6 +183,9 @@ extern int udp_lib_setsockopt(struct sock *sk, int level, int optname,
extern struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
__be32 daddr, __be16 dport,
int dif);
+extern struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be16 sport,
+ const struct in6_addr *daddr, __be16 dport,
+ int dif);
/*
* SNMP statistics for UDP and UDP-Lite
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 4f53532d4c2f..bcfb6b24b019 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1264,7 +1264,7 @@ struct xfrm_tunnel {
int (*handler)(struct sk_buff *skb);
int (*err_handler)(struct sk_buff *skb, u32 info);
- struct xfrm_tunnel *next;
+ struct xfrm_tunnel __rcu *next;
int priority;
};
@@ -1272,7 +1272,7 @@ struct xfrm6_tunnel {
int (*handler)(struct sk_buff *skb);
int (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt,
u8 type, u8 code, int offset, __be32 info);
- struct xfrm6_tunnel *next;
+ struct xfrm6_tunnel __rcu *next;
int priority;
};
@@ -1419,7 +1419,6 @@ extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family);
extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family);
extern __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr);
-extern void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr);
extern __be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr);
extern int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb);
extern int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb);
@@ -1466,8 +1465,6 @@ struct xfrm_state *xfrm_find_acq(struct net *net, struct xfrm_mark *mark,
xfrm_address_t *saddr, int create,
unsigned short family);
extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
-extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst,
- struct flowi *fl, int family, int strict);
#ifdef CONFIG_XFRM_MIGRATE
extern int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h
index fa0d52b8e622..b5fc9f39122b 100644
--- a/include/rdma/ib_addr.h
+++ b/include/rdma/ib_addr.h
@@ -39,7 +39,9 @@
#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <linux/socket.h>
+#include <linux/if_vlan.h>
#include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
struct rdma_addr_client {
atomic_t refcount;
@@ -63,6 +65,7 @@ struct rdma_dev_addr {
unsigned char broadcast[MAX_ADDR_LEN];
unsigned short dev_type;
int bound_dev_if;
+ enum rdma_transport_type transport;
};
/**
@@ -127,9 +130,51 @@ static inline int rdma_addr_gid_offset(struct rdma_dev_addr *dev_addr)
return dev_addr->dev_type == ARPHRD_INFINIBAND ? 4 : 0;
}
+static inline void iboe_mac_vlan_to_ll(union ib_gid *gid, u8 *mac, u16 vid)
+{
+ memset(gid->raw, 0, 16);
+ *((__be32 *) gid->raw) = cpu_to_be32(0xfe800000);
+ if (vid < 0x1000) {
+ gid->raw[12] = vid & 0xff;
+ gid->raw[11] = vid >> 8;
+ } else {
+ gid->raw[12] = 0xfe;
+ gid->raw[11] = 0xff;
+ }
+ memcpy(gid->raw + 13, mac + 3, 3);
+ memcpy(gid->raw + 8, mac, 3);
+ gid->raw[8] ^= 2;
+}
+
+static inline u16 rdma_vlan_dev_vlan_id(const struct net_device *dev)
+{
+ return dev->priv_flags & IFF_802_1Q_VLAN ?
+ vlan_dev_vlan_id(dev) : 0xffff;
+}
+
+static inline void iboe_addr_get_sgid(struct rdma_dev_addr *dev_addr,
+ union ib_gid *gid)
+{
+ struct net_device *dev;
+ u16 vid = 0xffff;
+
+ dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if);
+ if (dev) {
+ vid = rdma_vlan_dev_vlan_id(dev);
+ dev_put(dev);
+ }
+
+ iboe_mac_vlan_to_ll(gid, dev_addr->src_dev_addr, vid);
+}
+
static inline void rdma_addr_get_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid)
{
- memcpy(gid, dev_addr->src_dev_addr + rdma_addr_gid_offset(dev_addr), sizeof *gid);
+ if (dev_addr->transport == RDMA_TRANSPORT_IB &&
+ dev_addr->dev_type != ARPHRD_INFINIBAND)
+ iboe_addr_get_sgid(dev_addr, gid);
+ else
+ memcpy(gid, dev_addr->src_dev_addr +
+ rdma_addr_gid_offset(dev_addr), sizeof *gid);
}
static inline void rdma_addr_set_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid)
@@ -147,4 +192,91 @@ static inline void rdma_addr_set_dgid(struct rdma_dev_addr *dev_addr, union ib_g
memcpy(dev_addr->dst_dev_addr + rdma_addr_gid_offset(dev_addr), gid, sizeof *gid);
}
+static inline enum ib_mtu iboe_get_mtu(int mtu)
+{
+ /*
+ * reduce IB headers from effective IBoE MTU. 28 stands for
+ * atomic header which is the biggest possible header after BTH
+ */
+ mtu = mtu - IB_GRH_BYTES - IB_BTH_BYTES - 28;
+
+ if (mtu >= ib_mtu_enum_to_int(IB_MTU_4096))
+ return IB_MTU_4096;
+ else if (mtu >= ib_mtu_enum_to_int(IB_MTU_2048))
+ return IB_MTU_2048;
+ else if (mtu >= ib_mtu_enum_to_int(IB_MTU_1024))
+ return IB_MTU_1024;
+ else if (mtu >= ib_mtu_enum_to_int(IB_MTU_512))
+ return IB_MTU_512;
+ else if (mtu >= ib_mtu_enum_to_int(IB_MTU_256))
+ return IB_MTU_256;
+ else
+ return 0;
+}
+
+static inline int iboe_get_rate(struct net_device *dev)
+{
+ struct ethtool_cmd cmd;
+
+ if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings ||
+ dev->ethtool_ops->get_settings(dev, &cmd))
+ return IB_RATE_PORT_CURRENT;
+
+ if (cmd.speed >= 40000)
+ return IB_RATE_40_GBPS;
+ else if (cmd.speed >= 30000)
+ return IB_RATE_30_GBPS;
+ else if (cmd.speed >= 20000)
+ return IB_RATE_20_GBPS;
+ else if (cmd.speed >= 10000)
+ return IB_RATE_10_GBPS;
+ else
+ return IB_RATE_PORT_CURRENT;
+}
+
+static inline int rdma_link_local_addr(struct in6_addr *addr)
+{
+ if (addr->s6_addr32[0] == htonl(0xfe800000) &&
+ addr->s6_addr32[1] == 0)
+ return 1;
+
+ return 0;
+}
+
+static inline void rdma_get_ll_mac(struct in6_addr *addr, u8 *mac)
+{
+ memcpy(mac, &addr->s6_addr[8], 3);
+ memcpy(mac + 3, &addr->s6_addr[13], 3);
+ mac[0] ^= 2;
+}
+
+static inline int rdma_is_multicast_addr(struct in6_addr *addr)
+{
+ return addr->s6_addr[0] == 0xff;
+}
+
+static inline void rdma_get_mcast_mac(struct in6_addr *addr, u8 *mac)
+{
+ int i;
+
+ mac[0] = 0x33;
+ mac[1] = 0x33;
+ for (i = 2; i < 6; ++i)
+ mac[i] = addr->s6_addr[i + 10];
+}
+
+static inline u16 rdma_get_vlan_id(union ib_gid *dgid)
+{
+ u16 vid;
+
+ vid = dgid->raw[11] << 8 | dgid->raw[12];
+ return vid < 0x1000 ? vid : 0xffff;
+}
+
+static inline struct net_device *rdma_vlan_dev_real_dev(const struct net_device *dev)
+{
+ return dev->priv_flags & IFF_802_1Q_VLAN ?
+ vlan_dev_real_dev(dev) : 0;
+}
+
#endif /* IB_ADDR_H */
diff --git a/include/rdma/ib_pack.h b/include/rdma/ib_pack.h
index cbb50f4da3dd..b37fe3b10a9d 100644
--- a/include/rdma/ib_pack.h
+++ b/include/rdma/ib_pack.h
@@ -37,6 +37,8 @@
enum {
IB_LRH_BYTES = 8,
+ IB_ETH_BYTES = 14,
+ IB_VLAN_BYTES = 4,
IB_GRH_BYTES = 40,
IB_BTH_BYTES = 12,
IB_DETH_BYTES = 8
@@ -210,14 +212,32 @@ struct ib_unpacked_deth {
__be32 source_qpn;
};
+struct ib_unpacked_eth {
+ u8 dmac_h[4];
+ u8 dmac_l[2];
+ u8 smac_h[2];
+ u8 smac_l[4];
+ __be16 type;
+};
+
+struct ib_unpacked_vlan {
+ __be16 tag;
+ __be16 type;
+};
+
struct ib_ud_header {
+ int lrh_present;
struct ib_unpacked_lrh lrh;
- int grh_present;
- struct ib_unpacked_grh grh;
- struct ib_unpacked_bth bth;
+ int eth_present;
+ struct ib_unpacked_eth eth;
+ int vlan_present;
+ struct ib_unpacked_vlan vlan;
+ int grh_present;
+ struct ib_unpacked_grh grh;
+ struct ib_unpacked_bth bth;
struct ib_unpacked_deth deth;
- int immediate_present;
- __be32 immediate_data;
+ int immediate_present;
+ __be32 immediate_data;
};
void ib_pack(const struct ib_field *desc,
@@ -230,9 +250,12 @@ void ib_unpack(const struct ib_field *desc,
void *buf,
void *structure);
-void ib_ud_header_init(int payload_bytes,
- int grh_present,
- int immediate_present,
+void ib_ud_header_init(int payload_bytes,
+ int lrh_present,
+ int eth_present,
+ int vlan_present,
+ int grh_present,
+ int immediate_present,
struct ib_ud_header *header);
int ib_ud_header_pack(struct ib_ud_header *header,
diff --git a/include/rdma/ib_user_verbs.h b/include/rdma/ib_user_verbs.h
index a17f77106149..fe5b05177a2c 100644
--- a/include/rdma/ib_user_verbs.h
+++ b/include/rdma/ib_user_verbs.h
@@ -205,7 +205,8 @@ struct ib_uverbs_query_port_resp {
__u8 active_width;
__u8 active_speed;
__u8 phys_state;
- __u8 reserved[3];
+ __u8 link_layer;
+ __u8 reserved[2];
};
struct ib_uverbs_alloc_pd {
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 857b3b9cf120..e04c4888d1fd 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -75,6 +75,12 @@ enum rdma_transport_type {
enum rdma_transport_type
rdma_node_get_transport(enum rdma_node_type node_type) __attribute_const__;
+enum rdma_link_layer {
+ IB_LINK_LAYER_UNSPECIFIED,
+ IB_LINK_LAYER_INFINIBAND,
+ IB_LINK_LAYER_ETHERNET,
+};
+
enum ib_device_cap_flags {
IB_DEVICE_RESIZE_MAX_WR = 1,
IB_DEVICE_BAD_PKEY_CNTR = (1<<1),
@@ -1010,6 +1016,8 @@ struct ib_device {
int (*query_port)(struct ib_device *device,
u8 port_num,
struct ib_port_attr *port_attr);
+ enum rdma_link_layer (*get_link_layer)(struct ib_device *device,
+ u8 port_num);
int (*query_gid)(struct ib_device *device,
u8 port_num, int index,
union ib_gid *gid);
@@ -1222,6 +1230,9 @@ int ib_query_device(struct ib_device *device,
int ib_query_port(struct ib_device *device,
u8 port_num, struct ib_port_attr *port_attr);
+enum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device,
+ u8 port_num);
+
int ib_query_gid(struct ib_device *device,
u8 port_num, int index, union ib_gid *gid);
diff --git a/include/scsi/srp.h b/include/scsi/srp.h
index ad178fa78f66..1ae84db4c9fb 100644
--- a/include/scsi/srp.h
+++ b/include/scsi/srp.h
@@ -239,4 +239,42 @@ struct srp_rsp {
u8 data[0];
} __attribute__((packed));
+struct srp_cred_req {
+ u8 opcode;
+ u8 sol_not;
+ u8 reserved[2];
+ __be32 req_lim_delta;
+ u64 tag;
+};
+
+struct srp_cred_rsp {
+ u8 opcode;
+ u8 reserved[7];
+ u64 tag;
+};
+
+/*
+ * The SRP spec defines the fixed portion of the AER_REQ structure to be
+ * 36 bytes, so it needs to be packed to avoid having it padded to 40 bytes
+ * on 64-bit architectures.
+ */
+struct srp_aer_req {
+ u8 opcode;
+ u8 sol_not;
+ u8 reserved[2];
+ __be32 req_lim_delta;
+ u64 tag;
+ u32 reserved2;
+ __be64 lun;
+ __be32 sense_data_len;
+ u32 reserved3;
+ u8 sense_data[0];
+} __attribute__((packed));
+
+struct srp_aer_rsp {
+ u8 opcode;
+ u8 reserved[7];
+ u64 tag;
+};
+
#endif /* SCSI_SRP_H */
diff --git a/include/sound/core.h b/include/sound/core.h
index df26ebbfa9c6..1fa2407c966f 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -177,7 +177,7 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state);
#define snd_power_lock(card) do { (void)(card); } while (0)
#define snd_power_unlock(card) do { (void)(card); } while (0)
static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; }
-#define snd_power_get_state(card) SNDRV_CTL_POWER_D0
+#define snd_power_get_state(card) ({ (void)(card); SNDRV_CTL_POWER_D0; })
#define snd_power_change_state(card, state) do { (void)(card); } while (0)
#endif /* CONFIG_PM */
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 7dc97d12253c..4f865df42f0f 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -438,6 +438,8 @@
#define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */
#define CCCA_CURRADDR 0x18000008
+/* undefine CCR to avoid conflict with the definition for SH */
+#undef CCR
#define CCR 0x09 /* Cache control register */
#define CCR_CACHEINVALIDSIZE 0x07190009
#define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples cache for this channel */
diff --git a/include/sound/jack.h b/include/sound/jack.h
index d90b9fa32707..c140fc7cbd3f 100644
--- a/include/sound/jack.h
+++ b/include/sound/jack.h
@@ -47,6 +47,9 @@ enum snd_jack_types {
SND_JACK_BTN_0 = 0x4000,
SND_JACK_BTN_1 = 0x2000,
SND_JACK_BTN_2 = 0x1000,
+ SND_JACK_BTN_3 = 0x0800,
+ SND_JACK_BTN_4 = 0x0400,
+ SND_JACK_BTN_5 = 0x0200,
};
struct snd_jack {
@@ -55,7 +58,7 @@ struct snd_jack {
int type;
const char *id;
char name[100];
- unsigned int key[3]; /* Keep in sync with definitions above */
+ unsigned int key[6]; /* Keep in sync with definitions above */
void *private_data;
void (*private_free)(struct snd_jack *);
};
diff --git a/include/sound/max98088.h b/include/sound/max98088.h
new file mode 100644
index 000000000000..c3ba8239182d
--- /dev/null
+++ b/include/sound/max98088.h
@@ -0,0 +1,50 @@
+/*
+ * Platform data for MAX98088
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * 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 __SOUND_MAX98088_PDATA_H__
+#define __SOUND_MAX98088_PDATA_H__
+
+/* Equalizer filter response configuration */
+struct max98088_eq_cfg {
+ const char *name;
+ unsigned int rate;
+ u16 band1[5];
+ u16 band2[5];
+ u16 band3[5];
+ u16 band4[5];
+ u16 band5[5];
+};
+
+/* codec platform data */
+struct max98088_pdata {
+
+ /* Equalizers for DAI1 and DAI2 */
+ struct max98088_eq_cfg *eq_cfg;
+ unsigned int eq_cfgcnt;
+
+ /* Receiver output can be configured as power amplifier or LINE out */
+ /* Set receiver_mode to:
+ * 0 = amplifier output, or
+ * 1 = LINE level output
+ */
+ unsigned int receiver_mode:1;
+
+ /* Analog/digital microphone configuration:
+ * 0 = analog microphone input (normal setting)
+ * 1 = digital microphone input
+ */
+ unsigned int digmic_left_mode:1;
+ unsigned int digmic_right_mode:1;
+
+};
+
+#endif
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 85f1c6bf8566..dfd9b76b1853 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -278,6 +278,7 @@ struct snd_pcm_runtime {
snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */
snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */
+ unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */
snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */
/* -- HW params -- */
diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h
index 9d51d6f35893..fa60cbda90a4 100644
--- a/include/sound/sh_fsi.h
+++ b/include/sound/sh_fsi.h
@@ -114,7 +114,4 @@ struct sh_fsi_platform_info {
int (*set_rate)(int is_porta, int rate); /* for master mode */
};
-extern struct snd_soc_dai fsi_soc_dai[2];
-extern struct snd_soc_platform fsi_soc_platform;
-
#endif /* __SOUND_FSI_H */
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 377693a14385..e7b680248006 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -91,15 +91,17 @@ struct snd_pcm_substream;
SNDRV_PCM_FMTBIT_S32_LE |\
SNDRV_PCM_FMTBIT_S32_BE)
-struct snd_soc_dai_ops;
+struct snd_soc_dai_driver;
struct snd_soc_dai;
struct snd_ac97_bus_ops;
/* Digital Audio Interface registration */
-int snd_soc_register_dai(struct snd_soc_dai *dai);
-void snd_soc_unregister_dai(struct snd_soc_dai *dai);
-int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count);
-void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count);
+int snd_soc_register_dai(struct device *dev,
+ struct snd_soc_dai_driver *dai_drv);
+void snd_soc_unregister_dai(struct device *dev);
+int snd_soc_register_dais(struct device *dev,
+ struct snd_soc_dai_driver *dai_drv, size_t count);
+void snd_soc_unregister_dais(struct device *dev, size_t count);
/* Digital Audio Interface clocking API.*/
int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
@@ -126,16 +128,6 @@ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
/* Digital Audio Interface mute */
int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute);
-/*
- * Digital Audio Interface.
- *
- * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
- * operations and capabilities. Codec and platform drivers will register this
- * structure for every DAI they have.
- *
- * This structure covers the clocking, formating and ALSA operations for each
- * interface.
- */
struct snd_soc_dai_ops {
/*
* DAI clocking configuration, all optional.
@@ -191,24 +183,24 @@ struct snd_soc_dai_ops {
};
/*
- * Digital Audio Interface runtime data.
+ * Digital Audio Interface Driver.
*
- * Holds runtime data for a DAI.
+ * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
+ * operations and capabilities. Codec and platform drivers will register this
+ * structure for every DAI they have.
+ *
+ * This structure covers the clocking, formating and ALSA operations for each
+ * interface.
*/
-struct snd_soc_dai {
+struct snd_soc_dai_driver {
/* DAI description */
- char *name;
+ const char *name;
unsigned int id;
int ac97_control;
- struct device *dev;
- void *ac97_pdata; /* platform_data for the ac97 codec */
-
- /* DAI callbacks */
- int (*probe)(struct platform_device *pdev,
- struct snd_soc_dai *dai);
- void (*remove)(struct platform_device *pdev,
- struct snd_soc_dai *dai);
+ /* DAI driver callbacks */
+ int (*probe)(struct snd_soc_dai *dai);
+ int (*remove)(struct snd_soc_dai *dai);
int (*suspend)(struct snd_soc_dai *dai);
int (*resume)(struct snd_soc_dai *dai);
@@ -219,26 +211,51 @@ struct snd_soc_dai {
struct snd_soc_pcm_stream capture;
struct snd_soc_pcm_stream playback;
unsigned int symmetric_rates:1;
+};
+
+/*
+ * Digital Audio Interface runtime data.
+ *
+ * Holds runtime data for a DAI.
+ */
+struct snd_soc_dai {
+ const char *name;
+ int id;
+ struct device *dev;
+ void *ac97_pdata; /* platform_data for the ac97 codec */
+
+ /* driver ops */
+ struct snd_soc_dai_driver *driver;
/* DAI runtime info */
- struct snd_soc_codec *codec;
+ unsigned int capture_active:1; /* stream is in use */
+ unsigned int playback_active:1; /* stream is in use */
+ unsigned int symmetric_rates:1;
+ struct snd_pcm_runtime *runtime;
unsigned int active;
unsigned char pop_wait:1;
+ unsigned char probed:1;
- /* DAI private data */
- void *private_data;
+ /* DAI DMA data */
+ void *playback_dma_data;
+ void *capture_dma_data;
- /* parent platform */
- struct snd_soc_platform *platform;
+ /* parent platform/codec */
+ union {
+ struct snd_soc_platform *platform;
+ struct snd_soc_codec *codec;
+ };
+ struct snd_soc_card *card;
struct list_head list;
+ struct list_head card_list;
};
static inline void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai,
const struct snd_pcm_substream *ss)
{
return (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
- dai->playback.dma_data : dai->capture.dma_data;
+ dai->playback_dma_data : dai->capture_dma_data;
}
static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
@@ -246,9 +263,20 @@ static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
void *data)
{
if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dai->playback.dma_data = data;
+ dai->playback_dma_data = data;
else
- dai->capture.dma_data = data;
+ dai->capture_dma_data = data;
+}
+
+static inline void snd_soc_dai_set_drvdata(struct snd_soc_dai *dai,
+ void *data)
+{
+ dev_set_drvdata(dai->dev, data);
+}
+
+static inline void *snd_soc_dai_get_drvdata(struct snd_soc_dai *dai)
+{
+ return dev_get_drvdata(dai->dev);
}
#endif
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index c5d9987bc897..8fd3b41b763f 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -172,9 +172,19 @@
#define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
.reg = wreg, .shift = wshift, .invert = winvert }
+#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \
+ wevent, wflags) \
+{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
+ .reg = wreg, .shift = wshift, .invert = winvert, \
+ .event = wevent, .event_flags = wflags }
#define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
.reg = wreg, .shift = wshift, .invert = winvert }
+#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \
+ wevent, wflags) \
+{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
+ .reg = wreg, .shift = wshift, .invert = winvert, \
+ .event = wevent, .event_flags = wflags }
#define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
.shift = wshift, .invert = winvert}
@@ -322,14 +332,14 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
/* dapm path setup */
int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
-void snd_soc_dapm_free(struct snd_soc_device *socdev);
+void snd_soc_dapm_free(struct snd_soc_codec *codec);
int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
const struct snd_soc_dapm_route *route, int num);
/* dapm events */
-int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
- int event);
-void snd_soc_dapm_shutdown(struct snd_soc_device *socdev);
+int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
+ const char *stream, int event);
+void snd_soc_dapm_shutdown(struct snd_soc_card *card);
/* dapm sys fs - used by the core */
int snd_soc_dapm_sys_add(struct device *dev);
diff --git a/include/sound/soc-of-simple.h b/include/sound/soc-of-simple.h
deleted file mode 100644
index a064e1934a56..000000000000
--- a/include/sound/soc-of-simple.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * OF helpers for ALSA SoC
- *
- * Copyright (C) 2008, Secret Lab Technologies Ltd.
- */
-
-#ifndef _INCLUDE_SOC_OF_H_
-#define _INCLUDE_SOC_OF_H_
-
-#if defined(CONFIG_SND_SOC_OF_SIMPLE) || defined(CONFIG_SND_SOC_OF_SIMPLE_MODULE)
-
-#include <linux/of.h>
-#include <sound/soc.h>
-
-int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
- void *codec_data, struct snd_soc_dai *dai,
- struct device_node *node);
-
-int of_snd_soc_register_platform(struct snd_soc_platform *platform,
- struct device_node *node,
- struct snd_soc_dai *cpu_dai);
-
-#endif
-
-#endif /* _INCLUDE_SOC_OF_H_ */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 65e9d03ed4f5..5c3bce83f28a 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -214,10 +214,10 @@
* @OFF: Power Off. No restrictions on transition times.
*/
enum snd_soc_bias_level {
- SND_SOC_BIAS_ON,
- SND_SOC_BIAS_PREPARE,
- SND_SOC_BIAS_STANDBY,
SND_SOC_BIAS_OFF,
+ SND_SOC_BIAS_STANDBY,
+ SND_SOC_BIAS_PREPARE,
+ SND_SOC_BIAS_ON,
};
struct snd_jack;
@@ -228,13 +228,17 @@ struct snd_soc_ops;
struct snd_soc_dai_mode;
struct snd_soc_pcm_runtime;
struct snd_soc_dai;
+struct snd_soc_dai_driver;
struct snd_soc_platform;
struct snd_soc_dai_link;
+struct snd_soc_platform_driver;
struct snd_soc_codec;
+struct snd_soc_codec_driver;
struct soc_enum;
struct snd_soc_ac97_ops;
struct snd_soc_jack;
struct snd_soc_jack_pin;
+
#ifdef CONFIG_GPIOLIB
struct snd_soc_jack_gpio;
#endif
@@ -249,19 +253,18 @@ enum snd_soc_control_type {
SND_SOC_SPI,
};
-int snd_soc_register_platform(struct snd_soc_platform *platform);
-void snd_soc_unregister_platform(struct snd_soc_platform *platform);
-int snd_soc_register_codec(struct snd_soc_codec *codec);
-void snd_soc_unregister_codec(struct snd_soc_codec *codec);
+int snd_soc_register_platform(struct device *dev,
+ struct snd_soc_platform_driver *platform_drv);
+void snd_soc_unregister_platform(struct device *dev);
+int snd_soc_register_codec(struct device *dev,
+ struct snd_soc_codec_driver *codec_drv,
+ struct snd_soc_dai_driver *dai_drv, int num_dai);
+void snd_soc_unregister_codec(struct device *dev);
int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg);
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
int addr_bits, int data_bits,
enum snd_soc_control_type control);
-/* pcm <-> DAI connect */
-void snd_soc_free_pcms(struct snd_soc_device *socdev);
-int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
-
/* Utility functions to get clock rates from various things */
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
@@ -273,7 +276,7 @@ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
const struct snd_pcm_hardware *hw);
/* Jack reporting */
-int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
+int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
struct snd_soc_jack *jack);
void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
@@ -382,7 +385,7 @@ struct snd_soc_jack_gpio {
int invert;
int debounce_time;
struct snd_soc_jack *jack;
- struct work_struct work;
+ struct delayed_work work;
int (*jack_status_check)(void);
};
@@ -390,7 +393,7 @@ struct snd_soc_jack_gpio {
struct snd_soc_jack {
struct snd_jack *jack;
- struct snd_soc_card *card;
+ struct snd_soc_codec *codec;
struct list_head pins;
int status;
struct blocking_notifier_head notifier;
@@ -398,15 +401,13 @@ struct snd_soc_jack {
/* SoC PCM stream information */
struct snd_soc_pcm_stream {
- char *stream_name;
+ const char *stream_name;
u64 formats; /* SNDRV_PCM_FMTBIT_* */
unsigned int rates; /* SNDRV_PCM_RATE_* */
unsigned int rate_min; /* min rate */
unsigned int rate_max; /* max rate */
unsigned int channels_min; /* min channels */
unsigned int channels_max; /* max channels */
- unsigned int active; /* stream is in use */
- void *dma_data; /* used by platform code */
};
/* SoC audio ops */
@@ -419,44 +420,36 @@ struct snd_soc_ops {
int (*trigger)(struct snd_pcm_substream *, int);
};
-/* SoC Audio Codec */
+/* SoC Audio Codec device */
struct snd_soc_codec {
- char *name;
- struct module *owner;
- struct mutex mutex;
+ const char *name;
+ int id;
struct device *dev;
- struct snd_soc_device *socdev;
+ struct snd_soc_codec_driver *driver;
+ struct mutex mutex;
+ struct snd_soc_card *card;
struct list_head list;
-
- /* callbacks */
- int (*set_bias_level)(struct snd_soc_codec *,
- enum snd_soc_bias_level level);
+ struct list_head card_list;
+ int num_dai;
/* runtime */
- struct snd_card *card;
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
unsigned int active;
- unsigned int pcm_devs;
- void *drvdata;
+ unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
+ unsigned int cache_only:1; /* Suppress writes to hardware */
+ unsigned int cache_sync:1; /* Cache needs to be synced to hardware */
+ unsigned int suspended:1; /* Codec is in suspend PM state */
+ unsigned int probed:1; /* Codec has been probed */
+ unsigned int ac97_registered:1; /* Codec has been AC97 registered */
+ unsigned int ac97_created:1; /* Codec has been created by SoC */
+ unsigned int sysfs_registered:1; /* codec has been sysfs registered */
/* codec IO */
void *control_data; /* codec control (i2c/3wire) data */
- unsigned int (*read)(struct snd_soc_codec *, unsigned int);
- int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
- int (*display_register)(struct snd_soc_codec *, char *,
- size_t, unsigned int);
- int (*volatile_register)(unsigned int);
- int (*readable_register)(unsigned int);
hw_write_t hw_write;
unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
void *reg_cache;
- short reg_cache_size;
- short reg_cache_step;
-
- unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
- unsigned int cache_only:1; /* Suppress writes to hardware */
- unsigned int cache_sync:1; /* Cache needs to be synced to hardware */
/* dapm */
u32 pop_time;
@@ -466,10 +459,6 @@ struct snd_soc_codec {
enum snd_soc_bias_level suspend_bias_level;
struct delayed_work delayed_work;
- /* codec DAI's */
- struct snd_soc_dai *dai;
- unsigned int num_dai;
-
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_codec_root;
struct dentry *debugfs_reg;
@@ -478,23 +467,40 @@ struct snd_soc_codec {
#endif
};
-/* codec device */
-struct snd_soc_codec_device {
- int (*probe)(struct platform_device *pdev);
- int (*remove)(struct platform_device *pdev);
- int (*suspend)(struct platform_device *pdev, pm_message_t state);
- int (*resume)(struct platform_device *pdev);
+/* codec driver */
+struct snd_soc_codec_driver {
+
+ /* driver ops */
+ int (*probe)(struct snd_soc_codec *);
+ int (*remove)(struct snd_soc_codec *);
+ int (*suspend)(struct snd_soc_codec *,
+ pm_message_t state);
+ int (*resume)(struct snd_soc_codec *);
+
+ /* codec IO */
+ unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+ int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+ int (*display_register)(struct snd_soc_codec *, char *,
+ size_t, unsigned int);
+ int (*volatile_register)(unsigned int);
+ int (*readable_register)(unsigned int);
+ short reg_cache_size;
+ short reg_cache_step;
+ short reg_word_size;
+ const void *reg_cache_default;
+
+ /* codec bias level */
+ int (*set_bias_level)(struct snd_soc_codec *,
+ enum snd_soc_bias_level level);
};
/* SoC platform interface */
-struct snd_soc_platform {
- char *name;
- struct list_head list;
+struct snd_soc_platform_driver {
- int (*probe)(struct platform_device *pdev);
- int (*remove)(struct platform_device *pdev);
- int (*suspend)(struct snd_soc_dai_link *dai_link);
- int (*resume)(struct snd_soc_dai_link *dai_link);
+ int (*probe)(struct snd_soc_platform *);
+ int (*remove)(struct snd_soc_platform *);
+ int (*suspend)(struct snd_soc_dai *dai);
+ int (*resume)(struct snd_soc_dai *dai);
/* pcm creation and destruction */
int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
@@ -509,23 +515,31 @@ struct snd_soc_platform {
struct snd_soc_dai *);
/* platform stream ops */
- struct snd_pcm_ops *pcm_ops;
+ struct snd_pcm_ops *ops;
};
-/* SoC machine DAI configuration, glues a codec and cpu DAI together */
-struct snd_soc_dai_link {
- char *name; /* Codec name */
- char *stream_name; /* Stream name */
+struct snd_soc_platform {
+ const char *name;
+ int id;
+ struct device *dev;
+ struct snd_soc_platform_driver *driver;
- /* DAI */
- struct snd_soc_dai *codec_dai;
- struct snd_soc_dai *cpu_dai;
+ unsigned int suspended:1; /* platform is suspended */
+ unsigned int probed:1;
- /* machine stream operations */
- struct snd_soc_ops *ops;
+ struct snd_soc_card *card;
+ struct list_head list;
+ struct list_head card_list;
+};
- /* codec/machine specific init - e.g. add machine controls */
- int (*init)(struct snd_soc_codec *codec);
+struct snd_soc_dai_link {
+ /* config - must be set by machine driver */
+ const char *name; /* Codec name */
+ const char *stream_name; /* Stream name */
+ const char *codec_name; /* for multi-codec */
+ const char *platform_name; /* for multi-platform */
+ const char *cpu_dai_name;
+ const char *codec_dai_name;
/* Keep DAI active over suspend */
unsigned int ignore_suspend:1;
@@ -533,21 +547,24 @@ struct snd_soc_dai_link {
/* Symmetry requirements */
unsigned int symmetric_rates:1;
- /* Symmetry data - only valid if symmetry is being enforced */
- unsigned int rate;
+ /* codec/machine specific init - e.g. add machine controls */
+ int (*init)(struct snd_soc_pcm_runtime *rtd);
- /* DAI pcm */
- struct snd_pcm *pcm;
+ /* machine stream operations */
+ struct snd_soc_ops *ops;
};
/* SoC card */
struct snd_soc_card {
- char *name;
+ const char *name;
struct device *dev;
+ struct snd_card *snd_card;
+ struct module *owner;
struct list_head list;
+ struct mutex mutex;
- int instantiated;
+ bool instantiated;
int (*probe)(struct platform_device *pdev);
int (*remove)(struct platform_device *pdev);
@@ -568,28 +585,38 @@ struct snd_soc_card {
/* CPU <--> Codec DAI links */
struct snd_soc_dai_link *dai_link;
int num_links;
+ struct snd_soc_pcm_runtime *rtd;
+ int num_rtd;
- struct snd_soc_device *socdev;
-
- struct snd_soc_codec *codec;
-
- struct snd_soc_platform *platform;
- struct delayed_work delayed_work;
struct work_struct deferred_resume_work;
+
+ /* lists of probed devices belonging to this card */
+ struct list_head codec_dev_list;
+ struct list_head platform_dev_list;
+ struct list_head dai_dev_list;
};
-/* SoC Device - the audio subsystem */
-struct snd_soc_device {
- struct device *dev;
+/* SoC machine DAI configuration, glues a codec and cpu DAI together */
+struct snd_soc_pcm_runtime {
+ struct device dev;
struct snd_soc_card *card;
- struct snd_soc_codec_device *codec_dev;
- void *codec_data;
-};
+ struct snd_soc_dai_link *dai_link;
+
+ unsigned int complete:1;
+ unsigned int dev_registered:1;
+
+ /* Symmetry data - only valid if symmetry is being enforced */
+ unsigned int rate;
+ long pmdown_time;
-/* runtime channel data */
-struct snd_soc_pcm_runtime {
- struct snd_soc_dai_link *dai;
- struct snd_soc_device *socdev;
+ /* runtime devices */
+ struct snd_pcm *pcm;
+ struct snd_soc_codec *codec;
+ struct snd_soc_platform *platform;
+ struct snd_soc_dai *codec_dai;
+ struct snd_soc_dai *cpu_dai;
+
+ struct delayed_work delayed_work;
};
/* mixer control */
@@ -615,24 +642,48 @@ struct soc_enum {
static inline unsigned int snd_soc_read(struct snd_soc_codec *codec,
unsigned int reg)
{
- return codec->read(codec, reg);
+ return codec->driver->read(codec, reg);
}
static inline unsigned int snd_soc_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int val)
{
- return codec->write(codec, reg, val);
+ return codec->driver->write(codec, reg, val);
}
+/* device driver data */
+
static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,
- void *data)
+ void *data)
{
- codec->drvdata = data;
+ dev_set_drvdata(codec->dev, data);
}
static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec)
{
- return codec->drvdata;
+ return dev_get_drvdata(codec->dev);
+}
+
+static inline void snd_soc_platform_set_drvdata(struct snd_soc_platform *platform,
+ void *data)
+{
+ dev_set_drvdata(platform->dev, data);
+}
+
+static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platform)
+{
+ return dev_get_drvdata(platform->dev);
+}
+
+static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd,
+ void *data)
+{
+ dev_set_drvdata(&rtd->dev, data);
+}
+
+static inline void *snd_soc_pcm_get_drvdata(struct snd_soc_pcm_runtime *rtd)
+{
+ return dev_get_drvdata(&rtd->dev);
}
#include <sound/soc-dai.h>
diff --git a/include/sound/tlv.h b/include/sound/tlv.h
index 9fd5b19ccf5c..7067e2dfb0b9 100644
--- a/include/sound/tlv.h
+++ b/include/sound/tlv.h
@@ -38,9 +38,11 @@
#define SNDRV_CTL_TLVT_DB_MINMAX 4 /* dB scale with min/max */
#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5 /* dB scale with min/max with mute */
+#define TLV_DB_SCALE_MASK 0xffff
+#define TLV_DB_SCALE_MUTE 0x10000
#define TLV_DB_SCALE_ITEM(min, step, mute) \
SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int), \
- (min), ((step) & 0xffff) | ((mute) ? 0x10000 : 0)
+ (min), ((step) & TLV_DB_SCALE_MASK) | ((mute) ? TLV_DB_SCALE_MUTE : 0)
#define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) }
diff --git a/include/sound/tlv320aic3x.h b/include/sound/tlv320aic3x.h
index b1a5f34e5cfa..99e0308bf2c2 100644
--- a/include/sound/tlv320aic3x.h
+++ b/include/sound/tlv320aic3x.h
@@ -10,8 +10,49 @@
#ifndef __TLV320AIC3x_H__
#define __TLV320AIC3x_H__
+/* GPIO API */
+enum {
+ AIC3X_GPIO1_FUNC_DISABLED = 0,
+ AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC = 1,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX = 2,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2 = 3,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4 = 4,
+ AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8 = 5,
+ AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ = 6,
+ AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ = 7,
+ AIC3X_GPIO1_FUNC_INPUT = 8,
+ AIC3X_GPIO1_FUNC_OUTPUT = 9,
+ AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK = 10,
+ AIC3X_GPIO1_FUNC_AUDIO_WORDCLK = 11,
+ AIC3X_GPIO1_FUNC_BUTTON_IRQ = 12,
+ AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ = 13,
+ AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 14,
+ AIC3X_GPIO1_FUNC_ALL_IRQ = 16
+};
+
+enum {
+ AIC3X_GPIO2_FUNC_DISABLED = 0,
+ AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ = 2,
+ AIC3X_GPIO2_FUNC_INPUT = 3,
+ AIC3X_GPIO2_FUNC_OUTPUT = 4,
+ AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT = 5,
+ AIC3X_GPIO2_FUNC_AUDIO_BITCLK = 8,
+ AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
+ AIC3X_GPIO2_FUNC_ALL_IRQ = 10,
+ AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
+ AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
+ AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ = 13,
+ AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ = 14,
+ AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15
+};
+
+struct aic3x_setup_data {
+ unsigned int gpio_func[2];
+};
+
struct aic3x_pdata {
int gpio_reset; /* < 0 if not used */
+ struct aic3x_setup_data *setup;
};
-#endif \ No newline at end of file
+#endif
diff --git a/include/sound/wm8962.h b/include/sound/wm8962.h
new file mode 100644
index 000000000000..2b5306c503fb
--- /dev/null
+++ b/include/sound/wm8962.h
@@ -0,0 +1,32 @@
+/*
+ * wm8962.h -- WM8962 Soc Audio driver platform data
+ *
+ * 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 _WM8962_PDATA_H
+#define _WM8962_PDATA_H
+
+#define WM8962_MAX_GPIO 6
+
+/* Use to set GPIO default values to zero */
+#define WM8962_GPIO_SET 0x10000
+
+struct wm8962_pdata {
+ int gpio_base;
+ u32 gpio_init[WM8962_MAX_GPIO];
+
+ /* Setup for microphone detection, raw value to be written to
+ * R48(0x30) - only microphone related bits will be updated.
+ * Detection may be enabled here for use with signals brought
+ * out on the GPIOs. */
+ u32 mic_cfg;
+
+ bool irq_active_low;
+
+ bool spk_mono; /* Speaker outputs tied together as mono */
+};
+
+#endif
diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h
index 01e9e0076a92..289010d3270b 100644
--- a/include/trace/events/ext4.h
+++ b/include/trace/events/ext4.h
@@ -21,7 +21,8 @@ TRACE_EVENT(ext4_free_inode,
TP_ARGS(inode),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( umode_t, mode )
__field( uid_t, uid )
@@ -30,7 +31,8 @@ TRACE_EVENT(ext4_free_inode,
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
__entry->mode = inode->i_mode;
__entry->uid = inode->i_uid;
@@ -38,9 +40,10 @@ TRACE_EVENT(ext4_free_inode,
__entry->blocks = inode->i_blocks;
),
- TP_printk("dev %s ino %lu mode 0%o uid %u gid %u blocks %llu",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
- __entry->mode, __entry->uid, __entry->gid,
+ TP_printk("dev %d,%d ino %lu mode 0%o uid %u gid %u blocks %llu",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino, __entry->mode,
+ __entry->uid, __entry->gid,
(unsigned long long) __entry->blocks)
);
@@ -50,20 +53,22 @@ TRACE_EVENT(ext4_request_inode,
TP_ARGS(dir, mode),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, dir )
__field( umode_t, mode )
),
TP_fast_assign(
- __entry->dev = dir->i_sb->s_dev;
+ __entry->dev_major = MAJOR(dir->i_sb->s_dev);
+ __entry->dev_minor = MINOR(dir->i_sb->s_dev);
__entry->dir = dir->i_ino;
__entry->mode = mode;
),
- TP_printk("dev %s dir %lu mode 0%o",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->dir,
- __entry->mode)
+ TP_printk("dev %d,%d dir %lu mode 0%o",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->dir, __entry->mode)
);
TRACE_EVENT(ext4_allocate_inode,
@@ -72,21 +77,24 @@ TRACE_EVENT(ext4_allocate_inode,
TP_ARGS(inode, dir, mode),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( ino_t, dir )
__field( umode_t, mode )
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
__entry->dir = dir->i_ino;
__entry->mode = mode;
),
- TP_printk("dev %s ino %lu dir %lu mode 0%o",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
+ TP_printk("dev %d,%d ino %lu dir %lu mode 0%o",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino,
(unsigned long) __entry->dir, __entry->mode)
);
@@ -98,7 +106,8 @@ DECLARE_EVENT_CLASS(ext4__write_begin,
TP_ARGS(inode, pos, len, flags),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( loff_t, pos )
__field( unsigned int, len )
@@ -106,15 +115,17 @@ DECLARE_EVENT_CLASS(ext4__write_begin,
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
__entry->pos = pos;
__entry->len = len;
__entry->flags = flags;
),
- TP_printk("dev %s ino %lu pos %llu len %u flags %u",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
+ TP_printk("dev %d,%d ino %lu pos %llu len %u flags %u",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino,
__entry->pos, __entry->len, __entry->flags)
);
@@ -141,7 +152,8 @@ DECLARE_EVENT_CLASS(ext4__write_end,
TP_ARGS(inode, pos, len, copied),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( loff_t, pos )
__field( unsigned int, len )
@@ -149,16 +161,18 @@ DECLARE_EVENT_CLASS(ext4__write_end,
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
__entry->pos = pos;
__entry->len = len;
__entry->copied = copied;
),
- TP_printk("dev %s ino %lu pos %llu len %u copied %u",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
- __entry->pos, __entry->len, __entry->copied)
+ TP_printk("dev %d,%d ino %lu pos %llu len %u copied %u",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino, __entry->pos,
+ __entry->len, __entry->copied)
);
DEFINE_EVENT(ext4__write_end, ext4_ordered_write_end,
@@ -199,21 +213,23 @@ TRACE_EVENT(ext4_writepage,
TP_ARGS(inode, page),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( pgoff_t, index )
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
__entry->index = page->index;
),
- TP_printk("dev %s ino %lu page_index %lu",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
- __entry->index)
+ TP_printk("dev %d,%d ino %lu page_index %lu",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino, __entry->index)
);
TRACE_EVENT(ext4_da_writepages,
@@ -222,13 +238,13 @@ TRACE_EVENT(ext4_da_writepages,
TP_ARGS(inode, wbc),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( long, nr_to_write )
__field( long, pages_skipped )
__field( loff_t, range_start )
__field( loff_t, range_end )
- __field( char, nonblocking )
__field( char, for_kupdate )
__field( char, for_reclaim )
__field( char, range_cyclic )
@@ -236,24 +252,27 @@ TRACE_EVENT(ext4_da_writepages,
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
__entry->nr_to_write = wbc->nr_to_write;
__entry->pages_skipped = wbc->pages_skipped;
__entry->range_start = wbc->range_start;
__entry->range_end = wbc->range_end;
- __entry->nonblocking = wbc->nonblocking;
__entry->for_kupdate = wbc->for_kupdate;
__entry->for_reclaim = wbc->for_reclaim;
__entry->range_cyclic = wbc->range_cyclic;
__entry->writeback_index = inode->i_mapping->writeback_index;
),
- TP_printk("dev %s ino %lu nr_to_write %ld pages_skipped %ld range_start %llu range_end %llu nonblocking %d for_kupdate %d for_reclaim %d range_cyclic %d writeback_index %lu",
- jbd2_dev_to_name(__entry->dev),
+ TP_printk("dev %d,%d ino %lu nr_to_write %ld pages_skipped %ld "
+ "range_start %llu range_end %llu "
+ "for_kupdate %d for_reclaim %d "
+ "range_cyclic %d writeback_index %lu",
+ __entry->dev_major, __entry->dev_minor,
(unsigned long) __entry->ino, __entry->nr_to_write,
__entry->pages_skipped, __entry->range_start,
- __entry->range_end, __entry->nonblocking,
+ __entry->range_end,
__entry->for_kupdate, __entry->for_reclaim,
__entry->range_cyclic,
(unsigned long) __entry->writeback_index)
@@ -265,7 +284,8 @@ TRACE_EVENT(ext4_da_write_pages,
TP_ARGS(inode, mpd),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( __u64, b_blocknr )
__field( __u32, b_size )
@@ -276,7 +296,8 @@ TRACE_EVENT(ext4_da_write_pages,
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
__entry->b_blocknr = mpd->b_blocknr;
__entry->b_size = mpd->b_size;
@@ -286,8 +307,9 @@ TRACE_EVENT(ext4_da_write_pages,
__entry->pages_written = mpd->pages_written;
),
- TP_printk("dev %s ino %lu b_blocknr %llu b_size %u b_state 0x%04x first_page %lu io_done %d pages_written %d",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
+ TP_printk("dev %d,%d ino %lu b_blocknr %llu b_size %u b_state 0x%04x first_page %lu io_done %d pages_written %d",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino,
__entry->b_blocknr, __entry->b_size,
__entry->b_state, __entry->first_page,
__entry->io_done, __entry->pages_written)
@@ -300,7 +322,8 @@ TRACE_EVENT(ext4_da_writepages_result,
TP_ARGS(inode, wbc, ret, pages_written),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( int, ret )
__field( int, pages_written )
@@ -310,7 +333,8 @@ TRACE_EVENT(ext4_da_writepages_result,
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
__entry->ret = ret;
__entry->pages_written = pages_written;
@@ -319,8 +343,8 @@ TRACE_EVENT(ext4_da_writepages_result,
__entry->writeback_index = inode->i_mapping->writeback_index;
),
- TP_printk("dev %s ino %lu ret %d pages_written %d pages_skipped %ld more_io %d writeback_index %lu",
- jbd2_dev_to_name(__entry->dev),
+ TP_printk("dev %d,%d ino %lu ret %d pages_written %d pages_skipped %ld more_io %d writeback_index %lu",
+ __entry->dev_major, __entry->dev_minor,
(unsigned long) __entry->ino, __entry->ret,
__entry->pages_written, __entry->pages_skipped,
__entry->more_io,
@@ -334,20 +358,23 @@ TRACE_EVENT(ext4_discard_blocks,
TP_ARGS(sb, blk, count),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( __u64, blk )
__field( __u64, count )
),
TP_fast_assign(
- __entry->dev = sb->s_dev;
+ __entry->dev_major = MAJOR(sb->s_dev);
+ __entry->dev_minor = MINOR(sb->s_dev);
__entry->blk = blk;
__entry->count = count;
),
- TP_printk("dev %s blk %llu count %llu",
- jbd2_dev_to_name(__entry->dev), __entry->blk, __entry->count)
+ TP_printk("dev %d,%d blk %llu count %llu",
+ __entry->dev_major, __entry->dev_minor,
+ __entry->blk, __entry->count)
);
DECLARE_EVENT_CLASS(ext4__mb_new_pa,
@@ -357,7 +384,8 @@ DECLARE_EVENT_CLASS(ext4__mb_new_pa,
TP_ARGS(ac, pa),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( __u64, pa_pstart )
__field( __u32, pa_len )
@@ -366,16 +394,18 @@ DECLARE_EVENT_CLASS(ext4__mb_new_pa,
),
TP_fast_assign(
- __entry->dev = ac->ac_sb->s_dev;
+ __entry->dev_major = MAJOR(ac->ac_sb->s_dev);
+ __entry->dev_minor = MINOR(ac->ac_sb->s_dev);
__entry->ino = ac->ac_inode->i_ino;
__entry->pa_pstart = pa->pa_pstart;
__entry->pa_len = pa->pa_len;
__entry->pa_lstart = pa->pa_lstart;
),
- TP_printk("dev %s ino %lu pstart %llu len %u lstart %llu",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
- __entry->pa_pstart, __entry->pa_len, __entry->pa_lstart)
+ TP_printk("dev %d,%d ino %lu pstart %llu len %u lstart %llu",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino, __entry->pa_pstart,
+ __entry->pa_len, __entry->pa_lstart)
);
DEFINE_EVENT(ext4__mb_new_pa, ext4_mb_new_inode_pa,
@@ -396,14 +426,15 @@ DEFINE_EVENT(ext4__mb_new_pa, ext4_mb_new_group_pa,
TRACE_EVENT(ext4_mb_release_inode_pa,
TP_PROTO(struct super_block *sb,
- struct ext4_allocation_context *ac,
+ struct inode *inode,
struct ext4_prealloc_space *pa,
unsigned long long block, unsigned int count),
- TP_ARGS(sb, ac, pa, block, count),
+ TP_ARGS(sb, inode, pa, block, count),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( __u64, block )
__field( __u32, count )
@@ -411,43 +442,42 @@ TRACE_EVENT(ext4_mb_release_inode_pa,
),
TP_fast_assign(
- __entry->dev = sb->s_dev;
- __entry->ino = (ac && ac->ac_inode) ?
- ac->ac_inode->i_ino : 0;
+ __entry->dev_major = MAJOR(sb->s_dev);
+ __entry->dev_minor = MINOR(sb->s_dev);
+ __entry->ino = inode->i_ino;
__entry->block = block;
__entry->count = count;
),
- TP_printk("dev %s ino %lu block %llu count %u",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
- __entry->block, __entry->count)
+ TP_printk("dev %d,%d ino %lu block %llu count %u",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino, __entry->block, __entry->count)
);
TRACE_EVENT(ext4_mb_release_group_pa,
TP_PROTO(struct super_block *sb,
- struct ext4_allocation_context *ac,
struct ext4_prealloc_space *pa),
- TP_ARGS(sb, ac, pa),
+ TP_ARGS(sb, pa),
TP_STRUCT__entry(
- __field( dev_t, dev )
- __field( ino_t, ino )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( __u64, pa_pstart )
__field( __u32, pa_len )
),
TP_fast_assign(
- __entry->dev = sb->s_dev;
- __entry->ino = (ac && ac->ac_inode) ?
- ac->ac_inode->i_ino : 0;
+ __entry->dev_major = MAJOR(sb->s_dev);
+ __entry->dev_minor = MINOR(sb->s_dev);
__entry->pa_pstart = pa->pa_pstart;
__entry->pa_len = pa->pa_len;
),
- TP_printk("dev %s pstart %llu len %u",
- jbd2_dev_to_name(__entry->dev), __entry->pa_pstart, __entry->pa_len)
+ TP_printk("dev %d,%d pstart %llu len %u",
+ __entry->dev_major, __entry->dev_minor,
+ __entry->pa_pstart, __entry->pa_len)
);
TRACE_EVENT(ext4_discard_preallocations,
@@ -456,18 +486,21 @@ TRACE_EVENT(ext4_discard_preallocations,
TP_ARGS(inode),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
),
- TP_printk("dev %s ino %lu",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino)
+ TP_printk("dev %d,%d ino %lu",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino)
);
TRACE_EVENT(ext4_mb_discard_preallocations,
@@ -476,18 +509,20 @@ TRACE_EVENT(ext4_mb_discard_preallocations,
TP_ARGS(sb, needed),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( int, needed )
),
TP_fast_assign(
- __entry->dev = sb->s_dev;
+ __entry->dev_major = MAJOR(sb->s_dev);
+ __entry->dev_minor = MINOR(sb->s_dev);
__entry->needed = needed;
),
- TP_printk("dev %s needed %d",
- jbd2_dev_to_name(__entry->dev), __entry->needed)
+ TP_printk("dev %d,%d needed %d",
+ __entry->dev_major, __entry->dev_minor, __entry->needed)
);
TRACE_EVENT(ext4_request_blocks,
@@ -496,7 +531,8 @@ TRACE_EVENT(ext4_request_blocks,
TP_ARGS(ar),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( unsigned int, flags )
__field( unsigned int, len )
@@ -509,7 +545,8 @@ TRACE_EVENT(ext4_request_blocks,
),
TP_fast_assign(
- __entry->dev = ar->inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(ar->inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(ar->inode->i_sb->s_dev);
__entry->ino = ar->inode->i_ino;
__entry->flags = ar->flags;
__entry->len = ar->len;
@@ -521,8 +558,9 @@ TRACE_EVENT(ext4_request_blocks,
__entry->pright = ar->pright;
),
- TP_printk("dev %s ino %lu flags %u len %u lblk %llu goal %llu lleft %llu lright %llu pleft %llu pright %llu ",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
+ TP_printk("dev %d,%d ino %lu flags %u len %u lblk %llu goal %llu lleft %llu lright %llu pleft %llu pright %llu ",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino,
__entry->flags, __entry->len,
(unsigned long long) __entry->logical,
(unsigned long long) __entry->goal,
@@ -538,7 +576,8 @@ TRACE_EVENT(ext4_allocate_blocks,
TP_ARGS(ar, block),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( __u64, block )
__field( unsigned int, flags )
@@ -552,7 +591,8 @@ TRACE_EVENT(ext4_allocate_blocks,
),
TP_fast_assign(
- __entry->dev = ar->inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(ar->inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(ar->inode->i_sb->s_dev);
__entry->ino = ar->inode->i_ino;
__entry->block = block;
__entry->flags = ar->flags;
@@ -565,9 +605,10 @@ TRACE_EVENT(ext4_allocate_blocks,
__entry->pright = ar->pright;
),
- TP_printk("dev %s ino %lu flags %u len %u block %llu lblk %llu goal %llu lleft %llu lright %llu pleft %llu pright %llu ",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
- __entry->flags, __entry->len, __entry->block,
+ TP_printk("dev %d,%d ino %lu flags %u len %u block %llu lblk %llu goal %llu lleft %llu lright %llu pleft %llu pright %llu ",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino, __entry->flags,
+ __entry->len, __entry->block,
(unsigned long long) __entry->logical,
(unsigned long long) __entry->goal,
(unsigned long long) __entry->lleft,
@@ -583,7 +624,8 @@ TRACE_EVENT(ext4_free_blocks,
TP_ARGS(inode, block, count, flags),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( umode_t, mode )
__field( __u64, block )
@@ -592,7 +634,8 @@ TRACE_EVENT(ext4_free_blocks,
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
__entry->mode = inode->i_mode;
__entry->block = block;
@@ -600,8 +643,9 @@ TRACE_EVENT(ext4_free_blocks,
__entry->flags = flags;
),
- TP_printk("dev %s ino %lu mode 0%o block %llu count %lu flags %d",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
+ TP_printk("dev %d,%d ino %lu mode 0%o block %llu count %lu flags %d",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino,
__entry->mode, __entry->block, __entry->count,
__entry->flags)
);
@@ -612,7 +656,8 @@ TRACE_EVENT(ext4_sync_file,
TP_ARGS(file, datasync),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( ino_t, parent )
__field( int, datasync )
@@ -621,14 +666,16 @@ TRACE_EVENT(ext4_sync_file,
TP_fast_assign(
struct dentry *dentry = file->f_path.dentry;
- __entry->dev = dentry->d_inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(dentry->d_inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(dentry->d_inode->i_sb->s_dev);
__entry->ino = dentry->d_inode->i_ino;
__entry->datasync = datasync;
__entry->parent = dentry->d_parent->d_inode->i_ino;
),
- TP_printk("dev %s ino %ld parent %ld datasync %d ",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
+ TP_printk("dev %d,%d ino %ld parent %ld datasync %d ",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino,
(unsigned long) __entry->parent, __entry->datasync)
);
@@ -638,18 +685,20 @@ TRACE_EVENT(ext4_sync_fs,
TP_ARGS(sb, wait),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( int, wait )
),
TP_fast_assign(
- __entry->dev = sb->s_dev;
+ __entry->dev_major = MAJOR(sb->s_dev);
+ __entry->dev_minor = MINOR(sb->s_dev);
__entry->wait = wait;
),
- TP_printk("dev %s wait %d", jbd2_dev_to_name(__entry->dev),
- __entry->wait)
+ TP_printk("dev %d,%d wait %d", __entry->dev_major,
+ __entry->dev_minor, __entry->wait)
);
TRACE_EVENT(ext4_alloc_da_blocks,
@@ -658,21 +707,24 @@ TRACE_EVENT(ext4_alloc_da_blocks,
TP_ARGS(inode),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( unsigned int, data_blocks )
__field( unsigned int, meta_blocks )
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
__entry->data_blocks = EXT4_I(inode)->i_reserved_data_blocks;
__entry->meta_blocks = EXT4_I(inode)->i_reserved_meta_blocks;
),
- TP_printk("dev %s ino %lu data_blocks %u meta_blocks %u",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
+ TP_printk("dev %d,%d ino %lu data_blocks %u meta_blocks %u",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino,
__entry->data_blocks, __entry->meta_blocks)
);
@@ -682,7 +734,8 @@ TRACE_EVENT(ext4_mballoc_alloc,
TP_ARGS(ac),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( __u16, found )
__field( __u16, groups )
@@ -705,7 +758,8 @@ TRACE_EVENT(ext4_mballoc_alloc,
),
TP_fast_assign(
- __entry->dev = ac->ac_inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(ac->ac_inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(ac->ac_inode->i_sb->s_dev);
__entry->ino = ac->ac_inode->i_ino;
__entry->found = ac->ac_found;
__entry->flags = ac->ac_flags;
@@ -727,10 +781,11 @@ TRACE_EVENT(ext4_mballoc_alloc,
__entry->result_len = ac->ac_f_ex.fe_len;
),
- TP_printk("dev %s inode %lu orig %u/%d/%u@%u goal %u/%d/%u@%u "
+ TP_printk("dev %d,%d inode %lu orig %u/%d/%u@%u goal %u/%d/%u@%u "
"result %u/%d/%u@%u blks %u grps %u cr %u flags 0x%04x "
"tail %u broken %u",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino,
__entry->orig_group, __entry->orig_start,
__entry->orig_len, __entry->orig_logical,
__entry->goal_group, __entry->goal_start,
@@ -748,7 +803,8 @@ TRACE_EVENT(ext4_mballoc_prealloc,
TP_ARGS(ac),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( __u32, orig_logical )
__field( int, orig_start )
@@ -761,7 +817,8 @@ TRACE_EVENT(ext4_mballoc_prealloc,
),
TP_fast_assign(
- __entry->dev = ac->ac_inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(ac->ac_inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(ac->ac_inode->i_sb->s_dev);
__entry->ino = ac->ac_inode->i_ino;
__entry->orig_logical = ac->ac_o_ex.fe_logical;
__entry->orig_start = ac->ac_o_ex.fe_start;
@@ -773,8 +830,9 @@ TRACE_EVENT(ext4_mballoc_prealloc,
__entry->result_len = ac->ac_b_ex.fe_len;
),
- TP_printk("dev %s inode %lu orig %u/%d/%u@%u result %u/%d/%u@%u",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
+ TP_printk("dev %d,%d inode %lu orig %u/%d/%u@%u result %u/%d/%u@%u",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino,
__entry->orig_group, __entry->orig_start,
__entry->orig_len, __entry->orig_logical,
__entry->result_group, __entry->result_start,
@@ -782,46 +840,59 @@ TRACE_EVENT(ext4_mballoc_prealloc,
);
DECLARE_EVENT_CLASS(ext4__mballoc,
- TP_PROTO(struct ext4_allocation_context *ac),
+ TP_PROTO(struct super_block *sb,
+ struct inode *inode,
+ ext4_group_t group,
+ ext4_grpblk_t start,
+ ext4_grpblk_t len),
- TP_ARGS(ac),
+ TP_ARGS(sb, inode, group, start, len),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
- __field( __u32, result_logical )
__field( int, result_start )
__field( __u32, result_group )
__field( int, result_len )
),
TP_fast_assign(
- __entry->dev = ac->ac_inode->i_sb->s_dev;
- __entry->ino = ac->ac_inode->i_ino;
- __entry->result_logical = ac->ac_b_ex.fe_logical;
- __entry->result_start = ac->ac_b_ex.fe_start;
- __entry->result_group = ac->ac_b_ex.fe_group;
- __entry->result_len = ac->ac_b_ex.fe_len;
+ __entry->dev_major = MAJOR(sb->s_dev);
+ __entry->dev_minor = MINOR(sb->s_dev);
+ __entry->ino = inode ? inode->i_ino : 0;
+ __entry->result_start = start;
+ __entry->result_group = group;
+ __entry->result_len = len;
),
- TP_printk("dev %s inode %lu extent %u/%d/%u@%u ",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
+ TP_printk("dev %d,%d inode %lu extent %u/%d/%u ",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino,
__entry->result_group, __entry->result_start,
- __entry->result_len, __entry->result_logical)
+ __entry->result_len)
);
DEFINE_EVENT(ext4__mballoc, ext4_mballoc_discard,
- TP_PROTO(struct ext4_allocation_context *ac),
+ TP_PROTO(struct super_block *sb,
+ struct inode *inode,
+ ext4_group_t group,
+ ext4_grpblk_t start,
+ ext4_grpblk_t len),
- TP_ARGS(ac)
+ TP_ARGS(sb, inode, group, start, len)
);
DEFINE_EVENT(ext4__mballoc, ext4_mballoc_free,
- TP_PROTO(struct ext4_allocation_context *ac),
+ TP_PROTO(struct super_block *sb,
+ struct inode *inode,
+ ext4_group_t group,
+ ext4_grpblk_t start,
+ ext4_grpblk_t len),
- TP_ARGS(ac)
+ TP_ARGS(sb, inode, group, start, len)
);
TRACE_EVENT(ext4_forget,
@@ -830,7 +901,8 @@ TRACE_EVENT(ext4_forget,
TP_ARGS(inode, is_metadata, block),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( umode_t, mode )
__field( int, is_metadata )
@@ -838,16 +910,18 @@ TRACE_EVENT(ext4_forget,
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
__entry->mode = inode->i_mode;
__entry->is_metadata = is_metadata;
__entry->block = block;
),
- TP_printk("dev %s ino %lu mode 0%o is_metadata %d block %llu",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
- __entry->mode, __entry->is_metadata, __entry->block)
+ TP_printk("dev %d,%d ino %lu mode 0%o is_metadata %d block %llu",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino, __entry->mode,
+ __entry->is_metadata, __entry->block)
);
TRACE_EVENT(ext4_da_update_reserve_space,
@@ -856,7 +930,8 @@ TRACE_EVENT(ext4_da_update_reserve_space,
TP_ARGS(inode, used_blocks),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( umode_t, mode )
__field( __u64, i_blocks )
@@ -867,7 +942,8 @@ TRACE_EVENT(ext4_da_update_reserve_space,
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
__entry->mode = inode->i_mode;
__entry->i_blocks = inode->i_blocks;
@@ -877,9 +953,10 @@ TRACE_EVENT(ext4_da_update_reserve_space,
__entry->allocated_meta_blocks = EXT4_I(inode)->i_allocated_meta_blocks;
),
- TP_printk("dev %s ino %lu mode 0%o i_blocks %llu used_blocks %d reserved_data_blocks %d reserved_meta_blocks %d allocated_meta_blocks %d",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
- __entry->mode, (unsigned long long) __entry->i_blocks,
+ TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu used_blocks %d reserved_data_blocks %d reserved_meta_blocks %d allocated_meta_blocks %d",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino, __entry->mode,
+ (unsigned long long) __entry->i_blocks,
__entry->used_blocks, __entry->reserved_data_blocks,
__entry->reserved_meta_blocks, __entry->allocated_meta_blocks)
);
@@ -890,7 +967,8 @@ TRACE_EVENT(ext4_da_reserve_space,
TP_ARGS(inode, md_needed),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( umode_t, mode )
__field( __u64, i_blocks )
@@ -900,7 +978,8 @@ TRACE_EVENT(ext4_da_reserve_space,
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
__entry->mode = inode->i_mode;
__entry->i_blocks = inode->i_blocks;
@@ -909,8 +988,9 @@ TRACE_EVENT(ext4_da_reserve_space,
__entry->reserved_meta_blocks = EXT4_I(inode)->i_reserved_meta_blocks;
),
- TP_printk("dev %s ino %lu mode 0%o i_blocks %llu md_needed %d reserved_data_blocks %d reserved_meta_blocks %d",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
+ TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu md_needed %d reserved_data_blocks %d reserved_meta_blocks %d",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino,
__entry->mode, (unsigned long long) __entry->i_blocks,
__entry->md_needed, __entry->reserved_data_blocks,
__entry->reserved_meta_blocks)
@@ -922,7 +1002,8 @@ TRACE_EVENT(ext4_da_release_space,
TP_ARGS(inode, freed_blocks),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
__field( umode_t, mode )
__field( __u64, i_blocks )
@@ -933,7 +1014,8 @@ TRACE_EVENT(ext4_da_release_space,
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
__entry->mode = inode->i_mode;
__entry->i_blocks = inode->i_blocks;
@@ -943,8 +1025,9 @@ TRACE_EVENT(ext4_da_release_space,
__entry->allocated_meta_blocks = EXT4_I(inode)->i_allocated_meta_blocks;
),
- TP_printk("dev %s ino %lu mode 0%o i_blocks %llu freed_blocks %d reserved_data_blocks %d reserved_meta_blocks %d allocated_meta_blocks %d",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino,
+ TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu freed_blocks %d reserved_data_blocks %d reserved_meta_blocks %d allocated_meta_blocks %d",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino,
__entry->mode, (unsigned long long) __entry->i_blocks,
__entry->freed_blocks, __entry->reserved_data_blocks,
__entry->reserved_meta_blocks, __entry->allocated_meta_blocks)
@@ -956,18 +1039,20 @@ DECLARE_EVENT_CLASS(ext4__bitmap_load,
TP_ARGS(sb, group),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( __u32, group )
),
TP_fast_assign(
- __entry->dev = sb->s_dev;
+ __entry->dev_major = MAJOR(sb->s_dev);
+ __entry->dev_minor = MINOR(sb->s_dev);
__entry->group = group;
),
- TP_printk("dev %s group %u",
- jbd2_dev_to_name(__entry->dev), __entry->group)
+ TP_printk("dev %d,%d group %u",
+ __entry->dev_major, __entry->dev_minor, __entry->group)
);
DEFINE_EVENT(ext4__bitmap_load, ext4_mb_bitmap_load,
diff --git a/include/trace/events/irq.h b/include/trace/events/irq.h
index 6fa7cbab7d93..1c09820df585 100644
--- a/include/trace/events/irq.h
+++ b/include/trace/events/irq.h
@@ -86,76 +86,62 @@ TRACE_EVENT(irq_handler_exit,
DECLARE_EVENT_CLASS(softirq,
- TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
+ TP_PROTO(unsigned int vec_nr),
- TP_ARGS(h, vec),
+ TP_ARGS(vec_nr),
TP_STRUCT__entry(
- __field( int, vec )
+ __field( unsigned int, vec )
),
TP_fast_assign(
- if (vec)
- __entry->vec = (int)(h - vec);
- else
- __entry->vec = (int)(long)h;
+ __entry->vec = vec_nr;
),
- TP_printk("vec=%d [action=%s]", __entry->vec,
+ TP_printk("vec=%u [action=%s]", __entry->vec,
show_softirq_name(__entry->vec))
);
/**
* softirq_entry - called immediately before the softirq handler
- * @h: pointer to struct softirq_action
- * @vec: pointer to first struct softirq_action in softirq_vec array
+ * @vec_nr: softirq vector number
*
- * The @h parameter, contains a pointer to the struct softirq_action
- * which has a pointer to the action handler that is called. By subtracting
- * the @vec pointer from the @h pointer, we can determine the softirq
- * number. Also, when used in combination with the softirq_exit tracepoint
- * we can determine the softirq latency.
+ * When used in combination with the softirq_exit tracepoint
+ * we can determine the softirq handler runtine.
*/
DEFINE_EVENT(softirq, softirq_entry,
- TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
+ TP_PROTO(unsigned int vec_nr),
- TP_ARGS(h, vec)
+ TP_ARGS(vec_nr)
);
/**
* softirq_exit - called immediately after the softirq handler returns
- * @h: pointer to struct softirq_action
- * @vec: pointer to first struct softirq_action in softirq_vec array
+ * @vec_nr: softirq vector number
*
- * The @h parameter contains a pointer to the struct softirq_action
- * that has handled the softirq. By subtracting the @vec pointer from
- * the @h pointer, we can determine the softirq number. Also, when used in
- * combination with the softirq_entry tracepoint we can determine the softirq
- * latency.
+ * When used in combination with the softirq_entry tracepoint
+ * we can determine the softirq handler runtine.
*/
DEFINE_EVENT(softirq, softirq_exit,
- TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
+ TP_PROTO(unsigned int vec_nr),
- TP_ARGS(h, vec)
+ TP_ARGS(vec_nr)
);
/**
* softirq_raise - called immediately when a softirq is raised
- * @h: pointer to struct softirq_action
- * @vec: pointer to first struct softirq_action in softirq_vec array
+ * @vec_nr: softirq vector number
*
- * The @h parameter contains a pointer to the softirq vector number which is
- * raised. @vec is NULL and it means @h includes vector number not
- * softirq_action. When used in combination with the softirq_entry tracepoint
- * we can determine the softirq raise latency.
+ * When used in combination with the softirq_entry tracepoint
+ * we can determine the softirq raise to run latency.
*/
DEFINE_EVENT(softirq, softirq_raise,
- TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
+ TP_PROTO(unsigned int vec_nr),
- TP_ARGS(h, vec)
+ TP_ARGS(vec_nr)
);
#endif /* _TRACE_IRQ_H */
diff --git a/include/trace/events/jbd2.h b/include/trace/events/jbd2.h
index bf16545cc977..7447ea9305b5 100644
--- a/include/trace/events/jbd2.h
+++ b/include/trace/events/jbd2.h
@@ -17,17 +17,19 @@ TRACE_EVENT(jbd2_checkpoint,
TP_ARGS(journal, result),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( int, result )
),
TP_fast_assign(
- __entry->dev = journal->j_fs_dev->bd_dev;
+ __entry->dev_major = MAJOR(journal->j_fs_dev->bd_dev);
+ __entry->dev_minor = MINOR(journal->j_fs_dev->bd_dev);
__entry->result = result;
),
- TP_printk("dev %s result %d",
- jbd2_dev_to_name(__entry->dev), __entry->result)
+ TP_printk("dev %d,%d result %d",
+ __entry->dev_major, __entry->dev_minor, __entry->result)
);
DECLARE_EVENT_CLASS(jbd2_commit,
@@ -37,20 +39,22 @@ DECLARE_EVENT_CLASS(jbd2_commit,
TP_ARGS(journal, commit_transaction),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( char, sync_commit )
__field( int, transaction )
),
TP_fast_assign(
- __entry->dev = journal->j_fs_dev->bd_dev;
+ __entry->dev_major = MAJOR(journal->j_fs_dev->bd_dev);
+ __entry->dev_minor = MINOR(journal->j_fs_dev->bd_dev);
__entry->sync_commit = commit_transaction->t_synchronous_commit;
__entry->transaction = commit_transaction->t_tid;
),
- TP_printk("dev %s transaction %d sync %d",
- jbd2_dev_to_name(__entry->dev), __entry->transaction,
- __entry->sync_commit)
+ TP_printk("dev %d,%d transaction %d sync %d",
+ __entry->dev_major, __entry->dev_minor,
+ __entry->transaction, __entry->sync_commit)
);
DEFINE_EVENT(jbd2_commit, jbd2_start_commit,
@@ -87,22 +91,24 @@ TRACE_EVENT(jbd2_end_commit,
TP_ARGS(journal, commit_transaction),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( char, sync_commit )
__field( int, transaction )
__field( int, head )
),
TP_fast_assign(
- __entry->dev = journal->j_fs_dev->bd_dev;
+ __entry->dev_major = MAJOR(journal->j_fs_dev->bd_dev);
+ __entry->dev_minor = MINOR(journal->j_fs_dev->bd_dev);
__entry->sync_commit = commit_transaction->t_synchronous_commit;
__entry->transaction = commit_transaction->t_tid;
__entry->head = journal->j_tail_sequence;
),
- TP_printk("dev %s transaction %d sync %d head %d",
- jbd2_dev_to_name(__entry->dev), __entry->transaction,
- __entry->sync_commit, __entry->head)
+ TP_printk("dev %d,%d transaction %d sync %d head %d",
+ __entry->dev_major, __entry->dev_minor,
+ __entry->transaction, __entry->sync_commit, __entry->head)
);
TRACE_EVENT(jbd2_submit_inode_data,
@@ -111,17 +117,20 @@ TRACE_EVENT(jbd2_submit_inode_data,
TP_ARGS(inode),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( ino_t, ino )
),
TP_fast_assign(
- __entry->dev = inode->i_sb->s_dev;
+ __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+ __entry->dev_minor = MINOR(inode->i_sb->s_dev);
__entry->ino = inode->i_ino;
),
- TP_printk("dev %s ino %lu",
- jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino)
+ TP_printk("dev %d,%d ino %lu",
+ __entry->dev_major, __entry->dev_minor,
+ (unsigned long) __entry->ino)
);
TRACE_EVENT(jbd2_run_stats,
@@ -131,7 +140,8 @@ TRACE_EVENT(jbd2_run_stats,
TP_ARGS(dev, tid, stats),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( unsigned long, tid )
__field( unsigned long, wait )
__field( unsigned long, running )
@@ -144,7 +154,8 @@ TRACE_EVENT(jbd2_run_stats,
),
TP_fast_assign(
- __entry->dev = dev;
+ __entry->dev_major = MAJOR(dev);
+ __entry->dev_minor = MINOR(dev);
__entry->tid = tid;
__entry->wait = stats->rs_wait;
__entry->running = stats->rs_running;
@@ -156,9 +167,9 @@ TRACE_EVENT(jbd2_run_stats,
__entry->blocks_logged = stats->rs_blocks_logged;
),
- TP_printk("dev %s tid %lu wait %u running %u locked %u flushing %u "
+ TP_printk("dev %d,%d tid %lu wait %u running %u locked %u flushing %u "
"logging %u handle_count %u blocks %u blocks_logged %u",
- jbd2_dev_to_name(__entry->dev), __entry->tid,
+ __entry->dev_major, __entry->dev_minor, __entry->tid,
jiffies_to_msecs(__entry->wait),
jiffies_to_msecs(__entry->running),
jiffies_to_msecs(__entry->locked),
@@ -175,7 +186,8 @@ TRACE_EVENT(jbd2_checkpoint_stats,
TP_ARGS(dev, tid, stats),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( unsigned long, tid )
__field( unsigned long, chp_time )
__field( __u32, forced_to_close )
@@ -184,7 +196,8 @@ TRACE_EVENT(jbd2_checkpoint_stats,
),
TP_fast_assign(
- __entry->dev = dev;
+ __entry->dev_major = MAJOR(dev);
+ __entry->dev_minor = MINOR(dev);
__entry->tid = tid;
__entry->chp_time = stats->cs_chp_time;
__entry->forced_to_close= stats->cs_forced_to_close;
@@ -192,9 +205,9 @@ TRACE_EVENT(jbd2_checkpoint_stats,
__entry->dropped = stats->cs_dropped;
),
- TP_printk("dev %s tid %lu chp_time %u forced_to_close %u "
+ TP_printk("dev %d,%d tid %lu chp_time %u forced_to_close %u "
"written %u dropped %u",
- jbd2_dev_to_name(__entry->dev), __entry->tid,
+ __entry->dev_major, __entry->dev_minor, __entry->tid,
jiffies_to_msecs(__entry->chp_time),
__entry->forced_to_close, __entry->written, __entry->dropped)
);
@@ -207,7 +220,8 @@ TRACE_EVENT(jbd2_cleanup_journal_tail,
TP_ARGS(journal, first_tid, block_nr, freed),
TP_STRUCT__entry(
- __field( dev_t, dev )
+ __field( int, dev_major )
+ __field( int, dev_minor )
__field( tid_t, tail_sequence )
__field( tid_t, first_tid )
__field(unsigned long, block_nr )
@@ -215,16 +229,18 @@ TRACE_EVENT(jbd2_cleanup_journal_tail,
),
TP_fast_assign(
- __entry->dev = journal->j_fs_dev->bd_dev;
+ __entry->dev_major = MAJOR(journal->j_fs_dev->bd_dev);
+ __entry->dev_minor = MINOR(journal->j_fs_dev->bd_dev);
__entry->tail_sequence = journal->j_tail_sequence;
__entry->first_tid = first_tid;
__entry->block_nr = block_nr;
__entry->freed = freed;
),
- TP_printk("dev %s from %u to %u offset %lu freed %lu",
- jbd2_dev_to_name(__entry->dev), __entry->tail_sequence,
- __entry->first_tid, __entry->block_nr, __entry->freed)
+ TP_printk("dev %d,%d from %u to %u offset %lu freed %lu",
+ __entry->dev_major, __entry->dev_minor,
+ __entry->tail_sequence, __entry->first_tid,
+ __entry->block_nr, __entry->freed)
);
#endif /* _TRACE_JBD2_H */
diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h
index 370aa5a87322..c255fcc587bf 100644
--- a/include/trace/events/vmscan.h
+++ b/include/trace/events/vmscan.h
@@ -10,6 +10,7 @@
#define RECLAIM_WB_ANON 0x0001u
#define RECLAIM_WB_FILE 0x0002u
+#define RECLAIM_WB_MIXED 0x0010u
#define RECLAIM_WB_SYNC 0x0004u
#define RECLAIM_WB_ASYNC 0x0008u
@@ -17,13 +18,20 @@
(flags) ? __print_flags(flags, "|", \
{RECLAIM_WB_ANON, "RECLAIM_WB_ANON"}, \
{RECLAIM_WB_FILE, "RECLAIM_WB_FILE"}, \
+ {RECLAIM_WB_MIXED, "RECLAIM_WB_MIXED"}, \
{RECLAIM_WB_SYNC, "RECLAIM_WB_SYNC"}, \
{RECLAIM_WB_ASYNC, "RECLAIM_WB_ASYNC"} \
) : "RECLAIM_WB_NONE"
#define trace_reclaim_flags(page, sync) ( \
(page_is_file_cache(page) ? RECLAIM_WB_FILE : RECLAIM_WB_ANON) | \
- (sync == PAGEOUT_IO_SYNC ? RECLAIM_WB_SYNC : RECLAIM_WB_ASYNC) \
+ (sync == LUMPY_MODE_SYNC ? RECLAIM_WB_SYNC : RECLAIM_WB_ASYNC) \
+ )
+
+#define trace_shrink_flags(file, sync) ( \
+ (sync == LUMPY_MODE_SYNC ? RECLAIM_WB_MIXED : \
+ (file ? RECLAIM_WB_FILE : RECLAIM_WB_ANON)) | \
+ (sync == LUMPY_MODE_SYNC ? RECLAIM_WB_SYNC : RECLAIM_WB_ASYNC) \
)
TRACE_EVENT(mm_vmscan_kswapd_sleep,
@@ -269,6 +277,40 @@ TRACE_EVENT(mm_vmscan_writepage,
show_reclaim_flags(__entry->reclaim_flags))
);
+TRACE_EVENT(mm_vmscan_lru_shrink_inactive,
+
+ TP_PROTO(int nid, int zid,
+ unsigned long nr_scanned, unsigned long nr_reclaimed,
+ int priority, int reclaim_flags),
+
+ TP_ARGS(nid, zid, nr_scanned, nr_reclaimed, priority, reclaim_flags),
+
+ TP_STRUCT__entry(
+ __field(int, nid)
+ __field(int, zid)
+ __field(unsigned long, nr_scanned)
+ __field(unsigned long, nr_reclaimed)
+ __field(int, priority)
+ __field(int, reclaim_flags)
+ ),
+
+ TP_fast_assign(
+ __entry->nid = nid;
+ __entry->zid = zid;
+ __entry->nr_scanned = nr_scanned;
+ __entry->nr_reclaimed = nr_reclaimed;
+ __entry->priority = priority;
+ __entry->reclaim_flags = reclaim_flags;
+ ),
+
+ TP_printk("nid=%d zid=%d nr_scanned=%ld nr_reclaimed=%ld priority=%d flags=%s",
+ __entry->nid, __entry->zid,
+ __entry->nr_scanned, __entry->nr_reclaimed,
+ __entry->priority,
+ show_reclaim_flags(__entry->reclaim_flags))
+);
+
+
#endif /* _TRACE_VMSCAN_H */
/* This part must be outside protection */
diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h
index f345f66ae9d1..89a2b2db4375 100644
--- a/include/trace/events/writeback.h
+++ b/include/trace/events/writeback.h
@@ -96,8 +96,6 @@ DECLARE_EVENT_CLASS(wbc_class,
__field(long, nr_to_write)
__field(long, pages_skipped)
__field(int, sync_mode)
- __field(int, nonblocking)
- __field(int, encountered_congestion)
__field(int, for_kupdate)
__field(int, for_background)
__field(int, for_reclaim)
@@ -153,6 +151,41 @@ DEFINE_WBC_EVENT(wbc_balance_dirty_written);
DEFINE_WBC_EVENT(wbc_balance_dirty_wait);
DEFINE_WBC_EVENT(wbc_writepage);
+DECLARE_EVENT_CLASS(writeback_congest_waited_template,
+
+ TP_PROTO(unsigned int usec_timeout, unsigned int usec_delayed),
+
+ TP_ARGS(usec_timeout, usec_delayed),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, usec_timeout )
+ __field( unsigned int, usec_delayed )
+ ),
+
+ TP_fast_assign(
+ __entry->usec_timeout = usec_timeout;
+ __entry->usec_delayed = usec_delayed;
+ ),
+
+ TP_printk("usec_timeout=%u usec_delayed=%u",
+ __entry->usec_timeout,
+ __entry->usec_delayed)
+);
+
+DEFINE_EVENT(writeback_congest_waited_template, writeback_congestion_wait,
+
+ TP_PROTO(unsigned int usec_timeout, unsigned int usec_delayed),
+
+ TP_ARGS(usec_timeout, usec_delayed)
+);
+
+DEFINE_EVENT(writeback_congest_waited_template, writeback_wait_iff_congested,
+
+ TP_PROTO(unsigned int usec_timeout, unsigned int usec_delayed),
+
+ TP_ARGS(usec_timeout, usec_delayed)
+);
+
#endif /* _TRACE_WRITEBACK_H */
/* This part must be outside protection */
diff --git a/include/video/sh_mobile_hdmi.h b/include/video/sh_mobile_hdmi.h
index 577cf18cce89..1e1aa54ab2e4 100644
--- a/include/video/sh_mobile_hdmi.h
+++ b/include/video/sh_mobile_hdmi.h
@@ -14,9 +14,25 @@
struct sh_mobile_lcdc_chan_cfg;
struct device;
+/*
+ * flags format
+ *
+ * 0x0000000A
+ *
+ * A: Audio source select
+ */
+
+/* Audio source select */
+#define HDMI_SND_SRC_MASK (0xF << 0)
+#define HDMI_SND_SRC_I2S (0 << 0) /* default */
+#define HDMI_SND_SRC_SPDIF (1 << 0)
+#define HDMI_SND_SRC_DSD (2 << 0)
+#define HDMI_SND_SRC_HBR (3 << 0)
+
struct sh_mobile_hdmi_info {
struct sh_mobile_lcdc_chan_cfg *lcd_chan;
struct device *lcd_dev;
+ unsigned int flags;
};
#endif
diff --git a/include/video/vga.h b/include/video/vga.h
index b49a5120ca2d..2b8691f7d256 100644
--- a/include/video/vga.h
+++ b/include/video/vga.h
@@ -5,7 +5,7 @@
*
* Copyright history from vga16fb.c:
* Copyright 1999 Ben Pfaff and Petr Vandrovec
- * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
+ * Based on VGA info at http://www.osdever.net/FreeVGA/home.htm
* Based on VESA framebuffer (c) 1998 Gerd Knorr
*
* This file is subject to the terms and conditions of the GNU General
diff --git a/include/xen/Kbuild b/include/xen/Kbuild
index 4e65c16a445b..84ad8f02fee5 100644
--- a/include/xen/Kbuild
+++ b/include/xen/Kbuild
@@ -1 +1,2 @@
header-y += evtchn.h
+header-y += privcmd.h
diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
index d3938d3e71f8..d7a6c13bde69 100644
--- a/include/xen/interface/memory.h
+++ b/include/xen/interface/memory.h
@@ -186,6 +186,35 @@ struct xen_translate_gpfn_list {
};
DEFINE_GUEST_HANDLE_STRUCT(xen_translate_gpfn_list);
+/*
+ * Returns the pseudo-physical memory map as it was when the domain
+ * was started (specified by XENMEM_set_memory_map).
+ * arg == addr of struct xen_memory_map.
+ */
+#define XENMEM_memory_map 9
+struct xen_memory_map {
+ /*
+ * On call the number of entries which can be stored in buffer. On
+ * return the number of entries which have been stored in
+ * buffer.
+ */
+ unsigned int nr_entries;
+
+ /*
+ * Entries in the buffer are in the same format as returned by the
+ * BIOS INT 0x15 EAX=0xE820 call.
+ */
+ GUEST_HANDLE(void) buffer;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_memory_map);
+
+/*
+ * Returns the real physical memory map. Passes the same structure as
+ * XENMEM_memory_map.
+ * arg == addr of struct xen_memory_map.
+ */
+#define XENMEM_machine_memory_map 10
+
/*
* Prevent the balloon driver from changing the memory reservation
diff --git a/include/xen/privcmd.h b/include/xen/privcmd.h
new file mode 100644
index 000000000000..b42cdfd92fee
--- /dev/null
+++ b/include/xen/privcmd.h
@@ -0,0 +1,80 @@
+/******************************************************************************
+ * privcmd.h
+ *
+ * Interface to /proc/xen/privcmd.
+ *
+ * Copyright (c) 2003-2005, K A Fraser
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __LINUX_PUBLIC_PRIVCMD_H__
+#define __LINUX_PUBLIC_PRIVCMD_H__
+
+#include <linux/types.h>
+
+typedef unsigned long xen_pfn_t;
+
+#ifndef __user
+#define __user
+#endif
+
+struct privcmd_hypercall {
+ __u64 op;
+ __u64 arg[5];
+};
+
+struct privcmd_mmap_entry {
+ __u64 va;
+ __u64 mfn;
+ __u64 npages;
+};
+
+struct privcmd_mmap {
+ int num;
+ domid_t dom; /* target domain */
+ struct privcmd_mmap_entry __user *entry;
+};
+
+struct privcmd_mmapbatch {
+ int num; /* number of pages to populate */
+ domid_t dom; /* target domain */
+ __u64 addr; /* virtual address */
+ xen_pfn_t __user *arr; /* array of mfns - top nibble set on err */
+};
+
+/*
+ * @cmd: IOCTL_PRIVCMD_HYPERCALL
+ * @arg: &privcmd_hypercall_t
+ * Return: Value returned from execution of the specified hypercall.
+ */
+#define IOCTL_PRIVCMD_HYPERCALL \
+ _IOC(_IOC_NONE, 'P', 0, sizeof(struct privcmd_hypercall))
+#define IOCTL_PRIVCMD_MMAP \
+ _IOC(_IOC_NONE, 'P', 2, sizeof(struct privcmd_mmap))
+#define IOCTL_PRIVCMD_MMAPBATCH \
+ _IOC(_IOC_NONE, 'P', 3, sizeof(struct privcmd_mmapbatch))
+
+#endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
index 351f4051f6d8..98b92154a264 100644
--- a/include/xen/xen-ops.h
+++ b/include/xen/xen-ops.h
@@ -23,4 +23,9 @@ int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order);
+int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
+ unsigned long addr,
+ unsigned long mfn, int nr,
+ pgprot_t prot, unsigned domid);
+
#endif /* INCLUDE_XEN_OPS_H */
diff --git a/init/Kconfig b/init/Kconfig
index fdfd97efe0e0..88c10468db46 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -186,7 +186,7 @@ config KERNEL_LZO
depends on HAVE_KERNEL_LZO
help
Its compression ratio is the poorest among the 4. The kernel
- size is about about 10% bigger than gzip; however its speed
+ size is about 10% bigger than gzip; however its speed
(both compression and decompression) is the fastest.
endchoice
@@ -518,7 +518,6 @@ if CGROUPS
config CGROUP_DEBUG
bool "Example debug cgroup subsystem"
- depends on CGROUPS
default n
help
This option enables a simple cgroup subsystem that
@@ -529,7 +528,6 @@ config CGROUP_DEBUG
config CGROUP_NS
bool "Namespace cgroup subsystem"
- depends on CGROUPS
help
Provides a simple namespace cgroup subsystem to
provide hierarchical naming of sets of namespaces,
@@ -538,21 +536,18 @@ config CGROUP_NS
config CGROUP_FREEZER
bool "Freezer cgroup subsystem"
- depends on CGROUPS
help
Provides a way to freeze and unfreeze all tasks in a
cgroup.
config CGROUP_DEVICE
bool "Device controller for cgroups"
- depends on CGROUPS && EXPERIMENTAL
help
Provides a cgroup implementing whitelists for devices which
a process in the cgroup can mknod or open.
config CPUSETS
bool "Cpuset support"
- depends on CGROUPS
help
This option will let you create and manage CPUSETs which
allow dynamically partitioning a system into sets of CPUs and
@@ -568,7 +563,6 @@ config PROC_PID_CPUSET
config CGROUP_CPUACCT
bool "Simple CPU accounting cgroup subsystem"
- depends on CGROUPS
help
Provides a simple Resource Controller for monitoring the
total CPU consumed by the tasks in a cgroup.
@@ -578,11 +572,10 @@ config RESOURCE_COUNTERS
help
This option enables controller independent resource accounting
infrastructure that works with cgroups.
- depends on CGROUPS
config CGROUP_MEM_RES_CTLR
bool "Memory Resource Controller for Control Groups"
- depends on CGROUPS && RESOURCE_COUNTERS
+ depends on RESOURCE_COUNTERS
select MM_OWNER
help
Provides a memory resource controller that manages both anonymous
@@ -623,7 +616,7 @@ config CGROUP_MEM_RES_CTLR_SWAP
menuconfig CGROUP_SCHED
bool "Group CPU scheduler"
- depends on EXPERIMENTAL && CGROUPS
+ depends on EXPERIMENTAL
default n
help
This feature lets CPU scheduler recognize task groups and control CPU
@@ -652,7 +645,7 @@ endif #CGROUP_SCHED
config BLK_CGROUP
tristate "Block IO controller"
- depends on CGROUPS && BLOCK
+ depends on BLOCK
default n
---help---
Generic block IO controller cgroup interface. This is the common
@@ -682,6 +675,59 @@ config DEBUG_BLK_CGROUP
endif # CGROUPS
+menuconfig NAMESPACES
+ bool "Namespaces support" if EMBEDDED
+ default !EMBEDDED
+ help
+ Provides the way to make tasks work with different objects using
+ the same id. For example same IPC id may refer to different objects
+ or same user id or pid may refer to different tasks when used in
+ different namespaces.
+
+if NAMESPACES
+
+config UTS_NS
+ bool "UTS namespace"
+ default y
+ help
+ In this namespace tasks see different info provided with the
+ uname() system call
+
+config IPC_NS
+ bool "IPC namespace"
+ depends on (SYSVIPC || POSIX_MQUEUE)
+ default y
+ help
+ In this namespace tasks work with IPC ids which correspond to
+ different IPC objects in different namespaces.
+
+config USER_NS
+ bool "User namespace (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ default y
+ help
+ This allows containers, i.e. vservers, to use user namespaces
+ to provide different user info for different servers.
+ If unsure, say N.
+
+config PID_NS
+ bool "PID Namespaces"
+ default y
+ help
+ Support process id namespaces. This allows having multiple
+ processes with the same pid as long as they are in different
+ pid namespaces. This is a building block of containers.
+
+config NET_NS
+ bool "Network namespace"
+ depends on NET
+ default y
+ help
+ Allow user space to create what appear to be multiple instances
+ of the network stack.
+
+endif # NAMESPACES
+
config MM_OWNER
bool
@@ -734,57 +780,6 @@ config RELAY
If unsure, say N.
-config NAMESPACES
- bool "Namespaces support" if EMBEDDED
- default !EMBEDDED
- help
- Provides the way to make tasks work with different objects using
- the same id. For example same IPC id may refer to different objects
- or same user id or pid may refer to different tasks when used in
- different namespaces.
-
-config UTS_NS
- bool "UTS namespace"
- depends on NAMESPACES
- help
- In this namespace tasks see different info provided with the
- uname() system call
-
-config IPC_NS
- bool "IPC namespace"
- depends on NAMESPACES && (SYSVIPC || POSIX_MQUEUE)
- help
- In this namespace tasks work with IPC ids which correspond to
- different IPC objects in different namespaces.
-
-config USER_NS
- bool "User namespace (EXPERIMENTAL)"
- depends on NAMESPACES && EXPERIMENTAL
- help
- This allows containers, i.e. vservers, to use user namespaces
- to provide different user info for different servers.
- If unsure, say N.
-
-config PID_NS
- bool "PID Namespaces (EXPERIMENTAL)"
- default n
- depends on NAMESPACES && EXPERIMENTAL
- help
- Support process id namespaces. This allows having multiple
- processes with the same pid as long as they are in different
- pid namespaces. This is a building block of containers.
-
- Unless you want to work with an experimental feature
- say N here.
-
-config NET_NS
- bool "Network namespace"
- default n
- depends on NAMESPACES && EXPERIMENTAL && NET
- help
- Allow user space to create what appear to be multiple instances
- of the network stack.
-
config BLK_DEV_INITRD
bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support"
depends on BROKEN || !FRV
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 42db0551c3aa..830aaec9c7d5 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -291,7 +291,7 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data)
if (err)
return err;
- sys_chdir("/root");
+ sys_chdir((const char __user __force *)"/root");
ROOT_DEV = current->fs->pwd.mnt->mnt_sb->s_dev;
printk("VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",
current->fs->pwd.mnt->mnt_sb->s_type->name,
@@ -361,13 +361,13 @@ out:
#ifdef CONFIG_ROOT_NFS
static int __init mount_nfs_root(void)
{
- void *data = nfs_root_data();
+ char *root_dev, *root_data;
- create_dev("/dev/root", ROOT_DEV);
- if (data &&
- do_mount_root("/dev/root", "nfs", root_mountflags, data) == 0)
- return 1;
- return 0;
+ if (nfs_root_data(&root_dev, &root_data) != 0)
+ return 0;
+ if (do_mount_root(root_dev, "nfs", root_mountflags, root_data) != 0)
+ return 0;
+ return 1;
}
#endif
@@ -488,5 +488,5 @@ void __init prepare_namespace(void)
out:
devtmpfs_mount("dev");
sys_mount(".", "/", NULL, MS_MOVE, NULL);
- sys_chroot(".");
+ sys_chroot((const char __user __force *)".");
}
diff --git a/init/do_mounts_md.c b/init/do_mounts_md.c
index 69aebbf8fd2d..32c4799b8c91 100644
--- a/init/do_mounts_md.c
+++ b/init/do_mounts_md.c
@@ -283,7 +283,7 @@ static void __init autodetect_raid(void)
wait_for_device_probe();
- fd = sys_open("/dev/md0", 0, 0);
+ fd = sys_open((const char __user __force *) "/dev/md0", 0, 0);
if (fd >= 0) {
sys_ioctl(fd, RAID_AUTORUN, raid_autopart);
sys_close(fd);
diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c
index bf3ef667bf36..6e1ee6987c78 100644
--- a/init/do_mounts_rd.c
+++ b/init/do_mounts_rd.c
@@ -168,7 +168,7 @@ int __init rd_load_image(char *from)
char rotator[4] = { '|' , '/' , '-' , '\\' };
#endif
- out_fd = sys_open("/dev/ram", O_RDWR, 0);
+ out_fd = sys_open((const char __user __force *) "/dev/ram", O_RDWR, 0);
if (out_fd < 0)
goto out;
@@ -267,7 +267,7 @@ noclose_input:
sys_close(out_fd);
out:
kfree(buf);
- sys_unlink("/dev/ram");
+ sys_unlink((const char __user __force *) "/dev/ram");
return res;
}
diff --git a/init/initramfs.c b/init/initramfs.c
index 4b9c20205092..d9c6e782ff53 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -528,7 +528,7 @@ static void __init clean_rootfs(void)
struct linux_dirent64 *dirp;
int num;
- fd = sys_open("/", O_RDONLY, 0);
+ fd = sys_open((const char __user __force *) "/", O_RDONLY, 0);
WARN_ON(fd < 0);
if (fd < 0)
return;
@@ -590,7 +590,8 @@ static int __init populate_rootfs(void)
}
printk(KERN_INFO "rootfs image is not initramfs (%s)"
"; looks like an initrd\n", err);
- fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);
+ fd = sys_open((const char __user __force *) "/initrd.image",
+ O_WRONLY|O_CREAT, 0700);
if (fd >= 0) {
sys_write(fd, (char *)initrd_start,
initrd_end - initrd_start);
diff --git a/init/noinitramfs.c b/init/noinitramfs.c
index f4c1a3a1b8c5..267739d85179 100644
--- a/init/noinitramfs.c
+++ b/init/noinitramfs.c
@@ -29,17 +29,17 @@ static int __init default_rootfs(void)
{
int err;
- err = sys_mkdir("/dev", 0755);
+ err = sys_mkdir((const char __user __force *) "/dev", 0755);
if (err < 0)
goto out;
- err = sys_mknod((const char __user *) "/dev/console",
+ err = sys_mknod((const char __user __force *) "/dev/console",
S_IFCHR | S_IRUSR | S_IWUSR,
new_encode_dev(MKDEV(5, 1)));
if (err < 0)
goto out;
- err = sys_mkdir("/root", 0700);
+ err = sys_mkdir((const char __user __force *) "/root", 0700);
if (err < 0)
goto out;
diff --git a/ipc/compat.c b/ipc/compat.c
index 9dc2c7d3c9e6..845a28738d3a 100644
--- a/ipc/compat.c
+++ b/ipc/compat.c
@@ -241,6 +241,8 @@ long compat_sys_semctl(int first, int second, int third, void __user *uptr)
struct semid64_ds __user *up64;
int version = compat_ipc_parse_version(&third);
+ memset(&s64, 0, sizeof(s64));
+
if (!uptr)
return -EINVAL;
if (get_user(pad, (u32 __user *) uptr))
@@ -421,6 +423,8 @@ long compat_sys_msgctl(int first, int second, void __user *uptr)
int version = compat_ipc_parse_version(&second);
void __user *p;
+ memset(&m64, 0, sizeof(m64));
+
switch (second & (~IPC_64)) {
case IPC_INFO:
case IPC_RMID:
@@ -594,6 +598,8 @@ long compat_sys_shmctl(int first, int second, void __user *uptr)
int err, err2;
int version = compat_ipc_parse_version(&second);
+ memset(&s64, 0, sizeof(s64));
+
switch (second & (~IPC_64)) {
case IPC_RMID:
case SHM_LOCK:
diff --git a/ipc/compat_mq.c b/ipc/compat_mq.c
index d8d1e9ff4e88..380ea4fe08e7 100644
--- a/ipc/compat_mq.c
+++ b/ipc/compat_mq.c
@@ -53,6 +53,9 @@ asmlinkage long compat_sys_mq_open(const char __user *u_name,
void __user *p = NULL;
if (u_attr && oflag & O_CREAT) {
struct mq_attr attr;
+
+ memset(&attr, 0, sizeof(attr));
+
p = compat_alloc_user_space(sizeof(attr));
if (get_compat_mq_attr(&attr, u_attr) ||
copy_to_user(p, &attr, sizeof(attr)))
@@ -127,6 +130,8 @@ asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes,
struct mq_attr __user *p = compat_alloc_user_space(2 * sizeof(*p));
long ret;
+ memset(&mqstat, 0, sizeof(mqstat));
+
if (u_mqstat) {
if (get_compat_mq_attr(&mqstat, u_mqstat) ||
copy_to_user(p, &mqstat, sizeof(mqstat)))
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index e1e7b9635f5d..3a61ffefe884 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -116,6 +116,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
inode = new_inode(sb);
if (inode) {
+ inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
@@ -769,7 +770,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
inode = dentry->d_inode;
if (inode)
- atomic_inc(&inode->i_count);
+ ihold(inode);
err = mnt_want_write(ipc_ns->mq_mnt);
if (err)
goto out_err;
diff --git a/ipc/shm.c b/ipc/shm.c
index 7bc46a9fe1f8..fd658a1c2b88 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -108,7 +108,11 @@ void __init shm_init (void)
{
shm_init_ns(&init_ipc_ns);
ipc_init_proc_interface("sysvipc/shm",
- " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n",
+#if BITS_PER_LONG <= 32
+ " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n",
+#else
+ " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n",
+#endif
IPC_SHM_IDS, sysvipc_shm_proc_show);
}
@@ -544,6 +548,34 @@ static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminf
}
/*
+ * Calculate and add used RSS and swap pages of a shm.
+ * Called with shm_ids.rw_mutex held as a reader
+ */
+static void shm_add_rss_swap(struct shmid_kernel *shp,
+ unsigned long *rss_add, unsigned long *swp_add)
+{
+ struct inode *inode;
+
+ inode = shp->shm_file->f_path.dentry->d_inode;
+
+ if (is_file_hugepages(shp->shm_file)) {
+ struct address_space *mapping = inode->i_mapping;
+ struct hstate *h = hstate_file(shp->shm_file);
+ *rss_add += pages_per_huge_page(h) * mapping->nrpages;
+ } else {
+#ifdef CONFIG_SHMEM
+ struct shmem_inode_info *info = SHMEM_I(inode);
+ spin_lock(&info->lock);
+ *rss_add += inode->i_mapping->nrpages;
+ *swp_add += info->swapped;
+ spin_unlock(&info->lock);
+#else
+ *rss_add += inode->i_mapping->nrpages;
+#endif
+ }
+}
+
+/*
* Called with shm_ids.rw_mutex held as a reader
*/
static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
@@ -560,30 +592,13 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
for (total = 0, next_id = 0; total < in_use; next_id++) {
struct kern_ipc_perm *ipc;
struct shmid_kernel *shp;
- struct inode *inode;
ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id);
if (ipc == NULL)
continue;
shp = container_of(ipc, struct shmid_kernel, shm_perm);
- inode = shp->shm_file->f_path.dentry->d_inode;
-
- if (is_file_hugepages(shp->shm_file)) {
- struct address_space *mapping = inode->i_mapping;
- struct hstate *h = hstate_file(shp->shm_file);
- *rss += pages_per_huge_page(h) * mapping->nrpages;
- } else {
-#ifdef CONFIG_SHMEM
- struct shmem_inode_info *info = SHMEM_I(inode);
- spin_lock(&info->lock);
- *rss += inode->i_mapping->nrpages;
- *swp += info->swapped;
- spin_unlock(&info->lock);
-#else
- *rss += inode->i_mapping->nrpages;
-#endif
- }
+ shm_add_rss_swap(shp, rss, swp);
total++;
}
@@ -1072,6 +1087,9 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
{
struct shmid_kernel *shp = it;
+ unsigned long rss = 0, swp = 0;
+
+ shm_add_rss_swap(shp, &rss, &swp);
#if BITS_PER_LONG <= 32
#define SIZE_SPEC "%10lu"
@@ -1081,7 +1099,8 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
return seq_printf(s,
"%10d %10d %4o " SIZE_SPEC " %5u %5u "
- "%5lu %5u %5u %5u %5u %10lu %10lu %10lu\n",
+ "%5lu %5u %5u %5u %5u %10lu %10lu %10lu "
+ SIZE_SPEC " " SIZE_SPEC "\n",
shp->shm_perm.key,
shp->shm_perm.id,
shp->shm_perm.mode,
@@ -1095,6 +1114,8 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
shp->shm_perm.cgid,
shp->shm_atim,
shp->shm_dtim,
- shp->shm_ctim);
+ shp->shm_ctim,
+ rss * PAGE_SIZE,
+ swp * PAGE_SIZE);
}
#endif
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 7b69b8d0313d..5cf366965d0c 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -243,6 +243,11 @@ static int notify_on_release(const struct cgroup *cgrp)
return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
}
+static int clone_children(const struct cgroup *cgrp)
+{
+ return test_bit(CGRP_CLONE_CHILDREN, &cgrp->flags);
+}
+
/*
* for_each_subsys() allows you to iterate on each subsystem attached to
* an active hierarchy
@@ -777,6 +782,7 @@ static struct inode *cgroup_new_inode(mode_t mode, struct super_block *sb)
struct inode *inode = new_inode(sb);
if (inode) {
+ inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
@@ -1039,6 +1045,8 @@ static int cgroup_show_options(struct seq_file *seq, struct vfsmount *vfs)
seq_puts(seq, ",noprefix");
if (strlen(root->release_agent_path))
seq_printf(seq, ",release_agent=%s", root->release_agent_path);
+ if (clone_children(&root->top_cgroup))
+ seq_puts(seq, ",clone_children");
if (strlen(root->name))
seq_printf(seq, ",name=%s", root->name);
mutex_unlock(&cgroup_mutex);
@@ -1049,6 +1057,7 @@ struct cgroup_sb_opts {
unsigned long subsys_bits;
unsigned long flags;
char *release_agent;
+ bool clone_children;
char *name;
/* User explicitly requested empty subsystem */
bool none;
@@ -1065,7 +1074,8 @@ struct cgroup_sb_opts {
*/
static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
{
- char *token, *o = data ?: "all";
+ char *token, *o = data;
+ bool all_ss = false, one_ss = false;
unsigned long mask = (unsigned long)-1;
int i;
bool module_pin_failed = false;
@@ -1081,22 +1091,27 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
while ((token = strsep(&o, ",")) != NULL) {
if (!*token)
return -EINVAL;
- if (!strcmp(token, "all")) {
- /* Add all non-disabled subsystems */
- opts->subsys_bits = 0;
- for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
- struct cgroup_subsys *ss = subsys[i];
- if (ss == NULL)
- continue;
- if (!ss->disabled)
- opts->subsys_bits |= 1ul << i;
- }
- } else if (!strcmp(token, "none")) {
+ if (!strcmp(token, "none")) {
/* Explicitly have no subsystems */
opts->none = true;
- } else if (!strcmp(token, "noprefix")) {
+ continue;
+ }
+ if (!strcmp(token, "all")) {
+ /* Mutually exclusive option 'all' + subsystem name */
+ if (one_ss)
+ return -EINVAL;
+ all_ss = true;
+ continue;
+ }
+ if (!strcmp(token, "noprefix")) {
set_bit(ROOT_NOPREFIX, &opts->flags);
- } else if (!strncmp(token, "release_agent=", 14)) {
+ continue;
+ }
+ if (!strcmp(token, "clone_children")) {
+ opts->clone_children = true;
+ continue;
+ }
+ if (!strncmp(token, "release_agent=", 14)) {
/* Specifying two release agents is forbidden */
if (opts->release_agent)
return -EINVAL;
@@ -1104,7 +1119,9 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
kstrndup(token + 14, PATH_MAX - 1, GFP_KERNEL);
if (!opts->release_agent)
return -ENOMEM;
- } else if (!strncmp(token, "name=", 5)) {
+ continue;
+ }
+ if (!strncmp(token, "name=", 5)) {
const char *name = token + 5;
/* Can't specify an empty name */
if (!strlen(name))
@@ -1126,20 +1143,44 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
GFP_KERNEL);
if (!opts->name)
return -ENOMEM;
- } else {
- struct cgroup_subsys *ss;
- for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
- ss = subsys[i];
- if (ss == NULL)
- continue;
- if (!strcmp(token, ss->name)) {
- if (!ss->disabled)
- set_bit(i, &opts->subsys_bits);
- break;
- }
- }
- if (i == CGROUP_SUBSYS_COUNT)
- return -ENOENT;
+
+ continue;
+ }
+
+ for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
+ struct cgroup_subsys *ss = subsys[i];
+ if (ss == NULL)
+ continue;
+ if (strcmp(token, ss->name))
+ continue;
+ if (ss->disabled)
+ continue;
+
+ /* Mutually exclusive option 'all' + subsystem name */
+ if (all_ss)
+ return -EINVAL;
+ set_bit(i, &opts->subsys_bits);
+ one_ss = true;
+
+ break;
+ }
+ if (i == CGROUP_SUBSYS_COUNT)
+ return -ENOENT;
+ }
+
+ /*
+ * If the 'all' option was specified select all the subsystems,
+ * otherwise 'all, 'none' and a subsystem name options were not
+ * specified, let's default to 'all'
+ */
+ if (all_ss || (!all_ss && !one_ss && !opts->none)) {
+ for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
+ struct cgroup_subsys *ss = subsys[i];
+ if (ss == NULL)
+ continue;
+ if (ss->disabled)
+ continue;
+ set_bit(i, &opts->subsys_bits);
}
}
@@ -1354,6 +1395,8 @@ static struct cgroupfs_root *cgroup_root_from_opts(struct cgroup_sb_opts *opts)
strcpy(root->release_agent_path, opts->release_agent);
if (opts->name)
strcpy(root->name, opts->name);
+ if (opts->clone_children)
+ set_bit(CGRP_CLONE_CHILDREN, &root->top_cgroup.flags);
return root;
}
@@ -1879,6 +1922,8 @@ static int cgroup_release_agent_write(struct cgroup *cgrp, struct cftype *cft,
const char *buffer)
{
BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
+ if (strlen(buffer) >= PATH_MAX)
+ return -EINVAL;
if (!cgroup_lock_live_group(cgrp))
return -ENODEV;
strcpy(cgrp->root->release_agent_path, buffer);
@@ -3172,6 +3217,23 @@ fail:
return ret;
}
+static u64 cgroup_clone_children_read(struct cgroup *cgrp,
+ struct cftype *cft)
+{
+ return clone_children(cgrp);
+}
+
+static int cgroup_clone_children_write(struct cgroup *cgrp,
+ struct cftype *cft,
+ u64 val)
+{
+ if (val)
+ set_bit(CGRP_CLONE_CHILDREN, &cgrp->flags);
+ else
+ clear_bit(CGRP_CLONE_CHILDREN, &cgrp->flags);
+ return 0;
+}
+
/*
* for the common functions, 'private' gives the type of file
*/
@@ -3202,6 +3264,11 @@ static struct cftype files[] = {
.write_string = cgroup_write_event_control,
.mode = S_IWUGO,
},
+ {
+ .name = "cgroup.clone_children",
+ .read_u64 = cgroup_clone_children_read,
+ .write_u64 = cgroup_clone_children_write,
+ },
};
static struct cftype cft_release_agent = {
@@ -3331,6 +3398,9 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
if (notify_on_release(parent))
set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
+ if (clone_children(parent))
+ set_bit(CGRP_CLONE_CHILDREN, &cgrp->flags);
+
for_each_subsys(root, ss) {
struct cgroup_subsys_state *css = ss->create(ss, cgrp);
@@ -3345,6 +3415,8 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
goto err_destroy;
}
/* At error, ->destroy() callback has to free assigned ID. */
+ if (clone_children(parent) && ss->post_clone)
+ ss->post_clone(ss, cgrp);
}
cgroup_lock_hierarchy(root);
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c
index ce71ed53e88f..e7bebb7c6c38 100644
--- a/kernel/cgroup_freezer.c
+++ b/kernel/cgroup_freezer.c
@@ -48,20 +48,19 @@ static inline struct freezer *task_freezer(struct task_struct *task)
struct freezer, css);
}
-int cgroup_freezing_or_frozen(struct task_struct *task)
+static inline int __cgroup_freezing_or_frozen(struct task_struct *task)
{
- struct freezer *freezer;
- enum freezer_state state;
+ enum freezer_state state = task_freezer(task)->state;
+ return (state == CGROUP_FREEZING) || (state == CGROUP_FROZEN);
+}
+int cgroup_freezing_or_frozen(struct task_struct *task)
+{
+ int result;
task_lock(task);
- freezer = task_freezer(task);
- if (!freezer->css.cgroup->parent)
- state = CGROUP_THAWED; /* root cgroup can't be frozen */
- else
- state = freezer->state;
+ result = __cgroup_freezing_or_frozen(task);
task_unlock(task);
-
- return (state == CGROUP_FREEZING) || (state == CGROUP_FROZEN);
+ return result;
}
/*
@@ -154,13 +153,6 @@ static void freezer_destroy(struct cgroup_subsys *ss,
kfree(cgroup_freezer(cgroup));
}
-/* Task is frozen or will freeze immediately when next it gets woken */
-static bool is_task_frozen_enough(struct task_struct *task)
-{
- return frozen(task) ||
- (task_is_stopped_or_traced(task) && freezing(task));
-}
-
/*
* The call to cgroup_lock() in the freezer.state write method prevents
* a write to that file racing against an attach, and hence the
@@ -174,24 +166,25 @@ static int freezer_can_attach(struct cgroup_subsys *ss,
/*
* Anything frozen can't move or be moved to/from.
- *
- * Since orig_freezer->state == FROZEN means that @task has been
- * frozen, so it's sufficient to check the latter condition.
*/
- if (is_task_frozen_enough(task))
+ freezer = cgroup_freezer(new_cgroup);
+ if (freezer->state != CGROUP_THAWED)
return -EBUSY;
- freezer = cgroup_freezer(new_cgroup);
- if (freezer->state == CGROUP_FROZEN)
+ rcu_read_lock();
+ if (__cgroup_freezing_or_frozen(task)) {
+ rcu_read_unlock();
return -EBUSY;
+ }
+ rcu_read_unlock();
if (threadgroup) {
struct task_struct *c;
rcu_read_lock();
list_for_each_entry_rcu(c, &task->thread_group, thread_group) {
- if (is_task_frozen_enough(c)) {
+ if (__cgroup_freezing_or_frozen(c)) {
rcu_read_unlock();
return -EBUSY;
}
@@ -236,31 +229,30 @@ static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task)
/*
* caller must hold freezer->lock
*/
-static void update_freezer_state(struct cgroup *cgroup,
+static void update_if_frozen(struct cgroup *cgroup,
struct freezer *freezer)
{
struct cgroup_iter it;
struct task_struct *task;
unsigned int nfrozen = 0, ntotal = 0;
+ enum freezer_state old_state = freezer->state;
cgroup_iter_start(cgroup, &it);
while ((task = cgroup_iter_next(cgroup, &it))) {
ntotal++;
- if (is_task_frozen_enough(task))
+ if (frozen(task))
nfrozen++;
}
- /*
- * Transition to FROZEN when no new tasks can be added ensures
- * that we never exist in the FROZEN state while there are unfrozen
- * tasks.
- */
- if (nfrozen == ntotal)
- freezer->state = CGROUP_FROZEN;
- else if (nfrozen > 0)
- freezer->state = CGROUP_FREEZING;
- else
- freezer->state = CGROUP_THAWED;
+ if (old_state == CGROUP_THAWED) {
+ BUG_ON(nfrozen > 0);
+ } else if (old_state == CGROUP_FREEZING) {
+ if (nfrozen == ntotal)
+ freezer->state = CGROUP_FROZEN;
+ } else { /* old_state == CGROUP_FROZEN */
+ BUG_ON(nfrozen != ntotal);
+ }
+
cgroup_iter_end(cgroup, &it);
}
@@ -279,7 +271,7 @@ static int freezer_read(struct cgroup *cgroup, struct cftype *cft,
if (state == CGROUP_FREEZING) {
/* We change from FREEZING to FROZEN lazily if the cgroup was
* only partially frozen when we exitted write. */
- update_freezer_state(cgroup, freezer);
+ update_if_frozen(cgroup, freezer);
state = freezer->state;
}
spin_unlock_irq(&freezer->lock);
@@ -301,7 +293,7 @@ static int try_to_freeze_cgroup(struct cgroup *cgroup, struct freezer *freezer)
while ((task = cgroup_iter_next(cgroup, &it))) {
if (!freeze_task(task, true))
continue;
- if (is_task_frozen_enough(task))
+ if (frozen(task))
continue;
if (!freezing(task) && !freezer_should_skip(task))
num_cant_freeze_now++;
@@ -335,7 +327,7 @@ static int freezer_change_state(struct cgroup *cgroup,
spin_lock_irq(&freezer->lock);
- update_freezer_state(cgroup, freezer);
+ update_if_frozen(cgroup, freezer);
if (goal_state == freezer->state)
goto out;
diff --git a/kernel/cred.c b/kernel/cred.c
index 9a3e22641fe7..6a1aa004e376 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -325,7 +325,7 @@ EXPORT_SYMBOL(prepare_creds);
/*
* Prepare credentials for current to perform an execve()
- * - The caller must hold current->cred_guard_mutex
+ * - The caller must hold ->cred_guard_mutex
*/
struct cred *prepare_exec_creds(void)
{
@@ -384,8 +384,6 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
struct cred *new;
int ret;
- mutex_init(&p->cred_guard_mutex);
-
if (
#ifdef CONFIG_KEYS
!p->cred->thread_keyring &&
diff --git a/kernel/exit.c b/kernel/exit.c
index e2bdf37f9fde..b194febf5799 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -50,6 +50,7 @@
#include <linux/perf_event.h>
#include <trace/events/sched.h>
#include <linux/hw_breakpoint.h>
+#include <linux/oom.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -687,6 +688,8 @@ static void exit_mm(struct task_struct * tsk)
enter_lazy_tlb(mm, current);
/* We don't want this task to be frozen prematurely */
clear_freeze_flag(tsk);
+ if (tsk->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
+ atomic_dec(&mm->oom_disable_count);
task_unlock(tsk);
mm_update_next_owner(mm);
mmput(mm);
@@ -700,6 +703,8 @@ static void exit_mm(struct task_struct * tsk)
* space.
*/
static struct task_struct *find_new_reaper(struct task_struct *father)
+ __releases(&tasklist_lock)
+ __acquires(&tasklist_lock)
{
struct pid_namespace *pid_ns = task_active_pid_ns(father);
struct task_struct *thread;
diff --git a/kernel/fork.c b/kernel/fork.c
index c445f8cc408d..3b159c5991b7 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -65,6 +65,7 @@
#include <linux/perf_event.h>
#include <linux/posix-timers.h>
#include <linux/user-return-notifier.h>
+#include <linux/oom.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -488,6 +489,7 @@ static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p)
mm->cached_hole_size = ~0UL;
mm_init_aio(mm);
mm_init_owner(mm, p);
+ atomic_set(&mm->oom_disable_count, 0);
if (likely(!mm_alloc_pgd(mm))) {
mm->def_flags = 0;
@@ -741,6 +743,8 @@ good_mm:
/* Initializing for Swap token stuff */
mm->token_priority = 0;
mm->last_interval = 0;
+ if (tsk->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
+ atomic_inc(&mm->oom_disable_count);
tsk->mm = mm;
tsk->active_mm = mm;
@@ -904,6 +908,8 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
sig->oom_adj = current->signal->oom_adj;
sig->oom_score_adj = current->signal->oom_score_adj;
+ mutex_init(&sig->cred_guard_mutex);
+
return 0;
}
@@ -1299,8 +1305,13 @@ bad_fork_cleanup_io:
bad_fork_cleanup_namespaces:
exit_task_namespaces(p);
bad_fork_cleanup_mm:
- if (p->mm)
+ if (p->mm) {
+ task_lock(p);
+ if (p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
+ atomic_dec(&p->mm->oom_disable_count);
+ task_unlock(p);
mmput(p->mm);
+ }
bad_fork_cleanup_signal:
if (!(clone_flags & CLONE_THREAD))
free_signal_struct(p->signal);
@@ -1693,6 +1704,10 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
active_mm = current->active_mm;
current->mm = new_mm;
current->active_mm = new_mm;
+ if (current->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {
+ atomic_dec(&mm->oom_disable_count);
+ atomic_inc(&new_mm->oom_disable_count);
+ }
activate_mm(active_mm, new_mm);
new_mm = mm;
}
diff --git a/kernel/futex.c b/kernel/futex.c
index a118bf160e0b..6c683b37f2ce 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -169,7 +169,7 @@ static void get_futex_key_refs(union futex_key *key)
switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
case FUT_OFF_INODE:
- atomic_inc(&key->shared.inode->i_count);
+ ihold(key->shared.inode);
break;
case FUT_OFF_MMSHARED:
atomic_inc(&key->private.mm->mm_count);
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index 9d917ff72675..9988d03797f5 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -393,3 +393,18 @@ unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
struct irq_desc *desc = irq_to_desc(irq);
return desc ? desc->kstat_irqs[cpu] : 0;
}
+
+#ifdef CONFIG_GENERIC_HARDIRQS
+unsigned int kstat_irqs(unsigned int irq)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+ int cpu;
+ int sum = 0;
+
+ if (!desc)
+ return 0;
+ for_each_possible_cpu(cpu)
+ sum += desc->kstat_irqs[cpu];
+ return sum;
+}
+#endif /* CONFIG_GENERIC_HARDIRQS */
diff --git a/kernel/kexec.c b/kernel/kexec.c
index c0613f7d6730..b55045bc7563 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -816,7 +816,7 @@ static int kimage_load_normal_segment(struct kimage *image,
ptr = kmap(page);
/* Start with a clear page */
- memset(ptr, 0, PAGE_SIZE);
+ clear_page(ptr);
ptr += maddr & ~PAGE_MASK;
mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK);
if (mchunk > mbytes)
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 56a891914273..99865c33a60d 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -74,7 +74,8 @@ static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
/* NOTE: change this value only with kprobe_mutex held */
static bool kprobes_all_disarmed;
-static DEFINE_MUTEX(kprobe_mutex); /* Protects kprobe_table */
+/* This protects kprobe_table and optimizing_list */
+static DEFINE_MUTEX(kprobe_mutex);
static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
static struct {
spinlock_t lock ____cacheline_aligned_in_smp;
@@ -595,6 +596,7 @@ static __kprobes void try_to_optimize_kprobe(struct kprobe *p)
}
#ifdef CONFIG_SYSCTL
+/* This should be called with kprobe_mutex locked */
static void __kprobes optimize_all_kprobes(void)
{
struct hlist_head *head;
@@ -607,17 +609,16 @@ static void __kprobes optimize_all_kprobes(void)
return;
kprobes_allow_optimization = true;
- mutex_lock(&text_mutex);
for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
head = &kprobe_table[i];
hlist_for_each_entry_rcu(p, node, head, hlist)
if (!kprobe_disabled(p))
optimize_kprobe(p);
}
- mutex_unlock(&text_mutex);
printk(KERN_INFO "Kprobes globally optimized\n");
}
+/* This should be called with kprobe_mutex locked */
static void __kprobes unoptimize_all_kprobes(void)
{
struct hlist_head *head;
diff --git a/kernel/module.c b/kernel/module.c
index 2df46301a7a4..437a74a7524a 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2037,7 +2037,7 @@ static inline void layout_symtab(struct module *mod, struct load_info *info)
{
}
-static void add_kallsyms(struct module *mod, struct load_info *info)
+static void add_kallsyms(struct module *mod, const struct load_info *info)
{
}
#endif /* CONFIG_KALLSYMS */
diff --git a/kernel/ns_cgroup.c b/kernel/ns_cgroup.c
index 2a5dfec8efe0..2c98ad94ba0e 100644
--- a/kernel/ns_cgroup.c
+++ b/kernel/ns_cgroup.c
@@ -85,6 +85,14 @@ static struct cgroup_subsys_state *ns_create(struct cgroup_subsys *ss,
return ERR_PTR(-EPERM);
if (!cgroup_is_descendant(cgroup, current))
return ERR_PTR(-EPERM);
+ if (test_bit(CGRP_CLONE_CHILDREN, &cgroup->flags)) {
+ printk("ns_cgroup can't be created with parent "
+ "'clone_children' set.\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ printk_once("ns_cgroup deprecated: consider using the "
+ "'clone_children' flag without the ns_cgroup.\n");
ns_cgroup = kzalloc(sizeof(*ns_cgroup), GFP_KERNEL);
if (!ns_cgroup)
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index f309e8014c78..517d827f4982 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -417,8 +417,8 @@ event_filter_match(struct perf_event *event)
return event->cpu == -1 || event->cpu == smp_processor_id();
}
-static int
-__event_sched_out(struct perf_event *event,
+static void
+event_sched_out(struct perf_event *event,
struct perf_cpu_context *cpuctx,
struct perf_event_context *ctx)
{
@@ -437,13 +437,14 @@ __event_sched_out(struct perf_event *event,
}
if (event->state != PERF_EVENT_STATE_ACTIVE)
- return 0;
+ return;
event->state = PERF_EVENT_STATE_INACTIVE;
if (event->pending_disable) {
event->pending_disable = 0;
event->state = PERF_EVENT_STATE_OFF;
}
+ event->tstamp_stopped = ctx->time;
event->pmu->del(event, 0);
event->oncpu = -1;
@@ -452,19 +453,6 @@ __event_sched_out(struct perf_event *event,
ctx->nr_active--;
if (event->attr.exclusive || !cpuctx->active_oncpu)
cpuctx->exclusive = 0;
- return 1;
-}
-
-static void
-event_sched_out(struct perf_event *event,
- struct perf_cpu_context *cpuctx,
- struct perf_event_context *ctx)
-{
- int ret;
-
- ret = __event_sched_out(event, cpuctx, ctx);
- if (ret)
- event->tstamp_stopped = ctx->time;
}
static void
@@ -664,7 +652,7 @@ retry:
}
static int
-__event_sched_in(struct perf_event *event,
+event_sched_in(struct perf_event *event,
struct perf_cpu_context *cpuctx,
struct perf_event_context *ctx)
{
@@ -684,6 +672,8 @@ __event_sched_in(struct perf_event *event,
return -EAGAIN;
}
+ event->tstamp_running += ctx->time - event->tstamp_stopped;
+
if (!is_software_event(event))
cpuctx->active_oncpu++;
ctx->nr_active++;
@@ -694,35 +684,6 @@ __event_sched_in(struct perf_event *event,
return 0;
}
-static inline int
-event_sched_in(struct perf_event *event,
- struct perf_cpu_context *cpuctx,
- struct perf_event_context *ctx)
-{
- int ret = __event_sched_in(event, cpuctx, ctx);
- if (ret)
- return ret;
- event->tstamp_running += ctx->time - event->tstamp_stopped;
- return 0;
-}
-
-static void
-group_commit_event_sched_in(struct perf_event *group_event,
- struct perf_cpu_context *cpuctx,
- struct perf_event_context *ctx)
-{
- struct perf_event *event;
- u64 now = ctx->time;
-
- group_event->tstamp_running += now - group_event->tstamp_stopped;
- /*
- * Schedule in siblings as one group (if any):
- */
- list_for_each_entry(event, &group_event->sibling_list, group_entry) {
- event->tstamp_running += now - event->tstamp_stopped;
- }
-}
-
static int
group_sched_in(struct perf_event *group_event,
struct perf_cpu_context *cpuctx,
@@ -730,19 +691,15 @@ group_sched_in(struct perf_event *group_event,
{
struct perf_event *event, *partial_group = NULL;
struct pmu *pmu = group_event->pmu;
+ u64 now = ctx->time;
+ bool simulate = false;
if (group_event->state == PERF_EVENT_STATE_OFF)
return 0;
pmu->start_txn(pmu);
- /*
- * use __event_sched_in() to delay updating tstamp_running
- * until the transaction is committed. In case of failure
- * we will keep an unmodified tstamp_running which is a
- * requirement to get correct timing information
- */
- if (__event_sched_in(group_event, cpuctx, ctx)) {
+ if (event_sched_in(group_event, cpuctx, ctx)) {
pmu->cancel_txn(pmu);
return -EAGAIN;
}
@@ -751,31 +708,42 @@ group_sched_in(struct perf_event *group_event,
* Schedule in siblings as one group (if any):
*/
list_for_each_entry(event, &group_event->sibling_list, group_entry) {
- if (__event_sched_in(event, cpuctx, ctx)) {
+ if (event_sched_in(event, cpuctx, ctx)) {
partial_group = event;
goto group_error;
}
}
- if (!pmu->commit_txn(pmu)) {
- /* commit tstamp_running */
- group_commit_event_sched_in(group_event, cpuctx, ctx);
+ if (!pmu->commit_txn(pmu))
return 0;
- }
+
group_error:
/*
* Groups can be scheduled in as one unit only, so undo any
* partial group before returning:
+ * The events up to the failed event are scheduled out normally,
+ * tstamp_stopped will be updated.
*
- * use __event_sched_out() to avoid updating tstamp_stopped
- * because the event never actually ran
+ * The failed events and the remaining siblings need to have
+ * their timings updated as if they had gone thru event_sched_in()
+ * and event_sched_out(). This is required to get consistent timings
+ * across the group. This also takes care of the case where the group
+ * could never be scheduled by ensuring tstamp_stopped is set to mark
+ * the time the event was actually stopped, such that time delta
+ * calculation in update_event_times() is correct.
*/
list_for_each_entry(event, &group_event->sibling_list, group_entry) {
if (event == partial_group)
- break;
- __event_sched_out(event, cpuctx, ctx);
+ simulate = true;
+
+ if (simulate) {
+ event->tstamp_running += now - event->tstamp_stopped;
+ event->tstamp_stopped = now;
+ } else {
+ event_sched_out(event, cpuctx, ctx);
+ }
}
- __event_sched_out(group_event, cpuctx, ctx);
+ event_sched_out(group_event, cpuctx, ctx);
pmu->cancel_txn(pmu);
diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c
index a96b850ba08a..c7a8f453919e 100644
--- a/kernel/pm_qos_params.c
+++ b/kernel/pm_qos_params.c
@@ -399,7 +399,7 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
} else
return -EINVAL;
- pm_qos_req = (struct pm_qos_request_list *)filp->private_data;
+ pm_qos_req = filp->private_data;
pm_qos_update_request(pm_qos_req, value);
return count;
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index ac7eb109f196..0dac75ea4456 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -984,8 +984,8 @@ static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
src = kmap_atomic(s_page, KM_USER0);
dst = kmap_atomic(d_page, KM_USER1);
do_copy_page(dst, src);
- kunmap_atomic(src, KM_USER0);
kunmap_atomic(dst, KM_USER1);
+ kunmap_atomic(src, KM_USER0);
} else {
if (PageHighMem(d_page)) {
/* Page pointed to by src may contain some kernel
@@ -993,7 +993,7 @@ static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
*/
safe_copy_page(buffer, s_page);
dst = kmap_atomic(d_page, KM_USER0);
- memcpy(dst, buffer, PAGE_SIZE);
+ copy_page(dst, buffer);
kunmap_atomic(dst, KM_USER0);
} else {
safe_copy_page(page_address(d_page), s_page);
@@ -1687,7 +1687,7 @@ int snapshot_read_next(struct snapshot_handle *handle)
memory_bm_position_reset(&orig_bm);
memory_bm_position_reset(&copy_bm);
} else if (handle->cur <= nr_meta_pages) {
- memset(buffer, 0, PAGE_SIZE);
+ clear_page(buffer);
pack_pfns(buffer, &orig_bm);
} else {
struct page *page;
@@ -1701,7 +1701,7 @@ int snapshot_read_next(struct snapshot_handle *handle)
void *kaddr;
kaddr = kmap_atomic(page, KM_USER0);
- memcpy(buffer, kaddr, PAGE_SIZE);
+ copy_page(buffer, kaddr);
kunmap_atomic(kaddr, KM_USER0);
handle->buffer = buffer;
} else {
@@ -1984,7 +1984,7 @@ static void copy_last_highmem_page(void)
void *dst;
dst = kmap_atomic(last_highmem_page, KM_USER0);
- memcpy(dst, buffer, PAGE_SIZE);
+ copy_page(dst, buffer);
kunmap_atomic(dst, KM_USER0);
last_highmem_page = NULL;
}
@@ -2270,11 +2270,11 @@ swap_two_pages_data(struct page *p1, struct page *p2, void *buf)
kaddr1 = kmap_atomic(p1, KM_USER0);
kaddr2 = kmap_atomic(p2, KM_USER1);
- memcpy(buf, kaddr1, PAGE_SIZE);
- memcpy(kaddr1, kaddr2, PAGE_SIZE);
- memcpy(kaddr2, buf, PAGE_SIZE);
- kunmap_atomic(kaddr1, KM_USER0);
+ copy_page(buf, kaddr1);
+ copy_page(kaddr1, kaddr2);
+ copy_page(kaddr2, buf);
kunmap_atomic(kaddr2, KM_USER1);
+ kunmap_atomic(kaddr1, KM_USER0);
}
/**
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 916eaa790399..a0e4a86ccf94 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -251,7 +251,7 @@ static int write_page(void *buf, sector_t offset, struct bio **bio_chain)
if (bio_chain) {
src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
if (src) {
- memcpy(src, buf, PAGE_SIZE);
+ copy_page(src, buf);
} else {
WARN_ON_ONCE(1);
bio_chain = NULL; /* Go synchronous */
@@ -325,7 +325,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
error = write_page(handle->cur, handle->cur_swap, NULL);
if (error)
goto out;
- memset(handle->cur, 0, PAGE_SIZE);
+ clear_page(handle->cur);
handle->cur_swap = offset;
handle->k = 0;
}
@@ -910,7 +910,7 @@ int swsusp_check(void)
hib_resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
if (!IS_ERR(hib_resume_bdev)) {
set_blocksize(hib_resume_bdev, PAGE_SIZE);
- memset(swsusp_header, 0, PAGE_SIZE);
+ clear_page(swsusp_header);
error = hib_bio_read_page(swsusp_resume_block,
swsusp_header, NULL);
if (error)
diff --git a/kernel/printk.c b/kernel/printk.c
index 2531017795f6..b2ebaee8c377 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -210,7 +210,7 @@ __setup("log_buf_len=", log_buf_len_setup);
#ifdef CONFIG_BOOT_PRINTK_DELAY
-static unsigned int boot_delay; /* msecs delay after each printk during bootup */
+static int boot_delay; /* msecs delay after each printk during bootup */
static unsigned long long loops_per_msec; /* based on boot_delay */
static int __init boot_delay_setup(char *str)
@@ -647,6 +647,7 @@ static inline int can_use_console(unsigned int cpu)
* released but interrupts still disabled.
*/
static int acquire_console_semaphore_for_printk(unsigned int cpu)
+ __releases(&logbuf_lock)
{
int retval = 0;
@@ -1511,7 +1512,7 @@ int kmsg_dump_unregister(struct kmsg_dumper *dumper)
}
EXPORT_SYMBOL_GPL(kmsg_dump_unregister);
-static const char const *kmsg_reasons[] = {
+static const char * const kmsg_reasons[] = {
[KMSG_DUMP_OOPS] = "oops",
[KMSG_DUMP_PANIC] = "panic",
[KMSG_DUMP_KEXEC] = "kexec",
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index f34d798ef4a2..99bbaa3e5b0d 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -181,7 +181,7 @@ int ptrace_attach(struct task_struct *task)
* under ptrace.
*/
retval = -ERESTARTNOINTR;
- if (mutex_lock_interruptible(&task->cred_guard_mutex))
+ if (mutex_lock_interruptible(&task->signal->cred_guard_mutex))
goto out;
task_lock(task);
@@ -208,7 +208,7 @@ int ptrace_attach(struct task_struct *task)
unlock_tasklist:
write_unlock_irq(&tasklist_lock);
unlock_creds:
- mutex_unlock(&task->cred_guard_mutex);
+ mutex_unlock(&task->signal->cred_guard_mutex);
out:
return retval;
}
@@ -329,6 +329,8 @@ int ptrace_detach(struct task_struct *child, unsigned int data)
* and reacquire the lock.
*/
void exit_ptrace(struct task_struct *tracer)
+ __releases(&tasklist_lock)
+ __acquires(&tasklist_lock)
{
struct task_struct *p, *n;
LIST_HEAD(ptrace_dead);
@@ -402,7 +404,7 @@ int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long ds
return copied;
}
-static int ptrace_setoptions(struct task_struct *child, long data)
+static int ptrace_setoptions(struct task_struct *child, unsigned long data)
{
child->ptrace &= ~PT_TRACE_MASK;
@@ -481,7 +483,8 @@ static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info)
#define is_sysemu_singlestep(request) 0
#endif
-static int ptrace_resume(struct task_struct *child, long request, long data)
+static int ptrace_resume(struct task_struct *child, long request,
+ unsigned long data)
{
if (!valid_signal(data))
return -EIO;
@@ -558,10 +561,12 @@ static int ptrace_regset(struct task_struct *task, int req, unsigned int type,
#endif
int ptrace_request(struct task_struct *child, long request,
- long addr, long data)
+ unsigned long addr, unsigned long data)
{
int ret = -EIO;
siginfo_t siginfo;
+ void __user *datavp = (void __user *) data;
+ unsigned long __user *datalp = datavp;
switch (request) {
case PTRACE_PEEKTEXT:
@@ -578,19 +583,17 @@ int ptrace_request(struct task_struct *child, long request,
ret = ptrace_setoptions(child, data);
break;
case PTRACE_GETEVENTMSG:
- ret = put_user(child->ptrace_message, (unsigned long __user *) data);
+ ret = put_user(child->ptrace_message, datalp);
break;
case PTRACE_GETSIGINFO:
ret = ptrace_getsiginfo(child, &siginfo);
if (!ret)
- ret = copy_siginfo_to_user((siginfo_t __user *) data,
- &siginfo);
+ ret = copy_siginfo_to_user(datavp, &siginfo);
break;
case PTRACE_SETSIGINFO:
- if (copy_from_user(&siginfo, (siginfo_t __user *) data,
- sizeof siginfo))
+ if (copy_from_user(&siginfo, datavp, sizeof siginfo))
ret = -EFAULT;
else
ret = ptrace_setsiginfo(child, &siginfo);
@@ -621,7 +624,7 @@ int ptrace_request(struct task_struct *child, long request,
}
mmput(mm);
- ret = put_user(tmp, (unsigned long __user *) data);
+ ret = put_user(tmp, datalp);
break;
}
#endif
@@ -650,7 +653,7 @@ int ptrace_request(struct task_struct *child, long request,
case PTRACE_SETREGSET:
{
struct iovec kiov;
- struct iovec __user *uiov = (struct iovec __user *) data;
+ struct iovec __user *uiov = datavp;
if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov)))
return -EFAULT;
@@ -691,7 +694,8 @@ static struct task_struct *ptrace_get_task_struct(pid_t pid)
#define arch_ptrace_attach(child) do { } while (0)
#endif
-SYSCALL_DEFINE4(ptrace, long, request, long, pid, long, addr, long, data)
+SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
+ unsigned long, data)
{
struct task_struct *child;
long ret;
@@ -732,7 +736,8 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, long, addr, long, data)
return ret;
}
-int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data)
+int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr,
+ unsigned long data)
{
unsigned long tmp;
int copied;
@@ -743,7 +748,8 @@ int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data)
return put_user(tmp, (unsigned long __user *)data);
}
-int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data)
+int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr,
+ unsigned long data)
{
int copied;
diff --git a/kernel/resource.c b/kernel/resource.c
index 7b36976e5dea..9c9841cb6902 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -453,6 +453,8 @@ static struct resource * __insert_resource(struct resource *parent, struct resou
if (first == parent)
return first;
+ if (WARN_ON(first == new)) /* duplicated insertion */
+ return first;
if ((first->start > new->start) || (first->end < new->end))
break;
diff --git a/kernel/signal.c b/kernel/signal.c
index 919562c3d6b7..4e3cff10fdce 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1105,7 +1105,8 @@ int zap_other_threads(struct task_struct *p)
return count;
}
-struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long *flags)
+struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
+ unsigned long *flags)
{
struct sighand_struct *sighand;
@@ -1617,6 +1618,8 @@ static int sigkill_pending(struct task_struct *tsk)
* is gone, we keep current->exit_code unless clear_code.
*/
static void ptrace_stop(int exit_code, int clear_code, siginfo_t *info)
+ __releases(&current->sighand->siglock)
+ __acquires(&current->sighand->siglock)
{
if (arch_ptrace_stop_needed(exit_code, info)) {
/*
diff --git a/kernel/smp.c b/kernel/smp.c
index ed6aacfcb7ef..12ed8b013e2d 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -267,7 +267,7 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_single_data, csd_data);
*
* Returns 0 on success, else a negative status code.
*/
-int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
+int smp_call_function_single(int cpu, smp_call_func_t func, void *info,
int wait)
{
struct call_single_data d = {
@@ -336,7 +336,7 @@ EXPORT_SYMBOL(smp_call_function_single);
* 3) any other online cpu in @mask
*/
int smp_call_function_any(const struct cpumask *mask,
- void (*func)(void *info), void *info, int wait)
+ smp_call_func_t func, void *info, int wait)
{
unsigned int cpu;
const struct cpumask *nodemask;
@@ -416,7 +416,7 @@ void __smp_call_function_single(int cpu, struct call_single_data *data,
* must be disabled when calling this function.
*/
void smp_call_function_many(const struct cpumask *mask,
- void (*func)(void *), void *info, bool wait)
+ smp_call_func_t func, void *info, bool wait)
{
struct call_function_data *data;
unsigned long flags;
@@ -500,7 +500,7 @@ EXPORT_SYMBOL(smp_call_function_many);
* You must not call this function with disabled interrupts or from a
* hardware interrupt handler or from a bottom half handler.
*/
-int smp_call_function(void (*func)(void *), void *info, int wait)
+int smp_call_function(smp_call_func_t func, void *info, int wait)
{
preempt_disable();
smp_call_function_many(cpu_online_mask, func, info, wait);
diff --git a/kernel/softirq.c b/kernel/softirq.c
index fc978889b194..18f4be0d5fe0 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -67,7 +67,7 @@ char *softirq_to_name[NR_SOFTIRQS] = {
* to the pending events, so lets the scheduler to balance
* the softirq load for us.
*/
-void wakeup_softirqd(void)
+static void wakeup_softirqd(void)
{
/* Interrupts are disabled: no need to stop preemption */
struct task_struct *tsk = __get_cpu_var(ksoftirqd);
@@ -229,18 +229,20 @@ restart:
do {
if (pending & 1) {
+ unsigned int vec_nr = h - softirq_vec;
int prev_count = preempt_count();
- kstat_incr_softirqs_this_cpu(h - softirq_vec);
- trace_softirq_entry(h, softirq_vec);
+ kstat_incr_softirqs_this_cpu(vec_nr);
+
+ trace_softirq_entry(vec_nr);
h->action(h);
- trace_softirq_exit(h, softirq_vec);
+ trace_softirq_exit(vec_nr);
if (unlikely(prev_count != preempt_count())) {
- printk(KERN_ERR "huh, entered softirq %td %s %p"
+ printk(KERN_ERR "huh, entered softirq %u %s %p"
"with preempt_count %08x,"
- " exited with %08x?\n", h - softirq_vec,
- softirq_to_name[h - softirq_vec],
- h->action, prev_count, preempt_count());
+ " exited with %08x?\n", vec_nr,
+ softirq_to_name[vec_nr], h->action,
+ prev_count, preempt_count());
preempt_count() = prev_count;
}
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index 090c28812ce1..2df820b03beb 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -262,7 +262,7 @@ repeat:
cpu_stop_fn_t fn = work->fn;
void *arg = work->arg;
struct cpu_stop_done *done = work->done;
- char ksym_buf[KSYM_NAME_LEN];
+ char ksym_buf[KSYM_NAME_LEN] __maybe_unused;
__set_current_state(TASK_RUNNING);
@@ -304,7 +304,7 @@ static int __cpuinit cpu_stop_cpu_callback(struct notifier_block *nfb,
p = kthread_create(cpu_stopper_thread, stopper, "migration/%d",
cpu);
if (IS_ERR(p))
- return NOTIFY_BAD;
+ return notifier_from_errno(PTR_ERR(p));
get_task_struct(p);
kthread_bind(p, cpu);
sched_set_stop_task(cpu, p);
@@ -372,7 +372,7 @@ static int __init cpu_stop_init(void)
/* start one for the boot cpu */
err = cpu_stop_cpu_callback(&cpu_stop_cpu_notifier, CPU_UP_PREPARE,
bcpu);
- BUG_ON(err == NOTIFY_BAD);
+ BUG_ON(err != NOTIFY_OK);
cpu_stop_cpu_callback(&cpu_stop_cpu_notifier, CPU_ONLINE, bcpu);
register_cpu_notifier(&cpu_stop_cpu_notifier);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 3a45c224770f..c33a1edb799f 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -161,8 +161,6 @@ extern int no_unaligned_warning;
extern int unaligned_dump_stack;
#endif
-extern struct ratelimit_state printk_ratelimit_state;
-
#ifdef CONFIG_PROC_SYSCTL
static int proc_do_cad_pid(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos);
@@ -1340,28 +1338,28 @@ static struct ctl_table fs_table[] = {
.data = &inodes_stat,
.maxlen = 2*sizeof(int),
.mode = 0444,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_nr_inodes,
},
{
.procname = "inode-state",
.data = &inodes_stat,
.maxlen = 7*sizeof(int),
.mode = 0444,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_nr_inodes,
},
{
.procname = "file-nr",
.data = &files_stat,
- .maxlen = 3*sizeof(int),
+ .maxlen = sizeof(files_stat),
.mode = 0444,
.proc_handler = proc_nr_files,
},
{
.procname = "file-max",
.data = &files_stat.max_files,
- .maxlen = sizeof(int),
+ .maxlen = sizeof(files_stat.max_files),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_doulongvec_minmax,
},
{
.procname = "nr_open",
@@ -1377,7 +1375,7 @@ static struct ctl_table fs_table[] = {
.data = &dentry_stat,
.maxlen = 6*sizeof(int),
.mode = 0444,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_nr_dentry,
},
{
.procname = "overflowuid",
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 11281d5792bd..c8231fb15708 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -175,22 +175,8 @@ static void send_cpu_listeners(struct sk_buff *skb,
up_write(&listeners->sem);
}
-static int fill_pid(pid_t pid, struct task_struct *tsk,
- struct taskstats *stats)
+static void fill_stats(struct task_struct *tsk, struct taskstats *stats)
{
- int rc = 0;
-
- if (!tsk) {
- rcu_read_lock();
- tsk = find_task_by_vpid(pid);
- if (tsk)
- get_task_struct(tsk);
- rcu_read_unlock();
- if (!tsk)
- return -ESRCH;
- } else
- get_task_struct(tsk);
-
memset(stats, 0, sizeof(*stats));
/*
* Each accounting subsystem adds calls to its functions to
@@ -209,17 +195,27 @@ static int fill_pid(pid_t pid, struct task_struct *tsk,
/* fill in extended acct fields */
xacct_add_tsk(stats, tsk);
+}
- /* Define err: label here if needed */
- put_task_struct(tsk);
- return rc;
+static int fill_stats_for_pid(pid_t pid, struct taskstats *stats)
+{
+ struct task_struct *tsk;
+ rcu_read_lock();
+ tsk = find_task_by_vpid(pid);
+ if (tsk)
+ get_task_struct(tsk);
+ rcu_read_unlock();
+ if (!tsk)
+ return -ESRCH;
+ fill_stats(tsk, stats);
+ put_task_struct(tsk);
+ return 0;
}
-static int fill_tgid(pid_t tgid, struct task_struct *first,
- struct taskstats *stats)
+static int fill_stats_for_tgid(pid_t tgid, struct taskstats *stats)
{
- struct task_struct *tsk;
+ struct task_struct *tsk, *first;
unsigned long flags;
int rc = -ESRCH;
@@ -228,8 +224,7 @@ static int fill_tgid(pid_t tgid, struct task_struct *first,
* leaders who are already counted with the dead tasks
*/
rcu_read_lock();
- if (!first)
- first = find_task_by_vpid(tgid);
+ first = find_task_by_vpid(tgid);
if (!first || !lock_task_sighand(first, &flags))
goto out;
@@ -268,7 +263,6 @@ out:
return rc;
}
-
static void fill_tgid_exit(struct task_struct *tsk)
{
unsigned long flags;
@@ -360,6 +354,12 @@ static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid)
struct nlattr *na, *ret;
int aggr;
+ /* If we don't pad, we end up with alignment on a 4 byte boundary.
+ * This causes lots of runtime warnings on systems requiring 8 byte
+ * alignment */
+ u32 pids[2] = { pid, 0 };
+ int pid_size = ALIGN(sizeof(pid), sizeof(long));
+
aggr = (type == TASKSTATS_TYPE_PID)
? TASKSTATS_TYPE_AGGR_PID
: TASKSTATS_TYPE_AGGR_TGID;
@@ -367,7 +367,7 @@ static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid)
na = nla_nest_start(skb, aggr);
if (!na)
goto err;
- if (nla_put(skb, type, sizeof(pid), &pid) < 0)
+ if (nla_put(skb, type, pid_size, pids) < 0)
goto err;
ret = nla_reserve(skb, TASKSTATS_TYPE_STATS, sizeof(struct taskstats));
if (!ret)
@@ -424,39 +424,46 @@ err:
return rc;
}
-static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
+static int cmd_attr_register_cpumask(struct genl_info *info)
{
- int rc;
- struct sk_buff *rep_skb;
- struct taskstats *stats;
- size_t size;
cpumask_var_t mask;
+ int rc;
if (!alloc_cpumask_var(&mask, GFP_KERNEL))
return -ENOMEM;
-
rc = parse(info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK], mask);
if (rc < 0)
- goto free_return_rc;
- if (rc == 0) {
- rc = add_del_listener(info->snd_pid, mask, REGISTER);
- goto free_return_rc;
- }
+ goto out;
+ rc = add_del_listener(info->snd_pid, mask, REGISTER);
+out:
+ free_cpumask_var(mask);
+ return rc;
+}
+
+static int cmd_attr_deregister_cpumask(struct genl_info *info)
+{
+ cpumask_var_t mask;
+ int rc;
+ if (!alloc_cpumask_var(&mask, GFP_KERNEL))
+ return -ENOMEM;
rc = parse(info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK], mask);
if (rc < 0)
- goto free_return_rc;
- if (rc == 0) {
- rc = add_del_listener(info->snd_pid, mask, DEREGISTER);
-free_return_rc:
- free_cpumask_var(mask);
- return rc;
- }
+ goto out;
+ rc = add_del_listener(info->snd_pid, mask, DEREGISTER);
+out:
free_cpumask_var(mask);
+ return rc;
+}
+
+static int cmd_attr_pid(struct genl_info *info)
+{
+ struct taskstats *stats;
+ struct sk_buff *rep_skb;
+ size_t size;
+ u32 pid;
+ int rc;
- /*
- * Size includes space for nested attributes
- */
size = nla_total_size(sizeof(u32)) +
nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
@@ -465,33 +472,64 @@ free_return_rc:
return rc;
rc = -EINVAL;
- if (info->attrs[TASKSTATS_CMD_ATTR_PID]) {
- u32 pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]);
- stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, pid);
- if (!stats)
- goto err;
-
- rc = fill_pid(pid, NULL, stats);
- if (rc < 0)
- goto err;
- } else if (info->attrs[TASKSTATS_CMD_ATTR_TGID]) {
- u32 tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]);
- stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tgid);
- if (!stats)
- goto err;
-
- rc = fill_tgid(tgid, NULL, stats);
- if (rc < 0)
- goto err;
- } else
+ pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]);
+ stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, pid);
+ if (!stats)
+ goto err;
+
+ rc = fill_stats_for_pid(pid, stats);
+ if (rc < 0)
+ goto err;
+ return send_reply(rep_skb, info);
+err:
+ nlmsg_free(rep_skb);
+ return rc;
+}
+
+static int cmd_attr_tgid(struct genl_info *info)
+{
+ struct taskstats *stats;
+ struct sk_buff *rep_skb;
+ size_t size;
+ u32 tgid;
+ int rc;
+
+ size = nla_total_size(sizeof(u32)) +
+ nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
+
+ rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size);
+ if (rc < 0)
+ return rc;
+
+ rc = -EINVAL;
+ tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]);
+ stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tgid);
+ if (!stats)
goto err;
+ rc = fill_stats_for_tgid(tgid, stats);
+ if (rc < 0)
+ goto err;
return send_reply(rep_skb, info);
err:
nlmsg_free(rep_skb);
return rc;
}
+static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
+{
+ if (info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK])
+ return cmd_attr_register_cpumask(info);
+ else if (info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK])
+ return cmd_attr_deregister_cpumask(info);
+ else if (info->attrs[TASKSTATS_CMD_ATTR_PID])
+ return cmd_attr_pid(info);
+ else if (info->attrs[TASKSTATS_CMD_ATTR_TGID])
+ return cmd_attr_tgid(info);
+ else
+ return -EINVAL;
+}
+
static struct taskstats *taskstats_tgid_alloc(struct task_struct *tsk)
{
struct signal_struct *sig = tsk->signal;
@@ -555,9 +593,7 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
if (!stats)
goto err;
- rc = fill_pid(-1, tsk, stats);
- if (rc < 0)
- goto err;
+ fill_stats(tsk, stats);
/*
* Doesn't matter if tsk is the leader or the last group member leaving
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index c3dab054d18e..9ed509a015d8 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -224,6 +224,9 @@ enum {
RB_LEN_TIME_STAMP = 16,
};
+#define skip_time_extend(event) \
+ ((struct ring_buffer_event *)((char *)event + RB_LEN_TIME_EXTEND))
+
static inline int rb_null_event(struct ring_buffer_event *event)
{
return event->type_len == RINGBUF_TYPE_PADDING && !event->time_delta;
@@ -248,8 +251,12 @@ rb_event_data_length(struct ring_buffer_event *event)
return length + RB_EVNT_HDR_SIZE;
}
-/* inline for ring buffer fast paths */
-static unsigned
+/*
+ * Return the length of the given event. Will return
+ * the length of the time extend if the event is a
+ * time extend.
+ */
+static inline unsigned
rb_event_length(struct ring_buffer_event *event)
{
switch (event->type_len) {
@@ -274,13 +281,41 @@ rb_event_length(struct ring_buffer_event *event)
return 0;
}
+/*
+ * Return total length of time extend and data,
+ * or just the event length for all other events.
+ */
+static inline unsigned
+rb_event_ts_length(struct ring_buffer_event *event)
+{
+ unsigned len = 0;
+
+ if (event->type_len == RINGBUF_TYPE_TIME_EXTEND) {
+ /* time extends include the data event after it */
+ len = RB_LEN_TIME_EXTEND;
+ event = skip_time_extend(event);
+ }
+ return len + rb_event_length(event);
+}
+
/**
* ring_buffer_event_length - return the length of the event
* @event: the event to get the length of
+ *
+ * Returns the size of the data load of a data event.
+ * If the event is something other than a data event, it
+ * returns the size of the event itself. With the exception
+ * of a TIME EXTEND, where it still returns the size of the
+ * data load of the data event after it.
*/
unsigned ring_buffer_event_length(struct ring_buffer_event *event)
{
- unsigned length = rb_event_length(event);
+ unsigned length;
+
+ if (event->type_len == RINGBUF_TYPE_TIME_EXTEND)
+ event = skip_time_extend(event);
+
+ length = rb_event_length(event);
if (event->type_len > RINGBUF_TYPE_DATA_TYPE_LEN_MAX)
return length;
length -= RB_EVNT_HDR_SIZE;
@@ -294,6 +329,8 @@ EXPORT_SYMBOL_GPL(ring_buffer_event_length);
static void *
rb_event_data(struct ring_buffer_event *event)
{
+ if (event->type_len == RINGBUF_TYPE_TIME_EXTEND)
+ event = skip_time_extend(event);
BUG_ON(event->type_len > RINGBUF_TYPE_DATA_TYPE_LEN_MAX);
/* If length is in len field, then array[0] has the data */
if (event->type_len)
@@ -404,9 +441,6 @@ static inline int test_time_stamp(u64 delta)
/* Max payload is BUF_PAGE_SIZE - header (8bytes) */
#define BUF_MAX_DATA_SIZE (BUF_PAGE_SIZE - (sizeof(u32) * 2))
-/* Max number of timestamps that can fit on a page */
-#define RB_TIMESTAMPS_PER_PAGE (BUF_PAGE_SIZE / RB_LEN_TIME_EXTEND)
-
int ring_buffer_print_page_header(struct trace_seq *s)
{
struct buffer_data_page field;
@@ -1546,6 +1580,25 @@ static void rb_inc_iter(struct ring_buffer_iter *iter)
iter->head = 0;
}
+/* Slow path, do not inline */
+static noinline struct ring_buffer_event *
+rb_add_time_stamp(struct ring_buffer_event *event, u64 delta)
+{
+ event->type_len = RINGBUF_TYPE_TIME_EXTEND;
+
+ /* Not the first event on the page? */
+ if (rb_event_index(event)) {
+ event->time_delta = delta & TS_MASK;
+ event->array[0] = delta >> TS_SHIFT;
+ } else {
+ /* nope, just zero it */
+ event->time_delta = 0;
+ event->array[0] = 0;
+ }
+
+ return skip_time_extend(event);
+}
+
/**
* ring_buffer_update_event - update event type and data
* @event: the even to update
@@ -1558,28 +1611,31 @@ static void rb_inc_iter(struct ring_buffer_iter *iter)
* data field.
*/
static void
-rb_update_event(struct ring_buffer_event *event,
- unsigned type, unsigned length)
+rb_update_event(struct ring_buffer_per_cpu *cpu_buffer,
+ struct ring_buffer_event *event, unsigned length,
+ int add_timestamp, u64 delta)
{
- event->type_len = type;
-
- switch (type) {
-
- case RINGBUF_TYPE_PADDING:
- case RINGBUF_TYPE_TIME_EXTEND:
- case RINGBUF_TYPE_TIME_STAMP:
- break;
+ /* Only a commit updates the timestamp */
+ if (unlikely(!rb_event_is_commit(cpu_buffer, event)))
+ delta = 0;
- case 0:
- length -= RB_EVNT_HDR_SIZE;
- if (length > RB_MAX_SMALL_DATA || RB_FORCE_8BYTE_ALIGNMENT)
- event->array[0] = length;
- else
- event->type_len = DIV_ROUND_UP(length, RB_ALIGNMENT);
- break;
- default:
- BUG();
+ /*
+ * If we need to add a timestamp, then we
+ * add it to the start of the resevered space.
+ */
+ if (unlikely(add_timestamp)) {
+ event = rb_add_time_stamp(event, delta);
+ length -= RB_LEN_TIME_EXTEND;
+ delta = 0;
}
+
+ event->time_delta = delta;
+ length -= RB_EVNT_HDR_SIZE;
+ if (length > RB_MAX_SMALL_DATA || RB_FORCE_8BYTE_ALIGNMENT) {
+ event->type_len = 0;
+ event->array[0] = length;
+ } else
+ event->type_len = DIV_ROUND_UP(length, RB_ALIGNMENT);
}
/*
@@ -1823,10 +1879,13 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer,
local_sub(length, &tail_page->write);
}
-static struct ring_buffer_event *
+/*
+ * This is the slow path, force gcc not to inline it.
+ */
+static noinline struct ring_buffer_event *
rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer,
unsigned long length, unsigned long tail,
- struct buffer_page *tail_page, u64 *ts)
+ struct buffer_page *tail_page, u64 ts)
{
struct buffer_page *commit_page = cpu_buffer->commit_page;
struct ring_buffer *buffer = cpu_buffer->buffer;
@@ -1909,8 +1968,8 @@ rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer,
* Nested commits always have zero deltas, so
* just reread the time stamp
*/
- *ts = rb_time_stamp(buffer);
- next_page->page->time_stamp = *ts;
+ ts = rb_time_stamp(buffer);
+ next_page->page->time_stamp = ts;
}
out_again:
@@ -1929,12 +1988,21 @@ rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer,
static struct ring_buffer_event *
__rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
- unsigned type, unsigned long length, u64 *ts)
+ unsigned long length, u64 ts,
+ u64 delta, int add_timestamp)
{
struct buffer_page *tail_page;
struct ring_buffer_event *event;
unsigned long tail, write;
+ /*
+ * If the time delta since the last event is too big to
+ * hold in the time field of the event, then we append a
+ * TIME EXTEND event ahead of the data event.
+ */
+ if (unlikely(add_timestamp))
+ length += RB_LEN_TIME_EXTEND;
+
tail_page = cpu_buffer->tail_page;
write = local_add_return(length, &tail_page->write);
@@ -1943,7 +2011,7 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
tail = write - length;
/* See if we shot pass the end of this buffer page */
- if (write > BUF_PAGE_SIZE)
+ if (unlikely(write > BUF_PAGE_SIZE))
return rb_move_tail(cpu_buffer, length, tail,
tail_page, ts);
@@ -1951,18 +2019,16 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
event = __rb_page_index(tail_page, tail);
kmemcheck_annotate_bitfield(event, bitfield);
- rb_update_event(event, type, length);
+ rb_update_event(cpu_buffer, event, length, add_timestamp, delta);
- /* The passed in type is zero for DATA */
- if (likely(!type))
- local_inc(&tail_page->entries);
+ local_inc(&tail_page->entries);
/*
* If this is the first commit on the page, then update
* its timestamp.
*/
if (!tail)
- tail_page->page->time_stamp = *ts;
+ tail_page->page->time_stamp = ts;
return event;
}
@@ -1977,7 +2043,7 @@ rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer,
unsigned long addr;
new_index = rb_event_index(event);
- old_index = new_index + rb_event_length(event);
+ old_index = new_index + rb_event_ts_length(event);
addr = (unsigned long)event;
addr &= PAGE_MASK;
@@ -2003,76 +2069,13 @@ rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer,
return 0;
}
-static int
-rb_add_time_stamp(struct ring_buffer_per_cpu *cpu_buffer,
- u64 *ts, u64 *delta)
-{
- struct ring_buffer_event *event;
- int ret;
-
- WARN_ONCE(*delta > (1ULL << 59),
- KERN_WARNING "Delta way too big! %llu ts=%llu write stamp = %llu\n",
- (unsigned long long)*delta,
- (unsigned long long)*ts,
- (unsigned long long)cpu_buffer->write_stamp);
-
- /*
- * The delta is too big, we to add a
- * new timestamp.
- */
- event = __rb_reserve_next(cpu_buffer,
- RINGBUF_TYPE_TIME_EXTEND,
- RB_LEN_TIME_EXTEND,
- ts);
- if (!event)
- return -EBUSY;
-
- if (PTR_ERR(event) == -EAGAIN)
- return -EAGAIN;
-
- /* Only a commited time event can update the write stamp */
- if (rb_event_is_commit(cpu_buffer, event)) {
- /*
- * If this is the first on the page, then it was
- * updated with the page itself. Try to discard it
- * and if we can't just make it zero.
- */
- if (rb_event_index(event)) {
- event->time_delta = *delta & TS_MASK;
- event->array[0] = *delta >> TS_SHIFT;
- } else {
- /* try to discard, since we do not need this */
- if (!rb_try_to_discard(cpu_buffer, event)) {
- /* nope, just zero it */
- event->time_delta = 0;
- event->array[0] = 0;
- }
- }
- cpu_buffer->write_stamp = *ts;
- /* let the caller know this was the commit */
- ret = 1;
- } else {
- /* Try to discard the event */
- if (!rb_try_to_discard(cpu_buffer, event)) {
- /* Darn, this is just wasted space */
- event->time_delta = 0;
- event->array[0] = 0;
- }
- ret = 0;
- }
-
- *delta = 0;
-
- return ret;
-}
-
static void rb_start_commit(struct ring_buffer_per_cpu *cpu_buffer)
{
local_inc(&cpu_buffer->committing);
local_inc(&cpu_buffer->commits);
}
-static void rb_end_commit(struct ring_buffer_per_cpu *cpu_buffer)
+static inline void rb_end_commit(struct ring_buffer_per_cpu *cpu_buffer)
{
unsigned long commits;
@@ -2110,9 +2113,10 @@ rb_reserve_next_event(struct ring_buffer *buffer,
unsigned long length)
{
struct ring_buffer_event *event;
- u64 ts, delta = 0;
- int commit = 0;
+ u64 ts, delta;
int nr_loops = 0;
+ int add_timestamp;
+ u64 diff;
rb_start_commit(cpu_buffer);
@@ -2133,6 +2137,9 @@ rb_reserve_next_event(struct ring_buffer *buffer,
length = rb_calculate_event_length(length);
again:
+ add_timestamp = 0;
+ delta = 0;
+
/*
* We allow for interrupts to reenter here and do a trace.
* If one does, it will cause this original code to loop
@@ -2146,56 +2153,32 @@ rb_reserve_next_event(struct ring_buffer *buffer,
goto out_fail;
ts = rb_time_stamp(cpu_buffer->buffer);
+ diff = ts - cpu_buffer->write_stamp;
- /*
- * Only the first commit can update the timestamp.
- * Yes there is a race here. If an interrupt comes in
- * just after the conditional and it traces too, then it
- * will also check the deltas. More than one timestamp may
- * also be made. But only the entry that did the actual
- * commit will be something other than zero.
- */
- if (likely(cpu_buffer->tail_page == cpu_buffer->commit_page &&
- rb_page_write(cpu_buffer->tail_page) ==
- rb_commit_index(cpu_buffer))) {
- u64 diff;
-
- diff = ts - cpu_buffer->write_stamp;
-
- /* make sure this diff is calculated here */
- barrier();
-
- /* Did the write stamp get updated already? */
- if (unlikely(ts < cpu_buffer->write_stamp))
- goto get_event;
+ /* make sure this diff is calculated here */
+ barrier();
+ /* Did the write stamp get updated already? */
+ if (likely(ts >= cpu_buffer->write_stamp)) {
delta = diff;
if (unlikely(test_time_stamp(delta))) {
-
- commit = rb_add_time_stamp(cpu_buffer, &ts, &delta);
- if (commit == -EBUSY)
- goto out_fail;
-
- if (commit == -EAGAIN)
- goto again;
-
- RB_WARN_ON(cpu_buffer, commit < 0);
+ WARN_ONCE(delta > (1ULL << 59),
+ KERN_WARNING "Delta way too big! %llu ts=%llu write stamp = %llu\n",
+ (unsigned long long)delta,
+ (unsigned long long)ts,
+ (unsigned long long)cpu_buffer->write_stamp);
+ add_timestamp = 1;
}
}
- get_event:
- event = __rb_reserve_next(cpu_buffer, 0, length, &ts);
+ event = __rb_reserve_next(cpu_buffer, length, ts,
+ delta, add_timestamp);
if (unlikely(PTR_ERR(event) == -EAGAIN))
goto again;
if (!event)
goto out_fail;
- if (!rb_event_is_commit(cpu_buffer, event))
- delta = 0;
-
- event->time_delta = delta;
-
return event;
out_fail:
@@ -2207,13 +2190,9 @@ rb_reserve_next_event(struct ring_buffer *buffer,
#define TRACE_RECURSIVE_DEPTH 16
-static int trace_recursive_lock(void)
+/* Keep this code out of the fast path cache */
+static noinline void trace_recursive_fail(void)
{
- current->trace_recursion++;
-
- if (likely(current->trace_recursion < TRACE_RECURSIVE_DEPTH))
- return 0;
-
/* Disable all tracing before we do anything else */
tracing_off_permanent();
@@ -2225,10 +2204,21 @@ static int trace_recursive_lock(void)
in_nmi());
WARN_ON_ONCE(1);
+}
+
+static inline int trace_recursive_lock(void)
+{
+ current->trace_recursion++;
+
+ if (likely(current->trace_recursion < TRACE_RECURSIVE_DEPTH))
+ return 0;
+
+ trace_recursive_fail();
+
return -1;
}
-static void trace_recursive_unlock(void)
+static inline void trace_recursive_unlock(void)
{
WARN_ON_ONCE(!current->trace_recursion);
@@ -2308,12 +2298,28 @@ static void
rb_update_write_stamp(struct ring_buffer_per_cpu *cpu_buffer,
struct ring_buffer_event *event)
{
+ u64 delta;
+
/*
* The event first in the commit queue updates the
* time stamp.
*/
- if (rb_event_is_commit(cpu_buffer, event))
- cpu_buffer->write_stamp += event->time_delta;
+ if (rb_event_is_commit(cpu_buffer, event)) {
+ /*
+ * A commit event that is first on a page
+ * updates the write timestamp with the page stamp
+ */
+ if (!rb_event_index(event))
+ cpu_buffer->write_stamp =
+ cpu_buffer->commit_page->page->time_stamp;
+ else if (event->type_len == RINGBUF_TYPE_TIME_EXTEND) {
+ delta = event->array[0];
+ delta <<= TS_SHIFT;
+ delta += event->time_delta;
+ cpu_buffer->write_stamp += delta;
+ } else
+ cpu_buffer->write_stamp += event->time_delta;
+ }
}
static void rb_commit(struct ring_buffer_per_cpu *cpu_buffer,
@@ -2353,6 +2359,9 @@ EXPORT_SYMBOL_GPL(ring_buffer_unlock_commit);
static inline void rb_event_discard(struct ring_buffer_event *event)
{
+ if (event->type_len == RINGBUF_TYPE_TIME_EXTEND)
+ event = skip_time_extend(event);
+
/* array[0] holds the actual length for the discarded event */
event->array[0] = rb_event_data_length(event) - RB_EVNT_HDR_SIZE;
event->type_len = RINGBUF_TYPE_PADDING;
@@ -3049,12 +3058,12 @@ rb_buffer_peek(struct ring_buffer_per_cpu *cpu_buffer, u64 *ts,
again:
/*
- * We repeat when a timestamp is encountered. It is possible
- * to get multiple timestamps from an interrupt entering just
- * as one timestamp is about to be written, or from discarded
- * commits. The most that we can have is the number on a single page.
+ * We repeat when a time extend is encountered.
+ * Since the time extend is always attached to a data event,
+ * we should never loop more than once.
+ * (We never hit the following condition more than twice).
*/
- if (RB_WARN_ON(cpu_buffer, ++nr_loops > RB_TIMESTAMPS_PER_PAGE))
+ if (RB_WARN_ON(cpu_buffer, ++nr_loops > 2))
return NULL;
reader = rb_get_reader_page(cpu_buffer);
@@ -3130,14 +3139,12 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
return NULL;
/*
- * We repeat when a timestamp is encountered.
- * We can get multiple timestamps by nested interrupts or also
- * if filtering is on (discarding commits). Since discarding
- * commits can be frequent we can get a lot of timestamps.
- * But we limit them by not adding timestamps if they begin
- * at the start of a page.
+ * We repeat when a time extend is encountered.
+ * Since the time extend is always attached to a data event,
+ * we should never loop more than once.
+ * (We never hit the following condition more than twice).
*/
- if (RB_WARN_ON(cpu_buffer, ++nr_loops > RB_TIMESTAMPS_PER_PAGE))
+ if (RB_WARN_ON(cpu_buffer, ++nr_loops > 2))
return NULL;
if (rb_per_cpu_empty(cpu_buffer))
@@ -3835,7 +3842,8 @@ int ring_buffer_read_page(struct ring_buffer *buffer,
if (len > (commit - read))
len = (commit - read);
- size = rb_event_length(event);
+ /* Always keep the time extend and data together */
+ size = rb_event_ts_length(event);
if (len < size)
goto out_unlock;
@@ -3857,7 +3865,8 @@ int ring_buffer_read_page(struct ring_buffer *buffer,
break;
event = rb_reader_event(cpu_buffer);
- size = rb_event_length(event);
+ /* Always keep the time extend and data together */
+ size = rb_event_ts_length(event);
} while (len > size);
/* update bpage */
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 001bcd2ccf4a..82d9b8106cd0 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -3996,13 +3996,9 @@ static void tracing_init_debugfs_percpu(long cpu)
{
struct dentry *d_percpu = tracing_dentry_percpu();
struct dentry *d_cpu;
- /* strlen(cpu) + MAX(log10(cpu)) + '\0' */
- char cpu_dir[7];
+ char cpu_dir[30]; /* 30 characters should be more than enough */
- if (cpu > 999 || cpu < 0)
- return;
-
- sprintf(cpu_dir, "cpu%ld", cpu);
+ snprintf(cpu_dir, 30, "cpu%ld", cpu);
d_cpu = debugfs_create_dir(cpu_dir, d_percpu);
if (!d_cpu) {
pr_warning("Could not create debugfs '%s' entry\n", cpu_dir);
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 544301d29dee..2dec9bcde8b4 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -31,7 +31,6 @@
#include <linux/perf_event.h>
#include <linux/stringify.h>
#include <linux/limits.h>
-#include <linux/uaccess.h>
#include <asm/bitsperlong.h>
#include "trace.h"
@@ -648,7 +647,7 @@ static int register_trace_probe(struct trace_probe *tp)
}
ret = register_probe_event(tp);
if (ret) {
- pr_warning("Faild to register probe event(%d)\n", ret);
+ pr_warning("Failed to register probe event(%d)\n", ret);
goto end;
}
diff --git a/kernel/tsacct.c b/kernel/tsacct.c
index 0a67e041edf8..24dc60d9fa1f 100644
--- a/kernel/tsacct.c
+++ b/kernel/tsacct.c
@@ -63,12 +63,10 @@ void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk)
stats->ac_ppid = pid_alive(tsk) ?
rcu_dereference(tsk->real_parent)->tgid : 0;
rcu_read_unlock();
- stats->ac_utime = cputime_to_msecs(tsk->utime) * USEC_PER_MSEC;
- stats->ac_stime = cputime_to_msecs(tsk->stime) * USEC_PER_MSEC;
- stats->ac_utimescaled =
- cputime_to_msecs(tsk->utimescaled) * USEC_PER_MSEC;
- stats->ac_stimescaled =
- cputime_to_msecs(tsk->stimescaled) * USEC_PER_MSEC;
+ stats->ac_utime = cputime_to_usecs(tsk->utime);
+ stats->ac_stime = cputime_to_usecs(tsk->stime);
+ stats->ac_utimescaled = cputime_to_usecs(tsk->utimescaled);
+ stats->ac_stimescaled = cputime_to_usecs(tsk->stimescaled);
stats->ac_minflt = tsk->min_flt;
stats->ac_majflt = tsk->maj_flt;
diff --git a/kernel/user.c b/kernel/user.c
index 7e72614b736d..2c7d8d5914b1 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -91,6 +91,7 @@ static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
* upon function exit.
*/
static void free_user(struct user_struct *up, unsigned long flags)
+ __releases(&uidhash_lock)
{
uid_hash_remove(up);
spin_unlock_irqrestore(&uidhash_lock, flags);
diff --git a/kernel/wait.c b/kernel/wait.c
index c4bd3d825f35..b0310eb6cc1e 100644
--- a/kernel/wait.c
+++ b/kernel/wait.c
@@ -92,7 +92,7 @@ prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
}
EXPORT_SYMBOL(prepare_to_wait_exclusive);
-/*
+/**
* finish_wait - clean up after waiting in a queue
* @q: waitqueue waited on
* @wait: wait descriptor
@@ -127,11 +127,11 @@ void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
}
EXPORT_SYMBOL(finish_wait);
-/*
+/**
* abort_exclusive_wait - abort exclusive waiting in a queue
* @q: waitqueue waited on
* @wait: wait descriptor
- * @state: runstate of the waiter to be woken
+ * @mode: runstate of the waiter to be woken
* @key: key to identify a wait bit queue or %NULL
*
* Sets current thread back to running state and removes
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 30acdb74cc23..90db1bd1a978 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -2064,7 +2064,7 @@ static void insert_wq_barrier(struct cpu_workqueue_struct *cwq,
* checks and call back into the fixup functions where we
* might deadlock.
*/
- INIT_WORK_ON_STACK(&barr->work, wq_barrier_func);
+ INIT_WORK_ONSTACK(&barr->work, wq_barrier_func);
__set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(&barr->work));
init_completion(&barr->done);
@@ -2791,7 +2791,9 @@ static int alloc_cwqs(struct workqueue_struct *wq)
}
}
- /* just in case, make sure it's actually aligned */
+ /* just in case, make sure it's actually aligned
+ * - this is affected by PERCPU() alignment in vmlinux.lds.S
+ */
BUG_ON(!IS_ALIGNED(wq->cpu_wq.v, align));
return wq->cpu_wq.v ? 0 : -ENOMEM;
}
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 7b2a8ca97ada..28b42b9274d0 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -317,6 +317,14 @@ config DEBUG_OBJECTS_RCU_HEAD
help
Enable this to turn on debugging of RCU list heads (call_rcu() usage).
+config DEBUG_OBJECTS_PERCPU_COUNTER
+ bool "Debug percpu counter objects"
+ depends on DEBUG_OBJECTS
+ help
+ If you say Y here, additional code will be inserted into the
+ percpu counter routines to track the life time of percpu counter
+ objects and validate the percpu counter operations.
+
config DEBUG_OBJECTS_ENABLE_DEFAULT
int "debug_objects bootup default value (0-1)"
range 0 1
@@ -353,7 +361,7 @@ config SLUB_DEBUG_ON
config SLUB_STATS
default n
bool "Enable SLUB performance statistics"
- depends on SLUB && SLUB_DEBUG && SYSFS
+ depends on SLUB && SYSFS
help
SLUB statistics are useful to debug SLUBs allocation behavior in
order find ways to optimize the allocator. This should never be
@@ -366,7 +374,7 @@ config SLUB_STATS
config DEBUG_KMEMLEAK
bool "Kernel memory leak detector"
depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \
- (X86 || ARM || PPC || S390 || SPARC64 || SUPERH || MICROBLAZE)
+ (X86 || ARM || PPC || S390 || SPARC64 || SUPERH || MICROBLAZE || TILE)
select DEBUG_FS if SYSFS
select STACKTRACE if STACKTRACE_SUPPORT
@@ -740,6 +748,15 @@ config DEBUG_LIST
If unsure, say N.
+config TEST_LIST_SORT
+ bool "Linked list sorting test"
+ depends on DEBUG_KERNEL
+ help
+ Enable this to turn on 'list_sort()' function test. This test is
+ executed only once during system boot, so affects only boot time.
+
+ If unsure, say N.
+
config DEBUG_SG
bool "Debug SG table operations"
depends on DEBUG_KERNEL
@@ -1200,6 +1217,19 @@ config ATOMIC64_SELFTEST
If unsure, say N.
+config ASYNC_RAID6_TEST
+ tristate "Self test for hardware accelerated raid6 recovery"
+ depends on ASYNC_RAID6_RECOV
+ select ASYNC_MEMCPY
+ ---help---
+ This is a one-shot self test that permutes through the
+ recovery of all the possible two disk failure scenarios for a
+ N-disk array. Recovery is performed with the asynchronous
+ raid6 recovery routines, and will optionally use an offload
+ engine if one is available.
+
+ If unsure, say N.
+
source "samples/Kconfig"
source "lib/Kconfig.kgdb"
diff --git a/lib/bitmap.c b/lib/bitmap.c
index ffb78c916ccd..741fae905ae3 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -359,7 +359,6 @@ EXPORT_SYMBOL(bitmap_find_next_zero_area);
#define CHUNKSZ 32
#define nbits_to_hold_value(val) fls(val)
-#define unhex(c) (isdigit(c) ? (c - '0') : (toupper(c) - 'A' + 10))
#define BASEDEC 10 /* fancier cpuset lists input in decimal */
/**
@@ -466,7 +465,7 @@ int __bitmap_parse(const char *buf, unsigned int buflen,
if (chunk & ~((1UL << (CHUNKSZ - 4)) - 1))
return -EOVERFLOW;
- chunk = (chunk << 4) | unhex(c);
+ chunk = (chunk << 4) | hex_to_bin(c);
ndigits++; totaldigits++;
}
if (ndigits == 0)
diff --git a/lib/div64.c b/lib/div64.c
index a111eb8de9cf..5b4919191778 100644
--- a/lib/div64.c
+++ b/lib/div64.c
@@ -77,26 +77,58 @@ s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
EXPORT_SYMBOL(div_s64_rem);
#endif
-/* 64bit divisor, dividend and result. dynamic precision */
+/**
+ * div64_u64 - unsigned 64bit divide with 64bit divisor
+ * @dividend: 64bit dividend
+ * @divisor: 64bit divisor
+ *
+ * This implementation is a modified version of the algorithm proposed
+ * by the book 'Hacker's Delight'. The original source and full proof
+ * can be found here and is available for use without restriction.
+ *
+ * 'http://www.hackersdelight.org/HDcode/newCode/divDouble.c'
+ */
#ifndef div64_u64
u64 div64_u64(u64 dividend, u64 divisor)
{
- u32 high, d;
+ u32 high = divisor >> 32;
+ u64 quot;
- high = divisor >> 32;
- if (high) {
- unsigned int shift = fls(high);
+ if (high == 0) {
+ quot = div_u64(dividend, divisor);
+ } else {
+ int n = 1 + fls(high);
+ quot = div_u64(dividend >> n, divisor >> n);
- d = divisor >> shift;
- dividend >>= shift;
- } else
- d = divisor;
+ if (quot != 0)
+ quot--;
+ if ((dividend - quot * divisor) >= divisor)
+ quot++;
+ }
- return div_u64(dividend, d);
+ return quot;
}
EXPORT_SYMBOL(div64_u64);
#endif
+/**
+ * div64_s64 - signed 64bit divide with 64bit divisor
+ * @dividend: 64bit dividend
+ * @divisor: 64bit divisor
+ */
+#ifndef div64_s64
+s64 div64_s64(s64 dividend, s64 divisor)
+{
+ s64 quot, t;
+
+ quot = div64_u64(abs64(dividend), abs64(divisor));
+ t = (dividend ^ divisor) >> 63;
+
+ return (quot ^ t) - t;
+}
+EXPORT_SYMBOL(div64_s64);
+#endif
+
#endif /* BITS_PER_LONG == 32 */
/*
diff --git a/lib/idr.c b/lib/idr.c
index 7f1a4f0acf50..e15502e8b21e 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -106,16 +106,17 @@ static void idr_mark_full(struct idr_layer **pa, int id)
}
/**
- * idr_pre_get - reserver resources for idr allocation
+ * idr_pre_get - reserve resources for idr allocation
* @idp: idr handle
* @gfp_mask: memory allocation flags
*
- * This function should be called prior to locking and calling the
- * idr_get_new* functions. It preallocates enough memory to satisfy
- * the worst possible allocation.
+ * This function should be called prior to calling the idr_get_new* functions.
+ * It preallocates enough memory to satisfy the worst possible allocation. The
+ * caller should pass in GFP_KERNEL if possible. This of course requires that
+ * no spinning locks be held.
*
- * If the system is REALLY out of memory this function returns 0,
- * otherwise 1.
+ * If the system is REALLY out of memory this function returns %0,
+ * otherwise %1.
*/
int idr_pre_get(struct idr *idp, gfp_t gfp_mask)
{
@@ -284,17 +285,19 @@ static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
* idr_get_new_above - allocate new idr entry above or equal to a start id
* @idp: idr handle
* @ptr: pointer you want associated with the id
- * @start_id: id to start search at
+ * @starting_id: id to start search at
* @id: pointer to the allocated handle
*
* This is the allocate id function. It should be called with any
* required locks.
*
- * If memory is required, it will return -EAGAIN, you should unlock
- * and go back to the idr_pre_get() call. If the idr is full, it will
- * return -ENOSPC.
+ * If allocation from IDR's private freelist fails, idr_get_new_above() will
+ * return %-EAGAIN. The caller should retry the idr_pre_get() call to refill
+ * IDR's preallocation and then retry the idr_get_new_above() call.
+ *
+ * If the idr is full idr_get_new_above() will return %-ENOSPC.
*
- * @id returns a value in the range @starting_id ... 0x7fffffff
+ * @id returns a value in the range @starting_id ... %0x7fffffff
*/
int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id)
{
@@ -318,14 +321,13 @@ EXPORT_SYMBOL(idr_get_new_above);
* @ptr: pointer you want associated with the id
* @id: pointer to the allocated handle
*
- * This is the allocate id function. It should be called with any
- * required locks.
+ * If allocation from IDR's private freelist fails, idr_get_new_above() will
+ * return %-EAGAIN. The caller should retry the idr_pre_get() call to refill
+ * IDR's preallocation and then retry the idr_get_new_above() call.
*
- * If memory is required, it will return -EAGAIN, you should unlock
- * and go back to the idr_pre_get() call. If the idr is full, it will
- * return -ENOSPC.
+ * If the idr is full idr_get_new_above() will return %-ENOSPC.
*
- * @id returns a value in the range 0 ... 0x7fffffff
+ * @id returns a value in the range %0 ... %0x7fffffff
*/
int idr_get_new(struct idr *idp, void *ptr, int *id)
{
@@ -388,7 +390,7 @@ static void sub_remove(struct idr *idp, int shift, int id)
}
/**
- * idr_remove - remove the given id and free it's slot
+ * idr_remove - remove the given id and free its slot
* @idp: idr handle
* @id: unique key
*/
@@ -437,7 +439,7 @@ EXPORT_SYMBOL(idr_remove);
* function will remove all id mappings and leave all idp_layers
* unused.
*
- * A typical clean-up sequence for objects stored in an idr tree, will
+ * A typical clean-up sequence for objects stored in an idr tree will
* use idr_for_each() to free all objects, if necessay, then
* idr_remove_all() to remove all ids, and idr_destroy() to free
* up the cached idr_layers.
@@ -479,7 +481,7 @@ EXPORT_SYMBOL(idr_remove_all);
/**
* idr_destroy - release all cached layers within an idr tree
- * idp: idr handle
+ * @idp: idr handle
*/
void idr_destroy(struct idr *idp)
{
@@ -542,7 +544,7 @@ EXPORT_SYMBOL(idr_find);
* not allowed.
*
* We check the return of @fn each time. If it returns anything other
- * than 0, we break out and return that value.
+ * than %0, we break out and return that value.
*
* The caller must serialize idr_for_each() vs idr_get_new() and idr_remove().
*/
@@ -586,10 +588,11 @@ EXPORT_SYMBOL(idr_for_each);
/**
* idr_get_next - lookup next object of id to given id.
* @idp: idr handle
- * @id: pointer to lookup key
+ * @nextidp: pointer to lookup key
*
* Returns pointer to registered object with id, which is next number to
- * given id.
+ * given id. After being looked up, *@nextidp will be updated for the next
+ * iteration.
*/
void *idr_get_next(struct idr *idp, int *nextidp)
@@ -636,8 +639,8 @@ EXPORT_SYMBOL(idr_get_next);
* @id: lookup key
*
* Replace the pointer registered with an id and return the old value.
- * A -ENOENT return indicates that @id was not found.
- * A -EINVAL return indicates that @id was not within valid constraints.
+ * A %-ENOENT return indicates that @id was not found.
+ * A %-EINVAL return indicates that @id was not within valid constraints.
*
* The caller must serialize with writers.
*/
@@ -695,10 +698,11 @@ void idr_init(struct idr *idp)
EXPORT_SYMBOL(idr_init);
-/*
+/**
+ * DOC: IDA description
* IDA - IDR based ID allocator
*
- * this is id allocator without id -> pointer translation. Memory
+ * This is id allocator without id -> pointer translation. Memory
* usage is much lower than full blown idr because each id only
* occupies a bit. ida uses a custom leaf node which contains
* IDA_BITMAP_BITS slots.
@@ -731,8 +735,8 @@ static void free_bitmap(struct ida *ida, struct ida_bitmap *bitmap)
* following function. It preallocates enough memory to satisfy the
* worst possible allocation.
*
- * If the system is REALLY out of memory this function returns 0,
- * otherwise 1.
+ * If the system is REALLY out of memory this function returns %0,
+ * otherwise %1.
*/
int ida_pre_get(struct ida *ida, gfp_t gfp_mask)
{
@@ -758,17 +762,17 @@ EXPORT_SYMBOL(ida_pre_get);
/**
* ida_get_new_above - allocate new ID above or equal to a start id
* @ida: ida handle
- * @staring_id: id to start search at
+ * @starting_id: id to start search at
* @p_id: pointer to the allocated handle
*
* Allocate new ID above or equal to @ida. It should be called with
* any required locks.
*
- * If memory is required, it will return -EAGAIN, you should unlock
+ * If memory is required, it will return %-EAGAIN, you should unlock
* and go back to the ida_pre_get() call. If the ida is full, it will
- * return -ENOSPC.
+ * return %-ENOSPC.
*
- * @p_id returns a value in the range @starting_id ... 0x7fffffff.
+ * @p_id returns a value in the range @starting_id ... %0x7fffffff.
*/
int ida_get_new_above(struct ida *ida, int starting_id, int *p_id)
{
@@ -850,11 +854,11 @@ EXPORT_SYMBOL(ida_get_new_above);
*
* Allocate new ID. It should be called with any required locks.
*
- * If memory is required, it will return -EAGAIN, you should unlock
+ * If memory is required, it will return %-EAGAIN, you should unlock
* and go back to the idr_pre_get() call. If the idr is full, it will
- * return -ENOSPC.
+ * return %-ENOSPC.
*
- * @id returns a value in the range 0 ... 0x7fffffff.
+ * @id returns a value in the range %0 ... %0x7fffffff.
*/
int ida_get_new(struct ida *ida, int *p_id)
{
@@ -912,7 +916,7 @@ EXPORT_SYMBOL(ida_remove);
/**
* ida_destroy - release all cached layers within an ida tree
- * ida: ida handle
+ * @ida: ida handle
*/
void ida_destroy(struct ida *ida)
{
diff --git a/lib/list_sort.c b/lib/list_sort.c
index a7616fa3162e..d7325c6b103f 100644
--- a/lib/list_sort.c
+++ b/lib/list_sort.c
@@ -141,77 +141,151 @@ void list_sort(void *priv, struct list_head *head,
}
EXPORT_SYMBOL(list_sort);
-#ifdef DEBUG_LIST_SORT
+#ifdef CONFIG_TEST_LIST_SORT
+
+#include <linux/random.h>
+
+/*
+ * The pattern of set bits in the list length determines which cases
+ * are hit in list_sort().
+ */
+#define TEST_LIST_LEN (512+128+2) /* not including head */
+
+#define TEST_POISON1 0xDEADBEEF
+#define TEST_POISON2 0xA324354C
+
struct debug_el {
- struct list_head l_h;
+ unsigned int poison1;
+ struct list_head list;
+ unsigned int poison2;
int value;
unsigned serial;
};
-static int cmp(void *priv, struct list_head *a, struct list_head *b)
+/* Array, containing pointers to all elements in the test list */
+static struct debug_el **elts __initdata;
+
+static int __init check(struct debug_el *ela, struct debug_el *elb)
{
- return container_of(a, struct debug_el, l_h)->value
- - container_of(b, struct debug_el, l_h)->value;
+ if (ela->serial >= TEST_LIST_LEN) {
+ printk(KERN_ERR "list_sort_test: error: incorrect serial %d\n",
+ ela->serial);
+ return -EINVAL;
+ }
+ if (elb->serial >= TEST_LIST_LEN) {
+ printk(KERN_ERR "list_sort_test: error: incorrect serial %d\n",
+ elb->serial);
+ return -EINVAL;
+ }
+ if (elts[ela->serial] != ela || elts[elb->serial] != elb) {
+ printk(KERN_ERR "list_sort_test: error: phantom element\n");
+ return -EINVAL;
+ }
+ if (ela->poison1 != TEST_POISON1 || ela->poison2 != TEST_POISON2) {
+ printk(KERN_ERR "list_sort_test: error: bad poison: %#x/%#x\n",
+ ela->poison1, ela->poison2);
+ return -EINVAL;
+ }
+ if (elb->poison1 != TEST_POISON1 || elb->poison2 != TEST_POISON2) {
+ printk(KERN_ERR "list_sort_test: error: bad poison: %#x/%#x\n",
+ elb->poison1, elb->poison2);
+ return -EINVAL;
+ }
+ return 0;
}
-/*
- * The pattern of set bits in the list length determines which cases
- * are hit in list_sort().
- */
-#define LIST_SORT_TEST_LENGTH (512+128+2) /* not including head */
+static int __init cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+ struct debug_el *ela, *elb;
+
+ ela = container_of(a, struct debug_el, list);
+ elb = container_of(b, struct debug_el, list);
+
+ check(ela, elb);
+ return ela->value - elb->value;
+}
static int __init list_sort_test(void)
{
- int i, r = 1, count;
- struct list_head *head = kmalloc(sizeof(*head), GFP_KERNEL);
- struct list_head *cur;
+ int i, count = 1, err = -EINVAL;
+ struct debug_el *el;
+ struct list_head *cur, *tmp;
+ LIST_HEAD(head);
+
+ printk(KERN_DEBUG "list_sort_test: start testing list_sort()\n");
- printk(KERN_WARNING "testing list_sort()\n");
+ elts = kmalloc(sizeof(void *) * TEST_LIST_LEN, GFP_KERNEL);
+ if (!elts) {
+ printk(KERN_ERR "list_sort_test: error: cannot allocate "
+ "memory\n");
+ goto exit;
+ }
- cur = head;
- for (i = 0; i < LIST_SORT_TEST_LENGTH; i++) {
- struct debug_el *el = kmalloc(sizeof(*el), GFP_KERNEL);
- BUG_ON(!el);
+ for (i = 0; i < TEST_LIST_LEN; i++) {
+ el = kmalloc(sizeof(*el), GFP_KERNEL);
+ if (!el) {
+ printk(KERN_ERR "list_sort_test: error: cannot "
+ "allocate memory\n");
+ goto exit;
+ }
/* force some equivalencies */
- el->value = (r = (r * 725861) % 6599) % (LIST_SORT_TEST_LENGTH/3);
+ el->value = random32() % (TEST_LIST_LEN/3);
el->serial = i;
-
- el->l_h.prev = cur;
- cur->next = &el->l_h;
- cur = cur->next;
+ el->poison1 = TEST_POISON1;
+ el->poison2 = TEST_POISON2;
+ elts[i] = el;
+ list_add_tail(&el->list, &head);
}
- head->prev = cur;
- list_sort(NULL, head, cmp);
+ list_sort(NULL, &head, cmp);
+
+ for (cur = head.next; cur->next != &head; cur = cur->next) {
+ struct debug_el *el1;
+ int cmp_result;
- count = 1;
- for (cur = head->next; cur->next != head; cur = cur->next) {
- struct debug_el *el = container_of(cur, struct debug_el, l_h);
- int cmp_result = cmp(NULL, cur, cur->next);
if (cur->next->prev != cur) {
- printk(KERN_EMERG "list_sort() returned "
- "a corrupted list!\n");
- return 1;
- } else if (cmp_result > 0) {
- printk(KERN_EMERG "list_sort() failed to sort!\n");
- return 1;
- } else if (cmp_result == 0 &&
- el->serial >= container_of(cur->next,
- struct debug_el, l_h)->serial) {
- printk(KERN_EMERG "list_sort() failed to preserve order"
- " of equivalent elements!\n");
- return 1;
+ printk(KERN_ERR "list_sort_test: error: list is "
+ "corrupted\n");
+ goto exit;
+ }
+
+ cmp_result = cmp(NULL, cur, cur->next);
+ if (cmp_result > 0) {
+ printk(KERN_ERR "list_sort_test: error: list is not "
+ "sorted\n");
+ goto exit;
+ }
+
+ el = container_of(cur, struct debug_el, list);
+ el1 = container_of(cur->next, struct debug_el, list);
+ if (cmp_result == 0 && el->serial >= el1->serial) {
+ printk(KERN_ERR "list_sort_test: error: order of "
+ "equivalent elements not preserved\n");
+ goto exit;
+ }
+
+ if (check(el, el1)) {
+ printk(KERN_ERR "list_sort_test: error: element check "
+ "failed\n");
+ goto exit;
}
- kfree(cur->prev);
count++;
}
- kfree(cur);
- if (count != LIST_SORT_TEST_LENGTH) {
- printk(KERN_EMERG "list_sort() returned list of"
- "different length!\n");
- return 1;
+
+ if (count != TEST_LIST_LEN) {
+ printk(KERN_ERR "list_sort_test: error: bad list length %d",
+ count);
+ goto exit;
}
- return 0;
+
+ err = 0;
+exit:
+ kfree(elts);
+ list_for_each_safe(cur, tmp, &head) {
+ list_del(cur);
+ kfree(container_of(cur, struct debug_el, list));
+ }
+ return err;
}
module_init(list_sort_test);
-#endif
+#endif /* CONFIG_TEST_LIST_SORT */
diff --git a/lib/parser.c b/lib/parser.c
index fb34977246bb..6e89eca5cca0 100644
--- a/lib/parser.c
+++ b/lib/parser.c
@@ -128,12 +128,13 @@ static int match_number(substring_t *s, int *result, int base)
char *endp;
char *buf;
int ret;
+ size_t len = s->to - s->from;
- buf = kmalloc(s->to - s->from + 1, GFP_KERNEL);
+ buf = kmalloc(len + 1, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- memcpy(buf, s->from, s->to - s->from);
- buf[s->to - s->from] = '\0';
+ memcpy(buf, s->from, len);
+ buf[len] = '\0';
*result = simple_strtol(buf, &endp, base);
ret = 0;
if (endp == buf)
diff --git a/lib/percpu_counter.c b/lib/percpu_counter.c
index ec9048e74f44..604678d7d06d 100644
--- a/lib/percpu_counter.c
+++ b/lib/percpu_counter.c
@@ -8,10 +8,53 @@
#include <linux/init.h>
#include <linux/cpu.h>
#include <linux/module.h>
+#include <linux/debugobjects.h>
static LIST_HEAD(percpu_counters);
static DEFINE_MUTEX(percpu_counters_lock);
+#ifdef CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER
+
+static struct debug_obj_descr percpu_counter_debug_descr;
+
+static int percpu_counter_fixup_free(void *addr, enum debug_obj_state state)
+{
+ struct percpu_counter *fbc = addr;
+
+ switch (state) {
+ case ODEBUG_STATE_ACTIVE:
+ percpu_counter_destroy(fbc);
+ debug_object_free(fbc, &percpu_counter_debug_descr);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static struct debug_obj_descr percpu_counter_debug_descr = {
+ .name = "percpu_counter",
+ .fixup_free = percpu_counter_fixup_free,
+};
+
+static inline void debug_percpu_counter_activate(struct percpu_counter *fbc)
+{
+ debug_object_init(fbc, &percpu_counter_debug_descr);
+ debug_object_activate(fbc, &percpu_counter_debug_descr);
+}
+
+static inline void debug_percpu_counter_deactivate(struct percpu_counter *fbc)
+{
+ debug_object_deactivate(fbc, &percpu_counter_debug_descr);
+ debug_object_free(fbc, &percpu_counter_debug_descr);
+}
+
+#else /* CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER */
+static inline void debug_percpu_counter_activate(struct percpu_counter *fbc)
+{ }
+static inline void debug_percpu_counter_deactivate(struct percpu_counter *fbc)
+{ }
+#endif /* CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER */
+
void percpu_counter_set(struct percpu_counter *fbc, s64 amount)
{
int cpu;
@@ -30,9 +73,9 @@ void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch)
{
s64 count;
s32 *pcount;
- int cpu = get_cpu();
- pcount = per_cpu_ptr(fbc->counters, cpu);
+ preempt_disable();
+ pcount = this_cpu_ptr(fbc->counters);
count = *pcount + amount;
if (count >= batch || count <= -batch) {
spin_lock(&fbc->lock);
@@ -42,7 +85,7 @@ void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch)
} else {
*pcount = count;
}
- put_cpu();
+ preempt_enable();
}
EXPORT_SYMBOL(__percpu_counter_add);
@@ -75,7 +118,11 @@ int __percpu_counter_init(struct percpu_counter *fbc, s64 amount,
fbc->counters = alloc_percpu(s32);
if (!fbc->counters)
return -ENOMEM;
+
+ debug_percpu_counter_activate(fbc);
+
#ifdef CONFIG_HOTPLUG_CPU
+ INIT_LIST_HEAD(&fbc->list);
mutex_lock(&percpu_counters_lock);
list_add(&fbc->list, &percpu_counters);
mutex_unlock(&percpu_counters_lock);
@@ -89,6 +136,8 @@ void percpu_counter_destroy(struct percpu_counter *fbc)
if (!fbc->counters)
return;
+ debug_percpu_counter_deactivate(fbc);
+
#ifdef CONFIG_HOTPLUG_CPU
mutex_lock(&percpu_counters_lock);
list_del(&fbc->list);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 7af9d841c43b..c150d3dafff4 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -988,8 +988,15 @@ static noinline_for_stack
char *pointer(const char *fmt, char *buf, char *end, void *ptr,
struct printf_spec spec)
{
- if (!ptr)
+ if (!ptr) {
+ /*
+ * Print (null) with the same width as a pointer so it makes
+ * tabular output look nice.
+ */
+ if (spec.field_width == -1)
+ spec.field_width = 2 * sizeof(void *);
return string(buf, end, "(null)", spec);
+ }
switch (*fmt) {
case 'F':
@@ -1031,7 +1038,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
}
spec.flags |= SMALL;
if (spec.field_width == -1) {
- spec.field_width = 2*sizeof(void *);
+ spec.field_width = 2 * sizeof(void *);
spec.flags |= ZEROPAD;
}
spec.base = 16;
@@ -1497,7 +1504,7 @@ EXPORT_SYMBOL(snprintf);
* @...: Arguments for the format string
*
* The return value is the number of characters written into @buf not including
- * the trailing '\0'. If @size is <= 0 the function returns 0.
+ * the trailing '\0'. If @size is == 0 the function returns 0.
*/
int scnprintf(char *buf, size_t size, const char *fmt, ...)
@@ -1509,7 +1516,11 @@ int scnprintf(char *buf, size_t size, const char *fmt, ...)
i = vsnprintf(buf, size, fmt, args);
va_end(args);
- return (i >= size) ? (size - 1) : i;
+ if (likely(i < size))
+ return i;
+ if (size != 0)
+ return size - 1;
+ return 0;
}
EXPORT_SYMBOL(scnprintf);
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 65d420499a61..027100d30227 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -74,11 +74,11 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v)
nr_wb = nr_dirty = nr_io = nr_more_io = 0;
spin_lock(&inode_lock);
- list_for_each_entry(inode, &wb->b_dirty, i_list)
+ list_for_each_entry(inode, &wb->b_dirty, i_wb_list)
nr_dirty++;
- list_for_each_entry(inode, &wb->b_io, i_list)
+ list_for_each_entry(inode, &wb->b_io, i_wb_list)
nr_io++;
- list_for_each_entry(inode, &wb->b_more_io, i_list)
+ list_for_each_entry(inode, &wb->b_more_io, i_wb_list)
nr_more_io++;
spin_unlock(&inode_lock);
@@ -362,7 +362,7 @@ static int bdi_forker_thread(void *ptr)
{
struct bdi_writeback *me = ptr;
- current->flags |= PF_FLUSHER | PF_SWAPWRITE;
+ current->flags |= PF_SWAPWRITE;
set_freezable();
/*
@@ -729,6 +729,7 @@ static wait_queue_head_t congestion_wqh[2] = {
__WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]),
__WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1])
};
+static atomic_t nr_bdi_congested[2];
void clear_bdi_congested(struct backing_dev_info *bdi, int sync)
{
@@ -736,7 +737,8 @@ void clear_bdi_congested(struct backing_dev_info *bdi, int sync)
wait_queue_head_t *wqh = &congestion_wqh[sync];
bit = sync ? BDI_sync_congested : BDI_async_congested;
- clear_bit(bit, &bdi->state);
+ if (test_and_clear_bit(bit, &bdi->state))
+ atomic_dec(&nr_bdi_congested[sync]);
smp_mb__after_clear_bit();
if (waitqueue_active(wqh))
wake_up(wqh);
@@ -748,7 +750,8 @@ void set_bdi_congested(struct backing_dev_info *bdi, int sync)
enum bdi_state bit;
bit = sync ? BDI_sync_congested : BDI_async_congested;
- set_bit(bit, &bdi->state);
+ if (!test_and_set_bit(bit, &bdi->state))
+ atomic_inc(&nr_bdi_congested[sync]);
}
EXPORT_SYMBOL(set_bdi_congested);
@@ -764,13 +767,72 @@ EXPORT_SYMBOL(set_bdi_congested);
long congestion_wait(int sync, long timeout)
{
long ret;
+ unsigned long start = jiffies;
DEFINE_WAIT(wait);
wait_queue_head_t *wqh = &congestion_wqh[sync];
prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
ret = io_schedule_timeout(timeout);
finish_wait(wqh, &wait);
+
+ trace_writeback_congestion_wait(jiffies_to_usecs(timeout),
+ jiffies_to_usecs(jiffies - start));
+
return ret;
}
EXPORT_SYMBOL(congestion_wait);
+/**
+ * wait_iff_congested - Conditionally wait for a backing_dev to become uncongested or a zone to complete writes
+ * @zone: A zone to check if it is heavily congested
+ * @sync: SYNC or ASYNC IO
+ * @timeout: timeout in jiffies
+ *
+ * In the event of a congested backing_dev (any backing_dev) and the given
+ * @zone has experienced recent congestion, this waits for up to @timeout
+ * jiffies for either a BDI to exit congestion of the given @sync queue
+ * or a write to complete.
+ *
+ * In the absense of zone congestion, cond_resched() is called to yield
+ * the processor if necessary but otherwise does not sleep.
+ *
+ * The return value is 0 if the sleep is for the full timeout. Otherwise,
+ * it is the number of jiffies that were still remaining when the function
+ * returned. return_value == timeout implies the function did not sleep.
+ */
+long wait_iff_congested(struct zone *zone, int sync, long timeout)
+{
+ long ret;
+ unsigned long start = jiffies;
+ DEFINE_WAIT(wait);
+ wait_queue_head_t *wqh = &congestion_wqh[sync];
+
+ /*
+ * If there is no congestion, or heavy congestion is not being
+ * encountered in the current zone, yield if necessary instead
+ * of sleeping on the congestion queue
+ */
+ if (atomic_read(&nr_bdi_congested[sync]) == 0 ||
+ !zone_is_reclaim_congested(zone)) {
+ cond_resched();
+
+ /* In case we scheduled, work out time remaining */
+ ret = timeout - (jiffies - start);
+ if (ret < 0)
+ ret = 0;
+
+ goto out;
+ }
+
+ /* Sleep until uncongested or a write happens */
+ prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
+ ret = io_schedule_timeout(timeout);
+ finish_wait(wqh, &wait);
+
+out:
+ trace_writeback_wait_iff_congested(jiffies_to_usecs(timeout),
+ jiffies_to_usecs(jiffies - start));
+
+ return ret;
+}
+EXPORT_SYMBOL(wait_iff_congested);
diff --git a/mm/dmapool.c b/mm/dmapool.c
index 3df063706f53..4df2de77e069 100644
--- a/mm/dmapool.c
+++ b/mm/dmapool.c
@@ -311,6 +311,8 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
size_t offset;
void *retval;
+ might_sleep_if(mem_flags & __GFP_WAIT);
+
spin_lock_irqsave(&pool->lock, flags);
restart:
list_for_each_entry(page, &pool->page_list, page_list) {
diff --git a/mm/filemap.c b/mm/filemap.c
index 3d4df44e4221..75572b5f2374 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -612,6 +612,19 @@ void __lock_page_nosync(struct page *page)
TASK_UNINTERRUPTIBLE);
}
+int __lock_page_or_retry(struct page *page, struct mm_struct *mm,
+ unsigned int flags)
+{
+ if (!(flags & FAULT_FLAG_ALLOW_RETRY)) {
+ __lock_page(page);
+ return 1;
+ } else {
+ up_read(&mm->mmap_sem);
+ wait_on_page_locked(page);
+ return 0;
+ }
+}
+
/**
* find_get_page - find and get a page reference
* @mapping: the address_space to search
@@ -1539,25 +1552,28 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
* waiting for the lock.
*/
do_async_mmap_readahead(vma, ra, file, page, offset);
- lock_page(page);
-
- /* Did it get truncated? */
- if (unlikely(page->mapping != mapping)) {
- unlock_page(page);
- put_page(page);
- goto no_cached_page;
- }
} else {
/* No page in the page cache at all */
do_sync_mmap_readahead(vma, ra, file, offset);
count_vm_event(PGMAJFAULT);
ret = VM_FAULT_MAJOR;
retry_find:
- page = find_lock_page(mapping, offset);
+ page = find_get_page(mapping, offset);
if (!page)
goto no_cached_page;
}
+ if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags))
+ return ret | VM_FAULT_RETRY;
+
+ /* Did it get truncated? */
+ if (unlikely(page->mapping != mapping)) {
+ unlock_page(page);
+ put_page(page);
+ goto retry_find;
+ }
+ VM_BUG_ON(page->index != offset);
+
/*
* We have a locked page in the page cache, now we need to check
* that it's up-to-date. If not, it is going to be due to an error.
@@ -2177,12 +2193,12 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
}
if (written > 0) {
- loff_t end = pos + written;
- if (end > i_size_read(inode) && !S_ISBLK(inode->i_mode)) {
- i_size_write(inode, end);
+ pos += written;
+ if (pos > i_size_read(inode) && !S_ISBLK(inode->i_mode)) {
+ i_size_write(inode, pos);
mark_inode_dirty(inode);
}
- *ppos = end;
+ *ppos = pos;
}
out:
return written;
diff --git a/mm/highmem.c b/mm/highmem.c
index 7a0aa1be4993..693394daa2ed 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -29,6 +29,11 @@
#include <linux/kgdb.h>
#include <asm/tlbflush.h>
+
+#if defined(CONFIG_HIGHMEM) || defined(CONFIG_X86_32)
+DEFINE_PER_CPU(int, __kmap_atomic_idx);
+#endif
+
/*
* Virtual_count is not a pure "count".
* 0 means that it is not mapped, and has not been mapped
@@ -42,6 +47,9 @@
unsigned long totalhigh_pages __read_mostly;
EXPORT_SYMBOL(totalhigh_pages);
+
+EXPORT_PER_CPU_SYMBOL(__kmap_atomic_idx);
+
unsigned int nr_free_highpages (void)
{
pg_data_t *pgdat;
@@ -422,61 +430,3 @@ void __init page_address_init(void)
}
#endif /* defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL) */
-
-#ifdef CONFIG_DEBUG_HIGHMEM
-
-void debug_kmap_atomic(enum km_type type)
-{
- static int warn_count = 10;
-
- if (unlikely(warn_count < 0))
- return;
-
- if (unlikely(in_interrupt())) {
- if (in_nmi()) {
- if (type != KM_NMI && type != KM_NMI_PTE) {
- WARN_ON(1);
- warn_count--;
- }
- } else if (in_irq()) {
- if (type != KM_IRQ0 && type != KM_IRQ1 &&
- type != KM_BIO_SRC_IRQ && type != KM_BIO_DST_IRQ &&
- type != KM_BOUNCE_READ && type != KM_IRQ_PTE) {
- WARN_ON(1);
- warn_count--;
- }
- } else if (!irqs_disabled()) { /* softirq */
- if (type != KM_IRQ0 && type != KM_IRQ1 &&
- type != KM_SOFTIRQ0 && type != KM_SOFTIRQ1 &&
- type != KM_SKB_SUNRPC_DATA &&
- type != KM_SKB_DATA_SOFTIRQ &&
- type != KM_BOUNCE_READ) {
- WARN_ON(1);
- warn_count--;
- }
- }
- }
-
- if (type == KM_IRQ0 || type == KM_IRQ1 || type == KM_BOUNCE_READ ||
- type == KM_BIO_SRC_IRQ || type == KM_BIO_DST_IRQ ||
- type == KM_IRQ_PTE || type == KM_NMI ||
- type == KM_NMI_PTE ) {
- if (!irqs_disabled()) {
- WARN_ON(1);
- warn_count--;
- }
- } else if (type == KM_SOFTIRQ0 || type == KM_SOFTIRQ1) {
- if (irq_count() == 0 && !irqs_disabled()) {
- WARN_ON(1);
- warn_count--;
- }
- }
-#ifdef CONFIG_KGDB_KDB
- if (unlikely(type == KM_KDB && atomic_read(&kgdb_active) == -1)) {
- WARN_ON(1);
- warn_count--;
- }
-#endif /* CONFIG_KGDB_KDB */
-}
-
-#endif
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index c03273807182..c4a3558589ab 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -423,14 +423,14 @@ static void clear_huge_page(struct page *page,
}
}
-static void copy_gigantic_page(struct page *dst, struct page *src,
+static void copy_user_gigantic_page(struct page *dst, struct page *src,
unsigned long addr, struct vm_area_struct *vma)
{
int i;
struct hstate *h = hstate_vma(vma);
struct page *dst_base = dst;
struct page *src_base = src;
- might_sleep();
+
for (i = 0; i < pages_per_huge_page(h); ) {
cond_resched();
copy_user_highpage(dst, src, addr + i*PAGE_SIZE, vma);
@@ -440,14 +440,15 @@ static void copy_gigantic_page(struct page *dst, struct page *src,
src = mem_map_next(src, src_base, i);
}
}
-static void copy_huge_page(struct page *dst, struct page *src,
+
+static void copy_user_huge_page(struct page *dst, struct page *src,
unsigned long addr, struct vm_area_struct *vma)
{
int i;
struct hstate *h = hstate_vma(vma);
if (unlikely(pages_per_huge_page(h) > MAX_ORDER_NR_PAGES)) {
- copy_gigantic_page(dst, src, addr, vma);
+ copy_user_gigantic_page(dst, src, addr, vma);
return;
}
@@ -458,6 +459,40 @@ static void copy_huge_page(struct page *dst, struct page *src,
}
}
+static void copy_gigantic_page(struct page *dst, struct page *src)
+{
+ int i;
+ struct hstate *h = page_hstate(src);
+ struct page *dst_base = dst;
+ struct page *src_base = src;
+
+ for (i = 0; i < pages_per_huge_page(h); ) {
+ cond_resched();
+ copy_highpage(dst, src);
+
+ i++;
+ dst = mem_map_next(dst, dst_base, i);
+ src = mem_map_next(src, src_base, i);
+ }
+}
+
+void copy_huge_page(struct page *dst, struct page *src)
+{
+ int i;
+ struct hstate *h = page_hstate(src);
+
+ if (unlikely(pages_per_huge_page(h) > MAX_ORDER_NR_PAGES)) {
+ copy_gigantic_page(dst, src);
+ return;
+ }
+
+ might_sleep();
+ for (i = 0; i < pages_per_huge_page(h); i++) {
+ cond_resched();
+ copy_highpage(dst + i, src + i);
+ }
+}
+
static void enqueue_huge_page(struct hstate *h, struct page *page)
{
int nid = page_to_nid(page);
@@ -466,11 +501,24 @@ static void enqueue_huge_page(struct hstate *h, struct page *page)
h->free_huge_pages_node[nid]++;
}
+static struct page *dequeue_huge_page_node(struct hstate *h, int nid)
+{
+ struct page *page;
+
+ if (list_empty(&h->hugepage_freelists[nid]))
+ return NULL;
+ page = list_entry(h->hugepage_freelists[nid].next, struct page, lru);
+ list_del(&page->lru);
+ set_page_refcounted(page);
+ h->free_huge_pages--;
+ h->free_huge_pages_node[nid]--;
+ return page;
+}
+
static struct page *dequeue_huge_page_vma(struct hstate *h,
struct vm_area_struct *vma,
unsigned long address, int avoid_reserve)
{
- int nid;
struct page *page = NULL;
struct mempolicy *mpol;
nodemask_t *nodemask;
@@ -496,19 +544,13 @@ static struct page *dequeue_huge_page_vma(struct hstate *h,
for_each_zone_zonelist_nodemask(zone, z, zonelist,
MAX_NR_ZONES - 1, nodemask) {
- nid = zone_to_nid(zone);
- if (cpuset_zone_allowed_softwall(zone, htlb_alloc_mask) &&
- !list_empty(&h->hugepage_freelists[nid])) {
- page = list_entry(h->hugepage_freelists[nid].next,
- struct page, lru);
- list_del(&page->lru);
- h->free_huge_pages--;
- h->free_huge_pages_node[nid]--;
-
- if (!avoid_reserve)
- decrement_hugepage_resv_vma(h, vma);
-
- break;
+ if (cpuset_zone_allowed_softwall(zone, htlb_alloc_mask)) {
+ page = dequeue_huge_page_node(h, zone_to_nid(zone));
+ if (page) {
+ if (!avoid_reserve)
+ decrement_hugepage_resv_vma(h, vma);
+ break;
+ }
}
}
err:
@@ -770,11 +812,10 @@ static int free_pool_huge_page(struct hstate *h, nodemask_t *nodes_allowed,
return ret;
}
-static struct page *alloc_buddy_huge_page(struct hstate *h,
- struct vm_area_struct *vma, unsigned long address)
+static struct page *alloc_buddy_huge_page(struct hstate *h, int nid)
{
struct page *page;
- unsigned int nid;
+ unsigned int r_nid;
if (h->order >= MAX_ORDER)
return NULL;
@@ -812,9 +853,14 @@ static struct page *alloc_buddy_huge_page(struct hstate *h,
}
spin_unlock(&hugetlb_lock);
- page = alloc_pages(htlb_alloc_mask|__GFP_COMP|
- __GFP_REPEAT|__GFP_NOWARN,
- huge_page_order(h));
+ if (nid == NUMA_NO_NODE)
+ page = alloc_pages(htlb_alloc_mask|__GFP_COMP|
+ __GFP_REPEAT|__GFP_NOWARN,
+ huge_page_order(h));
+ else
+ page = alloc_pages_exact_node(nid,
+ htlb_alloc_mask|__GFP_COMP|__GFP_THISNODE|
+ __GFP_REPEAT|__GFP_NOWARN, huge_page_order(h));
if (page && arch_prepare_hugepage(page)) {
__free_pages(page, huge_page_order(h));
@@ -823,19 +869,13 @@ static struct page *alloc_buddy_huge_page(struct hstate *h,
spin_lock(&hugetlb_lock);
if (page) {
- /*
- * This page is now managed by the hugetlb allocator and has
- * no users -- drop the buddy allocator's reference.
- */
- put_page_testzero(page);
- VM_BUG_ON(page_count(page));
- nid = page_to_nid(page);
+ r_nid = page_to_nid(page);
set_compound_page_dtor(page, free_huge_page);
/*
* We incremented the global counters already
*/
- h->nr_huge_pages_node[nid]++;
- h->surplus_huge_pages_node[nid]++;
+ h->nr_huge_pages_node[r_nid]++;
+ h->surplus_huge_pages_node[r_nid]++;
__count_vm_event(HTLB_BUDDY_PGALLOC);
} else {
h->nr_huge_pages--;
@@ -848,6 +888,25 @@ static struct page *alloc_buddy_huge_page(struct hstate *h,
}
/*
+ * This allocation function is useful in the context where vma is irrelevant.
+ * E.g. soft-offlining uses this function because it only cares physical
+ * address of error page.
+ */
+struct page *alloc_huge_page_node(struct hstate *h, int nid)
+{
+ struct page *page;
+
+ spin_lock(&hugetlb_lock);
+ page = dequeue_huge_page_node(h, nid);
+ spin_unlock(&hugetlb_lock);
+
+ if (!page)
+ page = alloc_buddy_huge_page(h, nid);
+
+ return page;
+}
+
+/*
* Increase the hugetlb pool such that it can accomodate a reservation
* of size 'delta'.
*/
@@ -871,17 +930,14 @@ static int gather_surplus_pages(struct hstate *h, int delta)
retry:
spin_unlock(&hugetlb_lock);
for (i = 0; i < needed; i++) {
- page = alloc_buddy_huge_page(h, NULL, 0);
- if (!page) {
+ page = alloc_buddy_huge_page(h, NUMA_NO_NODE);
+ if (!page)
/*
* We were not able to allocate enough pages to
* satisfy the entire reservation so we free what
* we've allocated so far.
*/
- spin_lock(&hugetlb_lock);
- needed = 0;
goto free;
- }
list_add(&page->lru, &surplus_list);
}
@@ -908,31 +964,31 @@ retry:
needed += allocated;
h->resv_huge_pages += delta;
ret = 0;
-free:
+
+ spin_unlock(&hugetlb_lock);
/* Free the needed pages to the hugetlb pool */
list_for_each_entry_safe(page, tmp, &surplus_list, lru) {
if ((--needed) < 0)
break;
list_del(&page->lru);
+ /*
+ * This page is now managed by the hugetlb allocator and has
+ * no users -- drop the buddy allocator's reference.
+ */
+ put_page_testzero(page);
+ VM_BUG_ON(page_count(page));
enqueue_huge_page(h, page);
}
/* Free unnecessary surplus pages to the buddy allocator */
+free:
if (!list_empty(&surplus_list)) {
- spin_unlock(&hugetlb_lock);
list_for_each_entry_safe(page, tmp, &surplus_list, lru) {
list_del(&page->lru);
- /*
- * The page has a reference count of zero already, so
- * call free_huge_page directly instead of using
- * put_page. This must be done with hugetlb_lock
- * unlocked which is safe because free_huge_page takes
- * hugetlb_lock before deciding how to free the page.
- */
- free_huge_page(page);
+ put_page(page);
}
- spin_lock(&hugetlb_lock);
}
+ spin_lock(&hugetlb_lock);
return ret;
}
@@ -1052,14 +1108,13 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
spin_unlock(&hugetlb_lock);
if (!page) {
- page = alloc_buddy_huge_page(h, vma, addr);
+ page = alloc_buddy_huge_page(h, NUMA_NO_NODE);
if (!page) {
hugetlb_put_quota(inode->i_mapping, chg);
return ERR_PTR(-VM_FAULT_SIGBUS);
}
}
- set_page_refcounted(page);
set_page_private(page, (unsigned long) mapping);
vma_commit_reservation(h, vma, addr);
@@ -2153,6 +2208,19 @@ nomem:
return -ENOMEM;
}
+static int is_hugetlb_entry_migration(pte_t pte)
+{
+ swp_entry_t swp;
+
+ if (huge_pte_none(pte) || pte_present(pte))
+ return 0;
+ swp = pte_to_swp_entry(pte);
+ if (non_swap_entry(swp) && is_migration_entry(swp)) {
+ return 1;
+ } else
+ return 0;
+}
+
static int is_hugetlb_entry_hwpoisoned(pte_t pte)
{
swp_entry_t swp;
@@ -2380,10 +2448,13 @@ retry_avoidcopy:
* When the original hugepage is shared one, it does not have
* anon_vma prepared.
*/
- if (unlikely(anon_vma_prepare(vma)))
+ if (unlikely(anon_vma_prepare(vma))) {
+ /* Caller expects lock to be held */
+ spin_lock(&mm->page_table_lock);
return VM_FAULT_OOM;
+ }
- copy_huge_page(new_page, old_page, address, vma);
+ copy_user_huge_page(new_page, old_page, address, vma);
__SetPageUptodate(new_page);
/*
@@ -2515,22 +2586,20 @@ retry:
hugepage_add_new_anon_rmap(page, vma, address);
}
} else {
+ /*
+ * If memory error occurs between mmap() and fault, some process
+ * don't have hwpoisoned swap entry for errored virtual address.
+ * So we need to block hugepage fault by PG_hwpoison bit check.
+ */
+ if (unlikely(PageHWPoison(page))) {
+ ret = VM_FAULT_HWPOISON |
+ VM_FAULT_SET_HINDEX(h - hstates);
+ goto backout_unlocked;
+ }
page_dup_rmap(page);
}
/*
- * Since memory error handler replaces pte into hwpoison swap entry
- * at the time of error handling, a process which reserved but not have
- * the mapping to the error hugepage does not have hwpoison swap entry.
- * So we need to block accesses from such a process by checking
- * PG_hwpoison bit here.
- */
- if (unlikely(PageHWPoison(page))) {
- ret = VM_FAULT_HWPOISON;
- goto backout_unlocked;
- }
-
- /*
* If we are going to COW a private mapping later, we examine the
* pending reservations for this page now. This will ensure that
* any allocations necessary to record that reservation occur outside
@@ -2587,8 +2656,12 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
ptep = huge_pte_offset(mm, address);
if (ptep) {
entry = huge_ptep_get(ptep);
- if (unlikely(is_hugetlb_entry_hwpoisoned(entry)))
- return VM_FAULT_HWPOISON;
+ if (unlikely(is_hugetlb_entry_migration(entry))) {
+ migration_entry_wait(mm, (pmd_t *)ptep, address);
+ return 0;
+ } else if (unlikely(is_hugetlb_entry_hwpoisoned(entry)))
+ return VM_FAULT_HWPOISON_LARGE |
+ VM_FAULT_SET_HINDEX(h - hstates);
}
ptep = huge_pte_alloc(mm, address, huge_page_size(h));
@@ -2878,18 +2951,41 @@ void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
hugetlb_acct_memory(h, -(chg - freed));
}
+#ifdef CONFIG_MEMORY_FAILURE
+
+/* Should be called in hugetlb_lock */
+static int is_hugepage_on_freelist(struct page *hpage)
+{
+ struct page *page;
+ struct page *tmp;
+ struct hstate *h = page_hstate(hpage);
+ int nid = page_to_nid(hpage);
+
+ list_for_each_entry_safe(page, tmp, &h->hugepage_freelists[nid], lru)
+ if (page == hpage)
+ return 1;
+ return 0;
+}
+
/*
* This function is called from memory failure code.
* Assume the caller holds page lock of the head page.
*/
-void __isolate_hwpoisoned_huge_page(struct page *hpage)
+int dequeue_hwpoisoned_huge_page(struct page *hpage)
{
struct hstate *h = page_hstate(hpage);
int nid = page_to_nid(hpage);
+ int ret = -EBUSY;
spin_lock(&hugetlb_lock);
- list_del(&hpage->lru);
- h->free_huge_pages--;
- h->free_huge_pages_node[nid]--;
+ if (is_hugepage_on_freelist(hpage)) {
+ list_del(&hpage->lru);
+ set_page_refcounted(hpage);
+ h->free_huge_pages--;
+ h->free_huge_pages_node[nid]--;
+ ret = 0;
+ }
spin_unlock(&hugetlb_lock);
+ return ret;
}
+#endif
diff --git a/mm/internal.h b/mm/internal.h
index 6a697bb97fc5..dedb0aff673f 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -62,7 +62,7 @@ extern bool is_free_buddy_page(struct page *page);
*/
static inline unsigned long page_order(struct page *page)
{
- VM_BUG_ON(!PageBuddy(page));
+ /* PageBuddy() must be checked by the caller */
return page_private(page);
}
diff --git a/mm/maccess.c b/mm/maccess.c
index 4e348dbaecd7..e2b6f5634e0d 100644
--- a/mm/maccess.c
+++ b/mm/maccess.c
@@ -1,9 +1,9 @@
/*
* Access kernel memory without faulting.
*/
-#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/mm.h>
+#include <linux/uaccess.h>
/**
* probe_kernel_read(): safely attempt to read from a location
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 9be3cf8a5da4..9a99cfaf0a19 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -89,7 +89,10 @@ enum mem_cgroup_stat_index {
MEM_CGROUP_STAT_PGPGIN_COUNT, /* # of pages paged in */
MEM_CGROUP_STAT_PGPGOUT_COUNT, /* # of pages paged out */
MEM_CGROUP_STAT_SWAPOUT, /* # of pages, swapped out */
- MEM_CGROUP_EVENTS, /* incremented at every pagein/pageout */
+ MEM_CGROUP_STAT_DATA, /* end of data requires synchronization */
+ /* incremented at every pagein/pageout */
+ MEM_CGROUP_EVENTS = MEM_CGROUP_STAT_DATA,
+ MEM_CGROUP_ON_MOVE, /* someone is moving account between groups */
MEM_CGROUP_STAT_NSTATS,
};
@@ -254,6 +257,12 @@ struct mem_cgroup {
* percpu counter.
*/
struct mem_cgroup_stat_cpu *stat;
+ /*
+ * used when a cpu is offlined or other synchronizations
+ * See mem_cgroup_read_stat().
+ */
+ struct mem_cgroup_stat_cpu nocpu_base;
+ spinlock_t pcp_counter_lock;
};
/* Stuffs for move charges at task migration. */
@@ -530,14 +539,40 @@ mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz)
return mz;
}
+/*
+ * Implementation Note: reading percpu statistics for memcg.
+ *
+ * Both of vmstat[] and percpu_counter has threshold and do periodic
+ * synchronization to implement "quick" read. There are trade-off between
+ * reading cost and precision of value. Then, we may have a chance to implement
+ * a periodic synchronizion of counter in memcg's counter.
+ *
+ * But this _read() function is used for user interface now. The user accounts
+ * memory usage by memory cgroup and he _always_ requires exact value because
+ * he accounts memory. Even if we provide quick-and-fuzzy read, we always
+ * have to visit all online cpus and make sum. So, for now, unnecessary
+ * synchronization is not implemented. (just implemented for cpu hotplug)
+ *
+ * If there are kernel internal actions which can make use of some not-exact
+ * value, and reading all cpu value can be performance bottleneck in some
+ * common workload, threashold and synchonization as vmstat[] should be
+ * implemented.
+ */
static s64 mem_cgroup_read_stat(struct mem_cgroup *mem,
enum mem_cgroup_stat_index idx)
{
int cpu;
s64 val = 0;
- for_each_possible_cpu(cpu)
+ get_online_cpus();
+ for_each_online_cpu(cpu)
val += per_cpu(mem->stat->count[idx], cpu);
+#ifdef CONFIG_HOTPLUG_CPU
+ spin_lock(&mem->pcp_counter_lock);
+ val += mem->nocpu_base.count[idx];
+ spin_unlock(&mem->pcp_counter_lock);
+#endif
+ put_online_cpus();
return val;
}
@@ -659,40 +694,83 @@ static struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
return mem;
}
-/*
- * Call callback function against all cgroup under hierarchy tree.
- */
-static int mem_cgroup_walk_tree(struct mem_cgroup *root, void *data,
- int (*func)(struct mem_cgroup *, void *))
+/* The caller has to guarantee "mem" exists before calling this */
+static struct mem_cgroup *mem_cgroup_start_loop(struct mem_cgroup *mem)
{
- int found, ret, nextid;
struct cgroup_subsys_state *css;
- struct mem_cgroup *mem;
-
- if (!root->use_hierarchy)
- return (*func)(root, data);
+ int found;
- nextid = 1;
- do {
- ret = 0;
+ if (!mem) /* ROOT cgroup has the smallest ID */
+ return root_mem_cgroup; /*css_put/get against root is ignored*/
+ if (!mem->use_hierarchy) {
+ if (css_tryget(&mem->css))
+ return mem;
+ return NULL;
+ }
+ rcu_read_lock();
+ /*
+ * searching a memory cgroup which has the smallest ID under given
+ * ROOT cgroup. (ID >= 1)
+ */
+ css = css_get_next(&mem_cgroup_subsys, 1, &mem->css, &found);
+ if (css && css_tryget(css))
+ mem = container_of(css, struct mem_cgroup, css);
+ else
mem = NULL;
+ rcu_read_unlock();
+ return mem;
+}
+
+static struct mem_cgroup *mem_cgroup_get_next(struct mem_cgroup *iter,
+ struct mem_cgroup *root,
+ bool cond)
+{
+ int nextid = css_id(&iter->css) + 1;
+ int found;
+ int hierarchy_used;
+ struct cgroup_subsys_state *css;
+
+ hierarchy_used = iter->use_hierarchy;
+ css_put(&iter->css);
+ /* If no ROOT, walk all, ignore hierarchy */
+ if (!cond || (root && !hierarchy_used))
+ return NULL;
+
+ if (!root)
+ root = root_mem_cgroup;
+
+ do {
+ iter = NULL;
rcu_read_lock();
- css = css_get_next(&mem_cgroup_subsys, nextid, &root->css,
- &found);
+
+ css = css_get_next(&mem_cgroup_subsys, nextid,
+ &root->css, &found);
if (css && css_tryget(css))
- mem = container_of(css, struct mem_cgroup, css);
+ iter = container_of(css, struct mem_cgroup, css);
rcu_read_unlock();
-
- if (mem) {
- ret = (*func)(mem, data);
- css_put(&mem->css);
- }
+ /* If css is NULL, no more cgroups will be found */
nextid = found + 1;
- } while (!ret && css);
+ } while (css && !iter);
- return ret;
+ return iter;
}
+/*
+ * for_eacn_mem_cgroup_tree() for visiting all cgroup under tree. Please
+ * be careful that "break" loop is not allowed. We have reference count.
+ * Instead of that modify "cond" to be false and "continue" to exit the loop.
+ */
+#define for_each_mem_cgroup_tree_cond(iter, root, cond) \
+ for (iter = mem_cgroup_start_loop(root);\
+ iter != NULL;\
+ iter = mem_cgroup_get_next(iter, root, cond))
+
+#define for_each_mem_cgroup_tree(iter, root) \
+ for_each_mem_cgroup_tree_cond(iter, root, true)
+
+#define for_each_mem_cgroup_all(iter) \
+ for_each_mem_cgroup_tree_cond(iter, NULL, true)
+
static inline bool mem_cgroup_is_root(struct mem_cgroup *mem)
{
@@ -1051,7 +1129,52 @@ static unsigned int get_swappiness(struct mem_cgroup *memcg)
return swappiness;
}
-/* A routine for testing mem is not under move_account */
+static void mem_cgroup_start_move(struct mem_cgroup *mem)
+{
+ int cpu;
+
+ get_online_cpus();
+ spin_lock(&mem->pcp_counter_lock);
+ for_each_online_cpu(cpu)
+ per_cpu(mem->stat->count[MEM_CGROUP_ON_MOVE], cpu) += 1;
+ mem->nocpu_base.count[MEM_CGROUP_ON_MOVE] += 1;
+ spin_unlock(&mem->pcp_counter_lock);
+ put_online_cpus();
+
+ synchronize_rcu();
+}
+
+static void mem_cgroup_end_move(struct mem_cgroup *mem)
+{
+ int cpu;
+
+ if (!mem)
+ return;
+ get_online_cpus();
+ spin_lock(&mem->pcp_counter_lock);
+ for_each_online_cpu(cpu)
+ per_cpu(mem->stat->count[MEM_CGROUP_ON_MOVE], cpu) -= 1;
+ mem->nocpu_base.count[MEM_CGROUP_ON_MOVE] -= 1;
+ spin_unlock(&mem->pcp_counter_lock);
+ put_online_cpus();
+}
+/*
+ * 2 routines for checking "mem" is under move_account() or not.
+ *
+ * mem_cgroup_stealed() - checking a cgroup is mc.from or not. This is used
+ * for avoiding race in accounting. If true,
+ * pc->mem_cgroup may be overwritten.
+ *
+ * mem_cgroup_under_move() - checking a cgroup is mc.from or mc.to or
+ * under hierarchy of moving cgroups. This is for
+ * waiting at hith-memory prressure caused by "move".
+ */
+
+static bool mem_cgroup_stealed(struct mem_cgroup *mem)
+{
+ VM_BUG_ON(!rcu_read_lock_held());
+ return this_cpu_read(mem->stat->count[MEM_CGROUP_ON_MOVE]) > 0;
+}
static bool mem_cgroup_under_move(struct mem_cgroup *mem)
{
@@ -1092,13 +1215,6 @@ static bool mem_cgroup_wait_acct_move(struct mem_cgroup *mem)
return false;
}
-static int mem_cgroup_count_children_cb(struct mem_cgroup *mem, void *data)
-{
- int *val = data;
- (*val)++;
- return 0;
-}
-
/**
* mem_cgroup_print_oom_info: Called from OOM with tasklist_lock held in read mode.
* @memcg: The memory cgroup that went over limit
@@ -1173,7 +1289,10 @@ done:
static int mem_cgroup_count_children(struct mem_cgroup *mem)
{
int num = 0;
- mem_cgroup_walk_tree(mem, &num, mem_cgroup_count_children_cb);
+ struct mem_cgroup *iter;
+
+ for_each_mem_cgroup_tree(iter, mem)
+ num++;
return num;
}
@@ -1322,49 +1441,39 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
return total;
}
-static int mem_cgroup_oom_lock_cb(struct mem_cgroup *mem, void *data)
-{
- int *val = (int *)data;
- int x;
- /*
- * Logically, we can stop scanning immediately when we find
- * a memcg is already locked. But condidering unlock ops and
- * creation/removal of memcg, scan-all is simple operation.
- */
- x = atomic_inc_return(&mem->oom_lock);
- *val = max(x, *val);
- return 0;
-}
/*
* Check OOM-Killer is already running under our hierarchy.
* If someone is running, return false.
*/
static bool mem_cgroup_oom_lock(struct mem_cgroup *mem)
{
- int lock_count = 0;
+ int x, lock_count = 0;
+ struct mem_cgroup *iter;
- mem_cgroup_walk_tree(mem, &lock_count, mem_cgroup_oom_lock_cb);
+ for_each_mem_cgroup_tree(iter, mem) {
+ x = atomic_inc_return(&iter->oom_lock);
+ lock_count = max(x, lock_count);
+ }
if (lock_count == 1)
return true;
return false;
}
-static int mem_cgroup_oom_unlock_cb(struct mem_cgroup *mem, void *data)
+static int mem_cgroup_oom_unlock(struct mem_cgroup *mem)
{
+ struct mem_cgroup *iter;
+
/*
* When a new child is created while the hierarchy is under oom,
* mem_cgroup_oom_lock() may not be called. We have to use
* atomic_add_unless() here.
*/
- atomic_add_unless(&mem->oom_lock, -1, 0);
+ for_each_mem_cgroup_tree(iter, mem)
+ atomic_add_unless(&iter->oom_lock, -1, 0);
return 0;
}
-static void mem_cgroup_oom_unlock(struct mem_cgroup *mem)
-{
- mem_cgroup_walk_tree(mem, NULL, mem_cgroup_oom_unlock_cb);
-}
static DEFINE_MUTEX(memcg_oom_mutex);
static DECLARE_WAIT_QUEUE_HEAD(memcg_oom_waitq);
@@ -1462,34 +1571,73 @@ bool mem_cgroup_handle_oom(struct mem_cgroup *mem, gfp_t mask)
/*
* Currently used to update mapped file statistics, but the routine can be
* generalized to update other statistics as well.
+ *
+ * Notes: Race condition
+ *
+ * We usually use page_cgroup_lock() for accessing page_cgroup member but
+ * it tends to be costly. But considering some conditions, we doesn't need
+ * to do so _always_.
+ *
+ * Considering "charge", lock_page_cgroup() is not required because all
+ * file-stat operations happen after a page is attached to radix-tree. There
+ * are no race with "charge".
+ *
+ * Considering "uncharge", we know that memcg doesn't clear pc->mem_cgroup
+ * at "uncharge" intentionally. So, we always see valid pc->mem_cgroup even
+ * if there are race with "uncharge". Statistics itself is properly handled
+ * by flags.
+ *
+ * Considering "move", this is an only case we see a race. To make the race
+ * small, we check MEM_CGROUP_ON_MOVE percpu value and detect there are
+ * possibility of race condition. If there is, we take a lock.
*/
-void mem_cgroup_update_file_mapped(struct page *page, int val)
+
+static void mem_cgroup_update_file_stat(struct page *page, int idx, int val)
{
struct mem_cgroup *mem;
- struct page_cgroup *pc;
+ struct page_cgroup *pc = lookup_page_cgroup(page);
+ bool need_unlock = false;
- pc = lookup_page_cgroup(page);
if (unlikely(!pc))
return;
- lock_page_cgroup(pc);
+ rcu_read_lock();
mem = pc->mem_cgroup;
- if (!mem || !PageCgroupUsed(pc))
- goto done;
+ if (unlikely(!mem || !PageCgroupUsed(pc)))
+ goto out;
+ /* pc->mem_cgroup is unstable ? */
+ if (unlikely(mem_cgroup_stealed(mem))) {
+ /* take a lock against to access pc->mem_cgroup */
+ lock_page_cgroup(pc);
+ need_unlock = true;
+ mem = pc->mem_cgroup;
+ if (!mem || !PageCgroupUsed(pc))
+ goto out;
+ }
- /*
- * Preemption is already disabled. We can use __this_cpu_xxx
- */
- if (val > 0) {
- __this_cpu_inc(mem->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]);
- SetPageCgroupFileMapped(pc);
- } else {
- __this_cpu_dec(mem->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]);
- ClearPageCgroupFileMapped(pc);
+ this_cpu_add(mem->stat->count[idx], val);
+
+ switch (idx) {
+ case MEM_CGROUP_STAT_FILE_MAPPED:
+ if (val > 0)
+ SetPageCgroupFileMapped(pc);
+ else if (!page_mapped(page))
+ ClearPageCgroupFileMapped(pc);
+ break;
+ default:
+ BUG();
}
-done:
- unlock_page_cgroup(pc);
+out:
+ if (unlikely(need_unlock))
+ unlock_page_cgroup(pc);
+ rcu_read_unlock();
+ return;
+}
+
+void mem_cgroup_update_file_mapped(struct page *page, int val)
+{
+ mem_cgroup_update_file_stat(page, MEM_CGROUP_STAT_FILE_MAPPED, val);
}
/*
@@ -1605,15 +1753,55 @@ static void drain_all_stock_sync(void)
atomic_dec(&memcg_drain_count);
}
-static int __cpuinit memcg_stock_cpu_callback(struct notifier_block *nb,
+/*
+ * This function drains percpu counter value from DEAD cpu and
+ * move it to local cpu. Note that this function can be preempted.
+ */
+static void mem_cgroup_drain_pcp_counter(struct mem_cgroup *mem, int cpu)
+{
+ int i;
+
+ spin_lock(&mem->pcp_counter_lock);
+ for (i = 0; i < MEM_CGROUP_STAT_DATA; i++) {
+ s64 x = per_cpu(mem->stat->count[i], cpu);
+
+ per_cpu(mem->stat->count[i], cpu) = 0;
+ mem->nocpu_base.count[i] += x;
+ }
+ /* need to clear ON_MOVE value, works as a kind of lock. */
+ per_cpu(mem->stat->count[MEM_CGROUP_ON_MOVE], cpu) = 0;
+ spin_unlock(&mem->pcp_counter_lock);
+}
+
+static void synchronize_mem_cgroup_on_move(struct mem_cgroup *mem, int cpu)
+{
+ int idx = MEM_CGROUP_ON_MOVE;
+
+ spin_lock(&mem->pcp_counter_lock);
+ per_cpu(mem->stat->count[idx], cpu) = mem->nocpu_base.count[idx];
+ spin_unlock(&mem->pcp_counter_lock);
+}
+
+static int __cpuinit memcg_cpu_hotplug_callback(struct notifier_block *nb,
unsigned long action,
void *hcpu)
{
int cpu = (unsigned long)hcpu;
struct memcg_stock_pcp *stock;
+ struct mem_cgroup *iter;
+
+ if ((action == CPU_ONLINE)) {
+ for_each_mem_cgroup_all(iter)
+ synchronize_mem_cgroup_on_move(iter, cpu);
+ return NOTIFY_OK;
+ }
- if (action != CPU_DEAD)
+ if ((action != CPU_DEAD) || action != CPU_DEAD_FROZEN)
return NOTIFY_OK;
+
+ for_each_mem_cgroup_all(iter)
+ mem_cgroup_drain_pcp_counter(iter, cpu);
+
stock = &per_cpu(memcg_stock, cpu);
drain_stock(stock);
return NOTIFY_OK;
@@ -3038,6 +3226,7 @@ move_account:
lru_add_drain_all();
drain_all_stock_sync();
ret = 0;
+ mem_cgroup_start_move(mem);
for_each_node_state(node, N_HIGH_MEMORY) {
for (zid = 0; !ret && zid < MAX_NR_ZONES; zid++) {
enum lru_list l;
@@ -3051,6 +3240,7 @@ move_account:
if (ret)
break;
}
+ mem_cgroup_end_move(mem);
memcg_oom_recover(mem);
/* it seems parent cgroup doesn't have enough mem */
if (ret == -ENOMEM)
@@ -3137,33 +3327,25 @@ static int mem_cgroup_hierarchy_write(struct cgroup *cont, struct cftype *cft,
return retval;
}
-struct mem_cgroup_idx_data {
- s64 val;
- enum mem_cgroup_stat_index idx;
-};
-static int
-mem_cgroup_get_idx_stat(struct mem_cgroup *mem, void *data)
+static u64 mem_cgroup_get_recursive_idx_stat(struct mem_cgroup *mem,
+ enum mem_cgroup_stat_index idx)
{
- struct mem_cgroup_idx_data *d = data;
- d->val += mem_cgroup_read_stat(mem, d->idx);
- return 0;
-}
+ struct mem_cgroup *iter;
+ s64 val = 0;
-static void
-mem_cgroup_get_recursive_idx_stat(struct mem_cgroup *mem,
- enum mem_cgroup_stat_index idx, s64 *val)
-{
- struct mem_cgroup_idx_data d;
- d.idx = idx;
- d.val = 0;
- mem_cgroup_walk_tree(mem, &d, mem_cgroup_get_idx_stat);
- *val = d.val;
+ /* each per cpu's value can be minus.Then, use s64 */
+ for_each_mem_cgroup_tree(iter, mem)
+ val += mem_cgroup_read_stat(iter, idx);
+
+ if (val < 0) /* race ? */
+ val = 0;
+ return val;
}
static inline u64 mem_cgroup_usage(struct mem_cgroup *mem, bool swap)
{
- u64 idx_val, val;
+ u64 val;
if (!mem_cgroup_is_root(mem)) {
if (!swap)
@@ -3172,16 +3354,12 @@ static inline u64 mem_cgroup_usage(struct mem_cgroup *mem, bool swap)
return res_counter_read_u64(&mem->memsw, RES_USAGE);
}
- mem_cgroup_get_recursive_idx_stat(mem, MEM_CGROUP_STAT_CACHE, &idx_val);
- val = idx_val;
- mem_cgroup_get_recursive_idx_stat(mem, MEM_CGROUP_STAT_RSS, &idx_val);
- val += idx_val;
+ val = mem_cgroup_get_recursive_idx_stat(mem, MEM_CGROUP_STAT_CACHE);
+ val += mem_cgroup_get_recursive_idx_stat(mem, MEM_CGROUP_STAT_RSS);
- if (swap) {
- mem_cgroup_get_recursive_idx_stat(mem,
- MEM_CGROUP_STAT_SWAPOUT, &idx_val);
- val += idx_val;
- }
+ if (swap)
+ val += mem_cgroup_get_recursive_idx_stat(mem,
+ MEM_CGROUP_STAT_SWAPOUT);
return val << PAGE_SHIFT;
}
@@ -3389,9 +3567,9 @@ struct {
};
-static int mem_cgroup_get_local_stat(struct mem_cgroup *mem, void *data)
+static void
+mem_cgroup_get_local_stat(struct mem_cgroup *mem, struct mcs_total_stat *s)
{
- struct mcs_total_stat *s = data;
s64 val;
/* per cpu stat */
@@ -3421,13 +3599,15 @@ static int mem_cgroup_get_local_stat(struct mem_cgroup *mem, void *data)
s->stat[MCS_ACTIVE_FILE] += val * PAGE_SIZE;
val = mem_cgroup_get_local_zonestat(mem, LRU_UNEVICTABLE);
s->stat[MCS_UNEVICTABLE] += val * PAGE_SIZE;
- return 0;
}
static void
mem_cgroup_get_total_stat(struct mem_cgroup *mem, struct mcs_total_stat *s)
{
- mem_cgroup_walk_tree(mem, s, mem_cgroup_get_local_stat);
+ struct mem_cgroup *iter;
+
+ for_each_mem_cgroup_tree(iter, mem)
+ mem_cgroup_get_local_stat(iter, s);
}
static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
@@ -3604,7 +3784,7 @@ static int compare_thresholds(const void *a, const void *b)
return _a->threshold - _b->threshold;
}
-static int mem_cgroup_oom_notify_cb(struct mem_cgroup *mem, void *data)
+static int mem_cgroup_oom_notify_cb(struct mem_cgroup *mem)
{
struct mem_cgroup_eventfd_list *ev;
@@ -3615,7 +3795,10 @@ static int mem_cgroup_oom_notify_cb(struct mem_cgroup *mem, void *data)
static void mem_cgroup_oom_notify(struct mem_cgroup *mem)
{
- mem_cgroup_walk_tree(mem, NULL, mem_cgroup_oom_notify_cb);
+ struct mem_cgroup *iter;
+
+ for_each_mem_cgroup_tree(iter, mem)
+ mem_cgroup_oom_notify_cb(iter);
}
static int mem_cgroup_usage_register_event(struct cgroup *cgrp,
@@ -4032,6 +4215,7 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
vfree(mem);
mem = NULL;
}
+ spin_lock_init(&mem->pcp_counter_lock);
return mem;
}
@@ -4158,7 +4342,7 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
&per_cpu(memcg_stock, cpu);
INIT_WORK(&stock->work, drain_local_stock);
}
- hotcpu_notifier(memcg_stock_cpu_callback, 0);
+ hotcpu_notifier(memcg_cpu_hotplug_callback, 0);
} else {
parent = mem_cgroup_from_cont(cont->parent);
mem->use_hierarchy = parent->use_hierarchy;
@@ -4513,6 +4697,7 @@ static void mem_cgroup_clear_mc(void)
mc.to = NULL;
mc.moving_task = NULL;
spin_unlock(&mc.lock);
+ mem_cgroup_end_move(from);
memcg_oom_recover(from);
memcg_oom_recover(to);
wake_up_all(&mc.waitq);
@@ -4543,6 +4728,7 @@ static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
VM_BUG_ON(mc.moved_charge);
VM_BUG_ON(mc.moved_swap);
VM_BUG_ON(mc.moving_task);
+ mem_cgroup_start_move(from);
spin_lock(&mc.lock);
mc.from = from;
mc.to = mem;
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 757f6b0accfe..124324134ff6 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -7,21 +7,26 @@
* Free Software Foundation.
*
* High level machine check handler. Handles pages reported by the
- * hardware as being corrupted usually due to a 2bit ECC memory or cache
+ * hardware as being corrupted usually due to a multi-bit ECC memory or cache
* failure.
+ *
+ * In addition there is a "soft offline" entry point that allows stop using
+ * not-yet-corrupted-by-suspicious pages without killing anything.
*
* Handles page cache pages in various states. The tricky part
- * here is that we can access any page asynchronous to other VM
- * users, because memory failures could happen anytime and anywhere,
- * possibly violating some of their assumptions. This is why this code
- * has to be extremely careful. Generally it tries to use normal locking
- * rules, as in get the standard locks, even if that means the
- * error handling takes potentially a long time.
- *
- * The operation to map back from RMAP chains to processes has to walk
- * the complete process list and has non linear complexity with the number
- * mappings. In short it can be quite slow. But since memory corruptions
- * are rare we hope to get away with this.
+ * here is that we can access any page asynchronously in respect to
+ * other VM users, because memory failures could happen anytime and
+ * anywhere. This could violate some of their assumptions. This is why
+ * this code has to be extremely careful. Generally it tries to use
+ * normal locking rules, as in get the standard locks, even if that means
+ * the error handling takes potentially a long time.
+ *
+ * There are several operations here with exponential complexity because
+ * of unsuitable VM data structures. For example the operation to map back
+ * from RMAP chains to processes has to walk the complete process list and
+ * has non linear complexity with the number. But since memory corruptions
+ * are rare we hope to get away with this. This avoids impacting the core
+ * VM.
*/
/*
@@ -30,7 +35,6 @@
* - kcore/oldmem/vmcore/mem/kmem check for hwpoison pages
* - pass bad pages to kdump next kernel
*/
-#define DEBUG 1 /* remove me in 2.6.34 */
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/page-flags.h>
@@ -78,7 +82,7 @@ static int hwpoison_filter_dev(struct page *p)
return 0;
/*
- * page_mapping() does not accept slab page
+ * page_mapping() does not accept slab pages.
*/
if (PageSlab(p))
return -EINVAL;
@@ -268,7 +272,7 @@ struct to_kill {
struct list_head nd;
struct task_struct *tsk;
unsigned long addr;
- unsigned addr_valid:1;
+ char addr_valid;
};
/*
@@ -309,7 +313,7 @@ static void add_to_kill(struct task_struct *tsk, struct page *p,
* a SIGKILL because the error is not contained anymore.
*/
if (tk->addr == -EFAULT) {
- pr_debug("MCE: Unable to find user space address %lx in %s\n",
+ pr_info("MCE: Unable to find user space address %lx in %s\n",
page_to_pfn(p), tsk->comm);
tk->addr_valid = 0;
}
@@ -577,7 +581,7 @@ static int me_pagecache_clean(struct page *p, unsigned long pfn)
pfn, err);
} else if (page_has_private(p) &&
!try_to_release_page(p, GFP_NOIO)) {
- pr_debug("MCE %#lx: failed to release buffers\n", pfn);
+ pr_info("MCE %#lx: failed to release buffers\n", pfn);
} else {
ret = RECOVERED;
}
@@ -693,11 +697,10 @@ static int me_swapcache_clean(struct page *p, unsigned long pfn)
* Issues:
* - Error on hugepage is contained in hugepage unit (not in raw page unit.)
* To narrow down kill region to one page, we need to break up pmd.
- * - To support soft-offlining for hugepage, we need to support hugepage
- * migration.
*/
static int me_huge_page(struct page *p, unsigned long pfn)
{
+ int res = 0;
struct page *hpage = compound_head(p);
/*
* We can safely recover from error on free or reserved (i.e.
@@ -710,8 +713,9 @@ static int me_huge_page(struct page *p, unsigned long pfn)
* so there is no race between isolation and mapping/unmapping.
*/
if (!(page_mapping(hpage) || PageAnon(hpage))) {
- __isolate_hwpoisoned_huge_page(hpage);
- return RECOVERED;
+ res = dequeue_hwpoisoned_huge_page(hpage);
+ if (!res)
+ return RECOVERED;
}
return DELAYED;
}
@@ -836,8 +840,6 @@ static int page_action(struct page_state *ps, struct page *p,
return (result == RECOVERED || result == DELAYED) ? 0 : -EBUSY;
}
-#define N_UNMAP_TRIES 5
-
/*
* Do all that is necessary to remove user space mappings. Unmap
* the pages and send SIGBUS to the processes if the data was dirty.
@@ -849,7 +851,6 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
struct address_space *mapping;
LIST_HEAD(tokill);
int ret;
- int i;
int kill = 1;
struct page *hpage = compound_head(p);
@@ -903,17 +904,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
if (kill)
collect_procs(hpage, &tokill);
- /*
- * try_to_unmap can fail temporarily due to races.
- * Try a few times (RED-PEN better strategy?)
- */
- for (i = 0; i < N_UNMAP_TRIES; i++) {
- ret = try_to_unmap(hpage, ttu);
- if (ret == SWAP_SUCCESS)
- break;
- pr_debug("MCE %#lx: try_to_unmap retry needed %d\n", pfn, ret);
- }
-
+ ret = try_to_unmap(hpage, ttu);
if (ret != SWAP_SUCCESS)
printk(KERN_ERR "MCE %#lx: failed to unmap page (mapcount=%d)\n",
pfn, page_mapcount(hpage));
@@ -981,7 +972,10 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
* We need/can do nothing about count=0 pages.
* 1) it's a free page, and therefore in safe hand:
* prep_new_page() will be the gate keeper.
- * 2) it's part of a non-compound high order page.
+ * 2) it's a free hugepage, which is also safe:
+ * an affected hugepage will be dequeued from hugepage freelist,
+ * so there's no concern about reusing it ever after.
+ * 3) it's part of a non-compound high order page.
* Implies some kernel user: cannot stop them from
* R/W the page; let's pray that the page has been
* used and will be freed some time later.
@@ -993,6 +987,24 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
if (is_free_buddy_page(p)) {
action_result(pfn, "free buddy", DELAYED);
return 0;
+ } else if (PageHuge(hpage)) {
+ /*
+ * Check "just unpoisoned", "filter hit", and
+ * "race with other subpage."
+ */
+ lock_page_nosync(hpage);
+ if (!PageHWPoison(hpage)
+ || (hwpoison_filter(p) && TestClearPageHWPoison(p))
+ || (p != hpage && TestSetPageHWPoison(hpage))) {
+ atomic_long_sub(nr_pages, &mce_bad_pages);
+ return 0;
+ }
+ set_page_hwpoison_huge_page(hpage);
+ res = dequeue_hwpoisoned_huge_page(hpage);
+ action_result(pfn, "free huge",
+ res ? IGNORED : DELAYED);
+ unlock_page(hpage);
+ return res;
} else {
action_result(pfn, "high order kernel", IGNORED);
return -EBUSY;
@@ -1147,16 +1159,26 @@ int unpoison_memory(unsigned long pfn)
page = compound_head(p);
if (!PageHWPoison(p)) {
- pr_debug("MCE: Page was already unpoisoned %#lx\n", pfn);
+ pr_info("MCE: Page was already unpoisoned %#lx\n", pfn);
return 0;
}
nr_pages = 1 << compound_order(page);
if (!get_page_unless_zero(page)) {
+ /*
+ * Since HWPoisoned hugepage should have non-zero refcount,
+ * race between memory failure and unpoison seems to happen.
+ * In such case unpoison fails and memory failure runs
+ * to the end.
+ */
+ if (PageHuge(page)) {
+ pr_debug("MCE: Memory failure is now running on free hugepage %#lx\n", pfn);
+ return 0;
+ }
if (TestClearPageHWPoison(p))
atomic_long_sub(nr_pages, &mce_bad_pages);
- pr_debug("MCE: Software-unpoisoned free page %#lx\n", pfn);
+ pr_info("MCE: Software-unpoisoned free page %#lx\n", pfn);
return 0;
}
@@ -1168,12 +1190,12 @@ int unpoison_memory(unsigned long pfn)
* the free buddy page pool.
*/
if (TestClearPageHWPoison(page)) {
- pr_debug("MCE: Software-unpoisoned page %#lx\n", pfn);
+ pr_info("MCE: Software-unpoisoned page %#lx\n", pfn);
atomic_long_sub(nr_pages, &mce_bad_pages);
freeit = 1;
+ if (PageHuge(page))
+ clear_page_hwpoison_huge_page(page);
}
- if (PageHuge(p))
- clear_page_hwpoison_huge_page(page);
unlock_page(page);
put_page(page);
@@ -1187,7 +1209,11 @@ EXPORT_SYMBOL(unpoison_memory);
static struct page *new_page(struct page *p, unsigned long private, int **x)
{
int nid = page_to_nid(p);
- return alloc_pages_exact_node(nid, GFP_HIGHUSER_MOVABLE, 0);
+ if (PageHuge(p))
+ return alloc_huge_page_node(page_hstate(compound_head(p)),
+ nid);
+ else
+ return alloc_pages_exact_node(nid, GFP_HIGHUSER_MOVABLE, 0);
}
/*
@@ -1215,14 +1241,21 @@ static int get_any_page(struct page *p, unsigned long pfn, int flags)
* was free.
*/
set_migratetype_isolate(p);
+ /*
+ * When the target page is a free hugepage, just remove it
+ * from free hugepage list.
+ */
if (!get_page_unless_zero(compound_head(p))) {
- if (is_free_buddy_page(p)) {
- pr_debug("get_any_page: %#lx free buddy page\n", pfn);
+ if (PageHuge(p)) {
+ pr_info("get_any_page: %#lx free huge page\n", pfn);
+ ret = dequeue_hwpoisoned_huge_page(compound_head(p));
+ } else if (is_free_buddy_page(p)) {
+ pr_info("get_any_page: %#lx free buddy page\n", pfn);
/* Set hwpoison bit while page is still isolated */
SetPageHWPoison(p);
ret = 0;
} else {
- pr_debug("get_any_page: %#lx: unknown zero refcount page type %lx\n",
+ pr_info("get_any_page: %#lx: unknown zero refcount page type %lx\n",
pfn, p->flags);
ret = -EIO;
}
@@ -1235,6 +1268,46 @@ static int get_any_page(struct page *p, unsigned long pfn, int flags)
return ret;
}
+static int soft_offline_huge_page(struct page *page, int flags)
+{
+ int ret;
+ unsigned long pfn = page_to_pfn(page);
+ struct page *hpage = compound_head(page);
+ LIST_HEAD(pagelist);
+
+ ret = get_any_page(page, pfn, flags);
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ goto done;
+
+ if (PageHWPoison(hpage)) {
+ put_page(hpage);
+ pr_debug("soft offline: %#lx hugepage already poisoned\n", pfn);
+ return -EBUSY;
+ }
+
+ /* Keep page count to indicate a given hugepage is isolated. */
+
+ list_add(&hpage->lru, &pagelist);
+ ret = migrate_huge_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL, 0);
+ if (ret) {
+ putback_lru_pages(&pagelist);
+ pr_debug("soft offline: %#lx: migration failed %d, type %lx\n",
+ pfn, ret, page->flags);
+ if (ret > 0)
+ ret = -EIO;
+ return ret;
+ }
+done:
+ if (!PageHWPoison(hpage))
+ atomic_long_add(1 << compound_order(hpage), &mce_bad_pages);
+ set_page_hwpoison_huge_page(hpage);
+ dequeue_hwpoisoned_huge_page(hpage);
+ /* keep elevated page count for bad page */
+ return ret;
+}
+
/**
* soft_offline_page - Soft offline a page.
* @page: page to offline
@@ -1262,6 +1335,9 @@ int soft_offline_page(struct page *page, int flags)
int ret;
unsigned long pfn = page_to_pfn(page);
+ if (PageHuge(page))
+ return soft_offline_huge_page(page, flags);
+
ret = get_any_page(page, pfn, flags);
if (ret < 0)
return ret;
@@ -1288,7 +1364,7 @@ int soft_offline_page(struct page *page, int flags)
goto done;
}
if (!PageLRU(page)) {
- pr_debug("soft_offline: %#lx: unknown non LRU page type %lx\n",
+ pr_info("soft_offline: %#lx: unknown non LRU page type %lx\n",
pfn, page->flags);
return -EIO;
}
@@ -1302,7 +1378,7 @@ int soft_offline_page(struct page *page, int flags)
if (PageHWPoison(page)) {
unlock_page(page);
put_page(page);
- pr_debug("soft offline: %#lx page already poisoned\n", pfn);
+ pr_info("soft offline: %#lx page already poisoned\n", pfn);
return -EBUSY;
}
@@ -1323,7 +1399,7 @@ int soft_offline_page(struct page *page, int flags)
put_page(page);
if (ret == 1) {
ret = 0;
- pr_debug("soft_offline: %#lx: invalidated\n", pfn);
+ pr_info("soft_offline: %#lx: invalidated\n", pfn);
goto done;
}
@@ -1339,13 +1415,13 @@ int soft_offline_page(struct page *page, int flags)
list_add(&page->lru, &pagelist);
ret = migrate_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL, 0);
if (ret) {
- pr_debug("soft offline: %#lx: migration failed %d, type %lx\n",
+ pr_info("soft offline: %#lx: migration failed %d, type %lx\n",
pfn, ret, page->flags);
if (ret > 0)
ret = -EIO;
}
} else {
- pr_debug("soft offline: %#lx: isolation failed: %d, page count %d, type %lx\n",
+ pr_info("soft offline: %#lx: isolation failed: %d, page count %d, type %lx\n",
pfn, ret, page_count(page), page->flags);
}
if (ret)
diff --git a/mm/memory.c b/mm/memory.c
index 98b58fecedef..02e48aa0ed13 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -736,7 +736,7 @@ again:
dst_pte = pte_alloc_map_lock(dst_mm, dst_pmd, addr, &dst_ptl);
if (!dst_pte)
return -ENOMEM;
- src_pte = pte_offset_map_nested(src_pmd, addr);
+ src_pte = pte_offset_map(src_pmd, addr);
src_ptl = pte_lockptr(src_mm, src_pmd);
spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
orig_src_pte = src_pte;
@@ -767,7 +767,7 @@ again:
arch_leave_lazy_mmu_mode();
spin_unlock(src_ptl);
- pte_unmap_nested(orig_src_pte);
+ pte_unmap(orig_src_pte);
add_mm_rss_vec(dst_mm, rss);
pte_unmap_unlock(orig_dst_pte, dst_ptl);
cond_resched();
@@ -1450,7 +1450,8 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
if (ret & VM_FAULT_OOM)
return i ? i : -ENOMEM;
if (ret &
- (VM_FAULT_HWPOISON|VM_FAULT_SIGBUS))
+ (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE|
+ VM_FAULT_SIGBUS))
return i ? i : -EFAULT;
BUG();
}
@@ -1590,7 +1591,7 @@ struct page *get_dump_page(unsigned long addr)
}
#endif /* CONFIG_ELF_CORE */
-pte_t *get_locked_pte(struct mm_struct *mm, unsigned long addr,
+pte_t *__get_locked_pte(struct mm_struct *mm, unsigned long addr,
spinlock_t **ptl)
{
pgd_t * pgd = pgd_offset(mm, addr);
@@ -2079,7 +2080,7 @@ static inline void cow_user_page(struct page *dst, struct page *src, unsigned lo
* zeroes.
*/
if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE))
- memset(kaddr, 0, PAGE_SIZE);
+ clear_page(kaddr);
kunmap_atomic(kaddr, KM_USER0);
flush_dcache_page(dst);
} else
@@ -2107,6 +2108,7 @@ static inline void cow_user_page(struct page *dst, struct page *src, unsigned lo
static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long address, pte_t *page_table, pmd_t *pmd,
spinlock_t *ptl, pte_t orig_pte)
+ __releases(ptl)
{
struct page *old_page, *new_page;
pte_t entry;
@@ -2626,6 +2628,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
struct page *page, *swapcache = NULL;
swp_entry_t entry;
pte_t pte;
+ int locked;
struct mem_cgroup *ptr = NULL;
int exclusive = 0;
int ret = 0;
@@ -2676,8 +2679,12 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
goto out_release;
}
- lock_page(page);
+ locked = lock_page_or_retry(page, mm, flags);
delayacct_clear_flag(DELAYACCT_PF_SWAPIN);
+ if (!locked) {
+ ret |= VM_FAULT_RETRY;
+ goto out_release;
+ }
/*
* Make sure try_to_free_swap or reuse_swap_page or swapoff did not
@@ -2926,7 +2933,8 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
vmf.page = NULL;
ret = vma->vm_ops->fault(vma, &vmf);
- if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE)))
+ if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE |
+ VM_FAULT_RETRY)))
return ret;
if (unlikely(PageHWPoison(vmf.page))) {
@@ -3343,7 +3351,7 @@ int in_gate_area_no_task(unsigned long addr)
#endif /* __HAVE_ARCH_GATE_AREA */
-static int follow_pte(struct mm_struct *mm, unsigned long address,
+static int __follow_pte(struct mm_struct *mm, unsigned long address,
pte_t **ptepp, spinlock_t **ptlp)
{
pgd_t *pgd;
@@ -3380,6 +3388,17 @@ out:
return -EINVAL;
}
+static inline int follow_pte(struct mm_struct *mm, unsigned long address,
+ pte_t **ptepp, spinlock_t **ptlp)
+{
+ int res;
+
+ /* (void) is needed to make gcc happy */
+ (void) __cond_lock(*ptlp,
+ !(res = __follow_pte(mm, address, ptepp, ptlp)));
+ return res;
+}
+
/**
* follow_pfn - look up PFN at a user virtual address
* @vma: memory mapping
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index d4e940a26945..9260314a221e 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -602,27 +602,14 @@ static struct page *next_active_pageblock(struct page *page)
/* Checks if this range of memory is likely to be hot-removable. */
int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages)
{
- int type;
struct page *page = pfn_to_page(start_pfn);
struct page *end_page = page + nr_pages;
/* Check the starting page of each pageblock within the range */
for (; page < end_page; page = next_active_pageblock(page)) {
- type = get_pageblock_migratetype(page);
-
- /*
- * A pageblock containing MOVABLE or free pages is considered
- * removable
- */
- if (type != MIGRATE_MOVABLE && !pageblock_free(page))
- return 0;
-
- /*
- * A pageblock starting with a PageReserved page is not
- * considered removable.
- */
- if (PageReserved(page))
+ if (!is_pageblock_removable_nolock(page))
return 0;
+ cond_resched();
}
/* All pageblocks in the memory block are likely to be hot-removable */
@@ -659,7 +646,7 @@ static int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
* Scanning pfn is much easier than scanning lru list.
* Scan pfn from start to end and Find LRU page.
*/
-int scan_lru_pages(unsigned long start, unsigned long end)
+static unsigned long scan_lru_pages(unsigned long start, unsigned long end)
{
unsigned long pfn;
struct page *page;
@@ -709,29 +696,30 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
page_is_file_cache(page));
} else {
- /* Becasue we don't have big zone->lock. we should
- check this again here. */
- if (page_count(page))
- not_managed++;
#ifdef CONFIG_DEBUG_VM
printk(KERN_ALERT "removing pfn %lx from LRU failed\n",
pfn);
dump_page(page);
#endif
+ /* Becasue we don't have big zone->lock. we should
+ check this again here. */
+ if (page_count(page)) {
+ not_managed++;
+ ret = -EBUSY;
+ break;
+ }
}
}
- ret = -EBUSY;
- if (not_managed) {
- if (!list_empty(&source))
+ if (!list_empty(&source)) {
+ if (not_managed) {
+ putback_lru_pages(&source);
+ goto out;
+ }
+ /* this function returns # of failed pages */
+ ret = migrate_pages(&source, hotremove_migrate_alloc, 0, 1);
+ if (ret)
putback_lru_pages(&source);
- goto out;
}
- ret = 0;
- if (list_empty(&source))
- goto out;
- /* this function returns # of failed pages */
- ret = migrate_pages(&source, hotremove_migrate_alloc, 0, 1);
-
out:
return ret;
}
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index f969da5dd8a2..81a127643aea 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -924,15 +924,21 @@ static int migrate_to_node(struct mm_struct *mm, int source, int dest,
nodemask_t nmask;
LIST_HEAD(pagelist);
int err = 0;
+ struct vm_area_struct *vma;
nodes_clear(nmask);
node_set(source, nmask);
- check_range(mm, mm->mmap->vm_start, mm->task_size, &nmask,
+ vma = check_range(mm, mm->mmap->vm_start, mm->task_size, &nmask,
flags | MPOL_MF_DISCONTIG_OK, &pagelist);
+ if (IS_ERR(vma))
+ return PTR_ERR(vma);
- if (!list_empty(&pagelist))
+ if (!list_empty(&pagelist)) {
err = migrate_pages(&pagelist, new_node_page, dest, 0);
+ if (err)
+ putback_lru_pages(&pagelist);
+ }
return err;
}
@@ -1147,9 +1153,12 @@ static long do_mbind(unsigned long start, unsigned long len,
err = mbind_range(mm, start, end, new);
- if (!list_empty(&pagelist))
+ if (!list_empty(&pagelist)) {
nr_failed = migrate_pages(&pagelist, new_vma_page,
(unsigned long)vma, 0);
+ if (nr_failed)
+ putback_lru_pages(&pagelist);
+ }
if (!err && nr_failed && (flags & MPOL_MF_STRICT))
err = -EIO;
diff --git a/mm/migrate.c b/mm/migrate.c
index 38e7cad782f4..fe5a3c6a5426 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -32,6 +32,7 @@
#include <linux/security.h>
#include <linux/memcontrol.h>
#include <linux/syscalls.h>
+#include <linux/hugetlb.h>
#include <linux/gfp.h>
#include "internal.h"
@@ -95,26 +96,34 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma,
pte_t *ptep, pte;
spinlock_t *ptl;
- pgd = pgd_offset(mm, addr);
- if (!pgd_present(*pgd))
- goto out;
+ if (unlikely(PageHuge(new))) {
+ ptep = huge_pte_offset(mm, addr);
+ if (!ptep)
+ goto out;
+ ptl = &mm->page_table_lock;
+ } else {
+ pgd = pgd_offset(mm, addr);
+ if (!pgd_present(*pgd))
+ goto out;
- pud = pud_offset(pgd, addr);
- if (!pud_present(*pud))
- goto out;
+ pud = pud_offset(pgd, addr);
+ if (!pud_present(*pud))
+ goto out;
- pmd = pmd_offset(pud, addr);
- if (!pmd_present(*pmd))
- goto out;
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_present(*pmd))
+ goto out;
- ptep = pte_offset_map(pmd, addr);
+ ptep = pte_offset_map(pmd, addr);
- if (!is_swap_pte(*ptep)) {
- pte_unmap(ptep);
- goto out;
- }
+ if (!is_swap_pte(*ptep)) {
+ pte_unmap(ptep);
+ goto out;
+ }
+
+ ptl = pte_lockptr(mm, pmd);
+ }
- ptl = pte_lockptr(mm, pmd);
spin_lock(ptl);
pte = *ptep;
if (!is_swap_pte(pte))
@@ -130,10 +139,19 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma,
pte = pte_mkold(mk_pte(new, vma->vm_page_prot));
if (is_write_migration_entry(entry))
pte = pte_mkwrite(pte);
+#ifdef CONFIG_HUGETLB_PAGE
+ if (PageHuge(new))
+ pte = pte_mkhuge(pte);
+#endif
flush_cache_page(vma, addr, pte_pfn(pte));
set_pte_at(mm, addr, ptep, pte);
- if (PageAnon(new))
+ if (PageHuge(new)) {
+ if (PageAnon(new))
+ hugepage_add_anon_rmap(new, vma, addr);
+ else
+ page_dup_rmap(new);
+ } else if (PageAnon(new))
page_add_anon_rmap(new, vma, addr);
else
page_add_file_rmap(new);
@@ -276,11 +294,59 @@ static int migrate_page_move_mapping(struct address_space *mapping,
}
/*
+ * The expected number of remaining references is the same as that
+ * of migrate_page_move_mapping().
+ */
+int migrate_huge_page_move_mapping(struct address_space *mapping,
+ struct page *newpage, struct page *page)
+{
+ int expected_count;
+ void **pslot;
+
+ if (!mapping) {
+ if (page_count(page) != 1)
+ return -EAGAIN;
+ return 0;
+ }
+
+ spin_lock_irq(&mapping->tree_lock);
+
+ pslot = radix_tree_lookup_slot(&mapping->page_tree,
+ page_index(page));
+
+ expected_count = 2 + page_has_private(page);
+ if (page_count(page) != expected_count ||
+ (struct page *)radix_tree_deref_slot(pslot) != page) {
+ spin_unlock_irq(&mapping->tree_lock);
+ return -EAGAIN;
+ }
+
+ if (!page_freeze_refs(page, expected_count)) {
+ spin_unlock_irq(&mapping->tree_lock);
+ return -EAGAIN;
+ }
+
+ get_page(newpage);
+
+ radix_tree_replace_slot(pslot, newpage);
+
+ page_unfreeze_refs(page, expected_count);
+
+ __put_page(page);
+
+ spin_unlock_irq(&mapping->tree_lock);
+ return 0;
+}
+
+/*
* Copy the page to its new location
*/
-static void migrate_page_copy(struct page *newpage, struct page *page)
+void migrate_page_copy(struct page *newpage, struct page *page)
{
- copy_highpage(newpage, page);
+ if (PageHuge(page))
+ copy_huge_page(newpage, page);
+ else
+ copy_highpage(newpage, page);
if (PageError(page))
SetPageError(newpage);
@@ -431,7 +497,6 @@ static int writeout(struct address_space *mapping, struct page *page)
.nr_to_write = 1,
.range_start = 0,
.range_end = LLONG_MAX,
- .nonblocking = 1,
.for_reclaim = 1
};
int rc;
@@ -724,6 +789,92 @@ move_newpage:
}
/*
+ * Counterpart of unmap_and_move_page() for hugepage migration.
+ *
+ * This function doesn't wait the completion of hugepage I/O
+ * because there is no race between I/O and migration for hugepage.
+ * Note that currently hugepage I/O occurs only in direct I/O
+ * where no lock is held and PG_writeback is irrelevant,
+ * and writeback status of all subpages are counted in the reference
+ * count of the head page (i.e. if all subpages of a 2MB hugepage are
+ * under direct I/O, the reference of the head page is 512 and a bit more.)
+ * This means that when we try to migrate hugepage whose subpages are
+ * doing direct I/O, some references remain after try_to_unmap() and
+ * hugepage migration fails without data corruption.
+ *
+ * There is also no race when direct I/O is issued on the page under migration,
+ * because then pte is replaced with migration swap entry and direct I/O code
+ * will wait in the page fault for migration to complete.
+ */
+static int unmap_and_move_huge_page(new_page_t get_new_page,
+ unsigned long private, struct page *hpage,
+ int force, int offlining)
+{
+ int rc = 0;
+ int *result = NULL;
+ struct page *new_hpage = get_new_page(hpage, private, &result);
+ int rcu_locked = 0;
+ struct anon_vma *anon_vma = NULL;
+
+ if (!new_hpage)
+ return -ENOMEM;
+
+ rc = -EAGAIN;
+
+ if (!trylock_page(hpage)) {
+ if (!force)
+ goto out;
+ lock_page(hpage);
+ }
+
+ if (PageAnon(hpage)) {
+ rcu_read_lock();
+ rcu_locked = 1;
+
+ if (page_mapped(hpage)) {
+ anon_vma = page_anon_vma(hpage);
+ atomic_inc(&anon_vma->external_refcount);
+ }
+ }
+
+ try_to_unmap(hpage, TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
+
+ if (!page_mapped(hpage))
+ rc = move_to_new_page(new_hpage, hpage, 1);
+
+ if (rc)
+ remove_migration_ptes(hpage, hpage);
+
+ if (anon_vma && atomic_dec_and_lock(&anon_vma->external_refcount,
+ &anon_vma->lock)) {
+ int empty = list_empty(&anon_vma->head);
+ spin_unlock(&anon_vma->lock);
+ if (empty)
+ anon_vma_free(anon_vma);
+ }
+
+ if (rcu_locked)
+ rcu_read_unlock();
+out:
+ unlock_page(hpage);
+
+ if (rc != -EAGAIN) {
+ list_del(&hpage->lru);
+ put_page(hpage);
+ }
+
+ put_page(new_hpage);
+
+ if (result) {
+ if (rc)
+ *result = rc;
+ else
+ *result = page_to_nid(new_hpage);
+ }
+ return rc;
+}
+
+/*
* migrate_pages
*
* The function takes one list of pages to migrate and a function
@@ -732,8 +883,9 @@ move_newpage:
*
* The function returns after 10 attempts or if no pages
* are movable anymore because to has become empty
- * or no retryable pages exist anymore. All pages will be
- * returned to the LRU or freed.
+ * or no retryable pages exist anymore.
+ * Caller should call putback_lru_pages to return pages to the LRU
+ * or free list.
*
* Return: Number of pages not migrated or error code.
*/
@@ -780,7 +932,51 @@ out:
if (!swapwrite)
current->flags &= ~PF_SWAPWRITE;
- putback_lru_pages(from);
+ if (rc)
+ return rc;
+
+ return nr_failed + retry;
+}
+
+int migrate_huge_pages(struct list_head *from,
+ new_page_t get_new_page, unsigned long private, int offlining)
+{
+ int retry = 1;
+ int nr_failed = 0;
+ int pass = 0;
+ struct page *page;
+ struct page *page2;
+ int rc;
+
+ for (pass = 0; pass < 10 && retry; pass++) {
+ retry = 0;
+
+ list_for_each_entry_safe(page, page2, from, lru) {
+ cond_resched();
+
+ rc = unmap_and_move_huge_page(get_new_page,
+ private, page, pass > 2, offlining);
+
+ switch(rc) {
+ case -ENOMEM:
+ goto out;
+ case -EAGAIN:
+ retry++;
+ break;
+ case 0:
+ break;
+ default:
+ /* Permanent failure */
+ nr_failed++;
+ break;
+ }
+ }
+ }
+ rc = 0;
+out:
+
+ list_for_each_entry_safe(page, page2, from, lru)
+ put_page(page);
if (rc)
return rc;
@@ -841,7 +1037,7 @@ static int do_move_page_to_node_array(struct mm_struct *mm,
err = -EFAULT;
vma = find_vma(mm, pp->addr);
- if (!vma || !vma_migratable(vma))
+ if (!vma || pp->addr < vma->vm_start || !vma_migratable(vma))
goto set_status;
page = follow_page(vma, pp->addr, FOLL_GET);
@@ -890,9 +1086,12 @@ set_status:
}
err = 0;
- if (!list_empty(&pagelist))
+ if (!list_empty(&pagelist)) {
err = migrate_pages(&pagelist, new_page_node,
(unsigned long)pm, 0);
+ if (err)
+ putback_lru_pages(&pagelist);
+ }
up_read(&mm->mmap_sem);
return err;
@@ -1005,7 +1204,7 @@ static void do_pages_stat_array(struct mm_struct *mm, unsigned long nr_pages,
int err = -EFAULT;
vma = find_vma(mm, addr);
- if (!vma)
+ if (!vma || addr < vma->vm_start)
goto set_status;
page = follow_page(vma, addr, 0);
diff --git a/mm/mremap.c b/mm/mremap.c
index cde56ee51ef7..563fbdd6293a 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -101,7 +101,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
* pte locks because exclusive mmap_sem prevents deadlock.
*/
old_pte = pte_offset_map_lock(mm, old_pmd, old_addr, &old_ptl);
- new_pte = pte_offset_map_nested(new_pmd, new_addr);
+ new_pte = pte_offset_map(new_pmd, new_addr);
new_ptl = pte_lockptr(mm, new_pmd);
if (new_ptl != old_ptl)
spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
@@ -119,7 +119,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
arch_leave_lazy_mmu_mode();
if (new_ptl != old_ptl)
spin_unlock(new_ptl);
- pte_unmap_nested(new_pte - 1);
+ pte_unmap(new_pte - 1);
pte_unmap_unlock(old_pte - 1, old_ptl);
if (mapping)
spin_unlock(&mapping->i_mmap_lock);
diff --git a/mm/nommu.c b/mm/nommu.c
index 88ff091eb07a..30b5c20eec15 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -293,11 +293,58 @@ void *vmalloc(unsigned long size)
}
EXPORT_SYMBOL(vmalloc);
+/*
+ * vzalloc - allocate virtually continguos memory with zero fill
+ *
+ * @size: allocation size
+ *
+ * Allocate enough pages to cover @size from the page level
+ * allocator and map them into continguos kernel virtual space.
+ * The memory allocated is set to zero.
+ *
+ * For tight control over page level allocator and protection flags
+ * use __vmalloc() instead.
+ */
+void *vzalloc(unsigned long size)
+{
+ return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
+ PAGE_KERNEL);
+}
+EXPORT_SYMBOL(vzalloc);
+
+/**
+ * vmalloc_node - allocate memory on a specific node
+ * @size: allocation size
+ * @node: numa node
+ *
+ * Allocate enough pages to cover @size from the page level
+ * allocator and map them into contiguous kernel virtual space.
+ *
+ * For tight control over page level allocator and protection flags
+ * use __vmalloc() instead.
+ */
void *vmalloc_node(unsigned long size, int node)
{
return vmalloc(size);
}
-EXPORT_SYMBOL(vmalloc_node);
+
+/**
+ * vzalloc_node - allocate memory on a specific node with zero fill
+ * @size: allocation size
+ * @node: numa node
+ *
+ * Allocate enough pages to cover @size from the page level
+ * allocator and map them into contiguous kernel virtual space.
+ * The memory allocated is set to zero.
+ *
+ * For tight control over page level allocator and protection flags
+ * use __vmalloc() instead.
+ */
+void *vzalloc_node(unsigned long size, int node)
+{
+ return vzalloc(size);
+}
+EXPORT_SYMBOL(vzalloc_node);
#ifndef PAGE_KERNEL_EXEC
# define PAGE_KERNEL_EXEC PAGE_KERNEL
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 4029583a1024..7dcca55ede7c 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -162,10 +162,11 @@ unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem,
return 0;
/*
- * Shortcut check for OOM_SCORE_ADJ_MIN so the entire heuristic doesn't
- * need to be executed for something that cannot be killed.
+ * Shortcut check for a thread sharing p->mm that is OOM_SCORE_ADJ_MIN
+ * so the entire heuristic doesn't need to be executed for something
+ * that cannot be killed.
*/
- if (p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {
+ if (atomic_read(&p->mm->oom_disable_count)) {
task_unlock(p);
return 0;
}
@@ -403,16 +404,40 @@ static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order,
#define K(x) ((x) << (PAGE_SHIFT-10))
static int oom_kill_task(struct task_struct *p, struct mem_cgroup *mem)
{
+ struct task_struct *q;
+ struct mm_struct *mm;
+
p = find_lock_task_mm(p);
if (!p)
return 1;
+ /* mm cannot be safely dereferenced after task_unlock(p) */
+ mm = p->mm;
+
pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB\n",
task_pid_nr(p), p->comm, K(p->mm->total_vm),
K(get_mm_counter(p->mm, MM_ANONPAGES)),
K(get_mm_counter(p->mm, MM_FILEPAGES)));
task_unlock(p);
+ /*
+ * Kill all processes sharing p->mm in other thread groups, if any.
+ * They don't get access to memory reserves or a higher scheduler
+ * priority, though, to avoid depletion of all memory or task
+ * starvation. This prevents mm->mmap_sem livelock when an oom killed
+ * task cannot exit because it requires the semaphore and its contended
+ * by another thread trying to allocate memory itself. That thread will
+ * now get access to memory reserves since it has a pending fatal
+ * signal.
+ */
+ for_each_process(q)
+ if (q->mm == mm && !same_thread_group(q, p)) {
+ task_lock(q); /* Protect ->comm from prctl() */
+ pr_err("Kill process %d (%s) sharing same memory\n",
+ task_pid_nr(q), q->comm);
+ task_unlock(q);
+ force_sig(SIGKILL, q);
+ }
set_tsk_thread_flag(p, TIF_MEMDIE);
force_sig(SIGKILL, p);
@@ -680,7 +705,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask,
read_lock(&tasklist_lock);
if (sysctl_oom_kill_allocating_task &&
!oom_unkillable_task(current, NULL, nodemask) &&
- (current->signal->oom_adj != OOM_DISABLE)) {
+ current->mm && !atomic_read(&current->mm->oom_disable_count)) {
/*
* oom_kill_process() needs tasklist_lock held. If it returns
* non-zero, current could not be killed so we must fallback to
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index e3bccac1f025..b840afa89761 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -415,14 +415,8 @@ void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty)
if (vm_dirty_bytes)
dirty = DIV_ROUND_UP(vm_dirty_bytes, PAGE_SIZE);
- else {
- int dirty_ratio;
-
- dirty_ratio = vm_dirty_ratio;
- if (dirty_ratio < 5)
- dirty_ratio = 5;
- dirty = (dirty_ratio * available_memory) / 100;
- }
+ else
+ dirty = (vm_dirty_ratio * available_memory) / 100;
if (dirty_background_bytes)
background = DIV_ROUND_UP(dirty_background_bytes, PAGE_SIZE);
@@ -510,7 +504,7 @@ static void balance_dirty_pages(struct address_space *mapping,
* catch-up. This avoids (excessively) small writeouts
* when the bdi limits are ramping up.
*/
- if (nr_reclaimable + nr_writeback <
+ if (nr_reclaimable + nr_writeback <=
(background_thresh + dirty_thresh) / 2)
break;
@@ -542,8 +536,8 @@ static void balance_dirty_pages(struct address_space *mapping,
* the last resort safeguard.
*/
dirty_exceeded =
- (bdi_nr_reclaimable + bdi_nr_writeback >= bdi_thresh)
- || (nr_reclaimable + nr_writeback >= dirty_thresh);
+ (bdi_nr_reclaimable + bdi_nr_writeback > bdi_thresh)
+ || (nr_reclaimable + nr_writeback > dirty_thresh);
if (!dirty_exceeded)
break;
@@ -1121,6 +1115,7 @@ void account_page_dirtied(struct page *page, struct address_space *mapping)
{
if (mapping_cap_account_dirty(mapping)) {
__inc_zone_page_state(page, NR_FILE_DIRTY);
+ __inc_zone_page_state(page, NR_DIRTIED);
__inc_bdi_stat(mapping->backing_dev_info, BDI_RECLAIMABLE);
task_dirty_inc(current);
task_io_account_write(PAGE_CACHE_SIZE);
@@ -1129,6 +1124,18 @@ void account_page_dirtied(struct page *page, struct address_space *mapping)
EXPORT_SYMBOL(account_page_dirtied);
/*
+ * Helper function for set_page_writeback family.
+ * NOTE: Unlike account_page_dirtied this does not rely on being atomic
+ * wrt interrupts.
+ */
+void account_page_writeback(struct page *page)
+{
+ inc_zone_page_state(page, NR_WRITEBACK);
+ inc_zone_page_state(page, NR_WRITTEN);
+}
+EXPORT_SYMBOL(account_page_writeback);
+
+/*
* For address_spaces which do not use buffers. Just tag the page as dirty in
* its radix tree.
*
@@ -1366,7 +1373,7 @@ int test_set_page_writeback(struct page *page)
ret = TestSetPageWriteback(page);
}
if (!ret)
- inc_zone_page_state(page, NR_WRITEBACK);
+ account_page_writeback(page);
return ret;
}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 2a362c52fdf4..07a654486f75 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -531,7 +531,7 @@ static inline void __free_one_page(struct page *page,
* so it's less likely to be used soon and more likely to be merged
* as a higher order page
*/
- if ((order < MAX_ORDER-1) && pfn_valid_within(page_to_pfn(buddy))) {
+ if ((order < MAX_ORDER-2) && pfn_valid_within(page_to_pfn(buddy))) {
struct page *higher_page, *higher_buddy;
combined_idx = __find_combined_index(page_idx, order);
higher_page = page + combined_idx - page_idx;
@@ -1907,7 +1907,7 @@ __alloc_pages_high_priority(gfp_t gfp_mask, unsigned int order,
preferred_zone, migratetype);
if (!page && gfp_mask & __GFP_NOFAIL)
- congestion_wait(BLK_RW_ASYNC, HZ/50);
+ wait_iff_congested(preferred_zone, BLK_RW_ASYNC, HZ/50);
} while (!page && (gfp_mask & __GFP_NOFAIL));
return page;
@@ -1932,7 +1932,7 @@ gfp_to_alloc_flags(gfp_t gfp_mask)
const gfp_t wait = gfp_mask & __GFP_WAIT;
/* __GFP_HIGH is assumed to be the same as ALLOC_HIGH to save a branch. */
- BUILD_BUG_ON(__GFP_HIGH != ALLOC_HIGH);
+ BUILD_BUG_ON(__GFP_HIGH != (__force gfp_t) ALLOC_HIGH);
/*
* The caller may dip into page reserves a bit more if the caller
@@ -1940,7 +1940,7 @@ gfp_to_alloc_flags(gfp_t gfp_mask)
* policy or is asking for __GFP_HIGH memory. GFP_ATOMIC requests will
* set both ALLOC_HARDER (!wait) and ALLOC_HIGH (__GFP_HIGH).
*/
- alloc_flags |= (gfp_mask & __GFP_HIGH);
+ alloc_flags |= (__force int) (gfp_mask & __GFP_HIGH);
if (!wait) {
alloc_flags |= ALLOC_HARDER;
@@ -2095,7 +2095,7 @@ rebalance:
pages_reclaimed += did_some_progress;
if (should_alloc_retry(gfp_mask, order, pages_reclaimed)) {
/* Wait for some write requests to complete then retry */
- congestion_wait(BLK_RW_ASYNC, HZ/50);
+ wait_iff_congested(preferred_zone, BLK_RW_ASYNC, HZ/50);
goto rebalance;
}
@@ -5297,12 +5297,65 @@ void set_pageblock_flags_group(struct page *page, unsigned long flags,
* page allocater never alloc memory from ISOLATE block.
*/
+static int
+__count_immobile_pages(struct zone *zone, struct page *page, int count)
+{
+ unsigned long pfn, iter, found;
+ /*
+ * For avoiding noise data, lru_add_drain_all() should be called
+ * If ZONE_MOVABLE, the zone never contains immobile pages
+ */
+ if (zone_idx(zone) == ZONE_MOVABLE)
+ return true;
+
+ if (get_pageblock_migratetype(page) == MIGRATE_MOVABLE)
+ return true;
+
+ pfn = page_to_pfn(page);
+ for (found = 0, iter = 0; iter < pageblock_nr_pages; iter++) {
+ unsigned long check = pfn + iter;
+
+ if (!pfn_valid_within(check)) {
+ iter++;
+ continue;
+ }
+ page = pfn_to_page(check);
+ if (!page_count(page)) {
+ if (PageBuddy(page))
+ iter += (1 << page_order(page)) - 1;
+ continue;
+ }
+ if (!PageLRU(page))
+ found++;
+ /*
+ * If there are RECLAIMABLE pages, we need to check it.
+ * But now, memory offline itself doesn't call shrink_slab()
+ * and it still to be fixed.
+ */
+ /*
+ * If the page is not RAM, page_count()should be 0.
+ * we don't need more check. This is an _used_ not-movable page.
+ *
+ * The problematic thing here is PG_reserved pages. PG_reserved
+ * is set to both of a memory hole page and a _used_ kernel
+ * page at boot.
+ */
+ if (found > count)
+ return false;
+ }
+ return true;
+}
+
+bool is_pageblock_removable_nolock(struct page *page)
+{
+ struct zone *zone = page_zone(page);
+ return __count_immobile_pages(zone, page, 0);
+}
+
int set_migratetype_isolate(struct page *page)
{
struct zone *zone;
- struct page *curr_page;
- unsigned long flags, pfn, iter;
- unsigned long immobile = 0;
+ unsigned long flags, pfn;
struct memory_isolate_notify arg;
int notifier_ret;
int ret = -EBUSY;
@@ -5312,11 +5365,6 @@ int set_migratetype_isolate(struct page *page)
zone_idx = zone_idx(zone);
spin_lock_irqsave(&zone->lock, flags);
- if (get_pageblock_migratetype(page) == MIGRATE_MOVABLE ||
- zone_idx == ZONE_MOVABLE) {
- ret = 0;
- goto out;
- }
pfn = page_to_pfn(page);
arg.start_pfn = pfn;
@@ -5336,23 +5384,20 @@ int set_migratetype_isolate(struct page *page)
*/
notifier_ret = memory_isolate_notify(MEM_ISOLATE_COUNT, &arg);
notifier_ret = notifier_to_errno(notifier_ret);
- if (notifier_ret || !arg.pages_found)
+ if (notifier_ret)
goto out;
-
- for (iter = pfn; iter < (pfn + pageblock_nr_pages); iter++) {
- if (!pfn_valid_within(pfn))
- continue;
-
- curr_page = pfn_to_page(iter);
- if (!page_count(curr_page) || PageLRU(curr_page))
- continue;
-
- immobile++;
- }
-
- if (arg.pages_found == immobile)
+ /*
+ * FIXME: Now, memory hotplug doesn't call shrink_slab() by itself.
+ * We just check MOVABLE pages.
+ */
+ if (__count_immobile_pages(zone, page, arg.pages_found))
ret = 0;
+ /*
+ * immobile means "not-on-lru" paes. If immobile is larger than
+ * removable-by-driver pages reported by notifier, we'll fail.
+ */
+
out:
if (!ret) {
set_pageblock_migratetype(page, MIGRATE_ISOLATE);
diff --git a/mm/page_isolation.c b/mm/page_isolation.c
index 5e0ffd967452..4ae42bb40892 100644
--- a/mm/page_isolation.c
+++ b/mm/page_isolation.c
@@ -86,7 +86,7 @@ undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn)
* all pages in [start_pfn...end_pfn) must be in the same zone.
* zone->lock must be held before call this.
*
- * Returns 0 if all pages in the range is isolated.
+ * Returns 1 if all pages in the range is isolated.
*/
static int
__test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn)
@@ -119,7 +119,6 @@ int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)
struct zone *zone;
int ret;
- pfn = start_pfn;
/*
* Note: pageblock_nr_page != MAX_ORDER. Then, chunks of free page
* is not aligned to pageblock_nr_pages.
diff --git a/mm/percpu.c b/mm/percpu.c
index 6fc9015534f8..efe816856a9d 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -31,7 +31,7 @@
* as small as 4 bytes. The allocator organizes chunks into lists
* according to free size and tries to allocate from the fullest one.
* Each chunk keeps the maximum contiguous area size hint which is
- * guaranteed to be eqaul to or larger than the maximum contiguous
+ * guaranteed to be equal to or larger than the maximum contiguous
* area in the chunk. This helps the allocator not to iterate the
* chunk maps unnecessarily.
*
diff --git a/mm/rmap.c b/mm/rmap.c
index 92e6757f196e..1a8bf76bfd03 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -80,7 +80,7 @@ static inline struct anon_vma_chain *anon_vma_chain_alloc(void)
return kmem_cache_alloc(anon_vma_chain_cachep, GFP_KERNEL);
}
-void anon_vma_chain_free(struct anon_vma_chain *anon_vma_chain)
+static void anon_vma_chain_free(struct anon_vma_chain *anon_vma_chain)
{
kmem_cache_free(anon_vma_chain_cachep, anon_vma_chain);
}
@@ -314,7 +314,7 @@ void __init anon_vma_init(void)
* Getting a lock on a stable anon_vma from a page off the LRU is
* tricky: page_lock_anon_vma rely on RCU to guard against the races.
*/
-struct anon_vma *page_lock_anon_vma(struct page *page)
+struct anon_vma *__page_lock_anon_vma(struct page *page)
{
struct anon_vma *anon_vma, *root_anon_vma;
unsigned long anon_mapping;
@@ -348,6 +348,8 @@ out:
}
void page_unlock_anon_vma(struct anon_vma *anon_vma)
+ __releases(&anon_vma->root->lock)
+ __releases(RCU)
{
anon_vma_unlock(anon_vma);
rcu_read_unlock();
@@ -407,7 +409,7 @@ unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma)
*
* On success returns with pte mapped and locked.
*/
-pte_t *page_check_address(struct page *page, struct mm_struct *mm,
+pte_t *__page_check_address(struct page *page, struct mm_struct *mm,
unsigned long address, spinlock_t **ptlp, int sync)
{
pgd_t *pgd;
@@ -745,7 +747,7 @@ int page_mkclean(struct page *page)
if (mapping) {
ret = page_mkclean_file(mapping, page);
if (page_test_dirty(page)) {
- page_clear_dirty(page);
+ page_clear_dirty(page, 1);
ret = 1;
}
}
@@ -780,10 +782,10 @@ void page_move_anon_rmap(struct page *page,
}
/**
- * __page_set_anon_rmap - setup new anonymous rmap
- * @page: the page to add the mapping to
- * @vma: the vm area in which the mapping is added
- * @address: the user virtual address mapped
+ * __page_set_anon_rmap - set up new anonymous rmap
+ * @page: Page to add to rmap
+ * @vma: VM area to add page to.
+ * @address: User virtual address of the mapping
* @exclusive: the page is exclusively owned by the current process
*/
static void __page_set_anon_rmap(struct page *page,
@@ -793,25 +795,16 @@ static void __page_set_anon_rmap(struct page *page,
BUG_ON(!anon_vma);
+ if (PageAnon(page))
+ return;
+
/*
* If the page isn't exclusively mapped into this vma,
* we must use the _oldest_ possible anon_vma for the
* page mapping!
*/
- if (!exclusive) {
- if (PageAnon(page))
- return;
+ if (!exclusive)
anon_vma = anon_vma->root;
- } else {
- /*
- * In this case, swapped-out-but-not-discarded swap-cache
- * is remapped. So, no need to update page->mapping here.
- * We convice anon_vma poitned by page->mapping is not obsolete
- * because vma->anon_vma is necessary to be a family of it.
- */
- if (PageAnon(page))
- return;
- }
anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
page->mapping = (struct address_space *) anon_vma;
@@ -942,7 +935,7 @@ void page_remove_rmap(struct page *page)
* containing the swap entry, but page not yet written to swap.
*/
if ((!PageAnon(page) || PageSwapCache(page)) && page_test_dirty(page)) {
- page_clear_dirty(page);
+ page_clear_dirty(page, 1);
set_page_dirty(page);
}
/*
diff --git a/mm/shmem.c b/mm/shmem.c
index 080b09a57a8f..f6d350e8adc5 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1586,6 +1586,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
inode = new_inode(sb);
if (inode) {
+ inode->i_ino = get_next_ino();
inode_init_owner(inode, dir, mode);
inode->i_blocks = 0;
inode->i_mapping->backing_dev_info = &shmem_backing_dev_info;
@@ -1903,7 +1904,7 @@ static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentr
dir->i_size += BOGO_DIRENT_SIZE;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
inc_nlink(inode);
- atomic_inc(&inode->i_count); /* New dentry reference */
+ ihold(inode); /* New dentry reference */
dget(dentry); /* Extra pinning count for the created dentry */
d_instantiate(dentry, inode);
out:
@@ -2146,7 +2147,7 @@ static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
if (*len < 3)
return 255;
- if (hlist_unhashed(&inode->i_hash)) {
+ if (inode_unhashed(inode)) {
/* Unfortunately insert_inode_hash is not idempotent,
* so as we hash inodes here rather than at creation
* time, we need a lock to ensure we only try
@@ -2154,7 +2155,7 @@ static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
*/
static DEFINE_SPINLOCK(lock);
spin_lock(&lock);
- if (hlist_unhashed(&inode->i_hash))
+ if (inode_unhashed(inode))
__insert_inode_hash(inode,
inode->i_ino + inode->i_generation);
spin_unlock(&lock);
diff --git a/mm/slab.c b/mm/slab.c
index fcae9815d3b3..b1e40dafbab3 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -901,7 +901,7 @@ static int transfer_objects(struct array_cache *to,
struct array_cache *from, unsigned int max)
{
/* Figure out how many entries to transfer */
- int nr = min(min(from->avail, max), to->limit - to->avail);
+ int nr = min3(from->avail, max, to->limit - to->avail);
if (!nr)
return 0;
diff --git a/mm/slob.c b/mm/slob.c
index d582171c8101..617b6d6c42c7 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -500,7 +500,9 @@ void *__kmalloc_node(size_t size, gfp_t gfp, int node)
} else {
unsigned int order = get_order(size);
- ret = slob_new_pages(gfp | __GFP_COMP, get_order(size), node);
+ if (likely(order))
+ gfp |= __GFP_COMP;
+ ret = slob_new_pages(gfp, order, node);
if (ret) {
struct page *page;
page = virt_to_page(ret);
diff --git a/mm/slub.c b/mm/slub.c
index 13fffe1f0f3d..8fd5401bb071 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -168,7 +168,6 @@ static inline int kmem_cache_debug(struct kmem_cache *s)
/* Internal SLUB flags */
#define __OBJECT_POISON 0x80000000UL /* Poison object */
-#define __SYSFS_ADD_DEFERRED 0x40000000UL /* Not yet visible via sysfs */
static int kmem_size = sizeof(struct kmem_cache);
@@ -178,7 +177,7 @@ static struct notifier_block slab_notifier;
static enum {
DOWN, /* No slab functionality available */
- PARTIAL, /* kmem_cache_open() works but kmalloc does not */
+ PARTIAL, /* Kmem_cache_node works */
UP, /* Everything works but does not show up in sysfs */
SYSFS /* Sysfs up */
} slab_state = DOWN;
@@ -199,7 +198,7 @@ struct track {
enum track_item { TRACK_ALLOC, TRACK_FREE };
-#ifdef CONFIG_SLUB_DEBUG
+#ifdef CONFIG_SYSFS
static int sysfs_slab_add(struct kmem_cache *);
static int sysfs_slab_alias(struct kmem_cache *, const char *);
static void sysfs_slab_remove(struct kmem_cache *);
@@ -210,6 +209,7 @@ static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p)
{ return 0; }
static inline void sysfs_slab_remove(struct kmem_cache *s)
{
+ kfree(s->name);
kfree(s);
}
@@ -233,11 +233,7 @@ int slab_is_available(void)
static inline struct kmem_cache_node *get_node(struct kmem_cache *s, int node)
{
-#ifdef CONFIG_NUMA
return s->node[node];
-#else
- return &s->local_node;
-#endif
}
/* Verify that a pointer has an address that is valid within a slab page */
@@ -494,7 +490,7 @@ static void slab_err(struct kmem_cache *s, struct page *page, char *fmt, ...)
dump_stack();
}
-static void init_object(struct kmem_cache *s, void *object, int active)
+static void init_object(struct kmem_cache *s, void *object, u8 val)
{
u8 *p = object;
@@ -504,9 +500,7 @@ static void init_object(struct kmem_cache *s, void *object, int active)
}
if (s->flags & SLAB_RED_ZONE)
- memset(p + s->objsize,
- active ? SLUB_RED_ACTIVE : SLUB_RED_INACTIVE,
- s->inuse - s->objsize);
+ memset(p + s->objsize, val, s->inuse - s->objsize);
}
static u8 *check_bytes(u8 *start, unsigned int value, unsigned int bytes)
@@ -641,17 +635,14 @@ static int slab_pad_check(struct kmem_cache *s, struct page *page)
}
static int check_object(struct kmem_cache *s, struct page *page,
- void *object, int active)
+ void *object, u8 val)
{
u8 *p = object;
u8 *endobject = object + s->objsize;
if (s->flags & SLAB_RED_ZONE) {
- unsigned int red =
- active ? SLUB_RED_ACTIVE : SLUB_RED_INACTIVE;
-
if (!check_bytes_and_report(s, page, object, "Redzone",
- endobject, red, s->inuse - s->objsize))
+ endobject, val, s->inuse - s->objsize))
return 0;
} else {
if ((s->flags & SLAB_POISON) && s->objsize < s->inuse) {
@@ -661,7 +652,7 @@ static int check_object(struct kmem_cache *s, struct page *page,
}
if (s->flags & SLAB_POISON) {
- if (!active && (s->flags & __OBJECT_POISON) &&
+ if (val != SLUB_RED_ACTIVE && (s->flags & __OBJECT_POISON) &&
(!check_bytes_and_report(s, page, p, "Poison", p,
POISON_FREE, s->objsize - 1) ||
!check_bytes_and_report(s, page, p, "Poison",
@@ -673,7 +664,7 @@ static int check_object(struct kmem_cache *s, struct page *page,
check_pad_bytes(s, page, p);
}
- if (!s->offset && active)
+ if (!s->offset && val == SLUB_RED_ACTIVE)
/*
* Object and freepointer overlap. Cannot check
* freepointer while object is allocated.
@@ -792,6 +783,39 @@ static void trace(struct kmem_cache *s, struct page *page, void *object,
}
/*
+ * Hooks for other subsystems that check memory allocations. In a typical
+ * production configuration these hooks all should produce no code at all.
+ */
+static inline int slab_pre_alloc_hook(struct kmem_cache *s, gfp_t flags)
+{
+ flags &= gfp_allowed_mask;
+ lockdep_trace_alloc(flags);
+ might_sleep_if(flags & __GFP_WAIT);
+
+ return should_failslab(s->objsize, flags, s->flags);
+}
+
+static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags, void *object)
+{
+ flags &= gfp_allowed_mask;
+ kmemcheck_slab_alloc(s, flags, object, s->objsize);
+ kmemleak_alloc_recursive(object, s->objsize, 1, s->flags, flags);
+}
+
+static inline void slab_free_hook(struct kmem_cache *s, void *x)
+{
+ kmemleak_free_recursive(x, s->flags);
+}
+
+static inline void slab_free_hook_irq(struct kmem_cache *s, void *object)
+{
+ kmemcheck_slab_free(s, object, s->objsize);
+ debug_check_no_locks_freed(object, s->objsize);
+ if (!(s->flags & SLAB_DEBUG_OBJECTS))
+ debug_check_no_obj_freed(object, s->objsize);
+}
+
+/*
* Tracking of fully allocated slabs for debugging purposes.
*/
static void add_full(struct kmem_cache_node *n, struct page *page)
@@ -838,7 +862,7 @@ static inline void inc_slabs_node(struct kmem_cache *s, int node, int objects)
* dilemma by deferring the increment of the count during
* bootstrap (see early_kmem_cache_node_alloc).
*/
- if (!NUMA_BUILD || n) {
+ if (n) {
atomic_long_inc(&n->nr_slabs);
atomic_long_add(objects, &n->total_objects);
}
@@ -858,11 +882,11 @@ static void setup_object_debug(struct kmem_cache *s, struct page *page,
if (!(s->flags & (SLAB_STORE_USER|SLAB_RED_ZONE|__OBJECT_POISON)))
return;
- init_object(s, object, 0);
+ init_object(s, object, SLUB_RED_INACTIVE);
init_tracking(s, object);
}
-static int alloc_debug_processing(struct kmem_cache *s, struct page *page,
+static noinline int alloc_debug_processing(struct kmem_cache *s, struct page *page,
void *object, unsigned long addr)
{
if (!check_slab(s, page))
@@ -878,14 +902,14 @@ static int alloc_debug_processing(struct kmem_cache *s, struct page *page,
goto bad;
}
- if (!check_object(s, page, object, 0))
+ if (!check_object(s, page, object, SLUB_RED_INACTIVE))
goto bad;
/* Success perform special debug activities for allocs */
if (s->flags & SLAB_STORE_USER)
set_track(s, object, TRACK_ALLOC, addr);
trace(s, page, object, 1);
- init_object(s, object, 1);
+ init_object(s, object, SLUB_RED_ACTIVE);
return 1;
bad:
@@ -902,8 +926,8 @@ bad:
return 0;
}
-static int free_debug_processing(struct kmem_cache *s, struct page *page,
- void *object, unsigned long addr)
+static noinline int free_debug_processing(struct kmem_cache *s,
+ struct page *page, void *object, unsigned long addr)
{
if (!check_slab(s, page))
goto fail;
@@ -918,7 +942,7 @@ static int free_debug_processing(struct kmem_cache *s, struct page *page,
goto fail;
}
- if (!check_object(s, page, object, 1))
+ if (!check_object(s, page, object, SLUB_RED_ACTIVE))
return 0;
if (unlikely(s != page->slab)) {
@@ -942,7 +966,7 @@ static int free_debug_processing(struct kmem_cache *s, struct page *page,
if (s->flags & SLAB_STORE_USER)
set_track(s, object, TRACK_FREE, addr);
trace(s, page, object, 0);
- init_object(s, object, 0);
+ init_object(s, object, SLUB_RED_INACTIVE);
return 1;
fail:
@@ -1046,7 +1070,7 @@ static inline int free_debug_processing(struct kmem_cache *s,
static inline int slab_pad_check(struct kmem_cache *s, struct page *page)
{ return 1; }
static inline int check_object(struct kmem_cache *s, struct page *page,
- void *object, int active) { return 1; }
+ void *object, u8 val) { return 1; }
static inline void add_full(struct kmem_cache_node *n, struct page *page) {}
static inline unsigned long kmem_cache_flags(unsigned long objsize,
unsigned long flags, const char *name,
@@ -1066,7 +1090,19 @@ static inline void inc_slabs_node(struct kmem_cache *s, int node,
int objects) {}
static inline void dec_slabs_node(struct kmem_cache *s, int node,
int objects) {}
-#endif
+
+static inline int slab_pre_alloc_hook(struct kmem_cache *s, gfp_t flags)
+ { return 0; }
+
+static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags,
+ void *object) {}
+
+static inline void slab_free_hook(struct kmem_cache *s, void *x) {}
+
+static inline void slab_free_hook_irq(struct kmem_cache *s,
+ void *object) {}
+
+#endif /* CONFIG_SLUB_DEBUG */
/*
* Slab allocation and freeing
@@ -1194,7 +1230,7 @@ static void __free_slab(struct kmem_cache *s, struct page *page)
slab_pad_check(s, page);
for_each_object(p, s, page_address(page),
page->objects)
- check_object(s, page, p, 0);
+ check_object(s, page, p, SLUB_RED_INACTIVE);
}
kmemcheck_free_shadow(page, compound_order(page));
@@ -1274,13 +1310,19 @@ static void add_partial(struct kmem_cache_node *n,
spin_unlock(&n->list_lock);
}
+static inline void __remove_partial(struct kmem_cache_node *n,
+ struct page *page)
+{
+ list_del(&page->lru);
+ n->nr_partial--;
+}
+
static void remove_partial(struct kmem_cache *s, struct page *page)
{
struct kmem_cache_node *n = get_node(s, page_to_nid(page));
spin_lock(&n->list_lock);
- list_del(&page->lru);
- n->nr_partial--;
+ __remove_partial(n, page);
spin_unlock(&n->list_lock);
}
@@ -1293,8 +1335,7 @@ static inline int lock_and_freeze_slab(struct kmem_cache_node *n,
struct page *page)
{
if (slab_trylock(page)) {
- list_del(&page->lru);
- n->nr_partial--;
+ __remove_partial(n, page);
__SetPageSlubFrozen(page);
return 1;
}
@@ -1405,6 +1446,7 @@ static struct page *get_partial(struct kmem_cache *s, gfp_t flags, int node)
* On exit the slab lock will have been dropped.
*/
static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail)
+ __releases(bitlock)
{
struct kmem_cache_node *n = get_node(s, page_to_nid(page));
@@ -1447,6 +1489,7 @@ static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail)
* Remove the cpu slab
*/
static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
+ __releases(bitlock)
{
struct page *page = c->page;
int tail = 1;
@@ -1647,6 +1690,7 @@ new_slab:
goto load_freelist;
}
+ gfpflags &= gfp_allowed_mask;
if (gfpflags & __GFP_WAIT)
local_irq_enable();
@@ -1674,7 +1718,7 @@ debug:
c->page->inuse++;
c->page->freelist = get_freepointer(s, object);
- c->node = -1;
+ c->node = NUMA_NO_NODE;
goto unlock_out;
}
@@ -1695,12 +1739,7 @@ static __always_inline void *slab_alloc(struct kmem_cache *s,
struct kmem_cache_cpu *c;
unsigned long flags;
- gfpflags &= gfp_allowed_mask;
-
- lockdep_trace_alloc(gfpflags);
- might_sleep_if(gfpflags & __GFP_WAIT);
-
- if (should_failslab(s->objsize, gfpflags, s->flags))
+ if (slab_pre_alloc_hook(s, gfpflags))
return NULL;
local_irq_save(flags);
@@ -1719,8 +1758,7 @@ static __always_inline void *slab_alloc(struct kmem_cache *s,
if (unlikely(gfpflags & __GFP_ZERO) && object)
memset(object, 0, s->objsize);
- kmemcheck_slab_alloc(s, gfpflags, object, s->objsize);
- kmemleak_alloc_recursive(object, s->objsize, 1, s->flags, gfpflags);
+ slab_post_alloc_hook(s, gfpflags, object);
return object;
}
@@ -1754,7 +1792,6 @@ void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)
return ret;
}
EXPORT_SYMBOL(kmem_cache_alloc_node);
-#endif
#ifdef CONFIG_TRACING
void *kmem_cache_alloc_node_notrace(struct kmem_cache *s,
@@ -1765,6 +1802,7 @@ void *kmem_cache_alloc_node_notrace(struct kmem_cache *s,
}
EXPORT_SYMBOL(kmem_cache_alloc_node_notrace);
#endif
+#endif
/*
* Slow patch handling. This may still be called frequently since objects
@@ -1850,14 +1888,14 @@ static __always_inline void slab_free(struct kmem_cache *s,
struct kmem_cache_cpu *c;
unsigned long flags;
- kmemleak_free_recursive(x, s->flags);
+ slab_free_hook(s, x);
+
local_irq_save(flags);
c = __this_cpu_ptr(s->cpu_slab);
- kmemcheck_slab_free(s, object, s->objsize);
- debug_check_no_locks_freed(object, s->objsize);
- if (!(s->flags & SLAB_DEBUG_OBJECTS))
- debug_check_no_obj_freed(object, s->objsize);
- if (likely(page == c->page && c->node >= 0)) {
+
+ slab_free_hook_irq(s, x);
+
+ if (likely(page == c->page && c->node != NUMA_NO_NODE)) {
set_freepointer(s, object, c->freelist);
c->freelist = object;
stat(s, FREE_FASTPATH);
@@ -2062,26 +2100,18 @@ init_kmem_cache_node(struct kmem_cache_node *n, struct kmem_cache *s)
#endif
}
-static DEFINE_PER_CPU(struct kmem_cache_cpu, kmalloc_percpu[KMALLOC_CACHES]);
-
-static inline int alloc_kmem_cache_cpus(struct kmem_cache *s, gfp_t flags)
+static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
{
- if (s < kmalloc_caches + KMALLOC_CACHES && s >= kmalloc_caches)
- /*
- * Boot time creation of the kmalloc array. Use static per cpu data
- * since the per cpu allocator is not available yet.
- */
- s->cpu_slab = kmalloc_percpu + (s - kmalloc_caches);
- else
- s->cpu_slab = alloc_percpu(struct kmem_cache_cpu);
+ BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE <
+ SLUB_PAGE_SHIFT * sizeof(struct kmem_cache_cpu));
- if (!s->cpu_slab)
- return 0;
+ s->cpu_slab = alloc_percpu(struct kmem_cache_cpu);
- return 1;
+ return s->cpu_slab != NULL;
}
-#ifdef CONFIG_NUMA
+static struct kmem_cache *kmem_cache_node;
+
/*
* No kmalloc_node yet so do it by hand. We know that this is the first
* slab on the node for this slabcache. There are no concurrent accesses
@@ -2091,15 +2121,15 @@ static inline int alloc_kmem_cache_cpus(struct kmem_cache *s, gfp_t flags)
* when allocating for the kmalloc_node_cache. This is used for bootstrapping
* memory on a fresh node that has no slab structures yet.
*/
-static void early_kmem_cache_node_alloc(gfp_t gfpflags, int node)
+static void early_kmem_cache_node_alloc(int node)
{
struct page *page;
struct kmem_cache_node *n;
unsigned long flags;
- BUG_ON(kmalloc_caches->size < sizeof(struct kmem_cache_node));
+ BUG_ON(kmem_cache_node->size < sizeof(struct kmem_cache_node));
- page = new_slab(kmalloc_caches, gfpflags, node);
+ page = new_slab(kmem_cache_node, GFP_NOWAIT, node);
BUG_ON(!page);
if (page_to_nid(page) != node) {
@@ -2111,15 +2141,15 @@ static void early_kmem_cache_node_alloc(gfp_t gfpflags, int node)
n = page->freelist;
BUG_ON(!n);
- page->freelist = get_freepointer(kmalloc_caches, n);
+ page->freelist = get_freepointer(kmem_cache_node, n);
page->inuse++;
- kmalloc_caches->node[node] = n;
+ kmem_cache_node->node[node] = n;
#ifdef CONFIG_SLUB_DEBUG
- init_object(kmalloc_caches, n, 1);
- init_tracking(kmalloc_caches, n);
+ init_object(kmem_cache_node, n, SLUB_RED_ACTIVE);
+ init_tracking(kmem_cache_node, n);
#endif
- init_kmem_cache_node(n, kmalloc_caches);
- inc_slabs_node(kmalloc_caches, node, page->objects);
+ init_kmem_cache_node(n, kmem_cache_node);
+ inc_slabs_node(kmem_cache_node, node, page->objects);
/*
* lockdep requires consistent irq usage for each lock
@@ -2137,13 +2167,15 @@ static void free_kmem_cache_nodes(struct kmem_cache *s)
for_each_node_state(node, N_NORMAL_MEMORY) {
struct kmem_cache_node *n = s->node[node];
+
if (n)
- kmem_cache_free(kmalloc_caches, n);
+ kmem_cache_free(kmem_cache_node, n);
+
s->node[node] = NULL;
}
}
-static int init_kmem_cache_nodes(struct kmem_cache *s, gfp_t gfpflags)
+static int init_kmem_cache_nodes(struct kmem_cache *s)
{
int node;
@@ -2151,11 +2183,11 @@ static int init_kmem_cache_nodes(struct kmem_cache *s, gfp_t gfpflags)
struct kmem_cache_node *n;
if (slab_state == DOWN) {
- early_kmem_cache_node_alloc(gfpflags, node);
+ early_kmem_cache_node_alloc(node);
continue;
}
- n = kmem_cache_alloc_node(kmalloc_caches,
- gfpflags, node);
+ n = kmem_cache_alloc_node(kmem_cache_node,
+ GFP_KERNEL, node);
if (!n) {
free_kmem_cache_nodes(s);
@@ -2167,17 +2199,6 @@ static int init_kmem_cache_nodes(struct kmem_cache *s, gfp_t gfpflags)
}
return 1;
}
-#else
-static void free_kmem_cache_nodes(struct kmem_cache *s)
-{
-}
-
-static int init_kmem_cache_nodes(struct kmem_cache *s, gfp_t gfpflags)
-{
- init_kmem_cache_node(&s->local_node, s);
- return 1;
-}
-#endif
static void set_min_partial(struct kmem_cache *s, unsigned long min)
{
@@ -2312,7 +2333,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
}
-static int kmem_cache_open(struct kmem_cache *s, gfp_t gfpflags,
+static int kmem_cache_open(struct kmem_cache *s,
const char *name, size_t size,
size_t align, unsigned long flags,
void (*ctor)(void *))
@@ -2348,10 +2369,10 @@ static int kmem_cache_open(struct kmem_cache *s, gfp_t gfpflags,
#ifdef CONFIG_NUMA
s->remote_node_defrag_ratio = 1000;
#endif
- if (!init_kmem_cache_nodes(s, gfpflags & ~SLUB_DMA))
+ if (!init_kmem_cache_nodes(s))
goto error;
- if (alloc_kmem_cache_cpus(s, gfpflags & ~SLUB_DMA))
+ if (alloc_kmem_cache_cpus(s))
return 1;
free_kmem_cache_nodes(s);
@@ -2414,9 +2435,8 @@ static void list_slab_objects(struct kmem_cache *s, struct page *page,
#ifdef CONFIG_SLUB_DEBUG
void *addr = page_address(page);
void *p;
- long *map = kzalloc(BITS_TO_LONGS(page->objects) * sizeof(long),
- GFP_ATOMIC);
-
+ unsigned long *map = kzalloc(BITS_TO_LONGS(page->objects) *
+ sizeof(long), GFP_ATOMIC);
if (!map)
return;
slab_err(s, page, "%s", text);
@@ -2448,9 +2468,8 @@ static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n)
spin_lock_irqsave(&n->list_lock, flags);
list_for_each_entry_safe(page, h, &n->partial, lru) {
if (!page->inuse) {
- list_del(&page->lru);
+ __remove_partial(n, page);
discard_slab(s, page);
- n->nr_partial--;
} else {
list_slab_objects(s, page,
"Objects remaining on kmem_cache_close()");
@@ -2507,9 +2526,15 @@ EXPORT_SYMBOL(kmem_cache_destroy);
* Kmalloc subsystem
*******************************************************************/
-struct kmem_cache kmalloc_caches[KMALLOC_CACHES] __cacheline_aligned;
+struct kmem_cache *kmalloc_caches[SLUB_PAGE_SHIFT];
EXPORT_SYMBOL(kmalloc_caches);
+static struct kmem_cache *kmem_cache;
+
+#ifdef CONFIG_ZONE_DMA
+static struct kmem_cache *kmalloc_dma_caches[SLUB_PAGE_SHIFT];
+#endif
+
static int __init setup_slub_min_order(char *str)
{
get_option(&str, &slub_min_order);
@@ -2546,116 +2571,29 @@ static int __init setup_slub_nomerge(char *str)
__setup("slub_nomerge", setup_slub_nomerge);
-static struct kmem_cache *create_kmalloc_cache(struct kmem_cache *s,
- const char *name, int size, gfp_t gfp_flags)
+static struct kmem_cache *__init create_kmalloc_cache(const char *name,
+ int size, unsigned int flags)
{
- unsigned int flags = 0;
+ struct kmem_cache *s;
- if (gfp_flags & SLUB_DMA)
- flags = SLAB_CACHE_DMA;
+ s = kmem_cache_alloc(kmem_cache, GFP_NOWAIT);
/*
* This function is called with IRQs disabled during early-boot on
* single CPU so there's no need to take slub_lock here.
*/
- if (!kmem_cache_open(s, gfp_flags, name, size, ARCH_KMALLOC_MINALIGN,
+ if (!kmem_cache_open(s, name, size, ARCH_KMALLOC_MINALIGN,
flags, NULL))
goto panic;
list_add(&s->list, &slab_caches);
-
- if (sysfs_slab_add(s))
- goto panic;
return s;
panic:
panic("Creation of kmalloc slab %s size=%d failed.\n", name, size);
+ return NULL;
}
-#ifdef CONFIG_ZONE_DMA
-static struct kmem_cache *kmalloc_caches_dma[SLUB_PAGE_SHIFT];
-
-static void sysfs_add_func(struct work_struct *w)
-{
- struct kmem_cache *s;
-
- down_write(&slub_lock);
- list_for_each_entry(s, &slab_caches, list) {
- if (s->flags & __SYSFS_ADD_DEFERRED) {
- s->flags &= ~__SYSFS_ADD_DEFERRED;
- sysfs_slab_add(s);
- }
- }
- up_write(&slub_lock);
-}
-
-static DECLARE_WORK(sysfs_add_work, sysfs_add_func);
-
-static noinline struct kmem_cache *dma_kmalloc_cache(int index, gfp_t flags)
-{
- struct kmem_cache *s;
- char *text;
- size_t realsize;
- unsigned long slabflags;
- int i;
-
- s = kmalloc_caches_dma[index];
- if (s)
- return s;
-
- /* Dynamically create dma cache */
- if (flags & __GFP_WAIT)
- down_write(&slub_lock);
- else {
- if (!down_write_trylock(&slub_lock))
- goto out;
- }
-
- if (kmalloc_caches_dma[index])
- goto unlock_out;
-
- realsize = kmalloc_caches[index].objsize;
- text = kasprintf(flags & ~SLUB_DMA, "kmalloc_dma-%d",
- (unsigned int)realsize);
-
- s = NULL;
- for (i = 0; i < KMALLOC_CACHES; i++)
- if (!kmalloc_caches[i].size)
- break;
-
- BUG_ON(i >= KMALLOC_CACHES);
- s = kmalloc_caches + i;
-
- /*
- * Must defer sysfs creation to a workqueue because we don't know
- * what context we are called from. Before sysfs comes up, we don't
- * need to do anything because our sysfs initcall will start by
- * adding all existing slabs to sysfs.
- */
- slabflags = SLAB_CACHE_DMA|SLAB_NOTRACK;
- if (slab_state >= SYSFS)
- slabflags |= __SYSFS_ADD_DEFERRED;
-
- if (!text || !kmem_cache_open(s, flags, text,
- realsize, ARCH_KMALLOC_MINALIGN, slabflags, NULL)) {
- s->size = 0;
- kfree(text);
- goto unlock_out;
- }
-
- list_add(&s->list, &slab_caches);
- kmalloc_caches_dma[index] = s;
-
- if (slab_state >= SYSFS)
- schedule_work(&sysfs_add_work);
-
-unlock_out:
- up_write(&slub_lock);
-out:
- return kmalloc_caches_dma[index];
-}
-#endif
-
/*
* Conversion table for small slabs sizes / 8 to the index in the
* kmalloc array. This is necessary for slabs < 192 since we have non power
@@ -2708,10 +2646,10 @@ static struct kmem_cache *get_slab(size_t size, gfp_t flags)
#ifdef CONFIG_ZONE_DMA
if (unlikely((flags & SLUB_DMA)))
- return dma_kmalloc_cache(index, flags);
+ return kmalloc_dma_caches[index];
#endif
- return &kmalloc_caches[index];
+ return kmalloc_caches[index];
}
void *__kmalloc(size_t size, gfp_t flags)
@@ -2735,6 +2673,7 @@ void *__kmalloc(size_t size, gfp_t flags)
}
EXPORT_SYMBOL(__kmalloc);
+#ifdef CONFIG_NUMA
static void *kmalloc_large_node(size_t size, gfp_t flags, int node)
{
struct page *page;
@@ -2749,7 +2688,6 @@ static void *kmalloc_large_node(size_t size, gfp_t flags, int node)
return ptr;
}
-#ifdef CONFIG_NUMA
void *__kmalloc_node(size_t size, gfp_t flags, int node)
{
struct kmem_cache *s;
@@ -2889,8 +2827,7 @@ int kmem_cache_shrink(struct kmem_cache *s)
* may have freed the last object and be
* waiting to release the slab.
*/
- list_del(&page->lru);
- n->nr_partial--;
+ __remove_partial(n, page);
slab_unlock(page);
discard_slab(s, page);
} else {
@@ -2914,7 +2851,7 @@ int kmem_cache_shrink(struct kmem_cache *s)
}
EXPORT_SYMBOL(kmem_cache_shrink);
-#if defined(CONFIG_NUMA) && defined(CONFIG_MEMORY_HOTPLUG)
+#if defined(CONFIG_MEMORY_HOTPLUG)
static int slab_mem_going_offline_callback(void *arg)
{
struct kmem_cache *s;
@@ -2956,7 +2893,7 @@ static void slab_mem_offline_callback(void *arg)
BUG_ON(slabs_node(s, offline_node));
s->node[offline_node] = NULL;
- kmem_cache_free(kmalloc_caches, n);
+ kmem_cache_free(kmem_cache_node, n);
}
}
up_read(&slub_lock);
@@ -2989,7 +2926,7 @@ static int slab_mem_going_online_callback(void *arg)
* since memory is not yet available from the node that
* is brought up.
*/
- n = kmem_cache_alloc(kmalloc_caches, GFP_KERNEL);
+ n = kmem_cache_alloc(kmem_cache_node, GFP_KERNEL);
if (!n) {
ret = -ENOMEM;
goto out;
@@ -3035,46 +2972,92 @@ static int slab_memory_callback(struct notifier_block *self,
* Basic setup of slabs
*******************************************************************/
+/*
+ * Used for early kmem_cache structures that were allocated using
+ * the page allocator
+ */
+
+static void __init kmem_cache_bootstrap_fixup(struct kmem_cache *s)
+{
+ int node;
+
+ list_add(&s->list, &slab_caches);
+ s->refcount = -1;
+
+ for_each_node_state(node, N_NORMAL_MEMORY) {
+ struct kmem_cache_node *n = get_node(s, node);
+ struct page *p;
+
+ if (n) {
+ list_for_each_entry(p, &n->partial, lru)
+ p->slab = s;
+
+#ifdef CONFIG_SLAB_DEBUG
+ list_for_each_entry(p, &n->full, lru)
+ p->slab = s;
+#endif
+ }
+ }
+}
+
void __init kmem_cache_init(void)
{
int i;
int caches = 0;
+ struct kmem_cache *temp_kmem_cache;
+ int order;
+ struct kmem_cache *temp_kmem_cache_node;
+ unsigned long kmalloc_size;
+
+ kmem_size = offsetof(struct kmem_cache, node) +
+ nr_node_ids * sizeof(struct kmem_cache_node *);
+
+ /* Allocate two kmem_caches from the page allocator */
+ kmalloc_size = ALIGN(kmem_size, cache_line_size());
+ order = get_order(2 * kmalloc_size);
+ kmem_cache = (void *)__get_free_pages(GFP_NOWAIT, order);
-#ifdef CONFIG_NUMA
/*
* Must first have the slab cache available for the allocations of the
* struct kmem_cache_node's. There is special bootstrap code in
* kmem_cache_open for slab_state == DOWN.
*/
- create_kmalloc_cache(&kmalloc_caches[0], "kmem_cache_node",
- sizeof(struct kmem_cache_node), GFP_NOWAIT);
- kmalloc_caches[0].refcount = -1;
- caches++;
+ kmem_cache_node = (void *)kmem_cache + kmalloc_size;
+
+ kmem_cache_open(kmem_cache_node, "kmem_cache_node",
+ sizeof(struct kmem_cache_node),
+ 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
hotplug_memory_notifier(slab_memory_callback, SLAB_CALLBACK_PRI);
-#endif
/* Able to allocate the per node structures */
slab_state = PARTIAL;
- /* Caches that are not of the two-to-the-power-of size */
- if (KMALLOC_MIN_SIZE <= 32) {
- create_kmalloc_cache(&kmalloc_caches[1],
- "kmalloc-96", 96, GFP_NOWAIT);
- caches++;
- }
- if (KMALLOC_MIN_SIZE <= 64) {
- create_kmalloc_cache(&kmalloc_caches[2],
- "kmalloc-192", 192, GFP_NOWAIT);
- caches++;
- }
+ temp_kmem_cache = kmem_cache;
+ kmem_cache_open(kmem_cache, "kmem_cache", kmem_size,
+ 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
+ kmem_cache = kmem_cache_alloc(kmem_cache, GFP_NOWAIT);
+ memcpy(kmem_cache, temp_kmem_cache, kmem_size);
- for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) {
- create_kmalloc_cache(&kmalloc_caches[i],
- "kmalloc", 1 << i, GFP_NOWAIT);
- caches++;
- }
+ /*
+ * Allocate kmem_cache_node properly from the kmem_cache slab.
+ * kmem_cache_node is separately allocated so no need to
+ * update any list pointers.
+ */
+ temp_kmem_cache_node = kmem_cache_node;
+
+ kmem_cache_node = kmem_cache_alloc(kmem_cache, GFP_NOWAIT);
+ memcpy(kmem_cache_node, temp_kmem_cache_node, kmem_size);
+
+ kmem_cache_bootstrap_fixup(kmem_cache_node);
+ caches++;
+ kmem_cache_bootstrap_fixup(kmem_cache);
+ caches++;
+ /* Free temporary boot structure */
+ free_pages((unsigned long)temp_kmem_cache, order);
+
+ /* Now we can use the kmem_cache to allocate kmalloc slabs */
/*
* Patch up the size_index table if we have strange large alignment
@@ -3114,26 +3097,60 @@ void __init kmem_cache_init(void)
size_index[size_index_elem(i)] = 8;
}
+ /* Caches that are not of the two-to-the-power-of size */
+ if (KMALLOC_MIN_SIZE <= 32) {
+ kmalloc_caches[1] = create_kmalloc_cache("kmalloc-96", 96, 0);
+ caches++;
+ }
+
+ if (KMALLOC_MIN_SIZE <= 64) {
+ kmalloc_caches[2] = create_kmalloc_cache("kmalloc-192", 192, 0);
+ caches++;
+ }
+
+ for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) {
+ kmalloc_caches[i] = create_kmalloc_cache("kmalloc", 1 << i, 0);
+ caches++;
+ }
+
slab_state = UP;
/* Provide the correct kmalloc names now that the caches are up */
+ if (KMALLOC_MIN_SIZE <= 32) {
+ kmalloc_caches[1]->name = kstrdup(kmalloc_caches[1]->name, GFP_NOWAIT);
+ BUG_ON(!kmalloc_caches[1]->name);
+ }
+
+ if (KMALLOC_MIN_SIZE <= 64) {
+ kmalloc_caches[2]->name = kstrdup(kmalloc_caches[2]->name, GFP_NOWAIT);
+ BUG_ON(!kmalloc_caches[2]->name);
+ }
+
for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) {
char *s = kasprintf(GFP_NOWAIT, "kmalloc-%d", 1 << i);
BUG_ON(!s);
- kmalloc_caches[i].name = s;
+ kmalloc_caches[i]->name = s;
}
#ifdef CONFIG_SMP
register_cpu_notifier(&slab_notifier);
#endif
-#ifdef CONFIG_NUMA
- kmem_size = offsetof(struct kmem_cache, node) +
- nr_node_ids * sizeof(struct kmem_cache_node *);
-#else
- kmem_size = sizeof(struct kmem_cache);
-#endif
+#ifdef CONFIG_ZONE_DMA
+ for (i = 0; i < SLUB_PAGE_SHIFT; i++) {
+ struct kmem_cache *s = kmalloc_caches[i];
+
+ if (s && s->size) {
+ char *name = kasprintf(GFP_NOWAIT,
+ "dma-kmalloc-%d", s->objsize);
+
+ BUG_ON(!name);
+ kmalloc_dma_caches[i] = create_kmalloc_cache(name,
+ s->objsize, SLAB_CACHE_DMA);
+ }
+ }
+#endif
printk(KERN_INFO
"SLUB: Genslabs=%d, HWalign=%d, Order=%d-%d, MinObjects=%d,"
" CPUs=%d, Nodes=%d\n",
@@ -3211,6 +3228,7 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
size_t align, unsigned long flags, void (*ctor)(void *))
{
struct kmem_cache *s;
+ char *n;
if (WARN_ON(!name))
return NULL;
@@ -3234,19 +3252,25 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
return s;
}
+ n = kstrdup(name, GFP_KERNEL);
+ if (!n)
+ goto err;
+
s = kmalloc(kmem_size, GFP_KERNEL);
if (s) {
- if (kmem_cache_open(s, GFP_KERNEL, name,
+ if (kmem_cache_open(s, n,
size, align, flags, ctor)) {
list_add(&s->list, &slab_caches);
if (sysfs_slab_add(s)) {
list_del(&s->list);
+ kfree(n);
kfree(s);
goto err;
}
up_write(&slub_lock);
return s;
}
+ kfree(n);
kfree(s);
}
up_write(&slub_lock);
@@ -3318,6 +3342,7 @@ void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, unsigned long caller)
return ret;
}
+#ifdef CONFIG_NUMA
void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
int node, unsigned long caller)
{
@@ -3346,8 +3371,9 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
return ret;
}
+#endif
-#ifdef CONFIG_SLUB_DEBUG
+#ifdef CONFIG_SYSFS
static int count_inuse(struct page *page)
{
return page->inuse;
@@ -3357,7 +3383,9 @@ static int count_total(struct page *page)
{
return page->objects;
}
+#endif
+#ifdef CONFIG_SLUB_DEBUG
static int validate_slab(struct kmem_cache *s, struct page *page,
unsigned long *map)
{
@@ -3448,65 +3476,6 @@ static long validate_slab_cache(struct kmem_cache *s)
kfree(map);
return count;
}
-
-#ifdef SLUB_RESILIENCY_TEST
-static void resiliency_test(void)
-{
- u8 *p;
-
- printk(KERN_ERR "SLUB resiliency testing\n");
- printk(KERN_ERR "-----------------------\n");
- printk(KERN_ERR "A. Corruption after allocation\n");
-
- p = kzalloc(16, GFP_KERNEL);
- p[16] = 0x12;
- printk(KERN_ERR "\n1. kmalloc-16: Clobber Redzone/next pointer"
- " 0x12->0x%p\n\n", p + 16);
-
- validate_slab_cache(kmalloc_caches + 4);
-
- /* Hmmm... The next two are dangerous */
- p = kzalloc(32, GFP_KERNEL);
- p[32 + sizeof(void *)] = 0x34;
- printk(KERN_ERR "\n2. kmalloc-32: Clobber next pointer/next slab"
- " 0x34 -> -0x%p\n", p);
- printk(KERN_ERR
- "If allocated object is overwritten then not detectable\n\n");
-
- validate_slab_cache(kmalloc_caches + 5);
- p = kzalloc(64, GFP_KERNEL);
- p += 64 + (get_cycles() & 0xff) * sizeof(void *);
- *p = 0x56;
- printk(KERN_ERR "\n3. kmalloc-64: corrupting random byte 0x56->0x%p\n",
- p);
- printk(KERN_ERR
- "If allocated object is overwritten then not detectable\n\n");
- validate_slab_cache(kmalloc_caches + 6);
-
- printk(KERN_ERR "\nB. Corruption after free\n");
- p = kzalloc(128, GFP_KERNEL);
- kfree(p);
- *p = 0x78;
- printk(KERN_ERR "1. kmalloc-128: Clobber first word 0x78->0x%p\n\n", p);
- validate_slab_cache(kmalloc_caches + 7);
-
- p = kzalloc(256, GFP_KERNEL);
- kfree(p);
- p[50] = 0x9a;
- printk(KERN_ERR "\n2. kmalloc-256: Clobber 50th byte 0x9a->0x%p\n\n",
- p);
- validate_slab_cache(kmalloc_caches + 8);
-
- p = kzalloc(512, GFP_KERNEL);
- kfree(p);
- p[512] = 0xab;
- printk(KERN_ERR "\n3. kmalloc-512: Clobber redzone 0xab->0x%p\n\n", p);
- validate_slab_cache(kmalloc_caches + 9);
-}
-#else
-static void resiliency_test(void) {};
-#endif
-
/*
* Generate lists of code addresses where slabcache objects are allocated
* and freed.
@@ -3635,7 +3604,7 @@ static int add_location(struct loc_track *t, struct kmem_cache *s,
static void process_slab(struct loc_track *t, struct kmem_cache *s,
struct page *page, enum track_item alloc,
- long *map)
+ unsigned long *map)
{
void *addr = page_address(page);
void *p;
@@ -3735,7 +3704,71 @@ static int list_locations(struct kmem_cache *s, char *buf,
len += sprintf(buf, "No data\n");
return len;
}
+#endif
+
+#ifdef SLUB_RESILIENCY_TEST
+static void resiliency_test(void)
+{
+ u8 *p;
+ BUILD_BUG_ON(KMALLOC_MIN_SIZE > 16 || SLUB_PAGE_SHIFT < 10);
+
+ printk(KERN_ERR "SLUB resiliency testing\n");
+ printk(KERN_ERR "-----------------------\n");
+ printk(KERN_ERR "A. Corruption after allocation\n");
+
+ p = kzalloc(16, GFP_KERNEL);
+ p[16] = 0x12;
+ printk(KERN_ERR "\n1. kmalloc-16: Clobber Redzone/next pointer"
+ " 0x12->0x%p\n\n", p + 16);
+
+ validate_slab_cache(kmalloc_caches[4]);
+
+ /* Hmmm... The next two are dangerous */
+ p = kzalloc(32, GFP_KERNEL);
+ p[32 + sizeof(void *)] = 0x34;
+ printk(KERN_ERR "\n2. kmalloc-32: Clobber next pointer/next slab"
+ " 0x34 -> -0x%p\n", p);
+ printk(KERN_ERR
+ "If allocated object is overwritten then not detectable\n\n");
+
+ validate_slab_cache(kmalloc_caches[5]);
+ p = kzalloc(64, GFP_KERNEL);
+ p += 64 + (get_cycles() & 0xff) * sizeof(void *);
+ *p = 0x56;
+ printk(KERN_ERR "\n3. kmalloc-64: corrupting random byte 0x56->0x%p\n",
+ p);
+ printk(KERN_ERR
+ "If allocated object is overwritten then not detectable\n\n");
+ validate_slab_cache(kmalloc_caches[6]);
+
+ printk(KERN_ERR "\nB. Corruption after free\n");
+ p = kzalloc(128, GFP_KERNEL);
+ kfree(p);
+ *p = 0x78;
+ printk(KERN_ERR "1. kmalloc-128: Clobber first word 0x78->0x%p\n\n", p);
+ validate_slab_cache(kmalloc_caches[7]);
+
+ p = kzalloc(256, GFP_KERNEL);
+ kfree(p);
+ p[50] = 0x9a;
+ printk(KERN_ERR "\n2. kmalloc-256: Clobber 50th byte 0x9a->0x%p\n\n",
+ p);
+ validate_slab_cache(kmalloc_caches[8]);
+
+ p = kzalloc(512, GFP_KERNEL);
+ kfree(p);
+ p[512] = 0xab;
+ printk(KERN_ERR "\n3. kmalloc-512: Clobber redzone 0xab->0x%p\n\n", p);
+ validate_slab_cache(kmalloc_caches[9]);
+}
+#else
+#ifdef CONFIG_SYSFS
+static void resiliency_test(void) {};
+#endif
+#endif
+
+#ifdef CONFIG_SYSFS
enum slab_stat_type {
SL_ALL, /* All slabs */
SL_PARTIAL, /* Only partially allocated slabs */
@@ -3788,6 +3821,8 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
}
}
+ down_read(&slub_lock);
+#ifdef CONFIG_SLUB_DEBUG
if (flags & SO_ALL) {
for_each_node_state(node, N_NORMAL_MEMORY) {
struct kmem_cache_node *n = get_node(s, node);
@@ -3804,7 +3839,9 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
nodes[node] += x;
}
- } else if (flags & SO_PARTIAL) {
+ } else
+#endif
+ if (flags & SO_PARTIAL) {
for_each_node_state(node, N_NORMAL_MEMORY) {
struct kmem_cache_node *n = get_node(s, node);
@@ -3829,6 +3866,7 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
return x + sprintf(buf + x, "\n");
}
+#ifdef CONFIG_SLUB_DEBUG
static int any_slab_objects(struct kmem_cache *s)
{
int node;
@@ -3844,6 +3882,7 @@ static int any_slab_objects(struct kmem_cache *s)
}
return 0;
}
+#endif
#define to_slab_attr(n) container_of(n, struct slab_attribute, attr)
#define to_slab(n) container_of(n, struct kmem_cache, kobj);
@@ -3945,12 +3984,6 @@ static ssize_t aliases_show(struct kmem_cache *s, char *buf)
}
SLAB_ATTR_RO(aliases);
-static ssize_t slabs_show(struct kmem_cache *s, char *buf)
-{
- return show_slab_objects(s, buf, SO_ALL);
-}
-SLAB_ATTR_RO(slabs);
-
static ssize_t partial_show(struct kmem_cache *s, char *buf)
{
return show_slab_objects(s, buf, SO_PARTIAL);
@@ -3975,93 +4008,83 @@ static ssize_t objects_partial_show(struct kmem_cache *s, char *buf)
}
SLAB_ATTR_RO(objects_partial);
-static ssize_t total_objects_show(struct kmem_cache *s, char *buf)
-{
- return show_slab_objects(s, buf, SO_ALL|SO_TOTAL);
-}
-SLAB_ATTR_RO(total_objects);
-
-static ssize_t sanity_checks_show(struct kmem_cache *s, char *buf)
+static ssize_t reclaim_account_show(struct kmem_cache *s, char *buf)
{
- return sprintf(buf, "%d\n", !!(s->flags & SLAB_DEBUG_FREE));
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_RECLAIM_ACCOUNT));
}
-static ssize_t sanity_checks_store(struct kmem_cache *s,
+static ssize_t reclaim_account_store(struct kmem_cache *s,
const char *buf, size_t length)
{
- s->flags &= ~SLAB_DEBUG_FREE;
+ s->flags &= ~SLAB_RECLAIM_ACCOUNT;
if (buf[0] == '1')
- s->flags |= SLAB_DEBUG_FREE;
+ s->flags |= SLAB_RECLAIM_ACCOUNT;
return length;
}
-SLAB_ATTR(sanity_checks);
+SLAB_ATTR(reclaim_account);
-static ssize_t trace_show(struct kmem_cache *s, char *buf)
+static ssize_t hwcache_align_show(struct kmem_cache *s, char *buf)
{
- return sprintf(buf, "%d\n", !!(s->flags & SLAB_TRACE));
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_HWCACHE_ALIGN));
}
+SLAB_ATTR_RO(hwcache_align);
-static ssize_t trace_store(struct kmem_cache *s, const char *buf,
- size_t length)
+#ifdef CONFIG_ZONE_DMA
+static ssize_t cache_dma_show(struct kmem_cache *s, char *buf)
{
- s->flags &= ~SLAB_TRACE;
- if (buf[0] == '1')
- s->flags |= SLAB_TRACE;
- return length;
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_CACHE_DMA));
}
-SLAB_ATTR(trace);
+SLAB_ATTR_RO(cache_dma);
+#endif
-#ifdef CONFIG_FAILSLAB
-static ssize_t failslab_show(struct kmem_cache *s, char *buf)
+static ssize_t destroy_by_rcu_show(struct kmem_cache *s, char *buf)
{
- return sprintf(buf, "%d\n", !!(s->flags & SLAB_FAILSLAB));
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_DESTROY_BY_RCU));
}
+SLAB_ATTR_RO(destroy_by_rcu);
-static ssize_t failslab_store(struct kmem_cache *s, const char *buf,
- size_t length)
+#ifdef CONFIG_SLUB_DEBUG
+static ssize_t slabs_show(struct kmem_cache *s, char *buf)
{
- s->flags &= ~SLAB_FAILSLAB;
- if (buf[0] == '1')
- s->flags |= SLAB_FAILSLAB;
- return length;
+ return show_slab_objects(s, buf, SO_ALL);
}
-SLAB_ATTR(failslab);
-#endif
+SLAB_ATTR_RO(slabs);
-static ssize_t reclaim_account_show(struct kmem_cache *s, char *buf)
+static ssize_t total_objects_show(struct kmem_cache *s, char *buf)
{
- return sprintf(buf, "%d\n", !!(s->flags & SLAB_RECLAIM_ACCOUNT));
+ return show_slab_objects(s, buf, SO_ALL|SO_TOTAL);
}
+SLAB_ATTR_RO(total_objects);
-static ssize_t reclaim_account_store(struct kmem_cache *s,
- const char *buf, size_t length)
+static ssize_t sanity_checks_show(struct kmem_cache *s, char *buf)
{
- s->flags &= ~SLAB_RECLAIM_ACCOUNT;
- if (buf[0] == '1')
- s->flags |= SLAB_RECLAIM_ACCOUNT;
- return length;
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_DEBUG_FREE));
}
-SLAB_ATTR(reclaim_account);
-static ssize_t hwcache_align_show(struct kmem_cache *s, char *buf)
+static ssize_t sanity_checks_store(struct kmem_cache *s,
+ const char *buf, size_t length)
{
- return sprintf(buf, "%d\n", !!(s->flags & SLAB_HWCACHE_ALIGN));
+ s->flags &= ~SLAB_DEBUG_FREE;
+ if (buf[0] == '1')
+ s->flags |= SLAB_DEBUG_FREE;
+ return length;
}
-SLAB_ATTR_RO(hwcache_align);
+SLAB_ATTR(sanity_checks);
-#ifdef CONFIG_ZONE_DMA
-static ssize_t cache_dma_show(struct kmem_cache *s, char *buf)
+static ssize_t trace_show(struct kmem_cache *s, char *buf)
{
- return sprintf(buf, "%d\n", !!(s->flags & SLAB_CACHE_DMA));
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_TRACE));
}
-SLAB_ATTR_RO(cache_dma);
-#endif
-static ssize_t destroy_by_rcu_show(struct kmem_cache *s, char *buf)
+static ssize_t trace_store(struct kmem_cache *s, const char *buf,
+ size_t length)
{
- return sprintf(buf, "%d\n", !!(s->flags & SLAB_DESTROY_BY_RCU));
+ s->flags &= ~SLAB_TRACE;
+ if (buf[0] == '1')
+ s->flags |= SLAB_TRACE;
+ return length;
}
-SLAB_ATTR_RO(destroy_by_rcu);
+SLAB_ATTR(trace);
static ssize_t red_zone_show(struct kmem_cache *s, char *buf)
{
@@ -4139,6 +4162,40 @@ static ssize_t validate_store(struct kmem_cache *s,
}
SLAB_ATTR(validate);
+static ssize_t alloc_calls_show(struct kmem_cache *s, char *buf)
+{
+ if (!(s->flags & SLAB_STORE_USER))
+ return -ENOSYS;
+ return list_locations(s, buf, TRACK_ALLOC);
+}
+SLAB_ATTR_RO(alloc_calls);
+
+static ssize_t free_calls_show(struct kmem_cache *s, char *buf)
+{
+ if (!(s->flags & SLAB_STORE_USER))
+ return -ENOSYS;
+ return list_locations(s, buf, TRACK_FREE);
+}
+SLAB_ATTR_RO(free_calls);
+#endif /* CONFIG_SLUB_DEBUG */
+
+#ifdef CONFIG_FAILSLAB
+static ssize_t failslab_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_FAILSLAB));
+}
+
+static ssize_t failslab_store(struct kmem_cache *s, const char *buf,
+ size_t length)
+{
+ s->flags &= ~SLAB_FAILSLAB;
+ if (buf[0] == '1')
+ s->flags |= SLAB_FAILSLAB;
+ return length;
+}
+SLAB_ATTR(failslab);
+#endif
+
static ssize_t shrink_show(struct kmem_cache *s, char *buf)
{
return 0;
@@ -4158,22 +4215,6 @@ static ssize_t shrink_store(struct kmem_cache *s,
}
SLAB_ATTR(shrink);
-static ssize_t alloc_calls_show(struct kmem_cache *s, char *buf)
-{
- if (!(s->flags & SLAB_STORE_USER))
- return -ENOSYS;
- return list_locations(s, buf, TRACK_ALLOC);
-}
-SLAB_ATTR_RO(alloc_calls);
-
-static ssize_t free_calls_show(struct kmem_cache *s, char *buf)
-{
- if (!(s->flags & SLAB_STORE_USER))
- return -ENOSYS;
- return list_locations(s, buf, TRACK_FREE);
-}
-SLAB_ATTR_RO(free_calls);
-
#ifdef CONFIG_NUMA
static ssize_t remote_node_defrag_ratio_show(struct kmem_cache *s, char *buf)
{
@@ -4279,25 +4320,27 @@ static struct attribute *slab_attrs[] = {
&min_partial_attr.attr,
&objects_attr.attr,
&objects_partial_attr.attr,
- &total_objects_attr.attr,
- &slabs_attr.attr,
&partial_attr.attr,
&cpu_slabs_attr.attr,
&ctor_attr.attr,
&aliases_attr.attr,
&align_attr.attr,
- &sanity_checks_attr.attr,
- &trace_attr.attr,
&hwcache_align_attr.attr,
&reclaim_account_attr.attr,
&destroy_by_rcu_attr.attr,
+ &shrink_attr.attr,
+#ifdef CONFIG_SLUB_DEBUG
+ &total_objects_attr.attr,
+ &slabs_attr.attr,
+ &sanity_checks_attr.attr,
+ &trace_attr.attr,
&red_zone_attr.attr,
&poison_attr.attr,
&store_user_attr.attr,
&validate_attr.attr,
- &shrink_attr.attr,
&alloc_calls_attr.attr,
&free_calls_attr.attr,
+#endif
#ifdef CONFIG_ZONE_DMA
&cache_dma_attr.attr,
#endif
@@ -4377,6 +4420,7 @@ static void kmem_cache_release(struct kobject *kobj)
{
struct kmem_cache *s = to_slab(kobj);
+ kfree(s->name);
kfree(s);
}
@@ -4579,7 +4623,7 @@ static int __init slab_sysfs_init(void)
}
__initcall(slab_sysfs_init);
-#endif
+#endif /* CONFIG_SYSFS */
/*
* The /proc/slabinfo ABI
diff --git a/mm/swap.c b/mm/swap.c
index 3ce7bc373a52..3f4854205b16 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -378,6 +378,7 @@ void release_pages(struct page **pages, int nr, int cold)
pagevec_free(&pages_to_free);
}
+EXPORT_SYMBOL(release_pages);
/*
* The pages which we're about to release may be in the deferred lru-addition
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 9fc7bac7db0c..67ddaaf98c74 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -30,6 +30,7 @@
#include <linux/capability.h>
#include <linux/syscalls.h>
#include <linux/memcontrol.h>
+#include <linux/poll.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
@@ -58,6 +59,10 @@ static struct swap_info_struct *swap_info[MAX_SWAPFILES];
static DEFINE_MUTEX(swapon_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(proc_poll_wait);
+/* Activity counter to indicate that a swapon or swapoff has occurred */
+static atomic_t proc_poll_event = ATOMIC_INIT(0);
+
static inline unsigned char swap_count(unsigned char ent)
{
return ent & ~SWAP_HAS_CACHE; /* may include SWAP_HAS_CONT flag */
@@ -1680,6 +1685,8 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
}
filp_close(swap_file, NULL);
err = 0;
+ atomic_inc(&proc_poll_event);
+ wake_up_interruptible(&proc_poll_wait);
out_dput:
filp_close(victim, NULL);
@@ -1688,6 +1695,25 @@ out:
}
#ifdef CONFIG_PROC_FS
+struct proc_swaps {
+ struct seq_file seq;
+ int event;
+};
+
+static unsigned swaps_poll(struct file *file, poll_table *wait)
+{
+ struct proc_swaps *s = file->private_data;
+
+ poll_wait(file, &proc_poll_wait, wait);
+
+ if (s->event != atomic_read(&proc_poll_event)) {
+ s->event = atomic_read(&proc_poll_event);
+ return POLLIN | POLLRDNORM | POLLERR | POLLPRI;
+ }
+
+ return POLLIN | POLLRDNORM;
+}
+
/* iterator */
static void *swap_start(struct seq_file *swap, loff_t *pos)
{
@@ -1771,7 +1797,24 @@ static const struct seq_operations swaps_op = {
static int swaps_open(struct inode *inode, struct file *file)
{
- return seq_open(file, &swaps_op);
+ struct proc_swaps *s;
+ int ret;
+
+ s = kmalloc(sizeof(struct proc_swaps), GFP_KERNEL);
+ if (!s)
+ return -ENOMEM;
+
+ file->private_data = s;
+
+ ret = seq_open(file, &swaps_op);
+ if (ret) {
+ kfree(s);
+ return ret;
+ }
+
+ s->seq.private = s;
+ s->event = atomic_read(&proc_poll_event);
+ return ret;
}
static const struct file_operations proc_swaps_operations = {
@@ -1779,6 +1822,7 @@ static const struct file_operations proc_swaps_operations = {
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
+ .poll = swaps_poll,
};
static int __init procswaps_init(void)
@@ -2084,6 +2128,9 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
swap_info[prev]->next = type;
spin_unlock(&swap_lock);
mutex_unlock(&swapon_mutex);
+ atomic_inc(&proc_poll_event);
+ wake_up_interruptible(&proc_poll_wait);
+
error = 0;
goto out;
bad_swap:
diff --git a/mm/util.c b/mm/util.c
index 4735ea481816..73dac81e9f78 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -245,6 +245,19 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
}
#endif
+/*
+ * Like get_user_pages_fast() except its IRQ-safe in that it won't fall
+ * back to the regular GUP.
+ * If the architecture not support this fucntion, simply return with no
+ * page pinned
+ */
+int __attribute__((weak)) __get_user_pages_fast(unsigned long start,
+ int nr_pages, int write, struct page **pages)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__get_user_pages_fast);
+
/**
* get_user_pages_fast() - pin user pages in memory
* @start: starting user address
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 9f909622a25e..a3d66b3dc5cb 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -293,13 +293,13 @@ static void __insert_vmap_area(struct vmap_area *va)
struct rb_node *tmp;
while (*p) {
- struct vmap_area *tmp;
+ struct vmap_area *tmp_va;
parent = *p;
- tmp = rb_entry(parent, struct vmap_area, rb_node);
- if (va->va_start < tmp->va_end)
+ tmp_va = rb_entry(parent, struct vmap_area, rb_node);
+ if (va->va_start < tmp_va->va_end)
p = &(*p)->rb_left;
- else if (va->va_end > tmp->va_start)
+ else if (va->va_end > tmp_va->va_start)
p = &(*p)->rb_right;
else
BUG();
@@ -1596,6 +1596,13 @@ void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
}
EXPORT_SYMBOL(__vmalloc);
+static inline void *__vmalloc_node_flags(unsigned long size,
+ int node, gfp_t flags)
+{
+ return __vmalloc_node(size, 1, flags, PAGE_KERNEL,
+ node, __builtin_return_address(0));
+}
+
/**
* vmalloc - allocate virtually contiguous memory
* @size: allocation size
@@ -1607,12 +1614,28 @@ EXPORT_SYMBOL(__vmalloc);
*/
void *vmalloc(unsigned long size)
{
- return __vmalloc_node(size, 1, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL,
- -1, __builtin_return_address(0));
+ return __vmalloc_node_flags(size, -1, GFP_KERNEL | __GFP_HIGHMEM);
}
EXPORT_SYMBOL(vmalloc);
/**
+ * vzalloc - allocate virtually contiguous memory with zero fill
+ * @size: allocation size
+ * Allocate enough pages to cover @size from the page level
+ * allocator and map them into contiguous kernel virtual space.
+ * The memory allocated is set to zero.
+ *
+ * For tight control over page level allocator and protection flags
+ * use __vmalloc() instead.
+ */
+void *vzalloc(unsigned long size)
+{
+ return __vmalloc_node_flags(size, -1,
+ GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
+}
+EXPORT_SYMBOL(vzalloc);
+
+/**
* vmalloc_user - allocate zeroed virtually contiguous memory for userspace
* @size: allocation size
*
@@ -1653,6 +1676,25 @@ void *vmalloc_node(unsigned long size, int node)
}
EXPORT_SYMBOL(vmalloc_node);
+/**
+ * vzalloc_node - allocate memory on a specific node with zero fill
+ * @size: allocation size
+ * @node: numa node
+ *
+ * Allocate enough pages to cover @size from the page level
+ * allocator and map them into contiguous kernel virtual space.
+ * The memory allocated is set to zero.
+ *
+ * For tight control over page level allocator and protection flags
+ * use __vmalloc_node() instead.
+ */
+void *vzalloc_node(unsigned long size, int node)
+{
+ return __vmalloc_node_flags(size, node,
+ GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
+}
+EXPORT_SYMBOL(vzalloc_node);
+
#ifndef PAGE_KERNEL_EXEC
# define PAGE_KERNEL_EXEC PAGE_KERNEL
#endif
@@ -2350,6 +2392,7 @@ void pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms)
#ifdef CONFIG_PROC_FS
static void *s_start(struct seq_file *m, loff_t *pos)
+ __acquires(&vmlist_lock)
{
loff_t n = *pos;
struct vm_struct *v;
@@ -2376,6 +2419,7 @@ static void *s_next(struct seq_file *m, void *p, loff_t *pos)
}
static void s_stop(struct seq_file *m, void *p)
+ __releases(&vmlist_lock)
{
read_unlock(&vmlist_lock);
}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index c5dfabf25f11..b8a6fdc21312 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -51,6 +51,12 @@
#define CREATE_TRACE_POINTS
#include <trace/events/vmscan.h>
+enum lumpy_mode {
+ LUMPY_MODE_NONE,
+ LUMPY_MODE_ASYNC,
+ LUMPY_MODE_SYNC,
+};
+
struct scan_control {
/* Incremented by the number of inactive pages that were scanned */
unsigned long nr_scanned;
@@ -79,10 +85,10 @@ struct scan_control {
int order;
/*
- * Intend to reclaim enough contenious memory rather than to reclaim
- * enough amount memory. I.e, it's the mode for high order allocation.
+ * Intend to reclaim enough continuous memory rather than reclaim
+ * enough amount of memory. i.e, mode for high order allocation.
*/
- bool lumpy_reclaim_mode;
+ enum lumpy_mode lumpy_reclaim_mode;
/* Which cgroup do we reclaim from */
struct mem_cgroup *mem_cgroup;
@@ -265,6 +271,36 @@ unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
return ret;
}
+static void set_lumpy_reclaim_mode(int priority, struct scan_control *sc,
+ bool sync)
+{
+ enum lumpy_mode mode = sync ? LUMPY_MODE_SYNC : LUMPY_MODE_ASYNC;
+
+ /*
+ * Some reclaim have alredy been failed. No worth to try synchronous
+ * lumpy reclaim.
+ */
+ if (sync && sc->lumpy_reclaim_mode == LUMPY_MODE_NONE)
+ return;
+
+ /*
+ * If we need a large contiguous chunk of memory, or have
+ * trouble getting a small set of contiguous pages, we
+ * will reclaim both active and inactive pages.
+ */
+ if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
+ sc->lumpy_reclaim_mode = mode;
+ else if (sc->order && priority < DEF_PRIORITY - 2)
+ sc->lumpy_reclaim_mode = mode;
+ else
+ sc->lumpy_reclaim_mode = LUMPY_MODE_NONE;
+}
+
+static void disable_lumpy_reclaim_mode(struct scan_control *sc)
+{
+ sc->lumpy_reclaim_mode = LUMPY_MODE_NONE;
+}
+
static inline int is_page_cache_freeable(struct page *page)
{
/*
@@ -275,7 +311,8 @@ static inline int is_page_cache_freeable(struct page *page)
return page_count(page) - page_has_private(page) == 2;
}
-static int may_write_to_queue(struct backing_dev_info *bdi)
+static int may_write_to_queue(struct backing_dev_info *bdi,
+ struct scan_control *sc)
{
if (current->flags & PF_SWAPWRITE)
return 1;
@@ -283,6 +320,10 @@ static int may_write_to_queue(struct backing_dev_info *bdi)
return 1;
if (bdi == current->backing_dev_info)
return 1;
+
+ /* lumpy reclaim for hugepage often need a lot of write */
+ if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
+ return 1;
return 0;
}
@@ -307,12 +348,6 @@ static void handle_write_error(struct address_space *mapping,
unlock_page(page);
}
-/* Request for sync pageout. */
-enum pageout_io {
- PAGEOUT_IO_ASYNC,
- PAGEOUT_IO_SYNC,
-};
-
/* possible outcome of pageout() */
typedef enum {
/* failed to write page out, page is locked */
@@ -330,7 +365,7 @@ typedef enum {
* Calls ->writepage().
*/
static pageout_t pageout(struct page *page, struct address_space *mapping,
- enum pageout_io sync_writeback)
+ struct scan_control *sc)
{
/*
* If the page is dirty, only perform writeback if that write
@@ -366,7 +401,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
}
if (mapping->a_ops->writepage == NULL)
return PAGE_ACTIVATE;
- if (!may_write_to_queue(mapping->backing_dev_info))
+ if (!may_write_to_queue(mapping->backing_dev_info, sc))
return PAGE_KEEP;
if (clear_page_dirty_for_io(page)) {
@@ -376,7 +411,6 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
.nr_to_write = SWAP_CLUSTER_MAX,
.range_start = 0,
.range_end = LLONG_MAX,
- .nonblocking = 1,
.for_reclaim = 1,
};
@@ -394,7 +428,8 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
* direct reclaiming a large contiguous area and the
* first attempt to free a range of pages fails.
*/
- if (PageWriteback(page) && sync_writeback == PAGEOUT_IO_SYNC)
+ if (PageWriteback(page) &&
+ sc->lumpy_reclaim_mode == LUMPY_MODE_SYNC)
wait_on_page_writeback(page);
if (!PageWriteback(page)) {
@@ -402,7 +437,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
ClearPageReclaim(page);
}
trace_mm_vmscan_writepage(page,
- trace_reclaim_flags(page, sync_writeback));
+ trace_reclaim_flags(page, sc->lumpy_reclaim_mode));
inc_zone_page_state(page, NR_VMSCAN_WRITE);
return PAGE_SUCCESS;
}
@@ -580,7 +615,7 @@ static enum page_references page_check_references(struct page *page,
referenced_page = TestClearPageReferenced(page);
/* Lumpy reclaim - ignore references */
- if (sc->lumpy_reclaim_mode)
+ if (sc->lumpy_reclaim_mode != LUMPY_MODE_NONE)
return PAGEREF_RECLAIM;
/*
@@ -616,7 +651,7 @@ static enum page_references page_check_references(struct page *page,
}
/* Reclaim if clean, defer dirty pages to writeback */
- if (referenced_page)
+ if (referenced_page && !PageSwapBacked(page))
return PAGEREF_RECLAIM_CLEAN;
return PAGEREF_RECLAIM;
@@ -644,12 +679,14 @@ static noinline_for_stack void free_page_list(struct list_head *free_pages)
* shrink_page_list() returns the number of reclaimed pages
*/
static unsigned long shrink_page_list(struct list_head *page_list,
- struct scan_control *sc,
- enum pageout_io sync_writeback)
+ struct zone *zone,
+ struct scan_control *sc)
{
LIST_HEAD(ret_pages);
LIST_HEAD(free_pages);
int pgactivate = 0;
+ unsigned long nr_dirty = 0;
+ unsigned long nr_congested = 0;
unsigned long nr_reclaimed = 0;
cond_resched();
@@ -669,6 +706,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
goto keep;
VM_BUG_ON(PageActive(page));
+ VM_BUG_ON(page_zone(page) != zone);
sc->nr_scanned++;
@@ -694,10 +732,13 @@ static unsigned long shrink_page_list(struct list_head *page_list,
* for any page for which writeback has already
* started.
*/
- if (sync_writeback == PAGEOUT_IO_SYNC && may_enter_fs)
+ if (sc->lumpy_reclaim_mode == LUMPY_MODE_SYNC &&
+ may_enter_fs)
wait_on_page_writeback(page);
- else
- goto keep_locked;
+ else {
+ unlock_page(page);
+ goto keep_lumpy;
+ }
}
references = page_check_references(page, sc);
@@ -743,6 +784,8 @@ static unsigned long shrink_page_list(struct list_head *page_list,
}
if (PageDirty(page)) {
+ nr_dirty++;
+
if (references == PAGEREF_RECLAIM_CLEAN)
goto keep_locked;
if (!may_enter_fs)
@@ -751,14 +794,18 @@ static unsigned long shrink_page_list(struct list_head *page_list,
goto keep_locked;
/* Page is dirty, try to write it out here */
- switch (pageout(page, mapping, sync_writeback)) {
+ switch (pageout(page, mapping, sc)) {
case PAGE_KEEP:
+ nr_congested++;
goto keep_locked;
case PAGE_ACTIVATE:
goto activate_locked;
case PAGE_SUCCESS:
- if (PageWriteback(page) || PageDirty(page))
+ if (PageWriteback(page))
+ goto keep_lumpy;
+ if (PageDirty(page))
goto keep;
+
/*
* A synchronous write - probably a ramdisk. Go
* ahead and try to reclaim the page.
@@ -841,6 +888,7 @@ cull_mlocked:
try_to_free_swap(page);
unlock_page(page);
putback_lru_page(page);
+ disable_lumpy_reclaim_mode(sc);
continue;
activate_locked:
@@ -853,10 +901,21 @@ activate_locked:
keep_locked:
unlock_page(page);
keep:
+ disable_lumpy_reclaim_mode(sc);
+keep_lumpy:
list_add(&page->lru, &ret_pages);
VM_BUG_ON(PageLRU(page) || PageUnevictable(page));
}
+ /*
+ * Tag a zone as congested if all the dirty pages encountered were
+ * backed by a congested BDI. In this case, reclaimers should just
+ * back off and wait for congestion to clear because further reclaim
+ * will encounter the same problem
+ */
+ if (nr_dirty == nr_congested)
+ zone_set_flag(zone, ZONE_CONGESTED);
+
free_page_list(&free_pages);
list_splice(&ret_pages, page_list);
@@ -1006,7 +1065,7 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
/* Check that we have not crossed a zone boundary. */
if (unlikely(page_zone_id(cursor_page) != zone_id))
- continue;
+ break;
/*
* If we don't have enough swap space, reclaiming of
@@ -1014,8 +1073,8 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
* pointless.
*/
if (nr_swap_pages <= 0 && PageAnon(cursor_page) &&
- !PageSwapCache(cursor_page))
- continue;
+ !PageSwapCache(cursor_page))
+ break;
if (__isolate_lru_page(cursor_page, mode, file) == 0) {
list_move(&cursor_page->lru, dst);
@@ -1026,11 +1085,16 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
nr_lumpy_dirty++;
scan++;
} else {
- if (mode == ISOLATE_BOTH &&
- page_count(cursor_page))
- nr_lumpy_failed++;
+ /* the page is freed already. */
+ if (!page_count(cursor_page))
+ continue;
+ break;
}
}
+
+ /* If we break out of the loop above, lumpy reclaim failed */
+ if (pfn < end_pfn)
+ nr_lumpy_failed++;
}
*scanned = scan;
@@ -1253,7 +1317,7 @@ static inline bool should_reclaim_stall(unsigned long nr_taken,
return false;
/* Only stall on lumpy reclaim */
- if (!sc->lumpy_reclaim_mode)
+ if (sc->lumpy_reclaim_mode == LUMPY_MODE_NONE)
return false;
/* If we have relaimed everything on the isolated list, no stall */
@@ -1286,7 +1350,6 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
unsigned long nr_scanned;
unsigned long nr_reclaimed = 0;
unsigned long nr_taken;
- unsigned long nr_active;
unsigned long nr_anon;
unsigned long nr_file;
@@ -1298,15 +1361,15 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
return SWAP_CLUSTER_MAX;
}
-
+ set_lumpy_reclaim_mode(priority, sc, false);
lru_add_drain();
spin_lock_irq(&zone->lru_lock);
if (scanning_global_lru(sc)) {
nr_taken = isolate_pages_global(nr_to_scan,
&page_list, &nr_scanned, sc->order,
- sc->lumpy_reclaim_mode ?
- ISOLATE_BOTH : ISOLATE_INACTIVE,
+ sc->lumpy_reclaim_mode == LUMPY_MODE_NONE ?
+ ISOLATE_INACTIVE : ISOLATE_BOTH,
zone, 0, file);
zone->pages_scanned += nr_scanned;
if (current_is_kswapd())
@@ -1318,8 +1381,8 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
} else {
nr_taken = mem_cgroup_isolate_pages(nr_to_scan,
&page_list, &nr_scanned, sc->order,
- sc->lumpy_reclaim_mode ?
- ISOLATE_BOTH : ISOLATE_INACTIVE,
+ sc->lumpy_reclaim_mode == LUMPY_MODE_NONE ?
+ ISOLATE_INACTIVE : ISOLATE_BOTH,
zone, sc->mem_cgroup,
0, file);
/*
@@ -1337,20 +1400,12 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
spin_unlock_irq(&zone->lru_lock);
- nr_reclaimed = shrink_page_list(&page_list, sc, PAGEOUT_IO_ASYNC);
+ nr_reclaimed = shrink_page_list(&page_list, zone, sc);
/* Check if we should syncronously wait for writeback */
if (should_reclaim_stall(nr_taken, nr_reclaimed, priority, sc)) {
- congestion_wait(BLK_RW_ASYNC, HZ/10);
-
- /*
- * The attempt at page out may have made some
- * of the pages active, mark them inactive again.
- */
- nr_active = clear_active_flags(&page_list, NULL);
- count_vm_events(PGDEACTIVATE, nr_active);
-
- nr_reclaimed += shrink_page_list(&page_list, sc, PAGEOUT_IO_SYNC);
+ set_lumpy_reclaim_mode(priority, sc, true);
+ nr_reclaimed += shrink_page_list(&page_list, zone, sc);
}
local_irq_disable();
@@ -1359,6 +1414,12 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
__count_zone_vm_events(PGSTEAL, zone, nr_reclaimed);
putback_lru_pages(zone, sc, nr_anon, nr_file, &page_list);
+
+ trace_mm_vmscan_lru_shrink_inactive(zone->zone_pgdat->node_id,
+ zone_idx(zone),
+ nr_scanned, nr_reclaimed,
+ priority,
+ trace_shrink_flags(file, sc->lumpy_reclaim_mode));
return nr_reclaimed;
}
@@ -1506,6 +1567,7 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
spin_unlock_irq(&zone->lru_lock);
}
+#ifdef CONFIG_SWAP
static int inactive_anon_is_low_global(struct zone *zone)
{
unsigned long active, inactive;
@@ -1531,12 +1593,26 @@ static int inactive_anon_is_low(struct zone *zone, struct scan_control *sc)
{
int low;
+ /*
+ * If we don't have swap space, anonymous page deactivation
+ * is pointless.
+ */
+ if (!total_swap_pages)
+ return 0;
+
if (scanning_global_lru(sc))
low = inactive_anon_is_low_global(zone);
else
low = mem_cgroup_inactive_anon_is_low(sc->mem_cgroup);
return low;
}
+#else
+static inline int inactive_anon_is_low(struct zone *zone,
+ struct scan_control *sc)
+{
+ return 0;
+}
+#endif
static int inactive_file_is_low_global(struct zone *zone)
{
@@ -1721,21 +1797,6 @@ out:
}
}
-static void set_lumpy_reclaim_mode(int priority, struct scan_control *sc)
-{
- /*
- * If we need a large contiguous chunk of memory, or have
- * trouble getting a small set of contiguous pages, we
- * will reclaim both active and inactive pages.
- */
- if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
- sc->lumpy_reclaim_mode = 1;
- else if (sc->order && priority < DEF_PRIORITY - 2)
- sc->lumpy_reclaim_mode = 1;
- else
- sc->lumpy_reclaim_mode = 0;
-}
-
/*
* This is a basic per-zone page freer. Used by both kswapd and direct reclaim.
*/
@@ -1750,8 +1811,6 @@ static void shrink_zone(int priority, struct zone *zone,
get_scan_count(zone, sc, nr, priority);
- set_lumpy_reclaim_mode(priority, sc);
-
while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
nr[LRU_INACTIVE_FILE]) {
for_each_evictable_lru(l) {
@@ -1782,7 +1841,7 @@ static void shrink_zone(int priority, struct zone *zone,
* Even if we did not try to evict anon pages at all, we want to
* rebalance the anon lru active/inactive ratio.
*/
- if (inactive_anon_is_low(zone, sc) && nr_swap_pages > 0)
+ if (inactive_anon_is_low(zone, sc))
shrink_active_list(SWAP_CLUSTER_MAX, zone, sc, priority, 0);
throttle_vm_writeout(sc->gfp_mask);
@@ -1937,21 +1996,16 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
/* Take a nap, wait for some writeback to complete */
if (!sc->hibernation_mode && sc->nr_scanned &&
- priority < DEF_PRIORITY - 2)
- congestion_wait(BLK_RW_ASYNC, HZ/10);
+ priority < DEF_PRIORITY - 2) {
+ struct zone *preferred_zone;
+
+ first_zones_zonelist(zonelist, gfp_zone(sc->gfp_mask),
+ NULL, &preferred_zone);
+ wait_iff_congested(preferred_zone, BLK_RW_ASYNC, HZ/10);
+ }
}
out:
- /*
- * Now that we've scanned all the zones at this priority level, note
- * that level within the zone so that the next thread which performs
- * scanning of this zone will immediately start out at this priority
- * level. This affects only the decision whether or not to bring
- * mapped pages onto the inactive list.
- */
- if (priority < 0)
- priority = 0;
-
delayacct_freepages_end();
put_mems_allowed();
@@ -2247,6 +2301,15 @@ loop_again:
if (!zone_watermark_ok(zone, order,
min_wmark_pages(zone), end_zone, 0))
has_under_min_watermark_zone = 1;
+ } else {
+ /*
+ * If a zone reaches its high watermark,
+ * consider it to be no longer congested. It's
+ * possible there are dirty pages backed by
+ * congested BDIs but as pressure is relieved,
+ * spectulatively avoid congestion waits
+ */
+ zone_clear_flag(zone, ZONE_CONGESTED);
}
}
@@ -2987,6 +3050,7 @@ int scan_unevictable_handler(struct ctl_table *table, int write,
return 0;
}
+#ifdef CONFIG_NUMA
/*
* per node 'scan_unevictable_pages' attribute. On demand re-scan of
* a specified node's per zone unevictable lists for evictable pages.
@@ -3033,4 +3097,4 @@ void scan_unevictable_unregister_node(struct node *node)
{
sysdev_remove_file(&node->sysdev, &attr_scan_unevictable_pages);
}
-
+#endif
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 355a9e669aaa..cd2e42be7b68 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -17,6 +17,8 @@
#include <linux/vmstat.h>
#include <linux/sched.h>
#include <linux/math64.h>
+#include <linux/writeback.h>
+#include <linux/compaction.h>
#ifdef CONFIG_VM_EVENT_COUNTERS
DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
@@ -394,6 +396,7 @@ void zone_statistics(struct zone *preferred_zone, struct zone *z)
#endif
#ifdef CONFIG_COMPACTION
+
struct contig_page_info {
unsigned long free_pages;
unsigned long free_blocks_total;
@@ -745,6 +748,11 @@ static const char * const vmstat_text[] = {
"nr_isolated_anon",
"nr_isolated_file",
"nr_shmem",
+ "nr_dirtied",
+ "nr_written",
+ "nr_dirty_threshold",
+ "nr_dirty_background_threshold",
+
#ifdef CONFIG_NUMA
"numa_hit",
"numa_miss",
@@ -904,36 +912,44 @@ static const struct file_operations proc_zoneinfo_file_operations = {
.release = seq_release,
};
+enum writeback_stat_item {
+ NR_DIRTY_THRESHOLD,
+ NR_DIRTY_BG_THRESHOLD,
+ NR_VM_WRITEBACK_STAT_ITEMS,
+};
+
static void *vmstat_start(struct seq_file *m, loff_t *pos)
{
unsigned long *v;
-#ifdef CONFIG_VM_EVENT_COUNTERS
- unsigned long *e;
-#endif
- int i;
+ int i, stat_items_size;
if (*pos >= ARRAY_SIZE(vmstat_text))
return NULL;
+ stat_items_size = NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long) +
+ NR_VM_WRITEBACK_STAT_ITEMS * sizeof(unsigned long);
#ifdef CONFIG_VM_EVENT_COUNTERS
- v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long)
- + sizeof(struct vm_event_state), GFP_KERNEL);
-#else
- v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long),
- GFP_KERNEL);
+ stat_items_size += sizeof(struct vm_event_state);
#endif
+
+ v = kmalloc(stat_items_size, GFP_KERNEL);
m->private = v;
if (!v)
return ERR_PTR(-ENOMEM);
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
v[i] = global_page_state(i);
+ v += NR_VM_ZONE_STAT_ITEMS;
+
+ global_dirty_limits(v + NR_DIRTY_BG_THRESHOLD,
+ v + NR_DIRTY_THRESHOLD);
+ v += NR_VM_WRITEBACK_STAT_ITEMS;
+
#ifdef CONFIG_VM_EVENT_COUNTERS
- e = v + NR_VM_ZONE_STAT_ITEMS;
- all_vm_events(e);
- e[PGPGIN] /= 2; /* sectors -> kbytes */
- e[PGPGOUT] /= 2;
+ all_vm_events(v);
+ v[PGPGIN] /= 2; /* sectors -> kbytes */
+ v[PGPGOUT] /= 2;
#endif
- return v + *pos;
+ return m->private + *pos;
}
static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
diff --git a/net/802/fc.c b/net/802/fc.c
index 34cf1ee014b8..1e49f2d4ea96 100644
--- a/net/802/fc.c
+++ b/net/802/fc.c
@@ -70,7 +70,7 @@ static int fc_header(struct sk_buff *skb, struct net_device *dev,
if(daddr)
{
memcpy(fch->daddr,daddr,dev->addr_len);
- return(hdr_len);
+ return hdr_len;
}
return -hdr_len;
}
diff --git a/net/802/fddi.c b/net/802/fddi.c
index 3ef0ab0a543a..94b3ad08f39a 100644
--- a/net/802/fddi.c
+++ b/net/802/fddi.c
@@ -82,10 +82,10 @@ static int fddi_header(struct sk_buff *skb, struct net_device *dev,
if (daddr != NULL)
{
memcpy(fddi->daddr, daddr, dev->addr_len);
- return(hl);
+ return hl;
}
- return(-hl);
+ return -hl;
}
@@ -108,7 +108,7 @@ static int fddi_rebuild_header(struct sk_buff *skb)
{
printk("%s: Don't know how to resolve type %04X addresses.\n",
skb->dev->name, ntohs(fddi->hdr.llc_snap.ethertype));
- return(0);
+ return 0;
}
}
@@ -162,7 +162,7 @@ __be16 fddi_type_trans(struct sk_buff *skb, struct net_device *dev)
/* Assume 802.2 SNAP frames, for now */
- return(type);
+ return type;
}
EXPORT_SYMBOL(fddi_type_trans);
@@ -170,9 +170,9 @@ EXPORT_SYMBOL(fddi_type_trans);
int fddi_change_mtu(struct net_device *dev, int new_mtu)
{
if ((new_mtu < FDDI_K_SNAP_HLEN) || (new_mtu > FDDI_K_SNAP_DLEN))
- return(-EINVAL);
+ return -EINVAL;
dev->mtu = new_mtu;
- return(0);
+ return 0;
}
EXPORT_SYMBOL(fddi_change_mtu);
diff --git a/net/802/garp.c b/net/802/garp.c
index 941f2a324d3a..c1df2dad8c6b 100644
--- a/net/802/garp.c
+++ b/net/802/garp.c
@@ -346,8 +346,8 @@ int garp_request_join(const struct net_device *dev,
const struct garp_application *appl,
const void *data, u8 len, u8 type)
{
- struct garp_port *port = dev->garp_port;
- struct garp_applicant *app = port->applicants[appl->type];
+ struct garp_port *port = rtnl_dereference(dev->garp_port);
+ struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]);
struct garp_attr *attr;
spin_lock_bh(&app->lock);
@@ -366,8 +366,8 @@ void garp_request_leave(const struct net_device *dev,
const struct garp_application *appl,
const void *data, u8 len, u8 type)
{
- struct garp_port *port = dev->garp_port;
- struct garp_applicant *app = port->applicants[appl->type];
+ struct garp_port *port = rtnl_dereference(dev->garp_port);
+ struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]);
struct garp_attr *attr;
spin_lock_bh(&app->lock);
@@ -546,11 +546,11 @@ static int garp_init_port(struct net_device *dev)
static void garp_release_port(struct net_device *dev)
{
- struct garp_port *port = dev->garp_port;
+ struct garp_port *port = rtnl_dereference(dev->garp_port);
unsigned int i;
for (i = 0; i <= GARP_APPLICATION_MAX; i++) {
- if (port->applicants[i])
+ if (rtnl_dereference(port->applicants[i]))
return;
}
rcu_assign_pointer(dev->garp_port, NULL);
@@ -565,7 +565,7 @@ int garp_init_applicant(struct net_device *dev, struct garp_application *appl)
ASSERT_RTNL();
- if (!dev->garp_port) {
+ if (!rtnl_dereference(dev->garp_port)) {
err = garp_init_port(dev);
if (err < 0)
goto err1;
@@ -601,8 +601,8 @@ EXPORT_SYMBOL_GPL(garp_init_applicant);
void garp_uninit_applicant(struct net_device *dev, struct garp_application *appl)
{
- struct garp_port *port = dev->garp_port;
- struct garp_applicant *app = port->applicants[appl->type];
+ struct garp_port *port = rtnl_dereference(dev->garp_port);
+ struct garp_applicant *app = rtnl_dereference(port->applicants[appl->type]);
ASSERT_RTNL();
diff --git a/net/802/hippi.c b/net/802/hippi.c
index cd3e8e929529..91aca8780fd0 100644
--- a/net/802/hippi.c
+++ b/net/802/hippi.c
@@ -152,7 +152,7 @@ int hippi_change_mtu(struct net_device *dev, int new_mtu)
if ((new_mtu < 68) || (new_mtu > 65280))
return -EINVAL;
dev->mtu = new_mtu;
- return(0);
+ return 0;
}
EXPORT_SYMBOL(hippi_change_mtu);
diff --git a/net/802/stp.c b/net/802/stp.c
index 53c8f77f0ccd..978c30b1b36b 100644
--- a/net/802/stp.c
+++ b/net/802/stp.c
@@ -21,8 +21,8 @@
#define GARP_ADDR_MAX 0x2F
#define GARP_ADDR_RANGE (GARP_ADDR_MAX - GARP_ADDR_MIN)
-static const struct stp_proto *garp_protos[GARP_ADDR_RANGE + 1] __read_mostly;
-static const struct stp_proto *stp_proto __read_mostly;
+static const struct stp_proto __rcu *garp_protos[GARP_ADDR_RANGE + 1] __read_mostly;
+static const struct stp_proto __rcu *stp_proto __read_mostly;
static struct llc_sap *sap __read_mostly;
static unsigned int sap_registered;
diff --git a/net/802/tr.c b/net/802/tr.c
index 1c6e596074df..5e20cf8a074b 100644
--- a/net/802/tr.c
+++ b/net/802/tr.c
@@ -145,7 +145,7 @@ static int tr_header(struct sk_buff *skb, struct net_device *dev,
{
memcpy(trh->daddr,daddr,dev->addr_len);
tr_source_route(skb, trh, dev);
- return(hdr_len);
+ return hdr_len;
}
return -hdr_len;
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index a2ad15250575..52077ca22072 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -44,9 +44,6 @@
int vlan_net_id __read_mostly;
-/* Our listing of VLAN group(s) */
-static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE];
-
const char vlan_fullname[] = "802.1Q VLAN Support";
const char vlan_version[] = DRV_VERSION;
static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
@@ -59,40 +56,6 @@ static struct packet_type vlan_packet_type __read_mostly = {
/* End of global variables definitions. */
-static inline unsigned int vlan_grp_hashfn(unsigned int idx)
-{
- return ((idx >> VLAN_GRP_HASH_SHIFT) ^ idx) & VLAN_GRP_HASH_MASK;
-}
-
-/* Must be invoked with RCU read lock (no preempt) */
-static struct vlan_group *__vlan_find_group(struct net_device *real_dev)
-{
- struct vlan_group *grp;
- struct hlist_node *n;
- int hash = vlan_grp_hashfn(real_dev->ifindex);
-
- hlist_for_each_entry_rcu(grp, n, &vlan_group_hash[hash], hlist) {
- if (grp->real_dev == real_dev)
- return grp;
- }
-
- return NULL;
-}
-
-/* Find the protocol handler. Assumes VID < VLAN_VID_MASK.
- *
- * Must be invoked with RCU read lock (no preempt)
- */
-struct net_device *__find_vlan_dev(struct net_device *real_dev, u16 vlan_id)
-{
- struct vlan_group *grp = __vlan_find_group(real_dev);
-
- if (grp)
- return vlan_group_get_device(grp, vlan_id);
-
- return NULL;
-}
-
static void vlan_group_free(struct vlan_group *grp)
{
int i;
@@ -111,8 +74,6 @@ static struct vlan_group *vlan_group_alloc(struct net_device *real_dev)
return NULL;
grp->real_dev = real_dev;
- hlist_add_head_rcu(&grp->hlist,
- &vlan_group_hash[vlan_grp_hashfn(real_dev->ifindex)]);
return grp;
}
@@ -151,7 +112,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
ASSERT_RTNL();
- grp = __vlan_find_group(real_dev);
+ grp = rtnl_dereference(real_dev->vlgrp);
BUG_ON(!grp);
/* Take it out of our own structures, but be sure to interlock with
@@ -173,11 +134,10 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
if (grp->nr_vlans == 0) {
vlan_gvrp_uninit_applicant(real_dev);
- if (real_dev->features & NETIF_F_HW_VLAN_RX)
+ rcu_assign_pointer(real_dev->vlgrp, NULL);
+ if (ops->ndo_vlan_rx_register)
ops->ndo_vlan_rx_register(real_dev, NULL);
- hlist_del_rcu(&grp->hlist);
-
/* Free the group, after all cpu's are done. */
call_rcu(&grp->rcu, vlan_rcu_free);
}
@@ -196,18 +156,13 @@ int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id)
return -EOPNOTSUPP;
}
- if ((real_dev->features & NETIF_F_HW_VLAN_RX) && !ops->ndo_vlan_rx_register) {
- pr_info("8021q: device %s has buggy VLAN hw accel\n", name);
- return -EOPNOTSUPP;
- }
-
if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&
(!ops->ndo_vlan_rx_add_vid || !ops->ndo_vlan_rx_kill_vid)) {
pr_info("8021q: Device %s has buggy VLAN hw accel\n", name);
return -EOPNOTSUPP;
}
- if (__find_vlan_dev(real_dev, vlan_id) != NULL)
+ if (vlan_find_dev(real_dev, vlan_id) != NULL)
return -EEXIST;
return 0;
@@ -222,7 +177,7 @@ int register_vlan_dev(struct net_device *dev)
struct vlan_group *grp, *ngrp = NULL;
int err;
- grp = __vlan_find_group(real_dev);
+ grp = rtnl_dereference(real_dev->vlgrp);
if (!grp) {
ngrp = grp = vlan_group_alloc(real_dev);
if (!grp)
@@ -252,8 +207,11 @@ int register_vlan_dev(struct net_device *dev)
vlan_group_set_device(grp, vlan_id, dev);
grp->nr_vlans++;
- if (ngrp && real_dev->features & NETIF_F_HW_VLAN_RX)
- ops->ndo_vlan_rx_register(real_dev, ngrp);
+ if (ngrp) {
+ if (ops->ndo_vlan_rx_register)
+ ops->ndo_vlan_rx_register(real_dev, ngrp);
+ rcu_assign_pointer(real_dev->vlgrp, ngrp);
+ }
if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
ops->ndo_vlan_rx_add_vid(real_dev, vlan_id);
@@ -264,7 +222,6 @@ out_uninit_applicant:
vlan_gvrp_uninit_applicant(real_dev);
out_free_group:
if (ngrp) {
- hlist_del_rcu(&ngrp->hlist);
/* Free the group, after all cpu's are done. */
call_rcu(&ngrp->rcu, vlan_rcu_free);
}
@@ -321,7 +278,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
if (new_dev == NULL)
return -ENOBUFS;
- new_dev->real_num_tx_queues = real_dev->real_num_tx_queues;
+ netif_copy_real_num_queues(new_dev, real_dev);
dev_net_set(new_dev, net);
/* need 4 bytes for extra VLAN header info,
* hope the underlying device can handle it.
@@ -428,7 +385,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
dev->netdev_ops->ndo_vlan_rx_add_vid(dev, 0);
}
- grp = __vlan_find_group(dev);
+ grp = rtnl_dereference(dev->vlgrp);
if (!grp)
goto out;
@@ -439,7 +396,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
switch (event) {
case NETDEV_CHANGE:
/* Propagate real device state to vlan devices */
- for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
@@ -450,7 +407,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
case NETDEV_CHANGEADDR:
/* Adjust unicast filters on underlying device */
- for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
@@ -464,7 +421,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
break;
case NETDEV_CHANGEMTU:
- for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
@@ -478,7 +435,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
case NETDEV_FEAT_CHANGE:
/* Propagate device features to underlying device */
- for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
@@ -490,7 +447,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
case NETDEV_DOWN:
/* Put all VLANs for this dev in the down state too. */
- for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
@@ -508,7 +465,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
case NETDEV_UP:
/* Put all VLANs for this dev in the up state too. */
- for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
@@ -525,10 +482,14 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
break;
case NETDEV_UNREGISTER:
+ /* twiddle thumbs on netns device moves */
+ if (dev->reg_state != NETREG_UNREGISTERING)
+ break;
+
/* Delete all VLANs for this dev. */
grp->killall = 1;
- for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ for (i = 0; i < VLAN_N_VID; i++) {
vlandev = vlan_group_get_device(grp, i);
if (!vlandev)
continue;
@@ -536,7 +497,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
/* unregistration of last vlan destroys group, abort
* afterwards */
if (grp->nr_vlans == 1)
- i = VLAN_GROUP_ARRAY_LEN;
+ i = VLAN_N_VID;
unregister_vlan_dev(vlandev, &list);
}
@@ -742,8 +703,6 @@ err0:
static void __exit vlan_cleanup_module(void)
{
- unsigned int i;
-
vlan_ioctl_set(NULL);
vlan_netlink_fini();
@@ -751,10 +710,6 @@ static void __exit vlan_cleanup_module(void)
dev_remove_pack(&vlan_packet_type);
- /* This table must be empty if there are no module references left. */
- for (i = 0; i < VLAN_GRP_HASH_SIZE; i++)
- BUG_ON(!hlist_empty(&vlan_group_hash[i]));
-
unregister_pernet_subsys(&vlan_net_ops);
rcu_barrier(); /* Wait for completion of call_rcu()'s */
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index 8d9503ad01da..db01b3181fdc 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -72,23 +72,6 @@ static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev)
return netdev_priv(dev);
}
-#define VLAN_GRP_HASH_SHIFT 5
-#define VLAN_GRP_HASH_SIZE (1 << VLAN_GRP_HASH_SHIFT)
-#define VLAN_GRP_HASH_MASK (VLAN_GRP_HASH_SIZE - 1)
-
-/* Find a VLAN device by the MAC address of its Ethernet device, and
- * it's VLAN ID. The default configuration is to have VLAN's scope
- * to be box-wide, so the MAC will be ignored. The mac will only be
- * looked at if we are configured to have a separate set of VLANs per
- * each MAC addressable interface. Note that this latter option does
- * NOT follow the spec for VLANs, but may be useful for doing very
- * large quantities of VLAN MUX/DEMUX onto FrameRelay or ATM PVCs.
- *
- * Must be invoked with rcu_read_lock (ie preempt disabled)
- * or with RTNL.
- */
-struct net_device *__find_vlan_dev(struct net_device *real_dev, u16 vlan_id);
-
/* found in vlan_dev.c */
int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *ptype, struct net_device *orig_dev);
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 0eb96f7e44be..69b2f79800a5 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -4,53 +4,29 @@
#include <linux/netpoll.h>
#include "vlan.h"
-/* VLAN rx hw acceleration helper. This acts like netif_{rx,receive_skb}(). */
-int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
- u16 vlan_tci, int polling)
+bool vlan_hwaccel_do_receive(struct sk_buff **skbp)
{
+ struct sk_buff *skb = *skbp;
+ u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK;
struct net_device *vlan_dev;
- u16 vlan_id;
-
- if (netpoll_rx(skb))
- return NET_RX_DROP;
-
- if (skb_bond_should_drop(skb, ACCESS_ONCE(skb->dev->master)))
- skb->deliver_no_wcard = 1;
+ struct vlan_rx_stats *rx_stats;
- skb->skb_iif = skb->dev->ifindex;
- __vlan_hwaccel_put_tag(skb, vlan_tci);
- vlan_id = vlan_tci & VLAN_VID_MASK;
- vlan_dev = vlan_group_get_device(grp, vlan_id);
-
- if (vlan_dev)
- skb->dev = vlan_dev;
- else if (vlan_id) {
- if (!(skb->dev->flags & IFF_PROMISC))
- goto drop;
- skb->pkt_type = PACKET_OTHERHOST;
+ vlan_dev = vlan_find_dev(skb->dev, vlan_id);
+ if (!vlan_dev) {
+ if (vlan_id)
+ skb->pkt_type = PACKET_OTHERHOST;
+ return false;
}
- return (polling ? netif_receive_skb(skb) : netif_rx(skb));
+ skb = *skbp = skb_share_check(skb, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return false;
-drop:
- dev_kfree_skb_any(skb);
- return NET_RX_DROP;
-}
-EXPORT_SYMBOL(__vlan_hwaccel_rx);
-
-int vlan_hwaccel_do_receive(struct sk_buff *skb)
-{
- struct net_device *dev = skb->dev;
- struct vlan_rx_stats *rx_stats;
-
- skb->dev = vlan_dev_info(dev)->real_dev;
- netif_nit_deliver(skb);
-
- skb->dev = dev;
- skb->priority = vlan_get_ingress_priority(dev, skb->vlan_tci);
+ skb->dev = vlan_dev;
+ skb->priority = vlan_get_ingress_priority(vlan_dev, skb->vlan_tci);
skb->vlan_tci = 0;
- rx_stats = this_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats);
+ rx_stats = this_cpu_ptr(vlan_dev_info(vlan_dev)->vlan_rx_stats);
u64_stats_update_begin(&rx_stats->syncp);
rx_stats->rx_packets++;
@@ -67,12 +43,13 @@ int vlan_hwaccel_do_receive(struct sk_buff *skb)
* This allows the VLAN to have a different MAC than the
* underlying device, and still route correctly. */
if (!compare_ether_addr(eth_hdr(skb)->h_dest,
- dev->dev_addr))
+ vlan_dev->dev_addr))
skb->pkt_type = PACKET_HOST;
break;
}
u64_stats_update_end(&rx_stats->syncp);
- return 0;
+
+ return true;
}
struct net_device *vlan_dev_real_dev(const struct net_device *dev)
@@ -87,71 +64,27 @@ u16 vlan_dev_vlan_id(const struct net_device *dev)
}
EXPORT_SYMBOL(vlan_dev_vlan_id);
-static gro_result_t
-vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp,
- unsigned int vlan_tci, struct sk_buff *skb)
+/* VLAN rx hw acceleration helper. This acts like netif_{rx,receive_skb}(). */
+int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
+ u16 vlan_tci, int polling)
{
- struct sk_buff *p;
- struct net_device *vlan_dev;
- u16 vlan_id;
-
- if (skb_bond_should_drop(skb, ACCESS_ONCE(skb->dev->master)))
- skb->deliver_no_wcard = 1;
-
- skb->skb_iif = skb->dev->ifindex;
__vlan_hwaccel_put_tag(skb, vlan_tci);
- vlan_id = vlan_tci & VLAN_VID_MASK;
- vlan_dev = vlan_group_get_device(grp, vlan_id);
-
- if (vlan_dev)
- skb->dev = vlan_dev;
- else if (vlan_id) {
- if (!(skb->dev->flags & IFF_PROMISC))
- goto drop;
- skb->pkt_type = PACKET_OTHERHOST;
- }
-
- for (p = napi->gro_list; p; p = p->next) {
- NAPI_GRO_CB(p)->same_flow =
- p->dev == skb->dev && !compare_ether_header(
- skb_mac_header(p), skb_gro_mac_header(skb));
- NAPI_GRO_CB(p)->flush = 0;
- }
-
- return dev_gro_receive(napi, skb);
-
-drop:
- return GRO_DROP;
+ return polling ? netif_receive_skb(skb) : netif_rx(skb);
}
+EXPORT_SYMBOL(__vlan_hwaccel_rx);
gro_result_t vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
unsigned int vlan_tci, struct sk_buff *skb)
{
- if (netpoll_rx_on(skb))
- return vlan_hwaccel_receive_skb(skb, grp, vlan_tci)
- ? GRO_DROP : GRO_NORMAL;
-
- skb_gro_reset_offset(skb);
-
- return napi_skb_finish(vlan_gro_common(napi, grp, vlan_tci, skb), skb);
+ __vlan_hwaccel_put_tag(skb, vlan_tci);
+ return napi_gro_receive(napi, skb);
}
EXPORT_SYMBOL(vlan_gro_receive);
gro_result_t vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp,
unsigned int vlan_tci)
{
- struct sk_buff *skb = napi_frags_skb(napi);
-
- if (!skb)
- return GRO_DROP;
-
- if (netpoll_rx_on(skb)) {
- skb->protocol = eth_type_trans(skb, skb->dev);
- return vlan_hwaccel_receive_skb(skb, grp, vlan_tci)
- ? GRO_DROP : GRO_NORMAL;
- }
-
- return napi_frags_finish(napi, skb,
- vlan_gro_common(napi, grp, vlan_tci, skb));
+ __vlan_hwaccel_put_tag(napi->skb, vlan_tci);
+ return napi_gro_frags(napi);
}
EXPORT_SYMBOL(vlan_gro_frags);
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 3bccdd12a264..14e3d1fa07a0 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -158,7 +158,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
vlan_id = vlan_tci & VLAN_VID_MASK;
rcu_read_lock();
- vlan_dev = __find_vlan_dev(dev, vlan_id);
+ vlan_dev = vlan_find_dev(dev, vlan_id);
/* If the VLAN device is defined, we use it.
* If not, and the VID is 0, it is a 802.1p packet (not
@@ -177,8 +177,8 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
} else {
skb->dev = vlan_dev;
- rx_stats = per_cpu_ptr(vlan_dev_info(skb->dev)->vlan_rx_stats,
- smp_processor_id());
+ rx_stats = this_cpu_ptr(vlan_dev_info(skb->dev)->vlan_rx_stats);
+
u64_stats_update_begin(&rx_stats->syncp);
rx_stats->rx_packets++;
rx_stats->rx_bytes += skb->len;
@@ -226,12 +226,14 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
}
netif_rx(skb);
+
rcu_read_unlock();
return NET_RX_SUCCESS;
err_unlock:
rcu_read_unlock();
err_free:
+ atomic_long_inc(&dev->rx_dropped);
kfree_skb(skb);
return NET_RX_DROP;
}
@@ -843,7 +845,7 @@ static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, st
accum.rx_packets += rxpackets;
accum.rx_bytes += rxbytes;
accum.rx_multicast += rxmulticast;
- /* rx_errors is an ulong, not protected by syncp */
+ /* rx_errors is ulong, not protected by syncp */
accum.rx_errors += p->rx_errors;
}
stats->rx_packets = accum.rx_packets;
diff --git a/net/9p/client.c b/net/9p/client.c
index 9eb72505308f..a848bca9fbff 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -61,13 +61,13 @@ static const match_table_t tokens = {
inline int p9_is_proto_dotl(struct p9_client *clnt)
{
- return (clnt->proto_version == p9_proto_2000L);
+ return clnt->proto_version == p9_proto_2000L;
}
EXPORT_SYMBOL(p9_is_proto_dotl);
inline int p9_is_proto_dotu(struct p9_client *clnt)
{
- return (clnt->proto_version == p9_proto_2000u);
+ return clnt->proto_version == p9_proto_2000u;
}
EXPORT_SYMBOL(p9_is_proto_dotu);
@@ -450,32 +450,43 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
return err;
}
- if (type == P9_RERROR) {
+ if (type == P9_RERROR || type == P9_RLERROR) {
int ecode;
- char *ename;
- err = p9pdu_readf(req->rc, c->proto_version, "s?d",
- &ename, &ecode);
- if (err) {
- P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
- err);
- return err;
- }
+ if (!p9_is_proto_dotl(c)) {
+ char *ename;
- if (p9_is_proto_dotu(c) ||
- p9_is_proto_dotl(c))
- err = -ecode;
+ err = p9pdu_readf(req->rc, c->proto_version, "s?d",
+ &ename, &ecode);
+ if (err)
+ goto out_err;
+
+ if (p9_is_proto_dotu(c))
+ err = -ecode;
- if (!err || !IS_ERR_VALUE(err))
- err = p9_errstr2errno(ename, strlen(ename));
+ 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, "<<< RERROR (%d) %s\n", -ecode, ename);
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
+ }
- kfree(ename);
} else
err = 0;
return err;
+
+out_err:
+ P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", err);
+
+ return err;
}
/**
@@ -568,11 +579,14 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
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);
err = c->trans_mod->request(c, req);
if (err < 0) {
- c->status = Disconnected;
+ if (err != -ERESTARTSYS)
+ c->status = Disconnected;
goto reterr;
}
@@ -671,7 +685,7 @@ static void p9_fid_destroy(struct p9_fid *fid)
kfree(fid);
}
-int p9_client_version(struct p9_client *c)
+static int p9_client_version(struct p9_client *c)
{
int err = 0;
struct p9_req_t *req;
@@ -730,7 +744,6 @@ error:
return err;
}
-EXPORT_SYMBOL(p9_client_version);
struct p9_client *p9_client_create(const char *dev_name, char *options)
{
@@ -887,54 +900,6 @@ error:
}
EXPORT_SYMBOL(p9_client_attach);
-struct p9_fid *
-p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname)
-{
- int err;
- struct p9_req_t *req;
- struct p9_qid qid;
- struct p9_fid *afid;
-
- P9_DPRINTK(P9_DEBUG_9P, ">>> TAUTH uname %s aname %s\n", uname, aname);
- err = 0;
-
- afid = p9_fid_create(clnt);
- if (IS_ERR(afid)) {
- err = PTR_ERR(afid);
- afid = NULL;
- goto error;
- }
-
- req = p9_client_rpc(clnt, P9_TAUTH, "dss?d",
- afid ? afid->fid : P9_NOFID, uname, aname, n_uname);
- if (IS_ERR(req)) {
- err = PTR_ERR(req);
- goto error;
- }
-
- err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
- if (err) {
- p9pdu_dump(1, req->rc);
- p9_free_req(clnt, req);
- goto error;
- }
-
- P9_DPRINTK(P9_DEBUG_9P, "<<< RAUTH qid %x.%llx.%x\n",
- qid.type,
- (unsigned long long)qid.path,
- qid.version);
-
- memmove(&afid->qid, &qid, sizeof(struct p9_qid));
- p9_free_req(clnt, req);
- return afid;
-
-error:
- if (afid)
- p9_fid_destroy(afid);
- return ERR_PTR(err);
-}
-EXPORT_SYMBOL(p9_client_auth);
-
struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
int clone)
{
@@ -1200,12 +1165,44 @@ int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname)
}
EXPORT_SYMBOL(p9_client_link);
+int p9_client_fsync(struct p9_fid *fid, int datasync)
+{
+ int err;
+ struct p9_client *clnt;
+ struct p9_req_t *req;
+
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TFSYNC fid %d datasync:%d\n",
+ fid->fid, datasync);
+ err = 0;
+ clnt = fid->clnt;
+
+ req = p9_client_rpc(clnt, P9_TFSYNC, "dd", fid->fid, datasync);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto error;
+ }
+
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RFSYNC fid %d\n", fid->fid);
+
+ p9_free_req(clnt, req);
+
+error:
+ return err;
+}
+EXPORT_SYMBOL(p9_client_fsync);
+
int p9_client_clunk(struct p9_fid *fid)
{
int err;
struct p9_client *clnt;
struct p9_req_t *req;
+ if (!fid) {
+ P9_EPRINTK(KERN_WARNING, "Trying to clunk with NULL fid\n");
+ dump_stack();
+ return 0;
+ }
+
P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid);
err = 0;
clnt = fid->clnt;
@@ -1289,16 +1286,13 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
if (data) {
memmove(data, dataptr, count);
- }
-
- if (udata) {
+ } else {
err = copy_to_user(udata, dataptr, count);
if (err) {
err = -EFAULT;
goto free_and_error;
}
}
-
p9_free_req(clnt, req);
return count;
@@ -1810,3 +1804,96 @@ error:
}
EXPORT_SYMBOL(p9_client_mkdir_dotl);
+
+int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status)
+{
+ int err;
+ struct p9_client *clnt;
+ struct p9_req_t *req;
+
+ err = 0;
+ clnt = fid->clnt;
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TLOCK fid %d type %i flags %d "
+ "start %lld length %lld proc_id %d client_id %s\n",
+ fid->fid, flock->type, flock->flags, flock->start,
+ flock->length, flock->proc_id, flock->client_id);
+
+ req = p9_client_rpc(clnt, P9_TLOCK, "dbdqqds", fid->fid, flock->type,
+ flock->flags, flock->start, flock->length,
+ flock->proc_id, flock->client_id);
+
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ err = p9pdu_readf(req->rc, clnt->proto_version, "b", status);
+ if (err) {
+ p9pdu_dump(1, req->rc);
+ goto error;
+ }
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status);
+error:
+ p9_free_req(clnt, req);
+ return err;
+
+}
+EXPORT_SYMBOL(p9_client_lock_dotl);
+
+int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock)
+{
+ int err;
+ struct p9_client *clnt;
+ struct p9_req_t *req;
+
+ err = 0;
+ clnt = fid->clnt;
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TGETLOCK fid %d, type %i start %lld "
+ "length %lld proc_id %d client_id %s\n", fid->fid, glock->type,
+ glock->start, glock->length, glock->proc_id, glock->client_id);
+
+ req = p9_client_rpc(clnt, P9_TGETLOCK, "dbqqds", fid->fid, glock->type,
+ glock->start, glock->length, glock->proc_id, glock->client_id);
+
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ err = p9pdu_readf(req->rc, clnt->proto_version, "bqqds", &glock->type,
+ &glock->start, &glock->length, &glock->proc_id,
+ &glock->client_id);
+ if (err) {
+ p9pdu_dump(1, req->rc);
+ goto error;
+ }
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld "
+ "proc_id %d client_id %s\n", glock->type, glock->start,
+ glock->length, glock->proc_id, glock->client_id);
+error:
+ p9_free_req(clnt, req);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_getlock_dotl);
+
+int p9_client_readlink(struct p9_fid *fid, char **target)
+{
+ int err;
+ struct p9_client *clnt;
+ struct p9_req_t *req;
+
+ err = 0;
+ clnt = fid->clnt;
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TREADLINK fid %d\n", fid->fid);
+
+ req = p9_client_rpc(clnt, P9_TREADLINK, "d", fid->fid);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ err = p9pdu_readf(req->rc, clnt->proto_version, "s", target);
+ if (err) {
+ p9pdu_dump(1, req->rc);
+ goto error;
+ }
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target);
+error:
+ p9_free_req(clnt, req);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_readlink);
diff --git a/net/9p/protocol.c b/net/9p/protocol.c
index 3acd3afb20c8..45c15f491401 100644
--- a/net/9p/protocol.c
+++ b/net/9p/protocol.c
@@ -122,9 +122,8 @@ static size_t
pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
{
size_t len = MIN(pdu->capacity - pdu->size, size);
- int err = copy_from_user(&pdu->sdata[pdu->size], udata, len);
- if (err)
- printk(KERN_WARNING "pdu_write_u returning: %d\n", err);
+ if (copy_from_user(&pdu->sdata[pdu->size], udata, len))
+ len = 0;
pdu->size += len;
return size - len;
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index c85109d809ca..078eb162d9bf 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -222,7 +222,7 @@ static void p9_conn_cancel(struct p9_conn *m, int err)
}
}
-static unsigned int
+static int
p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt)
{
int ret, n;
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index b88515936e4b..c8f3f72ab20e 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -75,6 +75,8 @@ struct virtio_chan {
struct p9_client *client;
struct virtio_device *vdev;
struct virtqueue *vq;
+ int ring_bufs_avail;
+ wait_queue_head_t *vc_wq;
/* Scatterlist: can be too big for stack. */
struct scatterlist sg[VIRTQUEUE_NUM];
@@ -134,16 +136,30 @@ static void req_done(struct virtqueue *vq)
struct p9_fcall *rc;
unsigned int len;
struct p9_req_t *req;
+ unsigned long flags;
P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n");
- while ((rc = virtqueue_get_buf(chan->vq, &len)) != NULL) {
- 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);
- req->status = REQ_STATUS_RCVD;
- p9_client_cb(chan->client, req);
- }
+ do {
+ spin_lock_irqsave(&chan->lock, flags);
+ rc = virtqueue_get_buf(chan->vq, &len);
+
+ if (rc != NULL) {
+ if (!chan->ring_bufs_avail) {
+ chan->ring_bufs_avail = 1;
+ wake_up(chan->vc_wq);
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+ 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);
+ req->status = REQ_STATUS_RCVD;
+ p9_client_cb(chan->client, req);
+ } else {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ }
+ } while (rc != NULL);
}
/**
@@ -199,23 +215,43 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
int in, out;
struct virtio_chan *chan = client->trans;
char *rdata = (char *)req->rc+sizeof(struct p9_fcall);
+ unsigned long flags;
+ int err;
P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n");
+req_retry:
+ req->status = REQ_STATUS_SENT;
+
+ spin_lock_irqsave(&chan->lock, flags);
out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata,
req->tc->size);
in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata,
client->msize);
- req->status = REQ_STATUS_SENT;
-
- if (virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc) < 0) {
- P9_DPRINTK(P9_DEBUG_TRANS,
- "9p debug: virtio rpc add_buf returned failure");
- return -EIO;
+ 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:Retry virtio request\n");
+ goto req_retry;
+ } else {
+ 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);
P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n");
return 0;
@@ -290,14 +326,23 @@ static int p9_virtio_probe(struct virtio_device *vdev)
chan->tag_len = tag_len;
err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
if (err) {
- kfree(tag);
- goto out_free_vq;
+ goto out_free_tag;
}
+ chan->vc_wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL);
+ if (!chan->vc_wq) {
+ err = -ENOMEM;
+ goto out_free_tag;
+ }
+ init_waitqueue_head(chan->vc_wq);
+ chan->ring_bufs_avail = 1;
+
mutex_lock(&virtio_9p_lock);
list_add_tail(&chan->chan_list, &virtio_chan_list);
mutex_unlock(&virtio_9p_lock);
return 0;
+out_free_tag:
+ kfree(tag);
out_free_vq:
vdev->config->del_vqs(vdev);
kfree(chan);
@@ -371,6 +416,7 @@ static void p9_virtio_remove(struct virtio_device *vdev)
mutex_unlock(&virtio_9p_lock);
sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
kfree(chan->tag);
+ kfree(chan->vc_wq);
kfree(chan);
}
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 95fdd1185067..ff956d1115bc 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -310,9 +310,9 @@ static int clip_constructor(struct neighbour *neigh)
return 0;
}
-static u32 clip_hash(const void *pkey, const struct net_device *dev)
+static u32 clip_hash(const void *pkey, const struct net_device *dev, __u32 rnd)
{
- return jhash_2words(*(u32 *) pkey, dev->ifindex, clip_tbl.hash_rnd);
+ return jhash_2words(*(u32 *) pkey, dev->ifindex, rnd);
}
static struct neigh_table clip_tbl = {
diff --git a/net/atm/common.c b/net/atm/common.c
index 940404a73b3d..1b9c52a02cd3 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -792,7 +792,7 @@ int vcc_getsockopt(struct socket *sock, int level, int optname,
default:
if (level == SOL_SOCKET)
return -EINVAL;
- break;
+ break;
}
if (!vcc->dev || !vcc->dev->ops->getsockopt)
return -EINVAL;
diff --git a/net/atm/lec.c b/net/atm/lec.c
index d98bde1a0ac8..181d70c73d70 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -220,7 +220,6 @@ static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
static int lec_open(struct net_device *dev)
{
netif_start_queue(dev);
- memset(&dev->stats, 0, sizeof(struct net_device_stats));
return 0;
}
diff --git a/net/ax25/Kconfig b/net/ax25/Kconfig
index 2a72aa96a568..705e53ef4af0 100644
--- a/net/ax25/Kconfig
+++ b/net/ax25/Kconfig
@@ -7,7 +7,7 @@ menuconfig HAMRADIO
bool "Amateur Radio support"
help
If you want to connect your Linux box to an amateur radio, answer Y
- here. You want to read <http://www.tapr.org/tapr/html/pkthome.html>
+ here. You want to read <http://www.tapr.org/>
and more specifically about AX.25 on Linux
<http://www.linux-ax25.org/>.
@@ -42,7 +42,7 @@ config AX25
check out the file <file:Documentation/networking/ax25.txt> in the
kernel source. More information about digital amateur radio in
general is on the WWW at
- <http://www.tapr.org/tapr/html/pkthome.html>.
+ <http://www.tapr.org/>.
To compile this driver as a module, choose M here: the
module will be called ax25.
@@ -89,7 +89,7 @@ config NETROM
<http://www.linux-ax25.org>. You also might want to check out the
file <file:Documentation/networking/ax25.txt>. More information about
digital amateur radio in general is on the WWW at
- <http://www.tapr.org/tapr/html/pkthome.html>.
+ <http://www.tapr.org/>.
To compile this driver as a module, choose M here: the
module will be called netrom.
@@ -108,7 +108,7 @@ config ROSE
<http://www.linux-ax25.org>. You also might want to check out the
file <file:Documentation/networking/ax25.txt>. More information about
digital amateur radio in general is on the WWW at
- <http://www.tapr.org/tapr/html/pkthome.html>.
+ <http://www.tapr.org/>.
To compile this driver as a module, choose M here: the
module will be called rose.
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index cfdfd7e2a172..26eaebf4aaa9 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1103,7 +1103,7 @@ done:
out:
release_sock(sk);
- return 0;
+ return err;
}
/*
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index 7805945a5fd6..a1690845dc6e 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -412,7 +412,7 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
{
ax25_uid_assoc *user;
ax25_route *ax25_rt;
- int err;
+ int err = 0;
if ((ax25_rt = ax25_get_route(addr, NULL)) == NULL)
return -EHOSTUNREACH;
@@ -453,7 +453,7 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
put:
ax25_put_route(ax25_rt);
- return 0;
+ return err;
}
struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 421c45bd1b95..c4cf3f595004 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -265,6 +265,115 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
}
EXPORT_SYMBOL(bt_sock_recvmsg);
+static long bt_sock_data_wait(struct sock *sk, long timeo)
+{
+ DECLARE_WAITQUEUE(wait, current);
+
+ add_wait_queue(sk_sleep(sk), &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (!skb_queue_empty(&sk->sk_receive_queue))
+ break;
+
+ if (sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN))
+ break;
+
+ if (signal_pending(current) || !timeo)
+ break;
+
+ set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
+ clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ }
+
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(sk_sleep(sk), &wait);
+ return timeo;
+}
+
+int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t size, int flags)
+{
+ struct sock *sk = sock->sk;
+ int err = 0;
+ size_t target, copied = 0;
+ long timeo;
+
+ if (flags & MSG_OOB)
+ return -EOPNOTSUPP;
+
+ msg->msg_namelen = 0;
+
+ BT_DBG("sk %p size %zu", sk, size);
+
+ lock_sock(sk);
+
+ target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
+ timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
+
+ do {
+ struct sk_buff *skb;
+ int chunk;
+
+ skb = skb_dequeue(&sk->sk_receive_queue);
+ if (!skb) {
+ if (copied >= target)
+ break;
+
+ if ((err = sock_error(sk)) != 0)
+ break;
+ if (sk->sk_shutdown & RCV_SHUTDOWN)
+ break;
+
+ err = -EAGAIN;
+ if (!timeo)
+ break;
+
+ timeo = bt_sock_data_wait(sk, timeo);
+
+ if (signal_pending(current)) {
+ err = sock_intr_errno(timeo);
+ goto out;
+ }
+ continue;
+ }
+
+ chunk = min_t(unsigned int, skb->len, size);
+ if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
+ skb_queue_head(&sk->sk_receive_queue, skb);
+ if (!copied)
+ copied = -EFAULT;
+ break;
+ }
+ copied += chunk;
+ size -= chunk;
+
+ sock_recv_ts_and_drops(msg, sk, skb);
+
+ if (!(flags & MSG_PEEK)) {
+ skb_pull(skb, chunk);
+ if (skb->len) {
+ skb_queue_head(&sk->sk_receive_queue, skb);
+ break;
+ }
+ kfree_skb(skb);
+
+ } else {
+ /* put message back and return */
+ skb_queue_head(&sk->sk_receive_queue, skb);
+ break;
+ }
+ } while (size);
+
+out:
+ release_sock(sk);
+ return copied ? : err;
+}
+EXPORT_SYMBOL(bt_sock_stream_recvmsg);
+
static inline unsigned int bt_accept_poll(struct sock *parent)
{
struct list_head *p, *n;
@@ -297,13 +406,12 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
mask |= POLLERR;
if (sk->sk_shutdown & RCV_SHUTDOWN)
- mask |= POLLRDHUP;
+ mask |= POLLRDHUP | POLLIN | POLLRDNORM;
if (sk->sk_shutdown == SHUTDOWN_MASK)
mask |= POLLHUP;
- if (!skb_queue_empty(&sk->sk_receive_queue) ||
- (sk->sk_shutdown & RCV_SHUTDOWN))
+ if (!skb_queue_empty(&sk->sk_receive_queue))
mask |= POLLIN | POLLRDNORM;
if (sk->sk_state == BT_CLOSED)
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
index d4c6af082d48..ec0a1347f933 100644
--- a/net/bluetooth/cmtp/core.c
+++ b/net/bluetooth/cmtp/core.c
@@ -321,14 +321,10 @@ static int cmtp_session(void *arg)
int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
{
struct cmtp_session *session, *s;
- bdaddr_t src, dst;
int i, err;
BT_DBG("");
- baswap(&src, &bt_sk(sock->sk)->src);
- baswap(&dst, &bt_sk(sock->sk)->dst);
-
session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL);
if (!session)
return -ENOMEM;
@@ -347,7 +343,7 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
BT_DBG("mtu %d", session->mtu);
- sprintf(session->name, "%s", batostr(&dst));
+ sprintf(session->name, "%s", batostr(&bt_sk(sock->sk)->dst));
session->sock = sock;
session->state = BT_CONFIG;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index c52f091ee6de..bc2a052e518b 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -562,7 +562,6 @@ static int hci_dev_do_close(struct hci_dev *hdev)
hci_dev_lock_bh(hdev);
inquiry_cache_flush(hdev);
hci_conn_hash_flush(hdev);
- hci_blacklist_clear(hdev);
hci_dev_unlock_bh(hdev);
hci_notify(hdev, HCI_DEV_DOWN);
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 8fb967beee80..5fce3d6d07b4 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -37,9 +37,7 @@ static ssize_t show_link_type(struct device *dev, struct device_attribute *attr,
static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf)
{
struct hci_conn *conn = dev_get_drvdata(dev);
- bdaddr_t bdaddr;
- baswap(&bdaddr, &conn->dst);
- return sprintf(buf, "%s\n", batostr(&bdaddr));
+ return sprintf(buf, "%s\n", batostr(&conn->dst));
}
static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf)
@@ -196,8 +194,8 @@ static inline char *host_typetostr(int type)
switch (type) {
case HCI_BREDR:
return "BR/EDR";
- case HCI_80211:
- return "802.11";
+ case HCI_AMP:
+ return "AMP";
default:
return "UNKNOWN";
}
@@ -238,9 +236,7 @@ static ssize_t show_class(struct device *dev, struct device_attribute *attr, cha
static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
{
struct hci_dev *hdev = dev_get_drvdata(dev);
- bdaddr_t bdaddr;
- baswap(&bdaddr, &hdev->bdaddr);
- return sprintf(buf, "%s\n", batostr(&bdaddr));
+ return sprintf(buf, "%s\n", batostr(&hdev->bdaddr));
}
static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
@@ -408,10 +404,8 @@ static int inquiry_cache_show(struct seq_file *f, void *p)
for (e = cache->list; e; e = e->next) {
struct inquiry_data *data = &e->data;
- bdaddr_t bdaddr;
- baswap(&bdaddr, &data->bdaddr);
seq_printf(f, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
- batostr(&bdaddr),
+ batostr(&data->bdaddr),
data->pscan_rep_mode, data->pscan_period_mode,
data->pscan_mode, data->dev_class[2],
data->dev_class[1], data->dev_class[0],
@@ -445,13 +439,10 @@ static int blacklist_show(struct seq_file *f, void *p)
list_for_each(l, &hdev->blacklist) {
struct bdaddr_list *b;
- bdaddr_t bdaddr;
b = list_entry(l, struct bdaddr_list, list);
- baswap(&bdaddr, &b->bdaddr);
-
- seq_printf(f, "%s\n", batostr(&bdaddr));
+ seq_printf(f, "%s\n", batostr(&b->bdaddr));
}
hci_dev_unlock_bh(hdev);
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index bfe641b7dfaf..c0ee8b3928ed 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -758,7 +758,6 @@ static int hidp_setup_hid(struct hidp_session *session,
struct hidp_connadd_req *req)
{
struct hid_device *hid;
- bdaddr_t src, dst;
int err;
session->rd_data = kzalloc(req->rd_size, GFP_KERNEL);
@@ -781,9 +780,6 @@ static int hidp_setup_hid(struct hidp_session *session,
hid->driver_data = session;
- baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
- baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst);
-
hid->bus = BUS_BLUETOOTH;
hid->vendor = req->vendor;
hid->product = req->product;
@@ -791,8 +787,8 @@ static int hidp_setup_hid(struct hidp_session *session,
hid->country = req->country;
strncpy(hid->name, req->name, 128);
- strncpy(hid->phys, batostr(&src), 64);
- strncpy(hid->uniq, batostr(&dst), 64);
+ strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
+ strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
hid->dev.parent = hidp_get_device(session);
hid->ll_driver = &hidp_hid_driver;
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 0b54b7dd8401..daa7a988d9a6 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1008,10 +1008,20 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
goto done;
}
- if (la.l2_psm && __le16_to_cpu(la.l2_psm) < 0x1001 &&
- !capable(CAP_NET_BIND_SERVICE)) {
- err = -EACCES;
- goto done;
+ if (la.l2_psm) {
+ __u16 psm = __le16_to_cpu(la.l2_psm);
+
+ /* PSM must be odd and lsb of upper byte must be 0 */
+ if ((psm & 0x0101) != 0x0001) {
+ err = -EINVAL;
+ goto done;
+ }
+
+ /* Restrict usage of well-known PSMs */
+ if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) {
+ err = -EACCES;
+ goto done;
+ }
}
write_lock_bh(&l2cap_sk_list.lock);
@@ -1190,6 +1200,13 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
goto done;
}
+ /* PSM must be odd and lsb of upper byte must be 0 */
+ if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 &&
+ sk->sk_type != SOCK_RAW) {
+ err = -EINVAL;
+ goto done;
+ }
+
/* Set destination address and psm */
bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
l2cap_pi(sk)->psm = la.l2_psm;
@@ -1635,7 +1652,7 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
*frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
if (!*frag)
- return -EFAULT;
+ return err;
if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
return -EFAULT;
@@ -1661,7 +1678,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr
skb = bt_skb_send_alloc(sk, count + hlen,
msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb)
- return ERR_PTR(-ENOMEM);
+ return ERR_PTR(err);
/* Create L2CAP header */
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
@@ -1690,7 +1707,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *ms
skb = bt_skb_send_alloc(sk, count + hlen,
msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb)
- return ERR_PTR(-ENOMEM);
+ return ERR_PTR(err);
/* Create L2CAP header */
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
@@ -1727,7 +1744,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *m
skb = bt_skb_send_alloc(sk, count + hlen,
msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb)
- return ERR_PTR(-ENOMEM);
+ return ERR_PTR(err);
/* Create L2CAP header */
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
@@ -1934,6 +1951,9 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
release_sock(sk);
+ if (sock->type == SOCK_STREAM)
+ return bt_sock_stream_recvmsg(iocb, sock, msg, len, flags);
+
return bt_sock_recvmsg(iocb, sock, msg, len, flags);
}
@@ -2891,7 +2911,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
struct l2cap_chan_list *list = &conn->chan_list;
struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
struct l2cap_conn_rsp rsp;
- struct sock *parent, *uninitialized_var(sk);
+ struct sock *parent, *sk = NULL;
int result, status = L2CAP_CS_NO_INFO;
u16 dcid = 0, scid = __le16_to_cpu(req->scid);
@@ -3000,7 +3020,7 @@ sendresp:
L2CAP_INFO_REQ, sizeof(info), &info);
}
- if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) &&
+ if (sk && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) &&
result == L2CAP_CR_SUCCESS) {
u8 buf[128];
l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
@@ -3151,6 +3171,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
u8 buf[64];
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, buf), buf);
l2cap_pi(sk)->num_conf_req++;
@@ -4643,6 +4664,8 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
if (flags & ACL_START) {
struct l2cap_hdr *hdr;
+ struct sock *sk;
+ u16 cid;
int len;
if (conn->rx_len) {
@@ -4653,7 +4676,8 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
l2cap_conn_unreliable(conn, ECOMM);
}
- if (skb->len < 2) {
+ /* Start fragment always begin with Basic L2CAP header */
+ if (skb->len < L2CAP_HDR_SIZE) {
BT_ERR("Frame is too short (len %d)", skb->len);
l2cap_conn_unreliable(conn, ECOMM);
goto drop;
@@ -4661,6 +4685,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
hdr = (struct l2cap_hdr *) skb->data;
len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
+ cid = __le16_to_cpu(hdr->cid);
if (len == skb->len) {
/* Complete frame received */
@@ -4677,6 +4702,19 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
goto drop;
}
+ sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
+
+ if (sk && l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) {
+ BT_ERR("Frame exceeding recv MTU (len %d, MTU %d)",
+ len, l2cap_pi(sk)->imtu);
+ bh_unlock_sock(sk);
+ l2cap_conn_unreliable(conn, ECOMM);
+ goto drop;
+ }
+
+ if (sk)
+ bh_unlock_sock(sk);
+
/* Allocate skb for the complete frame (with header) */
conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!conn->rx_skb)
diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c
index ad2af5814e40..b826d1bf10df 100644
--- a/net/bluetooth/lib.c
+++ b/net/bluetooth/lib.c
@@ -51,8 +51,8 @@ char *batostr(bdaddr_t *ba)
i ^= 1;
sprintf(str[i], "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
- ba->b[0], ba->b[1], ba->b[2],
- ba->b[3], ba->b[4], ba->b[5]);
+ ba->b[5], ba->b[4], ba->b[3],
+ ba->b[2], ba->b[1], ba->b[0]);
return str[i];
}
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 7dca91bb8c57..39a5d87e33b4 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -113,11 +113,10 @@ static void rfcomm_session_del(struct rfcomm_session *s);
#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
#define __get_rpn_parity(line) (((line) >> 3) & 0x7)
-static inline void rfcomm_schedule(uint event)
+static inline void rfcomm_schedule(void)
{
if (!rfcomm_thread)
return;
- //set_bit(event, &rfcomm_event);
set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
wake_up_process(rfcomm_thread);
}
@@ -179,13 +178,13 @@ static unsigned char rfcomm_crc_table[256] = {
/* FCS on 2 bytes */
static inline u8 __fcs(u8 *data)
{
- return (0xff - __crc(data));
+ return 0xff - __crc(data);
}
/* FCS on 3 bytes */
static inline u8 __fcs2(u8 *data)
{
- return (0xff - rfcomm_crc_table[__crc(data) ^ data[2]]);
+ return 0xff - rfcomm_crc_table[__crc(data) ^ data[2]];
}
/* Check FCS */
@@ -203,13 +202,13 @@ static inline int __check_fcs(u8 *data, int type, u8 fcs)
static void rfcomm_l2state_change(struct sock *sk)
{
BT_DBG("%p state %d", sk, sk->sk_state);
- rfcomm_schedule(RFCOMM_SCHED_STATE);
+ rfcomm_schedule();
}
static void rfcomm_l2data_ready(struct sock *sk, int bytes)
{
BT_DBG("%p bytes %d", sk, bytes);
- rfcomm_schedule(RFCOMM_SCHED_RX);
+ rfcomm_schedule();
}
static int rfcomm_l2sock_create(struct socket **sock)
@@ -255,7 +254,7 @@ static void rfcomm_session_timeout(unsigned long arg)
BT_DBG("session %p state %ld", s, s->state);
set_bit(RFCOMM_TIMED_OUT, &s->flags);
- rfcomm_schedule(RFCOMM_SCHED_TIMEO);
+ rfcomm_schedule();
}
static void rfcomm_session_set_timer(struct rfcomm_session *s, long timeout)
@@ -283,7 +282,7 @@ static void rfcomm_dlc_timeout(unsigned long arg)
set_bit(RFCOMM_TIMED_OUT, &d->flags);
rfcomm_dlc_put(d);
- rfcomm_schedule(RFCOMM_SCHED_TIMEO);
+ rfcomm_schedule();
}
static void rfcomm_dlc_set_timer(struct rfcomm_dlc *d, long timeout)
@@ -465,7 +464,7 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
case BT_CONFIG:
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
- rfcomm_schedule(RFCOMM_SCHED_AUTH);
+ rfcomm_schedule();
break;
}
/* Fall through */
@@ -485,7 +484,7 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
case BT_CONNECT2:
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
- rfcomm_schedule(RFCOMM_SCHED_AUTH);
+ rfcomm_schedule();
break;
}
/* Fall through */
@@ -533,7 +532,7 @@ int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
skb_queue_tail(&d->tx_queue, skb);
if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
- rfcomm_schedule(RFCOMM_SCHED_TX);
+ rfcomm_schedule();
return len;
}
@@ -545,7 +544,7 @@ void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
d->v24_sig |= RFCOMM_V24_FC;
set_bit(RFCOMM_MSC_PENDING, &d->flags);
}
- rfcomm_schedule(RFCOMM_SCHED_TX);
+ rfcomm_schedule();
}
void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
@@ -556,7 +555,7 @@ void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
d->v24_sig &= ~RFCOMM_V24_FC;
set_bit(RFCOMM_MSC_PENDING, &d->flags);
}
- rfcomm_schedule(RFCOMM_SCHED_TX);
+ rfcomm_schedule();
}
/*
@@ -577,7 +576,7 @@ int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig)
d->v24_sig = v24_sig;
if (!test_and_set_bit(RFCOMM_MSC_PENDING, &d->flags))
- rfcomm_schedule(RFCOMM_SCHED_TX);
+ rfcomm_schedule();
return 0;
}
@@ -816,7 +815,7 @@ static int rfcomm_queue_disc(struct rfcomm_dlc *d)
cmd->fcs = __fcs2((u8 *) cmd);
skb_queue_tail(&d->tx_queue, skb);
- rfcomm_schedule(RFCOMM_SCHED_TX);
+ rfcomm_schedule();
return 0;
}
@@ -1415,8 +1414,8 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
return 0;
if (len == 1) {
- /* This is a request, return default settings */
- bit_rate = RFCOMM_RPN_BR_115200;
+ /* This is a request, return default (according to ETSI TS 07.10) settings */
+ bit_rate = RFCOMM_RPN_BR_9600;
data_bits = RFCOMM_RPN_DATA_8;
stop_bits = RFCOMM_RPN_STOP_1;
parity = RFCOMM_RPN_PARITY_NONE;
@@ -1431,9 +1430,9 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
if (rpn->param_mask & cpu_to_le16(RFCOMM_RPN_PM_BITRATE)) {
bit_rate = rpn->bit_rate;
- if (bit_rate != RFCOMM_RPN_BR_115200) {
+ if (bit_rate > RFCOMM_RPN_BR_230400) {
BT_DBG("RPN bit rate mismatch 0x%x", bit_rate);
- bit_rate = RFCOMM_RPN_BR_115200;
+ bit_rate = RFCOMM_RPN_BR_9600;
rpn_mask ^= RFCOMM_RPN_PM_BITRATE;
}
}
@@ -1698,7 +1697,7 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
break;
default:
- BT_ERR("Unknown packet type 0x%02x\n", type);
+ BT_ERR("Unknown packet type 0x%02x", type);
break;
}
kfree_skb(skb);
@@ -1884,7 +1883,7 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s)
* L2CAP MTU minus UIH header and FCS. */
s->mtu = min(l2cap_pi(nsock->sk)->omtu, l2cap_pi(nsock->sk)->imtu) - 5;
- rfcomm_schedule(RFCOMM_SCHED_RX);
+ rfcomm_schedule();
} else
sock_release(nsock);
}
@@ -2093,7 +2092,7 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
rfcomm_session_put(s);
- rfcomm_schedule(RFCOMM_SCHED_AUTH);
+ rfcomm_schedule();
}
static struct hci_cb rfcomm_cb = {
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 194b3a04cfd3..aec505f934df 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -621,121 +621,29 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
return sent;
}
-static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(sk_sleep(sk), &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (!skb_queue_empty(&sk->sk_receive_queue) ||
- sk->sk_err ||
- (sk->sk_shutdown & RCV_SHUTDOWN) ||
- signal_pending(current) ||
- !timeo)
- break;
-
- set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
- clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
- }
-
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
- return timeo;
-}
-
static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size, int flags)
{
struct sock *sk = sock->sk;
struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
- int err = 0;
- size_t target, copied = 0;
- long timeo;
+ int len;
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
rfcomm_dlc_accept(d);
return 0;
}
- if (flags & MSG_OOB)
- return -EOPNOTSUPP;
-
- msg->msg_namelen = 0;
-
- BT_DBG("sk %p size %zu", sk, size);
+ len = bt_sock_stream_recvmsg(iocb, sock, msg, size, flags);
lock_sock(sk);
+ if (!(flags & MSG_PEEK) && len > 0)
+ atomic_sub(len, &sk->sk_rmem_alloc);
- target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
- timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
-
- do {
- struct sk_buff *skb;
- int chunk;
-
- skb = skb_dequeue(&sk->sk_receive_queue);
- if (!skb) {
- if (copied >= target)
- break;
-
- if ((err = sock_error(sk)) != 0)
- break;
- if (sk->sk_shutdown & RCV_SHUTDOWN)
- break;
-
- err = -EAGAIN;
- if (!timeo)
- break;
-
- timeo = rfcomm_sock_data_wait(sk, timeo);
-
- if (signal_pending(current)) {
- err = sock_intr_errno(timeo);
- goto out;
- }
- continue;
- }
-
- chunk = min_t(unsigned int, skb->len, size);
- if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
- skb_queue_head(&sk->sk_receive_queue, skb);
- if (!copied)
- copied = -EFAULT;
- break;
- }
- copied += chunk;
- size -= chunk;
-
- sock_recv_ts_and_drops(msg, sk, skb);
-
- if (!(flags & MSG_PEEK)) {
- atomic_sub(chunk, &sk->sk_rmem_alloc);
-
- skb_pull(skb, chunk);
- if (skb->len) {
- skb_queue_head(&sk->sk_receive_queue, skb);
- break;
- }
- kfree_skb(skb);
-
- } else {
- /* put message back and return */
- skb_queue_head(&sk->sk_receive_queue, skb);
- break;
- }
- } while (size);
-
-out:
if (atomic_read(&sk->sk_rmem_alloc) <= (sk->sk_rcvbuf >> 2))
rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
-
release_sock(sk);
- return copied ? : err;
+
+ return len;
}
static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 84c2a4d013c6..a9b81f5dacd1 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -183,9 +183,7 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
{
struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
- bdaddr_t bdaddr;
- baswap(&bdaddr, &dev->dst);
- return sprintf(buf, "%s\n", batostr(&bdaddr));
+ return sprintf(buf, "%s\n", batostr(&dev->dst));
}
static ssize_t show_channel(struct device *tty_dev, struct device_attribute *attr, char *buf)
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index cf09fe591fc2..17cb0b633576 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -212,6 +212,11 @@ static int br_set_tx_csum(struct net_device *dev, u32 data)
return 0;
}
+static int br_set_flags(struct net_device *netdev, u32 data)
+{
+ return ethtool_op_set_flags(netdev, data, ETH_FLAG_TXVLAN);
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void br_poll_controller(struct net_device *br_dev)
{
@@ -304,6 +309,7 @@ static const struct ethtool_ops br_ethtool_ops = {
.get_ufo = ethtool_op_get_ufo,
.set_ufo = ethtool_op_set_ufo,
.get_flags = ethtool_op_get_flags,
+ .set_flags = br_set_flags,
};
static const struct net_device_ops br_netdev_ops = {
@@ -343,5 +349,5 @@ void br_dev_setup(struct net_device *dev)
dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX |
- NETIF_F_NETNS_LOCAL | NETIF_F_GSO;
+ NETIF_F_NETNS_LOCAL | NETIF_F_GSO | NETIF_F_HW_VLAN_TX;
}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index c03d2c3ff03e..89ad25a76202 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -61,30 +61,27 @@ static int port_cost(struct net_device *dev)
}
-/*
- * Check for port carrier transistions.
- * Called from work queue to allow for calling functions that
- * might sleep (such as speed check), and to debounce.
- */
+/* Check for port carrier transistions. */
void br_port_carrier_check(struct net_bridge_port *p)
{
struct net_device *dev = p->dev;
struct net_bridge *br = p->br;
- if (netif_carrier_ok(dev))
+ if (netif_running(dev) && netif_carrier_ok(dev))
p->path_cost = port_cost(dev);
- if (netif_running(br->dev)) {
- spin_lock_bh(&br->lock);
- if (netif_carrier_ok(dev)) {
- if (p->state == BR_STATE_DISABLED)
- br_stp_enable_port(p);
- } else {
- if (p->state != BR_STATE_DISABLED)
- br_stp_disable_port(p);
- }
- spin_unlock_bh(&br->lock);
+ if (!netif_running(br->dev))
+ return;
+
+ spin_lock_bh(&br->lock);
+ if (netif_running(dev) && netif_carrier_ok(dev)) {
+ if (p->state == BR_STATE_DISABLED)
+ br_stp_enable_port(p);
+ } else {
+ if (p->state != BR_STATE_DISABLED)
+ br_stp_disable_port(p);
}
+ spin_unlock_bh(&br->lock);
}
static void release_nbp(struct kobject *kobj)
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 826cd5221536..25207a1f182b 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -141,7 +141,7 @@ struct sk_buff *br_handle_frame(struct sk_buff *skb)
const unsigned char *dest = eth_hdr(skb)->h_dest;
int (*rhook)(struct sk_buff *skb);
- if (skb->pkt_type == PACKET_LOOPBACK)
+ if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
return skb;
if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
@@ -159,7 +159,7 @@ struct sk_buff *br_handle_frame(struct sk_buff *skb)
goto drop;
/* If STP is turned off, then forward */
- if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0)
+ if (p->br->stp_enabled == BR_NO_STP)
goto forward;
if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 137f23259a93..865fd7634b67 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -64,22 +64,24 @@ static int brnf_filter_pppoe_tagged __read_mostly = 0;
static inline __be16 vlan_proto(const struct sk_buff *skb)
{
- return vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
+ if (vlan_tx_tag_present(skb))
+ return skb->protocol;
+ else if (skb->protocol == htons(ETH_P_8021Q))
+ return vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
+ else
+ return 0;
}
#define IS_VLAN_IP(skb) \
- (skb->protocol == htons(ETH_P_8021Q) && \
- vlan_proto(skb) == htons(ETH_P_IP) && \
+ (vlan_proto(skb) == htons(ETH_P_IP) && \
brnf_filter_vlan_tagged)
#define IS_VLAN_IPV6(skb) \
- (skb->protocol == htons(ETH_P_8021Q) && \
- vlan_proto(skb) == htons(ETH_P_IPV6) &&\
+ (vlan_proto(skb) == htons(ETH_P_IPV6) && \
brnf_filter_vlan_tagged)
#define IS_VLAN_ARP(skb) \
- (skb->protocol == htons(ETH_P_8021Q) && \
- vlan_proto(skb) == htons(ETH_P_ARP) && \
+ (vlan_proto(skb) == htons(ETH_P_ARP) && \
brnf_filter_vlan_tagged)
static inline __be16 pppoe_proto(const struct sk_buff *skb)
@@ -106,7 +108,6 @@ static struct dst_ops fake_dst_ops = {
.family = AF_INET,
.protocol = cpu_to_be16(ETH_P_IP),
.update_pmtu = fake_update_pmtu,
- .entries = ATOMIC_INIT(0),
};
/*
@@ -209,6 +210,72 @@ static inline void nf_bridge_update_protocol(struct sk_buff *skb)
skb->protocol = htons(ETH_P_PPP_SES);
}
+/* When handing a packet over to the IP layer
+ * check whether we have a skb that is in the
+ * expected format
+ */
+
+static int br_parse_ip_options(struct sk_buff *skb)
+{
+ struct ip_options *opt;
+ struct iphdr *iph;
+ struct net_device *dev = skb->dev;
+ u32 len;
+
+ iph = ip_hdr(skb);
+ opt = &(IPCB(skb)->opt);
+
+ /* Basic sanity checks */
+ if (iph->ihl < 5 || iph->version != 4)
+ goto inhdr_error;
+
+ if (!pskb_may_pull(skb, iph->ihl*4))
+ goto inhdr_error;
+
+ iph = ip_hdr(skb);
+ if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
+ goto inhdr_error;
+
+ len = ntohs(iph->tot_len);
+ if (skb->len < len) {
+ IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INTRUNCATEDPKTS);
+ goto drop;
+ } else if (len < (iph->ihl*4))
+ goto inhdr_error;
+
+ if (pskb_trim_rcsum(skb, len)) {
+ IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);
+ goto drop;
+ }
+
+ /* Zero out the CB buffer if no options present */
+ if (iph->ihl == 5) {
+ memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
+ return 0;
+ }
+
+ opt->optlen = iph->ihl*4 - sizeof(struct iphdr);
+ if (ip_options_compile(dev_net(dev), opt, skb))
+ goto inhdr_error;
+
+ /* Check correct handling of SRR option */
+ if (unlikely(opt->srr)) {
+ struct in_device *in_dev = __in_dev_get_rcu(dev);
+ if (in_dev && !IN_DEV_SOURCE_ROUTE(in_dev))
+ goto drop;
+
+ if (ip_options_rcv_srr(skb))
+ goto drop;
+ }
+
+ return 0;
+
+inhdr_error:
+ IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS);
+drop:
+ return -1;
+}
+
/* Fill in the header for fragmented IP packets handled by
* the IPv4 connection tracking code.
*/
@@ -549,7 +616,6 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
{
struct net_bridge_port *p;
struct net_bridge *br;
- struct iphdr *iph;
__u32 len = nf_bridge_encap_header_len(skb);
if (unlikely(!pskb_may_pull(skb, len)))
@@ -578,28 +644,9 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
nf_bridge_pull_encap_header_rcsum(skb);
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
- goto inhdr_error;
-
- iph = ip_hdr(skb);
- if (iph->ihl < 5 || iph->version != 4)
- goto inhdr_error;
-
- if (!pskb_may_pull(skb, 4 * iph->ihl))
- goto inhdr_error;
-
- iph = ip_hdr(skb);
- if (ip_fast_csum((__u8 *) iph, iph->ihl) != 0)
- goto inhdr_error;
-
- len = ntohs(iph->tot_len);
- if (skb->len < len || len < 4 * iph->ihl)
- goto inhdr_error;
-
- pskb_trim_rcsum(skb, len);
-
- /* BUG: Should really parse the IP options here. */
- memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
+ if (br_parse_ip_options(skb))
+ /* Drop invalid packet */
+ goto out;
nf_bridge_put(skb->nf_bridge);
if (!nf_bridge_alloc(skb))
@@ -614,8 +661,6 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
return NF_STOLEN;
-inhdr_error:
-// IP_INC_STATS_BH(IpInHdrErrors);
out:
return NF_DROP;
}
@@ -759,14 +804,19 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff *skb,
#if defined(CONFIG_NF_CONNTRACK_IPV4) || defined(CONFIG_NF_CONNTRACK_IPV4_MODULE)
static int br_nf_dev_queue_xmit(struct sk_buff *skb)
{
+ int ret;
+
if (skb->nfct != NULL && skb->protocol == htons(ETH_P_IP) &&
skb->len + nf_bridge_mtu_reduction(skb) > skb->dev->mtu &&
!skb_is_gso(skb)) {
- /* BUG: Should really parse the IP options here. */
- memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
- return ip_fragment(skb, br_dev_queue_push_xmit);
+ if (br_parse_ip_options(skb))
+ /* Drop invalid packet */
+ return NF_DROP;
+ ret = ip_fragment(skb, br_dev_queue_push_xmit);
} else
- return br_dev_queue_push_xmit(skb);
+ ret = br_dev_queue_push_xmit(skb);
+
+ return ret;
}
#else
static int br_nf_dev_queue_xmit(struct sk_buff *skb)
@@ -954,15 +1004,22 @@ int __init br_netfilter_init(void)
{
int ret;
- ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
+ ret = dst_entries_init(&fake_dst_ops);
if (ret < 0)
return ret;
+
+ ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
+ if (ret < 0) {
+ dst_entries_destroy(&fake_dst_ops);
+ return ret;
+ }
#ifdef CONFIG_SYSCTL
brnf_sysctl_header = register_sysctl_paths(brnf_path, brnf_table);
if (brnf_sysctl_header == NULL) {
printk(KERN_WARNING
"br_netfilter: can't register to sysctl.\n");
nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
+ dst_entries_destroy(&fake_dst_ops);
return -ENOMEM;
}
#endif
@@ -976,4 +1033,5 @@ void br_netfilter_fini(void)
#ifdef CONFIG_SYSCTL
unregister_sysctl_table(brnf_sysctl_header);
#endif
+ dst_entries_destroy(&fake_dst_ops);
}
diff --git a/net/bridge/netfilter/ebt_vlan.c b/net/bridge/netfilter/ebt_vlan.c
index 87b53b3a921d..eae67bf0446c 100644
--- a/net/bridge/netfilter/ebt_vlan.c
+++ b/net/bridge/netfilter/ebt_vlan.c
@@ -39,8 +39,6 @@ static bool
ebt_vlan_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct ebt_vlan_info *info = par->matchinfo;
- const struct vlan_hdr *fp;
- struct vlan_hdr _frame;
unsigned short TCI; /* Whole TCI, given from parsed frame */
unsigned short id; /* VLAN ID, given from frame TCI */
@@ -48,9 +46,20 @@ ebt_vlan_mt(const struct sk_buff *skb, struct xt_action_param *par)
/* VLAN encapsulated Type/Length field, given from orig frame */
__be16 encap;
- fp = skb_header_pointer(skb, 0, sizeof(_frame), &_frame);
- if (fp == NULL)
- return false;
+ if (vlan_tx_tag_present(skb)) {
+ TCI = vlan_tx_tag_get(skb);
+ encap = skb->protocol;
+ } else {
+ const struct vlan_hdr *fp;
+ struct vlan_hdr _frame;
+
+ fp = skb_header_pointer(skb, 0, sizeof(_frame), &_frame);
+ if (fp == NULL)
+ return false;
+
+ TCI = ntohs(fp->h_vlan_TCI);
+ encap = fp->h_vlan_encapsulated_proto;
+ }
/* Tag Control Information (TCI) consists of the following elements:
* - User_priority. The user_priority field is three bits in length,
@@ -59,10 +68,8 @@ ebt_vlan_mt(const struct sk_buff *skb, struct xt_action_param *par)
* (CFI) is a single bit flag value. Currently ignored.
* - VLAN Identifier (VID). The VID is encoded as
* an unsigned binary number. */
- TCI = ntohs(fp->h_vlan_TCI);
id = TCI & VLAN_VID_MASK;
prio = (TCI >> 13) & 0x7;
- encap = fp->h_vlan_encapsulated_proto;
/* Checking VLAN Identifier (VID) */
if (GET_BITMASK(EBT_VLAN_ID))
@@ -111,10 +118,10 @@ static int ebt_vlan_mt_check(const struct xt_mtchk_param *par)
* 0 - The null VLAN ID.
* 1 - The default Port VID (PVID)
* 0x0FFF - Reserved for implementation use.
- * if_vlan.h: VLAN_GROUP_ARRAY_LEN 4096. */
+ * if_vlan.h: VLAN_N_VID 4096. */
if (GET_BITMASK(EBT_VLAN_ID)) {
if (!!info->id) { /* if id!=0 => check vid range */
- if (info->id > VLAN_GROUP_ARRAY_LEN) {
+ if (info->id > VLAN_N_VID) {
pr_debug("id %d is out of range (1-4096)\n",
info->id);
return -EINVAL;
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index bcc102e3be4d..a1dcf83f0d58 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -124,16 +124,23 @@ ebt_dev_check(const char *entry, const struct net_device *device)
#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
/* process standard matches */
static inline int
-ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
+ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb,
const struct net_device *in, const struct net_device *out)
{
+ const struct ethhdr *h = eth_hdr(skb);
+ __be16 ethproto;
int verdict, i;
+ if (vlan_tx_tag_present(skb))
+ ethproto = htons(ETH_P_8021Q);
+ else
+ ethproto = h->h_proto;
+
if (e->bitmask & EBT_802_3) {
- if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
+ if (FWINV2(ntohs(ethproto) >= 1536, EBT_IPROTO))
return 1;
} else if (!(e->bitmask & EBT_NOPROTO) &&
- FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
+ FWINV2(e->ethproto != ethproto, EBT_IPROTO))
return 1;
if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
@@ -213,7 +220,7 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
base = private->entries;
i = 0;
while (i < nentries) {
- if (ebt_basic_match(point, eth_hdr(skb), in, out))
+ if (ebt_basic_match(point, skb, in, out))
goto letscontinue;
if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &acpar) != 0)
diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
index 0b586e9d1378..b99369a055d1 100644
--- a/net/caif/caif_dev.c
+++ b/net/caif/caif_dev.c
@@ -9,6 +9,8 @@
* and Sakari Ailus <sakari.ailus@nokia.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -171,7 +173,7 @@ static int receive(struct sk_buff *skb, struct net_device *dev,
net = dev_net(dev);
pkt = cfpkt_fromnative(CAIF_DIR_IN, skb);
caifd = caif_get(dev);
- if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd)
+ if (!caifd || !caifd->layer.up || !caifd->layer.up->receive)
return NET_RX_DROP;
if (caifd->layer.up->receive(caifd->layer.up, pkt))
@@ -214,7 +216,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
switch (what) {
case NETDEV_REGISTER:
- pr_info("CAIF: %s():register %s\n", __func__, dev->name);
+ netdev_info(dev, "register\n");
caifd = caif_device_alloc(dev);
if (caifd == NULL)
break;
@@ -225,14 +227,13 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
break;
case NETDEV_UP:
- pr_info("CAIF: %s(): up %s\n", __func__, dev->name);
+ netdev_info(dev, "up\n");
caifd = caif_get(dev);
if (caifd == NULL)
break;
caifdev = netdev_priv(dev);
if (atomic_read(&caifd->state) == NETDEV_UP) {
- pr_info("CAIF: %s():%s already up\n",
- __func__, dev->name);
+ netdev_info(dev, "already up\n");
break;
}
atomic_set(&caifd->state, what);
@@ -273,7 +274,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
caifd = caif_get(dev);
if (caifd == NULL)
break;
- pr_info("CAIF: %s():going down %s\n", __func__, dev->name);
+ netdev_info(dev, "going down\n");
if (atomic_read(&caifd->state) == NETDEV_GOING_DOWN ||
atomic_read(&caifd->state) == NETDEV_DOWN)
@@ -295,11 +296,10 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
caifd = caif_get(dev);
if (caifd == NULL)
break;
- pr_info("CAIF: %s(): down %s\n", __func__, dev->name);
+ netdev_info(dev, "down\n");
if (atomic_read(&caifd->in_use))
- pr_warning("CAIF: %s(): "
- "Unregistering an active CAIF device: %s\n",
- __func__, dev->name);
+ netdev_warn(dev,
+ "Unregistering an active CAIF device\n");
cfcnfg_del_phy_layer(get_caif_conf(), &caifd->layer);
dev_put(dev);
atomic_set(&caifd->state, what);
@@ -307,7 +307,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
case NETDEV_UNREGISTER:
caifd = caif_get(dev);
- pr_info("CAIF: %s(): unregister %s\n", __func__, dev->name);
+ netdev_info(dev, "unregister\n");
atomic_set(&caifd->state, what);
caif_device_destroy(dev);
break;
@@ -391,7 +391,7 @@ static int __init caif_device_init(void)
int result;
cfg = cfcnfg_create();
if (!cfg) {
- pr_warning("CAIF: %s(): can't create cfcnfg.\n", __func__);
+ pr_warn("can't create cfcnfg\n");
goto err_cfcnfg_create_failed;
}
result = register_pernet_device(&caif_net_ops);
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index 4bf28f25f368..2eca2dd0000f 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -15,7 +17,6 @@
#include <linux/poll.h>
#include <linux/tcp.h>
#include <linux/uaccess.h>
-#include <linux/mutex.h>
#include <linux/debugfs.h>
#include <linux/caif/caif_socket.h>
#include <asm/atomic.h>
@@ -28,9 +29,6 @@
MODULE_LICENSE("GPL");
MODULE_ALIAS_NETPROTO(AF_CAIF);
-#define CAIF_DEF_SNDBUF (4096*10)
-#define CAIF_DEF_RCVBUF (4096*100)
-
/*
* CAIF state is re-using the TCP socket states.
* caif_states stored in sk_state reflect the state as reported by
@@ -157,9 +155,7 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
(unsigned)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) {
- trace_printk("CAIF: %s():"
- " sending flow OFF (queue len = %d %d)\n",
- __func__,
+ pr_debug("sending flow OFF (queue len = %d %d)\n",
atomic_read(&cf_sk->sk.sk_rmem_alloc),
sk_rcvbuf_lowwater(cf_sk));
set_rx_flow_off(cf_sk);
@@ -172,9 +168,7 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
return err;
if (!sk_rmem_schedule(sk, skb->truesize) && rx_flow_is_on(cf_sk)) {
set_rx_flow_off(cf_sk);
- trace_printk("CAIF: %s():"
- " sending flow OFF due to rmem_schedule\n",
- __func__);
+ pr_debug("sending flow OFF due to rmem_schedule\n");
dbfs_atomic_inc(&cnt.num_rx_flow_off);
caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ);
}
@@ -275,8 +269,7 @@ static void caif_ctrl_cb(struct cflayer *layr,
break;
default:
- pr_debug("CAIF: %s(): Unexpected flow command %d\n",
- __func__, flow);
+ pr_debug("Unexpected flow command %d\n", flow);
}
}
@@ -536,8 +529,7 @@ static int transmit_skb(struct sk_buff *skb, struct caifsock *cf_sk,
/* Slight paranoia, probably not needed. */
if (unlikely(loopcnt++ > 1000)) {
- pr_warning("CAIF: %s(): transmit retries failed,"
- " error = %d\n", __func__, ret);
+ pr_warn("transmit retries failed, error = %d\n", ret);
break;
}
@@ -912,8 +904,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
cf_sk->tailroom = tailroom;
cf_sk->maxframe = mtu - (headroom + tailroom);
if (cf_sk->maxframe < 1) {
- pr_warning("CAIF: %s(): CAIF Interface MTU too small (%u)\n",
- __func__, mtu);
+ pr_warn("CAIF Interface MTU too small (%d)\n", dev->mtu);
goto out;
}
@@ -1132,10 +1123,6 @@ static int caif_create(struct net *net, struct socket *sock, int protocol,
/* Store the protocol */
sk->sk_protocol = (unsigned char) protocol;
- /* Sendbuf dictates the amount of outbound packets not yet sent */
- sk->sk_sndbuf = CAIF_DEF_SNDBUF;
- sk->sk_rcvbuf = CAIF_DEF_RCVBUF;
-
/*
* Lock in order to try to stop someone from opening the socket
* too early.
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c
index 1c29189b344d..41adafd18914 100644
--- a/net/caif/cfcnfg.c
+++ b/net/caif/cfcnfg.c
@@ -3,6 +3,9 @@
* Author: Sjur Brendeland/sjur.brandeland@stericsson.com
* License terms: GNU General Public License (GPL) version 2
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/slab.h>
@@ -78,7 +81,7 @@ struct cfcnfg *cfcnfg_create(void)
/* Initiate this layer */
this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC);
if (!this) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
this->mux = cfmuxl_create();
@@ -106,7 +109,7 @@ struct cfcnfg *cfcnfg_create(void)
layer_set_up(this->ctrl, this);
return this;
out_of_mem:
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
kfree(this->mux);
kfree(this->ctrl);
kfree(this);
@@ -194,7 +197,7 @@ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
caif_assert(adap_layer != NULL);
channel_id = adap_layer->id;
if (adap_layer->dn == NULL || channel_id == 0) {
- pr_err("CAIF: %s():adap_layer->id is 0\n", __func__);
+ pr_err("adap_layer->dn == NULL or adap_layer->id is 0\n");
ret = -ENOTCONN;
goto end;
}
@@ -204,9 +207,8 @@ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
layer_set_up(servl, NULL);
ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
if (servl == NULL) {
- pr_err("CAIF: %s(): PROTOCOL ERROR "
- "- Error removing service_layer Channel_Id(%d)",
- __func__, channel_id);
+ pr_err("PROTOCOL ERROR - Error removing service_layer Channel_Id(%d)",
+ channel_id);
ret = -EINVAL;
goto end;
}
@@ -216,18 +218,14 @@ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
phyinfo = cfcnfg_get_phyinfo(cnfg, phyid);
if (phyinfo == NULL) {
- pr_warning("CAIF: %s(): "
- "No interface to send disconnect to\n",
- __func__);
+ pr_warn("No interface to send disconnect to\n");
ret = -ENODEV;
goto end;
}
if (phyinfo->id != phyid ||
phyinfo->phy_layer->id != phyid ||
phyinfo->frm_layer->id != phyid) {
- pr_err("CAIF: %s(): "
- "Inconsistency in phy registration\n",
- __func__);
+ pr_err("Inconsistency in phy registration\n");
ret = -EINVAL;
goto end;
}
@@ -276,21 +274,20 @@ int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
{
struct cflayer *frml;
if (adap_layer == NULL) {
- pr_err("CAIF: %s(): adap_layer is zero", __func__);
+ pr_err("adap_layer is zero\n");
return -EINVAL;
}
if (adap_layer->receive == NULL) {
- pr_err("CAIF: %s(): adap_layer->receive is NULL", __func__);
+ pr_err("adap_layer->receive is NULL\n");
return -EINVAL;
}
if (adap_layer->ctrlcmd == NULL) {
- pr_err("CAIF: %s(): adap_layer->ctrlcmd == NULL", __func__);
+ pr_err("adap_layer->ctrlcmd == NULL\n");
return -EINVAL;
}
frml = cnfg->phy_layers[param->phyid].frm_layer;
if (frml == NULL) {
- pr_err("CAIF: %s(): Specified PHY type does not exist!",
- __func__);
+ pr_err("Specified PHY type does not exist!\n");
return -ENODEV;
}
caif_assert(param->phyid == cnfg->phy_layers[param->phyid].id);
@@ -330,9 +327,7 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
struct net_device *netdev;
if (adapt_layer == NULL) {
- pr_debug("CAIF: %s(): link setup response "
- "but no client exist, send linkdown back\n",
- __func__);
+ pr_debug("link setup response but no client exist, send linkdown back\n");
cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL);
return;
}
@@ -374,13 +369,11 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
servicel = cfdbgl_create(channel_id, &phyinfo->dev_info);
break;
default:
- pr_err("CAIF: %s(): Protocol error. "
- "Link setup response - unknown channel type\n",
- __func__);
+ pr_err("Protocol error. Link setup response - unknown channel type\n");
return;
}
if (!servicel) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return;
}
layer_set_dn(servicel, cnfg->mux);
@@ -418,7 +411,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
}
}
if (*phyid == 0) {
- pr_err("CAIF: %s(): No Available PHY ID\n", __func__);
+ pr_err("No Available PHY ID\n");
return;
}
@@ -427,7 +420,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
phy_driver =
cfserl_create(CFPHYTYPE_FRAG, *phyid, stx);
if (!phy_driver) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return;
}
@@ -436,7 +429,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
phy_driver = NULL;
break;
default:
- pr_err("CAIF: %s(): %d", __func__, phy_type);
+ pr_err("%d\n", phy_type);
return;
break;
}
@@ -455,7 +448,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
phy_layer->type = phy_type;
frml = cffrml_create(*phyid, fcs);
if (!frml) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return;
}
cnfg->phy_layers[*phyid].frm_layer = frml;
diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
index 563145fdc4c3..08f267a109aa 100644
--- a/net/caif/cfctrl.c
+++ b/net/caif/cfctrl.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -36,7 +38,7 @@ struct cflayer *cfctrl_create(void)
struct cfctrl *this =
kmalloc(sizeof(struct cfctrl), GFP_ATOMIC);
if (!this) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cfctrl, serv.layer) == 0);
@@ -132,9 +134,7 @@ struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl,
list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
if (cfctrl_req_eq(req, p)) {
if (p != first)
- pr_warning("CAIF: %s(): Requests are not "
- "received in order\n",
- __func__);
+ pr_warn("Requests are not received in order\n");
atomic_set(&ctrl->rsp_seq_no,
p->sequence_no);
@@ -177,7 +177,7 @@ void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid)
int ret;
struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return;
}
caif_assert(offsetof(struct cfctrl, serv.layer) == 0);
@@ -189,8 +189,7 @@ void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid)
ret =
cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
if (ret < 0) {
- pr_err("CAIF: %s(): Could not transmit enum message\n",
- __func__);
+ pr_err("Could not transmit enum message\n");
cfpkt_destroy(pkt);
}
}
@@ -208,7 +207,7 @@ int cfctrl_linkup_request(struct cflayer *layer,
char utility_name[16];
struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return -ENOMEM;
}
cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_SETUP);
@@ -253,13 +252,13 @@ int cfctrl_linkup_request(struct cflayer *layer,
param->u.utility.paramlen);
break;
default:
- pr_warning("CAIF: %s():Request setup of bad link type = %d\n",
- __func__, param->linktype);
+ pr_warn("Request setup of bad link type = %d\n",
+ param->linktype);
return -EINVAL;
}
req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return -ENOMEM;
}
req->client_layer = user_layer;
@@ -276,8 +275,7 @@ int cfctrl_linkup_request(struct cflayer *layer,
ret =
cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
if (ret < 0) {
- pr_err("CAIF: %s(): Could not transmit linksetup request\n",
- __func__);
+ pr_err("Could not transmit linksetup request\n");
cfpkt_destroy(pkt);
return -ENODEV;
}
@@ -291,7 +289,7 @@ int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid,
struct cfctrl *cfctrl = container_obj(layer);
struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return -ENOMEM;
}
cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_DESTROY);
@@ -300,8 +298,7 @@ int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid,
ret =
cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
if (ret < 0) {
- pr_err("CAIF: %s(): Could not transmit link-down request\n",
- __func__);
+ pr_err("Could not transmit link-down request\n");
cfpkt_destroy(pkt);
}
return ret;
@@ -313,7 +310,7 @@ void cfctrl_sleep_req(struct cflayer *layer)
struct cfctrl *cfctrl = container_obj(layer);
struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return;
}
cfpkt_addbdy(pkt, CFCTRL_CMD_SLEEP);
@@ -330,7 +327,7 @@ void cfctrl_wake_req(struct cflayer *layer)
struct cfctrl *cfctrl = container_obj(layer);
struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return;
}
cfpkt_addbdy(pkt, CFCTRL_CMD_WAKE);
@@ -347,7 +344,7 @@ void cfctrl_getstartreason_req(struct cflayer *layer)
struct cfctrl *cfctrl = container_obj(layer);
struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return;
}
cfpkt_addbdy(pkt, CFCTRL_CMD_START_REASON);
@@ -364,12 +361,11 @@ void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer)
struct cfctrl_request_info *p, *tmp;
struct cfctrl *ctrl = container_obj(layr);
spin_lock(&ctrl->info_list_lock);
- pr_warning("CAIF: %s(): enter\n", __func__);
+ pr_warn("enter\n");
list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
if (p->client_layer == adap_layer) {
- pr_warning("CAIF: %s(): cancel req :%d\n", __func__,
- p->sequence_no);
+ pr_warn("cancel req :%d\n", p->sequence_no);
list_del(&p->list);
kfree(p);
}
@@ -520,9 +516,8 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
cfpkt_extr_head(pkt, &param, len);
break;
default:
- pr_warning("CAIF: %s(): Request setup "
- "- invalid link type (%d)",
- __func__, serv);
+ pr_warn("Request setup - invalid link type (%d)\n",
+ serv);
goto error;
}
@@ -532,9 +527,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
if (CFCTRL_ERR_BIT == (CFCTRL_ERR_BIT & cmdrsp) ||
cfpkt_erroneous(pkt)) {
- pr_err("CAIF: %s(): Invalid O/E bit or parse "
- "error on CAIF control channel",
- __func__);
+ pr_err("Invalid O/E bit or parse error on CAIF control channel\n");
cfctrl->res.reject_rsp(cfctrl->serv.layer.up,
0,
req ? req->client_layer
@@ -556,8 +549,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
cfctrl->res.linkdestroy_rsp(cfctrl->serv.layer.up, linkid);
break;
case CFCTRL_CMD_LINK_ERR:
- pr_err("CAIF: %s(): Frame Error Indication received\n",
- __func__);
+ pr_err("Frame Error Indication received\n");
cfctrl->res.linkerror_ind();
break;
case CFCTRL_CMD_ENUM:
@@ -576,7 +568,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
cfctrl->res.radioset_rsp();
break;
default:
- pr_err("CAIF: %s(): Unrecognized Control Frame\n", __func__);
+ pr_err("Unrecognized Control Frame\n");
goto error;
break;
}
@@ -595,8 +587,7 @@ static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
case CAIF_CTRLCMD_FLOW_OFF_IND:
spin_lock(&this->info_list_lock);
if (!list_empty(&this->list)) {
- pr_debug("CAIF: %s(): Received flow off in "
- "control layer", __func__);
+ pr_debug("Received flow off in control layer\n");
}
spin_unlock(&this->info_list_lock);
break;
@@ -620,7 +611,7 @@ static int handle_loop(struct cfctrl *ctrl, int cmd, struct cfpkt *pkt)
if (!ctrl->loop_linkused[linkid])
goto found;
spin_unlock(&ctrl->loop_linkid_lock);
- pr_err("CAIF: %s(): Out of link-ids\n", __func__);
+ pr_err("Out of link-ids\n");
return -EINVAL;
found:
if (!ctrl->loop_linkused[linkid])
diff --git a/net/caif/cfdbgl.c b/net/caif/cfdbgl.c
index 676648cac8dd..496fda9ac66f 100644
--- a/net/caif/cfdbgl.c
+++ b/net/caif/cfdbgl.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/slab.h>
#include <net/caif/caif_layer.h>
@@ -17,7 +19,7 @@ struct cflayer *cfdbgl_create(u8 channel_id, struct dev_info *dev_info)
{
struct cfsrvl *dbg = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
if (!dbg) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cfsrvl, layer) == 0);
diff --git a/net/caif/cfdgml.c b/net/caif/cfdgml.c
index ed9d53aff280..d3ed264ad6c4 100644
--- a/net/caif/cfdgml.c
+++ b/net/caif/cfdgml.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -26,7 +28,7 @@ struct cflayer *cfdgml_create(u8 channel_id, struct dev_info *dev_info)
{
struct cfsrvl *dgm = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
if (!dgm) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cfsrvl, layer) == 0);
@@ -49,14 +51,14 @@ static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt)
caif_assert(layr->ctrlcmd != NULL);
if (cfpkt_extr_head(pkt, &cmd, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
if ((cmd & DGM_CMD_BIT) == 0) {
if (cfpkt_extr_head(pkt, &dgmhdr, 3) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -75,8 +77,7 @@ static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt)
return 0;
default:
cfpkt_destroy(pkt);
- pr_info("CAIF: %s(): Unknown datagram control %d (0x%x)\n",
- __func__, cmd, cmd);
+ pr_info("Unknown datagram control %d (0x%x)\n", cmd, cmd);
return -EPROTO;
}
}
diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c
index e86a4ca3b217..a445043931ae 100644
--- a/net/caif/cffrml.c
+++ b/net/caif/cffrml.c
@@ -6,6 +6,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -32,7 +34,7 @@ struct cflayer *cffrml_create(u16 phyid, bool use_fcs)
{
struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC);
if (!this) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cffrml, layer) == 0);
@@ -83,7 +85,7 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt)
if (cfpkt_setlen(pkt, len) < 0) {
++cffrml_rcv_error;
- pr_err("CAIF: %s():Framing length error (%d)\n", __func__, len);
+ pr_err("Framing length error (%d)\n", len);
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -99,14 +101,14 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt)
cfpkt_add_trail(pkt, &tmp, 2);
++cffrml_rcv_error;
++cffrml_rcv_checsum_error;
- pr_info("CAIF: %s(): Frame checksum error "
- "(0x%x != 0x%x)\n", __func__, hdrchks, pktchks);
+ pr_info("Frame checksum error (0x%x != 0x%x)\n",
+ hdrchks, pktchks);
return -EILSEQ;
}
}
if (cfpkt_erroneous(pkt)) {
++cffrml_rcv_error;
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -132,7 +134,7 @@ static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt)
cfpkt_add_head(pkt, &tmp, 2);
cfpkt_info(pkt)->hdr_len += 2;
if (cfpkt_erroneous(pkt)) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
return -EPROTO;
}
ret = layr->dn->transmit(layr->dn, pkt);
diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c
index 80c8d332b258..46f34b2e0478 100644
--- a/net/caif/cfmuxl.c
+++ b/net/caif/cfmuxl.c
@@ -3,6 +3,9 @@
* Author: Sjur Brendeland/sjur.brandeland@stericsson.com
* License terms: GNU General Public License (GPL) version 2
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -190,7 +193,7 @@ static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt)
u8 id;
struct cflayer *up;
if (cfpkt_extr_head(pkt, &id, 1) < 0) {
- pr_err("CAIF: %s(): erroneous Caif Packet\n", __func__);
+ pr_err("erroneous Caif Packet\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -199,8 +202,8 @@ static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt)
up = get_up(muxl, id);
spin_unlock(&muxl->receive_lock);
if (up == NULL) {
- pr_info("CAIF: %s():Received data on unknown link ID = %d "
- "(0x%x) up == NULL", __func__, id, id);
+ pr_info("Received data on unknown link ID = %d (0x%x) up == NULL",
+ id, id);
cfpkt_destroy(pkt);
/*
* Don't return ERROR, since modem misbehaves and sends out
@@ -223,9 +226,8 @@ static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt)
struct caif_payload_info *info = cfpkt_info(pkt);
dn = get_dn(muxl, cfpkt_info(pkt)->dev_info);
if (dn == NULL) {
- pr_warning("CAIF: %s(): Send data on unknown phy "
- "ID = %d (0x%x)\n",
- __func__, info->dev_info->id, info->dev_info->id);
+ pr_warn("Send data on unknown phy ID = %d (0x%x)\n",
+ info->dev_info->id, info->dev_info->id);
return -ENOTCONN;
}
info->hdr_len += 1;
diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c
index c49a6695793a..d7e865e2ff65 100644
--- a/net/caif/cfpkt_skbuff.c
+++ b/net/caif/cfpkt_skbuff.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/hardirq.h>
@@ -12,11 +14,12 @@
#define PKT_PREFIX 48
#define PKT_POSTFIX 2
#define PKT_LEN_WHEN_EXTENDING 128
-#define PKT_ERROR(pkt, errmsg) do { \
- cfpkt_priv(pkt)->erronous = true; \
- skb_reset_tail_pointer(&pkt->skb); \
- pr_warning("CAIF: " errmsg);\
- } while (0)
+#define PKT_ERROR(pkt, errmsg) \
+do { \
+ cfpkt_priv(pkt)->erronous = true; \
+ skb_reset_tail_pointer(&pkt->skb); \
+ pr_warn(errmsg); \
+} while (0)
struct cfpktq {
struct sk_buff_head head;
@@ -130,13 +133,13 @@ int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len)
return -EPROTO;
if (unlikely(len > skb->len)) {
- PKT_ERROR(pkt, "cfpkt_extr_head read beyond end of packet\n");
+ PKT_ERROR(pkt, "read beyond end of packet\n");
return -EPROTO;
}
if (unlikely(len > skb_headlen(skb))) {
if (unlikely(skb_linearize(skb) != 0)) {
- PKT_ERROR(pkt, "cfpkt_extr_head linearize failed\n");
+ PKT_ERROR(pkt, "linearize failed\n");
return -EPROTO;
}
}
@@ -156,11 +159,11 @@ int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len)
return -EPROTO;
if (unlikely(skb_linearize(skb) != 0)) {
- PKT_ERROR(pkt, "cfpkt_extr_trail linearize failed\n");
+ PKT_ERROR(pkt, "linearize failed\n");
return -EPROTO;
}
if (unlikely(skb->data + len > skb_tail_pointer(skb))) {
- PKT_ERROR(pkt, "cfpkt_extr_trail read beyond end of packet\n");
+ PKT_ERROR(pkt, "read beyond end of packet\n");
return -EPROTO;
}
from = skb_tail_pointer(skb) - len;
@@ -202,7 +205,7 @@ int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len)
/* Make sure data is writable */
if (unlikely(skb_cow_data(skb, addlen, &lastskb) < 0)) {
- PKT_ERROR(pkt, "cfpkt_add_body: cow failed\n");
+ PKT_ERROR(pkt, "cow failed\n");
return -EPROTO;
}
/*
@@ -211,8 +214,7 @@ int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len)
* lengths of the top SKB.
*/
if (lastskb != skb) {
- pr_warning("CAIF: %s(): Packet is non-linear\n",
- __func__);
+ pr_warn("Packet is non-linear\n");
skb->len += len;
skb->data_len += len;
}
@@ -242,14 +244,14 @@ int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len)
if (unlikely(is_erronous(pkt)))
return -EPROTO;
if (unlikely(skb_headroom(skb) < len)) {
- PKT_ERROR(pkt, "cfpkt_add_head: no headroom\n");
+ PKT_ERROR(pkt, "no headroom\n");
return -EPROTO;
}
/* Make sure data is writable */
ret = skb_cow_data(skb, 0, &lastskb);
if (unlikely(ret < 0)) {
- PKT_ERROR(pkt, "cfpkt_add_head: cow failed\n");
+ PKT_ERROR(pkt, "cow failed\n");
return ret;
}
@@ -283,7 +285,7 @@ inline u16 cfpkt_iterate(struct cfpkt *pkt,
if (unlikely(is_erronous(pkt)))
return -EPROTO;
if (unlikely(skb_linearize(&pkt->skb) != 0)) {
- PKT_ERROR(pkt, "cfpkt_iterate: linearize failed\n");
+ PKT_ERROR(pkt, "linearize failed\n");
return -EPROTO;
}
return iter_func(data, pkt->skb.data, cfpkt_getlen(pkt));
@@ -309,7 +311,7 @@ int cfpkt_setlen(struct cfpkt *pkt, u16 len)
/* Need to expand SKB */
if (unlikely(!cfpkt_pad_trail(pkt, len - skb->len)))
- PKT_ERROR(pkt, "cfpkt_setlen: skb_pad_trail failed\n");
+ PKT_ERROR(pkt, "skb_pad_trail failed\n");
return cfpkt_getlen(pkt);
}
@@ -380,8 +382,7 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos)
return NULL;
if (skb->data + pos > skb_tail_pointer(skb)) {
- PKT_ERROR(pkt,
- "cfpkt_split: trying to split beyond end of packet");
+ PKT_ERROR(pkt, "trying to split beyond end of packet\n");
return NULL;
}
@@ -455,17 +456,17 @@ int cfpkt_raw_append(struct cfpkt *pkt, void **buf, unsigned int buflen)
return -EPROTO;
/* Make sure SKB is writable */
if (unlikely(skb_cow_data(skb, 0, &lastskb) < 0)) {
- PKT_ERROR(pkt, "cfpkt_raw_append: skb_cow_data failed\n");
+ PKT_ERROR(pkt, "skb_cow_data failed\n");
return -EPROTO;
}
if (unlikely(skb_linearize(skb) != 0)) {
- PKT_ERROR(pkt, "cfpkt_raw_append: linearize failed\n");
+ PKT_ERROR(pkt, "linearize failed\n");
return -EPROTO;
}
if (unlikely(skb_tailroom(skb) < buflen)) {
- PKT_ERROR(pkt, "cfpkt_raw_append: buffer too short - failed\n");
+ PKT_ERROR(pkt, "buffer too short - failed\n");
return -EPROTO;
}
@@ -483,14 +484,13 @@ int cfpkt_raw_extract(struct cfpkt *pkt, void **buf, unsigned int buflen)
return -EPROTO;
if (unlikely(buflen > skb->len)) {
- PKT_ERROR(pkt, "cfpkt_raw_extract: buflen too large "
- "- failed\n");
+ PKT_ERROR(pkt, "buflen too large - failed\n");
return -EPROTO;
}
if (unlikely(buflen > skb_headlen(skb))) {
if (unlikely(skb_linearize(skb) != 0)) {
- PKT_ERROR(pkt, "cfpkt_raw_extract: linearize failed\n");
+ PKT_ERROR(pkt, "linearize failed\n");
return -EPROTO;
}
}
diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c
index 9a699242d104..bde8481e8d25 100644
--- a/net/caif/cfrfml.c
+++ b/net/caif/cfrfml.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -48,7 +50,7 @@ struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info,
kzalloc(sizeof(struct cfrfml), GFP_ATOMIC);
if (!this) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
@@ -178,9 +180,7 @@ out:
cfpkt_destroy(rfml->incomplete_frm);
rfml->incomplete_frm = NULL;
- pr_info("CAIF: %s(): "
- "Connection error %d triggered on RFM link\n",
- __func__, err);
+ pr_info("Connection error %d triggered on RFM link\n", err);
/* Trigger connection error upon failure.*/
layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND,
@@ -280,9 +280,7 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt)
out:
if (err != 0) {
- pr_info("CAIF: %s(): "
- "Connection error %d triggered on RFM link\n",
- __func__, err);
+ pr_info("Connection error %d triggered on RFM link\n", err);
/* Trigger connection error upon failure.*/
layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND,
diff --git a/net/caif/cfserl.c b/net/caif/cfserl.c
index a11fbd68a13d..9297f7dea9d8 100644
--- a/net/caif/cfserl.c
+++ b/net/caif/cfserl.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -34,7 +36,7 @@ struct cflayer *cfserl_create(int type, int instance, bool use_stx)
{
struct cfserl *this = kmalloc(sizeof(struct cfserl), GFP_ATOMIC);
if (!this) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cfserl, layer) == 0);
diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c
index f40939a91211..ab5e542526bf 100644
--- a/net/caif/cfsrvl.c
+++ b/net/caif/cfsrvl.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -79,8 +81,7 @@ static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
layr->up->ctrlcmd(layr->up, ctrl, phyid);
break;
default:
- pr_warning("CAIF: %s(): "
- "Unexpected ctrl in cfsrvl (%d)\n", __func__, ctrl);
+ pr_warn("Unexpected ctrl in cfsrvl (%d)\n", ctrl);
/* We have both modem and phy flow on, send flow on */
layr->up->ctrlcmd(layr->up, ctrl, phyid);
service->phy_flow_on = true;
@@ -107,14 +108,12 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
u8 flow_on = SRVL_FLOW_ON;
pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n",
- __func__);
+ pr_warn("Out of memory\n");
return -ENOMEM;
}
if (cfpkt_add_head(pkt, &flow_on, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n",
- __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -131,14 +130,12 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
u8 flow_off = SRVL_FLOW_OFF;
pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
if (!pkt) {
- pr_warning("CAIF: %s(): Out of memory\n",
- __func__);
+ pr_warn("Out of memory\n");
return -ENOMEM;
}
if (cfpkt_add_head(pkt, &flow_off, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n",
- __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
diff --git a/net/caif/cfutill.c b/net/caif/cfutill.c
index 02795aff57a4..efad410e4c82 100644
--- a/net/caif/cfutill.c
+++ b/net/caif/cfutill.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
@@ -26,7 +28,7 @@ struct cflayer *cfutill_create(u8 channel_id, struct dev_info *dev_info)
{
struct cfsrvl *util = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
if (!util) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cfsrvl, layer) == 0);
@@ -47,7 +49,7 @@ static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt)
caif_assert(layr->up->receive != NULL);
caif_assert(layr->up->ctrlcmd != NULL);
if (cfpkt_extr_head(pkt, &cmd, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -64,16 +66,14 @@ static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt)
cfpkt_destroy(pkt);
return 0;
case UTIL_REMOTE_SHUTDOWN: /* Remote Shutdown Request */
- pr_err("CAIF: %s(): REMOTE SHUTDOWN REQUEST RECEIVED\n",
- __func__);
+ pr_err("REMOTE SHUTDOWN REQUEST RECEIVED\n");
layr->ctrlcmd(layr, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, 0);
service->open = false;
cfpkt_destroy(pkt);
return 0;
default:
cfpkt_destroy(pkt);
- pr_warning("CAIF: %s(): Unknown service control %d (0x%x)\n",
- __func__, cmd, cmd);
+ pr_warn("Unknown service control %d (0x%x)\n", cmd, cmd);
return -EPROTO;
}
}
diff --git a/net/caif/cfveil.c b/net/caif/cfveil.c
index 77cc09faac9a..3b425b189a99 100644
--- a/net/caif/cfveil.c
+++ b/net/caif/cfveil.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/stddef.h>
#include <linux/slab.h>
#include <net/caif/caif_layer.h>
@@ -25,7 +27,7 @@ struct cflayer *cfvei_create(u8 channel_id, struct dev_info *dev_info)
{
struct cfsrvl *vei = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
if (!vei) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cfsrvl, layer) == 0);
@@ -47,7 +49,7 @@ static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt)
if (cfpkt_extr_head(pkt, &cmd, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -67,8 +69,7 @@ static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt)
cfpkt_destroy(pkt);
return 0;
default: /* SET RS232 PIN */
- pr_warning("CAIF: %s():Unknown VEI control packet %d (0x%x)!\n",
- __func__, cmd, cmd);
+ pr_warn("Unknown VEI control packet %d (0x%x)!\n", cmd, cmd);
cfpkt_destroy(pkt);
return -EPROTO;
}
@@ -86,7 +87,7 @@ static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt)
caif_assert(layr->dn->transmit != NULL);
if (cfpkt_add_head(pkt, &tmp, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
return -EPROTO;
}
diff --git a/net/caif/cfvidl.c b/net/caif/cfvidl.c
index ada6ee2d48f5..bf6fef2a0eff 100644
--- a/net/caif/cfvidl.c
+++ b/net/caif/cfvidl.c
@@ -4,6 +4,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
@@ -21,7 +23,7 @@ struct cflayer *cfvidl_create(u8 channel_id, struct dev_info *dev_info)
{
struct cfsrvl *vid = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
if (!vid) {
- pr_warning("CAIF: %s(): Out of memory\n", __func__);
+ pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cfsrvl, layer) == 0);
@@ -38,7 +40,7 @@ static int cfvidl_receive(struct cflayer *layr, struct cfpkt *pkt)
{
u32 videoheader;
if (cfpkt_extr_head(pkt, &videoheader, 4) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+ pr_err("Packet is erroneous!\n");
cfpkt_destroy(pkt);
return -EPROTO;
}
diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c
index 4293e190ec53..84a422c98941 100644
--- a/net/caif/chnl_net.c
+++ b/net/caif/chnl_net.c
@@ -5,6 +5,8 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/init.h>
@@ -28,9 +30,6 @@
#define CONNECT_TIMEOUT (5 * HZ)
#define CAIF_NET_DEFAULT_QUEUE_LEN 500
-#undef pr_debug
-#define pr_debug pr_warning
-
/*This list is protected by the rtnl lock. */
static LIST_HEAD(chnl_net_list);
@@ -142,8 +141,7 @@ static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow,
int phyid)
{
struct chnl_net *priv = container_of(layr, struct chnl_net, chnl);
- pr_debug("CAIF: %s(): NET flowctrl func called flow: %s\n",
- __func__,
+ pr_debug("NET flowctrl func called flow: %s\n",
flow == CAIF_CTRLCMD_FLOW_ON_IND ? "ON" :
flow == CAIF_CTRLCMD_INIT_RSP ? "INIT" :
flow == CAIF_CTRLCMD_FLOW_OFF_IND ? "OFF" :
@@ -196,12 +194,12 @@ static int chnl_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
priv = netdev_priv(dev);
if (skb->len > priv->netdev->mtu) {
- pr_warning("CAIF: %s(): Size of skb exceeded MTU\n", __func__);
+ pr_warn("Size of skb exceeded MTU\n");
return -ENOSPC;
}
if (!priv->flowenabled) {
- pr_debug("CAIF: %s(): dropping packets flow off\n", __func__);
+ pr_debug("dropping packets flow off\n");
return NETDEV_TX_BUSY;
}
@@ -237,7 +235,7 @@ static int chnl_net_open(struct net_device *dev)
ASSERT_RTNL();
priv = netdev_priv(dev);
if (!priv) {
- pr_debug("CAIF: %s(): chnl_net_open: no priv\n", __func__);
+ pr_debug("chnl_net_open: no priv\n");
return -ENODEV;
}
@@ -246,18 +244,17 @@ static int chnl_net_open(struct net_device *dev)
result = caif_connect_client(&priv->conn_req, &priv->chnl,
&llifindex, &headroom, &tailroom);
if (result != 0) {
- pr_debug("CAIF: %s(): err: "
- "Unable to register and open device,"
- " Err:%d\n",
- __func__,
- result);
+ pr_debug("err: "
+ "Unable to register and open device,"
+ " Err:%d\n",
+ result);
goto error;
}
lldev = dev_get_by_index(dev_net(dev), llifindex);
if (lldev == NULL) {
- pr_debug("CAIF: %s(): no interface?\n", __func__);
+ pr_debug("no interface?\n");
result = -ENODEV;
goto error;
}
@@ -279,9 +276,7 @@ static int chnl_net_open(struct net_device *dev)
dev_put(lldev);
if (mtu < 100) {
- pr_warning("CAIF: %s(): "
- "CAIF Interface MTU too small (%d)\n",
- __func__, mtu);
+ pr_warn("CAIF Interface MTU too small (%d)\n", mtu);
result = -ENODEV;
goto error;
}
@@ -296,33 +291,32 @@ static int chnl_net_open(struct net_device *dev)
rtnl_lock();
if (result == -ERESTARTSYS) {
- pr_debug("CAIF: %s(): wait_event_interruptible"
- " woken by a signal\n", __func__);
+ pr_debug("wait_event_interruptible woken by a signal\n");
result = -ERESTARTSYS;
goto error;
}
if (result == 0) {
- pr_debug("CAIF: %s(): connect timeout\n", __func__);
+ pr_debug("connect timeout\n");
caif_disconnect_client(&priv->chnl);
priv->state = CAIF_DISCONNECTED;
- pr_debug("CAIF: %s(): state disconnected\n", __func__);
+ pr_debug("state disconnected\n");
result = -ETIMEDOUT;
goto error;
}
if (priv->state != CAIF_CONNECTED) {
- pr_debug("CAIF: %s(): connect failed\n", __func__);
+ pr_debug("connect failed\n");
result = -ECONNREFUSED;
goto error;
}
- pr_debug("CAIF: %s(): CAIF Netdevice connected\n", __func__);
+ pr_debug("CAIF Netdevice connected\n");
return 0;
error:
caif_disconnect_client(&priv->chnl);
priv->state = CAIF_DISCONNECTED;
- pr_debug("CAIF: %s(): state disconnected\n", __func__);
+ pr_debug("state disconnected\n");
return result;
}
@@ -413,7 +407,7 @@ static void caif_netlink_parms(struct nlattr *data[],
struct caif_connect_request *conn_req)
{
if (!data) {
- pr_warning("CAIF: %s: no params data found\n", __func__);
+ pr_warn("no params data found\n");
return;
}
if (data[IFLA_CAIF_IPV4_CONNID])
@@ -442,8 +436,7 @@ static int ipcaif_newlink(struct net *src_net, struct net_device *dev,
ret = register_netdevice(dev);
if (ret)
- pr_warning("CAIF: %s(): device rtml registration failed\n",
- __func__);
+ pr_warn("device rtml registration failed\n");
return ret;
}
diff --git a/net/can/raw.c b/net/can/raw.c
index a10e3338f084..e88f610fdb7b 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -90,23 +90,39 @@ struct raw_sock {
can_err_mask_t err_mask;
};
+/*
+ * Return pointer to store the extra msg flags for raw_recvmsg().
+ * We use the space of one unsigned int beyond the 'struct sockaddr_can'
+ * in skb->cb.
+ */
+static inline unsigned int *raw_flags(struct sk_buff *skb)
+{
+ BUILD_BUG_ON(sizeof(skb->cb) <= (sizeof(struct sockaddr_can) +
+ sizeof(unsigned int)));
+
+ /* return pointer after struct sockaddr_can */
+ return (unsigned int *)(&((struct sockaddr_can *)skb->cb)[1]);
+}
+
static inline struct raw_sock *raw_sk(const struct sock *sk)
{
return (struct raw_sock *)sk;
}
-static void raw_rcv(struct sk_buff *skb, void *data)
+static void raw_rcv(struct sk_buff *oskb, void *data)
{
struct sock *sk = (struct sock *)data;
struct raw_sock *ro = raw_sk(sk);
struct sockaddr_can *addr;
+ struct sk_buff *skb;
+ unsigned int *pflags;
/* check the received tx sock reference */
- if (!ro->recv_own_msgs && skb->sk == sk)
+ if (!ro->recv_own_msgs && oskb->sk == sk)
return;
/* clone the given skb to be able to enqueue it into the rcv queue */
- skb = skb_clone(skb, GFP_ATOMIC);
+ skb = skb_clone(oskb, GFP_ATOMIC);
if (!skb)
return;
@@ -123,6 +139,14 @@ static void raw_rcv(struct sk_buff *skb, void *data)
addr->can_family = AF_CAN;
addr->can_ifindex = skb->dev->ifindex;
+ /* add CAN specific message flags for raw_recvmsg() */
+ pflags = raw_flags(skb);
+ *pflags = 0;
+ if (oskb->sk)
+ *pflags |= MSG_DONTROUTE;
+ if (oskb->sk == sk)
+ *pflags |= MSG_CONFIRM;
+
if (sock_queue_rcv_skb(sk, skb) < 0)
kfree_skb(skb);
}
@@ -647,12 +671,12 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
if (err < 0)
goto free_skb;
- err = sock_tx_timestamp(msg, sk, skb_tx(skb));
+ err = sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
if (err < 0)
goto free_skb;
/* to be able to check the received tx sock reference in raw_rcv() */
- skb_tx(skb)->prevent_sk_orphan = 1;
+ skb_shinfo(skb)->tx_flags |= SKBTX_DRV_NEEDS_SK_REF;
skb->dev = dev;
skb->sk = sk;
@@ -707,6 +731,9 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
}
+ /* assign the flags that have been recorded in raw_rcv() */
+ msg->msg_flags |= *(raw_flags(skb));
+
skb_free_datagram(sk, skb);
return size;
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 282806ba7a57..cd1e039c8755 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -747,13 +747,12 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
mask |= POLLERR;
if (sk->sk_shutdown & RCV_SHUTDOWN)
- mask |= POLLRDHUP;
+ mask |= POLLRDHUP | POLLIN | POLLRDNORM;
if (sk->sk_shutdown == SHUTDOWN_MASK)
mask |= POLLHUP;
/* readable? */
- if (!skb_queue_empty(&sk->sk_receive_queue) ||
- (sk->sk_shutdown & RCV_SHUTDOWN))
+ if (!skb_queue_empty(&sk->sk_receive_queue))
mask |= POLLIN | POLLRDNORM;
/* Connection-based need to check for termination and startup */
diff --git a/net/core/dev.c b/net/core/dev.c
index 7ec85e27beed..35dfb8318483 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -131,6 +131,7 @@
#include <trace/events/net.h>
#include <trace/events/skb.h>
#include <linux/pci.h>
+#include <linux/inetdevice.h>
#include "net-sysfs.h"
@@ -373,6 +374,14 @@ static inline void netdev_set_addr_lockdep_class(struct net_device *dev)
* --ANK (980803)
*/
+static inline struct list_head *ptype_head(const struct packet_type *pt)
+{
+ if (pt->type == htons(ETH_P_ALL))
+ return &ptype_all;
+ else
+ return &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];
+}
+
/**
* dev_add_pack - add packet handler
* @pt: packet type declaration
@@ -388,16 +397,11 @@ static inline void netdev_set_addr_lockdep_class(struct net_device *dev)
void dev_add_pack(struct packet_type *pt)
{
- int hash;
+ struct list_head *head = ptype_head(pt);
- spin_lock_bh(&ptype_lock);
- if (pt->type == htons(ETH_P_ALL))
- list_add_rcu(&pt->list, &ptype_all);
- else {
- hash = ntohs(pt->type) & PTYPE_HASH_MASK;
- list_add_rcu(&pt->list, &ptype_base[hash]);
- }
- spin_unlock_bh(&ptype_lock);
+ spin_lock(&ptype_lock);
+ list_add_rcu(&pt->list, head);
+ spin_unlock(&ptype_lock);
}
EXPORT_SYMBOL(dev_add_pack);
@@ -416,15 +420,10 @@ EXPORT_SYMBOL(dev_add_pack);
*/
void __dev_remove_pack(struct packet_type *pt)
{
- struct list_head *head;
+ struct list_head *head = ptype_head(pt);
struct packet_type *pt1;
- spin_lock_bh(&ptype_lock);
-
- if (pt->type == htons(ETH_P_ALL))
- head = &ptype_all;
- else
- head = &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];
+ spin_lock(&ptype_lock);
list_for_each_entry(pt1, head, list) {
if (pt == pt1) {
@@ -435,7 +434,7 @@ void __dev_remove_pack(struct packet_type *pt)
printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);
out:
- spin_unlock_bh(&ptype_lock);
+ spin_unlock(&ptype_lock);
}
EXPORT_SYMBOL(__dev_remove_pack);
@@ -1486,8 +1485,9 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
skb_orphan(skb);
nf_reset(skb);
- if (!(dev->flags & IFF_UP) ||
- (skb->len > (dev->mtu + dev->hard_header_len))) {
+ if (unlikely(!(dev->flags & IFF_UP) ||
+ (skb->len > (dev->mtu + dev->hard_header_len + VLAN_HLEN)))) {
+ atomic_long_inc(&dev->rx_dropped);
kfree_skb(skb);
return NET_RX_DROP;
}
@@ -1555,21 +1555,56 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
* Routine to help set real_num_tx_queues. To avoid skbs mapped to queues
* greater then real_num_tx_queues stale skbs on the qdisc must be flushed.
*/
-void netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
+int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
{
- unsigned int real_num = dev->real_num_tx_queues;
+ if (txq < 1 || txq > dev->num_tx_queues)
+ return -EINVAL;
- if (unlikely(txq > dev->num_tx_queues))
- ;
- else if (txq > real_num)
- dev->real_num_tx_queues = txq;
- else if (txq < real_num) {
- dev->real_num_tx_queues = txq;
- qdisc_reset_all_tx_gt(dev, txq);
+ if (dev->reg_state == NETREG_REGISTERED) {
+ ASSERT_RTNL();
+
+ if (txq < dev->real_num_tx_queues)
+ qdisc_reset_all_tx_gt(dev, txq);
}
+
+ dev->real_num_tx_queues = txq;
+ return 0;
}
EXPORT_SYMBOL(netif_set_real_num_tx_queues);
+#ifdef CONFIG_RPS
+/**
+ * netif_set_real_num_rx_queues - set actual number of RX queues used
+ * @dev: Network device
+ * @rxq: Actual number of RX queues
+ *
+ * This must be called either with the rtnl_lock held or before
+ * registration of the net device. Returns 0 on success, or a
+ * negative error code. If called before registration, it always
+ * succeeds.
+ */
+int netif_set_real_num_rx_queues(struct net_device *dev, unsigned int rxq)
+{
+ int rc;
+
+ if (rxq < 1 || rxq > dev->num_rx_queues)
+ return -EINVAL;
+
+ if (dev->reg_state == NETREG_REGISTERED) {
+ ASSERT_RTNL();
+
+ rc = net_rx_queue_update_kobjects(dev, dev->real_num_rx_queues,
+ rxq);
+ if (rc)
+ return rc;
+ }
+
+ dev->real_num_rx_queues = rxq;
+ return 0;
+}
+EXPORT_SYMBOL(netif_set_real_num_rx_queues);
+#endif
+
static inline void __netif_reschedule(struct Qdisc *q)
{
struct softnet_data *sd;
@@ -1650,10 +1685,10 @@ EXPORT_SYMBOL(netif_device_attach);
static bool can_checksum_protocol(unsigned long features, __be16 protocol)
{
- return ((features & NETIF_F_GEN_CSUM) ||
- ((features & NETIF_F_IP_CSUM) &&
+ return ((features & NETIF_F_NO_CSUM) ||
+ ((features & NETIF_F_V4_CSUM) &&
protocol == htons(ETH_P_IP)) ||
- ((features & NETIF_F_IPV6_CSUM) &&
+ ((features & NETIF_F_V6_CSUM) &&
protocol == htons(ETH_P_IPV6)) ||
((features & NETIF_F_FCOE_CRC) &&
protocol == htons(ETH_P_FCOE)));
@@ -1661,17 +1696,18 @@ static bool can_checksum_protocol(unsigned long features, __be16 protocol)
static bool dev_can_checksum(struct net_device *dev, struct sk_buff *skb)
{
- if (can_checksum_protocol(dev->features, skb->protocol))
- return true;
+ __be16 protocol = skb->protocol;
+ int features = dev->features;
- if (skb->protocol == htons(ETH_P_8021Q)) {
+ if (vlan_tx_tag_present(skb)) {
+ features &= dev->vlan_features;
+ } else if (protocol == htons(ETH_P_8021Q)) {
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
- if (can_checksum_protocol(dev->features & dev->vlan_features,
- veh->h_vlan_encapsulated_proto))
- return true;
+ protocol = veh->h_vlan_encapsulated_proto;
+ features &= dev->vlan_features;
}
- return false;
+ return can_checksum_protocol(features, protocol);
}
/**
@@ -1760,6 +1796,16 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features)
__be16 type = skb->protocol;
int err;
+ if (type == htons(ETH_P_8021Q)) {
+ struct vlan_ethhdr *veh;
+
+ if (unlikely(!pskb_may_pull(skb, VLAN_ETH_HLEN)))
+ return ERR_PTR(-EINVAL);
+
+ veh = (struct vlan_ethhdr *)skb->data;
+ type = veh->h_vlan_encapsulated_proto;
+ }
+
skb_reset_mac_header(skb);
skb->mac_len = skb->network_header - skb->mac_header;
__skb_pull(skb, skb->mac_len);
@@ -1904,14 +1950,14 @@ static int dev_gso_segment(struct sk_buff *skb)
/*
* Try to orphan skb early, right before transmission by the device.
- * We cannot orphan skb if tx timestamp is requested, since
- * drivers need to call skb_tstamp_tx() to send the timestamp.
+ * We cannot orphan skb if tx timestamp is requested or the sk-reference
+ * is needed on driver level for other reasons, e.g. see net/can/raw.c
*/
static inline void skb_orphan_try(struct sk_buff *skb)
{
struct sock *sk = skb->sk;
- if (sk && !skb_tx(skb)->flags) {
+ if (sk && !skb_shinfo(skb)->tx_flags) {
/* skb_tx_hash() wont be able to get sk.
* We copy sk_hash into skb->rxhash
*/
@@ -1931,9 +1977,14 @@ static inline void skb_orphan_try(struct sk_buff *skb)
static inline int skb_needs_linearize(struct sk_buff *skb,
struct net_device *dev)
{
+ int features = dev->features;
+
+ if (skb->protocol == htons(ETH_P_8021Q) || vlan_tx_tag_present(skb))
+ features &= dev->vlan_features;
+
return skb_is_nonlinear(skb) &&
- ((skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST)) ||
- (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) ||
+ ((skb_has_frag_list(skb) && !(features & NETIF_F_FRAGLIST)) ||
+ (skb_shinfo(skb)->nr_frags && (!(features & NETIF_F_SG) ||
illegal_highdma(dev, skb))));
}
@@ -1956,6 +2007,15 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
skb_orphan_try(skb);
+ if (vlan_tx_tag_present(skb) &&
+ !(dev->features & NETIF_F_HW_VLAN_TX)) {
+ skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb));
+ if (unlikely(!skb))
+ goto out;
+
+ skb->vlan_tci = 0;
+ }
+
if (netif_needs_gso(dev, skb)) {
if (unlikely(dev_gso_segment(skb)))
goto out_kfree_skb;
@@ -2019,6 +2079,7 @@ out_kfree_gso_skb:
skb->destructor = DEV_GSO_CB(skb)->destructor;
out_kfree_skb:
kfree_skb(skb);
+out:
return rc;
}
@@ -2147,6 +2208,9 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
return rc;
}
+static DEFINE_PER_CPU(int, xmit_recursion);
+#define RECURSION_LIMIT 10
+
/**
* dev_queue_xmit - transmit a buffer
* @skb: buffer to transmit
@@ -2213,10 +2277,15 @@ int dev_queue_xmit(struct sk_buff *skb)
if (txq->xmit_lock_owner != cpu) {
+ if (__this_cpu_read(xmit_recursion) > RECURSION_LIMIT)
+ goto recursion_alert;
+
HARD_TX_LOCK(dev, txq, cpu);
if (!netif_tx_queue_stopped(txq)) {
+ __this_cpu_inc(xmit_recursion);
rc = dev_hard_start_xmit(skb, dev, txq);
+ __this_cpu_dec(xmit_recursion);
if (dev_xmit_complete(rc)) {
HARD_TX_UNLOCK(dev, txq);
goto out;
@@ -2228,7 +2297,9 @@ int dev_queue_xmit(struct sk_buff *skb)
"queue packet!\n", dev->name);
} else {
/* Recursion is detected! It is possible,
- * unfortunately */
+ * unfortunately
+ */
+recursion_alert:
if (net_ratelimit())
printk(KERN_CRIT "Dead loop on virtual device "
"%s, fix it urgently!\n", dev->name);
@@ -2264,69 +2335,44 @@ static inline void ____napi_schedule(struct softnet_data *sd,
__raise_softirq_irqoff(NET_RX_SOFTIRQ);
}
-#ifdef CONFIG_RPS
-
-/* One global table that all flow-based protocols share. */
-struct rps_sock_flow_table *rps_sock_flow_table __read_mostly;
-EXPORT_SYMBOL(rps_sock_flow_table);
-
/*
- * get_rps_cpu is called from netif_receive_skb and returns the target
- * CPU from the RPS map of the receiving queue for a given skb.
- * rcu_read_lock must be held on entry.
+ * __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.
*/
-static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
- struct rps_dev_flow **rflowp)
+__u32 __skb_get_rxhash(struct sk_buff *skb)
{
+ int nhoff, hash = 0, poff;
struct ipv6hdr *ip6;
struct iphdr *ip;
- struct netdev_rx_queue *rxqueue;
- struct rps_map *map;
- struct rps_dev_flow_table *flow_table;
- struct rps_sock_flow_table *sock_flow_table;
- int cpu = -1;
u8 ip_proto;
- u16 tcpu;
u32 addr1, addr2, ihl;
union {
u32 v32;
u16 v16[2];
} ports;
- if (skb_rx_queue_recorded(skb)) {
- u16 index = skb_get_rx_queue(skb);
- if (unlikely(index >= dev->num_rx_queues)) {
- WARN_ONCE(dev->num_rx_queues > 1, "%s received packet "
- "on queue %u, but number of RX queues is %u\n",
- dev->name, index, dev->num_rx_queues);
- goto done;
- }
- rxqueue = dev->_rx + index;
- } else
- rxqueue = dev->_rx;
-
- if (!rxqueue->rps_map && !rxqueue->rps_flow_table)
- goto done;
-
- if (skb->rxhash)
- goto got_hash; /* Skip hash computation on packet header */
+ nhoff = skb_network_offset(skb);
switch (skb->protocol) {
case __constant_htons(ETH_P_IP):
- if (!pskb_may_pull(skb, sizeof(*ip)))
+ if (!pskb_may_pull(skb, sizeof(*ip) + nhoff))
goto done;
- ip = (struct iphdr *) skb->data;
- ip_proto = ip->protocol;
+ ip = (struct iphdr *) (skb->data + nhoff);
+ if (ip->frag_off & htons(IP_MF | IP_OFFSET))
+ ip_proto = 0;
+ else
+ ip_proto = ip->protocol;
addr1 = (__force u32) ip->saddr;
addr2 = (__force u32) ip->daddr;
ihl = ip->ihl;
break;
case __constant_htons(ETH_P_IPV6):
- if (!pskb_may_pull(skb, sizeof(*ip6)))
+ if (!pskb_may_pull(skb, sizeof(*ip6) + nhoff))
goto done;
- ip6 = (struct ipv6hdr *) skb->data;
+ ip6 = (struct ipv6hdr *) (skb->data + nhoff);
ip_proto = ip6->nexthdr;
addr1 = (__force u32) ip6->saddr.s6_addr32[3];
addr2 = (__force u32) ip6->daddr.s6_addr32[3];
@@ -2335,33 +2381,81 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
default:
goto done;
}
- switch (ip_proto) {
- case IPPROTO_TCP:
- case IPPROTO_UDP:
- case IPPROTO_DCCP:
- case IPPROTO_ESP:
- case IPPROTO_AH:
- case IPPROTO_SCTP:
- case IPPROTO_UDPLITE:
- if (pskb_may_pull(skb, (ihl * 4) + 4)) {
- ports.v32 = * (__force u32 *) (skb->data + (ihl * 4));
+
+ ports.v32 = 0;
+ poff = proto_ports_offset(ip_proto);
+ if (poff >= 0) {
+ nhoff += ihl * 4 + 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]);
- break;
}
- default:
- ports.v32 = 0;
- break;
}
/* get a consistent hash (same value on both flow directions) */
if (addr2 < addr1)
swap(addr1, addr2);
- skb->rxhash = jhash_3words(addr1, addr2, ports.v32, hashrnd);
- if (!skb->rxhash)
- skb->rxhash = 1;
-got_hash:
+ hash = jhash_3words(addr1, addr2, ports.v32, hashrnd);
+ if (!hash)
+ hash = 1;
+
+done:
+ return hash;
+}
+EXPORT_SYMBOL(__skb_get_rxhash);
+
+#ifdef CONFIG_RPS
+
+/* One global table that all flow-based protocols share. */
+struct rps_sock_flow_table __rcu *rps_sock_flow_table __read_mostly;
+EXPORT_SYMBOL(rps_sock_flow_table);
+
+/*
+ * get_rps_cpu is called from netif_receive_skb and returns the target
+ * CPU from the RPS map of the receiving queue for a given skb.
+ * rcu_read_lock must be held on entry.
+ */
+static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
+ struct rps_dev_flow **rflowp)
+{
+ struct netdev_rx_queue *rxqueue;
+ struct rps_map *map;
+ struct rps_dev_flow_table *flow_table;
+ struct rps_sock_flow_table *sock_flow_table;
+ int cpu = -1;
+ u16 tcpu;
+
+ if (skb_rx_queue_recorded(skb)) {
+ u16 index = skb_get_rx_queue(skb);
+ if (unlikely(index >= dev->real_num_rx_queues)) {
+ WARN_ONCE(dev->real_num_rx_queues > 1,
+ "%s received packet on queue %u, but number "
+ "of RX queues is %u\n",
+ dev->name, index, dev->real_num_rx_queues);
+ goto done;
+ }
+ rxqueue = dev->_rx + index;
+ } else
+ rxqueue = dev->_rx;
+
+ map = rcu_dereference(rxqueue->rps_map);
+ if (map) {
+ if (map->len == 1) {
+ tcpu = map->cpus[0];
+ if (cpu_online(tcpu))
+ cpu = tcpu;
+ goto done;
+ }
+ } else if (!rcu_dereference_raw(rxqueue->rps_flow_table)) {
+ goto done;
+ }
+
+ skb_reset_network_header(skb);
+ if (!skb_get_rxhash(skb))
+ goto done;
+
flow_table = rcu_dereference(rxqueue->rps_flow_table);
sock_flow_table = rcu_dereference(rps_sock_flow_table);
if (flow_table && sock_flow_table) {
@@ -2401,7 +2495,6 @@ got_hash:
}
}
- map = rcu_dereference(rxqueue->rps_map);
if (map) {
tcpu = map->cpus[((u64) skb->rxhash * map->len) >> 32];
@@ -2487,6 +2580,7 @@ enqueue:
local_irq_restore(flags);
+ atomic_long_inc(&skb->dev->rx_dropped);
kfree_skb(skb);
return NET_RX_DROP;
}
@@ -2643,11 +2737,10 @@ EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook);
* the ingress scheduler, you just cant add policies on ingress.
*
*/
-static int ing_filter(struct sk_buff *skb)
+static int ing_filter(struct sk_buff *skb, struct netdev_queue *rxq)
{
struct net_device *dev = skb->dev;
u32 ttl = G_TC_RTTL(skb->tc_verd);
- struct netdev_queue *rxq;
int result = TC_ACT_OK;
struct Qdisc *q;
@@ -2661,8 +2754,6 @@ static int ing_filter(struct sk_buff *skb)
skb->tc_verd = SET_TC_RTTL(skb->tc_verd, ttl);
skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS);
- rxq = &dev->rx_queue;
-
q = rxq->qdisc;
if (q != &noop_qdisc) {
spin_lock(qdisc_lock(q));
@@ -2678,7 +2769,9 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb,
struct packet_type **pt_prev,
int *ret, struct net_device *orig_dev)
{
- if (skb->dev->rx_queue.qdisc == &noop_qdisc)
+ struct netdev_queue *rxq = rcu_dereference(skb->dev->ingress_queue);
+
+ if (!rxq || rxq->qdisc == &noop_qdisc)
goto out;
if (*pt_prev) {
@@ -2686,7 +2779,7 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb,
*pt_prev = NULL;
}
- switch (ing_filter(skb)) {
+ switch (ing_filter(skb, rxq)) {
case TC_ACT_SHOT:
case TC_ACT_STOLEN:
kfree_skb(skb);
@@ -2699,33 +2792,6 @@ out:
}
#endif
-/*
- * netif_nit_deliver - deliver received packets to network taps
- * @skb: buffer
- *
- * This function is used to deliver incoming packets to network
- * taps. It should be used when the normal netif_receive_skb path
- * is bypassed, for example because of VLAN acceleration.
- */
-void netif_nit_deliver(struct sk_buff *skb)
-{
- struct packet_type *ptype;
-
- if (list_empty(&ptype_all))
- return;
-
- skb_reset_network_header(skb);
- skb_reset_transport_header(skb);
- skb->mac_len = skb->network_header - skb->mac_header;
-
- rcu_read_lock();
- list_for_each_entry_rcu(ptype, &ptype_all, list) {
- if (!ptype->dev || ptype->dev == skb->dev)
- deliver_skb(skb, ptype, skb->dev);
- }
- rcu_read_unlock();
-}
-
/**
* netdev_rx_handler_register - register receive handler
* @dev: device to register a handler for
@@ -2836,8 +2902,6 @@ static int __netif_receive_skb(struct sk_buff *skb)
net_timestamp_check(skb);
trace_netif_receive_skb(skb);
- if (vlan_tx_tag_present(skb) && vlan_hwaccel_do_receive(skb))
- return NET_RX_SUCCESS;
/* if we've gotten here through NAPI, check netpoll */
if (netpoll_receive_skb(skb))
@@ -2851,8 +2915,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
* be delivered to pkt handlers that are exact matches. Also
* the deliver_no_wcard flag will be set. If packet handlers
* are sensitive to duplicate packets these skbs will need to
- * be dropped at the handler. The vlan accel path may have
- * already set the deliver_no_wcard flag.
+ * be dropped at the handler.
*/
null_or_orig = NULL;
orig_dev = skb->dev;
@@ -2911,6 +2974,18 @@ ncls:
goto out;
}
+ if (vlan_tx_tag_present(skb)) {
+ if (pt_prev) {
+ ret = deliver_skb(skb, pt_prev, orig_dev);
+ pt_prev = NULL;
+ }
+ if (vlan_hwaccel_do_receive(&skb)) {
+ ret = __netif_receive_skb(skb);
+ goto out;
+ } else if (unlikely(!skb))
+ goto out;
+ }
+
/*
* Make sure frames received on VLAN interfaces stacked on
* bonding interfaces still make their way to any base bonding
@@ -2938,6 +3013,7 @@ ncls:
if (pt_prev) {
ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
} else {
+ atomic_long_inc(&skb->dev->rx_dropped);
kfree_skb(skb);
/* Jamal, now you will not able to escape explaining
* me how you were going to use this. :-)
@@ -3058,7 +3134,7 @@ out:
return netif_receive_skb(skb);
}
-static void napi_gro_flush(struct napi_struct *napi)
+inline void napi_gro_flush(struct napi_struct *napi)
{
struct sk_buff *skb, *next;
@@ -3071,6 +3147,7 @@ static void napi_gro_flush(struct napi_struct *napi)
napi->gro_count = 0;
napi->gro_list = NULL;
}
+EXPORT_SYMBOL(napi_gro_flush);
enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
{
@@ -3085,7 +3162,7 @@ enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
if (!(skb->dev->features & NETIF_F_GRO) || netpoll_rx_on(skb))
goto normal;
- if (skb_is_gso(skb) || skb_has_frags(skb))
+ if (skb_is_gso(skb) || skb_has_frag_list(skb))
goto normal;
rcu_read_lock();
@@ -3164,16 +3241,19 @@ normal:
}
EXPORT_SYMBOL(dev_gro_receive);
-static gro_result_t
+static inline gro_result_t
__napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
{
struct sk_buff *p;
for (p = napi->gro_list; p; p = p->next) {
- NAPI_GRO_CB(p)->same_flow =
- (p->dev == skb->dev) &&
- !compare_ether_header(skb_mac_header(p),
+ unsigned long diffs;
+
+ diffs = (unsigned long)p->dev ^ (unsigned long)skb->dev;
+ diffs |= p->vlan_tci ^ skb->vlan_tci;
+ diffs |= compare_ether_header(skb_mac_header(p),
skb_gro_mac_header(skb));
+ NAPI_GRO_CB(p)->same_flow = !diffs;
NAPI_GRO_CB(p)->flush = 0;
}
@@ -3226,14 +3306,14 @@ gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
}
EXPORT_SYMBOL(napi_gro_receive);
-void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb)
+static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb)
{
__skb_pull(skb, skb_headlen(skb));
skb_reserve(skb, NET_IP_ALIGN - skb_headroom(skb));
+ skb->vlan_tci = 0;
napi->skb = skb;
}
-EXPORT_SYMBOL(napi_reuse_skb);
struct sk_buff *napi_get_frags(struct napi_struct *napi)
{
@@ -4867,21 +4947,6 @@ static void rollback_registered(struct net_device *dev)
rollback_registered_many(&single);
}
-static void __netdev_init_queue_locks_one(struct net_device *dev,
- struct netdev_queue *dev_queue,
- void *_unused)
-{
- spin_lock_init(&dev_queue->_xmit_lock);
- netdev_set_xmit_lockdep_class(&dev_queue->_xmit_lock, dev->type);
- dev_queue->xmit_lock_owner = -1;
-}
-
-static void netdev_init_queue_locks(struct net_device *dev)
-{
- netdev_for_each_tx_queue(dev, __netdev_init_queue_locks_one, NULL);
- __netdev_init_queue_locks_one(dev, &dev->rx_queue, NULL);
-}
-
unsigned long netdev_fix_features(unsigned long features, const char *name)
{
/* Fix illegal SG+CSUM combinations. */
@@ -4949,6 +5014,66 @@ void netif_stacked_transfer_operstate(const struct net_device *rootdev,
}
EXPORT_SYMBOL(netif_stacked_transfer_operstate);
+static int netif_alloc_rx_queues(struct net_device *dev)
+{
+#ifdef CONFIG_RPS
+ unsigned int i, count = dev->num_rx_queues;
+ struct netdev_rx_queue *rx;
+
+ BUG_ON(count < 1);
+
+ rx = kcalloc(count, sizeof(struct netdev_rx_queue), GFP_KERNEL);
+ if (!rx) {
+ pr_err("netdev: Unable to allocate %u rx queues.\n", count);
+ return -ENOMEM;
+ }
+ dev->_rx = rx;
+
+ /*
+ * Set a pointer to first element in the array which holds the
+ * reference count.
+ */
+ for (i = 0; i < count; i++)
+ rx[i].first = rx;
+#endif
+ return 0;
+}
+
+static int netif_alloc_netdev_queues(struct net_device *dev)
+{
+ unsigned int count = dev->num_tx_queues;
+ struct netdev_queue *tx;
+
+ BUG_ON(count < 1);
+
+ tx = kcalloc(count, sizeof(struct netdev_queue), GFP_KERNEL);
+ if (!tx) {
+ pr_err("netdev: Unable to allocate %u tx queues.\n",
+ count);
+ return -ENOMEM;
+ }
+ dev->_tx = tx;
+ return 0;
+}
+
+static void netdev_init_one_queue(struct net_device *dev,
+ struct netdev_queue *queue,
+ void *_unused)
+{
+ queue->dev = dev;
+
+ /* Initialize queue lock */
+ spin_lock_init(&queue->_xmit_lock);
+ netdev_set_xmit_lockdep_class(&queue->_xmit_lock, dev->type);
+ queue->xmit_lock_owner = -1;
+}
+
+static void netdev_init_queues(struct net_device *dev)
+{
+ netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL);
+ spin_lock_init(&dev->tx_global_lock);
+}
+
/**
* register_netdevice - register a network device
* @dev: device to register
@@ -4982,28 +5107,19 @@ int register_netdevice(struct net_device *dev)
spin_lock_init(&dev->addr_list_lock);
netdev_set_addr_lockdep_class(dev);
- netdev_init_queue_locks(dev);
dev->iflink = -1;
-#ifdef CONFIG_RPS
- if (!dev->num_rx_queues) {
- /*
- * Allocate a single RX queue if driver never called
- * alloc_netdev_mq
- */
+ ret = netif_alloc_rx_queues(dev);
+ if (ret)
+ goto out;
- dev->_rx = kzalloc(sizeof(struct netdev_rx_queue), GFP_KERNEL);
- if (!dev->_rx) {
- ret = -ENOMEM;
- goto out;
- }
+ ret = netif_alloc_netdev_queues(dev);
+ if (ret)
+ goto out;
+
+ netdev_init_queues(dev);
- dev->_rx->first = dev->_rx;
- atomic_set(&dev->_rx->count, 1);
- dev->num_rx_queues = 1;
- }
-#endif
/* Init, if this function is available */
if (dev->netdev_ops->ndo_init) {
ret = dev->netdev_ops->ndo_init(dev);
@@ -5043,6 +5159,12 @@ int register_netdevice(struct net_device *dev)
if (dev->features & NETIF_F_SG)
dev->features |= NETIF_F_GSO;
+ /* Enable GRO and NETIF_F_HIGHDMA for vlans by default,
+ * vlan_dev_init() will do the dev->features check, so these features
+ * are enabled only if supported by underlying device.
+ */
+ dev->vlan_features |= (NETIF_F_GRO | NETIF_F_HIGHDMA);
+
ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev);
ret = notifier_to_errno(ret);
if (ret)
@@ -5113,9 +5235,6 @@ int init_dummy_netdev(struct net_device *dev)
*/
dev->reg_state = NETREG_DUMMY;
- /* initialize the ref count */
- atomic_set(&dev->refcnt, 1);
-
/* NAPI wants this */
INIT_LIST_HEAD(&dev->napi_list);
@@ -5123,6 +5242,11 @@ int init_dummy_netdev(struct net_device *dev)
set_bit(__LINK_STATE_PRESENT, &dev->state);
set_bit(__LINK_STATE_START, &dev->state);
+ /* Note : We dont allocate pcpu_refcnt for dummy devices,
+ * because users of this 'device' dont need to change
+ * its refcount.
+ */
+
return 0;
}
EXPORT_SYMBOL_GPL(init_dummy_netdev);
@@ -5164,6 +5288,16 @@ out:
}
EXPORT_SYMBOL(register_netdev);
+int netdev_refcnt_read(const struct net_device *dev)
+{
+ int i, refcnt = 0;
+
+ for_each_possible_cpu(i)
+ refcnt += *per_cpu_ptr(dev->pcpu_refcnt, i);
+ return refcnt;
+}
+EXPORT_SYMBOL(netdev_refcnt_read);
+
/*
* netdev_wait_allrefs - wait until all references are gone.
*
@@ -5178,11 +5312,14 @@ EXPORT_SYMBOL(register_netdev);
static void netdev_wait_allrefs(struct net_device *dev)
{
unsigned long rebroadcast_time, warning_time;
+ int refcnt;
linkwatch_forget_dev(dev);
rebroadcast_time = warning_time = jiffies;
- while (atomic_read(&dev->refcnt) != 0) {
+ refcnt = netdev_refcnt_read(dev);
+
+ while (refcnt != 0) {
if (time_after(jiffies, rebroadcast_time + 1 * HZ)) {
rtnl_lock();
@@ -5209,11 +5346,13 @@ static void netdev_wait_allrefs(struct net_device *dev)
msleep(250);
+ refcnt = netdev_refcnt_read(dev);
+
if (time_after(jiffies, warning_time + 10 * HZ)) {
printk(KERN_EMERG "unregister_netdevice: "
"waiting for %s to become free. Usage "
"count = %d\n",
- dev->name, atomic_read(&dev->refcnt));
+ dev->name, refcnt);
warning_time = jiffies;
}
}
@@ -5271,9 +5410,9 @@ void netdev_run_todo(void)
netdev_wait_allrefs(dev);
/* paranoia */
- BUG_ON(atomic_read(&dev->refcnt));
- WARN_ON(dev->ip_ptr);
- WARN_ON(dev->ip6_ptr);
+ BUG_ON(netdev_refcnt_read(dev));
+ WARN_ON(rcu_dereference_raw(dev->ip_ptr));
+ WARN_ON(rcu_dereference_raw(dev->ip6_ptr));
WARN_ON(dev->dn_ptr);
if (dev->destructor)
@@ -5350,30 +5489,34 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
if (ops->ndo_get_stats64) {
memset(storage, 0, sizeof(*storage));
- return ops->ndo_get_stats64(dev, storage);
- }
- if (ops->ndo_get_stats) {
+ ops->ndo_get_stats64(dev, storage);
+ } else if (ops->ndo_get_stats) {
netdev_stats_to_stats64(storage, ops->ndo_get_stats(dev));
- return storage;
+ } else {
+ netdev_stats_to_stats64(storage, &dev->stats);
+ dev_txq_stats_fold(dev, storage);
}
- netdev_stats_to_stats64(storage, &dev->stats);
- dev_txq_stats_fold(dev, storage);
+ storage->rx_dropped += atomic_long_read(&dev->rx_dropped);
return storage;
}
EXPORT_SYMBOL(dev_get_stats);
-static void netdev_init_one_queue(struct net_device *dev,
- struct netdev_queue *queue,
- void *_unused)
+struct netdev_queue *dev_ingress_queue_create(struct net_device *dev)
{
- queue->dev = dev;
-}
+ struct netdev_queue *queue = dev_ingress_queue(dev);
-static void netdev_init_queues(struct net_device *dev)
-{
- netdev_init_one_queue(dev, &dev->rx_queue, NULL);
- netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL);
- spin_lock_init(&dev->tx_global_lock);
+#ifdef CONFIG_NET_CLS_ACT
+ if (queue)
+ return queue;
+ queue = kzalloc(sizeof(*queue), GFP_KERNEL);
+ if (!queue)
+ return NULL;
+ netdev_init_one_queue(dev, queue, NULL);
+ queue->qdisc = &noop_qdisc;
+ queue->qdisc_sleeping = &noop_qdisc;
+ rcu_assign_pointer(dev->ingress_queue, queue);
+#endif
+ return queue;
}
/**
@@ -5390,17 +5533,18 @@ static void netdev_init_queues(struct net_device *dev)
struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
void (*setup)(struct net_device *), unsigned int queue_count)
{
- struct netdev_queue *tx;
struct net_device *dev;
size_t alloc_size;
struct net_device *p;
-#ifdef CONFIG_RPS
- struct netdev_rx_queue *rx;
- int i;
-#endif
BUG_ON(strlen(name) >= sizeof(dev->name));
+ if (queue_count < 1) {
+ pr_err("alloc_netdev: Unable to allocate device "
+ "with zero queues.\n");
+ return NULL;
+ }
+
alloc_size = sizeof(struct net_device);
if (sizeof_priv) {
/* ensure 32-byte alignment of private area */
@@ -5416,55 +5560,31 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
return NULL;
}
- tx = kcalloc(queue_count, sizeof(struct netdev_queue), GFP_KERNEL);
- if (!tx) {
- printk(KERN_ERR "alloc_netdev: Unable to allocate "
- "tx qdiscs.\n");
- goto free_p;
- }
-
-#ifdef CONFIG_RPS
- rx = kcalloc(queue_count, sizeof(struct netdev_rx_queue), GFP_KERNEL);
- if (!rx) {
- printk(KERN_ERR "alloc_netdev: Unable to allocate "
- "rx queues.\n");
- goto free_tx;
- }
-
- atomic_set(&rx->count, queue_count);
-
- /*
- * Set a pointer to first element in the array which holds the
- * reference count.
- */
- for (i = 0; i < queue_count; i++)
- rx[i].first = rx;
-#endif
-
dev = PTR_ALIGN(p, NETDEV_ALIGN);
dev->padded = (char *)dev - (char *)p;
+ dev->pcpu_refcnt = alloc_percpu(int);
+ if (!dev->pcpu_refcnt)
+ goto free_p;
+
if (dev_addr_init(dev))
- goto free_rx;
+ goto free_pcpu;
dev_mc_init(dev);
dev_uc_init(dev);
dev_net_set(dev, &init_net);
- dev->_tx = tx;
dev->num_tx_queues = queue_count;
dev->real_num_tx_queues = queue_count;
#ifdef CONFIG_RPS
- dev->_rx = rx;
dev->num_rx_queues = queue_count;
+ dev->real_num_rx_queues = queue_count;
#endif
dev->gso_max_size = GSO_MAX_SIZE;
- netdev_init_queues(dev);
-
INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list);
dev->ethtool_ntuple_list.count = 0;
INIT_LIST_HEAD(&dev->napi_list);
@@ -5475,12 +5595,8 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
strcpy(dev->name, name);
return dev;
-free_rx:
-#ifdef CONFIG_RPS
- kfree(rx);
-free_tx:
-#endif
- kfree(tx);
+free_pcpu:
+ free_percpu(dev->pcpu_refcnt);
free_p:
kfree(p);
return NULL;
@@ -5503,6 +5619,8 @@ void free_netdev(struct net_device *dev)
kfree(dev->_tx);
+ kfree(rcu_dereference_raw(dev->ingress_queue));
+
/* Flush device addresses */
dev_addr_flush(dev);
@@ -5512,6 +5630,9 @@ void free_netdev(struct net_device *dev)
list_for_each_entry_safe(p, n, &dev->napi_list, dev_list)
netif_napi_del(p);
+ free_percpu(dev->pcpu_refcnt);
+ dev->pcpu_refcnt = NULL;
+
/* Compatibility with error handling in drivers */
if (dev->reg_state == NETREG_UNINITIALIZED) {
kfree((char *)dev - dev->padded);
@@ -5666,6 +5787,10 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
/* Notify protocols, that we are about to destroy
this device. They should clean all the things.
+
+ Note that dev->reg_state stays at NETREG_REGISTERED.
+ This is wanted because this way 8021q and macvlan know
+ the device is just moving and can keep their slaves up.
*/
call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
call_netdevice_notifiers(NETDEV_UNREGISTER_BATCH, dev);
diff --git a/net/core/dst.c b/net/core/dst.c
index 6c41b1fac3db..8abe628b79f1 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -168,7 +168,7 @@ void *dst_alloc(struct dst_ops *ops)
{
struct dst_entry *dst;
- if (ops->gc && atomic_read(&ops->entries) > ops->gc_thresh) {
+ if (ops->gc && dst_entries_get_fast(ops) > ops->gc_thresh) {
if (ops->gc(ops))
return NULL;
}
@@ -183,7 +183,7 @@ void *dst_alloc(struct dst_ops *ops)
#if RT_CACHE_DEBUG >= 2
atomic_inc(&dst_total);
#endif
- atomic_inc(&ops->entries);
+ dst_entries_add(ops, 1);
return dst;
}
EXPORT_SYMBOL(dst_alloc);
@@ -228,15 +228,15 @@ again:
child = dst->child;
dst->hh = NULL;
- if (hh && atomic_dec_and_test(&hh->hh_refcnt))
- kfree(hh);
+ if (hh)
+ hh_cache_put(hh);
if (neigh) {
dst->neighbour = NULL;
neigh_release(neigh);
}
- atomic_dec(&dst->ops->entries);
+ dst_entries_add(dst->ops, -1);
if (dst->ops->destroy)
dst->ops->destroy(dst);
@@ -271,13 +271,40 @@ void dst_release(struct dst_entry *dst)
if (dst) {
int newrefcnt;
- smp_mb__before_atomic_dec();
newrefcnt = atomic_dec_return(&dst->__refcnt);
WARN_ON(newrefcnt < 0);
+ if (unlikely(dst->flags & DST_NOCACHE) && !newrefcnt) {
+ dst = dst_destroy(dst);
+ if (dst)
+ __dst_free(dst);
+ }
}
}
EXPORT_SYMBOL(dst_release);
+/**
+ * skb_dst_set_noref - sets skb dst, without a reference
+ * @skb: buffer
+ * @dst: dst entry
+ *
+ * Sets skb dst, assuming a reference was not taken on dst
+ * skb_dst_drop() should not dst_release() this dst
+ */
+void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
+{
+ WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
+ /* If dst not in cache, we must take a reference, because
+ * dst_release() will destroy dst as soon as its refcount becomes zero
+ */
+ if (unlikely(dst->flags & DST_NOCACHE)) {
+ dst_hold(dst);
+ skb_dst_set(skb, dst);
+ } else {
+ skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF;
+ }
+}
+EXPORT_SYMBOL(skb_dst_set_noref);
+
/* Dirty hack. We did it in 2.2 (in __dst_free),
* we have _very_ good reasons not to repeat
* this mistake in 2.3, but we have no choice
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 8451ab481095..956a9f4971cb 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -19,6 +19,7 @@
#include <linux/netdevice.h>
#include <linux/bitops.h>
#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
#include <linux/slab.h>
/*
@@ -131,7 +132,8 @@ EXPORT_SYMBOL(ethtool_op_set_ufo);
* NETIF_F_xxx values in include/linux/netdevice.h
*/
static const u32 flags_dup_features =
- (ETH_FLAG_LRO | ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH);
+ (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | ETH_FLAG_NTUPLE |
+ ETH_FLAG_RXHASH);
u32 ethtool_op_get_flags(struct net_device *dev)
{
@@ -205,18 +207,24 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo info;
const struct ethtool_ops *ops = dev->ethtool_ops;
- if (!ops->get_drvinfo)
- return -EOPNOTSUPP;
-
memset(&info, 0, sizeof(info));
info.cmd = ETHTOOL_GDRVINFO;
- ops->get_drvinfo(dev, &info);
+ if (ops && ops->get_drvinfo) {
+ ops->get_drvinfo(dev, &info);
+ } else if (dev->dev.parent && dev->dev.parent->driver) {
+ strlcpy(info.bus_info, dev_name(dev->dev.parent),
+ sizeof(info.bus_info));
+ strlcpy(info.driver, dev->dev.parent->driver->name,
+ sizeof(info.driver));
+ } else {
+ return -EOPNOTSUPP;
+ }
/*
* this method of obtaining string set info is deprecated;
* Use ETHTOOL_GSSET_INFO instead.
*/
- if (ops->get_sset_count) {
+ if (ops && ops->get_sset_count) {
int rc;
rc = ops->get_sset_count(dev, ETH_SS_TEST);
@@ -229,9 +237,9 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
if (rc >= 0)
info.n_priv_flags = rc;
}
- if (ops->get_regs_len)
+ if (ops && ops->get_regs_len)
info.regdump_len = ops->get_regs_len(dev);
- if (ops->get_eeprom_len)
+ if (ops && ops->get_eeprom_len)
info.eedump_len = ops->get_eeprom_len(dev);
if (copy_to_user(useraddr, &info, sizeof(info)))
@@ -479,6 +487,38 @@ static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list,
list->count++;
}
+/*
+ * ethtool does not (or did not) set masks for flow parameters that are
+ * not specified, so if both value and mask are 0 then this must be
+ * treated as equivalent to a mask with all bits set. Implement that
+ * here rather than in drivers.
+ */
+static void rx_ntuple_fix_masks(struct ethtool_rx_ntuple_flow_spec *fs)
+{
+ struct ethtool_tcpip4_spec *entry = &fs->h_u.tcp_ip4_spec;
+ struct ethtool_tcpip4_spec *mask = &fs->m_u.tcp_ip4_spec;
+
+ if (fs->flow_type != TCP_V4_FLOW &&
+ fs->flow_type != UDP_V4_FLOW &&
+ fs->flow_type != SCTP_V4_FLOW)
+ return;
+
+ if (!(entry->ip4src | mask->ip4src))
+ mask->ip4src = htonl(0xffffffff);
+ if (!(entry->ip4dst | mask->ip4dst))
+ mask->ip4dst = htonl(0xffffffff);
+ if (!(entry->psrc | mask->psrc))
+ mask->psrc = htons(0xffff);
+ if (!(entry->pdst | mask->pdst))
+ mask->pdst = htons(0xffff);
+ if (!(entry->tos | mask->tos))
+ mask->tos = 0xff;
+ if (!(fs->vlan_tag | fs->vlan_tag_mask))
+ fs->vlan_tag_mask = 0xffff;
+ if (!(fs->data | fs->data_mask))
+ fs->data_mask = 0xffffffffffffffffULL;
+}
+
static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev,
void __user *useraddr)
{
@@ -493,6 +533,8 @@ static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev,
if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
return -EFAULT;
+ rx_ntuple_fix_masks(&cmd.fs);
+
/*
* Cache filter in dev struct for GET operation only if
* the underlying driver doesn't have its own GET operation, and
@@ -667,19 +709,19 @@ static int ethtool_get_rx_ntuple(struct net_device *dev, void __user *useraddr)
break;
case IP_USER_FLOW:
sprintf(p, "\tSrc IP addr: 0x%x\n",
- fsc->fs.h_u.raw_ip4_spec.ip4src);
+ fsc->fs.h_u.usr_ip4_spec.ip4src);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tSrc IP mask: 0x%x\n",
- fsc->fs.m_u.raw_ip4_spec.ip4src);
+ fsc->fs.m_u.usr_ip4_spec.ip4src);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tDest IP addr: 0x%x\n",
- fsc->fs.h_u.raw_ip4_spec.ip4dst);
+ fsc->fs.h_u.usr_ip4_spec.ip4dst);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tDest IP mask: 0x%x\n",
- fsc->fs.m_u.raw_ip4_spec.ip4dst);
+ fsc->fs.m_u.usr_ip4_spec.ip4dst);
p += ETH_GSTRING_LEN;
num_strings++;
break;
@@ -775,7 +817,7 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
if (regs.len > reglen)
regs.len = reglen;
- regbuf = kzalloc(reglen, GFP_USER);
+ regbuf = vmalloc(reglen);
if (!regbuf)
return -ENOMEM;
@@ -790,7 +832,7 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
ret = 0;
out:
- kfree(regbuf);
+ vfree(regbuf);
return ret;
}
@@ -1175,8 +1217,11 @@ static int ethtool_set_gro(struct net_device *dev, char __user *useraddr)
return -EFAULT;
if (edata.data) {
- if (!dev->ethtool_ops->get_rx_csum ||
- !dev->ethtool_ops->get_rx_csum(dev))
+ u32 rxcsum = dev->ethtool_ops->get_rx_csum ?
+ dev->ethtool_ops->get_rx_csum(dev) :
+ ethtool_op_get_rx_csum(dev);
+
+ if (!rxcsum)
return -EINVAL;
dev->features |= NETIF_F_GRO;
} else
@@ -1402,14 +1447,22 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
if (!dev || !netif_device_present(dev))
return -ENODEV;
- if (!dev->ethtool_ops)
- return -EOPNOTSUPP;
-
if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
return -EFAULT;
+ if (!dev->ethtool_ops) {
+ /* ETHTOOL_GDRVINFO does not require any driver support.
+ * It is also unprivileged and does not change anything,
+ * so we can take a shortcut to it. */
+ if (ethcmd == ETHTOOL_GDRVINFO)
+ return ethtool_get_drvinfo(dev, useraddr);
+ else
+ return -EOPNOTSUPP;
+ }
+
/* Allow some commands to be done by anyone */
switch (ethcmd) {
+ case ETHTOOL_GSET:
case ETHTOOL_GDRVINFO:
case ETHTOOL_GMSGLVL:
case ETHTOOL_GCOALESCE:
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 42e84e08a1be..82a4369ae150 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -144,7 +144,7 @@ fib_rules_register(const struct fib_rules_ops *tmpl, struct net *net)
}
EXPORT_SYMBOL_GPL(fib_rules_register);
-void fib_rules_cleanup_ops(struct fib_rules_ops *ops)
+static void fib_rules_cleanup_ops(struct fib_rules_ops *ops)
{
struct fib_rule *rule, *tmp;
@@ -153,7 +153,6 @@ void fib_rules_cleanup_ops(struct fib_rules_ops *ops)
fib_rule_put(rule);
}
}
-EXPORT_SYMBOL_GPL(fib_rules_cleanup_ops);
static void fib_rules_put_rcu(struct rcu_head *head)
{
@@ -182,7 +181,8 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
{
int ret = 0;
- if (rule->iifindex && (rule->iifindex != fl->iif))
+ if (rule->iifindex && (rule->iifindex != fl->iif) &&
+ !(fl->flags & FLOWI_FLAG_MATCH_ANY_IIF))
goto out;
if (rule->oifindex && (rule->oifindex != fl->oif))
@@ -225,9 +225,12 @@ jumped:
err = ops->action(rule, fl, flags, arg);
if (err != -EAGAIN) {
- fib_rule_get(rule);
- arg->rule = rule;
- goto out;
+ if ((arg->flags & FIB_LOOKUP_NOREF) ||
+ likely(atomic_inc_not_zero(&rule->refcnt))) {
+ arg->rule = rule;
+ goto out;
+ }
+ break;
}
}
@@ -348,12 +351,12 @@ 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->pref == rule->target) {
- rule->ctarget = r;
+ RCU_INIT_POINTER(rule->ctarget, r);
break;
}
}
- if (rule->ctarget == NULL)
+ if (rcu_dereference_protected(rule->ctarget, 1) == NULL)
unresolved = 1;
} else if (rule->action == FR_ACT_GOTO)
goto errout_free;
@@ -370,6 +373,11 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
fib_rule_get(rule);
+ if (last)
+ list_add_rcu(&rule->list, &last->list);
+ else
+ list_add_rcu(&rule->list, &ops->rules_list);
+
if (ops->unresolved_rules) {
/*
* There are unresolved goto rules in the list, check if
@@ -378,7 +386,7 @@ 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(r->ctarget != NULL);
+ BUG_ON(rtnl_dereference(r->ctarget) != NULL);
rcu_assign_pointer(r->ctarget, rule);
if (--ops->unresolved_rules == 0)
break;
@@ -392,11 +400,6 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
if (unresolved)
ops->unresolved_rules++;
- if (last)
- list_add_rcu(&rule->list, &last->list);
- else
- list_add_rcu(&rule->list, &ops->rules_list);
-
notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).pid);
flush_route_cache(ops);
rules_ops_put(ops);
@@ -484,14 +487,13 @@ 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 (tmp->ctarget == rule) {
+ if (rtnl_dereference(tmp->ctarget) == rule) {
rcu_assign_pointer(tmp->ctarget, NULL);
ops->unresolved_rules++;
}
}
}
- synchronize_rcu();
notify_rule_change(RTM_DELRULE, rule, ops, nlh,
NETLINK_CB(skb).pid);
fib_rule_put(rule);
@@ -543,7 +545,8 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
frh->action = rule->action;
frh->flags = rule->flags;
- if (rule->action == FR_ACT_GOTO && rule->ctarget == NULL)
+ if (rule->action == FR_ACT_GOTO &&
+ rcu_dereference_raw(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 52b051f82a01..7beaec36b541 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -89,8 +89,8 @@ int sk_filter(struct sock *sk, struct sk_buff *skb)
rcu_read_lock_bh();
filter = rcu_dereference_bh(sk->sk_filter);
if (filter) {
- unsigned int pkt_len = sk_run_filter(skb, filter->insns,
- filter->len);
+ unsigned int pkt_len = sk_run_filter(skb, filter->insns, filter->len);
+
err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM;
}
rcu_read_unlock_bh();
@@ -638,10 +638,9 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
return err;
}
- rcu_read_lock_bh();
- old_fp = rcu_dereference_bh(sk->sk_filter);
+ old_fp = rcu_dereference_protected(sk->sk_filter,
+ sock_owned_by_user(sk));
rcu_assign_pointer(sk->sk_filter, fp);
- rcu_read_unlock_bh();
if (old_fp)
sk_filter_delayed_uncharge(sk, old_fp);
@@ -654,14 +653,13 @@ int sk_detach_filter(struct sock *sk)
int ret = -ENOENT;
struct sk_filter *filter;
- rcu_read_lock_bh();
- filter = rcu_dereference_bh(sk->sk_filter);
+ filter = rcu_dereference_protected(sk->sk_filter,
+ sock_owned_by_user(sk));
if (filter) {
rcu_assign_pointer(sk->sk_filter, NULL);
sk_filter_delayed_uncharge(sk, filter);
ret = 0;
}
- rcu_read_unlock_bh();
return ret;
}
EXPORT_SYMBOL_GPL(sk_detach_filter);
diff --git a/net/core/flow.c b/net/core/flow.c
index f67dcbfe54ef..127c8a7ffd61 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -53,8 +53,7 @@ struct flow_flush_info {
struct flow_cache {
u32 hash_shift;
- unsigned long order;
- struct flow_cache_percpu *percpu;
+ struct flow_cache_percpu __percpu *percpu;
struct notifier_block hotcpu_notifier;
int low_watermark;
int high_watermark;
@@ -64,7 +63,7 @@ struct flow_cache {
atomic_t flow_cache_genid = ATOMIC_INIT(0);
EXPORT_SYMBOL(flow_cache_genid);
static struct flow_cache flow_cache_global;
-static struct kmem_cache *flow_cachep;
+static struct kmem_cache *flow_cachep __read_mostly;
static DEFINE_SPINLOCK(flow_cache_gc_lock);
static LIST_HEAD(flow_cache_gc_list);
@@ -177,15 +176,11 @@ static u32 flow_hash_code(struct flow_cache *fc,
{
u32 *k = (u32 *) key;
- return (jhash2(k, (sizeof(*key) / sizeof(u32)), fcp->hash_rnd)
- & (flow_cache_hash_size(fc) - 1));
+ return jhash2(k, (sizeof(*key) / sizeof(u32)), fcp->hash_rnd)
+ & (flow_cache_hash_size(fc) - 1);
}
-#if (BITS_PER_LONG == 64)
-typedef u64 flow_compare_t;
-#else
-typedef u32 flow_compare_t;
-#endif
+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
@@ -357,62 +352,73 @@ void flow_cache_flush(void)
put_online_cpus();
}
-static void __init flow_cache_cpu_prepare(struct flow_cache *fc,
- struct flow_cache_percpu *fcp)
+static int __cpuinit flow_cache_cpu_prepare(struct flow_cache *fc, int cpu)
{
- fcp->hash_table = (struct hlist_head *)
- __get_free_pages(GFP_KERNEL|__GFP_ZERO, fc->order);
- if (!fcp->hash_table)
- panic("NET: failed to allocate flow cache order %lu\n", fc->order);
+ struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, cpu);
+ size_t sz = sizeof(struct hlist_head) * flow_cache_hash_size(fc);
- fcp->hash_rnd_recalc = 1;
- fcp->hash_count = 0;
- tasklet_init(&fcp->flush_tasklet, flow_cache_flush_tasklet, 0);
+ if (!fcp->hash_table) {
+ fcp->hash_table = kzalloc_node(sz, GFP_KERNEL, cpu_to_node(cpu));
+ if (!fcp->hash_table) {
+ pr_err("NET: failed to allocate flow cache sz %zu\n", sz);
+ return -ENOMEM;
+ }
+ fcp->hash_rnd_recalc = 1;
+ fcp->hash_count = 0;
+ tasklet_init(&fcp->flush_tasklet, flow_cache_flush_tasklet, 0);
+ }
+ return 0;
}
-static int flow_cache_cpu(struct notifier_block *nfb,
+static int __cpuinit flow_cache_cpu(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
{
struct flow_cache *fc = container_of(nfb, struct flow_cache, hotcpu_notifier);
- int cpu = (unsigned long) hcpu;
+ int res, cpu = (unsigned long) hcpu;
struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, cpu);
- if (action == CPU_DEAD || action == CPU_DEAD_FROZEN)
+ switch (action) {
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
+ res = flow_cache_cpu_prepare(fc, cpu);
+ if (res)
+ return notifier_from_errno(res);
+ break;
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
__flow_cache_shrink(fc, fcp, 0);
+ break;
+ }
return NOTIFY_OK;
}
-static int flow_cache_init(struct flow_cache *fc)
+static int __init flow_cache_init(struct flow_cache *fc)
{
- unsigned long order;
int i;
fc->hash_shift = 10;
fc->low_watermark = 2 * flow_cache_hash_size(fc);
fc->high_watermark = 4 * flow_cache_hash_size(fc);
- for (order = 0;
- (PAGE_SIZE << order) <
- (sizeof(struct hlist_head)*flow_cache_hash_size(fc));
- order++)
- /* NOTHING */;
- fc->order = order;
fc->percpu = alloc_percpu(struct flow_cache_percpu);
+ if (!fc->percpu)
+ return -ENOMEM;
- setup_timer(&fc->rnd_timer, flow_cache_new_hashrnd,
- (unsigned long) fc);
- fc->rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD;
- add_timer(&fc->rnd_timer);
-
- for_each_possible_cpu(i)
- flow_cache_cpu_prepare(fc, per_cpu_ptr(fc->percpu, i));
-
+ for_each_online_cpu(i) {
+ if (flow_cache_cpu_prepare(fc, i))
+ return -ENOMEM;
+ }
fc->hotcpu_notifier = (struct notifier_block){
.notifier_call = flow_cache_cpu,
};
register_hotcpu_notifier(&fc->hotcpu_notifier);
+ setup_timer(&fc->rnd_timer, flow_cache_new_hashrnd,
+ (unsigned long) fc);
+ fc->rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD;
+ add_timer(&fc->rnd_timer);
+
return 0;
}
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c
index 6743146e4d6b..7c2373321b74 100644
--- a/net/core/gen_estimator.c
+++ b/net/core/gen_estimator.c
@@ -274,9 +274,9 @@ void gen_kill_estimator(struct gnet_stats_basic_packed *bstats,
while ((e = gen_find_node(bstats, rate_est))) {
rb_erase(&e->node, &est_root);
- write_lock_bh(&est_lock);
+ write_lock(&est_lock);
e->bstats = NULL;
- write_unlock_bh(&est_lock);
+ write_unlock(&est_lock);
list_del_rcu(&e->list);
call_rcu(&e->e_rcu, __gen_kill_estimator);
diff --git a/net/core/iovec.c b/net/core/iovec.c
index e6b133b77ccb..72aceb1fe4fa 100644
--- a/net/core/iovec.c
+++ b/net/core/iovec.c
@@ -42,7 +42,9 @@ long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address,
if (m->msg_namelen) {
if (mode == VERIFY_READ) {
- err = move_addr_to_kernel(m->msg_name, m->msg_namelen,
+ void __user *namep;
+ namep = (void __user __force *) m->msg_name;
+ err = move_addr_to_kernel(namep, m->msg_namelen,
address);
if (err < 0)
return err;
@@ -53,7 +55,7 @@ long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address,
}
size = m->msg_iovlen * sizeof(struct iovec);
- if (copy_from_user(iov, m->msg_iov, size))
+ if (copy_from_user(iov, (void __user __force *) m->msg_iov, size))
return -EFAULT;
m->msg_iov = iov;
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index a4e0a7482c2b..8cc8f9a79db9 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -122,7 +122,7 @@ static void neigh_cleanup_and_release(struct neighbour *neigh)
unsigned long neigh_rand_reach_time(unsigned long base)
{
- return (base ? (net_random() % base) + (base >> 1) : 0);
+ return base ? (net_random() % base) + (base >> 1) : 0;
}
EXPORT_SYMBOL(neigh_rand_reach_time);
@@ -131,15 +131,20 @@ static int neigh_forced_gc(struct neigh_table *tbl)
{
int shrunk = 0;
int i;
+ struct neigh_hash_table *nht;
NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
write_lock_bh(&tbl->lock);
- for (i = 0; i <= tbl->hash_mask; i++) {
- struct neighbour *n, **np;
+ nht = rcu_dereference_protected(tbl->nht,
+ lockdep_is_held(&tbl->lock));
+ for (i = 0; i <= nht->hash_mask; i++) {
+ struct neighbour *n;
+ struct neighbour __rcu **np;
- np = &tbl->hash_buckets[i];
- while ((n = *np) != NULL) {
+ np = &nht->hash_buckets[i];
+ while ((n = rcu_dereference_protected(*np,
+ lockdep_is_held(&tbl->lock))) != NULL) {
/* Neighbour record may be discarded if:
* - nobody refers to it.
* - it is not permanent
@@ -147,7 +152,9 @@ static int neigh_forced_gc(struct neigh_table *tbl)
write_lock(&n->lock);
if (atomic_read(&n->refcnt) == 1 &&
!(n->nud_state & NUD_PERMANENT)) {
- *np = n->next;
+ rcu_assign_pointer(*np,
+ rcu_dereference_protected(n->next,
+ lockdep_is_held(&tbl->lock)));
n->dead = 1;
shrunk = 1;
write_unlock(&n->lock);
@@ -199,16 +206,24 @@ static void pneigh_queue_purge(struct sk_buff_head *list)
static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
{
int i;
+ struct neigh_hash_table *nht;
- for (i = 0; i <= tbl->hash_mask; i++) {
- struct neighbour *n, **np = &tbl->hash_buckets[i];
+ nht = rcu_dereference_protected(tbl->nht,
+ lockdep_is_held(&tbl->lock));
- while ((n = *np) != NULL) {
+ for (i = 0; i <= nht->hash_mask; i++) {
+ struct neighbour *n;
+ struct neighbour __rcu **np = &nht->hash_buckets[i];
+
+ while ((n = rcu_dereference_protected(*np,
+ lockdep_is_held(&tbl->lock))) != NULL) {
if (dev && n->dev != dev) {
np = &n->next;
continue;
}
- *np = n->next;
+ rcu_assign_pointer(*np,
+ rcu_dereference_protected(n->next,
+ lockdep_is_held(&tbl->lock)));
write_lock(&n->lock);
neigh_del_timer(n);
n->dead = 1;
@@ -279,6 +294,7 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl)
skb_queue_head_init(&n->arp_queue);
rwlock_init(&n->lock);
+ seqlock_init(&n->ha_lock);
n->updated = n->used = now;
n->nud_state = NUD_NONE;
n->output = neigh_blackhole;
@@ -297,64 +313,86 @@ out_entries:
goto out;
}
-static struct neighbour **neigh_hash_alloc(unsigned int entries)
+static struct neigh_hash_table *neigh_hash_alloc(unsigned int entries)
{
- unsigned long size = entries * sizeof(struct neighbour *);
- struct neighbour **ret;
+ size_t size = entries * sizeof(struct neighbour *);
+ struct neigh_hash_table *ret;
+ struct neighbour **buckets;
- if (size <= PAGE_SIZE) {
- ret = kzalloc(size, GFP_ATOMIC);
- } else {
- ret = (struct neighbour **)
- __get_free_pages(GFP_ATOMIC|__GFP_ZERO, get_order(size));
+ ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
+ if (!ret)
+ return NULL;
+ if (size <= PAGE_SIZE)
+ buckets = kzalloc(size, GFP_ATOMIC);
+ else
+ buckets = (struct neighbour **)
+ __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
+ get_order(size));
+ if (!buckets) {
+ kfree(ret);
+ return NULL;
}
+ rcu_assign_pointer(ret->hash_buckets, buckets);
+ ret->hash_mask = entries - 1;
+ get_random_bytes(&ret->hash_rnd, sizeof(ret->hash_rnd));
return ret;
}
-static void neigh_hash_free(struct neighbour **hash, unsigned int entries)
+static void neigh_hash_free_rcu(struct rcu_head *head)
{
- unsigned long size = entries * sizeof(struct neighbour *);
+ struct neigh_hash_table *nht = container_of(head,
+ struct neigh_hash_table,
+ rcu);
+ size_t size = (nht->hash_mask + 1) * sizeof(struct neighbour *);
+ struct neighbour **buckets = nht->hash_buckets;
if (size <= PAGE_SIZE)
- kfree(hash);
+ kfree(buckets);
else
- free_pages((unsigned long)hash, get_order(size));
+ free_pages((unsigned long)buckets, get_order(size));
+ kfree(nht);
}
-static void neigh_hash_grow(struct neigh_table *tbl, unsigned long new_entries)
+static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
+ unsigned long new_entries)
{
- struct neighbour **new_hash, **old_hash;
- unsigned int i, new_hash_mask, old_entries;
+ unsigned int i, hash;
+ struct neigh_hash_table *new_nht, *old_nht;
NEIGH_CACHE_STAT_INC(tbl, hash_grows);
BUG_ON(!is_power_of_2(new_entries));
- new_hash = neigh_hash_alloc(new_entries);
- if (!new_hash)
- return;
-
- old_entries = tbl->hash_mask + 1;
- new_hash_mask = new_entries - 1;
- old_hash = tbl->hash_buckets;
+ old_nht = rcu_dereference_protected(tbl->nht,
+ lockdep_is_held(&tbl->lock));
+ new_nht = neigh_hash_alloc(new_entries);
+ if (!new_nht)
+ return old_nht;
- get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd));
- for (i = 0; i < old_entries; i++) {
+ for (i = 0; i <= old_nht->hash_mask; i++) {
struct neighbour *n, *next;
- for (n = old_hash[i]; n; n = next) {
- unsigned int hash_val = tbl->hash(n->primary_key, n->dev);
-
- hash_val &= new_hash_mask;
- next = n->next;
-
- n->next = new_hash[hash_val];
- new_hash[hash_val] = n;
+ for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
+ lockdep_is_held(&tbl->lock));
+ n != NULL;
+ n = next) {
+ hash = tbl->hash(n->primary_key, n->dev,
+ new_nht->hash_rnd);
+
+ hash &= new_nht->hash_mask;
+ next = rcu_dereference_protected(n->next,
+ lockdep_is_held(&tbl->lock));
+
+ rcu_assign_pointer(n->next,
+ rcu_dereference_protected(
+ new_nht->hash_buckets[hash],
+ lockdep_is_held(&tbl->lock)));
+ rcu_assign_pointer(new_nht->hash_buckets[hash], n);
}
}
- tbl->hash_buckets = new_hash;
- tbl->hash_mask = new_hash_mask;
- neigh_hash_free(old_hash, old_entries);
+ rcu_assign_pointer(tbl->nht, new_nht);
+ call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
+ return new_nht;
}
struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
@@ -363,19 +401,26 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
struct neighbour *n;
int key_len = tbl->key_len;
u32 hash_val;
+ struct neigh_hash_table *nht;
NEIGH_CACHE_STAT_INC(tbl, lookups);
- read_lock_bh(&tbl->lock);
- hash_val = tbl->hash(pkey, dev);
- for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
+ rcu_read_lock_bh();
+ nht = rcu_dereference_bh(tbl->nht);
+ hash_val = tbl->hash(pkey, dev, nht->hash_rnd) & nht->hash_mask;
+
+ for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
+ n != NULL;
+ n = rcu_dereference_bh(n->next)) {
if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
- neigh_hold(n);
+ if (!atomic_inc_not_zero(&n->refcnt))
+ n = NULL;
NEIGH_CACHE_STAT_INC(tbl, hits);
break;
}
}
- read_unlock_bh(&tbl->lock);
+
+ rcu_read_unlock_bh();
return n;
}
EXPORT_SYMBOL(neigh_lookup);
@@ -386,20 +431,27 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
struct neighbour *n;
int key_len = tbl->key_len;
u32 hash_val;
+ struct neigh_hash_table *nht;
NEIGH_CACHE_STAT_INC(tbl, lookups);
- read_lock_bh(&tbl->lock);
- hash_val = tbl->hash(pkey, NULL);
- for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
+ rcu_read_lock_bh();
+ nht = rcu_dereference_bh(tbl->nht);
+ hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) & nht->hash_mask;
+
+ for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
+ n != NULL;
+ n = rcu_dereference_bh(n->next)) {
if (!memcmp(n->primary_key, pkey, key_len) &&
net_eq(dev_net(n->dev), net)) {
- neigh_hold(n);
+ if (!atomic_inc_not_zero(&n->refcnt))
+ n = NULL;
NEIGH_CACHE_STAT_INC(tbl, hits);
break;
}
}
- read_unlock_bh(&tbl->lock);
+
+ rcu_read_unlock_bh();
return n;
}
EXPORT_SYMBOL(neigh_lookup_nodev);
@@ -411,6 +463,7 @@ struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey,
int key_len = tbl->key_len;
int error;
struct neighbour *n1, *rc, *n = neigh_alloc(tbl);
+ struct neigh_hash_table *nht;
if (!n) {
rc = ERR_PTR(-ENOBUFS);
@@ -437,18 +490,24 @@ struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey,
n->confirmed = jiffies - (n->parms->base_reachable_time << 1);
write_lock_bh(&tbl->lock);
+ nht = rcu_dereference_protected(tbl->nht,
+ lockdep_is_held(&tbl->lock));
- if (atomic_read(&tbl->entries) > (tbl->hash_mask + 1))
- neigh_hash_grow(tbl, (tbl->hash_mask + 1) << 1);
+ if (atomic_read(&tbl->entries) > (nht->hash_mask + 1))
+ nht = neigh_hash_grow(tbl, (nht->hash_mask + 1) << 1);
- hash_val = tbl->hash(pkey, dev) & tbl->hash_mask;
+ hash_val = tbl->hash(pkey, dev, nht->hash_rnd) & nht->hash_mask;
if (n->parms->dead) {
rc = ERR_PTR(-EINVAL);
goto out_tbl_unlock;
}
- for (n1 = tbl->hash_buckets[hash_val]; n1; n1 = n1->next) {
+ for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
+ lockdep_is_held(&tbl->lock));
+ n1 != NULL;
+ n1 = rcu_dereference_protected(n1->next,
+ lockdep_is_held(&tbl->lock))) {
if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
neigh_hold(n1);
rc = n1;
@@ -456,10 +515,12 @@ struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey,
}
}
- n->next = tbl->hash_buckets[hash_val];
- tbl->hash_buckets[hash_val] = n;
n->dead = 0;
neigh_hold(n);
+ rcu_assign_pointer(n->next,
+ rcu_dereference_protected(nht->hash_buckets[hash_val],
+ lockdep_is_held(&tbl->lock)));
+ rcu_assign_pointer(nht->hash_buckets[hash_val], n);
write_unlock_bh(&tbl->lock);
NEIGH_PRINTK2("neigh %p is created.\n", n);
rc = n;
@@ -616,6 +677,12 @@ static inline void neigh_parms_put(struct neigh_parms *parms)
neigh_parms_destroy(parms);
}
+static void neigh_destroy_rcu(struct rcu_head *head)
+{
+ struct neighbour *neigh = container_of(head, struct neighbour, rcu);
+
+ kmem_cache_free(neigh->tbl->kmem_cachep, neigh);
+}
/*
* neighbour must already be out of the table;
*
@@ -643,8 +710,7 @@ void neigh_destroy(struct neighbour *neigh)
write_seqlock_bh(&hh->hh_lock);
hh->hh_output = neigh_blackhole;
write_sequnlock_bh(&hh->hh_lock);
- if (atomic_dec_and_test(&hh->hh_refcnt))
- kfree(hh);
+ hh_cache_put(hh);
}
skb_queue_purge(&neigh->arp_queue);
@@ -655,7 +721,7 @@ void neigh_destroy(struct neighbour *neigh)
NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh);
atomic_dec(&neigh->tbl->entries);
- kmem_cache_free(neigh->tbl->kmem_cachep, neigh);
+ call_rcu(&neigh->rcu, neigh_destroy_rcu);
}
EXPORT_SYMBOL(neigh_destroy);
@@ -696,12 +762,16 @@ static void neigh_connect(struct neighbour *neigh)
static void neigh_periodic_work(struct work_struct *work)
{
struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
- struct neighbour *n, **np;
+ struct neighbour *n;
+ struct neighbour __rcu **np;
unsigned int i;
+ struct neigh_hash_table *nht;
NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
write_lock_bh(&tbl->lock);
+ nht = rcu_dereference_protected(tbl->nht,
+ lockdep_is_held(&tbl->lock));
/*
* periodically recompute ReachableTime from random function
@@ -715,10 +785,11 @@ static void neigh_periodic_work(struct work_struct *work)
neigh_rand_reach_time(p->base_reachable_time);
}
- for (i = 0 ; i <= tbl->hash_mask; i++) {
- np = &tbl->hash_buckets[i];
+ for (i = 0 ; i <= nht->hash_mask; i++) {
+ np = &nht->hash_buckets[i];
- while ((n = *np) != NULL) {
+ while ((n = rcu_dereference_protected(*np,
+ lockdep_is_held(&tbl->lock))) != NULL) {
unsigned int state;
write_lock(&n->lock);
@@ -766,9 +837,9 @@ next_elt:
static __inline__ int neigh_max_probes(struct neighbour *n)
{
struct neigh_parms *p = n->parms;
- return (n->nud_state & NUD_PROBE ?
+ return (n->nud_state & NUD_PROBE) ?
p->ucast_probes :
- p->ucast_probes + p->app_probes + p->mcast_probes);
+ p->ucast_probes + p->app_probes + p->mcast_probes;
}
static void neigh_invalidate(struct neighbour *neigh)
@@ -945,7 +1016,7 @@ out_unlock_bh:
}
EXPORT_SYMBOL(__neigh_event_send);
-static void neigh_update_hhs(struct neighbour *neigh)
+static void neigh_update_hhs(const struct neighbour *neigh)
{
struct hh_cache *hh;
void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
@@ -1081,7 +1152,9 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
}
if (lladdr != neigh->ha) {
+ write_seqlock(&neigh->ha_lock);
memcpy(&neigh->ha, lladdr, dev->addr_len);
+ write_sequnlock(&neigh->ha_lock);
neigh_update_hhs(neigh);
if (!(new & NUD_CONNECTED))
neigh->confirmed = jiffies -
@@ -1139,44 +1212,73 @@ struct neighbour *neigh_event_ns(struct neigh_table *tbl,
}
EXPORT_SYMBOL(neigh_event_ns);
+static inline bool neigh_hh_lookup(struct neighbour *n, struct dst_entry *dst,
+ __be16 protocol)
+{
+ struct hh_cache *hh;
+
+ smp_rmb(); /* paired with smp_wmb() in neigh_hh_init() */
+ for (hh = n->hh; hh; hh = hh->hh_next) {
+ if (hh->hh_type == protocol) {
+ atomic_inc(&hh->hh_refcnt);
+ if (unlikely(cmpxchg(&dst->hh, NULL, hh) != NULL))
+ hh_cache_put(hh);
+ return true;
+ }
+ }
+ return false;
+}
+
+/* called with read_lock_bh(&n->lock); */
static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst,
__be16 protocol)
{
struct hh_cache *hh;
struct net_device *dev = dst->dev;
- for (hh = n->hh; hh; hh = hh->hh_next)
- if (hh->hh_type == protocol)
- break;
+ if (likely(neigh_hh_lookup(n, dst, protocol)))
+ return;
- if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) {
- seqlock_init(&hh->hh_lock);
- hh->hh_type = protocol;
- atomic_set(&hh->hh_refcnt, 0);
- hh->hh_next = NULL;
+ /* slow path */
+ hh = kzalloc(sizeof(*hh), GFP_ATOMIC);
+ if (!hh)
+ return;
- if (dev->header_ops->cache(n, hh)) {
- kfree(hh);
- hh = NULL;
- } else {
- atomic_inc(&hh->hh_refcnt);
- hh->hh_next = n->hh;
- n->hh = hh;
- if (n->nud_state & NUD_CONNECTED)
- hh->hh_output = n->ops->hh_output;
- else
- hh->hh_output = n->ops->output;
- }
+ seqlock_init(&hh->hh_lock);
+ hh->hh_type = protocol;
+ atomic_set(&hh->hh_refcnt, 2);
+
+ if (dev->header_ops->cache(n, hh)) {
+ kfree(hh);
+ return;
}
- if (hh) {
- atomic_inc(&hh->hh_refcnt);
- dst->hh = hh;
+
+ write_lock_bh(&n->lock);
+
+ /* must check if another thread already did the insert */
+ if (neigh_hh_lookup(n, dst, protocol)) {
+ kfree(hh);
+ goto end;
}
+
+ if (n->nud_state & NUD_CONNECTED)
+ hh->hh_output = n->ops->hh_output;
+ else
+ hh->hh_output = n->ops->output;
+
+ hh->hh_next = n->hh;
+ smp_wmb(); /* paired with smp_rmb() in neigh_hh_lookup() */
+ n->hh = hh;
+
+ if (unlikely(cmpxchg(&dst->hh, NULL, hh) != NULL))
+ hh_cache_put(hh);
+end:
+ write_unlock_bh(&n->lock);
}
/* This function can be used in contexts, where only old dev_queue_xmit
- worked, f.e. if you want to override normal output path (eql, shaper),
- but resolution is not made yet.
+ * worked, f.e. if you want to override normal output path (eql, shaper),
+ * but resolution is not made yet.
*/
int neigh_compat_output(struct sk_buff *skb)
@@ -1210,19 +1312,19 @@ int neigh_resolve_output(struct sk_buff *skb)
if (!neigh_event_send(neigh, skb)) {
int err;
struct net_device *dev = neigh->dev;
- if (dev->header_ops->cache && !dst->hh) {
- write_lock_bh(&neigh->lock);
- if (!dst->hh)
- neigh_hh_init(neigh, dst, dst->ops->protocol);
- err = dev_hard_header(skb, dev, ntohs(skb->protocol),
- neigh->ha, NULL, skb->len);
- write_unlock_bh(&neigh->lock);
- } else {
- read_lock_bh(&neigh->lock);
+ unsigned int seq;
+
+ if (dev->header_ops->cache &&
+ !dst->hh &&
+ !(dst->flags & DST_NOCACHE))
+ neigh_hh_init(neigh, dst, dst->ops->protocol);
+
+ do {
+ seq = read_seqbegin(&neigh->ha_lock);
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len);
- read_unlock_bh(&neigh->lock);
- }
+ } while (read_seqretry(&neigh->ha_lock, seq));
+
if (err >= 0)
rc = neigh->ops->queue_xmit(skb);
else
@@ -1248,13 +1350,16 @@ int neigh_connected_output(struct sk_buff *skb)
struct dst_entry *dst = skb_dst(skb);
struct neighbour *neigh = dst->neighbour;
struct net_device *dev = neigh->dev;
+ unsigned int seq;
__skb_pull(skb, skb_network_offset(skb));
- read_lock_bh(&neigh->lock);
- err = dev_hard_header(skb, dev, ntohs(skb->protocol),
- neigh->ha, NULL, skb->len);
- read_unlock_bh(&neigh->lock);
+ do {
+ seq = read_seqbegin(&neigh->ha_lock);
+ err = dev_hard_header(skb, dev, ntohs(skb->protocol),
+ neigh->ha, NULL, skb->len);
+ } while (read_seqretry(&neigh->ha_lock, seq));
+
if (err >= 0)
err = neigh->ops->queue_xmit(skb);
else {
@@ -1436,17 +1541,14 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl)
panic("cannot create neighbour proc dir entry");
#endif
- tbl->hash_mask = 1;
- tbl->hash_buckets = neigh_hash_alloc(tbl->hash_mask + 1);
+ tbl->nht = neigh_hash_alloc(8);
phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
- if (!tbl->hash_buckets || !tbl->phash_buckets)
+ if (!tbl->nht || !tbl->phash_buckets)
panic("cannot allocate neighbour cache hashes");
- get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd));
-
rwlock_init(&tbl->lock);
INIT_DELAYED_WORK_DEFERRABLE(&tbl->gc_work, neigh_periodic_work);
schedule_delayed_work(&tbl->gc_work, tbl->parms.reachable_time);
@@ -1486,8 +1588,7 @@ int neigh_table_clear(struct neigh_table *tbl)
struct neigh_table **tp;
/* It is not clean... Fix it to unload IPv6 module safely */
- cancel_delayed_work(&tbl->gc_work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&tbl->gc_work);
del_timer_sync(&tbl->proxy_timer);
pneigh_queue_purge(&tbl->proxy_queue);
neigh_ifdown(tbl, NULL);
@@ -1502,8 +1603,8 @@ int neigh_table_clear(struct neigh_table *tbl)
}
write_unlock(&neigh_tbl_lock);
- neigh_hash_free(tbl->hash_buckets, tbl->hash_mask + 1);
- tbl->hash_buckets = NULL;
+ call_rcu(&tbl->nht->rcu, neigh_hash_free_rcu);
+ tbl->nht = NULL;
kfree(tbl->phash_buckets);
tbl->phash_buckets = NULL;
@@ -1529,6 +1630,7 @@ static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
struct net_device *dev = NULL;
int err = -EINVAL;
+ ASSERT_RTNL();
if (nlmsg_len(nlh) < sizeof(*ndm))
goto out;
@@ -1538,7 +1640,7 @@ static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
ndm = nlmsg_data(nlh);
if (ndm->ndm_ifindex) {
- dev = dev_get_by_index(net, ndm->ndm_ifindex);
+ dev = __dev_get_by_index(net, ndm->ndm_ifindex);
if (dev == NULL) {
err = -ENODEV;
goto out;
@@ -1554,34 +1656,31 @@ static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
read_unlock(&neigh_tbl_lock);
if (nla_len(dst_attr) < tbl->key_len)
- goto out_dev_put;
+ goto out;
if (ndm->ndm_flags & NTF_PROXY) {
err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
- goto out_dev_put;
+ goto out;
}
if (dev == NULL)
- goto out_dev_put;
+ goto out;
neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
if (neigh == NULL) {
err = -ENOENT;
- goto out_dev_put;
+ goto out;
}
err = neigh_update(neigh, NULL, NUD_FAILED,
NEIGH_UPDATE_F_OVERRIDE |
NEIGH_UPDATE_F_ADMIN);
neigh_release(neigh);
- goto out_dev_put;
+ goto out;
}
read_unlock(&neigh_tbl_lock);
err = -EAFNOSUPPORT;
-out_dev_put:
- if (dev)
- dev_put(dev);
out:
return err;
}
@@ -1595,6 +1694,7 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
struct net_device *dev = NULL;
int err;
+ ASSERT_RTNL();
err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
if (err < 0)
goto out;
@@ -1605,14 +1705,14 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
ndm = nlmsg_data(nlh);
if (ndm->ndm_ifindex) {
- dev = dev_get_by_index(net, ndm->ndm_ifindex);
+ dev = __dev_get_by_index(net, ndm->ndm_ifindex);
if (dev == NULL) {
err = -ENODEV;
goto out;
}
if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
- goto out_dev_put;
+ goto out;
}
read_lock(&neigh_tbl_lock);
@@ -1626,7 +1726,7 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
read_unlock(&neigh_tbl_lock);
if (nla_len(tb[NDA_DST]) < tbl->key_len)
- goto out_dev_put;
+ goto out;
dst = nla_data(tb[NDA_DST]);
lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
@@ -1639,29 +1739,29 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
pn->flags = ndm->ndm_flags;
err = 0;
}
- goto out_dev_put;
+ goto out;
}
if (dev == NULL)
- goto out_dev_put;
+ goto out;
neigh = neigh_lookup(tbl, dst, dev);
if (neigh == NULL) {
if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
err = -ENOENT;
- goto out_dev_put;
+ goto out;
}
neigh = __neigh_lookup_errno(tbl, dst, dev);
if (IS_ERR(neigh)) {
err = PTR_ERR(neigh);
- goto out_dev_put;
+ goto out;
}
} else {
if (nlh->nlmsg_flags & NLM_F_EXCL) {
err = -EEXIST;
neigh_release(neigh);
- goto out_dev_put;
+ goto out;
}
if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
@@ -1674,15 +1774,11 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
} else
err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
neigh_release(neigh);
- goto out_dev_put;
+ goto out;
}
read_unlock(&neigh_tbl_lock);
err = -EAFNOSUPPORT;
-
-out_dev_put:
- if (dev)
- dev_put(dev);
out:
return err;
}
@@ -1748,18 +1844,22 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
unsigned long now = jiffies;
unsigned int flush_delta = now - tbl->last_flush;
unsigned int rand_delta = now - tbl->last_rand;
-
+ struct neigh_hash_table *nht;
struct ndt_config ndc = {
.ndtc_key_len = tbl->key_len,
.ndtc_entry_size = tbl->entry_size,
.ndtc_entries = atomic_read(&tbl->entries),
.ndtc_last_flush = jiffies_to_msecs(flush_delta),
.ndtc_last_rand = jiffies_to_msecs(rand_delta),
- .ndtc_hash_rnd = tbl->hash_rnd,
- .ndtc_hash_mask = tbl->hash_mask,
.ndtc_proxy_qlen = tbl->proxy_queue.qlen,
};
+ rcu_read_lock_bh();
+ nht = rcu_dereference_bh(tbl->nht);
+ ndc.ndtc_hash_rnd = nht->hash_rnd;
+ ndc.ndtc_hash_mask = nht->hash_mask;
+ rcu_read_unlock_bh();
+
NLA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc);
}
@@ -2056,10 +2156,14 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
read_lock_bh(&neigh->lock);
ndm->ndm_state = neigh->nud_state;
- if ((neigh->nud_state & NUD_VALID) &&
- nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, neigh->ha) < 0) {
- read_unlock_bh(&neigh->lock);
- goto nla_put_failure;
+ if (neigh->nud_state & NUD_VALID) {
+ char haddr[MAX_ADDR_LEN];
+
+ neigh_ha_snapshot(haddr, neigh, neigh->dev);
+ if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
+ read_unlock_bh(&neigh->lock);
+ goto nla_put_failure;
+ }
}
ci.ndm_used = jiffies_to_clock_t(now - neigh->used);
@@ -2087,18 +2191,23 @@ static void neigh_update_notify(struct neighbour *neigh)
static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
struct netlink_callback *cb)
{
- struct net * net = sock_net(skb->sk);
+ struct net *net = sock_net(skb->sk);
struct neighbour *n;
int rc, h, s_h = cb->args[1];
int idx, s_idx = idx = cb->args[2];
+ struct neigh_hash_table *nht;
- read_lock_bh(&tbl->lock);
- for (h = 0; h <= tbl->hash_mask; h++) {
+ rcu_read_lock_bh();
+ nht = rcu_dereference_bh(tbl->nht);
+
+ for (h = 0; h <= nht->hash_mask; h++) {
if (h < s_h)
continue;
if (h > s_h)
s_idx = 0;
- for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next) {
+ for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
+ n != NULL;
+ n = rcu_dereference_bh(n->next)) {
if (!net_eq(dev_net(n->dev), net))
continue;
if (idx < s_idx)
@@ -2107,17 +2216,16 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
cb->nlh->nlmsg_seq,
RTM_NEWNEIGH,
NLM_F_MULTI) <= 0) {
- read_unlock_bh(&tbl->lock);
rc = -1;
goto out;
}
- next:
+next:
idx++;
}
}
- read_unlock_bh(&tbl->lock);
rc = skb->len;
out:
+ rcu_read_unlock_bh();
cb->args[1] = h;
cb->args[2] = idx;
return rc;
@@ -2150,15 +2258,22 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
{
int chain;
+ struct neigh_hash_table *nht;
- read_lock_bh(&tbl->lock);
- for (chain = 0; chain <= tbl->hash_mask; chain++) {
+ rcu_read_lock_bh();
+ nht = rcu_dereference_bh(tbl->nht);
+
+ read_lock(&tbl->lock); /* avoid resizes */
+ for (chain = 0; chain <= nht->hash_mask; chain++) {
struct neighbour *n;
- for (n = tbl->hash_buckets[chain]; n; n = n->next)
+ for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
+ n != NULL;
+ n = rcu_dereference_bh(n->next))
cb(n, cookie);
}
- read_unlock_bh(&tbl->lock);
+ read_unlock(&tbl->lock);
+ rcu_read_unlock_bh();
}
EXPORT_SYMBOL(neigh_for_each);
@@ -2167,18 +2282,25 @@ void __neigh_for_each_release(struct neigh_table *tbl,
int (*cb)(struct neighbour *))
{
int chain;
+ struct neigh_hash_table *nht;
- for (chain = 0; chain <= tbl->hash_mask; chain++) {
- struct neighbour *n, **np;
+ nht = rcu_dereference_protected(tbl->nht,
+ lockdep_is_held(&tbl->lock));
+ for (chain = 0; chain <= nht->hash_mask; chain++) {
+ struct neighbour *n;
+ struct neighbour __rcu **np;
- np = &tbl->hash_buckets[chain];
- while ((n = *np) != NULL) {
+ np = &nht->hash_buckets[chain];
+ while ((n = rcu_dereference_protected(*np,
+ lockdep_is_held(&tbl->lock))) != NULL) {
int release;
write_lock(&n->lock);
release = cb(n);
if (release) {
- *np = n->next;
+ rcu_assign_pointer(*np,
+ rcu_dereference_protected(n->next,
+ lockdep_is_held(&tbl->lock)));
n->dead = 1;
} else
np = &n->next;
@@ -2196,13 +2318,13 @@ static struct neighbour *neigh_get_first(struct seq_file *seq)
{
struct neigh_seq_state *state = seq->private;
struct net *net = seq_file_net(seq);
- struct neigh_table *tbl = state->tbl;
+ struct neigh_hash_table *nht = state->nht;
struct neighbour *n = NULL;
int bucket = state->bucket;
state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
- for (bucket = 0; bucket <= tbl->hash_mask; bucket++) {
- n = tbl->hash_buckets[bucket];
+ for (bucket = 0; bucket <= nht->hash_mask; bucket++) {
+ n = rcu_dereference_bh(nht->hash_buckets[bucket]);
while (n) {
if (!net_eq(dev_net(n->dev), net))
@@ -2219,8 +2341,8 @@ static struct neighbour *neigh_get_first(struct seq_file *seq)
break;
if (n->nud_state & ~NUD_NOARP)
break;
- next:
- n = n->next;
+next:
+ n = rcu_dereference_bh(n->next);
}
if (n)
@@ -2237,14 +2359,14 @@ static struct neighbour *neigh_get_next(struct seq_file *seq,
{
struct neigh_seq_state *state = seq->private;
struct net *net = seq_file_net(seq);
- struct neigh_table *tbl = state->tbl;
+ struct neigh_hash_table *nht = state->nht;
if (state->neigh_sub_iter) {
void *v = state->neigh_sub_iter(state, n, pos);
if (v)
return n;
}
- n = n->next;
+ n = rcu_dereference_bh(n->next);
while (1) {
while (n) {
@@ -2261,17 +2383,17 @@ static struct neighbour *neigh_get_next(struct seq_file *seq,
if (n->nud_state & ~NUD_NOARP)
break;
- next:
- n = n->next;
+next:
+ n = rcu_dereference_bh(n->next);
}
if (n)
break;
- if (++state->bucket > tbl->hash_mask)
+ if (++state->bucket > nht->hash_mask)
break;
- n = tbl->hash_buckets[state->bucket];
+ n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
}
if (n && pos)
@@ -2369,7 +2491,7 @@ static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
}
void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
- __acquires(tbl->lock)
+ __acquires(rcu_bh)
{
struct neigh_seq_state *state = seq->private;
@@ -2377,7 +2499,8 @@ void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl
state->bucket = 0;
state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
- read_lock_bh(&tbl->lock);
+ rcu_read_lock_bh();
+ state->nht = rcu_dereference_bh(tbl->nht);
return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
}
@@ -2411,12 +2534,9 @@ out:
EXPORT_SYMBOL(neigh_seq_next);
void neigh_seq_stop(struct seq_file *seq, void *v)
- __releases(tbl->lock)
+ __releases(rcu_bh)
{
- struct neigh_seq_state *state = seq->private;
- struct neigh_table *tbl = state->tbl;
-
- read_unlock_bh(&tbl->lock);
+ rcu_read_unlock_bh();
}
EXPORT_SYMBOL(neigh_seq_stop);
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index af4dfbadf2a0..a5ff5a89f376 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -515,7 +515,7 @@ static ssize_t rx_queue_attr_store(struct kobject *kobj, struct attribute *attr,
return attribute->store(queue, attribute, buf, count);
}
-static struct sysfs_ops rx_queue_sysfs_ops = {
+static const struct sysfs_ops rx_queue_sysfs_ops = {
.show = rx_queue_attr_show,
.store = rx_queue_attr_store,
};
@@ -598,7 +598,8 @@ static ssize_t store_rps_map(struct netdev_rx_queue *queue,
}
spin_lock(&rps_map_lock);
- old_map = queue->rps_map;
+ old_map = rcu_dereference_protected(queue->rps_map,
+ lockdep_is_held(&rps_map_lock));
rcu_assign_pointer(queue->rps_map, map);
spin_unlock(&rps_map_lock);
@@ -677,7 +678,8 @@ static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue,
table = NULL;
spin_lock(&rps_dev_flow_lock);
- old_table = queue->rps_flow_table;
+ old_table = rcu_dereference_protected(queue->rps_flow_table,
+ lockdep_is_held(&rps_dev_flow_lock));
rcu_assign_pointer(queue->rps_flow_table, table);
spin_unlock(&rps_dev_flow_lock);
@@ -705,13 +707,17 @@ static void rx_queue_release(struct kobject *kobj)
{
struct netdev_rx_queue *queue = to_rx_queue(kobj);
struct netdev_rx_queue *first = queue->first;
+ struct rps_map *map;
+ struct rps_dev_flow_table *flow_table;
- if (queue->rps_map)
- call_rcu(&queue->rps_map->rcu, rps_map_release);
- if (queue->rps_flow_table)
- call_rcu(&queue->rps_flow_table->rcu,
- rps_dev_flow_table_release);
+ map = rcu_dereference_raw(queue->rps_map);
+ if (map)
+ call_rcu(&map->rcu, rps_map_release);
+
+ flow_table = rcu_dereference_raw(queue->rps_flow_table);
+ if (flow_table)
+ call_rcu(&flow_table->rcu, rps_dev_flow_table_release);
if (atomic_dec_and_test(&first->count))
kfree(first);
@@ -726,6 +732,7 @@ static struct kobj_type rx_queue_ktype = {
static int rx_queue_add_kobject(struct net_device *net, int index)
{
struct netdev_rx_queue *queue = net->_rx + index;
+ struct netdev_rx_queue *first = queue->first;
struct kobject *kobj = &queue->kobj;
int error = 0;
@@ -738,38 +745,43 @@ static int rx_queue_add_kobject(struct net_device *net, int index)
}
kobject_uevent(kobj, KOBJ_ADD);
+ atomic_inc(&first->count);
return error;
}
-static int rx_queue_register_kobjects(struct net_device *net)
+int
+net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num)
{
int i;
int error = 0;
- net->queues_kset = kset_create_and_add("queues",
- NULL, &net->dev.kobj);
- if (!net->queues_kset)
- return -ENOMEM;
- for (i = 0; i < net->num_rx_queues; i++) {
+ for (i = old_num; i < new_num; i++) {
error = rx_queue_add_kobject(net, i);
- if (error)
+ if (error) {
+ new_num = old_num;
break;
+ }
}
- if (error)
- while (--i >= 0)
- kobject_put(&net->_rx[i].kobj);
+ while (--i >= new_num)
+ kobject_put(&net->_rx[i].kobj);
return error;
}
-static void rx_queue_remove_kobjects(struct net_device *net)
+static int rx_queue_register_kobjects(struct net_device *net)
{
- int i;
+ net->queues_kset = kset_create_and_add("queues",
+ NULL, &net->dev.kobj);
+ if (!net->queues_kset)
+ return -ENOMEM;
+ return net_rx_queue_update_kobjects(net, 0, net->real_num_rx_queues);
+}
- for (i = 0; i < net->num_rx_queues; i++)
- kobject_put(&net->_rx[i].kobj);
+static void rx_queue_remove_kobjects(struct net_device *net)
+{
+ net_rx_queue_update_kobjects(net, net->real_num_rx_queues, 0);
kset_unregister(net->queues_kset);
}
#endif /* CONFIG_RPS */
@@ -789,12 +801,13 @@ static const void *net_netlink_ns(struct sock *sk)
return sock_net(sk);
}
-static struct kobj_ns_type_operations net_ns_type_operations = {
+struct kobj_ns_type_operations net_ns_type_operations = {
.type = KOBJ_NS_TYPE_NET,
.current_ns = net_current_ns,
.netlink_ns = net_netlink_ns,
.initial_ns = net_initial_ns,
};
+EXPORT_SYMBOL_GPL(net_ns_type_operations);
static void net_kobj_ns_exit(struct net *net)
{
diff --git a/net/core/net-sysfs.h b/net/core/net-sysfs.h
index 805555e8b187..778e1571548d 100644
--- a/net/core/net-sysfs.h
+++ b/net/core/net-sysfs.h
@@ -4,4 +4,8 @@
int netdev_kobject_init(void);
int netdev_register_kobject(struct net_device *);
void netdev_unregister_kobject(struct net_device *);
+#ifdef CONFIG_RPS
+int net_rx_queue_update_kobjects(struct net_device *, int old_num, int new_num);
+#endif
+
#endif
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index c988e685433a..3f860261c5ee 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -42,7 +42,9 @@ static int net_assign_generic(struct net *net, int id, void *data)
BUG_ON(!mutex_is_locked(&net_mutex));
BUG_ON(id == 0);
- ng = old_ng = net->gen;
+ old_ng = rcu_dereference_protected(net->gen,
+ lockdep_is_held(&net_mutex));
+ ng = old_ng;
if (old_ng->len >= id)
goto assign;
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 537e01afd81b..4e98ffac3af0 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -288,11 +288,11 @@ static int netpoll_owner_active(struct net_device *dev)
return 0;
}
-void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
+void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
+ struct net_device *dev)
{
int status = NETDEV_TX_BUSY;
unsigned long tries;
- struct net_device *dev = np->dev;
const struct net_device_ops *ops = dev->netdev_ops;
/* It is up to the caller to keep npinfo alive. */
struct netpoll_info *npinfo = np->dev->npinfo;
@@ -346,7 +346,7 @@ void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
schedule_delayed_work(&npinfo->tx_work,0);
}
}
-EXPORT_SYMBOL(netpoll_send_skb);
+EXPORT_SYMBOL(netpoll_send_skb_on_dev);
void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
{
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 10a1ea72010d..679b797d06b1 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -729,16 +729,14 @@ static int hex32_arg(const char __user *user_buffer, unsigned long maxlen,
*num = 0;
for (; i < maxlen; i++) {
+ int value;
char c;
*num <<= 4;
if (get_user(c, &user_buffer[i]))
return -EFAULT;
- if ((c >= '0') && (c <= '9'))
- *num |= c - '0';
- else if ((c >= 'a') && (c <= 'f'))
- *num |= c - 'a' + 10;
- else if ((c >= 'A') && (c <= 'F'))
- *num |= c - 'A' + 10;
+ value = hex_to_bin(c);
+ if (value >= 0)
+ *num |= value;
else
break;
}
@@ -773,10 +771,10 @@ done:
static unsigned long num_arg(const char __user * user_buffer,
unsigned long maxlen, unsigned long *num)
{
- int i = 0;
+ int i;
*num = 0;
- for (; i < maxlen; i++) {
+ for (i = 0; i < maxlen; i++) {
char c;
if (get_user(c, &user_buffer[i]))
return -EFAULT;
@@ -791,9 +789,9 @@ static unsigned long num_arg(const char __user * user_buffer,
static int strn_len(const char __user * user_buffer, unsigned int maxlen)
{
- int i = 0;
+ int i;
- for (; i < maxlen; i++) {
+ for (i = 0; i < maxlen; i++) {
char c;
if (get_user(c, &user_buffer[i]))
return -EFAULT;
@@ -848,7 +846,7 @@ static ssize_t pktgen_if_write(struct file *file,
{
struct seq_file *seq = file->private_data;
struct pktgen_dev *pkt_dev = seq->private;
- int i = 0, max, len;
+ int i, max, len;
char name[16], valstr[32];
unsigned long value = 0;
char *pg_result = NULL;
@@ -862,13 +860,13 @@ static ssize_t pktgen_if_write(struct file *file,
return -EINVAL;
}
- max = count - i;
- tmp = count_trail_chars(&user_buffer[i], max);
+ max = count;
+ tmp = count_trail_chars(user_buffer, max);
if (tmp < 0) {
pr_warning("illegal format\n");
return tmp;
}
- i += tmp;
+ i = tmp;
/* Read variable name */
@@ -1766,7 +1764,7 @@ static ssize_t pktgen_thread_write(struct file *file,
{
struct seq_file *seq = file->private_data;
struct pktgen_thread *t = seq->private;
- int i = 0, max, len, ret;
+ int i, max, len, ret;
char name[40];
char *pg_result;
@@ -1775,12 +1773,12 @@ static ssize_t pktgen_thread_write(struct file *file,
return -EINVAL;
}
- max = count - i;
- len = count_trail_chars(&user_buffer[i], max);
+ max = count;
+ len = count_trail_chars(user_buffer, max);
if (len < 0)
return len;
- i += len;
+ i = len;
/* Read variable name */
@@ -1977,7 +1975,7 @@ static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev,
const char *ifname)
{
char b[IFNAMSIZ+5];
- int i = 0;
+ int i;
for (i = 0; ifname[i] != '@'; i++) {
if (i == IFNAMSIZ)
@@ -2521,8 +2519,8 @@ static void free_SAs(struct pktgen_dev *pkt_dev)
{
if (pkt_dev->cflows) {
/* let go of the SAs if we have them */
- int i = 0;
- for (; i < pkt_dev->cflows; i++) {
+ int i;
+ for (i = 0; i < pkt_dev->cflows; i++) {
struct xfrm_state *x = pkt_dev->flows[i].x;
if (x) {
xfrm_state_put(x);
@@ -3907,8 +3905,6 @@ static void __exit pg_cleanup(void)
{
struct pktgen_thread *t;
struct list_head *q, *n;
- wait_queue_head_t queue;
- init_waitqueue_head(&queue);
/* Stop all interfaces & threads */
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index f78d821bd935..8121268ddbdd 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -299,14 +299,6 @@ static void __rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops)
unregister_netdevice_many(&list_kill);
}
-void rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops)
-{
- rtnl_lock();
- __rtnl_kill_links(net, ops);
- rtnl_unlock();
-}
-EXPORT_SYMBOL_GPL(rtnl_kill_links);
-
/**
* __rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink.
* @ops: struct rtnl_link_ops * to unregister
@@ -612,36 +604,7 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
static void copy_rtnl_link_stats64(void *v, const struct rtnl_link_stats64 *b)
{
- struct rtnl_link_stats64 a;
-
- a.rx_packets = b->rx_packets;
- a.tx_packets = b->tx_packets;
- a.rx_bytes = b->rx_bytes;
- a.tx_bytes = b->tx_bytes;
- a.rx_errors = b->rx_errors;
- a.tx_errors = b->tx_errors;
- a.rx_dropped = b->rx_dropped;
- a.tx_dropped = b->tx_dropped;
-
- a.multicast = b->multicast;
- a.collisions = b->collisions;
-
- a.rx_length_errors = b->rx_length_errors;
- a.rx_over_errors = b->rx_over_errors;
- a.rx_crc_errors = b->rx_crc_errors;
- a.rx_frame_errors = b->rx_frame_errors;
- a.rx_fifo_errors = b->rx_fifo_errors;
- a.rx_missed_errors = b->rx_missed_errors;
-
- a.tx_aborted_errors = b->tx_aborted_errors;
- a.tx_carrier_errors = b->tx_carrier_errors;
- a.tx_fifo_errors = b->tx_fifo_errors;
- a.tx_heartbeat_errors = b->tx_heartbeat_errors;
- a.tx_window_errors = b->tx_window_errors;
-
- a.rx_compressed = b->rx_compressed;
- a.tx_compressed = b->tx_compressed;
- memcpy(v, &a, sizeof(a));
+ memcpy(v, b, sizeof(*b));
}
/* All VF info */
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 56ba3c4e4761..104f8444754a 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -202,8 +202,6 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
skb->data = data;
skb_reset_tail_pointer(skb);
skb->end = skb->tail + size;
- kmemcheck_annotate_bitfield(skb, flags1);
- kmemcheck_annotate_bitfield(skb, flags2);
#ifdef NET_SKBUFF_DATA_USES_OFFSET
skb->mac_header = ~0U;
#endif
@@ -249,10 +247,9 @@ EXPORT_SYMBOL(__alloc_skb);
struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
unsigned int length, gfp_t gfp_mask)
{
- int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
struct sk_buff *skb;
- skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, node);
+ skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, NUMA_NO_NODE);
if (likely(skb)) {
skb_reserve(skb, NET_SKB_PAD);
skb->dev = dev;
@@ -261,16 +258,6 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
}
EXPORT_SYMBOL(__netdev_alloc_skb);
-struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask)
-{
- int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
- struct page *page;
-
- page = alloc_pages_node(node, gfp_mask, 0);
- return page;
-}
-EXPORT_SYMBOL(__netdev_alloc_page);
-
void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
int size)
{
@@ -340,7 +327,7 @@ static void skb_release_data(struct sk_buff *skb)
put_page(skb_shinfo(skb)->frags[i].page);
}
- if (skb_has_frags(skb))
+ if (skb_has_frag_list(skb))
skb_drop_fraglist(skb);
kfree(skb->head);
@@ -686,16 +673,10 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
{
- int headerlen = skb->data - skb->head;
- /*
- * Allocate the copy buffer
- */
- struct sk_buff *n;
-#ifdef NET_SKBUFF_DATA_USES_OFFSET
- n = alloc_skb(skb->end + skb->data_len, gfp_mask);
-#else
- n = alloc_skb(skb->end - skb->head + skb->data_len, gfp_mask);
-#endif
+ int headerlen = skb_headroom(skb);
+ unsigned int size = (skb_end_pointer(skb) - skb->head) + skb->data_len;
+ struct sk_buff *n = alloc_skb(size, gfp_mask);
+
if (!n)
return NULL;
@@ -727,20 +708,14 @@ EXPORT_SYMBOL(skb_copy);
struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
{
- /*
- * Allocate the copy buffer
- */
- struct sk_buff *n;
-#ifdef NET_SKBUFF_DATA_USES_OFFSET
- n = alloc_skb(skb->end, gfp_mask);
-#else
- n = alloc_skb(skb->end - skb->head, gfp_mask);
-#endif
+ unsigned int size = skb_end_pointer(skb) - skb->head;
+ struct sk_buff *n = alloc_skb(size, gfp_mask);
+
if (!n)
goto out;
/* Set the data pointer */
- skb_reserve(n, skb->data - skb->head);
+ skb_reserve(n, skb_headroom(skb));
/* Set the tail pointer and length */
skb_put(n, skb_headlen(skb));
/* Copy the bytes */
@@ -760,7 +735,7 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
skb_shinfo(n)->nr_frags = i;
}
- if (skb_has_frags(skb)) {
+ if (skb_has_frag_list(skb)) {
skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list;
skb_clone_fraglist(n);
}
@@ -792,12 +767,9 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
{
int i;
u8 *data;
-#ifdef NET_SKBUFF_DATA_USES_OFFSET
- int size = nhead + skb->end + ntail;
-#else
- int size = nhead + (skb->end - skb->head) + ntail;
-#endif
+ int size = nhead + (skb_end_pointer(skb) - skb->head) + ntail;
long off;
+ bool fastpath;
BUG_ON(nhead < 0);
@@ -811,23 +783,36 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
goto nodata;
/* Copy only real data... and, alas, header. This should be
- * optimized for the cases when header is void. */
-#ifdef NET_SKBUFF_DATA_USES_OFFSET
- memcpy(data + nhead, skb->head, skb->tail);
-#else
- memcpy(data + nhead, skb->head, skb->tail - skb->head);
-#endif
- memcpy(data + size, skb_end_pointer(skb),
+ * optimized for the cases when header is void.
+ */
+ memcpy(data + nhead, skb->head, skb_tail_pointer(skb) - skb->head);
+
+ memcpy((struct skb_shared_info *)(data + size),
+ skb_shinfo(skb),
offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags]));
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
- get_page(skb_shinfo(skb)->frags[i].page);
+ /* Check if we can avoid taking references on fragments if we own
+ * the last reference on skb->head. (see skb_release_data())
+ */
+ if (!skb->cloned)
+ fastpath = true;
+ else {
+ int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;
- if (skb_has_frags(skb))
- skb_clone_fraglist(skb);
+ fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
+ }
- skb_release_data(skb);
+ if (fastpath) {
+ kfree(skb->head);
+ } else {
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+ get_page(skb_shinfo(skb)->frags[i].page);
+ if (skb_has_frag_list(skb))
+ skb_clone_fraglist(skb);
+
+ skb_release_data(skb);
+ }
off = (data + nhead) - skb->head;
skb->head = data;
@@ -1100,7 +1085,7 @@ drop_pages:
for (; i < nfrags; i++)
put_page(skb_shinfo(skb)->frags[i].page);
- if (skb_has_frags(skb))
+ if (skb_has_frag_list(skb))
skb_drop_fraglist(skb);
goto done;
}
@@ -1195,7 +1180,7 @@ unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta)
/* Optimization: no fragments, no reasons to preestimate
* size of pulled pages. Superb.
*/
- if (!skb_has_frags(skb))
+ if (!skb_has_frag_list(skb))
goto pull_pages;
/* Estimate size of pulled pages. */
@@ -2324,7 +2309,7 @@ next_skb:
st->frag_data = NULL;
}
- if (st->root_skb == st->cur_skb && skb_has_frags(st->root_skb)) {
+ if (st->root_skb == st->cur_skb && skb_has_frag_list(st->root_skb)) {
st->cur_skb = skb_shinfo(st->root_skb)->frag_list;
st->frag_idx = 0;
goto next_skb;
@@ -2894,7 +2879,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
return -ENOMEM;
/* Easy case. Most of packets will go this way. */
- if (!skb_has_frags(skb)) {
+ if (!skb_has_frag_list(skb)) {
/* A little of trouble, not enough of space for trailer.
* This should not happen, when stack is tuned to generate
* good frames. OK, on miss we reallocate and reserve even more
@@ -2929,7 +2914,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
if (skb1->next == NULL && tailbits) {
if (skb_shinfo(skb1)->nr_frags ||
- skb_has_frags(skb1) ||
+ skb_has_frag_list(skb1) ||
skb_tailroom(skb1) < tailbits)
ntail = tailbits + 128;
}
@@ -2938,7 +2923,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
skb_cloned(skb1) ||
ntail ||
skb_shinfo(skb1)->nr_frags ||
- skb_has_frags(skb1)) {
+ skb_has_frag_list(skb1)) {
struct sk_buff *skb2;
/* Fuck, we are miserable poor guys... */
@@ -3021,7 +3006,7 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,
} else {
/*
* no hardware time stamps available,
- * so keep the skb_shared_tx and only
+ * so keep the shared tx_flags and only
* store software time stamp
*/
skb->tstamp = ktime_get_real();
diff --git a/net/core/sock.c b/net/core/sock.c
index 7d99e13148e6..3eed5424e659 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1225,7 +1225,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
sock_reset_flag(newsk, SOCK_DONE);
skb_queue_head_init(&newsk->sk_error_queue);
- filter = newsk->sk_filter;
+ filter = rcu_dereference_protected(newsk->sk_filter, 1);
if (filter != NULL)
sk_filter_charge(newsk, filter);
@@ -1560,6 +1560,8 @@ struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size,
EXPORT_SYMBOL(sock_alloc_send_skb);
static void __lock_sock(struct sock *sk)
+ __releases(&sk->sk_lock.slock)
+ __acquires(&sk->sk_lock.slock)
{
DEFINE_WAIT(wait);
@@ -1576,6 +1578,8 @@ static void __lock_sock(struct sock *sk)
}
static void __release_sock(struct sock *sk)
+ __releases(&sk->sk_lock.slock)
+ __acquires(&sk->sk_lock.slock)
{
struct sk_buff *skb = sk->sk_backlog.head;
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 01eee5d984be..385b6095fdc4 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -34,7 +34,8 @@ static int rps_sock_flow_sysctl(ctl_table *table, int write,
mutex_lock(&sock_flow_mutex);
- orig_sock_table = rps_sock_flow_table;
+ orig_sock_table = rcu_dereference_protected(rps_sock_flow_table,
+ lockdep_is_held(&sock_flow_mutex));
size = orig_size = orig_sock_table ? orig_sock_table->mask + 1 : 0;
ret = proc_dointvec(&tmp, write, buffer, lenp, ppos);
diff --git a/net/core/utils.c b/net/core/utils.c
index f41854470539..5fea0ab21902 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -75,7 +75,7 @@ __be32 in_aton(const char *str)
str++;
}
}
- return(htonl(l));
+ return htonl(l);
}
EXPORT_SYMBOL(in_aton);
@@ -92,18 +92,19 @@ EXPORT_SYMBOL(in_aton);
static inline int xdigit2bin(char c, int delim)
{
+ int val;
+
if (c == delim || c == '\0')
return IN6PTON_DELIM;
if (c == ':')
return IN6PTON_COLON_MASK;
if (c == '.')
return IN6PTON_DOT;
- if (c >= '0' && c <= '9')
- return (IN6PTON_XDIGIT | IN6PTON_DIGIT| (c - '0'));
- if (c >= 'a' && c <= 'f')
- return (IN6PTON_XDIGIT | (c - 'a' + 10));
- if (c >= 'A' && c <= 'F')
- return (IN6PTON_XDIGIT | (c - 'A' + 10));
+
+ val = hex_to_bin(c);
+ if (val >= 0)
+ return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0);
+
if (delim == -1)
return IN6PTON_DELIM;
return IN6PTON_UNKNOWN;
diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h
index 6df6f8ac9636..117fb093dcaf 100644
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -62,22 +62,18 @@ struct ccid_operations {
void (*ccid_hc_tx_exit)(struct sock *sk);
void (*ccid_hc_rx_packet_recv)(struct sock *sk,
struct sk_buff *skb);
- int (*ccid_hc_rx_parse_options)(struct sock *sk,
- unsigned char option,
- unsigned char len, u16 idx,
- unsigned char* value);
+ int (*ccid_hc_rx_parse_options)(struct sock *sk, u8 pkt,
+ u8 opt, u8 *val, u8 len);
int (*ccid_hc_rx_insert_options)(struct sock *sk,
struct sk_buff *skb);
void (*ccid_hc_tx_packet_recv)(struct sock *sk,
struct sk_buff *skb);
- int (*ccid_hc_tx_parse_options)(struct sock *sk,
- unsigned char option,
- unsigned char len, u16 idx,
- unsigned char* value);
+ int (*ccid_hc_tx_parse_options)(struct sock *sk, u8 pkt,
+ u8 opt, u8 *val, u8 len);
int (*ccid_hc_tx_send_packet)(struct sock *sk,
struct sk_buff *skb);
void (*ccid_hc_tx_packet_sent)(struct sock *sk,
- int more, unsigned int len);
+ unsigned int len);
void (*ccid_hc_rx_get_info)(struct sock *sk,
struct tcp_info *info);
void (*ccid_hc_tx_get_info)(struct sock *sk,
@@ -148,10 +144,10 @@ static inline int ccid_hc_tx_send_packet(struct ccid *ccid, struct sock *sk,
}
static inline void ccid_hc_tx_packet_sent(struct ccid *ccid, struct sock *sk,
- int more, unsigned int len)
+ unsigned int len)
{
if (ccid->ccid_ops->ccid_hc_tx_packet_sent != NULL)
- ccid->ccid_ops->ccid_hc_tx_packet_sent(sk, more, len);
+ ccid->ccid_ops->ccid_hc_tx_packet_sent(sk, len);
}
static inline void ccid_hc_rx_packet_recv(struct ccid *ccid, struct sock *sk,
@@ -168,27 +164,31 @@ static inline void ccid_hc_tx_packet_recv(struct ccid *ccid, struct sock *sk,
ccid->ccid_ops->ccid_hc_tx_packet_recv(sk, skb);
}
+/**
+ * ccid_hc_tx_parse_options - Parse CCID-specific options sent by the receiver
+ * @pkt: type of packet that @opt appears on (RFC 4340, 5.1)
+ * @opt: the CCID-specific option type (RFC 4340, 5.8 and 10.3)
+ * @val: value of @opt
+ * @len: length of @val in bytes
+ */
static inline int ccid_hc_tx_parse_options(struct ccid *ccid, struct sock *sk,
- unsigned char option,
- unsigned char len, u16 idx,
- unsigned char* value)
+ u8 pkt, u8 opt, u8 *val, u8 len)
{
- int rc = 0;
- if (ccid->ccid_ops->ccid_hc_tx_parse_options != NULL)
- rc = ccid->ccid_ops->ccid_hc_tx_parse_options(sk, option, len, idx,
- value);
- return rc;
+ if (ccid->ccid_ops->ccid_hc_tx_parse_options == NULL)
+ return 0;
+ return ccid->ccid_ops->ccid_hc_tx_parse_options(sk, pkt, opt, val, len);
}
+/**
+ * ccid_hc_rx_parse_options - Parse CCID-specific options sent by the sender
+ * Arguments are analogous to ccid_hc_tx_parse_options()
+ */
static inline int ccid_hc_rx_parse_options(struct ccid *ccid, struct sock *sk,
- unsigned char option,
- unsigned char len, u16 idx,
- unsigned char* value)
+ u8 pkt, u8 opt, u8 *val, u8 len)
{
- int rc = 0;
- if (ccid->ccid_ops->ccid_hc_rx_parse_options != NULL)
- rc = ccid->ccid_ops->ccid_hc_rx_parse_options(sk, option, len, idx, value);
- return rc;
+ if (ccid->ccid_ops->ccid_hc_rx_parse_options == NULL)
+ return 0;
+ return ccid->ccid_ops->ccid_hc_rx_parse_options(sk, pkt, opt, val, len);
}
static inline int ccid_hc_rx_insert_options(struct ccid *ccid, struct sock *sk,
diff --git a/net/dccp/ccids/Kconfig b/net/dccp/ccids/Kconfig
index 8408398cd44e..0581143cb800 100644
--- a/net/dccp/ccids/Kconfig
+++ b/net/dccp/ccids/Kconfig
@@ -47,37 +47,6 @@ config IP_DCCP_CCID3_DEBUG
If in doubt, say N.
-config IP_DCCP_CCID3_RTO
- int "Use higher bound for nofeedback timer"
- default 100
- depends on IP_DCCP_CCID3 && EXPERIMENTAL
- ---help---
- Use higher lower bound for nofeedback timer expiration.
-
- The TFRC nofeedback timer normally expires after the maximum of 4
- RTTs and twice the current send interval (RFC 3448, 4.3). On LANs
- with a small RTT this can mean a high processing load and reduced
- performance, since then the nofeedback timer is triggered very
- frequently.
-
- This option enables to set a higher lower bound for the nofeedback
- value. Values in units of milliseconds can be set here.
-
- A value of 0 disables this feature by enforcing the value specified
- in RFC 3448. The following values have been suggested as bounds for
- experimental use:
- * 16-20ms to match the typical multimedia inter-frame interval
- * 100ms as a reasonable compromise [default]
- * 1000ms corresponds to the lower TCP RTO bound (RFC 2988, 2.4)
-
- The default of 100ms is a compromise between a large value for
- efficient DCCP implementations, and a small value to avoid disrupting
- the network in times of congestion.
-
- The purpose of the nofeedback timer is to slow DCCP down when there
- is serious network congestion: experimenting with larger values should
- therefore not be performed on WANs.
-
config IP_DCCP_TFRC_LIB
def_bool y if IP_DCCP_CCID3
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
index 9b3ae9922be1..d850e291f87c 100644
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -25,59 +25,14 @@
*/
#include <linux/slab.h>
#include "../feat.h"
-#include "../ccid.h"
-#include "../dccp.h"
#include "ccid2.h"
#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
static int ccid2_debug;
#define ccid2_pr_debug(format, a...) DCCP_PR_DEBUG(ccid2_debug, format, ##a)
-
-static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hc)
-{
- int len = 0;
- int pipe = 0;
- struct ccid2_seq *seqp = hc->tx_seqh;
-
- /* there is data in the chain */
- if (seqp != hc->tx_seqt) {
- seqp = seqp->ccid2s_prev;
- len++;
- if (!seqp->ccid2s_acked)
- pipe++;
-
- while (seqp != hc->tx_seqt) {
- struct ccid2_seq *prev = seqp->ccid2s_prev;
-
- len++;
- if (!prev->ccid2s_acked)
- pipe++;
-
- /* packets are sent sequentially */
- BUG_ON(dccp_delta_seqno(seqp->ccid2s_seq,
- prev->ccid2s_seq ) >= 0);
- BUG_ON(time_before(seqp->ccid2s_sent,
- prev->ccid2s_sent));
-
- seqp = prev;
- }
- }
-
- BUG_ON(pipe != hc->tx_pipe);
- ccid2_pr_debug("len of chain=%d\n", len);
-
- do {
- seqp = seqp->ccid2s_prev;
- len++;
- } while (seqp != hc->tx_seqh);
-
- ccid2_pr_debug("total len=%d\n", len);
- BUG_ON(len != hc->tx_seqbufc * CCID2_SEQBUF_LEN);
-}
#else
#define ccid2_pr_debug(format, a...)
-#define ccid2_hc_tx_check_sanity(hc)
#endif
static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hc)
@@ -156,19 +111,10 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val)
dp->dccps_l_ack_ratio = val;
}
-static void ccid2_change_srtt(struct ccid2_hc_tx_sock *hc, long val)
-{
- ccid2_pr_debug("change SRTT to %ld\n", val);
- hc->tx_srtt = val;
-}
-
-static void ccid2_start_rto_timer(struct sock *sk);
-
static void ccid2_hc_tx_rto_expire(unsigned long data)
{
struct sock *sk = (struct sock *)data;
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- long s;
bh_lock_sock(sk);
if (sock_owned_by_user(sk)) {
@@ -178,23 +124,19 @@ static void ccid2_hc_tx_rto_expire(unsigned long data)
ccid2_pr_debug("RTO_EXPIRE\n");
- ccid2_hc_tx_check_sanity(hc);
-
/* back-off timer */
hc->tx_rto <<= 1;
+ if (hc->tx_rto > DCCP_RTO_MAX)
+ hc->tx_rto = DCCP_RTO_MAX;
- s = hc->tx_rto / HZ;
- if (s > 60)
- hc->tx_rto = 60 * HZ;
-
- ccid2_start_rto_timer(sk);
+ sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
/* adjust pipe, cwnd etc */
hc->tx_ssthresh = hc->tx_cwnd / 2;
if (hc->tx_ssthresh < 2)
hc->tx_ssthresh = 2;
- hc->tx_cwnd = 1;
- hc->tx_pipe = 0;
+ hc->tx_cwnd = 1;
+ hc->tx_pipe = 0;
/* clear state about stuff we sent */
hc->tx_seqt = hc->tx_seqh;
@@ -204,23 +146,12 @@ static void ccid2_hc_tx_rto_expire(unsigned long data)
hc->tx_rpseq = 0;
hc->tx_rpdupack = -1;
ccid2_change_l_ack_ratio(sk, 1);
- ccid2_hc_tx_check_sanity(hc);
out:
bh_unlock_sock(sk);
sock_put(sk);
}
-static void ccid2_start_rto_timer(struct sock *sk)
-{
- struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
-
- ccid2_pr_debug("setting RTO timeout=%ld\n", hc->tx_rto);
-
- BUG_ON(timer_pending(&hc->tx_rtotimer));
- sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
-}
-
-static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
+static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
@@ -230,7 +161,7 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
hc->tx_seqh->ccid2s_seq = dp->dccps_gss;
hc->tx_seqh->ccid2s_acked = 0;
- hc->tx_seqh->ccid2s_sent = jiffies;
+ hc->tx_seqh->ccid2s_sent = ccid2_time_stamp;
next = hc->tx_seqh->ccid2s_next;
/* check if we need to alloc more space */
@@ -296,23 +227,20 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
}
#endif
- /* setup RTO timer */
- if (!timer_pending(&hc->tx_rtotimer))
- ccid2_start_rto_timer(sk);
+ sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
do {
struct ccid2_seq *seqp = hc->tx_seqt;
while (seqp != hc->tx_seqh) {
- ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n",
+ ccid2_pr_debug("out seq=%llu acked=%d time=%u\n",
(unsigned long long)seqp->ccid2s_seq,
seqp->ccid2s_acked, seqp->ccid2s_sent);
seqp = seqp->ccid2s_next;
}
} while (0);
ccid2_pr_debug("=========\n");
- ccid2_hc_tx_check_sanity(hc);
#endif
}
@@ -378,17 +306,87 @@ out_invalid_option:
return -1;
}
-static void ccid2_hc_tx_kill_rto_timer(struct sock *sk)
+/**
+ * ccid2_rtt_estimator - Sample RTT and compute RTO using RFC2988 algorithm
+ * This code is almost identical with TCP's tcp_rtt_estimator(), since
+ * - it has a higher sampling frequency (recommended by RFC 1323),
+ * - the RTO does not collapse into RTT due to RTTVAR going towards zero,
+ * - it is simple (cf. more complex proposals such as Eifel timer or research
+ * which suggests that the gain should be set according to window size),
+ * - in tests it was found to work well with CCID2 [gerrit].
+ */
+static void ccid2_rtt_estimator(struct sock *sk, const long mrtt)
{
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
+ long m = mrtt ? : 1;
- sk_stop_timer(sk, &hc->tx_rtotimer);
- ccid2_pr_debug("deleted RTO timer\n");
+ if (hc->tx_srtt == 0) {
+ /* First measurement m */
+ hc->tx_srtt = m << 3;
+ hc->tx_mdev = m << 1;
+
+ hc->tx_mdev_max = max(hc->tx_mdev, tcp_rto_min(sk));
+ hc->tx_rttvar = hc->tx_mdev_max;
+
+ hc->tx_rtt_seq = dccp_sk(sk)->dccps_gss;
+ } else {
+ /* Update scaled SRTT as SRTT += 1/8 * (m - SRTT) */
+ m -= (hc->tx_srtt >> 3);
+ hc->tx_srtt += m;
+
+ /* Similarly, update scaled mdev with regard to |m| */
+ if (m < 0) {
+ m = -m;
+ m -= (hc->tx_mdev >> 2);
+ /*
+ * This neutralises RTO increase when RTT < SRTT - mdev
+ * (see P. Sarolahti, A. Kuznetsov,"Congestion Control
+ * in Linux TCP", USENIX 2002, pp. 49-62).
+ */
+ if (m > 0)
+ m >>= 3;
+ } else {
+ m -= (hc->tx_mdev >> 2);
+ }
+ hc->tx_mdev += m;
+
+ if (hc->tx_mdev > hc->tx_mdev_max) {
+ hc->tx_mdev_max = hc->tx_mdev;
+ if (hc->tx_mdev_max > hc->tx_rttvar)
+ hc->tx_rttvar = hc->tx_mdev_max;
+ }
+
+ /*
+ * Decay RTTVAR at most once per flight, exploiting that
+ * 1) pipe <= cwnd <= Sequence_Window = W (RFC 4340, 7.5.2)
+ * 2) AWL = GSS-W+1 <= GAR <= GSS (RFC 4340, 7.5.1)
+ * GAR is a useful bound for FlightSize = pipe.
+ * AWL is probably too low here, as it over-estimates pipe.
+ */
+ if (after48(dccp_sk(sk)->dccps_gar, hc->tx_rtt_seq)) {
+ if (hc->tx_mdev_max < hc->tx_rttvar)
+ hc->tx_rttvar -= (hc->tx_rttvar -
+ hc->tx_mdev_max) >> 2;
+ hc->tx_rtt_seq = dccp_sk(sk)->dccps_gss;
+ hc->tx_mdev_max = tcp_rto_min(sk);
+ }
+ }
+
+ /*
+ * Set RTO from SRTT and RTTVAR
+ * As in TCP, 4 * RTTVAR >= TCP_RTO_MIN, giving a minimum RTO of 200 ms.
+ * This agrees with RFC 4341, 5:
+ * "Because DCCP does not retransmit data, DCCP does not require
+ * TCP's recommended minimum timeout of one second".
+ */
+ hc->tx_rto = (hc->tx_srtt >> 3) + hc->tx_rttvar;
+
+ if (hc->tx_rto > DCCP_RTO_MAX)
+ hc->tx_rto = DCCP_RTO_MAX;
}
-static inline void ccid2_new_ack(struct sock *sk,
- struct ccid2_seq *seqp,
- unsigned int *maxincr)
+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);
@@ -402,93 +400,27 @@ static inline void ccid2_new_ack(struct sock *sk,
hc->tx_cwnd += 1;
hc->tx_packets_acked = 0;
}
-
- /* update RTO */
- if (hc->tx_srtt == -1 ||
- time_after(jiffies, hc->tx_lastrtt + hc->tx_srtt)) {
- unsigned long r = (long)jiffies - (long)seqp->ccid2s_sent;
- int s;
-
- /* first measurement */
- if (hc->tx_srtt == -1) {
- ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n",
- r, jiffies,
- (unsigned long long)seqp->ccid2s_seq);
- ccid2_change_srtt(hc, r);
- hc->tx_rttvar = r >> 1;
- } else {
- /* RTTVAR */
- long tmp = hc->tx_srtt - r;
- long srtt;
-
- if (tmp < 0)
- tmp *= -1;
-
- tmp >>= 2;
- hc->tx_rttvar *= 3;
- hc->tx_rttvar >>= 2;
- hc->tx_rttvar += tmp;
-
- /* SRTT */
- srtt = hc->tx_srtt;
- srtt *= 7;
- srtt >>= 3;
- tmp = r >> 3;
- srtt += tmp;
- ccid2_change_srtt(hc, srtt);
- }
- s = hc->tx_rttvar << 2;
- /* clock granularity is 1 when based on jiffies */
- if (!s)
- s = 1;
- hc->tx_rto = hc->tx_srtt + s;
-
- /* must be at least a second */
- s = hc->tx_rto / HZ;
- /* DCCP doesn't require this [but I like it cuz my code sux] */
-#if 1
- if (s < 1)
- hc->tx_rto = HZ;
-#endif
- /* max 60 seconds */
- if (s > 60)
- hc->tx_rto = HZ * 60;
-
- hc->tx_lastrtt = jiffies;
-
- ccid2_pr_debug("srtt: %ld rttvar: %ld rto: %ld (HZ=%d) R=%lu\n",
- hc->tx_srtt, hc->tx_rttvar,
- hc->tx_rto, HZ, r);
- }
-
- /* we got a new ack, so re-start RTO timer */
- ccid2_hc_tx_kill_rto_timer(sk);
- ccid2_start_rto_timer(sk);
-}
-
-static void ccid2_hc_tx_dec_pipe(struct sock *sk)
-{
- struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
-
- if (hc->tx_pipe == 0)
- DCCP_BUG("pipe == 0");
- else
- hc->tx_pipe--;
-
- if (hc->tx_pipe == 0)
- ccid2_hc_tx_kill_rto_timer(sk);
+ /*
+ * FIXME: RTT is sampled several times per acknowledgment (for each
+ * entry in the Ack Vector), instead of once per Ack (as in TCP SACK).
+ * This causes the RTT to be over-estimated, since the older entries
+ * in the Ack Vector have earlier sending times.
+ * The cleanest solution is to not use the ccid2s_sent field at all
+ * and instead use DCCP timestamps: requires changes in other places.
+ */
+ ccid2_rtt_estimator(sk, ccid2_time_stamp - seqp->ccid2s_sent);
}
static void ccid2_congestion_event(struct sock *sk, struct ccid2_seq *seqp)
{
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- if (time_before(seqp->ccid2s_sent, hc->tx_last_cong)) {
+ if ((s32)(seqp->ccid2s_sent - hc->tx_last_cong) < 0) {
ccid2_pr_debug("Multiple losses in an RTT---treating as one\n");
return;
}
- hc->tx_last_cong = jiffies;
+ hc->tx_last_cong = ccid2_time_stamp;
hc->tx_cwnd = hc->tx_cwnd / 2 ? : 1U;
hc->tx_ssthresh = max(hc->tx_cwnd, 2U);
@@ -510,7 +442,6 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
int done = 0;
unsigned int maxincr = 0;
- ccid2_hc_tx_check_sanity(hc);
/* check reverse path congestion */
seqno = DCCP_SKB_CB(skb)->dccpd_seq;
@@ -620,7 +551,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
seqp->ccid2s_acked = 1;
ccid2_pr_debug("Got ack for %llu\n",
(unsigned long long)seqp->ccid2s_seq);
- ccid2_hc_tx_dec_pipe(sk);
+ hc->tx_pipe--;
}
if (seqp == hc->tx_seqt) {
done = 1;
@@ -677,7 +608,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
* one ack vector.
*/
ccid2_congestion_event(sk, seqp);
- ccid2_hc_tx_dec_pipe(sk);
+ hc->tx_pipe--;
}
if (seqp == hc->tx_seqt)
break;
@@ -695,7 +626,11 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
hc->tx_seqt = hc->tx_seqt->ccid2s_next;
}
- ccid2_hc_tx_check_sanity(hc);
+ /* restart RTO timer if not all outstanding data has been acked */
+ if (hc->tx_pipe == 0)
+ sk_stop_timer(sk, &hc->tx_rtotimer);
+ else
+ sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
}
static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
@@ -707,12 +642,8 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
/* RFC 4341, 5: initialise ssthresh to arbitrarily high (max) value */
hc->tx_ssthresh = ~0U;
- /*
- * RFC 4341, 5: "The cwnd parameter is initialized to at most four
- * packets for new connections, following the rules from [RFC3390]".
- * We need to convert the bytes of RFC3390 into the packets of RFC 4341.
- */
- hc->tx_cwnd = clamp(4380U / dp->dccps_mss_cache, 2U, 4U);
+ /* Use larger initial windows (RFC 4341, section 5). */
+ hc->tx_cwnd = rfc3390_bytes_to_packets(dp->dccps_mss_cache);
/* Make sure that Ack Ratio is enabled and within bounds. */
max_ratio = DIV_ROUND_UP(hc->tx_cwnd, 2);
@@ -723,15 +654,11 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
if (ccid2_hc_tx_alloc_seq(hc))
return -ENOMEM;
- hc->tx_rto = 3 * HZ;
- ccid2_change_srtt(hc, -1);
- hc->tx_rttvar = -1;
+ hc->tx_rto = DCCP_TIMEOUT_INIT;
hc->tx_rpdupack = -1;
- hc->tx_last_cong = jiffies;
+ hc->tx_last_cong = ccid2_time_stamp;
setup_timer(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire,
(unsigned long)sk);
-
- ccid2_hc_tx_check_sanity(hc);
return 0;
}
@@ -740,7 +667,7 @@ static void ccid2_hc_tx_exit(struct sock *sk)
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
int i;
- ccid2_hc_tx_kill_rto_timer(sk);
+ sk_stop_timer(sk, &hc->tx_rtotimer);
for (i = 0; i < hc->tx_seqbufc; i++)
kfree(hc->tx_seqbuf[i]);
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h
index 1ec6a30103bb..9731c2dc1487 100644
--- a/net/dccp/ccids/ccid2.h
+++ b/net/dccp/ccids/ccid2.h
@@ -18,18 +18,23 @@
#ifndef _DCCP_CCID2_H_
#define _DCCP_CCID2_H_
-#include <linux/dccp.h>
#include <linux/timer.h>
#include <linux/types.h>
#include "../ccid.h"
+#include "../dccp.h"
+
+/*
+ * CCID-2 timestamping faces the same issues as TCP timestamping.
+ * Hence we reuse/share as much of the code as possible.
+ */
+#define ccid2_time_stamp tcp_time_stamp
+
/* NUMDUPACK parameter from RFC 4341, p. 6 */
#define NUMDUPACK 3
-struct sock;
-
struct ccid2_seq {
u64 ccid2s_seq;
- unsigned long ccid2s_sent;
+ u32 ccid2s_sent;
int ccid2s_acked;
struct ccid2_seq *ccid2s_prev;
struct ccid2_seq *ccid2s_next;
@@ -42,7 +47,12 @@ struct ccid2_seq {
* struct ccid2_hc_tx_sock - CCID2 TX half connection
* @tx_{cwnd,ssthresh,pipe}: as per RFC 4341, section 5
* @tx_packets_acked: Ack counter for deriving cwnd growth (RFC 3465)
- * @tx_lastrtt: time RTT was last measured
+ * @tx_srtt: smoothed RTT estimate, scaled by 2^3
+ * @tx_mdev: smoothed RTT variation, scaled by 2^2
+ * @tx_mdev_max: maximum of @mdev during one flight
+ * @tx_rttvar: moving average/maximum of @mdev_max
+ * @tx_rto: RTO value deriving from SRTT and RTTVAR (RFC 2988)
+ * @tx_rtt_seq: to decay RTTVAR at most once per flight
* @tx_rpseq: last consecutive seqno
* @tx_rpdupack: dupacks since rpseq
*/
@@ -55,14 +65,19 @@ struct ccid2_hc_tx_sock {
int tx_seqbufc;
struct ccid2_seq *tx_seqh;
struct ccid2_seq *tx_seqt;
- long tx_rto;
- long tx_srtt;
- long tx_rttvar;
- unsigned long tx_lastrtt;
+
+ /* RTT measurement: variables/principles are the same as in TCP */
+ u32 tx_srtt,
+ tx_mdev,
+ tx_mdev_max,
+ tx_rttvar,
+ tx_rto;
+ u64 tx_rtt_seq:48;
struct timer_list tx_rtotimer;
+
u64 tx_rpseq;
int tx_rpdupack;
- unsigned long tx_last_cong;
+ u32 tx_last_cong;
u64 tx_high_ack;
};
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index 95f752986497..3060a60ed5ab 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -54,7 +54,6 @@ static const char *ccid3_tx_state_name(enum ccid3_hc_tx_states state)
[TFRC_SSTATE_NO_SENT] = "NO_SENT",
[TFRC_SSTATE_NO_FBACK] = "NO_FBACK",
[TFRC_SSTATE_FBACK] = "FBACK",
- [TFRC_SSTATE_TERM] = "TERM",
};
return ccid3_state_names[state];
@@ -91,19 +90,16 @@ static inline u64 rfc3390_initial_rate(struct sock *sk)
return scaled_div(w_init << 6, hc->tx_rtt);
}
-/*
- * Recalculate t_ipi and delta (should be called whenever X changes)
+/**
+ * ccid3_update_send_interval - Calculate new t_ipi = s / X_inst
+ * This respects the granularity of X_inst (64 * bytes/second).
*/
static void ccid3_update_send_interval(struct ccid3_hc_tx_sock *hc)
{
- /* Calculate new t_ipi = s / X_inst (X_inst is in 64 * bytes/second) */
hc->tx_t_ipi = scaled_div32(((u64)hc->tx_s) << 6, hc->tx_x);
- /* Calculate new delta by delta = min(t_ipi / 2, t_gran / 2) */
- hc->tx_delta = min_t(u32, hc->tx_t_ipi / 2, TFRC_OPSYS_HALF_TIME_GRAN);
-
- ccid3_pr_debug("t_ipi=%u, delta=%u, s=%u, X=%u\n", hc->tx_t_ipi,
- hc->tx_delta, hc->tx_s, (unsigned)(hc->tx_x >> 6));
+ ccid3_pr_debug("t_ipi=%u, s=%u, X=%u\n", hc->tx_t_ipi,
+ hc->tx_s, (unsigned)(hc->tx_x >> 6));
}
static u32 ccid3_hc_tx_idle_rtt(struct ccid3_hc_tx_sock *hc, ktime_t now)
@@ -211,16 +207,19 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
ccid3_pr_debug("%s(%p, state=%s) - entry\n", dccp_role(sk), sk,
ccid3_tx_state_name(hc->tx_state));
+ /* Ignore and do not restart after leaving the established state */
+ if ((1 << sk->sk_state) & ~(DCCPF_OPEN | DCCPF_PARTOPEN))
+ goto out;
+
+ /* Reset feedback state to "no feedback received" */
if (hc->tx_state == TFRC_SSTATE_FBACK)
ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);
- else if (hc->tx_state != TFRC_SSTATE_NO_FBACK)
- goto out;
/*
* Determine new allowed sending rate X as per draft rfc3448bis-00, 4.4
+ * RTO is 0 if and only if no feedback has been received yet.
*/
- if (hc->tx_t_rto == 0 || /* no feedback received yet */
- hc->tx_p == 0) {
+ if (hc->tx_t_rto == 0 || hc->tx_p == 0) {
/* halve send rate directly */
hc->tx_x = max(hc->tx_x / 2,
@@ -256,7 +255,7 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
* Set new timeout for the nofeedback timer.
* See comments in packet_recv() regarding the value of t_RTO.
*/
- if (unlikely(hc->tx_t_rto == 0)) /* no feedback yet */
+ if (unlikely(hc->tx_t_rto == 0)) /* no feedback received yet */
t_nfb = TFRC_INITIAL_TIMEOUT;
else
t_nfb = max(hc->tx_t_rto, 2 * hc->tx_t_ipi);
@@ -290,8 +289,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
if (unlikely(skb->len == 0))
return -EBADMSG;
- switch (hc->tx_state) {
- case TFRC_SSTATE_NO_SENT:
+ if (hc->tx_state == TFRC_SSTATE_NO_SENT) {
sk_reset_timer(sk, &hc->tx_no_feedback_timer, (jiffies +
usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)));
hc->tx_last_win_count = 0;
@@ -326,27 +324,22 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
ccid3_update_send_interval(hc);
ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);
- break;
- case TFRC_SSTATE_NO_FBACK:
- case TFRC_SSTATE_FBACK:
+
+ } else {
delay = ktime_us_delta(hc->tx_t_nom, now);
ccid3_pr_debug("delay=%ld\n", (long)delay);
/*
- * Scheduling of packet transmissions [RFC 3448, 4.6]
+ * Scheduling of packet transmissions (RFC 5348, 8.3)
*
* if (t_now > t_nom - delta)
* // send the packet now
* else
* // send the packet in (t_nom - t_now) milliseconds.
*/
- if (delay - (s64)hc->tx_delta >= 1000)
- return (u32)delay / 1000L;
+ if (delay >= TFRC_T_DELTA)
+ return (u32)delay / USEC_PER_MSEC;
ccid3_hc_tx_update_win_count(hc, now);
- break;
- case TFRC_SSTATE_TERM:
- DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk);
- return -EINVAL;
}
/* prepare to send now (add options etc.) */
@@ -358,8 +351,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
return 0;
}
-static void ccid3_hc_tx_packet_sent(struct sock *sk, int more,
- unsigned int len)
+static void ccid3_hc_tx_packet_sent(struct sock *sk, unsigned int len)
{
struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
@@ -372,48 +364,34 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more,
static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
- struct ccid3_options_received *opt_recv;
+ struct tfrc_tx_hist_entry *acked;
ktime_t now;
unsigned long t_nfb;
- u32 pinv, r_sample;
+ u32 r_sample;
/* we are only interested in ACKs */
if (!(DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_ACK ||
DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_DATAACK))
return;
- /* ... and only in the established state */
- if (hc->tx_state != TFRC_SSTATE_FBACK &&
- hc->tx_state != TFRC_SSTATE_NO_FBACK)
- return;
-
- opt_recv = &hc->tx_options_received;
- now = ktime_get_real();
-
- /* Estimate RTT from history if ACK number is valid */
- r_sample = tfrc_tx_hist_rtt(hc->tx_hist,
- DCCP_SKB_CB(skb)->dccpd_ack_seq, now);
- if (r_sample == 0) {
- DCCP_WARN("%s(%p): %s with bogus ACK-%llu\n", dccp_role(sk), sk,
- dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type),
- (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq);
- return;
- }
-
- /* Update receive rate in units of 64 * bytes/second */
- hc->tx_x_recv = opt_recv->ccid3or_receive_rate;
- hc->tx_x_recv <<= 6;
-
- /* Update loss event rate (which is scaled by 1e6) */
- pinv = opt_recv->ccid3or_loss_event_rate;
- if (pinv == ~0U || pinv == 0) /* see RFC 4342, 8.5 */
- hc->tx_p = 0;
- else /* can not exceed 100% */
- hc->tx_p = scaled_div(1, pinv);
/*
- * Validate new RTT sample and update moving average
+ * Locate the acknowledged packet in the TX history.
+ *
+ * Returning "entry not found" here can for instance happen when
+ * - the host has not sent out anything (e.g. a passive server),
+ * - the Ack is outdated (packet with higher Ack number was received),
+ * - it is a bogus Ack (for a packet not sent on this connection).
*/
- r_sample = dccp_sample_rtt(sk, r_sample);
+ acked = tfrc_tx_hist_find_entry(hc->tx_hist, dccp_hdr_ack_seq(skb));
+ if (acked == NULL)
+ return;
+ /* For the sake of RTT sampling, ignore/remove all older entries */
+ tfrc_tx_hist_purge(&acked->next);
+
+ /* Update the moving average for the RTT estimate (RFC 3448, 4.3) */
+ now = ktime_get_real();
+ r_sample = dccp_sample_rtt(sk, ktime_us_delta(now, acked->stamp));
hc->tx_rtt = tfrc_ewma(hc->tx_rtt, r_sample, 9);
+
/*
* Update allowed sending rate X as per draft rfc3448bis-00, 4.2/3
*/
@@ -461,13 +439,12 @@ done_computing_x:
sk->sk_write_space(sk);
/*
- * Update timeout interval for the nofeedback timer.
- * We use a configuration option to increase the lower bound.
- * This can help avoid triggering the nofeedback timer too
- * often ('spinning') on LANs with small RTTs.
+ * Update timeout interval for the nofeedback timer. In order to control
+ * rate halving on networks with very low RTTs (<= 1 ms), use per-route
+ * tunable RTAX_RTO_MIN value as the lower bound.
*/
- hc->tx_t_rto = max_t(u32, 4 * hc->tx_rtt, (CONFIG_IP_DCCP_CCID3_RTO *
- (USEC_PER_SEC / 1000)));
+ hc->tx_t_rto = max_t(u32, 4 * hc->tx_rtt,
+ USEC_PER_SEC/HZ * tcp_rto_min(sk));
/*
* Schedule no feedback timer to expire in
* max(t_RTO, 2 * s/X) = max(t_RTO, 2 * t_ipi)
@@ -482,66 +459,41 @@ done_computing_x:
jiffies + usecs_to_jiffies(t_nfb));
}
-static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
- unsigned char len, u16 idx,
- unsigned char *value)
+static int ccid3_hc_tx_parse_options(struct sock *sk, u8 packet_type,
+ u8 option, u8 *optval, u8 optlen)
{
- int rc = 0;
- const struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
- struct ccid3_options_received *opt_recv;
__be32 opt_val;
- opt_recv = &hc->tx_options_received;
-
- if (opt_recv->ccid3or_seqno != dp->dccps_gsr) {
- opt_recv->ccid3or_seqno = dp->dccps_gsr;
- opt_recv->ccid3or_loss_event_rate = ~0;
- opt_recv->ccid3or_loss_intervals_idx = 0;
- opt_recv->ccid3or_loss_intervals_len = 0;
- opt_recv->ccid3or_receive_rate = 0;
- }
-
switch (option) {
+ case TFRC_OPT_RECEIVE_RATE:
case TFRC_OPT_LOSS_EVENT_RATE:
- if (unlikely(len != 4)) {
- DCCP_WARN("%s(%p), invalid len %d "
- "for TFRC_OPT_LOSS_EVENT_RATE\n",
- dccp_role(sk), sk, len);
- rc = -EINVAL;
- } else {
- opt_val = get_unaligned((__be32 *)value);
- opt_recv->ccid3or_loss_event_rate = ntohl(opt_val);
- ccid3_pr_debug("%s(%p), LOSS_EVENT_RATE=%u\n",
- dccp_role(sk), sk,
- opt_recv->ccid3or_loss_event_rate);
+ /* Must be ignored on Data packets, cf. RFC 4342 8.3 and 8.5 */
+ if (packet_type == DCCP_PKT_DATA)
+ break;
+ if (unlikely(optlen != 4)) {
+ DCCP_WARN("%s(%p), invalid len %d for %u\n",
+ dccp_role(sk), sk, optlen, option);
+ return -EINVAL;
}
- break;
- case TFRC_OPT_LOSS_INTERVALS:
- opt_recv->ccid3or_loss_intervals_idx = idx;
- opt_recv->ccid3or_loss_intervals_len = len;
- ccid3_pr_debug("%s(%p), LOSS_INTERVALS=(%u, %u)\n",
- dccp_role(sk), sk,
- opt_recv->ccid3or_loss_intervals_idx,
- opt_recv->ccid3or_loss_intervals_len);
- break;
- case TFRC_OPT_RECEIVE_RATE:
- if (unlikely(len != 4)) {
- DCCP_WARN("%s(%p), invalid len %d "
- "for TFRC_OPT_RECEIVE_RATE\n",
- dccp_role(sk), sk, len);
- rc = -EINVAL;
- } else {
- opt_val = get_unaligned((__be32 *)value);
- opt_recv->ccid3or_receive_rate = ntohl(opt_val);
+ opt_val = ntohl(get_unaligned((__be32 *)optval));
+
+ if (option == TFRC_OPT_RECEIVE_RATE) {
+ /* Receive Rate is kept in units of 64 bytes/second */
+ hc->tx_x_recv = opt_val;
+ hc->tx_x_recv <<= 6;
+
ccid3_pr_debug("%s(%p), RECEIVE_RATE=%u\n",
- dccp_role(sk), sk,
- opt_recv->ccid3or_receive_rate);
+ dccp_role(sk), sk, opt_val);
+ } else {
+ /* Update the fixpoint Loss Event Rate fraction */
+ hc->tx_p = tfrc_invert_loss_event_rate(opt_val);
+
+ ccid3_pr_debug("%s(%p), LOSS_EVENT_RATE=%u\n",
+ dccp_role(sk), sk, opt_val);
}
- break;
}
-
- return rc;
+ return 0;
}
static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk)
@@ -559,42 +511,36 @@ static void ccid3_hc_tx_exit(struct sock *sk)
{
struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
- ccid3_hc_tx_set_state(sk, TFRC_SSTATE_TERM);
sk_stop_timer(sk, &hc->tx_no_feedback_timer);
-
tfrc_tx_hist_purge(&hc->tx_hist);
}
static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
{
- struct ccid3_hc_tx_sock *hc;
-
- /* Listen socks doesn't have a private CCID block */
- if (sk->sk_state == DCCP_LISTEN)
- return;
-
- hc = ccid3_hc_tx_sk(sk);
- info->tcpi_rto = hc->tx_t_rto;
- info->tcpi_rtt = hc->tx_rtt;
+ info->tcpi_rto = ccid3_hc_tx_sk(sk)->tx_t_rto;
+ info->tcpi_rtt = ccid3_hc_tx_sk(sk)->tx_rtt;
}
static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
u32 __user *optval, int __user *optlen)
{
- const struct ccid3_hc_tx_sock *hc;
+ const struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
+ struct tfrc_tx_info tfrc;
const void *val;
- /* Listen socks doesn't have a private CCID block */
- if (sk->sk_state == DCCP_LISTEN)
- return -EINVAL;
-
- hc = ccid3_hc_tx_sk(sk);
switch (optname) {
case DCCP_SOCKOPT_CCID_TX_INFO:
- if (len < sizeof(hc->tx_tfrc))
+ if (len < sizeof(tfrc))
return -EINVAL;
- len = sizeof(hc->tx_tfrc);
- val = &hc->tx_tfrc;
+ tfrc.tfrctx_x = hc->tx_x;
+ tfrc.tfrctx_x_recv = hc->tx_x_recv;
+ tfrc.tfrctx_x_calc = hc->tx_x_calc;
+ tfrc.tfrctx_rtt = hc->tx_rtt;
+ tfrc.tfrctx_p = hc->tx_p;
+ tfrc.tfrctx_rto = hc->tx_t_rto;
+ tfrc.tfrctx_ipi = hc->tx_t_ipi;
+ len = sizeof(tfrc);
+ val = &tfrc;
break;
default:
return -ENOPROTOOPT;
@@ -624,7 +570,6 @@ static const char *ccid3_rx_state_name(enum ccid3_hc_rx_states state)
static const char *const ccid3_rx_state_names[] = {
[TFRC_RSTATE_NO_DATA] = "NO_DATA",
[TFRC_RSTATE_DATA] = "DATA",
- [TFRC_RSTATE_TERM] = "TERM",
};
return ccid3_rx_state_names[state];
@@ -650,14 +595,9 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk,
{
struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
struct dccp_sock *dp = dccp_sk(sk);
- ktime_t now;
+ ktime_t now = ktime_get_real();
s64 delta = 0;
- if (unlikely(hc->rx_state == TFRC_RSTATE_TERM))
- return;
-
- now = ktime_get_real();
-
switch (fbtype) {
case CCID3_FBACK_INITIAL:
hc->rx_x_recv = 0;
@@ -701,14 +641,12 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk,
static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
{
- const struct ccid3_hc_rx_sock *hc;
+ const struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
__be32 x_recv, pinv;
if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN))
return 0;
- hc = ccid3_hc_rx_sk(sk);
-
if (dccp_packet_without_ack(skb))
return 0;
@@ -749,10 +687,11 @@ static u32 ccid3_first_li(struct sock *sk)
x_recv = scaled_div32(hc->rx_bytes_recv, delta);
if (x_recv == 0) { /* would also trigger divide-by-zero */
DCCP_WARN("X_recv==0\n");
- if ((x_recv = hc->rx_x_recv) == 0) {
+ if (hc->rx_x_recv == 0) {
DCCP_BUG("stored value of X_recv is zero");
return ~0U;
}
+ x_recv = hc->rx_x_recv;
}
fval = scaled_div(hc->rx_s, hc->rx_rtt);
@@ -862,46 +801,31 @@ static void ccid3_hc_rx_exit(struct sock *sk)
{
struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
- ccid3_hc_rx_set_state(sk, TFRC_RSTATE_TERM);
-
tfrc_rx_hist_purge(&hc->rx_hist);
tfrc_lh_cleanup(&hc->rx_li_hist);
}
static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
{
- const struct ccid3_hc_rx_sock *hc;
-
- /* Listen socks doesn't have a private CCID block */
- if (sk->sk_state == DCCP_LISTEN)
- return;
-
- hc = ccid3_hc_rx_sk(sk);
- info->tcpi_ca_state = hc->rx_state;
+ info->tcpi_ca_state = ccid3_hc_rx_sk(sk)->rx_state;
info->tcpi_options |= TCPI_OPT_TIMESTAMPS;
- info->tcpi_rcv_rtt = hc->rx_rtt;
+ info->tcpi_rcv_rtt = ccid3_hc_rx_sk(sk)->rx_rtt;
}
static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len,
u32 __user *optval, int __user *optlen)
{
- const struct ccid3_hc_rx_sock *hc;
+ const struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
struct tfrc_rx_info rx_info;
const void *val;
- /* Listen socks doesn't have a private CCID block */
- if (sk->sk_state == DCCP_LISTEN)
- return -EINVAL;
-
- hc = ccid3_hc_rx_sk(sk);
switch (optname) {
case DCCP_SOCKOPT_CCID_RX_INFO:
if (len < sizeof(rx_info))
return -EINVAL;
rx_info.tfrcrx_x_recv = hc->rx_x_recv;
rx_info.tfrcrx_rtt = hc->rx_rtt;
- rx_info.tfrcrx_p = hc->rx_pinv == 0 ? ~0U :
- scaled_div(1, hc->rx_pinv);
+ rx_info.tfrcrx_p = tfrc_invert_loss_event_rate(hc->rx_pinv);
len = sizeof(rx_info);
val = &rx_info;
break;
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h
index 032635776653..1a9933c29672 100644
--- a/net/dccp/ccids/ccid3.h
+++ b/net/dccp/ccids/ccid3.h
@@ -42,35 +42,36 @@
#include "lib/tfrc.h"
#include "../ccid.h"
-/* Two seconds as per RFC 3448 4.2 */
+/* Two seconds as per RFC 5348, 4.2 */
#define TFRC_INITIAL_TIMEOUT (2 * USEC_PER_SEC)
-/* In usecs - half the scheduling granularity as per RFC3448 4.6 */
-#define TFRC_OPSYS_HALF_TIME_GRAN (USEC_PER_SEC / (2 * HZ))
-
/* Parameter t_mbi from [RFC 3448, 4.3]: backoff interval in seconds */
#define TFRC_T_MBI 64
+/*
+ * The t_delta parameter (RFC 5348, 8.3): delays of less than %USEC_PER_MSEC are
+ * rounded down to 0, since sk_reset_timer() here uses millisecond granularity.
+ * Hence we can use a constant t_delta = %USEC_PER_MSEC when HZ >= 500. A coarse
+ * resolution of HZ < 500 means that the error is below one timer tick (t_gran)
+ * when using the constant t_delta = t_gran / 2 = %USEC_PER_SEC / (2 * HZ).
+ */
+#if (HZ >= 500)
+# define TFRC_T_DELTA USEC_PER_MSEC
+#else
+# define TFRC_T_DELTA (USEC_PER_SEC / (2 * HZ))
+#endif
+
enum ccid3_options {
TFRC_OPT_LOSS_EVENT_RATE = 192,
TFRC_OPT_LOSS_INTERVALS = 193,
TFRC_OPT_RECEIVE_RATE = 194,
};
-struct ccid3_options_received {
- u64 ccid3or_seqno:48,
- ccid3or_loss_intervals_idx:16;
- u16 ccid3or_loss_intervals_len;
- u32 ccid3or_loss_event_rate;
- u32 ccid3or_receive_rate;
-};
-
/* TFRC sender states */
enum ccid3_hc_tx_states {
TFRC_SSTATE_NO_SENT = 1,
TFRC_SSTATE_NO_FBACK,
TFRC_SSTATE_FBACK,
- TFRC_SSTATE_TERM,
};
/**
@@ -90,19 +91,16 @@ enum ccid3_hc_tx_states {
* @tx_no_feedback_timer: Handle to no feedback timer
* @tx_t_ld: Time last doubled during slow start
* @tx_t_nom: Nominal send time of next packet
- * @tx_delta: Send timer delta (RFC 3448, 4.6) in usecs
* @tx_hist: Packet history
- * @tx_options_received: Parsed set of retrieved options
*/
struct ccid3_hc_tx_sock {
- struct tfrc_tx_info tx_tfrc;
-#define tx_x tx_tfrc.tfrctx_x
-#define tx_x_recv tx_tfrc.tfrctx_x_recv
-#define tx_x_calc tx_tfrc.tfrctx_x_calc
-#define tx_rtt tx_tfrc.tfrctx_rtt
-#define tx_p tx_tfrc.tfrctx_p
-#define tx_t_rto tx_tfrc.tfrctx_rto
-#define tx_t_ipi tx_tfrc.tfrctx_ipi
+ u64 tx_x;
+ u64 tx_x_recv;
+ u32 tx_x_calc;
+ u32 tx_rtt;
+ u32 tx_p;
+ u32 tx_t_rto;
+ u32 tx_t_ipi;
u16 tx_s;
enum ccid3_hc_tx_states tx_state:8;
u8 tx_last_win_count;
@@ -110,9 +108,7 @@ struct ccid3_hc_tx_sock {
struct timer_list tx_no_feedback_timer;
ktime_t tx_t_ld;
ktime_t tx_t_nom;
- u32 tx_delta;
struct tfrc_tx_hist_entry *tx_hist;
- struct ccid3_options_received tx_options_received;
};
static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk)
@@ -126,21 +122,16 @@ static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk)
enum ccid3_hc_rx_states {
TFRC_RSTATE_NO_DATA = 1,
TFRC_RSTATE_DATA,
- TFRC_RSTATE_TERM = 127,
};
/**
* struct ccid3_hc_rx_sock - CCID3 receiver half-connection socket
- * @rx_x_recv: Receiver estimate of send rate (RFC 3448 4.3)
- * @rx_rtt: Receiver estimate of rtt (non-standard)
- * @rx_p: Current loss event rate (RFC 3448 5.4)
* @rx_last_counter: Tracks window counter (RFC 4342, 8.1)
* @rx_state: Receiver state, one of %ccid3_hc_rx_states
* @rx_bytes_recv: Total sum of DCCP payload bytes
* @rx_x_recv: Receiver estimate of send rate (RFC 3448, sec. 4.3)
* @rx_rtt: Receiver estimate of RTT
* @rx_tstamp_last_feedback: Time at which last feedback was sent
- * @rx_tstamp_last_ack: Time at which last feedback was sent
* @rx_hist: Packet history (loss detection + RTT sampling)
* @rx_li_hist: Loss Interval database
* @rx_s: Received packet size in bytes
diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c
index 8fc3cbf79071..497723c4d4bb 100644
--- a/net/dccp/ccids/lib/loss_interval.c
+++ b/net/dccp/ccids/lib/loss_interval.c
@@ -116,7 +116,7 @@ u8 tfrc_lh_update_i_mean(struct tfrc_loss_hist *lh, struct sk_buff *skb)
cur->li_length = len;
tfrc_lh_calc_i_mean(lh);
- return (lh->i_mean < old_i_mean);
+ return lh->i_mean < old_i_mean;
}
/* Determine if `new_loss' does begin a new loss interval [RFC 4342, 10.2] */
diff --git a/net/dccp/ccids/lib/packet_history.c b/net/dccp/ccids/lib/packet_history.c
index 3a4f414e94a0..de8fe294bf0b 100644
--- a/net/dccp/ccids/lib/packet_history.c
+++ b/net/dccp/ccids/lib/packet_history.c
@@ -38,18 +38,6 @@
#include "packet_history.h"
#include "../../dccp.h"
-/**
- * tfrc_tx_hist_entry - Simple singly-linked TX history list
- * @next: next oldest entry (LIFO order)
- * @seqno: sequence number of this entry
- * @stamp: send time of packet with sequence number @seqno
- */
-struct tfrc_tx_hist_entry {
- struct tfrc_tx_hist_entry *next;
- u64 seqno;
- ktime_t stamp;
-};
-
/*
* Transmitter History Routines
*/
@@ -71,15 +59,6 @@ void tfrc_tx_packet_history_exit(void)
}
}
-static struct tfrc_tx_hist_entry *
- tfrc_tx_hist_find_entry(struct tfrc_tx_hist_entry *head, u64 seqno)
-{
- while (head != NULL && head->seqno != seqno)
- head = head->next;
-
- return head;
-}
-
int tfrc_tx_hist_add(struct tfrc_tx_hist_entry **headp, u64 seqno)
{
struct tfrc_tx_hist_entry *entry = kmem_cache_alloc(tfrc_tx_hist_slab, gfp_any());
@@ -107,24 +86,6 @@ void tfrc_tx_hist_purge(struct tfrc_tx_hist_entry **headp)
*headp = NULL;
}
-u32 tfrc_tx_hist_rtt(struct tfrc_tx_hist_entry *head, const u64 seqno,
- const ktime_t now)
-{
- u32 rtt = 0;
- struct tfrc_tx_hist_entry *packet = tfrc_tx_hist_find_entry(head, seqno);
-
- if (packet != NULL) {
- rtt = ktime_us_delta(now, packet->stamp);
- /*
- * Garbage-collect older (irrelevant) entries:
- */
- tfrc_tx_hist_purge(&packet->next);
- }
-
- return rtt;
-}
-
-
/*
* Receiver History Routines
*/
diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h
index 7df6c5299999..7ee4a9d9d335 100644
--- a/net/dccp/ccids/lib/packet_history.h
+++ b/net/dccp/ccids/lib/packet_history.h
@@ -40,12 +40,28 @@
#include <linux/slab.h>
#include "tfrc.h"
-struct tfrc_tx_hist_entry;
+/**
+ * tfrc_tx_hist_entry - Simple singly-linked TX history list
+ * @next: next oldest entry (LIFO order)
+ * @seqno: sequence number of this entry
+ * @stamp: send time of packet with sequence number @seqno
+ */
+struct tfrc_tx_hist_entry {
+ struct tfrc_tx_hist_entry *next;
+ u64 seqno;
+ ktime_t stamp;
+};
+
+static inline struct tfrc_tx_hist_entry *
+ tfrc_tx_hist_find_entry(struct tfrc_tx_hist_entry *head, u64 seqno)
+{
+ while (head != NULL && head->seqno != seqno)
+ head = head->next;
+ return head;
+}
extern int tfrc_tx_hist_add(struct tfrc_tx_hist_entry **headp, u64 seqno);
extern void tfrc_tx_hist_purge(struct tfrc_tx_hist_entry **headp);
-extern u32 tfrc_tx_hist_rtt(struct tfrc_tx_hist_entry *head,
- const u64 seqno, const ktime_t now);
/* Subtraction a-b modulo-16, respects circular wrap-around */
#define SUB16(a, b) (((a) + 16 - (b)) & 0xF)
diff --git a/net/dccp/ccids/lib/tfrc.h b/net/dccp/ccids/lib/tfrc.h
index 01bb48e96c2e..f8ee3f549770 100644
--- a/net/dccp/ccids/lib/tfrc.h
+++ b/net/dccp/ccids/lib/tfrc.h
@@ -57,6 +57,7 @@ static inline u32 tfrc_ewma(const u32 avg, const u32 newval, const u8 weight)
extern u32 tfrc_calc_x(u16 s, u32 R, u32 p);
extern u32 tfrc_calc_x_reverse_lookup(u32 fvalue);
+extern u32 tfrc_invert_loss_event_rate(u32 loss_event_rate);
extern int tfrc_tx_packet_history_init(void);
extern void tfrc_tx_packet_history_exit(void);
diff --git a/net/dccp/ccids/lib/tfrc_equation.c b/net/dccp/ccids/lib/tfrc_equation.c
index 22ca1cf0eb55..a052a4377e26 100644
--- a/net/dccp/ccids/lib/tfrc_equation.c
+++ b/net/dccp/ccids/lib/tfrc_equation.c
@@ -687,3 +687,17 @@ u32 tfrc_calc_x_reverse_lookup(u32 fvalue)
index = tfrc_binsearch(fvalue, 0);
return (index + 1) * 1000000 / TFRC_CALC_X_ARRSIZE;
}
+
+/**
+ * tfrc_invert_loss_event_rate - Compute p so that 10^6 corresponds to 100%
+ * When @loss_event_rate is large, there is a chance that p is truncated to 0.
+ * To avoid re-entering slow-start in that case, we set p = TFRC_SMALLEST_P > 0.
+ */
+u32 tfrc_invert_loss_event_rate(u32 loss_event_rate)
+{
+ if (loss_event_rate == UINT_MAX) /* see RFC 4342, 8.5 */
+ return 0;
+ if (unlikely(loss_event_rate == 0)) /* map 1/0 into 100% */
+ return 1000000;
+ return max_t(u32, scaled_div(1, loss_event_rate), TFRC_SMALLEST_P);
+}
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index 3ccef1b70fee..3eb264b60823 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -153,18 +153,27 @@ static inline u64 max48(const u64 seq1, const u64 seq2)
}
/**
- * dccp_loss_free - Evaluates condition for data loss from RFC 4340, 7.7.1
- * @s1: start sequence number
- * @s2: end sequence number
+ * dccp_loss_count - Approximate the number of lost data packets in a burst loss
+ * @s1: last known sequence number before the loss ('hole')
+ * @s2: first sequence number seen after the 'hole'
* @ndp: NDP count on packet with sequence number @s2
- * Returns true if the sequence range s1...s2 has no data loss.
*/
-static inline bool dccp_loss_free(const u64 s1, const u64 s2, const u64 ndp)
+static inline u64 dccp_loss_count(const u64 s1, const u64 s2, const u64 ndp)
{
s64 delta = dccp_delta_seqno(s1, s2);
WARN_ON(delta < 0);
- return (u64)delta <= ndp + 1;
+ delta -= ndp + 1;
+
+ return delta > 0 ? delta : 0;
+}
+
+/**
+ * dccp_loss_free - Evaluate condition for data loss from RFC 4340, 7.7.1
+ */
+static inline bool dccp_loss_free(const u64 s1, const u64 s2, const u64 ndp)
+{
+ return dccp_loss_count(s1, s2, ndp) == 0;
}
enum {
@@ -246,7 +255,6 @@ static inline void dccp_clear_xmit_timers(struct sock *sk)
extern unsigned int dccp_sync_mss(struct sock *sk, u32 pmtu);
extern const char *dccp_packet_name(const int type);
-extern const char *dccp_state_name(const int state);
extern void dccp_set_state(struct sock *sk, const int state);
extern void dccp_done(struct sock *sk);
@@ -415,6 +423,23 @@ static inline void dccp_update_gsr(struct sock *sk, u64 seq)
dp->dccps_gsr = seq;
/* Sequence validity window depends on remote Sequence Window (7.5.1) */
dp->dccps_swl = SUB48(ADD48(dp->dccps_gsr, 1), dp->dccps_r_seq_win / 4);
+ /*
+ * Adjust SWL so that it is not below ISR. In contrast to RFC 4340,
+ * 7.5.1 we perform this check beyond the initial handshake: W/W' are
+ * always > 32, so for the first W/W' packets in the lifetime of a
+ * connection we always have to adjust SWL.
+ * A second reason why we are doing this is that the window depends on
+ * the feature-remote value of Sequence Window: nothing stops the peer
+ * from updating this value while we are busy adjusting SWL for the
+ * first W packets (we would have to count from scratch again then).
+ * Therefore it is safer to always make sure that the Sequence Window
+ * is not artificially extended by a peer who grows SWL downwards by
+ * continually updating the feature-remote Sequence-Window.
+ * If sequence numbers wrap it is bad luck. But that will take a while
+ * (48 bit), and this measure prevents Sequence-number attacks.
+ */
+ if (before48(dp->dccps_swl, dp->dccps_isr))
+ dp->dccps_swl = dp->dccps_isr;
dp->dccps_swh = ADD48(dp->dccps_gsr, (3 * dp->dccps_r_seq_win) / 4);
}
@@ -425,14 +450,16 @@ static inline void dccp_update_gss(struct sock *sk, u64 seq)
dp->dccps_gss = seq;
/* Ack validity window depends on local Sequence Window value (7.5.1) */
dp->dccps_awl = SUB48(ADD48(dp->dccps_gss, 1), dp->dccps_l_seq_win);
+ /* Adjust AWL so that it is not below ISS - see comment above for SWL */
+ if (before48(dp->dccps_awl, dp->dccps_iss))
+ dp->dccps_awl = dp->dccps_iss;
dp->dccps_awh = dp->dccps_gss;
}
static inline int dccp_ack_pending(const struct sock *sk)
{
const struct dccp_sock *dp = dccp_sk(sk);
- return dp->dccps_timestamp_echo != 0 ||
- (dp->dccps_hc_rx_ackvec != NULL &&
+ return (dp->dccps_hc_rx_ackvec != NULL &&
dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) ||
inet_csk_ack_scheduled(sk);
}
@@ -449,7 +476,6 @@ extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*);
extern int dccp_insert_option_elapsed_time(struct sk_buff *skb, u32 elapsed);
extern u32 dccp_timestamp(void);
extern void dccp_timestamping_init(void);
-extern int dccp_insert_option_timestamp(struct sk_buff *skb);
extern int dccp_insert_option(struct sk_buff *skb, unsigned char option,
const void *value, unsigned char len);
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index df7dd26cf07e..568def952722 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -730,16 +730,6 @@ int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
0, list, len);
}
-/* Analogous to dccp_feat_register_sp(), but for non-negotiable values */
-int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val)
-{
- /* any changes must be registered before establishing the connection */
- if (sk->sk_state != DCCP_CLOSED)
- return -EISCONN;
- if (dccp_feat_type(feat) != FEAT_NN)
- return -EINVAL;
- return __feat_register_nn(&dccp_sk(sk)->dccps_featneg, feat, 0, val);
-}
/*
* Tracking features whose value depend on the choice of CCID
diff --git a/net/dccp/feat.h b/net/dccp/feat.h
index f96721619def..e56a4e5e634e 100644
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -111,7 +111,6 @@ extern int dccp_feat_init(struct sock *sk);
extern void dccp_feat_initialise_sysctls(void);
extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
u8 const *list, u8 len);
-extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
extern int dccp_feat_clone_list(struct list_head const *, struct list_head *);
diff --git a/net/dccp/input.c b/net/dccp/input.c
index 10c957a88f4f..265985370fa1 100644
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -259,7 +259,7 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb)
sysctl_dccp_sync_ratelimit)))
return 0;
- DCCP_WARN("DCCP: Step 6 failed for %s packet, "
+ DCCP_WARN("Step 6 failed for %s packet, "
"(LSWL(%llu) <= P.seqno(%llu) <= S.SWH(%llu)) and "
"(P.ackno %s or LAWL(%llu) <= P.ackno(%llu) <= S.AWH(%llu), "
"sending SYNC...\n", dccp_packet_name(dh->dccph_type),
@@ -441,20 +441,14 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
kfree_skb(sk->sk_send_head);
sk->sk_send_head = NULL;
- dp->dccps_isr = DCCP_SKB_CB(skb)->dccpd_seq;
- dccp_update_gsr(sk, dp->dccps_isr);
/*
- * SWL and AWL are initially adjusted so that they are not less than
- * the initial Sequence Numbers received and sent, respectively:
- * SWL := max(GSR + 1 - floor(W/4), ISR),
- * AWL := max(GSS - W' + 1, ISS).
- * These adjustments MUST be applied only at the beginning of the
- * connection.
- *
- * AWL was adjusted in dccp_v4_connect -acme
+ * Set ISR, GSR from packet. ISS was set in dccp_v{4,6}_connect
+ * and GSS in dccp_transmit_skb(). Setting AWL/AWH and SWL/SWH
+ * is done as part of activating the feature values below, since
+ * these settings depend on the local/remote Sequence Window
+ * features, which were undefined or not confirmed until now.
*/
- dccp_set_seqno(&dp->dccps_swl,
- max48(dp->dccps_swl, dp->dccps_isr));
+ dp->dccps_gsr = dp->dccps_isr = DCCP_SKB_CB(skb)->dccpd_seq;
dccp_sync_mss(sk, icsk->icsk_pmtu_cookie);
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index d4a166f0f391..3f69ea114829 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -392,7 +392,7 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb,
newsk = dccp_create_openreq_child(sk, req, skb);
if (newsk == NULL)
- goto exit;
+ goto exit_nonewsk;
sk_setup_caps(newsk, dst);
@@ -409,16 +409,20 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb,
dccp_sync_mss(newsk, dst_mtu(dst));
+ if (__inet_inherit_port(sk, newsk) < 0) {
+ sock_put(newsk);
+ goto exit;
+ }
__inet_hash_nolisten(newsk, NULL);
- __inet_inherit_port(sk, newsk);
return newsk;
exit_overflow:
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
+exit_nonewsk:
+ dst_release(dst);
exit:
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
- dst_release(dst);
return NULL;
}
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 6e3f32575df7..dca711df9b60 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -564,7 +564,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
newsk = dccp_create_openreq_child(sk, req, skb);
if (newsk == NULL)
- goto out;
+ goto out_nonewsk;
/*
* No need to charge this sock to the relevant IPv6 refcnt debug socks
@@ -632,18 +632,22 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
+ if (__inet_inherit_port(sk, newsk) < 0) {
+ sock_put(newsk);
+ goto out;
+ }
__inet6_hash(newsk, NULL);
- __inet_inherit_port(sk, newsk);
return newsk;
out_overflow:
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
+out_nonewsk:
+ dst_release(dst);
out:
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
if (opt != NULL && opt != np->opt)
sock_kfree_s(sk, opt, opt->tot_len);
- dst_release(dst);
return NULL;
}
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c
index 128b089d3aef..d7041a0963af 100644
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -121,30 +121,18 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
*
* Choose S.ISS (initial seqno) or set from Init Cookies
* Initialize S.GAR := S.ISS
- * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
- */
- newdp->dccps_gar = newdp->dccps_iss = dreq->dreq_iss;
- dccp_update_gss(newsk, dreq->dreq_iss);
-
- newdp->dccps_isr = dreq->dreq_isr;
- dccp_update_gsr(newsk, dreq->dreq_isr);
-
- /*
- * SWL and AWL are initially adjusted so that they are not less than
- * the initial Sequence Numbers received and sent, respectively:
- * SWL := max(GSR + 1 - floor(W/4), ISR),
- * AWL := max(GSS - W' + 1, ISS).
- * These adjustments MUST be applied only at the beginning of the
- * connection.
+ * Set S.ISR, S.GSR from packet (or Init Cookies)
+ *
+ * Setting AWL/AWH and SWL/SWH happens as part of the feature
+ * activation below, as these windows all depend on the local
+ * and remote Sequence Window feature values (7.5.2).
*/
- dccp_set_seqno(&newdp->dccps_swl,
- max48(newdp->dccps_swl, newdp->dccps_isr));
- dccp_set_seqno(&newdp->dccps_awl,
- max48(newdp->dccps_awl, newdp->dccps_iss));
+ newdp->dccps_gss = newdp->dccps_iss = dreq->dreq_iss;
+ newdp->dccps_gar = newdp->dccps_iss;
+ newdp->dccps_gsr = newdp->dccps_isr = dreq->dreq_isr;
/*
- * Activate features after initialising the sequence numbers,
- * since CCID initialisation may depend on GSS, ISR, ISS etc.
+ * Activate features: initialise CCIDs, sequence windows etc.
*/
if (dccp_feat_activate_values(newsk, &dreq->dreq_featneg)) {
/* It is still raw copy of parent, so invalidate
diff --git a/net/dccp/options.c b/net/dccp/options.c
index bfda087bd90d..cd3061813009 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -96,18 +96,11 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
}
/*
- * CCID-Specific Options (from RFC 4340, sec. 10.3):
- *
- * Option numbers 128 through 191 are for options sent from the
- * HC-Sender to the HC-Receiver; option numbers 192 through 255
- * are for options sent from the HC-Receiver to the HC-Sender.
- *
* CCID-specific options are ignored during connection setup, as
* negotiation may still be in progress (see RFC 4340, 10.3).
* The same applies to Ack Vectors, as these depend on the CCID.
- *
*/
- if (dreq != NULL && (opt >= 128 ||
+ if (dreq != NULL && (opt >= DCCPO_MIN_RX_CCID_SPECIFIC ||
opt == DCCPO_ACK_VECTOR_0 || opt == DCCPO_ACK_VECTOR_1))
goto ignore_option;
@@ -170,6 +163,8 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
dccp_role(sk), ntohl(opt_val),
(unsigned long long)
DCCP_SKB_CB(skb)->dccpd_ack_seq);
+ /* schedule an Ack in case this sender is quiescent */
+ inet_csk_schedule_ack(sk);
break;
case DCCPO_TIMESTAMP_ECHO:
if (len != 4 && len != 6 && len != 8)
@@ -226,23 +221,15 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
dccp_pr_debug("%s rx opt: ELAPSED_TIME=%d\n",
dccp_role(sk), elapsed_time);
break;
- case 128 ... 191: {
- const u16 idx = value - options;
-
+ case DCCPO_MIN_RX_CCID_SPECIFIC ... DCCPO_MAX_RX_CCID_SPECIFIC:
if (ccid_hc_rx_parse_options(dp->dccps_hc_rx_ccid, sk,
- opt, len, idx,
- value) != 0)
+ pkt_type, opt, value, len))
goto out_invalid_option;
- }
break;
- case 192 ... 255: {
- const u16 idx = value - options;
-
+ case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC:
if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk,
- opt, len, idx,
- value) != 0)
+ pkt_type, opt, value, len))
goto out_invalid_option;
- }
break;
default:
DCCP_CRIT("DCCP(%p): option %d(len=%d) not "
@@ -384,7 +371,7 @@ int dccp_insert_option_elapsed_time(struct sk_buff *skb, u32 elapsed_time)
EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time);
-int dccp_insert_option_timestamp(struct sk_buff *skb)
+static int dccp_insert_option_timestamp(struct sk_buff *skb)
{
__be32 now = htonl(dccp_timestamp());
/* yes this will overflow but that is the point as we want a
@@ -393,8 +380,6 @@ int dccp_insert_option_timestamp(struct sk_buff *skb)
return dccp_insert_option(skb, DCCPO_TIMESTAMP, &now, sizeof(now));
}
-EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp);
-
static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp,
struct dccp_request_sock *dreq,
struct sk_buff *skb)
diff --git a/net/dccp/output.c b/net/dccp/output.c
index aadbdb58758b..a988fe9ffcba 100644
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -304,7 +304,7 @@ void dccp_write_xmit(struct sock *sk, int block)
dcb->dccpd_type = DCCP_PKT_DATA;
err = dccp_transmit_skb(sk, skb);
- ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len);
+ ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, len);
if (err)
DCCP_BUG("err=%d after ccid_hc_tx_packet_sent",
err);
@@ -474,8 +474,9 @@ int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code)
/*
* Do all connect socket setups that can be done AF independent.
*/
-static inline void dccp_connect_init(struct sock *sk)
+int dccp_connect(struct sock *sk)
{
+ struct sk_buff *skb;
struct dccp_sock *dp = dccp_sk(sk);
struct dst_entry *dst = __sk_dst_get(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
@@ -485,22 +486,12 @@ static inline void dccp_connect_init(struct sock *sk)
dccp_sync_mss(sk, dst_mtu(dst));
- /* Initialise GAR as per 8.5; AWL/AWH are set in dccp_transmit_skb() */
- dp->dccps_gar = dp->dccps_iss;
-
- icsk->icsk_retransmits = 0;
-}
-
-int dccp_connect(struct sock *sk)
-{
- struct sk_buff *skb;
- struct inet_connection_sock *icsk = inet_csk(sk);
-
/* do not connect if feature negotiation setup fails */
if (dccp_feat_finalise_settings(dccp_sk(sk)))
return -EPROTO;
- dccp_connect_init(sk);
+ /* Initialise GAR as per 8.5; AWL/AWH are set in dccp_transmit_skb() */
+ dp->dccps_gar = dp->dccps_iss;
skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation);
if (unlikely(skb == NULL))
@@ -516,6 +507,7 @@ int dccp_connect(struct sock *sk)
DCCP_INC_STATS(DCCP_MIB_ACTIVEOPENS);
/* Timer for repeating the REQUEST until an answer. */
+ icsk->icsk_retransmits = 0;
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
icsk->icsk_rto, DCCP_RTO_MAX);
return 0;
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 096250d1323b..7e5fc04eb6d1 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -50,6 +50,30 @@ EXPORT_SYMBOL_GPL(dccp_hashinfo);
/* the maximum queue length for tx in packets. 0 is no limit */
int sysctl_dccp_tx_qlen __read_mostly = 5;
+#ifdef CONFIG_IP_DCCP_DEBUG
+static const char *dccp_state_name(const int state)
+{
+ static const char *const dccp_state_names[] = {
+ [DCCP_OPEN] = "OPEN",
+ [DCCP_REQUESTING] = "REQUESTING",
+ [DCCP_PARTOPEN] = "PARTOPEN",
+ [DCCP_LISTEN] = "LISTEN",
+ [DCCP_RESPOND] = "RESPOND",
+ [DCCP_CLOSING] = "CLOSING",
+ [DCCP_ACTIVE_CLOSEREQ] = "CLOSEREQ",
+ [DCCP_PASSIVE_CLOSE] = "PASSIVE_CLOSE",
+ [DCCP_PASSIVE_CLOSEREQ] = "PASSIVE_CLOSEREQ",
+ [DCCP_TIME_WAIT] = "TIME_WAIT",
+ [DCCP_CLOSED] = "CLOSED",
+ };
+
+ if (state >= DCCP_MAX_STATES)
+ return "INVALID STATE!";
+ else
+ return dccp_state_names[state];
+}
+#endif
+
void dccp_set_state(struct sock *sk, const int state)
{
const int oldstate = sk->sk_state;
@@ -146,30 +170,6 @@ const char *dccp_packet_name(const int type)
EXPORT_SYMBOL_GPL(dccp_packet_name);
-const char *dccp_state_name(const int state)
-{
- static const char *const dccp_state_names[] = {
- [DCCP_OPEN] = "OPEN",
- [DCCP_REQUESTING] = "REQUESTING",
- [DCCP_PARTOPEN] = "PARTOPEN",
- [DCCP_LISTEN] = "LISTEN",
- [DCCP_RESPOND] = "RESPOND",
- [DCCP_CLOSING] = "CLOSING",
- [DCCP_ACTIVE_CLOSEREQ] = "CLOSEREQ",
- [DCCP_PASSIVE_CLOSE] = "PASSIVE_CLOSE",
- [DCCP_PASSIVE_CLOSEREQ] = "PASSIVE_CLOSEREQ",
- [DCCP_TIME_WAIT] = "TIME_WAIT",
- [DCCP_CLOSED] = "CLOSED",
- };
-
- if (state >= DCCP_MAX_STATES)
- return "INVALID STATE!";
- else
- return dccp_state_names[state];
-}
-
-EXPORT_SYMBOL_GPL(dccp_state_name);
-
int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
{
struct dccp_sock *dp = dccp_sk(sk);
@@ -944,7 +944,7 @@ void dccp_close(struct sock *sk, long timeout)
if (data_was_unread) {
/* Unread data was tossed, send an appropriate Reset Code */
- DCCP_WARN("DCCP: ABORT -- %u bytes unread\n", data_was_unread);
+ DCCP_WARN("ABORT with %u bytes unread\n", data_was_unread);
dccp_send_reset(sk, DCCP_RESET_CODE_ABORTED);
dccp_set_state(sk, DCCP_CLOSED);
} else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
index 0363bb95cc7d..a085dbcf5c7f 100644
--- a/net/decnet/dn_neigh.c
+++ b/net/decnet/dn_neigh.c
@@ -48,7 +48,6 @@
#include <net/dn_neigh.h>
#include <net/dn_route.h>
-static u32 dn_neigh_hash(const void *pkey, const struct net_device *dev);
static int dn_neigh_construct(struct neighbour *);
static void dn_long_error_report(struct neighbour *, struct sk_buff *);
static void dn_short_error_report(struct neighbour *, struct sk_buff *);
@@ -93,6 +92,13 @@ static const struct neigh_ops dn_phase3_ops = {
.queue_xmit = dev_queue_xmit
};
+static u32 dn_neigh_hash(const void *pkey,
+ const struct net_device *dev,
+ __u32 hash_rnd)
+{
+ return jhash_2words(*(__u16 *)pkey, 0, hash_rnd);
+}
+
struct neigh_table dn_neigh_table = {
.family = PF_DECnet,
.entry_size = sizeof(struct dn_neigh),
@@ -122,11 +128,6 @@ struct neigh_table dn_neigh_table = {
.gc_thresh3 = 1024,
};
-static u32 dn_neigh_hash(const void *pkey, const struct net_device *dev)
-{
- return jhash_2words(*(__u16 *)pkey, 0, dn_neigh_table.hash_rnd);
-}
-
static int dn_neigh_construct(struct neighbour *neigh)
{
struct net_device *dev = neigh->dev;
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
index baeb1eaf011b..2ef115277bea 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -693,22 +693,22 @@ void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg)
aux = scp->accessdata.acc_userl;
*skb_put(skb, 1) = aux;
if (aux > 0)
- memcpy(skb_put(skb, aux), scp->accessdata.acc_user, aux);
+ memcpy(skb_put(skb, aux), scp->accessdata.acc_user, aux);
aux = scp->accessdata.acc_passl;
*skb_put(skb, 1) = aux;
if (aux > 0)
- memcpy(skb_put(skb, aux), scp->accessdata.acc_pass, aux);
+ memcpy(skb_put(skb, aux), scp->accessdata.acc_pass, aux);
aux = scp->accessdata.acc_accl;
*skb_put(skb, 1) = aux;
if (aux > 0)
- memcpy(skb_put(skb, aux), scp->accessdata.acc_acc, aux);
+ memcpy(skb_put(skb, aux), scp->accessdata.acc_acc, aux);
aux = (__u8)le16_to_cpu(scp->conndata_out.opt_optl);
*skb_put(skb, 1) = aux;
if (aux > 0)
- memcpy(skb_put(skb,aux), scp->conndata_out.opt_data, aux);
+ memcpy(skb_put(skb, aux), scp->conndata_out.opt_data, aux);
scp->persist = dn_nsp_persist(sk);
scp->persist_fxn = dn_nsp_retrans_conninit;
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 6585ea6d1182..df0f3e54ff8a 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -132,7 +132,6 @@ static struct dst_ops dn_dst_ops = {
.negative_advice = dn_dst_negative_advice,
.link_failure = dn_dst_link_failure,
.update_pmtu = dn_dst_update_pmtu,
- .entries = ATOMIC_INIT(0),
};
static __inline__ unsigned dn_hash(__le16 src, __le16 dst)
@@ -1758,6 +1757,7 @@ void __init dn_route_init(void)
dn_dst_ops.kmem_cachep =
kmem_cache_create("dn_dst_cache", sizeof(struct dn_route), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+ dst_entries_init(&dn_dst_ops);
setup_timer(&dn_route_timer, dn_dst_check_expire, 0);
dn_route_timer.expires = jiffies + decnet_dst_gc_interval * HZ;
add_timer(&dn_route_timer);
@@ -1816,5 +1816,6 @@ void __exit dn_route_cleanup(void)
dn_run_flush(0);
proc_net_remove(&init_net, "decnet_cache");
+ dst_entries_destroy(&dn_dst_ops);
}
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index dc54bd0d083b..f8c1ae4b41f0 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -392,7 +392,7 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
dev_queue_xmit(skb);
dev_put(dev);
mutex_unlock(&econet_mutex);
- return(len);
+ return len;
out_free:
kfree_skb(skb);
@@ -637,7 +637,7 @@ static int econet_create(struct net *net, struct socket *sock, int protocol,
eo->num = protocol;
econet_insert_socket(&econet_sklist, sk);
- return(0);
+ return 0;
out:
return err;
}
@@ -1009,7 +1009,6 @@ static int __init aun_udp_initialise(void)
struct sockaddr_in sin;
skb_queue_head_init(&aun_queue);
- spin_lock_init(&aun_queue_lock);
setup_timer(&ab_cleanup_timer, ab_cleanup, 0);
ab_cleanup_timer.expires = jiffies + (HZ*2);
add_timer(&ab_cleanup_timer);
@@ -1167,7 +1166,6 @@ static int __init econet_proto_init(void)
goto out;
sock_register(&econet_family_ops);
#ifdef CONFIG_ECONET_AUNUDP
- spin_lock_init(&aun_queue_lock);
aun_udp_initialise();
#endif
#ifdef CONFIG_ECONET_NATIVE
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 215c83986a9d..f00ef2f1d814 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -367,7 +367,7 @@ struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count)
EXPORT_SYMBOL(alloc_etherdev_mq);
static size_t _format_mac_addr(char *buf, int buflen,
- const unsigned char *addr, int len)
+ const unsigned char *addr, int len)
{
int i;
char *cp = buf;
@@ -376,7 +376,7 @@ static size_t _format_mac_addr(char *buf, int buflen,
cp += scnprintf(cp, buflen - (cp - buf), "%02x", addr[i]);
if (i == len - 1)
break;
- cp += strlcpy(cp, ":", buflen - (cp - buf));
+ cp += scnprintf(cp, buflen - (cp - buf), ":");
}
return cp - buf;
}
@@ -386,7 +386,7 @@ ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len)
size_t l;
l = _format_mac_addr(buf, PAGE_SIZE, addr, len);
- l += strlcpy(buf + l, "\n", PAGE_SIZE - l);
- return ((ssize_t) l);
+ l += scnprintf(buf + l, PAGE_SIZE - l, "\n");
+ return (ssize_t)l;
}
EXPORT_SYMBOL(sysfs_format_mac);
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 7cd7760144f7..9e95d7fb6d5a 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -84,7 +84,7 @@ config IP_FIB_TRIE
An experimental study of compression methods for dynamic tries
Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002.
- http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/
+ <http://www.csc.kth.se/~snilsson/software/dyntrie2/>
endchoice
@@ -215,9 +215,15 @@ config NET_IPIP
be inserted in and removed from the running kernel whenever you
want). Most people won't need this and can say N.
+config NET_IPGRE_DEMUX
+ tristate "IP: GRE demultiplexer"
+ help
+ This is helper module to demultiplex GRE packets on GRE version field criteria.
+ Required by ip_gre and pptp modules.
+
config NET_IPGRE
tristate "IP: GRE tunnels over IP"
- depends on IPV6 || IPV6=n
+ depends on (IPV6 || IPV6=n) && NET_IPGRE_DEMUX
help
Tunneling means encapsulating data of one protocol type within
another protocol and sending it over a channel that understands the
@@ -556,7 +562,7 @@ config TCP_CONG_VENO
distinguishing to circumvent the difficult judgment of the packet loss
type. TCP Veno cuts down less congestion window in response to random
loss packets.
- See http://www.ntu.edu.sg/home5/ZHOU0022/papers/CPFu03a.pdf
+ See <http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=1177186>
config TCP_CONG_YEAH
tristate "YeAH TCP"
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 80ff87ce43aa..4978d22f9a75 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
obj-$(CONFIG_IP_MROUTE) += ipmr.o
obj-$(CONFIG_NET_IPIP) += ipip.o
+obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o
obj-$(CONFIG_NET_IPGRE) += ip_gre.o
obj-$(CONFIG_SYN_COOKIES) += syncookies.o
obj-$(CONFIG_INET_AH) += ah4.o
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 6a1100c25a9f..f581f77d1097 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -227,18 +227,16 @@ EXPORT_SYMBOL(inet_ehash_secret);
/*
* inet_ehash_secret must be set exactly once
- * Instead of using a dedicated spinlock, we (ab)use inetsw_lock
*/
void build_ehash_secret(void)
{
u32 rnd;
+
do {
get_random_bytes(&rnd, sizeof(rnd));
} while (rnd == 0);
- spin_lock_bh(&inetsw_lock);
- if (!inet_ehash_secret)
- inet_ehash_secret = rnd;
- spin_unlock_bh(&inetsw_lock);
+
+ cmpxchg(&inet_ehash_secret, 0, rnd);
}
EXPORT_SYMBOL(build_ehash_secret);
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 96c1955b3e2f..d8e540c5b071 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -55,7 +55,7 @@
* Stuart Cheshire : Metricom and grat arp fixes
* *** FOR 2.1 clean this up ***
* Lawrence V. Stefani: (08/12/96) Added FDDI support.
- * Alan Cox : Took the AP1000 nasty FDDI hack and
+ * Alan Cox : Took the AP1000 nasty FDDI hack and
* folded into the mainstream FDDI code.
* Ack spit, Linus how did you allow that
* one in...
@@ -120,14 +120,14 @@ EXPORT_SYMBOL(clip_tbl_hook);
#endif
#include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/netfilter_arp.h>
/*
* Interface to generic neighbour cache.
*/
-static u32 arp_hash(const void *pkey, const struct net_device *dev);
+static u32 arp_hash(const void *pkey, const struct net_device *dev, __u32 rnd);
static int arp_constructor(struct neighbour *neigh);
static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb);
static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb);
@@ -161,7 +161,7 @@ static const struct neigh_ops arp_direct_ops = {
.queue_xmit = dev_queue_xmit,
};
-const struct neigh_ops arp_broken_ops = {
+static const struct neigh_ops arp_broken_ops = {
.family = AF_INET,
.solicit = arp_solicit,
.error_report = arp_error_report,
@@ -170,35 +170,34 @@ const struct neigh_ops arp_broken_ops = {
.hh_output = dev_queue_xmit,
.queue_xmit = dev_queue_xmit,
};
-EXPORT_SYMBOL(arp_broken_ops);
struct neigh_table arp_tbl = {
- .family = AF_INET,
- .entry_size = sizeof(struct neighbour) + 4,
- .key_len = 4,
- .hash = arp_hash,
- .constructor = arp_constructor,
- .proxy_redo = parp_redo,
- .id = "arp_cache",
- .parms = {
- .tbl = &arp_tbl,
- .base_reachable_time = 30 * HZ,
- .retrans_time = 1 * HZ,
- .gc_staletime = 60 * HZ,
- .reachable_time = 30 * HZ,
- .delay_probe_time = 5 * HZ,
- .queue_len = 3,
- .ucast_probes = 3,
- .mcast_probes = 3,
- .anycast_delay = 1 * HZ,
- .proxy_delay = (8 * HZ) / 10,
- .proxy_qlen = 64,
- .locktime = 1 * HZ,
+ .family = AF_INET,
+ .entry_size = sizeof(struct neighbour) + 4,
+ .key_len = 4,
+ .hash = arp_hash,
+ .constructor = arp_constructor,
+ .proxy_redo = parp_redo,
+ .id = "arp_cache",
+ .parms = {
+ .tbl = &arp_tbl,
+ .base_reachable_time = 30 * HZ,
+ .retrans_time = 1 * HZ,
+ .gc_staletime = 60 * HZ,
+ .reachable_time = 30 * HZ,
+ .delay_probe_time = 5 * HZ,
+ .queue_len = 3,
+ .ucast_probes = 3,
+ .mcast_probes = 3,
+ .anycast_delay = 1 * HZ,
+ .proxy_delay = (8 * HZ) / 10,
+ .proxy_qlen = 64,
+ .locktime = 1 * HZ,
},
- .gc_interval = 30 * HZ,
- .gc_thresh1 = 128,
- .gc_thresh2 = 512,
- .gc_thresh3 = 1024,
+ .gc_interval = 30 * HZ,
+ .gc_thresh1 = 128,
+ .gc_thresh2 = 512,
+ .gc_thresh3 = 1024,
};
EXPORT_SYMBOL(arp_tbl);
@@ -226,14 +225,16 @@ int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir)
}
-static u32 arp_hash(const void *pkey, const struct net_device *dev)
+static u32 arp_hash(const void *pkey,
+ const struct net_device *dev,
+ __u32 hash_rnd)
{
- return jhash_2words(*(u32 *)pkey, dev->ifindex, arp_tbl.hash_rnd);
+ return jhash_2words(*(u32 *)pkey, dev->ifindex, hash_rnd);
}
static int arp_constructor(struct neighbour *neigh)
{
- __be32 addr = *(__be32*)neigh->primary_key;
+ __be32 addr = *(__be32 *)neigh->primary_key;
struct net_device *dev = neigh->dev;
struct in_device *in_dev;
struct neigh_parms *parms;
@@ -296,16 +297,19 @@ static int arp_constructor(struct neighbour *neigh)
neigh->ops = &arp_broken_ops;
neigh->output = neigh->ops->output;
return 0;
+#else
+ break;
#endif
- ;}
+ }
#endif
if (neigh->type == RTN_MULTICAST) {
neigh->nud_state = NUD_NOARP;
arp_mc_map(addr, neigh->ha, dev, 1);
- } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
+ } else if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) {
neigh->nud_state = NUD_NOARP;
memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
- } else if (neigh->type == RTN_BROADCAST || dev->flags&IFF_POINTOPOINT) {
+ } else if (neigh->type == RTN_BROADCAST ||
+ (dev->flags & IFF_POINTOPOINT)) {
neigh->nud_state = NUD_NOARP;
memcpy(neigh->ha, dev->broadcast, dev->addr_len);
}
@@ -315,7 +319,7 @@ static int arp_constructor(struct neighbour *neigh)
else
neigh->ops = &arp_generic_ops;
- if (neigh->nud_state&NUD_VALID)
+ if (neigh->nud_state & NUD_VALID)
neigh->output = neigh->ops->connected_output;
else
neigh->output = neigh->ops->output;
@@ -334,7 +338,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
__be32 saddr = 0;
u8 *dst_ha = NULL;
struct net_device *dev = neigh->dev;
- __be32 target = *(__be32*)neigh->primary_key;
+ __be32 target = *(__be32 *)neigh->primary_key;
int probes = atomic_read(&neigh->probes);
struct in_device *in_dev;
@@ -347,7 +351,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
default:
case 0: /* By default announce any local IP */
- if (skb && inet_addr_type(dev_net(dev), ip_hdr(skb)->saddr) == RTN_LOCAL)
+ if (skb && inet_addr_type(dev_net(dev),
+ ip_hdr(skb)->saddr) == RTN_LOCAL)
saddr = ip_hdr(skb)->saddr;
break;
case 1: /* Restrict announcements of saddr in same subnet */
@@ -369,16 +374,21 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
if (!saddr)
saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
- if ((probes -= neigh->parms->ucast_probes) < 0) {
- if (!(neigh->nud_state&NUD_VALID))
- printk(KERN_DEBUG "trying to ucast probe in NUD_INVALID\n");
+ probes -= neigh->parms->ucast_probes;
+ if (probes < 0) {
+ if (!(neigh->nud_state & NUD_VALID))
+ printk(KERN_DEBUG
+ "trying to ucast probe in NUD_INVALID\n");
dst_ha = neigh->ha;
read_lock_bh(&neigh->lock);
- } else if ((probes -= neigh->parms->app_probes) < 0) {
+ } else {
+ probes -= neigh->parms->app_probes;
+ if (probes < 0) {
#ifdef CONFIG_ARPD
- neigh_app_ns(neigh);
+ neigh_app_ns(neigh);
#endif
- return;
+ return;
+ }
}
arp_send(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr,
@@ -451,7 +461,8 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
* is allowed to use this function, it is scheduled to be removed. --ANK
*/
-static int arp_set_predefined(int addr_hint, unsigned char * haddr, __be32 paddr, struct net_device * dev)
+static int arp_set_predefined(int addr_hint, unsigned char *haddr,
+ __be32 paddr, struct net_device *dev)
{
switch (addr_hint) {
case RTN_LOCAL:
@@ -483,17 +494,16 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb)
paddr = skb_rtable(skb)->rt_gateway;
- if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr, paddr, dev))
+ if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr,
+ paddr, dev))
return 0;
n = __neigh_lookup(&arp_tbl, &paddr, dev, 1);
if (n) {
n->used = jiffies;
- if (n->nud_state&NUD_VALID || neigh_event_send(n, skb) == 0) {
- read_lock_bh(&n->lock);
- memcpy(haddr, n->ha, dev->addr_len);
- read_unlock_bh(&n->lock);
+ if (n->nud_state & NUD_VALID || neigh_event_send(n, skb) == 0) {
+ neigh_ha_snapshot(haddr, n, dev);
neigh_release(n);
return 0;
}
@@ -515,13 +525,14 @@ int arp_bind_neighbour(struct dst_entry *dst)
return -EINVAL;
if (n == NULL) {
__be32 nexthop = ((struct rtable *)dst)->rt_gateway;
- if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))
+ if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
nexthop = 0;
n = __neigh_lookup_errno(
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
- dev->type == ARPHRD_ATM ? clip_tbl_hook :
+ dev->type == ARPHRD_ATM ?
+ clip_tbl_hook :
#endif
- &arp_tbl, &nexthop, dev);
+ &arp_tbl, &nexthop, dev);
if (IS_ERR(n))
return PTR_ERR(n);
dst->neighbour = n;
@@ -543,8 +554,8 @@ static inline int arp_fwd_proxy(struct in_device *in_dev,
if (!IN_DEV_PROXY_ARP(in_dev))
return 0;
-
- if ((imi = IN_DEV_MEDIUM_ID(in_dev)) == 0)
+ imi = IN_DEV_MEDIUM_ID(in_dev);
+ if (imi == 0)
return 1;
if (imi == -1)
return 0;
@@ -555,7 +566,7 @@ static inline int arp_fwd_proxy(struct in_device *in_dev,
if (out_dev)
omi = IN_DEV_MEDIUM_ID(out_dev);
- return (omi != imi && omi != -1);
+ return omi != imi && omi != -1;
}
/*
@@ -685,7 +696,7 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
arp->ar_pln = 4;
arp->ar_op = htons(type);
- arp_ptr=(unsigned char *)(arp+1);
+ arp_ptr = (unsigned char *)(arp + 1);
memcpy(arp_ptr, src_hw, dev->addr_len);
arp_ptr += dev->addr_len;
@@ -735,9 +746,8 @@ void arp_send(int type, int ptype, __be32 dest_ip,
skb = arp_create(type, ptype, dest_ip, dev, src_ip,
dest_hw, src_hw, target_hw);
- if (skb == NULL) {
+ if (skb == NULL)
return;
- }
arp_xmit(skb);
}
@@ -815,7 +825,7 @@ static int arp_process(struct sk_buff *skb)
/*
* Extract fields
*/
- arp_ptr= (unsigned char *)(arp+1);
+ arp_ptr = (unsigned char *)(arp + 1);
sha = arp_ptr;
arp_ptr += dev->addr_len;
memcpy(&sip, arp_ptr, 4);
@@ -869,16 +879,17 @@ static int arp_process(struct sk_buff *skb)
addr_type = rt->rt_type;
if (addr_type == RTN_LOCAL) {
- int dont_send = 0;
+ int dont_send;
- if (!dont_send)
- dont_send |= arp_ignore(in_dev,sip,tip);
+ dont_send = arp_ignore(in_dev, sip, tip);
if (!dont_send && IN_DEV_ARPFILTER(in_dev))
- dont_send |= arp_filter(sip,tip,dev);
+ dont_send |= arp_filter(sip, tip, dev);
if (!dont_send) {
n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
if (n) {
- arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
+ arp_send(ARPOP_REPLY, ETH_P_ARP, sip,
+ dev, tip, sha, dev->dev_addr,
+ sha);
neigh_release(n);
}
}
@@ -887,8 +898,7 @@ static int arp_process(struct sk_buff *skb)
if (addr_type == RTN_UNICAST &&
(arp_fwd_proxy(in_dev, dev, rt) ||
arp_fwd_pvlan(in_dev, dev, rt, sip, tip) ||
- pneigh_lookup(&arp_tbl, net, &tip, dev, 0)))
- {
+ pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) {
n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
if (n)
neigh_release(n);
@@ -896,9 +906,12 @@ static int arp_process(struct sk_buff *skb)
if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED ||
skb->pkt_type == PACKET_HOST ||
in_dev->arp_parms->proxy_delay == 0) {
- arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
+ arp_send(ARPOP_REPLY, ETH_P_ARP, sip,
+ dev, tip, sha, dev->dev_addr,
+ sha);
} else {
- pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb);
+ pneigh_enqueue(&arp_tbl,
+ in_dev->arp_parms, skb);
return 0;
}
goto out;
@@ -939,7 +952,8 @@ static int arp_process(struct sk_buff *skb)
if (arp->ar_op != htons(ARPOP_REPLY) ||
skb->pkt_type != PACKET_HOST)
state = NUD_STALE;
- neigh_update(n, sha, state, override ? NEIGH_UPDATE_F_OVERRIDE : 0);
+ neigh_update(n, sha, state,
+ override ? NEIGH_UPDATE_F_OVERRIDE : 0);
neigh_release(n);
}
@@ -975,7 +989,8 @@ static int arp_rcv(struct sk_buff *skb, struct net_device *dev,
arp->ar_pln != 4)
goto freeskb;
- if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (skb == NULL)
goto out_of_mem;
memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
@@ -1019,7 +1034,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
return -EINVAL;
if (!dev && (r->arp_flags & ATF_COM)) {
dev = dev_getbyhwaddr(net, r->arp_ha.sa_family,
- r->arp_ha.sa_data);
+ r->arp_ha.sa_data);
if (!dev)
return -ENODEV;
}
@@ -1033,7 +1048,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
}
static int arp_req_set(struct net *net, struct arpreq *r,
- struct net_device * dev)
+ struct net_device *dev)
{
__be32 ip;
struct neighbour *neigh;
@@ -1046,10 +1061,11 @@ static int arp_req_set(struct net *net, struct arpreq *r,
if (r->arp_flags & ATF_PERM)
r->arp_flags |= ATF_COM;
if (dev == NULL) {
- struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
- .tos = RTO_ONLINK } } };
- struct rtable * rt;
- if ((err = ip_route_output_key(net, &rt, &fl)) != 0)
+ struct flowi fl = { .nl_u.ip4_u = { .daddr = ip,
+ .tos = RTO_ONLINK } };
+ struct rtable *rt;
+ err = ip_route_output_key(net, &rt, &fl);
+ if (err != 0)
return err;
dev = rt->dst.dev;
ip_rt_put(rt);
@@ -1083,9 +1099,9 @@ static int arp_req_set(struct net *net, struct arpreq *r,
unsigned state = NUD_STALE;
if (r->arp_flags & ATF_PERM)
state = NUD_PERMANENT;
- err = neigh_update(neigh, (r->arp_flags&ATF_COM) ?
+ err = neigh_update(neigh, (r->arp_flags & ATF_COM) ?
r->arp_ha.sa_data : NULL, state,
- NEIGH_UPDATE_F_OVERRIDE|
+ NEIGH_UPDATE_F_OVERRIDE |
NEIGH_UPDATE_F_ADMIN);
neigh_release(neigh);
}
@@ -1094,12 +1110,12 @@ static int arp_req_set(struct net *net, struct arpreq *r,
static unsigned arp_state_to_flags(struct neighbour *neigh)
{
- unsigned flags = 0;
if (neigh->nud_state&NUD_PERMANENT)
- flags = ATF_PERM|ATF_COM;
+ return ATF_PERM | ATF_COM;
else if (neigh->nud_state&NUD_VALID)
- flags = ATF_COM;
- return flags;
+ return ATF_COM;
+ else
+ return 0;
}
/*
@@ -1142,7 +1158,7 @@ static int arp_req_delete_public(struct net *net, struct arpreq *r,
}
static int arp_req_delete(struct net *net, struct arpreq *r,
- struct net_device * dev)
+ struct net_device *dev)
{
int err;
__be32 ip;
@@ -1153,10 +1169,11 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
if (dev == NULL) {
- struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
- .tos = RTO_ONLINK } } };
- struct rtable * rt;
- if ((err = ip_route_output_key(net, &rt, &fl)) != 0)
+ struct flowi fl = { .nl_u.ip4_u = { .daddr = ip,
+ .tos = RTO_ONLINK } };
+ struct rtable *rt;
+ err = ip_route_output_key(net, &rt, &fl);
+ if (err != 0)
return err;
dev = rt->dst.dev;
ip_rt_put(rt);
@@ -1166,7 +1183,7 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
err = -ENXIO;
neigh = neigh_lookup(&arp_tbl, &ip, dev);
if (neigh) {
- if (neigh->nud_state&~NUD_NOARP)
+ if (neigh->nud_state & ~NUD_NOARP)
err = neigh_update(neigh, NULL, NUD_FAILED,
NEIGH_UPDATE_F_OVERRIDE|
NEIGH_UPDATE_F_ADMIN);
@@ -1186,24 +1203,24 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
struct net_device *dev = NULL;
switch (cmd) {
- case SIOCDARP:
- case SIOCSARP:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- case SIOCGARP:
- err = copy_from_user(&r, arg, sizeof(struct arpreq));
- if (err)
- return -EFAULT;
- break;
- default:
- return -EINVAL;
+ case SIOCDARP:
+ case SIOCSARP:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ case SIOCGARP:
+ err = copy_from_user(&r, arg, sizeof(struct arpreq));
+ if (err)
+ return -EFAULT;
+ break;
+ default:
+ return -EINVAL;
}
if (r.arp_pa.sa_family != AF_INET)
return -EPFNOSUPPORT;
if (!(r.arp_flags & ATF_PUBL) &&
- (r.arp_flags & (ATF_NETMASK|ATF_DONTPUB)))
+ (r.arp_flags & (ATF_NETMASK | ATF_DONTPUB)))
return -EINVAL;
if (!(r.arp_flags & ATF_NETMASK))
((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr =
@@ -1211,7 +1228,8 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
rtnl_lock();
if (r.arp_dev[0]) {
err = -ENODEV;
- if ((dev = __dev_get_by_name(net, r.arp_dev)) == NULL)
+ dev = __dev_get_by_name(net, r.arp_dev);
+ if (dev == NULL)
goto out;
/* Mmmm... It is wrong... ARPHRD_NETROM==0 */
@@ -1243,7 +1261,8 @@ out:
return err;
}
-static int arp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+static int arp_netdev_event(struct notifier_block *this, unsigned long event,
+ void *ptr)
{
struct net_device *dev = ptr;
@@ -1311,12 +1330,13 @@ static char *ax2asc2(ax25_address *a, char *buf)
for (n = 0, s = buf; n < 6; n++) {
c = (a->ax25_call[n] >> 1) & 0x7F;
- if (c != ' ') *s++ = c;
+ if (c != ' ')
+ *s++ = c;
}
*s++ = '-';
-
- if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) {
+ n = (a->ax25_call[6] >> 1) & 0x0F;
+ if (n > 9) {
*s++ = '1';
n -= 10;
}
@@ -1325,10 +1345,9 @@ static char *ax2asc2(ax25_address *a, char *buf)
*s++ = '\0';
if (*buf == '\0' || *buf == '-')
- return "*";
+ return "*";
return buf;
-
}
#endif /* CONFIG_AX25 */
@@ -1408,10 +1427,10 @@ static void *arp_seq_start(struct seq_file *seq, loff_t *pos)
/* ------------------------------------------------------------------------ */
static const struct seq_operations arp_seq_ops = {
- .start = arp_seq_start,
- .next = neigh_seq_next,
- .stop = neigh_seq_stop,
- .show = arp_seq_show,
+ .start = arp_seq_start,
+ .next = neigh_seq_next,
+ .stop = neigh_seq_stop,
+ .show = arp_seq_show,
};
static int arp_seq_open(struct inode *inode, struct file *file)
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 3a92a76ae41d..094e150c6260 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -9,7 +9,7 @@
*
* The CIPSO draft specification can be found in the kernel's Documentation
* directory as well as the following URL:
- * http://netlabel.sourceforge.net/files/draft-ietf-cipso-ipsecurity-01.txt
+ * http://tools.ietf.org/id/draft-ietf-cipso-ipsecurity-01.txt
* The FIPS-188 specification can be found at the following URL:
* http://www.itl.nist.gov/fipspubs/fip188.htm
*
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
index 721a8a37b45c..174be6caa5c8 100644
--- a/net/ipv4/datagram.c
+++ b/net/ipv4/datagram.c
@@ -73,6 +73,6 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
inet->inet_id = jiffies;
sk_dst_set(sk, &rt->dst);
- return(0);
+ return 0;
}
EXPORT_SYMBOL(ip4_datagram_connect);
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index da14c49284f4..dc94b0316b78 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -209,7 +209,7 @@ static void inetdev_destroy(struct in_device *in_dev)
inet_free_ifa(ifa);
}
- dev->ip_ptr = NULL;
+ rcu_assign_pointer(dev->ip_ptr, NULL);
devinet_sysctl_unregister(in_dev);
neigh_parms_release(&arp_tbl, in_dev->arp_parms);
@@ -403,6 +403,9 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
return inet_insert_ifa(ifa);
}
+/* Caller must hold RCU or RTNL :
+ * We dont take a reference on found in_device
+ */
struct in_device *inetdev_by_index(struct net *net, int ifindex)
{
struct net_device *dev;
@@ -411,7 +414,7 @@ struct in_device *inetdev_by_index(struct net *net, int ifindex)
rcu_read_lock();
dev = dev_get_by_index_rcu(net, ifindex);
if (dev)
- in_dev = in_dev_get(dev);
+ in_dev = rcu_dereference_rtnl(dev->ip_ptr);
rcu_read_unlock();
return in_dev;
}
@@ -453,8 +456,6 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg
goto errout;
}
- __in_dev_put(in_dev);
-
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
ifap = &ifa->ifa_next) {
if (tb[IFA_LOCAL] &&
@@ -1059,7 +1060,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
switch (event) {
case NETDEV_REGISTER:
printk(KERN_DEBUG "inetdev_event: bug\n");
- dev->ip_ptr = NULL;
+ rcu_assign_pointer(dev->ip_ptr, NULL);
break;
case NETDEV_UP:
if (!inetdev_valid_mtu(dev->mtu))
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 7d02a9f999fa..36e27c2107de 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -147,35 +147,43 @@ static void fib_flush(struct net *net)
rt_cache_flush(net, -1);
}
-/*
- * Find the first device with a given source address.
+/**
+ * __ip_dev_find - find the first device with a given source address.
+ * @net: the net namespace
+ * @addr: the source address
+ * @devref: if true, take a reference on the found device
+ *
+ * If a caller uses devref=false, it should be protected by RCU, or RTNL
*/
-
-struct net_device * ip_dev_find(struct net *net, __be32 addr)
+struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
{
- struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
- struct fib_result res;
+ struct flowi fl = {
+ .nl_u = {
+ .ip4_u = {
+ .daddr = addr
+ }
+ },
+ .flags = FLOWI_FLAG_MATCH_ANY_IIF
+ };
+ struct fib_result res = { 0 };
struct net_device *dev = NULL;
- struct fib_table *local_table;
-#ifdef CONFIG_IP_MULTIPLE_TABLES
- res.r = NULL;
-#endif
-
- local_table = fib_get_table(net, RT_TABLE_LOCAL);
- if (!local_table || fib_table_lookup(local_table, &fl, &res))
+ rcu_read_lock();
+ if (fib_lookup(net, &fl, &res)) {
+ rcu_read_unlock();
return NULL;
+ }
if (res.type != RTN_LOCAL)
goto out;
dev = FIB_RES_DEV(res);
- if (dev)
+ if (dev && devref)
dev_hold(dev);
out:
- fib_res_put(&res);
+ rcu_read_unlock();
return dev;
}
-EXPORT_SYMBOL(ip_dev_find);
+EXPORT_SYMBOL(__ip_dev_find);
/*
* Find address type as if only "dev" was present in the system. If
@@ -202,11 +210,12 @@ static inline unsigned __inet_dev_addr_type(struct net *net,
local_table = fib_get_table(net, RT_TABLE_LOCAL);
if (local_table) {
ret = RTN_UNICAST;
- if (!fib_table_lookup(local_table, &fl, &res)) {
+ rcu_read_lock();
+ if (!fib_table_lookup(local_table, &fl, &res, FIB_LOOKUP_NOREF)) {
if (!dev || dev == res.fi->fib_dev)
ret = res.type;
- fib_res_put(&res);
}
+ rcu_read_unlock();
}
return ret;
}
@@ -220,30 +229,34 @@ EXPORT_SYMBOL(inet_addr_type);
unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
__be32 addr)
{
- return __inet_dev_addr_type(net, dev, addr);
+ return __inet_dev_addr_type(net, dev, addr);
}
EXPORT_SYMBOL(inet_dev_addr_type);
/* Given (packet source, input interface) and optional (dst, oif, tos):
- - (main) check, that source is valid i.e. not broadcast or our local
- address.
- - figure out what "logical" interface this packet arrived
- and calculate "specific destination" address.
- - check, that packet arrived from expected physical interface.
+ * - (main) check, that source is valid i.e. not broadcast or our local
+ * address.
+ * - figure out what "logical" interface this packet arrived
+ * and calculate "specific destination" address.
+ * - check, that packet arrived from expected physical interface.
+ * called with rcu_read_lock()
*/
-
int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
struct net_device *dev, __be32 *spec_dst,
u32 *itag, u32 mark)
{
struct in_device *in_dev;
- struct flowi fl = { .nl_u = { .ip4_u =
- { .daddr = src,
- .saddr = dst,
- .tos = tos } },
- .mark = mark,
- .iif = oif };
-
+ struct flowi fl = {
+ .nl_u = {
+ .ip4_u = {
+ .daddr = src,
+ .saddr = dst,
+ .tos = tos
+ }
+ },
+ .mark = mark,
+ .iif = oif
+ };
struct fib_result res;
int no_addr, rpf, accept_local;
bool dev_match;
@@ -251,7 +264,6 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
struct net *net;
no_addr = rpf = accept_local = 0;
- rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
if (in_dev) {
no_addr = in_dev->ifa_list == NULL;
@@ -260,7 +272,6 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
if (mark && !IN_DEV_SRC_VMARK(in_dev))
fl.mark = 0;
}
- rcu_read_unlock();
if (in_dev == NULL)
goto e_inval;
@@ -270,7 +281,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
goto last_resort;
if (res.type != RTN_UNICAST) {
if (res.type != RTN_LOCAL || !accept_local)
- goto e_inval_res;
+ goto e_inval;
}
*spec_dst = FIB_RES_PREFSRC(res);
fib_combine_itag(itag, &res);
@@ -291,10 +302,8 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
#endif
if (dev_match) {
ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
- fib_res_put(&res);
return ret;
}
- fib_res_put(&res);
if (no_addr)
goto last_resort;
if (rpf == 1)
@@ -307,7 +316,6 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
*spec_dst = FIB_RES_PREFSRC(res);
ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
}
- fib_res_put(&res);
}
return ret;
@@ -318,8 +326,6 @@ last_resort:
*itag = 0;
return 0;
-e_inval_res:
- fib_res_put(&res);
e_inval:
return -EINVAL;
e_rpf:
@@ -472,9 +478,9 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
}
/*
- * Handle IP routing ioctl calls. These are used to manipulate the routing tables
+ * Handle IP routing ioctl calls.
+ * These are used to manipulate the routing tables
*/
-
int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg)
{
struct fib_config cfg;
@@ -518,7 +524,7 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg)
return -EINVAL;
}
-const struct nla_policy rtm_ipv4_policy[RTA_MAX+1] = {
+const struct nla_policy rtm_ipv4_policy[RTA_MAX + 1] = {
[RTA_DST] = { .type = NLA_U32 },
[RTA_SRC] = { .type = NLA_U32 },
[RTA_IIF] = { .type = NLA_U32 },
@@ -532,7 +538,7 @@ const struct nla_policy rtm_ipv4_policy[RTA_MAX+1] = {
};
static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct fib_config *cfg)
+ struct nlmsghdr *nlh, struct fib_config *cfg)
{
struct nlattr *attr;
int err, remaining;
@@ -687,12 +693,11 @@ out:
}
/* Prepare and feed intra-kernel routing request.
- Really, it should be netlink message, but :-( netlink
- can be not configured, so that we feed it directly
- to fib engine. It is legal, because all events occur
- only when netlink is already locked.
+ * Really, it should be netlink message, but :-( netlink
+ * can be not configured, so that we feed it directly
+ * to fib engine. It is legal, because all events occur
+ * only when netlink is already locked.
*/
-
static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa)
{
struct net *net = dev_net(ifa->ifa_dev->dev);
@@ -738,9 +743,9 @@ void fib_add_ifaddr(struct in_ifaddr *ifa)
struct in_ifaddr *prim = ifa;
__be32 mask = ifa->ifa_mask;
__be32 addr = ifa->ifa_local;
- __be32 prefix = ifa->ifa_address&mask;
+ __be32 prefix = ifa->ifa_address & mask;
- if (ifa->ifa_flags&IFA_F_SECONDARY) {
+ if (ifa->ifa_flags & IFA_F_SECONDARY) {
prim = inet_ifa_byprefix(in_dev, prefix, mask);
if (prim == NULL) {
printk(KERN_WARNING "fib_add_ifaddr: bug: prim == NULL\n");
@@ -750,22 +755,24 @@ void fib_add_ifaddr(struct in_ifaddr *ifa)
fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim);
- if (!(dev->flags&IFF_UP))
+ if (!(dev->flags & IFF_UP))
return;
/* Add broadcast address, if it is explicitly assigned. */
if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF))
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
- if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) &&
+ if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) &&
(prefix != addr || ifa->ifa_prefixlen < 32)) {
- fib_magic(RTM_NEWROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
- RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim);
+ fib_magic(RTM_NEWROUTE,
+ dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,
+ prefix, ifa->ifa_prefixlen, prim);
/* Add network specific broadcasts, when it takes a sense */
if (ifa->ifa_prefixlen < 31) {
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim);
- fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix|~mask, 32, prim);
+ fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix | ~mask,
+ 32, prim);
}
}
}
@@ -776,17 +783,18 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
struct net_device *dev = in_dev->dev;
struct in_ifaddr *ifa1;
struct in_ifaddr *prim = ifa;
- __be32 brd = ifa->ifa_address|~ifa->ifa_mask;
- __be32 any = ifa->ifa_address&ifa->ifa_mask;
+ __be32 brd = ifa->ifa_address | ~ifa->ifa_mask;
+ __be32 any = ifa->ifa_address & ifa->ifa_mask;
#define LOCAL_OK 1
#define BRD_OK 2
#define BRD0_OK 4
#define BRD1_OK 8
unsigned ok = 0;
- if (!(ifa->ifa_flags&IFA_F_SECONDARY))
- fib_magic(RTM_DELROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
- RTN_UNICAST, any, ifa->ifa_prefixlen, prim);
+ if (!(ifa->ifa_flags & IFA_F_SECONDARY))
+ fib_magic(RTM_DELROUTE,
+ dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,
+ any, ifa->ifa_prefixlen, prim);
else {
prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask);
if (prim == NULL) {
@@ -796,9 +804,9 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
}
/* Deletion is more complicated than add.
- We should take care of not to delete too much :-)
-
- Scan address list to be sure that addresses are really gone.
+ * We should take care of not to delete too much :-)
+ *
+ * Scan address list to be sure that addresses are really gone.
*/
for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {
@@ -812,23 +820,23 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
ok |= BRD0_OK;
}
- if (!(ok&BRD_OK))
+ if (!(ok & BRD_OK))
fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
- if (!(ok&BRD1_OK))
+ if (!(ok & BRD1_OK))
fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim);
- if (!(ok&BRD0_OK))
+ if (!(ok & BRD0_OK))
fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim);
- if (!(ok&LOCAL_OK)) {
+ if (!(ok & LOCAL_OK)) {
fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
/* Check, that this local address finally disappeared. */
if (inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) {
/* And the last, but not the least thing.
- We must flush stray FIB entries.
-
- First of all, we scan fib_info list searching
- for stray nexthop entries, then ignite fib_flush.
- */
+ * We must flush stray FIB entries.
+ *
+ * First of all, we scan fib_info list searching
+ * for stray nexthop entries, then ignite fib_flush.
+ */
if (fib_sync_down_addr(dev_net(dev), ifa->ifa_local))
fib_flush(dev_net(dev));
}
@@ -839,14 +847,20 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
#undef BRD1_OK
}
-static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb )
+static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb)
{
struct fib_result res;
- struct flowi fl = { .mark = frn->fl_mark,
- .nl_u = { .ip4_u = { .daddr = frn->fl_addr,
- .tos = frn->fl_tos,
- .scope = frn->fl_scope } } };
+ struct flowi fl = {
+ .mark = frn->fl_mark,
+ .nl_u = {
+ .ip4_u = {
+ .daddr = frn->fl_addr,
+ .tos = frn->fl_tos,
+ .scope = frn->fl_scope
+ }
+ }
+ };
#ifdef CONFIG_IP_MULTIPLE_TABLES
res.r = NULL;
@@ -857,15 +871,16 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb )
local_bh_disable();
frn->tb_id = tb->tb_id;
- frn->err = fib_table_lookup(tb, &fl, &res);
+ rcu_read_lock();
+ frn->err = fib_table_lookup(tb, &fl, &res, FIB_LOOKUP_NOREF);
if (!frn->err) {
frn->prefixlen = res.prefixlen;
frn->nh_sel = res.nh_sel;
frn->type = res.type;
frn->scope = res.scope;
- fib_res_put(&res);
}
+ rcu_read_unlock();
local_bh_enable();
}
}
@@ -894,8 +909,8 @@ static void nl_fib_input(struct sk_buff *skb)
nl_fib_lookup(frn, tb);
- pid = NETLINK_CB(skb).pid; /* pid of sending process */
- NETLINK_CB(skb).pid = 0; /* from kernel */
+ pid = NETLINK_CB(skb).pid; /* pid of sending process */
+ NETLINK_CB(skb).pid = 0; /* from kernel */
NETLINK_CB(skb).dst_group = 0; /* unicast */
netlink_unicast(net->ipv4.fibnl, skb, pid, MSG_DONTWAIT);
}
@@ -942,7 +957,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
fib_del_ifaddr(ifa);
if (ifa->ifa_dev->ifa_list == NULL) {
/* Last address was deleted from this interface.
- Disable IP.
+ * Disable IP.
*/
fib_disable_ip(dev, 1, 0);
} else {
@@ -1001,16 +1016,15 @@ static struct notifier_block fib_netdev_notifier = {
static int __net_init ip_fib_net_init(struct net *net)
{
int err;
- unsigned int i;
+ size_t size = sizeof(struct hlist_head) * FIB_TABLE_HASHSZ;
- net->ipv4.fib_table_hash = kzalloc(
- sizeof(struct hlist_head)*FIB_TABLE_HASHSZ, GFP_KERNEL);
+ /* Avoid false sharing : Use at least a full cache line */
+ size = max_t(size_t, size, L1_CACHE_BYTES);
+
+ net->ipv4.fib_table_hash = kzalloc(size, GFP_KERNEL);
if (net->ipv4.fib_table_hash == NULL)
return -ENOMEM;
- for (i = 0; i < FIB_TABLE_HASHSZ; i++)
- INIT_HLIST_HEAD(&net->ipv4.fib_table_hash[i]);
-
err = fib4_rules_init(net);
if (err < 0)
goto fail;
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
index 4ed7e0dea1bc..b232375a0b75 100644
--- a/net/ipv4/fib_hash.c
+++ b/net/ipv4/fib_hash.c
@@ -54,36 +54,37 @@ struct fib_node {
struct fib_alias fn_embedded_alias;
};
-struct fn_zone {
- struct fn_zone *fz_next; /* Next not empty zone */
- struct hlist_head *fz_hash; /* Hash table pointer */
- int fz_nent; /* Number of entries */
+#define EMBEDDED_HASH_SIZE (L1_CACHE_BYTES / sizeof(struct hlist_head))
- int fz_divisor; /* Hash divisor */
+struct fn_zone {
+ struct fn_zone __rcu *fz_next; /* Next not empty zone */
+ struct hlist_head __rcu *fz_hash; /* Hash table pointer */
+ seqlock_t fz_lock;
u32 fz_hashmask; /* (fz_divisor - 1) */
-#define FZ_HASHMASK(fz) ((fz)->fz_hashmask)
- int fz_order; /* Zone order */
- __be32 fz_mask;
+ u8 fz_order; /* Zone order (0..32) */
+ u8 fz_revorder; /* 32 - fz_order */
+ __be32 fz_mask; /* inet_make_mask(order) */
#define FZ_MASK(fz) ((fz)->fz_mask)
-};
-/* NOTE. On fast computers evaluation of fz_hashmask and fz_mask
- * can be cheaper than memory lookup, so that FZ_* macros are used.
- */
+ struct hlist_head fz_embedded_hash[EMBEDDED_HASH_SIZE];
+
+ int fz_nent; /* Number of entries */
+ int fz_divisor; /* Hash size (mask+1) */
+};
struct fn_hash {
- struct fn_zone *fn_zones[33];
- struct fn_zone *fn_zone_list;
+ struct fn_zone *fn_zones[33];
+ struct fn_zone __rcu *fn_zone_list;
};
static inline u32 fn_hash(__be32 key, struct fn_zone *fz)
{
- u32 h = ntohl(key)>>(32 - fz->fz_order);
+ u32 h = ntohl(key) >> fz->fz_revorder;
h ^= (h>>20);
h ^= (h>>10);
h ^= (h>>5);
- h &= FZ_HASHMASK(fz);
+ h &= fz->fz_hashmask;
return h;
}
@@ -92,7 +93,6 @@ static inline __be32 fz_key(__be32 dst, struct fn_zone *fz)
return dst & FZ_MASK(fz);
}
-static DEFINE_RWLOCK(fib_hash_lock);
static unsigned int fib_hash_genid;
#define FZ_MAX_DIVISOR ((PAGE_SIZE<<MAX_ORDER) / sizeof(struct hlist_head))
@@ -101,12 +101,11 @@ static struct hlist_head *fz_hash_alloc(int divisor)
{
unsigned long size = divisor * sizeof(struct hlist_head);
- if (size <= PAGE_SIZE) {
+ if (size <= PAGE_SIZE)
return kzalloc(size, GFP_KERNEL);
- } else {
- return (struct hlist_head *)
- __get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(size));
- }
+
+ return (struct hlist_head *)
+ __get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(size));
}
/* The fib hash lock must be held when this is called. */
@@ -123,10 +122,11 @@ static inline void fn_rebuild_zone(struct fn_zone *fz,
hlist_for_each_entry_safe(f, node, n, &old_ht[i], fn_hash) {
struct hlist_head *new_head;
- hlist_del(&f->fn_hash);
+ hlist_del_rcu(&f->fn_hash);
- new_head = &fz->fz_hash[fn_hash(f->fn_key, fz)];
- hlist_add_head(&f->fn_hash, new_head);
+ new_head = rcu_dereference_protected(fz->fz_hash, 1) +
+ fn_hash(f->fn_key, fz);
+ hlist_add_head_rcu(&f->fn_hash, new_head);
}
}
}
@@ -147,14 +147,14 @@ static void fn_rehash_zone(struct fn_zone *fz)
int old_divisor, new_divisor;
u32 new_hashmask;
- old_divisor = fz->fz_divisor;
+ new_divisor = old_divisor = fz->fz_divisor;
switch (old_divisor) {
- case 16:
- new_divisor = 256;
+ case EMBEDDED_HASH_SIZE:
+ new_divisor *= EMBEDDED_HASH_SIZE;
break;
- case 256:
- new_divisor = 1024;
+ case EMBEDDED_HASH_SIZE*EMBEDDED_HASH_SIZE:
+ new_divisor *= (EMBEDDED_HASH_SIZE/2);
break;
default:
if ((old_divisor << 1) > FZ_MAX_DIVISOR) {
@@ -175,31 +175,55 @@ static void fn_rehash_zone(struct fn_zone *fz)
ht = fz_hash_alloc(new_divisor);
if (ht) {
- write_lock_bh(&fib_hash_lock);
- old_ht = fz->fz_hash;
- fz->fz_hash = ht;
+ struct fn_zone nfz;
+
+ memcpy(&nfz, fz, sizeof(nfz));
+
+ write_seqlock_bh(&fz->fz_lock);
+ old_ht = rcu_dereference_protected(fz->fz_hash, 1);
+ RCU_INIT_POINTER(nfz.fz_hash, ht);
+ nfz.fz_hashmask = new_hashmask;
+ nfz.fz_divisor = new_divisor;
+ fn_rebuild_zone(&nfz, old_ht, old_divisor);
+ fib_hash_genid++;
+ rcu_assign_pointer(fz->fz_hash, ht);
fz->fz_hashmask = new_hashmask;
fz->fz_divisor = new_divisor;
- fn_rebuild_zone(fz, old_ht, old_divisor);
- fib_hash_genid++;
- write_unlock_bh(&fib_hash_lock);
+ write_sequnlock_bh(&fz->fz_lock);
- fz_hash_free(old_ht, old_divisor);
+ if (old_ht != fz->fz_embedded_hash) {
+ synchronize_rcu();
+ fz_hash_free(old_ht, old_divisor);
+ }
}
}
-static inline void fn_free_node(struct fib_node * f)
+static void fn_free_node_rcu(struct rcu_head *head)
{
+ struct fib_node *f = container_of(head, struct fib_node, fn_embedded_alias.rcu);
+
kmem_cache_free(fn_hash_kmem, f);
}
+static inline void fn_free_node(struct fib_node *f)
+{
+ call_rcu(&f->fn_embedded_alias.rcu, fn_free_node_rcu);
+}
+
+static void fn_free_alias_rcu(struct rcu_head *head)
+{
+ struct fib_alias *fa = container_of(head, struct fib_alias, rcu);
+
+ kmem_cache_free(fn_alias_kmem, fa);
+}
+
static inline void fn_free_alias(struct fib_alias *fa, struct fib_node *f)
{
fib_release_info(fa->fa_info);
if (fa == &f->fn_embedded_alias)
fa->fa_info = NULL;
else
- kmem_cache_free(fn_alias_kmem, fa);
+ call_rcu(&fa->rcu, fn_free_alias_rcu);
}
static struct fn_zone *
@@ -210,68 +234,71 @@ fn_new_zone(struct fn_hash *table, int z)
if (!fz)
return NULL;
- if (z) {
- fz->fz_divisor = 16;
- } else {
- fz->fz_divisor = 1;
- }
- fz->fz_hashmask = (fz->fz_divisor - 1);
- fz->fz_hash = fz_hash_alloc(fz->fz_divisor);
- if (!fz->fz_hash) {
- kfree(fz);
- return NULL;
- }
+ seqlock_init(&fz->fz_lock);
+ fz->fz_divisor = z ? EMBEDDED_HASH_SIZE : 1;
+ fz->fz_hashmask = fz->fz_divisor - 1;
+ RCU_INIT_POINTER(fz->fz_hash, fz->fz_embedded_hash);
fz->fz_order = z;
+ fz->fz_revorder = 32 - z;
fz->fz_mask = inet_make_mask(z);
/* Find the first not empty zone with more specific mask */
- for (i=z+1; i<=32; i++)
+ for (i = z + 1; i <= 32; i++)
if (table->fn_zones[i])
break;
- write_lock_bh(&fib_hash_lock);
- if (i>32) {
+ if (i > 32) {
/* No more specific masks, we are the first. */
- fz->fz_next = table->fn_zone_list;
- table->fn_zone_list = fz;
+ rcu_assign_pointer(fz->fz_next,
+ rtnl_dereference(table->fn_zone_list));
+ rcu_assign_pointer(table->fn_zone_list, fz);
} else {
- fz->fz_next = table->fn_zones[i]->fz_next;
- table->fn_zones[i]->fz_next = fz;
+ rcu_assign_pointer(fz->fz_next,
+ rtnl_dereference(table->fn_zones[i]->fz_next));
+ rcu_assign_pointer(table->fn_zones[i]->fz_next, fz);
}
table->fn_zones[z] = fz;
fib_hash_genid++;
- write_unlock_bh(&fib_hash_lock);
return fz;
}
int fib_table_lookup(struct fib_table *tb,
- const struct flowi *flp, struct fib_result *res)
+ const struct flowi *flp, struct fib_result *res,
+ int fib_flags)
{
int err;
struct fn_zone *fz;
struct fn_hash *t = (struct fn_hash *)tb->tb_data;
- read_lock(&fib_hash_lock);
- for (fz = t->fn_zone_list; fz; fz = fz->fz_next) {
+ rcu_read_lock();
+ for (fz = rcu_dereference(t->fn_zone_list);
+ fz != NULL;
+ fz = rcu_dereference(fz->fz_next)) {
struct hlist_head *head;
struct hlist_node *node;
struct fib_node *f;
- __be32 k = fz_key(flp->fl4_dst, fz);
+ __be32 k;
+ unsigned int seq;
- head = &fz->fz_hash[fn_hash(k, fz)];
- hlist_for_each_entry(f, node, head, fn_hash) {
- if (f->fn_key != k)
- continue;
+ do {
+ seq = read_seqbegin(&fz->fz_lock);
+ k = fz_key(flp->fl4_dst, fz);
+
+ head = rcu_dereference(fz->fz_hash) + fn_hash(k, fz);
+ hlist_for_each_entry_rcu(f, node, head, fn_hash) {
+ if (f->fn_key != k)
+ continue;
- err = fib_semantic_match(&f->fn_alias,
+ err = fib_semantic_match(&f->fn_alias,
flp, res,
- fz->fz_order);
- if (err <= 0)
- goto out;
- }
+ fz->fz_order, fib_flags);
+ if (err <= 0)
+ goto out;
+ }
+ } while (read_seqretry(&fz->fz_lock, seq));
}
err = 1;
out:
- read_unlock(&fib_hash_lock);
+ rcu_read_unlock();
return err;
}
@@ -285,6 +312,7 @@ void fib_table_select_default(struct fib_table *tb,
struct fib_info *last_resort;
struct fn_hash *t = (struct fn_hash *)tb->tb_data;
struct fn_zone *fz = t->fn_zones[0];
+ struct hlist_head *head;
if (fz == NULL)
return;
@@ -293,11 +321,12 @@ void fib_table_select_default(struct fib_table *tb,
last_resort = NULL;
order = -1;
- read_lock(&fib_hash_lock);
- hlist_for_each_entry(f, node, &fz->fz_hash[0], fn_hash) {
+ rcu_read_lock();
+ head = rcu_dereference(fz->fz_hash);
+ hlist_for_each_entry_rcu(f, node, head, fn_hash) {
struct fib_alias *fa;
- list_for_each_entry(fa, &f->fn_alias, fa_list) {
+ list_for_each_entry_rcu(fa, &f->fn_alias, fa_list) {
struct fib_info *next_fi = fa->fa_info;
if (fa->fa_scope != res->scope ||
@@ -309,7 +338,8 @@ void fib_table_select_default(struct fib_table *tb,
if (!next_fi->fib_nh[0].nh_gw ||
next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
continue;
- fa->fa_state |= FA_S_ACCESSED;
+
+ fib_alias_accessed(fa);
if (fi == NULL) {
if (next_fi != res->fi)
@@ -341,25 +371,25 @@ void fib_table_select_default(struct fib_table *tb,
fib_result_assign(res, last_resort);
tb->tb_default = last_idx;
out:
- read_unlock(&fib_hash_lock);
+ rcu_read_unlock();
}
/* Insert node F to FZ. */
static inline void fib_insert_node(struct fn_zone *fz, struct fib_node *f)
{
- struct hlist_head *head = &fz->fz_hash[fn_hash(f->fn_key, fz)];
+ struct hlist_head *head = rtnl_dereference(fz->fz_hash) + fn_hash(f->fn_key, fz);
- hlist_add_head(&f->fn_hash, head);
+ hlist_add_head_rcu(&f->fn_hash, head);
}
/* Return the node in FZ matching KEY. */
static struct fib_node *fib_find_node(struct fn_zone *fz, __be32 key)
{
- struct hlist_head *head = &fz->fz_hash[fn_hash(key, fz)];
+ struct hlist_head *head = rtnl_dereference(fz->fz_hash) + fn_hash(key, fz);
struct hlist_node *node;
struct fib_node *f;
- hlist_for_each_entry(f, node, head, fn_hash) {
+ hlist_for_each_entry_rcu(f, node, head, fn_hash) {
if (f->fn_key == key)
return f;
}
@@ -367,6 +397,17 @@ static struct fib_node *fib_find_node(struct fn_zone *fz, __be32 key)
return NULL;
}
+
+static struct fib_alias *fib_fast_alloc(struct fib_node *f)
+{
+ struct fib_alias *fa = &f->fn_embedded_alias;
+
+ if (fa->fa_info != NULL)
+ fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
+ return fa;
+}
+
+/* Caller must hold RTNL. */
int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
{
struct fn_hash *table = (struct fn_hash *) tb->tb_data;
@@ -451,7 +492,6 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
}
if (cfg->fc_nlflags & NLM_F_REPLACE) {
- struct fib_info *fi_drop;
u8 state;
fa = fa_first;
@@ -460,21 +500,25 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
err = 0;
goto out;
}
- write_lock_bh(&fib_hash_lock);
- fi_drop = fa->fa_info;
- fa->fa_info = fi;
- fa->fa_type = cfg->fc_type;
- fa->fa_scope = cfg->fc_scope;
+ err = -ENOBUFS;
+ new_fa = fib_fast_alloc(f);
+ if (new_fa == NULL)
+ goto out;
+
+ new_fa->fa_tos = fa->fa_tos;
+ new_fa->fa_info = fi;
+ new_fa->fa_type = cfg->fc_type;
+ new_fa->fa_scope = cfg->fc_scope;
state = fa->fa_state;
- fa->fa_state &= ~FA_S_ACCESSED;
+ new_fa->fa_state = state & ~FA_S_ACCESSED;
fib_hash_genid++;
- write_unlock_bh(&fib_hash_lock);
+ list_replace_rcu(&fa->fa_list, &new_fa->fa_list);
- fib_release_info(fi_drop);
+ fn_free_alias(fa, f);
if (state & FA_S_ACCESSED)
rt_cache_flush(cfg->fc_nlinfo.nl_net, -1);
- rtmsg_fib(RTM_NEWROUTE, key, fa, cfg->fc_dst_len, tb->tb_id,
- &cfg->fc_nlinfo, NLM_F_REPLACE);
+ rtmsg_fib(RTM_NEWROUTE, key, new_fa, cfg->fc_dst_len,
+ tb->tb_id, &cfg->fc_nlinfo, NLM_F_REPLACE);
return 0;
}
@@ -506,12 +550,10 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
f = new_f;
}
- new_fa = &f->fn_embedded_alias;
- if (new_fa->fa_info != NULL) {
- new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
- if (new_fa == NULL)
- goto out;
- }
+ new_fa = fib_fast_alloc(f);
+ if (new_fa == NULL)
+ goto out;
+
new_fa->fa_info = fi;
new_fa->fa_tos = tos;
new_fa->fa_type = cfg->fc_type;
@@ -522,13 +564,11 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
* Insert new entry to the list.
*/
- write_lock_bh(&fib_hash_lock);
if (new_f)
fib_insert_node(fz, new_f);
- list_add_tail(&new_fa->fa_list,
+ list_add_tail_rcu(&new_fa->fa_list,
(fa ? &fa->fa_list : &f->fn_alias));
fib_hash_genid++;
- write_unlock_bh(&fib_hash_lock);
if (new_f)
fz->fz_nent++;
@@ -603,14 +643,12 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
tb->tb_id, &cfg->fc_nlinfo, 0);
kill_fn = 0;
- write_lock_bh(&fib_hash_lock);
- list_del(&fa->fa_list);
+ list_del_rcu(&fa->fa_list);
if (list_empty(&f->fn_alias)) {
- hlist_del(&f->fn_hash);
+ hlist_del_rcu(&f->fn_hash);
kill_fn = 1;
}
fib_hash_genid++;
- write_unlock_bh(&fib_hash_lock);
if (fa->fa_state & FA_S_ACCESSED)
rt_cache_flush(cfg->fc_nlinfo.nl_net, -1);
@@ -627,7 +665,7 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
static int fn_flush_list(struct fn_zone *fz, int idx)
{
- struct hlist_head *head = &fz->fz_hash[idx];
+ struct hlist_head *head = rtnl_dereference(fz->fz_hash) + idx;
struct hlist_node *node, *n;
struct fib_node *f;
int found = 0;
@@ -641,14 +679,12 @@ static int fn_flush_list(struct fn_zone *fz, int idx)
struct fib_info *fi = fa->fa_info;
if (fi && (fi->fib_flags&RTNH_F_DEAD)) {
- write_lock_bh(&fib_hash_lock);
- list_del(&fa->fa_list);
+ list_del_rcu(&fa->fa_list);
if (list_empty(&f->fn_alias)) {
- hlist_del(&f->fn_hash);
+ hlist_del_rcu(&f->fn_hash);
kill_f = 1;
}
fib_hash_genid++;
- write_unlock_bh(&fib_hash_lock);
fn_free_alias(fa, f);
found++;
@@ -662,13 +698,16 @@ static int fn_flush_list(struct fn_zone *fz, int idx)
return found;
}
+/* caller must hold RTNL. */
int fib_table_flush(struct fib_table *tb)
{
struct fn_hash *table = (struct fn_hash *) tb->tb_data;
struct fn_zone *fz;
int found = 0;
- for (fz = table->fn_zone_list; fz; fz = fz->fz_next) {
+ for (fz = rtnl_dereference(table->fn_zone_list);
+ fz != NULL;
+ fz = rtnl_dereference(fz->fz_next)) {
int i;
for (i = fz->fz_divisor - 1; i >= 0; i--)
@@ -690,10 +729,10 @@ fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb,
s_i = cb->args[4];
i = 0;
- hlist_for_each_entry(f, node, head, fn_hash) {
+ hlist_for_each_entry_rcu(f, node, head, fn_hash) {
struct fib_alias *fa;
- list_for_each_entry(fa, &f->fn_alias, fa_list) {
+ list_for_each_entry_rcu(fa, &f->fn_alias, fa_list) {
if (i < s_i)
goto next;
@@ -711,7 +750,7 @@ fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb,
cb->args[4] = i;
return -1;
}
- next:
+next:
i++;
}
}
@@ -725,14 +764,15 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb,
struct fn_zone *fz)
{
int h, s_h;
+ struct hlist_head *head = rcu_dereference(fz->fz_hash);
- if (fz->fz_hash == NULL)
+ if (head == NULL)
return skb->len;
s_h = cb->args[3];
for (h = s_h; h < fz->fz_divisor; h++) {
- if (hlist_empty(&fz->fz_hash[h]))
+ if (hlist_empty(head + h))
continue;
- if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h]) < 0) {
+ if (fn_hash_dump_bucket(skb, cb, tb, fz, head + h) < 0) {
cb->args[3] = h;
return -1;
}
@@ -746,23 +786,26 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb,
int fib_table_dump(struct fib_table *tb, struct sk_buff *skb,
struct netlink_callback *cb)
{
- int m, s_m;
+ int m = 0, s_m;
struct fn_zone *fz;
struct fn_hash *table = (struct fn_hash *)tb->tb_data;
s_m = cb->args[2];
- read_lock(&fib_hash_lock);
- for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) {
- if (m < s_m) continue;
+ rcu_read_lock();
+ for (fz = rcu_dereference(table->fn_zone_list);
+ fz != NULL;
+ fz = rcu_dereference(fz->fz_next), m++) {
+ if (m < s_m)
+ continue;
if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) {
cb->args[2] = m;
- read_unlock(&fib_hash_lock);
+ rcu_read_unlock();
return -1;
}
memset(&cb->args[3], 0,
sizeof(cb->args) - 3*sizeof(cb->args[0]));
}
- read_unlock(&fib_hash_lock);
+ rcu_read_unlock();
cb->args[2] = m;
return skb->len;
}
@@ -825,14 +868,15 @@ static struct fib_alias *fib_get_first(struct seq_file *seq)
iter->genid = fib_hash_genid;
iter->valid = 1;
- for (iter->zone = table->fn_zone_list; iter->zone;
- iter->zone = iter->zone->fz_next) {
+ for (iter->zone = rcu_dereference(table->fn_zone_list);
+ iter->zone != NULL;
+ iter->zone = rcu_dereference(iter->zone->fz_next)) {
int maxslot;
if (!iter->zone->fz_nent)
continue;
- iter->hash_head = iter->zone->fz_hash;
+ iter->hash_head = rcu_dereference(iter->zone->fz_hash);
maxslot = iter->zone->fz_divisor;
for (iter->bucket = 0; iter->bucket < maxslot;
@@ -911,13 +955,13 @@ static struct fib_alias *fib_get_next(struct seq_file *seq)
}
}
- iter->zone = iter->zone->fz_next;
+ iter->zone = rcu_dereference(iter->zone->fz_next);
if (!iter->zone)
goto out;
iter->bucket = 0;
- iter->hash_head = iter->zone->fz_hash;
+ iter->hash_head = rcu_dereference(iter->zone->fz_hash);
hlist_for_each_entry(fn, node, iter->hash_head, fn_hash) {
list_for_each_entry(fa, &fn->fn_alias, fa_list) {
@@ -950,11 +994,11 @@ static struct fib_alias *fib_get_idx(struct seq_file *seq, loff_t pos)
}
static void *fib_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(fib_hash_lock)
+ __acquires(RCU)
{
void *v = NULL;
- read_lock(&fib_hash_lock);
+ rcu_read_lock();
if (fib_get_table(seq_file_net(seq), RT_TABLE_MAIN))
v = *pos ? fib_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
return v;
@@ -967,15 +1011,16 @@ static void *fib_seq_next(struct seq_file *seq, void *v, loff_t *pos)
}
static void fib_seq_stop(struct seq_file *seq, void *v)
- __releases(fib_hash_lock)
+ __releases(RCU)
{
- read_unlock(&fib_hash_lock);
+ rcu_read_unlock();
}
static unsigned fib_flag_trans(int type, __be32 mask, struct fib_info *fi)
{
static const unsigned type2flags[RTN_MAX + 1] = {
- [7] = RTF_REJECT, [8] = RTF_REJECT,
+ [7] = RTF_REJECT,
+ [8] = RTF_REJECT,
};
unsigned flags = type2flags[type];
diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h
index 637b133973bd..a29edf2219c8 100644
--- a/net/ipv4/fib_lookup.h
+++ b/net/ipv4/fib_lookup.h
@@ -12,17 +12,22 @@ struct fib_alias {
u8 fa_type;
u8 fa_scope;
u8 fa_state;
-#ifdef CONFIG_IP_FIB_TRIE
struct rcu_head rcu;
-#endif
};
#define FA_S_ACCESSED 0x01
+/* Dont write on fa_state unless needed, to keep it shared on all cpus */
+static inline void fib_alias_accessed(struct fib_alias *fa)
+{
+ if (!(fa->fa_state & FA_S_ACCESSED))
+ fa->fa_state |= FA_S_ACCESSED;
+}
+
/* Exported by fib_semantics.c */
extern int fib_semantic_match(struct list_head *head,
const struct flowi *flp,
- struct fib_result *res, int prefixlen);
+ struct fib_result *res, int prefixlen, int fib_flags);
extern void fib_release_info(struct fib_info *);
extern struct fib_info *fib_create_info(struct fib_config *cfg);
extern int fib_nh_match(struct fib_config *cfg, struct fib_info *fi);
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 76daeb5ff564..7981a24f5c7b 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -6,7 +6,7 @@
* IPv4 Forwarding Information Base: policy rules.
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
- * Thomas Graf <tgraf@suug.ch>
+ * Thomas Graf <tgraf@suug.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -14,7 +14,7 @@
* 2 of the License, or (at your option) any later version.
*
* Fixes:
- * Rani Assaf : local_rule cannot be deleted
+ * Rani Assaf : local_rule cannot be deleted
* Marc Boucher : routing by fwmark
*/
@@ -32,8 +32,7 @@
#include <net/ip_fib.h>
#include <net/fib_rules.h>
-struct fib4_rule
-{
+struct fib4_rule {
struct fib_rule common;
u8 dst_len;
u8 src_len;
@@ -58,6 +57,7 @@ int fib_lookup(struct net *net, struct flowi *flp, struct fib_result *res)
{
struct fib_lookup_arg arg = {
.result = res,
+ .flags = FIB_LOOKUP_NOREF,
};
int err;
@@ -91,10 +91,11 @@ static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp,
goto errout;
}
- if ((tbl = fib_get_table(rule->fr_net, rule->table)) == NULL)
+ tbl = fib_get_table(rule->fr_net, rule->table);
+ if (!tbl)
goto errout;
- err = fib_table_lookup(tbl, flp, (struct fib_result *) arg->result);
+ err = fib_table_lookup(tbl, flp, (struct fib_result *) arg->result, arg->flags);
if (err > 0)
err = -EAGAIN;
errout:
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 20f09c5b31e8..3e0da3ef6116 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -60,21 +60,30 @@ static struct hlist_head fib_info_devhash[DEVINDEX_HASHSIZE];
static DEFINE_SPINLOCK(fib_multipath_lock);
-#define for_nexthops(fi) { int nhsel; const struct fib_nh * nh; \
-for (nhsel=0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
-
-#define change_nexthops(fi) { int nhsel; struct fib_nh *nexthop_nh; \
-for (nhsel=0, nexthop_nh = (struct fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nexthop_nh++, nhsel++)
+#define for_nexthops(fi) { \
+ int nhsel; const struct fib_nh *nh; \
+ for (nhsel = 0, nh = (fi)->fib_nh; \
+ nhsel < (fi)->fib_nhs; \
+ nh++, nhsel++)
+
+#define change_nexthops(fi) { \
+ int nhsel; struct fib_nh *nexthop_nh; \
+ for (nhsel = 0, nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \
+ nhsel < (fi)->fib_nhs; \
+ nexthop_nh++, nhsel++)
#else /* CONFIG_IP_ROUTE_MULTIPATH */
/* Hope, that gcc will optimize it to get rid of dummy loop */
-#define for_nexthops(fi) { int nhsel = 0; const struct fib_nh * nh = (fi)->fib_nh; \
-for (nhsel=0; nhsel < 1; nhsel++)
+#define for_nexthops(fi) { \
+ int nhsel; const struct fib_nh *nh = (fi)->fib_nh; \
+ for (nhsel = 0; nhsel < 1; nhsel++)
-#define change_nexthops(fi) { int nhsel = 0; struct fib_nh *nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \
-for (nhsel=0; nhsel < 1; nhsel++)
+#define change_nexthops(fi) { \
+ int nhsel; \
+ struct fib_nh *nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \
+ for (nhsel = 0; nhsel < 1; nhsel++)
#endif /* CONFIG_IP_ROUTE_MULTIPATH */
@@ -86,63 +95,70 @@ static const struct
int error;
u8 scope;
} fib_props[RTN_MAX + 1] = {
- {
+ [RTN_UNSPEC] = {
.error = 0,
.scope = RT_SCOPE_NOWHERE,
- }, /* RTN_UNSPEC */
- {
+ },
+ [RTN_UNICAST] = {
.error = 0,
.scope = RT_SCOPE_UNIVERSE,
- }, /* RTN_UNICAST */
- {
+ },
+ [RTN_LOCAL] = {
.error = 0,
.scope = RT_SCOPE_HOST,
- }, /* RTN_LOCAL */
- {
+ },
+ [RTN_BROADCAST] = {
.error = 0,
.scope = RT_SCOPE_LINK,
- }, /* RTN_BROADCAST */
- {
+ },
+ [RTN_ANYCAST] = {
.error = 0,
.scope = RT_SCOPE_LINK,
- }, /* RTN_ANYCAST */
- {
+ },
+ [RTN_MULTICAST] = {
.error = 0,
.scope = RT_SCOPE_UNIVERSE,
- }, /* RTN_MULTICAST */
- {
+ },
+ [RTN_BLACKHOLE] = {
.error = -EINVAL,
.scope = RT_SCOPE_UNIVERSE,
- }, /* RTN_BLACKHOLE */
- {
+ },
+ [RTN_UNREACHABLE] = {
.error = -EHOSTUNREACH,
.scope = RT_SCOPE_UNIVERSE,
- }, /* RTN_UNREACHABLE */
- {
+ },
+ [RTN_PROHIBIT] = {
.error = -EACCES,
.scope = RT_SCOPE_UNIVERSE,
- }, /* RTN_PROHIBIT */
- {
+ },
+ [RTN_THROW] = {
.error = -EAGAIN,
.scope = RT_SCOPE_UNIVERSE,
- }, /* RTN_THROW */
- {
+ },
+ [RTN_NAT] = {
.error = -EINVAL,
.scope = RT_SCOPE_NOWHERE,
- }, /* RTN_NAT */
- {
+ },
+ [RTN_XRESOLVE] = {
.error = -EINVAL,
.scope = RT_SCOPE_NOWHERE,
- }, /* RTN_XRESOLVE */
+ },
};
/* 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);
+
+ kfree(fi);
+}
+
void free_fib_info(struct fib_info *fi)
{
if (fi->fib_dead == 0) {
- printk(KERN_WARNING "Freeing alive fib_info %p\n", fi);
+ pr_warning("Freeing alive fib_info %p\n", fi);
return;
}
change_nexthops(fi) {
@@ -152,7 +168,7 @@ void free_fib_info(struct fib_info *fi)
} endfor_nexthops(fi);
fib_info_cnt--;
release_net(fi->fib_net);
- kfree(fi);
+ call_rcu(&fi->rcu, free_fib_info_rcu);
}
void fib_release_info(struct fib_info *fi)
@@ -173,7 +189,7 @@ void fib_release_info(struct fib_info *fi)
spin_unlock_bh(&fib_info_lock);
}
-static __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
+static inline int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
{
const struct fib_nh *onh = ofi->fib_nh;
@@ -187,7 +203,7 @@ static __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *
#ifdef CONFIG_NET_CLS_ROUTE
nh->nh_tclassid != onh->nh_tclassid ||
#endif
- ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
+ ((nh->nh_flags ^ onh->nh_flags) & ~RTNH_F_DEAD))
return -1;
onh++;
} endfor_nexthops(fi);
@@ -238,7 +254,7 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi)
nfi->fib_priority == fi->fib_priority &&
memcmp(nfi->fib_metrics, fi->fib_metrics,
sizeof(fi->fib_metrics)) == 0 &&
- ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
+ ((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_F_DEAD) == 0 &&
(nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0))
return fi;
}
@@ -247,9 +263,8 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi)
}
/* Check, that the gateway is already configured.
- Used only by redirect accept routine.
+ * Used only by redirect accept routine.
*/
-
int ip_fib_check_default(__be32 gw, struct net_device *dev)
{
struct hlist_head *head;
@@ -264,7 +279,7 @@ int ip_fib_check_default(__be32 gw, struct net_device *dev)
hlist_for_each_entry(nh, node, head, nh_hash) {
if (nh->nh_dev == dev &&
nh->nh_gw == gw &&
- !(nh->nh_flags&RTNH_F_DEAD)) {
+ !(nh->nh_flags & RTNH_F_DEAD)) {
spin_unlock(&fib_info_lock);
return 0;
}
@@ -362,10 +377,10 @@ int fib_detect_death(struct fib_info *fi, int order,
}
if (state == NUD_REACHABLE)
return 0;
- if ((state&NUD_VALID) && order != dflt)
+ if ((state & NUD_VALID) && order != dflt)
return 0;
- if ((state&NUD_VALID) ||
- (*last_idx<0 && order > dflt)) {
+ if ((state & NUD_VALID) ||
+ (*last_idx < 0 && order > dflt)) {
*last_resort = fi;
*last_idx = order;
}
@@ -476,75 +491,76 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
/*
- Picture
- -------
-
- Semantics of nexthop is very messy by historical reasons.
- We have to take into account, that:
- a) gateway can be actually local interface address,
- so that gatewayed route is direct.
- b) gateway must be on-link address, possibly
- described not by an ifaddr, but also by a direct route.
- c) If both gateway and interface are specified, they should not
- contradict.
- d) If we use tunnel routes, gateway could be not on-link.
-
- Attempt to reconcile all of these (alas, self-contradictory) conditions
- results in pretty ugly and hairy code with obscure logic.
-
- I chose to generalized it instead, so that the size
- of code does not increase practically, but it becomes
- much more general.
- Every prefix is assigned a "scope" value: "host" is local address,
- "link" is direct route,
- [ ... "site" ... "interior" ... ]
- and "universe" is true gateway route with global meaning.
-
- Every prefix refers to a set of "nexthop"s (gw, oif),
- where gw must have narrower scope. This recursion stops
- when gw has LOCAL scope or if "nexthop" is declared ONLINK,
- which means that gw is forced to be on link.
-
- Code is still hairy, but now it is apparently logically
- consistent and very flexible. F.e. as by-product it allows
- to co-exists in peace independent exterior and interior
- routing processes.
-
- Normally it looks as following.
-
- {universe prefix} -> (gw, oif) [scope link]
- |
- |-> {link prefix} -> (gw, oif) [scope local]
- |
- |-> {local prefix} (terminal node)
+ * Picture
+ * -------
+ *
+ * Semantics of nexthop is very messy by historical reasons.
+ * We have to take into account, that:
+ * a) gateway can be actually local interface address,
+ * so that gatewayed route is direct.
+ * b) gateway must be on-link address, possibly
+ * described not by an ifaddr, but also by a direct route.
+ * c) If both gateway and interface are specified, they should not
+ * contradict.
+ * d) If we use tunnel routes, gateway could be not on-link.
+ *
+ * Attempt to reconcile all of these (alas, self-contradictory) conditions
+ * results in pretty ugly and hairy code with obscure logic.
+ *
+ * I chose to generalized it instead, so that the size
+ * of code does not increase practically, but it becomes
+ * much more general.
+ * Every prefix is assigned a "scope" value: "host" is local address,
+ * "link" is direct route,
+ * [ ... "site" ... "interior" ... ]
+ * and "universe" is true gateway route with global meaning.
+ *
+ * Every prefix refers to a set of "nexthop"s (gw, oif),
+ * where gw must have narrower scope. This recursion stops
+ * when gw has LOCAL scope or if "nexthop" is declared ONLINK,
+ * which means that gw is forced to be on link.
+ *
+ * Code is still hairy, but now it is apparently logically
+ * consistent and very flexible. F.e. as by-product it allows
+ * to co-exists in peace independent exterior and interior
+ * routing processes.
+ *
+ * Normally it looks as following.
+ *
+ * {universe prefix} -> (gw, oif) [scope link]
+ * |
+ * |-> {link prefix} -> (gw, oif) [scope local]
+ * |
+ * |-> {local prefix} (terminal node)
*/
-
static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
struct fib_nh *nh)
{
int err;
struct net *net;
+ struct net_device *dev;
net = cfg->fc_nlinfo.nl_net;
if (nh->nh_gw) {
struct fib_result res;
- if (nh->nh_flags&RTNH_F_ONLINK) {
- struct net_device *dev;
+ if (nh->nh_flags & RTNH_F_ONLINK) {
if (cfg->fc_scope >= RT_SCOPE_LINK)
return -EINVAL;
if (inet_addr_type(net, nh->nh_gw) != RTN_UNICAST)
return -EINVAL;
- if ((dev = __dev_get_by_index(net, nh->nh_oif)) == NULL)
+ dev = __dev_get_by_index(net, nh->nh_oif);
+ if (!dev)
return -ENODEV;
- if (!(dev->flags&IFF_UP))
+ if (!(dev->flags & IFF_UP))
return -ENETDOWN;
nh->nh_dev = dev;
dev_hold(dev);
nh->nh_scope = RT_SCOPE_LINK;
return 0;
}
+ rcu_read_lock();
{
struct flowi fl = {
.nl_u = {
@@ -559,50 +575,53 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
/* It is not necessary, but requires a bit of thinking */
if (fl.fl4_scope < RT_SCOPE_LINK)
fl.fl4_scope = RT_SCOPE_LINK;
- if ((err = fib_lookup(net, &fl, &res)) != 0)
+ err = fib_lookup(net, &fl, &res);
+ if (err) {
+ rcu_read_unlock();
return err;
+ }
}
err = -EINVAL;
if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
goto out;
nh->nh_scope = res.scope;
nh->nh_oif = FIB_RES_OIF(res);
- if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
+ nh->nh_dev = dev = FIB_RES_DEV(res);
+ if (!dev)
goto out;
- dev_hold(nh->nh_dev);
- err = -ENETDOWN;
- if (!(nh->nh_dev->flags & IFF_UP))
- goto out;
- err = 0;
-out:
- fib_res_put(&res);
- return err;
+ dev_hold(dev);
+ err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN;
} else {
struct in_device *in_dev;
- if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK))
+ if (nh->nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK))
return -EINVAL;
+ rcu_read_lock();
+ err = -ENODEV;
in_dev = inetdev_by_index(net, nh->nh_oif);
if (in_dev == NULL)
- return -ENODEV;
- if (!(in_dev->dev->flags&IFF_UP)) {
- in_dev_put(in_dev);
- return -ENETDOWN;
- }
+ goto out;
+ err = -ENETDOWN;
+ if (!(in_dev->dev->flags & IFF_UP))
+ goto out;
nh->nh_dev = in_dev->dev;
dev_hold(nh->nh_dev);
nh->nh_scope = RT_SCOPE_HOST;
- in_dev_put(in_dev);
+ err = 0;
}
- return 0;
+out:
+ rcu_read_unlock();
+ return err;
}
static inline unsigned int fib_laddr_hashfn(__be32 val)
{
unsigned int mask = (fib_hash_size - 1);
- return ((__force u32)val ^ ((__force u32)val >> 7) ^ ((__force u32)val >> 14)) & mask;
+ return ((__force u32)val ^
+ ((__force u32)val >> 7) ^
+ ((__force u32)val >> 14)) & mask;
}
static struct hlist_head *fib_hash_alloc(int bytes)
@@ -611,7 +630,8 @@ static struct hlist_head *fib_hash_alloc(int bytes)
return kzalloc(bytes, GFP_KERNEL);
else
return (struct hlist_head *)
- __get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(bytes));
+ __get_free_pages(GFP_KERNEL | __GFP_ZERO,
+ get_order(bytes));
}
static void fib_hash_free(struct hlist_head *hash, int bytes)
@@ -806,7 +826,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
goto failure;
} else {
change_nexthops(fi) {
- if ((err = fib_check_nh(cfg, fi, nexthop_nh)) != 0)
+ err = fib_check_nh(cfg, fi, nexthop_nh);
+ if (err != 0)
goto failure;
} endfor_nexthops(fi)
}
@@ -819,7 +840,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
}
link_it:
- if ((ofi = fib_find_info(fi)) != NULL) {
+ ofi = fib_find_info(fi);
+ if (ofi) {
fi->fib_dead = 1;
free_fib_info(fi);
ofi->fib_treeref++;
@@ -864,7 +886,7 @@ failure:
/* Note! fib_semantic_match intentionally uses RCU list functions. */
int fib_semantic_match(struct list_head *head, const struct flowi *flp,
- struct fib_result *res, int prefixlen)
+ struct fib_result *res, int prefixlen, int fib_flags)
{
struct fib_alias *fa;
int nh_sel = 0;
@@ -879,7 +901,7 @@ int fib_semantic_match(struct list_head *head, const struct flowi *flp,
if (fa->fa_scope < flp->fl4_scope)
continue;
- fa->fa_state |= FA_S_ACCESSED;
+ fib_alias_accessed(fa);
err = fib_props[fa->fa_type].error;
if (err == 0) {
@@ -895,7 +917,7 @@ int fib_semantic_match(struct list_head *head, const struct flowi *flp,
case RTN_ANYCAST:
case RTN_MULTICAST:
for_nexthops(fi) {
- if (nh->nh_flags&RTNH_F_DEAD)
+ if (nh->nh_flags & RTNH_F_DEAD)
continue;
if (!flp->oif || flp->oif == nh->nh_oif)
break;
@@ -906,16 +928,15 @@ int fib_semantic_match(struct list_head *head, const struct flowi *flp,
goto out_fill_res;
}
#else
- if (nhsel < 1) {
+ if (nhsel < 1)
goto out_fill_res;
- }
#endif
endfor_nexthops(fi);
continue;
default:
- printk(KERN_WARNING "fib_semantic_match bad type %#x\n",
- fa->fa_type);
+ pr_warning("fib_semantic_match bad type %#x\n",
+ fa->fa_type);
return -EINVAL;
}
}
@@ -929,7 +950,8 @@ out_fill_res:
res->type = fa->fa_type;
res->scope = fa->fa_scope;
res->fi = fa->fa_info;
- atomic_inc(&res->fi->fib_clntref);
+ if (!(fib_flags & FIB_LOOKUP_NOREF))
+ atomic_inc(&res->fi->fib_clntref);
return 0;
}
@@ -1028,10 +1050,10 @@ nla_put_failure:
}
/*
- Update FIB if:
- - local address disappeared -> we must delete all the entries
- referring to it.
- - device went down -> we must shutdown all nexthops going via it.
+ * Update FIB if:
+ * - local address disappeared -> we must delete all the entries
+ * referring to it.
+ * - device went down -> we must shutdown all nexthops going via it.
*/
int fib_sync_down_addr(struct net *net, __be32 local)
{
@@ -1078,7 +1100,7 @@ int fib_sync_down_dev(struct net_device *dev, int force)
prev_fi = fi;
dead = 0;
change_nexthops(fi) {
- if (nexthop_nh->nh_flags&RTNH_F_DEAD)
+ if (nexthop_nh->nh_flags & RTNH_F_DEAD)
dead++;
else if (nexthop_nh->nh_dev == dev &&
nexthop_nh->nh_scope != scope) {
@@ -1110,10 +1132,9 @@ int fib_sync_down_dev(struct net_device *dev, int force)
#ifdef CONFIG_IP_ROUTE_MULTIPATH
/*
- Dead device goes up. We wake up dead nexthops.
- It takes sense only on multipath routes.
+ * Dead device goes up. We wake up dead nexthops.
+ * It takes sense only on multipath routes.
*/
-
int fib_sync_up(struct net_device *dev)
{
struct fib_info *prev_fi;
@@ -1123,7 +1144,7 @@ int fib_sync_up(struct net_device *dev)
struct fib_nh *nh;
int ret;
- if (!(dev->flags&IFF_UP))
+ if (!(dev->flags & IFF_UP))
return 0;
prev_fi = NULL;
@@ -1142,12 +1163,12 @@ int fib_sync_up(struct net_device *dev)
prev_fi = fi;
alive = 0;
change_nexthops(fi) {
- if (!(nexthop_nh->nh_flags&RTNH_F_DEAD)) {
+ if (!(nexthop_nh->nh_flags & RTNH_F_DEAD)) {
alive++;
continue;
}
if (nexthop_nh->nh_dev == NULL ||
- !(nexthop_nh->nh_dev->flags&IFF_UP))
+ !(nexthop_nh->nh_dev->flags & IFF_UP))
continue;
if (nexthop_nh->nh_dev != dev ||
!__in_dev_get_rtnl(dev))
@@ -1169,10 +1190,9 @@ int fib_sync_up(struct net_device *dev)
}
/*
- The algorithm is suboptimal, but it provides really
- fair weighted route distribution.
+ * The algorithm is suboptimal, but it provides really
+ * fair weighted route distribution.
*/
-
void fib_select_multipath(const struct flowi *flp, struct fib_result *res)
{
struct fib_info *fi = res->fi;
@@ -1182,7 +1202,7 @@ void fib_select_multipath(const struct flowi *flp, struct fib_result *res)
if (fi->fib_power <= 0) {
int power = 0;
change_nexthops(fi) {
- if (!(nexthop_nh->nh_flags&RTNH_F_DEAD)) {
+ if (!(nexthop_nh->nh_flags & RTNH_F_DEAD)) {
power += nexthop_nh->nh_weight;
nexthop_nh->nh_power = nexthop_nh->nh_weight;
}
@@ -1198,15 +1218,16 @@ void fib_select_multipath(const struct flowi *flp, struct fib_result *res)
/* w should be random number [0..fi->fib_power-1],
- it is pretty bad approximation.
+ * it is pretty bad approximation.
*/
w = jiffies % fi->fib_power;
change_nexthops(fi) {
- if (!(nexthop_nh->nh_flags&RTNH_F_DEAD) &&
+ if (!(nexthop_nh->nh_flags & RTNH_F_DEAD) &&
nexthop_nh->nh_power) {
- if ((w -= nexthop_nh->nh_power) <= 0) {
+ w -= nexthop_nh->nh_power;
+ if (w <= 0) {
nexthop_nh->nh_power--;
fi->fib_power--;
res->nh_sel = nhsel;
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 4a8e370862bc..b14450895102 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -16,7 +16,7 @@
*
* An experimental study of compression methods for dynamic tries
* Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002.
- * http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/
+ * http://www.csc.kth.se/~snilsson/software/dyntrie2/
*
*
* IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson
@@ -186,9 +186,7 @@ static inline struct tnode *node_parent_rcu(struct node *node)
{
struct tnode *ret = node_parent(node);
- return rcu_dereference_check(ret,
- rcu_read_lock_held() ||
- lockdep_rtnl_is_held());
+ return rcu_dereference_rtnl(ret);
}
/* Same as rcu_assign_pointer
@@ -211,9 +209,7 @@ static inline struct node *tnode_get_child_rcu(struct tnode *tn, unsigned int i)
{
struct node *ret = tnode_get_child(tn, i);
- return rcu_dereference_check(ret,
- rcu_read_lock_held() ||
- lockdep_rtnl_is_held());
+ return rcu_dereference_rtnl(ret);
}
static inline int tnode_child_length(const struct tnode *tn)
@@ -459,8 +455,8 @@ static struct tnode *tnode_new(t_key key, int pos, int bits)
tn->empty_children = 1<<bits;
}
- pr_debug("AT %p s=%u %lu\n", tn, (unsigned int) sizeof(struct tnode),
- (unsigned long) (sizeof(struct node) << bits));
+ pr_debug("AT %p s=%zu %zu\n", tn, sizeof(struct tnode),
+ sizeof(struct node) << bits);
return tn;
}
@@ -609,11 +605,10 @@ static struct node *resize(struct trie *t, struct tnode *tn)
/* Keep root node larger */
- if (!node_parent((struct node*) tn)) {
+ if (!node_parent((struct node *)tn)) {
inflate_threshold_use = inflate_threshold_root;
halve_threshold_use = halve_threshold_root;
- }
- else {
+ } else {
inflate_threshold_use = inflate_threshold;
halve_threshold_use = halve_threshold;
}
@@ -639,7 +634,7 @@ static struct node *resize(struct trie *t, struct tnode *tn)
check_tnode(tn);
/* Return if at least one inflate is run */
- if( max_work != MAX_WORK)
+ if (max_work != MAX_WORK)
return (struct node *) tn;
/*
@@ -966,9 +961,7 @@ fib_find_node(struct trie *t, u32 key)
struct node *n;
pos = 0;
- n = rcu_dereference_check(t->trie,
- rcu_read_lock_held() ||
- lockdep_rtnl_is_held());
+ n = rcu_dereference_rtnl(t->trie);
while (n != NULL && NODE_TYPE(n) == T_TNODE) {
tn = (struct tnode *) n;
@@ -1349,7 +1342,7 @@ err:
/* should be called with rcu_read_lock */
static int check_leaf(struct trie *t, struct leaf *l,
t_key key, const struct flowi *flp,
- struct fib_result *res)
+ struct fib_result *res, int fib_flags)
{
struct leaf_info *li;
struct hlist_head *hhead = &l->list;
@@ -1363,7 +1356,7 @@ static int check_leaf(struct trie *t, struct leaf *l,
if (l->key != (key & ntohl(mask)))
continue;
- err = fib_semantic_match(&li->falh, flp, res, plen);
+ err = fib_semantic_match(&li->falh, flp, res, plen, fib_flags);
#ifdef CONFIG_IP_FIB_TRIE_STATS
if (err <= 0)
@@ -1379,7 +1372,7 @@ static int check_leaf(struct trie *t, struct leaf *l,
}
int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
- struct fib_result *res)
+ struct fib_result *res, int fib_flags)
{
struct trie *t = (struct trie *) tb->tb_data;
int ret;
@@ -1391,8 +1384,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
t_key cindex = 0;
int current_prefix_length = KEYLENGTH;
struct tnode *cn;
- t_key node_prefix, key_prefix, pref_mismatch;
- int mp;
+ t_key pref_mismatch;
rcu_read_lock();
@@ -1406,7 +1398,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
/* Just a leaf? */
if (IS_LEAF(n)) {
- ret = check_leaf(t, (struct leaf *)n, key, flp, res);
+ ret = check_leaf(t, (struct leaf *)n, key, flp, res, fib_flags);
goto found;
}
@@ -1431,7 +1423,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
}
if (IS_LEAF(n)) {
- ret = check_leaf(t, (struct leaf *)n, key, flp, res);
+ ret = check_leaf(t, (struct leaf *)n, key, flp, res, fib_flags);
if (ret > 0)
goto backtrace;
goto found;
@@ -1507,10 +1499,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
* matching prefix.
*/
- node_prefix = mask_pfx(cn->key, cn->pos);
- key_prefix = mask_pfx(key, cn->pos);
- pref_mismatch = key_prefix^node_prefix;
- mp = 0;
+ pref_mismatch = mask_pfx(cn->key ^ key, cn->pos);
/*
* In short: If skipped bits in this node do not match
@@ -1518,13 +1507,9 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
* state.directly.
*/
if (pref_mismatch) {
- while (!(pref_mismatch & (1<<(KEYLENGTH-1)))) {
- mp++;
- pref_mismatch = pref_mismatch << 1;
- }
- key_prefix = tkey_extract_bits(cn->key, mp, cn->pos-mp);
+ int mp = KEYLENGTH - fls(pref_mismatch);
- if (key_prefix != 0)
+ if (tkey_extract_bits(cn->key, mp, cn->pos - mp) != 0)
goto backtrace;
if (current_prefix_length >= cn->pos)
@@ -1748,16 +1733,14 @@ static struct leaf *leaf_walk_rcu(struct tnode *p, struct node *c)
/* Node empty, walk back up to parent */
c = (struct node *) p;
- } while ( (p = node_parent_rcu(c)) != NULL);
+ } while ((p = node_parent_rcu(c)) != NULL);
return NULL; /* Root of trie */
}
static struct leaf *trie_firstleaf(struct trie *t)
{
- struct tnode *n = (struct tnode *) rcu_dereference_check(t->trie,
- rcu_read_lock_held() ||
- lockdep_rtnl_is_held());
+ struct tnode *n = (struct tnode *)rcu_dereference_rtnl(t->trie);
if (!n)
return NULL;
@@ -1855,7 +1838,8 @@ void fib_table_select_default(struct fib_table *tb,
if (!next_fi->fib_nh[0].nh_gw ||
next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
continue;
- fa->fa_state |= FA_S_ACCESSED;
+
+ fib_alias_accessed(fa);
if (fi == NULL) {
if (next_fi != res->fi)
@@ -2043,14 +2027,14 @@ struct fib_trie_iter {
struct seq_net_private p;
struct fib_table *tb;
struct tnode *tnode;
- unsigned index;
- unsigned depth;
+ unsigned int index;
+ unsigned int depth;
};
static struct node *fib_trie_get_next(struct fib_trie_iter *iter)
{
struct tnode *tn = iter->tnode;
- unsigned cindex = iter->index;
+ unsigned int cindex = iter->index;
struct tnode *p;
/* A single entry routing table */
@@ -2159,7 +2143,7 @@ static void trie_collect_stats(struct trie *t, struct trie_stat *s)
*/
static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
{
- unsigned i, max, pointers, bytes, avdepth;
+ unsigned int i, max, pointers, bytes, avdepth;
if (stat->leaves)
avdepth = stat->totdepth*100 / stat->leaves;
@@ -2356,7 +2340,8 @@ static void fib_trie_seq_stop(struct seq_file *seq, void *v)
static void seq_indent(struct seq_file *seq, int n)
{
- while (n-- > 0) seq_puts(seq, " ");
+ while (n-- > 0)
+ seq_puts(seq, " ");
}
static inline const char *rtn_scope(char *buf, size_t len, enum rt_scope_t s)
@@ -2388,7 +2373,7 @@ static const char *const rtn_type_names[__RTN_MAX] = {
[RTN_XRESOLVE] = "XRESOLVE",
};
-static inline const char *rtn_type(char *buf, size_t len, unsigned t)
+static inline const char *rtn_type(char *buf, size_t len, unsigned int t)
{
if (t < __RTN_MAX && rtn_type_names[t])
return rtn_type_names[t];
@@ -2544,13 +2529,12 @@ static void fib_route_seq_stop(struct seq_file *seq, void *v)
rcu_read_unlock();
}
-static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
+static unsigned int fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
{
- static unsigned type2flags[RTN_MAX + 1] = {
- [7] = RTF_REJECT, [8] = RTF_REJECT,
- };
- unsigned flags = type2flags[type];
+ unsigned int flags = 0;
+ if (type == RTN_UNREACHABLE || type == RTN_PROHIBIT)
+ flags = RTF_REJECT;
if (fi && fi->fib_nh->nh_gw)
flags |= RTF_GATEWAY;
if (mask == htonl(0xFFFFFFFF))
@@ -2562,7 +2546,7 @@ static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
/*
* This outputs /proc/net/route.
* The format of the file is not supposed to be changed
- * and needs to be same as fib_hash output to avoid breaking
+ * and needs to be same as fib_hash output to avoid breaking
* legacy utilities
*/
static int fib_route_seq_show(struct seq_file *seq, void *v)
@@ -2587,7 +2571,7 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
list_for_each_entry_rcu(fa, &li->falh, fa_list) {
const struct fib_info *fi = fa->fa_info;
- unsigned flags = fib_flag_trans(fa->fa_type, mask, fi);
+ unsigned int flags = fib_flag_trans(fa->fa_type, mask, fi);
int len;
if (fa->fa_type == RTN_BROADCAST
diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c
new file mode 100644
index 000000000000..c6933f2ea310
--- /dev/null
+++ b/net/ipv4/gre.c
@@ -0,0 +1,152 @@
+/*
+ * GRE over IPv4 demultiplexer driver
+ *
+ * Authors: Dmitry Kozlov (xeb@mail.ru)
+ *
+ * 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/kernel.h>
+#include <linux/kmod.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/netdevice.h>
+#include <linux/version.h>
+#include <linux/spinlock.h>
+#include <net/protocol.h>
+#include <net/gre.h>
+
+
+static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
+static DEFINE_SPINLOCK(gre_proto_lock);
+
+int gre_add_protocol(const struct gre_protocol *proto, u8 version)
+{
+ if (version >= GREPROTO_MAX)
+ goto err_out;
+
+ spin_lock(&gre_proto_lock);
+ if (gre_proto[version])
+ goto err_out_unlock;
+
+ rcu_assign_pointer(gre_proto[version], proto);
+ spin_unlock(&gre_proto_lock);
+ return 0;
+
+err_out_unlock:
+ spin_unlock(&gre_proto_lock);
+err_out:
+ return -1;
+}
+EXPORT_SYMBOL_GPL(gre_add_protocol);
+
+int gre_del_protocol(const struct gre_protocol *proto, u8 version)
+{
+ if (version >= GREPROTO_MAX)
+ goto err_out;
+
+ spin_lock(&gre_proto_lock);
+ 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);
+ spin_unlock(&gre_proto_lock);
+ synchronize_rcu();
+ return 0;
+
+err_out_unlock:
+ spin_unlock(&gre_proto_lock);
+err_out:
+ return -1;
+}
+EXPORT_SYMBOL_GPL(gre_del_protocol);
+
+static int gre_rcv(struct sk_buff *skb)
+{
+ const struct gre_protocol *proto;
+ u8 ver;
+ int ret;
+
+ if (!pskb_may_pull(skb, 12))
+ goto drop;
+
+ ver = skb->data[1]&0x7f;
+ if (ver >= GREPROTO_MAX)
+ goto drop;
+
+ rcu_read_lock();
+ proto = rcu_dereference(gre_proto[ver]);
+ if (!proto || !proto->handler)
+ goto drop_unlock;
+ ret = proto->handler(skb);
+ rcu_read_unlock();
+ return ret;
+
+drop_unlock:
+ rcu_read_unlock();
+drop:
+ kfree_skb(skb);
+ return NET_RX_DROP;
+}
+
+static void gre_err(struct sk_buff *skb, u32 info)
+{
+ const struct gre_protocol *proto;
+ u8 ver;
+
+ if (!pskb_may_pull(skb, 12))
+ goto drop;
+
+ ver = skb->data[1]&0x7f;
+ if (ver >= GREPROTO_MAX)
+ goto drop;
+
+ rcu_read_lock();
+ proto = rcu_dereference(gre_proto[ver]);
+ if (!proto || !proto->err_handler)
+ goto drop_unlock;
+ proto->err_handler(skb, info);
+ rcu_read_unlock();
+ return;
+
+drop_unlock:
+ rcu_read_unlock();
+drop:
+ kfree_skb(skb);
+}
+
+static const struct net_protocol net_gre_protocol = {
+ .handler = gre_rcv,
+ .err_handler = gre_err,
+ .netns_ok = 1,
+};
+
+static int __init gre_init(void)
+{
+ pr_info("GRE over IPv4 demultiplexor driver");
+
+ if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
+ pr_err("gre: can't add protocol\n");
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static void __exit gre_exit(void)
+{
+ inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
+}
+
+module_init(gre_init);
+module_exit(gre_exit);
+
+MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver");
+MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
+MODULE_LICENSE("GPL");
+
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index a0d847c7cba5..96bc7f9475a3 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -379,7 +379,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
inet->tos = ip_hdr(skb)->tos;
daddr = ipc.addr = rt->rt_src;
ipc.opt = NULL;
- ipc.shtx.flags = 0;
+ ipc.tx_flags = 0;
if (icmp_param->replyopts.optlen) {
ipc.opt = &icmp_param->replyopts;
if (ipc.opt->srr)
@@ -538,7 +538,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
inet_sk(sk)->tos = tos;
ipc.addr = iph->saddr;
ipc.opt = &icmp_param.replyopts;
- ipc.shtx.flags = 0;
+ ipc.tx_flags = 0;
{
struct flowi fl = {
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 2a4bb76f2132..c8877c6c7216 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1269,14 +1269,14 @@ void ip_mc_rejoin_group(struct ip_mc_list *im)
if (im->multiaddr == IGMP_ALL_HOSTS)
return;
- if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) {
- igmp_mod_timer(im, IGMP_Initial_Report_Delay);
- return;
- }
- /* else, v3 */
- im->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
- IGMP_Unsolicited_Report_Count;
- igmp_ifc_event(in_dev);
+ /* a failover is happening and switches
+ * must be notified immediately */
+ if (IGMP_V1_SEEN(in_dev))
+ igmp_send_report(in_dev, im, IGMP_HOST_MEMBERSHIP_REPORT);
+ else if (IGMP_V2_SEEN(in_dev))
+ igmp_send_report(in_dev, im, IGMPV2_HOST_MEMBERSHIP_REPORT);
+ else
+ igmp_send_report(in_dev, im, IGMPV3_HOST_MEMBERSHIP_REPORT);
#endif
}
EXPORT_SYMBOL(ip_mc_rejoin_group);
@@ -1418,6 +1418,7 @@ void ip_mc_destroy_dev(struct in_device *in_dev)
write_unlock_bh(&in_dev->mc_list_lock);
}
+/* RTNL is locked */
static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr)
{
struct flowi fl = { .nl_u = { .ip4_u =
@@ -1428,15 +1429,12 @@ static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr)
if (imr->imr_ifindex) {
idev = inetdev_by_index(net, imr->imr_ifindex);
- if (idev)
- __in_dev_put(idev);
return idev;
}
if (imr->imr_address.s_addr) {
- dev = ip_dev_find(net, imr->imr_address.s_addr);
+ dev = __ip_dev_find(net, imr->imr_address.s_addr, false);
if (!dev)
return NULL;
- dev_put(dev);
}
if (!dev && !ip_route_output_key(net, &rt, &fl)) {
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index e5fa2ddce320..ba8042665849 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -425,7 +425,7 @@ static int inet_diag_bc_run(const void *bc, int len,
bc += op->no;
}
}
- return (len == 0);
+ return len == 0;
}
static int valid_cc(const void *bc, int len, int cc)
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index fb7ad5a21ff3..1b344f30b463 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -101,19 +101,43 @@ void inet_put_port(struct sock *sk)
}
EXPORT_SYMBOL(inet_put_port);
-void __inet_inherit_port(struct sock *sk, struct sock *child)
+int __inet_inherit_port(struct sock *sk, struct sock *child)
{
struct inet_hashinfo *table = sk->sk_prot->h.hashinfo;
- const int bhash = inet_bhashfn(sock_net(sk), inet_sk(child)->inet_num,
+ unsigned short port = inet_sk(child)->inet_num;
+ const int bhash = inet_bhashfn(sock_net(sk), port,
table->bhash_size);
struct inet_bind_hashbucket *head = &table->bhash[bhash];
struct inet_bind_bucket *tb;
spin_lock(&head->lock);
tb = inet_csk(sk)->icsk_bind_hash;
+ if (tb->port != port) {
+ /* NOTE: using tproxy and redirecting skbs to a proxy
+ * on a different listener port breaks the assumption
+ * that the listener socket's icsk_bind_hash is the same
+ * as that of the child socket. We have to look up or
+ * create a new bind bucket for the child here. */
+ struct hlist_node *node;
+ inet_bind_bucket_for_each(tb, node, &head->chain) {
+ if (net_eq(ib_net(tb), sock_net(sk)) &&
+ tb->port == port)
+ break;
+ }
+ if (!node) {
+ tb = inet_bind_bucket_create(table->bind_bucket_cachep,
+ sock_net(sk), head, port);
+ if (!tb) {
+ spin_unlock(&head->lock);
+ return -ENOMEM;
+ }
+ }
+ }
sk_add_bind_node(child, &tb->owners);
inet_csk(child)->icsk_bind_hash = tb;
spin_unlock(&head->lock);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(__inet_inherit_port);
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index 9ffa24b9a804..9e94d7cf4f8a 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -72,18 +72,19 @@ static struct kmem_cache *peer_cachep __read_mostly;
#define node_height(x) x->avl_height
#define peer_avl_empty ((struct inet_peer *)&peer_fake_node)
+#define peer_avl_empty_rcu ((struct inet_peer __rcu __force *)&peer_fake_node)
static const struct inet_peer peer_fake_node = {
- .avl_left = peer_avl_empty,
- .avl_right = peer_avl_empty,
+ .avl_left = peer_avl_empty_rcu,
+ .avl_right = peer_avl_empty_rcu,
.avl_height = 0
};
static struct {
- struct inet_peer *root;
+ struct inet_peer __rcu *root;
spinlock_t lock;
int total;
} peers = {
- .root = peer_avl_empty,
+ .root = peer_avl_empty_rcu,
.lock = __SPIN_LOCK_UNLOCKED(peers.lock),
.total = 0,
};
@@ -156,11 +157,14 @@ static void unlink_from_unused(struct inet_peer *p)
*/
#define lookup(_daddr, _stack) \
({ \
- struct inet_peer *u, **v; \
+ struct inet_peer *u; \
+ struct inet_peer __rcu **v; \
\
stackptr = _stack; \
*stackptr++ = &peers.root; \
- for (u = peers.root; u != peer_avl_empty; ) { \
+ for (u = rcu_dereference_protected(peers.root, \
+ lockdep_is_held(&peers.lock)); \
+ u != peer_avl_empty; ) { \
if (_daddr == u->v4daddr) \
break; \
if ((__force __u32)_daddr < (__force __u32)u->v4daddr) \
@@ -168,7 +172,8 @@ static void unlink_from_unused(struct inet_peer *p)
else \
v = &u->avl_right; \
*stackptr++ = v; \
- u = *v; \
+ u = rcu_dereference_protected(*v, \
+ lockdep_is_held(&peers.lock)); \
} \
u; \
})
@@ -209,13 +214,17 @@ static struct inet_peer *lookup_rcu_bh(__be32 daddr)
/* Called with local BH disabled and the pool lock held. */
#define lookup_rightempty(start) \
({ \
- struct inet_peer *u, **v; \
+ struct inet_peer *u; \
+ struct inet_peer __rcu **v; \
*stackptr++ = &start->avl_left; \
v = &start->avl_left; \
- for (u = *v; u->avl_right != peer_avl_empty; ) { \
+ for (u = rcu_dereference_protected(*v, \
+ lockdep_is_held(&peers.lock)); \
+ u->avl_right != peer_avl_empty_rcu; ) { \
v = &u->avl_right; \
*stackptr++ = v; \
- u = *v; \
+ u = rcu_dereference_protected(*v, \
+ lockdep_is_held(&peers.lock)); \
} \
u; \
})
@@ -224,74 +233,86 @@ static struct inet_peer *lookup_rcu_bh(__be32 daddr)
* Variable names are the proof of operation correctness.
* Look into mm/map_avl.c for more detail description of the ideas.
*/
-static void peer_avl_rebalance(struct inet_peer **stack[],
- struct inet_peer ***stackend)
+static void peer_avl_rebalance(struct inet_peer __rcu **stack[],
+ struct inet_peer __rcu ***stackend)
{
- struct inet_peer **nodep, *node, *l, *r;
+ struct inet_peer __rcu **nodep;
+ struct inet_peer *node, *l, *r;
int lh, rh;
while (stackend > stack) {
nodep = *--stackend;
- node = *nodep;
- l = node->avl_left;
- r = node->avl_right;
+ node = rcu_dereference_protected(*nodep,
+ lockdep_is_held(&peers.lock));
+ l = rcu_dereference_protected(node->avl_left,
+ lockdep_is_held(&peers.lock));
+ r = rcu_dereference_protected(node->avl_right,
+ lockdep_is_held(&peers.lock));
lh = node_height(l);
rh = node_height(r);
if (lh > rh + 1) { /* l: RH+2 */
struct inet_peer *ll, *lr, *lrl, *lrr;
int lrh;
- ll = l->avl_left;
- lr = l->avl_right;
+ ll = rcu_dereference_protected(l->avl_left,
+ lockdep_is_held(&peers.lock));
+ lr = rcu_dereference_protected(l->avl_right,
+ lockdep_is_held(&peers.lock));
lrh = node_height(lr);
if (lrh <= node_height(ll)) { /* ll: RH+1 */
- node->avl_left = lr; /* lr: RH or RH+1 */
- node->avl_right = r; /* r: RH */
+ RCU_INIT_POINTER(node->avl_left, lr); /* lr: RH or RH+1 */
+ RCU_INIT_POINTER(node->avl_right, r); /* r: RH */
node->avl_height = lrh + 1; /* RH+1 or RH+2 */
- l->avl_left = ll; /* ll: RH+1 */
- l->avl_right = node; /* node: RH+1 or RH+2 */
+ RCU_INIT_POINTER(l->avl_left, ll); /* ll: RH+1 */
+ RCU_INIT_POINTER(l->avl_right, node); /* node: RH+1 or RH+2 */
l->avl_height = node->avl_height + 1;
- *nodep = l;
+ RCU_INIT_POINTER(*nodep, l);
} else { /* ll: RH, lr: RH+1 */
- lrl = lr->avl_left; /* lrl: RH or RH-1 */
- lrr = lr->avl_right; /* lrr: RH or RH-1 */
- node->avl_left = lrr; /* lrr: RH or RH-1 */
- node->avl_right = r; /* r: RH */
+ lrl = rcu_dereference_protected(lr->avl_left,
+ lockdep_is_held(&peers.lock)); /* lrl: RH or RH-1 */
+ lrr = rcu_dereference_protected(lr->avl_right,
+ lockdep_is_held(&peers.lock)); /* lrr: RH or RH-1 */
+ RCU_INIT_POINTER(node->avl_left, lrr); /* lrr: RH or RH-1 */
+ RCU_INIT_POINTER(node->avl_right, r); /* r: RH */
node->avl_height = rh + 1; /* node: RH+1 */
- l->avl_left = ll; /* ll: RH */
- l->avl_right = lrl; /* lrl: RH or RH-1 */
+ RCU_INIT_POINTER(l->avl_left, ll); /* ll: RH */
+ RCU_INIT_POINTER(l->avl_right, lrl); /* lrl: RH or RH-1 */
l->avl_height = rh + 1; /* l: RH+1 */
- lr->avl_left = l; /* l: RH+1 */
- lr->avl_right = node; /* node: RH+1 */
+ RCU_INIT_POINTER(lr->avl_left, l); /* l: RH+1 */
+ RCU_INIT_POINTER(lr->avl_right, node); /* node: RH+1 */
lr->avl_height = rh + 2;
- *nodep = lr;
+ RCU_INIT_POINTER(*nodep, lr);
}
} else if (rh > lh + 1) { /* r: LH+2 */
struct inet_peer *rr, *rl, *rlr, *rll;
int rlh;
- rr = r->avl_right;
- rl = r->avl_left;
+ rr = rcu_dereference_protected(r->avl_right,
+ lockdep_is_held(&peers.lock));
+ rl = rcu_dereference_protected(r->avl_left,
+ lockdep_is_held(&peers.lock));
rlh = node_height(rl);
if (rlh <= node_height(rr)) { /* rr: LH+1 */
- node->avl_right = rl; /* rl: LH or LH+1 */
- node->avl_left = l; /* l: LH */
+ RCU_INIT_POINTER(node->avl_right, rl); /* rl: LH or LH+1 */
+ RCU_INIT_POINTER(node->avl_left, l); /* l: LH */
node->avl_height = rlh + 1; /* LH+1 or LH+2 */
- r->avl_right = rr; /* rr: LH+1 */
- r->avl_left = node; /* node: LH+1 or LH+2 */
+ RCU_INIT_POINTER(r->avl_right, rr); /* rr: LH+1 */
+ RCU_INIT_POINTER(r->avl_left, node); /* node: LH+1 or LH+2 */
r->avl_height = node->avl_height + 1;
- *nodep = r;
+ RCU_INIT_POINTER(*nodep, r);
} else { /* rr: RH, rl: RH+1 */
- rlr = rl->avl_right; /* rlr: LH or LH-1 */
- rll = rl->avl_left; /* rll: LH or LH-1 */
- node->avl_right = rll; /* rll: LH or LH-1 */
- node->avl_left = l; /* l: LH */
+ rlr = rcu_dereference_protected(rl->avl_right,
+ lockdep_is_held(&peers.lock)); /* rlr: LH or LH-1 */
+ rll = rcu_dereference_protected(rl->avl_left,
+ lockdep_is_held(&peers.lock)); /* rll: LH or LH-1 */
+ RCU_INIT_POINTER(node->avl_right, rll); /* rll: LH or LH-1 */
+ RCU_INIT_POINTER(node->avl_left, l); /* l: LH */
node->avl_height = lh + 1; /* node: LH+1 */
- r->avl_right = rr; /* rr: LH */
- r->avl_left = rlr; /* rlr: LH or LH-1 */
+ RCU_INIT_POINTER(r->avl_right, rr); /* rr: LH */
+ RCU_INIT_POINTER(r->avl_left, rlr); /* rlr: LH or LH-1 */
r->avl_height = lh + 1; /* r: LH+1 */
- rl->avl_right = r; /* r: LH+1 */
- rl->avl_left = node; /* node: LH+1 */
+ RCU_INIT_POINTER(rl->avl_right, r); /* r: LH+1 */
+ RCU_INIT_POINTER(rl->avl_left, node); /* node: LH+1 */
rl->avl_height = lh + 2;
- *nodep = rl;
+ RCU_INIT_POINTER(*nodep, rl);
}
} else {
node->avl_height = (lh > rh ? lh : rh) + 1;
@@ -303,10 +324,10 @@ static void peer_avl_rebalance(struct inet_peer **stack[],
#define link_to_pool(n) \
do { \
n->avl_height = 1; \
- n->avl_left = peer_avl_empty; \
- n->avl_right = peer_avl_empty; \
- smp_wmb(); /* lockless readers can catch us now */ \
- **--stackptr = n; \
+ n->avl_left = peer_avl_empty_rcu; \
+ n->avl_right = peer_avl_empty_rcu; \
+ /* lockless readers can catch us now */ \
+ rcu_assign_pointer(**--stackptr, n); \
peer_avl_rebalance(stack, stackptr); \
} while (0)
@@ -330,24 +351,25 @@ static void unlink_from_pool(struct inet_peer *p)
* We use refcnt=-1 to alert lockless readers this entry is deleted.
*/
if (atomic_cmpxchg(&p->refcnt, 1, -1) == 1) {
- struct inet_peer **stack[PEER_MAXDEPTH];
- struct inet_peer ***stackptr, ***delp;
+ struct inet_peer __rcu **stack[PEER_MAXDEPTH];
+ struct inet_peer __rcu ***stackptr, ***delp;
if (lookup(p->v4daddr, stack) != p)
BUG();
delp = stackptr - 1; /* *delp[0] == p */
- if (p->avl_left == peer_avl_empty) {
+ if (p->avl_left == peer_avl_empty_rcu) {
*delp[0] = p->avl_right;
--stackptr;
} else {
/* look for a node to insert instead of p */
struct inet_peer *t;
t = lookup_rightempty(p);
- BUG_ON(*stackptr[-1] != t);
+ BUG_ON(rcu_dereference_protected(*stackptr[-1],
+ lockdep_is_held(&peers.lock)) != t);
**--stackptr = t->avl_left;
/* t is removed, t->v4daddr > x->v4daddr for any
* x in p->avl_left subtree.
* Put t in the old place of p. */
- *delp[0] = t;
+ RCU_INIT_POINTER(*delp[0], t);
t->avl_left = p->avl_left;
t->avl_right = p->avl_right;
t->avl_height = p->avl_height;
@@ -414,7 +436,7 @@ static int cleanup_once(unsigned long ttl)
struct inet_peer *inet_getpeer(__be32 daddr, int create)
{
struct inet_peer *p;
- struct inet_peer **stack[PEER_MAXDEPTH], ***stackptr;
+ struct inet_peer __rcu **stack[PEER_MAXDEPTH], ***stackptr;
/* Look up for the address quickly, lockless.
* Because of a concurrent writer, we might not find an existing entry.
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index b7c41654dde5..168440834ade 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -116,11 +116,11 @@ static int ip4_frag_match(struct inet_frag_queue *q, void *a)
struct ip4_create_arg *arg = a;
qp = container_of(q, struct ipq, q);
- return (qp->id == arg->iph->id &&
+ return qp->id == arg->iph->id &&
qp->saddr == arg->iph->saddr &&
qp->daddr == arg->iph->daddr &&
qp->protocol == arg->iph->protocol &&
- qp->user == arg->user);
+ qp->user == arg->user;
}
/* Memory Tracking Functions. */
@@ -542,7 +542,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
/* If the first fragment is fragmented itself, we split
* it to two chunks: the first with data and paged part
* and the second, holding only fragments. */
- if (skb_has_frags(head)) {
+ if (skb_has_frag_list(head)) {
struct sk_buff *clone;
int i, plen = 0;
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 35c93e8b6a46..01087e035b7d 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -44,6 +44,7 @@
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/rtnetlink.h>
+#include <net/gre.h>
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#include <net/ipv6.h>
@@ -63,13 +64,13 @@
We cannot track such dead loops during route installation,
it is infeasible task. The most general solutions would be
to keep skb->encapsulation counter (sort of local ttl),
- and silently drop packet when it expires. It is the best
+ and silently drop packet when it expires. It is a good
solution, but it supposes maintaing new variable in ALL
skb, even if no tunneling is used.
- Current solution: HARD_TX_LOCK lock breaks dead loops.
-
-
+ Current solution: xmit_recursion breaks dead loops. This is a percpu
+ counter, since when we enter the first ndo_xmit(), cpu migration is
+ forbidden. We force an exit if this counter reaches RECURSION_LIMIT
2. Networking dead loops would not kill routers, but would really
kill network. IP hop limit plays role of "t->recursion" in this case,
@@ -128,7 +129,7 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev);
static int ipgre_net_id __read_mostly;
struct ipgre_net {
- struct ip_tunnel *tunnels[4][HASH_SIZE];
+ struct ip_tunnel __rcu *tunnels[4][HASH_SIZE];
struct net_device *fb_tunnel_dev;
};
@@ -158,13 +159,40 @@ struct ipgre_net {
#define tunnels_l tunnels[1]
#define tunnels_wc tunnels[0]
/*
- * Locking : hash tables are protected by RCU and a spinlock
+ * Locking : hash tables are protected by RCU and RTNL
*/
-static DEFINE_SPINLOCK(ipgre_lock);
#define for_each_ip_tunnel_rcu(start) \
for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
+/* often modified stats are per cpu, other are shared (netdev->stats) */
+struct pcpu_tstats {
+ unsigned long rx_packets;
+ unsigned long rx_bytes;
+ unsigned long tx_packets;
+ unsigned long tx_bytes;
+};
+
+static struct net_device_stats *ipgre_get_stats(struct net_device *dev)
+{
+ struct pcpu_tstats sum = { 0 };
+ int i;
+
+ for_each_possible_cpu(i) {
+ const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
+
+ sum.rx_packets += tstats->rx_packets;
+ sum.rx_bytes += tstats->rx_bytes;
+ sum.tx_packets += tstats->tx_packets;
+ sum.tx_bytes += tstats->tx_bytes;
+ }
+ dev->stats.rx_packets = sum.rx_packets;
+ dev->stats.rx_bytes = sum.rx_bytes;
+ dev->stats.tx_packets = sum.tx_packets;
+ dev->stats.tx_bytes = sum.tx_bytes;
+ return &dev->stats;
+}
+
/* Given src, dst and key, find appropriate for input tunnel. */
static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
@@ -173,8 +201,8 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
{
struct net *net = dev_net(dev);
int link = dev->ifindex;
- unsigned h0 = HASH(remote);
- unsigned h1 = HASH(key);
+ unsigned int h0 = HASH(remote);
+ unsigned int h1 = HASH(key);
struct ip_tunnel *t, *cand = NULL;
struct ipgre_net *ign = net_generic(net, ipgre_net_id);
int dev_type = (gre_proto == htons(ETH_P_TEB)) ?
@@ -289,13 +317,13 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
return NULL;
}
-static struct ip_tunnel **__ipgre_bucket(struct ipgre_net *ign,
+static struct ip_tunnel __rcu **__ipgre_bucket(struct ipgre_net *ign,
struct ip_tunnel_parm *parms)
{
__be32 remote = parms->iph.daddr;
__be32 local = parms->iph.saddr;
__be32 key = parms->i_key;
- unsigned h = HASH(key);
+ unsigned int h = HASH(key);
int prio = 0;
if (local)
@@ -308,7 +336,7 @@ static struct ip_tunnel **__ipgre_bucket(struct ipgre_net *ign,
return &ign->tunnels[prio][h];
}
-static inline struct ip_tunnel **ipgre_bucket(struct ipgre_net *ign,
+static inline struct ip_tunnel __rcu **ipgre_bucket(struct ipgre_net *ign,
struct ip_tunnel *t)
{
return __ipgre_bucket(ign, &t->parms);
@@ -316,23 +344,22 @@ static inline struct ip_tunnel **ipgre_bucket(struct ipgre_net *ign,
static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t)
{
- struct ip_tunnel **tp = ipgre_bucket(ign, t);
+ struct ip_tunnel __rcu **tp = ipgre_bucket(ign, t);
- spin_lock_bh(&ipgre_lock);
- t->next = *tp;
+ rcu_assign_pointer(t->next, rtnl_dereference(*tp));
rcu_assign_pointer(*tp, t);
- spin_unlock_bh(&ipgre_lock);
}
static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t)
{
- struct ip_tunnel **tp;
-
- for (tp = ipgre_bucket(ign, t); *tp; tp = &(*tp)->next) {
- if (t == *tp) {
- spin_lock_bh(&ipgre_lock);
- *tp = t->next;
- spin_unlock_bh(&ipgre_lock);
+ struct ip_tunnel __rcu **tp;
+ struct ip_tunnel *iter;
+
+ for (tp = ipgre_bucket(ign, t);
+ (iter = rtnl_dereference(*tp)) != NULL;
+ tp = &iter->next) {
+ if (t == iter) {
+ rcu_assign_pointer(*tp, t->next);
break;
}
}
@@ -346,10 +373,13 @@ static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
__be32 local = parms->iph.saddr;
__be32 key = parms->i_key;
int link = parms->link;
- struct ip_tunnel *t, **tp;
+ struct ip_tunnel *t;
+ struct ip_tunnel __rcu **tp;
struct ipgre_net *ign = net_generic(net, ipgre_net_id);
- for (tp = __ipgre_bucket(ign, parms); (t = *tp) != NULL; tp = &t->next)
+ for (tp = __ipgre_bucket(ign, parms);
+ (t = rtnl_dereference(*tp)) != NULL;
+ tp = &t->next)
if (local == t->parms.iph.saddr &&
remote == t->parms.iph.daddr &&
key == t->parms.i_key &&
@@ -360,7 +390,7 @@ static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
return t;
}
-static struct ip_tunnel * ipgre_tunnel_locate(struct net *net,
+static struct ip_tunnel *ipgre_tunnel_locate(struct net *net,
struct ip_tunnel_parm *parms, int create)
{
struct ip_tunnel *t, *nt;
@@ -582,7 +612,7 @@ static int ipgre_rcv(struct sk_buff *skb)
if ((tunnel = ipgre_tunnel_lookup(skb->dev,
iph->saddr, iph->daddr, key,
gre_proto))) {
- struct net_device_stats *stats = &tunnel->dev->stats;
+ struct pcpu_tstats *tstats;
secpath_reset(skb);
@@ -606,22 +636,22 @@ static int ipgre_rcv(struct sk_buff *skb)
/* Looped back packet, drop it! */
if (skb_rtable(skb)->fl.iif == 0)
goto drop;
- stats->multicast++;
+ tunnel->dev->stats.multicast++;
skb->pkt_type = PACKET_BROADCAST;
}
#endif
if (((flags&GRE_CSUM) && csum) ||
(!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) {
- stats->rx_crc_errors++;
- stats->rx_errors++;
+ tunnel->dev->stats.rx_crc_errors++;
+ tunnel->dev->stats.rx_errors++;
goto drop;
}
if (tunnel->parms.i_flags&GRE_SEQ) {
if (!(flags&GRE_SEQ) ||
(tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) {
- stats->rx_fifo_errors++;
- stats->rx_errors++;
+ tunnel->dev->stats.rx_fifo_errors++;
+ tunnel->dev->stats.rx_errors++;
goto drop;
}
tunnel->i_seqno = seqno + 1;
@@ -630,8 +660,8 @@ static int ipgre_rcv(struct sk_buff *skb)
/* Warning: All skb pointers will be invalidated! */
if (tunnel->dev->type == ARPHRD_ETHER) {
if (!pskb_may_pull(skb, ETH_HLEN)) {
- stats->rx_length_errors++;
- stats->rx_errors++;
+ tunnel->dev->stats.rx_length_errors++;
+ tunnel->dev->stats.rx_errors++;
goto drop;
}
@@ -640,14 +670,19 @@ static int ipgre_rcv(struct sk_buff *skb)
skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
}
- skb_tunnel_rx(skb, tunnel->dev);
+ tstats = this_cpu_ptr(tunnel->dev->tstats);
+ tstats->rx_packets++;
+ tstats->rx_bytes += skb->len;
+
+ __skb_tunnel_rx(skb, tunnel->dev);
skb_reset_network_header(skb);
ipgre_ecn_decapsulate(iph, skb);
netif_rx(skb);
+
rcu_read_unlock();
- return(0);
+ return 0;
}
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
@@ -655,20 +690,19 @@ drop:
rcu_read_unlock();
drop_nolock:
kfree_skb(skb);
- return(0);
+ return 0;
}
static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
+ struct pcpu_tstats *tstats;
struct iphdr *old_iph = ip_hdr(skb);
struct iphdr *tiph;
u8 tos;
__be16 df;
struct rtable *rt; /* Route to the other host */
- struct net_device *tdev; /* Device to other host */
+ struct net_device *tdev; /* Device to other host */
struct iphdr *iph; /* Our new IP header */
unsigned int max_headroom; /* The extra header space needed */
int gre_hlen;
@@ -690,7 +724,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
/* NBMA tunnel */
if (skb_dst(skb) == NULL) {
- stats->tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
goto tx_error;
}
@@ -736,14 +770,20 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
}
{
- struct flowi fl = { .oif = tunnel->parms.link,
- .nl_u = { .ip4_u =
- { .daddr = dst,
- .saddr = tiph->saddr,
- .tos = RT_TOS(tos) } },
- .proto = IPPROTO_GRE };
+ struct flowi fl = {
+ .oif = tunnel->parms.link,
+ .nl_u = {
+ .ip4_u = {
+ .daddr = dst,
+ .saddr = tiph->saddr,
+ .tos = RT_TOS(tos)
+ }
+ },
+ .proto = IPPROTO_GRE
+ }
+;
if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
- stats->tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
goto tx_error;
}
}
@@ -751,7 +791,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
if (tdev == dev) {
ip_rt_put(rt);
- stats->collisions++;
+ dev->stats.collisions++;
goto tx_error;
}
@@ -814,7 +854,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
dev->needed_headroom = max_headroom;
if (!new_skb) {
ip_rt_put(rt);
- txq->tx_dropped++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -881,15 +921,15 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
}
nf_reset(skb);
-
- IPTUNNEL_XMIT();
+ tstats = this_cpu_ptr(dev->tstats);
+ __IPTUNNEL_XMIT(tstats, &dev->stats);
return NETDEV_TX_OK;
tx_error_icmp:
dst_link_failure(skb);
tx_error:
- stats->tx_errors++;
+ dev->stats.tx_errors++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -909,13 +949,19 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev)
/* Guess output device to choose reasonable mtu and needed_headroom */
if (iph->daddr) {
- struct flowi fl = { .oif = tunnel->parms.link,
- .nl_u = { .ip4_u =
- { .daddr = iph->daddr,
- .saddr = iph->saddr,
- .tos = RT_TOS(iph->tos) } },
- .proto = IPPROTO_GRE };
+ struct flowi fl = {
+ .oif = tunnel->parms.link,
+ .nl_u = {
+ .ip4_u = {
+ .daddr = iph->daddr,
+ .saddr = iph->saddr,
+ .tos = RT_TOS(iph->tos)
+ }
+ },
+ .proto = IPPROTO_GRE
+ };
struct rtable *rt;
+
if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
tdev = rt->dst.dev;
ip_rt_put(rt);
@@ -1012,7 +1058,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
break;
}
} else {
- unsigned nflags = 0;
+ unsigned int nflags = 0;
t = netdev_priv(dev);
@@ -1026,6 +1072,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
break;
}
ipgre_tunnel_unlink(ign, t);
+ synchronize_net();
t->parms.iph.saddr = p.iph.saddr;
t->parms.iph.daddr = p.iph.daddr;
t->parms.i_key = p.i_key;
@@ -1125,7 +1172,7 @@ static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
- const void *daddr, const void *saddr, unsigned len)
+ const void *daddr, const void *saddr, unsigned int len)
{
struct ip_tunnel *t = netdev_priv(dev);
struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
@@ -1167,13 +1214,19 @@ static int ipgre_open(struct net_device *dev)
struct ip_tunnel *t = netdev_priv(dev);
if (ipv4_is_multicast(t->parms.iph.daddr)) {
- struct flowi fl = { .oif = t->parms.link,
- .nl_u = { .ip4_u =
- { .daddr = t->parms.iph.daddr,
- .saddr = t->parms.iph.saddr,
- .tos = RT_TOS(t->parms.iph.tos) } },
- .proto = IPPROTO_GRE };
+ struct flowi fl = {
+ .oif = t->parms.link,
+ .nl_u = {
+ .ip4_u = {
+ .daddr = t->parms.iph.daddr,
+ .saddr = t->parms.iph.saddr,
+ .tos = RT_TOS(t->parms.iph.tos)
+ }
+ },
+ .proto = IPPROTO_GRE
+ };
struct rtable *rt;
+
if (ip_route_output_key(dev_net(dev), &rt, &fl))
return -EADDRNOTAVAIL;
dev = rt->dst.dev;
@@ -1193,10 +1246,8 @@ static int ipgre_close(struct net_device *dev)
if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
struct in_device *in_dev;
in_dev = inetdev_by_index(dev_net(dev), t->mlink);
- if (in_dev) {
+ if (in_dev)
ip_mc_dec_group(in_dev, t->parms.iph.daddr);
- in_dev_put(in_dev);
- }
}
return 0;
}
@@ -1213,12 +1264,19 @@ static const struct net_device_ops ipgre_netdev_ops = {
.ndo_start_xmit = ipgre_tunnel_xmit,
.ndo_do_ioctl = ipgre_tunnel_ioctl,
.ndo_change_mtu = ipgre_tunnel_change_mtu,
+ .ndo_get_stats = ipgre_get_stats,
};
+static void ipgre_dev_free(struct net_device *dev)
+{
+ free_percpu(dev->tstats);
+ free_netdev(dev);
+}
+
static void ipgre_tunnel_setup(struct net_device *dev)
{
dev->netdev_ops = &ipgre_netdev_ops;
- dev->destructor = free_netdev;
+ dev->destructor = ipgre_dev_free;
dev->type = ARPHRD_IPGRE;
dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
@@ -1256,6 +1314,10 @@ static int ipgre_tunnel_init(struct net_device *dev)
} else
dev->header_ops = &ipgre_header_ops;
+ dev->tstats = alloc_percpu(struct pcpu_tstats);
+ if (!dev->tstats)
+ return -ENOMEM;
+
return 0;
}
@@ -1274,14 +1336,13 @@ static void ipgre_fb_tunnel_init(struct net_device *dev)
tunnel->hlen = sizeof(struct iphdr) + 4;
dev_hold(dev);
- ign->tunnels_wc[0] = tunnel;
+ rcu_assign_pointer(ign->tunnels_wc[0], tunnel);
}
-static const struct net_protocol ipgre_protocol = {
- .handler = ipgre_rcv,
- .err_handler = ipgre_err,
- .netns_ok = 1,
+static const struct gre_protocol ipgre_protocol = {
+ .handler = ipgre_rcv,
+ .err_handler = ipgre_err,
};
static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
@@ -1291,11 +1352,13 @@ static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
for (prio = 0; prio < 4; prio++) {
int h;
for (h = 0; h < HASH_SIZE; h++) {
- struct ip_tunnel *t = ign->tunnels[prio][h];
+ struct ip_tunnel *t;
+
+ t = rtnl_dereference(ign->tunnels[prio][h]);
while (t != NULL) {
unregister_netdevice_queue(t->dev, head);
- t = t->next;
+ t = rtnl_dereference(t->next);
}
}
}
@@ -1441,6 +1504,10 @@ static int ipgre_tap_init(struct net_device *dev)
ipgre_tunnel_bind_dev(dev);
+ dev->tstats = alloc_percpu(struct pcpu_tstats);
+ if (!dev->tstats)
+ return -ENOMEM;
+
return 0;
}
@@ -1451,6 +1518,7 @@ static const struct net_device_ops ipgre_tap_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = ipgre_tunnel_change_mtu,
+ .ndo_get_stats = ipgre_get_stats,
};
static void ipgre_tap_setup(struct net_device *dev)
@@ -1459,7 +1527,7 @@ static void ipgre_tap_setup(struct net_device *dev)
ether_setup(dev);
dev->netdev_ops = &ipgre_tap_netdev_ops;
- dev->destructor = free_netdev;
+ dev->destructor = ipgre_dev_free;
dev->iflink = 0;
dev->features |= NETIF_F_NETNS_LOCAL;
@@ -1487,6 +1555,10 @@ static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nla
if (!tb[IFLA_MTU])
dev->mtu = mtu;
+ /* Can use a lockless transmit, unless we generate output sequences */
+ if (!(nt->parms.o_flags & GRE_SEQ))
+ dev->features |= NETIF_F_LLTX;
+
err = register_netdevice(dev);
if (err)
goto out;
@@ -1522,7 +1594,7 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
t = nt;
if (dev->type != ARPHRD_ETHER) {
- unsigned nflags = 0;
+ unsigned int nflags = 0;
if (ipv4_is_multicast(p.iph.daddr))
nflags = IFF_BROADCAST;
@@ -1663,7 +1735,7 @@ static int __init ipgre_init(void)
if (err < 0)
return err;
- err = inet_add_protocol(&ipgre_protocol, IPPROTO_GRE);
+ err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
if (err < 0) {
printk(KERN_INFO "ipgre init: can't add protocol\n");
goto add_proto_failed;
@@ -1683,7 +1755,7 @@ out:
tap_ops_failed:
rtnl_link_unregister(&ipgre_link_ops);
rtnl_link_failed:
- inet_del_protocol(&ipgre_protocol, IPPROTO_GRE);
+ gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
add_proto_failed:
unregister_pernet_device(&ipgre_net_ops);
goto out;
@@ -1693,7 +1765,7 @@ static void __exit ipgre_fini(void)
{
rtnl_link_unregister(&ipgre_tap_ops);
rtnl_link_unregister(&ipgre_link_ops);
- if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0)
+ if (gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0)
printk(KERN_INFO "ipgre close: can't remove protocol\n");
unregister_pernet_device(&ipgre_net_ops);
}
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index ba9836c488ed..1906fa35860c 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -466,7 +466,7 @@ error:
}
return -EINVAL;
}
-
+EXPORT_SYMBOL(ip_options_compile);
/*
* Undo all the changes done by ip_options_compile().
@@ -646,3 +646,4 @@ int ip_options_rcv_srr(struct sk_buff *skb)
}
return 0;
}
+EXPORT_SYMBOL(ip_options_rcv_srr);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 7649d7750075..439d2a34ee44 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -487,7 +487,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
* LATER: this step can be merged to real generation of fragments,
* we can switch to copy when see the first bad fragment.
*/
- if (skb_has_frags(skb)) {
+ if (skb_has_frag_list(skb)) {
struct sk_buff *frag, *frag2;
int first_len = skb_pagelen(skb);
@@ -844,10 +844,9 @@ int ip_append_data(struct sock *sk,
inet->cork.length = 0;
sk->sk_sndmsg_page = NULL;
sk->sk_sndmsg_off = 0;
- if ((exthdrlen = rt->dst.header_len) != 0) {
- length += exthdrlen;
- transhdrlen += exthdrlen;
- }
+ exthdrlen = rt->dst.header_len;
+ length += exthdrlen;
+ transhdrlen += exthdrlen;
} else {
rt = (struct rtable *)inet->cork.dst;
if (inet->cork.flags & IPCORK_OPT)
@@ -934,16 +933,19 @@ alloc_new_skb:
!(rt->dst.dev->features&NETIF_F_SG))
alloclen = mtu;
else
- alloclen = datalen + fragheaderlen;
+ alloclen = fraglen;
/* The last fragment gets additional space at tail.
* Note, with MSG_MORE we overallocate on fragments,
* because we have no idea what fragment will be
* the last.
*/
- if (datalen == length + fraggap)
+ if (datalen == length + fraggap) {
alloclen += rt->dst.trailer_len;
-
+ /* make sure mtu is not reached */
+ if (datalen > mtu - fragheaderlen - rt->dst.trailer_len)
+ datalen -= ALIGN(rt->dst.trailer_len, 8);
+ }
if (transhdrlen) {
skb = sock_alloc_send_skb(sk,
alloclen + hh_len + 15,
@@ -960,7 +962,7 @@ alloc_new_skb:
else
/* only the initial fragment is
time stamped */
- ipc->shtx.flags = 0;
+ ipc->tx_flags = 0;
}
if (skb == NULL)
goto error;
@@ -971,7 +973,7 @@ alloc_new_skb:
skb->ip_summed = csummode;
skb->csum = 0;
skb_reserve(skb, hh_len);
- *skb_tx(skb) = ipc->shtx;
+ skb_shinfo(skb)->tx_flags = ipc->tx_flags;
/*
* Find where to start putting bytes.
@@ -1391,7 +1393,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
daddr = ipc.addr = rt->rt_src;
ipc.opt = NULL;
- ipc.shtx.flags = 0;
+ ipc.tx_flags = 0;
if (replyopts.opt.optlen) {
ipc.opt = &replyopts.opt;
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 64b70ad162e3..3948c86e59ca 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -238,7 +238,7 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
but receiver should be enough clever f.e. to forward mtrace requests,
sent to multicast group to reach destination designated router.
*/
-struct ip_ra_chain *ip_ra_chain;
+struct ip_ra_chain __rcu *ip_ra_chain;
static DEFINE_SPINLOCK(ip_ra_lock);
@@ -253,7 +253,8 @@ static void ip_ra_destroy_rcu(struct rcu_head *head)
int ip_ra_control(struct sock *sk, unsigned char on,
void (*destructor)(struct sock *))
{
- struct ip_ra_chain *ra, *new_ra, **rap;
+ struct ip_ra_chain *ra, *new_ra;
+ struct ip_ra_chain __rcu **rap;
if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num == IPPROTO_RAW)
return -EINVAL;
@@ -261,7 +262,10 @@ int ip_ra_control(struct sock *sk, unsigned char on,
new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
spin_lock_bh(&ip_ra_lock);
- for (rap = &ip_ra_chain; (ra = *rap) != NULL; rap = &ra->next) {
+ for (rap = &ip_ra_chain;
+ (ra = rcu_dereference_protected(*rap,
+ lockdep_is_held(&ip_ra_lock))) != NULL;
+ rap = &ra->next) {
if (ra->sk == sk) {
if (on) {
spin_unlock_bh(&ip_ra_lock);
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index ec036731a70b..cd300aaee78f 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -122,31 +122,59 @@
static int ipip_net_id __read_mostly;
struct ipip_net {
- struct ip_tunnel *tunnels_r_l[HASH_SIZE];
- struct ip_tunnel *tunnels_r[HASH_SIZE];
- struct ip_tunnel *tunnels_l[HASH_SIZE];
- struct ip_tunnel *tunnels_wc[1];
- struct ip_tunnel **tunnels[4];
+ struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE];
+ struct ip_tunnel __rcu *tunnels_r[HASH_SIZE];
+ struct ip_tunnel __rcu *tunnels_l[HASH_SIZE];
+ struct ip_tunnel __rcu *tunnels_wc[1];
+ struct ip_tunnel __rcu **tunnels[4];
struct net_device *fb_tunnel_dev;
};
-static void ipip_tunnel_init(struct net_device *dev);
+static int ipip_tunnel_init(struct net_device *dev);
static void ipip_tunnel_setup(struct net_device *dev);
+static void ipip_dev_free(struct net_device *dev);
/*
- * Locking : hash tables are protected by RCU and a spinlock
+ * Locking : hash tables are protected by RCU and RTNL
*/
-static DEFINE_SPINLOCK(ipip_lock);
#define for_each_ip_tunnel_rcu(start) \
for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
+/* often modified stats are per cpu, other are shared (netdev->stats) */
+struct pcpu_tstats {
+ unsigned long rx_packets;
+ unsigned long rx_bytes;
+ unsigned long tx_packets;
+ unsigned long tx_bytes;
+};
+
+static struct net_device_stats *ipip_get_stats(struct net_device *dev)
+{
+ struct pcpu_tstats sum = { 0 };
+ int i;
+
+ for_each_possible_cpu(i) {
+ const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
+
+ sum.rx_packets += tstats->rx_packets;
+ sum.rx_bytes += tstats->rx_bytes;
+ sum.tx_packets += tstats->tx_packets;
+ sum.tx_bytes += tstats->tx_bytes;
+ }
+ dev->stats.rx_packets = sum.rx_packets;
+ dev->stats.rx_bytes = sum.rx_bytes;
+ dev->stats.tx_packets = sum.tx_packets;
+ dev->stats.tx_bytes = sum.tx_bytes;
+ return &dev->stats;
+}
+
static struct ip_tunnel * ipip_tunnel_lookup(struct net *net,
__be32 remote, __be32 local)
{
- unsigned h0 = HASH(remote);
- unsigned h1 = HASH(local);
+ unsigned int h0 = HASH(remote);
+ unsigned int h1 = HASH(local);
struct ip_tunnel *t;
struct ipip_net *ipn = net_generic(net, ipip_net_id);
@@ -169,12 +197,12 @@ static struct ip_tunnel * ipip_tunnel_lookup(struct net *net,
return NULL;
}
-static struct ip_tunnel **__ipip_bucket(struct ipip_net *ipn,
+static struct ip_tunnel __rcu **__ipip_bucket(struct ipip_net *ipn,
struct ip_tunnel_parm *parms)
{
__be32 remote = parms->iph.daddr;
__be32 local = parms->iph.saddr;
- unsigned h = 0;
+ unsigned int h = 0;
int prio = 0;
if (remote) {
@@ -188,7 +216,7 @@ static struct ip_tunnel **__ipip_bucket(struct ipip_net *ipn,
return &ipn->tunnels[prio][h];
}
-static inline struct ip_tunnel **ipip_bucket(struct ipip_net *ipn,
+static inline struct ip_tunnel __rcu **ipip_bucket(struct ipip_net *ipn,
struct ip_tunnel *t)
{
return __ipip_bucket(ipn, &t->parms);
@@ -196,13 +224,14 @@ static inline struct ip_tunnel **ipip_bucket(struct ipip_net *ipn,
static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t)
{
- struct ip_tunnel **tp;
-
- for (tp = ipip_bucket(ipn, t); *tp; tp = &(*tp)->next) {
- if (t == *tp) {
- spin_lock_bh(&ipip_lock);
- *tp = t->next;
- spin_unlock_bh(&ipip_lock);
+ struct ip_tunnel __rcu **tp;
+ struct ip_tunnel *iter;
+
+ for (tp = ipip_bucket(ipn, t);
+ (iter = rtnl_dereference(*tp)) != NULL;
+ tp = &iter->next) {
+ if (t == iter) {
+ rcu_assign_pointer(*tp, t->next);
break;
}
}
@@ -210,12 +239,10 @@ static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t)
static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t)
{
- struct ip_tunnel **tp = ipip_bucket(ipn, t);
+ struct ip_tunnel __rcu **tp = ipip_bucket(ipn, t);
- spin_lock_bh(&ipip_lock);
- t->next = *tp;
+ rcu_assign_pointer(t->next, rtnl_dereference(*tp));
rcu_assign_pointer(*tp, t);
- spin_unlock_bh(&ipip_lock);
}
static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
@@ -223,12 +250,15 @@ static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
{
__be32 remote = parms->iph.daddr;
__be32 local = parms->iph.saddr;
- struct ip_tunnel *t, **tp, *nt;
+ struct ip_tunnel *t, *nt;
+ struct ip_tunnel __rcu **tp;
struct net_device *dev;
char name[IFNAMSIZ];
struct ipip_net *ipn = net_generic(net, ipip_net_id);
- for (tp = __ipip_bucket(ipn, parms); (t = *tp) != NULL; tp = &t->next) {
+ for (tp = __ipip_bucket(ipn, parms);
+ (t = rtnl_dereference(*tp)) != NULL;
+ tp = &t->next) {
if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr)
return t;
}
@@ -238,7 +268,7 @@ static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
if (parms->name[0])
strlcpy(name, parms->name, IFNAMSIZ);
else
- sprintf(name, "tunl%%d");
+ strcpy(name, "tunl%d");
dev = alloc_netdev(sizeof(*t), name, ipip_tunnel_setup);
if (dev == NULL)
@@ -254,7 +284,8 @@ static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
nt = netdev_priv(dev);
nt->parms = *parms;
- ipip_tunnel_init(dev);
+ if (ipip_tunnel_init(dev) < 0)
+ goto failed_free;
if (register_netdevice(dev) < 0)
goto failed_free;
@@ -264,20 +295,19 @@ static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
return nt;
failed_free:
- free_netdev(dev);
+ ipip_dev_free(dev);
return NULL;
}
+/* called with RTNL */
static void ipip_tunnel_uninit(struct net_device *dev)
{
struct net *net = dev_net(dev);
struct ipip_net *ipn = net_generic(net, ipip_net_id);
- if (dev == ipn->fb_tunnel_dev) {
- spin_lock_bh(&ipip_lock);
- ipn->tunnels_wc[0] = NULL;
- spin_unlock_bh(&ipip_lock);
- } else
+ if (dev == ipn->fb_tunnel_dev)
+ rcu_assign_pointer(ipn->tunnels_wc[0], NULL);
+ else
ipip_tunnel_unlink(ipn, netdev_priv(dev));
dev_put(dev);
}
@@ -359,8 +389,10 @@ static int ipip_rcv(struct sk_buff *skb)
const struct iphdr *iph = ip_hdr(skb);
rcu_read_lock();
- if ((tunnel = ipip_tunnel_lookup(dev_net(skb->dev),
- iph->saddr, iph->daddr)) != NULL) {
+ tunnel = ipip_tunnel_lookup(dev_net(skb->dev), iph->saddr, iph->daddr);
+ if (tunnel != NULL) {
+ struct pcpu_tstats *tstats;
+
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
rcu_read_unlock();
kfree_skb(skb);
@@ -374,10 +406,16 @@ static int ipip_rcv(struct sk_buff *skb)
skb->protocol = htons(ETH_P_IP);
skb->pkt_type = PACKET_HOST;
- skb_tunnel_rx(skb, tunnel->dev);
+ tstats = this_cpu_ptr(tunnel->dev->tstats);
+ tstats->rx_packets++;
+ tstats->rx_bytes += skb->len;
+
+ __skb_tunnel_rx(skb, tunnel->dev);
ipip_ecn_decapsulate(iph, skb);
+
netif_rx(skb);
+
rcu_read_unlock();
return 0;
}
@@ -394,13 +432,12 @@ static int ipip_rcv(struct sk_buff *skb)
static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
+ struct pcpu_tstats *tstats;
struct iphdr *tiph = &tunnel->parms.iph;
u8 tos = tunnel->parms.iph.tos;
__be16 df = tiph->frag_off;
struct rtable *rt; /* Route to the other host */
- struct net_device *tdev; /* Device to other host */
+ struct net_device *tdev; /* Device to other host */
struct iphdr *old_iph = ip_hdr(skb);
struct iphdr *iph; /* Our new IP header */
unsigned int max_headroom; /* The extra header space needed */
@@ -410,13 +447,13 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->protocol != htons(ETH_P_IP))
goto tx_error;
- if (tos&1)
+ if (tos & 1)
tos = old_iph->tos;
if (!dst) {
/* NBMA tunnel */
if ((rt = skb_rtable(skb)) == NULL) {
- stats->tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
goto tx_error;
}
if ((dst = rt->rt_gateway) == 0)
@@ -424,14 +461,20 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
}
{
- struct flowi fl = { .oif = tunnel->parms.link,
- .nl_u = { .ip4_u =
- { .daddr = dst,
- .saddr = tiph->saddr,
- .tos = RT_TOS(tos) } },
- .proto = IPPROTO_IPIP };
+ struct flowi fl = {
+ .oif = tunnel->parms.link,
+ .nl_u = {
+ .ip4_u = {
+ .daddr = dst,
+ .saddr = tiph->saddr,
+ .tos = RT_TOS(tos)
+ }
+ },
+ .proto = IPPROTO_IPIP
+ };
+
if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
- stats->tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
goto tx_error_icmp;
}
}
@@ -439,7 +482,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
if (tdev == dev) {
ip_rt_put(rt);
- stats->collisions++;
+ dev->stats.collisions++;
goto tx_error;
}
@@ -449,7 +492,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
if (mtu < 68) {
- stats->collisions++;
+ dev->stats.collisions++;
ip_rt_put(rt);
goto tx_error;
}
@@ -485,7 +528,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
if (!new_skb) {
ip_rt_put(rt);
- txq->tx_dropped++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -522,14 +565,14 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
iph->ttl = old_iph->ttl;
nf_reset(skb);
-
- IPTUNNEL_XMIT();
+ tstats = this_cpu_ptr(dev->tstats);
+ __IPTUNNEL_XMIT(tstats, &dev->stats);
return NETDEV_TX_OK;
tx_error_icmp:
dst_link_failure(skb);
tx_error:
- stats->tx_errors++;
+ dev->stats.tx_errors++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -544,13 +587,19 @@ static void ipip_tunnel_bind_dev(struct net_device *dev)
iph = &tunnel->parms.iph;
if (iph->daddr) {
- struct flowi fl = { .oif = tunnel->parms.link,
- .nl_u = { .ip4_u =
- { .daddr = iph->daddr,
- .saddr = iph->saddr,
- .tos = RT_TOS(iph->tos) } },
- .proto = IPPROTO_IPIP };
+ struct flowi fl = {
+ .oif = tunnel->parms.link,
+ .nl_u = {
+ .ip4_u = {
+ .daddr = iph->daddr,
+ .saddr = iph->saddr,
+ .tos = RT_TOS(iph->tos)
+ }
+ },
+ .proto = IPPROTO_IPIP
+ };
struct rtable *rt;
+
if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
tdev = rt->dst.dev;
ip_rt_put(rt);
@@ -627,6 +676,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
}
t = netdev_priv(dev);
ipip_tunnel_unlink(ipn, t);
+ synchronize_net();
t->parms.iph.saddr = p.iph.saddr;
t->parms.iph.daddr = p.iph.daddr;
memcpy(dev->dev_addr, &p.iph.saddr, 4);
@@ -696,13 +746,19 @@ static const struct net_device_ops ipip_netdev_ops = {
.ndo_start_xmit = ipip_tunnel_xmit,
.ndo_do_ioctl = ipip_tunnel_ioctl,
.ndo_change_mtu = ipip_tunnel_change_mtu,
-
+ .ndo_get_stats = ipip_get_stats,
};
+static void ipip_dev_free(struct net_device *dev)
+{
+ free_percpu(dev->tstats);
+ free_netdev(dev);
+}
+
static void ipip_tunnel_setup(struct net_device *dev)
{
dev->netdev_ops = &ipip_netdev_ops;
- dev->destructor = free_netdev;
+ dev->destructor = ipip_dev_free;
dev->type = ARPHRD_TUNNEL;
dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr);
@@ -711,10 +767,11 @@ static void ipip_tunnel_setup(struct net_device *dev)
dev->iflink = 0;
dev->addr_len = 4;
dev->features |= NETIF_F_NETNS_LOCAL;
+ dev->features |= NETIF_F_LLTX;
dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
}
-static void ipip_tunnel_init(struct net_device *dev)
+static int ipip_tunnel_init(struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
@@ -725,9 +782,15 @@ static void ipip_tunnel_init(struct net_device *dev)
memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
ipip_tunnel_bind_dev(dev);
+
+ dev->tstats = alloc_percpu(struct pcpu_tstats);
+ if (!dev->tstats)
+ return -ENOMEM;
+
+ return 0;
}
-static void __net_init ipip_fb_tunnel_init(struct net_device *dev)
+static int __net_init ipip_fb_tunnel_init(struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
struct iphdr *iph = &tunnel->parms.iph;
@@ -740,11 +803,16 @@ static void __net_init ipip_fb_tunnel_init(struct net_device *dev)
iph->protocol = IPPROTO_IPIP;
iph->ihl = 5;
+ dev->tstats = alloc_percpu(struct pcpu_tstats);
+ if (!dev->tstats)
+ return -ENOMEM;
+
dev_hold(dev);
- ipn->tunnels_wc[0] = tunnel;
+ rcu_assign_pointer(ipn->tunnels_wc[0], tunnel);
+ return 0;
}
-static struct xfrm_tunnel ipip_handler = {
+static struct xfrm_tunnel ipip_handler __read_mostly = {
.handler = ipip_rcv,
.err_handler = ipip_err,
.priority = 1,
@@ -760,11 +828,12 @@ static void ipip_destroy_tunnels(struct ipip_net *ipn, struct list_head *head)
for (prio = 1; prio < 4; prio++) {
int h;
for (h = 0; h < HASH_SIZE; h++) {
- struct ip_tunnel *t = ipn->tunnels[prio][h];
+ struct ip_tunnel *t;
+ t = rtnl_dereference(ipn->tunnels[prio][h]);
while (t != NULL) {
unregister_netdevice_queue(t->dev, head);
- t = t->next;
+ t = rtnl_dereference(t->next);
}
}
}
@@ -789,7 +858,9 @@ static int __net_init ipip_init_net(struct net *net)
}
dev_net_set(ipn->fb_tunnel_dev, net);
- ipip_fb_tunnel_init(ipn->fb_tunnel_dev);
+ err = ipip_fb_tunnel_init(ipn->fb_tunnel_dev);
+ if (err)
+ goto err_reg_dev;
if ((err = register_netdev(ipn->fb_tunnel_dev)))
goto err_reg_dev;
@@ -797,7 +868,7 @@ static int __net_init ipip_init_net(struct net *net)
return 0;
err_reg_dev:
- free_netdev(ipn->fb_tunnel_dev);
+ ipip_dev_free(ipn->fb_tunnel_dev);
err_alloc_dev:
/* nothing */
return err;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 179fcab866fc..86dd5691af46 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -75,7 +75,7 @@ struct mr_table {
struct net *net;
#endif
u32 id;
- struct sock *mroute_sk;
+ struct sock __rcu *mroute_sk;
struct timer_list ipmr_expire_timer;
struct list_head mfc_unres_queue;
struct list_head mfc_cache_array[MFC_LINES];
@@ -98,7 +98,7 @@ struct ipmr_result {
};
/* Big lock, protecting vif table, mrt cache and mroute socket state.
- Note that the changes are semaphored via rtnl_lock.
+ * Note that the changes are semaphored via rtnl_lock.
*/
static DEFINE_RWLOCK(mrt_lock);
@@ -113,11 +113,11 @@ static DEFINE_RWLOCK(mrt_lock);
static DEFINE_SPINLOCK(mfc_unres_lock);
/* We return to original Alan's scheme. Hash table of resolved
- entries is changed only in process context and protected
- with weak lock mrt_lock. Queue of unresolved entries is protected
- with strong spinlock mfc_unres_lock.
-
- In this case data path is free of exclusive locks at all.
+ * entries is changed only in process context and protected
+ * with weak lock mrt_lock. Queue of unresolved entries is protected
+ * with strong spinlock mfc_unres_lock.
+ *
+ * In this case data path is free of exclusive locks at all.
*/
static struct kmem_cache *mrt_cachep __read_mostly;
@@ -396,9 +396,9 @@ struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
set_fs(KERNEL_DS);
err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL);
set_fs(oldfs);
- } else
+ } else {
err = -EOPNOTSUPP;
-
+ }
dev = NULL;
if (err == 0 &&
@@ -495,7 +495,8 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt)
dev->iflink = 0;
rcu_read_lock();
- if ((in_dev = __in_dev_get_rcu(dev)) == NULL) {
+ in_dev = __in_dev_get_rcu(dev);
+ if (!in_dev) {
rcu_read_unlock();
goto failure;
}
@@ -552,9 +553,10 @@ static int vif_delete(struct mr_table *mrt, int vifi, int notify,
mrt->mroute_reg_vif_num = -1;
#endif
- if (vifi+1 == mrt->maxvif) {
+ if (vifi + 1 == mrt->maxvif) {
int tmp;
- for (tmp=vifi-1; tmp>=0; tmp--) {
+
+ for (tmp = vifi - 1; tmp >= 0; tmp--) {
if (VIF_EXISTS(mrt, tmp))
break;
}
@@ -565,25 +567,33 @@ static int vif_delete(struct mr_table *mrt, int vifi, int notify,
dev_set_allmulti(dev, -1);
- if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
+ in_dev = __in_dev_get_rtnl(dev);
+ if (in_dev) {
IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)--;
ip_rt_multicast_event(in_dev);
}
- if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify)
+ if (v->flags & (VIFF_TUNNEL | VIFF_REGISTER) && !notify)
unregister_netdevice_queue(dev, head);
dev_put(dev);
return 0;
}
-static inline void ipmr_cache_free(struct mfc_cache *c)
+static void ipmr_cache_free_rcu(struct rcu_head *head)
{
+ struct mfc_cache *c = container_of(head, struct mfc_cache, rcu);
+
kmem_cache_free(mrt_cachep, c);
}
+static inline void ipmr_cache_free(struct mfc_cache *c)
+{
+ call_rcu(&c->rcu, ipmr_cache_free_rcu);
+}
+
/* Destroy an unresolved cache entry, killing queued skbs
- and reporting error to netlink readers.
+ * and reporting error to netlink readers.
*/
static void ipmr_destroy_unres(struct mr_table *mrt, struct mfc_cache *c)
@@ -605,8 +615,9 @@ static void ipmr_destroy_unres(struct mr_table *mrt, struct mfc_cache *c)
memset(&e->msg, 0, sizeof(e->msg));
rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
- } else
+ } else {
kfree_skb(skb);
+ }
}
ipmr_cache_free(c);
@@ -724,13 +735,13 @@ static int vif_add(struct net *net, struct mr_table *mrt,
case 0:
if (vifc->vifc_flags == VIFF_USE_IFINDEX) {
dev = dev_get_by_index(net, vifc->vifc_lcl_ifindex);
- if (dev && dev->ip_ptr == NULL) {
+ if (dev && __in_dev_get_rtnl(dev) == NULL) {
dev_put(dev);
return -EADDRNOTAVAIL;
}
- } else
+ } else {
dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
-
+ }
if (!dev)
return -EADDRNOTAVAIL;
err = dev_set_allmulti(dev, 1);
@@ -743,16 +754,16 @@ static int vif_add(struct net *net, struct mr_table *mrt,
return -EINVAL;
}
- if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) {
+ in_dev = __in_dev_get_rtnl(dev);
+ if (!in_dev) {
dev_put(dev);
return -EADDRNOTAVAIL;
}
IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
ip_rt_multicast_event(in_dev);
- /*
- * Fill in the VIF structures
- */
+ /* Fill in the VIF structures */
+
v->rate_limit = vifc->vifc_rate_limit;
v->local = vifc->vifc_lcl_addr.s_addr;
v->remote = vifc->vifc_rmt_addr.s_addr;
@@ -765,14 +776,14 @@ static int vif_add(struct net *net, struct mr_table *mrt,
v->pkt_in = 0;
v->pkt_out = 0;
v->link = dev->ifindex;
- if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER))
+ if (v->flags & (VIFF_TUNNEL | VIFF_REGISTER))
v->link = dev->iflink;
/* And finish update writing critical data */
write_lock_bh(&mrt_lock);
v->dev = dev;
#ifdef CONFIG_IP_PIMSM
- if (v->flags&VIFF_REGISTER)
+ if (v->flags & VIFF_REGISTER)
mrt->mroute_reg_vif_num = vifi;
#endif
if (vifi+1 > mrt->maxvif)
@@ -781,6 +792,7 @@ static int vif_add(struct net *net, struct mr_table *mrt,
return 0;
}
+/* called with rcu_read_lock() */
static struct mfc_cache *ipmr_cache_find(struct mr_table *mrt,
__be32 origin,
__be32 mcastgrp)
@@ -788,7 +800,7 @@ static struct mfc_cache *ipmr_cache_find(struct mr_table *mrt,
int line = MFC_HASH(mcastgrp, origin);
struct mfc_cache *c;
- list_for_each_entry(c, &mrt->mfc_cache_array[line], list) {
+ list_for_each_entry_rcu(c, &mrt->mfc_cache_array[line], list) {
if (c->mfc_origin == origin && c->mfc_mcastgrp == mcastgrp)
return c;
}
@@ -801,19 +813,20 @@ static struct mfc_cache *ipmr_cache_find(struct mr_table *mrt,
static struct mfc_cache *ipmr_cache_alloc(void)
{
struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
- if (c == NULL)
- return NULL;
- c->mfc_un.res.minvif = MAXVIFS;
+
+ if (c)
+ c->mfc_un.res.minvif = MAXVIFS;
return c;
}
static struct mfc_cache *ipmr_cache_alloc_unres(void)
{
struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
- if (c == NULL)
- return NULL;
- skb_queue_head_init(&c->mfc_un.unres.unresolved);
- c->mfc_un.unres.expires = jiffies + 10*HZ;
+
+ if (c) {
+ skb_queue_head_init(&c->mfc_un.unres.unresolved);
+ c->mfc_un.unres.expires = jiffies + 10*HZ;
+ }
return c;
}
@@ -827,17 +840,15 @@ static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt,
struct sk_buff *skb;
struct nlmsgerr *e;
- /*
- * Play the pending entries through our router
- */
+ /* Play the pending entries through our router */
while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
if (ip_hdr(skb)->version == 0) {
struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
if (__ipmr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) {
- nlh->nlmsg_len = (skb_tail_pointer(skb) -
- (u8 *)nlh);
+ nlh->nlmsg_len = skb_tail_pointer(skb) -
+ (u8 *)nlh;
} else {
nlh->nlmsg_type = NLMSG_ERROR;
nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
@@ -848,8 +859,9 @@ static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt,
}
rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
- } else
+ } else {
ip_mr_forward(net, mrt, skb, c, 0);
+ }
}
}
@@ -867,6 +879,7 @@ static int ipmr_cache_report(struct mr_table *mrt,
const int ihl = ip_hdrlen(pkt);
struct igmphdr *igmp;
struct igmpmsg *msg;
+ struct sock *mroute_sk;
int ret;
#ifdef CONFIG_IP_PIMSM
@@ -882,9 +895,9 @@ static int ipmr_cache_report(struct mr_table *mrt,
#ifdef CONFIG_IP_PIMSM
if (assert == IGMPMSG_WHOLEPKT) {
/* Ugly, but we have no choice with this interface.
- Duplicate old header, fix ihl, length etc.
- And all this only to mangle msg->im_msgtype and
- to set msg->im_mbz to "mbz" :-)
+ * Duplicate old header, fix ihl, length etc.
+ * And all this only to mangle msg->im_msgtype and
+ * to set msg->im_mbz to "mbz" :-)
*/
skb_push(skb, sizeof(struct iphdr));
skb_reset_network_header(skb);
@@ -901,39 +914,38 @@ static int ipmr_cache_report(struct mr_table *mrt,
#endif
{
- /*
- * Copy the IP header
- */
+ /* Copy the IP header */
skb->network_header = skb->tail;
skb_put(skb, ihl);
skb_copy_to_linear_data(skb, pkt->data, ihl);
- ip_hdr(skb)->protocol = 0; /* Flag to the kernel this is a route add */
+ ip_hdr(skb)->protocol = 0; /* Flag to the kernel this is a route add */
msg = (struct igmpmsg *)skb_network_header(skb);
msg->im_vif = vifi;
skb_dst_set(skb, dst_clone(skb_dst(pkt)));
- /*
- * Add our header
- */
+ /* Add our header */
- igmp=(struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
+ igmp = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
igmp->type =
msg->im_msgtype = assert;
- igmp->code = 0;
- ip_hdr(skb)->tot_len = htons(skb->len); /* Fix the length */
+ igmp->code = 0;
+ ip_hdr(skb)->tot_len = htons(skb->len); /* Fix the length */
skb->transport_header = skb->network_header;
}
- if (mrt->mroute_sk == NULL) {
+ rcu_read_lock();
+ mroute_sk = rcu_dereference(mrt->mroute_sk);
+ if (mroute_sk == NULL) {
+ rcu_read_unlock();
kfree_skb(skb);
return -EINVAL;
}
- /*
- * Deliver to mrouted
- */
- ret = sock_queue_rcv_skb(mrt->mroute_sk, skb);
+ /* Deliver to mrouted */
+
+ ret = sock_queue_rcv_skb(mroute_sk, skb);
+ rcu_read_unlock();
if (ret < 0) {
if (net_ratelimit())
printk(KERN_WARNING "mroute: pending queue full, dropping entries.\n");
@@ -965,9 +977,7 @@ ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb)
}
if (!found) {
- /*
- * Create a new entry if allowable
- */
+ /* Create a new entry if allowable */
if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
(c = ipmr_cache_alloc_unres()) == NULL) {
@@ -977,16 +987,14 @@ ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb)
return -ENOBUFS;
}
- /*
- * Fill in the new cache entry
- */
+ /* Fill in the new cache entry */
+
c->mfc_parent = -1;
c->mfc_origin = iph->saddr;
c->mfc_mcastgrp = iph->daddr;
- /*
- * Reflect first query at mrouted.
- */
+ /* Reflect first query at mrouted. */
+
err = ipmr_cache_report(mrt, skb, vifi, IGMPMSG_NOCACHE);
if (err < 0) {
/* If the report failed throw the cache entry
@@ -1006,10 +1014,9 @@ ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb)
mod_timer(&mrt->ipmr_expire_timer, c->mfc_un.unres.expires);
}
- /*
- * See if we can append the packet
- */
- if (c->mfc_un.unres.unresolved.qlen>3) {
+ /* See if we can append the packet */
+
+ if (c->mfc_un.unres.unresolved.qlen > 3) {
kfree_skb(skb);
err = -ENOBUFS;
} else {
@@ -1035,9 +1042,7 @@ static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc)
list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[line], list) {
if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
- write_lock_bh(&mrt_lock);
- list_del(&c->list);
- write_unlock_bh(&mrt_lock);
+ list_del_rcu(&c->list);
ipmr_cache_free(c);
return 0;
@@ -1090,9 +1095,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
if (!mrtsock)
c->mfc_flags |= MFC_STATIC;
- write_lock_bh(&mrt_lock);
- list_add(&c->list, &mrt->mfc_cache_array[line]);
- write_unlock_bh(&mrt_lock);
+ list_add_rcu(&c->list, &mrt->mfc_cache_array[line]);
/*
* Check to see if we resolved a queued list. If so we
@@ -1130,26 +1133,21 @@ static void mroute_clean_tables(struct mr_table *mrt)
LIST_HEAD(list);
struct mfc_cache *c, *next;
- /*
- * Shut down all active vif entries
- */
+ /* Shut down all active vif entries */
+
for (i = 0; i < mrt->maxvif; i++) {
- if (!(mrt->vif_table[i].flags&VIFF_STATIC))
+ if (!(mrt->vif_table[i].flags & VIFF_STATIC))
vif_delete(mrt, i, 0, &list);
}
unregister_netdevice_many(&list);
- /*
- * Wipe the cache
- */
+ /* Wipe the cache */
+
for (i = 0; i < MFC_LINES; i++) {
list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) {
- if (c->mfc_flags&MFC_STATIC)
+ if (c->mfc_flags & MFC_STATIC)
continue;
- write_lock_bh(&mrt_lock);
- list_del(&c->list);
- write_unlock_bh(&mrt_lock);
-
+ list_del_rcu(&c->list);
ipmr_cache_free(c);
}
}
@@ -1164,6 +1162,9 @@ static void mroute_clean_tables(struct mr_table *mrt)
}
}
+/* called from ip_ra_control(), before an RCU grace period,
+ * we dont need to call synchronize_rcu() here
+ */
static void mrtsock_destruct(struct sock *sk)
{
struct net *net = sock_net(sk);
@@ -1171,13 +1172,9 @@ static void mrtsock_destruct(struct sock *sk)
rtnl_lock();
ipmr_for_each_table(mrt, net) {
- if (sk == mrt->mroute_sk) {
+ if (sk == rtnl_dereference(mrt->mroute_sk)) {
IPV4_DEVCONF_ALL(net, MC_FORWARDING)--;
-
- write_lock_bh(&mrt_lock);
- mrt->mroute_sk = NULL;
- write_unlock_bh(&mrt_lock);
-
+ rcu_assign_pointer(mrt->mroute_sk, NULL);
mroute_clean_tables(mrt);
}
}
@@ -1204,7 +1201,8 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
return -ENOENT;
if (optname != MRT_INIT) {
- if (sk != mrt->mroute_sk && !capable(CAP_NET_ADMIN))
+ if (sk != rcu_dereference_raw(mrt->mroute_sk) &&
+ !capable(CAP_NET_ADMIN))
return -EACCES;
}
@@ -1217,23 +1215,20 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
return -ENOPROTOOPT;
rtnl_lock();
- if (mrt->mroute_sk) {
+ if (rtnl_dereference(mrt->mroute_sk)) {
rtnl_unlock();
return -EADDRINUSE;
}
ret = ip_ra_control(sk, 1, mrtsock_destruct);
if (ret == 0) {
- write_lock_bh(&mrt_lock);
- mrt->mroute_sk = sk;
- write_unlock_bh(&mrt_lock);
-
+ rcu_assign_pointer(mrt->mroute_sk, sk);
IPV4_DEVCONF_ALL(net, MC_FORWARDING)++;
}
rtnl_unlock();
return ret;
case MRT_DONE:
- if (sk != mrt->mroute_sk)
+ if (sk != rcu_dereference_raw(mrt->mroute_sk))
return -EACCES;
return ip_ra_control(sk, 0, NULL);
case MRT_ADD_VIF:
@@ -1246,7 +1241,8 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
return -ENFILE;
rtnl_lock();
if (optname == MRT_ADD_VIF) {
- ret = vif_add(net, mrt, &vif, sk == mrt->mroute_sk);
+ ret = vif_add(net, mrt, &vif,
+ sk == rtnl_dereference(mrt->mroute_sk));
} else {
ret = vif_delete(mrt, vif.vifc_vifi, 0, NULL);
}
@@ -1267,7 +1263,8 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
if (optname == MRT_DEL_MFC)
ret = ipmr_mfc_delete(mrt, &mfc);
else
- ret = ipmr_mfc_add(net, mrt, &mfc, sk == mrt->mroute_sk);
+ ret = ipmr_mfc_add(net, mrt, &mfc,
+ sk == rtnl_dereference(mrt->mroute_sk));
rtnl_unlock();
return ret;
/*
@@ -1276,7 +1273,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
case MRT_ASSERT:
{
int v;
- if (get_user(v,(int __user *)optval))
+ if (get_user(v, (int __user *)optval))
return -EFAULT;
mrt->mroute_do_assert = (v) ? 1 : 0;
return 0;
@@ -1286,7 +1283,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
{
int v;
- if (get_user(v,(int __user *)optval))
+ if (get_user(v, (int __user *)optval))
return -EFAULT;
v = (v) ? 1 : 0;
@@ -1309,14 +1306,16 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
return -EINVAL;
if (get_user(v, (u32 __user *)optval))
return -EFAULT;
- if (sk == mrt->mroute_sk)
- return -EBUSY;
rtnl_lock();
ret = 0;
- if (!ipmr_new_table(net, v))
- ret = -ENOMEM;
- raw_sk(sk)->ipmr_table = v;
+ if (sk == rtnl_dereference(mrt->mroute_sk)) {
+ ret = -EBUSY;
+ } else {
+ if (!ipmr_new_table(net, v))
+ ret = -ENOMEM;
+ raw_sk(sk)->ipmr_table = v;
+ }
rtnl_unlock();
return ret;
}
@@ -1347,9 +1346,9 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int
if (optname != MRT_VERSION &&
#ifdef CONFIG_IP_PIMSM
- optname!=MRT_PIM &&
+ optname != MRT_PIM &&
#endif
- optname!=MRT_ASSERT)
+ optname != MRT_ASSERT)
return -ENOPROTOOPT;
if (get_user(olr, optlen))
@@ -1416,19 +1415,19 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
if (copy_from_user(&sr, arg, sizeof(sr)))
return -EFAULT;
- read_lock(&mrt_lock);
+ rcu_read_lock();
c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr);
if (c) {
sr.pktcnt = c->mfc_un.res.pkt;
sr.bytecnt = c->mfc_un.res.bytes;
sr.wrong_if = c->mfc_un.res.wrong_if;
- read_unlock(&mrt_lock);
+ rcu_read_unlock();
if (copy_to_user(arg, &sr, sizeof(sr)))
return -EFAULT;
return 0;
}
- read_unlock(&mrt_lock);
+ rcu_read_unlock();
return -EADDRNOTAVAIL;
default:
return -ENOIOCTLCMD;
@@ -1465,7 +1464,7 @@ static struct notifier_block ip_mr_notifier = {
};
/*
- * Encapsulate a packet by attaching a valid IPIP header to it.
+ * Encapsulate a packet by attaching a valid IPIP header to it.
* This avoids tunnel drivers and other mess and gives us the speed so
* important for multicast video.
*/
@@ -1480,7 +1479,7 @@ static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
skb_reset_network_header(skb);
iph = ip_hdr(skb);
- iph->version = 4;
+ iph->version = 4;
iph->tos = old_iph->tos;
iph->ttl = old_iph->ttl;
iph->frag_off = 0;
@@ -1498,7 +1497,7 @@ static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
static inline int ipmr_forward_finish(struct sk_buff *skb)
{
- struct ip_options * opt = &(IPCB(skb)->opt);
+ struct ip_options *opt = &(IPCB(skb)->opt);
IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
@@ -1535,22 +1534,34 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
}
#endif
- if (vif->flags&VIFF_TUNNEL) {
- struct flowi fl = { .oif = vif->link,
- .nl_u = { .ip4_u =
- { .daddr = vif->remote,
- .saddr = vif->local,
- .tos = RT_TOS(iph->tos) } },
- .proto = IPPROTO_IPIP };
+ if (vif->flags & VIFF_TUNNEL) {
+ struct flowi fl = {
+ .oif = vif->link,
+ .nl_u = {
+ .ip4_u = {
+ .daddr = vif->remote,
+ .saddr = vif->local,
+ .tos = RT_TOS(iph->tos)
+ }
+ },
+ .proto = IPPROTO_IPIP
+ };
+
if (ip_route_output_key(net, &rt, &fl))
goto out_free;
encap = sizeof(struct iphdr);
} else {
- struct flowi fl = { .oif = vif->link,
- .nl_u = { .ip4_u =
- { .daddr = iph->daddr,
- .tos = RT_TOS(iph->tos) } },
- .proto = IPPROTO_IPIP };
+ struct flowi fl = {
+ .oif = vif->link,
+ .nl_u = {
+ .ip4_u = {
+ .daddr = iph->daddr,
+ .tos = RT_TOS(iph->tos)
+ }
+ },
+ .proto = IPPROTO_IPIP
+ };
+
if (ip_route_output_key(net, &rt, &fl))
goto out_free;
}
@@ -1559,8 +1570,8 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
if (skb->len+encap > dst_mtu(&rt->dst) && (ntohs(iph->frag_off) & IP_DF)) {
/* Do not fragment multicasts. Alas, IPv4 does not
- allow to send ICMP, so that packets will disappear
- to blackhole.
+ * allow to send ICMP, so that packets will disappear
+ * to blackhole.
*/
IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
@@ -1583,7 +1594,8 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
ip_decrease_ttl(ip_hdr(skb));
/* FIXME: forward and output firewalls used to be called here.
- * What do we do with netfilter? -- RR */
+ * What do we do with netfilter? -- RR
+ */
if (vif->flags & VIFF_TUNNEL) {
ip_encap(skb, vif->local, vif->remote);
/* FIXME: extra output firewall step used to be here. --RR */
@@ -1644,15 +1656,15 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
if (skb_rtable(skb)->fl.iif == 0) {
/* It is our own packet, looped back.
- Very complicated situation...
-
- The best workaround until routing daemons will be
- fixed is not to redistribute packet, if it was
- send through wrong interface. It means, that
- multicast applications WILL NOT work for
- (S,G), which have default multicast route pointing
- to wrong oif. In any case, it is not a good
- idea to use multicasting applications on router.
+ * Very complicated situation...
+ *
+ * The best workaround until routing daemons will be
+ * fixed is not to redistribute packet, if it was
+ * send through wrong interface. It means, that
+ * multicast applications WILL NOT work for
+ * (S,G), which have default multicast route pointing
+ * to wrong oif. In any case, it is not a good
+ * idea to use multicasting applications on router.
*/
goto dont_forward;
}
@@ -1662,9 +1674,9 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
if (true_vifi >= 0 && mrt->mroute_do_assert &&
/* pimsm uses asserts, when switching from RPT to SPT,
- so that we cannot check that packet arrived on an oif.
- It is bad, but otherwise we would need to move pretty
- large chunk of pimd to kernel. Ough... --ANK
+ * so that we cannot check that packet arrived on an oif.
+ * It is bad, but otherwise we would need to move pretty
+ * large chunk of pimd to kernel. Ough... --ANK
*/
(mrt->mroute_do_pim ||
cache->mfc_un.res.ttls[true_vifi] < 255) &&
@@ -1682,10 +1694,12 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
/*
* Forward the frame
*/
- for (ct = cache->mfc_un.res.maxvif-1; ct >= cache->mfc_un.res.minvif; ct--) {
+ for (ct = cache->mfc_un.res.maxvif - 1;
+ ct >= cache->mfc_un.res.minvif; ct--) {
if (ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {
if (psend != -1) {
struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+
if (skb2)
ipmr_queue_xmit(net, mrt, skb2, cache,
psend);
@@ -1696,6 +1710,7 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
if (psend != -1) {
if (local) {
struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+
if (skb2)
ipmr_queue_xmit(net, mrt, skb2, cache, psend);
} else {
@@ -1713,6 +1728,7 @@ dont_forward:
/*
* Multicast packets for forwarding arrive here
+ * Called with rcu_read_lock();
*/
int ip_mr_input(struct sk_buff *skb)
@@ -1724,9 +1740,9 @@ int ip_mr_input(struct sk_buff *skb)
int err;
/* Packet is looped back after forward, it should not be
- forwarded second time, but still can be delivered locally.
+ * forwarded second time, but still can be delivered locally.
*/
- if (IPCB(skb)->flags&IPSKB_FORWARDED)
+ if (IPCB(skb)->flags & IPSKB_FORWARDED)
goto dont_forward;
err = ipmr_fib_lookup(net, &skb_rtable(skb)->fl, &mrt);
@@ -1736,28 +1752,28 @@ int ip_mr_input(struct sk_buff *skb)
}
if (!local) {
- if (IPCB(skb)->opt.router_alert) {
- if (ip_call_ra_chain(skb))
- return 0;
- } else if (ip_hdr(skb)->protocol == IPPROTO_IGMP){
- /* IGMPv1 (and broken IGMPv2 implementations sort of
- Cisco IOS <= 11.2(8)) do not put router alert
- option to IGMP packets destined to routable
- groups. It is very bad, because it means
- that we can forward NO IGMP messages.
- */
- read_lock(&mrt_lock);
- if (mrt->mroute_sk) {
- nf_reset(skb);
- raw_rcv(mrt->mroute_sk, skb);
- read_unlock(&mrt_lock);
- return 0;
- }
- read_unlock(&mrt_lock);
+ if (IPCB(skb)->opt.router_alert) {
+ if (ip_call_ra_chain(skb))
+ return 0;
+ } else if (ip_hdr(skb)->protocol == IPPROTO_IGMP) {
+ /* IGMPv1 (and broken IGMPv2 implementations sort of
+ * Cisco IOS <= 11.2(8)) do not put router alert
+ * option to IGMP packets destined to routable
+ * groups. It is very bad, because it means
+ * that we can forward NO IGMP messages.
+ */
+ struct sock *mroute_sk;
+
+ mroute_sk = rcu_dereference(mrt->mroute_sk);
+ if (mroute_sk) {
+ nf_reset(skb);
+ raw_rcv(mroute_sk, skb);
+ return 0;
+ }
}
}
- read_lock(&mrt_lock);
+ /* already under rcu_read_lock() */
cache = ipmr_cache_find(mrt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
/*
@@ -1769,13 +1785,12 @@ int ip_mr_input(struct sk_buff *skb)
if (local) {
struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
ip_local_deliver(skb);
- if (skb2 == NULL) {
- read_unlock(&mrt_lock);
+ if (skb2 == NULL)
return -ENOBUFS;
- }
skb = skb2;
}
+ read_lock(&mrt_lock);
vif = ipmr_find_vif(mrt, skb->dev);
if (vif >= 0) {
int err2 = ipmr_cache_unresolved(mrt, vif, skb);
@@ -1788,8 +1803,8 @@ int ip_mr_input(struct sk_buff *skb)
return -ENODEV;
}
+ read_lock(&mrt_lock);
ip_mr_forward(net, mrt, skb, cache, local);
-
read_unlock(&mrt_lock);
if (local)
@@ -1805,6 +1820,7 @@ dont_forward:
}
#ifdef CONFIG_IP_PIMSM
+/* called with rcu_read_lock() */
static int __pim_rcv(struct mr_table *mrt, struct sk_buff *skb,
unsigned int pimlen)
{
@@ -1813,10 +1829,10 @@ static int __pim_rcv(struct mr_table *mrt, struct sk_buff *skb,
encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
/*
- Check that:
- a. packet is really destinted to a multicast group
- b. packet is not a NULL-REGISTER
- c. packet is not truncated
+ * Check that:
+ * a. packet is really sent to a multicast group
+ * b. packet is not a NULL-REGISTER
+ * c. packet is not truncated
*/
if (!ipv4_is_multicast(encap->daddr) ||
encap->tot_len == 0 ||
@@ -1826,26 +1842,23 @@ static int __pim_rcv(struct mr_table *mrt, struct sk_buff *skb,
read_lock(&mrt_lock);
if (mrt->mroute_reg_vif_num >= 0)
reg_dev = mrt->vif_table[mrt->mroute_reg_vif_num].dev;
- if (reg_dev)
- dev_hold(reg_dev);
read_unlock(&mrt_lock);
if (reg_dev == NULL)
return 1;
skb->mac_header = skb->network_header;
- skb_pull(skb, (u8*)encap - skb->data);
+ skb_pull(skb, (u8 *)encap - skb->data);
skb_reset_network_header(skb);
skb->protocol = htons(ETH_P_IP);
- skb->ip_summed = 0;
+ skb->ip_summed = CHECKSUM_NONE;
skb->pkt_type = PACKET_HOST;
skb_tunnel_rx(skb, reg_dev);
netif_rx(skb);
- dev_put(reg_dev);
- return 0;
+ return NET_RX_SUCCESS;
}
#endif
@@ -1854,7 +1867,7 @@ static int __pim_rcv(struct mr_table *mrt, struct sk_buff *skb,
* Handle IGMP messages of PIMv1
*/
-int pim_rcv_v1(struct sk_buff * skb)
+int pim_rcv_v1(struct sk_buff *skb)
{
struct igmphdr *pim;
struct net *net = dev_net(skb->dev);
@@ -1881,7 +1894,7 @@ drop:
#endif
#ifdef CONFIG_IP_PIMSM_V2
-static int pim_rcv(struct sk_buff * skb)
+static int pim_rcv(struct sk_buff *skb)
{
struct pimreghdr *pim;
struct net *net = dev_net(skb->dev);
@@ -1891,8 +1904,8 @@ static int pim_rcv(struct sk_buff * skb)
goto drop;
pim = (struct pimreghdr *)skb_transport_header(skb);
- if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
- (pim->flags&PIM_NULL_REGISTER) ||
+ if (pim->type != ((PIM_VERSION << 4) | (PIM_REGISTER)) ||
+ (pim->flags & PIM_NULL_REGISTER) ||
(ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
csum_fold(skb_checksum(skb, 0, skb->len, 0))))
goto drop;
@@ -1958,28 +1971,33 @@ int ipmr_get_route(struct net *net,
if (mrt == NULL)
return -ENOENT;
- read_lock(&mrt_lock);
+ rcu_read_lock();
cache = ipmr_cache_find(mrt, rt->rt_src, rt->rt_dst);
if (cache == NULL) {
struct sk_buff *skb2;
struct iphdr *iph;
struct net_device *dev;
- int vif;
+ int vif = -1;
if (nowait) {
- read_unlock(&mrt_lock);
+ rcu_read_unlock();
return -EAGAIN;
}
dev = skb->dev;
- if (dev == NULL || (vif = ipmr_find_vif(mrt, dev)) < 0) {
+ read_lock(&mrt_lock);
+ if (dev)
+ vif = ipmr_find_vif(mrt, dev);
+ if (vif < 0) {
read_unlock(&mrt_lock);
+ rcu_read_unlock();
return -ENODEV;
}
skb2 = skb_clone(skb, GFP_ATOMIC);
if (!skb2) {
read_unlock(&mrt_lock);
+ rcu_read_unlock();
return -ENOMEM;
}
@@ -1992,13 +2010,16 @@ int ipmr_get_route(struct net *net,
iph->version = 0;
err = ipmr_cache_unresolved(mrt, vif, skb2);
read_unlock(&mrt_lock);
+ rcu_read_unlock();
return err;
}
- if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
+ read_lock(&mrt_lock);
+ if (!nowait && (rtm->rtm_flags & RTM_F_NOTIFY))
cache->mfc_flags |= MFC_NOTIFY;
err = __ipmr_fill_mroute(mrt, skb, cache, rtm);
read_unlock(&mrt_lock);
+ rcu_read_unlock();
return err;
}
@@ -2050,14 +2071,14 @@ static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
s_h = cb->args[1];
s_e = cb->args[2];
- read_lock(&mrt_lock);
+ rcu_read_lock();
ipmr_for_each_table(mrt, net) {
if (t < s_t)
goto next_table;
if (t > s_t)
s_h = 0;
for (h = s_h; h < MFC_LINES; h++) {
- list_for_each_entry(mfc, &mrt->mfc_cache_array[h], list) {
+ list_for_each_entry_rcu(mfc, &mrt->mfc_cache_array[h], list) {
if (e < s_e)
goto next_entry;
if (ipmr_fill_mroute(mrt, skb,
@@ -2075,7 +2096,7 @@ next_table:
t++;
}
done:
- read_unlock(&mrt_lock);
+ rcu_read_unlock();
cb->args[2] = e;
cb->args[1] = h;
@@ -2086,7 +2107,8 @@ done:
#ifdef CONFIG_PROC_FS
/*
- * The /proc interfaces to multicast routing /proc/ip_mr_cache /proc/ip_mr_vif
+ * The /proc interfaces to multicast routing :
+ * /proc/net/ip_mr_cache & /proc/net/ip_mr_vif
*/
struct ipmr_vif_iter {
struct seq_net_private p;
@@ -2208,14 +2230,14 @@ static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net,
struct mr_table *mrt = it->mrt;
struct mfc_cache *mfc;
- read_lock(&mrt_lock);
+ rcu_read_lock();
for (it->ct = 0; it->ct < MFC_LINES; it->ct++) {
it->cache = &mrt->mfc_cache_array[it->ct];
- list_for_each_entry(mfc, it->cache, list)
+ list_for_each_entry_rcu(mfc, it->cache, list)
if (pos-- == 0)
return mfc;
}
- read_unlock(&mrt_lock);
+ rcu_read_unlock();
spin_lock_bh(&mfc_unres_lock);
it->cache = &mrt->mfc_unres_queue;
@@ -2274,7 +2296,7 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
}
/* exhausted cache_array, show unresolved */
- read_unlock(&mrt_lock);
+ rcu_read_unlock();
it->cache = &mrt->mfc_unres_queue;
it->ct = 0;
@@ -2282,7 +2304,7 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
if (!list_empty(it->cache))
return list_first_entry(it->cache, struct mfc_cache, list);
- end_of_list:
+end_of_list:
spin_unlock_bh(&mfc_unres_lock);
it->cache = NULL;
@@ -2297,7 +2319,7 @@ static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
if (it->cache == &mrt->mfc_unres_queue)
spin_unlock_bh(&mfc_unres_lock);
else if (it->cache == &mrt->mfc_cache_array[it->ct])
- read_unlock(&mrt_lock);
+ rcu_read_unlock();
}
static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
@@ -2323,7 +2345,7 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
mfc->mfc_un.res.bytes,
mfc->mfc_un.res.wrong_if);
for (n = mfc->mfc_un.res.minvif;
- n < mfc->mfc_un.res.maxvif; n++ ) {
+ n < mfc->mfc_un.res.maxvif; n++) {
if (VIF_EXISTS(mrt, n) &&
mfc->mfc_un.res.ttls[n] < 255)
seq_printf(seq,
@@ -2421,7 +2443,7 @@ int __init ip_mr_init(void)
mrt_cachep = kmem_cache_create("ip_mrt_cache",
sizeof(struct mfc_cache),
- 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
+ 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC,
NULL);
if (!mrt_cachep)
return -ENOMEM;
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 1833bdbf9805..babd1a2bae5f 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -147,7 +147,7 @@ config IP_NF_TARGET_ULOG
which can only be viewed through syslog.
The appropriate userspace logging daemon (ulogd) may be obtained from
- <http://www.gnumonks.org/projects/ulogd/>
+ <http://www.netfilter.org/projects/ulogd/index.html>
To compile it as a module, choose M here. If unsure, say N.
@@ -324,10 +324,10 @@ config IP_NF_TARGET_ECN
config IP_NF_TARGET_TTL
tristate '"TTL" target support'
- depends on NETFILTER_ADVANCED
+ depends on NETFILTER_ADVANCED && IP_NF_MANGLE
select NETFILTER_XT_TARGET_HL
---help---
- This is a backwards-compat option for the user's convenience
+ This is a backwards-compatible option for the user's convenience
(e.g. when running oldconfig). It selects
CONFIG_NETFILTER_XT_TARGET_HL.
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index e8f4f9a57f12..3cad2591ace0 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -72,7 +72,7 @@ static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
for (i = 0; i < len; i++)
ret |= (hdr_addr[i] ^ ap->addr[i]) & ap->mask[i];
- return (ret != 0);
+ return ret != 0;
}
/*
@@ -228,7 +228,7 @@ arpt_error(struct sk_buff *skb, const struct xt_action_param *par)
return NF_DROP;
}
-static inline const struct arpt_entry_target *
+static inline const struct xt_entry_target *
arpt_get_target_c(const struct arpt_entry *e)
{
return arpt_get_target((struct arpt_entry *)e);
@@ -282,7 +282,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
arp = arp_hdr(skb);
do {
- const struct arpt_entry_target *t;
+ const struct xt_entry_target *t;
if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) {
e = arpt_next_entry(e);
@@ -297,10 +297,10 @@ unsigned int arpt_do_table(struct sk_buff *skb,
if (!t->u.kernel.target->target) {
int v;
- v = ((struct arpt_standard_target *)t)->verdict;
+ v = ((struct xt_standard_target *)t)->verdict;
if (v < 0) {
/* Pop from stack? */
- if (v != ARPT_RETURN) {
+ if (v != XT_RETURN) {
verdict = (unsigned)(-v) - 1;
break;
}
@@ -332,7 +332,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
/* Target might have changed stuff. */
arp = arp_hdr(skb);
- if (verdict == ARPT_CONTINUE)
+ if (verdict == XT_CONTINUE)
e = arpt_next_entry(e);
else
/* Verdict */
@@ -377,7 +377,7 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
e->counters.pcnt = pos;
for (;;) {
- const struct arpt_standard_target *t
+ const struct xt_standard_target *t
= (void *)arpt_get_target_c(e);
int visited = e->comefrom & (1 << hook);
@@ -392,13 +392,13 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
/* Unconditional return/END. */
if ((e->target_offset == sizeof(struct arpt_entry) &&
(strcmp(t->target.u.user.name,
- ARPT_STANDARD_TARGET) == 0) &&
+ XT_STANDARD_TARGET) == 0) &&
t->verdict < 0 && unconditional(&e->arp)) ||
visited) {
unsigned int oldpos, size;
if ((strcmp(t->target.u.user.name,
- ARPT_STANDARD_TARGET) == 0) &&
+ XT_STANDARD_TARGET) == 0) &&
t->verdict < -NF_MAX_VERDICT - 1) {
duprintf("mark_source_chains: bad "
"negative verdict (%i)\n",
@@ -433,7 +433,7 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
int newpos = t->verdict;
if (strcmp(t->target.u.user.name,
- ARPT_STANDARD_TARGET) == 0 &&
+ XT_STANDARD_TARGET) == 0 &&
newpos >= 0) {
if (newpos > newinfo->size -
sizeof(struct arpt_entry)) {
@@ -464,14 +464,14 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
static inline int check_entry(const struct arpt_entry *e, const char *name)
{
- const struct arpt_entry_target *t;
+ const struct xt_entry_target *t;
if (!arp_checkentry(&e->arp)) {
duprintf("arp_tables: arp check failed %p %s.\n", e, name);
return -EINVAL;
}
- if (e->target_offset + sizeof(struct arpt_entry_target) > e->next_offset)
+ if (e->target_offset + sizeof(struct xt_entry_target) > e->next_offset)
return -EINVAL;
t = arpt_get_target_c(e);
@@ -483,7 +483,7 @@ static inline int check_entry(const struct arpt_entry *e, const char *name)
static inline int check_target(struct arpt_entry *e, const char *name)
{
- struct arpt_entry_target *t = arpt_get_target(e);
+ struct xt_entry_target *t = arpt_get_target(e);
int ret;
struct xt_tgchk_param par = {
.table = name,
@@ -506,7 +506,7 @@ static inline int check_target(struct arpt_entry *e, const char *name)
static inline int
find_check_entry(struct arpt_entry *e, const char *name, unsigned int size)
{
- struct arpt_entry_target *t;
+ struct xt_entry_target *t;
struct xt_target *target;
int ret;
@@ -536,7 +536,7 @@ out:
static bool check_underflow(const struct arpt_entry *e)
{
- const struct arpt_entry_target *t;
+ const struct xt_entry_target *t;
unsigned int verdict;
if (!unconditional(&e->arp))
@@ -544,7 +544,7 @@ static bool check_underflow(const struct arpt_entry *e)
t = arpt_get_target_c(e);
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
return false;
- verdict = ((struct arpt_standard_target *)t)->verdict;
+ verdict = ((struct xt_standard_target *)t)->verdict;
verdict = -verdict - 1;
return verdict == NF_DROP || verdict == NF_ACCEPT;
}
@@ -566,7 +566,7 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e,
}
if (e->next_offset
- < sizeof(struct arpt_entry) + sizeof(struct arpt_entry_target)) {
+ < sizeof(struct arpt_entry) + sizeof(struct xt_entry_target)) {
duprintf("checking: element %p size %u\n",
e, e->next_offset);
return -EINVAL;
@@ -598,7 +598,7 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e,
static inline void cleanup_entry(struct arpt_entry *e)
{
struct xt_tgdtor_param par;
- struct arpt_entry_target *t;
+ struct xt_entry_target *t;
t = arpt_get_target(e);
par.target = t->u.kernel.target;
@@ -794,7 +794,7 @@ static int copy_entries_to_user(unsigned int total_size,
/* FIXME: use iterator macros --RR */
/* ... then go back and fix counters and names */
for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
- const struct arpt_entry_target *t;
+ const struct xt_entry_target *t;
e = (struct arpt_entry *)(loc_cpu_entry + off);
if (copy_to_user(userptr + off
@@ -807,7 +807,7 @@ static int copy_entries_to_user(unsigned int total_size,
t = arpt_get_target_c(e);
if (copy_to_user(userptr + off + e->target_offset
- + offsetof(struct arpt_entry_target,
+ + offsetof(struct xt_entry_target,
u.user.name),
t->u.kernel.target->name,
strlen(t->u.kernel.target->name)+1) != 0) {
@@ -844,7 +844,7 @@ static int compat_calc_entry(const struct arpt_entry *e,
const struct xt_table_info *info,
const void *base, struct xt_table_info *newinfo)
{
- const struct arpt_entry_target *t;
+ const struct xt_entry_target *t;
unsigned int entry_offset;
int off, i, ret;
@@ -895,7 +895,7 @@ static int compat_table_info(const struct xt_table_info *info,
static int get_info(struct net *net, void __user *user,
const int *len, int compat)
{
- char name[ARPT_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
struct xt_table *t;
int ret;
@@ -908,7 +908,7 @@ static int get_info(struct net *net, void __user *user,
if (copy_from_user(name, user, sizeof(name)) != 0)
return -EFAULT;
- name[ARPT_TABLE_MAXNAMELEN-1] = '\0';
+ name[XT_TABLE_MAXNAMELEN-1] = '\0';
#ifdef CONFIG_COMPAT
if (compat)
xt_compat_lock(NFPROTO_ARP);
@@ -1204,7 +1204,7 @@ static int do_add_counters(struct net *net, const void __user *user,
#ifdef CONFIG_COMPAT
static inline void compat_release_entry(struct compat_arpt_entry *e)
{
- struct arpt_entry_target *t;
+ struct xt_entry_target *t;
t = compat_arpt_get_target(e);
module_put(t->u.kernel.target->me);
@@ -1220,7 +1220,7 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
const unsigned int *underflows,
const char *name)
{
- struct arpt_entry_target *t;
+ struct xt_entry_target *t;
struct xt_target *target;
unsigned int entry_offset;
int ret, off, h;
@@ -1288,7 +1288,7 @@ compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr,
unsigned int *size, const char *name,
struct xt_table_info *newinfo, unsigned char *base)
{
- struct arpt_entry_target *t;
+ struct xt_entry_target *t;
struct xt_target *target;
struct arpt_entry *de;
unsigned int origsize;
@@ -1474,7 +1474,7 @@ out_unlock:
}
struct compat_arpt_replace {
- char name[ARPT_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks;
u32 num_entries;
u32 size;
@@ -1567,7 +1567,7 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr,
struct xt_counters *counters,
unsigned int i)
{
- struct arpt_entry_target *t;
+ struct xt_entry_target *t;
struct compat_arpt_entry __user *ce;
u_int16_t target_offset, next_offset;
compat_uint_t origsize;
@@ -1628,7 +1628,7 @@ static int compat_copy_entries_to_user(unsigned int total_size,
}
struct compat_arpt_get_entries {
- char name[ARPT_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
compat_uint_t size;
struct compat_arpt_entry entrytable[0];
};
@@ -1828,7 +1828,7 @@ void arpt_unregister_table(struct xt_table *table)
/* The built-in targets: standard (NULL) and error. */
static struct xt_target arpt_builtin_tg[] __read_mostly = {
{
- .name = ARPT_STANDARD_TARGET,
+ .name = XT_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = NFPROTO_ARP,
#ifdef CONFIG_COMPAT
@@ -1838,9 +1838,9 @@ static struct xt_target arpt_builtin_tg[] __read_mostly = {
#endif
},
{
- .name = ARPT_ERROR_TARGET,
+ .name = XT_ERROR_TARGET,
.target = arpt_error,
- .targetsize = ARPT_FUNCTION_MAXNAMELEN,
+ .targetsize = XT_FUNCTION_MAXNAMELEN,
.family = NFPROTO_ARP,
},
};
diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c
index e1be7dd1171b..b8ddcc480ed9 100644
--- a/net/ipv4/netfilter/arpt_mangle.c
+++ b/net/ipv4/netfilter/arpt_mangle.c
@@ -63,7 +63,7 @@ static int checkentry(const struct xt_tgchk_param *par)
return false;
if (mangle->target != NF_DROP && mangle->target != NF_ACCEPT &&
- mangle->target != ARPT_CONTINUE)
+ mangle->target != XT_CONTINUE)
return false;
return true;
}
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index d163f2e3b2e9..d31b007a6d80 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -186,7 +186,7 @@ static inline bool unconditional(const struct ipt_ip *ip)
}
/* for const-correctness */
-static inline const struct ipt_entry_target *
+static inline const struct xt_entry_target *
ipt_get_target_c(const struct ipt_entry *e)
{
return ipt_get_target((struct ipt_entry *)e);
@@ -230,9 +230,9 @@ get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e,
const char *hookname, const char **chainname,
const char **comment, unsigned int *rulenum)
{
- const struct ipt_standard_target *t = (void *)ipt_get_target_c(s);
+ const struct xt_standard_target *t = (void *)ipt_get_target_c(s);
- if (strcmp(t->target.u.kernel.target->name, IPT_ERROR_TARGET) == 0) {
+ if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) {
/* Head of user chain: ERROR target with chainname */
*chainname = t->target.data;
(*rulenum) = 0;
@@ -241,7 +241,7 @@ get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e,
if (s->target_offset == sizeof(struct ipt_entry) &&
strcmp(t->target.u.kernel.target->name,
- IPT_STANDARD_TARGET) == 0 &&
+ XT_STANDARD_TARGET) == 0 &&
t->verdict < 0 &&
unconditional(&s->ip)) {
/* Tail of chains: STANDARD target (return/policy) */
@@ -346,7 +346,7 @@ ipt_do_table(struct sk_buff *skb,
get_entry(table_base, private->underflow[hook]));
do {
- const struct ipt_entry_target *t;
+ const struct xt_entry_target *t;
const struct xt_entry_match *ematch;
IP_NF_ASSERT(e);
@@ -380,10 +380,10 @@ ipt_do_table(struct sk_buff *skb,
if (!t->u.kernel.target->target) {
int v;
- v = ((struct ipt_standard_target *)t)->verdict;
+ v = ((struct xt_standard_target *)t)->verdict;
if (v < 0) {
/* Pop from stack? */
- if (v != IPT_RETURN) {
+ if (v != XT_RETURN) {
verdict = (unsigned)(-v) - 1;
break;
}
@@ -421,7 +421,7 @@ ipt_do_table(struct sk_buff *skb,
verdict = t->u.kernel.target->target(skb, &acpar);
/* Target might have changed stuff. */
ip = ip_hdr(skb);
- if (verdict == IPT_CONTINUE)
+ if (verdict == XT_CONTINUE)
e = ipt_next_entry(e);
else
/* Verdict */
@@ -461,7 +461,7 @@ mark_source_chains(const struct xt_table_info *newinfo,
e->counters.pcnt = pos;
for (;;) {
- const struct ipt_standard_target *t
+ const struct xt_standard_target *t
= (void *)ipt_get_target_c(e);
int visited = e->comefrom & (1 << hook);
@@ -475,13 +475,13 @@ mark_source_chains(const struct xt_table_info *newinfo,
/* Unconditional return/END. */
if ((e->target_offset == sizeof(struct ipt_entry) &&
(strcmp(t->target.u.user.name,
- IPT_STANDARD_TARGET) == 0) &&
+ XT_STANDARD_TARGET) == 0) &&
t->verdict < 0 && unconditional(&e->ip)) ||
visited) {
unsigned int oldpos, size;
if ((strcmp(t->target.u.user.name,
- IPT_STANDARD_TARGET) == 0) &&
+ XT_STANDARD_TARGET) == 0) &&
t->verdict < -NF_MAX_VERDICT - 1) {
duprintf("mark_source_chains: bad "
"negative verdict (%i)\n",
@@ -524,7 +524,7 @@ mark_source_chains(const struct xt_table_info *newinfo,
int newpos = t->verdict;
if (strcmp(t->target.u.user.name,
- IPT_STANDARD_TARGET) == 0 &&
+ XT_STANDARD_TARGET) == 0 &&
newpos >= 0) {
if (newpos > newinfo->size -
sizeof(struct ipt_entry)) {
@@ -552,7 +552,7 @@ mark_source_chains(const struct xt_table_info *newinfo,
return 1;
}
-static void cleanup_match(struct ipt_entry_match *m, struct net *net)
+static void cleanup_match(struct xt_entry_match *m, struct net *net)
{
struct xt_mtdtor_param par;
@@ -568,14 +568,14 @@ static void cleanup_match(struct ipt_entry_match *m, struct net *net)
static int
check_entry(const struct ipt_entry *e, const char *name)
{
- const struct ipt_entry_target *t;
+ const struct xt_entry_target *t;
if (!ip_checkentry(&e->ip)) {
duprintf("ip check failed %p %s.\n", e, par->match->name);
return -EINVAL;
}
- if (e->target_offset + sizeof(struct ipt_entry_target) >
+ if (e->target_offset + sizeof(struct xt_entry_target) >
e->next_offset)
return -EINVAL;
@@ -587,7 +587,7 @@ check_entry(const struct ipt_entry *e, const char *name)
}
static int
-check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par)
+check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
{
const struct ipt_ip *ip = par->entryinfo;
int ret;
@@ -605,7 +605,7 @@ check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par)
}
static int
-find_check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par)
+find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
{
struct xt_match *match;
int ret;
@@ -630,7 +630,7 @@ err:
static int check_target(struct ipt_entry *e, struct net *net, const char *name)
{
- struct ipt_entry_target *t = ipt_get_target(e);
+ struct xt_entry_target *t = ipt_get_target(e);
struct xt_tgchk_param par = {
.net = net,
.table = name,
@@ -656,7 +656,7 @@ static int
find_check_entry(struct ipt_entry *e, struct net *net, const char *name,
unsigned int size)
{
- struct ipt_entry_target *t;
+ struct xt_entry_target *t;
struct xt_target *target;
int ret;
unsigned int j;
@@ -707,7 +707,7 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name,
static bool check_underflow(const struct ipt_entry *e)
{
- const struct ipt_entry_target *t;
+ const struct xt_entry_target *t;
unsigned int verdict;
if (!unconditional(&e->ip))
@@ -715,7 +715,7 @@ static bool check_underflow(const struct ipt_entry *e)
t = ipt_get_target_c(e);
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
return false;
- verdict = ((struct ipt_standard_target *)t)->verdict;
+ verdict = ((struct xt_standard_target *)t)->verdict;
verdict = -verdict - 1;
return verdict == NF_DROP || verdict == NF_ACCEPT;
}
@@ -738,7 +738,7 @@ check_entry_size_and_hooks(struct ipt_entry *e,
}
if (e->next_offset
- < sizeof(struct ipt_entry) + sizeof(struct ipt_entry_target)) {
+ < sizeof(struct ipt_entry) + sizeof(struct xt_entry_target)) {
duprintf("checking: element %p size %u\n",
e, e->next_offset);
return -EINVAL;
@@ -771,7 +771,7 @@ static void
cleanup_entry(struct ipt_entry *e, struct net *net)
{
struct xt_tgdtor_param par;
- struct ipt_entry_target *t;
+ struct xt_entry_target *t;
struct xt_entry_match *ematch;
/* Cleanup all matches */
@@ -972,8 +972,8 @@ copy_entries_to_user(unsigned int total_size,
/* ... then go back and fix counters and names */
for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
unsigned int i;
- const struct ipt_entry_match *m;
- const struct ipt_entry_target *t;
+ const struct xt_entry_match *m;
+ const struct xt_entry_target *t;
e = (struct ipt_entry *)(loc_cpu_entry + off);
if (copy_to_user(userptr + off
@@ -990,7 +990,7 @@ copy_entries_to_user(unsigned int total_size,
m = (void *)e + i;
if (copy_to_user(userptr + off + i
- + offsetof(struct ipt_entry_match,
+ + offsetof(struct xt_entry_match,
u.user.name),
m->u.kernel.match->name,
strlen(m->u.kernel.match->name)+1)
@@ -1002,7 +1002,7 @@ copy_entries_to_user(unsigned int total_size,
t = ipt_get_target_c(e);
if (copy_to_user(userptr + off + e->target_offset
- + offsetof(struct ipt_entry_target,
+ + offsetof(struct xt_entry_target,
u.user.name),
t->u.kernel.target->name,
strlen(t->u.kernel.target->name)+1) != 0) {
@@ -1040,7 +1040,7 @@ static int compat_calc_entry(const struct ipt_entry *e,
const void *base, struct xt_table_info *newinfo)
{
const struct xt_entry_match *ematch;
- const struct ipt_entry_target *t;
+ const struct xt_entry_target *t;
unsigned int entry_offset;
int off, i, ret;
@@ -1092,7 +1092,7 @@ static int compat_table_info(const struct xt_table_info *info,
static int get_info(struct net *net, void __user *user,
const int *len, int compat)
{
- char name[IPT_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
struct xt_table *t;
int ret;
@@ -1105,7 +1105,7 @@ static int get_info(struct net *net, void __user *user,
if (copy_from_user(name, user, sizeof(name)) != 0)
return -EFAULT;
- name[IPT_TABLE_MAXNAMELEN-1] = '\0';
+ name[XT_TABLE_MAXNAMELEN-1] = '\0';
#ifdef CONFIG_COMPAT
if (compat)
xt_compat_lock(AF_INET);
@@ -1400,14 +1400,14 @@ do_add_counters(struct net *net, const void __user *user,
#ifdef CONFIG_COMPAT
struct compat_ipt_replace {
- char name[IPT_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks;
u32 num_entries;
u32 size;
u32 hook_entry[NF_INET_NUMHOOKS];
u32 underflow[NF_INET_NUMHOOKS];
u32 num_counters;
- compat_uptr_t counters; /* struct ipt_counters * */
+ compat_uptr_t counters; /* struct xt_counters * */
struct compat_ipt_entry entries[0];
};
@@ -1416,7 +1416,7 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr,
unsigned int *size, struct xt_counters *counters,
unsigned int i)
{
- struct ipt_entry_target *t;
+ struct xt_entry_target *t;
struct compat_ipt_entry __user *ce;
u_int16_t target_offset, next_offset;
compat_uint_t origsize;
@@ -1451,7 +1451,7 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr,
}
static int
-compat_find_calc_match(struct ipt_entry_match *m,
+compat_find_calc_match(struct xt_entry_match *m,
const char *name,
const struct ipt_ip *ip,
unsigned int hookmask,
@@ -1473,7 +1473,7 @@ compat_find_calc_match(struct ipt_entry_match *m,
static void compat_release_entry(struct compat_ipt_entry *e)
{
- struct ipt_entry_target *t;
+ struct xt_entry_target *t;
struct xt_entry_match *ematch;
/* Cleanup all matches */
@@ -1494,7 +1494,7 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
const char *name)
{
struct xt_entry_match *ematch;
- struct ipt_entry_target *t;
+ struct xt_entry_target *t;
struct xt_target *target;
unsigned int entry_offset;
unsigned int j;
@@ -1576,7 +1576,7 @@ compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr,
unsigned int *size, const char *name,
struct xt_table_info *newinfo, unsigned char *base)
{
- struct ipt_entry_target *t;
+ struct xt_entry_target *t;
struct xt_target *target;
struct ipt_entry *de;
unsigned int origsize;
@@ -1884,7 +1884,7 @@ compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user,
}
struct compat_ipt_get_entries {
- char name[IPT_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
compat_uint_t size;
struct compat_ipt_entry entrytable[0];
};
@@ -2039,7 +2039,7 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
case IPT_SO_GET_REVISION_MATCH:
case IPT_SO_GET_REVISION_TARGET: {
- struct ipt_get_revision rev;
+ struct xt_get_revision rev;
int target;
if (*len != sizeof(rev)) {
@@ -2176,7 +2176,7 @@ static int icmp_checkentry(const struct xt_mtchk_param *par)
static struct xt_target ipt_builtin_tg[] __read_mostly = {
{
- .name = IPT_STANDARD_TARGET,
+ .name = XT_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = NFPROTO_IPV4,
#ifdef CONFIG_COMPAT
@@ -2186,9 +2186,9 @@ static struct xt_target ipt_builtin_tg[] __read_mostly = {
#endif
},
{
- .name = IPT_ERROR_TARGET,
+ .name = XT_ERROR_TARGET,
.target = ipt_error,
- .targetsize = IPT_FUNCTION_MAXNAMELEN,
+ .targetsize = XT_FUNCTION_MAXNAMELEN,
.family = NFPROTO_IPV4,
},
};
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 3a43cf36db87..1e26a4897655 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -29,6 +29,7 @@
#include <net/netfilter/nf_conntrack.h>
#include <net/net_namespace.h>
#include <net/checksum.h>
+#include <net/ip.h>
#define CLUSTERIP_VERSION "0.8"
@@ -231,24 +232,22 @@ clusterip_hashfn(const struct sk_buff *skb,
{
const struct iphdr *iph = ip_hdr(skb);
unsigned long hashval;
- u_int16_t sport, dport;
- const u_int16_t *ports;
-
- switch (iph->protocol) {
- case IPPROTO_TCP:
- case IPPROTO_UDP:
- case IPPROTO_UDPLITE:
- case IPPROTO_SCTP:
- case IPPROTO_DCCP:
- case IPPROTO_ICMP:
- ports = (const void *)iph+iph->ihl*4;
- sport = ports[0];
- dport = ports[1];
- break;
- default:
+ u_int16_t sport = 0, dport = 0;
+ int poff;
+
+ poff = proto_ports_offset(iph->protocol);
+ if (poff >= 0) {
+ const u_int16_t *ports;
+ u16 _ports[2];
+
+ ports = skb_header_pointer(skb, iph->ihl * 4 + poff, 4, _ports);
+ if (ports) {
+ sport = ports[0];
+ dport = ports[1];
+ }
+ } else {
if (net_ratelimit())
pr_info("unknown protocol %u\n", iph->protocol);
- sport = dport = 0;
}
switch (config->hash_mode) {
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index 915fc17d7ce2..72ffc8fda2e9 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -24,16 +24,15 @@
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ipt_LOG.h>
#include <net/netfilter/nf_log.h>
+#include <net/netfilter/xt_log.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
MODULE_DESCRIPTION("Xtables: IPv4 packet logging to syslog");
-/* Use lock to serialize, so printks don't overlap */
-static DEFINE_SPINLOCK(log_lock);
-
/* One level of recursion won't kill us */
-static void dump_packet(const struct nf_loginfo *info,
+static void dump_packet(struct sbuff *m,
+ const struct nf_loginfo *info,
const struct sk_buff *skb,
unsigned int iphoff)
{
@@ -48,32 +47,32 @@ static void dump_packet(const struct nf_loginfo *info,
ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph);
if (ih == NULL) {
- printk("TRUNCATED");
+ sb_add(m, "TRUNCATED");
return;
}
/* Important fields:
* TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */
/* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */
- printk("SRC=%pI4 DST=%pI4 ",
+ sb_add(m, "SRC=%pI4 DST=%pI4 ",
&ih->saddr, &ih->daddr);
/* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */
- printk("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
+ sb_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK,
ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id));
/* Max length: 6 "CE DF MF " */
if (ntohs(ih->frag_off) & IP_CE)
- printk("CE ");
+ sb_add(m, "CE ");
if (ntohs(ih->frag_off) & IP_DF)
- printk("DF ");
+ sb_add(m, "DF ");
if (ntohs(ih->frag_off) & IP_MF)
- printk("MF ");
+ sb_add(m, "MF ");
/* Max length: 11 "FRAG:65535 " */
if (ntohs(ih->frag_off) & IP_OFFSET)
- printk("FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET);
+ sb_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET);
if ((logflags & IPT_LOG_IPOPT) &&
ih->ihl * 4 > sizeof(struct iphdr)) {
@@ -85,15 +84,15 @@ static void dump_packet(const struct nf_loginfo *info,
op = skb_header_pointer(skb, iphoff+sizeof(_iph),
optsize, _opt);
if (op == NULL) {
- printk("TRUNCATED");
+ sb_add(m, "TRUNCATED");
return;
}
/* Max length: 127 "OPT (" 15*4*2chars ") " */
- printk("OPT (");
+ sb_add(m, "OPT (");
for (i = 0; i < optsize; i++)
- printk("%02X", op[i]);
- printk(") ");
+ sb_add(m, "%02X", op[i]);
+ sb_add(m, ") ");
}
switch (ih->protocol) {
@@ -102,7 +101,7 @@ static void dump_packet(const struct nf_loginfo *info,
const struct tcphdr *th;
/* Max length: 10 "PROTO=TCP " */
- printk("PROTO=TCP ");
+ sb_add(m, "PROTO=TCP ");
if (ntohs(ih->frag_off) & IP_OFFSET)
break;
@@ -111,41 +110,41 @@ static void dump_packet(const struct nf_loginfo *info,
th = skb_header_pointer(skb, iphoff + ih->ihl * 4,
sizeof(_tcph), &_tcph);
if (th == NULL) {
- printk("INCOMPLETE [%u bytes] ",
+ sb_add(m, "INCOMPLETE [%u bytes] ",
skb->len - iphoff - ih->ihl*4);
break;
}
/* Max length: 20 "SPT=65535 DPT=65535 " */
- printk("SPT=%u DPT=%u ",
+ sb_add(m, "SPT=%u DPT=%u ",
ntohs(th->source), ntohs(th->dest));
/* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
if (logflags & IPT_LOG_TCPSEQ)
- printk("SEQ=%u ACK=%u ",
+ sb_add(m, "SEQ=%u ACK=%u ",
ntohl(th->seq), ntohl(th->ack_seq));
/* Max length: 13 "WINDOW=65535 " */
- printk("WINDOW=%u ", ntohs(th->window));
+ sb_add(m, "WINDOW=%u ", ntohs(th->window));
/* Max length: 9 "RES=0x3F " */
- printk("RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22));
+ sb_add(m, "RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22));
/* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
if (th->cwr)
- printk("CWR ");
+ sb_add(m, "CWR ");
if (th->ece)
- printk("ECE ");
+ sb_add(m, "ECE ");
if (th->urg)
- printk("URG ");
+ sb_add(m, "URG ");
if (th->ack)
- printk("ACK ");
+ sb_add(m, "ACK ");
if (th->psh)
- printk("PSH ");
+ sb_add(m, "PSH ");
if (th->rst)
- printk("RST ");
+ sb_add(m, "RST ");
if (th->syn)
- printk("SYN ");
+ sb_add(m, "SYN ");
if (th->fin)
- printk("FIN ");
+ sb_add(m, "FIN ");
/* Max length: 11 "URGP=65535 " */
- printk("URGP=%u ", ntohs(th->urg_ptr));
+ sb_add(m, "URGP=%u ", ntohs(th->urg_ptr));
if ((logflags & IPT_LOG_TCPOPT) &&
th->doff * 4 > sizeof(struct tcphdr)) {
@@ -158,15 +157,15 @@ static void dump_packet(const struct nf_loginfo *info,
iphoff+ih->ihl*4+sizeof(_tcph),
optsize, _opt);
if (op == NULL) {
- printk("TRUNCATED");
+ sb_add(m, "TRUNCATED");
return;
}
/* Max length: 127 "OPT (" 15*4*2chars ") " */
- printk("OPT (");
+ sb_add(m, "OPT (");
for (i = 0; i < optsize; i++)
- printk("%02X", op[i]);
- printk(") ");
+ sb_add(m, "%02X", op[i]);
+ sb_add(m, ") ");
}
break;
}
@@ -177,9 +176,9 @@ static void dump_packet(const struct nf_loginfo *info,
if (ih->protocol == IPPROTO_UDP)
/* Max length: 10 "PROTO=UDP " */
- printk("PROTO=UDP " );
+ sb_add(m, "PROTO=UDP " );
else /* Max length: 14 "PROTO=UDPLITE " */
- printk("PROTO=UDPLITE ");
+ sb_add(m, "PROTO=UDPLITE ");
if (ntohs(ih->frag_off) & IP_OFFSET)
break;
@@ -188,13 +187,13 @@ static void dump_packet(const struct nf_loginfo *info,
uh = skb_header_pointer(skb, iphoff+ih->ihl*4,
sizeof(_udph), &_udph);
if (uh == NULL) {
- printk("INCOMPLETE [%u bytes] ",
+ sb_add(m, "INCOMPLETE [%u bytes] ",
skb->len - iphoff - ih->ihl*4);
break;
}
/* Max length: 20 "SPT=65535 DPT=65535 " */
- printk("SPT=%u DPT=%u LEN=%u ",
+ sb_add(m, "SPT=%u DPT=%u LEN=%u ",
ntohs(uh->source), ntohs(uh->dest),
ntohs(uh->len));
break;
@@ -221,7 +220,7 @@ static void dump_packet(const struct nf_loginfo *info,
[ICMP_ADDRESSREPLY] = 12 };
/* Max length: 11 "PROTO=ICMP " */
- printk("PROTO=ICMP ");
+ sb_add(m, "PROTO=ICMP ");
if (ntohs(ih->frag_off) & IP_OFFSET)
break;
@@ -230,19 +229,19 @@ static void dump_packet(const struct nf_loginfo *info,
ich = skb_header_pointer(skb, iphoff + ih->ihl * 4,
sizeof(_icmph), &_icmph);
if (ich == NULL) {
- printk("INCOMPLETE [%u bytes] ",
+ sb_add(m, "INCOMPLETE [%u bytes] ",
skb->len - iphoff - ih->ihl*4);
break;
}
/* Max length: 18 "TYPE=255 CODE=255 " */
- printk("TYPE=%u CODE=%u ", ich->type, ich->code);
+ sb_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code);
/* Max length: 25 "INCOMPLETE [65535 bytes] " */
if (ich->type <= NR_ICMP_TYPES &&
required_len[ich->type] &&
skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) {
- printk("INCOMPLETE [%u bytes] ",
+ sb_add(m, "INCOMPLETE [%u bytes] ",
skb->len - iphoff - ih->ihl*4);
break;
}
@@ -251,35 +250,35 @@ static void dump_packet(const struct nf_loginfo *info,
case ICMP_ECHOREPLY:
case ICMP_ECHO:
/* Max length: 19 "ID=65535 SEQ=65535 " */
- printk("ID=%u SEQ=%u ",
+ sb_add(m, "ID=%u SEQ=%u ",
ntohs(ich->un.echo.id),
ntohs(ich->un.echo.sequence));
break;
case ICMP_PARAMETERPROB:
/* Max length: 14 "PARAMETER=255 " */
- printk("PARAMETER=%u ",
+ sb_add(m, "PARAMETER=%u ",
ntohl(ich->un.gateway) >> 24);
break;
case ICMP_REDIRECT:
/* Max length: 24 "GATEWAY=255.255.255.255 " */
- printk("GATEWAY=%pI4 ", &ich->un.gateway);
+ sb_add(m, "GATEWAY=%pI4 ", &ich->un.gateway);
/* Fall through */
case ICMP_DEST_UNREACH:
case ICMP_SOURCE_QUENCH:
case ICMP_TIME_EXCEEDED:
/* Max length: 3+maxlen */
if (!iphoff) { /* Only recurse once. */
- printk("[");
- dump_packet(info, skb,
+ sb_add(m, "[");
+ dump_packet(m, info, skb,
iphoff + ih->ihl*4+sizeof(_icmph));
- printk("] ");
+ sb_add(m, "] ");
}
/* Max length: 10 "MTU=65535 " */
if (ich->type == ICMP_DEST_UNREACH &&
ich->code == ICMP_FRAG_NEEDED)
- printk("MTU=%u ", ntohs(ich->un.frag.mtu));
+ sb_add(m, "MTU=%u ", ntohs(ich->un.frag.mtu));
}
break;
}
@@ -292,19 +291,19 @@ static void dump_packet(const struct nf_loginfo *info,
break;
/* Max length: 9 "PROTO=AH " */
- printk("PROTO=AH ");
+ sb_add(m, "PROTO=AH ");
/* Max length: 25 "INCOMPLETE [65535 bytes] " */
ah = skb_header_pointer(skb, iphoff+ih->ihl*4,
sizeof(_ahdr), &_ahdr);
if (ah == NULL) {
- printk("INCOMPLETE [%u bytes] ",
+ sb_add(m, "INCOMPLETE [%u bytes] ",
skb->len - iphoff - ih->ihl*4);
break;
}
/* Length: 15 "SPI=0xF1234567 " */
- printk("SPI=0x%x ", ntohl(ah->spi));
+ sb_add(m, "SPI=0x%x ", ntohl(ah->spi));
break;
}
case IPPROTO_ESP: {
@@ -312,7 +311,7 @@ static void dump_packet(const struct nf_loginfo *info,
const struct ip_esp_hdr *eh;
/* Max length: 10 "PROTO=ESP " */
- printk("PROTO=ESP ");
+ sb_add(m, "PROTO=ESP ");
if (ntohs(ih->frag_off) & IP_OFFSET)
break;
@@ -321,25 +320,25 @@ static void dump_packet(const struct nf_loginfo *info,
eh = skb_header_pointer(skb, iphoff+ih->ihl*4,
sizeof(_esph), &_esph);
if (eh == NULL) {
- printk("INCOMPLETE [%u bytes] ",
+ sb_add(m, "INCOMPLETE [%u bytes] ",
skb->len - iphoff - ih->ihl*4);
break;
}
/* Length: 15 "SPI=0xF1234567 " */
- printk("SPI=0x%x ", ntohl(eh->spi));
+ sb_add(m, "SPI=0x%x ", ntohl(eh->spi));
break;
}
/* Max length: 10 "PROTO 255 " */
default:
- printk("PROTO=%u ", ih->protocol);
+ sb_add(m, "PROTO=%u ", ih->protocol);
}
/* Max length: 15 "UID=4294967295 " */
if ((logflags & IPT_LOG_UID) && !iphoff && skb->sk) {
read_lock_bh(&skb->sk->sk_callback_lock);
if (skb->sk->sk_socket && skb->sk->sk_socket->file)
- printk("UID=%u GID=%u ",
+ sb_add(m, "UID=%u GID=%u ",
skb->sk->sk_socket->file->f_cred->fsuid,
skb->sk->sk_socket->file->f_cred->fsgid);
read_unlock_bh(&skb->sk->sk_callback_lock);
@@ -347,7 +346,7 @@ static void dump_packet(const struct nf_loginfo *info,
/* Max length: 16 "MARK=0xFFFFFFFF " */
if (!iphoff && skb->mark)
- printk("MARK=0x%x ", skb->mark);
+ sb_add(m, "MARK=0x%x ", skb->mark);
/* Proto Max log string length */
/* IP: 40+46+6+11+127 = 230 */
@@ -364,7 +363,8 @@ static void dump_packet(const struct nf_loginfo *info,
/* maxlen = 230+ 91 + 230 + 252 = 803 */
}
-static void dump_mac_header(const struct nf_loginfo *info,
+static void dump_mac_header(struct sbuff *m,
+ const struct nf_loginfo *info,
const struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
@@ -378,7 +378,7 @@ static void dump_mac_header(const struct nf_loginfo *info,
switch (dev->type) {
case ARPHRD_ETHER:
- printk("MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
+ sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
ntohs(eth_hdr(skb)->h_proto));
return;
@@ -387,17 +387,17 @@ static void dump_mac_header(const struct nf_loginfo *info,
}
fallback:
- printk("MAC=");
+ sb_add(m, "MAC=");
if (dev->hard_header_len &&
skb->mac_header != skb->network_header) {
const unsigned char *p = skb_mac_header(skb);
unsigned int i;
- printk("%02x", *p++);
+ sb_add(m, "%02x", *p++);
for (i = 1; i < dev->hard_header_len; i++, p++)
- printk(":%02x", *p);
+ sb_add(m, ":%02x", *p);
}
- printk(" ");
+ sb_add(m, " ");
}
static struct nf_loginfo default_loginfo = {
@@ -419,11 +419,12 @@ ipt_log_packet(u_int8_t pf,
const struct nf_loginfo *loginfo,
const char *prefix)
{
+ struct sbuff *m = sb_open();
+
if (!loginfo)
loginfo = &default_loginfo;
- spin_lock_bh(&log_lock);
- printk("<%d>%sIN=%s OUT=%s ", loginfo->u.log.level,
+ sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level,
prefix,
in ? in->name : "",
out ? out->name : "");
@@ -434,20 +435,20 @@ ipt_log_packet(u_int8_t pf,
physindev = skb->nf_bridge->physindev;
if (physindev && in != physindev)
- printk("PHYSIN=%s ", physindev->name);
+ sb_add(m, "PHYSIN=%s ", physindev->name);
physoutdev = skb->nf_bridge->physoutdev;
if (physoutdev && out != physoutdev)
- printk("PHYSOUT=%s ", physoutdev->name);
+ sb_add(m, "PHYSOUT=%s ", physoutdev->name);
}
#endif
/* MAC logging for input path only. */
if (in && !out)
- dump_mac_header(loginfo, skb);
+ dump_mac_header(m, loginfo, skb);
+
+ dump_packet(m, loginfo, skb, 0);
- dump_packet(loginfo, skb, 0);
- printk("\n");
- spin_unlock_bh(&log_lock);
+ sb_close(m);
}
static unsigned int
diff --git a/net/ipv4/netfilter/nf_nat_amanda.c b/net/ipv4/netfilter/nf_nat_amanda.c
index c31b87668250..0f23b3f06df0 100644
--- a/net/ipv4/netfilter/nf_nat_amanda.c
+++ b/net/ipv4/netfilter/nf_nat_amanda.c
@@ -44,9 +44,16 @@ static unsigned int help(struct sk_buff *skb,
/* Try to get same port: if not, try to change it. */
for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
+ int ret;
+
exp->tuple.dst.u.tcp.port = htons(port);
- if (nf_ct_expect_related(exp) == 0)
+ ret = nf_ct_expect_related(exp);
+ if (ret == 0)
+ break;
+ else if (ret != -EBUSY) {
+ port = 0;
break;
+ }
}
if (port == 0)
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 957c9241fb0c..295c97431e43 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -47,7 +47,7 @@ __nf_nat_proto_find(u_int8_t protonum)
return rcu_dereference(nf_nat_protos[protonum]);
}
-const struct nf_nat_protocol *
+static const struct nf_nat_protocol *
nf_nat_proto_find_get(u_int8_t protonum)
{
const struct nf_nat_protocol *p;
@@ -60,14 +60,12 @@ nf_nat_proto_find_get(u_int8_t protonum)
return p;
}
-EXPORT_SYMBOL_GPL(nf_nat_proto_find_get);
-void
+static void
nf_nat_proto_put(const struct nf_nat_protocol *p)
{
module_put(p->me);
}
-EXPORT_SYMBOL_GPL(nf_nat_proto_put);
/* We keep an extra hash for each conntrack, for fast searching. */
static inline unsigned int
@@ -262,11 +260,17 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
proto = __nf_nat_proto_find(orig_tuple->dst.protonum);
/* Only bother mapping if it's not already in range and unique */
- if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM) &&
- (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
- proto->in_range(tuple, maniptype, &range->min, &range->max)) &&
- !nf_nat_used_tuple(tuple, ct))
- goto out;
+ if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) {
+ if (range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+ if (proto->in_range(tuple, maniptype, &range->min,
+ &range->max) &&
+ (range->min.all == range->max.all ||
+ !nf_nat_used_tuple(tuple, ct)))
+ goto out;
+ } else if (!nf_nat_used_tuple(tuple, ct)) {
+ goto out;
+ }
+ }
/* Last change: get protocol to try to obtain unique tuple. */
proto->unique_tuple(tuple, range, maniptype, ct);
@@ -458,6 +462,18 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
return 0;
}
+ if (manip == IP_NAT_MANIP_SRC)
+ statusbit = IPS_SRC_NAT;
+ else
+ statusbit = IPS_DST_NAT;
+
+ /* Invert if this is reply dir. */
+ if (dir == IP_CT_DIR_REPLY)
+ statusbit ^= IPS_NAT_MASK;
+
+ if (!(ct->status & statusbit))
+ return 1;
+
pr_debug("icmp_reply_translation: translating error %p manip %u "
"dir %s\n", skb, manip,
dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
@@ -492,20 +508,9 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
/* Change outer to look the reply to an incoming packet
* (proto 0 means don't invert per-proto part). */
- if (manip == IP_NAT_MANIP_SRC)
- statusbit = IPS_SRC_NAT;
- else
- statusbit = IPS_DST_NAT;
-
- /* Invert if this is reply dir. */
- if (dir == IP_CT_DIR_REPLY)
- statusbit ^= IPS_NAT_MASK;
-
- if (ct->status & statusbit) {
- nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
- if (!manip_pkt(0, skb, 0, &target, manip))
- return 0;
- }
+ nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
+ if (!manip_pkt(0, skb, 0, &target, manip))
+ return 0;
return 1;
}
diff --git a/net/ipv4/netfilter/nf_nat_ftp.c b/net/ipv4/netfilter/nf_nat_ftp.c
index 86e0e84ff0a0..dc73abb3fe27 100644
--- a/net/ipv4/netfilter/nf_nat_ftp.c
+++ b/net/ipv4/netfilter/nf_nat_ftp.c
@@ -79,9 +79,16 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb,
/* Try to get same port: if not, try to change it. */
for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
+ int ret;
+
exp->tuple.dst.u.tcp.port = htons(port);
- if (nf_ct_expect_related(exp) == 0)
+ ret = nf_ct_expect_related(exp);
+ if (ret == 0)
+ break;
+ else if (ret != -EBUSY) {
+ port = 0;
break;
+ }
}
if (port == 0)
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index 5045196d853c..790f3160e012 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -222,13 +222,24 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
/* Try to get a pair of ports. */
for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port);
nated_port != 0; nated_port += 2) {
+ int ret;
+
rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
- if (nf_ct_expect_related(rtp_exp) == 0) {
+ ret = nf_ct_expect_related(rtp_exp);
+ if (ret == 0) {
rtcp_exp->tuple.dst.u.udp.port =
htons(nated_port + 1);
- if (nf_ct_expect_related(rtcp_exp) == 0)
+ ret = nf_ct_expect_related(rtcp_exp);
+ if (ret == 0)
+ break;
+ else if (ret != -EBUSY) {
+ nf_ct_unexpect_related(rtp_exp);
+ nated_port = 0;
break;
- nf_ct_unexpect_related(rtp_exp);
+ }
+ } else if (ret != -EBUSY) {
+ nated_port = 0;
+ break;
}
}
@@ -284,9 +295,16 @@ static int nat_t120(struct sk_buff *skb, struct nf_conn *ct,
/* Try to get same port: if not, try to change it. */
for (; nated_port != 0; nated_port++) {
+ int ret;
+
exp->tuple.dst.u.tcp.port = htons(nated_port);
- if (nf_ct_expect_related(exp) == 0)
+ ret = nf_ct_expect_related(exp);
+ if (ret == 0)
+ break;
+ else if (ret != -EBUSY) {
+ nated_port = 0;
break;
+ }
}
if (nated_port == 0) { /* No port available */
@@ -334,9 +352,16 @@ static int nat_h245(struct sk_buff *skb, struct nf_conn *ct,
/* Try to get same port: if not, try to change it. */
for (; nated_port != 0; nated_port++) {
+ int ret;
+
exp->tuple.dst.u.tcp.port = htons(nated_port);
- if (nf_ct_expect_related(exp) == 0)
+ ret = nf_ct_expect_related(exp);
+ if (ret == 0)
break;
+ else if (ret != -EBUSY) {
+ nated_port = 0;
+ break;
+ }
}
if (nated_port == 0) { /* No port available */
@@ -418,9 +443,16 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
/* Try to get same port: if not, try to change it. */
for (; nated_port != 0; nated_port++) {
+ int ret;
+
exp->tuple.dst.u.tcp.port = htons(nated_port);
- if (nf_ct_expect_related(exp) == 0)
+ ret = nf_ct_expect_related(exp);
+ if (ret == 0)
+ break;
+ else if (ret != -EBUSY) {
+ nated_port = 0;
break;
+ }
}
if (nated_port == 0) { /* No port available */
@@ -500,9 +532,16 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
/* Try to get same port: if not, try to change it. */
for (nated_port = ntohs(port); nated_port != 0; nated_port++) {
+ int ret;
+
exp->tuple.dst.u.tcp.port = htons(nated_port);
- if (nf_ct_expect_related(exp) == 0)
+ ret = nf_ct_expect_related(exp);
+ if (ret == 0)
break;
+ else if (ret != -EBUSY) {
+ nated_port = 0;
+ break;
+ }
}
if (nated_port == 0) { /* No port available */
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
index 4a0c6b548eee..31427fb57aa8 100644
--- a/net/ipv4/netfilter/nf_nat_helper.c
+++ b/net/ipv4/netfilter/nf_nat_helper.c
@@ -153,6 +153,35 @@ void nf_nat_set_seq_adjust(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
}
EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust);
+static void nf_nat_csum(struct sk_buff *skb, struct iphdr *iph, void *data,
+ int datalen, __sum16 *check, int oldlen)
+{
+ struct rtable *rt = skb_rtable(skb);
+
+ if (skb->ip_summed != CHECKSUM_PARTIAL) {
+ if (!(rt->rt_flags & RTCF_LOCAL) &&
+ skb->dev->features & NETIF_F_V4_CSUM) {
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ skb->csum_start = skb_headroom(skb) +
+ skb_network_offset(skb) +
+ iph->ihl * 4;
+ skb->csum_offset = (void *)check - data;
+ *check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+ datalen, iph->protocol, 0);
+ } else {
+ *check = 0;
+ *check = csum_tcpudp_magic(iph->saddr, iph->daddr,
+ datalen, iph->protocol,
+ csum_partial(data, datalen,
+ 0));
+ if (iph->protocol == IPPROTO_UDP && !*check)
+ *check = CSUM_MANGLED_0;
+ }
+ } else
+ inet_proto_csum_replace2(check, skb,
+ htons(oldlen), htons(datalen), 1);
+}
+
/* Generic function for mangling variable-length address changes inside
* NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
* command in FTP).
@@ -169,7 +198,6 @@ int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
const char *rep_buffer,
unsigned int rep_len, bool adjust)
{
- struct rtable *rt = skb_rtable(skb);
struct iphdr *iph;
struct tcphdr *tcph;
int oldlen, datalen;
@@ -192,26 +220,7 @@ int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
match_offset, match_len, rep_buffer, rep_len);
datalen = skb->len - iph->ihl*4;
- if (skb->ip_summed != CHECKSUM_PARTIAL) {
- if (!(rt->rt_flags & RTCF_LOCAL) &&
- skb->dev->features & NETIF_F_V4_CSUM) {
- skb->ip_summed = CHECKSUM_PARTIAL;
- skb->csum_start = skb_headroom(skb) +
- skb_network_offset(skb) +
- iph->ihl * 4;
- skb->csum_offset = offsetof(struct tcphdr, check);
- tcph->check = ~tcp_v4_check(datalen,
- iph->saddr, iph->daddr, 0);
- } else {
- tcph->check = 0;
- tcph->check = tcp_v4_check(datalen,
- iph->saddr, iph->daddr,
- csum_partial(tcph,
- datalen, 0));
- }
- } else
- inet_proto_csum_replace2(&tcph->check, skb,
- htons(oldlen), htons(datalen), 1);
+ nf_nat_csum(skb, iph, tcph, datalen, &tcph->check, oldlen);
if (adjust && rep_len != match_len)
nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq,
@@ -240,7 +249,6 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
const char *rep_buffer,
unsigned int rep_len)
{
- struct rtable *rt = skb_rtable(skb);
struct iphdr *iph;
struct udphdr *udph;
int datalen, oldlen;
@@ -274,29 +282,7 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL)
return 1;
- if (skb->ip_summed != CHECKSUM_PARTIAL) {
- if (!(rt->rt_flags & RTCF_LOCAL) &&
- skb->dev->features & NETIF_F_V4_CSUM) {
- skb->ip_summed = CHECKSUM_PARTIAL;
- skb->csum_start = skb_headroom(skb) +
- skb_network_offset(skb) +
- iph->ihl * 4;
- skb->csum_offset = offsetof(struct udphdr, check);
- udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
- datalen, IPPROTO_UDP,
- 0);
- } else {
- udph->check = 0;
- udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
- datalen, IPPROTO_UDP,
- csum_partial(udph,
- datalen, 0));
- if (!udph->check)
- udph->check = CSUM_MANGLED_0;
- }
- } else
- inet_proto_csum_replace2(&udph->check, skb,
- htons(oldlen), htons(datalen), 1);
+ nf_nat_csum(skb, iph, udph, datalen, &udph->check, oldlen);
return 1;
}
diff --git a/net/ipv4/netfilter/nf_nat_irc.c b/net/ipv4/netfilter/nf_nat_irc.c
index ea83a886b03e..535e1a802356 100644
--- a/net/ipv4/netfilter/nf_nat_irc.c
+++ b/net/ipv4/netfilter/nf_nat_irc.c
@@ -45,9 +45,16 @@ static unsigned int help(struct sk_buff *skb,
/* Try to get same port: if not, try to change it. */
for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
+ int ret;
+
exp->tuple.dst.u.tcp.port = htons(port);
- if (nf_ct_expect_related(exp) == 0)
+ ret = nf_ct_expect_related(exp);
+ if (ret == 0)
+ break;
+ else if (ret != -EBUSY) {
+ port = 0;
break;
+ }
}
if (port == 0)
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
index ebbd319f62f5..21c30426480b 100644
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -106,16 +106,15 @@ alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
{
/* Force range to this IP; let proto decide mapping for
per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
- Use reply in case it's already been mangled (eg local packet).
*/
- __be32 ip
- = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
- ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip
- : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip);
- struct nf_nat_range range
- = { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } };
-
- pr_debug("Allocating NULL binding for %p (%pI4)\n", ct, &ip);
+ struct nf_nat_range range;
+
+ range.flags = 0;
+ pr_debug("Allocating NULL binding for %p (%pI4)\n", ct,
+ HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC ?
+ &ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip :
+ &ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip);
+
return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
}
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index 11b538deaaec..e40cf7816fdb 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -307,9 +307,16 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int dataoff,
exp->expectfn = ip_nat_sip_expected;
for (; port != 0; port++) {
+ int ret;
+
exp->tuple.dst.u.udp.port = htons(port);
- if (nf_ct_expect_related(exp) == 0)
+ ret = nf_ct_expect_related(exp);
+ if (ret == 0)
+ break;
+ else if (ret != -EBUSY) {
+ port = 0;
break;
+ }
}
if (port == 0)
@@ -480,13 +487,25 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff,
/* Try to get same pair of ports: if not, try to change them. */
for (port = ntohs(rtp_exp->tuple.dst.u.udp.port);
port != 0; port += 2) {
+ int ret;
+
rtp_exp->tuple.dst.u.udp.port = htons(port);
- if (nf_ct_expect_related(rtp_exp) != 0)
+ ret = nf_ct_expect_related(rtp_exp);
+ if (ret == -EBUSY)
continue;
+ else if (ret < 0) {
+ port = 0;
+ break;
+ }
rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
- if (nf_ct_expect_related(rtcp_exp) == 0)
+ ret = nf_ct_expect_related(rtcp_exp);
+ if (ret == 0)
break;
- nf_ct_unexpect_related(rtp_exp);
+ else if (ret != -EBUSY) {
+ nf_ct_unexpect_related(rtp_exp);
+ port = 0;
+ break;
+ }
}
if (port == 0)
diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c
index f2d297351405..9ae5c01cd0b2 100644
--- a/net/ipv4/protocol.c
+++ b/net/ipv4/protocol.c
@@ -28,8 +28,7 @@
#include <linux/spinlock.h>
#include <net/protocol.h>
-const struct net_protocol *inet_protos[MAX_INET_PROTOS] ____cacheline_aligned_in_smp;
-static DEFINE_SPINLOCK(inet_proto_lock);
+const struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS] __read_mostly;
/*
* Add a protocol handler to the hash tables
@@ -37,20 +36,10 @@ static DEFINE_SPINLOCK(inet_proto_lock);
int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol)
{
- int hash, ret;
+ int hash = protocol & (MAX_INET_PROTOS - 1);
- hash = protocol & (MAX_INET_PROTOS - 1);
-
- spin_lock_bh(&inet_proto_lock);
- if (inet_protos[hash]) {
- ret = -1;
- } else {
- inet_protos[hash] = prot;
- ret = 0;
- }
- spin_unlock_bh(&inet_proto_lock);
-
- return ret;
+ return !cmpxchg((const struct net_protocol **)&inet_protos[hash],
+ NULL, prot) ? 0 : -1;
}
EXPORT_SYMBOL(inet_add_protocol);
@@ -60,18 +49,10 @@ EXPORT_SYMBOL(inet_add_protocol);
int inet_del_protocol(const struct net_protocol *prot, unsigned char protocol)
{
- int hash, ret;
-
- hash = protocol & (MAX_INET_PROTOS - 1);
+ int ret, hash = protocol & (MAX_INET_PROTOS - 1);
- spin_lock_bh(&inet_proto_lock);
- if (inet_protos[hash] == prot) {
- inet_protos[hash] = NULL;
- ret = 0;
- } else {
- ret = -1;
- }
- spin_unlock_bh(&inet_proto_lock);
+ ret = (cmpxchg((const struct net_protocol **)&inet_protos[hash],
+ prot, NULL) == prot) ? 0 : -1;
synchronize_net();
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 009a7b2aa1ef..1f85ef289895 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -505,7 +505,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
ipc.addr = inet->inet_saddr;
ipc.opt = NULL;
- ipc.shtx.flags = 0;
+ ipc.tx_flags = 0;
ipc.oif = sk->sk_bound_dev_if;
if (msg->msg_controllen) {
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index ac6559cb54f9..987bf9adb318 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -159,7 +159,6 @@ static struct dst_ops ipv4_dst_ops = {
.link_failure = ipv4_link_failure,
.update_pmtu = ip_rt_update_pmtu,
.local_out = __ip_local_out,
- .entries = ATOMIC_INIT(0),
};
#define ECN_OR_COST(class) TC_PRIO_##class
@@ -199,7 +198,7 @@ const __u8 ip_tos2prio[16] = {
*/
struct rt_hash_bucket {
- struct rtable *chain;
+ struct rtable __rcu *chain;
};
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || \
@@ -281,7 +280,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 (!rt_hash_table[st->bucket].chain)
+ if (!rcu_dereference_raw(rt_hash_table[st->bucket].chain))
continue;
rcu_read_lock_bh();
r = rcu_dereference_bh(rt_hash_table[st->bucket].chain);
@@ -301,17 +300,17 @@ static struct rtable *__rt_cache_get_next(struct seq_file *seq,
{
struct rt_cache_iter_state *st = seq->private;
- r = r->dst.rt_next;
+ r = rcu_dereference_bh(r->dst.rt_next);
while (!r) {
rcu_read_unlock_bh();
do {
if (--st->bucket < 0)
return NULL;
- } while (!rt_hash_table[st->bucket].chain);
+ } while (!rcu_dereference_raw(rt_hash_table[st->bucket].chain));
rcu_read_lock_bh();
- r = rt_hash_table[st->bucket].chain;
+ r = rcu_dereference_bh(rt_hash_table[st->bucket].chain);
}
- return rcu_dereference_bh(r);
+ return r;
}
static struct rtable *rt_cache_get_next(struct seq_file *seq,
@@ -466,7 +465,7 @@ static int rt_cpu_seq_show(struct seq_file *seq, void *v)
seq_printf(seq,"%08x %08x %08x %08x %08x %08x %08x %08x "
" %08x %08x %08x %08x %08x %08x %08x %08x %08x \n",
- atomic_read(&ipv4_dst_ops.entries),
+ dst_entries_get_slow(&ipv4_dst_ops),
st->in_hit,
st->in_slow_tot,
st->in_slow_mc,
@@ -722,19 +721,23 @@ static void rt_do_flush(int process_context)
for (i = 0; i <= rt_hash_mask; i++) {
if (process_context && need_resched())
cond_resched();
- rth = rt_hash_table[i].chain;
+ rth = rcu_dereference_raw(rt_hash_table[i].chain);
if (!rth)
continue;
spin_lock_bh(rt_hash_lock_addr(i));
#ifdef CONFIG_NET_NS
{
- struct rtable ** prev, * p;
+ struct rtable __rcu **prev;
+ struct rtable *p;
- rth = rt_hash_table[i].chain;
+ rth = rcu_dereference_protected(rt_hash_table[i].chain,
+ lockdep_is_held(rt_hash_lock_addr(i)));
/* defer releasing the head of the list after spin_unlock */
- for (tail = rth; tail; tail = tail->dst.rt_next)
+ for (tail = rth; tail;
+ tail = rcu_dereference_protected(tail->dst.rt_next,
+ lockdep_is_held(rt_hash_lock_addr(i))))
if (!rt_is_expired(tail))
break;
if (rth != tail)
@@ -742,8 +745,12 @@ static void rt_do_flush(int process_context)
/* call rt_free on entries after the tail requiring flush */
prev = &rt_hash_table[i].chain;
- for (p = *prev; p; p = next) {
- next = p->dst.rt_next;
+ for (p = rcu_dereference_protected(*prev,
+ lockdep_is_held(rt_hash_lock_addr(i)));
+ p != NULL;
+ p = next) {
+ next = rcu_dereference_protected(p->dst.rt_next,
+ lockdep_is_held(rt_hash_lock_addr(i)));
if (!rt_is_expired(p)) {
prev = &p->dst.rt_next;
} else {
@@ -753,14 +760,15 @@ static void rt_do_flush(int process_context)
}
}
#else
- rth = rt_hash_table[i].chain;
- rt_hash_table[i].chain = NULL;
+ rth = rcu_dereference_protected(rt_hash_table[i].chain,
+ lockdep_is_held(rt_hash_lock_addr(i)));
+ rcu_assign_pointer(rt_hash_table[i].chain, NULL);
tail = NULL;
#endif
spin_unlock_bh(rt_hash_lock_addr(i));
for (; rth != tail; rth = next) {
- next = rth->dst.rt_next;
+ next = rcu_dereference_protected(rth->dst.rt_next, 1);
rt_free(rth);
}
}
@@ -791,7 +799,7 @@ static int has_noalias(const struct rtable *head, const struct rtable *rth)
while (aux != rth) {
if (compare_hash_inputs(&aux->fl, &rth->fl))
return 0;
- aux = aux->dst.rt_next;
+ aux = rcu_dereference_protected(aux->dst.rt_next, 1);
}
return ONE;
}
@@ -800,7 +808,8 @@ static void rt_check_expire(void)
{
static unsigned int rover;
unsigned int i = rover, goal;
- struct rtable *rth, **rthp;
+ struct rtable *rth;
+ struct rtable __rcu **rthp;
unsigned long samples = 0;
unsigned long sum = 0, sum2 = 0;
unsigned long delta;
@@ -826,11 +835,12 @@ static void rt_check_expire(void)
samples++;
- if (*rthp == NULL)
+ if (rcu_dereference_raw(*rthp) == NULL)
continue;
length = 0;
spin_lock_bh(rt_hash_lock_addr(i));
- while ((rth = *rthp) != NULL) {
+ while ((rth = rcu_dereference_protected(*rthp,
+ lockdep_is_held(rt_hash_lock_addr(i)))) != NULL) {
prefetch(rth->dst.rt_next);
if (rt_is_expired(rth)) {
*rthp = rth->dst.rt_next;
@@ -942,9 +952,11 @@ static int rt_garbage_collect(struct dst_ops *ops)
static unsigned long last_gc;
static int rover;
static int equilibrium;
- struct rtable *rth, **rthp;
+ struct rtable *rth;
+ struct rtable __rcu **rthp;
unsigned long now = jiffies;
int goal;
+ int entries = dst_entries_get_fast(&ipv4_dst_ops);
/*
* Garbage collection is pretty expensive,
@@ -954,28 +966,28 @@ static int rt_garbage_collect(struct dst_ops *ops)
RT_CACHE_STAT_INC(gc_total);
if (now - last_gc < ip_rt_gc_min_interval &&
- atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size) {
+ entries < ip_rt_max_size) {
RT_CACHE_STAT_INC(gc_ignored);
goto out;
}
+ entries = dst_entries_get_slow(&ipv4_dst_ops);
/* Calculate number of entries, which we want to expire now. */
- goal = atomic_read(&ipv4_dst_ops.entries) -
- (ip_rt_gc_elasticity << rt_hash_log);
+ goal = entries - (ip_rt_gc_elasticity << rt_hash_log);
if (goal <= 0) {
if (equilibrium < ipv4_dst_ops.gc_thresh)
equilibrium = ipv4_dst_ops.gc_thresh;
- goal = atomic_read(&ipv4_dst_ops.entries) - equilibrium;
+ goal = entries - equilibrium;
if (goal > 0) {
equilibrium += min_t(unsigned int, goal >> 1, rt_hash_mask + 1);
- goal = atomic_read(&ipv4_dst_ops.entries) - equilibrium;
+ goal = entries - equilibrium;
}
} else {
/* We are in dangerous area. Try to reduce cache really
* aggressively.
*/
goal = max_t(unsigned int, goal >> 1, rt_hash_mask + 1);
- equilibrium = atomic_read(&ipv4_dst_ops.entries) - goal;
+ equilibrium = entries - goal;
}
if (now - last_gc >= ip_rt_gc_min_interval)
@@ -995,7 +1007,8 @@ static int rt_garbage_collect(struct dst_ops *ops)
k = (k + 1) & rt_hash_mask;
rthp = &rt_hash_table[k].chain;
spin_lock_bh(rt_hash_lock_addr(k));
- while ((rth = *rthp) != NULL) {
+ while ((rth = rcu_dereference_protected(*rthp,
+ lockdep_is_held(rt_hash_lock_addr(k)))) != NULL) {
if (!rt_is_expired(rth) &&
!rt_may_expire(rth, tmo, expire)) {
tmo >>= 1;
@@ -1032,14 +1045,16 @@ static int rt_garbage_collect(struct dst_ops *ops)
expire >>= 1;
#if RT_CACHE_DEBUG >= 2
printk(KERN_DEBUG "expire>> %u %d %d %d\n", expire,
- atomic_read(&ipv4_dst_ops.entries), goal, i);
+ dst_entries_get_fast(&ipv4_dst_ops), goal, i);
#endif
- if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
+ if (dst_entries_get_fast(&ipv4_dst_ops) < ip_rt_max_size)
goto out;
} while (!in_softirq() && time_before_eq(jiffies, now));
- if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
+ if (dst_entries_get_fast(&ipv4_dst_ops) < ip_rt_max_size)
+ goto out;
+ if (dst_entries_get_slow(&ipv4_dst_ops) < ip_rt_max_size)
goto out;
if (net_ratelimit())
printk(KERN_WARNING "dst cache overflow\n");
@@ -1049,11 +1064,12 @@ static int rt_garbage_collect(struct dst_ops *ops)
work_done:
expire += ip_rt_gc_min_interval;
if (expire > ip_rt_gc_timeout ||
- atomic_read(&ipv4_dst_ops.entries) < ipv4_dst_ops.gc_thresh)
+ dst_entries_get_fast(&ipv4_dst_ops) < ipv4_dst_ops.gc_thresh ||
+ dst_entries_get_slow(&ipv4_dst_ops) < ipv4_dst_ops.gc_thresh)
expire = ip_rt_gc_timeout;
#if RT_CACHE_DEBUG >= 2
printk(KERN_DEBUG "expire++ %u %d %d %d\n", expire,
- atomic_read(&ipv4_dst_ops.entries), goal, rover);
+ dst_entries_get_fast(&ipv4_dst_ops), goal, rover);
#endif
out: return 0;
}
@@ -1068,7 +1084,7 @@ static int slow_chain_length(const struct rtable *head)
while (rth) {
length += has_noalias(head, rth);
- rth = rth->dst.rt_next;
+ rth = rcu_dereference_protected(rth->dst.rt_next, 1);
}
return length >> FRACT_BITS;
}
@@ -1076,9 +1092,9 @@ static int slow_chain_length(const struct rtable *head)
static int rt_intern_hash(unsigned hash, struct rtable *rt,
struct rtable **rp, struct sk_buff *skb, int ifindex)
{
- struct rtable *rth, **rthp;
+ struct rtable *rth, *cand;
+ struct rtable __rcu **rthp, **candp;
unsigned long now;
- struct rtable *cand, **candp;
u32 min_score;
int chain_length;
int attempts = !in_softirq();
@@ -1102,30 +1118,31 @@ restart:
* Note that we do rt_free on this new route entry, so that
* once its refcount hits zero, we are still able to reap it
* (Thanks Alexey)
- * Note also the rt_free uses call_rcu. We don't actually
- * need rcu protection here, this is just our path to get
- * on the route gc list.
+ * Note: To avoid expensive rcu stuff for this uncached dst,
+ * we set DST_NOCACHE so that dst_release() can free dst without
+ * waiting a grace period.
*/
+ rt->dst.flags |= DST_NOCACHE;
if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) {
int err = arp_bind_neighbour(&rt->dst);
if (err) {
if (net_ratelimit())
printk(KERN_WARNING
"Neighbour table failure & not caching routes.\n");
- rt_drop(rt);
+ ip_rt_put(rt);
return err;
}
}
- rt_free(rt);
goto skip_hashing;
}
rthp = &rt_hash_table[hash].chain;
spin_lock_bh(rt_hash_lock_addr(hash));
- while ((rth = *rthp) != NULL) {
+ while ((rth = rcu_dereference_protected(*rthp,
+ lockdep_is_held(rt_hash_lock_addr(hash)))) != NULL) {
if (rt_is_expired(rth)) {
*rthp = rth->dst.rt_next;
rt_free(rth);
@@ -1268,18 +1285,11 @@ skip_hashing:
void rt_bind_peer(struct rtable *rt, int create)
{
- static DEFINE_SPINLOCK(rt_peer_lock);
struct inet_peer *peer;
peer = inet_getpeer(rt->rt_dst, create);
- spin_lock_bh(&rt_peer_lock);
- if (rt->peer == NULL) {
- rt->peer = peer;
- peer = NULL;
- }
- spin_unlock_bh(&rt_peer_lock);
- if (peer)
+ if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL)
inet_putpeer(peer);
}
@@ -1328,12 +1338,14 @@ EXPORT_SYMBOL(__ip_select_ident);
static void rt_del(unsigned hash, struct rtable *rt)
{
- struct rtable **rthp, *aux;
+ struct rtable __rcu **rthp;
+ struct rtable *aux;
rthp = &rt_hash_table[hash].chain;
spin_lock_bh(rt_hash_lock_addr(hash));
ip_rt_put(rt);
- while ((aux = *rthp) != NULL) {
+ while ((aux = rcu_dereference_protected(*rthp,
+ lockdep_is_held(rt_hash_lock_addr(hash)))) != NULL) {
if (aux == rt || rt_is_expired(aux)) {
*rthp = aux->dst.rt_next;
rt_free(aux);
@@ -1350,7 +1362,8 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
{
int i, k;
struct in_device *in_dev = __in_dev_get_rcu(dev);
- struct rtable *rth, **rthp;
+ struct rtable *rth;
+ struct rtable __rcu **rthp;
__be32 skeys[2] = { saddr, 0 };
int ikeys[2] = { dev->ifindex, 0 };
struct netevent_redirect netevent;
@@ -1383,7 +1396,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
unsigned hash = rt_hash(daddr, skeys[i], ikeys[k],
rt_genid(net));
- rthp=&rt_hash_table[hash].chain;
+ rthp = &rt_hash_table[hash].chain;
while ((rth = rcu_dereference(*rthp)) != NULL) {
struct rtable *rt;
@@ -1779,12 +1792,15 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt)
if (rt->fl.iif == 0)
src = rt->rt_src;
- else if (fib_lookup(dev_net(rt->dst.dev), &rt->fl, &res) == 0) {
- src = FIB_RES_PREFSRC(res);
- fib_res_put(&res);
- } else
- src = inet_select_addr(rt->dst.dev, rt->rt_gateway,
+ else {
+ rcu_read_lock();
+ if (fib_lookup(dev_net(rt->dst.dev), &rt->fl, &res) == 0)
+ src = FIB_RES_PREFSRC(res);
+ else
+ src = inet_select_addr(rt->dst.dev, rt->rt_gateway,
RT_SCOPE_UNIVERSE);
+ rcu_read_unlock();
+ }
memcpy(addr, &src, 4);
}
@@ -2087,6 +2103,7 @@ static int ip_mkroute_input(struct sk_buff *skb,
* Such approach solves two big problems:
* 1. Not simplex devices are handled properly.
* 2. IP spoofing attempts are filtered with 100% of guarantee.
+ * called with rcu_read_lock()
*/
static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
@@ -2108,7 +2125,6 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
unsigned hash;
__be32 spec_dst;
int err = -EINVAL;
- int free_res = 0;
struct net * net = dev_net(dev);
/* IP on this device is disabled. */
@@ -2124,7 +2140,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
ipv4_is_loopback(saddr))
goto martian_source;
- if (daddr == htonl(0xFFFFFFFF) || (saddr == 0 && daddr == 0))
+ if (ipv4_is_lbcast(daddr) || (saddr == 0 && daddr == 0))
goto brd_input;
/* Accept zero addresses only to limited broadcast;
@@ -2133,19 +2149,18 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
if (ipv4_is_zeronet(saddr))
goto martian_source;
- if (ipv4_is_lbcast(daddr) || ipv4_is_zeronet(daddr) ||
- ipv4_is_loopback(daddr))
+ if (ipv4_is_zeronet(daddr) || ipv4_is_loopback(daddr))
goto martian_destination;
/*
* Now we are ready to route packet.
*/
- if ((err = fib_lookup(net, &fl, &res)) != 0) {
+ err = fib_lookup(net, &fl, &res);
+ if (err != 0) {
if (!IN_DEV_FORWARD(in_dev))
goto e_hostunreach;
goto no_route;
}
- free_res = 1;
RT_CACHE_STAT_INC(in_slow_tot);
@@ -2154,8 +2169,8 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
if (res.type == RTN_LOCAL) {
err = fib_validate_source(saddr, daddr, tos,
- net->loopback_dev->ifindex,
- dev, &spec_dst, &itag, skb->mark);
+ net->loopback_dev->ifindex,
+ dev, &spec_dst, &itag, skb->mark);
if (err < 0)
goto martian_source_keep_err;
if (err)
@@ -2170,9 +2185,6 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
goto martian_destination;
err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);
-done:
- if (free_res)
- fib_res_put(&res);
out: return err;
brd_input:
@@ -2232,7 +2244,7 @@ local_input:
rth->rt_type = res.type;
hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net));
err = rt_intern_hash(hash, rth, NULL, skb, fl.iif);
- goto done;
+ goto out;
no_route:
RT_CACHE_STAT_INC(in_no_route);
@@ -2255,21 +2267,21 @@ martian_destination:
e_hostunreach:
err = -EHOSTUNREACH;
- goto done;
+ goto out;
e_inval:
err = -EINVAL;
- goto done;
+ goto out;
e_nobufs:
err = -ENOBUFS;
- goto done;
+ goto out;
martian_source:
err = -EINVAL;
martian_source_keep_err:
ip_handle_martian_source(dev, in_dev, skb, daddr, saddr);
- goto done;
+ goto out;
}
int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
@@ -2355,6 +2367,7 @@ skip_cache:
}
EXPORT_SYMBOL(ip_route_input_common);
+/* called with rcu_read_lock() */
static int __mkroute_output(struct rtable **result,
struct fib_result *res,
const struct flowi *fl,
@@ -2365,53 +2378,47 @@ static int __mkroute_output(struct rtable **result,
struct rtable *rth;
struct in_device *in_dev;
u32 tos = RT_FL_TOS(oldflp);
- int err = 0;
- if (ipv4_is_loopback(fl->fl4_src) && !(dev_out->flags&IFF_LOOPBACK))
+ if (ipv4_is_loopback(fl->fl4_src) && !(dev_out->flags & IFF_LOOPBACK))
return -EINVAL;
- if (fl->fl4_dst == htonl(0xFFFFFFFF))
+ if (ipv4_is_lbcast(fl->fl4_dst))
res->type = RTN_BROADCAST;
else if (ipv4_is_multicast(fl->fl4_dst))
res->type = RTN_MULTICAST;
- else if (ipv4_is_lbcast(fl->fl4_dst) || ipv4_is_zeronet(fl->fl4_dst))
+ else if (ipv4_is_zeronet(fl->fl4_dst))
return -EINVAL;
if (dev_out->flags & IFF_LOOPBACK)
flags |= RTCF_LOCAL;
- /* get work reference to inet device */
- in_dev = in_dev_get(dev_out);
+ in_dev = __in_dev_get_rcu(dev_out);
if (!in_dev)
return -EINVAL;
if (res->type == RTN_BROADCAST) {
flags |= RTCF_BROADCAST | RTCF_LOCAL;
- if (res->fi) {
- fib_info_put(res->fi);
- res->fi = NULL;
- }
+ res->fi = NULL;
} else if (res->type == RTN_MULTICAST) {
- flags |= RTCF_MULTICAST|RTCF_LOCAL;
+ flags |= RTCF_MULTICAST | RTCF_LOCAL;
if (!ip_check_mc(in_dev, oldflp->fl4_dst, oldflp->fl4_src,
oldflp->proto))
flags &= ~RTCF_LOCAL;
/* If multicast route do not exist use
- default one, but do not gateway in this case.
- Yes, it is hack.
+ * default one, but do not gateway in this case.
+ * Yes, it is hack.
*/
- if (res->fi && res->prefixlen < 4) {
- fib_info_put(res->fi);
+ if (res->fi && res->prefixlen < 4)
res->fi = NULL;
- }
}
rth = dst_alloc(&ipv4_dst_ops);
- if (!rth) {
- err = -ENOBUFS;
- goto cleanup;
- }
+ if (!rth)
+ return -ENOBUFS;
+
+ in_dev_hold(in_dev);
+ rth->idev = in_dev;
atomic_set(&rth->dst.__refcnt, 1);
rth->dst.flags= DST_HOST;
@@ -2432,7 +2439,6 @@ static int __mkroute_output(struct rtable **result,
cache entry */
rth->dst.dev = dev_out;
dev_hold(dev_out);
- rth->idev = in_dev_get(dev_out);
rth->rt_gateway = fl->fl4_dst;
rth->rt_spec_dst= fl->fl4_src;
@@ -2467,15 +2473,11 @@ static int __mkroute_output(struct rtable **result,
rt_set_nexthop(rth, res, 0);
rth->rt_flags = flags;
-
*result = rth;
- cleanup:
- /* release work reference to inet device */
- in_dev_put(in_dev);
-
- return err;
+ return 0;
}
+/* called with rcu_read_lock() */
static int ip_mkroute_output(struct rtable **rp,
struct fib_result *res,
const struct flowi *fl,
@@ -2497,6 +2499,7 @@ static int ip_mkroute_output(struct rtable **rp,
/*
* Major route resolver routine.
+ * called with rcu_read_lock();
*/
static int ip_route_output_slow(struct net *net, struct rtable **rp,
@@ -2515,9 +2518,8 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
.iif = net->loopback_dev->ifindex,
.oif = oldflp->oif };
struct fib_result res;
- unsigned flags = 0;
+ unsigned int flags = 0;
struct net_device *dev_out = NULL;
- int free_res = 0;
int err;
@@ -2543,9 +2545,9 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
if (oldflp->oif == 0 &&
(ipv4_is_multicast(oldflp->fl4_dst) ||
- oldflp->fl4_dst == htonl(0xFFFFFFFF))) {
+ ipv4_is_lbcast(oldflp->fl4_dst))) {
/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
- dev_out = ip_dev_find(net, oldflp->fl4_src);
+ dev_out = __ip_dev_find(net, oldflp->fl4_src, false);
if (dev_out == NULL)
goto out;
@@ -2570,29 +2572,24 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
if (!(oldflp->flags & FLOWI_FLAG_ANYSRC)) {
/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
- dev_out = ip_dev_find(net, oldflp->fl4_src);
- if (dev_out == NULL)
+ if (!__ip_dev_find(net, oldflp->fl4_src, false))
goto out;
- dev_put(dev_out);
- dev_out = NULL;
}
}
if (oldflp->oif) {
- dev_out = dev_get_by_index(net, oldflp->oif);
+ dev_out = dev_get_by_index_rcu(net, oldflp->oif);
err = -ENODEV;
if (dev_out == NULL)
goto out;
/* RACE: Check return value of inet_select_addr instead. */
- if (__in_dev_get_rtnl(dev_out) == NULL) {
- dev_put(dev_out);
+ if (rcu_dereference(dev_out->ip_ptr) == NULL)
goto out; /* Wrong error code */
- }
if (ipv4_is_local_multicast(oldflp->fl4_dst) ||
- oldflp->fl4_dst == htonl(0xFFFFFFFF)) {
+ ipv4_is_lbcast(oldflp->fl4_dst)) {
if (!fl.fl4_src)
fl.fl4_src = inet_select_addr(dev_out, 0,
RT_SCOPE_LINK);
@@ -2612,10 +2609,7 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
fl.fl4_dst = fl.fl4_src;
if (!fl.fl4_dst)
fl.fl4_dst = fl.fl4_src = htonl(INADDR_LOOPBACK);
- if (dev_out)
- dev_put(dev_out);
dev_out = net->loopback_dev;
- dev_hold(dev_out);
fl.oif = net->loopback_dev->ifindex;
res.type = RTN_LOCAL;
flags |= RTCF_LOCAL;
@@ -2649,23 +2643,15 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
res.type = RTN_UNICAST;
goto make_route;
}
- if (dev_out)
- dev_put(dev_out);
err = -ENETUNREACH;
goto out;
}
- free_res = 1;
if (res.type == RTN_LOCAL) {
if (!fl.fl4_src)
fl.fl4_src = fl.fl4_dst;
- if (dev_out)
- dev_put(dev_out);
dev_out = net->loopback_dev;
- dev_hold(dev_out);
fl.oif = dev_out->ifindex;
- if (res.fi)
- fib_info_put(res.fi);
res.fi = NULL;
flags |= RTCF_LOCAL;
goto make_route;
@@ -2682,28 +2668,21 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
if (!fl.fl4_src)
fl.fl4_src = FIB_RES_PREFSRC(res);
- if (dev_out)
- dev_put(dev_out);
dev_out = FIB_RES_DEV(res);
- dev_hold(dev_out);
fl.oif = dev_out->ifindex;
make_route:
err = ip_mkroute_output(rp, &res, &fl, oldflp, dev_out, flags);
-
- if (free_res)
- fib_res_put(&res);
- if (dev_out)
- dev_put(dev_out);
out: return err;
}
int __ip_route_output_key(struct net *net, struct rtable **rp,
const struct flowi *flp)
{
- unsigned hash;
+ unsigned int hash;
+ int res;
struct rtable *rth;
if (!rt_caching(net))
@@ -2734,7 +2713,10 @@ int __ip_route_output_key(struct net *net, struct rtable **rp,
rcu_read_unlock_bh();
slow_output:
- return ip_route_output_slow(net, rp, flp);
+ rcu_read_lock();
+ res = ip_route_output_slow(net, rp, flp);
+ rcu_read_unlock();
+ return res;
}
EXPORT_SYMBOL_GPL(__ip_route_output_key);
@@ -2753,7 +2735,6 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
.destroy = ipv4_dst_destroy,
.check = ipv4_blackhole_dst_check,
.update_pmtu = ipv4_rt_blackhole_update_pmtu,
- .entries = ATOMIC_INIT(0),
};
@@ -2798,7 +2779,7 @@ static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi
dst_release(&(*rp)->dst);
*rp = rt;
- return (rt ? 0 : -ENOMEM);
+ return rt ? 0 : -ENOMEM;
}
int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
@@ -3323,6 +3304,12 @@ int __init ip_rt_init(void)
ipv4_dst_blackhole_ops.kmem_cachep = ipv4_dst_ops.kmem_cachep;
+ if (dst_entries_init(&ipv4_dst_ops) < 0)
+ panic("IP: failed to allocate ipv4_dst_ops counter\n");
+
+ if (dst_entries_init(&ipv4_dst_blackhole_ops) < 0)
+ panic("IP: failed to allocate ipv4_dst_blackhole_ops counter\n");
+
rt_hash_table = (struct rt_hash_bucket *)
alloc_large_system_hash("IP route cache",
sizeof(struct rt_hash_bucket),
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index f115ea68a4ef..1664a0590bb8 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2392,7 +2392,12 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
err = tp->af_specific->md5_parse(sk, optval, optlen);
break;
#endif
-
+ case TCP_USER_TIMEOUT:
+ /* Cap the max timeout in ms TCP will retry/retrans
+ * before giving up and aborting (ETIMEDOUT) a connection.
+ */
+ icsk->icsk_user_timeout = msecs_to_jiffies(val);
+ break;
default:
err = -ENOPROTOOPT;
break;
@@ -2611,6 +2616,10 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
case TCP_THIN_DUPACK:
val = tp->thin_dupack;
break;
+
+ case TCP_USER_TIMEOUT:
+ val = jiffies_to_msecs(icsk->icsk_user_timeout);
+ break;
default:
return -ENOPROTOOPT;
}
diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c
index 1eba160b72dc..00ca688d8964 100644
--- a/net/ipv4/tcp_illinois.c
+++ b/net/ipv4/tcp_illinois.c
@@ -6,7 +6,7 @@
* The algorithm is described in:
* "TCP-Illinois: A Loss and Delay-Based Congestion Control Algorithm
* for High-Speed Networks"
- * http://www.ews.uiuc.edu/~shaoliu/papersandslides/liubassri06perf.pdf
+ * http://www.ifp.illinois.edu/~srikant/Papers/liubassri06perf.pdf
*
* Implemented from description in paper and ns-2 simulation.
* Copyright (C) 2007 Stephen Hemminger <shemminger@linux-foundation.org>
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index b55f60f6fcbe..3357f69e353d 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -182,7 +182,7 @@ static void tcp_incr_quickack(struct sock *sk)
icsk->icsk_ack.quick = min(quickacks, TCP_MAX_QUICKACKS);
}
-void tcp_enter_quickack_mode(struct sock *sk)
+static void tcp_enter_quickack_mode(struct sock *sk)
{
struct inet_connection_sock *icsk = inet_csk(sk);
tcp_incr_quickack(sk);
@@ -428,10 +428,10 @@ EXPORT_SYMBOL(tcp_initialize_rcv_mss);
*
* The algorithm for RTT estimation w/o timestamps is based on
* Dynamic Right-Sizing (DRS) by Wu Feng and Mike Fisk of LANL.
- * <http://www.lanl.gov/radiant/website/pubs/drs/lacsi2001.ps>
+ * <http://public.lanl.gov/radiant/pubs.html#DRS>
*
* More detail on this code can be found at
- * <http://www.psc.edu/~jheffner/senior_thesis.ps>,
+ * <http://staff.psc.edu/jheffner/>,
* though this reference is out of date. A new paper
* is pending.
*/
@@ -805,25 +805,12 @@ void tcp_update_metrics(struct sock *sk)
}
}
-/* Numbers are taken from RFC3390.
- *
- * John Heffner states:
- *
- * The RFC specifies a window of no more than 4380 bytes
- * unless 2*MSS > 4380. Reading the pseudocode in the RFC
- * is a bit misleading because they use a clamp at 4380 bytes
- * rather than use a multiplier in the relevant range.
- */
__u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst)
{
__u32 cwnd = (dst ? dst_metric(dst, RTAX_INITCWND) : 0);
- if (!cwnd) {
- if (tp->mss_cache > 1460)
- cwnd = 2;
- else
- cwnd = (tp->mss_cache > 1095) ? 3 : 4;
- }
+ if (!cwnd)
+ cwnd = rfc3390_bytes_to_packets(tp->mss_cache);
return min_t(__u32, cwnd, tp->snd_cwnd_clamp);
}
@@ -2314,7 +2301,7 @@ static inline int tcp_dupack_heuristics(struct tcp_sock *tp)
static inline int tcp_skb_timedout(struct sock *sk, struct sk_buff *skb)
{
- return (tcp_time_stamp - TCP_SKB_CB(skb)->when > inet_csk(sk)->icsk_rto);
+ return tcp_time_stamp - TCP_SKB_CB(skb)->when > inet_csk(sk)->icsk_rto;
}
static inline int tcp_head_timedout(struct sock *sk)
@@ -2508,7 +2495,7 @@ static void tcp_timeout_skbs(struct sock *sk)
/* Mark head of queue up as lost. With RFC3517 SACK, the packets is
* is against sacked "cnt", otherwise it's against facked "cnt"
*/
-static void tcp_mark_head_lost(struct sock *sk, int packets)
+static void tcp_mark_head_lost(struct sock *sk, int packets, int mark_head)
{
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
@@ -2516,13 +2503,13 @@ static void tcp_mark_head_lost(struct sock *sk, int packets)
int err;
unsigned int mss;
- if (packets == 0)
- return;
-
WARN_ON(packets > tp->packets_out);
if (tp->lost_skb_hint) {
skb = tp->lost_skb_hint;
cnt = tp->lost_cnt_hint;
+ /* Head already handled? */
+ if (mark_head && skb != tcp_write_queue_head(sk))
+ return;
} else {
skb = tcp_write_queue_head(sk);
cnt = 0;
@@ -2557,6 +2544,9 @@ static void tcp_mark_head_lost(struct sock *sk, int packets)
}
tcp_skb_mark_lost(tp, skb);
+
+ if (mark_head)
+ break;
}
tcp_verify_left_out(tp);
}
@@ -2568,17 +2558,18 @@ static void tcp_update_scoreboard(struct sock *sk, int fast_rexmit)
struct tcp_sock *tp = tcp_sk(sk);
if (tcp_is_reno(tp)) {
- tcp_mark_head_lost(sk, 1);
+ tcp_mark_head_lost(sk, 1, 1);
} else if (tcp_is_fack(tp)) {
int lost = tp->fackets_out - tp->reordering;
if (lost <= 0)
lost = 1;
- tcp_mark_head_lost(sk, lost);
+ tcp_mark_head_lost(sk, lost, 0);
} else {
int sacked_upto = tp->sacked_out - tp->reordering;
- if (sacked_upto < fast_rexmit)
- sacked_upto = fast_rexmit;
- tcp_mark_head_lost(sk, sacked_upto);
+ if (sacked_upto >= 0)
+ tcp_mark_head_lost(sk, sacked_upto, 0);
+ else if (fast_rexmit)
+ tcp_mark_head_lost(sk, 1, 1);
}
tcp_timeout_skbs(sk);
@@ -2887,7 +2878,7 @@ static void tcp_mtup_probe_success(struct sock *sk)
icsk->icsk_mtup.probe_size;
tp->snd_cwnd_cnt = 0;
tp->snd_cwnd_stamp = tcp_time_stamp;
- tp->rcv_ssthresh = tcp_current_ssthresh(sk);
+ tp->snd_ssthresh = tcp_current_ssthresh(sk);
icsk->icsk_mtup.search_low = icsk->icsk_mtup.probe_size;
icsk->icsk_mtup.probe_size = 0;
@@ -2984,7 +2975,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag)
before(tp->snd_una, tp->high_seq) &&
icsk->icsk_ca_state != TCP_CA_Open &&
tp->fackets_out > tp->reordering) {
- tcp_mark_head_lost(sk, tp->fackets_out - tp->reordering);
+ tcp_mark_head_lost(sk, tp->fackets_out - tp->reordering, 0);
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSS);
}
@@ -3412,8 +3403,8 @@ static void tcp_ack_probe(struct sock *sk)
static inline int tcp_ack_is_dubious(const struct sock *sk, const int flag)
{
- return (!(flag & FLAG_NOT_DUP) || (flag & FLAG_CA_ALERT) ||
- inet_csk(sk)->icsk_ca_state != TCP_CA_Open);
+ return !(flag & FLAG_NOT_DUP) || (flag & FLAG_CA_ALERT) ||
+ inet_csk(sk)->icsk_ca_state != TCP_CA_Open;
}
static inline int tcp_may_raise_cwnd(const struct sock *sk, const int flag)
@@ -3430,9 +3421,9 @@ static inline int tcp_may_update_window(const struct tcp_sock *tp,
const u32 ack, const u32 ack_seq,
const u32 nwin)
{
- return (after(ack, tp->snd_una) ||
+ return after(ack, tp->snd_una) ||
after(ack_seq, tp->snd_wl1) ||
- (ack_seq == tp->snd_wl1 && nwin > tp->snd_wnd));
+ (ack_seq == tp->snd_wl1 && nwin > tp->snd_wnd);
}
/* Update our send window.
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 020766292bb0..8f8527d41682 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1422,7 +1422,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newsk = tcp_create_openreq_child(sk, req, skb);
if (!newsk)
- goto exit;
+ goto exit_nonewsk;
newsk->sk_gso_type = SKB_GSO_TCPV4;
sk_setup_caps(newsk, dst);
@@ -1469,16 +1469,20 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
}
#endif
+ if (__inet_inherit_port(sk, newsk) < 0) {
+ sock_put(newsk);
+ goto exit;
+ }
__inet_hash_nolisten(newsk, NULL);
- __inet_inherit_port(sk, newsk);
return newsk;
exit_overflow:
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
+exit_nonewsk:
+ dst_release(dst);
exit:
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
- dst_release(dst);
return NULL;
}
EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
@@ -2571,7 +2575,6 @@ struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb)
return tcp_gro_receive(head, skb);
}
-EXPORT_SYMBOL(tcp4_gro_receive);
int tcp4_gro_complete(struct sk_buff *skb)
{
@@ -2584,7 +2587,6 @@ int tcp4_gro_complete(struct sk_buff *skb)
return tcp_gro_complete(skb);
}
-EXPORT_SYMBOL(tcp4_gro_complete);
struct proto tcp_prot = {
.name = "TCP",
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index f25b56cb85cb..43cf901d7659 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -55,7 +55,7 @@ static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)
return 1;
if (after(end_seq, s_win) && before(seq, e_win))
return 1;
- return (seq == e_win && seq == end_seq);
+ return seq == e_win && seq == end_seq;
}
/*
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index de3bd8458588..05b1ecf36763 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -224,16 +224,10 @@ void tcp_select_initial_window(int __space, __u32 mss,
}
}
- /* Set initial window to value enough for senders,
- * following RFC2414. Senders, not following this RFC,
- * will be satisfied with 2.
- */
+ /* Set initial window to value enough for senders, following RFC5681. */
if (mss > (1 << *rcv_wscale)) {
- int init_cwnd = 4;
- if (mss > 1460 * 3)
- init_cwnd = 2;
- else if (mss > 1460)
- init_cwnd = 3;
+ int init_cwnd = rfc3390_bytes_to_packets(mss);
+
/* when initializing use the value from init_rcv_wnd
* rather than the default from above
*/
@@ -1376,9 +1370,9 @@ static inline int tcp_nagle_check(const struct tcp_sock *tp,
const struct sk_buff *skb,
unsigned mss_now, int nonagle)
{
- return (skb->len < mss_now &&
+ return skb->len < mss_now &&
((nonagle & TCP_NAGLE_CORK) ||
- (!nonagle && tp->packets_out && tcp_minshall_check(tp))));
+ (!nonagle && tp->packets_out && tcp_minshall_check(tp)));
}
/* Return non-zero if the Nagle test allows this packet to be
@@ -1449,10 +1443,10 @@ int tcp_may_send_now(struct sock *sk)
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb = tcp_send_head(sk);
- return (skb &&
+ return skb &&
tcp_snd_test(sk, skb, tcp_current_mss(sk),
(tcp_skb_is_last(sk, skb) ?
- tp->nonagle : TCP_NAGLE_PUSH)));
+ tp->nonagle : TCP_NAGLE_PUSH));
}
/* Trim TSO SKB to LEN bytes, put the remaining data into a new packet
@@ -2429,6 +2423,12 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
__u8 rcv_wscale;
/* Set this up on the first call only */
req->window_clamp = tp->window_clamp ? : dst_metric(dst, RTAX_WINDOW);
+
+ /* limit the window selection if the user enforce a smaller rx buffer */
+ if (sk->sk_userlocks & SOCK_RCVBUF_LOCK &&
+ (req->window_clamp > tcp_full_space(sk) || req->window_clamp == 0))
+ req->window_clamp = tcp_full_space(sk);
+
/* tcp_full_space because it is guaranteed to be the first packet */
tcp_select_initial_window(tcp_full_space(sk),
mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0),
@@ -2555,6 +2555,11 @@ static void tcp_connect_init(struct sock *sk)
tcp_initialize_rcv_mss(sk);
+ /* limit the window selection if the user enforce a smaller rx buffer */
+ if (sk->sk_userlocks & SOCK_RCVBUF_LOCK &&
+ (tp->window_clamp > tcp_full_space(sk) || tp->window_clamp == 0))
+ tp->window_clamp = tcp_full_space(sk);
+
tcp_select_initial_window(tcp_full_space(sk),
tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0),
&tp->rcv_wnd,
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 74c54b30600f..74a6aa003657 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -140,10 +140,10 @@ static void tcp_mtu_probing(struct inet_connection_sock *icsk, struct sock *sk)
*/
static bool retransmits_timed_out(struct sock *sk,
unsigned int boundary,
+ unsigned int timeout,
bool syn_set)
{
- unsigned int timeout, linear_backoff_thresh;
- unsigned int start_ts;
+ unsigned int linear_backoff_thresh, start_ts;
unsigned int rto_base = syn_set ? TCP_TIMEOUT_INIT : TCP_RTO_MIN;
if (!inet_csk(sk)->icsk_retransmits)
@@ -154,14 +154,15 @@ static bool retransmits_timed_out(struct sock *sk,
else
start_ts = tcp_sk(sk)->retrans_stamp;
- linear_backoff_thresh = ilog2(TCP_RTO_MAX/rto_base);
-
- if (boundary <= linear_backoff_thresh)
- timeout = ((2 << boundary) - 1) * rto_base;
- else
- timeout = ((2 << linear_backoff_thresh) - 1) * rto_base +
- (boundary - linear_backoff_thresh) * TCP_RTO_MAX;
+ if (likely(timeout == 0)) {
+ linear_backoff_thresh = ilog2(TCP_RTO_MAX/rto_base);
+ if (boundary <= linear_backoff_thresh)
+ timeout = ((2 << boundary) - 1) * rto_base;
+ else
+ timeout = ((2 << linear_backoff_thresh) - 1) * rto_base +
+ (boundary - linear_backoff_thresh) * TCP_RTO_MAX;
+ }
return (tcp_time_stamp - start_ts) >= timeout;
}
@@ -178,7 +179,7 @@ static int tcp_write_timeout(struct sock *sk)
retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
syn_set = 1;
} else {
- if (retransmits_timed_out(sk, sysctl_tcp_retries1, 0)) {
+ if (retransmits_timed_out(sk, sysctl_tcp_retries1, 0, 0)) {
/* Black hole detection */
tcp_mtu_probing(icsk, sk);
@@ -191,14 +192,15 @@ static int tcp_write_timeout(struct sock *sk)
retry_until = tcp_orphan_retries(sk, alive);
do_reset = alive ||
- !retransmits_timed_out(sk, retry_until, 0);
+ !retransmits_timed_out(sk, retry_until, 0, 0);
if (tcp_out_of_resources(sk, do_reset))
return 1;
}
}
- if (retransmits_timed_out(sk, retry_until, syn_set)) {
+ if (retransmits_timed_out(sk, retry_until,
+ syn_set ? 0 : icsk->icsk_user_timeout, syn_set)) {
/* Has it gone just too far? */
tcp_write_err(sk);
return 1;
@@ -365,18 +367,19 @@ void tcp_retransmit_timer(struct sock *sk)
if (icsk->icsk_retransmits == 0) {
int mib_idx;
- if (icsk->icsk_ca_state == TCP_CA_Disorder) {
- if (tcp_is_sack(tp))
- mib_idx = LINUX_MIB_TCPSACKFAILURES;
- else
- mib_idx = LINUX_MIB_TCPRENOFAILURES;
- } else if (icsk->icsk_ca_state == TCP_CA_Recovery) {
+ if (icsk->icsk_ca_state == TCP_CA_Recovery) {
if (tcp_is_sack(tp))
mib_idx = LINUX_MIB_TCPSACKRECOVERYFAIL;
else
mib_idx = LINUX_MIB_TCPRENORECOVERYFAIL;
} else if (icsk->icsk_ca_state == TCP_CA_Loss) {
mib_idx = LINUX_MIB_TCPLOSSFAILURES;
+ } else if ((icsk->icsk_ca_state == TCP_CA_Disorder) ||
+ tp->sacked_out) {
+ if (tcp_is_sack(tp))
+ mib_idx = LINUX_MIB_TCPSACKFAILURES;
+ else
+ mib_idx = LINUX_MIB_TCPRENOFAILURES;
} else {
mib_idx = LINUX_MIB_TCPTIMEOUTS;
}
@@ -440,7 +443,7 @@ out_reset_timer:
icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
}
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
- if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1, 0))
+ if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1, 0, 0))
__sk_dst_reset(sk);
out:;
@@ -560,7 +563,14 @@ static void tcp_keepalive_timer (unsigned long data)
elapsed = keepalive_time_elapsed(tp);
if (elapsed >= keepalive_time_when(tp)) {
- if (icsk->icsk_probes_out >= keepalive_probes(tp)) {
+ /* If the TCP_USER_TIMEOUT option is enabled, use that
+ * to determine when to timeout instead.
+ */
+ if ((icsk->icsk_user_timeout != 0 &&
+ elapsed >= icsk->icsk_user_timeout &&
+ icsk->icsk_probes_out > 0) ||
+ (icsk->icsk_user_timeout == 0 &&
+ icsk->icsk_probes_out >= keepalive_probes(tp))) {
tcp_send_active_reset(sk, GFP_ATOMIC);
tcp_write_err(sk);
goto out;
diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c
index b612acf76183..38bc0b52d745 100644
--- a/net/ipv4/tcp_veno.c
+++ b/net/ipv4/tcp_veno.c
@@ -6,7 +6,7 @@
* "TCP Veno: TCP Enhancement for Transmission over Wireless Access Networks."
* IEEE Journal on Selected Areas in Communication,
* Feb. 2003.
- * See http://www.ntu.edu.sg/home5/ZHOU0022/papers/CPFu03a.pdf
+ * See http://www.ie.cuhk.edu.hk/fileadmin/staff_upload/soung/Journal/J3.pdf
*/
#include <linux/mm.h>
diff --git a/net/ipv4/tcp_westwood.c b/net/ipv4/tcp_westwood.c
index 20151d6a6241..a534dda5456e 100644
--- a/net/ipv4/tcp_westwood.c
+++ b/net/ipv4/tcp_westwood.c
@@ -80,7 +80,7 @@ static void tcp_westwood_init(struct sock *sk)
*/
static inline u32 westwood_do_filter(u32 a, u32 b)
{
- return (((7 * a) + b) >> 3);
+ return ((7 * a) + b) >> 3;
}
static void westwood_filter(struct westwood *w, u32 delta)
diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c
index 59186ca7808a..ac3b3ee4b07c 100644
--- a/net/ipv4/tunnel4.c
+++ b/net/ipv4/tunnel4.c
@@ -14,32 +14,37 @@
#include <net/protocol.h>
#include <net/xfrm.h>
-static struct xfrm_tunnel *tunnel4_handlers;
-static struct xfrm_tunnel *tunnel64_handlers;
+static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly;
+static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly;
static DEFINE_MUTEX(tunnel4_mutex);
-static inline struct xfrm_tunnel **fam_handlers(unsigned short family)
+static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family)
{
return (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers;
}
int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
{
- struct xfrm_tunnel **pprev;
+ struct xfrm_tunnel __rcu **pprev;
+ struct xfrm_tunnel *t;
+
int ret = -EEXIST;
int priority = handler->priority;
mutex_lock(&tunnel4_mutex);
- for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) {
- if ((*pprev)->priority > priority)
+ for (pprev = fam_handlers(family);
+ (t = rcu_dereference_protected(*pprev,
+ lockdep_is_held(&tunnel4_mutex))) != NULL;
+ pprev = &t->next) {
+ if (t->priority > priority)
break;
- if ((*pprev)->priority == priority)
+ if (t->priority == priority)
goto err;
}
handler->next = *pprev;
- *pprev = handler;
+ rcu_assign_pointer(*pprev, handler);
ret = 0;
@@ -52,13 +57,17 @@ EXPORT_SYMBOL(xfrm4_tunnel_register);
int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
{
- struct xfrm_tunnel **pprev;
+ struct xfrm_tunnel __rcu **pprev;
+ struct xfrm_tunnel *t;
int ret = -ENOENT;
mutex_lock(&tunnel4_mutex);
- for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) {
- if (*pprev == handler) {
+ for (pprev = fam_handlers(family);
+ (t = rcu_dereference_protected(*pprev,
+ lockdep_is_held(&tunnel4_mutex))) != NULL;
+ pprev = &t->next) {
+ if (t == handler) {
*pprev = handler->next;
ret = 0;
break;
@@ -73,6 +82,11 @@ int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
}
EXPORT_SYMBOL(xfrm4_tunnel_deregister);
+#define for_each_tunnel_rcu(head, handler) \
+ for (handler = rcu_dereference(head); \
+ handler != NULL; \
+ handler = rcu_dereference(handler->next)) \
+
static int tunnel4_rcv(struct sk_buff *skb)
{
struct xfrm_tunnel *handler;
@@ -80,7 +94,7 @@ static int tunnel4_rcv(struct sk_buff *skb)
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
goto drop;
- for (handler = tunnel4_handlers; handler; handler = handler->next)
+ for_each_tunnel_rcu(tunnel4_handlers, handler)
if (!handler->handler(skb))
return 0;
@@ -99,7 +113,7 @@ static int tunnel64_rcv(struct sk_buff *skb)
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
goto drop;
- for (handler = tunnel64_handlers; handler; handler = handler->next)
+ for_each_tunnel_rcu(tunnel64_handlers, handler)
if (!handler->handler(skb))
return 0;
@@ -115,7 +129,7 @@ static void tunnel4_err(struct sk_buff *skb, u32 info)
{
struct xfrm_tunnel *handler;
- for (handler = tunnel4_handlers; handler; handler = handler->next)
+ for_each_tunnel_rcu(tunnel4_handlers, handler)
if (!handler->err_handler(skb, info))
break;
}
@@ -125,7 +139,7 @@ static void tunnel64_err(struct sk_buff *skb, u32 info)
{
struct xfrm_tunnel *handler;
- for (handler = tunnel64_handlers; handler; handler = handler->next)
+ for_each_tunnel_rcu(tunnel64_handlers, handler)
if (!handler->err_handler(skb, info))
break;
}
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index fb23c2e63b52..28cb2d733a3c 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -797,7 +797,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
return -EOPNOTSUPP;
ipc.opt = NULL;
- ipc.shtx.flags = 0;
+ ipc.tx_flags = 0;
if (up->pending) {
/*
@@ -845,7 +845,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
ipc.addr = inet->inet_saddr;
ipc.oif = sk->sk_bound_dev_if;
- err = sock_tx_timestamp(msg, sk, &ipc.shtx);
+ err = sock_tx_timestamp(sk, &ipc.tx_flags);
if (err)
return err;
if (msg->msg_controllen) {
@@ -1413,7 +1413,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
}
}
- if (sk->sk_filter) {
+ if (rcu_dereference_raw(sk->sk_filter)) {
if (udp_lib_checksum_complete(skb))
goto drop;
}
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index a580349f0b8a..4464f3bff6a7 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -174,7 +174,7 @@ static inline int xfrm4_garbage_collect(struct dst_ops *ops)
struct net *net = container_of(ops, struct net, xfrm.xfrm4_dst_ops);
xfrm4_policy_afinfo.garbage_collect(net);
- return (atomic_read(&ops->entries) > ops->gc_thresh * 2);
+ return (dst_entries_get_slow(ops) > ops->gc_thresh * 2);
}
static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu)
@@ -232,7 +232,6 @@ static struct dst_ops xfrm4_dst_ops = {
.ifdown = xfrm4_dst_ifdown,
.local_out = __ip_local_out,
.gc_thresh = 1024,
- .entries = ATOMIC_INIT(0),
};
static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
@@ -288,6 +287,7 @@ void __init xfrm4_init(int rt_max_size)
* and start cleaning when were 1/2 full
*/
xfrm4_dst_ops.gc_thresh = rt_max_size/2;
+ dst_entries_init(&xfrm4_dst_ops);
xfrm4_state_init();
xfrm4_policy_init();
diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c
index 41f5982d2087..82806455e859 100644
--- a/net/ipv4/xfrm4_tunnel.c
+++ b/net/ipv4/xfrm4_tunnel.c
@@ -58,14 +58,14 @@ static int xfrm_tunnel_err(struct sk_buff *skb, u32 info)
return -ENOENT;
}
-static struct xfrm_tunnel xfrm_tunnel_handler = {
+static struct xfrm_tunnel xfrm_tunnel_handler __read_mostly = {
.handler = xfrm_tunnel_rcv,
.err_handler = xfrm_tunnel_err,
.priority = 2,
};
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static struct xfrm_tunnel xfrm64_tunnel_handler = {
+static struct xfrm_tunnel xfrm64_tunnel_handler __read_mostly = {
.handler = xfrm_tunnel_rcv,
.err_handler = xfrm_tunnel_err,
.priority = 2,
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 324fac3b6c16..e048ec62d109 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -243,7 +243,7 @@ static inline bool addrconf_qdisc_ok(const struct net_device *dev)
/* Check if a route is valid prefix route */
static inline int addrconf_is_prefix_route(const struct rt6_info *rt)
{
- return ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0);
+ return (rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0;
}
static void addrconf_del_timer(struct inet6_ifaddr *ifp)
@@ -836,7 +836,7 @@ 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;
+ unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp, age;
unsigned long regen_advance;
int tmp_plen;
int ret = 0;
@@ -886,12 +886,13 @@ retry:
goto out;
}
memcpy(&addr.s6_addr[8], idev->rndid, 8);
+ age = (jiffies - ifp->tstamp) / HZ;
tmp_valid_lft = min_t(__u32,
ifp->valid_lft,
- idev->cnf.temp_valid_lft);
+ idev->cnf.temp_valid_lft + age);
tmp_prefered_lft = min_t(__u32,
ifp->prefered_lft,
- idev->cnf.temp_prefered_lft -
+ idev->cnf.temp_prefered_lft + age -
idev->cnf.max_desync_factor);
tmp_plen = ifp->prefix_len;
max_addresses = idev->cnf.max_addresses;
@@ -1426,8 +1427,10 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
{
struct inet6_dev *idev = ifp->idev;
- if (addrconf_dad_end(ifp))
+ if (addrconf_dad_end(ifp)) {
+ in6_ifa_put(ifp);
return;
+ }
if (net_ratelimit())
printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n",
@@ -1544,7 +1547,7 @@ static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev)
return 0;
}
-int __ipv6_isatap_ifid(u8 *eui, __be32 addr)
+static int __ipv6_isatap_ifid(u8 *eui, __be32 addr)
{
if (addr == 0)
return -1;
@@ -1560,7 +1563,6 @@ int __ipv6_isatap_ifid(u8 *eui, __be32 addr)
memcpy(eui + 4, &addr, 4);
return 0;
}
-EXPORT_SYMBOL(__ipv6_isatap_ifid);
static int addrconf_ifid_sit(u8 *eui, struct net_device *dev)
{
@@ -2022,10 +2024,11 @@ ok:
ipv6_ifa_notify(0, ift);
}
- if (create && in6_dev->cnf.use_tempaddr > 0) {
+ 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 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);
@@ -2964,7 +2967,8 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
start sending router solicitations.
*/
- if (ifp->idev->cnf.forwarding == 0 &&
+ if ((ifp->idev->cnf.forwarding == 0 ||
+ ifp->idev->cnf.forwarding == 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/addrlabel.c b/net/ipv6/addrlabel.c
index 8175f802651b..c8993e5a337c 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -518,10 +518,9 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
static inline int ip6addrlbl_msgsize(void)
{
- return (NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))
+ return NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))
+ nla_total_size(16) /* IFAL_ADDRESS */
- + nla_total_size(4) /* IFAL_LABEL */
- );
+ + nla_total_size(4); /* IFAL_LABEL */
}
static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 56b9bf2516f4..54e8e42f7a88 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -343,7 +343,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
*/
v4addr = LOOPBACK4_IPV6;
if (!(addr_type & IPV6_ADDR_MULTICAST)) {
- if (!ipv6_chk_addr(net, &addr->sin6_addr,
+ if (!inet->transparent &&
+ !ipv6_chk_addr(net, &addr->sin6_addr,
dev, 0)) {
err = -EADDRNOTAVAIL;
goto out_unlock;
@@ -467,7 +468,7 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
sin->sin6_scope_id = sk->sk_bound_dev_if;
*uaddr_len = sizeof(*sin);
- return(0);
+ return 0;
}
EXPORT_SYMBOL(inet6_getname);
@@ -488,7 +489,7 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCADDRT:
case SIOCDELRT:
- return(ipv6_route_ioctl(net, cmd, (void __user *)arg));
+ return ipv6_route_ioctl(net, cmd, (void __user *)arg);
case SIOCSIFADDR:
return addrconf_add_ifaddr(net, (void __user *) arg);
@@ -502,7 +503,7 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return sk->sk_prot->ioctl(sk, cmd, arg);
}
/*NOTREACHED*/
- return(0);
+ return 0;
}
EXPORT_SYMBOL(inet6_ioctl);
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index ef371aa01ac5..320bdb877eed 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -577,6 +577,25 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
u8 *ptr = nh + opt->dst1;
put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr);
}
+ if (np->rxopt.bits.rxorigdstaddr) {
+ struct sockaddr_in6 sin6;
+ u16 *ports = (u16 *) skb_transport_header(skb);
+
+ if (skb_transport_offset(skb) + 4 <= skb->len) {
+ /* All current transport protocols have the port numbers in the
+ * first four bytes of the transport header and this function is
+ * written with this assumption in mind.
+ */
+
+ sin6.sin6_family = AF_INET6;
+ ipv6_addr_copy(&sin6.sin6_addr, &ipv6_hdr(skb)->daddr);
+ sin6.sin6_port = ports[1];
+ sin6.sin6_flowinfo = 0;
+ sin6.sin6_scope_id = 0;
+
+ put_cmsg(msg, SOL_IPV6, IPV6_ORIGDSTADDR, sizeof(sin6), &sin6);
+ }
+ }
return 0;
}
diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c
index e1caa5d526c2..14ed0a955b56 100644
--- a/net/ipv6/exthdrs_core.c
+++ b/net/ipv6/exthdrs_core.c
@@ -13,12 +13,12 @@ int ipv6_ext_hdr(u8 nexthdr)
/*
* find out if nexthdr is an extension header or a protocol
*/
- return ( (nexthdr == NEXTHDR_HOP) ||
+ return (nexthdr == NEXTHDR_HOP) ||
(nexthdr == NEXTHDR_ROUTING) ||
(nexthdr == NEXTHDR_FRAGMENT) ||
(nexthdr == NEXTHDR_AUTH) ||
(nexthdr == NEXTHDR_NONE) ||
- (nexthdr == NEXTHDR_DEST) );
+ (nexthdr == NEXTHDR_DEST);
}
/*
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index b1108ede18e1..d829874d8946 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -34,11 +34,10 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
{
struct fib_lookup_arg arg = {
.lookup_ptr = lookup,
+ .flags = FIB_LOOKUP_NOREF,
};
fib_rules_lookup(net->ipv6.fib6_rules_ops, fl, flags, &arg);
- if (arg.rule)
- fib_rule_put(arg.rule);
if (arg.result)
return arg.result;
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index b6a585909d35..de382114609b 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -1500,15 +1500,18 @@ static void fib6_gc_timer_cb(unsigned long arg)
static int __net_init fib6_net_init(struct net *net)
{
+ size_t size = sizeof(struct hlist_head) * FIB6_TABLE_HASHSZ;
+
setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net);
net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL);
if (!net->ipv6.rt6_stats)
goto out_timer;
- net->ipv6.fib_table_hash = kcalloc(FIB6_TABLE_HASHSZ,
- sizeof(*net->ipv6.fib_table_hash),
- GFP_KERNEL);
+ /* Avoid false sharing : Use at least a full cache line */
+ size = max_t(size_t, size, L1_CACHE_BYTES);
+
+ net->ipv6.fib_table_hash = kzalloc(size, GFP_KERNEL);
if (!net->ipv6.fib_table_hash)
goto out_rt6_stats;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 980912ed7a38..99157b4cd56e 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -637,7 +637,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
}
mtu -= hlen + sizeof(struct frag_hdr);
- if (skb_has_frags(skb)) {
+ if (skb_has_frag_list(skb)) {
int first_len = skb_pagelen(skb);
struct sk_buff *frag2;
@@ -878,8 +878,8 @@ static inline int ip6_rt_check(struct rt6key *rt_key,
struct in6_addr *fl_addr,
struct in6_addr *addr_cache)
{
- return ((rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) &&
- (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache)));
+ return (rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) &&
+ (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache));
}
static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 0fd027f3f47e..2a59610c2a58 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -75,7 +75,7 @@ MODULE_LICENSE("GPL");
(addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
(HASH_SIZE - 1))
-static void ip6_tnl_dev_init(struct net_device *dev);
+static int ip6_tnl_dev_init(struct net_device *dev);
static void ip6_tnl_dev_setup(struct net_device *dev);
static int ip6_tnl_net_id __read_mostly;
@@ -83,15 +83,42 @@ struct ip6_tnl_net {
/* the IPv6 tunnel fallback device */
struct net_device *fb_tnl_dev;
/* lists for storing tunnels in use */
- struct ip6_tnl *tnls_r_l[HASH_SIZE];
- struct ip6_tnl *tnls_wc[1];
- struct ip6_tnl **tnls[2];
+ struct ip6_tnl __rcu *tnls_r_l[HASH_SIZE];
+ struct ip6_tnl __rcu *tnls_wc[1];
+ struct ip6_tnl __rcu **tnls[2];
};
+/* often modified stats are per cpu, other are shared (netdev->stats) */
+struct pcpu_tstats {
+ unsigned long rx_packets;
+ unsigned long rx_bytes;
+ unsigned long tx_packets;
+ unsigned long tx_bytes;
+};
+
+static struct net_device_stats *ip6_get_stats(struct net_device *dev)
+{
+ struct pcpu_tstats sum = { 0 };
+ int i;
+
+ for_each_possible_cpu(i) {
+ const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
+
+ sum.rx_packets += tstats->rx_packets;
+ sum.rx_bytes += tstats->rx_bytes;
+ sum.tx_packets += tstats->tx_packets;
+ sum.tx_bytes += tstats->tx_bytes;
+ }
+ dev->stats.rx_packets = sum.rx_packets;
+ dev->stats.rx_bytes = sum.rx_bytes;
+ dev->stats.tx_packets = sum.tx_packets;
+ dev->stats.tx_bytes = sum.tx_bytes;
+ return &dev->stats;
+}
+
/*
- * Locking : hash tables are protected by RCU and a spinlock
+ * Locking : hash tables are protected by RCU and RTNL
*/
-static DEFINE_SPINLOCK(ip6_tnl_lock);
static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
{
@@ -138,8 +165,8 @@ static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
static struct ip6_tnl *
ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local)
{
- unsigned h0 = HASH(remote);
- unsigned h1 = HASH(local);
+ unsigned int h0 = HASH(remote);
+ unsigned int h1 = HASH(local);
struct ip6_tnl *t;
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
@@ -167,7 +194,7 @@ ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local)
* Return: head of IPv6 tunnel list
**/
-static struct ip6_tnl **
+static struct ip6_tnl __rcu **
ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p)
{
struct in6_addr *remote = &p->raddr;
@@ -190,12 +217,10 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p)
static void
ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
{
- struct ip6_tnl **tp = ip6_tnl_bucket(ip6n, &t->parms);
+ struct ip6_tnl __rcu **tp = ip6_tnl_bucket(ip6n, &t->parms);
- spin_lock_bh(&ip6_tnl_lock);
- t->next = *tp;
+ rcu_assign_pointer(t->next , rtnl_dereference(*tp));
rcu_assign_pointer(*tp, t);
- spin_unlock_bh(&ip6_tnl_lock);
}
/**
@@ -206,18 +231,25 @@ ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
static void
ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
{
- struct ip6_tnl **tp;
-
- for (tp = ip6_tnl_bucket(ip6n, &t->parms); *tp; tp = &(*tp)->next) {
- if (t == *tp) {
- spin_lock_bh(&ip6_tnl_lock);
- *tp = t->next;
- spin_unlock_bh(&ip6_tnl_lock);
+ struct ip6_tnl __rcu **tp;
+ struct ip6_tnl *iter;
+
+ for (tp = ip6_tnl_bucket(ip6n, &t->parms);
+ (iter = rtnl_dereference(*tp)) != NULL;
+ tp = &iter->next) {
+ if (t == iter) {
+ rcu_assign_pointer(*tp, t->next);
break;
}
}
}
+static void ip6_dev_free(struct net_device *dev)
+{
+ free_percpu(dev->tstats);
+ free_netdev(dev);
+}
+
/**
* ip6_tnl_create() - create a new tunnel
* @p: tunnel parameters
@@ -256,7 +288,9 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p)
t = netdev_priv(dev);
t->parms = *p;
- ip6_tnl_dev_init(dev);
+ err = ip6_tnl_dev_init(dev);
+ if (err < 0)
+ goto failed_free;
if ((err = register_netdevice(dev)) < 0)
goto failed_free;
@@ -266,7 +300,7 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p)
return t;
failed_free:
- free_netdev(dev);
+ ip6_dev_free(dev);
failed:
return NULL;
}
@@ -290,10 +324,13 @@ static struct ip6_tnl *ip6_tnl_locate(struct net *net,
{
struct in6_addr *remote = &p->raddr;
struct in6_addr *local = &p->laddr;
+ struct ip6_tnl __rcu **tp;
struct ip6_tnl *t;
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
- for (t = *ip6_tnl_bucket(ip6n, p); t; t = t->next) {
+ for (tp = ip6_tnl_bucket(ip6n, p);
+ (t = rtnl_dereference(*tp)) != NULL;
+ tp = &t->next) {
if (ipv6_addr_equal(local, &t->parms.laddr) &&
ipv6_addr_equal(remote, &t->parms.raddr))
return t;
@@ -318,13 +355,10 @@ ip6_tnl_dev_uninit(struct net_device *dev)
struct net *net = dev_net(dev);
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
- if (dev == ip6n->fb_tnl_dev) {
- spin_lock_bh(&ip6_tnl_lock);
- ip6n->tnls_wc[0] = NULL;
- spin_unlock_bh(&ip6_tnl_lock);
- } else {
+ if (dev == ip6n->fb_tnl_dev)
+ rcu_assign_pointer(ip6n->tnls_wc[0], NULL);
+ else
ip6_tnl_unlink(ip6n, t);
- }
ip6_tnl_dst_reset(t);
dev_put(dev);
}
@@ -702,6 +736,8 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr,
&ipv6h->daddr)) != NULL) {
+ struct pcpu_tstats *tstats;
+
if (t->parms.proto != ipproto && t->parms.proto != 0) {
rcu_read_unlock();
goto discard;
@@ -724,10 +760,16 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
skb->pkt_type = PACKET_HOST;
memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
- skb_tunnel_rx(skb, t->dev);
+ tstats = this_cpu_ptr(t->dev->tstats);
+ tstats->rx_packets++;
+ tstats->rx_bytes += skb->len;
+
+ __skb_tunnel_rx(skb, t->dev);
dscp_ecn_decapsulate(t, ipv6h, skb);
+
netif_rx(skb);
+
rcu_read_unlock();
return 0;
}
@@ -934,8 +976,10 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
err = ip6_local_out(skb);
if (net_xmit_eval(err) == 0) {
- stats->tx_bytes += pkt_len;
- stats->tx_packets++;
+ struct pcpu_tstats *tstats = this_cpu_ptr(t->dev->tstats);
+
+ tstats->tx_bytes += pkt_len;
+ tstats->tx_packets++;
} else {
stats->tx_errors++;
stats->tx_aborted_errors++;
@@ -1240,6 +1284,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
t = netdev_priv(dev);
ip6_tnl_unlink(ip6n, t);
+ synchronize_net();
err = ip6_tnl_change(t, &p);
ip6_tnl_link(ip6n, t);
netdev_state_change(dev);
@@ -1300,12 +1345,14 @@ ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
static const struct net_device_ops ip6_tnl_netdev_ops = {
- .ndo_uninit = ip6_tnl_dev_uninit,
+ .ndo_uninit = ip6_tnl_dev_uninit,
.ndo_start_xmit = ip6_tnl_xmit,
- .ndo_do_ioctl = ip6_tnl_ioctl,
+ .ndo_do_ioctl = ip6_tnl_ioctl,
.ndo_change_mtu = ip6_tnl_change_mtu,
+ .ndo_get_stats = ip6_get_stats,
};
+
/**
* ip6_tnl_dev_setup - setup virtual tunnel device
* @dev: virtual device associated with tunnel
@@ -1317,7 +1364,7 @@ static const struct net_device_ops ip6_tnl_netdev_ops = {
static void ip6_tnl_dev_setup(struct net_device *dev)
{
dev->netdev_ops = &ip6_tnl_netdev_ops;
- dev->destructor = free_netdev;
+ dev->destructor = ip6_dev_free;
dev->type = ARPHRD_TUNNEL6;
dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
@@ -1325,6 +1372,7 @@ static void ip6_tnl_dev_setup(struct net_device *dev)
dev->flags |= IFF_NOARP;
dev->addr_len = sizeof(struct in6_addr);
dev->features |= NETIF_F_NETNS_LOCAL;
+ dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
}
@@ -1333,12 +1381,17 @@ static void ip6_tnl_dev_setup(struct net_device *dev)
* @dev: virtual device associated with tunnel
**/
-static inline void
+static inline int
ip6_tnl_dev_init_gen(struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
+
t->dev = dev;
strcpy(t->parms.name, dev->name);
+ dev->tstats = alloc_percpu(struct pcpu_tstats);
+ if (!dev->tstats)
+ return -ENOMEM;
+ return 0;
}
/**
@@ -1346,11 +1399,15 @@ ip6_tnl_dev_init_gen(struct net_device *dev)
* @dev: virtual device associated with tunnel
**/
-static void ip6_tnl_dev_init(struct net_device *dev)
+static int ip6_tnl_dev_init(struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
- ip6_tnl_dev_init_gen(dev);
+ int err = ip6_tnl_dev_init_gen(dev);
+
+ if (err)
+ return err;
ip6_tnl_link_config(t);
+ return 0;
}
/**
@@ -1360,25 +1417,29 @@ static void ip6_tnl_dev_init(struct net_device *dev)
* Return: 0
**/
-static void __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
+static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
struct net *net = dev_net(dev);
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+ int err = ip6_tnl_dev_init_gen(dev);
+
+ if (err)
+ return err;
- ip6_tnl_dev_init_gen(dev);
t->parms.proto = IPPROTO_IPV6;
dev_hold(dev);
- ip6n->tnls_wc[0] = t;
+ rcu_assign_pointer(ip6n->tnls_wc[0], t);
+ return 0;
}
-static struct xfrm6_tunnel ip4ip6_handler = {
+static struct xfrm6_tunnel ip4ip6_handler __read_mostly = {
.handler = ip4ip6_rcv,
.err_handler = ip4ip6_err,
.priority = 1,
};
-static struct xfrm6_tunnel ip6ip6_handler = {
+static struct xfrm6_tunnel ip6ip6_handler __read_mostly = {
.handler = ip6ip6_rcv,
.err_handler = ip6ip6_err,
.priority = 1,
@@ -1391,14 +1452,14 @@ static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n)
LIST_HEAD(list);
for (h = 0; h < HASH_SIZE; h++) {
- t = ip6n->tnls_r_l[h];
+ t = rtnl_dereference(ip6n->tnls_r_l[h]);
while (t != NULL) {
unregister_netdevice_queue(t->dev, &list);
- t = t->next;
+ t = rtnl_dereference(t->next);
}
}
- t = ip6n->tnls_wc[0];
+ t = rtnl_dereference(ip6n->tnls_wc[0]);
unregister_netdevice_queue(t->dev, &list);
unregister_netdevice_many(&list);
}
@@ -1419,7 +1480,9 @@ static int __net_init ip6_tnl_init_net(struct net *net)
goto err_alloc_dev;
dev_net_set(ip6n->fb_tnl_dev, net);
- ip6_fb_tnl_dev_init(ip6n->fb_tnl_dev);
+ err = ip6_fb_tnl_dev_init(ip6n->fb_tnl_dev);
+ if (err < 0)
+ goto err_register;
err = register_netdev(ip6n->fb_tnl_dev);
if (err < 0)
@@ -1427,7 +1490,7 @@ static int __net_init ip6_tnl_init_net(struct net *net)
return 0;
err_register:
- free_netdev(ip6n->fb_tnl_dev);
+ ip6_dev_free(ip6n->fb_tnl_dev);
err_alloc_dev:
return err;
}
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 66078dad7fe8..6f32ffce7022 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -667,6 +667,7 @@ static int pim6_rcv(struct sk_buff *skb)
skb_tunnel_rx(skb, reg_dev);
netif_rx(skb);
+
dev_put(reg_dev);
return 0;
drop:
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index a7f66bc8f0b0..d1770e061c08 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -342,6 +342,25 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
retv = 0;
break;
+ case IPV6_TRANSPARENT:
+ if (!capable(CAP_NET_ADMIN)) {
+ retv = -EPERM;
+ break;
+ }
+ if (optlen < sizeof(int))
+ goto e_inval;
+ /* we don't have a separate transparent bit for IPV6 we use the one in the IPv4 socket */
+ inet_sk(sk)->transparent = valbool;
+ retv = 0;
+ break;
+
+ case IPV6_RECVORIGDSTADDR:
+ if (optlen < sizeof(int))
+ goto e_inval;
+ np->rxopt.bits.rxorigdstaddr = valbool;
+ retv = 0;
+ break;
+
case IPV6_HOPOPTS:
case IPV6_RTHDRDSTOPTS:
case IPV6_RTHDR:
@@ -1104,6 +1123,14 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
break;
}
+ case IPV6_TRANSPARENT:
+ val = inet_sk(sk)->transparent;
+ break;
+
+ case IPV6_RECVORIGDSTADDR:
+ val = np->rxopt.bits.rxorigdstaddr;
+ break;
+
case IPV6_UNICAST_HOPS:
case IPV6_MULTICAST_HOPS:
{
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 58841c4ae947..998d6d27e7cf 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -91,7 +91,9 @@
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6.h>
-static u32 ndisc_hash(const void *pkey, const struct net_device *dev);
+static u32 ndisc_hash(const void *pkey,
+ const struct net_device *dev,
+ __u32 rnd);
static int ndisc_constructor(struct neighbour *neigh);
static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
@@ -228,12 +230,12 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
do {
cur = ((void *)cur) + (cur->nd_opt_len << 3);
} while(cur < end && cur->nd_opt_type != type);
- return (cur <= end && cur->nd_opt_type == type ? cur : NULL);
+ return cur <= end && cur->nd_opt_type == type ? cur : NULL;
}
static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
{
- return (opt->nd_opt_type == ND_OPT_RDNSS);
+ return opt->nd_opt_type == ND_OPT_RDNSS;
}
static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
@@ -244,7 +246,7 @@ static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
do {
cur = ((void *)cur) + (cur->nd_opt_len << 3);
} while(cur < end && !ndisc_is_useropt(cur));
- return (cur <= end && ndisc_is_useropt(cur) ? cur : NULL);
+ return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
}
static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
@@ -319,7 +321,7 @@ static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p,
int prepad = ndisc_addr_option_pad(dev->type);
if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad))
return NULL;
- return (lladdr + prepad);
+ return lladdr + prepad;
}
int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
@@ -350,7 +352,9 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d
EXPORT_SYMBOL(ndisc_mc_map);
-static u32 ndisc_hash(const void *pkey, const struct net_device *dev)
+static u32 ndisc_hash(const void *pkey,
+ const struct net_device *dev,
+ __u32 hash_rnd)
{
const u32 *p32 = pkey;
u32 addr_hash, i;
@@ -359,7 +363,7 @@ static u32 ndisc_hash(const void *pkey, const struct net_device *dev)
for (i = 0; i < (sizeof(struct in6_addr) / sizeof(u32)); i++)
addr_hash ^= *p32++;
- return jhash_2words(addr_hash, dev->ifindex, nd_tbl.hash_rnd);
+ return jhash_2words(addr_hash, dev->ifindex, hash_rnd);
}
static int ndisc_constructor(struct neighbour *neigh)
@@ -1105,6 +1109,18 @@ errout:
rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
}
+static inline int accept_ra(struct inet6_dev *in6_dev)
+{
+ /*
+ * If forwarding is enabled, RA are not accepted unless the special
+ * hybrid mode (accept_ra=2) is enabled.
+ */
+ if (in6_dev->cnf.forwarding && in6_dev->cnf.accept_ra < 2)
+ return 0;
+
+ return in6_dev->cnf.accept_ra;
+}
+
static void ndisc_router_discovery(struct sk_buff *skb)
{
struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
@@ -1158,8 +1174,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
return;
}
- /* skip route and link configuration on routers */
- if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra)
+ if (!accept_ra(in6_dev))
goto skip_linkparms;
#ifdef CONFIG_IPV6_NDISC_NODETYPE
@@ -1309,8 +1324,7 @@ skip_linkparms:
NEIGH_UPDATE_F_ISROUTER);
}
- /* skip route and link configuration on routers */
- if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra)
+ if (!accept_ra(in6_dev))
goto out;
#ifdef CONFIG_IPV6_ROUTE_INFO
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 29d643bcafa4..448464844a25 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -5,10 +5,15 @@
menu "IPv6: Netfilter Configuration"
depends on INET && IPV6 && NETFILTER
+config NF_DEFRAG_IPV6
+ tristate
+ default n
+
config NF_CONNTRACK_IPV6
tristate "IPv6 connection tracking support"
depends on INET && IPV6 && NF_CONNTRACK
default m if NETFILTER_ADVANCED=n
+ select NF_DEFRAG_IPV6
---help---
Connection tracking keeps a record of what packets have passed
through your machine, in order to figure out how they are related
@@ -132,10 +137,10 @@ config IP6_NF_MATCH_RT
# The targets
config IP6_NF_TARGET_HL
tristate '"HL" hoplimit target support'
- depends on NETFILTER_ADVANCED
+ depends on NETFILTER_ADVANCED && IP6_NF_MANGLE
select NETFILTER_XT_TARGET_HL
---help---
- This is a backwards-compat option for the user's convenience
+ This is a backwards-compatible option for the user's convenience
(e.g. when running oldconfig). It selects
CONFIG_NETFILTER_XT_TARGET_HL.
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index aafbba30c899..0a432c9b0795 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -11,10 +11,14 @@ obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o
# objects for l3 independent conntrack
-nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o
+nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o
# l3 independent conntrack
-obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o
+obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o nf_defrag_ipv6.o
+
+# defrag
+nf_defrag_ipv6-objs := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o
+obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o
# matches
obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 8e754be92c24..51df035897e7 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -82,13 +82,13 @@ EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table);
int
ip6t_ext_hdr(u8 nexthdr)
{
- return ( (nexthdr == IPPROTO_HOPOPTS) ||
- (nexthdr == IPPROTO_ROUTING) ||
- (nexthdr == IPPROTO_FRAGMENT) ||
- (nexthdr == IPPROTO_ESP) ||
- (nexthdr == IPPROTO_AH) ||
- (nexthdr == IPPROTO_NONE) ||
- (nexthdr == IPPROTO_DSTOPTS) );
+ return (nexthdr == IPPROTO_HOPOPTS) ||
+ (nexthdr == IPPROTO_ROUTING) ||
+ (nexthdr == IPPROTO_FRAGMENT) ||
+ (nexthdr == IPPROTO_ESP) ||
+ (nexthdr == IPPROTO_AH) ||
+ (nexthdr == IPPROTO_NONE) ||
+ (nexthdr == IPPROTO_DSTOPTS);
}
/* Returns whether matches rule or not. */
@@ -215,7 +215,7 @@ static inline bool unconditional(const struct ip6t_ip6 *ipv6)
return memcmp(ipv6, &uncond, sizeof(uncond)) == 0;
}
-static inline const struct ip6t_entry_target *
+static inline const struct xt_entry_target *
ip6t_get_target_c(const struct ip6t_entry *e)
{
return ip6t_get_target((struct ip6t_entry *)e);
@@ -260,9 +260,9 @@ get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e,
const char *hookname, const char **chainname,
const char **comment, unsigned int *rulenum)
{
- const struct ip6t_standard_target *t = (void *)ip6t_get_target_c(s);
+ const struct xt_standard_target *t = (void *)ip6t_get_target_c(s);
- if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) {
+ if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) {
/* Head of user chain: ERROR target with chainname */
*chainname = t->target.data;
(*rulenum) = 0;
@@ -271,7 +271,7 @@ get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e,
if (s->target_offset == sizeof(struct ip6t_entry) &&
strcmp(t->target.u.kernel.target->name,
- IP6T_STANDARD_TARGET) == 0 &&
+ XT_STANDARD_TARGET) == 0 &&
t->verdict < 0 &&
unconditional(&s->ipv6)) {
/* Tail of chains: STANDARD target (return/policy) */
@@ -369,7 +369,7 @@ ip6t_do_table(struct sk_buff *skb,
e = get_entry(table_base, private->hook_entry[hook]);
do {
- const struct ip6t_entry_target *t;
+ const struct xt_entry_target *t;
const struct xt_entry_match *ematch;
IP_NF_ASSERT(e);
@@ -403,10 +403,10 @@ ip6t_do_table(struct sk_buff *skb,
if (!t->u.kernel.target->target) {
int v;
- v = ((struct ip6t_standard_target *)t)->verdict;
+ v = ((struct xt_standard_target *)t)->verdict;
if (v < 0) {
/* Pop from stack? */
- if (v != IP6T_RETURN) {
+ if (v != XT_RETURN) {
verdict = (unsigned)(-v) - 1;
break;
}
@@ -434,7 +434,7 @@ ip6t_do_table(struct sk_buff *skb,
acpar.targinfo = t->data;
verdict = t->u.kernel.target->target(skb, &acpar);
- if (verdict == IP6T_CONTINUE)
+ if (verdict == XT_CONTINUE)
e = ip6t_next_entry(e);
else
/* Verdict */
@@ -474,7 +474,7 @@ mark_source_chains(const struct xt_table_info *newinfo,
e->counters.pcnt = pos;
for (;;) {
- const struct ip6t_standard_target *t
+ const struct xt_standard_target *t
= (void *)ip6t_get_target_c(e);
int visited = e->comefrom & (1 << hook);
@@ -488,13 +488,13 @@ mark_source_chains(const struct xt_table_info *newinfo,
/* Unconditional return/END. */
if ((e->target_offset == sizeof(struct ip6t_entry) &&
(strcmp(t->target.u.user.name,
- IP6T_STANDARD_TARGET) == 0) &&
+ XT_STANDARD_TARGET) == 0) &&
t->verdict < 0 &&
unconditional(&e->ipv6)) || visited) {
unsigned int oldpos, size;
if ((strcmp(t->target.u.user.name,
- IP6T_STANDARD_TARGET) == 0) &&
+ XT_STANDARD_TARGET) == 0) &&
t->verdict < -NF_MAX_VERDICT - 1) {
duprintf("mark_source_chains: bad "
"negative verdict (%i)\n",
@@ -537,7 +537,7 @@ mark_source_chains(const struct xt_table_info *newinfo,
int newpos = t->verdict;
if (strcmp(t->target.u.user.name,
- IP6T_STANDARD_TARGET) == 0 &&
+ XT_STANDARD_TARGET) == 0 &&
newpos >= 0) {
if (newpos > newinfo->size -
sizeof(struct ip6t_entry)) {
@@ -565,7 +565,7 @@ mark_source_chains(const struct xt_table_info *newinfo,
return 1;
}
-static void cleanup_match(struct ip6t_entry_match *m, struct net *net)
+static void cleanup_match(struct xt_entry_match *m, struct net *net)
{
struct xt_mtdtor_param par;
@@ -581,14 +581,14 @@ static void cleanup_match(struct ip6t_entry_match *m, struct net *net)
static int
check_entry(const struct ip6t_entry *e, const char *name)
{
- const struct ip6t_entry_target *t;
+ const struct xt_entry_target *t;
if (!ip6_checkentry(&e->ipv6)) {
duprintf("ip_tables: ip check failed %p %s.\n", e, name);
return -EINVAL;
}
- if (e->target_offset + sizeof(struct ip6t_entry_target) >
+ if (e->target_offset + sizeof(struct xt_entry_target) >
e->next_offset)
return -EINVAL;
@@ -599,7 +599,7 @@ check_entry(const struct ip6t_entry *e, const char *name)
return 0;
}
-static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par)
+static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
{
const struct ip6t_ip6 *ipv6 = par->entryinfo;
int ret;
@@ -618,7 +618,7 @@ static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par)
}
static int
-find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par)
+find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
{
struct xt_match *match;
int ret;
@@ -643,7 +643,7 @@ err:
static int check_target(struct ip6t_entry *e, struct net *net, const char *name)
{
- struct ip6t_entry_target *t = ip6t_get_target(e);
+ struct xt_entry_target *t = ip6t_get_target(e);
struct xt_tgchk_param par = {
.net = net,
.table = name,
@@ -670,7 +670,7 @@ static int
find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
unsigned int size)
{
- struct ip6t_entry_target *t;
+ struct xt_entry_target *t;
struct xt_target *target;
int ret;
unsigned int j;
@@ -721,7 +721,7 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
static bool check_underflow(const struct ip6t_entry *e)
{
- const struct ip6t_entry_target *t;
+ const struct xt_entry_target *t;
unsigned int verdict;
if (!unconditional(&e->ipv6))
@@ -729,7 +729,7 @@ static bool check_underflow(const struct ip6t_entry *e)
t = ip6t_get_target_c(e);
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
return false;
- verdict = ((struct ip6t_standard_target *)t)->verdict;
+ verdict = ((struct xt_standard_target *)t)->verdict;
verdict = -verdict - 1;
return verdict == NF_DROP || verdict == NF_ACCEPT;
}
@@ -752,7 +752,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e,
}
if (e->next_offset
- < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
+ < sizeof(struct ip6t_entry) + sizeof(struct xt_entry_target)) {
duprintf("checking: element %p size %u\n",
e, e->next_offset);
return -EINVAL;
@@ -784,7 +784,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e,
static void cleanup_entry(struct ip6t_entry *e, struct net *net)
{
struct xt_tgdtor_param par;
- struct ip6t_entry_target *t;
+ struct xt_entry_target *t;
struct xt_entry_match *ematch;
/* Cleanup all matches */
@@ -985,8 +985,8 @@ copy_entries_to_user(unsigned int total_size,
/* ... then go back and fix counters and names */
for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
unsigned int i;
- const struct ip6t_entry_match *m;
- const struct ip6t_entry_target *t;
+ const struct xt_entry_match *m;
+ const struct xt_entry_target *t;
e = (struct ip6t_entry *)(loc_cpu_entry + off);
if (copy_to_user(userptr + off
@@ -1003,7 +1003,7 @@ copy_entries_to_user(unsigned int total_size,
m = (void *)e + i;
if (copy_to_user(userptr + off + i
- + offsetof(struct ip6t_entry_match,
+ + offsetof(struct xt_entry_match,
u.user.name),
m->u.kernel.match->name,
strlen(m->u.kernel.match->name)+1)
@@ -1015,7 +1015,7 @@ copy_entries_to_user(unsigned int total_size,
t = ip6t_get_target_c(e);
if (copy_to_user(userptr + off + e->target_offset
- + offsetof(struct ip6t_entry_target,
+ + offsetof(struct xt_entry_target,
u.user.name),
t->u.kernel.target->name,
strlen(t->u.kernel.target->name)+1) != 0) {
@@ -1053,7 +1053,7 @@ static int compat_calc_entry(const struct ip6t_entry *e,
const void *base, struct xt_table_info *newinfo)
{
const struct xt_entry_match *ematch;
- const struct ip6t_entry_target *t;
+ const struct xt_entry_target *t;
unsigned int entry_offset;
int off, i, ret;
@@ -1105,7 +1105,7 @@ static int compat_table_info(const struct xt_table_info *info,
static int get_info(struct net *net, void __user *user,
const int *len, int compat)
{
- char name[IP6T_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
struct xt_table *t;
int ret;
@@ -1118,7 +1118,7 @@ static int get_info(struct net *net, void __user *user,
if (copy_from_user(name, user, sizeof(name)) != 0)
return -EFAULT;
- name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
+ name[XT_TABLE_MAXNAMELEN-1] = '\0';
#ifdef CONFIG_COMPAT
if (compat)
xt_compat_lock(AF_INET6);
@@ -1415,14 +1415,14 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len,
#ifdef CONFIG_COMPAT
struct compat_ip6t_replace {
- char name[IP6T_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks;
u32 num_entries;
u32 size;
u32 hook_entry[NF_INET_NUMHOOKS];
u32 underflow[NF_INET_NUMHOOKS];
u32 num_counters;
- compat_uptr_t counters; /* struct ip6t_counters * */
+ compat_uptr_t counters; /* struct xt_counters * */
struct compat_ip6t_entry entries[0];
};
@@ -1431,7 +1431,7 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
unsigned int *size, struct xt_counters *counters,
unsigned int i)
{
- struct ip6t_entry_target *t;
+ struct xt_entry_target *t;
struct compat_ip6t_entry __user *ce;
u_int16_t target_offset, next_offset;
compat_uint_t origsize;
@@ -1466,7 +1466,7 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
}
static int
-compat_find_calc_match(struct ip6t_entry_match *m,
+compat_find_calc_match(struct xt_entry_match *m,
const char *name,
const struct ip6t_ip6 *ipv6,
unsigned int hookmask,
@@ -1488,7 +1488,7 @@ compat_find_calc_match(struct ip6t_entry_match *m,
static void compat_release_entry(struct compat_ip6t_entry *e)
{
- struct ip6t_entry_target *t;
+ struct xt_entry_target *t;
struct xt_entry_match *ematch;
/* Cleanup all matches */
@@ -1509,7 +1509,7 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
const char *name)
{
struct xt_entry_match *ematch;
- struct ip6t_entry_target *t;
+ struct xt_entry_target *t;
struct xt_target *target;
unsigned int entry_offset;
unsigned int j;
@@ -1591,7 +1591,7 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
unsigned int *size, const char *name,
struct xt_table_info *newinfo, unsigned char *base)
{
- struct ip6t_entry_target *t;
+ struct xt_entry_target *t;
struct xt_target *target;
struct ip6t_entry *de;
unsigned int origsize;
@@ -1899,7 +1899,7 @@ compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
}
struct compat_ip6t_get_entries {
- char name[IP6T_TABLE_MAXNAMELEN];
+ char name[XT_TABLE_MAXNAMELEN];
compat_uint_t size;
struct compat_ip6t_entry entrytable[0];
};
@@ -2054,7 +2054,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
case IP6T_SO_GET_REVISION_MATCH:
case IP6T_SO_GET_REVISION_TARGET: {
- struct ip6t_get_revision rev;
+ struct xt_get_revision rev;
int target;
if (*len != sizeof(rev)) {
@@ -2191,7 +2191,7 @@ static int icmp6_checkentry(const struct xt_mtchk_param *par)
/* The built-in targets: standard (NULL) and error. */
static struct xt_target ip6t_builtin_tg[] __read_mostly = {
{
- .name = IP6T_STANDARD_TARGET,
+ .name = XT_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = NFPROTO_IPV6,
#ifdef CONFIG_COMPAT
@@ -2201,9 +2201,9 @@ static struct xt_target ip6t_builtin_tg[] __read_mostly = {
#endif
},
{
- .name = IP6T_ERROR_TARGET,
+ .name = XT_ERROR_TARGET,
.target = ip6t_error,
- .targetsize = IP6T_FUNCTION_MAXNAMELEN,
+ .targetsize = XT_FUNCTION_MAXNAMELEN,
.family = NFPROTO_IPV6,
},
};
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
index 0a07ae7b933f..09c88891a753 100644
--- a/net/ipv6/netfilter/ip6t_LOG.c
+++ b/net/ipv6/netfilter/ip6t_LOG.c
@@ -23,6 +23,7 @@
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <net/netfilter/nf_log.h>
+#include <net/netfilter/xt_log.h>
MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
MODULE_DESCRIPTION("Xtables: IPv6 packet logging to syslog");
@@ -32,11 +33,9 @@ struct in_device;
#include <net/route.h>
#include <linux/netfilter_ipv6/ip6t_LOG.h>
-/* Use lock to serialize, so printks don't overlap */
-static DEFINE_SPINLOCK(log_lock);
-
/* One level of recursion won't kill us */
-static void dump_packet(const struct nf_loginfo *info,
+static void dump_packet(struct sbuff *m,
+ const struct nf_loginfo *info,
const struct sk_buff *skb, unsigned int ip6hoff,
int recurse)
{
@@ -55,15 +54,15 @@ static void dump_packet(const struct nf_loginfo *info,
ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h);
if (ih == NULL) {
- printk("TRUNCATED");
+ sb_add(m, "TRUNCATED");
return;
}
/* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */
- printk("SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr);
+ sb_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr);
/* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */
- printk("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
+ sb_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
ntohs(ih->payload_len) + sizeof(struct ipv6hdr),
(ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20,
ih->hop_limit,
@@ -78,35 +77,35 @@ static void dump_packet(const struct nf_loginfo *info,
hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
if (hp == NULL) {
- printk("TRUNCATED");
+ sb_add(m, "TRUNCATED");
return;
}
/* Max length: 48 "OPT (...) " */
if (logflags & IP6T_LOG_IPOPT)
- printk("OPT ( ");
+ sb_add(m, "OPT ( ");
switch (currenthdr) {
case IPPROTO_FRAGMENT: {
struct frag_hdr _fhdr;
const struct frag_hdr *fh;
- printk("FRAG:");
+ sb_add(m, "FRAG:");
fh = skb_header_pointer(skb, ptr, sizeof(_fhdr),
&_fhdr);
if (fh == NULL) {
- printk("TRUNCATED ");
+ sb_add(m, "TRUNCATED ");
return;
}
/* Max length: 6 "65535 " */
- printk("%u ", ntohs(fh->frag_off) & 0xFFF8);
+ sb_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8);
/* Max length: 11 "INCOMPLETE " */
if (fh->frag_off & htons(0x0001))
- printk("INCOMPLETE ");
+ sb_add(m, "INCOMPLETE ");
- printk("ID:%08x ", ntohl(fh->identification));
+ sb_add(m, "ID:%08x ", ntohl(fh->identification));
if (ntohs(fh->frag_off) & 0xFFF8)
fragment = 1;
@@ -120,7 +119,7 @@ static void dump_packet(const struct nf_loginfo *info,
case IPPROTO_HOPOPTS:
if (fragment) {
if (logflags & IP6T_LOG_IPOPT)
- printk(")");
+ sb_add(m, ")");
return;
}
hdrlen = ipv6_optlen(hp);
@@ -132,10 +131,10 @@ static void dump_packet(const struct nf_loginfo *info,
const struct ip_auth_hdr *ah;
/* Max length: 3 "AH " */
- printk("AH ");
+ sb_add(m, "AH ");
if (fragment) {
- printk(")");
+ sb_add(m, ")");
return;
}
@@ -146,13 +145,13 @@ static void dump_packet(const struct nf_loginfo *info,
* Max length: 26 "INCOMPLETE [65535
* bytes] )"
*/
- printk("INCOMPLETE [%u bytes] )",
+ sb_add(m, "INCOMPLETE [%u bytes] )",
skb->len - ptr);
return;
}
/* Length: 15 "SPI=0xF1234567 */
- printk("SPI=0x%x ", ntohl(ah->spi));
+ sb_add(m, "SPI=0x%x ", ntohl(ah->spi));
}
@@ -164,10 +163,10 @@ static void dump_packet(const struct nf_loginfo *info,
const struct ip_esp_hdr *eh;
/* Max length: 4 "ESP " */
- printk("ESP ");
+ sb_add(m, "ESP ");
if (fragment) {
- printk(")");
+ sb_add(m, ")");
return;
}
@@ -177,23 +176,23 @@ static void dump_packet(const struct nf_loginfo *info,
eh = skb_header_pointer(skb, ptr, sizeof(_esph),
&_esph);
if (eh == NULL) {
- printk("INCOMPLETE [%u bytes] )",
+ sb_add(m, "INCOMPLETE [%u bytes] )",
skb->len - ptr);
return;
}
/* Length: 16 "SPI=0xF1234567 )" */
- printk("SPI=0x%x )", ntohl(eh->spi) );
+ sb_add(m, "SPI=0x%x )", ntohl(eh->spi) );
}
return;
default:
/* Max length: 20 "Unknown Ext Hdr 255" */
- printk("Unknown Ext Hdr %u", currenthdr);
+ sb_add(m, "Unknown Ext Hdr %u", currenthdr);
return;
}
if (logflags & IP6T_LOG_IPOPT)
- printk(") ");
+ sb_add(m, ") ");
currenthdr = hp->nexthdr;
ptr += hdrlen;
@@ -205,7 +204,7 @@ static void dump_packet(const struct nf_loginfo *info,
const struct tcphdr *th;
/* Max length: 10 "PROTO=TCP " */
- printk("PROTO=TCP ");
+ sb_add(m, "PROTO=TCP ");
if (fragment)
break;
@@ -213,40 +212,40 @@ static void dump_packet(const struct nf_loginfo *info,
/* Max length: 25 "INCOMPLETE [65535 bytes] " */
th = skb_header_pointer(skb, ptr, sizeof(_tcph), &_tcph);
if (th == NULL) {
- printk("INCOMPLETE [%u bytes] ", skb->len - ptr);
+ sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr);
return;
}
/* Max length: 20 "SPT=65535 DPT=65535 " */
- printk("SPT=%u DPT=%u ",
+ sb_add(m, "SPT=%u DPT=%u ",
ntohs(th->source), ntohs(th->dest));
/* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
if (logflags & IP6T_LOG_TCPSEQ)
- printk("SEQ=%u ACK=%u ",
+ sb_add(m, "SEQ=%u ACK=%u ",
ntohl(th->seq), ntohl(th->ack_seq));
/* Max length: 13 "WINDOW=65535 " */
- printk("WINDOW=%u ", ntohs(th->window));
+ sb_add(m, "WINDOW=%u ", ntohs(th->window));
/* Max length: 9 "RES=0x3C " */
- printk("RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22));
+ sb_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22));
/* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
if (th->cwr)
- printk("CWR ");
+ sb_add(m, "CWR ");
if (th->ece)
- printk("ECE ");
+ sb_add(m, "ECE ");
if (th->urg)
- printk("URG ");
+ sb_add(m, "URG ");
if (th->ack)
- printk("ACK ");
+ sb_add(m, "ACK ");
if (th->psh)
- printk("PSH ");
+ sb_add(m, "PSH ");
if (th->rst)
- printk("RST ");
+ sb_add(m, "RST ");
if (th->syn)
- printk("SYN ");
+ sb_add(m, "SYN ");
if (th->fin)
- printk("FIN ");
+ sb_add(m, "FIN ");
/* Max length: 11 "URGP=65535 " */
- printk("URGP=%u ", ntohs(th->urg_ptr));
+ sb_add(m, "URGP=%u ", ntohs(th->urg_ptr));
if ((logflags & IP6T_LOG_TCPOPT) &&
th->doff * 4 > sizeof(struct tcphdr)) {
@@ -260,15 +259,15 @@ static void dump_packet(const struct nf_loginfo *info,
ptr + sizeof(struct tcphdr),
optsize, _opt);
if (op == NULL) {
- printk("OPT (TRUNCATED)");
+ sb_add(m, "OPT (TRUNCATED)");
return;
}
/* Max length: 127 "OPT (" 15*4*2chars ") " */
- printk("OPT (");
+ sb_add(m, "OPT (");
for (i =0; i < optsize; i++)
- printk("%02X", op[i]);
- printk(") ");
+ sb_add(m, "%02X", op[i]);
+ sb_add(m, ") ");
}
break;
}
@@ -279,9 +278,9 @@ static void dump_packet(const struct nf_loginfo *info,
if (currenthdr == IPPROTO_UDP)
/* Max length: 10 "PROTO=UDP " */
- printk("PROTO=UDP " );
+ sb_add(m, "PROTO=UDP " );
else /* Max length: 14 "PROTO=UDPLITE " */
- printk("PROTO=UDPLITE ");
+ sb_add(m, "PROTO=UDPLITE ");
if (fragment)
break;
@@ -289,12 +288,12 @@ static void dump_packet(const struct nf_loginfo *info,
/* Max length: 25 "INCOMPLETE [65535 bytes] " */
uh = skb_header_pointer(skb, ptr, sizeof(_udph), &_udph);
if (uh == NULL) {
- printk("INCOMPLETE [%u bytes] ", skb->len - ptr);
+ sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr);
return;
}
/* Max length: 20 "SPT=65535 DPT=65535 " */
- printk("SPT=%u DPT=%u LEN=%u ",
+ sb_add(m, "SPT=%u DPT=%u LEN=%u ",
ntohs(uh->source), ntohs(uh->dest),
ntohs(uh->len));
break;
@@ -304,7 +303,7 @@ static void dump_packet(const struct nf_loginfo *info,
const struct icmp6hdr *ic;
/* Max length: 13 "PROTO=ICMPv6 " */
- printk("PROTO=ICMPv6 ");
+ sb_add(m, "PROTO=ICMPv6 ");
if (fragment)
break;
@@ -312,18 +311,18 @@ static void dump_packet(const struct nf_loginfo *info,
/* Max length: 25 "INCOMPLETE [65535 bytes] " */
ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h);
if (ic == NULL) {
- printk("INCOMPLETE [%u bytes] ", skb->len - ptr);
+ sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr);
return;
}
/* Max length: 18 "TYPE=255 CODE=255 " */
- printk("TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code);
+ sb_add(m, "TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code);
switch (ic->icmp6_type) {
case ICMPV6_ECHO_REQUEST:
case ICMPV6_ECHO_REPLY:
/* Max length: 19 "ID=65535 SEQ=65535 " */
- printk("ID=%u SEQ=%u ",
+ sb_add(m, "ID=%u SEQ=%u ",
ntohs(ic->icmp6_identifier),
ntohs(ic->icmp6_sequence));
break;
@@ -334,35 +333,35 @@ static void dump_packet(const struct nf_loginfo *info,
case ICMPV6_PARAMPROB:
/* Max length: 17 "POINTER=ffffffff " */
- printk("POINTER=%08x ", ntohl(ic->icmp6_pointer));
+ sb_add(m, "POINTER=%08x ", ntohl(ic->icmp6_pointer));
/* Fall through */
case ICMPV6_DEST_UNREACH:
case ICMPV6_PKT_TOOBIG:
case ICMPV6_TIME_EXCEED:
/* Max length: 3+maxlen */
if (recurse) {
- printk("[");
- dump_packet(info, skb, ptr + sizeof(_icmp6h),
- 0);
- printk("] ");
+ sb_add(m, "[");
+ dump_packet(m, info, skb,
+ ptr + sizeof(_icmp6h), 0);
+ sb_add(m, "] ");
}
/* Max length: 10 "MTU=65535 " */
if (ic->icmp6_type == ICMPV6_PKT_TOOBIG)
- printk("MTU=%u ", ntohl(ic->icmp6_mtu));
+ sb_add(m, "MTU=%u ", ntohl(ic->icmp6_mtu));
}
break;
}
/* Max length: 10 "PROTO=255 " */
default:
- printk("PROTO=%u ", currenthdr);
+ sb_add(m, "PROTO=%u ", currenthdr);
}
/* Max length: 15 "UID=4294967295 " */
if ((logflags & IP6T_LOG_UID) && recurse && skb->sk) {
read_lock_bh(&skb->sk->sk_callback_lock);
if (skb->sk->sk_socket && skb->sk->sk_socket->file)
- printk("UID=%u GID=%u ",
+ sb_add(m, "UID=%u GID=%u ",
skb->sk->sk_socket->file->f_cred->fsuid,
skb->sk->sk_socket->file->f_cred->fsgid);
read_unlock_bh(&skb->sk->sk_callback_lock);
@@ -370,10 +369,11 @@ static void dump_packet(const struct nf_loginfo *info,
/* Max length: 16 "MARK=0xFFFFFFFF " */
if (!recurse && skb->mark)
- printk("MARK=0x%x ", skb->mark);
+ sb_add(m, "MARK=0x%x ", skb->mark);
}
-static void dump_mac_header(const struct nf_loginfo *info,
+static void dump_mac_header(struct sbuff *m,
+ const struct nf_loginfo *info,
const struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
@@ -387,7 +387,7 @@ static void dump_mac_header(const struct nf_loginfo *info,
switch (dev->type) {
case ARPHRD_ETHER:
- printk("MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
+ sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
ntohs(eth_hdr(skb)->h_proto));
return;
@@ -396,7 +396,7 @@ static void dump_mac_header(const struct nf_loginfo *info,
}
fallback:
- printk("MAC=");
+ sb_add(m, "MAC=");
if (dev->hard_header_len &&
skb->mac_header != skb->network_header) {
const unsigned char *p = skb_mac_header(skb);
@@ -408,19 +408,19 @@ fallback:
p = NULL;
if (p != NULL) {
- printk("%02x", *p++);
+ sb_add(m, "%02x", *p++);
for (i = 1; i < len; i++)
- printk(":%02x", p[i]);
+ sb_add(m, ":%02x", p[i]);
}
- printk(" ");
+ sb_add(m, " ");
if (dev->type == ARPHRD_SIT) {
const struct iphdr *iph =
(struct iphdr *)skb_mac_header(skb);
- printk("TUNNEL=%pI4->%pI4 ", &iph->saddr, &iph->daddr);
+ sb_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr, &iph->daddr);
}
} else
- printk(" ");
+ sb_add(m, " ");
}
static struct nf_loginfo default_loginfo = {
@@ -442,22 +442,23 @@ ip6t_log_packet(u_int8_t pf,
const struct nf_loginfo *loginfo,
const char *prefix)
{
+ struct sbuff *m = sb_open();
+
if (!loginfo)
loginfo = &default_loginfo;
- spin_lock_bh(&log_lock);
- printk("<%d>%sIN=%s OUT=%s ", loginfo->u.log.level,
- prefix,
- in ? in->name : "",
- out ? out->name : "");
+ sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level,
+ prefix,
+ in ? in->name : "",
+ out ? out->name : "");
/* MAC logging for input path only. */
if (in && !out)
- dump_mac_header(loginfo, skb);
+ dump_mac_header(m, loginfo, skb);
+
+ dump_packet(m, loginfo, skb, skb_network_offset(skb), 1);
- dump_packet(loginfo, skb, skb_network_offset(skb), 1);
- printk("\n");
- spin_unlock_bh(&log_lock);
+ sb_close(m);
}
static unsigned int
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index ff43461704be..c8af58b22562 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -16,7 +16,6 @@
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/icmp.h>
-#include <linux/sysctl.h>
#include <net/ipv6.h>
#include <net/inet_frag.h>
@@ -29,6 +28,7 @@
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
+#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
#include <net/netfilter/nf_log.h>
static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
@@ -189,53 +189,6 @@ out:
return nf_conntrack_confirm(skb);
}
-static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
- struct sk_buff *skb)
-{
- u16 zone = NF_CT_DEFAULT_ZONE;
-
- if (skb->nfct)
- zone = nf_ct_zone((struct nf_conn *)skb->nfct);
-
-#ifdef CONFIG_BRIDGE_NETFILTER
- if (skb->nf_bridge &&
- skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)
- return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone;
-#endif
- if (hooknum == NF_INET_PRE_ROUTING)
- return IP6_DEFRAG_CONNTRACK_IN + zone;
- else
- return IP6_DEFRAG_CONNTRACK_OUT + zone;
-
-}
-
-static unsigned int ipv6_defrag(unsigned int hooknum,
- struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
-{
- struct sk_buff *reasm;
-
- /* Previously seen (loopback)? */
- if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct))
- return NF_ACCEPT;
-
- reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb));
- /* queued */
- if (reasm == NULL)
- return NF_STOLEN;
-
- /* error occured or not fragmented */
- if (reasm == skb)
- return NF_ACCEPT;
-
- nf_ct_frag6_output(hooknum, reasm, (struct net_device *)in,
- (struct net_device *)out, okfn);
-
- return NF_STOLEN;
-}
-
static unsigned int __ipv6_conntrack_in(struct net *net,
unsigned int hooknum,
struct sk_buff *skb,
@@ -288,13 +241,6 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum,
static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = {
{
- .hook = ipv6_defrag,
- .owner = THIS_MODULE,
- .pf = NFPROTO_IPV6,
- .hooknum = NF_INET_PRE_ROUTING,
- .priority = NF_IP6_PRI_CONNTRACK_DEFRAG,
- },
- {
.hook = ipv6_conntrack_in,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV6,
@@ -309,13 +255,6 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = {
.priority = NF_IP6_PRI_CONNTRACK,
},
{
- .hook = ipv6_defrag,
- .owner = THIS_MODULE,
- .pf = NFPROTO_IPV6,
- .hooknum = NF_INET_LOCAL_OUT,
- .priority = NF_IP6_PRI_CONNTRACK_DEFRAG,
- },
- {
.hook = ipv6_confirm,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV6,
@@ -387,10 +326,6 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = {
.nlattr_to_tuple = ipv6_nlattr_to_tuple,
.nla_policy = ipv6_nla_policy,
#endif
-#ifdef CONFIG_SYSCTL
- .ctl_table_path = nf_net_netfilter_sysctl_path,
- .ctl_table = nf_ct_ipv6_sysctl_table,
-#endif
.me = THIS_MODULE,
};
@@ -403,16 +338,12 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
int ret = 0;
need_conntrack();
+ nf_defrag_ipv6_enable();
- ret = nf_ct_frag6_init();
- if (ret < 0) {
- pr_err("nf_conntrack_ipv6: can't initialize frag6.\n");
- return ret;
- }
ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp6);
if (ret < 0) {
pr_err("nf_conntrack_ipv6: can't register tcp.\n");
- goto cleanup_frag6;
+ return ret;
}
ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp6);
@@ -450,8 +381,6 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6);
cleanup_tcp:
nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6);
- cleanup_frag6:
- nf_ct_frag6_cleanup();
return ret;
}
@@ -463,7 +392,6 @@ static void __exit nf_conntrack_l3proto_ipv6_fini(void)
nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmpv6);
nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6);
nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6);
- nf_ct_frag6_cleanup();
}
module_init(nf_conntrack_l3proto_ipv6_init);
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 578f3c1a16db..3a3f129a44cb 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -73,7 +73,7 @@ static struct inet_frags nf_frags;
static struct netns_frags nf_init_frags;
#ifdef CONFIG_SYSCTL
-struct ctl_table nf_ct_ipv6_sysctl_table[] = {
+struct ctl_table nf_ct_frag6_sysctl_table[] = {
{
.procname = "nf_conntrack_frag6_timeout",
.data = &nf_init_frags.timeout,
@@ -97,6 +97,8 @@ struct ctl_table nf_ct_ipv6_sysctl_table[] = {
},
{ }
};
+
+static struct ctl_table_header *nf_ct_frag6_sysctl_header;
#endif
static unsigned int nf_hashfn(struct inet_frag_queue *q)
@@ -363,7 +365,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
/* If the first fragment is fragmented itself, we split
* it to two chunks: the first with data and paged part
* and the second, holding only fragments. */
- if (skb_has_frags(head)) {
+ if (skb_has_frag_list(head)) {
struct sk_buff *clone;
int i, plen = 0;
@@ -623,11 +625,24 @@ int nf_ct_frag6_init(void)
inet_frags_init_net(&nf_init_frags);
inet_frags_init(&nf_frags);
+#ifdef CONFIG_SYSCTL
+ nf_ct_frag6_sysctl_header = register_sysctl_paths(nf_net_netfilter_sysctl_path,
+ nf_ct_frag6_sysctl_table);
+ if (!nf_ct_frag6_sysctl_header) {
+ inet_frags_fini(&nf_frags);
+ return -ENOMEM;
+ }
+#endif
+
return 0;
}
void nf_ct_frag6_cleanup(void)
{
+#ifdef CONFIG_SYSCTL
+ unregister_sysctl_table(nf_ct_frag6_sysctl_header);
+ nf_ct_frag6_sysctl_header = NULL;
+#endif
inet_frags_fini(&nf_frags);
nf_init_frags.low_thresh = 0;
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
new file mode 100644
index 000000000000..99abfb53bab9
--- /dev/null
+++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
@@ -0,0 +1,131 @@
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/ipv6.h>
+#include <linux/in6.h>
+#include <linux/netfilter.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/icmp.h>
+#include <linux/sysctl.h>
+#include <net/ipv6.h>
+#include <net/inet_frag.h>
+
+#include <linux/netfilter_ipv6.h>
+#include <linux/netfilter_bridge.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_conntrack_l4proto.h>
+#include <net/netfilter/nf_conntrack_l3proto.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_zones.h>
+#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
+#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
+
+static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
+ struct sk_buff *skb)
+{
+ u16 zone = NF_CT_DEFAULT_ZONE;
+
+ if (skb->nfct)
+ zone = nf_ct_zone((struct nf_conn *)skb->nfct);
+
+#ifdef CONFIG_BRIDGE_NETFILTER
+ if (skb->nf_bridge &&
+ skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)
+ return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone;
+#endif
+ if (hooknum == NF_INET_PRE_ROUTING)
+ return IP6_DEFRAG_CONNTRACK_IN + zone;
+ else
+ return IP6_DEFRAG_CONNTRACK_OUT + zone;
+
+}
+
+static unsigned int ipv6_defrag(unsigned int hooknum,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ struct sk_buff *reasm;
+
+ /* Previously seen (loopback)? */
+ if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct))
+ return NF_ACCEPT;
+
+ reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb));
+ /* queued */
+ if (reasm == NULL)
+ return NF_STOLEN;
+
+ /* error occured or not fragmented */
+ if (reasm == skb)
+ return NF_ACCEPT;
+
+ nf_ct_frag6_output(hooknum, reasm, (struct net_device *)in,
+ (struct net_device *)out, okfn);
+
+ return NF_STOLEN;
+}
+
+static struct nf_hook_ops ipv6_defrag_ops[] = {
+ {
+ .hook = ipv6_defrag,
+ .owner = THIS_MODULE,
+ .pf = NFPROTO_IPV6,
+ .hooknum = NF_INET_PRE_ROUTING,
+ .priority = NF_IP6_PRI_CONNTRACK_DEFRAG,
+ },
+ {
+ .hook = ipv6_defrag,
+ .owner = THIS_MODULE,
+ .pf = NFPROTO_IPV6,
+ .hooknum = NF_INET_LOCAL_OUT,
+ .priority = NF_IP6_PRI_CONNTRACK_DEFRAG,
+ },
+};
+
+static int __init nf_defrag_init(void)
+{
+ int ret = 0;
+
+ ret = nf_ct_frag6_init();
+ if (ret < 0) {
+ pr_err("nf_defrag_ipv6: can't initialize frag6.\n");
+ return ret;
+ }
+ ret = nf_register_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops));
+ if (ret < 0) {
+ pr_err("nf_defrag_ipv6: can't register hooks\n");
+ goto cleanup_frag6;
+ }
+ return ret;
+
+cleanup_frag6:
+ nf_ct_frag6_cleanup();
+ return ret;
+
+}
+
+static void __exit nf_defrag_fini(void)
+{
+ nf_unregister_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops));
+ nf_ct_frag6_cleanup();
+}
+
+void nf_defrag_ipv6_enable(void)
+{
+}
+EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable);
+
+module_init(nf_defrag_init);
+module_exit(nf_defrag_fini);
+
+MODULE_LICENSE("GPL");
diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c
index 1fa3468f0f32..9a7978fdc02a 100644
--- a/net/ipv6/protocol.c
+++ b/net/ipv6/protocol.c
@@ -25,28 +25,15 @@
#include <linux/spinlock.h>
#include <net/protocol.h>
-const struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
-static DEFINE_SPINLOCK(inet6_proto_lock);
-
+const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS] __read_mostly;
int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol)
{
- int ret, hash = protocol & (MAX_INET_PROTOS - 1);
-
- spin_lock_bh(&inet6_proto_lock);
-
- if (inet6_protos[hash]) {
- ret = -1;
- } else {
- inet6_protos[hash] = prot;
- ret = 0;
- }
-
- spin_unlock_bh(&inet6_proto_lock);
+ int hash = protocol & (MAX_INET_PROTOS - 1);
- return ret;
+ return !cmpxchg((const struct inet6_protocol **)&inet6_protos[hash],
+ NULL, prot) ? 0 : -1;
}
-
EXPORT_SYMBOL(inet6_add_protocol);
/*
@@ -57,20 +44,11 @@ int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol
{
int ret, hash = protocol & (MAX_INET_PROTOS - 1);
- spin_lock_bh(&inet6_proto_lock);
-
- if (inet6_protos[hash] != prot) {
- ret = -1;
- } else {
- inet6_protos[hash] = NULL;
- ret = 0;
- }
-
- spin_unlock_bh(&inet6_proto_lock);
+ ret = (cmpxchg((const struct inet6_protocol **)&inet6_protos[hash],
+ prot, NULL) == prot) ? 0 : -1;
synchronize_net();
return ret;
}
-
EXPORT_SYMBOL(inet6_del_protocol);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index e677937a07fc..86c39526ba5e 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -373,7 +373,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr,
static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
{
- if ((raw6_sk(sk)->checksum || sk->sk_filter) &&
+ if ((raw6_sk(sk)->checksum || rcu_dereference_raw(sk->sk_filter)) &&
skb_checksum_complete(skb)) {
atomic_inc(&sk->sk_drops);
kfree_skb(skb);
@@ -764,7 +764,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
return -EINVAL;
if (sin6->sin6_family && sin6->sin6_family != AF_INET6)
- return(-EAFNOSUPPORT);
+ return -EAFNOSUPPORT;
/* port is the proto value [0..255] carried in nexthdr */
proto = ntohs(sin6->sin6_port);
@@ -772,10 +772,10 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
if (!proto)
proto = inet->inet_num;
else if (proto != inet->inet_num)
- return(-EINVAL);
+ return -EINVAL;
if (proto > 255)
- return(-EINVAL);
+ return -EINVAL;
daddr = &sin6->sin6_addr;
if (np->sndflow) {
@@ -985,7 +985,7 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname,
/* You may get strange result with a positive odd offset;
RFC2292bis agrees with me. */
if (val > 0 && (val&1))
- return(-EINVAL);
+ return -EINVAL;
if (val < 0) {
rp->checksum = 0;
} else {
@@ -997,7 +997,7 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname,
break;
default:
- return(-ENOPROTOOPT);
+ return -ENOPROTOOPT;
}
}
@@ -1190,7 +1190,7 @@ static int rawv6_init_sk(struct sock *sk)
default:
break;
}
- return(0);
+ return 0;
}
struct proto rawv6_prot = {
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 64cfef1b0a4c..c7ba3149633f 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -458,7 +458,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
/* If the first fragment is fragmented itself, we split
* it to two chunks: the first with data and paged part
* and the second, holding only fragments. */
- if (skb_has_frags(head)) {
+ if (skb_has_frag_list(head)) {
struct sk_buff *clone;
int i, plen = 0;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index a275c6e1e25c..25661f968f3f 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -109,7 +109,6 @@ static struct dst_ops ip6_dst_ops_template = {
.link_failure = ip6_link_failure,
.update_pmtu = ip6_rt_update_pmtu,
.local_out = __ip6_local_out,
- .entries = ATOMIC_INIT(0),
};
static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
@@ -122,7 +121,6 @@ static struct dst_ops ip6_dst_blackhole_ops = {
.destroy = ip6_dst_destroy,
.check = ip6_dst_check,
.update_pmtu = ip6_rt_blackhole_update_pmtu,
- .entries = ATOMIC_INIT(0),
};
static struct rt6_info ip6_null_entry_template = {
@@ -217,14 +215,14 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
static __inline__ int rt6_check_expired(const struct rt6_info *rt)
{
- return (rt->rt6i_flags & RTF_EXPIRES &&
- time_after(jiffies, rt->rt6i_expires));
+ return (rt->rt6i_flags & RTF_EXPIRES) &&
+ time_after(jiffies, rt->rt6i_expires);
}
static inline int rt6_need_strict(struct in6_addr *daddr)
{
- return (ipv6_addr_type(daddr) &
- (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK));
+ return ipv6_addr_type(daddr) &
+ (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK);
}
/*
@@ -440,7 +438,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
__func__, match);
net = dev_net(rt0->rt6i_dev);
- return (match ? match : net->ipv6.ip6_null_entry);
+ return match ? match : net->ipv6.ip6_null_entry;
}
#ifdef CONFIG_IPV6_ROUTE_INFO
@@ -859,7 +857,7 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl
dst_release(*dstp);
*dstp = new;
- return (new ? 0 : -ENOMEM);
+ return new ? 0 : -ENOMEM;
}
EXPORT_SYMBOL_GPL(ip6_dst_blackhole);
@@ -1058,19 +1056,22 @@ static int ip6_dst_gc(struct dst_ops *ops)
int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
+ int entries;
+ entries = dst_entries_get_fast(ops);
if (time_after(rt_last_gc + rt_min_interval, now) &&
- atomic_read(&ops->entries) <= rt_max_size)
+ entries <= rt_max_size)
goto out;
net->ipv6.ip6_rt_gc_expire++;
fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net);
net->ipv6.ip6_rt_last_gc = now;
- if (atomic_read(&ops->entries) < ops->gc_thresh)
+ entries = dst_entries_get_slow(ops);
+ if (entries < ops->gc_thresh)
net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
out:
net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
- return (atomic_read(&ops->entries) > rt_max_size);
+ return entries > rt_max_size;
}
/* Clean host part of a prefix. Not necessary in radix tree,
@@ -1169,6 +1170,8 @@ int ip6_route_add(struct fib6_config *cfg)
if (addr_type & IPV6_ADDR_MULTICAST)
rt->dst.input = ip6_mc_input;
+ else if (cfg->fc_flags & RTF_LOCAL)
+ rt->dst.input = ip6_input;
else
rt->dst.input = ip6_forward;
@@ -1190,7 +1193,8 @@ int ip6_route_add(struct fib6_config *cfg)
they would result in kernel looping; promote them to reject routes
*/
if ((cfg->fc_flags & RTF_REJECT) ||
- (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) {
+ (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK)
+ && !(cfg->fc_flags&RTF_LOCAL))) {
/* hold loopback dev/idev if we haven't done so. */
if (dev != net->loopback_dev) {
if (dev) {
@@ -2102,6 +2106,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
if (rtm->rtm_type == RTN_UNREACHABLE)
cfg->fc_flags |= RTF_REJECT;
+ if (rtm->rtm_type == RTN_LOCAL)
+ cfg->fc_flags |= RTF_LOCAL;
+
cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid;
cfg->fc_nlinfo.nlh = nlh;
cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
@@ -2222,6 +2229,8 @@ static int rt6_fill_node(struct net *net,
NLA_PUT_U32(skb, RTA_TABLE, table);
if (rt->rt6i_flags&RTF_REJECT)
rtm->rtm_type = RTN_UNREACHABLE;
+ else if (rt->rt6i_flags&RTF_LOCAL)
+ rtm->rtm_type = RTN_LOCAL;
else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK))
rtm->rtm_type = RTN_LOCAL;
else
@@ -2516,7 +2525,7 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v)
net->ipv6.rt6_stats->fib_rt_alloc,
net->ipv6.rt6_stats->fib_rt_entries,
net->ipv6.rt6_stats->fib_rt_cache,
- atomic_read(&net->ipv6.ip6_dst_ops.entries),
+ dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
net->ipv6.rt6_stats->fib_discarded_routes);
return 0;
@@ -2658,11 +2667,14 @@ static int __net_init ip6_route_net_init(struct net *net)
memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
sizeof(net->ipv6.ip6_dst_ops));
+ if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
+ goto out_ip6_dst_ops;
+
net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
sizeof(*net->ipv6.ip6_null_entry),
GFP_KERNEL);
if (!net->ipv6.ip6_null_entry)
- goto out_ip6_dst_ops;
+ goto out_ip6_dst_entries;
net->ipv6.ip6_null_entry->dst.path =
(struct dst_entry *)net->ipv6.ip6_null_entry;
net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
@@ -2712,6 +2724,8 @@ out_ip6_prohibit_entry:
out_ip6_null_entry:
kfree(net->ipv6.ip6_null_entry);
#endif
+out_ip6_dst_entries:
+ dst_entries_destroy(&net->ipv6.ip6_dst_ops);
out_ip6_dst_ops:
goto out;
}
@@ -2750,10 +2764,14 @@ int __init ip6_route_init(void)
if (!ip6_dst_ops_template.kmem_cachep)
goto out;
- ret = register_pernet_subsys(&ip6_route_net_ops);
+ ret = dst_entries_init(&ip6_dst_blackhole_ops);
if (ret)
goto out_kmem_cache;
+ ret = register_pernet_subsys(&ip6_route_net_ops);
+ if (ret)
+ goto out_dst_entries;
+
ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
/* Registering of the loopback is done before this portion of code,
@@ -2800,6 +2818,8 @@ out_fib6_init:
fib6_gc_cleanup();
out_register_subsys:
unregister_pernet_subsys(&ip6_route_net_ops);
+out_dst_entries:
+ dst_entries_destroy(&ip6_dst_blackhole_ops);
out_kmem_cache:
kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
goto out;
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 4699cd3c3118..d6bfaec3bbbf 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -63,36 +63,63 @@
#define HASH_SIZE 16
#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
-static void ipip6_tunnel_init(struct net_device *dev);
+static int ipip6_tunnel_init(struct net_device *dev);
static void ipip6_tunnel_setup(struct net_device *dev);
+static void ipip6_dev_free(struct net_device *dev);
static int sit_net_id __read_mostly;
struct sit_net {
- struct ip_tunnel *tunnels_r_l[HASH_SIZE];
- struct ip_tunnel *tunnels_r[HASH_SIZE];
- struct ip_tunnel *tunnels_l[HASH_SIZE];
- struct ip_tunnel *tunnels_wc[1];
- struct ip_tunnel **tunnels[4];
+ struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE];
+ struct ip_tunnel __rcu *tunnels_r[HASH_SIZE];
+ struct ip_tunnel __rcu *tunnels_l[HASH_SIZE];
+ struct ip_tunnel __rcu *tunnels_wc[1];
+ struct ip_tunnel __rcu **tunnels[4];
struct net_device *fb_tunnel_dev;
};
/*
- * Locking : hash tables are protected by RCU and a spinlock
+ * Locking : hash tables are protected by RCU and RTNL
*/
-static DEFINE_SPINLOCK(ipip6_lock);
#define for_each_ip_tunnel_rcu(start) \
for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
+/* often modified stats are per cpu, other are shared (netdev->stats) */
+struct pcpu_tstats {
+ unsigned long rx_packets;
+ unsigned long rx_bytes;
+ unsigned long tx_packets;
+ unsigned long tx_bytes;
+};
+
+static struct net_device_stats *ipip6_get_stats(struct net_device *dev)
+{
+ struct pcpu_tstats sum = { 0 };
+ int i;
+
+ for_each_possible_cpu(i) {
+ const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
+
+ sum.rx_packets += tstats->rx_packets;
+ sum.rx_bytes += tstats->rx_bytes;
+ sum.tx_packets += tstats->tx_packets;
+ sum.tx_bytes += tstats->tx_bytes;
+ }
+ dev->stats.rx_packets = sum.rx_packets;
+ dev->stats.rx_bytes = sum.rx_bytes;
+ dev->stats.tx_packets = sum.tx_packets;
+ dev->stats.tx_bytes = sum.tx_bytes;
+ return &dev->stats;
+}
/*
* Must be invoked with rcu_read_lock
*/
static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net,
struct net_device *dev, __be32 remote, __be32 local)
{
- unsigned h0 = HASH(remote);
- unsigned h1 = HASH(local);
+ unsigned int h0 = HASH(remote);
+ unsigned int h1 = HASH(local);
struct ip_tunnel *t;
struct sit_net *sitn = net_generic(net, sit_net_id);
@@ -121,12 +148,12 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net,
return NULL;
}
-static struct ip_tunnel **__ipip6_bucket(struct sit_net *sitn,
+static struct ip_tunnel __rcu **__ipip6_bucket(struct sit_net *sitn,
struct ip_tunnel_parm *parms)
{
__be32 remote = parms->iph.daddr;
__be32 local = parms->iph.saddr;
- unsigned h = 0;
+ unsigned int h = 0;
int prio = 0;
if (remote) {
@@ -140,7 +167,7 @@ static struct ip_tunnel **__ipip6_bucket(struct sit_net *sitn,
return &sitn->tunnels[prio][h];
}
-static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn,
+static inline struct ip_tunnel __rcu **ipip6_bucket(struct sit_net *sitn,
struct ip_tunnel *t)
{
return __ipip6_bucket(sitn, &t->parms);
@@ -148,13 +175,14 @@ static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn,
static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t)
{
- struct ip_tunnel **tp;
-
- for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) {
- if (t == *tp) {
- spin_lock_bh(&ipip6_lock);
- *tp = t->next;
- spin_unlock_bh(&ipip6_lock);
+ struct ip_tunnel __rcu **tp;
+ struct ip_tunnel *iter;
+
+ for (tp = ipip6_bucket(sitn, t);
+ (iter = rtnl_dereference(*tp)) != NULL;
+ tp = &iter->next) {
+ if (t == iter) {
+ rcu_assign_pointer(*tp, t->next);
break;
}
}
@@ -162,12 +190,10 @@ static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t)
static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
{
- struct ip_tunnel **tp = ipip6_bucket(sitn, t);
+ struct ip_tunnel __rcu **tp = ipip6_bucket(sitn, t);
- spin_lock_bh(&ipip6_lock);
- t->next = *tp;
+ rcu_assign_pointer(t->next, rtnl_dereference(*tp));
rcu_assign_pointer(*tp, t);
- spin_unlock_bh(&ipip6_lock);
}
static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
@@ -187,17 +213,20 @@ static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
#endif
}
-static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
+static struct ip_tunnel *ipip6_tunnel_locate(struct net *net,
struct ip_tunnel_parm *parms, int create)
{
__be32 remote = parms->iph.daddr;
__be32 local = parms->iph.saddr;
- struct ip_tunnel *t, **tp, *nt;
+ struct ip_tunnel *t, *nt;
+ struct ip_tunnel __rcu **tp;
struct net_device *dev;
char name[IFNAMSIZ];
struct sit_net *sitn = net_generic(net, sit_net_id);
- for (tp = __ipip6_bucket(sitn, parms); (t = *tp) != NULL; tp = &t->next) {
+ for (tp = __ipip6_bucket(sitn, parms);
+ (t = rtnl_dereference(*tp)) != NULL;
+ tp = &t->next) {
if (local == t->parms.iph.saddr &&
remote == t->parms.iph.daddr &&
parms->link == t->parms.link) {
@@ -213,7 +242,7 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
if (parms->name[0])
strlcpy(name, parms->name, IFNAMSIZ);
else
- sprintf(name, "sit%%d");
+ strcpy(name, "sit%d");
dev = alloc_netdev(sizeof(*t), name, ipip6_tunnel_setup);
if (dev == NULL)
@@ -229,7 +258,8 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
nt = netdev_priv(dev);
nt->parms = *parms;
- ipip6_tunnel_init(dev);
+ if (ipip6_tunnel_init(dev) < 0)
+ goto failed_free;
ipip6_tunnel_clone_6rd(dev, sitn);
if (parms->i_flags & SIT_ISATAP)
@@ -244,7 +274,7 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
return nt;
failed_free:
- free_netdev(dev);
+ ipip6_dev_free(dev);
failed:
return NULL;
}
@@ -340,7 +370,7 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
ASSERT_RTNL();
- for (p = t->prl; p; p = p->next) {
+ for (p = rtnl_dereference(t->prl); p; p = rtnl_dereference(p->next)) {
if (p->addr == a->addr) {
if (chg) {
p->flags = a->flags;
@@ -451,15 +481,12 @@ 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) {
- spin_lock_bh(&ipip6_lock);
- sitn->tunnels_wc[0] = NULL;
- spin_unlock_bh(&ipip6_lock);
- dev_put(dev);
+ rcu_assign_pointer(sitn->tunnels_wc[0], NULL);
} else {
ipip6_tunnel_unlink(sitn, netdev_priv(dev));
ipip6_tunnel_del_prl(netdev_priv(dev), NULL);
- dev_put(dev);
}
+ dev_put(dev);
}
@@ -548,6 +575,8 @@ static int ipip6_rcv(struct sk_buff *skb)
tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
iph->saddr, iph->daddr);
if (tunnel != NULL) {
+ struct pcpu_tstats *tstats;
+
secpath_reset(skb);
skb->mac_header = skb->network_header;
skb_reset_network_header(skb);
@@ -563,10 +592,16 @@ static int ipip6_rcv(struct sk_buff *skb)
return 0;
}
- skb_tunnel_rx(skb, tunnel->dev);
+ tstats = this_cpu_ptr(tunnel->dev->tstats);
+ tstats->rx_packets++;
+ tstats->rx_bytes += skb->len;
+
+ __skb_tunnel_rx(skb, tunnel->dev);
ipip6_ecn_decapsulate(iph, skb);
+
netif_rx(skb);
+
rcu_read_unlock();
return 0;
}
@@ -590,7 +625,7 @@ __be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel)
#ifdef CONFIG_IPV6_SIT_6RD
if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix,
tunnel->ip6rd.prefixlen)) {
- unsigned pbw0, pbi0;
+ unsigned int pbw0, pbi0;
int pbi1;
u32 d;
@@ -625,14 +660,13 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
+ struct pcpu_tstats *tstats;
struct iphdr *tiph = &tunnel->parms.iph;
struct ipv6hdr *iph6 = ipv6_hdr(skb);
u8 tos = tunnel->parms.iph.tos;
__be16 df = tiph->frag_off;
struct rtable *rt; /* Route to the other host */
- struct net_device *tdev; /* Device to other host */
+ struct net_device *tdev; /* Device to other host */
struct iphdr *iph; /* Our new IP header */
unsigned int max_headroom; /* The extra header space needed */
__be32 dst = tiph->daddr;
@@ -703,20 +737,20 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
.oif = tunnel->parms.link,
.proto = IPPROTO_IPV6 };
if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
- stats->tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
goto tx_error_icmp;
}
}
if (rt->rt_type != RTN_UNICAST) {
ip_rt_put(rt);
- stats->tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
goto tx_error_icmp;
}
tdev = rt->dst.dev;
if (tdev == dev) {
ip_rt_put(rt);
- stats->collisions++;
+ dev->stats.collisions++;
goto tx_error;
}
@@ -724,7 +758,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
if (mtu < 68) {
- stats->collisions++;
+ dev->stats.collisions++;
ip_rt_put(rt);
goto tx_error;
}
@@ -763,7 +797,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
if (!new_skb) {
ip_rt_put(rt);
- txq->tx_dropped++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -799,14 +833,14 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
iph->ttl = iph6->hop_limit;
nf_reset(skb);
-
- IPTUNNEL_XMIT();
+ tstats = this_cpu_ptr(dev->tstats);
+ __IPTUNNEL_XMIT(tstats, &dev->stats);
return NETDEV_TX_OK;
tx_error_icmp:
dst_link_failure(skb);
tx_error:
- stats->tx_errors++;
+ dev->stats.tx_errors++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -929,6 +963,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
}
t = netdev_priv(dev);
ipip6_tunnel_unlink(sitn, t);
+ synchronize_net();
t->parms.iph.saddr = p.iph.saddr;
t->parms.iph.daddr = p.iph.daddr;
memcpy(dev->dev_addr, &p.iph.saddr, 4);
@@ -1083,12 +1118,19 @@ static const struct net_device_ops ipip6_netdev_ops = {
.ndo_start_xmit = ipip6_tunnel_xmit,
.ndo_do_ioctl = ipip6_tunnel_ioctl,
.ndo_change_mtu = ipip6_tunnel_change_mtu,
+ .ndo_get_stats = ipip6_get_stats,
};
+static void ipip6_dev_free(struct net_device *dev)
+{
+ free_percpu(dev->tstats);
+ free_netdev(dev);
+}
+
static void ipip6_tunnel_setup(struct net_device *dev)
{
dev->netdev_ops = &ipip6_netdev_ops;
- dev->destructor = free_netdev;
+ dev->destructor = ipip6_dev_free;
dev->type = ARPHRD_SIT;
dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr);
@@ -1098,9 +1140,10 @@ static void ipip6_tunnel_setup(struct net_device *dev)
dev->iflink = 0;
dev->addr_len = 4;
dev->features |= NETIF_F_NETNS_LOCAL;
+ dev->features |= NETIF_F_LLTX;
}
-static void ipip6_tunnel_init(struct net_device *dev)
+static int ipip6_tunnel_init(struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
@@ -1111,9 +1154,14 @@ static void ipip6_tunnel_init(struct net_device *dev)
memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
ipip6_tunnel_bind_dev(dev);
+ dev->tstats = alloc_percpu(struct pcpu_tstats);
+ if (!dev->tstats)
+ return -ENOMEM;
+
+ return 0;
}
-static void __net_init ipip6_fb_tunnel_init(struct net_device *dev)
+static int __net_init ipip6_fb_tunnel_init(struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
struct iphdr *iph = &tunnel->parms.iph;
@@ -1128,11 +1176,15 @@ static void __net_init ipip6_fb_tunnel_init(struct net_device *dev)
iph->ihl = 5;
iph->ttl = 64;
+ dev->tstats = alloc_percpu(struct pcpu_tstats);
+ if (!dev->tstats)
+ return -ENOMEM;
dev_hold(dev);
sitn->tunnels_wc[0] = tunnel;
+ return 0;
}
-static struct xfrm_tunnel sit_handler = {
+static struct xfrm_tunnel sit_handler __read_mostly = {
.handler = ipip6_rcv,
.err_handler = ipip6_err,
.priority = 1,
@@ -1173,7 +1225,10 @@ static int __net_init sit_init_net(struct net *net)
}
dev_net_set(sitn->fb_tunnel_dev, net);
- ipip6_fb_tunnel_init(sitn->fb_tunnel_dev);
+ err = ipip6_fb_tunnel_init(sitn->fb_tunnel_dev);
+ if (err)
+ goto err_dev_free;
+
ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn);
if ((err = register_netdev(sitn->fb_tunnel_dev)))
@@ -1183,7 +1238,8 @@ static int __net_init sit_init_net(struct net *net)
err_reg_dev:
dev_put(sitn->fb_tunnel_dev);
- free_netdev(sitn->fb_tunnel_dev);
+err_dev_free:
+ ipip6_dev_free(sitn->fb_tunnel_dev);
err_alloc_dev:
return err;
}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index fe6d40418c0b..7e41e2cbb85e 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -139,7 +139,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
return -EINVAL;
if (usin->sin6_family != AF_INET6)
- return(-EAFNOSUPPORT);
+ return -EAFNOSUPPORT;
memset(&fl, 0, sizeof(fl));
@@ -1409,7 +1409,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newsk = tcp_create_openreq_child(sk, req, skb);
if (newsk == NULL)
- goto out;
+ goto out_nonewsk;
/*
* No need to charge this sock to the relevant IPv6 refcnt debug socks
@@ -1497,18 +1497,22 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
}
#endif
+ if (__inet_inherit_port(sk, newsk) < 0) {
+ sock_put(newsk);
+ goto out;
+ }
__inet6_hash(newsk, NULL);
- __inet_inherit_port(sk, newsk);
return newsk;
out_overflow:
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
-out:
- NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
+out_nonewsk:
if (opt && opt != np->opt)
sock_kfree_s(sk, opt, opt->tot_len);
dst_release(dst);
+out:
+ NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
return NULL;
}
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c
index fc3c86a47452..4f3cec12aa85 100644
--- a/net/ipv6/tunnel6.c
+++ b/net/ipv6/tunnel6.c
@@ -30,28 +30,31 @@
#include <net/protocol.h>
#include <net/xfrm.h>
-static struct xfrm6_tunnel *tunnel6_handlers;
-static struct xfrm6_tunnel *tunnel46_handlers;
+static struct xfrm6_tunnel __rcu *tunnel6_handlers __read_mostly;
+static struct xfrm6_tunnel __rcu *tunnel46_handlers __read_mostly;
static DEFINE_MUTEX(tunnel6_mutex);
int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family)
{
- struct xfrm6_tunnel **pprev;
+ struct xfrm6_tunnel __rcu **pprev;
+ struct xfrm6_tunnel *t;
int ret = -EEXIST;
int priority = handler->priority;
mutex_lock(&tunnel6_mutex);
for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers;
- *pprev; pprev = &(*pprev)->next) {
- if ((*pprev)->priority > priority)
+ (t = rcu_dereference_protected(*pprev,
+ lockdep_is_held(&tunnel6_mutex))) != NULL;
+ pprev = &t->next) {
+ if (t->priority > priority)
break;
- if ((*pprev)->priority == priority)
+ if (t->priority == priority)
goto err;
}
handler->next = *pprev;
- *pprev = handler;
+ rcu_assign_pointer(*pprev, handler);
ret = 0;
@@ -65,14 +68,17 @@ EXPORT_SYMBOL(xfrm6_tunnel_register);
int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family)
{
- struct xfrm6_tunnel **pprev;
+ struct xfrm6_tunnel __rcu **pprev;
+ struct xfrm6_tunnel *t;
int ret = -ENOENT;
mutex_lock(&tunnel6_mutex);
for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers;
- *pprev; pprev = &(*pprev)->next) {
- if (*pprev == handler) {
+ (t = rcu_dereference_protected(*pprev,
+ lockdep_is_held(&tunnel6_mutex))) != NULL;
+ pprev = &t->next) {
+ if (t == handler) {
*pprev = handler->next;
ret = 0;
break;
@@ -88,6 +94,11 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family)
EXPORT_SYMBOL(xfrm6_tunnel_deregister);
+#define for_each_tunnel_rcu(head, handler) \
+ for (handler = rcu_dereference(head); \
+ handler != NULL; \
+ handler = rcu_dereference(handler->next)) \
+
static int tunnel6_rcv(struct sk_buff *skb)
{
struct xfrm6_tunnel *handler;
@@ -95,7 +106,7 @@ static int tunnel6_rcv(struct sk_buff *skb)
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
goto drop;
- for (handler = tunnel6_handlers; handler; handler = handler->next)
+ for_each_tunnel_rcu(tunnel6_handlers, handler)
if (!handler->handler(skb))
return 0;
@@ -113,7 +124,7 @@ static int tunnel46_rcv(struct sk_buff *skb)
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
goto drop;
- for (handler = tunnel46_handlers; handler; handler = handler->next)
+ for_each_tunnel_rcu(tunnel46_handlers, handler)
if (!handler->handler(skb))
return 0;
@@ -129,7 +140,7 @@ static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
{
struct xfrm6_tunnel *handler;
- for (handler = tunnel6_handlers; handler; handler = handler->next)
+ for_each_tunnel_rcu(tunnel6_handlers, handler)
if (!handler->err_handler(skb, opt, type, code, offset, info))
break;
}
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 5acb3560ff15..91def93bec85 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -122,8 +122,8 @@ static void udp_v6_rehash(struct sock *sk)
static inline int compute_score(struct sock *sk, struct net *net,
unsigned short hnum,
- struct in6_addr *saddr, __be16 sport,
- struct in6_addr *daddr, __be16 dport,
+ const struct in6_addr *saddr, __be16 sport,
+ const struct in6_addr *daddr, __be16 dport,
int dif)
{
int score = -1;
@@ -239,8 +239,8 @@ exact_match:
}
static struct sock *__udp6_lib_lookup(struct net *net,
- struct in6_addr *saddr, __be16 sport,
- struct in6_addr *daddr, __be16 dport,
+ const struct in6_addr *saddr, __be16 sport,
+ const struct in6_addr *daddr, __be16 dport,
int dif, struct udp_table *udptable)
{
struct sock *sk, *result;
@@ -320,6 +320,14 @@ static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb,
udptable);
}
+struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be16 sport,
+ const struct in6_addr *daddr, __be16 dport, int dif)
+{
+ return __udp6_lib_lookup(net, saddr, sport, daddr, dport, dif, &udp_table);
+}
+EXPORT_SYMBOL_GPL(udp6_lib_lookup);
+
+
/*
* This should be easy, if there is something there we
* return it, otherwise we block.
@@ -519,7 +527,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
}
}
- if (sk->sk_filter) {
+ if (rcu_dereference_raw(sk->sk_filter)) {
if (udp_lib_checksum_complete(skb))
goto drop;
}
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 6baeabbbca82..7e74023ea6e4 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -199,7 +199,7 @@ static inline int xfrm6_garbage_collect(struct dst_ops *ops)
struct net *net = container_of(ops, struct net, xfrm.xfrm6_dst_ops);
xfrm6_policy_afinfo.garbage_collect(net);
- return (atomic_read(&ops->entries) > ops->gc_thresh * 2);
+ return dst_entries_get_fast(ops) > ops->gc_thresh * 2;
}
static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu)
@@ -255,7 +255,6 @@ static struct dst_ops xfrm6_dst_ops = {
.ifdown = xfrm6_dst_ifdown,
.local_out = __ip6_local_out,
.gc_thresh = 1024,
- .entries = ATOMIC_INIT(0),
};
static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
@@ -312,11 +311,13 @@ int __init xfrm6_init(void)
*/
gc_thresh = FIB6_TABLE_HASHSZ * 8;
xfrm6_dst_ops.gc_thresh = (gc_thresh < 1024) ? 1024 : gc_thresh;
+ dst_entries_init(&xfrm6_dst_ops);
ret = xfrm6_policy_init();
- if (ret)
+ if (ret) {
+ dst_entries_destroy(&xfrm6_dst_ops);
goto out;
-
+ }
ret = xfrm6_state_init();
if (ret)
goto out_policy;
@@ -341,4 +342,5 @@ void xfrm6_fini(void)
//xfrm6_input_fini();
xfrm6_policy_fini();
xfrm6_state_fini();
+ dst_entries_destroy(&xfrm6_dst_ops);
}
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 2ce3a8278f26..2969cad408de 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -199,7 +199,7 @@ static void x6spi_destroy_rcu(struct rcu_head *head)
container_of(head, struct xfrm6_tunnel_spi, rcu_head));
}
-void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr)
+static void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr)
{
struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
struct xfrm6_tunnel_spi *x6spi;
@@ -223,8 +223,6 @@ void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr)
spin_unlock_bh(&xfrm6_tunnel_spi_lock);
}
-EXPORT_SYMBOL(xfrm6_tunnel_free_spi);
-
static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
{
skb_push(skb, -skb_network_offset(skb));
@@ -317,13 +315,13 @@ static const struct xfrm_type xfrm6_tunnel_type = {
.output = xfrm6_tunnel_output,
};
-static struct xfrm6_tunnel xfrm6_tunnel_handler = {
+static struct xfrm6_tunnel xfrm6_tunnel_handler __read_mostly = {
.handler = xfrm6_tunnel_rcv,
.err_handler = xfrm6_tunnel_err,
.priority = 2,
};
-static struct xfrm6_tunnel xfrm46_tunnel_handler = {
+static struct xfrm6_tunnel xfrm46_tunnel_handler __read_mostly = {
.handler = xfrm6_tunnel_rcv,
.err_handler = xfrm6_tunnel_err,
.priority = 2,
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index fd55b5135de5..7f097989cde2 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -573,9 +573,9 @@ static int irda_find_lsap_sel(struct irda_sock *self, char *name)
/* Requested object/attribute doesn't exist */
if((self->errno == IAS_CLASS_UNKNOWN) ||
(self->errno == IAS_ATTRIB_UNKNOWN))
- return (-EADDRNOTAVAIL);
+ return -EADDRNOTAVAIL;
else
- return (-EHOSTUNREACH);
+ return -EHOSTUNREACH;
}
/* Get the remote TSAP selector */
@@ -663,7 +663,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
__func__, name);
self->daddr = DEV_ADDR_ANY;
kfree(discoveries);
- return(-ENOTUNIQ);
+ return -ENOTUNIQ;
}
/* First time we found that one, save it ! */
daddr = self->daddr;
@@ -677,7 +677,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
IRDA_DEBUG(0, "%s(), unexpected IAS query failure\n", __func__);
self->daddr = DEV_ADDR_ANY;
kfree(discoveries);
- return(-EHOSTUNREACH);
+ return -EHOSTUNREACH;
break;
}
}
@@ -689,7 +689,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
IRDA_DEBUG(1, "%s(), cannot discover service ''%s'' in any device !!!\n",
__func__, name);
self->daddr = DEV_ADDR_ANY;
- return(-EADDRNOTAVAIL);
+ return -EADDRNOTAVAIL;
}
/* Revert back to discovered device & service */
@@ -715,14 +715,11 @@ static int irda_getname(struct socket *sock, struct sockaddr *uaddr,
struct sockaddr_irda saddr;
struct sock *sk = sock->sk;
struct irda_sock *self = irda_sk(sk);
- int err;
- lock_kernel();
memset(&saddr, 0, sizeof(saddr));
if (peer) {
- err = -ENOTCONN;
if (sk->sk_state != TCP_ESTABLISHED)
- goto out;
+ return -ENOTCONN;
saddr.sir_family = AF_IRDA;
saddr.sir_lsap_sel = self->dtsap_sel;
@@ -739,10 +736,8 @@ static int irda_getname(struct socket *sock, struct sockaddr *uaddr,
/* uaddr_len come to us uninitialised */
*uaddr_len = sizeof (struct sockaddr_irda);
memcpy(uaddr, &saddr, *uaddr_len);
- err = 0;
-out:
- unlock_kernel();
- return err;
+
+ return 0;
}
/*
@@ -758,7 +753,8 @@ static int irda_listen(struct socket *sock, int backlog)
IRDA_DEBUG(2, "%s()\n", __func__);
- lock_kernel();
+ lock_sock(sk);
+
if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) &&
(sk->sk_type != SOCK_DGRAM))
goto out;
@@ -770,7 +766,7 @@ static int irda_listen(struct socket *sock, int backlog)
err = 0;
}
out:
- unlock_kernel();
+ release_sock(sk);
return err;
}
@@ -793,7 +789,7 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
if (addr_len != sizeof(struct sockaddr_irda))
return -EINVAL;
- lock_kernel();
+ lock_sock(sk);
#ifdef CONFIG_IRDA_ULTRA
/* Special care for Ultra sockets */
if ((sk->sk_type == SOCK_DGRAM) &&
@@ -836,7 +832,7 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
err = 0;
out:
- unlock_kernel();
+ release_sock(sk);
return err;
}
@@ -856,12 +852,13 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
IRDA_DEBUG(2, "%s()\n", __func__);
- lock_kernel();
err = irda_create(sock_net(sk), newsock, sk->sk_protocol, 0);
if (err)
- goto out;
+ return err;
err = -EINVAL;
+
+ lock_sock(sk);
if (sock->state != SS_UNCONNECTED)
goto out;
@@ -947,7 +944,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
irda_connect_response(new);
err = 0;
out:
- unlock_kernel();
+ release_sock(sk);
return err;
}
@@ -981,7 +978,7 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
- lock_kernel();
+ lock_sock(sk);
/* Don't allow connect for Ultra sockets */
err = -ESOCKTNOSUPPORT;
if ((sk->sk_type == SOCK_DGRAM) && (sk->sk_protocol == IRDAPROTO_ULTRA))
@@ -1072,6 +1069,8 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
if (sk->sk_state != TCP_ESTABLISHED) {
sock->state = SS_UNCONNECTED;
+ if (sk->sk_prot->disconnect(sk, flags))
+ sock->state = SS_DISCONNECTING;
err = sock_error(sk);
if (!err)
err = -ECONNRESET;
@@ -1084,7 +1083,7 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
self->saddr = irttp_get_saddr(self->tsap);
err = 0;
out:
- unlock_kernel();
+ release_sock(sk);
return err;
}
@@ -1231,7 +1230,6 @@ static int irda_release(struct socket *sock)
if (sk == NULL)
return 0;
- lock_kernel();
lock_sock(sk);
sk->sk_state = TCP_CLOSE;
sk->sk_shutdown |= SEND_SHUTDOWN;
@@ -1250,7 +1248,6 @@ static int irda_release(struct socket *sock)
/* Destroy networking socket if we are the last reference on it,
* i.e. if(sk->sk_refcnt == 0) -> sk_free(sk) */
sock_put(sk);
- unlock_kernel();
/* Notes on socket locking and deallocation... - Jean II
* In theory we should put pairs of sock_hold() / sock_put() to
@@ -1298,7 +1295,6 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len);
- lock_kernel();
/* Note : socket.c set MSG_EOR on SEQPACKET sockets */
if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT |
MSG_NOSIGNAL)) {
@@ -1306,6 +1302,8 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock,
goto out;
}
+ lock_sock(sk);
+
if (sk->sk_shutdown & SEND_SHUTDOWN)
goto out_err;
@@ -1361,14 +1359,14 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock,
goto out_err;
}
- unlock_kernel();
+ release_sock(sk);
/* Tell client how much data we actually sent */
return len;
out_err:
err = sk_stream_error(sk, msg->msg_flags, err);
out:
- unlock_kernel();
+ release_sock(sk);
return err;
}
@@ -1390,14 +1388,10 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG(4, "%s()\n", __func__);
- lock_kernel();
- if ((err = sock_error(sk)) < 0)
- goto out;
-
skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
flags & MSG_DONTWAIT, &err);
if (!skb)
- goto out;
+ return err;
skb_reset_transport_header(skb);
copied = skb->len;
@@ -1425,12 +1419,8 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
irttp_flow_request(self->tsap, FLOW_START);
}
}
- unlock_kernel();
- return copied;
-out:
- unlock_kernel();
- return err;
+ return copied;
}
/*
@@ -1448,17 +1438,15 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG(3, "%s()\n", __func__);
- lock_kernel();
if ((err = sock_error(sk)) < 0)
- goto out;
+ return err;
- err = -EINVAL;
if (sock->flags & __SO_ACCEPTCON)
- goto out;
+ return -EINVAL;
err =-EOPNOTSUPP;
if (flags & MSG_OOB)
- goto out;
+ return -EOPNOTSUPP;
err = 0;
target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
@@ -1500,7 +1488,7 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
finish_wait(sk_sleep(sk), &wait);
if (err)
- goto out;
+ return err;
if (sk->sk_shutdown & RCV_SHUTDOWN)
break;
@@ -1553,9 +1541,7 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
}
}
-out:
- unlock_kernel();
- return err ? : copied;
+ return copied;
}
/*
@@ -1573,13 +1559,12 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock,
struct sk_buff *skb;
int err;
- lock_kernel();
-
IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len);
- err = -EINVAL;
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
- goto out;
+ return -EINVAL;
+
+ lock_sock(sk);
if (sk->sk_shutdown & SEND_SHUTDOWN) {
send_sig(SIGPIPE, current, 0);
@@ -1630,10 +1615,12 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err);
goto out;
}
- unlock_kernel();
+
+ release_sock(sk);
return len;
+
out:
- unlock_kernel();
+ release_sock(sk);
return err;
}
@@ -1656,10 +1643,11 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len);
- lock_kernel();
err = -EINVAL;
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
- goto out;
+ return -EINVAL;
+
+ lock_sock(sk);
err = -EPIPE;
if (sk->sk_shutdown & SEND_SHUTDOWN) {
@@ -1732,7 +1720,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock,
if (err)
IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err);
out:
- unlock_kernel();
+ release_sock(sk);
return err ? : len;
}
#endif /* CONFIG_IRDA_ULTRA */
@@ -1747,7 +1735,7 @@ static int irda_shutdown(struct socket *sock, int how)
IRDA_DEBUG(1, "%s(%p)\n", __func__, self);
- lock_kernel();
+ lock_sock(sk);
sk->sk_state = TCP_CLOSE;
sk->sk_shutdown |= SEND_SHUTDOWN;
@@ -1769,7 +1757,7 @@ static int irda_shutdown(struct socket *sock, int how)
self->daddr = DEV_ADDR_ANY; /* Until we get re-connected */
self->saddr = 0x0; /* so IrLMP assign us any link */
- unlock_kernel();
+ release_sock(sk);
return 0;
}
@@ -1786,7 +1774,6 @@ static unsigned int irda_poll(struct file * file, struct socket *sock,
IRDA_DEBUG(4, "%s()\n", __func__);
- lock_kernel();
poll_wait(file, sk_sleep(sk), wait);
mask = 0;
@@ -1834,20 +1821,8 @@ static unsigned int irda_poll(struct file * file, struct socket *sock,
default:
break;
}
- unlock_kernel();
- return mask;
-}
-static unsigned int irda_datagram_poll(struct file *file, struct socket *sock,
- poll_table *wait)
-{
- int err;
-
- lock_kernel();
- err = datagram_poll(file, sock, wait);
- unlock_kernel();
-
- return err;
+ return mask;
}
/*
@@ -1860,7 +1835,6 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
IRDA_DEBUG(4, "%s(), cmd=%#x\n", __func__, cmd);
- lock_kernel();
err = -EINVAL;
switch (cmd) {
case TIOCOUTQ: {
@@ -1903,7 +1877,6 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
IRDA_DEBUG(1, "%s(), doing device ioctl!\n", __func__);
err = -ENOIOCTLCMD;
}
- unlock_kernel();
return err;
}
@@ -1927,7 +1900,7 @@ static int irda_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned lon
* Set some options for the socket
*
*/
-static int __irda_setsockopt(struct socket *sock, int level, int optname,
+static int irda_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
@@ -1935,13 +1908,15 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
struct irda_ias_set *ias_opt;
struct ias_object *ias_obj;
struct ias_attrib * ias_attr; /* Attribute in IAS object */
- int opt, free_ias = 0;
+ int opt, free_ias = 0, err = 0;
IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
if (level != SOL_IRLMP)
return -ENOPROTOOPT;
+ lock_sock(sk);
+
switch (optname) {
case IRLMP_IAS_SET:
/* The user want to add an attribute to an existing IAS object
@@ -1951,17 +1926,22 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
* create the right attribute...
*/
- if (optlen != sizeof(struct irda_ias_set))
- return -EINVAL;
+ if (optlen != sizeof(struct irda_ias_set)) {
+ err = -EINVAL;
+ goto out;
+ }
ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
- if (ias_opt == NULL)
- return -ENOMEM;
+ if (ias_opt == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
/* Copy query to the driver. */
if (copy_from_user(ias_opt, optval, optlen)) {
kfree(ias_opt);
- return -EFAULT;
+ err = -EFAULT;
+ goto out;
}
/* Find the object we target.
@@ -1971,7 +1951,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
if(ias_opt->irda_class_name[0] == '\0') {
if(self->ias_obj == NULL) {
kfree(ias_opt);
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
ias_obj = self->ias_obj;
} else
@@ -1983,7 +1964,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
if((!capable(CAP_NET_ADMIN)) &&
((ias_obj == NULL) || (ias_obj != self->ias_obj))) {
kfree(ias_opt);
- return -EPERM;
+ err = -EPERM;
+ goto out;
}
/* If the object doesn't exist, create it */
@@ -1993,7 +1975,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
jiffies);
if (ias_obj == NULL) {
kfree(ias_opt);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto out;
}
free_ias = 1;
}
@@ -2005,7 +1988,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
kfree(ias_obj->name);
kfree(ias_obj);
}
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
/* Look at the type */
@@ -2028,7 +2012,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
kfree(ias_obj);
}
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
/* Add an octet sequence attribute */
irias_add_octseq_attrib(
@@ -2060,7 +2045,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
kfree(ias_obj->name);
kfree(ias_obj);
}
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
irias_insert_object(ias_obj);
kfree(ias_opt);
@@ -2071,17 +2057,22 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
* object is not owned by the kernel and delete it.
*/
- if (optlen != sizeof(struct irda_ias_set))
- return -EINVAL;
+ if (optlen != sizeof(struct irda_ias_set)) {
+ err = -EINVAL;
+ goto out;
+ }
ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
- if (ias_opt == NULL)
- return -ENOMEM;
+ if (ias_opt == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
/* Copy query to the driver. */
if (copy_from_user(ias_opt, optval, optlen)) {
kfree(ias_opt);
- return -EFAULT;
+ err = -EFAULT;
+ goto out;
}
/* Find the object we target.
@@ -2094,7 +2085,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
ias_obj = irias_find_object(ias_opt->irda_class_name);
if(ias_obj == (struct ias_object *) NULL) {
kfree(ias_opt);
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
/* Only ROOT can mess with the global IAS database.
@@ -2103,7 +2095,8 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
if((!capable(CAP_NET_ADMIN)) &&
((ias_obj == NULL) || (ias_obj != self->ias_obj))) {
kfree(ias_opt);
- return -EPERM;
+ err = -EPERM;
+ goto out;
}
/* Find the attribute (in the object) we target */
@@ -2111,14 +2104,16 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
ias_opt->irda_attrib_name);
if(ias_attr == (struct ias_attrib *) NULL) {
kfree(ias_opt);
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
/* Check is the user space own the object */
if(ias_attr->value->owner != IAS_USER_ATTR) {
IRDA_DEBUG(1, "%s(), attempting to delete a kernel attribute\n", __func__);
kfree(ias_opt);
- return -EPERM;
+ err = -EPERM;
+ goto out;
}
/* Remove the attribute (and maybe the object) */
@@ -2126,11 +2121,15 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
kfree(ias_opt);
break;
case IRLMP_MAX_SDU_SIZE:
- if (optlen < sizeof(int))
- return -EINVAL;
+ if (optlen < sizeof(int)) {
+ err = -EINVAL;
+ goto out;
+ }
- if (get_user(opt, (int __user *)optval))
- return -EFAULT;
+ if (get_user(opt, (int __user *)optval)) {
+ err = -EFAULT;
+ goto out;
+ }
/* Only possible for a seqpacket service (TTP with SAR) */
if (sk->sk_type != SOCK_SEQPACKET) {
@@ -2140,16 +2139,21 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
} else {
IRDA_WARNING("%s: not allowed to set MAXSDUSIZE for this socket type!\n",
__func__);
- return -ENOPROTOOPT;
+ err = -ENOPROTOOPT;
+ goto out;
}
break;
case IRLMP_HINTS_SET:
- if (optlen < sizeof(int))
- return -EINVAL;
+ if (optlen < sizeof(int)) {
+ err = -EINVAL;
+ goto out;
+ }
/* The input is really a (__u8 hints[2]), easier as an int */
- if (get_user(opt, (int __user *)optval))
- return -EFAULT;
+ if (get_user(opt, (int __user *)optval)) {
+ err = -EFAULT;
+ goto out;
+ }
/* Unregister any old registration */
if (self->skey)
@@ -2163,12 +2167,16 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
* making a discovery (nodes which don't match any hint
* bit in the mask are not reported).
*/
- if (optlen < sizeof(int))
- return -EINVAL;
+ if (optlen < sizeof(int)) {
+ err = -EINVAL;
+ goto out;
+ }
/* The input is really a (__u8 hints[2]), easier as an int */
- if (get_user(opt, (int __user *)optval))
- return -EFAULT;
+ if (get_user(opt, (int __user *)optval)) {
+ err = -EFAULT;
+ goto out;
+ }
/* Set the new hint mask */
self->mask.word = (__u16) opt;
@@ -2180,19 +2188,12 @@ static int __irda_setsockopt(struct socket *sock, int level, int optname,
break;
default:
- return -ENOPROTOOPT;
+ err = -ENOPROTOOPT;
+ break;
}
- return 0;
-}
-static int irda_setsockopt(struct socket *sock, int level, int optname,
- char __user *optval, unsigned int optlen)
-{
- int err;
-
- lock_kernel();
- err = __irda_setsockopt(sock, level, optname, optval, optlen);
- unlock_kernel();
+out:
+ release_sock(sk);
return err;
}
@@ -2249,7 +2250,7 @@ static int irda_extract_ias_value(struct irda_ias_set *ias_opt,
/*
* Function irda_getsockopt (sock, level, optname, optval, optlen)
*/
-static int __irda_getsockopt(struct socket *sock, int level, int optname,
+static int irda_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
@@ -2262,7 +2263,7 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
int daddr = DEV_ADDR_ANY; /* Dest address for IAS queries */
int val = 0;
int len = 0;
- int err;
+ int err = 0;
int offset, total;
IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
@@ -2276,15 +2277,18 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
if(len < 0)
return -EINVAL;
+ lock_sock(sk);
+
switch (optname) {
case IRLMP_ENUMDEVICES:
/* Ask lmp for the current discovery log */
discoveries = irlmp_get_discoveries(&list.len, self->mask.word,
self->nslots);
/* Check if the we got some results */
- if (discoveries == NULL)
- return -EAGAIN; /* Didn't find any devices */
- err = 0;
+ if (discoveries == NULL) {
+ err = -EAGAIN;
+ goto out; /* Didn't find any devices */
+ }
/* Write total list length back to client */
if (copy_to_user(optval, &list,
@@ -2297,8 +2301,7 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
sizeof(struct irda_device_info);
/* Copy the list itself - watch for overflow */
- if(list.len > 2048)
- {
+ if (list.len > 2048) {
err = -EINVAL;
goto bed;
}
@@ -2314,17 +2317,20 @@ static int __irda_getsockopt(struct socket *sock, int level, int optname,
bed:
/* Free up our buffer */
kfree(discoveries);
- if (err)
- return err;
break;
case IRLMP_MAX_SDU_SIZE:
val = self->max_data_size;
len = sizeof(int);
- if (put_user(len, optlen))
- return -EFAULT;
+ if (put_user(len, optlen)) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ if (copy_to_user(optval, &val, len)) {
+ err = -EFAULT;
+ goto out;
+ }
- if (copy_to_user(optval, &val, len))
- return -EFAULT;
break;
case IRLMP_IAS_GET:
/* The user want an object from our local IAS database.
@@ -2332,17 +2338,22 @@ bed:
* that we found */
/* Check that the user has allocated the right space for us */
- if (len != sizeof(struct irda_ias_set))
- return -EINVAL;
+ if (len != sizeof(struct irda_ias_set)) {
+ err = -EINVAL;
+ goto out;
+ }
ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
- if (ias_opt == NULL)
- return -ENOMEM;
+ if (ias_opt == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
/* Copy query to the driver. */
if (copy_from_user(ias_opt, optval, len)) {
kfree(ias_opt);
- return -EFAULT;
+ err = -EFAULT;
+ goto out;
}
/* Find the object we target.
@@ -2355,7 +2366,8 @@ bed:
ias_obj = irias_find_object(ias_opt->irda_class_name);
if(ias_obj == (struct ias_object *) NULL) {
kfree(ias_opt);
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
/* Find the attribute (in the object) we target */
@@ -2363,21 +2375,23 @@ bed:
ias_opt->irda_attrib_name);
if(ias_attr == (struct ias_attrib *) NULL) {
kfree(ias_opt);
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
/* Translate from internal to user structure */
err = irda_extract_ias_value(ias_opt, ias_attr->value);
if(err) {
kfree(ias_opt);
- return err;
+ goto out;
}
/* Copy reply to the user */
if (copy_to_user(optval, ias_opt,
sizeof(struct irda_ias_set))) {
kfree(ias_opt);
- return -EFAULT;
+ err = -EFAULT;
+ goto out;
}
/* Note : don't need to put optlen, we checked it */
kfree(ias_opt);
@@ -2388,17 +2402,22 @@ bed:
* then wait for the answer to come back. */
/* Check that the user has allocated the right space for us */
- if (len != sizeof(struct irda_ias_set))
- return -EINVAL;
+ if (len != sizeof(struct irda_ias_set)) {
+ err = -EINVAL;
+ goto out;
+ }
ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
- if (ias_opt == NULL)
- return -ENOMEM;
+ if (ias_opt == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
/* Copy query to the driver. */
if (copy_from_user(ias_opt, optval, len)) {
kfree(ias_opt);
- return -EFAULT;
+ err = -EFAULT;
+ goto out;
}
/* At this point, there are two cases...
@@ -2419,7 +2438,8 @@ bed:
daddr = ias_opt->daddr;
if((!daddr) || (daddr == DEV_ADDR_ANY)) {
kfree(ias_opt);
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
}
@@ -2428,7 +2448,8 @@ bed:
IRDA_WARNING("%s: busy with a previous query\n",
__func__);
kfree(ias_opt);
- return -EBUSY;
+ err = -EBUSY;
+ goto out;
}
self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
@@ -2436,7 +2457,8 @@ bed:
if (self->iriap == NULL) {
kfree(ias_opt);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto out;
}
/* Treat unexpected wakeup as disconnect */
@@ -2455,7 +2477,8 @@ bed:
* we can free it regardless! */
kfree(ias_opt);
/* Treat signals as disconnect */
- return -EHOSTUNREACH;
+ err = -EHOSTUNREACH;
+ goto out;
}
/* Check what happened */
@@ -2465,9 +2488,11 @@ bed:
/* Requested object/attribute doesn't exist */
if((self->errno == IAS_CLASS_UNKNOWN) ||
(self->errno == IAS_ATTRIB_UNKNOWN))
- return (-EADDRNOTAVAIL);
+ err = -EADDRNOTAVAIL;
else
- return (-EHOSTUNREACH);
+ err = -EHOSTUNREACH;
+
+ goto out;
}
/* Translate from internal to user structure */
@@ -2476,14 +2501,15 @@ bed:
irias_delete_value(self->ias_result);
if (err) {
kfree(ias_opt);
- return err;
+ goto out;
}
/* Copy reply to the user */
if (copy_to_user(optval, ias_opt,
sizeof(struct irda_ias_set))) {
kfree(ias_opt);
- return -EFAULT;
+ err = -EFAULT;
+ goto out;
}
/* Note : don't need to put optlen, we checked it */
kfree(ias_opt);
@@ -2504,11 +2530,15 @@ bed:
*/
/* Check that the user is passing us an int */
- if (len != sizeof(int))
- return -EINVAL;
+ if (len != sizeof(int)) {
+ err = -EINVAL;
+ goto out;
+ }
/* Get timeout in ms (max time we block the caller) */
- if (get_user(val, (int __user *)optval))
- return -EFAULT;
+ if (get_user(val, (int __user *)optval)) {
+ err = -EFAULT;
+ goto out;
+ }
/* Tell IrLMP we want to be notified */
irlmp_update_client(self->ckey, self->mask.word,
@@ -2520,8 +2550,6 @@ bed:
/* Wait until a node is discovered */
if (!self->cachedaddr) {
- int ret = 0;
-
IRDA_DEBUG(1, "%s(), nothing discovered yet, going to sleep...\n", __func__);
/* Set watchdog timer to expire in <val> ms. */
@@ -2534,7 +2562,7 @@ bed:
/* Wait for IR-LMP to call us back */
__wait_event_interruptible(self->query_wait,
(self->cachedaddr != 0 || self->errno == -ETIME),
- ret);
+ err);
/* If watchdog is still activated, kill it! */
if(timer_pending(&(self->watchdog)))
@@ -2542,8 +2570,8 @@ bed:
IRDA_DEBUG(1, "%s(), ...waking up !\n", __func__);
- if (ret != 0)
- return ret;
+ if (err != 0)
+ goto out;
}
else
IRDA_DEBUG(1, "%s(), found immediately !\n",
@@ -2566,25 +2594,19 @@ bed:
* If the user want more details, he should query
* the whole discovery log and pick one device...
*/
- if (put_user(daddr, (int __user *)optval))
- return -EFAULT;
+ if (put_user(daddr, (int __user *)optval)) {
+ err = -EFAULT;
+ goto out;
+ }
break;
default:
- return -ENOPROTOOPT;
+ err = -ENOPROTOOPT;
}
- return 0;
-}
-
-static int irda_getsockopt(struct socket *sock, int level, int optname,
- char __user *optval, int __user *optlen)
-{
- int err;
+out:
- lock_kernel();
- err = __irda_getsockopt(sock, level, optname, optval, optlen);
- unlock_kernel();
+ release_sock(sk);
return err;
}
@@ -2628,7 +2650,7 @@ static const struct proto_ops irda_seqpacket_ops = {
.socketpair = sock_no_socketpair,
.accept = irda_accept,
.getname = irda_getname,
- .poll = irda_datagram_poll,
+ .poll = datagram_poll,
.ioctl = irda_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = irda_compat_ioctl,
@@ -2652,7 +2674,7 @@ static const struct proto_ops irda_dgram_ops = {
.socketpair = sock_no_socketpair,
.accept = irda_accept,
.getname = irda_getname,
- .poll = irda_datagram_poll,
+ .poll = datagram_poll,
.ioctl = irda_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = irda_compat_ioctl,
@@ -2677,7 +2699,7 @@ static const struct proto_ops irda_ultra_ops = {
.socketpair = sock_no_socketpair,
.accept = sock_no_accept,
.getname = irda_getname,
- .poll = irda_datagram_poll,
+ .poll = datagram_poll,
.ioctl = irda_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = irda_compat_ioctl,
diff --git a/net/irda/discovery.c b/net/irda/discovery.c
index c1c8ae939126..36c3f037f172 100644
--- a/net/irda/discovery.c
+++ b/net/irda/discovery.c
@@ -315,7 +315,7 @@ struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn,
/* Get the actual number of device in the buffer and return */
*pn = i;
- return(buffer);
+ return buffer;
}
#ifdef CONFIG_PROC_FS
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index faa82ca2dfdc..a39cca8331df 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -449,8 +449,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
}
#ifdef SERIAL_DO_RESTART
- return ((self->flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
+ return (self->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS;
#else
return -EAGAIN;
#endif
diff --git a/net/irda/iriap.c b/net/irda/iriap.c
index fce364c6c71a..5b743bdd89ba 100644
--- a/net/irda/iriap.c
+++ b/net/irda/iriap.c
@@ -502,7 +502,8 @@ static void iriap_getvaluebyclass_confirm(struct iriap_cb *self,
IRDA_DEBUG(4, "%s(), strlen=%d\n", __func__, value_len);
/* Make sure the string is null-terminated */
- fp[n+value_len] = 0x00;
+ if (n + value_len < skb->len)
+ fp[n + value_len] = 0x00;
IRDA_DEBUG(4, "Got string %s\n", fp+n);
/* Will truncate to IAS_MAX_STRING bytes */
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c
index 5bb8353105cc..8ee1ff6c742f 100644
--- a/net/irda/irlan/irlan_eth.c
+++ b/net/irda/irlan/irlan_eth.c
@@ -45,13 +45,11 @@ static int irlan_eth_close(struct net_device *dev);
static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb,
struct net_device *dev);
static void irlan_eth_set_multicast_list( struct net_device *dev);
-static struct net_device_stats *irlan_eth_get_stats(struct net_device *dev);
static const struct net_device_ops irlan_eth_netdev_ops = {
.ndo_open = irlan_eth_open,
.ndo_stop = irlan_eth_close,
.ndo_start_xmit = irlan_eth_xmit,
- .ndo_get_stats = irlan_eth_get_stats,
.ndo_set_multicast_list = irlan_eth_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
@@ -208,10 +206,10 @@ static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb,
* tried :-) DB
*/
/* irttp_data_request already free the packet */
- self->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
} else {
- self->stats.tx_packets++;
- self->stats.tx_bytes += len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += len;
}
return NETDEV_TX_OK;
@@ -226,15 +224,16 @@ static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb,
int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb)
{
struct irlan_cb *self = instance;
+ struct net_device *dev = self->dev;
if (skb == NULL) {
- ++self->stats.rx_dropped;
+ dev->stats.rx_dropped++;
return 0;
}
if (skb->len < ETH_HLEN) {
IRDA_DEBUG(0, "%s() : IrLAN frame too short (%d)\n",
__func__, skb->len);
- ++self->stats.rx_dropped;
+ dev->stats.rx_dropped++;
dev_kfree_skb(skb);
return 0;
}
@@ -244,10 +243,10 @@ int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb)
* might have been previously set by the low level IrDA network
* device driver
*/
- skb->protocol = eth_type_trans(skb, self->dev); /* Remove eth header */
+ skb->protocol = eth_type_trans(skb, dev); /* Remove eth header */
- self->stats.rx_packets++;
- self->stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
netif_rx(skb); /* Eat it! */
@@ -348,16 +347,3 @@ static void irlan_eth_set_multicast_list(struct net_device *dev)
else
irlan_set_broadcast_filter(self, FALSE);
}
-
-/*
- * Function irlan_get_stats (dev)
- *
- * Get the current statistics for this device
- *
- */
-static struct net_device_stats *irlan_eth_get_stats(struct net_device *dev)
-{
- struct irlan_cb *self = netdev_priv(dev);
-
- return &self->stats;
-}
diff --git a/net/irda/irlan/irlan_event.c b/net/irda/irlan/irlan_event.c
index cbcb4eb54037..43f16040a6fe 100644
--- a/net/irda/irlan/irlan_event.c
+++ b/net/irda/irlan/irlan_event.c
@@ -24,7 +24,7 @@
#include <net/irda/irlan_event.h>
-char *irlan_state[] = {
+const char * const irlan_state[] = {
"IRLAN_IDLE",
"IRLAN_QUERY",
"IRLAN_CONN",
diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c
index 0e7d8bde145d..6115a44c0a24 100644
--- a/net/irda/irlmp.c
+++ b/net/irda/irlmp.c
@@ -939,7 +939,7 @@ struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask, int nslots)
}
/* Return current cached discovery log */
- return(irlmp_copy_discoveries(irlmp->cachelog, pn, mask, TRUE));
+ return irlmp_copy_discoveries(irlmp->cachelog, pn, mask, TRUE);
}
EXPORT_SYMBOL(irlmp_get_discoveries);
diff --git a/net/irda/irlmp_frame.c b/net/irda/irlmp_frame.c
index 3750884094da..062e63b1c5c4 100644
--- a/net/irda/irlmp_frame.c
+++ b/net/irda/irlmp_frame.c
@@ -448,7 +448,7 @@ static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap_sel,
(self->cache.slsap_sel == slsap_sel) &&
(self->cache.dlsap_sel == dlsap_sel))
{
- return (self->cache.lsap);
+ return self->cache.lsap;
}
#endif
diff --git a/net/irda/irnet/irnet.h b/net/irda/irnet/irnet.h
index 4300df35d37d..0d82ff5aeff1 100644
--- a/net/irda/irnet/irnet.h
+++ b/net/irda/irnet/irnet.h
@@ -458,6 +458,8 @@ typedef struct irnet_socket
int disco_index; /* Last read in the discovery log */
int disco_number; /* Size of the discovery log */
+ struct mutex lock;
+
} irnet_socket;
/*
diff --git a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c
index e98e40d76f4f..7f17a8020e8a 100644
--- a/net/irda/irnet/irnet_irda.c
+++ b/net/irda/irnet/irnet_irda.c
@@ -238,7 +238,7 @@ irnet_ias_to_tsap(irnet_socket * self,
DEXIT(IRDA_SR_TRACE, "\n");
/* Return the TSAP */
- return(dtsap_sel);
+ return dtsap_sel;
}
/*------------------------------------------------------------------*/
@@ -301,7 +301,7 @@ irnet_connect_tsap(irnet_socket * self)
{
clear_bit(0, &self->ttp_connect);
DERROR(IRDA_SR_ERROR, "connect aborted!\n");
- return(err);
+ return err;
}
/* Connect to remote device */
@@ -312,7 +312,7 @@ irnet_connect_tsap(irnet_socket * self)
{
clear_bit(0, &self->ttp_connect);
DERROR(IRDA_SR_ERROR, "connect aborted!\n");
- return(err);
+ return err;
}
/* The above call is non-blocking.
@@ -321,7 +321,7 @@ irnet_connect_tsap(irnet_socket * self)
* See you there ;-) */
DEXIT(IRDA_SR_TRACE, "\n");
- return(err);
+ return err;
}
/*------------------------------------------------------------------*/
@@ -362,10 +362,10 @@ irnet_discover_next_daddr(irnet_socket * self)
/* The above request is non-blocking.
* After a while, IrDA will call us back in irnet_discovervalue_confirm()
* We will then call irnet_ias_to_tsap() and come back here again... */
- return(0);
+ return 0;
}
else
- return(1);
+ return 1;
}
/*------------------------------------------------------------------*/
@@ -436,7 +436,7 @@ irnet_discover_daddr_and_lsap_sel(irnet_socket * self)
/* Follow me in irnet_discovervalue_confirm() */
DEXIT(IRDA_SR_TRACE, "\n");
- return(0);
+ return 0;
}
/*------------------------------------------------------------------*/
@@ -485,7 +485,7 @@ irnet_dname_to_daddr(irnet_socket * self)
/* No luck ! */
DEBUG(IRDA_SR_INFO, "cannot discover device ``%s'' !!!\n", self->rname);
kfree(discoveries);
- return(-EADDRNOTAVAIL);
+ return -EADDRNOTAVAIL;
}
@@ -527,7 +527,7 @@ irda_irnet_create(irnet_socket * self)
INIT_WORK(&self->disconnect_work, irnet_ppp_disconnect);
DEXIT(IRDA_SOCK_TRACE, "\n");
- return(0);
+ return 0;
}
/*------------------------------------------------------------------*/
@@ -601,7 +601,7 @@ irda_irnet_connect(irnet_socket * self)
* We will finish the connection procedure in irnet_connect_tsap().
*/
DEXIT(IRDA_SOCK_TRACE, "\n");
- return(0);
+ return 0;
}
/*------------------------------------------------------------------*/
@@ -733,7 +733,7 @@ irnet_daddr_to_dname(irnet_socket * self)
/* No luck ! */
DEXIT(IRDA_SERV_INFO, ": cannot discover device 0x%08x !!!\n", self->daddr);
kfree(discoveries);
- return(-EADDRNOTAVAIL);
+ return -EADDRNOTAVAIL;
}
/*------------------------------------------------------------------*/
diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c
index dfe7b38dd4af..7fa86373de41 100644
--- a/net/irda/irnet/irnet_ppp.c
+++ b/net/irda/irnet/irnet_ppp.c
@@ -166,7 +166,7 @@ irnet_ctrl_write(irnet_socket * ap,
}
/* Success : we have parsed all commands successfully */
- return(count);
+ return count;
}
#ifdef INITIAL_DISCOVERY
@@ -300,7 +300,7 @@ irnet_ctrl_read(irnet_socket * ap,
}
DEXIT(CTRL_TRACE, "\n");
- return(strlen(event));
+ return strlen(event);
}
#endif /* INITIAL_DISCOVERY */
@@ -409,7 +409,7 @@ irnet_ctrl_read(irnet_socket * ap,
}
DEXIT(CTRL_TRACE, "\n");
- return(strlen(event));
+ return strlen(event);
}
/*------------------------------------------------------------------*/
@@ -480,7 +480,6 @@ dev_irnet_open(struct inode * inode,
ap = kzalloc(sizeof(*ap), GFP_KERNEL);
DABORT(ap == NULL, -ENOMEM, FS_ERROR, "Can't allocate struct irnet...\n");
- lock_kernel();
/* initialize the irnet structure */
ap->file = file;
@@ -502,18 +501,20 @@ dev_irnet_open(struct inode * inode,
{
DERROR(FS_ERROR, "Can't setup IrDA link...\n");
kfree(ap);
- unlock_kernel();
+
return err;
}
/* For the control channel */
ap->event_index = irnet_events.index; /* Cancel all past events */
+ mutex_init(&ap->lock);
+
/* Put our stuff where we will be able to find it later */
file->private_data = ap;
DEXIT(FS_TRACE, " - ap=0x%p\n", ap);
- unlock_kernel();
+
return 0;
}
@@ -623,7 +624,7 @@ dev_irnet_poll(struct file * file,
mask |= irnet_ctrl_poll(ap, file, wait);
DEXIT(FS_TRACE, " - mask=0x%X\n", mask);
- return(mask);
+ return mask;
}
/*------------------------------------------------------------------*/
@@ -663,8 +664,10 @@ dev_irnet_ioctl(
if((val == N_SYNC_PPP) || (val == N_PPP))
{
DEBUG(FS_INFO, "Entering PPP discipline.\n");
- /* PPP channel setup (ap->chan in configued in dev_irnet_open())*/
- lock_kernel();
+ /* PPP channel setup (ap->chan in configured in dev_irnet_open())*/
+ if (mutex_lock_interruptible(&ap->lock))
+ return -EINTR;
+
err = ppp_register_channel(&ap->chan);
if(err == 0)
{
@@ -677,14 +680,17 @@ dev_irnet_ioctl(
}
else
DERROR(FS_ERROR, "Can't setup PPP channel...\n");
- unlock_kernel();
+
+ mutex_unlock(&ap->lock);
}
else
{
/* In theory, should be N_TTY */
DEBUG(FS_INFO, "Exiting PPP discipline.\n");
/* Disconnect from the generic PPP layer */
- lock_kernel();
+ if (mutex_lock_interruptible(&ap->lock))
+ return -EINTR;
+
if(ap->ppp_open)
{
ap->ppp_open = 0;
@@ -693,24 +699,31 @@ dev_irnet_ioctl(
else
DERROR(FS_ERROR, "Channel not registered !\n");
err = 0;
- unlock_kernel();
+
+ mutex_unlock(&ap->lock);
}
break;
/* Query PPP channel and unit number */
case PPPIOCGCHAN:
- lock_kernel();
+ if (mutex_lock_interruptible(&ap->lock))
+ return -EINTR;
+
if(ap->ppp_open && !put_user(ppp_channel_index(&ap->chan),
(int __user *)argp))
err = 0;
- unlock_kernel();
+
+ mutex_unlock(&ap->lock);
break;
case PPPIOCGUNIT:
- lock_kernel();
+ if (mutex_lock_interruptible(&ap->lock))
+ return -EINTR;
+
if(ap->ppp_open && !put_user(ppp_unit_number(&ap->chan),
(int __user *)argp))
err = 0;
- unlock_kernel();
+
+ mutex_unlock(&ap->lock);
break;
/* All these ioctls can be passed both directly and from ppp_generic,
@@ -730,9 +743,12 @@ dev_irnet_ioctl(
if(!capable(CAP_NET_ADMIN))
err = -EPERM;
else {
- lock_kernel();
+ if (mutex_lock_interruptible(&ap->lock))
+ return -EINTR;
+
err = ppp_irnet_ioctl(&ap->chan, cmd, arg);
- unlock_kernel();
+
+ mutex_unlock(&ap->lock);
}
break;
@@ -740,7 +756,9 @@ dev_irnet_ioctl(
/* Get termios */
case TCGETS:
DEBUG(FS_INFO, "Get termios.\n");
- lock_kernel();
+ if (mutex_lock_interruptible(&ap->lock))
+ return -EINTR;
+
#ifndef TCGETS2
if(!kernel_termios_to_user_termios((struct termios __user *)argp, &ap->termios))
err = 0;
@@ -748,12 +766,15 @@ dev_irnet_ioctl(
if(kernel_termios_to_user_termios_1((struct termios __user *)argp, &ap->termios))
err = 0;
#endif
- unlock_kernel();
+
+ mutex_unlock(&ap->lock);
break;
/* Set termios */
case TCSETSF:
DEBUG(FS_INFO, "Set termios.\n");
- lock_kernel();
+ if (mutex_lock_interruptible(&ap->lock))
+ return -EINTR;
+
#ifndef TCGETS2
if(!user_termios_to_kernel_termios(&ap->termios, (struct termios __user *)argp))
err = 0;
@@ -761,7 +782,8 @@ dev_irnet_ioctl(
if(!user_termios_to_kernel_termios_1(&ap->termios, (struct termios __user *)argp))
err = 0;
#endif
- unlock_kernel();
+
+ mutex_unlock(&ap->lock);
break;
/* Set DTR/RTS */
@@ -784,9 +806,10 @@ dev_irnet_ioctl(
* We should also worry that we don't accept junk here and that
* we get rid of our own buffers */
#ifdef FLUSH_TO_PPP
- lock_kernel();
+ if (mutex_lock_interruptible(&ap->lock))
+ return -EINTR;
ppp_output_wakeup(&ap->chan);
- unlock_kernel();
+ mutex_unlock(&ap->lock);
#endif /* FLUSH_TO_PPP */
err = 0;
break;
diff --git a/net/irda/irnet/irnet_ppp.h b/net/irda/irnet/irnet_ppp.h
index b5df2418f90c..940225866da0 100644
--- a/net/irda/irnet/irnet_ppp.h
+++ b/net/irda/irnet/irnet_ppp.h
@@ -103,7 +103,8 @@ static const struct file_operations irnet_device_fops =
.poll = dev_irnet_poll,
.unlocked_ioctl = dev_irnet_ioctl,
.open = dev_irnet_open,
- .release = dev_irnet_close
+ .release = dev_irnet_close,
+ .llseek = noop_llseek,
/* Also : llseek, readdir, mmap, flush, fsync, fasync, lock, readv, writev */
};
diff --git a/net/irda/parameters.c b/net/irda/parameters.c
index fc1a20565e2d..71cd38c1a67f 100644
--- a/net/irda/parameters.c
+++ b/net/irda/parameters.c
@@ -298,6 +298,8 @@ static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi,
p.pi = pi; /* In case handler needs to know */
p.pl = buf[1]; /* Extract length of value */
+ if (p.pl > 32)
+ p.pl = 32;
IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d\n", __func__,
p.pi, p.pl);
@@ -318,7 +320,7 @@ static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi,
(__u8) str[0], (__u8) str[1]);
/* Null terminate string */
- str[p.pl+1] = '\0';
+ str[p.pl] = '\0';
p.pv.c = str; /* Handler will need to take a copy */
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index 499c045d6910..f7db676de77d 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -1798,7 +1798,8 @@ static void iucv_work_fn(struct work_struct *work)
* Handles external interrupts coming in from CP.
* Places the interrupt buffer on a queue and schedules iucv_tasklet_fn().
*/
-static void iucv_external_interrupt(u16 code)
+static void iucv_external_interrupt(unsigned int ext_int_code,
+ unsigned int param32, unsigned long param64)
{
struct iucv_irq_data *p;
struct iucv_irq_list *work;
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 43040e97c474..d87c22df6f1e 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -565,12 +565,12 @@ pfkey_proto2satype(uint16_t proto)
static uint8_t pfkey_proto_to_xfrm(uint8_t proto)
{
- return (proto == IPSEC_PROTO_ANY ? 0 : proto);
+ return proto == IPSEC_PROTO_ANY ? 0 : proto;
}
static uint8_t pfkey_proto_from_xfrm(uint8_t proto)
{
- return (proto ? proto : IPSEC_PROTO_ANY);
+ return proto ? proto : IPSEC_PROTO_ANY;
}
static inline int pfkey_sockaddr_len(sa_family_t family)
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 1712af1c7b3f..c64ce0a0bb03 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -111,6 +111,10 @@ struct l2tp_net {
spinlock_t l2tp_session_hlist_lock;
};
+static void l2tp_session_set_header_len(struct l2tp_session *session, int version);
+static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
+static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel);
+
static inline struct l2tp_net *l2tp_pernet(struct net *net)
{
BUG_ON(!net);
@@ -118,6 +122,34 @@ static inline struct l2tp_net *l2tp_pernet(struct net *net)
return net_generic(net, l2tp_net_id);
}
+
+/* Tunnel reference counts. Incremented per session that is added to
+ * the tunnel.
+ */
+static inline void l2tp_tunnel_inc_refcount_1(struct l2tp_tunnel *tunnel)
+{
+ atomic_inc(&tunnel->ref_count);
+}
+
+static inline void l2tp_tunnel_dec_refcount_1(struct l2tp_tunnel *tunnel)
+{
+ if (atomic_dec_and_test(&tunnel->ref_count))
+ l2tp_tunnel_free(tunnel);
+}
+#ifdef L2TP_REFCNT_DEBUG
+#define l2tp_tunnel_inc_refcount(_t) do { \
+ printk(KERN_DEBUG "l2tp_tunnel_inc_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \
+ l2tp_tunnel_inc_refcount_1(_t); \
+ } while (0)
+#define l2tp_tunnel_dec_refcount(_t) do { \
+ printk(KERN_DEBUG "l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \
+ l2tp_tunnel_dec_refcount_1(_t); \
+ } while (0)
+#else
+#define l2tp_tunnel_inc_refcount(t) l2tp_tunnel_inc_refcount_1(t)
+#define l2tp_tunnel_dec_refcount(t) l2tp_tunnel_dec_refcount_1(t)
+#endif
+
/* Session hash global list for L2TPv3.
* The session_id SHOULD be random according to RFC3931, but several
* L2TP implementations use incrementing session_ids. So we do a real
@@ -699,8 +731,8 @@ EXPORT_SYMBOL(l2tp_recv_common);
* Returns 1 if the packet was not a good data packet and could not be
* forwarded. All such packets are passed up to userspace to deal with.
*/
-int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
- int (*payload_hook)(struct sk_buff *skb))
+static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
+ int (*payload_hook)(struct sk_buff *skb))
{
struct l2tp_session *session = NULL;
unsigned char *ptr, *optr;
@@ -812,7 +844,6 @@ error:
return 1;
}
-EXPORT_SYMBOL_GPL(l2tp_udp_recv_core);
/* UDP encapsulation receive handler. See net/ipv4/udp.c.
* Return codes:
@@ -922,7 +953,8 @@ static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf)
return bufp - optr;
}
-int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t data_len)
+static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,
+ size_t data_len)
{
struct l2tp_tunnel *tunnel = session->tunnel;
unsigned int len = skb->len;
@@ -970,7 +1002,6 @@ int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t dat
return 0;
}
-EXPORT_SYMBOL_GPL(l2tp_xmit_core);
/* Automatically called when the skb is freed.
*/
@@ -1089,7 +1120,7 @@ EXPORT_SYMBOL_GPL(l2tp_xmit_skb);
* The tunnel context is deleted only when all session sockets have been
* closed.
*/
-void l2tp_tunnel_destruct(struct sock *sk)
+static void l2tp_tunnel_destruct(struct sock *sk)
{
struct l2tp_tunnel *tunnel;
@@ -1128,11 +1159,10 @@ void l2tp_tunnel_destruct(struct sock *sk)
end:
return;
}
-EXPORT_SYMBOL(l2tp_tunnel_destruct);
/* When the tunnel is closed, all the attached sessions need to go too.
*/
-void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
+static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
{
int hash;
struct hlist_node *walk;
@@ -1193,12 +1223,11 @@ again:
}
write_unlock_bh(&tunnel->hlist_lock);
}
-EXPORT_SYMBOL_GPL(l2tp_tunnel_closeall);
/* Really kill the tunnel.
* Come here only when all sessions have been cleared from the tunnel.
*/
-void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
+static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
{
struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
@@ -1217,7 +1246,6 @@ void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
atomic_dec(&l2tp_tunnel_count);
kfree(tunnel);
}
-EXPORT_SYMBOL_GPL(l2tp_tunnel_free);
/* Create a socket for the tunnel, if one isn't set up by
* userspace. This is used for static tunnels where there is no
@@ -1512,7 +1540,7 @@ EXPORT_SYMBOL_GPL(l2tp_session_delete);
/* We come here whenever a session's send_seq, cookie_len or
* l2specific_len parameters are set.
*/
-void l2tp_session_set_header_len(struct l2tp_session *session, int version)
+static void l2tp_session_set_header_len(struct l2tp_session *session, int version)
{
if (version == L2TP_HDR_VER_2) {
session->hdr_len = 6;
@@ -1525,7 +1553,6 @@ void l2tp_session_set_header_len(struct l2tp_session *session, int version)
}
}
-EXPORT_SYMBOL_GPL(l2tp_session_set_header_len);
struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
{
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index f0f318edd3f1..a16a48e79fab 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -231,48 +231,15 @@ extern int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_i
extern int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel);
extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg);
extern int l2tp_session_delete(struct l2tp_session *session);
-extern void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
extern void l2tp_session_free(struct l2tp_session *session);
extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb));
-extern int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, int (*payload_hook)(struct sk_buff *skb));
extern int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb);
-extern int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t data_len);
extern int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len);
-extern void l2tp_tunnel_destruct(struct sock *sk);
-extern void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel);
-extern void l2tp_session_set_header_len(struct l2tp_session *session, int version);
extern int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops *ops);
extern void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type);
-/* Tunnel reference counts. Incremented per session that is added to
- * the tunnel.
- */
-static inline void l2tp_tunnel_inc_refcount_1(struct l2tp_tunnel *tunnel)
-{
- atomic_inc(&tunnel->ref_count);
-}
-
-static inline void l2tp_tunnel_dec_refcount_1(struct l2tp_tunnel *tunnel)
-{
- if (atomic_dec_and_test(&tunnel->ref_count))
- l2tp_tunnel_free(tunnel);
-}
-#ifdef L2TP_REFCNT_DEBUG
-#define l2tp_tunnel_inc_refcount(_t) do { \
- printk(KERN_DEBUG "l2tp_tunnel_inc_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \
- l2tp_tunnel_inc_refcount_1(_t); \
- } while (0)
-#define l2tp_tunnel_dec_refcount(_t) do { \
- printk(KERN_DEBUG "l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \
- l2tp_tunnel_dec_refcount_1(_t); \
- } while (0)
-#else
-#define l2tp_tunnel_inc_refcount(t) l2tp_tunnel_inc_refcount_1(t)
-#define l2tp_tunnel_dec_refcount(t) l2tp_tunnel_dec_refcount_1(t)
-#endif
-
/* Session reference counts. Incremented when code obtains a reference
* to a session.
*/
diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c
index 1ae697681bc7..8d9ce0accc98 100644
--- a/net/l2tp/l2tp_eth.c
+++ b/net/l2tp/l2tp_eth.c
@@ -144,7 +144,6 @@ static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb,
nf_reset(skb);
if (dev_forward_skb(dev, skb) == NET_RX_SUCCESS) {
- dev->last_rx = jiffies;
dev->stats.rx_packets++;
dev->stats.rx_bytes += data_len;
} else
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index 226a0ae3bcfd..0bf6a59545ab 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -65,9 +65,7 @@ static struct sock *__l2tp_ip_bind_lookup(struct net *net, __be32 laddr, int dif
continue;
if ((l2tp->conn_id == tunnel_id) &&
-#ifdef CONFIG_NET_NS
- (sk->sk_net == net) &&
-#endif
+ net_eq(sock_net(sk), net) &&
!(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) &&
!(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif))
goto found;
@@ -578,7 +576,7 @@ out:
return copied;
}
-struct proto l2tp_ip_prot = {
+static struct proto l2tp_ip_prot = {
.name = "L2TP/IP",
.owner = THIS_MODULE,
.init = l2tp_ip_open,
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index ff954b3e94b6..39a21d0c61c4 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1768,7 +1768,7 @@ static const struct proto_ops pppol2tp_ops = {
.ioctl = pppox_ioctl,
};
-static struct pppox_proto pppol2tp_proto = {
+static const struct pppox_proto pppol2tp_proto = {
.create = pppol2tp_create,
.ioctl = pppol2tp_ioctl
};
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c
index a87cb3ba2df6..d2b03e0851ef 100644
--- a/net/mac80211/aes_ccm.c
+++ b/net/mac80211/aes_ccm.c
@@ -138,10 +138,8 @@ struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[])
struct crypto_cipher *tfm;
tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(tfm))
- return NULL;
-
- crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN);
+ if (!IS_ERR(tfm))
+ crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN);
return tfm;
}
diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c
index 3d097b3d7b62..b4d66cca76d6 100644
--- a/net/mac80211/aes_cmac.c
+++ b/net/mac80211/aes_cmac.c
@@ -119,10 +119,8 @@ struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[])
struct crypto_cipher *tfm;
tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(tfm))
- return NULL;
-
- crypto_cipher_setkey(tfm, key, AES_CMAC_KEY_LEN);
+ if (!IS_ERR(tfm))
+ crypto_cipher_setkey(tfm, key, AES_CMAC_KEY_LEN);
return tfm;
}
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index 965b272499fd..720b7a84af59 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -56,7 +56,7 @@ static void ieee80211_free_tid_rx(struct rcu_head *h)
}
void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
- u16 initiator, u16 reason)
+ u16 initiator, u16 reason, bool tx)
{
struct ieee80211_local *local = sta->local;
struct tid_ampdu_rx *tid_rx;
@@ -81,20 +81,21 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
"aggregation for tid %d\n", tid);
/* check if this is a self generated aggregation halt */
- if (initiator == WLAN_BACK_RECIPIENT)
+ if (initiator == WLAN_BACK_RECIPIENT && tx)
ieee80211_send_delba(sta->sdata, sta->sta.addr,
tid, 0, reason);
del_timer_sync(&tid_rx->session_timer);
+ del_timer_sync(&tid_rx->reorder_timer);
call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
}
void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
- u16 initiator, u16 reason)
+ u16 initiator, u16 reason, bool tx)
{
mutex_lock(&sta->ampdu_mlme.mtx);
- ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason);
+ ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason, tx);
mutex_unlock(&sta->ampdu_mlme.mtx);
}
@@ -120,6 +121,20 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
}
+static void sta_rx_agg_reorder_timer_expired(unsigned long data)
+{
+ u8 *ptid = (u8 *)data;
+ u8 *timer_to_id = ptid - *ptid;
+ struct sta_info *sta = container_of(timer_to_id, struct sta_info,
+ timer_to_tid[0]);
+
+ rcu_read_lock();
+ spin_lock(&sta->lock);
+ ieee80211_release_reorder_timeout(sta, *ptid);
+ spin_unlock(&sta->lock);
+ rcu_read_unlock();
+}
+
static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
u8 dialog_token, u16 status, u16 policy,
u16 buf_size, u16 timeout)
@@ -251,11 +266,18 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
goto end;
}
+ spin_lock_init(&tid_agg_rx->reorder_lock);
+
/* rx timer */
tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired;
tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
init_timer(&tid_agg_rx->session_timer);
+ /* rx reorder timer */
+ tid_agg_rx->reorder_timer.function = sta_rx_agg_reorder_timer_expired;
+ tid_agg_rx->reorder_timer.data = (unsigned long)&sta->timer_to_tid[tid];
+ init_timer(&tid_agg_rx->reorder_timer);
+
/* prepare reordering buffer */
tid_agg_rx->reorder_buf =
kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC);
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 8f23401832b7..d4679b265ba8 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -145,7 +145,8 @@ static void kfree_tid_tx(struct rcu_head *rcu_head)
}
int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
- enum ieee80211_back_parties initiator)
+ enum ieee80211_back_parties initiator,
+ bool tx)
{
struct ieee80211_local *local = sta->local;
struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
@@ -185,6 +186,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
tid_tx->stop_initiator = initiator;
+ tid_tx->tx_stop = tx;
ret = drv_ampdu_action(local, sta->sdata,
IEEE80211_AMPDU_TX_STOP,
@@ -577,13 +579,14 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
- enum ieee80211_back_parties initiator)
+ enum ieee80211_back_parties initiator,
+ bool tx)
{
int ret;
mutex_lock(&sta->ampdu_mlme.mtx);
- ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator);
+ ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator, tx);
mutex_unlock(&sta->ampdu_mlme.mtx);
@@ -672,7 +675,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
goto unlock_sta;
}
- if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR)
+ if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR && tid_tx->tx_stop)
ieee80211_send_delba(sta->sdata, ra, tid,
WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
@@ -772,7 +775,8 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
sta->ampdu_mlme.addba_req_num[tid] = 0;
} else {
- ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
+ ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
+ true);
}
out:
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 29ac8e1a509e..18bd0e550600 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -19,33 +19,6 @@
#include "rate.h"
#include "mesh.h"
-static bool nl80211_type_check(enum nl80211_iftype type)
-{
- switch (type) {
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_MONITOR:
-#ifdef CONFIG_MAC80211_MESH
- case NL80211_IFTYPE_MESH_POINT:
-#endif
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_AP_VLAN:
- case NL80211_IFTYPE_WDS:
- return true;
- default:
- return false;
- }
-}
-
-static bool nl80211_params_check(enum nl80211_iftype type,
- struct vif_params *params)
-{
- if (!nl80211_type_check(type))
- return false;
-
- return true;
-}
-
static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
@@ -55,9 +28,6 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
struct ieee80211_sub_if_data *sdata;
int err;
- if (!nl80211_params_check(type, params))
- return -EINVAL;
-
err = ieee80211_if_add(local, name, &dev, type, params);
if (err || type != NL80211_IFTYPE_MONITOR || !flags)
return err;
@@ -82,12 +52,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
int ret;
- if (ieee80211_sdata_running(sdata))
- return -EBUSY;
-
- if (!nl80211_params_check(type, params))
- return -EINVAL;
-
ret = ieee80211_if_change_type(sdata, type);
if (ret)
return ret;
@@ -104,54 +68,71 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
params && params->use_4addr >= 0)
sdata->u.mgd.use_4addr = params->use_4addr;
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags)
- sdata->u.mntr_flags = *flags;
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) {
+ struct ieee80211_local *local = sdata->local;
+
+ if (ieee80211_sdata_running(sdata)) {
+ /*
+ * Prohibit MONITOR_FLAG_COOK_FRAMES to be
+ * changed while the interface is up.
+ * Else we would need to add a lot of cruft
+ * to update everything:
+ * cooked_mntrs, monitor and all fif_* counters
+ * reconfigure hardware
+ */
+ if ((*flags & MONITOR_FLAG_COOK_FRAMES) !=
+ (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
+ return -EBUSY;
+
+ ieee80211_adjust_monitor_flags(sdata, -1);
+ sdata->u.mntr_flags = *flags;
+ ieee80211_adjust_monitor_flags(sdata, 1);
+
+ ieee80211_configure_filter(local);
+ } else {
+ /*
+ * Because the interface is down, ieee80211_do_stop
+ * and ieee80211_do_open take care of "everything"
+ * mentioned in the comment above.
+ */
+ sdata->u.mntr_flags = *flags;
+ }
+ }
return 0;
}
static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, const u8 *mac_addr,
+ u8 key_idx, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sta_info *sta = NULL;
- enum ieee80211_key_alg alg;
struct ieee80211_key *key;
int err;
- if (!netif_running(dev))
+ if (!ieee80211_sdata_running(sdata))
return -ENETDOWN;
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
+ /* reject WEP and TKIP keys if WEP failed to initialize */
switch (params->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
- case WLAN_CIPHER_SUITE_WEP104:
- alg = ALG_WEP;
- break;
case WLAN_CIPHER_SUITE_TKIP:
- alg = ALG_TKIP;
- break;
- case WLAN_CIPHER_SUITE_CCMP:
- alg = ALG_CCMP;
- break;
- case WLAN_CIPHER_SUITE_AES_CMAC:
- alg = ALG_AES_CMAC;
+ case WLAN_CIPHER_SUITE_WEP104:
+ if (IS_ERR(sdata->local->wep_tx_tfm))
+ return -EINVAL;
break;
default:
- return -EINVAL;
+ break;
}
- /* reject WEP and TKIP keys if WEP failed to initialize */
- if ((alg == ALG_WEP || alg == ALG_TKIP) &&
- IS_ERR(sdata->local->wep_tx_tfm))
- return -EINVAL;
+ key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len,
+ params->key, params->seq_len, params->seq);
+ if (IS_ERR(key))
+ return PTR_ERR(key);
- key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key,
- params->seq_len, params->seq);
- if (!key)
- return -ENOMEM;
+ if (pairwise)
+ key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
mutex_lock(&sdata->local->sta_mtx);
@@ -164,9 +145,10 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
}
}
- ieee80211_key_link(key, sdata, sta);
+ err = ieee80211_key_link(key, sdata, sta);
+ if (err)
+ ieee80211_key_free(sdata->local, key);
- err = 0;
out_unlock:
mutex_unlock(&sdata->local->sta_mtx);
@@ -174,7 +156,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
}
static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, const u8 *mac_addr)
+ u8 key_idx, bool pairwise, const u8 *mac_addr)
{
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
@@ -191,10 +173,17 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
if (!sta)
goto out_unlock;
- if (sta->key) {
- ieee80211_key_free(sdata->local, sta->key);
- WARN_ON(sta->key);
- ret = 0;
+ if (pairwise) {
+ if (sta->ptk) {
+ ieee80211_key_free(sdata->local, sta->ptk);
+ ret = 0;
+ }
+ } else {
+ if (sta->gtk[key_idx]) {
+ ieee80211_key_free(sdata->local,
+ sta->gtk[key_idx]);
+ ret = 0;
+ }
}
goto out_unlock;
@@ -216,7 +205,8 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
}
static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, const u8 *mac_addr, void *cookie,
+ u8 key_idx, bool pairwise, const u8 *mac_addr,
+ void *cookie,
void (*callback)(void *cookie,
struct key_params *params))
{
@@ -224,7 +214,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
struct sta_info *sta = NULL;
u8 seq[6] = {0};
struct key_params params;
- struct ieee80211_key *key;
+ struct ieee80211_key *key = NULL;
u32 iv32;
u16 iv16;
int err = -ENOENT;
@@ -238,7 +228,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
if (!sta)
goto out;
- key = sta->key;
+ if (pairwise)
+ key = sta->ptk;
+ else if (key_idx < NUM_DEFAULT_KEYS)
+ key = sta->gtk[key_idx];
} else
key = sdata->keys[key_idx];
@@ -247,10 +240,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
memset(&params, 0, sizeof(params));
- switch (key->conf.alg) {
- case ALG_TKIP:
- params.cipher = WLAN_CIPHER_SUITE_TKIP;
+ params.cipher = key->conf.cipher;
+ switch (key->conf.cipher) {
+ case WLAN_CIPHER_SUITE_TKIP:
iv32 = key->u.tkip.tx.iv32;
iv16 = key->u.tkip.tx.iv16;
@@ -268,8 +261,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
params.seq = seq;
params.seq_len = 6;
break;
- case ALG_CCMP:
- params.cipher = WLAN_CIPHER_SUITE_CCMP;
+ case WLAN_CIPHER_SUITE_CCMP:
seq[0] = key->u.ccmp.tx_pn[5];
seq[1] = key->u.ccmp.tx_pn[4];
seq[2] = key->u.ccmp.tx_pn[3];
@@ -279,14 +271,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
params.seq = seq;
params.seq_len = 6;
break;
- case ALG_WEP:
- if (key->conf.keylen == 5)
- params.cipher = WLAN_CIPHER_SUITE_WEP40;
- else
- params.cipher = WLAN_CIPHER_SUITE_WEP104;
- break;
- case ALG_AES_CMAC:
- params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
seq[0] = key->u.aes_cmac.tx_pn[5];
seq[1] = key->u.aes_cmac.tx_pn[4];
seq[2] = key->u.aes_cmac.tx_pn[3];
@@ -342,13 +327,19 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
STATION_INFO_TX_BYTES |
STATION_INFO_RX_PACKETS |
STATION_INFO_TX_PACKETS |
- STATION_INFO_TX_BITRATE;
+ STATION_INFO_TX_RETRIES |
+ STATION_INFO_TX_FAILED |
+ STATION_INFO_TX_BITRATE |
+ STATION_INFO_RX_DROP_MISC;
sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
sinfo->rx_bytes = sta->rx_bytes;
sinfo->tx_bytes = sta->tx_bytes;
sinfo->rx_packets = sta->rx_packets;
sinfo->tx_packets = sta->tx_packets;
+ sinfo->tx_retries = sta->tx_retry_count;
+ sinfo->tx_failed = sta->tx_retry_failed;
+ sinfo->rx_dropped_misc = sta->rx_dropped;
if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ||
(sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) {
@@ -634,6 +625,7 @@ 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;
@@ -642,7 +634,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
sband = local->hw.wiphy->bands[local->oper_channel->band];
- spin_lock_bh(&sta->lock);
+ spin_lock_irqsave(&sta->flaglock, flags);
mask = params->sta_flags_mask;
set = params->sta_flags_set;
@@ -669,7 +661,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
if (set & BIT(NL80211_STA_FLAG_MFP))
sta->flags |= WLAN_STA_MFP;
}
- spin_unlock_bh(&sta->lock);
+ spin_unlock_irqrestore(&sta->flaglock, flags);
/*
* cfg80211 validates this (1-2007) and allows setting the AID
@@ -1143,9 +1135,9 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
p.uapsd = false;
if (drv_conf_tx(local, params->queue, &p)) {
- printk(KERN_DEBUG "%s: failed to set TX queue "
- "parameters for queue %d\n",
- wiphy_name(local->hw.wiphy), params->queue);
+ wiphy_debug(local->hw.wiphy,
+ "failed to set TX queue parameters for queue %d\n",
+ params->queue);
return -EINVAL;
}
@@ -1207,15 +1199,26 @@ static int ieee80211_scan(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_scan_request *req)
{
- struct ieee80211_sub_if_data *sdata;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->vif.type != NL80211_IFTYPE_STATION &&
- sdata->vif.type != NL80211_IFTYPE_ADHOC &&
- sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
- (sdata->vif.type != NL80211_IFTYPE_AP || sdata->u.ap.beacon))
+ switch (ieee80211_vif_type_p2p(&sdata->vif)) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ if (sdata->local->ops->hw_scan)
+ break;
+ /* FIXME: implement NoA while scanning in software */
+ return -EOPNOTSUPP;
+ case NL80211_IFTYPE_AP:
+ if (sdata->u.ap.beacon)
+ return -EOPNOTSUPP;
+ break;
+ default:
return -EOPNOTSUPP;
+ }
return ieee80211_request_scan(sdata, req);
}
@@ -1362,7 +1365,7 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm)
}
static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
- u8 *addr)
+ const u8 *addr)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1411,7 +1414,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
if (!sdata->u.mgd.associated ||
sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
mutex_lock(&sdata->local->iflist_mtx);
- ieee80211_recalc_smps(sdata->local, sdata);
+ ieee80211_recalc_smps(sdata->local);
mutex_unlock(&sdata->local->iflist_mtx);
return 0;
}
@@ -1541,11 +1544,11 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
}
-static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
- bool channel_type_valid,
- const u8 *buf, size_t len, u64 *cookie)
+static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
+ const u8 *buf, size_t len, u64 *cookie)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
@@ -1566,7 +1569,11 @@ static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
switch (sdata->vif.type) {
case NL80211_IFTYPE_ADHOC:
- if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_P2P_GO:
+ if (!ieee80211_is_action(mgmt->frame_control) ||
+ mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
break;
rcu_read_lock();
sta = sta_info_get(sdata, mgmt->da);
@@ -1575,8 +1582,7 @@ static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
return -ENOLINK;
break;
case NL80211_IFTYPE_STATION:
- if (!(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED))
- flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+ case NL80211_IFTYPE_P2P_CLIENT:
break;
default:
return -EOPNOTSUPP;
@@ -1598,6 +1604,23 @@ static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
+static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
+ struct net_device *dev,
+ u16 frame_type, bool reg)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+
+ if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
+ return;
+
+ if (reg)
+ local->probe_req_reg++;
+ else
+ local->probe_req_reg--;
+
+ ieee80211_queue_work(&local->hw, &local->reconfig_filter);
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -1647,6 +1670,7 @@ struct cfg80211_ops mac80211_config_ops = {
.set_bitrate_mask = ieee80211_set_bitrate_mask,
.remain_on_channel = ieee80211_remain_on_channel,
.cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
- .action = ieee80211_action,
+ .mgmt_tx = ieee80211_mgmt_tx,
.set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
+ .mgmt_frame_register = ieee80211_mgmt_frame_register,
};
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 32be11e4c4d9..5b24740fc0b0 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -11,7 +11,7 @@ __ieee80211_get_channel_mode(struct ieee80211_local *local,
{
struct ieee80211_sub_if_data *sdata;
- WARN_ON(!mutex_is_locked(&local->iflist_mtx));
+ lockdep_assert_held(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata == ignore)
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index b8b0ae79a743..18260aa99c56 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -86,13 +86,15 @@ static ssize_t tsf_write(struct file *file,
if (strncmp(buf, "reset", 5) == 0) {
if (local->ops->reset_tsf) {
drv_reset_tsf(local);
- printk(KERN_INFO "%s: debugfs reset TSF\n", wiphy_name(local->hw.wiphy));
+ 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);
- printk(KERN_INFO "%s: debugfs set TSF to %#018llx\n", wiphy_name(local->hw.wiphy), tsf);
+ wiphy_info(local->hw.wiphy,
+ "debugfs set TSF to %#018llx\n", tsf);
+
}
}
@@ -375,7 +377,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
if (!phyd)
return;
- local->debugfs.stations = debugfs_create_dir("stations", phyd);
local->debugfs.keys = debugfs_create_dir("keys", phyd);
DEBUGFS_ADD(frequency);
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 7cd8dd9fc240..4aa47d074a79 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -66,26 +66,13 @@ static ssize_t key_algorithm_read(struct file *file,
char __user *userbuf,
size_t count, loff_t *ppos)
{
- char *alg;
+ char buf[15];
struct ieee80211_key *key = file->private_data;
+ u32 c = key->conf.cipher;
- switch (key->conf.alg) {
- case ALG_WEP:
- alg = "WEP\n";
- break;
- case ALG_TKIP:
- alg = "TKIP\n";
- break;
- case ALG_CCMP:
- alg = "CCMP\n";
- break;
- case ALG_AES_CMAC:
- alg = "AES-128-CMAC\n";
- break;
- default:
- return 0;
- }
- return simple_read_from_buffer(userbuf, count, ppos, alg, strlen(alg));
+ sprintf(buf, "%.2x-%.2x-%.2x:%d\n",
+ c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
+ return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
}
KEY_OPS(algorithm);
@@ -97,21 +84,22 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
int len;
struct ieee80211_key *key = file->private_data;
- switch (key->conf.alg) {
- case ALG_WEP:
+ switch (key->conf.cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
len = scnprintf(buf, sizeof(buf), "\n");
break;
- case ALG_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
key->u.tkip.tx.iv32,
key->u.tkip.tx.iv16);
break;
- case ALG_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
tpn = key->u.ccmp.tx_pn;
len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
break;
- case ALG_AES_CMAC:
+ case WLAN_CIPHER_SUITE_AES_CMAC:
tpn = key->u.aes_cmac.tx_pn;
len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
tpn[0], tpn[1], tpn[2], tpn[3], tpn[4],
@@ -132,11 +120,12 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
int i, len;
const u8 *rpn;
- switch (key->conf.alg) {
- case ALG_WEP:
+ switch (key->conf.cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
len = scnprintf(buf, sizeof(buf), "\n");
break;
- case ALG_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
p += scnprintf(p, sizeof(buf)+buf-p,
"%08x %04x\n",
@@ -144,7 +133,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
key->u.tkip.rx[i].iv16);
len = p - buf;
break;
- case ALG_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) {
rpn = key->u.ccmp.rx_pn[i];
p += scnprintf(p, sizeof(buf)+buf-p,
@@ -154,7 +143,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
}
len = p - buf;
break;
- case ALG_AES_CMAC:
+ case WLAN_CIPHER_SUITE_AES_CMAC:
rpn = key->u.aes_cmac.rx_pn;
p += scnprintf(p, sizeof(buf)+buf-p,
"%02x%02x%02x%02x%02x%02x\n",
@@ -176,11 +165,11 @@ static ssize_t key_replays_read(struct file *file, char __user *userbuf,
char buf[20];
int len;
- switch (key->conf.alg) {
- case ALG_CCMP:
+ switch (key->conf.cipher) {
+ case WLAN_CIPHER_SUITE_CCMP:
len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
break;
- case ALG_AES_CMAC:
+ case WLAN_CIPHER_SUITE_AES_CMAC:
len = scnprintf(buf, sizeof(buf), "%u\n",
key->u.aes_cmac.replays);
break;
@@ -198,8 +187,8 @@ static ssize_t key_icverrors_read(struct file *file, char __user *userbuf,
char buf[20];
int len;
- switch (key->conf.alg) {
- case ALG_AES_CMAC:
+ switch (key->conf.cipher) {
+ case WLAN_CIPHER_SUITE_AES_CMAC:
len = scnprintf(buf, sizeof(buf), "%u\n",
key->u.aes_cmac.icverrors);
break;
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 8ad33eef7dda..cbdf36d7841c 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -410,6 +410,9 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
sprintf(buf, "netdev:%s", sdata->name);
sdata->debugfs.dir = debugfs_create_dir(buf,
sdata->local->hw.wiphy->debugfsdir);
+ if (sdata->debugfs.dir)
+ sdata->debugfs.subdir_stations = debugfs_create_dir("stations",
+ sdata->debugfs.dir);
add_files(sdata);
}
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 6a8fdc372c43..4601fea1784d 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -198,7 +198,8 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu
else
ret = ieee80211_stop_tx_ba_session(&sta->sta, tid);
} else {
- __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, 3);
+ __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
+ 3, true);
ret = 0;
}
@@ -302,7 +303,7 @@ STA_OPS(ht_capa);
void ieee80211_sta_debugfs_add(struct sta_info *sta)
{
- struct dentry *stations_dir = sta->local->debugfs.stations;
+ struct dentry *stations_dir = sta->sdata->debugfs.subdir_stations;
u8 mac[3*ETH_ALEN];
sta->debugfs.add_has_run = true;
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 14123dce544b..16983825f8e8 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -54,6 +54,20 @@ static inline int drv_add_interface(struct ieee80211_local *local,
return ret;
}
+static inline int drv_change_interface(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ enum nl80211_iftype type, bool p2p)
+{
+ int ret;
+
+ might_sleep();
+
+ trace_drv_change_interface(local, sdata, type, p2p);
+ ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
+ trace_drv_return_int(local, ret);
+ return ret;
+}
+
static inline void drv_remove_interface(struct ieee80211_local *local,
struct ieee80211_vif *vif)
{
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 5d5d2a974668..6831fb1641c8 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -25,12 +25,14 @@ static inline void trace_ ## name(proto) {}
#define STA_PR_FMT " sta:%pM"
#define STA_PR_ARG __entry->sta_addr
-#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \
+#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \
+ __field(bool, p2p) \
__string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
-#define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \
+#define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \
+ __entry->p2p = sdata->vif.p2p; \
__assign_str(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
-#define VIF_PR_FMT " vif:%s(%d)"
-#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type
+#define VIF_PR_FMT " vif:%s(%d%s)"
+#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
/*
* Tracing for driver callbacks.
@@ -136,6 +138,34 @@ TRACE_EVENT(drv_add_interface,
)
);
+TRACE_EVENT(drv_change_interface,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ enum nl80211_iftype type, bool p2p),
+
+ TP_ARGS(local, sdata, type, p2p),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __field(u32, new_type)
+ __field(bool, new_p2p)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ __entry->new_type = type;
+ __entry->new_p2p = p2p;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT " new type:%d%s",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->new_type,
+ __entry->new_p2p ? "/p2p" : ""
+ )
+);
+
TRACE_EVENT(drv_remove_interface,
TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata),
@@ -336,7 +366,7 @@ TRACE_EVENT(drv_set_key,
LOCAL_ENTRY
VIF_ENTRY
STA_ENTRY
- __field(enum ieee80211_key_alg, alg)
+ __field(u32, cipher)
__field(u8, hw_key_idx)
__field(u8, flags)
__field(s8, keyidx)
@@ -346,7 +376,7 @@ TRACE_EVENT(drv_set_key,
LOCAL_ASSIGN;
VIF_ASSIGN;
STA_ASSIGN;
- __entry->alg = key->alg;
+ __entry->cipher = key->cipher;
__entry->flags = key->flags;
__entry->keyidx = key->keyidx;
__entry->hw_key_idx = key->hw_key_idx;
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 9d101fb33861..75d679d75e63 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -101,16 +101,16 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
ht_cap->mcs.rx_mask[32/8] |= 1;
}
-void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta)
+void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx)
{
int i;
cancel_work_sync(&sta->ampdu_mlme.work);
for (i = 0; i < STA_TID_NUM; i++) {
- __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR);
+ __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR, tx);
__ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
- WLAN_REASON_QSTA_LEAVE_QBSS);
+ WLAN_REASON_QSTA_LEAVE_QBSS, tx);
}
}
@@ -135,7 +135,7 @@ void ieee80211_ba_session_work(struct work_struct *work)
if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired))
___ieee80211_stop_rx_ba_session(
sta, tid, WLAN_BACK_RECIPIENT,
- WLAN_REASON_QSTA_TIMEOUT);
+ WLAN_REASON_QSTA_TIMEOUT, true);
tid_tx = sta->ampdu_mlme.tid_tx[tid];
if (!tid_tx)
@@ -146,7 +146,8 @@ void ieee80211_ba_session_work(struct work_struct *work)
else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP,
&tid_tx->state))
___ieee80211_stop_tx_ba_session(sta, tid,
- WLAN_BACK_INITIATOR);
+ WLAN_BACK_INITIATOR,
+ true);
}
mutex_unlock(&sta->ampdu_mlme.mtx);
}
@@ -214,9 +215,11 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
#endif /* CONFIG_MAC80211_HT_DEBUG */
if (initiator == WLAN_BACK_INITIATOR)
- __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0);
+ __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0,
+ true);
else
- __ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT);
+ __ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
+ true);
}
int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
@@ -265,3 +268,33 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
return 0;
}
+
+void ieee80211_request_smps_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data,
+ u.mgd.request_smps_work);
+
+ mutex_lock(&sdata->u.mgd.mtx);
+ __ieee80211_request_smps(sdata, sdata->u.mgd.driver_smps_mode);
+ mutex_unlock(&sdata->u.mgd.mtx);
+}
+
+void ieee80211_request_smps(struct ieee80211_vif *vif,
+ enum ieee80211_smps_mode smps_mode)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+ if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
+ return;
+
+ if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF))
+ smps_mode = IEEE80211_SMPS_AUTOMATIC;
+
+ sdata->u.mgd.driver_smps_mode = smps_mode;
+
+ ieee80211_queue_work(&sdata->local->hw,
+ &sdata->u.mgd.request_smps_work);
+}
+/* this might change ... don't want non-open drivers using it */
+EXPORT_SYMBOL_GPL(ieee80211_request_smps);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index c691780725a7..239c4836a946 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -173,6 +173,19 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
memcpy(skb_put(skb, ifibss->ie_len),
ifibss->ie, ifibss->ie_len);
+ if (local->hw.queues >= 4) {
+ pos = skb_put(skb, 9);
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 7; /* len */
+ *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
+ *pos++ = 0x50;
+ *pos++ = 0xf2;
+ *pos++ = 2; /* WME */
+ *pos++ = 0; /* WME info */
+ *pos++ = 1; /* WME ver */
+ *pos++ = 0; /* U-APSD no in use */
+ }
+
rcu_assign_pointer(ifibss->presp, skb);
sdata->vif.bss_conf.beacon_int = beacon_int;
@@ -266,37 +279,45 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
return;
- if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates &&
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
memcmp(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) {
- supp_rates = ieee80211_sta_get_rates(local, elems, band);
rcu_read_lock();
-
sta = sta_info_get(sdata, mgmt->sa);
- if (sta) {
- u32 prev_rates;
- prev_rates = sta->sta.supp_rates[band];
- /* make sure mandatory rates are always added */
- sta->sta.supp_rates[band] = supp_rates |
- ieee80211_mandatory_rates(local, band);
+ if (elems->supp_rates) {
+ supp_rates = ieee80211_sta_get_rates(local, elems,
+ band);
+ if (sta) {
+ u32 prev_rates;
+
+ prev_rates = sta->sta.supp_rates[band];
+ /* make sure mandatory rates are always added */
+ sta->sta.supp_rates[band] = supp_rates |
+ ieee80211_mandatory_rates(local, band);
- if (sta->sta.supp_rates[band] != prev_rates) {
+ if (sta->sta.supp_rates[band] != prev_rates) {
#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG "%s: updated supp_rates set "
- "for %pM based on beacon/probe_response "
- "(0x%x -> 0x%x)\n",
- sdata->name, sta->sta.addr,
- prev_rates, sta->sta.supp_rates[band]);
+ printk(KERN_DEBUG
+ "%s: updated supp_rates set "
+ "for %pM based on beacon"
+ "/probe_resp (0x%x -> 0x%x)\n",
+ sdata->name, sta->sta.addr,
+ prev_rates,
+ sta->sta.supp_rates[band]);
#endif
- rate_control_rate_init(sta);
- }
- rcu_read_unlock();
- } else {
- rcu_read_unlock();
- ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
- supp_rates, GFP_KERNEL);
+ rate_control_rate_init(sta);
+ }
+ } else
+ sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
+ mgmt->sa, supp_rates,
+ GFP_ATOMIC);
}
+
+ if (sta && elems->wmm_info)
+ set_sta_flags(sta, WLAN_STA_WME);
+
+ rcu_read_unlock();
}
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
@@ -427,14 +448,15 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
return NULL;
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n",
- wiphy_name(local->hw.wiphy), addr, sdata->name);
+ wiphy_debug(local->hw.wiphy, "Adding new IBSS station %pM (dev=%s)\n",
+ addr, sdata->name);
#endif
sta = sta_info_alloc(sdata, addr, gfp);
if (!sta)
return NULL;
+ sta->last_rx = jiffies;
set_sta_flags(sta, WLAN_STA_AUTHORIZED);
/* make sure mandatory rates are always added */
@@ -920,12 +942,14 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN);
sdata->u.ibss.ssid_len = params->ssid_len;
+ mutex_unlock(&sdata->u.ibss.mtx);
+
+ mutex_lock(&sdata->local->mtx);
ieee80211_recalc_idle(sdata->local);
+ mutex_unlock(&sdata->local->mtx);
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
- mutex_unlock(&sdata->u.ibss.mtx);
-
return 0;
}
@@ -980,7 +1004,9 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
mutex_unlock(&sdata->u.ibss.mtx);
+ mutex_lock(&local->mtx);
ieee80211_recalc_idle(sdata->local);
+ mutex_unlock(&local->mtx);
return 0;
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 65e0ed6c2975..b80c38689927 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -50,12 +50,6 @@ struct ieee80211_local;
* increased memory use (about 2 kB of RAM per entry). */
#define IEEE80211_FRAGMENT_MAX 4
-/*
- * Time after which we ignore scan results and no longer report/use
- * them in any way.
- */
-#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
-
#define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024))
#define IEEE80211_DEFAULT_UAPSD_QUEUES \
@@ -165,12 +159,37 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
#define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u)
#define RX_QUEUED ((__force ieee80211_rx_result) 3u)
-#define IEEE80211_RX_IN_SCAN BIT(0)
-/* frame is destined to interface currently processed (incl. multicast frames) */
-#define IEEE80211_RX_RA_MATCH BIT(1)
-#define IEEE80211_RX_AMSDU BIT(2)
-#define IEEE80211_RX_FRAGMENTED BIT(3)
-/* only add flags here that do not change with subframes of an aMPDU */
+/**
+ * enum ieee80211_packet_rx_flags - packet RX flags
+ * @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed
+ * (incl. multicast frames)
+ * @IEEE80211_RX_IN_SCAN: received while scanning
+ * @IEEE80211_RX_FRAGMENTED: fragmented frame
+ * @IEEE80211_RX_AMSDU: a-MSDU packet
+ * @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed
+ *
+ * These are per-frame flags that are attached to a frame in the
+ * @rx_flags field of &struct ieee80211_rx_status.
+ */
+enum ieee80211_packet_rx_flags {
+ IEEE80211_RX_IN_SCAN = BIT(0),
+ IEEE80211_RX_RA_MATCH = BIT(1),
+ IEEE80211_RX_FRAGMENTED = BIT(2),
+ IEEE80211_RX_AMSDU = BIT(3),
+ IEEE80211_RX_MALFORMED_ACTION_FRM = BIT(4),
+};
+
+/**
+ * enum ieee80211_rx_flags - RX data flags
+ *
+ * @IEEE80211_RX_CMNTR: received on cooked monitor already
+ *
+ * These flags are used across handling multiple interfaces
+ * for a single frame.
+ */
+enum ieee80211_rx_flags {
+ IEEE80211_RX_CMNTR = BIT(0),
+};
struct ieee80211_rx_data {
struct sk_buff *skb;
@@ -343,10 +362,14 @@ struct ieee80211_if_managed {
unsigned long timers_running; /* used for quiesce/restart */
bool powersave; /* powersave requested for this iface */
enum ieee80211_smps_mode req_smps, /* requested smps mode */
- ap_smps; /* smps mode AP thinks we're in */
+ ap_smps, /* smps mode AP thinks we're in */
+ driver_smps_mode; /* smps mode request */
+
+ struct work_struct request_smps_work;
unsigned int flags;
+ bool beacon_crc_valid;
u32 beacon_crc;
enum {
@@ -371,6 +394,13 @@ struct ieee80211_if_managed {
int ave_beacon_signal;
/*
+ * Number of Beacon frames used in ave_beacon_signal. This can be used
+ * to avoid generating less reliable cqm events that would be based
+ * only on couple of received frames.
+ */
+ unsigned int count_beacon_signal;
+
+ /*
* Last Beacon frame signal strength average (ave_beacon_signal / 16)
* that triggered a cqm event. 0 indicates that no event has been
* generated for the current association.
@@ -474,6 +504,19 @@ enum ieee80211_sub_if_data_flags {
IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3),
};
+/**
+ * enum ieee80211_sdata_state_bits - virtual interface state bits
+ * @SDATA_STATE_RUNNING: virtual interface is up & running; this
+ * mirrors netif_running() but is separate for interface type
+ * change handling while the interface is up
+ * @SDATA_STATE_OFFCHANNEL: This interface is currently in offchannel
+ * mode, so queues are stopped
+ */
+enum ieee80211_sdata_state_bits {
+ SDATA_STATE_RUNNING,
+ SDATA_STATE_OFFCHANNEL,
+};
+
struct ieee80211_sub_if_data {
struct list_head list;
@@ -487,6 +530,8 @@ struct ieee80211_sub_if_data {
unsigned int flags;
+ unsigned long state;
+
int drop_unencrypted;
char name[IFNAMSIZ];
@@ -497,17 +542,20 @@ struct ieee80211_sub_if_data {
*/
bool ht_opmode_valid;
+ /* to detect idle changes */
+ bool old_idle;
+
/* Fragment table for host-based reassembly */
struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
unsigned int fragment_next;
-#define NUM_DEFAULT_KEYS 4
-#define NUM_DEFAULT_MGMT_KEYS 2
struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
struct ieee80211_key *default_key;
struct ieee80211_key *default_mgmt_key;
u16 sequence_number;
+ __be16 control_port_protocol;
+ bool control_port_no_encrypt;
struct work_struct work;
struct sk_buff_head skb_queue;
@@ -539,6 +587,7 @@ struct ieee80211_sub_if_data {
#ifdef CONFIG_MAC80211_DEBUGFS
struct {
struct dentry *dir;
+ struct dentry *subdir_stations;
struct dentry *default_key;
struct dentry *default_mgmt_key;
} debugfs;
@@ -595,11 +644,17 @@ enum queue_stop_reason {
* determine if we are on the operating channel or not
* @SCAN_OFF_CHANNEL: We're off our operating channel for scanning,
* gets only set in conjunction with SCAN_SW_SCANNING
+ * @SCAN_COMPLETED: Set for our scan work function when the driver reported
+ * that the scan completed.
+ * @SCAN_ABORTED: Set for our scan work function when the driver reported
+ * a scan complete for an aborted scan.
*/
enum {
SCAN_SW_SCANNING,
SCAN_HW_SCANNING,
SCAN_OFF_CHANNEL,
+ SCAN_COMPLETED,
+ SCAN_ABORTED,
};
/**
@@ -634,7 +689,6 @@ struct ieee80211_local {
/*
* work stuff, potentially off-channel (in the future)
*/
- struct mutex work_mtx;
struct list_head work_list;
struct timer_list work_timer;
struct work_struct work_work;
@@ -653,9 +707,13 @@ struct ieee80211_local {
int open_count;
int monitors, cooked_mntrs;
/* number of interfaces with corresponding FIF_ flags */
- int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll;
+ int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll,
+ fif_probe_req;
+ int probe_req_reg;
unsigned int filter_flags; /* FIF_* */
+ bool wiphy_ciphers_allocated;
+
/* protects the aggregated multicast list and filter calls */
spinlock_t filter_lock;
@@ -746,9 +804,10 @@ struct ieee80211_local {
*/
struct mutex key_mtx;
+ /* mutex for scan and work locking */
+ struct mutex mtx;
/* Scanning and BSS list */
- struct mutex scan_mtx;
unsigned long scanning;
struct cfg80211_ssid scan_ssid;
struct cfg80211_scan_request *int_scan_req;
@@ -866,10 +925,14 @@ struct ieee80211_local {
#ifdef CONFIG_MAC80211_DEBUGFS
struct local_debugfsdentries {
struct dentry *rcdir;
- struct dentry *stations;
struct dentry *keys;
} debugfs;
#endif
+
+ /* dummy netdev for use w/ NAPI */
+ struct net_device napi_dev;
+
+ struct napi_struct napi;
};
static inline struct ieee80211_sub_if_data *
@@ -1003,6 +1066,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
+void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata);
+void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata);
/* IBSS code */
void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
@@ -1068,10 +1133,12 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
void ieee80211_remove_interfaces(struct ieee80211_local *local);
u32 __ieee80211_recalc_idle(struct ieee80211_local *local);
void ieee80211_recalc_idle(struct ieee80211_local *local);
+void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
+ const int offset);
static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
{
- return netif_running(sdata->dev);
+ return test_bit(SDATA_STATE_RUNNING, &sdata->state);
}
/* tx handling */
@@ -1105,12 +1172,13 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps, const u8 *da,
const u8 *bssid);
+void ieee80211_request_smps_work(struct work_struct *work);
void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
- u16 initiator, u16 reason);
+ u16 initiator, u16 reason, bool stop);
void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
- u16 initiator, u16 reason);
-void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta);
+ u16 initiator, u16 reason, bool stop);
+void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx);
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct ieee80211_mgmt *mgmt, size_t len);
@@ -1124,13 +1192,16 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
size_t len);
int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
- enum ieee80211_back_parties initiator);
+ enum ieee80211_back_parties initiator,
+ bool tx);
int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
- enum ieee80211_back_parties initiator);
+ enum ieee80211_back_parties initiator,
+ bool tx);
void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
void ieee80211_ba_session_work(struct work_struct *work);
void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid);
+void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid);
/* Spectrum management */
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
@@ -1146,6 +1217,12 @@ int __ieee80211_suspend(struct ieee80211_hw *hw);
static inline int __ieee80211_resume(struct ieee80211_hw *hw)
{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
+ "%s: resume with hardware scan still in progress\n",
+ wiphy_name(hw->wiphy));
+
return ieee80211_reconfig(hw_to_local(hw));
}
#else
@@ -1208,7 +1285,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
const u8 *key, u8 key_len, u8 key_idx);
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
const u8 *ie, size_t ie_len,
- enum ieee80211_band band);
+ enum ieee80211_band band, u32 rate_mask,
+ u8 channel);
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);
@@ -1221,8 +1299,7 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
enum ieee80211_band band);
int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode);
-void ieee80211_recalc_smps(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *forsdata);
+void ieee80211_recalc_smps(struct ieee80211_local *local);
size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
const u8 *ids, int n_ids, size_t offset);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index ebbe264e2b0b..f9163b12c7f1 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -24,6 +24,7 @@
#include "led.h"
#include "driver-ops.h"
#include "wme.h"
+#include "rate.h"
/**
* DOC: Interface list locking
@@ -94,21 +95,14 @@ static inline int identical_mac_addr_allowed(int type1, int type2)
type2 == NL80211_IFTYPE_AP_VLAN));
}
-static int ieee80211_open(struct net_device *dev)
+static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
+ enum nl80211_iftype iftype)
{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_sub_if_data *nsdata;
struct ieee80211_local *local = sdata->local;
- struct sta_info *sta;
- u32 changed = 0;
- int res;
- u32 hw_reconf_flags = 0;
- u8 null_addr[ETH_ALEN] = {0};
+ struct ieee80211_sub_if_data *nsdata;
+ struct net_device *dev = sdata->dev;
- /* fail early if user set an invalid address */
- if (compare_ether_addr(dev->dev_addr, null_addr) &&
- !is_valid_ether_addr(dev->dev_addr))
- return -EADDRNOTAVAIL;
+ ASSERT_RTNL();
/* we hold the RTNL here so can safely walk the list */
list_for_each_entry(nsdata, &local->interfaces, list) {
@@ -125,7 +119,7 @@ static int ieee80211_open(struct net_device *dev)
* belonging to the same hardware. Then, however, we're
* faced with having to adopt two different TSF timers...
*/
- if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
+ if (iftype == NL80211_IFTYPE_ADHOC &&
nsdata->vif.type == NL80211_IFTYPE_ADHOC)
return -EBUSY;
@@ -139,19 +133,56 @@ static int ieee80211_open(struct net_device *dev)
/*
* check whether it may have the same address
*/
- if (!identical_mac_addr_allowed(sdata->vif.type,
+ if (!identical_mac_addr_allowed(iftype,
nsdata->vif.type))
return -ENOTUNIQ;
/*
* can only add VLANs to enabled APs
*/
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+ if (iftype == NL80211_IFTYPE_AP_VLAN &&
nsdata->vif.type == NL80211_IFTYPE_AP)
sdata->bss = &nsdata->u.ap;
}
}
+ return 0;
+}
+
+void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
+ const int offset)
+{
+ struct ieee80211_local *local = sdata->local;
+ u32 flags = sdata->u.mntr_flags;
+
+#define ADJUST(_f, _s) do { \
+ if (flags & MONITOR_FLAG_##_f) \
+ local->fif_##_s += offset; \
+ } while (0)
+
+ ADJUST(FCSFAIL, fcsfail);
+ ADJUST(PLCPFAIL, plcpfail);
+ ADJUST(CONTROL, control);
+ ADJUST(CONTROL, pspoll);
+ ADJUST(OTHER_BSS, other_bss);
+
+#undef ADJUST
+}
+
+/*
+ * NOTE: Be very careful when changing this function, it must NOT return
+ * an error on interface type changes that have been pre-checked, so most
+ * checks should be in ieee80211_check_concurrent_iface.
+ */
+static int ieee80211_do_open(struct net_device *dev, bool coming_up)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
+ u32 changed = 0;
+ int res;
+ u32 hw_reconf_flags = 0;
+
switch (sdata->vif.type) {
case NL80211_IFTYPE_WDS:
if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
@@ -177,7 +208,9 @@ static int ieee80211_open(struct net_device *dev)
/* no special treatment */
break;
case NL80211_IFTYPE_UNSPECIFIED:
- case __NL80211_IFTYPE_AFTER_LAST:
+ case NUM_NL80211_IFTYPES:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
/* cannot happen */
WARN_ON(1);
break;
@@ -187,39 +220,30 @@ static int ieee80211_open(struct net_device *dev)
res = drv_start(local);
if (res)
goto err_del_bss;
+ if (local->ops->napi_poll)
+ napi_enable(&local->napi);
/* we're brought up, everything changes */
hw_reconf_flags = ~0;
ieee80211_led_radio(local, true);
}
/*
- * Check all interfaces and copy the hopefully now-present
- * MAC address to those that have the special null one.
+ * Copy the hopefully now-present MAC address to
+ * this interface, if it has the special null one.
*/
- list_for_each_entry(nsdata, &local->interfaces, list) {
- struct net_device *ndev = nsdata->dev;
-
- /*
- * No need to check running since we do not allow
- * it to start up with this invalid address.
- */
- if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) {
- memcpy(ndev->dev_addr,
- local->hw.wiphy->perm_addr,
- ETH_ALEN);
- memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN);
+ if (is_zero_ether_addr(dev->dev_addr)) {
+ memcpy(dev->dev_addr,
+ local->hw.wiphy->perm_addr,
+ ETH_ALEN);
+ memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
+
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ if (!local->open_count)
+ drv_stop(local);
+ return -EADDRNOTAVAIL;
}
}
- /*
- * Validate the MAC address for this device.
- */
- if (!is_valid_ether_addr(dev->dev_addr)) {
- if (!local->open_count)
- drv_stop(local);
- return -EADDRNOTAVAIL;
- }
-
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
/* no need to tell driver */
@@ -237,25 +261,17 @@ static int ieee80211_open(struct net_device *dev)
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
}
- if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
- local->fif_fcsfail++;
- if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
- local->fif_plcpfail++;
- if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) {
- local->fif_control++;
- local->fif_pspoll++;
- }
- if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
- local->fif_other_bss++;
-
+ ieee80211_adjust_monitor_flags(sdata, 1);
ieee80211_configure_filter(local);
netif_carrier_on(dev);
break;
default:
- res = drv_add_interface(local, &sdata->vif);
- if (res)
- goto err_stop;
+ if (coming_up) {
+ res = drv_add_interface(local, &sdata->vif);
+ if (res)
+ goto err_stop;
+ }
if (ieee80211_vif_is_mesh(&sdata->vif)) {
local->fif_other_bss++;
@@ -264,8 +280,11 @@ static int ieee80211_open(struct net_device *dev)
ieee80211_start_mesh(sdata);
} else if (sdata->vif.type == NL80211_IFTYPE_AP) {
local->fif_pspoll++;
+ local->fif_probe_req++;
ieee80211_configure_filter(local);
+ } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+ local->fif_probe_req++;
}
changed |= ieee80211_reset_erp_info(sdata);
@@ -277,6 +296,8 @@ static int ieee80211_open(struct net_device *dev)
netif_carrier_on(dev);
}
+ set_bit(SDATA_STATE_RUNNING, &sdata->state);
+
if (sdata->vif.type == NL80211_IFTYPE_WDS) {
/* Create STA entry for the WDS peer */
sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
@@ -294,6 +315,8 @@ static int ieee80211_open(struct net_device *dev)
/* STA has been freed */
goto err_del_interface;
}
+
+ rate_control_rate_init(sta);
}
/*
@@ -307,9 +330,13 @@ static int ieee80211_open(struct net_device *dev)
if (sdata->flags & IEEE80211_SDATA_PROMISC)
atomic_inc(&local->iff_promiscs);
+ mutex_lock(&local->mtx);
hw_reconf_flags |= __ieee80211_recalc_idle(local);
+ mutex_unlock(&local->mtx);
+
+ if (coming_up)
+ local->open_count++;
- local->open_count++;
if (hw_reconf_flags) {
ieee80211_hw_config(local, hw_reconf_flags);
/*
@@ -334,22 +361,42 @@ static int ieee80211_open(struct net_device *dev)
sdata->bss = NULL;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
list_del(&sdata->u.vlan.list);
+ clear_bit(SDATA_STATE_RUNNING, &sdata->state);
return res;
}
-static int ieee80211_stop(struct net_device *dev)
+static int ieee80211_open(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ int err;
+
+ /* fail early if user set an invalid address */
+ if (!is_zero_ether_addr(dev->dev_addr) &&
+ !is_valid_ether_addr(dev->dev_addr))
+ return -EADDRNOTAVAIL;
+
+ err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type);
+ if (err)
+ return err;
+
+ return ieee80211_do_open(dev, true);
+}
+
+static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
+ bool going_down)
+{
struct ieee80211_local *local = sdata->local;
unsigned long flags;
struct sk_buff *skb, *tmp;
u32 hw_reconf_flags = 0;
int i;
+ clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+
/*
* Stop TX on this interface first.
*/
- netif_tx_stop_all_queues(dev);
+ netif_tx_stop_all_queues(sdata->dev);
/*
* Purge work for this interface.
@@ -366,12 +413,9 @@ static int ieee80211_stop(struct net_device *dev)
* (because if we remove a STA after ops->remove_interface()
* the driver will have removed the vif info already!)
*
- * We could relax this and only unlink the stations from the
- * hash table and list but keep them on a per-sdata list that
- * will be inserted back again when the interface is brought
- * up again, but I don't currently see a use case for that,
- * except with WDS which gets a STA entry created when it is
- * brought up.
+ * This is relevant only in AP, WDS and mesh modes, since in
+ * all other modes we've already removed all stations when
+ * disconnecting etc.
*/
sta_info_flush(local, sdata);
@@ -387,14 +431,19 @@ static int ieee80211_stop(struct net_device *dev)
if (sdata->flags & IEEE80211_SDATA_PROMISC)
atomic_dec(&local->iff_promiscs);
- if (sdata->vif.type == NL80211_IFTYPE_AP)
+ if (sdata->vif.type == NL80211_IFTYPE_AP) {
local->fif_pspoll--;
+ local->fif_probe_req--;
+ } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+ local->fif_probe_req--;
+ }
- netif_addr_lock_bh(dev);
+ netif_addr_lock_bh(sdata->dev);
spin_lock_bh(&local->filter_lock);
- __hw_addr_unsync(&local->mc_list, &dev->mc, dev->addr_len);
+ __hw_addr_unsync(&local->mc_list, &sdata->dev->mc,
+ sdata->dev->addr_len);
spin_unlock_bh(&local->filter_lock);
- netif_addr_unlock_bh(dev);
+ netif_addr_unlock_bh(sdata->dev);
ieee80211_configure_filter(local);
@@ -406,11 +455,21 @@ static int ieee80211_stop(struct net_device *dev)
struct ieee80211_sub_if_data *vlan, *tmpsdata;
struct beacon_data *old_beacon = sdata->u.ap.beacon;
+ /* sdata_running will return false, so this will disable */
+ ieee80211_bss_info_change_notify(sdata,
+ BSS_CHANGED_BEACON_ENABLED);
+
/* remove beacon */
rcu_assign_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)
@@ -418,7 +477,8 @@ static int ieee80211_stop(struct net_device *dev)
WARN_ON(!list_empty(&sdata->u.ap.vlans));
}
- local->open_count--;
+ if (going_down)
+ local->open_count--;
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
@@ -437,40 +497,9 @@ static int ieee80211_stop(struct net_device *dev)
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
}
- if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
- local->fif_fcsfail--;
- if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
- local->fif_plcpfail--;
- if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) {
- local->fif_pspoll--;
- local->fif_control--;
- }
- if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
- local->fif_other_bss--;
-
+ ieee80211_adjust_monitor_flags(sdata, -1);
ieee80211_configure_filter(local);
break;
- case NL80211_IFTYPE_STATION:
- del_timer_sync(&sdata->u.mgd.chswitch_timer);
- del_timer_sync(&sdata->u.mgd.timer);
- del_timer_sync(&sdata->u.mgd.conn_mon_timer);
- del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
- /*
- * If any of the timers fired while we waited for it, it will
- * have queued its work. Now the work will be running again
- * but will not rearm the timer again because it checks
- * whether the interface is running, which, at this point,
- * it no longer is.
- */
- cancel_work_sync(&sdata->u.mgd.chswitch_work);
- cancel_work_sync(&sdata->u.mgd.monitor_work);
- cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work);
-
- /* fall through */
- case NL80211_IFTYPE_ADHOC:
- if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
- del_timer_sync(&sdata->u.ibss.timer);
- /* fall through */
case NL80211_IFTYPE_MESH_POINT:
if (ieee80211_vif_is_mesh(&sdata->vif)) {
/* other_bss and allmulti are always set on mesh
@@ -498,27 +527,34 @@ static int ieee80211_stop(struct net_device *dev)
ieee80211_scan_cancel(local);
/*
- * Disable beaconing for AP and mesh, IBSS can't
- * still be joined to a network at this point.
+ * Disable beaconing here for mesh only, AP and IBSS
+ * are already taken care of.
*/
- if (sdata->vif.type == NL80211_IFTYPE_AP ||
- sdata->vif.type == NL80211_IFTYPE_MESH_POINT) {
+ if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_BEACON_ENABLED);
- }
- /* free all remaining keys, there shouldn't be any */
+ /*
+ * Free all remaining keys, there shouldn't be any,
+ * except maybe group keys in AP more or WDS?
+ */
ieee80211_free_keys(sdata);
- drv_remove_interface(local, &sdata->vif);
+
+ if (going_down)
+ drv_remove_interface(local, &sdata->vif);
}
sdata->bss = NULL;
+ mutex_lock(&local->mtx);
hw_reconf_flags |= __ieee80211_recalc_idle(local);
+ mutex_unlock(&local->mtx);
ieee80211_recalc_ps(local, -1);
if (local->open_count == 0) {
+ if (local->ops->napi_poll)
+ napi_disable(&local->napi);
ieee80211_clear_tx_pending(local);
ieee80211_stop_device(local);
@@ -541,6 +577,13 @@ static int ieee80211_stop(struct net_device *dev)
}
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+}
+
+static int ieee80211_stop(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ ieee80211_do_stop(sdata, true);
return 0;
}
@@ -585,8 +628,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
- struct beacon_data *beacon;
- struct sk_buff *skb;
int flushed;
int i;
@@ -599,37 +640,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
__skb_queue_purge(&sdata->fragments[i].skb_list);
sdata->fragment_next = 0;
- switch (sdata->vif.type) {
- case NL80211_IFTYPE_AP:
- beacon = sdata->u.ap.beacon;
- rcu_assign_pointer(sdata->u.ap.beacon, NULL);
- synchronize_rcu();
- kfree(beacon);
-
- while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
- local->total_ps_buffered--;
- dev_kfree_skb(skb);
- }
-
- break;
- case NL80211_IFTYPE_MESH_POINT:
- if (ieee80211_vif_is_mesh(&sdata->vif))
- mesh_rmc_free(sdata);
- break;
- case NL80211_IFTYPE_ADHOC:
- if (WARN_ON(sdata->u.ibss.presp))
- kfree_skb(sdata->u.ibss.presp);
- break;
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_WDS:
- case NL80211_IFTYPE_AP_VLAN:
- case NL80211_IFTYPE_MONITOR:
- break;
- case NL80211_IFTYPE_UNSPECIFIED:
- case __NL80211_IFTYPE_AFTER_LAST:
- BUG();
- break;
- }
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ mesh_rmc_free(sdata);
flushed = sta_info_flush(local, sdata);
WARN_ON(flushed);
@@ -791,7 +803,8 @@ static void ieee80211_iface_work(struct work_struct *work)
__ieee80211_stop_rx_ba_session(
sta, tid, WLAN_BACK_RECIPIENT,
- WLAN_REASON_QSTA_REQUIRE_SETUP);
+ WLAN_REASON_QSTA_REQUIRE_SETUP,
+ true);
}
mutex_unlock(&local->sta_mtx);
} else switch (sdata->vif.type) {
@@ -844,9 +857,13 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
/* and set some type-dependent values */
sdata->vif.type = type;
+ sdata->vif.p2p = false;
sdata->dev->netdev_ops = &ieee80211_dataif_ops;
sdata->wdev.iftype = type;
+ sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE);
+ sdata->control_port_no_encrypt = false;
+
/* only monitor differs */
sdata->dev->type = ARPHRD_ETHER;
@@ -854,10 +871,20 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
INIT_WORK(&sdata->work, ieee80211_iface_work);
switch (type) {
+ case NL80211_IFTYPE_P2P_GO:
+ type = NL80211_IFTYPE_AP;
+ sdata->vif.type = type;
+ sdata->vif.p2p = true;
+ /* fall through */
case NL80211_IFTYPE_AP:
skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
INIT_LIST_HEAD(&sdata->u.ap.vlans);
break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ type = NL80211_IFTYPE_STATION;
+ sdata->vif.type = type;
+ sdata->vif.p2p = true;
+ /* fall through */
case NL80211_IFTYPE_STATION:
ieee80211_sta_setup_sdata(sdata);
break;
@@ -878,7 +905,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_AP_VLAN:
break;
case NL80211_IFTYPE_UNSPECIFIED:
- case __NL80211_IFTYPE_AFTER_LAST:
+ case NUM_NL80211_IFTYPES:
BUG();
break;
}
@@ -886,12 +913,85 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
ieee80211_debugfs_add_netdev(sdata);
}
+static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
+ enum nl80211_iftype type)
+{
+ struct ieee80211_local *local = sdata->local;
+ int ret, err;
+ enum nl80211_iftype internal_type = type;
+ bool p2p = false;
+
+ ASSERT_RTNL();
+
+ if (!local->ops->change_interface)
+ return -EBUSY;
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ /*
+ * Could maybe also all others here?
+ * Just not sure how that interacts
+ * with the RX/config path e.g. for
+ * mesh.
+ */
+ break;
+ default:
+ return -EBUSY;
+ }
+
+ switch (type) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ /*
+ * Could probably support everything
+ * but WDS here (WDS do_open can fail
+ * under memory pressure, which this
+ * code isn't prepared to handle).
+ */
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ p2p = true;
+ internal_type = NL80211_IFTYPE_STATION;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ p2p = true;
+ internal_type = NL80211_IFTYPE_AP;
+ break;
+ default:
+ return -EBUSY;
+ }
+
+ ret = ieee80211_check_concurrent_iface(sdata, internal_type);
+ if (ret)
+ return ret;
+
+ ieee80211_do_stop(sdata, false);
+
+ ieee80211_teardown_sdata(sdata->dev);
+
+ ret = drv_change_interface(local, sdata, internal_type, p2p);
+ if (ret)
+ type = sdata->vif.type;
+
+ ieee80211_setup_sdata(sdata, type);
+
+ err = ieee80211_do_open(sdata->dev, false);
+ WARN(err, "type change: do_open returned %d", err);
+
+ return ret;
+}
+
int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
enum nl80211_iftype type)
{
+ int ret;
+
ASSERT_RTNL();
- if (type == sdata->vif.type)
+ if (type == ieee80211_vif_type_p2p(&sdata->vif))
return 0;
/* Setting ad-hoc mode on non-IBSS channel is not supported. */
@@ -899,18 +999,15 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
type == NL80211_IFTYPE_ADHOC)
return -EOPNOTSUPP;
- /*
- * We could, here, on changes between IBSS/STA/MESH modes,
- * invoke an MLME function instead that disassociates etc.
- * and goes into the requested mode.
- */
-
- if (ieee80211_sdata_running(sdata))
- return -EBUSY;
-
- /* Purge and reset type-dependent state. */
- ieee80211_teardown_sdata(sdata->dev);
- ieee80211_setup_sdata(sdata, type);
+ if (ieee80211_sdata_running(sdata)) {
+ ret = ieee80211_runtime_change_iftype(sdata, type);
+ if (ret)
+ return ret;
+ } else {
+ /* Purge and reset type-dependent state. */
+ ieee80211_teardown_sdata(sdata->dev);
+ ieee80211_setup_sdata(sdata, type);
+ }
/* reset some values that shouldn't be kept across type changes */
sdata->vif.bss_conf.basic_rates =
@@ -1167,8 +1264,7 @@ static u32 ieee80211_idle_off(struct ieee80211_local *local,
return 0;
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: device no longer idle - %s\n",
- wiphy_name(local->hw.wiphy), reason);
+ wiphy_debug(local->hw.wiphy, "device no longer idle - %s\n", reason);
#endif
local->hw.conf.flags &= ~IEEE80211_CONF_IDLE;
@@ -1181,8 +1277,7 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
return 0;
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: device now idle\n",
- wiphy_name(local->hw.wiphy));
+ wiphy_debug(local->hw.wiphy, "device now idle\n");
#endif
drv_flush(local, false);
@@ -1195,28 +1290,61 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
int count = 0;
+ bool working = false, scanning = false;
+ struct ieee80211_work *wk;
- if (!list_empty(&local->work_list))
- return ieee80211_idle_off(local, "working");
-
- if (local->scanning)
- return ieee80211_idle_off(local, "scanning");
+#ifdef CONFIG_PROVE_LOCKING
+ WARN_ON(debug_locks && !lockdep_rtnl_is_held() &&
+ !lockdep_is_held(&local->iflist_mtx));
+#endif
+ lockdep_assert_held(&local->mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
- if (!ieee80211_sdata_running(sdata))
+ if (!ieee80211_sdata_running(sdata)) {
+ sdata->vif.bss_conf.idle = true;
continue;
+ }
+
+ sdata->old_idle = sdata->vif.bss_conf.idle;
+
/* do not count disabled managed interfaces */
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
- !sdata->u.mgd.associated)
+ !sdata->u.mgd.associated) {
+ sdata->vif.bss_conf.idle = true;
continue;
+ }
/* do not count unused IBSS interfaces */
if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
- !sdata->u.ibss.ssid_len)
+ !sdata->u.ibss.ssid_len) {
+ sdata->vif.bss_conf.idle = true;
continue;
+ }
/* count everything else */
count++;
}
+ list_for_each_entry(wk, &local->work_list, list) {
+ working = true;
+ wk->sdata->vif.bss_conf.idle = false;
+ }
+
+ if (local->scan_sdata) {
+ scanning = true;
+ local->scan_sdata->vif.bss_conf.idle = false;
+ }
+
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->old_idle == sdata->vif.bss_conf.idle)
+ continue;
+ if (!ieee80211_sdata_running(sdata))
+ continue;
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
+ }
+
+ if (working)
+ return ieee80211_idle_off(local, "working");
+ if (scanning)
+ return ieee80211_idle_off(local, "scanning");
if (!count)
return ieee80211_idle_on(local);
else
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 1b9d87ed143a..ccd676b2f599 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -49,7 +49,7 @@ static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
static void assert_key_lock(struct ieee80211_local *local)
{
- WARN_ON(!mutex_is_locked(&local->key_mtx));
+ lockdep_assert_held(&local->key_mtx);
}
static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key)
@@ -60,7 +60,7 @@ static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key)
return NULL;
}
-static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
+static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
{
struct ieee80211_sub_if_data *sdata;
struct ieee80211_sta *sta;
@@ -69,12 +69,20 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
might_sleep();
if (!key->local->ops->set_key)
- return;
+ goto out_unsupported;
assert_key_lock(key->local);
sta = get_sta_for_key(key);
+ /*
+ * If this is a per-STA GTK, check if it
+ * is supported; if not, return.
+ */
+ if (sta && !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE) &&
+ !(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK))
+ goto out_unsupported;
+
sdata = key->sdata;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
@@ -83,14 +91,28 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
- if (!ret)
+ if (!ret) {
key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
+ return 0;
+ }
- if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
- printk(KERN_ERR "mac80211-%s: failed to set key "
- "(%d, %pM) to hardware (%d)\n",
- wiphy_name(key->local->hw.wiphy),
- key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
+ if (ret != -ENOSPC && ret != -EOPNOTSUPP)
+ wiphy_err(key->local->hw.wiphy,
+ "failed to set key (%d, %pM) to hardware (%d)\n",
+ key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
+
+ out_unsupported:
+ switch (key->conf.cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ case WLAN_CIPHER_SUITE_TKIP:
+ case WLAN_CIPHER_SUITE_CCMP:
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ /* all of these we can do in software */
+ return 0;
+ default:
+ return -EINVAL;
+ }
}
static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
@@ -121,14 +143,33 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
sta, &key->conf);
if (ret)
- printk(KERN_ERR "mac80211-%s: failed to remove key "
- "(%d, %pM) from hardware (%d)\n",
- wiphy_name(key->local->hw.wiphy),
- key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
+ wiphy_err(key->local->hw.wiphy,
+ "failed to remove key (%d, %pM) from hardware (%d)\n",
+ key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
}
+void ieee80211_key_removed(struct ieee80211_key_conf *key_conf)
+{
+ struct ieee80211_key *key;
+
+ key = container_of(key_conf, struct ieee80211_key, conf);
+
+ might_sleep();
+ assert_key_lock(key->local);
+
+ key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
+
+ /*
+ * Flush TX path to avoid attempts to use this key
+ * after this function returns. Until then, drivers
+ * must be prepared to handle the key.
+ */
+ synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(ieee80211_key_removed);
+
static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
int idx)
{
@@ -184,6 +225,7 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
+ bool pairwise,
struct ieee80211_key *old,
struct ieee80211_key *new)
{
@@ -192,8 +234,14 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
if (new)
list_add(&new->list, &sdata->key_list);
- if (sta) {
- rcu_assign_pointer(sta->key, new);
+ if (sta && pairwise) {
+ rcu_assign_pointer(sta->ptk, new);
+ } else if (sta) {
+ if (old)
+ idx = old->conf.keyidx;
+ else
+ idx = new->conf.keyidx;
+ rcu_assign_pointer(sta->gtk[idx], new);
} else {
WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
@@ -227,20 +275,18 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
}
}
-struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
- int idx,
- size_t key_len,
+struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
const u8 *key_data,
size_t seq_len, const u8 *seq)
{
struct ieee80211_key *key;
- int i, j;
+ int i, j, err;
BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS);
key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL);
if (!key)
- return NULL;
+ return ERR_PTR(-ENOMEM);
/*
* Default to software encryption; we'll later upload the
@@ -249,15 +295,16 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
key->conf.flags = 0;
key->flags = 0;
- key->conf.alg = alg;
+ key->conf.cipher = cipher;
key->conf.keyidx = idx;
key->conf.keylen = key_len;
- switch (alg) {
- case ALG_WEP:
+ switch (cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
key->conf.iv_len = WEP_IV_LEN;
key->conf.icv_len = WEP_ICV_LEN;
break;
- case ALG_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
key->conf.iv_len = TKIP_IV_LEN;
key->conf.icv_len = TKIP_ICV_LEN;
if (seq) {
@@ -269,7 +316,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
}
}
break;
- case ALG_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
key->conf.iv_len = CCMP_HDR_LEN;
key->conf.icv_len = CCMP_MIC_LEN;
if (seq) {
@@ -278,42 +325,38 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
key->u.ccmp.rx_pn[i][j] =
seq[CCMP_PN_LEN - j - 1];
}
- break;
- case ALG_AES_CMAC:
- key->conf.iv_len = 0;
- key->conf.icv_len = sizeof(struct ieee80211_mmie);
- if (seq)
- for (j = 0; j < 6; j++)
- key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1];
- break;
- }
- memcpy(key->conf.key, key_data, key_len);
- INIT_LIST_HEAD(&key->list);
-
- if (alg == ALG_CCMP) {
/*
* Initialize AES key state here as an optimization so that
* it does not need to be initialized for every packet.
*/
key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data);
- if (!key->u.ccmp.tfm) {
+ if (IS_ERR(key->u.ccmp.tfm)) {
+ err = PTR_ERR(key->u.ccmp.tfm);
kfree(key);
- return NULL;
+ key = ERR_PTR(err);
}
- }
-
- if (alg == ALG_AES_CMAC) {
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ key->conf.iv_len = 0;
+ key->conf.icv_len = sizeof(struct ieee80211_mmie);
+ if (seq)
+ for (j = 0; j < 6; j++)
+ key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1];
/*
* Initialize AES key state here as an optimization so that
* it does not need to be initialized for every packet.
*/
key->u.aes_cmac.tfm =
ieee80211_aes_cmac_key_setup(key_data);
- if (!key->u.aes_cmac.tfm) {
+ if (IS_ERR(key->u.aes_cmac.tfm)) {
+ err = PTR_ERR(key->u.aes_cmac.tfm);
kfree(key);
- return NULL;
+ key = ERR_PTR(err);
}
+ break;
}
+ memcpy(key->conf.key, key_data, key_len);
+ INIT_LIST_HEAD(&key->list);
return key;
}
@@ -326,9 +369,9 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
if (key->local)
ieee80211_key_disable_hw_accel(key);
- if (key->conf.alg == ALG_CCMP)
+ if (key->conf.cipher == WLAN_CIPHER_SUITE_CCMP)
ieee80211_aes_key_free(key->u.ccmp.tfm);
- if (key->conf.alg == ALG_AES_CMAC)
+ if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
if (key->local)
ieee80211_debugfs_key_remove(key);
@@ -336,12 +379,13 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
kfree(key);
}
-void ieee80211_key_link(struct ieee80211_key *key,
- struct ieee80211_sub_if_data *sdata,
- struct sta_info *sta)
+int ieee80211_key_link(struct ieee80211_key *key,
+ struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta)
{
struct ieee80211_key *old_key;
- int idx;
+ int idx, ret;
+ bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
BUG_ON(!sdata);
BUG_ON(!key);
@@ -358,13 +402,6 @@ void ieee80211_key_link(struct ieee80211_key *key,
*/
if (test_sta_flags(sta, WLAN_STA_WME))
key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
-
- /*
- * This key is for a specific sta interface,
- * inform the driver that it should try to store
- * this key as pairwise key.
- */
- key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
} else {
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
struct sta_info *ap;
@@ -386,19 +423,23 @@ void ieee80211_key_link(struct ieee80211_key *key,
mutex_lock(&sdata->local->key_mtx);
- if (sta)
- old_key = sta->key;
+ if (sta && pairwise)
+ old_key = sta->ptk;
+ else if (sta)
+ old_key = sta->gtk[idx];
else
old_key = sdata->keys[idx];
- __ieee80211_key_replace(sdata, sta, old_key, key);
+ __ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
__ieee80211_key_destroy(old_key);
ieee80211_debugfs_key_add(key);
- ieee80211_key_enable_hw_accel(key);
+ ret = ieee80211_key_enable_hw_accel(key);
mutex_unlock(&sdata->local->key_mtx);
+
+ return ret;
}
static void __ieee80211_key_free(struct ieee80211_key *key)
@@ -408,7 +449,8 @@ static void __ieee80211_key_free(struct ieee80211_key *key)
*/
if (key->sdata)
__ieee80211_key_replace(key->sdata, key->sta,
- key, NULL);
+ key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
+ key, NULL);
__ieee80211_key_destroy(key);
}
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index b665bbb7a471..0db1c0f5f697 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -16,6 +16,9 @@
#include <linux/rcupdate.h>
#include <net/mac80211.h>
+#define NUM_DEFAULT_KEYS 4
+#define NUM_DEFAULT_MGMT_KEYS 2
+
#define WEP_IV_LEN 4
#define WEP_ICV_LEN 4
#define ALG_TKIP_KEY_LEN 32
@@ -123,18 +126,16 @@ struct ieee80211_key {
struct ieee80211_key_conf conf;
};
-struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
- int idx,
- size_t key_len,
+struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
const u8 *key_data,
size_t seq_len, const u8 *seq);
/*
* Insert a key into data structures (sdata, sta if necessary)
* to make it used, free old key.
*/
-void ieee80211_key_link(struct ieee80211_key *key,
- struct ieee80211_sub_if_data *sdata,
- struct sta_info *sta);
+int __must_check ieee80211_key_link(struct ieee80211_key *key,
+ struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta);
void ieee80211_key_free(struct ieee80211_local *local,
struct ieee80211_key *key);
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index ded5c3843e06..6b322fa681f5 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -54,6 +54,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
if (local->monitors || local->scanning)
new_flags |= FIF_BCN_PRBRESP_PROMISC;
+ if (local->fif_probe_req || local->probe_req_reg)
+ new_flags |= FIF_PROBE_REQ;
+
if (local->fif_fcsfail)
new_flags |= FIF_FCSFAIL;
@@ -99,16 +102,19 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
int ret = 0;
int power;
enum nl80211_channel_type channel_type;
+ u32 offchannel_flag;
might_sleep();
scan_chan = local->scan_channel;
+ offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
if (scan_chan) {
chan = scan_chan;
channel_type = NL80211_CHAN_NO_HT;
local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
- } else if (local->tmp_channel) {
+ } else if (local->tmp_channel &&
+ local->oper_channel != local->tmp_channel) {
chan = scan_chan = local->tmp_channel;
channel_type = local->tmp_channel_type;
local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
@@ -117,8 +123,9 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
channel_type = local->_oper_channel_type;
local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL;
}
+ offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
- if (chan != local->hw.conf.channel ||
+ if (offchannel_flag || chan != local->hw.conf.channel ||
channel_type != local->hw.conf.channel_type) {
local->hw.conf.channel = chan;
local->hw.conf.channel_type = channel_type;
@@ -197,6 +204,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
else if (sdata->vif.type == NL80211_IFTYPE_AP)
sdata->vif.bss_conf.bssid = sdata->vif.addr;
+ else if (sdata->vif.type == NL80211_IFTYPE_WDS)
+ sdata->vif.bss_conf.bssid = NULL;
else if (ieee80211_vif_is_mesh(&sdata->vif)) {
sdata->vif.bss_conf.bssid = zero;
} else {
@@ -207,6 +216,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_MESH_POINT:
break;
default:
@@ -291,7 +301,16 @@ static void ieee80211_restart_work(struct work_struct *work)
struct ieee80211_local *local =
container_of(work, struct ieee80211_local, restart_work);
+ /* wait for scan work complete */
+ flush_workqueue(local->workqueue);
+
+ mutex_lock(&local->mtx);
+ WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
+ "%s called with hardware scan in progress\n", __func__);
+ mutex_unlock(&local->mtx);
+
rtnl_lock();
+ ieee80211_scan_cancel(local);
ieee80211_reconfig(local);
rtnl_unlock();
}
@@ -302,7 +321,7 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
trace_api_restart_hw(local);
- /* use this reason, __ieee80211_resume will unblock it */
+ /* use this reason, ieee80211_reconfig will unblock it */
ieee80211_stop_queues_by_reason(hw,
IEEE80211_QUEUE_STOP_REASON_SUSPEND);
@@ -316,7 +335,7 @@ static void ieee80211_recalc_smps_work(struct work_struct *work)
container_of(work, struct ieee80211_local, recalc_smps);
mutex_lock(&local->iflist_mtx);
- ieee80211_recalc_smps(local, NULL);
+ ieee80211_recalc_smps(local);
mutex_unlock(&local->iflist_mtx);
}
@@ -336,9 +355,6 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
struct ieee80211_if_managed *ifmgd;
int c = 0;
- if (!netif_running(ndev))
- return NOTIFY_DONE;
-
/* Make sure it's our interface that got changed */
if (!wdev)
return NOTIFY_DONE;
@@ -349,11 +365,14 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
bss_conf = &sdata->vif.bss_conf;
+ if (!ieee80211_sdata_running(sdata))
+ return NOTIFY_DONE;
+
/* ARP filtering is only supported in managed mode */
if (sdata->vif.type != NL80211_IFTYPE_STATION)
return NOTIFY_DONE;
- idev = sdata->dev->ip_ptr;
+ idev = __in_dev_get_rtnl(sdata->dev);
if (!idev)
return NOTIFY_DONE;
@@ -390,6 +409,80 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
}
#endif
+static int ieee80211_napi_poll(struct napi_struct *napi, int budget)
+{
+ struct ieee80211_local *local =
+ container_of(napi, struct ieee80211_local, napi);
+
+ return local->ops->napi_poll(&local->hw, budget);
+}
+
+void ieee80211_napi_schedule(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ napi_schedule(&local->napi);
+}
+EXPORT_SYMBOL(ieee80211_napi_schedule);
+
+void ieee80211_napi_complete(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ napi_complete(&local->napi);
+}
+EXPORT_SYMBOL(ieee80211_napi_complete);
+
+/* There isn't a lot of sense in it, but you can transmit anything you like */
+static const struct ieee80211_txrx_stypes
+ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_ADHOC] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4),
+ },
+ [NL80211_IFTYPE_STATION] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
+ },
+ [NL80211_IFTYPE_AP] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4),
+ },
+ [NL80211_IFTYPE_AP_VLAN] = {
+ /* copy AP */
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4),
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
+ },
+ [NL80211_IFTYPE_P2P_GO] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4),
+ },
+};
+
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
const struct ieee80211_ops *ops)
{
@@ -419,6 +512,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
if (!wiphy)
return NULL;
+ wiphy->mgmt_stypes = ieee80211_default_mgmt_stypes;
+
wiphy->flags |= WIPHY_FLAG_NETNS_OK |
WIPHY_FLAG_4ADDR_AP |
WIPHY_FLAG_4ADDR_STATION;
@@ -444,6 +539,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
/* set up some defaults */
local->hw.queues = 1;
local->hw.max_rates = 1;
+ local->hw.max_report_rates = 0;
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;
@@ -455,7 +551,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
__hw_addr_init(&local->mc_list);
mutex_init(&local->iflist_mtx);
- mutex_init(&local->scan_mtx);
+ mutex_init(&local->mtx);
mutex_init(&local->key_mtx);
spin_lock_init(&local->filter_lock);
@@ -494,6 +590,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
skb_queue_head_init(&local->skb_queue);
skb_queue_head_init(&local->skb_queue_unreliable);
+ /* init dummy netdev for use w/ NAPI */
+ init_dummy_netdev(&local->napi_dev);
+
return local_to_hw(local);
}
EXPORT_SYMBOL(ieee80211_alloc_hw);
@@ -506,6 +605,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
int channels, max_bitrates;
bool supp_ht;
static const u32 cipher_suites[] = {
+ /* keep WEP first, it may be removed below */
WLAN_CIPHER_SUITE_WEP40,
WLAN_CIPHER_SUITE_WEP104,
WLAN_CIPHER_SUITE_TKIP,
@@ -515,6 +615,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
WLAN_CIPHER_SUITE_AES_CMAC
};
+ if (hw->max_report_rates == 0)
+ hw->max_report_rates = hw->max_rates;
+
/*
* generic code guarantees at least one band,
* set this very early because much code assumes
@@ -554,6 +657,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
/* mac80211 always supports monitor */
local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+#ifndef CONFIG_MAC80211_MESH
+ /* mesh depends on Kconfig, but drivers should set it if they want */
+ local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT);
+#endif
+
+ /* mac80211 supports control port protocol changing */
+ local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL;
+
if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
@@ -589,10 +700,41 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (local->hw.wiphy->max_scan_ie_len)
local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;
- local->hw.wiphy->cipher_suites = cipher_suites;
- local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
- if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))
- local->hw.wiphy->n_cipher_suites--;
+ /* Set up cipher suites unless driver already did */
+ if (!local->hw.wiphy->cipher_suites) {
+ local->hw.wiphy->cipher_suites = cipher_suites;
+ local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+ if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))
+ local->hw.wiphy->n_cipher_suites--;
+ }
+ if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) {
+ if (local->hw.wiphy->cipher_suites == cipher_suites) {
+ local->hw.wiphy->cipher_suites += 2;
+ local->hw.wiphy->n_cipher_suites -= 2;
+ } else {
+ u32 *suites;
+ int r, w = 0;
+
+ /* Filter out WEP */
+
+ suites = kmemdup(
+ local->hw.wiphy->cipher_suites,
+ sizeof(u32) * local->hw.wiphy->n_cipher_suites,
+ GFP_KERNEL);
+ if (!suites)
+ return -ENOMEM;
+ for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {
+ u32 suite = local->hw.wiphy->cipher_suites[r];
+ if (suite == WLAN_CIPHER_SUITE_WEP40 ||
+ suite == WLAN_CIPHER_SUITE_WEP104)
+ continue;
+ suites[w++] = suite;
+ }
+ local->hw.wiphy->cipher_suites = suites;
+ local->hw.wiphy->n_cipher_suites = w;
+ local->wiphy_ciphers_allocated = true;
+ }
+ }
result = wiphy_register(local->hw.wiphy);
if (result < 0)
@@ -606,7 +748,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
hw->queues = IEEE80211_MAX_QUEUES;
local->workqueue =
- create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
+ alloc_ordered_workqueue(wiphy_name(local->hw.wiphy), 0);
if (!local->workqueue) {
result = -ENOMEM;
goto fail_workqueue;
@@ -641,16 +783,16 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
result = ieee80211_wep_init(local);
if (result < 0)
- printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n",
- wiphy_name(local->hw.wiphy), result);
+ wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
+ result);
rtnl_lock();
result = ieee80211_init_rate_ctrl_alg(local,
hw->rate_control_algorithm);
if (result < 0) {
- printk(KERN_DEBUG "%s: Failed to initialize rate control "
- "algorithm\n", wiphy_name(local->hw.wiphy));
+ wiphy_debug(local->hw.wiphy,
+ "Failed to initialize rate control algorithm\n");
goto fail_rate;
}
@@ -659,8 +801,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
result = ieee80211_if_add(local, "wlan%d", NULL,
NL80211_IFTYPE_STATION, NULL);
if (result)
- printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
- wiphy_name(local->hw.wiphy));
+ wiphy_warn(local->hw.wiphy,
+ "Failed to add default virtual iface\n");
}
rtnl_unlock();
@@ -683,6 +825,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
goto fail_ifa;
#endif
+ netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll,
+ local->hw.napi_weight);
+
return 0;
#ifdef CONFIG_INET
@@ -703,6 +848,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
fail_workqueue:
wiphy_unregister(local->hw.wiphy);
fail_wiphy_register:
+ if (local->wiphy_ciphers_allocated)
+ kfree(local->hw.wiphy->cipher_suites);
kfree(local->int_scan_req);
return result;
}
@@ -738,6 +885,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
*/
del_timer_sync(&local->work_timer);
+ cancel_work_sync(&local->restart_work);
cancel_work_sync(&local->reconfig_filter);
ieee80211_clear_tx_pending(local);
@@ -746,8 +894,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
if (skb_queue_len(&local->skb_queue) ||
skb_queue_len(&local->skb_queue_unreliable))
- printk(KERN_WARNING "%s: skb_queue not empty\n",
- wiphy_name(local->hw.wiphy));
+ wiphy_warn(local->hw.wiphy, "skb_queue not empty\n");
skb_queue_purge(&local->skb_queue);
skb_queue_purge(&local->skb_queue_unreliable);
@@ -764,7 +911,10 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
struct ieee80211_local *local = hw_to_local(hw);
mutex_destroy(&local->iflist_mtx);
- mutex_destroy(&local->scan_mtx);
+ mutex_destroy(&local->mtx);
+
+ if (local->wiphy_ciphers_allocated)
+ kfree(local->hw.wiphy->cipher_suites);
wiphy_free(local->hw.wiphy);
}
@@ -812,12 +962,6 @@ static void __exit ieee80211_exit(void)
rc80211_minstrel_ht_exit();
rc80211_minstrel_exit();
- /*
- * For key todo, it'll be empty by now but the work
- * might still be scheduled.
- */
- flush_scheduled_work();
-
if (mesh_allocated)
ieee80211s_stop();
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index ebd3f1d9d889..58e741128968 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -115,7 +115,7 @@ struct mesh_path {
* @hash_rnd: random value used for hash computations
* @entries: number of entries in the table
* @free_node: function to free nodes of the table
- * @copy_node: fuction to copy nodes of the table
+ * @copy_node: function to copy nodes of the table
* @size_order: determines size of the table, there will be 2^size_order hash
* buckets
* @mean_chain_len: maximum average length for the hash buckets' list, if it is
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index ea13a80a476c..1c91f0f3c307 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -412,7 +412,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
enum plink_event event;
enum plink_frame_type ftype;
size_t baselen;
- bool deactivated;
+ bool deactivated, matches_local = true;
u8 ie_len;
u8 *baseaddr;
__le16 plid, llid, reason;
@@ -487,6 +487,7 @@ 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))) {
+ matches_local = false;
switch (ftype) {
case PLINK_OPEN:
event = OPN_RJCT;
@@ -498,7 +499,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
/* avoid warning */
break;
}
- spin_lock_bh(&sta->lock);
+ }
+
+ if (!sta && !matches_local) {
+ rcu_read_unlock();
+ reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+ llid = 0;
+ mesh_plink_frame_tx(sdata, PLINK_CLOSE, mgmt->sa, llid,
+ plid, reason);
+ return;
} else if (!sta) {
/* ftype == PLINK_OPEN */
u32 rates;
@@ -522,7 +531,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
}
event = OPN_ACPT;
spin_lock_bh(&sta->lock);
- } else {
+ } else if (matches_local) {
spin_lock_bh(&sta->lock);
switch (ftype) {
case PLINK_OPEN:
@@ -564,6 +573,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
rcu_read_unlock();
return;
}
+ } else {
+ spin_lock_bh(&sta->lock);
}
mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n",
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index b6c163ac22da..a3a9421555af 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -54,6 +54,12 @@
*/
#define IEEE80211_SIGNAL_AVE_WEIGHT 3
+/*
+ * How many Beacon frames need to have been used in average signal strength
+ * before starting to indicate signal change events.
+ */
+#define IEEE80211_SIGNAL_AVE_MIN_COUNT 4
+
#define TMR_RUNNING_TIMER 0
#define TMR_RUNNING_CHANSW 1
@@ -86,7 +92,7 @@ enum rx_mgmt_action {
/* utils */
static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd)
{
- WARN_ON(!mutex_is_locked(&ifmgd->mtx));
+ lockdep_assert_held(&ifmgd->mtx);
}
/*
@@ -109,7 +115,7 @@ static void run_again(struct ieee80211_if_managed *ifmgd,
mod_timer(&ifmgd->timer, timeout);
}
-static void mod_beacon_timer(struct ieee80211_sub_if_data *sdata)
+void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata)
{
if (sdata->local->hw.flags & IEEE80211_HW_BEACON_FILTER)
return;
@@ -118,6 +124,19 @@ static void mod_beacon_timer(struct ieee80211_sub_if_data *sdata)
round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME));
}
+void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+ if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
+ return;
+
+ mod_timer(&sdata->u.mgd.conn_mon_timer,
+ round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME));
+
+ ifmgd->probe_send_count = 0;
+}
+
static int ecw2cw(int ecw)
{
return (1 << ecw) - 1;
@@ -778,16 +797,17 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
params.uapsd = uapsd;
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
- "cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
- wiphy_name(local->hw.wiphy), queue, aci, acm,
- params.aifs, params.cw_min, params.cw_max, params.txop,
- params.uapsd);
+ wiphy_debug(local->hw.wiphy,
+ "WMM queue=%d aci=%d acm=%d aifs=%d "
+ "cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
+ queue, aci, acm,
+ params.aifs, params.cw_min, params.cw_max,
+ params.txop, params.uapsd);
#endif
if (drv_conf_tx(local, queue, &params))
- printk(KERN_DEBUG "%s: failed to set TX queue "
- "parameters for queue %d\n",
- wiphy_name(local->hw.wiphy), queue);
+ wiphy_debug(local->hw.wiphy,
+ "failed to set TX queue parameters for queue %d\n",
+ queue);
}
/* enable WMM or activate new settings */
@@ -860,14 +880,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
IEEE80211_STA_BEACON_POLL);
- /*
- * Always handle WMM once after association regardless
- * of the first value the AP uses. Setting -1 here has
- * that effect because the AP values is an unsigned
- * 4-bit value.
- */
- sdata->u.mgd.wmm_last_param_set = -1;
-
ieee80211_led_assoc(local, 1);
if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD)
@@ -901,7 +913,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, -1);
- ieee80211_recalc_smps(local, sdata);
+ ieee80211_recalc_smps(local);
mutex_unlock(&local->iflist_mtx);
netif_tx_start_all_queues(sdata->dev);
@@ -909,7 +921,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
}
static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
- bool remove_sta)
+ bool remove_sta, bool tx)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
@@ -948,7 +960,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
sta = sta_info_get(sdata, bssid);
if (sta) {
set_sta_flags(sta, WLAN_STA_BLOCK_BA);
- ieee80211_sta_tear_down_BA_sessions(sta);
+ ieee80211_sta_tear_down_BA_sessions(sta, tx);
}
mutex_unlock(&local->sta_mtx);
@@ -990,6 +1002,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
if (remove_sta)
sta_info_destroy_addr(sdata, bssid);
+
+ del_timer_sync(&sdata->u.mgd.conn_mon_timer);
+ del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
+ del_timer_sync(&sdata->u.mgd.timer);
+ del_timer_sync(&sdata->u.mgd.chswitch_timer);
}
void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
@@ -1006,21 +1023,26 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
if (is_multicast_ether_addr(hdr->addr1))
return;
- if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
- return;
-
- mod_timer(&sdata->u.mgd.conn_mon_timer,
- round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME));
+ ieee80211_sta_reset_conn_monitor(sdata);
}
static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
const u8 *ssid;
+ u8 *dst = ifmgd->associated->bssid;
+ u8 unicast_limit = max(1, IEEE80211_MAX_PROBE_TRIES - 3);
+
+ /*
+ * Try sending broadcast probe requests for the last three
+ * probe requests after the first ones failed since some
+ * buggy APs only support broadcast probe requests.
+ */
+ if (ifmgd->probe_send_count >= unicast_limit)
+ dst = NULL;
ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
- ieee80211_send_probe_req(sdata, ifmgd->associated->bssid,
- ssid + 2, ssid[1], NULL, 0);
+ ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0);
ifmgd->probe_send_count++;
ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT;
@@ -1102,9 +1124,12 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid);
- ieee80211_set_disassoc(sdata, true);
- ieee80211_recalc_idle(local);
+ ieee80211_set_disassoc(sdata, true, true);
mutex_unlock(&ifmgd->mtx);
+
+ mutex_lock(&local->mtx);
+ ieee80211_recalc_idle(local);
+ mutex_unlock(&local->mtx);
/*
* must be outside lock due to cfg80211,
* but that's not a problem.
@@ -1172,8 +1197,10 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
sdata->name, bssid, reason_code);
- ieee80211_set_disassoc(sdata, true);
+ ieee80211_set_disassoc(sdata, true, false);
+ mutex_lock(&sdata->local->mtx);
ieee80211_recalc_idle(sdata->local);
+ mutex_unlock(&sdata->local->mtx);
return RX_MGMT_CFG80211_DEAUTH;
}
@@ -1202,8 +1229,10 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
sdata->name, mgmt->sa, reason_code);
- ieee80211_set_disassoc(sdata, true);
+ ieee80211_set_disassoc(sdata, true, false);
+ mutex_lock(&sdata->local->mtx);
ieee80211_recalc_idle(sdata->local);
+ mutex_unlock(&sdata->local->mtx);
return RX_MGMT_CFG80211_DISASSOC;
}
@@ -1262,7 +1291,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
rates = 0;
basic_rates = 0;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[wk->chan->band];
for (i = 0; i < elems.supp_rates_len; i++) {
int rate = (elems.supp_rates[i] & 0x7f) * 5;
@@ -1298,11 +1327,11 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
}
}
- sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
+ sta->sta.supp_rates[wk->chan->band] = rates;
sdata->vif.bss_conf.basic_rates = basic_rates;
/* cf. IEEE 802.11 9.2.12 */
- if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+ if (wk->chan->band == IEEE80211_BAND_2GHZ &&
have_higher_than_11mbit)
sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
else
@@ -1330,6 +1359,14 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
return false;
}
+ /*
+ * Always handle WMM once after association regardless
+ * of the first value the AP uses. Setting -1 here has
+ * that effect because the AP values is an unsigned
+ * 4-bit value.
+ */
+ ifmgd->wmm_last_param_set = -1;
+
if (elems.wmm_param)
ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
elems.wmm_param_len);
@@ -1362,7 +1399,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
* Also start the timer that will detect beacon loss.
*/
ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
- mod_beacon_timer(sdata);
+ ieee80211_sta_reset_beacon_monitor(sdata);
return true;
}
@@ -1465,7 +1502,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
* we have or will be receiving any beacons or data, so let's
* schedule the timers again, just in case.
*/
- mod_beacon_timer(sdata);
+ ieee80211_sta_reset_beacon_monitor(sdata);
mod_timer(&ifmgd->conn_mon_timer,
round_jiffies_up(jiffies +
@@ -1540,15 +1577,18 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ifmgd->last_beacon_signal = rx_status->signal;
if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
- ifmgd->ave_beacon_signal = rx_status->signal;
+ ifmgd->ave_beacon_signal = rx_status->signal * 16;
ifmgd->last_cqm_event_signal = 0;
+ ifmgd->count_beacon_signal = 1;
} else {
ifmgd->ave_beacon_signal =
(IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
(16 - IEEE80211_SIGNAL_AVE_WEIGHT) *
ifmgd->ave_beacon_signal) / 16;
+ ifmgd->count_beacon_signal++;
}
if (bss_conf->cqm_rssi_thold &&
+ ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&
!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
int sig = ifmgd->ave_beacon_signal / 16;
int last_event = ifmgd->last_cqm_event_signal;
@@ -1588,7 +1628,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
* Push the beacon loss detection into the future since
* we are processing a beacon from the AP just now.
*/
- mod_beacon_timer(sdata);
+ ieee80211_sta_reset_beacon_monitor(sdata);
ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
@@ -1599,7 +1639,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len,
ifmgd->aid);
- if (ncrc != ifmgd->beacon_crc) {
+ if (ncrc != ifmgd->beacon_crc || !ifmgd->beacon_crc_valid) {
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
true);
@@ -1630,9 +1670,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
}
}
- if (ncrc == ifmgd->beacon_crc)
+ if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
return;
ifmgd->beacon_crc = ncrc;
+ ifmgd->beacon_crc_valid = true;
if (elems.erp_info && elems.erp_info_len >= 1) {
erp_valid = true;
@@ -1751,7 +1792,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct ieee80211_work *wk;
- mutex_lock(&local->work_mtx);
+ mutex_lock(&local->mtx);
list_for_each_entry(wk, &local->work_list, list) {
if (wk->sdata != sdata)
continue;
@@ -1783,7 +1824,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
free_work(wk);
break;
}
- mutex_unlock(&local->work_mtx);
+ mutex_unlock(&local->mtx);
cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
}
@@ -1823,10 +1864,12 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "No probe response from AP %pM"
- " after %dms, try %d\n", bssid,
- (1000 * IEEE80211_PROBE_WAIT)/HZ,
- ifmgd->probe_send_count);
+ wiphy_debug(local->hw.wiphy,
+ "%s: No probe response from AP %pM"
+ " after %dms, try %d\n",
+ sdata->name,
+ bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ,
+ ifmgd->probe_send_count);
#endif
ieee80211_mgd_probe_ap_send(sdata);
} else {
@@ -1836,12 +1879,16 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
*/
ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
IEEE80211_STA_BEACON_POLL);
- printk(KERN_DEBUG "No probe response from AP %pM"
- " after %dms, disconnecting.\n",
- bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
- ieee80211_set_disassoc(sdata, true);
- ieee80211_recalc_idle(local);
+ wiphy_debug(local->hw.wiphy,
+ "%s: No probe response from AP %pM"
+ " after %dms, disconnecting.\n",
+ sdata->name,
+ bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
+ ieee80211_set_disassoc(sdata, true, true);
mutex_unlock(&ifmgd->mtx);
+ mutex_lock(&local->mtx);
+ ieee80211_recalc_idle(local);
+ mutex_unlock(&local->mtx);
/*
* must be outside lock due to cfg80211,
* but that's not a problem.
@@ -1917,6 +1964,8 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
* time -- the code here is properly synchronised.
*/
+ cancel_work_sync(&ifmgd->request_smps_work);
+
cancel_work_sync(&ifmgd->beacon_connection_loss_work);
if (del_timer_sync(&ifmgd->timer))
set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
@@ -1952,6 +2001,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
INIT_WORK(&ifmgd->beacon_connection_loss_work,
ieee80211_beacon_connection_loss_work);
+ INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work);
setup_timer(&ifmgd->timer, ieee80211_sta_timer,
(unsigned long) sdata);
setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,
@@ -2158,7 +2208,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
}
/* Trying to reassociate - clear previous association state */
- ieee80211_set_disassoc(sdata, true);
+ ieee80211_set_disassoc(sdata, true, false);
}
mutex_unlock(&ifmgd->mtx);
@@ -2169,6 +2219,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
+ ifmgd->beacon_crc_valid = false;
+
for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
@@ -2249,6 +2301,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
else
ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
+ sdata->control_port_protocol = req->crypto.control_port_ethertype;
+ sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt;
+
ieee80211_add_work(wk);
return 0;
}
@@ -2267,7 +2322,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
memcpy(bssid, req->bss->bssid, ETH_ALEN);
if (ifmgd->associated == req->bss) {
- ieee80211_set_disassoc(sdata, false);
+ ieee80211_set_disassoc(sdata, false, true);
mutex_unlock(&ifmgd->mtx);
assoc_bss = true;
} else {
@@ -2275,7 +2330,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
mutex_unlock(&ifmgd->mtx);
- mutex_lock(&local->work_mtx);
+ mutex_lock(&local->mtx);
list_for_each_entry(wk, &local->work_list, list) {
if (wk->sdata != sdata)
continue;
@@ -2294,7 +2349,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
free_work(wk);
break;
}
- mutex_unlock(&local->work_mtx);
+ mutex_unlock(&local->mtx);
/*
* If somebody requests authentication and we haven't
@@ -2319,7 +2374,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
if (assoc_bss)
sta_info_destroy_addr(sdata, bssid);
+ mutex_lock(&sdata->local->mtx);
ieee80211_recalc_idle(sdata->local);
+ mutex_unlock(&sdata->local->mtx);
return 0;
}
@@ -2348,7 +2405,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
sdata->name, req->bss->bssid, req->reason_code);
memcpy(bssid, req->bss->bssid, ETH_ALEN);
- ieee80211_set_disassoc(sdata, false);
+ ieee80211_set_disassoc(sdata, false, true);
mutex_unlock(&ifmgd->mtx);
@@ -2357,7 +2414,9 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
cookie, !req->local_state_change);
sta_info_destroy_addr(sdata, bssid);
+ mutex_lock(&sdata->local->mtx);
ieee80211_recalc_idle(sdata->local);
+ mutex_unlock(&sdata->local->mtx);
return 0;
}
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index c36b1911987a..4b564091e51d 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -22,12 +22,16 @@
static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
local->offchannel_ps_enabled = false;
/* FIXME: what to do when local->pspolling is true? */
del_timer_sync(&local->dynamic_ps_timer);
+ del_timer_sync(&ifmgd->bcn_mon_timer);
+ del_timer_sync(&ifmgd->conn_mon_timer);
+
cancel_work_sync(&local->dynamic_ps_enable_work);
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
@@ -85,6 +89,9 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
mod_timer(&local->dynamic_ps_timer, jiffies +
msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
}
+
+ ieee80211_sta_reset_beacon_monitor(sdata);
+ ieee80211_sta_reset_conn_monitor(sdata);
}
void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local)
@@ -112,8 +119,10 @@ void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local)
* used from user space controlled off-channel operations.
*/
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
- sdata->vif.type != NL80211_IFTYPE_MONITOR)
+ sdata->vif.type != NL80211_IFTYPE_MONITOR) {
+ set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
netif_tx_stop_all_queues(sdata->dev);
+ }
}
mutex_unlock(&local->iflist_mtx);
}
@@ -131,6 +140,7 @@ void ieee80211_offchannel_stop_station(struct ieee80211_local *local)
continue;
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+ set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
netif_tx_stop_all_queues(sdata->dev);
if (sdata->u.mgd.associated)
ieee80211_offchannel_ps_enable(sdata);
@@ -155,8 +165,20 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
ieee80211_offchannel_ps_disable(sdata);
}
- if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
+ if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
+ clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
+ /*
+ * This may wake up queues even though the driver
+ * currently has them stopped. This is not very
+ * likely, since the driver won't have gotten any
+ * (or hardly any) new packets while we weren't
+ * on the right channel, and even if it happens
+ * it will at most lead to queueing up one more
+ * packet per queue in mac80211 rather than on
+ * the interface qdisc.
+ */
netif_tx_wake_all_queues(sdata->dev);
+ }
/* re-enable beaconing */
if (enable_beaconing &&
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index d287fde0431d..e37355193ed1 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -45,7 +45,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
list_for_each_entry(sta, &local->sta_list, list) {
if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
set_sta_flags(sta, WLAN_STA_BLOCK_BA);
- ieee80211_sta_tear_down_BA_sessions(sta);
+ ieee80211_sta_tear_down_BA_sessions(sta, true);
}
if (sta->uploaded) {
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 334cbd3d2aae..33f76993da08 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -208,7 +208,7 @@ 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_is_data(fc);
}
static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u8 max_rate_idx)
@@ -329,6 +329,9 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
* if needed.
*/
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+ /* Skip invalid rates */
+ if (info->control.rates[i].idx < 0)
+ break;
/* Rate masking supports only legacy rates for now */
if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS)
continue;
@@ -369,8 +372,8 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
ref = rate_control_alloc(name, local);
if (!ref) {
- printk(KERN_WARNING "%s: Failed to select rate control "
- "algorithm\n", wiphy_name(local->hw.wiphy));
+ wiphy_warn(local->hw.wiphy,
+ "Failed to select rate control algorithm\n");
return -ENOENT;
}
@@ -381,9 +384,8 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
sta_info_flush(local, NULL);
}
- printk(KERN_DEBUG "%s: Selected rate control "
- "algorithm '%s'\n", wiphy_name(local->hw.wiphy),
- ref->ops->name);
+ wiphy_debug(local->hw.wiphy, "Selected rate control algorithm '%s'\n",
+ ref->ops->name);
return 0;
}
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index c5b465904e3b..2a18d6602d4a 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -397,8 +397,9 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
!(info->flags & IEEE80211_TX_STAT_AMPDU))
return;
- if (!info->status.ampdu_len) {
- info->status.ampdu_ack_len = 1;
+ if (!(info->flags & IEEE80211_TX_STAT_AMPDU)) {
+ info->status.ampdu_ack_len =
+ (info->flags & IEEE80211_TX_STAT_ACK ? 1 : 0);
info->status.ampdu_len = 1;
}
@@ -426,7 +427,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
group = minstrel_ht_get_group_idx(&ar[i]);
rate = &mi->groups[group].rates[ar[i].idx % 8];
- if (last && (info->flags & IEEE80211_TX_STAT_ACK))
+ if (last)
rate->success += info->status.ampdu_ack_len;
rate->attempts += ar[i].count * info->status.ampdu_len;
diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c
index 7905f79cc2e4..4851e9e2daed 100644
--- a/net/mac80211/rc80211_pid_debugfs.c
+++ b/net/mac80211/rc80211_pid_debugfs.c
@@ -162,7 +162,7 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf,
file_info->next_entry = (file_info->next_entry + 1) %
RC_PID_EVENT_RING_SIZE;
- /* Print information about the event. Note that userpace needs to
+ /* Print information about the event. Note that userspace needs to
* provide large enough buffers. */
length = length < RC_PID_PRINT_BUF_SIZE ?
length : RC_PID_PRINT_BUF_SIZE;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 28624282c5f3..902b03ee8f60 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -315,6 +315,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
int tid;
/* does the frame have a qos control field? */
@@ -323,9 +324,7 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
/* frame has qos control */
tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
- rx->flags |= IEEE80211_RX_AMSDU;
- else
- rx->flags &= ~IEEE80211_RX_AMSDU;
+ status->rx_flags |= IEEE80211_RX_AMSDU;
} else {
/*
* IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"):
@@ -387,26 +386,25 @@ static ieee80211_rx_result debug_noinline
ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
{
struct ieee80211_local *local = rx->local;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
struct sk_buff *skb = rx->skb;
- if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning)))
+ if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN)))
+ return RX_CONTINUE;
+
+ if (test_bit(SCAN_HW_SCANNING, &local->scanning))
return ieee80211_scan_rx(rx->sdata, skb);
- if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning) &&
- (rx->flags & IEEE80211_RX_IN_SCAN))) {
+ if (test_bit(SCAN_SW_SCANNING, &local->scanning)) {
/* drop all the other packets during a software scan anyway */
if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED)
dev_kfree_skb(skb);
return RX_QUEUED;
}
- if (unlikely(rx->flags & IEEE80211_RX_IN_SCAN)) {
- /* scanning finished during invoking of handlers */
- I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
- return RX_DROP_UNUSABLE;
- }
-
- return RX_CONTINUE;
+ /* scanning finished during invoking of handlers */
+ I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
+ return RX_DROP_UNUSABLE;
}
@@ -538,20 +536,12 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
int index,
struct sk_buff_head *frames)
{
- struct ieee80211_supported_band *sband;
- struct ieee80211_rate *rate = NULL;
struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
- struct ieee80211_rx_status *status;
if (!skb)
goto no_frame;
- status = IEEE80211_SKB_RXCB(skb);
-
- /* release the reordered frames to stack */
- sband = hw->wiphy->bands[status->band];
- if (!(status->flag & RX_FLAG_HT))
- rate = &sband->bitrates[status->rate_idx];
+ /* release the frame from the reorder ring buffer */
tid_agg_rx->stored_mpdu_num--;
tid_agg_rx->reorder_buf[index] = NULL;
__skb_queue_tail(frames, skb);
@@ -580,9 +570,102 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
* frames that have not yet been received are assumed to be lost and the skb
* can be released for processing. This may also release other skb's from the
* reorder buffer if there are no additional gaps between the frames.
+ *
+ * Callers must hold tid_agg_rx->reorder_lock.
*/
#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
+static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
+ struct tid_ampdu_rx *tid_agg_rx,
+ struct sk_buff_head *frames)
+{
+ int index, j;
+
+ /* release the buffer until next missing frame */
+ index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+ tid_agg_rx->buf_size;
+ if (!tid_agg_rx->reorder_buf[index] &&
+ tid_agg_rx->stored_mpdu_num > 1) {
+ /*
+ * No buffers ready to be released, but check whether any
+ * frames in the reorder buffer have timed out.
+ */
+ int skipped = 1;
+ for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
+ j = (j + 1) % tid_agg_rx->buf_size) {
+ if (!tid_agg_rx->reorder_buf[j]) {
+ skipped++;
+ continue;
+ }
+ if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
+ HT_RX_REORDER_BUF_TIMEOUT))
+ goto set_release_timer;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ if (net_ratelimit())
+ wiphy_debug(hw->wiphy,
+ "release an RX reorder frame due to timeout on earlier frames\n");
+#endif
+ ieee80211_release_reorder_frame(hw, tid_agg_rx,
+ j, frames);
+
+ /*
+ * Increment the head seq# also for the skipped slots.
+ */
+ tid_agg_rx->head_seq_num =
+ (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
+ skipped = 0;
+ }
+ } else while (tid_agg_rx->reorder_buf[index]) {
+ ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames);
+ index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+ tid_agg_rx->buf_size;
+ }
+
+ /*
+ * Disable the reorder release timer for now.
+ *
+ * The current implementation lacks a proper locking scheme
+ * which would protect vital statistic and debug counters
+ * from being updated by two different but concurrent BHs.
+ *
+ * More information about the topic is available from:
+ * - thread: http://marc.info/?t=128635927000001
+ *
+ * What was wrong:
+ * => http://marc.info/?l=linux-wireless&m=128636170811964
+ * "Basically the thing is that until your patch, the data
+ * in the struct didn't actually need locking because it
+ * was accessed by the RX path only which is not concurrent."
+ *
+ * List of what needs to be fixed:
+ * => http://marc.info/?l=linux-wireless&m=128656352920957
+ *
+
+ if (tid_agg_rx->stored_mpdu_num) {
+ j = index = seq_sub(tid_agg_rx->head_seq_num,
+ tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+
+ for (; j != (index - 1) % tid_agg_rx->buf_size;
+ j = (j + 1) % tid_agg_rx->buf_size) {
+ if (tid_agg_rx->reorder_buf[j])
+ break;
+ }
+
+ set_release_timer:
+
+ mod_timer(&tid_agg_rx->reorder_timer,
+ tid_agg_rx->reorder_time[j] +
+ HT_RX_REORDER_BUF_TIMEOUT);
+ } else {
+ del_timer(&tid_agg_rx->reorder_timer);
+ }
+ */
+
+set_release_timer:
+ return;
+}
+
/*
* As this function belongs to the RX path it must be under
* rcu_read_lock protection. It returns false if the frame
@@ -598,14 +681,16 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
u16 head_seq_num, buf_size;
int index;
+ bool ret = true;
buf_size = tid_agg_rx->buf_size;
head_seq_num = tid_agg_rx->head_seq_num;
+ spin_lock(&tid_agg_rx->reorder_lock);
/* frame with out of date sequence number */
if (seq_less(mpdu_seq_num, head_seq_num)) {
dev_kfree_skb(skb);
- return true;
+ goto out;
}
/*
@@ -626,7 +711,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
/* check if we already stored this frame */
if (tid_agg_rx->reorder_buf[index]) {
dev_kfree_skb(skb);
- return true;
+ goto out;
}
/*
@@ -636,58 +721,19 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
tid_agg_rx->stored_mpdu_num == 0) {
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
- return false;
+ ret = false;
+ goto out;
}
/* put the frame in the reordering buffer */
tid_agg_rx->reorder_buf[index] = skb;
tid_agg_rx->reorder_time[index] = jiffies;
tid_agg_rx->stored_mpdu_num++;
- /* release the buffer until next missing frame */
- index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
- tid_agg_rx->buf_size;
- if (!tid_agg_rx->reorder_buf[index] &&
- tid_agg_rx->stored_mpdu_num > 1) {
- /*
- * No buffers ready to be released, but check whether any
- * frames in the reorder buffer have timed out.
- */
- int j;
- int skipped = 1;
- for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
- j = (j + 1) % tid_agg_rx->buf_size) {
- if (!tid_agg_rx->reorder_buf[j]) {
- skipped++;
- continue;
- }
- if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
- HT_RX_REORDER_BUF_TIMEOUT))
- break;
+ ieee80211_sta_reorder_release(hw, tid_agg_rx, frames);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_DEBUG "%s: release an RX reorder "
- "frame due to timeout on earlier "
- "frames\n",
- wiphy_name(hw->wiphy));
-#endif
- ieee80211_release_reorder_frame(hw, tid_agg_rx,
- j, frames);
-
- /*
- * Increment the head seq# also for the skipped slots.
- */
- tid_agg_rx->head_seq_num =
- (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
- skipped = 0;
- }
- } else while (tid_agg_rx->reorder_buf[index]) {
- ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames);
- index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
- tid_agg_rx->buf_size;
- }
-
- return true;
+ out:
+ spin_unlock(&tid_agg_rx->reorder_lock);
+ return ret;
}
/*
@@ -761,13 +807,14 @@ static ieee80211_rx_result debug_noinline
ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
/* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
rx->sta->last_seq_ctrl[rx->queue] ==
hdr->seq_ctrl)) {
- if (rx->flags & IEEE80211_RX_RA_MATCH) {
+ if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
rx->local->dot11FrameDuplicateCount++;
rx->sta->num_duplicates++;
}
@@ -796,11 +843,12 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
if (unlikely((ieee80211_is_data(hdr->frame_control) ||
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)))) {
if ((!ieee80211_has_fromds(hdr->frame_control) &&
!ieee80211_has_tods(hdr->frame_control) &&
ieee80211_is_data(hdr->frame_control)) ||
- !(rx->flags & IEEE80211_RX_RA_MATCH)) {
+ !(status->rx_flags & IEEE80211_RX_RA_MATCH)) {
/* Drop IBSS frames and frames for other hosts
* silently. */
return RX_DROP_MONITOR;
@@ -822,7 +870,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
int keyidx;
int hdrlen;
ieee80211_rx_result result = RX_DROP_UNUSABLE;
- struct ieee80211_key *stakey = NULL;
+ struct ieee80211_key *sta_ptk = NULL;
int mmie_keyidx = -1;
__le16 fc;
@@ -857,22 +905,25 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
* No point in finding a key and decrypting if the frame is neither
* addressed to us nor a multicast frame.
*/
- if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
return RX_CONTINUE;
/* start without a key */
rx->key = NULL;
if (rx->sta)
- stakey = rcu_dereference(rx->sta->key);
+ sta_ptk = rcu_dereference(rx->sta->ptk);
fc = hdr->frame_control;
if (!ieee80211_has_protected(fc))
mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
- if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
- rx->key = stakey;
+ if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) {
+ rx->key = sta_ptk;
+ if ((status->flag & RX_FLAG_DECRYPTED) &&
+ (status->flag & RX_FLAG_IV_STRIPPED))
+ return RX_CONTINUE;
/* Skip decryption if the frame is not protected. */
if (!ieee80211_has_protected(fc))
return RX_CONTINUE;
@@ -885,7 +936,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
if (mmie_keyidx < NUM_DEFAULT_KEYS ||
mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
return RX_DROP_MONITOR; /* unexpected BIP keyidx */
- rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
+ if (rx->sta)
+ rx->key = rcu_dereference(rx->sta->gtk[mmie_keyidx]);
+ if (!rx->key)
+ rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
} else if (!ieee80211_has_protected(fc)) {
/*
* The frame was not protected, so skip decryption. However, we
@@ -928,16 +982,25 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
keyidx = keyid >> 6;
- rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
+ /* check per-station GTK first, if multicast packet */
+ if (is_multicast_ether_addr(hdr->addr1) && rx->sta)
+ rx->key = rcu_dereference(rx->sta->gtk[keyidx]);
- /*
- * RSNA-protected unicast frames should always be sent with
- * pairwise or station-to-station keys, but for WEP we allow
- * using a key index as well.
- */
- if (rx->key && rx->key->conf.alg != ALG_WEP &&
- !is_multicast_ether_addr(hdr->addr1))
- rx->key = NULL;
+ /* if not found, try default key */
+ if (!rx->key) {
+ rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
+
+ /*
+ * RSNA-protected unicast frames should always be
+ * sent with pairwise or station-to-station keys,
+ * but for WEP we allow using a key index as well.
+ */
+ if (rx->key &&
+ rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 &&
+ rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 &&
+ !is_multicast_ether_addr(hdr->addr1))
+ rx->key = NULL;
+ }
}
if (rx->key) {
@@ -951,8 +1014,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
return RX_DROP_UNUSABLE;
/* the hdr variable is invalid now! */
- switch (rx->key->conf.alg) {
- case ALG_WEP:
+ switch (rx->key->conf.cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
/* Check for weak IVs if possible */
if (rx->sta && ieee80211_is_data(fc) &&
(!(status->flag & RX_FLAG_IV_STRIPPED) ||
@@ -962,15 +1026,21 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
result = ieee80211_crypto_wep_decrypt(rx);
break;
- case ALG_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
result = ieee80211_crypto_tkip_decrypt(rx);
break;
- case ALG_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
result = ieee80211_crypto_ccmp_decrypt(rx);
break;
- case ALG_AES_CMAC:
+ case WLAN_CIPHER_SUITE_AES_CMAC:
result = ieee80211_crypto_aes_cmac_decrypt(rx);
break;
+ default:
+ /*
+ * We can reach here only with HW-only algorithms
+ * but why didn't it decrypt the frame?!
+ */
+ return RX_DROP_UNUSABLE;
}
/* either the frame has been decrypted or will be dropped */
@@ -1079,7 +1149,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
sta->last_rx = jiffies;
}
- if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
return RX_CONTINUE;
if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
@@ -1236,6 +1306,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
unsigned int frag, seq;
struct ieee80211_fragment_entry *entry;
struct sk_buff *skb;
+ struct ieee80211_rx_status *status;
hdr = (struct ieee80211_hdr *)rx->skb->data;
fc = hdr->frame_control;
@@ -1265,7 +1336,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
/* This is the first fragment of a new frame. */
entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
rx->queue, &(rx->skb));
- if (rx->key && rx->key->conf.alg == ALG_CCMP &&
+ if (rx->key && rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP &&
ieee80211_has_protected(fc)) {
int queue = ieee80211_is_mgmt(fc) ?
NUM_RX_DATA_QUEUES : rx->queue;
@@ -1294,7 +1365,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
int i;
u8 pn[CCMP_PN_LEN], *rpn;
int queue;
- if (!rx->key || rx->key->conf.alg != ALG_CCMP)
+ if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP)
return RX_DROP_UNUSABLE;
memcpy(pn, entry->last_pn, CCMP_PN_LEN);
for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
@@ -1335,7 +1406,8 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
}
/* Complete frame has been reassembled - process it now */
- rx->flags |= IEEE80211_RX_FRAGMENTED;
+ status = IEEE80211_SKB_RXCB(rx->skb);
+ status->rx_flags |= IEEE80211_RX_FRAGMENTED;
out:
if (rx->sta)
@@ -1352,9 +1424,10 @@ 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) ||
- !(rx->flags & IEEE80211_RX_RA_MATCH)))
+ !(status->rx_flags & IEEE80211_RX_RA_MATCH)))
return RX_CONTINUE;
if ((sdata->vif.type != NL80211_IFTYPE_AP) &&
@@ -1492,7 +1565,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
* Allow EAPOL frames to us/the PAE group address regardless
* of whether the frame was encrypted or not.
*/
- if (ehdr->h_proto == htons(ETH_P_PAE) &&
+ if (ehdr->h_proto == rx->sdata->control_port_protocol &&
(compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 ||
compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
return true;
@@ -1515,6 +1588,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
struct sk_buff *skb, *xmit_skb;
struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
struct sta_info *dsta;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
skb = rx->skb;
xmit_skb = NULL;
@@ -1522,7 +1596,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
if ((sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
!(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
- (rx->flags & IEEE80211_RX_RA_MATCH) &&
+ (status->rx_flags & IEEE80211_RX_RA_MATCH) &&
(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
if (is_multicast_ether_addr(ehdr->h_dest)) {
/*
@@ -1599,6 +1673,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc = hdr->frame_control;
struct sk_buff_head frame_list;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
if (unlikely(!ieee80211_is_data(fc)))
return RX_CONTINUE;
@@ -1606,7 +1681,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
if (unlikely(!ieee80211_is_data_present(fc)))
return RX_DROP_MONITOR;
- if (!(rx->flags & IEEE80211_RX_AMSDU))
+ if (!(status->rx_flags & IEEE80211_RX_AMSDU))
return RX_CONTINUE;
if (ieee80211_has_a4(hdr->frame_control) &&
@@ -1657,6 +1732,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
struct sk_buff *skb = rx->skb, *fwd_skb;
struct ieee80211_local *local = rx->local;
struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
hdr = (struct ieee80211_hdr *) skb->data;
hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -1702,7 +1778,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
mesh_hdr->ttl--;
- if (rx->flags & IEEE80211_RX_RA_MATCH) {
+ if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
if (!mesh_hdr->ttl)
IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh,
dropped_frames_ttl);
@@ -1909,13 +1985,38 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
}
static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
+{
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+
+ /*
+ * From here on, look only at management frames.
+ * Data and control frames are already handled,
+ * and unknown (reserved) frames are useless.
+ */
+ if (rx->skb->len < 24)
+ return RX_DROP_MONITOR;
+
+ if (!ieee80211_is_mgmt(mgmt->frame_control))
+ return RX_DROP_MONITOR;
+
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
+ return RX_DROP_MONITOR;
+
+ if (ieee80211_drop_unencrypted_mgmt(rx))
+ return RX_DROP_UNUSABLE;
+
+ return RX_CONTINUE;
+}
+
+static ieee80211_rx_result debug_noinline
ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
{
struct ieee80211_local *local = rx->local;
struct ieee80211_sub_if_data *sdata = rx->sdata;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
- struct sk_buff *nskb;
- struct ieee80211_rx_status *status;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
int len = rx->skb->len;
if (!ieee80211_is_action(mgmt->frame_control))
@@ -1928,10 +2029,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)
return RX_DROP_UNUSABLE;
- if (!(rx->flags & IEEE80211_RX_RA_MATCH))
- return RX_DROP_UNUSABLE;
-
- if (ieee80211_drop_unencrypted_mgmt(rx))
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
return RX_DROP_UNUSABLE;
switch (mgmt->u.action.category) {
@@ -2024,17 +2122,36 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
goto queue;
}
+ return RX_CONTINUE;
+
invalid:
- /*
- * For AP mode, hostapd is responsible for handling any action
- * frames that we didn't handle, including returning unknown
- * ones. For all other modes we will return them to the sender,
- * setting the 0x80 bit in the action category, as required by
- * 802.11-2007 7.3.1.11.
- */
- if (sdata->vif.type == NL80211_IFTYPE_AP ||
- sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- return RX_DROP_MONITOR;
+ status->rx_flags |= IEEE80211_RX_MALFORMED_ACTION_FRM;
+ /* will return in the next handlers */
+ return RX_CONTINUE;
+
+ handled:
+ if (rx->sta)
+ rx->sta->rx_packets++;
+ dev_kfree_skb(rx->skb);
+ return RX_QUEUED;
+
+ queue:
+ rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
+ skb_queue_tail(&sdata->skb_queue, rx->skb);
+ ieee80211_queue_work(&local->hw, &sdata->work);
+ if (rx->sta)
+ rx->sta->rx_packets++;
+ return RX_QUEUED;
+}
+
+static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
+{
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+
+ /* skip known-bad action frames and return them in the next handler */
+ if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM)
+ return RX_CONTINUE;
/*
* Getting here means the kernel doesn't know how to handle
@@ -2042,12 +2159,46 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
* so userspace can register for those to know whether ones
* it transmitted were processed or returned.
*/
- status = IEEE80211_SKB_RXCB(rx->skb);
- if (cfg80211_rx_action(rx->sdata->dev, status->freq,
- rx->skb->data, rx->skb->len,
- GFP_ATOMIC))
- goto handled;
+ if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq,
+ rx->skb->data, rx->skb->len,
+ GFP_ATOMIC)) {
+ if (rx->sta)
+ rx->sta->rx_packets++;
+ dev_kfree_skb(rx->skb);
+ return RX_QUEUED;
+ }
+
+
+ return RX_CONTINUE;
+}
+
+static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
+{
+ struct ieee80211_local *local = rx->local;
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
+ struct sk_buff *nskb;
+ struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+
+ if (!ieee80211_is_action(mgmt->frame_control))
+ return RX_CONTINUE;
+
+ /*
+ * For AP mode, hostapd is responsible for handling any action
+ * frames that we didn't handle, including returning unknown
+ * ones. For all other modes we will return them to the sender,
+ * setting the 0x80 bit in the action category, as required by
+ * 802.11-2007 7.3.1.11.
+ * Newer versions of hostapd shall also use the management frame
+ * registration mechanisms, but older ones still use cooked
+ * monitor interfaces so push all frames there.
+ */
+ if (!(status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) &&
+ (sdata->vif.type == NL80211_IFTYPE_AP ||
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
+ return RX_DROP_MONITOR;
/* do not return rejected action frames */
if (mgmt->u.action.category & 0x80)
@@ -2066,20 +2217,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
ieee80211_tx_skb(rx->sdata, nskb);
}
-
- handled:
- if (rx->sta)
- rx->sta->rx_packets++;
dev_kfree_skb(rx->skb);
return RX_QUEUED;
-
- queue:
- rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
- skb_queue_tail(&sdata->skb_queue, rx->skb);
- ieee80211_queue_work(&local->hw, &sdata->work);
- if (rx->sta)
- rx->sta->rx_packets++;
- return RX_QUEUED;
}
static ieee80211_rx_result debug_noinline
@@ -2090,15 +2229,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
__le16 stype;
- if (!(rx->flags & IEEE80211_RX_RA_MATCH))
- return RX_DROP_MONITOR;
-
- if (rx->skb->len < 24)
- return RX_DROP_MONITOR;
-
- if (ieee80211_drop_unencrypted_mgmt(rx))
- return RX_DROP_UNUSABLE;
-
rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb);
if (rxs != RX_CONTINUE)
return rxs;
@@ -2199,6 +2329,14 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
struct net_device *prev_dev = NULL;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+ /*
+ * If cooked monitor has been processed already, then
+ * don't do it again. If not, set the flag.
+ */
+ if (rx->flags & IEEE80211_RX_CMNTR)
+ goto out_free_skb;
+ rx->flags |= IEEE80211_RX_CMNTR;
+
if (skb_headroom(skb) < sizeof(*rthdr) &&
pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))
goto out_free_skb;
@@ -2253,29 +2391,53 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
if (prev_dev) {
skb->dev = prev_dev;
netif_receive_skb(skb);
- skb = NULL;
- } else
- goto out_free_skb;
-
- return;
+ return;
+ }
out_free_skb:
dev_kfree_skb(skb);
}
+static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
+ ieee80211_rx_result res)
+{
+ switch (res) {
+ case RX_DROP_MONITOR:
+ I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop);
+ if (rx->sta)
+ rx->sta->rx_dropped++;
+ /* fall through */
+ case RX_CONTINUE: {
+ struct ieee80211_rate *rate = NULL;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_rx_status *status;
+
+ status = IEEE80211_SKB_RXCB((rx->skb));
+
+ sband = rx->local->hw.wiphy->bands[status->band];
+ if (!(status->flag & RX_FLAG_HT))
+ rate = &sband->bitrates[status->rate_idx];
+
+ ieee80211_rx_cooked_monitor(rx, rate);
+ break;
+ }
+ case RX_DROP_UNUSABLE:
+ I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop);
+ if (rx->sta)
+ rx->sta->rx_dropped++;
+ dev_kfree_skb(rx->skb);
+ break;
+ case RX_QUEUED:
+ I802_DEBUG_INC(rx->sdata->local->rx_handlers_queued);
+ break;
+ }
+}
-static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_rx_data *rx,
- struct sk_buff *skb,
- struct ieee80211_rate *rate)
+static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
+ struct sk_buff_head *frames)
{
- struct sk_buff_head reorder_release;
ieee80211_rx_result res = RX_DROP_MONITOR;
-
- __skb_queue_head_init(&reorder_release);
-
- rx->skb = skb;
- rx->sdata = sdata;
+ struct sk_buff *skb;
#define CALL_RXH(rxh) \
do { \
@@ -2284,23 +2446,14 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
goto rxh_next; \
} while (0);
- /*
- * NB: the rxh_next label works even if we jump
- * to it from here because then the list will
- * be empty, which is a trivial check
- */
- CALL_RXH(ieee80211_rx_h_passive_scan)
- CALL_RXH(ieee80211_rx_h_check)
-
- ieee80211_rx_reorder_ampdu(rx, &reorder_release);
-
- while ((skb = __skb_dequeue(&reorder_release))) {
+ while ((skb = __skb_dequeue(frames))) {
/*
* all the other fields are valid across frames
* that belong to an aMPDU since they are on the
* same TID from the same station
*/
rx->skb = skb;
+ rx->flags = 0;
CALL_RXH(ieee80211_rx_h_decrypt)
CALL_RXH(ieee80211_rx_h_check_more_data)
@@ -2312,50 +2465,92 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
CALL_RXH(ieee80211_rx_h_remove_qos_control)
CALL_RXH(ieee80211_rx_h_amsdu)
#ifdef CONFIG_MAC80211_MESH
- if (ieee80211_vif_is_mesh(&sdata->vif))
+ if (ieee80211_vif_is_mesh(&rx->sdata->vif))
CALL_RXH(ieee80211_rx_h_mesh_fwding);
#endif
CALL_RXH(ieee80211_rx_h_data)
/* special treatment -- needs the queue */
- res = ieee80211_rx_h_ctrl(rx, &reorder_release);
+ res = ieee80211_rx_h_ctrl(rx, frames);
if (res != RX_CONTINUE)
goto rxh_next;
+ CALL_RXH(ieee80211_rx_h_mgmt_check)
CALL_RXH(ieee80211_rx_h_action)
+ CALL_RXH(ieee80211_rx_h_userspace_mgmt)
+ CALL_RXH(ieee80211_rx_h_action_return)
CALL_RXH(ieee80211_rx_h_mgmt)
+ rxh_next:
+ ieee80211_rx_handlers_result(rx, res);
+
#undef CALL_RXH
+ }
+}
+
+static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
+{
+ struct sk_buff_head reorder_release;
+ ieee80211_rx_result res = RX_DROP_MONITOR;
+
+ __skb_queue_head_init(&reorder_release);
+
+#define CALL_RXH(rxh) \
+ do { \
+ res = rxh(rx); \
+ if (res != RX_CONTINUE) \
+ goto rxh_next; \
+ } while (0);
+
+ CALL_RXH(ieee80211_rx_h_passive_scan)
+ CALL_RXH(ieee80211_rx_h_check)
+
+ ieee80211_rx_reorder_ampdu(rx, &reorder_release);
+
+ ieee80211_rx_handlers(rx, &reorder_release);
+ return;
rxh_next:
- switch (res) {
- case RX_DROP_MONITOR:
- I802_DEBUG_INC(sdata->local->rx_handlers_drop);
- if (rx->sta)
- rx->sta->rx_dropped++;
- /* fall through */
- case RX_CONTINUE:
- ieee80211_rx_cooked_monitor(rx, rate);
- break;
- case RX_DROP_UNUSABLE:
- I802_DEBUG_INC(sdata->local->rx_handlers_drop);
- if (rx->sta)
- rx->sta->rx_dropped++;
- dev_kfree_skb(rx->skb);
- break;
- case RX_QUEUED:
- I802_DEBUG_INC(sdata->local->rx_handlers_queued);
- break;
- }
- }
+ ieee80211_rx_handlers_result(rx, res);
+
+#undef CALL_RXH
+}
+
+/*
+ * This function makes calls into the RX path. Therefore the
+ * caller must hold the sta_info->lock and everything has to
+ * be under rcu_read_lock protection as well.
+ */
+void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
+{
+ struct sk_buff_head frames;
+ struct ieee80211_rx_data rx = {
+ .sta = sta,
+ .sdata = sta->sdata,
+ .local = sta->local,
+ .queue = tid,
+ };
+ struct tid_ampdu_rx *tid_agg_rx;
+
+ tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
+ if (!tid_agg_rx)
+ return;
+
+ __skb_queue_head_init(&frames);
+
+ spin_lock(&tid_agg_rx->reorder_lock);
+ ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx, &frames);
+ spin_unlock(&tid_agg_rx->reorder_lock);
+
+ ieee80211_rx_handlers(&rx, &frames);
}
/* main receive path */
-static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_rx_data *rx,
+static int prepare_for_handlers(struct ieee80211_rx_data *rx,
struct ieee80211_hdr *hdr)
{
+ struct ieee80211_sub_if_data *sdata = rx->sdata;
struct sk_buff *skb = rx->skb;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
@@ -2369,7 +2564,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) {
if (!(sdata->dev->flags & IFF_PROMISC))
return 0;
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
}
break;
case NL80211_IFTYPE_ADHOC:
@@ -2379,15 +2574,15 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
return 1;
}
else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
- if (!(rx->flags & IEEE80211_RX_IN_SCAN))
+ if (!(status->rx_flags & IEEE80211_RX_IN_SCAN))
return 0;
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
} else if (!multicast &&
compare_ether_addr(sdata->vif.addr,
hdr->addr1) != 0) {
if (!(sdata->dev->flags & IFF_PROMISC))
return 0;
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
} else if (!rx->sta) {
int rate_idx;
if (status->flag & RX_FLAG_HT)
@@ -2405,7 +2600,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
if (!(sdata->dev->flags & IFF_PROMISC))
return 0;
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
}
break;
case NL80211_IFTYPE_AP_VLAN:
@@ -2416,9 +2611,9 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
return 0;
} else if (!ieee80211_bssid_match(bssid,
sdata->vif.addr)) {
- if (!(rx->flags & IEEE80211_RX_IN_SCAN))
+ if (!(status->rx_flags & IEEE80211_RX_IN_SCAN))
return 0;
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
}
break;
case NL80211_IFTYPE_WDS:
@@ -2427,9 +2622,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
return 0;
break;
- case NL80211_IFTYPE_MONITOR:
- case NL80211_IFTYPE_UNSPECIFIED:
- case __NL80211_IFTYPE_AFTER_LAST:
+ default:
/* should never get here */
WARN_ON(1);
break;
@@ -2439,12 +2632,56 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
}
/*
+ * This function returns whether or not the SKB
+ * was destined for RX processing or not, which,
+ * if consume is true, is equivalent to whether
+ * or not the skb was consumed.
+ */
+static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
+ struct sk_buff *skb, bool consume)
+{
+ struct ieee80211_local *local = rx->local;
+ struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+ int prepares;
+
+ rx->skb = skb;
+ status->rx_flags |= IEEE80211_RX_RA_MATCH;
+ prepares = prepare_for_handlers(rx, hdr);
+
+ if (!prepares)
+ return false;
+
+ if (status->flag & RX_FLAG_MMIC_ERROR) {
+ if (status->rx_flags & IEEE80211_RX_RA_MATCH)
+ ieee80211_rx_michael_mic_report(hdr, rx);
+ return false;
+ }
+
+ if (!consume) {
+ skb = skb_copy(skb, GFP_ATOMIC);
+ if (!skb) {
+ if (net_ratelimit())
+ wiphy_debug(local->hw.wiphy,
+ "failed to copy multicast frame for %s\n",
+ sdata->name);
+ return true;
+ }
+
+ rx->skb = skb;
+ }
+
+ ieee80211_invoke_rx_handlers(rx);
+ return true;
+}
+
+/*
* This is the actual Rx frames handler. as it blongs to Rx path it must
* be called with rcu_read_lock protection.
*/
static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ieee80211_rate *rate)
+ struct sk_buff *skb)
{
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_local *local = hw_to_local(hw);
@@ -2452,11 +2689,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr;
__le16 fc;
struct ieee80211_rx_data rx;
- int prepares;
- struct ieee80211_sub_if_data *prev = NULL;
- struct sk_buff *skb_new;
- struct sta_info *sta, *tmp;
- bool found_sta = false;
+ struct ieee80211_sub_if_data *prev;
+ struct sta_info *sta, *tmp, *prev_sta;
int err = 0;
fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
@@ -2469,7 +2703,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
- rx.flags |= IEEE80211_RX_IN_SCAN;
+ status->rx_flags |= IEEE80211_RX_IN_SCAN;
if (ieee80211_is_mgmt(fc))
err = skb_linearize(skb);
@@ -2486,91 +2720,67 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
ieee80211_verify_alignment(&rx);
if (ieee80211_is_data(fc)) {
+ prev_sta = NULL;
+
for_each_sta_info(local, hdr->addr2, sta, tmp) {
- rx.sta = sta;
- found_sta = true;
- rx.sdata = sta->sdata;
-
- rx.flags |= IEEE80211_RX_RA_MATCH;
- prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
- if (prepares) {
- if (status->flag & RX_FLAG_MMIC_ERROR) {
- if (rx.flags & IEEE80211_RX_RA_MATCH)
- ieee80211_rx_michael_mic_report(hdr, &rx);
- } else
- prev = rx.sdata;
- }
- }
- }
- if (!found_sta) {
- list_for_each_entry_rcu(sdata, &local->interfaces, list) {
- if (!ieee80211_sdata_running(sdata))
+ if (!prev_sta) {
+ prev_sta = sta;
continue;
+ }
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
- sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- continue;
+ rx.sta = prev_sta;
+ rx.sdata = prev_sta->sdata;
+ ieee80211_prepare_and_rx_handle(&rx, skb, false);
- /*
- * frame is destined for this interface, but if it's
- * not also for the previous one we handle that after
- * the loop to avoid copying the SKB once too much
- */
+ prev_sta = sta;
+ }
- if (!prev) {
- prev = sdata;
- continue;
- }
+ if (prev_sta) {
+ rx.sta = prev_sta;
+ rx.sdata = prev_sta->sdata;
- rx.sta = sta_info_get_bss(prev, hdr->addr2);
+ if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
+ return;
+ }
+ }
- rx.flags |= IEEE80211_RX_RA_MATCH;
- prepares = prepare_for_handlers(prev, &rx, hdr);
+ prev = NULL;
- if (!prepares)
- goto next;
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (!ieee80211_sdata_running(sdata))
+ continue;
- if (status->flag & RX_FLAG_MMIC_ERROR) {
- rx.sdata = prev;
- if (rx.flags & IEEE80211_RX_RA_MATCH)
- ieee80211_rx_michael_mic_report(hdr,
- &rx);
- goto next;
- }
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ continue;
- /*
- * frame was destined for the previous interface
- * so invoke RX handlers for it
- */
+ /*
+ * frame is destined for this interface, but if it's
+ * not also for the previous one we handle that after
+ * the loop to avoid copying the SKB once too much
+ */
- skb_new = skb_copy(skb, GFP_ATOMIC);
- if (!skb_new) {
- if (net_ratelimit())
- printk(KERN_DEBUG "%s: failed to copy "
- "multicast frame for %s\n",
- wiphy_name(local->hw.wiphy),
- prev->name);
- goto next;
- }
- ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate);
-next:
+ if (!prev) {
prev = sdata;
+ continue;
}
- if (prev) {
- rx.sta = sta_info_get_bss(prev, hdr->addr2);
+ rx.sta = sta_info_get_bss(prev, hdr->addr2);
+ rx.sdata = prev;
+ ieee80211_prepare_and_rx_handle(&rx, skb, false);
- rx.flags |= IEEE80211_RX_RA_MATCH;
- prepares = prepare_for_handlers(prev, &rx, hdr);
+ prev = sdata;
+ }
- if (!prepares)
- prev = NULL;
- }
+ if (prev) {
+ rx.sta = sta_info_get_bss(prev, hdr->addr2);
+ rx.sdata = prev;
+
+ if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
+ return;
}
- if (prev)
- ieee80211_invoke_rx_handlers(prev, &rx, skb, rate);
- else
- dev_kfree_skb(skb);
+
+ dev_kfree_skb(skb);
}
/*
@@ -2611,30 +2821,41 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
if (WARN_ON(!local->started))
goto drop;
- if (status->flag & RX_FLAG_HT) {
+ if (likely(!(status->flag & RX_FLAG_FAILED_PLCP_CRC))) {
/*
- * rate_idx is MCS index, which can be [0-76] as documented on:
- *
- * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n
- *
- * Anything else would be some sort of driver or hardware error.
- * The driver should catch hardware errors.
+ * Validate the rate, unless a PLCP error means that
+ * we probably can't have a valid rate here anyway.
*/
- if (WARN((status->rate_idx < 0 ||
- status->rate_idx > 76),
- "Rate marked as an HT rate but passed "
- "status->rate_idx is not "
- "an MCS index [0-76]: %d (0x%02x)\n",
- status->rate_idx,
- status->rate_idx))
- goto drop;
- } else {
- if (WARN_ON(status->rate_idx < 0 ||
- status->rate_idx >= sband->n_bitrates))
- goto drop;
- rate = &sband->bitrates[status->rate_idx];
+
+ if (status->flag & RX_FLAG_HT) {
+ /*
+ * rate_idx is MCS index, which can be [0-76]
+ * as documented on:
+ *
+ * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n
+ *
+ * Anything else would be some sort of driver or
+ * hardware error. The driver should catch hardware
+ * errors.
+ */
+ if (WARN((status->rate_idx < 0 ||
+ status->rate_idx > 76),
+ "Rate marked as an HT rate but passed "
+ "status->rate_idx is not "
+ "an MCS index [0-76]: %d (0x%02x)\n",
+ status->rate_idx,
+ status->rate_idx))
+ goto drop;
+ } else {
+ if (WARN_ON(status->rate_idx < 0 ||
+ status->rate_idx >= sband->n_bitrates))
+ goto drop;
+ rate = &sband->bitrates[status->rate_idx];
+ }
}
+ status->rx_flags = 0;
+
/*
* key references and virtual interfaces are protected using RCU
* and this requires that we are in a read-side RCU section during
@@ -2654,7 +2875,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
return;
}
- __ieee80211_rx_handle_packet(hw, skb, rate);
+ __ieee80211_rx_handle_packet(hw, skb);
rcu_read_unlock();
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 872d7b6ef6b3..fb274db77e3c 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -242,20 +242,19 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
local->hw_scan_req->n_channels = n_chans;
ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie,
- req->ie, req->ie_len, band);
+ req->ie, req->ie_len, band, (u32) -1,
+ 0);
local->hw_scan_req->ie_len = ielen;
return true;
}
-void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
+static bool __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
+ bool was_hw_scan)
{
struct ieee80211_local *local = hw_to_local(hw);
- bool was_hw_scan;
-
- trace_api_scan_completed(local, aborted);
- mutex_lock(&local->scan_mtx);
+ lockdep_assert_held(&local->mtx);
/*
* It's ok to abort a not-yet-running scan (that
@@ -266,17 +265,13 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
if (WARN_ON(!local->scanning && !aborted))
aborted = true;
- if (WARN_ON(!local->scan_req)) {
- mutex_unlock(&local->scan_mtx);
- return;
- }
+ if (WARN_ON(!local->scan_req))
+ return false;
- was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
- ieee80211_queue_delayed_work(&local->hw,
- &local->scan_work, 0);
- mutex_unlock(&local->scan_mtx);
- return;
+ int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req);
+ if (rc == 0)
+ return false;
}
kfree(local->hw_scan_req);
@@ -290,26 +285,42 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
local->scanning = 0;
local->scan_channel = NULL;
- /* we only have to protect scan_req and hw/sw scan */
- mutex_unlock(&local->scan_mtx);
-
- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
- if (was_hw_scan)
- goto done;
-
- ieee80211_configure_filter(local);
+ return true;
+}
- drv_sw_scan_complete(local);
+static void __ieee80211_scan_completed_finish(struct ieee80211_hw *hw,
+ bool was_hw_scan)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
- ieee80211_offchannel_return(local, true);
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+ if (!was_hw_scan) {
+ ieee80211_configure_filter(local);
+ drv_sw_scan_complete(local);
+ ieee80211_offchannel_return(local, true);
+ }
- done:
+ mutex_lock(&local->mtx);
ieee80211_recalc_idle(local);
+ mutex_unlock(&local->mtx);
+
ieee80211_mlme_notify_scan_completed(local);
ieee80211_ibss_notify_scan_completed(local);
ieee80211_mesh_notify_scan_completed(local);
ieee80211_queue_work(&local->hw, &local->work_work);
}
+
+void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ trace_api_scan_completed(local, aborted);
+
+ set_bit(SCAN_COMPLETED, &local->scanning);
+ if (aborted)
+ set_bit(SCAN_ABORTED, &local->scanning);
+ ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
+}
EXPORT_SYMBOL(ieee80211_scan_completed);
static int ieee80211_start_sw_scan(struct ieee80211_local *local)
@@ -353,6 +364,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
int rc;
+ lockdep_assert_held(&local->mtx);
+
if (local->scan_req)
return -EBUSY;
@@ -434,8 +447,8 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
}
-static int ieee80211_scan_state_decision(struct ieee80211_local *local,
- unsigned long *next_delay)
+static void ieee80211_scan_state_decision(struct ieee80211_local *local,
+ unsigned long *next_delay)
{
bool associated = false;
bool tx_empty = true;
@@ -445,12 +458,6 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata;
struct ieee80211_channel *next_chan;
- /* if no more bands/channels left, complete scan and advance to the idle state */
- if (local->scan_channel_idx >= local->scan_req->n_channels) {
- ieee80211_scan_completed(&local->hw, false);
- return 1;
- }
-
/*
* check if at least one STA interface is associated,
* check if at least one STA interface has pending tx frames
@@ -522,7 +529,6 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
}
*next_delay = 0;
- return 0;
}
static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
@@ -638,21 +644,18 @@ void ieee80211_scan_work(struct work_struct *work)
container_of(work, struct ieee80211_local, scan_work.work);
struct ieee80211_sub_if_data *sdata = local->scan_sdata;
unsigned long next_delay = 0;
+ bool aborted, hw_scan, finish;
- mutex_lock(&local->scan_mtx);
- if (!sdata || !local->scan_req) {
- mutex_unlock(&local->scan_mtx);
- return;
- }
+ mutex_lock(&local->mtx);
- if (local->hw_scan_req) {
- int rc = drv_hw_scan(local, sdata, local->hw_scan_req);
- mutex_unlock(&local->scan_mtx);
- if (rc)
- ieee80211_scan_completed(&local->hw, true);
- return;
+ if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) {
+ aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning);
+ goto out_complete;
}
+ if (!sdata || !local->scan_req)
+ goto out;
+
if (local->scan_req && !local->scanning) {
struct cfg80211_scan_request *req = local->scan_req;
int rc;
@@ -661,21 +664,21 @@ void ieee80211_scan_work(struct work_struct *work)
local->scan_sdata = NULL;
rc = __ieee80211_start_scan(sdata, req);
- mutex_unlock(&local->scan_mtx);
-
- if (rc)
- ieee80211_scan_completed(&local->hw, true);
- return;
+ if (rc) {
+ /* need to complete scan in cfg80211 */
+ local->scan_req = req;
+ aborted = true;
+ goto out_complete;
+ } else
+ goto out;
}
- mutex_unlock(&local->scan_mtx);
-
/*
* Avoid re-scheduling when the sdata is going away.
*/
if (!ieee80211_sdata_running(sdata)) {
- ieee80211_scan_completed(&local->hw, true);
- return;
+ aborted = true;
+ goto out_complete;
}
/*
@@ -685,8 +688,12 @@ void ieee80211_scan_work(struct work_struct *work)
do {
switch (local->next_scan_state) {
case SCAN_DECISION:
- if (ieee80211_scan_state_decision(local, &next_delay))
- return;
+ /* if no more bands/channels left, complete scan */
+ if (local->scan_channel_idx >= local->scan_req->n_channels) {
+ aborted = false;
+ goto out_complete;
+ }
+ ieee80211_scan_state_decision(local, &next_delay);
break;
case SCAN_SET_CHANNEL:
ieee80211_scan_state_set_channel(local, &next_delay);
@@ -704,6 +711,19 @@ void ieee80211_scan_work(struct work_struct *work)
} while (next_delay == 0);
ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay);
+ mutex_unlock(&local->mtx);
+ return;
+
+out_complete:
+ hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
+ finish = __ieee80211_scan_completed(&local->hw, aborted, hw_scan);
+ mutex_unlock(&local->mtx);
+ if (finish)
+ __ieee80211_scan_completed_finish(&local->hw, hw_scan);
+ return;
+
+out:
+ mutex_unlock(&local->mtx);
}
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
@@ -711,9 +731,9 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
{
int res;
- mutex_lock(&sdata->local->scan_mtx);
+ mutex_lock(&sdata->local->mtx);
res = __ieee80211_start_scan(sdata, req);
- mutex_unlock(&sdata->local->scan_mtx);
+ mutex_unlock(&sdata->local->mtx);
return res;
}
@@ -726,7 +746,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
int ret = -EBUSY;
enum ieee80211_band band;
- mutex_lock(&local->scan_mtx);
+ mutex_lock(&local->mtx);
/* busy scanning */
if (local->scan_req)
@@ -761,25 +781,44 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req);
unlock:
- mutex_unlock(&local->scan_mtx);
+ mutex_unlock(&local->mtx);
return ret;
}
+/*
+ * Only call this function when a scan can't be queued -- under RTNL.
+ */
void ieee80211_scan_cancel(struct ieee80211_local *local)
{
bool abortscan;
-
- cancel_delayed_work_sync(&local->scan_work);
+ bool finish = false;
/*
- * Only call this function when a scan can't be
- * queued -- mostly at suspend under RTNL.
+ * We are only canceling software scan, or deferred scan that was not
+ * yet really started (see __ieee80211_start_scan ).
+ *
+ * Regarding hardware scan:
+ * - we can not call __ieee80211_scan_completed() as when
+ * SCAN_HW_SCANNING bit is set this function change
+ * local->hw_scan_req to operate on 5G band, what race with
+ * driver which can use local->hw_scan_req
+ *
+ * - we can not cancel scan_work since driver can schedule it
+ * by ieee80211_scan_completed(..., true) to finish scan
+ *
+ * Hence low lever driver is responsible for canceling HW scan.
*/
- mutex_lock(&local->scan_mtx);
- abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
- (!local->scanning && local->scan_req);
- mutex_unlock(&local->scan_mtx);
+ mutex_lock(&local->mtx);
+ abortscan = local->scan_req && !test_bit(SCAN_HW_SCANNING, &local->scanning);
if (abortscan)
- ieee80211_scan_completed(&local->hw, true);
+ finish = __ieee80211_scan_completed(&local->hw, true, false);
+ mutex_unlock(&local->mtx);
+
+ if (abortscan) {
+ /* The scan is canceled, but stop work from being pending */
+ cancel_delayed_work_sync(&local->scan_work);
+ }
+ if (finish)
+ __ieee80211_scan_completed_finish(&local->hw, false);
}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 6d86f0c1ad04..6d8f897d8763 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -125,7 +125,7 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
lockdep_is_held(&local->sta_mtx));
while (sta) {
if ((sta->sdata == sdata ||
- sta->sdata->bss == sdata->bss) &&
+ (sta->sdata->bss && sta->sdata->bss == sdata->bss)) &&
memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
break;
sta = rcu_dereference_check(sta->hnext,
@@ -174,8 +174,7 @@ static void __sta_info_free(struct ieee80211_local *local,
}
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: Destroyed STA %pM\n",
- wiphy_name(local->hw.wiphy), sta->sta.addr);
+ wiphy_debug(local->hw.wiphy, "Destroyed STA %pM\n", sta->sta.addr);
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
kfree(sta);
@@ -262,8 +261,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: Allocated STA %pM\n",
- wiphy_name(local->hw.wiphy), sta->sta.addr);
+ wiphy_debug(local->hw.wiphy, "Allocated STA %pM\n", sta->sta.addr);
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
#ifdef CONFIG_MAC80211_MESH
@@ -282,7 +280,7 @@ static int sta_info_finish_insert(struct sta_info *sta, bool async)
unsigned long flags;
int err = 0;
- WARN_ON(!mutex_is_locked(&local->sta_mtx));
+ lockdep_assert_held(&local->sta_mtx);
/* notify driver */
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
@@ -300,8 +298,9 @@ static int sta_info_finish_insert(struct sta_info *sta, bool async)
sta->uploaded = true;
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (async)
- printk(KERN_DEBUG "%s: Finished adding IBSS STA %pM\n",
- wiphy_name(local->hw.wiphy), sta->sta.addr);
+ wiphy_debug(local->hw.wiphy,
+ "Finished adding IBSS STA %pM\n",
+ sta->sta.addr);
#endif
}
@@ -411,8 +410,8 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
spin_unlock_irqrestore(&local->sta_lock, flags);
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: Added IBSS STA %pM\n",
- wiphy_name(local->hw.wiphy), 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);
@@ -459,8 +458,7 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
}
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: Inserted STA %pM\n",
- wiphy_name(local->hw.wiphy), sta->sta.addr);
+ wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr);
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
/* move reference to rcu-protected */
@@ -618,7 +616,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
struct ieee80211_sub_if_data *sdata;
struct sk_buff *skb;
unsigned long flags;
- int ret;
+ int ret, i;
might_sleep();
@@ -635,7 +633,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
* will be sufficient.
*/
set_sta_flags(sta, WLAN_STA_BLOCK_BA);
- ieee80211_sta_tear_down_BA_sessions(sta);
+ ieee80211_sta_tear_down_BA_sessions(sta, true);
spin_lock_irqsave(&local->sta_lock, flags);
ret = sta_info_hash_del(local, sta);
@@ -646,10 +644,10 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
if (ret)
return ret;
- if (sta->key) {
- ieee80211_key_free(local, sta->key);
- WARN_ON(sta->key);
- }
+ for (i = 0; i < NUM_DEFAULT_KEYS; i++)
+ ieee80211_key_free(local, sta->gtk[i]);
+ if (sta->ptk)
+ ieee80211_key_free(local, sta->ptk);
sta->dead = true;
@@ -690,8 +688,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
#endif
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: Removed STA %pM\n",
- wiphy_name(local->hw.wiphy), sta->sta.addr);
+ wiphy_debug(local->hw.wiphy, "Removed STA %pM\n", sta->sta.addr);
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
cancel_work_sync(&sta->drv_unblock_wk);
@@ -841,13 +838,20 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
mutex_unlock(&local->sta_mtx);
}
-struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw,
- const u8 *addr)
+struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw,
+ const u8 *addr,
+ const u8 *localaddr)
{
struct sta_info *sta, *nxt;
- /* Just return a random station ... first in list ... */
+ /*
+ * Just return a random station if localaddr is NULL
+ * ... first in list.
+ */
for_each_sta_info(hw_to_local(hw), addr, sta, nxt) {
+ if (localaddr &&
+ compare_ether_addr(sta->sdata->vif.addr, localaddr) != 0)
+ continue;
if (!sta->uploaded)
return NULL;
return &sta->sta;
@@ -855,7 +859,7 @@ struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw,
return NULL;
}
-EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw);
+EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_ifaddr);
struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
const u8 *addr)
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 54262e72376d..9265acadef32 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -79,6 +79,7 @@ enum ieee80211_sta_info_flags {
* @dialog_token: dialog token for aggregation session
* @state: session state (see above)
* @stop_initiator: initiator of a session stop
+ * @tx_stop: TX DelBA frame when stopping
*
* This structure is protected by RCU and the per-station
* spinlock. Assignments to the array holding it must hold
@@ -95,6 +96,7 @@ struct tid_ampdu_tx {
unsigned long state;
u8 dialog_token;
u8 stop_initiator;
+ bool tx_stop;
};
/**
@@ -103,6 +105,7 @@ struct tid_ampdu_tx {
* @reorder_buf: buffer to reorder incoming aggregated MPDUs
* @reorder_time: jiffies when skb was added
* @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
+ * @reorder_timer: releases expired frames from the reorder buffer.
* @head_seq_num: head sequence number in reordering buffer.
* @stored_mpdu_num: number of MPDUs in reordering buffer
* @ssn: Starting Sequence Number expected to be aggregated.
@@ -110,20 +113,25 @@ struct tid_ampdu_tx {
* @timeout: reset timer value (in TUs).
* @dialog_token: dialog token for aggregation session
* @rcu_head: RCU head used for freeing this struct
+ * @reorder_lock: serializes access to reorder buffer, see below.
*
* This structure is protected by RCU and the per-station
* spinlock. Assignments to the array holding it must hold
- * the spinlock, only the RX path can access it under RCU
- * lock-free. The RX path, since it is single-threaded,
- * can even modify the structure without locking since the
- * only other modifications to it are done when the struct
- * can not yet or no longer be found by the RX path.
+ * the spinlock.
+ *
+ * The @reorder_lock is used to protect the variables and
+ * arrays such as @reorder_buf, @reorder_time, @head_seq_num,
+ * @stored_mpdu_num and @reorder_time from being corrupted by
+ * concurrent access of the RX path and the expired frame
+ * release timer.
*/
struct tid_ampdu_rx {
struct rcu_head rcu_head;
+ spinlock_t reorder_lock;
struct sk_buff **reorder_buf;
unsigned long *reorder_time;
struct timer_list session_timer;
+ struct timer_list reorder_timer;
u16 head_seq_num;
u16 stored_mpdu_num;
u16 ssn;
@@ -191,7 +199,8 @@ enum plink_state {
* @hnext: hash table linked list pointer
* @local: pointer to the global information
* @sdata: virtual interface this station belongs to
- * @key: peer key negotiated with this station, if any
+ * @ptk: peer key negotiated with this station, if any
+ * @gtk: group keys negotiated with this station, if any
* @rate_ctrl: rate control algorithm reference
* @rate_ctrl_priv: rate control private per-STA pointer
* @last_tx_rate: rate used for last transmit, to report to userspace as
@@ -246,7 +255,8 @@ struct sta_info {
struct sta_info *hnext;
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
- struct ieee80211_key *key;
+ struct ieee80211_key *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
+ struct ieee80211_key *ptk;
struct rate_control_ref *rate_ctrl;
void *rate_ctrl_priv;
spinlock_t lock;
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 34da67995d94..3153c19893b8 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -58,6 +58,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
info->control.vif = &sta->sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING |
IEEE80211_TX_INTFL_RETRANSMISSION;
+ info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
sta->tx_filtered_count++;
@@ -114,11 +115,10 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit())
- printk(KERN_DEBUG "%s: dropped TX filtered frame, "
- "queue_len=%d PS=%d @%lu\n",
- wiphy_name(local->hw.wiphy),
- skb_queue_len(&sta->tx_filtered),
- !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
+ 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);
#endif
dev_kfree_skb(skb);
}
@@ -176,7 +176,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
/* the HW cannot have attempted that rate */
- if (i >= hw->max_rates) {
+ if (i >= hw->max_report_rates) {
info->status.rates[i].idx = -1;
info->status.rates[i].count = 0;
} else if (info->status.rates[i].idx >= 0) {
@@ -296,7 +296,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
}
if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX)
- cfg80211_action_tx_status(
+ cfg80211_mgmt_tx_status(
skb->dev, (unsigned long) skb, skb->data, skb->len,
!!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index c54db966926b..96c594309506 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -273,6 +273,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
*/
return TX_DROP;
+ if (tx->sdata->vif.type == NL80211_IFTYPE_WDS)
+ return TX_CONTINUE;
+
if (tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
return TX_CONTINUE;
@@ -351,8 +354,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
local->total_ps_buffered = total;
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n",
- wiphy_name(local->hw.wiphy), purged);
+ wiphy_debug(local->hw.wiphy, "PS buffers full - purged %d frames\n",
+ purged);
#endif
}
@@ -509,6 +512,18 @@ ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx)
}
static ieee80211_tx_result debug_noinline
+ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
+ if (unlikely(tx->sdata->control_port_protocol == tx->skb->protocol &&
+ tx->sdata->control_port_no_encrypt))
+ info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+
+ return TX_CONTINUE;
+}
+
+static ieee80211_tx_result debug_noinline
ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
{
struct ieee80211_key *key = NULL;
@@ -517,7 +532,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
tx->key = NULL;
- else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
+ else if (tx->sta && (key = rcu_dereference(tx->sta->ptk)))
tx->key = key;
else if (ieee80211_is_mgmt(hdr->frame_control) &&
is_multicast_ether_addr(hdr->addr1) &&
@@ -527,7 +542,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
else if ((key = rcu_dereference(tx->sdata->default_key)))
tx->key = key;
else if (tx->sdata->drop_unencrypted &&
- (tx->skb->protocol != cpu_to_be16(ETH_P_PAE)) &&
+ (tx->skb->protocol != tx->sdata->control_port_protocol) &&
!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
(!ieee80211_is_robust_mgmt_frame(hdr) ||
(ieee80211_is_action(hdr->frame_control) &&
@@ -543,15 +558,16 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
tx->key->tx_rx_count++;
/* TODO: add threshold stuff again */
- switch (tx->key->conf.alg) {
- case ALG_WEP:
+ switch (tx->key->conf.cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
if (ieee80211_is_auth(hdr->frame_control))
break;
- case ALG_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
if (!ieee80211_is_data_present(hdr->frame_control))
tx->key = NULL;
break;
- case ALG_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
if (!ieee80211_is_data_present(hdr->frame_control) &&
!ieee80211_use_mfp(hdr->frame_control, tx->sta,
tx->skb))
@@ -561,7 +577,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
IEEE80211_KEY_FLAG_SW_MGMT) &&
ieee80211_is_mgmt(hdr->frame_control);
break;
- case ALG_AES_CMAC:
+ case WLAN_CIPHER_SUITE_AES_CMAC:
if (!ieee80211_is_mgmt(hdr->frame_control))
tx->key = NULL;
break;
@@ -946,22 +962,31 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
static ieee80211_tx_result debug_noinline
ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
if (!tx->key)
return TX_CONTINUE;
- switch (tx->key->conf.alg) {
- case ALG_WEP:
+ switch (tx->key->conf.cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
return ieee80211_crypto_wep_encrypt(tx);
- case ALG_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
return ieee80211_crypto_tkip_encrypt(tx);
- case ALG_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
return ieee80211_crypto_ccmp_encrypt(tx);
- case ALG_AES_CMAC:
+ case WLAN_CIPHER_SUITE_AES_CMAC:
return ieee80211_crypto_aes_cmac_encrypt(tx);
+ default:
+ /* handle hw-only algorithm */
+ if (info->control.hw_key) {
+ ieee80211_tx_set_protected(tx);
+ return TX_CONTINUE;
+ }
+ break;
+
}
- /* not reached */
- WARN_ON(1);
return TX_DROP;
}
@@ -1339,6 +1364,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
CALL_TXH(ieee80211_tx_h_dynamic_ps);
CALL_TXH(ieee80211_tx_h_check_assoc);
CALL_TXH(ieee80211_tx_h_ps_buf);
+ CALL_TXH(ieee80211_tx_h_check_control_port_protocol);
CALL_TXH(ieee80211_tx_h_select_key);
if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
CALL_TXH(ieee80211_tx_h_rate_ctrl);
@@ -1511,8 +1537,8 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
I802_DEBUG_INC(local->tx_expand_skb_head);
if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) {
- printk(KERN_DEBUG "%s: failed to reallocate TX buffer\n",
- wiphy_name(local->hw.wiphy));
+ wiphy_debug(local->hw.wiphy,
+ "failed to reallocate TX buffer\n");
return -ENOMEM;
}
@@ -1586,6 +1612,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
return;
}
+ hdr = (struct ieee80211_hdr *) skb->data;
info->control.vif = &sdata->vif;
if (ieee80211_vif_is_mesh(&sdata->vif) &&
@@ -1699,7 +1726,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
u16 ethertype, hdrlen, meshhdrlen = 0;
__le16 fc;
struct ieee80211_hdr hdr;
- struct ieee80211s_hdr mesh_hdr;
+ struct ieee80211s_hdr mesh_hdr __maybe_unused;
const u8 *encaps_data;
int encaps_len, skip_header_bytes;
int nh_pos, h_pos;
@@ -1816,7 +1843,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
#endif
case NL80211_IFTYPE_STATION:
memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
- if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) {
+ 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.addr2, sdata->vif.addr, ETH_ALEN);
@@ -1869,7 +1897,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
if (!ieee80211_vif_is_mesh(&sdata->vif) &&
unlikely(!is_multicast_ether_addr(hdr.addr1) &&
!(sta_flags & WLAN_STA_AUTHORIZED) &&
- !(ethertype == ETH_P_PAE &&
+ !(cpu_to_be16(ethertype) == sdata->control_port_protocol &&
compare_ether_addr(sdata->vif.addr,
skb->data + ETH_ALEN) == 0))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -2068,8 +2096,7 @@ void ieee80211_tx_pending(unsigned long data)
if (skb_queue_empty(&local->pending[i]))
list_for_each_entry_rcu(sdata, &local->interfaces, list)
- netif_tx_wake_queue(
- netdev_get_tx_queue(sdata->dev, i));
+ netif_wake_subqueue(sdata->dev, i);
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 748387d45bc0..0b6fc92bc0d7 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -283,8 +283,11 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
if (skb_queue_empty(&local->pending[queue])) {
rcu_read_lock();
- list_for_each_entry_rcu(sdata, &local->interfaces, list)
- netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
+ continue;
+ netif_wake_subqueue(sdata->dev, queue);
+ }
rcu_read_unlock();
} else
tasklet_schedule(&local->tx_pending_tasklet);
@@ -323,7 +326,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list)
- netif_tx_stop_queue(netdev_get_tx_queue(sdata->dev, queue));
+ netif_stop_subqueue(sdata->dev, queue);
rcu_read_unlock();
}
@@ -471,16 +474,10 @@ void ieee80211_iterate_active_interfaces(
list_for_each_entry(sdata, &local->interfaces, list) {
switch (sdata->vif.type) {
- case __NL80211_IFTYPE_AFTER_LAST:
- case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_AP_VLAN:
continue;
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_WDS:
- case NL80211_IFTYPE_MESH_POINT:
+ default:
break;
}
if (ieee80211_sdata_running(sdata))
@@ -505,16 +502,10 @@ void ieee80211_iterate_active_interfaces_atomic(
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
switch (sdata->vif.type) {
- case __NL80211_IFTYPE_AFTER_LAST:
- case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_AP_VLAN:
continue;
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_WDS:
- case NL80211_IFTYPE_MESH_POINT:
+ default:
break;
}
if (ieee80211_sdata_running(sdata))
@@ -904,26 +895,34 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
const u8 *ie, size_t ie_len,
- enum ieee80211_band band)
+ enum ieee80211_band band, u32 rate_mask,
+ u8 channel)
{
struct ieee80211_supported_band *sband;
u8 *pos;
size_t offset = 0, noffset;
int supp_rates_len, i;
+ u8 rates[32];
+ int num_rates;
+ int ext_rates_len;
sband = local->hw.wiphy->bands[band];
pos = buffer;
- supp_rates_len = min_t(int, sband->n_bitrates, 8);
+ num_rates = 0;
+ for (i = 0; i < sband->n_bitrates; i++) {
+ if ((BIT(i) & rate_mask) == 0)
+ continue; /* skip rate */
+ rates[num_rates++] = (u8) (sband->bitrates[i].bitrate / 5);
+ }
+
+ supp_rates_len = min_t(int, num_rates, 8);
*pos++ = WLAN_EID_SUPP_RATES;
*pos++ = supp_rates_len;
-
- for (i = 0; i < supp_rates_len; i++) {
- int rate = sband->bitrates[i].bitrate;
- *pos++ = (u8) (rate / 5);
- }
+ memcpy(pos, rates, supp_rates_len);
+ pos += supp_rates_len;
/* insert "request information" if in custom IEs */
if (ie && ie_len) {
@@ -941,14 +940,18 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
offset = noffset;
}
- if (sband->n_bitrates > i) {
+ ext_rates_len = num_rates - supp_rates_len;
+ if (ext_rates_len > 0) {
*pos++ = WLAN_EID_EXT_SUPP_RATES;
- *pos++ = sband->n_bitrates - i;
+ *pos++ = ext_rates_len;
+ memcpy(pos, rates + supp_rates_len, ext_rates_len);
+ pos += ext_rates_len;
+ }
- for (; i < sband->n_bitrates; i++) {
- int rate = sband->bitrates[i].bitrate;
- *pos++ = (u8) (rate / 5);
- }
+ if (channel && sband->band == IEEE80211_BAND_2GHZ) {
+ *pos++ = WLAN_EID_DS_PARAMS;
+ *pos++ = 1;
+ *pos++ = channel;
}
/* insert custom IEs that go before HT */
@@ -1017,6 +1020,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
struct ieee80211_mgmt *mgmt;
size_t buf_len;
u8 *buf;
+ u8 chan;
/* FIXME: come up with a proper value */
buf = kmalloc(200 + ie_len, GFP_KERNEL);
@@ -1026,8 +1030,14 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
return;
}
+ chan = ieee80211_frequency_to_channel(
+ local->hw.conf.channel->center_freq);
+
buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len,
- local->hw.conf.channel->band);
+ local->hw.conf.channel->band,
+ sdata->rc_rateidx_mask
+ [local->hw.conf.channel->band],
+ chan);
skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
ssid, ssid_len,
@@ -1189,7 +1199,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
/* ignore virtual */
break;
case NL80211_IFTYPE_UNSPECIFIED:
- case __NL80211_IFTYPE_AFTER_LAST:
+ case NUM_NL80211_IFTYPES:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
WARN_ON(1);
break;
}
@@ -1209,7 +1221,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list) {
- ieee80211_sta_tear_down_BA_sessions(sta);
+ ieee80211_sta_tear_down_BA_sessions(sta, true);
clear_sta_flags(sta, WLAN_STA_BLOCK_BA);
}
@@ -1285,17 +1297,13 @@ static int check_mgd_smps(struct ieee80211_if_managed *ifmgd,
}
/* must hold iflist_mtx */
-void ieee80211_recalc_smps(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *forsdata)
+void ieee80211_recalc_smps(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF;
int count = 0;
- if (forsdata)
- WARN_ON(!mutex_is_locked(&forsdata->u.mgd.mtx));
-
- WARN_ON(!mutex_is_locked(&local->iflist_mtx));
+ lockdep_assert_held(&local->iflist_mtx);
/*
* This function could be improved to handle multiple
@@ -1308,22 +1316,12 @@ void ieee80211_recalc_smps(struct ieee80211_local *local,
*/
list_for_each_entry(sdata, &local->interfaces, list) {
- if (!netif_running(sdata->dev))
+ if (!ieee80211_sdata_running(sdata))
continue;
if (sdata->vif.type != NL80211_IFTYPE_STATION)
goto set;
- if (sdata != forsdata) {
- /*
- * This nested is ok -- we are holding the iflist_mtx
- * so can't get here twice or so. But it's required
- * since normally we acquire it first and then the
- * iflist_mtx.
- */
- mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING);
- count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
- mutex_unlock(&sdata->u.mgd.mtx);
- } else
- count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
+
+ count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
if (count > 1) {
smps_mode = IEEE80211_SMPS_OFF;
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index 9ebc8d8a1f5b..2ff6d1e3ed21 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -222,7 +222,7 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local,
struct ieee80211_key *key)
{
u32 klen;
- u8 *rc4key;
+ u8 rc4key[3 + WLAN_KEY_LEN_WEP104];
u8 keyidx;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
unsigned int hdrlen;
@@ -240,15 +240,11 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local,
keyidx = skb->data[hdrlen + 3] >> 6;
- if (!key || keyidx != key->conf.keyidx || key->conf.alg != ALG_WEP)
+ if (!key || keyidx != key->conf.keyidx)
return -1;
klen = 3 + key->conf.keylen;
- rc4key = kmalloc(klen, GFP_ATOMIC);
- if (!rc4key)
- return -1;
-
/* Prepend 24-bit IV to RC4 key */
memcpy(rc4key, skb->data + hdrlen, 3);
@@ -260,8 +256,6 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local,
len))
ret = -1;
- kfree(rc4key);
-
/* Trim ICV */
skb_trim(skb, skb->len - WEP_ICV_LEN);
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index 81d4ad64184a..ae344d1ba056 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -43,7 +43,7 @@ enum work_action {
/* utils */
static inline void ASSERT_WORK_MTX(struct ieee80211_local *local)
{
- WARN_ON(!mutex_is_locked(&local->work_mtx));
+ lockdep_assert_held(&local->mtx);
}
/*
@@ -757,7 +757,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
mgmt = (struct ieee80211_mgmt *) skb->data;
fc = le16_to_cpu(mgmt->frame_control);
- mutex_lock(&local->work_mtx);
+ mutex_lock(&local->mtx);
list_for_each_entry(wk, &local->work_list, list) {
const u8 *bssid = NULL;
@@ -833,7 +833,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
WARN(1, "unexpected: %d", rma);
}
- mutex_unlock(&local->work_mtx);
+ mutex_unlock(&local->mtx);
if (rma != WORK_ACT_DONE)
goto out;
@@ -845,9 +845,9 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
case WORK_DONE_REQUEUE:
synchronize_rcu();
wk->started = false; /* restart */
- mutex_lock(&local->work_mtx);
+ mutex_lock(&local->mtx);
list_add_tail(&wk->list, &local->work_list);
- mutex_unlock(&local->work_mtx);
+ mutex_unlock(&local->mtx);
}
out:
@@ -888,9 +888,9 @@ static void ieee80211_work_work(struct work_struct *work)
while ((skb = skb_dequeue(&local->work_skb_queue)))
ieee80211_work_rx_queued_mgmt(local, skb);
- ieee80211_recalc_idle(local);
+ mutex_lock(&local->mtx);
- mutex_lock(&local->work_mtx);
+ ieee80211_recalc_idle(local);
list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
bool started = wk->started;
@@ -995,20 +995,16 @@ static void ieee80211_work_work(struct work_struct *work)
run_again(local, jiffies + HZ/2);
}
- mutex_lock(&local->scan_mtx);
-
if (list_empty(&local->work_list) && local->scan_req &&
!local->scanning)
ieee80211_queue_delayed_work(&local->hw,
&local->scan_work,
round_jiffies_relative(0));
- mutex_unlock(&local->scan_mtx);
-
- mutex_unlock(&local->work_mtx);
-
ieee80211_recalc_idle(local);
+ mutex_unlock(&local->mtx);
+
list_for_each_entry_safe(wk, tmp, &free_work, list) {
wk->done(wk, NULL);
list_del(&wk->list);
@@ -1035,16 +1031,15 @@ void ieee80211_add_work(struct ieee80211_work *wk)
wk->started = false;
local = wk->sdata->local;
- mutex_lock(&local->work_mtx);
+ mutex_lock(&local->mtx);
list_add_tail(&wk->list, &local->work_list);
- mutex_unlock(&local->work_mtx);
+ mutex_unlock(&local->mtx);
ieee80211_queue_work(&local->hw, &local->work_work);
}
void ieee80211_work_init(struct ieee80211_local *local)
{
- mutex_init(&local->work_mtx);
INIT_LIST_HEAD(&local->work_list);
setup_timer(&local->work_timer, ieee80211_work_timer,
(unsigned long)local);
@@ -1057,7 +1052,7 @@ void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
struct ieee80211_local *local = sdata->local;
struct ieee80211_work *wk;
- mutex_lock(&local->work_mtx);
+ mutex_lock(&local->mtx);
list_for_each_entry(wk, &local->work_list, list) {
if (wk->sdata != sdata)
continue;
@@ -1065,19 +1060,19 @@ void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
wk->started = true;
wk->timeout = jiffies;
}
- mutex_unlock(&local->work_mtx);
+ mutex_unlock(&local->mtx);
/* run cleanups etc. */
ieee80211_work_work(&local->work_work);
- mutex_lock(&local->work_mtx);
+ mutex_lock(&local->mtx);
list_for_each_entry(wk, &local->work_list, list) {
if (wk->sdata != sdata)
continue;
WARN_ON(1);
break;
}
- mutex_unlock(&local->work_mtx);
+ mutex_unlock(&local->mtx);
}
ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
@@ -1163,7 +1158,7 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
struct ieee80211_work *wk, *tmp;
bool found = false;
- mutex_lock(&local->work_mtx);
+ mutex_lock(&local->mtx);
list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
if ((unsigned long) wk == cookie) {
wk->timeout = jiffies;
@@ -1171,7 +1166,7 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
break;
}
}
- mutex_unlock(&local->work_mtx);
+ mutex_unlock(&local->mtx);
if (!found)
return -ENOENT;
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 8d59d27d887e..bee230d8fd11 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -36,8 +36,8 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
int tail;
hdr = (struct ieee80211_hdr *)skb->data;
- if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 ||
- !ieee80211_is_data_present(hdr->frame_control))
+ if (!tx->key || tx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
+ skb->len < 24 || !ieee80211_is_data_present(hdr->frame_control))
return TX_CONTINUE;
hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -94,7 +94,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
if (status->flag & RX_FLAG_MMIC_STRIPPED)
return RX_CONTINUE;
- if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
+ if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
!ieee80211_has_protected(hdr->frame_control) ||
!ieee80211_is_data_present(hdr->frame_control))
return RX_CONTINUE;
@@ -117,7 +117,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
key = &rx->key->conf.key[key_offset];
michael_mic(key, hdr, data, data_len, mic);
if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
- if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
return RX_DROP_UNUSABLE;
mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
@@ -221,19 +221,13 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
if (!rx->sta || skb->len - hdrlen < 12)
return RX_DROP_UNUSABLE;
- if (status->flag & RX_FLAG_DECRYPTED) {
- if (status->flag & RX_FLAG_IV_STRIPPED) {
- /*
- * Hardware took care of all processing, including
- * replay protection, and stripped the ICV/IV so
- * we cannot do any checks here.
- */
- return RX_CONTINUE;
- }
-
- /* let TKIP code verify IV, but skip decryption */
+ /*
+ * Let TKIP code verify IV, but skip decryption.
+ * In the case where hardware checks the IV as well,
+ * we don't even get here, see ieee80211_rx_h_decrypt()
+ */
+ if (status->flag & RX_FLAG_DECRYPTED)
hwaccel = 1;
- }
res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
key, skb->data + hdrlen,
@@ -447,10 +441,6 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
if (!rx->sta || data_len < 0)
return RX_DROP_UNUSABLE;
- if ((status->flag & RX_FLAG_DECRYPTED) &&
- (status->flag & RX_FLAG_IV_STRIPPED))
- return RX_CONTINUE;
-
ccmp_hdr2pn(pn, skb->data + hdrlen);
queue = ieee80211_is_mgmt(hdr->frame_control) ?
@@ -564,10 +554,6 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
if (!ieee80211_is_mgmt(hdr->frame_control))
return RX_CONTINUE;
- if ((status->flag & RX_FLAG_DECRYPTED) &&
- (status->flag & RX_FLAG_IV_STRIPPED))
- return RX_CONTINUE;
-
if (skb->len < 24 + sizeof(*mmie))
return RX_DROP_UNUSABLE;
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 43288259f4a1..1534f2b44caf 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -525,6 +525,7 @@ config NETFILTER_XT_TARGET_TPROXY
depends on NETFILTER_XTABLES
depends on NETFILTER_ADVANCED
select NF_DEFRAG_IPV4
+ select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES
help
This option adds a `TPROXY' target, which is somewhat similar to
REDIRECT. It can only be used in the mangle table and is useful
@@ -927,6 +928,7 @@ config NETFILTER_XT_MATCH_SOCKET
depends on NETFILTER_ADVANCED
depends on !NF_CONNTRACK || NF_CONNTRACK
select NF_DEFRAG_IPV4
+ select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES
help
This option adds a `socket' match, which can be used to match
packets for which a TCP or UDP socket lookup finds a valid socket.
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index fdaec7daff1d..85dabb86be6f 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -105,10 +105,8 @@ EXPORT_SYMBOL(nf_register_hooks);
void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n)
{
- unsigned int i;
-
- for (i = 0; i < n; i++)
- nf_unregister_hook(&reg[i]);
+ while (n-- > 0)
+ nf_unregister_hook(&reg[n]);
}
EXPORT_SYMBOL(nf_unregister_hooks);
diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig
index 46a77d5c3887..a22dac227055 100644
--- a/net/netfilter/ipvs/Kconfig
+++ b/net/netfilter/ipvs/Kconfig
@@ -3,7 +3,7 @@
#
menuconfig IP_VS
tristate "IP virtual server support"
- depends on NET && INET && NETFILTER && NF_CONNTRACK
+ depends on NET && INET && NETFILTER
---help---
IP Virtual Server support will let you build a high-performance
virtual server based on cluster of two or more real servers. This
@@ -235,7 +235,8 @@ comment 'IPVS application helper'
config IP_VS_FTP
tristate "FTP protocol helper"
- depends on IP_VS_PROTO_TCP && NF_NAT
+ depends on IP_VS_PROTO_TCP && NF_CONNTRACK && NF_NAT
+ select IP_VS_NFCT
---help---
FTP is a protocol that transfers IP address and/or port number in
the payload. In the virtual server via Network Address Translation,
@@ -247,4 +248,19 @@ config IP_VS_FTP
If you want to compile it in kernel, say Y. To compile it as a
module, choose M here. If unsure, say N.
+config IP_VS_NFCT
+ bool "Netfilter connection tracking"
+ depends on NF_CONNTRACK
+ ---help---
+ The Netfilter connection tracking support allows the IPVS
+ connection state to be exported to the Netfilter framework
+ for filtering purposes.
+
+config IP_VS_PE_SIP
+ tristate "SIP persistence engine"
+ depends on IP_VS_PROTO_UDP
+ depends on NF_CONNTRACK_SIP
+ ---help---
+ Allow persistence based on the SIP Call-ID
+
endif # IP_VS
diff --git a/net/netfilter/ipvs/Makefile b/net/netfilter/ipvs/Makefile
index e3baefd7066e..34ee602ddb66 100644
--- a/net/netfilter/ipvs/Makefile
+++ b/net/netfilter/ipvs/Makefile
@@ -9,10 +9,13 @@ ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_UDP) += ip_vs_proto_udp.o
ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_AH_ESP) += ip_vs_proto_ah_esp.o
ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_SCTP) += ip_vs_proto_sctp.o
+ip_vs-extra_objs-y :=
+ip_vs-extra_objs-$(CONFIG_IP_VS_NFCT) += ip_vs_nfct.o
+
ip_vs-objs := ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \
ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o \
- ip_vs_est.o ip_vs_proto.o \
- $(ip_vs_proto-objs-y)
+ ip_vs_est.o ip_vs_proto.o ip_vs_pe.o \
+ $(ip_vs_proto-objs-y) $(ip_vs-extra_objs-y)
# IPVS core
@@ -32,3 +35,6 @@ obj-$(CONFIG_IP_VS_NQ) += ip_vs_nq.o
# IPVS application helpers
obj-$(CONFIG_IP_VS_FTP) += ip_vs_ftp.o
+
+# IPVS connection template retrievers
+obj-$(CONFIG_IP_VS_PE_SIP) += ip_vs_pe_sip.o
diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c
index e76f87f4aca8..a475edee0912 100644
--- a/net/netfilter/ipvs/ip_vs_app.c
+++ b/net/netfilter/ipvs/ip_vs_app.c
@@ -103,8 +103,8 @@ ip_vs_app_inc_new(struct ip_vs_app *app, __u16 proto, __u16 port)
goto out;
list_add(&inc->a_list, &app->incs_list);
- IP_VS_DBG(9, "%s application %s:%u registered\n",
- pp->name, inc->name, inc->port);
+ IP_VS_DBG(9, "%s App %s:%u registered\n",
+ pp->name, inc->name, ntohs(inc->port));
return 0;
@@ -130,7 +130,7 @@ ip_vs_app_inc_release(struct ip_vs_app *inc)
pp->unregister_app(inc);
IP_VS_DBG(9, "%s App %s:%u unregistered\n",
- pp->name, inc->name, inc->port);
+ pp->name, inc->name, ntohs(inc->port));
list_del(&inc->a_list);
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index b71c69a2db13..e9adecdc8ca4 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -148,6 +148,42 @@ static unsigned int ip_vs_conn_hashkey(int af, unsigned proto,
& ip_vs_conn_tab_mask;
}
+static unsigned int ip_vs_conn_hashkey_param(const struct ip_vs_conn_param *p,
+ bool inverse)
+{
+ const union nf_inet_addr *addr;
+ __be16 port;
+
+ if (p->pe_data && p->pe->hashkey_raw)
+ return p->pe->hashkey_raw(p, ip_vs_conn_rnd, inverse) &
+ ip_vs_conn_tab_mask;
+
+ if (likely(!inverse)) {
+ addr = p->caddr;
+ port = p->cport;
+ } else {
+ addr = p->vaddr;
+ port = p->vport;
+ }
+
+ return ip_vs_conn_hashkey(p->af, p->protocol, addr, port);
+}
+
+static unsigned int ip_vs_conn_hashkey_conn(const struct ip_vs_conn *cp)
+{
+ struct ip_vs_conn_param p;
+
+ ip_vs_conn_fill_param(cp->af, cp->protocol, &cp->caddr, cp->cport,
+ NULL, 0, &p);
+
+ if (cp->dest && cp->dest->svc->pe) {
+ p.pe = cp->dest->svc->pe;
+ p.pe_data = cp->pe_data;
+ p.pe_data_len = cp->pe_data_len;
+ }
+
+ return ip_vs_conn_hashkey_param(&p, false);
+}
/*
* Hashes ip_vs_conn in ip_vs_conn_tab by proto,addr,port.
@@ -162,7 +198,7 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
return 0;
/* Hash by protocol, client address and port */
- hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
+ hash = ip_vs_conn_hashkey_conn(cp);
ct_write_lock(hash);
spin_lock(&cp->lock);
@@ -195,7 +231,7 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
int ret;
/* unhash it and decrease its reference counter */
- hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
+ hash = ip_vs_conn_hashkey_conn(cp);
ct_write_lock(hash);
spin_lock(&cp->lock);
@@ -218,27 +254,26 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
/*
* Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
* Called for pkts coming from OUTside-to-INside.
- * s_addr, s_port: pkt source address (foreign host)
- * d_addr, d_port: pkt dest address (load balancer)
+ * p->caddr, p->cport: pkt source address (foreign host)
+ * p->vaddr, p->vport: pkt dest address (load balancer)
*/
-static inline struct ip_vs_conn *__ip_vs_conn_in_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port)
+static inline struct ip_vs_conn *
+__ip_vs_conn_in_get(const struct ip_vs_conn_param *p)
{
unsigned hash;
struct ip_vs_conn *cp;
- hash = ip_vs_conn_hashkey(af, protocol, s_addr, s_port);
+ hash = ip_vs_conn_hashkey_param(p, false);
ct_read_lock(hash);
list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
- if (cp->af == af &&
- ip_vs_addr_equal(af, s_addr, &cp->caddr) &&
- ip_vs_addr_equal(af, d_addr, &cp->vaddr) &&
- s_port == cp->cport && d_port == cp->vport &&
- ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
- protocol == cp->protocol) {
+ if (cp->af == p->af &&
+ ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) &&
+ ip_vs_addr_equal(p->af, p->vaddr, &cp->vaddr) &&
+ p->cport == cp->cport && p->vport == cp->vport &&
+ ((!p->cport) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
+ p->protocol == cp->protocol) {
/* HIT */
atomic_inc(&cp->refcnt);
ct_read_unlock(hash);
@@ -251,99 +286,111 @@ static inline struct ip_vs_conn *__ip_vs_conn_in_get
return NULL;
}
-struct ip_vs_conn *ip_vs_conn_in_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port)
+struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p)
{
struct ip_vs_conn *cp;
- cp = __ip_vs_conn_in_get(af, protocol, s_addr, s_port, d_addr, d_port);
- if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt))
- cp = __ip_vs_conn_in_get(af, protocol, s_addr, 0, d_addr,
- d_port);
+ cp = __ip_vs_conn_in_get(p);
+ if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt)) {
+ struct ip_vs_conn_param cport_zero_p = *p;
+ cport_zero_p.cport = 0;
+ cp = __ip_vs_conn_in_get(&cport_zero_p);
+ }
IP_VS_DBG_BUF(9, "lookup/in %s %s:%d->%s:%d %s\n",
- ip_vs_proto_name(protocol),
- IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
- IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
+ ip_vs_proto_name(p->protocol),
+ IP_VS_DBG_ADDR(p->af, p->caddr), ntohs(p->cport),
+ IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
cp ? "hit" : "not hit");
return cp;
}
+static int
+ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb,
+ const struct ip_vs_iphdr *iph,
+ unsigned int proto_off, int inverse,
+ struct ip_vs_conn_param *p)
+{
+ __be16 _ports[2], *pptr;
+
+ pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
+ if (pptr == NULL)
+ return 1;
+
+ if (likely(!inverse))
+ ip_vs_conn_fill_param(af, iph->protocol, &iph->saddr, pptr[0],
+ &iph->daddr, pptr[1], p);
+ else
+ ip_vs_conn_fill_param(af, iph->protocol, &iph->daddr, pptr[1],
+ &iph->saddr, pptr[0], p);
+ return 0;
+}
+
struct ip_vs_conn *
ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,
struct ip_vs_protocol *pp,
const struct ip_vs_iphdr *iph,
unsigned int proto_off, int inverse)
{
- __be16 _ports[2], *pptr;
+ struct ip_vs_conn_param p;
- pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
- if (pptr == NULL)
+ if (ip_vs_conn_fill_param_proto(af, skb, iph, proto_off, inverse, &p))
return NULL;
- if (likely(!inverse))
- return ip_vs_conn_in_get(af, iph->protocol,
- &iph->saddr, pptr[0],
- &iph->daddr, pptr[1]);
- else
- return ip_vs_conn_in_get(af, iph->protocol,
- &iph->daddr, pptr[1],
- &iph->saddr, pptr[0]);
+ return ip_vs_conn_in_get(&p);
}
EXPORT_SYMBOL_GPL(ip_vs_conn_in_get_proto);
/* Get reference to connection template */
-struct ip_vs_conn *ip_vs_ct_in_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port)
+struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p)
{
unsigned hash;
struct ip_vs_conn *cp;
- hash = ip_vs_conn_hashkey(af, protocol, s_addr, s_port);
+ hash = ip_vs_conn_hashkey_param(p, false);
ct_read_lock(hash);
list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
- if (cp->af == af &&
- ip_vs_addr_equal(af, s_addr, &cp->caddr) &&
+ if (p->pe_data && p->pe->ct_match) {
+ if (p->pe->ct_match(p, cp))
+ goto out;
+ continue;
+ }
+
+ if (cp->af == p->af &&
+ ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) &&
/* protocol should only be IPPROTO_IP if
- * d_addr is a fwmark */
- ip_vs_addr_equal(protocol == IPPROTO_IP ? AF_UNSPEC : af,
- d_addr, &cp->vaddr) &&
- s_port == cp->cport && d_port == cp->vport &&
+ * p->vaddr is a fwmark */
+ ip_vs_addr_equal(p->protocol == IPPROTO_IP ? AF_UNSPEC :
+ p->af, p->vaddr, &cp->vaddr) &&
+ p->cport == cp->cport && p->vport == cp->vport &&
cp->flags & IP_VS_CONN_F_TEMPLATE &&
- protocol == cp->protocol) {
- /* HIT */
- atomic_inc(&cp->refcnt);
+ p->protocol == cp->protocol)
goto out;
- }
}
cp = NULL;
out:
+ if (cp)
+ atomic_inc(&cp->refcnt);
ct_read_unlock(hash);
IP_VS_DBG_BUF(9, "template lookup/in %s %s:%d->%s:%d %s\n",
- ip_vs_proto_name(protocol),
- IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
- IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
+ ip_vs_proto_name(p->protocol),
+ IP_VS_DBG_ADDR(p->af, p->caddr), ntohs(p->cport),
+ IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
cp ? "hit" : "not hit");
return cp;
}
-/*
- * Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
- * Called for pkts coming from inside-to-OUTside.
- * s_addr, s_port: pkt source address (inside host)
- * d_addr, d_port: pkt dest address (foreign host)
- */
-struct ip_vs_conn *ip_vs_conn_out_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port)
+/* Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
+ * Called for pkts coming from inside-to-OUTside.
+ * p->caddr, p->cport: pkt source address (inside host)
+ * p->vaddr, p->vport: pkt dest address (foreign host) */
+struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p)
{
unsigned hash;
struct ip_vs_conn *cp, *ret=NULL;
@@ -351,16 +398,16 @@ struct ip_vs_conn *ip_vs_conn_out_get
/*
* Check for "full" addressed entries
*/
- hash = ip_vs_conn_hashkey(af, protocol, d_addr, d_port);
+ hash = ip_vs_conn_hashkey_param(p, true);
ct_read_lock(hash);
list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
- if (cp->af == af &&
- ip_vs_addr_equal(af, d_addr, &cp->caddr) &&
- ip_vs_addr_equal(af, s_addr, &cp->daddr) &&
- d_port == cp->cport && s_port == cp->dport &&
- protocol == cp->protocol) {
+ if (cp->af == p->af &&
+ ip_vs_addr_equal(p->af, p->vaddr, &cp->caddr) &&
+ ip_vs_addr_equal(p->af, p->caddr, &cp->daddr) &&
+ p->vport == cp->cport && p->cport == cp->dport &&
+ p->protocol == cp->protocol) {
/* HIT */
atomic_inc(&cp->refcnt);
ret = cp;
@@ -371,9 +418,9 @@ struct ip_vs_conn *ip_vs_conn_out_get
ct_read_unlock(hash);
IP_VS_DBG_BUF(9, "lookup/out %s %s:%d->%s:%d %s\n",
- ip_vs_proto_name(protocol),
- IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
- IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
+ ip_vs_proto_name(p->protocol),
+ IP_VS_DBG_ADDR(p->af, p->caddr), ntohs(p->cport),
+ IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
ret ? "hit" : "not hit");
return ret;
@@ -385,20 +432,12 @@ ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb,
const struct ip_vs_iphdr *iph,
unsigned int proto_off, int inverse)
{
- __be16 _ports[2], *pptr;
+ struct ip_vs_conn_param p;
- pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
- if (pptr == NULL)
+ if (ip_vs_conn_fill_param_proto(af, skb, iph, proto_off, inverse, &p))
return NULL;
- if (likely(!inverse))
- return ip_vs_conn_out_get(af, iph->protocol,
- &iph->saddr, pptr[0],
- &iph->daddr, pptr[1]);
- else
- return ip_vs_conn_out_get(af, iph->protocol,
- &iph->daddr, pptr[1],
- &iph->saddr, pptr[0]);
+ return ip_vs_conn_out_get(&p);
}
EXPORT_SYMBOL_GPL(ip_vs_conn_out_get_proto);
@@ -505,6 +544,8 @@ static inline int ip_vs_dest_totalconns(struct ip_vs_dest *dest)
static inline void
ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
{
+ unsigned int conn_flags;
+
/* if dest is NULL, then return directly */
if (!dest)
return;
@@ -512,16 +553,20 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
/* Increase the refcnt counter of the dest */
atomic_inc(&dest->refcnt);
+ conn_flags = atomic_read(&dest->conn_flags);
+ if (cp->protocol != IPPROTO_UDP)
+ conn_flags &= ~IP_VS_CONN_F_ONE_PACKET;
/* Bind with the destination and its corresponding transmitter */
- if ((cp->flags & IP_VS_CONN_F_SYNC) &&
- (!(cp->flags & IP_VS_CONN_F_TEMPLATE)))
+ if (cp->flags & IP_VS_CONN_F_SYNC) {
/* if the connection is not template and is created
* by sync, preserve the activity flag.
*/
- cp->flags |= atomic_read(&dest->conn_flags) &
- (~IP_VS_CONN_F_INACTIVE);
- else
- cp->flags |= atomic_read(&dest->conn_flags);
+ if (!(cp->flags & IP_VS_CONN_F_TEMPLATE))
+ conn_flags &= ~IP_VS_CONN_F_INACTIVE;
+ /* connections inherit forwarding method from dest */
+ cp->flags &= ~IP_VS_CONN_F_FWD_MASK;
+ }
+ cp->flags |= conn_flags;
cp->dest = dest;
IP_VS_DBG_BUF(7, "Bind-dest %s c:%s:%d v:%s:%d "
@@ -717,6 +762,10 @@ static void ip_vs_conn_expire(unsigned long data)
if (cp->control)
ip_vs_control_del(cp);
+ if (cp->flags & IP_VS_CONN_F_NFCT)
+ ip_vs_conn_drop_conntrack(cp);
+
+ kfree(cp->pe_data);
if (unlikely(cp->app != NULL))
ip_vs_unbind_app(cp);
ip_vs_unbind_dest(cp);
@@ -751,13 +800,12 @@ void ip_vs_conn_expire_now(struct ip_vs_conn *cp)
* Create a new connection entry and hash it into the ip_vs_conn_tab
*/
struct ip_vs_conn *
-ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
- const union nf_inet_addr *vaddr, __be16 vport,
+ip_vs_conn_new(const struct ip_vs_conn_param *p,
const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
struct ip_vs_dest *dest)
{
struct ip_vs_conn *cp;
- struct ip_vs_protocol *pp = ip_vs_proto_get(proto);
+ struct ip_vs_protocol *pp = ip_vs_proto_get(p->protocol);
cp = kmem_cache_zalloc(ip_vs_conn_cachep, GFP_ATOMIC);
if (cp == NULL) {
@@ -767,17 +815,21 @@ ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
INIT_LIST_HEAD(&cp->c_list);
setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp);
- cp->af = af;
- cp->protocol = proto;
- ip_vs_addr_copy(af, &cp->caddr, caddr);
- cp->cport = cport;
- ip_vs_addr_copy(af, &cp->vaddr, vaddr);
- cp->vport = vport;
+ cp->af = p->af;
+ cp->protocol = p->protocol;
+ ip_vs_addr_copy(p->af, &cp->caddr, p->caddr);
+ cp->cport = p->cport;
+ ip_vs_addr_copy(p->af, &cp->vaddr, p->vaddr);
+ cp->vport = p->vport;
/* proto should only be IPPROTO_IP if d_addr is a fwmark */
- ip_vs_addr_copy(proto == IPPROTO_IP ? AF_UNSPEC : af,
+ ip_vs_addr_copy(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af,
&cp->daddr, daddr);
cp->dport = dport;
cp->flags = flags;
+ if (flags & IP_VS_CONN_F_TEMPLATE && p->pe_data) {
+ cp->pe_data = p->pe_data;
+ cp->pe_data_len = p->pe_data_len;
+ }
spin_lock_init(&cp->lock);
/*
@@ -803,7 +855,7 @@ ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
/* Bind its packet transmitter */
#ifdef CONFIG_IP_VS_IPV6
- if (af == AF_INET6)
+ if (p->af == AF_INET6)
ip_vs_bind_xmit_v6(cp);
else
#endif
@@ -812,13 +864,22 @@ ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
if (unlikely(pp && atomic_read(&pp->appcnt)))
ip_vs_bind_app(cp, pp);
+ /*
+ * Allow conntrack to be preserved. By default, conntrack
+ * is created and destroyed for every packet.
+ * Sometimes keeping conntrack can be useful for
+ * IP_VS_CONN_F_ONE_PACKET too.
+ */
+
+ if (ip_vs_conntrack_enabled())
+ cp->flags |= IP_VS_CONN_F_NFCT;
+
/* Hash it in the ip_vs_conn_tab finally */
ip_vs_conn_hash(cp);
return cp;
}
-
/*
* /proc/net/ip_vs_conn entries
*/
@@ -834,7 +895,7 @@ static void *ip_vs_conn_array(struct seq_file *seq, loff_t pos)
list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
if (pos-- == 0) {
seq->private = &ip_vs_conn_tab[idx];
- return cp;
+ return cp;
}
}
ct_read_unlock_bh(idx);
@@ -891,30 +952,45 @@ static int ip_vs_conn_seq_show(struct seq_file *seq, void *v)
if (v == SEQ_START_TOKEN)
seq_puts(seq,
- "Pro FromIP FPrt ToIP TPrt DestIP DPrt State Expires\n");
+ "Pro FromIP FPrt ToIP TPrt DestIP DPrt State Expires PEName PEData\n");
else {
const struct ip_vs_conn *cp = v;
+ char pe_data[IP_VS_PENAME_MAXLEN + IP_VS_PEDATA_MAXLEN + 3];
+ size_t len = 0;
+
+ if (cp->dest && cp->pe_data &&
+ cp->dest->svc->pe->show_pe_data) {
+ pe_data[0] = ' ';
+ len = strlen(cp->dest->svc->pe->name);
+ memcpy(pe_data + 1, cp->dest->svc->pe->name, len);
+ pe_data[len + 1] = ' ';
+ len += 2;
+ len += cp->dest->svc->pe->show_pe_data(cp,
+ pe_data + len);
+ }
+ pe_data[len] = '\0';
#ifdef CONFIG_IP_VS_IPV6
if (cp->af == AF_INET6)
- seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X %pI6 %04X %-11s %7lu\n",
+ seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X "
+ "%pI6 %04X %-11s %7lu%s\n",
ip_vs_proto_name(cp->protocol),
&cp->caddr.in6, ntohs(cp->cport),
&cp->vaddr.in6, ntohs(cp->vport),
&cp->daddr.in6, ntohs(cp->dport),
ip_vs_state_name(cp->protocol, cp->state),
- (cp->timer.expires-jiffies)/HZ);
+ (cp->timer.expires-jiffies)/HZ, pe_data);
else
#endif
seq_printf(seq,
"%-3s %08X %04X %08X %04X"
- " %08X %04X %-11s %7lu\n",
+ " %08X %04X %-11s %7lu%s\n",
ip_vs_proto_name(cp->protocol),
ntohl(cp->caddr.ip), ntohs(cp->cport),
ntohl(cp->vaddr.ip), ntohs(cp->vport),
ntohl(cp->daddr.ip), ntohs(cp->dport),
ip_vs_state_name(cp->protocol, cp->state),
- (cp->timer.expires-jiffies)/HZ);
+ (cp->timer.expires-jiffies)/HZ, pe_data);
}
return 0;
}
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 4c2f89df5cce..b4e51e9c5a04 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -40,6 +40,7 @@
#include <net/udp.h>
#include <net/icmp.h> /* for icmp_send */
#include <net/route.h>
+#include <net/ip6_checksum.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
@@ -47,6 +48,7 @@
#ifdef CONFIG_IP_VS_IPV6
#include <net/ipv6.h>
#include <linux/netfilter_ipv6.h>
+#include <net/ip6_route.h>
#endif
#include <net/ip_vs.h>
@@ -175,6 +177,18 @@ ip_vs_set_state(struct ip_vs_conn *cp, int direction,
return pp->state_transition(cp, direction, skb, pp);
}
+static inline void
+ip_vs_conn_fill_param_persist(const struct ip_vs_service *svc,
+ struct sk_buff *skb, int protocol,
+ const union nf_inet_addr *caddr, __be16 cport,
+ const union nf_inet_addr *vaddr, __be16 vport,
+ struct ip_vs_conn_param *p)
+{
+ ip_vs_conn_fill_param(svc->af, protocol, caddr, cport, vaddr, vport, p);
+ p->pe = svc->pe;
+ if (p->pe && p->pe->fill_param)
+ p->pe->fill_param(p, skb);
+}
/*
* IPVS persistent scheduling function
@@ -185,15 +199,16 @@ ip_vs_set_state(struct ip_vs_conn *cp, int direction,
*/
static struct ip_vs_conn *
ip_vs_sched_persist(struct ip_vs_service *svc,
- const struct sk_buff *skb,
+ struct sk_buff *skb,
__be16 ports[2])
{
struct ip_vs_conn *cp = NULL;
struct ip_vs_iphdr iph;
struct ip_vs_dest *dest;
struct ip_vs_conn *ct;
- __be16 dport; /* destination port to forward */
- __be16 flags;
+ __be16 dport = 0; /* destination port to forward */
+ unsigned int flags;
+ struct ip_vs_conn_param param;
union nf_inet_addr snet; /* source network of the client,
after masking */
@@ -226,120 +241,75 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
* service, and a template like <caddr, 0, vaddr, vport, daddr, dport>
* is created for other persistent services.
*/
- if (ports[1] == svc->port) {
- /* Check if a template already exists */
- if (svc->port != FTPPORT)
- ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
- &iph.daddr, ports[1]);
- else
- ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
- &iph.daddr, 0);
-
- if (!ct || !ip_vs_check_template(ct)) {
- /*
- * No template found or the dest of the connection
- * template is not available.
- */
- dest = svc->scheduler->schedule(svc, skb);
- if (dest == NULL) {
- IP_VS_DBG(1, "p-schedule: no dest found.\n");
- return NULL;
- }
-
- /*
- * Create a template like <protocol,caddr,0,
- * vaddr,vport,daddr,dport> for non-ftp service,
- * and <protocol,caddr,0,vaddr,0,daddr,0>
- * for ftp service.
+ {
+ int protocol = iph.protocol;
+ const union nf_inet_addr *vaddr = &iph.daddr;
+ const union nf_inet_addr fwmark = { .ip = htonl(svc->fwmark) };
+ __be16 vport = 0;
+
+ if (ports[1] == svc->port) {
+ /* non-FTP template:
+ * <protocol, caddr, 0, vaddr, vport, daddr, dport>
+ * FTP template:
+ * <protocol, caddr, 0, vaddr, 0, daddr, 0>
*/
if (svc->port != FTPPORT)
- ct = ip_vs_conn_new(svc->af, iph.protocol,
- &snet, 0,
- &iph.daddr,
- ports[1],
- &dest->addr, dest->port,
- IP_VS_CONN_F_TEMPLATE,
- dest);
- else
- ct = ip_vs_conn_new(svc->af, iph.protocol,
- &snet, 0,
- &iph.daddr, 0,
- &dest->addr, 0,
- IP_VS_CONN_F_TEMPLATE,
- dest);
- if (ct == NULL)
- return NULL;
-
- ct->timeout = svc->timeout;
+ vport = ports[1];
} else {
- /* set destination with the found template */
- dest = ct->dest;
- }
- dport = dest->port;
- } else {
- /*
- * Note: persistent fwmark-based services and persistent
- * port zero service are handled here.
- * fwmark template: <IPPROTO_IP,caddr,0,fwmark,0,daddr,0>
- * port zero template: <protocol,caddr,0,vaddr,0,daddr,0>
- */
- if (svc->fwmark) {
- union nf_inet_addr fwmark = {
- .ip = htonl(svc->fwmark)
- };
-
- ct = ip_vs_ct_in_get(svc->af, IPPROTO_IP, &snet, 0,
- &fwmark, 0);
- } else
- ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
- &iph.daddr, 0);
-
- if (!ct || !ip_vs_check_template(ct)) {
- /*
- * If it is not persistent port zero, return NULL,
- * otherwise create a connection template.
+ /* Note: persistent fwmark-based services and
+ * persistent port zero service are handled here.
+ * fwmark template:
+ * <IPPROTO_IP,caddr,0,fwmark,0,daddr,0>
+ * port zero template:
+ * <protocol,caddr,0,vaddr,0,daddr,0>
*/
- if (svc->port)
- return NULL;
-
- dest = svc->scheduler->schedule(svc, skb);
- if (dest == NULL) {
- IP_VS_DBG(1, "p-schedule: no dest found.\n");
- return NULL;
+ if (svc->fwmark) {
+ protocol = IPPROTO_IP;
+ vaddr = &fwmark;
}
+ }
+ ip_vs_conn_fill_param_persist(svc, skb, protocol, &snet, 0,
+ vaddr, vport, &param);
+ }
- /*
- * Create a template according to the service
- */
- if (svc->fwmark) {
- union nf_inet_addr fwmark = {
- .ip = htonl(svc->fwmark)
- };
-
- ct = ip_vs_conn_new(svc->af, IPPROTO_IP,
- &snet, 0,
- &fwmark, 0,
- &dest->addr, 0,
- IP_VS_CONN_F_TEMPLATE,
- dest);
- } else
- ct = ip_vs_conn_new(svc->af, iph.protocol,
- &snet, 0,
- &iph.daddr, 0,
- &dest->addr, 0,
- IP_VS_CONN_F_TEMPLATE,
- dest);
- if (ct == NULL)
- return NULL;
-
- ct->timeout = svc->timeout;
- } else {
- /* set destination with the found template */
- dest = ct->dest;
+ /* Check if a template already exists */
+ ct = ip_vs_ct_in_get(&param);
+ if (!ct || !ip_vs_check_template(ct)) {
+ /* No template found or the dest of the connection
+ * template is not available.
+ */
+ dest = svc->scheduler->schedule(svc, skb);
+ if (!dest) {
+ IP_VS_DBG(1, "p-schedule: no dest found.\n");
+ kfree(param.pe_data);
+ return NULL;
}
- dport = ports[1];
+
+ if (ports[1] == svc->port && svc->port != FTPPORT)
+ dport = dest->port;
+
+ /* Create a template
+ * This adds param.pe_data to the template,
+ * and thus param.pe_data will be destroyed
+ * when the template expires */
+ ct = ip_vs_conn_new(&param, &dest->addr, dport,
+ IP_VS_CONN_F_TEMPLATE, dest);
+ if (ct == NULL) {
+ kfree(param.pe_data);
+ return NULL;
+ }
+
+ ct->timeout = svc->timeout;
+ } else {
+ /* set destination with the found template */
+ dest = ct->dest;
+ kfree(param.pe_data);
}
+ dport = ports[1];
+ if (dport == svc->port && dest->port)
+ dport = dest->port;
+
flags = (svc->flags & IP_VS_SVC_F_ONEPACKET
&& iph.protocol == IPPROTO_UDP)?
IP_VS_CONN_F_ONE_PACKET : 0;
@@ -347,12 +317,9 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
/*
* Create a new connection according to the template
*/
- cp = ip_vs_conn_new(svc->af, iph.protocol,
- &iph.saddr, ports[0],
- &iph.daddr, ports[1],
- &dest->addr, dport,
- flags,
- dest);
+ ip_vs_conn_fill_param(svc->af, iph.protocol, &iph.saddr, ports[0],
+ &iph.daddr, ports[1], &param);
+ cp = ip_vs_conn_new(&param, &dest->addr, dport, flags, dest);
if (cp == NULL) {
ip_vs_conn_put(ct);
return NULL;
@@ -376,23 +343,53 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
* Protocols supported: TCP, UDP
*/
struct ip_vs_conn *
-ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
+ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
+ struct ip_vs_protocol *pp, int *ignored)
{
struct ip_vs_conn *cp = NULL;
struct ip_vs_iphdr iph;
struct ip_vs_dest *dest;
- __be16 _ports[2], *pptr, flags;
+ __be16 _ports[2], *pptr;
+ unsigned int flags;
+ *ignored = 1;
ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
if (pptr == NULL)
return NULL;
/*
+ * FTPDATA needs this check when using local real server.
+ * Never schedule Active FTPDATA connections from real server.
+ * For LVS-NAT they must be already created. For other methods
+ * with persistence the connection is created on SYN+ACK.
+ */
+ if (pptr[0] == FTPDATA) {
+ IP_VS_DBG_PKT(12, svc->af, pp, skb, 0,
+ "Not scheduling FTPDATA");
+ return NULL;
+ }
+
+ /*
+ * Do not schedule replies from local real server. It is risky
+ * for fwmark services but mostly for persistent services.
+ */
+ if ((!skb->dev || skb->dev->flags & IFF_LOOPBACK) &&
+ (svc->flags & IP_VS_SVC_F_PERSISTENT || svc->fwmark) &&
+ (cp = pp->conn_in_get(svc->af, skb, pp, &iph, iph.len, 1))) {
+ IP_VS_DBG_PKT(12, svc->af, pp, skb, 0,
+ "Not scheduling reply for existing connection");
+ __ip_vs_conn_put(cp);
+ return NULL;
+ }
+
+ /*
* Persistent service
*/
- if (svc->flags & IP_VS_SVC_F_PERSISTENT)
+ if (svc->flags & IP_VS_SVC_F_PERSISTENT) {
+ *ignored = 0;
return ip_vs_sched_persist(svc, skb, pptr);
+ }
/*
* Non-persistent service
@@ -405,6 +402,8 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
return NULL;
}
+ *ignored = 0;
+
dest = svc->scheduler->schedule(svc, skb);
if (dest == NULL) {
IP_VS_DBG(1, "Schedule: no dest found.\n");
@@ -418,14 +417,16 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
/*
* Create a connection entry.
*/
- cp = ip_vs_conn_new(svc->af, iph.protocol,
- &iph.saddr, pptr[0],
- &iph.daddr, pptr[1],
- &dest->addr, dest->port ? dest->port : pptr[1],
- flags,
- dest);
- if (cp == NULL)
- return NULL;
+ {
+ struct ip_vs_conn_param p;
+ ip_vs_conn_fill_param(svc->af, iph.protocol, &iph.saddr,
+ pptr[0], &iph.daddr, pptr[1], &p);
+ cp = ip_vs_conn_new(&p, &dest->addr,
+ dest->port ? dest->port : pptr[1],
+ flags, dest);
+ if (!cp)
+ return NULL;
+ }
IP_VS_DBG_BUF(6, "Schedule fwd:%c c:%s:%u v:%s:%u "
"d:%s:%u conn->flags:%X conn->refcnt:%d\n",
@@ -472,23 +473,26 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
if (sysctl_ip_vs_cache_bypass && svc->fwmark && unicast) {
int ret, cs;
struct ip_vs_conn *cp;
- __u16 flags = (svc->flags & IP_VS_SVC_F_ONEPACKET &&
- iph.protocol == IPPROTO_UDP)?
- IP_VS_CONN_F_ONE_PACKET : 0;
+ unsigned int flags = (svc->flags & IP_VS_SVC_F_ONEPACKET &&
+ iph.protocol == IPPROTO_UDP)?
+ IP_VS_CONN_F_ONE_PACKET : 0;
union nf_inet_addr daddr = { .all = { 0, 0, 0, 0 } };
ip_vs_service_put(svc);
/* create a new connection entry */
IP_VS_DBG(6, "%s(): create a cache_bypass entry\n", __func__);
- cp = ip_vs_conn_new(svc->af, iph.protocol,
- &iph.saddr, pptr[0],
- &iph.daddr, pptr[1],
- &daddr, 0,
- IP_VS_CONN_F_BYPASS | flags,
- NULL);
- if (cp == NULL)
- return NF_DROP;
+ {
+ struct ip_vs_conn_param p;
+ ip_vs_conn_fill_param(svc->af, iph.protocol,
+ &iph.saddr, pptr[0],
+ &iph.daddr, pptr[1], &p);
+ cp = ip_vs_conn_new(&p, &daddr, 0,
+ IP_VS_CONN_F_BYPASS | flags,
+ NULL);
+ if (!cp)
+ return NF_DROP;
+ }
/* statistics */
ip_vs_in_stats(cp, skb);
@@ -526,9 +530,14 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
* ICMP_PORT_UNREACH is sent here no matter it is TCP/UDP. --WZ
*/
#ifdef CONFIG_IP_VS_IPV6
- if (svc->af == AF_INET6)
+ if (svc->af == AF_INET6) {
+ if (!skb->dev) {
+ struct net *net = dev_net(skb_dst(skb)->dev);
+
+ skb->dev = net->loopback_dev;
+ }
icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
- else
+ } else
#endif
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
@@ -540,6 +549,15 @@ __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0));
}
+static inline enum ip_defrag_users ip_vs_defrag_user(unsigned int hooknum)
+{
+ if (NF_INET_LOCAL_IN == hooknum)
+ return IP_DEFRAG_VS_IN;
+ if (NF_INET_FORWARD == hooknum)
+ return IP_DEFRAG_VS_FWD;
+ return IP_DEFRAG_VS_OUT;
+}
+
static inline int ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user)
{
int err = ip_defrag(skb, user);
@@ -600,10 +618,10 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
skb->ip_summed = CHECKSUM_UNNECESSARY;
if (inout)
- IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
+ IP_VS_DBG_PKT(11, AF_INET, pp, skb, (void *)ciph - (void *)iph,
"Forwarding altered outgoing ICMP");
else
- IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
+ IP_VS_DBG_PKT(11, AF_INET, pp, skb, (void *)ciph - (void *)iph,
"Forwarding altered incoming ICMP");
}
@@ -637,17 +655,21 @@ void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
}
/* And finally the ICMP checksum */
- icmph->icmp6_cksum = 0;
- /* TODO IPv6: is this correct for ICMPv6? */
- ip_vs_checksum_complete(skb, icmp_offset);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ icmph->icmp6_cksum = ~csum_ipv6_magic(&iph->saddr, &iph->daddr,
+ skb->len - icmp_offset,
+ IPPROTO_ICMPV6, 0);
+ skb->csum_start = skb_network_header(skb) - skb->head + icmp_offset;
+ skb->csum_offset = offsetof(struct icmp6hdr, icmp6_cksum);
+ skb->ip_summed = CHECKSUM_PARTIAL;
if (inout)
- IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
- "Forwarding altered outgoing ICMPv6");
+ IP_VS_DBG_PKT(11, AF_INET6, pp, skb,
+ (void *)ciph - (void *)iph,
+ "Forwarding altered outgoing ICMPv6");
else
- IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
- "Forwarding altered incoming ICMPv6");
+ IP_VS_DBG_PKT(11, AF_INET6, pp, skb,
+ (void *)ciph - (void *)iph,
+ "Forwarding altered incoming ICMPv6");
}
#endif
@@ -688,10 +710,25 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
#endif
ip_vs_nat_icmp(skb, pp, cp, 1);
+#ifdef CONFIG_IP_VS_IPV6
+ if (af == AF_INET6) {
+ if (sysctl_ip_vs_snat_reroute && ip6_route_me_harder(skb) != 0)
+ goto out;
+ } else
+#endif
+ if ((sysctl_ip_vs_snat_reroute ||
+ skb_rtable(skb)->rt_flags & RTCF_LOCAL) &&
+ ip_route_me_harder(skb, RTN_LOCAL) != 0)
+ goto out;
+
/* do the statistics and put it back */
ip_vs_out_stats(cp, skb);
skb->ipvs_property = 1;
+ if (!(cp->flags & IP_VS_CONN_F_NFCT))
+ ip_vs_notrack(skb);
+ else
+ ip_vs_update_conntrack(skb, cp, 0);
verdict = NF_ACCEPT;
out:
@@ -705,7 +742,8 @@ out:
* Find any that might be relevant, check against existing connections.
* Currently handles error types - unreachable, quench, ttl exceeded.
*/
-static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
+static int ip_vs_out_icmp(struct sk_buff *skb, int *related,
+ unsigned int hooknum)
{
struct iphdr *iph;
struct icmphdr _icmph, *ic;
@@ -720,7 +758,7 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
/* reassemble IP fragments */
if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
- if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
+ if (ip_vs_gather_frags(skb, ip_vs_defrag_user(hooknum)))
return NF_STOLEN;
}
@@ -763,7 +801,8 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
pp->dont_defrag))
return NF_ACCEPT;
- IP_VS_DBG_PKT(11, pp, skb, offset, "Checking outgoing ICMP for");
+ IP_VS_DBG_PKT(11, AF_INET, pp, skb, offset,
+ "Checking outgoing ICMP for");
offset += cih->ihl * 4;
@@ -779,7 +818,8 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
}
#ifdef CONFIG_IP_VS_IPV6
-static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related)
+static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related,
+ unsigned int hooknum)
{
struct ipv6hdr *iph;
struct icmp6hdr _icmph, *ic;
@@ -795,7 +835,7 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related)
/* reassemble IP fragments */
if (ipv6_hdr(skb)->nexthdr == IPPROTO_FRAGMENT) {
- if (ip_vs_gather_frags_v6(skb, IP_DEFRAG_VS_OUT))
+ if (ip_vs_gather_frags_v6(skb, ip_vs_defrag_user(hooknum)))
return NF_STOLEN;
}
@@ -838,7 +878,8 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related)
if (unlikely(cih->nexthdr == IPPROTO_FRAGMENT && pp->dont_defrag))
return NF_ACCEPT;
- IP_VS_DBG_PKT(11, pp, skb, offset, "Checking outgoing ICMPv6 for");
+ IP_VS_DBG_PKT(11, AF_INET6, pp, skb, offset,
+ "Checking outgoing ICMPv6 for");
offset += sizeof(struct ipv6hdr);
@@ -886,7 +927,7 @@ static unsigned int
handle_response(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_conn *cp, int ihl)
{
- IP_VS_DBG_PKT(11, pp, skb, 0, "Outgoing packet");
+ IP_VS_DBG_PKT(11, af, pp, skb, 0, "Outgoing packet");
if (!skb_make_writable(skb, ihl))
goto drop;
@@ -905,6 +946,15 @@ handle_response(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
ip_send_check(ip_hdr(skb));
}
+ /*
+ * nf_iterate does not expect change in the skb->dst->dev.
+ * It looks like it is not fatal to enable this code for hooks
+ * where our handlers are at the end of the chain list and
+ * when all next handlers use skb->dst->dev and not outdev.
+ * It will definitely route properly the inout NAT traffic
+ * when multiple paths are used.
+ */
+
/* For policy routing, packets originating from this
* machine itself may be routed differently to packets
* passing through. We want this packet to be routed as
@@ -913,21 +963,25 @@ handle_response(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
*/
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) {
- if (ip6_route_me_harder(skb) != 0)
+ if (sysctl_ip_vs_snat_reroute && ip6_route_me_harder(skb) != 0)
goto drop;
} else
#endif
- if (ip_route_me_harder(skb, RTN_LOCAL) != 0)
+ if ((sysctl_ip_vs_snat_reroute ||
+ skb_rtable(skb)->rt_flags & RTCF_LOCAL) &&
+ ip_route_me_harder(skb, RTN_LOCAL) != 0)
goto drop;
- IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT");
+ IP_VS_DBG_PKT(10, af, pp, skb, 0, "After SNAT");
ip_vs_out_stats(cp, skb);
ip_vs_set_state(cp, IP_VS_DIR_OUTPUT, skb, pp);
- ip_vs_update_conntrack(skb, cp, 0);
- ip_vs_conn_put(cp);
-
skb->ipvs_property = 1;
+ if (!(cp->flags & IP_VS_CONN_F_NFCT))
+ ip_vs_notrack(skb);
+ else
+ ip_vs_update_conntrack(skb, cp, 0);
+ ip_vs_conn_put(cp);
LeaveFunction(11);
return NF_ACCEPT;
@@ -935,35 +989,46 @@ handle_response(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
drop:
ip_vs_conn_put(cp);
kfree_skb(skb);
+ LeaveFunction(11);
return NF_STOLEN;
}
/*
- * It is hooked at the NF_INET_FORWARD chain, used only for VS/NAT.
* Check if outgoing packet belongs to the established ip_vs_conn.
*/
static unsigned int
-ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
- const struct net_device *in, const struct net_device *out,
- int (*okfn)(struct sk_buff *))
+ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
{
struct ip_vs_iphdr iph;
struct ip_vs_protocol *pp;
struct ip_vs_conn *cp;
- int af;
EnterFunction(11);
- af = (skb->protocol == htons(ETH_P_IP)) ? AF_INET : AF_INET6;
-
+ /* Already marked as IPVS request or reply? */
if (skb->ipvs_property)
return NF_ACCEPT;
+ /* Bad... Do not break raw sockets */
+ if (unlikely(skb->sk != NULL && hooknum == NF_INET_LOCAL_OUT &&
+ af == AF_INET)) {
+ struct sock *sk = skb->sk;
+ struct inet_sock *inet = inet_sk(skb->sk);
+
+ if (inet && sk->sk_family == PF_INET && inet->nodefrag)
+ return NF_ACCEPT;
+ }
+
+ if (unlikely(!skb_dst(skb)))
+ return NF_ACCEPT;
+
ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) {
if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
- int related, verdict = ip_vs_out_icmp_v6(skb, &related);
+ int related;
+ int verdict = ip_vs_out_icmp_v6(skb, &related,
+ hooknum);
if (related)
return verdict;
@@ -972,7 +1037,8 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
} else
#endif
if (unlikely(iph.protocol == IPPROTO_ICMP)) {
- int related, verdict = ip_vs_out_icmp(skb, &related);
+ int related;
+ int verdict = ip_vs_out_icmp(skb, &related, hooknum);
if (related)
return verdict;
@@ -986,19 +1052,19 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
/* reassemble IP fragments */
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) {
- if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
- int related, verdict = ip_vs_out_icmp_v6(skb, &related);
-
- if (related)
- return verdict;
-
- ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+ if (ipv6_hdr(skb)->nexthdr == IPPROTO_FRAGMENT) {
+ if (ip_vs_gather_frags_v6(skb,
+ ip_vs_defrag_user(hooknum)))
+ return NF_STOLEN;
}
+
+ ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
} else
#endif
if (unlikely(ip_hdr(skb)->frag_off & htons(IP_MF|IP_OFFSET) &&
!pp->dont_defrag)) {
- if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
+ if (ip_vs_gather_frags(skb,
+ ip_vs_defrag_user(hooknum)))
return NF_STOLEN;
ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
@@ -1009,55 +1075,123 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
*/
cp = pp->conn_out_get(af, skb, pp, &iph, iph.len, 0);
- if (unlikely(!cp)) {
- if (sysctl_ip_vs_nat_icmp_send &&
- (pp->protocol == IPPROTO_TCP ||
- pp->protocol == IPPROTO_UDP ||
- pp->protocol == IPPROTO_SCTP)) {
- __be16 _ports[2], *pptr;
-
- pptr = skb_header_pointer(skb, iph.len,
- sizeof(_ports), _ports);
- if (pptr == NULL)
- return NF_ACCEPT; /* Not for me */
- if (ip_vs_lookup_real_service(af, iph.protocol,
- &iph.saddr,
- pptr[0])) {
- /*
- * Notify the real server: there is no
- * existing entry if it is not RST
- * packet or not TCP packet.
- */
- if ((iph.protocol != IPPROTO_TCP &&
- iph.protocol != IPPROTO_SCTP)
- || ((iph.protocol == IPPROTO_TCP
- && !is_tcp_reset(skb, iph.len))
- || (iph.protocol == IPPROTO_SCTP
- && !is_sctp_abort(skb,
- iph.len)))) {
+ if (likely(cp))
+ return handle_response(af, skb, pp, cp, iph.len);
+ if (sysctl_ip_vs_nat_icmp_send &&
+ (pp->protocol == IPPROTO_TCP ||
+ pp->protocol == IPPROTO_UDP ||
+ pp->protocol == IPPROTO_SCTP)) {
+ __be16 _ports[2], *pptr;
+
+ pptr = skb_header_pointer(skb, iph.len,
+ sizeof(_ports), _ports);
+ if (pptr == NULL)
+ return NF_ACCEPT; /* Not for me */
+ if (ip_vs_lookup_real_service(af, iph.protocol,
+ &iph.saddr,
+ pptr[0])) {
+ /*
+ * Notify the real server: there is no
+ * existing entry if it is not RST
+ * packet or not TCP packet.
+ */
+ if ((iph.protocol != IPPROTO_TCP &&
+ iph.protocol != IPPROTO_SCTP)
+ || ((iph.protocol == IPPROTO_TCP
+ && !is_tcp_reset(skb, iph.len))
+ || (iph.protocol == IPPROTO_SCTP
+ && !is_sctp_abort(skb,
+ iph.len)))) {
#ifdef CONFIG_IP_VS_IPV6
- if (af == AF_INET6)
- icmpv6_send(skb,
- ICMPV6_DEST_UNREACH,
- ICMPV6_PORT_UNREACH,
- 0);
- else
+ if (af == AF_INET6) {
+ struct net *net =
+ dev_net(skb_dst(skb)->dev);
+
+ if (!skb->dev)
+ skb->dev = net->loopback_dev;
+ icmpv6_send(skb,
+ ICMPV6_DEST_UNREACH,
+ ICMPV6_PORT_UNREACH,
+ 0);
+ } else
#endif
- icmp_send(skb,
- ICMP_DEST_UNREACH,
- ICMP_PORT_UNREACH, 0);
- return NF_DROP;
- }
+ icmp_send(skb,
+ ICMP_DEST_UNREACH,
+ ICMP_PORT_UNREACH, 0);
+ return NF_DROP;
}
}
- IP_VS_DBG_PKT(12, pp, skb, 0,
- "packet continues traversal as normal");
- return NF_ACCEPT;
}
+ IP_VS_DBG_PKT(12, af, pp, skb, 0,
+ "ip_vs_out: packet continues traversal as normal");
+ return NF_ACCEPT;
+}
+
+/*
+ * It is hooked at the NF_INET_FORWARD and NF_INET_LOCAL_IN chain,
+ * used only for VS/NAT.
+ * Check if packet is reply for established ip_vs_conn.
+ */
+static unsigned int
+ip_vs_reply4(unsigned int hooknum, struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return ip_vs_out(hooknum, skb, AF_INET);
+}
+
+/*
+ * It is hooked at the NF_INET_LOCAL_OUT chain, used only for VS/NAT.
+ * Check if packet is reply for established ip_vs_conn.
+ */
+static unsigned int
+ip_vs_local_reply4(unsigned int hooknum, struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ unsigned int verdict;
+
+ /* Disable BH in LOCAL_OUT until all places are fixed */
+ local_bh_disable();
+ verdict = ip_vs_out(hooknum, skb, AF_INET);
+ local_bh_enable();
+ return verdict;
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+
+/*
+ * It is hooked at the NF_INET_FORWARD and NF_INET_LOCAL_IN chain,
+ * used only for VS/NAT.
+ * Check if packet is reply for established ip_vs_conn.
+ */
+static unsigned int
+ip_vs_reply6(unsigned int hooknum, struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return ip_vs_out(hooknum, skb, AF_INET6);
+}
- return handle_response(af, skb, pp, cp, iph.len);
+/*
+ * It is hooked at the NF_INET_LOCAL_OUT chain, used only for VS/NAT.
+ * Check if packet is reply for established ip_vs_conn.
+ */
+static unsigned int
+ip_vs_local_reply6(unsigned int hooknum, struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ unsigned int verdict;
+
+ /* Disable BH in LOCAL_OUT until all places are fixed */
+ local_bh_disable();
+ verdict = ip_vs_out(hooknum, skb, AF_INET6);
+ local_bh_enable();
+ return verdict;
}
+#endif
/*
* Handle ICMP messages in the outside-to-inside direction (incoming).
@@ -1081,8 +1215,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
/* reassemble IP fragments */
if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
- if (ip_vs_gather_frags(skb, hooknum == NF_INET_LOCAL_IN ?
- IP_DEFRAG_VS_IN : IP_DEFRAG_VS_FWD))
+ if (ip_vs_gather_frags(skb, ip_vs_defrag_user(hooknum)))
return NF_STOLEN;
}
@@ -1125,7 +1258,8 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
pp->dont_defrag))
return NF_ACCEPT;
- IP_VS_DBG_PKT(11, pp, skb, offset, "Checking incoming ICMP for");
+ IP_VS_DBG_PKT(11, AF_INET, pp, skb, offset,
+ "Checking incoming ICMP for");
offset += cih->ihl * 4;
@@ -1159,7 +1293,14 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol)
offset += 2 * sizeof(__u16);
verdict = ip_vs_icmp_xmit(skb, cp, pp, offset);
- /* do not touch skb anymore */
+ /* LOCALNODE from FORWARD hook is not supported */
+ if (verdict == NF_ACCEPT && hooknum == NF_INET_FORWARD &&
+ skb_rtable(skb)->rt_flags & RTCF_LOCAL) {
+ IP_VS_DBG(1, "%s(): "
+ "local delivery to %pI4 but in FORWARD\n",
+ __func__, &skb_rtable(skb)->rt_dst);
+ verdict = NF_DROP;
+ }
out:
__ip_vs_conn_put(cp);
@@ -1180,14 +1321,13 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)
struct ip_vs_protocol *pp;
unsigned int offset, verdict;
union nf_inet_addr snet;
+ struct rt6_info *rt;
*related = 1;
/* reassemble IP fragments */
if (ipv6_hdr(skb)->nexthdr == IPPROTO_FRAGMENT) {
- if (ip_vs_gather_frags_v6(skb, hooknum == NF_INET_LOCAL_IN ?
- IP_DEFRAG_VS_IN :
- IP_DEFRAG_VS_FWD))
+ if (ip_vs_gather_frags_v6(skb, ip_vs_defrag_user(hooknum)))
return NF_STOLEN;
}
@@ -1230,7 +1370,8 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)
if (unlikely(cih->nexthdr == IPPROTO_FRAGMENT && pp->dont_defrag))
return NF_ACCEPT;
- IP_VS_DBG_PKT(11, pp, skb, offset, "Checking incoming ICMPv6 for");
+ IP_VS_DBG_PKT(11, AF_INET6, pp, skb, offset,
+ "Checking incoming ICMPv6 for");
offset += sizeof(struct ipv6hdr);
@@ -1258,7 +1399,15 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)
IPPROTO_SCTP == cih->nexthdr)
offset += 2 * sizeof(__u16);
verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset);
- /* do not touch skb anymore */
+ /* LOCALNODE from FORWARD hook is not supported */
+ if (verdict == NF_ACCEPT && hooknum == NF_INET_FORWARD &&
+ (rt = (struct rt6_info *) skb_dst(skb)) &&
+ rt->rt6i_dev && rt->rt6i_dev->flags & IFF_LOOPBACK) {
+ IP_VS_DBG(1, "%s(): "
+ "local delivery to %pI6 but in FORWARD\n",
+ __func__, &rt->rt6i_dst);
+ verdict = NF_DROP;
+ }
__ip_vs_conn_put(cp);
@@ -1272,35 +1421,49 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)
* and send it on its way...
*/
static unsigned int
-ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
- const struct net_device *in, const struct net_device *out,
- int (*okfn)(struct sk_buff *))
+ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
{
struct ip_vs_iphdr iph;
struct ip_vs_protocol *pp;
struct ip_vs_conn *cp;
- int ret, restart, af, pkts;
+ int ret, restart, pkts;
- af = (skb->protocol == htons(ETH_P_IP)) ? AF_INET : AF_INET6;
-
- ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+ /* Already marked as IPVS request or reply? */
+ if (skb->ipvs_property)
+ return NF_ACCEPT;
/*
- * Big tappo: only PACKET_HOST, including loopback for local client
- * Don't handle local packets on IPv6 for now
+ * Big tappo:
+ * - remote client: only PACKET_HOST
+ * - route: used for struct net when skb->dev is unset
*/
- if (unlikely(skb->pkt_type != PACKET_HOST)) {
- IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n",
- skb->pkt_type,
- iph.protocol,
- IP_VS_DBG_ADDR(af, &iph.daddr));
+ if (unlikely((skb->pkt_type != PACKET_HOST &&
+ hooknum != NF_INET_LOCAL_OUT) ||
+ !skb_dst(skb))) {
+ ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+ IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s"
+ " ignored in hook %u\n",
+ skb->pkt_type, iph.protocol,
+ IP_VS_DBG_ADDR(af, &iph.daddr), hooknum);
return NF_ACCEPT;
}
+ ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+
+ /* Bad... Do not break raw sockets */
+ if (unlikely(skb->sk != NULL && hooknum == NF_INET_LOCAL_OUT &&
+ af == AF_INET)) {
+ struct sock *sk = skb->sk;
+ struct inet_sock *inet = inet_sk(skb->sk);
+
+ if (inet && sk->sk_family == PF_INET && inet->nodefrag)
+ return NF_ACCEPT;
+ }
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) {
if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
- int related, verdict = ip_vs_in_icmp_v6(skb, &related, hooknum);
+ int related;
+ int verdict = ip_vs_in_icmp_v6(skb, &related, hooknum);
if (related)
return verdict;
@@ -1309,7 +1472,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
} else
#endif
if (unlikely(iph.protocol == IPPROTO_ICMP)) {
- int related, verdict = ip_vs_in_icmp(skb, &related, hooknum);
+ int related;
+ int verdict = ip_vs_in_icmp(skb, &related, hooknum);
if (related)
return verdict;
@@ -1329,23 +1493,18 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
if (unlikely(!cp)) {
int v;
- /* For local client packets, it could be a response */
- cp = pp->conn_out_get(af, skb, pp, &iph, iph.len, 0);
- if (cp)
- return handle_response(af, skb, pp, cp, iph.len);
-
if (!pp->conn_schedule(af, skb, pp, &v, &cp))
return v;
}
if (unlikely(!cp)) {
/* sorry, all this trouble for a no-hit :) */
- IP_VS_DBG_PKT(12, pp, skb, 0,
- "packet continues traversal as normal");
+ IP_VS_DBG_PKT(12, af, pp, skb, 0,
+ "ip_vs_in: packet continues traversal as normal");
return NF_ACCEPT;
}
- IP_VS_DBG_PKT(11, pp, skb, 0, "Incoming packet");
+ IP_VS_DBG_PKT(11, af, pp, skb, 0, "Incoming packet");
/* Check the server status */
if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
@@ -1381,8 +1540,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
if (af == AF_INET && (ip_vs_sync_state & IP_VS_STATE_MASTER) &&
cp->protocol == IPPROTO_SCTP) {
if ((cp->state == IP_VS_SCTP_S_ESTABLISHED &&
- (atomic_read(&cp->in_pkts) %
- sysctl_ip_vs_sync_threshold[1]
+ (pkts % sysctl_ip_vs_sync_threshold[1]
== sysctl_ip_vs_sync_threshold[0])) ||
(cp->old_state != cp->state &&
((cp->state == IP_VS_SCTP_S_CLOSED) ||
@@ -1393,7 +1551,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
}
}
- if (af == AF_INET &&
+ /* Keep this block last: TCP and others with pp->num_states <= 1 */
+ else if (af == AF_INET &&
(ip_vs_sync_state & IP_VS_STATE_MASTER) &&
(((cp->protocol != IPPROTO_TCP ||
cp->state == IP_VS_TCP_S_ESTABLISHED) &&
@@ -1412,6 +1571,72 @@ out:
return ret;
}
+/*
+ * AF_INET handler in NF_INET_LOCAL_IN chain
+ * Schedule and forward packets from remote clients
+ */
+static unsigned int
+ip_vs_remote_request4(unsigned int hooknum, struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return ip_vs_in(hooknum, skb, AF_INET);
+}
+
+/*
+ * AF_INET handler in NF_INET_LOCAL_OUT chain
+ * Schedule and forward packets from local clients
+ */
+static unsigned int
+ip_vs_local_request4(unsigned int hooknum, struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ unsigned int verdict;
+
+ /* Disable BH in LOCAL_OUT until all places are fixed */
+ local_bh_disable();
+ verdict = ip_vs_in(hooknum, skb, AF_INET);
+ local_bh_enable();
+ return verdict;
+}
+
+#ifdef CONFIG_IP_VS_IPV6
+
+/*
+ * AF_INET6 handler in NF_INET_LOCAL_IN chain
+ * Schedule and forward packets from remote clients
+ */
+static unsigned int
+ip_vs_remote_request6(unsigned int hooknum, struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return ip_vs_in(hooknum, skb, AF_INET6);
+}
+
+/*
+ * AF_INET6 handler in NF_INET_LOCAL_OUT chain
+ * Schedule and forward packets from local clients
+ */
+static unsigned int
+ip_vs_local_request6(unsigned int hooknum, struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ unsigned int verdict;
+
+ /* Disable BH in LOCAL_OUT until all places are fixed */
+ local_bh_disable();
+ verdict = ip_vs_in(hooknum, skb, AF_INET6);
+ local_bh_enable();
+ return verdict;
+}
+
+#endif
+
/*
* It is hooked at the NF_INET_FORWARD chain, in order to catch ICMP
@@ -1452,23 +1677,39 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb,
static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
+ /* After packet filtering, change source only for VS/NAT */
+ {
+ .hook = ip_vs_reply4,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_INET_LOCAL_IN,
+ .priority = 99,
+ },
/* After packet filtering, forward packet through VS/DR, VS/TUN,
* or VS/NAT(change destination), so that filtering rules can be
* applied to IPVS. */
{
- .hook = ip_vs_in,
+ .hook = ip_vs_remote_request4,
.owner = THIS_MODULE,
.pf = PF_INET,
- .hooknum = NF_INET_LOCAL_IN,
- .priority = 100,
+ .hooknum = NF_INET_LOCAL_IN,
+ .priority = 101,
},
- /* After packet filtering, change source only for VS/NAT */
+ /* Before ip_vs_in, change source only for VS/NAT */
{
- .hook = ip_vs_out,
+ .hook = ip_vs_local_reply4,
.owner = THIS_MODULE,
.pf = PF_INET,
- .hooknum = NF_INET_FORWARD,
- .priority = 100,
+ .hooknum = NF_INET_LOCAL_OUT,
+ .priority = -99,
+ },
+ /* After mangle, schedule and forward local requests */
+ {
+ .hook = ip_vs_local_request4,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_INET_LOCAL_OUT,
+ .priority = -98,
},
/* After packet filtering (but before ip_vs_out_icmp), catch icmp
* destined for 0.0.0.0/0, which is for incoming IPVS connections */
@@ -1476,27 +1717,51 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
.hook = ip_vs_forward_icmp,
.owner = THIS_MODULE,
.pf = PF_INET,
- .hooknum = NF_INET_FORWARD,
- .priority = 99,
+ .hooknum = NF_INET_FORWARD,
+ .priority = 99,
+ },
+ /* After packet filtering, change source only for VS/NAT */
+ {
+ .hook = ip_vs_reply4,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_INET_FORWARD,
+ .priority = 100,
},
#ifdef CONFIG_IP_VS_IPV6
+ /* After packet filtering, change source only for VS/NAT */
+ {
+ .hook = ip_vs_reply6,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_INET_LOCAL_IN,
+ .priority = 99,
+ },
/* After packet filtering, forward packet through VS/DR, VS/TUN,
* or VS/NAT(change destination), so that filtering rules can be
* applied to IPVS. */
{
- .hook = ip_vs_in,
+ .hook = ip_vs_remote_request6,
.owner = THIS_MODULE,
.pf = PF_INET6,
- .hooknum = NF_INET_LOCAL_IN,
- .priority = 100,
+ .hooknum = NF_INET_LOCAL_IN,
+ .priority = 101,
},
- /* After packet filtering, change source only for VS/NAT */
+ /* Before ip_vs_in, change source only for VS/NAT */
+ {
+ .hook = ip_vs_local_reply6,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_INET_LOCAL_OUT,
+ .priority = -99,
+ },
+ /* After mangle, schedule and forward local requests */
{
- .hook = ip_vs_out,
+ .hook = ip_vs_local_request6,
.owner = THIS_MODULE,
.pf = PF_INET6,
- .hooknum = NF_INET_FORWARD,
- .priority = 100,
+ .hooknum = NF_INET_LOCAL_OUT,
+ .priority = -98,
},
/* After packet filtering (but before ip_vs_out_icmp), catch icmp
* destined for 0.0.0.0/0, which is for incoming IPVS connections */
@@ -1504,8 +1769,16 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
.hook = ip_vs_forward_icmp_v6,
.owner = THIS_MODULE,
.pf = PF_INET6,
- .hooknum = NF_INET_FORWARD,
- .priority = 99,
+ .hooknum = NF_INET_FORWARD,
+ .priority = 99,
+ },
+ /* After packet filtering, change source only for VS/NAT */
+ {
+ .hook = ip_vs_reply6,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_INET_FORWARD,
+ .priority = 100,
},
#endif
};
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 0f0c079c422a..5f5daa30b0af 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -61,7 +61,7 @@ static DEFINE_RWLOCK(__ip_vs_svc_lock);
static DEFINE_RWLOCK(__ip_vs_rs_lock);
/* lock for state and timeout tables */
-static DEFINE_RWLOCK(__ip_vs_securetcp_lock);
+static DEFINE_SPINLOCK(ip_vs_securetcp_lock);
/* lock for drop entry handling */
static DEFINE_SPINLOCK(__ip_vs_dropentry_lock);
@@ -88,6 +88,10 @@ int sysctl_ip_vs_expire_nodest_conn = 0;
int sysctl_ip_vs_expire_quiescent_template = 0;
int sysctl_ip_vs_sync_threshold[2] = { 3, 50 };
int sysctl_ip_vs_nat_icmp_send = 0;
+#ifdef CONFIG_IP_VS_NFCT
+int sysctl_ip_vs_conntrack;
+#endif
+int sysctl_ip_vs_snat_reroute = 1;
#ifdef CONFIG_IP_VS_DEBUG
@@ -204,7 +208,7 @@ static void update_defense_level(void)
spin_unlock(&__ip_vs_droppacket_lock);
/* secure_tcp */
- write_lock(&__ip_vs_securetcp_lock);
+ spin_lock(&ip_vs_securetcp_lock);
switch (sysctl_ip_vs_secure_tcp) {
case 0:
if (old_secure_tcp >= 2)
@@ -238,7 +242,7 @@ static void update_defense_level(void)
old_secure_tcp = sysctl_ip_vs_secure_tcp;
if (to_change >= 0)
ip_vs_protocol_timeout_change(sysctl_ip_vs_secure_tcp>1);
- write_unlock(&__ip_vs_securetcp_lock);
+ spin_unlock(&ip_vs_securetcp_lock);
local_bh_enable();
}
@@ -401,7 +405,7 @@ static int ip_vs_svc_unhash(struct ip_vs_service *svc)
* Get service by {proto,addr,port} in the service table.
*/
static inline struct ip_vs_service *
-__ip_vs_service_get(int af, __u16 protocol, const union nf_inet_addr *vaddr,
+__ip_vs_service_find(int af, __u16 protocol, const union nf_inet_addr *vaddr,
__be16 vport)
{
unsigned hash;
@@ -416,7 +420,6 @@ __ip_vs_service_get(int af, __u16 protocol, const union nf_inet_addr *vaddr,
&& (svc->port == vport)
&& (svc->protocol == protocol)) {
/* HIT */
- atomic_inc(&svc->usecnt);
return svc;
}
}
@@ -429,7 +432,7 @@ __ip_vs_service_get(int af, __u16 protocol, const union nf_inet_addr *vaddr,
* Get service by {fwmark} in the service table.
*/
static inline struct ip_vs_service *
-__ip_vs_svc_fwm_get(int af, __u32 fwmark)
+__ip_vs_svc_fwm_find(int af, __u32 fwmark)
{
unsigned hash;
struct ip_vs_service *svc;
@@ -440,7 +443,6 @@ __ip_vs_svc_fwm_get(int af, __u32 fwmark)
list_for_each_entry(svc, &ip_vs_svc_fwm_table[hash], f_list) {
if (svc->fwmark == fwmark && svc->af == af) {
/* HIT */
- atomic_inc(&svc->usecnt);
return svc;
}
}
@@ -459,14 +461,14 @@ ip_vs_service_get(int af, __u32 fwmark, __u16 protocol,
/*
* Check the table hashed by fwmark first
*/
- if (fwmark && (svc = __ip_vs_svc_fwm_get(af, fwmark)))
+ if (fwmark && (svc = __ip_vs_svc_fwm_find(af, fwmark)))
goto out;
/*
* Check the table hashed by <protocol,addr,port>
* for "full" addressed entries
*/
- svc = __ip_vs_service_get(af, protocol, vaddr, vport);
+ svc = __ip_vs_service_find(af, protocol, vaddr, vport);
if (svc == NULL
&& protocol == IPPROTO_TCP
@@ -476,7 +478,7 @@ ip_vs_service_get(int af, __u32 fwmark, __u16 protocol,
* Check if ftp service entry exists, the packet
* might belong to FTP data connections.
*/
- svc = __ip_vs_service_get(af, protocol, vaddr, FTPPORT);
+ svc = __ip_vs_service_find(af, protocol, vaddr, FTPPORT);
}
if (svc == NULL
@@ -484,10 +486,12 @@ ip_vs_service_get(int af, __u32 fwmark, __u16 protocol,
/*
* Check if the catch-all port (port zero) exists
*/
- svc = __ip_vs_service_get(af, protocol, vaddr, 0);
+ svc = __ip_vs_service_find(af, protocol, vaddr, 0);
}
out:
+ if (svc)
+ atomic_inc(&svc->usecnt);
read_unlock(&__ip_vs_svc_lock);
IP_VS_DBG_BUF(9, "lookup service: fwm %u %s %s:%u %s\n",
@@ -506,14 +510,19 @@ __ip_vs_bind_svc(struct ip_vs_dest *dest, struct ip_vs_service *svc)
dest->svc = svc;
}
-static inline void
+static void
__ip_vs_unbind_svc(struct ip_vs_dest *dest)
{
struct ip_vs_service *svc = dest->svc;
dest->svc = NULL;
- if (atomic_dec_and_test(&svc->refcnt))
+ if (atomic_dec_and_test(&svc->refcnt)) {
+ IP_VS_DBG_BUF(3, "Removing service %u/%s:%u usecnt=%d\n",
+ svc->fwmark,
+ IP_VS_DBG_ADDR(svc->af, &svc->addr),
+ ntohs(svc->port), atomic_read(&svc->usecnt));
kfree(svc);
+ }
}
@@ -758,31 +767,18 @@ ip_vs_zero_stats(struct ip_vs_stats *stats)
* Update a destination in the given service
*/
static void
-__ip_vs_update_dest(struct ip_vs_service *svc,
- struct ip_vs_dest *dest, struct ip_vs_dest_user_kern *udest)
+__ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
+ struct ip_vs_dest_user_kern *udest, int add)
{
int conn_flags;
/* set the weight and the flags */
atomic_set(&dest->weight, udest->weight);
- conn_flags = udest->conn_flags | IP_VS_CONN_F_INACTIVE;
-
- /* check if local node and update the flags */
-#ifdef CONFIG_IP_VS_IPV6
- if (svc->af == AF_INET6) {
- if (__ip_vs_addr_is_local_v6(&udest->addr.in6)) {
- conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
- | IP_VS_CONN_F_LOCALNODE;
- }
- } else
-#endif
- if (inet_addr_type(&init_net, udest->addr.ip) == RTN_LOCAL) {
- conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
- | IP_VS_CONN_F_LOCALNODE;
- }
+ conn_flags = udest->conn_flags & IP_VS_CONN_F_DEST_MASK;
+ conn_flags |= IP_VS_CONN_F_INACTIVE;
/* set the IP_VS_CONN_F_NOOUTPUT flag if not masquerading/NAT */
- if ((conn_flags & IP_VS_CONN_F_FWD_MASK) != 0) {
+ if ((conn_flags & IP_VS_CONN_F_FWD_MASK) != IP_VS_CONN_F_MASQ) {
conn_flags |= IP_VS_CONN_F_NOOUTPUT;
} else {
/*
@@ -813,6 +809,29 @@ __ip_vs_update_dest(struct ip_vs_service *svc,
dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
dest->u_threshold = udest->u_threshold;
dest->l_threshold = udest->l_threshold;
+
+ spin_lock(&dest->dst_lock);
+ ip_vs_dst_reset(dest);
+ spin_unlock(&dest->dst_lock);
+
+ if (add)
+ ip_vs_new_estimator(&dest->stats);
+
+ write_lock_bh(&__ip_vs_svc_lock);
+
+ /* Wait until all other svc users go away */
+ IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
+
+ if (add) {
+ list_add(&dest->n_list, &svc->destinations);
+ svc->num_dests++;
+ }
+
+ /* call the update_service, because server weight may be changed */
+ if (svc->scheduler->update_service)
+ svc->scheduler->update_service(svc);
+
+ write_unlock_bh(&__ip_vs_svc_lock);
}
@@ -843,7 +862,7 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
return -EINVAL;
}
- dest = kzalloc(sizeof(struct ip_vs_dest), GFP_ATOMIC);
+ dest = kzalloc(sizeof(struct ip_vs_dest), GFP_KERNEL);
if (dest == NULL) {
pr_err("%s(): no memory.\n", __func__);
return -ENOMEM;
@@ -860,13 +879,12 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
atomic_set(&dest->activeconns, 0);
atomic_set(&dest->inactconns, 0);
atomic_set(&dest->persistconns, 0);
- atomic_set(&dest->refcnt, 0);
+ atomic_set(&dest->refcnt, 1);
INIT_LIST_HEAD(&dest->d_list);
spin_lock_init(&dest->dst_lock);
spin_lock_init(&dest->stats.lock);
- __ip_vs_update_dest(svc, dest, udest);
- ip_vs_new_estimator(&dest->stats);
+ __ip_vs_update_dest(svc, dest, udest, 1);
*dest_p = dest;
@@ -926,65 +944,22 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
IP_VS_DBG_ADDR(svc->af, &dest->vaddr),
ntohs(dest->vport));
- __ip_vs_update_dest(svc, dest, udest);
-
/*
* Get the destination from the trash
*/
list_del(&dest->n_list);
- ip_vs_new_estimator(&dest->stats);
-
- write_lock_bh(&__ip_vs_svc_lock);
-
+ __ip_vs_update_dest(svc, dest, udest, 1);
+ ret = 0;
+ } else {
/*
- * Wait until all other svc users go away.
+ * Allocate and initialize the dest structure
*/
- IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
-
- list_add(&dest->n_list, &svc->destinations);
- svc->num_dests++;
-
- /* call the update_service function of its scheduler */
- if (svc->scheduler->update_service)
- svc->scheduler->update_service(svc);
-
- write_unlock_bh(&__ip_vs_svc_lock);
- return 0;
- }
-
- /*
- * Allocate and initialize the dest structure
- */
- ret = ip_vs_new_dest(svc, udest, &dest);
- if (ret) {
- return ret;
+ ret = ip_vs_new_dest(svc, udest, &dest);
}
-
- /*
- * Add the dest entry into the list
- */
- atomic_inc(&dest->refcnt);
-
- write_lock_bh(&__ip_vs_svc_lock);
-
- /*
- * Wait until all other svc users go away.
- */
- IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
-
- list_add(&dest->n_list, &svc->destinations);
- svc->num_dests++;
-
- /* call the update_service function of its scheduler */
- if (svc->scheduler->update_service)
- svc->scheduler->update_service(svc);
-
- write_unlock_bh(&__ip_vs_svc_lock);
-
LeaveFunction(2);
- return 0;
+ return ret;
}
@@ -1023,19 +998,7 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
return -ENOENT;
}
- __ip_vs_update_dest(svc, dest, udest);
-
- write_lock_bh(&__ip_vs_svc_lock);
-
- /* Wait until all other svc users go away */
- IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
-
- /* call the update_service, because server weight may be changed */
- if (svc->scheduler->update_service)
- svc->scheduler->update_service(svc);
-
- write_unlock_bh(&__ip_vs_svc_lock);
-
+ __ip_vs_update_dest(svc, dest, udest, 0);
LeaveFunction(2);
return 0;
@@ -1062,6 +1025,10 @@ static void __ip_vs_del_dest(struct ip_vs_dest *dest)
* the destination into the trash.
*/
if (atomic_dec_and_test(&dest->refcnt)) {
+ IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u\n",
+ dest->vfwmark,
+ IP_VS_DBG_ADDR(dest->af, &dest->addr),
+ ntohs(dest->port));
ip_vs_dst_reset(dest);
/* simply decrease svc->refcnt here, let the caller check
and release the service if nobody refers to it.
@@ -1128,7 +1095,7 @@ ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
/*
* Wait until all other svc users go away.
*/
- IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
+ IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
/*
* Unlink dest from the service
@@ -1157,6 +1124,7 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
{
int ret = 0;
struct ip_vs_scheduler *sched = NULL;
+ struct ip_vs_pe *pe = NULL;
struct ip_vs_service *svc = NULL;
/* increase the module use count */
@@ -1167,7 +1135,17 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
if (sched == NULL) {
pr_info("Scheduler module ip_vs_%s not found\n", u->sched_name);
ret = -ENOENT;
- goto out_mod_dec;
+ goto out_err;
+ }
+
+ if (u->pe_name && *u->pe_name) {
+ pe = ip_vs_pe_get(u->pe_name);
+ if (pe == NULL) {
+ pr_info("persistence engine module ip_vs_pe_%s "
+ "not found\n", u->pe_name);
+ ret = -ENOENT;
+ goto out_err;
+ }
}
#ifdef CONFIG_IP_VS_IPV6
@@ -1177,7 +1155,7 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
}
#endif
- svc = kzalloc(sizeof(struct ip_vs_service), GFP_ATOMIC);
+ svc = kzalloc(sizeof(struct ip_vs_service), GFP_KERNEL);
if (svc == NULL) {
IP_VS_DBG(1, "%s(): no memory\n", __func__);
ret = -ENOMEM;
@@ -1185,7 +1163,7 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
}
/* I'm the first user of the service */
- atomic_set(&svc->usecnt, 1);
+ atomic_set(&svc->usecnt, 0);
atomic_set(&svc->refcnt, 0);
svc->af = u->af;
@@ -1207,6 +1185,10 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
goto out_err;
sched = NULL;
+ /* Bind the ct retriever */
+ ip_vs_bind_pe(svc, pe);
+ pe = NULL;
+
/* Update the virtual service counters */
if (svc->port == FTPPORT)
atomic_inc(&ip_vs_ftpsvc_counter);
@@ -1227,10 +1209,9 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
*svc_p = svc;
return 0;
- out_err:
+ out_err:
if (svc != NULL) {
- if (svc->scheduler)
- ip_vs_unbind_scheduler(svc);
+ ip_vs_unbind_scheduler(svc);
if (svc->inc) {
local_bh_disable();
ip_vs_app_inc_put(svc->inc);
@@ -1239,8 +1220,8 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
kfree(svc);
}
ip_vs_scheduler_put(sched);
+ ip_vs_pe_put(pe);
- out_mod_dec:
/* decrease the module use count */
ip_vs_use_count_dec();
@@ -1255,6 +1236,7 @@ static int
ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
{
struct ip_vs_scheduler *sched, *old_sched;
+ struct ip_vs_pe *pe = NULL, *old_pe = NULL;
int ret = 0;
/*
@@ -1267,6 +1249,17 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
}
old_sched = sched;
+ if (u->pe_name && *u->pe_name) {
+ pe = ip_vs_pe_get(u->pe_name);
+ if (pe == NULL) {
+ pr_info("persistence engine module ip_vs_pe_%s "
+ "not found\n", u->pe_name);
+ ret = -ENOENT;
+ goto out;
+ }
+ old_pe = pe;
+ }
+
#ifdef CONFIG_IP_VS_IPV6
if (u->af == AF_INET6 && (u->netmask < 1 || u->netmask > 128)) {
ret = -EINVAL;
@@ -1279,7 +1272,7 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
/*
* Wait until all other svc users go away.
*/
- IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
+ IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
/*
* Set the flags and timeout value
@@ -1318,15 +1311,17 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
}
}
+ old_pe = svc->pe;
+ if (pe != old_pe) {
+ ip_vs_unbind_pe(svc);
+ ip_vs_bind_pe(svc, pe);
+ }
+
out_unlock:
write_unlock_bh(&__ip_vs_svc_lock);
-#ifdef CONFIG_IP_VS_IPV6
out:
-#endif
-
- if (old_sched)
- ip_vs_scheduler_put(old_sched);
-
+ ip_vs_scheduler_put(old_sched);
+ ip_vs_pe_put(old_pe);
return ret;
}
@@ -1340,6 +1335,9 @@ static void __ip_vs_del_service(struct ip_vs_service *svc)
{
struct ip_vs_dest *dest, *nxt;
struct ip_vs_scheduler *old_sched;
+ struct ip_vs_pe *old_pe;
+
+ pr_info("%s: enter\n", __func__);
/* Count only IPv4 services for old get/setsockopt interface */
if (svc->af == AF_INET)
@@ -1350,8 +1348,12 @@ static void __ip_vs_del_service(struct ip_vs_service *svc)
/* Unbind scheduler */
old_sched = svc->scheduler;
ip_vs_unbind_scheduler(svc);
- if (old_sched)
- ip_vs_scheduler_put(old_sched);
+ ip_vs_scheduler_put(old_sched);
+
+ /* Unbind persistence engine */
+ old_pe = svc->pe;
+ ip_vs_unbind_pe(svc);
+ ip_vs_pe_put(old_pe);
/* Unbind app inc */
if (svc->inc) {
@@ -1378,21 +1380,23 @@ static void __ip_vs_del_service(struct ip_vs_service *svc)
/*
* Free the service if nobody refers to it
*/
- if (atomic_read(&svc->refcnt) == 0)
+ if (atomic_read(&svc->refcnt) == 0) {
+ IP_VS_DBG_BUF(3, "Removing service %u/%s:%u usecnt=%d\n",
+ svc->fwmark,
+ IP_VS_DBG_ADDR(svc->af, &svc->addr),
+ ntohs(svc->port), atomic_read(&svc->usecnt));
kfree(svc);
+ }
/* decrease the module use count */
ip_vs_use_count_dec();
}
/*
- * Delete a service from the service list
+ * Unlink a service from list and try to delete it if its refcnt reached 0
*/
-static int ip_vs_del_service(struct ip_vs_service *svc)
+static void ip_vs_unlink_service(struct ip_vs_service *svc)
{
- if (svc == NULL)
- return -EEXIST;
-
/*
* Unhash it from the service table
*/
@@ -1403,11 +1407,21 @@ static int ip_vs_del_service(struct ip_vs_service *svc)
/*
* Wait until all the svc users go away.
*/
- IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
+ IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
__ip_vs_del_service(svc);
write_unlock_bh(&__ip_vs_svc_lock);
+}
+
+/*
+ * Delete a service from the service list
+ */
+static int ip_vs_del_service(struct ip_vs_service *svc)
+{
+ if (svc == NULL)
+ return -EEXIST;
+ ip_vs_unlink_service(svc);
return 0;
}
@@ -1426,14 +1440,7 @@ static int ip_vs_flush(void)
*/
for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
list_for_each_entry_safe(svc, nxt, &ip_vs_svc_table[idx], s_list) {
- write_lock_bh(&__ip_vs_svc_lock);
- ip_vs_svc_unhash(svc);
- /*
- * Wait until all the svc users go away.
- */
- IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
- __ip_vs_del_service(svc);
- write_unlock_bh(&__ip_vs_svc_lock);
+ ip_vs_unlink_service(svc);
}
}
@@ -1443,14 +1450,7 @@ static int ip_vs_flush(void)
for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
list_for_each_entry_safe(svc, nxt,
&ip_vs_svc_fwm_table[idx], f_list) {
- write_lock_bh(&__ip_vs_svc_lock);
- ip_vs_svc_unhash(svc);
- /*
- * Wait until all the svc users go away.
- */
- IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
- __ip_vs_del_service(svc);
- write_unlock_bh(&__ip_vs_svc_lock);
+ ip_vs_unlink_service(svc);
}
}
@@ -1579,6 +1579,15 @@ static struct ctl_table vs_vars[] = {
.mode = 0644,
.proc_handler = proc_do_defense_mode,
},
+#ifdef CONFIG_IP_VS_NFCT
+ {
+ .procname = "conntrack",
+ .data = &sysctl_ip_vs_conntrack,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+#endif
{
.procname = "secure_tcp",
.data = &sysctl_ip_vs_secure_tcp,
@@ -1586,6 +1595,13 @@ static struct ctl_table vs_vars[] = {
.mode = 0644,
.proc_handler = proc_do_defense_mode,
},
+ {
+ .procname = "snat_reroute",
+ .data = &sysctl_ip_vs_snat_reroute,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
#if 0
{
.procname = "timeout_established",
@@ -2041,6 +2057,8 @@ static const unsigned char set_arglen[SET_CMDID(IP_VS_SO_SET_MAX)+1] = {
static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc,
struct ip_vs_service_user *usvc_compat)
{
+ memset(usvc, 0, sizeof(*usvc));
+
usvc->af = AF_INET;
usvc->protocol = usvc_compat->protocol;
usvc->addr.ip = usvc_compat->addr;
@@ -2058,6 +2076,8 @@ static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc,
static void ip_vs_copy_udest_compat(struct ip_vs_dest_user_kern *udest,
struct ip_vs_dest_user *udest_compat)
{
+ memset(udest, 0, sizeof(*udest));
+
udest->addr.ip = udest_compat->addr;
udest->port = udest_compat->port;
udest->conn_flags = udest_compat->conn_flags;
@@ -2147,10 +2167,10 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
/* Lookup the exact service by <protocol, addr, port> or fwmark */
if (usvc.fwmark == 0)
- svc = __ip_vs_service_get(usvc.af, usvc.protocol,
- &usvc.addr, usvc.port);
+ svc = __ip_vs_service_find(usvc.af, usvc.protocol,
+ &usvc.addr, usvc.port);
else
- svc = __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark);
+ svc = __ip_vs_svc_fwm_find(usvc.af, usvc.fwmark);
if (cmd != IP_VS_SO_SET_ADD
&& (svc == NULL || svc->protocol != usvc.protocol)) {
@@ -2189,9 +2209,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
ret = -EINVAL;
}
- if (svc)
- ip_vs_service_put(svc);
-
out_unlock:
mutex_unlock(&__ip_vs_mutex);
out_dec:
@@ -2284,10 +2301,10 @@ __ip_vs_get_dest_entries(const struct ip_vs_get_dests *get,
int ret = 0;
if (get->fwmark)
- svc = __ip_vs_svc_fwm_get(AF_INET, get->fwmark);
+ svc = __ip_vs_svc_fwm_find(AF_INET, get->fwmark);
else
- svc = __ip_vs_service_get(AF_INET, get->protocol, &addr,
- get->port);
+ svc = __ip_vs_service_find(AF_INET, get->protocol, &addr,
+ get->port);
if (svc) {
int count = 0;
@@ -2315,7 +2332,6 @@ __ip_vs_get_dest_entries(const struct ip_vs_get_dests *get,
}
count++;
}
- ip_vs_service_put(svc);
} else
ret = -ESRCH;
return ret;
@@ -2436,15 +2452,14 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
entry = (struct ip_vs_service_entry *)arg;
addr.ip = entry->addr;
if (entry->fwmark)
- svc = __ip_vs_svc_fwm_get(AF_INET, entry->fwmark);
+ svc = __ip_vs_svc_fwm_find(AF_INET, entry->fwmark);
else
- svc = __ip_vs_service_get(AF_INET, entry->protocol,
- &addr, entry->port);
+ svc = __ip_vs_service_find(AF_INET, entry->protocol,
+ &addr, entry->port);
if (svc) {
ip_vs_copy_service(entry, svc);
if (copy_to_user(user, entry, sizeof(*entry)) != 0)
ret = -EFAULT;
- ip_vs_service_put(svc);
} else
ret = -ESRCH;
}
@@ -2559,6 +2574,8 @@ static const struct nla_policy ip_vs_svc_policy[IPVS_SVC_ATTR_MAX + 1] = {
[IPVS_SVC_ATTR_FWMARK] = { .type = NLA_U32 },
[IPVS_SVC_ATTR_SCHED_NAME] = { .type = NLA_NUL_STRING,
.len = IP_VS_SCHEDNAME_MAXLEN },
+ [IPVS_SVC_ATTR_PE_NAME] = { .type = NLA_NUL_STRING,
+ .len = IP_VS_PENAME_MAXLEN },
[IPVS_SVC_ATTR_FLAGS] = { .type = NLA_BINARY,
.len = sizeof(struct ip_vs_flags) },
[IPVS_SVC_ATTR_TIMEOUT] = { .type = NLA_U32 },
@@ -2635,6 +2652,8 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb,
}
NLA_PUT_STRING(skb, IPVS_SVC_ATTR_SCHED_NAME, svc->scheduler->name);
+ if (svc->pe)
+ NLA_PUT_STRING(skb, IPVS_SVC_ATTR_PE_NAME, svc->pe->name);
NLA_PUT(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags);
NLA_PUT_U32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ);
NLA_PUT_U32(skb, IPVS_SVC_ATTR_NETMASK, svc->netmask);
@@ -2711,10 +2730,12 @@ nla_put_failure:
}
static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
- struct nlattr *nla, int full_entry)
+ struct nlattr *nla, int full_entry,
+ struct ip_vs_service **ret_svc)
{
struct nlattr *attrs[IPVS_SVC_ATTR_MAX + 1];
struct nlattr *nla_af, *nla_port, *nla_fwmark, *nla_protocol, *nla_addr;
+ struct ip_vs_service *svc;
/* Parse mandatory identifying service fields first */
if (nla == NULL ||
@@ -2750,14 +2771,21 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
usvc->fwmark = 0;
}
+ if (usvc->fwmark)
+ svc = __ip_vs_svc_fwm_find(usvc->af, usvc->fwmark);
+ else
+ svc = __ip_vs_service_find(usvc->af, usvc->protocol,
+ &usvc->addr, usvc->port);
+ *ret_svc = svc;
+
/* If a full entry was requested, check for the additional fields */
if (full_entry) {
- struct nlattr *nla_sched, *nla_flags, *nla_timeout,
+ struct nlattr *nla_sched, *nla_flags, *nla_pe, *nla_timeout,
*nla_netmask;
struct ip_vs_flags flags;
- struct ip_vs_service *svc;
nla_sched = attrs[IPVS_SVC_ATTR_SCHED_NAME];
+ nla_pe = attrs[IPVS_SVC_ATTR_PE_NAME];
nla_flags = attrs[IPVS_SVC_ATTR_FLAGS];
nla_timeout = attrs[IPVS_SVC_ATTR_TIMEOUT];
nla_netmask = attrs[IPVS_SVC_ATTR_NETMASK];
@@ -2768,21 +2796,14 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
nla_memcpy(&flags, nla_flags, sizeof(flags));
/* prefill flags from service if it already exists */
- if (usvc->fwmark)
- svc = __ip_vs_svc_fwm_get(usvc->af, usvc->fwmark);
- else
- svc = __ip_vs_service_get(usvc->af, usvc->protocol,
- &usvc->addr, usvc->port);
- if (svc) {
+ if (svc)
usvc->flags = svc->flags;
- ip_vs_service_put(svc);
- } else
- usvc->flags = 0;
/* set new flags from userland */
usvc->flags = (usvc->flags & ~flags.mask) |
(flags.flags & flags.mask);
usvc->sched_name = nla_data(nla_sched);
+ usvc->pe_name = nla_pe ? nla_data(nla_pe) : NULL;
usvc->timeout = nla_get_u32(nla_timeout);
usvc->netmask = nla_get_u32(nla_netmask);
}
@@ -2793,17 +2814,11 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla)
{
struct ip_vs_service_user_kern usvc;
+ struct ip_vs_service *svc;
int ret;
- ret = ip_vs_genl_parse_service(&usvc, nla, 0);
- if (ret)
- return ERR_PTR(ret);
-
- if (usvc.fwmark)
- return __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark);
- else
- return __ip_vs_service_get(usvc.af, usvc.protocol,
- &usvc.addr, usvc.port);
+ ret = ip_vs_genl_parse_service(&usvc, nla, 0, &svc);
+ return ret ? ERR_PTR(ret) : svc;
}
static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest)
@@ -2894,7 +2909,6 @@ static int ip_vs_genl_dump_dests(struct sk_buff *skb,
nla_put_failure:
cb->args[0] = idx;
- ip_vs_service_put(svc);
out_err:
mutex_unlock(&__ip_vs_mutex);
@@ -3107,17 +3121,10 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
ret = ip_vs_genl_parse_service(&usvc,
info->attrs[IPVS_CMD_ATTR_SERVICE],
- need_full_svc);
+ need_full_svc, &svc);
if (ret)
goto out;
- /* Lookup the exact service by <protocol, addr, port> or fwmark */
- if (usvc.fwmark == 0)
- svc = __ip_vs_service_get(usvc.af, usvc.protocol,
- &usvc.addr, usvc.port);
- else
- svc = __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark);
-
/* Unless we're adding a new service, the service must already exist */
if ((cmd != IPVS_CMD_NEW_SERVICE) && (svc == NULL)) {
ret = -ESRCH;
@@ -3151,6 +3158,7 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
break;
case IPVS_CMD_DEL_SERVICE:
ret = ip_vs_del_service(svc);
+ /* do not use svc, it can be freed */
break;
case IPVS_CMD_NEW_DEST:
ret = ip_vs_add_dest(svc, &udest);
@@ -3169,8 +3177,6 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
}
out:
- if (svc)
- ip_vs_service_put(svc);
mutex_unlock(&__ip_vs_mutex);
return ret;
@@ -3216,7 +3222,6 @@ static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info)
goto out_err;
} else if (svc) {
ret = ip_vs_genl_fill_service(msg, svc);
- ip_vs_service_put(svc);
if (ret)
goto nla_put_failure;
} else {
@@ -3385,6 +3390,16 @@ int __init ip_vs_control_init(void)
EnterFunction(2);
+ /* Initialize ip_vs_svc_table, ip_vs_svc_fwm_table, ip_vs_rtable */
+ for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+ INIT_LIST_HEAD(&ip_vs_svc_table[idx]);
+ INIT_LIST_HEAD(&ip_vs_svc_fwm_table[idx]);
+ }
+ for(idx = 0; idx < IP_VS_RTAB_SIZE; idx++) {
+ INIT_LIST_HEAD(&ip_vs_rtable[idx]);
+ }
+ smp_wmb();
+
ret = nf_register_sockopt(&ip_vs_sockopts);
if (ret) {
pr_err("cannot register sockopt.\n");
@@ -3403,15 +3418,6 @@ int __init ip_vs_control_init(void)
sysctl_header = register_sysctl_paths(net_vs_ctl_path, vs_vars);
- /* Initialize ip_vs_svc_table, ip_vs_svc_fwm_table, ip_vs_rtable */
- for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
- INIT_LIST_HEAD(&ip_vs_svc_table[idx]);
- INIT_LIST_HEAD(&ip_vs_svc_fwm_table[idx]);
- }
- for(idx = 0; idx < IP_VS_RTAB_SIZE; idx++) {
- INIT_LIST_HEAD(&ip_vs_rtable[idx]);
- }
-
ip_vs_new_estimator(&ip_vs_stats);
/* Hook the defense timer */
diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c
index 7e9af5b76d9e..75455000ad1c 100644
--- a/net/netfilter/ipvs/ip_vs_ftp.c
+++ b/net/netfilter/ipvs/ip_vs_ftp.c
@@ -20,17 +20,6 @@
*
* Author: Wouter Gadeyne
*
- *
- * Code for ip_vs_expect_related and ip_vs_expect_callback is taken from
- * http://www.ssi.bg/~ja/nfct/:
- *
- * ip_vs_nfct.c: Netfilter connection tracking support for IPVS
- *
- * Portions Copyright (C) 2001-2002
- * Antefacto Ltd, 181 Parnell St, Dublin 1, Ireland.
- *
- * Portions Copyright (C) 2003-2008
- * Julian Anastasov
*/
#define KMSG_COMPONENT "IPVS"
@@ -58,16 +47,6 @@
#define SERVER_STRING "227 Entering Passive Mode ("
#define CLIENT_STRING "PORT "
-#define FMT_TUPLE "%pI4:%u->%pI4:%u/%u"
-#define ARG_TUPLE(T) &(T)->src.u3.ip, ntohs((T)->src.u.all), \
- &(T)->dst.u3.ip, ntohs((T)->dst.u.all), \
- (T)->dst.protonum
-
-#define FMT_CONN "%pI4:%u->%pI4:%u->%pI4:%u/%u:%u"
-#define ARG_CONN(C) &((C)->caddr.ip), ntohs((C)->cport), \
- &((C)->vaddr.ip), ntohs((C)->vport), \
- &((C)->daddr.ip), ntohs((C)->dport), \
- (C)->protocol, (C)->state
/*
* List of ports (up to IP_VS_APP_MAX_PORTS) to be handled by helper
@@ -85,6 +64,8 @@ static int ip_vs_ftp_pasv;
static int
ip_vs_ftp_init_conn(struct ip_vs_app *app, struct ip_vs_conn *cp)
{
+ /* We use connection tracking for the command connection */
+ cp->flags |= IP_VS_CONN_F_NFCT;
return 0;
}
@@ -149,120 +130,6 @@ static int ip_vs_ftp_get_addrport(char *data, char *data_limit,
}
/*
- * Called from init_conntrack() as expectfn handler.
- */
-static void
-ip_vs_expect_callback(struct nf_conn *ct,
- struct nf_conntrack_expect *exp)
-{
- struct nf_conntrack_tuple *orig, new_reply;
- struct ip_vs_conn *cp;
-
- if (exp->tuple.src.l3num != PF_INET)
- return;
-
- /*
- * We assume that no NF locks are held before this callback.
- * ip_vs_conn_out_get and ip_vs_conn_in_get should match their
- * expectations even if they use wildcard values, now we provide the
- * actual values from the newly created original conntrack direction.
- * The conntrack is confirmed when packet reaches IPVS hooks.
- */
-
- /* RS->CLIENT */
- orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
- cp = ip_vs_conn_out_get(exp->tuple.src.l3num, orig->dst.protonum,
- &orig->src.u3, orig->src.u.tcp.port,
- &orig->dst.u3, orig->dst.u.tcp.port);
- if (cp) {
- /* Change reply CLIENT->RS to CLIENT->VS */
- new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
- IP_VS_DBG(7, "%s(): ct=%p, status=0x%lX, tuples=" FMT_TUPLE ", "
- FMT_TUPLE ", found inout cp=" FMT_CONN "\n",
- __func__, ct, ct->status,
- ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
- ARG_CONN(cp));
- new_reply.dst.u3 = cp->vaddr;
- new_reply.dst.u.tcp.port = cp->vport;
- IP_VS_DBG(7, "%s(): ct=%p, new tuples=" FMT_TUPLE ", " FMT_TUPLE
- ", inout cp=" FMT_CONN "\n",
- __func__, ct,
- ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
- ARG_CONN(cp));
- goto alter;
- }
-
- /* CLIENT->VS */
- cp = ip_vs_conn_in_get(exp->tuple.src.l3num, orig->dst.protonum,
- &orig->src.u3, orig->src.u.tcp.port,
- &orig->dst.u3, orig->dst.u.tcp.port);
- if (cp) {
- /* Change reply VS->CLIENT to RS->CLIENT */
- new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
- IP_VS_DBG(7, "%s(): ct=%p, status=0x%lX, tuples=" FMT_TUPLE ", "
- FMT_TUPLE ", found outin cp=" FMT_CONN "\n",
- __func__, ct, ct->status,
- ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
- ARG_CONN(cp));
- new_reply.src.u3 = cp->daddr;
- new_reply.src.u.tcp.port = cp->dport;
- IP_VS_DBG(7, "%s(): ct=%p, new tuples=" FMT_TUPLE ", "
- FMT_TUPLE ", outin cp=" FMT_CONN "\n",
- __func__, ct,
- ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
- ARG_CONN(cp));
- goto alter;
- }
-
- IP_VS_DBG(7, "%s(): ct=%p, status=0x%lX, tuple=" FMT_TUPLE
- " - unknown expect\n",
- __func__, ct, ct->status, ARG_TUPLE(orig));
- return;
-
-alter:
- /* Never alter conntrack for non-NAT conns */
- if (IP_VS_FWD_METHOD(cp) == IP_VS_CONN_F_MASQ)
- nf_conntrack_alter_reply(ct, &new_reply);
- ip_vs_conn_put(cp);
- return;
-}
-
-/*
- * Create NF conntrack expectation with wildcard (optional) source port.
- * Then the default callback function will alter the reply and will confirm
- * the conntrack entry when the first packet comes.
- */
-static void
-ip_vs_expect_related(struct sk_buff *skb, struct nf_conn *ct,
- struct ip_vs_conn *cp, u_int8_t proto,
- const __be16 *port, int from_rs)
-{
- struct nf_conntrack_expect *exp;
-
- BUG_ON(!ct || ct == &nf_conntrack_untracked);
-
- exp = nf_ct_expect_alloc(ct);
- if (!exp)
- return;
-
- if (from_rs)
- nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
- nf_ct_l3num(ct), &cp->daddr, &cp->caddr,
- proto, port, &cp->cport);
- else
- nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
- nf_ct_l3num(ct), &cp->caddr, &cp->vaddr,
- proto, port, &cp->vport);
-
- exp->expectfn = ip_vs_expect_callback;
-
- IP_VS_DBG(7, "%s(): ct=%p, expect tuple=" FMT_TUPLE "\n",
- __func__, ct, ARG_TUPLE(&exp->tuple));
- nf_ct_expect_related(exp);
- nf_ct_expect_put(exp);
-}
-
-/*
* Look at outgoing ftp packets to catch the response to a PASV command
* from the server (inside-to-outside).
* When we see one, we build a connection entry with the client address,
@@ -328,14 +195,19 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
/*
* Now update or create an connection entry for it
*/
- n_cp = ip_vs_conn_out_get(AF_INET, iph->protocol, &from, port,
- &cp->caddr, 0);
+ {
+ struct ip_vs_conn_param p;
+ ip_vs_conn_fill_param(AF_INET, iph->protocol,
+ &from, port, &cp->caddr, 0, &p);
+ n_cp = ip_vs_conn_out_get(&p);
+ }
if (!n_cp) {
- n_cp = ip_vs_conn_new(AF_INET, IPPROTO_TCP,
- &cp->caddr, 0,
- &cp->vaddr, port,
- &from, port,
- IP_VS_CONN_F_NO_CPORT,
+ struct ip_vs_conn_param p;
+ ip_vs_conn_fill_param(AF_INET, IPPROTO_TCP, &cp->caddr,
+ 0, &cp->vaddr, port, &p);
+ n_cp = ip_vs_conn_new(&p, &from, port,
+ IP_VS_CONN_F_NO_CPORT |
+ IP_VS_CONN_F_NFCT,
cp->dest);
if (!n_cp)
return 0;
@@ -370,9 +242,14 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
ret = nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
start-data, end-start,
buf, buf_len);
- if (ret)
- ip_vs_expect_related(skb, ct, n_cp,
- IPPROTO_TCP, NULL, 0);
+ if (ret) {
+ ip_vs_nfct_expect_related(skb, ct, n_cp,
+ IPPROTO_TCP, 0, 0);
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ /* csum is updated */
+ ret = 1;
+ }
}
/*
@@ -479,21 +356,22 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
ip_vs_proto_name(iph->protocol),
&to.ip, ntohs(port), &cp->vaddr.ip, 0);
- n_cp = ip_vs_conn_in_get(AF_INET, iph->protocol,
- &to, port,
- &cp->vaddr, htons(ntohs(cp->vport)-1));
- if (!n_cp) {
- n_cp = ip_vs_conn_new(AF_INET, IPPROTO_TCP,
- &to, port,
+ {
+ struct ip_vs_conn_param p;
+ ip_vs_conn_fill_param(AF_INET, iph->protocol, &to, port,
&cp->vaddr, htons(ntohs(cp->vport)-1),
- &cp->daddr, htons(ntohs(cp->dport)-1),
- 0,
- cp->dest);
- if (!n_cp)
- return 0;
+ &p);
+ n_cp = ip_vs_conn_in_get(&p);
+ if (!n_cp) {
+ n_cp = ip_vs_conn_new(&p, &cp->daddr,
+ htons(ntohs(cp->dport)-1),
+ IP_VS_CONN_F_NFCT, cp->dest);
+ if (!n_cp)
+ return 0;
- /* add its controller */
- ip_vs_control_add(n_cp, cp);
+ /* add its controller */
+ ip_vs_control_add(n_cp, cp);
+ }
}
/*
diff --git a/net/netfilter/ipvs/ip_vs_nfct.c b/net/netfilter/ipvs/ip_vs_nfct.c
new file mode 100644
index 000000000000..4680647cd450
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_nfct.c
@@ -0,0 +1,292 @@
+/*
+ * ip_vs_nfct.c: Netfilter connection tracking support for IPVS
+ *
+ * Portions Copyright (C) 2001-2002
+ * Antefacto Ltd, 181 Parnell St, Dublin 1, Ireland.
+ *
+ * Portions Copyright (C) 2003-2010
+ * Julian Anastasov
+ *
+ *
+ * This code 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
+ *
+ *
+ * Authors:
+ * Ben North <ben@redfrontdoor.org>
+ * Julian Anastasov <ja@ssi.bg> Reorganize and sync with latest kernels
+ * Hannes Eder <heder@google.com> Extend NFCT support for FTP, ipvs match
+ *
+ *
+ * Current status:
+ *
+ * - provide conntrack confirmation for new and related connections, by
+ * this way we can see their proper conntrack state in all hooks
+ * - support for all forwarding methods, not only NAT
+ * - FTP support (NAT), ability to support other NAT apps with expectations
+ * - to correctly create expectations for related NAT connections the proper
+ * NF conntrack support must be already installed, eg. ip_vs_ftp requires
+ * nf_conntrack_ftp ... iptables_nat for the same ports (but no iptables
+ * NAT rules are needed)
+ * - alter reply for NAT when forwarding packet in original direction:
+ * conntrack from client in NEW or RELATED (Passive FTP DATA) state or
+ * when RELATED conntrack is created from real server (Active FTP DATA)
+ * - if iptables_nat is not loaded the Passive FTP will not work (the
+ * PASV response can not be NAT-ed) but Active FTP should work
+ *
+ */
+
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/compiler.h>
+#include <linux/vmalloc.h>
+#include <linux/skbuff.h>
+#include <net/ip.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <net/ip_vs.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_expect.h>
+#include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_conntrack_zones.h>
+
+
+#define FMT_TUPLE "%pI4:%u->%pI4:%u/%u"
+#define ARG_TUPLE(T) &(T)->src.u3.ip, ntohs((T)->src.u.all), \
+ &(T)->dst.u3.ip, ntohs((T)->dst.u.all), \
+ (T)->dst.protonum
+
+#define FMT_CONN "%pI4:%u->%pI4:%u->%pI4:%u/%u:%u"
+#define ARG_CONN(C) &((C)->caddr.ip), ntohs((C)->cport), \
+ &((C)->vaddr.ip), ntohs((C)->vport), \
+ &((C)->daddr.ip), ntohs((C)->dport), \
+ (C)->protocol, (C)->state
+
+void
+ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp, int outin)
+{
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo);
+ struct nf_conntrack_tuple new_tuple;
+
+ if (ct == NULL || nf_ct_is_confirmed(ct) || nf_ct_is_untracked(ct) ||
+ nf_ct_is_dying(ct))
+ return;
+
+ /* Never alter conntrack for non-NAT conns */
+ if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
+ return;
+
+ /* Alter reply only in original direction */
+ if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
+ return;
+
+ /*
+ * The connection is not yet in the hashtable, so we update it.
+ * CIP->VIP will remain the same, so leave the tuple in
+ * IP_CT_DIR_ORIGINAL untouched. When the reply comes back from the
+ * real-server we will see RIP->DIP.
+ */
+ new_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+ /*
+ * This will also take care of UDP and other protocols.
+ */
+ if (outin) {
+ new_tuple.src.u3 = cp->daddr;
+ if (new_tuple.dst.protonum != IPPROTO_ICMP &&
+ new_tuple.dst.protonum != IPPROTO_ICMPV6)
+ new_tuple.src.u.tcp.port = cp->dport;
+ } else {
+ new_tuple.dst.u3 = cp->vaddr;
+ if (new_tuple.dst.protonum != IPPROTO_ICMP &&
+ new_tuple.dst.protonum != IPPROTO_ICMPV6)
+ new_tuple.dst.u.tcp.port = cp->vport;
+ }
+ IP_VS_DBG(7, "%s: Updating conntrack ct=%p, status=0x%lX, "
+ "ctinfo=%d, old reply=" FMT_TUPLE
+ ", new reply=" FMT_TUPLE ", cp=" FMT_CONN "\n",
+ __func__, ct, ct->status, ctinfo,
+ ARG_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple),
+ ARG_TUPLE(&new_tuple), ARG_CONN(cp));
+ nf_conntrack_alter_reply(ct, &new_tuple);
+}
+
+int ip_vs_confirm_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp)
+{
+ return nf_conntrack_confirm(skb);
+}
+
+/*
+ * Called from init_conntrack() as expectfn handler.
+ */
+static void ip_vs_nfct_expect_callback(struct nf_conn *ct,
+ struct nf_conntrack_expect *exp)
+{
+ struct nf_conntrack_tuple *orig, new_reply;
+ struct ip_vs_conn *cp;
+ struct ip_vs_conn_param p;
+
+ if (exp->tuple.src.l3num != PF_INET)
+ return;
+
+ /*
+ * We assume that no NF locks are held before this callback.
+ * ip_vs_conn_out_get and ip_vs_conn_in_get should match their
+ * expectations even if they use wildcard values, now we provide the
+ * actual values from the newly created original conntrack direction.
+ * The conntrack is confirmed when packet reaches IPVS hooks.
+ */
+
+ /* RS->CLIENT */
+ orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+ ip_vs_conn_fill_param(exp->tuple.src.l3num, orig->dst.protonum,
+ &orig->src.u3, orig->src.u.tcp.port,
+ &orig->dst.u3, orig->dst.u.tcp.port, &p);
+ cp = ip_vs_conn_out_get(&p);
+ if (cp) {
+ /* Change reply CLIENT->RS to CLIENT->VS */
+ new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+ IP_VS_DBG(7, "%s: ct=%p, status=0x%lX, tuples=" FMT_TUPLE ", "
+ FMT_TUPLE ", found inout cp=" FMT_CONN "\n",
+ __func__, ct, ct->status,
+ ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+ ARG_CONN(cp));
+ new_reply.dst.u3 = cp->vaddr;
+ new_reply.dst.u.tcp.port = cp->vport;
+ IP_VS_DBG(7, "%s: ct=%p, new tuples=" FMT_TUPLE ", " FMT_TUPLE
+ ", inout cp=" FMT_CONN "\n",
+ __func__, ct,
+ ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+ ARG_CONN(cp));
+ goto alter;
+ }
+
+ /* CLIENT->VS */
+ cp = ip_vs_conn_in_get(&p);
+ if (cp) {
+ /* Change reply VS->CLIENT to RS->CLIENT */
+ new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+ IP_VS_DBG(7, "%s: ct=%p, status=0x%lX, tuples=" FMT_TUPLE ", "
+ FMT_TUPLE ", found outin cp=" FMT_CONN "\n",
+ __func__, ct, ct->status,
+ ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+ ARG_CONN(cp));
+ new_reply.src.u3 = cp->daddr;
+ new_reply.src.u.tcp.port = cp->dport;
+ IP_VS_DBG(7, "%s: ct=%p, new tuples=" FMT_TUPLE ", "
+ FMT_TUPLE ", outin cp=" FMT_CONN "\n",
+ __func__, ct,
+ ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+ ARG_CONN(cp));
+ goto alter;
+ }
+
+ IP_VS_DBG(7, "%s: ct=%p, status=0x%lX, tuple=" FMT_TUPLE
+ " - unknown expect\n",
+ __func__, ct, ct->status, ARG_TUPLE(orig));
+ return;
+
+alter:
+ /* Never alter conntrack for non-NAT conns */
+ if (IP_VS_FWD_METHOD(cp) == IP_VS_CONN_F_MASQ)
+ nf_conntrack_alter_reply(ct, &new_reply);
+ ip_vs_conn_put(cp);
+ return;
+}
+
+/*
+ * Create NF conntrack expectation with wildcard (optional) source port.
+ * Then the default callback function will alter the reply and will confirm
+ * the conntrack entry when the first packet comes.
+ * Use port 0 to expect connection from any port.
+ */
+void ip_vs_nfct_expect_related(struct sk_buff *skb, struct nf_conn *ct,
+ struct ip_vs_conn *cp, u_int8_t proto,
+ const __be16 port, int from_rs)
+{
+ struct nf_conntrack_expect *exp;
+
+ if (ct == NULL || nf_ct_is_untracked(ct))
+ return;
+
+ exp = nf_ct_expect_alloc(ct);
+ if (!exp)
+ return;
+
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
+ from_rs ? &cp->daddr : &cp->caddr,
+ from_rs ? &cp->caddr : &cp->vaddr,
+ proto, port ? &port : NULL,
+ from_rs ? &cp->cport : &cp->vport);
+
+ exp->expectfn = ip_vs_nfct_expect_callback;
+
+ IP_VS_DBG(7, "%s: ct=%p, expect tuple=" FMT_TUPLE "\n",
+ __func__, ct, ARG_TUPLE(&exp->tuple));
+ nf_ct_expect_related(exp);
+ nf_ct_expect_put(exp);
+}
+EXPORT_SYMBOL(ip_vs_nfct_expect_related);
+
+/*
+ * Our connection was terminated, try to drop the conntrack immediately
+ */
+void ip_vs_conn_drop_conntrack(struct ip_vs_conn *cp)
+{
+ struct nf_conntrack_tuple_hash *h;
+ struct nf_conn *ct;
+ struct nf_conntrack_tuple tuple;
+
+ if (!cp->cport)
+ return;
+
+ tuple = (struct nf_conntrack_tuple) {
+ .dst = { .protonum = cp->protocol, .dir = IP_CT_DIR_ORIGINAL } };
+ tuple.src.u3 = cp->caddr;
+ tuple.src.u.all = cp->cport;
+ tuple.src.l3num = cp->af;
+ tuple.dst.u3 = cp->vaddr;
+ tuple.dst.u.all = cp->vport;
+
+ IP_VS_DBG(7, "%s: dropping conntrack with tuple=" FMT_TUPLE
+ " for conn " FMT_CONN "\n",
+ __func__, ARG_TUPLE(&tuple), ARG_CONN(cp));
+
+ h = nf_conntrack_find_get(&init_net, NF_CT_DEFAULT_ZONE, &tuple);
+ if (h) {
+ ct = nf_ct_tuplehash_to_ctrack(h);
+ /* Show what happens instead of calling nf_ct_kill() */
+ if (del_timer(&ct->timeout)) {
+ IP_VS_DBG(7, "%s: ct=%p, deleted conntrack timer for tuple="
+ FMT_TUPLE "\n",
+ __func__, ct, ARG_TUPLE(&tuple));
+ if (ct->timeout.function)
+ ct->timeout.function(ct->timeout.data);
+ } else {
+ IP_VS_DBG(7, "%s: ct=%p, no conntrack timer for tuple="
+ FMT_TUPLE "\n",
+ __func__, ct, ARG_TUPLE(&tuple));
+ }
+ nf_ct_put(ct);
+ } else {
+ IP_VS_DBG(7, "%s: no conntrack for tuple=" FMT_TUPLE "\n",
+ __func__, ARG_TUPLE(&tuple));
+ }
+}
+
diff --git a/net/netfilter/ipvs/ip_vs_pe.c b/net/netfilter/ipvs/ip_vs_pe.c
new file mode 100644
index 000000000000..3414af70ee12
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_pe.c
@@ -0,0 +1,147 @@
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <asm/string.h>
+#include <linux/kmod.h>
+#include <linux/sysctl.h>
+
+#include <net/ip_vs.h>
+
+/* IPVS pe list */
+static LIST_HEAD(ip_vs_pe);
+
+/* lock for service table */
+static DEFINE_SPINLOCK(ip_vs_pe_lock);
+
+/* Bind a service with a pe */
+void ip_vs_bind_pe(struct ip_vs_service *svc, struct ip_vs_pe *pe)
+{
+ svc->pe = pe;
+}
+
+/* Unbind a service from its pe */
+void ip_vs_unbind_pe(struct ip_vs_service *svc)
+{
+ svc->pe = NULL;
+}
+
+/* Get pe in the pe list by name */
+static struct ip_vs_pe *
+ip_vs_pe_getbyname(const char *pe_name)
+{
+ struct ip_vs_pe *pe;
+
+ IP_VS_DBG(2, "%s(): pe_name \"%s\"\n", __func__,
+ pe_name);
+
+ spin_lock_bh(&ip_vs_pe_lock);
+
+ list_for_each_entry(pe, &ip_vs_pe, n_list) {
+ /* Test and get the modules atomically */
+ if (pe->module &&
+ !try_module_get(pe->module)) {
+ /* This pe is just deleted */
+ continue;
+ }
+ if (strcmp(pe_name, pe->name)==0) {
+ /* HIT */
+ spin_unlock_bh(&ip_vs_pe_lock);
+ return pe;
+ }
+ if (pe->module)
+ module_put(pe->module);
+ }
+
+ spin_unlock_bh(&ip_vs_pe_lock);
+ return NULL;
+}
+
+/* Lookup pe and try to load it if it doesn't exist */
+struct ip_vs_pe *ip_vs_pe_get(const char *name)
+{
+ struct ip_vs_pe *pe;
+
+ /* Search for the pe by name */
+ pe = ip_vs_pe_getbyname(name);
+
+ /* If pe not found, load the module and search again */
+ if (!pe) {
+ request_module("ip_vs_pe_%s", name);
+ pe = ip_vs_pe_getbyname(name);
+ }
+
+ return pe;
+}
+
+void ip_vs_pe_put(struct ip_vs_pe *pe)
+{
+ if (pe && pe->module)
+ module_put(pe->module);
+}
+
+/* Register a pe in the pe list */
+int register_ip_vs_pe(struct ip_vs_pe *pe)
+{
+ struct ip_vs_pe *tmp;
+
+ /* increase the module use count */
+ ip_vs_use_count_inc();
+
+ spin_lock_bh(&ip_vs_pe_lock);
+
+ if (!list_empty(&pe->n_list)) {
+ spin_unlock_bh(&ip_vs_pe_lock);
+ ip_vs_use_count_dec();
+ pr_err("%s(): [%s] pe already linked\n",
+ __func__, pe->name);
+ return -EINVAL;
+ }
+
+ /* Make sure that the pe with this name doesn't exist
+ * in the pe list.
+ */
+ list_for_each_entry(tmp, &ip_vs_pe, n_list) {
+ if (strcmp(tmp->name, pe->name) == 0) {
+ spin_unlock_bh(&ip_vs_pe_lock);
+ ip_vs_use_count_dec();
+ pr_err("%s(): [%s] pe already existed "
+ "in the system\n", __func__, pe->name);
+ return -EINVAL;
+ }
+ }
+ /* Add it into the d-linked pe list */
+ list_add(&pe->n_list, &ip_vs_pe);
+ spin_unlock_bh(&ip_vs_pe_lock);
+
+ pr_info("[%s] pe registered.\n", pe->name);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(register_ip_vs_pe);
+
+/* Unregister a pe from the pe list */
+int unregister_ip_vs_pe(struct ip_vs_pe *pe)
+{
+ spin_lock_bh(&ip_vs_pe_lock);
+ if (list_empty(&pe->n_list)) {
+ spin_unlock_bh(&ip_vs_pe_lock);
+ pr_err("%s(): [%s] pe is not in the list. failed\n",
+ __func__, pe->name);
+ return -EINVAL;
+ }
+
+ /* Remove it from the d-linked pe list */
+ list_del(&pe->n_list);
+ spin_unlock_bh(&ip_vs_pe_lock);
+
+ /* decrease the module use count */
+ ip_vs_use_count_dec();
+
+ pr_info("[%s] pe unregistered.\n", pe->name);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(unregister_ip_vs_pe);
diff --git a/net/netfilter/ipvs/ip_vs_pe_sip.c b/net/netfilter/ipvs/ip_vs_pe_sip.c
new file mode 100644
index 000000000000..b8b4e9620f3e
--- /dev/null
+++ b/net/netfilter/ipvs/ip_vs_pe_sip.c
@@ -0,0 +1,169 @@
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <net/ip_vs.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <linux/netfilter/nf_conntrack_sip.h>
+
+#ifdef CONFIG_IP_VS_DEBUG
+static const char *ip_vs_dbg_callid(char *buf, size_t buf_len,
+ const char *callid, size_t callid_len,
+ int *idx)
+{
+ size_t len = min(min(callid_len, (size_t)64), buf_len - *idx - 1);
+ memcpy(buf + *idx, callid, len);
+ buf[*idx+len] = '\0';
+ *idx += len + 1;
+ return buf + *idx - len;
+}
+
+#define IP_VS_DEBUG_CALLID(callid, len) \
+ ip_vs_dbg_callid(ip_vs_dbg_buf, sizeof(ip_vs_dbg_buf), \
+ callid, len, &ip_vs_dbg_idx)
+#endif
+
+static int get_callid(const char *dptr, unsigned int dataoff,
+ unsigned int datalen,
+ unsigned int *matchoff, unsigned int *matchlen)
+{
+ /* Find callid */
+ while (1) {
+ int ret = ct_sip_get_header(NULL, dptr, dataoff, datalen,
+ SIP_HDR_CALL_ID, matchoff,
+ matchlen);
+ if (ret > 0)
+ break;
+ if (!ret)
+ return 0;
+ dataoff += *matchoff;
+ }
+
+ /* Empty callid is useless */
+ if (!*matchlen)
+ return -EINVAL;
+
+ /* Too large is useless */
+ if (*matchlen > IP_VS_PEDATA_MAXLEN)
+ return -EINVAL;
+
+ /* SIP headers are always followed by a line terminator */
+ if (*matchoff + *matchlen == datalen)
+ return -EINVAL;
+
+ /* RFC 2543 allows lines to be terminated with CR, LF or CRLF,
+ * RFC 3261 allows only CRLF, we support both. */
+ if (*(dptr + *matchoff + *matchlen) != '\r' &&
+ *(dptr + *matchoff + *matchlen) != '\n')
+ return -EINVAL;
+
+ IP_VS_DBG_BUF(9, "SIP callid %s (%d bytes)\n",
+ IP_VS_DEBUG_CALLID(dptr + *matchoff, *matchlen),
+ *matchlen);
+ return 0;
+}
+
+static int
+ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
+{
+ struct ip_vs_iphdr iph;
+ unsigned int dataoff, datalen, matchoff, matchlen;
+ const char *dptr;
+
+ ip_vs_fill_iphdr(p->af, skb_network_header(skb), &iph);
+
+ /* Only useful with UDP */
+ if (iph.protocol != IPPROTO_UDP)
+ return -EINVAL;
+
+ /* No Data ? */
+ dataoff = iph.len + sizeof(struct udphdr);
+ if (dataoff >= skb->len)
+ return -EINVAL;
+
+ dptr = skb->data + dataoff;
+ datalen = skb->len - dataoff;
+
+ if (get_callid(dptr, dataoff, datalen, &matchoff, &matchlen))
+ return -EINVAL;
+
+ p->pe_data = kmalloc(matchlen, GFP_ATOMIC);
+ if (!p->pe_data)
+ return -ENOMEM;
+
+ /* N.B: pe_data is only set on success,
+ * this allows fallback to the default persistence logic on failure
+ */
+ memcpy(p->pe_data, dptr + matchoff, matchlen);
+ p->pe_data_len = matchlen;
+
+ return 0;
+}
+
+static bool ip_vs_sip_ct_match(const struct ip_vs_conn_param *p,
+ struct ip_vs_conn *ct)
+
+{
+ bool ret = 0;
+
+ if (ct->af == p->af &&
+ ip_vs_addr_equal(p->af, p->caddr, &ct->caddr) &&
+ /* protocol should only be IPPROTO_IP if
+ * d_addr is a fwmark */
+ ip_vs_addr_equal(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af,
+ p->vaddr, &ct->vaddr) &&
+ ct->vport == p->vport &&
+ ct->flags & IP_VS_CONN_F_TEMPLATE &&
+ ct->protocol == p->protocol &&
+ ct->pe_data && ct->pe_data_len == p->pe_data_len &&
+ !memcmp(ct->pe_data, p->pe_data, p->pe_data_len))
+ ret = 1;
+
+ IP_VS_DBG_BUF(9, "SIP template match %s %s->%s:%d %s\n",
+ ip_vs_proto_name(p->protocol),
+ IP_VS_DEBUG_CALLID(p->pe_data, p->pe_data_len),
+ IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
+ ret ? "hit" : "not hit");
+
+ return ret;
+}
+
+static u32 ip_vs_sip_hashkey_raw(const struct ip_vs_conn_param *p,
+ u32 initval, bool inverse)
+{
+ return jhash(p->pe_data, p->pe_data_len, initval);
+}
+
+static int ip_vs_sip_show_pe_data(const struct ip_vs_conn *cp, char *buf)
+{
+ memcpy(buf, cp->pe_data, cp->pe_data_len);
+ return cp->pe_data_len;
+}
+
+static struct ip_vs_pe ip_vs_sip_pe =
+{
+ .name = "sip",
+ .refcnt = ATOMIC_INIT(0),
+ .module = THIS_MODULE,
+ .n_list = LIST_HEAD_INIT(ip_vs_sip_pe.n_list),
+ .fill_param = ip_vs_sip_fill_param,
+ .ct_match = ip_vs_sip_ct_match,
+ .hashkey_raw = ip_vs_sip_hashkey_raw,
+ .show_pe_data = ip_vs_sip_show_pe_data,
+};
+
+static int __init ip_vs_sip_init(void)
+{
+ return register_ip_vs_pe(&ip_vs_sip_pe);
+}
+
+static void __exit ip_vs_sip_cleanup(void)
+{
+ unregister_ip_vs_pe(&ip_vs_sip_pe);
+}
+
+module_init(ip_vs_sip_init);
+module_exit(ip_vs_sip_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c
index 027f654799fe..c53998390877 100644
--- a/net/netfilter/ipvs/ip_vs_proto.c
+++ b/net/netfilter/ipvs/ip_vs_proto.c
@@ -172,8 +172,8 @@ ip_vs_tcpudp_debug_packet_v4(struct ip_vs_protocol *pp,
else if (ih->frag_off & htons(IP_OFFSET))
sprintf(buf, "%pI4->%pI4 frag", &ih->saddr, &ih->daddr);
else {
- __be16 _ports[2], *pptr
-;
+ __be16 _ports[2], *pptr;
+
pptr = skb_header_pointer(skb, offset + ih->ihl*4,
sizeof(_ports), _ports);
if (pptr == NULL)
@@ -223,13 +223,13 @@ ip_vs_tcpudp_debug_packet_v6(struct ip_vs_protocol *pp,
void
-ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp,
+ip_vs_tcpudp_debug_packet(int af, struct ip_vs_protocol *pp,
const struct sk_buff *skb,
int offset,
const char *msg)
{
#ifdef CONFIG_IP_VS_IPV6
- if (skb->protocol == htons(ETH_P_IPV6))
+ if (af == AF_INET6)
ip_vs_tcpudp_debug_packet_v6(pp, skb, offset, msg);
else
#endif
diff --git a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
index 1892dfc12fdd..3a0461117d3f 100644
--- a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
@@ -40,6 +40,19 @@ struct isakmp_hdr {
#define PORT_ISAKMP 500
+static void
+ah_esp_conn_fill_param_proto(int af, const struct ip_vs_iphdr *iph,
+ int inverse, struct ip_vs_conn_param *p)
+{
+ if (likely(!inverse))
+ ip_vs_conn_fill_param(af, IPPROTO_UDP,
+ &iph->saddr, htons(PORT_ISAKMP),
+ &iph->daddr, htons(PORT_ISAKMP), p);
+ else
+ ip_vs_conn_fill_param(af, IPPROTO_UDP,
+ &iph->daddr, htons(PORT_ISAKMP),
+ &iph->saddr, htons(PORT_ISAKMP), p);
+}
static struct ip_vs_conn *
ah_esp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
@@ -47,21 +60,10 @@ ah_esp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
int inverse)
{
struct ip_vs_conn *cp;
+ struct ip_vs_conn_param p;
- if (likely(!inverse)) {
- cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
- &iph->saddr,
- htons(PORT_ISAKMP),
- &iph->daddr,
- htons(PORT_ISAKMP));
- } else {
- cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
- &iph->daddr,
- htons(PORT_ISAKMP),
- &iph->saddr,
- htons(PORT_ISAKMP));
- }
-
+ ah_esp_conn_fill_param_proto(af, iph, inverse, &p);
+ cp = ip_vs_conn_in_get(&p);
if (!cp) {
/*
* We are not sure if the packet is from our
@@ -87,21 +89,10 @@ ah_esp_conn_out_get(int af, const struct sk_buff *skb,
int inverse)
{
struct ip_vs_conn *cp;
+ struct ip_vs_conn_param p;
- if (likely(!inverse)) {
- cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
- &iph->saddr,
- htons(PORT_ISAKMP),
- &iph->daddr,
- htons(PORT_ISAKMP));
- } else {
- cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
- &iph->daddr,
- htons(PORT_ISAKMP),
- &iph->saddr,
- htons(PORT_ISAKMP));
- }
-
+ ah_esp_conn_fill_param_proto(af, iph, inverse, &p);
+ cp = ip_vs_conn_out_get(&p);
if (!cp) {
IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for inout packet "
"%s%s %s->%s\n",
@@ -126,54 +117,6 @@ ah_esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
return 0;
}
-
-static void
-ah_esp_debug_packet_v4(struct ip_vs_protocol *pp, const struct sk_buff *skb,
- int offset, const char *msg)
-{
- char buf[256];
- struct iphdr _iph, *ih;
-
- ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
- if (ih == NULL)
- sprintf(buf, "TRUNCATED");
- else
- sprintf(buf, "%pI4->%pI4", &ih->saddr, &ih->daddr);
-
- pr_debug("%s: %s %s\n", msg, pp->name, buf);
-}
-
-#ifdef CONFIG_IP_VS_IPV6
-static void
-ah_esp_debug_packet_v6(struct ip_vs_protocol *pp, const struct sk_buff *skb,
- int offset, const char *msg)
-{
- char buf[256];
- struct ipv6hdr _iph, *ih;
-
- ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
- if (ih == NULL)
- sprintf(buf, "TRUNCATED");
- else
- sprintf(buf, "%pI6->%pI6", &ih->saddr, &ih->daddr);
-
- pr_debug("%s: %s %s\n", msg, pp->name, buf);
-}
-#endif
-
-static void
-ah_esp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb,
- int offset, const char *msg)
-{
-#ifdef CONFIG_IP_VS_IPV6
- if (skb->protocol == htons(ETH_P_IPV6))
- ah_esp_debug_packet_v6(pp, skb, offset, msg);
- else
-#endif
- ah_esp_debug_packet_v4(pp, skb, offset, msg);
-}
-
-
static void ah_esp_init(struct ip_vs_protocol *pp)
{
/* nothing to do now */
@@ -204,7 +147,7 @@ struct ip_vs_protocol ip_vs_protocol_ah = {
.register_app = NULL,
.unregister_app = NULL,
.app_conn_bind = NULL,
- .debug_packet = ah_esp_debug_packet,
+ .debug_packet = ip_vs_tcpudp_debug_packet,
.timeout_change = NULL, /* ISAKMP */
.set_state_timeout = NULL,
};
@@ -228,7 +171,7 @@ struct ip_vs_protocol ip_vs_protocol_esp = {
.register_app = NULL,
.unregister_app = NULL,
.app_conn_bind = NULL,
- .debug_packet = ah_esp_debug_packet,
+ .debug_packet = ip_vs_tcpudp_debug_packet,
.timeout_change = NULL, /* ISAKMP */
};
#endif
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
index 4c0855cb006e..1ea96bcd342b 100644
--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
@@ -31,6 +31,8 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
if ((sch->type == SCTP_CID_INIT) &&
(svc = ip_vs_service_get(af, skb->mark, iph.protocol,
&iph.daddr, sh->dest))) {
+ int ignored;
+
if (ip_vs_todrop()) {
/*
* It seems that we are very loaded.
@@ -44,8 +46,8 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
* Let the virtual server select a real server for the
* incoming connection, and create a connection entry.
*/
- *cpp = ip_vs_schedule(svc, skb);
- if (!*cpp) {
+ *cpp = ip_vs_schedule(svc, skb, pp, &ignored);
+ if (!*cpp && !ignored) {
*verdict = ip_vs_leave(svc, skb, pp);
return 0;
}
@@ -61,6 +63,7 @@ sctp_snat_handler(struct sk_buff *skb,
{
sctp_sctphdr_t *sctph;
unsigned int sctphoff;
+ struct sk_buff *iter;
__be32 crc32;
#ifdef CONFIG_IP_VS_IPV6
@@ -89,8 +92,8 @@ sctp_snat_handler(struct sk_buff *skb,
/* Calculate the checksum */
crc32 = sctp_start_cksum((u8 *) sctph, skb_headlen(skb) - sctphoff);
- for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next)
- crc32 = sctp_update_cksum((u8 *) skb->data, skb_headlen(skb),
+ skb_walk_frags(skb, iter)
+ crc32 = sctp_update_cksum((u8 *) iter->data, skb_headlen(iter),
crc32);
crc32 = sctp_end_cksum(crc32);
sctph->checksum = crc32;
@@ -102,9 +105,9 @@ static int
sctp_dnat_handler(struct sk_buff *skb,
struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
{
-
sctp_sctphdr_t *sctph;
unsigned int sctphoff;
+ struct sk_buff *iter;
__be32 crc32;
#ifdef CONFIG_IP_VS_IPV6
@@ -133,8 +136,8 @@ sctp_dnat_handler(struct sk_buff *skb,
/* Calculate the checksum */
crc32 = sctp_start_cksum((u8 *) sctph, skb_headlen(skb) - sctphoff);
- for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next)
- crc32 = sctp_update_cksum((u8 *) skb->data, skb_headlen(skb),
+ skb_walk_frags(skb, iter)
+ crc32 = sctp_update_cksum((u8 *) iter->data, skb_headlen(iter),
crc32);
crc32 = sctp_end_cksum(crc32);
sctph->checksum = crc32;
@@ -145,9 +148,9 @@ sctp_dnat_handler(struct sk_buff *skb,
static int
sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
{
- struct sk_buff *list = skb_shinfo(skb)->frag_list;
unsigned int sctphoff;
struct sctphdr *sh, _sctph;
+ struct sk_buff *iter;
__le32 cmp;
__le32 val;
__u32 tmp;
@@ -166,15 +169,15 @@ sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
cmp = sh->checksum;
tmp = sctp_start_cksum((__u8 *) sh, skb_headlen(skb));
- for (; list; list = list->next)
- tmp = sctp_update_cksum((__u8 *) list->data,
- skb_headlen(list), tmp);
+ skb_walk_frags(skb, iter)
+ tmp = sctp_update_cksum((__u8 *) iter->data,
+ skb_headlen(iter), tmp);
val = sctp_end_cksum(tmp);
if (val != cmp) {
/* CRC failure, dump it. */
- IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+ IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
"Failed checksum for");
return 0;
}
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
index 282d24de8592..f6c5200e2146 100644
--- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
@@ -43,9 +43,12 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
return 0;
}
+ /* No !th->ack check to allow scheduling on SYN+ACK for Active FTP */
if (th->syn &&
(svc = ip_vs_service_get(af, skb->mark, iph.protocol, &iph.daddr,
th->dest))) {
+ int ignored;
+
if (ip_vs_todrop()) {
/*
* It seems that we are very loaded.
@@ -60,8 +63,8 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
* Let the virtual server select a real server for the
* incoming connection, and create a connection entry.
*/
- *cpp = ip_vs_schedule(svc, skb);
- if (!*cpp) {
+ *cpp = ip_vs_schedule(svc, skb, pp, &ignored);
+ if (!*cpp && !ignored) {
*verdict = ip_vs_leave(svc, skb, pp);
return 0;
}
@@ -101,15 +104,15 @@ tcp_partial_csum_update(int af, struct tcphdr *tcph,
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6)
tcph->check =
- csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
+ ~csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
ip_vs_check_diff2(oldlen, newlen,
- ~csum_unfold(tcph->check))));
+ csum_unfold(tcph->check))));
else
#endif
tcph->check =
- csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
+ ~csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
ip_vs_check_diff2(oldlen, newlen,
- ~csum_unfold(tcph->check))));
+ csum_unfold(tcph->check))));
}
@@ -120,6 +123,7 @@ tcp_snat_handler(struct sk_buff *skb,
struct tcphdr *tcph;
unsigned int tcphoff;
int oldlen;
+ int payload_csum = 0;
#ifdef CONFIG_IP_VS_IPV6
if (cp->af == AF_INET6)
@@ -134,13 +138,20 @@ tcp_snat_handler(struct sk_buff *skb,
return 0;
if (unlikely(cp->app != NULL)) {
+ int ret;
+
/* Some checks before mangling */
if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
return 0;
/* Call application helper if needed */
- if (!ip_vs_app_pkt_out(cp, skb))
+ if (!(ret = ip_vs_app_pkt_out(cp, skb)))
return 0;
+ /* ret=2: csum update is needed after payload mangling */
+ if (ret == 1)
+ oldlen = skb->len - tcphoff;
+ else
+ payload_csum = 1;
}
tcph = (void *)skb_network_header(skb) + tcphoff;
@@ -151,12 +162,13 @@ tcp_snat_handler(struct sk_buff *skb,
tcp_partial_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr,
htons(oldlen),
htons(skb->len - tcphoff));
- } else if (!cp->app) {
+ } else if (!payload_csum) {
/* Only port and addr are changed, do fast csum update */
tcp_fast_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr,
cp->dport, cp->vport);
if (skb->ip_summed == CHECKSUM_COMPLETE)
- skb->ip_summed = CHECKSUM_NONE;
+ skb->ip_summed = (cp->app && pp->csum_check) ?
+ CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
} else {
/* full checksum calculation */
tcph->check = 0;
@@ -174,6 +186,7 @@ tcp_snat_handler(struct sk_buff *skb,
skb->len - tcphoff,
cp->protocol,
skb->csum);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
pp->name, tcph->check,
@@ -190,6 +203,7 @@ tcp_dnat_handler(struct sk_buff *skb,
struct tcphdr *tcph;
unsigned int tcphoff;
int oldlen;
+ int payload_csum = 0;
#ifdef CONFIG_IP_VS_IPV6
if (cp->af == AF_INET6)
@@ -204,6 +218,8 @@ tcp_dnat_handler(struct sk_buff *skb,
return 0;
if (unlikely(cp->app != NULL)) {
+ int ret;
+
/* Some checks before mangling */
if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
return 0;
@@ -212,8 +228,13 @@ tcp_dnat_handler(struct sk_buff *skb,
* Attempt ip_vs_app call.
* It will fix ip_vs_conn and iph ack_seq stuff
*/
- if (!ip_vs_app_pkt_in(cp, skb))
+ if (!(ret = ip_vs_app_pkt_in(cp, skb)))
return 0;
+ /* ret=2: csum update is needed after payload mangling */
+ if (ret == 1)
+ oldlen = skb->len - tcphoff;
+ else
+ payload_csum = 1;
}
tcph = (void *)skb_network_header(skb) + tcphoff;
@@ -223,15 +244,16 @@ tcp_dnat_handler(struct sk_buff *skb,
* Adjust TCP checksums
*/
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- tcp_partial_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr,
+ tcp_partial_csum_update(cp->af, tcph, &cp->vaddr, &cp->daddr,
htons(oldlen),
htons(skb->len - tcphoff));
- } else if (!cp->app) {
+ } else if (!payload_csum) {
/* Only port and addr are changed, do fast csum update */
tcp_fast_csum_update(cp->af, tcph, &cp->vaddr, &cp->daddr,
cp->vport, cp->dport);
if (skb->ip_summed == CHECKSUM_COMPLETE)
- skb->ip_summed = CHECKSUM_NONE;
+ skb->ip_summed = (cp->app && pp->csum_check) ?
+ CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
} else {
/* full checksum calculation */
tcph->check = 0;
@@ -278,7 +300,7 @@ tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
skb->len - tcphoff,
ipv6_hdr(skb)->nexthdr,
skb->csum)) {
- IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+ IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
"Failed checksum for");
return 0;
}
@@ -289,7 +311,7 @@ tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
skb->len - tcphoff,
ip_hdr(skb)->protocol,
skb->csum)) {
- IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+ IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
"Failed checksum for");
return 0;
}
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
index 8553231b5d41..9d106a06bb0a 100644
--- a/net/netfilter/ipvs/ip_vs_proto_udp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
@@ -46,6 +46,8 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
svc = ip_vs_service_get(af, skb->mark, iph.protocol,
&iph.daddr, uh->dest);
if (svc) {
+ int ignored;
+
if (ip_vs_todrop()) {
/*
* It seems that we are very loaded.
@@ -60,8 +62,8 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
* Let the virtual server select a real server for the
* incoming connection, and create a connection entry.
*/
- *cpp = ip_vs_schedule(svc, skb);
- if (!*cpp) {
+ *cpp = ip_vs_schedule(svc, skb, pp, &ignored);
+ if (!*cpp && !ignored) {
*verdict = ip_vs_leave(svc, skb, pp);
return 0;
}
@@ -102,15 +104,15 @@ udp_partial_csum_update(int af, struct udphdr *uhdr,
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6)
uhdr->check =
- csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
+ ~csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
ip_vs_check_diff2(oldlen, newlen,
- ~csum_unfold(uhdr->check))));
+ csum_unfold(uhdr->check))));
else
#endif
uhdr->check =
- csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
+ ~csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
ip_vs_check_diff2(oldlen, newlen,
- ~csum_unfold(uhdr->check))));
+ csum_unfold(uhdr->check))));
}
@@ -121,6 +123,7 @@ udp_snat_handler(struct sk_buff *skb,
struct udphdr *udph;
unsigned int udphoff;
int oldlen;
+ int payload_csum = 0;
#ifdef CONFIG_IP_VS_IPV6
if (cp->af == AF_INET6)
@@ -135,6 +138,8 @@ udp_snat_handler(struct sk_buff *skb,
return 0;
if (unlikely(cp->app != NULL)) {
+ int ret;
+
/* Some checks before mangling */
if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
return 0;
@@ -142,8 +147,13 @@ udp_snat_handler(struct sk_buff *skb,
/*
* Call application helper if needed
*/
- if (!ip_vs_app_pkt_out(cp, skb))
+ if (!(ret = ip_vs_app_pkt_out(cp, skb)))
return 0;
+ /* ret=2: csum update is needed after payload mangling */
+ if (ret == 1)
+ oldlen = skb->len - udphoff;
+ else
+ payload_csum = 1;
}
udph = (void *)skb_network_header(skb) + udphoff;
@@ -156,12 +166,13 @@ udp_snat_handler(struct sk_buff *skb,
udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
htons(oldlen),
htons(skb->len - udphoff));
- } else if (!cp->app && (udph->check != 0)) {
+ } else if (!payload_csum && (udph->check != 0)) {
/* Only port and addr are changed, do fast csum update */
udp_fast_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
cp->dport, cp->vport);
if (skb->ip_summed == CHECKSUM_COMPLETE)
- skb->ip_summed = CHECKSUM_NONE;
+ skb->ip_summed = (cp->app && pp->csum_check) ?
+ CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
} else {
/* full checksum calculation */
udph->check = 0;
@@ -181,6 +192,7 @@ udp_snat_handler(struct sk_buff *skb,
skb->csum);
if (udph->check == 0)
udph->check = CSUM_MANGLED_0;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
pp->name, udph->check,
(char*)&(udph->check) - (char*)udph);
@@ -196,6 +208,7 @@ udp_dnat_handler(struct sk_buff *skb,
struct udphdr *udph;
unsigned int udphoff;
int oldlen;
+ int payload_csum = 0;
#ifdef CONFIG_IP_VS_IPV6
if (cp->af == AF_INET6)
@@ -210,6 +223,8 @@ udp_dnat_handler(struct sk_buff *skb,
return 0;
if (unlikely(cp->app != NULL)) {
+ int ret;
+
/* Some checks before mangling */
if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
return 0;
@@ -218,8 +233,13 @@ udp_dnat_handler(struct sk_buff *skb,
* Attempt ip_vs_app call.
* It will fix ip_vs_conn
*/
- if (!ip_vs_app_pkt_in(cp, skb))
+ if (!(ret = ip_vs_app_pkt_in(cp, skb)))
return 0;
+ /* ret=2: csum update is needed after payload mangling */
+ if (ret == 1)
+ oldlen = skb->len - udphoff;
+ else
+ payload_csum = 1;
}
udph = (void *)skb_network_header(skb) + udphoff;
@@ -229,15 +249,16 @@ udp_dnat_handler(struct sk_buff *skb,
* Adjust UDP checksums
*/
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
+ udp_partial_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr,
htons(oldlen),
htons(skb->len - udphoff));
- } else if (!cp->app && (udph->check != 0)) {
+ } else if (!payload_csum && (udph->check != 0)) {
/* Only port and addr are changed, do fast csum update */
udp_fast_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr,
cp->vport, cp->dport);
if (skb->ip_summed == CHECKSUM_COMPLETE)
- skb->ip_summed = CHECKSUM_NONE;
+ skb->ip_summed = (cp->app && pp->csum_check) ?
+ CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
} else {
/* full checksum calculation */
udph->check = 0;
@@ -293,7 +314,7 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
skb->len - udphoff,
ipv6_hdr(skb)->nexthdr,
skb->csum)) {
- IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+ IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
"Failed checksum for");
return 0;
}
@@ -304,7 +325,7 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
skb->len - udphoff,
ip_hdr(skb)->protocol,
skb->csum)) {
- IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+ IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
"Failed checksum for");
return 0;
}
diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c
index bbc1ac795952..076ebe00435d 100644
--- a/net/netfilter/ipvs/ip_vs_sched.c
+++ b/net/netfilter/ipvs/ip_vs_sched.c
@@ -35,7 +35,7 @@
static LIST_HEAD(ip_vs_schedulers);
/* lock for service table */
-static DEFINE_RWLOCK(__ip_vs_sched_lock);
+static DEFINE_SPINLOCK(ip_vs_sched_lock);
/*
@@ -46,15 +46,6 @@ int ip_vs_bind_scheduler(struct ip_vs_service *svc,
{
int ret;
- if (svc == NULL) {
- pr_err("%s(): svc arg NULL\n", __func__);
- return -EINVAL;
- }
- if (scheduler == NULL) {
- pr_err("%s(): scheduler arg NULL\n", __func__);
- return -EINVAL;
- }
-
svc->scheduler = scheduler;
if (scheduler->init_service) {
@@ -74,18 +65,10 @@ int ip_vs_bind_scheduler(struct ip_vs_service *svc,
*/
int ip_vs_unbind_scheduler(struct ip_vs_service *svc)
{
- struct ip_vs_scheduler *sched;
+ struct ip_vs_scheduler *sched = svc->scheduler;
- if (svc == NULL) {
- pr_err("%s(): svc arg NULL\n", __func__);
- return -EINVAL;
- }
-
- sched = svc->scheduler;
- if (sched == NULL) {
- pr_err("%s(): svc isn't bound\n", __func__);
- return -EINVAL;
- }
+ if (!sched)
+ return 0;
if (sched->done_service) {
if (sched->done_service(svc) != 0) {
@@ -108,7 +91,7 @@ static struct ip_vs_scheduler *ip_vs_sched_getbyname(const char *sched_name)
IP_VS_DBG(2, "%s(): sched_name \"%s\"\n", __func__, sched_name);
- read_lock_bh(&__ip_vs_sched_lock);
+ spin_lock_bh(&ip_vs_sched_lock);
list_for_each_entry(sched, &ip_vs_schedulers, n_list) {
/*
@@ -122,14 +105,14 @@ static struct ip_vs_scheduler *ip_vs_sched_getbyname(const char *sched_name)
}
if (strcmp(sched_name, sched->name)==0) {
/* HIT */
- read_unlock_bh(&__ip_vs_sched_lock);
+ spin_unlock_bh(&ip_vs_sched_lock);
return sched;
}
if (sched->module)
module_put(sched->module);
}
- read_unlock_bh(&__ip_vs_sched_lock);
+ spin_unlock_bh(&ip_vs_sched_lock);
return NULL;
}
@@ -159,7 +142,7 @@ struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name)
void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler)
{
- if (scheduler->module)
+ if (scheduler && scheduler->module)
module_put(scheduler->module);
}
@@ -184,10 +167,10 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
/* increase the module use count */
ip_vs_use_count_inc();
- write_lock_bh(&__ip_vs_sched_lock);
+ spin_lock_bh(&ip_vs_sched_lock);
if (!list_empty(&scheduler->n_list)) {
- write_unlock_bh(&__ip_vs_sched_lock);
+ spin_unlock_bh(&ip_vs_sched_lock);
ip_vs_use_count_dec();
pr_err("%s(): [%s] scheduler already linked\n",
__func__, scheduler->name);
@@ -200,7 +183,7 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
*/
list_for_each_entry(sched, &ip_vs_schedulers, n_list) {
if (strcmp(scheduler->name, sched->name) == 0) {
- write_unlock_bh(&__ip_vs_sched_lock);
+ spin_unlock_bh(&ip_vs_sched_lock);
ip_vs_use_count_dec();
pr_err("%s(): [%s] scheduler already existed "
"in the system\n", __func__, scheduler->name);
@@ -211,7 +194,7 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
* Add it into the d-linked scheduler list
*/
list_add(&scheduler->n_list, &ip_vs_schedulers);
- write_unlock_bh(&__ip_vs_sched_lock);
+ spin_unlock_bh(&ip_vs_sched_lock);
pr_info("[%s] scheduler registered.\n", scheduler->name);
@@ -229,9 +212,9 @@ int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
return -EINVAL;
}
- write_lock_bh(&__ip_vs_sched_lock);
+ spin_lock_bh(&ip_vs_sched_lock);
if (list_empty(&scheduler->n_list)) {
- write_unlock_bh(&__ip_vs_sched_lock);
+ spin_unlock_bh(&ip_vs_sched_lock);
pr_err("%s(): [%s] scheduler is not in the list. failed\n",
__func__, scheduler->name);
return -EINVAL;
@@ -241,7 +224,7 @@ int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
* Remove it from the d-linked scheduler list
*/
list_del(&scheduler->n_list);
- write_unlock_bh(&__ip_vs_sched_lock);
+ spin_unlock_bh(&ip_vs_sched_lock);
/* decrease the module use count */
ip_vs_use_count_dec();
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index 7ba06939829f..ab85aedea17e 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -288,6 +288,16 @@ void ip_vs_sync_conn(struct ip_vs_conn *cp)
ip_vs_sync_conn(cp->control);
}
+static inline int
+ip_vs_conn_fill_param_sync(int af, int protocol,
+ const union nf_inet_addr *caddr, __be16 cport,
+ const union nf_inet_addr *vaddr, __be16 vport,
+ struct ip_vs_conn_param *p)
+{
+ /* XXX: Need to take into account persistence engine */
+ ip_vs_conn_fill_param(af, protocol, caddr, cport, vaddr, vport, p);
+ return 0;
+}
/*
* Process received multicast message and create the corresponding
@@ -301,6 +311,7 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
struct ip_vs_conn *cp;
struct ip_vs_protocol *pp;
struct ip_vs_dest *dest;
+ struct ip_vs_conn_param param;
char *p;
int i;
@@ -370,18 +381,20 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
}
}
- if (!(flags & IP_VS_CONN_F_TEMPLATE))
- cp = ip_vs_conn_in_get(AF_INET, s->protocol,
- (union nf_inet_addr *)&s->caddr,
- s->cport,
- (union nf_inet_addr *)&s->vaddr,
- s->vport);
- else
- cp = ip_vs_ct_in_get(AF_INET, s->protocol,
- (union nf_inet_addr *)&s->caddr,
- s->cport,
- (union nf_inet_addr *)&s->vaddr,
- s->vport);
+ {
+ if (ip_vs_conn_fill_param_sync(AF_INET, s->protocol,
+ (union nf_inet_addr *)&s->caddr,
+ s->cport,
+ (union nf_inet_addr *)&s->vaddr,
+ s->vport, &param)) {
+ pr_err("ip_vs_conn_fill_param_sync failed");
+ return;
+ }
+ if (!(flags & IP_VS_CONN_F_TEMPLATE))
+ cp = ip_vs_conn_in_get(&param);
+ else
+ cp = ip_vs_ct_in_get(&param);
+ }
if (!cp) {
/*
* Find the appropriate destination for the connection.
@@ -406,14 +419,9 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
else
flags &= ~IP_VS_CONN_F_INACTIVE;
}
- cp = ip_vs_conn_new(AF_INET, s->protocol,
- (union nf_inet_addr *)&s->caddr,
- s->cport,
- (union nf_inet_addr *)&s->vaddr,
- s->vport,
+ cp = ip_vs_conn_new(&param,
(union nf_inet_addr *)&s->daddr,
- s->dport,
- flags, dest);
+ s->dport, flags, dest);
if (dest)
atomic_dec(&dest->refcnt);
if (!cp) {
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 49df6bea6a2d..de04ea39cde8 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -11,6 +11,16 @@
*
* Changes:
*
+ * Description of forwarding methods:
+ * - all transmitters are called from LOCAL_IN (remote clients) and
+ * LOCAL_OUT (local clients) but for ICMP can be called from FORWARD
+ * - not all connections have destination server, for example,
+ * connections in backup server when fwmark is used
+ * - bypass connections use daddr from packet
+ * LOCAL_OUT rules:
+ * - skb->dev is NULL, skb->protocol is not set (both are set in POST_ROUTING)
+ * - skb->pkt_type is not set yet
+ * - the only place where we can see skb->sk != NULL
*/
#define KMSG_COMPONENT "IPVS"
@@ -26,9 +36,9 @@
#include <net/route.h> /* for ip_route_output */
#include <net/ipv6.h>
#include <net/ip6_route.h>
+#include <net/addrconf.h>
#include <linux/icmpv6.h>
#include <linux/netfilter.h>
-#include <net/netfilter/nf_conntrack.h>
#include <linux/netfilter_ipv4.h>
#include <net/ip_vs.h>
@@ -38,26 +48,27 @@
* Destination cache to speed up outgoing route lookup
*/
static inline void
-__ip_vs_dst_set(struct ip_vs_dest *dest, u32 rtos, struct dst_entry *dst)
+__ip_vs_dst_set(struct ip_vs_dest *dest, u32 rtos, struct dst_entry *dst,
+ u32 dst_cookie)
{
struct dst_entry *old_dst;
old_dst = dest->dst_cache;
dest->dst_cache = dst;
dest->dst_rtos = rtos;
+ dest->dst_cookie = dst_cookie;
dst_release(old_dst);
}
static inline struct dst_entry *
-__ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos, u32 cookie)
+__ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos)
{
struct dst_entry *dst = dest->dst_cache;
if (!dst)
return NULL;
- if ((dst->obsolete
- || (dest->af == AF_INET && rtos != dest->dst_rtos)) &&
- dst->ops->check(dst, cookie) == NULL) {
+ if ((dst->obsolete || rtos != dest->dst_rtos) &&
+ dst->ops->check(dst, dest->dst_cookie) == NULL) {
dest->dst_cache = NULL;
dst_release(dst);
return NULL;
@@ -66,16 +77,24 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos, u32 cookie)
return dst;
}
+/*
+ * Get route to destination or remote server
+ * rt_mode: flags, &1=Allow local dest, &2=Allow non-local dest,
+ * &4=Allow redirect from remote daddr to local
+ */
static struct rtable *
-__ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
+__ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest,
+ __be32 daddr, u32 rtos, int rt_mode)
{
+ struct net *net = dev_net(skb_dst(skb)->dev);
struct rtable *rt; /* Route to the other host */
- struct ip_vs_dest *dest = cp->dest;
+ struct rtable *ort; /* Original route */
+ int local;
if (dest) {
spin_lock(&dest->dst_lock);
if (!(rt = (struct rtable *)
- __ip_vs_dst_check(dest, rtos, 0))) {
+ __ip_vs_dst_check(dest, rtos))) {
struct flowi fl = {
.oif = 0,
.nl_u = {
@@ -85,13 +104,13 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
.tos = rtos, } },
};
- if (ip_route_output_key(&init_net, &rt, &fl)) {
+ if (ip_route_output_key(net, &rt, &fl)) {
spin_unlock(&dest->dst_lock);
IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n",
&dest->addr.ip);
return NULL;
}
- __ip_vs_dst_set(dest, rtos, dst_clone(&rt->dst));
+ __ip_vs_dst_set(dest, rtos, dst_clone(&rt->dst), 0);
IP_VS_DBG(10, "new dst %pI4, refcnt=%d, rtos=%X\n",
&dest->addr.ip,
atomic_read(&rt->dst.__refcnt), rtos);
@@ -102,78 +121,199 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
.oif = 0,
.nl_u = {
.ip4_u = {
- .daddr = cp->daddr.ip,
+ .daddr = daddr,
.saddr = 0,
.tos = rtos, } },
};
- if (ip_route_output_key(&init_net, &rt, &fl)) {
+ if (ip_route_output_key(net, &rt, &fl)) {
IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n",
- &cp->daddr.ip);
+ &daddr);
return NULL;
}
}
+ local = rt->rt_flags & RTCF_LOCAL;
+ if (!((local ? 1 : 2) & rt_mode)) {
+ IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI4\n",
+ (rt->rt_flags & RTCF_LOCAL) ?
+ "local":"non-local", &rt->rt_dst);
+ ip_rt_put(rt);
+ return NULL;
+ }
+ if (local && !(rt_mode & 4) && !((ort = skb_rtable(skb)) &&
+ ort->rt_flags & RTCF_LOCAL)) {
+ IP_VS_DBG_RL("Redirect from non-local address %pI4 to local "
+ "requires NAT method, dest: %pI4\n",
+ &ip_hdr(skb)->daddr, &rt->rt_dst);
+ ip_rt_put(rt);
+ return NULL;
+ }
+ if (unlikely(!local && ipv4_is_loopback(ip_hdr(skb)->saddr))) {
+ IP_VS_DBG_RL("Stopping traffic from loopback address %pI4 "
+ "to non-local address, dest: %pI4\n",
+ &ip_hdr(skb)->saddr, &rt->rt_dst);
+ ip_rt_put(rt);
+ return NULL;
+ }
+
return rt;
}
+/* Reroute packet to local IPv4 stack after DNAT */
+static int
+__ip_vs_reroute_locally(struct sk_buff *skb)
+{
+ struct rtable *rt = skb_rtable(skb);
+ struct net_device *dev = rt->dst.dev;
+ struct net *net = dev_net(dev);
+ struct iphdr *iph = ip_hdr(skb);
+
+ if (rt->fl.iif) {
+ unsigned long orefdst = skb->_skb_refdst;
+
+ if (ip_route_input(skb, iph->daddr, iph->saddr,
+ iph->tos, skb->dev))
+ return 0;
+ refdst_drop(orefdst);
+ } else {
+ struct flowi fl = {
+ .oif = 0,
+ .nl_u = {
+ .ip4_u = {
+ .daddr = iph->daddr,
+ .saddr = iph->saddr,
+ .tos = RT_TOS(iph->tos),
+ }
+ },
+ .mark = skb->mark,
+ };
+ struct rtable *rt;
+
+ if (ip_route_output_key(net, &rt, &fl))
+ return 0;
+ if (!(rt->rt_flags & RTCF_LOCAL)) {
+ ip_rt_put(rt);
+ return 0;
+ }
+ /* Drop old route. */
+ skb_dst_drop(skb);
+ skb_dst_set(skb, &rt->dst);
+ }
+ return 1;
+}
+
#ifdef CONFIG_IP_VS_IPV6
+
+static inline int __ip_vs_is_local_route6(struct rt6_info *rt)
+{
+ return rt->rt6i_dev && rt->rt6i_dev->flags & IFF_LOOPBACK;
+}
+
+static struct dst_entry *
+__ip_vs_route_output_v6(struct net *net, struct in6_addr *daddr,
+ struct in6_addr *ret_saddr, int do_xfrm)
+{
+ struct dst_entry *dst;
+ struct flowi fl = {
+ .oif = 0,
+ .nl_u = {
+ .ip6_u = {
+ .daddr = *daddr,
+ },
+ },
+ };
+
+ dst = ip6_route_output(net, NULL, &fl);
+ if (dst->error)
+ goto out_err;
+ if (!ret_saddr)
+ return dst;
+ if (ipv6_addr_any(&fl.fl6_src) &&
+ ipv6_dev_get_saddr(net, ip6_dst_idev(dst)->dev,
+ &fl.fl6_dst, 0, &fl.fl6_src) < 0)
+ goto out_err;
+ if (do_xfrm && xfrm_lookup(net, &dst, &fl, NULL, 0) < 0)
+ goto out_err;
+ ipv6_addr_copy(ret_saddr, &fl.fl6_src);
+ return dst;
+
+out_err:
+ dst_release(dst);
+ IP_VS_DBG_RL("ip6_route_output error, dest: %pI6\n", daddr);
+ return NULL;
+}
+
+/*
+ * Get route to destination or remote server
+ * rt_mode: flags, &1=Allow local dest, &2=Allow non-local dest,
+ * &4=Allow redirect from remote daddr to local
+ */
static struct rt6_info *
-__ip_vs_get_out_rt_v6(struct ip_vs_conn *cp)
+__ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,
+ struct in6_addr *daddr, struct in6_addr *ret_saddr,
+ int do_xfrm, int rt_mode)
{
+ struct net *net = dev_net(skb_dst(skb)->dev);
struct rt6_info *rt; /* Route to the other host */
- struct ip_vs_dest *dest = cp->dest;
+ struct rt6_info *ort; /* Original route */
+ struct dst_entry *dst;
+ int local;
if (dest) {
spin_lock(&dest->dst_lock);
- rt = (struct rt6_info *)__ip_vs_dst_check(dest, 0, 0);
+ rt = (struct rt6_info *)__ip_vs_dst_check(dest, 0);
if (!rt) {
- struct flowi fl = {
- .oif = 0,
- .nl_u = {
- .ip6_u = {
- .daddr = dest->addr.in6,
- .saddr = {
- .s6_addr32 =
- { 0, 0, 0, 0 },
- },
- },
- },
- };
+ u32 cookie;
- rt = (struct rt6_info *)ip6_route_output(&init_net,
- NULL, &fl);
- if (!rt) {
+ dst = __ip_vs_route_output_v6(net, &dest->addr.in6,
+ &dest->dst_saddr,
+ do_xfrm);
+ if (!dst) {
spin_unlock(&dest->dst_lock);
- IP_VS_DBG_RL("ip6_route_output error, dest: %pI6\n",
- &dest->addr.in6);
return NULL;
}
- __ip_vs_dst_set(dest, 0, dst_clone(&rt->dst));
- IP_VS_DBG(10, "new dst %pI6, refcnt=%d\n",
- &dest->addr.in6,
+ rt = (struct rt6_info *) dst;
+ cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
+ __ip_vs_dst_set(dest, 0, dst_clone(&rt->dst), cookie);
+ IP_VS_DBG(10, "new dst %pI6, src %pI6, refcnt=%d\n",
+ &dest->addr.in6, &dest->dst_saddr,
atomic_read(&rt->dst.__refcnt));
}
+ if (ret_saddr)
+ ipv6_addr_copy(ret_saddr, &dest->dst_saddr);
spin_unlock(&dest->dst_lock);
} else {
- struct flowi fl = {
- .oif = 0,
- .nl_u = {
- .ip6_u = {
- .daddr = cp->daddr.in6,
- .saddr = {
- .s6_addr32 = { 0, 0, 0, 0 },
- },
- },
- },
- };
-
- rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl);
- if (!rt) {
- IP_VS_DBG_RL("ip6_route_output error, dest: %pI6\n",
- &cp->daddr.in6);
+ dst = __ip_vs_route_output_v6(net, daddr, ret_saddr, do_xfrm);
+ if (!dst)
return NULL;
- }
+ rt = (struct rt6_info *) dst;
+ }
+
+ local = __ip_vs_is_local_route6(rt);
+ if (!((local ? 1 : 2) & rt_mode)) {
+ IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI6\n",
+ local ? "local":"non-local", daddr);
+ dst_release(&rt->dst);
+ return NULL;
+ }
+ if (local && !(rt_mode & 4) &&
+ !((ort = (struct rt6_info *) skb_dst(skb)) &&
+ __ip_vs_is_local_route6(ort))) {
+ IP_VS_DBG_RL("Redirect from non-local address %pI6 to local "
+ "requires NAT method, dest: %pI6\n",
+ &ipv6_hdr(skb)->daddr, daddr);
+ dst_release(&rt->dst);
+ return NULL;
+ }
+ if (unlikely(!local && (!skb->dev || skb->dev->flags & IFF_LOOPBACK) &&
+ ipv6_addr_type(&ipv6_hdr(skb)->saddr) &
+ IPV6_ADDR_LOOPBACK)) {
+ IP_VS_DBG_RL("Stopping traffic from loopback address %pI6 "
+ "to non-local address, dest: %pI6\n",
+ &ipv6_hdr(skb)->saddr, daddr);
+ dst_release(&rt->dst);
+ return NULL;
}
return rt;
@@ -194,12 +334,44 @@ ip_vs_dst_reset(struct ip_vs_dest *dest)
dst_release(old_dst);
}
-#define IP_VS_XMIT(pf, skb, rt) \
+#define IP_VS_XMIT_TUNNEL(skb, cp) \
+({ \
+ int __ret = NF_ACCEPT; \
+ \
+ (skb)->ipvs_property = 1; \
+ if (unlikely((cp)->flags & IP_VS_CONN_F_NFCT)) \
+ __ret = ip_vs_confirm_conntrack(skb, cp); \
+ if (__ret == NF_ACCEPT) { \
+ nf_reset(skb); \
+ skb_forward_csum(skb); \
+ } \
+ __ret; \
+})
+
+#define IP_VS_XMIT_NAT(pf, skb, cp, local) \
+do { \
+ (skb)->ipvs_property = 1; \
+ if (likely(!((cp)->flags & IP_VS_CONN_F_NFCT))) \
+ ip_vs_notrack(skb); \
+ else \
+ ip_vs_update_conntrack(skb, cp, 1); \
+ if (local) \
+ return NF_ACCEPT; \
+ skb_forward_csum(skb); \
+ NF_HOOK(pf, NF_INET_LOCAL_OUT, (skb), NULL, \
+ skb_dst(skb)->dev, dst_output); \
+} while (0)
+
+#define IP_VS_XMIT(pf, skb, cp, local) \
do { \
(skb)->ipvs_property = 1; \
+ if (likely(!((cp)->flags & IP_VS_CONN_F_NFCT))) \
+ ip_vs_notrack(skb); \
+ if (local) \
+ return NF_ACCEPT; \
skb_forward_csum(skb); \
NF_HOOK(pf, NF_INET_LOCAL_OUT, (skb), NULL, \
- (rt)->dst.dev, dst_output); \
+ skb_dst(skb)->dev, dst_output); \
} while (0)
@@ -211,7 +383,7 @@ ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp)
{
/* we do not touch skb and do not need pskb ptr */
- return NF_ACCEPT;
+ IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 1);
}
@@ -226,24 +398,13 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
{
struct rtable *rt; /* Route to the other host */
struct iphdr *iph = ip_hdr(skb);
- u8 tos = iph->tos;
int mtu;
- struct flowi fl = {
- .oif = 0,
- .nl_u = {
- .ip4_u = {
- .daddr = iph->daddr,
- .saddr = 0,
- .tos = RT_TOS(tos), } },
- };
EnterFunction(10);
- if (ip_route_output_key(&init_net, &rt, &fl)) {
- IP_VS_DBG_RL("%s(): ip_route_output error, dest: %pI4\n",
- __func__, &iph->daddr);
+ if (!(rt = __ip_vs_get_out_rt(skb, NULL, iph->daddr,
+ RT_TOS(iph->tos), 2)))
goto tx_error_icmp;
- }
/* MTU checking */
mtu = dst_mtu(&rt->dst);
@@ -271,7 +432,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT(NFPROTO_IPV4, skb, rt);
+ IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 0);
LeaveFunction(10);
return NF_STOLEN;
@@ -292,28 +453,22 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
struct rt6_info *rt; /* Route to the other host */
struct ipv6hdr *iph = ipv6_hdr(skb);
int mtu;
- struct flowi fl = {
- .oif = 0,
- .nl_u = {
- .ip6_u = {
- .daddr = iph->daddr,
- .saddr = { .s6_addr32 = {0, 0, 0, 0} }, } },
- };
EnterFunction(10);
- rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl);
- if (!rt) {
- IP_VS_DBG_RL("%s(): ip6_route_output error, dest: %pI6\n",
- __func__, &iph->daddr);
+ if (!(rt = __ip_vs_get_out_rt_v6(skb, NULL, &iph->daddr, NULL, 0, 2)))
goto tx_error_icmp;
- }
/* MTU checking */
mtu = dst_mtu(&rt->dst);
if (skb->len > mtu) {
- dst_release(&rt->dst);
+ if (!skb->dev) {
+ struct net *net = dev_net(skb_dst(skb)->dev);
+
+ skb->dev = net->loopback_dev;
+ }
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+ dst_release(&rt->dst);
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
goto tx_error;
}
@@ -335,7 +490,7 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT(NFPROTO_IPV6, skb, rt);
+ IP_VS_XMIT(NFPROTO_IPV6, skb, cp, 0);
LeaveFunction(10);
return NF_STOLEN;
@@ -349,36 +504,6 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
}
#endif
-void
-ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp, int outin)
-{
- struct nf_conn *ct = (struct nf_conn *)skb->nfct;
- struct nf_conntrack_tuple new_tuple;
-
- if (ct == NULL || nf_ct_is_untracked(ct) || nf_ct_is_confirmed(ct))
- return;
-
- /*
- * The connection is not yet in the hashtable, so we update it.
- * CIP->VIP will remain the same, so leave the tuple in
- * IP_CT_DIR_ORIGINAL untouched. When the reply comes back from the
- * real-server we will see RIP->DIP.
- */
- new_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
- if (outin)
- new_tuple.src.u3 = cp->daddr;
- else
- new_tuple.dst.u3 = cp->vaddr;
- /*
- * This will also take care of UDP and other protocols.
- */
- if (outin)
- new_tuple.src.u.tcp.port = cp->dport;
- else
- new_tuple.dst.u.tcp.port = cp->vport;
- nf_conntrack_alter_reply(ct, &new_tuple);
-}
-
/*
* NAT transmitter (only for outside-to-inside nat forwarding)
* Not used for related ICMP
@@ -390,6 +515,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct rtable *rt; /* Route to the other host */
int mtu;
struct iphdr *iph = ip_hdr(skb);
+ int local;
EnterFunction(10);
@@ -403,16 +529,42 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p));
}
- if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos))))
+ if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
+ RT_TOS(iph->tos), 1|2|4)))
goto tx_error_icmp;
+ local = rt->rt_flags & RTCF_LOCAL;
+ /*
+ * Avoid duplicate tuple in reply direction for NAT traffic
+ * to local address when connection is sync-ed
+ */
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+ if (cp->flags & IP_VS_CONN_F_SYNC && local) {
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo);
+
+ if (ct && !nf_ct_is_untracked(ct)) {
+ IP_VS_DBG_RL_PKT(10, AF_INET, pp, skb, 0,
+ "ip_vs_nat_xmit(): "
+ "stopping DNAT to local address");
+ goto tx_error_put;
+ }
+ }
+#endif
+
+ /* From world but DNAT to loopback address? */
+ if (local && ipv4_is_loopback(rt->rt_dst) && skb_rtable(skb)->fl.iif) {
+ IP_VS_DBG_RL_PKT(1, AF_INET, pp, skb, 0, "ip_vs_nat_xmit(): "
+ "stopping DNAT to loopback address");
+ goto tx_error_put;
+ }
/* MTU checking */
mtu = dst_mtu(&rt->dst);
if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
- ip_rt_put(rt);
icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
- IP_VS_DBG_RL_PKT(0, pp, skb, 0, "ip_vs_nat_xmit(): frag needed for");
- goto tx_error;
+ IP_VS_DBG_RL_PKT(0, AF_INET, pp, skb, 0,
+ "ip_vs_nat_xmit(): frag needed for");
+ goto tx_error_put;
}
/* copy-on-write the packet before mangling it */
@@ -422,19 +574,28 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
if (skb_cow(skb, rt->dst.dev->hard_header_len))
goto tx_error_put;
- /* drop old route */
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
-
/* mangle the packet */
if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
- goto tx_error;
+ goto tx_error_put;
ip_hdr(skb)->daddr = cp->daddr.ip;
ip_send_check(ip_hdr(skb));
- IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
+ if (!local) {
+ /* drop old route */
+ skb_dst_drop(skb);
+ skb_dst_set(skb, &rt->dst);
+ } else {
+ ip_rt_put(rt);
+ /*
+ * Some IPv4 replies get local address from routes,
+ * not from iph, so while we DNAT after routing
+ * we need this second input/output route.
+ */
+ if (!__ip_vs_reroute_locally(skb))
+ goto tx_error;
+ }
- ip_vs_update_conntrack(skb, cp, 1);
+ IP_VS_DBG_PKT(10, AF_INET, pp, skb, 0, "After DNAT");
/* FIXME: when application helper enlarges the packet and the length
is larger than the MTU of outgoing device, there will be still
@@ -443,7 +604,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT(NFPROTO_IPV4, skb, rt);
+ IP_VS_XMIT_NAT(NFPROTO_IPV4, skb, cp, local);
LeaveFunction(10);
return NF_STOLEN;
@@ -451,8 +612,8 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
tx_error_icmp:
dst_link_failure(skb);
tx_error:
- LeaveFunction(10);
kfree_skb(skb);
+ LeaveFunction(10);
return NF_STOLEN;
tx_error_put:
ip_rt_put(rt);
@@ -466,6 +627,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
{
struct rt6_info *rt; /* Route to the other host */
int mtu;
+ int local;
EnterFunction(10);
@@ -480,18 +642,49 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p));
}
- rt = __ip_vs_get_out_rt_v6(cp);
- if (!rt)
+ if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL,
+ 0, 1|2|4)))
goto tx_error_icmp;
+ local = __ip_vs_is_local_route6(rt);
+ /*
+ * Avoid duplicate tuple in reply direction for NAT traffic
+ * to local address when connection is sync-ed
+ */
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+ if (cp->flags & IP_VS_CONN_F_SYNC && local) {
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo);
+
+ if (ct && !nf_ct_is_untracked(ct)) {
+ IP_VS_DBG_RL_PKT(10, AF_INET6, pp, skb, 0,
+ "ip_vs_nat_xmit_v6(): "
+ "stopping DNAT to local address");
+ goto tx_error_put;
+ }
+ }
+#endif
+
+ /* From world but DNAT to loopback address? */
+ if (local && skb->dev && !(skb->dev->flags & IFF_LOOPBACK) &&
+ ipv6_addr_type(&rt->rt6i_dst.addr) & IPV6_ADDR_LOOPBACK) {
+ IP_VS_DBG_RL_PKT(1, AF_INET6, pp, skb, 0,
+ "ip_vs_nat_xmit_v6(): "
+ "stopping DNAT to loopback address");
+ goto tx_error_put;
+ }
/* MTU checking */
mtu = dst_mtu(&rt->dst);
if (skb->len > mtu) {
- dst_release(&rt->dst);
+ if (!skb->dev) {
+ struct net *net = dev_net(skb_dst(skb)->dev);
+
+ skb->dev = net->loopback_dev;
+ }
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+ IP_VS_DBG_RL_PKT(0, AF_INET6, pp, skb, 0,
"ip_vs_nat_xmit_v6(): frag needed for");
- goto tx_error;
+ goto tx_error_put;
}
/* copy-on-write the packet before mangling it */
@@ -501,18 +694,21 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
if (skb_cow(skb, rt->dst.dev->hard_header_len))
goto tx_error_put;
- /* drop old route */
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
-
/* mangle the packet */
if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
goto tx_error;
- ipv6_hdr(skb)->daddr = cp->daddr.in6;
+ ipv6_addr_copy(&ipv6_hdr(skb)->daddr, &cp->daddr.in6);
- IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
+ if (!local || !skb->dev) {
+ /* drop the old route when skb is not shared */
+ skb_dst_drop(skb);
+ skb_dst_set(skb, &rt->dst);
+ } else {
+ /* destined to loopback, do we need to change route? */
+ dst_release(&rt->dst);
+ }
- ip_vs_update_conntrack(skb, cp, 1);
+ IP_VS_DBG_PKT(10, AF_INET6, pp, skb, 0, "After DNAT");
/* FIXME: when application helper enlarges the packet and the length
is larger than the MTU of outgoing device, there will be still
@@ -521,7 +717,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT(NFPROTO_IPV6, skb, rt);
+ IP_VS_XMIT_NAT(NFPROTO_IPV6, skb, cp, local);
LeaveFunction(10);
return NF_STOLEN;
@@ -567,30 +763,27 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct iphdr *old_iph = ip_hdr(skb);
u8 tos = old_iph->tos;
__be16 df = old_iph->frag_off;
- sk_buff_data_t old_transport_header = skb->transport_header;
struct iphdr *iph; /* Our new IP header */
unsigned int max_headroom; /* The extra header space needed */
int mtu;
+ int ret;
EnterFunction(10);
- if (skb->protocol != htons(ETH_P_IP)) {
- IP_VS_DBG_RL("%s(): protocol error, "
- "ETH_P_IP: %d, skb protocol: %d\n",
- __func__, htons(ETH_P_IP), skb->protocol);
- goto tx_error;
- }
-
- if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(tos))))
+ if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
+ RT_TOS(tos), 1|2)))
goto tx_error_icmp;
+ if (rt->rt_flags & RTCF_LOCAL) {
+ ip_rt_put(rt);
+ IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 1);
+ }
tdev = rt->dst.dev;
mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
if (mtu < 68) {
- ip_rt_put(rt);
IP_VS_DBG_RL("%s(): mtu less than 68\n", __func__);
- goto tx_error;
+ goto tx_error_put;
}
if (skb_dst(skb))
skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
@@ -600,9 +793,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
if ((old_iph->frag_off & htons(IP_DF))
&& mtu < ntohs(old_iph->tot_len)) {
icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
- ip_rt_put(rt);
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
- goto tx_error;
+ goto tx_error_put;
}
/*
@@ -625,7 +817,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
old_iph = ip_hdr(skb);
}
- skb->transport_header = old_transport_header;
+ skb->transport_header = skb->network_header;
/* fix old IP header checksum */
ip_send_check(old_iph);
@@ -655,7 +847,11 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- ip_local_out(skb);
+ ret = IP_VS_XMIT_TUNNEL(skb, cp);
+ if (ret == NF_ACCEPT)
+ ip_local_out(skb);
+ else if (ret == NF_DROP)
+ kfree_skb(skb);
LeaveFunction(10);
@@ -667,6 +863,9 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
kfree_skb(skb);
LeaveFunction(10);
return NF_STOLEN;
+tx_error_put:
+ ip_rt_put(rt);
+ goto tx_error;
}
#ifdef CONFIG_IP_VS_IPV6
@@ -675,43 +874,44 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp)
{
struct rt6_info *rt; /* Route to the other host */
+ struct in6_addr saddr; /* Source for tunnel */
struct net_device *tdev; /* Device to other host */
struct ipv6hdr *old_iph = ipv6_hdr(skb);
- sk_buff_data_t old_transport_header = skb->transport_header;
struct ipv6hdr *iph; /* Our new IP header */
unsigned int max_headroom; /* The extra header space needed */
int mtu;
+ int ret;
EnterFunction(10);
- if (skb->protocol != htons(ETH_P_IPV6)) {
- IP_VS_DBG_RL("%s(): protocol error, "
- "ETH_P_IPV6: %d, skb protocol: %d\n",
- __func__, htons(ETH_P_IPV6), skb->protocol);
- goto tx_error;
- }
-
- rt = __ip_vs_get_out_rt_v6(cp);
- if (!rt)
+ if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6,
+ &saddr, 1, 1|2)))
goto tx_error_icmp;
+ if (__ip_vs_is_local_route6(rt)) {
+ dst_release(&rt->dst);
+ IP_VS_XMIT(NFPROTO_IPV6, skb, cp, 1);
+ }
tdev = rt->dst.dev;
mtu = dst_mtu(&rt->dst) - sizeof(struct ipv6hdr);
- /* TODO IPv6: do we need this check in IPv6? */
- if (mtu < 1280) {
- dst_release(&rt->dst);
- IP_VS_DBG_RL("%s(): mtu less than 1280\n", __func__);
- goto tx_error;
+ if (mtu < IPV6_MIN_MTU) {
+ IP_VS_DBG_RL("%s(): mtu less than %d\n", __func__,
+ IPV6_MIN_MTU);
+ goto tx_error_put;
}
if (skb_dst(skb))
skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) {
+ if (!skb->dev) {
+ struct net *net = dev_net(skb_dst(skb)->dev);
+
+ skb->dev = net->loopback_dev;
+ }
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- dst_release(&rt->dst);
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
- goto tx_error;
+ goto tx_error_put;
}
/*
@@ -734,7 +934,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
old_iph = ipv6_hdr(skb);
}
- skb->transport_header = old_transport_header;
+ skb->transport_header = skb->network_header;
skb_push(skb, sizeof(struct ipv6hdr));
skb_reset_network_header(skb);
@@ -754,14 +954,18 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
be16_add_cpu(&iph->payload_len, sizeof(*old_iph));
iph->priority = old_iph->priority;
memset(&iph->flow_lbl, 0, sizeof(iph->flow_lbl));
- iph->daddr = rt->rt6i_dst.addr;
- iph->saddr = cp->vaddr.in6; /* rt->rt6i_src.addr; */
+ ipv6_addr_copy(&iph->daddr, &cp->daddr.in6);
+ ipv6_addr_copy(&iph->saddr, &saddr);
iph->hop_limit = old_iph->hop_limit;
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- ip6_local_out(skb);
+ ret = IP_VS_XMIT_TUNNEL(skb, cp);
+ if (ret == NF_ACCEPT)
+ ip6_local_out(skb);
+ else if (ret == NF_DROP)
+ kfree_skb(skb);
LeaveFunction(10);
@@ -773,6 +977,9 @@ tx_error:
kfree_skb(skb);
LeaveFunction(10);
return NF_STOLEN;
+tx_error_put:
+ dst_release(&rt->dst);
+ goto tx_error;
}
#endif
@@ -791,8 +998,13 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
EnterFunction(10);
- if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos))))
+ if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
+ RT_TOS(iph->tos), 1|2)))
goto tx_error_icmp;
+ if (rt->rt_flags & RTCF_LOCAL) {
+ ip_rt_put(rt);
+ IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 1);
+ }
/* MTU checking */
mtu = dst_mtu(&rt->dst);
@@ -820,7 +1032,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT(NFPROTO_IPV4, skb, rt);
+ IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 0);
LeaveFunction(10);
return NF_STOLEN;
@@ -843,13 +1055,22 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
EnterFunction(10);
- rt = __ip_vs_get_out_rt_v6(cp);
- if (!rt)
+ if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL,
+ 0, 1|2)))
goto tx_error_icmp;
+ if (__ip_vs_is_local_route6(rt)) {
+ dst_release(&rt->dst);
+ IP_VS_XMIT(NFPROTO_IPV6, skb, cp, 1);
+ }
/* MTU checking */
mtu = dst_mtu(&rt->dst);
if (skb->len > mtu) {
+ if (!skb->dev) {
+ struct net *net = dev_net(skb_dst(skb)->dev);
+
+ skb->dev = net->loopback_dev;
+ }
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
dst_release(&rt->dst);
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
@@ -873,7 +1094,7 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT(NFPROTO_IPV6, skb, rt);
+ IP_VS_XMIT(NFPROTO_IPV6, skb, cp, 0);
LeaveFunction(10);
return NF_STOLEN;
@@ -899,6 +1120,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct rtable *rt; /* Route to the other host */
int mtu;
int rc;
+ int local;
EnterFunction(10);
@@ -919,16 +1141,43 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
* mangle and send the packet here (only for VS/NAT)
*/
- if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(ip_hdr(skb)->tos))))
+ if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
+ RT_TOS(ip_hdr(skb)->tos), 1|2|4)))
goto tx_error_icmp;
+ local = rt->rt_flags & RTCF_LOCAL;
+
+ /*
+ * Avoid duplicate tuple in reply direction for NAT traffic
+ * to local address when connection is sync-ed
+ */
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+ if (cp->flags & IP_VS_CONN_F_SYNC && local) {
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo);
+
+ if (ct && !nf_ct_is_untracked(ct)) {
+ IP_VS_DBG(10, "%s(): "
+ "stopping DNAT to local address %pI4\n",
+ __func__, &cp->daddr.ip);
+ goto tx_error_put;
+ }
+ }
+#endif
+
+ /* From world but DNAT to loopback address? */
+ if (local && ipv4_is_loopback(rt->rt_dst) && skb_rtable(skb)->fl.iif) {
+ IP_VS_DBG(1, "%s(): "
+ "stopping DNAT to loopback %pI4\n",
+ __func__, &cp->daddr.ip);
+ goto tx_error_put;
+ }
/* MTU checking */
mtu = dst_mtu(&rt->dst);
if ((skb->len > mtu) && (ip_hdr(skb)->frag_off & htons(IP_DF))) {
- ip_rt_put(rt);
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
- goto tx_error;
+ goto tx_error_put;
}
/* copy-on-write the packet before mangling it */
@@ -938,16 +1187,27 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
if (skb_cow(skb, rt->dst.dev->hard_header_len))
goto tx_error_put;
- /* drop the old route when skb is not shared */
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
-
ip_vs_nat_icmp(skb, pp, cp, 0);
+ if (!local) {
+ /* drop the old route when skb is not shared */
+ skb_dst_drop(skb);
+ skb_dst_set(skb, &rt->dst);
+ } else {
+ ip_rt_put(rt);
+ /*
+ * Some IPv4 replies get local address from routes,
+ * not from iph, so while we DNAT after routing
+ * we need this second input/output route.
+ */
+ if (!__ip_vs_reroute_locally(skb))
+ goto tx_error;
+ }
+
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT(NFPROTO_IPV4, skb, rt);
+ IP_VS_XMIT_NAT(NFPROTO_IPV4, skb, cp, local);
rc = NF_STOLEN;
goto out;
@@ -973,6 +1233,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
struct rt6_info *rt; /* Route to the other host */
int mtu;
int rc;
+ int local;
EnterFunction(10);
@@ -993,17 +1254,49 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
* mangle and send the packet here (only for VS/NAT)
*/
- rt = __ip_vs_get_out_rt_v6(cp);
- if (!rt)
+ if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL,
+ 0, 1|2|4)))
goto tx_error_icmp;
+ local = __ip_vs_is_local_route6(rt);
+ /*
+ * Avoid duplicate tuple in reply direction for NAT traffic
+ * to local address when connection is sync-ed
+ */
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+ if (cp->flags & IP_VS_CONN_F_SYNC && local) {
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo);
+
+ if (ct && !nf_ct_is_untracked(ct)) {
+ IP_VS_DBG(10, "%s(): "
+ "stopping DNAT to local address %pI6\n",
+ __func__, &cp->daddr.in6);
+ goto tx_error_put;
+ }
+ }
+#endif
+
+ /* From world but DNAT to loopback address? */
+ if (local && skb->dev && !(skb->dev->flags & IFF_LOOPBACK) &&
+ ipv6_addr_type(&rt->rt6i_dst.addr) & IPV6_ADDR_LOOPBACK) {
+ IP_VS_DBG(1, "%s(): "
+ "stopping DNAT to loopback %pI6\n",
+ __func__, &cp->daddr.in6);
+ goto tx_error_put;
+ }
+
/* MTU checking */
mtu = dst_mtu(&rt->dst);
if (skb->len > mtu) {
- dst_release(&rt->dst);
+ if (!skb->dev) {
+ struct net *net = dev_net(skb_dst(skb)->dev);
+
+ skb->dev = net->loopback_dev;
+ }
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
- goto tx_error;
+ goto tx_error_put;
}
/* copy-on-write the packet before mangling it */
@@ -1013,16 +1306,21 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
if (skb_cow(skb, rt->dst.dev->hard_header_len))
goto tx_error_put;
- /* drop the old route when skb is not shared */
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
-
ip_vs_nat_icmp_v6(skb, pp, cp, 0);
+ if (!local || !skb->dev) {
+ /* drop the old route when skb is not shared */
+ skb_dst_drop(skb);
+ skb_dst_set(skb, &rt->dst);
+ } else {
+ /* destined to loopback, do we need to change route? */
+ dst_release(&rt->dst);
+ }
+
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT(NFPROTO_IPV6, skb, rt);
+ IP_VS_XMIT_NAT(NFPROTO_IPV6, skb, cp, local);
rc = NF_STOLEN;
goto out;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index df3eedb142ff..1eacf8d9966a 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -65,32 +65,42 @@ EXPORT_SYMBOL_GPL(nf_conntrack_max);
DEFINE_PER_CPU(struct nf_conn, nf_conntrack_untracked);
EXPORT_PER_CPU_SYMBOL(nf_conntrack_untracked);
-static int nf_conntrack_hash_rnd_initted;
-static unsigned int nf_conntrack_hash_rnd;
+static unsigned int nf_conntrack_hash_rnd __read_mostly;
-static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple,
- u16 zone, unsigned int size, unsigned int rnd)
+static u32 hash_conntrack_raw(const struct nf_conntrack_tuple *tuple, u16 zone)
{
unsigned int n;
- u_int32_t h;
/* The direction must be ignored, so we hash everything up to the
* destination ports (which is a multiple of 4) and treat the last
* three bytes manually.
*/
n = (sizeof(tuple->src) + sizeof(tuple->dst.u3)) / sizeof(u32);
- h = jhash2((u32 *)tuple, n,
- zone ^ rnd ^ (((__force __u16)tuple->dst.u.all << 16) |
- tuple->dst.protonum));
+ return jhash2((u32 *)tuple, n, zone ^ nf_conntrack_hash_rnd ^
+ (((__force __u16)tuple->dst.u.all << 16) |
+ tuple->dst.protonum));
+}
+
+static u32 __hash_bucket(u32 hash, unsigned int size)
+{
+ return ((u64)hash * size) >> 32;
+}
+
+static u32 hash_bucket(u32 hash, const struct net *net)
+{
+ return __hash_bucket(hash, net->ct.htable_size);
+}
- return ((u64)h * size) >> 32;
+static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple,
+ u16 zone, unsigned int size)
+{
+ return __hash_bucket(hash_conntrack_raw(tuple, zone), size);
}
static inline u_int32_t hash_conntrack(const struct net *net, u16 zone,
const struct nf_conntrack_tuple *tuple)
{
- return __hash_conntrack(tuple, zone, net->ct.htable_size,
- nf_conntrack_hash_rnd);
+ return __hash_conntrack(tuple, zone, net->ct.htable_size);
}
bool
@@ -292,20 +302,20 @@ static void death_by_timeout(unsigned long ul_conntrack)
* OR
* - Caller must lock nf_conntrack_lock before calling this function
*/
-struct nf_conntrack_tuple_hash *
-__nf_conntrack_find(struct net *net, u16 zone,
- const struct nf_conntrack_tuple *tuple)
+static struct nf_conntrack_tuple_hash *
+____nf_conntrack_find(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *tuple, u32 hash)
{
struct nf_conntrack_tuple_hash *h;
struct hlist_nulls_node *n;
- unsigned int hash = hash_conntrack(net, zone, tuple);
+ unsigned int bucket = hash_bucket(hash, net);
/* Disable BHs the entire time since we normally need to disable them
* at least once for the stats anyway.
*/
local_bh_disable();
begin:
- hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) {
+ hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[bucket], hnnode) {
if (nf_ct_tuple_equal(tuple, &h->tuple) &&
nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)) == zone) {
NF_CT_STAT_INC(net, found);
@@ -319,7 +329,7 @@ begin:
* not the expected one, we must restart lookup.
* We probably met an item that was moved to another chain.
*/
- if (get_nulls_value(n) != hash) {
+ if (get_nulls_value(n) != bucket) {
NF_CT_STAT_INC(net, search_restart);
goto begin;
}
@@ -327,19 +337,27 @@ begin:
return NULL;
}
+
+struct nf_conntrack_tuple_hash *
+__nf_conntrack_find(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *tuple)
+{
+ return ____nf_conntrack_find(net, zone, tuple,
+ hash_conntrack_raw(tuple, zone));
+}
EXPORT_SYMBOL_GPL(__nf_conntrack_find);
/* Find a connection corresponding to a tuple. */
-struct nf_conntrack_tuple_hash *
-nf_conntrack_find_get(struct net *net, u16 zone,
- const struct nf_conntrack_tuple *tuple)
+static struct nf_conntrack_tuple_hash *
+__nf_conntrack_find_get(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *tuple, u32 hash)
{
struct nf_conntrack_tuple_hash *h;
struct nf_conn *ct;
rcu_read_lock();
begin:
- h = __nf_conntrack_find(net, zone, tuple);
+ h = ____nf_conntrack_find(net, zone, tuple, hash);
if (h) {
ct = nf_ct_tuplehash_to_ctrack(h);
if (unlikely(nf_ct_is_dying(ct) ||
@@ -357,6 +375,14 @@ begin:
return h;
}
+
+struct nf_conntrack_tuple_hash *
+nf_conntrack_find_get(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *tuple)
+{
+ return __nf_conntrack_find_get(net, zone, tuple,
+ hash_conntrack_raw(tuple, zone));
+}
EXPORT_SYMBOL_GPL(nf_conntrack_find_get);
static void __nf_conntrack_hash_insert(struct nf_conn *ct,
@@ -409,8 +435,11 @@ __nf_conntrack_confirm(struct sk_buff *skb)
return NF_ACCEPT;
zone = nf_ct_zone(ct);
- hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
- repl_hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+ /* reuse the hash saved before */
+ hash = *(unsigned long *)&ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev;
+ hash = hash_bucket(hash, net);
+ repl_hash = hash_conntrack(net, zone,
+ &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
/* We're not in hash table, and we refuse to set up related
connections for unconfirmed conns. But packet copies and
@@ -567,17 +596,29 @@ static noinline int early_drop(struct net *net, unsigned int hash)
return dropped;
}
-struct nf_conn *nf_conntrack_alloc(struct net *net, u16 zone,
- const struct nf_conntrack_tuple *orig,
- const struct nf_conntrack_tuple *repl,
- gfp_t gfp)
+static struct nf_conn *
+__nf_conntrack_alloc(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *orig,
+ const struct nf_conntrack_tuple *repl,
+ gfp_t gfp, u32 hash)
{
struct nf_conn *ct;
- if (unlikely(!nf_conntrack_hash_rnd_initted)) {
- get_random_bytes(&nf_conntrack_hash_rnd,
- sizeof(nf_conntrack_hash_rnd));
- nf_conntrack_hash_rnd_initted = 1;
+ if (unlikely(!nf_conntrack_hash_rnd)) {
+ unsigned int rand;
+
+ /*
+ * Why not initialize nf_conntrack_rnd in a "init()" function ?
+ * Because there isn't enough entropy when system initializing,
+ * and we initialize it as late as possible.
+ */
+ do {
+ get_random_bytes(&rand, sizeof(rand));
+ } while (!rand);
+ cmpxchg(&nf_conntrack_hash_rnd, 0, rand);
+
+ /* recompute the hash as nf_conntrack_hash_rnd is initialized */
+ hash = hash_conntrack_raw(orig, zone);
}
/* We don't want any race condition at early drop stage */
@@ -585,8 +626,7 @@ struct nf_conn *nf_conntrack_alloc(struct net *net, u16 zone,
if (nf_conntrack_max &&
unlikely(atomic_read(&net->ct.count) > nf_conntrack_max)) {
- unsigned int hash = hash_conntrack(net, zone, orig);
- if (!early_drop(net, hash)) {
+ if (!early_drop(net, hash_bucket(hash, net))) {
atomic_dec(&net->ct.count);
if (net_ratelimit())
printk(KERN_WARNING
@@ -616,7 +656,8 @@ struct nf_conn *nf_conntrack_alloc(struct net *net, u16 zone,
ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode.pprev = NULL;
ct->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
- ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev = NULL;
+ /* save hash for reusing when confirming */
+ *(unsigned long *)(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev) = hash;
/* Don't set timer yet: wait for confirmation */
setup_timer(&ct->timeout, death_by_timeout, (unsigned long)ct);
write_pnet(&ct->ct_net, net);
@@ -643,6 +684,14 @@ out_free:
return ERR_PTR(-ENOMEM);
#endif
}
+
+struct nf_conn *nf_conntrack_alloc(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *orig,
+ const struct nf_conntrack_tuple *repl,
+ gfp_t gfp)
+{
+ return __nf_conntrack_alloc(net, zone, orig, repl, gfp, 0);
+}
EXPORT_SYMBOL_GPL(nf_conntrack_alloc);
void nf_conntrack_free(struct nf_conn *ct)
@@ -664,7 +713,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
struct nf_conntrack_l3proto *l3proto,
struct nf_conntrack_l4proto *l4proto,
struct sk_buff *skb,
- unsigned int dataoff)
+ unsigned int dataoff, u32 hash)
{
struct nf_conn *ct;
struct nf_conn_help *help;
@@ -678,7 +727,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
return NULL;
}
- ct = nf_conntrack_alloc(net, zone, tuple, &repl_tuple, GFP_ATOMIC);
+ ct = __nf_conntrack_alloc(net, zone, tuple, &repl_tuple, GFP_ATOMIC,
+ hash);
if (IS_ERR(ct)) {
pr_debug("Can't allocate conntrack.\n");
return (struct nf_conntrack_tuple_hash *)ct;
@@ -755,6 +805,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
struct nf_conntrack_tuple_hash *h;
struct nf_conn *ct;
u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
+ u32 hash;
if (!nf_ct_get_tuple(skb, skb_network_offset(skb),
dataoff, l3num, protonum, &tuple, l3proto,
@@ -764,10 +815,11 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
}
/* look for tuple match */
- h = nf_conntrack_find_get(net, zone, &tuple);
+ hash = hash_conntrack_raw(&tuple, zone);
+ h = __nf_conntrack_find_get(net, zone, &tuple, hash);
if (!h) {
h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto,
- skb, dataoff);
+ skb, dataoff, hash);
if (!h)
return NULL;
if (IS_ERR(h))
@@ -1307,8 +1359,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
ct = nf_ct_tuplehash_to_ctrack(h);
hlist_nulls_del_rcu(&h->hnnode);
bucket = __hash_conntrack(&h->tuple, nf_ct_zone(ct),
- hashsize,
- nf_conntrack_hash_rnd);
+ hashsize);
hlist_nulls_add_head_rcu(&h->hnnode, &hash[bucket]);
}
}
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index acb29ccaa41f..46e8966912b1 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -38,25 +38,30 @@ static int nf_ct_expect_hash_rnd_initted __read_mostly;
static struct kmem_cache *nf_ct_expect_cachep __read_mostly;
+static HLIST_HEAD(nf_ct_userspace_expect_list);
+
/* nf_conntrack_expect helper functions */
-void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
+void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
+ u32 pid, int report)
{
struct nf_conn_help *master_help = nfct_help(exp->master);
struct net *net = nf_ct_exp_net(exp);
- NF_CT_ASSERT(master_help);
NF_CT_ASSERT(!timer_pending(&exp->timeout));
hlist_del_rcu(&exp->hnode);
net->ct.expect_count--;
hlist_del(&exp->lnode);
- master_help->expecting[exp->class]--;
+ if (!(exp->flags & NF_CT_EXPECT_USERSPACE))
+ master_help->expecting[exp->class]--;
+
+ nf_ct_expect_event_report(IPEXP_DESTROY, exp, pid, report);
nf_ct_expect_put(exp);
NF_CT_STAT_INC(net, expect_delete);
}
-EXPORT_SYMBOL_GPL(nf_ct_unlink_expect);
+EXPORT_SYMBOL_GPL(nf_ct_unlink_expect_report);
static void nf_ct_expectation_timed_out(unsigned long ul_expect)
{
@@ -320,16 +325,21 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
atomic_inc(&exp->use);
- hlist_add_head(&exp->lnode, &master_help->expectations);
- master_help->expecting[exp->class]++;
+ if (master_help) {
+ hlist_add_head(&exp->lnode, &master_help->expectations);
+ master_help->expecting[exp->class]++;
+ } else if (exp->flags & NF_CT_EXPECT_USERSPACE)
+ hlist_add_head(&exp->lnode, &nf_ct_userspace_expect_list);
hlist_add_head_rcu(&exp->hnode, &net->ct.expect_hash[h]);
net->ct.expect_count++;
setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
(unsigned long)exp);
- p = &master_help->helper->expect_policy[exp->class];
- exp->timeout.expires = jiffies + p->timeout * HZ;
+ if (master_help) {
+ p = &master_help->helper->expect_policy[exp->class];
+ exp->timeout.expires = jiffies + p->timeout * HZ;
+ }
add_timer(&exp->timeout);
atomic_inc(&exp->use);
@@ -380,7 +390,9 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
unsigned int h;
int ret = 1;
- if (!master_help->helper) {
+ /* Don't allow expectations created from kernel-space with no helper */
+ if (!(expect->flags & NF_CT_EXPECT_USERSPACE) &&
+ (!master_help || (master_help && !master_help->helper))) {
ret = -ESHUTDOWN;
goto out;
}
@@ -398,13 +410,16 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
}
}
/* Will be over limit? */
- p = &master_help->helper->expect_policy[expect->class];
- if (p->max_expected &&
- master_help->expecting[expect->class] >= p->max_expected) {
- evict_oldest_expect(master, expect);
- if (master_help->expecting[expect->class] >= p->max_expected) {
- ret = -EMFILE;
- goto out;
+ if (master_help) {
+ p = &master_help->helper->expect_policy[expect->class];
+ if (p->max_expected &&
+ master_help->expecting[expect->class] >= p->max_expected) {
+ evict_oldest_expect(master, expect);
+ if (master_help->expecting[expect->class]
+ >= p->max_expected) {
+ ret = -EMFILE;
+ goto out;
+ }
}
}
@@ -439,6 +454,21 @@ out:
}
EXPORT_SYMBOL_GPL(nf_ct_expect_related_report);
+void nf_ct_remove_userspace_expectations(void)
+{
+ struct nf_conntrack_expect *exp;
+ struct hlist_node *n, *next;
+
+ hlist_for_each_entry_safe(exp, n, next,
+ &nf_ct_userspace_expect_list, lnode) {
+ if (del_timer(&exp->timeout)) {
+ nf_ct_unlink_expect(exp);
+ nf_ct_expect_put(exp);
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(nf_ct_remove_userspace_expectations);
+
#ifdef CONFIG_PROC_FS
struct ct_expect_iter_state {
struct seq_net_private p;
@@ -529,8 +559,12 @@ static int exp_seq_show(struct seq_file *s, void *v)
seq_printf(s, "PERMANENT");
delim = ",";
}
- if (expect->flags & NF_CT_EXPECT_INACTIVE)
+ if (expect->flags & NF_CT_EXPECT_INACTIVE) {
seq_printf(s, "%sINACTIVE", delim);
+ delim = ",";
+ }
+ if (expect->flags & NF_CT_EXPECT_USERSPACE)
+ seq_printf(s, "%sUSERSPACE", delim);
helper = rcu_dereference(nfct_help(expect->master)->helper);
if (helper) {
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 146476c6441a..b729ace1dcc1 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1588,8 +1588,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
const struct nf_conntrack_expect *exp)
{
struct nf_conn *master = exp->master;
- struct nf_conntrack_helper *helper;
long timeout = (exp->timeout.expires - jiffies) / HZ;
+ struct nf_conn_help *help;
if (timeout < 0)
timeout = 0;
@@ -1605,9 +1605,15 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout));
NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp));
- helper = rcu_dereference(nfct_help(master)->helper);
- if (helper)
- NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name);
+ NLA_PUT_BE32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags));
+ help = nfct_help(master);
+ if (help) {
+ struct nf_conntrack_helper *helper;
+
+ helper = rcu_dereference(help->helper);
+ if (helper)
+ NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name);
+ }
return 0;
@@ -1654,17 +1660,20 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item)
struct nlmsghdr *nlh;
struct nfgenmsg *nfmsg;
struct sk_buff *skb;
- unsigned int type;
+ unsigned int type, group;
int flags = 0;
- if (events & (1 << IPEXP_NEW)) {
+ if (events & (1 << IPEXP_DESTROY)) {
+ type = IPCTNL_MSG_EXP_DELETE;
+ group = NFNLGRP_CONNTRACK_EXP_DESTROY;
+ } else if (events & (1 << IPEXP_NEW)) {
type = IPCTNL_MSG_EXP_NEW;
flags = NLM_F_CREATE|NLM_F_EXCL;
+ group = NFNLGRP_CONNTRACK_EXP_NEW;
} else
return 0;
- if (!item->report &&
- !nfnetlink_has_listeners(net, NFNLGRP_CONNTRACK_EXP_NEW))
+ if (!item->report && !nfnetlink_has_listeners(net, group))
return 0;
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
@@ -1687,8 +1696,7 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item)
rcu_read_unlock();
nlmsg_end(skb, nlh);
- nfnetlink_send(skb, net, item->pid, NFNLGRP_CONNTRACK_EXP_NEW,
- item->report, GFP_ATOMIC);
+ nfnetlink_send(skb, net, item->pid, group, item->report, GFP_ATOMIC);
return 0;
nla_put_failure:
@@ -1761,6 +1769,8 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
[CTA_EXPECT_TIMEOUT] = { .type = NLA_U32 },
[CTA_EXPECT_ID] = { .type = NLA_U32 },
[CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING },
+ [CTA_EXPECT_ZONE] = { .type = NLA_U16 },
+ [CTA_EXPECT_FLAGS] = { .type = NLA_U32 },
};
static int
@@ -1869,7 +1879,13 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
}
/* after list removal, usage count == 1 */
- nf_ct_unexpect_related(exp);
+ spin_lock_bh(&nf_conntrack_lock);
+ if (del_timer(&exp->timeout)) {
+ nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).pid,
+ nlmsg_report(nlh));
+ nf_ct_expect_put(exp);
+ }
+ spin_unlock_bh(&nf_conntrack_lock);
/* have to put what we 'get' above.
* after this line usage count == 0 */
nf_ct_expect_put(exp);
@@ -1886,7 +1902,9 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
m_help = nfct_help(exp->master);
if (!strcmp(m_help->helper->name, name) &&
del_timer(&exp->timeout)) {
- nf_ct_unlink_expect(exp);
+ nf_ct_unlink_expect_report(exp,
+ NETLINK_CB(skb).pid,
+ nlmsg_report(nlh));
nf_ct_expect_put(exp);
}
}
@@ -1900,7 +1918,9 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
&net->ct.expect_hash[i],
hnode) {
if (del_timer(&exp->timeout)) {
- nf_ct_unlink_expect(exp);
+ nf_ct_unlink_expect_report(exp,
+ NETLINK_CB(skb).pid,
+ nlmsg_report(nlh));
nf_ct_expect_put(exp);
}
}
@@ -1946,23 +1966,35 @@ ctnetlink_create_expect(struct net *net, u16 zone,
if (!h)
return -ENOENT;
ct = nf_ct_tuplehash_to_ctrack(h);
- help = nfct_help(ct);
-
- if (!help || !help->helper) {
- /* such conntrack hasn't got any helper, abort */
- err = -EOPNOTSUPP;
- goto out;
- }
-
exp = nf_ct_expect_alloc(ct);
if (!exp) {
err = -ENOMEM;
goto out;
}
+ help = nfct_help(ct);
+ if (!help) {
+ if (!cda[CTA_EXPECT_TIMEOUT]) {
+ err = -EINVAL;
+ goto out;
+ }
+ exp->timeout.expires =
+ jiffies + ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ;
+
+ exp->flags = NF_CT_EXPECT_USERSPACE;
+ if (cda[CTA_EXPECT_FLAGS]) {
+ exp->flags |=
+ ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS]));
+ }
+ } else {
+ if (cda[CTA_EXPECT_FLAGS]) {
+ exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS]));
+ exp->flags &= ~NF_CT_EXPECT_USERSPACE;
+ } else
+ exp->flags = 0;
+ }
exp->class = 0;
exp->expectfn = NULL;
- exp->flags = 0;
exp->master = ct;
exp->helper = NULL;
memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple));
@@ -2130,6 +2162,7 @@ static void __exit ctnetlink_exit(void)
{
pr_info("ctnetlink: unregistering from nfnetlink.\n");
+ nf_ct_remove_userspace_expectations();
#ifdef CONFIG_NF_CONNTRACK_EVENTS
nf_ct_expect_unregister_notifier(&ctnl_notifier_exp);
nf_conntrack_unregister_notifier(&ctnl_notifier);
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index c4c885dca3bd..3fb2b73b24dc 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -329,8 +329,8 @@ static unsigned int get_conntrack_index(const struct tcphdr *tcph)
/* TCP connection tracking based on 'Real Stateful TCP Packet Filtering
in IP Filter' by Guido van Rooij.
- http://www.nluug.nl/events/sane2000/papers.html
- http://www.iae.nl/users/guido/papers/tcp_filtering.ps.gz
+ http://www.sane.nl/events/sane2000/papers.html
+ http://www.darkart.com/mirrors/www.obfuscation.org/ipf/
The boundaries and the conditions are changed according to RFC793:
the packet must intersect the window (i.e. segments may be
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index f64de9544866..bcf47eb518ef 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -130,6 +130,44 @@ static int digits_len(const struct nf_conn *ct, const char *dptr,
return len;
}
+static int iswordc(const char c)
+{
+ if (isalnum(c) || c == '!' || c == '"' || c == '%' ||
+ (c >= '(' && c <= '/') || c == ':' || c == '<' || c == '>' ||
+ c == '?' || (c >= '[' && c <= ']') || c == '_' || c == '`' ||
+ c == '{' || c == '}' || c == '~')
+ return 1;
+ return 0;
+}
+
+static int word_len(const char *dptr, const char *limit)
+{
+ int len = 0;
+ while (dptr < limit && iswordc(*dptr)) {
+ dptr++;
+ len++;
+ }
+ return len;
+}
+
+static int callid_len(const struct nf_conn *ct, const char *dptr,
+ const char *limit, int *shift)
+{
+ int len, domain_len;
+
+ len = word_len(dptr, limit);
+ dptr += len;
+ if (!len || dptr == limit || *dptr != '@')
+ return len;
+ dptr++;
+ len++;
+
+ domain_len = word_len(dptr, limit);
+ if (!domain_len)
+ return 0;
+ return len + domain_len;
+}
+
/* get media type + port length */
static int media_len(const struct nf_conn *ct, const char *dptr,
const char *limit, int *shift)
@@ -152,6 +190,9 @@ static int parse_addr(const struct nf_conn *ct, const char *cp,
const char *end;
int ret = 0;
+ if (!ct)
+ return 0;
+
memset(addr, 0, sizeof(*addr));
switch (nf_ct_l3num(ct)) {
case AF_INET:
@@ -296,6 +337,7 @@ static const struct sip_header ct_sip_hdrs[] = {
[SIP_HDR_VIA_TCP] = SIP_HDR("Via", "v", "TCP ", epaddr_len),
[SIP_HDR_EXPIRES] = SIP_HDR("Expires", NULL, NULL, digits_len),
[SIP_HDR_CONTENT_LENGTH] = SIP_HDR("Content-Length", "l", NULL, digits_len),
+ [SIP_HDR_CALL_ID] = SIP_HDR("Call-Id", "i", NULL, callid_len),
};
static const char *sip_follow_continuation(const char *dptr, const char *limit)
diff --git a/net/netfilter/nf_tproxy_core.c b/net/netfilter/nf_tproxy_core.c
index daab8c4a903c..4d87befb04c0 100644
--- a/net/netfilter/nf_tproxy_core.c
+++ b/net/netfilter/nf_tproxy_core.c
@@ -18,41 +18,6 @@
#include <net/udp.h>
#include <net/netfilter/nf_tproxy_core.h>
-struct sock *
-nf_tproxy_get_sock_v4(struct net *net, const u8 protocol,
- const __be32 saddr, const __be32 daddr,
- const __be16 sport, const __be16 dport,
- const struct net_device *in, bool listening_only)
-{
- struct sock *sk;
-
- /* look up socket */
- switch (protocol) {
- case IPPROTO_TCP:
- if (listening_only)
- sk = __inet_lookup_listener(net, &tcp_hashinfo,
- daddr, ntohs(dport),
- in->ifindex);
- else
- sk = __inet_lookup(net, &tcp_hashinfo,
- saddr, sport, daddr, dport,
- in->ifindex);
- break;
- case IPPROTO_UDP:
- sk = udp4_lib_lookup(net, saddr, sport, daddr, dport,
- in->ifindex);
- break;
- default:
- WARN_ON(1);
- sk = NULL;
- }
-
- pr_debug("tproxy socket lookup: proto %u %08x:%u -> %08x:%u, listener only: %d, sock %p\n",
- protocol, ntohl(saddr), ntohs(sport), ntohl(daddr), ntohs(dport), listening_only, sk);
-
- return sk;
-}
-EXPORT_SYMBOL_GPL(nf_tproxy_get_sock_v4);
static void
nf_tproxy_destructor(struct sk_buff *skb)
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index e34622fa0003..80463507420e 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -116,10 +116,8 @@ EXPORT_SYMBOL(xt_register_targets);
void
xt_unregister_targets(struct xt_target *target, unsigned int n)
{
- unsigned int i;
-
- for (i = 0; i < n; i++)
- xt_unregister_target(&target[i]);
+ while (n-- > 0)
+ xt_unregister_target(&target[n]);
}
EXPORT_SYMBOL(xt_unregister_targets);
@@ -174,10 +172,8 @@ EXPORT_SYMBOL(xt_register_matches);
void
xt_unregister_matches(struct xt_match *match, unsigned int n)
{
- unsigned int i;
-
- for (i = 0; i < n; i++)
- xt_unregister_match(&match[i]);
+ while (n-- > 0)
+ xt_unregister_match(&match[n]);
}
EXPORT_SYMBOL(xt_unregister_matches);
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
index c61294d85fda..640678f47a2a 100644
--- a/net/netfilter/xt_TPROXY.c
+++ b/net/netfilter/xt_TPROXY.c
@@ -1,7 +1,7 @@
/*
* Transparent proxy support for Linux/iptables
*
- * Copyright (c) 2006-2007 BalaBit IT Ltd.
+ * Copyright (c) 2006-2010 BalaBit IT Ltd.
* Author: Balazs Scheidler, Krisztian Kovacs
*
* This program is free software; you can redistribute it and/or modify
@@ -16,19 +16,98 @@
#include <net/checksum.h>
#include <net/udp.h>
#include <net/inet_sock.h>
-
+#include <linux/inetdevice.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter/xt_TPROXY.h>
#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
+
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+#define XT_TPROXY_HAVE_IPV6 1
+#include <net/if_inet6.h>
+#include <net/addrconf.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
+#endif
+
#include <net/netfilter/nf_tproxy_core.h>
+#include <linux/netfilter/xt_TPROXY.h>
+
+static inline __be32
+tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr)
+{
+ struct in_device *indev;
+ __be32 laddr;
+
+ if (user_laddr)
+ return user_laddr;
+
+ laddr = 0;
+ rcu_read_lock();
+ indev = __in_dev_get_rcu(skb->dev);
+ for_primary_ifa(indev) {
+ laddr = ifa->ifa_local;
+ break;
+ } endfor_ifa(indev);
+ rcu_read_unlock();
+
+ return laddr ? laddr : daddr;
+}
+
+/**
+ * tproxy_handle_time_wait4() - handle IPv4 TCP TIME_WAIT reopen redirections
+ * @skb: The skb being processed.
+ * @laddr: IPv4 address to redirect to or zero.
+ * @lport: TCP port to redirect to or zero.
+ * @sk: The TIME_WAIT TCP socket found by the lookup.
+ *
+ * We have to handle SYN packets arriving to TIME_WAIT sockets
+ * differently: instead of reopening the connection we should rather
+ * redirect the new connection to the proxy if there's a listener
+ * socket present.
+ *
+ * tproxy_handle_time_wait4() consumes the socket reference passed in.
+ *
+ * Returns the listener socket if there's one, the TIME_WAIT socket if
+ * no such listener is found, or NULL if the TCP header is incomplete.
+ */
+static struct sock *
+tproxy_handle_time_wait4(struct sk_buff *skb, __be32 laddr, __be16 lport,
+ struct sock *sk)
+{
+ const struct iphdr *iph = ip_hdr(skb);
+ struct tcphdr _hdr, *hp;
+
+ hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
+ if (hp == NULL) {
+ inet_twsk_put(inet_twsk(sk));
+ return NULL;
+ }
+
+ if (hp->syn && !hp->rst && !hp->ack && !hp->fin) {
+ /* SYN to a TIME_WAIT socket, we'd rather redirect it
+ * to a listener socket if there's one */
+ struct sock *sk2;
+
+ sk2 = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
+ iph->saddr, laddr ? laddr : iph->daddr,
+ hp->source, lport ? lport : hp->dest,
+ skb->dev, NFT_LOOKUP_LISTENER);
+ if (sk2) {
+ inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
+ inet_twsk_put(inet_twsk(sk));
+ sk = sk2;
+ }
+ }
+
+ return sk;
+}
static unsigned int
-tproxy_tg(struct sk_buff *skb, const struct xt_action_param *par)
+tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
+ u_int32_t mark_mask, u_int32_t mark_value)
{
const struct iphdr *iph = ip_hdr(skb);
- const struct xt_tproxy_target_info *tgi = par->targinfo;
struct udphdr _hdr, *hp;
struct sock *sk;
@@ -36,12 +115,195 @@ tproxy_tg(struct sk_buff *skb, const struct xt_action_param *par)
if (hp == NULL)
return NF_DROP;
+ /* check if there's an ongoing connection on the packet
+ * addresses, this happens if the redirect already happened
+ * and the current packet belongs to an already established
+ * connection */
sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
- iph->saddr,
- tgi->laddr ? tgi->laddr : iph->daddr,
- hp->source,
- tgi->lport ? tgi->lport : hp->dest,
- par->in, true);
+ iph->saddr, iph->daddr,
+ hp->source, hp->dest,
+ skb->dev, NFT_LOOKUP_ESTABLISHED);
+
+ laddr = tproxy_laddr4(skb, laddr, iph->daddr);
+ if (!lport)
+ lport = hp->dest;
+
+ /* UDP has no TCP_TIME_WAIT state, so we never enter here */
+ if (sk && sk->sk_state == TCP_TIME_WAIT)
+ /* reopening a TIME_WAIT connection needs special handling */
+ sk = tproxy_handle_time_wait4(skb, laddr, lport, sk);
+ else if (!sk)
+ /* no, there's no established connection, check if
+ * there's a listener on the redirected addr/port */
+ sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
+ iph->saddr, laddr,
+ hp->source, lport,
+ skb->dev, NFT_LOOKUP_LISTENER);
+
+ /* NOTE: assign_sock consumes our sk reference */
+ if (sk && nf_tproxy_assign_sock(skb, sk)) {
+ /* This should be in a separate target, but we don't do multiple
+ targets on the same rule yet */
+ skb->mark = (skb->mark & ~mark_mask) ^ mark_value;
+
+ pr_debug("redirecting: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n",
+ iph->protocol, &iph->daddr, ntohs(hp->dest),
+ &laddr, ntohs(lport), skb->mark);
+ return NF_ACCEPT;
+ }
+
+ pr_debug("no socket, dropping: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n",
+ iph->protocol, &iph->saddr, ntohs(hp->source),
+ &iph->daddr, ntohs(hp->dest), skb->mark);
+ return NF_DROP;
+}
+
+static unsigned int
+tproxy_tg4_v0(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ const struct xt_tproxy_target_info *tgi = par->targinfo;
+
+ return tproxy_tg4(skb, tgi->laddr, tgi->lport, tgi->mark_mask, tgi->mark_value);
+}
+
+static unsigned int
+tproxy_tg4_v1(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
+
+ return tproxy_tg4(skb, tgi->laddr.ip, tgi->lport, tgi->mark_mask, tgi->mark_value);
+}
+
+#ifdef XT_TPROXY_HAVE_IPV6
+
+static inline const struct in6_addr *
+tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr,
+ const struct in6_addr *daddr)
+{
+ struct inet6_dev *indev;
+ struct inet6_ifaddr *ifa;
+ struct in6_addr *laddr;
+
+ if (!ipv6_addr_any(user_laddr))
+ return user_laddr;
+ laddr = NULL;
+
+ rcu_read_lock();
+ indev = __in6_dev_get(skb->dev);
+ if (indev)
+ list_for_each_entry(ifa, &indev->addr_list, if_list) {
+ if (ifa->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))
+ continue;
+
+ laddr = &ifa->addr;
+ break;
+ }
+ rcu_read_unlock();
+
+ return laddr ? laddr : daddr;
+}
+
+/**
+ * tproxy_handle_time_wait6() - handle IPv6 TCP TIME_WAIT reopen redirections
+ * @skb: The skb being processed.
+ * @tproto: Transport protocol.
+ * @thoff: Transport protocol header offset.
+ * @par: Iptables target parameters.
+ * @sk: The TIME_WAIT TCP socket found by the lookup.
+ *
+ * We have to handle SYN packets arriving to TIME_WAIT sockets
+ * differently: instead of reopening the connection we should rather
+ * redirect the new connection to the proxy if there's a listener
+ * socket present.
+ *
+ * tproxy_handle_time_wait6() consumes the socket reference passed in.
+ *
+ * Returns the listener socket if there's one, the TIME_WAIT socket if
+ * no such listener is found, or NULL if the TCP header is incomplete.
+ */
+static struct sock *
+tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff,
+ const struct xt_action_param *par,
+ struct sock *sk)
+{
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
+ struct tcphdr _hdr, *hp;
+ const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
+
+ hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
+ if (hp == NULL) {
+ inet_twsk_put(inet_twsk(sk));
+ return NULL;
+ }
+
+ if (hp->syn && !hp->rst && !hp->ack && !hp->fin) {
+ /* SYN to a TIME_WAIT socket, we'd rather redirect it
+ * to a listener socket if there's one */
+ struct sock *sk2;
+
+ sk2 = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
+ &iph->saddr,
+ tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr),
+ hp->source,
+ tgi->lport ? tgi->lport : hp->dest,
+ skb->dev, NFT_LOOKUP_LISTENER);
+ if (sk2) {
+ inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
+ inet_twsk_put(inet_twsk(sk));
+ sk = sk2;
+ }
+ }
+
+ return sk;
+}
+
+static unsigned int
+tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
+ const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
+ struct udphdr _hdr, *hp;
+ struct sock *sk;
+ const struct in6_addr *laddr;
+ __be16 lport;
+ int thoff;
+ int tproto;
+
+ tproto = ipv6_find_hdr(skb, &thoff, -1, NULL);
+ if (tproto < 0) {
+ pr_debug("unable to find transport header in IPv6 packet, dropping\n");
+ return NF_DROP;
+ }
+
+ hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
+ if (hp == NULL) {
+ pr_debug("unable to grab transport header contents in IPv6 packet, dropping\n");
+ return NF_DROP;
+ }
+
+ /* check if there's an ongoing connection on the packet
+ * addresses, this happens if the redirect already happened
+ * and the current packet belongs to an already established
+ * connection */
+ sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
+ &iph->saddr, &iph->daddr,
+ hp->source, hp->dest,
+ par->in, NFT_LOOKUP_ESTABLISHED);
+
+ laddr = tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr);
+ lport = tgi->lport ? tgi->lport : hp->dest;
+
+ /* UDP has no TCP_TIME_WAIT state, so we never enter here */
+ if (sk && sk->sk_state == TCP_TIME_WAIT)
+ /* reopening a TIME_WAIT connection needs special handling */
+ sk = tproxy_handle_time_wait6(skb, tproto, thoff, par, sk);
+ else if (!sk)
+ /* no there's no established connection, check if
+ * there's a listener on the redirected addr/port */
+ sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
+ &iph->saddr, laddr,
+ hp->source, lport,
+ par->in, NFT_LOOKUP_LISTENER);
/* NOTE: assign_sock consumes our sk reference */
if (sk && nf_tproxy_assign_sock(skb, sk)) {
@@ -49,19 +311,34 @@ tproxy_tg(struct sk_buff *skb, const struct xt_action_param *par)
targets on the same rule yet */
skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value;
- pr_debug("redirecting: proto %u %08x:%u -> %08x:%u, mark: %x\n",
- iph->protocol, ntohl(iph->daddr), ntohs(hp->dest),
- ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark);
+ pr_debug("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
+ tproto, &iph->saddr, ntohs(hp->source),
+ laddr, ntohs(lport), skb->mark);
return NF_ACCEPT;
}
- pr_debug("no socket, dropping: proto %u %08x:%u -> %08x:%u, mark: %x\n",
- iph->protocol, ntohl(iph->daddr), ntohs(hp->dest),
- ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark);
+ pr_debug("no socket, dropping: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
+ tproto, &iph->saddr, ntohs(hp->source),
+ &iph->daddr, ntohs(hp->dest), skb->mark);
+
return NF_DROP;
}
-static int tproxy_tg_check(const struct xt_tgchk_param *par)
+static int tproxy_tg6_check(const struct xt_tgchk_param *par)
+{
+ const struct ip6t_ip6 *i = par->entryinfo;
+
+ if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
+ && !(i->flags & IP6T_INV_PROTO))
+ return 0;
+
+ pr_info("Can be used only in combination with "
+ "either -p tcp or -p udp\n");
+ return -EINVAL;
+}
+#endif
+
+static int tproxy_tg4_check(const struct xt_tgchk_param *par)
{
const struct ipt_ip *i = par->entryinfo;
@@ -74,31 +351,64 @@ static int tproxy_tg_check(const struct xt_tgchk_param *par)
return -EINVAL;
}
-static struct xt_target tproxy_tg_reg __read_mostly = {
- .name = "TPROXY",
- .family = AF_INET,
- .table = "mangle",
- .target = tproxy_tg,
- .targetsize = sizeof(struct xt_tproxy_target_info),
- .checkentry = tproxy_tg_check,
- .hooks = 1 << NF_INET_PRE_ROUTING,
- .me = THIS_MODULE,
+static struct xt_target tproxy_tg_reg[] __read_mostly = {
+ {
+ .name = "TPROXY",
+ .family = NFPROTO_IPV4,
+ .table = "mangle",
+ .target = tproxy_tg4_v0,
+ .revision = 0,
+ .targetsize = sizeof(struct xt_tproxy_target_info),
+ .checkentry = tproxy_tg4_check,
+ .hooks = 1 << NF_INET_PRE_ROUTING,
+ .me = THIS_MODULE,
+ },
+ {
+ .name = "TPROXY",
+ .family = NFPROTO_IPV4,
+ .table = "mangle",
+ .target = tproxy_tg4_v1,
+ .revision = 1,
+ .targetsize = sizeof(struct xt_tproxy_target_info_v1),
+ .checkentry = tproxy_tg4_check,
+ .hooks = 1 << NF_INET_PRE_ROUTING,
+ .me = THIS_MODULE,
+ },
+#ifdef XT_TPROXY_HAVE_IPV6
+ {
+ .name = "TPROXY",
+ .family = NFPROTO_IPV6,
+ .table = "mangle",
+ .target = tproxy_tg6_v1,
+ .revision = 1,
+ .targetsize = sizeof(struct xt_tproxy_target_info_v1),
+ .checkentry = tproxy_tg6_check,
+ .hooks = 1 << NF_INET_PRE_ROUTING,
+ .me = THIS_MODULE,
+ },
+#endif
+
};
static int __init tproxy_tg_init(void)
{
nf_defrag_ipv4_enable();
- return xt_register_target(&tproxy_tg_reg);
+#ifdef XT_TPROXY_HAVE_IPV6
+ nf_defrag_ipv6_enable();
+#endif
+
+ return xt_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg));
}
static void __exit tproxy_tg_exit(void)
{
- xt_unregister_target(&tproxy_tg_reg);
+ xt_unregister_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg));
}
module_init(tproxy_tg_init);
module_exit(tproxy_tg_exit);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Krisztian Kovacs");
+MODULE_AUTHOR("Balazs Scheidler, Krisztian Kovacs");
MODULE_DESCRIPTION("Netfilter transparent proxy (TPROXY) target module.");
MODULE_ALIAS("ipt_TPROXY");
+MODULE_ALIAS("ip6t_TPROXY");
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index b46a8390896d..9228ee0dc11a 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -448,6 +448,7 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
{
__be16 _ports[2], *ports;
u8 nexthdr;
+ int poff;
memset(dst, 0, sizeof(*dst));
@@ -492,19 +493,13 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
return 0;
}
- switch (nexthdr) {
- case IPPROTO_TCP:
- case IPPROTO_UDP:
- case IPPROTO_UDPLITE:
- case IPPROTO_SCTP:
- case IPPROTO_DCCP:
- ports = skb_header_pointer(skb, protoff, sizeof(_ports),
+ poff = proto_ports_offset(nexthdr);
+ if (poff >= 0) {
+ ports = skb_header_pointer(skb, protoff + poff, sizeof(_ports),
&_ports);
- break;
- default:
+ } else {
_ports[0] = _ports[1] = 0;
ports = _ports;
- break;
}
if (!ports)
return -1;
diff --git a/net/netfilter/xt_ipvs.c b/net/netfilter/xt_ipvs.c
index 7a4d66db95ae..9127a3d8aa35 100644
--- a/net/netfilter/xt_ipvs.c
+++ b/net/netfilter/xt_ipvs.c
@@ -16,7 +16,6 @@
#include <linux/ip_vs.h>
#include <linux/types.h>
#include <linux/netfilter/x_tables.h>
-#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_ipvs.h>
#include <net/netfilter/nf_conntrack.h>
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index 1ca89908cbad..d94a858dc52a 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -22,6 +22,12 @@
#include <net/netfilter/nf_tproxy_core.h>
#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+#define XT_SOCKET_HAVE_IPV6 1
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
+#endif
+
#include <linux/netfilter/xt_socket.h>
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
@@ -30,7 +36,7 @@
#endif
static int
-extract_icmp_fields(const struct sk_buff *skb,
+extract_icmp4_fields(const struct sk_buff *skb,
u8 *protocol,
__be32 *raddr,
__be32 *laddr,
@@ -86,7 +92,6 @@ extract_icmp_fields(const struct sk_buff *skb,
return 0;
}
-
static bool
socket_match(const struct sk_buff *skb, struct xt_action_param *par,
const struct xt_socket_mtinfo1 *info)
@@ -115,7 +120,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
dport = hp->dest;
} else if (iph->protocol == IPPROTO_ICMP) {
- if (extract_icmp_fields(skb, &protocol, &saddr, &daddr,
+ if (extract_icmp4_fields(skb, &protocol, &saddr, &daddr,
&sport, &dport))
return false;
} else {
@@ -142,7 +147,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
#endif
sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), protocol,
- saddr, daddr, sport, dport, par->in, false);
+ saddr, daddr, sport, dport, par->in, NFT_LOOKUP_ANY);
if (sk != NULL) {
bool wildcard;
bool transparent = true;
@@ -165,32 +170,157 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
sk = NULL;
}
- pr_debug("proto %u %08x:%u -> %08x:%u (orig %08x:%u) sock %p\n",
- protocol, ntohl(saddr), ntohs(sport),
- ntohl(daddr), ntohs(dport),
- ntohl(iph->daddr), hp ? ntohs(hp->dest) : 0, sk);
+ pr_debug("proto %hhu %pI4:%hu -> %pI4:%hu (orig %pI4:%hu) sock %p\n",
+ protocol, &saddr, ntohs(sport),
+ &daddr, ntohs(dport),
+ &iph->daddr, hp ? ntohs(hp->dest) : 0, sk);
return (sk != NULL);
}
static bool
-socket_mt_v0(const struct sk_buff *skb, struct xt_action_param *par)
+socket_mt4_v0(const struct sk_buff *skb, struct xt_action_param *par)
{
return socket_match(skb, par, NULL);
}
static bool
-socket_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
+socket_mt4_v1(const struct sk_buff *skb, struct xt_action_param *par)
{
return socket_match(skb, par, par->matchinfo);
}
+#ifdef XT_SOCKET_HAVE_IPV6
+
+static int
+extract_icmp6_fields(const struct sk_buff *skb,
+ unsigned int outside_hdrlen,
+ u8 *protocol,
+ struct in6_addr **raddr,
+ struct in6_addr **laddr,
+ __be16 *rport,
+ __be16 *lport)
+{
+ struct ipv6hdr *inside_iph, _inside_iph;
+ struct icmp6hdr *icmph, _icmph;
+ __be16 *ports, _ports[2];
+ u8 inside_nexthdr;
+ int inside_hdrlen;
+
+ icmph = skb_header_pointer(skb, outside_hdrlen,
+ sizeof(_icmph), &_icmph);
+ if (icmph == NULL)
+ return 1;
+
+ if (icmph->icmp6_type & ICMPV6_INFOMSG_MASK)
+ return 1;
+
+ inside_iph = skb_header_pointer(skb, outside_hdrlen + sizeof(_icmph), sizeof(_inside_iph), &_inside_iph);
+ if (inside_iph == NULL)
+ return 1;
+ inside_nexthdr = inside_iph->nexthdr;
+
+ inside_hdrlen = ipv6_skip_exthdr(skb, outside_hdrlen + sizeof(_icmph) + sizeof(_inside_iph), &inside_nexthdr);
+ if (inside_hdrlen < 0)
+ return 1; /* hjm: Packet has no/incomplete transport layer headers. */
+
+ if (inside_nexthdr != IPPROTO_TCP &&
+ inside_nexthdr != IPPROTO_UDP)
+ return 1;
+
+ ports = skb_header_pointer(skb, inside_hdrlen,
+ sizeof(_ports), &_ports);
+ if (ports == NULL)
+ return 1;
+
+ /* the inside IP packet is the one quoted from our side, thus
+ * its saddr is the local address */
+ *protocol = inside_nexthdr;
+ *laddr = &inside_iph->saddr;
+ *lport = ports[0];
+ *raddr = &inside_iph->daddr;
+ *rport = ports[1];
+
+ return 0;
+}
+
+static bool
+socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+ struct udphdr _hdr, *hp = NULL;
+ struct sock *sk;
+ struct in6_addr *daddr, *saddr;
+ __be16 dport, sport;
+ int thoff;
+ u8 tproto;
+ const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
+
+ tproto = ipv6_find_hdr(skb, &thoff, -1, NULL);
+ if (tproto < 0) {
+ pr_debug("unable to find transport header in IPv6 packet, dropping\n");
+ return NF_DROP;
+ }
+
+ if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
+ hp = skb_header_pointer(skb, thoff,
+ sizeof(_hdr), &_hdr);
+ if (hp == NULL)
+ return false;
+
+ saddr = &iph->saddr;
+ sport = hp->source;
+ daddr = &iph->daddr;
+ dport = hp->dest;
+
+ } else if (tproto == IPPROTO_ICMPV6) {
+ if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr,
+ &sport, &dport))
+ return false;
+ } else {
+ return false;
+ }
+
+ sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
+ saddr, daddr, sport, dport, par->in, NFT_LOOKUP_ANY);
+ if (sk != NULL) {
+ bool wildcard;
+ bool transparent = true;
+
+ /* Ignore sockets listening on INADDR_ANY */
+ wildcard = (sk->sk_state != TCP_TIME_WAIT &&
+ ipv6_addr_any(&inet6_sk(sk)->rcv_saddr));
+
+ /* Ignore non-transparent sockets,
+ if XT_SOCKET_TRANSPARENT is used */
+ if (info && info->flags & XT_SOCKET_TRANSPARENT)
+ transparent = ((sk->sk_state != TCP_TIME_WAIT &&
+ inet_sk(sk)->transparent) ||
+ (sk->sk_state == TCP_TIME_WAIT &&
+ inet_twsk(sk)->tw_transparent));
+
+ nf_tproxy_put_sock(sk);
+
+ if (wildcard || !transparent)
+ sk = NULL;
+ }
+
+ pr_debug("proto %hhu %pI6:%hu -> %pI6:%hu "
+ "(orig %pI6:%hu) sock %p\n",
+ tproto, saddr, ntohs(sport),
+ daddr, ntohs(dport),
+ &iph->daddr, hp ? ntohs(hp->dest) : 0, sk);
+
+ return (sk != NULL);
+}
+#endif
+
static struct xt_match socket_mt_reg[] __read_mostly = {
{
.name = "socket",
.revision = 0,
.family = NFPROTO_IPV4,
- .match = socket_mt_v0,
+ .match = socket_mt4_v0,
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN),
.me = THIS_MODULE,
@@ -199,17 +329,33 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.name = "socket",
.revision = 1,
.family = NFPROTO_IPV4,
- .match = socket_mt_v1,
+ .match = socket_mt4_v1,
.matchsize = sizeof(struct xt_socket_mtinfo1),
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN),
.me = THIS_MODULE,
},
+#ifdef XT_SOCKET_HAVE_IPV6
+ {
+ .name = "socket",
+ .revision = 1,
+ .family = NFPROTO_IPV6,
+ .match = socket_mt6_v1,
+ .matchsize = sizeof(struct xt_socket_mtinfo1),
+ .hooks = (1 << NF_INET_PRE_ROUTING) |
+ (1 << NF_INET_LOCAL_IN),
+ .me = THIS_MODULE,
+ },
+#endif
};
static int __init socket_mt_init(void)
{
nf_defrag_ipv4_enable();
+#ifdef XT_SOCKET_HAVE_IPV6
+ nf_defrag_ipv6_enable();
+#endif
+
return xt_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg));
}
@@ -225,3 +371,4 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Krisztian Kovacs, Balazs Scheidler");
MODULE_DESCRIPTION("x_tables socket match module");
MODULE_ALIAS("ipt_socket");
+MODULE_ALIAS("ip6t_socket");
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index cd96ed3ccee4..478181d53c55 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -83,9 +83,9 @@ struct netlink_sock {
struct module *module;
};
-struct listeners_rcu_head {
- struct rcu_head rcu_head;
- void *ptr;
+struct listeners {
+ struct rcu_head rcu;
+ unsigned long masks[0];
};
#define NETLINK_KERNEL_SOCKET 0x1
@@ -119,7 +119,7 @@ struct nl_pid_hash {
struct netlink_table {
struct nl_pid_hash hash;
struct hlist_head mc_list;
- unsigned long *listeners;
+ struct listeners __rcu *listeners;
unsigned int nl_nonroot;
unsigned int groups;
struct mutex *cb_mutex;
@@ -338,7 +338,7 @@ netlink_update_listeners(struct sock *sk)
if (i < NLGRPLONGS(nlk_sk(sk)->ngroups))
mask |= nlk_sk(sk)->groups[i];
}
- tbl->listeners[i] = mask;
+ tbl->listeners->masks[i] = mask;
}
/* this function is only called with the netlink table "grabbed", which
* makes sure updates are visible before bind or setsockopt return. */
@@ -936,7 +936,7 @@ EXPORT_SYMBOL(netlink_unicast);
int netlink_has_listeners(struct sock *sk, unsigned int group)
{
int res = 0;
- unsigned long *listeners;
+ struct listeners *listeners;
BUG_ON(!netlink_is_kernel(sk));
@@ -944,7 +944,7 @@ int netlink_has_listeners(struct sock *sk, unsigned int group)
listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners);
if (group - 1 < nl_table[sk->sk_protocol].groups)
- res = test_bit(group - 1, listeners);
+ res = test_bit(group - 1, listeners->masks);
rcu_read_unlock();
@@ -1498,7 +1498,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
struct socket *sock;
struct sock *sk;
struct netlink_sock *nlk;
- unsigned long *listeners = NULL;
+ struct listeners *listeners = NULL;
BUG_ON(!nl_table);
@@ -1523,8 +1523,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
if (groups < 32)
groups = 32;
- listeners = kzalloc(NLGRPSZ(groups) + sizeof(struct listeners_rcu_head),
- GFP_KERNEL);
+ listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL);
if (!listeners)
goto out_sock_release;
@@ -1541,7 +1540,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
netlink_table_grab();
if (!nl_table[unit].registered) {
nl_table[unit].groups = groups;
- nl_table[unit].listeners = listeners;
+ rcu_assign_pointer(nl_table[unit].listeners, listeners);
nl_table[unit].cb_mutex = cb_mutex;
nl_table[unit].module = module;
nl_table[unit].registered = 1;
@@ -1572,43 +1571,28 @@ netlink_kernel_release(struct sock *sk)
EXPORT_SYMBOL(netlink_kernel_release);
-static void netlink_free_old_listeners(struct rcu_head *rcu_head)
+static void listeners_free_rcu(struct rcu_head *head)
{
- struct listeners_rcu_head *lrh;
-
- lrh = container_of(rcu_head, struct listeners_rcu_head, rcu_head);
- kfree(lrh->ptr);
+ kfree(container_of(head, struct listeners, rcu));
}
int __netlink_change_ngroups(struct sock *sk, unsigned int groups)
{
- unsigned long *listeners, *old = NULL;
- struct listeners_rcu_head *old_rcu_head;
+ struct listeners *new, *old;
struct netlink_table *tbl = &nl_table[sk->sk_protocol];
if (groups < 32)
groups = 32;
if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) {
- listeners = kzalloc(NLGRPSZ(groups) +
- sizeof(struct listeners_rcu_head),
- GFP_ATOMIC);
- if (!listeners)
+ new = kzalloc(sizeof(*new) + NLGRPSZ(groups), GFP_ATOMIC);
+ if (!new)
return -ENOMEM;
- old = tbl->listeners;
- memcpy(listeners, old, NLGRPSZ(tbl->groups));
- rcu_assign_pointer(tbl->listeners, listeners);
- /*
- * Free the old memory after an RCU grace period so we
- * don't leak it. We use call_rcu() here in order to be
- * able to call this function from atomic contexts. The
- * allocation of this memory will have reserved enough
- * space for struct listeners_rcu_head at the end.
- */
- old_rcu_head = (void *)(tbl->listeners +
- NLGRPLONGS(tbl->groups));
- old_rcu_head->ptr = old;
- call_rcu(&old_rcu_head->rcu_head, netlink_free_old_listeners);
+ old = rcu_dereference_raw(tbl->listeners);
+ memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups));
+ rcu_assign_pointer(tbl->listeners, new);
+
+ call_rcu(&old->rcu, listeners_free_rcu);
}
tbl->groups = groups;
@@ -2104,18 +2088,17 @@ static void __net_exit netlink_net_exit(struct net *net)
static void __init netlink_add_usersock_entry(void)
{
- unsigned long *listeners;
+ struct listeners *listeners;
int groups = 32;
- listeners = kzalloc(NLGRPSZ(groups) + sizeof(struct listeners_rcu_head),
- GFP_KERNEL);
+ listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL);
if (!listeners)
- panic("netlink_add_usersock_entry: Cannot allocate listneres\n");
+ panic("netlink_add_usersock_entry: Cannot allocate listeners\n");
netlink_table_grab();
nl_table[NETLINK_USERSOCK].groups = groups;
- nl_table[NETLINK_USERSOCK].listeners = listeners;
+ rcu_assign_pointer(nl_table[NETLINK_USERSOCK].listeners, listeners);
nl_table[NETLINK_USERSOCK].module = THIS_MODULE;
nl_table[NETLINK_USERSOCK].registered = 1;
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 26ed3e8587c2..1781d99145e2 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -547,8 +547,20 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
info.attrs = family->attrbuf;
genl_info_net_set(&info, net);
+ memset(&info.user_ptr, 0, sizeof(info.user_ptr));
- return ops->doit(skb, &info);
+ if (family->pre_doit) {
+ err = family->pre_doit(ops, skb, &info);
+ if (err)
+ return err;
+ }
+
+ err = ops->doit(skb, &info);
+
+ if (family->post_doit)
+ family->post_doit(ops, skb, &info);
+
+ return err;
}
static void genl_rcv(struct sk_buff *skb)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 9a17f28b1253..3616f27b9d46 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -488,7 +488,7 @@ retry:
skb->dev = dev;
skb->priority = sk->sk_priority;
skb->mark = sk->sk_mark;
- err = sock_tx_timestamp(msg, sk, skb_tx(skb));
+ err = sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
if (err < 0)
goto out_unlock;
@@ -1209,7 +1209,7 @@ static int packet_snd(struct socket *sock,
err = skb_copy_datagram_from_iovec(skb, offset, msg->msg_iov, 0, len);
if (err)
goto out_free;
- err = sock_tx_timestamp(msg, sk, skb_tx(skb));
+ err = sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
if (err < 0)
goto out_free;
diff --git a/net/phonet/Kconfig b/net/phonet/Kconfig
index 6ec7d55b1769..0d9b8a220a78 100644
--- a/net/phonet/Kconfig
+++ b/net/phonet/Kconfig
@@ -14,3 +14,15 @@ config PHONET
To compile this driver as a module, choose M here: the module
will be called phonet. If unsure, say N.
+
+config PHONET_PIPECTRLR
+ bool "Phonet Pipe Controller (EXPERIMENTAL)"
+ depends on PHONET && EXPERIMENTAL
+ default N
+ help
+ The Pipe Controller implementation in Phonet stack to support Pipe
+ data with Nokia Slim modems like WG2.5 used on ST-Ericsson U8500
+ platform.
+
+ This option is incompatible with older Nokia modems.
+ Say N here unless you really know what you are doing.
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c
index 73aee7f2fcdc..fd95beb72f5d 100644
--- a/net/phonet/af_phonet.c
+++ b/net/phonet/af_phonet.c
@@ -251,6 +251,16 @@ int pn_skb_send(struct sock *sk, struct sk_buff *skb,
else if (phonet_address_lookup(net, daddr) == 0) {
dev = phonet_device_get(net);
skb->pkt_type = PACKET_LOOPBACK;
+ } else if (pn_sockaddr_get_object(target) == 0) {
+ /* Resource routing (small race until phonet_rcv()) */
+ struct sock *sk = pn_find_sock_by_res(net,
+ target->spn_resource);
+ if (sk) {
+ sock_put(sk);
+ dev = phonet_device_get(net);
+ skb->pkt_type = PACKET_LOOPBACK;
+ } else
+ dev = phonet_route_output(net, daddr);
} else
dev = phonet_route_output(net, daddr);
@@ -383,6 +393,13 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
goto out;
}
+ /* resource routing */
+ if (pn_sockaddr_get_object(&sa) == 0) {
+ struct sock *sk = pn_find_sock_by_res(net, sa.spn_resource);
+ if (sk)
+ return sk_receive_skb(sk, skb, 0);
+ }
+
/* check if we are the destination */
if (phonet_address_lookup(net, pn_sockaddr_get_addr(&sa)) == 0) {
/* Phonet packet input */
diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c
index 1bd38db4fe1e..2f032381bd45 100644
--- a/net/phonet/datagram.c
+++ b/net/phonet/datagram.c
@@ -52,6 +52,19 @@ static int pn_ioctl(struct sock *sk, int cmd, unsigned long arg)
answ = skb ? skb->len : 0;
release_sock(sk);
return put_user(answ, (int __user *)arg);
+
+ case SIOCPNADDRESOURCE:
+ case SIOCPNDELRESOURCE: {
+ u32 res;
+ if (get_user(res, (u32 __user *)arg))
+ return -EFAULT;
+ if (res >= 256)
+ return -EINVAL;
+ if (cmd == SIOCPNADDRESOURCE)
+ return pn_sock_bind_res(sk, res);
+ else
+ return pn_sock_unbind_res(sk, res);
+ }
}
return -ENOIOCTLCMD;
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index 15003021f4f0..3e60f2e4e6c2 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -109,6 +109,210 @@ static int pep_reply(struct sock *sk, struct sk_buff *oskb,
}
#define PAD 0x00
+
+#ifdef CONFIG_PHONET_PIPECTRLR
+static u8 pipe_negotiate_fc(u8 *host_fc, u8 *remote_fc, int len)
+{
+ int i, j;
+ u8 base_fc, final_fc;
+
+ for (i = 0; i < len; i++) {
+ base_fc = host_fc[i];
+ for (j = 0; j < len; j++) {
+ if (remote_fc[j] == base_fc) {
+ final_fc = base_fc;
+ goto done;
+ }
+ }
+ }
+ return -EINVAL;
+
+done:
+ return final_fc;
+
+}
+
+static int pipe_get_flow_info(struct sock *sk, struct sk_buff *skb,
+ u8 *pref_rx_fc, u8 *req_tx_fc)
+{
+ struct pnpipehdr *hdr;
+ u8 n_sb;
+
+ if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
+ return -EINVAL;
+
+ hdr = pnp_hdr(skb);
+ n_sb = hdr->data[4];
+
+ __skb_pull(skb, sizeof(*hdr) + 4);
+ while (n_sb > 0) {
+ u8 type, buf[3], len = sizeof(buf);
+ u8 *data = pep_get_sb(skb, &type, &len, buf);
+
+ if (data == NULL)
+ return -EINVAL;
+
+ switch (type) {
+ case PN_PIPE_SB_REQUIRED_FC_TX:
+ if (len < 3 || (data[2] | data[3] | data[4]) > 3)
+ break;
+ req_tx_fc[0] = data[2];
+ req_tx_fc[1] = data[3];
+ req_tx_fc[2] = data[4];
+ break;
+
+ case PN_PIPE_SB_PREFERRED_FC_RX:
+ if (len < 3 || (data[2] | data[3] | data[4]) > 3)
+ break;
+ pref_rx_fc[0] = data[2];
+ pref_rx_fc[1] = data[3];
+ pref_rx_fc[2] = data[4];
+ break;
+
+ }
+ n_sb--;
+ }
+ return 0;
+}
+
+static int pipe_handler_send_req(struct sock *sk, u8 utid,
+ u8 msg_id, gfp_t priority)
+{
+ int len;
+ struct pnpipehdr *ph;
+ struct sk_buff *skb;
+ struct pep_sock *pn = pep_sk(sk);
+
+ static const u8 data[4] = {
+ PAD, PAD, PAD, PAD,
+ };
+
+ switch (msg_id) {
+ case PNS_PEP_CONNECT_REQ:
+ len = sizeof(data);
+ break;
+
+ case PNS_PEP_DISCONNECT_REQ:
+ case PNS_PEP_ENABLE_REQ:
+ case PNS_PEP_DISABLE_REQ:
+ len = 0;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority);
+ if (!skb)
+ return -ENOMEM;
+ skb_set_owner_w(skb, sk);
+
+ skb_reserve(skb, MAX_PNPIPE_HEADER);
+ if (len) {
+ __skb_put(skb, len);
+ skb_copy_to_linear_data(skb, data, len);
+ }
+ __skb_push(skb, sizeof(*ph));
+ skb_reset_transport_header(skb);
+ ph = pnp_hdr(skb);
+ ph->utid = utid;
+ ph->message_id = msg_id;
+ ph->pipe_handle = pn->pipe_handle;
+ ph->error_code = PN_PIPE_NO_ERROR;
+
+ return pn_skb_send(sk, skb, &pn->remote_pep);
+}
+
+static int pipe_handler_send_created_ind(struct sock *sk,
+ u8 utid, u8 msg_id)
+{
+ int err_code;
+ struct pnpipehdr *ph;
+ struct sk_buff *skb;
+
+ struct pep_sock *pn = pep_sk(sk);
+ static u8 data[4] = {
+ 0x03, 0x04,
+ };
+ data[2] = pn->tx_fc;
+ data[3] = pn->rx_fc;
+
+ /*
+ * actually, below is number of sub-blocks and not error code.
+ * Pipe_created_ind message format does not have any
+ * error code field. However, the Phonet stack will always send
+ * an error code as part of pnpipehdr. So, use that err_code to
+ * specify the number of sub-blocks.
+ */
+ err_code = 0x01;
+
+ skb = alloc_skb(MAX_PNPIPE_HEADER + sizeof(data), GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+ skb_set_owner_w(skb, sk);
+
+ skb_reserve(skb, MAX_PNPIPE_HEADER);
+ __skb_put(skb, sizeof(data));
+ skb_copy_to_linear_data(skb, data, sizeof(data));
+ __skb_push(skb, sizeof(*ph));
+ skb_reset_transport_header(skb);
+ ph = pnp_hdr(skb);
+ ph->utid = utid;
+ ph->message_id = msg_id;
+ ph->pipe_handle = pn->pipe_handle;
+ ph->error_code = err_code;
+
+ return pn_skb_send(sk, skb, &pn->remote_pep);
+}
+
+static int pipe_handler_send_ind(struct sock *sk, u8 utid, u8 msg_id)
+{
+ int err_code;
+ struct pnpipehdr *ph;
+ struct sk_buff *skb;
+ struct pep_sock *pn = pep_sk(sk);
+
+ /*
+ * actually, below is a filler.
+ * Pipe_enabled/disabled_ind message format does not have any
+ * error code field. However, the Phonet stack will always send
+ * an error code as part of pnpipehdr. So, use that err_code to
+ * specify the filler value.
+ */
+ err_code = 0x0;
+
+ skb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+ skb_set_owner_w(skb, sk);
+
+ skb_reserve(skb, MAX_PNPIPE_HEADER);
+ __skb_push(skb, sizeof(*ph));
+ skb_reset_transport_header(skb);
+ ph = pnp_hdr(skb);
+ ph->utid = utid;
+ ph->message_id = msg_id;
+ ph->pipe_handle = pn->pipe_handle;
+ ph->error_code = err_code;
+
+ return pn_skb_send(sk, skb, &pn->remote_pep);
+}
+
+static int pipe_handler_enable_pipe(struct sock *sk, int enable)
+{
+ int utid, req;
+
+ if (enable) {
+ utid = PNS_PIPE_ENABLE_UTID;
+ req = PNS_PEP_ENABLE_REQ;
+ } else {
+ utid = PNS_PIPE_DISABLE_UTID;
+ req = PNS_PEP_DISABLE_REQ;
+ }
+ return pipe_handler_send_req(sk, utid, req, GFP_ATOMIC);
+}
+#endif
+
static int pep_accept_conn(struct sock *sk, struct sk_buff *skb)
{
static const u8 data[20] = {
@@ -192,7 +396,11 @@ static int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority)
ph->data[3] = PAD;
ph->data[4] = status;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ return pn_skb_send(sk, skb, &pn->remote_pep);
+#else
return pn_skb_send(sk, skb, &pipe_srv);
+#endif
}
/* Send our RX flow control information to the sender.
@@ -324,11 +532,35 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
sk->sk_state_change(sk);
break;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ case PNS_PEP_DISCONNECT_RESP:
+ pn->pipe_state = PIPE_IDLE;
+ sk->sk_state = TCP_CLOSE;
+ break;
+#endif
+
case PNS_PEP_ENABLE_REQ:
/* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */
pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
break;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ case PNS_PEP_ENABLE_RESP:
+ pn->pipe_state = PIPE_ENABLED;
+ pipe_handler_send_ind(sk, PNS_PIPE_ENABLED_IND_UTID,
+ PNS_PIPE_ENABLED_IND);
+
+ if (!pn_flow_safe(pn->tx_fc)) {
+ atomic_set(&pn->tx_credits, 1);
+ sk->sk_write_space(sk);
+ }
+ if (sk->sk_state == TCP_ESTABLISHED)
+ break; /* Nothing to do */
+ sk->sk_state = TCP_ESTABLISHED;
+ pipe_grant_credits(sk);
+ break;
+#endif
+
case PNS_PEP_RESET_REQ:
switch (hdr->state_after_reset) {
case PN_PIPE_DISABLE:
@@ -347,6 +579,17 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
break;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ case PNS_PEP_DISABLE_RESP:
+ pn->pipe_state = PIPE_DISABLED;
+ atomic_set(&pn->tx_credits, 0);
+ pipe_handler_send_ind(sk, PNS_PIPE_DISABLED_IND_UTID,
+ PNS_PIPE_DISABLED_IND);
+ sk->sk_state = TCP_SYN_RECV;
+ pn->rx_credits = 0;
+ break;
+#endif
+
case PNS_PEP_CTRL_REQ:
if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) {
atomic_inc(&sk->sk_drops);
@@ -438,6 +681,42 @@ static void pipe_destruct(struct sock *sk)
skb_queue_purge(&pn->ctrlreq_queue);
}
+#ifdef CONFIG_PHONET_PIPECTRLR
+static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb)
+{
+ struct pep_sock *pn = pep_sk(sk);
+ u8 host_pref_rx_fc[3] = {3, 2, 1}, host_req_tx_fc[3] = {3, 2, 1};
+ u8 remote_pref_rx_fc[3], remote_req_tx_fc[3];
+ u8 negotiated_rx_fc, negotiated_tx_fc;
+ int ret;
+
+ pipe_get_flow_info(sk, skb, remote_pref_rx_fc,
+ remote_req_tx_fc);
+ negotiated_tx_fc = pipe_negotiate_fc(remote_req_tx_fc,
+ host_pref_rx_fc,
+ sizeof(host_pref_rx_fc));
+ negotiated_rx_fc = pipe_negotiate_fc(host_req_tx_fc,
+ remote_pref_rx_fc,
+ sizeof(host_pref_rx_fc));
+
+ pn->pipe_state = PIPE_DISABLED;
+ sk->sk_state = TCP_SYN_RECV;
+ sk->sk_backlog_rcv = pipe_do_rcv;
+ sk->sk_destruct = pipe_destruct;
+ pn->rx_credits = 0;
+ pn->rx_fc = negotiated_rx_fc;
+ pn->tx_fc = negotiated_tx_fc;
+ sk->sk_state_change(sk);
+
+ ret = pipe_handler_send_created_ind(sk,
+ PNS_PIPE_CREATED_IND_UTID,
+ PNS_PIPE_CREATED_IND
+ );
+
+ return ret;
+}
+#endif
+
static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
{
struct sock *newsk;
@@ -601,6 +880,12 @@ static int pep_do_rcv(struct sock *sk, struct sk_buff *skb)
err = pep_connreq_rcv(sk, skb);
break;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ case PNS_PEP_CONNECT_RESP:
+ err = pep_connresp_rcv(sk, skb);
+ break;
+#endif
+
case PNS_PEP_DISCONNECT_REQ:
pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
break;
@@ -621,6 +906,28 @@ drop:
return err;
}
+static int pipe_do_remove(struct sock *sk)
+{
+ struct pep_sock *pn = pep_sk(sk);
+ struct pnpipehdr *ph;
+ struct sk_buff *skb;
+
+ skb = alloc_skb(MAX_PNPIPE_HEADER, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ skb_reserve(skb, MAX_PNPIPE_HEADER);
+ __skb_push(skb, sizeof(*ph));
+ skb_reset_transport_header(skb);
+ ph = pnp_hdr(skb);
+ ph->utid = 0;
+ ph->message_id = PNS_PIPE_REMOVE_REQ;
+ ph->pipe_handle = pn->pipe_handle;
+ ph->data[0] = PAD;
+
+ return pn_skb_send(sk, skb, &pipe_srv);
+}
+
/* associated socket ceases to exist */
static void pep_sock_close(struct sock *sk, long timeout)
{
@@ -639,7 +946,22 @@ static void pep_sock_close(struct sock *sk, long timeout)
sk_for_each_safe(sknode, p, n, &pn->ackq)
sk_del_node_init(sknode);
sk->sk_state = TCP_CLOSE;
+ } else if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED))
+ /* Forcefully remove dangling Phonet pipe */
+ pipe_do_remove(sk);
+
+#ifdef CONFIG_PHONET_PIPECTRLR
+ if (pn->pipe_state != PIPE_IDLE) {
+ /* send pep disconnect request */
+ pipe_handler_send_req(sk,
+ PNS_PEP_DISCONNECT_UTID, PNS_PEP_DISCONNECT_REQ,
+ GFP_KERNEL);
+
+ pn->pipe_state = PIPE_IDLE;
+ sk->sk_state = TCP_CLOSE;
}
+#endif
+
ifindex = pn->ifindex;
pn->ifindex = 0;
release_sock(sk);
@@ -716,6 +1038,20 @@ out:
return newsk;
}
+#ifdef CONFIG_PHONET_PIPECTRLR
+static int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len)
+{
+ struct pep_sock *pn = pep_sk(sk);
+ struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
+
+ memcpy(&pn->remote_pep, spn, sizeof(struct sockaddr_pn));
+
+ return pipe_handler_send_req(sk,
+ PNS_PEP_CONNECT_UTID, PNS_PEP_CONNECT_REQ,
+ GFP_ATOMIC);
+}
+#endif
+
static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
struct pep_sock *pn = pep_sk(sk);
@@ -767,6 +1103,18 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
lock_sock(sk);
switch (optname) {
+#ifdef CONFIG_PHONET_PIPECTRLR
+ case PNPIPE_PIPE_HANDLE:
+ if (val) {
+ if (pn->pipe_state > PIPE_IDLE) {
+ err = -EFAULT;
+ break;
+ }
+ pn->pipe_handle = val;
+ break;
+ }
+#endif
+
case PNPIPE_ENCAP:
if (val && val != PNPIPE_ENCAP_IP) {
err = -EINVAL;
@@ -792,6 +1140,17 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
err = 0;
}
goto out_norel;
+
+#ifdef CONFIG_PHONET_PIPECTRLR
+ case PNPIPE_ENABLE:
+ if (pn->pipe_state <= PIPE_IDLE) {
+ err = -ENOTCONN;
+ break;
+ }
+ err = pipe_handler_enable_pipe(sk, val);
+ break;
+#endif
+
default:
err = -ENOPROTOOPT;
}
@@ -816,9 +1175,19 @@ static int pep_getsockopt(struct sock *sk, int level, int optname,
case PNPIPE_ENCAP:
val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE;
break;
+
case PNPIPE_IFINDEX:
val = pn->ifindex;
break;
+
+#ifdef CONFIG_PHONET_PIPECTRLR
+ case PNPIPE_ENABLE:
+ if (pn->pipe_state <= PIPE_IDLE)
+ return -ENOTCONN;
+ val = pn->pipe_state != PIPE_DISABLED;
+ break;
+#endif
+
default:
return -ENOPROTOOPT;
}
@@ -835,6 +1204,7 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
{
struct pep_sock *pn = pep_sk(sk);
struct pnpipehdr *ph;
+ int err;
if (pn_flow_safe(pn->tx_fc) &&
!atomic_add_unless(&pn->tx_credits, -1, 0)) {
@@ -852,8 +1222,16 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
} else
ph->message_id = PNS_PIPE_DATA;
ph->pipe_handle = pn->pipe_handle;
+#ifdef CONFIG_PHONET_PIPECTRLR
+ err = pn_skb_send(sk, skb, &pn->remote_pep);
+#else
+ err = pn_skb_send(sk, skb, &pipe_srv);
+#endif
+
+ if (err && pn_flow_safe(pn->tx_fc))
+ atomic_inc(&pn->tx_credits);
+ return err;
- return pn_skb_send(sk, skb, &pipe_srv);
}
static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
@@ -873,7 +1251,7 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len,
flags & MSG_DONTWAIT, &err);
if (!skb)
- return -ENOBUFS;
+ return err;
skb_reserve(skb, MAX_PHONET_HEADER + 3);
err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
@@ -1045,6 +1423,8 @@ static void pep_sock_unhash(struct sock *sk)
struct sock *skparent = NULL;
lock_sock(sk);
+
+#ifndef CONFIG_PHONET_PIPECTRLR
if ((1 << sk->sk_state) & ~(TCPF_CLOSE|TCPF_LISTEN)) {
skparent = pn->listener;
release_sock(sk);
@@ -1054,6 +1434,7 @@ static void pep_sock_unhash(struct sock *sk)
sk_del_node_init(sk);
sk = skparent;
}
+#endif
/* Unhash a listening sock only when it is closed
* and all of its active connected pipes are closed. */
if (hlist_empty(&pn->hlist))
@@ -1067,6 +1448,9 @@ static void pep_sock_unhash(struct sock *sk)
static struct proto pep_proto = {
.close = pep_sock_close,
.accept = pep_sock_accept,
+#ifdef CONFIG_PHONET_PIPECTRLR
+ .connect = pep_sock_connect,
+#endif
.ioctl = pep_ioctl,
.init = pep_init,
.setsockopt = pep_setsockopt,
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index b18e48fae975..947038ddd04c 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -292,8 +292,7 @@ static void phonet_route_autodel(struct net_device *dev)
if (bitmap_empty(deleted, 64))
return; /* short-circuit RCU */
synchronize_rcu();
- for (i = find_first_bit(deleted, 64); i < 64;
- i = find_next_bit(deleted, 64, i + 1)) {
+ for_each_set_bit(i, deleted, 64) {
rtm_phonet_notify(RTM_DELROUTE, dev, i);
dev_put(dev);
}
@@ -374,6 +373,7 @@ int __init phonet_device_init(void)
if (err)
return err;
+ proc_net_fops_create(&init_net, "pnresource", 0, &pn_res_seq_fops);
register_netdevice_notifier(&phonet_device_notifier);
err = phonet_netlink_register();
if (err)
@@ -386,6 +386,7 @@ void phonet_device_exit(void)
rtnl_unregister_all(PF_PHONET);
unregister_netdevice_notifier(&phonet_device_notifier);
unregister_pernet_device(&phonet_net_ops);
+ proc_net_remove(&init_net, "pnresource");
}
int phonet_route_add(struct net_device *dev, u8 daddr)
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 6e9848bf0370..25f746d20c1f 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -158,6 +158,7 @@ void pn_sock_unhash(struct sock *sk)
spin_lock_bh(&pnsocks.lock);
sk_del_node_init(sk);
spin_unlock_bh(&pnsocks.lock);
+ pn_sock_unbind_all_res(sk);
}
EXPORT_SYMBOL(pn_sock_unhash);
@@ -224,6 +225,101 @@ static int pn_socket_autobind(struct socket *sock)
return 0; /* socket was already bound */
}
+#ifdef CONFIG_PHONET_PIPECTRLR
+static int pn_socket_connect(struct socket *sock, struct sockaddr *addr,
+ int len, int flags)
+{
+ struct sock *sk = sock->sk;
+ struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
+ long timeo;
+ int err;
+
+ if (len < sizeof(struct sockaddr_pn))
+ return -EINVAL;
+ if (spn->spn_family != AF_PHONET)
+ return -EAFNOSUPPORT;
+
+ lock_sock(sk);
+
+ switch (sock->state) {
+ case SS_UNCONNECTED:
+ sk->sk_state = TCP_CLOSE;
+ break;
+ case SS_CONNECTING:
+ switch (sk->sk_state) {
+ case TCP_SYN_RECV:
+ sock->state = SS_CONNECTED;
+ err = -EISCONN;
+ goto out;
+ case TCP_CLOSE:
+ err = -EALREADY;
+ if (flags & O_NONBLOCK)
+ goto out;
+ goto wait_connect;
+ }
+ break;
+ case SS_CONNECTED:
+ switch (sk->sk_state) {
+ case TCP_SYN_RECV:
+ err = -EISCONN;
+ goto out;
+ case TCP_CLOSE:
+ sock->state = SS_UNCONNECTED;
+ break;
+ }
+ break;
+ case SS_DISCONNECTING:
+ case SS_FREE:
+ break;
+ }
+ sk->sk_state = TCP_CLOSE;
+ sk_stream_kill_queues(sk);
+
+ sock->state = SS_CONNECTING;
+ err = sk->sk_prot->connect(sk, addr, len);
+ if (err < 0) {
+ sock->state = SS_UNCONNECTED;
+ sk->sk_state = TCP_CLOSE;
+ goto out;
+ }
+
+ err = -EINPROGRESS;
+wait_connect:
+ if (sk->sk_state != TCP_SYN_RECV && (flags & O_NONBLOCK))
+ goto out;
+
+ timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
+ release_sock(sk);
+
+ err = -ERESTARTSYS;
+ timeo = wait_event_interruptible_timeout(*sk_sleep(sk),
+ sk->sk_state != TCP_CLOSE,
+ timeo);
+
+ lock_sock(sk);
+ if (timeo < 0)
+ goto out; /* -ERESTARTSYS */
+
+ err = -ETIMEDOUT;
+ if (timeo == 0 && sk->sk_state != TCP_SYN_RECV)
+ goto out;
+
+ if (sk->sk_state != TCP_SYN_RECV) {
+ sock->state = SS_UNCONNECTED;
+ err = sock_error(sk);
+ if (!err)
+ err = -ECONNREFUSED;
+ goto out;
+ }
+ sock->state = SS_CONNECTED;
+ err = 0;
+
+out:
+ release_sock(sk);
+ return err;
+}
+#endif
+
static int pn_socket_accept(struct socket *sock, struct socket *newsock,
int flags)
{
@@ -281,7 +377,9 @@ static unsigned int pn_socket_poll(struct file *file, struct socket *sock,
if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
return POLLHUP;
- if (sk->sk_state == TCP_ESTABLISHED && atomic_read(&pn->tx_credits))
+ if (sk->sk_state == TCP_ESTABLISHED &&
+ atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf &&
+ atomic_read(&pn->tx_credits))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
return mask;
@@ -390,7 +488,11 @@ const struct proto_ops phonet_stream_ops = {
.owner = THIS_MODULE,
.release = pn_socket_release,
.bind = pn_socket_bind,
+#ifdef CONFIG_PHONET_PIPECTRLR
+ .connect = pn_socket_connect,
+#else
.connect = sock_no_connect,
+#endif
.socketpair = sock_no_socketpair,
.accept = pn_socket_accept,
.getname = pn_socket_getname,
@@ -563,3 +665,188 @@ const struct file_operations pn_sock_seq_fops = {
.release = seq_release_net,
};
#endif
+
+static struct {
+ struct sock *sk[256];
+} pnres;
+
+/*
+ * Find and hold socket based on resource.
+ */
+struct sock *pn_find_sock_by_res(struct net *net, u8 res)
+{
+ struct sock *sk;
+
+ if (!net_eq(net, &init_net))
+ return NULL;
+
+ rcu_read_lock();
+ sk = rcu_dereference(pnres.sk[res]);
+ if (sk)
+ sock_hold(sk);
+ rcu_read_unlock();
+ return sk;
+}
+
+static DEFINE_MUTEX(resource_mutex);
+
+int pn_sock_bind_res(struct sock *sk, u8 res)
+{
+ int ret = -EADDRINUSE;
+
+ if (!net_eq(sock_net(sk), &init_net))
+ return -ENOIOCTLCMD;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (pn_socket_autobind(sk->sk_socket))
+ return -EAGAIN;
+
+ mutex_lock(&resource_mutex);
+ if (pnres.sk[res] == NULL) {
+ sock_hold(sk);
+ rcu_assign_pointer(pnres.sk[res], sk);
+ ret = 0;
+ }
+ mutex_unlock(&resource_mutex);
+ return ret;
+}
+
+int pn_sock_unbind_res(struct sock *sk, u8 res)
+{
+ int ret = -ENOENT;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ mutex_lock(&resource_mutex);
+ if (pnres.sk[res] == sk) {
+ rcu_assign_pointer(pnres.sk[res], NULL);
+ ret = 0;
+ }
+ mutex_unlock(&resource_mutex);
+
+ if (ret == 0) {
+ synchronize_rcu();
+ sock_put(sk);
+ }
+ return ret;
+}
+
+void pn_sock_unbind_all_res(struct sock *sk)
+{
+ unsigned res, match = 0;
+
+ mutex_lock(&resource_mutex);
+ for (res = 0; res < 256; res++) {
+ if (pnres.sk[res] == sk) {
+ rcu_assign_pointer(pnres.sk[res], NULL);
+ match++;
+ }
+ }
+ mutex_unlock(&resource_mutex);
+
+ if (match == 0)
+ return;
+ synchronize_rcu();
+ while (match > 0) {
+ sock_put(sk);
+ match--;
+ }
+}
+
+#ifdef CONFIG_PROC_FS
+static struct sock **pn_res_get_idx(struct seq_file *seq, loff_t pos)
+{
+ struct net *net = seq_file_net(seq);
+ unsigned i;
+
+ if (!net_eq(net, &init_net))
+ return NULL;
+
+ for (i = 0; i < 256; i++) {
+ if (pnres.sk[i] == NULL)
+ continue;
+ if (!pos)
+ return pnres.sk + i;
+ pos--;
+ }
+ return NULL;
+}
+
+static struct sock **pn_res_get_next(struct seq_file *seq, struct sock **sk)
+{
+ struct net *net = seq_file_net(seq);
+ unsigned i;
+
+ BUG_ON(!net_eq(net, &init_net));
+
+ for (i = (sk - pnres.sk) + 1; i < 256; i++)
+ if (pnres.sk[i])
+ return pnres.sk + i;
+ return NULL;
+}
+
+static void *pn_res_seq_start(struct seq_file *seq, loff_t *pos)
+ __acquires(resource_mutex)
+{
+ mutex_lock(&resource_mutex);
+ return *pos ? pn_res_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
+}
+
+static void *pn_res_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct sock **sk;
+
+ if (v == SEQ_START_TOKEN)
+ sk = pn_res_get_idx(seq, 0);
+ else
+ sk = pn_res_get_next(seq, v);
+ (*pos)++;
+ return sk;
+}
+
+static void pn_res_seq_stop(struct seq_file *seq, void *v)
+ __releases(resource_mutex)
+{
+ mutex_unlock(&resource_mutex);
+}
+
+static int pn_res_seq_show(struct seq_file *seq, void *v)
+{
+ int len;
+
+ if (v == SEQ_START_TOKEN)
+ seq_printf(seq, "%s%n", "rs uid inode", &len);
+ else {
+ struct sock **psk = v;
+ struct sock *sk = *psk;
+
+ seq_printf(seq, "%02X %5d %lu%n",
+ (int) (psk - pnres.sk), sock_i_uid(sk),
+ sock_i_ino(sk), &len);
+ }
+ seq_printf(seq, "%*s\n", 63 - len, "");
+ return 0;
+}
+
+static const struct seq_operations pn_res_seq_ops = {
+ .start = pn_res_seq_start,
+ .next = pn_res_seq_next,
+ .stop = pn_res_seq_stop,
+ .show = pn_res_seq_show,
+};
+
+static int pn_res_open(struct inode *inode, struct file *file)
+{
+ return seq_open_net(inode, file, &pn_res_seq_ops,
+ sizeof(struct seq_net_private));
+}
+
+const struct file_operations pn_res_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = pn_res_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_net,
+};
+#endif
diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c
index aebfecbdb841..bb6ad81b671d 100644
--- a/net/rds/af_rds.c
+++ b/net/rds/af_rds.c
@@ -39,7 +39,15 @@
#include <net/sock.h>
#include "rds.h"
-#include "rdma.h"
+
+char *rds_str_array(char **array, size_t elements, size_t index)
+{
+ if ((index < elements) && array[index])
+ return array[index];
+ else
+ return "unknown";
+}
+EXPORT_SYMBOL(rds_str_array);
/* this is just used for stats gathering :/ */
static DEFINE_SPINLOCK(rds_sock_lock);
@@ -62,7 +70,7 @@ static int rds_release(struct socket *sock)
struct rds_sock *rs;
unsigned long flags;
- if (sk == NULL)
+ if (!sk)
goto out;
rs = rds_sk_to_rs(sk);
@@ -73,7 +81,15 @@ static int rds_release(struct socket *sock)
* with the socket. */
rds_clear_recv_queue(rs);
rds_cong_remove_socket(rs);
+
+ /*
+ * the binding lookup hash uses rcu, we need to
+ * make sure we sychronize_rcu before we free our
+ * entry
+ */
rds_remove_bound(rs);
+ synchronize_rcu();
+
rds_send_drop_to(rs, NULL);
rds_rdma_drop_keys(rs);
rds_notify_queue_get(rs, NULL);
@@ -83,6 +99,8 @@ static int rds_release(struct socket *sock)
rds_sock_count--;
spin_unlock_irqrestore(&rds_sock_lock, flags);
+ rds_trans_put(rs->rs_transport);
+
sock->sk = NULL;
sock_put(sk);
out:
@@ -514,7 +532,7 @@ out:
spin_unlock_irqrestore(&rds_sock_lock, flags);
}
-static void __exit rds_exit(void)
+static void rds_exit(void)
{
sock_unregister(rds_family_ops.family);
proto_unregister(&rds_proto);
@@ -529,7 +547,7 @@ static void __exit rds_exit(void)
}
module_exit(rds_exit);
-static int __init rds_init(void)
+static int rds_init(void)
{
int ret;
diff --git a/net/rds/bind.c b/net/rds/bind.c
index 5d95fc007f1a..2f6b3fcc79f8 100644
--- a/net/rds/bind.c
+++ b/net/rds/bind.c
@@ -34,45 +34,52 @@
#include <net/sock.h>
#include <linux/in.h>
#include <linux/if_arp.h>
+#include <linux/jhash.h>
#include "rds.h"
-/*
- * XXX this probably still needs more work.. no INADDR_ANY, and rbtrees aren't
- * particularly zippy.
- *
- * This is now called for every incoming frame so we arguably care much more
- * about it than we used to.
- */
+#define BIND_HASH_SIZE 1024
+static struct hlist_head bind_hash_table[BIND_HASH_SIZE];
static DEFINE_SPINLOCK(rds_bind_lock);
-static struct rb_root rds_bind_tree = RB_ROOT;
-static struct rds_sock *rds_bind_tree_walk(__be32 addr, __be16 port,
- struct rds_sock *insert)
+static struct hlist_head *hash_to_bucket(__be32 addr, __be16 port)
+{
+ return bind_hash_table + (jhash_2words((u32)addr, (u32)port, 0) &
+ (BIND_HASH_SIZE - 1));
+}
+
+static struct rds_sock *rds_bind_lookup(__be32 addr, __be16 port,
+ struct rds_sock *insert)
{
- struct rb_node **p = &rds_bind_tree.rb_node;
- struct rb_node *parent = NULL;
struct rds_sock *rs;
+ struct hlist_node *node;
+ struct hlist_head *head = hash_to_bucket(addr, port);
u64 cmp;
u64 needle = ((u64)be32_to_cpu(addr) << 32) | be16_to_cpu(port);
- while (*p) {
- parent = *p;
- rs = rb_entry(parent, struct rds_sock, rs_bound_node);
-
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(rs, node, head, rs_bound_node) {
cmp = ((u64)be32_to_cpu(rs->rs_bound_addr) << 32) |
be16_to_cpu(rs->rs_bound_port);
- if (needle < cmp)
- p = &(*p)->rb_left;
- else if (needle > cmp)
- p = &(*p)->rb_right;
- else
+ if (cmp == needle) {
+ rcu_read_unlock();
return rs;
+ }
}
+ rcu_read_unlock();
if (insert) {
- rb_link_node(&insert->rs_bound_node, parent, p);
- rb_insert_color(&insert->rs_bound_node, &rds_bind_tree);
+ /*
+ * make sure our addr and port are set before
+ * we are added to the list, other people
+ * in rcu will find us as soon as the
+ * hlist_add_head_rcu is done
+ */
+ insert->rs_bound_addr = addr;
+ insert->rs_bound_port = port;
+ rds_sock_addref(insert);
+
+ hlist_add_head_rcu(&insert->rs_bound_node, head);
}
return NULL;
}
@@ -86,15 +93,13 @@ static struct rds_sock *rds_bind_tree_walk(__be32 addr, __be16 port,
struct rds_sock *rds_find_bound(__be32 addr, __be16 port)
{
struct rds_sock *rs;
- unsigned long flags;
- spin_lock_irqsave(&rds_bind_lock, flags);
- rs = rds_bind_tree_walk(addr, port, NULL);
+ rs = rds_bind_lookup(addr, port, NULL);
+
if (rs && !sock_flag(rds_rs_to_sk(rs), SOCK_DEAD))
rds_sock_addref(rs);
else
rs = NULL;
- spin_unlock_irqrestore(&rds_bind_lock, flags);
rdsdebug("returning rs %p for %pI4:%u\n", rs, &addr,
ntohs(port));
@@ -121,22 +126,15 @@ static int rds_add_bound(struct rds_sock *rs, __be32 addr, __be16 *port)
do {
if (rover == 0)
rover++;
- if (rds_bind_tree_walk(addr, cpu_to_be16(rover), rs) == NULL) {
- *port = cpu_to_be16(rover);
+ if (!rds_bind_lookup(addr, cpu_to_be16(rover), rs)) {
+ *port = rs->rs_bound_port;
ret = 0;
+ rdsdebug("rs %p binding to %pI4:%d\n",
+ rs, &addr, (int)ntohs(*port));
break;
}
} while (rover++ != last);
- if (ret == 0) {
- rs->rs_bound_addr = addr;
- rs->rs_bound_port = *port;
- rds_sock_addref(rs);
-
- rdsdebug("rs %p binding to %pI4:%d\n",
- rs, &addr, (int)ntohs(*port));
- }
-
spin_unlock_irqrestore(&rds_bind_lock, flags);
return ret;
@@ -153,7 +151,7 @@ void rds_remove_bound(struct rds_sock *rs)
rs, &rs->rs_bound_addr,
ntohs(rs->rs_bound_port));
- rb_erase(&rs->rs_bound_node, &rds_bind_tree);
+ hlist_del_init_rcu(&rs->rs_bound_node);
rds_sock_put(rs);
rs->rs_bound_addr = 0;
}
@@ -184,7 +182,7 @@ int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
goto out;
trans = rds_trans_get_preferred(sin->sin_addr.s_addr);
- if (trans == NULL) {
+ if (!trans) {
ret = -EADDRNOTAVAIL;
rds_remove_bound(rs);
if (printk_ratelimit())
@@ -198,5 +196,9 @@ int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
out:
release_sock(sk);
+
+ /* we might have called rds_remove_bound on error */
+ if (ret)
+ synchronize_rcu();
return ret;
}
diff --git a/net/rds/cong.c b/net/rds/cong.c
index 0871a29f0780..75ea686f27d5 100644
--- a/net/rds/cong.c
+++ b/net/rds/cong.c
@@ -141,7 +141,7 @@ static struct rds_cong_map *rds_cong_from_addr(__be32 addr)
unsigned long flags;
map = kzalloc(sizeof(struct rds_cong_map), GFP_KERNEL);
- if (map == NULL)
+ if (!map)
return NULL;
map->m_addr = addr;
@@ -159,7 +159,7 @@ static struct rds_cong_map *rds_cong_from_addr(__be32 addr)
ret = rds_cong_tree_walk(addr, map);
spin_unlock_irqrestore(&rds_cong_lock, flags);
- if (ret == NULL) {
+ if (!ret) {
ret = map;
map = NULL;
}
@@ -205,7 +205,7 @@ int rds_cong_get_maps(struct rds_connection *conn)
conn->c_lcong = rds_cong_from_addr(conn->c_laddr);
conn->c_fcong = rds_cong_from_addr(conn->c_faddr);
- if (conn->c_lcong == NULL || conn->c_fcong == NULL)
+ if (!(conn->c_lcong && conn->c_fcong))
return -ENOMEM;
return 0;
@@ -221,7 +221,7 @@ void rds_cong_queue_updates(struct rds_cong_map *map)
list_for_each_entry(conn, &map->m_conn_list, c_map_item) {
if (!test_and_set_bit(0, &conn->c_map_queued)) {
rds_stats_inc(s_cong_update_queued);
- queue_delayed_work(rds_wq, &conn->c_send_w, 0);
+ rds_send_xmit(conn);
}
}
diff --git a/net/rds/connection.c b/net/rds/connection.c
index 7619b671ca28..9334d892366e 100644
--- a/net/rds/connection.c
+++ b/net/rds/connection.c
@@ -37,7 +37,6 @@
#include "rds.h"
#include "loop.h"
-#include "rdma.h"
#define RDS_CONNECTION_HASH_BITS 12
#define RDS_CONNECTION_HASH_ENTRIES (1 << RDS_CONNECTION_HASH_BITS)
@@ -63,18 +62,7 @@ static struct hlist_head *rds_conn_bucket(__be32 laddr, __be32 faddr)
var |= RDS_INFO_CONNECTION_FLAG_##suffix; \
} while (0)
-static inline int rds_conn_is_sending(struct rds_connection *conn)
-{
- int ret = 0;
-
- if (!mutex_trylock(&conn->c_send_lock))
- ret = 1;
- else
- mutex_unlock(&conn->c_send_lock);
-
- return ret;
-}
-
+/* rcu read lock must be held or the connection spinlock */
static struct rds_connection *rds_conn_lookup(struct hlist_head *head,
__be32 laddr, __be32 faddr,
struct rds_transport *trans)
@@ -82,7 +70,7 @@ static struct rds_connection *rds_conn_lookup(struct hlist_head *head,
struct rds_connection *conn, *ret = NULL;
struct hlist_node *pos;
- hlist_for_each_entry(conn, pos, head, c_hash_node) {
+ hlist_for_each_entry_rcu(conn, pos, head, c_hash_node) {
if (conn->c_faddr == faddr && conn->c_laddr == laddr &&
conn->c_trans == trans) {
ret = conn;
@@ -100,7 +88,7 @@ static struct rds_connection *rds_conn_lookup(struct hlist_head *head,
* and receiving over this connection again in the future. It is up to
* the transport to have serialized this call with its send and recv.
*/
-void rds_conn_reset(struct rds_connection *conn)
+static void rds_conn_reset(struct rds_connection *conn)
{
rdsdebug("connection %pI4 to %pI4 reset\n",
&conn->c_laddr, &conn->c_faddr);
@@ -129,10 +117,11 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
{
struct rds_connection *conn, *parent = NULL;
struct hlist_head *head = rds_conn_bucket(laddr, faddr);
+ struct rds_transport *loop_trans;
unsigned long flags;
int ret;
- spin_lock_irqsave(&rds_conn_lock, flags);
+ rcu_read_lock();
conn = rds_conn_lookup(head, laddr, faddr, trans);
if (conn && conn->c_loopback && conn->c_trans != &rds_loop_transport &&
!is_outgoing) {
@@ -143,12 +132,12 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
parent = conn;
conn = parent->c_passive;
}
- spin_unlock_irqrestore(&rds_conn_lock, flags);
+ rcu_read_unlock();
if (conn)
goto out;
conn = kmem_cache_zalloc(rds_conn_slab, gfp);
- if (conn == NULL) {
+ if (!conn) {
conn = ERR_PTR(-ENOMEM);
goto out;
}
@@ -159,7 +148,7 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
spin_lock_init(&conn->c_lock);
conn->c_next_tx_seq = 1;
- mutex_init(&conn->c_send_lock);
+ init_waitqueue_head(&conn->c_waitq);
INIT_LIST_HEAD(&conn->c_send_queue);
INIT_LIST_HEAD(&conn->c_retrans);
@@ -175,7 +164,9 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
* can bind to the destination address then we'd rather the messages
* flow through loopback rather than either transport.
*/
- if (rds_trans_get_preferred(faddr)) {
+ loop_trans = rds_trans_get_preferred(faddr);
+ if (loop_trans) {
+ rds_trans_put(loop_trans);
conn->c_loopback = 1;
if (is_outgoing && trans->t_prefer_loopback) {
/* "outgoing" connection - and the transport
@@ -238,7 +229,7 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
kmem_cache_free(rds_conn_slab, conn);
conn = found;
} else {
- hlist_add_head(&conn->c_hash_node, head);
+ hlist_add_head_rcu(&conn->c_hash_node, head);
rds_cong_add_conn(conn);
rds_conn_count++;
}
@@ -263,21 +254,91 @@ struct rds_connection *rds_conn_create_outgoing(__be32 laddr, __be32 faddr,
}
EXPORT_SYMBOL_GPL(rds_conn_create_outgoing);
+void rds_conn_shutdown(struct rds_connection *conn)
+{
+ /* shut it down unless it's down already */
+ if (!rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_DOWN)) {
+ /*
+ * Quiesce the connection mgmt handlers before we start tearing
+ * things down. We don't hold the mutex for the entire
+ * duration of the shutdown operation, else we may be
+ * deadlocking with the CM handler. Instead, the CM event
+ * handler is supposed to check for state DISCONNECTING
+ */
+ mutex_lock(&conn->c_cm_lock);
+ if (!rds_conn_transition(conn, RDS_CONN_UP, RDS_CONN_DISCONNECTING)
+ && !rds_conn_transition(conn, RDS_CONN_ERROR, RDS_CONN_DISCONNECTING)) {
+ rds_conn_error(conn, "shutdown called in state %d\n",
+ atomic_read(&conn->c_state));
+ mutex_unlock(&conn->c_cm_lock);
+ return;
+ }
+ mutex_unlock(&conn->c_cm_lock);
+
+ wait_event(conn->c_waitq,
+ !test_bit(RDS_IN_XMIT, &conn->c_flags));
+
+ conn->c_trans->conn_shutdown(conn);
+ rds_conn_reset(conn);
+
+ if (!rds_conn_transition(conn, RDS_CONN_DISCONNECTING, RDS_CONN_DOWN)) {
+ /* This can happen - eg when we're in the middle of tearing
+ * down the connection, and someone unloads the rds module.
+ * Quite reproduceable with loopback connections.
+ * Mostly harmless.
+ */
+ rds_conn_error(conn,
+ "%s: failed to transition to state DOWN, "
+ "current state is %d\n",
+ __func__,
+ atomic_read(&conn->c_state));
+ return;
+ }
+ }
+
+ /* Then reconnect if it's still live.
+ * The passive side of an IB loopback connection is never added
+ * to the conn hash, so we never trigger a reconnect on this
+ * conn - the reconnect is always triggered by the active peer. */
+ cancel_delayed_work_sync(&conn->c_conn_w);
+ rcu_read_lock();
+ if (!hlist_unhashed(&conn->c_hash_node)) {
+ rcu_read_unlock();
+ rds_queue_reconnect(conn);
+ } else {
+ rcu_read_unlock();
+ }
+}
+
+/*
+ * Stop and free a connection.
+ *
+ * This can only be used in very limited circumstances. It assumes that once
+ * the conn has been shutdown that no one else is referencing the connection.
+ * We can only ensure this in the rmmod path in the current code.
+ */
void rds_conn_destroy(struct rds_connection *conn)
{
struct rds_message *rm, *rtmp;
+ unsigned long flags;
rdsdebug("freeing conn %p for %pI4 -> "
"%pI4\n", conn, &conn->c_laddr,
&conn->c_faddr);
- hlist_del_init(&conn->c_hash_node);
+ /* Ensure conn will not be scheduled for reconnect */
+ spin_lock_irq(&rds_conn_lock);
+ hlist_del_init_rcu(&conn->c_hash_node);
+ spin_unlock_irq(&rds_conn_lock);
+ synchronize_rcu();
- /* wait for the rds thread to shut it down */
- atomic_set(&conn->c_state, RDS_CONN_ERROR);
- cancel_delayed_work(&conn->c_conn_w);
- queue_work(rds_wq, &conn->c_down_w);
- flush_workqueue(rds_wq);
+ /* shut the connection down */
+ rds_conn_drop(conn);
+ flush_work(&conn->c_down_w);
+
+ /* make sure lingering queued work won't try to ref the conn */
+ cancel_delayed_work_sync(&conn->c_send_w);
+ cancel_delayed_work_sync(&conn->c_recv_w);
/* tear down queued messages */
list_for_each_entry_safe(rm, rtmp,
@@ -302,7 +363,9 @@ void rds_conn_destroy(struct rds_connection *conn)
BUG_ON(!list_empty(&conn->c_retrans));
kmem_cache_free(rds_conn_slab, conn);
+ spin_lock_irqsave(&rds_conn_lock, flags);
rds_conn_count--;
+ spin_unlock_irqrestore(&rds_conn_lock, flags);
}
EXPORT_SYMBOL_GPL(rds_conn_destroy);
@@ -316,23 +379,23 @@ static void rds_conn_message_info(struct socket *sock, unsigned int len,
struct list_head *list;
struct rds_connection *conn;
struct rds_message *rm;
- unsigned long flags;
unsigned int total = 0;
+ unsigned long flags;
size_t i;
len /= sizeof(struct rds_info_message);
- spin_lock_irqsave(&rds_conn_lock, flags);
+ rcu_read_lock();
for (i = 0, head = rds_conn_hash; i < ARRAY_SIZE(rds_conn_hash);
i++, head++) {
- hlist_for_each_entry(conn, pos, head, c_hash_node) {
+ hlist_for_each_entry_rcu(conn, pos, head, c_hash_node) {
if (want_send)
list = &conn->c_send_queue;
else
list = &conn->c_retrans;
- spin_lock(&conn->c_lock);
+ spin_lock_irqsave(&conn->c_lock, flags);
/* XXX too lazy to maintain counts.. */
list_for_each_entry(rm, list, m_conn_item) {
@@ -343,11 +406,10 @@ static void rds_conn_message_info(struct socket *sock, unsigned int len,
conn->c_faddr, 0);
}
- spin_unlock(&conn->c_lock);
+ spin_unlock_irqrestore(&conn->c_lock, flags);
}
}
-
- spin_unlock_irqrestore(&rds_conn_lock, flags);
+ rcu_read_unlock();
lens->nr = total;
lens->each = sizeof(struct rds_info_message);
@@ -377,19 +439,17 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len,
uint64_t buffer[(item_len + 7) / 8];
struct hlist_head *head;
struct hlist_node *pos;
- struct hlist_node *tmp;
struct rds_connection *conn;
- unsigned long flags;
size_t i;
- spin_lock_irqsave(&rds_conn_lock, flags);
+ rcu_read_lock();
lens->nr = 0;
lens->each = item_len;
for (i = 0, head = rds_conn_hash; i < ARRAY_SIZE(rds_conn_hash);
i++, head++) {
- hlist_for_each_entry_safe(conn, pos, tmp, head, c_hash_node) {
+ hlist_for_each_entry_rcu(conn, pos, head, c_hash_node) {
/* XXX no c_lock usage.. */
if (!visitor(conn, buffer))
@@ -405,8 +465,7 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len,
lens->nr++;
}
}
-
- spin_unlock_irqrestore(&rds_conn_lock, flags);
+ rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(rds_for_each_conn_info);
@@ -423,8 +482,8 @@ static int rds_conn_info_visitor(struct rds_connection *conn,
sizeof(cinfo->transport));
cinfo->flags = 0;
- rds_conn_info_set(cinfo->flags,
- rds_conn_is_sending(conn), SENDING);
+ rds_conn_info_set(cinfo->flags, test_bit(RDS_IN_XMIT, &conn->c_flags),
+ SENDING);
/* XXX Future: return the state rather than these funky bits */
rds_conn_info_set(cinfo->flags,
atomic_read(&conn->c_state) == RDS_CONN_CONNECTING,
@@ -444,12 +503,12 @@ static void rds_conn_info(struct socket *sock, unsigned int len,
sizeof(struct rds_info_connection));
}
-int __init rds_conn_init(void)
+int rds_conn_init(void)
{
rds_conn_slab = kmem_cache_create("rds_connection",
sizeof(struct rds_connection),
0, 0, NULL);
- if (rds_conn_slab == NULL)
+ if (!rds_conn_slab)
return -ENOMEM;
rds_info_register_func(RDS_INFO_CONNECTIONS, rds_conn_info);
@@ -487,6 +546,18 @@ void rds_conn_drop(struct rds_connection *conn)
EXPORT_SYMBOL_GPL(rds_conn_drop);
/*
+ * If the connection is down, trigger a connect. We may have scheduled a
+ * delayed reconnect however - in this case we should not interfere.
+ */
+void rds_conn_connect_if_down(struct rds_connection *conn)
+{
+ if (rds_conn_state(conn) == RDS_CONN_DOWN &&
+ !test_and_set_bit(RDS_RECONNECT_PENDING, &conn->c_flags))
+ queue_delayed_work(rds_wq, &conn->c_conn_w, 0);
+}
+EXPORT_SYMBOL_GPL(rds_conn_connect_if_down);
+
+/*
* An error occurred on the connection
*/
void
diff --git a/net/rds/ib.c b/net/rds/ib.c
index 8f2d6dd7700a..4123967d4d65 100644
--- a/net/rds/ib.c
+++ b/net/rds/ib.c
@@ -42,7 +42,7 @@
#include "rds.h"
#include "ib.h"
-unsigned int fmr_pool_size = RDS_FMR_POOL_SIZE;
+static unsigned int fmr_pool_size = RDS_FMR_POOL_SIZE;
unsigned int fmr_message_size = RDS_FMR_SIZE + 1; /* +1 allows for unaligned MRs */
unsigned int rds_ib_retry_count = RDS_IB_DEFAULT_RETRY_COUNT;
@@ -53,13 +53,72 @@ MODULE_PARM_DESC(fmr_message_size, " Max size of a RDMA transfer");
module_param(rds_ib_retry_count, int, 0444);
MODULE_PARM_DESC(rds_ib_retry_count, " Number of hw retries before reporting an error");
+/*
+ * we have a clumsy combination of RCU and a rwsem protecting this list
+ * because it is used both in the get_mr fast path and while blocking in
+ * the FMR flushing path.
+ */
+DECLARE_RWSEM(rds_ib_devices_lock);
struct list_head rds_ib_devices;
/* NOTE: if also grabbing ibdev lock, grab this first */
DEFINE_SPINLOCK(ib_nodev_conns_lock);
LIST_HEAD(ib_nodev_conns);
-void rds_ib_add_one(struct ib_device *device)
+static void rds_ib_nodev_connect(void)
+{
+ struct rds_ib_connection *ic;
+
+ spin_lock(&ib_nodev_conns_lock);
+ list_for_each_entry(ic, &ib_nodev_conns, ib_node)
+ rds_conn_connect_if_down(ic->conn);
+ spin_unlock(&ib_nodev_conns_lock);
+}
+
+static void rds_ib_dev_shutdown(struct rds_ib_device *rds_ibdev)
+{
+ struct rds_ib_connection *ic;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rds_ibdev->spinlock, flags);
+ list_for_each_entry(ic, &rds_ibdev->conn_list, ib_node)
+ rds_conn_drop(ic->conn);
+ spin_unlock_irqrestore(&rds_ibdev->spinlock, flags);
+}
+
+/*
+ * rds_ib_destroy_mr_pool() blocks on a few things and mrs drop references
+ * from interrupt context so we push freing off into a work struct in krdsd.
+ */
+static void rds_ib_dev_free(struct work_struct *work)
+{
+ struct rds_ib_ipaddr *i_ipaddr, *i_next;
+ struct rds_ib_device *rds_ibdev = container_of(work,
+ struct rds_ib_device, free_work);
+
+ if (rds_ibdev->mr_pool)
+ rds_ib_destroy_mr_pool(rds_ibdev->mr_pool);
+ if (rds_ibdev->mr)
+ ib_dereg_mr(rds_ibdev->mr);
+ if (rds_ibdev->pd)
+ ib_dealloc_pd(rds_ibdev->pd);
+
+ list_for_each_entry_safe(i_ipaddr, i_next, &rds_ibdev->ipaddr_list, list) {
+ list_del(&i_ipaddr->list);
+ kfree(i_ipaddr);
+ }
+
+ kfree(rds_ibdev);
+}
+
+void rds_ib_dev_put(struct rds_ib_device *rds_ibdev)
+{
+ BUG_ON(atomic_read(&rds_ibdev->refcount) <= 0);
+ if (atomic_dec_and_test(&rds_ibdev->refcount))
+ queue_work(rds_wq, &rds_ibdev->free_work);
+}
+
+static void rds_ib_add_one(struct ib_device *device)
{
struct rds_ib_device *rds_ibdev;
struct ib_device_attr *dev_attr;
@@ -77,11 +136,14 @@ void rds_ib_add_one(struct ib_device *device)
goto free_attr;
}
- rds_ibdev = kmalloc(sizeof *rds_ibdev, GFP_KERNEL);
+ rds_ibdev = kzalloc_node(sizeof(struct rds_ib_device), GFP_KERNEL,
+ ibdev_to_node(device));
if (!rds_ibdev)
goto free_attr;
spin_lock_init(&rds_ibdev->spinlock);
+ atomic_set(&rds_ibdev->refcount, 1);
+ INIT_WORK(&rds_ibdev->free_work, rds_ib_dev_free);
rds_ibdev->max_wrs = dev_attr->max_qp_wr;
rds_ibdev->max_sge = min(dev_attr->max_sge, RDS_IB_MAX_SGE);
@@ -91,68 +153,107 @@ void rds_ib_add_one(struct ib_device *device)
min_t(unsigned int, dev_attr->max_fmr, fmr_pool_size) :
fmr_pool_size;
+ rds_ibdev->max_initiator_depth = dev_attr->max_qp_init_rd_atom;
+ rds_ibdev->max_responder_resources = dev_attr->max_qp_rd_atom;
+
rds_ibdev->dev = device;
rds_ibdev->pd = ib_alloc_pd(device);
- if (IS_ERR(rds_ibdev->pd))
- goto free_dev;
+ if (IS_ERR(rds_ibdev->pd)) {
+ rds_ibdev->pd = NULL;
+ goto put_dev;
+ }
- rds_ibdev->mr = ib_get_dma_mr(rds_ibdev->pd,
- IB_ACCESS_LOCAL_WRITE);
- if (IS_ERR(rds_ibdev->mr))
- goto err_pd;
+ rds_ibdev->mr = ib_get_dma_mr(rds_ibdev->pd, IB_ACCESS_LOCAL_WRITE);
+ if (IS_ERR(rds_ibdev->mr)) {
+ rds_ibdev->mr = NULL;
+ goto put_dev;
+ }
rds_ibdev->mr_pool = rds_ib_create_mr_pool(rds_ibdev);
if (IS_ERR(rds_ibdev->mr_pool)) {
rds_ibdev->mr_pool = NULL;
- goto err_mr;
+ goto put_dev;
}
INIT_LIST_HEAD(&rds_ibdev->ipaddr_list);
INIT_LIST_HEAD(&rds_ibdev->conn_list);
- list_add_tail(&rds_ibdev->list, &rds_ib_devices);
+
+ down_write(&rds_ib_devices_lock);
+ list_add_tail_rcu(&rds_ibdev->list, &rds_ib_devices);
+ up_write(&rds_ib_devices_lock);
+ atomic_inc(&rds_ibdev->refcount);
ib_set_client_data(device, &rds_ib_client, rds_ibdev);
+ atomic_inc(&rds_ibdev->refcount);
- goto free_attr;
+ rds_ib_nodev_connect();
-err_mr:
- ib_dereg_mr(rds_ibdev->mr);
-err_pd:
- ib_dealloc_pd(rds_ibdev->pd);
-free_dev:
- kfree(rds_ibdev);
+put_dev:
+ rds_ib_dev_put(rds_ibdev);
free_attr:
kfree(dev_attr);
}
-void rds_ib_remove_one(struct ib_device *device)
+/*
+ * New connections use this to find the device to associate with the
+ * connection. It's not in the fast path so we're not concerned about the
+ * performance of the IB call. (As of this writing, it uses an interrupt
+ * blocking spinlock to serialize walking a per-device list of all registered
+ * clients.)
+ *
+ * RCU is used to handle incoming connections racing with device teardown.
+ * Rather than use a lock to serialize removal from the client_data and
+ * getting a new reference, we use an RCU grace period. The destruction
+ * path removes the device from client_data and then waits for all RCU
+ * readers to finish.
+ *
+ * A new connection can get NULL from this if its arriving on a
+ * device that is in the process of being removed.
+ */
+struct rds_ib_device *rds_ib_get_client_data(struct ib_device *device)
{
struct rds_ib_device *rds_ibdev;
- struct rds_ib_ipaddr *i_ipaddr, *i_next;
+ rcu_read_lock();
rds_ibdev = ib_get_client_data(device, &rds_ib_client);
- if (!rds_ibdev)
- return;
+ if (rds_ibdev)
+ atomic_inc(&rds_ibdev->refcount);
+ rcu_read_unlock();
+ return rds_ibdev;
+}
- list_for_each_entry_safe(i_ipaddr, i_next, &rds_ibdev->ipaddr_list, list) {
- list_del(&i_ipaddr->list);
- kfree(i_ipaddr);
- }
+/*
+ * The IB stack is letting us know that a device is going away. This can
+ * happen if the underlying HCA driver is removed or if PCI hotplug is removing
+ * the pci function, for example.
+ *
+ * This can be called at any time and can be racing with any other RDS path.
+ */
+static void rds_ib_remove_one(struct ib_device *device)
+{
+ struct rds_ib_device *rds_ibdev;
- rds_ib_destroy_conns(rds_ibdev);
+ rds_ibdev = ib_get_client_data(device, &rds_ib_client);
+ if (!rds_ibdev)
+ return;
- if (rds_ibdev->mr_pool)
- rds_ib_destroy_mr_pool(rds_ibdev->mr_pool);
+ rds_ib_dev_shutdown(rds_ibdev);
- ib_dereg_mr(rds_ibdev->mr);
+ /* stop connection attempts from getting a reference to this device. */
+ ib_set_client_data(device, &rds_ib_client, NULL);
- while (ib_dealloc_pd(rds_ibdev->pd)) {
- rdsdebug("Failed to dealloc pd %p\n", rds_ibdev->pd);
- msleep(1);
- }
+ down_write(&rds_ib_devices_lock);
+ list_del_rcu(&rds_ibdev->list);
+ up_write(&rds_ib_devices_lock);
- list_del(&rds_ibdev->list);
- kfree(rds_ibdev);
+ /*
+ * This synchronize rcu is waiting for readers of both the ib
+ * client data and the devices list to finish before we drop
+ * both of those references.
+ */
+ synchronize_rcu();
+ rds_ib_dev_put(rds_ibdev);
+ rds_ib_dev_put(rds_ibdev);
}
struct ib_client rds_ib_client = {
@@ -186,7 +287,7 @@ static int rds_ib_conn_info_visitor(struct rds_connection *conn,
rdma_addr_get_sgid(dev_addr, (union ib_gid *) &iinfo->src_gid);
rdma_addr_get_dgid(dev_addr, (union ib_gid *) &iinfo->dst_gid);
- rds_ibdev = ib_get_client_data(ic->i_cm_id->device, &rds_ib_client);
+ rds_ibdev = ic->rds_ibdev;
iinfo->max_send_wr = ic->i_send_ring.w_nr;
iinfo->max_recv_wr = ic->i_recv_ring.w_nr;
iinfo->max_send_sge = rds_ibdev->max_sge;
@@ -248,29 +349,36 @@ static int rds_ib_laddr_check(__be32 addr)
return ret;
}
+static void rds_ib_unregister_client(void)
+{
+ ib_unregister_client(&rds_ib_client);
+ /* wait for rds_ib_dev_free() to complete */
+ flush_workqueue(rds_wq);
+}
+
void rds_ib_exit(void)
{
rds_info_deregister_func(RDS_INFO_IB_CONNECTIONS, rds_ib_ic_info);
+ rds_ib_unregister_client();
rds_ib_destroy_nodev_conns();
- ib_unregister_client(&rds_ib_client);
rds_ib_sysctl_exit();
rds_ib_recv_exit();
rds_trans_unregister(&rds_ib_transport);
+ rds_ib_fmr_exit();
}
struct rds_transport rds_ib_transport = {
.laddr_check = rds_ib_laddr_check,
.xmit_complete = rds_ib_xmit_complete,
.xmit = rds_ib_xmit,
- .xmit_cong_map = NULL,
.xmit_rdma = rds_ib_xmit_rdma,
+ .xmit_atomic = rds_ib_xmit_atomic,
.recv = rds_ib_recv,
.conn_alloc = rds_ib_conn_alloc,
.conn_free = rds_ib_conn_free,
.conn_connect = rds_ib_conn_connect,
.conn_shutdown = rds_ib_conn_shutdown,
.inc_copy_to_user = rds_ib_inc_copy_to_user,
- .inc_purge = rds_ib_inc_purge,
.inc_free = rds_ib_inc_free,
.cm_initiate_connect = rds_ib_cm_initiate_connect,
.cm_handle_connect = rds_ib_cm_handle_connect,
@@ -286,16 +394,20 @@ struct rds_transport rds_ib_transport = {
.t_type = RDS_TRANS_IB
};
-int __init rds_ib_init(void)
+int rds_ib_init(void)
{
int ret;
INIT_LIST_HEAD(&rds_ib_devices);
- ret = ib_register_client(&rds_ib_client);
+ ret = rds_ib_fmr_init();
if (ret)
goto out;
+ ret = ib_register_client(&rds_ib_client);
+ if (ret)
+ goto out_fmr_exit;
+
ret = rds_ib_sysctl_init();
if (ret)
goto out_ibreg;
@@ -317,7 +429,9 @@ out_recv:
out_sysctl:
rds_ib_sysctl_exit();
out_ibreg:
- ib_unregister_client(&rds_ib_client);
+ rds_ib_unregister_client();
+out_fmr_exit:
+ rds_ib_fmr_exit();
out:
return ret;
}
diff --git a/net/rds/ib.h b/net/rds/ib.h
index 64df4e79b29f..e34ad032b66d 100644
--- a/net/rds/ib.h
+++ b/net/rds/ib.h
@@ -3,11 +3,13 @@
#include <rdma/ib_verbs.h>
#include <rdma/rdma_cm.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
#include "rds.h"
#include "rdma_transport.h"
#define RDS_FMR_SIZE 256
-#define RDS_FMR_POOL_SIZE 4096
+#define RDS_FMR_POOL_SIZE 8192
#define RDS_IB_MAX_SGE 8
#define RDS_IB_RECV_SGE 2
@@ -19,6 +21,9 @@
#define RDS_IB_SUPPORTED_PROTOCOLS 0x00000003 /* minor versions supported */
+#define RDS_IB_RECYCLE_BATCH_COUNT 32
+
+extern struct rw_semaphore rds_ib_devices_lock;
extern struct list_head rds_ib_devices;
/*
@@ -26,20 +31,29 @@ extern struct list_head rds_ib_devices;
* try and minimize the amount of memory tied up both the device and
* socket receive queues.
*/
-/* page offset of the final full frag that fits in the page */
-#define RDS_PAGE_LAST_OFF (((PAGE_SIZE / RDS_FRAG_SIZE) - 1) * RDS_FRAG_SIZE)
struct rds_page_frag {
struct list_head f_item;
- struct page *f_page;
- unsigned long f_offset;
- dma_addr_t f_mapped;
+ struct list_head f_cache_entry;
+ struct scatterlist f_sg;
};
struct rds_ib_incoming {
struct list_head ii_frags;
+ struct list_head ii_cache_entry;
struct rds_incoming ii_inc;
};
+struct rds_ib_cache_head {
+ struct list_head *first;
+ unsigned long count;
+};
+
+struct rds_ib_refill_cache {
+ struct rds_ib_cache_head *percpu;
+ struct list_head *xfer;
+ struct list_head *ready;
+};
+
struct rds_ib_connect_private {
/* Add new fields at the end, and don't permute existing fields. */
__be32 dp_saddr;
@@ -53,8 +67,7 @@ struct rds_ib_connect_private {
};
struct rds_ib_send_work {
- struct rds_message *s_rm;
- struct rds_rdma_op *s_op;
+ void *s_op;
struct ib_send_wr s_wr;
struct ib_sge s_sge[RDS_IB_MAX_SGE];
unsigned long s_queued;
@@ -92,10 +105,11 @@ struct rds_ib_connection {
/* tx */
struct rds_ib_work_ring i_send_ring;
- struct rds_message *i_rm;
+ struct rm_data_op *i_data_op;
struct rds_header *i_send_hdrs;
u64 i_send_hdrs_dma;
struct rds_ib_send_work *i_sends;
+ atomic_t i_signaled_sends;
/* rx */
struct tasklet_struct i_recv_tasklet;
@@ -106,8 +120,9 @@ struct rds_ib_connection {
struct rds_header *i_recv_hdrs;
u64 i_recv_hdrs_dma;
struct rds_ib_recv_work *i_recvs;
- struct rds_page_frag i_frag;
u64 i_ack_recv; /* last ACK received */
+ struct rds_ib_refill_cache i_cache_incs;
+ struct rds_ib_refill_cache i_cache_frags;
/* sending acks */
unsigned long i_ack_flags;
@@ -138,7 +153,6 @@ struct rds_ib_connection {
/* Batched completions */
unsigned int i_unsignaled_wrs;
- long i_unsignaled_bytes;
};
/* This assumes that atomic_t is at least 32 bits */
@@ -164,9 +178,17 @@ struct rds_ib_device {
unsigned int max_fmrs;
int max_sge;
unsigned int max_wrs;
+ unsigned int max_initiator_depth;
+ unsigned int max_responder_resources;
spinlock_t spinlock; /* protect the above */
+ atomic_t refcount;
+ struct work_struct free_work;
};
+#define pcidev_to_node(pcidev) pcibus_to_node(pcidev->bus)
+#define ibdev_to_node(ibdev) pcidev_to_node(to_pci_dev(ibdev->dma_device))
+#define rdsibdev_to_node(rdsibdev) ibdev_to_node(rdsibdev->dev)
+
/* bits for i_ack_flags */
#define IB_ACK_IN_FLIGHT 0
#define IB_ACK_REQUESTED 1
@@ -202,6 +224,8 @@ struct rds_ib_statistics {
uint64_t s_ib_rdma_mr_pool_flush;
uint64_t s_ib_rdma_mr_pool_wait;
uint64_t s_ib_rdma_mr_pool_depleted;
+ uint64_t s_ib_atomic_cswp;
+ uint64_t s_ib_atomic_fadd;
};
extern struct workqueue_struct *rds_ib_wq;
@@ -241,11 +265,10 @@ static inline void rds_ib_dma_sync_sg_for_device(struct ib_device *dev,
/* ib.c */
extern struct rds_transport rds_ib_transport;
-extern void rds_ib_add_one(struct ib_device *device);
-extern void rds_ib_remove_one(struct ib_device *device);
+struct rds_ib_device *rds_ib_get_client_data(struct ib_device *device);
+void rds_ib_dev_put(struct rds_ib_device *rds_ibdev);
extern struct ib_client rds_ib_client;
-extern unsigned int fmr_pool_size;
extern unsigned int fmr_message_size;
extern unsigned int rds_ib_retry_count;
@@ -258,7 +281,7 @@ void rds_ib_conn_free(void *arg);
int rds_ib_conn_connect(struct rds_connection *conn);
void rds_ib_conn_shutdown(struct rds_connection *conn);
void rds_ib_state_change(struct sock *sk);
-int __init rds_ib_listen_init(void);
+int rds_ib_listen_init(void);
void rds_ib_listen_stop(void);
void __rds_ib_conn_error(struct rds_connection *conn, const char *, ...);
int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
@@ -275,15 +298,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn,
int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr);
void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn);
void rds_ib_remove_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn);
-void __rds_ib_destroy_conns(struct list_head *list, spinlock_t *list_lock);
-static inline void rds_ib_destroy_nodev_conns(void)
-{
- __rds_ib_destroy_conns(&ib_nodev_conns, &ib_nodev_conns_lock);
-}
-static inline void rds_ib_destroy_conns(struct rds_ib_device *rds_ibdev)
-{
- __rds_ib_destroy_conns(&rds_ibdev->conn_list, &rds_ibdev->spinlock);
-}
+void rds_ib_destroy_nodev_conns(void);
struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *);
void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev, struct rds_info_rdma_connection *iinfo);
void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *);
@@ -292,14 +307,16 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
void rds_ib_sync_mr(void *trans_private, int dir);
void rds_ib_free_mr(void *trans_private, int invalidate);
void rds_ib_flush_mrs(void);
+int rds_ib_fmr_init(void);
+void rds_ib_fmr_exit(void);
/* ib_recv.c */
-int __init rds_ib_recv_init(void);
+int rds_ib_recv_init(void);
void rds_ib_recv_exit(void);
int rds_ib_recv(struct rds_connection *conn);
-int rds_ib_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
- gfp_t page_gfp, int prefill);
-void rds_ib_inc_purge(struct rds_incoming *inc);
+int rds_ib_recv_alloc_caches(struct rds_ib_connection *ic);
+void rds_ib_recv_free_caches(struct rds_ib_connection *ic);
+void rds_ib_recv_refill(struct rds_connection *conn, int prefill);
void rds_ib_inc_free(struct rds_incoming *inc);
int rds_ib_inc_copy_to_user(struct rds_incoming *inc, struct iovec *iov,
size_t size);
@@ -325,17 +342,19 @@ u32 rds_ib_ring_completed(struct rds_ib_work_ring *ring, u32 wr_id, u32 oldest);
extern wait_queue_head_t rds_ib_ring_empty_wait;
/* ib_send.c */
+char *rds_ib_wc_status_str(enum ib_wc_status status);
void rds_ib_xmit_complete(struct rds_connection *conn);
int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
unsigned int hdr_off, unsigned int sg, unsigned int off);
void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context);
void rds_ib_send_init_ring(struct rds_ib_connection *ic);
void rds_ib_send_clear_ring(struct rds_ib_connection *ic);
-int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op);
+int rds_ib_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op);
void rds_ib_send_add_credits(struct rds_connection *conn, unsigned int credits);
void rds_ib_advertise_credits(struct rds_connection *conn, unsigned int posted);
int rds_ib_send_grab_credits(struct rds_ib_connection *ic, u32 wanted,
u32 *adv_credits, int need_posted, int max_posted);
+int rds_ib_xmit_atomic(struct rds_connection *conn, struct rm_atomic_op *op);
/* ib_stats.c */
DECLARE_PER_CPU(struct rds_ib_statistics, rds_ib_stats);
@@ -344,7 +363,7 @@ unsigned int rds_ib_stats_info_copy(struct rds_info_iterator *iter,
unsigned int avail);
/* ib_sysctl.c */
-int __init rds_ib_sysctl_init(void);
+int rds_ib_sysctl_init(void);
void rds_ib_sysctl_exit(void);
extern unsigned long rds_ib_sysctl_max_send_wr;
extern unsigned long rds_ib_sysctl_max_recv_wr;
@@ -352,30 +371,5 @@ extern unsigned long rds_ib_sysctl_max_unsig_wrs;
extern unsigned long rds_ib_sysctl_max_unsig_bytes;
extern unsigned long rds_ib_sysctl_max_recv_allocation;
extern unsigned int rds_ib_sysctl_flow_control;
-extern ctl_table rds_ib_sysctl_table[];
-
-/*
- * Helper functions for getting/setting the header and data SGEs in
- * RDS packets (not RDMA)
- *
- * From version 3.1 onwards, header is in front of data in the sge.
- */
-static inline struct ib_sge *
-rds_ib_header_sge(struct rds_ib_connection *ic, struct ib_sge *sge)
-{
- if (ic->conn->c_version > RDS_PROTOCOL_3_0)
- return &sge[0];
- else
- return &sge[1];
-}
-
-static inline struct ib_sge *
-rds_ib_data_sge(struct rds_ib_connection *ic, struct ib_sge *sge)
-{
- if (ic->conn->c_version > RDS_PROTOCOL_3_0)
- return &sge[1];
- else
- return &sge[0];
-}
#endif
diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c
index f68832798db2..ee369d201a65 100644
--- a/net/rds/ib_cm.c
+++ b/net/rds/ib_cm.c
@@ -38,6 +38,36 @@
#include "rds.h"
#include "ib.h"
+static char *rds_ib_event_type_strings[] = {
+#define RDS_IB_EVENT_STRING(foo) \
+ [IB_EVENT_##foo] = __stringify(IB_EVENT_##foo)
+ RDS_IB_EVENT_STRING(CQ_ERR),
+ RDS_IB_EVENT_STRING(QP_FATAL),
+ RDS_IB_EVENT_STRING(QP_REQ_ERR),
+ RDS_IB_EVENT_STRING(QP_ACCESS_ERR),
+ RDS_IB_EVENT_STRING(COMM_EST),
+ RDS_IB_EVENT_STRING(SQ_DRAINED),
+ RDS_IB_EVENT_STRING(PATH_MIG),
+ RDS_IB_EVENT_STRING(PATH_MIG_ERR),
+ RDS_IB_EVENT_STRING(DEVICE_FATAL),
+ RDS_IB_EVENT_STRING(PORT_ACTIVE),
+ RDS_IB_EVENT_STRING(PORT_ERR),
+ RDS_IB_EVENT_STRING(LID_CHANGE),
+ RDS_IB_EVENT_STRING(PKEY_CHANGE),
+ RDS_IB_EVENT_STRING(SM_CHANGE),
+ RDS_IB_EVENT_STRING(SRQ_ERR),
+ RDS_IB_EVENT_STRING(SRQ_LIMIT_REACHED),
+ RDS_IB_EVENT_STRING(QP_LAST_WQE_REACHED),
+ RDS_IB_EVENT_STRING(CLIENT_REREGISTER),
+#undef RDS_IB_EVENT_STRING
+};
+
+static char *rds_ib_event_str(enum ib_event_type type)
+{
+ return rds_str_array(rds_ib_event_type_strings,
+ ARRAY_SIZE(rds_ib_event_type_strings), type);
+};
+
/*
* Set the selected protocol version
*/
@@ -95,7 +125,6 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
{
const struct rds_ib_connect_private *dp = NULL;
struct rds_ib_connection *ic = conn->c_transport_data;
- struct rds_ib_device *rds_ibdev;
struct ib_qp_attr qp_attr;
int err;
@@ -111,11 +140,21 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
}
}
- printk(KERN_NOTICE "RDS/IB: connected to %pI4 version %u.%u%s\n",
- &conn->c_faddr,
- RDS_PROTOCOL_MAJOR(conn->c_version),
- RDS_PROTOCOL_MINOR(conn->c_version),
- ic->i_flowctl ? ", flow control" : "");
+ if (conn->c_version < RDS_PROTOCOL(3,1)) {
+ printk(KERN_NOTICE "RDS/IB: Connection to %pI4 version %u.%u failed,"
+ " no longer supported\n",
+ &conn->c_faddr,
+ RDS_PROTOCOL_MAJOR(conn->c_version),
+ RDS_PROTOCOL_MINOR(conn->c_version));
+ rds_conn_destroy(conn);
+ return;
+ } else {
+ printk(KERN_NOTICE "RDS/IB: connected to %pI4 version %u.%u%s\n",
+ &conn->c_faddr,
+ RDS_PROTOCOL_MAJOR(conn->c_version),
+ RDS_PROTOCOL_MINOR(conn->c_version),
+ ic->i_flowctl ? ", flow control" : "");
+ }
/*
* Init rings and fill recv. this needs to wait until protocol negotiation
@@ -125,7 +164,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
rds_ib_recv_init_ring(ic);
/* Post receive buffers - as a side effect, this will update
* the posted credit count. */
- rds_ib_recv_refill(conn, GFP_KERNEL, GFP_HIGHUSER, 1);
+ rds_ib_recv_refill(conn, 1);
/* Tune RNR behavior */
rds_ib_tune_rnr(ic, &qp_attr);
@@ -135,12 +174,11 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
if (err)
printk(KERN_NOTICE "ib_modify_qp(IB_QP_STATE, RTS): err=%d\n", err);
- /* update ib_device with this local ipaddr & conn */
- rds_ibdev = ib_get_client_data(ic->i_cm_id->device, &rds_ib_client);
- err = rds_ib_update_ipaddr(rds_ibdev, conn->c_laddr);
+ /* update ib_device with this local ipaddr */
+ err = rds_ib_update_ipaddr(ic->rds_ibdev, conn->c_laddr);
if (err)
- printk(KERN_ERR "rds_ib_update_ipaddr failed (%d)\n", err);
- rds_ib_add_conn(rds_ibdev, conn);
+ printk(KERN_ERR "rds_ib_update_ipaddr failed (%d)\n",
+ err);
/* If the peer gave us the last packet it saw, process this as if
* we had received a regular ACK. */
@@ -153,18 +191,23 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
static void rds_ib_cm_fill_conn_param(struct rds_connection *conn,
struct rdma_conn_param *conn_param,
struct rds_ib_connect_private *dp,
- u32 protocol_version)
+ u32 protocol_version,
+ u32 max_responder_resources,
+ u32 max_initiator_depth)
{
+ struct rds_ib_connection *ic = conn->c_transport_data;
+ struct rds_ib_device *rds_ibdev = ic->rds_ibdev;
+
memset(conn_param, 0, sizeof(struct rdma_conn_param));
- /* XXX tune these? */
- conn_param->responder_resources = 1;
- conn_param->initiator_depth = 1;
+
+ conn_param->responder_resources =
+ min_t(u32, rds_ibdev->max_responder_resources, max_responder_resources);
+ conn_param->initiator_depth =
+ min_t(u32, rds_ibdev->max_initiator_depth, max_initiator_depth);
conn_param->retry_count = min_t(unsigned int, rds_ib_retry_count, 7);
conn_param->rnr_retry_count = 7;
if (dp) {
- struct rds_ib_connection *ic = conn->c_transport_data;
-
memset(dp, 0, sizeof(*dp));
dp->dp_saddr = conn->c_laddr;
dp->dp_daddr = conn->c_faddr;
@@ -189,7 +232,8 @@ static void rds_ib_cm_fill_conn_param(struct rds_connection *conn,
static void rds_ib_cq_event_handler(struct ib_event *event, void *data)
{
- rdsdebug("event %u data %p\n", event->event, data);
+ rdsdebug("event %u (%s) data %p\n",
+ event->event, rds_ib_event_str(event->event), data);
}
static void rds_ib_qp_event_handler(struct ib_event *event, void *data)
@@ -197,16 +241,18 @@ static void rds_ib_qp_event_handler(struct ib_event *event, void *data)
struct rds_connection *conn = data;
struct rds_ib_connection *ic = conn->c_transport_data;
- rdsdebug("conn %p ic %p event %u\n", conn, ic, event->event);
+ rdsdebug("conn %p ic %p event %u (%s)\n", conn, ic, event->event,
+ rds_ib_event_str(event->event));
switch (event->event) {
case IB_EVENT_COMM_EST:
rdma_notify(ic->i_cm_id, IB_EVENT_COMM_EST);
break;
default:
- rdsdebug("Fatal QP Event %u "
+ rdsdebug("Fatal QP Event %u (%s) "
"- connection %pI4->%pI4, reconnecting\n",
- event->event, &conn->c_laddr, &conn->c_faddr);
+ event->event, rds_ib_event_str(event->event),
+ &conn->c_laddr, &conn->c_faddr);
rds_conn_drop(conn);
break;
}
@@ -224,18 +270,16 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
struct rds_ib_device *rds_ibdev;
int ret;
- /* rds_ib_add_one creates a rds_ib_device object per IB device,
- * and allocates a protection domain, memory range and FMR pool
- * for each. If that fails for any reason, it will not register
- * the rds_ibdev at all.
+ /*
+ * It's normal to see a null device if an incoming connection races
+ * with device removal, so we don't print a warning.
*/
- rds_ibdev = ib_get_client_data(dev, &rds_ib_client);
- if (rds_ibdev == NULL) {
- if (printk_ratelimit())
- printk(KERN_NOTICE "RDS/IB: No client_data for device %s\n",
- dev->name);
+ rds_ibdev = rds_ib_get_client_data(dev);
+ if (!rds_ibdev)
return -EOPNOTSUPP;
- }
+
+ /* add the conn now so that connection establishment has the dev */
+ rds_ib_add_conn(rds_ibdev, conn);
if (rds_ibdev->max_wrs < ic->i_send_ring.w_nr + 1)
rds_ib_ring_resize(&ic->i_send_ring, rds_ibdev->max_wrs - 1);
@@ -306,7 +350,7 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
ic->i_send_ring.w_nr *
sizeof(struct rds_header),
&ic->i_send_hdrs_dma, GFP_KERNEL);
- if (ic->i_send_hdrs == NULL) {
+ if (!ic->i_send_hdrs) {
ret = -ENOMEM;
rdsdebug("ib_dma_alloc_coherent send failed\n");
goto out;
@@ -316,7 +360,7 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
ic->i_recv_ring.w_nr *
sizeof(struct rds_header),
&ic->i_recv_hdrs_dma, GFP_KERNEL);
- if (ic->i_recv_hdrs == NULL) {
+ if (!ic->i_recv_hdrs) {
ret = -ENOMEM;
rdsdebug("ib_dma_alloc_coherent recv failed\n");
goto out;
@@ -324,22 +368,24 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
ic->i_ack = ib_dma_alloc_coherent(dev, sizeof(struct rds_header),
&ic->i_ack_dma, GFP_KERNEL);
- if (ic->i_ack == NULL) {
+ if (!ic->i_ack) {
ret = -ENOMEM;
rdsdebug("ib_dma_alloc_coherent ack failed\n");
goto out;
}
- ic->i_sends = vmalloc(ic->i_send_ring.w_nr * sizeof(struct rds_ib_send_work));
- if (ic->i_sends == NULL) {
+ ic->i_sends = vmalloc_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(ic->i_recv_ring.w_nr * sizeof(struct rds_ib_recv_work));
- if (ic->i_recvs == NULL) {
+ ic->i_recvs = vmalloc_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;
@@ -352,6 +398,7 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
ic->i_send_cq, ic->i_recv_cq);
out:
+ rds_ib_dev_put(rds_ibdev);
return ret;
}
@@ -409,7 +456,7 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
struct rds_ib_connection *ic = NULL;
struct rdma_conn_param conn_param;
u32 version;
- int err, destroy = 1;
+ int err = 1, destroy = 1;
/* Check whether the remote protocol version matches ours. */
version = rds_ib_protocol_compatible(event);
@@ -448,7 +495,6 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
/* Wait and see - our connect may still be succeeding */
rds_ib_stats_inc(s_ib_connect_raced);
}
- mutex_unlock(&conn->c_cm_lock);
goto out;
}
@@ -475,24 +521,23 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
err = rds_ib_setup_qp(conn);
if (err) {
rds_ib_conn_error(conn, "rds_ib_setup_qp failed (%d)\n", err);
- mutex_unlock(&conn->c_cm_lock);
goto out;
}
- rds_ib_cm_fill_conn_param(conn, &conn_param, &dp_rep, version);
+ rds_ib_cm_fill_conn_param(conn, &conn_param, &dp_rep, version,
+ event->param.conn.responder_resources,
+ event->param.conn.initiator_depth);
/* rdma_accept() calls rdma_reject() internally if it fails */
err = rdma_accept(cm_id, &conn_param);
- mutex_unlock(&conn->c_cm_lock);
- if (err) {
+ if (err)
rds_ib_conn_error(conn, "rdma_accept failed (%d)\n", err);
- goto out;
- }
-
- return 0;
out:
- rdma_reject(cm_id, NULL, 0);
+ if (conn)
+ mutex_unlock(&conn->c_cm_lock);
+ if (err)
+ rdma_reject(cm_id, NULL, 0);
return destroy;
}
@@ -516,8 +561,8 @@ int rds_ib_cm_initiate_connect(struct rdma_cm_id *cm_id)
goto out;
}
- rds_ib_cm_fill_conn_param(conn, &conn_param, &dp, RDS_PROTOCOL_VERSION);
-
+ rds_ib_cm_fill_conn_param(conn, &conn_param, &dp, RDS_PROTOCOL_VERSION,
+ UINT_MAX, UINT_MAX);
ret = rdma_connect(cm_id, &conn_param);
if (ret)
rds_ib_conn_error(conn, "rdma_connect failed (%d)\n", ret);
@@ -601,9 +646,19 @@ void rds_ib_conn_shutdown(struct rds_connection *conn)
ic->i_cm_id, err);
}
+ /*
+ * We want to wait for tx and rx completion to finish
+ * before we tear down the connection, but we have to be
+ * careful not to get stuck waiting on a send ring that
+ * only has unsignaled sends in it. We've shutdown new
+ * sends before getting here so by waiting for signaled
+ * sends to complete we're ensured that there will be no
+ * more tx processing.
+ */
wait_event(rds_ib_ring_empty_wait,
- rds_ib_ring_empty(&ic->i_send_ring) &&
- rds_ib_ring_empty(&ic->i_recv_ring));
+ rds_ib_ring_empty(&ic->i_recv_ring) &&
+ (atomic_read(&ic->i_signaled_sends) == 0));
+ tasklet_kill(&ic->i_recv_tasklet);
if (ic->i_send_hdrs)
ib_dma_free_coherent(dev,
@@ -654,9 +709,12 @@ void rds_ib_conn_shutdown(struct rds_connection *conn)
BUG_ON(ic->rds_ibdev);
/* Clear pending transmit */
- if (ic->i_rm) {
- rds_message_put(ic->i_rm);
- ic->i_rm = NULL;
+ if (ic->i_data_op) {
+ struct rds_message *rm;
+
+ rm = container_of(ic->i_data_op, struct rds_message, data);
+ rds_message_put(rm);
+ ic->i_data_op = NULL;
}
/* Clear the ACK state */
@@ -690,12 +748,19 @@ int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp)
{
struct rds_ib_connection *ic;
unsigned long flags;
+ int ret;
/* XXX too lazy? */
ic = kzalloc(sizeof(struct rds_ib_connection), GFP_KERNEL);
- if (ic == NULL)
+ if (!ic)
return -ENOMEM;
+ ret = rds_ib_recv_alloc_caches(ic);
+ if (ret) {
+ kfree(ic);
+ return ret;
+ }
+
INIT_LIST_HEAD(&ic->ib_node);
tasklet_init(&ic->i_recv_tasklet, rds_ib_recv_tasklet_fn,
(unsigned long) ic);
@@ -703,6 +768,7 @@ int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp)
#ifndef KERNEL_HAS_ATOMIC64
spin_lock_init(&ic->i_ack_lock);
#endif
+ atomic_set(&ic->i_signaled_sends, 0);
/*
* rds_ib_conn_shutdown() waits for these to be emptied so they
@@ -744,6 +810,8 @@ void rds_ib_conn_free(void *arg)
list_del(&ic->ib_node);
spin_unlock_irq(lock_ptr);
+ rds_ib_recv_free_caches(ic);
+
kfree(ic);
}
diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
index a54cd63f9e35..18a833c450c8 100644
--- a/net/rds/ib_rdma.c
+++ b/net/rds/ib_rdma.c
@@ -32,11 +32,16 @@
*/
#include <linux/kernel.h>
#include <linux/slab.h>
+#include <linux/rculist.h>
#include "rds.h"
-#include "rdma.h"
#include "ib.h"
+#include "xlist.h"
+static struct workqueue_struct *rds_ib_fmr_wq;
+
+static DEFINE_PER_CPU(unsigned long, clean_list_grace);
+#define CLEAN_LIST_BUSY_BIT 0
/*
* This is stored as mr->r_trans_private.
@@ -45,7 +50,11 @@ struct rds_ib_mr {
struct rds_ib_device *device;
struct rds_ib_mr_pool *pool;
struct ib_fmr *fmr;
- struct list_head list;
+
+ struct xlist_head xlist;
+
+ /* unmap_list is for freeing */
+ struct list_head unmap_list;
unsigned int remap_count;
struct scatterlist *sg;
@@ -59,14 +68,16 @@ struct rds_ib_mr {
*/
struct rds_ib_mr_pool {
struct mutex flush_lock; /* serialize fmr invalidate */
- struct work_struct flush_worker; /* flush worker */
+ struct delayed_work flush_worker; /* flush worker */
- spinlock_t list_lock; /* protect variables below */
atomic_t item_count; /* total # of MRs */
atomic_t dirty_count; /* # dirty of MRs */
- struct list_head drop_list; /* MRs that have reached their max_maps limit */
- struct list_head free_list; /* unused MRs */
- struct list_head clean_list; /* unused & unamapped MRs */
+
+ 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 */
+ wait_queue_head_t flush_wait;
+
atomic_t free_pinned; /* memory pinned by free MRs */
unsigned long max_items;
unsigned long max_items_soft;
@@ -74,7 +85,7 @@ struct rds_ib_mr_pool {
struct ib_fmr_attr fmr_attr;
};
-static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all);
+static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all, struct rds_ib_mr **);
static void rds_ib_teardown_mr(struct rds_ib_mr *ibmr);
static void rds_ib_mr_pool_flush_worker(struct work_struct *work);
@@ -83,16 +94,17 @@ static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr)
struct rds_ib_device *rds_ibdev;
struct rds_ib_ipaddr *i_ipaddr;
- list_for_each_entry(rds_ibdev, &rds_ib_devices, list) {
- spin_lock_irq(&rds_ibdev->spinlock);
- list_for_each_entry(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(rds_ibdev, &rds_ib_devices, list) {
+ list_for_each_entry_rcu(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
if (i_ipaddr->ipaddr == ipaddr) {
- spin_unlock_irq(&rds_ibdev->spinlock);
+ atomic_inc(&rds_ibdev->refcount);
+ rcu_read_unlock();
return rds_ibdev;
}
}
- spin_unlock_irq(&rds_ibdev->spinlock);
}
+ rcu_read_unlock();
return NULL;
}
@@ -108,7 +120,7 @@ static int rds_ib_add_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
i_ipaddr->ipaddr = ipaddr;
spin_lock_irq(&rds_ibdev->spinlock);
- list_add_tail(&i_ipaddr->list, &rds_ibdev->ipaddr_list);
+ list_add_tail_rcu(&i_ipaddr->list, &rds_ibdev->ipaddr_list);
spin_unlock_irq(&rds_ibdev->spinlock);
return 0;
@@ -116,17 +128,24 @@ static int rds_ib_add_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
static void rds_ib_remove_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
{
- struct rds_ib_ipaddr *i_ipaddr, *next;
+ struct rds_ib_ipaddr *i_ipaddr;
+ struct rds_ib_ipaddr *to_free = NULL;
+
spin_lock_irq(&rds_ibdev->spinlock);
- list_for_each_entry_safe(i_ipaddr, next, &rds_ibdev->ipaddr_list, list) {
+ list_for_each_entry_rcu(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
if (i_ipaddr->ipaddr == ipaddr) {
- list_del(&i_ipaddr->list);
- kfree(i_ipaddr);
+ list_del_rcu(&i_ipaddr->list);
+ to_free = i_ipaddr;
break;
}
}
spin_unlock_irq(&rds_ibdev->spinlock);
+
+ if (to_free) {
+ synchronize_rcu();
+ kfree(to_free);
+ }
}
int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
@@ -134,8 +153,10 @@ int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
struct rds_ib_device *rds_ibdev_old;
rds_ibdev_old = rds_ib_get_device(ipaddr);
- if (rds_ibdev_old)
+ if (rds_ibdev_old) {
rds_ib_remove_ipaddr(rds_ibdev_old, ipaddr);
+ rds_ib_dev_put(rds_ibdev_old);
+ }
return rds_ib_add_ipaddr(rds_ibdev, ipaddr);
}
@@ -150,12 +171,13 @@ void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *con
BUG_ON(list_empty(&ic->ib_node));
list_del(&ic->ib_node);
- spin_lock_irq(&rds_ibdev->spinlock);
+ spin_lock(&rds_ibdev->spinlock);
list_add_tail(&ic->ib_node, &rds_ibdev->conn_list);
- spin_unlock_irq(&rds_ibdev->spinlock);
+ spin_unlock(&rds_ibdev->spinlock);
spin_unlock_irq(&ib_nodev_conns_lock);
ic->rds_ibdev = rds_ibdev;
+ atomic_inc(&rds_ibdev->refcount);
}
void rds_ib_remove_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn)
@@ -175,18 +197,18 @@ void rds_ib_remove_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *
spin_unlock(&ib_nodev_conns_lock);
ic->rds_ibdev = NULL;
+ rds_ib_dev_put(rds_ibdev);
}
-void __rds_ib_destroy_conns(struct list_head *list, spinlock_t *list_lock)
+void rds_ib_destroy_nodev_conns(void)
{
struct rds_ib_connection *ic, *_ic;
LIST_HEAD(tmp_list);
/* avoid calling conn_destroy with irqs off */
- spin_lock_irq(list_lock);
- list_splice(list, &tmp_list);
- INIT_LIST_HEAD(list);
- spin_unlock_irq(list_lock);
+ spin_lock_irq(&ib_nodev_conns_lock);
+ list_splice(&ib_nodev_conns, &tmp_list);
+ spin_unlock_irq(&ib_nodev_conns_lock);
list_for_each_entry_safe(ic, _ic, &tmp_list, ib_node)
rds_conn_destroy(ic->conn);
@@ -200,12 +222,12 @@ struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_ibdev)
if (!pool)
return ERR_PTR(-ENOMEM);
- INIT_LIST_HEAD(&pool->free_list);
- INIT_LIST_HEAD(&pool->drop_list);
- INIT_LIST_HEAD(&pool->clean_list);
+ INIT_XLIST_HEAD(&pool->free_list);
+ INIT_XLIST_HEAD(&pool->drop_list);
+ INIT_XLIST_HEAD(&pool->clean_list);
mutex_init(&pool->flush_lock);
- spin_lock_init(&pool->list_lock);
- INIT_WORK(&pool->flush_worker, rds_ib_mr_pool_flush_worker);
+ init_waitqueue_head(&pool->flush_wait);
+ INIT_DELAYED_WORK(&pool->flush_worker, rds_ib_mr_pool_flush_worker);
pool->fmr_attr.max_pages = fmr_message_size;
pool->fmr_attr.max_maps = rds_ibdev->fmr_max_remaps;
@@ -233,34 +255,60 @@ void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev, struct rds_info_rdma_co
void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *pool)
{
- flush_workqueue(rds_wq);
- rds_ib_flush_mr_pool(pool, 1);
+ cancel_delayed_work_sync(&pool->flush_worker);
+ rds_ib_flush_mr_pool(pool, 1, NULL);
WARN_ON(atomic_read(&pool->item_count));
WARN_ON(atomic_read(&pool->free_pinned));
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;
- unsigned long flags;
+ struct xlist_head *ret;
+ unsigned long *flag;
- spin_lock_irqsave(&pool->list_lock, flags);
- if (!list_empty(&pool->clean_list)) {
- ibmr = list_entry(pool->clean_list.next, struct rds_ib_mr, list);
- list_del_init(&ibmr->list);
- }
- spin_unlock_irqrestore(&pool->list_lock, flags);
+ preempt_disable();
+ flag = &__get_cpu_var(clean_list_grace);
+ set_bit(CLEAN_LIST_BUSY_BIT, flag);
+ ret = xlist_del_head(&pool->clean_list);
+ if (ret)
+ ibmr = list_entry(ret, struct rds_ib_mr, xlist);
+ clear_bit(CLEAN_LIST_BUSY_BIT, flag);
+ preempt_enable();
return ibmr;
}
+static inline void wait_clean_list_grace(void)
+{
+ int cpu;
+ unsigned long *flag;
+
+ for_each_online_cpu(cpu) {
+ flag = &per_cpu(clean_list_grace, cpu);
+ while (test_bit(CLEAN_LIST_BUSY_BIT, flag))
+ cpu_relax();
+ }
+}
+
static struct rds_ib_mr *rds_ib_alloc_fmr(struct rds_ib_device *rds_ibdev)
{
struct rds_ib_mr_pool *pool = rds_ibdev->mr_pool;
struct rds_ib_mr *ibmr = NULL;
int err = 0, iter = 0;
+ if (atomic_read(&pool->dirty_count) >= pool->max_items / 10)
+ queue_delayed_work(rds_ib_fmr_wq, &pool->flush_worker, 10);
+
while (1) {
ibmr = rds_ib_reuse_fmr(pool);
if (ibmr)
@@ -287,19 +335,24 @@ static struct rds_ib_mr *rds_ib_alloc_fmr(struct rds_ib_device *rds_ibdev)
/* We do have some empty MRs. Flush them out. */
rds_ib_stats_inc(s_ib_rdma_mr_pool_wait);
- rds_ib_flush_mr_pool(pool, 0);
+ rds_ib_flush_mr_pool(pool, 0, &ibmr);
+ if (ibmr)
+ return ibmr;
}
- ibmr = kzalloc(sizeof(*ibmr), GFP_KERNEL);
+ ibmr = kzalloc_node(sizeof(*ibmr), GFP_KERNEL, rdsibdev_to_node(rds_ibdev));
if (!ibmr) {
err = -ENOMEM;
goto out_no_cigar;
}
+ memset(ibmr, 0, sizeof(*ibmr));
+
ibmr->fmr = ib_alloc_fmr(rds_ibdev->pd,
(IB_ACCESS_LOCAL_WRITE |
IB_ACCESS_REMOTE_READ |
- IB_ACCESS_REMOTE_WRITE),
+ IB_ACCESS_REMOTE_WRITE|
+ IB_ACCESS_REMOTE_ATOMIC),
&pool->fmr_attr);
if (IS_ERR(ibmr->fmr)) {
err = PTR_ERR(ibmr->fmr);
@@ -367,7 +420,8 @@ static int rds_ib_map_fmr(struct rds_ib_device *rds_ibdev, struct rds_ib_mr *ibm
if (page_cnt > fmr_message_size)
return -EINVAL;
- dma_pages = kmalloc(sizeof(u64) * page_cnt, GFP_ATOMIC);
+ dma_pages = kmalloc_node(sizeof(u64) * page_cnt, GFP_ATOMIC,
+ rdsibdev_to_node(rds_ibdev));
if (!dma_pages)
return -ENOMEM;
@@ -441,7 +495,7 @@ static void __rds_ib_teardown_mr(struct rds_ib_mr *ibmr)
/* FIXME we need a way to tell a r/w MR
* from a r/o MR */
- BUG_ON(in_interrupt());
+ BUG_ON(irqs_disabled());
set_page_dirty(page);
put_page(page);
}
@@ -477,33 +531,109 @@ 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
+ */
+static void xlist_append_to_list(struct xlist_head *xlist, 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);
+ list_add_tail(&ibmr->unmap_list, list);
+ cur = 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.
+ */
+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)
+{
+ struct rds_ib_mr *ibmr;
+ struct xlist_head *cur_mr = xlist;
+ struct xlist_head *tail_mr = NULL;
+
+ 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;
+ }
+ *tail_ret = tail_mr;
+}
+
+/*
* Flush our pool of MRs.
* At a minimum, all currently unused MRs are unmapped.
* If the number of MRs allocated exceeds the limit, we also try
* to free as many MRs as needed to get back to this limit.
*/
-static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all)
+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;
LIST_HEAD(unmap_list);
LIST_HEAD(fmr_list);
unsigned long unpinned = 0;
- unsigned long flags;
unsigned int nfreed = 0, ncleaned = 0, free_goal;
int ret = 0;
rds_ib_stats_inc(s_ib_rdma_mr_pool_flush);
- mutex_lock(&pool->flush_lock);
+ if (ibmr_ret) {
+ DEFINE_WAIT(wait);
+ while(!mutex_trylock(&pool->flush_lock)) {
+ ibmr = rds_ib_reuse_fmr(pool);
+ if (ibmr) {
+ *ibmr_ret = ibmr;
+ finish_wait(&pool->flush_wait, &wait);
+ goto out_nolock;
+ }
+
+ prepare_to_wait(&pool->flush_wait, &wait,
+ TASK_UNINTERRUPTIBLE);
+ if (xlist_empty(&pool->clean_list))
+ schedule();
+
+ ibmr = rds_ib_reuse_fmr(pool);
+ if (ibmr) {
+ *ibmr_ret = ibmr;
+ finish_wait(&pool->flush_wait, &wait);
+ goto out_nolock;
+ }
+ }
+ finish_wait(&pool->flush_wait, &wait);
+ } else
+ mutex_lock(&pool->flush_lock);
+
+ if (ibmr_ret) {
+ ibmr = rds_ib_reuse_fmr(pool);
+ if (ibmr) {
+ *ibmr_ret = ibmr;
+ goto out;
+ }
+ }
- spin_lock_irqsave(&pool->list_lock, flags);
/* Get the list of all MRs to be dropped. Ordering matters -
- * we want to put drop_list ahead of free_list. */
- list_splice_init(&pool->free_list, &unmap_list);
- list_splice_init(&pool->drop_list, &unmap_list);
+ * 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);
if (free_all)
- list_splice_init(&pool->clean_list, &unmap_list);
- spin_unlock_irqrestore(&pool->list_lock, flags);
+ xlist_append_to_list(&pool->clean_list, &unmap_list);
free_goal = rds_ib_flush_goal(pool, free_all);
@@ -511,19 +641,20 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all)
goto out;
/* String all ib_mr's onto one list and hand them to ib_unmap_fmr */
- list_for_each_entry(ibmr, &unmap_list, list)
+ list_for_each_entry(ibmr, &unmap_list, unmap_list)
list_add(&ibmr->fmr->list, &fmr_list);
+
ret = ib_unmap_fmr(&fmr_list);
if (ret)
printk(KERN_WARNING "RDS/IB: ib_unmap_fmr failed (err=%d)\n", ret);
/* Now we can destroy the DMA mapping and unpin any pages */
- list_for_each_entry_safe(ibmr, next, &unmap_list, list) {
+ list_for_each_entry_safe(ibmr, next, &unmap_list, unmap_list) {
unpinned += ibmr->sg_len;
__rds_ib_teardown_mr(ibmr);
if (nfreed < free_goal || ibmr->remap_count >= pool->fmr_attr.max_maps) {
rds_ib_stats_inc(s_ib_rdma_mr_free);
- list_del(&ibmr->list);
+ list_del(&ibmr->unmap_list);
ib_dealloc_fmr(ibmr->fmr);
kfree(ibmr);
nfreed++;
@@ -531,9 +662,27 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all)
ncleaned++;
}
- spin_lock_irqsave(&pool->list_lock, flags);
- list_splice(&unmap_list, &pool->clean_list);
- spin_unlock_irqrestore(&pool->list_lock, flags);
+ 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
+ * 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.
+ *
+ * This is pretty unlikely, but just in case wait for an xlist 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);
+ if (ibmr_ret)
+ refill_local(pool, &clean_xlist, ibmr_ret);
+
+ /* refill_local may have emptied our list */
+ if (!xlist_empty(&clean_xlist))
+ xlist_add(clean_xlist.next, clean_tail, &pool->clean_list);
+
+ }
atomic_sub(unpinned, &pool->free_pinned);
atomic_sub(ncleaned, &pool->dirty_count);
@@ -541,14 +690,35 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all)
out:
mutex_unlock(&pool->flush_lock);
+ if (waitqueue_active(&pool->flush_wait))
+ wake_up(&pool->flush_wait);
+out_nolock:
return ret;
}
+int rds_ib_fmr_init(void)
+{
+ rds_ib_fmr_wq = create_workqueue("rds_fmr_flushd");
+ if (!rds_ib_fmr_wq)
+ return -ENOMEM;
+ return 0;
+}
+
+/*
+ * By the time this is called all the IB devices should have been torn down and
+ * had their pools freed. As each pool is freed its work struct is waited on,
+ * so the pool flushing work queue should be idle by the time we get here.
+ */
+void rds_ib_fmr_exit(void)
+{
+ destroy_workqueue(rds_ib_fmr_wq);
+}
+
static void rds_ib_mr_pool_flush_worker(struct work_struct *work)
{
- struct rds_ib_mr_pool *pool = container_of(work, struct rds_ib_mr_pool, flush_worker);
+ struct rds_ib_mr_pool *pool = container_of(work, struct rds_ib_mr_pool, flush_worker.work);
- rds_ib_flush_mr_pool(pool, 0);
+ rds_ib_flush_mr_pool(pool, 0, NULL);
}
void rds_ib_free_mr(void *trans_private, int invalidate)
@@ -556,47 +726,49 @@ void rds_ib_free_mr(void *trans_private, int invalidate)
struct rds_ib_mr *ibmr = trans_private;
struct rds_ib_device *rds_ibdev = ibmr->device;
struct rds_ib_mr_pool *pool = rds_ibdev->mr_pool;
- unsigned long flags;
rdsdebug("RDS/IB: free_mr nents %u\n", ibmr->sg_len);
/* Return it to the pool's free list */
- spin_lock_irqsave(&pool->list_lock, flags);
if (ibmr->remap_count >= pool->fmr_attr.max_maps)
- list_add(&ibmr->list, &pool->drop_list);
+ xlist_add(&ibmr->xlist, &ibmr->xlist, &pool->drop_list);
else
- list_add(&ibmr->list, &pool->free_list);
+ xlist_add(&ibmr->xlist, &ibmr->xlist, &pool->free_list);
atomic_add(ibmr->sg_len, &pool->free_pinned);
atomic_inc(&pool->dirty_count);
- spin_unlock_irqrestore(&pool->list_lock, flags);
/* If we've pinned too many pages, request a flush */
if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned ||
atomic_read(&pool->dirty_count) >= pool->max_items / 10)
- queue_work(rds_wq, &pool->flush_worker);
+ queue_delayed_work(rds_ib_fmr_wq, &pool->flush_worker, 10);
if (invalidate) {
if (likely(!in_interrupt())) {
- rds_ib_flush_mr_pool(pool, 0);
+ rds_ib_flush_mr_pool(pool, 0, NULL);
} else {
/* We get here if the user created a MR marked
* as use_once and invalidate at the same time. */
- queue_work(rds_wq, &pool->flush_worker);
+ queue_delayed_work(rds_ib_fmr_wq,
+ &pool->flush_worker, 10);
}
}
+
+ rds_ib_dev_put(rds_ibdev);
}
void rds_ib_flush_mrs(void)
{
struct rds_ib_device *rds_ibdev;
+ down_read(&rds_ib_devices_lock);
list_for_each_entry(rds_ibdev, &rds_ib_devices, list) {
struct rds_ib_mr_pool *pool = rds_ibdev->mr_pool;
if (pool)
- rds_ib_flush_mr_pool(pool, 0);
+ rds_ib_flush_mr_pool(pool, 0, NULL);
}
+ up_read(&rds_ib_devices_lock);
}
void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
@@ -628,6 +800,7 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
printk(KERN_WARNING "RDS/IB: map_fmr failed (errno=%d)\n", ret);
ibmr->device = rds_ibdev;
+ rds_ibdev = NULL;
out:
if (ret) {
@@ -635,5 +808,8 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
rds_ib_free_mr(ibmr, 0);
ibmr = ERR_PTR(ret);
}
+ if (rds_ibdev)
+ rds_ib_dev_put(rds_ibdev);
return ibmr;
}
+
diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c
index c74e9904a6b2..e29e0ca32f74 100644
--- a/net/rds/ib_recv.c
+++ b/net/rds/ib_recv.c
@@ -43,42 +43,6 @@ static struct kmem_cache *rds_ib_incoming_slab;
static struct kmem_cache *rds_ib_frag_slab;
static atomic_t rds_ib_allocation = ATOMIC_INIT(0);
-static void rds_ib_frag_drop_page(struct rds_page_frag *frag)
-{
- rdsdebug("frag %p page %p\n", frag, frag->f_page);
- __free_page(frag->f_page);
- frag->f_page = NULL;
-}
-
-static void rds_ib_frag_free(struct rds_page_frag *frag)
-{
- rdsdebug("frag %p page %p\n", frag, frag->f_page);
- BUG_ON(frag->f_page != NULL);
- kmem_cache_free(rds_ib_frag_slab, frag);
-}
-
-/*
- * We map a page at a time. Its fragments are posted in order. This
- * is called in fragment order as the fragments get send completion events.
- * Only the last frag in the page performs the unmapping.
- *
- * It's OK for ring cleanup to call this in whatever order it likes because
- * DMA is not in flight and so we can unmap while other ring entries still
- * hold page references in their frags.
- */
-static void rds_ib_recv_unmap_page(struct rds_ib_connection *ic,
- struct rds_ib_recv_work *recv)
-{
- struct rds_page_frag *frag = recv->r_frag;
-
- rdsdebug("recv %p frag %p page %p\n", recv, frag, frag->f_page);
- if (frag->f_mapped)
- ib_dma_unmap_page(ic->i_cm_id->device,
- frag->f_mapped,
- RDS_FRAG_SIZE, DMA_FROM_DEVICE);
- frag->f_mapped = 0;
-}
-
void rds_ib_recv_init_ring(struct rds_ib_connection *ic)
{
struct rds_ib_recv_work *recv;
@@ -95,16 +59,161 @@ void rds_ib_recv_init_ring(struct rds_ib_connection *ic)
recv->r_wr.sg_list = recv->r_sge;
recv->r_wr.num_sge = RDS_IB_RECV_SGE;
- sge = rds_ib_data_sge(ic, recv->r_sge);
+ sge = &recv->r_sge[0];
+ sge->addr = ic->i_recv_hdrs_dma + (i * sizeof(struct rds_header));
+ sge->length = sizeof(struct rds_header);
+ sge->lkey = ic->i_mr->lkey;
+
+ sge = &recv->r_sge[1];
sge->addr = 0;
sge->length = RDS_FRAG_SIZE;
sge->lkey = ic->i_mr->lkey;
+ }
+}
- sge = rds_ib_header_sge(ic, recv->r_sge);
- sge->addr = ic->i_recv_hdrs_dma + (i * sizeof(struct rds_header));
- sge->length = sizeof(struct rds_header);
- sge->lkey = ic->i_mr->lkey;
+/*
+ * The entire 'from' list, including the from element itself, is put on
+ * to the tail of the 'to' list.
+ */
+static void list_splice_entire_tail(struct list_head *from,
+ struct list_head *to)
+{
+ struct list_head *from_last = from->prev;
+
+ list_splice_tail(from_last, to);
+ list_add_tail(from_last, to);
+}
+
+static void rds_ib_cache_xfer_to_ready(struct rds_ib_refill_cache *cache)
+{
+ struct list_head *tmp;
+
+ tmp = xchg(&cache->xfer, NULL);
+ if (tmp) {
+ if (cache->ready)
+ list_splice_entire_tail(tmp, cache->ready);
+ else
+ cache->ready = tmp;
+ }
+}
+
+static int rds_ib_recv_alloc_cache(struct rds_ib_refill_cache *cache)
+{
+ struct rds_ib_cache_head *head;
+ int cpu;
+
+ cache->percpu = alloc_percpu(struct rds_ib_cache_head);
+ if (!cache->percpu)
+ return -ENOMEM;
+
+ for_each_possible_cpu(cpu) {
+ head = per_cpu_ptr(cache->percpu, cpu);
+ head->first = NULL;
+ head->count = 0;
+ }
+ cache->xfer = NULL;
+ cache->ready = NULL;
+
+ return 0;
+}
+
+int rds_ib_recv_alloc_caches(struct rds_ib_connection *ic)
+{
+ int ret;
+
+ ret = rds_ib_recv_alloc_cache(&ic->i_cache_incs);
+ if (!ret) {
+ ret = rds_ib_recv_alloc_cache(&ic->i_cache_frags);
+ if (ret)
+ free_percpu(ic->i_cache_incs.percpu);
}
+
+ return ret;
+}
+
+static void rds_ib_cache_splice_all_lists(struct rds_ib_refill_cache *cache,
+ struct list_head *caller_list)
+{
+ struct rds_ib_cache_head *head;
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ head = per_cpu_ptr(cache->percpu, cpu);
+ if (head->first) {
+ list_splice_entire_tail(head->first, caller_list);
+ head->first = NULL;
+ }
+ }
+
+ if (cache->ready) {
+ list_splice_entire_tail(cache->ready, caller_list);
+ cache->ready = NULL;
+ }
+}
+
+void rds_ib_recv_free_caches(struct rds_ib_connection *ic)
+{
+ struct rds_ib_incoming *inc;
+ struct rds_ib_incoming *inc_tmp;
+ struct rds_page_frag *frag;
+ struct rds_page_frag *frag_tmp;
+ LIST_HEAD(list);
+
+ rds_ib_cache_xfer_to_ready(&ic->i_cache_incs);
+ rds_ib_cache_splice_all_lists(&ic->i_cache_incs, &list);
+ free_percpu(ic->i_cache_incs.percpu);
+
+ list_for_each_entry_safe(inc, inc_tmp, &list, ii_cache_entry) {
+ list_del(&inc->ii_cache_entry);
+ WARN_ON(!list_empty(&inc->ii_frags));
+ kmem_cache_free(rds_ib_incoming_slab, inc);
+ }
+
+ rds_ib_cache_xfer_to_ready(&ic->i_cache_frags);
+ rds_ib_cache_splice_all_lists(&ic->i_cache_frags, &list);
+ free_percpu(ic->i_cache_frags.percpu);
+
+ list_for_each_entry_safe(frag, frag_tmp, &list, f_cache_entry) {
+ list_del(&frag->f_cache_entry);
+ WARN_ON(!list_empty(&frag->f_item));
+ kmem_cache_free(rds_ib_frag_slab, frag);
+ }
+}
+
+/* fwd decl */
+static void rds_ib_recv_cache_put(struct list_head *new_item,
+ struct rds_ib_refill_cache *cache);
+static struct list_head *rds_ib_recv_cache_get(struct rds_ib_refill_cache *cache);
+
+
+/* Recycle frag and attached recv buffer f_sg */
+static void rds_ib_frag_free(struct rds_ib_connection *ic,
+ struct rds_page_frag *frag)
+{
+ rdsdebug("frag %p page %p\n", frag, sg_page(&frag->f_sg));
+
+ rds_ib_recv_cache_put(&frag->f_cache_entry, &ic->i_cache_frags);
+}
+
+/* Recycle inc after freeing attached frags */
+void rds_ib_inc_free(struct rds_incoming *inc)
+{
+ struct rds_ib_incoming *ibinc;
+ struct rds_page_frag *frag;
+ struct rds_page_frag *pos;
+ struct rds_ib_connection *ic = inc->i_conn->c_transport_data;
+
+ ibinc = container_of(inc, struct rds_ib_incoming, ii_inc);
+
+ /* Free attached frags */
+ list_for_each_entry_safe(frag, pos, &ibinc->ii_frags, f_item) {
+ list_del_init(&frag->f_item);
+ rds_ib_frag_free(ic, frag);
+ }
+ BUG_ON(!list_empty(&ibinc->ii_frags));
+
+ rdsdebug("freeing ibinc %p inc %p\n", ibinc, inc);
+ rds_ib_recv_cache_put(&ibinc->ii_cache_entry, &ic->i_cache_incs);
}
static void rds_ib_recv_clear_one(struct rds_ib_connection *ic,
@@ -115,10 +224,8 @@ static void rds_ib_recv_clear_one(struct rds_ib_connection *ic,
recv->r_ibinc = NULL;
}
if (recv->r_frag) {
- rds_ib_recv_unmap_page(ic, recv);
- if (recv->r_frag->f_page)
- rds_ib_frag_drop_page(recv->r_frag);
- rds_ib_frag_free(recv->r_frag);
+ ib_dma_unmap_sg(ic->i_cm_id->device, &recv->r_frag->f_sg, 1, DMA_FROM_DEVICE);
+ rds_ib_frag_free(ic, recv->r_frag);
recv->r_frag = NULL;
}
}
@@ -129,84 +236,111 @@ void rds_ib_recv_clear_ring(struct rds_ib_connection *ic)
for (i = 0; i < ic->i_recv_ring.w_nr; i++)
rds_ib_recv_clear_one(ic, &ic->i_recvs[i]);
-
- if (ic->i_frag.f_page)
- rds_ib_frag_drop_page(&ic->i_frag);
}
-static int rds_ib_recv_refill_one(struct rds_connection *conn,
- struct rds_ib_recv_work *recv,
- gfp_t kptr_gfp, gfp_t page_gfp)
+static struct rds_ib_incoming *rds_ib_refill_one_inc(struct rds_ib_connection *ic,
+ gfp_t slab_mask)
{
- struct rds_ib_connection *ic = conn->c_transport_data;
- dma_addr_t dma_addr;
- struct ib_sge *sge;
- int ret = -ENOMEM;
+ struct rds_ib_incoming *ibinc;
+ struct list_head *cache_item;
+ int avail_allocs;
- if (recv->r_ibinc == NULL) {
- if (!atomic_add_unless(&rds_ib_allocation, 1, rds_ib_sysctl_max_recv_allocation)) {
+ cache_item = rds_ib_recv_cache_get(&ic->i_cache_incs);
+ if (cache_item) {
+ ibinc = container_of(cache_item, struct rds_ib_incoming, ii_cache_entry);
+ } else {
+ avail_allocs = atomic_add_unless(&rds_ib_allocation,
+ 1, rds_ib_sysctl_max_recv_allocation);
+ if (!avail_allocs) {
rds_ib_stats_inc(s_ib_rx_alloc_limit);
- goto out;
+ return NULL;
}
- recv->r_ibinc = kmem_cache_alloc(rds_ib_incoming_slab,
- kptr_gfp);
- if (recv->r_ibinc == NULL) {
+ ibinc = kmem_cache_alloc(rds_ib_incoming_slab, slab_mask);
+ if (!ibinc) {
atomic_dec(&rds_ib_allocation);
- goto out;
+ return NULL;
}
- INIT_LIST_HEAD(&recv->r_ibinc->ii_frags);
- rds_inc_init(&recv->r_ibinc->ii_inc, conn, conn->c_faddr);
}
+ INIT_LIST_HEAD(&ibinc->ii_frags);
+ rds_inc_init(&ibinc->ii_inc, ic->conn, ic->conn->c_faddr);
- if (recv->r_frag == NULL) {
- recv->r_frag = kmem_cache_alloc(rds_ib_frag_slab, kptr_gfp);
- if (recv->r_frag == NULL)
- goto out;
- INIT_LIST_HEAD(&recv->r_frag->f_item);
- recv->r_frag->f_page = NULL;
+ return ibinc;
+}
+
+static struct rds_page_frag *rds_ib_refill_one_frag(struct rds_ib_connection *ic,
+ gfp_t slab_mask, gfp_t page_mask)
+{
+ struct rds_page_frag *frag;
+ struct list_head *cache_item;
+ int ret;
+
+ cache_item = rds_ib_recv_cache_get(&ic->i_cache_frags);
+ if (cache_item) {
+ frag = container_of(cache_item, struct rds_page_frag, f_cache_entry);
+ } else {
+ frag = kmem_cache_alloc(rds_ib_frag_slab, slab_mask);
+ if (!frag)
+ return NULL;
+
+ sg_init_table(&frag->f_sg, 1);
+ ret = rds_page_remainder_alloc(&frag->f_sg,
+ RDS_FRAG_SIZE, page_mask);
+ if (ret) {
+ kmem_cache_free(rds_ib_frag_slab, frag);
+ return NULL;
+ }
}
- if (ic->i_frag.f_page == NULL) {
- ic->i_frag.f_page = alloc_page(page_gfp);
- if (ic->i_frag.f_page == NULL)
- goto out;
- ic->i_frag.f_offset = 0;
+ INIT_LIST_HEAD(&frag->f_item);
+
+ return frag;
+}
+
+static int rds_ib_recv_refill_one(struct rds_connection *conn,
+ struct rds_ib_recv_work *recv, int prefill)
+{
+ struct rds_ib_connection *ic = conn->c_transport_data;
+ struct ib_sge *sge;
+ int ret = -ENOMEM;
+ gfp_t slab_mask = GFP_NOWAIT;
+ gfp_t page_mask = GFP_NOWAIT;
+
+ if (prefill) {
+ slab_mask = GFP_KERNEL;
+ page_mask = GFP_HIGHUSER;
}
- dma_addr = ib_dma_map_page(ic->i_cm_id->device,
- ic->i_frag.f_page,
- ic->i_frag.f_offset,
- RDS_FRAG_SIZE,
- DMA_FROM_DEVICE);
- if (ib_dma_mapping_error(ic->i_cm_id->device, dma_addr))
- goto out;
+ if (!ic->i_cache_incs.ready)
+ rds_ib_cache_xfer_to_ready(&ic->i_cache_incs);
+ if (!ic->i_cache_frags.ready)
+ rds_ib_cache_xfer_to_ready(&ic->i_cache_frags);
/*
- * Once we get the RDS_PAGE_LAST_OFF frag then rds_ib_frag_unmap()
- * must be called on this recv. This happens as completions hit
- * in order or on connection shutdown.
+ * ibinc was taken from recv if recv contained the start of a message.
+ * recvs that were continuations will still have this allocated.
*/
- recv->r_frag->f_page = ic->i_frag.f_page;
- recv->r_frag->f_offset = ic->i_frag.f_offset;
- recv->r_frag->f_mapped = dma_addr;
+ if (!recv->r_ibinc) {
+ recv->r_ibinc = rds_ib_refill_one_inc(ic, slab_mask);
+ if (!recv->r_ibinc)
+ goto out;
+ }
- sge = rds_ib_data_sge(ic, recv->r_sge);
- sge->addr = dma_addr;
- sge->length = RDS_FRAG_SIZE;
+ WARN_ON(recv->r_frag); /* leak! */
+ recv->r_frag = rds_ib_refill_one_frag(ic, slab_mask, page_mask);
+ if (!recv->r_frag)
+ goto out;
+
+ ret = ib_dma_map_sg(ic->i_cm_id->device, &recv->r_frag->f_sg,
+ 1, DMA_FROM_DEVICE);
+ WARN_ON(ret != 1);
- sge = rds_ib_header_sge(ic, recv->r_sge);
+ sge = &recv->r_sge[0];
sge->addr = ic->i_recv_hdrs_dma + (recv - ic->i_recvs) * sizeof(struct rds_header);
sge->length = sizeof(struct rds_header);
- get_page(recv->r_frag->f_page);
-
- if (ic->i_frag.f_offset < RDS_PAGE_LAST_OFF) {
- ic->i_frag.f_offset += RDS_FRAG_SIZE;
- } else {
- put_page(ic->i_frag.f_page);
- ic->i_frag.f_page = NULL;
- ic->i_frag.f_offset = 0;
- }
+ sge = &recv->r_sge[1];
+ sge->addr = sg_dma_address(&recv->r_frag->f_sg);
+ sge->length = sg_dma_len(&recv->r_frag->f_sg);
ret = 0;
out:
@@ -216,13 +350,11 @@ out:
/*
* This tries to allocate and post unused work requests after making sure that
* they have all the allocations they need to queue received fragments into
- * sockets. The i_recv_mutex is held here so that ring_alloc and _unalloc
- * pairs don't go unmatched.
+ * sockets.
*
* -1 is returned if posting fails due to temporary resource exhaustion.
*/
-int rds_ib_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
- gfp_t page_gfp, int prefill)
+void rds_ib_recv_refill(struct rds_connection *conn, int prefill)
{
struct rds_ib_connection *ic = conn->c_transport_data;
struct rds_ib_recv_work *recv;
@@ -236,28 +368,25 @@ int rds_ib_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
if (pos >= ic->i_recv_ring.w_nr) {
printk(KERN_NOTICE "Argh - ring alloc returned pos=%u\n",
pos);
- ret = -EINVAL;
break;
}
recv = &ic->i_recvs[pos];
- ret = rds_ib_recv_refill_one(conn, recv, kptr_gfp, page_gfp);
+ ret = rds_ib_recv_refill_one(conn, recv, prefill);
if (ret) {
- ret = -1;
break;
}
/* XXX when can this fail? */
ret = ib_post_recv(ic->i_cm_id->qp, &recv->r_wr, &failed_wr);
rdsdebug("recv %p ibinc %p page %p addr %lu ret %d\n", recv,
- recv->r_ibinc, recv->r_frag->f_page,
- (long) recv->r_frag->f_mapped, ret);
+ recv->r_ibinc, sg_page(&recv->r_frag->f_sg),
+ (long) sg_dma_address(&recv->r_frag->f_sg), ret);
if (ret) {
rds_ib_conn_error(conn, "recv post on "
"%pI4 returned %d, disconnecting and "
"reconnecting\n", &conn->c_faddr,
ret);
- ret = -1;
break;
}
@@ -270,37 +399,73 @@ int rds_ib_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
if (ret)
rds_ib_ring_unalloc(&ic->i_recv_ring, 1);
- return ret;
}
-void rds_ib_inc_purge(struct rds_incoming *inc)
+/*
+ * We want to recycle several types of recv allocations, like incs and frags.
+ * To use this, the *_free() function passes in the ptr to a list_head within
+ * the recyclee, as well as the cache to put it on.
+ *
+ * First, we put the memory on a percpu list. When this reaches a certain size,
+ * We move it to an intermediate non-percpu list in a lockless manner, with some
+ * xchg/compxchg wizardry.
+ *
+ * N.B. Instead of a list_head as the anchor, we use a single pointer, which can
+ * be NULL and xchg'd. The list is actually empty when the pointer is NULL, and
+ * list_empty() will return true with one element is actually present.
+ */
+static void rds_ib_recv_cache_put(struct list_head *new_item,
+ struct rds_ib_refill_cache *cache)
{
- struct rds_ib_incoming *ibinc;
- struct rds_page_frag *frag;
- struct rds_page_frag *pos;
+ unsigned long flags;
+ struct rds_ib_cache_head *chp;
+ struct list_head *old;
- ibinc = container_of(inc, struct rds_ib_incoming, ii_inc);
- rdsdebug("purging ibinc %p inc %p\n", ibinc, inc);
+ local_irq_save(flags);
- list_for_each_entry_safe(frag, pos, &ibinc->ii_frags, f_item) {
- list_del_init(&frag->f_item);
- rds_ib_frag_drop_page(frag);
- rds_ib_frag_free(frag);
- }
+ chp = per_cpu_ptr(cache->percpu, smp_processor_id());
+ if (!chp->first)
+ INIT_LIST_HEAD(new_item);
+ else /* put on front */
+ list_add_tail(new_item, chp->first);
+ chp->first = new_item;
+ chp->count++;
+
+ if (chp->count < RDS_IB_RECYCLE_BATCH_COUNT)
+ goto end;
+
+ /*
+ * Return our per-cpu first list to the cache's xfer by atomically
+ * grabbing the current xfer list, appending it to our per-cpu list,
+ * and then atomically returning that entire list back to the
+ * cache's xfer list as long as it's still empty.
+ */
+ do {
+ old = xchg(&cache->xfer, NULL);
+ if (old)
+ list_splice_entire_tail(old, chp->first);
+ old = cmpxchg(&cache->xfer, NULL, chp->first);
+ } while (old);
+
+ chp->first = NULL;
+ chp->count = 0;
+end:
+ local_irq_restore(flags);
}
-void rds_ib_inc_free(struct rds_incoming *inc)
+static struct list_head *rds_ib_recv_cache_get(struct rds_ib_refill_cache *cache)
{
- struct rds_ib_incoming *ibinc;
-
- ibinc = container_of(inc, struct rds_ib_incoming, ii_inc);
+ struct list_head *head = cache->ready;
+
+ if (head) {
+ if (!list_empty(head)) {
+ cache->ready = head->next;
+ list_del_init(head);
+ } else
+ cache->ready = NULL;
+ }
- rds_ib_inc_purge(inc);
- rdsdebug("freeing ibinc %p inc %p\n", ibinc, inc);
- BUG_ON(!list_empty(&ibinc->ii_frags));
- kmem_cache_free(rds_ib_incoming_slab, ibinc);
- atomic_dec(&rds_ib_allocation);
- BUG_ON(atomic_read(&rds_ib_allocation) < 0);
+ return head;
}
int rds_ib_inc_copy_to_user(struct rds_incoming *inc, struct iovec *first_iov,
@@ -336,13 +501,13 @@ int rds_ib_inc_copy_to_user(struct rds_incoming *inc, struct iovec *first_iov,
to_copy = min_t(unsigned long, to_copy, len - copied);
rdsdebug("%lu bytes to user [%p, %zu] + %lu from frag "
- "[%p, %lu] + %lu\n",
+ "[%p, %u] + %lu\n",
to_copy, iov->iov_base, iov->iov_len, iov_off,
- frag->f_page, frag->f_offset, frag_off);
+ sg_page(&frag->f_sg), frag->f_sg.offset, frag_off);
/* XXX needs + offset for multiple recvs per page */
- ret = rds_page_copy_to_user(frag->f_page,
- frag->f_offset + frag_off,
+ ret = rds_page_copy_to_user(sg_page(&frag->f_sg),
+ frag->f_sg.offset + frag_off,
iov->iov_base + iov_off,
to_copy);
if (ret) {
@@ -557,47 +722,6 @@ u64 rds_ib_piggyb_ack(struct rds_ib_connection *ic)
return rds_ib_get_ack(ic);
}
-static struct rds_header *rds_ib_get_header(struct rds_connection *conn,
- struct rds_ib_recv_work *recv,
- u32 data_len)
-{
- struct rds_ib_connection *ic = conn->c_transport_data;
- void *hdr_buff = &ic->i_recv_hdrs[recv - ic->i_recvs];
- void *addr;
- u32 misplaced_hdr_bytes;
-
- /*
- * Support header at the front (RDS 3.1+) as well as header-at-end.
- *
- * Cases:
- * 1) header all in header buff (great!)
- * 2) header all in data page (copy all to header buff)
- * 3) header split across hdr buf + data page
- * (move bit in hdr buff to end before copying other bit from data page)
- */
- if (conn->c_version > RDS_PROTOCOL_3_0 || data_len == RDS_FRAG_SIZE)
- return hdr_buff;
-
- if (data_len <= (RDS_FRAG_SIZE - sizeof(struct rds_header))) {
- addr = kmap_atomic(recv->r_frag->f_page, KM_SOFTIRQ0);
- memcpy(hdr_buff,
- addr + recv->r_frag->f_offset + data_len,
- sizeof(struct rds_header));
- kunmap_atomic(addr, KM_SOFTIRQ0);
- return hdr_buff;
- }
-
- misplaced_hdr_bytes = (sizeof(struct rds_header) - (RDS_FRAG_SIZE - data_len));
-
- memmove(hdr_buff + misplaced_hdr_bytes, hdr_buff, misplaced_hdr_bytes);
-
- addr = kmap_atomic(recv->r_frag->f_page, KM_SOFTIRQ0);
- memcpy(hdr_buff, addr + recv->r_frag->f_offset + data_len,
- sizeof(struct rds_header) - misplaced_hdr_bytes);
- kunmap_atomic(addr, KM_SOFTIRQ0);
- return hdr_buff;
-}
-
/*
* It's kind of lame that we're copying from the posted receive pages into
* long-lived bitmaps. We could have posted the bitmaps and rdma written into
@@ -639,7 +763,7 @@ static void rds_ib_cong_recv(struct rds_connection *conn,
to_copy = min(RDS_FRAG_SIZE - frag_off, PAGE_SIZE - map_off);
BUG_ON(to_copy & 7); /* Must be 64bit aligned. */
- addr = kmap_atomic(frag->f_page, KM_SOFTIRQ0);
+ addr = kmap_atomic(sg_page(&frag->f_sg), KM_SOFTIRQ0);
src = addr + frag_off;
dst = (void *)map->m_page_addrs[map_page] + map_off;
@@ -710,7 +834,7 @@ static void rds_ib_process_recv(struct rds_connection *conn,
}
data_len -= sizeof(struct rds_header);
- ihdr = rds_ib_get_header(conn, recv, data_len);
+ ihdr = &ic->i_recv_hdrs[recv - ic->i_recvs];
/* Validate the checksum. */
if (!rds_message_verify_checksum(ihdr)) {
@@ -742,12 +866,12 @@ static void rds_ib_process_recv(struct rds_connection *conn,
* the inc is freed. We don't go that route, so we have to drop the
* page ref ourselves. We can't just leave the page on the recv
* because that confuses the dma mapping of pages and each recv's use
- * of a partial page. We can leave the frag, though, it will be
- * reused.
+ * of a partial page.
*
* FIXME: Fold this into the code path below.
*/
- rds_ib_frag_drop_page(recv->r_frag);
+ rds_ib_frag_free(ic, recv->r_frag);
+ recv->r_frag = NULL;
return;
}
@@ -757,7 +881,7 @@ static void rds_ib_process_recv(struct rds_connection *conn,
* into the inc and save the inc so we can hang upcoming fragments
* off its list.
*/
- if (ibinc == NULL) {
+ if (!ibinc) {
ibinc = recv->r_ibinc;
recv->r_ibinc = NULL;
ic->i_ibinc = ibinc;
@@ -842,32 +966,38 @@ static inline void rds_poll_cq(struct rds_ib_connection *ic,
struct rds_ib_recv_work *recv;
while (ib_poll_cq(ic->i_recv_cq, 1, &wc) > 0) {
- rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n",
- (unsigned long long)wc.wr_id, wc.status, wc.byte_len,
+ rdsdebug("wc wr_id 0x%llx status %u (%s) byte_len %u imm_data %u\n",
+ (unsigned long long)wc.wr_id, wc.status,
+ rds_ib_wc_status_str(wc.status), wc.byte_len,
be32_to_cpu(wc.ex.imm_data));
rds_ib_stats_inc(s_ib_rx_cq_event);
recv = &ic->i_recvs[rds_ib_ring_oldest(&ic->i_recv_ring)];
- rds_ib_recv_unmap_page(ic, recv);
+ ib_dma_unmap_sg(ic->i_cm_id->device, &recv->r_frag->f_sg, 1, DMA_FROM_DEVICE);
/*
* Also process recvs in connecting state because it is possible
* to get a recv completion _before_ the rdmacm ESTABLISHED
* event is processed.
*/
- if (rds_conn_up(conn) || rds_conn_connecting(conn)) {
+ if (wc.status == IB_WC_SUCCESS) {
+ rds_ib_process_recv(conn, recv, wc.byte_len, state);
+ } else {
/* We expect errors as the qp is drained during shutdown */
- if (wc.status == IB_WC_SUCCESS) {
- rds_ib_process_recv(conn, recv, wc.byte_len, state);
- } else {
- rds_ib_conn_error(conn, "recv completion on "
- "%pI4 had status %u, disconnecting and "
- "reconnecting\n", &conn->c_faddr,
- wc.status);
- }
+ if (rds_conn_up(conn) || rds_conn_connecting(conn))
+ rds_ib_conn_error(conn, "recv completion on %pI4 had "
+ "status %u (%s), disconnecting and "
+ "reconnecting\n", &conn->c_faddr,
+ wc.status,
+ rds_ib_wc_status_str(wc.status));
}
+ /*
+ * It's very important that we only free this ring entry if we've truly
+ * freed the resources allocated to the entry. The refilling path can
+ * leak if we don't.
+ */
rds_ib_ring_free(&ic->i_recv_ring, 1);
}
}
@@ -897,11 +1027,8 @@ void rds_ib_recv_tasklet_fn(unsigned long data)
if (rds_ib_ring_empty(&ic->i_recv_ring))
rds_ib_stats_inc(s_ib_rx_ring_empty);
- /*
- * If the ring is running low, then schedule the thread to refill.
- */
if (rds_ib_ring_low(&ic->i_recv_ring))
- queue_delayed_work(rds_wq, &conn->c_recv_w, 0);
+ rds_ib_recv_refill(conn, 0);
}
int rds_ib_recv(struct rds_connection *conn)
@@ -910,25 +1037,13 @@ int rds_ib_recv(struct rds_connection *conn)
int ret = 0;
rdsdebug("conn %p\n", conn);
-
- /*
- * If we get a temporary posting failure in this context then
- * we're really low and we want the caller to back off for a bit.
- */
- mutex_lock(&ic->i_recv_mutex);
- if (rds_ib_recv_refill(conn, GFP_KERNEL, GFP_HIGHUSER, 0))
- ret = -ENOMEM;
- else
- rds_ib_stats_inc(s_ib_rx_refill_from_thread);
- mutex_unlock(&ic->i_recv_mutex);
-
if (rds_conn_up(conn))
rds_ib_attempt_ack(ic);
return ret;
}
-int __init rds_ib_recv_init(void)
+int rds_ib_recv_init(void)
{
struct sysinfo si;
int ret = -ENOMEM;
@@ -939,14 +1054,14 @@ int __init rds_ib_recv_init(void)
rds_ib_incoming_slab = kmem_cache_create("rds_ib_incoming",
sizeof(struct rds_ib_incoming),
- 0, 0, NULL);
- if (rds_ib_incoming_slab == NULL)
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!rds_ib_incoming_slab)
goto out;
rds_ib_frag_slab = kmem_cache_create("rds_ib_frag",
sizeof(struct rds_page_frag),
- 0, 0, NULL);
- if (rds_ib_frag_slab == NULL)
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!rds_ib_frag_slab)
kmem_cache_destroy(rds_ib_incoming_slab);
else
ret = 0;
diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c
index 17fa80803ab0..71f373c421bc 100644
--- a/net/rds/ib_send.c
+++ b/net/rds/ib_send.c
@@ -36,11 +36,49 @@
#include <linux/dmapool.h>
#include "rds.h"
-#include "rdma.h"
#include "ib.h"
-static void rds_ib_send_rdma_complete(struct rds_message *rm,
- int wc_status)
+static char *rds_ib_wc_status_strings[] = {
+#define RDS_IB_WC_STATUS_STR(foo) \
+ [IB_WC_##foo] = __stringify(IB_WC_##foo)
+ RDS_IB_WC_STATUS_STR(SUCCESS),
+ RDS_IB_WC_STATUS_STR(LOC_LEN_ERR),
+ RDS_IB_WC_STATUS_STR(LOC_QP_OP_ERR),
+ RDS_IB_WC_STATUS_STR(LOC_EEC_OP_ERR),
+ RDS_IB_WC_STATUS_STR(LOC_PROT_ERR),
+ RDS_IB_WC_STATUS_STR(WR_FLUSH_ERR),
+ RDS_IB_WC_STATUS_STR(MW_BIND_ERR),
+ RDS_IB_WC_STATUS_STR(BAD_RESP_ERR),
+ RDS_IB_WC_STATUS_STR(LOC_ACCESS_ERR),
+ RDS_IB_WC_STATUS_STR(REM_INV_REQ_ERR),
+ RDS_IB_WC_STATUS_STR(REM_ACCESS_ERR),
+ RDS_IB_WC_STATUS_STR(REM_OP_ERR),
+ RDS_IB_WC_STATUS_STR(RETRY_EXC_ERR),
+ RDS_IB_WC_STATUS_STR(RNR_RETRY_EXC_ERR),
+ RDS_IB_WC_STATUS_STR(LOC_RDD_VIOL_ERR),
+ RDS_IB_WC_STATUS_STR(REM_INV_RD_REQ_ERR),
+ RDS_IB_WC_STATUS_STR(REM_ABORT_ERR),
+ RDS_IB_WC_STATUS_STR(INV_EECN_ERR),
+ RDS_IB_WC_STATUS_STR(INV_EEC_STATE_ERR),
+ RDS_IB_WC_STATUS_STR(FATAL_ERR),
+ RDS_IB_WC_STATUS_STR(RESP_TIMEOUT_ERR),
+ RDS_IB_WC_STATUS_STR(GENERAL_ERR),
+#undef RDS_IB_WC_STATUS_STR
+};
+
+char *rds_ib_wc_status_str(enum ib_wc_status status)
+{
+ return rds_str_array(rds_ib_wc_status_strings,
+ ARRAY_SIZE(rds_ib_wc_status_strings), status);
+}
+
+/*
+ * Convert IB-specific error message to RDS error message and call core
+ * completion handler.
+ */
+static void rds_ib_send_complete(struct rds_message *rm,
+ int wc_status,
+ void (*complete)(struct rds_message *rm, int status))
{
int notify_status;
@@ -60,69 +98,125 @@ static void rds_ib_send_rdma_complete(struct rds_message *rm,
notify_status = RDS_RDMA_OTHER_ERROR;
break;
}
- rds_rdma_send_complete(rm, notify_status);
+ complete(rm, notify_status);
+}
+
+static void rds_ib_send_unmap_data(struct rds_ib_connection *ic,
+ struct rm_data_op *op,
+ int wc_status)
+{
+ if (op->op_nents)
+ ib_dma_unmap_sg(ic->i_cm_id->device,
+ op->op_sg, op->op_nents,
+ DMA_TO_DEVICE);
}
static void rds_ib_send_unmap_rdma(struct rds_ib_connection *ic,
- struct rds_rdma_op *op)
+ struct rm_rdma_op *op,
+ int wc_status)
{
- if (op->r_mapped) {
+ if (op->op_mapped) {
ib_dma_unmap_sg(ic->i_cm_id->device,
- op->r_sg, op->r_nents,
- op->r_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- op->r_mapped = 0;
+ op->op_sg, op->op_nents,
+ op->op_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ op->op_mapped = 0;
}
+
+ /* If the user asked for a completion notification on this
+ * message, we can implement three different semantics:
+ * 1. Notify when we received the ACK on the RDS message
+ * that was queued with the RDMA. This provides reliable
+ * notification of RDMA status at the expense of a one-way
+ * packet delay.
+ * 2. Notify when the IB stack gives us the completion event for
+ * the RDMA operation.
+ * 3. Notify when the IB stack gives us the completion event for
+ * the accompanying RDS messages.
+ * Here, we implement approach #3. To implement approach #2,
+ * we would need to take an event for the rdma WR. To implement #1,
+ * don't call rds_rdma_send_complete at all, and fall back to the notify
+ * handling in the ACK processing code.
+ *
+ * Note: There's no need to explicitly sync any RDMA buffers using
+ * ib_dma_sync_sg_for_cpu - the completion for the RDMA
+ * operation itself unmapped the RDMA buffers, which takes care
+ * of synching.
+ */
+ rds_ib_send_complete(container_of(op, struct rds_message, rdma),
+ wc_status, rds_rdma_send_complete);
+
+ if (op->op_write)
+ rds_stats_add(s_send_rdma_bytes, op->op_bytes);
+ else
+ rds_stats_add(s_recv_rdma_bytes, op->op_bytes);
}
-static void rds_ib_send_unmap_rm(struct rds_ib_connection *ic,
- struct rds_ib_send_work *send,
- int wc_status)
+static void rds_ib_send_unmap_atomic(struct rds_ib_connection *ic,
+ struct rm_atomic_op *op,
+ int wc_status)
{
- struct rds_message *rm = send->s_rm;
-
- rdsdebug("ic %p send %p rm %p\n", ic, send, rm);
-
- ib_dma_unmap_sg(ic->i_cm_id->device,
- rm->m_sg, rm->m_nents,
- DMA_TO_DEVICE);
-
- if (rm->m_rdma_op != NULL) {
- rds_ib_send_unmap_rdma(ic, rm->m_rdma_op);
-
- /* If the user asked for a completion notification on this
- * message, we can implement three different semantics:
- * 1. Notify when we received the ACK on the RDS message
- * that was queued with the RDMA. This provides reliable
- * notification of RDMA status at the expense of a one-way
- * packet delay.
- * 2. Notify when the IB stack gives us the completion event for
- * the RDMA operation.
- * 3. Notify when the IB stack gives us the completion event for
- * the accompanying RDS messages.
- * Here, we implement approach #3. To implement approach #2,
- * call rds_rdma_send_complete from the cq_handler. To implement #1,
- * don't call rds_rdma_send_complete at all, and fall back to the notify
- * handling in the ACK processing code.
- *
- * Note: There's no need to explicitly sync any RDMA buffers using
- * ib_dma_sync_sg_for_cpu - the completion for the RDMA
- * operation itself unmapped the RDMA buffers, which takes care
- * of synching.
- */
- rds_ib_send_rdma_complete(rm, wc_status);
+ /* unmap atomic recvbuf */
+ if (op->op_mapped) {
+ ib_dma_unmap_sg(ic->i_cm_id->device, op->op_sg, 1,
+ DMA_FROM_DEVICE);
+ op->op_mapped = 0;
+ }
- if (rm->m_rdma_op->r_write)
- rds_stats_add(s_send_rdma_bytes, rm->m_rdma_op->r_bytes);
- else
- rds_stats_add(s_recv_rdma_bytes, rm->m_rdma_op->r_bytes);
+ rds_ib_send_complete(container_of(op, struct rds_message, atomic),
+ wc_status, rds_atomic_send_complete);
+
+ if (op->op_type == RDS_ATOMIC_TYPE_CSWP)
+ rds_ib_stats_inc(s_ib_atomic_cswp);
+ else
+ rds_ib_stats_inc(s_ib_atomic_fadd);
+}
+
+/*
+ * Unmap the resources associated with a struct send_work.
+ *
+ * Returns the rm for no good reason other than it is unobtainable
+ * other than by switching on wr.opcode, currently, and the caller,
+ * the event handler, needs it.
+ */
+static struct rds_message *rds_ib_send_unmap_op(struct rds_ib_connection *ic,
+ struct rds_ib_send_work *send,
+ int wc_status)
+{
+ struct rds_message *rm = NULL;
+
+ /* In the error case, wc.opcode sometimes contains garbage */
+ switch (send->s_wr.opcode) {
+ case IB_WR_SEND:
+ if (send->s_op) {
+ rm = container_of(send->s_op, struct rds_message, data);
+ rds_ib_send_unmap_data(ic, send->s_op, wc_status);
+ }
+ break;
+ case IB_WR_RDMA_WRITE:
+ case IB_WR_RDMA_READ:
+ if (send->s_op) {
+ rm = container_of(send->s_op, struct rds_message, rdma);
+ rds_ib_send_unmap_rdma(ic, send->s_op, wc_status);
+ }
+ break;
+ case IB_WR_ATOMIC_FETCH_AND_ADD:
+ case IB_WR_ATOMIC_CMP_AND_SWP:
+ if (send->s_op) {
+ rm = container_of(send->s_op, struct rds_message, atomic);
+ rds_ib_send_unmap_atomic(ic, send->s_op, wc_status);
+ }
+ break;
+ default:
+ if (printk_ratelimit())
+ printk(KERN_NOTICE
+ "RDS/IB: %s: unexpected opcode 0x%x in WR!\n",
+ __func__, send->s_wr.opcode);
+ break;
}
- /* If anyone waited for this message to get flushed out, wake
- * them up now */
- rds_message_unmapped(rm);
+ send->s_wr.opcode = 0xdead;
- rds_message_put(rm);
- send->s_rm = NULL;
+ return rm;
}
void rds_ib_send_init_ring(struct rds_ib_connection *ic)
@@ -133,23 +227,18 @@ void rds_ib_send_init_ring(struct rds_ib_connection *ic)
for (i = 0, send = ic->i_sends; i < ic->i_send_ring.w_nr; i++, send++) {
struct ib_sge *sge;
- send->s_rm = NULL;
send->s_op = NULL;
send->s_wr.wr_id = i;
send->s_wr.sg_list = send->s_sge;
- send->s_wr.num_sge = 1;
- send->s_wr.opcode = IB_WR_SEND;
- send->s_wr.send_flags = 0;
send->s_wr.ex.imm_data = 0;
- sge = rds_ib_data_sge(ic, send->s_sge);
- sge->lkey = ic->i_mr->lkey;
-
- sge = rds_ib_header_sge(ic, send->s_sge);
+ sge = &send->s_sge[0];
sge->addr = ic->i_send_hdrs_dma + (i * sizeof(struct rds_header));
sge->length = sizeof(struct rds_header);
sge->lkey = ic->i_mr->lkey;
+
+ send->s_sge[1].lkey = ic->i_mr->lkey;
}
}
@@ -159,16 +248,24 @@ void rds_ib_send_clear_ring(struct rds_ib_connection *ic)
u32 i;
for (i = 0, send = ic->i_sends; i < ic->i_send_ring.w_nr; i++, send++) {
- if (send->s_wr.opcode == 0xdead)
- continue;
- if (send->s_rm)
- rds_ib_send_unmap_rm(ic, send, IB_WC_WR_FLUSH_ERR);
- if (send->s_op)
- rds_ib_send_unmap_rdma(ic, send->s_op);
+ if (send->s_op && send->s_wr.opcode != 0xdead)
+ rds_ib_send_unmap_op(ic, send, IB_WC_WR_FLUSH_ERR);
}
}
/*
+ * The only fast path caller always has a non-zero nr, so we don't
+ * bother testing nr before performing the atomic sub.
+ */
+static void rds_ib_sub_signaled(struct rds_ib_connection *ic, int nr)
+{
+ if ((atomic_sub_return(nr, &ic->i_signaled_sends) == 0) &&
+ waitqueue_active(&rds_ib_ring_empty_wait))
+ wake_up(&rds_ib_ring_empty_wait);
+ BUG_ON(atomic_read(&ic->i_signaled_sends) < 0);
+}
+
+/*
* The _oldest/_free ring operations here race cleanly with the alloc/unalloc
* operations performed in the send path. As the sender allocs and potentially
* unallocs the next free entry in the ring it doesn't alter which is
@@ -178,12 +275,14 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
{
struct rds_connection *conn = context;
struct rds_ib_connection *ic = conn->c_transport_data;
+ struct rds_message *rm = NULL;
struct ib_wc wc;
struct rds_ib_send_work *send;
u32 completed;
u32 oldest;
u32 i = 0;
int ret;
+ int nr_sig = 0;
rdsdebug("cq %p conn %p\n", cq, conn);
rds_ib_stats_inc(s_ib_tx_cq_call);
@@ -192,8 +291,9 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
rdsdebug("ib_req_notify_cq send failed: %d\n", ret);
while (ib_poll_cq(cq, 1, &wc) > 0) {
- rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n",
- (unsigned long long)wc.wr_id, wc.status, wc.byte_len,
+ rdsdebug("wc wr_id 0x%llx status %u (%s) byte_len %u imm_data %u\n",
+ (unsigned long long)wc.wr_id, wc.status,
+ rds_ib_wc_status_str(wc.status), wc.byte_len,
be32_to_cpu(wc.ex.imm_data));
rds_ib_stats_inc(s_ib_tx_cq_event);
@@ -210,51 +310,30 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
for (i = 0; i < completed; i++) {
send = &ic->i_sends[oldest];
+ if (send->s_wr.send_flags & IB_SEND_SIGNALED)
+ nr_sig++;
- /* In the error case, wc.opcode sometimes contains garbage */
- switch (send->s_wr.opcode) {
- case IB_WR_SEND:
- if (send->s_rm)
- rds_ib_send_unmap_rm(ic, send, wc.status);
- break;
- case IB_WR_RDMA_WRITE:
- case IB_WR_RDMA_READ:
- /* Nothing to be done - the SG list will be unmapped
- * when the SEND completes. */
- break;
- default:
- if (printk_ratelimit())
- printk(KERN_NOTICE
- "RDS/IB: %s: unexpected opcode 0x%x in WR!\n",
- __func__, send->s_wr.opcode);
- break;
- }
+ rm = rds_ib_send_unmap_op(ic, send, wc.status);
- send->s_wr.opcode = 0xdead;
- send->s_wr.num_sge = 1;
if (send->s_queued + HZ/2 < jiffies)
rds_ib_stats_inc(s_ib_tx_stalled);
- /* If a RDMA operation produced an error, signal this right
- * away. If we don't, the subsequent SEND that goes with this
- * RDMA will be canceled with ERR_WFLUSH, and the application
- * never learn that the RDMA failed. */
- if (unlikely(wc.status == IB_WC_REM_ACCESS_ERR && send->s_op)) {
- struct rds_message *rm;
-
- rm = rds_send_get_message(conn, send->s_op);
- if (rm) {
- if (rm->m_rdma_op)
- rds_ib_send_unmap_rdma(ic, rm->m_rdma_op);
- rds_ib_send_rdma_complete(rm, wc.status);
- rds_message_put(rm);
+ if (send->s_op) {
+ if (send->s_op == rm->m_final_op) {
+ /* If anyone waited for this message to get flushed out, wake
+ * them up now */
+ rds_message_unmapped(rm);
}
+ rds_message_put(rm);
+ send->s_op = NULL;
}
oldest = (oldest + 1) % ic->i_send_ring.w_nr;
}
rds_ib_ring_free(&ic->i_send_ring, completed);
+ rds_ib_sub_signaled(ic, nr_sig);
+ nr_sig = 0;
if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags) ||
test_bit(0, &conn->c_map_queued))
@@ -262,10 +341,10 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
/* We expect errors as the qp is drained during shutdown */
if (wc.status != IB_WC_SUCCESS && rds_conn_up(conn)) {
- rds_ib_conn_error(conn,
- "send completion on %pI4 "
- "had status %u, disconnecting and reconnecting\n",
- &conn->c_faddr, wc.status);
+ rds_ib_conn_error(conn, "send completion on %pI4 had status "
+ "%u (%s), disconnecting and reconnecting\n",
+ &conn->c_faddr, wc.status,
+ rds_ib_wc_status_str(wc.status));
}
}
}
@@ -294,7 +373,7 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
* credits (see rds_ib_send_add_credits below).
*
* The RDS send code is essentially single-threaded; rds_send_xmit
- * grabs c_send_lock to ensure exclusive access to the send ring.
+ * sets RDS_IN_XMIT to ensure exclusive access to the send ring.
* However, the ACK sending code is independent and can race with
* message SENDs.
*
@@ -413,40 +492,21 @@ void rds_ib_advertise_credits(struct rds_connection *conn, unsigned int posted)
set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
}
-static inline void
-rds_ib_xmit_populate_wr(struct rds_ib_connection *ic,
- struct rds_ib_send_work *send, unsigned int pos,
- unsigned long buffer, unsigned int length,
- int send_flags)
+static inline int rds_ib_set_wr_signal_state(struct rds_ib_connection *ic,
+ struct rds_ib_send_work *send,
+ bool notify)
{
- struct ib_sge *sge;
-
- WARN_ON(pos != send - ic->i_sends);
-
- send->s_wr.send_flags = send_flags;
- send->s_wr.opcode = IB_WR_SEND;
- send->s_wr.num_sge = 2;
- send->s_wr.next = NULL;
- send->s_queued = jiffies;
- send->s_op = NULL;
-
- if (length != 0) {
- sge = rds_ib_data_sge(ic, send->s_sge);
- sge->addr = buffer;
- sge->length = length;
- sge->lkey = ic->i_mr->lkey;
-
- sge = rds_ib_header_sge(ic, send->s_sge);
- } else {
- /* We're sending a packet with no payload. There is only
- * one SGE */
- send->s_wr.num_sge = 1;
- sge = &send->s_sge[0];
+ /*
+ * We want to delay signaling completions just enough to get
+ * the batching benefits but not so much that we create dead time
+ * on the wire.
+ */
+ if (ic->i_unsignaled_wrs-- == 0 || notify) {
+ ic->i_unsignaled_wrs = rds_ib_sysctl_max_unsig_wrs;
+ send->s_wr.send_flags |= IB_SEND_SIGNALED;
+ return 1;
}
-
- sge->addr = ic->i_send_hdrs_dma + (pos * sizeof(struct rds_header));
- sge->length = sizeof(struct rds_header);
- sge->lkey = ic->i_mr->lkey;
+ return 0;
}
/*
@@ -475,13 +535,14 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
u32 pos;
u32 i;
u32 work_alloc;
- u32 credit_alloc;
+ u32 credit_alloc = 0;
u32 posted;
u32 adv_credits = 0;
int send_flags = 0;
- int sent;
+ int bytes_sent = 0;
int ret;
int flow_controlled = 0;
+ int nr_sig = 0;
BUG_ON(off % RDS_FRAG_SIZE);
BUG_ON(hdr_off != 0 && hdr_off != sizeof(struct rds_header));
@@ -507,14 +568,13 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
goto out;
}
- credit_alloc = work_alloc;
if (ic->i_flowctl) {
credit_alloc = rds_ib_send_grab_credits(ic, work_alloc, &posted, 0, RDS_MAX_ADV_CREDIT);
adv_credits += posted;
if (credit_alloc < work_alloc) {
rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc - credit_alloc);
work_alloc = credit_alloc;
- flow_controlled++;
+ flow_controlled = 1;
}
if (work_alloc == 0) {
set_bit(RDS_LL_SEND_FULL, &conn->c_flags);
@@ -525,31 +585,25 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
}
/* map the message the first time we see it */
- if (ic->i_rm == NULL) {
- /*
- printk(KERN_NOTICE "rds_ib_xmit prep msg dport=%u flags=0x%x len=%d\n",
- be16_to_cpu(rm->m_inc.i_hdr.h_dport),
- rm->m_inc.i_hdr.h_flags,
- be32_to_cpu(rm->m_inc.i_hdr.h_len));
- */
- if (rm->m_nents) {
- rm->m_count = ib_dma_map_sg(dev,
- rm->m_sg, rm->m_nents, DMA_TO_DEVICE);
- rdsdebug("ic %p mapping rm %p: %d\n", ic, rm, rm->m_count);
- if (rm->m_count == 0) {
+ if (!ic->i_data_op) {
+ if (rm->data.op_nents) {
+ rm->data.op_count = ib_dma_map_sg(dev,
+ rm->data.op_sg,
+ rm->data.op_nents,
+ DMA_TO_DEVICE);
+ rdsdebug("ic %p mapping rm %p: %d\n", ic, rm, rm->data.op_count);
+ if (rm->data.op_count == 0) {
rds_ib_stats_inc(s_ib_tx_sg_mapping_failure);
rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
ret = -ENOMEM; /* XXX ? */
goto out;
}
} else {
- rm->m_count = 0;
+ rm->data.op_count = 0;
}
- ic->i_unsignaled_wrs = rds_ib_sysctl_max_unsig_wrs;
- ic->i_unsignaled_bytes = rds_ib_sysctl_max_unsig_bytes;
rds_message_addref(rm);
- ic->i_rm = rm;
+ ic->i_data_op = &rm->data;
/* Finalize the header */
if (test_bit(RDS_MSG_ACK_REQUIRED, &rm->m_flags))
@@ -559,10 +613,10 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
/* If it has a RDMA op, tell the peer we did it. This is
* used by the peer to release use-once RDMA MRs. */
- if (rm->m_rdma_op) {
+ if (rm->rdma.op_active) {
struct rds_ext_header_rdma ext_hdr;
- ext_hdr.h_rdma_rkey = cpu_to_be32(rm->m_rdma_op->r_key);
+ ext_hdr.h_rdma_rkey = cpu_to_be32(rm->rdma.op_rkey);
rds_message_add_extension(&rm->m_inc.i_hdr,
RDS_EXTHDR_RDMA, &ext_hdr, sizeof(ext_hdr));
}
@@ -582,99 +636,77 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
/*
* Update adv_credits since we reset the ACK_REQUIRED bit.
*/
- rds_ib_send_grab_credits(ic, 0, &posted, 1, RDS_MAX_ADV_CREDIT - adv_credits);
- adv_credits += posted;
- BUG_ON(adv_credits > 255);
+ if (ic->i_flowctl) {
+ rds_ib_send_grab_credits(ic, 0, &posted, 1, RDS_MAX_ADV_CREDIT - adv_credits);
+ adv_credits += posted;
+ BUG_ON(adv_credits > 255);
+ }
}
- send = &ic->i_sends[pos];
- first = send;
- prev = NULL;
- scat = &rm->m_sg[sg];
- sent = 0;
- i = 0;
-
/* Sometimes you want to put a fence between an RDMA
* READ and the following SEND.
* We could either do this all the time
* or when requested by the user. Right now, we let
* the application choose.
*/
- if (rm->m_rdma_op && rm->m_rdma_op->r_fence)
+ if (rm->rdma.op_active && rm->rdma.op_fence)
send_flags = IB_SEND_FENCE;
- /*
- * We could be copying the header into the unused tail of the page.
- * That would need to be changed in the future when those pages might
- * be mapped userspace pages or page cache pages. So instead we always
- * use a second sge and our long-lived ring of mapped headers. We send
- * the header after the data so that the data payload can be aligned on
- * the receiver.
- */
+ /* Each frag gets a header. Msgs may be 0 bytes */
+ send = &ic->i_sends[pos];
+ first = send;
+ prev = NULL;
+ scat = &ic->i_data_op->op_sg[sg];
+ i = 0;
+ do {
+ unsigned int len = 0;
- /* handle a 0-len message */
- if (be32_to_cpu(rm->m_inc.i_hdr.h_len) == 0) {
- rds_ib_xmit_populate_wr(ic, send, pos, 0, 0, send_flags);
- goto add_header;
- }
+ /* Set up the header */
+ send->s_wr.send_flags = send_flags;
+ send->s_wr.opcode = IB_WR_SEND;
+ send->s_wr.num_sge = 1;
+ send->s_wr.next = NULL;
+ send->s_queued = jiffies;
+ send->s_op = NULL;
- /* if there's data reference it with a chain of work reqs */
- for (; i < work_alloc && scat != &rm->m_sg[rm->m_count]; i++) {
- unsigned int len;
+ send->s_sge[0].addr = ic->i_send_hdrs_dma
+ + (pos * sizeof(struct rds_header));
+ send->s_sge[0].length = sizeof(struct rds_header);
- send = &ic->i_sends[pos];
+ memcpy(&ic->i_send_hdrs[pos], &rm->m_inc.i_hdr, sizeof(struct rds_header));
- len = min(RDS_FRAG_SIZE, ib_sg_dma_len(dev, scat) - off);
- rds_ib_xmit_populate_wr(ic, send, pos,
- ib_sg_dma_address(dev, scat) + off, len,
- send_flags);
+ /* Set up the data, if present */
+ if (i < work_alloc
+ && scat != &rm->data.op_sg[rm->data.op_count]) {
+ len = min(RDS_FRAG_SIZE, ib_sg_dma_len(dev, scat) - off);
+ send->s_wr.num_sge = 2;
- /*
- * We want to delay signaling completions just enough to get
- * the batching benefits but not so much that we create dead time
- * on the wire.
- */
- if (ic->i_unsignaled_wrs-- == 0) {
- ic->i_unsignaled_wrs = rds_ib_sysctl_max_unsig_wrs;
- send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
- }
+ send->s_sge[1].addr = ib_sg_dma_address(dev, scat) + off;
+ send->s_sge[1].length = len;
- ic->i_unsignaled_bytes -= len;
- if (ic->i_unsignaled_bytes <= 0) {
- ic->i_unsignaled_bytes = rds_ib_sysctl_max_unsig_bytes;
- send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+ bytes_sent += len;
+ off += len;
+ if (off == ib_sg_dma_len(dev, scat)) {
+ scat++;
+ off = 0;
+ }
}
+ rds_ib_set_wr_signal_state(ic, send, 0);
+
/*
* Always signal the last one if we're stopping due to flow control.
*/
- if (flow_controlled && i == (work_alloc-1))
+ if (ic->i_flowctl && flow_controlled && i == (work_alloc-1))
send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+ if (send->s_wr.send_flags & IB_SEND_SIGNALED)
+ nr_sig++;
+
rdsdebug("send %p wr %p num_sge %u next %p\n", send,
&send->s_wr, send->s_wr.num_sge, send->s_wr.next);
- sent += len;
- off += len;
- if (off == ib_sg_dma_len(dev, scat)) {
- scat++;
- off = 0;
- }
-
-add_header:
- /* Tack on the header after the data. The header SGE should already
- * have been set up to point to the right header buffer. */
- memcpy(&ic->i_send_hdrs[pos], &rm->m_inc.i_hdr, sizeof(struct rds_header));
-
- if (0) {
- struct rds_header *hdr = &ic->i_send_hdrs[pos];
-
- printk(KERN_NOTICE "send WR dport=%u flags=0x%x len=%d\n",
- be16_to_cpu(hdr->h_dport),
- hdr->h_flags,
- be32_to_cpu(hdr->h_len));
- }
- if (adv_credits) {
+ if (ic->i_flowctl && adv_credits) {
struct rds_header *hdr = &ic->i_send_hdrs[pos];
/* add credit and redo the header checksum */
@@ -689,20 +721,25 @@ add_header:
prev = send;
pos = (pos + 1) % ic->i_send_ring.w_nr;
- }
+ send = &ic->i_sends[pos];
+ i++;
+
+ } while (i < work_alloc
+ && scat != &rm->data.op_sg[rm->data.op_count]);
/* Account the RDS header in the number of bytes we sent, but just once.
* The caller has no concept of fragmentation. */
if (hdr_off == 0)
- sent += sizeof(struct rds_header);
+ bytes_sent += sizeof(struct rds_header);
/* if we finished the message then send completion owns it */
- if (scat == &rm->m_sg[rm->m_count]) {
- prev->s_rm = ic->i_rm;
- prev->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
- ic->i_rm = NULL;
+ if (scat == &rm->data.op_sg[rm->data.op_count]) {
+ prev->s_op = ic->i_data_op;
+ prev->s_wr.send_flags |= IB_SEND_SOLICITED;
+ ic->i_data_op = NULL;
}
+ /* Put back wrs & credits we didn't use */
if (i < work_alloc) {
rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc - i);
work_alloc = i;
@@ -710,6 +747,9 @@ add_header:
if (ic->i_flowctl && i < credit_alloc)
rds_ib_send_add_credits(conn, credit_alloc - i);
+ if (nr_sig)
+ atomic_add(nr_sig, &ic->i_signaled_sends);
+
/* XXX need to worry about failed_wr and partial sends. */
failed_wr = &first->s_wr;
ret = ib_post_send(ic->i_cm_id->qp, &first->s_wr, &failed_wr);
@@ -720,32 +760,127 @@ add_header:
printk(KERN_WARNING "RDS/IB: ib_post_send to %pI4 "
"returned %d\n", &conn->c_faddr, ret);
rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
- if (prev->s_rm) {
- ic->i_rm = prev->s_rm;
- prev->s_rm = NULL;
+ rds_ib_sub_signaled(ic, nr_sig);
+ if (prev->s_op) {
+ ic->i_data_op = prev->s_op;
+ prev->s_op = NULL;
}
rds_ib_conn_error(ic->conn, "ib_post_send failed\n");
goto out;
}
- ret = sent;
+ ret = bytes_sent;
out:
BUG_ON(adv_credits);
return ret;
}
-int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
+/*
+ * Issue atomic operation.
+ * A simplified version of the rdma case, we always map 1 SG, and
+ * only 8 bytes, for the return value from the atomic operation.
+ */
+int rds_ib_xmit_atomic(struct rds_connection *conn, struct rm_atomic_op *op)
+{
+ struct rds_ib_connection *ic = conn->c_transport_data;
+ struct rds_ib_send_work *send = NULL;
+ struct ib_send_wr *failed_wr;
+ struct rds_ib_device *rds_ibdev;
+ u32 pos;
+ u32 work_alloc;
+ int ret;
+ int nr_sig = 0;
+
+ rds_ibdev = ib_get_client_data(ic->i_cm_id->device, &rds_ib_client);
+
+ work_alloc = rds_ib_ring_alloc(&ic->i_send_ring, 1, &pos);
+ if (work_alloc != 1) {
+ rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
+ rds_ib_stats_inc(s_ib_tx_ring_full);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* address of send request in ring */
+ send = &ic->i_sends[pos];
+ send->s_queued = jiffies;
+
+ if (op->op_type == RDS_ATOMIC_TYPE_CSWP) {
+ send->s_wr.opcode = IB_WR_MASKED_ATOMIC_CMP_AND_SWP;
+ send->s_wr.wr.atomic.compare_add = op->op_m_cswp.compare;
+ send->s_wr.wr.atomic.swap = op->op_m_cswp.swap;
+ send->s_wr.wr.atomic.compare_add_mask = op->op_m_cswp.compare_mask;
+ send->s_wr.wr.atomic.swap_mask = op->op_m_cswp.swap_mask;
+ } else { /* FADD */
+ send->s_wr.opcode = IB_WR_MASKED_ATOMIC_FETCH_AND_ADD;
+ send->s_wr.wr.atomic.compare_add = op->op_m_fadd.add;
+ send->s_wr.wr.atomic.swap = 0;
+ send->s_wr.wr.atomic.compare_add_mask = op->op_m_fadd.nocarry_mask;
+ send->s_wr.wr.atomic.swap_mask = 0;
+ }
+ nr_sig = rds_ib_set_wr_signal_state(ic, send, op->op_notify);
+ send->s_wr.num_sge = 1;
+ send->s_wr.next = NULL;
+ send->s_wr.wr.atomic.remote_addr = op->op_remote_addr;
+ send->s_wr.wr.atomic.rkey = op->op_rkey;
+ send->s_op = op;
+ rds_message_addref(container_of(send->s_op, struct rds_message, atomic));
+
+ /* map 8 byte retval buffer to the device */
+ ret = ib_dma_map_sg(ic->i_cm_id->device, op->op_sg, 1, DMA_FROM_DEVICE);
+ rdsdebug("ic %p mapping atomic op %p. mapped %d pg\n", ic, op, ret);
+ if (ret != 1) {
+ rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
+ rds_ib_stats_inc(s_ib_tx_sg_mapping_failure);
+ ret = -ENOMEM; /* XXX ? */
+ goto out;
+ }
+
+ /* Convert our struct scatterlist to struct ib_sge */
+ send->s_sge[0].addr = ib_sg_dma_address(ic->i_cm_id->device, op->op_sg);
+ send->s_sge[0].length = ib_sg_dma_len(ic->i_cm_id->device, op->op_sg);
+ send->s_sge[0].lkey = ic->i_mr->lkey;
+
+ rdsdebug("rva %Lx rpa %Lx len %u\n", op->op_remote_addr,
+ send->s_sge[0].addr, send->s_sge[0].length);
+
+ if (nr_sig)
+ atomic_add(nr_sig, &ic->i_signaled_sends);
+
+ failed_wr = &send->s_wr;
+ ret = ib_post_send(ic->i_cm_id->qp, &send->s_wr, &failed_wr);
+ rdsdebug("ic %p send %p (wr %p) ret %d wr %p\n", ic,
+ send, &send->s_wr, ret, failed_wr);
+ BUG_ON(failed_wr != &send->s_wr);
+ if (ret) {
+ printk(KERN_WARNING "RDS/IB: atomic ib_post_send to %pI4 "
+ "returned %d\n", &conn->c_faddr, ret);
+ rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
+ rds_ib_sub_signaled(ic, nr_sig);
+ goto out;
+ }
+
+ if (unlikely(failed_wr != &send->s_wr)) {
+ printk(KERN_WARNING "RDS/IB: atomic ib_post_send() rc=%d, but failed_wqe updated!\n", ret);
+ BUG_ON(failed_wr != &send->s_wr);
+ }
+
+out:
+ return ret;
+}
+
+int rds_ib_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
{
struct rds_ib_connection *ic = conn->c_transport_data;
struct rds_ib_send_work *send = NULL;
struct rds_ib_send_work *first;
struct rds_ib_send_work *prev;
struct ib_send_wr *failed_wr;
- struct rds_ib_device *rds_ibdev;
struct scatterlist *scat;
unsigned long len;
- u64 remote_addr = op->r_remote_addr;
+ u64 remote_addr = op->op_remote_addr;
+ u32 max_sge = ic->rds_ibdev->max_sge;
u32 pos;
u32 work_alloc;
u32 i;
@@ -753,29 +888,28 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
int sent;
int ret;
int num_sge;
-
- rds_ibdev = ib_get_client_data(ic->i_cm_id->device, &rds_ib_client);
-
- /* map the message the first time we see it */
- if (!op->r_mapped) {
- op->r_count = ib_dma_map_sg(ic->i_cm_id->device,
- op->r_sg, op->r_nents, (op->r_write) ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE);
- rdsdebug("ic %p mapping op %p: %d\n", ic, op, op->r_count);
- if (op->r_count == 0) {
+ int nr_sig = 0;
+
+ /* map the op the first time we see it */
+ if (!op->op_mapped) {
+ op->op_count = ib_dma_map_sg(ic->i_cm_id->device,
+ op->op_sg, op->op_nents, (op->op_write) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ rdsdebug("ic %p mapping op %p: %d\n", ic, op, op->op_count);
+ if (op->op_count == 0) {
rds_ib_stats_inc(s_ib_tx_sg_mapping_failure);
ret = -ENOMEM; /* XXX ? */
goto out;
}
- op->r_mapped = 1;
+ op->op_mapped = 1;
}
/*
* Instead of knowing how to return a partial rdma read/write we insist that there
* be enough work requests to send the entire message.
*/
- i = ceil(op->r_count, rds_ibdev->max_sge);
+ i = ceil(op->op_count, max_sge);
work_alloc = rds_ib_ring_alloc(&ic->i_send_ring, i, &pos);
if (work_alloc != i) {
@@ -788,30 +922,24 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
send = &ic->i_sends[pos];
first = send;
prev = NULL;
- scat = &op->r_sg[0];
+ scat = &op->op_sg[0];
sent = 0;
- num_sge = op->r_count;
+ num_sge = op->op_count;
- for (i = 0; i < work_alloc && scat != &op->r_sg[op->r_count]; i++) {
+ for (i = 0; i < work_alloc && scat != &op->op_sg[op->op_count]; i++) {
send->s_wr.send_flags = 0;
send->s_queued = jiffies;
- /*
- * We want to delay signaling completions just enough to get
- * the batching benefits but not so much that we create dead time on the wire.
- */
- if (ic->i_unsignaled_wrs-- == 0) {
- ic->i_unsignaled_wrs = rds_ib_sysctl_max_unsig_wrs;
- send->s_wr.send_flags = IB_SEND_SIGNALED;
- }
+ send->s_op = NULL;
+
+ nr_sig += rds_ib_set_wr_signal_state(ic, send, op->op_notify);
- send->s_wr.opcode = op->r_write ? IB_WR_RDMA_WRITE : IB_WR_RDMA_READ;
+ send->s_wr.opcode = op->op_write ? IB_WR_RDMA_WRITE : IB_WR_RDMA_READ;
send->s_wr.wr.rdma.remote_addr = remote_addr;
- send->s_wr.wr.rdma.rkey = op->r_key;
- send->s_op = op;
+ send->s_wr.wr.rdma.rkey = op->op_rkey;
- if (num_sge > rds_ibdev->max_sge) {
- send->s_wr.num_sge = rds_ibdev->max_sge;
- num_sge -= rds_ibdev->max_sge;
+ if (num_sge > max_sge) {
+ send->s_wr.num_sge = max_sge;
+ num_sge -= max_sge;
} else {
send->s_wr.num_sge = num_sge;
}
@@ -821,7 +949,7 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
if (prev)
prev->s_wr.next = &send->s_wr;
- for (j = 0; j < send->s_wr.num_sge && scat != &op->r_sg[op->r_count]; j++) {
+ for (j = 0; j < send->s_wr.num_sge && scat != &op->op_sg[op->op_count]; j++) {
len = ib_sg_dma_len(ic->i_cm_id->device, scat);
send->s_sge[j].addr =
ib_sg_dma_address(ic->i_cm_id->device, scat);
@@ -843,15 +971,20 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
send = ic->i_sends;
}
- /* if we finished the message then send completion owns it */
- if (scat == &op->r_sg[op->r_count])
- prev->s_wr.send_flags = IB_SEND_SIGNALED;
+ /* give a reference to the last op */
+ if (scat == &op->op_sg[op->op_count]) {
+ prev->s_op = op;
+ rds_message_addref(container_of(op, struct rds_message, rdma));
+ }
if (i < work_alloc) {
rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc - i);
work_alloc = i;
}
+ if (nr_sig)
+ atomic_add(nr_sig, &ic->i_signaled_sends);
+
failed_wr = &first->s_wr;
ret = ib_post_send(ic->i_cm_id->qp, &first->s_wr, &failed_wr);
rdsdebug("ic %p first %p (wr %p) ret %d wr %p\n", ic,
@@ -861,6 +994,7 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
printk(KERN_WARNING "RDS/IB: rdma ib_post_send to %pI4 "
"returned %d\n", &conn->c_faddr, ret);
rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
+ rds_ib_sub_signaled(ic, nr_sig);
goto out;
}
diff --git a/net/rds/ib_stats.c b/net/rds/ib_stats.c
index d2c904dd6fbc..2d5965d6e97c 100644
--- a/net/rds/ib_stats.c
+++ b/net/rds/ib_stats.c
@@ -67,6 +67,8 @@ static const char *const rds_ib_stat_names[] = {
"ib_rdma_mr_pool_flush",
"ib_rdma_mr_pool_wait",
"ib_rdma_mr_pool_depleted",
+ "ib_atomic_cswp",
+ "ib_atomic_fadd",
};
unsigned int rds_ib_stats_info_copy(struct rds_info_iterator *iter,
diff --git a/net/rds/ib_sysctl.c b/net/rds/ib_sysctl.c
index 03f01cb4e0fe..1253b006efdb 100644
--- a/net/rds/ib_sysctl.c
+++ b/net/rds/ib_sysctl.c
@@ -49,10 +49,6 @@ unsigned long rds_ib_sysctl_max_unsig_wrs = 16;
static unsigned long rds_ib_sysctl_max_unsig_wr_min = 1;
static unsigned long rds_ib_sysctl_max_unsig_wr_max = 64;
-unsigned long rds_ib_sysctl_max_unsig_bytes = (16 << 20);
-static unsigned long rds_ib_sysctl_max_unsig_bytes_min = 1;
-static unsigned long rds_ib_sysctl_max_unsig_bytes_max = ~0UL;
-
/*
* This sysctl does nothing.
*
@@ -65,7 +61,7 @@ static unsigned long rds_ib_sysctl_max_unsig_bytes_max = ~0UL;
*/
unsigned int rds_ib_sysctl_flow_control = 0;
-ctl_table rds_ib_sysctl_table[] = {
+static ctl_table rds_ib_sysctl_table[] = {
{
.procname = "max_send_wr",
.data = &rds_ib_sysctl_max_send_wr,
@@ -94,15 +90,6 @@ ctl_table rds_ib_sysctl_table[] = {
.extra2 = &rds_ib_sysctl_max_unsig_wr_max,
},
{
- .procname = "max_unsignaled_bytes",
- .data = &rds_ib_sysctl_max_unsig_bytes,
- .maxlen = sizeof(unsigned long),
- .mode = 0644,
- .proc_handler = proc_doulongvec_minmax,
- .extra1 = &rds_ib_sysctl_max_unsig_bytes_min,
- .extra2 = &rds_ib_sysctl_max_unsig_bytes_max,
- },
- {
.procname = "max_recv_allocation",
.data = &rds_ib_sysctl_max_recv_allocation,
.maxlen = sizeof(unsigned long),
@@ -132,10 +119,10 @@ void rds_ib_sysctl_exit(void)
unregister_sysctl_table(rds_ib_sysctl_hdr);
}
-int __init rds_ib_sysctl_init(void)
+int rds_ib_sysctl_init(void)
{
rds_ib_sysctl_hdr = register_sysctl_paths(rds_ib_sysctl_path, rds_ib_sysctl_table);
- if (rds_ib_sysctl_hdr == NULL)
+ if (!rds_ib_sysctl_hdr)
return -ENOMEM;
return 0;
}
diff --git a/net/rds/info.c b/net/rds/info.c
index c45c4173a44d..4fdf1b6e84ff 100644
--- a/net/rds/info.c
+++ b/net/rds/info.c
@@ -76,7 +76,7 @@ void rds_info_register_func(int optname, rds_info_func func)
BUG_ON(optname < RDS_INFO_FIRST || optname > RDS_INFO_LAST);
spin_lock(&rds_info_lock);
- BUG_ON(rds_info_funcs[offset] != NULL);
+ BUG_ON(rds_info_funcs[offset]);
rds_info_funcs[offset] = func;
spin_unlock(&rds_info_lock);
}
@@ -102,7 +102,7 @@ EXPORT_SYMBOL_GPL(rds_info_deregister_func);
*/
void rds_info_iter_unmap(struct rds_info_iterator *iter)
{
- if (iter->addr != NULL) {
+ if (iter->addr) {
kunmap_atomic(iter->addr, KM_USER0);
iter->addr = NULL;
}
@@ -117,7 +117,7 @@ void rds_info_copy(struct rds_info_iterator *iter, void *data,
unsigned long this;
while (bytes) {
- if (iter->addr == NULL)
+ if (!iter->addr)
iter->addr = kmap_atomic(*iter->pages, KM_USER0);
this = min(bytes, PAGE_SIZE - iter->offset);
@@ -188,7 +188,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
>> PAGE_SHIFT;
pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL);
- if (pages == NULL) {
+ if (!pages) {
ret = -ENOMEM;
goto out;
}
@@ -206,7 +206,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
call_func:
func = rds_info_funcs[optname - RDS_INFO_FIRST];
- if (func == NULL) {
+ if (!func) {
ret = -ENOPROTOOPT;
goto out;
}
@@ -234,7 +234,7 @@ call_func:
ret = -EFAULT;
out:
- for (i = 0; pages != NULL && i < nr_pages; i++)
+ for (i = 0; pages && i < nr_pages; i++)
put_page(pages[i]);
kfree(pages);
diff --git a/net/rds/iw.c b/net/rds/iw.c
index c8f3d3525cb9..5a9676fe594f 100644
--- a/net/rds/iw.c
+++ b/net/rds/iw.c
@@ -56,7 +56,7 @@ struct list_head rds_iw_devices;
DEFINE_SPINLOCK(iw_nodev_conns_lock);
LIST_HEAD(iw_nodev_conns);
-void rds_iw_add_one(struct ib_device *device)
+static void rds_iw_add_one(struct ib_device *device)
{
struct rds_iw_device *rds_iwdev;
struct ib_device_attr *dev_attr;
@@ -124,7 +124,7 @@ free_attr:
kfree(dev_attr);
}
-void rds_iw_remove_one(struct ib_device *device)
+static void rds_iw_remove_one(struct ib_device *device)
{
struct rds_iw_device *rds_iwdev;
struct rds_iw_cm_id *i_cm_id, *next;
@@ -264,7 +264,6 @@ struct rds_transport rds_iw_transport = {
.laddr_check = rds_iw_laddr_check,
.xmit_complete = rds_iw_xmit_complete,
.xmit = rds_iw_xmit,
- .xmit_cong_map = NULL,
.xmit_rdma = rds_iw_xmit_rdma,
.recv = rds_iw_recv,
.conn_alloc = rds_iw_conn_alloc,
@@ -272,7 +271,6 @@ struct rds_transport rds_iw_transport = {
.conn_connect = rds_iw_conn_connect,
.conn_shutdown = rds_iw_conn_shutdown,
.inc_copy_to_user = rds_iw_inc_copy_to_user,
- .inc_purge = rds_iw_inc_purge,
.inc_free = rds_iw_inc_free,
.cm_initiate_connect = rds_iw_cm_initiate_connect,
.cm_handle_connect = rds_iw_cm_handle_connect,
@@ -289,7 +287,7 @@ struct rds_transport rds_iw_transport = {
.t_prefer_loopback = 1,
};
-int __init rds_iw_init(void)
+int rds_iw_init(void)
{
int ret;
diff --git a/net/rds/iw.h b/net/rds/iw.h
index eef2f0c28476..90151922178c 100644
--- a/net/rds/iw.h
+++ b/net/rds/iw.h
@@ -70,7 +70,7 @@ struct rds_iw_send_work {
struct rds_message *s_rm;
/* We should really put these into a union: */
- struct rds_rdma_op *s_op;
+ struct rm_rdma_op *s_op;
struct rds_iw_mapping *s_mapping;
struct ib_mr *s_mr;
struct ib_fast_reg_page_list *s_page_list;
@@ -268,8 +268,6 @@ static inline u32 rds_iw_local_dma_lkey(struct rds_iw_connection *ic)
/* ib.c */
extern struct rds_transport rds_iw_transport;
-extern void rds_iw_add_one(struct ib_device *device);
-extern void rds_iw_remove_one(struct ib_device *device);
extern struct ib_client rds_iw_client;
extern unsigned int fastreg_pool_size;
@@ -284,7 +282,7 @@ void rds_iw_conn_free(void *arg);
int rds_iw_conn_connect(struct rds_connection *conn);
void rds_iw_conn_shutdown(struct rds_connection *conn);
void rds_iw_state_change(struct sock *sk);
-int __init rds_iw_listen_init(void);
+int rds_iw_listen_init(void);
void rds_iw_listen_stop(void);
void __rds_iw_conn_error(struct rds_connection *conn, const char *, ...);
int rds_iw_cm_handle_connect(struct rdma_cm_id *cm_id,
@@ -318,15 +316,13 @@ void *rds_iw_get_mr(struct scatterlist *sg, unsigned long nents,
void rds_iw_sync_mr(void *trans_private, int dir);
void rds_iw_free_mr(void *trans_private, int invalidate);
void rds_iw_flush_mrs(void);
-void rds_iw_remove_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_id);
/* ib_recv.c */
-int __init rds_iw_recv_init(void);
+int rds_iw_recv_init(void);
void rds_iw_recv_exit(void);
int rds_iw_recv(struct rds_connection *conn);
int rds_iw_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
gfp_t page_gfp, int prefill);
-void rds_iw_inc_purge(struct rds_incoming *inc);
void rds_iw_inc_free(struct rds_incoming *inc);
int rds_iw_inc_copy_to_user(struct rds_incoming *inc, struct iovec *iov,
size_t size);
@@ -358,7 +354,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
void rds_iw_send_cq_comp_handler(struct ib_cq *cq, void *context);
void rds_iw_send_init_ring(struct rds_iw_connection *ic);
void rds_iw_send_clear_ring(struct rds_iw_connection *ic);
-int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op);
+int rds_iw_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op);
void rds_iw_send_add_credits(struct rds_connection *conn, unsigned int credits);
void rds_iw_advertise_credits(struct rds_connection *conn, unsigned int posted);
int rds_iw_send_grab_credits(struct rds_iw_connection *ic, u32 wanted,
@@ -371,7 +367,7 @@ unsigned int rds_iw_stats_info_copy(struct rds_info_iterator *iter,
unsigned int avail);
/* ib_sysctl.c */
-int __init rds_iw_sysctl_init(void);
+int rds_iw_sysctl_init(void);
void rds_iw_sysctl_exit(void);
extern unsigned long rds_iw_sysctl_max_send_wr;
extern unsigned long rds_iw_sysctl_max_recv_wr;
@@ -379,7 +375,6 @@ extern unsigned long rds_iw_sysctl_max_unsig_wrs;
extern unsigned long rds_iw_sysctl_max_unsig_bytes;
extern unsigned long rds_iw_sysctl_max_recv_allocation;
extern unsigned int rds_iw_sysctl_flow_control;
-extern ctl_table rds_iw_sysctl_table[];
/*
* Helper functions for getting/setting the header and data SGEs in
diff --git a/net/rds/iw_cm.c b/net/rds/iw_cm.c
index b5dd6ac39be8..712cf2d1f28e 100644
--- a/net/rds/iw_cm.c
+++ b/net/rds/iw_cm.c
@@ -257,7 +257,7 @@ static int rds_iw_setup_qp(struct rds_connection *conn)
* the rds_iwdev at all.
*/
rds_iwdev = ib_get_client_data(dev, &rds_iw_client);
- if (rds_iwdev == NULL) {
+ if (!rds_iwdev) {
if (printk_ratelimit())
printk(KERN_NOTICE "RDS/IW: No client_data for device %s\n",
dev->name);
@@ -292,7 +292,7 @@ static int rds_iw_setup_qp(struct rds_connection *conn)
ic->i_send_ring.w_nr *
sizeof(struct rds_header),
&ic->i_send_hdrs_dma, GFP_KERNEL);
- if (ic->i_send_hdrs == NULL) {
+ if (!ic->i_send_hdrs) {
ret = -ENOMEM;
rdsdebug("ib_dma_alloc_coherent send failed\n");
goto out;
@@ -302,7 +302,7 @@ static int rds_iw_setup_qp(struct rds_connection *conn)
ic->i_recv_ring.w_nr *
sizeof(struct rds_header),
&ic->i_recv_hdrs_dma, GFP_KERNEL);
- if (ic->i_recv_hdrs == NULL) {
+ if (!ic->i_recv_hdrs) {
ret = -ENOMEM;
rdsdebug("ib_dma_alloc_coherent recv failed\n");
goto out;
@@ -310,14 +310,14 @@ static int rds_iw_setup_qp(struct rds_connection *conn)
ic->i_ack = ib_dma_alloc_coherent(dev, sizeof(struct rds_header),
&ic->i_ack_dma, GFP_KERNEL);
- if (ic->i_ack == NULL) {
+ if (!ic->i_ack) {
ret = -ENOMEM;
rdsdebug("ib_dma_alloc_coherent ack failed\n");
goto out;
}
ic->i_sends = vmalloc(ic->i_send_ring.w_nr * sizeof(struct rds_iw_send_work));
- if (ic->i_sends == NULL) {
+ if (!ic->i_sends) {
ret = -ENOMEM;
rdsdebug("send allocation failed\n");
goto out;
@@ -325,7 +325,7 @@ static int rds_iw_setup_qp(struct rds_connection *conn)
rds_iw_send_init_ring(ic);
ic->i_recvs = vmalloc(ic->i_recv_ring.w_nr * sizeof(struct rds_iw_recv_work));
- if (ic->i_recvs == NULL) {
+ if (!ic->i_recvs) {
ret = -ENOMEM;
rdsdebug("recv allocation failed\n");
goto out;
@@ -696,7 +696,7 @@ int rds_iw_conn_alloc(struct rds_connection *conn, gfp_t gfp)
/* XXX too lazy? */
ic = kzalloc(sizeof(struct rds_iw_connection), GFP_KERNEL);
- if (ic == NULL)
+ if (!ic)
return -ENOMEM;
INIT_LIST_HEAD(&ic->iw_node);
diff --git a/net/rds/iw_rdma.c b/net/rds/iw_rdma.c
index 13dc1862d862..59509e9a9e72 100644
--- a/net/rds/iw_rdma.c
+++ b/net/rds/iw_rdma.c
@@ -34,7 +34,6 @@
#include <linux/slab.h>
#include "rds.h"
-#include "rdma.h"
#include "iw.h"
@@ -158,7 +157,8 @@ static int rds_iw_add_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *
return 0;
}
-void rds_iw_remove_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_id)
+static void rds_iw_remove_cm_id(struct rds_iw_device *rds_iwdev,
+ struct rdma_cm_id *cm_id)
{
struct rds_iw_cm_id *i_cm_id;
@@ -207,9 +207,9 @@ void rds_iw_add_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *con
BUG_ON(list_empty(&ic->iw_node));
list_del(&ic->iw_node);
- spin_lock_irq(&rds_iwdev->spinlock);
+ spin_lock(&rds_iwdev->spinlock);
list_add_tail(&ic->iw_node, &rds_iwdev->conn_list);
- spin_unlock_irq(&rds_iwdev->spinlock);
+ spin_unlock(&rds_iwdev->spinlock);
spin_unlock_irq(&iw_nodev_conns_lock);
ic->rds_iwdev = rds_iwdev;
diff --git a/net/rds/iw_recv.c b/net/rds/iw_recv.c
index 3d479067d54d..5e57347f49ff 100644
--- a/net/rds/iw_recv.c
+++ b/net/rds/iw_recv.c
@@ -53,7 +53,7 @@ static void rds_iw_frag_drop_page(struct rds_page_frag *frag)
static void rds_iw_frag_free(struct rds_page_frag *frag)
{
rdsdebug("frag %p page %p\n", frag, frag->f_page);
- BUG_ON(frag->f_page != NULL);
+ BUG_ON(frag->f_page);
kmem_cache_free(rds_iw_frag_slab, frag);
}
@@ -143,14 +143,14 @@ static int rds_iw_recv_refill_one(struct rds_connection *conn,
struct ib_sge *sge;
int ret = -ENOMEM;
- if (recv->r_iwinc == NULL) {
+ if (!recv->r_iwinc) {
if (!atomic_add_unless(&rds_iw_allocation, 1, rds_iw_sysctl_max_recv_allocation)) {
rds_iw_stats_inc(s_iw_rx_alloc_limit);
goto out;
}
recv->r_iwinc = kmem_cache_alloc(rds_iw_incoming_slab,
kptr_gfp);
- if (recv->r_iwinc == NULL) {
+ if (!recv->r_iwinc) {
atomic_dec(&rds_iw_allocation);
goto out;
}
@@ -158,17 +158,17 @@ static int rds_iw_recv_refill_one(struct rds_connection *conn,
rds_inc_init(&recv->r_iwinc->ii_inc, conn, conn->c_faddr);
}
- if (recv->r_frag == NULL) {
+ if (!recv->r_frag) {
recv->r_frag = kmem_cache_alloc(rds_iw_frag_slab, kptr_gfp);
- if (recv->r_frag == NULL)
+ if (!recv->r_frag)
goto out;
INIT_LIST_HEAD(&recv->r_frag->f_item);
recv->r_frag->f_page = NULL;
}
- if (ic->i_frag.f_page == NULL) {
+ if (!ic->i_frag.f_page) {
ic->i_frag.f_page = alloc_page(page_gfp);
- if (ic->i_frag.f_page == NULL)
+ if (!ic->i_frag.f_page)
goto out;
ic->i_frag.f_offset = 0;
}
@@ -273,7 +273,7 @@ int rds_iw_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
return ret;
}
-void rds_iw_inc_purge(struct rds_incoming *inc)
+static void rds_iw_inc_purge(struct rds_incoming *inc)
{
struct rds_iw_incoming *iwinc;
struct rds_page_frag *frag;
@@ -716,7 +716,7 @@ static void rds_iw_process_recv(struct rds_connection *conn,
* into the inc and save the inc so we can hang upcoming fragments
* off its list.
*/
- if (iwinc == NULL) {
+ if (!iwinc) {
iwinc = recv->r_iwinc;
recv->r_iwinc = NULL;
ic->i_iwinc = iwinc;
@@ -887,7 +887,7 @@ int rds_iw_recv(struct rds_connection *conn)
return ret;
}
-int __init rds_iw_recv_init(void)
+int rds_iw_recv_init(void)
{
struct sysinfo si;
int ret = -ENOMEM;
@@ -899,13 +899,13 @@ int __init rds_iw_recv_init(void)
rds_iw_incoming_slab = kmem_cache_create("rds_iw_incoming",
sizeof(struct rds_iw_incoming),
0, 0, NULL);
- if (rds_iw_incoming_slab == NULL)
+ if (!rds_iw_incoming_slab)
goto out;
rds_iw_frag_slab = kmem_cache_create("rds_iw_frag",
sizeof(struct rds_page_frag),
0, 0, NULL);
- if (rds_iw_frag_slab == NULL)
+ if (!rds_iw_frag_slab)
kmem_cache_destroy(rds_iw_incoming_slab);
else
ret = 0;
diff --git a/net/rds/iw_send.c b/net/rds/iw_send.c
index 52182ff7519e..6280ea020d4e 100644
--- a/net/rds/iw_send.c
+++ b/net/rds/iw_send.c
@@ -36,7 +36,6 @@
#include <linux/dmapool.h>
#include "rds.h"
-#include "rdma.h"
#include "iw.h"
static void rds_iw_send_rdma_complete(struct rds_message *rm,
@@ -64,13 +63,13 @@ static void rds_iw_send_rdma_complete(struct rds_message *rm,
}
static void rds_iw_send_unmap_rdma(struct rds_iw_connection *ic,
- struct rds_rdma_op *op)
+ struct rm_rdma_op *op)
{
- if (op->r_mapped) {
+ if (op->op_mapped) {
ib_dma_unmap_sg(ic->i_cm_id->device,
- op->r_sg, op->r_nents,
- op->r_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- op->r_mapped = 0;
+ op->op_sg, op->op_nents,
+ op->op_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ op->op_mapped = 0;
}
}
@@ -83,11 +82,11 @@ static void rds_iw_send_unmap_rm(struct rds_iw_connection *ic,
rdsdebug("ic %p send %p rm %p\n", ic, send, rm);
ib_dma_unmap_sg(ic->i_cm_id->device,
- rm->m_sg, rm->m_nents,
+ rm->data.op_sg, rm->data.op_nents,
DMA_TO_DEVICE);
- if (rm->m_rdma_op != NULL) {
- rds_iw_send_unmap_rdma(ic, rm->m_rdma_op);
+ if (rm->rdma.op_active) {
+ rds_iw_send_unmap_rdma(ic, &rm->rdma);
/* If the user asked for a completion notification on this
* message, we can implement three different semantics:
@@ -111,10 +110,10 @@ static void rds_iw_send_unmap_rm(struct rds_iw_connection *ic,
*/
rds_iw_send_rdma_complete(rm, wc_status);
- if (rm->m_rdma_op->r_write)
- rds_stats_add(s_send_rdma_bytes, rm->m_rdma_op->r_bytes);
+ if (rm->rdma.op_write)
+ rds_stats_add(s_send_rdma_bytes, rm->rdma.op_bytes);
else
- rds_stats_add(s_recv_rdma_bytes, rm->m_rdma_op->r_bytes);
+ rds_stats_add(s_recv_rdma_bytes, rm->rdma.op_bytes);
}
/* If anyone waited for this message to get flushed out, wake
@@ -556,25 +555,27 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
}
/* map the message the first time we see it */
- if (ic->i_rm == NULL) {
+ if (!ic->i_rm) {
/*
printk(KERN_NOTICE "rds_iw_xmit prep msg dport=%u flags=0x%x len=%d\n",
be16_to_cpu(rm->m_inc.i_hdr.h_dport),
rm->m_inc.i_hdr.h_flags,
be32_to_cpu(rm->m_inc.i_hdr.h_len));
*/
- if (rm->m_nents) {
- rm->m_count = ib_dma_map_sg(dev,
- rm->m_sg, rm->m_nents, DMA_TO_DEVICE);
- rdsdebug("ic %p mapping rm %p: %d\n", ic, rm, rm->m_count);
- if (rm->m_count == 0) {
+ if (rm->data.op_nents) {
+ rm->data.op_count = ib_dma_map_sg(dev,
+ rm->data.op_sg,
+ rm->data.op_nents,
+ DMA_TO_DEVICE);
+ rdsdebug("ic %p mapping rm %p: %d\n", ic, rm, rm->data.op_count);
+ if (rm->data.op_count == 0) {
rds_iw_stats_inc(s_iw_tx_sg_mapping_failure);
rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc);
ret = -ENOMEM; /* XXX ? */
goto out;
}
} else {
- rm->m_count = 0;
+ rm->data.op_count = 0;
}
ic->i_unsignaled_wrs = rds_iw_sysctl_max_unsig_wrs;
@@ -590,10 +591,10 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
/* If it has a RDMA op, tell the peer we did it. This is
* used by the peer to release use-once RDMA MRs. */
- if (rm->m_rdma_op) {
+ if (rm->rdma.op_active) {
struct rds_ext_header_rdma ext_hdr;
- ext_hdr.h_rdma_rkey = cpu_to_be32(rm->m_rdma_op->r_key);
+ ext_hdr.h_rdma_rkey = cpu_to_be32(rm->rdma.op_rkey);
rds_message_add_extension(&rm->m_inc.i_hdr,
RDS_EXTHDR_RDMA, &ext_hdr, sizeof(ext_hdr));
}
@@ -621,7 +622,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
send = &ic->i_sends[pos];
first = send;
prev = NULL;
- scat = &rm->m_sg[sg];
+ scat = &rm->data.op_sg[sg];
sent = 0;
i = 0;
@@ -631,7 +632,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
* or when requested by the user. Right now, we let
* the application choose.
*/
- if (rm->m_rdma_op && rm->m_rdma_op->r_fence)
+ if (rm->rdma.op_active && rm->rdma.op_fence)
send_flags = IB_SEND_FENCE;
/*
@@ -650,7 +651,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
}
/* if there's data reference it with a chain of work reqs */
- for (; i < work_alloc && scat != &rm->m_sg[rm->m_count]; i++) {
+ for (; i < work_alloc && scat != &rm->data.op_sg[rm->data.op_count]; i++) {
unsigned int len;
send = &ic->i_sends[pos];
@@ -728,7 +729,7 @@ add_header:
sent += sizeof(struct rds_header);
/* if we finished the message then send completion owns it */
- if (scat == &rm->m_sg[rm->m_count]) {
+ if (scat == &rm->data.op_sg[rm->data.op_count]) {
prev->s_rm = ic->i_rm;
prev->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
ic->i_rm = NULL;
@@ -784,7 +785,7 @@ static void rds_iw_build_send_fastreg(struct rds_iw_device *rds_iwdev, struct rd
ib_update_fast_reg_key(send->s_mr, send->s_remap_count++);
}
-int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
+int rds_iw_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
{
struct rds_iw_connection *ic = conn->c_transport_data;
struct rds_iw_send_work *send = NULL;
@@ -794,7 +795,7 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
struct rds_iw_device *rds_iwdev;
struct scatterlist *scat;
unsigned long len;
- u64 remote_addr = op->r_remote_addr;
+ u64 remote_addr = op->op_remote_addr;
u32 pos, fr_pos;
u32 work_alloc;
u32 i;
@@ -806,21 +807,21 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
rds_iwdev = ib_get_client_data(ic->i_cm_id->device, &rds_iw_client);
/* map the message the first time we see it */
- if (!op->r_mapped) {
- op->r_count = ib_dma_map_sg(ic->i_cm_id->device,
- op->r_sg, op->r_nents, (op->r_write) ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE);
- rdsdebug("ic %p mapping op %p: %d\n", ic, op, op->r_count);
- if (op->r_count == 0) {
+ if (!op->op_mapped) {
+ op->op_count = ib_dma_map_sg(ic->i_cm_id->device,
+ op->op_sg, op->op_nents, (op->op_write) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ rdsdebug("ic %p mapping op %p: %d\n", ic, op, op->op_count);
+ if (op->op_count == 0) {
rds_iw_stats_inc(s_iw_tx_sg_mapping_failure);
ret = -ENOMEM; /* XXX ? */
goto out;
}
- op->r_mapped = 1;
+ op->op_mapped = 1;
}
- if (!op->r_write) {
+ if (!op->op_write) {
/* Alloc space on the send queue for the fastreg */
work_alloc = rds_iw_ring_alloc(&ic->i_send_ring, 1, &fr_pos);
if (work_alloc != 1) {
@@ -835,7 +836,7 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
* Instead of knowing how to return a partial rdma read/write we insist that there
* be enough work requests to send the entire message.
*/
- i = ceil(op->r_count, rds_iwdev->max_sge);
+ i = ceil(op->op_count, rds_iwdev->max_sge);
work_alloc = rds_iw_ring_alloc(&ic->i_send_ring, i, &pos);
if (work_alloc != i) {
@@ -846,17 +847,17 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
}
send = &ic->i_sends[pos];
- if (!op->r_write) {
+ if (!op->op_write) {
first = prev = &ic->i_sends[fr_pos];
} else {
first = send;
prev = NULL;
}
- scat = &op->r_sg[0];
+ scat = &op->op_sg[0];
sent = 0;
- num_sge = op->r_count;
+ num_sge = op->op_count;
- for (i = 0; i < work_alloc && scat != &op->r_sg[op->r_count]; i++) {
+ for (i = 0; i < work_alloc && scat != &op->op_sg[op->op_count]; i++) {
send->s_wr.send_flags = 0;
send->s_queued = jiffies;
@@ -873,13 +874,13 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
* for local access after RDS is finished with it, using
* IB_WR_RDMA_READ_WITH_INV will invalidate it after the read has completed.
*/
- if (op->r_write)
+ if (op->op_write)
send->s_wr.opcode = IB_WR_RDMA_WRITE;
else
send->s_wr.opcode = IB_WR_RDMA_READ_WITH_INV;
send->s_wr.wr.rdma.remote_addr = remote_addr;
- send->s_wr.wr.rdma.rkey = op->r_key;
+ send->s_wr.wr.rdma.rkey = op->op_rkey;
send->s_op = op;
if (num_sge > rds_iwdev->max_sge) {
@@ -893,7 +894,7 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
if (prev)
prev->s_wr.next = &send->s_wr;
- for (j = 0; j < send->s_wr.num_sge && scat != &op->r_sg[op->r_count]; j++) {
+ for (j = 0; j < send->s_wr.num_sge && scat != &op->op_sg[op->op_count]; j++) {
len = ib_sg_dma_len(ic->i_cm_id->device, scat);
if (send->s_wr.opcode == IB_WR_RDMA_READ_WITH_INV)
@@ -927,7 +928,7 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
}
/* if we finished the message then send completion owns it */
- if (scat == &op->r_sg[op->r_count])
+ if (scat == &op->op_sg[op->op_count])
first->s_wr.send_flags = IB_SEND_SIGNALED;
if (i < work_alloc) {
@@ -941,9 +942,9 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
* adapters do not allow using the lkey for this at all. To bypass this use a
* fastreg_mr (or possibly a dma_mr)
*/
- if (!op->r_write) {
+ if (!op->op_write) {
rds_iw_build_send_fastreg(rds_iwdev, ic, &ic->i_sends[fr_pos],
- op->r_count, sent, conn->c_xmit_rm->m_rs->rs_user_addr);
+ op->op_count, sent, conn->c_xmit_rm->m_rs->rs_user_addr);
work_alloc++;
}
diff --git a/net/rds/iw_sysctl.c b/net/rds/iw_sysctl.c
index 1c4428a61a02..e2e47176e729 100644
--- a/net/rds/iw_sysctl.c
+++ b/net/rds/iw_sysctl.c
@@ -55,7 +55,7 @@ static unsigned long rds_iw_sysctl_max_unsig_bytes_max = ~0UL;
unsigned int rds_iw_sysctl_flow_control = 1;
-ctl_table rds_iw_sysctl_table[] = {
+static ctl_table rds_iw_sysctl_table[] = {
{
.procname = "max_send_wr",
.data = &rds_iw_sysctl_max_send_wr,
@@ -122,10 +122,10 @@ void rds_iw_sysctl_exit(void)
unregister_sysctl_table(rds_iw_sysctl_hdr);
}
-int __init rds_iw_sysctl_init(void)
+int rds_iw_sysctl_init(void)
{
rds_iw_sysctl_hdr = register_sysctl_paths(rds_iw_sysctl_path, rds_iw_sysctl_table);
- if (rds_iw_sysctl_hdr == NULL)
+ if (!rds_iw_sysctl_hdr)
return -ENOMEM;
return 0;
}
diff --git a/net/rds/loop.c b/net/rds/loop.c
index dd9879379457..c390156b426f 100644
--- a/net/rds/loop.c
+++ b/net/rds/loop.c
@@ -61,10 +61,17 @@ static int rds_loop_xmit(struct rds_connection *conn, struct rds_message *rm,
unsigned int hdr_off, unsigned int sg,
unsigned int off)
{
+ /* Do not send cong updates to loopback */
+ if (rm->m_inc.i_hdr.h_flags & RDS_FLAG_CONG_BITMAP) {
+ rds_cong_map_updated(conn->c_fcong, ~(u64) 0);
+ return sizeof(struct rds_header) + RDS_CONG_MAP_BYTES;
+ }
+
BUG_ON(hdr_off || sg || off);
rds_inc_init(&rm->m_inc, conn, conn->c_laddr);
- rds_message_addref(rm); /* for the inc */
+ /* For the embedded inc. Matching put is in loop_inc_free() */
+ rds_message_addref(rm);
rds_recv_incoming(conn, conn->c_laddr, conn->c_faddr, &rm->m_inc,
GFP_KERNEL, KM_USER0);
@@ -77,16 +84,14 @@ static int rds_loop_xmit(struct rds_connection *conn, struct rds_message *rm,
return sizeof(struct rds_header) + be32_to_cpu(rm->m_inc.i_hdr.h_len);
}
-static int rds_loop_xmit_cong_map(struct rds_connection *conn,
- struct rds_cong_map *map,
- unsigned long offset)
+/*
+ * See rds_loop_xmit(). Since our inc is embedded in the rm, we
+ * make sure the rm lives at least until the inc is done.
+ */
+static void rds_loop_inc_free(struct rds_incoming *inc)
{
- BUG_ON(offset);
- BUG_ON(map != conn->c_lcong);
-
- rds_cong_map_updated(conn->c_fcong, ~(u64) 0);
-
- return sizeof(struct rds_header) + RDS_CONG_MAP_BYTES;
+ struct rds_message *rm = container_of(inc, struct rds_message, m_inc);
+ rds_message_put(rm);
}
/* we need to at least give the thread something to succeed */
@@ -112,7 +117,7 @@ static int rds_loop_conn_alloc(struct rds_connection *conn, gfp_t gfp)
unsigned long flags;
lc = kzalloc(sizeof(struct rds_loop_connection), GFP_KERNEL);
- if (lc == NULL)
+ if (!lc)
return -ENOMEM;
INIT_LIST_HEAD(&lc->loop_node);
@@ -169,14 +174,12 @@ void rds_loop_exit(void)
*/
struct rds_transport rds_loop_transport = {
.xmit = rds_loop_xmit,
- .xmit_cong_map = rds_loop_xmit_cong_map,
.recv = rds_loop_recv,
.conn_alloc = rds_loop_conn_alloc,
.conn_free = rds_loop_conn_free,
.conn_connect = rds_loop_conn_connect,
.conn_shutdown = rds_loop_conn_shutdown,
.inc_copy_to_user = rds_message_inc_copy_to_user,
- .inc_purge = rds_message_inc_purge,
- .inc_free = rds_message_inc_free,
+ .inc_free = rds_loop_inc_free,
.t_name = "loopback",
};
diff --git a/net/rds/message.c b/net/rds/message.c
index 9a1d67e001ba..a84545dae370 100644
--- a/net/rds/message.c
+++ b/net/rds/message.c
@@ -34,9 +34,6 @@
#include <linux/slab.h>
#include "rds.h"
-#include "rdma.h"
-
-static DECLARE_WAIT_QUEUE_HEAD(rds_message_flush_waitq);
static unsigned int rds_exthdr_size[__RDS_EXTHDR_MAX] = {
[RDS_EXTHDR_NONE] = 0,
@@ -63,29 +60,31 @@ static void rds_message_purge(struct rds_message *rm)
if (unlikely(test_bit(RDS_MSG_PAGEVEC, &rm->m_flags)))
return;
- for (i = 0; i < rm->m_nents; i++) {
- rdsdebug("putting data page %p\n", (void *)sg_page(&rm->m_sg[i]));
+ for (i = 0; i < rm->data.op_nents; i++) {
+ rdsdebug("putting data page %p\n", (void *)sg_page(&rm->data.op_sg[i]));
/* XXX will have to put_page for page refs */
- __free_page(sg_page(&rm->m_sg[i]));
+ __free_page(sg_page(&rm->data.op_sg[i]));
}
- rm->m_nents = 0;
+ rm->data.op_nents = 0;
- if (rm->m_rdma_op)
- rds_rdma_free_op(rm->m_rdma_op);
- if (rm->m_rdma_mr)
- rds_mr_put(rm->m_rdma_mr);
-}
+ if (rm->rdma.op_active)
+ rds_rdma_free_op(&rm->rdma);
+ if (rm->rdma.op_rdma_mr)
+ rds_mr_put(rm->rdma.op_rdma_mr);
-void rds_message_inc_purge(struct rds_incoming *inc)
-{
- struct rds_message *rm = container_of(inc, struct rds_message, m_inc);
- rds_message_purge(rm);
+ if (rm->atomic.op_active)
+ rds_atomic_free_op(&rm->atomic);
+ if (rm->atomic.op_rdma_mr)
+ rds_mr_put(rm->atomic.op_rdma_mr);
}
void rds_message_put(struct rds_message *rm)
{
rdsdebug("put rm %p ref %d\n", rm, atomic_read(&rm->m_refcount));
-
+ if (atomic_read(&rm->m_refcount) == 0) {
+printk(KERN_CRIT "danger refcount zero on %p\n", rm);
+WARN_ON(1);
+ }
if (atomic_dec_and_test(&rm->m_refcount)) {
BUG_ON(!list_empty(&rm->m_sock_item));
BUG_ON(!list_empty(&rm->m_conn_item));
@@ -96,12 +95,6 @@ void rds_message_put(struct rds_message *rm)
}
EXPORT_SYMBOL_GPL(rds_message_put);
-void rds_message_inc_free(struct rds_incoming *inc)
-{
- struct rds_message *rm = container_of(inc, struct rds_message, m_inc);
- rds_message_put(rm);
-}
-
void rds_message_populate_header(struct rds_header *hdr, __be16 sport,
__be16 dport, u64 seq)
{
@@ -113,8 +106,8 @@ void rds_message_populate_header(struct rds_header *hdr, __be16 sport,
}
EXPORT_SYMBOL_GPL(rds_message_populate_header);
-int rds_message_add_extension(struct rds_header *hdr,
- unsigned int type, const void *data, unsigned int len)
+int rds_message_add_extension(struct rds_header *hdr, unsigned int type,
+ const void *data, unsigned int len)
{
unsigned int ext_len = sizeof(u8) + len;
unsigned char *dst;
@@ -184,26 +177,6 @@ none:
return RDS_EXTHDR_NONE;
}
-int rds_message_add_version_extension(struct rds_header *hdr, unsigned int version)
-{
- struct rds_ext_header_version ext_hdr;
-
- ext_hdr.h_version = cpu_to_be32(version);
- return rds_message_add_extension(hdr, RDS_EXTHDR_VERSION, &ext_hdr, sizeof(ext_hdr));
-}
-
-int rds_message_get_version_extension(struct rds_header *hdr, unsigned int *version)
-{
- struct rds_ext_header_version ext_hdr;
- unsigned int pos = 0, len = sizeof(ext_hdr);
-
- /* We assume the version extension is the only one present */
- if (rds_message_next_extension(hdr, &pos, &ext_hdr, &len) != RDS_EXTHDR_VERSION)
- return 0;
- *version = be32_to_cpu(ext_hdr.h_version);
- return 1;
-}
-
int rds_message_add_rdma_dest_extension(struct rds_header *hdr, u32 r_key, u32 offset)
{
struct rds_ext_header_rdma_dest ext_hdr;
@@ -214,41 +187,68 @@ int rds_message_add_rdma_dest_extension(struct rds_header *hdr, u32 r_key, u32 o
}
EXPORT_SYMBOL_GPL(rds_message_add_rdma_dest_extension);
-struct rds_message *rds_message_alloc(unsigned int nents, gfp_t gfp)
+/*
+ * Each rds_message is allocated with extra space for the scatterlist entries
+ * rds ops will need. This is to minimize memory allocation count. Then, each rds op
+ * can grab SGs when initializing its part of the rds_message.
+ */
+struct rds_message *rds_message_alloc(unsigned int extra_len, gfp_t gfp)
{
struct rds_message *rm;
- rm = kzalloc(sizeof(struct rds_message) +
- (nents * sizeof(struct scatterlist)), gfp);
+ rm = kzalloc(sizeof(struct rds_message) + extra_len, gfp);
if (!rm)
goto out;
- if (nents)
- sg_init_table(rm->m_sg, nents);
+ rm->m_used_sgs = 0;
+ rm->m_total_sgs = extra_len / sizeof(struct scatterlist);
+
atomic_set(&rm->m_refcount, 1);
INIT_LIST_HEAD(&rm->m_sock_item);
INIT_LIST_HEAD(&rm->m_conn_item);
spin_lock_init(&rm->m_rs_lock);
+ init_waitqueue_head(&rm->m_flush_wait);
out:
return rm;
}
+/*
+ * RDS ops use this to grab SG entries from the rm's sg pool.
+ */
+struct scatterlist *rds_message_alloc_sgs(struct rds_message *rm, int nents)
+{
+ struct scatterlist *sg_first = (struct scatterlist *) &rm[1];
+ struct scatterlist *sg_ret;
+
+ WARN_ON(rm->m_used_sgs + nents > rm->m_total_sgs);
+ WARN_ON(!nents);
+
+ sg_ret = &sg_first[rm->m_used_sgs];
+ sg_init_table(sg_ret, nents);
+ rm->m_used_sgs += nents;
+
+ return sg_ret;
+}
+
struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned int total_len)
{
struct rds_message *rm;
unsigned int i;
+ int num_sgs = ceil(total_len, PAGE_SIZE);
+ int extra_bytes = num_sgs * sizeof(struct scatterlist);
- rm = rds_message_alloc(ceil(total_len, PAGE_SIZE), GFP_KERNEL);
- if (rm == NULL)
+ rm = rds_message_alloc(extra_bytes, GFP_NOWAIT);
+ if (!rm)
return ERR_PTR(-ENOMEM);
set_bit(RDS_MSG_PAGEVEC, &rm->m_flags);
rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len);
- rm->m_nents = ceil(total_len, PAGE_SIZE);
+ rm->data.op_nents = ceil(total_len, PAGE_SIZE);
+ rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs);
- for (i = 0; i < rm->m_nents; ++i) {
- sg_set_page(&rm->m_sg[i],
+ for (i = 0; i < rm->data.op_nents; ++i) {
+ sg_set_page(&rm->data.op_sg[i],
virt_to_page(page_addrs[i]),
PAGE_SIZE, 0);
}
@@ -256,40 +256,33 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned in
return rm;
}
-struct rds_message *rds_message_copy_from_user(struct iovec *first_iov,
+int rds_message_copy_from_user(struct rds_message *rm, struct iovec *first_iov,
size_t total_len)
{
unsigned long to_copy;
unsigned long iov_off;
unsigned long sg_off;
- struct rds_message *rm;
struct iovec *iov;
struct scatterlist *sg;
- int ret;
-
- rm = rds_message_alloc(ceil(total_len, PAGE_SIZE), GFP_KERNEL);
- if (rm == NULL) {
- ret = -ENOMEM;
- goto out;
- }
+ int ret = 0;
rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len);
/*
* now allocate and copy in the data payload.
*/
- sg = rm->m_sg;
+ sg = rm->data.op_sg;
iov = first_iov;
iov_off = 0;
sg_off = 0; /* Dear gcc, sg->page will be null from kzalloc. */
while (total_len) {
- if (sg_page(sg) == NULL) {
+ if (!sg_page(sg)) {
ret = rds_page_remainder_alloc(sg, total_len,
GFP_HIGHUSER);
if (ret)
goto out;
- rm->m_nents++;
+ rm->data.op_nents++;
sg_off = 0;
}
@@ -320,14 +313,8 @@ struct rds_message *rds_message_copy_from_user(struct iovec *first_iov,
sg++;
}
- ret = 0;
out:
- if (ret) {
- if (rm)
- rds_message_put(rm);
- rm = ERR_PTR(ret);
- }
- return rm;
+ return ret;
}
int rds_message_inc_copy_to_user(struct rds_incoming *inc,
@@ -348,7 +335,7 @@ int rds_message_inc_copy_to_user(struct rds_incoming *inc,
iov = first_iov;
iov_off = 0;
- sg = rm->m_sg;
+ sg = rm->data.op_sg;
vec_off = 0;
copied = 0;
@@ -394,15 +381,14 @@ int rds_message_inc_copy_to_user(struct rds_incoming *inc,
*/
void rds_message_wait(struct rds_message *rm)
{
- wait_event(rds_message_flush_waitq,
+ wait_event_interruptible(rm->m_flush_wait,
!test_bit(RDS_MSG_MAPPED, &rm->m_flags));
}
void rds_message_unmapped(struct rds_message *rm)
{
clear_bit(RDS_MSG_MAPPED, &rm->m_flags);
- if (waitqueue_active(&rds_message_flush_waitq))
- wake_up(&rds_message_flush_waitq);
+ wake_up_interruptible(&rm->m_flush_wait);
}
EXPORT_SYMBOL_GPL(rds_message_unmapped);
diff --git a/net/rds/page.c b/net/rds/page.c
index 1dfbfea12e9b..d8acdebe3c7c 100644
--- a/net/rds/page.c
+++ b/net/rds/page.c
@@ -40,7 +40,8 @@ struct rds_page_remainder {
unsigned long r_offset;
};
-DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_page_remainder, rds_page_remainders);
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_page_remainder,
+ rds_page_remainders);
/*
* returns 0 on success or -errno on failure.
@@ -103,7 +104,7 @@ int rds_page_remainder_alloc(struct scatterlist *scat, unsigned long bytes,
/* jump straight to allocation if we're trying for a huge page */
if (bytes >= PAGE_SIZE) {
page = alloc_page(gfp);
- if (page == NULL) {
+ if (!page) {
ret = -ENOMEM;
} else {
sg_set_page(scat, page, PAGE_SIZE, 0);
@@ -149,7 +150,7 @@ int rds_page_remainder_alloc(struct scatterlist *scat, unsigned long bytes,
rem = &per_cpu(rds_page_remainders, get_cpu());
local_irq_save(flags);
- if (page == NULL) {
+ if (!page) {
ret = -ENOMEM;
break;
}
@@ -173,6 +174,7 @@ out:
ret ? 0 : scat->length);
return ret;
}
+EXPORT_SYMBOL_GPL(rds_page_remainder_alloc);
static int rds_page_remainder_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
diff --git a/net/rds/rdma.c b/net/rds/rdma.c
index 75fd13bb631b..1a41debca1ce 100644
--- a/net/rds/rdma.c
+++ b/net/rds/rdma.c
@@ -35,7 +35,7 @@
#include <linux/rbtree.h>
#include <linux/dma-mapping.h> /* for DMA_*_DEVICE */
-#include "rdma.h"
+#include "rds.h"
/*
* XXX
@@ -130,14 +130,22 @@ void rds_rdma_drop_keys(struct rds_sock *rs)
{
struct rds_mr *mr;
struct rb_node *node;
+ unsigned long flags;
/* Release any MRs associated with this socket */
+ spin_lock_irqsave(&rs->rs_rdma_lock, flags);
while ((node = rb_first(&rs->rs_rdma_keys))) {
mr = container_of(node, struct rds_mr, r_rb_node);
if (mr->r_trans == rs->rs_transport)
mr->r_invalidate = 0;
+ rb_erase(&mr->r_rb_node, &rs->rs_rdma_keys);
+ RB_CLEAR_NODE(&mr->r_rb_node);
+ spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
+ rds_destroy_mr(mr);
rds_mr_put(mr);
+ spin_lock_irqsave(&rs->rs_rdma_lock, flags);
}
+ spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
if (rs->rs_transport && rs->rs_transport->flush_mrs)
rs->rs_transport->flush_mrs();
@@ -181,7 +189,7 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args,
goto out;
}
- if (rs->rs_transport->get_mr == NULL) {
+ if (!rs->rs_transport->get_mr) {
ret = -EOPNOTSUPP;
goto out;
}
@@ -197,13 +205,13 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args,
/* XXX clamp nr_pages to limit the size of this alloc? */
pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL);
- if (pages == NULL) {
+ if (!pages) {
ret = -ENOMEM;
goto out;
}
mr = kzalloc(sizeof(struct rds_mr), GFP_KERNEL);
- if (mr == NULL) {
+ if (!mr) {
ret = -ENOMEM;
goto out;
}
@@ -230,13 +238,13 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args,
* r/o or r/w. We need to assume r/w, or we'll do a lot of RDMA to
* the zero page.
*/
- ret = rds_pin_pages(args->vec.addr & PAGE_MASK, nr_pages, pages, 1);
+ ret = rds_pin_pages(args->vec.addr, nr_pages, pages, 1);
if (ret < 0)
goto out;
nents = ret;
sg = kcalloc(nents, sizeof(*sg), GFP_KERNEL);
- if (sg == NULL) {
+ if (!sg) {
ret = -ENOMEM;
goto out;
}
@@ -406,68 +414,127 @@ void rds_rdma_unuse(struct rds_sock *rs, u32 r_key, int force)
spin_lock_irqsave(&rs->rs_rdma_lock, flags);
mr = rds_mr_tree_walk(&rs->rs_rdma_keys, r_key, NULL);
- if (mr && (mr->r_use_once || force)) {
+ if (!mr) {
+ printk(KERN_ERR "rds: trying to unuse MR with unknown r_key %u!\n", r_key);
+ spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
+ return;
+ }
+
+ if (mr->r_use_once || force) {
rb_erase(&mr->r_rb_node, &rs->rs_rdma_keys);
RB_CLEAR_NODE(&mr->r_rb_node);
zot_me = 1;
- } else if (mr)
- atomic_inc(&mr->r_refcount);
+ }
spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
/* May have to issue a dma_sync on this memory region.
* Note we could avoid this if the operation was a RDMA READ,
* but at this point we can't tell. */
- if (mr != NULL) {
- if (mr->r_trans->sync_mr)
- mr->r_trans->sync_mr(mr->r_trans_private, DMA_FROM_DEVICE);
-
- /* If the MR was marked as invalidate, this will
- * trigger an async flush. */
- if (zot_me)
- rds_destroy_mr(mr);
- rds_mr_put(mr);
- }
+ if (mr->r_trans->sync_mr)
+ mr->r_trans->sync_mr(mr->r_trans_private, DMA_FROM_DEVICE);
+
+ /* If the MR was marked as invalidate, this will
+ * trigger an async flush. */
+ if (zot_me)
+ rds_destroy_mr(mr);
+ rds_mr_put(mr);
}
-void rds_rdma_free_op(struct rds_rdma_op *ro)
+void rds_rdma_free_op(struct rm_rdma_op *ro)
{
unsigned int i;
- for (i = 0; i < ro->r_nents; i++) {
- struct page *page = sg_page(&ro->r_sg[i]);
+ for (i = 0; i < ro->op_nents; i++) {
+ struct page *page = sg_page(&ro->op_sg[i]);
/* Mark page dirty if it was possibly modified, which
* is the case for a RDMA_READ which copies from remote
* to local memory */
- if (!ro->r_write) {
- BUG_ON(in_interrupt());
+ if (!ro->op_write) {
+ BUG_ON(irqs_disabled());
set_page_dirty(page);
}
put_page(page);
}
- kfree(ro->r_notifier);
- kfree(ro);
+ kfree(ro->op_notifier);
+ ro->op_notifier = NULL;
+ ro->op_active = 0;
+}
+
+void rds_atomic_free_op(struct rm_atomic_op *ao)
+{
+ struct page *page = sg_page(ao->op_sg);
+
+ /* Mark page dirty if it was possibly modified, which
+ * is the case for a RDMA_READ which copies from remote
+ * to local memory */
+ set_page_dirty(page);
+ put_page(page);
+
+ kfree(ao->op_notifier);
+ ao->op_notifier = NULL;
+ ao->op_active = 0;
}
+
/*
- * args is a pointer to an in-kernel copy in the sendmsg cmsg.
+ * Count the number of pages needed to describe an incoming iovec.
*/
-static struct rds_rdma_op *rds_rdma_prepare(struct rds_sock *rs,
- struct rds_rdma_args *args)
+static int rds_rdma_pages(struct rds_rdma_args *args)
{
struct rds_iovec vec;
- struct rds_rdma_op *op = NULL;
+ struct rds_iovec __user *local_vec;
+ unsigned int tot_pages = 0;
unsigned int nr_pages;
- unsigned int max_pages;
+ unsigned int i;
+
+ local_vec = (struct rds_iovec __user *)(unsigned long) args->local_vec_addr;
+
+ /* figure out the number of pages in the vector */
+ for (i = 0; i < args->nr_local; i++) {
+ if (copy_from_user(&vec, &local_vec[i],
+ sizeof(struct rds_iovec)))
+ return -EFAULT;
+
+ nr_pages = rds_pages_in_vec(&vec);
+ if (nr_pages == 0)
+ return -EINVAL;
+
+ tot_pages += nr_pages;
+ }
+
+ return tot_pages;
+}
+
+int rds_rdma_extra_size(struct rds_rdma_args *args)
+{
+ return rds_rdma_pages(args) * sizeof(struct scatterlist);
+}
+
+/*
+ * The application asks for a RDMA transfer.
+ * Extract all arguments and set up the rdma_op
+ */
+int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
+ struct cmsghdr *cmsg)
+{
+ struct rds_rdma_args *args;
+ struct rds_iovec vec;
+ struct rm_rdma_op *op = &rm->rdma;
+ int nr_pages;
unsigned int nr_bytes;
struct page **pages = NULL;
struct rds_iovec __user *local_vec;
- struct scatterlist *sg;
unsigned int nr;
unsigned int i, j;
- int ret;
+ int ret = 0;
+ if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct rds_rdma_args))
+ || rm->rdma.op_active)
+ return -EINVAL;
+
+ args = CMSG_DATA(cmsg);
if (rs->rs_bound_addr == 0) {
ret = -ENOTCONN; /* XXX not a great errno */
@@ -479,61 +546,38 @@ static struct rds_rdma_op *rds_rdma_prepare(struct rds_sock *rs,
goto out;
}
- nr_pages = 0;
- max_pages = 0;
-
- local_vec = (struct rds_iovec __user *)(unsigned long) args->local_vec_addr;
-
- /* figure out the number of pages in the vector */
- for (i = 0; i < args->nr_local; i++) {
- if (copy_from_user(&vec, &local_vec[i],
- sizeof(struct rds_iovec))) {
- ret = -EFAULT;
- goto out;
- }
-
- nr = rds_pages_in_vec(&vec);
- if (nr == 0) {
- ret = -EINVAL;
- goto out;
- }
-
- max_pages = max(nr, max_pages);
- nr_pages += nr;
- }
-
- pages = kcalloc(max_pages, sizeof(struct page *), GFP_KERNEL);
- if (pages == NULL) {
- ret = -ENOMEM;
+ nr_pages = rds_rdma_pages(args);
+ if (nr_pages < 0)
goto out;
- }
- op = kzalloc(offsetof(struct rds_rdma_op, r_sg[nr_pages]), GFP_KERNEL);
- if (op == NULL) {
+ pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL);
+ if (!pages) {
ret = -ENOMEM;
goto out;
}
- op->r_write = !!(args->flags & RDS_RDMA_READWRITE);
- op->r_fence = !!(args->flags & RDS_RDMA_FENCE);
- op->r_notify = !!(args->flags & RDS_RDMA_NOTIFY_ME);
- op->r_recverr = rs->rs_recverr;
+ op->op_write = !!(args->flags & RDS_RDMA_READWRITE);
+ op->op_fence = !!(args->flags & RDS_RDMA_FENCE);
+ op->op_notify = !!(args->flags & RDS_RDMA_NOTIFY_ME);
+ op->op_silent = !!(args->flags & RDS_RDMA_SILENT);
+ op->op_active = 1;
+ op->op_recverr = rs->rs_recverr;
WARN_ON(!nr_pages);
- sg_init_table(op->r_sg, nr_pages);
+ op->op_sg = rds_message_alloc_sgs(rm, nr_pages);
- if (op->r_notify || op->r_recverr) {
+ if (op->op_notify || op->op_recverr) {
/* We allocate an uninitialized notifier here, because
* we don't want to do that in the completion handler. We
* would have to use GFP_ATOMIC there, and don't want to deal
* with failed allocations.
*/
- op->r_notifier = kmalloc(sizeof(struct rds_notifier), GFP_KERNEL);
- if (!op->r_notifier) {
+ op->op_notifier = kmalloc(sizeof(struct rds_notifier), GFP_KERNEL);
+ if (!op->op_notifier) {
ret = -ENOMEM;
goto out;
}
- op->r_notifier->n_user_token = args->user_token;
- op->r_notifier->n_status = RDS_RDMA_SUCCESS;
+ op->op_notifier->n_user_token = args->user_token;
+ op->op_notifier->n_status = RDS_RDMA_SUCCESS;
}
/* The cookie contains the R_Key of the remote memory region, and
@@ -543,15 +587,17 @@ static struct rds_rdma_op *rds_rdma_prepare(struct rds_sock *rs,
* destination address (which is really an offset into the MR)
* FIXME: We may want to move this into ib_rdma.c
*/
- op->r_key = rds_rdma_cookie_key(args->cookie);
- op->r_remote_addr = args->remote_vec.addr + rds_rdma_cookie_offset(args->cookie);
+ op->op_rkey = rds_rdma_cookie_key(args->cookie);
+ op->op_remote_addr = args->remote_vec.addr + rds_rdma_cookie_offset(args->cookie);
nr_bytes = 0;
rdsdebug("RDS: rdma prepare nr_local %llu rva %llx rkey %x\n",
(unsigned long long)args->nr_local,
(unsigned long long)args->remote_vec.addr,
- op->r_key);
+ op->op_rkey);
+
+ local_vec = (struct rds_iovec __user *)(unsigned long) args->local_vec_addr;
for (i = 0; i < args->nr_local; i++) {
if (copy_from_user(&vec, &local_vec[i],
@@ -569,15 +615,10 @@ static struct rds_rdma_op *rds_rdma_prepare(struct rds_sock *rs,
rs->rs_user_addr = vec.addr;
rs->rs_user_bytes = vec.bytes;
- /* did the user change the vec under us? */
- if (nr > max_pages || op->r_nents + nr > nr_pages) {
- ret = -EINVAL;
- goto out;
- }
/* If it's a WRITE operation, we want to pin the pages for reading.
* If it's a READ operation, we need to pin the pages for writing.
*/
- ret = rds_pin_pages(vec.addr & PAGE_MASK, nr, pages, !op->r_write);
+ ret = rds_pin_pages(vec.addr, nr, pages, !op->op_write);
if (ret < 0)
goto out;
@@ -588,8 +629,9 @@ static struct rds_rdma_op *rds_rdma_prepare(struct rds_sock *rs,
for (j = 0; j < nr; j++) {
unsigned int offset = vec.addr & ~PAGE_MASK;
+ struct scatterlist *sg;
- sg = &op->r_sg[op->r_nents + j];
+ sg = &op->op_sg[op->op_nents + j];
sg_set_page(sg, pages[j],
min_t(unsigned int, vec.bytes, PAGE_SIZE - offset),
offset);
@@ -601,10 +643,9 @@ static struct rds_rdma_op *rds_rdma_prepare(struct rds_sock *rs,
vec.bytes -= sg->length;
}
- op->r_nents += nr;
+ op->op_nents += nr;
}
-
if (nr_bytes > args->remote_vec.bytes) {
rdsdebug("RDS nr_bytes %u remote_bytes %u do not match\n",
nr_bytes,
@@ -612,38 +653,17 @@ static struct rds_rdma_op *rds_rdma_prepare(struct rds_sock *rs,
ret = -EINVAL;
goto out;
}
- op->r_bytes = nr_bytes;
+ op->op_bytes = nr_bytes;
ret = 0;
out:
kfree(pages);
- if (ret) {
- if (op)
- rds_rdma_free_op(op);
- op = ERR_PTR(ret);
- }
- return op;
-}
-
-/*
- * The application asks for a RDMA transfer.
- * Extract all arguments and set up the rdma_op
- */
-int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
- struct cmsghdr *cmsg)
-{
- struct rds_rdma_op *op;
-
- if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct rds_rdma_args)) ||
- rm->m_rdma_op != NULL)
- return -EINVAL;
+ if (ret)
+ rds_rdma_free_op(op);
- op = rds_rdma_prepare(rs, CMSG_DATA(cmsg));
- if (IS_ERR(op))
- return PTR_ERR(op);
rds_stats_inc(s_send_rdma);
- rm->m_rdma_op = op;
- return 0;
+
+ return ret;
}
/*
@@ -673,7 +693,7 @@ int rds_cmsg_rdma_dest(struct rds_sock *rs, struct rds_message *rm,
spin_lock_irqsave(&rs->rs_rdma_lock, flags);
mr = rds_mr_tree_walk(&rs->rs_rdma_keys, r_key, NULL);
- if (mr == NULL)
+ if (!mr)
err = -EINVAL; /* invalid r_key */
else
atomic_inc(&mr->r_refcount);
@@ -681,7 +701,7 @@ int rds_cmsg_rdma_dest(struct rds_sock *rs, struct rds_message *rm,
if (mr) {
mr->r_trans->sync_mr(mr->r_trans_private, DMA_TO_DEVICE);
- rm->m_rdma_mr = mr;
+ rm->rdma.op_rdma_mr = mr;
}
return err;
}
@@ -699,5 +719,98 @@ int rds_cmsg_rdma_map(struct rds_sock *rs, struct rds_message *rm,
rm->m_rdma_cookie != 0)
return -EINVAL;
- return __rds_rdma_map(rs, CMSG_DATA(cmsg), &rm->m_rdma_cookie, &rm->m_rdma_mr);
+ return __rds_rdma_map(rs, CMSG_DATA(cmsg), &rm->m_rdma_cookie, &rm->rdma.op_rdma_mr);
+}
+
+/*
+ * Fill in rds_message for an atomic request.
+ */
+int rds_cmsg_atomic(struct rds_sock *rs, struct rds_message *rm,
+ struct cmsghdr *cmsg)
+{
+ struct page *page = NULL;
+ struct rds_atomic_args *args;
+ int ret = 0;
+
+ if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct rds_atomic_args))
+ || rm->atomic.op_active)
+ return -EINVAL;
+
+ args = CMSG_DATA(cmsg);
+
+ /* Nonmasked & masked cmsg ops converted to masked hw ops */
+ switch (cmsg->cmsg_type) {
+ case RDS_CMSG_ATOMIC_FADD:
+ rm->atomic.op_type = RDS_ATOMIC_TYPE_FADD;
+ rm->atomic.op_m_fadd.add = args->fadd.add;
+ rm->atomic.op_m_fadd.nocarry_mask = 0;
+ break;
+ case RDS_CMSG_MASKED_ATOMIC_FADD:
+ rm->atomic.op_type = RDS_ATOMIC_TYPE_FADD;
+ rm->atomic.op_m_fadd.add = args->m_fadd.add;
+ rm->atomic.op_m_fadd.nocarry_mask = args->m_fadd.nocarry_mask;
+ break;
+ case RDS_CMSG_ATOMIC_CSWP:
+ rm->atomic.op_type = RDS_ATOMIC_TYPE_CSWP;
+ rm->atomic.op_m_cswp.compare = args->cswp.compare;
+ rm->atomic.op_m_cswp.swap = args->cswp.swap;
+ rm->atomic.op_m_cswp.compare_mask = ~0;
+ rm->atomic.op_m_cswp.swap_mask = ~0;
+ break;
+ case RDS_CMSG_MASKED_ATOMIC_CSWP:
+ rm->atomic.op_type = RDS_ATOMIC_TYPE_CSWP;
+ rm->atomic.op_m_cswp.compare = args->m_cswp.compare;
+ rm->atomic.op_m_cswp.swap = args->m_cswp.swap;
+ rm->atomic.op_m_cswp.compare_mask = args->m_cswp.compare_mask;
+ rm->atomic.op_m_cswp.swap_mask = args->m_cswp.swap_mask;
+ break;
+ default:
+ BUG(); /* should never happen */
+ }
+
+ rm->atomic.op_notify = !!(args->flags & RDS_RDMA_NOTIFY_ME);
+ rm->atomic.op_silent = !!(args->flags & RDS_RDMA_SILENT);
+ rm->atomic.op_active = 1;
+ rm->atomic.op_recverr = rs->rs_recverr;
+ rm->atomic.op_sg = rds_message_alloc_sgs(rm, 1);
+
+ /* verify 8 byte-aligned */
+ if (args->local_addr & 0x7) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = rds_pin_pages(args->local_addr, 1, &page, 1);
+ if (ret != 1)
+ goto err;
+ ret = 0;
+
+ sg_set_page(rm->atomic.op_sg, page, 8, offset_in_page(args->local_addr));
+
+ if (rm->atomic.op_notify || rm->atomic.op_recverr) {
+ /* We allocate an uninitialized notifier here, because
+ * we don't want to do that in the completion handler. We
+ * would have to use GFP_ATOMIC there, and don't want to deal
+ * with failed allocations.
+ */
+ rm->atomic.op_notifier = kmalloc(sizeof(*rm->atomic.op_notifier), GFP_KERNEL);
+ if (!rm->atomic.op_notifier) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ rm->atomic.op_notifier->n_user_token = args->user_token;
+ rm->atomic.op_notifier->n_status = RDS_RDMA_SUCCESS;
+ }
+
+ rm->atomic.op_rkey = rds_rdma_cookie_key(args->cookie);
+ rm->atomic.op_remote_addr = args->remote_addr + rds_rdma_cookie_offset(args->cookie);
+
+ return ret;
+err:
+ if (page)
+ put_page(page);
+ kfree(rm->atomic.op_notifier);
+
+ return ret;
}
diff --git a/net/rds/rdma.h b/net/rds/rdma.h
deleted file mode 100644
index 909c39835a5d..000000000000
--- a/net/rds/rdma.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef _RDS_RDMA_H
-#define _RDS_RDMA_H
-
-#include <linux/rbtree.h>
-#include <linux/spinlock.h>
-#include <linux/scatterlist.h>
-
-#include "rds.h"
-
-struct rds_mr {
- struct rb_node r_rb_node;
- atomic_t r_refcount;
- u32 r_key;
-
- /* A copy of the creation flags */
- unsigned int r_use_once:1;
- unsigned int r_invalidate:1;
- unsigned int r_write:1;
-
- /* This is for RDS_MR_DEAD.
- * It would be nice & consistent to make this part of the above
- * bit field here, but we need to use test_and_set_bit.
- */
- unsigned long r_state;
- struct rds_sock *r_sock; /* back pointer to the socket that owns us */
- struct rds_transport *r_trans;
- void *r_trans_private;
-};
-
-/* Flags for mr->r_state */
-#define RDS_MR_DEAD 0
-
-struct rds_rdma_op {
- u32 r_key;
- u64 r_remote_addr;
- unsigned int r_write:1;
- unsigned int r_fence:1;
- unsigned int r_notify:1;
- unsigned int r_recverr:1;
- unsigned int r_mapped:1;
- struct rds_notifier *r_notifier;
- unsigned int r_bytes;
- unsigned int r_nents;
- unsigned int r_count;
- struct scatterlist r_sg[0];
-};
-
-static inline rds_rdma_cookie_t rds_rdma_make_cookie(u32 r_key, u32 offset)
-{
- return r_key | (((u64) offset) << 32);
-}
-
-static inline u32 rds_rdma_cookie_key(rds_rdma_cookie_t cookie)
-{
- return cookie;
-}
-
-static inline u32 rds_rdma_cookie_offset(rds_rdma_cookie_t cookie)
-{
- return cookie >> 32;
-}
-
-int rds_get_mr(struct rds_sock *rs, char __user *optval, int optlen);
-int rds_get_mr_for_dest(struct rds_sock *rs, char __user *optval, int optlen);
-int rds_free_mr(struct rds_sock *rs, char __user *optval, int optlen);
-void rds_rdma_drop_keys(struct rds_sock *rs);
-int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
- struct cmsghdr *cmsg);
-int rds_cmsg_rdma_dest(struct rds_sock *rs, struct rds_message *rm,
- struct cmsghdr *cmsg);
-int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
- struct cmsghdr *cmsg);
-int rds_cmsg_rdma_map(struct rds_sock *rs, struct rds_message *rm,
- struct cmsghdr *cmsg);
-void rds_rdma_free_op(struct rds_rdma_op *ro);
-void rds_rdma_send_complete(struct rds_message *rm, int);
-
-extern void __rds_put_mr_final(struct rds_mr *mr);
-static inline void rds_mr_put(struct rds_mr *mr)
-{
- if (atomic_dec_and_test(&mr->r_refcount))
- __rds_put_mr_final(mr);
-}
-
-#endif
diff --git a/net/rds/rdma_transport.c b/net/rds/rdma_transport.c
index e599ba2f950d..4195a0539829 100644
--- a/net/rds/rdma_transport.c
+++ b/net/rds/rdma_transport.c
@@ -36,6 +36,34 @@
static struct rdma_cm_id *rds_rdma_listen_id;
+static char *rds_cm_event_strings[] = {
+#define RDS_CM_EVENT_STRING(foo) \
+ [RDMA_CM_EVENT_##foo] = __stringify(RDMA_CM_EVENT_##foo)
+ RDS_CM_EVENT_STRING(ADDR_RESOLVED),
+ RDS_CM_EVENT_STRING(ADDR_ERROR),
+ RDS_CM_EVENT_STRING(ROUTE_RESOLVED),
+ RDS_CM_EVENT_STRING(ROUTE_ERROR),
+ RDS_CM_EVENT_STRING(CONNECT_REQUEST),
+ RDS_CM_EVENT_STRING(CONNECT_RESPONSE),
+ RDS_CM_EVENT_STRING(CONNECT_ERROR),
+ RDS_CM_EVENT_STRING(UNREACHABLE),
+ RDS_CM_EVENT_STRING(REJECTED),
+ RDS_CM_EVENT_STRING(ESTABLISHED),
+ RDS_CM_EVENT_STRING(DISCONNECTED),
+ RDS_CM_EVENT_STRING(DEVICE_REMOVAL),
+ RDS_CM_EVENT_STRING(MULTICAST_JOIN),
+ RDS_CM_EVENT_STRING(MULTICAST_ERROR),
+ RDS_CM_EVENT_STRING(ADDR_CHANGE),
+ RDS_CM_EVENT_STRING(TIMEWAIT_EXIT),
+#undef RDS_CM_EVENT_STRING
+};
+
+static char *rds_cm_event_str(enum rdma_cm_event_type type)
+{
+ return rds_str_array(rds_cm_event_strings,
+ ARRAY_SIZE(rds_cm_event_strings), type);
+};
+
int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
struct rdma_cm_event *event)
{
@@ -44,8 +72,8 @@ int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
struct rds_transport *trans;
int ret = 0;
- rdsdebug("conn %p id %p handling event %u\n", conn, cm_id,
- event->event);
+ rdsdebug("conn %p id %p handling event %u (%s)\n", conn, cm_id,
+ event->event, rds_cm_event_str(event->event));
if (cm_id->device->node_type == RDMA_NODE_RNIC)
trans = &rds_iw_transport;
@@ -109,7 +137,8 @@ int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
default:
/* things like device disconnect? */
- printk(KERN_ERR "RDS: unknown event %u!\n", event->event);
+ printk(KERN_ERR "RDS: unknown event %u (%s)!\n",
+ event->event, rds_cm_event_str(event->event));
break;
}
@@ -117,12 +146,13 @@ out:
if (conn)
mutex_unlock(&conn->c_cm_lock);
- rdsdebug("id %p event %u handling ret %d\n", cm_id, event->event, ret);
+ rdsdebug("id %p event %u (%s) handling ret %d\n", cm_id, event->event,
+ rds_cm_event_str(event->event), ret);
return ret;
}
-static int __init rds_rdma_listen_init(void)
+static int rds_rdma_listen_init(void)
{
struct sockaddr_in sin;
struct rdma_cm_id *cm_id;
@@ -177,7 +207,7 @@ static void rds_rdma_listen_stop(void)
}
}
-int __init rds_rdma_init(void)
+static int rds_rdma_init(void)
{
int ret;
@@ -204,7 +234,7 @@ out:
}
module_init(rds_rdma_init);
-void rds_rdma_exit(void)
+static void rds_rdma_exit(void)
{
/* stop listening first to ensure no new connections are attempted */
rds_rdma_listen_stop();
diff --git a/net/rds/rdma_transport.h b/net/rds/rdma_transport.h
index 2f2c7d976c21..faba4e382695 100644
--- a/net/rds/rdma_transport.h
+++ b/net/rds/rdma_transport.h
@@ -11,10 +11,6 @@ int rds_rdma_conn_connect(struct rds_connection *conn);
int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
struct rdma_cm_event *event);
-/* from rdma_transport.c */
-int rds_rdma_init(void);
-void rds_rdma_exit(void);
-
/* from ib.c */
extern struct rds_transport rds_ib_transport;
int rds_ib_init(void);
diff --git a/net/rds/rds.h b/net/rds/rds.h
index c224b5bb3ba9..9542449c0720 100644
--- a/net/rds/rds.h
+++ b/net/rds/rds.h
@@ -80,6 +80,7 @@ enum {
/* Bits for c_flags */
#define RDS_LL_SEND_FULL 0
#define RDS_RECONNECT_PENDING 1
+#define RDS_IN_XMIT 2
struct rds_connection {
struct hlist_node c_hash_node;
@@ -91,12 +92,13 @@ struct rds_connection {
struct rds_cong_map *c_lcong;
struct rds_cong_map *c_fcong;
- struct mutex c_send_lock; /* protect send ring */
struct rds_message *c_xmit_rm;
unsigned long c_xmit_sg;
unsigned int c_xmit_hdr_off;
unsigned int c_xmit_data_off;
+ unsigned int c_xmit_atomic_sent;
unsigned int c_xmit_rdma_sent;
+ unsigned int c_xmit_data_sent;
spinlock_t c_lock; /* protect msg queues */
u64 c_next_tx_seq;
@@ -116,11 +118,10 @@ struct rds_connection {
struct delayed_work c_conn_w;
struct work_struct c_down_w;
struct mutex c_cm_lock; /* protect conn state & cm */
+ wait_queue_head_t c_waitq;
struct list_head c_map_item;
unsigned long c_map_queued;
- unsigned long c_map_offset;
- unsigned long c_map_bytes;
unsigned int c_unacked_packets;
unsigned int c_unacked_bytes;
@@ -206,6 +207,48 @@ struct rds_incoming {
rds_rdma_cookie_t i_rdma_cookie;
};
+struct rds_mr {
+ struct rb_node r_rb_node;
+ atomic_t r_refcount;
+ u32 r_key;
+
+ /* A copy of the creation flags */
+ unsigned int r_use_once:1;
+ unsigned int r_invalidate:1;
+ unsigned int r_write:1;
+
+ /* This is for RDS_MR_DEAD.
+ * It would be nice & consistent to make this part of the above
+ * bit field here, but we need to use test_and_set_bit.
+ */
+ unsigned long r_state;
+ struct rds_sock *r_sock; /* back pointer to the socket that owns us */
+ struct rds_transport *r_trans;
+ void *r_trans_private;
+};
+
+/* Flags for mr->r_state */
+#define RDS_MR_DEAD 0
+
+static inline rds_rdma_cookie_t rds_rdma_make_cookie(u32 r_key, u32 offset)
+{
+ return r_key | (((u64) offset) << 32);
+}
+
+static inline u32 rds_rdma_cookie_key(rds_rdma_cookie_t cookie)
+{
+ return cookie;
+}
+
+static inline u32 rds_rdma_cookie_offset(rds_rdma_cookie_t cookie)
+{
+ return cookie >> 32;
+}
+
+/* atomic operation types */
+#define RDS_ATOMIC_TYPE_CSWP 0
+#define RDS_ATOMIC_TYPE_FADD 1
+
/*
* m_sock_item and m_conn_item are on lists that are serialized under
* conn->c_lock. m_sock_item has additional meaning in that once it is empty
@@ -258,13 +301,71 @@ struct rds_message {
* -> rs->rs_lock
*/
spinlock_t m_rs_lock;
+ wait_queue_head_t m_flush_wait;
+
struct rds_sock *m_rs;
- struct rds_rdma_op *m_rdma_op;
+
+ /* cookie to send to remote, in rds header */
rds_rdma_cookie_t m_rdma_cookie;
- struct rds_mr *m_rdma_mr;
- unsigned int m_nents;
- unsigned int m_count;
- struct scatterlist m_sg[0];
+
+ unsigned int m_used_sgs;
+ unsigned int m_total_sgs;
+
+ void *m_final_op;
+
+ struct {
+ struct rm_atomic_op {
+ int op_type;
+ union {
+ struct {
+ uint64_t compare;
+ uint64_t swap;
+ uint64_t compare_mask;
+ uint64_t swap_mask;
+ } op_m_cswp;
+ struct {
+ uint64_t add;
+ uint64_t nocarry_mask;
+ } op_m_fadd;
+ };
+
+ u32 op_rkey;
+ u64 op_remote_addr;
+ unsigned int op_notify:1;
+ unsigned int op_recverr:1;
+ unsigned int op_mapped:1;
+ unsigned int op_silent:1;
+ unsigned int op_active:1;
+ struct scatterlist *op_sg;
+ struct rds_notifier *op_notifier;
+
+ struct rds_mr *op_rdma_mr;
+ } atomic;
+ struct rm_rdma_op {
+ u32 op_rkey;
+ u64 op_remote_addr;
+ unsigned int op_write:1;
+ unsigned int op_fence:1;
+ unsigned int op_notify:1;
+ unsigned int op_recverr:1;
+ unsigned int op_mapped:1;
+ unsigned int op_silent:1;
+ unsigned int op_active:1;
+ unsigned int op_bytes;
+ unsigned int op_nents;
+ unsigned int op_count;
+ struct scatterlist *op_sg;
+ struct rds_notifier *op_notifier;
+
+ struct rds_mr *op_rdma_mr;
+ } rdma;
+ struct rm_data_op {
+ unsigned int op_active:1;
+ unsigned int op_nents;
+ unsigned int op_count;
+ struct scatterlist *op_sg;
+ } data;
+ };
};
/*
@@ -305,10 +406,6 @@ struct rds_notifier {
* transport is responsible for other serialization, including
* rds_recv_incoming(). This is called in process context but
* should try hard not to block.
- *
- * @xmit_cong_map: This asks the transport to send the local bitmap down the
- * given connection. XXX get a better story about the bitmap
- * flag and header.
*/
#define RDS_TRANS_IB 0
@@ -332,13 +429,11 @@ struct rds_transport {
void (*xmit_complete)(struct rds_connection *conn);
int (*xmit)(struct rds_connection *conn, struct rds_message *rm,
unsigned int hdr_off, unsigned int sg, unsigned int off);
- int (*xmit_cong_map)(struct rds_connection *conn,
- struct rds_cong_map *map, unsigned long offset);
- int (*xmit_rdma)(struct rds_connection *conn, struct rds_rdma_op *op);
+ int (*xmit_rdma)(struct rds_connection *conn, struct rm_rdma_op *op);
+ int (*xmit_atomic)(struct rds_connection *conn, struct rm_atomic_op *op);
int (*recv)(struct rds_connection *conn);
int (*inc_copy_to_user)(struct rds_incoming *inc, struct iovec *iov,
size_t size);
- void (*inc_purge)(struct rds_incoming *inc);
void (*inc_free)(struct rds_incoming *inc);
int (*cm_handle_connect)(struct rdma_cm_id *cm_id,
@@ -367,17 +462,11 @@ struct rds_sock {
* bound_addr used for both incoming and outgoing, no INADDR_ANY
* support.
*/
- struct rb_node rs_bound_node;
+ struct hlist_node rs_bound_node;
__be32 rs_bound_addr;
__be32 rs_conn_addr;
__be16 rs_bound_port;
__be16 rs_conn_port;
-
- /*
- * This is only used to communicate the transport between bind and
- * initiating connections. All other trans use is referenced through
- * the connection.
- */
struct rds_transport *rs_transport;
/*
@@ -466,8 +555,8 @@ struct rds_statistics {
uint64_t s_recv_ping;
uint64_t s_send_queue_empty;
uint64_t s_send_queue_full;
- uint64_t s_send_sem_contention;
- uint64_t s_send_sem_queue_raced;
+ uint64_t s_send_lock_contention;
+ uint64_t s_send_lock_queue_raced;
uint64_t s_send_immediate_retry;
uint64_t s_send_delayed_retry;
uint64_t s_send_drop_acked;
@@ -487,6 +576,7 @@ struct rds_statistics {
};
/* af_rds.c */
+char *rds_str_array(char **array, size_t elements, size_t index);
void rds_sock_addref(struct rds_sock *rs);
void rds_sock_put(struct rds_sock *rs);
void rds_wake_sk_sleep(struct rds_sock *rs);
@@ -521,15 +611,16 @@ void rds_cong_exit(void);
struct rds_message *rds_cong_update_alloc(struct rds_connection *conn);
/* conn.c */
-int __init rds_conn_init(void);
+int rds_conn_init(void);
void rds_conn_exit(void);
struct rds_connection *rds_conn_create(__be32 laddr, __be32 faddr,
struct rds_transport *trans, gfp_t gfp);
struct rds_connection *rds_conn_create_outgoing(__be32 laddr, __be32 faddr,
struct rds_transport *trans, gfp_t gfp);
+void rds_conn_shutdown(struct rds_connection *conn);
void rds_conn_destroy(struct rds_connection *conn);
-void rds_conn_reset(struct rds_connection *conn);
void rds_conn_drop(struct rds_connection *conn);
+void rds_conn_connect_if_down(struct rds_connection *conn);
void rds_for_each_conn_info(struct socket *sock, unsigned int len,
struct rds_info_iterator *iter,
struct rds_info_lengths *lens,
@@ -566,7 +657,8 @@ rds_conn_connecting(struct rds_connection *conn)
/* message.c */
struct rds_message *rds_message_alloc(unsigned int nents, gfp_t gfp);
-struct rds_message *rds_message_copy_from_user(struct iovec *first_iov,
+struct scatterlist *rds_message_alloc_sgs(struct rds_message *rm, int nents);
+int rds_message_copy_from_user(struct rds_message *rm, struct iovec *first_iov,
size_t total_len);
struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned int total_len);
void rds_message_populate_header(struct rds_header *hdr, __be16 sport,
@@ -575,12 +667,9 @@ int rds_message_add_extension(struct rds_header *hdr,
unsigned int type, const void *data, unsigned int len);
int rds_message_next_extension(struct rds_header *hdr,
unsigned int *pos, void *buf, unsigned int *buflen);
-int rds_message_add_version_extension(struct rds_header *hdr, unsigned int version);
-int rds_message_get_version_extension(struct rds_header *hdr, unsigned int *version);
int rds_message_add_rdma_dest_extension(struct rds_header *hdr, u32 r_key, u32 offset);
int rds_message_inc_copy_to_user(struct rds_incoming *inc,
struct iovec *first_iov, size_t size);
-void rds_message_inc_purge(struct rds_incoming *inc);
void rds_message_inc_free(struct rds_incoming *inc);
void rds_message_addref(struct rds_message *rm);
void rds_message_put(struct rds_message *rm);
@@ -614,7 +703,6 @@ void rds_page_exit(void);
/* recv.c */
void rds_inc_init(struct rds_incoming *inc, struct rds_connection *conn,
__be32 saddr);
-void rds_inc_addref(struct rds_incoming *inc);
void rds_inc_put(struct rds_incoming *inc);
void rds_recv_incoming(struct rds_connection *conn, __be32 saddr, __be32 daddr,
struct rds_incoming *inc, gfp_t gfp, enum km_type km);
@@ -636,14 +724,38 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest);
typedef int (*is_acked_func)(struct rds_message *rm, uint64_t ack);
void rds_send_drop_acked(struct rds_connection *conn, u64 ack,
is_acked_func is_acked);
-int rds_send_acked_before(struct rds_connection *conn, u64 seq);
-void rds_send_remove_from_sock(struct list_head *messages, int status);
int rds_send_pong(struct rds_connection *conn, __be16 dport);
struct rds_message *rds_send_get_message(struct rds_connection *,
- struct rds_rdma_op *);
+ struct rm_rdma_op *);
/* rdma.c */
void rds_rdma_unuse(struct rds_sock *rs, u32 r_key, int force);
+int rds_get_mr(struct rds_sock *rs, char __user *optval, int optlen);
+int rds_get_mr_for_dest(struct rds_sock *rs, char __user *optval, int optlen);
+int rds_free_mr(struct rds_sock *rs, char __user *optval, int optlen);
+void rds_rdma_drop_keys(struct rds_sock *rs);
+int rds_rdma_extra_size(struct rds_rdma_args *args);
+int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
+ struct cmsghdr *cmsg);
+int rds_cmsg_rdma_dest(struct rds_sock *rs, struct rds_message *rm,
+ struct cmsghdr *cmsg);
+int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
+ struct cmsghdr *cmsg);
+int rds_cmsg_rdma_map(struct rds_sock *rs, struct rds_message *rm,
+ struct cmsghdr *cmsg);
+void rds_rdma_free_op(struct rm_rdma_op *ro);
+void rds_atomic_free_op(struct rm_atomic_op *ao);
+void rds_rdma_send_complete(struct rds_message *rm, int wc_status);
+void rds_atomic_send_complete(struct rds_message *rm, int wc_status);
+int rds_cmsg_atomic(struct rds_sock *rs, struct rds_message *rm,
+ struct cmsghdr *cmsg);
+
+extern void __rds_put_mr_final(struct rds_mr *mr);
+static inline void rds_mr_put(struct rds_mr *mr)
+{
+ if (atomic_dec_and_test(&mr->r_refcount))
+ __rds_put_mr_final(mr);
+}
/* stats.c */
DECLARE_PER_CPU_SHARED_ALIGNED(struct rds_statistics, rds_stats);
@@ -657,14 +769,14 @@ DECLARE_PER_CPU_SHARED_ALIGNED(struct rds_statistics, rds_stats);
put_cpu(); \
} while (0)
#define rds_stats_add(member, count) rds_stats_add_which(rds_stats, member, count)
-int __init rds_stats_init(void);
+int rds_stats_init(void);
void rds_stats_exit(void);
void rds_stats_info_copy(struct rds_info_iterator *iter,
uint64_t *values, const char *const *names,
size_t nr);
/* sysctl.c */
-int __init rds_sysctl_init(void);
+int rds_sysctl_init(void);
void rds_sysctl_exit(void);
extern unsigned long rds_sysctl_sndbuf_min;
extern unsigned long rds_sysctl_sndbuf_default;
@@ -678,9 +790,10 @@ extern unsigned long rds_sysctl_trace_flags;
extern unsigned int rds_sysctl_trace_level;
/* threads.c */
-int __init rds_threads_init(void);
+int rds_threads_init(void);
void rds_threads_exit(void);
extern struct workqueue_struct *rds_wq;
+void rds_queue_reconnect(struct rds_connection *conn);
void rds_connect_worker(struct work_struct *);
void rds_shutdown_worker(struct work_struct *);
void rds_send_worker(struct work_struct *);
@@ -691,9 +804,10 @@ void rds_connect_complete(struct rds_connection *conn);
int rds_trans_register(struct rds_transport *trans);
void rds_trans_unregister(struct rds_transport *trans);
struct rds_transport *rds_trans_get_preferred(__be32 addr);
+void rds_trans_put(struct rds_transport *trans);
unsigned int rds_trans_stats_info_copy(struct rds_info_iterator *iter,
unsigned int avail);
-int __init rds_trans_init(void);
+int rds_trans_init(void);
void rds_trans_exit(void);
#endif
diff --git a/net/rds/recv.c b/net/rds/recv.c
index c93588c2d553..596689e59272 100644
--- a/net/rds/recv.c
+++ b/net/rds/recv.c
@@ -36,7 +36,6 @@
#include <linux/in.h>
#include "rds.h"
-#include "rdma.h"
void rds_inc_init(struct rds_incoming *inc, struct rds_connection *conn,
__be32 saddr)
@@ -49,12 +48,11 @@ void rds_inc_init(struct rds_incoming *inc, struct rds_connection *conn,
}
EXPORT_SYMBOL_GPL(rds_inc_init);
-void rds_inc_addref(struct rds_incoming *inc)
+static void rds_inc_addref(struct rds_incoming *inc)
{
rdsdebug("addref inc %p ref %d\n", inc, atomic_read(&inc->i_refcount));
atomic_inc(&inc->i_refcount);
}
-EXPORT_SYMBOL_GPL(rds_inc_addref);
void rds_inc_put(struct rds_incoming *inc)
{
@@ -210,7 +208,7 @@ void rds_recv_incoming(struct rds_connection *conn, __be32 saddr, __be32 daddr,
}
rs = rds_find_bound(daddr, inc->i_hdr.h_dport);
- if (rs == NULL) {
+ if (!rs) {
rds_stats_inc(s_recv_drop_no_sock);
goto out;
}
@@ -251,7 +249,7 @@ static int rds_next_incoming(struct rds_sock *rs, struct rds_incoming **inc)
{
unsigned long flags;
- if (*inc == NULL) {
+ if (!*inc) {
read_lock_irqsave(&rs->rs_recv_lock, flags);
if (!list_empty(&rs->rs_recv_queue)) {
*inc = list_entry(rs->rs_recv_queue.next,
@@ -334,10 +332,10 @@ int rds_notify_queue_get(struct rds_sock *rs, struct msghdr *msghdr)
if (msghdr) {
cmsg.user_token = notifier->n_user_token;
- cmsg.status = notifier->n_status;
+ cmsg.status = notifier->n_status;
err = put_cmsg(msghdr, SOL_RDS, RDS_CMSG_RDMA_STATUS,
- sizeof(cmsg), &cmsg);
+ sizeof(cmsg), &cmsg);
if (err)
break;
}
diff --git a/net/rds/send.c b/net/rds/send.c
index 9c1c6bcaa6c9..0bc9db17a87d 100644
--- a/net/rds/send.c
+++ b/net/rds/send.c
@@ -37,7 +37,6 @@
#include <linux/list.h>
#include "rds.h"
-#include "rdma.h"
/* When transmitting messages in rds_send_xmit, we need to emerge from
* time to time and briefly release the CPU. Otherwise the softlock watchdog
@@ -53,8 +52,11 @@ static int send_batch_count = 64;
module_param(send_batch_count, int, 0444);
MODULE_PARM_DESC(send_batch_count, " batch factor when working the send queue");
+static void rds_send_remove_from_sock(struct list_head *messages, int status);
+
/*
- * Reset the send state. Caller must hold c_send_lock when calling here.
+ * Reset the send state. Callers must ensure that this doesn't race with
+ * rds_send_xmit().
*/
void rds_send_reset(struct rds_connection *conn)
{
@@ -62,18 +64,22 @@ void rds_send_reset(struct rds_connection *conn)
unsigned long flags;
if (conn->c_xmit_rm) {
+ rm = conn->c_xmit_rm;
+ conn->c_xmit_rm = NULL;
/* Tell the user the RDMA op is no longer mapped by the
* transport. This isn't entirely true (it's flushed out
* independently) but as the connection is down, there's
* no ongoing RDMA to/from that memory */
- rds_message_unmapped(conn->c_xmit_rm);
- rds_message_put(conn->c_xmit_rm);
- conn->c_xmit_rm = NULL;
+ rds_message_unmapped(rm);
+ rds_message_put(rm);
}
+
conn->c_xmit_sg = 0;
conn->c_xmit_hdr_off = 0;
conn->c_xmit_data_off = 0;
+ conn->c_xmit_atomic_sent = 0;
conn->c_xmit_rdma_sent = 0;
+ conn->c_xmit_data_sent = 0;
conn->c_map_queued = 0;
@@ -90,6 +96,25 @@ void rds_send_reset(struct rds_connection *conn)
spin_unlock_irqrestore(&conn->c_lock, flags);
}
+static int acquire_in_xmit(struct rds_connection *conn)
+{
+ return test_and_set_bit(RDS_IN_XMIT, &conn->c_flags) == 0;
+}
+
+static void release_in_xmit(struct rds_connection *conn)
+{
+ clear_bit(RDS_IN_XMIT, &conn->c_flags);
+ smp_mb__after_clear_bit();
+ /*
+ * We don't use wait_on_bit()/wake_up_bit() because our waking is in a
+ * hot path and finding waiters is very rare. We don't want to walk
+ * the system-wide hashed waitqueue buckets in the fast path only to
+ * almost never find waiters.
+ */
+ if (waitqueue_active(&conn->c_waitq))
+ wake_up_all(&conn->c_waitq);
+}
+
/*
* We're making the concious trade-off here to only send one message
* down the connection at a time.
@@ -109,102 +134,69 @@ int rds_send_xmit(struct rds_connection *conn)
struct rds_message *rm;
unsigned long flags;
unsigned int tmp;
- unsigned int send_quota = send_batch_count;
struct scatterlist *sg;
int ret = 0;
- int was_empty = 0;
LIST_HEAD(to_be_dropped);
+restart:
+
/*
* sendmsg calls here after having queued its message on the send
* queue. We only have one task feeding the connection at a time. If
* another thread is already feeding the queue then we back off. This
* avoids blocking the caller and trading per-connection data between
* caches per message.
- *
- * The sem holder will issue a retry if they notice that someone queued
- * a message after they stopped walking the send queue but before they
- * dropped the sem.
*/
- if (!mutex_trylock(&conn->c_send_lock)) {
- rds_stats_inc(s_send_sem_contention);
+ if (!acquire_in_xmit(conn)) {
+ rds_stats_inc(s_send_lock_contention);
ret = -ENOMEM;
goto out;
}
+ /*
+ * rds_conn_shutdown() sets the conn state and then tests RDS_IN_XMIT,
+ * we do the opposite to avoid races.
+ */
+ if (!rds_conn_up(conn)) {
+ release_in_xmit(conn);
+ ret = 0;
+ goto out;
+ }
+
if (conn->c_trans->xmit_prepare)
conn->c_trans->xmit_prepare(conn);
/*
* spin trying to push headers and data down the connection until
- * the connection doens't make forward progress.
+ * the connection doesn't make forward progress.
*/
- while (--send_quota) {
- /*
- * See if need to send a congestion map update if we're
- * between sending messages. The send_sem protects our sole
- * use of c_map_offset and _bytes.
- * Note this is used only by transports that define a special
- * xmit_cong_map function. For all others, we create allocate
- * a cong_map message and treat it just like any other send.
- */
- if (conn->c_map_bytes) {
- ret = conn->c_trans->xmit_cong_map(conn, conn->c_lcong,
- conn->c_map_offset);
- if (ret <= 0)
- break;
+ while (1) {
- conn->c_map_offset += ret;
- conn->c_map_bytes -= ret;
- if (conn->c_map_bytes)
- continue;
- }
-
- /* If we're done sending the current message, clear the
- * offset and S/G temporaries.
- */
rm = conn->c_xmit_rm;
- if (rm != NULL &&
- conn->c_xmit_hdr_off == sizeof(struct rds_header) &&
- conn->c_xmit_sg == rm->m_nents) {
- conn->c_xmit_rm = NULL;
- conn->c_xmit_sg = 0;
- conn->c_xmit_hdr_off = 0;
- conn->c_xmit_data_off = 0;
- conn->c_xmit_rdma_sent = 0;
-
- /* Release the reference to the previous message. */
- rds_message_put(rm);
- rm = NULL;
- }
- /* If we're asked to send a cong map update, do so.
+ /*
+ * If between sending messages, we can send a pending congestion
+ * map update.
*/
- if (rm == NULL && test_and_clear_bit(0, &conn->c_map_queued)) {
- if (conn->c_trans->xmit_cong_map != NULL) {
- conn->c_map_offset = 0;
- conn->c_map_bytes = sizeof(struct rds_header) +
- RDS_CONG_MAP_BYTES;
- continue;
- }
-
+ if (!rm && test_and_clear_bit(0, &conn->c_map_queued)) {
rm = rds_cong_update_alloc(conn);
if (IS_ERR(rm)) {
ret = PTR_ERR(rm);
break;
}
+ rm->data.op_active = 1;
conn->c_xmit_rm = rm;
}
/*
- * Grab the next message from the send queue, if there is one.
+ * If not already working on one, grab the next message.
*
* c_xmit_rm holds a ref while we're sending this message down
* the connction. We can use this ref while holding the
* send_sem.. rds_send_reset() is serialized with it.
*/
- if (rm == NULL) {
+ if (!rm) {
unsigned int len;
spin_lock_irqsave(&conn->c_lock, flags);
@@ -224,10 +216,8 @@ int rds_send_xmit(struct rds_connection *conn)
spin_unlock_irqrestore(&conn->c_lock, flags);
- if (rm == NULL) {
- was_empty = 1;
+ if (!rm)
break;
- }
/* Unfortunately, the way Infiniband deals with
* RDMA to a bad MR key is by moving the entire
@@ -236,13 +226,12 @@ int rds_send_xmit(struct rds_connection *conn)
* connection.
* Therefore, we never retransmit messages with RDMA ops.
*/
- if (rm->m_rdma_op &&
+ if (rm->rdma.op_active &&
test_bit(RDS_MSG_RETRANSMITTED, &rm->m_flags)) {
spin_lock_irqsave(&conn->c_lock, flags);
if (test_and_clear_bit(RDS_MSG_ON_CONN, &rm->m_flags))
list_move(&rm->m_conn_item, &to_be_dropped);
spin_unlock_irqrestore(&conn->c_lock, flags);
- rds_message_put(rm);
continue;
}
@@ -263,23 +252,55 @@ int rds_send_xmit(struct rds_connection *conn)
conn->c_xmit_rm = rm;
}
- /*
- * Try and send an rdma message. Let's see if we can
- * keep this simple and require that the transport either
- * send the whole rdma or none of it.
- */
- if (rm->m_rdma_op && !conn->c_xmit_rdma_sent) {
- ret = conn->c_trans->xmit_rdma(conn, rm->m_rdma_op);
+ /* The transport either sends the whole rdma or none of it */
+ if (rm->rdma.op_active && !conn->c_xmit_rdma_sent) {
+ rm->m_final_op = &rm->rdma;
+ ret = conn->c_trans->xmit_rdma(conn, &rm->rdma);
if (ret)
break;
conn->c_xmit_rdma_sent = 1;
+
/* The transport owns the mapped memory for now.
* You can't unmap it while it's on the send queue */
set_bit(RDS_MSG_MAPPED, &rm->m_flags);
}
- if (conn->c_xmit_hdr_off < sizeof(struct rds_header) ||
- conn->c_xmit_sg < rm->m_nents) {
+ if (rm->atomic.op_active && !conn->c_xmit_atomic_sent) {
+ rm->m_final_op = &rm->atomic;
+ ret = conn->c_trans->xmit_atomic(conn, &rm->atomic);
+ if (ret)
+ break;
+ conn->c_xmit_atomic_sent = 1;
+
+ /* The transport owns the mapped memory for now.
+ * You can't unmap it while it's on the send queue */
+ set_bit(RDS_MSG_MAPPED, &rm->m_flags);
+ }
+
+ /*
+ * A number of cases require an RDS header to be sent
+ * even if there is no data.
+ * We permit 0-byte sends; rds-ping depends on this.
+ * However, if there are exclusively attached silent ops,
+ * we skip the hdr/data send, to enable silent operation.
+ */
+ if (rm->data.op_nents == 0) {
+ int ops_present;
+ int all_ops_are_silent = 1;
+
+ ops_present = (rm->atomic.op_active || rm->rdma.op_active);
+ if (rm->atomic.op_active && !rm->atomic.op_silent)
+ all_ops_are_silent = 0;
+ if (rm->rdma.op_active && !rm->rdma.op_silent)
+ all_ops_are_silent = 0;
+
+ if (ops_present && all_ops_are_silent
+ && !rm->m_rdma_cookie)
+ rm->data.op_active = 0;
+ }
+
+ if (rm->data.op_active && !conn->c_xmit_data_sent) {
+ rm->m_final_op = &rm->data;
ret = conn->c_trans->xmit(conn, rm,
conn->c_xmit_hdr_off,
conn->c_xmit_sg,
@@ -295,7 +316,7 @@ int rds_send_xmit(struct rds_connection *conn)
ret -= tmp;
}
- sg = &rm->m_sg[conn->c_xmit_sg];
+ sg = &rm->data.op_sg[conn->c_xmit_sg];
while (ret) {
tmp = min_t(int, ret, sg->length -
conn->c_xmit_data_off);
@@ -306,49 +327,63 @@ int rds_send_xmit(struct rds_connection *conn)
sg++;
conn->c_xmit_sg++;
BUG_ON(ret != 0 &&
- conn->c_xmit_sg == rm->m_nents);
+ conn->c_xmit_sg == rm->data.op_nents);
}
}
+
+ if (conn->c_xmit_hdr_off == sizeof(struct rds_header) &&
+ (conn->c_xmit_sg == rm->data.op_nents))
+ conn->c_xmit_data_sent = 1;
}
- }
- /* Nuke any messages we decided not to retransmit. */
- if (!list_empty(&to_be_dropped))
- rds_send_remove_from_sock(&to_be_dropped, RDS_RDMA_DROPPED);
+ /*
+ * A rm will only take multiple times through this loop
+ * if there is a data op. Thus, if the data is sent (or there was
+ * none), then we're done with the rm.
+ */
+ if (!rm->data.op_active || conn->c_xmit_data_sent) {
+ conn->c_xmit_rm = NULL;
+ conn->c_xmit_sg = 0;
+ conn->c_xmit_hdr_off = 0;
+ conn->c_xmit_data_off = 0;
+ conn->c_xmit_rdma_sent = 0;
+ conn->c_xmit_atomic_sent = 0;
+ conn->c_xmit_data_sent = 0;
+
+ rds_message_put(rm);
+ }
+ }
if (conn->c_trans->xmit_complete)
conn->c_trans->xmit_complete(conn);
- /*
- * We might be racing with another sender who queued a message but
- * backed off on noticing that we held the c_send_lock. If we check
- * for queued messages after dropping the sem then either we'll
- * see the queued message or the queuer will get the sem. If we
- * notice the queued message then we trigger an immediate retry.
- *
- * We need to be careful only to do this when we stopped processing
- * the send queue because it was empty. It's the only way we
- * stop processing the loop when the transport hasn't taken
- * responsibility for forward progress.
- */
- mutex_unlock(&conn->c_send_lock);
+ release_in_xmit(conn);
- if (conn->c_map_bytes || (send_quota == 0 && !was_empty)) {
- /* We exhausted the send quota, but there's work left to
- * do. Return and (re-)schedule the send worker.
- */
- ret = -EAGAIN;
+ /* Nuke any messages we decided not to retransmit. */
+ if (!list_empty(&to_be_dropped)) {
+ /* irqs on here, so we can put(), unlike above */
+ list_for_each_entry(rm, &to_be_dropped, m_conn_item)
+ rds_message_put(rm);
+ rds_send_remove_from_sock(&to_be_dropped, RDS_RDMA_DROPPED);
}
- if (ret == 0 && was_empty) {
- /* A simple bit test would be way faster than taking the
- * spin lock */
- spin_lock_irqsave(&conn->c_lock, flags);
+ /*
+ * Other senders can queue a message after we last test the send queue
+ * but before we clear RDS_IN_XMIT. In that case they'd back off and
+ * not try and send their newly queued message. We need to check the
+ * send queue after having cleared RDS_IN_XMIT so that their message
+ * doesn't get stuck on the send queue.
+ *
+ * If the transport cannot continue (i.e ret != 0), then it must
+ * call us when more room is available, such as from the tx
+ * completion handler.
+ */
+ if (ret == 0) {
+ smp_mb();
if (!list_empty(&conn->c_send_queue)) {
- rds_stats_inc(s_send_sem_queue_raced);
- ret = -EAGAIN;
+ rds_stats_inc(s_send_lock_queue_raced);
+ goto restart;
}
- spin_unlock_irqrestore(&conn->c_lock, flags);
}
out:
return ret;
@@ -376,52 +411,60 @@ static inline int rds_send_is_acked(struct rds_message *rm, u64 ack,
}
/*
- * Returns true if there are no messages on the send and retransmit queues
- * which have a sequence number greater than or equal to the given sequence
- * number.
+ * This is pretty similar to what happens below in the ACK
+ * handling code - except that we call here as soon as we get
+ * the IB send completion on the RDMA op and the accompanying
+ * message.
*/
-int rds_send_acked_before(struct rds_connection *conn, u64 seq)
+void rds_rdma_send_complete(struct rds_message *rm, int status)
{
- struct rds_message *rm, *tmp;
- int ret = 1;
+ struct rds_sock *rs = NULL;
+ struct rm_rdma_op *ro;
+ struct rds_notifier *notifier;
+ unsigned long flags;
- spin_lock(&conn->c_lock);
+ spin_lock_irqsave(&rm->m_rs_lock, flags);
- list_for_each_entry_safe(rm, tmp, &conn->c_retrans, m_conn_item) {
- if (be64_to_cpu(rm->m_inc.i_hdr.h_sequence) < seq)
- ret = 0;
- break;
- }
+ ro = &rm->rdma;
+ if (test_bit(RDS_MSG_ON_SOCK, &rm->m_flags) &&
+ ro->op_active && ro->op_notify && ro->op_notifier) {
+ notifier = ro->op_notifier;
+ rs = rm->m_rs;
+ sock_hold(rds_rs_to_sk(rs));
- list_for_each_entry_safe(rm, tmp, &conn->c_send_queue, m_conn_item) {
- if (be64_to_cpu(rm->m_inc.i_hdr.h_sequence) < seq)
- ret = 0;
- break;
+ notifier->n_status = status;
+ spin_lock(&rs->rs_lock);
+ list_add_tail(&notifier->n_list, &rs->rs_notify_queue);
+ spin_unlock(&rs->rs_lock);
+
+ ro->op_notifier = NULL;
}
- spin_unlock(&conn->c_lock);
+ spin_unlock_irqrestore(&rm->m_rs_lock, flags);
- return ret;
+ if (rs) {
+ rds_wake_sk_sleep(rs);
+ sock_put(rds_rs_to_sk(rs));
+ }
}
+EXPORT_SYMBOL_GPL(rds_rdma_send_complete);
/*
- * This is pretty similar to what happens below in the ACK
- * handling code - except that we call here as soon as we get
- * the IB send completion on the RDMA op and the accompanying
- * message.
+ * Just like above, except looks at atomic op
*/
-void rds_rdma_send_complete(struct rds_message *rm, int status)
+void rds_atomic_send_complete(struct rds_message *rm, int status)
{
struct rds_sock *rs = NULL;
- struct rds_rdma_op *ro;
+ struct rm_atomic_op *ao;
struct rds_notifier *notifier;
+ unsigned long flags;
- spin_lock(&rm->m_rs_lock);
+ spin_lock_irqsave(&rm->m_rs_lock, flags);
- ro = rm->m_rdma_op;
- if (test_bit(RDS_MSG_ON_SOCK, &rm->m_flags) &&
- ro && ro->r_notify && ro->r_notifier) {
- notifier = ro->r_notifier;
+ ao = &rm->atomic;
+ if (test_bit(RDS_MSG_ON_SOCK, &rm->m_flags)
+ && ao->op_active && ao->op_notify && ao->op_notifier) {
+ notifier = ao->op_notifier;
rs = rm->m_rs;
sock_hold(rds_rs_to_sk(rs));
@@ -430,17 +473,17 @@ void rds_rdma_send_complete(struct rds_message *rm, int status)
list_add_tail(&notifier->n_list, &rs->rs_notify_queue);
spin_unlock(&rs->rs_lock);
- ro->r_notifier = NULL;
+ ao->op_notifier = NULL;
}
- spin_unlock(&rm->m_rs_lock);
+ spin_unlock_irqrestore(&rm->m_rs_lock, flags);
if (rs) {
rds_wake_sk_sleep(rs);
sock_put(rds_rs_to_sk(rs));
}
}
-EXPORT_SYMBOL_GPL(rds_rdma_send_complete);
+EXPORT_SYMBOL_GPL(rds_atomic_send_complete);
/*
* This is the same as rds_rdma_send_complete except we
@@ -448,15 +491,23 @@ EXPORT_SYMBOL_GPL(rds_rdma_send_complete);
* socket, socket lock) and can just move the notifier.
*/
static inline void
-__rds_rdma_send_complete(struct rds_sock *rs, struct rds_message *rm, int status)
+__rds_send_complete(struct rds_sock *rs, struct rds_message *rm, int status)
{
- struct rds_rdma_op *ro;
+ struct rm_rdma_op *ro;
+ struct rm_atomic_op *ao;
+
+ ro = &rm->rdma;
+ if (ro->op_active && ro->op_notify && ro->op_notifier) {
+ ro->op_notifier->n_status = status;
+ list_add_tail(&ro->op_notifier->n_list, &rs->rs_notify_queue);
+ ro->op_notifier = NULL;
+ }
- ro = rm->m_rdma_op;
- if (ro && ro->r_notify && ro->r_notifier) {
- ro->r_notifier->n_status = status;
- list_add_tail(&ro->r_notifier->n_list, &rs->rs_notify_queue);
- ro->r_notifier = NULL;
+ ao = &rm->atomic;
+ if (ao->op_active && ao->op_notify && ao->op_notifier) {
+ ao->op_notifier->n_status = status;
+ list_add_tail(&ao->op_notifier->n_list, &rs->rs_notify_queue);
+ ao->op_notifier = NULL;
}
/* No need to wake the app - caller does this */
@@ -468,7 +519,7 @@ __rds_rdma_send_complete(struct rds_sock *rs, struct rds_message *rm, int status
* So speed is not an issue here.
*/
struct rds_message *rds_send_get_message(struct rds_connection *conn,
- struct rds_rdma_op *op)
+ struct rm_rdma_op *op)
{
struct rds_message *rm, *tmp, *found = NULL;
unsigned long flags;
@@ -476,7 +527,7 @@ struct rds_message *rds_send_get_message(struct rds_connection *conn,
spin_lock_irqsave(&conn->c_lock, flags);
list_for_each_entry_safe(rm, tmp, &conn->c_retrans, m_conn_item) {
- if (rm->m_rdma_op == op) {
+ if (&rm->rdma == op) {
atomic_inc(&rm->m_refcount);
found = rm;
goto out;
@@ -484,7 +535,7 @@ struct rds_message *rds_send_get_message(struct rds_connection *conn,
}
list_for_each_entry_safe(rm, tmp, &conn->c_send_queue, m_conn_item) {
- if (rm->m_rdma_op == op) {
+ if (&rm->rdma == op) {
atomic_inc(&rm->m_refcount);
found = rm;
break;
@@ -506,7 +557,7 @@ EXPORT_SYMBOL_GPL(rds_send_get_message);
* removing the messages from the 'messages' list regardless of if it found
* the messages on the socket list or not.
*/
-void rds_send_remove_from_sock(struct list_head *messages, int status)
+static void rds_send_remove_from_sock(struct list_head *messages, int status)
{
unsigned long flags;
struct rds_sock *rs = NULL;
@@ -544,19 +595,20 @@ void rds_send_remove_from_sock(struct list_head *messages, int status)
spin_lock(&rs->rs_lock);
if (test_and_clear_bit(RDS_MSG_ON_SOCK, &rm->m_flags)) {
- struct rds_rdma_op *ro = rm->m_rdma_op;
+ struct rm_rdma_op *ro = &rm->rdma;
struct rds_notifier *notifier;
list_del_init(&rm->m_sock_item);
rds_send_sndbuf_remove(rs, rm);
- if (ro && ro->r_notifier && (status || ro->r_notify)) {
- notifier = ro->r_notifier;
+ if (ro->op_active && ro->op_notifier &&
+ (ro->op_notify || (ro->op_recverr && status))) {
+ notifier = ro->op_notifier;
list_add_tail(&notifier->n_list,
&rs->rs_notify_queue);
if (!notifier->n_status)
notifier->n_status = status;
- rm->m_rdma_op->r_notifier = NULL;
+ rm->rdma.op_notifier = NULL;
}
was_on_sock = 1;
rm->m_rs = NULL;
@@ -619,9 +671,8 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest)
{
struct rds_message *rm, *tmp;
struct rds_connection *conn;
- unsigned long flags, flags2;
+ unsigned long flags;
LIST_HEAD(list);
- int wake = 0;
/* get all the messages we're dropping under the rs lock */
spin_lock_irqsave(&rs->rs_lock, flags);
@@ -631,59 +682,54 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest)
dest->sin_port != rm->m_inc.i_hdr.h_dport))
continue;
- wake = 1;
list_move(&rm->m_sock_item, &list);
rds_send_sndbuf_remove(rs, rm);
clear_bit(RDS_MSG_ON_SOCK, &rm->m_flags);
}
/* order flag updates with the rs lock */
- if (wake)
- smp_mb__after_clear_bit();
+ smp_mb__after_clear_bit();
spin_unlock_irqrestore(&rs->rs_lock, flags);
- conn = NULL;
+ if (list_empty(&list))
+ return;
- /* now remove the messages from the conn list as needed */
+ /* Remove the messages from the conn */
list_for_each_entry(rm, &list, m_sock_item) {
- /* We do this here rather than in the loop above, so that
- * we don't have to nest m_rs_lock under rs->rs_lock */
- spin_lock_irqsave(&rm->m_rs_lock, flags2);
- /* If this is a RDMA operation, notify the app. */
- spin_lock(&rs->rs_lock);
- __rds_rdma_send_complete(rs, rm, RDS_RDMA_CANCELED);
- spin_unlock(&rs->rs_lock);
- rm->m_rs = NULL;
- spin_unlock_irqrestore(&rm->m_rs_lock, flags2);
+ conn = rm->m_inc.i_conn;
+
+ spin_lock_irqsave(&conn->c_lock, flags);
/*
- * If we see this flag cleared then we're *sure* that someone
- * else beat us to removing it from the conn. If we race
- * with their flag update we'll get the lock and then really
- * see that the flag has been cleared.
+ * Maybe someone else beat us to removing rm from the conn.
+ * If we race with their flag update we'll get the lock and
+ * then really see that the flag has been cleared.
*/
- if (!test_bit(RDS_MSG_ON_CONN, &rm->m_flags))
+ if (!test_and_clear_bit(RDS_MSG_ON_CONN, &rm->m_flags)) {
+ spin_unlock_irqrestore(&conn->c_lock, flags);
continue;
-
- if (conn != rm->m_inc.i_conn) {
- if (conn)
- spin_unlock_irqrestore(&conn->c_lock, flags);
- conn = rm->m_inc.i_conn;
- spin_lock_irqsave(&conn->c_lock, flags);
}
+ list_del_init(&rm->m_conn_item);
+ spin_unlock_irqrestore(&conn->c_lock, flags);
- if (test_and_clear_bit(RDS_MSG_ON_CONN, &rm->m_flags)) {
- list_del_init(&rm->m_conn_item);
- rds_message_put(rm);
- }
- }
+ /*
+ * Couldn't grab m_rs_lock in top loop (lock ordering),
+ * but we can now.
+ */
+ spin_lock_irqsave(&rm->m_rs_lock, flags);
- if (conn)
- spin_unlock_irqrestore(&conn->c_lock, flags);
+ spin_lock(&rs->rs_lock);
+ __rds_send_complete(rs, rm, RDS_RDMA_CANCELED);
+ spin_unlock(&rs->rs_lock);
- if (wake)
- rds_wake_sk_sleep(rs);
+ rm->m_rs = NULL;
+ spin_unlock_irqrestore(&rm->m_rs_lock, flags);
+
+ rds_message_put(rm);
+ }
+
+ rds_wake_sk_sleep(rs);
while (!list_empty(&list)) {
rm = list_entry(list.next, struct rds_message, m_sock_item);
@@ -763,6 +809,63 @@ out:
return *queued;
}
+/*
+ * rds_message is getting to be quite complicated, and we'd like to allocate
+ * it all in one go. This figures out how big it needs to be up front.
+ */
+static int rds_rm_size(struct msghdr *msg, int data_len)
+{
+ struct cmsghdr *cmsg;
+ int size = 0;
+ int cmsg_groups = 0;
+ int retval;
+
+ for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+ if (!CMSG_OK(msg, cmsg))
+ return -EINVAL;
+
+ if (cmsg->cmsg_level != SOL_RDS)
+ continue;
+
+ switch (cmsg->cmsg_type) {
+ case RDS_CMSG_RDMA_ARGS:
+ cmsg_groups |= 1;
+ retval = rds_rdma_extra_size(CMSG_DATA(cmsg));
+ if (retval < 0)
+ return retval;
+ size += retval;
+
+ break;
+
+ case RDS_CMSG_RDMA_DEST:
+ case RDS_CMSG_RDMA_MAP:
+ cmsg_groups |= 2;
+ /* these are valid but do no add any size */
+ break;
+
+ case RDS_CMSG_ATOMIC_CSWP:
+ case RDS_CMSG_ATOMIC_FADD:
+ case RDS_CMSG_MASKED_ATOMIC_CSWP:
+ case RDS_CMSG_MASKED_ATOMIC_FADD:
+ cmsg_groups |= 1;
+ size += sizeof(struct scatterlist);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ }
+
+ size += ceil(data_len, PAGE_SIZE) * sizeof(struct scatterlist);
+
+ /* Ensure (DEST, MAP) are never used with (ARGS, ATOMIC) */
+ if (cmsg_groups == 3)
+ return -EINVAL;
+
+ return size;
+}
+
static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm,
struct msghdr *msg, int *allocated_mr)
{
@@ -777,7 +880,7 @@ static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm,
continue;
/* As a side effect, RDMA_DEST and RDMA_MAP will set
- * rm->m_rdma_cookie and rm->m_rdma_mr.
+ * rm->rdma.m_rdma_cookie and rm->rdma.m_rdma_mr.
*/
switch (cmsg->cmsg_type) {
case RDS_CMSG_RDMA_ARGS:
@@ -793,6 +896,12 @@ static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm,
if (!ret)
*allocated_mr = 1;
break;
+ case RDS_CMSG_ATOMIC_CSWP:
+ case RDS_CMSG_ATOMIC_FADD:
+ case RDS_CMSG_MASKED_ATOMIC_CSWP:
+ case RDS_CMSG_MASKED_ATOMIC_FADD:
+ ret = rds_cmsg_atomic(rs, rm, cmsg);
+ break;
default:
return -EINVAL;
@@ -850,13 +959,26 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
goto out;
}
- rm = rds_message_copy_from_user(msg->msg_iov, payload_len);
- if (IS_ERR(rm)) {
- ret = PTR_ERR(rm);
- rm = NULL;
+ /* size of rm including all sgs */
+ ret = rds_rm_size(msg, payload_len);
+ if (ret < 0)
+ goto out;
+
+ rm = rds_message_alloc(ret, GFP_KERNEL);
+ if (!rm) {
+ ret = -ENOMEM;
goto out;
}
+ /* Attach data to the rm */
+ if (payload_len) {
+ rm->data.op_sg = rds_message_alloc_sgs(rm, ceil(payload_len, PAGE_SIZE));
+ ret = rds_message_copy_from_user(rm, msg->msg_iov, payload_len);
+ if (ret)
+ goto out;
+ }
+ rm->data.op_active = 1;
+
rm->m_daddr = daddr;
/* rds_conn_create has a spinlock that runs with IRQ off.
@@ -879,22 +1001,23 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
if (ret)
goto out;
- if ((rm->m_rdma_cookie || rm->m_rdma_op) &&
- conn->c_trans->xmit_rdma == NULL) {
+ if (rm->rdma.op_active && !conn->c_trans->xmit_rdma) {
if (printk_ratelimit())
printk(KERN_NOTICE "rdma_op %p conn xmit_rdma %p\n",
- rm->m_rdma_op, conn->c_trans->xmit_rdma);
+ &rm->rdma, conn->c_trans->xmit_rdma);
ret = -EOPNOTSUPP;
goto out;
}
- /* If the connection is down, trigger a connect. We may
- * have scheduled a delayed reconnect however - in this case
- * we should not interfere.
- */
- if (rds_conn_state(conn) == RDS_CONN_DOWN &&
- !test_and_set_bit(RDS_RECONNECT_PENDING, &conn->c_flags))
- queue_delayed_work(rds_wq, &conn->c_conn_w, 0);
+ if (rm->atomic.op_active && !conn->c_trans->xmit_atomic) {
+ if (printk_ratelimit())
+ printk(KERN_NOTICE "atomic_op %p conn xmit_atomic %p\n",
+ &rm->atomic, conn->c_trans->xmit_atomic);
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rds_conn_connect_if_down(conn);
ret = rds_cong_wait(conn->c_fcong, dport, nonblock, rs);
if (ret) {
@@ -938,7 +1061,7 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
rds_stats_inc(s_send_queued);
if (!test_bit(RDS_LL_SEND_FULL, &conn->c_flags))
- rds_send_worker(&conn->c_send_w.work);
+ rds_send_xmit(conn);
rds_message_put(rm);
return payload_len;
@@ -966,20 +1089,15 @@ rds_send_pong(struct rds_connection *conn, __be16 dport)
int ret = 0;
rm = rds_message_alloc(0, GFP_ATOMIC);
- if (rm == NULL) {
+ if (!rm) {
ret = -ENOMEM;
goto out;
}
rm->m_daddr = conn->c_faddr;
+ rm->data.op_active = 1;
- /* If the connection is down, trigger a connect. We may
- * have scheduled a delayed reconnect however - in this case
- * we should not interfere.
- */
- if (rds_conn_state(conn) == RDS_CONN_DOWN &&
- !test_and_set_bit(RDS_RECONNECT_PENDING, &conn->c_flags))
- queue_delayed_work(rds_wq, &conn->c_conn_w, 0);
+ rds_conn_connect_if_down(conn);
ret = rds_cong_wait(conn->c_fcong, dport, 1, NULL);
if (ret)
@@ -999,7 +1117,9 @@ rds_send_pong(struct rds_connection *conn, __be16 dport)
rds_stats_inc(s_send_queued);
rds_stats_inc(s_send_pong);
- queue_delayed_work(rds_wq, &conn->c_send_w, 0);
+ if (!test_bit(RDS_LL_SEND_FULL, &conn->c_flags))
+ rds_send_xmit(conn);
+
rds_message_put(rm);
return 0;
diff --git a/net/rds/stats.c b/net/rds/stats.c
index 7598eb07cfb1..10c759ccac0c 100644
--- a/net/rds/stats.c
+++ b/net/rds/stats.c
@@ -57,8 +57,8 @@ static const char *const rds_stat_names[] = {
"recv_ping",
"send_queue_empty",
"send_queue_full",
- "send_sem_contention",
- "send_sem_queue_raced",
+ "send_lock_contention",
+ "send_lock_queue_raced",
"send_immediate_retry",
"send_delayed_retry",
"send_drop_acked",
@@ -143,7 +143,7 @@ void rds_stats_exit(void)
rds_info_deregister_func(RDS_INFO_COUNTERS, rds_stats_info);
}
-int __init rds_stats_init(void)
+int rds_stats_init(void)
{
rds_info_register_func(RDS_INFO_COUNTERS, rds_stats_info);
return 0;
diff --git a/net/rds/sysctl.c b/net/rds/sysctl.c
index 7829a20325d3..25ad0c77a26c 100644
--- a/net/rds/sysctl.c
+++ b/net/rds/sysctl.c
@@ -105,13 +105,13 @@ void rds_sysctl_exit(void)
unregister_sysctl_table(rds_sysctl_reg_table);
}
-int __init rds_sysctl_init(void)
+int rds_sysctl_init(void)
{
rds_sysctl_reconnect_min = msecs_to_jiffies(1);
rds_sysctl_reconnect_min_jiffies = rds_sysctl_reconnect_min;
rds_sysctl_reg_table = register_sysctl_paths(rds_sysctl_path, rds_sysctl_rds_table);
- if (rds_sysctl_reg_table == NULL)
+ if (!rds_sysctl_reg_table)
return -ENOMEM;
return 0;
}
diff --git a/net/rds/tcp.c b/net/rds/tcp.c
index babf4577ff7d..08a8c6cf2d10 100644
--- a/net/rds/tcp.c
+++ b/net/rds/tcp.c
@@ -41,7 +41,7 @@
/* only for info exporting */
static DEFINE_SPINLOCK(rds_tcp_tc_list_lock);
static LIST_HEAD(rds_tcp_tc_list);
-unsigned int rds_tcp_tc_count;
+static unsigned int rds_tcp_tc_count;
/* Track rds_tcp_connection structs so they can be cleaned up */
static DEFINE_SPINLOCK(rds_tcp_conn_lock);
@@ -200,7 +200,7 @@ static int rds_tcp_conn_alloc(struct rds_connection *conn, gfp_t gfp)
struct rds_tcp_connection *tc;
tc = kmem_cache_alloc(rds_tcp_conn_slab, gfp);
- if (tc == NULL)
+ if (!tc)
return -ENOMEM;
tc->t_sock = NULL;
@@ -243,7 +243,7 @@ static void rds_tcp_destroy_conns(void)
}
}
-void rds_tcp_exit(void)
+static void rds_tcp_exit(void)
{
rds_info_deregister_func(RDS_INFO_TCP_SOCKETS, rds_tcp_tc_info);
rds_tcp_listen_stop();
@@ -258,7 +258,6 @@ struct rds_transport rds_tcp_transport = {
.laddr_check = rds_tcp_laddr_check,
.xmit_prepare = rds_tcp_xmit_prepare,
.xmit_complete = rds_tcp_xmit_complete,
- .xmit_cong_map = rds_tcp_xmit_cong_map,
.xmit = rds_tcp_xmit,
.recv = rds_tcp_recv,
.conn_alloc = rds_tcp_conn_alloc,
@@ -266,7 +265,6 @@ struct rds_transport rds_tcp_transport = {
.conn_connect = rds_tcp_conn_connect,
.conn_shutdown = rds_tcp_conn_shutdown,
.inc_copy_to_user = rds_tcp_inc_copy_to_user,
- .inc_purge = rds_tcp_inc_purge,
.inc_free = rds_tcp_inc_free,
.stats_info_copy = rds_tcp_stats_info_copy,
.exit = rds_tcp_exit,
@@ -276,14 +274,14 @@ struct rds_transport rds_tcp_transport = {
.t_prefer_loopback = 1,
};
-int __init rds_tcp_init(void)
+static int rds_tcp_init(void)
{
int ret;
rds_tcp_conn_slab = kmem_cache_create("rds_tcp_connection",
sizeof(struct rds_tcp_connection),
0, 0, NULL);
- if (rds_tcp_conn_slab == NULL) {
+ if (!rds_tcp_conn_slab) {
ret = -ENOMEM;
goto out;
}
diff --git a/net/rds/tcp.h b/net/rds/tcp.h
index 844fa6b9cf5a..9cf2927d0021 100644
--- a/net/rds/tcp.h
+++ b/net/rds/tcp.h
@@ -43,8 +43,6 @@ struct rds_tcp_statistics {
};
/* tcp.c */
-int __init rds_tcp_init(void);
-void rds_tcp_exit(void);
void rds_tcp_tune(struct socket *sock);
void rds_tcp_nonagle(struct socket *sock);
void rds_tcp_set_callbacks(struct socket *sock, struct rds_connection *conn);
@@ -61,16 +59,15 @@ void rds_tcp_conn_shutdown(struct rds_connection *conn);
void rds_tcp_state_change(struct sock *sk);
/* tcp_listen.c */
-int __init rds_tcp_listen_init(void);
+int rds_tcp_listen_init(void);
void rds_tcp_listen_stop(void);
void rds_tcp_listen_data_ready(struct sock *sk, int bytes);
/* tcp_recv.c */
-int __init rds_tcp_recv_init(void);
+int rds_tcp_recv_init(void);
void rds_tcp_recv_exit(void);
void rds_tcp_data_ready(struct sock *sk, int bytes);
int rds_tcp_recv(struct rds_connection *conn);
-void rds_tcp_inc_purge(struct rds_incoming *inc);
void rds_tcp_inc_free(struct rds_incoming *inc);
int rds_tcp_inc_copy_to_user(struct rds_incoming *inc, struct iovec *iov,
size_t size);
@@ -81,8 +78,6 @@ void rds_tcp_xmit_complete(struct rds_connection *conn);
int rds_tcp_xmit(struct rds_connection *conn, struct rds_message *rm,
unsigned int hdr_off, unsigned int sg, unsigned int off);
void rds_tcp_write_space(struct sock *sk);
-int rds_tcp_xmit_cong_map(struct rds_connection *conn,
- struct rds_cong_map *map, unsigned long offset);
/* tcp_stats.c */
DECLARE_PER_CPU(struct rds_tcp_statistics, rds_tcp_stats);
diff --git a/net/rds/tcp_connect.c b/net/rds/tcp_connect.c
index c519939e8da9..af95c8e058fc 100644
--- a/net/rds/tcp_connect.c
+++ b/net/rds/tcp_connect.c
@@ -45,7 +45,7 @@ void rds_tcp_state_change(struct sock *sk)
read_lock_bh(&sk->sk_callback_lock);
conn = sk->sk_user_data;
- if (conn == NULL) {
+ if (!conn) {
state_change = sk->sk_state_change;
goto out;
}
diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c
index 27844f231d10..8b5cc4aa8868 100644
--- a/net/rds/tcp_listen.c
+++ b/net/rds/tcp_listen.c
@@ -116,7 +116,7 @@ void rds_tcp_listen_data_ready(struct sock *sk, int bytes)
read_lock_bh(&sk->sk_callback_lock);
ready = sk->sk_user_data;
- if (ready == NULL) { /* check for teardown race */
+ if (!ready) { /* check for teardown race */
ready = sk->sk_data_ready;
goto out;
}
@@ -135,7 +135,7 @@ out:
ready(sk, bytes);
}
-int __init rds_tcp_listen_init(void)
+int rds_tcp_listen_init(void)
{
struct sockaddr_in sin;
struct socket *sock = NULL;
@@ -178,7 +178,7 @@ void rds_tcp_listen_stop(void)
struct socket *sock = rds_tcp_listen_sock;
struct sock *sk;
- if (sock == NULL)
+ if (!sock)
return;
sk = sock->sk;
diff --git a/net/rds/tcp_recv.c b/net/rds/tcp_recv.c
index e43797404102..78205e25500a 100644
--- a/net/rds/tcp_recv.c
+++ b/net/rds/tcp_recv.c
@@ -39,7 +39,7 @@
static struct kmem_cache *rds_tcp_incoming_slab;
-void rds_tcp_inc_purge(struct rds_incoming *inc)
+static void rds_tcp_inc_purge(struct rds_incoming *inc)
{
struct rds_tcp_incoming *tinc;
tinc = container_of(inc, struct rds_tcp_incoming, ti_inc);
@@ -190,10 +190,10 @@ static int rds_tcp_data_recv(read_descriptor_t *desc, struct sk_buff *skb,
* processing.
*/
while (left) {
- if (tinc == NULL) {
+ if (!tinc) {
tinc = kmem_cache_alloc(rds_tcp_incoming_slab,
arg->gfp);
- if (tinc == NULL) {
+ if (!tinc) {
desc->error = -ENOMEM;
goto out;
}
@@ -229,7 +229,7 @@ static int rds_tcp_data_recv(read_descriptor_t *desc, struct sk_buff *skb,
if (left && tc->t_tinc_data_rem) {
clone = skb_clone(skb, arg->gfp);
- if (clone == NULL) {
+ if (!clone) {
desc->error = -ENOMEM;
goto out;
}
@@ -272,7 +272,8 @@ out:
}
/* the caller has to hold the sock lock */
-int rds_tcp_read_sock(struct rds_connection *conn, gfp_t gfp, enum km_type km)
+static int rds_tcp_read_sock(struct rds_connection *conn, gfp_t gfp,
+ enum km_type km)
{
struct rds_tcp_connection *tc = conn->c_transport_data;
struct socket *sock = tc->t_sock;
@@ -326,7 +327,7 @@ void rds_tcp_data_ready(struct sock *sk, int bytes)
read_lock_bh(&sk->sk_callback_lock);
conn = sk->sk_user_data;
- if (conn == NULL) { /* check for teardown race */
+ if (!conn) { /* check for teardown race */
ready = sk->sk_data_ready;
goto out;
}
@@ -342,12 +343,12 @@ out:
ready(sk, bytes);
}
-int __init rds_tcp_recv_init(void)
+int rds_tcp_recv_init(void)
{
rds_tcp_incoming_slab = kmem_cache_create("rds_tcp_incoming",
sizeof(struct rds_tcp_incoming),
0, 0, NULL);
- if (rds_tcp_incoming_slab == NULL)
+ if (!rds_tcp_incoming_slab)
return -ENOMEM;
return 0;
}
diff --git a/net/rds/tcp_send.c b/net/rds/tcp_send.c
index 2f012a07d94d..1b4fd68f0c7c 100644
--- a/net/rds/tcp_send.c
+++ b/net/rds/tcp_send.c
@@ -63,7 +63,7 @@ void rds_tcp_xmit_complete(struct rds_connection *conn)
}
/* the core send_sem serializes this with other xmit and shutdown */
-int rds_tcp_sendmsg(struct socket *sock, void *data, unsigned int len)
+static int rds_tcp_sendmsg(struct socket *sock, void *data, unsigned int len)
{
struct kvec vec = {
.iov_base = data,
@@ -77,56 +77,6 @@ int rds_tcp_sendmsg(struct socket *sock, void *data, unsigned int len)
}
/* the core send_sem serializes this with other xmit and shutdown */
-int rds_tcp_xmit_cong_map(struct rds_connection *conn,
- struct rds_cong_map *map, unsigned long offset)
-{
- static struct rds_header rds_tcp_map_header = {
- .h_flags = RDS_FLAG_CONG_BITMAP,
- };
- struct rds_tcp_connection *tc = conn->c_transport_data;
- unsigned long i;
- int ret;
- int copied = 0;
-
- /* Some problem claims cpu_to_be32(constant) isn't a constant. */
- rds_tcp_map_header.h_len = cpu_to_be32(RDS_CONG_MAP_BYTES);
-
- if (offset < sizeof(struct rds_header)) {
- ret = rds_tcp_sendmsg(tc->t_sock,
- (void *)&rds_tcp_map_header + offset,
- sizeof(struct rds_header) - offset);
- if (ret <= 0)
- return ret;
- offset += ret;
- copied = ret;
- if (offset < sizeof(struct rds_header))
- return ret;
- }
-
- offset -= sizeof(struct rds_header);
- i = offset / PAGE_SIZE;
- offset = offset % PAGE_SIZE;
- BUG_ON(i >= RDS_CONG_MAP_PAGES);
-
- do {
- ret = tc->t_sock->ops->sendpage(tc->t_sock,
- virt_to_page(map->m_page_addrs[i]),
- offset, PAGE_SIZE - offset,
- MSG_DONTWAIT);
- if (ret <= 0)
- break;
- copied += ret;
- offset += ret;
- if (offset == PAGE_SIZE) {
- offset = 0;
- i++;
- }
- } while (i < RDS_CONG_MAP_PAGES);
-
- return copied ? copied : ret;
-}
-
-/* the core send_sem serializes this with other xmit and shutdown */
int rds_tcp_xmit(struct rds_connection *conn, struct rds_message *rm,
unsigned int hdr_off, unsigned int sg, unsigned int off)
{
@@ -166,21 +116,21 @@ int rds_tcp_xmit(struct rds_connection *conn, struct rds_message *rm,
goto out;
}
- while (sg < rm->m_nents) {
+ while (sg < rm->data.op_nents) {
ret = tc->t_sock->ops->sendpage(tc->t_sock,
- sg_page(&rm->m_sg[sg]),
- rm->m_sg[sg].offset + off,
- rm->m_sg[sg].length - off,
+ sg_page(&rm->data.op_sg[sg]),
+ rm->data.op_sg[sg].offset + off,
+ rm->data.op_sg[sg].length - off,
MSG_DONTWAIT|MSG_NOSIGNAL);
- rdsdebug("tcp sendpage %p:%u:%u ret %d\n", (void *)sg_page(&rm->m_sg[sg]),
- rm->m_sg[sg].offset + off, rm->m_sg[sg].length - off,
+ rdsdebug("tcp sendpage %p:%u:%u ret %d\n", (void *)sg_page(&rm->data.op_sg[sg]),
+ rm->data.op_sg[sg].offset + off, rm->data.op_sg[sg].length - off,
ret);
if (ret <= 0)
break;
off += ret;
done += ret;
- if (off == rm->m_sg[sg].length) {
+ if (off == rm->data.op_sg[sg].length) {
off = 0;
sg++;
}
@@ -226,7 +176,7 @@ void rds_tcp_write_space(struct sock *sk)
read_lock_bh(&sk->sk_callback_lock);
conn = sk->sk_user_data;
- if (conn == NULL) {
+ if (!conn) {
write_space = sk->sk_write_space;
goto out;
}
diff --git a/net/rds/threads.c b/net/rds/threads.c
index 786c20eaaf5e..0fd90f8c5f59 100644
--- a/net/rds/threads.c
+++ b/net/rds/threads.c
@@ -61,7 +61,7 @@
*
* Transition to state DISCONNECTING/DOWN:
* - Inside the shutdown worker; synchronizes with xmit path
- * through c_send_lock, and with connection management callbacks
+ * through RDS_IN_XMIT, and with connection management callbacks
* via c_cm_lock.
*
* For receive callbacks, we rely on the underlying transport
@@ -110,7 +110,7 @@ EXPORT_SYMBOL_GPL(rds_connect_complete);
* We should *always* start with a random backoff; otherwise a broken connection
* will always take several iterations to be re-established.
*/
-static void rds_queue_reconnect(struct rds_connection *conn)
+void rds_queue_reconnect(struct rds_connection *conn)
{
unsigned long rand;
@@ -156,58 +156,6 @@ void rds_connect_worker(struct work_struct *work)
}
}
-void rds_shutdown_worker(struct work_struct *work)
-{
- struct rds_connection *conn = container_of(work, struct rds_connection, c_down_w);
-
- /* shut it down unless it's down already */
- if (!rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_DOWN)) {
- /*
- * Quiesce the connection mgmt handlers before we start tearing
- * things down. We don't hold the mutex for the entire
- * duration of the shutdown operation, else we may be
- * deadlocking with the CM handler. Instead, the CM event
- * handler is supposed to check for state DISCONNECTING
- */
- mutex_lock(&conn->c_cm_lock);
- if (!rds_conn_transition(conn, RDS_CONN_UP, RDS_CONN_DISCONNECTING) &&
- !rds_conn_transition(conn, RDS_CONN_ERROR, RDS_CONN_DISCONNECTING)) {
- rds_conn_error(conn, "shutdown called in state %d\n",
- atomic_read(&conn->c_state));
- mutex_unlock(&conn->c_cm_lock);
- return;
- }
- mutex_unlock(&conn->c_cm_lock);
-
- mutex_lock(&conn->c_send_lock);
- conn->c_trans->conn_shutdown(conn);
- rds_conn_reset(conn);
- mutex_unlock(&conn->c_send_lock);
-
- if (!rds_conn_transition(conn, RDS_CONN_DISCONNECTING, RDS_CONN_DOWN)) {
- /* This can happen - eg when we're in the middle of tearing
- * down the connection, and someone unloads the rds module.
- * Quite reproduceable with loopback connections.
- * Mostly harmless.
- */
- rds_conn_error(conn,
- "%s: failed to transition to state DOWN, "
- "current state is %d\n",
- __func__,
- atomic_read(&conn->c_state));
- return;
- }
- }
-
- /* Then reconnect if it's still live.
- * The passive side of an IB loopback connection is never added
- * to the conn hash, so we never trigger a reconnect on this
- * conn - the reconnect is always triggered by the active peer. */
- cancel_delayed_work(&conn->c_conn_w);
- if (!hlist_unhashed(&conn->c_hash_node))
- rds_queue_reconnect(conn);
-}
-
void rds_send_worker(struct work_struct *work)
{
struct rds_connection *conn = container_of(work, struct rds_connection, c_send_w.work);
@@ -252,15 +200,22 @@ void rds_recv_worker(struct work_struct *work)
}
}
+void rds_shutdown_worker(struct work_struct *work)
+{
+ struct rds_connection *conn = container_of(work, struct rds_connection, c_down_w);
+
+ rds_conn_shutdown(conn);
+}
+
void rds_threads_exit(void)
{
destroy_workqueue(rds_wq);
}
-int __init rds_threads_init(void)
+int rds_threads_init(void)
{
- rds_wq = create_workqueue("krdsd");
- if (rds_wq == NULL)
+ rds_wq = create_singlethread_workqueue("krdsd");
+ if (!rds_wq)
return -ENOMEM;
return 0;
diff --git a/net/rds/transport.c b/net/rds/transport.c
index 7e1067901353..7f2ac4fec367 100644
--- a/net/rds/transport.c
+++ b/net/rds/transport.c
@@ -71,19 +71,28 @@ void rds_trans_unregister(struct rds_transport *trans)
}
EXPORT_SYMBOL_GPL(rds_trans_unregister);
+void rds_trans_put(struct rds_transport *trans)
+{
+ if (trans && trans->t_owner)
+ module_put(trans->t_owner);
+}
+
struct rds_transport *rds_trans_get_preferred(__be32 addr)
{
struct rds_transport *ret = NULL;
- int i;
+ struct rds_transport *trans;
+ unsigned int i;
if (IN_LOOPBACK(ntohl(addr)))
return &rds_loop_transport;
down_read(&rds_trans_sem);
- for (i = 0; i < RDS_TRANS_COUNT; i++)
- {
- if (transports[i] && (transports[i]->laddr_check(addr) == 0)) {
- ret = transports[i];
+ for (i = 0; i < RDS_TRANS_COUNT; i++) {
+ trans = transports[i];
+
+ if (trans && (trans->laddr_check(addr) == 0) &&
+ (!trans->t_owner || try_module_get(trans->t_owner))) {
+ ret = trans;
break;
}
}
diff --git a/net/rds/xlist.h b/net/rds/xlist.h
new file mode 100644
index 000000000000..e6b5190daddd
--- /dev/null
+++ b/net/rds/xlist.h
@@ -0,0 +1,80 @@
+#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/input.c b/net/rfkill/input.c
index 3713d7ecab96..1bca6d49ec96 100644
--- a/net/rfkill/input.c
+++ b/net/rfkill/input.c
@@ -142,7 +142,7 @@ static unsigned long rfkill_last_scheduled;
static unsigned long rfkill_ratelimit(const unsigned long last)
{
const unsigned long delay = msecs_to_jiffies(RFKILL_OPS_DELAY);
- return (time_after(jiffies, last + delay)) ? 0 : delay;
+ return time_after(jiffies, last + delay) ? 0 : delay;
}
static void rfkill_schedule_ratelimited(void)
diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c
index a750a28e0221..fa5f5641a2c2 100644
--- a/net/rose/rose_link.c
+++ b/net/rose/rose_link.c
@@ -114,7 +114,7 @@ static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
if (ax25s)
ax25_cb_put(ax25s);
- return (neigh->ax25 != NULL);
+ return neigh->ax25 != NULL;
}
/*
@@ -137,7 +137,7 @@ static int rose_link_up(struct rose_neigh *neigh)
if (ax25s)
ax25_cb_put(ax25s);
- return (neigh->ax25 != NULL);
+ return neigh->ax25 != NULL;
}
/*
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 2f691fb180d1..a36270a994d7 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -518,6 +518,16 @@ config NET_ACT_SKBEDIT
To compile this code as a module, choose M here: the
module will be called act_skbedit.
+config NET_ACT_CSUM
+ tristate "Checksum Updating"
+ depends on NET_CLS_ACT && INET
+ ---help---
+ Say Y here to update some common checksum after some direct
+ packet alterations.
+
+ To compile this code as a module, choose M here: the
+ module will be called act_csum.
+
config NET_CLS_IND
bool "Incoming device classification"
depends on NET_CLS_U32 || NET_CLS_FW
diff --git a/net/sched/Makefile b/net/sched/Makefile
index f14e71bfa58f..960f5dba6304 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_NET_ACT_NAT) += act_nat.o
obj-$(CONFIG_NET_ACT_PEDIT) += act_pedit.o
obj-$(CONFIG_NET_ACT_SIMP) += act_simple.o
obj-$(CONFIG_NET_ACT_SKBEDIT) += act_skbedit.o
+obj-$(CONFIG_NET_ACT_CSUM) += act_csum.o
obj-$(CONFIG_NET_SCH_FIFO) += sch_fifo.o
obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o
obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
new file mode 100644
index 000000000000..67dc7ce9b63a
--- /dev/null
+++ b/net/sched/act_csum.c
@@ -0,0 +1,595 @@
+/*
+ * Checksum updating actions
+ *
+ * Copyright (c) 2010 Gregoire Baron <baronchon@n7mm.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.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#include <linux/netlink.h>
+#include <net/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <linux/skbuff.h>
+
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/icmp.h>
+#include <linux/icmpv6.h>
+#include <linux/igmp.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/ip6_checksum.h>
+
+#include <net/act_api.h>
+
+#include <linux/tc_act/tc_csum.h>
+#include <net/tc_act/tc_csum.h>
+
+#define CSUM_TAB_MASK 15
+static struct tcf_common *tcf_csum_ht[CSUM_TAB_MASK + 1];
+static u32 csum_idx_gen;
+static DEFINE_RWLOCK(csum_lock);
+
+static struct tcf_hashinfo csum_hash_info = {
+ .htab = tcf_csum_ht,
+ .hmask = CSUM_TAB_MASK,
+ .lock = &csum_lock,
+};
+
+static const struct nla_policy csum_policy[TCA_CSUM_MAX + 1] = {
+ [TCA_CSUM_PARMS] = { .len = sizeof(struct tc_csum), },
+};
+
+static int tcf_csum_init(struct nlattr *nla, struct nlattr *est,
+ struct tc_action *a, int ovr, int bind)
+{
+ struct nlattr *tb[TCA_CSUM_MAX + 1];
+ struct tc_csum *parm;
+ struct tcf_common *pc;
+ struct tcf_csum *p;
+ int ret = 0, err;
+
+ if (nla == NULL)
+ return -EINVAL;
+
+ err = nla_parse_nested(tb, TCA_CSUM_MAX, nla,csum_policy);
+ if (err < 0)
+ return err;
+
+ if (tb[TCA_CSUM_PARMS] == NULL)
+ return -EINVAL;
+ parm = nla_data(tb[TCA_CSUM_PARMS]);
+
+ pc = tcf_hash_check(parm->index, a, bind, &csum_hash_info);
+ if (!pc) {
+ pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
+ &csum_idx_gen, &csum_hash_info);
+ if (IS_ERR(pc))
+ return PTR_ERR(pc);
+ p = to_tcf_csum(pc);
+ ret = ACT_P_CREATED;
+ } else {
+ p = to_tcf_csum(pc);
+ if (!ovr) {
+ tcf_hash_release(pc, bind, &csum_hash_info);
+ return -EEXIST;
+ }
+ }
+
+ spin_lock_bh(&p->tcf_lock);
+ p->tcf_action = parm->action;
+ p->update_flags = parm->update_flags;
+ spin_unlock_bh(&p->tcf_lock);
+
+ if (ret == ACT_P_CREATED)
+ tcf_hash_insert(pc, &csum_hash_info);
+
+ return ret;
+}
+
+static int tcf_csum_cleanup(struct tc_action *a, int bind)
+{
+ struct tcf_csum *p = a->priv;
+ return tcf_hash_release(&p->common, bind, &csum_hash_info);
+}
+
+/**
+ * tcf_csum_skb_nextlayer - Get next layer pointer
+ * @skb: sk_buff to use
+ * @ihl: previous summed headers length
+ * @ipl: complete packet length
+ * @jhl: next header length
+ *
+ * Check the expected next layer availability in the specified sk_buff.
+ * Return the next layer pointer if pass, NULL otherwise.
+ */
+static void *tcf_csum_skb_nextlayer(struct sk_buff *skb,
+ unsigned int ihl, unsigned int ipl,
+ unsigned int jhl)
+{
+ int ntkoff = skb_network_offset(skb);
+ int hl = ihl + jhl;
+
+ if (!pskb_may_pull(skb, ipl + ntkoff) || (ipl < hl) ||
+ (skb_cloned(skb) &&
+ !skb_clone_writable(skb, hl + ntkoff) &&
+ pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+ return NULL;
+ else
+ return (void *)(skb_network_header(skb) + ihl);
+}
+
+static int tcf_csum_ipv4_icmp(struct sk_buff *skb,
+ unsigned int ihl, unsigned int ipl)
+{
+ struct icmphdr *icmph;
+
+ icmph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*icmph));
+ if (icmph == NULL)
+ return 0;
+
+ icmph->checksum = 0;
+ skb->csum = csum_partial(icmph, ipl - ihl, 0);
+ icmph->checksum = csum_fold(skb->csum);
+
+ skb->ip_summed = CHECKSUM_NONE;
+
+ return 1;
+}
+
+static int tcf_csum_ipv4_igmp(struct sk_buff *skb,
+ unsigned int ihl, unsigned int ipl)
+{
+ struct igmphdr *igmph;
+
+ igmph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*igmph));
+ if (igmph == NULL)
+ return 0;
+
+ igmph->csum = 0;
+ skb->csum = csum_partial(igmph, ipl - ihl, 0);
+ igmph->csum = csum_fold(skb->csum);
+
+ skb->ip_summed = CHECKSUM_NONE;
+
+ return 1;
+}
+
+static int tcf_csum_ipv6_icmp(struct sk_buff *skb, struct ipv6hdr *ip6h,
+ unsigned int ihl, unsigned int ipl)
+{
+ struct icmp6hdr *icmp6h;
+
+ icmp6h = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*icmp6h));
+ if (icmp6h == NULL)
+ return 0;
+
+ icmp6h->icmp6_cksum = 0;
+ skb->csum = csum_partial(icmp6h, ipl - ihl, 0);
+ icmp6h->icmp6_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+ ipl - ihl, IPPROTO_ICMPV6,
+ skb->csum);
+
+ skb->ip_summed = CHECKSUM_NONE;
+
+ return 1;
+}
+
+static int tcf_csum_ipv4_tcp(struct sk_buff *skb, struct iphdr *iph,
+ unsigned int ihl, unsigned int ipl)
+{
+ struct tcphdr *tcph;
+
+ tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph));
+ if (tcph == NULL)
+ return 0;
+
+ tcph->check = 0;
+ skb->csum = csum_partial(tcph, ipl - ihl, 0);
+ tcph->check = tcp_v4_check(ipl - ihl,
+ iph->saddr, iph->daddr, skb->csum);
+
+ skb->ip_summed = CHECKSUM_NONE;
+
+ return 1;
+}
+
+static int tcf_csum_ipv6_tcp(struct sk_buff *skb, struct ipv6hdr *ip6h,
+ unsigned int ihl, unsigned int ipl)
+{
+ struct tcphdr *tcph;
+
+ tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph));
+ if (tcph == NULL)
+ return 0;
+
+ tcph->check = 0;
+ skb->csum = csum_partial(tcph, ipl - ihl, 0);
+ tcph->check = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+ ipl - ihl, IPPROTO_TCP,
+ skb->csum);
+
+ skb->ip_summed = CHECKSUM_NONE;
+
+ return 1;
+}
+
+static int tcf_csum_ipv4_udp(struct sk_buff *skb, struct iphdr *iph,
+ unsigned int ihl, unsigned int ipl, int udplite)
+{
+ struct udphdr *udph;
+ u16 ul;
+
+ /*
+ * Support both UDP and UDPLITE checksum algorithms, Don't use
+ * udph->len to get the real length without any protocol check,
+ * UDPLITE uses udph->len for another thing,
+ * Use iph->tot_len, or just ipl.
+ */
+
+ udph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*udph));
+ if (udph == NULL)
+ return 0;
+
+ ul = ntohs(udph->len);
+
+ if (udplite || udph->check) {
+
+ udph->check = 0;
+
+ if (udplite) {
+ if (ul == 0)
+ skb->csum = csum_partial(udph, ipl - ihl, 0);
+ else if ((ul >= sizeof(*udph)) && (ul <= ipl - ihl))
+ skb->csum = csum_partial(udph, ul, 0);
+ else
+ goto ignore_obscure_skb;
+ } else {
+ if (ul != ipl - ihl)
+ goto ignore_obscure_skb;
+
+ skb->csum = csum_partial(udph, ul, 0);
+ }
+
+ udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
+ ul, iph->protocol,
+ skb->csum);
+
+ if (!udph->check)
+ udph->check = CSUM_MANGLED_0;
+ }
+
+ skb->ip_summed = CHECKSUM_NONE;
+
+ignore_obscure_skb:
+ return 1;
+}
+
+static int tcf_csum_ipv6_udp(struct sk_buff *skb, struct ipv6hdr *ip6h,
+ unsigned int ihl, unsigned int ipl, int udplite)
+{
+ struct udphdr *udph;
+ u16 ul;
+
+ /*
+ * Support both UDP and UDPLITE checksum algorithms, Don't use
+ * udph->len to get the real length without any protocol check,
+ * UDPLITE uses udph->len for another thing,
+ * Use ip6h->payload_len + sizeof(*ip6h) ... , or just ipl.
+ */
+
+ udph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*udph));
+ if (udph == NULL)
+ return 0;
+
+ ul = ntohs(udph->len);
+
+ udph->check = 0;
+
+ if (udplite) {
+ if (ul == 0)
+ skb->csum = csum_partial(udph, ipl - ihl, 0);
+
+ else if ((ul >= sizeof(*udph)) && (ul <= ipl - ihl))
+ skb->csum = csum_partial(udph, ul, 0);
+
+ else
+ goto ignore_obscure_skb;
+ } else {
+ if (ul != ipl - ihl)
+ goto ignore_obscure_skb;
+
+ skb->csum = csum_partial(udph, ul, 0);
+ }
+
+ udph->check = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, ul,
+ udplite ? IPPROTO_UDPLITE : IPPROTO_UDP,
+ skb->csum);
+
+ if (!udph->check)
+ udph->check = CSUM_MANGLED_0;
+
+ skb->ip_summed = CHECKSUM_NONE;
+
+ignore_obscure_skb:
+ return 1;
+}
+
+static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags)
+{
+ struct iphdr *iph;
+ int ntkoff;
+
+ ntkoff = skb_network_offset(skb);
+
+ if (!pskb_may_pull(skb, sizeof(*iph) + ntkoff))
+ goto fail;
+
+ iph = ip_hdr(skb);
+
+ switch (iph->frag_off & htons(IP_OFFSET) ? 0 : iph->protocol) {
+ case IPPROTO_ICMP:
+ if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP)
+ if (!tcf_csum_ipv4_icmp(skb, iph->ihl * 4,
+ ntohs(iph->tot_len)))
+ goto fail;
+ break;
+ case IPPROTO_IGMP:
+ if (update_flags & TCA_CSUM_UPDATE_FLAG_IGMP)
+ if (!tcf_csum_ipv4_igmp(skb, iph->ihl * 4,
+ ntohs(iph->tot_len)))
+ goto fail;
+ break;
+ case IPPROTO_TCP:
+ if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP)
+ if (!tcf_csum_ipv4_tcp(skb, iph, iph->ihl * 4,
+ ntohs(iph->tot_len)))
+ goto fail;
+ break;
+ case IPPROTO_UDP:
+ if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP)
+ if (!tcf_csum_ipv4_udp(skb, iph, iph->ihl * 4,
+ ntohs(iph->tot_len), 0))
+ goto fail;
+ break;
+ case IPPROTO_UDPLITE:
+ if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE)
+ if (!tcf_csum_ipv4_udp(skb, iph, iph->ihl * 4,
+ ntohs(iph->tot_len), 1))
+ goto fail;
+ break;
+ }
+
+ if (update_flags & TCA_CSUM_UPDATE_FLAG_IPV4HDR) {
+ if (skb_cloned(skb) &&
+ !skb_clone_writable(skb, sizeof(*iph) + ntkoff) &&
+ pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ goto fail;
+
+ ip_send_check(iph);
+ }
+
+ return 1;
+
+fail:
+ return 0;
+}
+
+static int tcf_csum_ipv6_hopopts(struct ipv6_opt_hdr *ip6xh,
+ unsigned int ixhl, unsigned int *pl)
+{
+ int off, len, optlen;
+ unsigned char *xh = (void *)ip6xh;
+
+ off = sizeof(*ip6xh);
+ len = ixhl - off;
+
+ while (len > 1) {
+ switch (xh[off]) {
+ case IPV6_TLV_PAD0:
+ optlen = 1;
+ break;
+ case IPV6_TLV_JUMBO:
+ optlen = xh[off + 1] + 2;
+ if (optlen != 6 || len < 6 || (off & 3) != 2)
+ /* wrong jumbo option length/alignment */
+ return 0;
+ *pl = ntohl(*(__be32 *)(xh + off + 2));
+ goto done;
+ default:
+ optlen = xh[off + 1] + 2;
+ if (optlen > len)
+ /* ignore obscure options */
+ goto done;
+ break;
+ }
+ off += optlen;
+ len -= optlen;
+ }
+
+done:
+ return 1;
+}
+
+static int tcf_csum_ipv6(struct sk_buff *skb, u32 update_flags)
+{
+ struct ipv6hdr *ip6h;
+ struct ipv6_opt_hdr *ip6xh;
+ unsigned int hl, ixhl;
+ unsigned int pl;
+ int ntkoff;
+ u8 nexthdr;
+
+ ntkoff = skb_network_offset(skb);
+
+ hl = sizeof(*ip6h);
+
+ if (!pskb_may_pull(skb, hl + ntkoff))
+ goto fail;
+
+ ip6h = ipv6_hdr(skb);
+
+ pl = ntohs(ip6h->payload_len);
+ nexthdr = ip6h->nexthdr;
+
+ do {
+ switch (nexthdr) {
+ case NEXTHDR_FRAGMENT:
+ goto ignore_skb;
+ case NEXTHDR_ROUTING:
+ case NEXTHDR_HOP:
+ case NEXTHDR_DEST:
+ if (!pskb_may_pull(skb, hl + sizeof(*ip6xh) + ntkoff))
+ goto fail;
+ ip6xh = (void *)(skb_network_header(skb) + hl);
+ ixhl = ipv6_optlen(ip6xh);
+ if (!pskb_may_pull(skb, hl + ixhl + ntkoff))
+ goto fail;
+ if ((nexthdr == NEXTHDR_HOP) &&
+ !(tcf_csum_ipv6_hopopts(ip6xh, ixhl, &pl)))
+ goto fail;
+ nexthdr = ip6xh->nexthdr;
+ hl += ixhl;
+ break;
+ case IPPROTO_ICMPV6:
+ if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP)
+ if (!tcf_csum_ipv6_icmp(skb, ip6h,
+ hl, pl + sizeof(*ip6h)))
+ goto fail;
+ goto done;
+ case IPPROTO_TCP:
+ if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP)
+ if (!tcf_csum_ipv6_tcp(skb, ip6h,
+ hl, pl + sizeof(*ip6h)))
+ goto fail;
+ goto done;
+ case IPPROTO_UDP:
+ if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP)
+ if (!tcf_csum_ipv6_udp(skb, ip6h, hl,
+ pl + sizeof(*ip6h), 0))
+ goto fail;
+ goto done;
+ case IPPROTO_UDPLITE:
+ if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE)
+ if (!tcf_csum_ipv6_udp(skb, ip6h, hl,
+ pl + sizeof(*ip6h), 1))
+ goto fail;
+ goto done;
+ default:
+ goto ignore_skb;
+ }
+ } while (pskb_may_pull(skb, hl + 1 + ntkoff));
+
+done:
+ignore_skb:
+ return 1;
+
+fail:
+ return 0;
+}
+
+static int tcf_csum(struct sk_buff *skb,
+ struct tc_action *a, struct tcf_result *res)
+{
+ struct tcf_csum *p = a->priv;
+ int action;
+ u32 update_flags;
+
+ spin_lock(&p->tcf_lock);
+ p->tcf_tm.lastuse = jiffies;
+ p->tcf_bstats.bytes += qdisc_pkt_len(skb);
+ p->tcf_bstats.packets++;
+ action = p->tcf_action;
+ update_flags = p->update_flags;
+ spin_unlock(&p->tcf_lock);
+
+ if (unlikely(action == TC_ACT_SHOT))
+ goto drop;
+
+ switch (skb->protocol) {
+ case cpu_to_be16(ETH_P_IP):
+ if (!tcf_csum_ipv4(skb, update_flags))
+ goto drop;
+ break;
+ case cpu_to_be16(ETH_P_IPV6):
+ if (!tcf_csum_ipv6(skb, update_flags))
+ goto drop;
+ break;
+ }
+
+ return action;
+
+drop:
+ spin_lock(&p->tcf_lock);
+ p->tcf_qstats.drops++;
+ spin_unlock(&p->tcf_lock);
+ return TC_ACT_SHOT;
+}
+
+static int tcf_csum_dump(struct sk_buff *skb,
+ struct tc_action *a, int bind, int ref)
+{
+ unsigned char *b = skb_tail_pointer(skb);
+ struct tcf_csum *p = a->priv;
+ struct tc_csum opt = {
+ .update_flags = p->update_flags,
+ .index = p->tcf_index,
+ .action = p->tcf_action,
+ .refcnt = p->tcf_refcnt - ref,
+ .bindcnt = p->tcf_bindcnt - bind,
+ };
+ struct tcf_t t;
+
+ NLA_PUT(skb, TCA_CSUM_PARMS, sizeof(opt), &opt);
+ t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install);
+ t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse);
+ t.expires = jiffies_to_clock_t(p->tcf_tm.expires);
+ NLA_PUT(skb, TCA_CSUM_TM, sizeof(t), &t);
+
+ return skb->len;
+
+nla_put_failure:
+ nlmsg_trim(skb, b);
+ return -1;
+}
+
+static struct tc_action_ops act_csum_ops = {
+ .kind = "csum",
+ .hinfo = &csum_hash_info,
+ .type = TCA_ACT_CSUM,
+ .capab = TCA_CAP_NONE,
+ .owner = THIS_MODULE,
+ .act = tcf_csum,
+ .dump = tcf_csum_dump,
+ .cleanup = tcf_csum_cleanup,
+ .lookup = tcf_hash_search,
+ .init = tcf_csum_init,
+ .walk = tcf_generic_walker
+};
+
+MODULE_DESCRIPTION("Checksum updating actions");
+MODULE_LICENSE("GPL");
+
+static int __init csum_init_module(void)
+{
+ return tcf_register_action(&act_csum_ops);
+}
+
+static void __exit csum_cleanup_module(void)
+{
+ tcf_unregister_action(&act_csum_ops);
+}
+
+module_init(csum_init_module);
+module_exit(csum_cleanup_module);
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index c7e59e6ec349..8daef9632255 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -39,7 +39,7 @@ static struct tcf_hashinfo ipt_hash_info = {
.lock = &ipt_lock,
};
-static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
+static int ipt_init_target(struct xt_entry_target *t, char *table, unsigned int hook)
{
struct xt_tgchk_param par;
struct xt_target *target;
@@ -66,7 +66,7 @@ static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int
return 0;
}
-static void ipt_destroy_target(struct ipt_entry_target *t)
+static void ipt_destroy_target(struct xt_entry_target *t)
{
struct xt_tgdtor_param par = {
.target = t->u.kernel.target,
@@ -99,7 +99,7 @@ static const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = {
[TCA_IPT_TABLE] = { .type = NLA_STRING, .len = IFNAMSIZ },
[TCA_IPT_HOOK] = { .type = NLA_U32 },
[TCA_IPT_INDEX] = { .type = NLA_U32 },
- [TCA_IPT_TARG] = { .len = sizeof(struct ipt_entry_target) },
+ [TCA_IPT_TARG] = { .len = sizeof(struct xt_entry_target) },
};
static int tcf_ipt_init(struct nlattr *nla, struct nlattr *est,
@@ -108,7 +108,7 @@ static int tcf_ipt_init(struct nlattr *nla, struct nlattr *est,
struct nlattr *tb[TCA_IPT_MAX + 1];
struct tcf_ipt *ipt;
struct tcf_common *pc;
- struct ipt_entry_target *td, *t;
+ struct xt_entry_target *td, *t;
char *tname;
int ret = 0, err;
u32 hook = 0;
@@ -126,7 +126,7 @@ static int tcf_ipt_init(struct nlattr *nla, struct nlattr *est,
if (tb[TCA_IPT_TARG] == NULL)
return -EINVAL;
- td = (struct ipt_entry_target *)nla_data(tb[TCA_IPT_TARG]);
+ td = (struct xt_entry_target *)nla_data(tb[TCA_IPT_TARG]);
if (nla_len(tb[TCA_IPT_TARG]) < td->u.target_size)
return -EINVAL;
@@ -230,7 +230,7 @@ static int tcf_ipt(struct sk_buff *skb, struct tc_action *a,
result = TC_ACT_SHOT;
ipt->tcf_qstats.drops++;
break;
- case IPT_CONTINUE:
+ case XT_CONTINUE:
result = TC_ACT_PIPE;
break;
default:
@@ -249,7 +249,7 @@ static int tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int
{
unsigned char *b = skb_tail_pointer(skb);
struct tcf_ipt *ipt = a->priv;
- struct ipt_entry_target *t;
+ struct xt_entry_target *t;
struct tcf_t tm;
struct tc_cnt c;
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index e17096e3913c..5b271a18bc3a 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -111,44 +111,41 @@ static u32 flow_get_proto(struct sk_buff *skb)
}
}
-static int has_ports(u8 protocol)
-{
- switch (protocol) {
- case IPPROTO_TCP:
- case IPPROTO_UDP:
- case IPPROTO_UDPLITE:
- case IPPROTO_SCTP:
- case IPPROTO_DCCP:
- case IPPROTO_ESP:
- return 1;
- default:
- return 0;
- }
-}
-
static u32 flow_get_proto_src(struct sk_buff *skb)
{
switch (skb->protocol) {
case htons(ETH_P_IP): {
struct iphdr *iph;
+ int poff;
if (!pskb_network_may_pull(skb, sizeof(*iph)))
break;
iph = ip_hdr(skb);
- if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
- has_ports(iph->protocol) &&
- pskb_network_may_pull(skb, iph->ihl * 4 + 2))
- return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4));
+ if (iph->frag_off & htons(IP_MF|IP_OFFSET))
+ 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));
+ }
break;
}
case htons(ETH_P_IPV6): {
struct ipv6hdr *iph;
+ int poff;
- if (!pskb_network_may_pull(skb, sizeof(*iph) + 2))
+ if (!pskb_network_may_pull(skb, sizeof(*iph)))
break;
iph = ipv6_hdr(skb);
- if (has_ports(iph->nexthdr))
- return ntohs(*(__be16 *)&iph[1]);
+ 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));
+ }
break;
}
}
@@ -161,24 +158,36 @@ static u32 flow_get_proto_dst(struct sk_buff *skb)
switch (skb->protocol) {
case htons(ETH_P_IP): {
struct iphdr *iph;
+ int poff;
if (!pskb_network_may_pull(skb, sizeof(*iph)))
break;
iph = ip_hdr(skb);
- if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
- has_ports(iph->protocol) &&
- pskb_network_may_pull(skb, iph->ihl * 4 + 4))
- return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2));
+ if (iph->frag_off & htons(IP_MF|IP_OFFSET))
+ 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 (!pskb_network_may_pull(skb, sizeof(*iph) + 4))
+ if (!pskb_network_may_pull(skb, sizeof(*iph)))
break;
iph = ipv6_hdr(skb);
- if (has_ports(iph->nexthdr))
- return ntohs(*(__be16 *)((void *)&iph[1] + 2));
+ 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;
}
}
@@ -297,6 +306,11 @@ static u32 flow_get_vlan_tag(const struct sk_buff *skb)
return tag & VLAN_VID_MASK;
}
+static u32 flow_get_rxhash(struct sk_buff *skb)
+{
+ return skb_get_rxhash(skb);
+}
+
static u32 flow_key_get(struct sk_buff *skb, int key)
{
switch (key) {
@@ -334,6 +348,8 @@ static u32 flow_key_get(struct sk_buff *skb, int key)
return flow_get_skgid(skb);
case FLOW_KEY_VLAN_TAG:
return flow_get_vlan_tag(skb);
+ case FLOW_KEY_RXHASH:
+ return flow_get_rxhash(skb);
default:
WARN_ON(1);
return 0;
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c
index 3bcac8aa333c..34da5e29ea1a 100644
--- a/net/sched/em_meta.c
+++ b/net/sched/em_meta.c
@@ -223,6 +223,11 @@ META_COLLECTOR(int_maclen)
dst->value = skb->mac_len;
}
+META_COLLECTOR(int_rxhash)
+{
+ dst->value = skb_get_rxhash(skb);
+}
+
/**************************************************************************
* Netfilter
**************************************************************************/
@@ -541,6 +546,7 @@ static struct meta_ops __meta_ops[TCF_META_TYPE_MAX+1][TCF_META_ID_MAX+1] = {
[META_ID(SK_SENDMSG_OFF)] = META_FUNC(int_sk_sendmsg_off),
[META_ID(SK_WRITE_PENDING)] = META_FUNC(int_sk_write_pend),
[META_ID(VLAN_TAG)] = META_FUNC(int_vlan_tag),
+ [META_ID(RXHASH)] = META_FUNC(int_rxhash),
}
};
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 408eea7086aa..b22ca2d1cebc 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -240,7 +240,10 @@ struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
if (q)
goto out;
- q = qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle);
+ if (dev_ingress_queue(dev))
+ q = qdisc_match_from_root(
+ dev_ingress_queue(dev)->qdisc_sleeping,
+ handle);
out:
return q;
}
@@ -360,7 +363,7 @@ static struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt)
tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16);
}
- if (!s || tsize != s->tsize || (!tab && tsize > 0))
+ if (tsize != s->tsize || (!tab && tsize > 0))
return ERR_PTR(-EINVAL);
spin_lock(&qdisc_stab_lock);
@@ -690,6 +693,8 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
(new && new->flags & TCQ_F_INGRESS)) {
num_q = 1;
ingress = 1;
+ if (!dev_ingress_queue(dev))
+ return -ENOENT;
}
if (dev->flags & IFF_UP)
@@ -701,7 +706,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
}
for (i = 0; i < num_q; i++) {
- struct netdev_queue *dev_queue = &dev->rx_queue;
+ struct netdev_queue *dev_queue = dev_ingress_queue(dev);
if (!ingress)
dev_queue = netdev_get_tx_queue(dev, i);
@@ -979,7 +984,8 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
return -ENOENT;
q = qdisc_leaf(p, clid);
} else { /* ingress */
- q = dev->rx_queue.qdisc_sleeping;
+ if (dev_ingress_queue(dev))
+ q = dev_ingress_queue(dev)->qdisc_sleeping;
}
} else {
q = dev->qdisc;
@@ -1043,8 +1049,9 @@ replay:
if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL)
return -ENOENT;
q = qdisc_leaf(p, clid);
- } else { /*ingress */
- q = dev->rx_queue.qdisc_sleeping;
+ } else { /* ingress */
+ if (dev_ingress_queue_create(dev))
+ q = dev_ingress_queue(dev)->qdisc_sleeping;
}
} else {
q = dev->qdisc;
@@ -1123,11 +1130,14 @@ replay:
create_n_graft:
if (!(n->nlmsg_flags&NLM_F_CREATE))
return -ENOENT;
- if (clid == TC_H_INGRESS)
- q = qdisc_create(dev, &dev->rx_queue, p,
- tcm->tcm_parent, tcm->tcm_parent,
- tca, &err);
- else {
+ if (clid == TC_H_INGRESS) {
+ if (dev_ingress_queue(dev))
+ q = qdisc_create(dev, dev_ingress_queue(dev), p,
+ tcm->tcm_parent, tcm->tcm_parent,
+ tca, &err);
+ else
+ err = -ENOENT;
+ } else {
struct netdev_queue *dev_queue;
if (p && p->ops->cl_ops && p->ops->cl_ops->select_queue)
@@ -1304,8 +1314,10 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx) < 0)
goto done;
- dev_queue = &dev->rx_queue;
- if (tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb, &q_idx, s_q_idx) < 0)
+ dev_queue = dev_ingress_queue(dev);
+ if (dev_queue &&
+ tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb,
+ &q_idx, s_q_idx) < 0)
goto done;
cont:
@@ -1595,8 +1607,10 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t) < 0)
goto done;
- dev_queue = &dev->rx_queue;
- if (tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, &t, s_t) < 0)
+ dev_queue = dev_ingress_queue(dev);
+ if (dev_queue &&
+ tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb,
+ &t, s_t) < 0)
goto done;
done:
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index 6318e1136b83..282540778aa8 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -275,8 +275,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
goto err_out;
}
flow->filter_list = NULL;
- flow->q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
- &pfifo_qdisc_ops, classid);
+ flow->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid);
if (!flow->q)
flow->q = &noop_qdisc;
pr_debug("atm_tc_change: qdisc %p\n", flow->q);
@@ -543,7 +542,7 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
INIT_LIST_HEAD(&p->flows);
INIT_LIST_HEAD(&p->link.list);
list_add(&p->link.list, &p->flows);
- p->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
+ p->link.q = qdisc_create_dflt(sch->dev_queue,
&pfifo_qdisc_ops, sch->handle);
if (!p->link.q)
p->link.q = &noop_qdisc;
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 28c01ef5abc8..eb7631590865 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1379,9 +1379,9 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt)
q->link.sibling = &q->link;
q->link.common.classid = sch->handle;
q->link.qdisc = sch;
- if (!(q->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
- &pfifo_qdisc_ops,
- sch->handle)))
+ q->link.q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
+ sch->handle);
+ if (!q->link.q)
q->link.q = &noop_qdisc;
q->link.priority = TC_CBQ_MAXPRIO-1;
@@ -1623,7 +1623,7 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
struct cbq_class *cl = (struct cbq_class*)arg;
if (new == NULL) {
- new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
+ new = qdisc_create_dflt(sch->dev_queue,
&pfifo_qdisc_ops, cl->common.classid);
if (new == NULL)
return -ENOBUFS;
@@ -1874,8 +1874,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
cl->R_tab = rtab;
rtab = NULL;
cl->refcnt = 1;
- if (!(cl->q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
- &pfifo_qdisc_ops, classid)))
+ cl->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid);
+ if (!cl->q)
cl->q = &noop_qdisc;
cl->common.classid = classid;
cl->tparent = parent;
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
index b74046a95397..aa8b5313f8cf 100644
--- a/net/sched/sch_drr.c
+++ b/net/sched/sch_drr.c
@@ -110,7 +110,7 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
cl->refcnt = 1;
cl->common.classid = classid;
cl->quantum = quantum;
- cl->qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
+ cl->qdisc = qdisc_create_dflt(sch->dev_queue,
&pfifo_qdisc_ops, classid);
if (cl->qdisc == NULL)
cl->qdisc = &noop_qdisc;
@@ -218,7 +218,7 @@ static int drr_graft_class(struct Qdisc *sch, unsigned long arg,
struct drr_class *cl = (struct drr_class *)arg;
if (new == NULL) {
- new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
+ new = qdisc_create_dflt(sch->dev_queue,
&pfifo_qdisc_ops, cl->common.classid);
if (new == NULL)
new = &noop_qdisc;
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 63d41f86679c..1d295d62bb5c 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -61,8 +61,7 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg,
sch, p, new, old);
if (new == NULL) {
- new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
- &pfifo_qdisc_ops,
+ new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
sch->handle);
if (new == NULL)
new = &noop_qdisc;
@@ -384,8 +383,7 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt)
p->default_index = default_index;
p->set_tc_index = nla_get_flag(tb[TCA_DSMARK_SET_TC_INDEX]);
- p->q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
- &pfifo_qdisc_ops, sch->handle);
+ p->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, sch->handle);
if (p->q == NULL)
p->q = &noop_qdisc;
diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c
index 5948bafa8ce2..4dfecb0cba37 100644
--- a/net/sched/sch_fifo.c
+++ b/net/sched/sch_fifo.c
@@ -172,8 +172,7 @@ struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
struct Qdisc *q;
int err = -ENOMEM;
- q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
- ops, TC_H_MAKE(sch->handle, 1));
+ q = qdisc_create_dflt(sch->dev_queue, ops, TC_H_MAKE(sch->handle, 1));
if (q) {
err = fifo_set_limit(q, limit);
if (err < 0) {
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 2aeb3a4386a1..5dbb3cd96e59 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -383,6 +383,7 @@ struct Qdisc noop_qdisc = {
.list = LIST_HEAD_INIT(noop_qdisc.list),
.q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock),
.dev_queue = &noop_netdev_queue,
+ .busylock = __SPIN_LOCK_UNLOCKED(noop_qdisc.busylock),
};
EXPORT_SYMBOL(noop_qdisc);
@@ -409,6 +410,7 @@ static struct Qdisc noqueue_qdisc = {
.list = LIST_HEAD_INIT(noqueue_qdisc.list),
.q.lock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock),
.dev_queue = &noqueue_netdev_queue,
+ .busylock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.busylock),
};
@@ -574,10 +576,8 @@ errout:
return ERR_PTR(err);
}
-struct Qdisc * qdisc_create_dflt(struct net_device *dev,
- struct netdev_queue *dev_queue,
- struct Qdisc_ops *ops,
- unsigned int parentid)
+struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
+ struct Qdisc_ops *ops, unsigned int parentid)
{
struct Qdisc *sch;
@@ -682,7 +682,7 @@ static void attach_one_default_qdisc(struct net_device *dev,
struct Qdisc *qdisc;
if (dev->tx_queue_len) {
- qdisc = qdisc_create_dflt(dev, dev_queue,
+ qdisc = qdisc_create_dflt(dev_queue,
&pfifo_fast_ops, TC_H_ROOT);
if (!qdisc) {
printk(KERN_INFO "%s: activation failed\n", dev->name);
@@ -709,7 +709,7 @@ static void attach_default_qdiscs(struct net_device *dev)
dev->qdisc = txq->qdisc_sleeping;
atomic_inc(&dev->qdisc->refcnt);
} else {
- qdisc = qdisc_create_dflt(dev, txq, &mq_qdisc_ops, TC_H_ROOT);
+ qdisc = qdisc_create_dflt(txq, &mq_qdisc_ops, TC_H_ROOT);
if (qdisc) {
qdisc->ops->attach(qdisc);
dev->qdisc = qdisc;
@@ -753,7 +753,8 @@ void dev_activate(struct net_device *dev)
need_watchdog = 0;
netdev_for_each_tx_queue(dev, transition_one_qdisc, &need_watchdog);
- transition_one_qdisc(dev, &dev->rx_queue, NULL);
+ if (dev_ingress_queue(dev))
+ transition_one_qdisc(dev, dev_ingress_queue(dev), NULL);
if (need_watchdog) {
dev->trans_start = jiffies;
@@ -812,7 +813,8 @@ static bool some_qdisc_is_busy(struct net_device *dev)
void dev_deactivate(struct net_device *dev)
{
netdev_for_each_tx_queue(dev, dev_deactivate_queue, &noop_qdisc);
- dev_deactivate_queue(dev, &dev->rx_queue, &noop_qdisc);
+ if (dev_ingress_queue(dev))
+ dev_deactivate_queue(dev, dev_ingress_queue(dev), &noop_qdisc);
dev_watchdog_down(dev);
@@ -838,7 +840,8 @@ void dev_init_scheduler(struct net_device *dev)
{
dev->qdisc = &noop_qdisc;
netdev_for_each_tx_queue(dev, dev_init_scheduler_queue, &noop_qdisc);
- dev_init_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc);
+ if (dev_ingress_queue(dev))
+ dev_init_scheduler_queue(dev, dev_ingress_queue(dev), &noop_qdisc);
setup_timer(&dev->watchdog_timer, dev_watchdog, (unsigned long)dev);
}
@@ -861,7 +864,8 @@ static void shutdown_scheduler_queue(struct net_device *dev,
void dev_shutdown(struct net_device *dev)
{
netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc);
- shutdown_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc);
+ if (dev_ingress_queue(dev))
+ shutdown_scheduler_queue(dev, dev_ingress_queue(dev), &noop_qdisc);
qdisc_destroy(dev->qdisc);
dev->qdisc = &noop_qdisc;
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 47496098d35c..069c62b7bb36 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1088,7 +1088,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
cl->refcnt = 1;
cl->sched = q;
cl->cl_parent = parent;
- cl->qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
+ cl->qdisc = qdisc_create_dflt(sch->dev_queue,
&pfifo_qdisc_ops, classid);
if (cl->qdisc == NULL)
cl->qdisc = &noop_qdisc;
@@ -1209,8 +1209,7 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
if (cl->level > 0)
return -EINVAL;
if (new == NULL) {
- new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
- &pfifo_qdisc_ops,
+ new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
cl->cl_common.classid);
if (new == NULL)
new = &noop_qdisc;
@@ -1452,8 +1451,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt)
q->root.cl_common.classid = sch->handle;
q->root.refcnt = 1;
q->root.sched = q;
- q->root.qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
- &pfifo_qdisc_ops,
+ q->root.qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
sch->handle);
if (q->root.qdisc == NULL)
q->root.qdisc = &noop_qdisc;
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 4be8d04b262d..01b519d6c52d 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1121,8 +1121,7 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
if (cl->level)
return -EINVAL;
if (new == NULL &&
- (new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
- &pfifo_qdisc_ops,
+ (new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
cl->common.classid)) == NULL)
return -ENOBUFS;
@@ -1247,8 +1246,7 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
return -EBUSY;
if (!cl->level && htb_parent_last_child(cl)) {
- new_q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
- &pfifo_qdisc_ops,
+ new_q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
cl->parent->common.classid);
last_child = 1;
}
@@ -1302,14 +1300,14 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
struct htb_class *cl = (struct htb_class *)*arg, *parent;
struct nlattr *opt = tca[TCA_OPTIONS];
struct qdisc_rate_table *rtab = NULL, *ctab = NULL;
- struct nlattr *tb[TCA_HTB_RTAB + 1];
+ struct nlattr *tb[__TCA_HTB_MAX];
struct tc_htb_opt *hopt;
/* extract all subattrs from opt attr */
if (!opt)
goto failure;
- err = nla_parse_nested(tb, TCA_HTB_RTAB, opt, htb_policy);
+ err = nla_parse_nested(tb, TCA_HTB_MAX, opt, htb_policy);
if (err < 0)
goto failure;
@@ -1377,7 +1375,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
/* create leaf qdisc early because it uses kmalloc(GFP_KERNEL)
so that can't be used inside of sch_tree_lock
-- thanks to Karlis Peisenieks */
- new_q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
+ new_q = qdisc_create_dflt(sch->dev_queue,
&pfifo_qdisc_ops, classid);
sch_tree_lock(sch);
if (parent && !parent->level) {
diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c
index fe91e50f9d98..ecc302f4d2a1 100644
--- a/net/sched/sch_mq.c
+++ b/net/sched/sch_mq.c
@@ -56,7 +56,7 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt)
for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
dev_queue = netdev_get_tx_queue(dev, ntx);
- qdisc = qdisc_create_dflt(dev, dev_queue, &pfifo_fast_ops,
+ qdisc = qdisc_create_dflt(dev_queue, &pfifo_fast_ops,
TC_H_MAKE(TC_H_MAJ(sch->handle),
TC_H_MIN(ntx + 1)));
if (qdisc == NULL)
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c
index 6ae251279fc2..32690deab5d0 100644
--- a/net/sched/sch_multiq.c
+++ b/net/sched/sch_multiq.c
@@ -227,8 +227,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt)
for (i = 0; i < q->bands; i++) {
if (q->queues[i] == &noop_qdisc) {
struct Qdisc *child, *old;
- child = qdisc_create_dflt(qdisc_dev(sch),
- sch->dev_queue,
+ child = qdisc_create_dflt(sch->dev_queue,
&pfifo_qdisc_ops,
TC_H_MAKE(sch->handle,
i + 1));
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 4714ff162bbd..e5593c083a78 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -538,8 +538,7 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt)
qdisc_watchdog_init(&q->watchdog, sch);
- q->qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
- &tfifo_qdisc_ops,
+ q->qdisc = qdisc_create_dflt(sch->dev_queue, &tfifo_qdisc_ops,
TC_H_MAKE(sch->handle, 1));
if (!q->qdisc) {
pr_debug("netem: qdisc create failed\n");
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 0748fb1e3a49..b1c95bce33ce 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -200,7 +200,7 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt)
for (i=0; i<q->bands; i++) {
if (q->queues[i] == &noop_qdisc) {
struct Qdisc *child, *old;
- child = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
+ child = qdisc_create_dflt(sch->dev_queue,
&pfifo_qdisc_ops,
TC_H_MAKE(sch->handle, i + 1));
if (child) {
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 201cbac2b32c..3cf478d012dd 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -123,40 +123,39 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
case htons(ETH_P_IP):
{
const struct iphdr *iph;
+ int poff;
if (!pskb_network_may_pull(skb, sizeof(*iph)))
goto err;
iph = ip_hdr(skb);
h = (__force u32)iph->daddr;
h2 = (__force u32)iph->saddr ^ iph->protocol;
- if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
- (iph->protocol == IPPROTO_TCP ||
- iph->protocol == IPPROTO_UDP ||
- iph->protocol == IPPROTO_UDPLITE ||
- iph->protocol == IPPROTO_SCTP ||
- iph->protocol == IPPROTO_DCCP ||
- iph->protocol == IPPROTO_ESP) &&
- pskb_network_may_pull(skb, iph->ihl * 4 + 4))
- h2 ^= *(((u32*)iph) + iph->ihl);
+ if (iph->frag_off & htons(IP_MF|IP_OFFSET))
+ break;
+ poff = proto_ports_offset(iph->protocol);
+ if (poff >= 0 &&
+ pskb_network_may_pull(skb, iph->ihl * 4 + 4 + poff)) {
+ iph = ip_hdr(skb);
+ h2 ^= *(u32*)((void *)iph + iph->ihl * 4 + poff);
+ }
break;
}
case htons(ETH_P_IPV6):
{
struct ipv6hdr *iph;
+ int poff;
if (!pskb_network_may_pull(skb, sizeof(*iph)))
goto err;
iph = ipv6_hdr(skb);
h = (__force u32)iph->daddr.s6_addr32[3];
h2 = (__force u32)iph->saddr.s6_addr32[3] ^ iph->nexthdr;
- if ((iph->nexthdr == IPPROTO_TCP ||
- iph->nexthdr == IPPROTO_UDP ||
- iph->nexthdr == IPPROTO_UDPLITE ||
- iph->nexthdr == IPPROTO_SCTP ||
- iph->nexthdr == IPPROTO_DCCP ||
- iph->nexthdr == IPPROTO_ESP) &&
- pskb_network_may_pull(skb, sizeof(*iph) + 4))
- h2 ^= *(u32*)&iph[1];
+ poff = proto_ports_offset(iph->nexthdr);
+ if (poff >= 0 &&
+ pskb_network_may_pull(skb, sizeof(*iph) + 4 + poff)) {
+ iph = ipv6_hdr(skb);
+ h2 ^= *(u32*)((void *)iph + sizeof(*iph) + poff);
+ }
break;
}
default:
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index feaabc103ce6..401af9596709 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -241,11 +241,11 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device *
}
if (neigh_event_send(n, skb_res) == 0) {
int err;
+ char haddr[MAX_ADDR_LEN];
- read_lock(&n->lock);
- err = dev_hard_header(skb, dev, ntohs(skb->protocol),
- n->ha, NULL, skb->len);
- read_unlock(&n->lock);
+ neigh_ha_snapshot(haddr, n, dev);
+ err = dev_hard_header(skb, dev, ntohs(skb->protocol), haddr,
+ NULL, skb->len);
if (err < 0) {
neigh_release(n);
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 0b85e5256434..5f1fb8bd862d 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -48,6 +48,8 @@
* be incorporated into the next SCTP release.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/poll.h>
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 476caaf100ed..6c8556459a75 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -37,6 +37,8 @@
* be incorporated into the next SCTP release.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/net.h>
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
index ccb6dc48d15b..397296fb156f 100644
--- a/net/sctp/inqueue.c
+++ b/net/sctp/inqueue.c
@@ -43,6 +43,8 @@
* be incorporated into the next SCTP release.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
#include <linux/interrupt.h>
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 732689140fb8..95e0c8eda1a0 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -47,6 +47,8 @@
* be incorporated into the next SCTP release.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
@@ -336,7 +338,7 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk,
memcpy(saddr, baddr, sizeof(union sctp_addr));
SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr);
} else {
- printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
+ pr_err("%s: asoc:%p Could not find a valid source "
"address for the dest:%pI6\n",
__func__, asoc, &daddr->v6.sin6_addr);
}
diff --git a/net/sctp/objcnt.c b/net/sctp/objcnt.c
index f73ec0ea93ba..8ef8e7d9eb61 100644
--- a/net/sctp/objcnt.c
+++ b/net/sctp/objcnt.c
@@ -38,6 +38,8 @@
* be incorporated into the next SCTP release.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <net/sctp/sctp.h>
@@ -134,8 +136,7 @@ void sctp_dbg_objcnt_init(void)
ent = proc_create("sctp_dbg_objcnt", 0,
proc_net_sctp, &sctp_objcnt_ops);
if (!ent)
- printk(KERN_WARNING
- "sctp_dbg_objcnt: Unable to create /proc entry.\n");
+ pr_warn("sctp_dbg_objcnt: Unable to create /proc entry.\n");
}
/* Cleanup the objcount entry in the proc filesystem. */
diff --git a/net/sctp/output.c b/net/sctp/output.c
index bcc4590ccaf2..60600d337a3a 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -41,6 +41,8 @@
* be incorporated into the next SCTP release.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/wait.h>
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index c04b2eb59186..8c6d379b4bb6 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -46,6 +46,8 @@
* be incorporated into the next SCTP release.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/types.h>
#include <linux/list.h> /* For struct list_head */
#include <linux/socket.h>
@@ -1463,23 +1465,23 @@ static void sctp_check_transmitted(struct sctp_outq *q,
/* Display the end of the
* current range.
*/
- SCTP_DEBUG_PRINTK("-%08x",
- dbg_last_ack_tsn);
+ SCTP_DEBUG_PRINTK_CONT("-%08x",
+ dbg_last_ack_tsn);
}
/* Start a new range. */
- SCTP_DEBUG_PRINTK(",%08x", tsn);
+ SCTP_DEBUG_PRINTK_CONT(",%08x", tsn);
dbg_ack_tsn = tsn;
break;
case 1: /* The last TSN was NOT ACKed. */
if (dbg_last_kept_tsn != dbg_kept_tsn) {
/* Display the end of current range. */
- SCTP_DEBUG_PRINTK("-%08x",
- dbg_last_kept_tsn);
+ SCTP_DEBUG_PRINTK_CONT("-%08x",
+ dbg_last_kept_tsn);
}
- SCTP_DEBUG_PRINTK("\n");
+ SCTP_DEBUG_PRINTK_CONT("\n");
/* FALL THROUGH... */
default:
@@ -1526,18 +1528,18 @@ static void sctp_check_transmitted(struct sctp_outq *q,
break;
if (dbg_last_kept_tsn != dbg_kept_tsn)
- SCTP_DEBUG_PRINTK("-%08x",
- dbg_last_kept_tsn);
+ SCTP_DEBUG_PRINTK_CONT("-%08x",
+ dbg_last_kept_tsn);
- SCTP_DEBUG_PRINTK(",%08x", tsn);
+ SCTP_DEBUG_PRINTK_CONT(",%08x", tsn);
dbg_kept_tsn = tsn;
break;
case 0:
if (dbg_last_ack_tsn != dbg_ack_tsn)
- SCTP_DEBUG_PRINTK("-%08x",
- dbg_last_ack_tsn);
- SCTP_DEBUG_PRINTK("\n");
+ SCTP_DEBUG_PRINTK_CONT("-%08x",
+ dbg_last_ack_tsn);
+ SCTP_DEBUG_PRINTK_CONT("\n");
/* FALL THROUGH... */
default:
@@ -1556,17 +1558,17 @@ static void sctp_check_transmitted(struct sctp_outq *q,
switch (dbg_prt_state) {
case 0:
if (dbg_last_ack_tsn != dbg_ack_tsn) {
- SCTP_DEBUG_PRINTK("-%08x\n", dbg_last_ack_tsn);
+ SCTP_DEBUG_PRINTK_CONT("-%08x\n", dbg_last_ack_tsn);
} else {
- SCTP_DEBUG_PRINTK("\n");
+ SCTP_DEBUG_PRINTK_CONT("\n");
}
break;
case 1:
if (dbg_last_kept_tsn != dbg_kept_tsn) {
- SCTP_DEBUG_PRINTK("-%08x\n", dbg_last_kept_tsn);
+ SCTP_DEBUG_PRINTK_CONT("-%08x\n", dbg_last_kept_tsn);
} else {
- SCTP_DEBUG_PRINTK("\n");
+ SCTP_DEBUG_PRINTK_CONT("\n");
}
}
#endif /* SCTP_DEBUG */
diff --git a/net/sctp/probe.c b/net/sctp/probe.c
index 289b1ba62cac..bc6cd75cc1dc 100644
--- a/net/sctp/probe.c
+++ b/net/sctp/probe.c
@@ -22,6 +22,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/socket.h>
@@ -193,7 +195,7 @@ static __init int sctpprobe_init(void)
if (ret)
goto remove_proc;
- pr_info("SCTP probe registered (port=%d)\n", port);
+ pr_info("probe registered (port=%d)\n", port);
return 0;
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 5027b83f1cc0..1ef29c74d85e 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -46,6 +46,8 @@
* be incorporated into the next SCTP release.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
@@ -707,8 +709,7 @@ static int sctp_ctl_sock_init(void)
&init_net);
if (err < 0) {
- printk(KERN_ERR
- "SCTP: Failed to create the SCTP control socket.\n");
+ pr_err("Failed to create the SCTP control socket\n");
return err;
}
return 0;
@@ -798,7 +799,7 @@ static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *len)
static int sctp_inet_af_supported(sa_family_t family, struct sctp_sock *sp)
{
/* PF_INET only supports AF_INET addresses. */
- return (AF_INET == family);
+ return AF_INET == family;
}
/* Address matching with wildcards allowed. */
@@ -1206,7 +1207,7 @@ SCTP_STATIC __init int sctp_init(void)
__get_free_pages(GFP_ATOMIC, order);
} while (!sctp_assoc_hashtable && --order > 0);
if (!sctp_assoc_hashtable) {
- printk(KERN_ERR "SCTP: Failed association hash alloc.\n");
+ pr_err("Failed association hash alloc\n");
status = -ENOMEM;
goto err_ahash_alloc;
}
@@ -1220,7 +1221,7 @@ SCTP_STATIC __init int sctp_init(void)
sctp_ep_hashtable = (struct sctp_hashbucket *)
kmalloc(64 * sizeof(struct sctp_hashbucket), GFP_KERNEL);
if (!sctp_ep_hashtable) {
- printk(KERN_ERR "SCTP: Failed endpoint_hash alloc.\n");
+ pr_err("Failed endpoint_hash alloc\n");
status = -ENOMEM;
goto err_ehash_alloc;
}
@@ -1239,7 +1240,7 @@ SCTP_STATIC __init int sctp_init(void)
__get_free_pages(GFP_ATOMIC, order);
} while (!sctp_port_hashtable && --order > 0);
if (!sctp_port_hashtable) {
- printk(KERN_ERR "SCTP: Failed bind hash alloc.");
+ pr_err("Failed bind hash alloc\n");
status = -ENOMEM;
goto err_bhash_alloc;
}
@@ -1248,8 +1249,7 @@ SCTP_STATIC __init int sctp_init(void)
INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain);
}
- printk(KERN_INFO "SCTP: Hash tables configured "
- "(established %d bind %d)\n",
+ pr_info("Hash tables configured (established %d bind %d)\n",
sctp_assoc_hashsize, sctp_port_hashsize);
/* Disable ADDIP by default. */
@@ -1290,8 +1290,7 @@ SCTP_STATIC __init int sctp_init(void)
/* Initialize the control inode/socket for handling OOTB packets. */
if ((status = sctp_ctl_sock_init())) {
- printk (KERN_ERR
- "SCTP: Failed to initialize the SCTP control sock.\n");
+ pr_err("Failed to initialize the SCTP control sock\n");
goto err_ctl_sock_init;
}
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 246f92924658..2cc46f0962ca 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -50,6 +50,8 @@
* be incorporated into the next SCTP release.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/ip.h>
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index f5e5e27cac5e..b21b218d564f 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -47,6 +47,8 @@
* be incorporated into the next SCTP release.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/skbuff.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -1146,26 +1148,23 @@ static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_DISPOSITION_VIOLATION:
if (net_ratelimit())
- printk(KERN_ERR "sctp protocol violation state %d "
- "chunkid %d\n", state, subtype.chunk);
+ pr_err("protocol violation state %d chunkid %d\n",
+ state, subtype.chunk);
break;
case SCTP_DISPOSITION_NOT_IMPL:
- printk(KERN_WARNING "sctp unimplemented feature in state %d, "
- "event_type %d, event_id %d\n",
- state, event_type, subtype.chunk);
+ pr_warn("unimplemented feature in state %d, event_type %d, event_id %d\n",
+ state, event_type, subtype.chunk);
break;
case SCTP_DISPOSITION_BUG:
- printk(KERN_ERR "sctp bug in state %d, "
- "event_type %d, event_id %d\n",
+ pr_err("bug in state %d, event_type %d, event_id %d\n",
state, event_type, subtype.chunk);
BUG();
break;
default:
- printk(KERN_ERR "sctp impossible disposition %d "
- "in state %d, event_type %d, event_id %d\n",
+ pr_err("impossible disposition %d in state %d, event_type %d, event_id %d\n",
status, state, event_type, subtype.chunk);
BUG();
break;
@@ -1679,8 +1678,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
sctp_cmd_send_asconf(asoc);
break;
default:
- printk(KERN_WARNING "Impossible command: %u, %p\n",
- cmd->verb, cmd->obj.ptr);
+ pr_warn("Impossible command: %u, %p\n",
+ cmd->verb, cmd->obj.ptr);
break;
}
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index d344dc481ccc..4b4eb7c96bbd 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -50,6 +50,8 @@
* be incorporated into the next SCTP release.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/ip.h>
@@ -1138,18 +1140,16 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
if (unlikely(!link)) {
if (from_addr.sa.sa_family == AF_INET6) {
if (net_ratelimit())
- printk(KERN_WARNING
- "%s association %p could not find address %pI6\n",
- __func__,
- asoc,
- &from_addr.v6.sin6_addr);
+ pr_warn("%s association %p could not find address %pI6\n",
+ __func__,
+ asoc,
+ &from_addr.v6.sin6_addr);
} else {
if (net_ratelimit())
- printk(KERN_WARNING
- "%s association %p could not find address %pI4\n",
- __func__,
- asoc,
- &from_addr.v4.sin_addr.s_addr);
+ pr_warn("%s association %p could not find address %pI4\n",
+ __func__,
+ asoc,
+ &from_addr.v4.sin_addr.s_addr);
}
return SCTP_DISPOSITION_DISCARD;
}
diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c
index 6d9b3aafcc5d..546d4387fb3c 100644
--- a/net/sctp/sm_statetable.c
+++ b/net/sctp/sm_statetable.c
@@ -46,6 +46,8 @@
* be incorporated into the next SCTP release.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/skbuff.h>
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
@@ -66,15 +68,19 @@ static const sctp_sm_table_entry_t bug = {
.name = "sctp_sf_bug"
};
-#define DO_LOOKUP(_max, _type, _table) \
- if ((event_subtype._type > (_max))) { \
- printk(KERN_WARNING \
- "sctp table %p possible attack:" \
- " event %d exceeds max %d\n", \
- _table, event_subtype._type, _max); \
- return &bug; \
- } \
- return &_table[event_subtype._type][(int)state];
+#define DO_LOOKUP(_max, _type, _table) \
+({ \
+ const sctp_sm_table_entry_t *rtn; \
+ \
+ if ((event_subtype._type > (_max))) { \
+ pr_warn("table %p possible attack: event %d exceeds max %d\n", \
+ _table, event_subtype._type, _max); \
+ rtn = &bug; \
+ } else \
+ rtn = &_table[event_subtype._type][(int)state]; \
+ \
+ rtn; \
+})
const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
sctp_state_t state,
@@ -83,21 +89,15 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
switch (event_type) {
case SCTP_EVENT_T_CHUNK:
return sctp_chunk_event_lookup(event_subtype.chunk, state);
- break;
case SCTP_EVENT_T_TIMEOUT:
- DO_LOOKUP(SCTP_EVENT_TIMEOUT_MAX, timeout,
- timeout_event_table);
- break;
-
+ return DO_LOOKUP(SCTP_EVENT_TIMEOUT_MAX, timeout,
+ timeout_event_table);
case SCTP_EVENT_T_OTHER:
- DO_LOOKUP(SCTP_EVENT_OTHER_MAX, other, other_event_table);
- break;
-
+ return DO_LOOKUP(SCTP_EVENT_OTHER_MAX, other,
+ other_event_table);
case SCTP_EVENT_T_PRIMITIVE:
- DO_LOOKUP(SCTP_EVENT_PRIMITIVE_MAX, primitive,
- primitive_event_table);
- break;
-
+ return DO_LOOKUP(SCTP_EVENT_PRIMITIVE_MAX, primitive,
+ primitive_event_table);
default:
/* Yikes! We got an illegal event type. */
return &bug;
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index fbb70770ad05..e34ca9cc1167 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -57,6 +57,8 @@
* be incorporated into the next SCTP release.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/wait.h>
@@ -2469,9 +2471,8 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,
if (params.sack_delay == 0 && params.sack_freq == 0)
return 0;
} else if (optlen == sizeof(struct sctp_assoc_value)) {
- printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value "
- "in delayed_ack socket option deprecated\n");
- printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n");
+ pr_warn("Use of struct sctp_assoc_value in delayed_ack socket option deprecated\n");
+ pr_warn("Use struct sctp_sack_info instead\n");
if (copy_from_user(&params, optval, optlen))
return -EFAULT;
@@ -2879,10 +2880,8 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
int val;
if (optlen == sizeof(int)) {
- printk(KERN_WARNING
- "SCTP: Use of int in maxseg socket option deprecated\n");
- printk(KERN_WARNING
- "SCTP: Use struct sctp_assoc_value instead\n");
+ pr_warn("Use of int in maxseg socket option deprecated\n");
+ pr_warn("Use struct sctp_assoc_value instead\n");
if (copy_from_user(&val, optval, optlen))
return -EFAULT;
params.assoc_id = 0;
@@ -3132,10 +3131,8 @@ static int sctp_setsockopt_maxburst(struct sock *sk,
int assoc_id = 0;
if (optlen == sizeof(int)) {
- printk(KERN_WARNING
- "SCTP: Use of int in max_burst socket option deprecated\n");
- printk(KERN_WARNING
- "SCTP: Use struct sctp_assoc_value instead\n");
+ pr_warn("Use of int in max_burst socket option deprecated\n");
+ pr_warn("Use struct sctp_assoc_value instead\n");
if (copy_from_user(&val, optval, optlen))
return -EFAULT;
} else if (optlen == sizeof(struct sctp_assoc_value)) {
@@ -3606,7 +3603,40 @@ out:
/* The SCTP ioctl handler. */
SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
- return -ENOIOCTLCMD;
+ int rc = -ENOTCONN;
+
+ sctp_lock_sock(sk);
+
+ /*
+ * SEQPACKET-style sockets in LISTENING state are valid, for
+ * SCTP, so only discard TCP-style sockets in LISTENING state.
+ */
+ if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
+ goto out;
+
+ switch (cmd) {
+ case SIOCINQ: {
+ struct sk_buff *skb;
+ unsigned int amount = 0;
+
+ skb = skb_peek(&sk->sk_receive_queue);
+ if (skb != NULL) {
+ /*
+ * We will only return the amount of this packet since
+ * that is all that will be read.
+ */
+ amount = skb->len;
+ }
+ rc = put_user(amount, (int __user *)arg);
+ break;
+ }
+ default:
+ rc = -ENOIOCTLCMD;
+ break;
+ }
+out:
+ sctp_release_sock(sk);
+ return rc;
}
/* This is the function which gets called during socket creation to
@@ -3865,7 +3895,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len,
}
out:
- return (retval);
+ return retval;
}
@@ -3921,7 +3951,7 @@ static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len,
}
out:
- return (retval);
+ return retval;
}
/* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS)
@@ -4292,9 +4322,8 @@ static int sctp_getsockopt_delayed_ack(struct sock *sk, int len,
if (copy_from_user(&params, optval, len))
return -EFAULT;
} else if (len == sizeof(struct sctp_assoc_value)) {
- printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value "
- "in delayed_ack socket option deprecated\n");
- printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n");
+ pr_warn("Use of struct sctp_assoc_value in delayed_ack socket option deprecated\n");
+ pr_warn("Use struct sctp_sack_info instead\n");
if (copy_from_user(&params, optval, len))
return -EFAULT;
} else
@@ -4940,10 +4969,8 @@ static int sctp_getsockopt_maxseg(struct sock *sk, int len,
struct sctp_association *asoc;
if (len == sizeof(int)) {
- printk(KERN_WARNING
- "SCTP: Use of int in maxseg socket option deprecated\n");
- printk(KERN_WARNING
- "SCTP: Use struct sctp_assoc_value instead\n");
+ pr_warn("Use of int in maxseg socket option deprecated\n");
+ pr_warn("Use struct sctp_assoc_value instead\n");
params.assoc_id = 0;
} else if (len >= sizeof(struct sctp_assoc_value)) {
len = sizeof(struct sctp_assoc_value);
@@ -5034,10 +5061,8 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,
struct sctp_association *asoc;
if (len == sizeof(int)) {
- printk(KERN_WARNING
- "SCTP: Use of int in max_burst socket option deprecated\n");
- printk(KERN_WARNING
- "SCTP: Use struct sctp_assoc_value instead\n");
+ pr_warn("Use of int in max_burst socket option deprecated\n");
+ pr_warn("Use struct sctp_assoc_value instead\n");
params.assoc_id = 0;
} else if (len >= sizeof(struct sctp_assoc_value)) {
len = sizeof(struct sctp_assoc_value);
@@ -5580,7 +5605,7 @@ static int sctp_get_port(struct sock *sk, unsigned short snum)
/* Note: sk->sk_num gets filled in if ephemeral port request. */
ret = sctp_get_port_local(sk, &addr);
- return (ret ? 1 : 0);
+ return ret ? 1 : 0;
}
/*
@@ -5597,8 +5622,7 @@ SCTP_STATIC int sctp_listen_start(struct sock *sk, int backlog)
tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(tfm)) {
if (net_ratelimit()) {
- printk(KERN_INFO
- "SCTP: failed to load transform for %s: %ld\n",
+ pr_info("failed to load transform for %s: %ld\n",
sctp_hmac_alg, PTR_ERR(tfm));
}
return -ENOSYS;
@@ -5727,13 +5751,12 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
mask |= POLLERR;
if (sk->sk_shutdown & RCV_SHUTDOWN)
- mask |= POLLRDHUP;
+ mask |= POLLRDHUP | POLLIN | POLLRDNORM;
if (sk->sk_shutdown == SHUTDOWN_MASK)
mask |= POLLHUP;
/* Is it readable? Reconsider this code with TCP-style support. */
- if (!skb_queue_empty(&sk->sk_receive_queue) ||
- (sk->sk_shutdown & RCV_SHUTDOWN))
+ if (!skb_queue_empty(&sk->sk_receive_queue))
mask |= POLLIN | POLLRDNORM;
/* The association is either gone or not ready. */
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index 132046cb82fc..d3ae493d234a 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -48,6 +48,8 @@
* be incorporated into the next SCTP release.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/random.h>
@@ -244,10 +246,9 @@ void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu)
struct dst_entry *dst;
if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) {
- printk(KERN_WARNING "%s: Reported pmtu %d too low, "
- "using default minimum of %d\n",
- __func__, pmtu,
- SCTP_DEFAULT_MINSEGMENT);
+ pr_warn("%s: Reported pmtu %d too low, using default minimum of %d\n",
+ __func__, pmtu,
+ SCTP_DEFAULT_MINSEGMENT);
/* Use default minimum segment size and disable
* pmtu discovery on this transport.
*/
diff --git a/net/socket.c b/net/socket.c
index 9eac5c394134..ee3cd280c76e 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -209,8 +209,8 @@ int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr *kaddr)
* specified. Zero is returned for a success.
*/
-int move_addr_to_user(struct sockaddr *kaddr, int klen, void __user *uaddr,
- int __user *ulen)
+static int move_addr_to_user(struct sockaddr *kaddr, int klen,
+ void __user *uaddr, int __user *ulen)
{
int err;
int len;
@@ -377,7 +377,7 @@ static int sock_alloc_file(struct socket *sock, struct file **f, int flags)
&socket_file_ops);
if (unlikely(!file)) {
/* drop dentry, keep inode */
- atomic_inc(&path.dentry->d_inode->i_count);
+ ihold(path.dentry->d_inode);
path_put(&path);
put_unused_fd(fd);
return -ENFILE;
@@ -480,6 +480,7 @@ static struct socket *sock_alloc(void)
sock = SOCKET_I(inode);
kmemcheck_annotate_bitfield(sock, type);
+ inode->i_ino = get_next_ino();
inode->i_mode = S_IFSOCK | S_IRWXUGO;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
@@ -536,14 +537,13 @@ void sock_release(struct socket *sock)
}
EXPORT_SYMBOL(sock_release);
-int sock_tx_timestamp(struct msghdr *msg, struct sock *sk,
- union skb_shared_tx *shtx)
+int sock_tx_timestamp(struct sock *sk, __u8 *tx_flags)
{
- shtx->flags = 0;
+ *tx_flags = 0;
if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE))
- shtx->hardware = 1;
+ *tx_flags |= SKBTX_HW_TSTAMP;
if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE))
- shtx->software = 1;
+ *tx_flags |= SKBTX_SW_TSTAMP;
return 0;
}
EXPORT_SYMBOL(sock_tx_timestamp);
@@ -663,7 +663,8 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
}
EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
-inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
+static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk,
+ struct sk_buff *skb)
{
if (sock_flag(sk, SOCK_RXQ_OVFL) && skb && skb->dropcount)
put_cmsg(msg, SOL_SOCKET, SO_RXQ_OVFL,
@@ -1145,7 +1146,7 @@ call_kill:
}
EXPORT_SYMBOL(sock_wake_async);
-static int __sock_create(struct net *net, int family, int type, int protocol,
+int __sock_create(struct net *net, int family, int type, int protocol,
struct socket **res, int kern)
{
int err;
@@ -1257,6 +1258,7 @@ out_release:
rcu_read_unlock();
goto out_sock_release;
}
+EXPORT_SYMBOL(__sock_create);
int sock_create(int family, int type, int protocol, struct socket **res)
{
@@ -1920,7 +1922,8 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags)
* Afterwards, it will be a kernel pointer. Thus the compiler-assisted
* checking falls down on this.
*/
- if (copy_from_user(ctl_buf, (void __user *)msg_sys.msg_control,
+ if (copy_from_user(ctl_buf,
+ (void __user __force *)msg_sys.msg_control,
ctl_len))
goto out_freectl;
msg_sys.msg_control = ctl_buf;
@@ -3055,14 +3058,19 @@ int kernel_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen)
{
mm_segment_t oldfs = get_fs();
+ char __user *uoptval;
+ int __user *uoptlen;
int err;
+ uoptval = (char __user __force *) optval;
+ uoptlen = (int __user __force *) optlen;
+
set_fs(KERNEL_DS);
if (level == SOL_SOCKET)
- err = sock_getsockopt(sock, level, optname, optval, optlen);
+ err = sock_getsockopt(sock, level, optname, uoptval, uoptlen);
else
- err = sock->ops->getsockopt(sock, level, optname, optval,
- optlen);
+ err = sock->ops->getsockopt(sock, level, optname, uoptval,
+ uoptlen);
set_fs(oldfs);
return err;
}
@@ -3072,13 +3080,16 @@ int kernel_setsockopt(struct socket *sock, int level, int optname,
char *optval, unsigned int optlen)
{
mm_segment_t oldfs = get_fs();
+ char __user *uoptval;
int err;
+ uoptval = (char __user __force *) optval;
+
set_fs(KERNEL_DS);
if (level == SOL_SOCKET)
- err = sock_setsockopt(sock, level, optname, optval, optlen);
+ err = sock_setsockopt(sock, level, optname, uoptval, optlen);
else
- err = sock->ops->setsockopt(sock, level, optname, optval,
+ err = sock->ops->setsockopt(sock, level, optname, uoptval,
optlen);
set_fs(oldfs);
return err;
diff --git a/net/sunrpc/Kconfig b/net/sunrpc/Kconfig
index 3376d7657185..8873fd8ddacd 100644
--- a/net/sunrpc/Kconfig
+++ b/net/sunrpc/Kconfig
@@ -36,22 +36,3 @@ config RPCSEC_GSS_KRB5
Kerberos support should be installed.
If unsure, say Y.
-
-config RPCSEC_GSS_SPKM3
- tristate "Secure RPC: SPKM3 mechanism (EXPERIMENTAL)"
- depends on SUNRPC && EXPERIMENTAL
- select SUNRPC_GSS
- select CRYPTO
- select CRYPTO_MD5
- select CRYPTO_DES
- select CRYPTO_CAST5
- select CRYPTO_CBC
- help
- Choose Y here to enable Secure RPC using the SPKM3 public key
- GSS-API mechanism (RFC 2025).
-
- Secure RPC calls with SPKM3 require an auxiliary userspace
- daemon which may be found in the Linux nfs-utils package
- available from http://linux-nfs.org/.
-
- If unsure, say N.
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index e9eaaf7d43c1..afe67849269f 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -595,7 +595,7 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
int
rpcauth_refreshcred(struct rpc_task *task)
{
- struct rpc_cred *cred = task->tk_rqstp->rq_cred;
+ struct rpc_cred *cred;
int err;
cred = task->tk_rqstp->rq_cred;
@@ -658,7 +658,7 @@ out1:
return err;
}
-void __exit rpcauth_remove_module(void)
+void rpcauth_remove_module(void)
{
rpc_destroy_authunix();
rpc_destroy_generic_auth();
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c
index 43162bb3b78f..e010a015d996 100644
--- a/net/sunrpc/auth_generic.c
+++ b/net/sunrpc/auth_generic.c
@@ -158,7 +158,7 @@ int __init rpc_init_generic_auth(void)
return rpcauth_init_credcache(&generic_auth);
}
-void __exit rpc_destroy_generic_auth(void)
+void rpc_destroy_generic_auth(void)
{
rpcauth_destroy_credcache(&generic_auth);
}
diff --git a/net/sunrpc/auth_gss/Makefile b/net/sunrpc/auth_gss/Makefile
index 74a231735f67..7350d86a32ee 100644
--- a/net/sunrpc/auth_gss/Makefile
+++ b/net/sunrpc/auth_gss/Makefile
@@ -11,8 +11,3 @@ obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o
rpcsec_gss_krb5-objs := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \
gss_krb5_seqnum.o gss_krb5_wrap.o gss_krb5_crypto.o gss_krb5_keys.o
-
-obj-$(CONFIG_RPCSEC_GSS_SPKM3) += rpcsec_gss_spkm3.o
-
-rpcsec_gss_spkm3-objs := gss_spkm3_mech.o gss_spkm3_seal.o gss_spkm3_unseal.o \
- gss_spkm3_token.o
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 12c485982814..3835ce35e224 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -1050,7 +1050,7 @@ gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
out:
if (acred->machine_cred != gss_cred->gc_machine_cred)
return 0;
- return (rc->cr_uid == acred->uid);
+ return rc->cr_uid == acred->uid;
}
/*
diff --git a/net/sunrpc/auth_gss/gss_generic_token.c b/net/sunrpc/auth_gss/gss_generic_token.c
index 310b78e99456..c586e92bcf76 100644
--- a/net/sunrpc/auth_gss/gss_generic_token.c
+++ b/net/sunrpc/auth_gss/gss_generic_token.c
@@ -76,19 +76,19 @@ static int
der_length_size( int length)
{
if (length < (1<<7))
- return(1);
+ return 1;
else if (length < (1<<8))
- return(2);
+ return 2;
#if (SIZEOF_INT == 2)
else
- return(3);
+ return 3;
#else
else if (length < (1<<16))
- return(3);
+ return 3;
else if (length < (1<<24))
- return(4);
+ return 4;
else
- return(5);
+ return 5;
#endif
}
@@ -121,14 +121,14 @@ der_read_length(unsigned char **buf, int *bufsize)
int ret;
if (*bufsize < 1)
- return(-1);
+ return -1;
sf = *(*buf)++;
(*bufsize)--;
if (sf & 0x80) {
if ((sf &= 0x7f) > ((*bufsize)-1))
- return(-1);
+ return -1;
if (sf > SIZEOF_INT)
- return (-1);
+ return -1;
ret = 0;
for (; sf; sf--) {
ret = (ret<<8) + (*(*buf)++);
@@ -138,7 +138,7 @@ der_read_length(unsigned char **buf, int *bufsize)
ret = sf;
}
- return(ret);
+ return ret;
}
/* returns the length of a token, given the mech oid and the body size */
@@ -148,7 +148,7 @@ g_token_size(struct xdr_netobj *mech, unsigned int body_size)
{
/* set body_size to sequence contents size */
body_size += 2 + (int) mech->len; /* NEED overflow check */
- return(1 + der_length_size(body_size) + body_size);
+ return 1 + der_length_size(body_size) + body_size;
}
EXPORT_SYMBOL_GPL(g_token_size);
@@ -186,27 +186,27 @@ g_verify_token_header(struct xdr_netobj *mech, int *body_size,
int ret = 0;
if ((toksize-=1) < 0)
- return(G_BAD_TOK_HEADER);
+ return G_BAD_TOK_HEADER;
if (*buf++ != 0x60)
- return(G_BAD_TOK_HEADER);
+ return G_BAD_TOK_HEADER;
if ((seqsize = der_read_length(&buf, &toksize)) < 0)
- return(G_BAD_TOK_HEADER);
+ return G_BAD_TOK_HEADER;
if (seqsize != toksize)
- return(G_BAD_TOK_HEADER);
+ return G_BAD_TOK_HEADER;
if ((toksize-=1) < 0)
- return(G_BAD_TOK_HEADER);
+ return G_BAD_TOK_HEADER;
if (*buf++ != 0x06)
- return(G_BAD_TOK_HEADER);
+ return G_BAD_TOK_HEADER;
if ((toksize-=1) < 0)
- return(G_BAD_TOK_HEADER);
+ return G_BAD_TOK_HEADER;
toid.len = *buf++;
if ((toksize-=toid.len) < 0)
- return(G_BAD_TOK_HEADER);
+ return G_BAD_TOK_HEADER;
toid.data = buf;
buf+=toid.len;
@@ -217,17 +217,17 @@ g_verify_token_header(struct xdr_netobj *mech, int *body_size,
to return G_BAD_TOK_HEADER if the token header is in fact bad */
if ((toksize-=2) < 0)
- return(G_BAD_TOK_HEADER);
+ return G_BAD_TOK_HEADER;
if (ret)
- return(ret);
+ return ret;
if (!ret) {
*buf_in = buf;
*body_size = toksize;
}
- return(ret);
+ return ret;
}
EXPORT_SYMBOL_GPL(g_verify_token_header);
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 778e5dfc5144..f375decc024b 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -427,7 +427,7 @@ static int
context_derive_keys_rc4(struct krb5_ctx *ctx)
{
struct crypto_hash *hmac;
- char sigkeyconstant[] = "signaturekey";
+ static const char sigkeyconstant[] = "signaturekey";
int slen = strlen(sigkeyconstant) + 1; /* include null terminator */
struct hash_desc desc;
struct scatterlist sg[1];
diff --git a/net/sunrpc/auth_gss/gss_krb5_seqnum.c b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
index 415c013ba382..62ac90c62cb1 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seqnum.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
@@ -162,5 +162,5 @@ krb5_get_seq_num(struct krb5_ctx *kctx,
*seqnum = ((plain[0]) |
(plain[1] << 8) | (plain[2] << 16) | (plain[3] << 24));
- return (0);
+ return 0;
}
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
index 2689de39dc78..8b4061049d76 100644
--- a/net/sunrpc/auth_gss/gss_mech_switch.c
+++ b/net/sunrpc/auth_gss/gss_mech_switch.c
@@ -331,7 +331,7 @@ gss_delete_sec_context(struct gss_ctx **context_handle)
*context_handle);
if (!*context_handle)
- return(GSS_S_NO_CONTEXT);
+ return GSS_S_NO_CONTEXT;
if ((*context_handle)->internal_ctx_id)
(*context_handle)->mech_type->gm_ops
->gss_delete_sec_context((*context_handle)
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
deleted file mode 100644
index adade3d313f2..000000000000
--- a/net/sunrpc/auth_gss/gss_spkm3_mech.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * linux/net/sunrpc/gss_spkm3_mech.c
- *
- * Copyright (c) 2003 The Regents of the University of Michigan.
- * All rights reserved.
- *
- * Andy Adamson <andros@umich.edu>
- * J. Bruce Fields <bfields@umich.edu>
- *
- * 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 University 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 ``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 REGENTS 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/err.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/sunrpc/auth.h>
-#include <linux/in.h>
-#include <linux/sunrpc/svcauth_gss.h>
-#include <linux/sunrpc/gss_spkm3.h>
-#include <linux/sunrpc/xdr.h>
-#include <linux/crypto.h>
-
-#ifdef RPC_DEBUG
-# define RPCDBG_FACILITY RPCDBG_AUTH
-#endif
-
-static const void *
-simple_get_bytes(const void *p, const void *end, void *res, int len)
-{
- const void *q = (const void *)((const char *)p + len);
- if (unlikely(q > end || q < p))
- return ERR_PTR(-EFAULT);
- memcpy(res, p, len);
- return q;
-}
-
-static const void *
-simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res)
-{
- const void *q;
- unsigned int len;
- p = simple_get_bytes(p, end, &len, sizeof(len));
- if (IS_ERR(p))
- return p;
- res->len = len;
- if (len == 0) {
- res->data = NULL;
- return p;
- }
- q = (const void *)((const char *)p + len);
- if (unlikely(q > end || q < p))
- return ERR_PTR(-EFAULT);
- res->data = kmemdup(p, len, GFP_NOFS);
- if (unlikely(res->data == NULL))
- return ERR_PTR(-ENOMEM);
- return q;
-}
-
-static int
-gss_import_sec_context_spkm3(const void *p, size_t len,
- struct gss_ctx *ctx_id,
- gfp_t gfp_mask)
-{
- const void *end = (const void *)((const char *)p + len);
- struct spkm3_ctx *ctx;
- int version;
-
- if (!(ctx = kzalloc(sizeof(*ctx), gfp_mask)))
- goto out_err;
-
- p = simple_get_bytes(p, end, &version, sizeof(version));
- if (IS_ERR(p))
- goto out_err_free_ctx;
- if (version != 1) {
- dprintk("RPC: unknown spkm3 token format: "
- "obsolete nfs-utils?\n");
- p = ERR_PTR(-EINVAL);
- goto out_err_free_ctx;
- }
-
- p = simple_get_netobj(p, end, &ctx->ctx_id);
- if (IS_ERR(p))
- goto out_err_free_ctx;
-
- p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime));
- if (IS_ERR(p))
- goto out_err_free_ctx_id;
-
- p = simple_get_netobj(p, end, &ctx->mech_used);
- if (IS_ERR(p))
- goto out_err_free_ctx_id;
-
- p = simple_get_bytes(p, end, &ctx->ret_flags, sizeof(ctx->ret_flags));
- if (IS_ERR(p))
- goto out_err_free_mech;
-
- p = simple_get_netobj(p, end, &ctx->conf_alg);
- if (IS_ERR(p))
- goto out_err_free_mech;
-
- p = simple_get_netobj(p, end, &ctx->derived_conf_key);
- if (IS_ERR(p))
- goto out_err_free_conf_alg;
-
- p = simple_get_netobj(p, end, &ctx->intg_alg);
- if (IS_ERR(p))
- goto out_err_free_conf_key;
-
- p = simple_get_netobj(p, end, &ctx->derived_integ_key);
- if (IS_ERR(p))
- goto out_err_free_intg_alg;
-
- if (p != end) {
- p = ERR_PTR(-EFAULT);
- goto out_err_free_intg_key;
- }
-
- ctx_id->internal_ctx_id = ctx;
-
- dprintk("RPC: Successfully imported new spkm context.\n");
- return 0;
-
-out_err_free_intg_key:
- kfree(ctx->derived_integ_key.data);
-out_err_free_intg_alg:
- kfree(ctx->intg_alg.data);
-out_err_free_conf_key:
- kfree(ctx->derived_conf_key.data);
-out_err_free_conf_alg:
- kfree(ctx->conf_alg.data);
-out_err_free_mech:
- kfree(ctx->mech_used.data);
-out_err_free_ctx_id:
- kfree(ctx->ctx_id.data);
-out_err_free_ctx:
- kfree(ctx);
-out_err:
- return PTR_ERR(p);
-}
-
-static void
-gss_delete_sec_context_spkm3(void *internal_ctx)
-{
- struct spkm3_ctx *sctx = internal_ctx;
-
- kfree(sctx->derived_integ_key.data);
- kfree(sctx->intg_alg.data);
- kfree(sctx->derived_conf_key.data);
- kfree(sctx->conf_alg.data);
- kfree(sctx->mech_used.data);
- kfree(sctx->ctx_id.data);
- kfree(sctx);
-}
-
-static u32
-gss_verify_mic_spkm3(struct gss_ctx *ctx,
- struct xdr_buf *signbuf,
- struct xdr_netobj *checksum)
-{
- u32 maj_stat = 0;
- struct spkm3_ctx *sctx = ctx->internal_ctx_id;
-
- maj_stat = spkm3_read_token(sctx, checksum, signbuf, SPKM_MIC_TOK);
-
- dprintk("RPC: gss_verify_mic_spkm3 returning %d\n", maj_stat);
- return maj_stat;
-}
-
-static u32
-gss_get_mic_spkm3(struct gss_ctx *ctx,
- struct xdr_buf *message_buffer,
- struct xdr_netobj *message_token)
-{
- u32 err = 0;
- struct spkm3_ctx *sctx = ctx->internal_ctx_id;
-
- err = spkm3_make_token(sctx, message_buffer,
- message_token, SPKM_MIC_TOK);
- dprintk("RPC: gss_get_mic_spkm3 returning %d\n", err);
- return err;
-}
-
-static const struct gss_api_ops gss_spkm3_ops = {
- .gss_import_sec_context = gss_import_sec_context_spkm3,
- .gss_get_mic = gss_get_mic_spkm3,
- .gss_verify_mic = gss_verify_mic_spkm3,
- .gss_delete_sec_context = gss_delete_sec_context_spkm3,
-};
-
-static struct pf_desc gss_spkm3_pfs[] = {
- {RPC_AUTH_GSS_SPKM, RPC_GSS_SVC_NONE, "spkm3"},
- {RPC_AUTH_GSS_SPKMI, RPC_GSS_SVC_INTEGRITY, "spkm3i"},
-};
-
-static struct gss_api_mech gss_spkm3_mech = {
- .gm_name = "spkm3",
- .gm_owner = THIS_MODULE,
- .gm_oid = {7, "\053\006\001\005\005\001\003"},
- .gm_ops = &gss_spkm3_ops,
- .gm_pf_num = ARRAY_SIZE(gss_spkm3_pfs),
- .gm_pfs = gss_spkm3_pfs,
-};
-
-static int __init init_spkm3_module(void)
-{
- int status;
-
- status = gss_mech_register(&gss_spkm3_mech);
- if (status)
- printk("Failed to register spkm3 gss mechanism!\n");
- return status;
-}
-
-static void __exit cleanup_spkm3_module(void)
-{
- gss_mech_unregister(&gss_spkm3_mech);
-}
-
-MODULE_LICENSE("GPL");
-module_init(init_spkm3_module);
-module_exit(cleanup_spkm3_module);
diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c
deleted file mode 100644
index 5a3a65a0e2b4..000000000000
--- a/net/sunrpc/auth_gss/gss_spkm3_seal.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * linux/net/sunrpc/gss_spkm3_seal.c
- *
- * Copyright (c) 2003 The Regents of the University of Michigan.
- * All rights reserved.
- *
- * Andy Adamson <andros@umich.edu>
- *
- * 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 University 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 ``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 REGENTS 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/types.h>
-#include <linux/jiffies.h>
-#include <linux/sunrpc/gss_spkm3.h>
-#include <linux/random.h>
-#include <linux/crypto.h>
-#include <linux/pagemap.h>
-#include <linux/scatterlist.h>
-#include <linux/sunrpc/xdr.h>
-
-#ifdef RPC_DEBUG
-# define RPCDBG_FACILITY RPCDBG_AUTH
-#endif
-
-const struct xdr_netobj hmac_md5_oid = { 8, "\x2B\x06\x01\x05\x05\x08\x01\x01"};
-const struct xdr_netobj cast5_cbc_oid = {9, "\x2A\x86\x48\x86\xF6\x7D\x07\x42\x0A"};
-
-/*
- * spkm3_make_token()
- *
- * Only SPKM_MIC_TOK with md5 intg-alg is supported
- */
-
-u32
-spkm3_make_token(struct spkm3_ctx *ctx,
- struct xdr_buf * text, struct xdr_netobj * token,
- int toktype)
-{
- s32 checksum_type;
- char tokhdrbuf[25];
- char cksumdata[16];
- struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
- struct xdr_netobj mic_hdr = {.len = 0, .data = tokhdrbuf};
- int tokenlen = 0;
- unsigned char *ptr;
- s32 now;
- int ctxelen = 0, ctxzbit = 0;
- int md5elen = 0, md5zbit = 0;
-
- now = jiffies;
-
- if (ctx->ctx_id.len != 16) {
- dprintk("RPC: spkm3_make_token BAD ctx_id.len %d\n",
- ctx->ctx_id.len);
- goto out_err;
- }
-
- if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) {
- dprintk("RPC: gss_spkm3_seal: unsupported I-ALG "
- "algorithm. only support hmac-md5 I-ALG.\n");
- goto out_err;
- } else
- checksum_type = CKSUMTYPE_HMAC_MD5;
-
- if (!g_OID_equal(&ctx->conf_alg, &cast5_cbc_oid)) {
- dprintk("RPC: gss_spkm3_seal: unsupported C-ALG "
- "algorithm\n");
- goto out_err;
- }
-
- if (toktype == SPKM_MIC_TOK) {
- /* Calculate checksum over the mic-header */
- asn1_bitstring_len(&ctx->ctx_id, &ctxelen, &ctxzbit);
- spkm3_mic_header(&mic_hdr.data, &mic_hdr.len, ctx->ctx_id.data,
- ctxelen, ctxzbit);
- if (make_spkm3_checksum(checksum_type, &ctx->derived_integ_key,
- (char *)mic_hdr.data, mic_hdr.len,
- text, 0, &md5cksum))
- goto out_err;
-
- asn1_bitstring_len(&md5cksum, &md5elen, &md5zbit);
- tokenlen = 10 + ctxelen + 1 + md5elen + 1;
-
- /* Create token header using generic routines */
- token->len = g_token_size(&ctx->mech_used, tokenlen + 2);
-
- ptr = token->data;
- g_make_token_header(&ctx->mech_used, tokenlen + 2, &ptr);
-
- spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit);
- } else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */
- dprintk("RPC: gss_spkm3_seal: SPKM_WRAP_TOK "
- "not supported\n");
- goto out_err;
- }
-
- /* XXX need to implement sequence numbers, and ctx->expired */
-
- return GSS_S_COMPLETE;
-out_err:
- token->data = NULL;
- token->len = 0;
- return GSS_S_FAILURE;
-}
-
-static int
-spkm3_checksummer(struct scatterlist *sg, void *data)
-{
- struct hash_desc *desc = data;
-
- return crypto_hash_update(desc, sg, sg->length);
-}
-
-/* checksum the plaintext data and hdrlen bytes of the token header */
-s32
-make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header,
- unsigned int hdrlen, struct xdr_buf *body,
- unsigned int body_offset, struct xdr_netobj *cksum)
-{
- char *cksumname;
- struct hash_desc desc; /* XXX add to ctx? */
- struct scatterlist sg[1];
- int err;
-
- switch (cksumtype) {
- case CKSUMTYPE_HMAC_MD5:
- cksumname = "hmac(md5)";
- break;
- default:
- dprintk("RPC: spkm3_make_checksum:"
- " unsupported checksum %d", cksumtype);
- return GSS_S_FAILURE;
- }
-
- if (key->data == NULL || key->len <= 0) return GSS_S_FAILURE;
-
- desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(desc.tfm))
- return GSS_S_FAILURE;
- cksum->len = crypto_hash_digestsize(desc.tfm);
- desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
-
- err = crypto_hash_setkey(desc.tfm, key->data, key->len);
- if (err)
- goto out;
-
- err = crypto_hash_init(&desc);
- if (err)
- goto out;
-
- sg_init_one(sg, header, hdrlen);
- crypto_hash_update(&desc, sg, sg->length);
-
- xdr_process_buf(body, body_offset, body->len - body_offset,
- spkm3_checksummer, &desc);
- crypto_hash_final(&desc, cksum->data);
-
-out:
- crypto_free_hash(desc.tfm);
-
- return err ? GSS_S_FAILURE : 0;
-}
diff --git a/net/sunrpc/auth_gss/gss_spkm3_token.c b/net/sunrpc/auth_gss/gss_spkm3_token.c
deleted file mode 100644
index a99825d7caa0..000000000000
--- a/net/sunrpc/auth_gss/gss_spkm3_token.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * linux/net/sunrpc/gss_spkm3_token.c
- *
- * Copyright (c) 2003 The Regents of the University of Michigan.
- * All rights reserved.
- *
- * Andy Adamson <andros@umich.edu>
- *
- * 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 University 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 ``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 REGENTS 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/types.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
-#include <linux/sunrpc/gss_spkm3.h>
-#include <linux/random.h>
-#include <linux/crypto.h>
-
-#ifdef RPC_DEBUG
-# define RPCDBG_FACILITY RPCDBG_AUTH
-#endif
-
-/*
- * asn1_bitstring_len()
- *
- * calculate the asn1 bitstring length of the xdr_netobject
- */
-void
-asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits)
-{
- int i, zbit = 0,elen = in->len;
- char *ptr;
-
- ptr = &in->data[in->len -1];
-
- /* count trailing 0's */
- for(i = in->len; i > 0; i--) {
- if (*ptr == 0) {
- ptr--;
- elen--;
- } else
- break;
- }
-
- /* count number of 0 bits in final octet */
- ptr = &in->data[elen - 1];
- for(i = 0; i < 8; i++) {
- short mask = 0x01;
-
- if (!((mask << i) & *ptr))
- zbit++;
- else
- break;
- }
- *enclen = elen;
- *zerobits = zbit;
-}
-
-/*
- * decode_asn1_bitstring()
- *
- * decode a bitstring into a buffer of the expected length.
- * enclen = bit string length
- * explen = expected length (define in rfc)
- */
-int
-decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, int explen)
-{
- if (!(out->data = kzalloc(explen,GFP_NOFS)))
- return 0;
- out->len = explen;
- memcpy(out->data, in, enclen);
- return 1;
-}
-
-/*
- * SPKMInnerContextToken choice SPKM_MIC asn1 token layout
- *
- * contextid is always 16 bytes plain data. max asn1 bitstring len = 17.
- *
- * tokenlen = pos[0] to end of token (max pos[45] with MD5 cksum)
- *
- * pos value
- * ----------
- * [0] a4 SPKM-MIC tag
- * [1] ?? innertoken length (max 44)
- *
- *
- * tok_hdr piece of checksum data starts here
- *
- * the maximum mic-header len = 9 + 17 = 26
- * mic-header
- * ----------
- * [2] 30 SEQUENCE tag
- * [3] ?? mic-header length: (max 23) = TokenID + ContextID
- *
- * TokenID - all fields constant and can be hardcoded
- * -------
- * [4] 02 Type 2
- * [5] 02 Length 2
- * [6][7] 01 01 TokenID (SPKM_MIC_TOK)
- *
- * ContextID - encoded length not constant, calculated
- * ---------
- * [8] 03 Type 3
- * [9] ?? encoded length
- * [10] ?? ctxzbit
- * [11] contextid
- *
- * mic_header piece of checksum data ends here.
- *
- * int-cksum - encoded length not constant, calculated
- * ---------
- * [??] 03 Type 3
- * [??] ?? encoded length
- * [??] ?? md5zbit
- * [??] int-cksum (NID_md5 = 16)
- *
- * maximum SPKM-MIC innercontext token length =
- * 10 + encoded contextid_size(17 max) + 2 + encoded
- * cksum_size (17 maxfor NID_md5) = 46
- */
-
-/*
- * spkm3_mic_header()
- *
- * Prepare the SPKM_MIC_TOK mic-header for check-sum calculation
- * elen: 16 byte context id asn1 bitstring encoded length
- */
-void
-spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen, unsigned char *ctxdata, int elen, int zbit)
-{
- char *hptr = *hdrbuf;
- char *top = *hdrbuf;
-
- *(u8 *)hptr++ = 0x30;
- *(u8 *)hptr++ = elen + 7; /* on the wire header length */
-
- /* tokenid */
- *(u8 *)hptr++ = 0x02;
- *(u8 *)hptr++ = 0x02;
- *(u8 *)hptr++ = 0x01;
- *(u8 *)hptr++ = 0x01;
-
- /* coniextid */
- *(u8 *)hptr++ = 0x03;
- *(u8 *)hptr++ = elen + 1; /* add 1 to include zbit */
- *(u8 *)hptr++ = zbit;
- memcpy(hptr, ctxdata, elen);
- hptr += elen;
- *hdrlen = hptr - top;
-}
-
-/*
- * spkm3_mic_innercontext_token()
- *
- * *tokp points to the beginning of the SPKM_MIC token described
- * in rfc 2025, section 3.2.1:
- *
- * toklen is the inner token length
- */
-void
-spkm3_make_mic_token(unsigned char **tokp, int toklen, struct xdr_netobj *mic_hdr, struct xdr_netobj *md5cksum, int md5elen, int md5zbit)
-{
- unsigned char *ict = *tokp;
-
- *(u8 *)ict++ = 0xa4;
- *(u8 *)ict++ = toklen;
- memcpy(ict, mic_hdr->data, mic_hdr->len);
- ict += mic_hdr->len;
-
- *(u8 *)ict++ = 0x03;
- *(u8 *)ict++ = md5elen + 1; /* add 1 to include zbit */
- *(u8 *)ict++ = md5zbit;
- memcpy(ict, md5cksum->data, md5elen);
-}
-
-u32
-spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, unsigned char **cksum)
-{
- struct xdr_netobj spkm3_ctx_id = {.len =0, .data = NULL};
- unsigned char *ptr = *tokp;
- int ctxelen;
- u32 ret = GSS_S_DEFECTIVE_TOKEN;
-
- /* spkm3 innercontext token preamble */
- if ((ptr[0] != 0xa4) || (ptr[2] != 0x30)) {
- dprintk("RPC: BAD SPKM ictoken preamble\n");
- goto out;
- }
-
- *mic_hdrlen = ptr[3];
-
- /* token type */
- if ((ptr[4] != 0x02) || (ptr[5] != 0x02)) {
- dprintk("RPC: BAD asn1 SPKM3 token type\n");
- goto out;
- }
-
- /* only support SPKM_MIC_TOK */
- if((ptr[6] != 0x01) || (ptr[7] != 0x01)) {
- dprintk("RPC: ERROR unsupported SPKM3 token\n");
- goto out;
- }
-
- /* contextid */
- if (ptr[8] != 0x03) {
- dprintk("RPC: BAD SPKM3 asn1 context-id type\n");
- goto out;
- }
-
- ctxelen = ptr[9];
- if (ctxelen > 17) { /* length includes asn1 zbit octet */
- dprintk("RPC: BAD SPKM3 contextid len %d\n", ctxelen);
- goto out;
- }
-
- /* ignore ptr[10] */
-
- if(!decode_asn1_bitstring(&spkm3_ctx_id, &ptr[11], ctxelen - 1, 16))
- goto out;
-
- /*
- * in the current implementation: the optional int-alg is not present
- * so the default int-alg (md5) is used the optional snd-seq field is
- * also not present
- */
-
- if (*mic_hdrlen != 6 + ctxelen) {
- dprintk("RPC: BAD SPKM_ MIC_TOK header len %d: we only "
- "support default int-alg (should be absent) "
- "and do not support snd-seq\n", *mic_hdrlen);
- goto out;
- }
- /* checksum */
- *cksum = (&ptr[10] + ctxelen); /* ctxelen includes ptr[10] */
-
- ret = GSS_S_COMPLETE;
-out:
- kfree(spkm3_ctx_id.data);
- return ret;
-}
-
diff --git a/net/sunrpc/auth_gss/gss_spkm3_unseal.c b/net/sunrpc/auth_gss/gss_spkm3_unseal.c
deleted file mode 100644
index cc21ee860bb6..000000000000
--- a/net/sunrpc/auth_gss/gss_spkm3_unseal.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * linux/net/sunrpc/gss_spkm3_unseal.c
- *
- * Copyright (c) 2003 The Regents of the University of Michigan.
- * All rights reserved.
- *
- * Andy Adamson <andros@umich.edu>
- *
- * 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 University 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 ``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 REGENTS 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/types.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
-#include <linux/sunrpc/gss_spkm3.h>
-#include <linux/crypto.h>
-
-#ifdef RPC_DEBUG
-# define RPCDBG_FACILITY RPCDBG_AUTH
-#endif
-
-/*
- * spkm3_read_token()
- *
- * only SPKM_MIC_TOK with md5 intg-alg is supported
- */
-u32
-spkm3_read_token(struct spkm3_ctx *ctx,
- struct xdr_netobj *read_token, /* checksum */
- struct xdr_buf *message_buffer, /* signbuf */
- int toktype)
-{
- s32 checksum_type;
- s32 code;
- struct xdr_netobj wire_cksum = {.len =0, .data = NULL};
- char cksumdata[16];
- struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
- unsigned char *ptr = (unsigned char *)read_token->data;
- unsigned char *cksum;
- int bodysize, md5elen;
- int mic_hdrlen;
- u32 ret = GSS_S_DEFECTIVE_TOKEN;
-
- if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used,
- &bodysize, &ptr, read_token->len))
- goto out;
-
- /* decode the token */
-
- if (toktype != SPKM_MIC_TOK) {
- dprintk("RPC: BAD SPKM3 token type: %d\n", toktype);
- goto out;
- }
-
- if ((ret = spkm3_verify_mic_token(&ptr, &mic_hdrlen, &cksum)))
- goto out;
-
- if (*cksum++ != 0x03) {
- dprintk("RPC: spkm3_read_token BAD checksum type\n");
- goto out;
- }
- md5elen = *cksum++;
- cksum++; /* move past the zbit */
-
- if (!decode_asn1_bitstring(&wire_cksum, cksum, md5elen - 1, 16))
- goto out;
-
- /* HARD CODED FOR MD5 */
-
- /* compute the checksum of the message.
- * ptr + 2 = start of header piece of checksum
- * mic_hdrlen + 2 = length of header piece of checksum
- */
- ret = GSS_S_DEFECTIVE_TOKEN;
- if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) {
- dprintk("RPC: gss_spkm3_seal: unsupported I-ALG "
- "algorithm\n");
- goto out;
- }
-
- checksum_type = CKSUMTYPE_HMAC_MD5;
-
- code = make_spkm3_checksum(checksum_type,
- &ctx->derived_integ_key, ptr + 2, mic_hdrlen + 2,
- message_buffer, 0, &md5cksum);
-
- if (code)
- goto out;
-
- ret = GSS_S_BAD_SIG;
- code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len);
- if (code) {
- dprintk("RPC: bad MIC checksum\n");
- goto out;
- }
-
-
- /* XXX: need to add expiration and sequencing */
- ret = GSS_S_COMPLETE;
-out:
- kfree(wire_cksum.data);
- return ret;
-}
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index cc385b3a59c2..dec2a6fc7c12 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -964,7 +964,7 @@ svcauth_gss_set_client(struct svc_rqst *rqstp)
if (rqstp->rq_gssclient == NULL)
return SVC_DENIED;
stat = svcauth_unix_set_client(rqstp);
- if (stat == SVC_DROP)
+ if (stat == SVC_DROP || stat == SVC_CLOSE)
return stat;
return SVC_OK;
}
@@ -1018,7 +1018,7 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
return SVC_DENIED;
memset(&rsikey, 0, sizeof(rsikey));
if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx))
- return SVC_DROP;
+ return SVC_CLOSE;
*authp = rpc_autherr_badverf;
if (svc_safe_getnetobj(argv, &tmpobj)) {
kfree(rsikey.in_handle.data);
@@ -1026,38 +1026,35 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
}
if (dup_netobj(&rsikey.in_token, &tmpobj)) {
kfree(rsikey.in_handle.data);
- return SVC_DROP;
+ return SVC_CLOSE;
}
/* Perform upcall, or find upcall result: */
rsip = rsi_lookup(&rsikey);
rsi_free(&rsikey);
if (!rsip)
- return SVC_DROP;
- switch (cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle)) {
- case -EAGAIN:
- case -ETIMEDOUT:
- case -ENOENT:
+ return SVC_CLOSE;
+ if (cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle) < 0)
/* No upcall result: */
- return SVC_DROP;
- case 0:
- ret = SVC_DROP;
- /* Got an answer to the upcall; use it: */
- if (gss_write_init_verf(rqstp, rsip))
- goto out;
- if (resv->iov_len + 4 > PAGE_SIZE)
- goto out;
- svc_putnl(resv, RPC_SUCCESS);
- if (svc_safe_putnetobj(resv, &rsip->out_handle))
- goto out;
- if (resv->iov_len + 3 * 4 > PAGE_SIZE)
- goto out;
- svc_putnl(resv, rsip->major_status);
- svc_putnl(resv, rsip->minor_status);
- svc_putnl(resv, GSS_SEQ_WIN);
- if (svc_safe_putnetobj(resv, &rsip->out_token))
- goto out;
- }
+ return SVC_CLOSE;
+
+ ret = SVC_CLOSE;
+ /* Got an answer to the upcall; use it: */
+ if (gss_write_init_verf(rqstp, rsip))
+ goto out;
+ if (resv->iov_len + 4 > PAGE_SIZE)
+ goto out;
+ svc_putnl(resv, RPC_SUCCESS);
+ if (svc_safe_putnetobj(resv, &rsip->out_handle))
+ goto out;
+ if (resv->iov_len + 3 * 4 > PAGE_SIZE)
+ goto out;
+ svc_putnl(resv, rsip->major_status);
+ svc_putnl(resv, rsip->minor_status);
+ svc_putnl(resv, GSS_SEQ_WIN);
+ if (svc_safe_putnetobj(resv, &rsip->out_token))
+ goto out;
+
ret = SVC_COMPLETE;
out:
cache_put(&rsip->h, &rsi_cache);
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 7dce81a926c5..e433e7580e27 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -33,15 +33,16 @@
#include <linux/sunrpc/cache.h>
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/rpc_pipe_fs.h>
+#include "netns.h"
#define RPCDBG_FACILITY RPCDBG_CACHE
-static int cache_defer_req(struct cache_req *req, struct cache_head *item);
+static void cache_defer_req(struct cache_req *req, struct cache_head *item);
static void cache_revisit_request(struct cache_head *item);
static void cache_init(struct cache_head *h)
{
- time_t now = get_seconds();
+ time_t now = seconds_since_boot();
h->next = NULL;
h->flags = 0;
kref_init(&h->ref);
@@ -51,7 +52,7 @@ static void cache_init(struct cache_head *h)
static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h)
{
- return (h->expiry_time < get_seconds()) ||
+ return (h->expiry_time < seconds_since_boot()) ||
(detail->flush_time > h->last_refresh);
}
@@ -126,7 +127,7 @@ static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch);
static void cache_fresh_locked(struct cache_head *head, time_t expiry)
{
head->expiry_time = expiry;
- head->last_refresh = get_seconds();
+ head->last_refresh = seconds_since_boot();
set_bit(CACHE_VALID, &head->flags);
}
@@ -237,7 +238,7 @@ int cache_check(struct cache_detail *detail,
/* now see if we want to start an upcall */
refresh_age = (h->expiry_time - h->last_refresh);
- age = get_seconds() - h->last_refresh;
+ age = seconds_since_boot() - h->last_refresh;
if (rqstp == NULL) {
if (rv == -EAGAIN)
@@ -252,7 +253,7 @@ int cache_check(struct cache_detail *detail,
cache_revisit_request(h);
if (rv == -EAGAIN) {
set_bit(CACHE_NEGATIVE, &h->flags);
- cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY);
+ cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);
cache_fresh_unlocked(h, detail);
rv = -ENOENT;
}
@@ -267,7 +268,8 @@ int cache_check(struct cache_detail *detail,
}
if (rv == -EAGAIN) {
- if (cache_defer_req(rqstp, h) < 0) {
+ cache_defer_req(rqstp, h);
+ if (!test_bit(CACHE_PENDING, &h->flags)) {
/* Request is not deferred */
rv = cache_is_valid(detail, h);
if (rv == -EAGAIN)
@@ -387,11 +389,11 @@ static int cache_clean(void)
return -1;
}
current_detail = list_entry(next, struct cache_detail, others);
- if (current_detail->nextcheck > get_seconds())
+ if (current_detail->nextcheck > seconds_since_boot())
current_index = current_detail->hash_size;
else {
current_index = 0;
- current_detail->nextcheck = get_seconds()+30*60;
+ current_detail->nextcheck = seconds_since_boot()+30*60;
}
}
@@ -476,7 +478,7 @@ EXPORT_SYMBOL_GPL(cache_flush);
void cache_purge(struct cache_detail *detail)
{
detail->flush_time = LONG_MAX;
- detail->nextcheck = get_seconds();
+ detail->nextcheck = seconds_since_boot();
cache_flush();
detail->flush_time = 1;
}
@@ -505,81 +507,155 @@ EXPORT_SYMBOL_GPL(cache_purge);
static DEFINE_SPINLOCK(cache_defer_lock);
static LIST_HEAD(cache_defer_list);
-static struct list_head cache_defer_hash[DFR_HASHSIZE];
+static struct hlist_head cache_defer_hash[DFR_HASHSIZE];
static int cache_defer_cnt;
-static int cache_defer_req(struct cache_req *req, struct cache_head *item)
+static void __unhash_deferred_req(struct cache_deferred_req *dreq)
+{
+ hlist_del_init(&dreq->hash);
+ if (!list_empty(&dreq->recent)) {
+ list_del_init(&dreq->recent);
+ cache_defer_cnt--;
+ }
+}
+
+static void __hash_deferred_req(struct cache_deferred_req *dreq, struct cache_head *item)
{
- struct cache_deferred_req *dreq, *discard;
int hash = DFR_HASH(item);
- if (cache_defer_cnt >= DFR_MAX) {
- /* too much in the cache, randomly drop this one,
- * or continue and drop the oldest below
- */
- if (net_random()&1)
- return -ENOMEM;
- }
- dreq = req->defer(req);
- if (dreq == NULL)
- return -ENOMEM;
+ INIT_LIST_HEAD(&dreq->recent);
+ hlist_add_head(&dreq->hash, &cache_defer_hash[hash]);
+}
+
+static void setup_deferral(struct cache_deferred_req *dreq,
+ struct cache_head *item,
+ int count_me)
+{
dreq->item = item;
spin_lock(&cache_defer_lock);
- list_add(&dreq->recent, &cache_defer_list);
-
- if (cache_defer_hash[hash].next == NULL)
- INIT_LIST_HEAD(&cache_defer_hash[hash]);
- list_add(&dreq->hash, &cache_defer_hash[hash]);
+ __hash_deferred_req(dreq, item);
- /* it is in, now maybe clean up */
- discard = NULL;
- if (++cache_defer_cnt > DFR_MAX) {
- discard = list_entry(cache_defer_list.prev,
- struct cache_deferred_req, recent);
- list_del_init(&discard->recent);
- list_del_init(&discard->hash);
- cache_defer_cnt--;
+ if (count_me) {
+ cache_defer_cnt++;
+ list_add(&dreq->recent, &cache_defer_list);
}
+
spin_unlock(&cache_defer_lock);
+}
+
+struct thread_deferred_req {
+ struct cache_deferred_req handle;
+ struct completion completion;
+};
+
+static void cache_restart_thread(struct cache_deferred_req *dreq, int too_many)
+{
+ struct thread_deferred_req *dr =
+ container_of(dreq, struct thread_deferred_req, handle);
+ complete(&dr->completion);
+}
+
+static void cache_wait_req(struct cache_req *req, struct cache_head *item)
+{
+ struct thread_deferred_req sleeper;
+ struct cache_deferred_req *dreq = &sleeper.handle;
+
+ sleeper.completion = COMPLETION_INITIALIZER_ONSTACK(sleeper.completion);
+ dreq->revisit = cache_restart_thread;
+
+ setup_deferral(dreq, item, 0);
+
+ if (!test_bit(CACHE_PENDING, &item->flags) ||
+ wait_for_completion_interruptible_timeout(
+ &sleeper.completion, req->thread_wait) <= 0) {
+ /* The completion wasn't completed, so we need
+ * to clean up
+ */
+ spin_lock(&cache_defer_lock);
+ if (!hlist_unhashed(&sleeper.handle.hash)) {
+ __unhash_deferred_req(&sleeper.handle);
+ spin_unlock(&cache_defer_lock);
+ } else {
+ /* cache_revisit_request already removed
+ * this from the hash table, but hasn't
+ * called ->revisit yet. It will very soon
+ * and we need to wait for it.
+ */
+ spin_unlock(&cache_defer_lock);
+ wait_for_completion(&sleeper.completion);
+ }
+ }
+}
+
+static void cache_limit_defers(void)
+{
+ /* Make sure we haven't exceed the limit of allowed deferred
+ * requests.
+ */
+ struct cache_deferred_req *discard = NULL;
+
+ if (cache_defer_cnt <= DFR_MAX)
+ return;
+
+ spin_lock(&cache_defer_lock);
+
+ /* Consider removing either the first or the last */
+ if (cache_defer_cnt > DFR_MAX) {
+ if (net_random() & 1)
+ discard = list_entry(cache_defer_list.next,
+ struct cache_deferred_req, recent);
+ else
+ discard = list_entry(cache_defer_list.prev,
+ struct cache_deferred_req, recent);
+ __unhash_deferred_req(discard);
+ }
+ spin_unlock(&cache_defer_lock);
if (discard)
- /* there was one too many */
discard->revisit(discard, 1);
+}
- if (!test_bit(CACHE_PENDING, &item->flags)) {
- /* must have just been validated... */
- cache_revisit_request(item);
- return -EAGAIN;
+static void cache_defer_req(struct cache_req *req, struct cache_head *item)
+{
+ struct cache_deferred_req *dreq;
+
+ if (req->thread_wait) {
+ cache_wait_req(req, item);
+ if (!test_bit(CACHE_PENDING, &item->flags))
+ return;
}
- return 0;
+ dreq = req->defer(req);
+ if (dreq == NULL)
+ return;
+ setup_deferral(dreq, item, 1);
+ if (!test_bit(CACHE_PENDING, &item->flags))
+ /* Bit could have been cleared before we managed to
+ * set up the deferral, so need to revisit just in case
+ */
+ cache_revisit_request(item);
+
+ cache_limit_defers();
}
static void cache_revisit_request(struct cache_head *item)
{
struct cache_deferred_req *dreq;
struct list_head pending;
-
- struct list_head *lp;
+ struct hlist_node *lp, *tmp;
int hash = DFR_HASH(item);
INIT_LIST_HEAD(&pending);
spin_lock(&cache_defer_lock);
- lp = cache_defer_hash[hash].next;
- if (lp) {
- while (lp != &cache_defer_hash[hash]) {
- dreq = list_entry(lp, struct cache_deferred_req, hash);
- lp = lp->next;
- if (dreq->item == item) {
- list_del_init(&dreq->hash);
- list_move(&dreq->recent, &pending);
- cache_defer_cnt--;
- }
+ hlist_for_each_entry_safe(dreq, lp, tmp, &cache_defer_hash[hash], hash)
+ if (dreq->item == item) {
+ __unhash_deferred_req(dreq);
+ list_add(&dreq->recent, &pending);
}
- }
+
spin_unlock(&cache_defer_lock);
while (!list_empty(&pending)) {
@@ -600,9 +676,8 @@ void cache_clean_deferred(void *owner)
list_for_each_entry_safe(dreq, tmp, &cache_defer_list, recent) {
if (dreq->owner == owner) {
- list_del_init(&dreq->hash);
- list_move(&dreq->recent, &pending);
- cache_defer_cnt--;
+ __unhash_deferred_req(dreq);
+ list_add(&dreq->recent, &pending);
}
}
spin_unlock(&cache_defer_lock);
@@ -901,7 +976,7 @@ static int cache_release(struct inode *inode, struct file *filp,
filp->private_data = NULL;
kfree(rp);
- cd->last_close = get_seconds();
+ cd->last_close = seconds_since_boot();
atomic_dec(&cd->readers);
}
module_put(cd->owner);
@@ -1014,6 +1089,23 @@ static void warn_no_listener(struct cache_detail *detail)
}
}
+static bool cache_listeners_exist(struct cache_detail *detail)
+{
+ if (atomic_read(&detail->readers))
+ return true;
+ if (detail->last_close == 0)
+ /* This cache was never opened */
+ return false;
+ if (detail->last_close < seconds_since_boot() - 30)
+ /*
+ * We allow for the possibility that someone might
+ * restart a userspace daemon without restarting the
+ * server; but after 30 seconds, we give up.
+ */
+ return false;
+ return true;
+}
+
/*
* register an upcall request to user-space and queue it up for read() by the
* upcall daemon.
@@ -1032,10 +1124,9 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h,
char *bp;
int len;
- if (atomic_read(&detail->readers) == 0 &&
- detail->last_close < get_seconds() - 30) {
- warn_no_listener(detail);
- return -EINVAL;
+ if (!cache_listeners_exist(detail)) {
+ warn_no_listener(detail);
+ return -EINVAL;
}
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
@@ -1094,13 +1185,19 @@ int qword_get(char **bpp, char *dest, int bufsize)
if (bp[0] == '\\' && bp[1] == 'x') {
/* HEX STRING */
bp += 2;
- while (isxdigit(bp[0]) && isxdigit(bp[1]) && len < bufsize) {
- int byte = isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
- bp++;
- byte <<= 4;
- byte |= isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
- *dest++ = byte;
- bp++;
+ while (len < bufsize) {
+ int h, l;
+
+ h = hex_to_bin(bp[0]);
+ if (h < 0)
+ break;
+
+ l = hex_to_bin(bp[1]);
+ if (l < 0)
+ break;
+
+ *dest++ = (h << 4) | l;
+ bp += 2;
len++;
}
} else {
@@ -1218,7 +1315,8 @@ static int c_show(struct seq_file *m, void *p)
ifdebug(CACHE)
seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n",
- cp->expiry_time, atomic_read(&cp->ref.refcount), cp->flags);
+ convert_to_wallclock(cp->expiry_time),
+ atomic_read(&cp->ref.refcount), cp->flags);
cache_get(cp);
if (cache_check(cd, cp, NULL))
/* cache_check does a cache_put on failure */
@@ -1284,7 +1382,7 @@ static ssize_t read_flush(struct file *file, char __user *buf,
unsigned long p = *ppos;
size_t len;
- sprintf(tbuf, "%lu\n", cd->flush_time);
+ sprintf(tbuf, "%lu\n", convert_to_wallclock(cd->flush_time));
len = strlen(tbuf);
if (p >= len)
return 0;
@@ -1302,19 +1400,20 @@ static ssize_t write_flush(struct file *file, const char __user *buf,
struct cache_detail *cd)
{
char tbuf[20];
- char *ep;
- long flushtime;
+ char *bp, *ep;
+
if (*ppos || count > sizeof(tbuf)-1)
return -EINVAL;
if (copy_from_user(tbuf, buf, count))
return -EFAULT;
tbuf[count] = 0;
- flushtime = simple_strtoul(tbuf, &ep, 0);
+ simple_strtoul(tbuf, &ep, 0);
if (*ep && *ep != '\n')
return -EINVAL;
- cd->flush_time = flushtime;
- cd->nextcheck = get_seconds();
+ bp = tbuf;
+ cd->flush_time = get_expiry(&bp);
+ cd->nextcheck = seconds_since_boot();
cache_flush();
*ppos += count;
@@ -1438,8 +1537,10 @@ static const struct file_operations cache_flush_operations_procfs = {
.llseek = no_llseek,
};
-static void remove_cache_proc_entries(struct cache_detail *cd)
+static void remove_cache_proc_entries(struct cache_detail *cd, struct net *net)
{
+ struct sunrpc_net *sn;
+
if (cd->u.procfs.proc_ent == NULL)
return;
if (cd->u.procfs.flush_ent)
@@ -1449,15 +1550,18 @@ static void remove_cache_proc_entries(struct cache_detail *cd)
if (cd->u.procfs.content_ent)
remove_proc_entry("content", cd->u.procfs.proc_ent);
cd->u.procfs.proc_ent = NULL;
- remove_proc_entry(cd->name, proc_net_rpc);
+ sn = net_generic(net, sunrpc_net_id);
+ remove_proc_entry(cd->name, sn->proc_net_rpc);
}
#ifdef CONFIG_PROC_FS
-static int create_cache_proc_entries(struct cache_detail *cd)
+static int create_cache_proc_entries(struct cache_detail *cd, struct net *net)
{
struct proc_dir_entry *p;
+ struct sunrpc_net *sn;
- cd->u.procfs.proc_ent = proc_mkdir(cd->name, proc_net_rpc);
+ sn = net_generic(net, sunrpc_net_id);
+ cd->u.procfs.proc_ent = proc_mkdir(cd->name, sn->proc_net_rpc);
if (cd->u.procfs.proc_ent == NULL)
goto out_nomem;
cd->u.procfs.channel_ent = NULL;
@@ -1488,11 +1592,11 @@ static int create_cache_proc_entries(struct cache_detail *cd)
}
return 0;
out_nomem:
- remove_cache_proc_entries(cd);
+ remove_cache_proc_entries(cd, net);
return -ENOMEM;
}
#else /* CONFIG_PROC_FS */
-static int create_cache_proc_entries(struct cache_detail *cd)
+static int create_cache_proc_entries(struct cache_detail *cd, struct net *net)
{
return 0;
}
@@ -1503,23 +1607,33 @@ void __init cache_initialize(void)
INIT_DELAYED_WORK_DEFERRABLE(&cache_cleaner, do_cache_clean);
}
-int cache_register(struct cache_detail *cd)
+int cache_register_net(struct cache_detail *cd, struct net *net)
{
int ret;
sunrpc_init_cache_detail(cd);
- ret = create_cache_proc_entries(cd);
+ ret = create_cache_proc_entries(cd, net);
if (ret)
sunrpc_destroy_cache_detail(cd);
return ret;
}
+
+int cache_register(struct cache_detail *cd)
+{
+ return cache_register_net(cd, &init_net);
+}
EXPORT_SYMBOL_GPL(cache_register);
-void cache_unregister(struct cache_detail *cd)
+void cache_unregister_net(struct cache_detail *cd, struct net *net)
{
- remove_cache_proc_entries(cd);
+ remove_cache_proc_entries(cd, net);
sunrpc_destroy_cache_detail(cd);
}
+
+void cache_unregister(struct cache_detail *cd)
+{
+ cache_unregister_net(cd, &init_net);
+}
EXPORT_SYMBOL_GPL(cache_unregister);
static ssize_t cache_read_pipefs(struct file *filp, char __user *buf,
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index fa5549079d79..9dab9573be41 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -284,6 +284,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
struct rpc_xprt *xprt;
struct rpc_clnt *clnt;
struct xprt_create xprtargs = {
+ .net = args->net,
.ident = args->protocol,
.srcaddr = args->saddress,
.dstaddr = args->address,
@@ -1675,7 +1676,7 @@ rpc_verify_header(struct rpc_task *task)
rpcauth_invalcred(task);
/* Ensure we obtain a new XID! */
xprt_release(task);
- task->tk_action = call_refresh;
+ task->tk_action = call_reserve;
goto out_retry;
case RPC_AUTH_BADCRED:
case RPC_AUTH_BADVERF:
diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h
new file mode 100644
index 000000000000..d013bf211cae
--- /dev/null
+++ b/net/sunrpc/netns.h
@@ -0,0 +1,19 @@
+#ifndef __SUNRPC_NETNS_H__
+#define __SUNRPC_NETNS_H__
+
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+
+struct cache_detail;
+
+struct sunrpc_net {
+ struct proc_dir_entry *proc_net_rpc;
+ struct cache_detail *ip_map_cache;
+};
+
+extern int sunrpc_net_id;
+
+int ip_map_cache_create(struct net *);
+void ip_map_cache_destroy(struct net *);
+
+#endif
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 28bcd52e3ce9..7df92d237cb8 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -203,7 +203,7 @@ rpc_pipe_release(struct inode *inode, struct file *filp)
mutex_lock(&inode->i_mutex);
if (rpci->ops == NULL)
goto out;
- msg = (struct rpc_pipe_msg *)filp->private_data;
+ msg = filp->private_data;
if (msg != NULL) {
spin_lock(&inode->i_lock);
msg->errno = -EAGAIN;
@@ -325,7 +325,7 @@ rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
len = rpci->pipelen;
if (filp->private_data) {
struct rpc_pipe_msg *msg;
- msg = (struct rpc_pipe_msg *)filp->private_data;
+ msg = filp->private_data;
len += msg->len - msg->copied;
}
spin_unlock(&inode->i_lock);
@@ -445,6 +445,7 @@ rpc_get_inode(struct super_block *sb, umode_t mode)
struct inode *inode = new_inode(sb);
if (!inode)
return NULL;
+ inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch(mode & S_IFMT) {
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index dac219a56ae1..fa6d7ca2c851 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -177,6 +177,7 @@ static DEFINE_MUTEX(rpcb_create_local_mutex);
static int rpcb_create_local(void)
{
struct rpc_create_args args = {
+ .net = &init_net,
.protocol = XPRT_TRANSPORT_TCP,
.address = (struct sockaddr *)&rpcb_inaddr_loopback,
.addrsize = sizeof(rpcb_inaddr_loopback),
@@ -211,8 +212,9 @@ static int rpcb_create_local(void)
*/
clnt4 = rpc_bind_new_program(clnt, &rpcb_program, RPCBVERS_4);
if (IS_ERR(clnt4)) {
- dprintk("RPC: failed to create local rpcbind v4 "
- "cleint (errno %ld).\n", PTR_ERR(clnt4));
+ dprintk("RPC: failed to bind second program to "
+ "rpcbind v4 client (errno %ld).\n",
+ PTR_ERR(clnt4));
clnt4 = NULL;
}
@@ -228,6 +230,7 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
size_t salen, int proto, u32 version)
{
struct rpc_create_args args = {
+ .net = &init_net,
.protocol = proto,
.address = srvaddr,
.addrsize = salen,
@@ -247,7 +250,7 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
((struct sockaddr_in6 *)srvaddr)->sin6_port = htons(RPCBIND_PORT);
break;
default:
- return NULL;
+ return ERR_PTR(-EAFNOSUPPORT);
}
return rpc_create(&args);
@@ -475,57 +478,6 @@ int rpcb_v4_register(const u32 program, const u32 version,
return -EAFNOSUPPORT;
}
-/**
- * rpcb_getport_sync - obtain the port for an RPC service on a given host
- * @sin: address of remote peer
- * @prog: RPC program number to bind
- * @vers: RPC version number to bind
- * @prot: transport protocol to use to make this request
- *
- * Return value is the requested advertised port number,
- * or a negative errno value.
- *
- * Called from outside the RPC client in a synchronous task context.
- * Uses default timeout parameters specified by underlying transport.
- *
- * XXX: Needs to support IPv6
- */
-int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot)
-{
- struct rpcbind_args map = {
- .r_prog = prog,
- .r_vers = vers,
- .r_prot = prot,
- .r_port = 0,
- };
- struct rpc_message msg = {
- .rpc_proc = &rpcb_procedures2[RPCBPROC_GETPORT],
- .rpc_argp = &map,
- .rpc_resp = &map,
- };
- struct rpc_clnt *rpcb_clnt;
- int status;
-
- dprintk("RPC: %s(%pI4, %u, %u, %d)\n",
- __func__, &sin->sin_addr.s_addr, prog, vers, prot);
-
- rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
- sizeof(*sin), prot, RPCBVERS_2);
- if (IS_ERR(rpcb_clnt))
- return PTR_ERR(rpcb_clnt);
-
- status = rpc_call_sync(rpcb_clnt, &msg, 0);
- rpc_shutdown_client(rpcb_clnt);
-
- if (status >= 0) {
- if (map.r_port != 0)
- return map.r_port;
- status = -EACCES;
- }
- return status;
-}
-EXPORT_SYMBOL_GPL(rpcb_getport_sync);
-
static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbind_args *map, struct rpc_procinfo *proc)
{
struct rpc_message msg = {
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index cace6049e4a5..243fc09b164e 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -376,7 +376,7 @@ int rpc_queue_empty(struct rpc_wait_queue *queue)
spin_lock_bh(&queue->lock);
res = queue->qlen;
spin_unlock_bh(&queue->lock);
- return (res == 0);
+ return res == 0;
}
EXPORT_SYMBOL_GPL(rpc_queue_empty);
@@ -908,7 +908,7 @@ static int rpciod_start(void)
* Create the rpciod thread and wait for it to start.
*/
dprintk("RPC: creating workqueue rpciod\n");
- wq = create_workqueue("rpciod");
+ wq = alloc_workqueue("rpciod", WQ_RESCUER, 0);
rpciod_workqueue = wq;
return rpciod_workqueue != NULL;
}
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c
index ea1046f3f9a3..f71a73107ae9 100644
--- a/net/sunrpc/stats.c
+++ b/net/sunrpc/stats.c
@@ -22,11 +22,10 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svcsock.h>
#include <linux/sunrpc/metrics.h>
-#include <net/net_namespace.h>
-#define RPCDBG_FACILITY RPCDBG_MISC
+#include "netns.h"
-struct proc_dir_entry *proc_net_rpc = NULL;
+#define RPCDBG_FACILITY RPCDBG_MISC
/*
* Get RPC client stats
@@ -218,10 +217,11 @@ EXPORT_SYMBOL_GPL(rpc_print_iostats);
static inline struct proc_dir_entry *
do_register(const char *name, void *data, const struct file_operations *fops)
{
- rpc_proc_init();
- dprintk("RPC: registering /proc/net/rpc/%s\n", name);
+ struct sunrpc_net *sn;
- return proc_create_data(name, 0, proc_net_rpc, fops, data);
+ dprintk("RPC: registering /proc/net/rpc/%s\n", name);
+ sn = net_generic(&init_net, sunrpc_net_id);
+ return proc_create_data(name, 0, sn->proc_net_rpc, fops, data);
}
struct proc_dir_entry *
@@ -234,7 +234,10 @@ EXPORT_SYMBOL_GPL(rpc_proc_register);
void
rpc_proc_unregister(const char *name)
{
- remove_proc_entry(name, proc_net_rpc);
+ struct sunrpc_net *sn;
+
+ sn = net_generic(&init_net, sunrpc_net_id);
+ remove_proc_entry(name, sn->proc_net_rpc);
}
EXPORT_SYMBOL_GPL(rpc_proc_unregister);
@@ -248,25 +251,29 @@ EXPORT_SYMBOL_GPL(svc_proc_register);
void
svc_proc_unregister(const char *name)
{
- remove_proc_entry(name, proc_net_rpc);
+ struct sunrpc_net *sn;
+
+ sn = net_generic(&init_net, sunrpc_net_id);
+ remove_proc_entry(name, sn->proc_net_rpc);
}
EXPORT_SYMBOL_GPL(svc_proc_unregister);
-void
-rpc_proc_init(void)
+int rpc_proc_init(struct net *net)
{
+ struct sunrpc_net *sn;
+
dprintk("RPC: registering /proc/net/rpc\n");
- if (!proc_net_rpc)
- proc_net_rpc = proc_mkdir("rpc", init_net.proc_net);
+ sn = net_generic(net, sunrpc_net_id);
+ sn->proc_net_rpc = proc_mkdir("rpc", net->proc_net);
+ if (sn->proc_net_rpc == NULL)
+ return -ENOMEM;
+
+ return 0;
}
-void
-rpc_proc_exit(void)
+void rpc_proc_exit(struct net *net)
{
dprintk("RPC: unregistering /proc/net/rpc\n");
- if (proc_net_rpc) {
- proc_net_rpc = NULL;
- remove_proc_entry("rpc", init_net.proc_net);
- }
+ remove_proc_entry("rpc", net->proc_net);
}
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index c0d085013a2b..9d0809160994 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -22,7 +22,44 @@
#include <linux/sunrpc/rpc_pipe_fs.h>
#include <linux/sunrpc/xprtsock.h>
-extern struct cache_detail ip_map_cache, unix_gid_cache;
+#include "netns.h"
+
+int sunrpc_net_id;
+
+static __net_init int sunrpc_init_net(struct net *net)
+{
+ int err;
+
+ err = rpc_proc_init(net);
+ if (err)
+ goto err_proc;
+
+ err = ip_map_cache_create(net);
+ if (err)
+ goto err_ipmap;
+
+ return 0;
+
+err_ipmap:
+ rpc_proc_exit(net);
+err_proc:
+ return err;
+}
+
+static __net_exit void sunrpc_exit_net(struct net *net)
+{
+ ip_map_cache_destroy(net);
+ rpc_proc_exit(net);
+}
+
+static struct pernet_operations sunrpc_net_ops = {
+ .init = sunrpc_init_net,
+ .exit = sunrpc_exit_net,
+ .id = &sunrpc_net_id,
+ .size = sizeof(struct sunrpc_net),
+};
+
+extern struct cache_detail unix_gid_cache;
extern void cleanup_rpcb_clnt(void);
@@ -38,18 +75,22 @@ init_sunrpc(void)
err = rpcauth_init_module();
if (err)
goto out3;
+
+ cache_initialize();
+
+ err = register_pernet_subsys(&sunrpc_net_ops);
+ if (err)
+ goto out4;
#ifdef RPC_DEBUG
rpc_register_sysctl();
#endif
-#ifdef CONFIG_PROC_FS
- rpc_proc_init();
-#endif
- cache_initialize();
- cache_register(&ip_map_cache);
cache_register(&unix_gid_cache);
svc_init_xprt_sock(); /* svc sock transport */
init_socket_xprt(); /* clnt sock transport */
return 0;
+
+out4:
+ rpcauth_remove_module();
out3:
rpc_destroy_mempool();
out2:
@@ -67,14 +108,11 @@ cleanup_sunrpc(void)
svc_cleanup_xprt_sock();
unregister_rpc_pipefs();
rpc_destroy_mempool();
- cache_unregister(&ip_map_cache);
cache_unregister(&unix_gid_cache);
+ unregister_pernet_subsys(&sunrpc_net_ops);
#ifdef RPC_DEBUG
rpc_unregister_sysctl();
#endif
-#ifdef CONFIG_PROC_FS
- rpc_proc_exit();
-#endif
rcu_barrier(); /* Wait for completion of call_rcu()'s */
}
MODULE_LICENSE("GPL");
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index d9017d64597e..6359c42c4941 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -1055,6 +1055,9 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
goto err_bad;
case SVC_DENIED:
goto err_bad_auth;
+ case SVC_CLOSE:
+ if (test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags))
+ svc_close_xprt(rqstp->rq_xprt);
case SVC_DROP:
goto dropit;
case SVC_COMPLETE:
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index cbc084939dd8..c82fe739fbdc 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -100,16 +100,14 @@ EXPORT_SYMBOL_GPL(svc_unreg_xprt_class);
*/
int svc_print_xprts(char *buf, int maxlen)
{
- struct list_head *le;
+ struct svc_xprt_class *xcl;
char tmpstr[80];
int len = 0;
buf[0] = '\0';
spin_lock(&svc_xprt_class_lock);
- list_for_each(le, &svc_xprt_class_list) {
+ list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
int slen;
- struct svc_xprt_class *xcl =
- list_entry(le, struct svc_xprt_class, xcl_list);
sprintf(tmpstr, "%s %d\n", xcl->xcl_name, xcl->xcl_max_payload);
slen = strlen(tmpstr);
@@ -128,9 +126,9 @@ static void svc_xprt_free(struct kref *kref)
struct svc_xprt *xprt =
container_of(kref, struct svc_xprt, xpt_ref);
struct module *owner = xprt->xpt_class->xcl_owner;
- if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags) &&
- xprt->xpt_auth_cache != NULL)
- svcauth_unix_info_release(xprt->xpt_auth_cache);
+ if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags))
+ svcauth_unix_info_release(xprt);
+ put_net(xprt->xpt_net);
xprt->xpt_ops->xpo_free(xprt);
module_put(owner);
}
@@ -156,15 +154,18 @@ void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
INIT_LIST_HEAD(&xprt->xpt_list);
INIT_LIST_HEAD(&xprt->xpt_ready);
INIT_LIST_HEAD(&xprt->xpt_deferred);
+ INIT_LIST_HEAD(&xprt->xpt_users);
mutex_init(&xprt->xpt_mutex);
spin_lock_init(&xprt->xpt_lock);
set_bit(XPT_BUSY, &xprt->xpt_flags);
rpc_init_wait_queue(&xprt->xpt_bc_pending, "xpt_bc_pending");
+ xprt->xpt_net = get_net(&init_net);
}
EXPORT_SYMBOL_GPL(svc_xprt_init);
static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
struct svc_serv *serv,
+ struct net *net,
const int family,
const unsigned short port,
int flags)
@@ -199,12 +200,12 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
return ERR_PTR(-EAFNOSUPPORT);
}
- return xcl->xcl_ops->xpo_create(serv, sap, len, flags);
+ return xcl->xcl_ops->xpo_create(serv, net, sap, len, flags);
}
int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
- const int family, const unsigned short port,
- int flags)
+ struct net *net, const int family,
+ const unsigned short port, int flags)
{
struct svc_xprt_class *xcl;
@@ -220,7 +221,7 @@ int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
goto err;
spin_unlock(&svc_xprt_class_lock);
- newxprt = __svc_xpo_create(xcl, serv, family, port, flags);
+ newxprt = __svc_xpo_create(xcl, serv, net, family, port, flags);
if (IS_ERR(newxprt)) {
module_put(xcl->xcl_owner);
return PTR_ERR(newxprt);
@@ -329,12 +330,6 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
"svc_xprt_enqueue: "
"threads and transports both waiting??\n");
- if (test_bit(XPT_DEAD, &xprt->xpt_flags)) {
- /* Don't enqueue dead transports */
- dprintk("svc: transport %p is dead, not enqueued\n", xprt);
- goto out_unlock;
- }
-
pool->sp_stats.packets++;
/* Mark transport as busy. It will remain in this state until
@@ -651,6 +646,11 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
if (signalled() || kthread_should_stop())
return -EINTR;
+ /* Normally we will wait up to 5 seconds for any required
+ * cache information to be provided.
+ */
+ rqstp->rq_chandle.thread_wait = 5*HZ;
+
spin_lock_bh(&pool->sp_lock);
xprt = svc_xprt_dequeue(pool);
if (xprt) {
@@ -658,6 +658,12 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
svc_xprt_get(xprt);
rqstp->rq_reserved = serv->sv_max_mesg;
atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
+
+ /* As there is a shortage of threads and this request
+ * had to be queued, don't allow the thread to wait so
+ * long for cache updates.
+ */
+ rqstp->rq_chandle.thread_wait = 1*HZ;
} else {
/* No data pending. Go to sleep */
svc_thread_enqueue(pool, rqstp);
@@ -868,6 +874,19 @@ static void svc_age_temp_xprts(unsigned long closure)
mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
}
+static void call_xpt_users(struct svc_xprt *xprt)
+{
+ struct svc_xpt_user *u;
+
+ spin_lock(&xprt->xpt_lock);
+ while (!list_empty(&xprt->xpt_users)) {
+ u = list_first_entry(&xprt->xpt_users, struct svc_xpt_user, list);
+ list_del(&u->list);
+ u->callback(u);
+ }
+ spin_unlock(&xprt->xpt_lock);
+}
+
/*
* Remove a dead transport
*/
@@ -878,7 +897,7 @@ void svc_delete_xprt(struct svc_xprt *xprt)
/* Only do this once */
if (test_and_set_bit(XPT_DEAD, &xprt->xpt_flags))
- return;
+ BUG();
dprintk("svc: svc_delete_xprt(%p)\n", xprt);
xprt->xpt_ops->xpo_detach(xprt);
@@ -900,6 +919,7 @@ void svc_delete_xprt(struct svc_xprt *xprt)
while ((dr = svc_deferred_dequeue(xprt)) != NULL)
kfree(dr);
+ call_xpt_users(xprt);
svc_xprt_put(xprt);
}
@@ -910,10 +930,7 @@ void svc_close_xprt(struct svc_xprt *xprt)
/* someone else will have to effect the close */
return;
- svc_xprt_get(xprt);
svc_delete_xprt(xprt);
- clear_bit(XPT_BUSY, &xprt->xpt_flags);
- svc_xprt_put(xprt);
}
EXPORT_SYMBOL_GPL(svc_close_xprt);
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 207311610988..560677d187f1 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -18,6 +18,8 @@
#include <linux/sunrpc/clnt.h>
+#include "netns.h"
+
/*
* AUTHUNIX and AUTHNULL credentials are both handled here.
* AUTHNULL is treated just like AUTHUNIX except that the uid/gid
@@ -92,7 +94,6 @@ struct ip_map {
struct unix_domain *m_client;
int m_add_change;
};
-static struct cache_head *ip_table[IP_HASHMAX];
static void ip_map_put(struct kref *kref)
{
@@ -178,8 +179,8 @@ static int ip_map_upcall(struct cache_detail *cd, struct cache_head *h)
return sunrpc_cache_pipe_upcall(cd, h, ip_map_request);
}
-static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr);
-static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
+static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, struct in6_addr *addr);
+static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
static int ip_map_parse(struct cache_detail *cd,
char *mesg, int mlen)
@@ -219,10 +220,9 @@ static int ip_map_parse(struct cache_detail *cd,
switch (address.sa.sa_family) {
case AF_INET:
/* Form a mapped IPv4 address in sin6 */
- memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
- sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
- sin6.sin6_addr.s6_addr32[3] = address.s4.sin_addr.s_addr;
+ ipv6_addr_set_v4mapped(address.s4.sin_addr.s_addr,
+ &sin6.sin6_addr);
break;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
case AF_INET6:
@@ -249,9 +249,9 @@ static int ip_map_parse(struct cache_detail *cd,
dom = NULL;
/* IPv6 scope IDs are ignored for now */
- ipmp = ip_map_lookup(class, &sin6.sin6_addr);
+ ipmp = __ip_map_lookup(cd, class, &sin6.sin6_addr);
if (ipmp) {
- err = ip_map_update(ipmp,
+ err = __ip_map_update(cd, ipmp,
container_of(dom, struct unix_domain, h),
expiry);
} else
@@ -294,29 +294,15 @@ static int ip_map_show(struct seq_file *m,
}
-struct cache_detail ip_map_cache = {
- .owner = THIS_MODULE,
- .hash_size = IP_HASHMAX,
- .hash_table = ip_table,
- .name = "auth.unix.ip",
- .cache_put = ip_map_put,
- .cache_upcall = ip_map_upcall,
- .cache_parse = ip_map_parse,
- .cache_show = ip_map_show,
- .match = ip_map_match,
- .init = ip_map_init,
- .update = update,
- .alloc = ip_map_alloc,
-};
-
-static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr)
+static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class,
+ struct in6_addr *addr)
{
struct ip_map ip;
struct cache_head *ch;
strcpy(ip.m_class, class);
ipv6_addr_copy(&ip.m_addr, addr);
- ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
+ ch = sunrpc_cache_lookup(cd, &ip.h,
hash_str(class, IP_HASHBITS) ^
hash_ip6(*addr));
@@ -326,7 +312,17 @@ static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr)
return NULL;
}
-static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry)
+static inline struct ip_map *ip_map_lookup(struct net *net, char *class,
+ struct in6_addr *addr)
+{
+ struct sunrpc_net *sn;
+
+ sn = net_generic(net, sunrpc_net_id);
+ return __ip_map_lookup(sn->ip_map_cache, class, addr);
+}
+
+static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm,
+ struct unix_domain *udom, time_t expiry)
{
struct ip_map ip;
struct cache_head *ch;
@@ -344,17 +340,25 @@ static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t ex
ip.m_add_change++;
}
ip.h.expiry_time = expiry;
- ch = sunrpc_cache_update(&ip_map_cache,
- &ip.h, &ipm->h,
+ ch = sunrpc_cache_update(cd, &ip.h, &ipm->h,
hash_str(ipm->m_class, IP_HASHBITS) ^
hash_ip6(ipm->m_addr));
if (!ch)
return -ENOMEM;
- cache_put(ch, &ip_map_cache);
+ cache_put(ch, cd);
return 0;
}
-int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
+static inline int ip_map_update(struct net *net, struct ip_map *ipm,
+ struct unix_domain *udom, time_t expiry)
+{
+ struct sunrpc_net *sn;
+
+ sn = net_generic(net, sunrpc_net_id);
+ return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry);
+}
+
+int auth_unix_add_addr(struct net *net, struct in6_addr *addr, struct auth_domain *dom)
{
struct unix_domain *udom;
struct ip_map *ipmp;
@@ -362,10 +366,10 @@ int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
if (dom->flavour != &svcauth_unix)
return -EINVAL;
udom = container_of(dom, struct unix_domain, h);
- ipmp = ip_map_lookup("nfsd", addr);
+ ipmp = ip_map_lookup(net, "nfsd", addr);
if (ipmp)
- return ip_map_update(ipmp, udom, NEVER);
+ return ip_map_update(net, ipmp, udom, NEVER);
else
return -ENOMEM;
}
@@ -383,16 +387,18 @@ int auth_unix_forget_old(struct auth_domain *dom)
}
EXPORT_SYMBOL_GPL(auth_unix_forget_old);
-struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
+struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr)
{
struct ip_map *ipm;
struct auth_domain *rv;
+ struct sunrpc_net *sn;
- ipm = ip_map_lookup("nfsd", addr);
+ sn = net_generic(net, sunrpc_net_id);
+ ipm = ip_map_lookup(net, "nfsd", addr);
if (!ipm)
return NULL;
- if (cache_check(&ip_map_cache, &ipm->h, NULL))
+ if (cache_check(sn->ip_map_cache, &ipm->h, NULL))
return NULL;
if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) {
@@ -403,22 +409,29 @@ struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
rv = &ipm->m_client->h;
kref_get(&rv->ref);
}
- cache_put(&ipm->h, &ip_map_cache);
+ cache_put(&ipm->h, sn->ip_map_cache);
return rv;
}
EXPORT_SYMBOL_GPL(auth_unix_lookup);
void svcauth_unix_purge(void)
{
- cache_purge(&ip_map_cache);
+ struct net *net;
+
+ for_each_net(net) {
+ struct sunrpc_net *sn;
+
+ sn = net_generic(net, sunrpc_net_id);
+ cache_purge(sn->ip_map_cache);
+ }
}
EXPORT_SYMBOL_GPL(svcauth_unix_purge);
static inline struct ip_map *
-ip_map_cached_get(struct svc_rqst *rqstp)
+ip_map_cached_get(struct svc_xprt *xprt)
{
struct ip_map *ipm = NULL;
- struct svc_xprt *xprt = rqstp->rq_xprt;
+ struct sunrpc_net *sn;
if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) {
spin_lock(&xprt->xpt_lock);
@@ -430,9 +443,10 @@ ip_map_cached_get(struct svc_rqst *rqstp)
* remembered, e.g. by a second mount from the
* same IP address.
*/
+ sn = net_generic(xprt->xpt_net, sunrpc_net_id);
xprt->xpt_auth_cache = NULL;
spin_unlock(&xprt->xpt_lock);
- cache_put(&ipm->h, &ip_map_cache);
+ cache_put(&ipm->h, sn->ip_map_cache);
return NULL;
}
cache_get(&ipm->h);
@@ -443,10 +457,8 @@ ip_map_cached_get(struct svc_rqst *rqstp)
}
static inline void
-ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
+ip_map_cached_put(struct svc_xprt *xprt, struct ip_map *ipm)
{
- struct svc_xprt *xprt = rqstp->rq_xprt;
-
if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) {
spin_lock(&xprt->xpt_lock);
if (xprt->xpt_auth_cache == NULL) {
@@ -456,15 +468,26 @@ ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
}
spin_unlock(&xprt->xpt_lock);
}
- if (ipm)
- cache_put(&ipm->h, &ip_map_cache);
+ if (ipm) {
+ struct sunrpc_net *sn;
+
+ sn = net_generic(xprt->xpt_net, sunrpc_net_id);
+ cache_put(&ipm->h, sn->ip_map_cache);
+ }
}
void
-svcauth_unix_info_release(void *info)
+svcauth_unix_info_release(struct svc_xprt *xpt)
{
- struct ip_map *ipm = info;
- cache_put(&ipm->h, &ip_map_cache);
+ struct ip_map *ipm;
+
+ ipm = xpt->xpt_auth_cache;
+ if (ipm != NULL) {
+ struct sunrpc_net *sn;
+
+ sn = net_generic(xpt->xpt_net, sunrpc_net_id);
+ cache_put(&ipm->h, sn->ip_map_cache);
+ }
}
/****************************************************************************
@@ -674,6 +697,8 @@ static struct group_info *unix_gid_find(uid_t uid, struct svc_rqst *rqstp)
switch (ret) {
case -ENOENT:
return ERR_PTR(-ENOENT);
+ case -ETIMEDOUT:
+ return ERR_PTR(-ESHUTDOWN);
case 0:
gi = get_group_info(ug->gi);
cache_put(&ug->h, &unix_gid_cache);
@@ -691,6 +716,9 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
struct ip_map *ipm;
struct group_info *gi;
struct svc_cred *cred = &rqstp->rq_cred;
+ struct svc_xprt *xprt = rqstp->rq_xprt;
+ struct net *net = xprt->xpt_net;
+ struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
switch (rqstp->rq_addr.ss_family) {
case AF_INET:
@@ -709,26 +737,27 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
if (rqstp->rq_proc == 0)
return SVC_OK;
- ipm = ip_map_cached_get(rqstp);
+ ipm = ip_map_cached_get(xprt);
if (ipm == NULL)
- ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
+ ipm = __ip_map_lookup(sn->ip_map_cache, rqstp->rq_server->sv_program->pg_class,
&sin6->sin6_addr);
if (ipm == NULL)
return SVC_DENIED;
- switch (cache_check(&ip_map_cache, &ipm->h, &rqstp->rq_chandle)) {
+ switch (cache_check(sn->ip_map_cache, &ipm->h, &rqstp->rq_chandle)) {
default:
BUG();
- case -EAGAIN:
case -ETIMEDOUT:
+ return SVC_CLOSE;
+ case -EAGAIN:
return SVC_DROP;
case -ENOENT:
return SVC_DENIED;
case 0:
rqstp->rq_client = &ipm->m_client->h;
kref_get(&rqstp->rq_client->ref);
- ip_map_cached_put(rqstp, ipm);
+ ip_map_cached_put(xprt, ipm);
break;
}
@@ -736,6 +765,8 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
switch (PTR_ERR(gi)) {
case -EAGAIN:
return SVC_DROP;
+ case -ESHUTDOWN:
+ return SVC_CLOSE;
case -ENOENT:
break;
default:
@@ -776,7 +807,7 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
cred->cr_gid = (gid_t) -1;
cred->cr_group_info = groups_alloc(0);
if (cred->cr_group_info == NULL)
- return SVC_DROP; /* kmalloc failure - client must retry */
+ return SVC_CLOSE; /* kmalloc failure - client must retry */
/* Put NULL verifier */
svc_putnl(resv, RPC_AUTH_NULL);
@@ -840,7 +871,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
goto badcred;
cred->cr_group_info = groups_alloc(slen);
if (cred->cr_group_info == NULL)
- return SVC_DROP;
+ return SVC_CLOSE;
for (i = 0; i < slen; i++)
GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv);
if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
@@ -886,3 +917,56 @@ struct auth_ops svcauth_unix = {
.set_client = svcauth_unix_set_client,
};
+int ip_map_cache_create(struct net *net)
+{
+ int err = -ENOMEM;
+ struct cache_detail *cd;
+ struct cache_head **tbl;
+ struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+ cd = kzalloc(sizeof(struct cache_detail), GFP_KERNEL);
+ if (cd == NULL)
+ goto err_cd;
+
+ tbl = kzalloc(IP_HASHMAX * sizeof(struct cache_head *), GFP_KERNEL);
+ if (tbl == NULL)
+ goto err_tbl;
+
+ cd->owner = THIS_MODULE,
+ cd->hash_size = IP_HASHMAX,
+ cd->hash_table = tbl,
+ cd->name = "auth.unix.ip",
+ cd->cache_put = ip_map_put,
+ cd->cache_upcall = ip_map_upcall,
+ cd->cache_parse = ip_map_parse,
+ cd->cache_show = ip_map_show,
+ cd->match = ip_map_match,
+ cd->init = ip_map_init,
+ cd->update = update,
+ cd->alloc = ip_map_alloc,
+
+ err = cache_register_net(cd, net);
+ if (err)
+ goto err_reg;
+
+ sn->ip_map_cache = cd;
+ return 0;
+
+err_reg:
+ kfree(tbl);
+err_tbl:
+ kfree(cd);
+err_cd:
+ return err;
+}
+
+void ip_map_cache_destroy(struct net *net)
+{
+ struct sunrpc_net *sn;
+
+ sn = net_generic(net, sunrpc_net_id);
+ cache_purge(sn->ip_map_cache);
+ cache_unregister_net(sn->ip_map_cache, net);
+ kfree(sn->ip_map_cache->hash_table);
+ kfree(sn->ip_map_cache);
+}
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 7e534dd09077..07919e16be3e 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -64,7 +64,8 @@ static void svc_tcp_sock_detach(struct svc_xprt *);
static void svc_sock_free(struct svc_xprt *);
static struct svc_xprt *svc_create_socket(struct svc_serv *, int,
- struct sockaddr *, int, int);
+ struct net *, struct sockaddr *,
+ int, int);
#ifdef CONFIG_DEBUG_LOCK_ALLOC
static struct lock_class_key svc_key[2];
static struct lock_class_key svc_slock_key[2];
@@ -657,10 +658,11 @@ static struct svc_xprt *svc_udp_accept(struct svc_xprt *xprt)
}
static struct svc_xprt *svc_udp_create(struct svc_serv *serv,
+ struct net *net,
struct sockaddr *sa, int salen,
int flags)
{
- return svc_create_socket(serv, IPPROTO_UDP, sa, salen, flags);
+ return svc_create_socket(serv, IPPROTO_UDP, net, sa, salen, flags);
}
static struct svc_xprt_ops svc_udp_ops = {
@@ -1133,9 +1135,6 @@ static int svc_tcp_sendto(struct svc_rqst *rqstp)
reclen = htonl(0x80000000|((xbufp->len ) - 4));
memcpy(xbufp->head[0].iov_base, &reclen, 4);
- if (test_bit(XPT_DEAD, &rqstp->rq_xprt->xpt_flags))
- return -ENOTCONN;
-
sent = svc_sendto(rqstp, &rqstp->rq_res);
if (sent != xbufp->len) {
printk(KERN_NOTICE
@@ -1178,10 +1177,11 @@ static int svc_tcp_has_wspace(struct svc_xprt *xprt)
}
static struct svc_xprt *svc_tcp_create(struct svc_serv *serv,
+ struct net *net,
struct sockaddr *sa, int salen,
int flags)
{
- return svc_create_socket(serv, IPPROTO_TCP, sa, salen, flags);
+ return svc_create_socket(serv, IPPROTO_TCP, net, sa, salen, flags);
}
static struct svc_xprt_ops svc_tcp_ops = {
@@ -1258,19 +1258,13 @@ void svc_sock_update_bufs(struct svc_serv *serv)
* The number of server threads has changed. Update
* rcvbuf and sndbuf accordingly on all sockets
*/
- struct list_head *le;
+ struct svc_sock *svsk;
spin_lock_bh(&serv->sv_lock);
- list_for_each(le, &serv->sv_permsocks) {
- struct svc_sock *svsk =
- list_entry(le, struct svc_sock, sk_xprt.xpt_list);
+ list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list)
set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
- }
- list_for_each(le, &serv->sv_tempsocks) {
- struct svc_sock *svsk =
- list_entry(le, struct svc_sock, sk_xprt.xpt_list);
+ list_for_each_entry(svsk, &serv->sv_tempsocks, sk_xprt.xpt_list)
set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
- }
spin_unlock_bh(&serv->sv_lock);
}
EXPORT_SYMBOL_GPL(svc_sock_update_bufs);
@@ -1385,6 +1379,7 @@ EXPORT_SYMBOL_GPL(svc_addsock);
*/
static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
int protocol,
+ struct net *net,
struct sockaddr *sin, int len,
int flags)
{
@@ -1421,7 +1416,7 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
return ERR_PTR(-EINVAL);
}
- error = sock_create_kern(family, type, protocol, &sock);
+ error = __sock_create(net, family, type, protocol, &sock, 1);
if (error < 0)
return ERR_PTR(error);
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index a1f82a87d34d..cd9e841e7492 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -111,6 +111,23 @@ xdr_decode_string_inplace(__be32 *p, char **sp,
}
EXPORT_SYMBOL_GPL(xdr_decode_string_inplace);
+/**
+ * xdr_terminate_string - '\0'-terminate a string residing in an xdr_buf
+ * @buf: XDR buffer where string resides
+ * @len: length of string, in bytes
+ *
+ */
+void
+xdr_terminate_string(struct xdr_buf *buf, const u32 len)
+{
+ char *kaddr;
+
+ kaddr = kmap_atomic(buf->pages[0], KM_USER0);
+ kaddr[buf->page_base + len] = '\0';
+ kunmap_atomic(kaddr, KM_USER0);
+}
+EXPORT_SYMBOL(xdr_terminate_string);
+
void
xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
unsigned int len)
@@ -395,24 +412,29 @@ xdr_shrink_pagelen(struct xdr_buf *buf, size_t len)
{
struct kvec *tail;
size_t copy;
- char *p;
unsigned int pglen = buf->page_len;
+ unsigned int tailbuf_len;
tail = buf->tail;
BUG_ON (len > pglen);
+ tailbuf_len = buf->buflen - buf->head->iov_len - buf->page_len;
+
/* Shift the tail first */
- if (tail->iov_len != 0) {
- p = (char *)tail->iov_base + len;
+ if (tailbuf_len != 0) {
+ unsigned int free_space = tailbuf_len - tail->iov_len;
+
+ if (len < free_space)
+ free_space = len;
+ tail->iov_len += free_space;
+
+ copy = len;
if (tail->iov_len > len) {
- copy = tail->iov_len - len;
- memmove(p, tail->iov_base, copy);
+ char *p = (char *)tail->iov_base + len;
+ memmove(p, tail->iov_base, tail->iov_len - len);
} else
- buf->buflen -= len;
- /* Copy from the inlined pages into the tail */
- copy = len;
- if (copy > tail->iov_len)
copy = tail->iov_len;
+ /* Copy from the inlined pages into the tail */
_copy_from_pages((char *)tail->iov_base,
buf->pages, buf->page_base + pglen - len,
copy);
@@ -551,6 +573,27 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
EXPORT_SYMBOL_GPL(xdr_init_decode);
/**
+ * xdr_inline_peek - Allow read-ahead in the XDR data stream
+ * @xdr: pointer to xdr_stream struct
+ * @nbytes: number of bytes of data to decode
+ *
+ * Check if the input buffer is long enough to enable us to decode
+ * 'nbytes' more bytes of data starting at the current position.
+ * If so return the current pointer without updating the current
+ * pointer position.
+ */
+__be32 * xdr_inline_peek(struct xdr_stream *xdr, size_t nbytes)
+{
+ __be32 *p = xdr->p;
+ __be32 *q = p + XDR_QUADLEN(nbytes);
+
+ if (unlikely(q > xdr->end || q < p))
+ return NULL;
+ return p;
+}
+EXPORT_SYMBOL_GPL(xdr_inline_peek);
+
+/**
* xdr_inline_decode - Retrieve non-page XDR data to decode
* @xdr: pointer to xdr_stream struct
* @nbytes: number of bytes of data to decode
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 970fb00f388c..4c8f18aff7c3 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -199,8 +199,6 @@ int xprt_reserve_xprt(struct rpc_task *task)
if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) {
if (task == xprt->snd_task)
return 1;
- if (task == NULL)
- return 0;
goto out_sleep;
}
xprt->snd_task = task;
@@ -757,13 +755,11 @@ static void xprt_connect_status(struct rpc_task *task)
*/
struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
{
- struct list_head *pos;
+ struct rpc_rqst *entry;
- list_for_each(pos, &xprt->recv) {
- struct rpc_rqst *entry = list_entry(pos, struct rpc_rqst, rq_list);
+ list_for_each_entry(entry, &xprt->recv, rq_list)
if (entry->rq_xid == xid)
return entry;
- }
dprintk("RPC: xprt_lookup_rqst did not find xid %08x\n",
ntohl(xid));
@@ -962,6 +958,37 @@ static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
spin_unlock(&xprt->reserve_lock);
}
+struct rpc_xprt *xprt_alloc(struct net *net, int size, int max_req)
+{
+ struct rpc_xprt *xprt;
+
+ xprt = kzalloc(size, GFP_KERNEL);
+ if (xprt == NULL)
+ goto out;
+
+ xprt->max_reqs = max_req;
+ xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL);
+ if (xprt->slot == NULL)
+ goto out_free;
+
+ xprt->xprt_net = get_net(net);
+ return xprt;
+
+out_free:
+ kfree(xprt);
+out:
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(xprt_alloc);
+
+void xprt_free(struct rpc_xprt *xprt)
+{
+ put_net(xprt->xprt_net);
+ kfree(xprt->slot);
+ kfree(xprt);
+}
+EXPORT_SYMBOL_GPL(xprt_free);
+
/**
* xprt_reserve - allocate an RPC request slot
* @task: RPC task requesting a slot allocation
diff --git a/net/sunrpc/xprtrdma/svc_rdma.c b/net/sunrpc/xprtrdma/svc_rdma.c
index d718b8fa9525..09af4fab1a45 100644
--- a/net/sunrpc/xprtrdma/svc_rdma.c
+++ b/net/sunrpc/xprtrdma/svc_rdma.c
@@ -43,6 +43,7 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/sysctl.h>
+#include <linux/workqueue.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/sched.h>
#include <linux/sunrpc/svc_rdma.h>
@@ -74,6 +75,8 @@ atomic_t rdma_stat_sq_prod;
struct kmem_cache *svc_rdma_map_cachep;
struct kmem_cache *svc_rdma_ctxt_cachep;
+struct workqueue_struct *svc_rdma_wq;
+
/*
* This function implements reading and resetting an atomic_t stat
* variable through read/write to a proc file. Any write to the file
@@ -231,7 +234,7 @@ static ctl_table svcrdma_root_table[] = {
void svc_rdma_cleanup(void)
{
dprintk("SVCRDMA Module Removed, deregister RPC RDMA transport\n");
- flush_scheduled_work();
+ destroy_workqueue(svc_rdma_wq);
if (svcrdma_table_header) {
unregister_sysctl_table(svcrdma_table_header);
svcrdma_table_header = NULL;
@@ -249,6 +252,11 @@ int svc_rdma_init(void)
dprintk("\tsq_depth : %d\n",
svcrdma_max_requests * RPCRDMA_SQ_DEPTH_MULT);
dprintk("\tmax_inline : %d\n", svcrdma_max_req_size);
+
+ svc_rdma_wq = alloc_workqueue("svc_rdma", 0, 0);
+ if (!svc_rdma_wq)
+ return -ENOMEM;
+
if (!svcrdma_table_header)
svcrdma_table_header =
register_sysctl_table(svcrdma_root_table);
@@ -283,6 +291,7 @@ int svc_rdma_init(void)
kmem_cache_destroy(svc_rdma_map_cachep);
err0:
unregister_sysctl_table(svcrdma_table_header);
+ destroy_workqueue(svc_rdma_wq);
return -ENOMEM;
}
MODULE_AUTHOR("Tom Tucker <tom@opengridcomputing.com>");
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
index 0194de814933..df67211c4baf 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
@@ -263,9 +263,9 @@ static int fast_reg_read_chunks(struct svcxprt_rdma *xprt,
frmr->page_list_len = PAGE_ALIGN(byte_count) >> PAGE_SHIFT;
for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
frmr->page_list->page_list[page_no] =
- ib_dma_map_single(xprt->sc_cm_id->device,
- page_address(rqstp->rq_arg.pages[page_no]),
- PAGE_SIZE, DMA_FROM_DEVICE);
+ ib_dma_map_page(xprt->sc_cm_id->device,
+ rqstp->rq_arg.pages[page_no], 0,
+ PAGE_SIZE, DMA_FROM_DEVICE);
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
frmr->page_list->page_list[page_no]))
goto fatal_err;
@@ -309,17 +309,21 @@ static int rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
int count)
{
int i;
+ unsigned long off;
ctxt->count = count;
ctxt->direction = DMA_FROM_DEVICE;
for (i = 0; i < count; i++) {
ctxt->sge[i].length = 0; /* in case map fails */
if (!frmr) {
+ BUG_ON(0 == virt_to_page(vec[i].iov_base));
+ off = (unsigned long)vec[i].iov_base & ~PAGE_MASK;
ctxt->sge[i].addr =
- ib_dma_map_single(xprt->sc_cm_id->device,
- vec[i].iov_base,
- vec[i].iov_len,
- DMA_FROM_DEVICE);
+ ib_dma_map_page(xprt->sc_cm_id->device,
+ virt_to_page(vec[i].iov_base),
+ off,
+ vec[i].iov_len,
+ DMA_FROM_DEVICE);
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
ctxt->sge[i].addr))
return -EINVAL;
@@ -491,6 +495,7 @@ next_sge:
printk(KERN_ERR "svcrdma: Error %d posting RDMA_READ\n",
err);
set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+ svc_rdma_unmap_dma(ctxt);
svc_rdma_put_context(ctxt, 0);
goto out;
}
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
index b15e1ebb2bfa..249a835b703f 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
@@ -70,8 +70,8 @@
* on extra page for the RPCRMDA header.
*/
static int fast_reg_xdr(struct svcxprt_rdma *xprt,
- struct xdr_buf *xdr,
- struct svc_rdma_req_map *vec)
+ struct xdr_buf *xdr,
+ struct svc_rdma_req_map *vec)
{
int sge_no;
u32 sge_bytes;
@@ -96,21 +96,25 @@ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
vec->count = 2;
sge_no++;
- /* Build the FRMR */
+ /* Map the XDR head */
frmr->kva = frva;
frmr->direction = DMA_TO_DEVICE;
frmr->access_flags = 0;
frmr->map_len = PAGE_SIZE;
frmr->page_list_len = 1;
+ page_off = (unsigned long)xdr->head[0].iov_base & ~PAGE_MASK;
frmr->page_list->page_list[page_no] =
- ib_dma_map_single(xprt->sc_cm_id->device,
- (void *)xdr->head[0].iov_base,
- PAGE_SIZE, DMA_TO_DEVICE);
+ ib_dma_map_page(xprt->sc_cm_id->device,
+ virt_to_page(xdr->head[0].iov_base),
+ page_off,
+ PAGE_SIZE - page_off,
+ DMA_TO_DEVICE);
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
frmr->page_list->page_list[page_no]))
goto fatal_err;
atomic_inc(&xprt->sc_dma_used);
+ /* Map the XDR page list */
page_off = xdr->page_base;
page_bytes = xdr->page_len + page_off;
if (!page_bytes)
@@ -128,9 +132,9 @@ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
page_bytes -= sge_bytes;
frmr->page_list->page_list[page_no] =
- ib_dma_map_single(xprt->sc_cm_id->device,
- page_address(page),
- PAGE_SIZE, DMA_TO_DEVICE);
+ ib_dma_map_page(xprt->sc_cm_id->device,
+ page, page_off,
+ sge_bytes, DMA_TO_DEVICE);
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
frmr->page_list->page_list[page_no]))
goto fatal_err;
@@ -166,8 +170,10 @@ static int fast_reg_xdr(struct svcxprt_rdma *xprt,
vec->sge[sge_no].iov_base = frva + frmr->map_len + page_off;
frmr->page_list->page_list[page_no] =
- ib_dma_map_single(xprt->sc_cm_id->device, va, PAGE_SIZE,
- DMA_TO_DEVICE);
+ ib_dma_map_page(xprt->sc_cm_id->device, virt_to_page(va),
+ page_off,
+ PAGE_SIZE,
+ DMA_TO_DEVICE);
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
frmr->page_list->page_list[page_no]))
goto fatal_err;
@@ -245,6 +251,35 @@ static int map_xdr(struct svcxprt_rdma *xprt,
return 0;
}
+static dma_addr_t dma_map_xdr(struct svcxprt_rdma *xprt,
+ struct xdr_buf *xdr,
+ u32 xdr_off, size_t len, int dir)
+{
+ struct page *page;
+ dma_addr_t dma_addr;
+ if (xdr_off < xdr->head[0].iov_len) {
+ /* This offset is in the head */
+ xdr_off += (unsigned long)xdr->head[0].iov_base & ~PAGE_MASK;
+ page = virt_to_page(xdr->head[0].iov_base);
+ } else {
+ xdr_off -= xdr->head[0].iov_len;
+ if (xdr_off < xdr->page_len) {
+ /* This offset is in the page list */
+ page = xdr->pages[xdr_off >> PAGE_SHIFT];
+ xdr_off &= ~PAGE_MASK;
+ } else {
+ /* This offset is in the tail */
+ xdr_off -= xdr->page_len;
+ xdr_off += (unsigned long)
+ xdr->tail[0].iov_base & ~PAGE_MASK;
+ page = virt_to_page(xdr->tail[0].iov_base);
+ }
+ }
+ dma_addr = ib_dma_map_page(xprt->sc_cm_id->device, page, xdr_off,
+ min_t(size_t, PAGE_SIZE, len), dir);
+ return dma_addr;
+}
+
/* Assumptions:
* - We are using FRMR
* - or -
@@ -293,10 +328,9 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
sge[sge_no].length = sge_bytes;
if (!vec->frmr) {
sge[sge_no].addr =
- ib_dma_map_single(xprt->sc_cm_id->device,
- (void *)
- vec->sge[xdr_sge_no].iov_base + sge_off,
- sge_bytes, DMA_TO_DEVICE);
+ dma_map_xdr(xprt, &rqstp->rq_res, xdr_off,
+ sge_bytes, DMA_TO_DEVICE);
+ xdr_off += sge_bytes;
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
sge[sge_no].addr))
goto err;
@@ -333,6 +367,8 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
goto err;
return 0;
err:
+ svc_rdma_unmap_dma(ctxt);
+ svc_rdma_put_frmr(xprt, vec->frmr);
svc_rdma_put_context(ctxt, 0);
/* Fatal error, close transport */
return -EIO;
@@ -494,7 +530,8 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
* In all three cases, this function prepares the RPCRDMA header in
* sge[0], the 'type' parameter indicates the type to place in the
* RPCRDMA header, and the 'byte_count' field indicates how much of
- * the XDR to include in this RDMA_SEND.
+ * the XDR to include in this RDMA_SEND. NB: The offset of the payload
+ * to send is zero in the XDR.
*/
static int send_reply(struct svcxprt_rdma *rdma,
struct svc_rqst *rqstp,
@@ -536,23 +573,24 @@ static int send_reply(struct svcxprt_rdma *rdma,
ctxt->sge[0].lkey = rdma->sc_dma_lkey;
ctxt->sge[0].length = svc_rdma_xdr_get_reply_hdr_len(rdma_resp);
ctxt->sge[0].addr =
- ib_dma_map_single(rdma->sc_cm_id->device, page_address(page),
- ctxt->sge[0].length, DMA_TO_DEVICE);
+ ib_dma_map_page(rdma->sc_cm_id->device, page, 0,
+ ctxt->sge[0].length, DMA_TO_DEVICE);
if (ib_dma_mapping_error(rdma->sc_cm_id->device, ctxt->sge[0].addr))
goto err;
atomic_inc(&rdma->sc_dma_used);
ctxt->direction = DMA_TO_DEVICE;
- /* Determine how many of our SGE are to be transmitted */
+ /* Map the payload indicated by 'byte_count' */
for (sge_no = 1; byte_count && sge_no < vec->count; sge_no++) {
+ int xdr_off = 0;
sge_bytes = min_t(size_t, vec->sge[sge_no].iov_len, byte_count);
byte_count -= sge_bytes;
if (!vec->frmr) {
ctxt->sge[sge_no].addr =
- ib_dma_map_single(rdma->sc_cm_id->device,
- vec->sge[sge_no].iov_base,
- sge_bytes, DMA_TO_DEVICE);
+ dma_map_xdr(rdma, &rqstp->rq_res, xdr_off,
+ sge_bytes, DMA_TO_DEVICE);
+ xdr_off += sge_bytes;
if (ib_dma_mapping_error(rdma->sc_cm_id->device,
ctxt->sge[sge_no].addr))
goto err;
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index edea15a54e51..9df1eadc912a 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -45,6 +45,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/workqueue.h>
#include <rdma/ib_verbs.h>
#include <rdma/rdma_cm.h>
#include <linux/sunrpc/svc_rdma.h>
@@ -52,6 +53,7 @@
#define RPCDBG_FACILITY RPCDBG_SVCXPRT
static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
+ struct net *net,
struct sockaddr *sa, int salen,
int flags);
static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt);
@@ -89,6 +91,9 @@ struct svc_xprt_class svc_rdma_class = {
/* WR context cache. Created in svc_rdma.c */
extern struct kmem_cache *svc_rdma_ctxt_cachep;
+/* Workqueue created in svc_rdma.c */
+extern struct workqueue_struct *svc_rdma_wq;
+
struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
{
struct svc_rdma_op_ctxt *ctxt;
@@ -120,7 +125,7 @@ void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
*/
if (ctxt->sge[i].lkey == xprt->sc_dma_lkey) {
atomic_dec(&xprt->sc_dma_used);
- ib_dma_unmap_single(xprt->sc_cm_id->device,
+ ib_dma_unmap_page(xprt->sc_cm_id->device,
ctxt->sge[i].addr,
ctxt->sge[i].length,
ctxt->direction);
@@ -502,8 +507,8 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
BUG_ON(sge_no >= xprt->sc_max_sge);
page = svc_rdma_get_page();
ctxt->pages[sge_no] = page;
- pa = ib_dma_map_single(xprt->sc_cm_id->device,
- page_address(page), PAGE_SIZE,
+ pa = ib_dma_map_page(xprt->sc_cm_id->device,
+ page, 0, PAGE_SIZE,
DMA_FROM_DEVICE);
if (ib_dma_mapping_error(xprt->sc_cm_id->device, pa))
goto err_put_ctxt;
@@ -511,9 +516,9 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
ctxt->sge[sge_no].addr = pa;
ctxt->sge[sge_no].length = PAGE_SIZE;
ctxt->sge[sge_no].lkey = xprt->sc_dma_lkey;
+ ctxt->count = sge_no + 1;
buflen += PAGE_SIZE;
}
- ctxt->count = sge_no;
recv_wr.next = NULL;
recv_wr.sg_list = &ctxt->sge[0];
recv_wr.num_sge = ctxt->count;
@@ -529,6 +534,7 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
return ret;
err_put_ctxt:
+ svc_rdma_unmap_dma(ctxt);
svc_rdma_put_context(ctxt, 1);
return -ENOMEM;
}
@@ -670,6 +676,7 @@ static int rdma_cma_handler(struct rdma_cm_id *cma_id,
* Create a listening RDMA service endpoint.
*/
static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
+ struct net *net,
struct sockaddr *sa, int salen,
int flags)
{
@@ -798,8 +805,8 @@ static void frmr_unmap_dma(struct svcxprt_rdma *xprt,
if (ib_dma_mapping_error(frmr->mr->device, addr))
continue;
atomic_dec(&xprt->sc_dma_used);
- ib_dma_unmap_single(frmr->mr->device, addr, PAGE_SIZE,
- frmr->direction);
+ ib_dma_unmap_page(frmr->mr->device, addr, PAGE_SIZE,
+ frmr->direction);
}
}
@@ -1184,7 +1191,7 @@ static void svc_rdma_free(struct svc_xprt *xprt)
struct svcxprt_rdma *rdma =
container_of(xprt, struct svcxprt_rdma, sc_xprt);
INIT_WORK(&rdma->sc_work, __svc_rdma_free);
- schedule_work(&rdma->sc_work);
+ queue_work(svc_rdma_wq, &rdma->sc_work);
}
static int svc_rdma_has_wspace(struct svc_xprt *xprt)
@@ -1274,7 +1281,7 @@ int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
atomic_read(&xprt->sc_sq_count) <
xprt->sc_sq_depth);
if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
- return 0;
+ return -ENOTCONN;
continue;
}
/* Take a transport ref for each WR posted */
@@ -1306,7 +1313,6 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
enum rpcrdma_errcode err)
{
struct ib_send_wr err_wr;
- struct ib_sge sge;
struct page *p;
struct svc_rdma_op_ctxt *ctxt;
u32 *va;
@@ -1319,26 +1325,27 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
/* XDR encode error */
length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
+ ctxt = svc_rdma_get_context(xprt);
+ ctxt->direction = DMA_FROM_DEVICE;
+ ctxt->count = 1;
+ ctxt->pages[0] = p;
+
/* Prepare SGE for local address */
- sge.addr = ib_dma_map_single(xprt->sc_cm_id->device,
- page_address(p), PAGE_SIZE, DMA_FROM_DEVICE);
- if (ib_dma_mapping_error(xprt->sc_cm_id->device, sge.addr)) {
+ ctxt->sge[0].addr = ib_dma_map_page(xprt->sc_cm_id->device,
+ p, 0, length, DMA_FROM_DEVICE);
+ if (ib_dma_mapping_error(xprt->sc_cm_id->device, ctxt->sge[0].addr)) {
put_page(p);
return;
}
atomic_inc(&xprt->sc_dma_used);
- sge.lkey = xprt->sc_dma_lkey;
- sge.length = length;
-
- ctxt = svc_rdma_get_context(xprt);
- ctxt->count = 1;
- ctxt->pages[0] = p;
+ ctxt->sge[0].lkey = xprt->sc_dma_lkey;
+ ctxt->sge[0].length = length;
/* Prepare SEND WR */
memset(&err_wr, 0, sizeof err_wr);
ctxt->wr_op = IB_WR_SEND;
err_wr.wr_id = (unsigned long)ctxt;
- err_wr.sg_list = &sge;
+ err_wr.sg_list = ctxt->sge;
err_wr.num_sge = 1;
err_wr.opcode = IB_WR_SEND;
err_wr.send_flags = IB_SEND_SIGNALED;
@@ -1348,9 +1355,7 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
if (ret) {
dprintk("svcrdma: Error %d posting send for protocol error\n",
ret);
- ib_dma_unmap_single(xprt->sc_cm_id->device,
- sge.addr, PAGE_SIZE,
- DMA_FROM_DEVICE);
+ svc_rdma_unmap_dma(ctxt);
svc_rdma_put_context(ctxt, 1);
}
}
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
index a85e866a77f7..0867070bb5ca 100644
--- a/net/sunrpc/xprtrdma/transport.c
+++ b/net/sunrpc/xprtrdma/transport.c
@@ -237,8 +237,7 @@ xprt_rdma_destroy(struct rpc_xprt *xprt)
dprintk("RPC: %s: called\n", __func__);
- cancel_delayed_work(&r_xprt->rdma_connect);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&r_xprt->rdma_connect);
xprt_clear_connected(xprt);
@@ -251,9 +250,7 @@ xprt_rdma_destroy(struct rpc_xprt *xprt)
xprt_rdma_free_addresses(xprt);
- kfree(xprt->slot);
- xprt->slot = NULL;
- kfree(xprt);
+ xprt_free(xprt);
dprintk("RPC: %s: returning\n", __func__);
@@ -285,23 +282,14 @@ xprt_setup_rdma(struct xprt_create *args)
return ERR_PTR(-EBADF);
}
- xprt = kzalloc(sizeof(struct rpcrdma_xprt), GFP_KERNEL);
+ xprt = xprt_alloc(args->net, sizeof(struct rpcrdma_xprt),
+ xprt_rdma_slot_table_entries);
if (xprt == NULL) {
dprintk("RPC: %s: couldn't allocate rpcrdma_xprt\n",
__func__);
return ERR_PTR(-ENOMEM);
}
- xprt->max_reqs = xprt_rdma_slot_table_entries;
- xprt->slot = kcalloc(xprt->max_reqs,
- sizeof(struct rpc_rqst), GFP_KERNEL);
- if (xprt->slot == NULL) {
- dprintk("RPC: %s: couldn't allocate %d slots\n",
- __func__, xprt->max_reqs);
- kfree(xprt);
- return ERR_PTR(-ENOMEM);
- }
-
/* 60 second timeout, no retries */
xprt->timeout = &xprt_rdma_default_timeout;
xprt->bind_timeout = (60U * HZ);
@@ -410,8 +398,7 @@ out3:
out2:
rpcrdma_ia_close(&new_xprt->rx_ia);
out1:
- kfree(xprt->slot);
- kfree(xprt);
+ xprt_free(xprt);
return ERR_PTR(rc);
}
@@ -460,7 +447,7 @@ xprt_rdma_connect(struct rpc_task *task)
} else {
schedule_delayed_work(&r_xprt->rdma_connect, 0);
if (!RPC_IS_ASYNC(task))
- flush_scheduled_work();
+ flush_delayed_work(&r_xprt->rdma_connect);
}
}
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index fe9306bf10cc..dfcab5ac65af 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -774,8 +774,7 @@ static void xs_destroy(struct rpc_xprt *xprt)
xs_close(xprt);
xs_free_peer_addresses(xprt);
- kfree(xprt->slot);
- kfree(xprt);
+ xprt_free(xprt);
module_put(THIS_MODULE);
}
@@ -1516,7 +1515,7 @@ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port)
xs_update_peer_port(xprt);
}
-static unsigned short xs_get_srcport(struct sock_xprt *transport, struct socket *sock)
+static unsigned short xs_get_srcport(struct sock_xprt *transport)
{
unsigned short port = transport->srcport;
@@ -1525,7 +1524,7 @@ static unsigned short xs_get_srcport(struct sock_xprt *transport, struct socket
return port;
}
-static unsigned short xs_next_srcport(struct sock_xprt *transport, struct socket *sock, unsigned short port)
+static unsigned short xs_next_srcport(struct sock_xprt *transport, unsigned short port)
{
if (transport->srcport != 0)
transport->srcport = 0;
@@ -1535,23 +1534,18 @@ static unsigned short xs_next_srcport(struct sock_xprt *transport, struct socket
return xprt_max_resvport;
return --port;
}
-
-static int xs_bind4(struct sock_xprt *transport, struct socket *sock)
+static int xs_bind(struct sock_xprt *transport, struct socket *sock)
{
- struct sockaddr_in myaddr = {
- .sin_family = AF_INET,
- };
- struct sockaddr_in *sa;
+ struct sockaddr_storage myaddr;
int err, nloop = 0;
- unsigned short port = xs_get_srcport(transport, sock);
+ unsigned short port = xs_get_srcport(transport);
unsigned short last;
- sa = (struct sockaddr_in *)&transport->srcaddr;
- myaddr.sin_addr = sa->sin_addr;
+ memcpy(&myaddr, &transport->srcaddr, transport->xprt.addrlen);
do {
- myaddr.sin_port = htons(port);
- err = kernel_bind(sock, (struct sockaddr *) &myaddr,
- sizeof(myaddr));
+ rpc_set_port((struct sockaddr *)&myaddr, port);
+ err = kernel_bind(sock, (struct sockaddr *)&myaddr,
+ transport->xprt.addrlen);
if (port == 0)
break;
if (err == 0) {
@@ -1559,48 +1553,23 @@ static int xs_bind4(struct sock_xprt *transport, struct socket *sock)
break;
}
last = port;
- port = xs_next_srcport(transport, sock, port);
+ port = xs_next_srcport(transport, port);
if (port > last)
nloop++;
} while (err == -EADDRINUSE && nloop != 2);
- dprintk("RPC: %s %pI4:%u: %s (%d)\n",
- __func__, &myaddr.sin_addr,
- port, err ? "failed" : "ok", err);
- return err;
-}
-
-static int xs_bind6(struct sock_xprt *transport, struct socket *sock)
-{
- struct sockaddr_in6 myaddr = {
- .sin6_family = AF_INET6,
- };
- struct sockaddr_in6 *sa;
- int err, nloop = 0;
- unsigned short port = xs_get_srcport(transport, sock);
- unsigned short last;
- sa = (struct sockaddr_in6 *)&transport->srcaddr;
- myaddr.sin6_addr = sa->sin6_addr;
- do {
- myaddr.sin6_port = htons(port);
- err = kernel_bind(sock, (struct sockaddr *) &myaddr,
- sizeof(myaddr));
- if (port == 0)
- break;
- if (err == 0) {
- transport->srcport = port;
- break;
- }
- last = port;
- port = xs_next_srcport(transport, sock, port);
- if (port > last)
- nloop++;
- } while (err == -EADDRINUSE && nloop != 2);
- dprintk("RPC: xs_bind6 %pI6:%u: %s (%d)\n",
- &myaddr.sin6_addr, port, err ? "failed" : "ok", err);
+ if (myaddr.ss_family == AF_INET)
+ dprintk("RPC: %s %pI4:%u: %s (%d)\n", __func__,
+ &((struct sockaddr_in *)&myaddr)->sin_addr,
+ port, err ? "failed" : "ok", err);
+ else
+ dprintk("RPC: %s %pI6:%u: %s (%d)\n", __func__,
+ &((struct sockaddr_in6 *)&myaddr)->sin6_addr,
+ port, err ? "failed" : "ok", err);
return err;
}
+
#ifdef CONFIG_DEBUG_LOCK_ALLOC
static struct lock_class_key xs_key[2];
static struct lock_class_key xs_slock_key[2];
@@ -1622,6 +1591,18 @@ static inline void xs_reclassify_socket6(struct socket *sock)
sock_lock_init_class_and_name(sk, "slock-AF_INET6-RPC",
&xs_slock_key[1], "sk_lock-AF_INET6-RPC", &xs_key[1]);
}
+
+static inline void xs_reclassify_socket(int family, struct socket *sock)
+{
+ switch (family) {
+ case AF_INET:
+ xs_reclassify_socket4(sock);
+ break;
+ case AF_INET6:
+ xs_reclassify_socket6(sock);
+ break;
+ }
+}
#else
static inline void xs_reclassify_socket4(struct socket *sock)
{
@@ -1630,8 +1611,36 @@ static inline void xs_reclassify_socket4(struct socket *sock)
static inline void xs_reclassify_socket6(struct socket *sock)
{
}
+
+static inline void xs_reclassify_socket(int family, struct socket *sock)
+{
+}
#endif
+static struct socket *xs_create_sock(struct rpc_xprt *xprt,
+ struct sock_xprt *transport, int family, int type, int protocol)
+{
+ struct socket *sock;
+ int err;
+
+ err = __sock_create(xprt->xprt_net, family, type, protocol, &sock, 1);
+ if (err < 0) {
+ dprintk("RPC: can't create %d transport socket (%d).\n",
+ protocol, -err);
+ goto out;
+ }
+ xs_reclassify_socket(family, sock);
+
+ if (xs_bind(transport, sock)) {
+ sock_release(sock);
+ goto out;
+ }
+
+ return sock;
+out:
+ return ERR_PTR(err);
+}
+
static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
{
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
@@ -1661,82 +1670,23 @@ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
xs_udp_do_set_buffer_size(xprt);
}
-/**
- * xs_udp_connect_worker4 - set up a UDP socket
- * @work: RPC transport to connect
- *
- * Invoked by a work queue tasklet.
- */
-static void xs_udp_connect_worker4(struct work_struct *work)
+static void xs_udp_setup_socket(struct work_struct *work)
{
struct sock_xprt *transport =
container_of(work, struct sock_xprt, connect_worker.work);
struct rpc_xprt *xprt = &transport->xprt;
struct socket *sock = transport->sock;
- int err, status = -EIO;
+ int status = -EIO;
if (xprt->shutdown)
goto out;
/* Start by resetting any existing state */
xs_reset_transport(transport);
-
- err = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
- if (err < 0) {
- dprintk("RPC: can't create UDP transport socket (%d).\n", -err);
+ sock = xs_create_sock(xprt, transport,
+ xs_addr(xprt)->sa_family, SOCK_DGRAM, IPPROTO_UDP);
+ if (IS_ERR(sock))
goto out;
- }
- xs_reclassify_socket4(sock);
-
- if (xs_bind4(transport, sock)) {
- sock_release(sock);
- goto out;
- }
-
- dprintk("RPC: worker connecting xprt %p via %s to "
- "%s (port %s)\n", xprt,
- xprt->address_strings[RPC_DISPLAY_PROTO],
- xprt->address_strings[RPC_DISPLAY_ADDR],
- xprt->address_strings[RPC_DISPLAY_PORT]);
-
- xs_udp_finish_connecting(xprt, sock);
- status = 0;
-out:
- xprt_clear_connecting(xprt);
- xprt_wake_pending_tasks(xprt, status);
-}
-
-/**
- * xs_udp_connect_worker6 - set up a UDP socket
- * @work: RPC transport to connect
- *
- * Invoked by a work queue tasklet.
- */
-static void xs_udp_connect_worker6(struct work_struct *work)
-{
- struct sock_xprt *transport =
- container_of(work, struct sock_xprt, connect_worker.work);
- struct rpc_xprt *xprt = &transport->xprt;
- struct socket *sock = transport->sock;
- int err, status = -EIO;
-
- if (xprt->shutdown)
- goto out;
-
- /* Start by resetting any existing state */
- xs_reset_transport(transport);
-
- err = sock_create_kern(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock);
- if (err < 0) {
- dprintk("RPC: can't create UDP transport socket (%d).\n", -err);
- goto out;
- }
- xs_reclassify_socket6(sock);
-
- if (xs_bind6(transport, sock) < 0) {
- sock_release(sock);
- goto out;
- }
dprintk("RPC: worker connecting xprt %p via %s to "
"%s (port %s)\n", xprt,
@@ -1755,12 +1705,12 @@ out:
* We need to preserve the port number so the reply cache on the server can
* find our cached RPC replies when we get around to reconnecting.
*/
-static void xs_abort_connection(struct rpc_xprt *xprt, struct sock_xprt *transport)
+static void xs_abort_connection(struct sock_xprt *transport)
{
int result;
struct sockaddr any;
- dprintk("RPC: disconnecting xprt %p to reuse port\n", xprt);
+ dprintk("RPC: disconnecting xprt %p to reuse port\n", transport);
/*
* Disconnect the transport socket by doing a connect operation
@@ -1770,13 +1720,13 @@ static void xs_abort_connection(struct rpc_xprt *xprt, struct sock_xprt *transpo
any.sa_family = AF_UNSPEC;
result = kernel_connect(transport->sock, &any, sizeof(any), 0);
if (!result)
- xs_sock_mark_closed(xprt);
+ xs_sock_mark_closed(&transport->xprt);
else
dprintk("RPC: AF_UNSPEC connect return code %d\n",
result);
}
-static void xs_tcp_reuse_connection(struct rpc_xprt *xprt, struct sock_xprt *transport)
+static void xs_tcp_reuse_connection(struct sock_xprt *transport)
{
unsigned int state = transport->inet->sk_state;
@@ -1799,7 +1749,7 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt, struct sock_xprt *tra
"sk_shutdown set to %d\n",
__func__, transport->inet->sk_shutdown);
}
- xs_abort_connection(xprt, transport);
+ xs_abort_connection(transport);
}
static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
@@ -1852,12 +1802,12 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
*
* Invoked by a work queue tasklet.
*/
-static void xs_tcp_setup_socket(struct rpc_xprt *xprt,
- struct sock_xprt *transport,
- struct socket *(*create_sock)(struct rpc_xprt *,
- struct sock_xprt *))
+static void xs_tcp_setup_socket(struct work_struct *work)
{
+ struct sock_xprt *transport =
+ container_of(work, struct sock_xprt, connect_worker.work);
struct socket *sock = transport->sock;
+ struct rpc_xprt *xprt = &transport->xprt;
int status = -EIO;
if (xprt->shutdown)
@@ -1865,7 +1815,8 @@ static void xs_tcp_setup_socket(struct rpc_xprt *xprt,
if (!sock) {
clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
- sock = create_sock(xprt, transport);
+ sock = xs_create_sock(xprt, transport,
+ xs_addr(xprt)->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (IS_ERR(sock)) {
status = PTR_ERR(sock);
goto out;
@@ -1876,7 +1827,7 @@ static void xs_tcp_setup_socket(struct rpc_xprt *xprt,
abort_and_exit = test_and_clear_bit(XPRT_CONNECTION_ABORT,
&xprt->state);
/* "close" the socket, preserving the local port */
- xs_tcp_reuse_connection(xprt, transport);
+ xs_tcp_reuse_connection(transport);
if (abort_and_exit)
goto out_eagain;
@@ -1925,84 +1876,6 @@ out:
xprt_wake_pending_tasks(xprt, status);
}
-static struct socket *xs_create_tcp_sock4(struct rpc_xprt *xprt,
- struct sock_xprt *transport)
-{
- struct socket *sock;
- int err;
-
- /* start from scratch */
- err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
- if (err < 0) {
- dprintk("RPC: can't create TCP transport socket (%d).\n",
- -err);
- goto out_err;
- }
- xs_reclassify_socket4(sock);
-
- if (xs_bind4(transport, sock) < 0) {
- sock_release(sock);
- goto out_err;
- }
- return sock;
-out_err:
- return ERR_PTR(-EIO);
-}
-
-/**
- * xs_tcp_connect_worker4 - connect a TCP socket to a remote endpoint
- * @work: RPC transport to connect
- *
- * Invoked by a work queue tasklet.
- */
-static void xs_tcp_connect_worker4(struct work_struct *work)
-{
- struct sock_xprt *transport =
- container_of(work, struct sock_xprt, connect_worker.work);
- struct rpc_xprt *xprt = &transport->xprt;
-
- xs_tcp_setup_socket(xprt, transport, xs_create_tcp_sock4);
-}
-
-static struct socket *xs_create_tcp_sock6(struct rpc_xprt *xprt,
- struct sock_xprt *transport)
-{
- struct socket *sock;
- int err;
-
- /* start from scratch */
- err = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &sock);
- if (err < 0) {
- dprintk("RPC: can't create TCP transport socket (%d).\n",
- -err);
- goto out_err;
- }
- xs_reclassify_socket6(sock);
-
- if (xs_bind6(transport, sock) < 0) {
- sock_release(sock);
- goto out_err;
- }
- return sock;
-out_err:
- return ERR_PTR(-EIO);
-}
-
-/**
- * xs_tcp_connect_worker6 - connect a TCP socket to a remote endpoint
- * @work: RPC transport to connect
- *
- * Invoked by a work queue tasklet.
- */
-static void xs_tcp_connect_worker6(struct work_struct *work)
-{
- struct sock_xprt *transport =
- container_of(work, struct sock_xprt, connect_worker.work);
- struct rpc_xprt *xprt = &transport->xprt;
-
- xs_tcp_setup_socket(xprt, transport, xs_create_tcp_sock6);
-}
-
/**
* xs_connect - connect a socket to a remote endpoint
* @task: address of RPC task that manages state of connect request
@@ -2262,6 +2135,31 @@ static struct rpc_xprt_ops bc_tcp_ops = {
.print_stats = xs_tcp_print_stats,
};
+static int xs_init_anyaddr(const int family, struct sockaddr *sap)
+{
+ static const struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl(INADDR_ANY),
+ };
+ static const struct sockaddr_in6 sin6 = {
+ .sin6_family = AF_INET6,
+ .sin6_addr = IN6ADDR_ANY_INIT,
+ };
+
+ switch (family) {
+ case AF_INET:
+ memcpy(sap, &sin, sizeof(sin));
+ break;
+ case AF_INET6:
+ memcpy(sap, &sin6, sizeof(sin6));
+ break;
+ default:
+ dprintk("RPC: %s: Bad address family\n", __func__);
+ return -EAFNOSUPPORT;
+ }
+ return 0;
+}
+
static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
unsigned int slot_table_size)
{
@@ -2273,27 +2171,25 @@ static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
return ERR_PTR(-EBADF);
}
- new = kzalloc(sizeof(*new), GFP_KERNEL);
- if (new == NULL) {
+ xprt = xprt_alloc(args->net, sizeof(*new), slot_table_size);
+ if (xprt == NULL) {
dprintk("RPC: xs_setup_xprt: couldn't allocate "
"rpc_xprt\n");
return ERR_PTR(-ENOMEM);
}
- xprt = &new->xprt;
-
- xprt->max_reqs = slot_table_size;
- xprt->slot = kcalloc(xprt->max_reqs, sizeof(struct rpc_rqst), GFP_KERNEL);
- if (xprt->slot == NULL) {
- kfree(xprt);
- dprintk("RPC: xs_setup_xprt: couldn't allocate slot "
- "table\n");
- return ERR_PTR(-ENOMEM);
- }
+ new = container_of(xprt, struct sock_xprt, xprt);
memcpy(&xprt->addr, args->dstaddr, args->addrlen);
xprt->addrlen = args->addrlen;
if (args->srcaddr)
memcpy(&new->srcaddr, args->srcaddr, args->addrlen);
+ else {
+ int err;
+ err = xs_init_anyaddr(args->dstaddr->sa_family,
+ (struct sockaddr *)&new->srcaddr);
+ if (err != 0)
+ return ERR_PTR(err);
+ }
return xprt;
}
@@ -2341,7 +2237,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
xprt_set_bound(xprt);
INIT_DELAYED_WORK(&transport->connect_worker,
- xs_udp_connect_worker4);
+ xs_udp_setup_socket);
xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP);
break;
case AF_INET6:
@@ -2349,7 +2245,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
xprt_set_bound(xprt);
INIT_DELAYED_WORK(&transport->connect_worker,
- xs_udp_connect_worker6);
+ xs_udp_setup_socket);
xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP6);
break;
default:
@@ -2371,8 +2267,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
return xprt;
ret = ERR_PTR(-EINVAL);
out_err:
- kfree(xprt->slot);
- kfree(xprt);
+ xprt_free(xprt);
return ret;
}
@@ -2416,7 +2311,7 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
xprt_set_bound(xprt);
INIT_DELAYED_WORK(&transport->connect_worker,
- xs_tcp_connect_worker4);
+ xs_tcp_setup_socket);
xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP);
break;
case AF_INET6:
@@ -2424,7 +2319,7 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
xprt_set_bound(xprt);
INIT_DELAYED_WORK(&transport->connect_worker,
- xs_tcp_connect_worker6);
+ xs_tcp_setup_socket);
xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP6);
break;
default:
@@ -2447,8 +2342,7 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
return xprt;
ret = ERR_PTR(-EINVAL);
out_err:
- kfree(xprt->slot);
- kfree(xprt);
+ xprt_free(xprt);
return ret;
}
@@ -2507,15 +2401,10 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
goto out_err;
}
- if (xprt_bound(xprt))
- dprintk("RPC: set up xprt to %s (port %s) via %s\n",
- xprt->address_strings[RPC_DISPLAY_ADDR],
- xprt->address_strings[RPC_DISPLAY_PORT],
- xprt->address_strings[RPC_DISPLAY_PROTO]);
- else
- dprintk("RPC: set up xprt to %s (autobind) via %s\n",
- xprt->address_strings[RPC_DISPLAY_ADDR],
- xprt->address_strings[RPC_DISPLAY_PROTO]);
+ dprintk("RPC: set up xprt to %s (port %s) via %s\n",
+ xprt->address_strings[RPC_DISPLAY_ADDR],
+ xprt->address_strings[RPC_DISPLAY_PORT],
+ xprt->address_strings[RPC_DISPLAY_PROTO]);
/*
* Since we don't want connections for the backchannel, we set
@@ -2528,8 +2417,7 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
return xprt;
ret = ERR_PTR(-EINVAL);
out_err:
- kfree(xprt->slot);
- kfree(xprt);
+ xprt_free(xprt);
return ret;
}
diff --git a/net/tipc/addr.c b/net/tipc/addr.c
index c048543ffbeb..8a2e89bffde5 100644
--- a/net/tipc/addr.c
+++ b/net/tipc/addr.c
@@ -41,11 +41,6 @@
#include "cluster.h"
#include "net.h"
-u32 tipc_get_addr(void)
-{
- return tipc_own_addr;
-}
-
/**
* tipc_addr_domain_valid - validates a network domain address
*
@@ -89,7 +84,7 @@ int tipc_addr_domain_valid(u32 addr)
int tipc_addr_node_valid(u32 addr)
{
- return (tipc_addr_domain_valid(addr) && tipc_node(addr));
+ return tipc_addr_domain_valid(addr) && tipc_node(addr);
}
int tipc_in_scope(u32 domain, u32 addr)
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index a008c6689305..22a60fc98392 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -121,6 +121,9 @@ static DEFINE_SPINLOCK(bc_lock);
const char tipc_bclink_name[] = "broadcast-link";
+static void tipc_nmap_diff(struct tipc_node_map *nm_a,
+ struct tipc_node_map *nm_b,
+ struct tipc_node_map *nm_diff);
static u32 buf_seqno(struct sk_buff *buf)
{
@@ -143,6 +146,19 @@ static void bcbuf_decr_acks(struct sk_buff *buf)
}
+static void bclink_set_last_sent(void)
+{
+ if (bcl->next_out)
+ bcl->fsm_msg_cnt = mod(buf_seqno(bcl->next_out) - 1);
+ else
+ bcl->fsm_msg_cnt = mod(bcl->next_out_no - 1);
+}
+
+u32 tipc_bclink_get_last_sent(void)
+{
+ return bcl->fsm_msg_cnt;
+}
+
/**
* bclink_set_gap - set gap according to contents of current deferred pkt queue
*
@@ -171,7 +187,7 @@ static void bclink_set_gap(struct tipc_node *n_ptr)
static int bclink_ack_allowed(u32 n)
{
- return((n % TIPC_MIN_LINK_WIN) == tipc_own_tag);
+ return (n % TIPC_MIN_LINK_WIN) == tipc_own_tag;
}
@@ -237,8 +253,10 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
/* Try resolving broadcast link congestion, if necessary */
- if (unlikely(bcl->next_out))
+ if (unlikely(bcl->next_out)) {
tipc_link_push_queue(bcl);
+ bclink_set_last_sent();
+ }
if (unlikely(released && !list_empty(&bcl->waiting_ports)))
tipc_link_wakeup_ports(bcl, 0);
spin_unlock_bh(&bc_lock);
@@ -272,7 +290,7 @@ static void bclink_send_nack(struct tipc_node *n_ptr)
if (!less(n_ptr->bclink.gap_after, n_ptr->bclink.gap_to))
return;
- buf = buf_acquire(INT_H_SIZE);
+ buf = tipc_buf_acquire(INT_H_SIZE);
if (buf) {
msg = buf_msg(buf);
tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG,
@@ -395,7 +413,7 @@ int tipc_bclink_send_msg(struct sk_buff *buf)
if (unlikely(res == -ELINKCONG))
buf_discard(buf);
else
- bcl->stats.sent_info++;
+ bclink_set_last_sent();
if (bcl->out_queue_size > bcl->stats.max_queue_sz)
bcl->stats.max_queue_sz = bcl->out_queue_size;
@@ -529,15 +547,6 @@ receive:
tipc_node_unlock(node);
}
-u32 tipc_bclink_get_last_sent(void)
-{
- u32 last_sent = mod(bcl->next_out_no - 1);
-
- if (bcl->next_out)
- last_sent = mod(buf_seqno(bcl->next_out) - 1);
- return last_sent;
-}
-
u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr)
{
return (n_ptr->bclink.supported &&
@@ -570,6 +579,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
msg = buf_msg(buf);
msg_set_non_seq(msg, 1);
msg_set_mc_netid(msg, tipc_net_id);
+ bcl->stats.sent_info++;
}
/* Send buffer over bearers until all targets reached */
@@ -609,11 +619,13 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
bcbearer->remains = bcbearer->remains_new;
}
- /* Unable to reach all targets */
+ /*
+ * 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)
+ */
- bcbearer->bearer.publ.blocked = 1;
- bcl->stats.bearer_congs++;
- return 1;
+ return TIPC_OK;
}
/**
@@ -862,8 +874,9 @@ void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node)
* @nm_diff: output node map A-B (i.e. nodes of A that are not in B)
*/
-void tipc_nmap_diff(struct tipc_node_map *nm_a, struct tipc_node_map *nm_b,
- struct tipc_node_map *nm_diff)
+static void tipc_nmap_diff(struct tipc_node_map *nm_a,
+ struct tipc_node_map *nm_b,
+ struct tipc_node_map *nm_diff)
{
int stop = ARRAY_SIZE(nm_a->map);
int w;
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h
index e8c2b81658c7..011c03f0a4ab 100644
--- a/net/tipc/bcast.h
+++ b/net/tipc/bcast.h
@@ -84,9 +84,6 @@ static inline int tipc_nmap_equal(struct tipc_node_map *nm_a, struct tipc_node_m
return !memcmp(nm_a, nm_b, sizeof(*nm_a));
}
-void tipc_nmap_diff(struct tipc_node_map *nm_a, struct tipc_node_map *nm_b,
- struct tipc_node_map *nm_diff);
-
void tipc_port_list_add(struct port_list *pl_ptr, u32 port);
void tipc_port_list_free(struct port_list *pl_ptr);
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 52ae17b2583e..9927d1d56c4f 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -63,7 +63,7 @@ static int media_name_valid(const char *name)
len = strlen(name);
if ((len + 1) > TIPC_MAX_MEDIA_NAME)
return 0;
- return (strspn(name, tipc_alphabet) == len);
+ return strspn(name, tipc_alphabet) == len;
}
/**
@@ -288,9 +288,6 @@ static struct bearer *bearer_find(const char *name)
struct bearer *b_ptr;
u32 i;
- if (tipc_mode != TIPC_NET_MODE)
- return NULL;
-
for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
if (b_ptr->active && (!strcmp(b_ptr->publ.name, name)))
return b_ptr;
@@ -559,8 +556,6 @@ restart:
}
b_ptr = &tipc_bearers[bearer_id];
- memset(b_ptr, 0, sizeof(struct bearer));
-
strcpy(b_ptr->publ.name, name);
res = m_ptr->enable_bearer(&b_ptr->publ);
if (res) {
@@ -630,30 +625,17 @@ int tipc_block_bearer(const char *name)
* Note: This routine assumes caller holds tipc_net_lock.
*/
-static int bearer_disable(const char *name)
+static int bearer_disable(struct bearer *b_ptr)
{
- struct bearer *b_ptr;
struct link *l_ptr;
struct link *temp_l_ptr;
- b_ptr = bearer_find(name);
- if (!b_ptr) {
- warn("Attempt to disable unknown bearer <%s>\n", name);
- return -EINVAL;
- }
-
- info("Disabling bearer <%s>\n", name);
+ info("Disabling bearer <%s>\n", b_ptr->publ.name);
tipc_disc_stop_link_req(b_ptr->link_req);
spin_lock_bh(&b_ptr->publ.lock);
b_ptr->link_req = NULL;
b_ptr->publ.blocked = 1;
- if (b_ptr->media->disable_bearer) {
- spin_unlock_bh(&b_ptr->publ.lock);
- write_unlock_bh(&tipc_net_lock);
- b_ptr->media->disable_bearer(&b_ptr->publ);
- write_lock_bh(&tipc_net_lock);
- spin_lock_bh(&b_ptr->publ.lock);
- }
+ b_ptr->media->disable_bearer(&b_ptr->publ);
list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
tipc_link_delete(l_ptr);
}
@@ -664,10 +646,16 @@ static int bearer_disable(const char *name)
int tipc_disable_bearer(const char *name)
{
+ struct bearer *b_ptr;
int res;
write_lock_bh(&tipc_net_lock);
- res = bearer_disable(name);
+ b_ptr = bearer_find(name);
+ if (b_ptr == NULL) {
+ warn("Attempt to disable unknown bearer <%s>\n", name);
+ res = -EINVAL;
+ } else
+ res = bearer_disable(b_ptr);
write_unlock_bh(&tipc_net_lock);
return res;
}
@@ -680,13 +668,7 @@ void tipc_bearer_stop(void)
for (i = 0; i < MAX_BEARERS; i++) {
if (tipc_bearers[i].active)
- tipc_bearers[i].publ.blocked = 1;
- }
- for (i = 0; i < MAX_BEARERS; i++) {
- if (tipc_bearers[i].active)
- bearer_disable(tipc_bearers[i].publ.name);
+ bearer_disable(&tipc_bearers[i]);
}
media_count = 0;
}
-
-
diff --git a/net/tipc/cluster.c b/net/tipc/cluster.c
index e68f705381bc..7fea14b98b97 100644
--- a/net/tipc/cluster.c
+++ b/net/tipc/cluster.c
@@ -113,25 +113,6 @@ void tipc_cltr_delete(struct cluster *c_ptr)
kfree(c_ptr);
}
-u32 tipc_cltr_next_node(struct cluster *c_ptr, u32 addr)
-{
- struct tipc_node *n_ptr;
- u32 n_num = tipc_node(addr) + 1;
-
- if (!c_ptr)
- return addr;
- for (; n_num <= c_ptr->highest_node; n_num++) {
- n_ptr = c_ptr->nodes[n_num];
- if (n_ptr && tipc_node_has_active_links(n_ptr))
- return n_ptr->addr;
- }
- for (n_num = 1; n_num < tipc_node(addr); n_num++) {
- n_ptr = c_ptr->nodes[n_num];
- if (n_ptr && tipc_node_has_active_links(n_ptr))
- return n_ptr->addr;
- }
- return 0;
-}
void tipc_cltr_attach_node(struct cluster *c_ptr, struct tipc_node *n_ptr)
{
@@ -232,7 +213,7 @@ struct tipc_node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector)
static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest)
{
u32 size = INT_H_SIZE + data_size;
- struct sk_buff *buf = buf_acquire(size);
+ struct sk_buff *buf = tipc_buf_acquire(size);
struct tipc_msg *msg;
if (buf) {
diff --git a/net/tipc/cluster.h b/net/tipc/cluster.h
index 333efb0b9c44..32636d98c9c6 100644
--- a/net/tipc/cluster.h
+++ b/net/tipc/cluster.h
@@ -75,7 +75,7 @@ void tipc_cltr_attach_node(struct cluster *c_ptr, struct tipc_node *n_ptr);
void tipc_cltr_send_slave_routes(struct cluster *c_ptr, u32 dest);
void tipc_cltr_broadcast(struct sk_buff *buf);
int tipc_cltr_init(void);
-u32 tipc_cltr_next_node(struct cluster *c_ptr, u32 addr);
+
void tipc_cltr_bcast_new_route(struct cluster *c_ptr, u32 dest, u32 lo, u32 hi);
void tipc_cltr_send_local_routes(struct cluster *c_ptr, u32 dest);
void tipc_cltr_bcast_lost_route(struct cluster *c_ptr, u32 dest, u32 lo, u32 hi);
diff --git a/net/tipc/config.c b/net/tipc/config.c
index 961d1b097146..50a6133a3668 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -95,7 +95,7 @@ int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type,
return 1;
}
-struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value)
+static struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value)
{
struct sk_buff *buf;
__be32 value_net;
@@ -109,6 +109,11 @@ struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value)
return buf;
}
+static struct sk_buff *tipc_cfg_reply_unsigned(u32 value)
+{
+ return tipc_cfg_reply_unsigned_type(TIPC_TLV_UNSIGNED, value);
+}
+
struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string)
{
struct sk_buff *buf;
@@ -120,139 +125,6 @@ struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string)
return buf;
}
-
-#if 0
-
-/* Now obsolete code for handling commands not yet implemented the new way */
-
-/*
- * Some of this code assumed that the manager structure contains two added
- * fields:
- * u32 link_subscriptions;
- * struct list_head link_subscribers;
- * which are currently not present. These fields may need to be re-introduced
- * if and when support for link subscriptions is added.
- */
-
-void tipc_cfg_link_event(u32 addr, char *name, int up)
-{
- /* TIPC DOESN'T HANDLE LINK EVENT SUBSCRIPTIONS AT THE MOMENT */
-}
-
-int tipc_cfg_cmd(const struct tipc_cmd_msg * msg,
- char *data,
- u32 sz,
- u32 *ret_size,
- struct tipc_portid *orig)
-{
- int rv = -EINVAL;
- u32 cmd = msg->cmd;
-
- *ret_size = 0;
- switch (cmd) {
- case TIPC_REMOVE_LINK:
- case TIPC_CMD_BLOCK_LINK:
- case TIPC_CMD_UNBLOCK_LINK:
- if (!cfg_check_connection(orig))
- rv = link_control(msg->argv.link_name, msg->cmd, 0);
- break;
- case TIPC_ESTABLISH:
- {
- int connected;
-
- tipc_isconnected(mng.conn_port_ref, &connected);
- if (connected || !orig) {
- rv = TIPC_FAILURE;
- break;
- }
- rv = tipc_connect2port(mng.conn_port_ref, orig);
- if (rv == TIPC_OK)
- orig = 0;
- break;
- }
- case TIPC_GET_PEER_ADDRESS:
- *ret_size = link_peer_addr(msg->argv.link_name, data, sz);
- break;
- case TIPC_GET_ROUTES:
- rv = TIPC_OK;
- break;
- default: {}
- }
- if (*ret_size)
- rv = TIPC_OK;
- return rv;
-}
-
-static void cfg_cmd_event(struct tipc_cmd_msg *msg,
- char *data,
- u32 sz,
- struct tipc_portid const *orig)
-{
- int rv = -EINVAL;
- struct tipc_cmd_result_msg rmsg;
- struct iovec msg_sect[2];
- int *arg;
-
- msg->cmd = ntohl(msg->cmd);
-
- cfg_prepare_res_msg(msg->cmd, msg->usr_handle, rv, &rmsg, msg_sect,
- data, 0);
- if (ntohl(msg->magic) != TIPC_MAGIC)
- goto exit;
-
- switch (msg->cmd) {
- case TIPC_CREATE_LINK:
- if (!cfg_check_connection(orig))
- rv = disc_create_link(&msg->argv.create_link);
- break;
- case TIPC_LINK_SUBSCRIBE:
- {
- struct subscr_data *sub;
-
- if (mng.link_subscriptions > 64)
- break;
- sub = kmalloc(sizeof(*sub),
- GFP_ATOMIC);
- if (sub == NULL) {
- warn("Memory squeeze; dropped remote link subscription\n");
- break;
- }
- INIT_LIST_HEAD(&sub->subd_list);
- tipc_createport(mng.user_ref,
- (void *)sub,
- TIPC_HIGH_IMPORTANCE,
- 0,
- 0,
- (tipc_conn_shutdown_event)cfg_linksubscr_cancel,
- 0,
- 0,
- (tipc_conn_msg_event)cfg_linksubscr_cancel,
- 0,
- &sub->port_ref);
- if (!sub->port_ref) {
- kfree(sub);
- break;
- }
- memcpy(sub->usr_handle,msg->usr_handle,
- sizeof(sub->usr_handle));
- sub->domain = msg->argv.domain;
- list_add_tail(&sub->subd_list, &mng.link_subscribers);
- tipc_connect2port(sub->port_ref, orig);
- rmsg.retval = TIPC_OK;
- tipc_send(sub->port_ref, 2u, msg_sect);
- mng.link_subscriptions++;
- return;
- }
- default:
- rv = tipc_cfg_cmd(msg, data, sz, (u32 *)&msg_sect[1].iov_len, orig);
- }
-exit:
- rmsg.result_len = htonl(msg_sect[1].iov_len);
- rmsg.retval = htonl(rv);
- tipc_cfg_respond(msg_sect, 2u, orig);
-}
-#endif
-
#define MAX_STATS_INFO 2000
static struct sk_buff *tipc_show_stats(void)
@@ -557,14 +429,6 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
case TIPC_CMD_SHOW_PORTS:
rep_tlv_buf = tipc_port_get_ports();
break;
-#if 0
- case TIPC_CMD_SHOW_PORT_STATS:
- rep_tlv_buf = port_show_stats(req_tlv_area, req_tlv_space);
- break;
- case TIPC_CMD_RESET_PORT_STATS:
- rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED);
- break;
-#endif
case TIPC_CMD_SET_LOG_SIZE:
rep_tlv_buf = tipc_log_resize_cmd(req_tlv_area, req_tlv_space);
break;
diff --git a/net/tipc/config.h b/net/tipc/config.h
index 5cd7cc56c54d..481e12ece715 100644
--- a/net/tipc/config.h
+++ b/net/tipc/config.h
@@ -45,7 +45,6 @@
struct sk_buff *tipc_cfg_reply_alloc(int payload_size);
int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type,
void *tlv_data, int tlv_data_size);
-struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value);
struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string);
static inline struct sk_buff *tipc_cfg_reply_none(void)
@@ -53,11 +52,6 @@ static inline struct sk_buff *tipc_cfg_reply_none(void)
return tipc_cfg_reply_alloc(0);
}
-static inline struct sk_buff *tipc_cfg_reply_unsigned(u32 value)
-{
- return tipc_cfg_reply_unsigned_type(TIPC_TLV_UNSIGNED, value);
-}
-
static inline struct sk_buff *tipc_cfg_reply_error_string(char *string)
{
return tipc_cfg_reply_string_type(TIPC_TLV_ERROR_STRING, string);
diff --git a/net/tipc/core.c b/net/tipc/core.c
index 696468117985..e2a09eb8efd4 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -96,13 +96,8 @@ int tipc_net_id;
int tipc_remote_management;
-int tipc_get_mode(void)
-{
- return tipc_mode;
-}
-
/**
- * buf_acquire - creates a TIPC message buffer
+ * tipc_buf_acquire - creates a TIPC message buffer
* @size: message size (including TIPC header)
*
* Returns a new buffer with data pointers set to the specified size.
@@ -111,7 +106,7 @@ int tipc_get_mode(void)
* There may also be unrequested tailroom present at the buffer's end.
*/
-struct sk_buff *buf_acquire(u32 size)
+struct sk_buff *tipc_buf_acquire(u32 size)
{
struct sk_buff *skb;
unsigned int buf_size = (BUF_HEADROOM + size + 3) & ~3u;
@@ -129,7 +124,7 @@ struct sk_buff *buf_acquire(u32 size)
* tipc_core_stop_net - shut down TIPC networking sub-systems
*/
-void tipc_core_stop_net(void)
+static void tipc_core_stop_net(void)
{
tipc_eth_media_stop();
tipc_net_stop();
@@ -154,7 +149,7 @@ int tipc_core_start_net(unsigned long addr)
* tipc_core_stop - switch TIPC from SINGLE NODE to NOT RUNNING mode
*/
-void tipc_core_stop(void)
+static void tipc_core_stop(void)
{
if (tipc_mode != TIPC_NODE_MODE)
return;
@@ -169,13 +164,14 @@ void tipc_core_stop(void)
tipc_nametbl_stop();
tipc_ref_table_stop();
tipc_socket_stop();
+ tipc_log_resize(0);
}
/**
* tipc_core_start - switch TIPC from NOT RUNNING to SINGLE NODE mode
*/
-int tipc_core_start(void)
+static int tipc_core_start(void)
{
int res;
@@ -203,7 +199,9 @@ static int __init tipc_init(void)
{
int res;
- tipc_log_resize(CONFIG_TIPC_LOG);
+ if (tipc_log_resize(CONFIG_TIPC_LOG) != 0)
+ warn("Unable to create log buffer\n");
+
info("Activated (version " TIPC_MOD_VER
" compiled " __DATE__ " " __TIME__ ")\n");
@@ -230,7 +228,6 @@ static void __exit tipc_exit(void)
tipc_core_stop_net();
tipc_core_stop();
info("Deactivated\n");
- tipc_log_resize(0);
}
module_init(tipc_init);
@@ -244,8 +241,6 @@ MODULE_VERSION(TIPC_MOD_VER);
EXPORT_SYMBOL(tipc_attach);
EXPORT_SYMBOL(tipc_detach);
-EXPORT_SYMBOL(tipc_get_addr);
-EXPORT_SYMBOL(tipc_get_mode);
EXPORT_SYMBOL(tipc_createport);
EXPORT_SYMBOL(tipc_deleteport);
EXPORT_SYMBOL(tipc_ownidentity);
@@ -260,23 +255,10 @@ EXPORT_SYMBOL(tipc_withdraw);
EXPORT_SYMBOL(tipc_connect2port);
EXPORT_SYMBOL(tipc_disconnect);
EXPORT_SYMBOL(tipc_shutdown);
-EXPORT_SYMBOL(tipc_isconnected);
-EXPORT_SYMBOL(tipc_peer);
-EXPORT_SYMBOL(tipc_ref_valid);
EXPORT_SYMBOL(tipc_send);
-EXPORT_SYMBOL(tipc_send_buf);
EXPORT_SYMBOL(tipc_send2name);
-EXPORT_SYMBOL(tipc_forward2name);
-EXPORT_SYMBOL(tipc_send_buf2name);
-EXPORT_SYMBOL(tipc_forward_buf2name);
EXPORT_SYMBOL(tipc_send2port);
-EXPORT_SYMBOL(tipc_forward2port);
-EXPORT_SYMBOL(tipc_send_buf2port);
-EXPORT_SYMBOL(tipc_forward_buf2port);
EXPORT_SYMBOL(tipc_multicast);
-/* EXPORT_SYMBOL(tipc_multicast_buf); not available yet */
-EXPORT_SYMBOL(tipc_ispublished);
-EXPORT_SYMBOL(tipc_available_nodes);
/* TIPC API for external bearers (see tipc_bearer.h) */
@@ -293,6 +275,4 @@ EXPORT_SYMBOL(tipc_createport_raw);
EXPORT_SYMBOL(tipc_reject_msg);
EXPORT_SYMBOL(tipc_send_buf_fast);
EXPORT_SYMBOL(tipc_acknowledge);
-EXPORT_SYMBOL(tipc_get_port);
-EXPORT_SYMBOL(tipc_get_handle);
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 188799017abd..e19389e57227 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -83,9 +83,7 @@
* Note: TIPC_LOG is configured to echo its output to the system console;
* user-defined buffers can be configured to do the same thing.
*/
-
extern struct print_buf *const TIPC_NULL;
-extern struct print_buf *const TIPC_CONS;
extern struct print_buf *const TIPC_LOG;
void tipc_printf(struct print_buf *, const char *fmt, ...);
@@ -204,10 +202,7 @@ extern atomic_t tipc_user_count;
* Routines available to privileged subsystems
*/
-extern int tipc_core_start(void);
-extern void tipc_core_stop(void);
-extern int tipc_core_start_net(unsigned long addr);
-extern void tipc_core_stop_net(void);
+extern int tipc_core_start_net(unsigned long);
extern int tipc_handler_start(void);
extern void tipc_handler_stop(void);
extern int tipc_netlink_start(void);
@@ -328,7 +323,7 @@ static inline struct tipc_msg *buf_msg(struct sk_buff *skb)
return (struct tipc_msg *)skb->data;
}
-extern struct sk_buff *buf_acquire(u32 size);
+extern struct sk_buff *tipc_buf_acquire(u32 size);
/**
* buf_discard - frees a TIPC message buffer
diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c
index 1885a7edb0c8..46f51d208e5e 100644
--- a/net/tipc/dbg.c
+++ b/net/tipc/dbg.c
@@ -52,7 +52,7 @@ static struct print_buf null_buf = { NULL, 0, NULL, 0 };
struct print_buf *const TIPC_NULL = &null_buf;
static struct print_buf cons_buf = { NULL, 0, NULL, 1 };
-struct print_buf *const TIPC_CONS = &cons_buf;
+static struct print_buf *const TIPC_CONS = &cons_buf;
static struct print_buf log_buf = { NULL, 0, NULL, 1 };
struct print_buf *const TIPC_LOG = &log_buf;
@@ -76,6 +76,10 @@ struct print_buf *const TIPC_LOG = &log_buf;
static char print_string[TIPC_PB_MAX_STR];
static DEFINE_SPINLOCK(print_lock);
+static void tipc_printbuf_reset(struct print_buf *pb);
+static int tipc_printbuf_empty(struct print_buf *pb);
+static void tipc_printbuf_move(struct print_buf *pb_to,
+ struct print_buf *pb_from);
#define FORMAT(PTR,LEN,FMT) \
{\
@@ -116,7 +120,7 @@ void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size)
* @pb: pointer to print buffer structure
*/
-void tipc_printbuf_reset(struct print_buf *pb)
+static void tipc_printbuf_reset(struct print_buf *pb)
{
if (pb->buf) {
pb->crs = pb->buf;
@@ -132,9 +136,9 @@ void tipc_printbuf_reset(struct print_buf *pb)
* Returns non-zero if print buffer is empty.
*/
-int tipc_printbuf_empty(struct print_buf *pb)
+static int tipc_printbuf_empty(struct print_buf *pb)
{
- return (!pb->buf || (pb->crs == pb->buf));
+ return !pb->buf || (pb->crs == pb->buf);
}
/**
@@ -169,7 +173,7 @@ int tipc_printbuf_validate(struct print_buf *pb)
tipc_printf(pb, err);
}
}
- return (pb->crs - pb->buf + 1);
+ return pb->crs - pb->buf + 1;
}
/**
@@ -181,7 +185,8 @@ int tipc_printbuf_validate(struct print_buf *pb)
* Source print buffer becomes empty if a successful move occurs.
*/
-void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
+static void tipc_printbuf_move(struct print_buf *pb_to,
+ struct print_buf *pb_from)
{
int len;
diff --git a/net/tipc/dbg.h b/net/tipc/dbg.h
index 5ef1bc8f64ef..3ba6ba8b434a 100644
--- a/net/tipc/dbg.h
+++ b/net/tipc/dbg.h
@@ -56,10 +56,7 @@ struct print_buf {
#define TIPC_PB_MAX_STR 512 /* max printable string (with trailing NUL) */
void tipc_printbuf_init(struct print_buf *pb, char *buf, u32 size);
-void tipc_printbuf_reset(struct print_buf *pb);
-int tipc_printbuf_empty(struct print_buf *pb);
int tipc_printbuf_validate(struct print_buf *pb);
-void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from);
int tipc_log_resize(int log_size);
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index fc1fcf5e6b53..4a7cd3719b78 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -46,16 +46,6 @@
#define TIPC_LINK_REQ_FAST 2000 /* normal delay if bearer has no links */
#define TIPC_LINK_REQ_SLOW 600000 /* normal delay if bearer has links */
-#if 0
-#define GET_NODE_INFO 300
-#define GET_NODE_INFO_RESULT 301
-#define FORWARD_LINK_PROBE 302
-#define LINK_REQUEST_REJECTED 303
-#define LINK_REQUEST_ACCEPTED 304
-#define DROP_LINK_REQUEST 305
-#define CHECK_LINK_COUNT 306
-#endif
-
/*
* TODO: Most of the inter-cluster setup stuff should be
* rewritten, and be made conformant with specification.
@@ -78,30 +68,6 @@ struct link_req {
unsigned int timer_intv;
};
-
-#if 0
-int disc_create_link(const struct tipc_link_create *argv)
-{
- /*
- * Code for inter cluster link setup here
- */
- return TIPC_OK;
-}
-#endif
-
-/*
- * disc_lost_link(): A link has lost contact
- */
-
-void tipc_disc_link_event(u32 addr, char *name, int up)
-{
- if (in_own_cluster(addr))
- return;
- /*
- * Code for inter cluster link setup here
- */
-}
-
/**
* tipc_disc_init_msg - initialize a link setup message
* @type: message type (request or response)
@@ -115,7 +81,7 @@ static struct sk_buff *tipc_disc_init_msg(u32 type,
u32 dest_domain,
struct bearer *b_ptr)
{
- struct sk_buff *buf = buf_acquire(DSC_H_SIZE);
+ struct sk_buff *buf = tipc_buf_acquire(DSC_H_SIZE);
struct tipc_msg *msg;
if (buf) {
@@ -203,6 +169,14 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr)
return;
}
spin_lock_bh(&n_ptr->lock);
+
+ /* Don't talk to neighbor during cleanup after last session */
+
+ if (n_ptr->cleanup_required) {
+ spin_unlock_bh(&n_ptr->lock);
+ return;
+ }
+
link = n_ptr->links[b_ptr->identity];
if (!link) {
dbg("creating link\n");
diff --git a/net/tipc/discover.h b/net/tipc/discover.h
index c36eaeb7d5d0..f8e750636123 100644
--- a/net/tipc/discover.h
+++ b/net/tipc/discover.h
@@ -50,9 +50,4 @@ void tipc_disc_stop_link_req(struct link_req *req);
void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr);
-void tipc_disc_link_event(u32 addr, char *name, int up);
-#if 0
-int disc_create_link(const struct tipc_link_create *argv);
-#endif
-
#endif
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index 6230d16020c4..6e988ba485fd 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -72,17 +72,26 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
{
struct sk_buff *clone;
struct net_device *dev;
+ int delta;
clone = skb_clone(buf, GFP_ATOMIC);
- if (clone) {
- skb_reset_network_header(clone);
- dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev;
- clone->dev = dev;
- dev_hard_header(clone, dev, ETH_P_TIPC,
- &dest->dev_addr.eth_addr,
- dev->dev_addr, clone->len);
- dev_queue_xmit(clone);
+ if (!clone)
+ return 0;
+
+ dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev;
+ delta = dev->hard_header_len - skb_headroom(buf);
+
+ if ((delta > 0) &&
+ pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) {
+ kfree_skb(clone);
+ return 0;
}
+
+ skb_reset_network_header(clone);
+ clone->dev = dev;
+ dev_hard_header(clone, dev, ETH_P_TIPC, &dest->dev_addr.eth_addr,
+ dev->dev_addr, clone->len);
+ dev_queue_xmit(clone);
return 0;
}
@@ -92,15 +101,12 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
* Accept only packets explicitly sent to this node, or broadcast packets;
* ignores packets sent using Ethernet multicast, and traffic sent to other
* nodes (which can happen if interface is running in promiscuous mode).
- * Routine truncates any Ethernet padding/CRC appended to the message,
- * and ensures message size matches actual length
*/
static int recv_msg(struct sk_buff *buf, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv;
- u32 size;
if (!net_eq(dev_net(dev), &init_net)) {
kfree_skb(buf);
@@ -109,13 +115,9 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
if (likely(eb_ptr->bearer)) {
if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
- size = msg_size((struct tipc_msg *)buf->data);
- skb_trim(buf, size);
- if (likely(buf->len == size)) {
- buf->next = NULL;
- tipc_recv_msg(buf, eb_ptr->bearer);
- return 0;
- }
+ buf->next = NULL;
+ tipc_recv_msg(buf, eb_ptr->bearer);
+ return 0;
}
}
kfree_skb(buf);
@@ -133,6 +135,16 @@ static int enable_bearer(struct tipc_bearer *tb_ptr)
struct eth_bearer *eb_ptr = &eth_bearers[0];
struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
+ int pending_dev = 0;
+
+ /* Find unused Ethernet bearer structure */
+
+ while (eb_ptr->dev) {
+ if (!eb_ptr->bearer)
+ pending_dev++;
+ if (++eb_ptr == stop)
+ return pending_dev ? -EAGAIN : -EDQUOT;
+ }
/* Find device with specified name */
diff --git a/net/tipc/link.c b/net/tipc/link.c
index a3616b99529b..b31992ccd5d3 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -99,23 +99,6 @@ struct link_name {
char if_peer[TIPC_MAX_IF_NAME];
};
-#if 0
-
-/* LINK EVENT CODE IS NOT SUPPORTED AT PRESENT */
-
-/**
- * struct link_event - link up/down event notification
- */
-
-struct link_event {
- u32 addr;
- int up;
- void (*fcn)(u32, char *, int);
- char name[TIPC_MAX_LINK_NAME];
-};
-
-#endif
-
static void link_handle_out_of_seq_msg(struct link *l_ptr,
struct sk_buff *buf);
static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf);
@@ -129,6 +112,9 @@ static void link_state_event(struct link *l_ptr, u32 event);
static void link_reset_statistics(struct link *l_ptr);
static void link_print(struct link *l_ptr, struct print_buf *buf,
const char *str);
+static void link_start(struct link *l_ptr);
+static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf);
+
/*
* Debugging code used by link routines only
@@ -239,13 +225,13 @@ int tipc_link_is_up(struct link *l_ptr)
{
if (!l_ptr)
return 0;
- return (link_working_working(l_ptr) || link_working_unknown(l_ptr));
+ return link_working_working(l_ptr) || link_working_unknown(l_ptr);
}
int tipc_link_is_active(struct link *l_ptr)
{
- return ((l_ptr->owner->active_links[0] == l_ptr) ||
- (l_ptr->owner->active_links[1] == l_ptr));
+ return (l_ptr->owner->active_links[0] == l_ptr) ||
+ (l_ptr->owner->active_links[1] == l_ptr);
}
/**
@@ -459,7 +445,7 @@ struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer,
k_init_timer(&l_ptr->timer, (Handler)link_timeout, (unsigned long)l_ptr);
list_add_tail(&l_ptr->link_list, &b_ptr->links);
- tipc_k_signal((Handler)tipc_link_start, (unsigned long)l_ptr);
+ tipc_k_signal((Handler)link_start, (unsigned long)l_ptr);
dbg("tipc_link_create(): tolerance = %u,cont intv = %u, abort_limit = %u\n",
l_ptr->tolerance, l_ptr->continuity_interval, l_ptr->abort_limit);
@@ -499,9 +485,9 @@ void tipc_link_delete(struct link *l_ptr)
kfree(l_ptr);
}
-void tipc_link_start(struct link *l_ptr)
+static void link_start(struct link *l_ptr)
{
- dbg("tipc_link_start %x\n", l_ptr);
+ dbg("link_start %x\n", l_ptr);
link_state_event(l_ptr, STARTING_EVT);
}
@@ -634,39 +620,9 @@ void tipc_link_stop(struct link *l_ptr)
l_ptr->proto_msg_queue = NULL;
}
-#if 0
-
/* LINK EVENT CODE IS NOT SUPPORTED AT PRESENT */
-
-static void link_recv_event(struct link_event *ev)
-{
- ev->fcn(ev->addr, ev->name, ev->up);
- kfree(ev);
-}
-
-static void link_send_event(void (*fcn)(u32 a, char *n, int up),
- struct link *l_ptr, int up)
-{
- struct link_event *ev;
-
- ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
- if (!ev) {
- warn("Link event allocation failure\n");
- return;
- }
- ev->addr = l_ptr->addr;
- ev->up = up;
- ev->fcn = fcn;
- memcpy(ev->name, l_ptr->name, TIPC_MAX_LINK_NAME);
- tipc_k_signal((Handler)link_recv_event, (unsigned long)ev);
-}
-
-#else
-
#define link_send_event(fcn, l_ptr, up) do { } while (0)
-#endif
-
void tipc_link_reset(struct link *l_ptr)
{
struct sk_buff *buf;
@@ -690,10 +646,7 @@ void tipc_link_reset(struct link *l_ptr)
tipc_node_link_down(l_ptr->owner, l_ptr);
tipc_bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr);
-#if 0
- tipc_printf(TIPC_CONS, "\nReset link <%s>\n", l_ptr->name);
- dbg_link_dump();
-#endif
+
if (was_active_link && tipc_node_has_active_links(l_ptr->owner) &&
l_ptr->owner->permit_changeover) {
l_ptr->reset_checkpoint = checkpoint;
@@ -1050,7 +1003,7 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf)
/* Fragmentation needed ? */
if (size > max_packet)
- return tipc_link_send_long_buf(l_ptr, buf);
+ return link_send_long_buf(l_ptr, buf);
/* Packet can be queued or sent: */
@@ -1086,7 +1039,7 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf)
/* Try creating a new bundle */
if (size <= max_packet * 2 / 3) {
- struct sk_buff *bundler = buf_acquire(max_packet);
+ struct sk_buff *bundler = tipc_buf_acquire(max_packet);
struct tipc_msg bundler_hdr;
if (bundler) {
@@ -1362,7 +1315,7 @@ again:
/* Prepare header of first fragment: */
- buf_chain = buf = buf_acquire(max_pkt);
+ buf_chain = buf = tipc_buf_acquire(max_pkt);
if (!buf)
return -ENOMEM;
buf->next = NULL;
@@ -1419,7 +1372,7 @@ error:
msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE);
msg_set_fragm_no(&fragm_hdr, ++fragm_no);
prev = buf;
- buf = buf_acquire(fragm_sz + INT_H_SIZE);
+ buf = tipc_buf_acquire(fragm_sz + INT_H_SIZE);
if (!buf)
goto error;
@@ -1802,6 +1755,15 @@ static int link_recv_buf_validate(struct sk_buff *buf)
return pskb_may_pull(buf, hdr_size);
}
+/**
+ * tipc_recv_msg - process TIPC messages arriving from off-node
+ * @head: pointer to message buffer chain
+ * @tb_ptr: pointer to bearer message arrived on
+ *
+ * Invoked with no locks held. Bearer pointer must point to a valid bearer
+ * structure (i.e. cannot be NULL), but bearer can be inactive.
+ */
+
void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
{
read_lock_bh(&tipc_net_lock);
@@ -1819,6 +1781,11 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
head = head->next;
+ /* Ensure bearer is still enabled */
+
+ if (unlikely(!b_ptr->active))
+ goto cont;
+
/* Ensure message is well-formed */
if (unlikely(!link_recv_buf_validate(buf)))
@@ -1855,13 +1822,22 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
goto cont;
}
- /* Locate unicast link endpoint that should handle message */
+ /* Locate neighboring node that sent message */
n_ptr = tipc_node_find(msg_prevnode(msg));
if (unlikely(!n_ptr))
goto cont;
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);
+ goto cont;
+ }
+
+ /* Locate unicast link endpoint that should handle message */
+
l_ptr = n_ptr->links[b_ptr->identity];
if (unlikely(!l_ptr)) {
tipc_node_unlock(n_ptr);
@@ -2172,7 +2148,7 @@ void tipc_link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg,
if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) {
if (!l_ptr->proto_msg_queue) {
l_ptr->proto_msg_queue =
- buf_acquire(sizeof(l_ptr->proto_msg));
+ tipc_buf_acquire(sizeof(l_ptr->proto_msg));
}
buf = l_ptr->proto_msg_queue;
if (!buf)
@@ -2186,7 +2162,7 @@ void tipc_link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg,
msg_dbg(msg, ">>");
- buf = buf_acquire(msg_size);
+ buf = tipc_buf_acquire(msg_size);
if (!buf)
return;
@@ -2345,10 +2321,10 @@ exit:
* tipc_link_tunnel(): Send one message via a link belonging to
* another bearer. Owner node is locked.
*/
-void tipc_link_tunnel(struct link *l_ptr,
- struct tipc_msg *tunnel_hdr,
- struct tipc_msg *msg,
- u32 selector)
+static void tipc_link_tunnel(struct link *l_ptr,
+ struct tipc_msg *tunnel_hdr,
+ struct tipc_msg *msg,
+ u32 selector)
{
struct link *tunnel;
struct sk_buff *buf;
@@ -2361,7 +2337,7 @@ void tipc_link_tunnel(struct link *l_ptr,
return;
}
msg_set_size(tunnel_hdr, length + INT_H_SIZE);
- buf = buf_acquire(length + INT_H_SIZE);
+ buf = tipc_buf_acquire(length + INT_H_SIZE);
if (!buf) {
warn("Link changeover error, "
"unable to send tunnel msg\n");
@@ -2407,7 +2383,7 @@ void tipc_link_changeover(struct link *l_ptr)
if (!l_ptr->first_out) {
struct sk_buff *buf;
- buf = buf_acquire(INT_H_SIZE);
+ buf = tipc_buf_acquire(INT_H_SIZE);
if (buf) {
skb_copy_to_linear_data(buf, &tunnel_hdr, INT_H_SIZE);
msg_set_size(&tunnel_hdr, INT_H_SIZE);
@@ -2468,7 +2444,7 @@ void tipc_link_send_duplicate(struct link *l_ptr, struct link *tunnel)
msg_set_ack(msg, mod(l_ptr->next_in_no - 1)); /* Update */
msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
msg_set_size(&tunnel_hdr, length + INT_H_SIZE);
- outbuf = buf_acquire(length + INT_H_SIZE);
+ outbuf = tipc_buf_acquire(length + INT_H_SIZE);
if (outbuf == NULL) {
warn("Link changeover error, "
"unable to send duplicate msg\n");
@@ -2504,7 +2480,7 @@ static struct sk_buff *buf_extract(struct sk_buff *skb, u32 from_pos)
u32 size = msg_size(msg);
struct sk_buff *eb;
- eb = buf_acquire(size);
+ eb = tipc_buf_acquire(size);
if (eb)
skb_copy_to_linear_data(eb, msg, size);
return eb;
@@ -2632,11 +2608,11 @@ void tipc_link_recv_bundle(struct sk_buff *buf)
/*
- * tipc_link_send_long_buf: Entry for buffers needing fragmentation.
+ * link_send_long_buf: Entry for buffers needing fragmentation.
* The buffer is complete, inclusive total message length.
* Returns user data length.
*/
-int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
+static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
{
struct tipc_msg *inmsg = buf_msg(buf);
struct tipc_msg fragm_hdr;
@@ -2675,7 +2651,7 @@ int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
fragm_sz = rest;
msg_set_type(&fragm_hdr, LAST_FRAGMENT);
}
- fragm = buf_acquire(fragm_sz + INT_H_SIZE);
+ fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE);
if (fragm == NULL) {
warn("Link unable to fragment message\n");
dsz = -ENOMEM;
@@ -2780,7 +2756,7 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb,
buf_discard(fbuf);
return 0;
}
- pbuf = buf_acquire(msg_size(imsg));
+ pbuf = tipc_buf_acquire(msg_size(imsg));
if (pbuf != NULL) {
pbuf->next = *pending;
*pending = pbuf;
@@ -3174,44 +3150,6 @@ struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_s
return buf;
}
-#if 0
-int link_control(const char *name, u32 op, u32 val)
-{
- int res = -EINVAL;
- struct link *l_ptr;
- u32 bearer_id;
- struct tipc_node * node;
- u32 a;
-
- a = link_name2addr(name, &bearer_id);
- read_lock_bh(&tipc_net_lock);
- node = tipc_node_find(a);
- if (node) {
- tipc_node_lock(node);
- l_ptr = node->links[bearer_id];
- if (l_ptr) {
- if (op == TIPC_REMOVE_LINK) {
- struct bearer *b_ptr = l_ptr->b_ptr;
- spin_lock_bh(&b_ptr->publ.lock);
- tipc_link_delete(l_ptr);
- spin_unlock_bh(&b_ptr->publ.lock);
- }
- if (op == TIPC_CMD_BLOCK_LINK) {
- tipc_link_reset(l_ptr);
- l_ptr->blocked = 1;
- }
- if (op == TIPC_CMD_UNBLOCK_LINK) {
- l_ptr->blocked = 0;
- }
- res = 0;
- }
- tipc_node_unlock(node);
- }
- read_unlock_bh(&tipc_net_lock);
- return res;
-}
-#endif
-
/**
* tipc_link_get_max_pkt - get maximum packet size to use when sending to destination
* @dest: network address of destination node
@@ -3242,28 +3180,6 @@ u32 tipc_link_get_max_pkt(u32 dest, u32 selector)
return res;
}
-#if 0
-static void link_dump_rec_queue(struct link *l_ptr)
-{
- struct sk_buff *crs;
-
- if (!l_ptr->oldest_deferred_in) {
- info("Reception queue empty\n");
- return;
- }
- info("Contents of Reception queue:\n");
- crs = l_ptr->oldest_deferred_in;
- while (crs) {
- if (crs->data == (void *)0x0000a3a3) {
- info("buffer %x invalid\n", crs);
- return;
- }
- msg_dbg(buf_msg(crs), "In rec queue:\n");
- crs = crs->next;
- }
-}
-#endif
-
static void link_dump_send_queue(struct link *l_ptr)
{
if (l_ptr->next_out) {
diff --git a/net/tipc/link.h b/net/tipc/link.h
index 2e5385c47d30..f98bc613de67 100644
--- a/net/tipc/link.h
+++ b/net/tipc/link.h
@@ -210,10 +210,6 @@ struct link {
u32 msg_length_counts;
u32 msg_lengths_total;
u32 msg_length_profile[7];
-#if 0
- u32 sent_tunneled;
- u32 recv_tunneled;
-#endif
} stats;
struct print_buf print_buf;
@@ -229,7 +225,6 @@ void tipc_link_send_duplicate(struct link *l_ptr, struct link *dest);
void tipc_link_reset_fragments(struct link *l_ptr);
int tipc_link_is_up(struct link *l_ptr);
int tipc_link_is_active(struct link *l_ptr);
-void tipc_link_start(struct link *l_ptr);
u32 tipc_link_push_packet(struct link *l_ptr);
void tipc_link_stop(struct link *l_ptr);
struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space, u16 cmd);
@@ -243,9 +238,6 @@ int tipc_link_send_sections_fast(struct port* sender,
struct iovec const *msg_sect,
const u32 num_sect,
u32 destnode);
-int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf);
-void tipc_link_tunnel(struct link *l_ptr, struct tipc_msg *tnl_hdr,
- struct tipc_msg *msg, u32 selector);
void tipc_link_recv_bundle(struct sk_buff *buf);
int tipc_link_recv_fragment(struct sk_buff **pending,
struct sk_buff **fb,
@@ -279,12 +271,12 @@ static inline int between(u32 lower, u32 upper, u32 n)
static inline int less_eq(u32 left, u32 right)
{
- return (mod(right - left) < 32768u);
+ return mod(right - left) < 32768u;
}
static inline int less(u32 left, u32 right)
{
- return (less_eq(left, right) && (mod(right) != mod(left)));
+ return less_eq(left, right) && (mod(right) != mod(left));
}
static inline u32 lesser(u32 left, u32 right)
@@ -299,32 +291,32 @@ static inline u32 lesser(u32 left, u32 right)
static inline int link_working_working(struct link *l_ptr)
{
- return (l_ptr->state == WORKING_WORKING);
+ return l_ptr->state == WORKING_WORKING;
}
static inline int link_working_unknown(struct link *l_ptr)
{
- return (l_ptr->state == WORKING_UNKNOWN);
+ return l_ptr->state == WORKING_UNKNOWN;
}
static inline int link_reset_unknown(struct link *l_ptr)
{
- return (l_ptr->state == RESET_UNKNOWN);
+ return l_ptr->state == RESET_UNKNOWN;
}
static inline int link_reset_reset(struct link *l_ptr)
{
- return (l_ptr->state == RESET_RESET);
+ return l_ptr->state == RESET_RESET;
}
static inline int link_blocked(struct link *l_ptr)
{
- return (l_ptr->exp_msg_count || l_ptr->blocked);
+ return l_ptr->exp_msg_count || l_ptr->blocked;
}
static inline int link_congested(struct link *l_ptr)
{
- return (l_ptr->out_queue_size >= l_ptr->queue_limit[0]);
+ return l_ptr->out_queue_size >= l_ptr->queue_limit[0];
}
#endif
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index 381063817b41..ecb532fb0351 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -112,7 +112,7 @@ int tipc_msg_build(struct tipc_msg *hdr,
return dsz;
}
- *buf = buf_acquire(sz);
+ *buf = tipc_buf_acquire(sz);
if (!(*buf))
return -ENOMEM;
skb_copy_to_linear_data(*buf, hdr, hsz);
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index 995d2da35b01..031aad18efce 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -104,7 +104,7 @@ static inline u32 msg_user(struct tipc_msg *m)
static inline u32 msg_isdata(struct tipc_msg *m)
{
- return (msg_user(m) <= TIPC_CRITICAL_IMPORTANCE);
+ return msg_user(m) <= TIPC_CRITICAL_IMPORTANCE;
}
static inline void msg_set_user(struct tipc_msg *m, u32 n)
@@ -289,7 +289,7 @@ static inline void msg_set_destnode(struct tipc_msg *m, u32 a)
static inline int msg_is_dest(struct tipc_msg *m, u32 d)
{
- return(msg_short(m) || (msg_destnode(m) == d));
+ return msg_short(m) || (msg_destnode(m) == d);
}
static inline u32 msg_routed(struct tipc_msg *m)
@@ -632,7 +632,7 @@ static inline void msg_set_bcast_tag(struct tipc_msg *m, u32 n)
static inline u32 msg_max_pkt(struct tipc_msg *m)
{
- return (msg_bits(m, 9, 16, 0xffff) * 4);
+ return msg_bits(m, 9, 16, 0xffff) * 4;
}
static inline void msg_set_max_pkt(struct tipc_msg *m, u32 n)
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index 6ac3c543250b..7b907171f879 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -98,7 +98,7 @@ static void publ_to_item(struct distr_item *i, struct publication *p)
static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest)
{
- struct sk_buff *buf = buf_acquire(LONG_H_SIZE + size);
+ struct sk_buff *buf = tipc_buf_acquire(LONG_H_SIZE + size);
struct tipc_msg *msg;
if (buf != NULL) {
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index 8ba79620db3f..3a8de4334da1 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -116,7 +116,7 @@ DEFINE_RWLOCK(tipc_nametbl_lock);
static int hash(int x)
{
- return(x & (tipc_nametbl_size - 1));
+ return x & (tipc_nametbl_size - 1);
}
/**
@@ -613,8 +613,7 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
}
/*
- * tipc_nametbl_translate(): Translate tipc_name -> tipc_portid.
- * Very time-critical.
+ * tipc_nametbl_translate - translate name to port id
*
* Note: on entry 'destnode' is the search domain used during translation;
* on exit it passes back the node address of the matching port (if any)
@@ -685,7 +684,6 @@ found:
}
spin_unlock_bh(&seq->lock);
not_found:
- *destnode = 0;
read_unlock_bh(&tipc_nametbl_lock);
return 0;
}
@@ -877,7 +875,7 @@ static void subseq_list(struct sub_seq *sseq, struct print_buf *buf, u32 depth,
u32 index)
{
char portIdStr[27];
- char *scopeStr;
+ const char *scope_str[] = {"", " zone", " cluster", " node"};
struct publication *publ = sseq->zone_list;
tipc_printf(buf, "%-10u %-10u ", sseq->lower, sseq->upper);
@@ -893,15 +891,8 @@ static void subseq_list(struct sub_seq *sseq, struct print_buf *buf, u32 depth,
tipc_node(publ->node), publ->ref);
tipc_printf(buf, "%-26s ", portIdStr);
if (depth > 3) {
- if (publ->node != tipc_own_addr)
- scopeStr = "";
- else if (publ->scope == TIPC_NODE_SCOPE)
- scopeStr = "node";
- else if (publ->scope == TIPC_CLUSTER_SCOPE)
- scopeStr = "cluster";
- else
- scopeStr = "zone";
- tipc_printf(buf, "%-10u %s", publ->key, scopeStr);
+ tipc_printf(buf, "%-10u %s", publ->key,
+ scope_str[publ->scope]);
}
publ = publ->zone_list_next;
@@ -951,24 +942,19 @@ static void nameseq_list(struct name_seq *seq, struct print_buf *buf, u32 depth,
static void nametbl_header(struct print_buf *buf, u32 depth)
{
- tipc_printf(buf, "Type ");
-
- if (depth > 1)
- tipc_printf(buf, "Lower Upper ");
- if (depth > 2)
- tipc_printf(buf, "Port Identity ");
- if (depth > 3)
- tipc_printf(buf, "Publication");
-
- tipc_printf(buf, "\n-----------");
-
- if (depth > 1)
- tipc_printf(buf, "--------------------- ");
- if (depth > 2)
- tipc_printf(buf, "-------------------------- ");
- if (depth > 3)
- tipc_printf(buf, "------------------");
-
+ const char *header[] = {
+ "Type ",
+ "Lower Upper ",
+ "Port Identity ",
+ "Publication Scope"
+ };
+
+ int i;
+
+ if (depth > 4)
+ depth = 4;
+ for (i = 0; i < depth; i++)
+ tipc_printf(buf, header[i]);
tipc_printf(buf, "\n");
}
@@ -1023,16 +1009,6 @@ static void nametbl_list(struct print_buf *buf, u32 depth_info,
}
}
-#if 0
-void tipc_nametbl_print(struct print_buf *buf, const char *str)
-{
- tipc_printf(buf, str);
- read_lock_bh(&tipc_nametbl_lock);
- nametbl_list(buf, 0, 0, 0, 0);
- read_unlock_bh(&tipc_nametbl_lock);
-}
-#endif
-
#define MAX_NAME_TBL_QUERY 32768
struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space)
@@ -1065,13 +1041,6 @@ struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space)
return buf;
}
-#if 0
-void tipc_nametbl_dump(void)
-{
- nametbl_list(TIPC_CONS, 0, 0, 0, 0);
-}
-#endif
-
int tipc_nametbl_init(void)
{
table.types = kcalloc(tipc_nametbl_size, sizeof(struct hlist_head),
diff --git a/net/tipc/net.c b/net/tipc/net.c
index f61b7694138b..1a621cfd6604 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -129,15 +129,6 @@ u32 tipc_net_select_router(u32 addr, u32 ref)
return tipc_zone_select_router(tipc_net.zones[tipc_zone(addr)], addr, ref);
}
-#if 0
-u32 tipc_net_next_node(u32 a)
-{
- if (tipc_net.zones[tipc_zone(a)])
- return tipc_zone_next_node(a);
- return 0;
-}
-#endif
-
void tipc_net_remove_as_router(u32 router)
{
u32 z_num;
@@ -248,6 +239,7 @@ void tipc_net_route_msg(struct sk_buff *buf)
/* Handle message for another node */
msg_dbg(msg, "NET>SEND>: ");
+ skb_trim(buf, msg_size(msg));
tipc_link_send(buf, dnode, msg_link_selector(msg));
}
diff --git a/net/tipc/node.c b/net/tipc/node.c
index b634942caba5..b4d87eb2dc5d 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -50,7 +50,8 @@ void node_print(struct print_buf *buf, struct tipc_node *n_ptr, char *str);
static void node_lost_contact(struct tipc_node *n_ptr);
static void node_established_contact(struct tipc_node *n_ptr);
-struct tipc_node *tipc_nodes = NULL; /* sorted list of nodes within cluster */
+/* sorted list of nodes within cluster */
+static struct tipc_node *tipc_nodes = NULL;
static DEFINE_SPINLOCK(node_create_lock);
@@ -125,16 +126,6 @@ void tipc_node_delete(struct tipc_node *n_ptr)
if (!n_ptr)
return;
-#if 0
- /* Not needed because links are already deleted via tipc_bearer_stop() */
-
- u32 l_num;
-
- for (l_num = 0; l_num < MAX_BEARERS; l_num++) {
- link_delete(n_ptr->links[l_num]);
- }
-#endif
-
dbg("node %x deleted\n", n_ptr->addr);
kfree(n_ptr);
}
@@ -237,23 +228,22 @@ void tipc_node_link_down(struct tipc_node *n_ptr, struct link *l_ptr)
int tipc_node_has_active_links(struct tipc_node *n_ptr)
{
- return (n_ptr &&
- ((n_ptr->active_links[0]) || (n_ptr->active_links[1])));
+ return n_ptr->active_links[0] != NULL;
}
int tipc_node_has_redundant_links(struct tipc_node *n_ptr)
{
- return (n_ptr->working_links > 1);
+ return n_ptr->working_links > 1;
}
static int tipc_node_has_active_routes(struct tipc_node *n_ptr)
{
- return (n_ptr && (n_ptr->last_router >= 0));
+ return n_ptr && (n_ptr->last_router >= 0);
}
int tipc_node_is_up(struct tipc_node *n_ptr)
{
- return (tipc_node_has_active_links(n_ptr) || tipc_node_has_active_routes(n_ptr));
+ return tipc_node_has_active_links(n_ptr) || tipc_node_has_active_routes(n_ptr);
}
struct tipc_node *tipc_node_attach_link(struct link *l_ptr)
@@ -384,6 +374,20 @@ static void node_established_contact(struct tipc_node *n_ptr)
tipc_highest_allowed_slave);
}
+static void node_cleanup_finished(unsigned long node_addr)
+{
+ struct tipc_node *n_ptr;
+
+ read_lock_bh(&tipc_net_lock);
+ n_ptr = tipc_node_find(node_addr);
+ if (n_ptr) {
+ tipc_node_lock(n_ptr);
+ n_ptr->cleanup_required = 0;
+ tipc_node_unlock(n_ptr);
+ }
+ read_unlock_bh(&tipc_net_lock);
+}
+
static void node_lost_contact(struct tipc_node *n_ptr)
{
struct cluster *c_ptr;
@@ -458,6 +462,11 @@ static void node_lost_contact(struct tipc_node *n_ptr)
tipc_k_signal((Handler)ns->handle_node_down,
(unsigned long)ns->usr_handle);
}
+
+ /* Prevent re-contact with node until all cleanup is done */
+
+ n_ptr->cleanup_required = 1;
+ tipc_k_signal((Handler)node_cleanup_finished, n_ptr->addr);
}
/**
@@ -579,38 +588,6 @@ void tipc_node_remove_router(struct tipc_node *n_ptr, u32 router)
node_lost_contact(n_ptr);
}
-#if 0
-void node_print(struct print_buf *buf, struct tipc_node *n_ptr, char *str)
-{
- u32 i;
-
- tipc_printf(buf, "\n\n%s", str);
- for (i = 0; i < MAX_BEARERS; i++) {
- if (!n_ptr->links[i])
- continue;
- tipc_printf(buf, "Links[%u]: %x, ", i, n_ptr->links[i]);
- }
- tipc_printf(buf, "Active links: [%x,%x]\n",
- n_ptr->active_links[0], n_ptr->active_links[1]);
-}
-#endif
-
-u32 tipc_available_nodes(const u32 domain)
-{
- struct tipc_node *n_ptr;
- u32 cnt = 0;
-
- read_lock_bh(&tipc_net_lock);
- for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
- if (!tipc_in_scope(domain, n_ptr->addr))
- continue;
- if (tipc_node_is_up(n_ptr))
- cnt++;
- }
- read_unlock_bh(&tipc_net_lock);
- return cnt;
-}
-
struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
{
u32 domain;
diff --git a/net/tipc/node.h b/net/tipc/node.h
index 6f990da5d143..fff331b2d26c 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -52,6 +52,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
* @link_cnt: number of links to node
* @permit_changeover: non-zero if node has redundant links to this system
* @routers: bitmap (used for multicluster communication)
@@ -78,6 +79,7 @@ struct tipc_node {
struct link *links[MAX_BEARERS];
int link_cnt;
int working_links;
+ int cleanup_required;
int permit_changeover;
u32 routers[512/32];
int last_router;
@@ -94,7 +96,6 @@ struct tipc_node {
} bclink;
};
-extern struct tipc_node *tipc_nodes;
extern u32 tipc_own_tag;
struct tipc_node *tipc_node_create(u32 addr);
diff --git a/net/tipc/port.c b/net/tipc/port.c
index 0737680e9266..82092eaa1536 100644
--- a/net/tipc/port.c
+++ b/net/tipc/port.c
@@ -293,34 +293,6 @@ int tipc_deleteport(u32 ref)
return 0;
}
-/**
- * tipc_get_port() - return port associated with 'ref'
- *
- * Note: Port is not locked.
- */
-
-struct tipc_port *tipc_get_port(const u32 ref)
-{
- return (struct tipc_port *)tipc_ref_deref(ref);
-}
-
-/**
- * tipc_get_handle - return user handle associated to port 'ref'
- */
-
-void *tipc_get_handle(const u32 ref)
-{
- struct port *p_ptr;
- void * handle;
-
- p_ptr = tipc_port_lock(ref);
- if (!p_ptr)
- return NULL;
- handle = p_ptr->publ.usr_handle;
- tipc_port_unlock(p_ptr);
- return handle;
-}
-
static int port_unreliable(struct port *p_ptr)
{
return msg_src_droppable(&p_ptr->publ.phdr);
@@ -392,7 +364,7 @@ static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode,
struct sk_buff *buf;
struct tipc_msg *msg;
- buf = buf_acquire(LONG_H_SIZE);
+ buf = tipc_buf_acquire(LONG_H_SIZE);
if (buf) {
msg = buf_msg(buf);
tipc_msg_init(msg, usr, type, LONG_H_SIZE, destnode);
@@ -433,7 +405,7 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err)
hdr_sz = MCAST_H_SIZE;
else
hdr_sz = LONG_H_SIZE;
- rbuf = buf_acquire(data_sz + hdr_sz);
+ rbuf = tipc_buf_acquire(data_sz + hdr_sz);
if (rbuf == NULL) {
buf_discard(buf);
return data_sz;
@@ -588,19 +560,10 @@ void tipc_port_recv_proto_msg(struct sk_buff *buf)
if (!p_ptr) {
err = TIPC_ERR_NO_PORT;
} else if (p_ptr->publ.connected) {
- if (port_peernode(p_ptr) != msg_orignode(msg))
+ if ((port_peernode(p_ptr) != msg_orignode(msg)) ||
+ (port_peerport(p_ptr) != msg_origport(msg))) {
err = TIPC_ERR_NO_PORT;
- if (port_peerport(p_ptr) != msg_origport(msg))
- err = TIPC_ERR_NO_PORT;
- if (!err && msg_routed(msg)) {
- u32 seqno = msg_transp_seqno(msg);
- u32 myno = ++p_ptr->last_in_seqno;
- if (seqno != myno) {
- err = TIPC_ERR_NO_PORT;
- abort_buf = port_build_self_abort_msg(p_ptr, err);
- }
- }
- if (msg_type(msg) == CONN_ACK) {
+ } else if (msg_type(msg) == CONN_ACK) {
int wakeup = tipc_port_congested(p_ptr) &&
p_ptr->publ.congested &&
p_ptr->wakeup;
@@ -719,50 +682,6 @@ struct sk_buff *tipc_port_get_ports(void)
return buf;
}
-#if 0
-
-#define MAX_PORT_STATS 2000
-
-struct sk_buff *port_show_stats(const void *req_tlv_area, int req_tlv_space)
-{
- u32 ref;
- struct port *p_ptr;
- struct sk_buff *buf;
- struct tlv_desc *rep_tlv;
- struct print_buf pb;
- int str_len;
-
- if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_PORT_REF))
- return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
-
- ref = *(u32 *)TLV_DATA(req_tlv_area);
- ref = ntohl(ref);
-
- p_ptr = tipc_port_lock(ref);
- if (!p_ptr)
- return cfg_reply_error_string("port not found");
-
- buf = tipc_cfg_reply_alloc(TLV_SPACE(MAX_PORT_STATS));
- if (!buf) {
- tipc_port_unlock(p_ptr);
- return NULL;
- }
- rep_tlv = (struct tlv_desc *)buf->data;
-
- tipc_printbuf_init(&pb, TLV_DATA(rep_tlv), MAX_PORT_STATS);
- port_print(p_ptr, &pb, 1);
- /* NEED TO FILL IN ADDITIONAL PORT STATISTICS HERE */
- tipc_port_unlock(p_ptr);
- str_len = tipc_printbuf_validate(&pb);
-
- skb_put(buf, TLV_SPACE(str_len));
- TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
-
- return buf;
-}
-
-#endif
-
void tipc_port_reinit(void)
{
struct port *p_ptr;
@@ -1295,50 +1214,13 @@ int tipc_shutdown(u32 ref)
return tipc_disconnect(ref);
}
-int tipc_isconnected(u32 ref, int *isconnected)
-{
- struct port *p_ptr;
-
- p_ptr = tipc_port_lock(ref);
- if (!p_ptr)
- return -EINVAL;
- *isconnected = p_ptr->publ.connected;
- tipc_port_unlock(p_ptr);
- return 0;
-}
-
-int tipc_peer(u32 ref, struct tipc_portid *peer)
-{
- struct port *p_ptr;
- int res;
-
- p_ptr = tipc_port_lock(ref);
- if (!p_ptr)
- return -EINVAL;
- if (p_ptr->publ.connected) {
- peer->ref = port_peerport(p_ptr);
- peer->node = port_peernode(p_ptr);
- res = 0;
- } else
- res = -ENOTCONN;
- tipc_port_unlock(p_ptr);
- return res;
-}
-
-int tipc_ref_valid(u32 ref)
-{
- /* Works irrespective of type */
- return !!tipc_ref_deref(ref);
-}
-
-
/*
* tipc_port_recv_sections(): Concatenate and deliver sectioned
* message for this node.
*/
-int tipc_port_recv_sections(struct port *sender, unsigned int num_sect,
- struct iovec const *msg_sect)
+static int tipc_port_recv_sections(struct port *sender, unsigned int num_sect,
+ struct iovec const *msg_sect)
{
struct sk_buff *buf;
int res;
@@ -1389,65 +1271,16 @@ int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect)
}
/**
- * tipc_send_buf - send message buffer on connection
- */
-
-int tipc_send_buf(u32 ref, struct sk_buff *buf, unsigned int dsz)
-{
- struct port *p_ptr;
- struct tipc_msg *msg;
- u32 destnode;
- u32 hsz;
- u32 sz;
- u32 res;
-
- p_ptr = tipc_port_deref(ref);
- if (!p_ptr || !p_ptr->publ.connected)
- return -EINVAL;
-
- msg = &p_ptr->publ.phdr;
- hsz = msg_hdr_sz(msg);
- sz = hsz + dsz;
- msg_set_size(msg, sz);
- if (skb_cow(buf, hsz))
- return -ENOMEM;
-
- skb_push(buf, hsz);
- skb_copy_to_linear_data(buf, msg, hsz);
- destnode = msg_destnode(msg);
- p_ptr->publ.congested = 1;
- if (!tipc_port_congested(p_ptr)) {
- if (likely(destnode != tipc_own_addr))
- res = tipc_send_buf_fast(buf, destnode);
- else {
- tipc_port_recv_msg(buf);
- res = sz;
- }
- if (likely(res != -ELINKCONG)) {
- port_incr_out_seqno(p_ptr);
- p_ptr->sent++;
- p_ptr->publ.congested = 0;
- return res;
- }
- }
- if (port_unreliable(p_ptr)) {
- p_ptr->publ.congested = 0;
- return dsz;
- }
- return -ELINKCONG;
-}
-
-/**
* tipc_forward2name - forward message sections to port name
*/
-int tipc_forward2name(u32 ref,
- struct tipc_name const *name,
- u32 domain,
- u32 num_sect,
- struct iovec const *msg_sect,
- struct tipc_portid const *orig,
- unsigned int importance)
+static int tipc_forward2name(u32 ref,
+ struct tipc_name const *name,
+ u32 domain,
+ u32 num_sect,
+ struct iovec const *msg_sect,
+ struct tipc_portid const *orig,
+ unsigned int importance)
{
struct port *p_ptr;
struct tipc_msg *msg;
@@ -1473,7 +1306,7 @@ int tipc_forward2name(u32 ref,
msg_set_destnode(msg, destnode);
msg_set_destport(msg, destport);
- if (likely(destport || destnode)) {
+ if (likely(destport)) {
p_ptr->sent++;
if (likely(destnode == tipc_own_addr))
return tipc_port_recv_sections(p_ptr, num_sect, msg_sect);
@@ -1510,89 +1343,15 @@ int tipc_send2name(u32 ref,
}
/**
- * tipc_forward_buf2name - forward message buffer to port name
- */
-
-int tipc_forward_buf2name(u32 ref,
- struct tipc_name const *name,
- u32 domain,
- struct sk_buff *buf,
- unsigned int dsz,
- struct tipc_portid const *orig,
- unsigned int importance)
-{
- struct port *p_ptr;
- struct tipc_msg *msg;
- u32 destnode = domain;
- u32 destport;
- int res;
-
- p_ptr = (struct port *)tipc_ref_deref(ref);
- if (!p_ptr || p_ptr->publ.connected)
- return -EINVAL;
-
- msg = &p_ptr->publ.phdr;
- if (importance <= TIPC_CRITICAL_IMPORTANCE)
- msg_set_importance(msg, importance);
- msg_set_type(msg, TIPC_NAMED_MSG);
- msg_set_orignode(msg, orig->node);
- msg_set_origport(msg, orig->ref);
- msg_set_nametype(msg, name->type);
- msg_set_nameinst(msg, name->instance);
- msg_set_lookup_scope(msg, tipc_addr_scope(domain));
- msg_set_hdr_sz(msg, LONG_H_SIZE);
- msg_set_size(msg, LONG_H_SIZE + dsz);
- destport = tipc_nametbl_translate(name->type, name->instance, &destnode);
- msg_set_destnode(msg, destnode);
- msg_set_destport(msg, destport);
- msg_dbg(msg, "forw2name ==> ");
- if (skb_cow(buf, LONG_H_SIZE))
- return -ENOMEM;
- skb_push(buf, LONG_H_SIZE);
- skb_copy_to_linear_data(buf, msg, LONG_H_SIZE);
- msg_dbg(buf_msg(buf),"PREP:");
- if (likely(destport || destnode)) {
- p_ptr->sent++;
- if (destnode == tipc_own_addr)
- return tipc_port_recv_msg(buf);
- res = tipc_send_buf_fast(buf, destnode);
- if (likely(res != -ELINKCONG))
- return res;
- if (port_unreliable(p_ptr))
- return dsz;
- return -ELINKCONG;
- }
- return tipc_reject_msg(buf, TIPC_ERR_NO_NAME);
-}
-
-/**
- * tipc_send_buf2name - send message buffer to port name
- */
-
-int tipc_send_buf2name(u32 ref,
- struct tipc_name const *dest,
- u32 domain,
- struct sk_buff *buf,
- unsigned int dsz)
-{
- struct tipc_portid orig;
-
- orig.ref = ref;
- orig.node = tipc_own_addr;
- return tipc_forward_buf2name(ref, dest, domain, buf, dsz, &orig,
- TIPC_PORT_IMPORTANCE);
-}
-
-/**
* tipc_forward2port - forward message sections to port identity
*/
-int tipc_forward2port(u32 ref,
- struct tipc_portid const *dest,
- unsigned int num_sect,
- struct iovec const *msg_sect,
- struct tipc_portid const *orig,
- unsigned int importance)
+static int tipc_forward2port(u32 ref,
+ struct tipc_portid const *dest,
+ unsigned int num_sect,
+ struct iovec const *msg_sect,
+ struct tipc_portid const *orig,
+ unsigned int importance)
{
struct port *p_ptr;
struct tipc_msg *msg;
@@ -1644,12 +1403,12 @@ int tipc_send2port(u32 ref,
/**
* tipc_forward_buf2port - forward message buffer to port identity
*/
-int tipc_forward_buf2port(u32 ref,
- struct tipc_portid const *dest,
- struct sk_buff *buf,
- unsigned int dsz,
- struct tipc_portid const *orig,
- unsigned int importance)
+static int tipc_forward_buf2port(u32 ref,
+ struct tipc_portid const *dest,
+ struct sk_buff *buf,
+ unsigned int dsz,
+ struct tipc_portid const *orig,
+ unsigned int importance)
{
struct port *p_ptr;
struct tipc_msg *msg;
diff --git a/net/tipc/port.h b/net/tipc/port.h
index 8d1652aab298..73bbf442b346 100644
--- a/net/tipc/port.h
+++ b/net/tipc/port.h
@@ -109,8 +109,6 @@ struct port {
extern spinlock_t tipc_port_list_lock;
struct port_list;
-int tipc_port_recv_sections(struct port *p_ptr, u32 num_sect,
- struct iovec const *msg_sect);
int tipc_port_reject_sections(struct port *p_ptr, struct tipc_msg *hdr,
struct iovec const *msg_sect, u32 num_sect,
int err);
@@ -157,7 +155,7 @@ static inline u32 tipc_peer_node(struct port *p_ptr)
static inline int tipc_port_congested(struct port *p_ptr)
{
- return((p_ptr->sent - p_ptr->acked) >= (TIPC_FLOW_CONTROL_WIN * 2));
+ return (p_ptr->sent - p_ptr->acked) >= (TIPC_FLOW_CONTROL_WIN * 2);
}
/**
diff --git a/net/tipc/ref.c b/net/tipc/ref.c
index 8dea66500cf5..ab8ad32d8c20 100644
--- a/net/tipc/ref.c
+++ b/net/tipc/ref.c
@@ -282,23 +282,6 @@ void *tipc_ref_lock(u32 ref)
return NULL;
}
-/**
- * tipc_ref_unlock - unlock referenced object
- */
-
-void tipc_ref_unlock(u32 ref)
-{
- if (likely(tipc_ref_table.entries)) {
- struct reference *entry;
-
- entry = &tipc_ref_table.entries[ref &
- tipc_ref_table.index_mask];
- if (likely((entry->ref == ref) && (entry->object)))
- spin_unlock_bh(&entry->lock);
- else
- err("Attempt to unlock non-existent reference\n");
- }
-}
/**
* tipc_ref_deref - return pointer referenced object (without locking it)
diff --git a/net/tipc/ref.h b/net/tipc/ref.h
index 7e3798ea93b9..5bc8e7ab84de 100644
--- a/net/tipc/ref.h
+++ b/net/tipc/ref.h
@@ -44,7 +44,6 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock);
void tipc_ref_discard(u32 ref);
void *tipc_ref_lock(u32 ref);
-void tipc_ref_unlock(u32 ref);
void *tipc_ref_deref(u32 ref);
#endif
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 66e889ba48fd..33217fc3d697 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -64,6 +64,7 @@ struct tipc_sock {
struct sock sk;
struct tipc_port *p;
struct tipc_portid peer_name;
+ long conn_timeout;
};
#define tipc_sk(sk) ((struct tipc_sock *)(sk))
@@ -240,9 +241,9 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol,
sock->state = state;
sock_init_data(sock, sk);
- sk->sk_rcvtimeo = msecs_to_jiffies(CONN_TIMEOUT_DEFAULT);
sk->sk_backlog_rcv = backlog_rcv;
tipc_sk(sk)->p = tp_ptr;
+ tipc_sk(sk)->conn_timeout = msecs_to_jiffies(CONN_TIMEOUT_DEFAULT);
spin_unlock_bh(tp_ptr->lock);
@@ -429,36 +430,55 @@ static int get_name(struct socket *sock, struct sockaddr *uaddr,
* to handle any preventable race conditions, so TIPC will do the same ...
*
* TIPC sets the returned events as follows:
- * a) POLLRDNORM and POLLIN are set if the socket's receive queue is non-empty
- * or if a connection-oriented socket is does not have an active connection
- * (i.e. a read operation will not block).
- * b) POLLOUT is set except when a socket's connection has been terminated
- * (i.e. a write operation will not block).
- * c) POLLHUP is set when a socket's connection has been terminated.
- *
- * IMPORTANT: The fact that a read or write operation will not block does NOT
- * imply that the operation will succeed!
+ *
+ * socket state flags set
+ * ------------ ---------
+ * unconnected no read flags
+ * no write flags
+ *
+ * connecting POLLIN/POLLRDNORM if ACK/NACK in rx queue
+ * no write flags
+ *
+ * connected POLLIN/POLLRDNORM if data in rx queue
+ * POLLOUT if port is not congested
+ *
+ * disconnecting POLLIN/POLLRDNORM/POLLHUP
+ * no write flags
+ *
+ * listening POLLIN if SYN in rx queue
+ * no write flags
+ *
+ * ready POLLIN/POLLRDNORM if data in rx queue
+ * [connectionless] POLLOUT (since port cannot be congested)
+ *
+ * IMPORTANT: The fact that a read or write operation is indicated does NOT
+ * imply that the operation will succeed, merely that it should be performed
+ * and will not block.
*/
static unsigned int poll(struct file *file, struct socket *sock,
poll_table *wait)
{
struct sock *sk = sock->sk;
- u32 mask;
+ u32 mask = 0;
poll_wait(file, sk_sleep(sk), wait);
- if (!skb_queue_empty(&sk->sk_receive_queue) ||
- (sock->state == SS_UNCONNECTED) ||
- (sock->state == SS_DISCONNECTING))
- mask = (POLLRDNORM | POLLIN);
- else
- mask = 0;
-
- if (sock->state == SS_DISCONNECTING)
- mask |= POLLHUP;
- else
- mask |= POLLOUT;
+ switch ((int)sock->state) {
+ case SS_READY:
+ case SS_CONNECTED:
+ if (!tipc_sk_port(sk)->congested)
+ mask |= POLLOUT;
+ /* fall thru' */
+ case SS_CONNECTING:
+ case SS_LISTENING:
+ if (!skb_queue_empty(&sk->sk_receive_queue))
+ mask |= (POLLIN | POLLRDNORM);
+ break;
+ case SS_DISCONNECTING:
+ mask = (POLLIN | POLLRDNORM | POLLHUP);
+ break;
+ }
return mask;
}
@@ -1026,9 +1046,8 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
struct sk_buff *buf;
struct tipc_msg *msg;
unsigned int sz;
- int sz_to_copy;
+ int sz_to_copy, target, needed;
int sz_copied = 0;
- int needed;
char __user *crs = m->msg_iov->iov_base;
unsigned char *buf_crs;
u32 err;
@@ -1050,6 +1069,8 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
goto exit;
}
+ target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len);
+
restart:
/* Look for a message in receive queue; wait if necessary */
@@ -1138,7 +1159,7 @@ restart:
if ((sz_copied < buf_len) && /* didn't get all requested data */
(!skb_queue_empty(&sk->sk_receive_queue) ||
- (flags & MSG_WAITALL)) && /* and more is ready or required */
+ (sz_copied < target)) && /* and more is ready or required */
(!(flags & MSG_PEEK)) && /* and aren't just peeking at data */
(!err)) /* and haven't reached a FIN */
goto restart;
@@ -1174,7 +1195,7 @@ static int rx_queue_full(struct tipc_msg *msg, u32 queue_size, u32 base)
if (msg_connected(msg))
threshold *= 4;
- return (queue_size >= threshold);
+ return queue_size >= threshold;
}
/**
@@ -1365,6 +1386,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;
int res;
lock_sock(sk);
@@ -1379,7 +1401,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
/* For now, TIPC does not support the non-blocking form of connect() */
if (flags & O_NONBLOCK) {
- res = -EWOULDBLOCK;
+ res = -EOPNOTSUPP;
goto exit;
}
@@ -1425,11 +1447,12 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
/* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */
+ timeout = tipc_sk(sk)->conn_timeout;
release_sock(sk);
res = wait_event_interruptible_timeout(*sk_sleep(sk),
(!skb_queue_empty(&sk->sk_receive_queue) ||
(sock->state != SS_CONNECTING)),
- sk->sk_rcvtimeo);
+ timeout ? timeout : MAX_SCHEDULE_TIMEOUT);
lock_sock(sk);
if (res > 0) {
@@ -1692,7 +1715,7 @@ static int setsockopt(struct socket *sock,
res = tipc_set_portunreturnable(tport->ref, value);
break;
case TIPC_CONN_TIMEOUT:
- sk->sk_rcvtimeo = msecs_to_jiffies(value);
+ tipc_sk(sk)->conn_timeout = msecs_to_jiffies(value);
/* no need to set "res", since already 0 at this point */
break;
default:
@@ -1747,7 +1770,7 @@ static int getsockopt(struct socket *sock,
res = tipc_portunreturnable(tport->ref, &value);
break;
case TIPC_CONN_TIMEOUT:
- value = jiffies_to_msecs(sk->sk_rcvtimeo);
+ value = jiffies_to_msecs(tipc_sk(sk)->conn_timeout);
/* no need to set "res", since already 0 at this point */
break;
case TIPC_NODE_RECVQ_DEPTH:
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index ab6eab4c45e2..33313961d010 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -76,6 +76,19 @@ struct top_srv {
static struct top_srv topsrv = { 0 };
/**
+ * htohl - convert value to endianness used by destination
+ * @in: value to convert
+ * @swap: non-zero if endianness must be reversed
+ *
+ * Returns converted value
+ */
+
+static u32 htohl(u32 in, int swap)
+{
+ return swap ? swab32(in) : in;
+}
+
+/**
* subscr_send_event - send a message containing a tipc_event to the subscriber
*
* Note: Must not hold subscriber's server port lock, since tipc_send() will
@@ -94,11 +107,11 @@ static void subscr_send_event(struct subscription *sub,
msg_sect.iov_base = (void *)&sub->evt;
msg_sect.iov_len = sizeof(struct tipc_event);
- sub->evt.event = htonl(event);
- sub->evt.found_lower = htonl(found_lower);
- sub->evt.found_upper = htonl(found_upper);
- sub->evt.port.ref = htonl(port_ref);
- sub->evt.port.node = htonl(node);
+ sub->evt.event = htohl(event, sub->swap);
+ sub->evt.found_lower = htohl(found_lower, sub->swap);
+ sub->evt.found_upper = htohl(found_upper, sub->swap);
+ sub->evt.port.ref = htohl(port_ref, sub->swap);
+ sub->evt.port.node = htohl(node, sub->swap);
tipc_send(sub->server_ref, 1, &msg_sect);
}
@@ -274,29 +287,16 @@ static void subscr_cancel(struct tipc_subscr *s,
{
struct subscription *sub;
struct subscription *sub_temp;
- __u32 type, lower, upper, timeout, filter;
int found = 0;
/* Find first matching subscription, exit if not found */
- type = ntohl(s->seq.type);
- lower = ntohl(s->seq.lower);
- upper = ntohl(s->seq.upper);
- timeout = ntohl(s->timeout);
- filter = ntohl(s->filter) & ~TIPC_SUB_CANCEL;
-
list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
subscription_list) {
- if ((type == sub->seq.type) &&
- (lower == sub->seq.lower) &&
- (upper == sub->seq.upper) &&
- (timeout == sub->timeout) &&
- (filter == sub->filter) &&
- !memcmp(s->usr_handle,sub->evt.s.usr_handle,
- sizeof(s->usr_handle)) ){
- found = 1;
- break;
- }
+ if (!memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr))) {
+ found = 1;
+ break;
+ }
}
if (!found)
return;
@@ -310,7 +310,7 @@ static void subscr_cancel(struct tipc_subscr *s,
k_term_timer(&sub->timer);
spin_lock_bh(subscriber->lock);
}
- dbg("Cancel: removing sub %u,%u,%u from subscriber %p list\n",
+ dbg("Cancel: removing sub %u,%u,%u from subscriber %x list\n",
sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
subscr_del(sub);
}
@@ -325,10 +325,16 @@ static struct subscription *subscr_subscribe(struct tipc_subscr *s,
struct subscriber *subscriber)
{
struct subscription *sub;
+ int swap;
+
+ /* Determine subscriber's endianness */
+
+ swap = !(s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE));
/* Detect & process a subscription cancellation request */
- if (ntohl(s->filter) & TIPC_SUB_CANCEL) {
+ if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) {
+ s->filter &= ~htohl(TIPC_SUB_CANCEL, swap);
subscr_cancel(s, subscriber);
return NULL;
}
@@ -353,12 +359,13 @@ static struct subscription *subscr_subscribe(struct tipc_subscr *s,
/* Initialize subscription object */
- sub->seq.type = ntohl(s->seq.type);
- sub->seq.lower = ntohl(s->seq.lower);
- sub->seq.upper = ntohl(s->seq.upper);
- sub->timeout = ntohl(s->timeout);
- sub->filter = ntohl(s->filter);
- if ((sub->filter && (sub->filter != TIPC_SUB_PORTS)) ||
+ sub->seq.type = htohl(s->seq.type, swap);
+ sub->seq.lower = htohl(s->seq.lower, swap);
+ sub->seq.upper = htohl(s->seq.upper, swap);
+ sub->timeout = htohl(s->timeout, swap);
+ sub->filter = htohl(s->filter, swap);
+ if ((!(sub->filter & TIPC_SUB_PORTS) ==
+ !(sub->filter & TIPC_SUB_SERVICE)) ||
(sub->seq.lower > sub->seq.upper)) {
warn("Subscription rejected, illegal request\n");
kfree(sub);
@@ -369,6 +376,7 @@ static struct subscription *subscr_subscribe(struct tipc_subscr *s,
INIT_LIST_HEAD(&sub->nameseq_list);
list_add(&sub->subscription_list, &subscriber->subscription_list);
sub->server_ref = subscriber->port_ref;
+ sub->swap = swap;
memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr));
atomic_inc(&topsrv.subscription_count);
if (sub->timeout != TIPC_WAIT_FOREVER) {
@@ -598,12 +606,3 @@ void tipc_subscr_stop(void)
topsrv.user_ref = 0;
}
}
-
-
-int tipc_ispublished(struct tipc_name const *name)
-{
- u32 domain = 0;
-
- return(tipc_nametbl_translate(name->type, name->instance,&domain) != 0);
-}
-
diff --git a/net/tipc/subscr.h b/net/tipc/subscr.h
index c20f496d95b2..45d89bf4d202 100644
--- a/net/tipc/subscr.h
+++ b/net/tipc/subscr.h
@@ -53,6 +53,7 @@ typedef void (*tipc_subscr_event) (struct subscription *sub,
* @nameseq_list: adjacent subscriptions in name sequence's subscription list
* @subscription_list: adjacent subscriptions in subscriber's subscription list
* @server_ref: object reference of server port associated with subscription
+ * @swap: indicates if subscriber uses opposite endianness in its messages
* @evt: template for events generated by subscription
*/
@@ -65,6 +66,7 @@ struct subscription {
struct list_head nameseq_list;
struct list_head subscription_list;
u32 server_ref;
+ int swap;
struct tipc_event evt;
};
diff --git a/net/tipc/zone.c b/net/tipc/zone.c
index 2c01ba2d86bf..83f8b5e91fc8 100644
--- a/net/tipc/zone.c
+++ b/net/tipc/zone.c
@@ -160,14 +160,3 @@ u32 tipc_zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref)
}
return 0;
}
-
-
-u32 tipc_zone_next_node(u32 addr)
-{
- struct cluster *c_ptr = tipc_cltr_find(addr);
-
- if (c_ptr)
- return tipc_cltr_next_node(c_ptr, addr);
- return 0;
-}
-
diff --git a/net/tipc/zone.h b/net/tipc/zone.h
index 7bdc3406ba9b..bd1c20ce9d06 100644
--- a/net/tipc/zone.h
+++ b/net/tipc/zone.h
@@ -61,7 +61,6 @@ void tipc_zone_send_external_routes(struct _zone *z_ptr, u32 dest);
struct _zone *tipc_zone_create(u32 addr);
void tipc_zone_delete(struct _zone *z_ptr);
void tipc_zone_attach_cluster(struct _zone *z_ptr, struct cluster *c_ptr);
-u32 tipc_zone_next_node(u32 addr);
static inline struct _zone *tipc_zone_find(u32 addr)
{
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 0b39b2451ea5..3c95304a0817 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -117,7 +117,7 @@
static struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1];
static DEFINE_SPINLOCK(unix_table_lock);
-static atomic_t unix_nr_socks = ATOMIC_INIT(0);
+static atomic_long_t unix_nr_socks;
#define unix_sockets_unbound (&unix_socket_table[UNIX_HASH_SIZE])
@@ -360,13 +360,13 @@ static void unix_sock_destructor(struct sock *sk)
if (u->addr)
unix_release_addr(u->addr);
- atomic_dec(&unix_nr_socks);
+ atomic_long_dec(&unix_nr_socks);
local_bh_disable();
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
local_bh_enable();
#ifdef UNIX_REFCNT_DEBUG
- printk(KERN_DEBUG "UNIX %p is destroyed, %d are still alive.\n", sk,
- atomic_read(&unix_nr_socks));
+ printk(KERN_DEBUG "UNIX %p is destroyed, %ld are still alive.\n", sk,
+ atomic_long_read(&unix_nr_socks));
#endif
}
@@ -606,8 +606,8 @@ static struct sock *unix_create1(struct net *net, struct socket *sock)
struct sock *sk = NULL;
struct unix_sock *u;
- atomic_inc(&unix_nr_socks);
- if (atomic_read(&unix_nr_socks) > 2 * get_max_files())
+ atomic_long_inc(&unix_nr_socks);
+ if (atomic_long_read(&unix_nr_socks) > 2 * get_max_files())
goto out;
sk = sk_alloc(net, PF_UNIX, GFP_KERNEL, &unix_proto);
@@ -632,7 +632,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock)
unix_insert_socket(unix_sockets_unbound, sk);
out:
if (sk == NULL)
- atomic_dec(&unix_nr_socks);
+ atomic_long_dec(&unix_nr_socks);
else {
local_bh_disable();
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
@@ -1511,6 +1511,8 @@ restart:
goto restart;
}
+ if (sock_flag(other, SOCK_RCVTSTAMP))
+ __net_timestamp(skb);
skb_queue_tail(&other->sk_receive_queue, skb);
unix_state_unlock(other);
other->sk_data_ready(other, len);
@@ -1722,6 +1724,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
if (err)
goto out_free;
+ if (sock_flag(sk, SOCK_RCVTSTAMP))
+ __sock_recv_timestamp(msg, sk, skb);
+
if (!siocb->scm) {
siocb->scm = &tmp_scm;
memset(&tmp_scm, 0, sizeof(tmp_scm));
@@ -2033,11 +2038,10 @@ static unsigned int unix_poll(struct file *file, struct socket *sock, poll_table
if (sk->sk_shutdown == SHUTDOWN_MASK)
mask |= POLLHUP;
if (sk->sk_shutdown & RCV_SHUTDOWN)
- mask |= POLLRDHUP;
+ mask |= POLLRDHUP | POLLIN | POLLRDNORM;
/* readable? */
- if (!skb_queue_empty(&sk->sk_receive_queue) ||
- (sk->sk_shutdown & RCV_SHUTDOWN))
+ if (!skb_queue_empty(&sk->sk_receive_queue))
mask |= POLLIN | POLLRDNORM;
/* Connection-based need to check for termination and startup */
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
index 2bf23406637a..74944a2dd436 100644
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -471,7 +471,7 @@ static int wanrouter_device_setup(struct wan_device *wandev,
data = vmalloc(conf->data_size);
if (!data) {
printk(KERN_INFO
- "%s: ERROR, Faild allocate kernel memory !\n",
+ "%s: ERROR, Failed allocate kernel memory !\n",
wandev->name);
kfree(conf);
return -ENOBUFS;
@@ -481,7 +481,7 @@ static int wanrouter_device_setup(struct wan_device *wandev,
err = wandev->setup(wandev, conf);
} else {
printk(KERN_INFO
- "%s: ERROR, Faild to copy from user data !\n",
+ "%s: ERROR, Failed to copy from user data !\n",
wandev->name);
err = -EFAULT;
}
diff --git a/net/wireless/core.c b/net/wireless/core.c
index d6d046b9f6f2..9c21ebf9780e 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -253,11 +253,16 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
WARN_ON(err);
wdev->netdev->features |= NETIF_F_NETNS_LOCAL;
}
+
+ return err;
}
wiphy_net_set(&rdev->wiphy, net);
- return err;
+ err = device_rename(&rdev->wiphy.dev, dev_name(&rdev->wiphy.dev));
+ WARN_ON(err);
+
+ return 0;
}
static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
@@ -428,7 +433,7 @@ int wiphy_register(struct wiphy *wiphy)
/* sanity check ifmodes */
WARN_ON(!ifmodes);
- ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1;
+ ifmodes &= ((1 << NUM_NL80211_IFTYPES) - 1) & ~1;
if (WARN_ON(ifmodes != wiphy->interface_modes))
wiphy->interface_modes = ifmodes;
@@ -683,8 +688,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work);
INIT_LIST_HEAD(&wdev->event_list);
spin_lock_init(&wdev->event_lock);
- INIT_LIST_HEAD(&wdev->action_registrations);
- spin_lock_init(&wdev->action_registrations_lock);
+ INIT_LIST_HEAD(&wdev->mgmt_registrations);
+ spin_lock_init(&wdev->mgmt_registrations_lock);
mutex_lock(&rdev->devlist_mtx);
list_add_rcu(&wdev->list, &rdev->netdev_list);
@@ -724,6 +729,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
dev->ethtool_ops = &cfg80211_ethtool_ops;
if ((wdev->iftype == NL80211_IFTYPE_STATION ||
+ wdev->iftype == NL80211_IFTYPE_P2P_CLIENT ||
wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
dev->priv_flags |= IFF_DONT_BRIDGE;
break;
@@ -732,6 +738,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
case NL80211_IFTYPE_ADHOC:
cfg80211_leave_ibss(rdev, dev, true);
break;
+ case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
wdev_lock(wdev);
#ifdef CONFIG_CFG80211_WEXT
@@ -804,7 +811,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
sysfs_remove_link(&dev->dev.kobj, "phy80211");
list_del_rcu(&wdev->list);
rdev->devlist_generation++;
- cfg80211_mlme_purge_actions(wdev);
+ cfg80211_mlme_purge_registrations(wdev);
#ifdef CONFIG_CFG80211_WEXT
kfree(wdev->wext.keys);
#endif
@@ -910,52 +917,3 @@ static void __exit cfg80211_exit(void)
destroy_workqueue(cfg80211_wq);
}
module_exit(cfg80211_exit);
-
-static int ___wiphy_printk(const char *level, const struct wiphy *wiphy,
- struct va_format *vaf)
-{
- if (!wiphy)
- return printk("%s(NULL wiphy *): %pV", level, vaf);
-
- return printk("%s%s: %pV", level, wiphy_name(wiphy), vaf);
-}
-
-int __wiphy_printk(const char *level, const struct wiphy *wiphy,
- const char *fmt, ...)
-{
- struct va_format vaf;
- va_list args;
- int r;
-
- va_start(args, fmt);
-
- vaf.fmt = fmt;
- vaf.va = &args;
-
- r = ___wiphy_printk(level, wiphy, &vaf);
- va_end(args);
-
- return r;
-}
-EXPORT_SYMBOL(__wiphy_printk);
-
-#define define_wiphy_printk_level(func, kern_level) \
-int func(const struct wiphy *wiphy, const char *fmt, ...) \
-{ \
- struct va_format vaf; \
- va_list args; \
- int r; \
- \
- va_start(args, fmt); \
- \
- vaf.fmt = fmt; \
- vaf.va = &args; \
- \
- r = ___wiphy_printk(kern_level, wiphy, &vaf); \
- va_end(args); \
- \
- return r; \
-} \
-EXPORT_SYMBOL(func);
-
-define_wiphy_printk_level(wiphy_debug, KERN_DEBUG);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 63d57ae399c3..6583cca0e2ee 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -86,7 +86,7 @@ struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy)
static inline
bool wiphy_idx_valid(int wiphy_idx)
{
- return (wiphy_idx >= 0);
+ return wiphy_idx >= 0;
}
@@ -95,7 +95,10 @@ extern struct mutex cfg80211_mutex;
extern struct list_head cfg80211_rdev_list;
extern int cfg80211_rdev_list_generation;
-#define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex))
+static inline void assert_cfg80211_lock(void)
+{
+ lockdep_assert_held(&cfg80211_mutex);
+}
/*
* You can use this to mark a wiphy_idx as not having an associated wiphy.
@@ -202,8 +205,8 @@ static inline void wdev_unlock(struct wireless_dev *wdev)
mutex_unlock(&wdev->mtx);
}
-#define ASSERT_RDEV_LOCK(rdev) WARN_ON(!mutex_is_locked(&(rdev)->mtx));
-#define ASSERT_WDEV_LOCK(wdev) WARN_ON(!mutex_is_locked(&(wdev)->mtx));
+#define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx)
+#define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx)
enum cfg80211_event_type {
EVENT_CONNECT_RESULT,
@@ -331,16 +334,17 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
const u8 *resp_ie, size_t resp_ie_len,
u16 status, bool wextev,
struct cfg80211_bss *bss);
-int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
- const u8 *match_data, int match_len);
-void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid);
-void cfg80211_mlme_purge_actions(struct wireless_dev *wdev);
-int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
- struct net_device *dev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
- bool channel_type_valid,
- const u8 *buf, size_t len, u64 *cookie);
+int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
+ u16 frame_type, const u8 *match_data,
+ int match_len);
+void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid);
+void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);
+int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
+ const u8 *buf, size_t len, u64 *cookie);
/* SME */
int __cfg80211_connect(struct cfg80211_registered_device *rdev,
@@ -371,7 +375,7 @@ bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev);
/* internal helpers */
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
struct key_params *params, int key_idx,
- const u8 *mac_addr);
+ bool pairwise, const u8 *mac_addr);
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
size_t ie_len, u16 reason, bool from_ap);
void cfg80211_sme_scan_done(struct net_device *dev);
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 27a8ce9343c3..f33fbb79437c 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -88,6 +88,25 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
if (wdev->ssid_len)
return -EALREADY;
+ if (!params->basic_rates) {
+ /*
+ * If no rates were explicitly configured,
+ * use the mandatory rate set for 11b or
+ * 11a for maximum compatibility.
+ */
+ struct ieee80211_supported_band *sband =
+ rdev->wiphy.bands[params->channel->band];
+ int j;
+ u32 flag = params->channel->band == IEEE80211_BAND_5GHZ ?
+ IEEE80211_RATE_MANDATORY_A :
+ IEEE80211_RATE_MANDATORY_B;
+
+ for (j = 0; j < sband->n_bitrates; j++) {
+ if (sband->bitrates[j].flags & flag)
+ params->basic_rates |= BIT(j);
+ }
+ }
+
if (WARN_ON(wdev->connect_keys))
kfree(wdev->connect_keys);
wdev->connect_keys = connkeys;
@@ -141,7 +160,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
*/
if (rdev->ops->del_key)
for (i = 0; i < 6; i++)
- rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
+ rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL);
if (wdev->current_bss) {
cfg80211_unhold_bss(wdev->current_bss);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index d1a3fb99fdf2..26838d903b9a 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -149,7 +149,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
const u8 *bssid = mgmt->bssid;
int i;
- bool found = false;
+ bool found = false, was_current = false;
ASSERT_WDEV_LOCK(wdev);
@@ -159,6 +159,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
cfg80211_put_bss(&wdev->current_bss->pub);
wdev->current_bss = NULL;
found = true;
+ was_current = true;
} else for (i = 0; i < MAX_AUTH_BSSES; i++) {
if (wdev->auth_bsses[i] &&
memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
@@ -183,7 +184,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
- if (wdev->sme_state == CFG80211_SME_CONNECTED) {
+ if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) {
u16 reason_code;
bool from_ap;
@@ -747,31 +748,53 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
}
EXPORT_SYMBOL(cfg80211_new_sta);
-struct cfg80211_action_registration {
+struct cfg80211_mgmt_registration {
struct list_head list;
u32 nlpid;
int match_len;
+ __le16 frame_type;
+
u8 match[];
};
-int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
- const u8 *match_data, int match_len)
+int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
+ u16 frame_type, const u8 *match_data,
+ int match_len)
{
- struct cfg80211_action_registration *reg, *nreg;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ struct cfg80211_mgmt_registration *reg, *nreg;
int err = 0;
+ u16 mgmt_type;
+
+ if (!wdev->wiphy->mgmt_stypes)
+ return -EOPNOTSUPP;
+
+ if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT)
+ return -EINVAL;
+
+ if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE))
+ return -EINVAL;
+
+ mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
+ if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type)))
+ return -EINVAL;
nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL);
if (!nreg)
return -ENOMEM;
- spin_lock_bh(&wdev->action_registrations_lock);
+ spin_lock_bh(&wdev->mgmt_registrations_lock);
- list_for_each_entry(reg, &wdev->action_registrations, list) {
+ list_for_each_entry(reg, &wdev->mgmt_registrations, list) {
int mlen = min(match_len, reg->match_len);
+ if (frame_type != le16_to_cpu(reg->frame_type))
+ continue;
+
if (memcmp(reg->match, match_data, mlen) == 0) {
err = -EALREADY;
break;
@@ -786,140 +809,212 @@ int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
memcpy(nreg->match, match_data, match_len);
nreg->match_len = match_len;
nreg->nlpid = snd_pid;
- list_add(&nreg->list, &wdev->action_registrations);
+ nreg->frame_type = cpu_to_le16(frame_type);
+ list_add(&nreg->list, &wdev->mgmt_registrations);
+
+ if (rdev->ops->mgmt_frame_register)
+ rdev->ops->mgmt_frame_register(wiphy, wdev->netdev,
+ frame_type, true);
out:
- spin_unlock_bh(&wdev->action_registrations_lock);
+ spin_unlock_bh(&wdev->mgmt_registrations_lock);
+
return err;
}
-void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid)
+void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid)
{
- struct cfg80211_action_registration *reg, *tmp;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ struct cfg80211_mgmt_registration *reg, *tmp;
- spin_lock_bh(&wdev->action_registrations_lock);
+ spin_lock_bh(&wdev->mgmt_registrations_lock);
- list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
- if (reg->nlpid == nlpid) {
- list_del(&reg->list);
- kfree(reg);
+ list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
+ if (reg->nlpid != nlpid)
+ continue;
+
+ if (rdev->ops->mgmt_frame_register) {
+ u16 frame_type = le16_to_cpu(reg->frame_type);
+
+ rdev->ops->mgmt_frame_register(wiphy, wdev->netdev,
+ frame_type, false);
}
+
+ list_del(&reg->list);
+ kfree(reg);
}
- spin_unlock_bh(&wdev->action_registrations_lock);
+ spin_unlock_bh(&wdev->mgmt_registrations_lock);
}
-void cfg80211_mlme_purge_actions(struct wireless_dev *wdev)
+void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
{
- struct cfg80211_action_registration *reg, *tmp;
+ struct cfg80211_mgmt_registration *reg, *tmp;
- spin_lock_bh(&wdev->action_registrations_lock);
+ spin_lock_bh(&wdev->mgmt_registrations_lock);
- list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
+ list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
list_del(&reg->list);
kfree(reg);
}
- spin_unlock_bh(&wdev->action_registrations_lock);
+ spin_unlock_bh(&wdev->mgmt_registrations_lock);
}
-int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
- struct net_device *dev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
- bool channel_type_valid,
- const u8 *buf, size_t len, u64 *cookie)
+int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
+ const u8 *buf, size_t len, u64 *cookie)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
const struct ieee80211_mgmt *mgmt;
+ u16 stype;
- if (rdev->ops->action == NULL)
+ if (!wdev->wiphy->mgmt_stypes)
return -EOPNOTSUPP;
+
+ if (!rdev->ops->mgmt_tx)
+ return -EOPNOTSUPP;
+
if (len < 24 + 1)
return -EINVAL;
mgmt = (const struct ieee80211_mgmt *) buf;
- if (!ieee80211_is_action(mgmt->frame_control))
+
+ if (!ieee80211_is_mgmt(mgmt->frame_control))
return -EINVAL;
- if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
- /* Verify that we are associated with the destination AP */
+
+ stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
+ if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].tx & BIT(stype >> 4)))
+ return -EINVAL;
+
+ if (ieee80211_is_action(mgmt->frame_control) &&
+ mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
+ int err = 0;
+
wdev_lock(wdev);
- if (!wdev->current_bss ||
- memcmp(wdev->current_bss->pub.bssid, mgmt->bssid,
- ETH_ALEN) != 0 ||
- (wdev->iftype == NL80211_IFTYPE_STATION &&
- memcmp(wdev->current_bss->pub.bssid, mgmt->da,
- ETH_ALEN) != 0)) {
- wdev_unlock(wdev);
- return -ENOTCONN;
- }
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ if (!wdev->current_bss) {
+ err = -ENOTCONN;
+ break;
+ }
+
+ if (memcmp(wdev->current_bss->pub.bssid,
+ mgmt->bssid, ETH_ALEN)) {
+ err = -ENOTCONN;
+ break;
+ }
+
+ /*
+ * check for IBSS DA must be done by driver as
+ * cfg80211 doesn't track the stations
+ */
+ if (wdev->iftype == NL80211_IFTYPE_ADHOC)
+ break;
+ /* for station, check that DA is the AP */
+ if (memcmp(wdev->current_bss->pub.bssid,
+ mgmt->da, ETH_ALEN)) {
+ err = -ENOTCONN;
+ break;
+ }
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_AP_VLAN:
+ if (memcmp(mgmt->bssid, dev->dev_addr, ETH_ALEN))
+ err = -EINVAL;
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
wdev_unlock(wdev);
+
+ if (err)
+ return err;
}
if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0)
return -EINVAL;
/* Transmit the Action frame as requested by user space */
- return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type,
- channel_type_valid, buf, len, cookie);
+ return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, channel_type,
+ channel_type_valid, buf, len, cookie);
}
-bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
- size_t len, gfp_t gfp)
+bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
+ size_t len, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
- struct cfg80211_action_registration *reg;
- const u8 *action_data;
- int action_data_len;
+ struct cfg80211_mgmt_registration *reg;
+ const struct ieee80211_txrx_stypes *stypes =
+ &wiphy->mgmt_stypes[wdev->iftype];
+ struct ieee80211_mgmt *mgmt = (void *)buf;
+ const u8 *data;
+ int data_len;
bool result = false;
+ __le16 ftype = mgmt->frame_control &
+ cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE);
+ u16 stype;
- /* frame length - min size excluding category */
- action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1);
+ stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4;
- /* action data starts with category */
- action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1;
+ if (!(stypes->rx & BIT(stype)))
+ return false;
- spin_lock_bh(&wdev->action_registrations_lock);
+ data = buf + ieee80211_hdrlen(mgmt->frame_control);
+ data_len = len - ieee80211_hdrlen(mgmt->frame_control);
+
+ spin_lock_bh(&wdev->mgmt_registrations_lock);
+
+ list_for_each_entry(reg, &wdev->mgmt_registrations, list) {
+ if (reg->frame_type != ftype)
+ continue;
- list_for_each_entry(reg, &wdev->action_registrations, list) {
- if (reg->match_len > action_data_len)
+ if (reg->match_len > data_len)
continue;
- if (memcmp(reg->match, action_data, reg->match_len))
+ if (memcmp(reg->match, data, reg->match_len))
continue;
/* found match! */
/* Indicate the received Action frame to user space */
- if (nl80211_send_action(rdev, dev, reg->nlpid, freq,
- buf, len, gfp))
+ if (nl80211_send_mgmt(rdev, dev, reg->nlpid, freq,
+ buf, len, gfp))
continue;
result = true;
break;
}
- spin_unlock_bh(&wdev->action_registrations_lock);
+ spin_unlock_bh(&wdev->mgmt_registrations_lock);
return result;
}
-EXPORT_SYMBOL(cfg80211_rx_action);
+EXPORT_SYMBOL(cfg80211_rx_mgmt);
-void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
- const u8 *buf, size_t len, bool ack, gfp_t gfp)
+void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie,
+ const u8 *buf, size_t len, bool ack, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
/* Indicate TX status of the Action frame to user space */
- nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
+ nl80211_send_mgmt_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
}
-EXPORT_SYMBOL(cfg80211_action_tx_status);
+EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
void cfg80211_cqm_rssi_notify(struct net_device *dev,
enum nl80211_cqm_rssi_threshold_event rssi_event,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 37902a54e9c1..c506241f8637 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -23,6 +23,11 @@
#include "nl80211.h"
#include "reg.h"
+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,
+ struct genl_info *info);
+
/* the netlink family */
static struct genl_family nl80211_fam = {
.id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */
@@ -31,6 +36,8 @@ static struct genl_family nl80211_fam = {
.version = 1, /* no particular meaning now */
.maxattr = NL80211_ATTR_MAX,
.netnsok = true,
+ .pre_doit = nl80211_pre_doit,
+ .post_doit = nl80211_post_doit,
};
/* internal helper: get rdev and dev */
@@ -86,6 +93,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
[NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+ [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
[NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
[NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
@@ -136,6 +144,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
.len = sizeof(struct nl80211_sta_flag_update),
},
[NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
+ [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 },
+ [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG },
[NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
[NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
[NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
@@ -156,9 +166,10 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
+ [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
};
-/* policy for the attributes */
+/* policy for the key attributes */
static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
[NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
[NL80211_KEY_IDX] = { .type = NLA_U8 },
@@ -166,6 +177,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
[NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
[NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
[NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
+ [NL80211_KEY_TYPE] = { .type = NLA_U32 },
};
/* ifidx get helper */
@@ -188,6 +200,47 @@ static int nl80211_get_ifidx(struct netlink_callback *cb)
return res;
}
+static int nl80211_prepare_netdev_dump(struct sk_buff *skb,
+ struct netlink_callback *cb,
+ struct cfg80211_registered_device **rdev,
+ struct net_device **dev)
+{
+ int ifidx = cb->args[0];
+ int err;
+
+ if (!ifidx)
+ ifidx = nl80211_get_ifidx(cb);
+ if (ifidx < 0)
+ return ifidx;
+
+ cb->args[0] = ifidx;
+
+ rtnl_lock();
+
+ *dev = __dev_get_by_index(sock_net(skb->sk), ifidx);
+ if (!*dev) {
+ err = -ENODEV;
+ goto out_rtnl;
+ }
+
+ *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
+ if (IS_ERR(dev)) {
+ err = PTR_ERR(dev);
+ goto out_rtnl;
+ }
+
+ return 0;
+ out_rtnl:
+ rtnl_unlock();
+ return err;
+}
+
+static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev)
+{
+ cfg80211_unlock_rdev(rdev);
+ rtnl_unlock();
+}
+
/* IE validation */
static bool is_valid_ie_attr(const struct nlattr *attr)
{
@@ -255,6 +308,7 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
struct key_parse {
struct key_params p;
int idx;
+ int type;
bool def, defmgmt;
};
@@ -285,6 +339,12 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
if (tb[NL80211_KEY_CIPHER])
k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
+ if (tb[NL80211_KEY_TYPE]) {
+ k->type = nla_get_u32(tb[NL80211_KEY_TYPE]);
+ if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
+ return -EINVAL;
+ }
+
return 0;
}
@@ -309,6 +369,12 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
+ if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
+ k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
+ if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
+ return -EINVAL;
+ }
+
return 0;
}
@@ -318,6 +384,7 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
memset(k, 0, sizeof(*k));
k->idx = -1;
+ k->type = -1;
if (info->attrs[NL80211_ATTR_KEY])
err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k);
@@ -382,7 +449,7 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
} else if (parse.defmgmt)
goto error;
err = cfg80211_validate_key_settings(rdev, &parse.p,
- parse.idx, NULL);
+ parse.idx, false, NULL);
if (err)
goto error;
result->params[parse.idx].cipher = parse.p.cipher;
@@ -401,18 +468,17 @@ static int nl80211_key_allowed(struct wireless_dev *wdev)
{
ASSERT_WDEV_LOCK(wdev);
- if (!netif_running(wdev->netdev))
- return -ENETDOWN;
-
switch (wdev->iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_P2P_GO:
break;
case NL80211_IFTYPE_ADHOC:
if (!wdev->current_bss)
return -ENOLINK;
break;
case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
if (wdev->sme_state != CFG80211_SME_CONNECTED)
return -ENOLINK;
break;
@@ -437,6 +503,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
struct ieee80211_rate *rate;
int i;
u16 ifmodes = dev->wiphy.interface_modes;
+ const struct ieee80211_txrx_stypes *mgmt_stypes =
+ dev->wiphy.mgmt_stypes;
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
if (!hdr)
@@ -464,6 +532,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
dev->wiphy.max_scan_ie_len);
+ if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN);
+
NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES,
sizeof(u32) * dev->wiphy.n_cipher_suites,
dev->wiphy.cipher_suites);
@@ -471,6 +542,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
dev->wiphy.max_num_pmkids);
+ if (dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE);
+
nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
if (!nl_modes)
goto nla_put_failure;
@@ -587,12 +661,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
CMD(flush_pmksa, FLUSH_PMKSA);
CMD(remain_on_channel, REMAIN_ON_CHANNEL);
CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
- CMD(action, ACTION);
+ CMD(mgmt_tx, FRAME);
if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
i++;
NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
}
CMD(set_channel, SET_CHANNEL);
+ CMD(set_wds_peer, SET_WDS_PEER);
#undef CMD
@@ -608,6 +683,55 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
nla_nest_end(msg, nl_cmds);
+ if (mgmt_stypes) {
+ u16 stypes;
+ struct nlattr *nl_ftypes, *nl_ifs;
+ enum nl80211_iftype ift;
+
+ nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
+ if (!nl_ifs)
+ goto nla_put_failure;
+
+ for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
+ nl_ftypes = nla_nest_start(msg, ift);
+ if (!nl_ftypes)
+ goto nla_put_failure;
+ i = 0;
+ stypes = mgmt_stypes[ift].tx;
+ while (stypes) {
+ if (stypes & 1)
+ NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE,
+ (i << 4) | IEEE80211_FTYPE_MGMT);
+ stypes >>= 1;
+ i++;
+ }
+ nla_nest_end(msg, nl_ftypes);
+ }
+
+ nla_nest_end(msg, nl_ifs);
+
+ nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
+ if (!nl_ifs)
+ goto nla_put_failure;
+
+ for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
+ nl_ftypes = nla_nest_start(msg, ift);
+ if (!nl_ftypes)
+ goto nla_put_failure;
+ i = 0;
+ stypes = mgmt_stypes[ift].rx;
+ while (stypes) {
+ if (stypes & 1)
+ NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE,
+ (i << 4) | IEEE80211_FTYPE_MGMT);
+ stypes >>= 1;
+ i++;
+ }
+ nla_nest_end(msg, nl_ftypes);
+ }
+ nla_nest_end(msg, nl_ifs);
+ }
+
return genlmsg_end(msg, hdr);
nla_put_failure:
@@ -644,28 +768,18 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
{
struct sk_buff *msg;
- struct cfg80211_registered_device *dev;
-
- dev = cfg80211_get_dev_from_info(info);
- if (IS_ERR(dev))
- return PTR_ERR(dev);
+ struct cfg80211_registered_device *dev = info->user_ptr[0];
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
- goto out_err;
-
- if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0)
- goto out_free;
+ return -ENOMEM;
- cfg80211_unlock_rdev(dev);
+ if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
return genlmsg_reply(msg, info);
-
- out_free:
- nlmsg_free(msg);
- out_err:
- cfg80211_unlock_rdev(dev);
- return -ENOBUFS;
}
static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
@@ -709,7 +823,8 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
wdev->iftype == NL80211_IFTYPE_AP ||
wdev->iftype == NL80211_IFTYPE_WDS ||
wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
- wdev->iftype == NL80211_IFTYPE_MONITOR;
+ wdev->iftype == NL80211_IFTYPE_MONITOR ||
+ wdev->iftype == NL80211_IFTYPE_P2P_GO;
}
static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
@@ -753,38 +868,48 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- struct net_device *netdev;
- int result;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *netdev = info->user_ptr[1];
- rtnl_lock();
+ return __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info);
+}
- result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev);
- if (result)
- goto unlock;
+static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ const u8 *bssid;
- result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info);
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
- unlock:
- rtnl_unlock();
+ if (netif_running(dev))
+ return -EBUSY;
- return result;
+ if (!rdev->ops->set_wds_peer)
+ return -EOPNOTSUPP;
+
+ if (wdev->iftype != NL80211_IFTYPE_WDS)
+ return -EOPNOTSUPP;
+
+ bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ return rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid);
}
+
static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev;
struct net_device *netdev = NULL;
struct wireless_dev *wdev;
- int result, rem_txq_params = 0;
+ int result = 0, rem_txq_params = 0;
struct nlattr *nl_txq_params;
u32 changed;
u8 retry_short = 0, retry_long = 0;
u32 frag_threshold = 0, rts_threshold = 0;
u8 coverage_class = 0;
- rtnl_lock();
-
/*
* Try to find the wiphy and netdev. Normally this
* function shouldn't need the netdev, but this is
@@ -811,8 +936,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
rdev = __cfg80211_rdev_from_info(info);
if (IS_ERR(rdev)) {
mutex_unlock(&cfg80211_mutex);
- result = PTR_ERR(rdev);
- goto unlock;
+ return PTR_ERR(rdev);
}
wdev = NULL;
netdev = NULL;
@@ -994,8 +1118,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
mutex_unlock(&rdev->mtx);
if (netdev)
dev_put(netdev);
- unlock:
- rtnl_unlock();
return result;
}
@@ -1075,33 +1197,20 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
{
struct sk_buff *msg;
- struct cfg80211_registered_device *dev;
- struct net_device *netdev;
- int err;
-
- err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev);
- if (err)
- return err;
+ struct cfg80211_registered_device *dev = info->user_ptr[0];
+ struct net_device *netdev = info->user_ptr[1];
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
- goto out_err;
+ return -ENOMEM;
if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0,
- dev, netdev) < 0)
- goto out_free;
-
- dev_put(netdev);
- cfg80211_unlock_rdev(dev);
+ dev, netdev) < 0) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
return genlmsg_reply(msg, info);
-
- out_free:
- nlmsg_free(msg);
- out_err:
- dev_put(netdev);
- cfg80211_unlock_rdev(dev);
- return -ENOBUFS;
}
static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
@@ -1161,39 +1270,29 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct vif_params params;
int err;
enum nl80211_iftype otype, ntype;
- struct net_device *dev;
+ struct net_device *dev = info->user_ptr[1];
u32 _flags, *flags = NULL;
bool change = false;
memset(&params, 0, sizeof(params));
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
otype = ntype = dev->ieee80211_ptr->iftype;
if (info->attrs[NL80211_ATTR_IFTYPE]) {
ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
if (otype != ntype)
change = true;
- if (ntype > NL80211_IFTYPE_MAX) {
- err = -EINVAL;
- goto unlock;
- }
+ if (ntype > NL80211_IFTYPE_MAX)
+ return -EINVAL;
}
if (info->attrs[NL80211_ATTR_MESH_ID]) {
- if (ntype != NL80211_IFTYPE_MESH_POINT) {
- err = -EINVAL;
- goto unlock;
- }
+ if (ntype != NL80211_IFTYPE_MESH_POINT)
+ return -EINVAL;
params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
change = true;
@@ -1204,20 +1303,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
change = true;
err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
if (err)
- goto unlock;
+ return err;
} else {
params.use_4addr = -1;
}
if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
- if (ntype != NL80211_IFTYPE_MONITOR) {
- err = -EINVAL;
- goto unlock;
- }
+ if (ntype != NL80211_IFTYPE_MONITOR)
+ return -EINVAL;
err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
&_flags);
if (err)
- goto unlock;
+ return err;
flags = &_flags;
change = true;
@@ -1231,17 +1328,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
if (!err && params.use_4addr != -1)
dev->ieee80211_ptr->use_4addr = params.use_4addr;
- unlock:
- dev_put(dev);
- cfg80211_unlock_rdev(rdev);
- unlock_rtnl:
- rtnl_unlock();
return err;
}
static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct vif_params params;
int err;
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
@@ -1258,19 +1350,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}
- rtnl_lock();
-
- rdev = cfg80211_get_dev_from_info(info);
- if (IS_ERR(rdev)) {
- err = PTR_ERR(rdev);
- goto unlock_rtnl;
- }
-
if (!rdev->ops->add_virtual_intf ||
- !(rdev->wiphy.interface_modes & (1 << type))) {
- err = -EOPNOTSUPP;
- goto unlock;
- }
+ !(rdev->wiphy.interface_modes & (1 << type)))
+ return -EOPNOTSUPP;
if (type == NL80211_IFTYPE_MESH_POINT &&
info->attrs[NL80211_ATTR_MESH_ID]) {
@@ -1282,7 +1364,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
if (err)
- goto unlock;
+ return err;
}
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
@@ -1292,38 +1374,18 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
type, err ? NULL : &flags, &params);
- unlock:
- cfg80211_unlock_rdev(rdev);
- unlock_rtnl:
- rtnl_unlock();
return err;
}
static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- int err;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (!rdev->ops->del_virtual_intf) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev);
+ if (!rdev->ops->del_virtual_intf)
+ return -EOPNOTSUPP;
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- unlock_rtnl:
- rtnl_unlock();
- return err;
+ return rdev->ops->del_virtual_intf(&rdev->wiphy, dev);
}
struct get_key_cookie {
@@ -1376,11 +1438,12 @@ static void get_key_callback(void *c, struct key_params *params)
static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
int err;
- struct net_device *dev;
+ struct net_device *dev = info->user_ptr[1];
u8 key_idx = 0;
- u8 *mac_addr = NULL;
+ const u8 *mac_addr = NULL;
+ bool pairwise;
struct get_key_cookie cookie = {
.error = 0,
};
@@ -1396,30 +1459,28 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (!rdev->ops->get_key) {
- err = -EOPNOTSUPP;
- goto out;
+ pairwise = !!mac_addr;
+ if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
+ u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
+ if (kt >= NUM_NL80211_KEYTYPES)
+ return -EINVAL;
+ if (kt != NL80211_KEYTYPE_GROUP &&
+ kt != NL80211_KEYTYPE_PAIRWISE)
+ return -EINVAL;
+ pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
}
+ if (!rdev->ops->get_key)
+ return -EOPNOTSUPP;
+
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (!msg) {
- err = -ENOMEM;
- goto out;
- }
+ if (!msg)
+ return -ENOMEM;
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
NL80211_CMD_NEW_KEY);
-
- if (IS_ERR(hdr)) {
- err = PTR_ERR(hdr);
- goto free_msg;
- }
+ if (IS_ERR(hdr))
+ return PTR_ERR(hdr);
cookie.msg = msg;
cookie.idx = key_idx;
@@ -1429,8 +1490,12 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
if (mac_addr)
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
- err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, mac_addr,
- &cookie, get_key_callback);
+ if (pairwise && mac_addr &&
+ !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
+ return -ENOENT;
+
+ err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, pairwise,
+ mac_addr, &cookie, get_key_callback);
if (err)
goto free_msg;
@@ -1439,28 +1504,21 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
goto nla_put_failure;
genlmsg_end(msg, hdr);
- err = genlmsg_reply(msg, info);
- goto out;
+ return genlmsg_reply(msg, info);
nla_put_failure:
err = -ENOBUFS;
free_msg:
nlmsg_free(msg);
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- unlock_rtnl:
- rtnl_unlock();
-
return err;
}
static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct key_parse key;
int err;
- struct net_device *dev;
+ struct net_device *dev = info->user_ptr[1];
int (*func)(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index);
@@ -1475,21 +1533,13 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
if (!key.def && !key.defmgmt)
return -EINVAL;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
if (key.def)
func = rdev->ops->set_default_key;
else
func = rdev->ops->set_default_mgmt_key;
- if (!func) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!func)
+ return -EOPNOTSUPP;
wdev_lock(dev->ieee80211_ptr);
err = nl80211_key_allowed(dev->ieee80211_ptr);
@@ -1506,23 +1556,16 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
#endif
wdev_unlock(dev->ieee80211_ptr);
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
-
- unlock_rtnl:
- rtnl_unlock();
-
return err;
}
static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
int err;
- struct net_device *dev;
+ struct net_device *dev = info->user_ptr[1];
struct key_parse key;
- u8 *mac_addr = NULL;
+ const u8 *mac_addr = NULL;
err = nl80211_parse_key(info, &key);
if (err)
@@ -1534,43 +1577,42 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
- rtnl_lock();
+ if (key.type == -1) {
+ if (mac_addr)
+ key.type = NL80211_KEYTYPE_PAIRWISE;
+ else
+ key.type = NL80211_KEYTYPE_GROUP;
+ }
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
+ /* for now */
+ if (key.type != NL80211_KEYTYPE_PAIRWISE &&
+ key.type != NL80211_KEYTYPE_GROUP)
+ return -EINVAL;
- if (!rdev->ops->add_key) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!rdev->ops->add_key)
+ return -EOPNOTSUPP;
- if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) {
- err = -EINVAL;
- goto out;
- }
+ if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
+ key.type == NL80211_KEYTYPE_PAIRWISE,
+ mac_addr))
+ return -EINVAL;
wdev_lock(dev->ieee80211_ptr);
err = nl80211_key_allowed(dev->ieee80211_ptr);
if (!err)
err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx,
+ key.type == NL80211_KEYTYPE_PAIRWISE,
mac_addr, &key.p);
wdev_unlock(dev->ieee80211_ptr);
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- unlock_rtnl:
- rtnl_unlock();
-
return err;
}
static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
int err;
- struct net_device *dev;
+ struct net_device *dev = info->user_ptr[1];
u8 *mac_addr = NULL;
struct key_parse key;
@@ -1581,21 +1623,32 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
- rtnl_lock();
+ if (key.type == -1) {
+ if (mac_addr)
+ key.type = NL80211_KEYTYPE_PAIRWISE;
+ else
+ key.type = NL80211_KEYTYPE_GROUP;
+ }
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
+ /* for now */
+ if (key.type != NL80211_KEYTYPE_PAIRWISE &&
+ key.type != NL80211_KEYTYPE_GROUP)
+ return -EINVAL;
- if (!rdev->ops->del_key) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!rdev->ops->del_key)
+ return -EOPNOTSUPP;
wdev_lock(dev->ieee80211_ptr);
err = nl80211_key_allowed(dev->ieee80211_ptr);
+
+ if (key.type == NL80211_KEYTYPE_PAIRWISE && mac_addr &&
+ !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
+ err = -ENOENT;
+
if (!err)
- err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
+ err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx,
+ key.type == NL80211_KEYTYPE_PAIRWISE,
+ mac_addr);
#ifdef CONFIG_CFG80211_WEXT
if (!err) {
@@ -1607,13 +1660,6 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
#endif
wdev_unlock(dev->ieee80211_ptr);
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
-
- unlock_rtnl:
- rtnl_unlock();
-
return err;
}
@@ -1621,35 +1667,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
{
int (*call)(struct wiphy *wiphy, struct net_device *dev,
struct beacon_parameters *info);
- struct cfg80211_registered_device *rdev;
- int err;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
struct beacon_parameters params;
int haveinfo = 0;
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]))
return -EINVAL;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
switch (info->genlhdr->cmd) {
case NL80211_CMD_NEW_BEACON:
/* these are required for NEW_BEACON */
if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
!info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
- !info->attrs[NL80211_ATTR_BEACON_HEAD]) {
- err = -EINVAL;
- goto out;
- }
+ !info->attrs[NL80211_ATTR_BEACON_HEAD])
+ return -EINVAL;
call = rdev->ops->add_beacon;
break;
@@ -1658,14 +1694,11 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
break;
default:
WARN_ON(1);
- err = -EOPNOTSUPP;
- goto out;
+ return -EOPNOTSUPP;
}
- if (!call) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!call)
+ return -EOPNOTSUPP;
memset(&params, 0, sizeof(params));
@@ -1695,52 +1728,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
haveinfo = 1;
}
- if (!haveinfo) {
- err = -EINVAL;
- goto out;
- }
-
- err = call(&rdev->wiphy, dev, &params);
-
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- unlock_rtnl:
- rtnl_unlock();
+ if (!haveinfo)
+ return -EINVAL;
- return err;
+ return call(&rdev->wiphy, dev, &params);
}
static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- int err;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (!rdev->ops->del_beacon) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
- err = -EOPNOTSUPP;
- goto out;
- }
- err = rdev->ops->del_beacon(&rdev->wiphy, dev);
+ if (!rdev->ops->del_beacon)
+ return -EOPNOTSUPP;
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- unlock_rtnl:
- rtnl_unlock();
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
- return err;
+ return rdev->ops->del_beacon(&rdev->wiphy, dev);
}
static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
@@ -1861,6 +1867,12 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
if (sinfo->filled & STATION_INFO_TX_PACKETS)
NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS,
sinfo->tx_packets);
+ if (sinfo->filled & STATION_INFO_TX_RETRIES)
+ NLA_PUT_U32(msg, NL80211_STA_INFO_TX_RETRIES,
+ sinfo->tx_retries);
+ if (sinfo->filled & STATION_INFO_TX_FAILED)
+ NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED,
+ sinfo->tx_failed);
nla_nest_end(msg, sinfoattr);
return genlmsg_end(msg, hdr);
@@ -1877,28 +1889,12 @@ static int nl80211_dump_station(struct sk_buff *skb,
struct cfg80211_registered_device *dev;
struct net_device *netdev;
u8 mac_addr[ETH_ALEN];
- int ifidx = cb->args[0];
int sta_idx = cb->args[1];
int err;
- if (!ifidx)
- ifidx = nl80211_get_ifidx(cb);
- if (ifidx < 0)
- return ifidx;
-
- rtnl_lock();
-
- netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
- if (!netdev) {
- err = -ENODEV;
- goto out_rtnl;
- }
-
- dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
- if (IS_ERR(dev)) {
- err = PTR_ERR(dev);
- goto out_rtnl;
- }
+ err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev);
+ if (err)
+ return err;
if (!dev->ops->dump_station) {
err = -EOPNOTSUPP;
@@ -1928,21 +1924,19 @@ static int nl80211_dump_station(struct sk_buff *skb,
cb->args[1] = sta_idx;
err = skb->len;
out_err:
- cfg80211_unlock_rdev(dev);
- out_rtnl:
- rtnl_unlock();
+ nl80211_finish_netdev_dump(dev);
return err;
}
static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- int err;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
struct station_info sinfo;
struct sk_buff *msg;
u8 *mac_addr = NULL;
+ int err;
memset(&sinfo, 0, sizeof(sinfo));
@@ -1951,41 +1945,24 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto out_rtnl;
-
- if (!rdev->ops->get_station) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!rdev->ops->get_station)
+ return -EOPNOTSUPP;
err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo);
if (err)
- goto out;
+ return err;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
- goto out;
+ return -ENOMEM;
if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
- dev, mac_addr, &sinfo) < 0)
- goto out_free;
-
- err = genlmsg_reply(msg, info);
- goto out;
-
- out_free:
- nlmsg_free(msg);
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- out_rtnl:
- rtnl_unlock();
+ dev, mac_addr, &sinfo) < 0) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
- return err;
+ return genlmsg_reply(msg, info);
}
/*
@@ -2015,9 +1992,9 @@ static int get_vlan(struct genl_info *info,
static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
int err;
- struct net_device *dev;
+ struct net_device *dev = info->user_ptr[1];
struct station_parameters params;
u8 *mac_addr = NULL;
@@ -2055,12 +2032,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
params.plink_action =
nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto out_rtnl;
-
err = get_vlan(info, rdev, &params.vlan);
if (err)
goto out;
@@ -2071,10 +2042,12 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
switch (dev->ieee80211_ptr->iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_P2P_GO:
/* disallow mesh-specific things */
if (params.plink_action)
err = -EINVAL;
break;
+ case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
/* disallow everything but AUTHORIZED flag */
if (params.plink_action)
@@ -2120,19 +2093,15 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
out:
if (params.vlan)
dev_put(params.vlan);
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- out_rtnl:
- rtnl_unlock();
return err;
}
static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
int err;
- struct net_device *dev;
+ struct net_device *dev = info->user_ptr[1];
struct station_parameters params;
u8 *mac_addr = NULL;
@@ -2169,17 +2138,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
if (parse_station_flags(info, &params))
return -EINVAL;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto out_rtnl;
-
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
- dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
- err = -EINVAL;
- goto out;
- }
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EINVAL;
err = get_vlan(info, rdev, &params.vlan);
if (err)
@@ -2193,61 +2155,33 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
-
err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, &params);
out:
if (params.vlan)
dev_put(params.vlan);
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- out_rtnl:
- rtnl_unlock();
-
return err;
}
static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- int err;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
u8 *mac_addr = NULL;
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto out_rtnl;
-
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
- dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
- err = -EINVAL;
- goto out;
- }
-
- if (!rdev->ops->del_station) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- err = rdev->ops->del_station(&rdev->wiphy, dev, mac_addr);
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EINVAL;
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- out_rtnl:
- rtnl_unlock();
+ if (!rdev->ops->del_station)
+ return -EOPNOTSUPP;
- return err;
+ return rdev->ops->del_station(&rdev->wiphy, dev, mac_addr);
}
static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq,
@@ -2310,28 +2244,12 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
struct net_device *netdev;
u8 dst[ETH_ALEN];
u8 next_hop[ETH_ALEN];
- int ifidx = cb->args[0];
int path_idx = cb->args[1];
int err;
- if (!ifidx)
- ifidx = nl80211_get_ifidx(cb);
- if (ifidx < 0)
- return ifidx;
-
- rtnl_lock();
-
- netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
- if (!netdev) {
- err = -ENODEV;
- goto out_rtnl;
- }
-
- dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
- if (IS_ERR(dev)) {
- err = PTR_ERR(dev);
- goto out_rtnl;
- }
+ err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev);
+ if (err)
+ return err;
if (!dev->ops->dump_mpath) {
err = -EOPNOTSUPP;
@@ -2365,18 +2283,15 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
cb->args[1] = path_idx;
err = skb->len;
out_err:
- cfg80211_unlock_rdev(dev);
- out_rtnl:
- rtnl_unlock();
-
+ nl80211_finish_netdev_dump(dev);
return err;
}
static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
int err;
- struct net_device *dev;
+ struct net_device *dev = info->user_ptr[1];
struct mpath_info pinfo;
struct sk_buff *msg;
u8 *dst = NULL;
@@ -2389,53 +2304,33 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto out_rtnl;
-
- if (!rdev->ops->get_mpath) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!rdev->ops->get_mpath)
+ return -EOPNOTSUPP;
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+ return -EOPNOTSUPP;
err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo);
if (err)
- goto out;
+ return err;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
- goto out;
+ return -ENOMEM;
if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0,
- dev, dst, next_hop, &pinfo) < 0)
- goto out_free;
-
- err = genlmsg_reply(msg, info);
- goto out;
-
- out_free:
- nlmsg_free(msg);
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- out_rtnl:
- rtnl_unlock();
+ dev, dst, next_hop, &pinfo) < 0) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
- return err;
+ return genlmsg_reply(msg, info);
}
static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- int err;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
u8 *dst = NULL;
u8 *next_hop = NULL;
@@ -2448,42 +2343,19 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto out_rtnl;
-
- if (!rdev->ops->change_mpath) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
-
- err = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop);
+ if (!rdev->ops->change_mpath)
+ return -EOPNOTSUPP;
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- out_rtnl:
- rtnl_unlock();
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+ return -EOPNOTSUPP;
- return err;
+ return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop);
}
+
static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- int err;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
u8 *dst = NULL;
u8 *next_hop = NULL;
@@ -2496,75 +2368,34 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto out_rtnl;
-
- if (!rdev->ops->add_mpath) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
-
- err = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop);
+ if (!rdev->ops->add_mpath)
+ return -EOPNOTSUPP;
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- out_rtnl:
- rtnl_unlock();
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+ return -EOPNOTSUPP;
- return err;
+ return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop);
}
static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- int err;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
u8 *dst = NULL;
if (info->attrs[NL80211_ATTR_MAC])
dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto out_rtnl;
-
- if (!rdev->ops->del_mpath) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- err = rdev->ops->del_mpath(&rdev->wiphy, dev, dst);
-
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- out_rtnl:
- rtnl_unlock();
+ if (!rdev->ops->del_mpath)
+ return -EOPNOTSUPP;
- return err;
+ return rdev->ops->del_mpath(&rdev->wiphy, dev, dst);
}
static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- int err;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
struct bss_parameters params;
memset(&params, 0, sizeof(params));
@@ -2592,31 +2423,14 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_AP_ISOLATE])
params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto out_rtnl;
-
- if (!rdev->ops->change_bss) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- err = rdev->ops->change_bss(&rdev->wiphy, dev, &params);
+ if (!rdev->ops->change_bss)
+ return -EOPNOTSUPP;
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- out_rtnl:
- rtnl_unlock();
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
- return err;
+ return rdev->ops->change_bss(&rdev->wiphy, dev, &params);
}
static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
@@ -2695,37 +2509,26 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
static int nl80211_get_mesh_params(struct sk_buff *skb,
struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct mesh_config cur_params;
int err;
- struct net_device *dev;
+ struct net_device *dev = info->user_ptr[1];
void *hdr;
struct nlattr *pinfoattr;
struct sk_buff *msg;
- rtnl_lock();
-
- /* Look up our device */
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto out_rtnl;
-
- if (!rdev->ops->get_mesh_params) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!rdev->ops->get_mesh_params)
+ return -EOPNOTSUPP;
/* Get the mesh params */
err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params);
if (err)
- goto out;
+ return err;
/* Draw up a netlink message to send back */
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (!msg) {
- err = -ENOBUFS;
- goto out;
- }
+ if (!msg)
+ return -ENOMEM;
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
NL80211_CMD_GET_MESH_PARAMS);
if (!hdr)
@@ -2764,21 +2567,12 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
cur_params.dot11MeshHWMPRootMode);
nla_nest_end(msg, pinfoattr);
genlmsg_end(msg, hdr);
- err = genlmsg_reply(msg, info);
- goto out;
+ return genlmsg_reply(msg, info);
nla_put_failure:
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
- err = -EMSGSIZE;
- out:
- /* Cleanup */
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- out_rtnl:
- rtnl_unlock();
-
- return err;
+ return -ENOBUFS;
}
#define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \
@@ -2808,10 +2602,9 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
{
- int err;
u32 mask;
- struct cfg80211_registered_device *rdev;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
struct mesh_config cfg;
struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
struct nlattr *parent_attr;
@@ -2823,16 +2616,8 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
parent_attr, nl80211_meshconf_params_policy))
return -EINVAL;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto out_rtnl;
-
- if (!rdev->ops->set_mesh_params) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!rdev->ops->set_mesh_params)
+ return -EOPNOTSUPP;
/* This makes sure that there aren't more than 32 mesh config
* parameters (otherwise our bitfield scheme would not work.) */
@@ -2878,16 +2663,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
nla_get_u8);
/* Apply changes */
- err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
-
- out:
- /* cleanup */
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- out_rtnl:
- rtnl_unlock();
-
- return err;
+ return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
}
#undef FILL_IN_MESH_PARAM_IF_SET
@@ -3070,8 +2846,8 @@ static int validate_scan_freqs(struct nlattr *freqs)
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
struct cfg80211_scan_request *request;
struct cfg80211_ssid *ssid;
struct ieee80211_channel *channel;
@@ -3084,36 +2860,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
return -EINVAL;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto out_rtnl;
-
wiphy = &rdev->wiphy;
- if (!rdev->ops->scan) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
+ if (!rdev->ops->scan)
+ return -EOPNOTSUPP;
- if (rdev->scan_req) {
- err = -EBUSY;
- goto out;
- }
+ if (rdev->scan_req)
+ return -EBUSY;
if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
n_channels = validate_scan_freqs(
info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
- if (!n_channels) {
- err = -EINVAL;
- goto out;
- }
+ if (!n_channels)
+ return -EINVAL;
} else {
n_channels = 0;
@@ -3126,29 +2885,23 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
n_ssids++;
- if (n_ssids > wiphy->max_scan_ssids) {
- err = -EINVAL;
- goto out;
- }
+ if (n_ssids > wiphy->max_scan_ssids)
+ return -EINVAL;
if (info->attrs[NL80211_ATTR_IE])
ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
else
ie_len = 0;
- if (ie_len > wiphy->max_scan_ie_len) {
- err = -EINVAL;
- goto out;
- }
+ if (ie_len > wiphy->max_scan_ie_len)
+ return -EINVAL;
request = kzalloc(sizeof(*request)
+ sizeof(*ssid) * n_ssids
+ sizeof(channel) * n_channels
+ ie_len, GFP_KERNEL);
- if (!request) {
- err = -ENOMEM;
- goto out;
- }
+ if (!request)
+ return -ENOMEM;
if (n_ssids)
request->ssids = (void *)&request->channels[n_channels];
@@ -3236,18 +2989,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
if (!err) {
nl80211_send_scan_start(rdev, dev);
dev_hold(dev);
- }
-
+ } else {
out_free:
- if (err) {
rdev->scan_req = NULL;
kfree(request);
}
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- out_rtnl:
- rtnl_unlock();
return err;
}
@@ -3306,6 +3052,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
}
switch (wdev->iftype) {
+ case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
if (intbss == wdev->current_bss)
NLA_PUT_U32(msg, NL80211_BSS_STATUS,
@@ -3343,25 +3090,12 @@ static int nl80211_dump_scan(struct sk_buff *skb,
struct net_device *dev;
struct cfg80211_internal_bss *scan;
struct wireless_dev *wdev;
- int ifidx = cb->args[0];
int start = cb->args[1], idx = 0;
int err;
- if (!ifidx)
- ifidx = nl80211_get_ifidx(cb);
- if (ifidx < 0)
- return ifidx;
- cb->args[0] = ifidx;
-
- dev = dev_get_by_index(sock_net(skb->sk), ifidx);
- if (!dev)
- return -ENODEV;
-
- rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
- if (IS_ERR(rdev)) {
- err = PTR_ERR(rdev);
- goto out_put_netdev;
- }
+ err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev);
+ if (err)
+ return err;
wdev = dev->ieee80211_ptr;
@@ -3377,21 +3111,17 @@ static int nl80211_dump_scan(struct sk_buff *skb,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
rdev, wdev, scan) < 0) {
idx--;
- goto out;
+ break;
}
}
- out:
spin_unlock_bh(&rdev->bss_lock);
wdev_unlock(wdev);
cb->args[1] = idx;
- err = skb->len;
- cfg80211_unlock_rdev(rdev);
- out_put_netdev:
- dev_put(dev);
+ nl80211_finish_netdev_dump(rdev);
- return err;
+ return skb->len;
}
static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq,
@@ -3421,6 +3151,23 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq,
if (survey->filled & SURVEY_INFO_NOISE_DBM)
NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE,
survey->noise);
+ if (survey->filled & SURVEY_INFO_IN_USE)
+ NLA_PUT_FLAG(msg, NL80211_SURVEY_INFO_IN_USE);
+ if (survey->filled & SURVEY_INFO_CHANNEL_TIME)
+ NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME,
+ survey->channel_time);
+ if (survey->filled & SURVEY_INFO_CHANNEL_TIME_BUSY)
+ NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
+ survey->channel_time_busy);
+ if (survey->filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY)
+ NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
+ survey->channel_time_ext_busy);
+ if (survey->filled & SURVEY_INFO_CHANNEL_TIME_RX)
+ NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
+ survey->channel_time_rx);
+ if (survey->filled & SURVEY_INFO_CHANNEL_TIME_TX)
+ NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
+ survey->channel_time_tx);
nla_nest_end(msg, infoattr);
@@ -3437,29 +3184,12 @@ static int nl80211_dump_survey(struct sk_buff *skb,
struct survey_info survey;
struct cfg80211_registered_device *dev;
struct net_device *netdev;
- int ifidx = cb->args[0];
int survey_idx = cb->args[1];
int res;
- if (!ifidx)
- ifidx = nl80211_get_ifidx(cb);
- if (ifidx < 0)
- return ifidx;
- cb->args[0] = ifidx;
-
- rtnl_lock();
-
- netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
- if (!netdev) {
- res = -ENODEV;
- goto out_rtnl;
- }
-
- dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
- if (IS_ERR(dev)) {
- res = PTR_ERR(dev);
- goto out_rtnl;
- }
+ res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev);
+ if (res)
+ return res;
if (!dev->ops->dump_survey) {
res = -EOPNOTSUPP;
@@ -3487,10 +3217,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
cb->args[1] = survey_idx;
res = skb->len;
out_err:
- cfg80211_unlock_rdev(dev);
- out_rtnl:
- rtnl_unlock();
-
+ nl80211_finish_netdev_dump(dev);
return res;
}
@@ -3523,8 +3250,8 @@ static bool nl80211_valid_cipher_suite(u32 cipher)
static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
struct ieee80211_channel *chan;
const u8 *bssid, *ssid, *ie = NULL;
int err, ssid_len, ie_len = 0;
@@ -3552,6 +3279,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
return err;
if (key.idx >= 0) {
+ if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP)
+ return -EINVAL;
if (!key.p.key || !key.p.key_len)
return -EINVAL;
if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
@@ -3566,34 +3295,31 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
key.p.key = NULL;
}
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (!rdev->ops->auth) {
- err = -EOPNOTSUPP;
- goto out;
+ if (key.idx >= 0) {
+ int i;
+ bool ok = false;
+ for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) {
+ if (key.p.cipher == rdev->wiphy.cipher_suites[i]) {
+ ok = true;
+ break;
+ }
+ }
+ if (!ok)
+ return -EINVAL;
}
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!rdev->ops->auth)
+ return -EOPNOTSUPP;
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+ return -EOPNOTSUPP;
bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
chan = ieee80211_get_channel(&rdev->wiphy,
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
- if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) {
- err = -EINVAL;
- goto out;
- }
+ if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED))
+ return -EINVAL;
ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
@@ -3604,27 +3330,19 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
}
auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
- if (!nl80211_valid_auth_type(auth_type)) {
- err = -EINVAL;
- goto out;
- }
+ if (!nl80211_valid_auth_type(auth_type))
+ return -EINVAL;
local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
- err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
- ssid, ssid_len, ie, ie_len,
- key.p.key, key.p.key_len, key.idx,
- local_state_change);
-
-out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
-unlock_rtnl:
- rtnl_unlock();
- return err;
+ return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
+ ssid, ssid_len, ie, ie_len,
+ key.p.key, key.p.key_len, key.idx,
+ local_state_change);
}
-static int nl80211_crypto_settings(struct genl_info *info,
+static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
+ struct genl_info *info,
struct cfg80211_crypto_settings *settings,
int cipher_limit)
{
@@ -3632,6 +3350,19 @@ static int nl80211_crypto_settings(struct genl_info *info,
settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
+ if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
+ u16 proto;
+ proto = nla_get_u16(
+ info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
+ settings->control_port_ethertype = cpu_to_be16(proto);
+ if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
+ proto != ETH_P_PAE)
+ return -EINVAL;
+ if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT])
+ settings->control_port_no_encrypt = true;
+ } else
+ settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);
+
if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
void *data;
int len, i;
@@ -3691,8 +3422,8 @@ static int nl80211_crypto_settings(struct genl_info *info,
static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
struct cfg80211_crypto_settings crypto;
struct ieee80211_channel *chan;
const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
@@ -3707,35 +3438,19 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
!info->attrs[NL80211_ATTR_WIPHY_FREQ])
return -EINVAL;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (!rdev->ops->assoc) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!rdev->ops->assoc)
+ return -EOPNOTSUPP;
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+ return -EOPNOTSUPP;
bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
chan = ieee80211_get_channel(&rdev->wiphy,
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
- if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) {
- err = -EINVAL;
- goto out;
- }
+ if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED))
+ return -EINVAL;
ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
@@ -3750,35 +3465,28 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
if (mfp == NL80211_MFP_REQUIRED)
use_mfp = true;
- else if (mfp != NL80211_MFP_NO) {
- err = -EINVAL;
- goto out;
- }
+ else if (mfp != NL80211_MFP_NO)
+ return -EINVAL;
}
if (info->attrs[NL80211_ATTR_PREV_BSSID])
prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
- err = nl80211_crypto_settings(info, &crypto, 1);
+ err = nl80211_crypto_settings(rdev, info, &crypto, 1);
if (!err)
err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
ssid, ssid_len, ie, ie_len, use_mfp,
&crypto);
-out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
-unlock_rtnl:
- rtnl_unlock();
return err;
}
static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
const u8 *ie = NULL, *bssid;
- int err, ie_len = 0;
+ int ie_len = 0;
u16 reason_code;
bool local_state_change;
@@ -3791,34 +3499,19 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
if (!info->attrs[NL80211_ATTR_REASON_CODE])
return -EINVAL;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (!rdev->ops->deauth) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!rdev->ops->deauth)
+ return -EOPNOTSUPP;
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+ return -EOPNOTSUPP;
bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
if (reason_code == 0) {
/* Reason Code 0 is reserved */
- err = -EINVAL;
- goto out;
+ return -EINVAL;
}
if (info->attrs[NL80211_ATTR_IE]) {
@@ -3828,23 +3521,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
- err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
- local_state_change);
-
-out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
-unlock_rtnl:
- rtnl_unlock();
- return err;
+ return cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
+ local_state_change);
}
static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
const u8 *ie = NULL, *bssid;
- int err, ie_len = 0;
+ int ie_len = 0;
u16 reason_code;
bool local_state_change;
@@ -3857,34 +3543,19 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
if (!info->attrs[NL80211_ATTR_REASON_CODE])
return -EINVAL;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (!rdev->ops->disassoc) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!rdev->ops->disassoc)
+ return -EOPNOTSUPP;
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+ return -EOPNOTSUPP;
bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
if (reason_code == 0) {
/* Reason Code 0 is reserved */
- err = -EINVAL;
- goto out;
+ return -EINVAL;
}
if (info->attrs[NL80211_ATTR_IE]) {
@@ -3894,21 +3565,14 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
- err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
- local_state_change);
-
-out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
-unlock_rtnl:
- rtnl_unlock();
- return err;
+ return cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
+ local_state_change);
}
static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
struct cfg80211_ibss_params ibss;
struct wiphy *wiphy;
struct cfg80211_cached_keys *connkeys = NULL;
@@ -3933,26 +3597,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (!rdev->ops->join_ibss) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!rdev->ops->join_ibss)
+ return -EOPNOTSUPP;
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
+ return -EOPNOTSUPP;
wiphy = &rdev->wiphy;
@@ -3970,24 +3619,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
if (!ibss.channel ||
ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
- ibss.channel->flags & IEEE80211_CHAN_DISABLED) {
- err = -EINVAL;
- goto out;
- }
+ ibss.channel->flags & IEEE80211_CHAN_DISABLED)
+ return -EINVAL;
ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
- if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
- connkeys = nl80211_parse_connkeys(rdev,
- info->attrs[NL80211_ATTR_KEYS]);
- if (IS_ERR(connkeys)) {
- err = PTR_ERR(connkeys);
- connkeys = NULL;
- goto out;
- }
- }
-
if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
u8 *rates =
nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
@@ -3997,10 +3634,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
wiphy->bands[ibss.channel->band];
int i, j;
- if (n_rates == 0) {
- err = -EINVAL;
- goto out;
- }
+ if (n_rates == 0)
+ return -EINVAL;
for (i = 0; i < n_rates; i++) {
int rate = (rates[i] & 0x7f) * 5;
@@ -4013,77 +3648,36 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
break;
}
}
- if (!found) {
- err = -EINVAL;
- goto out;
- }
- }
- } else {
- /*
- * If no rates were explicitly configured,
- * use the mandatory rate set for 11b or
- * 11a for maximum compatibility.
- */
- struct ieee80211_supported_band *sband =
- wiphy->bands[ibss.channel->band];
- int j;
- u32 flag = ibss.channel->band == IEEE80211_BAND_5GHZ ?
- IEEE80211_RATE_MANDATORY_A :
- IEEE80211_RATE_MANDATORY_B;
-
- for (j = 0; j < sband->n_bitrates; j++) {
- if (sband->bitrates[j].flags & flag)
- ibss.basic_rates |= BIT(j);
+ if (!found)
+ return -EINVAL;
}
}
- err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
+ if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
+ connkeys = nl80211_parse_connkeys(rdev,
+ info->attrs[NL80211_ATTR_KEYS]);
+ if (IS_ERR(connkeys))
+ return PTR_ERR(connkeys);
+ }
-out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
-unlock_rtnl:
+ err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
if (err)
kfree(connkeys);
- rtnl_unlock();
return err;
}
static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- struct net_device *dev;
- int err;
-
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (!rdev->ops->leave_ibss) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
+ if (!rdev->ops->leave_ibss)
+ return -EOPNOTSUPP;
- err = cfg80211_leave_ibss(rdev, dev, false);
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
+ return -EOPNOTSUPP;
-out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
-unlock_rtnl:
- rtnl_unlock();
- return err;
+ return cfg80211_leave_ibss(rdev, dev, false);
}
#ifdef CONFIG_NL80211_TESTMODE
@@ -4093,20 +3687,12 @@ static struct genl_multicast_group nl80211_testmode_mcgrp = {
static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
int err;
if (!info->attrs[NL80211_ATTR_TESTDATA])
return -EINVAL;
- rtnl_lock();
-
- rdev = cfg80211_get_dev_from_info(info);
- if (IS_ERR(rdev)) {
- err = PTR_ERR(rdev);
- goto unlock_rtnl;
- }
-
err = -EOPNOTSUPP;
if (rdev->ops->testmode_cmd) {
rdev->testmode_info = info;
@@ -4116,10 +3702,6 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
rdev->testmode_info = NULL;
}
- cfg80211_unlock_rdev(rdev);
-
- unlock_rtnl:
- rtnl_unlock();
return err;
}
@@ -4210,8 +3792,8 @@ EXPORT_SYMBOL(cfg80211_testmode_event);
static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
struct cfg80211_connect_params connect;
struct wiphy *wiphy;
struct cfg80211_cached_keys *connkeys = NULL;
@@ -4236,25 +3818,14 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
- err = nl80211_crypto_settings(info, &connect.crypto,
+ err = nl80211_crypto_settings(rdev, info, &connect.crypto,
NL80211_MAX_NR_CIPHER_SUITES);
if (err)
return err;
- rtnl_lock();
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+ return -EOPNOTSUPP;
wiphy = &rdev->wiphy;
@@ -4273,39 +3844,27 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
ieee80211_get_channel(wiphy,
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
if (!connect.channel ||
- connect.channel->flags & IEEE80211_CHAN_DISABLED) {
- err = -EINVAL;
- goto out;
- }
+ connect.channel->flags & IEEE80211_CHAN_DISABLED)
+ return -EINVAL;
}
if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
connkeys = nl80211_parse_connkeys(rdev,
info->attrs[NL80211_ATTR_KEYS]);
- if (IS_ERR(connkeys)) {
- err = PTR_ERR(connkeys);
- connkeys = NULL;
- goto out;
- }
+ if (IS_ERR(connkeys))
+ return PTR_ERR(connkeys);
}
err = cfg80211_connect(rdev, dev, &connect, connkeys);
-
-out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
-unlock_rtnl:
if (err)
kfree(connkeys);
- rtnl_unlock();
return err;
}
static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- struct net_device *dev;
- int err;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
u16 reason;
if (!info->attrs[NL80211_ATTR_REASON_CODE])
@@ -4316,35 +3875,16 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
if (reason == 0)
return -EINVAL;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
-
- err = cfg80211_disconnect(rdev, dev, reason, true);
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+ return -EOPNOTSUPP;
-out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
-unlock_rtnl:
- rtnl_unlock();
- return err;
+ return cfg80211_disconnect(rdev, dev, reason, true);
}
static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net *net;
int err;
u32 pid;
@@ -4354,43 +3894,26 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]);
- rtnl_lock();
-
- rdev = cfg80211_get_dev_from_info(info);
- if (IS_ERR(rdev)) {
- err = PTR_ERR(rdev);
- goto out_rtnl;
- }
-
net = get_net_ns_by_pid(pid);
- if (IS_ERR(net)) {
- err = PTR_ERR(net);
- goto out;
- }
+ if (IS_ERR(net))
+ return PTR_ERR(net);
err = 0;
/* check if anything to do */
- if (net_eq(wiphy_net(&rdev->wiphy), net))
- goto out_put_net;
+ if (!net_eq(wiphy_net(&rdev->wiphy), net))
+ err = cfg80211_switch_netns(rdev, net);
- err = cfg80211_switch_netns(rdev, net);
- out_put_net:
put_net(net);
- out:
- cfg80211_unlock_rdev(rdev);
- out_rtnl:
- rtnl_unlock();
return err;
}
static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_pmksa *pmksa) = NULL;
- int err;
- struct net_device *dev;
+ struct net_device *dev = info->user_ptr[1];
struct cfg80211_pmksa pmksa;
memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
@@ -4401,19 +3924,12 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
if (!info->attrs[NL80211_ATTR_PMKID])
return -EINVAL;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto out_rtnl;
-
pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+ return -EOPNOTSUPP;
switch (info->genlhdr->cmd) {
case NL80211_CMD_SET_PMKSA:
@@ -4427,61 +3943,32 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
break;
}
- if (!rdev_ops) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- err = rdev_ops(&rdev->wiphy, dev, &pmksa);
-
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- out_rtnl:
- rtnl_unlock();
+ if (!rdev_ops)
+ return -EOPNOTSUPP;
- return err;
+ return rdev_ops(&rdev->wiphy, dev, &pmksa);
}
static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- int err;
- struct net_device *dev;
-
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto out_rtnl;
-
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (!rdev->ops->flush_pmksa) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- err = rdev->ops->flush_pmksa(&rdev->wiphy, dev);
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- out_rtnl:
- rtnl_unlock();
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+ return -EOPNOTSUPP;
- return err;
+ if (!rdev->ops->flush_pmksa)
+ return -EOPNOTSUPP;
+ return rdev->ops->flush_pmksa(&rdev->wiphy, dev);
}
static int nl80211_remain_on_channel(struct sk_buff *skb,
struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
struct ieee80211_channel *chan;
struct sk_buff *msg;
void *hdr;
@@ -4503,21 +3990,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
if (!duration || !msecs_to_jiffies(duration) || duration > 5000)
return -EINVAL;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (!rdev->ops->remain_on_channel) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
+ if (!rdev->ops->remain_on_channel)
+ return -EOPNOTSUPP;
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
channel_type = nla_get_u32(
@@ -4525,24 +3999,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
if (channel_type != NL80211_CHAN_NO_HT &&
channel_type != NL80211_CHAN_HT20 &&
channel_type != NL80211_CHAN_HT40PLUS &&
- channel_type != NL80211_CHAN_HT40MINUS) {
- err = -EINVAL;
- goto out;
- }
+ channel_type != NL80211_CHAN_HT40MINUS)
+ return -EINVAL;
}
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
chan = rdev_freq_to_chan(rdev, freq, channel_type);
- if (chan == NULL) {
- err = -EINVAL;
- goto out;
- }
+ if (chan == NULL)
+ return -EINVAL;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (!msg) {
- err = -ENOMEM;
- goto out;
- }
+ if (!msg)
+ return -ENOMEM;
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
NL80211_CMD_REMAIN_ON_CHANNEL);
@@ -4561,58 +4029,32 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
genlmsg_end(msg, hdr);
- err = genlmsg_reply(msg, info);
- goto out;
+
+ return genlmsg_reply(msg, info);
nla_put_failure:
err = -ENOBUFS;
free_msg:
nlmsg_free(msg);
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- unlock_rtnl:
- rtnl_unlock();
return err;
}
static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
u64 cookie;
- int err;
if (!info->attrs[NL80211_ATTR_COOKIE])
return -EINVAL;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (!rdev->ops->cancel_remain_on_channel) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
+ if (!rdev->ops->cancel_remain_on_channel)
+ return -EOPNOTSUPP;
cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
- err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie);
-
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- unlock_rtnl:
- rtnl_unlock();
- return err;
+ return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie);
}
static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
@@ -4648,26 +4090,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
struct genl_info *info)
{
struct nlattr *tb[NL80211_TXRATE_MAX + 1];
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct cfg80211_bitrate_mask mask;
- int err, rem, i;
- struct net_device *dev;
+ int rem, i;
+ struct net_device *dev = info->user_ptr[1];
struct nlattr *tx_rates;
struct ieee80211_supported_band *sband;
if (info->attrs[NL80211_ATTR_TX_RATES] == NULL)
return -EINVAL;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (!rdev->ops->set_bitrate_mask) {
- err = -EOPNOTSUPP;
- goto unlock;
- }
+ if (!rdev->ops->set_bitrate_mask)
+ return -EOPNOTSUPP;
memset(&mask, 0, sizeof(mask));
/* Default to all rates enabled */
@@ -4684,15 +4118,11 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem)
{
enum ieee80211_band band = nla_type(tx_rates);
- if (band < 0 || band >= IEEE80211_NUM_BANDS) {
- err = -EINVAL;
- goto unlock;
- }
+ if (band < 0 || band >= IEEE80211_NUM_BANDS)
+ return -EINVAL;
sband = rdev->wiphy.bands[band];
- if (sband == NULL) {
- err = -EINVAL;
- goto unlock;
- }
+ if (sband == NULL)
+ return -EINVAL;
nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
nla_len(tx_rates), nl80211_txattr_policy);
if (tb[NL80211_TXRATE_LEGACY]) {
@@ -4700,68 +4130,48 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
sband,
nla_data(tb[NL80211_TXRATE_LEGACY]),
nla_len(tb[NL80211_TXRATE_LEGACY]));
- if (mask.control[band].legacy == 0) {
- err = -EINVAL;
- goto unlock;
- }
+ if (mask.control[band].legacy == 0)
+ return -EINVAL;
}
}
- err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask);
-
- unlock:
- dev_put(dev);
- cfg80211_unlock_rdev(rdev);
- unlock_rtnl:
- rtnl_unlock();
- return err;
+ return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask);
}
-static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- struct net_device *dev;
- int err;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
return -EINVAL;
- if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1)
- return -EINVAL;
-
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
+ if (info->attrs[NL80211_ATTR_FRAME_TYPE])
+ frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
- dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
/* not much point in registering if we can't reply */
- if (!rdev->ops->action) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!rdev->ops->mgmt_tx)
+ return -EOPNOTSUPP;
- err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid,
+ return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid,
+ frame_type,
nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- unlock_rtnl:
- rtnl_unlock();
- return err;
}
-static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
- struct net_device *dev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
struct ieee80211_channel *chan;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
bool channel_type_valid = false;
@@ -4775,27 +4185,16 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
!info->attrs[NL80211_ATTR_WIPHY_FREQ])
return -EINVAL;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
- if (!rdev->ops->action) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!rdev->ops->mgmt_tx)
+ return -EOPNOTSUPP;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
- dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
channel_type = nla_get_u32(
@@ -4803,147 +4202,104 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
if (channel_type != NL80211_CHAN_NO_HT &&
channel_type != NL80211_CHAN_HT20 &&
channel_type != NL80211_CHAN_HT40PLUS &&
- channel_type != NL80211_CHAN_HT40MINUS) {
- err = -EINVAL;
- goto out;
- }
+ channel_type != NL80211_CHAN_HT40MINUS)
+ return -EINVAL;
channel_type_valid = true;
}
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
chan = rdev_freq_to_chan(rdev, freq, channel_type);
- if (chan == NULL) {
- err = -EINVAL;
- goto out;
- }
+ if (chan == NULL)
+ return -EINVAL;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (!msg) {
- err = -ENOMEM;
- goto out;
- }
+ if (!msg)
+ return -ENOMEM;
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
- NL80211_CMD_ACTION);
+ NL80211_CMD_FRAME);
if (IS_ERR(hdr)) {
err = PTR_ERR(hdr);
goto free_msg;
}
- err = cfg80211_mlme_action(rdev, dev, chan, channel_type,
- channel_type_valid,
- nla_data(info->attrs[NL80211_ATTR_FRAME]),
- nla_len(info->attrs[NL80211_ATTR_FRAME]),
- &cookie);
+ err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, channel_type,
+ channel_type_valid,
+ nla_data(info->attrs[NL80211_ATTR_FRAME]),
+ nla_len(info->attrs[NL80211_ATTR_FRAME]),
+ &cookie);
if (err)
goto free_msg;
NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
genlmsg_end(msg, hdr);
- err = genlmsg_reply(msg, info);
- goto out;
+ return genlmsg_reply(msg, info);
nla_put_failure:
err = -ENOBUFS;
free_msg:
nlmsg_free(msg);
- out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
-unlock_rtnl:
- rtnl_unlock();
return err;
}
static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct wireless_dev *wdev;
- struct net_device *dev;
+ struct net_device *dev = info->user_ptr[1];
u8 ps_state;
bool state;
int err;
- if (!info->attrs[NL80211_ATTR_PS_STATE]) {
- err = -EINVAL;
- goto out;
- }
+ if (!info->attrs[NL80211_ATTR_PS_STATE])
+ return -EINVAL;
ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
- if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) {
- err = -EINVAL;
- goto out;
- }
-
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rdev;
+ if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED)
+ return -EINVAL;
wdev = dev->ieee80211_ptr;
- if (!rdev->ops->set_power_mgmt) {
- err = -EOPNOTSUPP;
- goto unlock_rdev;
- }
+ if (!rdev->ops->set_power_mgmt)
+ return -EOPNOTSUPP;
state = (ps_state == NL80211_PS_ENABLED) ? true : false;
if (state == wdev->ps)
- goto unlock_rdev;
-
- wdev->ps = state;
-
- if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, wdev->ps,
- wdev->ps_timeout))
- /* assume this means it's off */
- wdev->ps = false;
-
-unlock_rdev:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- rtnl_unlock();
+ return 0;
-out:
+ err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, state,
+ wdev->ps_timeout);
+ if (!err)
+ wdev->ps = state;
return err;
}
static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
enum nl80211_ps_state ps_state;
struct wireless_dev *wdev;
- struct net_device *dev;
+ struct net_device *dev = info->user_ptr[1];
struct sk_buff *msg;
void *hdr;
int err;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rtnl;
-
wdev = dev->ieee80211_ptr;
- if (!rdev->ops->set_power_mgmt) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ if (!rdev->ops->set_power_mgmt)
+ return -EOPNOTSUPP;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (!msg) {
- err = -ENOMEM;
- goto out;
- }
+ if (!msg)
+ return -ENOMEM;
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
NL80211_CMD_GET_POWER_SAVE);
if (!hdr) {
- err = -ENOMEM;
+ err = -ENOBUFS;
goto free_msg;
}
@@ -4955,22 +4311,12 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state);
genlmsg_end(msg, hdr);
- err = genlmsg_reply(msg, info);
- goto out;
+ return genlmsg_reply(msg, info);
-nla_put_failure:
+ nla_put_failure:
err = -ENOBUFS;
-
-free_msg:
+ free_msg:
nlmsg_free(msg);
-
-out:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
-
-unlock_rtnl:
- rtnl_unlock();
-
return err;
}
@@ -4984,41 +4330,24 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = {
static int nl80211_set_cqm_rssi(struct genl_info *info,
s32 threshold, u32 hysteresis)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct wireless_dev *wdev;
- struct net_device *dev;
- int err;
+ struct net_device *dev = info->user_ptr[1];
if (threshold > 0)
return -EINVAL;
- rtnl_lock();
-
- err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
- if (err)
- goto unlock_rdev;
-
wdev = dev->ieee80211_ptr;
- if (!rdev->ops->set_cqm_rssi_config) {
- err = -EOPNOTSUPP;
- goto unlock_rdev;
- }
-
- if (wdev->iftype != NL80211_IFTYPE_STATION) {
- err = -EOPNOTSUPP;
- goto unlock_rdev;
- }
-
- err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev,
- threshold, hysteresis);
+ if (!rdev->ops->set_cqm_rssi_config)
+ return -EOPNOTSUPP;
-unlock_rdev:
- cfg80211_unlock_rdev(rdev);
- dev_put(dev);
- rtnl_unlock();
+ if (wdev->iftype != NL80211_IFTYPE_STATION &&
+ wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
+ return -EOPNOTSUPP;
- return err;
+ return rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev,
+ threshold, hysteresis);
}
static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
@@ -5052,6 +4381,65 @@ out:
return err;
}
+#define NL80211_FLAG_NEED_WIPHY 0x01
+#define NL80211_FLAG_NEED_NETDEV 0x02
+#define NL80211_FLAG_NEED_RTNL 0x04
+#define NL80211_FLAG_CHECK_NETDEV_UP 0x08
+#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\
+ NL80211_FLAG_CHECK_NETDEV_UP)
+
+static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev;
+ struct net_device *dev;
+ int err;
+ bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
+
+ if (rtnl)
+ rtnl_lock();
+
+ if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
+ rdev = cfg80211_get_dev_from_info(info);
+ if (IS_ERR(rdev)) {
+ if (rtnl)
+ rtnl_unlock();
+ return PTR_ERR(rdev);
+ }
+ info->user_ptr[0] = rdev;
+ } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
+ if (err) {
+ if (rtnl)
+ rtnl_unlock();
+ return err;
+ }
+ if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
+ !netif_running(dev)) {
+ cfg80211_unlock_rdev(rdev);
+ dev_put(dev);
+ if (rtnl)
+ rtnl_unlock();
+ return -ENETDOWN;
+ }
+ info->user_ptr[0] = rdev;
+ info->user_ptr[1] = dev;
+ }
+
+ return 0;
+}
+
+static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
+ struct genl_info *info)
+{
+ if (info->user_ptr[0])
+ cfg80211_unlock_rdev(info->user_ptr[0]);
+ if (info->user_ptr[1])
+ dev_put(info->user_ptr[1]);
+ if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
+ rtnl_unlock();
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -5059,12 +4447,14 @@ static struct genl_ops nl80211_ops[] = {
.dumpit = nl80211_dump_wiphy,
.policy = nl80211_policy,
/* can be retrieved by unprivileged users */
+ .internal_flags = NL80211_FLAG_NEED_WIPHY,
},
{
.cmd = NL80211_CMD_SET_WIPHY,
.doit = nl80211_set_wiphy,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_GET_INTERFACE,
@@ -5072,90 +4462,119 @@ static struct genl_ops nl80211_ops[] = {
.dumpit = nl80211_dump_interface,
.policy = nl80211_policy,
/* can be retrieved by unprivileged users */
+ .internal_flags = NL80211_FLAG_NEED_NETDEV,
},
{
.cmd = NL80211_CMD_SET_INTERFACE,
.doit = nl80211_set_interface,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_NEW_INTERFACE,
.doit = nl80211_new_interface,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_WIPHY |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_DEL_INTERFACE,
.doit = nl80211_del_interface,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_GET_KEY,
.doit = nl80211_get_key,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_SET_KEY,
.doit = nl80211_set_key,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_NEW_KEY,
.doit = nl80211_new_key,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_DEL_KEY,
.doit = nl80211_del_key,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_SET_BEACON,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.doit = nl80211_addset_beacon,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_NEW_BEACON,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.doit = nl80211_addset_beacon,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_DEL_BEACON,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.doit = nl80211_del_beacon,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_GET_STATION,
.doit = nl80211_get_station,
.dumpit = nl80211_dump_station,
.policy = nl80211_policy,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_SET_STATION,
.doit = nl80211_set_station,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_NEW_STATION,
.doit = nl80211_new_station,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_DEL_STATION,
.doit = nl80211_del_station,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_GET_MPATH,
@@ -5163,30 +4582,40 @@ static struct genl_ops nl80211_ops[] = {
.dumpit = nl80211_dump_mpath,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_SET_MPATH,
.doit = nl80211_set_mpath,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_NEW_MPATH,
.doit = nl80211_new_mpath,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_DEL_MPATH,
.doit = nl80211_del_mpath,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_SET_BSS,
.doit = nl80211_set_bss,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_GET_REG,
@@ -5211,18 +4640,24 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_get_mesh_params,
.policy = nl80211_policy,
/* can be retrieved by unprivileged users */
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_SET_MESH_PARAMS,
.doit = nl80211_set_mesh_params,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_TRIGGER_SCAN,
.doit = nl80211_trigger_scan,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_GET_SCAN,
@@ -5234,36 +4669,48 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_authenticate,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_ASSOCIATE,
.doit = nl80211_associate,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_DEAUTHENTICATE,
.doit = nl80211_deauthenticate,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_DISASSOCIATE,
.doit = nl80211_disassociate,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_JOIN_IBSS,
.doit = nl80211_join_ibss,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_LEAVE_IBSS,
.doit = nl80211_leave_ibss,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
#ifdef CONFIG_NL80211_TESTMODE
{
@@ -5271,6 +4718,8 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_testmode_do,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_WIPHY |
+ NL80211_FLAG_NEED_RTNL,
},
#endif
{
@@ -5278,18 +4727,24 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_connect,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_DISCONNECT,
.doit = nl80211_disconnect,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_SET_WIPHY_NETNS,
.doit = nl80211_wiphy_netns,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_WIPHY |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_GET_SURVEY,
@@ -5301,72 +4756,104 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_setdel_pmksa,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_DEL_PMKSA,
.doit = nl80211_setdel_pmksa,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_FLUSH_PMKSA,
.doit = nl80211_flush_pmksa,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
.doit = nl80211_remain_on_channel,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
.doit = nl80211_cancel_remain_on_channel,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
.doit = nl80211_set_tx_bitrate_mask,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
- .cmd = NL80211_CMD_REGISTER_ACTION,
- .doit = nl80211_register_action,
+ .cmd = NL80211_CMD_REGISTER_FRAME,
+ .doit = nl80211_register_mgmt,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
- .cmd = NL80211_CMD_ACTION,
- .doit = nl80211_action,
+ .cmd = NL80211_CMD_FRAME,
+ .doit = nl80211_tx_mgmt,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_SET_POWER_SAVE,
.doit = nl80211_set_power_save,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_GET_POWER_SAVE,
.doit = nl80211_get_power_save,
.policy = nl80211_policy,
/* can be retrieved by unprivileged users */
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_SET_CQM,
.doit = nl80211_set_cqm,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_SET_CHANNEL,
.doit = nl80211_set_channel,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL80211_CMD_SET_WDS_PEER,
+ .doit = nl80211_set_wds_peer,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
},
};
@@ -6040,9 +5527,9 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
nl80211_mlme_mcgrp.id, gfp);
}
-int nl80211_send_action(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, u32 nlpid,
- int freq, const u8 *buf, size_t len, gfp_t gfp)
+int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, u32 nlpid,
+ int freq, const u8 *buf, size_t len, gfp_t gfp)
{
struct sk_buff *msg;
void *hdr;
@@ -6052,7 +5539,7 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev,
if (!msg)
return -ENOMEM;
- hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION);
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
if (!hdr) {
nlmsg_free(msg);
return -ENOMEM;
@@ -6080,10 +5567,10 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev,
return -ENOBUFS;
}
-void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, u64 cookie,
- const u8 *buf, size_t len, bool ack,
- gfp_t gfp)
+void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, u64 cookie,
+ const u8 *buf, size_t len, bool ack,
+ gfp_t gfp)
{
struct sk_buff *msg;
void *hdr;
@@ -6092,7 +5579,7 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
if (!msg)
return;
- hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS);
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS);
if (!hdr) {
nlmsg_free(msg);
return;
@@ -6179,7 +5666,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list)
list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
- cfg80211_mlme_unregister_actions(wdev, notify->pid);
+ cfg80211_mlme_unregister_socket(wdev, notify->pid);
rcu_read_unlock();
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 2ad7fbc7d9f1..30d2f939150d 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -74,13 +74,13 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *mac_addr,
struct station_info *sinfo, gfp_t gfp);
-int nl80211_send_action(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, u32 nlpid, int freq,
- const u8 *buf, size_t len, gfp_t gfp);
-void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, u64 cookie,
- const u8 *buf, size_t len, bool ack,
- gfp_t gfp);
+int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, u32 nlpid, int freq,
+ const u8 *buf, size_t len, gfp_t gfp);
+void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, u64 cookie,
+ const u8 *buf, size_t len, bool ack,
+ gfp_t gfp);
void
nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c
index 1332c445d1c7..dbe35e138e94 100644
--- a/net/wireless/radiotap.c
+++ b/net/wireless/radiotap.c
@@ -14,6 +14,7 @@
* See COPYING for more details.
*/
+#include <linux/kernel.h>
#include <net/cfg80211.h>
#include <net/ieee80211_radiotap.h>
#include <asm/unaligned.h>
@@ -45,7 +46,7 @@ static const struct radiotap_align_size rtap_namespace_sizes[] = {
};
static const struct ieee80211_radiotap_namespace radiotap_ns = {
- .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]),
+ .n_bits = ARRAY_SIZE(rtap_namespace_sizes),
.align_size = rtap_namespace_sizes,
};
@@ -200,7 +201,7 @@ int ieee80211_radiotap_iterator_next(
{
while (1) {
int hit = 0;
- int pad, align, size, subns, vnslen;
+ int pad, align, size, subns;
uint32_t oui;
/* if no more EXT bits, that's it */
@@ -260,6 +261,27 @@ int ieee80211_radiotap_iterator_next(
if (pad)
iterator->_arg += align - pad;
+ if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) {
+ int vnslen;
+
+ if ((unsigned long)iterator->_arg + size -
+ (unsigned long)iterator->_rtheader >
+ (unsigned long)iterator->_max_length)
+ return -EINVAL;
+
+ oui = (*iterator->_arg << 16) |
+ (*(iterator->_arg + 1) << 8) |
+ *(iterator->_arg + 2);
+ subns = *(iterator->_arg + 3);
+
+ find_ns(iterator, oui, subns);
+
+ vnslen = get_unaligned_le16(iterator->_arg + 4);
+ iterator->_next_ns_data = iterator->_arg + size + vnslen;
+ if (!iterator->current_namespace)
+ size += vnslen;
+ }
+
/*
* this is what we will return to user, but we need to
* move on first so next call has something fresh to test
@@ -286,40 +308,25 @@ int ieee80211_radiotap_iterator_next(
/* these special ones are valid in each bitmap word */
switch (iterator->_arg_index % 32) {
case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
- iterator->_bitmap_shifter >>= 1;
- iterator->_arg_index++;
-
iterator->_reset_on_ext = 1;
- vnslen = get_unaligned_le16(iterator->this_arg + 4);
- iterator->_next_ns_data = iterator->_arg + vnslen;
- oui = (*iterator->this_arg << 16) |
- (*(iterator->this_arg + 1) << 8) |
- *(iterator->this_arg + 2);
- subns = *(iterator->this_arg + 3);
-
- find_ns(iterator, oui, subns);
-
iterator->is_radiotap_ns = 0;
- /* allow parsers to show this information */
+ /*
+ * If parser didn't register this vendor
+ * namespace with us, allow it to show it
+ * as 'raw. Do do that, set argument index
+ * to vendor namespace.
+ */
iterator->this_arg_index =
IEEE80211_RADIOTAP_VENDOR_NAMESPACE;
- iterator->this_arg_size += vnslen;
- if ((unsigned long)iterator->this_arg +
- iterator->this_arg_size -
- (unsigned long)iterator->_rtheader >
- (unsigned long)(unsigned long)iterator->_max_length)
- return -EINVAL;
- hit = 1;
- break;
+ if (!iterator->current_namespace)
+ hit = 1;
+ goto next_entry;
case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
- iterator->_bitmap_shifter >>= 1;
- iterator->_arg_index++;
-
iterator->_reset_on_ext = 1;
iterator->current_namespace = &radiotap_ns;
iterator->is_radiotap_ns = 1;
- break;
+ goto next_entry;
case IEEE80211_RADIOTAP_EXT:
/*
* bit 31 was set, there is more
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index f180db0de66c..4b9f8912526c 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -36,6 +36,7 @@
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/random.h>
+#include <linux/ctype.h>
#include <linux/nl80211.h>
#include <linux/platform_device.h>
#include <net/cfg80211.h>
@@ -73,7 +74,11 @@ const struct ieee80211_regdomain *cfg80211_regdomain;
* - last_request
*/
static DEFINE_MUTEX(reg_mutex);
-#define assert_reg_lock() WARN_ON(!mutex_is_locked(&reg_mutex))
+
+static inline void assert_reg_lock(void)
+{
+ lockdep_assert_held(&reg_mutex);
+}
/* Used to queue up regulatory hints */
static LIST_HEAD(reg_requests_list);
@@ -181,14 +186,6 @@ static bool is_alpha2_set(const char *alpha2)
return false;
}
-static bool is_alpha_upper(char letter)
-{
- /* ASCII A - Z */
- if (letter >= 65 && letter <= 90)
- return true;
- return false;
-}
-
static bool is_unknown_alpha2(const char *alpha2)
{
if (!alpha2)
@@ -220,7 +217,7 @@ static bool is_an_alpha2(const char *alpha2)
{
if (!alpha2)
return false;
- if (is_alpha_upper(alpha2[0]) && is_alpha_upper(alpha2[1]))
+ if (isalpha(alpha2[0]) && isalpha(alpha2[1]))
return true;
return false;
}
@@ -1170,7 +1167,7 @@ static int ignore_request(struct wiphy *wiphy,
return 0;
return -EALREADY;
}
- return REG_INTERSECT;
+ return 0;
case NL80211_REGDOM_SET_BY_DRIVER:
if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) {
if (regdom_changes(pending_request->alpha2))
@@ -1399,6 +1396,11 @@ static DECLARE_WORK(reg_work, reg_todo);
static void queue_regulatory_request(struct regulatory_request *request)
{
+ if (isalpha(request->alpha2[0]))
+ request->alpha2[0] = toupper(request->alpha2[0]);
+ if (isalpha(request->alpha2[1]))
+ request->alpha2[1] = toupper(request->alpha2[1]);
+
spin_lock(&reg_requests_lock);
list_add_tail(&request->list, &reg_requests_list);
spin_unlock(&reg_requests_lock);
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 5ca8c7180141..503ebb86ba18 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -650,14 +650,14 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
bss = container_of(pub, struct cfg80211_internal_bss, pub);
spin_lock_bh(&dev->bss_lock);
+ if (!list_empty(&bss->list)) {
+ list_del_init(&bss->list);
+ dev->bss_generation++;
+ rb_erase(&bss->rbn, &dev->bss_tree);
- list_del(&bss->list);
- dev->bss_generation++;
- rb_erase(&bss->rbn, &dev->bss_tree);
-
+ kref_put(&bss->ref, bss_release);
+ }
spin_unlock_bh(&dev->bss_lock);
-
- kref_put(&bss->ref, bss_release);
}
EXPORT_SYMBOL(cfg80211_unlink_bss);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index a8c2d6b877ae..e17b0bee6bdc 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -411,7 +411,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
ASSERT_WDEV_LOCK(wdev);
- if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
+ wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
return;
if (wdev->sme_state != CFG80211_SME_CONNECTING)
@@ -548,7 +549,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
ASSERT_WDEV_LOCK(wdev);
- if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
+ wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
return;
if (wdev->sme_state != CFG80211_SME_CONNECTED)
@@ -644,7 +646,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
ASSERT_WDEV_LOCK(wdev);
- if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
+ wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
return;
if (wdev->sme_state != CFG80211_SME_CONNECTED)
@@ -695,7 +698,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
*/
if (rdev->ops->del_key)
for (i = 0; i < 6; i++)
- rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
+ rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL);
#ifdef CONFIG_CFG80211_WEXT
memset(&wrqu, 0, sizeof(wrqu));
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index 9f2cef3e0ca0..4294fa22bb2d 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -35,6 +35,14 @@ SHOW_FMT(index, "%d", wiphy_idx);
SHOW_FMT(macaddress, "%pM", wiphy.perm_addr);
SHOW_FMT(address_mask, "%pM", wiphy.addr_mask);
+static ssize_t name_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf) {
+ struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy;
+ return sprintf(buf, "%s\n", dev_name(&wiphy->dev));
+}
+
+
static ssize_t addresses_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -57,6 +65,7 @@ static struct device_attribute ieee80211_dev_attrs[] = {
__ATTR_RO(macaddress),
__ATTR_RO(address_mask),
__ATTR_RO(addresses),
+ __ATTR_RO(name),
{}
};
@@ -110,6 +119,13 @@ static int wiphy_resume(struct device *dev)
return ret;
}
+static const void *wiphy_namespace(struct device *d)
+{
+ struct wiphy *wiphy = container_of(d, struct wiphy, dev);
+
+ return wiphy_net(wiphy);
+}
+
struct class ieee80211_class = {
.name = "ieee80211",
.owner = THIS_MODULE,
@@ -120,6 +136,8 @@ struct class ieee80211_class = {
#endif
.suspend = wiphy_suspend,
.resume = wiphy_resume,
+ .ns_type = &net_ns_type_operations,
+ .namespace = wiphy_namespace,
};
int wiphy_sysfs_init(void)
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 0c8a1e8b7690..76120aeda57d 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -144,19 +144,25 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
struct key_params *params, int key_idx,
- const u8 *mac_addr)
+ bool pairwise, const u8 *mac_addr)
{
int i;
if (key_idx > 5)
return -EINVAL;
+ if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
+ return -EINVAL;
+
+ if (pairwise && !mac_addr)
+ return -EINVAL;
+
/*
* Disallow pairwise keys with non-zero index unless it's WEP
* (because current deployments use pairwise WEP keys with
* non-zero indizes but 802.11i clearly specifies to use zero)
*/
- if (mac_addr && key_idx &&
+ if (pairwise && key_idx &&
params->cipher != WLAN_CIPHER_SUITE_WEP40 &&
params->cipher != WLAN_CIPHER_SUITE_WEP104)
return -EINVAL;
@@ -183,7 +189,14 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
return -EINVAL;
break;
default:
- return -EINVAL;
+ /*
+ * We don't know anything about this algorithm,
+ * allow using it -- but the driver must check
+ * all parameters! We still check below whether
+ * or not the driver supports this algorithm,
+ * of course.
+ */
+ break;
}
if (params->seq) {
@@ -221,7 +234,7 @@ const unsigned char bridge_tunnel_header[] __aligned(2) =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
EXPORT_SYMBOL(bridge_tunnel_header);
-unsigned int ieee80211_hdrlen(__le16 fc)
+unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc)
{
unsigned int hdrlen = 24;
@@ -319,7 +332,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
case cpu_to_le16(IEEE80211_FCTL_TODS):
if (unlikely(iftype != NL80211_IFTYPE_AP &&
- iftype != NL80211_IFTYPE_AP_VLAN))
+ iftype != NL80211_IFTYPE_AP_VLAN &&
+ iftype != NL80211_IFTYPE_P2P_GO))
return -1;
break;
case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
@@ -347,7 +361,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
break;
case cpu_to_le16(IEEE80211_FCTL_FROMDS):
if ((iftype != NL80211_IFTYPE_STATION &&
- iftype != NL80211_IFTYPE_MESH_POINT) ||
+ iftype != NL80211_IFTYPE_P2P_CLIENT &&
+ iftype != NL80211_IFTYPE_MESH_POINT) ||
(is_multicast_ether_addr(dst) &&
!compare_ether_addr(src, addr)))
return -1;
@@ -424,6 +439,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
switch (iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_P2P_GO:
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
/* DA BSSID SA */
memcpy(hdr.addr1, skb->data, ETH_ALEN);
@@ -432,6 +448,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
hdrlen = 24;
break;
case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
/* BSSID SA DA */
memcpy(hdr.addr1, bssid, ETH_ALEN);
@@ -666,7 +683,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
for (i = 0; i < 6; i++) {
if (!wdev->connect_keys->params[i].cipher)
continue;
- if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL,
+ if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL,
&wdev->connect_keys->params[i])) {
printk(KERN_ERR "%s: failed to set key %d\n",
dev->name, i);
@@ -771,7 +788,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
/* if it's part of a bridge, reject changing type to station/ibss */
if ((dev->priv_flags & IFF_BRIDGE_PORT) &&
- (ntype == NL80211_IFTYPE_ADHOC || ntype == NL80211_IFTYPE_STATION))
+ (ntype == NL80211_IFTYPE_ADHOC ||
+ ntype == NL80211_IFTYPE_STATION ||
+ ntype == NL80211_IFTYPE_P2P_CLIENT))
return -EBUSY;
if (ntype != otype) {
@@ -782,6 +801,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
cfg80211_leave_ibss(rdev, dev, false);
break;
case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
cfg80211_disconnect(rdev, dev,
WLAN_REASON_DEAUTH_LEAVING, true);
break;
@@ -810,9 +830,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
if (dev->ieee80211_ptr->use_4addr)
break;
/* fall through */
+ case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_ADHOC:
dev->priv_flags |= IFF_DONT_BRIDGE;
break;
+ case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_WDS:
@@ -823,7 +845,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
/* monitor can't bridge anyway */
break;
case NL80211_IFTYPE_UNSPECIFIED:
- case __NL80211_IFTYPE_AFTER_LAST:
+ case NUM_NL80211_IFTYPES:
/* not happening */
break;
}
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 7e5c3a45f811..12222ee6ebf2 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -432,14 +432,17 @@ int cfg80211_wext_giwretry(struct net_device *dev,
EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
- struct net_device *dev, const u8 *addr,
- bool remove, bool tx_key, int idx,
- struct key_params *params)
+ struct net_device *dev, bool pairwise,
+ const u8 *addr, bool remove, bool tx_key,
+ int idx, struct key_params *params)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
int err, i;
bool rejoin = false;
+ if (pairwise && !addr)
+ return -EINVAL;
+
if (!wdev->wext.keys) {
wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
GFP_KERNEL);
@@ -478,7 +481,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
__cfg80211_leave_ibss(rdev, wdev->netdev, true);
rejoin = true;
}
- err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
+
+ if (!pairwise && addr &&
+ !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
+ err = -ENOENT;
+ else
+ err = rdev->ops->del_key(&rdev->wiphy, dev, idx,
+ pairwise, addr);
}
wdev->wext.connect.privacy = false;
/*
@@ -507,12 +516,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
if (addr)
tx_key = false;
- if (cfg80211_validate_key_settings(rdev, params, idx, addr))
+ if (cfg80211_validate_key_settings(rdev, params, idx, pairwise, addr))
return -EINVAL;
err = 0;
if (wdev->current_bss)
- err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params);
+ err = rdev->ops->add_key(&rdev->wiphy, dev, idx,
+ pairwise, addr, params);
if (err)
return err;
@@ -563,17 +573,17 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
}
static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
- struct net_device *dev, const u8 *addr,
- bool remove, bool tx_key, int idx,
- struct key_params *params)
+ struct net_device *dev, bool pairwise,
+ const u8 *addr, bool remove, bool tx_key,
+ int idx, struct key_params *params)
{
int err;
/* devlist mutex needed for possible IBSS re-join */
mutex_lock(&rdev->devlist_mtx);
wdev_lock(dev->ieee80211_ptr);
- err = __cfg80211_set_encryption(rdev, dev, addr, remove,
- tx_key, idx, params);
+ err = __cfg80211_set_encryption(rdev, dev, pairwise, addr,
+ remove, tx_key, idx, params);
wdev_unlock(dev->ieee80211_ptr);
mutex_unlock(&rdev->devlist_mtx);
@@ -635,7 +645,7 @@ int cfg80211_wext_siwencode(struct net_device *dev,
else if (!remove)
return -EINVAL;
- return cfg80211_set_encryption(rdev, dev, NULL, remove,
+ return cfg80211_set_encryption(rdev, dev, false, NULL, remove,
wdev->wext.default_key == -1,
idx, &params);
}
@@ -725,7 +735,9 @@ int cfg80211_wext_siwencodeext(struct net_device *dev,
}
return cfg80211_set_encryption(
- rdev, dev, addr, remove,
+ rdev, dev,
+ !(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY),
+ addr, remove,
ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
idx, &params);
}
@@ -1354,6 +1366,10 @@ struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
}
wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
+ if (sinfo.filled & STATION_INFO_RX_DROP_MISC)
+ wstats.discard.misc = sinfo.rx_dropped_misc;
+ if (sinfo.filled & STATION_INFO_TX_FAILED)
+ wstats.discard.retries = sinfo.tx_failed;
return &wstats;
}
diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c
index 8f5116f5af19..dc675a3daa3d 100644
--- a/net/wireless/wext-core.c
+++ b/net/wireless/wext-core.c
@@ -611,7 +611,7 @@ struct iw_statistics *get_wireless_stats(struct net_device *dev)
#endif
#ifdef CONFIG_CFG80211_WEXT
- if (dev->ieee80211_ptr && dev->ieee80211_ptr &&
+ if (dev->ieee80211_ptr &&
dev->ieee80211_ptr->wiphy &&
dev->ieee80211_ptr->wiphy->wext &&
dev->ieee80211_ptr->wiphy->wext->get_wireless_stats)
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index 9818198add8a..6fffe62d7c25 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -197,6 +197,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
wdev->wext.connect.ssid_len = len;
wdev->wext.connect.crypto.control_port = false;
+ wdev->wext.connect.crypto.control_port_ethertype =
+ cpu_to_be16(ETH_P_PAE);
err = cfg80211_mgd_wext_connect(rdev, wdev);
out:
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 5e86d4e97dce..f7af98dff409 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -507,14 +507,14 @@ static int x25_listen(struct socket *sock, int backlog)
struct sock *sk = sock->sk;
int rc = -EOPNOTSUPP;
- lock_kernel();
+ lock_sock(sk);
if (sk->sk_state != TCP_LISTEN) {
memset(&x25_sk(sk)->dest_addr, 0, X25_ADDR_LEN);
sk->sk_max_ack_backlog = backlog;
sk->sk_state = TCP_LISTEN;
rc = 0;
}
- unlock_kernel();
+ release_sock(sk);
return rc;
}
@@ -688,7 +688,6 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
int len, i, rc = 0;
- lock_kernel();
if (!sock_flag(sk, SOCK_ZAPPED) ||
addr_len != sizeof(struct sockaddr_x25) ||
addr->sx25_family != AF_X25) {
@@ -704,12 +703,13 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
}
}
+ lock_sock(sk);
x25_sk(sk)->source_addr = addr->sx25_addr;
x25_insert_socket(sk);
sock_reset_flag(sk, SOCK_ZAPPED);
+ release_sock(sk);
SOCK_DEBUG(sk, "x25_bind: socket is bound\n");
out:
- unlock_kernel();
return rc;
}
@@ -751,7 +751,6 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr,
struct x25_route *rt;
int rc = 0;
- lock_kernel();
lock_sock(sk);
if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
sock->state = SS_CONNECTED;
@@ -829,7 +828,6 @@ out_put_route:
x25_route_put(rt);
out:
release_sock(sk);
- unlock_kernel();
return rc;
}
@@ -869,8 +867,7 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
struct sk_buff *skb;
int rc = -EINVAL;
- lock_kernel();
- if (!sk || sk->sk_state != TCP_LISTEN)
+ if (!sk)
goto out;
rc = -EOPNOTSUPP;
@@ -878,6 +875,10 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
goto out;
lock_sock(sk);
+ rc = -EINVAL;
+ if (sk->sk_state != TCP_LISTEN)
+ goto out2;
+
rc = x25_wait_for_data(sk, sk->sk_rcvtimeo);
if (rc)
goto out2;
@@ -897,7 +898,6 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
out2:
release_sock(sk);
out:
- unlock_kernel();
return rc;
}
@@ -909,7 +909,6 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr,
struct x25_sock *x25 = x25_sk(sk);
int rc = 0;
- lock_kernel();
if (peer) {
if (sk->sk_state != TCP_ESTABLISHED) {
rc = -ENOTCONN;
@@ -923,19 +922,6 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr,
*uaddr_len = sizeof(*sx25);
out:
- unlock_kernel();
- return rc;
-}
-
-static unsigned int x25_datagram_poll(struct file *file, struct socket *sock,
- poll_table *wait)
-{
- int rc;
-
- lock_kernel();
- rc = datagram_poll(file, sock, wait);
- unlock_kernel();
-
return rc;
}
@@ -1746,7 +1732,7 @@ static const struct proto_ops x25_proto_ops = {
.socketpair = sock_no_socketpair,
.accept = x25_accept,
.getname = x25_getname,
- .poll = x25_datagram_poll,
+ .poll = datagram_poll,
.ioctl = x25_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = compat_x25_ioctl,
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index cbab6e1a8c9c..044e77898512 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -50,6 +50,9 @@ static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
static void xfrm_init_pmtu(struct dst_entry *dst);
static int stale_bundle(struct dst_entry *dst);
+static int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst,
+ struct flowi *fl, int family, int strict);
+
static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
int dir);
@@ -2276,7 +2279,7 @@ static void xfrm_init_pmtu(struct dst_entry *dst)
* still valid.
*/
-int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
+static int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
struct flowi *fl, int family, int strict)
{
struct dst_entry *dst = &first->u.dst;
@@ -2358,8 +2361,6 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
return 1;
}
-EXPORT_SYMBOL(xfrm_bundle_ok);
-
int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
{
struct net *net;
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 2039acdf5122..90b54d4697fd 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2,7 +2,7 @@
# (c) 2001, Dave Jones. (the file handling bit)
# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)
# (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite)
-# (c) 2008,2009, Andy Whitcroft <apw@canonical.com>
+# (c) 2008-2010 Andy Whitcroft <apw@canonical.com>
# Licensed under the terms of the GNU GPL License version 2
use strict;
@@ -10,7 +10,7 @@ use strict;
my $P = $0;
$P =~ s@.*/@@g;
-my $V = '0.30';
+my $V = '0.31';
use Getopt::Long qw(:config no_auto_abbrev);
@@ -103,6 +103,8 @@ for my $key (keys %debug) {
die "$@" if ($@);
}
+my $rpt_cleaners = 0;
+
if ($terse) {
$emacs = 1;
$quiet++;
@@ -150,6 +152,20 @@ our $Sparse = qr{
# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check
our $Attribute = qr{
const|
+ __percpu|
+ __nocast|
+ __safe|
+ __bitwise__|
+ __packed__|
+ __packed2__|
+ __naked|
+ __maybe_unused|
+ __always_unused|
+ __noreturn|
+ __used|
+ __cold|
+ __noclone|
+ __deprecated|
__read_mostly|
__kprobes|
__(?:mem|cpu|dev|)(?:initdata|initconst|init\b)|
@@ -675,15 +691,15 @@ sub ctx_block_get {
$blk .= $rawlines[$line];
# Handle nested #if/#else.
- if ($rawlines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) {
+ if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) {
push(@stack, $level);
- } elsif ($rawlines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) {
+ } elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) {
$level = $stack[$#stack - 1];
- } elsif ($rawlines[$line] =~ /^.\s*#\s*endif\b/) {
+ } elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) {
$level = pop(@stack);
}
- foreach my $c (split(//, $rawlines[$line])) {
+ foreach my $c (split(//, $lines[$line])) {
##print "C<$c>L<$level><$open$close>O<$off>\n";
if ($off > 0) {
$off--;
@@ -843,7 +859,12 @@ sub annotate_values {
$av_preprocessor = 0;
}
- } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\()/) {
+ } elsif ($cur =~ /^(\(\s*$Type\s*)\)/) {
+ print "CAST($1)\n" if ($dbg_values > 1);
+ push(@av_paren_type, $type);
+ $type = 'C';
+
+ } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) {
print "DECLARE($1)\n" if ($dbg_values > 1);
$type = 'T';
@@ -1308,7 +1329,11 @@ sub process {
$here = "#$realline: " if ($file);
# extract the filename as it passes
- if ($line=~/^\+\+\+\s+(\S+)/) {
+ if ($line =~ /^diff --git.*?(\S+)$/) {
+ $realfile = $1;
+ $realfile =~ s@^([^/]*)/@@;
+
+ } elsif ($line =~ /^\+\+\+\s+(\S+)/) {
$realfile = $1;
$realfile =~ s@^([^/]*)/@@;
@@ -1332,6 +1357,14 @@ sub process {
$cnt_lines++ if ($realcnt != 0);
+# Check for incorrect file permissions
+ if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) {
+ my $permhere = $here . "FILE: $realfile\n";
+ if ($realfile =~ /(Makefile|Kconfig|\.c|\.h|\.S|\.tmpl)$/) {
+ ERROR("do not set execute permissions for source files\n" . $permhere);
+ }
+ }
+
#check the patch for a signoff:
if ($line =~ /^\s*signed-off-by:/i) {
# This is a signoff, if ugly, so do not double report.
@@ -1389,21 +1422,38 @@ sub process {
} elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) {
my $herevet = "$here\n" . cat_vet($rawline) . "\n";
ERROR("trailing whitespace\n" . $herevet);
+ $rpt_cleaners = 1;
}
# check for Kconfig help text having a real description
+# Only applies when adding the entry originally, after that we do not have
+# sufficient context to determine whether it is indeed long enough.
if ($realfile =~ /Kconfig/ &&
- $line =~ /\+?\s*(---)?help(---)?$/) {
+ $line =~ /\+\s*(?:---)?help(?:---)?$/) {
my $length = 0;
- for (my $l = $linenr; defined($lines[$l]); $l++) {
- my $f = $lines[$l];
+ my $cnt = $realcnt;
+ my $ln = $linenr + 1;
+ my $f;
+ my $is_end = 0;
+ while ($cnt > 0 && defined $lines[$ln - 1]) {
+ $f = $lines[$ln - 1];
+ $cnt-- if ($lines[$ln - 1] !~ /^-/);
+ $is_end = $lines[$ln - 1] =~ /^\+/;
+ $ln++;
+
+ next if ($f =~ /^-/);
+ $f =~ s/^.//;
$f =~ s/#.*//;
$f =~ s/^\s+//;
next if ($f =~ /^$/);
- last if ($f =~ /^\s*config\s/);
+ if ($f =~ /^\s*config\s/) {
+ $is_end = 1;
+ last;
+ }
$length++;
}
- WARN("please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($length < 4);
+ WARN("please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($is_end && $length < 4);
+ #print "is_end<$is_end> length<$length>\n";
}
# check we are in a valid source file if not then ignore this hunk
@@ -1450,6 +1500,7 @@ sub process {
$rawline =~ /^\+\s* \s*/) {
my $herevet = "$here\n" . cat_vet($rawline) . "\n";
ERROR("code indent should use tabs where possible\n" . $herevet);
+ $rpt_cleaners = 1;
}
# check for space before tabs.
@@ -1459,10 +1510,13 @@ sub process {
}
# check for spaces at the beginning of a line.
- if ($rawline =~ /^\+ / && $rawline !~ /\+ +\*/) {
+# Exceptions:
+# 1) within comments
+# 2) indented preprocessor commands
+# 3) hanging labels
+ if ($rawline =~ /^\+ / && $line !~ /\+ *(?:$;|#|$Ident:)/) {
my $herevet = "$here\n" . cat_vet($rawline) . "\n";
- WARN("please, no space for starting a line, \
- excluding comments\n" . $herevet);
+ WARN("please, no spaces at the start of a line\n" . $herevet);
}
# check we are in a valid C source file if not then ignore this hunk
@@ -1598,7 +1652,7 @@ sub process {
if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
ERROR("that open brace { should be on the previous line\n" .
- "$here\n$ctx\n$lines[$ctx_ln - 1]\n");
+ "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n");
}
if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ &&
$ctx =~ /\)\s*\;\s*$/ &&
@@ -1607,7 +1661,7 @@ sub process {
my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]);
if ($nindent > $indent) {
WARN("trailing semicolon indicates no statements, indent implies otherwise\n" .
- "$here\n$ctx\n$lines[$ctx_ln - 1]\n");
+ "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n");
}
}
}
@@ -1768,8 +1822,17 @@ sub process {
!defined $suppress_export{$realline_next} &&
($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
$lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
+ # Handle definitions which produce identifiers with
+ # a prefix:
+ # XXX(foo);
+ # EXPORT_SYMBOL(something_foo);
my $name = $1;
- if ($stat !~ /(?:
+ if ($stat =~ /^.([A-Z_]+)\s*\(\s*($Ident)/ &&
+ $name =~ /^${Ident}_$2/) {
+#print "FOO C name<$name>\n";
+ $suppress_export{$realline_next} = 1;
+
+ } elsif ($stat !~ /(?:
\n.}\s*$|
^.DEFINE_$Ident\(\Q$name\E\)|
^.DECLARE_$Ident\(\Q$name\E\)|
@@ -1806,6 +1869,23 @@ sub process {
$herecurr);
}
+# check for static const char * arrays.
+ if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) {
+ WARN("static const char * array should probably be static const char * const\n" .
+ $herecurr);
+ }
+
+# check for static char foo[] = "bar" declarations.
+ if ($line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/) {
+ WARN("static char array declaration should probably be static const char\n" .
+ $herecurr);
+ }
+
+# check for declarations of struct pci_device_id
+ if ($line =~ /\bstruct\s+pci_device_id\s+\w+\s*\[\s*\]\s*\=\s*\{/) {
+ WARN("Use DEFINE_PCI_DEVICE_TABLE for struct pci_device_id\n" . $herecurr);
+ }
+
# check for new typedefs, only function parameters and sparse annotations
# make sense.
if ($line =~ /\btypedef\s/ &&
@@ -1899,6 +1979,11 @@ sub process {
ERROR("open brace '{' following $1 go on the same line\n" . $hereprev);
}
+# missing space after union, struct or enum definition
+ if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) {
+ WARN("missing space after $1 definition\n" . $herecurr);
+ }
+
# check for spacing round square brackets; allowed:
# 1. with a type on the left -- int [] a;
# 2. at the beginning of a line for slice initialisers -- [0...10] = 5,
@@ -2176,21 +2261,29 @@ sub process {
my $value = $2;
# Flatten any parentheses
- $value =~ s/\)\(/\) \(/g;
+ $value =~ s/\(/ \(/g;
+ $value =~ s/\)/\) /g;
while ($value =~ s/\[[^\{\}]*\]/1/ ||
$value !~ /(?:$Ident|-?$Constant)\s*
$Compare\s*
(?:$Ident|-?$Constant)/x &&
$value =~ s/\([^\(\)]*\)/1/) {
}
-
- if ($value =~ /^(?:$Ident|-?$Constant)$/) {
+#print "value<$value>\n";
+ if ($value =~ /^\s*(?:$Ident|-?$Constant)\s*$/) {
ERROR("return is not a function, parentheses are not required\n" . $herecurr);
} elsif ($spacing !~ /\s+/) {
ERROR("space required before the open parenthesis '('\n" . $herecurr);
}
}
+# Return of what appears to be an errno should normally be -'ve
+ if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) {
+ my $name = $1;
+ if ($name ne 'EOF' && $name ne 'ERROR') {
+ WARN("return of an errno should typically be -ve (return -$1)\n" . $herecurr);
+ }
+ }
# Need a space before open parenthesis after if, while etc
if ($line=~/\b(if|while|for|switch)\(/) {
@@ -2409,8 +2502,8 @@ sub process {
\.$Ident\s*=\s*|
^\"|\"$
}x;
- #print "REST<$rest> dstat<$dstat>\n";
- if ($rest ne '') {
+ #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
+ if ($rest ne '' && $rest ne ',') {
if ($rest !~ /while\s*\(/ &&
$dstat !~ /$exceptions/)
{
@@ -2839,6 +2932,15 @@ sub process {
print "\n" if ($quiet == 0);
}
+ if ($quiet == 0) {
+ # If there were whitespace errors which cleanpatch can fix
+ # then suggest that.
+ if ($rpt_cleaners) {
+ print "NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or\n";
+ print " scripts/cleanfile\n\n";
+ }
+ }
+
if ($clean == 1 && $quiet == 0) {
print "$vname has no obvious style problems and is ready for submission.\n"
}
diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
index b2281982f52f..d21ec3a89603 100755
--- a/scripts/get_maintainer.pl
+++ b/scripts/get_maintainer.pl
@@ -13,7 +13,7 @@
use strict;
my $P = $0;
-my $V = '0.24';
+my $V = '0.26-beta6';
use Getopt::Long qw(:config no_auto_abbrev);
@@ -24,15 +24,19 @@ my $email_maintainer = 1;
my $email_list = 1;
my $email_subscriber_list = 0;
my $email_git_penguin_chiefs = 0;
-my $email_git = 1;
+my $email_git = 0;
my $email_git_all_signature_types = 0;
my $email_git_blame = 0;
+my $email_git_blame_signatures = 1;
+my $email_git_fallback = 1;
my $email_git_min_signatures = 1;
my $email_git_max_maintainers = 5;
my $email_git_min_percent = 5;
my $email_git_since = "1-year-ago";
my $email_hg_since = "-365";
+my $interactive = 0;
my $email_remove_duplicates = 1;
+my $email_use_mailmap = 1;
my $output_multiline = 1;
my $output_separator = ", ";
my $output_roles = 0;
@@ -49,8 +53,13 @@ my $pattern_depth = 0;
my $version = 0;
my $help = 0;
+my $vcs_used = 0;
+
my $exit = 0;
+my %commit_author_hash;
+my %commit_signer_hash;
+
my @penguin_chief = ();
push(@penguin_chief, "Linus Torvalds:torvalds\@linux-foundation.org");
#Andrew wants in on most everything - 2009/01/14
@@ -73,7 +82,6 @@ my @signature_tags = ();
push(@signature_tags, "Signed-off-by:");
push(@signature_tags, "Reviewed-by:");
push(@signature_tags, "Acked-by:");
-my $signaturePattern = "\(" . join("|", @signature_tags) . "\)";
# rfc822 email address - preloaded methods go here.
my $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])";
@@ -86,31 +94,70 @@ my %VCS_cmds;
my %VCS_cmds_git = (
"execute_cmd" => \&git_execute_cmd,
"available" => '(which("git") ne "") && (-d ".git")',
- "find_signers_cmd" => "git log --no-color --since=\$email_git_since -- \$file",
- "find_commit_signers_cmd" => "git log --no-color -1 \$commit",
+ "find_signers_cmd" =>
+ "git log --no-color --since=\$email_git_since " .
+ '--format="GitCommit: %H%n' .
+ 'GitAuthor: %an <%ae>%n' .
+ 'GitDate: %aD%n' .
+ 'GitSubject: %s%n' .
+ '%b%n"' .
+ " -- \$file",
+ "find_commit_signers_cmd" =>
+ "git log --no-color " .
+ '--format="GitCommit: %H%n' .
+ 'GitAuthor: %an <%ae>%n' .
+ 'GitDate: %aD%n' .
+ 'GitSubject: %s%n' .
+ '%b%n"' .
+ " -1 \$commit",
+ "find_commit_author_cmd" =>
+ "git log --no-color " .
+ '--format="GitCommit: %H%n' .
+ 'GitAuthor: %an <%ae>%n' .
+ 'GitDate: %aD%n' .
+ 'GitSubject: %s%n"' .
+ " -1 \$commit",
"blame_range_cmd" => "git blame -l -L \$diff_start,+\$diff_length \$file",
"blame_file_cmd" => "git blame -l \$file",
- "commit_pattern" => "^commit [0-9a-f]{40,40}",
- "blame_commit_pattern" => "^([0-9a-f]+) "
+ "commit_pattern" => "^GitCommit: ([0-9a-f]{40,40})",
+ "blame_commit_pattern" => "^([0-9a-f]+) ",
+ "author_pattern" => "^GitAuthor: (.*)",
+ "subject_pattern" => "^GitSubject: (.*)",
);
my %VCS_cmds_hg = (
"execute_cmd" => \&hg_execute_cmd,
"available" => '(which("hg") ne "") && (-d ".hg")',
"find_signers_cmd" =>
- "hg log --date=\$email_hg_since" .
- " --template='commit {node}\\n{desc}\\n' -- \$file",
- "find_commit_signers_cmd" => "hg log --template='{desc}\\n' -r \$commit",
+ "hg log --date=\$email_hg_since " .
+ "--template='HgCommit: {node}\\n" .
+ "HgAuthor: {author}\\n" .
+ "HgSubject: {desc}\\n'" .
+ " -- \$file",
+ "find_commit_signers_cmd" =>
+ "hg log " .
+ "--template='HgSubject: {desc}\\n'" .
+ " -r \$commit",
+ "find_commit_author_cmd" =>
+ "hg log " .
+ "--template='HgCommit: {node}\\n" .
+ "HgAuthor: {author}\\n" .
+ "HgSubject: {desc|firstline}\\n'" .
+ " -r \$commit",
"blame_range_cmd" => "", # not supported
- "blame_file_cmd" => "hg blame -c \$file",
- "commit_pattern" => "^commit [0-9a-f]{40,40}",
- "blame_commit_pattern" => "^([0-9a-f]+):"
+ "blame_file_cmd" => "hg blame -n \$file",
+ "commit_pattern" => "^HgCommit: ([0-9a-f]{40,40})",
+ "blame_commit_pattern" => "^([ 0-9a-f]+):",
+ "author_pattern" => "^HgAuthor: (.*)",
+ "subject_pattern" => "^HgSubject: (.*)",
);
-if (-f "${lk_path}.get_maintainer.conf") {
+my $conf = which_conf(".get_maintainer.conf");
+if (-f $conf) {
my @conf_args;
- open(my $conffile, '<', "${lk_path}.get_maintainer.conf")
- or warn "$P: Can't open .get_maintainer.conf: $!\n";
+ open(my $conffile, '<', "$conf")
+ or warn "$P: Can't find a readable .get_maintainer.conf file $!\n";
+
while (<$conffile>) {
my $line = $_;
@@ -136,13 +183,17 @@ if (!GetOptions(
'git!' => \$email_git,
'git-all-signature-types!' => \$email_git_all_signature_types,
'git-blame!' => \$email_git_blame,
+ 'git-blame-signatures!' => \$email_git_blame_signatures,
+ 'git-fallback!' => \$email_git_fallback,
'git-chief-penguins!' => \$email_git_penguin_chiefs,
'git-min-signatures=i' => \$email_git_min_signatures,
'git-max-maintainers=i' => \$email_git_max_maintainers,
'git-min-percent=i' => \$email_git_min_percent,
'git-since=s' => \$email_git_since,
'hg-since=s' => \$email_hg_since,
+ 'i|interactive!' => \$interactive,
'remove-duplicates!' => \$email_remove_duplicates,
+ 'mailmap!' => \$email_use_mailmap,
'm!' => \$email_maintainer,
'n!' => \$email_usename,
'l!' => \$email_list,
@@ -181,13 +232,9 @@ if (-t STDIN && !@ARGV) {
die "$P: missing patchfile or -f file - use --help if necessary\n";
}
-if ($output_separator ne ", ") {
- $output_multiline = 0;
-}
-
-if ($output_rolestats) {
- $output_roles = 1;
-}
+$output_multiline = 0 if ($output_separator ne ", ");
+$output_rolestats = 1 if ($interactive);
+$output_roles = 1 if ($output_rolestats);
if ($sections) {
$email = 0;
@@ -197,6 +244,7 @@ if ($sections) {
$subsystem = 0;
$web = 0;
$keywords = 0;
+ $interactive = 0;
} else {
my $selections = $email + $scm + $status + $subsystem + $web;
if ($selections == 0) {
@@ -215,10 +263,6 @@ if (!top_of_kernel_tree($lk_path)) {
. "a linux kernel source tree.\n";
}
-if ($email_git_all_signature_types) {
- $signaturePattern = "(.+?)[Bb][Yy]:";
-}
-
## Read MAINTAINERS for type/value pairs
my @typevalue = ();
@@ -253,31 +297,82 @@ while (<$maint>) {
}
close($maint);
-my %mailmap;
-if ($email_remove_duplicates) {
- open(my $mailmap, '<', "${lk_path}.mailmap")
- or warn "$P: Can't open .mailmap: $!\n";
- while (<$mailmap>) {
- my $line = $_;
+#
+# Read mail address map
+#
- next if ($line =~ m/^\s*#/);
- next if ($line =~ m/^\s*$/);
+my $mailmap;
- my ($name, $address) = parse_email($line);
- $line = format_email($name, $address, $email_usename);
+read_mailmap();
- next if ($line =~ m/^\s*$/);
+sub read_mailmap {
+ $mailmap = {
+ names => {},
+ addresses => {}
+ };
- if (exists($mailmap{$name})) {
- my $obj = $mailmap{$name};
- push(@$obj, $address);
- } else {
- my @arr = ($address);
- $mailmap{$name} = \@arr;
+ return if (!$email_use_mailmap || !(-f "${lk_path}.mailmap"));
+
+ open(my $mailmap_file, '<', "${lk_path}.mailmap")
+ or warn "$P: Can't open .mailmap: $!\n";
+
+ while (<$mailmap_file>) {
+ s/#.*$//; #strip comments
+ s/^\s+|\s+$//g; #trim
+
+ next if (/^\s*$/); #skip empty lines
+ #entries have one of the following formats:
+ # name1 <mail1>
+ # <mail1> <mail2>
+ # name1 <mail1> <mail2>
+ # name1 <mail1> name2 <mail2>
+ # (see man git-shortlog)
+ if (/^(.+)<(.+)>$/) {
+ my $real_name = $1;
+ my $address = $2;
+
+ $real_name =~ s/\s+$//;
+ ($real_name, $address) = parse_email("$real_name <$address>");
+ $mailmap->{names}->{$address} = $real_name;
+
+ } elsif (/^<([^\s]+)>\s*<([^\s]+)>$/) {
+ my $real_address = $1;
+ my $wrong_address = $2;
+
+ $mailmap->{addresses}->{$wrong_address} = $real_address;
+
+ } elsif (/^(.+)<([^\s]+)>\s*<([^\s]+)>$/) {
+ my $real_name = $1;
+ my $real_address = $2;
+ my $wrong_address = $3;
+
+ $real_name =~ s/\s+$//;
+ ($real_name, $real_address) =
+ parse_email("$real_name <$real_address>");
+ $mailmap->{names}->{$wrong_address} = $real_name;
+ $mailmap->{addresses}->{$wrong_address} = $real_address;
+
+ } elsif (/^(.+)<([^\s]+)>\s*([^\s].*)<([^\s]+)>$/) {
+ my $real_name = $1;
+ my $real_address = $2;
+ my $wrong_name = $3;
+ my $wrong_address = $4;
+
+ $real_name =~ s/\s+$//;
+ ($real_name, $real_address) =
+ parse_email("$real_name <$real_address>");
+
+ $wrong_name =~ s/\s+$//;
+ ($wrong_name, $wrong_address) =
+ parse_email("$wrong_name <$wrong_address>");
+
+ my $wrong_email = format_email($wrong_name, $wrong_address, 1);
+ $mailmap->{names}->{$wrong_email} = $real_name;
+ $mailmap->{addresses}->{$wrong_email} = $real_address;
}
}
- close($mailmap);
+ close($mailmap_file);
}
## use the filenames on the command line or find the filenames in the patchfiles
@@ -302,7 +397,7 @@ foreach my $file (@ARGV) {
}
if ($from_filename) {
push(@files, $file);
- if (-f $file && ($keywords || $file_emails)) {
+ if ($file ne "MAINTAINERS" && -f $file && ($keywords || $file_emails)) {
open(my $f, '<', $file)
or die "$P: Can't open $file: $!\n";
my $text = do { local($/) ; <$f> };
@@ -357,67 +452,127 @@ foreach my $file (@ARGV) {
@file_emails = uniq(@file_emails);
+my %email_hash_name;
+my %email_hash_address;
my @email_to = ();
+my %hash_list_to;
my @list_to = ();
my @scm = ();
my @web = ();
my @subsystem = ();
my @status = ();
+my %deduplicate_name_hash = ();
+my %deduplicate_address_hash = ();
+my $signature_pattern;
-# Find responsible parties
+my @maintainers = get_maintainers();
-foreach my $file (@files) {
+if (@maintainers) {
+ @maintainers = merge_email(@maintainers);
+ output(@maintainers);
+}
- my %hash;
- my $tvi = find_first_section();
- while ($tvi < @typevalue) {
- my $start = find_starting_index($tvi);
- my $end = find_ending_index($tvi);
- my $exclude = 0;
- my $i;
-
- #Do not match excluded file patterns
-
- for ($i = $start; $i < $end; $i++) {
- my $line = $typevalue[$i];
- if ($line =~ m/^(\C):\s*(.*)/) {
- my $type = $1;
- my $value = $2;
- if ($type eq 'X') {
- if (file_match_pattern($file, $value)) {
- $exclude = 1;
- last;
- }
- }
- }
- }
+if ($scm) {
+ @scm = uniq(@scm);
+ output(@scm);
+}
+
+if ($status) {
+ @status = uniq(@status);
+ output(@status);
+}
+
+if ($subsystem) {
+ @subsystem = uniq(@subsystem);
+ output(@subsystem);
+}
+
+if ($web) {
+ @web = uniq(@web);
+ output(@web);
+}
+
+exit($exit);
+
+sub get_maintainers {
+ %email_hash_name = ();
+ %email_hash_address = ();
+ %commit_author_hash = ();
+ %commit_signer_hash = ();
+ @email_to = ();
+ %hash_list_to = ();
+ @list_to = ();
+ @scm = ();
+ @web = ();
+ @subsystem = ();
+ @status = ();
+ %deduplicate_name_hash = ();
+ %deduplicate_address_hash = ();
+ if ($email_git_all_signature_types) {
+ $signature_pattern = "(.+?)[Bb][Yy]:";
+ } else {
+ $signature_pattern = "\(" . join("|", @signature_tags) . "\)";
+ }
+
+ # Find responsible parties
+
+ my %exact_pattern_match_hash = ();
+
+ foreach my $file (@files) {
+
+ my %hash;
+ my $tvi = find_first_section();
+ while ($tvi < @typevalue) {
+ my $start = find_starting_index($tvi);
+ my $end = find_ending_index($tvi);
+ my $exclude = 0;
+ my $i;
+
+ #Do not match excluded file patterns
- if (!$exclude) {
for ($i = $start; $i < $end; $i++) {
my $line = $typevalue[$i];
if ($line =~ m/^(\C):\s*(.*)/) {
my $type = $1;
my $value = $2;
- if ($type eq 'F') {
+ if ($type eq 'X') {
if (file_match_pattern($file, $value)) {
- my $value_pd = ($value =~ tr@/@@);
- my $file_pd = ($file =~ tr@/@@);
- $value_pd++ if (substr($value,-1,1) ne "/");
- if ($pattern_depth == 0 ||
- (($file_pd - $value_pd) < $pattern_depth)) {
- $hash{$tvi} = $value_pd;
+ $exclude = 1;
+ last;
+ }
+ }
+ }
+ }
+
+ if (!$exclude) {
+ for ($i = $start; $i < $end; $i++) {
+ my $line = $typevalue[$i];
+ if ($line =~ m/^(\C):\s*(.*)/) {
+ my $type = $1;
+ my $value = $2;
+ if ($type eq 'F') {
+ if (file_match_pattern($file, $value)) {
+ my $value_pd = ($value =~ tr@/@@);
+ my $file_pd = ($file =~ tr@/@@);
+ $value_pd++ if (substr($value,-1,1) ne "/");
+ $value_pd = -1 if ($value =~ /^\.\*/);
+ if ($value_pd >= $file_pd) {
+ $exact_pattern_match_hash{$file} = 1;
+ }
+ if ($pattern_depth == 0 ||
+ (($file_pd - $value_pd) < $pattern_depth)) {
+ $hash{$tvi} = $value_pd;
+ }
}
}
}
}
}
+ $tvi = $end + 1;
}
- $tvi = $end + 1;
- }
-
- foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
- add_categories($line);
+ foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
+ add_categories($line);
if ($sections) {
my $i;
my $start = find_starting_index($line);
@@ -435,80 +590,71 @@ foreach my $file (@files) {
}
print("\n");
}
+ }
}
- if ($email && $email_git) {
- vcs_file_signoffs($file);
+ if ($keywords) {
+ @keyword_tvi = sort_and_uniq(@keyword_tvi);
+ foreach my $line (@keyword_tvi) {
+ add_categories($line);
+ }
}
- if ($email && $email_git_blame) {
- vcs_file_blame($file);
+ foreach my $email (@email_to, @list_to) {
+ $email->[0] = deduplicate_email($email->[0]);
}
-}
-if ($keywords) {
- @keyword_tvi = sort_and_uniq(@keyword_tvi);
- foreach my $line (@keyword_tvi) {
- add_categories($line);
+ foreach my $file (@files) {
+ if ($email &&
+ ($email_git || ($email_git_fallback &&
+ !$exact_pattern_match_hash{$file}))) {
+ vcs_file_signoffs($file);
+ }
+ if ($email && $email_git_blame) {
+ vcs_file_blame($file);
+ }
}
-}
-if ($email) {
- foreach my $chief (@penguin_chief) {
- if ($chief =~ m/^(.*):(.*)/) {
- my $email_address;
+ if ($email) {
+ foreach my $chief (@penguin_chief) {
+ if ($chief =~ m/^(.*):(.*)/) {
+ my $email_address;
- $email_address = format_email($1, $2, $email_usename);
- if ($email_git_penguin_chiefs) {
- push(@email_to, [$email_address, 'chief penguin']);
- } else {
- @email_to = grep($_->[0] !~ /${email_address}/, @email_to);
+ $email_address = format_email($1, $2, $email_usename);
+ if ($email_git_penguin_chiefs) {
+ push(@email_to, [$email_address, 'chief penguin']);
+ } else {
+ @email_to = grep($_->[0] !~ /${email_address}/, @email_to);
+ }
}
}
- }
- foreach my $email (@file_emails) {
- my ($name, $address) = parse_email($email);
+ foreach my $email (@file_emails) {
+ my ($name, $address) = parse_email($email);
- my $tmp_email = format_email($name, $address, $email_usename);
- push_email_address($tmp_email, '');
- add_role($tmp_email, 'in file');
+ my $tmp_email = format_email($name, $address, $email_usename);
+ push_email_address($tmp_email, '');
+ add_role($tmp_email, 'in file');
+ }
}
-}
-if ($email || $email_list) {
my @to = ();
- if ($email) {
- @to = (@to, @email_to);
- }
- if ($email_list) {
- @to = (@to, @list_to);
+ if ($email || $email_list) {
+ if ($email) {
+ @to = (@to, @email_to);
+ }
+ if ($email_list) {
+ @to = (@to, @list_to);
+ }
}
- output(merge_email(@to));
-}
-
-if ($scm) {
- @scm = uniq(@scm);
- output(@scm);
-}
-
-if ($status) {
- @status = uniq(@status);
- output(@status);
-}
-if ($subsystem) {
- @subsystem = uniq(@subsystem);
- output(@subsystem);
-}
+ if ($interactive) {
+ @to = interactive_get_maintainers(\@to);
+ }
-if ($web) {
- @web = uniq(@web);
- output(@web);
+ return @to;
}
-exit($exit);
-
sub file_match_pattern {
my ($file, $pattern) = @_;
if (substr($pattern, -1) eq "/") {
@@ -537,7 +683,8 @@ MAINTAINER field selection options:
--email => print email address(es) if any
--git => include recent git \*-by: signers
--git-all-signature-types => include signers regardless of signature type
- or use only ${signaturePattern} signers (default: $email_git_all_signature_types)
+ or use only ${signature_pattern} signers (default: $email_git_all_signature_types)
+ --git-fallback => use git when no exact MAINTAINERS pattern (default: $email_git_fallback)
--git-chief-penguins => include ${penguin_chiefs}
--git-min-signatures => number of signatures required (default: $email_git_min_signatures)
--git-max-maintainers => maximum maintainers to add (default: $email_git_max_maintainers)
@@ -545,6 +692,7 @@ MAINTAINER field selection options:
--git-blame => use git blame to find modified commits for patch or file
--git-since => git history to use (default: $email_git_since)
--hg-since => hg history to use (default: $email_hg_since)
+ --interactive => display a menu (mostly useful if used with the --git option)
--m => include maintainer(s) if any
--n => include name 'Full Name <addr\@domain.tld>'
--l => include list(s) if any
@@ -565,8 +713,9 @@ Output type options:
Other options:
--pattern-depth => Number of pattern directory traversals (default: 0 (all))
- --keywords => scan patch for keywords (default: 1 (on))
- --sections => print the entire subsystem sections with pattern matches
+ --keywords => scan patch for keywords (default: $keywords)
+ --sections => print all of the subsystem sections with pattern matches
+ --mailmap => use .mailmap file (default: $email_use_mailmap)
--version => show version
--help => show this help information
@@ -606,30 +755,30 @@ EOT
}
sub top_of_kernel_tree {
- my ($lk_path) = @_;
+ my ($lk_path) = @_;
- if ($lk_path ne "" && substr($lk_path,length($lk_path)-1,1) ne "/") {
- $lk_path .= "/";
- }
- if ( (-f "${lk_path}COPYING")
- && (-f "${lk_path}CREDITS")
- && (-f "${lk_path}Kbuild")
- && (-f "${lk_path}MAINTAINERS")
- && (-f "${lk_path}Makefile")
- && (-f "${lk_path}README")
- && (-d "${lk_path}Documentation")
- && (-d "${lk_path}arch")
- && (-d "${lk_path}include")
- && (-d "${lk_path}drivers")
- && (-d "${lk_path}fs")
- && (-d "${lk_path}init")
- && (-d "${lk_path}ipc")
- && (-d "${lk_path}kernel")
- && (-d "${lk_path}lib")
- && (-d "${lk_path}scripts")) {
- return 1;
- }
- return 0;
+ if ($lk_path ne "" && substr($lk_path,length($lk_path)-1,1) ne "/") {
+ $lk_path .= "/";
+ }
+ if ( (-f "${lk_path}COPYING")
+ && (-f "${lk_path}CREDITS")
+ && (-f "${lk_path}Kbuild")
+ && (-f "${lk_path}MAINTAINERS")
+ && (-f "${lk_path}Makefile")
+ && (-f "${lk_path}README")
+ && (-d "${lk_path}Documentation")
+ && (-d "${lk_path}arch")
+ && (-d "${lk_path}include")
+ && (-d "${lk_path}drivers")
+ && (-d "${lk_path}fs")
+ && (-d "${lk_path}init")
+ && (-d "${lk_path}ipc")
+ && (-d "${lk_path}kernel")
+ && (-d "${lk_path}lib")
+ && (-d "${lk_path}scripts")) {
+ return 1;
+ }
+ return 0;
}
sub parse_email {
@@ -821,11 +970,19 @@ sub add_categories {
}
if ($list_additional =~ m/subscribers-only/) {
if ($email_subscriber_list) {
- push(@list_to, [$list_address, "subscriber list${list_role}"]);
+ if (!$hash_list_to{lc($list_address)}) {
+ $hash_list_to{lc($list_address)} = 1;
+ push(@list_to, [$list_address,
+ "subscriber list${list_role}"]);
+ }
}
} else {
if ($email_list) {
- push(@list_to, [$list_address, "open list${list_role}"]);
+ if (!$hash_list_to{lc($list_address)}) {
+ $hash_list_to{lc($list_address)} = 1;
+ push(@list_to, [$list_address,
+ "open list${list_role}"]);
+ }
}
}
} elsif ($ptype eq "M") {
@@ -856,15 +1013,12 @@ sub add_categories {
}
}
-my %email_hash_name;
-my %email_hash_address;
-
sub email_inuse {
my ($name, $address) = @_;
return 1 if (($name eq "") && ($address eq ""));
- return 1 if (($name ne "") && exists($email_hash_name{$name}));
- return 1 if (($address ne "") && exists($email_hash_address{$address}));
+ return 1 if (($name ne "") && exists($email_hash_name{lc($name)}));
+ return 1 if (($address ne "") && exists($email_hash_address{lc($address)}));
return 0;
}
@@ -882,8 +1036,8 @@ sub push_email_address {
push(@email_to, [format_email($name, $address, $email_usename), $role]);
} elsif (!email_inuse($name, $address)) {
push(@email_to, [format_email($name, $address, $email_usename), $role]);
- $email_hash_name{$name}++;
- $email_hash_address{$address}++;
+ $email_hash_name{lc($name)}++ if ($name ne "");
+ $email_hash_address{lc($address)}++;
}
return 1;
@@ -952,30 +1106,69 @@ sub which {
return "";
}
-sub mailmap {
- my (@lines) = @_;
- my %hash;
+sub which_conf {
+ my ($conf) = @_;
- foreach my $line (@lines) {
- my ($name, $address) = parse_email($line);
- if (!exists($hash{$name})) {
- $hash{$name} = $address;
- } elsif ($address ne $hash{$name}) {
- $address = $hash{$name};
- $line = format_email($name, $address, $email_usename);
+ foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) {
+ if (-e "$path/$conf") {
+ return "$path/$conf";
}
- if (exists($mailmap{$name})) {
- my $obj = $mailmap{$name};
- foreach my $map_address (@$obj) {
- if (($map_address eq $address) &&
- ($map_address ne $hash{$name})) {
- $line = format_email($name, $hash{$name}, $email_usename);
- }
- }
+ }
+
+ return "";
+}
+
+sub mailmap_email {
+ my ($line) = @_;
+
+ my ($name, $address) = parse_email($line);
+ my $email = format_email($name, $address, 1);
+ my $real_name = $name;
+ my $real_address = $address;
+
+ if (exists $mailmap->{names}->{$email} ||
+ exists $mailmap->{addresses}->{$email}) {
+ if (exists $mailmap->{names}->{$email}) {
+ $real_name = $mailmap->{names}->{$email};
+ }
+ if (exists $mailmap->{addresses}->{$email}) {
+ $real_address = $mailmap->{addresses}->{$email};
+ }
+ } else {
+ if (exists $mailmap->{names}->{$address}) {
+ $real_name = $mailmap->{names}->{$address};
+ }
+ if (exists $mailmap->{addresses}->{$address}) {
+ $real_address = $mailmap->{addresses}->{$address};
}
}
+ return format_email($real_name, $real_address, 1);
+}
- return @lines;
+sub mailmap {
+ my (@addresses) = @_;
+
+ my @mapped_emails = ();
+ foreach my $line (@addresses) {
+ push(@mapped_emails, mailmap_email($line));
+ }
+ merge_by_realname(@mapped_emails) if ($email_use_mailmap);
+ return @mapped_emails;
+}
+
+sub merge_by_realname {
+ my %address_map;
+ my (@emails) = @_;
+
+ foreach my $email (@emails) {
+ my ($name, $address) = parse_email($email);
+ if (exists $address_map{$name}) {
+ $address = $address_map{$name};
+ $email = format_email($name, $address, 1);
+ } else {
+ $address_map{$name} = $address;
+ }
+ }
}
sub git_execute_cmd {
@@ -999,10 +1192,30 @@ sub hg_execute_cmd {
return @lines;
}
+sub extract_formatted_signatures {
+ my (@signature_lines) = @_;
+
+ my @type = @signature_lines;
+
+ s/\s*(.*):.*/$1/ for (@type);
+
+ # cut -f2- -d":"
+ s/\s*.*:\s*(.+)\s*/$1/ for (@signature_lines);
+
+## Reformat email addresses (with names) to avoid badly written signatures
+
+ foreach my $signer (@signature_lines) {
+ $signer = deduplicate_email($signer);
+ }
+
+ return (\@type, \@signature_lines);
+}
+
sub vcs_find_signers {
my ($cmd) = @_;
- my @lines = ();
my $commits;
+ my @lines = ();
+ my @signatures = ();
@lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
@@ -1010,21 +1223,48 @@ sub vcs_find_signers {
$commits = grep(/$pattern/, @lines); # of commits
- @lines = grep(/^[ \t]*${signaturePattern}.*\@.*$/, @lines);
+ @signatures = grep(/^[ \t]*${signature_pattern}.*\@.*$/, @lines);
+
+ return (0, @signatures) if !@signatures;
+
+ save_commits_by_author(@lines) if ($interactive);
+ save_commits_by_signer(@lines) if ($interactive);
+
+ if (!$email_git_penguin_chiefs) {
+ @signatures = grep(!/${penguin_chiefs}/i, @signatures);
+ }
+
+ my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
+
+ return ($commits, @$signers_ref);
+}
+
+sub vcs_find_author {
+ my ($cmd) = @_;
+ my @lines = ();
+
+ @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
if (!$email_git_penguin_chiefs) {
@lines = grep(!/${penguin_chiefs}/i, @lines);
}
- # cut -f2- -d":"
- s/.*:\s*(.+)\s*/$1/ for (@lines);
-## Reformat email addresses (with names) to avoid badly written signatures
+ return @lines if !@lines;
+ my @authors = ();
foreach my $line (@lines) {
- my ($name, $address) = parse_email($line);
- $line = format_email($name, $address, 1);
+ if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
+ my $author = $1;
+ my ($name, $address) = parse_email($author);
+ $author = format_email($name, $address, 1);
+ push(@authors, $author);
+ }
}
- return ($commits, @lines);
+ save_commits_by_author(@lines) if ($interactive);
+ save_commits_by_signer(@lines) if ($interactive);
+
+ return @authors;
}
sub vcs_save_commits {
@@ -1084,6 +1324,10 @@ sub vcs_blame {
@commits = vcs_save_commits($cmd);
}
+ foreach my $commit (@commits) {
+ $commit =~ s/^\^//g;
+ }
+
return @commits;
}
@@ -1092,7 +1336,7 @@ sub vcs_exists {
%VCS_cmds = %VCS_cmds_git;
return 1 if eval $VCS_cmds{"available"};
%VCS_cmds = %VCS_cmds_hg;
- return 1 if eval $VCS_cmds{"available"};
+ return 2 if eval $VCS_cmds{"available"};
%VCS_cmds = ();
if (!$printed_novcs) {
warn("$P: No supported VCS found. Add --nogit to options?\n");
@@ -1104,6 +1348,405 @@ sub vcs_exists {
return 0;
}
+sub vcs_is_git {
+ vcs_exists();
+ return $vcs_used == 1;
+}
+
+sub vcs_is_hg {
+ return $vcs_used == 2;
+}
+
+sub interactive_get_maintainers {
+ my ($list_ref) = @_;
+ my @list = @$list_ref;
+
+ vcs_exists();
+
+ my %selected;
+ my %authored;
+ my %signed;
+ my $count = 0;
+ my $maintained = 0;
+ foreach my $entry (@list) {
+ $maintained = 1 if ($entry->[1] =~ /^(maintainer|supporter)/i);
+ $selected{$count} = 1;
+ $authored{$count} = 0;
+ $signed{$count} = 0;
+ $count++;
+ }
+
+ #menu loop
+ my $done = 0;
+ my $print_options = 0;
+ my $redraw = 1;
+ while (!$done) {
+ $count = 0;
+ if ($redraw) {
+ printf STDERR "\n%1s %2s %-65s",
+ "*", "#", "email/list and role:stats";
+ if ($email_git ||
+ ($email_git_fallback && !$maintained) ||
+ $email_git_blame) {
+ print STDERR "auth sign";
+ }
+ print STDERR "\n";
+ foreach my $entry (@list) {
+ my $email = $entry->[0];
+ my $role = $entry->[1];
+ my $sel = "";
+ $sel = "*" if ($selected{$count});
+ my $commit_author = $commit_author_hash{$email};
+ my $commit_signer = $commit_signer_hash{$email};
+ my $authored = 0;
+ my $signed = 0;
+ $authored++ for (@{$commit_author});
+ $signed++ for (@{$commit_signer});
+ printf STDERR "%1s %2d %-65s", $sel, $count + 1, $email;
+ printf STDERR "%4d %4d", $authored, $signed
+ if ($authored > 0 || $signed > 0);
+ printf STDERR "\n %s\n", $role;
+ if ($authored{$count}) {
+ my $commit_author = $commit_author_hash{$email};
+ foreach my $ref (@{$commit_author}) {
+ print STDERR " Author: @{$ref}[1]\n";
+ }
+ }
+ if ($signed{$count}) {
+ my $commit_signer = $commit_signer_hash{$email};
+ foreach my $ref (@{$commit_signer}) {
+ print STDERR " @{$ref}[2]: @{$ref}[1]\n";
+ }
+ }
+
+ $count++;
+ }
+ }
+ my $date_ref = \$email_git_since;
+ $date_ref = \$email_hg_since if (vcs_is_hg());
+ if ($print_options) {
+ $print_options = 0;
+ if (vcs_exists()) {
+ print STDERR <<EOT
+
+Version Control options:
+g use git history [$email_git]
+gf use git-fallback [$email_git_fallback]
+b use git blame [$email_git_blame]
+bs use blame signatures [$email_git_blame_signatures]
+c# minimum commits [$email_git_min_signatures]
+%# min percent [$email_git_min_percent]
+d# history to use [$$date_ref]
+x# max maintainers [$email_git_max_maintainers]
+t all signature types [$email_git_all_signature_types]
+m use .mailmap [$email_use_mailmap]
+EOT
+ }
+ print STDERR <<EOT
+
+Additional options:
+0 toggle all
+tm toggle maintainers
+tg toggle git entries
+tl toggle open list entries
+ts toggle subscriber list entries
+f emails in file [$file_emails]
+k keywords in file [$keywords]
+r remove duplicates [$email_remove_duplicates]
+p# pattern match depth [$pattern_depth]
+EOT
+ }
+ print STDERR
+"\n#(toggle), A#(author), S#(signed) *(all), ^(none), O(options), Y(approve): ";
+
+ my $input = <STDIN>;
+ chomp($input);
+
+ $redraw = 1;
+ my $rerun = 0;
+ my @wish = split(/[, ]+/, $input);
+ foreach my $nr (@wish) {
+ $nr = lc($nr);
+ my $sel = substr($nr, 0, 1);
+ my $str = substr($nr, 1);
+ my $val = 0;
+ $val = $1 if $str =~ /^(\d+)$/;
+
+ if ($sel eq "y") {
+ $interactive = 0;
+ $done = 1;
+ $output_rolestats = 0;
+ $output_roles = 0;
+ last;
+ } elsif ($nr =~ /^\d+$/ && $nr > 0 && $nr <= $count) {
+ $selected{$nr - 1} = !$selected{$nr - 1};
+ } elsif ($sel eq "*" || $sel eq '^') {
+ my $toggle = 0;
+ $toggle = 1 if ($sel eq '*');
+ for (my $i = 0; $i < $count; $i++) {
+ $selected{$i} = $toggle;
+ }
+ } elsif ($sel eq "0") {
+ for (my $i = 0; $i < $count; $i++) {
+ $selected{$i} = !$selected{$i};
+ }
+ } elsif ($sel eq "t") {
+ if (lc($str) eq "m") {
+ for (my $i = 0; $i < $count; $i++) {
+ $selected{$i} = !$selected{$i}
+ if ($list[$i]->[1] =~ /^(maintainer|supporter)/i);
+ }
+ } elsif (lc($str) eq "g") {
+ for (my $i = 0; $i < $count; $i++) {
+ $selected{$i} = !$selected{$i}
+ if ($list[$i]->[1] =~ /^(author|commit|signer)/i);
+ }
+ } elsif (lc($str) eq "l") {
+ for (my $i = 0; $i < $count; $i++) {
+ $selected{$i} = !$selected{$i}
+ if ($list[$i]->[1] =~ /^(open list)/i);
+ }
+ } elsif (lc($str) eq "s") {
+ for (my $i = 0; $i < $count; $i++) {
+ $selected{$i} = !$selected{$i}
+ if ($list[$i]->[1] =~ /^(subscriber list)/i);
+ }
+ }
+ } elsif ($sel eq "a") {
+ if ($val > 0 && $val <= $count) {
+ $authored{$val - 1} = !$authored{$val - 1};
+ } elsif ($str eq '*' || $str eq '^') {
+ my $toggle = 0;
+ $toggle = 1 if ($str eq '*');
+ for (my $i = 0; $i < $count; $i++) {
+ $authored{$i} = $toggle;
+ }
+ }
+ } elsif ($sel eq "s") {
+ if ($val > 0 && $val <= $count) {
+ $signed{$val - 1} = !$signed{$val - 1};
+ } elsif ($str eq '*' || $str eq '^') {
+ my $toggle = 0;
+ $toggle = 1 if ($str eq '*');
+ for (my $i = 0; $i < $count; $i++) {
+ $signed{$i} = $toggle;
+ }
+ }
+ } elsif ($sel eq "o") {
+ $print_options = 1;
+ $redraw = 1;
+ } elsif ($sel eq "g") {
+ if ($str eq "f") {
+ bool_invert(\$email_git_fallback);
+ } else {
+ bool_invert(\$email_git);
+ }
+ $rerun = 1;
+ } elsif ($sel eq "b") {
+ if ($str eq "s") {
+ bool_invert(\$email_git_blame_signatures);
+ } else {
+ bool_invert(\$email_git_blame);
+ }
+ $rerun = 1;
+ } elsif ($sel eq "c") {
+ if ($val > 0) {
+ $email_git_min_signatures = $val;
+ $rerun = 1;
+ }
+ } elsif ($sel eq "x") {
+ if ($val > 0) {
+ $email_git_max_maintainers = $val;
+ $rerun = 1;
+ }
+ } elsif ($sel eq "%") {
+ if ($str ne "" && $val >= 0) {
+ $email_git_min_percent = $val;
+ $rerun = 1;
+ }
+ } elsif ($sel eq "d") {
+ if (vcs_is_git()) {
+ $email_git_since = $str;
+ } elsif (vcs_is_hg()) {
+ $email_hg_since = $str;
+ }
+ $rerun = 1;
+ } elsif ($sel eq "t") {
+ bool_invert(\$email_git_all_signature_types);
+ $rerun = 1;
+ } elsif ($sel eq "f") {
+ bool_invert(\$file_emails);
+ $rerun = 1;
+ } elsif ($sel eq "r") {
+ bool_invert(\$email_remove_duplicates);
+ $rerun = 1;
+ } elsif ($sel eq "m") {
+ bool_invert(\$email_use_mailmap);
+ read_mailmap();
+ $rerun = 1;
+ } elsif ($sel eq "k") {
+ bool_invert(\$keywords);
+ $rerun = 1;
+ } elsif ($sel eq "p") {
+ if ($str ne "" && $val >= 0) {
+ $pattern_depth = $val;
+ $rerun = 1;
+ }
+ } elsif ($sel eq "h" || $sel eq "?") {
+ print STDERR <<EOT
+
+Interactive mode allows you to select the various maintainers, submitters,
+commit signers and mailing lists that could be CC'd on a patch.
+
+Any *'d entry is selected.
+
+If you have git or hg installed, you can choose to summarize the commit
+history of files in the patch. Also, each line of the current file can
+be matched to its commit author and that commits signers with blame.
+
+Various knobs exist to control the length of time for active commit
+tracking, the maximum number of commit authors and signers to add,
+and such.
+
+Enter selections at the prompt until you are satisfied that the selected
+maintainers are appropriate. You may enter multiple selections separated
+by either commas or spaces.
+
+EOT
+ } else {
+ print STDERR "invalid option: '$nr'\n";
+ $redraw = 0;
+ }
+ }
+ if ($rerun) {
+ print STDERR "git-blame can be very slow, please have patience..."
+ if ($email_git_blame);
+ goto &get_maintainers;
+ }
+ }
+
+ #drop not selected entries
+ $count = 0;
+ my @new_emailto = ();
+ foreach my $entry (@list) {
+ if ($selected{$count}) {
+ push(@new_emailto, $list[$count]);
+ }
+ $count++;
+ }
+ return @new_emailto;
+}
+
+sub bool_invert {
+ my ($bool_ref) = @_;
+
+ if ($$bool_ref) {
+ $$bool_ref = 0;
+ } else {
+ $$bool_ref = 1;
+ }
+}
+
+sub deduplicate_email {
+ my ($email) = @_;
+
+ my $matched = 0;
+ my ($name, $address) = parse_email($email);
+ $email = format_email($name, $address, 1);
+ $email = mailmap_email($email);
+
+ return $email if (!$email_remove_duplicates);
+
+ ($name, $address) = parse_email($email);
+
+ if ($name ne "" && $deduplicate_name_hash{lc($name)}) {
+ $name = $deduplicate_name_hash{lc($name)}->[0];
+ $address = $deduplicate_name_hash{lc($name)}->[1];
+ $matched = 1;
+ } elsif ($deduplicate_address_hash{lc($address)}) {
+ $name = $deduplicate_address_hash{lc($address)}->[0];
+ $address = $deduplicate_address_hash{lc($address)}->[1];
+ $matched = 1;
+ }
+ if (!$matched) {
+ $deduplicate_name_hash{lc($name)} = [ $name, $address ];
+ $deduplicate_address_hash{lc($address)} = [ $name, $address ];
+ }
+ $email = format_email($name, $address, 1);
+ $email = mailmap_email($email);
+ return $email;
+}
+
+sub save_commits_by_author {
+ my (@lines) = @_;
+
+ my @authors = ();
+ my @commits = ();
+ my @subjects = ();
+
+ foreach my $line (@lines) {
+ if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
+ my $author = $1;
+ $author = deduplicate_email($author);
+ push(@authors, $author);
+ }
+ push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
+ push(@subjects, $1) if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
+ }
+
+ for (my $i = 0; $i < @authors; $i++) {
+ my $exists = 0;
+ foreach my $ref(@{$commit_author_hash{$authors[$i]}}) {
+ if (@{$ref}[0] eq $commits[$i] &&
+ @{$ref}[1] eq $subjects[$i]) {
+ $exists = 1;
+ last;
+ }
+ }
+ if (!$exists) {
+ push(@{$commit_author_hash{$authors[$i]}},
+ [ ($commits[$i], $subjects[$i]) ]);
+ }
+ }
+}
+
+sub save_commits_by_signer {
+ my (@lines) = @_;
+
+ my $commit = "";
+ my $subject = "";
+
+ foreach my $line (@lines) {
+ $commit = $1 if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
+ $subject = $1 if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
+ if ($line =~ /^[ \t]*${signature_pattern}.*\@.*$/) {
+ my @signatures = ($line);
+ my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
+ my @types = @$types_ref;
+ my @signers = @$signers_ref;
+
+ my $type = $types[0];
+ my $signer = $signers[0];
+
+ $signer = deduplicate_email($signer);
+
+ my $exists = 0;
+ foreach my $ref(@{$commit_signer_hash{$signer}}) {
+ if (@{$ref}[0] eq $commit &&
+ @{$ref}[1] eq $subject &&
+ @{$ref}[2] eq $type) {
+ $exists = 1;
+ last;
+ }
+ }
+ if (!$exists) {
+ push(@{$commit_signer_hash{$signer}},
+ [ ($commit, $subject, $type) ]);
+ }
+ }
+ }
+}
+
sub vcs_assign {
my ($role, $divisor, @lines) = @_;
@@ -1117,9 +1760,9 @@ sub vcs_assign {
$divisor = 1;
}
- if ($email_remove_duplicates) {
- @lines = mailmap(@lines);
- }
+ @lines = mailmap(@lines);
+
+ return if (@lines <= 0);
@lines = sort(@lines);
@@ -1152,12 +1795,18 @@ sub vcs_file_signoffs {
my @signers = ();
my $commits;
- return if (!vcs_exists());
+ $vcs_used = vcs_exists();
+ return if (!$vcs_used);
my $cmd = $VCS_cmds{"find_signers_cmd"};
$cmd =~ s/(\$\w+)/$1/eeg; # interpolate $cmd
($commits, @signers) = vcs_find_signers($cmd);
+
+ foreach my $signer (@signers) {
+ $signer = deduplicate_email($signer);
+ }
+
vcs_assign("commit_signer", $commits, @signers);
}
@@ -1165,29 +1814,114 @@ sub vcs_file_blame {
my ($file) = @_;
my @signers = ();
+ my @all_commits = ();
my @commits = ();
my $total_commits;
+ my $total_lines;
- return if (!vcs_exists());
+ $vcs_used = vcs_exists();
+ return if (!$vcs_used);
- @commits = vcs_blame($file);
- @commits = uniq(@commits);
+ @all_commits = vcs_blame($file);
+ @commits = uniq(@all_commits);
$total_commits = @commits;
+ $total_lines = @all_commits;
- foreach my $commit (@commits) {
- my $commit_count;
- my @commit_signers = ();
+ if ($email_git_blame_signatures) {
+ if (vcs_is_hg()) {
+ my $commit_count;
+ my @commit_signers = ();
+ my $commit = join(" -r ", @commits);
+ my $cmd;
+
+ $cmd = $VCS_cmds{"find_commit_signers_cmd"};
+ $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd
+
+ ($commit_count, @commit_signers) = vcs_find_signers($cmd);
+
+ push(@signers, @commit_signers);
+ } else {
+ foreach my $commit (@commits) {
+ my $commit_count;
+ my @commit_signers = ();
+ my $cmd;
- my $cmd = $VCS_cmds{"find_commit_signers_cmd"};
- $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd
+ $cmd = $VCS_cmds{"find_commit_signers_cmd"};
+ $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd
- ($commit_count, @commit_signers) = vcs_find_signers($cmd);
- push(@signers, @commit_signers);
+ ($commit_count, @commit_signers) = vcs_find_signers($cmd);
+
+ push(@signers, @commit_signers);
+ }
+ }
}
if ($from_filename) {
+ if ($output_rolestats) {
+ my @blame_signers;
+ if (vcs_is_hg()) {{ # Double brace for last exit
+ my $commit_count;
+ my @commit_signers = ();
+ @commits = uniq(@commits);
+ @commits = sort(@commits);
+ my $commit = join(" -r ", @commits);
+ my $cmd;
+
+ $cmd = $VCS_cmds{"find_commit_author_cmd"};
+ $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd
+
+ my @lines = ();
+
+ @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
+ if (!$email_git_penguin_chiefs) {
+ @lines = grep(!/${penguin_chiefs}/i, @lines);
+ }
+
+ last if !@lines;
+
+ my @authors = ();
+ foreach my $line (@lines) {
+ if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
+ my $author = $1;
+ $author = deduplicate_email($author);
+ push(@authors, $author);
+ }
+ }
+
+ save_commits_by_author(@lines) if ($interactive);
+ save_commits_by_signer(@lines) if ($interactive);
+
+ push(@signers, @authors);
+ }}
+ else {
+ foreach my $commit (@commits) {
+ my $i;
+ my $cmd = $VCS_cmds{"find_commit_author_cmd"};
+ $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd
+ my @author = vcs_find_author($cmd);
+ next if !@author;
+
+ my $formatted_author = deduplicate_email($author[0]);
+
+ my $count = grep(/$commit/, @all_commits);
+ for ($i = 0; $i < $count ; $i++) {
+ push(@blame_signers, $formatted_author);
+ }
+ }
+ }
+ if (@blame_signers) {
+ vcs_assign("authored lines", $total_lines, @blame_signers);
+ }
+ }
+ foreach my $signer (@signers) {
+ $signer = deduplicate_email($signer);
+ }
vcs_assign("commits", $total_commits, @signers);
} else {
+ foreach my $signer (@signers) {
+ $signer = deduplicate_email($signer);
+ }
vcs_assign("modified commits", $total_commits, @signers);
}
}
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
index 82396050f186..36cc0cc39e78 100644
--- a/security/apparmor/path.c
+++ b/security/apparmor/path.c
@@ -72,10 +72,8 @@ static int d_namespace_path(struct path *path, char *buf, int buflen,
path_get(&root);
}
- spin_lock(&dcache_lock);
tmp = root;
res = __d_path(path, &tmp, buf, buflen);
- spin_unlock(&dcache_lock);
*name = res;
/* handle error conditions - and still allow a partial path to
diff --git a/security/inode.c b/security/inode.c
index 88839866cbcd..cb8f47c66a58 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -61,6 +61,7 @@ static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev)
struct inode *inode = new_inode(sb);
if (inode) {
+ inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch (mode & S_IFMT) {
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 3fbcd1dda0ef..ac79032bdf23 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -70,6 +70,7 @@ int ima_init(void);
void ima_cleanup(void);
int ima_fs_init(void);
void ima_fs_cleanup(void);
+int ima_inode_alloc(struct inode *inode);
int ima_add_template_entry(struct ima_template_entry *entry, int violation,
const char *op, struct inode *inode);
int ima_calc_hash(struct file *file, char *digest);
@@ -96,19 +97,16 @@ static inline unsigned long ima_hash_key(u8 *digest)
}
/* iint cache flags */
-#define IMA_MEASURED 1
+#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 long flags;
+ unsigned char flags;
u8 digest[IMA_DIGEST_SIZE];
struct mutex mutex; /* protects: version, flags, digest */
- long readcount; /* measured files readcount */
- long writecount; /* measured files writecount */
- long opencount; /* opens reference count */
- struct kref refcount; /* ima_iint_cache reference count */
- struct rcu_head rcu;
};
/* LIM API function definitions */
@@ -122,13 +120,11 @@ int ima_store_template(struct ima_template_entry *entry, int violation,
void ima_template_show(struct seq_file *m, void *e,
enum ima_show_type show);
-/* radix tree calls to lookup, insert, delete
+/* 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_get(struct inode *inode);
-void iint_free(struct kref *kref);
-void iint_rcu_free(struct rcu_head *rcu);
+struct ima_iint_cache *ima_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 52015d098fdf..d3963de6003d 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -116,7 +116,7 @@ int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode,
{
int must_measure;
- if (iint->flags & IMA_MEASURED)
+ if (iint && iint->flags & IMA_MEASURED)
return 1;
must_measure = ima_match_policy(inode, function, mask);
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
index afba4aef812f..c442e47b6785 100644
--- a/security/integrity/ima/ima_iint.c
+++ b/security/integrity/ima/ima_iint.c
@@ -12,98 +12,119 @@
* File: ima_iint.c
* - implements the IMA hooks: ima_inode_alloc, ima_inode_free
* - cache integrity information associated with an inode
- * using a radix tree.
+ * using a rbtree tree.
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/spinlock.h>
-#include <linux/radix-tree.h>
+#include <linux/rbtree.h>
#include "ima.h"
-RADIX_TREE(ima_iint_store, GFP_ATOMIC);
-DEFINE_SPINLOCK(ima_iint_lock);
+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_get - return the iint associated with an inode
- *
- * ima_iint_find_get gets a reference to the iint. Caller must
- * remember to put the iint reference.
+/*
+ * __ima_iint_find - return the iint associated with an inode
*/
-struct ima_iint_cache *ima_iint_find_get(struct inode *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;
- rcu_read_lock();
- iint = radix_tree_lookup(&ima_iint_store, (unsigned long)inode);
- if (!iint)
- goto out;
- kref_get(&iint->refcount);
-out:
- rcu_read_unlock();
return iint;
}
-/**
- * ima_inode_alloc - allocate an iint associated with an inode
- * @inode: pointer to the inode
+/*
+ * ima_iint_find - return the iint associated with an inode
*/
-int ima_inode_alloc(struct inode *inode)
+struct ima_iint_cache *ima_iint_find(struct inode *inode)
{
- struct ima_iint_cache *iint = NULL;
- int rc = 0;
-
- iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
- if (!iint)
- return -ENOMEM;
+ struct ima_iint_cache *iint;
- rc = radix_tree_preload(GFP_NOFS);
- if (rc < 0)
- goto out;
+ if (!IS_IMA(inode))
+ return NULL;
spin_lock(&ima_iint_lock);
- rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint);
+ iint = __ima_iint_find(inode);
spin_unlock(&ima_iint_lock);
- radix_tree_preload_end();
-out:
- if (rc < 0)
- kmem_cache_free(iint_cache, iint);
- return rc;
+ return iint;
}
-/* iint_free - called when the iint refcount goes to zero */
-void iint_free(struct kref *kref)
+static void iint_free(struct ima_iint_cache *iint)
{
- struct ima_iint_cache *iint = container_of(kref, struct ima_iint_cache,
- refcount);
iint->version = 0;
iint->flags = 0UL;
- if (iint->readcount != 0) {
- printk(KERN_INFO "%s: readcount: %ld\n", __func__,
- iint->readcount);
- iint->readcount = 0;
- }
- if (iint->writecount != 0) {
- printk(KERN_INFO "%s: writecount: %ld\n", __func__,
- iint->writecount);
- iint->writecount = 0;
- }
- if (iint->opencount != 0) {
- printk(KERN_INFO "%s: opencount: %ld\n", __func__,
- iint->opencount);
- iint->opencount = 0;
- }
- kref_init(&iint->refcount);
kmem_cache_free(iint_cache, iint);
}
-void iint_rcu_free(struct rcu_head *rcu_head)
+/**
+ * ima_inode_alloc - allocate an iint associated with an inode
+ * @inode: pointer to the inode
+ */
+int ima_inode_alloc(struct inode *inode)
{
- struct ima_iint_cache *iint = container_of(rcu_head,
- struct ima_iint_cache, rcu);
- kref_put(&iint->refcount, iint_free);
+ 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;
}
/**
@@ -116,11 +137,20 @@ void ima_inode_free(struct inode *inode)
{
struct ima_iint_cache *iint;
+ if (inode->i_readcount)
+ printk(KERN_INFO "%s: readcount: %u\n", __func__, inode->i_readcount);
+
+ inode->i_readcount = 0;
+
+ if (!IS_IMA(inode))
+ return;
+
spin_lock(&ima_iint_lock);
- iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode);
+ iint = __ima_iint_find(inode);
+ rb_erase(&iint->rb_node, &ima_iint_tree);
spin_unlock(&ima_iint_lock);
- if (iint)
- call_rcu(&iint->rcu, iint_rcu_free);
+
+ iint_free(iint);
}
static void init_once(void *foo)
@@ -131,10 +161,6 @@ static void init_once(void *foo)
iint->version = 0;
iint->flags = 0UL;
mutex_init(&iint->mutex);
- iint->readcount = 0;
- iint->writecount = 0;
- iint->opencount = 0;
- kref_init(&iint->refcount);
}
static int __init ima_iintcache_init(void)
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index e662b89d4079..203de979d305 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -85,50 +85,6 @@ out:
return found;
}
-/* ima_read_write_check - reflect possible reading/writing errors in the PCR.
- *
- * When opening a file for read, if the file is already open for write,
- * the file could change, resulting in a file measurement error.
- *
- * Opening a file for write, if the file is already open for read, results
- * in a time of measure, time of use (ToMToU) error.
- *
- * In either case invalidate the PCR.
- */
-enum iint_pcr_error { TOMTOU, OPEN_WRITERS };
-static void ima_read_write_check(enum iint_pcr_error error,
- struct ima_iint_cache *iint,
- struct inode *inode,
- const unsigned char *filename)
-{
- switch (error) {
- case TOMTOU:
- if (iint->readcount > 0)
- ima_add_violation(inode, filename, "invalid_pcr",
- "ToMToU");
- break;
- case OPEN_WRITERS:
- if (iint->writecount > 0)
- ima_add_violation(inode, filename, "invalid_pcr",
- "open_writers");
- break;
- }
-}
-
-/*
- * Update the counts given an fmode_t
- */
-static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode)
-{
- BUG_ON(!mutex_is_locked(&iint->mutex));
-
- iint->opencount++;
- if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
- iint->readcount++;
- if (mode & FMODE_WRITE)
- iint->writecount++;
-}
-
/*
* ima_counts_get - increment file counts
*
@@ -145,62 +101,101 @@ void ima_counts_get(struct file *file)
struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
fmode_t mode = file->f_mode;
- struct ima_iint_cache *iint;
int rc;
+ bool send_tomtou = false, send_writers = false;
- if (!iint_initialized || !S_ISREG(inode->i_mode))
+ if (!S_ISREG(inode->i_mode))
return;
- iint = ima_iint_find_get(inode);
- if (!iint)
- return;
- mutex_lock(&iint->mutex);
+
+ spin_lock(&inode->i_lock);
+
if (!ima_initialized)
goto out;
- rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK);
- if (rc < 0)
- goto out;
if (mode & FMODE_WRITE) {
- ima_read_write_check(TOMTOU, iint, inode, dentry->d_name.name);
+ if (inode->i_readcount && IS_IMA(inode))
+ send_tomtou = true;
goto out;
}
- ima_read_write_check(OPEN_WRITERS, iint, inode, dentry->d_name.name);
+
+ rc = ima_must_measure(NULL, inode, MAY_READ, FILE_CHECK);
+ if (rc < 0)
+ goto out;
+
+ if (atomic_read(&inode->i_writecount) > 0)
+ send_writers = true;
out:
- ima_inc_counts(iint, file->f_mode);
- mutex_unlock(&iint->mutex);
+ /* remember the vfs deals with i_writecount */
+ if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
+ inode->i_readcount++;
- kref_put(&iint->refcount, iint_free);
+ spin_unlock(&inode->i_lock);
+
+ if (send_tomtou)
+ ima_add_violation(inode, dentry->d_name.name, "invalid_pcr",
+ "ToMToU");
+ if (send_writers)
+ ima_add_violation(inode, dentry->d_name.name, "invalid_pcr",
+ "open_writers");
}
/*
* Decrement ima counts
*/
-static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
- struct file *file)
+static void ima_dec_counts(struct inode *inode, struct file *file)
{
mode_t mode = file->f_mode;
- BUG_ON(!mutex_is_locked(&iint->mutex));
- iint->opencount--;
- if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
- iint->readcount--;
- if (mode & FMODE_WRITE) {
- iint->writecount--;
- if (iint->writecount == 0) {
- if (iint->version != inode->i_version)
- iint->flags &= ~IMA_MEASURED;
+ assert_spin_locked(&inode->i_lock);
+
+ if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+ if (unlikely(inode->i_readcount == 0)) {
+ if (!ima_limit_imbalance(file)) {
+ printk(KERN_INFO "%s: open/free imbalance (r:%u)\n",
+ __func__, inode->i_readcount);
+ dump_stack();
+ }
+ return;
}
+ inode->i_readcount--;
}
+}
- if (((iint->opencount < 0) ||
- (iint->readcount < 0) ||
- (iint->writecount < 0)) &&
- !ima_limit_imbalance(file)) {
- printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n",
- __func__, iint->readcount, iint->writecount,
- iint->opencount);
- dump_stack();
- }
+static void ima_check_last_writer(struct ima_iint_cache *iint,
+ struct inode *inode,
+ struct file *file)
+{
+ mode_t mode = file->f_mode;
+
+ BUG_ON(!mutex_is_locked(&iint->mutex));
+ assert_spin_locked(&inode->i_lock);
+
+ if (mode & FMODE_WRITE &&
+ atomic_read(&inode->i_writecount) == 1 &&
+ iint->version != inode->i_version)
+ iint->flags &= ~IMA_MEASURED;
+}
+
+static void ima_file_free_iint(struct ima_iint_cache *iint, struct inode *inode,
+ struct file *file)
+{
+ mutex_lock(&iint->mutex);
+ spin_lock(&inode->i_lock);
+
+ ima_dec_counts(inode, file);
+ ima_check_last_writer(iint, inode, file);
+
+ spin_unlock(&inode->i_lock);
+ mutex_unlock(&iint->mutex);
+}
+
+static void ima_file_free_noiint(struct inode *inode, struct file *file)
+{
+ spin_lock(&inode->i_lock);
+
+ ima_dec_counts(inode, file);
+
+ spin_unlock(&inode->i_lock);
}
/**
@@ -208,7 +203,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
* @file: pointer to file structure being freed
*
* Flag files that changed, based on i_version;
- * and decrement the iint readcount/writecount.
+ * and decrement the i_readcount.
*/
void ima_file_free(struct file *file)
{
@@ -217,14 +212,14 @@ void ima_file_free(struct file *file)
if (!iint_initialized || !S_ISREG(inode->i_mode))
return;
- iint = ima_iint_find_get(inode);
- if (!iint)
- return;
- mutex_lock(&iint->mutex);
- ima_dec_counts(iint, inode, file);
- mutex_unlock(&iint->mutex);
- kref_put(&iint->refcount, iint_free);
+ iint = ima_iint_find(inode);
+
+ if (iint)
+ ima_file_free_iint(iint, inode, file);
+ else
+ ima_file_free_noiint(inode, file);
+
}
static int process_measurement(struct file *file, const unsigned char *filename,
@@ -236,11 +231,21 @@ static int process_measurement(struct file *file, const unsigned char *filename,
if (!ima_initialized || !S_ISREG(inode->i_mode))
return 0;
- iint = ima_iint_find_get(inode);
- if (!iint)
- return -ENOMEM;
+
+ rc = ima_must_measure(NULL, inode, mask, function);
+ if (rc != 0)
+ return rc;
+retry:
+ iint = ima_iint_find(inode);
+ if (!iint) {
+ rc = ima_inode_alloc(inode);
+ if (!rc || rc == -EEXIST)
+ goto retry;
+ return rc;
+ }
mutex_lock(&iint->mutex);
+
rc = ima_must_measure(iint, inode, mask, function);
if (rc != 0)
goto out;
@@ -250,7 +255,6 @@ static int process_measurement(struct file *file, const unsigned char *filename,
ima_store_measurement(iint, file, filename);
out:
mutex_unlock(&iint->mutex);
- kref_put(&iint->refcount, iint_free);
return rc;
}
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index f8e7251ae2c8..504bdd2452bd 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -207,7 +207,7 @@ static int install_process_keyring(void)
ret = install_process_keyring_to_cred(new);
if (ret < 0) {
abort_creds(new);
- return ret != -EEXIST ?: 0;
+ return ret != -EEXIST ? ret : 0;
}
return commit_creds(new);
diff --git a/security/security.c b/security/security.c
index b50f472061a4..3ef5e2a7a741 100644
--- a/security/security.c
+++ b/security/security.c
@@ -325,16 +325,8 @@ EXPORT_SYMBOL(security_sb_parse_opts_str);
int security_inode_alloc(struct inode *inode)
{
- int ret;
-
inode->i_security = NULL;
- ret = security_ops->inode_alloc_security(inode);
- if (ret)
- return ret;
- ret = ima_inode_alloc(inode);
- if (ret)
- security_inode_free(inode);
- return ret;
+ return security_ops->inode_alloc_security(inode);
}
void security_inode_free(struct inode *inode)
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 87e0556bae70..55a755c1a1bd 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -978,6 +978,7 @@ static struct inode *sel_make_inode(struct super_block *sb, int mode)
struct inode *ret = new_inode(sb);
if (ret) {
+ ret->i_ino = get_next_ino();
ret->i_mode = mode;
ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
}
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c
index ed8ccd680102..1d0bf8fa1922 100644
--- a/security/tomoyo/realpath.c
+++ b/security/tomoyo/realpath.c
@@ -127,10 +127,8 @@ char *tomoyo_realpath_from_path(struct path *path)
/* If we don't have a vfsmount, we can't calculate. */
if (!path->mnt)
break;
- spin_lock(&dcache_lock);
/* go to whatever namespace root we are under */
pos = __d_path(path, &ns_root, buf, buf_len);
- spin_unlock(&dcache_lock);
/* Prepend "/proc" prefix if using internal proc vfs mount. */
if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
(path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
diff --git a/sound/core/init.c b/sound/core/init.c
index f7c3df8b521b..57b792e2439a 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -604,11 +604,16 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr,
return -EEXIST;
}
for (idx = 0; idx < snd_ecards_limit; idx++) {
- if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1))
- goto __exist;
+ if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) {
+ if (card == snd_cards[idx])
+ goto __ok;
+ else
+ goto __exist;
+ }
}
strcpy(card->id, buf1);
snd_info_card_id_change(card);
+__ok:
mutex_unlock(&snd_card_mutex);
return count;
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index f50ebf20df96..822dd56993ca 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -77,7 +77,7 @@ static int snd_mixer_oss_release(struct inode *inode, struct file *file)
struct snd_mixer_oss_file *fmixer;
if (file->private_data) {
- fmixer = (struct snd_mixer_oss_file *) file->private_data;
+ fmixer = file->private_data;
module_put(fmixer->card->module);
snd_card_file_remove(fmixer->card, file);
kfree(fmixer);
@@ -368,7 +368,7 @@ static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int
static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- return snd_mixer_oss_ioctl1((struct snd_mixer_oss_file *) file->private_data, cmd, arg);
+ return snd_mixer_oss_ioctl1(file->private_data, cmd, arg);
}
int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg)
@@ -582,7 +582,7 @@ static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
struct snd_mixer_oss_slot *pslot,
int *left, int *right)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
*left = *right = 100;
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
@@ -618,8 +618,10 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN)
return;
down_read(&card->controls_rwsem);
- if ((kctl = snd_ctl_find_numid(card, numid)) == NULL)
+ if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
+ up_read(&card->controls_rwsem);
return;
+ }
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
@@ -658,7 +660,7 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
return;
down_read(&card->controls_rwsem);
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
- up_read(&fmixer->card->controls_rwsem);
+ up_read(&card->controls_rwsem);
return;
}
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
@@ -691,7 +693,7 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
struct snd_mixer_oss_slot *pslot,
int left, int right)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
@@ -740,7 +742,7 @@ static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
struct snd_mixer_oss_slot *pslot,
int *active)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
int left, right;
left = right = 1;
@@ -753,7 +755,7 @@ static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer,
struct snd_mixer_oss_slot *pslot,
int *active)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
int left, right;
left = right = 1;
@@ -766,7 +768,7 @@ static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
struct snd_mixer_oss_slot *pslot,
int active)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0);
return 0;
@@ -776,7 +778,7 @@ static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer,
struct snd_mixer_oss_slot *pslot,
int active)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1);
return 0;
@@ -797,7 +799,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL) {
err = -ENOMEM;
- goto __unlock;
+ goto __free_only;
}
down_read(&card->controls_rwsem);
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
@@ -813,7 +815,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
pslot = &mixer->slots[idx];
- slot = (struct slot *)pslot->private_data;
+ slot = pslot->private_data;
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
continue;
if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
@@ -826,6 +828,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
err = 0;
__unlock:
up_read(&card->controls_rwsem);
+ __free_only:
kfree(uctl);
kfree(uinfo);
return err;
@@ -847,7 +850,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL) {
err = -ENOMEM;
- goto __unlock;
+ goto __free_only;
}
down_read(&card->controls_rwsem);
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
@@ -861,7 +864,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
pslot = &mixer->slots[idx];
- slot = (struct slot *)pslot->private_data;
+ slot = pslot->private_data;
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
continue;
if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
@@ -880,6 +883,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
err = 0;
__unlock:
up_read(&card->controls_rwsem);
+ __free_only:
kfree(uctl);
kfree(uinfo);
return err;
@@ -925,7 +929,7 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl
static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
{
- struct slot *p = (struct slot *)chn->private_data;
+ struct slot *p = chn->private_data;
if (p) {
if (p->allocated && p->assigned) {
kfree(p->assigned->name);
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index ac242a377aea..6b4b1287b314 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -364,8 +364,7 @@ static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- snd_pcm_proc_info_read((struct snd_pcm_substream *)entry->private_data,
- buffer);
+ snd_pcm_proc_info_read(entry->private_data, buffer);
}
static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index e23e0e7ab26f..a1707cca9c66 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -334,11 +334,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
/* delta = "expected next hw_ptr" for in_interrupt != 0 */
delta = runtime->hw_ptr_interrupt + runtime->period_size;
if (delta > new_hw_ptr) {
- hw_base += runtime->buffer_size;
- if (hw_base >= runtime->boundary)
- hw_base = 0;
- new_hw_ptr = hw_base + pos;
- goto __delta;
+ /* check for double acknowledged interrupts */
+ hdelta = jiffies - runtime->hw_ptr_jiffies;
+ if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
+ hw_base += runtime->buffer_size;
+ if (hw_base >= runtime->boundary)
+ hw_base = 0;
+ new_hw_ptr = hw_base + pos;
+ goto __delta;
+ }
}
}
/* new_hw_ptr might be lower than old_hw_ptr in case when */
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index d4eb2ef80784..8bc7cb3db330 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -142,7 +142,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
#ifdef RULES_DEBUG
#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v
-char *snd_pcm_hw_param_names[] = {
+static const char * const snd_pcm_hw_param_names[] = {
HW_PARAM(ACCESS),
HW_PARAM(FORMAT),
HW_PARAM(SUBFORMAT),
@@ -864,6 +864,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
runtime->hw_ptr_jiffies = jiffies;
+ runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) /
+ runtime->rate;
runtime->status->state = state;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
index 480c38623da8..c8961165277c 100644
--- a/sound/drivers/Kconfig
+++ b/sound/drivers/Kconfig
@@ -74,6 +74,25 @@ config SND_DUMMY
To compile this driver as a module, choose M here: the module
will be called snd-dummy.
+config SND_ALOOP
+ tristate "Generic loopback driver (PCM)"
+ select SND_PCM
+ help
+ Say 'Y' or 'M' to include support for the PCM loopback device.
+ This module returns played samples back to the user space using
+ the standard ALSA PCM device. The devices are routed 0->1 and
+ 1->0, where first number is the playback PCM device and second
+ number is the capture device. Module creates two PCM devices and
+ configured number of substreams (see the pcm_substreams module
+ parameter).
+
+ The looback device allow time sychronization with an external
+ timing source using the time shift universal control (+-20%
+ of system time).
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-aloop.
+
config SND_VIRMIDI
tristate "Virtual MIDI soundcard"
depends on SND_SEQUENCER
diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile
index d4a07f9ff2c7..1a8440c8b138 100644
--- a/sound/drivers/Makefile
+++ b/sound/drivers/Makefile
@@ -4,6 +4,7 @@
#
snd-dummy-objs := dummy.o
+snd-aloop-objs := aloop.o
snd-mtpav-objs := mtpav.o
snd-mts64-objs := mts64.o
snd-portman2x4-objs := portman2x4.o
@@ -13,6 +14,7 @@ snd-ml403-ac97cr-objs := ml403-ac97cr.o pcm-indirect2.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_DUMMY) += snd-dummy.o
+obj-$(CONFIG_SND_ALOOP) += snd-aloop.o
obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
new file mode 100644
index 000000000000..12b44b0b6777
--- /dev/null
+++ b/sound/drivers/aloop.c
@@ -0,0 +1,1258 @@
+/*
+ * Loopback soundcard
+ *
+ * Original code:
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ *
+ * More accurate positioning and full-duplex support:
+ * Copyright (c) Ahmet İnan <ainan at mathematik.uni-freiburg.de>
+ *
+ * Major (almost complete) rewrite:
+ * Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ * A next major update in 2010 (separate timers for playback and capture):
+ * Copyright (c) Jaroslav Kysela <perex@perex.cz>
+ *
+ * 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/init.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
+MODULE_DESCRIPTION("A loopback soundcard");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}");
+
+#define MAX_PCM_SUBSTREAMS 8
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
+static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
+static int pcm_notify[SNDRV_CARDS];
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for loopback soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for loopback soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable this loopback soundcard.");
+module_param_array(pcm_substreams, int, NULL, 0444);
+MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver.");
+module_param_array(pcm_notify, int, NULL, 0444);
+MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes.");
+
+#define NO_PITCH 100000
+
+struct loopback_pcm;
+
+struct loopback_cable {
+ spinlock_t lock;
+ struct loopback_pcm *streams[2];
+ struct snd_pcm_hardware hw;
+ /* flags */
+ unsigned int valid;
+ unsigned int running;
+ unsigned int pause;
+};
+
+struct loopback_setup {
+ unsigned int notify: 1;
+ unsigned int rate_shift;
+ unsigned int format;
+ unsigned int rate;
+ unsigned int channels;
+ struct snd_ctl_elem_id active_id;
+ struct snd_ctl_elem_id format_id;
+ struct snd_ctl_elem_id rate_id;
+ struct snd_ctl_elem_id channels_id;
+};
+
+struct loopback {
+ struct snd_card *card;
+ struct mutex cable_lock;
+ struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2];
+ struct snd_pcm *pcm[2];
+ struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2];
+};
+
+struct loopback_pcm {
+ struct loopback *loopback;
+ struct snd_pcm_substream *substream;
+ struct loopback_cable *cable;
+ unsigned int pcm_buffer_size;
+ unsigned int buf_pos; /* position in buffer */
+ unsigned int silent_size;
+ /* PCM parameters */
+ unsigned int pcm_period_size;
+ unsigned int pcm_bps; /* bytes per second */
+ unsigned int pcm_salign; /* bytes per sample * channels */
+ unsigned int pcm_rate_shift; /* rate shift value */
+ /* flags */
+ unsigned int period_update_pending :1;
+ /* timer stuff */
+ unsigned int irq_pos; /* fractional IRQ position */
+ unsigned int period_size_frac;
+ unsigned long last_jiffies;
+ struct timer_list timer;
+};
+
+static struct platform_device *devices[SNDRV_CARDS];
+
+static inline unsigned int byte_pos(struct loopback_pcm *dpcm, unsigned int x)
+{
+ if (dpcm->pcm_rate_shift == NO_PITCH) {
+ x /= HZ;
+ } else {
+ x = div_u64(NO_PITCH * (unsigned long long)x,
+ HZ * (unsigned long long)dpcm->pcm_rate_shift);
+ }
+ return x - (x % dpcm->pcm_salign);
+}
+
+static inline unsigned int frac_pos(struct loopback_pcm *dpcm, unsigned int x)
+{
+ if (dpcm->pcm_rate_shift == NO_PITCH) { /* no pitch */
+ return x * HZ;
+ } else {
+ x = div_u64(dpcm->pcm_rate_shift * (unsigned long long)x * HZ,
+ NO_PITCH);
+ }
+ return x;
+}
+
+static inline struct loopback_setup *get_setup(struct loopback_pcm *dpcm)
+{
+ int device = dpcm->substream->pstr->pcm->device;
+
+ if (dpcm->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ device ^= 1;
+ return &dpcm->loopback->setup[dpcm->substream->number][device];
+}
+
+static inline unsigned int get_notify(struct loopback_pcm *dpcm)
+{
+ return get_setup(dpcm)->notify;
+}
+
+static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm)
+{
+ return get_setup(dpcm)->rate_shift;
+}
+
+static void loopback_timer_start(struct loopback_pcm *dpcm)
+{
+ unsigned long tick;
+ unsigned int rate_shift = get_rate_shift(dpcm);
+
+ if (rate_shift != dpcm->pcm_rate_shift) {
+ dpcm->pcm_rate_shift = rate_shift;
+ dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size);
+ }
+ if (dpcm->period_size_frac <= dpcm->irq_pos) {
+ dpcm->irq_pos %= dpcm->period_size_frac;
+ dpcm->period_update_pending = 1;
+ }
+ tick = dpcm->period_size_frac - dpcm->irq_pos;
+ tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps;
+ dpcm->timer.expires = jiffies + tick;
+ add_timer(&dpcm->timer);
+}
+
+static inline void loopback_timer_stop(struct loopback_pcm *dpcm)
+{
+ del_timer(&dpcm->timer);
+ dpcm->timer.expires = 0;
+}
+
+#define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK)
+#define CABLE_VALID_CAPTURE (1 << SNDRV_PCM_STREAM_CAPTURE)
+#define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE)
+
+static int loopback_check_format(struct loopback_cable *cable, int stream)
+{
+ struct snd_pcm_runtime *runtime, *cruntime;
+ struct loopback_setup *setup;
+ struct snd_card *card;
+ int check;
+
+ if (cable->valid != CABLE_VALID_BOTH) {
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ goto __notify;
+ return 0;
+ }
+ runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
+ substream->runtime;
+ cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
+ substream->runtime;
+ check = runtime->format != cruntime->format ||
+ runtime->rate != cruntime->rate ||
+ runtime->channels != cruntime->channels;
+ if (!check)
+ return 0;
+ if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+ return -EIO;
+ } else {
+ snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
+ substream, SNDRV_PCM_STATE_DRAINING);
+ __notify:
+ runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
+ substream->runtime;
+ setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]);
+ card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card;
+ if (setup->format != runtime->format) {
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &setup->format_id);
+ setup->format = runtime->format;
+ }
+ if (setup->rate != runtime->rate) {
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &setup->rate_id);
+ setup->rate = runtime->rate;
+ }
+ if (setup->channels != runtime->channels) {
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &setup->channels_id);
+ setup->channels = runtime->channels;
+ }
+ }
+ return 0;
+}
+
+static void loopback_active_notify(struct loopback_pcm *dpcm)
+{
+ snd_ctl_notify(dpcm->loopback->card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &get_setup(dpcm)->active_id);
+}
+
+static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct loopback_pcm *dpcm = runtime->private_data;
+ struct loopback_cable *cable = dpcm->cable;
+ int err, stream = 1 << substream->stream;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ err = loopback_check_format(cable, substream->stream);
+ if (err < 0)
+ return err;
+ dpcm->last_jiffies = jiffies;
+ dpcm->pcm_rate_shift = 0;
+ spin_lock(&cable->lock);
+ cable->running |= stream;
+ cable->pause &= ~stream;
+ spin_unlock(&cable->lock);
+ loopback_timer_start(dpcm);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ loopback_active_notify(dpcm);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ spin_lock(&cable->lock);
+ cable->running &= ~stream;
+ cable->pause &= ~stream;
+ spin_unlock(&cable->lock);
+ loopback_timer_stop(dpcm);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ loopback_active_notify(dpcm);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ spin_lock(&cable->lock);
+ cable->pause |= stream;
+ spin_unlock(&cable->lock);
+ loopback_timer_stop(dpcm);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ spin_lock(&cable->lock);
+ dpcm->last_jiffies = jiffies;
+ cable->pause &= ~stream;
+ spin_unlock(&cable->lock);
+ loopback_timer_start(dpcm);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void params_change_substream(struct loopback_pcm *dpcm,
+ struct snd_pcm_runtime *runtime)
+{
+ struct snd_pcm_runtime *dst_runtime;
+
+ if (dpcm == NULL || dpcm->substream == NULL)
+ return;
+ dst_runtime = dpcm->substream->runtime;
+ if (dst_runtime == NULL)
+ return;
+ dst_runtime->hw = dpcm->cable->hw;
+}
+
+static void params_change(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct loopback_pcm *dpcm = runtime->private_data;
+ struct loopback_cable *cable = dpcm->cable;
+
+ cable->hw.formats = (1ULL << runtime->format);
+ cable->hw.rate_min = runtime->rate;
+ cable->hw.rate_max = runtime->rate;
+ cable->hw.channels_min = runtime->channels;
+ cable->hw.channels_max = runtime->channels;
+ params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
+ runtime);
+ params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE],
+ runtime);
+}
+
+static int loopback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct loopback_pcm *dpcm = runtime->private_data;
+ struct loopback_cable *cable = dpcm->cable;
+ int bps, salign;
+
+ salign = (snd_pcm_format_width(runtime->format) *
+ runtime->channels) / 8;
+ bps = salign * runtime->rate;
+ if (bps <= 0 || salign <= 0)
+ return -EINVAL;
+
+ dpcm->buf_pos = 0;
+ dpcm->pcm_buffer_size = frames_to_bytes(runtime, runtime->buffer_size);
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ /* clear capture buffer */
+ dpcm->silent_size = dpcm->pcm_buffer_size;
+ snd_pcm_format_set_silence(runtime->format, runtime->dma_area,
+ runtime->buffer_size * runtime->channels);
+ }
+
+ dpcm->irq_pos = 0;
+ dpcm->period_update_pending = 0;
+ dpcm->pcm_bps = bps;
+ dpcm->pcm_salign = salign;
+ dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size);
+
+ mutex_lock(&dpcm->loopback->cable_lock);
+ if (!(cable->valid & ~(1 << substream->stream)) ||
+ (get_setup(dpcm)->notify &&
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
+ params_change(substream);
+ cable->valid |= 1 << substream->stream;
+ mutex_unlock(&dpcm->loopback->cable_lock);
+
+ return 0;
+}
+
+static void clear_capture_buf(struct loopback_pcm *dpcm, unsigned int bytes)
+{
+ struct snd_pcm_runtime *runtime = dpcm->substream->runtime;
+ char *dst = runtime->dma_area;
+ unsigned int dst_off = dpcm->buf_pos;
+
+ if (dpcm->silent_size >= dpcm->pcm_buffer_size)
+ return;
+ if (dpcm->silent_size + bytes > dpcm->pcm_buffer_size)
+ bytes = dpcm->pcm_buffer_size - dpcm->silent_size;
+
+ for (;;) {
+ unsigned int size = bytes;
+ if (dst_off + size > dpcm->pcm_buffer_size)
+ size = dpcm->pcm_buffer_size - dst_off;
+ snd_pcm_format_set_silence(runtime->format, dst + dst_off,
+ bytes_to_frames(runtime, size) *
+ runtime->channels);
+ dpcm->silent_size += size;
+ bytes -= size;
+ if (!bytes)
+ break;
+ dst_off = 0;
+ }
+}
+
+static void copy_play_buf(struct loopback_pcm *play,
+ struct loopback_pcm *capt,
+ unsigned int bytes)
+{
+ struct snd_pcm_runtime *runtime = play->substream->runtime;
+ char *src = runtime->dma_area;
+ char *dst = capt->substream->runtime->dma_area;
+ unsigned int src_off = play->buf_pos;
+ unsigned int dst_off = capt->buf_pos;
+ unsigned int clear_bytes = 0;
+
+ /* check if playback is draining, trim the capture copy size
+ * when our pointer is at the end of playback ring buffer */
+ if (runtime->status->state == SNDRV_PCM_STATE_DRAINING &&
+ snd_pcm_playback_hw_avail(runtime) < runtime->buffer_size) {
+ snd_pcm_uframes_t appl_ptr, appl_ptr1, diff;
+ appl_ptr = appl_ptr1 = runtime->control->appl_ptr;
+ appl_ptr1 -= appl_ptr1 % runtime->buffer_size;
+ appl_ptr1 += play->buf_pos / play->pcm_salign;
+ if (appl_ptr < appl_ptr1)
+ appl_ptr1 -= runtime->buffer_size;
+ diff = (appl_ptr - appl_ptr1) * play->pcm_salign;
+ if (diff < bytes) {
+ clear_bytes = bytes - diff;
+ bytes = diff;
+ }
+ }
+
+ for (;;) {
+ unsigned int size = bytes;
+ if (src_off + size > play->pcm_buffer_size)
+ size = play->pcm_buffer_size - src_off;
+ if (dst_off + size > capt->pcm_buffer_size)
+ size = capt->pcm_buffer_size - dst_off;
+ memcpy(dst + dst_off, src + src_off, size);
+ capt->silent_size = 0;
+ bytes -= size;
+ if (!bytes)
+ break;
+ src_off = (src_off + size) % play->pcm_buffer_size;
+ dst_off = (dst_off + size) % capt->pcm_buffer_size;
+ }
+
+ if (clear_bytes > 0) {
+ clear_capture_buf(capt, clear_bytes);
+ capt->silent_size = 0;
+ }
+}
+
+#define BYTEPOS_UPDATE_POSONLY 0
+#define BYTEPOS_UPDATE_CLEAR 1
+#define BYTEPOS_UPDATE_COPY 2
+
+static void loopback_bytepos_update(struct loopback_pcm *dpcm,
+ unsigned int delta,
+ unsigned int cmd)
+{
+ unsigned int count;
+ unsigned long last_pos;
+
+ last_pos = byte_pos(dpcm, dpcm->irq_pos);
+ dpcm->irq_pos += delta * dpcm->pcm_bps;
+ count = byte_pos(dpcm, dpcm->irq_pos) - last_pos;
+ if (!count)
+ return;
+ if (cmd == BYTEPOS_UPDATE_CLEAR)
+ clear_capture_buf(dpcm, count);
+ else if (cmd == BYTEPOS_UPDATE_COPY)
+ copy_play_buf(dpcm->cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
+ dpcm->cable->streams[SNDRV_PCM_STREAM_CAPTURE],
+ count);
+ dpcm->buf_pos += count;
+ dpcm->buf_pos %= dpcm->pcm_buffer_size;
+ if (dpcm->irq_pos >= dpcm->period_size_frac) {
+ dpcm->irq_pos %= dpcm->period_size_frac;
+ dpcm->period_update_pending = 1;
+ }
+}
+
+static unsigned int loopback_pos_update(struct loopback_cable *cable)
+{
+ struct loopback_pcm *dpcm_play =
+ cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
+ struct loopback_pcm *dpcm_capt =
+ cable->streams[SNDRV_PCM_STREAM_CAPTURE];
+ unsigned long delta_play = 0, delta_capt = 0;
+ unsigned int running;
+
+ spin_lock(&cable->lock);
+ running = cable->running ^ cable->pause;
+ if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) {
+ delta_play = jiffies - dpcm_play->last_jiffies;
+ dpcm_play->last_jiffies += delta_play;
+ }
+
+ if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) {
+ delta_capt = jiffies - dpcm_capt->last_jiffies;
+ dpcm_capt->last_jiffies += delta_capt;
+ }
+
+ if (delta_play == 0 && delta_capt == 0) {
+ spin_unlock(&cable->lock);
+ return running;
+ }
+
+ if (delta_play > delta_capt) {
+ loopback_bytepos_update(dpcm_play, delta_play - delta_capt,
+ BYTEPOS_UPDATE_POSONLY);
+ delta_play = delta_capt;
+ } else if (delta_play < delta_capt) {
+ loopback_bytepos_update(dpcm_capt, delta_capt - delta_play,
+ BYTEPOS_UPDATE_CLEAR);
+ delta_capt = delta_play;
+ }
+
+ if (delta_play == 0 && delta_capt == 0) {
+ spin_unlock(&cable->lock);
+ return running;
+ }
+ /* note delta_capt == delta_play at this moment */
+ loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY);
+ loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY);
+ spin_unlock(&cable->lock);
+ return running;
+}
+
+static void loopback_timer_function(unsigned long data)
+{
+ struct loopback_pcm *dpcm = (struct loopback_pcm *)data;
+ unsigned int running;
+
+ running = loopback_pos_update(dpcm->cable);
+ if (running & (1 << dpcm->substream->stream)) {
+ loopback_timer_start(dpcm);
+ if (dpcm->period_update_pending) {
+ dpcm->period_update_pending = 0;
+ snd_pcm_period_elapsed(dpcm->substream);
+ }
+ }
+}
+
+static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct loopback_pcm *dpcm = runtime->private_data;
+
+ loopback_pos_update(dpcm->cable);
+ return bytes_to_frames(runtime, dpcm->buf_pos);
+}
+
+static struct snd_pcm_hardware loopback_pcm_hardware =
+{
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |
+ SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE),
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 32,
+ .buffer_bytes_max = 2 * 1024 * 1024,
+ .period_bytes_min = 64,
+ /* note check overflow in frac_pos() using pcm_rate_shift before
+ changing period_bytes_max value */
+ .period_bytes_max = 1024 * 1024,
+ .periods_min = 1,
+ .periods_max = 1024,
+ .fifo_size = 0,
+};
+
+static void loopback_runtime_free(struct snd_pcm_runtime *runtime)
+{
+ struct loopback_pcm *dpcm = runtime->private_data;
+ kfree(dpcm);
+}
+
+static int loopback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+}
+
+static int loopback_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct loopback_pcm *dpcm = runtime->private_data;
+ struct loopback_cable *cable = dpcm->cable;
+
+ mutex_lock(&dpcm->loopback->cable_lock);
+ cable->valid &= ~(1 << substream->stream);
+ mutex_unlock(&dpcm->loopback->cable_lock);
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static unsigned int get_cable_index(struct snd_pcm_substream *substream)
+{
+ if (!substream->pcm->device)
+ return substream->stream;
+ else
+ return !substream->stream;
+}
+
+static int rule_format(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+
+ struct snd_pcm_hardware *hw = rule->private;
+ struct snd_mask *maskp = hw_param_mask(params, rule->var);
+
+ maskp->bits[0] &= (u_int32_t)hw->formats;
+ maskp->bits[1] &= (u_int32_t)(hw->formats >> 32);
+ memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
+ if (! maskp->bits[0] && ! maskp->bits[1])
+ return -EINVAL;
+ return 0;
+}
+
+static int rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_pcm_hardware *hw = rule->private;
+ struct snd_interval t;
+
+ t.min = hw->rate_min;
+ t.max = hw->rate_max;
+ t.openmin = t.openmax = 0;
+ t.integer = 0;
+ return snd_interval_refine(hw_param_interval(params, rule->var), &t);
+}
+
+static int rule_channels(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_pcm_hardware *hw = rule->private;
+ struct snd_interval t;
+
+ t.min = hw->channels_min;
+ t.max = hw->channels_max;
+ t.openmin = t.openmax = 0;
+ t.integer = 0;
+ return snd_interval_refine(hw_param_interval(params, rule->var), &t);
+}
+
+static int loopback_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct loopback *loopback = substream->private_data;
+ struct loopback_pcm *dpcm;
+ struct loopback_cable *cable;
+ int err = 0;
+ int dev = get_cable_index(substream);
+
+ mutex_lock(&loopback->cable_lock);
+ dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
+ if (!dpcm) {
+ err = -ENOMEM;
+ goto unlock;
+ }
+ dpcm->loopback = loopback;
+ dpcm->substream = substream;
+ setup_timer(&dpcm->timer, loopback_timer_function,
+ (unsigned long)dpcm);
+
+ cable = loopback->cables[substream->number][dev];
+ if (!cable) {
+ cable = kzalloc(sizeof(*cable), GFP_KERNEL);
+ if (!cable) {
+ kfree(dpcm);
+ err = -ENOMEM;
+ goto unlock;
+ }
+ spin_lock_init(&cable->lock);
+ cable->hw = loopback_pcm_hardware;
+ loopback->cables[substream->number][dev] = cable;
+ }
+ dpcm->cable = cable;
+ cable->streams[substream->stream] = dpcm;
+
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+
+ /* use dynamic rules based on actual runtime->hw values */
+ /* note that the default rules created in the PCM midlevel code */
+ /* are cached -> they do not reflect the actual state */
+ err = snd_pcm_hw_rule_add(runtime, 0,
+ SNDRV_PCM_HW_PARAM_FORMAT,
+ rule_format, &runtime->hw,
+ SNDRV_PCM_HW_PARAM_FORMAT, -1);
+ if (err < 0)
+ goto unlock;
+ err = snd_pcm_hw_rule_add(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ rule_rate, &runtime->hw,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+ if (err < 0)
+ goto unlock;
+ err = snd_pcm_hw_rule_add(runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ rule_channels, &runtime->hw,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (err < 0)
+ goto unlock;
+
+ runtime->private_data = dpcm;
+ runtime->private_free = loopback_runtime_free;
+ if (get_notify(dpcm))
+ runtime->hw = loopback_pcm_hardware;
+ else
+ runtime->hw = cable->hw;
+ unlock:
+ mutex_unlock(&loopback->cable_lock);
+ return err;
+}
+
+static int loopback_close(struct snd_pcm_substream *substream)
+{
+ struct loopback *loopback = substream->private_data;
+ struct loopback_pcm *dpcm = substream->runtime->private_data;
+ struct loopback_cable *cable;
+ int dev = get_cable_index(substream);
+
+ loopback_timer_stop(dpcm);
+ mutex_lock(&loopback->cable_lock);
+ cable = loopback->cables[substream->number][dev];
+ if (cable->streams[!substream->stream]) {
+ /* other stream is still alive */
+ cable->streams[substream->stream] = NULL;
+ } else {
+ /* free the cable */
+ loopback->cables[substream->number][dev] = NULL;
+ kfree(cable);
+ }
+ mutex_unlock(&loopback->cable_lock);
+ return 0;
+}
+
+static struct snd_pcm_ops loopback_playback_ops = {
+ .open = loopback_open,
+ .close = loopback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = loopback_hw_params,
+ .hw_free = loopback_hw_free,
+ .prepare = loopback_prepare,
+ .trigger = loopback_trigger,
+ .pointer = loopback_pointer,
+};
+
+static struct snd_pcm_ops loopback_capture_ops = {
+ .open = loopback_open,
+ .close = loopback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = loopback_hw_params,
+ .hw_free = loopback_hw_free,
+ .prepare = loopback_prepare,
+ .trigger = loopback_trigger,
+ .pointer = loopback_pointer,
+};
+
+static int __devinit loopback_pcm_new(struct loopback *loopback,
+ int device, int substreams)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ err = snd_pcm_new(loopback->card, "Loopback PCM", device,
+ substreams, substreams, &pcm);
+ if (err < 0)
+ return err;
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_capture_ops);
+
+ pcm->private_data = loopback;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, "Loopback PCM");
+
+ loopback->pcm[device] = pcm;
+
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ 0, 2 * 1024 * 1024);
+ return 0;
+}
+
+static int loopback_rate_shift_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 80000;
+ uinfo->value.integer.max = 120000;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] =
+ loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].rate_shift;
+ return 0;
+}
+
+static int loopback_rate_shift_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+ int change = 0;
+
+ val = ucontrol->value.integer.value[0];
+ if (val < 80000)
+ val = 80000;
+ if (val > 120000)
+ val = 120000;
+ mutex_lock(&loopback->cable_lock);
+ if (val != loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].rate_shift) {
+ loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].rate_shift = val;
+ change = 1;
+ }
+ mutex_unlock(&loopback->cable_lock);
+ return change;
+}
+
+static int loopback_notify_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] =
+ loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].notify;
+ return 0;
+}
+
+static int loopback_notify_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+ int change = 0;
+
+ val = ucontrol->value.integer.value[0] ? 1 : 0;
+ if (val != loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].notify) {
+ loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].notify = val;
+ change = 1;
+ }
+ return change;
+}
+
+static int loopback_active_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+ struct loopback_cable *cable = loopback->cables
+ [kcontrol->id.subdevice][kcontrol->id.device ^ 1];
+ unsigned int val = 0;
+
+ if (cable != NULL)
+ val = (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
+ 1 : 0;
+ ucontrol->value.integer.value[0] = val;
+ return 0;
+}
+
+static int loopback_format_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int loopback_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] =
+ loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].format;
+ return 0;
+}
+
+static int loopback_rate_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 192000;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int loopback_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] =
+ loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].rate;
+ return 0;
+}
+
+static int loopback_channels_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 1;
+ uinfo->value.integer.max = 1024;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int loopback_channels_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] =
+ loopback->setup[kcontrol->id.subdevice]
+ [kcontrol->id.device].channels;
+ return 0;
+}
+
+static struct snd_kcontrol_new loopback_controls[] __devinitdata = {
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "PCM Rate Shift 100000",
+ .info = loopback_rate_shift_info,
+ .get = loopback_rate_shift_get,
+ .put = loopback_rate_shift_put,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "PCM Notify",
+ .info = snd_ctl_boolean_mono_info,
+ .get = loopback_notify_get,
+ .put = loopback_notify_put,
+},
+#define ACTIVE_IDX 2
+{
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "PCM Slave Active",
+ .info = snd_ctl_boolean_mono_info,
+ .get = loopback_active_get,
+},
+#define FORMAT_IDX 3
+{
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "PCM Slave Format",
+ .info = loopback_format_info,
+ .get = loopback_format_get
+},
+#define RATE_IDX 4
+{
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "PCM Slave Rate",
+ .info = loopback_rate_info,
+ .get = loopback_rate_get
+},
+#define CHANNELS_IDX 5
+{
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "PCM Slave Channels",
+ .info = loopback_channels_info,
+ .get = loopback_channels_get
+}
+};
+
+static int __devinit loopback_mixer_new(struct loopback *loopback, int notify)
+{
+ struct snd_card *card = loopback->card;
+ struct snd_pcm *pcm;
+ struct snd_kcontrol *kctl;
+ struct loopback_setup *setup;
+ int err, dev, substr, substr_count, idx;
+
+ strcpy(card->mixername, "Loopback Mixer");
+ for (dev = 0; dev < 2; dev++) {
+ pcm = loopback->pcm[dev];
+ substr_count =
+ pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count;
+ for (substr = 0; substr < substr_count; substr++) {
+ setup = &loopback->setup[substr][dev];
+ setup->notify = notify;
+ setup->rate_shift = NO_PITCH;
+ setup->format = SNDRV_PCM_FORMAT_S16_LE;
+ setup->rate = 48000;
+ setup->channels = 2;
+ for (idx = 0; idx < ARRAY_SIZE(loopback_controls);
+ idx++) {
+ kctl = snd_ctl_new1(&loopback_controls[idx],
+ loopback);
+ if (!kctl)
+ return -ENOMEM;
+ kctl->id.device = dev;
+ kctl->id.subdevice = substr;
+ switch (idx) {
+ case ACTIVE_IDX:
+ setup->active_id = kctl->id;
+ break;
+ case FORMAT_IDX:
+ setup->format_id = kctl->id;
+ break;
+ case RATE_IDX:
+ setup->rate_id = kctl->id;
+ break;
+ case CHANNELS_IDX:
+ setup->channels_id = kctl->id;
+ break;
+ default:
+ break;
+ }
+ err = snd_ctl_add(card, kctl);
+ if (err < 0)
+ return err;
+ }
+ }
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+
+static void print_dpcm_info(struct snd_info_buffer *buffer,
+ struct loopback_pcm *dpcm,
+ const char *id)
+{
+ snd_iprintf(buffer, " %s\n", id);
+ if (dpcm == NULL) {
+ snd_iprintf(buffer, " inactive\n");
+ return;
+ }
+ snd_iprintf(buffer, " buffer_size:\t%u\n", dpcm->pcm_buffer_size);
+ snd_iprintf(buffer, " buffer_pos:\t\t%u\n", dpcm->buf_pos);
+ snd_iprintf(buffer, " silent_size:\t%u\n", dpcm->silent_size);
+ snd_iprintf(buffer, " period_size:\t%u\n", dpcm->pcm_period_size);
+ snd_iprintf(buffer, " bytes_per_sec:\t%u\n", dpcm->pcm_bps);
+ snd_iprintf(buffer, " sample_align:\t%u\n", dpcm->pcm_salign);
+ snd_iprintf(buffer, " rate_shift:\t\t%u\n", dpcm->pcm_rate_shift);
+ snd_iprintf(buffer, " update_pending:\t%u\n",
+ dpcm->period_update_pending);
+ snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos);
+ snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac);
+ snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n",
+ dpcm->last_jiffies, jiffies);
+ snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires);
+}
+
+static void print_substream_info(struct snd_info_buffer *buffer,
+ struct loopback *loopback,
+ int sub,
+ int num)
+{
+ struct loopback_cable *cable = loopback->cables[sub][num];
+
+ snd_iprintf(buffer, "Cable %i substream %i:\n", num, sub);
+ if (cable == NULL) {
+ snd_iprintf(buffer, " inactive\n");
+ return;
+ }
+ snd_iprintf(buffer, " valid: %u\n", cable->valid);
+ snd_iprintf(buffer, " running: %u\n", cable->running);
+ snd_iprintf(buffer, " pause: %u\n", cable->pause);
+ print_dpcm_info(buffer, cable->streams[0], "Playback");
+ print_dpcm_info(buffer, cable->streams[1], "Capture");
+}
+
+static void print_cable_info(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct loopback *loopback = entry->private_data;
+ int sub, num;
+
+ mutex_lock(&loopback->cable_lock);
+ num = entry->name[strlen(entry->name)-1];
+ num = num == '0' ? 0 : 1;
+ for (sub = 0; sub < MAX_PCM_SUBSTREAMS; sub++)
+ print_substream_info(buffer, loopback, sub, num);
+ mutex_unlock(&loopback->cable_lock);
+}
+
+static int __devinit loopback_proc_new(struct loopback *loopback, int cidx)
+{
+ char name[32];
+ struct snd_info_entry *entry;
+ int err;
+
+ snprintf(name, sizeof(name), "cable#%d", cidx);
+ err = snd_card_proc_new(loopback->card, name, &entry);
+ if (err < 0)
+ return err;
+
+ snd_info_set_text_ops(entry, loopback, print_cable_info);
+ return 0;
+}
+
+#else /* !CONFIG_PROC_FS */
+
+#define loopback_proc_new(loopback, cidx) do { } while (0)
+
+#endif
+
+static int __devinit loopback_probe(struct platform_device *devptr)
+{
+ struct snd_card *card;
+ struct loopback *loopback;
+ int dev = devptr->id;
+ int err;
+
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct loopback), &card);
+ if (err < 0)
+ return err;
+ loopback = card->private_data;
+
+ if (pcm_substreams[dev] < 1)
+ pcm_substreams[dev] = 1;
+ if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)
+ pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
+
+ loopback->card = card;
+ mutex_init(&loopback->cable_lock);
+
+ err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]);
+ if (err < 0)
+ goto __nodev;
+ err = loopback_pcm_new(loopback, 1, pcm_substreams[dev]);
+ if (err < 0)
+ goto __nodev;
+ err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0);
+ if (err < 0)
+ goto __nodev;
+ loopback_proc_new(loopback, 0);
+ loopback_proc_new(loopback, 1);
+ strcpy(card->driver, "Loopback");
+ strcpy(card->shortname, "Loopback");
+ sprintf(card->longname, "Loopback %i", dev + 1);
+ err = snd_card_register(card);
+ if (!err) {
+ platform_set_drvdata(devptr, card);
+ return 0;
+ }
+ __nodev:
+ snd_card_free(card);
+ return err;
+}
+
+static int __devexit loopback_remove(struct platform_device *devptr)
+{
+ snd_card_free(platform_get_drvdata(devptr));
+ platform_set_drvdata(devptr, NULL);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int loopback_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct snd_card *card = platform_get_drvdata(pdev);
+ struct loopback *loopback = card->private_data;
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+ snd_pcm_suspend_all(loopback->pcm[0]);
+ snd_pcm_suspend_all(loopback->pcm[1]);
+ return 0;
+}
+
+static int loopback_resume(struct platform_device *pdev)
+{
+ struct snd_card *card = platform_get_drvdata(pdev);
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+#endif
+
+#define SND_LOOPBACK_DRIVER "snd_aloop"
+
+static struct platform_driver loopback_driver = {
+ .probe = loopback_probe,
+ .remove = __devexit_p(loopback_remove),
+#ifdef CONFIG_PM
+ .suspend = loopback_suspend,
+ .resume = loopback_resume,
+#endif
+ .driver = {
+ .name = SND_LOOPBACK_DRIVER
+ },
+};
+
+static void loopback_unregister_all(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(devices); ++i)
+ platform_device_unregister(devices[i]);
+ platform_driver_unregister(&loopback_driver);
+}
+
+static int __init alsa_card_loopback_init(void)
+{
+ int i, err, cards;
+
+ err = platform_driver_register(&loopback_driver);
+ if (err < 0)
+ return err;
+
+
+ cards = 0;
+ for (i = 0; i < SNDRV_CARDS; i++) {
+ struct platform_device *device;
+ if (!enable[i])
+ continue;
+ device = platform_device_register_simple(SND_LOOPBACK_DRIVER,
+ i, NULL, 0);
+ if (IS_ERR(device))
+ continue;
+ if (!platform_get_drvdata(device)) {
+ platform_device_unregister(device);
+ continue;
+ }
+ devices[i] = device;
+ cards++;
+ }
+ if (!cards) {
+#ifdef MODULE
+ printk(KERN_ERR "aloop: No loopback enabled\n");
+#endif
+ loopback_unregister_all();
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __exit alsa_card_loopback_exit(void)
+{
+ loopback_unregister_all();
+}
+
+module_init(alsa_card_loopback_init)
+module_exit(alsa_card_loopback_exit)
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c
index 0e631c3221e3..f4cd49336f33 100644
--- a/sound/drivers/virmidi.c
+++ b/sound/drivers/virmidi.c
@@ -94,7 +94,7 @@ static int __devinit snd_virmidi_probe(struct platform_device *devptr)
sizeof(struct snd_card_virmidi), &card);
if (err < 0)
return err;
- vmidi = (struct snd_card_virmidi *)card->private_data;
+ vmidi = card->private_data;
vmidi->card = card;
if (midi_devs[dev] > MAX_MIDI_DEVICES) {
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index 42d7844ecd0b..57ccba88700d 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -878,7 +878,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
static void proc_regs_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data;
+ struct snd_akm4xxx *ak = entry->private_data;
int reg, val, chip;
for (chip = 0; chip < ak->num_chips; chip++) {
for (reg = 0; reg < ak->total_regs; reg++) {
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index c6990c680796..52064cfa91f3 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -77,6 +77,32 @@ config SND_ALS100
To compile this driver as a module, choose M here: the module
will be called snd-als100.
+config SND_AZT1605
+ tristate "Aztech AZT1605 Driver"
+ depends on SND
+ select SND_WSS_LIB
+ select SND_MPU401_UART
+ select SND_OPL3_LIB
+ help
+ Say Y here to include support for Aztech Sound Galaxy cards
+ based on the AZT1605 chipset.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-azt1605.
+
+config SND_AZT2316
+ tristate "Aztech AZT2316 Driver"
+ depends on SND
+ select SND_WSS_LIB
+ select SND_MPU401_UART
+ select SND_OPL3_LIB
+ help
+ Say Y here to include support for Aztech Sound Galaxy cards
+ based on the AZT2316 chipset.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-azt2316.
+
config SND_AZT2320
tristate "Aztech Systems AZT2320"
depends on PNP
@@ -351,16 +377,6 @@ config SND_SB16_CSP
coprocessor can do variable tasks like various compression and
decompression algorithms.
-config SND_SGALAXY
- tristate "Aztech Sound Galaxy"
- select SND_WSS_LIB
- help
- Say Y here to include support for Aztech Sound Galaxy
- soundcards.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-sgalaxy.
-
config SND_SSCAPE
tristate "Ensoniq SoundScape driver"
select SND_MPU401_UART
diff --git a/sound/isa/Makefile b/sound/isa/Makefile
index c73d30c4f462..8d781e419e2e 100644
--- a/sound/isa/Makefile
+++ b/sound/isa/Makefile
@@ -10,7 +10,6 @@ snd-cmi8330-objs := cmi8330.o
snd-es18xx-objs := es18xx.o
snd-opl3sa2-objs := opl3sa2.o
snd-sc6000-objs := sc6000.o
-snd-sgalaxy-objs := sgalaxy.o
snd-sscape-objs := sscape.o
# Toplevel Module Dependency
@@ -21,8 +20,7 @@ obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
obj-$(CONFIG_SND_SC6000) += snd-sc6000.o
-obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o
obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o
-obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ msnd/ opti9xx/ \
+obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ galaxy/ gus/ msnd/ opti9xx/ \
sb/ wavefront/ wss/
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
index bbcbf92a8ebe..3cb75bc97699 100644
--- a/sound/isa/ad1816a/ad1816a.c
+++ b/sound/isa/ad1816a/ad1816a.c
@@ -162,7 +162,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
sizeof(struct snd_card_ad1816a), &card);
if (error < 0)
return error;
- acard = (struct snd_card_ad1816a *)card->private_data;
+ acard = card->private_data;
if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) {
snd_card_free(card);
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c
index f7aa637b0d18..aac8dc15c2fe 100644
--- a/sound/isa/azt2320.c
+++ b/sound/isa/azt2320.c
@@ -188,7 +188,7 @@ static int __devinit snd_card_azt2320_probe(int dev,
sizeof(struct snd_card_azt2320), &card);
if (error < 0)
return error;
- acard = (struct snd_card_azt2320 *)card->private_data;
+ acard = card->private_data;
if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
snd_card_free(card);
diff --git a/sound/isa/galaxy/Makefile b/sound/isa/galaxy/Makefile
new file mode 100644
index 000000000000..e307066d4315
--- /dev/null
+++ b/sound/isa/galaxy/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for ALSA
+# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+#
+
+snd-azt1605-objs := azt1605.o
+snd-azt2316-objs := azt2316.o
+
+obj-$(CONFIG_SND_AZT1605) += snd-azt1605.o
+obj-$(CONFIG_SND_AZT2316) += snd-azt2316.o
diff --git a/sound/isa/galaxy/azt1605.c b/sound/isa/galaxy/azt1605.c
new file mode 100644
index 000000000000..9a97643cb713
--- /dev/null
+++ b/sound/isa/galaxy/azt1605.c
@@ -0,0 +1,91 @@
+/*
+ * Aztech AZT1605 Driver
+ * Copyright (C) 2007,2010 Rene Herman
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define AZT1605
+
+#define CRD_NAME "Aztech AZT1605"
+#define DRV_NAME "AZT1605"
+#define DEV_NAME "azt1605"
+
+#define GALAXY_DSP_MAJOR 2
+#define GALAXY_DSP_MINOR 1
+
+#define GALAXY_CONFIG_SIZE 3
+
+/*
+ * 24-bit config register
+ */
+
+#define GALAXY_CONFIG_SBA_220 (0 << 0)
+#define GALAXY_CONFIG_SBA_240 (1 << 0)
+#define GALAXY_CONFIG_SBA_260 (2 << 0)
+#define GALAXY_CONFIG_SBA_280 (3 << 0)
+#define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280
+
+#define GALAXY_CONFIG_MPUA_300 (0 << 2)
+#define GALAXY_CONFIG_MPUA_330 (1 << 2)
+
+#define GALAXY_CONFIG_MPU_ENABLE (1 << 3)
+
+#define GALAXY_CONFIG_GAME_ENABLE (1 << 4)
+
+#define GALAXY_CONFIG_CD_PANASONIC (1 << 5)
+#define GALAXY_CONFIG_CD_MITSUMI (1 << 6)
+#define GALAXY_CONFIG_CD_MASK (\
+ GALAXY_CONFIG_CD_PANASONIC | GALAXY_CONFIG_CD_MITSUMI)
+
+#define GALAXY_CONFIG_UNUSED (1 << 7)
+#define GALAXY_CONFIG_UNUSED_MASK GALAXY_CONFIG_UNUSED
+
+#define GALAXY_CONFIG_SBIRQ_2 (1 << 8)
+#define GALAXY_CONFIG_SBIRQ_3 (1 << 9)
+#define GALAXY_CONFIG_SBIRQ_5 (1 << 10)
+#define GALAXY_CONFIG_SBIRQ_7 (1 << 11)
+
+#define GALAXY_CONFIG_MPUIRQ_2 (1 << 12)
+#define GALAXY_CONFIG_MPUIRQ_3 (1 << 13)
+#define GALAXY_CONFIG_MPUIRQ_5 (1 << 14)
+#define GALAXY_CONFIG_MPUIRQ_7 (1 << 15)
+
+#define GALAXY_CONFIG_WSSA_530 (0 << 16)
+#define GALAXY_CONFIG_WSSA_604 (1 << 16)
+#define GALAXY_CONFIG_WSSA_E80 (2 << 16)
+#define GALAXY_CONFIG_WSSA_F40 (3 << 16)
+
+#define GALAXY_CONFIG_WSS_ENABLE (1 << 18)
+
+#define GALAXY_CONFIG_CDIRQ_11 (1 << 19)
+#define GALAXY_CONFIG_CDIRQ_12 (1 << 20)
+#define GALAXY_CONFIG_CDIRQ_15 (1 << 21)
+#define GALAXY_CONFIG_CDIRQ_MASK (\
+ GALAXY_CONFIG_CDIRQ_11 | GALAXY_CONFIG_CDIRQ_12 |\
+ GALAXY_CONFIG_CDIRQ_15)
+
+#define GALAXY_CONFIG_CDDMA_DISABLE (0 << 22)
+#define GALAXY_CONFIG_CDDMA_0 (1 << 22)
+#define GALAXY_CONFIG_CDDMA_1 (2 << 22)
+#define GALAXY_CONFIG_CDDMA_3 (3 << 22)
+#define GALAXY_CONFIG_CDDMA_MASK GALAXY_CONFIG_CDDMA_3
+
+#define GALAXY_CONFIG_MASK (\
+ GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CD_MASK |\
+ GALAXY_CONFIG_UNUSED_MASK | GALAXY_CONFIG_CDIRQ_MASK |\
+ GALAXY_CONFIG_CDDMA_MASK)
+
+#include "galaxy.c"
diff --git a/sound/isa/galaxy/azt2316.c b/sound/isa/galaxy/azt2316.c
new file mode 100644
index 000000000000..189441141df6
--- /dev/null
+++ b/sound/isa/galaxy/azt2316.c
@@ -0,0 +1,111 @@
+/*
+ * Aztech AZT2316 Driver
+ * Copyright (C) 2007,2010 Rene Herman
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define AZT2316
+
+#define CRD_NAME "Aztech AZT2316"
+#define DRV_NAME "AZT2316"
+#define DEV_NAME "azt2316"
+
+#define GALAXY_DSP_MAJOR 3
+#define GALAXY_DSP_MINOR 1
+
+#define GALAXY_CONFIG_SIZE 4
+
+/*
+ * 32-bit config register
+ */
+
+#define GALAXY_CONFIG_SBA_220 (0 << 0)
+#define GALAXY_CONFIG_SBA_240 (1 << 0)
+#define GALAXY_CONFIG_SBA_260 (2 << 0)
+#define GALAXY_CONFIG_SBA_280 (3 << 0)
+#define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280
+
+#define GALAXY_CONFIG_SBIRQ_2 (1 << 2)
+#define GALAXY_CONFIG_SBIRQ_5 (1 << 3)
+#define GALAXY_CONFIG_SBIRQ_7 (1 << 4)
+#define GALAXY_CONFIG_SBIRQ_10 (1 << 5)
+
+#define GALAXY_CONFIG_SBDMA_DISABLE (0 << 6)
+#define GALAXY_CONFIG_SBDMA_0 (1 << 6)
+#define GALAXY_CONFIG_SBDMA_1 (2 << 6)
+#define GALAXY_CONFIG_SBDMA_3 (3 << 6)
+
+#define GALAXY_CONFIG_WSSA_530 (0 << 8)
+#define GALAXY_CONFIG_WSSA_604 (1 << 8)
+#define GALAXY_CONFIG_WSSA_E80 (2 << 8)
+#define GALAXY_CONFIG_WSSA_F40 (3 << 8)
+
+#define GALAXY_CONFIG_WSS_ENABLE (1 << 10)
+
+#define GALAXY_CONFIG_GAME_ENABLE (1 << 11)
+
+#define GALAXY_CONFIG_MPUA_300 (0 << 12)
+#define GALAXY_CONFIG_MPUA_330 (1 << 12)
+
+#define GALAXY_CONFIG_MPU_ENABLE (1 << 13)
+
+#define GALAXY_CONFIG_CDA_310 (0 << 14)
+#define GALAXY_CONFIG_CDA_320 (1 << 14)
+#define GALAXY_CONFIG_CDA_340 (2 << 14)
+#define GALAXY_CONFIG_CDA_350 (3 << 14)
+#define GALAXY_CONFIG_CDA_MASK GALAXY_CONFIG_CDA_350
+
+#define GALAXY_CONFIG_CD_DISABLE (0 << 16)
+#define GALAXY_CONFIG_CD_PANASONIC (1 << 16)
+#define GALAXY_CONFIG_CD_SONY (2 << 16)
+#define GALAXY_CONFIG_CD_MITSUMI (3 << 16)
+#define GALAXY_CONFIG_CD_AZTECH (4 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_5 (5 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_6 (6 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_7 (7 << 16)
+#define GALAXY_CONFIG_CD_MASK GALAXY_CONFIG_CD_UNUSED_7
+
+#define GALAXY_CONFIG_CDDMA8_DISABLE (0 << 20)
+#define GALAXY_CONFIG_CDDMA8_0 (1 << 20)
+#define GALAXY_CONFIG_CDDMA8_1 (2 << 20)
+#define GALAXY_CONFIG_CDDMA8_3 (3 << 20)
+#define GALAXY_CONFIG_CDDMA8_MASK GALAXY_CONFIG_CDDMA8_3
+
+#define GALAXY_CONFIG_CDDMA16_DISABLE (0 << 22)
+#define GALAXY_CONFIG_CDDMA16_5 (1 << 22)
+#define GALAXY_CONFIG_CDDMA16_6 (2 << 22)
+#define GALAXY_CONFIG_CDDMA16_7 (3 << 22)
+#define GALAXY_CONFIG_CDDMA16_MASK GALAXY_CONFIG_CDDMA16_7
+
+#define GALAXY_CONFIG_MPUIRQ_2 (1 << 24)
+#define GALAXY_CONFIG_MPUIRQ_5 (1 << 25)
+#define GALAXY_CONFIG_MPUIRQ_7 (1 << 26)
+#define GALAXY_CONFIG_MPUIRQ_10 (1 << 27)
+
+#define GALAXY_CONFIG_CDIRQ_5 (1 << 28)
+#define GALAXY_CONFIG_CDIRQ_11 (1 << 29)
+#define GALAXY_CONFIG_CDIRQ_12 (1 << 30)
+#define GALAXY_CONFIG_CDIRQ_15 (1 << 31)
+#define GALAXY_CONFIG_CDIRQ_MASK (\
+ GALAXY_CONFIG_CDIRQ_5 | GALAXY_CONFIG_CDIRQ_11 |\
+ GALAXY_CONFIG_CDIRQ_12 | GALAXY_CONFIG_CDIRQ_15)
+
+#define GALAXY_CONFIG_MASK (\
+ GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CDA_MASK |\
+ GALAXY_CONFIG_CD_MASK | GALAXY_CONFIG_CDDMA16_MASK |\
+ GALAXY_CONFIG_CDDMA8_MASK | GALAXY_CONFIG_CDIRQ_MASK)
+
+#include "galaxy.c"
diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c
new file mode 100644
index 000000000000..ee54df082b9c
--- /dev/null
+++ b/sound/isa/galaxy/galaxy.c
@@ -0,0 +1,652 @@
+/*
+ * Aztech AZT1605/AZT2316 Driver
+ * Copyright (C) 2007,2010 Rene Herman
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/isa.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <asm/processor.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/wss.h>
+#include <sound/mpu401.h>
+#include <sound/opl3.h>
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Rene Herman");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
+
+static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
+module_param_array(wss_port, long, NULL, 0444);
+MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver.");
+module_param_array(mpu_port, long, NULL, 0444);
+MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
+module_param_array(fm_port, long, NULL, 0444);
+MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver.");
+module_param_array(irq, int, NULL, 0444);
+MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
+module_param_array(mpu_irq, int, NULL, 0444);
+MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
+module_param_array(dma1, int, NULL, 0444);
+MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver.");
+module_param_array(dma2, int, NULL, 0444);
+MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver.");
+
+/*
+ * Generic SB DSP support routines
+ */
+
+#define DSP_PORT_RESET 0x6
+#define DSP_PORT_READ 0xa
+#define DSP_PORT_COMMAND 0xc
+#define DSP_PORT_STATUS 0xc
+#define DSP_PORT_DATA_AVAIL 0xe
+
+#define DSP_SIGNATURE 0xaa
+
+#define DSP_COMMAND_GET_VERSION 0xe1
+
+static int __devinit dsp_get_byte(void __iomem *port, u8 *val)
+{
+ int loops = 1000;
+
+ while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) {
+ if (!loops--)
+ return -EIO;
+ cpu_relax();
+ }
+ *val = ioread8(port + DSP_PORT_READ);
+ return 0;
+}
+
+static int __devinit dsp_reset(void __iomem *port)
+{
+ u8 val;
+
+ iowrite8(1, port + DSP_PORT_RESET);
+ udelay(10);
+ iowrite8(0, port + DSP_PORT_RESET);
+
+ if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int __devinit dsp_command(void __iomem *port, u8 cmd)
+{
+ int loops = 1000;
+
+ while (ioread8(port + DSP_PORT_STATUS) & 0x80) {
+ if (!loops--)
+ return -EIO;
+ cpu_relax();
+ }
+ iowrite8(cmd, port + DSP_PORT_COMMAND);
+ return 0;
+}
+
+static int __devinit dsp_get_version(void __iomem *port, u8 *major, u8 *minor)
+{
+ int err;
+
+ err = dsp_command(port, DSP_COMMAND_GET_VERSION);
+ if (err < 0)
+ return err;
+
+ err = dsp_get_byte(port, major);
+ if (err < 0)
+ return err;
+
+ err = dsp_get_byte(port, minor);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/*
+ * Generic WSS support routines
+ */
+
+#define WSS_CONFIG_DMA_0 (1 << 0)
+#define WSS_CONFIG_DMA_1 (2 << 0)
+#define WSS_CONFIG_DMA_3 (3 << 0)
+#define WSS_CONFIG_DUPLEX (1 << 2)
+#define WSS_CONFIG_IRQ_7 (1 << 3)
+#define WSS_CONFIG_IRQ_9 (2 << 3)
+#define WSS_CONFIG_IRQ_10 (3 << 3)
+#define WSS_CONFIG_IRQ_11 (4 << 3)
+
+#define WSS_PORT_CONFIG 0
+#define WSS_PORT_SIGNATURE 3
+
+#define WSS_SIGNATURE 4
+
+static int __devinit wss_detect(void __iomem *wss_port)
+{
+ if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void wss_set_config(void __iomem *wss_port, u8 wss_config)
+{
+ iowrite8(wss_config, wss_port + WSS_PORT_CONFIG);
+}
+
+/*
+ * Aztech Sound Galaxy specifics
+ */
+
+#define GALAXY_PORT_CONFIG 1024
+#define CONFIG_PORT_SET 4
+
+#define DSP_COMMAND_GALAXY_8 8
+#define GALAXY_COMMAND_GET_TYPE 5
+
+#define DSP_COMMAND_GALAXY_9 9
+#define GALAXY_COMMAND_WSSMODE 0
+#define GALAXY_COMMAND_SB8MODE 1
+
+#define GALAXY_MODE_WSS GALAXY_COMMAND_WSSMODE
+#define GALAXY_MODE_SB8 GALAXY_COMMAND_SB8MODE
+
+struct snd_galaxy {
+ void __iomem *port;
+ void __iomem *config_port;
+ void __iomem *wss_port;
+ u32 config;
+ struct resource *res_port;
+ struct resource *res_config_port;
+ struct resource *res_wss_port;
+};
+
+static u32 config[SNDRV_CARDS];
+static u8 wss_config[SNDRV_CARDS];
+
+static int __devinit snd_galaxy_match(struct device *dev, unsigned int n)
+{
+ if (!enable[n])
+ return 0;
+
+ switch (port[n]) {
+ case SNDRV_AUTO_PORT:
+ dev_err(dev, "please specify port\n");
+ return 0;
+ case 0x220:
+ config[n] |= GALAXY_CONFIG_SBA_220;
+ break;
+ case 0x240:
+ config[n] |= GALAXY_CONFIG_SBA_240;
+ break;
+ case 0x260:
+ config[n] |= GALAXY_CONFIG_SBA_260;
+ break;
+ case 0x280:
+ config[n] |= GALAXY_CONFIG_SBA_280;
+ break;
+ default:
+ dev_err(dev, "invalid port %#lx\n", port[n]);
+ return 0;
+ }
+
+ switch (wss_port[n]) {
+ case SNDRV_AUTO_PORT:
+ dev_err(dev, "please specify wss_port\n");
+ return 0;
+ case 0x530:
+ config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530;
+ break;
+ case 0x604:
+ config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604;
+ break;
+ case 0xe80:
+ config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80;
+ break;
+ case 0xf40:
+ config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40;
+ break;
+ default:
+ dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]);
+ return 0;
+ }
+
+ switch (irq[n]) {
+ case SNDRV_AUTO_IRQ:
+ dev_err(dev, "please specify irq\n");
+ return 0;
+ case 7:
+ wss_config[n] |= WSS_CONFIG_IRQ_7;
+ break;
+ case 2:
+ irq[n] = 9;
+ case 9:
+ wss_config[n] |= WSS_CONFIG_IRQ_9;
+ break;
+ case 10:
+ wss_config[n] |= WSS_CONFIG_IRQ_10;
+ break;
+ case 11:
+ wss_config[n] |= WSS_CONFIG_IRQ_11;
+ break;
+ default:
+ dev_err(dev, "invalid IRQ %d\n", irq[n]);
+ return 0;
+ }
+
+ switch (dma1[n]) {
+ case SNDRV_AUTO_DMA:
+ dev_err(dev, "please specify dma1\n");
+ return 0;
+ case 0:
+ wss_config[n] |= WSS_CONFIG_DMA_0;
+ break;
+ case 1:
+ wss_config[n] |= WSS_CONFIG_DMA_1;
+ break;
+ case 3:
+ wss_config[n] |= WSS_CONFIG_DMA_3;
+ break;
+ default:
+ dev_err(dev, "invalid playback DMA %d\n", dma1[n]);
+ return 0;
+ }
+
+ if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) {
+ dma2[n] = -1;
+ goto mpu;
+ }
+
+ wss_config[n] |= WSS_CONFIG_DUPLEX;
+ switch (dma2[n]) {
+ case 0:
+ break;
+ case 1:
+ if (dma1[n] == 0)
+ break;
+ default:
+ dev_err(dev, "invalid capture DMA %d\n", dma2[n]);
+ return 0;
+ }
+
+mpu:
+ switch (mpu_port[n]) {
+ case SNDRV_AUTO_PORT:
+ dev_warn(dev, "mpu_port not specified; not using MPU-401\n");
+ mpu_port[n] = -1;
+ goto fm;
+ case 0x300:
+ config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300;
+ break;
+ case 0x330:
+ config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330;
+ break;
+ default:
+ dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]);
+ return 0;
+ }
+
+ switch (mpu_irq[n]) {
+ case SNDRV_AUTO_IRQ:
+ dev_warn(dev, "mpu_irq not specified: using polling mode\n");
+ mpu_irq[n] = -1;
+ break;
+ case 2:
+ mpu_irq[n] = 9;
+ case 9:
+ config[n] |= GALAXY_CONFIG_MPUIRQ_2;
+ break;
+#ifdef AZT1605
+ case 3:
+ config[n] |= GALAXY_CONFIG_MPUIRQ_3;
+ break;
+#endif
+ case 5:
+ config[n] |= GALAXY_CONFIG_MPUIRQ_5;
+ break;
+ case 7:
+ config[n] |= GALAXY_CONFIG_MPUIRQ_7;
+ break;
+#ifdef AZT2316
+ case 10:
+ config[n] |= GALAXY_CONFIG_MPUIRQ_10;
+ break;
+#endif
+ default:
+ dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]);
+ return 0;
+ }
+
+ if (mpu_irq[n] == irq[n]) {
+ dev_err(dev, "cannot share IRQ between WSS and MPU-401\n");
+ return 0;
+ }
+
+fm:
+ switch (fm_port[n]) {
+ case SNDRV_AUTO_PORT:
+ dev_warn(dev, "fm_port not specified: not using OPL3\n");
+ fm_port[n] = -1;
+ break;
+ case 0x388:
+ break;
+ default:
+ dev_err(dev, "illegal FM port %#lx\n", fm_port[n]);
+ return 0;
+ }
+
+ config[n] |= GALAXY_CONFIG_GAME_ENABLE;
+ return 1;
+}
+
+static int __devinit galaxy_init(struct snd_galaxy *galaxy, u8 *type)
+{
+ u8 major;
+ u8 minor;
+ int err;
+
+ err = dsp_reset(galaxy->port);
+ if (err < 0)
+ return err;
+
+ err = dsp_get_version(galaxy->port, &major, &minor);
+ if (err < 0)
+ return err;
+
+ if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR)
+ return -ENODEV;
+
+ err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8);
+ if (err < 0)
+ return err;
+
+ err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE);
+ if (err < 0)
+ return err;
+
+ err = dsp_get_byte(galaxy->port, type);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int __devinit galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode)
+{
+ int err;
+
+ err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9);
+ if (err < 0)
+ return err;
+
+ err = dsp_command(galaxy->port, mode);
+ if (err < 0)
+ return err;
+
+#ifdef AZT1605
+ /*
+ * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again
+ */
+ err = dsp_reset(galaxy->port);
+ if (err < 0)
+ return err;
+#endif
+
+ return 0;
+}
+
+static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config)
+{
+ u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET);
+ int i;
+
+ iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET);
+ for (i = 0; i < GALAXY_CONFIG_SIZE; i++) {
+ iowrite8(config, galaxy->config_port + i);
+ config >>= 8;
+ }
+ iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET);
+ msleep(10);
+}
+
+static void __devinit galaxy_config(struct snd_galaxy *galaxy, u32 config)
+{
+ int i;
+
+ for (i = GALAXY_CONFIG_SIZE; i; i--) {
+ u8 tmp = ioread8(galaxy->config_port + i - 1);
+ galaxy->config = (galaxy->config << 8) | tmp;
+ }
+ config |= galaxy->config & GALAXY_CONFIG_MASK;
+ galaxy_set_config(galaxy, config);
+}
+
+static int __devinit galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config)
+{
+ int err;
+
+ err = wss_detect(galaxy->wss_port);
+ if (err < 0)
+ return err;
+
+ wss_set_config(galaxy->wss_port, wss_config);
+
+ err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static void snd_galaxy_free(struct snd_card *card)
+{
+ struct snd_galaxy *galaxy = card->private_data;
+
+ if (galaxy->wss_port) {
+ wss_set_config(galaxy->wss_port, 0);
+ ioport_unmap(galaxy->wss_port);
+ release_and_free_resource(galaxy->res_wss_port);
+ }
+ if (galaxy->config_port) {
+ galaxy_set_config(galaxy, galaxy->config);
+ ioport_unmap(galaxy->config_port);
+ release_and_free_resource(galaxy->res_config_port);
+ }
+ if (galaxy->port) {
+ ioport_unmap(galaxy->port);
+ release_and_free_resource(galaxy->res_port);
+ }
+}
+
+static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n)
+{
+ struct snd_galaxy *galaxy;
+ struct snd_wss *chip;
+ struct snd_card *card;
+ u8 type;
+ int err;
+
+ err = snd_card_create(index[n], id[n], THIS_MODULE, sizeof *galaxy,
+ &card);
+ if (err < 0)
+ return err;
+
+ snd_card_set_dev(card, dev);
+
+ card->private_free = snd_galaxy_free;
+ galaxy = card->private_data;
+
+ galaxy->res_port = request_region(port[n], 16, DRV_NAME);
+ if (!galaxy->res_port) {
+ dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n],
+ port[n] + 15);
+ err = -EBUSY;
+ goto error;
+ }
+ galaxy->port = ioport_map(port[n], 16);
+
+ err = galaxy_init(galaxy, &type);
+ if (err < 0) {
+ dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]);
+ goto error;
+ }
+ dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]);
+
+ galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG,
+ 16, DRV_NAME);
+ if (!galaxy->res_config_port) {
+ dev_err(dev, "could not grab ports %#lx-%#lx\n",
+ port[n] + GALAXY_PORT_CONFIG,
+ port[n] + GALAXY_PORT_CONFIG + 15);
+ err = -EBUSY;
+ goto error;
+ }
+ galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16);
+
+ galaxy_config(galaxy, config[n]);
+
+ galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME);
+ if (!galaxy->res_wss_port) {
+ dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n],
+ wss_port[n] + 3);
+ err = -EBUSY;
+ goto error;
+ }
+ galaxy->wss_port = ioport_map(wss_port[n], 4);
+
+ err = galaxy_wss_config(galaxy, wss_config[n]);
+ if (err < 0) {
+ dev_err(dev, "could not configure WSS\n");
+ goto error;
+ }
+
+ strcpy(card->driver, DRV_NAME);
+ strcpy(card->shortname, DRV_NAME);
+ sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d",
+ card->shortname, port[n], wss_port[n], irq[n], dma1[n],
+ dma2[n]);
+
+ err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n],
+ dma2[n], WSS_HW_DETECT, 0, &chip);
+ if (err < 0)
+ goto error;
+
+ err = snd_wss_pcm(chip, 0, NULL);
+ if (err < 0)
+ goto error;
+
+ err = snd_wss_mixer(chip);
+ if (err < 0)
+ goto error;
+
+ err = snd_wss_timer(chip, 0, NULL);
+ if (err < 0)
+ goto error;
+
+ if (mpu_port[n] >= 0) {
+ err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+ mpu_port[n], 0, mpu_irq[n],
+ IRQF_DISABLED, NULL);
+ if (err < 0)
+ goto error;
+ }
+
+ if (fm_port[n] >= 0) {
+ struct snd_opl3 *opl3;
+
+ err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
+ OPL3_HW_AUTO, 0, &opl3);
+ if (err < 0) {
+ dev_err(dev, "no OPL device at %#lx\n", fm_port[n]);
+ goto error;
+ }
+ err = snd_opl3_timer_new(opl3, 1, 2);
+ if (err < 0)
+ goto error;
+
+ err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+ if (err < 0)
+ goto error;
+ }
+
+ err = snd_card_register(card);
+ if (err < 0)
+ goto error;
+
+ dev_set_drvdata(dev, card);
+ return 0;
+
+error:
+ snd_card_free(card);
+ return err;
+}
+
+static int __devexit snd_galaxy_remove(struct device *dev, unsigned int n)
+{
+ snd_card_free(dev_get_drvdata(dev));
+ dev_set_drvdata(dev, NULL);
+ return 0;
+}
+
+static struct isa_driver snd_galaxy_driver = {
+ .match = snd_galaxy_match,
+ .probe = snd_galaxy_probe,
+ .remove = __devexit_p(snd_galaxy_remove),
+
+ .driver = {
+ .name = DEV_NAME
+ }
+};
+
+static int __init alsa_card_galaxy_init(void)
+{
+ return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS);
+}
+
+static void __exit alsa_card_galaxy_exit(void)
+{
+ isa_unregister_driver(&snd_galaxy_driver);
+}
+
+module_init(alsa_card_galaxy_init);
+module_exit(alsa_card_galaxy_exit);
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
index f26eac8d8110..3e4a58b72913 100644
--- a/sound/isa/gus/gusmax.c
+++ b/sound/isa/gus/gusmax.c
@@ -191,7 +191,7 @@ static int __devinit snd_gusmax_mixer(struct snd_wss *chip)
static void snd_gusmax_free(struct snd_card *card)
{
- struct snd_gusmax *maxcard = (struct snd_gusmax *)card->private_data;
+ struct snd_gusmax *maxcard = card->private_data;
if (maxcard == NULL)
return;
@@ -219,7 +219,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev)
if (err < 0)
return err;
card->private_free = snd_gusmax_free;
- maxcard = (struct snd_gusmax *)card->private_data;
+ maxcard = card->private_data;
maxcard->card = card;
maxcard->irq = -1;
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
index 81284a8fa0ce..2259e3f726a7 100644
--- a/sound/isa/sb/sb8.c
+++ b/sound/isa/sb/sb8.c
@@ -72,7 +72,7 @@ static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id)
static void snd_sb8_free(struct snd_card *card)
{
- struct snd_sb8 *acard = (struct snd_sb8 *)card->private_data;
+ struct snd_sb8 *acard = card->private_data;
if (acard == NULL)
return;
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c
deleted file mode 100644
index 6fe27b9d9440..000000000000
--- a/sound/isa/sgalaxy.c
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Driver for Aztech Sound Galaxy cards
- * Copyright (c) by Christopher Butler <chrisb@sandy.force9.co.uk.
- *
- * I don't have documentation for this card, I based this driver on the
- * driver for OSS/Free included in the kernel source (drivers/sound/sgalaxy.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.
- *
- * 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/init.h>
-#include <linux/err.h>
-#include <linux/isa.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/interrupt.h>
-#include <linux/moduleparam.h>
-#include <asm/dma.h>
-#include <sound/core.h>
-#include <sound/sb.h>
-#include <sound/wss.h>
-#include <sound/control.h>
-#define SNDRV_LEGACY_FIND_FREE_IRQ
-#define SNDRV_LEGACY_FIND_FREE_DMA
-#include <sound/initval.h>
-
-MODULE_AUTHOR("Christopher Butler <chrisb@sandy.force9.co.uk>");
-MODULE_DESCRIPTION("Aztech Sound Galaxy");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Aztech Systems,Sound Galaxy}}");
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
-static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240 */
-static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */
-static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 7,9,10,11 */
-static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for Sound Galaxy soundcard.");
-module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for Sound Galaxy soundcard.");
-module_param_array(sbport, long, NULL, 0444);
-MODULE_PARM_DESC(sbport, "Port # for Sound Galaxy SB driver.");
-module_param_array(wssport, long, NULL, 0444);
-MODULE_PARM_DESC(wssport, "Port # for Sound Galaxy WSS driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for Sound Galaxy driver.");
-module_param_array(dma1, int, NULL, 0444);
-MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver.");
-
-#define SGALAXY_AUXC_LEFT 18
-#define SGALAXY_AUXC_RIGHT 19
-
-#define PFX "sgalaxy: "
-
-/*
-
- */
-
-#define AD1848P1( port, x ) ( port + c_d_c_AD1848##x )
-
-/* from lowlevel/sb/sb.c - to avoid having to allocate a struct snd_sb for the */
-/* short time we actually need it.. */
-
-static int snd_sgalaxy_sbdsp_reset(unsigned long port)
-{
- int i;
-
- outb(1, SBP1(port, RESET));
- udelay(10);
- outb(0, SBP1(port, RESET));
- udelay(30);
- for (i = 0; i < 1000 && !(inb(SBP1(port, DATA_AVAIL)) & 0x80); i++);
- if (inb(SBP1(port, READ)) != 0xaa) {
- snd_printd("sb_reset: failed at 0x%lx!!!\n", port);
- return -ENODEV;
- }
- return 0;
-}
-
-static int __devinit snd_sgalaxy_sbdsp_command(unsigned long port,
- unsigned char val)
-{
- int i;
-
- for (i = 10000; i; i--)
- if ((inb(SBP1(port, STATUS)) & 0x80) == 0) {
- outb(val, SBP1(port, COMMAND));
- return 1;
- }
-
- return 0;
-}
-
-static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id)
-{
- return IRQ_NONE;
-}
-
-static int __devinit snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma)
-{
- static int interrupt_bits[] = {-1, -1, -1, -1, -1, -1, -1, 0x08, -1,
- 0x10, 0x18, 0x20, -1, -1, -1, -1};
- static int dma_bits[] = {1, 2, 0, 3};
- int tmp, tmp1;
-
- if ((tmp = inb(port + 3)) == 0xff)
- {
- snd_printdd("I/O address dead (0x%lx)\n", port);
- return 0;
- }
-#if 0
- snd_printdd("WSS signature = 0x%x\n", tmp);
-#endif
-
- if ((tmp & 0x3f) != 0x04 &&
- (tmp & 0x3f) != 0x0f &&
- (tmp & 0x3f) != 0x00) {
- snd_printdd("No WSS signature detected on port 0x%lx\n",
- port + 3);
- return 0;
- }
-
-#if 0
- snd_printdd(PFX "setting up IRQ/DMA for WSS\n");
-#endif
-
- /* initialize IRQ for WSS codec */
- tmp = interrupt_bits[irq % 16];
- if (tmp < 0)
- return -EINVAL;
-
- if (request_irq(irq, snd_sgalaxy_dummy_interrupt, IRQF_DISABLED, "sgalaxy", NULL)) {
- snd_printk(KERN_ERR "sgalaxy: can't grab irq %d\n", irq);
- return -EIO;
- }
-
- outb(tmp | 0x40, port);
- tmp1 = dma_bits[dma % 4];
- outb(tmp | tmp1, port);
-
- free_irq(irq, NULL);
-
- return 0;
-}
-
-static int __devinit snd_sgalaxy_detect(int dev, int irq, int dma)
-{
-#if 0
- snd_printdd(PFX "switching to WSS mode\n");
-#endif
-
- /* switch to WSS mode */
- snd_sgalaxy_sbdsp_reset(sbport[dev]);
-
- snd_sgalaxy_sbdsp_command(sbport[dev], 9);
- snd_sgalaxy_sbdsp_command(sbport[dev], 0);
-
- udelay(400);
- return snd_sgalaxy_setup_wss(wssport[dev], irq, dma);
-}
-
-static struct snd_kcontrol_new snd_sgalaxy_controls[] = {
-WSS_DOUBLE("Aux Playback Switch", 0,
- SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1),
-WSS_DOUBLE("Aux Playback Volume", 0,
- SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0)
-};
-
-static int __devinit snd_sgalaxy_mixer(struct snd_wss *chip)
-{
- struct snd_card *card = chip->card;
- struct snd_ctl_elem_id id1, id2;
- unsigned int idx;
- int err;
-
- memset(&id1, 0, sizeof(id1));
- memset(&id2, 0, sizeof(id2));
- id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- /* reassign AUX0 to LINE */
- strcpy(id1.name, "Aux Playback Switch");
- strcpy(id2.name, "Line Playback Switch");
- if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
- return err;
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "Line Playback Volume");
- if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
- return err;
- /* reassign AUX1 to FM */
- strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
- strcpy(id2.name, "FM Playback Switch");
- if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
- return err;
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "FM Playback Volume");
- if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
- return err;
- /* build AUX2 input */
- for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) {
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_sgalaxy_controls[idx], chip));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
-static int __devinit snd_sgalaxy_match(struct device *devptr, unsigned int dev)
-{
- if (!enable[dev])
- return 0;
- if (sbport[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR PFX "specify SB port\n");
- return 0;
- }
- if (wssport[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR PFX "specify WSS port\n");
- return 0;
- }
- return 1;
-}
-
-static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev)
-{
- static int possible_irqs[] = {7, 9, 10, 11, -1};
- static int possible_dmas[] = {1, 3, 0, -1};
- int err, xirq, xdma1;
- struct snd_card *card;
- struct snd_wss *chip;
-
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
- if (err < 0)
- return err;
-
- xirq = irq[dev];
- if (xirq == SNDRV_AUTO_IRQ) {
- if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
- err = -EBUSY;
- goto _err;
- }
- }
- xdma1 = dma1[dev];
- if (xdma1 == SNDRV_AUTO_DMA) {
- if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free DMA\n");
- err = -EBUSY;
- goto _err;
- }
- }
-
- if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0)
- goto _err;
-
- err = snd_wss_create(card, wssport[dev] + 4, -1,
- xirq, xdma1, -1,
- WSS_HW_DETECT, 0, &chip);
- if (err < 0)
- goto _err;
- card->private_data = chip;
-
- err = snd_wss_pcm(chip, 0, NULL);
- if (err < 0) {
- snd_printdd(PFX "error creating new WSS PCM device\n");
- goto _err;
- }
- err = snd_wss_mixer(chip);
- if (err < 0) {
- snd_printdd(PFX "error creating new WSS mixer\n");
- goto _err;
- }
- if ((err = snd_sgalaxy_mixer(chip)) < 0) {
- snd_printdd(PFX "the mixer rewrite failed\n");
- goto _err;
- }
-
- strcpy(card->driver, "Sound Galaxy");
- strcpy(card->shortname, "Sound Galaxy");
- sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d",
- wssport[dev], xirq, xdma1);
-
- snd_card_set_dev(card, devptr);
-
- if ((err = snd_card_register(card)) < 0)
- goto _err;
-
- dev_set_drvdata(devptr, card);
- return 0;
-
- _err:
- snd_card_free(card);
- return err;
-}
-
-static int __devexit snd_sgalaxy_remove(struct device *devptr, unsigned int dev)
-{
- snd_card_free(dev_get_drvdata(devptr));
- dev_set_drvdata(devptr, NULL);
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n,
- pm_message_t state)
-{
- struct snd_card *card = dev_get_drvdata(pdev);
- struct snd_wss *chip = card->private_data;
-
- snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
- chip->suspend(chip);
- return 0;
-}
-
-static int snd_sgalaxy_resume(struct device *pdev, unsigned int n)
-{
- struct snd_card *card = dev_get_drvdata(pdev);
- struct snd_wss *chip = card->private_data;
-
- chip->resume(chip);
- snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]);
- snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]);
-
- snd_power_change_state(card, SNDRV_CTL_POWER_D0);
- return 0;
-}
-#endif
-
-#define DEV_NAME "sgalaxy"
-
-static struct isa_driver snd_sgalaxy_driver = {
- .match = snd_sgalaxy_match,
- .probe = snd_sgalaxy_probe,
- .remove = __devexit_p(snd_sgalaxy_remove),
-#ifdef CONFIG_PM
- .suspend = snd_sgalaxy_suspend,
- .resume = snd_sgalaxy_resume,
-#endif
- .driver = {
- .name = DEV_NAME
- },
-};
-
-static int __init alsa_card_sgalaxy_init(void)
-{
- return isa_register_driver(&snd_sgalaxy_driver, SNDRV_CARDS);
-}
-
-static void __exit alsa_card_sgalaxy_exit(void)
-{
- isa_unregister_driver(&snd_sgalaxy_driver);
-}
-
-module_init(alsa_card_sgalaxy_init)
-module_exit(alsa_card_sgalaxy_exit)
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index a513651fa149..76c090218073 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -545,11 +545,3 @@ config SOUND_KAHLUA
endif # SOUND_OSS
-config SOUND_SH_DAC_AUDIO
- tristate "SuperH DAC audio support"
- depends on CPU_SH3 && HIGH_RES_TIMERS
-
-config SOUND_SH_DAC_AUDIO_CHANNEL
- int "DAC channel"
- default "1"
- depends on SOUND_SH_DAC_AUDIO
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index 567b8a74178a..96f14dcd0cd1 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_SOUND_OSS) += sound.o
# Please leave it as is, cause the link order is significant !
-obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o
obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o
obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
index 456a1b4d7832..854c303264dc 100644
--- a/sound/oss/ac97_codec.c
+++ b/sound/oss/ac97_codec.c
@@ -21,11 +21,8 @@
*
**************************************************************************
*
- * The Intel Audio Codec '97 specification is available at the Intel
- * audio homepage: http://developer.intel.com/ial/scalableplatforms/audio/
- *
- * The specification itself is currently available at:
- * ftp://download.intel.com/ial/scalableplatforms/ac97r22.pdf
+ * The Intel Audio Codec '97 specification is available at:
+ * http://download.intel.com/support/motherboards/desktop/sb/ac97_r23.pdf
*
**************************************************************************
*
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c
index c6f2621221ba..a8f626d99c5b 100644
--- a/sound/oss/au1550_ac97.c
+++ b/sound/oss/au1550_ac97.c
@@ -43,7 +43,6 @@
#include <linux/sound.h>
#include <linux/slab.h>
#include <linux/soundcard.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
@@ -77,6 +76,7 @@
/* Boot options
* 0 = no VRA, 1 = use VRA if codec supports it
*/
+static DEFINE_MUTEX(au1550_ac97_mutex);
static int vra = 1;
module_param(vra, bool, 0);
MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
@@ -171,7 +171,7 @@ au1550_delay(int msec)
static u16
rdcodec(struct ac97_codec *codec, u8 addr)
{
- struct au1550_state *s = (struct au1550_state *)codec->private_data;
+ struct au1550_state *s = codec->private_data;
unsigned long flags;
u32 cmd, val;
u16 data;
@@ -239,7 +239,7 @@ rdcodec(struct ac97_codec *codec, u8 addr)
static void
wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
{
- struct au1550_state *s = (struct au1550_state *)codec->private_data;
+ struct au1550_state *s = codec->private_data;
unsigned long flags;
u32 cmd, val;
int i;
@@ -798,9 +798,9 @@ au1550_llseek(struct file *file, loff_t offset, int origin)
static int
au1550_open_mixdev(struct inode *inode, struct file *file)
{
- lock_kernel();
+ mutex_lock(&au1550_ac97_mutex);
file->private_data = &au1550_state;
- unlock_kernel();
+ mutex_unlock(&au1550_ac97_mutex);
return 0;
}
@@ -820,13 +820,13 @@ mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
static long
au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
+ struct au1550_state *s = file->private_data;
struct ac97_codec *codec = s->codec;
int ret;
- lock_kernel();
+ mutex_lock(&au1550_ac97_mutex);
ret = mixdev_ioctl(codec, cmd, arg);
- unlock_kernel();
+ mutex_unlock(&au1550_ac97_mutex);
return ret;
}
@@ -1031,7 +1031,7 @@ copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user)
static ssize_t
au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
+ struct au1550_state *s = file->private_data;
struct dmabuf *db = &s->dma_adc;
DECLARE_WAITQUEUE(wait, current);
ssize_t ret;
@@ -1111,7 +1111,7 @@ out2:
static ssize_t
au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
+ struct au1550_state *s = file->private_data;
struct dmabuf *db = &s->dma_dac;
DECLARE_WAITQUEUE(wait, current);
ssize_t ret = 0;
@@ -1211,7 +1211,7 @@ out2:
static unsigned int
au1550_poll(struct file *file, struct poll_table_struct *wait)
{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
+ struct au1550_state *s = file->private_data;
unsigned long flags;
unsigned int mask = 0;
@@ -1250,12 +1250,12 @@ au1550_poll(struct file *file, struct poll_table_struct *wait)
static int
au1550_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
+ struct au1550_state *s = file->private_data;
struct dmabuf *db;
unsigned long size;
int ret = 0;
- lock_kernel();
+ mutex_lock(&au1550_ac97_mutex);
mutex_lock(&s->sem);
if (vma->vm_flags & VM_WRITE)
db = &s->dma_dac;
@@ -1283,7 +1283,7 @@ au1550_mmap(struct file *file, struct vm_area_struct *vma)
db->mapped = 1;
out:
mutex_unlock(&s->sem);
- unlock_kernel();
+ mutex_unlock(&au1550_ac97_mutex);
return ret;
}
@@ -1342,7 +1342,7 @@ dma_count_done(struct dmabuf *db)
static int
au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
+ struct au1550_state *s = file->private_data;
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
@@ -1781,9 +1781,9 @@ au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret;
- lock_kernel();
+ mutex_lock(&au1550_ac97_mutex);
ret = au1550_ioctl(file, cmd, arg);
- unlock_kernel();
+ mutex_unlock(&au1550_ac97_mutex);
return ret;
}
@@ -1804,7 +1804,7 @@ au1550_open(struct inode *inode, struct file *file)
#endif
file->private_data = s;
- lock_kernel();
+ mutex_lock(&au1550_ac97_mutex);
/* wait for device to become free */
mutex_lock(&s->open_mutex);
while (s->open_mode & file->f_mode) {
@@ -1861,21 +1861,21 @@ au1550_open(struct inode *inode, struct file *file)
out:
mutex_unlock(&s->open_mutex);
out2:
- unlock_kernel();
+ mutex_unlock(&au1550_ac97_mutex);
return ret;
}
static int
au1550_release(struct inode *inode, struct file *file)
{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
+ struct au1550_state *s = file->private_data;
- lock_kernel();
+ mutex_lock(&au1550_ac97_mutex);
if (file->f_mode & FMODE_WRITE) {
- unlock_kernel();
+ mutex_unlock(&au1550_ac97_mutex);
drain_dac(s, file->f_flags & O_NONBLOCK);
- lock_kernel();
+ mutex_lock(&au1550_ac97_mutex);
}
mutex_lock(&s->open_mutex);
@@ -1892,7 +1892,7 @@ au1550_release(struct inode *inode, struct file *file)
s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
mutex_unlock(&s->open_mutex);
wake_up(&s->open_wait);
- unlock_kernel();
+ mutex_unlock(&au1550_ac97_mutex);
return 0;
}
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
index 6ecd41abb066..87e2c72651f5 100644
--- a/sound/oss/dmasound/dmasound_core.c
+++ b/sound/oss/dmasound/dmasound_core.c
@@ -181,7 +181,7 @@
#include <linux/init.h>
#include <linux/soundcard.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
@@ -194,6 +194,7 @@
* Declarations
*/
+static DEFINE_MUTEX(dmasound_core_mutex);
int dmasound_catchRadius = 0;
module_param(dmasound_catchRadius, int, 0);
@@ -323,22 +324,22 @@ static struct {
static int mixer_open(struct inode *inode, struct file *file)
{
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
if (!try_module_get(dmasound.mach.owner)) {
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return -ENODEV;
}
mixer.busy = 1;
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return 0;
}
static int mixer_release(struct inode *inode, struct file *file)
{
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
mixer.busy = 0;
module_put(dmasound.mach.owner);
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return 0;
}
@@ -370,9 +371,9 @@ static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
{
int ret;
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
ret = mixer_ioctl(file, cmd, arg);
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return ret;
}
@@ -752,9 +753,9 @@ static int sq_open(struct inode *inode, struct file *file)
{
int rc;
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
if (!try_module_get(dmasound.mach.owner)) {
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return -ENODEV;
}
@@ -799,11 +800,11 @@ static int sq_open(struct inode *inode, struct file *file)
sound_set_format(AFMT_MU_LAW);
}
#endif
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return 0;
out:
module_put(dmasound.mach.owner);
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return rc;
}
@@ -869,7 +870,7 @@ static int sq_release(struct inode *inode, struct file *file)
{
int rc = 0;
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
if (file->f_mode & FMODE_WRITE) {
if (write_sq.busy)
@@ -900,7 +901,7 @@ static int sq_release(struct inode *inode, struct file *file)
write_sq_wake_up(file); /* checks f_mode */
#endif /* blocking open() */
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return rc;
}
@@ -1141,9 +1142,9 @@ static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
{
int ret;
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
ret = sq_ioctl(file, cmd, arg);
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return ret;
}
@@ -1257,7 +1258,7 @@ static int state_open(struct inode *inode, struct file *file)
int len = 0;
int ret;
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
ret = -EBUSY;
if (state.busy)
goto out;
@@ -1329,16 +1330,16 @@ printk("dmasound: stat buffer used %d bytes\n", len) ;
state.len = len;
ret = 0;
out:
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return ret;
}
static int state_release(struct inode *inode, struct file *file)
{
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
state.busy = 0;
module_put(dmasound.mach.owner);
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return 0;
}
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c
index ca942f7cd231..7b5c77b32a90 100644
--- a/sound/oss/msnd_pinnacle.c
+++ b/sound/oss/msnd_pinnacle.c
@@ -39,7 +39,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/gfp.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -79,6 +79,7 @@
dev.rec_sample_rate / \
dev.rec_channels)
+static DEFINE_MUTEX(msnd_pinnacle_mutex);
static multisound_dev_t dev;
#ifndef HAVE_DSPCODEH
@@ -651,12 +652,12 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ret = -EINVAL;
- lock_kernel();
+ mutex_lock(&msnd_pinnacle_mutex);
if (minor == dev.dsp_minor)
ret = dsp_ioctl(file, cmd, arg);
else if (minor == dev.mixer_minor)
ret = mixer_ioctl(cmd, arg);
- unlock_kernel();
+ mutex_unlock(&msnd_pinnacle_mutex);
return ret;
}
@@ -761,7 +762,7 @@ static int dev_open(struct inode *inode, struct file *file)
int minor = iminor(inode);
int err = 0;
- lock_kernel();
+ mutex_lock(&msnd_pinnacle_mutex);
if (minor == dev.dsp_minor) {
if ((file->f_mode & FMODE_WRITE &&
test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) ||
@@ -791,7 +792,7 @@ static int dev_open(struct inode *inode, struct file *file)
} else
err = -EINVAL;
out:
- unlock_kernel();
+ mutex_unlock(&msnd_pinnacle_mutex);
return err;
}
@@ -800,14 +801,14 @@ static int dev_release(struct inode *inode, struct file *file)
int minor = iminor(inode);
int err = 0;
- lock_kernel();
+ mutex_lock(&msnd_pinnacle_mutex);
if (minor == dev.dsp_minor)
err = dsp_release(file);
else if (minor == dev.mixer_minor) {
/* nothing */
} else
err = -EINVAL;
- unlock_kernel();
+ mutex_unlock(&msnd_pinnacle_mutex);
return err;
}
diff --git a/sound/oss/sb_ess.c b/sound/oss/sb_ess.c
index 51a3d381a59e..9890cf2066ff 100644
--- a/sound/oss/sb_ess.c
+++ b/sound/oss/sb_ess.c
@@ -1722,7 +1722,6 @@ printk (KERN_INFO "FKS: es_rec_set_recmask mask = %x\n", mask);
right = (value & 0x0000ff00) >> 8;
} else { /* Turn it off (3) */
left = 0;
- left = 0;
right = 0;
}
sb_common_mixer_set(devc, i + ES_REC_MIXER_RECDIFF, left, right);
diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c
deleted file mode 100644
index 479e3025a8a3..000000000000
--- a/sound/oss/sh_dac_audio.c
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * sound/oss/sh_dac_audio.c
- *
- * SH DAC based sound :(
- *
- * Copyright (C) 2004,2005 Andriy Skulysh
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/linkage.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/sound.h>
-#include <linux/smp_lock.h>
-#include <linux/soundcard.h>
-#include <linux/interrupt.h>
-#include <linux/hrtimer.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/delay.h>
-#include <asm/clock.h>
-#include <cpu/dac.h>
-#include <asm/machvec.h>
-#include <mach/hp6xx.h>
-#include <asm/hd64461.h>
-
-#define MODNAME "sh_dac_audio"
-
-#define BUFFER_SIZE 48000
-
-static int rate;
-static int empty;
-static char *data_buffer, *buffer_begin, *buffer_end;
-static int in_use, device_major;
-static struct hrtimer hrtimer;
-static ktime_t wakeups_per_second;
-
-static void dac_audio_start_timer(void)
-{
- hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
-}
-
-static void dac_audio_stop_timer(void)
-{
- hrtimer_cancel(&hrtimer);
-}
-
-static void dac_audio_reset(void)
-{
- dac_audio_stop_timer();
- buffer_begin = buffer_end = data_buffer;
- empty = 1;
-}
-
-static void dac_audio_sync(void)
-{
- while (!empty)
- schedule();
-}
-
-static void dac_audio_start(void)
-{
- if (mach_is_hp6xx()) {
- u16 v = __raw_readw(HD64461_GPADR);
- v &= ~HD64461_GPADR_SPEAKER;
- __raw_writew(v, HD64461_GPADR);
- }
-
- sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-}
-static void dac_audio_stop(void)
-{
- dac_audio_stop_timer();
-
- if (mach_is_hp6xx()) {
- u16 v = __raw_readw(HD64461_GPADR);
- v |= HD64461_GPADR_SPEAKER;
- __raw_writew(v, HD64461_GPADR);
- }
-
- sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
- sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-}
-
-static void dac_audio_set_rate(void)
-{
- wakeups_per_second = ktime_set(0, 1000000000 / rate);
-}
-
-static int dac_audio_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int val;
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, (int *)arg);
-
- case SNDCTL_DSP_SYNC:
- dac_audio_sync();
- return 0;
-
- case SNDCTL_DSP_RESET:
- dac_audio_reset();
- return 0;
-
- case SNDCTL_DSP_GETFMTS:
- return put_user(AFMT_U8, (int *)arg);
-
- case SNDCTL_DSP_SETFMT:
- return put_user(AFMT_U8, (int *)arg);
-
- case SNDCTL_DSP_NONBLOCK:
- spin_lock(&file->f_lock);
- file->f_flags |= O_NONBLOCK;
- spin_unlock(&file->f_lock);
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return 0;
-
- case SOUND_PCM_WRITE_RATE:
- val = *(int *)arg;
- if (val > 0) {
- rate = val;
- dac_audio_set_rate();
- }
- return put_user(rate, (int *)arg);
-
- case SNDCTL_DSP_STEREO:
- return put_user(0, (int *)arg);
-
- case SOUND_PCM_WRITE_CHANNELS:
- return put_user(1, (int *)arg);
-
- case SNDCTL_DSP_SETDUPLEX:
- return -EINVAL;
-
- case SNDCTL_DSP_PROFILE:
- return -EINVAL;
-
- case SNDCTL_DSP_GETBLKSIZE:
- return put_user(BUFFER_SIZE, (int *)arg);
-
- case SNDCTL_DSP_SETFRAGMENT:
- return 0;
-
- default:
- printk(KERN_ERR "sh_dac_audio: unimplemented ioctl=0x%x\n",
- cmd);
- return -EINVAL;
- }
- return -EINVAL;
-}
-
-static long dac_audio_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
-{
- int ret;
-
- lock_kernel();
- ret = dac_audio_ioctl(file, cmd, arg);
- unlock_kernel();
-
- return ret;
-}
-
-static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count,
- loff_t * ppos)
-{
- int free;
- int nbytes;
-
- if (!count) {
- dac_audio_sync();
- return 0;
- }
-
- free = buffer_begin - buffer_end;
-
- if (free < 0)
- free += BUFFER_SIZE;
- if ((free == 0) && (empty))
- free = BUFFER_SIZE;
- if (count > free)
- count = free;
- if (buffer_begin > buffer_end) {
- if (copy_from_user((void *)buffer_end, buf, count))
- return -EFAULT;
-
- buffer_end += count;
- } else {
- nbytes = data_buffer + BUFFER_SIZE - buffer_end;
- if (nbytes > count) {
- if (copy_from_user((void *)buffer_end, buf, count))
- return -EFAULT;
- buffer_end += count;
- } else {
- if (copy_from_user((void *)buffer_end, buf, nbytes))
- return -EFAULT;
- if (copy_from_user
- ((void *)data_buffer, buf + nbytes, count - nbytes))
- return -EFAULT;
- buffer_end = data_buffer + count - nbytes;
- }
- }
-
- if (empty) {
- empty = 0;
- dac_audio_start_timer();
- }
-
- return count;
-}
-
-static ssize_t dac_audio_read(struct file *file, char *buf, size_t count,
- loff_t * ppos)
-{
- return -EINVAL;
-}
-
-static int dac_audio_open(struct inode *inode, struct file *file)
-{
- if (file->f_mode & FMODE_READ)
- return -ENODEV;
-
- lock_kernel();
- if (in_use) {
- unlock_kernel();
- return -EBUSY;
- }
-
- in_use = 1;
-
- dac_audio_start();
- unlock_kernel();
- return 0;
-}
-
-static int dac_audio_release(struct inode *inode, struct file *file)
-{
- dac_audio_sync();
- dac_audio_stop();
- in_use = 0;
-
- return 0;
-}
-
-const struct file_operations dac_audio_fops = {
- .read = dac_audio_read,
- .write = dac_audio_write,
- .unlocked_ioctl = dac_audio_unlocked_ioctl,
- .open = dac_audio_open,
- .release = dac_audio_release,
-};
-
-static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle)
-{
- if (!empty) {
- sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
- buffer_begin++;
-
- if (buffer_begin == data_buffer + BUFFER_SIZE)
- buffer_begin = data_buffer;
- if (buffer_begin == buffer_end)
- empty = 1;
- }
-
- if (!empty)
- hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
-
- return HRTIMER_NORESTART;
-}
-
-static int __init dac_audio_init(void)
-{
- if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) {
- printk(KERN_ERR "Cannot register dsp device");
- return device_major;
- }
-
- in_use = 0;
-
- data_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
- if (data_buffer == NULL)
- return -ENOMEM;
-
- dac_audio_reset();
- rate = 8000;
- dac_audio_set_rate();
-
- /* Today: High Resolution Timer driven DAC playback.
- * The timer callback gets called once per sample. Ouch.
- *
- * Future: A much better approach would be to use the
- * SH7720 CMT+DMAC+DAC hardware combination like this:
- * - Program sample rate using CMT0 or CMT1
- * - Program DMAC to use CMT for timing and output to DAC
- * - Play sound using DMAC, let CPU sleep.
- * - While at it, rewrite this driver to use ALSA.
- */
-
- hrtimer_init(&hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- hrtimer.function = sh_dac_audio_timer;
-
- return 0;
-}
-
-static void __exit dac_audio_exit(void)
-{
- unregister_sound_dsp(device_major);
- kfree((void *)data_buffer);
-}
-
-module_init(dac_audio_init);
-module_exit(dac_audio_exit);
-
-MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
-MODULE_DESCRIPTION("SH DAC sound driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
index 07f803e6d203..46c0d03dbecc 100644
--- a/sound/oss/soundcard.c
+++ b/sound/oss/soundcard.c
@@ -40,7 +40,7 @@
#include <linux/major.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/device.h>
@@ -56,6 +56,7 @@
* Table for permanently allocated memory (used when unloading the module)
*/
void * sound_mem_blocks[MAX_MEM_BLOCKS];
+static DEFINE_MUTEX(soundcard_mutex);
int sound_nblocks = 0;
/* Persistent DMA buffers */
@@ -151,7 +152,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
* big one anyway, we might as well bandage here..
*/
- lock_kernel();
+ mutex_lock(&soundcard_mutex);
DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count));
switch (dev & 0x0f) {
@@ -169,7 +170,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
case SND_DEV_MIDIN:
ret = MIDIbuf_read(dev, file, buf, count);
}
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return ret;
}
@@ -178,7 +179,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou
int dev = iminor(file->f_path.dentry->d_inode);
int ret = -EINVAL;
- lock_kernel();
+ mutex_lock(&soundcard_mutex);
DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count));
switch (dev & 0x0f) {
case SND_DEV_SEQ:
@@ -196,7 +197,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou
ret = MIDIbuf_write(dev, file, buf, count);
break;
}
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return ret;
}
@@ -210,7 +211,7 @@ static int sound_open(struct inode *inode, struct file *file)
printk(KERN_ERR "Invalid minor device %d\n", dev);
return -ENXIO;
}
- lock_kernel();
+ mutex_lock(&soundcard_mutex);
switch (dev & 0x0f) {
case SND_DEV_CTL:
dev >>= 4;
@@ -247,15 +248,15 @@ static int sound_open(struct inode *inode, struct file *file)
retval = -ENXIO;
}
- unlock_kernel();
- return 0;
+ mutex_unlock(&soundcard_mutex);
+ return retval;
}
static int sound_release(struct inode *inode, struct file *file)
{
int dev = iminor(inode);
- lock_kernel();
+ mutex_lock(&soundcard_mutex);
DEB(printk("sound_release(dev=%d)\n", dev));
switch (dev & 0x0f) {
case SND_DEV_CTL:
@@ -280,7 +281,7 @@ static int sound_release(struct inode *inode, struct file *file)
default:
printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev);
}
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return 0;
}
@@ -354,7 +355,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (cmd == OSS_GETVERSION)
return __put_user(SOUND_VERSION, (int __user *)p);
- lock_kernel();
+ mutex_lock(&soundcard_mutex);
if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */
(dev & 0x0f) != SND_DEV_CTL) {
dtype = dev & 0x0f;
@@ -369,7 +370,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ret = sound_mixer_ioctl(dev >> 4, cmd, p);
break;
}
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return ret;
}
@@ -399,7 +400,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return ret;
}
@@ -439,35 +440,35 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n");
return -EINVAL;
}
- lock_kernel();
+ mutex_lock(&soundcard_mutex);
if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */
dmap = audio_devs[dev]->dmap_out;
else if (vma->vm_flags & VM_READ)
dmap = audio_devs[dev]->dmap_in;
else {
printk(KERN_ERR "Sound: Undefined mmap() access\n");
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EINVAL;
}
if (dmap == NULL) {
printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n");
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EIO;
}
if (dmap->raw_buf == NULL) {
printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n");
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EIO;
}
if (dmap->mapping_flags) {
printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n");
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EIO;
}
if (vma->vm_pgoff != 0) {
printk(KERN_ERR "Sound: mmap() offset must be 0.\n");
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EINVAL;
}
size = vma->vm_end - vma->vm_start;
@@ -478,7 +479,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
if (remap_pfn_range(vma, vma->vm_start,
virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EAGAIN;
}
@@ -490,7 +491,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
memset(dmap->raw_buf,
dmap->neutral_byte,
dmap->bytes_in_use);
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return 0;
}
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c
index b15840ad2527..44357d877a27 100644
--- a/sound/oss/swarm_cs4297a.c
+++ b/sound/oss/swarm_cs4297a.c
@@ -68,7 +68,6 @@
#include <linux/delay.h>
#include <linux/sound.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/soundcard.h>
#include <linux/ac97_codec.h>
#include <linux/pci.h>
@@ -94,6 +93,7 @@
struct cs4297a_state;
+static DEFINE_MUTEX(swarm_cs4297a_mutex);
static void stop_dac(struct cs4297a_state *s);
static void stop_adc(struct cs4297a_state *s);
static void start_dac(struct cs4297a_state *s);
@@ -1535,7 +1535,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n"));
- lock_kernel();
+ mutex_lock(&swarm_cs4297a_mutex);
list_for_each(entry, &cs4297a_devs)
{
s = list_entry(entry, struct cs4297a_state, list);
@@ -1547,7 +1547,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n"));
- unlock_kernel();
+ mutex_unlock(&swarm_cs4297a_mutex);
return -ENODEV;
}
VALIDATE_STATE(s);
@@ -1555,7 +1555,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n"));
- unlock_kernel();
+ mutex_unlock(&swarm_cs4297a_mutex);
return nonseekable_open(inode, file);
}
@@ -1575,10 +1575,10 @@ static int cs4297a_ioctl_mixdev(struct file *file,
unsigned int cmd, unsigned long arg)
{
int ret;
- lock_kernel();
+ mutex_lock(&swarm_cs4297a_mutex);
ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd,
arg);
- unlock_kernel();
+ mutex_unlock(&swarm_cs4297a_mutex);
return ret;
}
@@ -2350,9 +2350,9 @@ static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
{
int ret;
- lock_kernel();
+ mutex_lock(&swarm_cs4297a_mutex);
ret = cs4297a_ioctl(file, cmd, arg);
- unlock_kernel();
+ mutex_unlock(&swarm_cs4297a_mutex);
return ret;
}
@@ -2509,9 +2509,9 @@ static int cs4297a_open(struct inode *inode, struct file *file)
{
int ret;
- lock_kernel();
+ mutex_lock(&swarm_cs4297a_mutex);
ret = cs4297a_open(inode, file);
- unlock_kernel();
+ mutex_unlock(&swarm_cs4297a_mutex);
return ret;
}
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c
index 8cd73cdd88af..643f1113b1d8 100644
--- a/sound/oss/vwsnd.c
+++ b/sound/oss/vwsnd.c
@@ -145,7 +145,6 @@
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/wait.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
@@ -160,6 +159,7 @@
#ifdef VWSND_DEBUG
+static DEFINE_MUTEX(vwsnd_mutex);
static int shut_up = 1;
/*
@@ -2891,11 +2891,11 @@ static long vwsnd_audio_ioctl(struct file *file,
vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
int ret;
- lock_kernel();
+ mutex_lock(&vwsnd_mutex);
mutex_lock(&devc->io_mutex);
ret = vwsnd_audio_do_ioctl(file, cmd, arg);
mutex_unlock(&devc->io_mutex);
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return ret;
}
@@ -2922,7 +2922,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
DBGE("(inode=0x%p, file=0x%p)\n", inode, file);
- lock_kernel();
+ mutex_lock(&vwsnd_mutex);
INC_USE_COUNT;
for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F))
@@ -2930,7 +2930,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
if (devc == NULL) {
DEC_USE_COUNT;
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return -ENODEV;
}
@@ -2939,13 +2939,13 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
mutex_unlock(&devc->open_mutex);
if (file->f_flags & O_NONBLOCK) {
DEC_USE_COUNT;
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return -EBUSY;
}
interruptible_sleep_on(&devc->open_wait);
if (signal_pending(current)) {
DEC_USE_COUNT;
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return -ERESTARTSYS;
}
mutex_lock(&devc->open_mutex);
@@ -2998,7 +2998,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
file->private_data = devc;
DBGRV();
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return 0;
}
@@ -3012,7 +3012,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file)
vwsnd_port_t *wport = NULL, *rport = NULL;
int err = 0;
- lock_kernel();
+ mutex_lock(&vwsnd_mutex);
mutex_lock(&devc->io_mutex);
{
DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
@@ -3040,7 +3040,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file)
wake_up(&devc->open_wait);
DEC_USE_COUNT;
DBGR();
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return err;
}
@@ -3068,18 +3068,18 @@ static int vwsnd_mixer_open(struct inode *inode, struct file *file)
DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
INC_USE_COUNT;
- lock_kernel();
+ mutex_lock(&vwsnd_mutex);
for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
if (devc->mixer_minor == iminor(inode))
break;
if (devc == NULL) {
DEC_USE_COUNT;
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return -ENODEV;
}
file->private_data = devc;
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return 0;
}
@@ -3223,7 +3223,7 @@ static long vwsnd_mixer_ioctl(struct file *file,
DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg);
- lock_kernel();
+ mutex_lock(&vwsnd_mutex);
mutex_lock(&devc->mix_mutex);
{
if ((cmd & ~nrmask) == MIXER_READ(0))
@@ -3234,7 +3234,7 @@ static long vwsnd_mixer_ioctl(struct file *file,
retval = -EINVAL;
}
mutex_unlock(&devc->mix_mutex);
- unlock_kernel();
+ mutex_unlock(&vwsnd_mutex);
return retval;
}
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index e7a8cd058efb..12e34653b8a8 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -207,12 +207,12 @@ config SND_CMIPCI
config SND_OXYGEN_LIB
tristate
- select SND_PCM
- select SND_MPU401_UART
config SND_OXYGEN
tristate "C-Media 8788 (Oxygen)"
select SND_OXYGEN_LIB
+ select SND_PCM
+ select SND_MPU401_UART
help
Say Y here to include support for sound cards based on the
C-Media CMI8788 (Oxygen HD Audio) chip:
@@ -581,6 +581,8 @@ config SND_HDSPM
config SND_HIFIER
tristate "TempoTec HiFier Fantasia"
select SND_OXYGEN_LIB
+ select SND_PCM
+ select SND_MPU401_UART
help
Say Y here to include support for the MediaTek/TempoTec HiFier
Fantasia sound card.
@@ -815,14 +817,17 @@ config SND_VIA82XX_MODEM
will be called snd-via82xx-modem.
config SND_VIRTUOSO
- tristate "Asus Virtuoso 100/200 (Xonar)"
+ tristate "Asus Virtuoso 66/100/200 (Xonar)"
select SND_OXYGEN_LIB
+ select SND_PCM
+ select SND_MPU401_UART
+ select SND_JACK if INPUT=y || INPUT=SND
help
Say Y here to include support for sound cards based on the
- Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X,
+ Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS,
Essence ST (Deluxe), and Essence STX.
- Support for the DS is experimental.
- Support for the HDAV1.3 (Deluxe) is very experimental.
+ Support for the HDAV1.3 (Deluxe) is incomplete; for the
+ HDAV1.3 Slim and Xense, missing.
To compile this driver as a module, choose M here: the module
will be called snd-virtuoso.
diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c
index c92f493d341e..557c782ae4fc 100644
--- a/sound/pci/au88x0/au88x0_mixer.c
+++ b/sound/pci/au88x0/au88x0_mixer.c
@@ -23,7 +23,7 @@ static int __devinit snd_vortex_mixer(vortex_t * vortex)
if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0)
return err;
memset(&ac97, 0, sizeof(ac97));
- // Intialize AC97 codec stuff.
+ // Initialize AC97 codec stuff.
ac97.private_data = vortex;
ac97.scaps = AC97_SCAP_NO_SPDIF;
err = snd_ac97_mixer(pbus, &ac97, &vortex->codec);
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h
index 14b8d9a91aae..f19c11077255 100644
--- a/sound/pci/ca0106/ca0106.h
+++ b/sound/pci/ca0106/ca0106.h
@@ -670,8 +670,9 @@ struct snd_ca0106_details {
gpio_type = 2 -> shared side-out/line-in. */
int i2c_adc; /* with i2c_adc=1, the driver adds some capture volume
controls, phone, mic, line-in and aux. */
- int spi_dac; /* spi_dac=1 adds the mute switch for each analog
- output, front, rear, etc. */
+ u16 spi_dac; /* spi_dac = 0 -> no spi interface for DACs
+ spi_dac = 0x<front><rear><center-lfe><side>
+ -> specifies DAC id for each channel pair. */
};
// definition of the chip-specific record
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 0a3d3d6e77b4..d2d12c08f937 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -227,7 +227,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
.name = "Audigy SE [SB0570]",
.gpio_type = 1,
.i2c_adc = 1,
- .spi_dac = 1 } ,
+ .spi_dac = 0x4021 } ,
/* New Audigy LS. Has a different DAC. */
/* SB0570:
* CTRL:CA0106-DAT
@@ -238,7 +238,17 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
.name = "Audigy SE OEM [SB0570a]",
.gpio_type = 1,
.i2c_adc = 1,
- .spi_dac = 1 } ,
+ .spi_dac = 0x4021 } ,
+ /* Sound Blaster 5.1vx
+ * Tested: Playback on front, rear, center/lfe speakers
+ * Not-Tested: Capture
+ */
+ { .serial = 0x10041102,
+ .name = "Sound Blaster 5.1vx [SB1070]",
+ .gpio_type = 1,
+ .i2c_adc = 0,
+ .spi_dac = 0x0124
+ } ,
/* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
/* SB0438
* CTRL:CA0106-DAT
@@ -254,7 +264,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
.name = "MSI K8N Diamond MB",
.gpio_type = 2,
.i2c_adc = 1,
- .spi_dac = 1 } ,
+ .spi_dac = 0x4021 } ,
/* Giga-byte GA-G1975X mobo
* Novell bnc#395807
*/
@@ -483,16 +493,18 @@ static void snd_ca0106_pcm_free_substream(struct snd_pcm_runtime *runtime)
}
static const int spi_dacd_reg[] = {
- [PCM_FRONT_CHANNEL] = SPI_DACD4_REG,
- [PCM_REAR_CHANNEL] = SPI_DACD0_REG,
- [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG,
- [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_REG,
+ SPI_DACD0_REG,
+ SPI_DACD1_REG,
+ SPI_DACD2_REG,
+ 0,
+ SPI_DACD4_REG,
};
static const int spi_dacd_bit[] = {
- [PCM_FRONT_CHANNEL] = SPI_DACD4_BIT,
- [PCM_REAR_CHANNEL] = SPI_DACD0_BIT,
- [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT,
- [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT,
+ SPI_DACD0_BIT,
+ SPI_DACD1_BIT,
+ SPI_DACD2_BIT,
+ 0,
+ SPI_DACD4_BIT,
};
static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
@@ -504,6 +516,45 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
}
}
+static int snd_ca0106_channel_dac(struct snd_ca0106_details *details,
+ int channel_id)
+{
+ switch (channel_id) {
+ case PCM_FRONT_CHANNEL:
+ return (details->spi_dac & 0xf000) >> (4 * 3);
+ case PCM_REAR_CHANNEL:
+ return (details->spi_dac & 0x0f00) >> (4 * 2);
+ case PCM_CENTER_LFE_CHANNEL:
+ return (details->spi_dac & 0x00f0) >> (4 * 1);
+ case PCM_UNKNOWN_CHANNEL:
+ return (details->spi_dac & 0x000f) >> (4 * 0);
+ default:
+ snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n",
+ channel_id);
+ }
+ return 0;
+}
+
+static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id,
+ int power)
+{
+ if (chip->details->spi_dac) {
+ const int dac = snd_ca0106_channel_dac(chip->details,
+ channel_id);
+ const int reg = spi_dacd_reg[dac];
+ const int bit = spi_dacd_bit[dac];
+
+ if (power)
+ /* Power up */
+ chip->spi_dac_reg[reg] &= ~bit;
+ else
+ /* Power down */
+ chip->spi_dac_reg[reg] |= bit;
+ return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+ }
+ return 0;
+}
+
/* open_playback callback */
static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream,
int channel_id)
@@ -543,12 +594,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr
return err;
snd_pcm_set_sync(substream);
- if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) {
- const int reg = spi_dacd_reg[channel_id];
-
- /* Power up dac */
- chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id];
- err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+ /* Front channel dac should already be on */
+ if (channel_id != PCM_FRONT_CHANNEL) {
+ err = snd_ca0106_pcm_power_dac(chip, channel_id, 1);
if (err < 0)
return err;
}
@@ -568,13 +616,14 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream)
restore_spdif_bits(chip, epcm->channel_id);
- if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) {
- const int reg = spi_dacd_reg[epcm->channel_id];
-
- /* Power down DAC */
- chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id];
- snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+ /* Front channel dac should stay on */
+ if (epcm->channel_id != PCM_FRONT_CHANNEL) {
+ int err;
+ err = snd_ca0106_pcm_power_dac(chip, epcm->channel_id, 0);
+ if (err < 0)
+ return err;
}
+
/* FIXME: maybe zero others */
return 0;
}
@@ -1002,29 +1051,27 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream)
struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_ca0106_pcm *epcm = runtime->private_data;
- snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0;
+ unsigned int ptr, prev_ptr;
int channel = epcm->channel_id;
+ int timeout = 10;
if (!epcm->running)
return 0;
- ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
- ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
- ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
- if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
- ptr2 = bytes_to_frames(runtime, ptr1);
- ptr2+= (ptr4 >> 3) * runtime->period_size;
- ptr=ptr2;
- if (ptr >= runtime->buffer_size)
- ptr -= runtime->buffer_size;
- /*
- printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
- "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
- ptr1, ptr2, ptr, (int)runtime->buffer_size,
- (int)runtime->period_size, (int)runtime->frame_bits,
- (int)runtime->rate);
- */
- return ptr;
+ prev_ptr = -1;
+ do {
+ ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
+ ptr = (ptr >> 3) * runtime->period_size;
+ ptr += bytes_to_frames(runtime,
+ snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel));
+ if (ptr >= runtime->buffer_size)
+ ptr -= runtime->buffer_size;
+ if (prev_ptr == ptr)
+ return ptr;
+ prev_ptr = ptr;
+ } while (--timeout);
+ snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n");
+ return 0;
}
/* pointer_capture callback */
@@ -1362,7 +1409,7 @@ static unsigned int spi_dac_init[] = {
SPI_REG(12, 0x00),
SPI_REG(SPI_LDA4_REG, SPI_DA_BIT_0dB),
SPI_REG(SPI_RDA4_REG, SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE),
- SPI_REG(SPI_DACD4_REG, 0x00),
+ SPI_REG(SPI_DACD4_REG, SPI_DACD4_BIT),
};
static unsigned int i2c_adc_init[][2] = {
@@ -1541,7 +1588,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
/* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */
}
- if (chip->details->spi_dac == 1) {
+ if (chip->details->spi_dac) {
/* The SB0570 use SPI to control DAC. */
int size, n;
@@ -1553,6 +1600,9 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
if (reg < ARRAY_SIZE(chip->spi_dac_reg))
chip->spi_dac_reg[reg] = spi_dac_init[n];
}
+
+ /* Enable front dac only */
+ snd_ca0106_pcm_power_dac(chip, PCM_FRONT_CHANNEL, 1);
}
}
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 85fd315d9999..630aa4998189 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -676,28 +676,65 @@ static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata =
I2C_VOLUME("Aux Capture Volume", 3),
};
-#define SPI_SWITCH(xname,reg,bit) \
-{ \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
- .info = spi_mute_info, \
- .get = spi_mute_get, \
- .put = spi_mute_put, \
- .private_value = (reg<<SPI_REG_SHIFT) | (bit) \
-}
-
-static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctls[]
-__devinitdata = {
- SPI_SWITCH("Analog Front Playback Switch",
- SPI_DMUTE4_REG, SPI_DMUTE4_BIT),
- SPI_SWITCH("Analog Rear Playback Switch",
- SPI_DMUTE0_REG, SPI_DMUTE0_BIT),
- SPI_SWITCH("Analog Center/LFE Playback Switch",
- SPI_DMUTE2_REG, SPI_DMUTE2_BIT),
- SPI_SWITCH("Analog Side Playback Switch",
- SPI_DMUTE1_REG, SPI_DMUTE1_BIT),
+static const int spi_dmute_reg[] = {
+ SPI_DMUTE0_REG,
+ SPI_DMUTE1_REG,
+ SPI_DMUTE2_REG,
+ 0,
+ SPI_DMUTE4_REG,
+};
+static const int spi_dmute_bit[] = {
+ SPI_DMUTE0_BIT,
+ SPI_DMUTE1_BIT,
+ SPI_DMUTE2_BIT,
+ 0,
+ SPI_DMUTE4_BIT,
};
+static struct snd_kcontrol_new __devinit
+snd_ca0106_volume_spi_dac_ctl(struct snd_ca0106_details *details,
+ int channel_id)
+{
+ struct snd_kcontrol_new spi_switch = {0};
+ int reg, bit;
+ int dac_id;
+
+ spi_switch.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ spi_switch.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+ spi_switch.info = spi_mute_info;
+ spi_switch.get = spi_mute_get;
+ spi_switch.put = spi_mute_put;
+
+ switch (channel_id) {
+ case PCM_FRONT_CHANNEL:
+ spi_switch.name = "Analog Front Playback Switch";
+ dac_id = (details->spi_dac & 0xf000) >> (4 * 3);
+ break;
+ case PCM_REAR_CHANNEL:
+ spi_switch.name = "Analog Rear Playback Switch";
+ dac_id = (details->spi_dac & 0x0f00) >> (4 * 2);
+ break;
+ case PCM_CENTER_LFE_CHANNEL:
+ spi_switch.name = "Analog Center/LFE Playback Switch";
+ dac_id = (details->spi_dac & 0x00f0) >> (4 * 1);
+ break;
+ case PCM_UNKNOWN_CHANNEL:
+ spi_switch.name = "Analog Side Playback Switch";
+ dac_id = (details->spi_dac & 0x000f) >> (4 * 0);
+ break;
+ default:
+ /* Unused channel */
+ spi_switch.name = NULL;
+ dac_id = 0;
+ }
+ reg = spi_dmute_reg[dac_id];
+ bit = spi_dmute_bit[dac_id];
+
+ spi_switch.private_value = (reg << SPI_REG_SHIFT) | bit;
+
+ return spi_switch;
+}
+
static int __devinit remove_ctl(struct snd_card *card, const char *name)
{
struct snd_ctl_elem_id id;
@@ -832,8 +869,18 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
if (err < 0)
return err;
}
- if (emu->details->spi_dac == 1)
- ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls);
+ if (emu->details->spi_dac) {
+ int i;
+ for (i = 0;; i++) {
+ struct snd_kcontrol_new ctl;
+ ctl = snd_ca0106_volume_spi_dac_ctl(emu->details, i);
+ if (!ctl.name)
+ break;
+ err = snd_ctl_add(card, snd_ctl_new1(&ctl, emu));
+ if (err < 0)
+ return err;
+ }
+ }
/* Create virtual master controls */
vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
@@ -845,7 +892,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
return err;
add_slaves(card, vmaster, slave_vols);
- if (emu->details->spi_dac == 1) {
+ if (emu->details->spi_dac) {
vmaster = snd_ctl_make_virtual_master("Master Playback Switch",
NULL);
if (!vmaster)
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c
index 8578c70c61f2..bab564824efe 100644
--- a/sound/pci/emu10k1/emumpu401.c
+++ b/sound/pci/emu10k1/emumpu401.c
@@ -321,7 +321,7 @@ static struct snd_rawmidi_ops snd_emu10k1_midi_input =
static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi)
{
- struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)rmidi->private_data;
+ struct snd_emu10k1_midi *midi = rmidi->private_data;
midi->interrupt = NULL;
midi->rmidi = NULL;
}
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index c7fba5379813..537cfba829a5 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -22,7 +22,7 @@
/* Power-Management-Code ( CONFIG_PM )
* for ens1371 only ( FIXME )
* derived from cs4281.c, atiixp.c and via82xx.c
- * using http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c1540.htm
+ * using http://www.alsa-project.org/~tiwai/writing-an-alsa-driver/
* by Kurt J. Bosch
*/
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 9194c3c1d04a..0ea5cc60ac78 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -119,47 +119,20 @@ config SND_HDA_CODEC_VIA
snd-hda-codec-via.
This module is automatically loaded at probing.
-config SND_HDA_CODEC_ATIHDMI
- bool "Build ATI HDMI HD-audio codec support"
- default y
- help
- Say Y here to include ATI HDMI HD-audio codec support in
- snd-hda-intel driver, such as ATI RS600 HDMI.
-
- When the HD-audio driver is built as a module, the codec
- support code is also built as another module,
- snd-hda-codec-atihdmi.
- This module is automatically loaded at probing.
-
-config SND_HDA_CODEC_NVHDMI
- bool "Build NVIDIA HDMI HD-audio codec support"
- default y
- help
- Say Y here to include NVIDIA HDMI HD-audio codec support in
- snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
-
- When the HD-audio driver is built as a module, the codec
- support code is also built as another module,
- snd-hda-codec-nvhdmi.
- This module is automatically loaded at probing.
-
-config SND_HDA_CODEC_INTELHDMI
- bool "Build INTEL HDMI HD-audio codec support"
+config SND_HDA_CODEC_HDMI
+ bool "Build HDMI/DisplayPort HD-audio codec support"
select SND_DYNAMIC_MINORS
default y
help
- Say Y here to include INTEL HDMI HD-audio codec support in
- snd-hda-intel driver, such as Eaglelake integrated HDMI.
+ Say Y here to include HDMI and DisplayPort HD-audio codec
+ support in snd-hda-intel driver. This includes all AMD/ATI,
+ Intel and Nvidia HDMI/DisplayPort codecs.
When the HD-audio driver is built as a module, the codec
support code is also built as another module,
- snd-hda-codec-intelhdmi.
+ snd-hda-codec-hdmi.
This module is automatically loaded at probing.
-config SND_HDA_ELD
- def_bool y
- depends on SND_HDA_CODEC_INTELHDMI || SND_HDA_CODEC_NVHDMI
-
config SND_HDA_CODEC_CIRRUS
bool "Build Cirrus Logic codec support"
depends on SND_HDA_INTEL
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 24bc195b02da..17ef3658f34b 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -3,7 +3,6 @@ snd-hda-intel-objs := hda_intel.o
snd-hda-codec-y := hda_codec.o
snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
-snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o
snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
@@ -12,13 +11,11 @@ snd-hda-codec-cmedia-objs := patch_cmedia.o
snd-hda-codec-analog-objs := patch_analog.o
snd-hda-codec-idt-objs := patch_sigmatel.o
snd-hda-codec-si3054-objs := patch_si3054.o
-snd-hda-codec-atihdmi-objs := patch_atihdmi.o
snd-hda-codec-cirrus-objs := patch_cirrus.o
snd-hda-codec-ca0110-objs := patch_ca0110.o
snd-hda-codec-conexant-objs := patch_conexant.o
snd-hda-codec-via-objs := patch_via.o
-snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o
-snd-hda-codec-intelhdmi-objs := patch_intelhdmi.o
+snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o
# common driver
obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
@@ -39,9 +36,6 @@ endif
ifdef CONFIG_SND_HDA_CODEC_SI3054
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o
endif
-ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
-endif
ifdef CONFIG_SND_HDA_CODEC_CIRRUS
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o
endif
@@ -54,11 +48,8 @@ endif
ifdef CONFIG_SND_HDA_CODEC_VIA
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o
endif
-ifdef CONFIG_SND_HDA_CODEC_NVHDMI
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-nvhdmi.o
-endif
-ifdef CONFIG_SND_HDA_CODEC_INTELHDMI
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-intelhdmi.o
+ifdef CONFIG_SND_HDA_CODEC_HDMI
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-hdmi.o
endif
# this must be the last entry after codec drivers;
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 14829210ef0b..644e3f14f8ca 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1216,6 +1216,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
struct hda_codec *c;
struct hda_cvt_setup *p;
unsigned int oldval, newval;
+ int type;
int i;
if (!nid)
@@ -1254,10 +1255,12 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
p->dirty = 0;
/* make other inactive cvts with the same stream-tag dirty */
+ type = get_wcaps_type(get_wcaps(codec, nid));
list_for_each_entry(c, &codec->bus->codec_list, list) {
for (i = 0; i < c->cvt_setups.used; i++) {
p = snd_array_elem(&c->cvt_setups, i);
- if (!p->active && p->stream_tag == stream_tag)
+ if (!p->active && p->stream_tag == stream_tag &&
+ get_wcaps_type(get_wcaps(codec, p->nid)) == type)
p->dirty = 1;
}
}
@@ -1281,6 +1284,9 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid,
if (!nid)
return;
+ if (codec->no_sticky_stream)
+ do_now = 1;
+
snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid);
p = get_hda_cvt_setup(codec, nid);
if (p) {
@@ -1831,6 +1837,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
hda_nid_t nid = get_amp_nid(kcontrol);
int dir = get_amp_direction(kcontrol);
unsigned int ofs = get_amp_offset(kcontrol);
+ bool min_mute = get_amp_min_mute(kcontrol);
u32 caps, val1, val2;
if (size < 4 * sizeof(unsigned int))
@@ -1841,6 +1848,8 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
val1 += ofs;
val1 = ((int)val1) * ((int)val2);
+ if (min_mute)
+ val2 |= TLV_DB_SCALE_MUTE;
if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
return -EFAULT;
if (put_user(2 * sizeof(unsigned int), _tlv + 1))
@@ -2228,10 +2237,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
HDA_AMP_MUTE,
*valp ? 0 : HDA_AMP_MUTE);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- if (codec->patch_ops.check_power_status)
- codec->patch_ops.check_power_status(codec, nid);
-#endif
+ hda_call_check_power_status(codec, nid);
snd_hda_power_down(codec);
return change;
}
@@ -4372,6 +4378,34 @@ static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
}
+/* add the found input-pin to the cfg->inputs[] table */
+static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
+ int type)
+{
+ if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
+ cfg->inputs[cfg->num_inputs].pin = nid;
+ cfg->inputs[cfg->num_inputs].type = type;
+ cfg->num_inputs++;
+ }
+}
+
+/* sort inputs in the order of AUTO_PIN_* type */
+static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
+{
+ int i, j;
+
+ for (i = 0; i < cfg->num_inputs; i++) {
+ for (j = i + 1; j < cfg->num_inputs; j++) {
+ if (cfg->inputs[i].type > cfg->inputs[j].type) {
+ struct auto_pin_cfg_item tmp;
+ tmp = cfg->inputs[i];
+ cfg->inputs[i] = cfg->inputs[j];
+ cfg->inputs[j] = tmp;
+ }
+ }
+ }
+}
+
/*
* Parse all pin widgets and store the useful pin nids to cfg
*
@@ -4385,7 +4419,7 @@ static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
* output, i.e. to line_out_pins[0]. So, line_outs is always positive
* if any analog output exists.
*
- * The analog input pins are assigned to input_pins array.
+ * The analog input pins are assigned to inputs array.
* The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
* respectively.
*/
@@ -4398,6 +4432,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
+ int i;
memset(cfg, 0, sizeof(*cfg));
@@ -4468,33 +4503,17 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
cfg->hp_outs++;
break;
- case AC_JACK_MIC_IN: {
- int preferred, alt;
- if (loc == AC_JACK_LOC_FRONT ||
- (loc & 0x30) == AC_JACK_LOC_INTERNAL) {
- preferred = AUTO_PIN_FRONT_MIC;
- alt = AUTO_PIN_MIC;
- } else {
- preferred = AUTO_PIN_MIC;
- alt = AUTO_PIN_FRONT_MIC;
- }
- if (!cfg->input_pins[preferred])
- cfg->input_pins[preferred] = nid;
- else if (!cfg->input_pins[alt])
- cfg->input_pins[alt] = nid;
+ case AC_JACK_MIC_IN:
+ add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
break;
- }
case AC_JACK_LINE_IN:
- if (loc == AC_JACK_LOC_FRONT)
- cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid;
- else
- cfg->input_pins[AUTO_PIN_LINE] = nid;
+ add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
break;
case AC_JACK_CD:
- cfg->input_pins[AUTO_PIN_CD] = nid;
+ add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
break;
case AC_JACK_AUX:
- cfg->input_pins[AUTO_PIN_AUX] = nid;
+ add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
break;
case AC_JACK_SPDIF_OUT:
case AC_JACK_DIG_OTHER_OUT:
@@ -4539,6 +4558,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
memmove(sequences_hp + i, sequences_hp + i + 1,
sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
}
+ memset(cfg->hp_pins + cfg->hp_outs, 0,
+ sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
}
/* sort by sequence */
@@ -4549,21 +4570,6 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
cfg->hp_outs);
- /* if we have only one mic, make it AUTO_PIN_MIC */
- if (!cfg->input_pins[AUTO_PIN_MIC] &&
- cfg->input_pins[AUTO_PIN_FRONT_MIC]) {
- cfg->input_pins[AUTO_PIN_MIC] =
- cfg->input_pins[AUTO_PIN_FRONT_MIC];
- cfg->input_pins[AUTO_PIN_FRONT_MIC] = 0;
- }
- /* ditto for line-in */
- if (!cfg->input_pins[AUTO_PIN_LINE] &&
- cfg->input_pins[AUTO_PIN_FRONT_LINE]) {
- cfg->input_pins[AUTO_PIN_LINE] =
- cfg->input_pins[AUTO_PIN_FRONT_LINE];
- cfg->input_pins[AUTO_PIN_FRONT_LINE] = 0;
- }
-
/*
* FIX-UP: if no line-outs are detected, try to use speaker or HP pin
* as a primary output
@@ -4602,6 +4608,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
break;
}
+ sort_autocfg_input_pins(cfg);
+
/*
* debug prints of the parsed results
*/
@@ -4621,14 +4629,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
if (cfg->dig_outs)
snd_printd(" dig-out=0x%x/0x%x\n",
cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
- snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
- " cd=0x%x, aux=0x%x\n",
- cfg->input_pins[AUTO_PIN_MIC],
- cfg->input_pins[AUTO_PIN_FRONT_MIC],
- cfg->input_pins[AUTO_PIN_LINE],
- cfg->input_pins[AUTO_PIN_FRONT_LINE],
- cfg->input_pins[AUTO_PIN_CD],
- cfg->input_pins[AUTO_PIN_AUX]);
+ snd_printd(" inputs:");
+ for (i = 0; i < cfg->num_inputs; i++) {
+ snd_printdd(" %s=0x%x",
+ hda_get_autocfg_input_label(codec, cfg, i),
+ cfg->inputs[i].pin);
+ }
+ snd_printd("\n");
if (cfg->dig_in_pin)
snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin);
@@ -4636,11 +4643,165 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
}
EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config);
-/* labels for input pins */
-const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = {
- "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux"
-};
-EXPORT_SYMBOL_HDA(auto_pin_cfg_labels);
+int snd_hda_get_input_pin_attr(unsigned int def_conf)
+{
+ unsigned int loc = get_defcfg_location(def_conf);
+ unsigned int conn = get_defcfg_connect(def_conf);
+ if (conn == AC_JACK_PORT_NONE)
+ return INPUT_PIN_ATTR_UNUSED;
+ /* Windows may claim the internal mic to be BOTH, too */
+ if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH)
+ return INPUT_PIN_ATTR_INT;
+ if ((loc & 0x30) == AC_JACK_LOC_INTERNAL)
+ return INPUT_PIN_ATTR_INT;
+ if ((loc & 0x30) == AC_JACK_LOC_SEPARATE)
+ return INPUT_PIN_ATTR_DOCK;
+ if (loc == AC_JACK_LOC_REAR)
+ return INPUT_PIN_ATTR_REAR;
+ if (loc == AC_JACK_LOC_FRONT)
+ return INPUT_PIN_ATTR_FRONT;
+ return INPUT_PIN_ATTR_NORMAL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
+
+/**
+ * hda_get_input_pin_label - Give a label for the given input pin
+ *
+ * When check_location is true, the function checks the pin location
+ * for mic and line-in pins, and set an appropriate prefix like "Front",
+ * "Rear", "Internal".
+ */
+
+const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
+ int check_location)
+{
+ unsigned int def_conf;
+ static const char *mic_names[] = {
+ "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
+ };
+ int attr;
+
+ def_conf = snd_hda_codec_get_pincfg(codec, pin);
+
+ switch (get_defcfg_device(def_conf)) {
+ case AC_JACK_MIC_IN:
+ if (!check_location)
+ return "Mic";
+ attr = snd_hda_get_input_pin_attr(def_conf);
+ if (!attr)
+ return "None";
+ return mic_names[attr - 1];
+ case AC_JACK_LINE_IN:
+ if (!check_location)
+ return "Line";
+ attr = snd_hda_get_input_pin_attr(def_conf);
+ if (!attr)
+ return "None";
+ if (attr == INPUT_PIN_ATTR_DOCK)
+ return "Dock Line";
+ return "Line";
+ case AC_JACK_AUX:
+ return "Aux";
+ case AC_JACK_CD:
+ return "CD";
+ case AC_JACK_SPDIF_IN:
+ return "SPDIF In";
+ case AC_JACK_DIG_OTHER_IN:
+ return "Digital In";
+ default:
+ return "Misc";
+ }
+}
+EXPORT_SYMBOL_HDA(hda_get_input_pin_label);
+
+/* Check whether the location prefix needs to be added to the label.
+ * If all mic-jacks are in the same location (e.g. rear panel), we don't
+ * have to put "Front" prefix to each label. In such a case, returns false.
+ */
+static int check_mic_location_need(struct hda_codec *codec,
+ const struct auto_pin_cfg *cfg,
+ int input)
+{
+ unsigned int defc;
+ int i, attr, attr2;
+
+ defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin);
+ attr = snd_hda_get_input_pin_attr(defc);
+ /* for internal or docking mics, we need locations */
+ if (attr <= INPUT_PIN_ATTR_NORMAL)
+ return 1;
+
+ attr = 0;
+ for (i = 0; i < cfg->num_inputs; i++) {
+ defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin);
+ attr2 = snd_hda_get_input_pin_attr(defc);
+ if (attr2 >= INPUT_PIN_ATTR_NORMAL) {
+ if (attr && attr != attr2)
+ return 1; /* different locations found */
+ attr = attr2;
+ }
+ }
+ return 0;
+}
+
+/**
+ * hda_get_autocfg_input_label - Get a label for the given input
+ *
+ * Get a label for the given input pin defined by the autocfg item.
+ * Unlike hda_get_input_pin_label(), this function checks all inputs
+ * defined in autocfg and avoids the redundant mic/line prefix as much as
+ * possible.
+ */
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+ const struct auto_pin_cfg *cfg,
+ int input)
+{
+ int type = cfg->inputs[input].type;
+ int has_multiple_pins = 0;
+
+ if ((input > 0 && cfg->inputs[input - 1].type == type) ||
+ (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type))
+ has_multiple_pins = 1;
+ if (has_multiple_pins && type == AUTO_PIN_MIC)
+ has_multiple_pins &= check_mic_location_need(codec, cfg, input);
+ return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
+ has_multiple_pins);
+}
+EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
+
+/**
+ * snd_hda_add_imux_item - Add an item to input_mux
+ *
+ * When the same label is used already in the existing items, the number
+ * suffix is appended to the label. This label index number is stored
+ * to type_idx when non-NULL pointer is given.
+ */
+int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
+ int index, int *type_idx)
+{
+ int i, label_idx = 0;
+ if (imux->num_items >= HDA_MAX_NUM_INPUTS) {
+ snd_printd(KERN_ERR "hda_codec: Too many imux items!\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < imux->num_items; i++) {
+ if (!strncmp(label, imux->items[i].label, strlen(label)))
+ label_idx++;
+ }
+ if (type_idx)
+ *type_idx = label_idx;
+ if (label_idx > 0)
+ snprintf(imux->items[imux->num_items].label,
+ sizeof(imux->items[imux->num_items].label),
+ "%s %d", label, label_idx);
+ else
+ strlcpy(imux->items[imux->num_items].label, label,
+ sizeof(imux->items[imux->num_items].label));
+ imux->items[imux->num_items].index = index;
+ imux->num_items++;
+ return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_add_imux_item);
#ifdef CONFIG_PM
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 62c702240108..fdf8d44f8b6b 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -850,6 +850,7 @@ struct hda_codec {
unsigned int pin_amp_workaround:1; /* pin out-amp takes index
* (e.g. Conexant codecs)
*/
+ unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */
unsigned int pins_shutup:1; /* pins are shut up */
unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
#ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -989,6 +990,18 @@ int snd_hda_suspend(struct hda_bus *bus);
int snd_hda_resume(struct hda_bus *bus);
#endif
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static inline
+int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
+{
+ if (codec->patch_ops.check_power_status)
+ return codec->patch_ops.check_power_status(codec, nid);
+ return 0;
+}
+#else
+#define hda_call_check_power_status(codec, nid) 0
+#endif
+
/*
* get widget information
*/
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index 26c3ade73583..cb0c23a6b473 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -332,7 +332,6 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
AC_DIPSIZE_ELD_BUF);
}
-EXPORT_SYMBOL_HDA(snd_hdmi_get_eld_size);
int snd_hdmi_get_eld(struct hdmi_eld *eld,
struct hda_codec *codec, hda_nid_t nid)
@@ -368,7 +367,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
kfree(buf);
return ret;
}
-EXPORT_SYMBOL_HDA(snd_hdmi_get_eld);
static void hdmi_show_short_audio_desc(struct cea_sad *a)
{
@@ -407,7 +405,6 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
}
buf[j] = '\0'; /* necessary when j == 0 */
}
-EXPORT_SYMBOL_HDA(snd_print_channel_allocation);
void snd_hdmi_show_eld(struct hdmi_eld *e)
{
@@ -426,7 +423,6 @@ void snd_hdmi_show_eld(struct hdmi_eld *e)
for (i = 0; i < e->sad_count; i++)
hdmi_show_short_audio_desc(e->sad + i);
}
-EXPORT_SYMBOL_HDA(snd_hdmi_show_eld);
#ifdef CONFIG_PROC_FS
@@ -585,7 +581,6 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_eld_proc_new);
void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
{
@@ -594,7 +589,6 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
eld->proc_entry = NULL;
}
}
-EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free);
#endif /* CONFIG_PROC_FS */
@@ -645,4 +639,3 @@ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm,
pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max);
pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps);
}
-EXPORT_SYMBOL_HDA(hdmi_eld_update_pcm_info);
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 5ea21285ee1f..fb0582f8d725 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -61,7 +61,6 @@ struct hda_gspec {
struct hda_gnode *cap_vol_node; /* Node for capture volume */
unsigned int cur_cap_src; /* current capture source */
struct hda_input_mux input_mux;
- char cap_labels[HDA_MAX_NUM_INPUTS][16];
unsigned int def_amp_in_caps;
unsigned int def_amp_out_caps;
@@ -506,11 +505,10 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl)
* returns 0 if not found, 1 if found, or a negative error code.
*/
static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
- struct hda_gnode *node)
+ struct hda_gnode *node, int idx)
{
int i, err;
unsigned int pinctl;
- char *label;
const char *type;
if (node->checked)
@@ -523,7 +521,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
child = hda_get_node(spec, node->conn_list[i]);
if (! child)
continue;
- err = parse_adc_sub_nodes(codec, spec, child);
+ err = parse_adc_sub_nodes(codec, spec, child, idx);
if (err < 0)
return err;
if (err > 0) {
@@ -564,9 +562,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
return 0;
type = "Input";
}
- label = spec->cap_labels[spec->input_mux.num_items];
- strcpy(label, type);
- spec->input_mux.items[spec->input_mux.num_items].label = label;
+ snd_hda_add_imux_item(&spec->input_mux, type, idx, NULL);
/* unmute the PIN external input */
unmute_input(codec, node, 0); /* index = 0? */
@@ -577,29 +573,6 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
return 1; /* found */
}
-/* add a capture source element */
-static void add_cap_src(struct hda_gspec *spec, int idx)
-{
- struct hda_input_mux_item *csrc;
- char *buf;
- int num, ocap;
-
- num = spec->input_mux.num_items;
- csrc = &spec->input_mux.items[num];
- buf = spec->cap_labels[num];
- for (ocap = 0; ocap < num; ocap++) {
- if (! strcmp(buf, spec->cap_labels[ocap])) {
- /* same label already exists,
- * put the index number to be unique
- */
- sprintf(buf, "%s %d", spec->cap_labels[ocap], num);
- break;
- }
- }
- csrc->index = idx;
- spec->input_mux.num_items++;
-}
-
/*
* parse input
*/
@@ -624,22 +597,18 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node)
for (i = 0; i < adc_node->nconns; i++) {
node = hda_get_node(spec, adc_node->conn_list[i]);
if (node && node->type == AC_WID_PIN) {
- err = parse_adc_sub_nodes(codec, spec, node);
+ err = parse_adc_sub_nodes(codec, spec, node, i);
if (err < 0)
return err;
- else if (err > 0)
- add_cap_src(spec, i);
}
}
/* ... then check the rests, more complicated connections */
for (i = 0; i < adc_node->nconns; i++) {
node = hda_get_node(spec, adc_node->conn_list[i]);
if (node && node->type != AC_WID_PIN) {
- err = parse_adc_sub_nodes(codec, spec, node);
+ err = parse_adc_sub_nodes(codec, spec, node, i);
if (err < 0)
return err;
- else if (err > 0)
- add_cap_src(spec, i);
}
}
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 34940a079051..21aa9b0e28f6 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -78,8 +78,8 @@ MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
module_param_array(model, charp, NULL, 0444);
MODULE_PARM_DESC(model, "Use the given board model.");
module_param_array(position_fix, int, NULL, 0444);
-MODULE_PARM_DESC(position_fix, "Fix DMA pointer "
- "(0 = auto, 1 = none, 2 = POSBUF).");
+MODULE_PARM_DESC(position_fix, "DMA pointer read method."
+ "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO).");
module_param_array(bdl_pos_adj, int, NULL, 0644);
MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
module_param_array(probe_mask, int, NULL, 0444);
@@ -305,6 +305,7 @@ enum {
POS_FIX_AUTO,
POS_FIX_LPIB,
POS_FIX_POSBUF,
+ POS_FIX_VIACOMBO,
};
/* Defines for ATI HD Audio support in SB450 south bridge */
@@ -433,7 +434,6 @@ struct azx {
unsigned int polling_mode :1;
unsigned int msi :1;
unsigned int irq_pending_warned :1;
- unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
unsigned int probing :1; /* codec probing phase */
/* for debugging */
@@ -458,6 +458,7 @@ enum {
AZX_DRIVER_ULI,
AZX_DRIVER_NVIDIA,
AZX_DRIVER_TERA,
+ AZX_DRIVER_CTX,
AZX_DRIVER_GENERIC,
AZX_NUM_DRIVERS, /* keep this as last entry */
};
@@ -473,6 +474,7 @@ static char *driver_short_names[] __devinitdata = {
[AZX_DRIVER_ULI] = "HDA ULI M5461",
[AZX_DRIVER_NVIDIA] = "HDA NVidia",
[AZX_DRIVER_TERA] = "HDA Teradici",
+ [AZX_DRIVER_CTX] = "HDA Creative",
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
};
@@ -563,7 +565,10 @@ static void azx_init_cmd_io(struct azx *chip)
/* reset the rirb hw write pointer */
azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
/* set N=1, get RIRB response interrupt for new entry */
- azx_writew(chip, RINTCNT, 1);
+ if (chip->driver_type == AZX_DRIVER_CTX)
+ azx_writew(chip, RINTCNT, 0xc0);
+ else
+ azx_writew(chip, RINTCNT, 1);
/* enable rirb dma and response irq */
azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
spin_unlock_irq(&chip->reg_lock);
@@ -1136,8 +1141,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
/* clear rirb int */
status = azx_readb(chip, RIRBSTS);
if (status & RIRB_INT_MASK) {
- if (status & RIRB_INT_RESPONSE)
+ if (status & RIRB_INT_RESPONSE) {
+ if (chip->driver_type == AZX_DRIVER_CTX)
+ udelay(80);
azx_update_rirb(chip);
+ }
azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
}
@@ -1309,11 +1317,8 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));
/* enable the position buffer */
- if (chip->position_fix[0] == POS_FIX_POSBUF ||
- chip->position_fix[0] == POS_FIX_AUTO ||
- chip->position_fix[1] == POS_FIX_POSBUF ||
- chip->position_fix[1] == POS_FIX_AUTO ||
- chip->via_dmapos_patch) {
+ if (chip->position_fix[0] != POS_FIX_LPIB ||
+ chip->position_fix[1] != POS_FIX_LPIB) {
if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
azx_writel(chip, DPLBASE,
(u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
@@ -1647,7 +1652,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
struct azx_dev *azx_dev = get_azx_dev(substream);
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned int bufsize, period_bytes, format_val;
+ unsigned int bufsize, period_bytes, format_val, stream_tag;
int err;
azx_stream_reset(chip, azx_dev);
@@ -1689,7 +1694,12 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
else
azx_dev->fifo_size = 0;
- return snd_hda_codec_prepare(apcm->codec, hinfo, azx_dev->stream_tag,
+ stream_tag = azx_dev->stream_tag;
+ /* CA-IBG chips need the playback stream starting from 1 */
+ if (chip->driver_type == AZX_DRIVER_CTX &&
+ stream_tag > chip->capture_streams)
+ stream_tag -= chip->capture_streams;
+ return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
azx_dev->format_val, substream);
}
@@ -1852,20 +1862,21 @@ static unsigned int azx_get_position(struct azx *chip,
struct azx_dev *azx_dev)
{
unsigned int pos;
+ int stream = azx_dev->substream->stream;
- if (chip->via_dmapos_patch)
+ switch (chip->position_fix[stream]) {
+ case POS_FIX_LPIB:
+ /* read LPIB */
+ pos = azx_sd_readl(azx_dev, SD_LPIB);
+ break;
+ case POS_FIX_VIACOMBO:
pos = azx_via_get_position(chip, azx_dev);
- else {
- int stream = azx_dev->substream->stream;
- if (chip->position_fix[stream] == POS_FIX_POSBUF ||
- chip->position_fix[stream] == POS_FIX_AUTO) {
- /* use the position buffer */
- pos = le32_to_cpu(*azx_dev->posbuf);
- } else {
- /* read LPIB */
- pos = azx_sd_readl(azx_dev, SD_LPIB);
- }
+ break;
+ default:
+ /* use the position buffer */
+ pos = le32_to_cpu(*azx_dev->posbuf);
}
+
if (pos >= azx_dev->bufsize)
pos = 0;
return pos;
@@ -2313,19 +2324,10 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
switch (fix) {
case POS_FIX_LPIB:
case POS_FIX_POSBUF:
+ case POS_FIX_VIACOMBO:
return fix;
}
- /* Check VIA/ATI HD Audio Controller exist */
- switch (chip->driver_type) {
- case AZX_DRIVER_VIA:
- case AZX_DRIVER_ATI:
- chip->via_dmapos_patch = 1;
- /* Use link position directly, avoid any transfer problem. */
- return POS_FIX_LPIB;
- }
- chip->via_dmapos_patch = 0;
-
q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
if (q) {
printk(KERN_INFO
@@ -2334,6 +2336,15 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
q->value, q->subvendor, q->subdevice);
return q->value;
}
+
+ /* Check VIA/ATI HD Audio Controller exist */
+ switch (chip->driver_type) {
+ case AZX_DRIVER_VIA:
+ case AZX_DRIVER_ATI:
+ /* Use link position directly, avoid any transfer problem. */
+ return POS_FIX_VIACOMBO;
+ }
+
return POS_FIX_AUTO;
}
@@ -2735,25 +2746,17 @@ static void __devexit azx_remove(struct pci_dev *pci)
/* PCI IDs */
static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
- /* ICH 6..10 */
- { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH },
- { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH },
- { PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH },
- { PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH },
- { PCI_DEVICE(0x8086, 0x2911), .driver_data = AZX_DRIVER_ICH },
- { PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH },
- { PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH },
- { PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH },
- { PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH },
- /* PCH */
- { PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH },
- { PCI_DEVICE(0x8086, 0x3b57), .driver_data = AZX_DRIVER_ICH },
/* CPT */
{ PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
/* PBG */
{ PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH },
/* SCH */
{ PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
+ /* Generic Intel */
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
+ .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
+ .class_mask = 0xffffff,
+ .driver_data = AZX_DRIVER_ICH },
/* ATI SB 450/600 */
{ PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI },
{ PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI },
@@ -2794,11 +2797,13 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
.class_mask = 0xffffff,
- .driver_data = AZX_DRIVER_GENERIC },
+ .driver_data = AZX_DRIVER_CTX },
#else
/* this entry seems still valid -- i.e. without emu20kx chip */
- { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC },
+ { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX },
#endif
+ /* Vortex86MX */
+ { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
/* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 28ab4aead48f..46bbefe2e4a9 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -38,10 +38,11 @@
*/
#define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs) \
((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23))
+#define HDA_AMP_VAL_MIN_MUTE (1<<29)
#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \
HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0)
/* mono volume with index (index=0,1,...) (channel=1,2) */
-#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
+#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, dir, flags) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
.subdevice = HDA_SUBDEV_AMP_FLAG, \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
@@ -51,16 +52,20 @@
.get = snd_hda_mixer_amp_volume_get, \
.put = snd_hda_mixer_amp_volume_put, \
.tlv = { .c = snd_hda_mixer_amp_tlv }, \
- .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
+ .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, dir) | flags }
/* stereo volume with index */
#define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \
- HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction)
+ HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction, 0)
/* mono volume */
#define HDA_CODEC_VOLUME_MONO(xname, nid, channel, xindex, direction) \
- HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction)
+ HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction, 0)
/* stereo volume */
#define HDA_CODEC_VOLUME(xname, nid, xindex, direction) \
HDA_CODEC_VOLUME_MONO(xname, nid, 3, xindex, direction)
+/* stereo volume with min=mute */
+#define HDA_CODEC_VOLUME_MIN_MUTE(xname, nid, xindex, direction) \
+ HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, 3, xindex, direction, \
+ HDA_AMP_VAL_MIN_MUTE)
/* mono mute switch with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
@@ -215,7 +220,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
*/
#define HDA_MAX_NUM_INPUTS 16
struct hda_input_mux_item {
- const char *label;
+ char label[32];
unsigned int index;
};
struct hda_input_mux {
@@ -366,9 +371,7 @@ struct hda_bus_unsolicited {
enum {
AUTO_PIN_MIC,
- AUTO_PIN_FRONT_MIC,
- AUTO_PIN_LINE,
- AUTO_PIN_FRONT_LINE,
+ AUTO_PIN_LINE_IN,
AUTO_PIN_CD,
AUTO_PIN_AUX,
AUTO_PIN_LAST
@@ -380,9 +383,33 @@ enum {
AUTO_PIN_HP_OUT
};
-extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST];
-
#define AUTO_CFG_MAX_OUTS 5
+#define AUTO_CFG_MAX_INS 8
+
+struct auto_pin_cfg_item {
+ hda_nid_t pin;
+ int type;
+};
+
+struct auto_pin_cfg;
+const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
+ int check_location);
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+ const struct auto_pin_cfg *cfg,
+ int input);
+int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
+ int index, int *type_index_ret);
+
+enum {
+ INPUT_PIN_ATTR_UNUSED, /* pin not connected */
+ INPUT_PIN_ATTR_INT, /* internal mic/line-in */
+ INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */
+ INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */
+ INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */
+ INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */
+};
+
+int snd_hda_get_input_pin_attr(unsigned int def_conf);
struct auto_pin_cfg {
int line_outs;
@@ -393,7 +420,8 @@ struct auto_pin_cfg {
int hp_outs;
int line_out_type; /* AUTO_PIN_XXX_OUT */
hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
- hda_nid_t input_pins[AUTO_PIN_LAST];
+ int num_inputs;
+ struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
int dig_outs;
hda_nid_t dig_out_pins[2];
hda_nid_t dig_in_pin;
@@ -558,6 +586,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1)
#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf)
#define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f)
+#define get_amp_min_mute(kc) (((kc)->private_value >> 29) & 0x1)
/*
* CEA Short Audio Descriptor data
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 10bbbaf6ebc3..f7ff3f7ccb8e 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -1276,6 +1276,7 @@ static int patch_ad1986a(struct hda_codec *codec)
spec->multiout.no_share_stream = 1;
codec->no_trigger_sense = 1;
+ codec->no_sticky_stream = 1;
return 0;
}
@@ -1463,6 +1464,7 @@ static int patch_ad1983(struct hda_codec *codec)
codec->patch_ops = ad198x_patch_ops;
codec->no_trigger_sense = 1;
+ codec->no_sticky_stream = 1;
return 0;
}
@@ -1917,6 +1919,7 @@ static int patch_ad1981(struct hda_codec *codec)
}
codec->no_trigger_sense = 1;
+ codec->no_sticky_stream = 1;
return 0;
}
@@ -2880,7 +2883,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
/* create input playback/capture controls for the given pin */
static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
- const char *ctlname, int boost)
+ const char *ctlname, int ctlidx, int boost)
{
char name[32];
int err, idx;
@@ -2909,25 +2912,27 @@ static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
}
/* create playback/capture controls for input pins */
-static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec,
+static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
+ struct ad198x_spec *spec = codec->spec;
struct hda_input_mux *imux = &spec->private_imux;
- int i, err;
-
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- err = new_analog_input(spec, cfg->input_pins[i],
- auto_pin_cfg_labels[i],
- i <= AUTO_PIN_FRONT_MIC);
+ int i, err, type, type_idx;
+
+ for (i = 0; i < cfg->num_inputs; i++) {
+ const char *label;
+ type = cfg->inputs[i].type;
+ label = hda_get_autocfg_input_label(codec, cfg, i);
+ snd_hda_add_imux_item(imux, label,
+ ad1988_pin_to_adc_idx(cfg->inputs[i].pin),
+ &type_idx);
+ err = new_analog_input(spec, cfg->inputs[i].pin,
+ label, type_idx,
+ type == AUTO_PIN_MIC);
if (err < 0)
return err;
- imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
- imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->input_pins[i]);
- imux->num_items++;
}
- imux->items[imux->num_items].label = "Mix";
- imux->items[imux->num_items].index = 9;
- imux->num_items++;
+ snd_hda_add_imux_item(imux, "Mix", 9, NULL);
if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
"Analog Mix Playback Volume",
@@ -2994,12 +2999,11 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec)
static void ad1988_auto_init_analog_input(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
+ const struct auto_pin_cfg *cfg = &spec->autocfg;
int i, idx;
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- hda_nid_t nid = spec->autocfg.input_pins[i];
- if (! nid)
- continue;
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
switch (nid) {
case 0x15: /* port-C */
snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
@@ -3009,7 +3013,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
break;
}
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
+ i == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
if (nid != AD1988_PIN_CD_NID)
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_MUTE);
@@ -3040,7 +3044,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
"Speaker")) < 0 ||
(err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
"Headphone")) < 0 ||
- (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
+ (err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
return err;
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
@@ -3235,6 +3239,7 @@ static int patch_ad1988(struct hda_codec *codec)
spec->vmaster_nid = 0x04;
codec->no_trigger_sense = 1;
+ codec->no_sticky_stream = 1;
return 0;
}
@@ -3449,6 +3454,7 @@ static int patch_ad1884(struct hda_codec *codec)
codec->patch_ops = ad198x_patch_ops;
codec->no_trigger_sense = 1;
+ codec->no_sticky_stream = 1;
return 0;
}
@@ -4422,6 +4428,7 @@ static int patch_ad1884a(struct hda_codec *codec)
}
codec->no_trigger_sense = 1;
+ codec->no_sticky_stream = 1;
return 0;
}
@@ -4761,6 +4768,7 @@ static int patch_ad1882(struct hda_codec *codec)
}
codec->no_trigger_sense = 1;
+ codec->no_sticky_stream = 1;
return 0;
}
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
deleted file mode 100644
index fb684f00156b..000000000000
--- a/sound/pci/hda/patch_atihdmi.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * HD audio interface patch for ATI HDMI codecs
- *
- * Copyright (c) 2006 ATI Technologies Inc.
- *
- *
- * This driver is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This driver 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/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include "hda_codec.h"
-#include "hda_local.h"
-
-struct atihdmi_spec {
- struct hda_multi_out multiout;
-
- struct hda_pcm pcm_rec;
-};
-
-#define CVT_NID 0x02 /* audio converter */
-#define PIN_NID 0x03 /* HDMI output pin */
-
-static struct hda_verb atihdmi_basic_init[] = {
- /* enable digital output on pin widget */
- { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- {} /* terminator */
-};
-
-/*
- * Controls
- */
-static int atihdmi_build_controls(struct hda_codec *codec)
-{
- struct atihdmi_spec *spec = codec->spec;
- int err;
-
- err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static int atihdmi_init(struct hda_codec *codec)
-{
- snd_hda_sequence_write(codec, atihdmi_basic_init);
- /* SI codec requires to unmute the pin */
- if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
- snd_hda_codec_write(codec, PIN_NID, 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_OUT_UNMUTE);
- return 0;
-}
-
-/*
- * Digital out
- */
-static int atihdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct atihdmi_spec *spec = codec->spec;
- return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int atihdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct atihdmi_spec *spec = codec->spec;
- return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int atihdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- unsigned int stream_tag,
- unsigned int format,
- struct snd_pcm_substream *substream)
-{
- struct atihdmi_spec *spec = codec->spec;
- int chans = substream->runtime->channels;
- int i, err;
-
- err = snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
- format, substream);
- if (err < 0)
- return err;
- snd_hda_codec_write(codec, CVT_NID, 0, AC_VERB_SET_CVT_CHAN_COUNT,
- chans - 1);
- /* FIXME: XXX */
- for (i = 0; i < chans; i++) {
- snd_hda_codec_write(codec, CVT_NID, 0,
- AC_VERB_SET_HDMI_CHAN_SLOT,
- (i << 4) | i);
- }
- return 0;
-}
-
-static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
- .nid = CVT_NID, /* NID to query formats and rates and setup streams */
- .ops = {
- .open = atihdmi_dig_playback_pcm_open,
- .close = atihdmi_dig_playback_pcm_close,
- .prepare = atihdmi_dig_playback_pcm_prepare
- },
-};
-
-static int atihdmi_build_pcms(struct hda_codec *codec)
-{
- struct atihdmi_spec *spec = codec->spec;
- struct hda_pcm *info = &spec->pcm_rec;
- unsigned int chans;
-
- codec->num_pcms = 1;
- codec->pcm_info = info;
-
- info->name = "ATI HDMI";
- info->pcm_type = HDA_PCM_TYPE_HDMI;
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback;
-
- /* FIXME: we must check ELD and change the PCM parameters dynamically
- */
- chans = get_wcaps(codec, CVT_NID);
- chans = get_wcaps_channels(chans);
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
-
- return 0;
-}
-
-static void atihdmi_free(struct hda_codec *codec)
-{
- kfree(codec->spec);
-}
-
-static struct hda_codec_ops atihdmi_patch_ops = {
- .build_controls = atihdmi_build_controls,
- .build_pcms = atihdmi_build_pcms,
- .init = atihdmi_init,
- .free = atihdmi_free,
-};
-
-static int patch_atihdmi(struct hda_codec *codec)
-{
- struct atihdmi_spec *spec;
-
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
-
- spec->multiout.num_dacs = 0; /* no analog */
- spec->multiout.max_channels = 2;
- /* NID for copying analog to digital,
- * seems to be unused in pure-digital
- * case.
- */
- spec->multiout.dig_out_nid = CVT_NID;
-
- codec->patch_ops = atihdmi_patch_ops;
-
- return 0;
-}
-
-/*
- * patch entries
- */
-static struct hda_codec_preset snd_hda_preset_atihdmi[] = {
- { .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi },
- { .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi },
- { .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi },
- { .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi },
- { .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi },
- { .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi },
- {} /* terminator */
-};
-
-MODULE_ALIAS("snd-hda-codec-id:1002793c");
-MODULE_ALIAS("snd-hda-codec-id:10027919");
-MODULE_ALIAS("snd-hda-codec-id:1002791a");
-MODULE_ALIAS("snd-hda-codec-id:1002aa01");
-MODULE_ALIAS("snd-hda-codec-id:10951390");
-MODULE_ALIAS("snd-hda-codec-id:17e80047");
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("ATI HDMI HD-audio codec");
-
-static struct hda_codec_preset_list atihdmi_list = {
- .preset = snd_hda_preset_atihdmi,
- .owner = THIS_MODULE,
-};
-
-static int __init patch_atihdmi_init(void)
-{
- return snd_hda_add_codec_preset(&atihdmi_list);
-}
-
-static void __exit patch_atihdmi_exit(void)
-{
- snd_hda_delete_codec_preset(&atihdmi_list);
-}
-
-module_init(patch_atihdmi_init)
-module_exit(patch_atihdmi_exit)
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c
index af478019088e..46c8bf48c31f 100644
--- a/sound/pci/hda/patch_ca0110.c
+++ b/sound/pci/hda/patch_ca0110.c
@@ -468,13 +468,13 @@ static void parse_input(struct hda_codec *codec)
spec->dig_in = nid;
continue;
}
- for (j = 0; j < AUTO_PIN_LAST; j++)
- if (cfg->input_pins[j] == pin)
+ for (j = 0; j < cfg->num_inputs; j++)
+ if (cfg->inputs[j].pin == pin)
break;
- if (j >= AUTO_PIN_LAST)
+ if (j >= cfg->num_inputs)
continue;
spec->input_pins[n] = pin;
- spec->input_labels[n] = auto_pin_cfg_labels[j];
+ spec->input_labels[n] = hda_get_input_pin_label(codec, pin, 1);
spec->adcs[n] = nid;
n++;
}
@@ -489,7 +489,7 @@ static void parse_digital(struct hda_codec *codec)
if (cfg->dig_outs &&
snd_hda_get_connections(codec, cfg->dig_out_pins[0],
&spec->dig_out, 1) == 1)
- spec->multiout.dig_out_nid = cfg->dig_out_pins[0];
+ spec->multiout.dig_out_nid = spec->dig_out;
}
static int ca0110_parse_auto_config(struct hda_codec *codec)
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 488fd9ade1ba..460fb2ef7e39 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -65,6 +65,7 @@ struct cs_spec {
/* available models */
enum {
+ CS420X_MBP53,
CS420X_MBP55,
CS420X_IMAC27,
CS420X_AUTO,
@@ -329,12 +330,12 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx)
{
struct cs_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
- hda_nid_t pin = cfg->input_pins[idx];
+ hda_nid_t pin = cfg->inputs[idx].pin;
unsigned int val = snd_hda_query_pin_caps(codec, pin);
if (!(val & AC_PINCAP_PRES_DETECT))
return 0;
val = snd_hda_codec_get_pincfg(codec, pin);
- return (get_defcfg_connect(val) == AC_JACK_PORT_COMPLEX);
+ return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT);
}
static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
@@ -424,10 +425,8 @@ static int parse_input(struct hda_codec *codec)
struct auto_pin_cfg *cfg = &spec->autocfg;
int i;
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- hda_nid_t pin = cfg->input_pins[i];
- if (!pin)
- continue;
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t pin = cfg->inputs[i].pin;
spec->input_idx[spec->num_inputs] = i;
spec->capsrc_idx[i] = spec->num_inputs++;
spec->cur_input = i;
@@ -438,16 +437,17 @@ static int parse_input(struct hda_codec *codec)
/* check whether the automatic mic switch is available */
if (spec->num_inputs == 2 &&
- spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) {
- if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) {
- if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
+ cfg->inputs[0].type == AUTO_PIN_MIC &&
+ cfg->inputs[1].type == AUTO_PIN_MIC) {
+ if (is_ext_mic(codec, cfg->inputs[0].pin)) {
+ if (!is_ext_mic(codec, cfg->inputs[1].pin)) {
spec->mic_detect = 1;
- spec->automic_idx = AUTO_PIN_FRONT_MIC;
+ spec->automic_idx = 0;
}
} else {
- if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
+ if (is_ext_mic(codec, cfg->inputs[1].pin)) {
spec->mic_detect = 1;
- spec->automic_idx = AUTO_PIN_MIC;
+ spec->automic_idx = 1;
}
}
}
@@ -674,6 +674,7 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
unsigned int idx;
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -682,7 +683,8 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
if (uinfo->value.enumerated.item >= spec->num_inputs)
uinfo->value.enumerated.item = spec->num_inputs - 1;
idx = spec->input_idx[uinfo->value.enumerated.item];
- strcpy(uinfo->value.enumerated.name, auto_pin_cfg_labels[idx]);
+ strcpy(uinfo->value.enumerated.name,
+ hda_get_input_pin_label(codec, cfg->inputs[idx].pin, 1));
return 0;
}
@@ -740,6 +742,27 @@ static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec,
return bind;
}
+/* add a (input-boost) volume control to the given input pin */
+static int add_input_volume_control(struct hda_codec *codec,
+ struct auto_pin_cfg *cfg,
+ int item)
+{
+ hda_nid_t pin = cfg->inputs[item].pin;
+ u32 caps;
+ const char *label;
+ struct snd_kcontrol *kctl;
+
+ if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP))
+ return 0;
+ caps = query_amp_caps(codec, pin, HDA_INPUT);
+ caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
+ if (caps <= 1)
+ return 0;
+ label = hda_get_autocfg_input_label(codec, cfg, item);
+ return add_volume(codec, label, 0,
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl);
+}
+
static int build_input(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
@@ -779,6 +802,12 @@ static int build_input(struct hda_codec *codec)
return err;
}
+ for (i = 0; i < spec->num_inputs; i++) {
+ err = add_input_volume_control(codec, &spec->autocfg, i);
+ if (err < 0)
+ return err;
+ }
+
return 0;
}
@@ -838,7 +867,8 @@ static void cs_automute(struct hda_codec *codec)
AC_VERB_SET_PIN_WIDGET_CONTROL,
hp_present ? 0 : PIN_OUT);
}
- if (spec->board_config == CS420X_MBP55 ||
+ if (spec->board_config == CS420X_MBP53 ||
+ spec->board_config == CS420X_MBP55 ||
spec->board_config == CS420X_IMAC27) {
unsigned int gpio = hp_present ? 0x02 : 0x08;
snd_hda_codec_write(codec, 0x01, 0,
@@ -853,15 +883,12 @@ static void cs_automic(struct hda_codec *codec)
hda_nid_t nid;
unsigned int present;
- nid = cfg->input_pins[spec->automic_idx];
+ nid = cfg->inputs[spec->automic_idx].pin;
present = snd_hda_jack_detect(codec, nid);
if (present)
change_cur_input(codec, spec->automic_idx, 0);
- else {
- unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ?
- AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC;
- change_cur_input(codec, imic, 0);
- }
+ else
+ change_cur_input(codec, !spec->automic_idx, 0);
}
/*
@@ -918,14 +945,14 @@ static void init_input(struct hda_codec *codec)
unsigned int coef;
int i;
- for (i = 0; i < AUTO_PIN_LAST; i++) {
+ for (i = 0; i < cfg->num_inputs; i++) {
unsigned int ctl;
- hda_nid_t pin = cfg->input_pins[i];
- if (!pin || !spec->adc_nid[i])
+ hda_nid_t pin = cfg->inputs[i].pin;
+ if (!spec->adc_nid[i])
continue;
/* set appropriate pin control and mute first */
ctl = PIN_IN;
- if (i <= AUTO_PIN_FRONT_MIC) {
+ if (cfg->inputs[i].type == AUTO_PIN_MIC) {
unsigned int caps = snd_hda_query_pin_caps(codec, pin);
caps >>= AC_PINCAP_VREF_SHIFT;
if (caps & AC_PINCAP_VREF_80)
@@ -1130,6 +1157,7 @@ static int cs_parse_auto_config(struct hda_codec *codec)
}
static const char *cs420x_models[CS420X_MODELS] = {
+ [CS420X_MBP53] = "mbp53",
[CS420X_MBP55] = "mbp55",
[CS420X_IMAC27] = "imac27",
[CS420X_AUTO] = "auto",
@@ -1137,7 +1165,9 @@ static const char *cs420x_models[CS420X_MODELS] = {
static struct snd_pci_quirk cs420x_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
+ SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
{} /* terminator */
};
@@ -1147,6 +1177,20 @@ struct cs_pincfg {
u32 val;
};
+static struct cs_pincfg mbp53_pincfgs[] = {
+ { 0x09, 0x012b4050 },
+ { 0x0a, 0x90100141 },
+ { 0x0b, 0x90100140 },
+ { 0x0c, 0x018b3020 },
+ { 0x0d, 0x90a00110 },
+ { 0x0e, 0x400000f0 },
+ { 0x0f, 0x01cbe030 },
+ { 0x10, 0x014be060 },
+ { 0x12, 0x400000f0 },
+ { 0x15, 0x400000f0 },
+ {} /* terminator */
+};
+
static struct cs_pincfg mbp55_pincfgs[] = {
{ 0x09, 0x012b4030 },
{ 0x0a, 0x90100121 },
@@ -1176,6 +1220,7 @@ static struct cs_pincfg imac27_pincfgs[] = {
};
static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
+ [CS420X_MBP53] = mbp53_pincfgs,
[CS420X_MBP55] = mbp55_pincfgs,
[CS420X_IMAC27] = imac27_pincfgs,
};
@@ -1208,6 +1253,7 @@ static int patch_cs420x(struct hda_codec *codec)
switch (spec->board_config) {
case CS420X_IMAC27:
+ case CS420X_MBP53:
case CS420X_MBP55:
/* GPIO1 = headphones */
/* GPIO3 = speakers */
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 972e7c453b3d..6361f752b5f3 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -57,6 +57,12 @@ struct conexant_jack {
};
+struct pin_dac_pair {
+ hda_nid_t pin;
+ hda_nid_t dac;
+ int type;
+};
+
struct conexant_spec {
struct snd_kcontrol_new *mixers[5];
@@ -77,6 +83,7 @@ struct conexant_spec {
unsigned int cur_eapd;
unsigned int hp_present;
unsigned int auto_mic;
+ int auto_mic_ext; /* autocfg.inputs[] index for ext mic */
unsigned int need_dac_fix;
/* capture */
@@ -110,9 +117,12 @@ struct conexant_spec {
struct auto_pin_cfg autocfg;
struct hda_input_mux private_imux;
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
+ struct pin_dac_pair dac_info[8];
+ int dac_info_filled;
- unsigned int dell_automute;
unsigned int port_d_mode;
+ unsigned int auto_mute:1; /* used in auto-parser */
+ unsigned int dell_automute:1;
unsigned int dell_vostro:1;
unsigned int ideapad:1;
unsigned int thinkpad:1;
@@ -3065,7 +3075,7 @@ enum {
CXT5066_LAPTOP, /* Laptops w/ EAPD support */
CXT5066_DELL_LAPTOP, /* Dell Laptop */
CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */
- CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */
+ CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */
CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */
CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */
CXT5066_HP_LAPTOP, /* HP Laptop */
@@ -3076,25 +3086,26 @@ static const char *cxt5066_models[CXT5066_MODELS] = {
[CXT5066_LAPTOP] = "laptop",
[CXT5066_DELL_LAPTOP] = "dell-laptop",
[CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5",
- [CXT5066_DELL_VOSTO] = "dell-vostro",
+ [CXT5066_DELL_VOSTRO] = "dell-vostro",
[CXT5066_IDEAPAD] = "ideapad",
[CXT5066_THINKPAD] = "thinkpad",
[CXT5066_HP_LAPTOP] = "hp-laptop",
};
static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
- SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
- CXT5066_LAPTOP),
+ SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD),
+ SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO),
SND_PCI_QUIRK(0x1028, 0x02f5, "Dell",
CXT5066_DELL_LAPTOP),
- SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
- SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTO),
- SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO),
+ SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO),
SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP),
SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
+ SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
+ CXT5066_LAPTOP),
+ SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
@@ -3196,7 +3207,7 @@ static int patch_cxt5066(struct hda_codec *codec)
spec->capture_prepare = cxt5066_olpc_capture_prepare;
spec->capture_cleanup = cxt5066_olpc_capture_cleanup;
break;
- case CXT5066_DELL_VOSTO:
+ case CXT5066_DELL_VOSTRO:
codec->patch_ops.init = cxt5066_init;
codec->patch_ops.unsol_event = cxt5066_vostro_event;
spec->init_verbs[0] = cxt5066_init_verbs_vostro;
@@ -3254,6 +3265,604 @@ static int patch_cxt5066(struct hda_codec *codec)
}
/*
+ * Automatic parser for CX20641 & co
+ */
+
+static hda_nid_t cx_auto_adc_nids[] = { 0x14 };
+
+/* get the connection index of @nid in the widget @mux */
+static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
+ hda_nid_t nid)
+{
+ hda_nid_t conn[HDA_MAX_NUM_INPUTS];
+ int i, nums;
+
+ nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
+ for (i = 0; i < nums; i++)
+ if (conn[i] == nid)
+ return i;
+ return -1;
+}
+
+/* get an unassigned DAC from the given list.
+ * Return the nid if found and reduce the DAC list, or return zero if
+ * not found
+ */
+static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t pin,
+ hda_nid_t *dacs, int *num_dacs)
+{
+ int i, nums = *num_dacs;
+ hda_nid_t ret = 0;
+
+ for (i = 0; i < nums; i++) {
+ if (get_connection_index(codec, pin, dacs[i]) >= 0) {
+ ret = dacs[i];
+ break;
+ }
+ }
+ if (!ret)
+ return 0;
+ if (--nums > 0)
+ memmove(dacs, dacs + 1, nums * sizeof(hda_nid_t));
+ *num_dacs = nums;
+ return ret;
+}
+
+#define MAX_AUTO_DACS 5
+
+/* fill analog DAC list from the widget tree */
+static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs)
+{
+ hda_nid_t nid, end_nid;
+ int nums = 0;
+
+ end_nid = codec->start_nid + codec->num_nodes;
+ for (nid = codec->start_nid; nid < end_nid; nid++) {
+ unsigned int wcaps = get_wcaps(codec, nid);
+ unsigned int type = get_wcaps_type(wcaps);
+ if (type == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) {
+ dacs[nums++] = nid;
+ if (nums >= MAX_AUTO_DACS)
+ break;
+ }
+ }
+ return nums;
+}
+
+/* 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)
+{
+ int i, nums;
+
+ nums = 0;
+ for (i = 0; i < num_pins; i++) {
+ filled[nums].pin = pins[i];
+ filled[nums].type = type;
+ filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest);
+ nums++;
+ }
+ return nums;
+}
+
+/* parse analog output paths */
+static void cx_auto_parse_output(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ hda_nid_t dacs[MAX_AUTO_DACS];
+ int i, j, nums, rest;
+
+ 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);
+ 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)
+ continue;
+ switch (spec->dac_info[i].type) {
+ case AUTO_PIN_LINE_OUT:
+ spec->private_dac_nids[spec->multiout.num_dacs] = dac;
+ spec->multiout.num_dacs++;
+ break;
+ case AUTO_PIN_HP_OUT:
+ case AUTO_PIN_SPEAKER_OUT:
+ if (!spec->multiout.hp_nid) {
+ spec->multiout.hp_nid = dac;
+ break;
+ }
+ for (j = 0; j < ARRAY_SIZE(spec->multiout.extra_out_nid); j++)
+ if (!spec->multiout.extra_out_nid[j]) {
+ spec->multiout.extra_out_nid[j] = dac;
+ break;
+ }
+ break;
+ }
+ }
+ spec->multiout.dac_nids = spec->private_dac_nids;
+ spec->multiout.max_channels = nums * 2;
+
+ if (cfg->hp_outs > 0)
+ spec->auto_mute = 1;
+ spec->vmaster_nid = spec->private_dac_nids[0];
+}
+
+/* auto-mute/unmute speaker and line outs according to headphone jack */
+static void cx_auto_hp_automute(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i, present;
+
+ if (!spec->auto_mute)
+ return;
+ present = 0;
+ for (i = 0; i < cfg->hp_outs; i++) {
+ if (snd_hda_jack_detect(codec, cfg->hp_pins[i])) {
+ present = 1;
+ break;
+ }
+ }
+ for (i = 0; i < cfg->line_outs; i++) {
+ snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ present ? 0 : PIN_OUT);
+ }
+ for (i = 0; i < cfg->speaker_outs; i++) {
+ snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ present ? 0 : PIN_OUT);
+ }
+}
+
+/* automatic switch internal and external mic */
+static void cx_auto_automic(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ struct hda_input_mux *imux = &spec->private_imux;
+ int ext_idx = spec->auto_mic_ext;
+
+ if (!spec->auto_mic)
+ return;
+ if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) {
+ snd_hda_codec_write(codec, spec->adc_nids[0], 0,
+ AC_VERB_SET_CONNECT_SEL,
+ imux->items[ext_idx].index);
+ } else {
+ snd_hda_codec_write(codec, spec->adc_nids[0], 0,
+ AC_VERB_SET_CONNECT_SEL,
+ imux->items[!ext_idx].index);
+ }
+}
+
+static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20;
+ switch (res >> 26) {
+ case CONEXANT_HP_EVENT:
+ cx_auto_hp_automute(codec);
+ conexant_report_jack(codec, nid);
+ break;
+ case CONEXANT_MIC_EVENT:
+ cx_auto_automic(codec);
+ conexant_report_jack(codec, nid);
+ break;
+ }
+}
+
+/* return true if it's an internal-mic pin */
+static int is_int_mic(struct hda_codec *codec, hda_nid_t pin)
+{
+ unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
+ return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
+ snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT;
+}
+
+/* return true if it's an external-mic pin */
+static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin)
+{
+ unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
+ return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
+ snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL &&
+ (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_PRES_DETECT);
+}
+
+/* check whether the pin config is suitable for auto-mic switching;
+ * auto-mic is enabled only when one int-mic and one-ext mic exist
+ */
+static void cx_auto_check_auto_mic(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+
+ if (is_ext_mic(codec, cfg->inputs[0].pin) &&
+ is_int_mic(codec, cfg->inputs[1].pin)) {
+ spec->auto_mic = 1;
+ spec->auto_mic_ext = 1;
+ return;
+ }
+ if (is_int_mic(codec, cfg->inputs[1].pin) &&
+ is_ext_mic(codec, cfg->inputs[0].pin)) {
+ spec->auto_mic = 1;
+ spec->auto_mic_ext = 0;
+ return;
+ }
+}
+
+static void cx_auto_parse_input(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ struct hda_input_mux *imux;
+ int i;
+
+ imux = &spec->private_imux;
+ for (i = 0; i < cfg->num_inputs; i++) {
+ int idx = get_connection_index(codec, spec->adc_nids[0],
+ cfg->inputs[i].pin);
+ if (idx >= 0) {
+ const char *label;
+ label = hda_get_autocfg_input_label(codec, cfg, i);
+ snd_hda_add_imux_item(imux, label, idx, NULL);
+ }
+ }
+ if (imux->num_items == 2 && cfg->num_inputs == 2)
+ cx_auto_check_auto_mic(codec);
+ if (imux->num_items > 1 && !spec->auto_mic)
+ spec->input_mux = imux;
+}
+
+/* get digital-input audio widget corresponding to the given pin */
+static hda_nid_t cx_auto_get_dig_in(struct hda_codec *codec, hda_nid_t pin)
+{
+ hda_nid_t nid, end_nid;
+
+ end_nid = codec->start_nid + codec->num_nodes;
+ for (nid = codec->start_nid; nid < end_nid; nid++) {
+ unsigned int wcaps = get_wcaps(codec, nid);
+ unsigned int type = get_wcaps_type(wcaps);
+ if (type == AC_WID_AUD_IN && (wcaps & AC_WCAP_DIGITAL)) {
+ if (get_connection_index(codec, nid, pin) >= 0)
+ return nid;
+ }
+ }
+ return 0;
+}
+
+static void cx_auto_parse_digital(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ hda_nid_t nid;
+
+ if (cfg->dig_outs &&
+ snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) == 1)
+ spec->multiout.dig_out_nid = nid;
+ if (cfg->dig_in_pin)
+ spec->dig_in_nid = cx_auto_get_dig_in(codec, cfg->dig_in_pin);
+}
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+static void cx_auto_parse_beep(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ hda_nid_t nid, end_nid;
+
+ end_nid = codec->start_nid + codec->num_nodes;
+ for (nid = codec->start_nid; nid < end_nid; nid++)
+ if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) {
+ set_beep_amp(spec, nid, 0, HDA_OUTPUT);
+ break;
+ }
+}
+#else
+#define cx_auto_parse_beep(codec)
+#endif
+
+static int cx_auto_parse_auto_config(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ int err;
+
+ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+ if (err < 0)
+ return err;
+
+ cx_auto_parse_output(codec);
+ cx_auto_parse_input(codec);
+ cx_auto_parse_digital(codec);
+ cx_auto_parse_beep(codec);
+ return 0;
+}
+
+static void cx_auto_turn_on_eapd(struct hda_codec *codec, int num_pins,
+ hda_nid_t *pins)
+{
+ int i;
+ for (i = 0; i < num_pins; i++) {
+ if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
+ snd_hda_codec_write(codec, pins[i], 0,
+ AC_VERB_SET_EAPD_BTLENABLE, 0x02);
+ }
+}
+
+static void select_connection(struct hda_codec *codec, hda_nid_t pin,
+ hda_nid_t src)
+{
+ int idx = get_connection_index(codec, pin, src);
+ if (idx >= 0)
+ snd_hda_codec_write(codec, pin, 0,
+ AC_VERB_SET_CONNECT_SEL, idx);
+}
+
+static void cx_auto_init_output(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ hda_nid_t nid;
+ int i;
+
+ for (i = 0; i < spec->multiout.num_dacs; i++)
+ snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+ for (i = 0; i < cfg->hp_outs; i++)
+ snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+ if (spec->auto_mute) {
+ for (i = 0; i < cfg->hp_outs; i++) {
+ snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | CONEXANT_HP_EVENT);
+ }
+ cx_auto_hp_automute(codec);
+ } else {
+ for (i = 0; i < cfg->line_outs; i++)
+ snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ for (i = 0; i < cfg->speaker_outs; i++)
+ snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ }
+
+ for (i = 0; i < spec->dac_info_filled; i++) {
+ nid = spec->dac_info[i].dac;
+ if (!nid)
+ nid = spec->multiout.dac_nids[0];
+ select_connection(codec, spec->dac_info[i].pin, nid);
+ }
+
+ /* turn on EAPD */
+ cx_auto_turn_on_eapd(codec, cfg->line_outs, cfg->line_out_pins);
+ cx_auto_turn_on_eapd(codec, cfg->hp_outs, cfg->hp_pins);
+ cx_auto_turn_on_eapd(codec, cfg->speaker_outs, cfg->speaker_pins);
+}
+
+static void cx_auto_init_input(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i;
+
+ for (i = 0; i < spec->num_adc_nids; i++)
+ snd_hda_codec_write(codec, spec->adc_nids[i], 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0));
+
+ for (i = 0; i < cfg->num_inputs; i++) {
+ unsigned int type;
+ if (cfg->inputs[i].type == AUTO_PIN_MIC)
+ type = PIN_VREF80;
+ else
+ type = PIN_IN;
+ snd_hda_codec_write(codec, cfg->inputs[i].pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, type);
+ }
+
+ if (spec->auto_mic) {
+ int ext_idx = spec->auto_mic_ext;
+ snd_hda_codec_write(codec, cfg->inputs[ext_idx].pin, 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | CONEXANT_MIC_EVENT);
+ cx_auto_automic(codec);
+ } else {
+ for (i = 0; i < spec->num_adc_nids; i++) {
+ snd_hda_codec_write(codec, spec->adc_nids[i], 0,
+ AC_VERB_SET_CONNECT_SEL,
+ spec->private_imux.items[0].index);
+ }
+ }
+}
+
+static void cx_auto_init_digital(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+
+ if (spec->multiout.dig_out_nid)
+ snd_hda_codec_write(codec, cfg->dig_out_pins[0], 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ if (spec->dig_in_nid)
+ snd_hda_codec_write(codec, cfg->dig_in_pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
+}
+
+static int cx_auto_init(struct hda_codec *codec)
+{
+ /*snd_hda_sequence_write(codec, cx_auto_init_verbs);*/
+ cx_auto_init_output(codec);
+ cx_auto_init_input(codec);
+ cx_auto_init_digital(codec);
+ return 0;
+}
+
+static int cx_auto_add_volume(struct hda_codec *codec, const char *basename,
+ const char *dir, int cidx,
+ hda_nid_t nid, int hda_dir)
+{
+ static char name[32];
+ static struct snd_kcontrol_new knew[] = {
+ HDA_CODEC_VOLUME(name, 0, 0, 0),
+ HDA_CODEC_MUTE(name, 0, 0, 0),
+ };
+ static char *sfx[2] = { "Volume", "Switch" };
+ int i, err;
+
+ for (i = 0; i < 2; i++) {
+ struct snd_kcontrol *kctl;
+ knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, hda_dir);
+ knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
+ knew[i].index = cidx;
+ snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]);
+ kctl = snd_ctl_new1(&knew[i], codec);
+ if (!kctl)
+ return -ENOMEM;
+ err = snd_hda_ctl_add(codec, nid, kctl);
+ if (err < 0)
+ return err;
+ if (!(query_amp_caps(codec, nid, hda_dir) & AC_AMPCAP_MUTE))
+ break;
+ }
+ return 0;
+}
+
+#define cx_auto_add_pb_volume(codec, nid, str, idx) \
+ cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
+
+static int cx_auto_build_output_controls(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ int i, err;
+ int num_line = 0, num_hp = 0, num_spk = 0;
+ static const char *texts[3] = { "Front", "Surround", "CLFE" };
+
+ if (spec->dac_info_filled == 1)
+ return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac,
+ "Master", 0);
+ for (i = 0; i < spec->dac_info_filled; i++) {
+ const char *label;
+ int idx, type;
+ if (!spec->dac_info[i].dac)
+ continue;
+ type = spec->dac_info[i].type;
+ if (type == AUTO_PIN_LINE_OUT)
+ type = spec->autocfg.line_out_type;
+ switch (type) {
+ case AUTO_PIN_LINE_OUT:
+ default:
+ label = texts[num_line++];
+ idx = 0;
+ break;
+ case AUTO_PIN_HP_OUT:
+ label = "Headphone";
+ idx = num_hp++;
+ break;
+ case AUTO_PIN_SPEAKER_OUT:
+ label = "Speaker";
+ idx = num_spk++;
+ break;
+ }
+ err = cx_auto_add_pb_volume(codec, spec->dac_info[i].dac,
+ label, idx);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static int cx_auto_build_input_controls(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ static const char *prev_label;
+ int i, err, cidx;
+
+ err = cx_auto_add_volume(codec, "Capture", "", 0, spec->adc_nids[0],
+ HDA_INPUT);
+ if (err < 0)
+ return err;
+ prev_label = NULL;
+ cidx = 0;
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
+ const char *label;
+ if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
+ continue;
+ label = hda_get_autocfg_input_label(codec, cfg, i);
+ if (label == prev_label)
+ cidx++;
+ else
+ cidx = 0;
+ prev_label = label;
+ err = cx_auto_add_volume(codec, label, " Capture", cidx,
+ nid, HDA_INPUT);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static int cx_auto_build_controls(struct hda_codec *codec)
+{
+ int err;
+
+ err = cx_auto_build_output_controls(codec);
+ if (err < 0)
+ return err;
+ err = cx_auto_build_input_controls(codec);
+ if (err < 0)
+ return err;
+ return conexant_build_controls(codec);
+}
+
+static struct hda_codec_ops cx_auto_patch_ops = {
+ .build_controls = cx_auto_build_controls,
+ .build_pcms = conexant_build_pcms,
+ .init = cx_auto_init,
+ .free = conexant_free,
+ .unsol_event = cx_auto_unsol_event,
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+ .suspend = conexant_suspend,
+#endif
+ .reboot_notify = snd_hda_shutup_pins,
+};
+
+static int patch_conexant_auto(struct hda_codec *codec)
+{
+ struct conexant_spec *spec;
+ int err;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+ codec->spec = spec;
+ spec->adc_nids = cx_auto_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids);
+ spec->capsrc_nids = spec->adc_nids;
+ err = cx_auto_parse_auto_config(codec);
+ if (err < 0) {
+ kfree(codec->spec);
+ codec->spec = NULL;
+ return err;
+ }
+ codec->patch_ops = cx_auto_patch_ops;
+ if (spec->beep_amp)
+ snd_hda_attach_beep_device(codec, spec->beep_amp);
+ return 0;
+}
+
+/*
*/
static struct hda_codec_preset snd_hda_preset_conexant[] = {
@@ -3271,6 +3880,22 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = {
.patch = patch_cxt5066 },
{ .id = 0x14f15069, .name = "CX20585",
.patch = patch_cxt5066 },
+ { .id = 0x14f15097, .name = "CX20631",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f15098, .name = "CX20632",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f150a1, .name = "CX20641",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f150a2, .name = "CX20642",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f150ab, .name = "CX20651",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f150ac, .name = "CX20652",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f150b8, .name = "CX20664",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f150b9, .name = "CX20665",
+ .patch = patch_conexant_auto },
{} /* terminator */
};
@@ -3281,6 +3906,14 @@ MODULE_ALIAS("snd-hda-codec-id:14f15066");
MODULE_ALIAS("snd-hda-codec-id:14f15067");
MODULE_ALIAS("snd-hda-codec-id:14f15068");
MODULE_ALIAS("snd-hda-codec-id:14f15069");
+MODULE_ALIAS("snd-hda-codec-id:14f15097");
+MODULE_ALIAS("snd-hda-codec-id:14f15098");
+MODULE_ALIAS("snd-hda-codec-id:14f150a1");
+MODULE_ALIAS("snd-hda-codec-id:14f150a2");
+MODULE_ALIAS("snd-hda-codec-id:14f150ab");
+MODULE_ALIAS("snd-hda-codec-id:14f150ac");
+MODULE_ALIAS("snd-hda-codec-id:14f150b8");
+MODULE_ALIAS("snd-hda-codec-id:14f150b9");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Conexant HD-audio codec");
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index afd6022a96a7..d3e49aa5b9ec 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -3,6 +3,9 @@
* patch_hdmi.c - routines for HDMI/DisplayPort codecs
*
* Copyright(c) 2008-2010 Intel Corporation. All rights reserved.
+ * Copyright (c) 2006 ATI Technologies Inc.
+ * Copyright (c) 2008 NVIDIA Corp. All rights reserved.
+ * Copyright (c) 2008 Wei Ni <wni@nvidia.com>
*
* Authors:
* Wu Fengguang <wfg@linux.intel.com>
@@ -25,6 +28,22 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+/*
+ * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
+ * could support two independent pipes, each of them can be connected to one or
+ * more ports (DVI, HDMI or DisplayPort).
+ *
+ * The HDA correspondence of pipes/ports are converter/pin nodes.
+ */
+#define MAX_HDMI_CVTS 3
+#define MAX_HDMI_PINS 3
struct hdmi_spec {
int num_cvts;
@@ -49,10 +68,10 @@ struct hdmi_spec {
struct hda_pcm_stream codec_pcm_pars[MAX_HDMI_CVTS];
/*
- * nvhdmi specific
+ * ati/nvhdmi specific
*/
struct hda_multi_out multiout;
- unsigned int codec_type;
+ struct hda_pcm_stream *pcm_playback;
/* misc flags */
/* PD bit indicates only the update, not the current state */
@@ -65,13 +84,25 @@ struct hdmi_audio_infoframe {
u8 ver; /* 0x01 */
u8 len; /* 0x0a */
- u8 checksum; /* PB0 */
+ u8 checksum;
+
u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */
u8 SS01_SF24;
u8 CXT04;
u8 CA;
u8 LFEPBL01_LSV36_DM_INH7;
- u8 reserved[5]; /* PB6 - PB10 */
+};
+
+struct dp_audio_infoframe {
+ u8 type; /* 0x84 */
+ u8 len; /* 0x1b */
+ u8 ver; /* 0x11 << 2 */
+
+ u8 CC02_CT47; /* match with HDMI infoframe from this on */
+ u8 SS01_SF24;
+ u8 CXT04;
+ u8 CA;
+ u8 LFEPBL01_LSV36_DM_INH7;
};
/*
@@ -162,7 +193,7 @@ static int hdmi_channel_mapping[0x32][8] = {
/* 4ch */
[0x03] = { 0x00, 0x11, 0x23, 0x32, 0x44, 0xf5, 0xf6, 0xf7 },
/* surround41 */
- [0x09] = { 0x00, 0x11, 0x24, 0x34, 0x43, 0xf2, 0xf6, 0xf7 },
+ [0x09] = { 0x00, 0x11, 0x24, 0x35, 0x42, 0xf3, 0xf6, 0xf7 },
/* surround50 */
[0x0a] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0xf2, 0xf6, 0xf7 },
/* surround51 */
@@ -175,7 +206,7 @@ static int hdmi_channel_mapping[0x32][8] = {
* This is an ordered list!
*
* The preceding ones have better chances to be selected by
- * hdmi_setup_channel_allocation().
+ * hdmi_channel_allocation().
*/
static struct cea_channel_speaker_allocation channel_allocations[] = {
/* channel: 7 6 5 4 3 2 1 0 */
@@ -352,14 +383,14 @@ static void init_channel_allocations(void)
*
* TODO: it could select the wrong CA from multiple candidates.
*/
-static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
- struct hdmi_audio_infoframe *ai)
+static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
+ int channels)
{
struct hdmi_spec *spec = codec->spec;
struct hdmi_eld *eld;
int i;
+ int ca = 0;
int spk_mask = 0;
- int channels = 1 + (ai->CC02_CT47 & 0x7);
char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
/*
@@ -397,16 +428,16 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
if (channels == channel_allocations[i].channels &&
(spk_mask & channel_allocations[i].spk_mask) ==
channel_allocations[i].spk_mask) {
- ai->CA = channel_allocations[i].ca_index;
+ ca = channel_allocations[i].ca_index;
break;
}
}
snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf));
snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n",
- ai->CA, channels, buf);
+ ca, channels, buf);
- return ai->CA;
+ return ca;
}
static void hdmi_debug_channel_mapping(struct hda_codec *codec,
@@ -428,10 +459,9 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec,
static void hdmi_setup_channel_mapping(struct hda_codec *codec,
hda_nid_t pin_nid,
- struct hdmi_audio_infoframe *ai)
+ int ca)
{
int i;
- int ca = ai->CA;
int err;
if (hdmi_channel_mapping[ca][1] == 0) {
@@ -528,41 +558,37 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
#endif
}
-static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *ai)
+static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *hdmi_ai)
{
- u8 *bytes = (u8 *)ai;
+ u8 *bytes = (u8 *)hdmi_ai;
u8 sum = 0;
int i;
- ai->checksum = 0;
+ hdmi_ai->checksum = 0;
- for (i = 0; i < sizeof(*ai); i++)
+ for (i = 0; i < sizeof(*hdmi_ai); i++)
sum += bytes[i];
- ai->checksum = -sum;
+ hdmi_ai->checksum = -sum;
}
static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
hda_nid_t pin_nid,
- struct hdmi_audio_infoframe *ai)
+ u8 *dip, int size)
{
- u8 *bytes = (u8 *)ai;
int i;
hdmi_debug_dip_size(codec, pin_nid);
hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */
- hdmi_checksum_audio_infoframe(ai);
-
hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
- for (i = 0; i < sizeof(*ai); i++)
- hdmi_write_dip_byte(codec, pin_nid, bytes[i]);
+ for (i = 0; i < size; i++)
+ hdmi_write_dip_byte(codec, pin_nid, dip[i]);
}
static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
- struct hdmi_audio_infoframe *ai)
+ u8 *dip, int size)
{
- u8 *bytes = (u8 *)ai;
u8 val;
int i;
@@ -571,10 +597,10 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
return false;
hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
- for (i = 0; i < sizeof(*ai); i++) {
+ for (i = 0; i < size; i++) {
val = snd_hda_codec_read(codec, pin_nid, 0,
AC_VERB_GET_HDMI_DIP_DATA, 0);
- if (val != bytes[i])
+ if (val != dip[i])
return false;
}
@@ -586,15 +612,13 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
{
struct hdmi_spec *spec = codec->spec;
hda_nid_t pin_nid;
+ int channels = substream->runtime->channels;
+ int ca;
int i;
- struct hdmi_audio_infoframe ai = {
- .type = 0x84,
- .ver = 0x01,
- .len = 0x0a,
- .CC02_CT47 = substream->runtime->channels - 1,
- };
+ u8 ai[max(sizeof(struct hdmi_audio_infoframe),
+ sizeof(struct dp_audio_infoframe))];
- hdmi_setup_channel_allocation(codec, nid, &ai);
+ ca = hdmi_channel_allocation(codec, nid, channels);
for (i = 0; i < spec->num_pins; i++) {
if (spec->pin_cvt[i] != nid)
@@ -603,14 +627,45 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
continue;
pin_nid = spec->pin[i];
- if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) {
+
+ memset(ai, 0, sizeof(ai));
+ if (spec->sink_eld[i].conn_type == 0) { /* HDMI */
+ struct hdmi_audio_infoframe *hdmi_ai;
+
+ hdmi_ai = (struct hdmi_audio_infoframe *)ai;
+ hdmi_ai->type = 0x84;
+ hdmi_ai->ver = 0x01;
+ hdmi_ai->len = 0x0a;
+ hdmi_ai->CC02_CT47 = channels - 1;
+ hdmi_checksum_audio_infoframe(hdmi_ai);
+ } else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */
+ struct dp_audio_infoframe *dp_ai;
+
+ dp_ai = (struct dp_audio_infoframe *)ai;
+ dp_ai->type = 0x84;
+ dp_ai->len = 0x1b;
+ dp_ai->ver = 0x11 << 2;
+ dp_ai->CC02_CT47 = channels - 1;
+ } else {
+ snd_printd("HDMI: unknown connection type at pin %d\n",
+ pin_nid);
+ continue;
+ }
+
+ /*
+ * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
+ * sizeof(*dp_ai) to avoid partial match/update problems when
+ * the user switches between HDMI/DP monitors.
+ */
+ if (!hdmi_infoframe_uptodate(codec, pin_nid, ai, sizeof(ai))) {
snd_printdd("hdmi_setup_audio_infoframe: "
"cvt=%d pin=%d channels=%d\n",
nid, pin_nid,
- substream->runtime->channels);
- hdmi_setup_channel_mapping(codec, pin_nid, &ai);
+ channels);
+ hdmi_setup_channel_mapping(codec, pin_nid, ca);
hdmi_stop_infoframe_trans(codec, pin_nid);
- hdmi_fill_audio_infoframe(codec, pin_nid, &ai);
+ hdmi_fill_audio_infoframe(codec, pin_nid,
+ ai, sizeof(ai));
hdmi_start_infoframe_trans(codec, pin_nid);
}
}
@@ -791,7 +846,6 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
/*
* HDA/HDMI auto parsing
*/
-
static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
{
struct hdmi_spec *spec = codec->spec;
@@ -922,3 +976,664 @@ static int hdmi_parse_codec(struct hda_codec *codec)
return 0;
}
+/*
+ */
+static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = {
+ "HDMI 0",
+ "HDMI 1",
+ "HDMI 2",
+};
+
+/*
+ * HDMI callbacks
+ */
+
+static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ hdmi_set_channel_count(codec, hinfo->nid,
+ substream->runtime->channels);
+
+ hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
+
+ return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
+}
+
+static struct hda_pcm_stream generic_hdmi_pcm_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .ops = {
+ .open = hdmi_pcm_open,
+ .prepare = generic_hdmi_playback_pcm_prepare,
+ },
+};
+
+static int generic_hdmi_build_pcms(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hda_pcm *info = spec->pcm_rec;
+ int i;
+
+ codec->num_pcms = spec->num_cvts;
+ codec->pcm_info = info;
+
+ for (i = 0; i < codec->num_pcms; i++, info++) {
+ unsigned int chans;
+ struct hda_pcm_stream *pstr;
+
+ chans = get_wcaps(codec, spec->cvt[i]);
+ chans = get_wcaps_channels(chans);
+
+ info->name = generic_hdmi_pcm_names[i];
+ info->pcm_type = HDA_PCM_TYPE_HDMI;
+ pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
+ if (spec->pcm_playback)
+ *pstr = *spec->pcm_playback;
+ else
+ *pstr = generic_hdmi_pcm_playback;
+ pstr->nid = spec->cvt[i];
+ if (pstr->channels_max <= 2 && chans && chans <= 16)
+ pstr->channels_max = chans;
+ }
+
+ return 0;
+}
+
+static int generic_hdmi_build_controls(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int err;
+ int i;
+
+ for (i = 0; i < codec->num_pcms; i++) {
+ err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int generic_hdmi_init(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; spec->pin[i]; i++) {
+ hdmi_enable_output(codec, spec->pin[i]);
+ snd_hda_codec_write(codec, spec->pin[i], 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | spec->pin[i]);
+ }
+ return 0;
+}
+
+static void generic_hdmi_free(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i < spec->num_pins; i++)
+ snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
+
+ kfree(spec);
+}
+
+static struct hda_codec_ops generic_hdmi_patch_ops = {
+ .init = generic_hdmi_init,
+ .free = generic_hdmi_free,
+ .build_pcms = generic_hdmi_build_pcms,
+ .build_controls = generic_hdmi_build_controls,
+ .unsol_event = hdmi_unsol_event,
+};
+
+static int patch_generic_hdmi(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec;
+ int i;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+ if (hdmi_parse_codec(codec) < 0) {
+ codec->spec = NULL;
+ kfree(spec);
+ return -EINVAL;
+ }
+ codec->patch_ops = generic_hdmi_patch_ops;
+
+ for (i = 0; i < spec->num_pins; i++)
+ snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
+
+ init_channel_allocations();
+
+ return 0;
+}
+
+/*
+ * Nvidia specific implementations
+ */
+
+#define Nv_VERB_SET_Channel_Allocation 0xF79
+#define Nv_VERB_SET_Info_Frame_Checksum 0xF7A
+#define Nv_VERB_SET_Audio_Protection_On 0xF98
+#define Nv_VERB_SET_Audio_Protection_Off 0xF99
+
+#define nvhdmi_master_con_nid_7x 0x04
+#define nvhdmi_master_pin_nid_7x 0x05
+
+static hda_nid_t nvhdmi_con_nids_7x[4] = {
+ /*front, rear, clfe, rear_surr */
+ 0x6, 0x8, 0xa, 0xc,
+};
+
+static struct hda_verb nvhdmi_basic_init_7x[] = {
+ /* set audio protect on */
+ { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
+ /* enable digital output on pin widget */
+ { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+ { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+ { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+ { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+ { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+ {} /* terminator */
+};
+
+#ifdef LIMITED_RATE_FMT_SUPPORT
+/* support only the safe format and rate */
+#define SUPPORTED_RATES SNDRV_PCM_RATE_48000
+#define SUPPORTED_MAXBPS 16
+#define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE
+#else
+/* support all rates and formats */
+#define SUPPORTED_RATES \
+ (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+#define SUPPORTED_MAXBPS 24
+#define SUPPORTED_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+#endif
+
+static int nvhdmi_7x_init(struct hda_codec *codec)
+{
+ snd_hda_sequence_write(codec, nvhdmi_basic_init_7x);
+ return 0;
+}
+
+static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int simple_playback_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+ stream_tag, format, substream);
+}
+
+static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int i;
+
+ snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
+ 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
+ for (i = 0; i < 4; i++) {
+ /* set the stream id */
+ snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
+ AC_VERB_SET_CHANNEL_STREAMID, 0);
+ /* set the stream format */
+ snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
+ AC_VERB_SET_STREAM_FORMAT, 0);
+ }
+
+ return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ int chs;
+ unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id;
+ int i;
+
+ mutex_lock(&codec->spdif_mutex);
+
+ chs = substream->runtime->channels;
+ chan = chs ? (chs - 1) : 1;
+
+ switch (chs) {
+ default:
+ case 0:
+ case 2:
+ chanmask = 0x00;
+ break;
+ case 4:
+ chanmask = 0x08;
+ break;
+ case 6:
+ chanmask = 0x0b;
+ break;
+ case 8:
+ chanmask = 0x13;
+ break;
+ }
+ dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT;
+ dataDCC2 = 0x2;
+
+ /* set the Audio InforFrame Channel Allocation */
+ snd_hda_codec_write(codec, 0x1, 0,
+ Nv_VERB_SET_Channel_Allocation, chanmask);
+
+ /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
+ if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
+ snd_hda_codec_write(codec,
+ nvhdmi_master_con_nid_7x,
+ 0,
+ AC_VERB_SET_DIGI_CONVERT_1,
+ codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+
+ /* set the stream id */
+ snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
+ AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
+
+ /* set the stream format */
+ snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
+ AC_VERB_SET_STREAM_FORMAT, format);
+
+ /* turn on again (if needed) */
+ /* enable and set the channel status audio/data flag */
+ if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
+ snd_hda_codec_write(codec,
+ nvhdmi_master_con_nid_7x,
+ 0,
+ AC_VERB_SET_DIGI_CONVERT_1,
+ codec->spdif_ctls & 0xff);
+ snd_hda_codec_write(codec,
+ nvhdmi_master_con_nid_7x,
+ 0,
+ AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (chs == 2)
+ channel_id = 0;
+ else
+ channel_id = i * 2;
+
+ /* turn off SPDIF once;
+ *otherwise the IEC958 bits won't be updated
+ */
+ if (codec->spdif_status_reset &&
+ (codec->spdif_ctls & AC_DIG1_ENABLE))
+ snd_hda_codec_write(codec,
+ nvhdmi_con_nids_7x[i],
+ 0,
+ AC_VERB_SET_DIGI_CONVERT_1,
+ codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+ /* set the stream id */
+ snd_hda_codec_write(codec,
+ nvhdmi_con_nids_7x[i],
+ 0,
+ AC_VERB_SET_CHANNEL_STREAMID,
+ (stream_tag << 4) | channel_id);
+ /* set the stream format */
+ snd_hda_codec_write(codec,
+ nvhdmi_con_nids_7x[i],
+ 0,
+ AC_VERB_SET_STREAM_FORMAT,
+ format);
+ /* turn on again (if needed) */
+ /* enable and set the channel status audio/data flag */
+ if (codec->spdif_status_reset &&
+ (codec->spdif_ctls & AC_DIG1_ENABLE)) {
+ snd_hda_codec_write(codec,
+ nvhdmi_con_nids_7x[i],
+ 0,
+ AC_VERB_SET_DIGI_CONVERT_1,
+ codec->spdif_ctls & 0xff);
+ snd_hda_codec_write(codec,
+ nvhdmi_con_nids_7x[i],
+ 0,
+ AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+ }
+ }
+
+ /* set the Audio Info Frame Checksum */
+ snd_hda_codec_write(codec, 0x1, 0,
+ Nv_VERB_SET_Info_Frame_Checksum,
+ (0x71 - chan - chanmask));
+
+ mutex_unlock(&codec->spdif_mutex);
+ return 0;
+}
+
+static struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 8,
+ .nid = nvhdmi_master_con_nid_7x,
+ .rates = SUPPORTED_RATES,
+ .maxbps = SUPPORTED_MAXBPS,
+ .formats = SUPPORTED_FORMATS,
+ .ops = {
+ .open = simple_playback_pcm_open,
+ .close = nvhdmi_8ch_7x_pcm_close,
+ .prepare = nvhdmi_8ch_7x_pcm_prepare
+ },
+};
+
+static struct hda_pcm_stream nvhdmi_pcm_playback_2ch = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = nvhdmi_master_con_nid_7x,
+ .rates = SUPPORTED_RATES,
+ .maxbps = SUPPORTED_MAXBPS,
+ .formats = SUPPORTED_FORMATS,
+ .ops = {
+ .open = simple_playback_pcm_open,
+ .close = simple_playback_pcm_close,
+ .prepare = simple_playback_pcm_prepare
+ },
+};
+
+static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
+ .build_controls = generic_hdmi_build_controls,
+ .build_pcms = generic_hdmi_build_pcms,
+ .init = nvhdmi_7x_init,
+ .free = generic_hdmi_free,
+};
+
+static struct hda_codec_ops nvhdmi_patch_ops_2ch = {
+ .build_controls = generic_hdmi_build_controls,
+ .build_pcms = generic_hdmi_build_pcms,
+ .init = nvhdmi_7x_init,
+ .free = generic_hdmi_free,
+};
+
+static int patch_nvhdmi_8ch_89(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec;
+ int err = patch_generic_hdmi(codec);
+
+ if (err < 0)
+ return err;
+ spec = codec->spec;
+ spec->old_pin_detect = 1;
+ return 0;
+}
+
+static int patch_nvhdmi_2ch(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ spec->multiout.num_dacs = 0; /* no analog */
+ spec->multiout.max_channels = 2;
+ spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
+ spec->old_pin_detect = 1;
+ spec->num_cvts = 1;
+ spec->cvt[0] = nvhdmi_master_con_nid_7x;
+ spec->pcm_playback = &nvhdmi_pcm_playback_2ch;
+
+ codec->patch_ops = nvhdmi_patch_ops_2ch;
+
+ return 0;
+}
+
+static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec;
+ int err = patch_nvhdmi_2ch(codec);
+
+ if (err < 0)
+ return err;
+ spec = codec->spec;
+ spec->multiout.max_channels = 8;
+ spec->pcm_playback = &nvhdmi_pcm_playback_8ch_7x;
+ codec->patch_ops = nvhdmi_patch_ops_8ch_7x;
+ return 0;
+}
+
+/*
+ * ATI-specific implementations
+ *
+ * FIXME: we may omit the whole this and use the generic code once after
+ * it's confirmed to work.
+ */
+
+#define ATIHDMI_CVT_NID 0x02 /* audio converter */
+#define ATIHDMI_PIN_NID 0x03 /* HDMI output pin */
+
+static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int chans = substream->runtime->channels;
+ int i, err;
+
+ err = simple_playback_pcm_prepare(hinfo, codec, stream_tag, format,
+ substream);
+ if (err < 0)
+ return err;
+ snd_hda_codec_write(codec, spec->cvt[0], 0, AC_VERB_SET_CVT_CHAN_COUNT,
+ chans - 1);
+ /* FIXME: XXX */
+ for (i = 0; i < chans; i++) {
+ snd_hda_codec_write(codec, spec->cvt[0], 0,
+ AC_VERB_SET_HDMI_CHAN_SLOT,
+ (i << 4) | i);
+ }
+ return 0;
+}
+
+static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = ATIHDMI_CVT_NID,
+ .ops = {
+ .open = simple_playback_pcm_open,
+ .close = simple_playback_pcm_close,
+ .prepare = atihdmi_playback_pcm_prepare
+ },
+};
+
+static struct hda_verb atihdmi_basic_init[] = {
+ /* enable digital output on pin widget */
+ { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ {} /* terminator */
+};
+
+static int atihdmi_init(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ snd_hda_sequence_write(codec, atihdmi_basic_init);
+ /* SI codec requires to unmute the pin */
+ if (get_wcaps(codec, spec->pin[0]) & AC_WCAP_OUT_AMP)
+ snd_hda_codec_write(codec, spec->pin[0], 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_UNMUTE);
+ return 0;
+}
+
+static struct hda_codec_ops atihdmi_patch_ops = {
+ .build_controls = generic_hdmi_build_controls,
+ .build_pcms = generic_hdmi_build_pcms,
+ .init = atihdmi_init,
+ .free = generic_hdmi_free,
+};
+
+
+static int patch_atihdmi(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ spec->multiout.num_dacs = 0; /* no analog */
+ spec->multiout.max_channels = 2;
+ spec->multiout.dig_out_nid = ATIHDMI_CVT_NID;
+ spec->num_cvts = 1;
+ spec->cvt[0] = ATIHDMI_CVT_NID;
+ spec->pin[0] = ATIHDMI_PIN_NID;
+ spec->pcm_playback = &atihdmi_pcm_digital_playback;
+
+ codec->patch_ops = atihdmi_patch_ops;
+
+ return 0;
+}
+
+
+/*
+ * patch entries
+ */
+static struct hda_codec_preset snd_hda_preset_hdmi[] = {
+{ .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi },
+{ .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi },
+{ .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi },
+{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi },
+{ .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x10de0002, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
+{ .id = 0x10de0003, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
+{ .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
+{ .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
+{ .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x },
+{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
+{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
+{ .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x80862801, .name = "Bearlake HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x80862802, .name = "Cantiga HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x80862803, .name = "Eaglelake HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi },
+{} /* terminator */
+};
+
+MODULE_ALIAS("snd-hda-codec-id:1002793c");
+MODULE_ALIAS("snd-hda-codec-id:10027919");
+MODULE_ALIAS("snd-hda-codec-id:1002791a");
+MODULE_ALIAS("snd-hda-codec-id:1002aa01");
+MODULE_ALIAS("snd-hda-codec-id:10951390");
+MODULE_ALIAS("snd-hda-codec-id:10951392");
+MODULE_ALIAS("snd-hda-codec-id:10de0002");
+MODULE_ALIAS("snd-hda-codec-id:10de0003");
+MODULE_ALIAS("snd-hda-codec-id:10de0005");
+MODULE_ALIAS("snd-hda-codec-id:10de0006");
+MODULE_ALIAS("snd-hda-codec-id:10de0007");
+MODULE_ALIAS("snd-hda-codec-id:10de000a");
+MODULE_ALIAS("snd-hda-codec-id:10de000b");
+MODULE_ALIAS("snd-hda-codec-id:10de000c");
+MODULE_ALIAS("snd-hda-codec-id:10de000d");
+MODULE_ALIAS("snd-hda-codec-id:10de0010");
+MODULE_ALIAS("snd-hda-codec-id:10de0011");
+MODULE_ALIAS("snd-hda-codec-id:10de0012");
+MODULE_ALIAS("snd-hda-codec-id:10de0013");
+MODULE_ALIAS("snd-hda-codec-id:10de0014");
+MODULE_ALIAS("snd-hda-codec-id:10de0018");
+MODULE_ALIAS("snd-hda-codec-id:10de0019");
+MODULE_ALIAS("snd-hda-codec-id:10de001a");
+MODULE_ALIAS("snd-hda-codec-id:10de001b");
+MODULE_ALIAS("snd-hda-codec-id:10de001c");
+MODULE_ALIAS("snd-hda-codec-id:10de0040");
+MODULE_ALIAS("snd-hda-codec-id:10de0041");
+MODULE_ALIAS("snd-hda-codec-id:10de0042");
+MODULE_ALIAS("snd-hda-codec-id:10de0043");
+MODULE_ALIAS("snd-hda-codec-id:10de0044");
+MODULE_ALIAS("snd-hda-codec-id:10de0067");
+MODULE_ALIAS("snd-hda-codec-id:10de8001");
+MODULE_ALIAS("snd-hda-codec-id:17e80047");
+MODULE_ALIAS("snd-hda-codec-id:80860054");
+MODULE_ALIAS("snd-hda-codec-id:80862801");
+MODULE_ALIAS("snd-hda-codec-id:80862802");
+MODULE_ALIAS("snd-hda-codec-id:80862803");
+MODULE_ALIAS("snd-hda-codec-id:80862804");
+MODULE_ALIAS("snd-hda-codec-id:80862805");
+MODULE_ALIAS("snd-hda-codec-id:808629fb");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("HDMI HD-audio codec");
+MODULE_ALIAS("snd-hda-codec-intelhdmi");
+MODULE_ALIAS("snd-hda-codec-nvhdmi");
+MODULE_ALIAS("snd-hda-codec-atihdmi");
+
+static struct hda_codec_preset_list intel_list = {
+ .preset = snd_hda_preset_hdmi,
+ .owner = THIS_MODULE,
+};
+
+static int __init patch_hdmi_init(void)
+{
+ return snd_hda_add_codec_preset(&intel_list);
+}
+
+static void __exit patch_hdmi_exit(void)
+{
+ snd_hda_delete_codec_preset(&intel_list);
+}
+
+module_init(patch_hdmi_init)
+module_exit(patch_hdmi_exit)
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c
deleted file mode 100644
index 36a9b83a6174..000000000000
--- a/sound/pci/hda/patch_intelhdmi.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- *
- * patch_intelhdmi.c - Patch for Intel HDMI codecs
- *
- * Copyright(c) 2008 Intel Corporation. All rights reserved.
- *
- * Authors:
- * Jiang Zhe <zhe.jiang@intel.com>
- * Wu Fengguang <wfg@linux.intel.com>
- *
- * Maintained by:
- * Wu Fengguang <wfg@linux.intel.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/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include "hda_codec.h"
-#include "hda_local.h"
-
-/*
- * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
- * could support two independent pipes, each of them can be connected to one or
- * more ports (DVI, HDMI or DisplayPort).
- *
- * The HDA correspondence of pipes/ports are converter/pin nodes.
- */
-#define MAX_HDMI_CVTS 3
-#define MAX_HDMI_PINS 3
-
-#include "patch_hdmi.c"
-
-static char *intel_hdmi_pcm_names[MAX_HDMI_CVTS] = {
- "INTEL HDMI 0",
- "INTEL HDMI 1",
- "INTEL HDMI 2",
-};
-
-/*
- * HDMI callbacks
- */
-
-static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- unsigned int stream_tag,
- unsigned int format,
- struct snd_pcm_substream *substream)
-{
- hdmi_set_channel_count(codec, hinfo->nid,
- substream->runtime->channels);
-
- hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
-
- return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
-}
-
-static struct hda_pcm_stream intel_hdmi_pcm_playback = {
- .substreams = 1,
- .channels_min = 2,
- .ops = {
- .open = hdmi_pcm_open,
- .prepare = intel_hdmi_playback_pcm_prepare,
- },
-};
-
-static int intel_hdmi_build_pcms(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hda_pcm *info = spec->pcm_rec;
- int i;
-
- codec->num_pcms = spec->num_cvts;
- codec->pcm_info = info;
-
- for (i = 0; i < codec->num_pcms; i++, info++) {
- unsigned int chans;
-
- chans = get_wcaps(codec, spec->cvt[i]);
- chans = get_wcaps_channels(chans);
-
- info->name = intel_hdmi_pcm_names[i];
- info->pcm_type = HDA_PCM_TYPE_HDMI;
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
- intel_hdmi_pcm_playback;
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i];
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
- }
-
- return 0;
-}
-
-static int intel_hdmi_build_controls(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int err;
- int i;
-
- for (i = 0; i < codec->num_pcms; i++) {
- err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
-static int intel_hdmi_init(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int i;
-
- for (i = 0; spec->pin[i]; i++) {
- hdmi_enable_output(codec, spec->pin[i]);
- snd_hda_codec_write(codec, spec->pin[i], 0,
- AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | spec->pin[i]);
- }
- return 0;
-}
-
-static void intel_hdmi_free(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i < spec->num_pins; i++)
- snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
-
- kfree(spec);
-}
-
-static struct hda_codec_ops intel_hdmi_patch_ops = {
- .init = intel_hdmi_init,
- .free = intel_hdmi_free,
- .build_pcms = intel_hdmi_build_pcms,
- .build_controls = intel_hdmi_build_controls,
- .unsol_event = hdmi_unsol_event,
-};
-
-static int patch_intel_hdmi(struct hda_codec *codec)
-{
- struct hdmi_spec *spec;
- int i;
-
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
- if (hdmi_parse_codec(codec) < 0) {
- codec->spec = NULL;
- kfree(spec);
- return -EINVAL;
- }
- codec->patch_ops = intel_hdmi_patch_ops;
-
- for (i = 0; i < spec->num_pins; i++)
- snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
-
- init_channel_allocations();
-
- return 0;
-}
-
-static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
-{ .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_intel_hdmi },
-{ .id = 0x80862801, .name = "Bearlake HDMI", .patch = patch_intel_hdmi },
-{ .id = 0x80862802, .name = "Cantiga HDMI", .patch = patch_intel_hdmi },
-{ .id = 0x80862803, .name = "Eaglelake HDMI", .patch = patch_intel_hdmi },
-{ .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_intel_hdmi },
-{ .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_intel_hdmi },
-{ .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_intel_hdmi },
-{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi },
-{} /* terminator */
-};
-
-MODULE_ALIAS("snd-hda-codec-id:808629fb");
-MODULE_ALIAS("snd-hda-codec-id:80862801");
-MODULE_ALIAS("snd-hda-codec-id:80862802");
-MODULE_ALIAS("snd-hda-codec-id:80862803");
-MODULE_ALIAS("snd-hda-codec-id:80862804");
-MODULE_ALIAS("snd-hda-codec-id:80862805");
-MODULE_ALIAS("snd-hda-codec-id:80860054");
-MODULE_ALIAS("snd-hda-codec-id:10951392");
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Intel HDMI HD-audio codec");
-
-static struct hda_codec_preset_list intel_list = {
- .preset = snd_hda_preset_intelhdmi,
- .owner = THIS_MODULE,
-};
-
-static int __init patch_intelhdmi_init(void)
-{
- return snd_hda_add_codec_preset(&intel_list);
-}
-
-static void __exit patch_intelhdmi_exit(void)
-{
- snd_hda_delete_codec_preset(&intel_list);
-}
-
-module_init(patch_intelhdmi_init)
-module_exit(patch_intelhdmi_exit)
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c
deleted file mode 100644
index baa108b9d6aa..000000000000
--- a/sound/pci/hda/patch_nvhdmi.c
+++ /dev/null
@@ -1,608 +0,0 @@
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * HD audio interface patch for NVIDIA HDMI codecs
- *
- * Copyright (c) 2008 NVIDIA Corp. All rights reserved.
- * Copyright (c) 2008 Wei Ni <wni@nvidia.com>
- *
- *
- * This driver is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This driver 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/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include "hda_codec.h"
-#include "hda_local.h"
-
-#define MAX_HDMI_CVTS 1
-#define MAX_HDMI_PINS 1
-
-#include "patch_hdmi.c"
-
-static char *nvhdmi_pcm_names[MAX_HDMI_CVTS] = {
- "NVIDIA HDMI",
-};
-
-/* define below to restrict the supported rates and formats */
-/* #define LIMITED_RATE_FMT_SUPPORT */
-
-enum HDACodec {
- HDA_CODEC_NVIDIA_MCP7X,
- HDA_CODEC_NVIDIA_MCP89,
- HDA_CODEC_NVIDIA_GT21X,
- HDA_CODEC_INVALID
-};
-
-#define Nv_VERB_SET_Channel_Allocation 0xF79
-#define Nv_VERB_SET_Info_Frame_Checksum 0xF7A
-#define Nv_VERB_SET_Audio_Protection_On 0xF98
-#define Nv_VERB_SET_Audio_Protection_Off 0xF99
-
-#define nvhdmi_master_con_nid_7x 0x04
-#define nvhdmi_master_pin_nid_7x 0x05
-
-#define nvhdmi_master_con_nid_89 0x04
-#define nvhdmi_master_pin_nid_89 0x05
-
-static hda_nid_t nvhdmi_con_nids_7x[4] = {
- /*front, rear, clfe, rear_surr */
- 0x6, 0x8, 0xa, 0xc,
-};
-
-static struct hda_verb nvhdmi_basic_init_7x[] = {
- /* set audio protect on */
- { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
- /* enable digital output on pin widget */
- { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
- { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
- { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
- { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
- { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
- {} /* terminator */
-};
-
-#ifdef LIMITED_RATE_FMT_SUPPORT
-/* support only the safe format and rate */
-#define SUPPORTED_RATES SNDRV_PCM_RATE_48000
-#define SUPPORTED_MAXBPS 16
-#define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE
-#else
-/* support all rates and formats */
-#define SUPPORTED_RATES \
- (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
- SNDRV_PCM_RATE_192000)
-#define SUPPORTED_MAXBPS 24
-#define SUPPORTED_FORMATS \
- (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
-#endif
-
-/*
- * Controls
- */
-static int nvhdmi_build_controls(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int err;
- int i;
-
- if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
- || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
- for (i = 0; i < codec->num_pcms; i++) {
- err = snd_hda_create_spdif_out_ctls(codec,
- spec->cvt[i]);
- if (err < 0)
- return err;
- }
- } else {
- err = snd_hda_create_spdif_out_ctls(codec,
- spec->multiout.dig_out_nid);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
-static int nvhdmi_init(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int i;
- if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
- || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
- for (i = 0; spec->pin[i]; i++) {
- hdmi_enable_output(codec, spec->pin[i]);
- snd_hda_codec_write(codec, spec->pin[i], 0,
- AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | spec->pin[i]);
- }
- } else {
- snd_hda_sequence_write(codec, nvhdmi_basic_init_7x);
- }
- return 0;
-}
-
-static void nvhdmi_free(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int i;
-
- if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
- || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
- for (i = 0; i < spec->num_pins; i++)
- snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
- }
-
- kfree(spec);
-}
-
-/*
- * Digital out
- */
-static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct hdmi_spec *spec = codec->spec;
- return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int nvhdmi_dig_playback_pcm_close_8ch_7x(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct hdmi_spec *spec = codec->spec;
- int i;
-
- snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
- 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
- for (i = 0; i < 4; i++) {
- /* set the stream id */
- snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
- AC_VERB_SET_CHANNEL_STREAMID, 0);
- /* set the stream format */
- snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
- AC_VERB_SET_STREAM_FORMAT, 0);
- }
-
- return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct hdmi_spec *spec = codec->spec;
- return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int nvhdmi_dig_playback_pcm_prepare_8ch_89(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- unsigned int stream_tag,
- unsigned int format,
- struct snd_pcm_substream *substream)
-{
- hdmi_set_channel_count(codec, hinfo->nid,
- substream->runtime->channels);
-
- hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
-
- return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
-}
-
-static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- unsigned int stream_tag,
- unsigned int format,
- struct snd_pcm_substream *substream)
-{
- int chs;
- unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id;
- int i;
-
- mutex_lock(&codec->spdif_mutex);
-
- chs = substream->runtime->channels;
- chan = chs ? (chs - 1) : 1;
-
- switch (chs) {
- default:
- case 0:
- case 2:
- chanmask = 0x00;
- break;
- case 4:
- chanmask = 0x08;
- break;
- case 6:
- chanmask = 0x0b;
- break;
- case 8:
- chanmask = 0x13;
- break;
- }
- dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT;
- dataDCC2 = 0x2;
-
- /* set the Audio InforFrame Channel Allocation */
- snd_hda_codec_write(codec, 0x1, 0,
- Nv_VERB_SET_Channel_Allocation, chanmask);
-
- /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
- if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
- snd_hda_codec_write(codec,
- nvhdmi_master_con_nid_7x,
- 0,
- AC_VERB_SET_DIGI_CONVERT_1,
- codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
-
- /* set the stream id */
- snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
- AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
-
- /* set the stream format */
- snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
- AC_VERB_SET_STREAM_FORMAT, format);
-
- /* turn on again (if needed) */
- /* enable and set the channel status audio/data flag */
- if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
- snd_hda_codec_write(codec,
- nvhdmi_master_con_nid_7x,
- 0,
- AC_VERB_SET_DIGI_CONVERT_1,
- codec->spdif_ctls & 0xff);
- snd_hda_codec_write(codec,
- nvhdmi_master_con_nid_7x,
- 0,
- AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
- }
-
- for (i = 0; i < 4; i++) {
- if (chs == 2)
- channel_id = 0;
- else
- channel_id = i * 2;
-
- /* turn off SPDIF once;
- *otherwise the IEC958 bits won't be updated
- */
- if (codec->spdif_status_reset &&
- (codec->spdif_ctls & AC_DIG1_ENABLE))
- snd_hda_codec_write(codec,
- nvhdmi_con_nids_7x[i],
- 0,
- AC_VERB_SET_DIGI_CONVERT_1,
- codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
- /* set the stream id */
- snd_hda_codec_write(codec,
- nvhdmi_con_nids_7x[i],
- 0,
- AC_VERB_SET_CHANNEL_STREAMID,
- (stream_tag << 4) | channel_id);
- /* set the stream format */
- snd_hda_codec_write(codec,
- nvhdmi_con_nids_7x[i],
- 0,
- AC_VERB_SET_STREAM_FORMAT,
- format);
- /* turn on again (if needed) */
- /* enable and set the channel status audio/data flag */
- if (codec->spdif_status_reset &&
- (codec->spdif_ctls & AC_DIG1_ENABLE)) {
- snd_hda_codec_write(codec,
- nvhdmi_con_nids_7x[i],
- 0,
- AC_VERB_SET_DIGI_CONVERT_1,
- codec->spdif_ctls & 0xff);
- snd_hda_codec_write(codec,
- nvhdmi_con_nids_7x[i],
- 0,
- AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
- }
- }
-
- /* set the Audio Info Frame Checksum */
- snd_hda_codec_write(codec, 0x1, 0,
- Nv_VERB_SET_Info_Frame_Checksum,
- (0x71 - chan - chanmask));
-
- mutex_unlock(&codec->spdif_mutex);
- return 0;
-}
-
-static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- unsigned int stream_tag,
- unsigned int format,
- struct snd_pcm_substream *substream)
-{
- struct hdmi_spec *spec = codec->spec;
- return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
- format, substream);
-}
-
-static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = {
- .substreams = 1,
- .channels_min = 2,
- .ops = {
- .open = hdmi_pcm_open,
- .prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89,
- },
-};
-
-static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_7x = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 8,
- .nid = nvhdmi_master_con_nid_7x,
- .rates = SUPPORTED_RATES,
- .maxbps = SUPPORTED_MAXBPS,
- .formats = SUPPORTED_FORMATS,
- .ops = {
- .open = nvhdmi_dig_playback_pcm_open,
- .close = nvhdmi_dig_playback_pcm_close_8ch_7x,
- .prepare = nvhdmi_dig_playback_pcm_prepare_8ch
- },
-};
-
-static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
- .nid = nvhdmi_master_con_nid_7x,
- .rates = SUPPORTED_RATES,
- .maxbps = SUPPORTED_MAXBPS,
- .formats = SUPPORTED_FORMATS,
- .ops = {
- .open = nvhdmi_dig_playback_pcm_open,
- .close = nvhdmi_dig_playback_pcm_close_2ch,
- .prepare = nvhdmi_dig_playback_pcm_prepare_2ch
- },
-};
-
-static int nvhdmi_build_pcms_8ch_89(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hda_pcm *info = spec->pcm_rec;
- int i;
-
- codec->num_pcms = spec->num_cvts;
- codec->pcm_info = info;
-
- for (i = 0; i < codec->num_pcms; i++, info++) {
- unsigned int chans;
-
- chans = get_wcaps(codec, spec->cvt[i]);
- chans = get_wcaps_channels(chans);
-
- info->name = nvhdmi_pcm_names[i];
- info->pcm_type = HDA_PCM_TYPE_HDMI;
- info->stream[SNDRV_PCM_STREAM_PLAYBACK]
- = nvhdmi_pcm_digital_playback_8ch_89;
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i];
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
- }
-
- return 0;
-}
-
-static int nvhdmi_build_pcms_8ch_7x(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hda_pcm *info = spec->pcm_rec;
-
- codec->num_pcms = 1;
- codec->pcm_info = info;
-
- info->name = "NVIDIA HDMI";
- info->pcm_type = HDA_PCM_TYPE_HDMI;
- info->stream[SNDRV_PCM_STREAM_PLAYBACK]
- = nvhdmi_pcm_digital_playback_8ch_7x;
-
- return 0;
-}
-
-static int nvhdmi_build_pcms_2ch(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hda_pcm *info = spec->pcm_rec;
-
- codec->num_pcms = 1;
- codec->pcm_info = info;
-
- info->name = "NVIDIA HDMI";
- info->pcm_type = HDA_PCM_TYPE_HDMI;
- info->stream[SNDRV_PCM_STREAM_PLAYBACK]
- = nvhdmi_pcm_digital_playback_2ch;
-
- return 0;
-}
-
-static struct hda_codec_ops nvhdmi_patch_ops_8ch_89 = {
- .build_controls = nvhdmi_build_controls,
- .build_pcms = nvhdmi_build_pcms_8ch_89,
- .init = nvhdmi_init,
- .free = nvhdmi_free,
- .unsol_event = hdmi_unsol_event,
-};
-
-static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
- .build_controls = nvhdmi_build_controls,
- .build_pcms = nvhdmi_build_pcms_8ch_7x,
- .init = nvhdmi_init,
- .free = nvhdmi_free,
-};
-
-static struct hda_codec_ops nvhdmi_patch_ops_2ch = {
- .build_controls = nvhdmi_build_controls,
- .build_pcms = nvhdmi_build_pcms_2ch,
- .init = nvhdmi_init,
- .free = nvhdmi_free,
-};
-
-static int patch_nvhdmi_8ch_89(struct hda_codec *codec)
-{
- struct hdmi_spec *spec;
- int i;
-
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
- spec->codec_type = HDA_CODEC_NVIDIA_MCP89;
- spec->old_pin_detect = 1;
-
- if (hdmi_parse_codec(codec) < 0) {
- codec->spec = NULL;
- kfree(spec);
- return -EINVAL;
- }
- codec->patch_ops = nvhdmi_patch_ops_8ch_89;
-
- for (i = 0; i < spec->num_pins; i++)
- snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
-
- init_channel_allocations();
-
- return 0;
-}
-
-static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
-{
- struct hdmi_spec *spec;
-
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
-
- spec->multiout.num_dacs = 0; /* no analog */
- spec->multiout.max_channels = 8;
- spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
- spec->codec_type = HDA_CODEC_NVIDIA_MCP7X;
- spec->old_pin_detect = 1;
-
- codec->patch_ops = nvhdmi_patch_ops_8ch_7x;
-
- return 0;
-}
-
-static int patch_nvhdmi_2ch(struct hda_codec *codec)
-{
- struct hdmi_spec *spec;
-
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
-
- spec->multiout.num_dacs = 0; /* no analog */
- spec->multiout.max_channels = 2;
- spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
- spec->codec_type = HDA_CODEC_NVIDIA_MCP7X;
- spec->old_pin_detect = 1;
-
- codec->patch_ops = nvhdmi_patch_ops_2ch;
-
- return 0;
-}
-
-/*
- * patch entries
- */
-static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
- { .id = 0x10de0002, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
- { .id = 0x10de0003, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
- { .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
- { .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
- { .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x },
- { .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
- { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
- { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
- {} /* terminator */
-};
-
-MODULE_ALIAS("snd-hda-codec-id:10de0002");
-MODULE_ALIAS("snd-hda-codec-id:10de0003");
-MODULE_ALIAS("snd-hda-codec-id:10de0005");
-MODULE_ALIAS("snd-hda-codec-id:10de0006");
-MODULE_ALIAS("snd-hda-codec-id:10de0007");
-MODULE_ALIAS("snd-hda-codec-id:10de000a");
-MODULE_ALIAS("snd-hda-codec-id:10de000b");
-MODULE_ALIAS("snd-hda-codec-id:10de000c");
-MODULE_ALIAS("snd-hda-codec-id:10de000d");
-MODULE_ALIAS("snd-hda-codec-id:10de0010");
-MODULE_ALIAS("snd-hda-codec-id:10de0011");
-MODULE_ALIAS("snd-hda-codec-id:10de0012");
-MODULE_ALIAS("snd-hda-codec-id:10de0013");
-MODULE_ALIAS("snd-hda-codec-id:10de0014");
-MODULE_ALIAS("snd-hda-codec-id:10de0018");
-MODULE_ALIAS("snd-hda-codec-id:10de0019");
-MODULE_ALIAS("snd-hda-codec-id:10de001a");
-MODULE_ALIAS("snd-hda-codec-id:10de001b");
-MODULE_ALIAS("snd-hda-codec-id:10de001c");
-MODULE_ALIAS("snd-hda-codec-id:10de0040");
-MODULE_ALIAS("snd-hda-codec-id:10de0041");
-MODULE_ALIAS("snd-hda-codec-id:10de0042");
-MODULE_ALIAS("snd-hda-codec-id:10de0043");
-MODULE_ALIAS("snd-hda-codec-id:10de0044");
-MODULE_ALIAS("snd-hda-codec-id:10de0067");
-MODULE_ALIAS("snd-hda-codec-id:10de8001");
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("NVIDIA HDMI HD-audio codec");
-
-static struct hda_codec_preset_list nvhdmi_list = {
- .preset = snd_hda_preset_nvhdmi,
- .owner = THIS_MODULE,
-};
-
-static int __init patch_nvhdmi_init(void)
-{
- return snd_hda_add_codec_preset(&nvhdmi_list);
-}
-
-static void __exit patch_nvhdmi_exit(void)
-{
- snd_hda_delete_codec_preset(&nvhdmi_list);
-}
-
-module_init(patch_nvhdmi_init)
-module_exit(patch_nvhdmi_exit)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index a432e6efd19b..5f00589cb791 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <sound/core.h>
+#include <sound/jack.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_beep.h"
@@ -282,6 +283,12 @@ struct alc_mic_route {
unsigned char amix_idx;
};
+struct alc_jack {
+ hda_nid_t nid;
+ int type;
+ struct snd_jack *jack;
+};
+
#define MUX_IDX_UNDEF ((unsigned char)-1)
struct alc_customize_define {
@@ -294,6 +301,7 @@ struct alc_customize_define {
unsigned int platform_type:1;
unsigned int swap:1;
unsigned int override:1;
+ unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
};
struct alc_spec {
@@ -357,6 +365,9 @@ struct alc_spec {
/* PCM information */
struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
+ /* jack detection */
+ struct snd_array jacks;
+
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
struct alc_customize_define cdefine;
@@ -383,6 +394,7 @@ struct alc_spec {
unsigned int no_analog :1; /* digital I/O only */
unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
int init_amp;
+ int codec_variant; /* flag for other variants */
/* for virtual master */
hda_nid_t vmaster_nid;
@@ -846,7 +858,7 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
{
unsigned int val = PIN_IN;
- if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
+ if (auto_pin_type == AUTO_PIN_MIC) {
unsigned int pincap;
unsigned int oldval;
oldval = snd_hda_codec_read(codec, nid, 0,
@@ -866,6 +878,28 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
}
+static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+
+ if (!cfg->line_outs) {
+ while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
+ cfg->line_out_pins[cfg->line_outs])
+ cfg->line_outs++;
+ }
+ if (!cfg->speaker_outs) {
+ while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
+ cfg->speaker_pins[cfg->speaker_outs])
+ cfg->speaker_outs++;
+ }
+ if (!cfg->hp_outs) {
+ while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
+ cfg->hp_pins[cfg->hp_outs])
+ cfg->hp_outs++;
+ }
+}
+
/*
*/
static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
@@ -934,6 +968,8 @@ static void setup_preset(struct hda_codec *codec,
if (preset->setup)
preset->setup(codec);
+
+ alc_fixup_autocfg_pin_nums(codec);
}
/* Enable GPIO mask and set output */
@@ -990,25 +1026,136 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
alc_fix_pll(codec);
}
-static void alc_automute_pin(struct hda_codec *codec)
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+static void alc_free_jack_priv(struct snd_jack *jack)
+{
+ struct alc_jack *jacks = jack->private_data;
+ jacks->nid = 0;
+ jacks->jack = NULL;
+}
+
+static int alc_add_jack(struct hda_codec *codec,
+ hda_nid_t nid, int type)
+{
+ struct alc_spec *spec;
+ struct alc_jack *jack;
+ const char *name;
+ int err;
+
+ spec = codec->spec;
+ snd_array_init(&spec->jacks, sizeof(*jack), 32);
+ jack = snd_array_new(&spec->jacks);
+ if (!jack)
+ return -ENOMEM;
+
+ jack->nid = nid;
+ jack->type = type;
+ name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
+
+ err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
+ if (err < 0)
+ return err;
+ jack->jack->private_data = jack;
+ jack->jack->private_free = alc_free_jack_priv;
+ return 0;
+}
+
+static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
{
struct alc_spec *spec = codec->spec;
- unsigned int nid = spec->autocfg.hp_pins[0];
+ struct alc_jack *jacks = spec->jacks.list;
+
+ if (jacks) {
+ int i;
+ for (i = 0; i < spec->jacks.used; i++) {
+ if (jacks->nid == nid) {
+ unsigned int present;
+ present = snd_hda_jack_detect(codec, nid);
+
+ present = (present) ? jacks->type : 0;
+
+ snd_jack_report(jacks->jack, present);
+ }
+ jacks++;
+ }
+ }
+}
+
+static int alc_init_jacks(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int err;
+ unsigned int hp_nid = spec->autocfg.hp_pins[0];
+ unsigned int mic_nid = spec->ext_mic.pin;
+
+ if (hp_nid) {
+ err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE);
+ if (err < 0)
+ return err;
+ alc_report_jack(codec, hp_nid);
+ }
+
+ if (mic_nid) {
+ err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE);
+ if (err < 0)
+ return err;
+ alc_report_jack(codec, mic_nid);
+ }
+
+ return 0;
+}
+#else
+static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
+{
+}
+
+static inline int alc_init_jacks(struct hda_codec *codec)
+{
+ return 0;
+}
+#endif
+
+static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
+{
+ struct alc_spec *spec = codec->spec;
+ unsigned int mute;
+ hda_nid_t nid;
int i;
- if (!nid)
- return;
- spec->jack_present = snd_hda_jack_detect(codec, nid);
+ spec->jack_present = 0;
+ for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
+ nid = spec->autocfg.hp_pins[i];
+ if (!nid)
+ break;
+ if (snd_hda_jack_detect(codec, nid)) {
+ spec->jack_present = 1;
+ break;
+ }
+ alc_report_jack(codec, spec->autocfg.hp_pins[i]);
+ }
+
+ mute = spec->jack_present ? HDA_AMP_MUTE : 0;
+ /* Toggle internal speakers muting */
for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
nid = spec->autocfg.speaker_pins[i];
if (!nid)
break;
- snd_hda_codec_write(codec, nid, 0,
+ if (pinctl) {
+ snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
spec->jack_present ? 0 : PIN_OUT);
+ } else {
+ snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, mute);
+ }
}
}
+static void alc_automute_pin(struct hda_codec *codec)
+{
+ alc_automute_speaker(codec, 1);
+}
+
static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
hda_nid_t nid)
{
@@ -1090,6 +1237,7 @@ static void alc_mic_automute(struct hda_codec *codec)
AC_VERB_SET_CONNECT_SEL,
alive->mux_idx);
}
+ alc_report_jack(codec, spec->ext_mic.pin);
/* FIXME: analog mixer */
}
@@ -1236,24 +1384,35 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
static void alc_init_auto_hp(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i;
- if (!spec->autocfg.hp_pins[0])
- return;
+ if (!cfg->hp_pins[0]) {
+ if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+ return;
+ }
- if (!spec->autocfg.speaker_pins[0]) {
- if (spec->autocfg.line_out_pins[0] &&
- spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
- spec->autocfg.speaker_pins[0] =
- spec->autocfg.line_out_pins[0];
- else
+ if (!cfg->speaker_pins[0]) {
+ if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
return;
+ memcpy(cfg->speaker_pins, cfg->line_out_pins,
+ sizeof(cfg->speaker_pins));
+ cfg->speaker_outs = cfg->line_outs;
}
- snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
- spec->autocfg.hp_pins[0]);
- snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0,
+ if (!cfg->hp_pins[0]) {
+ memcpy(cfg->hp_pins, cfg->line_out_pins,
+ sizeof(cfg->hp_pins));
+ cfg->hp_outs = cfg->line_outs;
+ }
+
+ for (i = 0; i < cfg->hp_outs; i++) {
+ snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
+ cfg->hp_pins[i]);
+ snd_hda_codec_write_cache(codec, cfg->hp_pins[i], 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | ALC880_HP_EVENT);
+ }
spec->unsol_event = alc_sku_unsol_event;
}
@@ -1265,30 +1424,28 @@ static void alc_init_auto_mic(struct hda_codec *codec)
int i;
/* there must be only two mic inputs exclusively */
- for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++)
- if (cfg->input_pins[i])
+ for (i = 0; i < cfg->num_inputs; i++)
+ if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
return;
fixed = ext = 0;
- for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) {
- hda_nid_t nid = cfg->input_pins[i];
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
unsigned int defcfg;
- if (!nid)
- return;
defcfg = snd_hda_codec_get_pincfg(codec, nid);
- switch (get_defcfg_connect(defcfg)) {
- case AC_JACK_PORT_FIXED:
+ switch (snd_hda_get_input_pin_attr(defcfg)) {
+ case INPUT_PIN_ATTR_INT:
if (fixed)
return; /* already occupied */
fixed = nid;
break;
- case AC_JACK_PORT_COMPLEX:
+ case INPUT_PIN_ATTR_UNUSED:
+ return; /* invalid entry */
+ default:
if (ext)
return; /* already occupied */
ext = nid;
break;
- default:
- return; /* invalid entry */
}
}
if (!ext || !fixed)
@@ -1308,6 +1465,11 @@ static void alc_init_auto_mic(struct hda_codec *codec)
spec->unsol_event = alc_sku_unsol_event;
}
+/* Could be any non-zero and even value. When used as fixup, tells
+ * the driver to ignore any present sku defines.
+ */
+#define ALC_FIXUP_SKU_IGNORE (2)
+
static int alc_auto_parse_customize_define(struct hda_codec *codec)
{
unsigned int ass, tmp, i;
@@ -1316,6 +1478,13 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec)
spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
+ if (spec->cdefine.fixup) {
+ ass = spec->cdefine.sku_cfg;
+ if (ass == ALC_FIXUP_SKU_IGNORE)
+ return -1;
+ goto do_sku;
+ }
+
ass = codec->subsystem_id & 0xffff;
if (ass != codec->bus->pci->subsystem_device && (ass & 1))
goto do_sku;
@@ -1383,6 +1552,13 @@ static int alc_subsystem_id(struct hda_codec *codec,
unsigned nid;
struct alc_spec *spec = codec->spec;
+ if (spec->cdefine.fixup) {
+ ass = spec->cdefine.sku_cfg;
+ if (ass == ALC_FIXUP_SKU_IGNORE)
+ return 0;
+ goto do_sku;
+ }
+
ass = codec->subsystem_id & 0xffff;
if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
goto do_sku;
@@ -1502,6 +1678,7 @@ struct alc_pincfg {
};
struct alc_fixup {
+ unsigned int sku;
const struct alc_pincfg *pins;
const struct hda_verb *verbs;
};
@@ -1512,12 +1689,22 @@ static void alc_pick_fixup(struct hda_codec *codec,
int pre_init)
{
const struct alc_pincfg *cfg;
+ struct alc_spec *spec;
quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
if (!quirk)
return;
fix += quirk->value;
cfg = fix->pins;
+ if (pre_init && fix->sku) {
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ snd_printdd(KERN_INFO "hda_codec: %s: Apply sku override for %s\n",
+ codec->chip_name, quirk->name);
+#endif
+ spec = codec->spec;
+ spec->cdefine.sku_cfg = fix->sku;
+ spec->cdefine.fixup = 1;
+ }
if (pre_init && cfg) {
#ifdef CONFIG_SND_DEBUG_VERBOSE
snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n",
@@ -1546,6 +1733,15 @@ static int alc_read_coef_idx(struct hda_codec *codec,
return val;
}
+static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
+ unsigned int coef_val)
+{
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
+ coef_idx);
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
+ coef_val);
+}
+
/* set right pin controls for digital I/O */
static void alc_auto_init_digital(struct hda_codec *codec)
{
@@ -1723,31 +1919,7 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
static void alc_automute_amp(struct hda_codec *codec)
{
- struct alc_spec *spec = codec->spec;
- unsigned int mute;
- hda_nid_t nid;
- int i;
-
- spec->jack_present = 0;
- for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
- nid = spec->autocfg.hp_pins[i];
- if (!nid)
- break;
- if (snd_hda_jack_detect(codec, nid)) {
- spec->jack_present = 1;
- break;
- }
- }
-
- mute = spec->jack_present ? HDA_AMP_MUTE : 0;
- /* Toggle internal speakers muting */
- for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
- nid = spec->autocfg.speaker_pins[i];
- if (!nid)
- break;
- snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
- HDA_AMP_MUTE, mute);
- }
+ alc_automute_speaker(codec, 0);
}
static void alc_automute_amp_unsol_event(struct hda_codec *codec,
@@ -3602,10 +3774,7 @@ static int alc_init(struct hda_codec *codec)
if (spec->init_hook)
spec->init_hook(codec);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- if (codec->patch_ops.check_power_status)
- codec->patch_ops.check_power_status(codec, 0x01);
-#endif
+ hda_call_check_power_status(codec, 0x01);
return 0;
}
@@ -4001,10 +4170,7 @@ static int alc_resume(struct hda_codec *codec)
codec->patch_ops.init(codec);
snd_hda_codec_resume_amp(codec);
snd_hda_codec_resume_cache(codec);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- if (codec->patch_ops.check_power_status)
- codec->patch_ops.check_power_status(codec, 0x01);
-#endif
+ hda_call_check_power_status(codec, 0x01);
return 0;
}
#endif
@@ -4729,7 +4895,7 @@ static struct snd_kcontrol_new alc880_control_templates[] = {
/* add dynamic controls */
static int add_control(struct alc_spec *spec, int type, const char *name,
- unsigned long val)
+ int cidx, unsigned long val)
{
struct snd_kcontrol_new *knew;
@@ -4741,6 +4907,7 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
knew->name = kstrdup(name, GFP_KERNEL);
if (!knew->name)
return -ENOMEM;
+ knew->index = cidx;
if (get_amp_nid_(val))
knew->subdevice = HDA_SUBDEV_AMP_FLAG;
knew->private_value = val;
@@ -4749,17 +4916,21 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
static int add_control_with_pfx(struct alc_spec *spec, int type,
const char *pfx, const char *dir,
- const char *sfx, unsigned long val)
+ const char *sfx, int cidx, unsigned long val)
{
char name[32];
snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
- return add_control(spec, type, name, val);
+ return add_control(spec, type, name, cidx, val);
}
-#define add_pb_vol_ctrl(spec, type, pfx, val) \
- add_control_with_pfx(spec, type, pfx, "Playback", "Volume", val)
-#define add_pb_sw_ctrl(spec, type, pfx, val) \
- add_control_with_pfx(spec, type, pfx, "Playback", "Switch", val)
+#define add_pb_vol_ctrl(spec, type, pfx, val) \
+ add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
+#define add_pb_sw_ctrl(spec, type, pfx, val) \
+ add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
+#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \
+ add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
+#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
+ add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
@@ -4912,16 +5083,16 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
/* create input playback/capture controls for the given pin */
static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
- const char *ctlname,
+ const char *ctlname, int ctlidx,
int idx, hda_nid_t mix_nid)
{
int err;
- err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
+ err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
if (err < 0)
return err;
- err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
+ err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
if (err < 0)
return err;
@@ -4942,20 +5113,27 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec,
{
struct alc_spec *spec = codec->spec;
struct hda_input_mux *imux = &spec->private_imux[0];
- int i, err, idx;
+ int i, err, idx, type, type_idx = 0;
- for (i = 0; i < AUTO_PIN_LAST; i++) {
+ for (i = 0; i < cfg->num_inputs; i++) {
hda_nid_t pin;
+ const char *label;
- pin = cfg->input_pins[i];
+ pin = cfg->inputs[i].pin;
if (!alc_is_input_pin(codec, pin))
continue;
+ type = cfg->inputs[i].type;
+ if (i > 0 && type == cfg->inputs[i - 1].type)
+ type_idx++;
+ else
+ type_idx = 0;
+ label = hda_get_autocfg_input_label(codec, cfg, i);
if (mixer) {
idx = get_connection_index(codec, mixer, pin);
if (idx >= 0) {
err = new_analog_input(spec, pin,
- auto_pin_cfg_labels[i],
+ label, type_idx,
idx, mixer);
if (err < 0)
return err;
@@ -4967,12 +5145,8 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec,
idx = get_connection_index(codec, cap1, pin);
if (idx < 0 && cap2)
idx = get_connection_index(codec, cap2, pin);
- if (idx >= 0) {
- imux->items[imux->num_items].label =
- auto_pin_cfg_labels[i];
- imux->items[imux->num_items].index = idx;
- imux->num_items++;
- }
+ if (idx >= 0)
+ snd_hda_add_imux_item(imux, label, idx, NULL);
}
return 0;
}
@@ -5044,12 +5218,13 @@ static void alc880_auto_init_extra_out(struct hda_codec *codec)
static void alc880_auto_init_analog_input(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
int i;
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- hda_nid_t nid = spec->autocfg.input_pins[i];
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
if (alc_is_input_pin(codec, nid)) {
- alc_set_input_pin(codec, nid, i);
+ alc_set_input_pin(codec, nid, cfg->inputs[i].type);
if (nid != ALC880_PIN_CD_NID &&
(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
snd_hda_codec_write(codec, nid, 0,
@@ -5214,19 +5389,13 @@ static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
static void fixup_single_adc(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- hda_nid_t pin = 0;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
int i;
/* search for the input pin; there must be only one */
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- if (spec->autocfg.input_pins[i]) {
- pin = spec->autocfg.input_pins[i];
- break;
- }
- }
- if (!pin)
+ if (cfg->num_inputs != 1)
return;
- i = init_capsrc_for_pin(codec, pin);
+ i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
if (i >= 0) {
/* use only this ADC */
if (spec->capsrc_nids)
@@ -5279,6 +5448,7 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
int num_nids)
{
struct alc_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
int n;
hda_nid_t fallback_adc = 0, fallback_cap = 0;
@@ -5304,10 +5474,8 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
fallback_adc = adc;
fallback_cap = cap;
}
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- hda_nid_t nid = spec->autocfg.input_pins[i];
- if (!nid)
- continue;
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
for (j = 0; j < nconns; j++) {
if (conn[j] == nid)
break;
@@ -5315,7 +5483,7 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
if (j >= nconns)
break;
}
- if (i >= AUTO_PIN_LAST) {
+ if (i >= cfg->num_inputs) {
int num_adcs = spec->num_adc_nids;
spec->private_adc_nids[num_adcs] = adc;
spec->private_capsrc_nids[num_adcs] = cap;
@@ -6683,12 +6851,13 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec)
static void alc260_auto_init_analog_input(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
int i;
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- hda_nid_t nid = spec->autocfg.input_pins[i];
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
if (nid >= 0x12) {
- alc_set_input_pin(codec, nid, i);
+ alc_set_input_pin(codec, nid, cfg->inputs[i].type);
if (nid != ALC260_PIN_CD_NID &&
(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
snd_hda_codec_write(codec, nid, 0,
@@ -6810,14 +6979,12 @@ enum {
PINFIX_HP_DC5750,
};
-static struct alc_pincfg alc260_hp_dc5750_pinfix[] = {
- { 0x11, 0x90130110 }, /* speaker */
- { }
-};
-
static const struct alc_fixup alc260_fixups[] = {
[PINFIX_HP_DC5750] = {
- .pins = alc260_hp_dc5750_pinfix
+ .pins = (const struct alc_pincfg[]) {
+ { 0x11, 0x90130110 }, /* speaker */
+ { }
+ }
},
};
@@ -10461,32 +10628,33 @@ static struct alc_config_preset alc882_presets[] = {
enum {
PINFIX_ABIT_AW9D_MAX,
PINFIX_PB_M5210,
-};
-
-static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
- { 0x15, 0x01080104 }, /* side */
- { 0x16, 0x01011012 }, /* rear */
- { 0x17, 0x01016011 }, /* clfe */
- { }
-};
-
-static const struct hda_verb pb_m5210_verbs[] = {
- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
- {}
+ PINFIX_ACER_ASPIRE_7736,
};
static const struct alc_fixup alc882_fixups[] = {
[PINFIX_ABIT_AW9D_MAX] = {
- .pins = alc882_abit_aw9d_pinfix
+ .pins = (const struct alc_pincfg[]) {
+ { 0x15, 0x01080104 }, /* side */
+ { 0x16, 0x01011012 }, /* rear */
+ { 0x17, 0x01016011 }, /* clfe */
+ { }
+ }
},
[PINFIX_PB_M5210] = {
- .verbs = pb_m5210_verbs
+ .verbs = (const struct hda_verb[]) {
+ { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
+ {}
+ }
+ },
+ [PINFIX_ACER_ASPIRE_7736] = {
+ .sku = ALC_FIXUP_SKU_IGNORE,
},
};
static struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
+ SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
{}
};
@@ -10535,16 +10703,21 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
hda_nid_t pin, dac;
+ int i;
- pin = spec->autocfg.hp_pins[0];
- if (pin) {
+ for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
+ pin = spec->autocfg.hp_pins[i];
+ if (!pin)
+ break;
dac = spec->multiout.hp_nid;
if (!dac)
dac = spec->multiout.dac_nids[0]; /* to front */
alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
}
- pin = spec->autocfg.speaker_pins[0];
- if (pin) {
+ for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
+ pin = spec->autocfg.speaker_pins[i];
+ if (!pin)
+ break;
dac = spec->multiout.extra_out_nid[0];
if (!dac)
dac = spec->multiout.dac_nids[0]; /* to front */
@@ -10555,13 +10728,12 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec)
static void alc882_auto_init_analog_input(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
int i;
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- hda_nid_t nid = spec->autocfg.input_pins[i];
- if (!nid)
- continue;
- alc_set_input_pin(codec, nid, i);
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
+ alc_set_input_pin(codec, nid, cfg->inputs[i].type);
if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
@@ -10623,24 +10795,23 @@ static void alc882_auto_init_input_src(struct hda_codec *codec)
static int alc_auto_add_mic_boost(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- int err;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i, err;
hda_nid_t nid;
- nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
- if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
- err = add_control(spec, ALC_CTL_WIDGET_VOL,
- "Mic Boost",
- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
- if (err < 0)
- return err;
- }
- nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
- if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
- err = add_control(spec, ALC_CTL_WIDGET_VOL,
- "Front Mic Boost",
+ for (i = 0; i < cfg->num_inputs; i++) {
+ if (cfg->inputs[i].type > AUTO_PIN_MIC)
+ break;
+ nid = cfg->inputs[i].pin;
+ if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
+ char label[32];
+ snprintf(label, sizeof(label), "%s Boost",
+ hda_get_autocfg_input_label(codec, cfg, i));
+ err = add_control(spec, ALC_CTL_WIDGET_VOL, label, 0,
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
- if (err < 0)
- return err;
+ if (err < 0)
+ return err;
+ }
}
return 0;
}
@@ -10726,8 +10897,6 @@ static int patch_alc882(struct hda_codec *codec)
codec->spec = spec;
- alc_auto_parse_customize_define(codec);
-
switch (codec->vendor_id) {
case 0x10ec0882:
case 0x10ec0885:
@@ -10755,6 +10924,8 @@ static int patch_alc882(struct hda_codec *codec)
if (board_config == ALC882_AUTO)
alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1);
+ alc_auto_parse_customize_define(codec);
+
if (board_config == ALC882_AUTO) {
/* automatic parse from the BIOS config */
err = alc882_parse_auto_config(codec);
@@ -10835,6 +11006,8 @@ static int patch_alc882(struct hda_codec *codec)
codec->patch_ops = alc_patch_ops;
if (board_config == ALC882_AUTO)
spec->init_hook = alc882_auto_init;
+
+ alc_init_jacks(codec);
#ifdef CONFIG_SND_HDA_POWER_SAVE
if (!spec->loopback.amplist)
spec->loopback.amplist = alc882_loopbacks;
@@ -11831,7 +12004,7 @@ static int alc262_check_volbit(hda_nid_t nid)
}
static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
- const char *pfx, int *vbits)
+ const char *pfx, int *vbits, int idx)
{
unsigned long val;
int vbit;
@@ -11846,11 +12019,11 @@ static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
else
val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
- return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val);
+ return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
}
static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
- const char *pfx)
+ const char *pfx, int idx)
{
unsigned long val;
@@ -11860,7 +12033,7 @@ static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
else
val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
- return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
+ return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
}
/* add playback controls from the parsed DAC table */
@@ -11869,7 +12042,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
{
const char *pfx;
int vbits;
- int err;
+ int i, err;
spec->multiout.num_dacs = 1; /* only use one dac */
spec->multiout.dac_nids = spec->private_dac_nids;
@@ -11879,39 +12052,52 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
pfx = "Master";
else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
pfx = "Speaker";
+ else if (cfg->line_out_type == AUTO_PIN_HP_OUT)
+ pfx = "Headphone";
else
pfx = "Front";
- err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[0], pfx);
- if (err < 0)
- return err;
- err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[0], "Speaker");
- if (err < 0)
- return err;
- err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[0], "Headphone");
- if (err < 0)
- return err;
+ for (i = 0; i < 2; i++) {
+ err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i);
+ if (err < 0)
+ return err;
+ if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+ err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
+ "Speaker", i);
+ if (err < 0)
+ return err;
+ }
+ if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+ err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
+ "Headphone", i);
+ if (err < 0)
+ return err;
+ }
+ }
vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
alc262_check_volbit(cfg->speaker_pins[0]) |
alc262_check_volbit(cfg->hp_pins[0]);
if (vbits == 1 || vbits == 2)
pfx = "Master"; /* only one mixer is used */
- else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
- pfx = "Speaker";
- else
- pfx = "Front";
vbits = 0;
- err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[0], pfx, &vbits);
- if (err < 0)
- return err;
- err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[0], "Speaker",
- &vbits);
- if (err < 0)
- return err;
- err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[0], "Headphone",
- &vbits);
- if (err < 0)
- return err;
+ for (i = 0; i < 2; i++) {
+ err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
+ &vbits, i);
+ if (err < 0)
+ return err;
+ if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+ err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
+ "Speaker", &vbits, i);
+ if (err < 0)
+ return err;
+ }
+ if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+ err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
+ "Headphone", &vbits, i);
+ if (err < 0)
+ return err;
+ }
+ }
return 0;
}
@@ -12199,6 +12385,35 @@ static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
{}
};
+/*
+ * Pin config fixes
+ */
+enum {
+ PINFIX_FSC_H270,
+};
+
+static const struct alc_fixup alc262_fixups[] = {
+ [PINFIX_FSC_H270] = {
+ .pins = (const struct alc_pincfg[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x15, 0x0221142f }, /* front HP */
+ { 0x1b, 0x0121141f }, /* rear HP */
+ { }
+ }
+ },
+ [PINFIX_PB_M5210] = {
+ .verbs = (const struct hda_verb[]) {
+ { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
+ {}
+ }
+ },
+};
+
+static struct snd_pci_quirk alc262_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
+ {}
+};
+
#ifdef CONFIG_SND_HDA_POWER_SAVE
#define alc262_loopbacks alc880_loopbacks
@@ -12622,6 +12837,9 @@ static int patch_alc262(struct hda_codec *codec)
board_config = ALC262_AUTO;
}
+ if (board_config == ALC262_AUTO)
+ alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 1);
+
if (board_config == ALC262_AUTO) {
/* automatic parse from the BIOS config */
err = alc262_parse_auto_config(codec);
@@ -12690,11 +12908,16 @@ static int patch_alc262(struct hda_codec *codec)
if (!spec->no_analog && has_cdefine_beep(codec))
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (board_config == ALC262_AUTO)
+ alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 0);
+
spec->vmaster_nid = 0x0c;
codec->patch_ops = alc_patch_ops;
if (board_config == ALC262_AUTO)
spec->init_hook = alc262_auto_init;
+
+ alc_init_jacks(codec);
#ifdef CONFIG_SND_HDA_POWER_SAVE
if (!spec->loopback.amplist)
spec->loopback.amplist = alc262_loopbacks;
@@ -13310,8 +13533,10 @@ static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
static void alc268_auto_init_multi_out(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- hda_nid_t nid = spec->autocfg.line_out_pins[0];
- if (nid) {
+ int i;
+
+ for (i = 0; i < spec->autocfg.line_outs; i++) {
+ hda_nid_t nid = spec->autocfg.line_out_pins[i];
int pin_type = get_pin_type(spec->autocfg.line_out_type);
alc268_auto_set_output_and_unmute(codec, nid, pin_type);
}
@@ -13321,13 +13546,19 @@ static void alc268_auto_init_hp_out(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
hda_nid_t pin;
+ int i;
- pin = spec->autocfg.hp_pins[0];
- if (pin)
+ for (i = 0; i < spec->autocfg.hp_outs; i++) {
+ pin = spec->autocfg.hp_pins[i];
alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
- pin = spec->autocfg.speaker_pins[0];
- if (pin)
+ }
+ for (i = 0; i < spec->autocfg.speaker_outs; i++) {
+ pin = spec->autocfg.speaker_pins[i];
alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
+ }
+ if (spec->autocfg.mono_out_pin)
+ snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
}
static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
@@ -13766,6 +13997,8 @@ static int patch_alc268(struct hda_codec *codec)
if (board_config == ALC268_AUTO)
spec->init_hook = alc268_auto_init;
+ alc_init_jacks(codec);
+
return 0;
}
@@ -14132,6 +14365,7 @@ static void alc269_speaker_automute(struct hda_codec *codec)
HDA_AMP_MUTE, bits);
snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
HDA_AMP_MUTE, bits);
+ alc_report_jack(codec, nid);
}
/* unsolicited event for HP jack sensing */
@@ -14386,6 +14620,13 @@ static int alc275_setup_dual_adc(struct hda_codec *codec)
return 0;
}
+/* different alc269-variants */
+enum {
+ ALC269_TYPE_NORMAL,
+ ALC269_TYPE_ALC259,
+ ALC269_TYPE_ALC271X,
+};
+
/*
* BIOS auto configuration
*/
@@ -14403,7 +14644,11 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
if (err < 0)
return err;
- err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
+ if (spec->codec_variant == ALC269_TYPE_NORMAL)
+ err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
+ else
+ err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0,
+ 0x22, 0);
if (err < 0)
return err;
@@ -14414,7 +14659,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
if (spec->kctls.list)
add_mixer(spec, spec->kctls.list);
- if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010) {
+ if (spec->codec_variant != ALC269_TYPE_NORMAL) {
add_verb(spec, alc269vb_init_verbs);
alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
} else {
@@ -14461,19 +14706,71 @@ static void alc269_auto_init(struct hda_codec *codec)
alc_inithook(codec);
}
+#ifdef SND_HDA_NEEDS_RESUME
+static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
+{
+ int val = alc_read_coef_idx(codec, 0x04);
+ if (power_up)
+ val |= 1 << 11;
+ else
+ val &= ~(1 << 11);
+ alc_write_coef_idx(codec, 0x04, val);
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static int alc269_suspend(struct hda_codec *codec, pm_message_t state)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
+ alc269_toggle_power_output(codec, 0);
+ if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+ alc269_toggle_power_output(codec, 0);
+ msleep(150);
+ }
+
+ alc_shutup(codec);
+ if (spec && spec->power_hook)
+ spec->power_hook(codec);
+ return 0;
+}
+#endif /* CONFIG_SND_HDA_POWER_SAVE */
+
+static int alc269_resume(struct hda_codec *codec)
+{
+ if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+ alc269_toggle_power_output(codec, 0);
+ msleep(150);
+ }
+
+ codec->patch_ops.init(codec);
+
+ if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
+ alc269_toggle_power_output(codec, 1);
+ msleep(200);
+ }
+
+ if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
+ alc269_toggle_power_output(codec, 1);
+
+ snd_hda_codec_resume_amp(codec);
+ snd_hda_codec_resume_cache(codec);
+ hda_call_check_power_status(codec, 0x01);
+ return 0;
+}
+#endif /* SND_HDA_NEEDS_RESUME */
+
enum {
ALC269_FIXUP_SONY_VAIO,
ALC269_FIXUP_DELL_M101Z,
};
-static const struct hda_verb alc269_sony_vaio_fixup_verbs[] = {
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
- {}
-};
-
static const struct alc_fixup alc269_fixups[] = {
[ALC269_FIXUP_SONY_VAIO] = {
- .verbs = alc269_sony_vaio_fixup_verbs
+ .verbs = (const struct hda_verb[]) {
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
+ {}
+ }
},
[ALC269_FIXUP_DELL_M101Z] = {
.verbs = (const struct hda_verb[]) {
@@ -14486,8 +14783,7 @@ static const struct alc_fixup alc269_fixups[] = {
};
static struct snd_pci_quirk alc269_fixup_tbl[] = {
- SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
- SND_PCI_QUIRK(0x104d, 0x9077, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
+ SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
{}
};
@@ -14689,12 +14985,46 @@ static struct alc_config_preset alc269_presets[] = {
},
};
+static int alc269_fill_coef(struct hda_codec *codec)
+{
+ int val;
+
+ if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
+ alc_write_coef_idx(codec, 0xf, 0x960b);
+ alc_write_coef_idx(codec, 0xe, 0x8817);
+ }
+
+ if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
+ alc_write_coef_idx(codec, 0xf, 0x960b);
+ alc_write_coef_idx(codec, 0xe, 0x8814);
+ }
+
+ if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
+ val = alc_read_coef_idx(codec, 0x04);
+ /* Power up output pin */
+ alc_write_coef_idx(codec, 0x04, val | (1<<11));
+ }
+
+ if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+ val = alc_read_coef_idx(codec, 0xd);
+ if ((val & 0x0c00) >> 10 != 0x1) {
+ /* Capless ramp up clock control */
+ alc_write_coef_idx(codec, 0xd, val | 1<<10);
+ }
+ val = alc_read_coef_idx(codec, 0x17);
+ if ((val & 0x01c0) >> 6 != 0x4) {
+ /* Class D power on reset */
+ alc_write_coef_idx(codec, 0x17, val | 1<<7);
+ }
+ }
+ return 0;
+}
+
static int patch_alc269(struct hda_codec *codec)
{
struct alc_spec *spec;
int board_config;
int err;
- int is_alc269vb = 0;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
@@ -14706,14 +15036,18 @@ static int patch_alc269(struct hda_codec *codec)
if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
if (codec->bus->pci->subsystem_vendor == 0x1025 &&
- spec->cdefine.platform_type == 1)
+ spec->cdefine.platform_type == 1) {
alc_codec_rename(codec, "ALC271X");
- else
+ spec->codec_variant = ALC269_TYPE_ALC271X;
+ } else {
alc_codec_rename(codec, "ALC259");
- is_alc269vb = 1;
+ spec->codec_variant = ALC269_TYPE_ALC259;
+ }
} else
alc_fix_pll_init(codec, 0x20, 0x04, 15);
+ alc269_fill_coef(codec);
+
board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
alc269_models,
alc269_cfg_tbl);
@@ -14770,7 +15104,7 @@ static int patch_alc269(struct hda_codec *codec)
spec->stream_digital_capture = &alc269_pcm_digital_capture;
if (!spec->adc_nids) { /* wasn't filled automatically? use default */
- if (!is_alc269vb) {
+ if (spec->codec_variant != ALC269_TYPE_NORMAL) {
spec->adc_nids = alc269_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
spec->capsrc_nids = alc269_capsrc_nids;
@@ -14792,8 +15126,16 @@ static int patch_alc269(struct hda_codec *codec)
spec->vmaster_nid = 0x02;
codec->patch_ops = alc_patch_ops;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+ codec->patch_ops.suspend = alc269_suspend;
+#endif
+#ifdef SND_HDA_NEEDS_RESUME
+ codec->patch_ops.resume = alc269_resume;
+#endif
if (board_config == ALC269_AUTO)
spec->init_hook = alc269_auto_init;
+
+ alc_init_jacks(codec);
#ifdef CONFIG_SND_HDA_POWER_SAVE
if (!spec->loopback.amplist)
spec->loopback.amplist = alc269_loopbacks;
@@ -15606,12 +15948,13 @@ static void alc861_auto_init_hp_out(struct hda_codec *codec)
static void alc861_auto_init_analog_input(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
int i;
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- hda_nid_t nid = spec->autocfg.input_pins[i];
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
if (nid >= 0x0c && nid <= 0x11)
- alc_set_input_pin(codec, nid, i);
+ alc_set_input_pin(codec, nid, cfg->inputs[i].type);
}
}
@@ -15840,15 +16183,13 @@ enum {
PINFIX_FSC_AMILO_PI1505,
};
-static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = {
- { 0x0b, 0x0221101f }, /* HP */
- { 0x0f, 0x90170310 }, /* speaker */
- { }
-};
-
static const struct alc_fixup alc861_fixups[] = {
[PINFIX_FSC_AMILO_PI1505] = {
- .pins = alc861_fsc_amilo_pi1505_pinfix
+ .pins = (const struct alc_pincfg[]) {
+ { 0x0b, 0x0221101f }, /* HP */
+ { 0x0f, 0x90170310 }, /* speaker */
+ { }
+ }
},
};
@@ -16600,12 +16941,13 @@ static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
int i;
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- hda_nid_t nid = spec->autocfg.input_pins[i];
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
if (alc_is_input_pin(codec, nid)) {
- alc_set_input_pin(codec, nid, i);
+ alc_set_input_pin(codec, nid, cfg->inputs[i].type);
if (nid != ALC861VD_PIN_CD_NID &&
(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
snd_hda_codec_write(codec, nid, 0,
@@ -16815,16 +17157,14 @@ enum {
};
/* reset GPIO1 */
-static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
- {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
- { }
-};
-
static const struct alc_fixup alc861vd_fixups[] = {
[ALC660VD_FIX_ASUS_GPIO1] = {
- .verbs = alc660vd_fix_asus_gpio1_verbs,
+ .verbs = (const struct hda_verb[]) {
+ {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
+ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+ {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+ { }
+ }
},
};
@@ -18838,12 +19178,13 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec)
static void alc662_auto_init_analog_input(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
int i;
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- hda_nid_t nid = spec->autocfg.input_pins[i];
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
if (alc_is_input_pin(codec, nid)) {
- alc_set_input_pin(codec, nid, i);
+ alc_set_input_pin(codec, nid, cfg->inputs[i].type);
if (nid != ALC662_PIN_CD_NID &&
(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
snd_hda_codec_write(codec, nid, 0,
@@ -18935,10 +19276,40 @@ static void alc662_auto_init(struct hda_codec *codec)
alc_inithook(codec);
}
+enum {
+ ALC662_FIXUP_ASPIRE,
+ ALC662_FIXUP_IDEAPAD,
+};
+
+static const struct alc_fixup alc662_fixups[] = {
+ [ALC662_FIXUP_ASPIRE] = {
+ .pins = (const struct alc_pincfg[]) {
+ { 0x15, 0x99130112 }, /* subwoofer */
+ { }
+ }
+ },
+ [ALC662_FIXUP_IDEAPAD] = {
+ .pins = (const struct alc_pincfg[]) {
+ { 0x17, 0x99130112 }, /* subwoofer */
+ { }
+ }
+ },
+};
+
+static struct snd_pci_quirk alc662_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
+ SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
+ SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
+ {}
+};
+
+
+
static int patch_alc662(struct hda_codec *codec)
{
struct alc_spec *spec;
int err, board_config;
+ int coef;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
@@ -18950,12 +19321,15 @@ static int patch_alc662(struct hda_codec *codec)
alc_fix_pll_init(codec, 0x20, 0x04, 15);
- if (alc_read_coef_idx(codec, 0) == 0x8020)
+ coef = alc_read_coef_idx(codec, 0);
+ if (coef == 0x8020 || coef == 0x8011)
alc_codec_rename(codec, "ALC661");
- else if ((alc_read_coef_idx(codec, 0) & (1 << 14)) &&
- codec->bus->pci->subsystem_vendor == 0x1025 &&
- spec->cdefine.platform_type == 1)
+ else if (coef & (1 << 14) &&
+ codec->bus->pci->subsystem_vendor == 0x1025 &&
+ spec->cdefine.platform_type == 1)
alc_codec_rename(codec, "ALC272X");
+ else if (coef == 0x4011)
+ alc_codec_rename(codec, "ALC656");
board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
alc662_models,
@@ -18967,6 +19341,7 @@ static int patch_alc662(struct hda_codec *codec)
}
if (board_config == ALC662_AUTO) {
+ alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 1);
/* automatic parse from the BIOS config */
err = alc662_parse_auto_config(codec);
if (err < 0) {
@@ -19025,8 +19400,13 @@ static int patch_alc662(struct hda_codec *codec)
spec->vmaster_nid = 0x02;
codec->patch_ops = alc_patch_ops;
- if (board_config == ALC662_AUTO)
+ if (board_config == ALC662_AUTO) {
spec->init_hook = alc662_auto_init;
+ alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 0);
+ }
+
+ alc_init_jacks(codec);
+
#ifdef CONFIG_SND_HDA_POWER_SAVE
if (!spec->loopback.amplist)
spec->loopback.amplist = alc662_loopbacks;
@@ -19070,6 +19450,39 @@ static hda_nid_t alc680_adc_nids[3] = {
/*
* Analog capture ADC cgange
*/
+static void alc680_rec_autoswitch(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int pin_found = 0;
+ int type_found = AUTO_PIN_LAST;
+ hda_nid_t nid;
+ int i;
+
+ for (i = 0; i < cfg->num_inputs; i++) {
+ nid = cfg->inputs[i].pin;
+ if (!(snd_hda_query_pin_caps(codec, nid) &
+ AC_PINCAP_PRES_DETECT))
+ continue;
+ if (snd_hda_jack_detect(codec, nid)) {
+ if (cfg->inputs[i].type < type_found) {
+ type_found = cfg->inputs[i].type;
+ pin_found = nid;
+ }
+ }
+ }
+
+ nid = 0x07;
+ if (pin_found)
+ snd_hda_get_connections(codec, pin_found, &nid, 1);
+
+ if (nid != spec->cur_adc)
+ __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
+ spec->cur_adc = nid;
+ snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
+ spec->cur_adc_format);
+}
+
static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
@@ -19077,24 +19490,12 @@ static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream)
{
struct alc_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- unsigned int pre_mic, pre_line;
-
- pre_mic = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]);
- pre_line = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_LINE]);
+ spec->cur_adc = 0x07;
spec->cur_adc_stream_tag = stream_tag;
spec->cur_adc_format = format;
- if (pre_mic || pre_line) {
- if (pre_mic)
- snd_hda_codec_setup_stream(codec, 0x08, stream_tag, 0,
- format);
- else
- snd_hda_codec_setup_stream(codec, 0x09, stream_tag, 0,
- format);
- } else
- snd_hda_codec_setup_stream(codec, 0x07, stream_tag, 0, format);
+ alc680_rec_autoswitch(codec);
return 0;
}
@@ -19180,6 +19581,7 @@ static struct hda_verb alc680_init_verbs[] = {
{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
+ {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
{ }
};
@@ -19192,25 +19594,11 @@ static void alc680_base_setup(struct hda_codec *codec)
spec->autocfg.hp_pins[0] = 0x16;
spec->autocfg.speaker_pins[0] = 0x14;
spec->autocfg.speaker_pins[1] = 0x15;
- spec->autocfg.input_pins[AUTO_PIN_MIC] = 0x18;
- spec->autocfg.input_pins[AUTO_PIN_LINE] = 0x19;
-}
-
-static void alc680_rec_autoswitch(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- unsigned int present;
- hda_nid_t new_adc;
-
- present = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]);
-
- new_adc = present ? 0x8 : 0x7;
- __snd_hda_codec_cleanup_stream(codec, !present ? 0x8 : 0x7, 1);
- snd_hda_codec_setup_stream(codec, new_adc,
- spec->cur_adc_stream_tag, 0,
- spec->cur_adc_format);
-
+ spec->autocfg.num_inputs = 2;
+ spec->autocfg.inputs[0].pin = 0x18;
+ spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
+ spec->autocfg.inputs[1].pin = 0x19;
+ spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
}
static void alc680_unsol_event(struct hda_codec *codec,
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index c16c5ba0fda0..93fa59cc60ef 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -32,6 +32,7 @@
#include <sound/core.h>
#include <sound/asoundef.h>
#include <sound/jack.h>
+#include <sound/tlv.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_beep.h"
@@ -263,6 +264,7 @@ struct sigmatel_spec {
struct sigmatel_mic_route ext_mic;
struct sigmatel_mic_route int_mic;
+ struct sigmatel_mic_route dock_mic;
const char **spdif_labels;
@@ -382,6 +384,11 @@ static unsigned int stac92hd83xxx_pwr_mapping[4] = {
0x03, 0x0c, 0x20, 0x40,
};
+#define STAC92HD83XXX_NUM_DMICS 2
+static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
+ 0x11, 0x20, 0
+};
+
#define STAC92HD83XXX_NUM_CAPS 2
static unsigned long stac92hd83xxx_capvols[] = {
HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
@@ -986,7 +993,7 @@ static struct hda_verb stac9205_core_init[] = {
}
static struct snd_kcontrol_new stac9200_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
@@ -1014,7 +1021,7 @@ static struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
};
static struct snd_kcontrol_new stac925x_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
{ } /* end */
};
@@ -1105,9 +1112,7 @@ static int stac92xx_build_controls(struct hda_codec *codec)
struct hda_input_mux *smux = &spec->private_smux;
/* check for mute support on SPDIF out */
if (wcaps & AC_WCAP_OUT_AMP) {
- smux->items[smux->num_items].label = "Off";
- smux->items[smux->num_items].index = 0;
- smux->num_items++;
+ snd_hda_add_imux_item(smux, "Off", 0, NULL);
spec->spdif_mute = 1;
}
stac_smux_mixer.count = spec->num_smuxes;
@@ -1140,6 +1145,8 @@ static int stac92xx_build_controls(struct hda_codec *codec)
HDA_OUTPUT, vmaster_tlv);
/* correct volume offset */
vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
+ /* minimum value is actually mute */
+ vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
vmaster_tlv, slave_vols);
if (err < 0)
@@ -1180,14 +1187,11 @@ static int stac92xx_build_controls(struct hda_codec *codec)
if (err < 0)
return err;
}
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- nid = cfg->input_pins[i];
- if (nid) {
- err = stac92xx_add_jack(codec, nid,
- SND_JACK_MICROPHONE);
- if (err < 0)
- return err;
- }
+ for (i = 0; i < cfg->num_inputs; i++) {
+ nid = cfg->inputs[i].pin;
+ err = stac92xx_add_jack(codec, nid, SND_JACK_MICROPHONE);
+ if (err < 0)
+ return err;
}
return 0;
@@ -2779,7 +2783,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
struct sigmatel_spec *spec = codec->spec;
char name[22];
- if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) {
+ if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
&& nid == spec->line_switch)
control = STAC_CTL_WIDGET_IO_SWITCH;
@@ -2791,7 +2795,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
}
if (control) {
- strcpy(name, auto_pin_cfg_labels[idx]);
+ strcpy(name, hda_get_input_pin_label(codec, nid, 1));
return stac92xx_add_control(codec->spec, control,
strcat(name, " Jack Mode"), nid);
}
@@ -2823,41 +2827,49 @@ static hda_nid_t check_line_out_switch(struct hda_codec *codec)
struct auto_pin_cfg *cfg = &spec->autocfg;
hda_nid_t nid;
unsigned int pincap;
+ int i;
if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
return 0;
- nid = cfg->input_pins[AUTO_PIN_LINE];
- pincap = snd_hda_query_pin_caps(codec, nid);
- if (pincap & AC_PINCAP_OUT)
- return nid;
+ for (i = 0; i < cfg->num_inputs; i++) {
+ if (cfg->inputs[i].type == AUTO_PIN_LINE_IN) {
+ nid = cfg->inputs[i].pin;
+ pincap = snd_hda_query_pin_caps(codec, nid);
+ if (pincap & AC_PINCAP_OUT)
+ return nid;
+ }
+ }
return 0;
}
+static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid);
+
/* check whether the mic-input can be used as line-out */
-static hda_nid_t check_mic_out_switch(struct hda_codec *codec)
+static hda_nid_t check_mic_out_switch(struct hda_codec *codec, hda_nid_t *dac)
{
struct sigmatel_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
unsigned int def_conf, pincap;
- unsigned int mic_pin;
+ int i;
+ *dac = 0;
if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
return 0;
- mic_pin = AUTO_PIN_MIC;
- for (;;) {
- hda_nid_t nid = cfg->input_pins[mic_pin];
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
+ if (cfg->inputs[i].type != AUTO_PIN_MIC)
+ continue;
def_conf = snd_hda_codec_get_pincfg(codec, nid);
/* some laptops have an internal analog microphone
* which can't be used as a output */
- if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
+ if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
pincap = snd_hda_query_pin_caps(codec, nid);
- if (pincap & AC_PINCAP_OUT)
- return nid;
+ if (pincap & AC_PINCAP_OUT) {
+ *dac = get_unassigned_dac(codec, nid);
+ if (*dac)
+ return nid;
+ }
}
- if (mic_pin == AUTO_PIN_MIC)
- mic_pin = AUTO_PIN_FRONT_MIC;
- else
- break;
}
return 0;
}
@@ -3004,17 +3016,14 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
}
}
/* add mic as output */
- nid = check_mic_out_switch(codec);
- if (nid) {
- dac = get_unassigned_dac(codec, nid);
- if (dac) {
- snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
- nid, cfg->line_outs);
- cfg->line_out_pins[cfg->line_outs] = nid;
- cfg->line_outs++;
- spec->mic_switch = nid;
- add_spec_dacs(spec, dac);
- }
+ nid = check_mic_out_switch(codec, &dac);
+ if (nid && dac) {
+ snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
+ nid, cfg->line_outs);
+ cfg->line_out_pins[cfg->line_outs] = nid;
+ cfg->line_outs++;
+ spec->mic_switch = nid;
+ add_spec_dacs(spec, dac);
}
snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
@@ -3204,13 +3213,13 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
return err;
}
- for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) {
- nid = cfg->input_pins[idx];
- if (nid) {
- err = stac92xx_add_jack_mode_control(codec, nid, idx);
- if (err < 0)
- return err;
- }
+ for (idx = 0; idx < cfg->num_inputs; idx++) {
+ if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN)
+ break;
+ nid = cfg->inputs[idx].pin;
+ err = stac92xx_add_jack_mode_control(codec, nid, idx);
+ if (err < 0)
+ return err;
}
return 0;
@@ -3256,12 +3265,9 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
return -EINVAL;
- for (i = 0; i < num_cons; i++) {
- mono_mux->items[mono_mux->num_items].label =
- stac92xx_mono_labels[i];
- mono_mux->items[mono_mux->num_items].index = i;
- mono_mux->num_items++;
- }
+ for (i = 0; i < num_cons; i++)
+ snd_hda_add_imux_item(mono_mux, stac92xx_mono_labels[i], i,
+ NULL);
return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
"Mono Mux", spec->mono_nid);
@@ -3386,11 +3392,8 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
if (!labels)
labels = stac92xx_spdif_labels;
- for (i = 0; i < num_cons; i++) {
- spdif_mux->items[spdif_mux->num_items].label = labels[i];
- spdif_mux->items[spdif_mux->num_items].index = i;
- spdif_mux->num_items++;
- }
+ for (i = 0; i < num_cons; i++)
+ snd_hda_add_imux_item(spdif_mux, labels[i], i, NULL);
return 0;
}
@@ -3417,7 +3420,7 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
/* create a volume assigned to the given pin (only if supported) */
/* return 1 if the volume control is created */
static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid,
- const char *label, int direction)
+ const char *label, int idx, int direction)
{
unsigned int caps, nums;
char name[32];
@@ -3434,8 +3437,8 @@ static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid,
if (!nums)
return 0;
snprintf(name, sizeof(name), "%s Capture Volume", label);
- err = stac92xx_add_control(codec->spec, STAC_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction));
+ err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction));
if (err < 0)
return err;
return 1;
@@ -3448,27 +3451,14 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
struct sigmatel_spec *spec = codec->spec;
struct hda_input_mux *imux = &spec->private_imux;
struct hda_input_mux *dimux = &spec->private_dimux;
- int err, i, active_mics;
+ int err, i;
unsigned int def_conf;
- dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
- dimux->items[dimux->num_items].index = 0;
- dimux->num_items++;
-
- active_mics = 0;
- for (i = 0; i < spec->num_dmics; i++) {
- /* check the validity: sometimes it's a dead vendor-spec node */
- if (get_wcaps_type(get_wcaps(codec, spec->dmic_nids[i]))
- != AC_WID_PIN)
- continue;
- def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]);
- if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
- active_mics++;
- }
+ snd_hda_add_imux_item(dimux, stac92xx_dmic_labels[0], 0, NULL);
for (i = 0; i < spec->num_dmics; i++) {
hda_nid_t nid;
- int index;
+ int index, type_idx;
const char *label;
nid = spec->dmic_nids[i];
@@ -3482,28 +3472,23 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
if (index < 0)
continue;
- if (active_mics == 1)
- label = "Digital Mic";
- else
- label = stac92xx_dmic_labels[dimux->num_items];
+ label = hda_get_input_pin_label(codec, nid, 1);
+ snd_hda_add_imux_item(dimux, label, index, &type_idx);
- err = create_elem_capture_vol(codec, nid, label, HDA_INPUT);
+ err = create_elem_capture_vol(codec, nid, label, type_idx,
+ HDA_INPUT);
if (err < 0)
return err;
if (!err) {
err = create_elem_capture_vol(codec, nid, label,
- HDA_OUTPUT);
+ type_idx, HDA_OUTPUT);
if (err < 0)
return err;
}
- dimux->items[dimux->num_items].label = label;
- dimux->items[dimux->num_items].index = index;
- dimux->num_items++;
if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) {
- imux->items[imux->num_items].label = label;
- imux->items[imux->num_items].index = index;
- imux->num_items++;
+ snd_hda_add_imux_item(imux, label, index, NULL);
+ spec->num_analog_muxes++;
}
}
@@ -3511,20 +3496,27 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
}
static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid,
- hda_nid_t *fixed, hda_nid_t *ext)
+ hda_nid_t *fixed, hda_nid_t *ext, hda_nid_t *dock)
{
unsigned int cfg;
if (!nid)
return 0;
cfg = snd_hda_codec_get_pincfg(codec, nid);
- switch (get_defcfg_connect(cfg)) {
- case AC_JACK_PORT_FIXED:
+ switch (snd_hda_get_input_pin_attr(cfg)) {
+ case INPUT_PIN_ATTR_INT:
if (*fixed)
return 1; /* already occupied */
*fixed = nid;
break;
- case AC_JACK_PORT_COMPLEX:
+ case INPUT_PIN_ATTR_UNUSED:
+ break;
+ case INPUT_PIN_ATTR_DOCK:
+ if (*dock)
+ return 1; /* already occupied */
+ *dock = nid;
+ break;
+ default:
if (*ext)
return 1; /* already occupied */
*ext = nid;
@@ -3542,10 +3534,13 @@ static int set_mic_route(struct hda_codec *codec,
int i;
mic->pin = pin;
- for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
- if (pin == cfg->input_pins[i])
+ if (pin == 0)
+ return 0;
+ for (i = 0; i < cfg->num_inputs; i++) {
+ if (pin == cfg->inputs[i].pin)
break;
- if (i <= AUTO_PIN_FRONT_MIC) {
+ }
+ if (i < cfg->num_inputs && cfg->inputs[i].type == AUTO_PIN_MIC) {
/* analog pin */
i = get_connection_index(codec, spec->mux_nids[0], pin);
if (i < 0)
@@ -3576,26 +3571,29 @@ static int stac_check_auto_mic(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
- hda_nid_t fixed, ext;
+ hda_nid_t fixed, ext, dock;
int i;
- for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) {
- if (cfg->input_pins[i])
+ for (i = 0; i < cfg->num_inputs; i++) {
+ if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
return 0; /* must be exclusively mics */
}
- fixed = ext = 0;
- for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
- if (check_mic_pin(codec, cfg->input_pins[i], &fixed, &ext))
+ fixed = ext = dock = 0;
+ for (i = 0; i < cfg->num_inputs; i++)
+ if (check_mic_pin(codec, cfg->inputs[i].pin,
+ &fixed, &ext, &dock))
return 0;
for (i = 0; i < spec->num_dmics; i++)
- if (check_mic_pin(codec, spec->dmic_nids[i], &fixed, &ext))
+ if (check_mic_pin(codec, spec->dmic_nids[i],
+ &fixed, &ext, &dock))
return 0;
- if (!fixed || !ext)
- return 0;
+ if (!fixed && !ext && !dock)
+ return 0; /* no input to switch */
if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
return 0; /* no unsol support */
if (set_mic_route(codec, &spec->ext_mic, ext) ||
- set_mic_route(codec, &spec->int_mic, fixed))
+ set_mic_route(codec, &spec->int_mic, fixed) ||
+ set_mic_route(codec, &spec->dock_mic, dock))
return 0; /* something is wrong */
return 1;
}
@@ -3606,13 +3604,12 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
struct sigmatel_spec *spec = codec->spec;
struct hda_input_mux *imux = &spec->private_imux;
int i, j;
+ const char *label;
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- hda_nid_t nid = cfg->input_pins[i];
- int index, err;
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
+ int index, err, type_idx;
- if (!nid)
- continue;
index = -1;
for (j = 0; j < spec->num_muxes; j++) {
index = get_connection_index(codec, spec->mux_nids[j],
@@ -3623,15 +3620,14 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
if (index < 0)
continue;
+ label = hda_get_autocfg_input_label(codec, cfg, i);
+ snd_hda_add_imux_item(imux, label, index, &type_idx);
+
err = create_elem_capture_vol(codec, nid,
- auto_pin_cfg_labels[i],
+ label, type_idx,
HDA_INPUT);
if (err < 0)
return err;
-
- imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
- imux->items[imux->num_items].index = index;
- imux->num_items++;
}
spec->num_analog_muxes = imux->num_items;
@@ -4305,38 +4301,38 @@ static int stac92xx_init(struct hda_codec *codec)
AC_VERB_SET_CONNECT_SEL, 0);
if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT))
stac_issue_unsol_event(codec, spec->ext_mic.pin);
- }
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- hda_nid_t nid = cfg->input_pins[i];
- if (nid) {
- unsigned int pinctl, conf;
- if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
- /* for mic pins, force to initialize */
- pinctl = stac92xx_get_default_vref(codec, nid);
+ if (enable_pin_detect(codec, spec->dock_mic.pin,
+ STAC_MIC_EVENT))
+ stac_issue_unsol_event(codec, spec->dock_mic.pin);
+ }
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
+ int type = cfg->inputs[i].type;
+ unsigned int pinctl, conf;
+ if (type == AUTO_PIN_MIC) {
+ /* for mic pins, force to initialize */
+ pinctl = stac92xx_get_default_vref(codec, nid);
+ pinctl |= AC_PINCTL_IN_EN;
+ stac92xx_auto_set_pinctl(codec, nid, pinctl);
+ } else {
+ pinctl = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ /* if PINCTL already set then skip */
+ /* Also, if both INPUT and OUTPUT are set,
+ * it must be a BIOS bug; need to override, too
+ */
+ if (!(pinctl & AC_PINCTL_IN_EN) ||
+ (pinctl & AC_PINCTL_OUT_EN)) {
+ pinctl &= ~AC_PINCTL_OUT_EN;
pinctl |= AC_PINCTL_IN_EN;
stac92xx_auto_set_pinctl(codec, nid, pinctl);
- } else {
- pinctl = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
- /* if PINCTL already set then skip */
- /* Also, if both INPUT and OUTPUT are set,
- * it must be a BIOS bug; need to override, too
- */
- if (!(pinctl & AC_PINCTL_IN_EN) ||
- (pinctl & AC_PINCTL_OUT_EN)) {
- pinctl &= ~AC_PINCTL_OUT_EN;
- pinctl |= AC_PINCTL_IN_EN;
- stac92xx_auto_set_pinctl(codec, nid,
- pinctl);
- }
- }
- conf = snd_hda_codec_get_pincfg(codec, nid);
- if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
- if (enable_pin_detect(codec, nid,
- STAC_INSERT_EVENT))
- stac_issue_unsol_event(codec, nid);
}
}
+ conf = snd_hda_codec_get_pincfg(codec, nid);
+ if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
+ if (enable_pin_detect(codec, nid, STAC_INSERT_EVENT))
+ stac_issue_unsol_event(codec, nid);
+ }
}
for (i = 0; i < spec->num_dmics; i++)
stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
@@ -4383,11 +4379,9 @@ static int stac92xx_init(struct hda_codec *codec)
stac_issue_unsol_event(codec, nid);
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
/* sync mute LED */
- if (spec->gpio_led && codec->patch_ops.check_power_status)
- codec->patch_ops.check_power_status(codec, 0x01);
-#endif
+ if (spec->gpio_led)
+ hda_call_check_power_status(codec, 0x01);
if (spec->dac_list)
stac92xx_power_down(codec);
return 0;
@@ -4688,6 +4682,36 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
}
}
+/* get the pin connection (fixed, none, etc) */
+static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ unsigned int cfg;
+
+ cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
+ return get_defcfg_connect(cfg);
+}
+
+static int stac92xx_connected_ports(struct hda_codec *codec,
+ hda_nid_t *nids, int num_nids)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ int idx, num;
+ unsigned int def_conf;
+
+ for (num = 0; num < num_nids; num++) {
+ for (idx = 0; idx < spec->num_pins; idx++)
+ if (spec->pin_nids[idx] == nids[num])
+ break;
+ if (idx >= spec->num_pins)
+ break;
+ def_conf = stac_get_defcfg_connect(codec, idx);
+ if (def_conf == AC_JACK_PORT_NONE)
+ break;
+ }
+ return num;
+}
+
static void stac92xx_mic_detect(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
@@ -4695,6 +4719,8 @@ static void stac92xx_mic_detect(struct hda_codec *codec)
if (get_pin_presence(codec, spec->ext_mic.pin))
mic = &spec->ext_mic;
+ else if (get_pin_presence(codec, spec->dock_mic.pin))
+ mic = &spec->dock_mic;
else
mic = &spec->int_mic;
if (mic->dmux_idx >= 0)
@@ -4937,11 +4963,9 @@ static int stac92xx_resume(struct hda_codec *codec)
stac_issue_unsol_event(codec,
spec->autocfg.line_out_pins[0]);
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
/* sync mute LED */
- if (spec->gpio_led && codec->patch_ops.check_power_status)
- codec->patch_ops.check_power_status(codec, 0x01);
-#endif
+ if (spec->gpio_led)
+ hda_call_check_power_status(codec, 0x01);
return 0;
}
@@ -5302,6 +5326,82 @@ again:
return 0;
}
+static int stac92hd83xxx_set_system_btl_amp(struct hda_codec *codec)
+{
+ if (codec->vendor_id != 0x111d7605 &&
+ codec->vendor_id != 0x111d76d1)
+ return 0;
+
+ switch (codec->subsystem_id) {
+ case 0x103c1618:
+ case 0x103c1619:
+ case 0x103c161a:
+ case 0x103c161b:
+ case 0x103c161c:
+ case 0x103c161d:
+ case 0x103c161e:
+ case 0x103c161f:
+ case 0x103c1620:
+ case 0x103c1621:
+ case 0x103c1622:
+ case 0x103c1623:
+
+ case 0x103c162a:
+ case 0x103c162b:
+
+ case 0x103c1630:
+ case 0x103c1631:
+
+ case 0x103c1633:
+
+ case 0x103c1635:
+
+ case 0x103c164f:
+
+ case 0x103c1676:
+ case 0x103c1677:
+ case 0x103c1678:
+ case 0x103c1679:
+ case 0x103c167a:
+ case 0x103c167b:
+ case 0x103c167c:
+ case 0x103c167d:
+ case 0x103c167e:
+ case 0x103c167f:
+ case 0x103c1680:
+ case 0x103c1681:
+ case 0x103c1682:
+ case 0x103c1683:
+ case 0x103c1684:
+ case 0x103c1685:
+ case 0x103c1686:
+ case 0x103c1687:
+ case 0x103c1688:
+ case 0x103c1689:
+ case 0x103c168a:
+ case 0x103c168b:
+ case 0x103c168c:
+ case 0x103c168d:
+ case 0x103c168e:
+ case 0x103c168f:
+ case 0x103c1690:
+ case 0x103c1691:
+ case 0x103c1692:
+
+ case 0x103c3587:
+ case 0x103c3588:
+ case 0x103c3589:
+ case 0x103c358a:
+
+ case 0x103c3667:
+ case 0x103c3668:
+ /* set BTL amp level to 13.43dB for louder speaker output */
+ return snd_hda_codec_write_cache(codec, codec->afg, 0,
+ 0x7F4, 0x14);
+ }
+ return 0;
+}
+
static int patch_stac92hd83xxx(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
@@ -5313,11 +5413,16 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;
+ /* reset pin power-down; Windows may leave these bits after reboot */
+ snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7EC, 0);
+ snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0);
codec->no_trigger_sense = 1;
codec->spec = spec;
spec->linear_tone_beep = 1;
codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
spec->digbeep_nid = 0x21;
+ spec->dmic_nids = stac92hd83xxx_dmic_nids;
+ spec->dmux_nids = stac92hd83xxx_mux_nids;
spec->mux_nids = stac92hd83xxx_mux_nids;
spec->num_muxes = ARRAY_SIZE(stac92hd83xxx_mux_nids);
spec->adc_nids = stac92hd83xxx_adc_nids;
@@ -5363,9 +5468,13 @@ again:
case 0x111d76d4:
case 0x111d7605:
case 0x111d76d5:
+ case 0x111d76e7:
if (spec->board_config == STAC_92HD83XXX_PWR_REF)
break;
spec->num_pwrs = 0;
+ spec->num_dmics = stac92xx_connected_ports(codec,
+ stac92hd83xxx_dmic_nids,
+ STAC92HD83XXX_NUM_DMICS);
break;
}
@@ -5419,41 +5528,13 @@ again:
AC_VERB_SET_CONNECT_SEL, num_dacs);
}
+ stac92hd83xxx_set_system_btl_amp(codec);
+
codec->proc_widget_hook = stac92hd_proc_hook;
return 0;
}
-/* get the pin connection (fixed, none, etc) */
-static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
-{
- struct sigmatel_spec *spec = codec->spec;
- unsigned int cfg;
-
- cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
- return get_defcfg_connect(cfg);
-}
-
-static int stac92hd71bxx_connected_ports(struct hda_codec *codec,
- hda_nid_t *nids, int num_nids)
-{
- struct sigmatel_spec *spec = codec->spec;
- int idx, num;
- unsigned int def_conf;
-
- for (num = 0; num < num_nids; num++) {
- for (idx = 0; idx < spec->num_pins; idx++)
- if (spec->pin_nids[idx] == nids[num])
- break;
- if (idx >= spec->num_pins)
- break;
- def_conf = stac_get_defcfg_connect(codec, idx);
- if (def_conf == AC_JACK_PORT_NONE)
- break;
- }
- return num;
-}
-
static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec,
hda_nid_t dig0pin)
{
@@ -5592,7 +5673,7 @@ again:
case 0x111d76b5:
spec->init = stac92hd71bxx_core_init;
codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
- spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+ spec->num_dmics = stac92xx_connected_ports(codec,
stac92hd71bxx_dmic_nids,
STAC92HD71BXX_NUM_DMICS);
break;
@@ -5624,7 +5705,7 @@ again:
snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0;
- spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+ spec->num_dmics = stac92xx_connected_ports(codec,
stac92hd71bxx_dmic_nids,
STAC92HD71BXX_NUM_DMICS - 1);
break;
@@ -5638,7 +5719,7 @@ again:
default:
spec->init = stac92hd71bxx_core_init;
codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
- spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+ spec->num_dmics = stac92xx_connected_ports(codec,
stac92hd71bxx_dmic_nids,
STAC92HD71BXX_NUM_DMICS);
break;
@@ -6320,6 +6401,8 @@ static 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 = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx},
+ { .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx},
{} /* terminator */
};
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index ae3acb2b42d1..d1c3f8defc48 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -444,8 +444,8 @@ static hda_nid_t vt1812_adc_nids[2] = {
/* add dynamic controls */
-static int via_add_control(struct via_spec *spec, int type, const char *name,
- unsigned long val)
+static int __via_add_control(struct via_spec *spec, int type, const char *name,
+ int idx, unsigned long val)
{
struct snd_kcontrol_new *knew;
@@ -463,6 +463,9 @@ static int via_add_control(struct via_spec *spec, int type, const char *name,
return 0;
}
+#define via_add_control(spec, type, name, val) \
+ __via_add_control(spec, type, name, 0, val)
+
static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec,
struct snd_kcontrol_new *tmpl)
{
@@ -494,18 +497,18 @@ static void via_free_kctls(struct hda_codec *codec)
/* create input playback/capture controls for the given pin */
static int via_new_analog_input(struct via_spec *spec, const char *ctlname,
- int idx, int mix_nid)
+ int type_idx, int idx, int mix_nid)
{
char name[32];
int err;
sprintf(name, "%s Playback Volume", ctlname);
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, name, type_idx,
HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
if (err < 0)
return err;
sprintf(name, "%s Playback Switch", ctlname);
- err = via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name,
+ err = __via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name, type_idx,
HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
if (err < 0)
return err;
@@ -557,17 +560,15 @@ static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
static void via_auto_init_analog_input(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
+ const struct auto_pin_cfg *cfg = &spec->autocfg;
unsigned int ctl;
int i;
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- hda_nid_t nid = spec->autocfg.input_pins[i];
- if (!nid)
- continue;
-
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
if (spec->smart51_enabled && is_smart51_pins(spec, nid))
ctl = PIN_OUT;
- else if (i <= AUTO_PIN_FRONT_MIC)
+ else if (i == AUTO_PIN_MIC)
ctl = PIN_VREF50;
else
ctl = PIN_IN;
@@ -1322,15 +1323,14 @@ static void mute_aa_path(struct hda_codec *codec, int mute)
}
static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin)
{
- int res = 0;
- int index;
- for (index = AUTO_PIN_MIC; index < AUTO_PIN_FRONT_LINE; index++) {
- if (pin == spec->autocfg.input_pins[index]) {
- res = 1;
- break;
- }
+ const struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i;
+
+ for (i = 0; i < cfg->num_inputs; i++) {
+ if (pin == cfg->inputs[i].pin)
+ return cfg->inputs[i].type <= AUTO_PIN_LINE_IN;
}
- return res;
+ return 0;
}
static int via_smart51_info(struct snd_kcontrol *kcontrol,
@@ -1348,25 +1348,21 @@ static int via_smart51_get(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct via_spec *spec = codec->spec;
- int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
+ const struct auto_pin_cfg *cfg = &spec->autocfg;
int on = 1;
int i;
- for (i = 0; i < ARRAY_SIZE(index); i++) {
- hda_nid_t nid = spec->autocfg.input_pins[index[i]];
- if (nid) {
- int ctl =
- snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL,
- 0);
- if (i == AUTO_PIN_FRONT_MIC
- && spec->hp_independent_mode
- && spec->codec_type != VT1718S)
- continue; /* ignore FMic for independent HP */
- if (ctl & AC_PINCTL_IN_EN
- && !(ctl & AC_PINCTL_OUT_EN))
- on = 0;
- }
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
+ int ctl = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
+ continue;
+ if (cfg->inputs[i].type == AUTO_PIN_MIC &&
+ spec->hp_independent_mode && spec->codec_type != VT1718S)
+ continue; /* ignore FMic for independent HP */
+ if ((ctl & AC_PINCTL_IN_EN) && !(ctl & AC_PINCTL_OUT_EN))
+ on = 0;
}
*ucontrol->value.integer.value = on;
return 0;
@@ -1377,36 +1373,38 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct via_spec *spec = codec->spec;
+ const struct auto_pin_cfg *cfg = &spec->autocfg;
int out_in = *ucontrol->value.integer.value
? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN;
- int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
int i;
- for (i = 0; i < ARRAY_SIZE(index); i++) {
- hda_nid_t nid = spec->autocfg.input_pins[index[i]];
- if (i == AUTO_PIN_FRONT_MIC
- && spec->hp_independent_mode
- && spec->codec_type != VT1718S)
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
+ unsigned int parm;
+
+ if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
+ continue;
+ if (cfg->inputs[i].type == AUTO_PIN_MIC &&
+ spec->hp_independent_mode && spec->codec_type != VT1718S)
continue; /* don't retask FMic for independent HP */
- if (nid) {
- unsigned int parm = snd_hda_codec_read(
- codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
- parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
- parm |= out_in;
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- parm);
- if (out_in == AC_PINCTL_OUT_EN) {
- mute_aa_path(codec, 1);
- notify_aa_path_ctls(codec);
- }
- if (spec->codec_type == VT1718S)
- snd_hda_codec_amp_stereo(
+
+ parm = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
+ parm |= out_in;
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ parm);
+ if (out_in == AC_PINCTL_OUT_EN) {
+ mute_aa_path(codec, 1);
+ notify_aa_path_ctls(codec);
+ }
+ if (spec->codec_type == VT1718S) {
+ snd_hda_codec_amp_stereo(
codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE,
HDA_AMP_UNMUTE);
}
- if (i == AUTO_PIN_FRONT_MIC) {
+ if (cfg->inputs[i].type == AUTO_PIN_MIC) {
if (spec->codec_type == VT1708S
|| spec->codec_type == VT1716S) {
/* input = index 1 (AOW3) */
@@ -1442,7 +1440,7 @@ static struct snd_kcontrol_new via_smart51_mixer[2] = {
static int via_smart51_build(struct via_spec *spec)
{
struct snd_kcontrol_new *knew;
- int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
+ const struct auto_pin_cfg *cfg = &spec->autocfg;
hda_nid_t nid;
int i;
@@ -1450,13 +1448,14 @@ static int via_smart51_build(struct via_spec *spec)
if (knew == NULL)
return -ENOMEM;
- for (i = 0; i < ARRAY_SIZE(index); i++) {
- nid = spec->autocfg.input_pins[index[i]];
- if (nid) {
+ for (i = 0; i < cfg->num_inputs; i++) {
+ nid = cfg->inputs[i].pin;
+ if (cfg->inputs[i].type <= AUTO_PIN_LINE_IN) {
knew = via_clone_control(spec, &via_smart51_mixer[1]);
if (knew == NULL)
return -ENOMEM;
knew->subdevice = nid;
+ break;
}
}
@@ -2375,13 +2374,8 @@ static void create_hp_imux(struct via_spec *spec)
static const char *texts[] = { "OFF", "ON", NULL};
/* for hp mode select */
- i = 0;
- while (texts[i] != NULL) {
- imux->items[imux->num_items].label = texts[i];
- imux->items[imux->num_items].index = i;
- imux->num_items++;
- i++;
- }
+ for (i = 0; texts[i]; i++)
+ snd_hda_add_imux_item(imux, texts[i], i, NULL);
spec->hp_mux = &spec->private_imux[1];
}
@@ -2413,51 +2407,53 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
}
/* create playback/capture controls for input pins */
-static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
+static int vt_auto_create_analog_input_ctls(struct hda_codec *codec,
+ const struct auto_pin_cfg *cfg,
+ hda_nid_t cap_nid,
+ hda_nid_t pin_idxs[], int num_idxs)
{
- static char *labels[] = {
- "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
- };
+ struct via_spec *spec = codec->spec;
struct hda_input_mux *imux = &spec->private_imux[0];
- int i, err, idx = 0;
+ int i, err, idx, type, type_idx = 0;
/* for internal loopback recording select */
- imux->items[imux->num_items].label = "Stereo Mixer";
- imux->items[imux->num_items].index = idx;
- imux->num_items++;
-
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- if (!cfg->input_pins[i])
- continue;
-
- switch (cfg->input_pins[i]) {
- case 0x1d: /* Mic */
- idx = 2;
- break;
-
- case 0x1e: /* Line In */
- idx = 3;
- break;
-
- case 0x21: /* Front Mic */
- idx = 4;
- break;
-
- case 0x24: /* CD */
- idx = 1;
+ for (idx = 0; idx < num_idxs; idx++) {
+ if (pin_idxs[idx] == 0xff) {
+ snd_hda_add_imux_item(imux, "Stereo Mixer", idx, NULL);
break;
}
- err = via_new_analog_input(spec, labels[i], idx, 0x17);
+ }
+
+ for (i = 0; i < cfg->num_inputs; i++) {
+ const char *label;
+ type = cfg->inputs[i].type;
+ for (idx = 0; idx < num_idxs; idx++)
+ if (pin_idxs[idx] == cfg->inputs[i].pin)
+ break;
+ if (idx >= num_idxs)
+ continue;
+ if (i > 0 && type == cfg->inputs[i - 1].type)
+ type_idx++;
+ else
+ type_idx = 0;
+ label = hda_get_autocfg_input_label(codec, cfg, i);
+ err = via_new_analog_input(spec, label, type_idx, idx, cap_nid);
if (err < 0)
return err;
- imux->items[imux->num_items].label = labels[i];
- imux->items[imux->num_items].index = idx;
- imux->num_items++;
+ snd_hda_add_imux_item(imux, label, idx, NULL);
}
return 0;
}
+/* create playback/capture controls for input pins */
+static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec,
+ const struct auto_pin_cfg *cfg)
+{
+ static hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 };
+ return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs,
+ ARRAY_SIZE(pin_idxs));
+}
+
#ifdef CONFIG_SND_HDA_POWER_SAVE
static struct hda_amp_list vt1708_loopbacks[] = {
{ 0x17, HDA_INPUT, 1 },
@@ -2554,7 +2550,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
if (err < 0)
return err;
- err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
+ err = vt1708_auto_create_analog_input_ctls(codec, &spec->autocfg);
if (err < 0)
return err;
/* add jack detect on/off control */
@@ -3021,49 +3017,12 @@ static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
}
/* create playback/capture controls for input pins */
-static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
- static char *labels[] = {
- "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
- };
- struct hda_input_mux *imux = &spec->private_imux[0];
- int i, err, idx = 0;
-
- /* for internal loopback recording select */
- imux->items[imux->num_items].label = "Stereo Mixer";
- imux->items[imux->num_items].index = idx;
- imux->num_items++;
-
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- if (!cfg->input_pins[i])
- continue;
-
- switch (cfg->input_pins[i]) {
- case 0x1d: /* Mic */
- idx = 2;
- break;
-
- case 0x1e: /* Line In */
- idx = 3;
- break;
-
- case 0x21: /* Front Mic */
- idx = 4;
- break;
-
- case 0x23: /* CD */
- idx = 1;
- break;
- }
- err = via_new_analog_input(spec, labels[i], idx, 0x18);
- if (err < 0)
- return err;
- imux->items[imux->num_items].label = labels[i];
- imux->items[imux->num_items].index = idx;
- imux->num_items++;
- }
- return 0;
+ static hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 };
+ return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs,
+ ARRAY_SIZE(pin_idxs));
}
static int vt1709_parse_auto_config(struct hda_codec *codec)
@@ -3086,7 +3045,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
if (err < 0)
return err;
- err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
+ err = vt1709_auto_create_analog_input_ctls(codec, &spec->autocfg);
if (err < 0)
return err;
@@ -3588,49 +3547,12 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
}
/* create playback/capture controls for input pins */
-static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
- static char *labels[] = {
- "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
- };
- struct hda_input_mux *imux = &spec->private_imux[0];
- int i, err, idx = 0;
-
- /* for internal loopback recording select */
- imux->items[imux->num_items].label = "Stereo Mixer";
- imux->items[imux->num_items].index = idx;
- imux->num_items++;
-
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- if (!cfg->input_pins[i])
- continue;
-
- switch (cfg->input_pins[i]) {
- case 0x1a: /* Mic */
- idx = 2;
- break;
-
- case 0x1b: /* Line In */
- idx = 3;
- break;
-
- case 0x1e: /* Front Mic */
- idx = 4;
- break;
-
- case 0x1f: /* CD */
- idx = 1;
- break;
- }
- err = via_new_analog_input(spec, labels[i], idx, 0x16);
- if (err < 0)
- return err;
- imux->items[imux->num_items].label = labels[i];
- imux->items[imux->num_items].index = idx;
- imux->num_items++;
- }
- return 0;
+ static hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e };
+ return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
+ ARRAY_SIZE(pin_idxs));
}
static int vt1708B_parse_auto_config(struct hda_codec *codec)
@@ -3653,7 +3575,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
if (err < 0)
return err;
- err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
+ err = vt1708B_auto_create_analog_input_ctls(codec, &spec->autocfg);
if (err < 0)
return err;
@@ -4061,49 +3983,12 @@ static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
}
/* create playback/capture controls for input pins */
-static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
- static char *labels[] = {
- "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
- };
- struct hda_input_mux *imux = &spec->private_imux[0];
- int i, err, idx = 0;
-
- /* for internal loopback recording select */
- imux->items[imux->num_items].label = "Stereo Mixer";
- imux->items[imux->num_items].index = 5;
- imux->num_items++;
-
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- if (!cfg->input_pins[i])
- continue;
-
- switch (cfg->input_pins[i]) {
- case 0x1a: /* Mic */
- idx = 2;
- break;
-
- case 0x1b: /* Line In */
- idx = 3;
- break;
-
- case 0x1e: /* Front Mic */
- idx = 4;
- break;
-
- case 0x1f: /* CD */
- idx = 1;
- break;
- }
- err = via_new_analog_input(spec, labels[i], idx, 0x16);
- if (err < 0)
- return err;
- imux->items[imux->num_items].label = labels[i];
- imux->items[imux->num_items].index = idx-1;
- imux->num_items++;
- }
- return 0;
+ static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
+ return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
+ ARRAY_SIZE(pin_idxs));
}
/* fill out digital output widgets; one for master and one for slave outputs */
@@ -4151,7 +4036,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
if (err < 0)
return err;
- err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+ err = vt1708S_auto_create_analog_input_ctls(codec, &spec->autocfg);
if (err < 0)
return err;
@@ -4441,58 +4326,20 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
imux = &spec->private_imux[1];
/* for hp mode select */
- i = 0;
- while (texts[i] != NULL) {
- imux->items[imux->num_items].label = texts[i];
- imux->items[imux->num_items].index = i;
- imux->num_items++;
- i++;
- }
+ for (i = 0; texts[i]; i++)
+ snd_hda_add_imux_item(imux, texts[i], i, NULL);
spec->hp_mux = &spec->private_imux[1];
return 0;
}
/* create playback/capture controls for input pins */
-static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
- static char *labels[] = {
- "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
- };
- struct hda_input_mux *imux = &spec->private_imux[0];
- int i, err, idx = 0;
-
- /* for internal loopback recording select */
- imux->items[imux->num_items].label = "Stereo Mixer";
- imux->items[imux->num_items].index = 3;
- imux->num_items++;
-
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- if (!cfg->input_pins[i])
- continue;
-
- switch (cfg->input_pins[i]) {
- case 0x14: /* Mic */
- idx = 1;
- break;
-
- case 0x15: /* Line In */
- idx = 2;
- break;
-
- case 0x18: /* Front Mic */
- idx = 3;
- break;
- }
- err = via_new_analog_input(spec, labels[i], idx, 0x1A);
- if (err < 0)
- return err;
- imux->items[imux->num_items].label = labels[i];
- imux->items[imux->num_items].index = idx-1;
- imux->num_items++;
- }
- return 0;
+ static hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff };
+ return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs,
+ ARRAY_SIZE(pin_idxs));
}
static int vt1702_parse_auto_config(struct hda_codec *codec)
@@ -4521,7 +4368,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
(0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
(0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
(1 << AC_AMPCAP_MUTE_SHIFT));
- err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
+ err = vt1702_auto_create_analog_input_ctls(codec, &spec->autocfg);
if (err < 0)
return err;
@@ -4872,49 +4719,12 @@ static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
}
/* create playback/capture controls for input pins */
-static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
- static char *labels[] = {
- "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
- };
- struct hda_input_mux *imux = &spec->private_imux[0];
- int i, err, idx = 0;
-
- /* for internal loopback recording select */
- imux->items[imux->num_items].label = "Stereo Mixer";
- imux->items[imux->num_items].index = 5;
- imux->num_items++;
-
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- if (!cfg->input_pins[i])
- continue;
-
- switch (cfg->input_pins[i]) {
- case 0x2b: /* Mic */
- idx = 1;
- break;
-
- case 0x2a: /* Line In */
- idx = 2;
- break;
-
- case 0x29: /* Front Mic */
- idx = 3;
- break;
-
- case 0x2c: /* CD */
- idx = 0;
- break;
- }
- err = via_new_analog_input(spec, labels[i], idx, 0x21);
- if (err < 0)
- return err;
- imux->items[imux->num_items].label = labels[i];
- imux->items[imux->num_items].index = idx;
- imux->num_items++;
- }
- return 0;
+ static hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff };
+ return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
+ ARRAY_SIZE(pin_idxs));
}
static int vt1718S_parse_auto_config(struct hda_codec *codec)
@@ -4938,7 +4748,7 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec)
err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
if (err < 0)
return err;
- err = vt1718S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+ err = vt1718S_auto_create_analog_input_ctls(codec, &spec->autocfg);
if (err < 0)
return err;
@@ -5371,49 +5181,12 @@ static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
}
/* create playback/capture controls for input pins */
-static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
- static char *labels[] = {
- "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
- };
- struct hda_input_mux *imux = &spec->private_imux[0];
- int i, err, idx = 0;
-
- /* for internal loopback recording select */
- imux->items[imux->num_items].label = "Stereo Mixer";
- imux->items[imux->num_items].index = 5;
- imux->num_items++;
-
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- if (!cfg->input_pins[i])
- continue;
-
- switch (cfg->input_pins[i]) {
- case 0x1a: /* Mic */
- idx = 2;
- break;
-
- case 0x1b: /* Line In */
- idx = 3;
- break;
-
- case 0x1e: /* Front Mic */
- idx = 4;
- break;
-
- case 0x1f: /* CD */
- idx = 1;
- break;
- }
- err = via_new_analog_input(spec, labels[i], idx, 0x16);
- if (err < 0)
- return err;
- imux->items[imux->num_items].label = labels[i];
- imux->items[imux->num_items].index = idx-1;
- imux->num_items++;
- }
- return 0;
+ static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
+ return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
+ ARRAY_SIZE(pin_idxs));
}
static int vt1716S_parse_auto_config(struct hda_codec *codec)
@@ -5436,7 +5209,7 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec)
err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
if (err < 0)
return err;
- err = vt1716S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+ err = vt1716S_auto_create_analog_input_ctls(codec, &spec->autocfg);
if (err < 0)
return err;
@@ -5717,54 +5490,25 @@ static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
}
/* create playback/capture controls for input pins */
-static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt2002P_auto_create_analog_input_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
- static char *labels[] = {
- "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
- };
+ struct via_spec *spec = codec->spec;
struct hda_input_mux *imux = &spec->private_imux[0];
- int i, err, idx = 0;
-
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- if (!cfg->input_pins[i])
- continue;
-
- switch (cfg->input_pins[i]) {
- case 0x2b: /* Mic */
- idx = 0;
- break;
-
- case 0x2a: /* Line In */
- idx = 1;
- break;
-
- case 0x29: /* Front Mic */
- idx = 2;
- break;
- }
- err = via_new_analog_input(spec, labels[i], idx, 0x21);
- if (err < 0)
- return err;
- imux->items[imux->num_items].label = labels[i];
- imux->items[imux->num_items].index = idx;
- imux->num_items++;
- }
+ static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff };
+ int err;
+ err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
+ ARRAY_SIZE(pin_idxs));
+ if (err < 0)
+ return err;
/* build volume/mute control of loopback */
- err = via_new_analog_input(spec, "Stereo Mixer", 3, 0x21);
+ err = via_new_analog_input(spec, "Stereo Mixer", 0, 3, 0x21);
if (err < 0)
return err;
- /* for internal loopback recording select */
- imux->items[imux->num_items].label = "Stereo Mixer";
- imux->items[imux->num_items].index = 3;
- imux->num_items++;
-
/* for digital mic select */
- imux->items[imux->num_items].label = "Digital Mic";
- imux->items[imux->num_items].index = 4;
- imux->num_items++;
+ snd_hda_add_imux_item(imux, "Digital Mic", 4, NULL);
return 0;
}
@@ -5792,7 +5536,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec)
err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
if (err < 0)
return err;
- err = vt2002P_auto_create_analog_input_ctls(spec, &spec->autocfg);
+ err = vt2002P_auto_create_analog_input_ctls(codec, &spec->autocfg);
if (err < 0)
return err;
@@ -6067,53 +5811,26 @@ static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
}
/* create playback/capture controls for input pins */
-static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1812_auto_create_analog_input_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
- static char *labels[] = {
- "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
- };
+ struct via_spec *spec = codec->spec;
struct hda_input_mux *imux = &spec->private_imux[0];
- int i, err, idx = 0;
-
- for (i = 0; i < AUTO_PIN_LAST; i++) {
- if (!cfg->input_pins[i])
- continue;
-
- switch (cfg->input_pins[i]) {
- case 0x2b: /* Mic */
- idx = 0;
- break;
+ static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff };
+ int err;
- case 0x2a: /* Line In */
- idx = 1;
- break;
+ err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
+ ARRAY_SIZE(pin_idxs));
+ if (err < 0)
+ return err;
- case 0x29: /* Front Mic */
- idx = 2;
- break;
- }
- err = via_new_analog_input(spec, labels[i], idx, 0x21);
- if (err < 0)
- return err;
- imux->items[imux->num_items].label = labels[i];
- imux->items[imux->num_items].index = idx;
- imux->num_items++;
- }
/* build volume/mute control of loopback */
- err = via_new_analog_input(spec, "Stereo Mixer", 5, 0x21);
+ err = via_new_analog_input(spec, "Stereo Mixer", 0, 5, 0x21);
if (err < 0)
return err;
- /* for internal loopback recording select */
- imux->items[imux->num_items].label = "Stereo Mixer";
- imux->items[imux->num_items].index = 5;
- imux->num_items++;
-
/* for digital mic select */
- imux->items[imux->num_items].label = "Digital Mic";
- imux->items[imux->num_items].index = 6;
- imux->num_items++;
+ snd_hda_add_imux_item(imux, "Digital Mic", 6, NULL);
return 0;
}
@@ -6141,7 +5858,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec)
err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
if (err < 0)
return err;
- err = vt1812_auto_create_analog_input_ctls(spec, &spec->autocfg);
+ err = vt1812_auto_create_analog_input_ctls(codec, &spec->autocfg);
if (err < 0)
return err;
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index d216362626d0..712c1710f9a2 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -563,6 +563,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
case ICE1712_SUBDEVICE_DELTA1010E:
case ICE1712_SUBDEVICE_DELTA1010LT:
case ICE1712_SUBDEVICE_MEDIASTATION:
+ case ICE1712_SUBDEVICE_EDIROLDA2496:
ice->num_total_dacs = 8;
ice->num_total_adcs = 8;
break;
@@ -635,6 +636,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
err = snd_ice1712_akm4xxx_init(ak, &akm_delta410, &akm_delta410_priv, ice);
break;
case ICE1712_SUBDEVICE_DELTA1010LT:
+ case ICE1712_SUBDEVICE_EDIROLDA2496:
err = snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, &akm_delta1010lt_priv, ice);
break;
case ICE1712_SUBDEVICE_DELTA66:
@@ -734,6 +736,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice)
case ICE1712_SUBDEVICE_DELTA66:
case ICE1712_SUBDEVICE_VX442:
case ICE1712_SUBDEVICE_DELTA66E:
+ case ICE1712_SUBDEVICE_EDIROLDA2496:
err = snd_ice1712_akm4xxx_build_controls(ice);
if (err < 0)
return err;
@@ -813,5 +816,12 @@ struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = {
.chip_init = snd_ice1712_delta_init,
.build_controls = snd_ice1712_delta_add_controls,
},
+ {
+ .subvendor = ICE1712_SUBDEVICE_EDIROLDA2496,
+ .name = "Edirol DA2496",
+ .model = "da2496",
+ .chip_init = snd_ice1712_delta_init,
+ .build_controls = snd_ice1712_delta_add_controls,
+ },
{ } /* terminator */
};
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h
index f7f14df81f26..1a0ac6cd6501 100644
--- a/sound/pci/ice1712/delta.h
+++ b/sound/pci/ice1712/delta.h
@@ -34,7 +34,8 @@
"{MidiMan M Audio,Delta 410},"\
"{MidiMan M Audio,Audiophile 24/96},"\
"{Digigram,VX442},"\
- "{Lionstracs,Mediastation},"
+ "{Lionstracs,Mediastation},"\
+ "{Edirol,DA2496},"
#define ICE1712_SUBDEVICE_DELTA1010 0x121430d6
#define ICE1712_SUBDEVICE_DELTA1010E 0xff1430d6
@@ -47,6 +48,7 @@
#define ICE1712_SUBDEVICE_DELTA1010LT 0x12143bd6
#define ICE1712_SUBDEVICE_VX442 0x12143cd6
#define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100
+#define ICE1712_SUBDEVICE_EDIROLDA2496 0xce164010
/* entry point */
extern struct snd_ice1712_card_info snd_ice1712_delta_cards[];
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
index 6bc3f91b7281..cdb873f5da50 100644
--- a/sound/pci/ice1712/pontis.c
+++ b/sound/pci/ice1712/pontis.c
@@ -638,7 +638,7 @@ static struct snd_kcontrol_new pontis_controls[] __devinitdata = {
*/
static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
- struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+ struct snd_ice1712 *ice = entry->private_data;
char line[64];
unsigned int reg, val;
mutex_lock(&ice->gpio_mutex);
@@ -653,7 +653,7 @@ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buf
static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
- struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+ struct snd_ice1712 *ice = entry->private_data;
int reg, val;
mutex_lock(&ice->gpio_mutex);
@@ -676,7 +676,7 @@ static void wm_proc_init(struct snd_ice1712 *ice)
static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
- struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+ struct snd_ice1712 *ice = entry->private_data;
int reg, val;
mutex_lock(&ice->gpio_mutex);
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c
index 2a8e5cd8f2d8..e36ddb94c382 100644
--- a/sound/pci/ice1712/prodigy192.c
+++ b/sound/pci/ice1712/prodigy192.c
@@ -654,7 +654,7 @@ static int prodigy192_ak4114_init(struct snd_ice1712 *ice)
static void stac9460_proc_regs_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+ struct snd_ice1712 *ice = entry->private_data;
int reg, val;
/* registers 0x0 - 0x14 */
for (reg = 0; reg <= 0x15; reg++) {
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 467749249576..400f9ebd243e 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -716,7 +716,7 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich
* Intel 82443MX running a 100MHz processor system bus has a hardware bug,
* which aborts PCI busmaster for audio transfer. A workaround is to set
* the pages as non-cached. For details, see the errata in
- * http://www.intel.com/design/chipsets/specupdt/245051.htm
+ * http://download.intel.com/design/chipsets/specupdt/24505108.pdf
*/
static void fill_nocache(void *buf, int size, int nocache)
{
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index 6c0a11adb2a8..98a8eb3c92f7 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -79,6 +79,7 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
{ OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF },
+ { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
@@ -505,7 +506,8 @@ static const struct oxygen_model model_generic = {
PLAYBACK_2_TO_AC97_1 |
CAPTURE_0_FROM_I2S_1 |
CAPTURE_1_FROM_SPDIF |
- CAPTURE_2_FROM_AC97_1,
+ CAPTURE_2_FROM_AC97_1 |
+ AC97_CD_INPUT,
.dac_channels = 8,
.dac_volume_min = 0,
.dac_volume_max = 255,
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index a3409edcfb50..7d5222caa0a9 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -34,6 +34,7 @@
/* CAPTURE_3_FROM_I2S_3 not implemented */
#define MIDI_OUTPUT 0x0800
#define MIDI_INPUT 0x1000
+#define AC97_CD_INPUT 0x2000
enum {
CONTROL_SPDIF_PCM,
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index 7e93cf884437..e5ebe56fb0c5 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -308,25 +308,46 @@ static void oxygen_restore_eeprom(struct oxygen *chip,
}
}
-static void pci_bridge_magic(void)
+static void configure_pcie_bridge(struct pci_dev *pci)
{
- struct pci_dev *pci = NULL;
+ enum { PEX811X, PI7C9X110 };
+ static const struct pci_device_id bridge_ids[] = {
+ { PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X },
+ { PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X },
+ { PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 },
+ { }
+ };
+ struct pci_dev *bridge;
+ const struct pci_device_id *id;
u32 tmp;
- for (;;) {
- /* If there is any Pericom PI7C9X110 PCI-E/PCI bridge ... */
- pci = pci_get_device(0x12d8, 0xe110, pci);
- if (!pci)
- break;
- /*
- * ... configure its secondary internal arbiter to park to
- * the secondary port, instead of to the last master.
- */
- if (!pci_read_config_dword(pci, 0x40, &tmp)) {
- tmp |= 1;
- pci_write_config_dword(pci, 0x40, tmp);
- }
- /* Why? Try asking C-Media. */
+ if (!pci->bus || !pci->bus->self)
+ return;
+ bridge = pci->bus->self;
+
+ id = pci_match_id(bridge_ids, bridge);
+ if (!id)
+ return;
+
+ switch (id->driver_data) {
+ case PEX811X: /* PLX PEX8111/PEX8112 PCIe/PCI bridge */
+ pci_read_config_dword(bridge, 0x48, &tmp);
+ tmp |= 1; /* enable blind prefetching */
+ tmp |= 1 << 11; /* enable beacon generation */
+ pci_write_config_dword(bridge, 0x48, tmp);
+
+ pci_write_config_dword(bridge, 0x84, 0x0c);
+ pci_read_config_dword(bridge, 0x88, &tmp);
+ tmp &= ~(7 << 27);
+ tmp |= 2 << 27; /* set prefetch size to 128 bytes */
+ pci_write_config_dword(bridge, 0x88, tmp);
+ break;
+
+ case PI7C9X110: /* Pericom PI7C9X110 PCIe/PCI bridge */
+ pci_read_config_dword(bridge, 0x40, &tmp);
+ tmp |= 1; /* park the PCI arbiter to the sound chip */
+ pci_write_config_dword(bridge, 0x40, tmp);
+ break;
}
}
@@ -613,7 +634,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
snd_card_set_dev(card, &pci->dev);
card->private_free = oxygen_card_free;
- pci_bridge_magic();
+ configure_pcie_bridge(pci);
oxygen_init(chip);
chip->model.init(chip);
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index f375b8a27862..2849b36f5f7e 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -708,7 +708,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl,
.private_value = ((codec) << 24) | ((stereo) << 16) | (index), \
}
-static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0);
+static DECLARE_TLV_DB_SCALE(monitor_db_scale, -600, 600, 0);
static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0);
static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0);
@@ -972,6 +972,9 @@ static int add_controls(struct oxygen *chip,
if (!strcmp(template.name, "Stereo Upmixing") &&
chip->model.dac_channels == 2)
continue;
+ if (!strncmp(template.name, "CD Capture ", 11) &&
+ !(chip->model.device_config & AC97_CD_INPUT))
+ continue;
if (!strcmp(template.name, "Master Playback Volume") &&
chip->model.dac_tlv) {
template.tlv.p = chip->model.dac_tlv;
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index 9dff6954c397..814667442eb0 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -56,8 +56,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = {
.channels_max = 2,
.buffer_bytes_max = BUFFER_BYTES_MAX,
.period_bytes_min = PERIOD_BYTES_MIN,
- .period_bytes_max = BUFFER_BYTES_MAX / 2,
- .periods_min = 2,
+ .period_bytes_max = BUFFER_BYTES_MAX,
+ .periods_min = 1,
.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
};
static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
@@ -82,8 +82,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
.channels_max = 8,
.buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH,
.period_bytes_min = PERIOD_BYTES_MIN,
- .period_bytes_max = BUFFER_BYTES_MAX_MULTICH / 2,
- .periods_min = 2,
+ .period_bytes_max = BUFFER_BYTES_MAX_MULTICH,
+ .periods_min = 1,
.periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN,
};
static const struct snd_pcm_hardware oxygen_ac97_hardware = {
@@ -100,8 +100,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = {
.channels_max = 2,
.buffer_bytes_max = BUFFER_BYTES_MAX,
.period_bytes_min = PERIOD_BYTES_MIN,
- .period_bytes_max = BUFFER_BYTES_MAX / 2,
- .periods_min = 2,
+ .period_bytes_max = BUFFER_BYTES_MAX,
+ .periods_min = 1,
.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
};
diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h
index 72de159d4567..4dcd41b78258 100644
--- a/sound/pci/oxygen/oxygen_regs.h
+++ b/sound/pci/oxygen/oxygen_regs.h
@@ -436,13 +436,15 @@
/* OXYGEN_CHANNEL_* */
#define OXYGEN_CODEC_VERSION 0xe4
-#define OXYGEN_XCID_MASK 0x07
+#define OXYGEN_CODEC_ID_MASK 0x07
#define OXYGEN_REVISION 0xe6
-#define OXYGEN_REVISION_XPKGID_MASK 0x0007
+#define OXYGEN_PACKAGE_ID_MASK 0x0007
+#define OXYGEN_PACKAGE_ID_8786 0x0004
+#define OXYGEN_PACKAGE_ID_8787 0x0006
+#define OXYGEN_PACKAGE_ID_8788 0x0007
#define OXYGEN_REVISION_MASK 0xfff8
-#define OXYGEN_REVISION_2 0x0008 /* bit flag */
-#define OXYGEN_REVISION_8787 0x0014 /* 8 bits */
+#define OXYGEN_REVISION_2 0x0008
#define OXYGEN_OFFSIN_48K 0xe8
#define OXYGEN_OFFSBASE_48K 0xe9
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index 06c863e86e3d..469010a8b849 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -25,9 +25,9 @@
#include "xonar.h"
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_DESCRIPTION("Asus AVx00 driver");
+MODULE_DESCRIPTION("Asus Virtuoso driver");
MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}");
+MODULE_SUPPORTED_DEVICE("{{Asus,AV66},{Asus,AV100},{Asus,AV200}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
@@ -49,6 +49,7 @@ static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = {
{ OXYGEN_PCI_SUBID(0x1043, 0x834f) },
{ OXYGEN_PCI_SUBID(0x1043, 0x835c) },
{ OXYGEN_PCI_SUBID(0x1043, 0x835d) },
+ { OXYGEN_PCI_SUBID(0x1043, 0x835e) },
{ OXYGEN_PCI_SUBID(0x1043, 0x838e) },
{ OXYGEN_PCI_SUBID_BROKEN_EEPROM },
{ }
diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c
index 7c4986b27f2b..aa27c31049af 100644
--- a/sound/pci/oxygen/xonar_cs43xx.c
+++ b/sound/pci/oxygen/xonar_cs43xx.c
@@ -367,13 +367,6 @@ static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip,
static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0);
-static int xonar_d1_control_filter(struct snd_kcontrol_new *template)
-{
- if (!strncmp(template->name, "CD Capture ", 11))
- return 1; /* no CD input */
- return 0;
-}
-
static int xonar_d1_mixer_init(struct oxygen *chip)
{
int err;
@@ -391,7 +384,6 @@ static const struct oxygen_model model_xonar_d1 = {
.longname = "Asus Virtuoso 100",
.chip = "AV200",
.init = xonar_d1_init,
- .control_filter = xonar_d1_control_filter,
.mixer_init = xonar_d1_mixer_init,
.cleanup = xonar_d1_cleanup,
.suspend = xonar_d1_suspend,
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c
index ba18fb546b4f..d491fd6c0be2 100644
--- a/sound/pci/oxygen/xonar_pcm179x.c
+++ b/sound/pci/oxygen/xonar_pcm179x.c
@@ -132,6 +132,18 @@
* GPIO 5 <- 0
*/
+/*
+ * Xonar HDAV1.3 Slim
+ * ------------------
+ *
+ * CMI8788:
+ *
+ * GPIO 1 -> enable output
+ *
+ * TXD -> HDMI controller
+ * RXD <- HDMI controller
+ */
+
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/mutex.h>
@@ -362,7 +374,6 @@ static void xonar_st_init_common(struct oxygen *chip)
{
struct xonar_pcm179x *data = chip->model_data;
- data->generic.anti_pop_delay = 100;
data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
data->dacs = chip->model.private_data ? 4 : 1;
data->hp_gain_offset = 2*-18;
@@ -408,6 +419,7 @@ static void xonar_st_init(struct oxygen *chip)
{
struct xonar_pcm179x *data = chip->model_data;
+ data->generic.anti_pop_delay = 100;
data->has_cs2000 = 1;
data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1;
@@ -428,6 +440,7 @@ static void xonar_stx_init(struct oxygen *chip)
struct xonar_pcm179x *data = chip->model_data;
xonar_st_init_i2c(chip);
+ data->generic.anti_pop_delay = 800;
data->generic.ext_power_reg = OXYGEN_GPI_DATA;
data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
data->generic.ext_power_bit = GPI_EXT_POWER;
@@ -915,13 +928,6 @@ static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
return 0;
}
-static int xonar_st_control_filter(struct snd_kcontrol_new *template)
-{
- if (!strncmp(template->name, "CD Capture ", 11))
- return 1; /* no CD input */
- return 0;
-}
-
static int add_pcm1796_controls(struct oxygen *chip)
{
int err;
@@ -991,7 +997,8 @@ static const struct oxygen_model model_xonar_d2 = {
CAPTURE_0_FROM_I2S_2 |
CAPTURE_1_FROM_SPDIF |
MIDI_OUTPUT |
- MIDI_INPUT,
+ MIDI_INPUT |
+ AC97_CD_INPUT,
.dac_channels = 8,
.dac_volume_min = 255 - 2*60,
.dac_volume_max = 255,
@@ -1037,7 +1044,6 @@ static const struct oxygen_model model_xonar_st = {
.longname = "Asus Virtuoso 100",
.chip = "AV200",
.init = xonar_st_init,
- .control_filter = xonar_st_control_filter,
.mixer_init = xonar_st_mixer_init,
.cleanup = xonar_st_cleanup,
.suspend = xonar_st_suspend,
@@ -1108,6 +1114,9 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
chip->model.resume = xonar_stx_resume;
chip->model.set_dac_params = set_pcm1796_params;
break;
+ case 0x835e:
+ snd_printk(KERN_ERR "the HDAV1.3 Slim is not supported\n");
+ return -ENODEV;
default:
return -EINVAL;
}
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c
index b82c1cfa96f5..200f7601276f 100644
--- a/sound/pci/oxygen/xonar_wm87x6.c
+++ b/sound/pci/oxygen/xonar_wm87x6.c
@@ -25,16 +25,24 @@
* SPI 0 -> WM8766 (surround, center/LFE, back)
* SPI 1 -> WM8776 (front, input)
*
- * GPIO 4 <- headphone detect
- * GPIO 6 -> route input jack to input 1/2 (1/0)
- * GPIO 7 -> enable output to speakers
- * GPIO 8 -> enable output to speakers
+ * GPIO 4 <- headphone detect, 0 = plugged
+ * GPIO 6 -> route input jack to mic-in (0) or line-in (1)
+ * GPIO 7 -> enable output to front L/R speaker channels
+ * GPIO 8 -> enable output to other speaker channels and front panel headphone
+ *
+ * WM8766:
+ *
+ * input 1 <- line
+ * input 2 <- mic
+ * input 3 <- front mic
+ * input 4 <- aux
*/
#include <linux/pci.h>
#include <linux/delay.h>
#include <sound/control.h>
#include <sound/core.h>
+#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
@@ -44,7 +52,8 @@
#define GPIO_DS_HP_DETECT 0x0010
#define GPIO_DS_INPUT_ROUTE 0x0040
-#define GPIO_DS_OUTPUT_ENABLE 0x0180
+#define GPIO_DS_OUTPUT_FRONTLR 0x0080
+#define GPIO_DS_OUTPUT_ENABLE 0x0100
#define LC_CONTROL_LIMITER 0x40000000
#define LC_CONTROL_ALC 0x20000000
@@ -56,6 +65,7 @@ struct xonar_wm87x6 {
struct snd_kcontrol *line_adcmux_control;
struct snd_kcontrol *mic_adcmux_control;
struct snd_kcontrol *lc_controls[13];
+ struct snd_jack *hp_jack;
};
static void wm8776_write(struct oxygen *chip,
@@ -97,8 +107,12 @@ static void wm8766_write(struct oxygen *chip,
(0 << OXYGEN_SPI_CODEC_SHIFT) |
OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
(reg << 9) | value);
- if (reg < ARRAY_SIZE(data->wm8766_regs))
+ if (reg < ARRAY_SIZE(data->wm8766_regs)) {
+ if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
+ (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
+ value &= ~WM8766_UPDATE;
data->wm8766_regs[reg] = value;
+ }
}
static void wm8766_write_cached(struct oxygen *chip,
@@ -107,12 +121,8 @@ static void wm8766_write_cached(struct oxygen *chip,
struct xonar_wm87x6 *data = chip->model_data;
if (reg >= ARRAY_SIZE(data->wm8766_regs) ||
- value != data->wm8766_regs[reg]) {
- if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
- (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
- value &= ~WM8766_UPDATE;
+ value != data->wm8766_regs[reg])
wm8766_write(chip, reg, value);
- }
}
static void wm8776_registers_init(struct oxygen *chip)
@@ -141,7 +151,10 @@ static void wm8776_registers_init(struct oxygen *chip)
static void wm8766_registers_init(struct oxygen *chip)
{
+ struct xonar_wm87x6 *data = chip->model_data;
+
wm8766_write(chip, WM8766_RESET, 0);
+ wm8766_write(chip, WM8766_DAC_CTRL, data->wm8766_regs[WM8766_DAC_CTRL]);
wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24);
wm8766_write(chip, WM8766_DAC_CTRL2,
WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
@@ -170,6 +183,40 @@ static void wm8776_init(struct oxygen *chip)
wm8776_registers_init(chip);
}
+static void wm8766_init(struct oxygen *chip)
+{
+ struct xonar_wm87x6 *data = chip->model_data;
+
+ data->wm8766_regs[WM8766_DAC_CTRL] =
+ WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
+ wm8766_registers_init(chip);
+}
+
+static void xonar_ds_handle_hp_jack(struct oxygen *chip)
+{
+ struct xonar_wm87x6 *data = chip->model_data;
+ bool hp_plugged;
+ unsigned int reg;
+
+ mutex_lock(&chip->mutex);
+
+ hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
+ GPIO_DS_HP_DETECT);
+
+ oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+ hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR,
+ GPIO_DS_OUTPUT_FRONTLR);
+
+ reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL;
+ if (hp_plugged)
+ reg |= WM8766_MUTEALL;
+ wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
+
+ snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0);
+
+ mutex_unlock(&chip->mutex);
+}
+
static void xonar_ds_init(struct oxygen *chip)
{
struct xonar_wm87x6 *data = chip->model_data;
@@ -178,16 +225,22 @@ static void xonar_ds_init(struct oxygen *chip)
data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE;
wm8776_init(chip);
- wm8766_registers_init(chip);
+ wm8766_init(chip);
- oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE,
- GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE);
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+ GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR);
+ oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
+ GPIO_DS_HP_DETECT);
oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE);
oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT);
chip->interrupt_mask |= OXYGEN_INT_GPIO;
xonar_enable_output(chip);
+ snd_jack_new(chip->card, "Headphone",
+ SND_JACK_HEADPHONE, &data->hp_jack);
+ xonar_ds_handle_hp_jack(chip);
+
snd_component_add(chip->card, "WM8776");
snd_component_add(chip->card, "WM8766");
}
@@ -208,6 +261,7 @@ static void xonar_ds_resume(struct oxygen *chip)
wm8776_registers_init(chip);
wm8766_registers_init(chip);
xonar_enable_output(chip);
+ xonar_ds_handle_hp_jack(chip);
}
static void wm8776_adc_hardware_filter(unsigned int channel,
@@ -323,12 +377,27 @@ static void update_wm87x6_mute(struct oxygen *chip)
(chip->dac_mute ? WM8766_DMUTE_MASK : 0));
}
-static void xonar_ds_gpio_changed(struct oxygen *chip)
+static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed)
{
- u16 bits;
+ struct xonar_wm87x6 *data = chip->model_data;
+ unsigned int reg;
- bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
- snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT));
+ /*
+ * The WM8766 can mix left and right channels, but this setting
+ * applies to all three stereo pairs.
+ */
+ reg = data->wm8766_regs[WM8766_DAC_CTRL] &
+ ~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK);
+ if (mixed)
+ reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX;
+ else
+ reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
+ wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
+}
+
+static void xonar_ds_gpio_changed(struct oxygen *chip)
+{
+ xonar_ds_handle_hp_jack(chip);
}
static int wm8776_bit_switch_get(struct snd_kcontrol *ctl,
@@ -896,7 +965,10 @@ static const struct snd_kcontrol_new ds_controls[] = {
.put = wm8776_input_mux_put,
.private_value = 1 << 1,
},
- WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0),
+ WM8776_BIT_SWITCH("Front Mic Capture Switch",
+ WM8776_ADCMUX, 1 << 2, 0, 0),
+ WM8776_BIT_SWITCH("Aux Capture Switch",
+ WM8776_ADCMUX, 1 << 3, 0, 0),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "ADC Filter Capture Enum",
@@ -956,13 +1028,6 @@ static const struct snd_kcontrol_new lc_controls[] = {
LC_CONTROL_ALC, wm8776_ngth_db_scale),
};
-static int xonar_ds_control_filter(struct snd_kcontrol_new *template)
-{
- if (!strncmp(template->name, "CD Capture ", 11))
- return 1; /* no CD input */
- return 0;
-}
-
static int xonar_ds_mixer_init(struct oxygen *chip)
{
struct xonar_wm87x6 *data = chip->model_data;
@@ -999,10 +1064,9 @@ static int xonar_ds_mixer_init(struct oxygen *chip)
static const struct oxygen_model model_xonar_ds = {
.shortname = "Xonar DS",
- .longname = "Asus Virtuoso 200",
+ .longname = "Asus Virtuoso 66",
.chip = "AV200",
.init = xonar_ds_init,
- .control_filter = xonar_ds_control_filter,
.mixer_init = xonar_ds_mixer_init,
.cleanup = xonar_ds_cleanup,
.suspend = xonar_ds_suspend,
@@ -1013,6 +1077,7 @@ static const struct oxygen_model model_xonar_ds = {
.set_adc_params = set_wm8776_adc_params,
.update_dac_volume = update_wm87x6_volume,
.update_dac_mute = update_wm87x6_mute,
+ .update_center_lfe_mix = update_wm8766_center_lfe_mix,
.gpio_changed = xonar_ds_gpio_changed,
.dac_tlv = wm87x6_dac_db_scale,
.model_data_size = sizeof(struct xonar_wm87x6),
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index d19dc052c391..d5f5b440fc40 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -1527,14 +1527,14 @@ snd_rme96_free(void *private_data)
static void
snd_rme96_free_spdif_pcm(struct snd_pcm *pcm)
{
- struct rme96 *rme96 = (struct rme96 *) pcm->private_data;
+ struct rme96 *rme96 = pcm->private_data;
rme96->spdif_pcm = NULL;
}
static void
snd_rme96_free_adat_pcm(struct snd_pcm *pcm)
{
- struct rme96 *rme96 = (struct rme96 *) pcm->private_data;
+ struct rme96 *rme96 = pcm->private_data;
rme96->adat_pcm = NULL;
}
@@ -1661,7 +1661,7 @@ static void
snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
int n;
- struct rme96 *rme96 = (struct rme96 *)entry->private_data;
+ struct rme96 *rme96 = entry->private_data;
rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
@@ -2348,7 +2348,7 @@ snd_rme96_probe(struct pci_dev *pci,
if (err < 0)
return err;
card->private_free = snd_rme96_card_free;
- rme96 = (struct rme96 *)card->private_data;
+ rme96 = card->private_data;
rme96->card = card;
rme96->pci = pci;
snd_card_set_dev(card, &pci->dev);
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index d6fa7bfd9aa1..0b720cf7783e 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -3284,7 +3284,7 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
static void
snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
- struct hdsp *hdsp = (struct hdsp *) entry->private_data;
+ struct hdsp *hdsp = entry->private_data;
unsigned int status;
unsigned int status2;
char *pref_sync_ref;
@@ -4566,7 +4566,7 @@ static int hdsp_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rm
static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
{
- struct hdsp *hdsp = (struct hdsp *)hw->private_data;
+ struct hdsp *hdsp = hw->private_data;
void __user *argp = (void __user *)arg;
int err;
@@ -5156,7 +5156,7 @@ static int snd_hdsp_free(struct hdsp *hdsp)
static void snd_hdsp_card_free(struct snd_card *card)
{
- struct hdsp *hdsp = (struct hdsp *) card->private_data;
+ struct hdsp *hdsp = card->private_data;
if (hdsp)
snd_hdsp_free(hdsp);
@@ -5182,7 +5182,7 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci,
if (err < 0)
return err;
- hdsp = (struct hdsp *) card->private_data;
+ hdsp = card->private_data;
card->private_free = snd_hdsp_card_free;
hdsp->dev = dev;
hdsp->pci = pci;
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 20afdf9772ee..961d98297695 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -785,7 +785,7 @@ static int snapper_set_capture_source(struct pmac_tumbler *mix)
if (! mix->i2c.client)
return -ENODEV;
if (mix->capture_source)
- mix->acs = mix->acs |= 2;
+ mix->acs |= 2;
else
mix->acs &= ~2;
return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs);
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
index dc5249fba85c..d0e75323ec19 100644
--- a/sound/soc/atmel/atmel-pcm.c
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -179,7 +179,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
runtime->dma_bytes = params_buffer_bytes(params);
- prtd->params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
prtd->dma_buffer = runtime->dma_addr;
@@ -374,14 +374,14 @@ static int atmel_pcm_new(struct snd_card *card,
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = 0xffffffff;
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = atmel_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
pr_debug("at32-pcm:"
"Allocating PCM capture DMA buffer\n");
ret = atmel_pcm_preallocate_dma_buffer(pcm,
@@ -414,12 +414,9 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm)
}
#ifdef CONFIG_PM
-static int atmel_pcm_suspend(struct snd_soc_dai_link *dai_link)
+static int atmel_pcm_suspend(struct snd_soc_dai *dai)
{
- struct snd_pcm *pcm = dai_link->pcm;
- struct snd_pcm_str *stream = &pcm->streams[0];
- struct snd_pcm_substream *substream = stream->substream;
- struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = dai->runtime;
struct atmel_runtime_data *prtd;
struct atmel_pcm_dma_params *params;
@@ -441,12 +438,9 @@ static int atmel_pcm_suspend(struct snd_soc_dai_link *dai_link)
return 0;
}
-static int atmel_pcm_resume(struct snd_soc_dai_link *dai_link)
+static int atmel_pcm_resume(struct snd_soc_dai *dai)
{
- struct snd_pcm *pcm = dai_link->pcm;
- struct snd_pcm_str *stream = &pcm->streams[0];
- struct snd_pcm_substream *substream = stream->substream;
- struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = dai->runtime;
struct atmel_runtime_data *prtd;
struct atmel_pcm_dma_params *params;
@@ -470,27 +464,46 @@ static int atmel_pcm_resume(struct snd_soc_dai_link *dai_link)
#define atmel_pcm_resume NULL
#endif
-struct snd_soc_platform atmel_soc_platform = {
- .name = "atmel-audio",
- .pcm_ops = &atmel_pcm_ops,
+static struct snd_soc_platform_driver atmel_soc_platform = {
+ .ops = &atmel_pcm_ops,
.pcm_new = atmel_pcm_new,
.pcm_free = atmel_pcm_free_dma_buffers,
.suspend = atmel_pcm_suspend,
.resume = atmel_pcm_resume,
};
-EXPORT_SYMBOL_GPL(atmel_soc_platform);
-static int __init atmel_pcm_modinit(void)
+static int __devinit atmel_soc_platform_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_platform(&pdev->dev, &atmel_soc_platform);
+}
+
+static int __devexit atmel_soc_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver atmel_pcm_driver = {
+ .driver = {
+ .name = "atmel-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = atmel_soc_platform_probe,
+ .remove = __devexit_p(atmel_soc_platform_remove),
+};
+
+static int __init snd_atmel_pcm_init(void)
{
- return snd_soc_register_platform(&atmel_soc_platform);
+ return platform_driver_register(&atmel_pcm_driver);
}
-module_init(atmel_pcm_modinit);
+module_init(snd_atmel_pcm_init);
-static void __exit atmel_pcm_modexit(void)
+static void __exit snd_atmel_pcm_exit(void)
{
- snd_soc_unregister_platform(&atmel_soc_platform);
+ platform_driver_unregister(&atmel_pcm_driver);
}
-module_exit(atmel_pcm_modexit);
+module_exit(snd_atmel_pcm_exit);
MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
MODULE_DESCRIPTION("Atmel PCM module");
diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h
index ec9b2824b663..2597329302e7 100644
--- a/sound/soc/atmel/atmel-pcm.h
+++ b/sound/soc/atmel/atmel-pcm.h
@@ -74,9 +74,6 @@ struct atmel_pcm_dma_params {
void (*dma_intr_handler)(u32, struct snd_pcm_substream *);
};
-extern struct snd_soc_platform atmel_soc_platform;
-
-
/*
* SSC register access (since ssc_writel() / ssc_readl() require literal name)
*/
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index c85844d4845b..5d230cee3fa7 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -205,8 +205,7 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
static int atmel_ssc_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+ struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
int dir_mask;
pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
@@ -235,8 +234,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+ struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
struct atmel_pcm_dma_params *dma_params;
int dir, dir_mask;
@@ -338,7 +336,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- int id = rtd->dai->cpu_dai->id;
+ int id = dai->id;
struct atmel_ssc_info *ssc_p = &ssc_info[id];
struct atmel_pcm_dma_params *dma_params;
int dir, channels, bits;
@@ -368,7 +366,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
* function. It should not be used for other purposes
* as it is common to all substreams.
*/
- snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream, dma_params);
+ snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params);
channels = params_channels(params);
@@ -605,8 +603,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+ struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
struct atmel_pcm_dma_params *dma_params;
int dir;
@@ -690,6 +687,32 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
# define atmel_ssc_resume NULL
#endif /* CONFIG_PM */
+static int atmel_ssc_probe(struct snd_soc_dai *dai)
+{
+ struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
+ int ret = 0;
+
+ snd_soc_dai_set_drvdata(dai, ssc_p);
+
+ /*
+ * Request SSC device
+ */
+ ssc_p->ssc = ssc_request(dai->id);
+ if (IS_ERR(ssc_p->ssc)) {
+ printk(KERN_ERR "ASoC: Failed to request SSC %d\n", dai->id);
+ ret = PTR_ERR(ssc_p->ssc);
+ }
+
+ return ret;
+}
+
+static int atmel_ssc_remove(struct snd_soc_dai *dai)
+{
+ struct atmel_ssc_info *ssc_p = snd_soc_dai_get_drvdata(dai);
+
+ ssc_free(ssc_p->ssc);
+ return 0;
+}
#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
@@ -705,9 +728,11 @@ static struct snd_soc_dai_ops atmel_ssc_dai_ops = {
.set_clkdiv = atmel_ssc_set_dai_clkdiv,
};
-struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
- { .name = "atmel-ssc0",
- .id = 0,
+static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
+ {
+ .name = "atmel-ssc-dai.0",
+ .probe = atmel_ssc_probe,
+ .remove = atmel_ssc_remove,
.suspend = atmel_ssc_suspend,
.resume = atmel_ssc_resume,
.playback = {
@@ -721,11 +746,12 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
.rates = ATMEL_SSC_RATES,
.formats = ATMEL_SSC_FORMATS,},
.ops = &atmel_ssc_dai_ops,
- .private_data = &ssc_info[0],
},
#if NUM_SSC_DEVICES == 3
- { .name = "atmel-ssc1",
- .id = 1,
+ {
+ .name = "atmel-ssc-dai.1",
+ .probe = atmel_ssc_probe,
+ .remove = atmel_ssc_remove,
.suspend = atmel_ssc_suspend,
.resume = atmel_ssc_resume,
.playback = {
@@ -739,10 +765,11 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
.rates = ATMEL_SSC_RATES,
.formats = ATMEL_SSC_FORMATS,},
.ops = &atmel_ssc_dai_ops,
- .private_data = &ssc_info[1],
},
- { .name = "atmel-ssc2",
- .id = 2,
+ {
+ .name = "atmel-ssc-dai.2",
+ .probe = atmel_ssc_probe,
+ .remove = atmel_ssc_remove,
.suspend = atmel_ssc_suspend,
.resume = atmel_ssc_resume,
.playback = {
@@ -756,23 +783,94 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
.rates = ATMEL_SSC_RATES,
.formats = ATMEL_SSC_FORMATS,},
.ops = &atmel_ssc_dai_ops,
- .private_data = &ssc_info[2],
},
#endif
};
-EXPORT_SYMBOL_GPL(atmel_ssc_dai);
-static int __init atmel_ssc_modinit(void)
+static __devinit int asoc_ssc_probe(struct platform_device *pdev)
+{
+ BUG_ON(pdev->id < 0);
+ BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai));
+ return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]);
+}
+
+static int __devexit asoc_ssc_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver asoc_ssc_driver = {
+ .driver = {
+ .name = "atmel-ssc-dai",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = asoc_ssc_probe,
+ .remove = __devexit_p(asoc_ssc_remove),
+};
+
+/**
+ * atmel_ssc_set_audio - Allocate the specified SSC for audio use.
+ */
+int atmel_ssc_set_audio(int ssc_id)
+{
+ struct ssc_device *ssc;
+ static struct platform_device *dma_pdev;
+ struct platform_device *ssc_pdev;
+ int ret;
+
+ if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai))
+ return -EINVAL;
+
+ /* Allocate a dummy device for DMA if we don't have one already */
+ if (!dma_pdev) {
+ dma_pdev = platform_device_alloc("atmel-pcm-audio", -1);
+ if (!dma_pdev)
+ return -ENOMEM;
+
+ ret = platform_device_add(dma_pdev);
+ if (ret < 0) {
+ platform_device_put(dma_pdev);
+ dma_pdev = NULL;
+ return ret;
+ }
+ }
+
+ ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
+ if (!ssc_pdev) {
+ ssc_free(ssc);
+ return -ENOMEM;
+ }
+
+ /* If we can grab the SSC briefly to parent the DAI device off it */
+ ssc = ssc_request(ssc_id);
+ if (IS_ERR(ssc))
+ pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n",
+ PTR_ERR(ssc));
+ else
+ ssc_pdev->dev.parent = &(ssc->pdev->dev);
+ ssc_free(ssc);
+
+ ret = platform_device_add(ssc_pdev);
+ if (ret < 0)
+ platform_device_put(ssc_pdev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);
+
+static int __init snd_atmel_ssc_init(void)
{
- return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
+ return platform_driver_register(&asoc_ssc_driver);
}
-module_init(atmel_ssc_modinit);
+module_init(snd_atmel_ssc_init);
-static void __exit atmel_ssc_modexit(void)
+static void __exit snd_atmel_ssc_exit(void)
{
- snd_soc_unregister_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
+ platform_driver_unregister(&asoc_ssc_driver);
}
-module_exit(atmel_ssc_modexit);
+module_exit(snd_atmel_ssc_exit);
/* Module information */
MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com");
diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h
index 391135f9c6c1..5d4f0f9b4d9a 100644
--- a/sound/soc/atmel/atmel_ssc_dai.h
+++ b/sound/soc/atmel/atmel_ssc_dai.h
@@ -116,6 +116,7 @@ struct atmel_ssc_info {
struct atmel_pcm_dma_params *dma_params[2];
struct atmel_ssc_state ssc_state;
};
-extern struct snd_soc_dai atmel_ssc_dai[];
+
+int atmel_ssc_set_audio(int ssc);
#endif /* _AT91_SSC_DAI_H */
diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c
index 9df4c68ef000..5f4e59f4461c 100644
--- a/sound/soc/atmel/playpaq_wm8510.c
+++ b/sound/soc/atmel/playpaq_wm8510.c
@@ -83,7 +83,7 @@ static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock(
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct at32_ssc_info *ssc_p = cpu_dai->private_data;
+ struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
struct ssc_device *ssc = ssc_p->ssc;
struct ssc_clock_data cd;
unsigned int rate, width_bits, channels;
@@ -131,9 +131,9 @@ static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct at32_ssc_info *ssc_p = cpu_dai->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
struct ssc_device *ssc = ssc_p->ssc;
unsigned int pll_out = 0, bclk = 0, mclk_div = 0;
int ret;
@@ -315,8 +315,9 @@ static const struct snd_soc_dapm_route intercon[] = {
-static int playpaq_wm8510_init(struct snd_soc_codec *codec)
+static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int i;
/*
@@ -342,7 +343,7 @@ static int playpaq_wm8510_init(struct snd_soc_codec *codec)
/* Make CSB show PLL rate */
- snd_soc_dai_set_clkdiv(codec->dai, WM8510_OPCLKDIV,
+ snd_soc_dai_set_clkdiv(rtd->codec_dai, WM8510_OPCLKDIV,
WM8510_OPCLKDIV_1 | 4);
return 0;
@@ -353,8 +354,10 @@ static int playpaq_wm8510_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link playpaq_wm8510_dai = {
.name = "WM8510",
.stream_name = "WM8510 PCM",
- .cpu_dai = &at32_ssc_dai[0],
- .codec_dai = &wm8510_dai,
+ .cpu_dai_name= "atmel-ssc-dai.0",
+ .platform_name = "atmel-pcm-audio",
+ .codec_name = "wm8510-codec.0-0x1a",
+ .codec_dai_name = "wm8510-hifi",
.init = playpaq_wm8510_init,
.ops = &playpaq_wm8510_ops,
};
@@ -363,46 +366,16 @@ static struct snd_soc_dai_link playpaq_wm8510_dai = {
static struct snd_soc_card snd_soc_playpaq = {
.name = "LRS_PlayPaq_WM8510",
- .platform = &at32_soc_platform,
.dai_link = &playpaq_wm8510_dai,
.num_links = 1,
};
-
-
-static struct wm8510_setup_data playpaq_wm8510_setup = {
- .i2c_bus = 0,
- .i2c_address = 0x1a,
-};
-
-
-
-static struct snd_soc_device playpaq_wm8510_snd_devdata = {
- .card = &snd_soc_playpaq,
- .codec_dev = &soc_codec_dev_wm8510,
- .codec_data = &playpaq_wm8510_setup,
-};
-
static struct platform_device *playpaq_snd_device;
static int __init playpaq_asoc_init(void)
{
int ret = 0;
- struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
- struct ssc_device *ssc = NULL;
-
-
- /*
- * Request SSC device
- */
- ssc = ssc_request(0);
- if (IS_ERR(ssc)) {
- ret = PTR_ERR(ssc);
- goto err_ssc;
- }
- ssc_p->ssc = ssc;
-
/*
* Configure MCLK for WM8510
@@ -439,8 +412,7 @@ static int __init playpaq_asoc_init(void)
goto err_device_alloc;
}
- platform_set_drvdata(playpaq_snd_device, &playpaq_wm8510_snd_devdata);
- playpaq_wm8510_snd_devdata.dev = &playpaq_snd_device->dev;
+ platform_set_drvdata(playpaq_snd_device, &snd_soc_playpaq);
ret = platform_device_add(playpaq_snd_device);
if (ret) {
@@ -468,25 +440,12 @@ err_pll0:
clk_put(_gclk0);
_gclk0 = NULL;
}
-err_gclk0:
- ssc_free(ssc);
-err_ssc:
return ret;
}
static void __exit playpaq_asoc_exit(void)
{
- struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
- struct ssc_device *ssc;
-
- if (ssc_p != NULL) {
- ssc = ssc_p->ssc;
- if (ssc != NULL)
- ssc_free(ssc);
- ssc_p->ssc = NULL;
- }
-
if (_gclk0 != NULL) {
clk_put(_gclk0);
_gclk0 = NULL;
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index e028744c32ce..293569dfd0ed 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -69,8 +69,8 @@ static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* set codec DAI configuration */
@@ -136,16 +136,17 @@ static const struct snd_soc_dapm_route intercon[] = {
/*
* Logic for a wm8731 as connected on a at91sam9g20ek board.
*/
-static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
+static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *codec_dai = &codec->dai[0];
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
printk(KERN_DEBUG
"at91sam9g20ek_wm8731 "
": at91sam9g20ek_wm8731_init() called\n");
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
MCLK_RATE, SND_SOC_CLOCK_IN);
if (ret < 0) {
printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
@@ -179,37 +180,37 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link at91sam9g20ek_dai = {
.name = "WM8731",
.stream_name = "WM8731 PCM",
- .cpu_dai = &atmel_ssc_dai[0],
- .codec_dai = &wm8731_dai,
+ .cpu_dai_name = "atmel-ssc-dai.0",
+ .codec_dai_name = "wm8731-hifi",
.init = at91sam9g20ek_wm8731_init,
+ .platform_name = "atmel-pcm-audio",
+ .codec_name = "wm8731-codec.0-001b",
.ops = &at91sam9g20ek_ops,
};
static struct snd_soc_card snd_soc_at91sam9g20ek = {
.name = "AT91SAMG20-EK",
- .platform = &atmel_soc_platform,
.dai_link = &at91sam9g20ek_dai,
.num_links = 1,
.set_bias_level = at91sam9g20ek_set_bias_level,
};
-static struct snd_soc_device at91sam9g20ek_snd_devdata = {
- .card = &snd_soc_at91sam9g20ek,
- .codec_dev = &soc_codec_dev_wm8731,
-};
-
static struct platform_device *at91sam9g20ek_snd_device;
static int __init at91sam9g20ek_init(void)
{
- struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
- struct ssc_device *ssc = NULL;
struct clk *pllb;
int ret;
if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc()))
return -ENODEV;
+ ret = atmel_ssc_set_audio(0);
+ if (ret != 0) {
+ pr_err("Failed to set SSC 0 for audio: %d\n", ret);
+ return ret;
+ }
+
/*
* Codec MCLK is supplied by PCK0 - set it up.
*/
@@ -235,18 +236,6 @@ static int __init at91sam9g20ek_init(void)
clk_set_rate(mclk, MCLK_RATE);
- /*
- * Request SSC device
- */
- ssc = ssc_request(0);
- if (IS_ERR(ssc)) {
- printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
- ret = PTR_ERR(ssc);
- ssc = NULL;
- goto err_ssc;
- }
- ssc_p->ssc = ssc;
-
at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1);
if (!at91sam9g20ek_snd_device) {
printk(KERN_ERR "ASoC: Platform device allocation failed\n");
@@ -254,8 +243,7 @@ static int __init at91sam9g20ek_init(void)
}
platform_set_drvdata(at91sam9g20ek_snd_device,
- &at91sam9g20ek_snd_devdata);
- at91sam9g20ek_snd_devdata.dev = &at91sam9g20ek_snd_device->dev;
+ &snd_soc_at91sam9g20ek);
ret = platform_device_add(at91sam9g20ek_snd_device);
if (ret) {
@@ -265,9 +253,6 @@ static int __init at91sam9g20ek_init(void)
return ret;
-err_ssc:
- ssc_free(ssc);
- ssc_p->ssc = NULL;
err_mclk:
clk_put(mclk);
mclk = NULL;
@@ -277,16 +262,6 @@ err:
static void __exit at91sam9g20ek_exit(void)
{
- struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
- struct ssc_device *ssc;
-
- if (ssc_p != NULL) {
- ssc = ssc_p->ssc;
- if (ssc != NULL)
- ssc_free(ssc);
- ssc_p->ssc = NULL;
- }
-
platform_device_unregister(at91sam9g20ek_snd_device);
at91sam9g20ek_snd_device = NULL;
clk_put(mclk);
diff --git a/sound/soc/atmel/snd-soc-afeb9260.c b/sound/soc/atmel/snd-soc-afeb9260.c
index 23349de27313..e3d283561c19 100644
--- a/sound/soc/atmel/snd-soc-afeb9260.c
+++ b/sound/soc/atmel/snd-soc-afeb9260.c
@@ -46,8 +46,8 @@ static int afeb9260_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int err;
/* Set codec DAI configuration */
@@ -102,8 +102,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"MICIN", NULL, "Mic Jack"},
};
-static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec)
+static int afeb9260_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
/* Add afeb9260 specific widgets */
snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
@@ -125,8 +126,10 @@ static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link afeb9260_dai = {
.name = "TLV320AIC23",
.stream_name = "AIC23",
- .cpu_dai = &atmel_ssc_dai[0],
- .codec_dai = &tlv320aic23_dai,
+ .cpu_dai_name = "atmel-ssc-dai.0",
+ .codec_dai_name = "tlv320aic23-hifi",
+ .platform_name = "atmel_pcm-audio",
+ .codec_name = "tlv320aic23-codec.0-0x1a",
.init = afeb9260_tlv320aic23_init,
.ops = &afeb9260_ops,
};
@@ -134,37 +137,20 @@ static struct snd_soc_dai_link afeb9260_dai = {
/* Audio machine driver */
static struct snd_soc_card snd_soc_machine_afeb9260 = {
.name = "AFEB9260",
- .platform = &atmel_soc_platform,
.dai_link = &afeb9260_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device afeb9260_snd_devdata = {
- .card = &snd_soc_machine_afeb9260,
- .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
static struct platform_device *afeb9260_snd_device;
static int __init afeb9260_soc_init(void)
{
int err;
struct device *dev;
- struct atmel_ssc_info *ssc_p = afeb9260_dai.cpu_dai->private_data;
- struct ssc_device *ssc = NULL;
if (!(machine_is_afeb9260()))
return -ENODEV;
- ssc = ssc_request(0);
- if (IS_ERR(ssc)) {
- printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
- err = PTR_ERR(ssc);
- ssc = NULL;
- goto err_ssc;
- }
- ssc_p->ssc = ssc;
afeb9260_snd_device = platform_device_alloc("soc-audio", -1);
if (!afeb9260_snd_device) {
@@ -172,8 +158,7 @@ static int __init afeb9260_soc_init(void)
return -ENOMEM;
}
- platform_set_drvdata(afeb9260_snd_device, &afeb9260_snd_devdata);
- afeb9260_snd_devdata.dev = &afeb9260_snd_device->dev;
+ platform_set_drvdata(afeb9260_snd_device, &snd_soc_machine_afeb9260);
err = platform_device_add(afeb9260_snd_device);
if (err)
goto err1;
@@ -184,9 +169,7 @@ static int __init afeb9260_soc_init(void)
err1:
platform_device_del(afeb9260_snd_device);
platform_device_put(afeb9260_snd_device);
-err_ssc:
return err;
-
}
static void __exit afeb9260_soc_exit(void)
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c
index cdf7be1b9b91..b62fcd33e586 100644
--- a/sound/soc/au1x/db1200.c
+++ b/sound/soc/au1x/db1200.c
@@ -19,7 +19,6 @@
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#include <asm/mach-db1x00/bcsr.h>
-#include "../codecs/ac97.h"
#include "../codecs/wm8731.h"
#include "psc.h"
@@ -28,20 +27,16 @@
static struct snd_soc_dai_link db1200_ac97_dai = {
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &au1xpsc_ac97_dai,
- .codec_dai = &ac97_dai,
+ .codec_dai_name = "ac97-hifi",
+ .cpu_dai_name = "au1xpsc_ac97.1",
+ .platform_name = "au1xpsc-pcm.1",
+ .codec_name = "ac97-codec.1",
};
static struct snd_soc_card db1200_ac97_machine = {
.name = "DB1200_AC97",
.dai_link = &db1200_ac97_dai,
.num_links = 1,
- .platform = &au1xpsc_soc_platform,
-};
-
-static struct snd_soc_device db1200_ac97_devdata = {
- .card = &db1200_ac97_machine,
- .codec_dev = &soc_codec_dev_ac97,
};
/*------------------------- I2S PART ---------------------------*/
@@ -49,12 +44,12 @@ static struct snd_soc_device db1200_ac97_devdata = {
static int db1200_i2s_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* WM8731 has its own 12MHz crystal */
- snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
+ snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
12000000, SND_SOC_CLOCK_IN);
/* codec is bitclock and lrclk master */
@@ -80,8 +75,10 @@ static struct snd_soc_ops db1200_i2s_wm8731_ops = {
static struct snd_soc_dai_link db1200_i2s_dai = {
.name = "WM8731",
.stream_name = "WM8731 PCM",
- .cpu_dai = &au1xpsc_i2s_dai,
- .codec_dai = &wm8731_dai,
+ .codec_dai_name = "wm8731-hifi",
+ .cpu_dai_name = "au1xpsc_i2s.1",
+ .platform_name = "au1xpsc-pcm.1",
+ .codec_name = "wm8731-codec.0-001b",
.ops = &db1200_i2s_wm8731_ops,
};
@@ -89,12 +86,6 @@ static struct snd_soc_card db1200_i2s_machine = {
.name = "DB1200_I2S",
.dai_link = &db1200_i2s_dai,
.num_links = 1,
- .platform = &au1xpsc_soc_platform,
-};
-
-static struct snd_soc_device db1200_i2s_devdata = {
- .card = &db1200_i2s_machine,
- .codec_dev = &soc_codec_dev_wm8731,
};
/*------------------------- COMMON PART ---------------------------*/
@@ -106,18 +97,16 @@ static int __init db1200_audio_load(void)
int ret;
ret = -ENOMEM;
- db1200_asoc_dev = platform_device_alloc("soc-audio", -1);
+ db1200_asoc_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */
if (!db1200_asoc_dev)
goto out;
/* DB1200 board setup set PSC1MUX to preferred audio device */
if (bcsr_read(BCSR_RESETS) & BCSR_RESETS_PSC1MUX)
- platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_devdata);
+ platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_machine);
else
- platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_devdata);
+ platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_machine);
- db1200_ac97_devdata.dev = &db1200_asoc_dev->dev;
- db1200_i2s_devdata.dev = &db1200_asoc_dev->dev;
ret = platform_device_add(db1200_asoc_dev);
if (ret) {
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index 6d9f4c624949..10fdd2854e58 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -10,9 +10,6 @@
*
* DMA glue for Au1x-PSC audio.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
*/
@@ -61,9 +58,6 @@ struct au1xpsc_audio_dmadata {
int msbits;
};
-/* instance data. There can be only one, MacLeod!!!! */
-static struct au1xpsc_audio_dmadata *au1xpsc_audio_pcmdma[2];
-
/*
* These settings are somewhat okay, at least on my machine audio plays
* almost skip-free. Especially the 64kB buffer seems to help a LOT.
@@ -199,6 +193,14 @@ out:
return 0;
}
+static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss)
+{
+ struct snd_soc_pcm_runtime *rtd = ss->private_data;
+ struct au1xpsc_audio_dmadata *pcd =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ return &pcd[SUBSTREAM_TYPE(ss)];
+}
+
static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -211,7 +213,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
goto out;
stype = SUBSTREAM_TYPE(substream);
- pcd = au1xpsc_audio_pcmdma[stype];
+ pcd = to_dmadata(substream);
DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d "
"runtime->min_align %d\n",
@@ -249,8 +251,7 @@ static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream)
static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
{
- struct au1xpsc_audio_dmadata *pcd =
- au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)];
+ struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
au1xxx_dbdma_reset(pcd->ddma_chan);
@@ -267,7 +268,7 @@ static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
- u32 c = au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->ddma_chan;
+ u32 c = to_dmadata(substream)->ddma_chan;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -287,8 +288,7 @@ static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
static snd_pcm_uframes_t
au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
{
- return bytes_to_frames(substream->runtime,
- au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->pos);
+ return bytes_to_frames(substream->runtime, to_dmadata(substream)->pos);
}
static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
@@ -299,7 +299,7 @@ static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
{
- au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]);
+ au1x_pcm_dbdma_free(to_dmadata(substream));
return 0;
}
@@ -329,42 +329,21 @@ static int au1xpsc_pcm_new(struct snd_card *card,
return 0;
}
-static int au1xpsc_pcm_probe(struct platform_device *pdev)
-{
- if (!au1xpsc_audio_pcmdma[PCM_TX] || !au1xpsc_audio_pcmdma[PCM_RX])
- return -ENODEV;
-
- return 0;
-}
-
-static int au1xpsc_pcm_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
/* au1xpsc audio platform */
-struct snd_soc_platform au1xpsc_soc_platform = {
- .name = "au1xpsc-pcm-dbdma",
- .probe = au1xpsc_pcm_probe,
- .remove = au1xpsc_pcm_remove,
- .pcm_ops = &au1xpsc_pcm_ops,
+struct snd_soc_platform_driver au1xpsc_soc_platform = {
+ .ops = &au1xpsc_pcm_ops,
.pcm_new = au1xpsc_pcm_new,
.pcm_free = au1xpsc_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
{
+ struct au1xpsc_audio_dmadata *dmadata;
struct resource *r;
int ret;
- if (au1xpsc_audio_pcmdma[PCM_TX] || au1xpsc_audio_pcmdma[PCM_RX])
- return -EBUSY;
-
- /* TX DMA */
- au1xpsc_audio_pcmdma[PCM_TX]
- = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
- if (!au1xpsc_audio_pcmdma[PCM_TX])
+ dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
+ if (!dmadata)
return -ENOMEM;
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -372,47 +351,33 @@ static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
ret = -ENODEV;
goto out1;
}
- (au1xpsc_audio_pcmdma[PCM_TX])->ddma_id = r->start;
+ dmadata[PCM_TX].ddma_id = r->start;
/* RX DMA */
- au1xpsc_audio_pcmdma[PCM_RX]
- = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
- if (!au1xpsc_audio_pcmdma[PCM_RX])
- return -ENOMEM;
-
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!r) {
ret = -ENODEV;
- goto out2;
+ goto out1;
}
- (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start;
+ dmadata[PCM_RX].ddma_id = r->start;
+
+ platform_set_drvdata(pdev, dmadata);
- ret = snd_soc_register_platform(&au1xpsc_soc_platform);
+ ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform);
if (!ret)
return ret;
-out2:
- kfree(au1xpsc_audio_pcmdma[PCM_RX]);
- au1xpsc_audio_pcmdma[PCM_RX] = NULL;
out1:
- kfree(au1xpsc_audio_pcmdma[PCM_TX]);
- au1xpsc_audio_pcmdma[PCM_TX] = NULL;
+ kfree(dmadata);
return ret;
}
static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev)
{
- int i;
+ struct au1xpsc_audio_dmadata *dmadata = platform_get_drvdata(pdev);
- snd_soc_unregister_platform(&au1xpsc_soc_platform);
-
- for (i = 0; i < 2; i++) {
- if (au1xpsc_audio_pcmdma[i]) {
- au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]);
- kfree(au1xpsc_audio_pcmdma[i]);
- au1xpsc_audio_pcmdma[i] = NULL;
- }
- }
+ snd_soc_unregister_platform(&pdev->dev);
+ kfree(dmadata);
return 0;
}
@@ -428,8 +393,6 @@ static struct platform_driver au1xpsc_pcm_driver = {
static int __init au1xpsc_audio_dbdma_load(void)
{
- au1xpsc_audio_pcmdma[PCM_TX] = NULL;
- au1xpsc_audio_pcmdma[PCM_RX] = NULL;
return platform_driver_register(&au1xpsc_pcm_driver);
}
@@ -467,7 +430,7 @@ struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev)
res[1].start = res[1].end = id[1];
res[0].flags = res[1].flags = IORESOURCE_DMA;
- pd = platform_device_alloc("au1xpsc-pcm", -1);
+ pd = platform_device_alloc("au1xpsc-pcm", pdev->id);
if (!pd)
goto out;
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index d14a5a91a465..d0db66f24a00 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -10,9 +10,6 @@
*
* Au1xxx-PSC AC97 glue.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
*/
#include <linux/init.h>
@@ -56,12 +53,29 @@
/* instance data. There can be only one, MacLeod!!!! */
static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
+#if 0
+
+/* this could theoretically work, but ac97->bus->card->private_data can be NULL
+ * when snd_ac97_mixer() is called; I don't know if the rest further down the
+ * chain are always valid either.
+ */
+static inline struct au1xpsc_audio_data *ac97_to_pscdata(struct snd_ac97 *x)
+{
+ struct snd_soc_card *c = x->bus->card->private_data;
+ return snd_soc_dai_get_drvdata(c->rtd->cpu_dai);
+}
+
+#else
+
+#define ac97_to_pscdata(x) au1xpsc_ac97_workdata
+
+#endif
+
/* AC97 controller reads codec register */
static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
unsigned short reg)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
unsigned short retry, tmo;
unsigned long data;
@@ -102,8 +116,7 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
unsigned short val)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
unsigned int tmo, retry;
au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
@@ -134,8 +147,7 @@ static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
/* AC97 controller asserts a warm reset */
static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata));
au_sync();
@@ -146,8 +158,7 @@ static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
int i;
/* disable PSC during cold reset */
@@ -202,8 +213,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
unsigned long r, ro, stat;
int chans, t, stype = SUBSTREAM_TYPE(substream);
@@ -283,8 +293,7 @@ out:
static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
int ret, stype = SUBSTREAM_TYPE(substream);
ret = 0;
@@ -315,27 +324,19 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
return ret;
}
-static int au1xpsc_ac97_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int au1xpsc_ac97_probe(struct snd_soc_dai *dai)
{
return au1xpsc_ac97_workdata ? 0 : -ENODEV;
}
-static void au1xpsc_ac97_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
-{
-}
-
static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
.trigger = au1xpsc_ac97_trigger,
.hw_params = au1xpsc_ac97_hw_params,
};
-struct snd_soc_dai au1xpsc_ac97_dai = {
- .name = "au1xpsc_ac97",
+static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
.ac97_control = 1,
.probe = au1xpsc_ac97_probe,
- .remove = au1xpsc_ac97_remove,
.playback = {
.rates = AC97_RATES,
.formats = AC97_FMTS,
@@ -350,7 +351,6 @@ struct snd_soc_dai au1xpsc_ac97_dai = {
},
.ops = &au1xpsc_ac97_dai_ops,
};
-EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
{
@@ -359,9 +359,6 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
unsigned long sel;
struct au1xpsc_audio_data *wd;
- if (au1xpsc_ac97_workdata)
- return -EBUSY;
-
wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
if (!wd)
return -ENOMEM;
@@ -395,18 +392,24 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd));
au_sync();
- ret = snd_soc_register_dai(&au1xpsc_ac97_dai);
+ /* name the DAI like this device instance ("au1xpsc-ac97.PSCINDEX") */
+ memcpy(&wd->dai_drv, &au1xpsc_ac97_dai_template,
+ sizeof(struct snd_soc_dai_driver));
+ wd->dai_drv.name = dev_name(&pdev->dev);
+
+ platform_set_drvdata(pdev, wd);
+
+ ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
if (ret)
goto out1;
wd->dmapd = au1xpsc_pcm_add(pdev);
if (wd->dmapd) {
- platform_set_drvdata(pdev, wd);
- au1xpsc_ac97_workdata = wd; /* MDEV */
+ au1xpsc_ac97_workdata = wd;
return 0;
}
- snd_soc_unregister_dai(&au1xpsc_ac97_dai);
+ snd_soc_unregister_dai(&pdev->dev);
out1:
release_mem_region(r->start, resource_size(r));
out0:
@@ -422,7 +425,7 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
if (wd->dmapd)
au1xpsc_pcm_destroy(wd->dmapd);
- snd_soc_unregister_dai(&au1xpsc_ac97_dai);
+ snd_soc_unregister_dai(&pdev->dev);
/* disable PSC completely */
au_writel(0, AC97_CFG(wd));
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index 6083fe7799fa..fca091276320 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -10,9 +10,6 @@
*
* Au1xxx-PSC I2S glue.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
* NOTE: so far only PSC slave mode (bit- and frameclock) is supported.
*/
@@ -54,13 +51,10 @@
((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC)
-/* instance data. There can be only one, MacLeod!!!! */
-static struct au1xpsc_audio_data *au1xpsc_i2s_workdata;
-
static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(cpu_dai);
unsigned long ct;
int ret;
@@ -120,7 +114,7 @@ static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
int cfgbits;
unsigned long stat;
@@ -245,7 +239,7 @@ static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype)
static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
int ret, stype = SUBSTREAM_TYPE(substream);
switch (cmd) {
@@ -263,27 +257,13 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
return ret;
}
-static int au1xpsc_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
-{
- return au1xpsc_i2s_workdata ? 0 : -ENODEV;
-}
-
-static void au1xpsc_i2s_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
-{
-}
-
static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
.trigger = au1xpsc_i2s_trigger,
.hw_params = au1xpsc_i2s_hw_params,
.set_fmt = au1xpsc_i2s_set_fmt,
};
-struct snd_soc_dai au1xpsc_i2s_dai = {
- .name = "au1xpsc_i2s",
- .probe = au1xpsc_i2s_probe,
- .remove = au1xpsc_i2s_remove,
+static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
.playback = {
.rates = AU1XPSC_I2S_RATES,
.formats = AU1XPSC_I2S_FMTS,
@@ -298,7 +278,6 @@ struct snd_soc_dai au1xpsc_i2s_dai = {
},
.ops = &au1xpsc_i2s_dai_ops,
};
-EXPORT_SYMBOL(au1xpsc_i2s_dai);
static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
{
@@ -307,9 +286,6 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
int ret;
struct au1xpsc_audio_data *wd;
- if (au1xpsc_i2s_workdata)
- return -EBUSY;
-
wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
if (!wd)
return -ENOMEM;
@@ -346,19 +322,23 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
* time out.
*/
- ret = snd_soc_register_dai(&au1xpsc_i2s_dai);
+ /* name the DAI like this device instance ("au1xpsc-i2s.PSCINDEX") */
+ memcpy(&wd->dai_drv, &au1xpsc_i2s_dai_template,
+ sizeof(struct snd_soc_dai_driver));
+ wd->dai_drv.name = dev_name(&pdev->dev);
+
+ platform_set_drvdata(pdev, wd);
+
+ ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
if (ret)
goto out1;
/* finally add the DMA device for this PSC */
wd->dmapd = au1xpsc_pcm_add(pdev);
- if (wd->dmapd) {
- platform_set_drvdata(pdev, wd);
- au1xpsc_i2s_workdata = wd;
+ if (wd->dmapd)
return 0;
- }
- snd_soc_unregister_dai(&au1xpsc_i2s_dai);
+ snd_soc_unregister_dai(&pdev->dev);
out1:
release_mem_region(r->start, resource_size(r));
out0:
@@ -374,7 +354,7 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
if (wd->dmapd)
au1xpsc_pcm_destroy(wd->dmapd);
- snd_soc_unregister_dai(&au1xpsc_i2s_dai);
+ snd_soc_unregister_dai(&pdev->dev);
au_writel(0, I2S_CFG(wd));
au_sync();
@@ -385,8 +365,6 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
release_mem_region(r->start, resource_size(r));
kfree(wd);
- au1xpsc_i2s_workdata = NULL; /* MDEV */
-
return 0;
}
@@ -446,7 +424,6 @@ static struct platform_driver au1xpsc_i2s_driver = {
static int __init au1xpsc_i2s_load(void)
{
- au1xpsc_i2s_workdata = NULL;
return platform_driver_register(&au1xpsc_i2s_driver);
}
diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h
index 093775d4dc3e..b30eadd422a7 100644
--- a/sound/soc/au1x/psc.h
+++ b/sound/soc/au1x/psc.h
@@ -8,19 +8,11 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
*/
#ifndef _AU1X_PCM_H
#define _AU1X_PCM_H
-extern struct snd_soc_dai au1xpsc_ac97_dai;
-extern struct snd_soc_dai au1xpsc_i2s_dai;
-extern struct snd_soc_platform au1xpsc_soc_platform;
-extern struct snd_ac97_bus_ops soc_ac97_ops;
-
/* DBDMA helpers */
extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev);
extern void au1xpsc_pcm_destroy(struct platform_device *dmapd);
@@ -31,6 +23,8 @@ struct au1xpsc_audio_data {
unsigned long cfg;
unsigned long rate;
+ struct snd_soc_dai_driver dai_drv;
+
unsigned long pm[2];
struct mutex lock;
struct platform_device *dmapd;
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 5e7aacf3bb5a..5a2fd8abaefa 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -422,14 +422,14 @@ int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -439,25 +439,44 @@ int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
return ret;
}
-struct snd_soc_platform bf5xx_ac97_soc_platform = {
- .name = "bf5xx-audio",
- .pcm_ops = &bf5xx_pcm_ac97_ops,
+static struct snd_soc_platform_driver bf5xx_ac97_soc_platform = {
+ .ops = &bf5xx_pcm_ac97_ops,
.pcm_new = bf5xx_pcm_ac97_new,
.pcm_free = bf5xx_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform);
-static int __init bfin_ac97_init(void)
+static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&bf5xx_ac97_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &bf5xx_ac97_soc_platform);
}
-module_init(bfin_ac97_init);
-static void __exit bfin_ac97_exit(void)
+static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&bf5xx_ac97_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver bf5xx_pcm_driver = {
+ .driver = {
+ .name = "bf5xx-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = bf5xx_soc_platform_probe,
+ .remove = __devexit_p(bf5xx_soc_platform_remove),
+};
+
+static int __init snd_bf5xx_pcm_init(void)
+{
+ return platform_driver_register(&bf5xx_pcm_driver);
+}
+module_init(snd_bf5xx_pcm_init);
+
+static void __exit snd_bf5xx_pcm_exit(void)
+{
+ platform_driver_unregister(&bf5xx_pcm_driver);
}
-module_exit(bfin_ac97_exit);
+module_exit(snd_bf5xx_pcm_exit);
MODULE_AUTHOR("Cliff Cai");
MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module");
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.h b/sound/soc/blackfin/bf5xx-ac97-pcm.h
index 350125a0ae21..d324d5826a9b 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.h
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.h
@@ -23,7 +23,4 @@ struct bf5xx_gpio {
u32 frm;
};
-/* platform data */
-extern struct snd_soc_platform bf5xx_ac97_soc_platform;
-
#endif
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index c0eba5109980..c5f856ec27ca 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -255,7 +255,7 @@ EXPORT_SYMBOL_GPL(soc_ac97_ops);
#ifdef CONFIG_PM
static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
{
- struct sport_device *sport = dai->private_data;
+ struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
pr_debug("%s : sport %d\n", __func__, dai->id);
if (!dai->active)
@@ -270,7 +270,7 @@ static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
{
int ret;
- struct sport_device *sport = dai->private_data;
+ struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
pr_debug("%s : sport %d\n", __func__, dai->id);
if (!dai->active)
@@ -306,8 +306,7 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
#define bf5xx_ac97_resume NULL
#endif
-static int bf5xx_ac97_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
{
int ret = 0;
cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
@@ -379,8 +378,7 @@ peripheral_err:
return ret;
}
-static void bf5xx_ac97_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int bf5xx_ac97_remove(struct snd_soc_dai *dai)
{
free_page((unsigned long)cmd_count);
cmd_count = NULL;
@@ -388,11 +386,10 @@ static void bf5xx_ac97_remove(struct platform_device *pdev,
#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
#endif
+ return 0;
}
-struct snd_soc_dai bfin_ac97_dai = {
- .name = "bf5xx-ac97",
- .id = 0,
+struct snd_soc_dai_driver bfin_ac97_dai = {
.ac97_control = 1,
.probe = bf5xx_ac97_probe,
.remove = bf5xx_ac97_remove,
@@ -417,18 +414,40 @@ struct snd_soc_dai bfin_ac97_dai = {
};
EXPORT_SYMBOL_GPL(bfin_ac97_dai);
+static __devinit int asoc_bfin_ac97_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
+}
+
+static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver asoc_bfin_ac97_driver = {
+ .driver = {
+ .name = "bfin-ac97",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = asoc_bfin_ac97_probe,
+ .remove = __devexit_p(asoc_bfin_ac97_remove),
+};
+
static int __init bfin_ac97_init(void)
{
- return snd_soc_register_dai(&bfin_ac97_dai);
+ return platform_driver_register(&asoc_bfin_ac97_driver);
}
module_init(bfin_ac97_init);
static void __exit bfin_ac97_exit(void)
{
- snd_soc_unregister_dai(&bfin_ac97_dai);
+ platform_driver_unregister(&asoc_bfin_ac97_driver);
}
module_exit(bfin_ac97_exit);
+
MODULE_AUTHOR("Roy Huang");
MODULE_DESCRIPTION("AC97 driver for ADI Blackfin");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-ac97.h b/sound/soc/blackfin/bf5xx-ac97.h
index a1f97dd809d6..15c635e33f4d 100644
--- a/sound/soc/blackfin/bf5xx-ac97.h
+++ b/sound/soc/blackfin/bf5xx-ac97.h
@@ -50,8 +50,6 @@ struct ac97_frame {
#define TAG_PCM_SR 0x0080
#define TAG_PCM_LFE 0x0040
-extern struct snd_soc_dai bfin_ac97_dai;
-
void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \
size_t count, unsigned int chan_mask);
diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c
index 0f45a3f56be8..2394bff2b655 100644
--- a/sound/soc/blackfin/bf5xx-ad1836.c
+++ b/sound/soc/blackfin/bf5xx-ad1836.c
@@ -40,9 +40,9 @@ static struct snd_soc_card bf5xx_ad1836;
static int bf5xx_ad1836_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- cpu_dai->private_data = sport_handle;
+ snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
return 0;
}
@@ -50,8 +50,8 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
int ret = 0;
/* set cpu DAI configuration */
@@ -83,23 +83,19 @@ static struct snd_soc_ops bf5xx_ad1836_ops = {
static struct snd_soc_dai_link bf5xx_ad1836_dai = {
.name = "ad1836",
.stream_name = "AD1836",
- .cpu_dai = &bf5xx_tdm_dai,
- .codec_dai = &ad1836_dai,
+ .cpu_dai_name = "bf5xx-tdm",
+ .codec_dai_name = "ad1836-hifi",
+ .platform_name = "bf5xx-tdm-pcm-audio",
+ .codec_name = "ad1836-codec.0",
.ops = &bf5xx_ad1836_ops,
};
static struct snd_soc_card bf5xx_ad1836 = {
.name = "bf5xx_ad1836",
- .platform = &bf5xx_tdm_soc_platform,
.dai_link = &bf5xx_ad1836_dai,
.num_links = 1,
};
-static struct snd_soc_device bf5xx_ad1836_snd_devdata = {
- .card = &bf5xx_ad1836,
- .codec_dev = &soc_codec_dev_ad1836,
-};
-
static struct platform_device *bfxx_ad1836_snd_device;
static int __init bf5xx_ad1836_init(void)
@@ -110,8 +106,7 @@ static int __init bf5xx_ad1836_init(void)
if (!bfxx_ad1836_snd_device)
return -ENOMEM;
- platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836_snd_devdata);
- bf5xx_ad1836_snd_devdata.dev = &bfxx_ad1836_snd_device->dev;
+ platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836);
ret = platform_device_add(bfxx_ad1836_snd_device);
if (ret)
diff --git a/sound/soc/blackfin/bf5xx-ad193x.c b/sound/soc/blackfin/bf5xx-ad193x.c
index b8c9060cfd8e..e4a625317a1a 100644
--- a/sound/soc/blackfin/bf5xx-ad193x.c
+++ b/sound/soc/blackfin/bf5xx-ad193x.c
@@ -49,9 +49,9 @@ static struct snd_soc_card bf5xx_ad193x;
static int bf5xx_ad193x_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- cpu_dai->private_data = sport_handle;
+ snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
return 0;
}
@@ -59,8 +59,8 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
int ret = 0;
/* set cpu DAI configuration */
@@ -97,23 +97,19 @@ static struct snd_soc_ops bf5xx_ad193x_ops = {
static struct snd_soc_dai_link bf5xx_ad193x_dai = {
.name = "ad193x",
.stream_name = "AD193X",
- .cpu_dai = &bf5xx_tdm_dai,
- .codec_dai = &ad193x_dai,
+ .cpu_dai_name = "bf5xx-tdm",
+ .codec_dai_name ="ad193x-hifi",
+ .platform_name = "bf5xx-tdm-pcm-audio",
+ .codec_name = "ad193x-codec.5",
.ops = &bf5xx_ad193x_ops,
};
static struct snd_soc_card bf5xx_ad193x = {
.name = "bf5xx_ad193x",
- .platform = &bf5xx_tdm_soc_platform,
.dai_link = &bf5xx_ad193x_dai,
.num_links = 1,
};
-static struct snd_soc_device bf5xx_ad193x_snd_devdata = {
- .card = &bf5xx_ad193x,
- .codec_dev = &soc_codec_dev_ad193x,
-};
-
static struct platform_device *bfxx_ad193x_snd_device;
static int __init bf5xx_ad193x_init(void)
@@ -124,8 +120,7 @@ static int __init bf5xx_ad193x_init(void)
if (!bfxx_ad193x_snd_device)
return -ENOMEM;
- platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x_snd_devdata);
- bf5xx_ad193x_snd_devdata.dev = &bfxx_ad193x_snd_device->dev;
+ platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x);
ret = platform_device_add(bfxx_ad193x_snd_device);
if (ret)
diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c
index 92f7c327bb7a..d57c9c9c9883 100644
--- a/sound/soc/blackfin/bf5xx-ad1980.c
+++ b/sound/soc/blackfin/bf5xx-ad1980.c
@@ -56,10 +56,10 @@ static struct snd_soc_card bf5xx_board;
static int bf5xx_board_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
pr_debug("%s enter\n", __func__);
- cpu_dai->private_data = sport_handle;
+ snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
return 0;
}
@@ -70,23 +70,19 @@ static struct snd_soc_ops bf5xx_board_ops = {
static struct snd_soc_dai_link bf5xx_board_dai = {
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &bfin_ac97_dai,
- .codec_dai = &ad1980_dai,
+ .cpu_dai_name = "bfin-ac97",
+ .codec_dai_name = "ad1980-hifi",
+ .platform_name = "bfin-pcm-audio",
+ .codec_name = "ad1980-codec",
.ops = &bf5xx_board_ops,
};
static struct snd_soc_card bf5xx_board = {
.name = "bf5xx-board",
- .platform = &bf5xx_ac97_soc_platform,
.dai_link = &bf5xx_board_dai,
.num_links = 1,
};
-static struct snd_soc_device bf5xx_board_snd_devdata = {
- .card = &bf5xx_board,
- .codec_dev = &soc_codec_dev_ad1980,
-};
-
static struct platform_device *bf5xx_board_snd_device;
static int __init bf5xx_board_init(void)
@@ -97,8 +93,7 @@ static int __init bf5xx_board_init(void)
if (!bf5xx_board_snd_device)
return -ENOMEM;
- platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board_snd_devdata);
- bf5xx_board_snd_devdata.dev = &bf5xx_board_snd_device->dev;
+ platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board);
ret = platform_device_add(bf5xx_board_snd_device);
if (ret)
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c
index 9825b71d0e28..900ced54ac79 100644
--- a/sound/soc/blackfin/bf5xx-ad73311.c
+++ b/sound/soc/blackfin/bf5xx-ad73311.c
@@ -47,7 +47,6 @@
#include "../codecs/ad73311.h"
#include "bf5xx-sport.h"
#include "bf5xx-i2s-pcm.h"
-#include "bf5xx-i2s.h"
#if CONFIG_SND_BF5XX_SPORT_NUM == 0
#define bfin_write_SPORT_TCR1 bfin_write_SPORT0_TCR1
@@ -150,10 +149,10 @@ static int bf5xx_probe(struct platform_device *pdev)
static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
pr_debug("%s enter\n", __func__);
- cpu_dai->private_data = sport_handle;
+ snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
return 0;
}
@@ -161,7 +160,7 @@ static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0;
pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
@@ -185,24 +184,20 @@ static struct snd_soc_ops bf5xx_ad73311_ops = {
static struct snd_soc_dai_link bf5xx_ad73311_dai = {
.name = "ad73311",
.stream_name = "AD73311",
- .cpu_dai = &bf5xx_i2s_dai,
- .codec_dai = &ad73311_dai,
+ .cpu_dai_name = "bf5xx-i2s",
+ .codec_dai_name = "ad73311-hifi",
+ .platform_name = "bfin-pcm-audio",
+ .codec_name = "ad73311-codec",
.ops = &bf5xx_ad73311_ops,
};
static struct snd_soc_card bf5xx_ad73311 = {
.name = "bf5xx_ad73311",
- .platform = &bf5xx_i2s_soc_platform,
.probe = bf5xx_probe,
.dai_link = &bf5xx_ad73311_dai,
.num_links = 1,
};
-static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
- .card = &bf5xx_ad73311,
- .codec_dev = &soc_codec_dev_ad73311,
-};
-
static struct platform_device *bf5xx_ad73311_snd_device;
static int __init bf5xx_ad73311_init(void)
@@ -214,8 +209,7 @@ static int __init bf5xx_ad73311_init(void)
if (!bf5xx_ad73311_snd_device)
return -ENOMEM;
- platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
- bf5xx_ad73311_snd_devdata.dev = &bf5xx_ad73311_snd_device->dev;
+ platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311);
ret = platform_device_add(bf5xx_ad73311_snd_device);
if (ret)
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
index 1d2a1adf2575..890a0dccf902 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.c
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -40,7 +40,6 @@
#include <asm/dma.h>
#include "bf5xx-i2s-pcm.h"
-#include "bf5xx-i2s.h"
#include "bf5xx-sport.h"
static void bf5xx_dma_irq(void *data)
@@ -257,14 +256,14 @@ int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -274,25 +273,44 @@ int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
return ret;
}
-struct snd_soc_platform bf5xx_i2s_soc_platform = {
- .name = "bf5xx-audio",
- .pcm_ops = &bf5xx_pcm_i2s_ops,
+static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = {
+ .ops = &bf5xx_pcm_i2s_ops,
.pcm_new = bf5xx_pcm_i2s_new,
.pcm_free = bf5xx_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform);
-static int __init bfin_i2s_init(void)
+static int __devinit bfin_i2s_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&bf5xx_i2s_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &bf5xx_i2s_soc_platform);
}
-module_init(bfin_i2s_init);
-static void __exit bfin_i2s_exit(void)
+static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&bf5xx_i2s_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver bfin_i2s_pcm_driver = {
+ .driver = {
+ .name = "bfin-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = bfin_i2s_soc_platform_probe,
+ .remove = __devexit_p(bfin_i2s_soc_platform_remove),
+};
+
+static int __init snd_bfin_i2s_pcm_init(void)
+{
+ return platform_driver_register(&bfin_i2s_pcm_driver);
+}
+module_init(snd_bfin_i2s_pcm_init);
+
+static void __exit snd_bfin_i2s_pcm_exit(void)
+{
+ platform_driver_unregister(&bfin_i2s_pcm_driver);
}
-module_exit(bfin_i2s_exit);
+module_exit(snd_bfin_i2s_pcm_exit);
MODULE_AUTHOR("Cliff Cai");
MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module");
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.h b/sound/soc/blackfin/bf5xx-i2s-pcm.h
index 4d4609a97c59..0c2c5a68d4ff 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.h
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.h
@@ -23,7 +23,4 @@ struct bf5xx_gpio {
u32 frm;
};
-/* platform data */
-extern struct snd_soc_platform bf5xx_i2s_soc_platform;
-
#endif
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
index 3e6ada0dd1c4..d453b1e9d607 100644
--- a/sound/soc/blackfin/bf5xx-i2s.c
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -42,7 +42,6 @@
#include <linux/gpio.h>
#include "bf5xx-sport.h"
-#include "bf5xx-i2s.h"
struct bf5xx_i2s_port {
u16 tcr1;
@@ -195,8 +194,7 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
bf5xx_i2s.configured = 0;
}
-static int bf5xx_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int bf5xx_i2s_probe(struct snd_soc_dai *dai)
{
pr_debug("%s enter\n", __func__);
if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
@@ -215,11 +213,11 @@ static int bf5xx_i2s_probe(struct platform_device *pdev,
return 0;
}
-static void bf5xx_i2s_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int bf5xx_i2s_remove(struct snd_soc_dai *dai)
{
pr_debug("%s enter\n", __func__);
peripheral_free_list(&sport_req[sport_num][0]);
+ return 0;
}
#ifdef CONFIG_PM
@@ -228,9 +226,9 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
pr_debug("%s : sport %d\n", __func__, dai->id);
- if (dai->capture.active)
+ if (dai->capture_active)
sport_rx_stop(sport_handle);
- if (dai->playback.active)
+ if (dai->playback_active)
sport_tx_stop(sport_handle);
return 0;
}
@@ -277,9 +275,7 @@ static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
.set_fmt = bf5xx_i2s_set_dai_fmt,
};
-struct snd_soc_dai bf5xx_i2s_dai = {
- .name = "bf5xx-i2s",
- .id = 0,
+static struct snd_soc_dai_driver bf5xx_i2s_dai = {
.probe = bf5xx_i2s_probe,
.remove = bf5xx_i2s_remove,
.suspend = bf5xx_i2s_suspend,
@@ -296,18 +292,39 @@ struct snd_soc_dai bf5xx_i2s_dai = {
.formats = BF5XX_I2S_FORMATS,},
.ops = &bf5xx_i2s_dai_ops,
};
-EXPORT_SYMBOL_GPL(bf5xx_i2s_dai);
+
+static int bfin_i2s_drv_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+}
+
+static int __devexit bfin_i2s_drv_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver bfin_i2s_driver = {
+ .probe = bfin_i2s_drv_probe,
+ .remove = __devexit_p(bfin_i2s_drv_remove),
+
+ .driver = {
+ .name = "bf5xx-i2s",
+ .owner = THIS_MODULE,
+ },
+};
static int __init bfin_i2s_init(void)
{
- return snd_soc_register_dai(&bf5xx_i2s_dai);
+ return platform_driver_register(&bfin_i2s_driver);
}
-module_init(bfin_i2s_init);
static void __exit bfin_i2s_exit(void)
{
- snd_soc_unregister_dai(&bf5xx_i2s_dai);
+ platform_driver_unregister(&bfin_i2s_driver);
}
+
+module_init(bfin_i2s_init);
module_exit(bfin_i2s_exit);
/* Module information */
diff --git a/sound/soc/blackfin/bf5xx-i2s.h b/sound/soc/blackfin/bf5xx-i2s.h
deleted file mode 100644
index 264ecdcba35a..000000000000
--- a/sound/soc/blackfin/bf5xx-i2s.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * sound/soc/blackfin/bf5xx-i2s.h
- *
- * 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 _BF5XX_I2S_H
-#define _BF5XX_I2S_H
-
-extern struct snd_soc_dai bf5xx_i2s_dai;
-
-#endif
diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c
index 3a00fa4dbe6d..36f2769eb912 100644
--- a/sound/soc/blackfin/bf5xx-ssm2602.c
+++ b/sound/soc/blackfin/bf5xx-ssm2602.c
@@ -42,17 +42,16 @@
#include "../codecs/ssm2602.h"
#include "bf5xx-sport.h"
#include "bf5xx-i2s-pcm.h"
-#include "bf5xx-i2s.h"
static struct snd_soc_card bf5xx_ssm2602;
static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
pr_debug("%s enter\n", __func__);
- cpu_dai->private_data = sport_handle;
+ snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
return 0;
}
@@ -60,8 +59,8 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret = 0;
@@ -118,36 +117,19 @@ static struct snd_soc_ops bf5xx_ssm2602_ops = {
static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
.name = "ssm2602",
.stream_name = "SSM2602",
- .cpu_dai = &bf5xx_i2s_dai,
- .codec_dai = &ssm2602_dai,
+ .cpu_dai_name = "bf5xx-i2s",
+ .codec_dai_name = "ssm2602-hifi",
+ .platform_name = "bf5xx-pcm-audio",
+ .codec_name = "ssm2602-codec.0-0x1b",
.ops = &bf5xx_ssm2602_ops,
};
-/*
- * SSM2602 2 wire address is determined by CSB
- * state during powerup.
- * low = 0x1a
- * high = 0x1b
- */
-
-static struct ssm2602_setup_data bf5xx_ssm2602_setup = {
- .i2c_bus = 0,
- .i2c_address = 0x1b,
-};
-
static struct snd_soc_card bf5xx_ssm2602 = {
.name = "bf5xx_ssm2602",
- .platform = &bf5xx_i2s_soc_platform,
.dai_link = &bf5xx_ssm2602_dai,
.num_links = 1,
};
-static struct snd_soc_device bf5xx_ssm2602_snd_devdata = {
- .card = &bf5xx_ssm2602,
- .codec_dev = &soc_codec_dev_ssm2602,
- .codec_data = &bf5xx_ssm2602_setup,
-};
-
static struct platform_device *bf5xx_ssm2602_snd_device;
static int __init bf5xx_ssm2602_init(void)
@@ -159,9 +141,7 @@ static int __init bf5xx_ssm2602_init(void)
if (!bf5xx_ssm2602_snd_device)
return -ENOMEM;
- platform_set_drvdata(bf5xx_ssm2602_snd_device,
- &bf5xx_ssm2602_snd_devdata);
- bf5xx_ssm2602_snd_devdata.dev = &bf5xx_ssm2602_snd_device->dev;
+ platform_set_drvdata(bf5xx_ssm2602_snd_device, &bf5xx_ssm2602);
ret = platform_device_add(bf5xx_ssm2602_snd_device);
if (ret)
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c
index 6bac1ac1a315..74cf759b78a6 100644
--- a/sound/soc/blackfin/bf5xx-tdm-pcm.c
+++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c
@@ -290,14 +290,14 @@ static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai,
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -307,25 +307,44 @@ out:
return ret;
}
-struct snd_soc_platform bf5xx_tdm_soc_platform = {
- .name = "bf5xx-audio",
- .pcm_ops = &bf5xx_pcm_tdm_ops,
+static struct snd_soc_platform_driver bf5xx_tdm_soc_platform = {
+ .ops = &bf5xx_pcm_tdm_ops,
.pcm_new = bf5xx_pcm_tdm_new,
.pcm_free = bf5xx_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(bf5xx_tdm_soc_platform);
-static int __init bfin_pcm_tdm_init(void)
+static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&bf5xx_tdm_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &bf5xx_tdm_soc_platform);
}
-module_init(bfin_pcm_tdm_init);
-static void __exit bfin_pcm_tdm_exit(void)
+static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&bf5xx_tdm_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver bfin_tdm_driver = {
+ .driver = {
+ .name = "bf5xx-tdm-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = bf5xx_soc_platform_probe,
+ .remove = __devexit_p(bf5xx_soc_platform_remove),
+};
+
+static int __init snd_bfin_tdm_init(void)
+{
+ return platform_driver_register(&bfin_tdm_driver);
+}
+module_init(snd_bfin_tdm_init);
+
+static void __exit snd_bfin_tdm_exit(void)
+{
+ platform_driver_unregister(&bfin_tdm_driver);
}
-module_exit(bfin_pcm_tdm_exit);
+module_exit(snd_bfin_tdm_exit);
MODULE_AUTHOR("Barry Song");
MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module");
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.h b/sound/soc/blackfin/bf5xx-tdm-pcm.h
index ddc5047df88c..7f8cc01c4477 100644
--- a/sound/soc/blackfin/bf5xx-tdm-pcm.h
+++ b/sound/soc/blackfin/bf5xx-tdm-pcm.h
@@ -15,7 +15,4 @@ struct bf5xx_pcm_dma_params {
char *name; /* stream identifier */
};
-/* platform data */
-extern struct snd_soc_platform bf5xx_tdm_soc_platform;
-
#endif
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c
index 24c14269f4bc..125123929f16 100644
--- a/sound/soc/blackfin/bf5xx-tdm.c
+++ b/sound/soc/blackfin/bf5xx-tdm.c
@@ -214,9 +214,9 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
if (!dai->active)
return 0;
- if (dai->capture.active)
+ if (dai->capture_active)
sport_rx_stop(sport);
- if (dai->playback.active)
+ if (dai->playback_active)
sport_tx_stop(sport);
return 0;
}
@@ -224,7 +224,7 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
{
int ret;
- struct sport_device *sport = dai->private_data;
+ struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
if (!dai->active)
return 0;
@@ -262,9 +262,7 @@ static struct snd_soc_dai_ops bf5xx_tdm_dai_ops = {
.set_channel_map = bf5xx_tdm_set_channel_map,
};
-struct snd_soc_dai bf5xx_tdm_dai = {
- .name = "bf5xx-tdm",
- .id = 0,
+static struct snd_soc_dai_driver bf5xx_tdm_dai = {
.suspend = bf5xx_tdm_suspend,
.resume = bf5xx_tdm_resume,
.playback = {
@@ -279,7 +277,6 @@ struct snd_soc_dai bf5xx_tdm_dai = {
.formats = SNDRV_PCM_FMTBIT_S32_LE,},
.ops = &bf5xx_tdm_dai_ops,
};
-EXPORT_SYMBOL_GPL(bf5xx_tdm_dai);
static int __devinit bfin_tdm_probe(struct platform_device *pdev)
{
@@ -320,7 +317,7 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
goto sport_config_err;
}
- ret = snd_soc_register_dai(&bf5xx_tdm_dai);
+ ret = snd_soc_register_dai(&pdev->dev, &bf5xx_tdm_dai);
if (ret) {
pr_err("Failed to register DAI: %d\n", ret);
goto sport_config_err;
@@ -337,7 +334,7 @@ sport_config_err:
static int __devexit bfin_tdm_remove(struct platform_device *pdev)
{
peripheral_free_list(&sport_req[sport_num][0]);
- snd_soc_unregister_dai(&bf5xx_tdm_dai);
+ snd_soc_unregister_dai(&pdev->dev);
return 0;
}
diff --git a/sound/soc/blackfin/bf5xx-tdm.h b/sound/soc/blackfin/bf5xx-tdm.h
index 04189a18c1ba..e986a3ea3315 100644
--- a/sound/soc/blackfin/bf5xx-tdm.h
+++ b/sound/soc/blackfin/bf5xx-tdm.h
@@ -20,6 +20,4 @@ struct bf5xx_tdm_port {
int configured;
};
-extern struct snd_soc_dai bf5xx_tdm_dai;
-
#endif
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
new file mode 100644
index 000000000000..01d19e9f53f9
--- /dev/null
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -0,0 +1,1486 @@
+/*
+ * 88pm860x-codec.c -- 88PM860x ALSA SoC Audio Driver
+ *
+ * Copyright 2010 Marvell International Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.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/module.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/88pm860x.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/jack.h>
+
+#include "88pm860x-codec.h"
+
+#define MAX_NAME_LEN 20
+#define REG_CACHE_SIZE 0x40
+#define REG_CACHE_BASE 0xb0
+
+/* Status Register 1 (0x01) */
+#define REG_STATUS_1 0x01
+#define MIC_STATUS (1 << 7)
+#define HOOK_STATUS (1 << 6)
+#define HEADSET_STATUS (1 << 5)
+
+/* Mic Detection Register (0x37) */
+#define REG_MIC_DET 0x37
+#define CONTINUOUS_POLLING (3 << 1)
+#define EN_MIC_DET (1 << 0)
+#define MICDET_MASK 0x07
+
+/* Headset Detection Register (0x38) */
+#define REG_HS_DET 0x38
+#define EN_HS_DET (1 << 0)
+
+/* Misc2 Register (0x42) */
+#define REG_MISC2 0x42
+#define AUDIO_PLL (1 << 5)
+#define AUDIO_SECTION_RESET (1 << 4)
+#define AUDIO_SECTION_ON (1 << 3)
+
+/* PCM Interface Register 2 (0xb1) */
+#define PCM_INF2_BCLK (1 << 6) /* Bit clock polarity */
+#define PCM_INF2_FS (1 << 5) /* Frame Sync polarity */
+#define PCM_INF2_MASTER (1 << 4) /* Master / Slave */
+#define PCM_INF2_18WL (1 << 3) /* 18 / 16 bits */
+#define PCM_GENERAL_I2S 0
+#define PCM_EXACT_I2S 1
+#define PCM_LEFT_I2S 2
+#define PCM_RIGHT_I2S 3
+#define PCM_SHORT_FS 4
+#define PCM_LONG_FS 5
+#define PCM_MODE_MASK 7
+
+/* I2S Interface Register 4 (0xbe) */
+#define I2S_EQU_BYP (1 << 6)
+
+/* DAC Offset Register (0xcb) */
+#define DAC_MUTE (1 << 7)
+#define MUTE_LEFT (1 << 6)
+#define MUTE_RIGHT (1 << 2)
+
+/* ADC Analog Register 1 (0xd0) */
+#define REG_ADC_ANA_1 0xd0
+#define MIC1BIAS_MASK 0x60
+
+/* Earpiece/Speaker Control Register 2 (0xda) */
+#define REG_EAR2 0xda
+#define RSYNC_CHANGE (1 << 2)
+
+/* Audio Supplies Register 2 (0xdc) */
+#define REG_SUPPLIES2 0xdc
+#define LDO15_READY (1 << 4)
+#define LDO15_EN (1 << 3)
+#define CPUMP_READY (1 << 2)
+#define CPUMP_EN (1 << 1)
+#define AUDIO_EN (1 << 0)
+#define SUPPLY_MASK (LDO15_EN | CPUMP_EN | AUDIO_EN)
+
+/* Audio Enable Register 1 (0xdd) */
+#define ADC_MOD_RIGHT (1 << 1)
+#define ADC_MOD_LEFT (1 << 0)
+
+/* Audio Enable Register 2 (0xde) */
+#define ADC_LEFT (1 << 5)
+#define ADC_RIGHT (1 << 4)
+
+/* DAC Enable Register 2 (0xe1) */
+#define DAC_LEFT (1 << 5)
+#define DAC_RIGHT (1 << 4)
+#define MODULATOR (1 << 3)
+
+/* Shorts Register (0xeb) */
+#define REG_SHORTS 0xeb
+#define CLR_SHORT_LO2 (1 << 7)
+#define SHORT_LO2 (1 << 6)
+#define CLR_SHORT_LO1 (1 << 5)
+#define SHORT_LO1 (1 << 4)
+#define CLR_SHORT_HS2 (1 << 3)
+#define SHORT_HS2 (1 << 2)
+#define CLR_SHORT_HS1 (1 << 1)
+#define SHORT_HS1 (1 << 0)
+
+/*
+ * This widget should be just after DAC & PGA in DAPM power-on sequence and
+ * before DAC & PGA in DAPM power-off sequence.
+ */
+#define PM860X_DAPM_OUTPUT(wname, wevent) \
+{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
+ .shift = 0, .invert = 0, .kcontrols = NULL, \
+ .num_kcontrols = 0, .event = wevent, \
+ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, }
+
+struct pm860x_det {
+ struct snd_soc_jack *hp_jack;
+ struct snd_soc_jack *mic_jack;
+ int hp_det;
+ int mic_det;
+ int hook_det;
+ int hs_shrt;
+ int lo_shrt;
+};
+
+struct pm860x_priv {
+ unsigned int sysclk;
+ unsigned int pcmclk;
+ unsigned int dir;
+ unsigned int filter;
+ struct snd_soc_codec *codec;
+ struct i2c_client *i2c;
+ struct pm860x_chip *chip;
+ struct pm860x_det det;
+
+ int irq[4];
+ unsigned char name[4][MAX_NAME_LEN];
+ unsigned char reg_cache[REG_CACHE_SIZE];
+};
+
+/* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */
+static const DECLARE_TLV_DB_SCALE(dpga_tlv, -9450, 150, 1);
+
+/* -9dB to 0db in 3dB steps */
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -900, 300, 0);
+
+/* {-23, -17, -13.5, -11, -9, -6, -3, 0}dB */
+static const unsigned int mic_tlv[] = {
+ TLV_DB_RANGE_HEAD(5),
+ 0, 0, TLV_DB_SCALE_ITEM(-2300, 0, 0),
+ 1, 1, TLV_DB_SCALE_ITEM(-1700, 0, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(-1350, 0, 0),
+ 3, 3, TLV_DB_SCALE_ITEM(-1100, 0, 0),
+ 4, 7, TLV_DB_SCALE_ITEM(-900, 300, 0),
+};
+
+/* {0, 0, 0, -6, 0, 6, 12, 18}dB */
+static const unsigned int aux_tlv[] = {
+ TLV_DB_RANGE_HEAD(2),
+ 0, 2, TLV_DB_SCALE_ITEM(0, 0, 0),
+ 3, 7, TLV_DB_SCALE_ITEM(-600, 600, 0),
+};
+
+/* {-16, -13, -10, -7, -5.2, -3,3, -2.2, 0}dB, mute instead of -16dB */
+static const unsigned int out_tlv[] = {
+ TLV_DB_RANGE_HEAD(4),
+ 0, 3, TLV_DB_SCALE_ITEM(-1600, 300, 1),
+ 4, 4, TLV_DB_SCALE_ITEM(-520, 0, 0),
+ 5, 5, TLV_DB_SCALE_ITEM(-330, 0, 0),
+ 6, 7, TLV_DB_SCALE_ITEM(-220, 220, 0),
+};
+
+static const unsigned int st_tlv[] = {
+ TLV_DB_RANGE_HEAD(8),
+ 0, 1, TLV_DB_SCALE_ITEM(-12041, 602, 0),
+ 2, 3, TLV_DB_SCALE_ITEM(-11087, 250, 0),
+ 4, 5, TLV_DB_SCALE_ITEM(-10643, 158, 0),
+ 6, 7, TLV_DB_SCALE_ITEM(-10351, 116, 0),
+ 8, 9, TLV_DB_SCALE_ITEM(-10133, 92, 0),
+ 10, 13, TLV_DB_SCALE_ITEM(-9958, 70, 0),
+ 14, 17, TLV_DB_SCALE_ITEM(-9689, 53, 0),
+ 18, 271, TLV_DB_SCALE_ITEM(-9484, 37, 0),
+};
+
+/* Sidetone Gain = M * 2^(-5-N) */
+struct st_gain {
+ unsigned int db;
+ unsigned int m;
+ unsigned int n;
+};
+
+static struct st_gain st_table[] = {
+ {-12041, 1, 15}, {-11439, 1, 14}, {-11087, 3, 15}, {-10837, 1, 13},
+ {-10643, 5, 15}, {-10485, 3, 14}, {-10351, 7, 15}, {-10235, 1, 12},
+ {-10133, 9, 15}, {-10041, 5, 14}, { -9958, 11, 15}, { -9883, 3, 13},
+ { -9813, 13, 15}, { -9749, 7, 14}, { -9689, 15, 15}, { -9633, 1, 11},
+ { -9580, 17, 15}, { -9531, 9, 14}, { -9484, 19, 15}, { -9439, 5, 13},
+ { -9397, 21, 15}, { -9356, 11, 14}, { -9318, 23, 15}, { -9281, 3, 12},
+ { -9245, 25, 15}, { -9211, 13, 14}, { -9178, 27, 15}, { -9147, 7, 13},
+ { -9116, 29, 15}, { -9087, 15, 14}, { -9058, 31, 15}, { -9031, 1, 10},
+ { -8978, 17, 14}, { -8929, 9, 13}, { -8882, 19, 14}, { -8837, 5, 12},
+ { -8795, 21, 14}, { -8754, 11, 13}, { -8716, 23, 14}, { -8679, 3, 11},
+ { -8643, 25, 14}, { -8609, 13, 13}, { -8576, 27, 14}, { -8545, 7, 12},
+ { -8514, 29, 14}, { -8485, 15, 13}, { -8456, 31, 14}, { -8429, 1, 9},
+ { -8376, 17, 13}, { -8327, 9, 12}, { -8280, 19, 13}, { -8235, 5, 11},
+ { -8193, 21, 13}, { -8152, 11, 12}, { -8114, 23, 13}, { -8077, 3, 10},
+ { -8041, 25, 13}, { -8007, 13, 12}, { -7974, 27, 13}, { -7943, 7, 11},
+ { -7912, 29, 13}, { -7883, 15, 12}, { -7854, 31, 13}, { -7827, 1, 8},
+ { -7774, 17, 12}, { -7724, 9, 11}, { -7678, 19, 12}, { -7633, 5, 10},
+ { -7591, 21, 12}, { -7550, 11, 11}, { -7512, 23, 12}, { -7475, 3, 9},
+ { -7439, 25, 12}, { -7405, 13, 11}, { -7372, 27, 12}, { -7341, 7, 10},
+ { -7310, 29, 12}, { -7281, 15, 11}, { -7252, 31, 12}, { -7225, 1, 7},
+ { -7172, 17, 11}, { -7122, 9, 10}, { -7075, 19, 11}, { -7031, 5, 9},
+ { -6989, 21, 11}, { -6948, 11, 10}, { -6910, 23, 11}, { -6873, 3, 8},
+ { -6837, 25, 11}, { -6803, 13, 10}, { -6770, 27, 11}, { -6739, 7, 9},
+ { -6708, 29, 11}, { -6679, 15, 10}, { -6650, 31, 11}, { -6623, 1, 6},
+ { -6570, 17, 10}, { -6520, 9, 9}, { -6473, 19, 10}, { -6429, 5, 8},
+ { -6386, 21, 10}, { -6346, 11, 9}, { -6307, 23, 10}, { -6270, 3, 7},
+ { -6235, 25, 10}, { -6201, 13, 9}, { -6168, 27, 10}, { -6137, 7, 8},
+ { -6106, 29, 10}, { -6077, 15, 9}, { -6048, 31, 10}, { -6021, 1, 5},
+ { -5968, 17, 9}, { -5918, 9, 8}, { -5871, 19, 9}, { -5827, 5, 7},
+ { -5784, 21, 9}, { -5744, 11, 8}, { -5705, 23, 9}, { -5668, 3, 6},
+ { -5633, 25, 9}, { -5599, 13, 8}, { -5566, 27, 9}, { -5535, 7, 7},
+ { -5504, 29, 9}, { -5475, 15, 8}, { -5446, 31, 9}, { -5419, 1, 4},
+ { -5366, 17, 8}, { -5316, 9, 7}, { -5269, 19, 8}, { -5225, 5, 6},
+ { -5182, 21, 8}, { -5142, 11, 7}, { -5103, 23, 8}, { -5066, 3, 5},
+ { -5031, 25, 8}, { -4997, 13, 7}, { -4964, 27, 8}, { -4932, 7, 6},
+ { -4902, 29, 8}, { -4873, 15, 7}, { -4844, 31, 8}, { -4816, 1, 3},
+ { -4764, 17, 7}, { -4714, 9, 6}, { -4667, 19, 7}, { -4623, 5, 5},
+ { -4580, 21, 7}, { -4540, 11, 6}, { -4501, 23, 7}, { -4464, 3, 4},
+ { -4429, 25, 7}, { -4395, 13, 6}, { -4362, 27, 7}, { -4330, 7, 5},
+ { -4300, 29, 7}, { -4270, 15, 6}, { -4242, 31, 7}, { -4214, 1, 2},
+ { -4162, 17, 6}, { -4112, 9, 5}, { -4065, 19, 6}, { -4021, 5, 4},
+ { -3978, 21, 6}, { -3938, 11, 5}, { -3899, 23, 6}, { -3862, 3, 3},
+ { -3827, 25, 6}, { -3793, 13, 5}, { -3760, 27, 6}, { -3728, 7, 4},
+ { -3698, 29, 6}, { -3668, 15, 5}, { -3640, 31, 6}, { -3612, 1, 1},
+ { -3560, 17, 5}, { -3510, 9, 4}, { -3463, 19, 5}, { -3419, 5, 3},
+ { -3376, 21, 5}, { -3336, 11, 4}, { -3297, 23, 5}, { -3260, 3, 2},
+ { -3225, 25, 5}, { -3191, 13, 4}, { -3158, 27, 5}, { -3126, 7, 3},
+ { -3096, 29, 5}, { -3066, 15, 4}, { -3038, 31, 5}, { -3010, 1, 0},
+ { -2958, 17, 4}, { -2908, 9, 3}, { -2861, 19, 4}, { -2816, 5, 2},
+ { -2774, 21, 4}, { -2734, 11, 3}, { -2695, 23, 4}, { -2658, 3, 1},
+ { -2623, 25, 4}, { -2589, 13, 3}, { -2556, 27, 4}, { -2524, 7, 2},
+ { -2494, 29, 4}, { -2464, 15, 3}, { -2436, 31, 4}, { -2408, 2, 0},
+ { -2356, 17, 3}, { -2306, 9, 2}, { -2259, 19, 3}, { -2214, 5, 1},
+ { -2172, 21, 3}, { -2132, 11, 2}, { -2093, 23, 3}, { -2056, 3, 0},
+ { -2021, 25, 3}, { -1987, 13, 2}, { -1954, 27, 3}, { -1922, 7, 1},
+ { -1892, 29, 3}, { -1862, 15, 2}, { -1834, 31, 3}, { -1806, 4, 0},
+ { -1754, 17, 2}, { -1704, 9, 1}, { -1657, 19, 2}, { -1612, 5, 0},
+ { -1570, 21, 2}, { -1530, 11, 1}, { -1491, 23, 2}, { -1454, 6, 0},
+ { -1419, 25, 2}, { -1384, 13, 1}, { -1352, 27, 2}, { -1320, 7, 0},
+ { -1290, 29, 2}, { -1260, 15, 1}, { -1232, 31, 2}, { -1204, 8, 0},
+ { -1151, 17, 1}, { -1102, 9, 0}, { -1055, 19, 1}, { -1010, 10, 0},
+ { -968, 21, 1}, { -928, 11, 0}, { -889, 23, 1}, { -852, 12, 0},
+ { -816, 25, 1}, { -782, 13, 0}, { -750, 27, 1}, { -718, 14, 0},
+ { -688, 29, 1}, { -658, 15, 0}, { -630, 31, 1}, { -602, 16, 0},
+ { -549, 17, 0}, { -500, 18, 0}, { -453, 19, 0}, { -408, 20, 0},
+ { -366, 21, 0}, { -325, 22, 0}, { -287, 23, 0}, { -250, 24, 0},
+ { -214, 25, 0}, { -180, 26, 0}, { -148, 27, 0}, { -116, 28, 0},
+ { -86, 29, 0}, { -56, 30, 0}, { -28, 31, 0}, { 0, 0, 0},
+};
+
+static int pm860x_volatile(unsigned int reg)
+{
+ BUG_ON(reg >= REG_CACHE_SIZE);
+
+ switch (reg) {
+ case PM860X_AUDIO_SUPPLIES_2:
+ return 1;
+ }
+
+ return 0;
+}
+
+static unsigned int pm860x_read_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ unsigned char *cache = codec->reg_cache;
+
+ BUG_ON(reg >= REG_CACHE_SIZE);
+
+ if (pm860x_volatile(reg))
+ return cache[reg];
+
+ reg += REG_CACHE_BASE;
+
+ return pm860x_reg_read(codec->control_data, reg);
+}
+
+static int pm860x_write_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg, unsigned int value)
+{
+ unsigned char *cache = codec->reg_cache;
+
+ BUG_ON(reg >= REG_CACHE_SIZE);
+
+ if (!pm860x_volatile(reg))
+ cache[reg] = (unsigned char)value;
+
+ reg += REG_CACHE_BASE;
+
+ return pm860x_reg_write(codec->control_data, reg, value);
+}
+
+static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ int val[2], val2[2], i;
+
+ val[0] = snd_soc_read(codec, reg) & 0x3f;
+ val[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT) >> 4) & 0xf;
+ val2[0] = snd_soc_read(codec, reg2) & 0x3f;
+ val2[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT)) & 0xf;
+
+ for (i = 0; i < ARRAY_SIZE(st_table); i++) {
+ if ((st_table[i].m == val[0]) && (st_table[i].n == val[1]))
+ ucontrol->value.integer.value[0] = i;
+ if ((st_table[i].m == val2[0]) && (st_table[i].n == val2[1]))
+ ucontrol->value.integer.value[1] = i;
+ }
+ return 0;
+}
+
+static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ int err;
+ unsigned int val, val2;
+
+ val = ucontrol->value.integer.value[0];
+ val2 = ucontrol->value.integer.value[1];
+
+ err = snd_soc_update_bits(codec, reg, 0x3f, st_table[val].m);
+ if (err < 0)
+ return err;
+ err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0xf0,
+ st_table[val].n << 4);
+ if (err < 0)
+ return err;
+
+ err = snd_soc_update_bits(codec, reg2, 0x3f, st_table[val2].m);
+ if (err < 0)
+ return err;
+ err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0x0f,
+ st_table[val2].n);
+ return err;
+}
+
+static int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ unsigned int shift = mc->shift;
+ int max = mc->max, val, val2;
+ unsigned int mask = (1 << fls(max)) - 1;
+
+ val = snd_soc_read(codec, reg) >> shift;
+ val2 = snd_soc_read(codec, reg2) >> shift;
+ ucontrol->value.integer.value[0] = (max - val) & mask;
+ ucontrol->value.integer.value[1] = (max - val2) & mask;
+
+ return 0;
+}
+
+static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ unsigned int shift = mc->shift;
+ int max = mc->max;
+ unsigned int mask = (1 << fls(max)) - 1;
+ int err;
+ unsigned int val, val2, val_mask;
+
+ val_mask = mask << shift;
+ val = ((max - ucontrol->value.integer.value[0]) & mask);
+ val2 = ((max - ucontrol->value.integer.value[1]) & mask);
+
+ val = val << shift;
+ val2 = val2 << shift;
+
+ err = snd_soc_update_bits(codec, reg, val_mask, val);
+ if (err < 0)
+ return err;
+
+ err = snd_soc_update_bits(codec, reg2, val_mask, val2);
+ return err;
+}
+
+/* DAPM Widget Events */
+/*
+ * A lot registers are belong to RSYNC domain. It requires enabling RSYNC bit
+ * after updating these registers. Otherwise, these updated registers won't
+ * be effective.
+ */
+static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ /*
+ * In order to avoid current on the load, mute power-on and power-off
+ * should be transients.
+ * Unmute by DAC_MUTE. It should be unmuted when DAPM sequence is
+ * finished.
+ */
+ snd_soc_update_bits(codec, PM860X_DAC_OFFSET, DAC_MUTE, 0);
+ snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+ RSYNC_CHANGE, RSYNC_CHANGE);
+ return 0;
+}
+
+static int pm860x_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ unsigned int dac = 0;
+ int data;
+
+ if (!strcmp(w->name, "Left DAC"))
+ dac = DAC_LEFT;
+ if (!strcmp(w->name, "Right DAC"))
+ dac = DAC_RIGHT;
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (dac) {
+ /* Auto mute in power-on sequence. */
+ dac |= MODULATOR;
+ snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
+ DAC_MUTE, DAC_MUTE);
+ snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+ RSYNC_CHANGE, RSYNC_CHANGE);
+ /* update dac */
+ snd_soc_update_bits(codec, PM860X_DAC_EN_2,
+ dac, dac);
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ if (dac) {
+ /* Auto mute in power-off sequence. */
+ snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
+ DAC_MUTE, DAC_MUTE);
+ snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+ RSYNC_CHANGE, RSYNC_CHANGE);
+ /* update dac */
+ data = snd_soc_read(codec, PM860X_DAC_EN_2);
+ data &= ~dac;
+ if (!(data & (DAC_LEFT | DAC_RIGHT)))
+ data &= ~MODULATOR;
+ snd_soc_write(codec, PM860X_DAC_EN_2, data);
+ }
+ break;
+ }
+ return 0;
+}
+
+static const char *pm860x_opamp_texts[] = {"-50%", "-25%", "0%", "75%"};
+
+static const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"};
+
+static const struct soc_enum pm860x_hs1_opamp_enum =
+ SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_hs2_opamp_enum =
+ SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_hs1_pa_enum =
+ SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_hs2_pa_enum =
+ SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_lo1_opamp_enum =
+ SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_lo2_opamp_enum =
+ SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_lo1_pa_enum =
+ SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_lo2_pa_enum =
+ SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_spk_pa_enum =
+ SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 5, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_ear_pa_enum =
+ SOC_ENUM_SINGLE(PM860X_EAR_CTRL_2, 0, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_spk_ear_opamp_enum =
+ SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 3, 4, pm860x_opamp_texts);
+
+static const struct snd_kcontrol_new pm860x_snd_controls[] = {
+ SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2,
+ PM860X_ADC_ANA_3, 6, 3, 0, adc_tlv),
+ SOC_DOUBLE_TLV("AUX Capture Volume", PM860X_ADC_ANA_3, 0, 3, 7, 0,
+ aux_tlv),
+ SOC_SINGLE_TLV("MIC1 Capture Volume", PM860X_ADC_ANA_2, 0, 7, 0,
+ mic_tlv),
+ SOC_SINGLE_TLV("MIC3 Capture Volume", PM860X_ADC_ANA_2, 3, 7, 0,
+ mic_tlv),
+ SOC_DOUBLE_R_EXT_TLV("Sidetone Volume", PM860X_SIDETONE_L_GAIN,
+ PM860X_SIDETONE_R_GAIN, 0, ARRAY_SIZE(st_table)-1,
+ 0, snd_soc_get_volsw_2r_st,
+ snd_soc_put_volsw_2r_st, st_tlv),
+ SOC_SINGLE_TLV("Speaker Playback Volume", PM860X_EAR_CTRL_1,
+ 0, 7, 0, out_tlv),
+ SOC_DOUBLE_R_TLV("Line Playback Volume", PM860X_LO1_CTRL,
+ PM860X_LO2_CTRL, 0, 7, 0, out_tlv),
+ SOC_DOUBLE_R_TLV("Headset Playback Volume", PM860X_HS1_CTRL,
+ PM860X_HS2_CTRL, 0, 7, 0, out_tlv),
+ SOC_DOUBLE_R_EXT_TLV("Hifi Left Playback Volume",
+ PM860X_HIFIL_GAIN_LEFT,
+ PM860X_HIFIL_GAIN_RIGHT, 0, 63, 0,
+ snd_soc_get_volsw_2r_out,
+ snd_soc_put_volsw_2r_out, dpga_tlv),
+ SOC_DOUBLE_R_EXT_TLV("Hifi Right Playback Volume",
+ PM860X_HIFIR_GAIN_LEFT,
+ PM860X_HIFIR_GAIN_RIGHT, 0, 63, 0,
+ snd_soc_get_volsw_2r_out,
+ snd_soc_put_volsw_2r_out, dpga_tlv),
+ SOC_DOUBLE_R_EXT_TLV("Lofi Playback Volume", PM860X_LOFI_GAIN_LEFT,
+ PM860X_LOFI_GAIN_RIGHT, 0, 63, 0,
+ snd_soc_get_volsw_2r_out,
+ snd_soc_put_volsw_2r_out, dpga_tlv),
+ SOC_ENUM("Headset1 Operational Amplifier Current",
+ pm860x_hs1_opamp_enum),
+ SOC_ENUM("Headset2 Operational Amplifier Current",
+ pm860x_hs2_opamp_enum),
+ SOC_ENUM("Headset1 Amplifier Current", pm860x_hs1_pa_enum),
+ SOC_ENUM("Headset2 Amplifier Current", pm860x_hs2_pa_enum),
+ SOC_ENUM("Lineout1 Operational Amplifier Current",
+ pm860x_lo1_opamp_enum),
+ SOC_ENUM("Lineout2 Operational Amplifier Current",
+ pm860x_lo2_opamp_enum),
+ SOC_ENUM("Lineout1 Amplifier Current", pm860x_lo1_pa_enum),
+ SOC_ENUM("Lineout2 Amplifier Current", pm860x_lo2_pa_enum),
+ SOC_ENUM("Speaker Operational Amplifier Current",
+ pm860x_spk_ear_opamp_enum),
+ SOC_ENUM("Speaker Amplifier Current", pm860x_spk_pa_enum),
+ SOC_ENUM("Earpiece Amplifier Current", pm860x_ear_pa_enum),
+};
+
+/*
+ * DAPM Controls
+ */
+
+/* PCM Switch / PCM Interface */
+static const struct snd_kcontrol_new pcm_switch_controls =
+ SOC_DAPM_SINGLE("Switch", PM860X_ADC_EN_2, 0, 1, 0);
+
+/* AUX1 Switch */
+static const struct snd_kcontrol_new aux1_switch_controls =
+ SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 4, 1, 0);
+
+/* AUX2 Switch */
+static const struct snd_kcontrol_new aux2_switch_controls =
+ SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 5, 1, 0);
+
+/* Left Ex. PA Switch */
+static const struct snd_kcontrol_new lepa_switch_controls =
+ SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 2, 1, 0);
+
+/* Right Ex. PA Switch */
+static const struct snd_kcontrol_new repa_switch_controls =
+ SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 1, 1, 0);
+
+/* PCM Mux / Mux7 */
+static const char *aif1_text[] = {
+ "PCM L", "PCM R",
+};
+
+static const struct soc_enum aif1_enum =
+ SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 6, 2, aif1_text);
+
+static const struct snd_kcontrol_new aif1_mux =
+ SOC_DAPM_ENUM("PCM Mux", aif1_enum);
+
+/* I2S Mux / Mux9 */
+static const char *i2s_din_text[] = {
+ "DIN", "DIN1",
+};
+
+static const struct soc_enum i2s_din_enum =
+ SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 1, 2, i2s_din_text);
+
+static const struct snd_kcontrol_new i2s_din_mux =
+ SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum);
+
+/* I2S Mic Mux / Mux8 */
+static const char *i2s_mic_text[] = {
+ "Ex PA", "ADC",
+};
+
+static const struct soc_enum i2s_mic_enum =
+ SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 4, 2, i2s_mic_text);
+
+static const struct snd_kcontrol_new i2s_mic_mux =
+ SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum);
+
+/* ADCL Mux / Mux2 */
+static const char *adcl_text[] = {
+ "ADCR", "ADCL",
+};
+
+static const struct soc_enum adcl_enum =
+ SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 4, 2, adcl_text);
+
+static const struct snd_kcontrol_new adcl_mux =
+ SOC_DAPM_ENUM("ADC Left Mux", adcl_enum);
+
+/* ADCR Mux / Mux3 */
+static const char *adcr_text[] = {
+ "ADCL", "ADCR",
+};
+
+static const struct soc_enum adcr_enum =
+ SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 2, 2, adcr_text);
+
+static const struct snd_kcontrol_new adcr_mux =
+ SOC_DAPM_ENUM("ADC Right Mux", adcr_enum);
+
+/* ADCR EC Mux / Mux6 */
+static const char *adcr_ec_text[] = {
+ "ADCR", "EC",
+};
+
+static const struct soc_enum adcr_ec_enum =
+ SOC_ENUM_SINGLE(PM860X_ADC_EN_2, 3, 2, adcr_ec_text);
+
+static const struct snd_kcontrol_new adcr_ec_mux =
+ SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum);
+
+/* EC Mux / Mux4 */
+static const char *ec_text[] = {
+ "Left", "Right", "Left + Right",
+};
+
+static const struct soc_enum ec_enum =
+ SOC_ENUM_SINGLE(PM860X_EC_PATH, 1, 3, ec_text);
+
+static const struct snd_kcontrol_new ec_mux =
+ SOC_DAPM_ENUM("EC Mux", ec_enum);
+
+static const char *dac_text[] = {
+ "No input", "Right", "Left", "No input",
+};
+
+/* DAC Headset 1 Mux / Mux10 */
+static const struct soc_enum dac_hs1_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 0, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_hs1_mux =
+ SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum);
+
+/* DAC Headset 2 Mux / Mux11 */
+static const struct soc_enum dac_hs2_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 2, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_hs2_mux =
+ SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum);
+
+/* DAC Lineout 1 Mux / Mux12 */
+static const struct soc_enum dac_lo1_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 4, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_lo1_mux =
+ SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum);
+
+/* DAC Lineout 2 Mux / Mux13 */
+static const struct soc_enum dac_lo2_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 6, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_lo2_mux =
+ SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum);
+
+/* DAC Spearker Earphone Mux / Mux14 */
+static const struct soc_enum dac_spk_ear_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_2, 0, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_spk_ear_mux =
+ SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum);
+
+/* Headset 1 Mux / Mux15 */
+static const char *in_text[] = {
+ "Digital", "Analog",
+};
+
+static const struct soc_enum hs1_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 0, 2, in_text);
+
+static const struct snd_kcontrol_new hs1_mux =
+ SOC_DAPM_ENUM("Headset1 Mux", hs1_enum);
+
+/* Headset 2 Mux / Mux16 */
+static const struct soc_enum hs2_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 1, 2, in_text);
+
+static const struct snd_kcontrol_new hs2_mux =
+ SOC_DAPM_ENUM("Headset2 Mux", hs2_enum);
+
+/* Lineout 1 Mux / Mux17 */
+static const struct soc_enum lo1_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 2, 2, in_text);
+
+static const struct snd_kcontrol_new lo1_mux =
+ SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum);
+
+/* Lineout 2 Mux / Mux18 */
+static const struct soc_enum lo2_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 3, 2, in_text);
+
+static const struct snd_kcontrol_new lo2_mux =
+ SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum);
+
+/* Speaker Earpiece Demux */
+static const char *spk_text[] = {
+ "Earpiece", "Speaker",
+};
+
+static const struct soc_enum spk_enum =
+ SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 6, 2, spk_text);
+
+static const struct snd_kcontrol_new spk_demux =
+ SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum);
+
+/* MIC Mux / Mux1 */
+static const char *mic_text[] = {
+ "Mic 1", "Mic 2",
+};
+
+static const struct soc_enum mic_enum =
+ SOC_ENUM_SINGLE(PM860X_ADC_ANA_4, 4, 2, mic_text);
+
+static const struct snd_kcontrol_new mic_mux =
+ SOC_DAPM_ENUM("MIC Mux", mic_enum);
+
+static const struct snd_soc_dapm_widget pm860x_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("PCM SDI", "PCM Playback", 0,
+ PM860X_ADC_EN_2, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PCM SDO", "PCM Capture", 0,
+ PM860X_PCM_IFACE_3, 1, 1),
+
+
+ SND_SOC_DAPM_AIF_IN("I2S DIN", "I2S Playback", 0,
+ PM860X_DAC_EN_2, 0, 0),
+ SND_SOC_DAPM_AIF_IN("I2S DIN1", "I2S Playback", 0,
+ PM860X_DAC_EN_2, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("I2S DOUT", "I2S Capture", 0,
+ PM860X_I2S_IFACE_3, 5, 1),
+ SND_SOC_DAPM_MUX("I2S Mic Mux", SND_SOC_NOPM, 0, 0, &i2s_mic_mux),
+ SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adcl_mux),
+ SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcr_mux),
+ SND_SOC_DAPM_MUX("EC Mux", SND_SOC_NOPM, 0, 0, &ec_mux),
+ SND_SOC_DAPM_MUX("ADCR EC Mux", SND_SOC_NOPM, 0, 0, &adcr_ec_mux),
+ SND_SOC_DAPM_SWITCH("Left EPA", SND_SOC_NOPM, 0, 0,
+ &lepa_switch_controls),
+ SND_SOC_DAPM_SWITCH("Right EPA", SND_SOC_NOPM, 0, 0,
+ &repa_switch_controls),
+
+ SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Left ADC MOD", PM860X_ADC_EN_1,
+ 0, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Right ADC MOD", PM860X_ADC_EN_1,
+ 1, 1, 1, 0),
+ SND_SOC_DAPM_ADC("Left ADC", NULL, PM860X_ADC_EN_2, 5, 0),
+ SND_SOC_DAPM_ADC("Right ADC", NULL, PM860X_ADC_EN_2, 4, 0),
+
+ SND_SOC_DAPM_SWITCH("AUX1 Switch", SND_SOC_NOPM, 0, 0,
+ &aux1_switch_controls),
+ SND_SOC_DAPM_SWITCH("AUX2 Switch", SND_SOC_NOPM, 0, 0,
+ &aux2_switch_controls),
+
+ SND_SOC_DAPM_MUX("MIC Mux", SND_SOC_NOPM, 0, 0, &mic_mux),
+ SND_SOC_DAPM_MICBIAS("Mic1 Bias", PM860X_ADC_ANA_1, 2, 0),
+ SND_SOC_DAPM_MICBIAS("Mic3 Bias", PM860X_ADC_ANA_1, 7, 0),
+ SND_SOC_DAPM_PGA("MIC1 Volume", PM860X_ADC_EN_1, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("MIC3 Volume", PM860X_ADC_EN_1, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("AUX1 Volume", PM860X_ADC_EN_1, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("AUX2 Volume", PM860X_ADC_EN_1, 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Sidetone PGA", PM860X_ADC_EN_2, 1, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Lofi PGA", PM860X_ADC_EN_2, 2, 0, NULL, 0),
+
+ SND_SOC_DAPM_INPUT("AUX1"),
+ SND_SOC_DAPM_INPUT("AUX2"),
+ SND_SOC_DAPM_INPUT("MIC1P"),
+ SND_SOC_DAPM_INPUT("MIC1N"),
+ SND_SOC_DAPM_INPUT("MIC2P"),
+ SND_SOC_DAPM_INPUT("MIC2N"),
+ SND_SOC_DAPM_INPUT("MIC3P"),
+ SND_SOC_DAPM_INPUT("MIC3N"),
+
+ SND_SOC_DAPM_DAC_E("Left DAC", NULL, SND_SOC_NOPM, 0, 0,
+ pm860x_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("Right DAC", NULL, SND_SOC_NOPM, 0, 0,
+ pm860x_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_MUX("I2S DIN Mux", SND_SOC_NOPM, 0, 0, &i2s_din_mux),
+ SND_SOC_DAPM_MUX("DAC HS1 Mux", SND_SOC_NOPM, 0, 0, &dac_hs1_mux),
+ SND_SOC_DAPM_MUX("DAC HS2 Mux", SND_SOC_NOPM, 0, 0, &dac_hs2_mux),
+ SND_SOC_DAPM_MUX("DAC LO1 Mux", SND_SOC_NOPM, 0, 0, &dac_lo1_mux),
+ SND_SOC_DAPM_MUX("DAC LO2 Mux", SND_SOC_NOPM, 0, 0, &dac_lo2_mux),
+ SND_SOC_DAPM_MUX("DAC SP Mux", SND_SOC_NOPM, 0, 0, &dac_spk_ear_mux),
+ SND_SOC_DAPM_MUX("Headset1 Mux", SND_SOC_NOPM, 0, 0, &hs1_mux),
+ SND_SOC_DAPM_MUX("Headset2 Mux", SND_SOC_NOPM, 0, 0, &hs2_mux),
+ SND_SOC_DAPM_MUX("Lineout1 Mux", SND_SOC_NOPM, 0, 0, &lo1_mux),
+ SND_SOC_DAPM_MUX("Lineout2 Mux", SND_SOC_NOPM, 0, 0, &lo2_mux),
+ SND_SOC_DAPM_MUX("Speaker Earpiece Demux", SND_SOC_NOPM, 0, 0,
+ &spk_demux),
+
+
+ SND_SOC_DAPM_PGA("Headset1 PGA", PM860X_DAC_EN_1, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Headset2 PGA", PM860X_DAC_EN_1, 1, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("HS1"),
+ SND_SOC_DAPM_OUTPUT("HS2"),
+ SND_SOC_DAPM_PGA("Lineout1 PGA", PM860X_DAC_EN_1, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Lineout2 PGA", PM860X_DAC_EN_1, 3, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+ SND_SOC_DAPM_PGA("Earpiece PGA", PM860X_DAC_EN_1, 4, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("EARP"),
+ SND_SOC_DAPM_OUTPUT("EARN"),
+ SND_SOC_DAPM_PGA("Speaker PGA", PM860X_DAC_EN_1, 5, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("LSP"),
+ SND_SOC_DAPM_OUTPUT("LSN"),
+ SND_SOC_DAPM_REG(snd_soc_dapm_supply, "VCODEC", PM860X_AUDIO_SUPPLIES_2,
+ 0, SUPPLY_MASK, SUPPLY_MASK, 0),
+
+ PM860X_DAPM_OUTPUT("RSYNC", pm860x_rsync_event),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* supply */
+ {"Left DAC", NULL, "VCODEC"},
+ {"Right DAC", NULL, "VCODEC"},
+ {"Left ADC", NULL, "VCODEC"},
+ {"Right ADC", NULL, "VCODEC"},
+ {"Left ADC", NULL, "Left ADC MOD"},
+ {"Right ADC", NULL, "Right ADC MOD"},
+
+ /* PCM/AIF1 Inputs */
+ {"PCM SDO", NULL, "ADC Left Mux"},
+ {"PCM SDO", NULL, "ADCR EC Mux"},
+
+ /* PCM/AFI2 Outputs */
+ {"Lofi PGA", NULL, "PCM SDI"},
+ {"Lofi PGA", NULL, "Sidetone PGA"},
+ {"Left DAC", NULL, "Lofi PGA"},
+ {"Right DAC", NULL, "Lofi PGA"},
+
+ /* I2S/AIF2 Inputs */
+ {"MIC Mux", "Mic 1", "MIC1P"},
+ {"MIC Mux", "Mic 1", "MIC1N"},
+ {"MIC Mux", "Mic 2", "MIC2P"},
+ {"MIC Mux", "Mic 2", "MIC2N"},
+ {"MIC1 Volume", NULL, "MIC Mux"},
+ {"MIC3 Volume", NULL, "MIC3P"},
+ {"MIC3 Volume", NULL, "MIC3N"},
+ {"Left ADC", NULL, "MIC1 Volume"},
+ {"Right ADC", NULL, "MIC3 Volume"},
+ {"ADC Left Mux", "ADCR", "Right ADC"},
+ {"ADC Left Mux", "ADCL", "Left ADC"},
+ {"ADC Right Mux", "ADCL", "Left ADC"},
+ {"ADC Right Mux", "ADCR", "Right ADC"},
+ {"Left EPA", "Switch", "Left DAC"},
+ {"Right EPA", "Switch", "Right DAC"},
+ {"EC Mux", "Left", "Left DAC"},
+ {"EC Mux", "Right", "Right DAC"},
+ {"EC Mux", "Left + Right", "Left DAC"},
+ {"EC Mux", "Left + Right", "Right DAC"},
+ {"ADCR EC Mux", "ADCR", "ADC Right Mux"},
+ {"ADCR EC Mux", "EC", "EC Mux"},
+ {"I2S Mic Mux", "Ex PA", "Left EPA"},
+ {"I2S Mic Mux", "Ex PA", "Right EPA"},
+ {"I2S Mic Mux", "ADC", "ADC Left Mux"},
+ {"I2S Mic Mux", "ADC", "ADCR EC Mux"},
+ {"I2S DOUT", NULL, "I2S Mic Mux"},
+
+ /* I2S/AIF2 Outputs */
+ {"I2S DIN Mux", "DIN", "I2S DIN"},
+ {"I2S DIN Mux", "DIN1", "I2S DIN1"},
+ {"Left DAC", NULL, "I2S DIN Mux"},
+ {"Right DAC", NULL, "I2S DIN Mux"},
+ {"DAC HS1 Mux", "Left", "Left DAC"},
+ {"DAC HS1 Mux", "Right", "Right DAC"},
+ {"DAC HS2 Mux", "Left", "Left DAC"},
+ {"DAC HS2 Mux", "Right", "Right DAC"},
+ {"DAC LO1 Mux", "Left", "Left DAC"},
+ {"DAC LO1 Mux", "Right", "Right DAC"},
+ {"DAC LO2 Mux", "Left", "Left DAC"},
+ {"DAC LO2 Mux", "Right", "Right DAC"},
+ {"Headset1 Mux", "Digital", "DAC HS1 Mux"},
+ {"Headset2 Mux", "Digital", "DAC HS2 Mux"},
+ {"Lineout1 Mux", "Digital", "DAC LO1 Mux"},
+ {"Lineout2 Mux", "Digital", "DAC LO2 Mux"},
+ {"Headset1 PGA", NULL, "Headset1 Mux"},
+ {"Headset2 PGA", NULL, "Headset2 Mux"},
+ {"Lineout1 PGA", NULL, "Lineout1 Mux"},
+ {"Lineout2 PGA", NULL, "Lineout2 Mux"},
+ {"DAC SP Mux", "Left", "Left DAC"},
+ {"DAC SP Mux", "Right", "Right DAC"},
+ {"Speaker Earpiece Demux", "Speaker", "DAC SP Mux"},
+ {"Speaker PGA", NULL, "Speaker Earpiece Demux"},
+ {"Earpiece PGA", NULL, "Speaker Earpiece Demux"},
+
+ {"RSYNC", NULL, "Headset1 PGA"},
+ {"RSYNC", NULL, "Headset2 PGA"},
+ {"RSYNC", NULL, "Lineout1 PGA"},
+ {"RSYNC", NULL, "Lineout2 PGA"},
+ {"RSYNC", NULL, "Speaker PGA"},
+ {"RSYNC", NULL, "Speaker PGA"},
+ {"RSYNC", NULL, "Earpiece PGA"},
+ {"RSYNC", NULL, "Earpiece PGA"},
+
+ {"HS1", NULL, "RSYNC"},
+ {"HS2", NULL, "RSYNC"},
+ {"LINEOUT1", NULL, "RSYNC"},
+ {"LINEOUT2", NULL, "RSYNC"},
+ {"LSP", NULL, "RSYNC"},
+ {"LSN", NULL, "RSYNC"},
+ {"EARP", NULL, "RSYNC"},
+ {"EARN", NULL, "RSYNC"},
+};
+
+/*
+ * Use MUTE_LEFT & MUTE_RIGHT to implement digital mute.
+ * These bits can also be used to mute.
+ */
+static int pm860x_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ int data = 0, mask = MUTE_LEFT | MUTE_RIGHT;
+
+ if (mute)
+ data = mask;
+ snd_soc_update_bits(codec, PM860X_DAC_OFFSET, mask, data);
+ snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+ RSYNC_CHANGE, RSYNC_CHANGE);
+ return 0;
+}
+
+static int pm860x_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ unsigned char inf = 0, mask = 0;
+
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ inf &= ~PCM_INF2_18WL;
+ break;
+ case SNDRV_PCM_FORMAT_S18_3LE:
+ inf |= PCM_INF2_18WL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ mask |= PCM_INF2_18WL;
+ snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
+
+ /* sample rate */
+ switch (params_rate(params)) {
+ case 8000:
+ inf = 0;
+ break;
+ case 16000:
+ inf = 3;
+ break;
+ case 32000:
+ inf = 6;
+ break;
+ case 48000:
+ inf = 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec, PM860X_PCM_RATE, 0x0f, inf);
+
+ return 0;
+}
+
+static int pm860x_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+ unsigned char inf = 0, mask = 0;
+ int ret = -EINVAL;
+
+ mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ if (pm860x->dir == PM860X_CLK_DIR_OUT) {
+ inf |= PCM_INF2_MASTER;
+ ret = 0;
+ }
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ if (pm860x->dir == PM860X_CLK_DIR_IN) {
+ inf &= ~PCM_INF2_MASTER;
+ ret = 0;
+ }
+ break;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ inf |= PCM_EXACT_I2S;
+ ret = 0;
+ break;
+ }
+ mask |= PCM_MODE_MASK;
+ if (ret)
+ return ret;
+ snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
+ return 0;
+}
+
+static int pm860x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+
+ if (dir == PM860X_CLK_DIR_OUT)
+ pm860x->dir = PM860X_CLK_DIR_OUT;
+ else {
+ pm860x->dir = PM860X_CLK_DIR_IN;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int pm860x_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ unsigned char inf;
+
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ inf = 0;
+ break;
+ case SNDRV_PCM_FORMAT_S18_3LE:
+ inf = PCM_INF2_18WL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, PCM_INF2_18WL, inf);
+
+ /* sample rate */
+ switch (params_rate(params)) {
+ case 8000:
+ inf = 0;
+ break;
+ case 11025:
+ inf = 1;
+ break;
+ case 16000:
+ inf = 3;
+ break;
+ case 22050:
+ inf = 4;
+ break;
+ case 32000:
+ inf = 6;
+ break;
+ case 44100:
+ inf = 7;
+ break;
+ case 48000:
+ inf = 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec, PM860X_I2S_IFACE_4, 0xf, inf);
+
+ return 0;
+}
+
+static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+ unsigned char inf = 0, mask = 0;
+
+ mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ if (pm860x->dir == PM860X_CLK_DIR_OUT)
+ inf |= PCM_INF2_MASTER;
+ else
+ return -EINVAL;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ if (pm860x->dir == PM860X_CLK_DIR_IN)
+ inf &= ~PCM_INF2_MASTER;
+ else
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ inf |= PCM_EXACT_I2S;
+ break;
+ default:
+ return -EINVAL;
+ }
+ mask |= PCM_MODE_MASK;
+ snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, mask, inf);
+ return 0;
+}
+
+static int pm860x_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ int data;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ /* Enable Audio PLL & Audio section */
+ data = AUDIO_PLL | AUDIO_SECTION_RESET
+ | AUDIO_SECTION_ON;
+ pm860x_reg_write(codec->control_data, REG_MISC2, data);
+ }
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON;
+ pm860x_set_bits(codec->control_data, REG_MISC2, data, 0);
+ break;
+ }
+ codec->bias_level = level;
+ return 0;
+}
+
+static struct snd_soc_dai_ops pm860x_pcm_dai_ops = {
+ .digital_mute = pm860x_digital_mute,
+ .hw_params = pm860x_pcm_hw_params,
+ .set_fmt = pm860x_pcm_set_dai_fmt,
+ .set_sysclk = pm860x_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops pm860x_i2s_dai_ops = {
+ .digital_mute = pm860x_digital_mute,
+ .hw_params = pm860x_i2s_hw_params,
+ .set_fmt = pm860x_i2s_set_dai_fmt,
+ .set_sysclk = pm860x_set_dai_sysclk,
+};
+
+#define PM860X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+
+static struct snd_soc_dai_driver pm860x_dai[] = {
+ {
+ /* DAI PCM */
+ .name = "88pm860x-pcm",
+ .id = 1,
+ .playback = {
+ .stream_name = "PCM Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = PM860X_RATES,
+ .formats = SNDRV_PCM_FORMAT_S16_LE | \
+ SNDRV_PCM_FORMAT_S18_3LE,
+ },
+ .capture = {
+ .stream_name = "PCM Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = PM860X_RATES,
+ .formats = SNDRV_PCM_FORMAT_S16_LE | \
+ SNDRV_PCM_FORMAT_S18_3LE,
+ },
+ .ops = &pm860x_pcm_dai_ops,
+ }, {
+ /* DAI I2S */
+ .name = "88pm860x-i2s",
+ .id = 2,
+ .playback = {
+ .stream_name = "I2S Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FORMAT_S16_LE | \
+ SNDRV_PCM_FORMAT_S18_3LE,
+ },
+ .capture = {
+ .stream_name = "I2S Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FORMAT_S16_LE | \
+ SNDRV_PCM_FORMAT_S18_3LE,
+ },
+ .ops = &pm860x_i2s_dai_ops,
+ },
+};
+
+static irqreturn_t pm860x_codec_handler(int irq, void *data)
+{
+ struct pm860x_priv *pm860x = data;
+ int status, shrt, report = 0, mic_report = 0;
+ int mask;
+
+ status = pm860x_reg_read(pm860x->i2c, REG_STATUS_1);
+ shrt = pm860x_reg_read(pm860x->i2c, REG_SHORTS);
+ mask = pm860x->det.hs_shrt | pm860x->det.hook_det | pm860x->det.lo_shrt
+ | pm860x->det.hp_det;
+
+ if ((pm860x->det.hp_det & SND_JACK_HEADPHONE)
+ && (status & HEADSET_STATUS))
+ report |= SND_JACK_HEADPHONE;
+
+ if ((pm860x->det.mic_det & SND_JACK_MICROPHONE)
+ && (status & MIC_STATUS))
+ mic_report |= SND_JACK_MICROPHONE;
+
+ if (pm860x->det.hs_shrt && (shrt & (SHORT_HS1 | SHORT_HS2)))
+ report |= pm860x->det.hs_shrt;
+
+ if (pm860x->det.hook_det && (status & HOOK_STATUS))
+ report |= pm860x->det.hook_det;
+
+ if (pm860x->det.lo_shrt && (shrt & (SHORT_LO1 | SHORT_LO2)))
+ report |= pm860x->det.lo_shrt;
+
+ if (report)
+ snd_soc_jack_report(pm860x->det.hp_jack, report, mask);
+ if (mic_report)
+ snd_soc_jack_report(pm860x->det.mic_jack, SND_JACK_MICROPHONE,
+ SND_JACK_MICROPHONE);
+
+ dev_dbg(pm860x->codec->dev, "headphone report:0x%x, mask:%x\n",
+ report, mask);
+ dev_dbg(pm860x->codec->dev, "microphone report:0x%x\n", mic_report);
+ return IRQ_HANDLED;
+}
+
+int pm860x_hs_jack_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack,
+ int det, int hook, int hs_shrt, int lo_shrt)
+{
+ struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+ int data;
+
+ pm860x->det.hp_jack = jack;
+ pm860x->det.hp_det = det;
+ pm860x->det.hook_det = hook;
+ pm860x->det.hs_shrt = hs_shrt;
+ pm860x->det.lo_shrt = lo_shrt;
+
+ if (det & SND_JACK_HEADPHONE)
+ pm860x_set_bits(codec->control_data, REG_HS_DET,
+ EN_HS_DET, EN_HS_DET);
+ /* headset short detect */
+ if (hs_shrt) {
+ data = CLR_SHORT_HS2 | CLR_SHORT_HS1;
+ pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
+ }
+ /* Lineout short detect */
+ if (lo_shrt) {
+ data = CLR_SHORT_LO2 | CLR_SHORT_LO1;
+ pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
+ }
+
+ /* sync status */
+ pm860x_codec_handler(0, pm860x);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pm860x_hs_jack_detect);
+
+int pm860x_mic_jack_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack, int det)
+{
+ struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+
+ pm860x->det.mic_jack = jack;
+ pm860x->det.mic_det = det;
+
+ if (det & SND_JACK_MICROPHONE)
+ pm860x_set_bits(codec->control_data, REG_MIC_DET,
+ MICDET_MASK, MICDET_MASK);
+
+ /* sync status */
+ pm860x_codec_handler(0, pm860x);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pm860x_mic_jack_detect);
+
+static int pm860x_probe(struct snd_soc_codec *codec)
+{
+ struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+ int i, ret;
+
+ pm860x->codec = codec;
+
+ codec->control_data = pm860x->i2c;
+
+ for (i = 0; i < 4; i++) {
+ ret = request_threaded_irq(pm860x->irq[i], NULL,
+ pm860x_codec_handler, IRQF_ONESHOT,
+ pm860x->name[i], pm860x);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to request IRQ!\n");
+ goto out_irq;
+ }
+ }
+
+ pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ ret = pm860x_bulk_read(codec->control_data, REG_CACHE_BASE,
+ REG_CACHE_SIZE, codec->reg_cache);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to fill register cache: %d\n",
+ ret);
+ goto out_codec;
+ }
+
+ snd_soc_add_controls(codec, pm860x_snd_controls,
+ ARRAY_SIZE(pm860x_snd_controls));
+ snd_soc_dapm_new_controls(codec, pm860x_dapm_widgets,
+ ARRAY_SIZE(pm860x_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+ return 0;
+
+out_codec:
+ i = 3;
+out_irq:
+ for (; i >= 0; i--)
+ free_irq(pm860x->irq[i], pm860x);
+ return -EINVAL;
+}
+
+static int pm860x_remove(struct snd_soc_codec *codec)
+{
+ struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+ int i;
+
+ for (i = 3; i >= 0; i--)
+ free_irq(pm860x->irq[i], pm860x);
+ pm860x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_pm860x = {
+ .probe = pm860x_probe,
+ .remove = pm860x_remove,
+ .read = pm860x_read_reg_cache,
+ .write = pm860x_write_reg_cache,
+ .reg_cache_size = REG_CACHE_SIZE,
+ .reg_word_size = sizeof(u8),
+ .set_bias_level = pm860x_set_bias_level,
+};
+
+static int __devinit pm860x_codec_probe(struct platform_device *pdev)
+{
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct pm860x_priv *pm860x;
+ struct resource *res;
+ int i, ret;
+
+ pm860x = kzalloc(sizeof(struct pm860x_priv), GFP_KERNEL);
+ if (pm860x == NULL)
+ return -ENOMEM;
+
+ pm860x->chip = chip;
+ pm860x->i2c = (chip->id == CHIP_PM8607) ? chip->client
+ : chip->companion;
+ platform_set_drvdata(pdev, pm860x);
+
+ for (i = 0; i < 4; i++) {
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get IRQ resources\n");
+ goto out;
+ }
+ pm860x->irq[i] = res->start + chip->irq_base;
+ strncpy(pm860x->name[i], res->name, MAX_NAME_LEN);
+ }
+
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pm860x,
+ pm860x_dai, ARRAY_SIZE(pm860x_dai));
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register codec\n");
+ goto out;
+ }
+ return ret;
+
+out:
+ platform_set_drvdata(pdev, NULL);
+ kfree(pm860x);
+ return -EINVAL;
+}
+
+static int __devexit pm860x_codec_remove(struct platform_device *pdev)
+{
+ struct pm860x_priv *pm860x = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_codec(&pdev->dev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(pm860x);
+ return 0;
+}
+
+static struct platform_driver pm860x_codec_driver = {
+ .driver = {
+ .name = "88pm860x-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = pm860x_codec_probe,
+ .remove = __devexit_p(pm860x_codec_remove),
+};
+
+static __init int pm860x_init(void)
+{
+ return platform_driver_register(&pm860x_codec_driver);
+}
+module_init(pm860x_init);
+
+static __exit void pm860x_exit(void)
+{
+ platform_driver_unregister(&pm860x_codec_driver);
+}
+module_exit(pm860x_exit);
+
+MODULE_DESCRIPTION("ASoC 88PM860x driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:88pm860x-codec");
+
diff --git a/sound/soc/codecs/88pm860x-codec.h b/sound/soc/codecs/88pm860x-codec.h
new file mode 100644
index 000000000000..3364ba4a3607
--- /dev/null
+++ b/sound/soc/codecs/88pm860x-codec.h
@@ -0,0 +1,97 @@
+/*
+ * 88pm860x-codec.h -- 88PM860x ALSA SoC Audio Driver
+ *
+ * Copyright 2010 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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 __88PM860X_H
+#define __88PM860X_H
+
+/* The offset of these registers are 0xb0 */
+#define PM860X_PCM_IFACE_1 0x00
+#define PM860X_PCM_IFACE_2 0x01
+#define PM860X_PCM_IFACE_3 0x02
+#define PM860X_PCM_RATE 0x03
+#define PM860X_EC_PATH 0x04
+#define PM860X_SIDETONE_L_GAIN 0x05
+#define PM860X_SIDETONE_R_GAIN 0x06
+#define PM860X_SIDETONE_SHIFT 0x07
+#define PM860X_ADC_OFFSET_1 0x08
+#define PM860X_ADC_OFFSET_2 0x09
+#define PM860X_DMIC_DELAY 0x0a
+
+#define PM860X_I2S_IFACE_1 0x0b
+#define PM860X_I2S_IFACE_2 0x0c
+#define PM860X_I2S_IFACE_3 0x0d
+#define PM860X_I2S_IFACE_4 0x0e
+#define PM860X_EQUALIZER_N0_1 0x0f
+#define PM860X_EQUALIZER_N0_2 0x10
+#define PM860X_EQUALIZER_N1_1 0x11
+#define PM860X_EQUALIZER_N1_2 0x12
+#define PM860X_EQUALIZER_D1_1 0x13
+#define PM860X_EQUALIZER_D1_2 0x14
+#define PM860X_LOFI_GAIN_LEFT 0x15
+#define PM860X_LOFI_GAIN_RIGHT 0x16
+#define PM860X_HIFIL_GAIN_LEFT 0x17
+#define PM860X_HIFIL_GAIN_RIGHT 0x18
+#define PM860X_HIFIR_GAIN_LEFT 0x19
+#define PM860X_HIFIR_GAIN_RIGHT 0x1a
+#define PM860X_DAC_OFFSET 0x1b
+#define PM860X_OFFSET_LEFT_1 0x1c
+#define PM860X_OFFSET_LEFT_2 0x1d
+#define PM860X_OFFSET_RIGHT_1 0x1e
+#define PM860X_OFFSET_RIGHT_2 0x1f
+#define PM860X_ADC_ANA_1 0x20
+#define PM860X_ADC_ANA_2 0x21
+#define PM860X_ADC_ANA_3 0x22
+#define PM860X_ADC_ANA_4 0x23
+#define PM860X_ANA_TO_ANA 0x24
+#define PM860X_HS1_CTRL 0x25
+#define PM860X_HS2_CTRL 0x26
+#define PM860X_LO1_CTRL 0x27
+#define PM860X_LO2_CTRL 0x28
+#define PM860X_EAR_CTRL_1 0x29
+#define PM860X_EAR_CTRL_2 0x2a
+#define PM860X_AUDIO_SUPPLIES_1 0x2b
+#define PM860X_AUDIO_SUPPLIES_2 0x2c
+#define PM860X_ADC_EN_1 0x2d
+#define PM860X_ADC_EN_2 0x2e
+#define PM860X_DAC_EN_1 0x2f
+#define PM860X_DAC_EN_2 0x31
+#define PM860X_AUDIO_CAL_1 0x32
+#define PM860X_AUDIO_CAL_2 0x33
+#define PM860X_AUDIO_CAL_3 0x34
+#define PM860X_AUDIO_CAL_4 0x35
+#define PM860X_AUDIO_CAL_5 0x36
+#define PM860X_ANA_INPUT_SEL_1 0x37
+#define PM860X_ANA_INPUT_SEL_2 0x38
+
+#define PM860X_PCM_IFACE_4 0x39
+#define PM860X_I2S_IFACE_5 0x3a
+
+#define PM860X_SHORTS 0x3b
+#define PM860X_PLL_ADJ_1 0x3c
+#define PM860X_PLL_ADJ_2 0x3d
+
+/* bits definition */
+#define PM860X_CLK_DIR_IN 0
+#define PM860X_CLK_DIR_OUT 1
+
+#define PM860X_DET_HEADSET (1 << 0)
+#define PM860X_DET_MIC (1 << 1)
+#define PM860X_DET_HOOK (1 << 2)
+#define PM860X_SHORT_HEADSET (1 << 3)
+#define PM860X_SHORT_LINEOUT (1 << 4)
+#define PM860X_DET_MASK 0x1F
+
+extern int pm860x_hs_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
+ int, int, int, int);
+extern int pm860x_mic_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
+ int);
+
+#endif /* __88PM860X_H */
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 83f5c67d3c41..94a9d06b9027 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -10,6 +10,7 @@ config SND_SOC_I2C_AND_SPI
config SND_SOC_ALL_CODECS
tristate "Build all ASoC CODEC drivers"
+ select SND_SOC_88PM860X if MFD_88PM860X
select SND_SOC_L3
select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
select SND_SOC_AD1836 if SPI_MASTER
@@ -26,6 +27,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS4270 if I2C
select SND_SOC_DA7210 if I2C
select SND_SOC_JZ4740 if SOC_JZ4740
+ select SND_SOC_MAX98088 if I2C
select SND_SOC_MAX9877 if I2C
select SND_SOC_PCM3008
select SND_SOC_SPDIF
@@ -40,6 +42,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TWL6040 if TWL4030_CORE
select SND_SOC_UDA134X
select SND_SOC_UDA1380 if I2C
+ select SND_SOC_WL1273 if WL1273_CORE
select SND_SOC_WM2000 if I2C
select SND_SOC_WM8350 if MFD_WM8350
select SND_SOC_WM8400 if MFD_WM8400
@@ -54,6 +57,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
+ select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8900 if I2C
select SND_SOC_WM8903 if I2C
select SND_SOC_WM8904 if I2C
@@ -61,9 +65,11 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8955 if I2C
select SND_SOC_WM8960 if I2C
select SND_SOC_WM8961 if I2C
+ select SND_SOC_WM8962 if I2C
select SND_SOC_WM8971 if I2C
select SND_SOC_WM8974 if I2C
select SND_SOC_WM8978 if I2C
+ select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8990 if I2C
select SND_SOC_WM8993 if I2C
@@ -84,6 +90,9 @@ config SND_SOC_ALL_CODECS
If unsure select "N".
+config SND_SOC_88PM860X
+ tristate
+
config SND_SOC_WM_HUBS
tristate
default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
@@ -150,6 +159,9 @@ config SND_SOC_L3
config SND_SOC_DA7210
tristate
+config SND_SOC_MAX98088
+ tristate
+
config SND_SOC_PCM3008
tristate
@@ -188,6 +200,9 @@ config SND_SOC_UDA134X
config SND_SOC_UDA1380
tristate
+config SND_SOC_WL1273
+ tristate
+
config SND_SOC_WM8350
tristate
@@ -227,6 +242,9 @@ config SND_SOC_WM8753
config SND_SOC_WM8776
tristate
+config SND_SOC_WM8804
+ tristate
+
config SND_SOC_WM8900
tristate
@@ -248,6 +266,9 @@ config SND_SOC_WM8960
config SND_SOC_WM8961
tristate
+config SND_SOC_WM8962
+ tristate
+
config SND_SOC_WM8971
tristate
@@ -257,6 +278,9 @@ config SND_SOC_WM8974
config SND_SOC_WM8978
tristate
+config SND_SOC_WM8985
+ tristate
+
config SND_SOC_WM8988
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 53524095759c..f67a2d6f7a46 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,3 +1,4 @@
+snd-soc-88pm860x-objs := 88pm860x-codec.o
snd-soc-ac97-objs := ac97.o
snd-soc-ad1836-objs := ad1836.o
snd-soc-ad193x-objs := ad193x.o
@@ -14,6 +15,7 @@ snd-soc-cs4270-objs := cs4270.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
snd-soc-l3-objs := l3.o
+snd-soc-max98088-objs := max98088.o
snd-soc-pcm3008-objs := pcm3008.o
snd-soc-spdif-objs := spdif_transciever.o
snd-soc-ssm2602-objs := ssm2602.o
@@ -26,6 +28,7 @@ snd-soc-twl4030-objs := twl4030.o
snd-soc-twl6040-objs := twl6040.o
snd-soc-uda134x-objs := uda134x.o
snd-soc-uda1380-objs := uda1380.o
+snd-soc-wl1273-objs := wl1273.o
snd-soc-wm8350-objs := wm8350.o
snd-soc-wm8400-objs := wm8400.o
snd-soc-wm8510-objs := wm8510.o
@@ -39,6 +42,7 @@ snd-soc-wm8741-objs := wm8741.o
snd-soc-wm8750-objs := wm8750.o
snd-soc-wm8753-objs := wm8753.o
snd-soc-wm8776-objs := wm8776.o
+snd-soc-wm8804-objs := wm8804.o
snd-soc-wm8900-objs := wm8900.o
snd-soc-wm8903-objs := wm8903.o
snd-soc-wm8904-objs := wm8904.o
@@ -46,9 +50,11 @@ snd-soc-wm8940-objs := wm8940.o
snd-soc-wm8955-objs := wm8955.o
snd-soc-wm8960-objs := wm8960.o
snd-soc-wm8961-objs := wm8961.o
+snd-soc-wm8962-objs := wm8962.o
snd-soc-wm8971-objs := wm8971.o
snd-soc-wm8974-objs := wm8974.o
snd-soc-wm8978-objs := wm8978.o
+snd-soc-wm8985-objs := wm8985.o
snd-soc-wm8988-objs := wm8988.o
snd-soc-wm8990-objs := wm8990.o
snd-soc-wm8993-objs := wm8993.o
@@ -66,6 +72,7 @@ snd-soc-tpa6130a2-objs := tpa6130a2.o
snd-soc-wm2000-objs := wm2000.o
snd-soc-wm9090-objs := wm9090.o
+obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o
@@ -83,6 +90,7 @@ obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
+obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
@@ -95,6 +103,7 @@ obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
+obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o
obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o
obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o
obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o
@@ -108,6 +117,7 @@ obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o
obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o
+obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o
obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o
obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o
obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o
@@ -115,9 +125,11 @@ obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o
obj-$(CONFIG_SND_SOC_WM8955) += snd-soc-wm8955.o
obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o
obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o
+obj-$(CONFIG_SND_SOC_WM8962) += snd-soc-wm8962.o
obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o
obj-$(CONFIG_SND_SOC_WM8978) += snd-soc-wm8978.o
+obj-$(CONFIG_SND_SOC_WM8985) += snd-soc-wm8985.o
obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o
obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 1f5e57a4bb7a..3c087936aa57 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -21,17 +21,13 @@
#include <sound/ac97_codec.h>
#include <sound/initval.h>
#include <sound/soc.h>
-#include "ac97.h"
-
-#define AC97_VERSION "0.6"
static int ac97_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
@@ -46,8 +42,8 @@ static struct snd_soc_dai_ops ac97_dai_ops = {
.prepare = ac97_prepare,
};
-struct snd_soc_dai ac97_dai = {
- .name = "AC97 HiFi",
+static struct snd_soc_dai_driver ac97_dai = {
+ .name = "ac97-hifi",
.ac97_control = 1,
.playback = {
.stream_name = "AC97 Playback",
@@ -63,7 +59,6 @@ struct snd_soc_dai ac97_dai = {
.formats = SND_SOC_STD_AC97_FMTS,},
.ops = &ac97_dai_ops,
};
-EXPORT_SYMBOL_GPL(ac97_dai);
static unsigned int ac97_read(struct snd_soc_codec *codec,
unsigned int reg)
@@ -78,95 +73,41 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
return 0;
}
-static int ac97_soc_probe(struct platform_device *pdev)
+static int ac97_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_codec *codec;
struct snd_ac97_bus *ac97_bus;
struct snd_ac97_template ac97_template;
- int i;
- int ret = 0;
-
- printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION);
-
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (!socdev->card->codec)
- return -ENOMEM;
- codec = socdev->card->codec;
- mutex_init(&codec->mutex);
-
- codec->name = "AC97";
- codec->owner = THIS_MODULE;
- codec->dai = &ac97_dai;
- codec->num_dai = 1;
- codec->write = ac97_write;
- codec->read = ac97_read;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0)
- goto err;
+ int ret;
/* add codec as bus device for standard ac97 */
- ret = snd_ac97_bus(codec->card, 0, &soc_ac97_ops, NULL, &ac97_bus);
+ ret = snd_ac97_bus(codec->card->snd_card, 0, &soc_ac97_ops, NULL, &ac97_bus);
if (ret < 0)
- goto bus_err;
+ return ret;
memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
if (ret < 0)
- goto bus_err;
-
- for (i = 0; i < card->num_links; i++) {
- if (card->dai_link[i].codec_dai->ac97_control) {
- snd_ac97_dev_add_pdata(codec->ac97,
- card->dai_link[i].cpu_dai->ac97_pdata);
- }
- }
+ return ret;
return 0;
-
-bus_err:
- snd_soc_free_pcms(socdev);
-
-err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
- return ret;
}
-static int ac97_soc_remove(struct platform_device *pdev)
+static int ac97_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (!codec)
- return 0;
-
- snd_soc_free_pcms(socdev);
- kfree(socdev->card->codec);
-
return 0;
}
#ifdef CONFIG_PM
-static int ac97_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+static int ac97_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_ac97_suspend(socdev->card->codec->ac97);
+ snd_ac97_suspend(codec->ac97);
return 0;
}
-static int ac97_soc_resume(struct platform_device *pdev)
+static int ac97_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_ac97_resume(socdev->card->codec->ac97);
+ snd_ac97_resume(codec->ac97);
return 0;
}
@@ -175,14 +116,50 @@ static int ac97_soc_resume(struct platform_device *pdev)
#define ac97_soc_resume NULL
#endif
-struct snd_soc_codec_device soc_codec_dev_ac97 = {
+static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
+ .write = ac97_write,
+ .read = ac97_read,
.probe = ac97_soc_probe,
.remove = ac97_soc_remove,
.suspend = ac97_soc_suspend,
.resume = ac97_soc_resume,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ac97);
+
+static __devinit int ac97_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_ac97, &ac97_dai, 1);
+}
+
+static int __devexit ac97_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver ac97_codec_driver = {
+ .driver = {
+ .name = "ac97-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = ac97_probe,
+ .remove = __devexit_p(ac97_remove),
+};
+
+static int __init ac97_init(void)
+{
+ return platform_driver_register(&ac97_codec_driver);
+}
+module_init(ac97_init);
+
+static void __exit ac97_exit(void)
+{
+ platform_driver_unregister(&ac97_codec_driver);
+}
+module_exit(ac97_exit);
MODULE_DESCRIPTION("Soc Generic AC97 driver");
MODULE_AUTHOR("Liam Girdwood");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ac97-codec");
diff --git a/sound/soc/codecs/ac97.h b/sound/soc/codecs/ac97.h
deleted file mode 100644
index 281aa42e2bbb..000000000000
--- a/sound/soc/codecs/ac97.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * linux/sound/codecs/ac97.h -- ALSA SoC Layer
- *
- * Author: Liam Girdwood
- * Created: Dec 1st 2005
- * Copyright: Wolfson Microelectronics. PLC.
- *
- * 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_SND_SOC_AC97_H
-#define __LINUX_SND_SOC_AC97_H
-
-extern struct snd_soc_codec_device soc_codec_dev_ac97;
-extern struct snd_soc_dai ac97_dai;
-
-#endif
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index a01006c8c606..d272534c8f84 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -33,15 +33,10 @@
/* codec private data */
struct ad1836_priv {
- struct snd_soc_codec codec;
- u16 reg_cache[AD1836_NUM_REGS];
+ enum snd_soc_control_type control_type;
+ void *control_data;
};
-static struct snd_soc_codec *ad1836_codec;
-struct snd_soc_codec_device soc_codec_dev_ad1836;
-static int ad1836_register(struct ad1836_priv *ad1836);
-static void ad1836_unregister(struct ad1836_priv *ad1836);
-
/*
* AD1836 volume/mute/de-emphasis etc. controls
*/
@@ -146,8 +141,7 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
int word_len = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* bit size */
switch (params_format(params)) {
@@ -173,12 +167,9 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
}
#ifdef CONFIG_PM
-static int ad1836_soc_suspend(struct platform_device *pdev,
+static int ad1836_soc_suspend(struct snd_soc_codec *codec,
pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
/* reset clock control mode */
u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
@@ -186,11 +177,8 @@ static int ad1836_soc_suspend(struct platform_device *pdev,
return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
}
-static int ad1836_soc_resume(struct platform_device *pdev)
+static int ad1836_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
/* restore clock control mode */
u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
adc_ctrl2 |= AD1836_ADC_AUX;
@@ -202,49 +190,14 @@ static int ad1836_soc_resume(struct platform_device *pdev)
#define ad1836_soc_resume NULL
#endif
-static int __devinit ad1836_spi_probe(struct spi_device *spi)
-{
- struct snd_soc_codec *codec;
- struct ad1836_priv *ad1836;
-
- ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL);
- if (ad1836 == NULL)
- return -ENOMEM;
-
- codec = &ad1836->codec;
- codec->control_data = spi;
- codec->dev = &spi->dev;
-
- dev_set_drvdata(&spi->dev, ad1836);
-
- return ad1836_register(ad1836);
-}
-
-static int __devexit ad1836_spi_remove(struct spi_device *spi)
-{
- struct ad1836_priv *ad1836 = dev_get_drvdata(&spi->dev);
-
- ad1836_unregister(ad1836);
- return 0;
-}
-
-static struct spi_driver ad1836_spi_driver = {
- .driver = {
- .name = "ad1836",
- .owner = THIS_MODULE,
- },
- .probe = ad1836_spi_probe,
- .remove = __devexit_p(ad1836_spi_remove),
-};
-
static struct snd_soc_dai_ops ad1836_dai_ops = {
.hw_params = ad1836_hw_params,
.set_fmt = ad1836_set_dai_fmt,
};
/* codec DAI instance */
-struct snd_soc_dai ad1836_dai = {
- .name = "AD1836",
+static struct snd_soc_dai_driver ad1836_dai = {
+ .name = "ad1836-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -263,35 +216,13 @@ struct snd_soc_dai ad1836_dai = {
},
.ops = &ad1836_dai_ops,
};
-EXPORT_SYMBOL_GPL(ad1836_dai);
-static int ad1836_register(struct ad1836_priv *ad1836)
+static int ad1836_probe(struct snd_soc_codec *codec)
{
- int ret;
- struct snd_soc_codec *codec = &ad1836->codec;
-
- if (ad1836_codec) {
- dev_err(codec->dev, "Another ad1836 is registered\n");
- kfree(ad1836);
- return -EINVAL;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
- snd_soc_codec_set_drvdata(codec, ad1836);
- codec->reg_cache = ad1836->reg_cache;
- codec->reg_cache_size = AD1836_NUM_REGS;
- codec->name = "AD1836";
- codec->owner = THIS_MODULE;
- codec->dai = &ad1836_dai;
- codec->num_dai = 1;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- ad1836_dai.dev = codec->dev;
- ad1836_codec = codec;
+ struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+ codec->control_data = ad1836->control_data;
ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI);
if (ret < 0) {
dev_err(codec->dev, "failed to set cache I/O: %d\n",
@@ -319,81 +250,69 @@ static int ad1836_register(struct ad1836_priv *ad1836)
snd_soc_write(codec, AD1836_DAC_L3_VOL, 0x3FF);
snd_soc_write(codec, AD1836_DAC_R3_VOL, 0x3FF);
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- kfree(ad1836);
- return ret;
- }
-
- ret = snd_soc_register_dai(&ad1836_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- kfree(ad1836);
- return ret;
- }
-
- return 0;
-}
-
-static void ad1836_unregister(struct ad1836_priv *ad1836)
-{
- snd_soc_unregister_dai(&ad1836_dai);
- snd_soc_unregister_codec(&ad1836->codec);
- kfree(ad1836);
- ad1836_codec = NULL;
-}
-
-static int ad1836_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (ad1836_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = ad1836_codec;
- codec = ad1836_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
snd_soc_add_controls(codec, ad1836_snd_controls,
ARRAY_SIZE(ad1836_snd_controls));
snd_soc_dapm_new_controls(codec, ad1836_dapm_widgets,
ARRAY_SIZE(ad1836_dapm_widgets));
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
-pcm_err:
return ret;
}
/* power down chip */
-static int ad1836_remove(struct platform_device *pdev)
+static int ad1836_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
+ /* reset clock control mode */
+ u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
+ adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
- return 0;
+ return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
}
-struct snd_soc_codec_device soc_codec_dev_ad1836 = {
+static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
.probe = ad1836_probe,
.remove = ad1836_remove,
.suspend = ad1836_soc_suspend,
.resume = ad1836_soc_resume,
+ .reg_cache_size = AD1836_NUM_REGS,
+ .reg_word_size = sizeof(u16),
+};
+
+static int __devinit ad1836_spi_probe(struct spi_device *spi)
+{
+ struct ad1836_priv *ad1836;
+ int ret;
+
+ ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL);
+ if (ad1836 == NULL)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, ad1836);
+ ad1836->control_data = spi;
+ ad1836->control_type = SND_SOC_SPI;
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_ad1836, &ad1836_dai, 1);
+ if (ret < 0)
+ kfree(ad1836);
+ return ret;
+}
+
+static int __devexit ad1836_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
+}
+
+static struct spi_driver ad1836_spi_driver = {
+ .driver = {
+ .name = "ad1836-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = ad1836_spi_probe,
+ .remove = __devexit_p(ad1836_spi_remove),
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836);
static int __init ad1836_init(void)
{
diff --git a/sound/soc/codecs/ad1836.h b/sound/soc/codecs/ad1836.h
index e9d90d3951c5..845596717fdf 100644
--- a/sound/soc/codecs/ad1836.h
+++ b/sound/soc/codecs/ad1836.h
@@ -60,6 +60,4 @@
#define AD1836_NUM_REGS 16
-extern struct snd_soc_dai ad1836_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad1836;
#endif
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index 1def75e4862f..fa2834c91b9f 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -24,9 +24,10 @@
/* codec private data */
struct ad193x_priv {
- unsigned int sysclk;
- struct snd_soc_codec codec;
u8 reg_cache[AD193X_NUM_REGS];
+ enum snd_soc_control_type bus_type;
+ void *control_data;
+ int sysclk;
};
/* ad193x register cache & default register settings */
@@ -34,9 +35,6 @@ 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,
};
-static struct snd_soc_codec *ad193x_codec;
-struct snd_soc_codec_device soc_codec_dev_ad193x;
-
/*
* AD193X volume/mute/de-emphasis etc. controls
*/
@@ -275,8 +273,7 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
int word_len = 0, reg = 0, master_rate = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
/* bit size */
@@ -323,100 +320,6 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type)
-{
- struct snd_soc_codec *codec;
- struct ad193x_priv *ad193x;
- int ret;
-
- if (ad193x_codec) {
- dev_err(dev, "Another ad193x is registered\n");
- return -EINVAL;
- }
-
- ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
- if (ad193x == NULL)
- return -ENOMEM;
-
- dev_set_drvdata(dev, ad193x);
-
- codec = &ad193x->codec;
- mutex_init(&codec->mutex);
- codec->control_data = ctrl_data;
- codec->dev = dev;
- snd_soc_codec_set_drvdata(codec, ad193x);
- codec->reg_cache = ad193x->reg_cache;
- codec->reg_cache_size = AD193X_NUM_REGS;
- codec->name = "AD193X";
- codec->owner = THIS_MODULE;
- codec->dai = &ad193x_dai;
- codec->num_dai = 1;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- ad193x_dai.dev = codec->dev;
- ad193x_codec = codec;
-
- memcpy(codec->reg_cache, ad193x_reg, AD193X_NUM_REGS);
-
- if (bus_type == SND_SOC_I2C)
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, bus_type);
- else
- ret = snd_soc_codec_set_cache_io(codec, 16, 8, bus_type);
- if (ret < 0) {
- dev_err(codec->dev, "failed to set cache I/O: %d\n",
- ret);
- kfree(ad193x);
- return ret;
- }
-
- /* default setting for ad193x */
-
- /* unmute dac channels */
- snd_soc_write(codec, AD193X_DAC_CHNL_MUTE, 0x0);
- /* de-emphasis: 48kHz, powedown dac */
- snd_soc_write(codec, AD193X_DAC_CTRL2, 0x1A);
- /* powerdown dac, dac in tdm mode */
- snd_soc_write(codec, AD193X_DAC_CTRL0, 0x41);
- /* high-pass filter enable */
- snd_soc_write(codec, AD193X_ADC_CTRL0, 0x3);
- /* sata delay=1, adc aux mode */
- snd_soc_write(codec, AD193X_ADC_CTRL1, 0x43);
- /* pll input: mclki/xi */
- snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
- snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
- ad193x->sysclk = 12288000;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- kfree(ad193x);
- return ret;
- }
-
- ret = snd_soc_register_dai(&ad193x_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- kfree(ad193x);
- return ret;
- }
-
- return 0;
-}
-
-static int ad193x_bus_remove(struct device *dev)
-{
- struct ad193x_priv *ad193x = dev_get_drvdata(dev);
-
- snd_soc_unregister_dai(&ad193x_dai);
- snd_soc_unregister_codec(&ad193x->codec);
- kfree(ad193x);
- ad193x_codec = NULL;
-
- return 0;
-}
-
static struct snd_soc_dai_ops ad193x_dai_ops = {
.hw_params = ad193x_hw_params,
.digital_mute = ad193x_mute,
@@ -426,8 +329,8 @@ static struct snd_soc_dai_ops ad193x_dai_ops = {
};
/* codec DAI instance */
-struct snd_soc_dai ad193x_dai = {
- .name = "AD193X",
+static struct snd_soc_dai_driver ad193x_dai = {
+ .name = "ad193x-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -446,28 +349,39 @@ struct snd_soc_dai ad193x_dai = {
},
.ops = &ad193x_dai_ops,
};
-EXPORT_SYMBOL_GPL(ad193x_dai);
-static int ad193x_probe(struct platform_device *pdev)
+static int ad193x_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
+ struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
+ int ret;
- if (ad193x_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
+ codec->control_data = ad193x->control_data;
+ if (ad193x->bus_type == SND_SOC_I2C)
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->bus_type);
+ else
+ ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->bus_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to set cache I/O: %d\n",
+ ret);
+ kfree(ad193x);
+ return ret;
}
- socdev->card->codec = ad193x_codec;
- codec = ad193x_codec;
+ /* default setting for ad193x */
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
+ /* unmute dac channels */
+ snd_soc_write(codec, AD193X_DAC_CHNL_MUTE, 0x0);
+ /* de-emphasis: 48kHz, powedown dac */
+ snd_soc_write(codec, AD193X_DAC_CTRL2, 0x1A);
+ /* powerdown dac, dac in tdm mode */
+ snd_soc_write(codec, AD193X_DAC_CTRL0, 0x41);
+ /* high-pass filter enable */
+ snd_soc_write(codec, AD193X_ADC_CTRL0, 0x3);
+ /* sata delay=1, adc aux mode */
+ snd_soc_write(codec, AD193X_ADC_CTRL1, 0x43);
+ /* pll input: mclki/xi */
+ snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
+ snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
snd_soc_add_controls(codec, ad193x_snd_controls,
ARRAY_SIZE(ad193x_snd_controls));
@@ -475,41 +389,47 @@ static int ad193x_probe(struct platform_device *pdev)
ARRAY_SIZE(ad193x_dapm_widgets));
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
-pcm_err:
return ret;
}
-/* power down chip */
-static int ad193x_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ad193x = {
+static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
.probe = ad193x_probe,
- .remove = ad193x_remove,
+ .reg_cache_default = ad193x_reg,
+ .reg_cache_size = AD193X_NUM_REGS,
+ .reg_word_size = sizeof(u16),
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad193x);
#if defined(CONFIG_SPI_MASTER)
static int __devinit ad193x_spi_probe(struct spi_device *spi)
{
- return ad193x_bus_probe(&spi->dev, spi, SND_SOC_SPI);
+ struct ad193x_priv *ad193x;
+ int ret;
+
+ ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
+ if (ad193x == NULL)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, ad193x);
+ ad193x->control_data = spi;
+ ad193x->bus_type = SND_SOC_SPI;
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_ad193x, &ad193x_dai, 1);
+ if (ret < 0)
+ kfree(ad193x);
+ return ret;
}
static int __devexit ad193x_spi_remove(struct spi_device *spi)
{
- return ad193x_bus_remove(&spi->dev);
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
}
static struct spi_driver ad193x_spi_driver = {
.driver = {
- .name = "ad193x",
+ .name = "ad193x-codec",
.owner = THIS_MODULE,
},
.probe = ad193x_spi_probe,
@@ -528,17 +448,34 @@ MODULE_DEVICE_TABLE(i2c, ad193x_id);
static int __devinit ad193x_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- return ad193x_bus_probe(&client->dev, client, SND_SOC_I2C);
+ struct ad193x_priv *ad193x;
+ int ret;
+
+ ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
+ if (ad193x == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, ad193x);
+ ad193x->control_data = client;
+ ad193x->bus_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&client->dev,
+ &soc_codec_dev_ad193x, &ad193x_dai, 1);
+ if (ret < 0)
+ kfree(ad193x);
+ return ret;
}
static int __devexit ad193x_i2c_remove(struct i2c_client *client)
{
- return ad193x_bus_remove(&client->dev);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
}
static struct i2c_driver ad193x_i2c_driver = {
.driver = {
- .name = "ad193x",
+ .name = "ad193x-codec",
},
.probe = ad193x_i2c_probe,
.remove = __devexit_p(ad193x_i2c_remove),
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h
index 654ba64ae04c..9747b5497877 100644
--- a/sound/soc/codecs/ad193x.h
+++ b/sound/soc/codecs/ad193x.h
@@ -80,7 +80,4 @@
#define AD193X_NUM_REGS 17
-extern struct snd_soc_dai ad193x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad193x;
-
#endif
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 70cfaec3be2c..410ccd5d41cd 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -33,11 +33,6 @@
#include "ad1980.h"
-static unsigned int ac97_read(struct snd_soc_codec *codec,
- unsigned int reg);
-static int ac97_write(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int val);
-
/*
* AD1980 register cache
*/
@@ -138,8 +133,8 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
return 0;
}
-struct snd_soc_dai ad1980_dai = {
- .name = "AC97",
+static struct snd_soc_dai_driver ad1980_dai = {
+ .name = "ad1980-hifi",
.ac97_control = 1,
.playback = {
.stream_name = "Playback",
@@ -185,53 +180,20 @@ err:
return -EIO;
}
-static int ad1980_soc_probe(struct platform_device *pdev)
+static int ad1980_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
+ int ret;
u16 vendor_id2;
u16 ext_status;
printk(KERN_INFO "AD1980 SoC Audio Codec\n");
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (socdev->card->codec == NULL)
- return -ENOMEM;
- codec = socdev->card->codec;
- mutex_init(&codec->mutex);
-
- codec->reg_cache =
- kzalloc(sizeof(u16) * ARRAY_SIZE(ad1980_reg), GFP_KERNEL);
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto cache_err;
- }
- memcpy(codec->reg_cache, ad1980_reg, sizeof(u16) * \
- ARRAY_SIZE(ad1980_reg));
- codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(ad1980_reg);
- codec->reg_cache_step = 2;
- codec->name = "AD1980";
- codec->owner = THIS_MODULE;
- codec->dai = &ad1980_dai;
- codec->num_dai = 1;
- codec->write = ac97_write;
- codec->read = ac97_read;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
if (ret < 0) {
printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
- goto codec_err;
+ return ret;
}
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0)
- goto pcm_err;
-
-
ret = ad1980_reset(codec, 0);
if (ret < 0) {
printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n");
@@ -270,41 +232,60 @@ static int ad1980_soc_probe(struct platform_device *pdev)
return 0;
reset_err:
- snd_soc_free_pcms(socdev);
-
-pcm_err:
snd_soc_free_ac97_codec(codec);
-
-codec_err:
- kfree(codec->reg_cache);
-
-cache_err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
return ret;
}
-static int ad1980_soc_remove(struct platform_device *pdev)
+static int ad1980_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec == NULL)
- return 0;
-
- snd_soc_dapm_free(socdev);
- snd_soc_free_pcms(socdev);
snd_soc_free_ac97_codec(codec);
- kfree(codec->reg_cache);
- kfree(codec);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_ad1980 = {
+static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
.probe = ad1980_soc_probe,
.remove = ad1980_soc_remove,
+ .reg_cache_size = ARRAY_SIZE(ad1980_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = ad1980_reg,
+ .reg_cache_step = 2,
+ .write = ac97_write,
+ .read = ac97_read,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980);
+
+static __devinit int ad1980_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_ad1980, &ad1980_dai, 1);
+}
+
+static int __devexit ad1980_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver ad1980_codec_driver = {
+ .driver = {
+ .name = "ad1980-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = ad1980_probe,
+ .remove = __devexit_p(ad1980_remove),
+};
+
+static int __init ad1980_init(void)
+{
+ return platform_driver_register(&ad1980_codec_driver);
+}
+module_init(ad1980_init);
+
+static void __exit ad1980_exit(void)
+{
+ platform_driver_unregister(&ad1980_codec_driver);
+}
+module_exit(ad1980_exit);
MODULE_DESCRIPTION("ASoC ad1980 driver (Obsolete)");
MODULE_AUTHOR("Roy Huang, Cliff Cai");
diff --git a/sound/soc/codecs/ad1980.h b/sound/soc/codecs/ad1980.h
index 538f37c90806..eb0af44ad3df 100644
--- a/sound/soc/codecs/ad1980.h
+++ b/sound/soc/codecs/ad1980.h
@@ -23,7 +23,4 @@
#define PR5 0x2000
#define PR6 0x4000
-extern struct snd_soc_dai ad1980_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad1980;
-
#endif
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
index 475807bea2c2..de799cd1ba72 100644
--- a/sound/soc/codecs/ad73311.c
+++ b/sound/soc/codecs/ad73311.c
@@ -23,8 +23,8 @@
#include "ad73311.h"
-struct snd_soc_dai ad73311_dai = {
- .name = "AD73311",
+static struct snd_soc_dai_driver ad73311_dai = {
+ .name = "ad73311-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -38,68 +38,40 @@ struct snd_soc_dai ad73311_dai = {
.rates = SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
};
-EXPORT_SYMBOL_GPL(ad73311_dai);
-static int ad73311_soc_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
- mutex_init(&codec->mutex);
- codec->name = "AD73311";
- codec->owner = THIS_MODULE;
- codec->dai = &ad73311_dai;
- codec->num_dai = 1;
- socdev->card->codec = codec;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "ad73311: failed to create pcms\n");
- goto pcm_err;
- }
-
- return ret;
+static struct snd_soc_codec_driver soc_codec_dev_ad73311;
-pcm_err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
- return ret;
+static int ad73311_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_ad73311, &ad73311_dai, 1);
}
-static int ad73311_soc_remove(struct platform_device *pdev)
+static int __devexit ad73311_remove(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec == NULL)
- return 0;
- snd_soc_free_pcms(socdev);
- kfree(codec);
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_ad73311 = {
- .probe = ad73311_soc_probe,
- .remove = ad73311_soc_remove,
+static struct platform_driver ad73311_codec_driver = {
+ .driver = {
+ .name = "ad73311-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = ad73311_probe,
+ .remove = __devexit_p(ad73311_remove),
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311);
static int __init ad73311_init(void)
{
- return snd_soc_register_dai(&ad73311_dai);
+ return platform_driver_register(&ad73311_codec_driver);
}
module_init(ad73311_init);
static void __exit ad73311_exit(void)
{
- snd_soc_unregister_dai(&ad73311_dai);
+ platform_driver_unregister(&ad73311_codec_driver);
}
module_exit(ad73311_exit);
diff --git a/sound/soc/codecs/ad73311.h b/sound/soc/codecs/ad73311.h
index 569573d2d4d7..4b353eefc0bf 100644
--- a/sound/soc/codecs/ad73311.h
+++ b/sound/soc/codecs/ad73311.h
@@ -85,6 +85,4 @@
#define REGF_INV (1 << 6)
#define REGF_ALB (1 << 7)
-extern struct snd_soc_dai ad73311_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad73311;
#endif
diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c
index f8e75edb27b7..8402854ec15e 100644
--- a/sound/soc/codecs/ads117x.c
+++ b/sound/soc/codecs/ads117x.c
@@ -19,16 +19,12 @@
#include <sound/initval.h>
#include <sound/soc.h>
-#include "ads117x.h"
-
#define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000)
-
#define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
-struct snd_soc_dai ads117x_dai = {
+static struct snd_soc_dai_driver ads117x_dai = {
/* ADC */
- .name = "ADS117X ADC",
- .id = 1,
+ .name = "ads117x-hifi",
.capture = {
.stream_name = "Capture",
.channels_min = 1,
@@ -36,75 +32,29 @@ struct snd_soc_dai ads117x_dai = {
.rates = ADS117X_RATES,
.formats = ADS117X_FORMATS,},
};
-EXPORT_SYMBOL_GPL(ads117x_dai);
-
-static int ads117x_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret;
-
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
- codec->name = "ADS117X";
- codec->owner = THIS_MODULE;
- codec->dai = &ads117x_dai;
- codec->num_dai = 1;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "ads117x: failed to create pcms\n");
- kfree(codec);
- return ret;
- }
-
- return 0;
-}
-
-static int ads117x_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- snd_soc_free_pcms(socdev);
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ads117x = {
- .probe = ads117x_probe,
- .remove = ads117x_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ads117x);
+static struct snd_soc_codec_driver soc_codec_dev_ads117x;
-static __devinit int ads117x_platform_probe(struct platform_device *pdev)
+static __devinit int ads117x_probe(struct platform_device *pdev)
{
- ads117x_dai.dev = &pdev->dev;
- return snd_soc_register_dai(&ads117x_dai);
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_ads117x, &ads117x_dai, 1);
}
-static int __devexit ads117x_platform_remove(struct platform_device *pdev)
+static int __devexit ads117x_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&ads117x_dai);
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static struct platform_driver ads117x_codec_driver = {
.driver = {
- .name = "ads117x",
+ .name = "ads117x-codec",
.owner = THIS_MODULE,
},
- .probe = ads117x_platform_probe,
- .remove = __devexit_p(ads117x_platform_remove),
+ .probe = ads117x_probe,
+ .remove = __devexit_p(ads117x_remove),
};
static int __init ads117x_init(void)
diff --git a/sound/soc/codecs/ads117x.h b/sound/soc/codecs/ads117x.h
index dbcf50ec9bd1..3ce028614002 100644
--- a/sound/soc/codecs/ads117x.h
+++ b/sound/soc/codecs/ads117x.h
@@ -9,5 +9,5 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
-extern struct snd_soc_dai ads117x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ads117x;
+extern struct snd_soc_dai_driver ads117x_dai;
+extern struct snd_soc_codec_driver soc_codec_dev_ads117x;
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index 192aebda3029..c27f8f59dc66 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -17,8 +17,6 @@
#include <linux/spi/spi.h>
#include <sound/asoundef.h>
-#include "ak4104.h"
-
/* AK4104 registers addresses */
#define AK4104_REG_CONTROL1 0x00
#define AK4104_REG_RESERVED 0x01
@@ -45,11 +43,11 @@
#define AK4104_TX_TXE (1 << 0)
#define AK4104_TX_V (1 << 1)
-#define DRV_NAME "ak4104"
+#define DRV_NAME "ak4104-codec"
struct ak4104_private {
- struct snd_soc_codec codec;
- u8 reg_cache[AK4104_NUM_REGS];
+ enum snd_soc_control_type control_type;
+ void *control_data;
};
static int ak4104_fill_cache(struct snd_soc_codec *codec)
@@ -58,7 +56,7 @@ static int ak4104_fill_cache(struct snd_soc_codec *codec)
u8 *reg_cache = codec->reg_cache;
struct spi_device *spi = codec->control_data;
- for (i = 0; i < codec->reg_cache_size; i++) {
+ for (i = 0; i < codec->driver->reg_cache_size; i++) {
int ret = spi_w8r8(spi, i | AK4104_READ);
if (ret < 0) {
dev_err(&spi->dev, "SPI write failure\n");
@@ -76,7 +74,7 @@ static unsigned int ak4104_read_reg_cache(struct snd_soc_codec *codec,
{
u8 *reg_cache = codec->reg_cache;
- if (reg >= codec->reg_cache_size)
+ if (reg >= codec->driver->reg_cache_size)
return -EINVAL;
return reg_cache[reg];
@@ -88,7 +86,7 @@ static int ak4104_spi_write(struct snd_soc_codec *codec, unsigned int reg,
u8 *cache = codec->reg_cache;
struct spi_device *spi = codec->control_data;
- if (reg >= codec->reg_cache_size)
+ if (reg >= codec->driver->reg_cache_size)
return -EINVAL;
/* only write to the hardware if value has changed */
@@ -145,8 +143,7 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
int val = 0;
/* set the IEC958 bits: consumer mode, no copyright bit */
@@ -178,8 +175,8 @@ static struct snd_soc_dai_ops ak4101_dai_ops = {
.set_fmt = ak4104_set_dai_fmt,
};
-struct snd_soc_dai ak4104_dai = {
- .name = DRV_NAME,
+static struct snd_soc_dai_driver ak4104_dai = {
+ .name = "ak4104-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -192,45 +189,17 @@ struct snd_soc_dai ak4104_dai = {
.ops = &ak4101_dai_ops,
};
-static struct snd_soc_codec *ak4104_codec;
-
-static int ak4104_spi_probe(struct spi_device *spi)
+static int ak4104_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec;
- struct ak4104_private *ak4104;
+ struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
int ret, val;
- spi->bits_per_word = 8;
- spi->mode = SPI_MODE_0;
- ret = spi_setup(spi);
- if (ret < 0)
- return ret;
-
- ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL);
- if (!ak4104) {
- dev_err(&spi->dev, "could not allocate codec\n");
- return -ENOMEM;
- }
-
- codec = &ak4104->codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->dev = &spi->dev;
- codec->name = DRV_NAME;
- codec->owner = THIS_MODULE;
- codec->dai = &ak4104_dai;
- codec->num_dai = 1;
- snd_soc_codec_set_drvdata(codec, ak4104);
- codec->control_data = spi;
- codec->reg_cache = ak4104->reg_cache;
- codec->reg_cache_size = AK4104_NUM_REGS;
+ codec->control_data = ak4104->control_data;
/* read all regs and fill the cache */
ret = ak4104_fill_cache(codec);
if (ret < 0) {
- dev_err(&spi->dev, "failed to fill register cache\n");
+ dev_err(codec->dev, "failed to fill register cache\n");
return ret;
}
@@ -238,93 +207,81 @@ static int ak4104_spi_probe(struct spi_device *spi)
* should contain 0x5b. Not a good way to verify the presence of
* the device, but there is no hardware ID register. */
if (ak4104_read_reg_cache(codec, AK4104_REG_RESERVED) !=
- AK4104_RESERVED_VAL) {
- ret = -ENODEV;
- goto error_free_codec;
- }
+ AK4104_RESERVED_VAL)
+ return -ENODEV;
/* set power-up and non-reset bits */
val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
val |= AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN;
ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
if (ret < 0)
- goto error_free_codec;
+ return ret;
/* enable transmitter */
val = ak4104_read_reg_cache(codec, AK4104_REG_TX);
val |= AK4104_TX_TXE;
ret = ak4104_spi_write(codec, AK4104_REG_TX, val);
if (ret < 0)
- goto error_free_codec;
-
- ak4104_codec = codec;
- ret = snd_soc_register_dai(&ak4104_dai);
- if (ret < 0) {
- dev_err(&spi->dev, "failed to register DAI\n");
- goto error_free_codec;
- }
+ return ret;
- spi_set_drvdata(spi, ak4104);
- dev_info(&spi->dev, "SPI device initialized\n");
+ dev_info(codec->dev, "SPI device initialized\n");
return 0;
-
-error_free_codec:
- kfree(ak4104);
- ak4104_dai.dev = NULL;
- return ret;
}
-static int __devexit ak4104_spi_remove(struct spi_device *spi)
+static int ak4104_remove(struct snd_soc_codec *codec)
{
- int ret, val;
- struct ak4104_private *ak4104 = spi_get_drvdata(spi);
+ int val, ret;
- val = ak4104_read_reg_cache(&ak4104->codec, AK4104_REG_CONTROL1);
+ val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
if (val < 0)
return val;
/* clear power-up and non-reset bits */
val &= ~(AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
- ret = ak4104_spi_write(&ak4104->codec, AK4104_REG_CONTROL1, val);
- if (ret < 0)
- return ret;
+ ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
- ak4104_codec = NULL;
- kfree(ak4104);
- return 0;
+ return ret;
}
-static int ak4104_probe(struct platform_device *pdev)
+static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
+ .probe = ak4104_probe,
+ .remove = ak4104_remove,
+ .reg_cache_size = AK4104_NUM_REGS,
+ .reg_word_size = sizeof(u16),
+};
+
+static int ak4104_spi_probe(struct spi_device *spi)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = ak4104_codec;
+ struct ak4104_private *ak4104;
int ret;
- /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */
- socdev->card->codec = codec;
-
- /* Register PCMs */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms\n");
+ spi->bits_per_word = 8;
+ spi->mode = SPI_MODE_0;
+ ret = spi_setup(spi);
+ if (ret < 0)
return ret;
- }
- return 0;
+ ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL);
+ if (ak4104 == NULL)
+ return -ENOMEM;
+
+ ak4104->control_data = spi;
+ ak4104->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, ak4104);
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_device_ak4104, &ak4104_dai, 1);
+ if (ret < 0)
+ kfree(ak4104);
+ return ret;
}
-static int ak4104_remove(struct platform_device *pdev)
+static int __devexit ak4104_spi_remove(struct spi_device *spi)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- snd_soc_free_pcms(socdev);
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
return 0;
-};
-
-struct snd_soc_codec_device soc_codec_device_ak4104 = {
- .probe = ak4104_probe,
- .remove = ak4104_remove
-};
-EXPORT_SYMBOL_GPL(soc_codec_device_ak4104);
+}
static struct spi_driver ak4104_spi_driver = {
.driver = {
diff --git a/sound/soc/codecs/ak4104.h b/sound/soc/codecs/ak4104.h
deleted file mode 100644
index eb88fe7e4def..000000000000
--- a/sound/soc/codecs/ak4104.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _AK4104_H
-#define _AK4104_H
-
-extern struct snd_soc_dai ak4104_dai;
-extern struct snd_soc_codec_device soc_codec_device_ak4104;
-
-#endif
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index d4253675b2d3..cd88c8f32a38 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -31,11 +31,11 @@
#define AK4535_VERSION "0.3"
-struct snd_soc_codec_device soc_codec_dev_ak4535;
-
/* codec private data */
struct ak4535_priv {
unsigned int sysclk;
+ enum snd_soc_control_type control_type;
+ void *control_data;
};
/*
@@ -313,8 +313,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5);
int rate = params_rate(params), fs = 256;
@@ -378,14 +377,16 @@ static int ak4535_mute(struct snd_soc_dai *dai, int mute)
static int ak4535_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u16 i;
+ u16 i, mute_reg;
switch (level) {
case SND_SOC_BIAS_ON:
- ak4535_mute(codec->dai, 0);
+ mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
+ ak4535_write(codec, AK4535_DAC, mute_reg);
break;
case SND_SOC_BIAS_PREPARE:
- ak4535_mute(codec->dai, 1);
+ mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
+ ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
break;
case SND_SOC_BIAS_STANDBY:
i = ak4535_read_reg_cache(codec, AK4535_PM1);
@@ -413,8 +414,8 @@ static struct snd_soc_dai_ops ak4535_dai_ops = {
.set_sysclk = ak4535_set_dai_sysclk,
};
-struct snd_soc_dai ak4535_dai = {
- .name = "AK4535",
+static struct snd_soc_dai_driver ak4535_dai = {
+ .name = "ak4535-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -429,54 +430,27 @@ struct snd_soc_dai ak4535_dai = {
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
.ops = &ak4535_dai_ops,
};
-EXPORT_SYMBOL_GPL(ak4535_dai);
-static int ak4535_suspend(struct platform_device *pdev, pm_message_t state)
+static int ak4535_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int ak4535_resume(struct platform_device *pdev)
+static int ak4535_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
ak4535_sync(codec);
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-/*
- * initialise the AK4535 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int ak4535_init(struct snd_soc_device *socdev)
+static int ak4535_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
- int ret = 0;
+ struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
- codec->name = "AK4535";
- codec->owner = THIS_MODULE;
- codec->read = ak4535_read_reg_cache;
- codec->write = ak4535_write;
- codec->set_bias_level = ak4535_set_bias_level;
- codec->dai = &ak4535_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(ak4535_reg);
- codec->reg_cache = kmemdup(ak4535_reg, sizeof(ak4535_reg), GFP_KERNEL);
-
- if (codec->reg_cache == NULL)
- return -ENOMEM;
+ printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "ak4535: failed to create pcms\n");
- goto pcm_err;
- }
+ codec->control_data = ak4535->control_data;
/* power on device */
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -485,39 +459,55 @@ static int ak4535_init(struct snd_soc_device *socdev)
ARRAY_SIZE(ak4535_snd_controls));
ak4535_add_widgets(codec);
- return ret;
-
-pcm_err:
- kfree(codec->reg_cache);
+ return 0;
+}
- return ret;
+/* power down chip */
+static int ak4535_remove(struct snd_soc_codec *codec)
+{
+ ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
-static struct snd_soc_device *ak4535_socdev;
+static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
+ .probe = ak4535_probe,
+ .remove = ak4535_remove,
+ .suspend = ak4535_suspend,
+ .resume = ak4535_resume,
+ .read = ak4535_read_reg_cache,
+ .write = ak4535_write,
+ .set_bias_level = ak4535_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(ak4535_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = ak4535_reg,
+};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-static int ak4535_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static __devinit int ak4535_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
- struct snd_soc_device *socdev = ak4535_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct ak4535_priv *ak4535;
int ret;
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
+ ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
+ if (ak4535 == NULL)
+ return -ENOMEM;
- ret = ak4535_init(socdev);
- if (ret < 0)
- printk(KERN_ERR "failed to initialise AK4535\n");
+ i2c_set_clientdata(i2c, ak4535);
+ ak4535->control_data = i2c;
+ ak4535->control_type = SND_SOC_I2C;
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_ak4535, &ak4535_dai, 1);
+ if (ret < 0)
+ kfree(ak4535);
return ret;
}
-static int ak4535_i2c_remove(struct i2c_client *client)
+static __devexit int ak4535_i2c_remove(struct i2c_client *client)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -529,138 +519,34 @@ MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id);
static struct i2c_driver ak4535_i2c_driver = {
.driver = {
- .name = "AK4535 I2C Codec",
+ .name = "ak4535-codec",
.owner = THIS_MODULE,
},
.probe = ak4535_i2c_probe,
- .remove = ak4535_i2c_remove,
+ .remove = __devexit_p(ak4535_i2c_remove),
.id_table = ak4535_i2c_id,
};
-
-static int ak4535_add_i2c_device(struct platform_device *pdev,
- const struct ak4535_setup_data *setup)
-{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- int ret;
-
- ret = i2c_add_driver(&ak4535_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
- }
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "ak4535", I2C_NAME_SIZE);
-
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
-
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
- }
-
- return 0;
-
-err_driver:
- i2c_del_driver(&ak4535_i2c_driver);
- return -ENODEV;
-}
#endif
-static int ak4535_probe(struct platform_device *pdev)
+static int __init ak4535_modinit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct ak4535_setup_data *setup;
- struct snd_soc_codec *codec;
- struct ak4535_priv *ak4535;
- int ret;
-
- printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
-
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
- if (ak4535 == NULL) {
- kfree(codec);
- return -ENOMEM;
- }
-
- snd_soc_codec_set_drvdata(codec, ak4535);
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- ak4535_socdev = socdev;
- ret = -ENODEV;
-
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- codec->hw_write = (hw_write_t)i2c_master_send;
- ret = ak4535_add_i2c_device(pdev, setup);
- }
-#endif
-
+ ret = i2c_add_driver(&ak4535_i2c_driver);
if (ret != 0) {
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
+ printk(KERN_ERR "Failed to register AK4535 I2C driver: %d\n",
+ ret);
}
+#endif
return ret;
}
+module_init(ak4535_modinit);
-/* power down chip */
-static int ak4535_remove(struct platform_device *pdev)
+static void __exit ak4535_exit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (codec->control_data)
- i2c_unregister_device(codec->control_data);
i2c_del_driver(&ak4535_i2c_driver);
#endif
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ak4535 = {
- .probe = ak4535_probe,
- .remove = ak4535_remove,
- .suspend = ak4535_suspend,
- .resume = ak4535_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535);
-
-static int __init ak4535_modinit(void)
-{
- return snd_soc_register_dai(&ak4535_dai);
-}
-module_init(ak4535_modinit);
-
-static void __exit ak4535_exit(void)
-{
- snd_soc_unregister_dai(&ak4535_dai);
}
module_exit(ak4535_exit);
diff --git a/sound/soc/codecs/ak4535.h b/sound/soc/codecs/ak4535.h
index c7a58703ea39..0431e5f634a2 100644
--- a/sound/soc/codecs/ak4535.h
+++ b/sound/soc/codecs/ak4535.h
@@ -36,12 +36,4 @@
#define AK4535_CACHEREGNUM 0x10
-struct ak4535_setup_data {
- int i2c_bus;
- unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai ak4535_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ak4535;
-
#endif
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 3d7dc55305ec..90c90b7f4a2e 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -30,8 +30,6 @@
#include <sound/initval.h>
#include <sound/tlv.h>
-#include "ak4642.h"
-
#define AK4642_VERSION "0.0.1"
#define PW_MGMT1 0x00
@@ -74,6 +72,12 @@
#define AK4642_CACHEREGNUM 0x25
+/* PW_MGMT1*/
+#define PMVCM (1 << 6) /* VCOM Power Management */
+#define PMMIN (1 << 5) /* MIN Input Power Management */
+#define PMDAC (1 << 2) /* DAC Power Management */
+#define PMADL (1 << 0) /* MIC Amp Lch and ADC Lch Power Management */
+
/* PW_MGMT2 */
#define HPMTN (1 << 6)
#define PMHPL (1 << 5)
@@ -85,6 +89,23 @@
#define PMHP_MASK (PMHPL | PMHPR)
#define PMHP PMHP_MASK
+/* PW_MGMT3 */
+#define PMADR (1 << 0) /* MIC L / ADC R Power Management */
+
+/* SG_SL1 */
+#define MINS (1 << 6) /* Switch from MIN to Speaker */
+#define DACL (1 << 4) /* Switch from DAC to Stereo or Receiver */
+#define PMMP (1 << 2) /* MPWR pin Power Management */
+#define MGAIN0 (1 << 0) /* MIC amp gain*/
+
+/* TIMER */
+#define ZTM(param) ((param & 0x3) << 4) /* ALC Zoro Crossing TimeOut */
+#define WTM(param) (((param & 0x4) << 4) | ((param & 0x3) << 2))
+
+/* ALC_CTL1 */
+#define ALC (1 << 5) /* ALC Enable */
+#define LMTH0 (1 << 0) /* ALC Limiter / Recovery Level */
+
/* MD_CTL1 */
#define PLL3 (1 << 7)
#define PLL2 (1 << 6)
@@ -102,7 +123,11 @@
#define FS3 (1 << 5)
#define FS_MASK (FS0 | FS1 | FS2 | FS3)
-struct snd_soc_codec_device soc_codec_dev_ak4642;
+/* MD_CTL3 */
+#define BST1 (1 << 3)
+
+/* MD_CTL4 */
+#define DACH (1 << 0)
/*
* Playback Volume (table 39)
@@ -123,11 +148,11 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = {
/* codec private data */
struct ak4642_priv {
- struct snd_soc_codec codec;
+ unsigned int sysclk;
+ enum snd_soc_control_type control_type;
+ void *control_data;
};
-static struct snd_soc_codec *ak4642_codec;
-
/*
* ak4642 register cache
*/
@@ -219,11 +244,12 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
* This operation came from example code of
* "ASAHI KASEI AK4642" (japanese) manual p97.
*/
- ak4642_write(codec, 0x0f, 0x09);
- ak4642_write(codec, 0x0e, 0x19);
- ak4642_write(codec, 0x09, 0x91);
- ak4642_write(codec, 0x0c, 0x91);
- ak4642_write(codec, 0x00, 0x64);
+ snd_soc_update_bits(codec, MD_CTL4, DACH, DACH);
+ snd_soc_update_bits(codec, MD_CTL3, BST1, BST1);
+ ak4642_write(codec, L_IVC, 0x91); /* volume */
+ ak4642_write(codec, R_IVC, 0x91); /* volume */
+ snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMMIN | PMDAC,
+ PMVCM | PMMIN | PMDAC);
snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP);
snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN);
} else {
@@ -240,13 +266,12 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
* This operation came from example code of
* "ASAHI KASEI AK4642" (japanese) manual p94.
*/
- ak4642_write(codec, 0x02, 0x05);
- ak4642_write(codec, 0x06, 0x3c);
- ak4642_write(codec, 0x08, 0xe1);
- ak4642_write(codec, 0x0b, 0x00);
- ak4642_write(codec, 0x07, 0x21);
- ak4642_write(codec, 0x00, 0x41);
- ak4642_write(codec, 0x10, 0x01);
+ ak4642_write(codec, SG_SL1, PMMP | MGAIN0);
+ ak4642_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
+ ak4642_write(codec, ALC_CTL1, ALC | LMTH0);
+ snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMADL,
+ PMVCM | PMADL);
+ snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR);
}
return 0;
@@ -262,14 +287,14 @@ static void ak4642_dai_shutdown(struct snd_pcm_substream *substream,
/* stop headphone output */
snd_soc_update_bits(codec, PW_MGMT2, HPMTN, 0);
snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, 0);
- ak4642_write(codec, 0x00, 0x40);
- ak4642_write(codec, 0x0e, 0x11);
- ak4642_write(codec, 0x0f, 0x08);
+ snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, 0);
+ snd_soc_update_bits(codec, MD_CTL3, BST1, 0);
+ snd_soc_update_bits(codec, MD_CTL4, DACH, 0);
} else {
/* stop stereo input */
- ak4642_write(codec, 0x00, 0x40);
- ak4642_write(codec, 0x10, 0x00);
- ak4642_write(codec, 0x07, 0x01);
+ snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0);
+ snd_soc_update_bits(codec, PW_MGMT3, PMADR, 0);
+ snd_soc_update_bits(codec, ALC_CTL1, ALC, 0);
}
}
@@ -393,8 +418,8 @@ static struct snd_soc_dai_ops ak4642_dai_ops = {
.hw_params = ak4642_dai_hw_params,
};
-struct snd_soc_dai ak4642_dai = {
- .name = "AK4642",
+static struct snd_soc_dai_driver ak4642_dai = {
+ .name = "ak4642-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -410,112 +435,65 @@ struct snd_soc_dai ak4642_dai = {
.ops = &ak4642_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(ak4642_dai);
-static int ak4642_resume(struct platform_device *pdev)
+static int ak4642_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
ak4642_sync(codec);
return 0;
}
-/*
- * initialise the AK4642 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int ak4642_init(struct ak4642_priv *ak4642)
+
+static int ak4642_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = &ak4642->codec;
- int ret = 0;
+ struct ak4642_priv *ak4642 = snd_soc_codec_get_drvdata(codec);
- if (ak4642_codec) {
- dev_err(codec->dev, "Another ak4642 is registered\n");
- return -EINVAL;
- }
+ dev_info(codec->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, ak4642);
- codec->name = "AK4642";
- codec->owner = THIS_MODULE;
- codec->read = ak4642_read_reg_cache;
- codec->write = ak4642_write;
- codec->dai = &ak4642_dai;
- codec->num_dai = 1;
codec->hw_write = (hw_write_t)i2c_master_send;
- codec->reg_cache_size = ARRAY_SIZE(ak4642_reg);
- codec->reg_cache = kmemdup(ak4642_reg,
- sizeof(ak4642_reg), GFP_KERNEL);
+ codec->control_data = ak4642->control_data;
- if (!codec->reg_cache)
- return -ENOMEM;
-
- ak4642_dai.dev = codec->dev;
- ak4642_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto reg_cache_err;
- }
-
- ret = snd_soc_register_dai(&ak4642_dai);
- if (ret) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- goto reg_cache_err;
- }
-
- return ret;
-
-reg_cache_err:
- kfree(codec->reg_cache);
- codec->reg_cache = NULL;
+ snd_soc_add_controls(codec, ak4642_snd_controls,
+ ARRAY_SIZE(ak4642_snd_controls));
- return ret;
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
+ .probe = ak4642_probe,
+ .resume = ak4642_resume,
+ .read = ak4642_read_reg_cache,
+ .write = ak4642_write,
+ .reg_cache_size = ARRAY_SIZE(ak4642_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = ak4642_reg,
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static int ak4642_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static __devinit int ak4642_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
struct ak4642_priv *ak4642;
- struct snd_soc_codec *codec;
int ret;
ak4642 = kzalloc(sizeof(struct ak4642_priv), GFP_KERNEL);
if (!ak4642)
return -ENOMEM;
- codec = &ak4642->codec;
- codec->dev = &i2c->dev;
-
i2c_set_clientdata(i2c, ak4642);
- codec->control_data = i2c;
+ ak4642->control_data = i2c;
+ ak4642->control_type = SND_SOC_I2C;
- ret = ak4642_init(ak4642);
- if (ret < 0) {
- printk(KERN_ERR "failed to initialise AK4642\n");
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_ak4642, &ak4642_dai, 1);
+ if (ret < 0)
kfree(ak4642);
- }
-
return ret;
}
-static int ak4642_i2c_remove(struct i2c_client *client)
+static __devexit int ak4642_i2c_remove(struct i2c_client *client)
{
- struct ak4642_priv *ak4642 = i2c_get_clientdata(client);
-
- snd_soc_unregister_dai(&ak4642_dai);
- snd_soc_unregister_codec(&ak4642->codec);
- kfree(ak4642->codec.reg_cache);
- kfree(ak4642);
- ak4642_codec = NULL;
-
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -528,64 +506,15 @@ MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
static struct i2c_driver ak4642_i2c_driver = {
.driver = {
- .name = "AK4642 I2C Codec",
+ .name = "ak4642-codec",
.owner = THIS_MODULE,
},
.probe = ak4642_i2c_probe,
- .remove = ak4642_i2c_remove,
+ .remove = __devexit_p(ak4642_i2c_remove),
.id_table = ak4642_i2c_id,
};
-
#endif
-static int ak4642_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- int ret;
-
- if (!ak4642_codec) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = ak4642_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "ak4642: failed to create pcms\n");
- goto pcm_err;
- }
-
- snd_soc_add_controls(ak4642_codec, ak4642_snd_controls,
- ARRAY_SIZE(ak4642_snd_controls));
-
- dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
- return ret;
-
-pcm_err:
- return ret;
-
-}
-
-/* power down chip */
-static int ak4642_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ak4642 = {
- .probe = ak4642_probe,
- .remove = ak4642_remove,
- .resume = ak4642_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ak4642);
-
static int __init ak4642_modinit(void)
{
int ret = 0;
diff --git a/sound/soc/codecs/ak4642.h b/sound/soc/codecs/ak4642.h
deleted file mode 100644
index e476833d314e..000000000000
--- a/sound/soc/codecs/ak4642.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * ak4642.h -- AK4642 Soc Audio driver
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ak4535.c
- *
- * 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 _AK4642_H
-#define _AK4642_H
-
-extern struct snd_soc_dai ak4642_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ak4642;
-
-#endif
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index 87566932a3b1..24f5f49bb9d2 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -23,11 +23,11 @@
#include "ak4671.h"
-static struct snd_soc_codec *ak4671_codec;
/* codec private data */
struct ak4671_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
u8 reg_cache[AK4671_CACHEREGNUM];
};
@@ -619,8 +619,8 @@ static struct snd_soc_dai_ops ak4671_dai_ops = {
.set_fmt = ak4671_set_dai_fmt,
};
-struct snd_soc_dai ak4671_dai = {
- .name = "AK4671",
+static struct snd_soc_dai_driver ak4671_dai = {
+ .name = "ak4671-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -635,27 +635,18 @@ struct snd_soc_dai ak4671_dai = {
.formats = AK4671_FORMATS,},
.ops = &ak4671_dai_ops,
};
-EXPORT_SYMBOL_GPL(ak4671_dai);
-static int ak4671_probe(struct platform_device *pdev)
+static int ak4671_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (ak4671_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
+ struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec);
+ int ret;
- socdev->card->codec = ak4671_codec;
- codec = ak4671_codec;
+ codec->hw_write = (hw_write_t)i2c_master_send;
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type);
if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
}
snd_soc_add_controls(codec, ak4671_snd_controls,
@@ -665,121 +656,48 @@ static int ak4671_probe(struct platform_device *pdev)
ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return ret;
-
-pcm_err:
- return ret;
}
-static int ak4671_remove(struct platform_device *pdev)
+static int ak4671_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
+ ak4671_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_ak4671 = {
+static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
.probe = ak4671_probe,
.remove = ak4671_remove,
+ .set_bias_level = ak4671_set_bias_level,
+ .reg_cache_size = AK4671_CACHEREGNUM,
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = ak4671_reg,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ak4671);
-
-static int ak4671_register(struct ak4671_priv *ak4671,
- enum snd_soc_control_type control)
-{
- int ret;
- struct snd_soc_codec *codec = &ak4671->codec;
-
- if (ak4671_codec) {
- dev_err(codec->dev, "Another AK4671 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, ak4671);
- codec->name = "AK4671";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = ak4671_set_bias_level;
- codec->dai = &ak4671_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = AK4671_CACHEREGNUM;
- codec->reg_cache = &ak4671->reg_cache;
-
- memcpy(codec->reg_cache, ak4671_reg, sizeof(ak4671_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, control);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
- }
-
- ak4671_dai.dev = codec->dev;
- ak4671_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&ak4671_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(ak4671);
- return ret;
-}
-
-static void ak4671_unregister(struct ak4671_priv *ak4671)
-{
- ak4671_set_bias_level(&ak4671->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&ak4671_dai);
- snd_soc_unregister_codec(&ak4671->codec);
- kfree(ak4671);
- ak4671_codec = NULL;
-}
static int __devinit ak4671_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ak4671_priv *ak4671;
- struct snd_soc_codec *codec;
+ int ret;
ak4671 = kzalloc(sizeof(struct ak4671_priv), GFP_KERNEL);
if (ak4671 == NULL)
return -ENOMEM;
- codec = &ak4671->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
i2c_set_clientdata(client, ak4671);
- codec->control_data = client;
-
- codec->dev = &client->dev;
+ ak4671->control_data = client;
+ ak4671->control_type = SND_SOC_I2C;
- return ak4671_register(ak4671, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&client->dev,
+ &soc_codec_dev_ak4671, &ak4671_dai, 1);
+ if (ret < 0)
+ kfree(ak4671);
+ return ret;
}
static __devexit int ak4671_i2c_remove(struct i2c_client *client)
{
- struct ak4671_priv *ak4671 = i2c_get_clientdata(client);
-
- ak4671_unregister(ak4671);
-
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -791,7 +709,7 @@ MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id);
static struct i2c_driver ak4671_i2c_driver = {
.driver = {
- .name = "ak4671",
+ .name = "ak4671-codec",
.owner = THIS_MODULE,
},
.probe = ak4671_i2c_probe,
diff --git a/sound/soc/codecs/ak4671.h b/sound/soc/codecs/ak4671.h
index e2fad964e88b..61cb7ab7552c 100644
--- a/sound/soc/codecs/ak4671.h
+++ b/sound/soc/codecs/ak4671.h
@@ -150,7 +150,4 @@
/* AK4671_LOUT2_POWER_MANAGEMENT (0x10) Fields */
#define AK4671_MUTEN 0x04
-extern struct snd_soc_dai ak4671_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ak4671;
-
#endif
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c
index a320fb5a0e26..823643932dde 100644
--- a/sound/soc/codecs/cq93vc.c
+++ b/sound/soc/codecs/cq93vc.c
@@ -30,6 +30,7 @@
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/mfd/davinci_voicecodec.h>
+#include <linux/spi/spi.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -41,8 +42,6 @@
#include <mach/dm365.h>
-#include "cq93vc.h"
-
static inline unsigned int cq93vc_read(struct snd_soc_codec *codec,
unsigned int reg)
{
@@ -130,8 +129,8 @@ static struct snd_soc_dai_ops cq93vc_dai_ops = {
.set_sysclk = cq93vc_set_dai_sysclk,
};
-struct snd_soc_dai cq93vc_dai = {
- .name = "CQ93VC",
+static struct snd_soc_dai_driver cq93vc_dai = {
+ .name = "cq93vc-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -146,36 +145,20 @@ struct snd_soc_dai cq93vc_dai = {
.formats = CQ93VC_FORMATS,},
.ops = &cq93vc_dai_ops,
};
-EXPORT_SYMBOL_GPL(cq93vc_dai);
-static int cq93vc_resume(struct platform_device *pdev)
+static int cq93vc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-static struct snd_soc_codec *cq93vc_codec;
-
-static int cq93vc_probe(struct platform_device *pdev)
+static int cq93vc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct device *dev = &pdev->dev;
- struct snd_soc_codec *codec;
- int ret;
-
- socdev->card->codec = cq93vc_codec;
- codec = socdev->card->codec;
-
- /* Register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(dev, "%s: failed to create pcms\n", pdev->name);
- return ret;
- }
+ struct davinci_vc *davinci_vc = codec->dev->platform_data;
+
+ davinci_vc->cq93vc.codec = codec;
+ codec->control_data = davinci_vc;
/* Set controls */
snd_soc_add_controls(codec, cq93vc_snd_controls,
@@ -187,108 +170,51 @@ static int cq93vc_probe(struct platform_device *pdev)
return 0;
}
-static int cq93vc_remove(struct platform_device *pdev)
+static int cq93vc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
+ cq93vc_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_cq93vc = {
+static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
+ .read = cq93vc_read,
+ .write = cq93vc_write,
+ .set_bias_level = cq93vc_set_bias_level,
.probe = cq93vc_probe,
.remove = cq93vc_remove,
.resume = cq93vc_resume,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_cq93vc);
-static __init int cq93vc_codec_probe(struct platform_device *pdev)
+static int cq93vc_platform_probe(struct platform_device *pdev)
{
- struct davinci_vc *davinci_vc = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret;
-
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL) {
- dev_dbg(davinci_vc->dev,
- "could not allocate memory for codec data\n");
- return -ENOMEM;
- }
-
- davinci_vc->cq93vc.codec = codec;
-
- cq93vc_dai.dev = &pdev->dev;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
- codec->dev = &pdev->dev;
- codec->name = "CQ93VC";
- codec->owner = THIS_MODULE;
- codec->read = cq93vc_read;
- codec->write = cq93vc_write;
- codec->set_bias_level = cq93vc_set_bias_level;
- codec->dai = &cq93vc_dai;
- codec->num_dai = 1;
- codec->control_data = davinci_vc;
-
- cq93vc_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret) {
- dev_err(davinci_vc->dev, "failed to register codec\n");
- goto fail1;
- }
-
- ret = snd_soc_register_dai(&cq93vc_dai);
- if (ret) {
- dev_err(davinci_vc->dev, "could register dai\n");
- goto fail2;
- }
- return 0;
-
-fail2:
- snd_soc_unregister_codec(codec);
-
-fail1:
- kfree(codec);
- cq93vc_codec = NULL;
-
- return ret;
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_cq93vc, &cq93vc_dai, 1);
}
-static int __devexit cq93vc_codec_remove(struct platform_device *pdev)
+static int cq93vc_platform_remove(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- snd_soc_unregister_dai(&cq93vc_dai);
- snd_soc_unregister_codec(&codec);
-
- kfree(codec);
- cq93vc_codec = NULL;
-
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static struct platform_driver cq93vc_codec_driver = {
.driver = {
- .name = "cq93vc",
- .owner = THIS_MODULE,
- },
- .probe = cq93vc_codec_probe,
- .remove = __devexit_p(cq93vc_codec_remove),
+ .name = "cq93vc-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = cq93vc_platform_probe,
+ .remove = __devexit_p(cq93vc_platform_remove),
};
-static __init int cq93vc_init(void)
+static int __init cq93vc_init(void)
{
- return platform_driver_probe(&cq93vc_codec_driver, cq93vc_codec_probe);
+ return platform_driver_register(&cq93vc_codec_driver);
}
module_init(cq93vc_init);
-static __exit void cq93vc_exit(void)
+static void __exit cq93vc_exit(void)
{
platform_driver_unregister(&cq93vc_codec_driver);
}
diff --git a/sound/soc/codecs/cq93vc.h b/sound/soc/codecs/cq93vc.h
deleted file mode 100644
index 845b1968ef9c..000000000000
--- a/sound/soc/codecs/cq93vc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * ALSA SoC CQ0093 Voice Codec Driver for DaVinci platforms
- *
- * Copyright (C) 2010 Texas Instruments, Inc
- *
- * Author: Miguel Aguilar <miguel.aguilar@ridgerun.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 _CQ93VC_H
-#define _CQ93VC_H
-
-extern struct snd_soc_dai cq93vc_dai;
-extern struct snd_soc_codec_device soc_codec_dev_cq93vc;
-
-#endif
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 30d949239def..6d4bdc609ac8 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -31,8 +31,6 @@
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
-#include "cs4270.h"
-
/*
* The codec isn't really big-endian or little-endian, since the I2S
* interface requires data to be sent serially with the MSbit first.
@@ -114,7 +112,8 @@ static const char *supply_names[] = {
/* Private data for the CS4270 */
struct cs4270_private {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
u8 reg_cache[CS4270_NUMREGS];
unsigned int mclk; /* Input frequency of the MCLK pin */
unsigned int mode; /* The mode (I2S or left-justified) */
@@ -212,44 +211,8 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
{
struct snd_soc_codec *codec = codec_dai->codec;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
- unsigned int rates = 0;
- unsigned int rate_min = -1;
- unsigned int rate_max = 0;
- unsigned int i;
cs4270->mclk = freq;
-
- if (cs4270->mclk) {
- for (i = 0; i < NUM_MCLK_RATIOS; i++) {
- unsigned int rate = freq / cs4270_mode_ratios[i].ratio;
- rates |= snd_pcm_rate_to_rate_bit(rate);
- if (rate < rate_min)
- rate_min = rate;
- if (rate > rate_max)
- rate_max = rate;
- }
- /* FIXME: soc should support a rate list */
- rates &= ~SNDRV_PCM_RATE_KNOT;
-
- if (!rates) {
- dev_err(codec->dev, "could not find a valid sample rate\n");
- return -EINVAL;
- }
- } else {
- /* enable all possible rates */
- rates = SNDRV_PCM_RATE_8000_192000;
- rate_min = 8000;
- rate_max = 192000;
- }
-
- codec_dai->playback.rates = rates;
- codec_dai->playback.rate_min = rate_min;
- codec_dai->playback.rate_max = rate_max;
-
- codec_dai->capture.rates = rates;
- codec_dai->capture.rate_min = rate_min;
- codec_dai->capture.rate_max = rate_max;
-
return 0;
}
@@ -410,8 +373,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int ret;
unsigned int i;
@@ -549,19 +511,6 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = {
snd_soc_get_volsw, cs4270_soc_put_mute),
};
-/*
- * cs4270_codec - global variable to store codec for the ASoC probe function
- *
- * If struct i2c_driver had a private_data field, we wouldn't need to use
- * cs4270_codec. This is the only way to pass the codec structure from
- * cs4270_i2c_probe() to cs4270_probe(). Unfortunately, there is no good
- * way to synchronize these two functions. cs4270_i2c_probe() can be called
- * multiple times before cs4270_probe() is called even once. So for now, we
- * also only allow cs4270_i2c_probe() to be run once. That means that we do
- * not support more than one cs4270 device in the system, at least for now.
- */
-static struct snd_soc_codec *cs4270_codec;
-
static struct snd_soc_dai_ops cs4270_dai_ops = {
.hw_params = cs4270_hw_params,
.set_sysclk = cs4270_set_dai_sysclk,
@@ -569,25 +518,28 @@ static struct snd_soc_dai_ops cs4270_dai_ops = {
.digital_mute = cs4270_dai_mute,
};
-struct snd_soc_dai cs4270_dai = {
- .name = "cs4270",
+static struct snd_soc_dai_driver cs4270_dai = {
+ .name = "cs4270-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
- .rates = 0,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 4000,
+ .rate_max = 216000,
.formats = CS4270_FORMATS,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
- .rates = 0,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 4000,
+ .rate_max = 216000,
.formats = CS4270_FORMATS,
},
.ops = &cs4270_dai_ops,
};
-EXPORT_SYMBOL_GPL(cs4270_dai);
/**
* cs4270_probe - ASoC probe function
@@ -596,153 +548,19 @@ EXPORT_SYMBOL_GPL(cs4270_dai);
* This function is called when ASoC has all the pieces it needs to
* instantiate a sound driver.
*/
-static int cs4270_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = cs4270_codec;
- struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
- int i, ret;
-
- /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */
- socdev->card->codec = codec;
-
- /* Register PCMs */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms\n");
- return ret;
- }
-
- /* Add the non-DAPM controls */
- ret = snd_soc_add_controls(codec, cs4270_snd_controls,
- ARRAY_SIZE(cs4270_snd_controls));
- if (ret < 0) {
- dev_err(codec->dev, "failed to add controls\n");
- goto error_free_pcms;
- }
-
- /* get the power supply regulators */
- for (i = 0; i < ARRAY_SIZE(supply_names); i++)
- cs4270->supplies[i].supply = supply_names[i];
-
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies),
- cs4270->supplies);
- if (ret < 0)
- goto error_free_pcms;
-
- ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
- cs4270->supplies);
- if (ret < 0)
- goto error_free_regulators;
-
- return 0;
-
-error_free_regulators:
- regulator_bulk_free(ARRAY_SIZE(cs4270->supplies),
- cs4270->supplies);
-
-error_free_pcms:
- snd_soc_free_pcms(socdev);
-
- return ret;
-}
-
-/**
- * cs4270_remove - ASoC remove function
- * @pdev: platform device
- *
- * This function is the counterpart to cs4270_probe().
- */
-static int cs4270_remove(struct platform_device *pdev)
+static int cs4270_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = cs4270_codec;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
+ int i, ret, reg;
- snd_soc_free_pcms(socdev);
- regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
- regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
-
- return 0;
-};
-
-/**
- * cs4270_i2c_probe - initialize the I2C interface of the CS4270
- * @i2c_client: the I2C client object
- * @id: the I2C device ID (ignored)
- *
- * This function is called whenever the I2C subsystem finds a device that
- * matches the device ID given via a prior call to i2c_add_driver().
- */
-static int cs4270_i2c_probe(struct i2c_client *i2c_client,
- const struct i2c_device_id *id)
-{
- struct snd_soc_codec *codec;
- struct cs4270_private *cs4270;
- unsigned int reg;
- int ret;
-
- /* For now, we only support one cs4270 device in the system. See the
- * comment for cs4270_codec.
- */
- if (cs4270_codec) {
- dev_err(&i2c_client->dev, "ignoring CS4270 at addr %X\n",
- i2c_client->addr);
- dev_err(&i2c_client->dev, "only one per board allowed\n");
- /* Should we return something other than ENODEV here? */
- return -ENODEV;
- }
-
- /* Verify that we have a CS4270 */
-
- ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
- if (ret < 0) {
- dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
- i2c_client->addr);
- return ret;
- }
- /* The top four bits of the chip ID should be 1100. */
- if ((ret & 0xF0) != 0xC0) {
- dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",
- i2c_client->addr);
- return -ENODEV;
- }
-
- dev_info(&i2c_client->dev, "found device at i2c address %X\n",
- i2c_client->addr);
- dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF);
-
- /* Allocate enough space for the snd_soc_codec structure
- and our private data together. */
- cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL);
- if (!cs4270) {
- dev_err(&i2c_client->dev, "could not allocate codec\n");
- return -ENOMEM;
- }
- codec = &cs4270->codec;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->dev = &i2c_client->dev;
- codec->name = "CS4270";
- codec->owner = THIS_MODULE;
- codec->dai = &cs4270_dai;
- codec->num_dai = 1;
- snd_soc_codec_set_drvdata(codec, cs4270);
- codec->control_data = i2c_client;
- codec->read = cs4270_read_reg_cache;
- codec->write = cs4270_i2c_write;
- codec->reg_cache = cs4270->reg_cache;
- codec->reg_cache_size = CS4270_NUMREGS;
+ codec->control_data = cs4270->control_data;
/* The I2C interface is set up, so pre-fill our register cache */
ret = cs4270_fill_cache(codec);
if (ret < 0) {
- dev_err(&i2c_client->dev, "failed to fill register cache\n");
- goto error_free_codec;
+ dev_err(codec->dev, "failed to fill register cache\n");
+ return ret;
}
/* Disable auto-mute. This feature appears to be buggy. In some
@@ -755,7 +573,7 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
reg &= ~CS4270_MUTE_AUTO;
ret = cs4270_i2c_write(codec, CS4270_MUTE, reg);
if (ret < 0) {
- dev_err(&i2c_client->dev, "i2c write failed\n");
+ dev_err(codec->dev, "i2c write failed\n");
return ret;
}
@@ -769,65 +587,56 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO);
ret = cs4270_i2c_write(codec, CS4270_TRANS, reg);
if (ret < 0) {
- dev_err(&i2c_client->dev, "i2c write failed\n");
+ dev_err(codec->dev, "i2c write failed\n");
return ret;
}
- /* Initialize the DAI. Normally, we'd prefer to have a kmalloc'd DAI
- * structure for each CS4270 device, but the machine driver needs to
- * have a pointer to the DAI structure, so for now it must be a global
- * variable.
- */
- cs4270_dai.dev = &i2c_client->dev;
-
- /* Register the DAI. If all the other ASoC driver have already
- * registered, then this will call our probe function, so
- * cs4270_codec needs to be ready.
- */
- cs4270_codec = codec;
- ret = snd_soc_register_dai(&cs4270_dai);
+ /* Add the non-DAPM controls */
+ ret = snd_soc_add_controls(codec, cs4270_snd_controls,
+ ARRAY_SIZE(cs4270_snd_controls));
if (ret < 0) {
- dev_err(&i2c_client->dev, "failed to register DAIe\n");
- goto error_free_codec;
+ dev_err(codec->dev, "failed to add controls\n");
+ return ret;
}
- i2c_set_clientdata(i2c_client, cs4270);
+ /* get the power supply regulators */
+ for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+ cs4270->supplies[i].supply = supply_names[i];
+
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies),
+ cs4270->supplies);
+ if (ret < 0)
+ return ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
+ cs4270->supplies);
+ if (ret < 0)
+ goto error_free_regulators;
return 0;
-error_free_codec:
- kfree(cs4270);
- cs4270_codec = NULL;
- cs4270_dai.dev = NULL;
+error_free_regulators:
+ regulator_bulk_free(ARRAY_SIZE(cs4270->supplies),
+ cs4270->supplies);
return ret;
}
/**
- * cs4270_i2c_remove - remove an I2C device
- * @i2c_client: the I2C client object
+ * cs4270_remove - ASoC remove function
+ * @pdev: platform device
*
- * This function is the counterpart to cs4270_i2c_probe().
+ * This function is the counterpart to cs4270_probe().
*/
-static int cs4270_i2c_remove(struct i2c_client *i2c_client)
+static int cs4270_remove(struct snd_soc_codec *codec)
{
- struct cs4270_private *cs4270 = i2c_get_clientdata(i2c_client);
+ struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
- kfree(cs4270);
- cs4270_codec = NULL;
- cs4270_dai.dev = NULL;
+ regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
+ regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
return 0;
-}
-
-/*
- * cs4270_id - I2C device IDs supported by this driver
- */
-static struct i2c_device_id cs4270_id[] = {
- {"cs4270", 0},
- {}
};
-MODULE_DEVICE_TABLE(i2c, cs4270_id);
#ifdef CONFIG_PM
@@ -840,9 +649,8 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id);
* and all registers are written back to the hardware when resuming.
*/
-static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
+static int cs4270_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg)
{
- struct snd_soc_codec *codec = cs4270_codec;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int reg, ret;
@@ -860,9 +668,8 @@ static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
return 0;
}
-static int cs4270_soc_resume(struct platform_device *pdev)
+static int cs4270_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = cs4270_codec;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *i2c_client = codec->control_data;
int reg;
@@ -896,6 +703,95 @@ static int cs4270_soc_resume(struct platform_device *pdev)
#endif /* CONFIG_PM */
/*
+ * ASoC codec device structure
+ *
+ * Assign this variable to the codec_dev field of the machine driver's
+ * snd_soc_device structure.
+ */
+static struct snd_soc_codec_driver soc_codec_device_cs4270 = {
+ .probe = cs4270_probe,
+ .remove = cs4270_remove,
+ .suspend = cs4270_soc_suspend,
+ .resume = cs4270_soc_resume,
+ .read = cs4270_read_reg_cache,
+ .write = cs4270_i2c_write,
+ .reg_cache_size = CS4270_NUMREGS,
+ .reg_word_size = sizeof(u8),
+};
+
+/**
+ * cs4270_i2c_probe - initialize the I2C interface of the CS4270
+ * @i2c_client: the I2C client object
+ * @id: the I2C device ID (ignored)
+ *
+ * This function is called whenever the I2C subsystem finds a device that
+ * matches the device ID given via a prior call to i2c_add_driver().
+ */
+static int cs4270_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
+{
+ struct cs4270_private *cs4270;
+ int ret;
+
+ /* Verify that we have a CS4270 */
+
+ ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
+ i2c_client->addr);
+ return ret;
+ }
+ /* The top four bits of the chip ID should be 1100. */
+ if ((ret & 0xF0) != 0xC0) {
+ dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",
+ i2c_client->addr);
+ return -ENODEV;
+ }
+
+ dev_info(&i2c_client->dev, "found device at i2c address %X\n",
+ i2c_client->addr);
+ dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF);
+
+ cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL);
+ if (!cs4270) {
+ dev_err(&i2c_client->dev, "could not allocate codec\n");
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(i2c_client, cs4270);
+ cs4270->control_data = i2c_client;
+ cs4270->control_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&i2c_client->dev,
+ &soc_codec_device_cs4270, &cs4270_dai, 1);
+ if (ret < 0)
+ kfree(cs4270);
+ return ret;
+}
+
+/**
+ * cs4270_i2c_remove - remove an I2C device
+ * @i2c_client: the I2C client object
+ *
+ * This function is the counterpart to cs4270_i2c_probe().
+ */
+static int cs4270_i2c_remove(struct i2c_client *i2c_client)
+{
+ snd_soc_unregister_codec(&i2c_client->dev);
+ kfree(i2c_get_clientdata(i2c_client));
+ return 0;
+}
+
+/*
+ * cs4270_id - I2C device IDs supported by this driver
+ */
+static struct i2c_device_id cs4270_id[] = {
+ {"cs4270", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs4270_id);
+
+/*
* cs4270_i2c_driver - I2C device identification
*
* This structure tells the I2C subsystem how to identify and support a
@@ -903,7 +799,7 @@ static int cs4270_soc_resume(struct platform_device *pdev)
*/
static struct i2c_driver cs4270_i2c_driver = {
.driver = {
- .name = "cs4270",
+ .name = "cs4270-codec",
.owner = THIS_MODULE,
},
.id_table = cs4270_id,
@@ -911,20 +807,6 @@ static struct i2c_driver cs4270_i2c_driver = {
.remove = cs4270_i2c_remove,
};
-/*
- * ASoC codec device structure
- *
- * Assign this variable to the codec_dev field of the machine driver's
- * snd_soc_device structure.
- */
-struct snd_soc_codec_device soc_codec_device_cs4270 = {
- .probe = cs4270_probe,
- .remove = cs4270_remove,
- .suspend = cs4270_soc_suspend,
- .resume = cs4270_soc_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_device_cs4270);
-
static int __init cs4270_init(void)
{
pr_info("Cirrus Logic CS4270 ALSA SoC Codec Driver\n");
diff --git a/sound/soc/codecs/cs4270.h b/sound/soc/codecs/cs4270.h
deleted file mode 100644
index adc6cd9667d4..000000000000
--- a/sound/soc/codecs/cs4270.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Cirrus Logic CS4270 ALSA SoC Codec Driver
- *
- * Author: Timur Tabi <timur@freescale.com>
- *
- * Copyright 2007 Freescale Semiconductor, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef _CS4270_H
-#define _CS4270_H
-
-/*
- * The ASoC codec DAI structure for the CS4270. Assign this structure to
- * the .codec_dai field of your machine driver's snd_soc_dai_link structure.
- */
-extern struct snd_soc_dai cs4270_dai;
-
-/*
- * The ASoC codec device structure for the CS4270. Assign this structure
- * to the .codec_dev field of your machine driver's snd_soc_device
- * structure.
- */
-extern struct snd_soc_codec_device soc_codec_device_cs4270;
-
-#endif
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index dd9b8550c402..cb086eaf4e07 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -42,15 +42,14 @@ enum master_slave_mode {
};
struct cs42l51_private {
+ enum snd_soc_control_type control_type;
+ void *control_data;
unsigned int mclk;
unsigned int audio_mode; /* The mode (I2S or left-justified) */
enum master_slave_mode func;
- struct snd_soc_codec codec;
u8 reg_cache[CS42L51_NUMREGS];
};
-static struct snd_soc_codec *cs42l51_codec;
-
#define CS42L51_FORMATS ( \
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
@@ -75,134 +74,6 @@ static int cs42l51_fill_cache(struct snd_soc_codec *codec)
return 0;
}
-static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
- const struct i2c_device_id *id)
-{
- struct snd_soc_codec *codec;
- struct cs42l51_private *cs42l51;
- int ret = 0;
- int reg;
-
- if (cs42l51_codec)
- return -EBUSY;
-
- /* Verify that we have a CS42L51 */
- ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
- if (ret < 0) {
- dev_err(&i2c_client->dev, "failed to read I2C\n");
- goto error;
- }
-
- if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
- (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
- dev_err(&i2c_client->dev, "Invalid chip id\n");
- ret = -ENODEV;
- goto error;
- }
-
- dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
- ret & 7);
-
- cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
- if (!cs42l51) {
- dev_err(&i2c_client->dev, "could not allocate codec\n");
- return -ENOMEM;
- }
- codec = &cs42l51->codec;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->dev = &i2c_client->dev;
- codec->name = "CS42L51";
- codec->owner = THIS_MODULE;
- codec->dai = &cs42l51_dai;
- codec->num_dai = 1;
- snd_soc_codec_set_drvdata(codec, cs42l51);
-
- codec->control_data = i2c_client;
- codec->reg_cache = cs42l51->reg_cache;
- codec->reg_cache_size = CS42L51_NUMREGS;
- i2c_set_clientdata(i2c_client, codec);
-
- ret = cs42l51_fill_cache(codec);
- if (ret < 0) {
- dev_err(&i2c_client->dev, "failed to fill register cache\n");
- goto error_alloc;
- }
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
- if (ret < 0) {
- dev_err(&i2c_client->dev, "Failed to set cache I/O: %d\n", ret);
- goto error_alloc;
- }
-
- /*
- * DAC configuration
- * - Use signal processor
- * - auto mute
- * - vol changes immediate
- * - no de-emphasize
- */
- reg = CS42L51_DAC_CTL_DATA_SEL(1)
- | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
- ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
- if (ret < 0)
- goto error_alloc;
-
- cs42l51_dai.dev = codec->dev;
- cs42l51_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto error_alloc;
- }
-
- ret = snd_soc_register_dai(&cs42l51_dai);
- if (ret < 0) {
- dev_err(&i2c_client->dev, "failed to register DAIe\n");
- goto error_reg;
- }
-
- return 0;
-
-error_reg:
- snd_soc_unregister_codec(codec);
-error_alloc:
- kfree(cs42l51);
-error:
- return ret;
-}
-
-static int cs42l51_i2c_remove(struct i2c_client *client)
-{
- struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
- snd_soc_unregister_dai(&cs42l51_dai);
- snd_soc_unregister_codec(cs42l51_codec);
- cs42l51_codec = NULL;
- kfree(cs42l51);
- return 0;
-}
-
-
-static const struct i2c_device_id cs42l51_id[] = {
- {"cs42l51", 0},
- {}
-};
-MODULE_DEVICE_TABLE(i2c, cs42l51_id);
-
-static struct i2c_driver cs42l51_i2c_driver = {
- .driver = {
- .name = "CS42L51 I2C",
- .owner = THIS_MODULE,
- },
- .id_table = cs42l51_id,
- .probe = cs42l51_i2c_probe,
- .remove = cs42l51_i2c_remove,
-};
-
static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -484,51 +355,8 @@ static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
{
struct snd_soc_codec *codec = codec_dai->codec;
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
- struct cs42l51_ratios *ratios = NULL;
- int nr_ratios = 0;
- unsigned int rates = 0;
- unsigned int rate_min = -1;
- unsigned int rate_max = 0;
- int i;
cs42l51->mclk = freq;
-
- switch (cs42l51->func) {
- case MODE_MASTER:
- return -EINVAL;
- case MODE_SLAVE:
- ratios = slave_ratios;
- nr_ratios = ARRAY_SIZE(slave_ratios);
- break;
- case MODE_SLAVE_AUTO:
- ratios = slave_auto_ratios;
- nr_ratios = ARRAY_SIZE(slave_auto_ratios);
- break;
- }
-
- for (i = 0; i < nr_ratios; i++) {
- unsigned int rate = freq / ratios[i].ratio;
- rates |= snd_pcm_rate_to_rate_bit(rate);
- if (rate < rate_min)
- rate_min = rate;
- if (rate > rate_max)
- rate_max = rate;
- }
- rates &= ~SNDRV_PCM_RATE_KNOT;
-
- if (!rates) {
- dev_err(codec->dev, "could not find a valid sample rate\n");
- return -EINVAL;
- }
-
- codec_dai->playback.rates = rates;
- codec_dai->playback.rate_min = rate_min;
- codec_dai->playback.rate_max = rate_max;
-
- codec_dai->capture.rates = rates;
- codec_dai->capture.rate_min = rate_min;
- codec_dai->capture.rate_max = rate_max;
-
return 0;
}
@@ -537,8 +365,7 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
int ret;
unsigned int i;
@@ -670,8 +497,8 @@ static struct snd_soc_dai_ops cs42l51_dai_ops = {
.digital_mute = cs42l51_dai_mute,
};
-struct snd_soc_dai cs42l51_dai = {
- .name = "CS42L51 HiFi",
+static struct snd_soc_dai_driver cs42l51_dai = {
+ .name = "cs42l51-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -688,30 +515,39 @@ struct snd_soc_dai cs42l51_dai = {
},
.ops = &cs42l51_dai_ops,
};
-EXPORT_SYMBOL_GPL(cs42l51_dai);
-
-static int cs42l51_probe(struct platform_device *pdev)
+static int cs42l51_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
+ struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+ int ret, reg;
- if (!cs42l51_codec) {
- dev_err(&pdev->dev, "CS42L51 codec not yet registered\n");
- return -EINVAL;
- }
+ codec->control_data = cs42l51->control_data;
- socdev->card->codec = cs42l51_codec;
- codec = socdev->card->codec;
+ ret = cs42l51_fill_cache(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to fill register cache\n");
+ return ret;
+ }
- /* Register PCMs */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs42l51->control_type);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to create PCMs\n");
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
+ /*
+ * DAC configuration
+ * - Use signal processor
+ * - auto mute
+ * - vol changes immediate
+ * - no de-emphasize
+ */
+ reg = CS42L51_DAC_CTL_DATA_SEL(1)
+ | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
+ ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
+ if (ret < 0)
+ return ret;
+
snd_soc_add_controls(codec, cs42l51_snd_controls,
ARRAY_SIZE(cs42l51_snd_controls));
snd_soc_dapm_new_controls(codec, cs42l51_dapm_widgets,
@@ -722,22 +558,77 @@ static int cs42l51_probe(struct platform_device *pdev)
return 0;
}
+static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
+ .probe = cs42l51_probe,
+ .reg_cache_size = CS42L51_NUMREGS,
+ .reg_word_size = sizeof(u8),
+};
-static int cs42l51_remove(struct platform_device *pdev)
+static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct cs42l51_private *cs42l51;
+ int ret;
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
+ /* Verify that we have a CS42L51 */
+ ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "failed to read I2C\n");
+ goto error;
+ }
+
+ if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
+ (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
+ dev_err(&i2c_client->dev, "Invalid chip id\n");
+ ret = -ENODEV;
+ goto error;
+ }
+
+ dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
+ ret & 7);
+
+ cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
+ if (!cs42l51) {
+ dev_err(&i2c_client->dev, "could not allocate codec\n");
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(i2c_client, cs42l51);
+ cs42l51->control_data = i2c_client;
+ cs42l51->control_type = SND_SOC_I2C;
+ ret = snd_soc_register_codec(&i2c_client->dev,
+ &soc_codec_device_cs42l51, &cs42l51_dai, 1);
+ if (ret < 0)
+ kfree(cs42l51);
+error:
+ return ret;
+}
+
+static int cs42l51_i2c_remove(struct i2c_client *client)
+{
+ struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
+
+ snd_soc_unregister_codec(&client->dev);
+ kfree(cs42l51);
return 0;
}
-struct snd_soc_codec_device soc_codec_device_cs42l51 = {
- .probe = cs42l51_probe,
- .remove = cs42l51_remove
+static const struct i2c_device_id cs42l51_id[] = {
+ {"cs42l51", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs42l51_id);
+
+static struct i2c_driver cs42l51_i2c_driver = {
+ .driver = {
+ .name = "cs42l51-codec",
+ .owner = THIS_MODULE,
+ },
+ .id_table = cs42l51_id,
+ .probe = cs42l51_i2c_probe,
+ .remove = cs42l51_i2c_remove,
};
-EXPORT_SYMBOL_GPL(soc_codec_device_cs42l51);
static int __init cs42l51_init(void)
{
@@ -758,6 +649,6 @@ static void __exit cs42l51_exit(void)
}
module_exit(cs42l51_exit);
-MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h
index 8f0bd9786ad2..2beeb171db4b 100644
--- a/sound/soc/codecs/cs42l51.h
+++ b/sound/soc/codecs/cs42l51.h
@@ -158,6 +158,4 @@
#define CS42L51_LASTREG 0x20
#define CS42L51_NUMREGS (CS42L51_LASTREG - CS42L51_FIRSTREG + 1)
-extern struct snd_soc_dai cs42l51_dai;
-extern struct snd_soc_codec_device soc_codec_device_cs42l51;
#endif
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index f07a415c753f..e8d27c8f9ba3 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -24,7 +24,8 @@
struct cx20442_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
u8 reg_cache[1];
};
@@ -102,7 +103,7 @@ static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
{
u8 *reg_cache = codec->reg_cache;
- if (reg >= codec->reg_cache_size)
+ if (reg >= codec->driver->reg_cache_size)
return -EINVAL;
return reg_cache[reg];
@@ -164,16 +165,17 @@ static int cx20442_pm_to_v253_vsp(u8 value)
static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
+ struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
u8 *reg_cache = codec->reg_cache;
int vls, vsp, old, len;
char buf[18];
- if (reg >= codec->reg_cache_size)
+ if (reg >= codec->driver->reg_cache_size)
return -EINVAL;
/* hw_write and control_data pointers required for talking to the modem
* are expected to be set by the line discipline initialization code */
- if (!codec->hw_write || !codec->control_data)
+ if (!codec->hw_write || !cx20442->control_data)
return -EIO;
old = reg_cache[reg];
@@ -202,17 +204,13 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
return -ENOMEM;
dev_dbg(codec->dev, "%s: %s\n", __func__, buf);
- if (codec->hw_write(codec->control_data, buf, len) != len)
+ if (codec->hw_write(cx20442->control_data, buf, len) != len)
return -EIO;
return 0;
}
-/* Moved up here as line discipline referres it during initialization */
-static struct snd_soc_codec *cx20442_codec;
-
-
/*
* Line discpline related code
*
@@ -228,15 +226,15 @@ static const char *v253_init = "ate0m0q0+fclass=8\r";
/* Line discipline .open() */
static int v253_open(struct tty_struct *tty)
{
- struct snd_soc_codec *codec = cx20442_codec;
int ret, len = strlen(v253_init);
/* Doesn't make sense without write callback */
if (!tty->ops->write)
return -EINVAL;
- /* Pass the codec structure address for use by other ldisc callbacks */
- tty->disc_data = codec;
+ /* Won't work if no codec pointer has been passed by a card driver */
+ if (!tty->disc_data)
+ return -ENODEV;
if (tty->ops->write(tty, v253_init, len) != len) {
ret = -EIO;
@@ -253,15 +251,18 @@ err:
static void v253_close(struct tty_struct *tty)
{
struct snd_soc_codec *codec = tty->disc_data;
+ struct cx20442_priv *cx20442;
tty->disc_data = NULL;
if (!codec)
return;
+ cx20442 = snd_soc_codec_get_drvdata(codec);
+
/* Prevent the codec driver from further accessing the modem */
codec->hw_write = NULL;
- codec->control_data = NULL;
+ cx20442->control_data = NULL;
codec->pop_time = 0;
}
@@ -277,15 +278,18 @@ static void v253_receive(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{
struct snd_soc_codec *codec = tty->disc_data;
+ struct cx20442_priv *cx20442;
if (!codec)
return;
- if (!codec->control_data) {
+ cx20442 = snd_soc_codec_get_drvdata(codec);
+
+ if (!cx20442->control_data) {
/* First modem response, complete setup procedure */
/* Set up codec driver access to modem controls */
- codec->control_data = tty;
+ cx20442->control_data = tty;
codec->hw_write = (hw_write_t)tty->ops->write;
codec->pop_time = 1;
}
@@ -313,8 +317,8 @@ EXPORT_SYMBOL_GPL(v253_ops);
* Codec DAI
*/
-struct snd_soc_dai cx20442_dai = {
- .name = "CX20442",
+static struct snd_soc_dai_driver cx20442_dai = {
+ .name = "cx20442-voice",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -330,142 +334,63 @@ struct snd_soc_dai cx20442_dai = {
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
};
-EXPORT_SYMBOL_GPL(cx20442_dai);
-static int cx20442_codec_probe(struct platform_device *pdev)
+static int cx20442_codec_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret;
-
- if (!cx20442_codec) {
- dev_err(&pdev->dev, "cx20442 not yet discovered\n");
- return -ENODEV;
- }
- codec = cx20442_codec;
-
- socdev->card->codec = codec;
+ struct cx20442_priv *cx20442;
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to create pcms\n");
- goto pcm_err;
- }
+ cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL);
+ if (cx20442 == NULL)
+ return -ENOMEM;
+ snd_soc_codec_set_drvdata(codec, cx20442);
cx20442_add_widgets(codec);
-pcm_err:
- return ret;
+ cx20442->control_data = NULL;
+ codec->hw_write = NULL;
+ codec->pop_time = 0;
+
+ return 0;
}
/* power down chip */
-static int cx20442_codec_remove(struct platform_device *pdev)
+static int cx20442_codec_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
+ if (cx20442->control_data) {
+ struct tty_struct *tty = cx20442->control_data;
+ tty_hangup(tty);
+ }
+ kfree(cx20442);
return 0;
}
-struct snd_soc_codec_device cx20442_codec_dev = {
+static struct snd_soc_codec_driver cx20442_codec_dev = {
.probe = cx20442_codec_probe,
.remove = cx20442_codec_remove,
+ .reg_cache_size = 1,
+ .reg_word_size = sizeof(u8),
+ .read = cx20442_read_reg_cache,
+ .write = cx20442_write,
};
-EXPORT_SYMBOL_GPL(cx20442_codec_dev);
-
-static int cx20442_register(struct cx20442_priv *cx20442)
-{
- struct snd_soc_codec *codec = &cx20442->codec;
- int ret;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "CX20442";
- codec->owner = THIS_MODULE;
- snd_soc_codec_set_drvdata(codec, cx20442);
-
- codec->dai = &cx20442_dai;
- codec->num_dai = 1;
-
- codec->reg_cache = &cx20442->reg_cache;
- codec->reg_cache_size = ARRAY_SIZE(cx20442->reg_cache);
- codec->read = cx20442_read_reg_cache;
- codec->write = cx20442_write;
-
- codec->bias_level = SND_SOC_BIAS_OFF;
-
- cx20442_dai.dev = codec->dev;
-
- cx20442_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&cx20442_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- cx20442_codec = NULL;
- kfree(cx20442);
- return ret;
-}
-
-static void cx20442_unregister(struct cx20442_priv *cx20442)
-{
- snd_soc_unregister_dai(&cx20442_dai);
- snd_soc_unregister_codec(&cx20442->codec);
-
- cx20442_codec = NULL;
- kfree(cx20442);
-}
static int cx20442_platform_probe(struct platform_device *pdev)
{
- struct cx20442_priv *cx20442;
- struct snd_soc_codec *codec;
-
- cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL);
- if (cx20442 == NULL)
- return -ENOMEM;
-
- codec = &cx20442->codec;
-
- codec->control_data = NULL;
- codec->hw_write = NULL;
- codec->pop_time = 0;
-
- codec->dev = &pdev->dev;
- platform_set_drvdata(pdev, cx20442);
-
- return cx20442_register(cx20442);
+ return snd_soc_register_codec(&pdev->dev,
+ &cx20442_codec_dev, &cx20442_dai, 1);
}
static int __exit cx20442_platform_remove(struct platform_device *pdev)
{
- struct cx20442_priv *cx20442 = platform_get_drvdata(pdev);
-
- cx20442_unregister(cx20442);
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static struct platform_driver cx20442_platform_driver = {
.driver = {
- .name = "cx20442",
+ .name = "cx20442-codec",
.owner = THIS_MODULE,
},
.probe = cx20442_platform_probe,
@@ -487,4 +412,4 @@ module_exit(cx20442_exit);
MODULE_DESCRIPTION("ASoC CX20442-11 voice modem codec driver");
MODULE_AUTHOR("Janusz Krzysztofik");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:cx20442");
+MODULE_ALIAS("platform:cx20442-codec");
diff --git a/sound/soc/codecs/cx20442.h b/sound/soc/codecs/cx20442.h
index 688a5eb62e17..c7a7c79ef0cd 100644
--- a/sound/soc/codecs/cx20442.h
+++ b/sound/soc/codecs/cx20442.h
@@ -13,8 +13,6 @@
#ifndef _CX20442_CODEC_H
#define _CX20442_CODEC_H
-extern struct snd_soc_dai cx20442_dai;
-extern struct snd_soc_codec_device cx20442_codec_dev;
extern struct tty_ldisc_ops v253_ops;
#endif
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 3c51d6a57523..58bb9b994811 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -25,8 +25,6 @@
#include <sound/initval.h>
#include <sound/tlv.h>
-#include "da7210.h"
-
/* DA7210 register space */
#define DA7210_STATUS 0x02
#define DA7210_STARTUP1 0x03
@@ -162,11 +160,10 @@ static const struct snd_kcontrol_new da7210_snd_controls[] = {
/* Codec private data */
struct da7210_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
};
-static struct snd_soc_codec *da7210_codec;
-
/*
* Register cache
*/
@@ -209,12 +206,12 @@ static int da7210_write(struct snd_soc_codec *codec, u32 reg, u32 value)
u8 *cache = codec->reg_cache;
u8 data[2];
- BUG_ON(codec->volatile_register);
+ BUG_ON(codec->driver->volatile_register);
data[0] = reg & 0xff;
data[1] = value & 0xff;
- if (reg >= codec->reg_cache_size)
+ if (reg >= codec->driver->reg_cache_size)
return -EIO;
if (2 != codec->hw_write(codec->control_data, data, 2))
@@ -267,8 +264,7 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u32 dai_cfg1;
u32 hpf_reg, hpf_mask, hpf_value;
u32 fs, bypass;
@@ -430,9 +426,8 @@ static struct snd_soc_dai_ops da7210_dai_ops = {
.set_fmt = da7210_set_dai_fmt,
};
-struct snd_soc_dai da7210_dai = {
- .name = "DA7210 IIS",
- .id = 0,
+static struct snd_soc_dai_driver da7210_dai = {
+ .name = "da7210-hifi",
/* playback capabilities */
.playback = {
.stream_name = "Playback",
@@ -452,55 +447,15 @@ struct snd_soc_dai da7210_dai = {
.ops = &da7210_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(da7210_dai);
-/*
- * Initialize the DA7210 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int da7210_init(struct da7210_priv *da7210)
+static int da7210_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = &da7210->codec;
- int ret = 0;
+ struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
- if (da7210_codec) {
- dev_err(codec->dev, "Another da7210 is registered\n");
- return -EINVAL;
- }
+ dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, da7210);
- codec->name = "DA7210";
- codec->owner = THIS_MODULE;
- codec->read = da7210_read;
- codec->write = da7210_write;
- codec->dai = &da7210_dai;
- codec->num_dai = 1;
+ codec->control_data = da7210->control_data;
codec->hw_write = (hw_write_t)i2c_master_send;
- codec->reg_cache_size = ARRAY_SIZE(da7210_reg);
- codec->reg_cache = kmemdup(da7210_reg,
- sizeof(da7210_reg), GFP_KERNEL);
-
- if (!codec->reg_cache)
- return -ENOMEM;
-
- da7210_dai.dev = codec->dev;
- da7210_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret) {
- dev_err(codec->dev, "Failed to register CODEC: %d\n", ret);
- goto init_err;
- }
-
- ret = snd_soc_register_dai(&da7210_dai);
- if (ret) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto codec_err;
- }
/* FIXME
*
@@ -583,54 +538,50 @@ static int da7210_init(struct da7210_priv *da7210)
/* Activate all enabled subsystem */
da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
- return ret;
-
-codec_err:
- snd_soc_unregister_codec(codec);
-init_err:
- kfree(codec->reg_cache);
- codec->reg_cache = NULL;
+ snd_soc_add_controls(codec, da7210_snd_controls,
+ ARRAY_SIZE(da7210_snd_controls));
- return ret;
+ dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
+ .probe = da7210_probe,
+ .read = da7210_read,
+ .write = da7210_write,
+ .reg_cache_size = ARRAY_SIZE(da7210_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = da7210_reg,
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct da7210_priv *da7210;
- struct snd_soc_codec *codec;
int ret;
da7210 = kzalloc(sizeof(struct da7210_priv), GFP_KERNEL);
if (!da7210)
return -ENOMEM;
- codec = &da7210->codec;
- codec->dev = &i2c->dev;
-
i2c_set_clientdata(i2c, da7210);
- codec->control_data = i2c;
+ da7210->control_data = i2c;
+ da7210->control_type = SND_SOC_I2C;
- ret = da7210_init(da7210);
- if (ret < 0) {
- pr_err("Failed to initialise da7210 audio codec\n");
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_da7210, &da7210_dai, 1);
+ if (ret < 0)
kfree(da7210);
- }
return ret;
}
static int __devexit da7210_i2c_remove(struct i2c_client *client)
{
- struct da7210_priv *da7210 = i2c_get_clientdata(client);
-
- snd_soc_unregister_dai(&da7210_dai);
- kfree(da7210->codec.reg_cache);
- kfree(da7210);
- da7210_codec = NULL;
-
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -643,59 +594,15 @@ MODULE_DEVICE_TABLE(i2c, da7210_i2c_id);
/* I2C codec control layer */
static struct i2c_driver da7210_i2c_driver = {
.driver = {
- .name = "DA7210 I2C Codec",
+ .name = "da7210-codec",
.owner = THIS_MODULE,
},
- .probe = da7210_i2c_probe,
- .remove = __devexit_p(da7210_i2c_remove),
- .id_table = da7210_i2c_id,
+ .probe = da7210_i2c_probe,
+ .remove = __devexit_p(da7210_i2c_remove),
+ .id_table = da7210_i2c_id,
};
#endif
-static int da7210_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret;
-
- if (!da7210_codec) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = da7210_codec;
- codec = da7210_codec;
-
- /* Register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0)
- goto pcm_err;
-
- snd_soc_add_controls(da7210_codec, da7210_snd_controls,
- ARRAY_SIZE(da7210_snd_controls));
-
- dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
-
-pcm_err:
- return ret;
-}
-
-static int da7210_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_da7210 = {
- .probe = da7210_probe,
- .remove = da7210_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_da7210);
-
static int __init da7210_modinit(void)
{
int ret = 0;
diff --git a/sound/soc/codecs/da7210.h b/sound/soc/codecs/da7210.h
deleted file mode 100644
index 390d621eb742..000000000000
--- a/sound/soc/codecs/da7210.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * da7210.h -- audio driver for da7210
- *
- * Copyright (c) 2009 Dialog Semiconductor
- * Written by David Chen <Dajun.chen@diasemi.com>
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#ifndef _DA7210_H
-#define _DA7210_H
-
-extern struct snd_soc_dai da7210_dai;
-extern struct snd_soc_codec_device soc_codec_dev_da7210;
-
-#endif
-
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index 66557de1e4fe..16253ec9b022 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -74,29 +74,22 @@ static const uint32_t jz4740_codec_regs[] = {
struct jz4740_codec {
void __iomem *base;
struct resource *mem;
-
- uint32_t reg_cache[2];
- struct snd_soc_codec codec;
};
-static inline struct jz4740_codec *codec_to_jz4740(struct snd_soc_codec *codec)
-{
- return container_of(codec, struct jz4740_codec, codec);
-}
-
static unsigned int jz4740_codec_read(struct snd_soc_codec *codec,
unsigned int reg)
{
- struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
+ struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
return readl(jz4740_codec->base + (reg << 2));
}
static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val)
{
- struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
+ struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
+ u32 *cache = codec->reg_cache;
- jz4740_codec->reg_cache[reg] = val;
+ cache[reg] = val;
writel(val, jz4740_codec->base + (reg << 2));
return 0;
@@ -172,8 +165,7 @@ static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
{
uint32_t val;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec =rtd->codec;
switch (params_rate(params)) {
case 8000:
@@ -219,8 +211,8 @@ static struct snd_soc_dai_ops jz4740_codec_dai_ops = {
.hw_params = jz4740_codec_hw_params,
};
-struct snd_soc_dai jz4740_codec_dai = {
- .name = "jz4740",
+static struct snd_soc_dai_driver jz4740_codec_dai = {
+ .name = "jz4740-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -238,7 +230,6 @@ struct snd_soc_dai jz4740_codec_dai = {
.ops = &jz4740_codec_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(jz4740_codec_dai);
static void jz4740_codec_wakeup(struct snd_soc_codec *codec)
{
@@ -302,23 +293,10 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static struct snd_soc_codec *jz4740_codec_codec;
-
-static int jz4740_codec_dev_probe(struct platform_device *pdev)
+static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
{
- int ret;
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = jz4740_codec_codec;
-
- BUG_ON(!codec);
-
- socdev->card->codec = codec;
-
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret) {
- dev_err(&pdev->dev, "Failed to create pcms: %d\n", ret);
- return ret;
- }
+ snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
+ JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
snd_soc_add_controls(codec, jz4740_codec_controls,
ARRAY_SIZE(jz4740_codec_controls));
@@ -331,34 +309,27 @@ static int jz4740_codec_dev_probe(struct platform_device *pdev)
snd_soc_dapm_new_widgets(codec);
+ jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
return 0;
}
-static int jz4740_codec_dev_remove(struct platform_device *pdev)
+static int jz4740_codec_dev_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
+ jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
#ifdef CONFIG_PM_SLEEP
-static int jz4740_codec_suspend(struct platform_device *pdev, pm_message_t state)
+static int jz4740_codec_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
}
-static int jz4740_codec_resume(struct platform_device *pdev)
+static int jz4740_codec_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
}
@@ -367,19 +338,23 @@ static int jz4740_codec_resume(struct platform_device *pdev)
#define jz4740_codec_resume NULL
#endif
-struct snd_soc_codec_device soc_codec_dev_jz4740_codec = {
+static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
.probe = jz4740_codec_dev_probe,
.remove = jz4740_codec_dev_remove,
.suspend = jz4740_codec_suspend,
.resume = jz4740_codec_resume,
+ .read = jz4740_codec_read,
+ .write = jz4740_codec_write,
+ .set_bias_level = jz4740_codec_set_bias_level,
+ .reg_cache_default = jz4740_codec_regs,
+ .reg_word_size = sizeof(u32),
+ .reg_cache_size = 2,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_jz4740_codec);
static int __devinit jz4740_codec_probe(struct platform_device *pdev)
{
int ret;
struct jz4740_codec *jz4740_codec;
- struct snd_soc_codec *codec;
struct resource *mem;
jz4740_codec = kzalloc(sizeof(*jz4740_codec), GFP_KERNEL);
@@ -408,55 +383,17 @@ static int __devinit jz4740_codec_probe(struct platform_device *pdev)
}
jz4740_codec->mem = mem;
- jz4740_codec_dai.dev = &pdev->dev;
-
- codec = &jz4740_codec->codec;
-
- codec->dev = &pdev->dev;
- codec->name = "jz4740";
- codec->owner = THIS_MODULE;
-
- codec->read = jz4740_codec_read;
- codec->write = jz4740_codec_write;
- codec->set_bias_level = jz4740_codec_set_bias_level;
- codec->bias_level = SND_SOC_BIAS_OFF;
-
- codec->dai = &jz4740_codec_dai;
- codec->num_dai = 1;
-
- codec->reg_cache = jz4740_codec->reg_cache;
- codec->reg_cache_size = 2;
- memcpy(codec->reg_cache, jz4740_codec_regs, sizeof(jz4740_codec_regs));
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- jz4740_codec_codec = codec;
-
- snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
- JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
-
platform_set_drvdata(pdev, jz4740_codec);
- ret = snd_soc_register_codec(codec);
+ ret = snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_jz4740_codec, &jz4740_codec_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Failed to register codec\n");
goto err_iounmap;
}
- ret = snd_soc_register_dai(&jz4740_codec_dai);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register codec dai\n");
- goto err_unregister_codec;
- }
-
- jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
return 0;
-err_unregister_codec:
- snd_soc_unregister_codec(codec);
err_iounmap:
iounmap(jz4740_codec->base);
err_release_mem_region:
@@ -472,8 +409,7 @@ static int __devexit jz4740_codec_remove(struct platform_device *pdev)
struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev);
struct resource *mem = jz4740_codec->mem;
- snd_soc_unregister_dai(&jz4740_codec_dai);
- snd_soc_unregister_codec(&jz4740_codec->codec);
+ snd_soc_unregister_codec(&pdev->dev);
iounmap(jz4740_codec->base);
release_mem_region(mem->start, resource_size(mem));
diff --git a/sound/soc/codecs/jz4740.h b/sound/soc/codecs/jz4740.h
deleted file mode 100644
index b5a0691be763..000000000000
--- a/sound/soc/codecs/jz4740.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
- *
- * 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.
- *
- * 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.
- *
- */
-
-#ifndef __SND_SOC_CODECS_JZ4740_CODEC_H__
-#define __SND_SOC_CODECS_JZ4740_CODEC_H__
-
-extern struct snd_soc_dai jz4740_codec_dai;
-extern struct snd_soc_codec_device soc_codec_dev_jz4740_codec;
-
-#endif
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
new file mode 100644
index 000000000000..bc22ee93a75d
--- /dev/null
+++ b/sound/soc/codecs/max98088.c
@@ -0,0 +1,2097 @@
+/*
+ * max98088.c -- MAX98088 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+#include <sound/max98088.h>
+#include "max98088.h"
+
+struct max98088_cdata {
+ unsigned int rate;
+ unsigned int fmt;
+ int eq_sel;
+};
+
+struct max98088_priv {
+ u8 reg_cache[M98088_REG_CNT];
+ void *control_data;
+ struct max98088_pdata *pdata;
+ unsigned int sysclk;
+ struct max98088_cdata dai[2];
+ int eq_textcnt;
+ const char **eq_texts;
+ struct soc_enum eq_enum;
+ u8 ina_state;
+ u8 inb_state;
+ unsigned int ex_mode;
+ unsigned int digmic;
+ unsigned int mic1pre;
+ unsigned int mic2pre;
+ unsigned int extmic_mode;
+};
+
+static const u8 max98088_reg[M98088_REG_CNT] = {
+ 0x00, /* 00 IRQ status */
+ 0x00, /* 01 MIC status */
+ 0x00, /* 02 jack status */
+ 0x00, /* 03 battery voltage */
+ 0x00, /* 04 */
+ 0x00, /* 05 */
+ 0x00, /* 06 */
+ 0x00, /* 07 */
+ 0x00, /* 08 */
+ 0x00, /* 09 */
+ 0x00, /* 0A */
+ 0x00, /* 0B */
+ 0x00, /* 0C */
+ 0x00, /* 0D */
+ 0x00, /* 0E */
+ 0x00, /* 0F interrupt enable */
+
+ 0x00, /* 10 master clock */
+ 0x00, /* 11 DAI1 clock mode */
+ 0x00, /* 12 DAI1 clock control */
+ 0x00, /* 13 DAI1 clock control */
+ 0x00, /* 14 DAI1 format */
+ 0x00, /* 15 DAI1 clock */
+ 0x00, /* 16 DAI1 config */
+ 0x00, /* 17 DAI1 TDM */
+ 0x00, /* 18 DAI1 filters */
+ 0x00, /* 19 DAI2 clock mode */
+ 0x00, /* 1A DAI2 clock control */
+ 0x00, /* 1B DAI2 clock control */
+ 0x00, /* 1C DAI2 format */
+ 0x00, /* 1D DAI2 clock */
+ 0x00, /* 1E DAI2 config */
+ 0x00, /* 1F DAI2 TDM */
+
+ 0x00, /* 20 DAI2 filters */
+ 0x00, /* 21 data config */
+ 0x00, /* 22 DAC mixer */
+ 0x00, /* 23 left ADC mixer */
+ 0x00, /* 24 right ADC mixer */
+ 0x00, /* 25 left HP mixer */
+ 0x00, /* 26 right HP mixer */
+ 0x00, /* 27 HP control */
+ 0x00, /* 28 left REC mixer */
+ 0x00, /* 29 right REC mixer */
+ 0x00, /* 2A REC control */
+ 0x00, /* 2B left SPK mixer */
+ 0x00, /* 2C right SPK mixer */
+ 0x00, /* 2D SPK control */
+ 0x00, /* 2E sidetone */
+ 0x00, /* 2F DAI1 playback level */
+
+ 0x00, /* 30 DAI1 playback level */
+ 0x00, /* 31 DAI2 playback level */
+ 0x00, /* 32 DAI2 playbakc level */
+ 0x00, /* 33 left ADC level */
+ 0x00, /* 34 right ADC level */
+ 0x00, /* 35 MIC1 level */
+ 0x00, /* 36 MIC2 level */
+ 0x00, /* 37 INA level */
+ 0x00, /* 38 INB level */
+ 0x00, /* 39 left HP volume */
+ 0x00, /* 3A right HP volume */
+ 0x00, /* 3B left REC volume */
+ 0x00, /* 3C right REC volume */
+ 0x00, /* 3D left SPK volume */
+ 0x00, /* 3E right SPK volume */
+ 0x00, /* 3F MIC config */
+
+ 0x00, /* 40 MIC threshold */
+ 0x00, /* 41 excursion limiter filter */
+ 0x00, /* 42 excursion limiter threshold */
+ 0x00, /* 43 ALC */
+ 0x00, /* 44 power limiter threshold */
+ 0x00, /* 45 power limiter config */
+ 0x00, /* 46 distortion limiter config */
+ 0x00, /* 47 audio input */
+ 0x00, /* 48 microphone */
+ 0x00, /* 49 level control */
+ 0x00, /* 4A bypass switches */
+ 0x00, /* 4B jack detect */
+ 0x00, /* 4C input enable */
+ 0x00, /* 4D output enable */
+ 0xF0, /* 4E bias control */
+ 0x00, /* 4F DAC power */
+
+ 0x0F, /* 50 DAC power */
+ 0x00, /* 51 system */
+ 0x00, /* 52 DAI1 EQ1 */
+ 0x00, /* 53 DAI1 EQ1 */
+ 0x00, /* 54 DAI1 EQ1 */
+ 0x00, /* 55 DAI1 EQ1 */
+ 0x00, /* 56 DAI1 EQ1 */
+ 0x00, /* 57 DAI1 EQ1 */
+ 0x00, /* 58 DAI1 EQ1 */
+ 0x00, /* 59 DAI1 EQ1 */
+ 0x00, /* 5A DAI1 EQ1 */
+ 0x00, /* 5B DAI1 EQ1 */
+ 0x00, /* 5C DAI1 EQ2 */
+ 0x00, /* 5D DAI1 EQ2 */
+ 0x00, /* 5E DAI1 EQ2 */
+ 0x00, /* 5F DAI1 EQ2 */
+
+ 0x00, /* 60 DAI1 EQ2 */
+ 0x00, /* 61 DAI1 EQ2 */
+ 0x00, /* 62 DAI1 EQ2 */
+ 0x00, /* 63 DAI1 EQ2 */
+ 0x00, /* 64 DAI1 EQ2 */
+ 0x00, /* 65 DAI1 EQ2 */
+ 0x00, /* 66 DAI1 EQ3 */
+ 0x00, /* 67 DAI1 EQ3 */
+ 0x00, /* 68 DAI1 EQ3 */
+ 0x00, /* 69 DAI1 EQ3 */
+ 0x00, /* 6A DAI1 EQ3 */
+ 0x00, /* 6B DAI1 EQ3 */
+ 0x00, /* 6C DAI1 EQ3 */
+ 0x00, /* 6D DAI1 EQ3 */
+ 0x00, /* 6E DAI1 EQ3 */
+ 0x00, /* 6F DAI1 EQ3 */
+
+ 0x00, /* 70 DAI1 EQ4 */
+ 0x00, /* 71 DAI1 EQ4 */
+ 0x00, /* 72 DAI1 EQ4 */
+ 0x00, /* 73 DAI1 EQ4 */
+ 0x00, /* 74 DAI1 EQ4 */
+ 0x00, /* 75 DAI1 EQ4 */
+ 0x00, /* 76 DAI1 EQ4 */
+ 0x00, /* 77 DAI1 EQ4 */
+ 0x00, /* 78 DAI1 EQ4 */
+ 0x00, /* 79 DAI1 EQ4 */
+ 0x00, /* 7A DAI1 EQ5 */
+ 0x00, /* 7B DAI1 EQ5 */
+ 0x00, /* 7C DAI1 EQ5 */
+ 0x00, /* 7D DAI1 EQ5 */
+ 0x00, /* 7E DAI1 EQ5 */
+ 0x00, /* 7F DAI1 EQ5 */
+
+ 0x00, /* 80 DAI1 EQ5 */
+ 0x00, /* 81 DAI1 EQ5 */
+ 0x00, /* 82 DAI1 EQ5 */
+ 0x00, /* 83 DAI1 EQ5 */
+ 0x00, /* 84 DAI2 EQ1 */
+ 0x00, /* 85 DAI2 EQ1 */
+ 0x00, /* 86 DAI2 EQ1 */
+ 0x00, /* 87 DAI2 EQ1 */
+ 0x00, /* 88 DAI2 EQ1 */
+ 0x00, /* 89 DAI2 EQ1 */
+ 0x00, /* 8A DAI2 EQ1 */
+ 0x00, /* 8B DAI2 EQ1 */
+ 0x00, /* 8C DAI2 EQ1 */
+ 0x00, /* 8D DAI2 EQ1 */
+ 0x00, /* 8E DAI2 EQ2 */
+ 0x00, /* 8F DAI2 EQ2 */
+
+ 0x00, /* 90 DAI2 EQ2 */
+ 0x00, /* 91 DAI2 EQ2 */
+ 0x00, /* 92 DAI2 EQ2 */
+ 0x00, /* 93 DAI2 EQ2 */
+ 0x00, /* 94 DAI2 EQ2 */
+ 0x00, /* 95 DAI2 EQ2 */
+ 0x00, /* 96 DAI2 EQ2 */
+ 0x00, /* 97 DAI2 EQ2 */
+ 0x00, /* 98 DAI2 EQ3 */
+ 0x00, /* 99 DAI2 EQ3 */
+ 0x00, /* 9A DAI2 EQ3 */
+ 0x00, /* 9B DAI2 EQ3 */
+ 0x00, /* 9C DAI2 EQ3 */
+ 0x00, /* 9D DAI2 EQ3 */
+ 0x00, /* 9E DAI2 EQ3 */
+ 0x00, /* 9F DAI2 EQ3 */
+
+ 0x00, /* A0 DAI2 EQ3 */
+ 0x00, /* A1 DAI2 EQ3 */
+ 0x00, /* A2 DAI2 EQ4 */
+ 0x00, /* A3 DAI2 EQ4 */
+ 0x00, /* A4 DAI2 EQ4 */
+ 0x00, /* A5 DAI2 EQ4 */
+ 0x00, /* A6 DAI2 EQ4 */
+ 0x00, /* A7 DAI2 EQ4 */
+ 0x00, /* A8 DAI2 EQ4 */
+ 0x00, /* A9 DAI2 EQ4 */
+ 0x00, /* AA DAI2 EQ4 */
+ 0x00, /* AB DAI2 EQ4 */
+ 0x00, /* AC DAI2 EQ5 */
+ 0x00, /* AD DAI2 EQ5 */
+ 0x00, /* AE DAI2 EQ5 */
+ 0x00, /* AF DAI2 EQ5 */
+
+ 0x00, /* B0 DAI2 EQ5 */
+ 0x00, /* B1 DAI2 EQ5 */
+ 0x00, /* B2 DAI2 EQ5 */
+ 0x00, /* B3 DAI2 EQ5 */
+ 0x00, /* B4 DAI2 EQ5 */
+ 0x00, /* B5 DAI2 EQ5 */
+ 0x00, /* B6 DAI1 biquad */
+ 0x00, /* B7 DAI1 biquad */
+ 0x00, /* B8 DAI1 biquad */
+ 0x00, /* B9 DAI1 biquad */
+ 0x00, /* BA DAI1 biquad */
+ 0x00, /* BB DAI1 biquad */
+ 0x00, /* BC DAI1 biquad */
+ 0x00, /* BD DAI1 biquad */
+ 0x00, /* BE DAI1 biquad */
+ 0x00, /* BF DAI1 biquad */
+
+ 0x00, /* C0 DAI2 biquad */
+ 0x00, /* C1 DAI2 biquad */
+ 0x00, /* C2 DAI2 biquad */
+ 0x00, /* C3 DAI2 biquad */
+ 0x00, /* C4 DAI2 biquad */
+ 0x00, /* C5 DAI2 biquad */
+ 0x00, /* C6 DAI2 biquad */
+ 0x00, /* C7 DAI2 biquad */
+ 0x00, /* C8 DAI2 biquad */
+ 0x00, /* C9 DAI2 biquad */
+ 0x00, /* CA */
+ 0x00, /* CB */
+ 0x00, /* CC */
+ 0x00, /* CD */
+ 0x00, /* CE */
+ 0x00, /* CF */
+
+ 0x00, /* D0 */
+ 0x00, /* D1 */
+ 0x00, /* D2 */
+ 0x00, /* D3 */
+ 0x00, /* D4 */
+ 0x00, /* D5 */
+ 0x00, /* D6 */
+ 0x00, /* D7 */
+ 0x00, /* D8 */
+ 0x00, /* D9 */
+ 0x00, /* DA */
+ 0x70, /* DB */
+ 0x00, /* DC */
+ 0x00, /* DD */
+ 0x00, /* DE */
+ 0x00, /* DF */
+
+ 0x00, /* E0 */
+ 0x00, /* E1 */
+ 0x00, /* E2 */
+ 0x00, /* E3 */
+ 0x00, /* E4 */
+ 0x00, /* E5 */
+ 0x00, /* E6 */
+ 0x00, /* E7 */
+ 0x00, /* E8 */
+ 0x00, /* E9 */
+ 0x00, /* EA */
+ 0x00, /* EB */
+ 0x00, /* EC */
+ 0x00, /* ED */
+ 0x00, /* EE */
+ 0x00, /* EF */
+
+ 0x00, /* F0 */
+ 0x00, /* F1 */
+ 0x00, /* F2 */
+ 0x00, /* F3 */
+ 0x00, /* F4 */
+ 0x00, /* F5 */
+ 0x00, /* F6 */
+ 0x00, /* F7 */
+ 0x00, /* F8 */
+ 0x00, /* F9 */
+ 0x00, /* FA */
+ 0x00, /* FB */
+ 0x00, /* FC */
+ 0x00, /* FD */
+ 0x00, /* FE */
+ 0x00, /* FF */
+};
+
+static struct {
+ int readable;
+ int writable;
+ int vol;
+} max98088_access[M98088_REG_CNT] = {
+ { 0xFF, 0xFF, 1 }, /* 00 IRQ status */
+ { 0xFF, 0x00, 1 }, /* 01 MIC status */
+ { 0xFF, 0x00, 1 }, /* 02 jack status */
+ { 0x1F, 0x1F, 1 }, /* 03 battery voltage */
+ { 0xFF, 0xFF, 0 }, /* 04 */
+ { 0xFF, 0xFF, 0 }, /* 05 */
+ { 0xFF, 0xFF, 0 }, /* 06 */
+ { 0xFF, 0xFF, 0 }, /* 07 */
+ { 0xFF, 0xFF, 0 }, /* 08 */
+ { 0xFF, 0xFF, 0 }, /* 09 */
+ { 0xFF, 0xFF, 0 }, /* 0A */
+ { 0xFF, 0xFF, 0 }, /* 0B */
+ { 0xFF, 0xFF, 0 }, /* 0C */
+ { 0xFF, 0xFF, 0 }, /* 0D */
+ { 0xFF, 0xFF, 0 }, /* 0E */
+ { 0xFF, 0xFF, 0 }, /* 0F interrupt enable */
+
+ { 0xFF, 0xFF, 0 }, /* 10 master clock */
+ { 0xFF, 0xFF, 0 }, /* 11 DAI1 clock mode */
+ { 0xFF, 0xFF, 0 }, /* 12 DAI1 clock control */
+ { 0xFF, 0xFF, 0 }, /* 13 DAI1 clock control */
+ { 0xFF, 0xFF, 0 }, /* 14 DAI1 format */
+ { 0xFF, 0xFF, 0 }, /* 15 DAI1 clock */
+ { 0xFF, 0xFF, 0 }, /* 16 DAI1 config */
+ { 0xFF, 0xFF, 0 }, /* 17 DAI1 TDM */
+ { 0xFF, 0xFF, 0 }, /* 18 DAI1 filters */
+ { 0xFF, 0xFF, 0 }, /* 19 DAI2 clock mode */
+ { 0xFF, 0xFF, 0 }, /* 1A DAI2 clock control */
+ { 0xFF, 0xFF, 0 }, /* 1B DAI2 clock control */
+ { 0xFF, 0xFF, 0 }, /* 1C DAI2 format */
+ { 0xFF, 0xFF, 0 }, /* 1D DAI2 clock */
+ { 0xFF, 0xFF, 0 }, /* 1E DAI2 config */
+ { 0xFF, 0xFF, 0 }, /* 1F DAI2 TDM */
+
+ { 0xFF, 0xFF, 0 }, /* 20 DAI2 filters */
+ { 0xFF, 0xFF, 0 }, /* 21 data config */
+ { 0xFF, 0xFF, 0 }, /* 22 DAC mixer */
+ { 0xFF, 0xFF, 0 }, /* 23 left ADC mixer */
+ { 0xFF, 0xFF, 0 }, /* 24 right ADC mixer */
+ { 0xFF, 0xFF, 0 }, /* 25 left HP mixer */
+ { 0xFF, 0xFF, 0 }, /* 26 right HP mixer */
+ { 0xFF, 0xFF, 0 }, /* 27 HP control */
+ { 0xFF, 0xFF, 0 }, /* 28 left REC mixer */
+ { 0xFF, 0xFF, 0 }, /* 29 right REC mixer */
+ { 0xFF, 0xFF, 0 }, /* 2A REC control */
+ { 0xFF, 0xFF, 0 }, /* 2B left SPK mixer */
+ { 0xFF, 0xFF, 0 }, /* 2C right SPK mixer */
+ { 0xFF, 0xFF, 0 }, /* 2D SPK control */
+ { 0xFF, 0xFF, 0 }, /* 2E sidetone */
+ { 0xFF, 0xFF, 0 }, /* 2F DAI1 playback level */
+
+ { 0xFF, 0xFF, 0 }, /* 30 DAI1 playback level */
+ { 0xFF, 0xFF, 0 }, /* 31 DAI2 playback level */
+ { 0xFF, 0xFF, 0 }, /* 32 DAI2 playbakc level */
+ { 0xFF, 0xFF, 0 }, /* 33 left ADC level */
+ { 0xFF, 0xFF, 0 }, /* 34 right ADC level */
+ { 0xFF, 0xFF, 0 }, /* 35 MIC1 level */
+ { 0xFF, 0xFF, 0 }, /* 36 MIC2 level */
+ { 0xFF, 0xFF, 0 }, /* 37 INA level */
+ { 0xFF, 0xFF, 0 }, /* 38 INB level */
+ { 0xFF, 0xFF, 0 }, /* 39 left HP volume */
+ { 0xFF, 0xFF, 0 }, /* 3A right HP volume */
+ { 0xFF, 0xFF, 0 }, /* 3B left REC volume */
+ { 0xFF, 0xFF, 0 }, /* 3C right REC volume */
+ { 0xFF, 0xFF, 0 }, /* 3D left SPK volume */
+ { 0xFF, 0xFF, 0 }, /* 3E right SPK volume */
+ { 0xFF, 0xFF, 0 }, /* 3F MIC config */
+
+ { 0xFF, 0xFF, 0 }, /* 40 MIC threshold */
+ { 0xFF, 0xFF, 0 }, /* 41 excursion limiter filter */
+ { 0xFF, 0xFF, 0 }, /* 42 excursion limiter threshold */
+ { 0xFF, 0xFF, 0 }, /* 43 ALC */
+ { 0xFF, 0xFF, 0 }, /* 44 power limiter threshold */
+ { 0xFF, 0xFF, 0 }, /* 45 power limiter config */
+ { 0xFF, 0xFF, 0 }, /* 46 distortion limiter config */
+ { 0xFF, 0xFF, 0 }, /* 47 audio input */
+ { 0xFF, 0xFF, 0 }, /* 48 microphone */
+ { 0xFF, 0xFF, 0 }, /* 49 level control */
+ { 0xFF, 0xFF, 0 }, /* 4A bypass switches */
+ { 0xFF, 0xFF, 0 }, /* 4B jack detect */
+ { 0xFF, 0xFF, 0 }, /* 4C input enable */
+ { 0xFF, 0xFF, 0 }, /* 4D output enable */
+ { 0xFF, 0xFF, 0 }, /* 4E bias control */
+ { 0xFF, 0xFF, 0 }, /* 4F DAC power */
+
+ { 0xFF, 0xFF, 0 }, /* 50 DAC power */
+ { 0xFF, 0xFF, 0 }, /* 51 system */
+ { 0xFF, 0xFF, 0 }, /* 52 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 53 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 54 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 55 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 56 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 57 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 58 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 59 DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 5A DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 5B DAI1 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 5C DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 5D DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 5E DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 5F DAI1 EQ2 */
+
+ { 0xFF, 0xFF, 0 }, /* 60 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 61 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 62 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 63 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 64 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 65 DAI1 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 66 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 67 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 68 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 69 DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6A DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6B DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6C DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6D DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6E DAI1 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 6F DAI1 EQ3 */
+
+ { 0xFF, 0xFF, 0 }, /* 70 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 71 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 72 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 73 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 74 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 75 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 76 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 77 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 78 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 79 DAI1 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* 7A DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7B DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7C DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7D DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7E DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 7F DAI1 EQ5 */
+
+ { 0xFF, 0xFF, 0 }, /* 80 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 81 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 82 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 83 DAI1 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* 84 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 85 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 86 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 87 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 88 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 89 DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8A DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8B DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8C DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8D DAI2 EQ1 */
+ { 0xFF, 0xFF, 0 }, /* 8E DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 8F DAI2 EQ2 */
+
+ { 0xFF, 0xFF, 0 }, /* 90 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 91 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 92 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 93 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 94 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 95 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 96 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 97 DAI2 EQ2 */
+ { 0xFF, 0xFF, 0 }, /* 98 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 99 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9A DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9B DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9C DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9D DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9E DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* 9F DAI2 EQ3 */
+
+ { 0xFF, 0xFF, 0 }, /* A0 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* A1 DAI2 EQ3 */
+ { 0xFF, 0xFF, 0 }, /* A2 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A3 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A4 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A5 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A6 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A7 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A8 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* A9 DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* AA DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* AB DAI2 EQ4 */
+ { 0xFF, 0xFF, 0 }, /* AC DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* AD DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* AE DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* AF DAI2 EQ5 */
+
+ { 0xFF, 0xFF, 0 }, /* B0 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B1 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B2 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B3 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B4 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B5 DAI2 EQ5 */
+ { 0xFF, 0xFF, 0 }, /* B6 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* B7 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* B8 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* B9 DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BA DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BB DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BC DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BD DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BE DAI1 biquad */
+ { 0xFF, 0xFF, 0 }, /* BF DAI1 biquad */
+
+ { 0xFF, 0xFF, 0 }, /* C0 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C1 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C2 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C3 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C4 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C5 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C6 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C7 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C8 DAI2 biquad */
+ { 0xFF, 0xFF, 0 }, /* C9 DAI2 biquad */
+ { 0x00, 0x00, 0 }, /* CA */
+ { 0x00, 0x00, 0 }, /* CB */
+ { 0x00, 0x00, 0 }, /* CC */
+ { 0x00, 0x00, 0 }, /* CD */
+ { 0x00, 0x00, 0 }, /* CE */
+ { 0x00, 0x00, 0 }, /* CF */
+
+ { 0x00, 0x00, 0 }, /* D0 */
+ { 0x00, 0x00, 0 }, /* D1 */
+ { 0x00, 0x00, 0 }, /* D2 */
+ { 0x00, 0x00, 0 }, /* D3 */
+ { 0x00, 0x00, 0 }, /* D4 */
+ { 0x00, 0x00, 0 }, /* D5 */
+ { 0x00, 0x00, 0 }, /* D6 */
+ { 0x00, 0x00, 0 }, /* D7 */
+ { 0x00, 0x00, 0 }, /* D8 */
+ { 0x00, 0x00, 0 }, /* D9 */
+ { 0x00, 0x00, 0 }, /* DA */
+ { 0x00, 0x00, 0 }, /* DB */
+ { 0x00, 0x00, 0 }, /* DC */
+ { 0x00, 0x00, 0 }, /* DD */
+ { 0x00, 0x00, 0 }, /* DE */
+ { 0x00, 0x00, 0 }, /* DF */
+
+ { 0x00, 0x00, 0 }, /* E0 */
+ { 0x00, 0x00, 0 }, /* E1 */
+ { 0x00, 0x00, 0 }, /* E2 */
+ { 0x00, 0x00, 0 }, /* E3 */
+ { 0x00, 0x00, 0 }, /* E4 */
+ { 0x00, 0x00, 0 }, /* E5 */
+ { 0x00, 0x00, 0 }, /* E6 */
+ { 0x00, 0x00, 0 }, /* E7 */
+ { 0x00, 0x00, 0 }, /* E8 */
+ { 0x00, 0x00, 0 }, /* E9 */
+ { 0x00, 0x00, 0 }, /* EA */
+ { 0x00, 0x00, 0 }, /* EB */
+ { 0x00, 0x00, 0 }, /* EC */
+ { 0x00, 0x00, 0 }, /* ED */
+ { 0x00, 0x00, 0 }, /* EE */
+ { 0x00, 0x00, 0 }, /* EF */
+
+ { 0x00, 0x00, 0 }, /* F0 */
+ { 0x00, 0x00, 0 }, /* F1 */
+ { 0x00, 0x00, 0 }, /* F2 */
+ { 0x00, 0x00, 0 }, /* F3 */
+ { 0x00, 0x00, 0 }, /* F4 */
+ { 0x00, 0x00, 0 }, /* F5 */
+ { 0x00, 0x00, 0 }, /* F6 */
+ { 0x00, 0x00, 0 }, /* F7 */
+ { 0x00, 0x00, 0 }, /* F8 */
+ { 0x00, 0x00, 0 }, /* F9 */
+ { 0x00, 0x00, 0 }, /* FA */
+ { 0x00, 0x00, 0 }, /* FB */
+ { 0x00, 0x00, 0 }, /* FC */
+ { 0x00, 0x00, 0 }, /* FD */
+ { 0x00, 0x00, 0 }, /* FE */
+ { 0xFF, 0x00, 1 }, /* FF */
+};
+
+static int max98088_volatile_register(unsigned int reg)
+{
+ return max98088_access[reg].vol;
+}
+
+
+/*
+ * Load equalizer DSP coefficient configurations registers
+ */
+static void m98088_eq_band(struct snd_soc_codec *codec, unsigned int dai,
+ unsigned int band, u16 *coefs)
+{
+ unsigned int eq_reg;
+ unsigned int i;
+
+ BUG_ON(band > 4);
+ BUG_ON(dai > 1);
+
+ /* Load the base register address */
+ eq_reg = dai ? M98088_REG_84_DAI2_EQ_BASE : M98088_REG_52_DAI1_EQ_BASE;
+
+ /* Add the band address offset, note adjustment for word address */
+ eq_reg += band * (M98088_COEFS_PER_BAND << 1);
+
+ /* Step through the registers and coefs */
+ for (i = 0; i < M98088_COEFS_PER_BAND; i++) {
+ snd_soc_write(codec, eq_reg++, M98088_BYTE1(coefs[i]));
+ snd_soc_write(codec, eq_reg++, M98088_BYTE0(coefs[i]));
+ }
+}
+
+/*
+ * Excursion limiter modes
+ */
+static const char *max98088_exmode_texts[] = {
+ "Off", "100Hz", "400Hz", "600Hz", "800Hz", "1000Hz", "200-400Hz",
+ "400-600Hz", "400-800Hz",
+};
+
+static const unsigned int max98088_exmode_values[] = {
+ 0x00, 0x43, 0x10, 0x20, 0x30, 0x40, 0x11, 0x22, 0x32
+};
+
+static const struct soc_enum max98088_exmode_enum =
+ SOC_VALUE_ENUM_SINGLE(M98088_REG_41_SPKDHP, 0, 127,
+ ARRAY_SIZE(max98088_exmode_texts),
+ max98088_exmode_texts,
+ max98088_exmode_values);
+static const struct snd_kcontrol_new max98088_exmode_controls =
+ SOC_DAPM_VALUE_ENUM("Route", max98088_exmode_enum);
+
+static const char *max98088_ex_thresh[] = { /* volts PP */
+ "0.6", "1.2", "1.8", "2.4", "3.0", "3.6", "4.2", "4.8"};
+static const struct soc_enum max98088_ex_thresh_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_42_SPKDHP_THRESH, 0, 8,
+ max98088_ex_thresh),
+};
+
+static const char *max98088_fltr_mode[] = {"Voice", "Music" };
+static const struct soc_enum max98088_filter_mode_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 7, 2, max98088_fltr_mode),
+};
+
+static const char *max98088_extmic_text[] = { "None", "MIC1", "MIC2" };
+
+static const struct soc_enum max98088_extmic_enum =
+ SOC_ENUM_SINGLE(M98088_REG_48_CFG_MIC, 0, 3, max98088_extmic_text);
+
+static const struct snd_kcontrol_new max98088_extmic_mux =
+ SOC_DAPM_ENUM("External MIC Mux", max98088_extmic_enum);
+
+static const char *max98088_dai1_fltr[] = {
+ "Off", "fc=258/fs=16k", "fc=500/fs=16k",
+ "fc=258/fs=8k", "fc=500/fs=8k", "fc=200"};
+static const struct soc_enum max98088_dai1_dac_filter_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 0, 6, max98088_dai1_fltr),
+};
+static const struct soc_enum max98088_dai1_adc_filter_enum[] = {
+ SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 4, 6, max98088_dai1_fltr),
+};
+
+static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int sel = ucontrol->value.integer.value[0];
+
+ max98088->mic1pre = sel;
+ snd_soc_update_bits(codec, M98088_REG_35_LVL_MIC1, M98088_MICPRE_MASK,
+ (1+sel)<<M98088_MICPRE_SHIFT);
+
+ return 0;
+}
+
+static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = max98088->mic1pre;
+ return 0;
+}
+
+static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ unsigned int sel = ucontrol->value.integer.value[0];
+
+ max98088->mic2pre = sel;
+ snd_soc_update_bits(codec, M98088_REG_36_LVL_MIC2, M98088_MICPRE_MASK,
+ (1+sel)<<M98088_MICPRE_SHIFT);
+
+ return 0;
+}
+
+static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = max98088->mic2pre;
+ return 0;
+}
+
+static const unsigned int max98088_micboost_tlv[] = {
+ TLV_DB_RANGE_HEAD(2),
+ 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
+};
+
+static const struct snd_kcontrol_new max98088_snd_controls[] = {
+
+ SOC_DOUBLE_R("Headphone Volume", M98088_REG_39_LVL_HP_L,
+ M98088_REG_3A_LVL_HP_R, 0, 31, 0),
+ SOC_DOUBLE_R("Speaker Volume", M98088_REG_3D_LVL_SPK_L,
+ M98088_REG_3E_LVL_SPK_R, 0, 31, 0),
+ SOC_DOUBLE_R("Receiver Volume", M98088_REG_3B_LVL_REC_L,
+ M98088_REG_3C_LVL_REC_R, 0, 31, 0),
+
+ SOC_DOUBLE_R("Headphone Switch", M98088_REG_39_LVL_HP_L,
+ M98088_REG_3A_LVL_HP_R, 7, 1, 1),
+ SOC_DOUBLE_R("Speaker Switch", M98088_REG_3D_LVL_SPK_L,
+ M98088_REG_3E_LVL_SPK_R, 7, 1, 1),
+ SOC_DOUBLE_R("Receiver Switch", M98088_REG_3B_LVL_REC_L,
+ M98088_REG_3C_LVL_REC_R, 7, 1, 1),
+
+ SOC_SINGLE("MIC1 Volume", M98088_REG_35_LVL_MIC1, 0, 31, 1),
+ SOC_SINGLE("MIC2 Volume", M98088_REG_36_LVL_MIC2, 0, 31, 1),
+
+ SOC_SINGLE_EXT_TLV("MIC1 Boost Volume",
+ M98088_REG_35_LVL_MIC1, 5, 2, 0,
+ max98088_mic1pre_get, max98088_mic1pre_set,
+ max98088_micboost_tlv),
+ SOC_SINGLE_EXT_TLV("MIC2 Boost Volume",
+ M98088_REG_36_LVL_MIC2, 5, 2, 0,
+ max98088_mic2pre_get, max98088_mic2pre_set,
+ max98088_micboost_tlv),
+
+ SOC_SINGLE("INA Volume", M98088_REG_37_LVL_INA, 0, 7, 1),
+ SOC_SINGLE("INB Volume", M98088_REG_38_LVL_INB, 0, 7, 1),
+
+ SOC_SINGLE("ADCL Volume", M98088_REG_33_LVL_ADC_L, 0, 15, 0),
+ SOC_SINGLE("ADCR Volume", M98088_REG_34_LVL_ADC_R, 0, 15, 0),
+
+ SOC_SINGLE("ADCL Boost Volume", M98088_REG_33_LVL_ADC_L, 4, 3, 0),
+ SOC_SINGLE("ADCR Boost Volume", M98088_REG_34_LVL_ADC_R, 4, 3, 0),
+
+ SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0),
+ SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0),
+
+ SOC_ENUM("EX Limiter Threshold", max98088_ex_thresh_enum),
+
+ SOC_ENUM("DAI1 Filter Mode", max98088_filter_mode_enum),
+ SOC_ENUM("DAI1 DAC Filter", max98088_dai1_dac_filter_enum),
+ SOC_ENUM("DAI1 ADC Filter", max98088_dai1_adc_filter_enum),
+ SOC_SINGLE("DAI2 DC Block Switch", M98088_REG_20_DAI2_FILTERS,
+ 0, 1, 0),
+
+ SOC_SINGLE("ALC Switch", M98088_REG_43_SPKALC_COMP, 7, 1, 0),
+ SOC_SINGLE("ALC Threshold", M98088_REG_43_SPKALC_COMP, 0, 7, 0),
+ SOC_SINGLE("ALC Multiband", M98088_REG_43_SPKALC_COMP, 3, 1, 0),
+ SOC_SINGLE("ALC Release Time", M98088_REG_43_SPKALC_COMP, 4, 7, 0),
+
+ SOC_SINGLE("PWR Limiter Threshold", M98088_REG_44_PWRLMT_CFG,
+ 4, 15, 0),
+ SOC_SINGLE("PWR Limiter Weight", M98088_REG_44_PWRLMT_CFG, 0, 7, 0),
+ SOC_SINGLE("PWR Limiter Time1", M98088_REG_45_PWRLMT_TIME, 0, 15, 0),
+ SOC_SINGLE("PWR Limiter Time2", M98088_REG_45_PWRLMT_TIME, 4, 15, 0),
+
+ SOC_SINGLE("THD Limiter Threshold", M98088_REG_46_THDLMT_CFG, 4, 15, 0),
+ SOC_SINGLE("THD Limiter Time", M98088_REG_46_THDLMT_CFG, 0, 7, 0),
+};
+
+/* Left speaker mixer switch */
+static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 4, 1, 0),
+};
+
+/* Right speaker mixer switch */
+static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 4, 1, 0),
+};
+
+/* Left headphone mixer switch */
+static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_25_MIX_HP_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_25_MIX_HP_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_25_MIX_HP_LEFT, 4, 1, 0),
+};
+
+/* Right headphone mixer switch */
+static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_26_MIX_HP_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_26_MIX_HP_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_26_MIX_HP_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_26_MIX_HP_RIGHT, 4, 1, 0),
+};
+
+/* Left earpiece/receiver mixer switch */
+static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_28_MIX_REC_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_28_MIX_REC_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_28_MIX_REC_LEFT, 4, 1, 0),
+};
+
+/* Right earpiece/receiver mixer switch */
+static const struct snd_kcontrol_new max98088_right_rec_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 5, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_29_MIX_REC_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_29_MIX_REC_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_29_MIX_REC_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_29_MIX_REC_RIGHT, 4, 1, 0),
+};
+
+/* Left ADC mixer switch */
+static const struct snd_kcontrol_new max98088_left_ADC_mixer_controls[] = {
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_23_MIX_ADC_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_23_MIX_ADC_LEFT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_23_MIX_ADC_LEFT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_23_MIX_ADC_LEFT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_23_MIX_ADC_LEFT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_23_MIX_ADC_LEFT, 0, 1, 0),
+};
+
+/* Right ADC mixer switch */
+static const struct snd_kcontrol_new max98088_right_ADC_mixer_controls[] = {
+ SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 6, 1, 0),
+ SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 3, 1, 0),
+ SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 2, 1, 0),
+ SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 1, 1, 0),
+ SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 0, 1, 0),
+};
+
+static int max98088_mic_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (w->reg == M98088_REG_35_LVL_MIC1) {
+ snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK,
+ (1+max98088->mic1pre)<<M98088_MICPRE_SHIFT);
+ } else {
+ snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK,
+ (1+max98088->mic2pre)<<M98088_MICPRE_SHIFT);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * The line inputs are 2-channel stereo inputs with the left
+ * and right channels sharing a common PGA power control signal.
+ */
+static int max98088_line_pga(struct snd_soc_dapm_widget *w,
+ int event, int line, u8 channel)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ u8 *state;
+
+ BUG_ON(!((channel == 1) || (channel == 2)));
+
+ switch (line) {
+ case LINE_INA:
+ state = &max98088->ina_state;
+ break;
+ case LINE_INB:
+ state = &max98088->inb_state;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ *state |= channel;
+ snd_soc_update_bits(codec, w->reg,
+ (1 << w->shift), (1 << w->shift));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ *state &= ~channel;
+ if (*state == 0) {
+ snd_soc_update_bits(codec, w->reg,
+ (1 << w->shift), 0);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int max98088_pga_ina1_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ return max98088_line_pga(w, event, LINE_INA, 1);
+}
+
+static int max98088_pga_ina2_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ return max98088_line_pga(w, event, LINE_INA, 2);
+}
+
+static int max98088_pga_inb1_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ return max98088_line_pga(w, event, LINE_INB, 1);
+}
+
+static int max98088_pga_inb2_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ return max98088_line_pga(w, event, LINE_INB, 2);
+}
+
+static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
+
+ SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 1, 0),
+ SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 0, 0),
+
+ SND_SOC_DAPM_DAC("DACL1", "HiFi Playback",
+ M98088_REG_4D_PWR_EN_OUT, 1, 0),
+ SND_SOC_DAPM_DAC("DACR1", "HiFi Playback",
+ M98088_REG_4D_PWR_EN_OUT, 0, 0),
+ SND_SOC_DAPM_DAC("DACL2", "Aux Playback",
+ M98088_REG_4D_PWR_EN_OUT, 1, 0),
+ SND_SOC_DAPM_DAC("DACR2", "Aux Playback",
+ M98088_REG_4D_PWR_EN_OUT, 0, 0),
+
+ SND_SOC_DAPM_PGA("HP Left Out", M98088_REG_4D_PWR_EN_OUT,
+ 7, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("HP Right Out", M98088_REG_4D_PWR_EN_OUT,
+ 6, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("SPK Left Out", M98088_REG_4D_PWR_EN_OUT,
+ 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("SPK Right Out", M98088_REG_4D_PWR_EN_OUT,
+ 4, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("REC Left Out", M98088_REG_4D_PWR_EN_OUT,
+ 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("REC Right Out", M98088_REG_4D_PWR_EN_OUT,
+ 2, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("External MIC", SND_SOC_NOPM, 0, 0,
+ &max98088_extmic_mux),
+
+ SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_hp_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_hp_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_hp_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_hp_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Left SPK Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_speaker_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_speaker_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right SPK Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_speaker_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_speaker_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Left REC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_rec_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_rec_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right REC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_rec_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_rec_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_left_ADC_mixer_controls[0],
+ ARRAY_SIZE(max98088_left_ADC_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
+ &max98088_right_ADC_mixer_controls[0],
+ ARRAY_SIZE(max98088_right_ADC_mixer_controls)),
+
+ SND_SOC_DAPM_PGA_E("MIC1 Input", M98088_REG_35_LVL_MIC1,
+ 5, 0, NULL, 0, max98088_mic_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("MIC2 Input", M98088_REG_36_LVL_MIC2,
+ 5, 0, NULL, 0, max98088_mic_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INA1 Input", M98088_REG_4C_PWR_EN_IN,
+ 7, 0, NULL, 0, max98088_pga_ina1_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INA2 Input", M98088_REG_4C_PWR_EN_IN,
+ 7, 0, NULL, 0, max98088_pga_ina2_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INB1 Input", M98088_REG_4C_PWR_EN_IN,
+ 6, 0, NULL, 0, max98088_pga_inb1_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("INB2 Input", M98088_REG_4C_PWR_EN_IN,
+ 6, 0, NULL, 0, max98088_pga_inb2_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MICBIAS("MICBIAS", M98088_REG_4C_PWR_EN_IN, 3, 0),
+
+ SND_SOC_DAPM_MUX("EX Limiter Mode", SND_SOC_NOPM, 0, 0,
+ &max98088_exmode_controls),
+
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+ SND_SOC_DAPM_OUTPUT("SPKL"),
+ SND_SOC_DAPM_OUTPUT("SPKR"),
+ SND_SOC_DAPM_OUTPUT("RECL"),
+ SND_SOC_DAPM_OUTPUT("RECR"),
+
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("INA1"),
+ SND_SOC_DAPM_INPUT("INA2"),
+ SND_SOC_DAPM_INPUT("INB1"),
+ SND_SOC_DAPM_INPUT("INB2"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* Left headphone output mixer */
+ {"Left HP Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Left HP Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Left HP Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Left HP Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left HP Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left HP Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left HP Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left HP Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left HP Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left HP Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Right headphone output mixer */
+ {"Right HP Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Right HP Mixer", "Left DAC2 Switch", "DACL2" },
+ {"Right HP Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Right HP Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right HP Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right HP Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right HP Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right HP Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right HP Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right HP Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Left speaker output mixer */
+ {"Left SPK Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Left SPK Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Left SPK Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Left SPK Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left SPK Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left SPK Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left SPK Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left SPK Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left SPK Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left SPK Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Right speaker output mixer */
+ {"Right SPK Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Right SPK Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Right SPK Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Right SPK Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right SPK Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right SPK Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right SPK Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right SPK Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right SPK Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right SPK Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Earpiece/Receiver output mixer */
+ {"Left REC Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Left REC Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Left REC Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Left REC Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left REC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left REC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left REC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left REC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left REC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left REC Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Earpiece/Receiver output mixer */
+ {"Right REC Mixer", "Left DAC1 Switch", "DACL1"},
+ {"Right REC Mixer", "Left DAC2 Switch", "DACL2"},
+ {"Right REC Mixer", "Right DAC1 Switch", "DACR1"},
+ {"Right REC Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right REC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right REC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right REC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right REC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right REC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right REC Mixer", "INB2 Switch", "INB2 Input"},
+
+ {"HP Left Out", NULL, "Left HP Mixer"},
+ {"HP Right Out", NULL, "Right HP Mixer"},
+ {"SPK Left Out", NULL, "Left SPK Mixer"},
+ {"SPK Right Out", NULL, "Right SPK Mixer"},
+ {"REC Left Out", NULL, "Left REC Mixer"},
+ {"REC Right Out", NULL, "Right REC Mixer"},
+
+ {"HPL", NULL, "HP Left Out"},
+ {"HPR", NULL, "HP Right Out"},
+ {"SPKL", NULL, "SPK Left Out"},
+ {"SPKR", NULL, "SPK Right Out"},
+ {"RECL", NULL, "REC Left Out"},
+ {"RECR", NULL, "REC Right Out"},
+
+ /* Left ADC input mixer */
+ {"Left ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Left ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Left ADC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Left ADC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Left ADC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Left ADC Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Right ADC input mixer */
+ {"Right ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+ {"Right ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+ {"Right ADC Mixer", "INA1 Switch", "INA1 Input"},
+ {"Right ADC Mixer", "INA2 Switch", "INA2 Input"},
+ {"Right ADC Mixer", "INB1 Switch", "INB1 Input"},
+ {"Right ADC Mixer", "INB2 Switch", "INB2 Input"},
+
+ /* Inputs */
+ {"ADCL", NULL, "Left ADC Mixer"},
+ {"ADCR", NULL, "Right ADC Mixer"},
+ {"INA1 Input", NULL, "INA1"},
+ {"INA2 Input", NULL, "INA2"},
+ {"INB1 Input", NULL, "INB1"},
+ {"INB2 Input", NULL, "INB2"},
+ {"MIC1 Input", NULL, "MIC1"},
+ {"MIC2 Input", NULL, "MIC2"},
+};
+
+static int max98088_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, max98088_dapm_widgets,
+ ARRAY_SIZE(max98088_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ snd_soc_add_controls(codec, max98088_snd_controls,
+ ARRAY_SIZE(max98088_snd_controls));
+
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+/* codec mclk clock divider coefficients */
+static const struct {
+ u32 rate;
+ u8 sr;
+} rate_table[] = {
+ {8000, 0x10},
+ {11025, 0x20},
+ {16000, 0x30},
+ {22050, 0x40},
+ {24000, 0x50},
+ {32000, 0x60},
+ {44100, 0x70},
+ {48000, 0x80},
+ {88200, 0x90},
+ {96000, 0xA0},
+};
+
+static inline int rate_value(int rate, u8 *value)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+ if (rate_table[i].rate >= rate) {
+ *value = rate_table[i].sr;
+ return 0;
+ }
+ }
+ *value = rate_table[0].sr;
+ return -EINVAL;
+}
+
+static int max98088_dai1_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ unsigned long long ni;
+ unsigned int rate;
+ u8 regval;
+
+ cdata = &max98088->dai[0];
+
+ rate = params_rate(params);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+ M98088_DAI_WS, 0);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+ M98088_DAI_WS, M98088_DAI_WS);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+
+ if (rate_value(rate, &regval))
+ return -EINVAL;
+
+ snd_soc_update_bits(codec, M98088_REG_11_DAI1_CLKMODE,
+ M98088_CLKMODE_MASK, regval);
+ cdata->rate = rate;
+
+ /* Configure NI when operating as master */
+ if (snd_soc_read(codec, M98088_REG_14_DAI1_FORMAT)
+ & M98088_DAI_MAS) {
+ if (max98088->sysclk == 0) {
+ dev_err(codec->dev, "Invalid system clock frequency\n");
+ return -EINVAL;
+ }
+ ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+ * (unsigned long long int)rate;
+ do_div(ni, (unsigned long long int)max98088->sysclk);
+ snd_soc_write(codec, M98088_REG_12_DAI1_CLKCFG_HI,
+ (ni >> 8) & 0x7F);
+ snd_soc_write(codec, M98088_REG_13_DAI1_CLKCFG_LO,
+ ni & 0xFF);
+ }
+
+ /* Update sample rate mode */
+ if (rate < 50000)
+ snd_soc_update_bits(codec, M98088_REG_18_DAI1_FILTERS,
+ M98088_DAI_DHF, 0);
+ else
+ snd_soc_update_bits(codec, M98088_REG_18_DAI1_FILTERS,
+ M98088_DAI_DHF, M98088_DAI_DHF);
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN,
+ M98088_SHDNRUN);
+
+ return 0;
+}
+
+static int max98088_dai2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ unsigned long long ni;
+ unsigned int rate;
+ u8 regval;
+
+ cdata = &max98088->dai[1];
+
+ rate = params_rate(params);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+ M98088_DAI_WS, 0);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+ M98088_DAI_WS, M98088_DAI_WS);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+
+ if (rate_value(rate, &regval))
+ return -EINVAL;
+
+ snd_soc_update_bits(codec, M98088_REG_19_DAI2_CLKMODE,
+ M98088_CLKMODE_MASK, regval);
+ cdata->rate = rate;
+
+ /* Configure NI when operating as master */
+ if (snd_soc_read(codec, M98088_REG_1C_DAI2_FORMAT)
+ & M98088_DAI_MAS) {
+ if (max98088->sysclk == 0) {
+ dev_err(codec->dev, "Invalid system clock frequency\n");
+ return -EINVAL;
+ }
+ ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+ * (unsigned long long int)rate;
+ do_div(ni, (unsigned long long int)max98088->sysclk);
+ snd_soc_write(codec, M98088_REG_1A_DAI2_CLKCFG_HI,
+ (ni >> 8) & 0x7F);
+ snd_soc_write(codec, M98088_REG_1B_DAI2_CLKCFG_LO,
+ ni & 0xFF);
+ }
+
+ /* Update sample rate mode */
+ if (rate < 50000)
+ snd_soc_update_bits(codec, M98088_REG_20_DAI2_FILTERS,
+ M98088_DAI_DHF, 0);
+ else
+ snd_soc_update_bits(codec, M98088_REG_20_DAI2_FILTERS,
+ M98088_DAI_DHF, M98088_DAI_DHF);
+
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN,
+ M98088_SHDNRUN);
+
+ return 0;
+}
+
+static int max98088_dai_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+ /* Requested clock frequency is already setup */
+ if (freq == max98088->sysclk)
+ return 0;
+
+ max98088->sysclk = freq; /* remember current sysclk */
+
+ /* Setup clocks for slave mode, and using the PLL
+ * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
+ * 0x02 (when master clk is 20MHz to 30MHz)..
+ */
+ if ((freq >= 10000000) && (freq < 20000000)) {
+ snd_soc_write(codec, M98088_REG_10_SYS_CLK, 0x10);
+ } else if ((freq >= 20000000) && (freq < 30000000)) {
+ snd_soc_write(codec, M98088_REG_10_SYS_CLK, 0x20);
+ } else {
+ dev_err(codec->dev, "Invalid master clock frequency\n");
+ return -EINVAL;
+ }
+
+ if (snd_soc_read(codec, M98088_REG_51_PWR_SYS) & M98088_SHDNRUN) {
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS,
+ M98088_SHDNRUN, 0);
+ snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS,
+ M98088_SHDNRUN, M98088_SHDNRUN);
+ }
+
+ dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+ max98088->sysclk = freq;
+ return 0;
+}
+
+static int max98088_dai1_set_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ u8 reg15val;
+ u8 reg14val = 0;
+
+ cdata = &max98088->dai[0];
+
+ if (fmt != cdata->fmt) {
+ cdata->fmt = fmt;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* Slave mode PLL */
+ snd_soc_write(codec, M98088_REG_12_DAI1_CLKCFG_HI,
+ 0x80);
+ snd_soc_write(codec, M98088_REG_13_DAI1_CLKCFG_LO,
+ 0x00);
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* Set to master mode */
+ reg14val |= M98088_DAI_MAS;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ default:
+ dev_err(codec->dev, "Clock mode unsupported");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ reg14val |= M98088_DAI_DLY;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ reg14val |= M98088_DAI_WCI;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg14val |= M98088_DAI_BCI;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ reg14val |= M98088_DAI_BCI|M98088_DAI_WCI;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+ M98088_DAI_MAS | M98088_DAI_DLY | M98088_DAI_BCI |
+ M98088_DAI_WCI, reg14val);
+
+ reg15val = M98088_DAI_BSEL64;
+ if (max98088->digmic)
+ reg15val |= M98088_DAI_OSR64;
+ snd_soc_write(codec, M98088_REG_15_DAI1_CLOCK, reg15val);
+ }
+
+ return 0;
+}
+
+static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ u8 reg1Cval = 0;
+
+ cdata = &max98088->dai[1];
+
+ if (fmt != cdata->fmt) {
+ cdata->fmt = fmt;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* Slave mode PLL */
+ snd_soc_write(codec, M98088_REG_1A_DAI2_CLKCFG_HI,
+ 0x80);
+ snd_soc_write(codec, M98088_REG_1B_DAI2_CLKCFG_LO,
+ 0x00);
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* Set to master mode */
+ reg1Cval |= M98088_DAI_MAS;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ default:
+ dev_err(codec->dev, "Clock mode unsupported");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ reg1Cval |= M98088_DAI_DLY;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ reg1Cval |= M98088_DAI_WCI;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg1Cval |= M98088_DAI_BCI;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ reg1Cval |= M98088_DAI_BCI|M98088_DAI_WCI;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+ M98088_DAI_MAS | M98088_DAI_DLY | M98088_DAI_BCI |
+ M98088_DAI_WCI, reg1Cval);
+
+ snd_soc_write(codec, M98088_REG_1D_DAI2_CLOCK,
+ M98088_DAI_BSEL64);
+ }
+
+ return 0;
+}
+
+static void max98088_sync_cache(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ int i;
+
+ if (!codec->cache_sync)
+ return;
+
+ codec->cache_only = 0;
+
+ /* write back cached values if they're writeable and
+ * different from the hardware default.
+ */
+ for (i = 1; i < ARRAY_SIZE(max98088->reg_cache); i++) {
+ if (!max98088_access[i].writable)
+ continue;
+
+ if (max98088->reg_cache[i] == max98088_reg[i])
+ continue;
+
+ snd_soc_write(codec, i, max98088->reg_cache[i]);
+ }
+
+ codec->cache_sync = 0;
+}
+
+static int max98088_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_OFF)
+ max98088_sync_cache(codec);
+
+ snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+ M98088_MBEN, M98088_MBEN);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+ M98088_MBEN, 0);
+ codec->cache_sync = 1;
+ break;
+ }
+ codec->bias_level = level;
+ return 0;
+}
+
+#define MAX98088_RATES SNDRV_PCM_RATE_8000_96000
+#define MAX98088_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops max98088_dai1_ops = {
+ .set_sysclk = max98088_dai_set_sysclk,
+ .set_fmt = max98088_dai1_set_fmt,
+ .hw_params = max98088_dai1_hw_params,
+};
+
+static struct snd_soc_dai_ops max98088_dai2_ops = {
+ .set_sysclk = max98088_dai_set_sysclk,
+ .set_fmt = max98088_dai2_set_fmt,
+ .hw_params = max98088_dai2_hw_params,
+};
+
+static struct snd_soc_dai_driver max98088_dai[] = {
+{
+ .name = "HiFi",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98088_RATES,
+ .formats = MAX98088_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98088_RATES,
+ .formats = MAX98088_FORMATS,
+ },
+ .ops = &max98088_dai1_ops,
+},
+{
+ .name = "Aux",
+ .playback = {
+ .stream_name = "Aux Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98088_RATES,
+ .formats = MAX98088_FORMATS,
+ },
+ .ops = &max98088_dai2_ops,
+}
+};
+
+static int max98088_get_channel(const char *name)
+{
+ if (strcmp(name, "EQ1 Mode") == 0)
+ return 0;
+ if (strcmp(name, "EQ2 Mode") == 0)
+ return 1;
+ return -EINVAL;
+}
+
+static void max98088_setup_eq1(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_eq_cfg *coef_set;
+ int best, best_val, save, i, sel, fs;
+ struct max98088_cdata *cdata;
+
+ cdata = &max98088->dai[0];
+
+ if (!pdata || !max98088->eq_textcnt)
+ return;
+
+ /* Find the selected configuration with nearest sample rate */
+ fs = cdata->rate;
+ sel = cdata->eq_sel;
+
+ best = 0;
+ best_val = INT_MAX;
+ for (i = 0; i < pdata->eq_cfgcnt; i++) {
+ if (strcmp(pdata->eq_cfg[i].name, max98088->eq_texts[sel]) == 0 &&
+ abs(pdata->eq_cfg[i].rate - fs) < best_val) {
+ best = i;
+ best_val = abs(pdata->eq_cfg[i].rate - fs);
+ }
+ }
+
+ dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+ pdata->eq_cfg[best].name,
+ pdata->eq_cfg[best].rate, fs);
+
+ /* Disable EQ while configuring, and save current on/off state */
+ save = snd_soc_read(codec, M98088_REG_49_CFG_LEVEL);
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, 0);
+
+ coef_set = &pdata->eq_cfg[sel];
+
+ m98088_eq_band(codec, 0, 0, coef_set->band1);
+ m98088_eq_band(codec, 0, 1, coef_set->band2);
+ m98088_eq_band(codec, 0, 2, coef_set->band3);
+ m98088_eq_band(codec, 0, 3, coef_set->band4);
+ m98088_eq_band(codec, 0, 4, coef_set->band5);
+
+ /* Restore the original on/off state */
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, save);
+}
+
+static void max98088_setup_eq2(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_eq_cfg *coef_set;
+ int best, best_val, save, i, sel, fs;
+ struct max98088_cdata *cdata;
+
+ cdata = &max98088->dai[1];
+
+ if (!pdata || !max98088->eq_textcnt)
+ return;
+
+ /* Find the selected configuration with nearest sample rate */
+ fs = cdata->rate;
+
+ sel = cdata->eq_sel;
+ best = 0;
+ best_val = INT_MAX;
+ for (i = 0; i < pdata->eq_cfgcnt; i++) {
+ if (strcmp(pdata->eq_cfg[i].name, max98088->eq_texts[sel]) == 0 &&
+ abs(pdata->eq_cfg[i].rate - fs) < best_val) {
+ best = i;
+ best_val = abs(pdata->eq_cfg[i].rate - fs);
+ }
+ }
+
+ dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+ pdata->eq_cfg[best].name,
+ pdata->eq_cfg[best].rate, fs);
+
+ /* Disable EQ while configuring, and save current on/off state */
+ save = snd_soc_read(codec, M98088_REG_49_CFG_LEVEL);
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN, 0);
+
+ coef_set = &pdata->eq_cfg[sel];
+
+ m98088_eq_band(codec, 1, 0, coef_set->band1);
+ m98088_eq_band(codec, 1, 1, coef_set->band2);
+ m98088_eq_band(codec, 1, 2, coef_set->band3);
+ m98088_eq_band(codec, 1, 3, coef_set->band4);
+ m98088_eq_band(codec, 1, 4, coef_set->band5);
+
+ /* Restore the original on/off state */
+ snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN,
+ save);
+}
+
+static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ int channel = max98088_get_channel(kcontrol->id.name);
+ struct max98088_cdata *cdata;
+ int sel = ucontrol->value.integer.value[0];
+
+ cdata = &max98088->dai[channel];
+
+ if (sel >= pdata->eq_cfgcnt)
+ return -EINVAL;
+
+ cdata->eq_sel = sel;
+
+ switch (channel) {
+ case 0:
+ max98088_setup_eq1(codec);
+ break;
+ case 1:
+ max98088_setup_eq2(codec);
+ break;
+ }
+
+ return 0;
+}
+
+static int max98088_get_eq_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ int channel = max98088_get_channel(kcontrol->id.name);
+ struct max98088_cdata *cdata;
+
+ cdata = &max98088->dai[channel];
+ ucontrol->value.enumerated.item[0] = cdata->eq_sel;
+ return 0;
+}
+
+static void max98088_handle_eq_pdata(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ struct max98088_eq_cfg *cfg;
+ unsigned int cfgcnt;
+ int i, j;
+ const char **t;
+ int ret;
+
+ struct snd_kcontrol_new controls[] = {
+ SOC_ENUM_EXT("EQ1 Mode",
+ max98088->eq_enum,
+ max98088_get_eq_enum,
+ max98088_put_eq_enum),
+ SOC_ENUM_EXT("EQ2 Mode",
+ max98088->eq_enum,
+ max98088_get_eq_enum,
+ max98088_put_eq_enum),
+ };
+
+ cfg = pdata->eq_cfg;
+ cfgcnt = pdata->eq_cfgcnt;
+
+ /* Setup an array of texts for the equalizer enum.
+ * This is based on Mark Brown's equalizer driver code.
+ */
+ max98088->eq_textcnt = 0;
+ max98088->eq_texts = NULL;
+ for (i = 0; i < cfgcnt; i++) {
+ for (j = 0; j < max98088->eq_textcnt; j++) {
+ if (strcmp(cfg[i].name, max98088->eq_texts[j]) == 0)
+ break;
+ }
+
+ if (j != max98088->eq_textcnt)
+ continue;
+
+ /* Expand the array */
+ t = krealloc(max98088->eq_texts,
+ sizeof(char *) * (max98088->eq_textcnt + 1),
+ GFP_KERNEL);
+ if (t == NULL)
+ continue;
+
+ /* Store the new entry */
+ t[max98088->eq_textcnt] = cfg[i].name;
+ max98088->eq_textcnt++;
+ max98088->eq_texts = t;
+ }
+
+ /* Now point the soc_enum to .texts array items */
+ max98088->eq_enum.texts = max98088->eq_texts;
+ max98088->eq_enum.max = max98088->eq_textcnt;
+
+ ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+ if (ret != 0)
+ dev_err(codec->dev, "Failed to add EQ control: %d\n", ret);
+}
+
+static void max98088_handle_pdata(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_pdata *pdata = max98088->pdata;
+ u8 regval = 0;
+
+ if (!pdata) {
+ dev_dbg(codec->dev, "No platform data\n");
+ return;
+ }
+
+ /* Configure mic for analog/digital mic mode */
+ if (pdata->digmic_left_mode)
+ regval |= M98088_DIGMIC_L;
+
+ if (pdata->digmic_right_mode)
+ regval |= M98088_DIGMIC_R;
+
+ max98088->digmic = (regval ? 1 : 0);
+
+ snd_soc_write(codec, M98088_REG_48_CFG_MIC, regval);
+
+ /* Configure receiver output */
+ regval = ((pdata->receiver_mode) ? M98088_REC_LINEMODE : 0);
+ snd_soc_update_bits(codec, M98088_REG_2A_MIC_REC_CNTL,
+ M98088_REC_LINEMODE_MASK, regval);
+
+ /* Configure equalizers */
+ if (pdata->eq_cfgcnt)
+ max98088_handle_eq_pdata(codec);
+}
+
+#ifdef CONFIG_PM
+static int max98088_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static int max98088_resume(struct snd_soc_codec *codec)
+{
+ max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+#else
+#define max98088_suspend NULL
+#define max98088_resume NULL
+#endif
+
+static int max98088_probe(struct snd_soc_codec *codec)
+{
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ struct max98088_cdata *cdata;
+ int ret = 0;
+
+ codec->cache_sync = 1;
+ memcpy(codec->reg_cache, max98088_reg, sizeof(max98088_reg));
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ /* initalize private data */
+
+ max98088->sysclk = (unsigned)-1;
+ max98088->eq_textcnt = 0;
+
+ cdata = &max98088->dai[0];
+ cdata->rate = (unsigned)-1;
+ cdata->fmt = (unsigned)-1;
+ cdata->eq_sel = 0;
+
+ cdata = &max98088->dai[1];
+ cdata->rate = (unsigned)-1;
+ cdata->fmt = (unsigned)-1;
+ cdata->eq_sel = 0;
+
+ max98088->ina_state = 0;
+ max98088->inb_state = 0;
+ max98088->ex_mode = 0;
+ max98088->digmic = 0;
+ max98088->mic1pre = 0;
+ max98088->mic2pre = 0;
+
+ ret = snd_soc_read(codec, M98088_REG_FF_REV_ID);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read device revision: %d\n",
+ ret);
+ goto err_access;
+ }
+ dev_info(codec->dev, "revision %c\n", ret + 'A');
+
+ snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV);
+
+ /* initialize registers cache to hardware default */
+ max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00);
+
+ snd_soc_write(codec, M98088_REG_22_MIX_DAC,
+ M98088_DAI1L_TO_DACL|M98088_DAI2L_TO_DACL|
+ M98088_DAI1R_TO_DACR|M98088_DAI2R_TO_DACR);
+
+ snd_soc_write(codec, M98088_REG_4E_BIAS_CNTL, 0xF0);
+ snd_soc_write(codec, M98088_REG_50_DAC_BIAS2, 0x0F);
+
+ snd_soc_write(codec, M98088_REG_16_DAI1_IOCFG,
+ M98088_S1NORMAL|M98088_SDATA);
+
+ snd_soc_write(codec, M98088_REG_1E_DAI2_IOCFG,
+ M98088_S2NORMAL|M98088_SDATA);
+
+ max98088_handle_pdata(codec);
+
+ max98088_add_widgets(codec);
+
+err_access:
+ return ret;
+}
+
+static int max98088_remove(struct snd_soc_codec *codec)
+{
+ max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
+ .probe = max98088_probe,
+ .remove = max98088_remove,
+ .suspend = max98088_suspend,
+ .resume = max98088_resume,
+ .set_bias_level = max98088_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(max98088_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = max98088_reg,
+ .volatile_register = max98088_volatile_register,
+};
+
+static int max98088_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct max98088_priv *max98088;
+ int ret;
+
+ max98088 = kzalloc(sizeof(struct max98088_priv), GFP_KERNEL);
+ if (max98088 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, max98088);
+ max98088->control_data = i2c;
+ max98088->pdata = i2c->dev.platform_data;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_max98088, &max98088_dai[0], 2);
+ if (ret < 0)
+ kfree(max98088);
+ return ret;
+}
+
+static int __devexit max98088_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id max98088_i2c_id[] = {
+ { "max98088", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max98088_i2c_id);
+
+static struct i2c_driver max98088_i2c_driver = {
+ .driver = {
+ .name = "max98088",
+ .owner = THIS_MODULE,
+ },
+ .probe = max98088_i2c_probe,
+ .remove = __devexit_p(max98088_i2c_remove),
+ .id_table = max98088_i2c_id,
+};
+
+static int __init max98088_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&max98088_i2c_driver);
+ if (ret)
+ pr_err("Failed to register max98088 I2C driver: %d\n", ret);
+
+ return ret;
+}
+module_init(max98088_init);
+
+static void __exit max98088_exit(void)
+{
+ i2c_del_driver(&max98088_i2c_driver);
+}
+module_exit(max98088_exit);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98088 driver");
+MODULE_AUTHOR("Peter Hsiang, Jesse Marroquin");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98088.h b/sound/soc/codecs/max98088.h
new file mode 100644
index 000000000000..56554c797fef
--- /dev/null
+++ b/sound/soc/codecs/max98088.h
@@ -0,0 +1,193 @@
+/*
+ * max98088.h -- MAX98088 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * 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 _MAX98088_H
+#define _MAX98088_H
+
+/*
+ * MAX98088 Registers Definition
+ */
+#define M98088_REG_00_IRQ_STATUS 0x00
+#define M98088_REG_01_MIC_STATUS 0x01
+#define M98088_REG_02_JACK_STAUS 0x02
+#define M98088_REG_03_BATTERY_VOLTAGE 0x03
+#define M98088_REG_0F_IRQ_ENABLE 0x0F
+#define M98088_REG_10_SYS_CLK 0x10
+#define M98088_REG_11_DAI1_CLKMODE 0x11
+#define M98088_REG_12_DAI1_CLKCFG_HI 0x12
+#define M98088_REG_13_DAI1_CLKCFG_LO 0x13
+#define M98088_REG_14_DAI1_FORMAT 0x14
+#define M98088_REG_15_DAI1_CLOCK 0x15
+#define M98088_REG_16_DAI1_IOCFG 0x16
+#define M98088_REG_17_DAI1_TDM 0x17
+#define M98088_REG_18_DAI1_FILTERS 0x18
+#define M98088_REG_19_DAI2_CLKMODE 0x19
+#define M98088_REG_1A_DAI2_CLKCFG_HI 0x1A
+#define M98088_REG_1B_DAI2_CLKCFG_LO 0x1B
+#define M98088_REG_1C_DAI2_FORMAT 0x1C
+#define M98088_REG_1D_DAI2_CLOCK 0x1D
+#define M98088_REG_1E_DAI2_IOCFG 0x1E
+#define M98088_REG_1F_DAI2_TDM 0x1F
+#define M98088_REG_20_DAI2_FILTERS 0x20
+#define M98088_REG_21_SRC 0x21
+#define M98088_REG_22_MIX_DAC 0x22
+#define M98088_REG_23_MIX_ADC_LEFT 0x23
+#define M98088_REG_24_MIX_ADC_RIGHT 0x24
+#define M98088_REG_25_MIX_HP_LEFT 0x25
+#define M98088_REG_26_MIX_HP_RIGHT 0x26
+#define M98088_REG_27_MIX_HP_CNTL 0x27
+#define M98088_REG_28_MIX_REC_LEFT 0x28
+#define M98088_REG_29_MIX_REC_RIGHT 0x29
+#define M98088_REG_2A_MIC_REC_CNTL 0x2A
+#define M98088_REG_2B_MIX_SPK_LEFT 0x2B
+#define M98088_REG_2C_MIX_SPK_RIGHT 0x2C
+#define M98088_REG_2D_MIX_SPK_CNTL 0x2D
+#define M98088_REG_2E_LVL_SIDETONE 0x2E
+#define M98088_REG_2F_LVL_DAI1_PLAY 0x2F
+#define M98088_REG_30_LVL_DAI1_PLAY_EQ 0x30
+#define M98088_REG_31_LVL_DAI2_PLAY 0x31
+#define M98088_REG_32_LVL_DAI2_PLAY_EQ 0x32
+#define M98088_REG_33_LVL_ADC_L 0x33
+#define M98088_REG_34_LVL_ADC_R 0x34
+#define M98088_REG_35_LVL_MIC1 0x35
+#define M98088_REG_36_LVL_MIC2 0x36
+#define M98088_REG_37_LVL_INA 0x37
+#define M98088_REG_38_LVL_INB 0x38
+#define M98088_REG_39_LVL_HP_L 0x39
+#define M98088_REG_3A_LVL_HP_R 0x3A
+#define M98088_REG_3B_LVL_REC_L 0x3B
+#define M98088_REG_3C_LVL_REC_R 0x3C
+#define M98088_REG_3D_LVL_SPK_L 0x3D
+#define M98088_REG_3E_LVL_SPK_R 0x3E
+#define M98088_REG_3F_MICAGC_CFG 0x3F
+#define M98088_REG_40_MICAGC_THRESH 0x40
+#define M98088_REG_41_SPKDHP 0x41
+#define M98088_REG_42_SPKDHP_THRESH 0x42
+#define M98088_REG_43_SPKALC_COMP 0x43
+#define M98088_REG_44_PWRLMT_CFG 0x44
+#define M98088_REG_45_PWRLMT_TIME 0x45
+#define M98088_REG_46_THDLMT_CFG 0x46
+#define M98088_REG_47_CFG_AUDIO_IN 0x47
+#define M98088_REG_48_CFG_MIC 0x48
+#define M98088_REG_49_CFG_LEVEL 0x49
+#define M98088_REG_4A_CFG_BYPASS 0x4A
+#define M98088_REG_4B_CFG_JACKDET 0x4B
+#define M98088_REG_4C_PWR_EN_IN 0x4C
+#define M98088_REG_4D_PWR_EN_OUT 0x4D
+#define M98088_REG_4E_BIAS_CNTL 0x4E
+#define M98088_REG_4F_DAC_BIAS1 0x4F
+#define M98088_REG_50_DAC_BIAS2 0x50
+#define M98088_REG_51_PWR_SYS 0x51
+#define M98088_REG_52_DAI1_EQ_BASE 0x52
+#define M98088_REG_84_DAI2_EQ_BASE 0x84
+#define M98088_REG_B6_DAI1_BIQUAD_BASE 0xB6
+#define M98088_REG_C0_DAI2_BIQUAD_BASE 0xC0
+#define M98088_REG_FF_REV_ID 0xFF
+
+#define M98088_REG_CNT (0xFF+1)
+
+/* MAX98088 Registers Bit Fields */
+
+/* M98088_REG_11_DAI1_CLKMODE, M98088_REG_19_DAI2_CLKMODE */
+ #define M98088_CLKMODE_MASK 0xFF
+
+/* M98088_REG_14_DAI1_FORMAT, M98088_REG_1C_DAI2_FORMAT */
+ #define M98088_DAI_MAS (1<<7)
+ #define M98088_DAI_WCI (1<<6)
+ #define M98088_DAI_BCI (1<<5)
+ #define M98088_DAI_DLY (1<<4)
+ #define M98088_DAI_TDM (1<<2)
+ #define M98088_DAI_FSW (1<<1)
+ #define M98088_DAI_WS (1<<0)
+
+/* M98088_REG_15_DAI1_CLOCK, M98088_REG_1D_DAI2_CLOCK */
+ #define M98088_DAI_BSEL64 (1<<0)
+ #define M98088_DAI_OSR64 (1<<6)
+
+/* M98088_REG_16_DAI1_IOCFG, M98088_REG_1E_DAI2_IOCFG */
+ #define M98088_S1NORMAL (1<<6)
+ #define M98088_S2NORMAL (2<<6)
+ #define M98088_SDATA (3<<0)
+
+/* M98088_REG_18_DAI1_FILTERS, M98088_REG_20_DAI2_FILTERS */
+ #define M98088_DAI_DHF (1<<3)
+
+/* M98088_REG_22_MIX_DAC */
+ #define M98088_DAI1L_TO_DACL (1<<7)
+ #define M98088_DAI1R_TO_DACL (1<<6)
+ #define M98088_DAI2L_TO_DACL (1<<5)
+ #define M98088_DAI2R_TO_DACL (1<<4)
+ #define M98088_DAI1L_TO_DACR (1<<3)
+ #define M98088_DAI1R_TO_DACR (1<<2)
+ #define M98088_DAI2L_TO_DACR (1<<1)
+ #define M98088_DAI2R_TO_DACR (1<<0)
+
+/* M98088_REG_2A_MIC_REC_CNTL */
+ #define M98088_REC_LINEMODE (1<<7)
+ #define M98088_REC_LINEMODE_MASK (1<<7)
+
+/* M98088_REG_35_LVL_MIC1, M98088_REG_36_LVL_MIC2 */
+ #define M98088_MICPRE_MASK (3<<5)
+ #define M98088_MICPRE_SHIFT 5
+
+/* M98088_REG_3A_LVL_HP_R */
+ #define M98088_HP_MUTE (1<<7)
+
+/* M98088_REG_3C_LVL_REC_R */
+ #define M98088_REC_MUTE (1<<7)
+
+/* M98088_REG_3E_LVL_SPK_R */
+ #define M98088_SP_MUTE (1<<7)
+
+/* M98088_REG_48_CFG_MIC */
+ #define M98088_EXTMIC_MASK (3<<0)
+ #define M98088_DIGMIC_L (1<<5)
+ #define M98088_DIGMIC_R (1<<4)
+
+/* M98088_REG_49_CFG_LEVEL */
+ #define M98088_VSEN (1<<6)
+ #define M98088_ZDEN (1<<5)
+ #define M98088_EQ2EN (1<<1)
+ #define M98088_EQ1EN (1<<0)
+
+/* M98088_REG_4C_PWR_EN_IN */
+ #define M98088_INAEN (1<<7)
+ #define M98088_INBEN (1<<6)
+ #define M98088_MBEN (1<<3)
+ #define M98088_ADLEN (1<<1)
+ #define M98088_ADREN (1<<0)
+
+/* M98088_REG_4D_PWR_EN_OUT */
+ #define M98088_HPLEN (1<<7)
+ #define M98088_HPREN (1<<6)
+ #define M98088_HPEN ((1<<7)|(1<<6))
+ #define M98088_SPLEN (1<<5)
+ #define M98088_SPREN (1<<4)
+ #define M98088_RECEN (1<<3)
+ #define M98088_DALEN (1<<1)
+ #define M98088_DAREN (1<<0)
+
+/* M98088_REG_51_PWR_SYS */
+ #define M98088_SHDNRUN (1<<7)
+ #define M98088_PERFMODE (1<<3)
+ #define M98088_HPPLYBACK (1<<2)
+ #define M98088_PWRSV8K (1<<1)
+ #define M98088_PWRSV (1<<0)
+
+/* Line inputs */
+#define LINE_INA 0
+#define LINE_INB 1
+
+#define M98088_COEFS_PER_BAND 5
+
+#define M98088_BYTE1(w) ((w >> 8) & 0xff)
+#define M98088_BYTE0(w) (w & 0xff)
+
+#endif
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c
index 5a5f187a2657..bd8f26e41602 100644
--- a/sound/soc/codecs/pcm3008.c
+++ b/sound/soc/codecs/pcm3008.c
@@ -32,8 +32,8 @@
#define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000)
-struct snd_soc_dai pcm3008_dai = {
- .name = "PCM3008 HiFi",
+static struct snd_soc_dai_driver pcm3008_dai = {
+ .name = "pcm3008-hifi",
.playback = {
.stream_name = "PCM3008 Playback",
.channels_min = 1,
@@ -49,7 +49,6 @@ struct snd_soc_dai pcm3008_dai = {
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
};
-EXPORT_SYMBOL_GPL(pcm3008_dai);
static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
{
@@ -59,38 +58,13 @@ static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
gpio_free(setup->pdda_pin);
}
-static int pcm3008_soc_probe(struct platform_device *pdev)
+static int pcm3008_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct pcm3008_setup_data *setup = socdev->codec_data;
+ struct pcm3008_setup_data *setup = codec->dev->platform_data;
int ret = 0;
printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION);
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (!socdev->card->codec)
- return -ENOMEM;
-
- codec = socdev->card->codec;
- mutex_init(&codec->mutex);
-
- codec->name = "PCM3008";
- codec->owner = THIS_MODULE;
- codec->dai = &pcm3008_dai;
- codec->num_dai = 1;
- codec->write = NULL;
- codec->read = NULL;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- /* Register PCMs. */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "pcm3008: failed to create pcms\n");
- goto pcm_err;
- }
-
/* DEM1 DEM0 DE-EMPHASIS_MODE
* Low Low De-emphasis 44.1 kHz ON
* Low High De-emphasis OFF
@@ -130,33 +104,22 @@ static int pcm3008_soc_probe(struct platform_device *pdev)
gpio_err:
pcm3008_gpio_free(setup);
-pcm_err:
- kfree(socdev->card->codec);
return ret;
}
-static int pcm3008_soc_remove(struct platform_device *pdev)
+static int pcm3008_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- struct pcm3008_setup_data *setup = socdev->codec_data;
-
- if (!codec)
- return 0;
+ struct pcm3008_setup_data *setup = codec->dev->platform_data;
pcm3008_gpio_free(setup);
- snd_soc_free_pcms(socdev);
- kfree(socdev->card->codec);
-
return 0;
}
#ifdef CONFIG_PM
-static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+static int pcm3008_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct pcm3008_setup_data *setup = socdev->codec_data;
+ struct pcm3008_setup_data *setup = codec->dev->platform_data;
gpio_set_value(setup->pdad_pin, 0);
gpio_set_value(setup->pdda_pin, 0);
@@ -164,10 +127,9 @@ static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg)
return 0;
}
-static int pcm3008_soc_resume(struct platform_device *pdev)
+static int pcm3008_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct pcm3008_setup_data *setup = socdev->codec_data;
+ struct pcm3008_setup_data *setup = codec->dev->platform_data;
gpio_set_value(setup->pdad_pin, 1);
gpio_set_value(setup->pdda_pin, 1);
@@ -179,23 +141,45 @@ static int pcm3008_soc_resume(struct platform_device *pdev)
#define pcm3008_soc_resume NULL
#endif
-struct snd_soc_codec_device soc_codec_dev_pcm3008 = {
+static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
.probe = pcm3008_soc_probe,
.remove = pcm3008_soc_remove,
.suspend = pcm3008_soc_suspend,
.resume = pcm3008_soc_resume,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008);
-static int __init pcm3008_init(void)
+static int __devinit pcm3008_codec_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_pcm3008, &pcm3008_dai, 1);
+}
+
+static int __devexit pcm3008_codec_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+MODULE_ALIAS("platform:pcm3008-codec");
+
+static struct platform_driver pcm3008_codec_driver = {
+ .probe = pcm3008_codec_probe,
+ .remove = __devexit_p(pcm3008_codec_remove),
+ .driver = {
+ .name = "pcm3008-codec",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pcm3008_modinit(void)
{
- return snd_soc_register_dai(&pcm3008_dai);
+ return platform_driver_register(&pcm3008_codec_driver);
}
-module_init(pcm3008_init);
+module_init(pcm3008_modinit);
static void __exit pcm3008_exit(void)
{
- snd_soc_unregister_dai(&pcm3008_dai);
+ platform_driver_unregister(&pcm3008_codec_driver);
}
module_exit(pcm3008_exit);
diff --git a/sound/soc/codecs/pcm3008.h b/sound/soc/codecs/pcm3008.h
index d04e87d3c060..7e5489ab4812 100644
--- a/sound/soc/codecs/pcm3008.h
+++ b/sound/soc/codecs/pcm3008.h
@@ -19,7 +19,4 @@ struct pcm3008_setup_data {
unsigned pdda_pin;
};
-extern struct snd_soc_codec_device soc_codec_dev_pcm3008;
-extern struct snd_soc_dai pcm3008_dai;
-
#endif
diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c
index 9119836051a4..4c32b54913ad 100644
--- a/sound/soc/codecs/spdif_transciever.c
+++ b/sound/soc/codecs/spdif_transciever.c
@@ -21,57 +21,16 @@
#include <sound/pcm.h>
#include <sound/initval.h>
-#include "spdif_transciever.h"
-
MODULE_LICENSE("GPL");
#define STUB_RATES SNDRV_PCM_RATE_8000_96000
#define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE
-static struct snd_soc_codec *spdif_dit_codec;
-
-static int spdif_dit_codec_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret;
-
- if (spdif_dit_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = spdif_dit_codec;
- codec = spdif_dit_codec;
-
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto err_create_pcms;
- }
-
- return 0;
-
-err_create_pcms:
- return ret;
-}
-
-static int spdif_dit_codec_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
-
- return 0;
-}
-struct snd_soc_codec_device soc_codec_dev_spdif_dit = {
- .probe = spdif_dit_codec_probe,
- .remove = spdif_dit_codec_remove,
-}; EXPORT_SYMBOL_GPL(soc_codec_dev_spdif_dit);
+static struct snd_soc_codec_driver soc_codec_spdif_dit;
-struct snd_soc_dai dit_stub_dai = {
- .name = "DIT",
+static struct snd_soc_dai_driver dit_stub_dai = {
+ .name = "dit-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -80,65 +39,16 @@ struct snd_soc_dai dit_stub_dai = {
.formats = STUB_FORMATS,
},
};
-EXPORT_SYMBOL_GPL(dit_stub_dai);
static int spdif_dit_probe(struct platform_device *pdev)
{
- struct snd_soc_codec *codec;
- int ret;
-
- if (spdif_dit_codec) {
- dev_err(&pdev->dev, "Another Codec is registered\n");
- ret = -EINVAL;
- goto err_reg_codec;
- }
-
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- codec->dev = &pdev->dev;
-
- mutex_init(&codec->mutex);
-
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "spdif-dit";
- codec->owner = THIS_MODULE;
- codec->dai = &dit_stub_dai;
- codec->num_dai = 1;
-
- spdif_dit_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_reg_codec;
- }
-
- dit_stub_dai.dev = &pdev->dev;
- ret = snd_soc_register_dai(&dit_stub_dai);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to register dai: %d\n", ret);
- goto err_reg_dai;
- }
-
- return 0;
-
-err_reg_dai:
- snd_soc_unregister_codec(codec);
-err_reg_codec:
- kfree(spdif_dit_codec);
- return ret;
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_spdif_dit,
+ &dit_stub_dai, 1);
}
static int spdif_dit_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&dit_stub_dai);
- snd_soc_unregister_codec(spdif_dit_codec);
- kfree(spdif_dit_codec);
- spdif_dit_codec = NULL;
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
diff --git a/sound/soc/codecs/spdif_transciever.h b/sound/soc/codecs/spdif_transciever.h
deleted file mode 100644
index 1e102124f546..000000000000
--- a/sound/soc/codecs/spdif_transciever.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * ALSA SoC DIT/DIR driver header
- *
- * Author: Steve Chen, <schen@mvista.com>
- * Copyright: (C) 2008 MontaVista Software, Inc., <source@mvista.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 CODEC_STUBS_H
-#define CODEC_STUBS_H
-
-extern struct snd_soc_codec_device soc_codec_dev_spdif_dit;
-extern struct snd_soc_dai dit_stub_dai;
-
-#endif /* CODEC_STUBS_H */
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index b47ed4f6ab20..6f38d619bf8a 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -45,11 +45,11 @@
#define SSM2602_VERSION "0.1"
-struct snd_soc_codec_device soc_codec_dev_ssm2602;
-
/* codec private data */
struct ssm2602_priv {
unsigned int sysclk;
+ enum snd_soc_control_type control_type;
+ void *control_data;
struct snd_pcm_substream *master_substream;
struct snd_pcm_substream *slave_substream;
};
@@ -276,8 +276,7 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
{
u16 srate;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *i2c = codec->control_data;
u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
@@ -321,8 +320,7 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *i2c = codec->control_data;
struct snd_pcm_runtime *master_runtime;
@@ -360,8 +358,7 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* set active */
ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
@@ -372,8 +369,7 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
/* deactivate */
@@ -518,8 +514,8 @@ static struct snd_soc_dai_ops ssm2602_dai_ops = {
.set_fmt = ssm2602_set_dai_fmt,
};
-struct snd_soc_dai ssm2602_dai = {
- .name = "SSM2602",
+static struct snd_soc_dai_driver ssm2602_dai = {
+ .name = "ssm2602-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -534,21 +530,15 @@ struct snd_soc_dai ssm2602_dai = {
.formats = SSM2602_FORMATS,},
.ops = &ssm2602_dai_ops,
};
-EXPORT_SYMBOL_GPL(ssm2602_dai);
-static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state)
+static int ssm2602_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int ssm2602_resume(struct platform_device *pdev)
+static int ssm2602_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -563,36 +553,17 @@ static int ssm2602_resume(struct platform_device *pdev)
return 0;
}
-/*
- * initialise the ssm2602 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int ssm2602_init(struct snd_soc_device *socdev)
+static int ssm2602_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
- int reg, ret = 0;
-
- codec->name = "SSM2602";
- codec->owner = THIS_MODULE;
- codec->read = ssm2602_read_reg_cache;
- codec->write = ssm2602_write;
- codec->set_bias_level = ssm2602_set_bias_level;
- codec->dai = &ssm2602_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = sizeof(ssm2602_reg);
- codec->reg_cache = kmemdup(ssm2602_reg, sizeof(ssm2602_reg),
- GFP_KERNEL);
- if (codec->reg_cache == NULL)
- return -ENOMEM;
+ struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0, reg;
+
+ pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
+
+ codec->control_data = ssm2602->control_data;
ssm2602_reset(codec);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- pr_err("ssm2602: failed to create pcms\n");
- goto pcm_err;
- }
/*power on device*/
ssm2602_write(codec, SSM2602_ACTIVE, 0);
/* set the update bits */
@@ -614,13 +585,27 @@ static int ssm2602_init(struct snd_soc_device *socdev)
ssm2602_add_widgets(codec);
return ret;
+}
-pcm_err:
- kfree(codec->reg_cache);
- return ret;
+/* remove everything here */
+static int ssm2602_remove(struct snd_soc_codec *codec)
+{
+ ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
-static struct snd_soc_device *ssm2602_socdev;
+static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
+ .probe = ssm2602_probe,
+ .remove = ssm2602_remove,
+ .suspend = ssm2602_suspend,
+ .resume = ssm2602_resume,
+ .read = ssm2602_read_reg_cache,
+ .write = ssm2602_write,
+ .set_bias_level = ssm2602_set_bias_level,
+ .reg_cache_size = sizeof(ssm2602_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = ssm2602_reg,
+};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
/*
@@ -632,24 +617,28 @@ static struct snd_soc_device *ssm2602_socdev;
static int ssm2602_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- struct snd_soc_device *socdev = ssm2602_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct ssm2602_priv *ssm2602;
int ret;
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
+ ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
+ if (ssm2602 == NULL)
+ return -ENOMEM;
- ret = ssm2602_init(socdev);
- if (ret < 0)
- pr_err("failed to initialise SSM2602\n");
+ i2c_set_clientdata(i2c, ssm2602);
+ ssm2602->control_data = i2c;
+ ssm2602->control_type = SND_SOC_I2C;
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
+ if (ret < 0)
+ kfree(ssm2602);
return ret;
}
static int ssm2602_i2c_remove(struct i2c_client *client)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -658,130 +647,39 @@ static const struct i2c_device_id ssm2602_i2c_id[] = {
{ }
};
MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
+
/* corgi i2c codec control layer */
static struct i2c_driver ssm2602_i2c_driver = {
.driver = {
- .name = "SSM2602 I2C Codec",
+ .name = "ssm2602-codec",
.owner = THIS_MODULE,
},
.probe = ssm2602_i2c_probe,
.remove = ssm2602_i2c_remove,
.id_table = ssm2602_i2c_id,
};
-
-static int ssm2602_add_i2c_device(struct platform_device *pdev,
- const struct ssm2602_setup_data *setup)
-{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- int ret;
-
- ret = i2c_add_driver(&ssm2602_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
- }
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "ssm2602", I2C_NAME_SIZE);
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
- }
- return 0;
-err_driver:
- i2c_del_driver(&ssm2602_i2c_driver);
- return -ENODEV;
-}
#endif
-static int ssm2602_probe(struct platform_device *pdev)
+
+static int __init ssm2602_modinit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct ssm2602_setup_data *setup;
- struct snd_soc_codec *codec;
- struct ssm2602_priv *ssm2602;
int ret = 0;
-
- pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
-
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
- if (ssm2602 == NULL) {
- kfree(codec);
- return -ENOMEM;
- }
-
- snd_soc_codec_set_drvdata(codec, ssm2602);
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- ssm2602_socdev = socdev;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- codec->hw_write = (hw_write_t)i2c_master_send;
- ret = ssm2602_add_i2c_device(pdev, setup);
+ ret = i2c_add_driver(&ssm2602_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register SSM2602 I2C driver: %d\n",
+ ret);
}
-#else
- /* other interfaces */
#endif
return ret;
}
+module_init(ssm2602_modinit);
-/* remove everything here */
-static int ssm2602_remove(struct platform_device *pdev)
+static void __exit ssm2602_exit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_unregister_device(codec->control_data);
i2c_del_driver(&ssm2602_i2c_driver);
#endif
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ssm2602 = {
- .probe = ssm2602_probe,
- .remove = ssm2602_remove,
- .suspend = ssm2602_suspend,
- .resume = ssm2602_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602);
-
-static int __init ssm2602_modinit(void)
-{
- return snd_soc_register_dai(&ssm2602_dai);
-}
-module_init(ssm2602_modinit);
-
-static void __exit ssm2602_exit(void)
-{
- snd_soc_unregister_dai(&ssm2602_dai);
}
module_exit(ssm2602_exit);
diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h
index f344e6d76e31..42a47d0f8e25 100644
--- a/sound/soc/codecs/ssm2602.h
+++ b/sound/soc/codecs/ssm2602.h
@@ -124,7 +124,4 @@ struct ssm2602_setup_data {
unsigned short i2c_address;
};
-extern struct snd_soc_dai ssm2602_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ssm2602;
-
#endif
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index ee86568545c2..00d67cc8e206 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -25,7 +25,6 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
-#include <sound/soc-of-simple.h>
#include "stac9766.h"
@@ -257,20 +256,15 @@ static int stac9766_reset(struct snd_soc_codec *codec, int try_warm)
return 0;
}
-static int stac9766_codec_suspend(struct platform_device *pdev,
+static int stac9766_codec_suspend(struct snd_soc_codec *codec,
pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
stac9766_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int stac9766_codec_resume(struct platform_device *pdev)
+static int stac9766_codec_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
u16 id, reset;
reset = 0;
@@ -300,10 +294,9 @@ static struct snd_soc_dai_ops stac9766_dai_ops_digital = {
.prepare = ac97_digital_prepare,
};
-struct snd_soc_dai stac9766_dai[] = {
+static struct snd_soc_dai_driver stac9766_dai[] = {
{
- .name = "stac9766 analog",
- .id = 0,
+ .name = "stac9766-hifi-analog",
.ac97_control = 1,
/* stream cababilities */
@@ -325,8 +318,7 @@ struct snd_soc_dai stac9766_dai[] = {
.ops = &stac9766_dai_ops_analog,
},
{
- .name = "stac9766 IEC958",
- .id = 1,
+ .name = "stac9766-hifi-IEC958",
.ac97_control = 1,
/* stream cababilities */
@@ -342,57 +334,24 @@ struct snd_soc_dai stac9766_dai[] = {
.ops = &stac9766_dai_ops_digital,
}
};
-EXPORT_SYMBOL_GPL(stac9766_dai);
-static int stac9766_codec_probe(struct platform_device *pdev)
+static int stac9766_codec_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
int ret = 0;
printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION);
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (socdev->card->codec == NULL)
- return -ENOMEM;
- codec = socdev->card->codec;
- mutex_init(&codec->mutex);
-
- codec->reg_cache = kmemdup(stac9766_reg, sizeof(stac9766_reg),
- GFP_KERNEL);
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto cache_err;
- }
- codec->reg_cache_size = sizeof(stac9766_reg);
- codec->reg_cache_step = 2;
-
- codec->name = "STAC9766";
- codec->owner = THIS_MODULE;
- codec->dai = stac9766_dai;
- codec->num_dai = ARRAY_SIZE(stac9766_dai);
- codec->write = stac9766_ac97_write;
- codec->read = stac9766_ac97_read;
- codec->set_bias_level = stac9766_set_bias_level;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
if (ret < 0)
goto codec_err;
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0)
- goto pcm_err;
-
/* do a cold reset for the controller and then try
* a warm reset followed by an optional cold reset for codec */
stac9766_reset(codec, 0);
ret = stac9766_reset(codec, 1);
if (ret < 0) {
printk(KERN_ERR "Failed to reset STAC9766: AC97 link error\n");
- goto reset_err;
+ goto codec_err;
}
stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -402,40 +361,63 @@ static int stac9766_codec_probe(struct platform_device *pdev)
return 0;
-reset_err:
- snd_soc_free_pcms(socdev);
-pcm_err:
- snd_soc_free_ac97_codec(codec);
codec_err:
- kfree(snd_soc_codec_get_drvdata(codec));
-cache_err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
+ snd_soc_free_ac97_codec(codec);
return ret;
}
-static int stac9766_codec_remove(struct platform_device *pdev)
+static int stac9766_codec_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec == NULL)
- return 0;
-
- snd_soc_free_pcms(socdev);
snd_soc_free_ac97_codec(codec);
- kfree(codec->reg_cache);
- kfree(codec);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_stac9766 = {
+static struct snd_soc_codec_driver soc_codec_dev_stac9766 = {
+ .write = stac9766_ac97_write,
+ .read = stac9766_ac97_read,
+ .set_bias_level = stac9766_set_bias_level,
.probe = stac9766_codec_probe,
.remove = stac9766_codec_remove,
.suspend = stac9766_codec_suspend,
.resume = stac9766_codec_resume,
+ .reg_cache_size = sizeof(stac9766_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_step = 2,
+};
+
+static __devinit int stac9766_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_stac9766, stac9766_dai, ARRAY_SIZE(stac9766_dai));
+}
+
+static int __devexit stac9766_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver stac9766_codec_driver = {
+ .driver = {
+ .name = "stac9766-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = stac9766_probe,
+ .remove = __devexit_p(stac9766_remove),
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_stac9766);
+
+static int __init stac9766_init(void)
+{
+ return platform_driver_register(&stac9766_codec_driver);
+}
+module_init(stac9766_init);
+
+static void __exit stac9766_exit(void)
+{
+ platform_driver_unregister(&stac9766_codec_driver);
+}
+module_exit(stac9766_exit);
MODULE_DESCRIPTION("ASoC stac9766 driver");
MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
diff --git a/sound/soc/codecs/stac9766.h b/sound/soc/codecs/stac9766.h
index 65642eb8393e..c726f907e2c0 100644
--- a/sound/soc/codecs/stac9766.h
+++ b/sound/soc/codecs/stac9766.h
@@ -14,8 +14,4 @@
#define STAC9766_DAI_AC97_ANALOG 0
#define STAC9766_DAI_AC97_DIGITAL 1
-extern struct snd_soc_dai stac9766_dai[];
-extern struct snd_soc_codec_device soc_codec_dev_stac9766;
-
-
#endif
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 0a4b0fef3355..e8652b1ae326 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -240,7 +240,8 @@ static const struct snd_soc_dapm_route intercon[] = {
/* AIC23 driver data */
struct aic23 {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
int mclk;
int requested_adc;
int requested_dac;
@@ -404,11 +405,10 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 iface_reg;
int ret;
- struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+ struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
u32 sample_rate_adc = aic23->requested_adc;
u32 sample_rate_dac = aic23->requested_dac;
u32 sample_rate = params_rate(params);
@@ -452,8 +452,7 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* set active */
tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001);
@@ -465,9 +464,8 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
- struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+ struct snd_soc_codec *codec = rtd->codec;
+ struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
/* deactivate */
if (!codec->active) {
@@ -546,8 +544,7 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
- struct snd_soc_codec *codec = codec_dai->codec;
- struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+ struct aic23 *aic23 = snd_soc_dai_get_drvdata(codec_dai);
aic23->mclk = freq;
return 0;
}
@@ -594,8 +591,8 @@ static struct snd_soc_dai_ops tlv320aic23_dai_ops = {
.set_sysclk = tlv320aic23_set_dai_sysclk,
};
-struct snd_soc_dai tlv320aic23_dai = {
- .name = "tlv320aic23",
+static struct snd_soc_dai_driver tlv320aic23_dai = {
+ .name = "tlv320aic23-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -610,23 +607,17 @@ struct snd_soc_dai tlv320aic23_dai = {
.formats = AIC23_FORMATS,},
.ops = &tlv320aic23_dai_ops,
};
-EXPORT_SYMBOL_GPL(tlv320aic23_dai);
-static int tlv320aic23_suspend(struct platform_device *pdev,
+static int tlv320aic23_suspend(struct snd_soc_codec *codec,
pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int tlv320aic23_resume(struct platform_device *pdev)
+static int tlv320aic23_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
u16 reg;
/* Sync reg_cache with the hardware */
@@ -639,39 +630,19 @@ static int tlv320aic23_resume(struct platform_device *pdev)
return 0;
}
-/*
- * initialise the AIC23 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int tlv320aic23_init(struct snd_soc_device *socdev)
+static int tlv320aic23_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
- int ret = 0;
- u16 reg;
+ struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
+ int reg;
- codec->name = "tlv320aic23";
- codec->owner = THIS_MODULE;
- codec->read = tlv320aic23_read_reg_cache;
- codec->write = tlv320aic23_write;
- codec->set_bias_level = tlv320aic23_set_bias_level;
- codec->dai = &tlv320aic23_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(tlv320aic23_reg);
- codec->reg_cache =
- kmemdup(tlv320aic23_reg, sizeof(tlv320aic23_reg), GFP_KERNEL);
- if (codec->reg_cache == NULL)
- return -ENOMEM;
+ printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
+ codec->control_data = aic23->control_data;
+ codec->hw_write = (hw_write_t)i2c_master_send;
+ codec->hw_read = NULL;
/* Reset codec */
tlv320aic23_write(codec, TLV320AIC23_RESET, 0);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "tlv320aic23: failed to create pcms\n");
- goto pcm_err;
- }
-
/* power on device */
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -707,13 +678,27 @@ static int tlv320aic23_init(struct snd_soc_device *socdev)
ARRAY_SIZE(tlv320aic23_snd_controls));
tlv320aic23_add_widgets(codec);
- return ret;
+ return 0;
+}
-pcm_err:
- kfree(codec->reg_cache);
- return ret;
+static int tlv320aic23_remove(struct snd_soc_codec *codec)
+{
+ tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
-static struct snd_soc_device *tlv320aic23_socdev;
+
+static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
+ .reg_cache_size = ARRAY_SIZE(tlv320aic23_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = tlv320aic23_reg,
+ .probe = tlv320aic23_probe,
+ .remove = tlv320aic23_remove,
+ .suspend = tlv320aic23_suspend,
+ .resume = tlv320aic23_resume,
+ .read = tlv320aic23_read_reg_cache,
+ .write = tlv320aic23_write,
+ .set_bias_level = tlv320aic23_set_bias_level,
+};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
/*
@@ -723,31 +708,30 @@ static struct snd_soc_device *tlv320aic23_socdev;
static int tlv320aic23_codec_probe(struct i2c_client *i2c,
const struct i2c_device_id *i2c_id)
{
- struct snd_soc_device *socdev = tlv320aic23_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct aic23 *aic23;
int ret;
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EINVAL;
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
+ aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL);
+ if (aic23 == NULL)
+ return -ENOMEM;
- ret = tlv320aic23_init(socdev);
- if (ret < 0) {
- printk(KERN_ERR "tlv320aic23: failed to initialise AIC23\n");
- goto err;
- }
- return ret;
+ i2c_set_clientdata(i2c, aic23);
+ aic23->control_data = i2c;
+ aic23->control_type = SND_SOC_I2C;
-err:
- kfree(codec);
- kfree(i2c);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1);
+ if (ret < 0)
+ kfree(aic23);
return ret;
}
static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
{
- put_device(&i2c->dev);
+ snd_soc_unregister_codec(&i2c->dev);
+ kfree(i2c_get_clientdata(i2c));
return 0;
}
@@ -760,7 +744,7 @@ MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
static struct i2c_driver tlv320aic23_i2c_driver = {
.driver = {
- .name = "tlv320aic23",
+ .name = "tlv320aic23-codec",
},
.probe = tlv320aic23_codec_probe,
.remove = __exit_p(tlv320aic23_i2c_remove),
@@ -769,71 +753,25 @@ static struct i2c_driver tlv320aic23_i2c_driver = {
#endif
-static int tlv320aic23_probe(struct platform_device *pdev)
+static int __init tlv320aic23_modinit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct aic23 *aic23;
- int ret = 0;
-
- printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
-
- aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL);
- if (aic23 == NULL)
- return -ENOMEM;
- codec = &aic23->codec;
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- tlv320aic23_socdev = socdev;
+ int ret;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- codec->hw_write = (hw_write_t) i2c_master_send;
- codec->hw_read = NULL;
ret = i2c_add_driver(&tlv320aic23_i2c_driver);
- if (ret != 0)
- printk(KERN_ERR "can't add i2c driver");
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register TLV320AIC23 I2C driver: %d\n",
+ ret);
+ }
#endif
return ret;
}
+module_init(tlv320aic23_modinit);
-static int tlv320aic23_remove(struct platform_device *pdev)
+static void __exit tlv320aic23_exit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- struct aic23 *aic23 = container_of(codec, struct aic23, codec);
-
- if (codec->control_data)
- tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&tlv320aic23_i2c_driver);
#endif
- kfree(codec->reg_cache);
- kfree(aic23);
-
- return 0;
-}
-struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = {
- .probe = tlv320aic23_probe,
- .remove = tlv320aic23_remove,
- .suspend = tlv320aic23_suspend,
- .resume = tlv320aic23_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23);
-
-static int __init tlv320aic23_modinit(void)
-{
- return snd_soc_register_dai(&tlv320aic23_dai);
-}
-module_init(tlv320aic23_modinit);
-
-static void __exit tlv320aic23_exit(void)
-{
- snd_soc_unregister_dai(&tlv320aic23_dai);
}
module_exit(tlv320aic23_exit);
diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h
index 79d1faf8e570..e804120bd3da 100644
--- a/sound/soc/codecs/tlv320aic23.h
+++ b/sound/soc/codecs/tlv320aic23.h
@@ -116,7 +116,4 @@
#define TLV320AIC23_SIDETONE_12 0x080
#define TLV320AIC23_SIDETONE_18 0x0c0
-extern struct snd_soc_dai tlv320aic23_dai;
-extern struct snd_soc_codec_device soc_codec_dev_tlv320aic23;
-
#endif /* _TLV320AIC23_H */
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index f0e00fd4b435..6b7d71ec0004 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -19,7 +19,6 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include <sound/soc-of-simple.h>
#include <sound/initval.h>
#include "tlv320aic26.h"
@@ -130,8 +129,7 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
int fsref, divisor, wlen, pval, jval, dval, qval;
u16 reg;
@@ -278,8 +276,8 @@ static struct snd_soc_dai_ops aic26_dai_ops = {
.set_fmt = aic26_set_fmt,
};
-struct snd_soc_dai aic26_dai = {
- .name = "tlv320aic26",
+static struct snd_soc_dai_driver aic26_dai = {
+ .name = "tlv320aic26-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -296,7 +294,6 @@ struct snd_soc_dai aic26_dai = {
},
.ops = &aic26_dai_ops,
};
-EXPORT_SYMBOL_GPL(aic26_dai);
/* ---------------------------------------------------------------------
* ALSA controls
@@ -319,61 +316,6 @@ static const struct snd_kcontrol_new aic26_snd_controls[] = {
};
/* ---------------------------------------------------------------------
- * SoC CODEC portion of driver: probe and release routines
- */
-static int aic26_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct aic26 *aic26;
- int ret, err;
-
- dev_info(&pdev->dev, "Probing AIC26 SoC CODEC driver\n");
- dev_dbg(&pdev->dev, "socdev=%p\n", socdev);
- dev_dbg(&pdev->dev, "codec_data=%p\n", socdev->codec_data);
-
- /* Fetch the relevant aic26 private data here (it's already been
- * stored in the .codec pointer) */
- aic26 = socdev->codec_data;
- if (aic26 == NULL) {
- dev_err(&pdev->dev, "aic26: missing codec pointer\n");
- return -ENODEV;
- }
- codec = &aic26->codec;
- socdev->card->codec = codec;
-
- dev_dbg(&pdev->dev, "Registering PCMs, dev=%p, socdev->dev=%p\n",
- &pdev->dev, socdev->dev);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "aic26: failed to create pcms\n");
- return -ENODEV;
- }
-
- /* register controls */
- dev_dbg(&pdev->dev, "Registering controls\n");
- err = snd_soc_add_controls(codec, aic26_snd_controls,
- ARRAY_SIZE(aic26_snd_controls));
- WARN_ON(err < 0);
-
- return 0;
-}
-
-static int aic26_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- snd_soc_free_pcms(socdev);
- return 0;
-}
-
-struct snd_soc_codec_device aic26_soc_codec_dev = {
- .probe = aic26_probe,
- .remove = aic26_remove,
-};
-EXPORT_SYMBOL_GPL(aic26_soc_codec_dev);
-
-/* ---------------------------------------------------------------------
* SPI device portion of driver: sysfs files for debugging
*/
@@ -409,95 +351,95 @@ static ssize_t aic26_keyclick_set(struct device *dev,
static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
/* ---------------------------------------------------------------------
- * SPI device portion of driver: probe and release routines and SPI
- * driver registration.
+ * SoC CODEC portion of driver: probe and release routines
*/
-static int aic26_spi_probe(struct spi_device *spi)
+static int aic26_probe(struct snd_soc_codec *codec)
{
- struct aic26 *aic26;
- int ret, i, reg;
-
- dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n");
-
- /* Allocate driver data */
- aic26 = kzalloc(sizeof *aic26, GFP_KERNEL);
- if (!aic26)
- return -ENOMEM;
-
- /* Initialize the driver data */
- aic26->spi = spi;
- dev_set_drvdata(&spi->dev, aic26);
+ struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
+ int ret, err, i, reg;
- /* Setup what we can in the codec structure so that the register
- * access functions will work as expected. More will be filled
- * out when it is probed by the SoC CODEC part of this driver */
- snd_soc_codec_set_drvdata(&aic26->codec, aic26);
- aic26->codec.name = "aic26";
- aic26->codec.owner = THIS_MODULE;
- aic26->codec.dai = &aic26_dai;
- aic26->codec.num_dai = 1;
- aic26->codec.read = aic26_reg_read;
- aic26->codec.write = aic26_reg_write;
- aic26->master = 1;
- mutex_init(&aic26->codec.mutex);
- INIT_LIST_HEAD(&aic26->codec.dapm_widgets);
- INIT_LIST_HEAD(&aic26->codec.dapm_paths);
- aic26->codec.reg_cache_size = AIC26_NUM_REGS;
- aic26->codec.reg_cache = aic26->reg_cache;
-
- aic26_dai.dev = &spi->dev;
- ret = snd_soc_register_dai(&aic26_dai);
- if (ret != 0) {
- dev_err(&spi->dev, "Failed to register DAI: %d\n", ret);
- kfree(aic26);
- return ret;
- }
+ dev_info(codec->dev, "Probing AIC26 SoC CODEC driver\n");
/* Reset the codec to power on defaults */
- aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00);
+ aic26_reg_write(codec, AIC26_REG_RESET, 0xBB00);
/* Power up CODEC */
- aic26_reg_write(&aic26->codec, AIC26_REG_POWER_CTRL, 0);
+ aic26_reg_write(codec, AIC26_REG_POWER_CTRL, 0);
/* Audio Control 3 (master mode, fsref rate) */
- reg = aic26_reg_read(&aic26->codec, AIC26_REG_AUDIO_CTRL3);
+ reg = aic26_reg_read(codec, AIC26_REG_AUDIO_CTRL3);
reg &= ~0xf800;
reg |= 0x0800; /* set master mode */
- aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL3, reg);
+ aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
/* Fill register cache */
for (i = 0; i < ARRAY_SIZE(aic26->reg_cache); i++)
- aic26_reg_read(&aic26->codec, i);
+ aic26_reg_read(codec, i);
/* Register the sysfs files for debugging */
/* Create SysFS files */
- ret = device_create_file(&spi->dev, &dev_attr_keyclick);
+ ret = device_create_file(codec->dev, &dev_attr_keyclick);
if (ret)
- dev_info(&spi->dev, "error creating sysfs files\n");
+ dev_info(codec->dev, "error creating sysfs files\n");
-#if defined(CONFIG_SND_SOC_OF_SIMPLE)
- /* Tell the of_soc helper about this codec */
- of_snd_soc_register_codec(&aic26_soc_codec_dev, aic26, &aic26_dai,
- spi->dev.archdata.of_node);
-#endif
+ /* register controls */
+ dev_dbg(codec->dev, "Registering controls\n");
+ err = snd_soc_add_controls(codec, aic26_snd_controls,
+ ARRAY_SIZE(aic26_snd_controls));
+ WARN_ON(err < 0);
- dev_dbg(&spi->dev, "SPI device initialized\n");
return 0;
}
-static int aic26_spi_remove(struct spi_device *spi)
+static struct snd_soc_codec_driver aic26_soc_codec_dev = {
+ .probe = aic26_probe,
+ .read = aic26_reg_read,
+ .write = aic26_reg_write,
+ .reg_cache_size = AIC26_NUM_REGS,
+ .reg_word_size = sizeof(u16),
+};
+
+/* ---------------------------------------------------------------------
+ * SPI device portion of driver: probe and release routines and SPI
+ * driver registration.
+ */
+static int aic26_spi_probe(struct spi_device *spi)
{
- struct aic26 *aic26 = dev_get_drvdata(&spi->dev);
+ struct aic26 *aic26;
+ int ret;
- snd_soc_unregister_dai(&aic26_dai);
- kfree(aic26);
+ dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n");
+
+ /* Allocate driver data */
+ aic26 = kzalloc(sizeof *aic26, GFP_KERNEL);
+ if (!aic26)
+ return -ENOMEM;
+ /* Initialize the driver data */
+ aic26->spi = spi;
+ dev_set_drvdata(&spi->dev, aic26);
+ aic26->master = 1;
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &aic26_soc_codec_dev, &aic26_dai, 1);
+ if (ret < 0)
+ kfree(aic26);
+ return ret;
+
+ dev_dbg(&spi->dev, "SPI device initialized\n");
+ return 0;
+}
+
+static int aic26_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
return 0;
}
static struct spi_driver aic26_spi = {
.driver = {
- .name = "tlv320aic26",
+ .name = "tlv320aic26-codec",
.owner = THIS_MODULE,
},
.probe = aic26_spi_probe,
diff --git a/sound/soc/codecs/tlv320aic26.h b/sound/soc/codecs/tlv320aic26.h
index 786ba16c945f..62b1f2261429 100644
--- a/sound/soc/codecs/tlv320aic26.h
+++ b/sound/soc/codecs/tlv320aic26.h
@@ -90,7 +90,4 @@ enum aic26_wlen {
AIC26_WLEN_32 = 3 << 10,
};
-extern struct snd_soc_dai aic26_dai;
-extern struct snd_soc_codec_device aic26_soc_codec_dev;
-
#endif /* _TLV320AIC16_H_ */
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 71a69908ccf6..fc687790188b 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -12,11 +12,11 @@
*
* Notes:
* The AIC3X is a driver for a low power stereo audio
- * codecs aic31, aic32, aic33.
+ * codecs aic31, aic32, aic33, aic3007.
*
* It supports full aic33 codec functionality.
- * The compatibility with aic32, aic31 is as follows:
- * aic32 | aic31
+ * The compatibility with aic32, aic31 and aic3007 is as follows:
+ * aic32/aic3007 | aic31
* ---------------------------------------
* MONO_LOUT -> N/A | MONO_LOUT -> N/A
* | IN1L -> LINE1L
@@ -61,13 +61,29 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
"DRVDD", /* ADC Analog and Output Driver Voltage */
};
+struct aic3x_priv;
+
+struct aic3x_disable_nb {
+ struct notifier_block nb;
+ struct aic3x_priv *aic3x;
+};
+
/* codec private data */
struct aic3x_priv {
- struct snd_soc_codec codec;
+ struct snd_soc_codec *codec;
struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
+ struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES];
+ enum snd_soc_control_type control_type;
+ struct aic3x_setup_data *setup;
+ void *control_data;
unsigned int sysclk;
int master;
int gpio_reset;
+ int power;
+#define AIC3X_MODEL_3X 0
+#define AIC3X_MODEL_33 1
+#define AIC3X_MODEL_3007 2
+ u16 model;
};
/*
@@ -106,62 +122,23 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
};
/*
- * read aic3x register cache
+ * read from the aic3x register space. Only use for this function is if
+ * wanting to read volatile bits from those registers that has both read-only
+ * and read/write bits. All other cases should use snd_soc_read.
*/
-static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg)
+static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
+ u8 *value)
{
u8 *cache = codec->reg_cache;
- if (reg >= AIC3X_CACHEREGNUM)
- return -1;
- return cache[reg];
-}
-/*
- * write aic3x register cache
- */
-static inline void aic3x_write_reg_cache(struct snd_soc_codec *codec,
- u8 reg, u8 value)
-{
- u8 *cache = codec->reg_cache;
+ if (codec->cache_only)
+ return -EINVAL;
if (reg >= AIC3X_CACHEREGNUM)
- return;
- cache[reg] = value;
-}
-
-/*
- * write to the aic3x register space
- */
-static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
- u8 data[2];
-
- /* data is
- * D15..D8 aic3x register offset
- * D7...D0 register data
- */
- data[0] = reg & 0xff;
- data[1] = value & 0xff;
-
- aic3x_write_reg_cache(codec, data[0], data[1]);
- if (codec->hw_write(codec->control_data, data, 2) == 2)
- return 0;
- else
- return -EIO;
-}
-
-/*
- * read from the aic3x register space
- */
-static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
- u8 *value)
-{
- *value = reg & 0xff;
+ return -1;
- value[0] = i2c_smbus_read_byte_data(codec->control_data, value[0]);
+ *value = codec->hw_read(codec, reg);
+ cache[reg] = *value;
- aic3x_write_reg_cache(codec, reg, *value);
return 0;
}
@@ -286,64 +263,102 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
SOC_DOUBLE_R_TLV("PCM Playback Volume",
LDAC_VOL, RDAC_VOL, 0, 0x7f, 1, dac_tlv),
+ /*
+ * Output controls that map to output mixer switches. Note these are
+ * only for swapped L-to-R and R-to-L routes. See below stereo controls
+ * for direct L-to-L and R-to-R routes.
+ */
+ SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume",
+ LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Left Line Mixer PGAR Bypass Volume",
+ PGAR_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Left Line Mixer DACR1 Playback Volume",
+ DACR1_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+ SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume",
+ LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Right Line Mixer PGAL Bypass Volume",
+ PGAL_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Right Line Mixer DACL1 Playback Volume",
+ DACL1_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+ SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume",
+ LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Left HP Mixer PGAR Bypass Volume",
+ PGAR_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Left HP Mixer DACR1 Playback Volume",
+ DACR1_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+
+ SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume",
+ LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Right HP Mixer PGAL Bypass Volume",
+ PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Right HP Mixer DACL1 Playback Volume",
+ DACL1_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+
+ SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume",
+ LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Left HPCOM Mixer PGAR Bypass Volume",
+ PGAR_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Left HPCOM Mixer DACR1 Playback Volume",
+ DACR1_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+ SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume",
+ LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Right HPCOM Mixer PGAL Bypass Volume",
+ PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("Right HPCOM Mixer DACL1 Playback Volume",
+ DACL1_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+ /* Stereo output controls for direct L-to-L and R-to-R routes */
+ SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume",
+ LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
+ SOC_DOUBLE_R_TLV("Line PGA Bypass Volume",
+ PGAL_2_LLOPM_VOL, PGAR_2_RLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
SOC_DOUBLE_R_TLV("Line DAC Playback Volume",
DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,
0, 118, 1, output_stage_tlv),
- SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0),
- SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0),
- SOC_DOUBLE_R_TLV("LineL DAC Playback Volume",
- DACL1_2_LLOPM_VOL, DACR1_2_LLOPM_VOL,
- 0, 118, 1, output_stage_tlv),
- SOC_SINGLE_TLV("LineL Left PGA Bypass Playback Volume",
- PGAL_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
- SOC_SINGLE_TLV("LineR Right PGA Bypass Playback Volume",
- PGAR_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R_TLV("LineL Line2 Bypass Playback Volume",
- LINE2L_2_LLOPM_VOL, LINE2R_2_LLOPM_VOL,
+
+ SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume",
+ LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R_TLV("LineR Line2 Bypass Playback Volume",
- LINE2L_2_RLOPM_VOL, LINE2R_2_RLOPM_VOL,
+ SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume",
+ PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
0, 118, 1, output_stage_tlv),
-
SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
0, 118, 1, output_stage_tlv),
- SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
- SOC_DOUBLE_R_TLV("Mono PGA Bypass Playback Volume",
- PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
+
+ SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",
+ LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R_TLV("Mono Line2 Bypass Playback Volume",
- LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
+ SOC_DOUBLE_R_TLV("HP PGA Bypass Volume",
+ PGAL_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
0, 118, 1, output_stage_tlv),
-
SOC_DOUBLE_R_TLV("HP DAC Playback Volume",
DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL,
0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
- 0x01, 0),
- SOC_DOUBLE_R_TLV("HP Right PGA Bypass Playback Volume",
- PGAR_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
+
+ SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume",
+ LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
0, 118, 1, output_stage_tlv),
- SOC_SINGLE_TLV("HPL PGA Bypass Playback Volume",
- PGAL_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
- SOC_SINGLE_TLV("HPR PGA Bypass Playback Volume",
- PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R_TLV("HP Line2 Bypass Playback Volume",
- LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
+ SOC_DOUBLE_R_TLV("HPCOM PGA Bypass Volume",
+ PGAL_2_HPLCOM_VOL, PGAR_2_HPRCOM_VOL,
0, 118, 1, output_stage_tlv),
-
SOC_DOUBLE_R_TLV("HPCOM DAC Playback Volume",
DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL,
0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
+
+ /* Output pin mute controls */
+ SOC_DOUBLE_R("Line Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3,
+ 0x01, 0),
+ SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
+ SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
+ 0x01, 0),
+ SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
0x01, 0),
- SOC_SINGLE_TLV("HPLCOM PGA Bypass Playback Volume",
- PGAL_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
- SOC_SINGLE_TLV("HPRCOM PGA Bypass Playback Volume",
- PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Playback Volume",
- LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
- 0, 118, 1, output_stage_tlv),
/*
* Note: enable Automatic input Gain Controller with care. It can
@@ -359,6 +374,14 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
};
+/*
+ * Class-D amplifier gain. From 0 to 18 dB in 6 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl =
+ SOC_DOUBLE_TLV("Class-D Amplifier Gain", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv);
+
/* Left DAC Mux */
static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]);
@@ -375,22 +398,74 @@ SOC_DAPM_ENUM("Route", aic3x_enum[LHPCOM_ENUM]);
static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls =
SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]);
-/* Left DAC_L1 Mixer */
-static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = {
- SOC_DAPM_SINGLE("LineL Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("LineR Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
+/* Left Line Mixer */
+static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
+};
+
+/* Right Line Mixer */
+static const struct snd_kcontrol_new aic3x_right_line_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new aic3x_mono_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0),
+};
+
+/* Left HP Mixer */
+static const struct snd_kcontrol_new aic3x_left_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLOUT_VOL, 7, 1, 0),
+};
+
+/* Right HP Mixer */
+static const struct snd_kcontrol_new aic3x_right_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPROUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
+};
+
+/* Left HPCOM Mixer */
+static const struct snd_kcontrol_new aic3x_left_hpcom_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLCOM_VOL, 7, 1, 0),
};
-/* Right DAC_R1 Mixer */
-static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = {
- SOC_DAPM_SINGLE("LineL Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("LineR Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
+/* Right HPCOM Mixer */
+static const struct snd_kcontrol_new aic3x_right_hpcom_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPRCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
};
/* Left PGA Mixer */
@@ -427,54 +502,11 @@ SOC_DAPM_ENUM("Route", aic3x_enum[LINE2L_ENUM]);
static const struct snd_kcontrol_new aic3x_right_line2_mux_controls =
SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]);
-/* Left PGA Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = {
- SOC_DAPM_SINGLE("LineL Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("LineR Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPL Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPR Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPLCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPRCOM Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
-};
-
-/* Right PGA Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = {
- SOC_DAPM_SINGLE("LineL Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("LineR Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPL Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPR Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPLCOM Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPRCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
-};
-
-/* Left Line2 Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = {
- SOC_DAPM_SINGLE("LineL Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("LineR Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPLCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
-};
-
-/* Right Line2 Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = {
- SOC_DAPM_SINGLE("LineL Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("LineR Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
- SOC_DAPM_SINGLE("HPRCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
-};
-
static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
/* Left DAC to Left Outputs */
SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_PWR, 7, 0),
SND_SOC_DAPM_MUX("Left DAC Mux", SND_SOC_NOPM, 0, 0,
&aic3x_left_dac_mux_controls),
- SND_SOC_DAPM_MIXER("Left DAC_L1 Mixer", SND_SOC_NOPM, 0, 0,
- &aic3x_left_dac_mixer_controls[0],
- ARRAY_SIZE(aic3x_left_dac_mixer_controls)),
SND_SOC_DAPM_MUX("Left HPCOM Mux", SND_SOC_NOPM, 0, 0,
&aic3x_left_hpcom_mux_controls),
SND_SOC_DAPM_PGA("Left Line Out", LLOPM_CTRL, 0, 0, NULL, 0),
@@ -485,9 +517,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_PWR, 6, 0),
SND_SOC_DAPM_MUX("Right DAC Mux", SND_SOC_NOPM, 0, 0,
&aic3x_right_dac_mux_controls),
- SND_SOC_DAPM_MIXER("Right DAC_R1 Mixer", SND_SOC_NOPM, 0, 0,
- &aic3x_right_dac_mixer_controls[0],
- ARRAY_SIZE(aic3x_right_dac_mixer_controls)),
SND_SOC_DAPM_MUX("Right HPCOM Mux", SND_SOC_NOPM, 0, 0,
&aic3x_right_hpcom_mux_controls),
SND_SOC_DAPM_PGA("Right Line Out", RLOPM_CTRL, 0, 0, NULL, 0),
@@ -551,25 +580,28 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD",
MICBIAS_CTRL, 6, 3, 3, 0),
- /* Left PGA to Left Output bypass */
- SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0,
- &aic3x_left_pga_bp_mixer_controls[0],
- ARRAY_SIZE(aic3x_left_pga_bp_mixer_controls)),
-
- /* Right PGA to Right Output bypass */
- SND_SOC_DAPM_MIXER("Right PGA Bypass Mixer", SND_SOC_NOPM, 0, 0,
- &aic3x_right_pga_bp_mixer_controls[0],
- ARRAY_SIZE(aic3x_right_pga_bp_mixer_controls)),
-
- /* Left Line2 to Left Output bypass */
- SND_SOC_DAPM_MIXER("Left Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0,
- &aic3x_left_line2_bp_mixer_controls[0],
- ARRAY_SIZE(aic3x_left_line2_bp_mixer_controls)),
-
- /* Right Line2 to Right Output bypass */
- SND_SOC_DAPM_MIXER("Right Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0,
- &aic3x_right_line2_bp_mixer_controls[0],
- ARRAY_SIZE(aic3x_right_line2_bp_mixer_controls)),
+ /* Output mixers */
+ SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
+ &aic3x_left_line_mixer_controls[0],
+ ARRAY_SIZE(aic3x_left_line_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0,
+ &aic3x_right_line_mixer_controls[0],
+ ARRAY_SIZE(aic3x_right_line_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0,
+ &aic3x_mono_mixer_controls[0],
+ ARRAY_SIZE(aic3x_mono_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+ &aic3x_left_hp_mixer_controls[0],
+ ARRAY_SIZE(aic3x_left_hp_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+ &aic3x_right_hp_mixer_controls[0],
+ ARRAY_SIZE(aic3x_right_hp_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Left HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+ &aic3x_left_hpcom_mixer_controls[0],
+ ARRAY_SIZE(aic3x_left_hpcom_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Right HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+ &aic3x_right_hpcom_mixer_controls[0],
+ ARRAY_SIZE(aic3x_right_hpcom_mixer_controls)),
SND_SOC_DAPM_OUTPUT("LLOUT"),
SND_SOC_DAPM_OUTPUT("RLOUT"),
@@ -585,69 +617,26 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("LINE1R"),
SND_SOC_DAPM_INPUT("LINE2L"),
SND_SOC_DAPM_INPUT("LINE2R"),
-};
-
-static const struct snd_soc_dapm_route intercon[] = {
- /* Left Output */
- {"Left DAC Mux", "DAC_L1", "Left DAC"},
- {"Left DAC Mux", "DAC_L2", "Left DAC"},
- {"Left DAC Mux", "DAC_L3", "Left DAC"},
-
- {"Left DAC_L1 Mixer", "LineL Switch", "Left DAC Mux"},
- {"Left DAC_L1 Mixer", "LineR Switch", "Left DAC Mux"},
- {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"},
- {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"},
- {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"},
- {"Left Line Out", NULL, "Left DAC Mux"},
- {"Left HP Out", NULL, "Left DAC Mux"},
-
- {"Left HPCOM Mux", "differential of HPLOUT", "Left DAC_L1 Mixer"},
- {"Left HPCOM Mux", "constant VCM", "Left DAC_L1 Mixer"},
- {"Left HPCOM Mux", "single-ended", "Left DAC_L1 Mixer"},
-
- {"Left Line Out", NULL, "Left DAC_L1 Mixer"},
- {"Mono Out", NULL, "Left DAC_L1 Mixer"},
- {"Left HP Out", NULL, "Left DAC_L1 Mixer"},
- {"Left HP Com", NULL, "Left HPCOM Mux"},
-
- {"LLOUT", NULL, "Left Line Out"},
- {"LLOUT", NULL, "Left Line Out"},
- {"HPLOUT", NULL, "Left HP Out"},
- {"HPLCOM", NULL, "Left HP Com"},
-
- /* Right Output */
- {"Right DAC Mux", "DAC_R1", "Right DAC"},
- {"Right DAC Mux", "DAC_R2", "Right DAC"},
- {"Right DAC Mux", "DAC_R3", "Right DAC"},
- {"Right DAC_R1 Mixer", "LineL Switch", "Right DAC Mux"},
- {"Right DAC_R1 Mixer", "LineR Switch", "Right DAC Mux"},
- {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"},
- {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"},
- {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"},
- {"Right Line Out", NULL, "Right DAC Mux"},
- {"Right HP Out", NULL, "Right DAC Mux"},
+ /*
+ * Virtual output pin to detection block inside codec. This can be
+ * used to keep codec bias on if gpio or detection features are needed.
+ * Force pin on or construct a path with an input jack and mic bias
+ * widgets.
+ */
+ SND_SOC_DAPM_OUTPUT("Detection"),
+};
- {"Right HPCOM Mux", "differential of HPROUT", "Right DAC_R1 Mixer"},
- {"Right HPCOM Mux", "constant VCM", "Right DAC_R1 Mixer"},
- {"Right HPCOM Mux", "single-ended", "Right DAC_R1 Mixer"},
- {"Right HPCOM Mux", "differential of HPLCOM", "Right DAC_R1 Mixer"},
- {"Right HPCOM Mux", "external feedback", "Right DAC_R1 Mixer"},
+static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = {
+ /* Class-D outputs */
+ SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Class-D Out", CLASSD_CTRL, 2, 0, NULL, 0),
- {"Right Line Out", NULL, "Right DAC_R1 Mixer"},
- {"Mono Out", NULL, "Right DAC_R1 Mixer"},
- {"Right HP Out", NULL, "Right DAC_R1 Mixer"},
- {"Right HP Com", NULL, "Right HPCOM Mux"},
-
- {"RLOUT", NULL, "Right Line Out"},
- {"RLOUT", NULL, "Right Line Out"},
- {"HPROUT", NULL, "Right HP Out"},
- {"HPRCOM", NULL, "Right HP Com"},
-
- /* Mono Output */
- {"MONO_LOUT", NULL, "Mono Out"},
- {"MONO_LOUT", NULL, "Mono Out"},
+ SND_SOC_DAPM_OUTPUT("SPOP"),
+ SND_SOC_DAPM_OUTPUT("SPOM"),
+};
+static const struct snd_soc_dapm_route intercon[] = {
/* Left Input */
{"Left Line1L Mux", "single-ended", "LINE1L"},
{"Left Line1L Mux", "differential", "LINE1L"},
@@ -680,74 +669,6 @@ static const struct snd_soc_dapm_route intercon[] = {
{"Right ADC", NULL, "Right PGA Mixer"},
{"Right ADC", NULL, "GPIO1 dmic modclk"},
- /* Left PGA Bypass */
- {"Left PGA Bypass Mixer", "LineL Switch", "Left PGA Mixer"},
- {"Left PGA Bypass Mixer", "LineR Switch", "Left PGA Mixer"},
- {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"},
- {"Left PGA Bypass Mixer", "HPL Switch", "Left PGA Mixer"},
- {"Left PGA Bypass Mixer", "HPR Switch", "Left PGA Mixer"},
- {"Left PGA Bypass Mixer", "HPLCOM Switch", "Left PGA Mixer"},
- {"Left PGA Bypass Mixer", "HPRCOM Switch", "Left PGA Mixer"},
-
- {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"},
- {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"},
- {"Left HPCOM Mux", "single-ended", "Left PGA Bypass Mixer"},
-
- {"Left Line Out", NULL, "Left PGA Bypass Mixer"},
- {"Mono Out", NULL, "Left PGA Bypass Mixer"},
- {"Left HP Out", NULL, "Left PGA Bypass Mixer"},
-
- /* Right PGA Bypass */
- {"Right PGA Bypass Mixer", "LineL Switch", "Right PGA Mixer"},
- {"Right PGA Bypass Mixer", "LineR Switch", "Right PGA Mixer"},
- {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"},
- {"Right PGA Bypass Mixer", "HPL Switch", "Right PGA Mixer"},
- {"Right PGA Bypass Mixer", "HPR Switch", "Right PGA Mixer"},
- {"Right PGA Bypass Mixer", "HPLCOM Switch", "Right PGA Mixer"},
- {"Right PGA Bypass Mixer", "HPRCOM Switch", "Right PGA Mixer"},
-
- {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"},
- {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"},
- {"Right HPCOM Mux", "single-ended", "Right PGA Bypass Mixer"},
- {"Right HPCOM Mux", "differential of HPLCOM", "Right PGA Bypass Mixer"},
- {"Right HPCOM Mux", "external feedback", "Right PGA Bypass Mixer"},
-
- {"Right Line Out", NULL, "Right PGA Bypass Mixer"},
- {"Mono Out", NULL, "Right PGA Bypass Mixer"},
- {"Right HP Out", NULL, "Right PGA Bypass Mixer"},
-
- /* Left Line2 Bypass */
- {"Left Line2 Bypass Mixer", "LineL Switch", "Left Line2L Mux"},
- {"Left Line2 Bypass Mixer", "LineR Switch", "Left Line2L Mux"},
- {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"},
- {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"},
- {"Left Line2 Bypass Mixer", "HPLCOM Switch", "Left Line2L Mux"},
-
- {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"},
- {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"},
- {"Left HPCOM Mux", "single-ended", "Left Line2 Bypass Mixer"},
-
- {"Left Line Out", NULL, "Left Line2 Bypass Mixer"},
- {"Mono Out", NULL, "Left Line2 Bypass Mixer"},
- {"Left HP Out", NULL, "Left Line2 Bypass Mixer"},
-
- /* Right Line2 Bypass */
- {"Right Line2 Bypass Mixer", "LineL Switch", "Right Line2R Mux"},
- {"Right Line2 Bypass Mixer", "LineR Switch", "Right Line2R Mux"},
- {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"},
- {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"},
- {"Right Line2 Bypass Mixer", "HPRCOM Switch", "Right Line2R Mux"},
-
- {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"},
- {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"},
- {"Right HPCOM Mux", "single-ended", "Right Line2 Bypass Mixer"},
- {"Right HPCOM Mux", "differential of HPLCOM", "Right Line2 Bypass Mixer"},
- {"Right HPCOM Mux", "external feedback", "Right Line2 Bypass Mixer"},
-
- {"Right Line Out", NULL, "Right Line2 Bypass Mixer"},
- {"Mono Out", NULL, "Right Line2 Bypass Mixer"},
- {"Right HP Out", NULL, "Right Line2 Bypass Mixer"},
-
/*
* Logical path between digital mic enable and GPIO1 modulator clock
* output function
@@ -755,16 +676,131 @@ static const struct snd_soc_dapm_route intercon[] = {
{"GPIO1 dmic modclk", NULL, "DMic Rate 128"},
{"GPIO1 dmic modclk", NULL, "DMic Rate 64"},
{"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
+
+ /* Left DAC Output */
+ {"Left DAC Mux", "DAC_L1", "Left DAC"},
+ {"Left DAC Mux", "DAC_L2", "Left DAC"},
+ {"Left DAC Mux", "DAC_L3", "Left DAC"},
+
+ /* Right DAC Output */
+ {"Right DAC Mux", "DAC_R1", "Right DAC"},
+ {"Right DAC Mux", "DAC_R2", "Right DAC"},
+ {"Right DAC Mux", "DAC_R3", "Right DAC"},
+
+ /* Left Line Output */
+ {"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+ {"Left Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+ {"Left Line Mixer", "DACL1 Switch", "Left DAC Mux"},
+ {"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+ {"Left Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+ {"Left Line Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+ {"Left Line Out", NULL, "Left Line Mixer"},
+ {"Left Line Out", NULL, "Left DAC Mux"},
+ {"LLOUT", NULL, "Left Line Out"},
+
+ /* Right Line Output */
+ {"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+ {"Right Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+ {"Right Line Mixer", "DACL1 Switch", "Left DAC Mux"},
+ {"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+ {"Right Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+ {"Right Line Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+ {"Right Line Out", NULL, "Right Line Mixer"},
+ {"Right Line Out", NULL, "Right DAC Mux"},
+ {"RLOUT", NULL, "Right Line Out"},
+
+ /* Mono Output */
+ {"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+ {"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+ {"Mono Mixer", "DACL1 Switch", "Left DAC Mux"},
+ {"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+ {"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+ {"Mono Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+ {"Mono Out", NULL, "Mono Mixer"},
+ {"MONO_LOUT", NULL, "Mono Out"},
+
+ /* Left HP Output */
+ {"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+ {"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+ {"Left HP Mixer", "DACL1 Switch", "Left DAC Mux"},
+ {"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+ {"Left HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+ {"Left HP Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+ {"Left HP Out", NULL, "Left HP Mixer"},
+ {"Left HP Out", NULL, "Left DAC Mux"},
+ {"HPLOUT", NULL, "Left HP Out"},
+
+ /* Right HP Output */
+ {"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+ {"Right HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+ {"Right HP Mixer", "DACL1 Switch", "Left DAC Mux"},
+ {"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+ {"Right HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+ {"Right HP Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+ {"Right HP Out", NULL, "Right HP Mixer"},
+ {"Right HP Out", NULL, "Right DAC Mux"},
+ {"HPROUT", NULL, "Right HP Out"},
+
+ /* Left HPCOM Output */
+ {"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+ {"Left HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+ {"Left HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
+ {"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+ {"Left HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+ {"Left HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+ {"Left HPCOM Mux", "differential of HPLOUT", "Left HP Mixer"},
+ {"Left HPCOM Mux", "constant VCM", "Left HPCOM Mixer"},
+ {"Left HPCOM Mux", "single-ended", "Left HPCOM Mixer"},
+ {"Left HP Com", NULL, "Left HPCOM Mux"},
+ {"HPLCOM", NULL, "Left HP Com"},
+
+ /* Right HPCOM Output */
+ {"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+ {"Right HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+ {"Right HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
+ {"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+ {"Right HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+ {"Right HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+ {"Right HPCOM Mux", "differential of HPROUT", "Right HP Mixer"},
+ {"Right HPCOM Mux", "constant VCM", "Right HPCOM Mixer"},
+ {"Right HPCOM Mux", "single-ended", "Right HPCOM Mixer"},
+ {"Right HPCOM Mux", "differential of HPLCOM", "Left HPCOM Mixer"},
+ {"Right HPCOM Mux", "external feedback", "Right HPCOM Mixer"},
+ {"Right HP Com", NULL, "Right HPCOM Mux"},
+ {"HPRCOM", NULL, "Right HP Com"},
+};
+
+static const struct snd_soc_dapm_route intercon_3007[] = {
+ /* Class-D outputs */
+ {"Left Class-D Out", NULL, "Left Line Out"},
+ {"Right Class-D Out", NULL, "Left Line Out"},
+ {"SPOP", NULL, "Left Class-D Out"},
+ {"SPOM", NULL, "Right Class-D Out"},
};
static int aic3x_add_widgets(struct snd_soc_codec *codec)
{
+ struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+
snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
ARRAY_SIZE(aic3x_dapm_widgets));
/* set up audio path interconnects */
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+ if (aic3x->model == AIC3X_MODEL_3007) {
+ snd_soc_dapm_new_controls(codec, aic3007_dapm_widgets,
+ ARRAY_SIZE(aic3007_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, intercon_3007, ARRAY_SIZE(intercon_3007));
+ }
+
return 0;
}
@@ -773,8 +809,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec =rtd->codec;
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
@@ -783,8 +818,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
int clk;
/* select data word length */
- data =
- aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
+ data = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
break;
@@ -798,7 +832,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
data |= (0x03 << 4);
break;
}
- aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data);
+ snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, data);
/* Fsref can be 44100 or 48000 */
fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000;
@@ -813,17 +847,17 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
if (bypass_pll) {
pll_q &= 0xf;
- aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
- aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
+ snd_soc_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
+ snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
/* disable PLL if it is bypassed */
- reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
- aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE);
+ reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+ snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE);
} else {
- aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
+ snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
/* enable PLL when it is used */
- reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
- aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE);
+ reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+ snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE);
}
/* Route Left DAC to left channel input and
@@ -832,7 +866,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
if (params_rate(params) >= 64000)
data |= DUAL_RATE_MODE;
- aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data);
+ snd_soc_write(codec, AIC3X_CODEC_DATAPATH_REG, data);
/* codec sample rate select */
data = (fsref * 20) / params_rate(params);
@@ -841,7 +875,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
data /= 5;
data -= 2;
data |= (data << 4);
- aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data);
+ snd_soc_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data);
if (bypass_pll)
return 0;
@@ -910,13 +944,16 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
}
found:
- data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
- aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT));
- aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT);
- aic3x_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
- aic3x_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT);
- aic3x_write(codec, AIC3X_PLL_PROGD_REG,
- (pll_d & 0x3F) << PLLD_LSB_SHIFT);
+ data = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+ snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
+ data | (pll_p << PLLP_SHIFT));
+ snd_soc_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG,
+ pll_r << PLLR_SHIFT);
+ snd_soc_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
+ snd_soc_write(codec, AIC3X_PLL_PROGC_REG,
+ (pll_d >> 6) << PLLD_MSB_SHIFT);
+ snd_soc_write(codec, AIC3X_PLL_PROGD_REG,
+ (pll_d & 0x3F) << PLLD_LSB_SHIFT);
return 0;
}
@@ -924,15 +961,15 @@ found:
static int aic3x_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
- u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON;
- u8 rdac_reg = aic3x_read_reg_cache(codec, RDAC_VOL) & ~MUTE_ON;
+ u8 ldac_reg = snd_soc_read(codec, LDAC_VOL) & ~MUTE_ON;
+ u8 rdac_reg = snd_soc_read(codec, RDAC_VOL) & ~MUTE_ON;
if (mute) {
- aic3x_write(codec, LDAC_VOL, ldac_reg | MUTE_ON);
- aic3x_write(codec, RDAC_VOL, rdac_reg | MUTE_ON);
+ snd_soc_write(codec, LDAC_VOL, ldac_reg | MUTE_ON);
+ snd_soc_write(codec, RDAC_VOL, rdac_reg | MUTE_ON);
} else {
- aic3x_write(codec, LDAC_VOL, ldac_reg);
- aic3x_write(codec, RDAC_VOL, rdac_reg);
+ snd_soc_write(codec, LDAC_VOL, ldac_reg);
+ snd_soc_write(codec, RDAC_VOL, rdac_reg);
}
return 0;
@@ -956,8 +993,8 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
u8 iface_areg, iface_breg;
int delay = 0;
- iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f;
- iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f;
+ iface_areg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f;
+ iface_breg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f;
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -996,13 +1033,98 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
}
/* set iface */
- aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg);
- aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg);
- aic3x_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
+ snd_soc_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg);
+ snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg);
+ snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
+
+ return 0;
+}
+
+static int aic3x_init_3007(struct snd_soc_codec *codec)
+{
+ u8 tmp1, tmp2, *cache = codec->reg_cache;
+
+ /*
+ * There is no need to cache writes to undocumented page 0xD but
+ * respective page 0 register cache entries must be preserved
+ */
+ tmp1 = cache[0xD];
+ tmp2 = cache[0x8];
+ /* Class-D speaker driver init; datasheet p. 46 */
+ snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D);
+ snd_soc_write(codec, 0xD, 0x0D);
+ snd_soc_write(codec, 0x8, 0x5C);
+ snd_soc_write(codec, 0x8, 0x5D);
+ snd_soc_write(codec, 0x8, 0x5C);
+ snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00);
+ cache[0xD] = tmp1;
+ cache[0x8] = tmp2;
return 0;
}
+static int aic3x_regulator_event(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct aic3x_disable_nb *disable_nb =
+ container_of(nb, struct aic3x_disable_nb, nb);
+ struct aic3x_priv *aic3x = disable_nb->aic3x;
+
+ if (event & REGULATOR_EVENT_DISABLE) {
+ /*
+ * Put codec to reset and require cache sync as at least one
+ * of the supplies was disabled
+ */
+ if (aic3x->gpio_reset >= 0)
+ gpio_set_value(aic3x->gpio_reset, 0);
+ aic3x->codec->cache_sync = 1;
+ }
+
+ return 0;
+}
+
+static int aic3x_set_power(struct snd_soc_codec *codec, int power)
+{
+ struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+ int i, ret;
+ u8 *cache = codec->reg_cache;
+
+ if (power) {
+ ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
+ aic3x->supplies);
+ if (ret)
+ goto out;
+ aic3x->power = 1;
+ /*
+ * Reset release and cache sync is necessary only if some
+ * supply was off or if there were cached writes
+ */
+ if (!codec->cache_sync)
+ goto out;
+
+ if (aic3x->gpio_reset >= 0) {
+ udelay(1);
+ gpio_set_value(aic3x->gpio_reset, 1);
+ }
+
+ /* Sync reg_cache with the hardware */
+ codec->cache_only = 0;
+ for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++)
+ snd_soc_write(codec, i, cache[i]);
+ if (aic3x->model == AIC3X_MODEL_3007)
+ aic3x_init_3007(codec);
+ codec->cache_sync = 0;
+ } else {
+ aic3x->power = 0;
+ /* HW writes are needless when bias is off */
+ codec->cache_only = 1;
+ ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies),
+ aic3x->supplies);
+ }
+out:
+ return ret;
+}
+
static int aic3x_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
@@ -1013,23 +1135,29 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
- if (aic3x->master) {
+ if (codec->bias_level == SND_SOC_BIAS_STANDBY &&
+ aic3x->master) {
/* enable pll */
- reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
- aic3x_write(codec, AIC3X_PLL_PROGA_REG,
- reg | PLL_ENABLE);
+ reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+ snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
+ reg | PLL_ENABLE);
}
break;
case SND_SOC_BIAS_STANDBY:
- /* fall through and disable pll */
- case SND_SOC_BIAS_OFF:
- if (aic3x->master) {
+ if (!aic3x->power)
+ aic3x_set_power(codec, 1);
+ if (codec->bias_level == SND_SOC_BIAS_PREPARE &&
+ aic3x->master) {
/* disable pll */
- reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
- aic3x_write(codec, AIC3X_PLL_PROGA_REG,
- reg & ~PLL_ENABLE);
+ reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+ snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
+ reg & ~PLL_ENABLE);
}
break;
+ case SND_SOC_BIAS_OFF:
+ if (aic3x->power)
+ aic3x_set_power(codec, 0);
+ break;
}
codec->bias_level = level;
@@ -1040,8 +1168,8 @@ void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state)
{
u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG;
u8 bit = gpio ? 3: 0;
- u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit);
- aic3x_write(codec, reg, val | (!!state << bit));
+ u8 val = snd_soc_read(codec, reg) & ~(1 << bit);
+ snd_soc_write(codec, reg, val | (!!state << bit));
}
EXPORT_SYMBOL_GPL(aic3x_set_gpio);
@@ -1070,7 +1198,7 @@ void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect,
if (detect & AIC3X_HEADSET_DETECT_MASK)
val |= AIC3X_HEADSET_DETECT_ENABLED;
- aic3x_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val);
+ snd_soc_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val);
}
EXPORT_SYMBOL_GPL(aic3x_set_headset_detection);
@@ -1101,8 +1229,8 @@ static struct snd_soc_dai_ops aic3x_dai_ops = {
.set_fmt = aic3x_set_dai_fmt,
};
-struct snd_soc_dai aic3x_dai = {
- .name = "tlv320aic3x",
+static struct snd_soc_dai_driver aic3x_dai = {
+ .name = "tlv320aic3x-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -1116,34 +1244,18 @@ struct snd_soc_dai aic3x_dai = {
.rates = AIC3X_RATES,
.formats = AIC3X_FORMATS,},
.ops = &aic3x_dai_ops,
+ .symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(aic3x_dai);
-static int aic3x_suspend(struct platform_device *pdev, pm_message_t state)
+static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int aic3x_resume(struct platform_device *pdev)
+static int aic3x_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- int i;
- u8 data[2];
- u8 *cache = codec->reg_cache;
-
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) {
- data[0] = i;
- data[1] = cache[i];
- codec->hw_write(codec->control_data, data, 2);
- }
-
aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -1155,152 +1267,203 @@ static int aic3x_resume(struct platform_device *pdev)
*/
static int aic3x_init(struct snd_soc_codec *codec)
{
+ struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
int reg;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "tlv320aic3x";
- codec->owner = THIS_MODULE;
- codec->read = aic3x_read_reg_cache;
- codec->write = aic3x_write;
- codec->set_bias_level = aic3x_set_bias_level;
- codec->dai = &aic3x_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(aic3x_reg);
- codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL);
- if (codec->reg_cache == NULL)
- return -ENOMEM;
-
- aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
- aic3x_write(codec, AIC3X_RESET, SOFT_RESET);
+ snd_soc_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
+ snd_soc_write(codec, AIC3X_RESET, SOFT_RESET);
/* DAC default volume and mute */
- aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON);
- aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON);
+ snd_soc_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON);
+ snd_soc_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON);
/* DAC to HP default volume and route to Output mixer */
- aic3x_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON);
- aic3x_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON);
- aic3x_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON);
- aic3x_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON);
/* DAC to Line Out default volume and route to Output mixer */
- aic3x_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
- aic3x_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
/* DAC to Mono Line Out default volume and route to Output mixer */
- aic3x_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
- aic3x_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
/* unmute all outputs */
- reg = aic3x_read_reg_cache(codec, LLOPM_CTRL);
- aic3x_write(codec, LLOPM_CTRL, reg | UNMUTE);
- reg = aic3x_read_reg_cache(codec, RLOPM_CTRL);
- aic3x_write(codec, RLOPM_CTRL, reg | UNMUTE);
- reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL);
- aic3x_write(codec, MONOLOPM_CTRL, reg | UNMUTE);
- reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL);
- aic3x_write(codec, HPLOUT_CTRL, reg | UNMUTE);
- reg = aic3x_read_reg_cache(codec, HPROUT_CTRL);
- aic3x_write(codec, HPROUT_CTRL, reg | UNMUTE);
- reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL);
- aic3x_write(codec, HPLCOM_CTRL, reg | UNMUTE);
- reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL);
- aic3x_write(codec, HPRCOM_CTRL, reg | UNMUTE);
+ reg = snd_soc_read(codec, LLOPM_CTRL);
+ snd_soc_write(codec, LLOPM_CTRL, reg | UNMUTE);
+ reg = snd_soc_read(codec, RLOPM_CTRL);
+ snd_soc_write(codec, RLOPM_CTRL, reg | UNMUTE);
+ reg = snd_soc_read(codec, MONOLOPM_CTRL);
+ snd_soc_write(codec, MONOLOPM_CTRL, reg | UNMUTE);
+ reg = snd_soc_read(codec, HPLOUT_CTRL);
+ snd_soc_write(codec, HPLOUT_CTRL, reg | UNMUTE);
+ reg = snd_soc_read(codec, HPROUT_CTRL);
+ snd_soc_write(codec, HPROUT_CTRL, reg | UNMUTE);
+ reg = snd_soc_read(codec, HPLCOM_CTRL);
+ snd_soc_write(codec, HPLCOM_CTRL, reg | UNMUTE);
+ reg = snd_soc_read(codec, HPRCOM_CTRL);
+ snd_soc_write(codec, HPRCOM_CTRL, reg | UNMUTE);
/* ADC default volume and unmute */
- aic3x_write(codec, LADC_VOL, DEFAULT_GAIN);
- aic3x_write(codec, RADC_VOL, DEFAULT_GAIN);
+ snd_soc_write(codec, LADC_VOL, DEFAULT_GAIN);
+ snd_soc_write(codec, RADC_VOL, DEFAULT_GAIN);
/* By default route Line1 to ADC PGA mixer */
- aic3x_write(codec, LINE1L_2_LADC_CTRL, 0x0);
- aic3x_write(codec, LINE1R_2_RADC_CTRL, 0x0);
+ snd_soc_write(codec, LINE1L_2_LADC_CTRL, 0x0);
+ snd_soc_write(codec, LINE1R_2_RADC_CTRL, 0x0);
/* PGA to HP Bypass default volume, disconnect from Output Mixer */
- aic3x_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL);
- aic3x_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL);
- aic3x_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL);
- aic3x_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL);
/* PGA to Line Out default volume, disconnect from Output Mixer */
- aic3x_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
- aic3x_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
/* PGA to Mono Line Out default volume, disconnect from Output Mixer */
- aic3x_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
- aic3x_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
/* Line2 to HP Bypass default volume, disconnect from Output Mixer */
- aic3x_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
- aic3x_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL);
- aic3x_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL);
- aic3x_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL);
/* Line2 Line Out default volume, disconnect from Output Mixer */
- aic3x_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
- aic3x_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
/* Line2 to Mono Out default volume, disconnect from Output Mixer */
- aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
- aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
- /* off, with power on */
- aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ if (aic3x->model == AIC3X_MODEL_3007) {
+ aic3x_init_3007(codec);
+ snd_soc_write(codec, CLASSD_CTRL, 0);
+ }
return 0;
}
-static struct snd_soc_codec *aic3x_codec;
-
-static int aic3x_register(struct snd_soc_codec *codec)
+static int aic3x_probe(struct snd_soc_codec *codec)
{
- int ret;
+ struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+ int ret, i;
- ret = aic3x_init(codec);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to initialise device\n");
+ codec->control_data = aic3x->control_data;
+ aic3x->codec = codec;
+ codec->idle_bias_off = 1;
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
- aic3x_codec = codec;
+ if (aic3x->gpio_reset >= 0) {
+ ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
+ if (ret != 0)
+ goto err_gpio;
+ gpio_direction_output(aic3x->gpio_reset, 0);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
+ aic3x->supplies[i].supply = aic3x_supply_names[i];
- ret = snd_soc_register_codec(codec);
- if (ret) {
- dev_err(codec->dev, "Failed to register codec\n");
- return ret;
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies),
+ aic3x->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ goto err_get;
+ }
+ for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {
+ aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;
+ aic3x->disable_nb[i].aic3x = aic3x;
+ ret = regulator_register_notifier(aic3x->supplies[i].consumer,
+ &aic3x->disable_nb[i].nb);
+ if (ret) {
+ dev_err(codec->dev,
+ "Failed to request regulator notifier: %d\n",
+ ret);
+ goto err_notif;
+ }
}
- ret = snd_soc_register_dai(&aic3x_dai);
- if (ret) {
- dev_err(codec->dev, "Failed to register dai\n");
- snd_soc_unregister_codec(codec);
- return ret;
+ codec->cache_only = 1;
+ aic3x_init(codec);
+
+ if (aic3x->setup) {
+ /* setup GPIO functions */
+ snd_soc_write(codec, AIC3X_GPIO1_REG,
+ (aic3x->setup->gpio_func[0] & 0xf) << 4);
+ snd_soc_write(codec, AIC3X_GPIO2_REG,
+ (aic3x->setup->gpio_func[1] & 0xf) << 4);
}
+ snd_soc_add_controls(codec, aic3x_snd_controls,
+ ARRAY_SIZE(aic3x_snd_controls));
+ if (aic3x->model == AIC3X_MODEL_3007)
+ snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
+
+ aic3x_add_widgets(codec);
+
return 0;
+
+err_notif:
+ while (i--)
+ regulator_unregister_notifier(aic3x->supplies[i].consumer,
+ &aic3x->disable_nb[i].nb);
+ regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
+err_get:
+ if (aic3x->gpio_reset >= 0)
+ gpio_free(aic3x->gpio_reset);
+err_gpio:
+ kfree(aic3x);
+ return ret;
}
-static int aic3x_unregister(struct aic3x_priv *aic3x)
+static int aic3x_remove(struct snd_soc_codec *codec)
{
- aic3x_set_bias_level(&aic3x->codec, SND_SOC_BIAS_OFF);
-
- snd_soc_unregister_dai(&aic3x_dai);
- snd_soc_unregister_codec(&aic3x->codec);
+ struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+ int i;
+ aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
if (aic3x->gpio_reset >= 0) {
gpio_set_value(aic3x->gpio_reset, 0);
gpio_free(aic3x->gpio_reset);
}
- regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
+ for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
+ regulator_unregister_notifier(aic3x->supplies[i].consumer,
+ &aic3x->disable_nb[i].nb);
regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
- kfree(aic3x);
- aic3x_codec = NULL;
-
return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
+ .set_bias_level = aic3x_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(aic3x_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = aic3x_reg,
+ .probe = aic3x_probe,
+ .remove = aic3x_remove,
+ .suspend = aic3x_suspend,
+ .resume = aic3x_resume,
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
/*
* AIC3X 2 wire address can be up to 4 devices with device addresses
* 0x18, 0x19, 0x1A, 0x1B
*/
+static const struct i2c_device_id aic3x_i2c_id[] = {
+ [AIC3X_MODEL_3X] = { "tlv320aic3x", 0 },
+ [AIC3X_MODEL_33] = { "tlv320aic33", 0 },
+ [AIC3X_MODEL_3007] = { "tlv320aic3007", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
+
/*
* If the i2c layer weren't so broken, we could pass this kind of data
* around
@@ -1308,10 +1471,10 @@ static int aic3x_unregister(struct aic3x_priv *aic3x)
static int aic3x_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- struct snd_soc_codec *codec;
- struct aic3x_priv *aic3x;
struct aic3x_pdata *pdata = i2c->dev.platform_data;
- int ret, i;
+ struct aic3x_priv *aic3x;
+ int ret;
+ const struct i2c_device_id *tbl;
aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
if (aic3x == NULL) {
@@ -1319,75 +1482,41 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
}
- codec = &aic3x->codec;
- codec->dev = &i2c->dev;
- snd_soc_codec_set_drvdata(codec, aic3x);
- codec->control_data = i2c;
- codec->hw_write = (hw_write_t) i2c_master_send;
+ aic3x->control_data = i2c;
+ aic3x->control_type = SND_SOC_I2C;
i2c_set_clientdata(i2c, aic3x);
-
- aic3x->gpio_reset = -1;
- if (pdata && pdata->gpio_reset >= 0) {
- ret = gpio_request(pdata->gpio_reset, "tlv320aic3x reset");
- if (ret != 0)
- goto err_gpio;
+ if (pdata) {
aic3x->gpio_reset = pdata->gpio_reset;
- gpio_direction_output(aic3x->gpio_reset, 0);
- }
-
- for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
- aic3x->supplies[i].supply = aic3x_supply_names[i];
-
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies),
- aic3x->supplies);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err_get;
- }
-
- ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
- aic3x->supplies);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
- goto err_enable;
+ aic3x->setup = pdata->setup;
+ } else {
+ aic3x->gpio_reset = -1;
}
- if (aic3x->gpio_reset >= 0) {
- udelay(1);
- gpio_set_value(aic3x->gpio_reset, 1);
+ for (tbl = aic3x_i2c_id; tbl->name[0]; tbl++) {
+ if (!strcmp(tbl->name, id->name))
+ break;
}
+ aic3x->model = tbl - aic3x_i2c_id;
- return aic3x_register(codec);
-
-err_enable:
- regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
-err_get:
- if (aic3x->gpio_reset >= 0)
- gpio_free(aic3x->gpio_reset);
-err_gpio:
- kfree(aic3x);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_aic3x, &aic3x_dai, 1);
+ if (ret < 0)
+ kfree(aic3x);
return ret;
}
static int aic3x_i2c_remove(struct i2c_client *client)
{
- struct aic3x_priv *aic3x = i2c_get_clientdata(client);
-
- return aic3x_unregister(aic3x);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
}
-static const struct i2c_device_id aic3x_i2c_id[] = {
- { "tlv320aic3x", 0 },
- { "tlv320aic33", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
-
/* machine i2c codec control layer */
static struct i2c_driver aic3x_i2c_driver = {
.driver = {
- .name = "aic3x I2C Codec",
+ .name = "tlv320aic3x-codec",
.owner = THIS_MODULE,
},
.probe = aic3x_i2c_probe,
@@ -1409,90 +1538,27 @@ static inline void aic3x_i2c_exit(void)
{
i2c_del_driver(&aic3x_i2c_driver);
}
-#else
-static inline void aic3x_i2c_init(void) { }
-static inline void aic3x_i2c_exit(void) { }
#endif
-static int aic3x_probe(struct platform_device *pdev)
+static int __init aic3x_modinit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct aic3x_setup_data *setup;
- struct snd_soc_codec *codec;
int ret = 0;
-
- codec = aic3x_codec;
- if (!codec) {
- dev_err(&pdev->dev, "Codec not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = codec;
- setup = socdev->codec_data;
-
- if (setup) {
- /* setup GPIO functions */
- aic3x_write(codec, AIC3X_GPIO1_REG,
- (setup->gpio_func[0] & 0xf) << 4);
- aic3x_write(codec, AIC3X_GPIO2_REG,
- (setup->gpio_func[1] & 0xf) << 4);
- }
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "aic3x: failed to create pcms\n");
- goto pcm_err;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&aic3x_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n",
+ ret);
}
-
- snd_soc_add_controls(codec, aic3x_snd_controls,
- ARRAY_SIZE(aic3x_snd_controls));
-
- aic3x_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- kfree(codec->reg_cache);
+#endif
return ret;
}
-
-static int aic3x_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- /* power down chip */
- if (codec->control_data)
- aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- kfree(codec->reg_cache);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_aic3x = {
- .probe = aic3x_probe,
- .remove = aic3x_remove,
- .suspend = aic3x_suspend,
- .resume = aic3x_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x);
-
-static int __init aic3x_modinit(void)
-{
- aic3x_i2c_init();
-
- return 0;
-}
module_init(aic3x_modinit);
static void __exit aic3x_exit(void)
{
- aic3x_i2c_exit();
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&aic3x_i2c_driver);
+#endif
}
module_exit(aic3x_exit);
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
index 9af1c886213c..06a19784b162 100644
--- a/sound/soc/codecs/tlv320aic3x.h
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -81,50 +81,63 @@
/* DAC Digital control registers */
#define LDAC_VOL 43
#define RDAC_VOL 44
-/* High Power Output control registers */
+/* Left High Power Output control registers */
#define LINE2L_2_HPLOUT_VOL 45
-#define LINE2R_2_HPROUT_VOL 62
#define PGAL_2_HPLOUT_VOL 46
-#define PGAL_2_HPROUT_VOL 60
-#define PGAR_2_HPLOUT_VOL 49
-#define PGAR_2_HPROUT_VOL 63
#define DACL1_2_HPLOUT_VOL 47
-#define DACR1_2_HPROUT_VOL 64
+#define LINE2R_2_HPLOUT_VOL 48
+#define PGAR_2_HPLOUT_VOL 49
+#define DACR1_2_HPLOUT_VOL 50
#define HPLOUT_CTRL 51
-#define HPROUT_CTRL 65
-/* High Power COM control registers */
+/* Left High Power COM control registers */
#define LINE2L_2_HPLCOM_VOL 52
-#define LINE2R_2_HPRCOM_VOL 69
#define PGAL_2_HPLCOM_VOL 53
+#define DACL1_2_HPLCOM_VOL 54
+#define LINE2R_2_HPLCOM_VOL 55
#define PGAR_2_HPLCOM_VOL 56
+#define DACR1_2_HPLCOM_VOL 57
+#define HPLCOM_CTRL 58
+/* Right High Power Output control registers */
+#define LINE2L_2_HPROUT_VOL 59
+#define PGAL_2_HPROUT_VOL 60
+#define DACL1_2_HPROUT_VOL 61
+#define LINE2R_2_HPROUT_VOL 62
+#define PGAR_2_HPROUT_VOL 63
+#define DACR1_2_HPROUT_VOL 64
+#define HPROUT_CTRL 65
+/* Right High Power COM control registers */
+#define LINE2L_2_HPRCOM_VOL 66
#define PGAL_2_HPRCOM_VOL 67
+#define DACL1_2_HPRCOM_VOL 68
+#define LINE2R_2_HPRCOM_VOL 69
#define PGAR_2_HPRCOM_VOL 70
-#define DACL1_2_HPLCOM_VOL 54
#define DACR1_2_HPRCOM_VOL 71
-#define HPLCOM_CTRL 58
#define HPRCOM_CTRL 72
/* Mono Line Output Plus/Minus control registers */
#define LINE2L_2_MONOLOPM_VOL 73
-#define LINE2R_2_MONOLOPM_VOL 76
#define PGAL_2_MONOLOPM_VOL 74
-#define PGAR_2_MONOLOPM_VOL 77
#define DACL1_2_MONOLOPM_VOL 75
+#define LINE2R_2_MONOLOPM_VOL 76
+#define PGAR_2_MONOLOPM_VOL 77
#define DACR1_2_MONOLOPM_VOL 78
#define MONOLOPM_CTRL 79
-/* Line Output Plus/Minus control registers */
+/* Class-D speaker driver on tlv320aic3007 */
+#define CLASSD_CTRL 73
+/* Left Line Output Plus/Minus control registers */
#define LINE2L_2_LLOPM_VOL 80
-#define LINE2L_2_RLOPM_VOL 87
-#define LINE2R_2_LLOPM_VOL 83
-#define LINE2R_2_RLOPM_VOL 90
#define PGAL_2_LLOPM_VOL 81
-#define PGAL_2_RLOPM_VOL 88
-#define PGAR_2_LLOPM_VOL 84
-#define PGAR_2_RLOPM_VOL 91
#define DACL1_2_LLOPM_VOL 82
-#define DACL1_2_RLOPM_VOL 89
-#define DACR1_2_RLOPM_VOL 92
+#define LINE2R_2_LLOPM_VOL 83
+#define PGAR_2_LLOPM_VOL 84
#define DACR1_2_LLOPM_VOL 85
#define LLOPM_CTRL 86
+/* Right Line Output Plus/Minus control registers */
+#define LINE2L_2_RLOPM_VOL 87
+#define PGAL_2_RLOPM_VOL 88
+#define DACL1_2_RLOPM_VOL 89
+#define LINE2R_2_RLOPM_VOL 90
+#define PGAR_2_RLOPM_VOL 91
+#define DACR1_2_RLOPM_VOL 92
#define RLOPM_CTRL 93
/* GPIO/IRQ registers */
#define AIC3X_STICKY_IRQ_FLAGS_REG 96
@@ -199,42 +212,6 @@
/* Default input volume */
#define DEFAULT_GAIN 0x20
-/* GPIO API */
-enum {
- AIC3X_GPIO1_FUNC_DISABLED = 0,
- AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC = 1,
- AIC3X_GPIO1_FUNC_CLOCK_MUX = 2,
- AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2 = 3,
- AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4 = 4,
- AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8 = 5,
- AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ = 6,
- AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ = 7,
- AIC3X_GPIO1_FUNC_INPUT = 8,
- AIC3X_GPIO1_FUNC_OUTPUT = 9,
- AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK = 10,
- AIC3X_GPIO1_FUNC_AUDIO_WORDCLK = 11,
- AIC3X_GPIO1_FUNC_BUTTON_IRQ = 12,
- AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ = 13,
- AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 14,
- AIC3X_GPIO1_FUNC_ALL_IRQ = 16
-};
-
-enum {
- AIC3X_GPIO2_FUNC_DISABLED = 0,
- AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ = 2,
- AIC3X_GPIO2_FUNC_INPUT = 3,
- AIC3X_GPIO2_FUNC_OUTPUT = 4,
- AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT = 5,
- AIC3X_GPIO2_FUNC_AUDIO_BITCLK = 8,
- AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
- AIC3X_GPIO2_FUNC_ALL_IRQ = 10,
- AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
- AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
- AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ = 13,
- AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ = 14,
- AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15
-};
-
void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state);
int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio);
@@ -281,11 +258,4 @@ void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect,
int aic3x_headset_detected(struct snd_soc_codec *codec);
int aic3x_button_pressed(struct snd_soc_codec *codec);
-struct aic3x_setup_data {
- unsigned int gpio_func[2];
-};
-
-extern struct snd_soc_dai aic3x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_aic3x;
-
#endif /* _AIC3X_H */
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 8651b01ed223..d251ff54a2d3 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -66,8 +66,6 @@
static void dac33_calculate_times(struct snd_pcm_substream *substream);
static int dac33_prepare_chip(struct snd_pcm_substream *substream);
-static struct snd_soc_codec *tlv320dac33_codec;
-
enum dac33_state {
DAC33_IDLE = 0,
DAC33_PREFILL,
@@ -93,7 +91,7 @@ struct tlv320dac33_priv {
struct mutex mutex;
struct workqueue_struct *dac33_wq;
struct work_struct work;
- struct snd_soc_codec codec;
+ struct snd_soc_codec *codec;
struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
struct snd_pcm_substream *substream;
int power_gpio;
@@ -128,6 +126,8 @@ struct tlv320dac33_priv {
unsigned int uthr;
enum dac33_state state;
+ enum snd_soc_control_type control_type;
+ void *control_data;
};
static const u8 dac33_reg[DAC33_CACHEREGNUM] = {
@@ -524,6 +524,22 @@ static const struct soc_enum dac33_fifo_mode_enum =
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts),
dac33_fifo_mode_texts);
+/* L/R Line Output Gain */
+static const char *lr_lineout_gain_texts[] = {
+ "Line -12dB DAC 0dB", "Line -6dB DAC 6dB",
+ "Line 0dB DAC 12dB", "Line 6dB DAC 18dB",
+};
+
+static const struct soc_enum l_lineout_gain_enum =
+ SOC_ENUM_SINGLE(DAC33_LDAC_PWR_CTRL, 0,
+ ARRAY_SIZE(lr_lineout_gain_texts),
+ lr_lineout_gain_texts);
+
+static const struct soc_enum r_lineout_gain_enum =
+ SOC_ENUM_SINGLE(DAC33_RDAC_PWR_CTRL, 0,
+ ARRAY_SIZE(lr_lineout_gain_texts),
+ lr_lineout_gain_texts);
+
/*
* DACL/R digital volume control:
* from 0 dB to -63.5 in 0.5 dB steps
@@ -541,6 +557,8 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = {
DAC33_LDAC_DIG_VOL_CTRL, DAC33_RDAC_DIG_VOL_CTRL, 7, 1, 1),
SOC_DOUBLE_R("Line to Line Out Volume",
DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1),
+ SOC_ENUM("Left Line Output Gain", l_lineout_gain_enum),
+ SOC_ENUM("Right Line Output Gain", r_lineout_gain_enum),
};
static const struct snd_kcontrol_new dac33_mode_snd_controls[] = {
@@ -650,9 +668,8 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
{
- struct snd_soc_codec *codec;
-
- codec = &dac33->codec;
+ struct snd_soc_codec *codec = dac33->codec;
+ unsigned int delay;
switch (dac33->fifo_mode) {
case DAC33_FIFO_MODE1:
@@ -668,8 +685,9 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
dac33_write16(codec, DAC33_PREFILL_MSB,
DAC33_THRREG(dac33->alarm_threshold));
/* Enable Alarm Threshold IRQ with a delay */
- udelay(SAMPLES_TO_US(dac33->burst_rate,
- dac33->alarm_threshold));
+ delay = SAMPLES_TO_US(dac33->burst_rate,
+ dac33->alarm_threshold) + 1000;
+ usleep_range(delay, delay + 500);
dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
break;
case DAC33_FIFO_MODE7:
@@ -695,9 +713,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
{
- struct snd_soc_codec *codec;
-
- codec = &dac33->codec;
+ struct snd_soc_codec *codec = dac33->codec;
switch (dac33->fifo_mode) {
case DAC33_FIFO_MODE1:
@@ -726,7 +742,7 @@ static void dac33_work(struct work_struct *work)
u8 reg;
dac33 = container_of(work, struct tlv320dac33_priv, work);
- codec = &dac33->codec;
+ codec = dac33->codec;
mutex_lock(&dac33->mutex);
switch (dac33->state) {
@@ -771,11 +787,11 @@ static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
static void dac33_oscwait(struct snd_soc_codec *codec)
{
- int timeout = 20;
+ int timeout = 60;
u8 reg;
do {
- msleep(1);
+ usleep_range(1000, 2000);
dac33_read(codec, DAC33_INT_OSC_STATUS, &reg);
} while (((reg & 0x03) != DAC33_OSCSTATUS_NORMAL) && timeout--);
if ((reg & 0x03) != DAC33_OSCSTATUS_NORMAL)
@@ -787,8 +803,7 @@ static int dac33_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
/* Stream started, save the substream pointer */
@@ -801,8 +816,7 @@ static void dac33_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
dac33->substream = NULL;
@@ -817,8 +831,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* Check parameters for validity */
switch (params_rate(params)) {
@@ -856,8 +869,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
static int dac33_prepare_chip(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
u8 aictrl_a, aictrl_b, fifoctrl_a;
@@ -1049,8 +1061,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
static void dac33_calculate_times(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
unsigned int period_size = substream->runtime->period_size;
unsigned int rate = substream->runtime->rate;
@@ -1129,8 +1140,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
@@ -1163,8 +1173,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
unsigned long long t0, t1, t_now;
unsigned int time_delta, uthr;
@@ -1389,24 +1398,46 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
-static int dac33_soc_probe(struct platform_device *pdev)
+static int dac33_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct tlv320dac33_priv *dac33;
+ struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
- BUG_ON(!tlv320dac33_codec);
+ codec->control_data = dac33->control_data;
+ codec->hw_write = (hw_write_t) i2c_master_send;
+ codec->idle_bias_off = 1;
+ dac33->codec = codec;
- codec = tlv320dac33_codec;
- socdev->card->codec = codec;
- dac33 = snd_soc_codec_get_drvdata(codec);
+ /* Read the tlv320dac33 ID registers */
+ ret = dac33_hard_power(codec, 1);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
+ goto err_power;
+ }
+ dac33_read_id(codec);
+ dac33_hard_power(codec, 0);
+
+ /* Check if the IRQ number is valid and request it */
+ if (dac33->irq >= 0) {
+ ret = request_irq(dac33->irq, dac33_interrupt_handler,
+ IRQF_TRIGGER_RISING | IRQF_DISABLED,
+ codec->name, codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
+ dac33->irq, ret);
+ dac33->irq = -1;
+ }
+ if (dac33->irq != -1) {
+ /* Setup work queue */
+ dac33->dac33_wq =
+ create_singlethread_workqueue("tlv320dac33");
+ if (dac33->dac33_wq == NULL) {
+ free_irq(dac33->irq, codec);
+ return -ENOMEM;
+ }
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms\n");
- goto pcm_err;
+ INIT_WORK(&dac33->work, dac33_work);
+ }
}
snd_soc_add_controls(codec, dac33_snd_controls,
@@ -1420,56 +1451,51 @@ static int dac33_soc_probe(struct platform_device *pdev)
snd_soc_add_controls(codec, dac33_fifo_snd_controls,
ARRAY_SIZE(dac33_fifo_snd_controls));
}
-
dac33_add_widgets(codec);
- return 0;
-
-pcm_err:
- dac33_hard_power(codec, 0);
+err_power:
return ret;
}
-static int dac33_soc_remove(struct platform_device *pdev)
+static int dac33_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
+ if (dac33->irq >= 0) {
+ free_irq(dac33->irq, dac33->codec);
+ destroy_workqueue(dac33->dac33_wq);
+ }
return 0;
}
-static int dac33_soc_suspend(struct platform_device *pdev, pm_message_t state)
+static int dac33_soc_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int dac33_soc_resume(struct platform_device *pdev)
+static int dac33_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_tlv320dac33 = {
+static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
+ .read = dac33_read_reg_cache,
+ .write = dac33_write_locked,
+ .set_bias_level = dac33_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(dac33_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = dac33_reg,
.probe = dac33_soc_probe,
.remove = dac33_soc_remove,
.suspend = dac33_soc_suspend,
.resume = dac33_soc_resume,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320dac33);
#define DAC33_RATES (SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000)
@@ -1485,8 +1511,8 @@ static struct snd_soc_dai_ops dac33_dai_ops = {
.set_fmt = dac33_set_dai_fmt,
};
-struct snd_soc_dai dac33_dai = {
- .name = "tlv320dac33",
+static struct snd_soc_dai_driver dac33_dai = {
+ .name = "tlv320dac33-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -1495,14 +1521,12 @@ struct snd_soc_dai dac33_dai = {
.formats = DAC33_FORMATS,},
.ops = &dac33_dai_ops,
};
-EXPORT_SYMBOL_GPL(dac33_dai);
static int __devinit dac33_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tlv320dac33_platform_data *pdata;
struct tlv320dac33_priv *dac33;
- struct snd_soc_codec *codec;
int ret, i;
if (client->dev.platform_data == NULL) {
@@ -1515,33 +1539,9 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
if (dac33 == NULL)
return -ENOMEM;
- codec = &dac33->codec;
- snd_soc_codec_set_drvdata(codec, dac33);
- codec->control_data = client;
-
- mutex_init(&codec->mutex);
+ dac33->control_data = client;
mutex_init(&dac33->mutex);
spin_lock_init(&dac33->lock);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "tlv320dac33";
- codec->owner = THIS_MODULE;
- codec->read = dac33_read_reg_cache;
- codec->write = dac33_write_locked;
- codec->hw_write = (hw_write_t) i2c_master_send;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = dac33_set_bias_level;
- codec->idle_bias_off = 1;
- codec->dai = &dac33_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(dac33_reg);
- codec->reg_cache = kmemdup(dac33_reg, ARRAY_SIZE(dac33_reg),
- GFP_KERNEL);
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto error_reg;
- }
i2c_set_clientdata(client, dac33);
@@ -1561,125 +1561,59 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
/* Disable FIFO use by default */
dac33->fifo_mode = DAC33_FIFO_BYPASS;
- tlv320dac33_codec = codec;
-
- codec->dev = &client->dev;
- dac33_dai.dev = codec->dev;
-
/* Check if the reset GPIO number is valid and request it */
if (dac33->power_gpio >= 0) {
ret = gpio_request(dac33->power_gpio, "tlv320dac33 reset");
if (ret < 0) {
- dev_err(codec->dev,
+ dev_err(&client->dev,
"Failed to request reset GPIO (%d)\n",
dac33->power_gpio);
- snd_soc_unregister_dai(&dac33_dai);
- snd_soc_unregister_codec(codec);
- goto error_gpio;
+ goto err_gpio;
}
gpio_direction_output(dac33->power_gpio, 0);
}
- /* Check if the IRQ number is valid and request it */
- if (dac33->irq >= 0) {
- ret = request_irq(dac33->irq, dac33_interrupt_handler,
- IRQF_TRIGGER_RISING | IRQF_DISABLED,
- codec->name, codec);
- if (ret < 0) {
- dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
- dac33->irq, ret);
- dac33->irq = -1;
- }
- if (dac33->irq != -1) {
- /* Setup work queue */
- dac33->dac33_wq =
- create_singlethread_workqueue("tlv320dac33");
- if (dac33->dac33_wq == NULL) {
- free_irq(dac33->irq, &dac33->codec);
- ret = -ENOMEM;
- goto error_wq;
- }
-
- INIT_WORK(&dac33->work, dac33_work);
- }
- }
-
for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++)
dac33->supplies[i].supply = dac33_supply_names[i];
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(dac33->supplies),
+ ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(dac33->supplies),
dac33->supplies);
if (ret != 0) {
- dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ dev_err(&client->dev, "Failed to request supplies: %d\n", ret);
goto err_get;
}
- /* Read the tlv320dac33 ID registers */
- ret = dac33_hard_power(codec, 1);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
- goto error_codec;
- }
- dac33_read_id(codec);
- dac33_hard_power(codec, 0);
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto error_codec;
- }
-
- ret = snd_soc_register_dai(&dac33_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- goto error_codec;
- }
+ ret = snd_soc_register_codec(&client->dev,
+ &soc_codec_dev_tlv320dac33, &dac33_dai, 1);
+ if (ret < 0)
+ goto err_register;
return ret;
-
-error_codec:
+err_register:
regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
err_get:
- if (dac33->irq >= 0) {
- free_irq(dac33->irq, &dac33->codec);
- destroy_workqueue(dac33->dac33_wq);
- }
-error_wq:
if (dac33->power_gpio >= 0)
gpio_free(dac33->power_gpio);
-error_gpio:
- kfree(codec->reg_cache);
-error_reg:
- tlv320dac33_codec = NULL;
+err_gpio:
kfree(dac33);
-
return ret;
}
static int __devexit dac33_i2c_remove(struct i2c_client *client)
{
- struct tlv320dac33_priv *dac33;
-
- dac33 = i2c_get_clientdata(client);
+ struct tlv320dac33_priv *dac33 = i2c_get_clientdata(client);
if (unlikely(dac33->chip_power))
- dac33_hard_power(&dac33->codec, 0);
+ dac33_hard_power(dac33->codec, 0);
if (dac33->power_gpio >= 0)
gpio_free(dac33->power_gpio);
- if (dac33->irq >= 0)
- free_irq(dac33->irq, &dac33->codec);
regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
- destroy_workqueue(dac33->dac33_wq);
- snd_soc_unregister_dai(&dac33_dai);
- snd_soc_unregister_codec(&dac33->codec);
- kfree(dac33->codec.reg_cache);
+ snd_soc_unregister_codec(&client->dev);
kfree(dac33);
- tlv320dac33_codec = NULL;
return 0;
}
@@ -1694,7 +1628,7 @@ static const struct i2c_device_id tlv320dac33_i2c_id[] = {
static struct i2c_driver tlv320dac33_i2c_driver = {
.driver = {
- .name = "tlv320dac33",
+ .name = "tlv320dac33-codec",
.owner = THIS_MODULE,
},
.probe = dac33_i2c_probe,
diff --git a/sound/soc/codecs/tlv320dac33.h b/sound/soc/codecs/tlv320dac33.h
index eb8ae07f0bd2..7c318b5da437 100644
--- a/sound/soc/codecs/tlv320dac33.h
+++ b/sound/soc/codecs/tlv320dac33.h
@@ -261,7 +261,4 @@
#define TLV320DAC33_MCLK 0
#define TLV320DAC33_SLEEPCLK 1
-extern struct snd_soc_dai dac33_dai;
-extern struct snd_soc_codec_device soc_codec_dev_tlv320dac33;
-
#endif /* __TLV320DAC33_H */
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index 99b70e5978a2..329acc1a2074 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -98,16 +98,21 @@ static u8 tpa6130a2_read(int reg)
return data->regs[reg];
}
-static void tpa6130a2_initialize(void)
+static int tpa6130a2_initialize(void)
{
struct tpa6130a2_data *data;
- int i;
+ int i, ret = 0;
BUG_ON(tpa6130a2_client == NULL);
data = i2c_get_clientdata(tpa6130a2_client);
- for (i = 1; i < TPA6130A2_REG_VERSION; i++)
- tpa6130a2_i2c_write(i, data->regs[i]);
+ for (i = 1; i < TPA6130A2_REG_VERSION; i++) {
+ ret = tpa6130a2_i2c_write(i, data->regs[i]);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
}
static int tpa6130a2_power(int power)
@@ -133,7 +138,16 @@ static int tpa6130a2_power(int power)
}
data->power_state = 1;
- tpa6130a2_initialize();
+ ret = tpa6130a2_initialize();
+ if (ret < 0) {
+ dev_err(&tpa6130a2_client->dev,
+ "Failed to initialize chip\n");
+ if (data->power_gpio >= 0)
+ gpio_set_value(data->power_gpio, 0);
+ regulator_disable(data->supply);
+ data->power_state = 0;
+ goto exit;
+ }
/* Clear SWS */
val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
@@ -375,7 +389,9 @@ int tpa6130a2_add_controls(struct snd_soc_codec *codec)
{
struct tpa6130a2_data *data;
- BUG_ON(tpa6130a2_client == NULL);
+ if (tpa6130a2_client == NULL)
+ return -ENODEV;
+
data = i2c_get_clientdata(tpa6130a2_client);
snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets,
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 7b618bbff884..cbebec6ba1ba 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -36,7 +36,16 @@
#include <sound/initval.h>
#include <sound/tlv.h>
-#include "twl4030.h"
+/* Register descriptions are here */
+#include <linux/mfd/twl4030-codec.h>
+
+/* Shadow register used by the audio driver */
+#define TWL4030_REG_SW_SHADOW 0x4A
+#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1)
+
+/* TWL4030_REG_SW_SHADOW (0x4A) Fields */
+#define TWL4030_HFL_EN 0x01
+#define TWL4030_HFR_EN 0x02
/*
* twl4030 register cache & default register settings
@@ -277,21 +286,19 @@ static inline void twl4030_reset_registers(struct snd_soc_codec *codec)
}
-static void twl4030_init_chip(struct platform_device *pdev)
+static void twl4030_init_chip(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct twl4030_setup_data *setup = socdev->codec_data;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct twl4030_codec_audio_data *pdata = dev_get_platdata(codec->dev);
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 reg, byte;
int i = 0;
/* Check defaults, if instructed before anything else */
- if (setup && setup->check_defaults)
+ if (pdata && pdata->check_defaults)
twl4030_check_defaults(codec);
/* Reset registers, if no setup data or if instructed to do so */
- if (!setup || (setup && setup->reset_registers))
+ if (!pdata || (pdata && pdata->reset_registers))
twl4030_reset_registers(codec);
/* Refresh APLL_CTL register from HW */
@@ -312,20 +319,14 @@ static void twl4030_init_chip(struct platform_device *pdev)
twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
/* Machine dependent setup */
- if (!setup)
+ if (!pdata)
return;
- twl4030->digimic_delay = setup->digimic_delay;
-
- /* Configuration for headset ramp delay from setup data */
- if (setup->sysclk != twl4030->sysclk)
- dev_warn(codec->dev,
- "Mismatch in APLL mclk: %u (configured: %u)\n",
- setup->sysclk, twl4030->sysclk);
+ twl4030->digimic_delay = pdata->digimic_delay;
reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
reg &= ~TWL4030_RAMP_DELAY;
- reg |= (setup->ramp_delay_value << 2);
+ reg |= (pdata->ramp_delay_value << 2);
twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg);
/* initiate offset cancellation */
@@ -333,7 +334,7 @@ static void twl4030_init_chip(struct platform_device *pdev)
reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
reg &= ~TWL4030_OFFSET_CNCL_SEL;
- reg |= setup->offset_cncl_path;
+ reg |= pdata->offset_cncl_path;
twl4030_write(codec, TWL4030_REG_ANAMICL,
reg | TWL4030_CNCL_OFFSET_START);
@@ -718,9 +719,7 @@ static int aif_event(struct snd_soc_dapm_widget *w,
static void headset_ramp(struct snd_soc_codec *codec, int ramp)
{
- struct snd_soc_device *socdev = codec->socdev;
- struct twl4030_setup_data *setup = socdev->codec_data;
-
+ struct twl4030_codec_audio_data *pdata = codec->dev->platform_data;
unsigned char hs_gain, hs_pop;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
/* Base values for ramp delay calculation: 2^19 - 2^26 */
@@ -732,9 +731,9 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
/* Enable external mute control, this dramatically reduces
* the pop-noise */
- if (setup && setup->hs_extmute) {
- if (setup->set_hs_extmute) {
- setup->set_hs_extmute(1);
+ if (pdata && pdata->hs_extmute) {
+ if (pdata->set_hs_extmute) {
+ pdata->set_hs_extmute(1);
} else {
hs_pop |= TWL4030_EXTMUTE;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -772,9 +771,9 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
}
/* Disable external mute */
- if (setup && setup->hs_extmute) {
- if (setup->set_hs_extmute) {
- setup->set_hs_extmute(0);
+ if (pdata && pdata->hs_extmute) {
+ if (pdata->set_hs_extmute) {
+ pdata->set_hs_extmute(0);
} else {
hs_pop &= ~TWL4030_EXTMUTE;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -1707,8 +1706,7 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
if (twl4030->master_substream) {
@@ -1738,8 +1736,7 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
if (twl4030->master_substream == substream)
@@ -1764,8 +1761,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 mode, old_mode, format, old_format;
@@ -1999,8 +1995,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 mode;
@@ -2033,8 +2028,7 @@ static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* Enable voice digital filters */
twl4030_voice_enable(codec, substream->stream, 0);
@@ -2044,8 +2038,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 old_mode, mode;
@@ -2175,7 +2168,7 @@ static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)
#define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000)
#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
-static struct snd_soc_dai_ops twl4030_dai_ops = {
+static struct snd_soc_dai_ops twl4030_dai_hifi_ops = {
.startup = twl4030_startup,
.shutdown = twl4030_shutdown,
.hw_params = twl4030_hw_params,
@@ -2193,9 +2186,9 @@ static struct snd_soc_dai_ops twl4030_dai_voice_ops = {
.set_tristate = twl4030_voice_set_tristate,
};
-struct snd_soc_dai twl4030_dai[] = {
+static struct snd_soc_dai_driver twl4030_dai[] = {
{
- .name = "twl4030",
+ .name = "twl4030-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 2,
@@ -2208,10 +2201,10 @@ struct snd_soc_dai twl4030_dai[] = {
.channels_max = 4,
.rates = TWL4030_RATES,
.formats = TWL4030_FORMATS,},
- .ops = &twl4030_dai_ops,
+ .ops = &twl4030_dai_hifi_ops,
},
{
- .name = "twl4030 Voice",
+ .name = "twl4030-voice",
.playback = {
.stream_name = "Voice Playback",
.channels_min = 1,
@@ -2227,164 +2220,91 @@ struct snd_soc_dai twl4030_dai[] = {
.ops = &twl4030_dai_voice_ops,
},
};
-EXPORT_SYMBOL_GPL(twl4030_dai);
-static int twl4030_soc_suspend(struct platform_device *pdev, pm_message_t state)
+static int twl4030_soc_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
return 0;
}
-static int twl4030_soc_resume(struct platform_device *pdev)
+static int twl4030_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-static struct snd_soc_codec *twl4030_codec;
-
-static int twl4030_soc_probe(struct platform_device *pdev)
+static int twl4030_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret;
-
- BUG_ON(!twl4030_codec);
-
- codec = twl4030_codec;
- socdev->card->codec = codec;
-
- twl4030_init_chip(pdev);
+ struct twl4030_priv *twl4030;
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to create pcms\n");
- return ret;
+ twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
+ if (twl4030 == NULL) {
+ printk("Can not allocate memroy\n");
+ return -ENOMEM;
}
+ snd_soc_codec_set_drvdata(codec, twl4030);
+ /* Set the defaults, and power up the codec */
+ twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
+ codec->idle_bias_off = 1;
+
+ twl4030_init_chip(codec);
snd_soc_add_controls(codec, twl4030_snd_controls,
ARRAY_SIZE(twl4030_snd_controls));
twl4030_add_widgets(codec);
-
return 0;
}
-static int twl4030_soc_remove(struct platform_device *pdev)
+static int twl4030_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
/* Reset registers to their chip default before leaving */
twl4030_reset_registers(codec);
twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
+ .probe = twl4030_soc_probe,
+ .remove = twl4030_soc_remove,
+ .suspend = twl4030_soc_suspend,
+ .resume = twl4030_soc_resume,
+ .read = twl4030_read_reg_cache,
+ .write = twl4030_write,
+ .set_bias_level = twl4030_set_bias_level,
+ .reg_cache_size = sizeof(twl4030_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = twl4030_reg,
+};
+
static int __devinit twl4030_codec_probe(struct platform_device *pdev)
{
struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data;
- struct snd_soc_codec *codec;
- struct twl4030_priv *twl4030;
- int ret;
if (!pdata) {
dev_err(&pdev->dev, "platform_data is missing\n");
return -EINVAL;
}
- twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
- if (twl4030 == NULL) {
- dev_err(&pdev->dev, "Can not allocate memroy\n");
- return -ENOMEM;
- }
-
- codec = &twl4030->codec;
- snd_soc_codec_set_drvdata(codec, twl4030);
- codec->dev = &pdev->dev;
- twl4030_dai[0].dev = &pdev->dev;
- twl4030_dai[1].dev = &pdev->dev;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "twl4030";
- codec->owner = THIS_MODULE;
- codec->read = twl4030_read_reg_cache;
- codec->write = twl4030_write;
- codec->set_bias_level = twl4030_set_bias_level;
- codec->idle_bias_off = 1;
- codec->dai = twl4030_dai;
- codec->num_dai = ARRAY_SIZE(twl4030_dai);
- codec->reg_cache_size = sizeof(twl4030_reg);
- codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg),
- GFP_KERNEL);
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto error_cache;
- }
-
- platform_set_drvdata(pdev, twl4030);
- twl4030_codec = codec;
-
- /* Set the defaults, and power up the codec */
- twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
- codec->bias_level = SND_SOC_BIAS_OFF;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto error_codec;
- }
-
- ret = snd_soc_register_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
- snd_soc_unregister_codec(codec);
- goto error_codec;
- }
-
- return 0;
-
-error_codec:
- twl4030_codec_enable(codec, 0);
- kfree(codec->reg_cache);
-error_cache:
- kfree(twl4030);
- return ret;
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030,
+ twl4030_dai, ARRAY_SIZE(twl4030_dai));
}
static int __devexit twl4030_codec_remove(struct platform_device *pdev)
{
- struct twl4030_priv *twl4030 = platform_get_drvdata(pdev);
+ struct twl4030_priv *twl4030 = dev_get_drvdata(&pdev->dev);
- snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
- snd_soc_unregister_codec(&twl4030->codec);
- kfree(twl4030->codec.reg_cache);
+ snd_soc_unregister_codec(&pdev->dev);
kfree(twl4030);
-
- twl4030_codec = NULL;
return 0;
}
-MODULE_ALIAS("platform:twl4030_codec_audio");
+MODULE_ALIAS("platform:twl4030-codec");
static struct platform_driver twl4030_codec_driver = {
.probe = twl4030_codec_probe,
.remove = __devexit_p(twl4030_codec_remove),
.driver = {
- .name = "twl4030_codec_audio",
+ .name = "twl4030-codec",
.owner = THIS_MODULE,
},
};
@@ -2401,14 +2321,6 @@ static void __exit twl4030_exit(void)
}
module_exit(twl4030_exit);
-struct snd_soc_codec_device soc_codec_dev_twl4030 = {
- .probe = twl4030_soc_probe,
- .remove = twl4030_soc_remove,
- .suspend = twl4030_soc_suspend,
- .resume = twl4030_soc_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030);
-
MODULE_DESCRIPTION("ASoC TWL4030 codec driver");
MODULE_AUTHOR("Steve Sakoman");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
deleted file mode 100644
index 6c57430f6e24..000000000000
--- a/sound/soc/codecs/twl4030.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * ALSA SoC TWL4030 codec driver
- *
- * Author: Steve Sakoman <steve@sakoman.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __TWL4030_AUDIO_H__
-#define __TWL4030_AUDIO_H__
-
-/* Register descriptions are here */
-#include <linux/mfd/twl4030-codec.h>
-
-/* Shadow register used by the audio driver */
-#define TWL4030_REG_SW_SHADOW 0x4A
-#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1)
-
-/* TWL4030_REG_SW_SHADOW (0x4A) Fields */
-#define TWL4030_HFL_EN 0x01
-#define TWL4030_HFR_EN 0x02
-
-#define TWL4030_DAI_HIFI 0
-#define TWL4030_DAI_VOICE 1
-
-extern struct snd_soc_dai twl4030_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_twl4030;
-
-struct twl4030_setup_data {
- unsigned int ramp_delay_value;
- unsigned int digimic_delay; /* in ms */
- unsigned int sysclk;
- unsigned int offset_cncl_path;
- unsigned int check_defaults:1;
- unsigned int reset_registers:1;
- unsigned int hs_extmute:1;
- void (*set_hs_extmute)(int mute);
-};
-
-#endif /* End of __TWL4030_AUDIO_H__ */
-
-
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 64a807f1a8a1..10f6e5214511 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -45,7 +45,6 @@
/* codec private data */
struct twl6040_data {
- struct snd_soc_codec codec;
int audpwron;
int naudint;
int codec_powered;
@@ -770,8 +769,7 @@ static int twl6040_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
if (!priv->sysclk) {
@@ -803,8 +801,7 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
u8 lppllctl;
int rate;
@@ -839,8 +836,7 @@ static int twl6040_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
switch (cmd) {
@@ -978,8 +974,8 @@ static struct snd_soc_dai_ops twl6040_dai_ops = {
.set_sysclk = twl6040_set_dai_sysclk,
};
-struct snd_soc_dai twl6040_dai = {
- .name = "twl6040",
+static struct snd_soc_dai_driver twl6040_dai = {
+ .name = "twl6040-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -996,24 +992,17 @@ struct snd_soc_dai twl6040_dai = {
},
.ops = &twl6040_dai_ops,
};
-EXPORT_SYMBOL_GPL(twl6040_dai);
#ifdef CONFIG_PM
-static int twl6040_suspend(struct platform_device *pdev, pm_message_t state)
+static int twl6040_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int twl6040_resume(struct platform_device *pdev)
+static int twl6040_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -1023,68 +1012,9 @@ static int twl6040_resume(struct platform_device *pdev)
#define twl6040_resume NULL
#endif
-static struct snd_soc_codec *twl6040_codec;
-
-static int twl6040_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- BUG_ON(!twl6040_codec);
-
- codec = twl6040_codec;
- socdev->card->codec = codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to create pcms\n");
- return ret;
- }
-
- snd_soc_add_controls(codec, twl6040_snd_controls,
- ARRAY_SIZE(twl6040_snd_controls));
- twl6040_add_widgets(codec);
-
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to register card\n");
- goto card_err;
- }
-
- return ret;
-
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
- return ret;
-}
-
-static int twl6040_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_twl6040 = {
- .probe = twl6040_probe,
- .remove = twl6040_remove,
- .suspend = twl6040_suspend,
- .resume = twl6040_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_twl6040);
-
-static int __devinit twl6040_codec_probe(struct platform_device *pdev)
+static int twl6040_probe(struct snd_soc_codec *codec)
{
- struct twl4030_codec_data *twl_codec = pdev->dev.platform_data;
- struct snd_soc_codec *codec;
+ struct twl4030_codec_data *twl_codec = codec->dev->platform_data;
struct twl6040_data *priv;
int audpwron, naudint;
int ret = 0;
@@ -1092,6 +1022,7 @@ static int __devinit twl6040_codec_probe(struct platform_device *pdev)
priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
+ snd_soc_codec_set_drvdata(codec, priv);
if (twl_codec) {
audpwron = twl_codec->audpwron_gpio;
@@ -1104,29 +1035,6 @@ static int __devinit twl6040_codec_probe(struct platform_device *pdev)
priv->audpwron = audpwron;
priv->naudint = naudint;
- codec = &priv->codec;
- codec->dev = &pdev->dev;
- twl6040_dai.dev = &pdev->dev;
-
- codec->name = "twl6040";
- codec->owner = THIS_MODULE;
- codec->read = twl6040_read_reg_cache;
- codec->write = twl6040_write;
- codec->set_bias_level = twl6040_set_bias_level;
- snd_soc_codec_set_drvdata(codec, priv);
- codec->dai = &twl6040_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(twl6040_reg);
- codec->reg_cache = kmemdup(twl6040_reg, sizeof(twl6040_reg),
- GFP_KERNEL);
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto cache_err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
init_completion(&priv->ready);
if (gpio_is_valid(audpwron)) {
@@ -1169,23 +1077,12 @@ static int __devinit twl6040_codec_probe(struct platform_device *pdev)
if (ret)
goto irq_err;
- ret = snd_soc_register_codec(codec);
- if (ret)
- goto reg_err;
-
- twl6040_codec = codec;
-
- ret = snd_soc_register_dai(&twl6040_dai);
- if (ret)
- goto dai_err;
+ snd_soc_add_controls(codec, twl6040_snd_controls,
+ ARRAY_SIZE(twl6040_snd_controls));
+ twl6040_add_widgets(codec);
return 0;
-dai_err:
- snd_soc_unregister_codec(codec);
- twl6040_codec = NULL;
-reg_err:
- twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
irq_err:
if (naudint)
free_irq(naudint, codec);
@@ -1193,36 +1090,57 @@ gpio2_err:
if (gpio_is_valid(audpwron))
gpio_free(audpwron);
gpio1_err:
- kfree(codec->reg_cache);
-cache_err:
kfree(priv);
return ret;
}
-static int __devexit twl6040_codec_remove(struct platform_device *pdev)
+static int twl6040_remove(struct snd_soc_codec *codec)
{
- struct twl6040_data *priv = snd_soc_codec_get_drvdata(twl6040_codec);
+ struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
int audpwron = priv->audpwron;
int naudint = priv->naudint;
+ twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
if (gpio_is_valid(audpwron))
gpio_free(audpwron);
if (naudint)
- free_irq(naudint, twl6040_codec);
+ free_irq(naudint, codec);
- snd_soc_unregister_dai(&twl6040_dai);
- snd_soc_unregister_codec(twl6040_codec);
+ kfree(priv);
- kfree(twl6040_codec);
- twl6040_codec = NULL;
+ return 0;
+}
+static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
+ .probe = twl6040_probe,
+ .remove = twl6040_remove,
+ .suspend = twl6040_suspend,
+ .resume = twl6040_resume,
+ .read = twl6040_read_reg_cache,
+ .write = twl6040_write,
+ .set_bias_level = twl6040_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(twl6040_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = twl6040_reg,
+};
+
+static int __devinit twl6040_codec_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_twl6040, &twl6040_dai, 1);
+}
+
+static int __devexit twl6040_codec_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static struct platform_driver twl6040_codec_driver = {
.driver = {
- .name = "twl6040_codec",
+ .name = "twl6040-codec",
.owner = THIS_MODULE,
},
.probe = twl6040_codec_probe,
diff --git a/sound/soc/codecs/twl6040.h b/sound/soc/codecs/twl6040.h
index c472070a1da2..f7c77fa58a3c 100644
--- a/sound/soc/codecs/twl6040.h
+++ b/sound/soc/codecs/twl6040.h
@@ -135,7 +135,4 @@
#define TWL6040_HPPLL_ID 1
#define TWL6040_LPPLL_ID 2
-extern struct snd_soc_dai twl6040_dai;
-extern struct snd_soc_codec_device soc_codec_dev_twl6040;
-
#endif /* End of __TWL6040_H__ */
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index f3b4c1d6a82d..7540a509a6f5 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -161,8 +161,7 @@ static int uda134x_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec =rtd->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
struct snd_pcm_runtime *master_runtime;
@@ -194,8 +193,7 @@ static void uda134x_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
if (uda134x->master_substream == substream)
@@ -209,8 +207,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
u8 hw_params;
@@ -364,7 +361,7 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
pd->power(1);
/* Sync reg_cache with the hardware */
for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++)
- codec->write(codec, i, *cache++);
+ codec->driver->write(codec, i, *cache++);
}
break;
case SND_SOC_BIAS_STANDBY:
@@ -465,8 +462,8 @@ static struct snd_soc_dai_ops uda134x_dai_ops = {
.set_fmt = uda134x_set_dai_fmt,
};
-struct snd_soc_dai uda134x_dai = {
- .name = "UDA134X",
+static struct snd_soc_dai_driver uda134x_dai = {
+ .name = "uda134x-hifi",
/* playback capabilities */
.playback = {
.stream_name = "Playback",
@@ -486,27 +483,21 @@ struct snd_soc_dai uda134x_dai = {
/* pcm operations */
.ops = &uda134x_dai_ops,
};
-EXPORT_SYMBOL(uda134x_dai);
-
-static int uda134x_soc_probe(struct platform_device *pdev)
+static int uda134x_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
struct uda134x_priv *uda134x;
- void *codec_setup_data = socdev->codec_data;
- int ret = -ENOMEM;
- struct uda134x_platform_data *pd;
+ struct uda134x_platform_data *pd = dev_get_drvdata(codec->card->dev);
+ int ret;
printk(KERN_INFO "UDA134X SoC Audio Codec\n");
- if (!codec_setup_data) {
+ if (!pd) {
printk(KERN_ERR "UDA134X SoC codec: "
"missing L3 bitbang function\n");
return -ENODEV;
}
- pd = codec_setup_data;
switch (pd->model) {
case UDA134X_UDA1340:
case UDA134X_UDA1341:
@@ -520,58 +511,22 @@ static int uda134x_soc_probe(struct platform_device *pdev)
return -EINVAL;
}
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (socdev->card->codec == NULL)
- return ret;
-
- codec = socdev->card->codec;
-
uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL);
if (uda134x == NULL)
- goto priv_err;
+ return -ENOMEM;
snd_soc_codec_set_drvdata(codec, uda134x);
- codec->reg_cache = kmemdup(uda134x_reg, sizeof(uda134x_reg),
- GFP_KERNEL);
- if (codec->reg_cache == NULL)
- goto reg_err;
-
- mutex_init(&codec->mutex);
-
- codec->reg_cache_size = sizeof(uda134x_reg);
- codec->reg_cache_step = 1;
-
- codec->name = "UDA134X";
- codec->owner = THIS_MODULE;
- codec->dai = &uda134x_dai;
- codec->num_dai = 1;
- codec->read = uda134x_read_reg_cache;
- codec->write = uda134x_write;
-
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->control_data = codec_setup_data;
+ codec->control_data = pd;
if (pd->power)
pd->power(1);
uda134x_reset(codec);
- if (pd->is_powered_on_standby) {
- codec->set_bias_level = NULL;
+ if (pd->is_powered_on_standby)
uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
- } else {
- codec->set_bias_level = uda134x_set_bias_level;
+ else
uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- }
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "UDA134X: failed to register pcms\n");
- goto pcm_err;
- }
switch (pd->model) {
case UDA134X_UDA1340:
@@ -590,61 +545,42 @@ static int uda134x_soc_probe(struct platform_device *pdev)
default:
printk(KERN_ERR "%s unknown codec type: %d",
__func__, pd->model);
- return -EINVAL;
+ kfree(uda134x);
+ return -EINVAL;
}
if (ret < 0) {
printk(KERN_ERR "UDA134X: failed to register controls\n");
- goto pcm_err;
+ kfree(uda134x);
+ return ret;
}
return 0;
-
-pcm_err:
- kfree(codec->reg_cache);
-reg_err:
- kfree(snd_soc_codec_get_drvdata(codec));
-priv_err:
- kfree(codec);
- return ret;
}
/* power down chip */
-static int uda134x_soc_remove(struct platform_device *pdev)
+static int uda134x_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec->reg_cache);
- kfree(codec);
-
+ kfree(uda134x);
return 0;
}
#if defined(CONFIG_PM)
-static int uda134x_soc_suspend(struct platform_device *pdev,
+static int uda134x_soc_suspend(struct snd_soc_codec *codec,
pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int uda134x_soc_resume(struct platform_device *pdev)
+static int uda134x_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
return 0;
@@ -654,25 +590,53 @@ static int uda134x_soc_resume(struct platform_device *pdev)
#define uda134x_soc_resume NULL
#endif /* CONFIG_PM */
-struct snd_soc_codec_device soc_codec_dev_uda134x = {
+static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
.probe = uda134x_soc_probe,
.remove = uda134x_soc_remove,
.suspend = uda134x_soc_suspend,
.resume = uda134x_soc_resume,
+ .reg_cache_size = sizeof(uda134x_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_step = 1,
+ .read = uda134x_read_reg_cache,
+ .write = uda134x_write,
+#ifdef POWER_OFF_ON_STANDBY
+ .set_bias_level = uda134x_set_bias_level,
+#endif
+};
+
+static int __devinit uda134x_codec_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_uda134x, &uda134x_dai, 1);
+}
+
+static int __devexit uda134x_codec_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver uda134x_codec_driver = {
+ .driver = {
+ .name = "uda134x-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = uda134x_codec_probe,
+ .remove = __devexit_p(uda134x_codec_remove),
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x);
-static int __init uda134x_init(void)
+static int __init uda134x_codec_init(void)
{
- return snd_soc_register_dai(&uda134x_dai);
+ return platform_driver_register(&uda134x_codec_driver);
}
-module_init(uda134x_init);
+module_init(uda134x_codec_init);
-static void __exit uda134x_exit(void)
+static void __exit uda134x_codec_exit(void)
{
- snd_soc_unregister_dai(&uda134x_dai);
+ platform_driver_unregister(&uda134x_codec_driver);
}
-module_exit(uda134x_exit);
+module_exit(uda134x_codec_exit);
MODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h
index 205f03b3eaf8..9faae06972b3 100644
--- a/sound/soc/codecs/uda134x.h
+++ b/sound/soc/codecs/uda134x.h
@@ -31,7 +31,4 @@
#define STATUS0_DAIFMT_MASK (~(7<<1))
#define STATUS0_SYSCLK_MASK (~(3<<4))
-extern struct snd_soc_dai uda134x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_uda134x;
-
#endif
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 2f925a27dcde..0c6c725736c6 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -33,14 +33,13 @@
#include "uda1380.h"
-static struct snd_soc_codec *uda1380_codec;
-
/* codec private data */
struct uda1380_priv {
- struct snd_soc_codec codec;
+ struct snd_soc_codec *codec;
u16 reg_cache[UDA1380_CACHEREGNUM];
unsigned int dac_clk;
struct work_struct work;
+ void *control_data;
};
/*
@@ -131,10 +130,51 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
return -EIO;
}
-#define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0)
+static void uda1380_sync_cache(struct snd_soc_codec *codec)
+{
+ int reg;
+ u8 data[3];
+ u16 *cache = codec->reg_cache;
+
+ /* Sync reg_cache with the hardware */
+ for (reg = 0; reg < UDA1380_MVOL; reg++) {
+ data[0] = reg;
+ data[1] = (cache[reg] & 0xff00) >> 8;
+ data[2] = cache[reg] & 0x00ff;
+ if (codec->hw_write(codec->control_data, data, 3) != 3)
+ dev_err(codec->dev, "%s: write to reg 0x%x failed\n",
+ __func__, reg);
+ }
+}
+
+static int uda1380_reset(struct snd_soc_codec *codec)
+{
+ struct uda1380_platform_data *pdata = codec->dev->platform_data;
+
+ if (gpio_is_valid(pdata->gpio_reset)) {
+ gpio_set_value(pdata->gpio_reset, 1);
+ mdelay(1);
+ gpio_set_value(pdata->gpio_reset, 0);
+ } else {
+ u8 data[3];
+
+ data[0] = UDA1380_RESET;
+ data[1] = 0;
+ data[2] = 0;
+
+ if (codec->hw_write(codec->control_data, data, 3) != 3) {
+ dev_err(codec->dev, "%s: failed\n", __func__);
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
static void uda1380_flush_work(struct work_struct *work)
{
+ struct uda1380_priv *uda1380 = container_of(work, struct uda1380_priv, work);
+ struct snd_soc_codec *uda1380_codec = uda1380->codec;
int bit, reg;
for_each_set_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) {
@@ -145,6 +185,7 @@ static void uda1380_flush_work(struct work_struct *work)
uda1380_read_reg_cache(uda1380_codec, reg));
clear_bit(bit, &uda1380_cache_dirty);
}
+
}
/* declarations of ALSA reg_elem_REAL controls */
@@ -474,8 +515,7 @@ static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
@@ -501,8 +541,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
/* set WSPLL power and divider if running from this clock */
@@ -540,8 +579,7 @@ static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
/* shut down WSPLL power if running from this clock */
@@ -562,18 +600,41 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
int pm = uda1380_read_reg_cache(codec, UDA1380_PM);
+ int reg;
+ struct uda1380_platform_data *pdata = codec->dev->platform_data;
+
+ if (codec->bias_level == level)
+ return 0;
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
+ /* ADC, DAC on */
uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm);
break;
case SND_SOC_BIAS_STANDBY:
- uda1380_write(codec, UDA1380_PM, R02_PON_BIAS);
- break;
- case SND_SOC_BIAS_OFF:
+ if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ if (gpio_is_valid(pdata->gpio_power)) {
+ gpio_set_value(pdata->gpio_power, 1);
+ mdelay(1);
+ uda1380_reset(codec);
+ }
+
+ uda1380_sync_cache(codec);
+ }
uda1380_write(codec, UDA1380_PM, 0x0);
break;
+ case SND_SOC_BIAS_OFF:
+ if (!gpio_is_valid(pdata->gpio_power))
+ break;
+
+ gpio_set_value(pdata->gpio_power, 0);
+
+ /* Mark mixer regs cache dirty to sync them with
+ * codec regs on power on.
+ */
+ for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; reg++)
+ set_bit(reg - 0x10, &uda1380_cache_dirty);
}
codec->bias_level = level;
return 0;
@@ -604,9 +665,9 @@ static struct snd_soc_dai_ops uda1380_dai_ops_capture = {
.set_fmt = uda1380_set_dai_fmt_capture,
};
-struct snd_soc_dai uda1380_dai[] = {
+static struct snd_soc_dai_driver uda1380_dai[] = {
{
- .name = "UDA1380",
+ .name = "uda1380-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -622,7 +683,7 @@ struct snd_soc_dai uda1380_dai[] = {
.ops = &uda1380_dai_ops,
},
{ /* playback only - dual interface */
- .name = "UDA1380",
+ .name = "uda1380-hifi-playback",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -633,7 +694,7 @@ struct snd_soc_dai uda1380_dai[] = {
.ops = &uda1380_dai_ops_playback,
},
{ /* capture only - dual interface*/
- .name = "UDA1380",
+ .name = "uda1380-hifi-capture",
.capture = {
.stream_name = "Capture",
.channels_min = 1,
@@ -644,67 +705,69 @@ struct snd_soc_dai uda1380_dai[] = {
.ops = &uda1380_dai_ops_capture,
},
};
-EXPORT_SYMBOL_GPL(uda1380_dai);
-static int uda1380_suspend(struct platform_device *pdev, pm_message_t state)
+static int uda1380_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int uda1380_resume(struct platform_device *pdev)
+static int uda1380_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- int i;
- u8 data[2];
- u16 *cache = codec->reg_cache;
-
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(uda1380_reg); i++) {
- data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
- data[1] = cache[i] & 0x00ff;
- codec->hw_write(codec->control_data, data, 2);
- }
uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-static int uda1380_probe(struct platform_device *pdev)
+static int uda1380_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct uda1380_platform_data *pdata;
- int ret = 0;
+ struct uda1380_platform_data *pdata =codec->dev->platform_data;
+ struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
+ int ret;
- if (uda1380_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
+ uda1380->codec = codec;
+
+ codec->hw_write = (hw_write_t)i2c_master_send;
+ codec->control_data = uda1380->control_data;
+
+ if (!pdata)
+ return -EINVAL;
- socdev->card->codec = uda1380_codec;
- codec = uda1380_codec;
- pdata = codec->dev->platform_data;
+ if (gpio_is_valid(pdata->gpio_reset)) {
+ ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
+ if (ret)
+ goto err_out;
+ ret = gpio_direction_output(pdata->gpio_reset, 0);
+ if (ret)
+ goto err_gpio_reset_conf;
+ }
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
+ if (gpio_is_valid(pdata->gpio_power)) {
+ ret = gpio_request(pdata->gpio_power, "uda1380 power");
+ if (ret)
+ goto err_gpio;
+ ret = gpio_direction_output(pdata->gpio_power, 0);
+ if (ret)
+ goto err_gpio_power_conf;
+ } else {
+ ret = uda1380_reset(codec);
+ if (ret) {
+ dev_err(codec->dev, "Failed to issue reset\n");
+ goto err_reset;
+ }
}
+ INIT_WORK(&uda1380->work, uda1380_flush_work);
+
/* power on device */
uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* set clock input */
switch (pdata->dac_clk) {
case UDA1380_DAC_CLK_SYSCLK:
- uda1380_write(codec, UDA1380_CLK, 0);
+ uda1380_write_reg_cache(codec, UDA1380_CLK, 0);
break;
case UDA1380_DAC_CLK_WSPLL:
- uda1380_write(codec, UDA1380_CLK, R00_DAC_CLK);
+ uda1380_write_reg_cache(codec, UDA1380_CLK,
+ R00_DAC_CLK);
break;
}
@@ -712,167 +775,73 @@ static int uda1380_probe(struct platform_device *pdev)
ARRAY_SIZE(uda1380_snd_controls));
uda1380_add_widgets(codec);
- return ret;
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int uda1380_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_uda1380 = {
- .probe = uda1380_probe,
- .remove = uda1380_remove,
- .suspend = uda1380_suspend,
- .resume = uda1380_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380);
-
-static int uda1380_register(struct uda1380_priv *uda1380)
-{
- int ret, i;
- struct snd_soc_codec *codec = &uda1380->codec;
- struct uda1380_platform_data *pdata = codec->dev->platform_data;
-
- if (uda1380_codec) {
- dev_err(codec->dev, "Another UDA1380 is registered\n");
- return -EINVAL;
- }
-
- if (!pdata || !pdata->gpio_power || !pdata->gpio_reset)
- return -EINVAL;
-
- ret = gpio_request(pdata->gpio_power, "uda1380 power");
- if (ret)
- goto err_out;
- ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
- if (ret)
- goto err_gpio;
-
- gpio_direction_output(pdata->gpio_power, 1);
-
- /* we may need to have the clock running here - pH5 */
- gpio_direction_output(pdata->gpio_reset, 1);
- udelay(5);
- gpio_set_value(pdata->gpio_reset, 0);
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, uda1380);
- codec->name = "UDA1380";
- codec->owner = THIS_MODULE;
- codec->read = uda1380_read_reg_cache;
- codec->write = uda1380_write;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = uda1380_set_bias_level;
- codec->dai = uda1380_dai;
- codec->num_dai = ARRAY_SIZE(uda1380_dai);
- codec->reg_cache_size = ARRAY_SIZE(uda1380_reg);
- codec->reg_cache = &uda1380->reg_cache;
- codec->reg_cache_step = 1;
-
- memcpy(codec->reg_cache, uda1380_reg, sizeof(uda1380_reg));
-
- ret = uda1380_reset(codec);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to issue reset\n");
- goto err_reset;
- }
-
- INIT_WORK(&uda1380->work, uda1380_flush_work);
- for (i = 0; i < ARRAY_SIZE(uda1380_dai); i++)
- uda1380_dai[i].dev = codec->dev;
-
- uda1380_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_reset;
- }
-
- ret = snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
- goto err_dai;
- }
-
- return 0;
-
-err_dai:
- snd_soc_unregister_codec(codec);
err_reset:
- gpio_set_value(pdata->gpio_power, 0);
- gpio_free(pdata->gpio_reset);
+err_gpio_power_conf:
+ if (gpio_is_valid(pdata->gpio_power))
+ gpio_free(pdata->gpio_power);
+
+err_gpio_reset_conf:
err_gpio:
- gpio_free(pdata->gpio_power);
+ if (gpio_is_valid(pdata->gpio_reset))
+ gpio_free(pdata->gpio_reset);
err_out:
return ret;
}
-static void uda1380_unregister(struct uda1380_priv *uda1380)
+/* power down chip */
+static int uda1380_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = &uda1380->codec;
- struct uda1380_platform_data *pdata = codec->dev->platform_data;
+ struct uda1380_platform_data *pdata =codec->dev->platform_data;
- snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
- snd_soc_unregister_codec(&uda1380->codec);
+ uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
- gpio_set_value(pdata->gpio_power, 0);
gpio_free(pdata->gpio_reset);
gpio_free(pdata->gpio_power);
- kfree(uda1380);
- uda1380_codec = NULL;
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
+ .probe = uda1380_probe,
+ .remove = uda1380_remove,
+ .suspend = uda1380_suspend,
+ .resume = uda1380_resume,
+ .read = uda1380_read_reg_cache,
+ .write = uda1380_write,
+ .set_bias_level = uda1380_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(uda1380_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = uda1380_reg,
+ .reg_cache_step = 1,
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int uda1380_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct uda1380_priv *uda1380;
- struct snd_soc_codec *codec;
int ret;
uda1380 = kzalloc(sizeof(struct uda1380_priv), GFP_KERNEL);
if (uda1380 == NULL)
return -ENOMEM;
- codec = &uda1380->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
i2c_set_clientdata(i2c, uda1380);
- codec->control_data = i2c;
+ uda1380->control_data = i2c;
- codec->dev = &i2c->dev;
-
- ret = uda1380_register(uda1380);
- if (ret != 0)
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai));
+ if (ret < 0)
kfree(uda1380);
-
return ret;
}
static int __devexit uda1380_i2c_remove(struct i2c_client *i2c)
{
- struct uda1380_priv *uda1380 = i2c_get_clientdata(i2c);
- uda1380_unregister(uda1380);
+ snd_soc_unregister_codec(&i2c->dev);
+ kfree(i2c_get_clientdata(i2c));
return 0;
}
@@ -884,7 +853,7 @@ MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id);
static struct i2c_driver uda1380_i2c_driver = {
.driver = {
- .name = "UDA1380 I2C Codec",
+ .name = "uda1380-codec",
.owner = THIS_MODULE,
},
.probe = uda1380_i2c_probe,
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h
index 9cefa8a54770..942e3927c72b 100644
--- a/sound/soc/codecs/uda1380.h
+++ b/sound/soc/codecs/uda1380.h
@@ -76,7 +76,4 @@
#define UDA1380_DAI_PLAYBACK 1 /* playback DAI */
#define UDA1380_DAI_CAPTURE 2 /* capture DAI */
-extern struct snd_soc_dai uda1380_dai[3];
-extern struct snd_soc_codec_device soc_codec_dev_uda1380;
-
#endif /* _UDA1380_H */
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
new file mode 100644
index 000000000000..0c47c788ccdf
--- /dev/null
+++ b/sound/soc/codecs/wl1273.c
@@ -0,0 +1,528 @@
+/*
+ * ALSA SoC WL1273 codec driver
+ *
+ * Author: Matti Aaltonen, <matti.j.aaltonen@nokia.com>
+ *
+ * Copyright: (C) 2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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/mfd/wl1273-core.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wl1273.h"
+
+enum wl1273_mode { WL1273_MODE_BT, WL1273_MODE_FM_RX, WL1273_MODE_FM_TX };
+
+/* codec private data */
+struct wl1273_priv {
+ enum wl1273_mode mode;
+ struct wl1273_core *core;
+ unsigned int channels;
+};
+
+static int snd_wl1273_fm_set_i2s_mode(struct wl1273_core *core,
+ int rate, int width)
+{
+ struct device *dev = &core->i2c_dev->dev;
+ int r = 0;
+ u16 mode;
+
+ dev_dbg(dev, "rate: %d\n", rate);
+ dev_dbg(dev, "width: %d\n", width);
+
+ mutex_lock(&core->lock);
+
+ mode = core->i2s_mode & ~WL1273_IS2_WIDTH & ~WL1273_IS2_RATE;
+
+ switch (rate) {
+ case 48000:
+ mode |= WL1273_IS2_RATE_48K;
+ break;
+ case 44100:
+ mode |= WL1273_IS2_RATE_44_1K;
+ break;
+ case 32000:
+ mode |= WL1273_IS2_RATE_32K;
+ break;
+ case 22050:
+ mode |= WL1273_IS2_RATE_22_05K;
+ break;
+ case 16000:
+ mode |= WL1273_IS2_RATE_16K;
+ break;
+ case 12000:
+ mode |= WL1273_IS2_RATE_12K;
+ break;
+ case 11025:
+ mode |= WL1273_IS2_RATE_11_025;
+ break;
+ case 8000:
+ mode |= WL1273_IS2_RATE_8K;
+ break;
+ default:
+ dev_err(dev, "Sampling rate: %d not supported\n", rate);
+ r = -EINVAL;
+ goto out;
+ }
+
+ switch (width) {
+ case 16:
+ mode |= WL1273_IS2_WIDTH_32;
+ break;
+ case 20:
+ mode |= WL1273_IS2_WIDTH_40;
+ break;
+ case 24:
+ mode |= WL1273_IS2_WIDTH_48;
+ break;
+ case 25:
+ mode |= WL1273_IS2_WIDTH_50;
+ break;
+ case 30:
+ mode |= WL1273_IS2_WIDTH_60;
+ break;
+ case 32:
+ mode |= WL1273_IS2_WIDTH_64;
+ break;
+ case 40:
+ mode |= WL1273_IS2_WIDTH_80;
+ break;
+ case 48:
+ mode |= WL1273_IS2_WIDTH_96;
+ break;
+ case 64:
+ mode |= WL1273_IS2_WIDTH_128;
+ break;
+ default:
+ dev_err(dev, "Data width: %d not supported\n", width);
+ r = -EINVAL;
+ goto out;
+ }
+
+ dev_dbg(dev, "WL1273_I2S_DEF_MODE: 0x%04x\n", WL1273_I2S_DEF_MODE);
+ dev_dbg(dev, "core->i2s_mode: 0x%04x\n", core->i2s_mode);
+ dev_dbg(dev, "mode: 0x%04x\n", mode);
+
+ if (core->i2s_mode != mode) {
+ r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET, mode);
+ if (r)
+ goto out;
+
+ core->i2s_mode = mode;
+ r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
+ WL1273_AUDIO_ENABLE_I2S);
+ if (r)
+ goto out;
+ }
+out:
+ mutex_unlock(&core->lock);
+
+ return r;
+}
+
+static int snd_wl1273_fm_set_channel_number(struct wl1273_core *core,
+ int channel_number)
+{
+ struct i2c_client *client = core->i2c_dev;
+ struct device *dev = &client->dev;
+ int r = 0;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ mutex_lock(&core->lock);
+
+ if (core->channel_number == channel_number)
+ goto out;
+
+ if (channel_number == 1 && core->mode == WL1273_MODE_RX)
+ r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
+ WL1273_RX_MONO);
+ else if (channel_number == 1 && core->mode == WL1273_MODE_TX)
+ r = wl1273_fm_write_cmd(core, WL1273_MONO_SET,
+ WL1273_TX_MONO);
+ else if (channel_number == 2 && core->mode == WL1273_MODE_RX)
+ r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
+ WL1273_RX_STEREO);
+ else if (channel_number == 2 && core->mode == WL1273_MODE_TX)
+ r = wl1273_fm_write_cmd(core, WL1273_MONO_SET,
+ WL1273_TX_STEREO);
+ else
+ r = -EINVAL;
+out:
+ mutex_unlock(&core->lock);
+
+ return r;
+}
+
+static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = wl1273->mode;
+
+ return 0;
+}
+
+static const char *wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" };
+
+static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+ if (wl1273->mode == ucontrol->value.integer.value[0])
+ return 0;
+
+ /* Do not allow changes while stream is running */
+ if (codec->active)
+ return -EPERM;
+
+ if (ucontrol->value.integer.value[0] < 0 ||
+ ucontrol->value.integer.value[0] >= ARRAY_SIZE(wl1273_audio_route))
+ return -EINVAL;
+
+ wl1273->mode = ucontrol->value.integer.value[0];
+
+ return 1;
+}
+
+static const struct soc_enum wl1273_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_route), wl1273_audio_route);
+
+static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+ ucontrol->value.integer.value[0] = wl1273->core->audio_mode;
+
+ return 0;
+}
+
+static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+ int val, r = 0;
+
+ dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+ val = ucontrol->value.integer.value[0];
+ if (wl1273->core->audio_mode == val)
+ return 0;
+
+ r = wl1273_fm_set_audio(wl1273->core, val);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static const char *wl1273_audio_strings[] = { "Digital", "Analog" };
+
+static const struct soc_enum wl1273_audio_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_strings),
+ wl1273_audio_strings);
+
+static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+ ucontrol->value.integer.value[0] = wl1273->core->volume;
+
+ return 0;
+}
+
+static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+ int r;
+
+ dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+ r = wl1273_fm_set_volume(wl1273->core,
+ ucontrol->value.integer.value[0]);
+ if (r)
+ return r;
+
+ return 1;
+}
+
+static const struct snd_kcontrol_new wl1273_controls[] = {
+ SOC_ENUM_EXT("Codec Mode", wl1273_enum,
+ snd_wl1273_get_audio_route, snd_wl1273_set_audio_route),
+ SOC_ENUM_EXT("Audio Switch", wl1273_audio_enum,
+ snd_wl1273_fm_audio_get, snd_wl1273_fm_audio_put),
+ SOC_SINGLE_EXT("Volume", 0, 0, WL1273_MAX_VOLUME, 0,
+ snd_wl1273_fm_volume_get, snd_wl1273_fm_volume_put),
+};
+
+static int wl1273_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+ switch (wl1273->mode) {
+ case WL1273_MODE_BT:
+ snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_RATE,
+ 8000, 8000);
+ snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS, 1, 1);
+ break;
+ case WL1273_MODE_FM_RX:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_err("Cannot play in RX mode.\n");
+ return -EINVAL;
+ }
+ break;
+ case WL1273_MODE_FM_TX:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ pr_err("Cannot capture in TX mode.\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+static int wl1273_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(rtd->codec);
+ struct wl1273_core *core = wl1273->core;
+ unsigned int rate, width, r;
+
+ if (params_format(params) != SNDRV_PCM_FORMAT_S16_LE) {
+ pr_err("Only SNDRV_PCM_FORMAT_S16_LE supported.\n");
+ return -EINVAL;
+ }
+
+ rate = params_rate(params);
+ width = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
+
+ if (wl1273->mode == WL1273_MODE_BT) {
+ if (rate != 8000) {
+ pr_err("Rate %d not supported.\n", params_rate(params));
+ return -EINVAL;
+ }
+
+ if (params_channels(params) != 1) {
+ pr_err("Only mono supported.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+ }
+
+ if (wl1273->mode == WL1273_MODE_FM_TX &&
+ substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ pr_err("Only playback supported with TX.\n");
+ return -EINVAL;
+ }
+
+ if (wl1273->mode == WL1273_MODE_FM_RX &&
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_err("Only capture supported with RX.\n");
+ return -EINVAL;
+ }
+
+ if (wl1273->mode != WL1273_MODE_FM_RX &&
+ wl1273->mode != WL1273_MODE_FM_TX) {
+ pr_err("Unexpected mode: %d.\n", wl1273->mode);
+ return -EINVAL;
+ }
+
+ r = snd_wl1273_fm_set_i2s_mode(core, rate, width);
+ if (r)
+ return r;
+
+ wl1273->channels = params_channels(params);
+ r = snd_wl1273_fm_set_channel_number(core, wl1273->channels);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops wl1273_dai_ops = {
+ .startup = wl1273_startup,
+ .hw_params = wl1273_hw_params,
+};
+
+static struct snd_soc_dai_driver wl1273_dai = {
+ .name = "wl1273-fm",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE},
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE},
+ .ops = &wl1273_dai_ops,
+};
+
+/* Audio interface format for the soc_card driver */
+int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt)
+{
+ struct wl1273_priv *wl1273;
+
+ if (codec == NULL || fmt == NULL)
+ return -EINVAL;
+
+ wl1273 = snd_soc_codec_get_drvdata(codec);
+
+ switch (wl1273->mode) {
+ case WL1273_MODE_FM_RX:
+ case WL1273_MODE_FM_TX:
+ *fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM;
+
+ break;
+ case WL1273_MODE_BT:
+ *fmt = SND_SOC_DAIFMT_DSP_A |
+ SND_SOC_DAIFMT_IB_NF |
+ SND_SOC_DAIFMT_CBM_CFM;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wl1273_get_format);
+
+static int wl1273_probe(struct snd_soc_codec *codec)
+{
+ struct wl1273_core **core = codec->dev->platform_data;
+ struct wl1273_priv *wl1273;
+ int r;
+
+ dev_dbg(codec->dev, "%s.\n", __func__);
+
+ if (!core) {
+ dev_err(codec->dev, "Platform data is missing.\n");
+ return -EINVAL;
+ }
+
+ wl1273 = kzalloc(sizeof(struct wl1273_priv), GFP_KERNEL);
+ if (wl1273 == NULL) {
+ dev_err(codec->dev, "Cannot allocate memory.\n");
+ return -ENOMEM;
+ }
+
+ wl1273->mode = WL1273_MODE_BT;
+ wl1273->core = *core;
+
+ snd_soc_codec_set_drvdata(codec, wl1273);
+ mutex_init(&codec->mutex);
+
+ r = snd_soc_add_controls(codec, wl1273_controls,
+ ARRAY_SIZE(wl1273_controls));
+ if (r)
+ kfree(wl1273);
+
+ return r;
+}
+
+static int wl1273_remove(struct snd_soc_codec *codec)
+{
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s\n", __func__);
+ kfree(wl1273);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wl1273 = {
+ .probe = wl1273_probe,
+ .remove = wl1273_remove,
+};
+
+static int __devinit wl1273_platform_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wl1273,
+ &wl1273_dai, 1);
+}
+
+static int __devexit wl1273_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+MODULE_ALIAS("platform:wl1273-codec");
+
+static struct platform_driver wl1273_platform_driver = {
+ .driver = {
+ .name = "wl1273-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = wl1273_platform_probe,
+ .remove = __devexit_p(wl1273_platform_remove),
+};
+
+static int __init wl1273_init(void)
+{
+ return platform_driver_register(&wl1273_platform_driver);
+}
+module_init(wl1273_init);
+
+static void __exit wl1273_exit(void)
+{
+ platform_driver_unregister(&wl1273_platform_driver);
+}
+module_exit(wl1273_exit);
+
+MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>");
+MODULE_DESCRIPTION("ASoC WL1273 codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wl1273.h b/sound/soc/codecs/wl1273.h
new file mode 100644
index 000000000000..14ed027fdcfc
--- /dev/null
+++ b/sound/soc/codecs/wl1273.h
@@ -0,0 +1,101 @@
+/*
+ * sound/soc/codec/wl1273.h
+ *
+ * ALSA SoC WL1273 codec driver
+ *
+ * Copyright (C) Nokia Corporation
+ * Author: Matti Aaltonen <matti.j.aaltonen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1273_CODEC_H__
+#define __WL1273_CODEC_H__
+
+/* I2S protocol, left channel first, data width 16 bits */
+#define WL1273_PCM_DEF_MODE 0x00
+
+/* Rx */
+#define WL1273_AUDIO_ENABLE_I2S (1 << 0)
+#define WL1273_AUDIO_ENABLE_ANALOG (1 << 1)
+
+/* Tx */
+#define WL1273_AUDIO_IO_SET_ANALOG 0
+#define WL1273_AUDIO_IO_SET_I2S 1
+
+#define WL1273_POWER_SET_OFF 0
+#define WL1273_POWER_SET_FM (1 << 0)
+#define WL1273_POWER_SET_RDS (1 << 1)
+#define WL1273_POWER_SET_RETENTION (1 << 4)
+
+#define WL1273_PUPD_SET_OFF 0x00
+#define WL1273_PUPD_SET_ON 0x01
+#define WL1273_PUPD_SET_RETENTION 0x10
+
+/* I2S mode */
+#define WL1273_IS2_WIDTH_32 0x0
+#define WL1273_IS2_WIDTH_40 0x1
+#define WL1273_IS2_WIDTH_22_23 0x2
+#define WL1273_IS2_WIDTH_23_22 0x3
+#define WL1273_IS2_WIDTH_48 0x4
+#define WL1273_IS2_WIDTH_50 0x5
+#define WL1273_IS2_WIDTH_60 0x6
+#define WL1273_IS2_WIDTH_64 0x7
+#define WL1273_IS2_WIDTH_80 0x8
+#define WL1273_IS2_WIDTH_96 0x9
+#define WL1273_IS2_WIDTH_128 0xa
+#define WL1273_IS2_WIDTH 0xf
+
+#define WL1273_IS2_FORMAT_STD (0x0 << 4)
+#define WL1273_IS2_FORMAT_LEFT (0x1 << 4)
+#define WL1273_IS2_FORMAT_RIGHT (0x2 << 4)
+#define WL1273_IS2_FORMAT_USER (0x3 << 4)
+
+#define WL1273_IS2_MASTER (0x0 << 6)
+#define WL1273_IS2_SLAVEW (0x1 << 6)
+
+#define WL1273_IS2_TRI_AFTER_SENDING (0x0 << 7)
+#define WL1273_IS2_TRI_ALWAYS_ACTIVE (0x1 << 7)
+
+#define WL1273_IS2_SDOWS_RR (0x0 << 8)
+#define WL1273_IS2_SDOWS_RF (0x1 << 8)
+#define WL1273_IS2_SDOWS_FR (0x2 << 8)
+#define WL1273_IS2_SDOWS_FF (0x3 << 8)
+
+#define WL1273_IS2_TRI_OPT (0x0 << 10)
+#define WL1273_IS2_TRI_ALWAYS (0x1 << 10)
+
+#define WL1273_IS2_RATE_48K (0x0 << 12)
+#define WL1273_IS2_RATE_44_1K (0x1 << 12)
+#define WL1273_IS2_RATE_32K (0x2 << 12)
+#define WL1273_IS2_RATE_22_05K (0x4 << 12)
+#define WL1273_IS2_RATE_16K (0x5 << 12)
+#define WL1273_IS2_RATE_12K (0x8 << 12)
+#define WL1273_IS2_RATE_11_025 (0x9 << 12)
+#define WL1273_IS2_RATE_8K (0xa << 12)
+#define WL1273_IS2_RATE (0xf << 12)
+
+#define WL1273_I2S_DEF_MODE (WL1273_IS2_WIDTH_32 | \
+ WL1273_IS2_FORMAT_STD | \
+ WL1273_IS2_MASTER | \
+ WL1273_IS2_TRI_AFTER_SENDING | \
+ WL1273_IS2_SDOWS_RR | \
+ WL1273_IS2_TRI_OPT | \
+ WL1273_IS2_RATE_48K)
+
+int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt);
+
+#endif /* End of __WL1273_CODEC_H__ */
diff --git a/sound/soc/codecs/wm2000.h b/sound/soc/codecs/wm2000.h
index c18e261c3c7f..0b6f056f73cc 100644
--- a/sound/soc/codecs/wm2000.h
+++ b/sound/soc/codecs/wm2000.h
@@ -16,9 +16,6 @@ struct wm2000_setup_data {
extern int wm2000_add_controls(struct snd_soc_codec *codec);
-extern struct snd_soc_dai wm2000_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm2000;
-
#define WM2000_REG_SYS_START 0x8000
#define WM2000_REG_SPEECH_CLARITY 0x8fef
#define WM2000_REG_SYS_WATCHDOG 0x8ff6
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 0221ca79b3ae..f4f1fba38eb9 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -1321,20 +1321,14 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static int wm8350_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8350_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8350_resume(struct platform_device *pdev)
+static int wm8350_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -1489,24 +1483,74 @@ int wm8350_mic_jack_detect(struct snd_soc_codec *codec,
}
EXPORT_SYMBOL_GPL(wm8350_mic_jack_detect);
-static struct snd_soc_codec *wm8350_codec;
+#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000)
+
+#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8350_dai_ops = {
+ .hw_params = wm8350_pcm_hw_params,
+ .digital_mute = wm8350_mute,
+ .trigger = wm8350_pcm_trigger,
+ .set_fmt = wm8350_set_dai_fmt,
+ .set_sysclk = wm8350_set_dai_sysclk,
+ .set_pll = wm8350_set_fll,
+ .set_clkdiv = wm8350_set_clkdiv,
+};
+
+static struct snd_soc_dai_driver wm8350_dai = {
+ .name = "wm8350-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8350_RATES,
+ .formats = WM8350_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8350_RATES,
+ .formats = WM8350_FORMATS,
+ },
+ .ops = &wm8350_dai_ops,
+};
-static int wm8350_probe(struct platform_device *pdev)
+static int wm8350_codec_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct wm8350 *wm8350;
+ struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
struct wm8350_data *priv;
- int ret;
struct wm8350_output *out1;
struct wm8350_output *out2;
+ int ret, i;
- BUG_ON(!wm8350_codec);
+ if (wm8350->codec.platform_data == NULL) {
+ dev_err(codec->dev, "No audio platform data supplied\n");
+ return -EINVAL;
+ }
+
+ priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+ snd_soc_codec_set_drvdata(codec, priv);
+
+ for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+ priv->supplies[i].supply = supply_names[i];
+
+ ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
+ priv->supplies);
+ if (ret != 0)
+ goto err_priv;
+
+ wm8350->codec.codec = codec;
+ codec->control_data = wm8350;
- socdev->card->codec = wm8350_codec;
- codec = socdev->card->codec;
- wm8350 = codec->control_data;
- priv = snd_soc_codec_get_drvdata(codec);
+ /* Put the codec into reset if it wasn't already */
+ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
+
+ INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work);
/* Enable the codec */
wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
@@ -1557,11 +1601,6 @@ static int wm8350_probe(struct platform_device *pdev)
wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD,
wm8350_mic_handler, 0, "Microphone detect", priv);
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to create pcms\n");
- return ret;
- }
snd_soc_add_controls(codec, wm8350_snd_controls,
ARRAY_SIZE(wm8350_snd_controls));
@@ -1570,14 +1609,16 @@ static int wm8350_probe(struct platform_device *pdev)
wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
+
+err_priv:
+ kfree(priv);
+ return ret;
}
-static int wm8350_remove(struct platform_device *pdev)
+static int wm8350_codec_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- struct wm8350 *wm8350 = codec->control_data;
struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
+ struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
int ret;
wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
@@ -1607,134 +1648,30 @@ static int wm8350_remove(struct platform_device *pdev)
wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
+ regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
+ kfree(priv);
return 0;
}
-#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000)
-
-#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
- SNDRV_PCM_FMTBIT_S20_3LE |\
- SNDRV_PCM_FMTBIT_S24_LE)
-
-static struct snd_soc_dai_ops wm8350_dai_ops = {
- .hw_params = wm8350_pcm_hw_params,
- .digital_mute = wm8350_mute,
- .trigger = wm8350_pcm_trigger,
- .set_fmt = wm8350_set_dai_fmt,
- .set_sysclk = wm8350_set_dai_sysclk,
- .set_pll = wm8350_set_fll,
- .set_clkdiv = wm8350_set_clkdiv,
-};
-
-struct snd_soc_dai wm8350_dai = {
- .name = "WM8350",
- .playback = {
- .stream_name = "Playback",
- .channels_min = 1,
- .channels_max = 2,
- .rates = WM8350_RATES,
- .formats = WM8350_FORMATS,
- },
- .capture = {
- .stream_name = "Capture",
- .channels_min = 1,
- .channels_max = 2,
- .rates = WM8350_RATES,
- .formats = WM8350_FORMATS,
- },
- .ops = &wm8350_dai_ops,
-};
-EXPORT_SYMBOL_GPL(wm8350_dai);
-
-struct snd_soc_codec_device soc_codec_dev_wm8350 = {
- .probe = wm8350_probe,
- .remove = wm8350_remove,
+static struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
+ .probe = wm8350_codec_probe,
+ .remove = wm8350_codec_remove,
.suspend = wm8350_suspend,
.resume = wm8350_resume,
+ .read = wm8350_codec_read,
+ .write = wm8350_codec_write,
+ .set_bias_level = wm8350_set_bias_level,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8350);
-static __devinit int wm8350_codec_probe(struct platform_device *pdev)
+static int __devinit wm8350_probe(struct platform_device *pdev)
{
- struct wm8350 *wm8350 = platform_get_drvdata(pdev);
- struct wm8350_data *priv;
- struct snd_soc_codec *codec;
- int ret, i;
-
- if (wm8350->codec.platform_data == NULL) {
- dev_err(&pdev->dev, "No audio platform data supplied\n");
- return -EINVAL;
- }
-
- priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL);
- if (priv == NULL)
- return -ENOMEM;
-
- for (i = 0; i < ARRAY_SIZE(supply_names); i++)
- priv->supplies[i].supply = supply_names[i];
-
- ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
- priv->supplies);
- if (ret != 0)
- goto err_priv;
-
- codec = &priv->codec;
- wm8350->codec.codec = codec;
-
- wm8350_dai.dev = &pdev->dev;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
- codec->dev = &pdev->dev;
- codec->name = "WM8350";
- codec->owner = THIS_MODULE;
- codec->read = wm8350_codec_read;
- codec->write = wm8350_codec_write;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8350_set_bias_level;
- codec->dai = &wm8350_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8350_MAX_REGISTER;
- snd_soc_codec_set_drvdata(codec, priv);
- codec->control_data = wm8350;
-
- /* Put the codec into reset if it wasn't already */
- wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
-
- INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work);
- ret = snd_soc_register_codec(codec);
- if (ret != 0)
- goto err_supply;
-
- wm8350_codec = codec;
-
- ret = snd_soc_register_dai(&wm8350_dai);
- if (ret != 0)
- goto err_codec;
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err_supply:
- regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
-err_priv:
- kfree(priv);
- wm8350_codec = NULL;
- return ret;
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8350,
+ &wm8350_dai, 1);
}
-static int __devexit wm8350_codec_remove(struct platform_device *pdev)
+static int __devexit wm8350_remove(struct platform_device *pdev)
{
- struct wm8350 *wm8350 = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = wm8350->codec.codec;
- struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
-
- snd_soc_unregister_dai(&wm8350_dai);
- snd_soc_unregister_codec(codec);
- regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
- kfree(priv);
- wm8350_codec = NULL;
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
@@ -1743,8 +1680,8 @@ static struct platform_driver wm8350_codec_driver = {
.name = "wm8350-codec",
.owner = THIS_MODULE,
},
- .probe = wm8350_codec_probe,
- .remove = __devexit_p(wm8350_codec_remove),
+ .probe = wm8350_probe,
+ .remove = __devexit_p(wm8350_remove),
};
static __init int wm8350_init(void)
diff --git a/sound/soc/codecs/wm8350.h b/sound/soc/codecs/wm8350.h
index 9ed0467c71db..74108eb82938 100644
--- a/sound/soc/codecs/wm8350.h
+++ b/sound/soc/codecs/wm8350.h
@@ -15,9 +15,6 @@
#include <sound/soc.h>
#include <linux/mfd/wm8350/audio.h>
-extern struct snd_soc_dai wm8350_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8350;
-
enum wm8350_jack {
WM8350_JDL = 1,
WM8350_JDR = 2,
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 8f294066b0ed..850299786e02 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -65,7 +65,7 @@ static struct regulator_bulk_data power[] = {
/* codec private data */
struct wm8400_priv {
- struct snd_soc_codec codec;
+ struct snd_soc_codec *codec;
struct wm8400 *wm8400;
u16 fake_register;
unsigned int sysclk;
@@ -1163,8 +1163,7 @@ static int wm8400_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
audio1 &= ~WM8400_AIF_WL_MASK;
@@ -1332,10 +1331,9 @@ static struct snd_soc_dai_ops wm8400_dai_ops = {
* 1. ADC/DAC on Primary Interface
* 2. ADC on Primary Interface/DAC on secondary
*/
-struct snd_soc_dai wm8400_dai = {
+static struct snd_soc_dai_driver wm8400_dai = {
/* ADC/DAC on primary */
- .name = "WM8400 ADC/DAC Primary",
- .id = 1,
+ .name = "wm8400-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -1352,147 +1350,53 @@ struct snd_soc_dai wm8400_dai = {
},
.ops = &wm8400_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8400_dai);
-static int wm8400_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8400_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8400_resume(struct platform_device *pdev)
+static int wm8400_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-static struct snd_soc_codec *wm8400_codec;
-
-static int wm8400_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret;
-
- if (!wm8400_codec) {
- dev_err(&pdev->dev, "wm8400 not yet discovered\n");
- return -ENODEV;
- }
- codec = wm8400_codec;
-
- socdev->card->codec = codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to create pcms\n");
- goto pcm_err;
- }
-
- wm8400_add_controls(codec);
- wm8400_add_widgets(codec);
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int wm8400_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8400 = {
- .probe = wm8400_probe,
- .remove = wm8400_remove,
- .suspend = wm8400_suspend,
- .resume = wm8400_resume,
-};
-
static void wm8400_probe_deferred(struct work_struct *work)
{
struct wm8400_priv *priv = container_of(work, struct wm8400_priv,
work);
- struct snd_soc_codec *codec = &priv->codec;
- int ret;
+ struct snd_soc_codec *codec = priv->codec;
/* charge output caps */
wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- /* We're done, tell the subsystem. */
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(priv->wm8400->dev,
- "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm8400_dai);
- if (ret != 0) {
- dev_err(priv->wm8400->dev,
- "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
- return;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
}
-static int wm8400_codec_probe(struct platform_device *dev)
+static int wm8400_codec_probe(struct snd_soc_codec *codec)
{
+ struct wm8400 *wm8400 = dev_get_platdata(codec->dev);
struct wm8400_priv *priv;
int ret;
u16 reg;
- struct snd_soc_codec *codec;
priv = kzalloc(sizeof(struct wm8400_priv), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
- codec = &priv->codec;
snd_soc_codec_set_drvdata(codec, priv);
- codec->control_data = dev_get_drvdata(&dev->dev);
- priv->wm8400 = dev_get_drvdata(&dev->dev);
+ codec->control_data = priv->wm8400 = wm8400;
+ priv->codec = codec;
- ret = regulator_bulk_get(priv->wm8400->dev,
+ ret = regulator_bulk_get(wm8400->dev,
ARRAY_SIZE(power), &power[0]);
if (ret != 0) {
- dev_err(&dev->dev, "Failed to get regulators: %d\n", ret);
+ dev_err(codec->dev, "Failed to get regulators: %d\n", ret);
goto err;
}
- codec->dev = &dev->dev;
- wm8400_dai.dev = &dev->dev;
-
- codec->name = "WM8400";
- codec->owner = THIS_MODULE;
- codec->read = wm8400_read;
- codec->write = wm8400_write;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8400_set_bias_level;
- codec->dai = &wm8400_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8400_REGISTER_COUNT;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
INIT_WORK(&priv->work, wm8400_probe_deferred);
wm8400_codec_reset(codec);
@@ -1511,65 +1415,78 @@ static int wm8400_codec_probe(struct platform_device *dev)
wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
- wm8400_codec = codec;
-
if (!schedule_work(&priv->work)) {
ret = -EINVAL;
goto err_regulator;
}
-
+ wm8400_add_controls(codec);
+ wm8400_add_widgets(codec);
return 0;
err_regulator:
- wm8400_codec = NULL;
regulator_bulk_free(ARRAY_SIZE(power), power);
err:
kfree(priv);
return ret;
}
-static int __exit wm8400_codec_remove(struct platform_device *dev)
+static int wm8400_codec_remove(struct snd_soc_codec *codec)
{
- struct wm8400_priv *priv = snd_soc_codec_get_drvdata(wm8400_codec);
+ struct wm8400_priv *priv = snd_soc_codec_get_drvdata(codec);
u16 reg;
- snd_soc_unregister_dai(&wm8400_dai);
- snd_soc_unregister_codec(wm8400_codec);
-
- reg = wm8400_read(wm8400_codec, WM8400_POWER_MANAGEMENT_1);
- wm8400_write(wm8400_codec, WM8400_POWER_MANAGEMENT_1,
+ reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+ wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
reg & (~WM8400_CODEC_ENA));
regulator_bulk_free(ARRAY_SIZE(power), power);
kfree(priv);
- wm8400_codec = NULL;
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
+ .probe = wm8400_codec_probe,
+ .remove = wm8400_codec_remove,
+ .suspend = wm8400_suspend,
+ .resume = wm8400_resume,
+ .read = wm8400_read,
+ .write = wm8400_write,
+ .set_bias_level = wm8400_set_bias_level,
+};
+
+static int __devinit wm8400_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8400,
+ &wm8400_dai, 1);
+}
+static int __devexit wm8400_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static struct platform_driver wm8400_codec_driver = {
.driver = {
- .name = "wm8400-codec",
- .owner = THIS_MODULE,
- },
- .probe = wm8400_codec_probe,
- .remove = __exit_p(wm8400_codec_remove),
+ .name = "wm8400-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8400_probe,
+ .remove = __devexit_p(wm8400_remove),
};
-static int __init wm8400_codec_init(void)
+static __init int wm8400_init(void)
{
return platform_driver_register(&wm8400_codec_driver);
}
-module_init(wm8400_codec_init);
+module_init(wm8400_init);
-static void __exit wm8400_codec_exit(void)
+static __exit void wm8400_exit(void)
{
platform_driver_unregister(&wm8400_codec_driver);
}
-module_exit(wm8400_codec_exit);
-
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8400);
+module_exit(wm8400_exit);
MODULE_DESCRIPTION("ASoC WM8400 driver");
MODULE_AUTHOR("Mark Brown");
diff --git a/sound/soc/codecs/wm8400.h b/sound/soc/codecs/wm8400.h
index 79c5934d4776..521adb193870 100644
--- a/sound/soc/codecs/wm8400.h
+++ b/sound/soc/codecs/wm8400.h
@@ -56,7 +56,4 @@
#define WM8400_BCLK_DIV_44 (0xE << 1)
#define WM8400_BCLK_DIV_48 (0xF << 1)
-extern struct snd_soc_dai wm8400_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8400;
-
#endif
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 0f7bcb61071a..8f107095760e 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -29,10 +29,6 @@
#include "wm8510.h"
-#define WM8510_VERSION "0.6"
-
-struct snd_soc_codec_device soc_codec_dev_wm8510;
-
/*
* wm8510 register cache
* We can't read the WM8510 register space when we are
@@ -61,6 +57,11 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
#define wm8510_reset(c) snd_soc_write(c, WM8510_RESET, 0)
+/* codec private data */
+struct wm8510_priv {
+ enum snd_soc_control_type control_type;
+};
+
static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" };
static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
static const char *wm8510_alc[] = { "ALC", "Limiter" };
@@ -403,8 +404,7 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f;
u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1;
@@ -514,8 +514,8 @@ static struct snd_soc_dai_ops wm8510_dai_ops = {
.set_pll = wm8510_set_dai_pll,
};
-struct snd_soc_dai wm8510_dai = {
- .name = "WM8510 HiFi",
+static struct snd_soc_dai_driver wm8510_dai = {
+ .name = "wm8510-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -531,21 +531,15 @@ struct snd_soc_dai wm8510_dai = {
.ops = &wm8510_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8510_dai);
-static int wm8510_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8510_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8510_resume(struct platform_device *pdev)
+static int wm8510_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -561,256 +555,158 @@ static int wm8510_resume(struct platform_device *pdev)
return 0;
}
-/*
- * initialise the WM8510 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8510_init(struct snd_soc_device *socdev,
- enum snd_soc_control_type control)
+static int wm8510_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
- int ret = 0;
-
- codec->name = "WM8510";
- codec->owner = THIS_MODULE;
- codec->set_bias_level = wm8510_set_bias_level;
- codec->dai = &wm8510_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm8510_reg);
- codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL);
-
- if (codec->reg_cache == NULL)
- return -ENOMEM;
+ struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
+ int ret;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8510->control_type);
if (ret < 0) {
- printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n",
- ret);
- goto err;
+ printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", ret);
+ return ret;
}
wm8510_reset(codec);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "wm8510: failed to create pcms\n");
- goto err;
- }
-
/* power on device */
- codec->bias_level = SND_SOC_BIAS_OFF;
wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
snd_soc_add_controls(codec, wm8510_snd_controls,
ARRAY_SIZE(wm8510_snd_controls));
wm8510_add_widgets(codec);
return ret;
-
-err:
- kfree(codec->reg_cache);
- return ret;
}
-static struct snd_soc_device *wm8510_socdev;
+/* power down chip */
+static int wm8510_remove(struct snd_soc_codec *codec)
+{
+ struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ kfree(wm8510);
+ return 0;
+}
-/*
- * WM8510 2 wire address is 0x1a
- */
+static struct snd_soc_codec_driver soc_codec_dev_wm8510 = {
+ .probe = wm8510_probe,
+ .remove = wm8510_remove,
+ .suspend = wm8510_suspend,
+ .resume = wm8510_resume,
+ .set_bias_level = wm8510_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8510_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default =wm8510_reg,
+};
-static int wm8510_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8510_spi_probe(struct spi_device *spi)
{
- struct snd_soc_device *socdev = wm8510_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct wm8510_priv *wm8510;
int ret;
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
+ wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL);
+ if (wm8510 == NULL)
+ return -ENOMEM;
- ret = wm8510_init(socdev, SND_SOC_I2C);
- if (ret < 0)
- pr_err("failed to initialise WM8510\n");
+ wm8510->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8510);
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8510, &wm8510_dai, 1);
+ if (ret < 0)
+ kfree(wm8510);
return ret;
}
-static int wm8510_i2c_remove(struct i2c_client *client)
+static int __devexit wm8510_spi_remove(struct spi_device *spi)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
+ snd_soc_unregister_codec(&spi->dev);
return 0;
}
-static const struct i2c_device_id wm8510_i2c_id[] = {
- { "wm8510", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
-
-static struct i2c_driver wm8510_i2c_driver = {
+static struct spi_driver wm8510_spi_driver = {
.driver = {
- .name = "WM8510 I2C Codec",
- .owner = THIS_MODULE,
+ .name = "wm8510",
+ .owner = THIS_MODULE,
},
- .probe = wm8510_i2c_probe,
- .remove = wm8510_i2c_remove,
- .id_table = wm8510_i2c_id,
+ .probe = wm8510_spi_probe,
+ .remove = __devexit_p(wm8510_spi_remove),
};
+#endif /* CONFIG_SPI_MASTER */
-static int wm8510_add_i2c_device(struct platform_device *pdev,
- const struct wm8510_setup_data *setup)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8510_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
+ struct wm8510_priv *wm8510;
int ret;
- ret = i2c_add_driver(&wm8510_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
- }
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "wm8510", I2C_NAME_SIZE);
-
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
-
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
- }
-
- return 0;
-
-err_driver:
- i2c_del_driver(&wm8510_i2c_driver);
- return -ENODEV;
-}
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8510_spi_probe(struct spi_device *spi)
-{
- struct snd_soc_device *socdev = wm8510_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
- int ret;
+ wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL);
+ if (wm8510 == NULL)
+ return -ENOMEM;
- codec->control_data = spi;
+ i2c_set_clientdata(i2c, wm8510);
+ wm8510->control_type = SND_SOC_I2C;
- ret = wm8510_init(socdev, SND_SOC_SPI);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8510, &wm8510_dai, 1);
if (ret < 0)
- dev_err(&spi->dev, "failed to initialise WM8510\n");
-
+ kfree(wm8510);
return ret;
}
-static int __devexit wm8510_spi_remove(struct spi_device *spi)
+static __devexit int wm8510_i2c_remove(struct i2c_client *client)
{
+ snd_soc_unregister_codec(&client->dev);
return 0;
}
-static struct spi_driver wm8510_spi_driver = {
+static const struct i2c_device_id wm8510_i2c_id[] = {
+ { "wm8510", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
+
+static struct i2c_driver wm8510_i2c_driver = {
.driver = {
- .name = "wm8510",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
+ .name = "wm8510-codec",
+ .owner = THIS_MODULE,
},
- .probe = wm8510_spi_probe,
- .remove = __devexit_p(wm8510_spi_remove),
+ .probe = wm8510_i2c_probe,
+ .remove = __devexit_p(wm8510_i2c_remove),
+ .id_table = wm8510_i2c_id,
};
-#endif /* CONFIG_SPI_MASTER */
+#endif
-static int wm8510_probe(struct platform_device *pdev)
+static int __init wm8510_modinit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct wm8510_setup_data *setup;
- struct snd_soc_codec *codec;
int ret = 0;
-
- pr_info("WM8510 Audio Codec %s", WM8510_VERSION);
-
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- wm8510_socdev = socdev;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- ret = wm8510_add_i2c_device(pdev, setup);
+ ret = i2c_add_driver(&wm8510_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8510 I2C driver: %d\n",
+ ret);
}
#endif
#if defined(CONFIG_SPI_MASTER)
- if (setup->spi) {
- ret = spi_register_driver(&wm8510_spi_driver);
- if (ret != 0)
- printk(KERN_ERR "can't add spi driver");
+ ret = spi_register_driver(&wm8510_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8510 SPI driver: %d\n",
+ ret);
}
#endif
-
- if (ret != 0)
- kfree(codec);
return ret;
}
+module_init(wm8510_modinit);
-/* power down chip */
-static int wm8510_remove(struct platform_device *pdev)
+static void __exit wm8510_exit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_unregister_device(codec->control_data);
i2c_del_driver(&wm8510_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
spi_unregister_driver(&wm8510_spi_driver);
#endif
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8510 = {
- .probe = wm8510_probe,
- .remove = wm8510_remove,
- .suspend = wm8510_suspend,
- .resume = wm8510_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510);
-
-static int __init wm8510_modinit(void)
-{
- return snd_soc_register_dai(&wm8510_dai);
-}
-module_init(wm8510_modinit);
-
-static void __exit wm8510_exit(void)
-{
- snd_soc_unregister_dai(&wm8510_dai);
}
module_exit(wm8510_exit);
diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h
index bdefcf5c69ff..b3e26ed9f2d0 100644
--- a/sound/soc/codecs/wm8510.h
+++ b/sound/soc/codecs/wm8510.h
@@ -99,7 +99,4 @@ struct wm8510_setup_data {
unsigned short i2c_address;
};
-extern struct snd_soc_dai wm8510_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8510;
-
#endif
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 0ad039b4adf5..712ef7c76f90 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -30,9 +30,6 @@
#include "wm8523.h"
-static struct snd_soc_codec *wm8523_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8523;
-
#define WM8523_NUM_SUPPLIES 2
static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = {
"AVDD",
@@ -43,7 +40,7 @@ static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = {
/* codec private data */
struct wm8523_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
u16 reg_cache[WM8523_REGISTER_COUNT];
struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES];
unsigned int sysclk;
@@ -162,8 +159,7 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
int i;
u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
@@ -387,8 +383,8 @@ static struct snd_soc_dai_ops wm8523_dai_ops = {
.set_fmt = wm8523_set_dai_fmt,
};
-struct snd_soc_dai wm8523_dai = {
- .name = "WM8523",
+static struct snd_soc_dai_driver wm8523_dai = {
+ .name = "wm8523-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2, /* Mono modes not yet supported */
@@ -398,25 +394,17 @@ struct snd_soc_dai wm8523_dai = {
},
.ops = &wm8523_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8523_dai);
#ifdef CONFIG_PM
-static int wm8523_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8523_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8523_resume(struct platform_device *pdev)
+static int wm8523_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
return 0;
}
#else
@@ -424,93 +412,20 @@ static int wm8523_resume(struct platform_device *pdev)
#define wm8523_resume NULL
#endif
-static int wm8523_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (wm8523_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8523_codec;
- codec = wm8523_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8523_snd_controls,
- ARRAY_SIZE(wm8523_snd_controls));
- wm8523_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-static int wm8523_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8523 = {
- .probe = wm8523_probe,
- .remove = wm8523_remove,
- .suspend = wm8523_suspend,
- .resume = wm8523_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8523);
-
-static int wm8523_register(struct wm8523_priv *wm8523,
- enum snd_soc_control_type control)
+static int wm8523_probe(struct snd_soc_codec *codec)
{
- int ret;
- struct snd_soc_codec *codec = &wm8523->codec;
- int i;
-
- if (wm8523_codec) {
- dev_err(codec->dev, "Another WM8523 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8523);
- codec->name = "WM8523";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8523_set_bias_level;
- codec->dai = &wm8523_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8523_REGISTER_COUNT;
- codec->reg_cache = &wm8523->reg_cache;
- codec->volatile_register = wm8523_volatile_register;
+ struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
+ int ret, i;
+ codec->hw_write = (hw_write_t)i2c_master_send;
wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
wm8523->rate_constraint.count =
ARRAY_SIZE(wm8523->rate_constraint_list);
- memcpy(codec->reg_cache, wm8523_reg, sizeof(wm8523_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8523->control_type);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++)
@@ -520,7 +435,7 @@ static int wm8523_register(struct wm8523_priv *wm8523,
wm8523->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err;
+ return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
@@ -555,8 +470,6 @@ static int wm8523_register(struct wm8523_priv *wm8523,
goto err_enable;
}
- wm8523_dai.dev = codec->dev;
-
/* Change some default settings - latch VU and enable ZC */
wm8523->reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU;
wm8523->reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC;
@@ -566,69 +479,67 @@ static int wm8523_register(struct wm8523_priv *wm8523,
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
- wm8523_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_enable;
- }
-
- ret = snd_soc_register_dai(&wm8523_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8523_snd_controls,
+ ARRAY_SIZE(wm8523_snd_controls));
+ wm8523_add_widgets(codec);
return 0;
-err_codec:
- snd_soc_unregister_codec(codec);
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
err_get:
regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
-err:
- kfree(wm8523);
+
return ret;
}
-static void wm8523_unregister(struct wm8523_priv *wm8523)
+static int wm8523_remove(struct snd_soc_codec *codec)
{
- wm8523_set_bias_level(&wm8523->codec, SND_SOC_BIAS_OFF);
+ struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
+
+ wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
- snd_soc_unregister_dai(&wm8523_dai);
- snd_soc_unregister_codec(&wm8523->codec);
- kfree(wm8523);
- wm8523_codec = NULL;
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8523 = {
+ .probe = wm8523_probe,
+ .remove = wm8523_remove,
+ .suspend = wm8523_suspend,
+ .resume = wm8523_resume,
+ .set_bias_level = wm8523_set_bias_level,
+ .reg_cache_size = WM8523_REGISTER_COUNT,
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8523_reg,
+ .volatile_register = wm8523_volatile_register,
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8523_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8523_priv *wm8523;
- struct snd_soc_codec *codec;
+ int ret;
wm8523 = kzalloc(sizeof(struct wm8523_priv), GFP_KERNEL);
if (wm8523 == NULL)
return -ENOMEM;
- codec = &wm8523->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
i2c_set_clientdata(i2c, wm8523);
- codec->control_data = i2c;
+ wm8523->control_type = SND_SOC_I2C;
- codec->dev = &i2c->dev;
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8523, &wm8523_dai, 1);
+ if (ret < 0)
+ kfree(wm8523);
+ return ret;
- return wm8523_register(wm8523, SND_SOC_I2C);
}
static __devexit int wm8523_i2c_remove(struct i2c_client *client)
{
- struct wm8523_priv *wm8523 = i2c_get_clientdata(client);
- wm8523_unregister(wm8523);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -640,7 +551,7 @@ MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id);
static struct i2c_driver wm8523_i2c_driver = {
.driver = {
- .name = "WM8523",
+ .name = "wm8523-codec",
.owner = THIS_MODULE,
},
.probe = wm8523_i2c_probe,
diff --git a/sound/soc/codecs/wm8523.h b/sound/soc/codecs/wm8523.h
index 1aa9ce3e1357..4d5b1eb8f2fc 100644
--- a/sound/soc/codecs/wm8523.h
+++ b/sound/soc/codecs/wm8523.h
@@ -154,7 +154,4 @@
#define WM8523_ZD_COUNT_SHIFT 0 /* ZD_COUNT - [1:0] */
#define WM8523_ZD_COUNT_WIDTH 2 /* ZD_COUNT - [1:0] */
-extern struct snd_soc_dai wm8523_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8523;
-
#endif
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 72deeabef4fe..a2e0ed59b376 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -94,6 +94,8 @@
#define WM8580_MAX_REGISTER 0x35
+#define WM8580_DACOSR 0x40
+
/* PLLB4 (register 7h) */
#define WM8580_PLLB4_MCLKOUTSRC_MASK 0x60
#define WM8580_PLLB4_MCLKOUTSRC_PLLA 0x20
@@ -112,19 +114,7 @@
/* AIF control 1 (registers 9h-bh) */
#define WM8580_AIF_RATE_MASK 0x7
-#define WM8580_AIF_RATE_128 0x0
-#define WM8580_AIF_RATE_192 0x1
-#define WM8580_AIF_RATE_256 0x2
-#define WM8580_AIF_RATE_384 0x3
-#define WM8580_AIF_RATE_512 0x4
-#define WM8580_AIF_RATE_768 0x5
-#define WM8580_AIF_RATE_1152 0x6
-
#define WM8580_AIF_BCLKSEL_MASK 0x18
-#define WM8580_AIF_BCLKSEL_64 0x00
-#define WM8580_AIF_BCLKSEL_128 0x08
-#define WM8580_AIF_BCLKSEL_256 0x10
-#define WM8580_AIF_BCLKSEL_SYSCLK 0x18
#define WM8580_AIF_MS 0x20
@@ -199,11 +189,12 @@ static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = {
/* codec private data */
struct wm8580_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES];
u16 reg_cache[WM8580_MAX_REGISTER + 1];
struct pll_state a;
struct pll_state b;
+ int sysclk[2];
};
static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
@@ -273,8 +264,8 @@ SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 1),
SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 1),
SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 1),
-SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0),
-SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
+SOC_DOUBLE("Capture Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 1),
+SOC_SINGLE("Capture High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
};
static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = {
@@ -476,6 +467,10 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
return 0;
}
+static const int wm8580_sysclk_ratios[] = {
+ 128, 192, 256, 384, 512, 768, 1152,
+};
+
/*
* Set PCM DAI bit size and sample rate.
*/
@@ -484,29 +479,68 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
- u16 paifb = snd_soc_read(codec, WM8580_PAIF3 + dai->id);
+ struct snd_soc_codec *codec = rtd->codec;
+ struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+ u16 paifa = 0;
+ u16 paifb = 0;
+ int i, ratio, osr;
- paifb &= ~WM8580_AIF_LENGTH_MASK;
/* bit size */
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
+ paifa |= 0x8;
break;
case SNDRV_PCM_FORMAT_S20_3LE:
+ paifa |= 0x10;
paifb |= WM8580_AIF_LENGTH_20;
break;
case SNDRV_PCM_FORMAT_S24_LE:
+ paifa |= 0x10;
paifb |= WM8580_AIF_LENGTH_24;
break;
case SNDRV_PCM_FORMAT_S32_LE:
+ paifa |= 0x10;
paifb |= WM8580_AIF_LENGTH_24;
break;
default:
return -EINVAL;
}
- snd_soc_write(codec, WM8580_PAIF3 + dai->id, paifb);
+ /* Look up the SYSCLK ratio; accept only exact matches */
+ ratio = wm8580->sysclk[dai->id] / params_rate(params);
+ for (i = 0; i < ARRAY_SIZE(wm8580_sysclk_ratios); i++)
+ if (ratio == wm8580_sysclk_ratios[i])
+ break;
+ if (i == ARRAY_SIZE(wm8580_sysclk_ratios)) {
+ dev_err(codec->dev, "Invalid clock ratio %d/%d\n",
+ wm8580->sysclk[dai->id], params_rate(params));
+ return -EINVAL;
+ }
+ paifa |= i;
+ dev_dbg(codec->dev, "Running at %dfs with %dHz clock\n",
+ wm8580_sysclk_ratios[i], wm8580->sysclk[dai->driver->id]);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ switch (ratio) {
+ case 128:
+ case 192:
+ osr = WM8580_DACOSR;
+ dev_dbg(codec->dev, "Selecting 64x OSR\n");
+ break;
+ default:
+ osr = 0;
+ dev_dbg(codec->dev, "Selecting 128x OSR\n");
+ break;
+ }
+
+ snd_soc_update_bits(codec, WM8580_PAIF3, WM8580_DACOSR, osr);
+ }
+
+ snd_soc_update_bits(codec, WM8580_PAIF1 + dai->driver->id,
+ WM8580_AIF_RATE_MASK | WM8580_AIF_BCLKSEL_MASK,
+ paifa);
+ snd_soc_update_bits(codec, WM8580_PAIF3 + dai->driver->id,
+ WM8580_AIF_LENGTH_MASK, paifb);
return 0;
}
@@ -518,8 +552,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int aifb;
int can_invert_lrclk;
- aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->id);
- aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->id);
+ aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->driver->id);
+ aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->driver->id);
aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP);
@@ -585,8 +619,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL;
}
- snd_soc_write(codec, WM8580_PAIF1 + codec_dai->id, aifa);
- snd_soc_write(codec, WM8580_PAIF3 + codec_dai->id, aifb);
+ snd_soc_write(codec, WM8580_PAIF1 + codec_dai->driver->id, aifa);
+ snd_soc_write(codec, WM8580_PAIF3 + codec_dai->driver->id, aifb);
return 0;
}
@@ -624,28 +658,6 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
snd_soc_write(codec, WM8580_PLLB4, reg);
break;
- case WM8580_DAC_CLKSEL:
- reg = snd_soc_read(codec, WM8580_CLKSEL);
- reg &= ~WM8580_CLKSEL_DAC_CLKSEL_MASK;
-
- switch (div) {
- case WM8580_CLKSRC_MCLK:
- break;
-
- case WM8580_CLKSRC_PLLA:
- reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLA;
- break;
-
- case WM8580_CLKSRC_PLLB:
- reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLB;
- break;
-
- default:
- return -EINVAL;
- }
- snd_soc_write(codec, WM8580_CLKSEL, reg);
- break;
-
case WM8580_CLKOUTSRC:
reg = snd_soc_read(codec, WM8580_PLLB4);
reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK;
@@ -679,6 +691,55 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
return 0;
}
+static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+ int sel, sel_mask, sel_shift;
+
+ switch (dai->driver->id) {
+ case WM8580_DAI_PAIFRX:
+ sel_mask = 0x3;
+ sel_shift = 0;
+ break;
+
+ case WM8580_DAI_PAIFTX:
+ sel_mask = 0xc;
+ sel_shift = 2;
+ break;
+
+ default:
+ BUG_ON("Unknown DAI driver ID\n");
+ return -EINVAL;
+ }
+
+ switch (clk_id) {
+ case WM8580_CLKSRC_ADCMCLK:
+ if (dai->id != WM8580_DAI_PAIFTX)
+ return -EINVAL;
+ sel = 0 << sel_shift;
+ break;
+ case WM8580_CLKSRC_PLLA:
+ sel = 1 << sel_shift;
+ break;
+ case WM8580_CLKSRC_PLLB:
+ sel = 2 << sel_shift;
+ break;
+ case WM8580_CLKSRC_MCLK:
+ sel = 3 << sel_shift;
+ break;
+ default:
+ dev_err(codec->dev, "Unknown clock %d\n", clk_id);
+ return -EINVAL;
+ }
+
+ /* We really should validate PLL settings but not yet */
+ wm8580->sysclk[dai->id] = freq;
+
+ return snd_soc_update_bits(codec, WM8580_CLKSEL, sel_mask, sel);
+}
+
static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute)
{
struct snd_soc_codec *codec = codec_dai->codec;
@@ -732,6 +793,7 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_ops wm8580_dai_ops_playback = {
+ .set_sysclk = wm8580_set_sysclk,
.hw_params = wm8580_paif_hw_params,
.set_fmt = wm8580_set_paif_dai_fmt,
.set_clkdiv = wm8580_set_dai_clkdiv,
@@ -740,16 +802,17 @@ static struct snd_soc_dai_ops wm8580_dai_ops_playback = {
};
static struct snd_soc_dai_ops wm8580_dai_ops_capture = {
+ .set_sysclk = wm8580_set_sysclk,
.hw_params = wm8580_paif_hw_params,
.set_fmt = wm8580_set_paif_dai_fmt,
.set_clkdiv = wm8580_set_dai_clkdiv,
.set_pll = wm8580_set_dai_pll,
};
-struct snd_soc_dai wm8580_dai[] = {
+static struct snd_soc_dai_driver wm8580_dai[] = {
{
- .name = "WM8580 PAIFRX",
- .id = 0,
+ .name = "wm8580-hifi-playback",
+ .id = WM8580_DAI_PAIFRX,
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -760,8 +823,8 @@ struct snd_soc_dai wm8580_dai[] = {
.ops = &wm8580_dai_ops_playback,
},
{
- .name = "WM8580 PAIFTX",
- .id = 1,
+ .name = "wm8580-hifi-capture",
+ .id = WM8580_DAI_PAIFTX,
.capture = {
.stream_name = "Capture",
.channels_min = 2,
@@ -772,90 +835,16 @@ struct snd_soc_dai wm8580_dai[] = {
.ops = &wm8580_dai_ops_capture,
},
};
-EXPORT_SYMBOL_GPL(wm8580_dai);
-
-static struct snd_soc_codec *wm8580_codec;
-static int wm8580_probe(struct platform_device *pdev)
+static int wm8580_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (wm8580_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8580_codec;
- codec = wm8580_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8580_snd_controls,
- ARRAY_SIZE(wm8580_snd_controls));
- wm8580_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int wm8580_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8580 = {
- .probe = wm8580_probe,
- .remove = wm8580_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580);
-
-static int wm8580_register(struct wm8580_priv *wm8580,
- enum snd_soc_control_type control)
-{
- int ret, i;
- struct snd_soc_codec *codec = &wm8580->codec;
-
- if (wm8580_codec) {
- dev_err(codec->dev, "Another WM8580 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8580);
- codec->name = "WM8580";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8580_set_bias_level;
- codec->dai = wm8580_dai;
- codec->num_dai = ARRAY_SIZE(wm8580_dai);
- codec->reg_cache_size = ARRAY_SIZE(wm8580->reg_cache);
- codec->reg_cache = &wm8580->reg_cache;
-
- memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg));
+ struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0,i;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8580->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++)
@@ -865,7 +854,7 @@ static int wm8580_register(struct wm8580_priv *wm8580,
wm8580->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err;
+ return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),
@@ -882,74 +871,68 @@ static int wm8580_register(struct wm8580_priv *wm8580,
goto err_regulator_enable;
}
- for (i = 0; i < ARRAY_SIZE(wm8580_dai); i++)
- wm8580_dai[i].dev = codec->dev;
-
wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- wm8580_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_regulator_enable;
- }
-
- ret = snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8580_snd_controls,
+ ARRAY_SIZE(wm8580_snd_controls));
+ wm8580_add_widgets(codec);
return 0;
-err_codec:
- snd_soc_unregister_codec(codec);
err_regulator_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
err_regulator_get:
regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
-err:
- kfree(wm8580);
return ret;
}
-static void wm8580_unregister(struct wm8580_priv *wm8580)
+/* power down chip */
+static int wm8580_remove(struct snd_soc_codec *codec)
{
- wm8580_set_bias_level(&wm8580->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
- snd_soc_unregister_codec(&wm8580->codec);
+ struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+
+ wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
- kfree(wm8580);
- wm8580_codec = NULL;
+
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8580 = {
+ .probe = wm8580_probe,
+ .remove = wm8580_remove,
+ .set_bias_level = wm8580_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8580_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = &wm8580_reg,
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static int wm8580_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8580_priv *wm8580;
- struct snd_soc_codec *codec;
+ int ret;
wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL);
if (wm8580 == NULL)
return -ENOMEM;
- codec = &wm8580->codec;
-
i2c_set_clientdata(i2c, wm8580);
- codec->control_data = i2c;
+ wm8580->control_type = SND_SOC_I2C;
- codec->dev = &i2c->dev;
-
- return wm8580_register(wm8580, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai));
+ if (ret < 0)
+ kfree(wm8580);
+ return ret;
}
static int wm8580_i2c_remove(struct i2c_client *client)
{
- struct wm8580_priv *wm8580 = i2c_get_clientdata(client);
- wm8580_unregister(wm8580);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -961,7 +944,7 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id);
static struct i2c_driver wm8580_i2c_driver = {
.driver = {
- .name = "wm8580",
+ .name = "wm8580-codec",
.owner = THIS_MODULE,
},
.probe = wm8580_i2c_probe,
@@ -972,7 +955,7 @@ static struct i2c_driver wm8580_i2c_driver = {
static int __init wm8580_modinit(void)
{
- int ret;
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8580_i2c_driver);
@@ -981,7 +964,7 @@ static int __init wm8580_modinit(void)
}
#endif
- return 0;
+ return ret;
}
module_init(wm8580_modinit);
diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h
index 0dfb5ddde6a2..1d34656d0dcb 100644
--- a/sound/soc/codecs/wm8580.h
+++ b/sound/soc/codecs/wm8580.h
@@ -19,20 +19,17 @@
#define WM8580_PLLB 2
#define WM8580_MCLK 1
-#define WM8580_DAC_CLKSEL 2
-#define WM8580_CLKOUTSRC 3
+#define WM8580_CLKOUTSRC 2
-#define WM8580_CLKSRC_MCLK 1
-#define WM8580_CLKSRC_PLLA 2
-#define WM8580_CLKSRC_PLLB 3
-#define WM8580_CLKSRC_OSC 4
-#define WM8580_CLKSRC_NONE 5
+#define WM8580_CLKSRC_MCLK 1
+#define WM8580_CLKSRC_PLLA 2
+#define WM8580_CLKSRC_PLLB 3
+#define WM8580_CLKSRC_OSC 4
+#define WM8580_CLKSRC_NONE 5
+#define WM8580_CLKSRC_ADCMCLK 6
#define WM8580_DAI_PAIFRX 0
#define WM8580_DAI_PAIFTX 1
-extern struct snd_soc_dai wm8580_dai[];
-extern struct snd_soc_codec_device soc_codec_dev_wm8580;
-
#endif
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index e2dba07f0260..54fbd76c8bca 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -31,11 +31,9 @@
#include "wm8711.h"
-static struct snd_soc_codec *wm8711_codec;
-
/* codec private data */
struct wm8711_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type bus_type;
u16 reg_cache[WM8711_CACHEREGNUM];
unsigned int sysclk;
};
@@ -163,7 +161,7 @@ static int wm8711_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
- struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
+ struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc;
int i = get_coeff(wm8711->sysclk, params_rate(params));
u16 srate = (coeff_div[i].sr << 2) |
@@ -227,7 +225,7 @@ static int wm8711_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
- struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
+ struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
switch (freq) {
case 11289600:
@@ -338,8 +336,8 @@ static struct snd_soc_dai_ops wm8711_ops = {
.set_fmt = wm8711_set_dai_fmt,
};
-struct snd_soc_dai wm8711_dai = {
- .name = "WM8711",
+static struct snd_soc_dai_driver wm8711_dai = {
+ .name = "wm8711-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -349,22 +347,16 @@ struct snd_soc_dai wm8711_dai = {
},
.ops = &wm8711_ops,
};
-EXPORT_SYMBOL_GPL(wm8711_dai);
-static int wm8711_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8711_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
snd_soc_write(codec, WM8711_ACTIVE, 0x0);
wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8711_resume(struct platform_device *pdev)
+static int wm8711_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -380,99 +372,23 @@ static int wm8711_resume(struct platform_device *pdev)
return 0;
}
-static int wm8711_probe(struct platform_device *pdev)
+static int wm8711_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (wm8711_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8711_codec;
- codec = wm8711_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8711_snd_controls,
- ARRAY_SIZE(wm8711_snd_controls));
- wm8711_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int wm8711_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8711 = {
- .probe = wm8711_probe,
- .remove = wm8711_remove,
- .suspend = wm8711_suspend,
- .resume = wm8711_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8711);
-
-static int wm8711_register(struct wm8711_priv *wm8711,
- enum snd_soc_control_type control)
-{
- int ret;
- struct snd_soc_codec *codec = &wm8711->codec;
- u16 reg;
-
- if (wm8711_codec) {
- dev_err(codec->dev, "Another WM8711 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8711);
- codec->name = "WM8711";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8711_set_bias_level;
- codec->dai = &wm8711_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8711_CACHEREGNUM;
- codec->reg_cache = &wm8711->reg_cache;
-
- memcpy(codec->reg_cache, wm8711_reg, sizeof(wm8711_reg));
+ struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
+ int ret, reg;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8711->bus_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
ret = wm8711_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
+ return ret;
}
- wm8711_dai.dev = codec->dev;
-
wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch the update bits */
@@ -481,70 +397,62 @@ static int wm8711_register(struct wm8711_priv *wm8711,
reg = snd_soc_read(codec, WM8711_ROUT1V);
snd_soc_write(codec, WM8711_ROUT1V, reg | 0x0100);
- wm8711_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm8711_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
+ snd_soc_add_controls(codec, wm8711_snd_controls,
+ ARRAY_SIZE(wm8711_snd_controls));
+ wm8711_add_widgets(codec);
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8711);
return ret;
+
}
-static void wm8711_unregister(struct wm8711_priv *wm8711)
+/* power down chip */
+static int wm8711_remove(struct snd_soc_codec *codec)
{
- wm8711_set_bias_level(&wm8711->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8711_dai);
- snd_soc_unregister_codec(&wm8711->codec);
- kfree(wm8711);
- wm8711_codec = NULL;
+ wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
+ .probe = wm8711_probe,
+ .remove = wm8711_remove,
+ .suspend = wm8711_suspend,
+ .resume = wm8711_resume,
+ .set_bias_level = wm8711_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8711_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8711_reg,
+};
+
#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8711_spi_probe(struct spi_device *spi)
{
- struct snd_soc_codec *codec;
struct wm8711_priv *wm8711;
+ int ret;
wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
if (wm8711 == NULL)
return -ENOMEM;
- codec = &wm8711->codec;
- codec->control_data = spi;
- codec->dev = &spi->dev;
+ spi_set_drvdata(spi, wm8711);
+ wm8711->bus_type = SND_SOC_SPI;
- dev_set_drvdata(&spi->dev, wm8711);
-
- return wm8711_register(wm8711, SND_SOC_SPI);
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8711, &wm8711_dai, 1);
+ if (ret < 0)
+ kfree(wm8711);
+ return ret;
}
static int __devexit wm8711_spi_remove(struct spi_device *spi)
{
- struct wm8711_priv *wm8711 = dev_get_drvdata(&spi->dev);
-
- wm8711_unregister(wm8711);
-
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
return 0;
}
static struct spi_driver wm8711_spi_driver = {
.driver = {
- .name = "wm8711",
- .bus = &spi_bus_type,
+ .name = "wm8711-codec",
.owner = THIS_MODULE,
},
.probe = wm8711_spi_probe,
@@ -553,31 +461,30 @@ static struct spi_driver wm8711_spi_driver = {
#endif /* CONFIG_SPI_MASTER */
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static __devinit int wm8711_i2c_probe(struct i2c_client *i2c,
+static __devinit int wm8711_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct wm8711_priv *wm8711;
- struct snd_soc_codec *codec;
+ int ret;
wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
if (wm8711 == NULL)
return -ENOMEM;
- codec = &wm8711->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
- i2c_set_clientdata(i2c, wm8711);
- codec->control_data = i2c;
+ i2c_set_clientdata(client, wm8711);
+ wm8711->bus_type = SND_SOC_I2C;
- codec->dev = &i2c->dev;
-
- return wm8711_register(wm8711, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&client->dev,
+ &soc_codec_dev_wm8711, &wm8711_dai, 1);
+ if (ret < 0)
+ kfree(wm8711);
+ return ret;
}
static __devexit int wm8711_i2c_remove(struct i2c_client *client)
{
- struct wm8711_priv *wm8711 = i2c_get_clientdata(client);
- wm8711_unregister(wm8711);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -589,7 +496,7 @@ MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id);
static struct i2c_driver wm8711_i2c_driver = {
.driver = {
- .name = "WM8711 I2C Codec",
+ .name = "wm8711-codec",
.owner = THIS_MODULE,
},
.probe = wm8711_i2c_probe,
diff --git a/sound/soc/codecs/wm8711.h b/sound/soc/codecs/wm8711.h
index 381e84a43816..a61db985499f 100644
--- a/sound/soc/codecs/wm8711.h
+++ b/sound/soc/codecs/wm8711.h
@@ -36,7 +36,4 @@ struct wm8711_setup_data {
unsigned short i2c_address;
};
-extern struct snd_soc_dai wm8711_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8711;
-
#endif
diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c
index 9d1df2628136..748808285119 100644
--- a/sound/soc/codecs/wm8727.c
+++ b/sound/soc/codecs/wm8727.c
@@ -23,7 +23,6 @@
#include <sound/initval.h>
#include <sound/soc.h>
-#include "wm8727.h"
/*
* Note this is a simple chip with no configuration interface, sample rate is
* determined automatically by examining the Master clock and Bit clock ratios
@@ -33,8 +32,8 @@
SNDRV_PCM_RATE_192000)
-struct snd_soc_dai wm8727_dai = {
- .name = "WM8727",
+static struct snd_soc_dai_driver wm8727_dai = {
+ .name = "wm8727-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -43,103 +42,18 @@ struct snd_soc_dai wm8727_dai = {
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
},
};
-EXPORT_SYMBOL_GPL(wm8727_dai);
-static struct snd_soc_codec *wm8727_codec;
+static struct snd_soc_codec_driver soc_codec_dev_wm8727;
-static int wm8727_soc_probe(struct platform_device *pdev)
+static __devinit int wm8727_probe(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- int ret = 0;
-
- BUG_ON(!wm8727_codec);
-
- socdev->card->codec = wm8727_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "wm8727: failed to create pcms\n");
- goto pcm_err;
- }
-
- return ret;
-
-pcm_err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
- return ret;
-}
-
-static int wm8727_soc_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8727 = {
- .probe = wm8727_soc_probe,
- .remove = wm8727_soc_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8727);
-
-
-static __devinit int wm8727_platform_probe(struct platform_device *pdev)
-{
- struct snd_soc_codec *codec;
- int ret;
-
- if (wm8727_codec) {
- dev_err(&pdev->dev, "Another WM8727 is registered\n");
- return -EBUSY;
- }
-
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
- wm8727_codec = codec;
-
- platform_set_drvdata(pdev, codec);
-
- mutex_init(&codec->mutex);
- codec->dev = &pdev->dev;
- codec->name = "WM8727";
- codec->owner = THIS_MODULE;
- codec->dai = &wm8727_dai;
- codec->num_dai = 1;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- wm8727_dai.dev = &pdev->dev;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(&pdev->dev, "Failed to register CODEC: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm8727_dai);
- if (ret != 0) {
- dev_err(&pdev->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(codec);
- return ret;
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_wm8727, &wm8727_dai, 1);
}
-static int __devexit wm8727_platform_remove(struct platform_device *pdev)
+static int __devexit wm8727_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&wm8727_dai);
- snd_soc_unregister_codec(platform_get_drvdata(pdev));
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
@@ -149,8 +63,8 @@ static struct platform_driver wm8727_codec_driver = {
.owner = THIS_MODULE,
},
- .probe = wm8727_platform_probe,
- .remove = __devexit_p(wm8727_platform_remove),
+ .probe = wm8727_probe,
+ .remove = __devexit_p(wm8727_remove),
};
static int __init wm8727_init(void)
diff --git a/sound/soc/codecs/wm8727.h b/sound/soc/codecs/wm8727.h
deleted file mode 100644
index ee19aa71bcdc..000000000000
--- a/sound/soc/codecs/wm8727.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * wm8727.h
- *
- * Created on: 15-Oct-2009
- * Author: neil.jones@imgtec.com
- *
- * Copyright (C) 2009 Imagination Technologies Ltd.
- *
- * 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 WM8727_H_
-#define WM8727_H_
-
-extern struct snd_soc_dai wm8727_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8727;
-
-#endif /* WM8727_H_ */
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index 34be2d2b69ef..075f35e4f4cb 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -29,8 +29,6 @@
#include "wm8728.h"
-struct snd_soc_codec_device soc_codec_dev_wm8728;
-
/*
* We can't read the WM8728 register space so we cache them instead.
* Note that the defaults here aren't the physical defaults, we latch
@@ -44,6 +42,11 @@ static const u16 wm8728_reg_defaults[] = {
0x100,
};
+/* codec private data */
+struct wm8728_priv {
+ enum snd_soc_control_type control_type;
+};
+
static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1);
static const struct snd_kcontrol_new wm8728_snd_controls[] = {
@@ -96,8 +99,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 dac = snd_soc_read(codec, WM8728_DACCTL);
dac &= ~0x18;
@@ -210,8 +212,8 @@ static struct snd_soc_dai_ops wm8728_dai_ops = {
.set_fmt = wm8728_set_dai_fmt,
};
-struct snd_soc_dai wm8728_dai = {
- .name = "WM8728",
+static struct snd_soc_dai_driver wm8728_dai = {
+ .name = "wm8728-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -221,63 +223,31 @@ struct snd_soc_dai wm8728_dai = {
},
.ops = &wm8728_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8728_dai);
-static int wm8728_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8728_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8728_resume(struct platform_device *pdev)
+static int wm8728_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-/*
- * initialise the WM8728 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8728_init(struct snd_soc_device *socdev,
- enum snd_soc_control_type control)
+static int wm8728_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
- int ret = 0;
-
- codec->name = "WM8728";
- codec->owner = THIS_MODULE;
- codec->set_bias_level = wm8728_set_bias_level;
- codec->dai = &wm8728_dai;
- codec->num_dai = 1;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults);
- codec->reg_cache = kmemdup(wm8728_reg_defaults,
- sizeof(wm8728_reg_defaults),
- GFP_KERNEL);
- if (codec->reg_cache == NULL)
- return -ENOMEM;
+ struct wm8728_priv *wm8728 = snd_soc_codec_get_drvdata(codec);
+ int ret;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8728->control_type);
if (ret < 0) {
printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n",
ret);
- goto err;
- }
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "wm8728: failed to create pcms\n");
- goto err;
+ return ret;
}
/* power on device */
@@ -288,215 +258,136 @@ static int wm8728_init(struct snd_soc_device *socdev,
wm8728_add_widgets(codec);
return ret;
-
-err:
- kfree(codec->reg_cache);
- return ret;
}
-static struct snd_soc_device *wm8728_socdev;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static int wm8728_remove(struct snd_soc_codec *codec)
+{
+ wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
-/*
- * WM8728 2 wire address is determined by GPIO5
- * state during powerup.
- * low = 0x1a
- * high = 0x1b
- */
+static struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
+ .probe = wm8728_probe,
+ .remove = wm8728_remove,
+ .suspend = wm8728_suspend,
+ .resume = wm8728_resume,
+ .set_bias_level = wm8728_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8728_reg_defaults,
+};
-static int wm8728_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8728_spi_probe(struct spi_device *spi)
{
- struct snd_soc_device *socdev = wm8728_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct wm8728_priv *wm8728;
int ret;
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
+ wm8728 = kzalloc(sizeof(struct wm8728_priv), GFP_KERNEL);
+ if (wm8728 == NULL)
+ return -ENOMEM;
+
+ wm8728->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8728);
- ret = wm8728_init(socdev, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8728, &wm8728_dai, 1);
if (ret < 0)
- pr_err("failed to initialise WM8728\n");
-
+ kfree(wm8728);
return ret;
}
-static int wm8728_i2c_remove(struct i2c_client *client)
+static int __devexit wm8728_spi_remove(struct spi_device *spi)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
return 0;
}
-static const struct i2c_device_id wm8728_i2c_id[] = {
- { "wm8728", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id);
-
-static struct i2c_driver wm8728_i2c_driver = {
+static struct spi_driver wm8728_spi_driver = {
.driver = {
- .name = "WM8728 I2C Codec",
- .owner = THIS_MODULE,
+ .name = "wm8728-codec",
+ .owner = THIS_MODULE,
},
- .probe = wm8728_i2c_probe,
- .remove = wm8728_i2c_remove,
- .id_table = wm8728_i2c_id,
+ .probe = wm8728_spi_probe,
+ .remove = __devexit_p(wm8728_spi_remove),
};
+#endif /* CONFIG_SPI_MASTER */
-static int wm8728_add_i2c_device(struct platform_device *pdev,
- const struct wm8728_setup_data *setup)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8728_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
+ struct wm8728_priv *wm8728;
int ret;
- ret = i2c_add_driver(&wm8728_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
- }
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "wm8728", I2C_NAME_SIZE);
-
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
-
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
- }
-
- return 0;
-
-err_driver:
- i2c_del_driver(&wm8728_i2c_driver);
- return -ENODEV;
-}
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8728_spi_probe(struct spi_device *spi)
-{
- struct snd_soc_device *socdev = wm8728_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
- int ret;
+ wm8728 = kzalloc(sizeof(struct wm8728_priv), GFP_KERNEL);
+ if (wm8728 == NULL)
+ return -ENOMEM;
- codec->control_data = spi;
+ i2c_set_clientdata(i2c, wm8728);
+ wm8728->control_type = SND_SOC_I2C;
- ret = wm8728_init(socdev, SND_SOC_SPI);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8728, &wm8728_dai, 1);
if (ret < 0)
- dev_err(&spi->dev, "failed to initialise WM8728\n");
-
+ kfree(wm8728);
return ret;
}
-static int __devexit wm8728_spi_remove(struct spi_device *spi)
+static __devexit int wm8728_i2c_remove(struct i2c_client *client)
{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
-static struct spi_driver wm8728_spi_driver = {
+static const struct i2c_device_id wm8728_i2c_id[] = {
+ { "wm8728", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id);
+
+static struct i2c_driver wm8728_i2c_driver = {
.driver = {
- .name = "wm8728",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
+ .name = "wm8728-codec",
+ .owner = THIS_MODULE,
},
- .probe = wm8728_spi_probe,
- .remove = __devexit_p(wm8728_spi_remove),
+ .probe = wm8728_i2c_probe,
+ .remove = __devexit_p(wm8728_i2c_remove),
+ .id_table = wm8728_i2c_id,
};
-#endif /* CONFIG_SPI_MASTER */
+#endif
-static int wm8728_probe(struct platform_device *pdev)
+static int __init wm8728_modinit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct wm8728_setup_data *setup;
- struct snd_soc_codec *codec;
int ret = 0;
-
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- wm8728_socdev = socdev;
- ret = -ENODEV;
-
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- ret = wm8728_add_i2c_device(pdev, setup);
+ ret = i2c_add_driver(&wm8728_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8728 I2C driver: %d\n",
+ ret);
}
#endif
#if defined(CONFIG_SPI_MASTER)
- if (setup->spi) {
- ret = spi_register_driver(&wm8728_spi_driver);
- if (ret != 0)
- printk(KERN_ERR "can't add spi driver");
+ ret = spi_register_driver(&wm8728_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8728 SPI driver: %d\n",
+ ret);
}
#endif
-
- if (ret != 0)
- kfree(codec);
-
return ret;
}
+module_init(wm8728_modinit);
-/* power down chip */
-static int wm8728_remove(struct platform_device *pdev)
+static void __exit wm8728_exit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_unregister_device(codec->control_data);
i2c_del_driver(&wm8728_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
spi_unregister_driver(&wm8728_spi_driver);
#endif
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8728 = {
- .probe = wm8728_probe,
- .remove = wm8728_remove,
- .suspend = wm8728_suspend,
- .resume = wm8728_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728);
-
-static int __init wm8728_modinit(void)
-{
- return snd_soc_register_dai(&wm8728_dai);
-}
-module_init(wm8728_modinit);
-
-static void __exit wm8728_exit(void)
-{
- snd_soc_unregister_dai(&wm8728_dai);
}
module_exit(wm8728_exit);
diff --git a/sound/soc/codecs/wm8728.h b/sound/soc/codecs/wm8728.h
index d269c132474b..8aea362ffd47 100644
--- a/sound/soc/codecs/wm8728.h
+++ b/sound/soc/codecs/wm8728.h
@@ -18,13 +18,4 @@
#define WM8728_DACCTL 0x02
#define WM8728_IFCTL 0x03
-struct wm8728_setup_data {
- int spi;
- int i2c_bus;
- unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai wm8728_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8728;
-
#endif
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 0ab9b6355297..631385802eb4 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -32,9 +32,6 @@
#include "wm8731.h"
-static struct snd_soc_codec *wm8731_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8731;
-
#define WM8731_NUM_SUPPLIES 4
static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
"AVDD",
@@ -45,10 +42,11 @@ static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
/* codec private data */
struct wm8731_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
u16 reg_cache[WM8731_CACHEREGNUM];
unsigned int sysclk;
+ int sysclk_type;
};
@@ -113,6 +111,7 @@ static const struct snd_kcontrol_new wm8731_input_mux_controls =
SOC_DAPM_ENUM("Input Select", wm8731_enum[0]);
static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0),
SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1,
&wm8731_output_mixer_controls[0],
ARRAY_SIZE(wm8731_output_mixer_controls)),
@@ -130,7 +129,18 @@ SND_SOC_DAPM_INPUT("RLINEIN"),
SND_SOC_DAPM_INPUT("LLINEIN"),
};
+static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec);
+
+ return wm8731->sysclk_type == WM8731_SYSCLK_MCLK;
+}
+
static const struct snd_soc_dapm_route intercon[] = {
+ {"DAC", NULL, "OSC", wm8731_check_osc},
+ {"ADC", NULL, "OSC", wm8731_check_osc},
+
/* output mixer */
{"Output Mixer", "Line Bypass Switch", "Line Input"},
{"Output Mixer", "HiFi Playback Switch", "DAC"},
@@ -222,9 +232,7 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8731_IFACE) & 0xfff3;
int i = get_coeff(wm8731->sysclk, params_rate(params));
@@ -252,9 +260,7 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
static int wm8731_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = dai->codec;
/* set active */
snd_soc_write(codec, WM8731_ACTIVE, 0x0001);
@@ -265,9 +271,7 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream,
static void wm8731_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = dai->codec;
/* deactivate */
if (!codec->active) {
@@ -294,6 +298,15 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
struct snd_soc_codec *codec = codec_dai->codec;
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+ switch (clk_id) {
+ case WM8731_SYSCLK_XTAL:
+ case WM8731_SYSCLK_MCLK:
+ wm8731->sysclk_type = clk_id;
+ break;
+ default:
+ return -EINVAL;
+ }
+
switch (freq) {
case 11289600:
case 12000000:
@@ -301,9 +314,14 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
case 16934400:
case 18432000:
wm8731->sysclk = freq;
- return 0;
+ break;
+ default:
+ return -EINVAL;
}
- return -EINVAL;
+
+ snd_soc_dapm_sync(codec);
+
+ return 0;
}
@@ -428,8 +446,8 @@ static struct snd_soc_dai_ops wm8731_dai_ops = {
.set_fmt = wm8731_set_dai_fmt,
};
-struct snd_soc_dai wm8731_dai = {
- .name = "WM8731",
+static struct snd_soc_dai_driver wm8731_dai = {
+ .name = "wm8731-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -445,24 +463,17 @@ struct snd_soc_dai wm8731_dai = {
.ops = &wm8731_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8731_dai);
#ifdef CONFIG_PM
-static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8731_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8731_resume(struct platform_device *pdev)
+static int wm8731_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -472,88 +483,15 @@ static int wm8731_resume(struct platform_device *pdev)
#define wm8731_resume NULL
#endif
-static int wm8731_probe(struct platform_device *pdev)
+static int wm8731_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (wm8731_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8731_codec;
- codec = wm8731_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8731_snd_controls,
- ARRAY_SIZE(wm8731_snd_controls));
- wm8731_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int wm8731_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8731 = {
- .probe = wm8731_probe,
- .remove = wm8731_remove,
- .suspend = wm8731_suspend,
- .resume = wm8731_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
-
-static int wm8731_register(struct wm8731_priv *wm8731,
- enum snd_soc_control_type control)
-{
- int ret, i;
- struct snd_soc_codec *codec = &wm8731->codec;
-
- if (wm8731_codec) {
- dev_err(codec->dev, "Another WM8731 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8731);
- codec->name = "WM8731";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8731_set_bias_level;
- codec->dai = &wm8731_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8731_CACHEREGNUM;
- codec->reg_cache = &wm8731->reg_cache;
-
- memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg));
+ struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0, i;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8731->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)
@@ -563,7 +501,7 @@ static int wm8731_register(struct wm8731_priv *wm8731,
wm8731->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err;
+ return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
@@ -579,8 +517,6 @@ static int wm8731_register(struct wm8731_priv *wm8731,
goto err_regulator_enable;
}
- wm8731_dai.dev = codec->dev;
-
wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch the update bits */
@@ -592,79 +528,78 @@ static int wm8731_register(struct wm8731_priv *wm8731,
/* Disable bypass path by default */
snd_soc_update_bits(codec, WM8731_APANA, 0x4, 0);
- wm8731_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_regulator_enable;
- }
-
- ret = snd_soc_register_dai(&wm8731_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8731_snd_controls,
+ ARRAY_SIZE(wm8731_snd_controls));
+ wm8731_add_widgets(codec);
/* Regulators will have been enabled by bias management */
regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
return 0;
-err_codec:
- snd_soc_unregister_codec(codec);
err_regulator_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
err_regulator_get:
regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
-err:
+
kfree(wm8731);
return ret;
}
-static void wm8731_unregister(struct wm8731_priv *wm8731)
+/* power down chip */
+static int wm8731_remove(struct snd_soc_codec *codec)
{
- wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8731_dai);
- snd_soc_unregister_codec(&wm8731->codec);
+ struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+
+ wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
- kfree(wm8731);
- wm8731_codec = NULL;
+
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
+ .probe = wm8731_probe,
+ .remove = wm8731_remove,
+ .suspend = wm8731_suspend,
+ .resume = wm8731_resume,
+ .set_bias_level = wm8731_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8731_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8731_reg,
+};
+
#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8731_spi_probe(struct spi_device *spi)
{
- struct snd_soc_codec *codec;
struct wm8731_priv *wm8731;
+ int ret;
wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
if (wm8731 == NULL)
return -ENOMEM;
- codec = &wm8731->codec;
- codec->control_data = spi;
- codec->dev = &spi->dev;
-
- dev_set_drvdata(&spi->dev, wm8731);
+ wm8731->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8731);
- return wm8731_register(wm8731, SND_SOC_SPI);
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8731, &wm8731_dai, 1);
+ if (ret < 0)
+ kfree(wm8731);
+ return ret;
}
static int __devexit wm8731_spi_remove(struct spi_device *spi)
{
- struct wm8731_priv *wm8731 = dev_get_drvdata(&spi->dev);
-
- wm8731_unregister(wm8731);
-
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
return 0;
}
static struct spi_driver wm8731_spi_driver = {
.driver = {
- .name = "wm8731",
- .bus = &spi_bus_type,
+ .name = "wm8731-codec",
.owner = THIS_MODULE,
},
.probe = wm8731_spi_probe,
@@ -677,26 +612,26 @@ static __devinit int wm8731_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8731_priv *wm8731;
- struct snd_soc_codec *codec;
+ int ret;
wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
if (wm8731 == NULL)
return -ENOMEM;
- codec = &wm8731->codec;
-
i2c_set_clientdata(i2c, wm8731);
- codec->control_data = i2c;
-
- codec->dev = &i2c->dev;
+ wm8731->control_type = SND_SOC_I2C;
- return wm8731_register(wm8731, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8731, &wm8731_dai, 1);
+ if (ret < 0)
+ kfree(wm8731);
+ return ret;
}
static __devexit int wm8731_i2c_remove(struct i2c_client *client)
{
- struct wm8731_priv *wm8731 = i2c_get_clientdata(client);
- wm8731_unregister(wm8731);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -708,7 +643,7 @@ MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
static struct i2c_driver wm8731_i2c_driver = {
.driver = {
- .name = "wm8731",
+ .name = "wm8731-codec",
.owner = THIS_MODULE,
},
.probe = wm8731_i2c_probe,
@@ -719,7 +654,7 @@ static struct i2c_driver wm8731_i2c_driver = {
static int __init wm8731_modinit(void)
{
- int ret;
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8731_i2c_driver);
if (ret != 0) {
@@ -734,7 +669,7 @@ static int __init wm8731_modinit(void)
ret);
}
#endif
- return 0;
+ return ret;
}
module_init(wm8731_modinit);
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h
index cd7b806e8ad0..e9c0c76ab73b 100644
--- a/sound/soc/codecs/wm8731.h
+++ b/sound/soc/codecs/wm8731.h
@@ -31,10 +31,9 @@
#define WM8731_CACHEREGNUM 10
-#define WM8731_SYSCLK 0
-#define WM8731_DAI 0
+#define WM8731_SYSCLK_XTAL 1
+#define WM8731_SYSCLK_MCLK 2
-extern struct snd_soc_dai wm8731_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8731;
+#define WM8731_DAI 0
#endif
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index b9ea8904ad4b..90e31e9aa6f7 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -30,25 +30,21 @@
#include "wm8741.h"
-static struct snd_soc_codec *wm8741_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8741;
-
#define WM8741_NUM_SUPPLIES 2
static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
"AVDD",
"DVDD",
};
-#define WM8741_NUM_RATES 4
+#define WM8741_NUM_RATES 6
/* codec private data */
struct wm8741_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
u16 reg_cache[WM8741_REGISTER_COUNT];
struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
unsigned int sysclk;
- unsigned int rate_constraint_list[WM8741_NUM_RATES];
- struct snd_pcm_hw_constraint_list rate_constraint;
+ struct snd_pcm_hw_constraint_list *sysclk_constraints;
};
static const u16 wm8741_reg_defaults[WM8741_REGISTER_COUNT] = {
@@ -111,10 +107,84 @@ static struct {
int value;
int ratio;
} lrclk_ratios[WM8741_NUM_RATES] = {
- { 1, 256 },
- { 2, 384 },
- { 3, 512 },
- { 4, 768 },
+ { 1, 128 },
+ { 2, 192 },
+ { 3, 256 },
+ { 4, 384 },
+ { 5, 512 },
+ { 6, 768 },
+};
+
+static unsigned int rates_11289[] = {
+ 44100, 88235,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_11289 = {
+ .count = ARRAY_SIZE(rates_11289),
+ .list = rates_11289,
+};
+
+static unsigned int rates_12288[] = {
+ 32000, 48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_12288 = {
+ .count = ARRAY_SIZE(rates_12288),
+ .list = rates_12288,
+};
+
+static unsigned int rates_16384[] = {
+ 32000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_16384 = {
+ .count = ARRAY_SIZE(rates_16384),
+ .list = rates_16384,
+};
+
+static unsigned int rates_16934[] = {
+ 44100, 88235,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_16934 = {
+ .count = ARRAY_SIZE(rates_16934),
+ .list = rates_16934,
+};
+
+static unsigned int rates_18432[] = {
+ 48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_18432 = {
+ .count = ARRAY_SIZE(rates_18432),
+ .list = rates_18432,
+};
+
+static unsigned int rates_22579[] = {
+ 44100, 88235, 1764000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_22579 = {
+ .count = ARRAY_SIZE(rates_22579),
+ .list = rates_22579,
+};
+
+static unsigned int rates_24576[] = {
+ 32000, 48000, 96000, 192000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_24576 = {
+ .count = ARRAY_SIZE(rates_24576),
+ .list = rates_24576,
+};
+
+static unsigned int rates_36864[] = {
+ 48000, 96000, 19200
+};
+
+static struct snd_pcm_hw_constraint_list constraints_36864 = {
+ .count = ARRAY_SIZE(rates_36864),
+ .list = rates_36864,
};
@@ -135,7 +205,7 @@ static int wm8741_startup(struct snd_pcm_substream *substream,
snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
- &wm8741->rate_constraint);
+ wm8741->sysclk_constraints);
return 0;
}
@@ -145,8 +215,7 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC;
int i;
@@ -196,47 +265,52 @@ static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai,
{
struct snd_soc_codec *codec = codec_dai->codec;
struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
- unsigned int val;
- int i;
dev_dbg(codec->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq);
- wm8741->sysclk = freq;
-
- wm8741->rate_constraint.count = 0;
-
- for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
- dev_dbg(codec->dev, "index = %d, ratio = %d, freq = %d",
- i, lrclk_ratios[i].ratio, freq);
-
- val = freq / lrclk_ratios[i].ratio;
- /* Check that it's a standard rate since core can't
- * cope with others and having the odd rates confuses
- * constraint matching.
- */
- switch (val) {
- case 32000:
- case 44100:
- case 48000:
- case 64000:
- case 88200:
- case 96000:
- dev_dbg(codec->dev, "Supported sample rate: %dHz\n",
- val);
- wm8741->rate_constraint_list[i] = val;
- wm8741->rate_constraint.count++;
- break;
- default:
- dev_dbg(codec->dev, "Skipping sample rate: %dHz\n",
- val);
- }
+ switch (freq) {
+ case 11289600:
+ wm8741->sysclk_constraints = &constraints_11289;
+ wm8741->sysclk = freq;
+ return 0;
+
+ case 12288000:
+ wm8741->sysclk_constraints = &constraints_12288;
+ wm8741->sysclk = freq;
+ return 0;
+
+ case 16384000:
+ wm8741->sysclk_constraints = &constraints_16384;
+ wm8741->sysclk = freq;
+ return 0;
+
+ case 16934400:
+ wm8741->sysclk_constraints = &constraints_16934;
+ wm8741->sysclk = freq;
+ return 0;
+
+ case 18432000:
+ wm8741->sysclk_constraints = &constraints_18432;
+ wm8741->sysclk = freq;
+ return 0;
+
+ case 22579200:
+ case 33868800:
+ wm8741->sysclk_constraints = &constraints_22579;
+ wm8741->sysclk = freq;
+ return 0;
+
+ case 24576000:
+ wm8741->sysclk_constraints = &constraints_24576;
+ wm8741->sysclk = freq;
+ return 0;
+
+ case 36864000:
+ wm8741->sysclk_constraints = &constraints_36864;
+ wm8741->sysclk = freq;
+ return 0;
}
-
- /* Need at least one supported rate... */
- if (wm8741->rate_constraint.count == 0)
- return -EINVAL;
-
- return 0;
+ return -EINVAL;
}
static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
@@ -314,8 +388,8 @@ static struct snd_soc_dai_ops wm8741_dai_ops = {
.set_fmt = wm8741_set_dai_fmt,
};
-struct snd_soc_dai wm8741_dai = {
- .name = "WM8741",
+static struct snd_soc_dai_driver wm8741_dai = {
+ .name = "wm8741",
.playback = {
.stream_name = "Playback",
.channels_min = 2, /* Mono modes not yet supported */
@@ -325,13 +399,10 @@ struct snd_soc_dai wm8741_dai = {
},
.ops = &wm8741_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8741_dai);
#ifdef CONFIG_PM
-static int wm8741_resume(struct platform_device *pdev)
+static int wm8741_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
u16 *cache = codec->reg_cache;
int i;
@@ -348,189 +419,99 @@ static int wm8741_resume(struct platform_device *pdev)
#define wm8741_resume NULL
#endif
-static int wm8741_probe(struct platform_device *pdev)
+static int wm8741_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
+ struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
- if (wm8741_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8741->control_type);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
}
- socdev->card->codec = wm8741_codec;
- codec = wm8741_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ ret = wm8741_reset(codec);
if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
+ dev_err(codec->dev, "Failed to issue reset\n");
+ return ret;
}
+ /* Change some default settings - latch VU */
+ wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
+ wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
+ wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
+ wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
+
snd_soc_add_controls(codec, wm8741_snd_controls,
ARRAY_SIZE(wm8741_snd_controls));
wm8741_add_widgets(codec);
- return ret;
-
-pcm_err:
+ dev_dbg(codec->dev, "Successful registration\n");
return ret;
}
-static int wm8741_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8741 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
.probe = wm8741_probe,
- .remove = wm8741_remove,
.resume = wm8741_resume,
+ .reg_cache_size = ARRAY_SIZE(wm8741_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = &wm8741_reg_defaults,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8741);
-static int wm8741_register(struct wm8741_priv *wm8741,
- enum snd_soc_control_type control)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static int wm8741_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
- int ret;
- struct snd_soc_codec *codec = &wm8741->codec;
- int i;
-
- if (wm8741_codec) {
- dev_err(codec->dev, "Another WM8741 is registered\n");
- return -EINVAL;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8741);
- codec->name = "WM8741";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = NULL;
- codec->dai = &wm8741_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8741_REGISTER_COUNT;
- codec->reg_cache = &wm8741->reg_cache;
-
- wm8741->rate_constraint.list = &wm8741->rate_constraint_list[0];
- wm8741->rate_constraint.count =
- ARRAY_SIZE(wm8741->rate_constraint_list);
-
- memcpy(codec->reg_cache, wm8741_reg_defaults,
- sizeof(wm8741->reg_cache));
+ struct wm8741_priv *wm8741;
+ int ret, i;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
- }
+ wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
+ if (wm8741 == NULL)
+ return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
wm8741->supplies[i].supply = wm8741_supply_names[i];
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies),
+ ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8741->supplies),
wm8741->supplies);
if (ret != 0) {
- dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
goto err;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
wm8741->supplies);
if (ret != 0) {
- dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
goto err_get;
}
- ret = wm8741_reset(codec);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to issue reset\n");
- goto err_enable;
- }
-
- wm8741_dai.dev = codec->dev;
-
- /* Change some default settings - latch VU */
- wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
- wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
- wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
- wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
-
- wm8741_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_register_dai(&wm8741_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- return ret;
- }
+ i2c_set_clientdata(i2c, wm8741);
+ wm8741->control_type = SND_SOC_I2C;
- dev_dbg(codec->dev, "Successful registration\n");
- return 0;
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8741, &wm8741_dai, 1);
+ if (ret < 0)
+ goto err_enable;
+ return ret;
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
err_get:
regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
-
err:
kfree(wm8741);
return ret;
}
-static void wm8741_unregister(struct wm8741_priv *wm8741)
-{
- regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
-
- snd_soc_unregister_dai(&wm8741_dai);
- snd_soc_unregister_codec(&wm8741->codec);
- kfree(wm8741);
- wm8741_codec = NULL;
-}
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static __devinit int wm8741_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
-{
- struct wm8741_priv *wm8741;
- struct snd_soc_codec *codec;
-
- wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
- if (wm8741 == NULL)
- return -ENOMEM;
-
- codec = &wm8741->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
- i2c_set_clientdata(i2c, wm8741);
- codec->control_data = i2c;
-
- codec->dev = &i2c->dev;
-
- return wm8741_register(wm8741, SND_SOC_I2C);
-}
-
-static __devexit int wm8741_i2c_remove(struct i2c_client *client)
+static int wm8741_i2c_remove(struct i2c_client *client)
{
struct wm8741_priv *wm8741 = i2c_get_clientdata(client);
- wm8741_unregister(wm8741);
+
+ snd_soc_unregister_codec(&client->dev);
+ regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -540,29 +521,28 @@ static const struct i2c_device_id wm8741_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id);
-
static struct i2c_driver wm8741_i2c_driver = {
.driver = {
- .name = "WM8741",
+ .name = "wm8741-codec",
.owner = THIS_MODULE,
},
.probe = wm8741_i2c_probe,
- .remove = __devexit_p(wm8741_i2c_remove),
+ .remove = wm8741_i2c_remove,
.id_table = wm8741_i2c_id,
};
#endif
static int __init wm8741_modinit(void)
{
- int ret;
+ int ret = 0;
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8741_i2c_driver);
- if (ret != 0) {
- printk(KERN_ERR "Failed to register WM8741 I2C driver: %d\n",
- ret);
- }
+ if (ret != 0)
+ pr_err("Failed to register WM8741 I2C driver: %d\n", ret);
#endif
- return 0;
+
+ return ret;
}
module_init(wm8741_modinit);
diff --git a/sound/soc/codecs/wm8741.h b/sound/soc/codecs/wm8741.h
index fdef6ecd1f6f..56c1b1d4a681 100644
--- a/sound/soc/codecs/wm8741.h
+++ b/sound/soc/codecs/wm8741.h
@@ -208,7 +208,4 @@
#define WM8741_SYSCLK 0
-extern struct snd_soc_dai wm8741_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8741;
-
#endif
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index e2c05e3e323a..6c924cd2cfd4 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -52,7 +52,7 @@ static const u16 wm8750_reg[] = {
/* codec private data */
struct wm8750_priv {
unsigned int sysclk;
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
u16 reg_cache[ARRAY_SIZE(wm8750_reg)];
};
@@ -560,8 +560,7 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3;
u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0;
@@ -649,8 +648,8 @@ static struct snd_soc_dai_ops wm8750_dai_ops = {
.set_sysclk = wm8750_set_dai_sysclk,
};
-struct snd_soc_dai wm8750_dai = {
- .name = "WM8750",
+static struct snd_soc_dai_driver wm8750_dai = {
+ .name = "wm8750-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -665,21 +664,15 @@ struct snd_soc_dai wm8750_dai = {
.formats = WM8750_FORMATS,},
.ops = &wm8750_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8750_dai);
-static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8750_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8750_resume(struct platform_device *pdev)
+static int wm8750_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -698,100 +691,21 @@ static int wm8750_resume(struct platform_device *pdev)
return 0;
}
-static struct snd_soc_codec *wm8750_codec;
-
-static int wm8750_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (!wm8750_codec) {
- dev_err(&pdev->dev, "WM8750 codec not yet registered\n");
- return -EINVAL;
- }
-
- socdev->card->codec = wm8750_codec;
- codec = wm8750_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "wm8750: failed to create pcms\n");
- goto err;
- }
-
- snd_soc_add_controls(codec, wm8750_snd_controls,
- ARRAY_SIZE(wm8750_snd_controls));
- wm8750_add_widgets(codec);
-
- return 0;
-
-err:
- return ret;
-}
-
-/* power down chip */
-static int wm8750_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8750 = {
- .probe = wm8750_probe,
- .remove = wm8750_remove,
- .suspend = wm8750_suspend,
- .resume = wm8750_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750);
-
-/*
- * initialise the WM8750 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8750_register(struct wm8750_priv *wm8750,
- enum snd_soc_control_type control)
+static int wm8750_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = &wm8750->codec;
- int reg, ret = 0;
-
- if (wm8750_codec) {
- dev_err(codec->dev, "Multiple WM8750 devices not supported\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "WM8750";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_STANDBY;
- codec->set_bias_level = wm8750_set_bias_level;
- codec->dai = &wm8750_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm8750->reg_cache) + 1;
- codec->reg_cache = &wm8750->reg_cache;
- snd_soc_codec_set_drvdata(codec, wm8750);
-
- memcpy(codec->reg_cache, wm8750_reg, sizeof(wm8750->reg_cache));
+ struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
+ int reg, ret;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8750->control_type);
if (ret < 0) {
printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
ret = wm8750_reset(codec);
if (ret < 0) {
printk(KERN_ERR "wm8750: failed to reset: %d\n", ret);
- goto err;
+ return ret;
}
/* charge output caps */
@@ -815,150 +729,130 @@ static int wm8750_register(struct wm8750_priv *wm8750,
reg = snd_soc_read(codec, WM8750_RINVOL);
snd_soc_write(codec, WM8750_RINVOL, reg | 0x0100);
- wm8750_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dais(&wm8750_dai, 1);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8750);
+ snd_soc_add_controls(codec, wm8750_snd_controls,
+ ARRAY_SIZE(wm8750_snd_controls));
+ wm8750_add_widgets(codec);
return ret;
}
-static void wm8750_unregister(struct wm8750_priv *wm8750)
+static int wm8750_remove(struct snd_soc_codec *codec)
{
- wm8750_set_bias_level(&wm8750->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dais(&wm8750_dai, 1);
- snd_soc_unregister_codec(&wm8750->codec);
- kfree(wm8750);
- wm8750_codec = NULL;
+ wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-/*
- * WM8750 2 wire address is determined by GPIO5
- * state during powerup.
- * low = 0x1a
- * high = 0x1b
- */
+static struct snd_soc_codec_driver soc_codec_dev_wm8750 = {
+ .probe = wm8750_probe,
+ .remove = wm8750_remove,
+ .suspend = wm8750_suspend,
+ .resume = wm8750_resume,
+ .set_bias_level = wm8750_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8750_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8750_reg,
+};
-static int wm8750_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8750_spi_probe(struct spi_device *spi)
{
- struct snd_soc_codec *codec;
struct wm8750_priv *wm8750;
+ int ret;
wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
if (wm8750 == NULL)
return -ENOMEM;
- codec = &wm8750->codec;
- codec->control_data = i2c;
- i2c_set_clientdata(i2c, wm8750);
-
- codec->dev = &i2c->dev;
+ wm8750->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8750);
- return wm8750_register(wm8750, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8750, &wm8750_dai, 1);
+ if (ret < 0)
+ kfree(wm8750);
+ return ret;
}
-static int wm8750_i2c_remove(struct i2c_client *client)
+static int __devexit wm8750_spi_remove(struct spi_device *spi)
{
- struct wm8750_priv *wm8750 = i2c_get_clientdata(client);
- wm8750_unregister(wm8750);
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
return 0;
}
-static const struct i2c_device_id wm8750_i2c_id[] = {
- { "wm8750", 0 },
- { "wm8987", 0 }, /* WM8987 is register compatible with WM8750 */
- { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
-
-static struct i2c_driver wm8750_i2c_driver = {
+static struct spi_driver wm8750_spi_driver = {
.driver = {
- .name = "WM8750 I2C Codec",
- .owner = THIS_MODULE,
+ .name = "wm8750-codec",
+ .owner = THIS_MODULE,
},
- .probe = wm8750_i2c_probe,
- .remove = wm8750_i2c_remove,
- .id_table = wm8750_i2c_id,
+ .probe = wm8750_spi_probe,
+ .remove = __devexit_p(wm8750_spi_remove),
};
-#endif
+#endif /* CONFIG_SPI_MASTER */
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8750_spi_probe(struct spi_device *spi)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8750_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
- struct snd_soc_codec *codec;
struct wm8750_priv *wm8750;
+ int ret;
wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
if (wm8750 == NULL)
return -ENOMEM;
- codec = &wm8750->codec;
- codec->control_data = spi;
- codec->dev = &spi->dev;
-
- dev_set_drvdata(&spi->dev, wm8750);
+ i2c_set_clientdata(i2c, wm8750);
+ wm8750->control_type = SND_SOC_I2C;
- return wm8750_register(wm8750, SND_SOC_SPI);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8750, &wm8750_dai, 1);
+ if (ret < 0)
+ kfree(wm8750);
+ return ret;
}
-static int __devexit wm8750_spi_remove(struct spi_device *spi)
+static __devexit int wm8750_i2c_remove(struct i2c_client *client)
{
- struct wm8750_priv *wm8750 = dev_get_drvdata(&spi->dev);
- wm8750_unregister(wm8750);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
-static const struct spi_device_id wm8750_spi_id[] = {
+static const struct i2c_device_id wm8750_i2c_id[] = {
{ "wm8750", 0 },
{ "wm8987", 0 },
{ }
};
-MODULE_DEVICE_TABLE(spi, wm8750_spi_id);
+MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
-static struct spi_driver wm8750_spi_driver = {
+static struct i2c_driver wm8750_i2c_driver = {
.driver = {
- .name = "WM8750 SPI Codec",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
+ .name = "wm8750-codec",
+ .owner = THIS_MODULE,
},
- .probe = wm8750_spi_probe,
- .remove = __devexit_p(wm8750_spi_remove),
- .id_table = wm8750_spi_id,
+ .probe = wm8750_i2c_probe,
+ .remove = __devexit_p(wm8750_i2c_remove),
+ .id_table = wm8750_i2c_id,
};
#endif
static int __init wm8750_modinit(void)
{
- int ret;
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8750_i2c_driver);
- if (ret != 0)
- pr_err("Failed to register WM8750 I2C driver: %d\n", ret);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8750 I2C driver: %d\n",
+ ret);
+ }
#endif
#if defined(CONFIG_SPI_MASTER)
ret = spi_register_driver(&wm8750_spi_driver);
- if (ret != 0)
- pr_err("Failed to register WM8750 SPI driver: %d\n", ret);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8750 SPI driver: %d\n",
+ ret);
+ }
#endif
- return 0;
+ return ret;
}
module_init(wm8750_modinit);
diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h
index 1dc100e19cfe..121427c047fb 100644
--- a/sound/soc/codecs/wm8750.h
+++ b/sound/soc/codecs/wm8750.h
@@ -57,13 +57,4 @@
#define WM8750_SYSCLK 0
-struct wm8750_setup_data {
- int spi;
- int i2c_bus;
- unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai wm8750_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8750;
-
#endif
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index b59f349c5218..8f679a13f2bc 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -57,7 +57,7 @@ module_param(caps_charge, int, 0);
MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
- unsigned int mode);
+ struct snd_soc_dai *dai, unsigned int hifi);
/*
* wm8753 register cache
@@ -85,10 +85,11 @@ static const u16 wm8753_reg[] = {
/* codec private data */
struct wm8753_priv {
+ enum snd_soc_control_type control_type;
unsigned int sysclk;
unsigned int pcmclk;
- struct snd_soc_codec codec;
u16 reg_cache[ARRAY_SIZE(wm8753_reg)];
+ int dai_func;
};
/*
@@ -228,6 +229,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL);
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0])
return 0;
@@ -235,8 +237,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
mode &= 0xfff3;
mode |= (ucontrol->value.integer.value[0] << 2);
- wm8753_write(codec, WM8753_IOCTL, mode);
- wm8753_set_dai_mode(codec, ucontrol->value.integer.value[0]);
+ wm8753->dai_func = ucontrol->value.integer.value[0];
return 1;
}
@@ -904,6 +905,13 @@ static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
+static int wm8753_pcm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ wm8753_set_dai_mode(dai->codec, dai, 0);
+ return 0;
+}
+
/*
* Set PCM DAI bit size and sample rate.
*/
@@ -912,8 +920,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3;
u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f;
@@ -1138,6 +1145,13 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
+static int wm8753_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ wm8753_set_dai_mode(dai->codec, dai, 1);
+ return 0;
+}
+
/*
* Set PCM DAI bit size and sample rate.
*/
@@ -1146,8 +1160,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0;
u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3;
@@ -1240,12 +1253,12 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7;
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
/* the digital mute covers the HiFi and Voice DAC's on the WM8753.
* make sure we check if they are not both active when we mute */
- if (mute && dai->id == 1) {
- if (!wm8753_dai[WM8753_DAI_VOICE].playback.active ||
- !wm8753_dai[WM8753_DAI_HIFI].playback.active)
+ if (mute && wm8753->dai_func == 1) {
+ if (!codec->active)
wm8753_write(codec, WM8753_DAC, mute_reg | 0x8);
} else {
if (mute)
@@ -1303,6 +1316,7 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
* 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture
*/
static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = {
+ .startup = wm8753_i2s_startup,
.hw_params = wm8753_i2s_hw_params,
.digital_mute = wm8753_mute,
.set_fmt = wm8753_mode1h_set_dai_fmt,
@@ -1312,6 +1326,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = {
};
static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = {
+ .startup = wm8753_pcm_startup,
.hw_params = wm8753_pcm_hw_params,
.digital_mute = wm8753_mute,
.set_fmt = wm8753_mode1v_set_dai_fmt,
@@ -1321,6 +1336,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = {
};
static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = {
+ .startup = wm8753_pcm_startup,
.hw_params = wm8753_pcm_hw_params,
.digital_mute = wm8753_mute,
.set_fmt = wm8753_mode2_set_dai_fmt,
@@ -1330,6 +1346,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = {
};
static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = {
+ .startup = wm8753_i2s_startup,
.hw_params = wm8753_i2s_hw_params,
.digital_mute = wm8753_mute,
.set_fmt = wm8753_mode3_4_set_dai_fmt,
@@ -1339,6 +1356,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = {
};
static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = {
+ .startup = wm8753_i2s_startup,
.hw_params = wm8753_i2s_hw_params,
.digital_mute = wm8753_mute,
.set_fmt = wm8753_mode3_4_set_dai_fmt,
@@ -1347,10 +1365,9 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = {
.set_sysclk = wm8753_set_dai_sysclk,
};
-static const struct snd_soc_dai wm8753_all_dai[] = {
+static struct snd_soc_dai_driver wm8753_all_dai[] = {
/* DAI HiFi mode 1 */
-{ .name = "WM8753 HiFi",
- .id = 1,
+{ .name = "wm8753-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
@@ -1366,8 +1383,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
.ops = &wm8753_dai_ops_hifi_mode1,
},
/* DAI Voice mode 1 */
-{ .name = "WM8753 Voice",
- .id = 1,
+{ .name = "wm8753-voice",
.playback = {
.stream_name = "Voice Playback",
.channels_min = 1,
@@ -1383,12 +1399,10 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
.ops = &wm8753_dai_ops_voice_mode1,
},
/* DAI HiFi mode 2 - dummy */
-{ .name = "WM8753 HiFi",
- .id = 2,
+{ .name = "wm8753-hifi",
},
/* DAI Voice mode 2 */
-{ .name = "WM8753 Voice",
- .id = 2,
+{ .name = "wm8753-voice",
.playback = {
.stream_name = "Voice Playback",
.channels_min = 1,
@@ -1404,8 +1418,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
.ops = &wm8753_dai_ops_voice_mode2,
},
/* DAI HiFi mode 3 */
-{ .name = "WM8753 HiFi",
- .id = 3,
+{ .name = "wm8753-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
@@ -1421,12 +1434,10 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
.ops = &wm8753_dai_ops_hifi_mode3,
},
/* DAI Voice mode 3 - dummy */
-{ .name = "WM8753 Voice",
- .id = 3,
+{ .name = "wm8753-voice",
},
/* DAI HiFi mode 4 */
-{ .name = "WM8753 HiFi",
- .id = 4,
+{ .name = "wm8753-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
@@ -1442,58 +1453,31 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
.ops = &wm8753_dai_ops_hifi_mode4,
},
/* DAI Voice mode 4 - dummy */
-{ .name = "WM8753 Voice",
- .id = 4,
+{ .name = "wm8753-voice",
},
};
-struct snd_soc_dai wm8753_dai[] = {
+static struct snd_soc_dai_driver wm8753_dai[] = {
{
- .name = "WM8753 DAI 0",
+ .name = "wm8753-aif0",
},
{
- .name = "WM8753 DAI 1",
+ .name = "wm8753-aif1",
},
};
-EXPORT_SYMBOL_GPL(wm8753_dai);
-static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode)
+static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
+ struct snd_soc_dai *dai, unsigned int hifi)
{
- if (mode < 4) {
- int playback_active, capture_active, codec_active, pop_wait;
- void *private_data;
- struct list_head list;
-
- playback_active = wm8753_dai[0].playback.active;
- capture_active = wm8753_dai[0].capture.active;
- codec_active = wm8753_dai[0].active;
- private_data = wm8753_dai[0].private_data;
- pop_wait = wm8753_dai[0].pop_wait;
- list = wm8753_dai[0].list;
- wm8753_dai[0] = wm8753_all_dai[mode << 1];
- wm8753_dai[0].playback.active = playback_active;
- wm8753_dai[0].capture.active = capture_active;
- wm8753_dai[0].active = codec_active;
- wm8753_dai[0].private_data = private_data;
- wm8753_dai[0].pop_wait = pop_wait;
- wm8753_dai[0].list = list;
-
- playback_active = wm8753_dai[1].playback.active;
- capture_active = wm8753_dai[1].capture.active;
- codec_active = wm8753_dai[1].active;
- private_data = wm8753_dai[1].private_data;
- pop_wait = wm8753_dai[1].pop_wait;
- list = wm8753_dai[1].list;
- wm8753_dai[1] = wm8753_all_dai[(mode << 1) + 1];
- wm8753_dai[1].playback.active = playback_active;
- wm8753_dai[1].capture.active = capture_active;
- wm8753_dai[1].active = codec_active;
- wm8753_dai[1].private_data = private_data;
- wm8753_dai[1].pop_wait = pop_wait;
- wm8753_dai[1].list = list;
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+
+ if (wm8753->dai_func < 4) {
+ if (hifi)
+ dai->driver = &wm8753_all_dai[wm8753->dai_func << 1];
+ else
+ dai->driver = &wm8753_all_dai[(wm8753->dai_func << 1) + 1];
}
- wm8753_dai[0].codec = codec;
- wm8753_dai[1].codec = codec;
+ wm8753_write(codec, WM8753_IOCTL, wm8753->dai_func);
}
static void wm8753_work(struct work_struct *work)
@@ -1503,19 +1487,14 @@ static void wm8753_work(struct work_struct *work)
wm8753_set_bias_level(codec, codec->bias_level);
}
-static int wm8753_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8753_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8753_resume(struct platform_device *pdev)
+static int wm8753_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -1547,41 +1526,6 @@ static int wm8753_resume(struct platform_device *pdev)
return 0;
}
-static struct snd_soc_codec *wm8753_codec;
-
-static int wm8753_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (!wm8753_codec) {
- dev_err(&pdev->dev, "WM8753 codec not yet registered\n");
- return -EINVAL;
- }
-
- socdev->card->codec = wm8753_codec;
- codec = wm8753_codec;
-
- wm8753_set_dai_mode(codec, 0);
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "wm8753: failed to create pcms\n");
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8753_snd_controls,
- ARRAY_SIZE(wm8753_snd_controls));
- wm8753_add_widgets(codec);
-
- return 0;
-
-pcm_err:
- return ret;
-}
-
/*
* This function forces any delayed work to be queued and run.
*/
@@ -1601,62 +1545,28 @@ static int run_delayed_work(struct delayed_work *dwork)
return ret;
}
-/* power down chip */
-static int wm8753_remove(struct platform_device *pdev)
+static int wm8753_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8753 = {
- .probe = wm8753_probe,
- .remove = wm8753_remove,
- .suspend = wm8753_suspend,
- .resume = wm8753_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0, reg;
-static int wm8753_register(struct wm8753_priv *wm8753)
-{
- int ret, i;
- struct snd_soc_codec *codec = &wm8753->codec;
- u16 reg;
+ INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
- if (wm8753_codec) {
- dev_err(codec->dev, "Multiple WM8753 devices not supported\n");
- ret = -EINVAL;
- goto err;
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8753->control_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
}
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "WM8753";
- codec->owner = THIS_MODULE;
- codec->read = wm8753_read_reg_cache;
- codec->write = wm8753_write;
- codec->bias_level = SND_SOC_BIAS_STANDBY;
- codec->set_bias_level = wm8753_set_bias_level;
- codec->dai = wm8753_dai;
- codec->num_dai = 2;
- codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache) + 1;
- codec->reg_cache = &wm8753->reg_cache;
- snd_soc_codec_set_drvdata(codec, wm8753);
-
- memcpy(codec->reg_cache, wm8753_reg, sizeof(wm8753->reg_cache));
- INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
-
ret = wm8753_reset(codec);
if (ret < 0) {
- dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
+ dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+ return ret;
}
+ wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ wm8753->dai_func = 0;
+
/* charge output caps */
wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
schedule_delayed_work(&codec->delayed_work,
@@ -1684,165 +1594,133 @@ static int wm8753_register(struct wm8753_priv *wm8753)
reg = wm8753_read_reg_cache(codec, WM8753_RINVOL);
wm8753_write(codec, WM8753_RINVOL, reg | 0x0100);
- wm8753_codec = codec;
-
- for (i = 0; i < ARRAY_SIZE(wm8753_dai); i++)
- wm8753_dai[i].dev = codec->dev;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8753_snd_controls,
+ ARRAY_SIZE(wm8753_snd_controls));
+ wm8753_add_widgets(codec);
return 0;
-
-err_codec:
- run_delayed_work(&codec->delayed_work);
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8753);
- return ret;
}
-static void wm8753_unregister(struct wm8753_priv *wm8753)
+/* power down chip */
+static int wm8753_remove(struct snd_soc_codec *codec)
{
- wm8753_set_bias_level(&wm8753->codec, SND_SOC_BIAS_OFF);
- run_delayed_work(&wm8753->codec.delayed_work);
- snd_soc_unregister_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai));
- snd_soc_unregister_codec(&wm8753->codec);
- kfree(wm8753);
- wm8753_codec = NULL;
+ run_delayed_work(&codec->delayed_work);
+ wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
}
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static struct snd_soc_codec_driver soc_codec_dev_wm8753 = {
+ .probe = wm8753_probe,
+ .remove = wm8753_remove,
+ .suspend = wm8753_suspend,
+ .resume = wm8753_resume,
+ .set_bias_level = wm8753_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8753_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8753_reg,
+};
-static int wm8753_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8753_spi_probe(struct spi_device *spi)
{
- struct snd_soc_codec *codec;
struct wm8753_priv *wm8753;
+ int ret;
wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
if (wm8753 == NULL)
return -ENOMEM;
- codec = &wm8753->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
- codec->control_data = i2c;
- i2c_set_clientdata(i2c, wm8753);
-
- codec->dev = &i2c->dev;
+ wm8753->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8753);
- return wm8753_register(wm8753);
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai));
+ if (ret < 0)
+ kfree(wm8753);
+ return ret;
}
-static int wm8753_i2c_remove(struct i2c_client *client)
+static int __devexit wm8753_spi_remove(struct spi_device *spi)
{
- struct wm8753_priv *wm8753 = i2c_get_clientdata(client);
- wm8753_unregister(wm8753);
- return 0;
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
}
-static const struct i2c_device_id wm8753_i2c_id[] = {
- { "wm8753", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
-
-static struct i2c_driver wm8753_i2c_driver = {
+static struct spi_driver wm8753_spi_driver = {
.driver = {
- .name = "wm8753",
- .owner = THIS_MODULE,
+ .name = "wm8753-codec",
+ .owner = THIS_MODULE,
},
- .probe = wm8753_i2c_probe,
- .remove = wm8753_i2c_remove,
- .id_table = wm8753_i2c_id,
+ .probe = wm8753_spi_probe,
+ .remove = __devexit_p(wm8753_spi_remove),
};
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
-static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
-{
- struct spi_transfer t;
- struct spi_message m;
- u8 msg[2];
-
- if (len <= 0)
- return 0;
+#endif /* CONFIG_SPI_MASTER */
- msg[0] = data[0];
- msg[1] = data[1];
-
- spi_message_init(&m);
- memset(&t, 0, (sizeof t));
-
- t.tx_buf = &msg[0];
- t.len = len;
-
- spi_message_add_tail(&t, &m);
- spi_sync(spi, &m);
-
- return len;
-}
-
-static int __devinit wm8753_spi_probe(struct spi_device *spi)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8753_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
- struct snd_soc_codec *codec;
struct wm8753_priv *wm8753;
+ int ret;
wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
if (wm8753 == NULL)
return -ENOMEM;
- codec = &wm8753->codec;
- codec->control_data = spi;
- codec->hw_write = (hw_write_t)wm8753_spi_write;
- codec->dev = &spi->dev;
+ i2c_set_clientdata(i2c, wm8753);
+ wm8753->control_type = SND_SOC_I2C;
- dev_set_drvdata(&spi->dev, wm8753);
-
- return wm8753_register(wm8753);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai));
+ if (ret < 0)
+ kfree(wm8753);
+ return ret;
}
-static int __devexit wm8753_spi_remove(struct spi_device *spi)
+static __devexit int wm8753_i2c_remove(struct i2c_client *client)
{
- struct wm8753_priv *wm8753 = dev_get_drvdata(&spi->dev);
- wm8753_unregister(wm8753);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
-static struct spi_driver wm8753_spi_driver = {
+static const struct i2c_device_id wm8753_i2c_id[] = {
+ { "wm8753", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
+
+static struct i2c_driver wm8753_i2c_driver = {
.driver = {
- .name = "wm8753",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
+ .name = "wm8753-codec",
+ .owner = THIS_MODULE,
},
- .probe = wm8753_spi_probe,
- .remove = __devexit_p(wm8753_spi_remove),
+ .probe = wm8753_i2c_probe,
+ .remove = __devexit_p(wm8753_i2c_remove),
+ .id_table = wm8753_i2c_id,
};
#endif
static int __init wm8753_modinit(void)
{
- int ret;
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8753_i2c_driver);
- if (ret != 0)
- pr_err("Failed to register WM8753 I2C driver: %d\n", ret);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8753 I2C driver: %d\n",
+ ret);
+ }
#endif
#if defined(CONFIG_SPI_MASTER)
ret = spi_register_driver(&wm8753_spi_driver);
- if (ret != 0)
- pr_err("Failed to register WM8753 SPI driver: %d\n", ret);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8753 SPI driver: %d\n",
+ ret);
+ }
#endif
- return 0;
+ return ret;
}
module_init(wm8753_modinit);
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h
index 57b2ba244040..94edac144bcb 100644
--- a/sound/soc/codecs/wm8753.h
+++ b/sound/soc/codecs/wm8753.h
@@ -115,7 +115,4 @@
#define WM8753_DAI_HIFI 0
#define WM8753_DAI_VOICE 1
-extern struct snd_soc_dai wm8753_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_wm8753;
-
#endif
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index f8154e661524..04182c464e35 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -31,20 +31,13 @@
#include "wm8776.h"
-static struct snd_soc_codec *wm8776_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8776;
-
/* codec private data */
struct wm8776_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
u16 reg_cache[WM8776_CACHEREGNUM];
int sysclk[2];
};
-#ifdef CONFIG_SPI_MASTER
-static int wm8776_spi_write(struct spi_device *spi, const char *data, int len);
-#endif
-
static const u16 wm8776_reg[WM8776_CACHEREGNUM] = {
0x79, 0x79, 0x79, 0xff, 0xff, /* 4 */
0xff, 0x00, 0x90, 0x00, 0x00, /* 9 */
@@ -144,7 +137,7 @@ static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct snd_soc_codec *codec = dai->codec;
int reg, iface, master;
- switch (dai->id) {
+ switch (dai->driver->id) {
case WM8776_DAI_DAC:
reg = WM8776_DACIFCTRL;
master = 0x80;
@@ -226,7 +219,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
iface = 0;
- switch (dai->id) {
+ switch (dai->driver->id) {
case WM8776_DAI_DAC:
iface_reg = WM8776_DACIFCTRL;
master = 0x80;
@@ -260,7 +253,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
/* Only need to set MCLK/LRCLK ratio if we're master */
if (snd_soc_read(codec, WM8776_MSTRCTRL) & master) {
for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) {
- if (wm8776->sysclk[dai->id] / params_rate(params)
+ if (wm8776->sysclk[dai->driver->id] / params_rate(params)
== mclk_ratios[i])
break;
}
@@ -268,7 +261,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
if (i == ARRAY_SIZE(mclk_ratios)) {
dev_err(codec->dev,
"Unable to configure MCLK ratio %d/%d\n",
- wm8776->sysclk[dai->id], params_rate(params));
+ wm8776->sysclk[dai->driver->id], params_rate(params));
return -EINVAL;
}
@@ -298,9 +291,9 @@ static int wm8776_set_sysclk(struct snd_soc_dai *dai,
struct snd_soc_codec *codec = dai->codec;
struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
- BUG_ON(dai->id >= ARRAY_SIZE(wm8776->sysclk));
+ BUG_ON(dai->driver->id >= ARRAY_SIZE(wm8776->sysclk));
- wm8776->sysclk[dai->id] = freq;
+ wm8776->sysclk[dai->driver->id] = freq;
return 0;
}
@@ -350,10 +343,10 @@ static struct snd_soc_dai_ops wm8776_adc_ops = {
.set_sysclk = wm8776_set_sysclk,
};
-struct snd_soc_dai wm8776_dai[] = {
+static struct snd_soc_dai_driver wm8776_dai[] = {
{
- .name = "WM8776 Playback",
- .id = WM8776_DAI_DAC,
+ .name = "wm8776-hifi-playback",
+ .id = WM8776_DAI_DAC,
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -364,8 +357,8 @@ struct snd_soc_dai wm8776_dai[] = {
.ops = &wm8776_dac_ops,
},
{
- .name = "WM8776 Capture",
- .id = WM8776_DAI_ADC,
+ .name = "wm8776-hifi-capture",
+ .id = WM8776_DAI_ADC,
.capture = {
.stream_name = "Capture",
.channels_min = 2,
@@ -376,23 +369,17 @@ struct snd_soc_dai wm8776_dai[] = {
.ops = &wm8776_adc_ops,
},
};
-EXPORT_SYMBOL_GPL(wm8776_dai);
#ifdef CONFIG_PM
-static int wm8776_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8776_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8776_resume(struct platform_device *pdev)
+static int wm8776_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -415,27 +402,30 @@ static int wm8776_resume(struct platform_device *pdev)
#define wm8776_resume NULL
#endif
-static int wm8776_probe(struct platform_device *pdev)
+static int wm8776_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
+ struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
- if (wm8776_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8776->control_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
}
- socdev->card->codec = wm8776_codec;
- codec = wm8776_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ ret = wm8776_reset(codec);
if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
+ dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+ return ret;
}
+ wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ /* Latch the update bits; right channel only since we always
+ * update both. */
+ snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
+ snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
+
snd_soc_add_controls(codec, wm8776_snd_controls,
ARRAY_SIZE(wm8776_snd_controls));
snd_soc_dapm_new_controls(codec, wm8776_dapm_widgets,
@@ -443,169 +433,56 @@ static int wm8776_probe(struct platform_device *pdev)
snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
return ret;
-
-pcm_err:
- return ret;
}
/* power down chip */
-static int wm8776_remove(struct platform_device *pdev)
+static int wm8776_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
+ wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_wm8776 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm8776 = {
.probe = wm8776_probe,
.remove = wm8776_remove,
.suspend = wm8776_suspend,
.resume = wm8776_resume,
+ .set_bias_level = wm8776_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8776_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8776_reg,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8776);
-
-static int wm8776_register(struct wm8776_priv *wm8776,
- enum snd_soc_control_type control)
-{
- int ret, i;
- struct snd_soc_codec *codec = &wm8776->codec;
-
- if (wm8776_codec) {
- dev_err(codec->dev, "Another WM8776 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8776);
- codec->name = "WM8776";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8776_set_bias_level;
- codec->dai = wm8776_dai;
- codec->num_dai = ARRAY_SIZE(wm8776_dai);
- codec->reg_cache_size = WM8776_CACHEREGNUM;
- codec->reg_cache = &wm8776->reg_cache;
-
- memcpy(codec->reg_cache, wm8776_reg, sizeof(wm8776_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
- }
-
- for (i = 0; i < ARRAY_SIZE(wm8776_dai); i++)
- wm8776_dai[i].dev = codec->dev;
-
- ret = wm8776_reset(codec);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
- goto err;
- }
-
- wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- /* Latch the update bits; right channel only since we always
- * update both. */
- snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
- snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
-
- wm8776_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8776);
- return ret;
-}
-
-static void wm8776_unregister(struct wm8776_priv *wm8776)
-{
- wm8776_set_bias_level(&wm8776->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
- snd_soc_unregister_codec(&wm8776->codec);
- kfree(wm8776);
- wm8776_codec = NULL;
-}
#if defined(CONFIG_SPI_MASTER)
-static int wm8776_spi_write(struct spi_device *spi, const char *data, int len)
-{
- struct spi_transfer t;
- struct spi_message m;
- u8 msg[2];
-
- if (len <= 0)
- return 0;
-
- msg[0] = data[0];
- msg[1] = data[1];
-
- spi_message_init(&m);
- memset(&t, 0, (sizeof t));
-
- t.tx_buf = &msg[0];
- t.len = len;
-
- spi_message_add_tail(&t, &m);
- spi_sync(spi, &m);
-
- return len;
-}
-
static int __devinit wm8776_spi_probe(struct spi_device *spi)
{
- struct snd_soc_codec *codec;
struct wm8776_priv *wm8776;
+ int ret;
wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
if (wm8776 == NULL)
return -ENOMEM;
- codec = &wm8776->codec;
- codec->control_data = spi;
- codec->hw_write = (hw_write_t)wm8776_spi_write;
- codec->dev = &spi->dev;
+ wm8776->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8776);
- dev_set_drvdata(&spi->dev, wm8776);
-
- return wm8776_register(wm8776, SND_SOC_SPI);
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
+ if (ret < 0)
+ kfree(wm8776);
+ return ret;
}
static int __devexit wm8776_spi_remove(struct spi_device *spi)
{
- struct wm8776_priv *wm8776 = dev_get_drvdata(&spi->dev);
-
- wm8776_unregister(wm8776);
-
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
return 0;
}
static struct spi_driver wm8776_spi_driver = {
.driver = {
- .name = "wm8776",
- .bus = &spi_bus_type,
+ .name = "wm8776-codec",
.owner = THIS_MODULE,
},
.probe = wm8776_spi_probe,
@@ -618,27 +495,26 @@ static __devinit int wm8776_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8776_priv *wm8776;
- struct snd_soc_codec *codec;
+ int ret;
wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
if (wm8776 == NULL)
return -ENOMEM;
- codec = &wm8776->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
i2c_set_clientdata(i2c, wm8776);
- codec->control_data = i2c;
-
- codec->dev = &i2c->dev;
+ wm8776->control_type = SND_SOC_I2C;
- return wm8776_register(wm8776, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
+ if (ret < 0)
+ kfree(wm8776);
+ return ret;
}
static __devexit int wm8776_i2c_remove(struct i2c_client *client)
{
- struct wm8776_priv *wm8776 = i2c_get_clientdata(client);
- wm8776_unregister(wm8776);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -650,7 +526,7 @@ MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id);
static struct i2c_driver wm8776_i2c_driver = {
.driver = {
- .name = "wm8776",
+ .name = "wm8776-codec",
.owner = THIS_MODULE,
},
.probe = wm8776_i2c_probe,
@@ -661,22 +537,22 @@ static struct i2c_driver wm8776_i2c_driver = {
static int __init wm8776_modinit(void)
{
- int ret;
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8776_i2c_driver);
if (ret != 0) {
- printk(KERN_ERR "Failed to register WM8776 I2C driver: %d\n",
+ printk(KERN_ERR "Failed to register wm8776 I2C driver: %d\n",
ret);
}
#endif
#if defined(CONFIG_SPI_MASTER)
ret = spi_register_driver(&wm8776_spi_driver);
if (ret != 0) {
- printk(KERN_ERR "Failed to register WM8776 SPI driver: %d\n",
+ printk(KERN_ERR "Failed to register wm8776 SPI driver: %d\n",
ret);
}
#endif
- return 0;
+ return ret;
}
module_init(wm8776_modinit);
diff --git a/sound/soc/codecs/wm8776.h b/sound/soc/codecs/wm8776.h
index 6606d25d2d83..4cf1c8e0bfc9 100644
--- a/sound/soc/codecs/wm8776.h
+++ b/sound/soc/codecs/wm8776.h
@@ -45,7 +45,4 @@
#define WM8776_DAI_DAC 0
#define WM8776_DAI_ADC 1
-extern struct snd_soc_dai wm8776_dai[];
-extern struct snd_soc_codec_device soc_codec_dev_wm8776;
-
#endif
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
new file mode 100644
index 000000000000..4599e8e95aa2
--- /dev/null
+++ b/sound/soc/codecs/wm8804.c
@@ -0,0 +1,833 @@
+/*
+ * wm8804.c -- WM8804 S/PDIF transceiver driver
+ *
+ * Copyright 2010 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8804.h"
+
+#define WM8804_NUM_SUPPLIES 2
+static const char *wm8804_supply_names[WM8804_NUM_SUPPLIES] = {
+ "PVDD",
+ "DVDD"
+};
+
+static const u8 wm8804_reg_defs[] = {
+ 0x05, /* R0 - RST/DEVID1 */
+ 0x88, /* R1 - DEVID2 */
+ 0x04, /* R2 - DEVREV */
+ 0x21, /* R3 - PLL1 */
+ 0xFD, /* R4 - PLL2 */
+ 0x36, /* R5 - PLL3 */
+ 0x07, /* R6 - PLL4 */
+ 0x16, /* R7 - PLL5 */
+ 0x18, /* R8 - PLL6 */
+ 0xFF, /* R9 - SPDMODE */
+ 0x00, /* R10 - INTMASK */
+ 0x00, /* R11 - INTSTAT */
+ 0x00, /* R12 - SPDSTAT */
+ 0x00, /* R13 - RXCHAN1 */
+ 0x00, /* R14 - RXCHAN2 */
+ 0x00, /* R15 - RXCHAN3 */
+ 0x00, /* R16 - RXCHAN4 */
+ 0x00, /* R17 - RXCHAN5 */
+ 0x00, /* R18 - SPDTX1 */
+ 0x00, /* R19 - SPDTX2 */
+ 0x00, /* R20 - SPDTX3 */
+ 0x71, /* R21 - SPDTX4 */
+ 0x0B, /* R22 - SPDTX5 */
+ 0x70, /* R23 - GPO0 */
+ 0x57, /* R24 - GPO1 */
+ 0x00, /* R25 */
+ 0x42, /* R26 - GPO2 */
+ 0x06, /* R27 - AIFTX */
+ 0x06, /* R28 - AIFRX */
+ 0x80, /* R29 - SPDRX1 */
+ 0x07, /* R30 - PWRDN */
+};
+
+struct wm8804_priv {
+ enum snd_soc_control_type control_type;
+ struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES];
+ struct notifier_block disable_nb[WM8804_NUM_SUPPLIES];
+ struct snd_soc_codec *codec;
+};
+
+static int txsrc_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
+static int txsrc_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
+/*
+ * We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8804_REGULATOR_EVENT(n) \
+static int wm8804_regulator_event_##n(struct notifier_block *nb, \
+ unsigned long event, void *data) \
+{ \
+ struct wm8804_priv *wm8804 = container_of(nb, struct wm8804_priv, \
+ disable_nb[n]); \
+ if (event & REGULATOR_EVENT_DISABLE) { \
+ wm8804->codec->cache_sync = 1; \
+ } \
+ return 0; \
+}
+
+WM8804_REGULATOR_EVENT(0)
+WM8804_REGULATOR_EVENT(1)
+
+static const char *txsrc_text[] = { "S/PDIF RX", "AIF" };
+static const SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text);
+
+static const struct snd_kcontrol_new wm8804_snd_controls[] = {
+ SOC_ENUM_EXT("Input Source", txsrc, txsrc_get, txsrc_put),
+ SOC_SINGLE("TX Playback Switch", WM8804_PWRDN, 2, 1, 1),
+ SOC_SINGLE("AIF Playback Switch", WM8804_PWRDN, 4, 1, 1)
+};
+
+static int txsrc_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec;
+ unsigned int src;
+
+ codec = snd_kcontrol_chip(kcontrol);
+ src = snd_soc_read(codec, WM8804_SPDTX4);
+ if (src & 0x40)
+ ucontrol->value.integer.value[0] = 1;
+ else
+ ucontrol->value.integer.value[0] = 0;
+
+ return 0;
+}
+
+static int txsrc_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec;
+ unsigned int src, txpwr;
+
+ codec = snd_kcontrol_chip(kcontrol);
+
+ if (ucontrol->value.integer.value[0] != 0
+ && ucontrol->value.integer.value[0] != 1)
+ return -EINVAL;
+
+ src = snd_soc_read(codec, WM8804_SPDTX4);
+ switch ((src & 0x40) >> 6) {
+ case 0:
+ if (!ucontrol->value.integer.value[0])
+ return 0;
+ break;
+ case 1:
+ if (ucontrol->value.integer.value[1])
+ return 0;
+ break;
+ }
+
+ /* save the current power state of the transmitter */
+ txpwr = snd_soc_read(codec, WM8804_PWRDN) & 0x4;
+ /* power down the transmitter */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x4);
+ /* set the tx source */
+ snd_soc_update_bits(codec, WM8804_SPDTX4, 0x40,
+ ucontrol->value.integer.value[0] << 6);
+
+ if (ucontrol->value.integer.value[0]) {
+ /* power down the receiver */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x2, 0x2);
+ /* power up the AIF */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x10, 0);
+ } else {
+ /* don't power down the AIF -- may be used as an output */
+ /* power up the receiver */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x2, 0);
+ }
+
+ /* restore the transmitter's configuration */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, txpwr);
+
+ return 0;
+}
+
+static int wm8804_volatile(unsigned int reg)
+{
+ switch (reg) {
+ case WM8804_RST_DEVID1:
+ case WM8804_DEVID2:
+ case WM8804_DEVREV:
+ case WM8804_INTSTAT:
+ case WM8804_SPDSTAT:
+ case WM8804_RXCHAN1:
+ case WM8804_RXCHAN2:
+ case WM8804_RXCHAN3:
+ case WM8804_RXCHAN4:
+ case WM8804_RXCHAN5:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int wm8804_reset(struct snd_soc_codec *codec)
+{
+ return snd_soc_write(codec, WM8804_RST_DEVID1, 0x0);
+}
+
+static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec;
+ u16 format, master, bcp, lrp;
+
+ codec = dai->codec;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ format = 0x2;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ format = 0x0;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ format = 0x1;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ format = 0x3;
+ break;
+ default:
+ dev_err(dai->dev, "Unknown dai format\n");
+ return -EINVAL;
+ }
+
+ /* set data format */
+ snd_soc_update_bits(codec, WM8804_AIFTX, 0x3, format);
+ snd_soc_update_bits(codec, WM8804_AIFRX, 0x3, format);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ master = 1;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ master = 0;
+ break;
+ default:
+ dev_err(dai->dev, "Unknown master/slave configuration\n");
+ return -EINVAL;
+ }
+
+ /* set master/slave mode */
+ snd_soc_update_bits(codec, WM8804_AIFRX, 0x40, master << 6);
+
+ bcp = lrp = 0;
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ bcp = lrp = 1;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ bcp = 1;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ lrp = 1;
+ break;
+ default:
+ dev_err(dai->dev, "Unknown polarity configuration\n");
+ return -EINVAL;
+ }
+
+ /* set frame inversion */
+ snd_soc_update_bits(codec, WM8804_AIFTX, 0x10 | 0x20,
+ (bcp << 4) | (lrp << 5));
+ snd_soc_update_bits(codec, WM8804_AIFRX, 0x10 | 0x20,
+ (bcp << 4) | (lrp << 5));
+ return 0;
+}
+
+static int wm8804_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec;
+ u16 blen;
+
+ codec = dai->codec;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ blen = 0x0;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ blen = 0x1;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ blen = 0x2;
+ break;
+ default:
+ dev_err(dai->dev, "Unsupported word length: %u\n",
+ params_format(params));
+ return -EINVAL;
+ }
+
+ /* set word length */
+ snd_soc_update_bits(codec, WM8804_AIFTX, 0xc, blen << 2);
+ snd_soc_update_bits(codec, WM8804_AIFRX, 0xc, blen << 2);
+
+ return 0;
+}
+
+struct pll_div {
+ u32 prescale:1;
+ u32 mclkdiv:1;
+ u32 freqmode:2;
+ u32 n:4;
+ u32 k:22;
+};
+
+/* PLL rate to output rate divisions */
+static struct {
+ unsigned int div;
+ unsigned int freqmode;
+ unsigned int mclkdiv;
+} post_table[] = {
+ { 2, 0, 0 },
+ { 4, 0, 1 },
+ { 4, 1, 0 },
+ { 8, 1, 1 },
+ { 8, 2, 0 },
+ { 16, 2, 1 },
+ { 12, 3, 0 },
+ { 24, 3, 1 }
+};
+
+#define FIXED_PLL_SIZE ((1ULL << 22) * 10)
+static int pll_factors(struct pll_div *pll_div, unsigned int target,
+ unsigned int source)
+{
+ u64 Kpart;
+ unsigned long int K, Ndiv, Nmod, tmp;
+ int i;
+
+ /*
+ * Scale the output frequency up; the PLL should run in the
+ * region of 90-100MHz.
+ */
+ for (i = 0; i < ARRAY_SIZE(post_table); i++) {
+ tmp = target * post_table[i].div;
+ if (tmp >= 90000000 && tmp <= 100000000) {
+ pll_div->freqmode = post_table[i].freqmode;
+ pll_div->mclkdiv = post_table[i].mclkdiv;
+ target *= post_table[i].div;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(post_table)) {
+ pr_err("%s: Unable to scale output frequency: %uHz\n",
+ __func__, target);
+ return -EINVAL;
+ }
+
+ pll_div->prescale = 0;
+ Ndiv = target / source;
+ if (Ndiv < 5) {
+ source >>= 1;
+ pll_div->prescale = 1;
+ Ndiv = target / source;
+ }
+
+ if (Ndiv < 5 || Ndiv > 13) {
+ pr_err("%s: WM8804 N value is not within the recommended range: %lu\n",
+ __func__, Ndiv);
+ return -EINVAL;
+ }
+ pll_div->n = Ndiv;
+
+ Nmod = target % source;
+ Kpart = FIXED_PLL_SIZE * (u64)Nmod;
+
+ do_div(Kpart, source);
+
+ K = Kpart & 0xffffffff;
+ if ((K % 10) >= 5)
+ K += 5;
+ K /= 10;
+ pll_div->k = K;
+
+ return 0;
+}
+
+static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
+ int source, unsigned int freq_in,
+ unsigned int freq_out)
+{
+ struct snd_soc_codec *codec;
+
+ codec = dai->codec;
+ if (!freq_in || !freq_out) {
+ /* disable the PLL */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1);
+ return 0;
+ } else {
+ int ret;
+ struct pll_div pll_div;
+
+ ret = pll_factors(&pll_div, freq_out, freq_in);
+ if (ret)
+ return ret;
+
+ /* power down the PLL before reprogramming it */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1);
+
+ if (!freq_in || !freq_out)
+ return 0;
+
+ /* set PLLN and PRESCALE */
+ snd_soc_update_bits(codec, WM8804_PLL4, 0xf | 0x10,
+ pll_div.n | (pll_div.prescale << 4));
+ /* set mclkdiv and freqmode */
+ snd_soc_update_bits(codec, WM8804_PLL5, 0x3 | 0x8,
+ pll_div.freqmode | (pll_div.mclkdiv << 3));
+ /* set PLLK */
+ snd_soc_write(codec, WM8804_PLL1, pll_div.k & 0xff);
+ snd_soc_write(codec, WM8804_PLL2, (pll_div.k >> 8) & 0xff);
+ snd_soc_write(codec, WM8804_PLL3, pll_div.k >> 16);
+
+ /* power up the PLL */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0);
+ }
+
+ return 0;
+}
+
+static int wm8804_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec;
+
+ codec = dai->codec;
+
+ switch (clk_id) {
+ case WM8804_TX_CLKSRC_MCLK:
+ if ((freq >= 10000000 && freq <= 14400000)
+ || (freq >= 16280000 && freq <= 27000000))
+ snd_soc_update_bits(codec, WM8804_PLL6, 0x80, 0x80);
+ else {
+ dev_err(dai->dev, "OSCCLOCK is not within the "
+ "recommended range: %uHz\n", freq);
+ return -EINVAL;
+ }
+ break;
+ case WM8804_TX_CLKSRC_PLL:
+ snd_soc_update_bits(codec, WM8804_PLL6, 0x80, 0);
+ break;
+ case WM8804_CLKOUT_SRC_CLK1:
+ snd_soc_update_bits(codec, WM8804_PLL6, 0x8, 0);
+ break;
+ case WM8804_CLKOUT_SRC_OSCCLK:
+ snd_soc_update_bits(codec, WM8804_PLL6, 0x8, 0x8);
+ break;
+ default:
+ dev_err(dai->dev, "Unknown clock source: %d\n", clk_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wm8804_set_clkdiv(struct snd_soc_dai *dai,
+ int div_id, int div)
+{
+ struct snd_soc_codec *codec;
+
+ codec = dai->codec;
+ switch (div_id) {
+ case WM8804_CLKOUT_DIV:
+ snd_soc_update_bits(codec, WM8804_PLL5, 0x30,
+ (div & 0x3) << 4);
+ break;
+ default:
+ dev_err(dai->dev, "Unknown clock divider: %d\n", div_id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void wm8804_sync_cache(struct snd_soc_codec *codec)
+{
+ short i;
+ u8 *cache;
+
+ if (!codec->cache_sync)
+ return;
+
+ codec->cache_only = 0;
+ cache = codec->reg_cache;
+ for (i = 0; i < codec->driver->reg_cache_size; i++) {
+ if (i == WM8804_RST_DEVID1 || cache[i] == wm8804_reg_defs[i])
+ continue;
+ snd_soc_write(codec, i, cache[i]);
+ }
+ codec->cache_sync = 0;
+}
+
+static int wm8804_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ int ret;
+ struct wm8804_priv *wm8804;
+
+ wm8804 = snd_soc_codec_get_drvdata(codec);
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ /* power up the OSC and the PLL */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0);
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
+ wm8804->supplies);
+ if (ret) {
+ dev_err(codec->dev,
+ "Failed to enable supplies: %d\n",
+ ret);
+ return ret;
+ }
+ wm8804_sync_cache(codec);
+ }
+ /* power down the OSC and the PLL */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9);
+ break;
+ case SND_SOC_BIAS_OFF:
+ /* power down the OSC and the PLL */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9);
+ regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies),
+ wm8804->supplies);
+ break;
+ }
+
+ codec->bias_level = level;
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8804_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int wm8804_resume(struct snd_soc_codec *codec)
+{
+ wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ return 0;
+}
+#else
+#define wm8804_suspend NULL
+#define wm8804_resume NULL
+#endif
+
+static int wm8804_remove(struct snd_soc_codec *codec)
+{
+ struct wm8804_priv *wm8804;
+ int i;
+
+ wm8804 = snd_soc_codec_get_drvdata(codec);
+ wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i)
+ regulator_unregister_notifier(wm8804->supplies[i].consumer,
+ &wm8804->disable_nb[i]);
+ regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
+ return 0;
+}
+
+static int wm8804_probe(struct snd_soc_codec *codec)
+{
+ struct wm8804_priv *wm8804;
+ int i, id1, id2, ret;
+
+ wm8804 = snd_soc_codec_get_drvdata(codec);
+ wm8804->codec = codec;
+
+ codec->idle_bias_off = 1;
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, wm8804->control_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
+ wm8804->supplies[i].supply = wm8804_supply_names[i];
+
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies),
+ wm8804->supplies);
+ if (ret) {
+ dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0;
+ wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1;
+
+ /* This should really be moved into the regulator core */
+ for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) {
+ ret = regulator_register_notifier(wm8804->supplies[i].consumer,
+ &wm8804->disable_nb[i]);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to register regulator notifier: %d\n",
+ ret);
+ }
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
+ wm8804->supplies);
+ if (ret) {
+ dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ goto err_reg_get;
+ }
+
+ id1 = snd_soc_read(codec, WM8804_RST_DEVID1);
+ if (id1 < 0) {
+ dev_err(codec->dev, "Failed to read device ID: %d\n", id1);
+ ret = id1;
+ goto err_reg_enable;
+ }
+
+ id2 = snd_soc_read(codec, WM8804_DEVID2);
+ if (id2 < 0) {
+ dev_err(codec->dev, "Failed to read device ID: %d\n", id2);
+ ret = id2;
+ goto err_reg_enable;
+ }
+
+ id2 = (id2 << 8) | id1;
+
+ if (id2 != ((wm8804_reg_defs[WM8804_DEVID2] << 8)
+ | wm8804_reg_defs[WM8804_RST_DEVID1])) {
+ dev_err(codec->dev, "Invalid device ID: %#x\n", id2);
+ ret = -EINVAL;
+ goto err_reg_enable;
+ }
+
+ ret = snd_soc_read(codec, WM8804_DEVREV);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read device revision: %d\n",
+ ret);
+ goto err_reg_enable;
+ }
+ dev_info(codec->dev, "revision %c\n", ret + 'A');
+
+ ret = wm8804_reset(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+ goto err_reg_enable;
+ }
+
+ wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ snd_soc_add_controls(codec, wm8804_snd_controls,
+ ARRAY_SIZE(wm8804_snd_controls));
+ return 0;
+
+err_reg_enable:
+ regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
+err_reg_get:
+ regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
+ return ret;
+}
+
+static struct snd_soc_dai_ops wm8804_dai_ops = {
+ .hw_params = wm8804_hw_params,
+ .set_fmt = wm8804_set_fmt,
+ .set_sysclk = wm8804_set_sysclk,
+ .set_clkdiv = wm8804_set_clkdiv,
+ .set_pll = wm8804_set_pll
+};
+
+#define WM8804_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver wm8804_dai = {
+ .name = "wm8804-spdif",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = WM8804_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = WM8804_FORMATS,
+ },
+ .ops = &wm8804_dai_ops,
+ .symmetric_rates = 1
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
+ .probe = wm8804_probe,
+ .remove = wm8804_remove,
+ .suspend = wm8804_suspend,
+ .resume = wm8804_resume,
+ .set_bias_level = wm8804_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8804_reg_defs),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = wm8804_reg_defs,
+ .volatile_register = wm8804_volatile
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8804_spi_probe(struct spi_device *spi)
+{
+ struct wm8804_priv *wm8804;
+ int ret;
+
+ wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL);
+ if (!wm8804)
+ return -ENOMEM;
+
+ wm8804->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8804);
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8804, &wm8804_dai, 1);
+ if (ret < 0)
+ kfree(wm8804);
+ return ret;
+}
+
+static int __devexit wm8804_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
+}
+
+static struct spi_driver wm8804_spi_driver = {
+ .driver = {
+ .name = "wm8804",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8804_spi_probe,
+ .remove = __devexit_p(wm8804_spi_remove)
+};
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8804_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8804_priv *wm8804;
+ int ret;
+
+ wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL);
+ if (!wm8804)
+ return -ENOMEM;
+
+ wm8804->control_type = SND_SOC_I2C;
+ i2c_set_clientdata(i2c, wm8804);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8804, &wm8804_dai, 1);
+ if (ret < 0)
+ kfree(wm8804);
+ return ret;
+}
+
+static __devexit int wm8804_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id wm8804_i2c_id[] = {
+ { "wm8804", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id);
+
+static struct i2c_driver wm8804_i2c_driver = {
+ .driver = {
+ .name = "wm8804",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8804_i2c_probe,
+ .remove = __devexit_p(wm8804_i2c_remove),
+ .id_table = wm8804_i2c_id
+};
+#endif
+
+static int __init wm8804_modinit(void)
+{
+ int ret = 0;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8804_i2c_driver);
+ if (ret) {
+ printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n",
+ ret);
+ }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ ret = spi_register_driver(&wm8804_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8804 SPI driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
+}
+module_init(wm8804_modinit);
+
+static void __exit wm8804_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8804_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&wm8804_spi_driver);
+#endif
+}
+module_exit(wm8804_exit);
+
+MODULE_DESCRIPTION("ASoC WM8804 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8804.h b/sound/soc/codecs/wm8804.h
new file mode 100644
index 000000000000..8ec14f5573cb
--- /dev/null
+++ b/sound/soc/codecs/wm8804.h
@@ -0,0 +1,61 @@
+/*
+ * wm8804.h -- WM8804 S/PDIF transceiver driver
+ *
+ * Copyright 2010 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.
+ */
+
+#ifndef _WM8804_H
+#define _WM8804_H
+
+/*
+ * Register values.
+ */
+#define WM8804_RST_DEVID1 0x00
+#define WM8804_DEVID2 0x01
+#define WM8804_DEVREV 0x02
+#define WM8804_PLL1 0x03
+#define WM8804_PLL2 0x04
+#define WM8804_PLL3 0x05
+#define WM8804_PLL4 0x06
+#define WM8804_PLL5 0x07
+#define WM8804_PLL6 0x08
+#define WM8804_SPDMODE 0x09
+#define WM8804_INTMASK 0x0A
+#define WM8804_INTSTAT 0x0B
+#define WM8804_SPDSTAT 0x0C
+#define WM8804_RXCHAN1 0x0D
+#define WM8804_RXCHAN2 0x0E
+#define WM8804_RXCHAN3 0x0F
+#define WM8804_RXCHAN4 0x10
+#define WM8804_RXCHAN5 0x11
+#define WM8804_SPDTX1 0x12
+#define WM8804_SPDTX2 0x13
+#define WM8804_SPDTX3 0x14
+#define WM8804_SPDTX4 0x15
+#define WM8804_SPDTX5 0x16
+#define WM8804_GPO0 0x17
+#define WM8804_GPO1 0x18
+#define WM8804_GPO2 0x1A
+#define WM8804_AIFTX 0x1B
+#define WM8804_AIFRX 0x1C
+#define WM8804_SPDRX1 0x1D
+#define WM8804_PWRDN 0x1E
+
+#define WM8804_REGISTER_COUNT 30
+#define WM8804_MAX_REGISTER 0x1E
+
+#define WM8804_TX_CLKSRC_MCLK 1
+#define WM8804_TX_CLKSRC_PLL 2
+
+#define WM8804_CLKOUT_SRC_CLK1 3
+#define WM8804_CLKOUT_SRC_OSCCLK 4
+
+#define WM8804_CLKOUT_DIV 1
+
+#endif /* _WM8804_H */
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 5da17a704e5a..b4f11724a63f 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/spi/spi.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -137,11 +138,8 @@
#define WM8900_LRC_MASK 0xfc00
-struct snd_soc_codec_device soc_codec_dev_wm8900;
-
struct wm8900_priv {
- struct snd_soc_codec codec;
-
+ enum snd_soc_control_type control_type;
u16 reg_cache[WM8900_MAXREG];
u32 fll_in; /* FLL input frequency */
@@ -627,8 +625,7 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 reg;
reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60;
@@ -1015,8 +1012,8 @@ static struct snd_soc_dai_ops wm8900_dai_ops = {
.digital_mute = wm8900_digital_mute,
};
-struct snd_soc_dai wm8900_dai = {
- .name = "WM8900 HiFi",
+static struct snd_soc_dai_driver wm8900_dai = {
+ .name = "wm8900-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
@@ -1033,7 +1030,6 @@ struct snd_soc_dai wm8900_dai = {
},
.ops = &wm8900_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8900_dai);
static int wm8900_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
@@ -1128,10 +1124,8 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8900_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
int fll_out = wm8900->fll_out;
int fll_in = wm8900->fll_in;
@@ -1140,7 +1134,7 @@ static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
/* Stop the FLL in an orderly fashion */
ret = wm8900_set_fll(codec, 0, 0, 0);
if (ret != 0) {
- dev_err(&pdev->dev, "Failed to stop FLL\n");
+ dev_err(codec->dev, "Failed to stop FLL\n");
return ret;
}
@@ -1152,10 +1146,8 @@ static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int wm8900_resume(struct platform_device *pdev)
+static int wm8900_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
u16 *cache;
int i, ret;
@@ -1176,7 +1168,7 @@ static int wm8900_resume(struct platform_device *pdev)
ret = wm8900_set_fll(codec, 0, fll_in, fll_out);
if (ret != 0) {
- dev_err(&pdev->dev, "Failed to restart FLL\n");
+ dev_err(codec->dev, "Failed to restart FLL\n");
return ret;
}
}
@@ -1186,60 +1178,32 @@ static int wm8900_resume(struct platform_device *pdev)
snd_soc_write(codec, i, cache[i]);
kfree(cache);
} else
- dev_err(&pdev->dev, "Unable to allocate register cache\n");
+ dev_err(codec->dev, "Unable to allocate register cache\n");
return 0;
}
-static struct snd_soc_codec *wm8900_codec;
-
-static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int wm8900_probe(struct snd_soc_codec *codec)
{
- struct wm8900_priv *wm8900;
- struct snd_soc_codec *codec;
- unsigned int reg;
- int ret;
-
- wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
- if (wm8900 == NULL)
- return -ENOMEM;
+ struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0, reg;
- codec = &wm8900->codec;
- snd_soc_codec_set_drvdata(codec, wm8900);
- codec->reg_cache = &wm8900->reg_cache[0];
- codec->reg_cache_size = WM8900_MAXREG;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "WM8900";
- codec->owner = THIS_MODULE;
- codec->dai = &wm8900_dai;
- codec->num_dai = 1;
- codec->control_data = i2c;
- codec->set_bias_level = wm8900_set_bias_level;
- codec->volatile_register = wm8900_volatile_register;
- codec->dev = &i2c->dev;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8900->control_type);
if (ret != 0) {
- dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
}
reg = snd_soc_read(codec, WM8900_REG_ID);
if (reg != 0x8900) {
- dev_err(&i2c->dev, "Device is not a WM8900 - ID %x\n", reg);
- ret = -ENODEV;
- goto err;
+ dev_err(codec->dev, "Device is not a WM8900 - ID %x\n", reg);
+ return -ENODEV;
}
/* Read back from the chip */
reg = snd_soc_read(codec, WM8900_REG_POWER1);
reg = (reg >> 12) & 0xf;
- dev_info(&i2c->dev, "WM8900 revision %d\n", reg);
+ dev_info(codec->dev, "WM8900 revision %d\n", reg);
wm8900_reset(codec);
@@ -1271,43 +1235,94 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
/* Set the DAC and mixer output bias */
snd_soc_write(codec, WM8900_REG_OUTBIASCTL, 0x81);
- wm8900_dai.dev = &i2c->dev;
+ snd_soc_add_controls(codec, wm8900_snd_controls,
+ ARRAY_SIZE(wm8900_snd_controls));
+ wm8900_add_widgets(codec);
- wm8900_codec = codec;
+ return 0;
+}
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
+/* power down chip */
+static int wm8900_remove(struct snd_soc_codec *codec)
+{
+ wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
- ret = snd_soc_register_dai(&wm8900_dai);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+static struct snd_soc_codec_driver soc_codec_dev_wm8900 = {
+ .probe = wm8900_probe,
+ .remove = wm8900_remove,
+ .suspend = wm8900_suspend,
+ .resume = wm8900_resume,
+ .set_bias_level = wm8900_set_bias_level,
+ .volatile_register = wm8900_volatile_register,
+ .reg_cache_size = ARRAY_SIZE(wm8900_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8900_reg_defaults,
+};
- return ret;
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8900_spi_probe(struct spi_device *spi)
+{
+ struct wm8900_priv *wm8900;
+ int ret;
+
+ wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
+ if (wm8900 == NULL)
+ return -ENOMEM;
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8900);
- wm8900_codec = NULL;
+ wm8900->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8900);
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8900, &wm8900_dai, 1);
+ if (ret < 0)
+ kfree(wm8900);
return ret;
}
-static __devexit int wm8900_i2c_remove(struct i2c_client *client)
+static int __devexit wm8900_spi_remove(struct spi_device *spi)
{
- snd_soc_unregister_dai(&wm8900_dai);
- snd_soc_unregister_codec(wm8900_codec);
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
+}
- wm8900_set_bias_level(wm8900_codec, SND_SOC_BIAS_OFF);
+static struct spi_driver wm8900_spi_driver = {
+ .driver = {
+ .name = "wm8900-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8900_spi_probe,
+ .remove = __devexit_p(wm8900_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8900_priv *wm8900;
+ int ret;
+
+ wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
+ if (wm8900 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm8900);
+ wm8900->control_type = SND_SOC_I2C;
- wm8900_dai.dev = NULL;
- kfree(snd_soc_codec_get_drvdata(wm8900_codec));
- wm8900_codec = NULL;
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8900, &wm8900_dai, 1);
+ if (ret < 0)
+ kfree(wm8900);
+ return ret;
+}
+static __devexit int wm8900_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1319,71 +1334,44 @@ MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id);
static struct i2c_driver wm8900_i2c_driver = {
.driver = {
- .name = "WM8900",
+ .name = "wm8900-codec",
.owner = THIS_MODULE,
},
- .probe = wm8900_i2c_probe,
- .remove = __devexit_p(wm8900_i2c_remove),
+ .probe = wm8900_i2c_probe,
+ .remove = __devexit_p(wm8900_i2c_remove),
.id_table = wm8900_i2c_id,
};
+#endif
-static int wm8900_probe(struct platform_device *pdev)
+static int __init wm8900_modinit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
int ret = 0;
-
- if (!wm8900_codec) {
- dev_err(&pdev->dev, "I2C client not yet instantiated\n");
- return -ENODEV;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8900_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8900 I2C driver: %d\n",
+ ret);
}
-
- codec = wm8900_codec;
- socdev->card->codec = codec;
-
- /* Register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to register new PCMs\n");
- goto pcm_err;
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ ret = spi_register_driver(&wm8900_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8900 SPI driver: %d\n",
+ ret);
}
-
- snd_soc_add_controls(codec, wm8900_snd_controls,
- ARRAY_SIZE(wm8900_snd_controls));
- wm8900_add_widgets(codec);
-
-pcm_err:
+#endif
return ret;
}
-
-/* power down chip */
-static int wm8900_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8900 = {
- .probe = wm8900_probe,
- .remove = wm8900_remove,
- .suspend = wm8900_suspend,
- .resume = wm8900_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900);
-
-static int __init wm8900_modinit(void)
-{
- return i2c_add_driver(&wm8900_i2c_driver);
-}
module_init(wm8900_modinit);
static void __exit wm8900_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8900_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&wm8900_spi_driver);
+#endif
}
module_exit(wm8900_exit);
diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h
index fd15007d10c7..583f257e799b 100644
--- a/sound/soc/codecs/wm8900.h
+++ b/sound/soc/codecs/wm8900.h
@@ -52,7 +52,4 @@
#define WM8900_DAC_CLKDIV_5_5 0x14
#define WM8900_DAC_CLKDIV_6 0x18
-extern struct snd_soc_dai wm8900_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8900;
-
#endif
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index bf08282d5ee5..622b60238a82 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -213,10 +213,11 @@ static u16 wm8903_reg_defaults[] = {
};
struct wm8903_priv {
- struct snd_soc_codec codec;
+
u16 reg_cache[ARRAY_SIZE(wm8903_reg_defaults)];
int sysclk;
+ int irq;
/* Reference counts */
int class_w_users;
@@ -252,7 +253,6 @@ static int wm8903_volatile_register(unsigned int reg)
static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
{
u16 reg[5];
- struct i2c_client *i2c = codec->control_data;
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
BUG_ON(start > 48);
@@ -262,7 +262,7 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0,
reg[0] | WM8903_WSEQ_ENA);
- dev_dbg(&i2c->dev, "Starting sequence at %d\n", start);
+ dev_dbg(codec->dev, "Starting sequence at %d\n", start);
snd_soc_write(codec, WM8903_WRITE_SEQUENCER_3,
start | WM8903_WSEQ_START);
@@ -277,7 +277,7 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
reg[4] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_4);
} while (reg[4] & WM8903_WSEQ_BUSY);
- dev_dbg(&i2c->dev, "Sequence complete\n");
+ dev_dbg(codec->dev, "Sequence complete\n");
/* Disable the sequencer again if we enabled it */
snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]);
@@ -422,7 +422,6 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
struct snd_soc_codec *codec = widget->codec;
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
- struct i2c_client *i2c = codec->control_data;
u16 reg;
int ret;
@@ -431,7 +430,7 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
/* Turn it off if we're about to enable bypass */
if (ucontrol->value.integer.value[0]) {
if (wm8903->class_w_users == 0) {
- dev_dbg(&i2c->dev, "Disabling Class W\n");
+ dev_dbg(codec->dev, "Disabling Class W\n");
snd_soc_write(codec, WM8903_CLASS_W_0, reg &
~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V));
}
@@ -444,14 +443,14 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
/* If we've just disabled the last bypass path turn Class W on */
if (!ucontrol->value.integer.value[0]) {
if (wm8903->class_w_users == 1) {
- dev_dbg(&i2c->dev, "Enabling Class W\n");
+ dev_dbg(codec->dev, "Enabling Class W\n");
snd_soc_write(codec, WM8903_CLASS_W_0, reg |
WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
}
wm8903->class_w_users--;
}
- dev_dbg(&i2c->dev, "Bypass use count now %d\n",
+ dev_dbg(codec->dev, "Bypass use count now %d\n",
wm8903->class_w_users);
return ret;
@@ -935,7 +934,6 @@ static int wm8903_add_widgets(struct snd_soc_codec *codec)
static int wm8903_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- struct i2c_client *i2c = codec->control_data;
u16 reg, reg2;
switch (level) {
@@ -974,7 +972,7 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
/* By default no bypass paths are enabled so
* enable Class W support.
*/
- dev_dbg(&i2c->dev, "Enabling Class W\n");
+ dev_dbg(codec->dev, "Enabling Class W\n");
snd_soc_write(codec, WM8903_CLASS_W_0, reg |
WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
}
@@ -1228,10 +1226,8 @@ static int wm8903_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
- struct i2c_client *i2c = codec->control_data;
struct snd_pcm_runtime *master_runtime;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -1245,7 +1241,7 @@ static int wm8903_startup(struct snd_pcm_substream *substream,
if (wm8903->master_substream) {
master_runtime = wm8903->master_substream->runtime;
- dev_dbg(&i2c->dev, "Constraining to %d bits\n",
+ dev_dbg(codec->dev, "Constraining to %d bits\n",
master_runtime->sample_bits);
snd_pcm_hw_constraint_minmax(substream->runtime,
@@ -1264,8 +1260,7 @@ static void wm8903_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -1284,10 +1279,8 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec =rtd->codec;
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
- struct i2c_client *i2c = codec->control_data;
int fs = params_rate(params);
int bclk;
int bclk_div;
@@ -1306,7 +1299,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
u16 dac_digital1 = snd_soc_read(codec, WM8903_DAC_DIGITAL_1);
if (substream == wm8903->slave_substream) {
- dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
+ dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
return 0;
}
@@ -1332,7 +1325,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
switch (sample_rates[dsp_config].rate) {
case 88200:
case 96000:
- dev_err(&i2c->dev, "%dHz unsupported by ADC\n",
+ dev_err(codec->dev, "%dHz unsupported by ADC\n",
fs);
return -EINVAL;
@@ -1340,7 +1333,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
break;
}
- dev_dbg(&i2c->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate);
+ dev_dbg(codec->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate);
clock1 &= ~WM8903_SAMPLE_RATE_MASK;
clock1 |= sample_rates[dsp_config].value;
@@ -1366,7 +1359,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- dev_dbg(&i2c->dev, "MCLK = %dHz, target sample rate = %dHz\n",
+ dev_dbg(codec->dev, "MCLK = %dHz, target sample rate = %dHz\n",
wm8903->sysclk, fs);
/* We may not have an MCLK which allows us to generate exactly
@@ -1401,12 +1394,12 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
clock1 |= clk_sys_ratios[clk_config].rate << WM8903_CLK_SYS_RATE_SHIFT;
clock1 |= clk_sys_ratios[clk_config].mode << WM8903_CLK_SYS_MODE_SHIFT;
- dev_dbg(&i2c->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n",
+ dev_dbg(codec->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n",
clk_sys_ratios[clk_config].rate,
clk_sys_ratios[clk_config].mode,
clk_sys_ratios[clk_config].div);
- dev_dbg(&i2c->dev, "Actual CLK_SYS = %dHz\n", clk_sys);
+ dev_dbg(codec->dev, "Actual CLK_SYS = %dHz\n", clk_sys);
/* We may not get quite the right frequency if using
* approximate clocks so look for the closest match that is
@@ -1428,7 +1421,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
aif2 &= ~WM8903_BCLK_DIV_MASK;
aif3 &= ~WM8903_LRCLK_RATE_MASK;
- dev_dbg(&i2c->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n",
+ dev_dbg(codec->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n",
bclk_divs[bclk_div].ratio / 10, bclk,
(clk_sys * 10) / bclk_divs[bclk_div].ratio);
@@ -1504,8 +1497,8 @@ EXPORT_SYMBOL_GPL(wm8903_mic_detect);
static irqreturn_t wm8903_irq(int irq, void *data)
{
- struct wm8903_priv *wm8903 = data;
- struct snd_soc_codec *codec = &wm8903->codec;
+ struct snd_soc_codec *codec = data;
+ struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
int mic_report;
int int_pol;
int int_val = 0;
@@ -1586,8 +1579,8 @@ static struct snd_soc_dai_ops wm8903_dai_ops = {
.set_sysclk = wm8903_set_dai_sysclk,
};
-struct snd_soc_dai wm8903_dai = {
- .name = "WM8903",
+static struct snd_soc_dai_driver wm8903_dai = {
+ .name = "wm8903-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -1605,23 +1598,16 @@ struct snd_soc_dai wm8903_dai = {
.ops = &wm8903_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8903_dai);
-static int wm8903_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8903_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8903_resume(struct platform_device *pdev)
+static int wm8903_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- struct i2c_client *i2c = codec->control_data;
int i;
u16 *reg_cache = codec->reg_cache;
u16 *tmp_cache = kmemdup(reg_cache, sizeof(wm8903_reg_defaults),
@@ -1637,65 +1623,37 @@ static int wm8903_resume(struct platform_device *pdev)
snd_soc_write(codec, i, tmp_cache[i]);
kfree(tmp_cache);
} else {
- dev_err(&i2c->dev, "Failed to allocate temporary cache\n");
+ dev_err(codec->dev, "Failed to allocate temporary cache\n");
}
return 0;
}
-static struct snd_soc_codec *wm8903_codec;
-
-static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int wm8903_probe(struct snd_soc_codec *codec)
{
- struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev);
- struct wm8903_priv *wm8903;
- struct snd_soc_codec *codec;
+ struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev);
+ struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
int ret, i;
int trigger, irq_pol;
u16 val;
- wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
- if (wm8903 == NULL)
- return -ENOMEM;
-
- codec = &wm8903->codec;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->dev = &i2c->dev;
- codec->name = "WM8903";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8903_set_bias_level;
- codec->dai = &wm8903_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm8903->reg_cache);
- codec->reg_cache = &wm8903->reg_cache[0];
- snd_soc_codec_set_drvdata(codec, wm8903);
- codec->volatile_register = wm8903_volatile_register;
init_completion(&wm8903->wseq);
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
-
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret != 0) {
- dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
}
val = snd_soc_read(codec, WM8903_SW_RESET_AND_ID);
if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) {
- dev_err(&i2c->dev,
+ dev_err(codec->dev,
"Device with ID register %x is not a WM8903\n", val);
return -ENODEV;
}
val = snd_soc_read(codec, WM8903_REVISION_NUMBER);
- dev_info(&i2c->dev, "WM8903 revision %d\n",
+ dev_info(codec->dev, "WM8903 revision %d\n",
val & WM8903_CHIP_REV_MASK);
wm8903_reset(codec);
@@ -1721,7 +1679,7 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
wm8903->mic_delay = pdata->micdet_delay;
}
- if (i2c->irq) {
+ if (wm8903->irq) {
if (pdata && pdata->irq_active_low) {
trigger = IRQF_TRIGGER_LOW;
irq_pol = WM8903_IRQ_POL;
@@ -1733,13 +1691,13 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
snd_soc_update_bits(codec, WM8903_INTERRUPT_CONTROL,
WM8903_IRQ_POL, irq_pol);
- ret = request_threaded_irq(i2c->irq, NULL, wm8903_irq,
+ ret = request_threaded_irq(wm8903->irq, NULL, wm8903_irq,
trigger | IRQF_ONESHOT,
- "wm8903", wm8903);
+ "wm8903", codec);
if (ret != 0) {
- dev_err(&i2c->dev, "Failed to request IRQ: %d\n",
+ dev_err(codec->dev, "Failed to request IRQ: %d\n",
ret);
- goto err;
+ return ret;
}
/* Enable write sequencer interrupts */
@@ -1781,133 +1739,96 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
val |= WM8903_DAC_MUTEMODE;
snd_soc_write(codec, WM8903_DAC_DIGITAL_1, val);
- wm8903_dai.dev = &i2c->dev;
- wm8903_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
- goto err_irq;
- }
-
- ret = snd_soc_register_dai(&wm8903_dai);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
- return ret;
+ snd_soc_add_controls(codec, wm8903_snd_controls,
+ ARRAY_SIZE(wm8903_snd_controls));
+ wm8903_add_widgets(codec);
-err_codec:
- snd_soc_unregister_codec(codec);
-err_irq:
- if (i2c->irq)
- free_irq(i2c->irq, wm8903);
-err:
- wm8903_codec = NULL;
- kfree(wm8903);
return ret;
}
-static __devexit int wm8903_i2c_remove(struct i2c_client *client)
+/* power down chip */
+static int wm8903_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- struct wm8903_priv *priv = snd_soc_codec_get_drvdata(codec);
+ wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
- snd_soc_unregister_dai(&wm8903_dai);
- snd_soc_unregister_codec(codec);
+static struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
+ .probe = wm8903_probe,
+ .remove = wm8903_remove,
+ .suspend = wm8903_suspend,
+ .resume = wm8903_resume,
+ .set_bias_level = wm8903_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8903_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8903_reg_defaults,
+ .volatile_register = wm8903_volatile_register,
+};
- wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8903_priv *wm8903;
+ int ret;
- if (client->irq)
- free_irq(client->irq, priv);
+ wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
+ if (wm8903 == NULL)
+ return -ENOMEM;
- kfree(priv);
+ i2c_set_clientdata(i2c, wm8903);
+ wm8903->irq = i2c->irq;
- wm8903_codec = NULL;
- wm8903_dai.dev = NULL;
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8903, &wm8903_dai, 1);
+ if (ret < 0)
+ kfree(wm8903);
+ return ret;
+}
+static __devexit int wm8903_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
-/* i2c codec control layer */
static const struct i2c_device_id wm8903_i2c_id[] = {
- { "wm8903", 0 },
- { }
+ { "wm8903", 0 },
+ { }
};
MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id);
static struct i2c_driver wm8903_i2c_driver = {
.driver = {
- .name = "WM8903",
+ .name = "wm8903-codec",
.owner = THIS_MODULE,
},
- .probe = wm8903_i2c_probe,
- .remove = __devexit_p(wm8903_i2c_remove),
+ .probe = wm8903_i2c_probe,
+ .remove = __devexit_p(wm8903_i2c_remove),
.id_table = wm8903_i2c_id,
};
+#endif
-static int wm8903_probe(struct platform_device *pdev)
+static int __init wm8903_modinit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
int ret = 0;
-
- if (!wm8903_codec) {
- dev_err(&pdev->dev, "I2C device not yet probed\n");
- goto err;
- }
-
- socdev->card->codec = wm8903_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to create pcms\n");
- goto err;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8903_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8903 I2C driver: %d\n",
+ ret);
}
-
- snd_soc_add_controls(socdev->card->codec, wm8903_snd_controls,
- ARRAY_SIZE(wm8903_snd_controls));
- wm8903_add_widgets(socdev->card->codec);
-
+#endif
return ret;
-
-err:
- return ret;
-}
-
-/* power down chip */
-static int wm8903_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8903 = {
- .probe = wm8903_probe,
- .remove = wm8903_remove,
- .suspend = wm8903_suspend,
- .resume = wm8903_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903);
-
-static int __init wm8903_modinit(void)
-{
- return i2c_add_driver(&wm8903_i2c_driver);
}
module_init(wm8903_modinit);
static void __exit wm8903_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8903_i2c_driver);
+#endif
}
module_exit(wm8903_exit);
diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h
index ce384a2ad820..996435e681e5 100644
--- a/sound/soc/codecs/wm8903.h
+++ b/sound/soc/codecs/wm8903.h
@@ -15,9 +15,6 @@
#include <linux/i2c.h>
-extern struct snd_soc_dai wm8903_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8903;
-
extern int wm8903_mic_detect(struct snd_soc_codec *codec,
struct snd_soc_jack *jack,
int det, int shrt);
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index f7dcabf6283c..33be84e506ea 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -31,9 +31,6 @@
#include "wm8904.h"
-static struct snd_soc_codec *wm8904_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8904;
-
enum wm8904_type {
WM8904,
WM8912,
@@ -52,10 +49,11 @@ static const char *wm8904_supply_names[WM8904_NUM_SUPPLIES] = {
/* codec private data */
struct wm8904_priv {
- struct snd_soc_codec codec;
+
u16 reg_cache[WM8904_MAX_REGISTER + 1];
enum wm8904_type devtype;
+ void *control_data;
struct regulator_bulk_data supplies[WM8904_NUM_SUPPLIES];
@@ -689,7 +687,7 @@ static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+ struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata;
int value = ucontrol->value.integer.value[0];
@@ -760,7 +758,7 @@ static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+ struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata;
int value = ucontrol->value.integer.value[0];
@@ -2218,8 +2216,8 @@ static struct snd_soc_dai_ops wm8904_dai_ops = {
.digital_mute = wm8904_digital_mute,
};
-struct snd_soc_dai wm8904_dai = {
- .name = "WM8904",
+static struct snd_soc_dai_driver wm8904_dai = {
+ .name = "wm8904-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -2237,24 +2235,17 @@ struct snd_soc_dai wm8904_dai = {
.ops = &wm8904_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8904_dai);
#ifdef CONFIG_PM
-static int wm8904_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8904_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8904_resume(struct platform_device *pdev)
+static int wm8904_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -2264,9 +2255,9 @@ static int wm8904_resume(struct platform_device *pdev)
#define wm8904_resume NULL
#endif
-static void wm8904_handle_retune_mobile_pdata(struct wm8904_priv *wm8904)
+static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = &wm8904->codec;
+ struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata;
struct snd_kcontrol_new control =
SOC_ENUM_EXT("EQ Mode",
@@ -2315,20 +2306,20 @@ static void wm8904_handle_retune_mobile_pdata(struct wm8904_priv *wm8904)
wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts;
wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts;
- ret = snd_soc_add_controls(&wm8904->codec, &control, 1);
+ ret = snd_soc_add_controls(codec, &control, 1);
if (ret != 0)
- dev_err(wm8904->codec.dev,
+ dev_err(codec->dev,
"Failed to add ReTune Mobile control: %d\n", ret);
}
-static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
+static void wm8904_handle_pdata(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = &wm8904->codec;
+ struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata;
int ret, i;
if (!pdata) {
- snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls,
+ snd_soc_add_controls(codec, wm8904_eq_controls,
ARRAY_SIZE(wm8904_eq_controls));
return;
}
@@ -2344,7 +2335,7 @@ static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
wm8904->drc_texts = kmalloc(sizeof(char *)
* pdata->num_drc_cfgs, GFP_KERNEL);
if (!wm8904->drc_texts) {
- dev_err(wm8904->codec.dev,
+ dev_err(codec->dev,
"Failed to allocate %d DRC config texts\n",
pdata->num_drc_cfgs);
return;
@@ -2356,9 +2347,9 @@ static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
wm8904->drc_enum.max = pdata->num_drc_cfgs;
wm8904->drc_enum.texts = wm8904->drc_texts;
- ret = snd_soc_add_controls(&wm8904->codec, &control, 1);
+ ret = snd_soc_add_controls(codec, &control, 1);
if (ret != 0)
- dev_err(wm8904->codec.dev,
+ dev_err(codec->dev,
"Failed to add DRC mode control: %d\n", ret);
wm8904_set_drc(codec);
@@ -2368,89 +2359,19 @@ static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
pdata->num_retune_mobile_cfgs);
if (pdata->num_retune_mobile_cfgs)
- wm8904_handle_retune_mobile_pdata(wm8904);
+ wm8904_handle_retune_mobile_pdata(codec);
else
- snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls,
+ snd_soc_add_controls(codec, wm8904_eq_controls,
ARRAY_SIZE(wm8904_eq_controls));
}
-static int wm8904_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (wm8904_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
- socdev->card->codec = wm8904_codec;
- codec = wm8904_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- wm8904_handle_pdata(snd_soc_codec_get_drvdata(codec));
-
- wm8904_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-static int wm8904_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8904 = {
- .probe = wm8904_probe,
- .remove = wm8904_remove,
- .suspend = wm8904_suspend,
- .resume = wm8904_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8904);
-
-static int wm8904_register(struct wm8904_priv *wm8904,
- enum snd_soc_control_type control)
+static int wm8904_probe(struct snd_soc_codec *codec)
{
+ struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata;
- int ret;
- struct snd_soc_codec *codec = &wm8904->codec;
- int i;
-
- if (wm8904_codec) {
- dev_err(codec->dev, "Another WM8904 is registered\n");
- ret = -EINVAL;
- goto err;
- }
+ int ret, i;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8904);
- codec->name = "WM8904";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8904_set_bias_level;
- codec->dai = &wm8904_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8904_MAX_REGISTER;
- codec->reg_cache = &wm8904->reg_cache;
- codec->volatile_register = wm8904_volatile_register;
codec->cache_sync = 1;
codec->idle_bias_off = 1;
@@ -2463,16 +2384,13 @@ static int wm8904_register(struct wm8904_priv *wm8904,
default:
dev_err(codec->dev, "Unknown device type %d\n",
wm8904->devtype);
- ret = -EINVAL;
- goto err;
+ return -EINVAL;
}
- memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++)
@@ -2482,7 +2400,7 @@ static int wm8904_register(struct wm8904_priv *wm8904,
wm8904->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err;
+ return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
@@ -2517,8 +2435,6 @@ static int wm8904_register(struct wm8904_priv *wm8904,
goto err_enable;
}
- wm8904_dai.dev = codec->dev;
-
/* Change some default settings - latch VU and enable ZC */
wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_LEFT] |= WM8904_ADC_VU;
wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_RIGHT] |= WM8904_ADC_VU;
@@ -2563,72 +2479,68 @@ static int wm8904_register(struct wm8904_priv *wm8904,
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
- wm8904_codec = codec;
+ wm8904_handle_pdata(codec);
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_enable;
- }
-
- ret = snd_soc_register_dai(&wm8904_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+ wm8904_add_widgets(codec);
return 0;
-err_codec:
- snd_soc_unregister_codec(codec);
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
err_get:
regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
-err:
- kfree(wm8904);
return ret;
}
-static void wm8904_unregister(struct wm8904_priv *wm8904)
+static int wm8904_remove(struct snd_soc_codec *codec)
{
- wm8904_set_bias_level(&wm8904->codec, SND_SOC_BIAS_OFF);
+ struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+
+ wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
- snd_soc_unregister_dai(&wm8904_dai);
- snd_soc_unregister_codec(&wm8904->codec);
- kfree(wm8904);
- wm8904_codec = NULL;
+
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8904 = {
+ .probe = wm8904_probe,
+ .remove = wm8904_remove,
+ .suspend = wm8904_suspend,
+ .resume = wm8904_resume,
+ .set_bias_level = wm8904_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8904_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8904_reg,
+ .volatile_register = wm8904_volatile_register,
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8904_priv *wm8904;
- struct snd_soc_codec *codec;
+ int ret;
wm8904 = kzalloc(sizeof(struct wm8904_priv), GFP_KERNEL);
if (wm8904 == NULL)
return -ENOMEM;
- codec = &wm8904->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
wm8904->devtype = id->driver_data;
-
i2c_set_clientdata(i2c, wm8904);
- codec->control_data = i2c;
+ wm8904->control_data = i2c;
wm8904->pdata = i2c->dev.platform_data;
- codec->dev = &i2c->dev;
-
- return wm8904_register(wm8904, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8904, &wm8904_dai, 1);
+ if (ret < 0)
+ kfree(wm8904);
+ return ret;
}
static __devexit int wm8904_i2c_remove(struct i2c_client *client)
{
- struct wm8904_priv *wm8904 = i2c_get_clientdata(client);
- wm8904_unregister(wm8904);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -2641,7 +2553,7 @@ MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id);
static struct i2c_driver wm8904_i2c_driver = {
.driver = {
- .name = "WM8904",
+ .name = "wm8904-codec",
.owner = THIS_MODULE,
},
.probe = wm8904_i2c_probe,
@@ -2652,15 +2564,15 @@ static struct i2c_driver wm8904_i2c_driver = {
static int __init wm8904_modinit(void)
{
- int ret;
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8904_i2c_driver);
if (ret != 0) {
- printk(KERN_ERR "Failed to register WM8904 I2C driver: %d\n",
+ printk(KERN_ERR "Failed to register wm8904 I2C driver: %d\n",
ret);
}
#endif
- return 0;
+ return ret;
}
module_init(wm8904_modinit);
diff --git a/sound/soc/codecs/wm8904.h b/sound/soc/codecs/wm8904.h
index abe5059b3004..9e8c84188ba7 100644
--- a/sound/soc/codecs/wm8904.h
+++ b/sound/soc/codecs/wm8904.h
@@ -21,9 +21,6 @@
#define WM8904_FLL_LRCLK 3
#define WM8904_FLL_FREE_RUNNING 4
-extern struct snd_soc_dai wm8904_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8904;
-
/*
* Register values.
*/
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index f0c11138e610..2cb16f895c46 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -44,7 +44,8 @@
struct wm8940_priv {
unsigned int sysclk;
u16 reg_cache[WM8940_CACHEREGNUM];
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
};
static u16 wm8940_reg_defaults[] = {
@@ -365,8 +366,7 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F;
u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1;
u16 companding = snd_soc_read(codec,
@@ -636,8 +636,8 @@ static struct snd_soc_dai_ops wm8940_dai_ops = {
.set_pll = wm8940_set_dai_pll,
};
-struct snd_soc_dai wm8940_dai = {
- .name = "WM8940",
+static struct snd_soc_dai_driver wm8940_dai = {
+ .name = "wm8940-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -655,20 +655,14 @@ struct snd_soc_dai wm8940_dai = {
.ops = &wm8940_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8940_dai);
-static int wm8940_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8940_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
}
-static int wm8940_resume(struct platform_device *pdev)
+static int wm8940_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
int ret;
u8 data[3];
@@ -697,108 +691,26 @@ error_ret:
return ret;
}
-static struct snd_soc_codec *wm8940_codec;
-
-static int wm8940_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
-
- int ret = 0;
-
- if (wm8940_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8940_codec;
- codec = wm8940_codec;
-
- mutex_init(&codec->mutex);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- ret = snd_soc_add_controls(codec, wm8940_snd_controls,
- ARRAY_SIZE(wm8940_snd_controls));
- if (ret)
- goto error_free_pcms;
- ret = wm8940_add_widgets(codec);
- if (ret)
- goto error_free_pcms;
-
- return ret;
-
-error_free_pcms:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-pcm_err:
- return ret;
-}
-
-static int wm8940_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8940 = {
- .probe = wm8940_probe,
- .remove = wm8940_remove,
- .suspend = wm8940_suspend,
- .resume = wm8940_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940);
-
-static int wm8940_register(struct wm8940_priv *wm8940,
- enum snd_soc_control_type control)
+static int wm8940_probe(struct snd_soc_codec *codec)
{
- struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data;
- struct snd_soc_codec *codec = &wm8940->codec;
+ struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
+ struct wm8940_setup_data *pdata = codec->dev->platform_data;
int ret;
u16 reg;
- if (wm8940_codec) {
- dev_err(codec->dev, "Another WM8940 is registered\n");
- return -EINVAL;
- }
-
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8940);
- codec->name = "WM8940";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8940_set_bias_level;
- codec->dai = &wm8940_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults);
- codec->reg_cache = &wm8940->reg_cache;
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+ codec->control_data = wm8940->control_data;
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
- memcpy(codec->reg_cache, wm8940_reg_defaults,
- sizeof(wm8940_reg_defaults));
-
ret = wm8940_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
return ret;
}
- wm8940_dai.dev = codec->dev;
-
wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
ret = snd_soc_write(codec, WM8940_POWER1, 0x180);
@@ -814,64 +726,60 @@ static int wm8940_register(struct wm8940_priv *wm8940,
return ret;
}
-
- wm8940_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ ret = snd_soc_add_controls(codec, wm8940_snd_controls,
+ ARRAY_SIZE(wm8940_snd_controls));
+ if (ret)
return ret;
- }
-
- ret = snd_soc_register_dai(&wm8940_dai);
- if (ret) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
+ ret = wm8940_add_widgets(codec);
+ if (ret)
return ret;
- }
- return 0;
+ return ret;
+;
}
-static void wm8940_unregister(struct wm8940_priv *wm8940)
+static int wm8940_remove(struct snd_soc_codec *codec)
{
- wm8940_set_bias_level(&wm8940->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8940_dai);
- snd_soc_unregister_codec(&wm8940->codec);
- kfree(wm8940);
- wm8940_codec = NULL;
+ wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
-static int wm8940_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
+ .probe = wm8940_probe,
+ .remove = wm8940_remove,
+ .suspend = wm8940_suspend,
+ .resume = wm8940_resume,
+ .set_bias_level = wm8940_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8940_reg_defaults,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8940_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
- int ret;
struct wm8940_priv *wm8940;
- struct snd_soc_codec *codec;
+ int ret;
- wm8940 = kzalloc(sizeof *wm8940, GFP_KERNEL);
+ wm8940 = kzalloc(sizeof(struct wm8940_priv), GFP_KERNEL);
if (wm8940 == NULL)
return -ENOMEM;
- codec = &wm8940->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
i2c_set_clientdata(i2c, wm8940);
- codec->control_data = i2c;
- codec->dev = &i2c->dev;
+ wm8940->control_data = i2c;
- ret = wm8940_register(wm8940, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8940, &wm8940_dai, 1);
if (ret < 0)
kfree(wm8940);
-
return ret;
}
-static int __devexit wm8940_i2c_remove(struct i2c_client *client)
+static __devexit int wm8940_i2c_remove(struct i2c_client *client)
{
- struct wm8940_priv *wm8940 = i2c_get_clientdata(client);
-
- wm8940_unregister(wm8940);
-
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -883,29 +791,34 @@ MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id);
static struct i2c_driver wm8940_i2c_driver = {
.driver = {
- .name = "WM8940 I2C Codec",
+ .name = "wm8940-codec",
.owner = THIS_MODULE,
},
- .probe = wm8940_i2c_probe,
- .remove = __devexit_p(wm8940_i2c_remove),
+ .probe = wm8940_i2c_probe,
+ .remove = __devexit_p(wm8940_i2c_remove),
.id_table = wm8940_i2c_id,
};
+#endif
static int __init wm8940_modinit(void)
{
- int ret;
-
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8940_i2c_driver);
- if (ret)
- printk(KERN_ERR "Failed to register WM8940 I2C driver: %d\n",
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8940 I2C driver: %d\n",
ret);
+ }
+#endif
return ret;
}
module_init(wm8940_modinit);
static void __exit wm8940_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8940_i2c_driver);
+#endif
}
module_exit(wm8940_exit);
diff --git a/sound/soc/codecs/wm8940.h b/sound/soc/codecs/wm8940.h
index 8410eed3ef84..907fe192e9e0 100644
--- a/sound/soc/codecs/wm8940.h
+++ b/sound/soc/codecs/wm8940.h
@@ -15,8 +15,6 @@ struct wm8940_setup_data {
#define WM8940_VROI_30K 1
unsigned int vroi:1;
};
-extern struct snd_soc_dai wm8940_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8940;
/* WM8940 register space */
#define WM8940_SOFTRESET 0x00
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index 5f025593d84d..f89ad6c9a80b 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -30,9 +30,6 @@
#include "wm8955.h"
-static struct snd_soc_codec *wm8955_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8955;
-
#define WM8955_NUM_SUPPLIES 4
static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = {
"DCVDD",
@@ -43,7 +40,8 @@ static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = {
/* codec private data */
struct wm8955_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+
u16 reg_cache[WM8955_MAX_REGISTER + 1];
unsigned int mclk_rate;
@@ -52,8 +50,6 @@ struct wm8955_priv {
int fs;
struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES];
-
- struct wm8955_pdata *pdata;
};
static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = {
@@ -870,8 +866,8 @@ static struct snd_soc_dai_ops wm8955_dai_ops = {
.digital_mute = wm8955_digital_mute,
};
-struct snd_soc_dai wm8955_dai = {
- .name = "WM8955",
+static struct snd_soc_dai_driver wm8955_dai = {
+ .name = "wm8955-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -881,24 +877,17 @@ struct snd_soc_dai wm8955_dai = {
},
.ops = &wm8955_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8955_dai);
#ifdef CONFIG_PM
-static int wm8955_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8955_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8955_resume(struct platform_device *pdev)
+static int wm8955_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -908,86 +897,16 @@ static int wm8955_resume(struct platform_device *pdev)
#define wm8955_resume NULL
#endif
-static int wm8955_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (wm8955_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8955_codec;
- codec = wm8955_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- wm8955_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-static int wm8955_remove(struct platform_device *pdev)
+static int wm8955_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8955 = {
- .probe = wm8955_probe,
- .remove = wm8955_remove,
- .suspend = wm8955_suspend,
- .resume = wm8955_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8955);
-
-static int wm8955_register(struct wm8955_priv *wm8955,
- enum snd_soc_control_type control)
-{
- int ret;
- struct snd_soc_codec *codec = &wm8955->codec;
- int i;
-
- if (wm8955_codec) {
- dev_err(codec->dev, "Another WM8955 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8955);
- codec->name = "WM8955";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8955_set_bias_level;
- codec->dai = &wm8955_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8955_MAX_REGISTER;
- codec->reg_cache = &wm8955->reg_cache;
-
- memcpy(codec->reg_cache, wm8955_reg, sizeof(wm8955_reg));
+ struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+ struct wm8955_pdata *pdata = dev_get_platdata(codec->dev);
+ int ret, i;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8955->control_type);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++)
@@ -997,7 +916,7 @@ static int wm8955_register(struct wm8955_priv *wm8955,
wm8955->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err;
+ return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
@@ -1013,8 +932,6 @@ static int wm8955_register(struct wm8955_priv *wm8955,
goto err_enable;
}
- wm8955_dai.dev = codec->dev;
-
/* Change some default settings - latch VU and enable ZC */
wm8955->reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU;
wm8955->reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU;
@@ -1028,12 +945,12 @@ static int wm8955_register(struct wm8955_priv *wm8955,
wm8955->reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB;
/* Set platform data values */
- if (wm8955->pdata) {
- if (wm8955->pdata->out2_speaker)
+ if (pdata) {
+ if (pdata->out2_speaker)
wm8955->reg_cache[WM8955_ADDITIONAL_CONTROL_2]
|= WM8955_ROUT2INV;
- if (wm8955->pdata->monoin_diff)
+ if (pdata->monoin_diff)
wm8955->reg_cache[WM8955_MONO_OUT_MIX_1]
|= WM8955_DMEN;
}
@@ -1043,70 +960,60 @@ static int wm8955_register(struct wm8955_priv *wm8955,
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
- wm8955_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_enable;
- }
-
- ret = snd_soc_register_dai(&wm8955_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
+ wm8955_add_widgets(codec);
return 0;
-err_codec:
- snd_soc_unregister_codec(codec);
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
err_get:
regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
-err:
- kfree(wm8955);
return ret;
}
-static void wm8955_unregister(struct wm8955_priv *wm8955)
+static int wm8955_remove(struct snd_soc_codec *codec)
{
- wm8955_set_bias_level(&wm8955->codec, SND_SOC_BIAS_OFF);
+ struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+
+ wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
- snd_soc_unregister_dai(&wm8955_dai);
- snd_soc_unregister_codec(&wm8955->codec);
- kfree(wm8955);
- wm8955_codec = NULL;
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8955 = {
+ .probe = wm8955_probe,
+ .remove = wm8955_remove,
+ .suspend = wm8955_suspend,
+ .resume = wm8955_resume,
+ .set_bias_level = wm8955_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8955_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8955_reg,
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8955_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8955_priv *wm8955;
- struct snd_soc_codec *codec;
+ int ret;
wm8955 = kzalloc(sizeof(struct wm8955_priv), GFP_KERNEL);
if (wm8955 == NULL)
return -ENOMEM;
- codec = &wm8955->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
i2c_set_clientdata(i2c, wm8955);
- codec->control_data = i2c;
- wm8955->pdata = i2c->dev.platform_data;
-
- codec->dev = &i2c->dev;
- return wm8955_register(wm8955, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8955, &wm8955_dai, 1);
+ if (ret < 0)
+ kfree(wm8955);
+ return ret;
}
static __devexit int wm8955_i2c_remove(struct i2c_client *client)
{
- struct wm8955_priv *wm8955 = i2c_get_clientdata(client);
- wm8955_unregister(wm8955);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1118,7 +1025,7 @@ MODULE_DEVICE_TABLE(i2c, wm8955_i2c_id);
static struct i2c_driver wm8955_i2c_driver = {
.driver = {
- .name = "wm8955",
+ .name = "wm8955-codec",
.owner = THIS_MODULE,
},
.probe = wm8955_i2c_probe,
@@ -1129,7 +1036,7 @@ static struct i2c_driver wm8955_i2c_driver = {
static int __init wm8955_modinit(void)
{
- int ret;
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8955_i2c_driver);
if (ret != 0) {
@@ -1137,7 +1044,7 @@ static int __init wm8955_modinit(void)
ret);
}
#endif
- return 0;
+ return ret;
}
module_init(wm8955_modinit);
diff --git a/sound/soc/codecs/wm8955.h b/sound/soc/codecs/wm8955.h
index ae349c8531f6..d13fd5c5fa63 100644
--- a/sound/soc/codecs/wm8955.h
+++ b/sound/soc/codecs/wm8955.h
@@ -15,9 +15,6 @@
#define WM8955_CLK_MCLK 1
-extern struct snd_soc_dai wm8955_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8955;
-
/*
* Register values.
*/
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 3c6ee61f6c95..8d5efb333c33 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -29,8 +29,6 @@
#define AUDIO_NAME "wm8960"
-struct snd_soc_codec_device soc_codec_dev_wm8960;
-
/* R25 - Power 1 */
#define WM8960_VMID_MASK 0x180
#define WM8960_VREF 0x40
@@ -75,7 +73,10 @@ static const u16 wm8960_reg[WM8960_CACHEREGNUM] = {
struct wm8960_priv {
u16 reg_cache[WM8960_CACHEREGNUM];
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
+ int (*set_bias_level)(struct snd_soc_codec *,
+ enum snd_soc_bias_level level);
struct snd_soc_dapm_widget *lout1;
struct snd_soc_dapm_widget *rout1;
struct snd_soc_dapm_widget *out3;
@@ -507,8 +508,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
int i;
@@ -849,6 +849,14 @@ static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
return 0;
}
+static int wm8960_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+
+ return wm8960->set_bias_level(codec, level);
+}
+
#define WM8960_RATES SNDRV_PCM_RATE_8000_48000
#define WM8960_FORMATS \
@@ -863,8 +871,8 @@ static struct snd_soc_dai_ops wm8960_dai_ops = {
.set_pll = wm8960_set_dai_pll,
};
-struct snd_soc_dai wm8960_dai = {
- .name = "WM8960",
+static struct snd_soc_dai_driver wm8960_dai = {
+ .name = "wm8960-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -880,21 +888,18 @@ struct snd_soc_dai wm8960_dai = {
.ops = &wm8960_dai_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8960_dai);
-static int wm8960_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8960_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
- codec->set_bias_level(codec, SND_SOC_BIAS_OFF);
+ wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8960_resume(struct platform_device *pdev)
+static int wm8960_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -906,78 +911,19 @@ static int wm8960_resume(struct platform_device *pdev)
codec->hw_write(codec->control_data, data, 2);
}
- codec->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
+ wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
-static struct snd_soc_codec *wm8960_codec;
-
-static int wm8960_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (wm8960_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8960_codec;
- codec = wm8960_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8960_snd_controls,
- ARRAY_SIZE(wm8960_snd_controls));
- wm8960_add_widgets(codec);
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int wm8960_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8960 = {
- .probe = wm8960_probe,
- .remove = wm8960_remove,
- .suspend = wm8960_suspend,
- .resume = wm8960_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8960);
-
-static int wm8960_register(struct wm8960_priv *wm8960,
- enum snd_soc_control_type control)
+static int wm8960_probe(struct snd_soc_codec *codec)
{
- struct wm8960_data *pdata = wm8960->codec.dev->platform_data;
- struct snd_soc_codec *codec = &wm8960->codec;
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+ struct wm8960_data *pdata = dev_get_platdata(codec->dev);
int ret;
u16 reg;
- if (wm8960_codec) {
- dev_err(codec->dev, "Another WM8960 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- codec->set_bias_level = wm8960_set_bias_level_out3;
+ wm8960->set_bias_level = wm8960_set_bias_level_out3;
+ codec->control_data = wm8960->control_data;
if (!pdata) {
dev_warn(codec->dev, "No platform data supplied\n");
@@ -988,39 +934,22 @@ static int wm8960_register(struct wm8960_priv *wm8960,
}
if (pdata->capless)
- codec->set_bias_level = wm8960_set_bias_level_capless;
+ wm8960->set_bias_level = wm8960_set_bias_level_capless;
}
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8960);
- codec->name = "WM8960";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->dai = &wm8960_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8960_CACHEREGNUM;
- codec->reg_cache = &wm8960->reg_cache;
-
- memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8960->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
ret = wm8960_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
+ return ret;
}
- wm8960_dai.dev = codec->dev;
-
- codec->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch the update bits */
reg = snd_soc_read(codec, WM8960_LINVOL);
@@ -1044,62 +973,58 @@ static int wm8960_register(struct wm8960_priv *wm8960,
reg = snd_soc_read(codec, WM8960_ROUT2);
snd_soc_write(codec, WM8960_ROUT2, reg | 0x100);
- wm8960_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm8960_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8960_snd_controls,
+ ARRAY_SIZE(wm8960_snd_controls));
+ wm8960_add_widgets(codec);
return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8960);
- return ret;
}
-static void wm8960_unregister(struct wm8960_priv *wm8960)
+/* power down chip */
+static int wm8960_remove(struct snd_soc_codec *codec)
{
- wm8960->codec.set_bias_level(&wm8960->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8960_dai);
- snd_soc_unregister_codec(&wm8960->codec);
- kfree(wm8960);
- wm8960_codec = NULL;
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+
+ wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
+ .probe = wm8960_probe,
+ .remove = wm8960_remove,
+ .suspend = wm8960_suspend,
+ .resume = wm8960_resume,
+ .set_bias_level = wm8960_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8960_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8960_reg,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8960_priv *wm8960;
- struct snd_soc_codec *codec;
+ int ret;
wm8960 = kzalloc(sizeof(struct wm8960_priv), GFP_KERNEL);
if (wm8960 == NULL)
return -ENOMEM;
- codec = &wm8960->codec;
-
i2c_set_clientdata(i2c, wm8960);
- codec->control_data = i2c;
-
- codec->dev = &i2c->dev;
+ wm8960->control_data = i2c;
- return wm8960_register(wm8960, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8960, &wm8960_dai, 1);
+ if (ret < 0)
+ kfree(wm8960);
+ return ret;
}
static __devexit int wm8960_i2c_remove(struct i2c_client *client)
{
- struct wm8960_priv *wm8960 = i2c_get_clientdata(client);
- wm8960_unregister(wm8960);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1111,35 +1036,37 @@ MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id);
static struct i2c_driver wm8960_i2c_driver = {
.driver = {
- .name = "wm8960",
+ .name = "wm8960-codec",
.owner = THIS_MODULE,
},
.probe = wm8960_i2c_probe,
.remove = __devexit_p(wm8960_i2c_remove),
.id_table = wm8960_i2c_id,
};
+#endif
static int __init wm8960_modinit(void)
{
- int ret;
-
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8960_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register WM8960 I2C driver: %d\n",
ret);
}
-
+#endif
return ret;
}
module_init(wm8960_modinit);
static void __exit wm8960_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8960_i2c_driver);
+#endif
}
module_exit(wm8960_exit);
-
MODULE_DESCRIPTION("ASoC WM8960 driver");
MODULE_AUTHOR("Liam Girdwood");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h
index a5ef65481b86..2d8163d7004b 100644
--- a/sound/soc/codecs/wm8960.h
+++ b/sound/soc/codecs/wm8960.h
@@ -110,7 +110,4 @@
#define WM8960_OPCLK_DIV_5_5 (4 << 0)
#define WM8960_OPCLK_DIV_6 (5 << 0)
-extern struct snd_soc_dai wm8960_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8960;
-
#endif
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 2549d3a297ab..4f326f604104 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -288,7 +288,7 @@ static u16 wm8961_reg_defaults[] = {
};
struct wm8961_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
int sysclk;
u16 reg_cache[WM8961_MAX_REGISTER];
};
@@ -940,8 +940,8 @@ static struct snd_soc_dai_ops wm8961_dai_ops = {
.set_clkdiv = wm8961_set_clkdiv,
};
-struct snd_soc_dai wm8961_dai = {
- .name = "WM8961",
+static struct snd_soc_dai_driver wm8961_dai = {
+ .name = "wm8961-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
@@ -956,140 +956,22 @@ struct snd_soc_dai wm8961_dai = {
.formats = WM8961_FORMATS,},
.ops = &wm8961_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8961_dai);
-
-static struct snd_soc_codec *wm8961_codec;
-
-static int wm8961_probe(struct platform_device *pdev)
+static int wm8961_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
int ret = 0;
-
- if (wm8961_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8961_codec;
- codec = wm8961_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8961_snd_controls,
- ARRAY_SIZE(wm8961_snd_controls));
- snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets,
- ARRAY_SIZE(wm8961_dapm_widgets));
- snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-static int wm8961_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int wm8961_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-static int wm8961_resume(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- u16 *reg_cache = codec->reg_cache;
- int i;
-
- for (i = 0; i < codec->reg_cache_size; i++) {
- if (reg_cache[i] == wm8961_reg_defaults[i])
- continue;
-
- if (i == WM8961_SOFTWARE_RESET)
- continue;
-
- snd_soc_write(codec, i, reg_cache[i]);
- }
-
- wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-#else
-#define wm8961_suspend NULL
-#define wm8961_resume NULL
-#endif
-
-struct snd_soc_codec_device soc_codec_dev_wm8961 = {
- .probe = wm8961_probe,
- .remove = wm8961_remove,
- .suspend = wm8961_suspend,
- .resume = wm8961_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8961);
-
-static int wm8961_register(struct wm8961_priv *wm8961)
-{
- struct snd_soc_codec *codec = &wm8961->codec;
- int ret;
u16 reg;
- if (wm8961_codec) {
- dev_err(codec->dev, "Another WM8961 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8961);
- codec->name = "WM8961";
- codec->owner = THIS_MODULE;
- codec->dai = &wm8961_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm8961->reg_cache);
- codec->reg_cache = &wm8961->reg_cache;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8961_set_bias_level;
- codec->volatile_register = wm8961_volatile_register;
-
- memcpy(codec->reg_cache, wm8961_reg_defaults,
- sizeof(wm8961_reg_defaults));
-
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
reg = snd_soc_read(codec, WM8961_SOFTWARE_RESET);
if (reg != 0x1801) {
dev_err(codec->dev, "Device is not a WM8961: ID=0x%x\n", reg);
- ret = -EINVAL;
- goto err;
+ return -EINVAL;
}
/* This isn't volatile - readback doesn't correspond to write */
@@ -1102,7 +984,7 @@ static int wm8961_register(struct wm8961_priv *wm8961)
ret = wm8961_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
+ return ret;
}
/* Enable class W */
@@ -1140,64 +1022,89 @@ static int wm8961_register(struct wm8961_priv *wm8961)
wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- wm8961_dai.dev = codec->dev;
+ snd_soc_add_controls(codec, wm8961_snd_controls,
+ ARRAY_SIZE(wm8961_snd_controls));
+ snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets,
+ ARRAY_SIZE(wm8961_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
- wm8961_codec = codec;
+ return 0;
+}
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
+static int wm8961_remove(struct snd_soc_codec *codec)
+{
+ wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
- ret = snd_soc_register_dai(&wm8961_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+#ifdef CONFIG_PM
+static int wm8961_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8961);
- return ret;
}
-static void wm8961_unregister(struct wm8961_priv *wm8961)
+static int wm8961_resume(struct snd_soc_codec *codec)
{
- wm8961_set_bias_level(&wm8961->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8961_dai);
- snd_soc_unregister_codec(&wm8961->codec);
- kfree(wm8961);
- wm8961_codec = NULL;
+ u16 *reg_cache = codec->reg_cache;
+ int i;
+
+ for (i = 0; i < codec->driver->reg_cache_size; i++) {
+ if (reg_cache[i] == wm8961_reg_defaults[i])
+ continue;
+
+ if (i == WM8961_SOFTWARE_RESET)
+ continue;
+
+ snd_soc_write(codec, i, reg_cache[i]);
+ }
+
+ wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
}
+#else
+#define wm8961_suspend NULL
+#define wm8961_resume NULL
+#endif
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8961 = {
+ .probe = wm8961_probe,
+ .remove = wm8961_remove,
+ .suspend = wm8961_suspend,
+ .resume = wm8961_resume,
+ .set_bias_level = wm8961_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8961_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8961_reg_defaults,
+ .volatile_register = wm8961_volatile_register,
+};
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8961_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8961_priv *wm8961;
- struct snd_soc_codec *codec;
+ int ret;
wm8961 = kzalloc(sizeof(struct wm8961_priv), GFP_KERNEL);
if (wm8961 == NULL)
return -ENOMEM;
- codec = &wm8961->codec;
-
i2c_set_clientdata(i2c, wm8961);
- codec->control_data = i2c;
-
- codec->dev = &i2c->dev;
- return wm8961_register(wm8961);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8961, &wm8961_dai, 1);
+ if (ret < 0)
+ kfree(wm8961);
+ return ret;
}
static __devexit int wm8961_i2c_remove(struct i2c_client *client)
{
- struct wm8961_priv *wm8961 = i2c_get_clientdata(client);
- wm8961_unregister(wm8961);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1209,35 +1116,37 @@ MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id);
static struct i2c_driver wm8961_i2c_driver = {
.driver = {
- .name = "wm8961",
+ .name = "wm8961-codec",
.owner = THIS_MODULE,
},
.probe = wm8961_i2c_probe,
.remove = __devexit_p(wm8961_i2c_remove),
.id_table = wm8961_i2c_id,
};
+#endif
static int __init wm8961_modinit(void)
{
- int ret;
-
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8961_i2c_driver);
if (ret != 0) {
- printk(KERN_ERR "Failed to register WM8961 I2C driver: %d\n",
+ printk(KERN_ERR "Failed to register wm8961 I2C driver: %d\n",
ret);
}
-
+#endif
return ret;
}
module_init(wm8961_modinit);
static void __exit wm8961_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8961_i2c_driver);
+#endif
}
module_exit(wm8961_exit);
-
MODULE_DESCRIPTION("ASoC WM8961 driver");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8961.h b/sound/soc/codecs/wm8961.h
index 5513bfd720d6..1d736e5701c8 100644
--- a/sound/soc/codecs/wm8961.h
+++ b/sound/soc/codecs/wm8961.h
@@ -11,9 +11,6 @@
#include <sound/soc.h>
-extern struct snd_soc_codec_device soc_codec_dev_wm8961;
-extern struct snd_soc_dai wm8961_dai;
-
#define WM8961_BCLK 1
#define WM8961_LRCLK 2
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
new file mode 100644
index 000000000000..894d0cd3aa9b
--- /dev/null
+++ b/sound/soc/codecs/wm8962.c
@@ -0,0 +1,3977 @@
+/*
+ * wm8962.c -- WM8962 ALSA SoC Audio driver
+ *
+ * Copyright 2010 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gcd.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/wm8962.h>
+
+#include "wm8962.h"
+
+#define WM8962_NUM_SUPPLIES 8
+static const char *wm8962_supply_names[WM8962_NUM_SUPPLIES] = {
+ "DCVDD",
+ "DBVDD",
+ "AVDD",
+ "CPVDD",
+ "MICVDD",
+ "PLLVDD",
+ "SPKVDD1",
+ "SPKVDD2",
+};
+
+/* codec private data */
+struct wm8962_priv {
+ struct snd_soc_codec *codec;
+
+ u16 reg_cache[WM8962_MAX_REGISTER + 1];
+
+ int sysclk;
+ int sysclk_rate;
+
+ int bclk; /* Desired BCLK */
+ int lrclk;
+
+ int fll_src;
+ int fll_fref;
+ int fll_fout;
+
+ struct delayed_work mic_work;
+ struct snd_soc_jack *jack;
+
+ struct regulator_bulk_data supplies[WM8962_NUM_SUPPLIES];
+ struct notifier_block disable_nb[WM8962_NUM_SUPPLIES];
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ struct input_dev *beep;
+ struct work_struct beep_work;
+ int beep_rate;
+#endif
+
+#ifdef CONFIG_GPIOLIB
+ struct gpio_chip gpio_chip;
+#endif
+};
+
+/* We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8962_REGULATOR_EVENT(n) \
+static int wm8962_regulator_event_##n(struct notifier_block *nb, \
+ unsigned long event, void *data) \
+{ \
+ struct wm8962_priv *wm8962 = container_of(nb, struct wm8962_priv, \
+ disable_nb[n]); \
+ if (event & REGULATOR_EVENT_DISABLE) { \
+ wm8962->codec->cache_sync = 1; \
+ } \
+ return 0; \
+}
+
+WM8962_REGULATOR_EVENT(0)
+WM8962_REGULATOR_EVENT(1)
+WM8962_REGULATOR_EVENT(2)
+WM8962_REGULATOR_EVENT(3)
+WM8962_REGULATOR_EVENT(4)
+WM8962_REGULATOR_EVENT(5)
+WM8962_REGULATOR_EVENT(6)
+WM8962_REGULATOR_EVENT(7)
+
+static const u16 wm8962_reg[WM8962_MAX_REGISTER + 1] = {
+ [0] = 0x009F, /* R0 - Left Input volume */
+ [1] = 0x049F, /* R1 - Right Input volume */
+ [2] = 0x0000, /* R2 - HPOUTL volume */
+ [3] = 0x0000, /* R3 - HPOUTR volume */
+ [4] = 0x0020, /* R4 - Clocking1 */
+ [5] = 0x0018, /* R5 - ADC & DAC Control 1 */
+ [6] = 0x2008, /* R6 - ADC & DAC Control 2 */
+ [7] = 0x000A, /* R7 - Audio Interface 0 */
+ [8] = 0x01E4, /* R8 - Clocking2 */
+ [9] = 0x0300, /* R9 - Audio Interface 1 */
+ [10] = 0x00C0, /* R10 - Left DAC volume */
+ [11] = 0x00C0, /* R11 - Right DAC volume */
+
+ [14] = 0x0040, /* R14 - Audio Interface 2 */
+ [15] = 0x6243, /* R15 - Software Reset */
+
+ [17] = 0x007B, /* R17 - ALC1 */
+ [18] = 0x0000, /* R18 - ALC2 */
+ [19] = 0x1C32, /* R19 - ALC3 */
+ [20] = 0x3200, /* R20 - Noise Gate */
+ [21] = 0x00C0, /* R21 - Left ADC volume */
+ [22] = 0x00C0, /* R22 - Right ADC volume */
+ [23] = 0x0160, /* R23 - Additional control(1) */
+ [24] = 0x0000, /* R24 - Additional control(2) */
+ [25] = 0x0000, /* R25 - Pwr Mgmt (1) */
+ [26] = 0x0000, /* R26 - Pwr Mgmt (2) */
+ [27] = 0x0010, /* R27 - Additional Control (3) */
+ [28] = 0x0000, /* R28 - Anti-pop */
+
+ [30] = 0x005E, /* R30 - Clocking 3 */
+ [31] = 0x0000, /* R31 - Input mixer control (1) */
+ [32] = 0x0145, /* R32 - Left input mixer volume */
+ [33] = 0x0145, /* R33 - Right input mixer volume */
+ [34] = 0x0009, /* R34 - Input mixer control (2) */
+ [35] = 0x0003, /* R35 - Input bias control */
+ [37] = 0x0008, /* R37 - Left input PGA control */
+ [38] = 0x0008, /* R38 - Right input PGA control */
+
+ [40] = 0x0000, /* R40 - SPKOUTL volume */
+ [41] = 0x0000, /* R41 - SPKOUTR volume */
+
+ [47] = 0x0000, /* R47 - Thermal Shutdown Status */
+ [48] = 0x8027, /* R48 - Additional Control (4) */
+ [49] = 0x0010, /* R49 - Class D Control 1 */
+
+ [51] = 0x0003, /* R51 - Class D Control 2 */
+
+ [56] = 0x0506, /* R56 - Clocking 4 */
+ [57] = 0x0000, /* R57 - DAC DSP Mixing (1) */
+ [58] = 0x0000, /* R58 - DAC DSP Mixing (2) */
+
+ [60] = 0x0300, /* R60 - DC Servo 0 */
+ [61] = 0x0300, /* R61 - DC Servo 1 */
+
+ [64] = 0x0810, /* R64 - DC Servo 4 */
+
+ [66] = 0x0000, /* R66 - DC Servo 6 */
+
+ [68] = 0x001B, /* R68 - Analogue PGA Bias */
+ [69] = 0x0000, /* R69 - Analogue HP 0 */
+
+ [71] = 0x01FB, /* R71 - Analogue HP 2 */
+ [72] = 0x0000, /* R72 - Charge Pump 1 */
+
+ [82] = 0x0004, /* R82 - Charge Pump B */
+
+ [87] = 0x0000, /* R87 - Write Sequencer Control 1 */
+
+ [90] = 0x0000, /* R90 - Write Sequencer Control 2 */
+
+ [93] = 0x0000, /* R93 - Write Sequencer Control 3 */
+ [94] = 0x0000, /* R94 - Control Interface */
+
+ [99] = 0x0000, /* R99 - Mixer Enables */
+ [100] = 0x0000, /* R100 - Headphone Mixer (1) */
+ [101] = 0x0000, /* R101 - Headphone Mixer (2) */
+ [102] = 0x013F, /* R102 - Headphone Mixer (3) */
+ [103] = 0x013F, /* R103 - Headphone Mixer (4) */
+
+ [105] = 0x0000, /* R105 - Speaker Mixer (1) */
+ [106] = 0x0000, /* R106 - Speaker Mixer (2) */
+ [107] = 0x013F, /* R107 - Speaker Mixer (3) */
+ [108] = 0x013F, /* R108 - Speaker Mixer (4) */
+ [109] = 0x0003, /* R109 - Speaker Mixer (5) */
+ [110] = 0x0002, /* R110 - Beep Generator (1) */
+
+ [115] = 0x0006, /* R115 - Oscillator Trim (3) */
+ [116] = 0x0026, /* R116 - Oscillator Trim (4) */
+
+ [119] = 0x0000, /* R119 - Oscillator Trim (7) */
+
+ [124] = 0x0011, /* R124 - Analogue Clocking1 */
+ [125] = 0x004B, /* R125 - Analogue Clocking2 */
+ [126] = 0x000D, /* R126 - Analogue Clocking3 */
+ [127] = 0x0000, /* R127 - PLL Software Reset */
+
+ [129] = 0x0000, /* R129 - PLL2 */
+
+ [131] = 0x0000, /* R131 - PLL 4 */
+
+ [136] = 0x0067, /* R136 - PLL 9 */
+ [137] = 0x001C, /* R137 - PLL 10 */
+ [138] = 0x0071, /* R138 - PLL 11 */
+ [139] = 0x00C7, /* R139 - PLL 12 */
+ [140] = 0x0067, /* R140 - PLL 13 */
+ [141] = 0x0048, /* R141 - PLL 14 */
+ [142] = 0x0022, /* R142 - PLL 15 */
+ [143] = 0x0097, /* R143 - PLL 16 */
+
+ [155] = 0x000C, /* R155 - FLL Control (1) */
+ [156] = 0x0039, /* R156 - FLL Control (2) */
+ [157] = 0x0180, /* R157 - FLL Control (3) */
+
+ [159] = 0x0032, /* R159 - FLL Control (5) */
+ [160] = 0x0018, /* R160 - FLL Control (6) */
+ [161] = 0x007D, /* R161 - FLL Control (7) */
+ [162] = 0x0008, /* R162 - FLL Control (8) */
+
+ [252] = 0x0005, /* R252 - General test 1 */
+
+ [256] = 0x0000, /* R256 - DF1 */
+ [257] = 0x0000, /* R257 - DF2 */
+ [258] = 0x0000, /* R258 - DF3 */
+ [259] = 0x0000, /* R259 - DF4 */
+ [260] = 0x0000, /* R260 - DF5 */
+ [261] = 0x0000, /* R261 - DF6 */
+ [262] = 0x0000, /* R262 - DF7 */
+
+ [264] = 0x0000, /* R264 - LHPF1 */
+ [265] = 0x0000, /* R265 - LHPF2 */
+
+ [268] = 0x0000, /* R268 - THREED1 */
+ [269] = 0x0000, /* R269 - THREED2 */
+ [270] = 0x0000, /* R270 - THREED3 */
+ [271] = 0x0000, /* R271 - THREED4 */
+
+ [276] = 0x000C, /* R276 - DRC 1 */
+ [277] = 0x0925, /* R277 - DRC 2 */
+ [278] = 0x0000, /* R278 - DRC 3 */
+ [279] = 0x0000, /* R279 - DRC 4 */
+ [280] = 0x0000, /* R280 - DRC 5 */
+
+ [285] = 0x0000, /* R285 - Tloopback */
+
+ [335] = 0x0004, /* R335 - EQ1 */
+ [336] = 0x6318, /* R336 - EQ2 */
+ [337] = 0x6300, /* R337 - EQ3 */
+ [338] = 0x0FCA, /* R338 - EQ4 */
+ [339] = 0x0400, /* R339 - EQ5 */
+ [340] = 0x00D8, /* R340 - EQ6 */
+ [341] = 0x1EB5, /* R341 - EQ7 */
+ [342] = 0xF145, /* R342 - EQ8 */
+ [343] = 0x0B75, /* R343 - EQ9 */
+ [344] = 0x01C5, /* R344 - EQ10 */
+ [345] = 0x1C58, /* R345 - EQ11 */
+ [346] = 0xF373, /* R346 - EQ12 */
+ [347] = 0x0A54, /* R347 - EQ13 */
+ [348] = 0x0558, /* R348 - EQ14 */
+ [349] = 0x168E, /* R349 - EQ15 */
+ [350] = 0xF829, /* R350 - EQ16 */
+ [351] = 0x07AD, /* R351 - EQ17 */
+ [352] = 0x1103, /* R352 - EQ18 */
+ [353] = 0x0564, /* R353 - EQ19 */
+ [354] = 0x0559, /* R354 - EQ20 */
+ [355] = 0x4000, /* R355 - EQ21 */
+ [356] = 0x6318, /* R356 - EQ22 */
+ [357] = 0x6300, /* R357 - EQ23 */
+ [358] = 0x0FCA, /* R358 - EQ24 */
+ [359] = 0x0400, /* R359 - EQ25 */
+ [360] = 0x00D8, /* R360 - EQ26 */
+ [361] = 0x1EB5, /* R361 - EQ27 */
+ [362] = 0xF145, /* R362 - EQ28 */
+ [363] = 0x0B75, /* R363 - EQ29 */
+ [364] = 0x01C5, /* R364 - EQ30 */
+ [365] = 0x1C58, /* R365 - EQ31 */
+ [366] = 0xF373, /* R366 - EQ32 */
+ [367] = 0x0A54, /* R367 - EQ33 */
+ [368] = 0x0558, /* R368 - EQ34 */
+ [369] = 0x168E, /* R369 - EQ35 */
+ [370] = 0xF829, /* R370 - EQ36 */
+ [371] = 0x07AD, /* R371 - EQ37 */
+ [372] = 0x1103, /* R372 - EQ38 */
+ [373] = 0x0564, /* R373 - EQ39 */
+ [374] = 0x0559, /* R374 - EQ40 */
+ [375] = 0x4000, /* R375 - EQ41 */
+
+ [513] = 0x0000, /* R513 - GPIO 2 */
+ [514] = 0x0000, /* R514 - GPIO 3 */
+
+ [516] = 0x8100, /* R516 - GPIO 5 */
+ [517] = 0x8100, /* R517 - GPIO 6 */
+
+ [560] = 0x0000, /* R560 - Interrupt Status 1 */
+ [561] = 0x0000, /* R561 - Interrupt Status 2 */
+
+ [568] = 0x0030, /* R568 - Interrupt Status 1 Mask */
+ [569] = 0xFFED, /* R569 - Interrupt Status 2 Mask */
+
+ [576] = 0x0000, /* R576 - Interrupt Control */
+
+ [584] = 0x002D, /* R584 - IRQ Debounce */
+
+ [586] = 0x0000, /* R586 - MICINT Source Pol */
+
+ [768] = 0x1C00, /* R768 - DSP2 Power Management */
+
+ [1037] = 0x0000, /* R1037 - DSP2_ExecControl */
+
+ [8192] = 0x0000, /* R8192 - DSP2 Instruction RAM 0 */
+
+ [9216] = 0x0030, /* R9216 - DSP2 Address RAM 2 */
+ [9217] = 0x0000, /* R9217 - DSP2 Address RAM 1 */
+ [9218] = 0x0000, /* R9218 - DSP2 Address RAM 0 */
+
+ [12288] = 0x0000, /* R12288 - DSP2 Data1 RAM 1 */
+ [12289] = 0x0000, /* R12289 - DSP2 Data1 RAM 0 */
+
+ [13312] = 0x0000, /* R13312 - DSP2 Data2 RAM 1 */
+ [13313] = 0x0000, /* R13313 - DSP2 Data2 RAM 0 */
+
+ [14336] = 0x0000, /* R14336 - DSP2 Data3 RAM 1 */
+ [14337] = 0x0000, /* R14337 - DSP2 Data3 RAM 0 */
+
+ [15360] = 0x000A, /* R15360 - DSP2 Coeff RAM 0 */
+
+ [16384] = 0x0000, /* R16384 - RETUNEADC_SHARED_COEFF_1 */
+ [16385] = 0x0000, /* R16385 - RETUNEADC_SHARED_COEFF_0 */
+ [16386] = 0x0000, /* R16386 - RETUNEDAC_SHARED_COEFF_1 */
+ [16387] = 0x0000, /* R16387 - RETUNEDAC_SHARED_COEFF_0 */
+ [16388] = 0x0000, /* R16388 - SOUNDSTAGE_ENABLES_1 */
+ [16389] = 0x0000, /* R16389 - SOUNDSTAGE_ENABLES_0 */
+
+ [16896] = 0x0002, /* R16896 - HDBASS_AI_1 */
+ [16897] = 0xBD12, /* R16897 - HDBASS_AI_0 */
+ [16898] = 0x007C, /* R16898 - HDBASS_AR_1 */
+ [16899] = 0x586C, /* R16899 - HDBASS_AR_0 */
+ [16900] = 0x0053, /* R16900 - HDBASS_B_1 */
+ [16901] = 0x8121, /* R16901 - HDBASS_B_0 */
+ [16902] = 0x003F, /* R16902 - HDBASS_K_1 */
+ [16903] = 0x8BD8, /* R16903 - HDBASS_K_0 */
+ [16904] = 0x0032, /* R16904 - HDBASS_N1_1 */
+ [16905] = 0xF52D, /* R16905 - HDBASS_N1_0 */
+ [16906] = 0x0065, /* R16906 - HDBASS_N2_1 */
+ [16907] = 0xAC8C, /* R16907 - HDBASS_N2_0 */
+ [16908] = 0x006B, /* R16908 - HDBASS_N3_1 */
+ [16909] = 0xE087, /* R16909 - HDBASS_N3_0 */
+ [16910] = 0x0072, /* R16910 - HDBASS_N4_1 */
+ [16911] = 0x1483, /* R16911 - HDBASS_N4_0 */
+ [16912] = 0x0072, /* R16912 - HDBASS_N5_1 */
+ [16913] = 0x1483, /* R16913 - HDBASS_N5_0 */
+ [16914] = 0x0043, /* R16914 - HDBASS_X1_1 */
+ [16915] = 0x3525, /* R16915 - HDBASS_X1_0 */
+ [16916] = 0x0006, /* R16916 - HDBASS_X2_1 */
+ [16917] = 0x6A4A, /* R16917 - HDBASS_X2_0 */
+ [16918] = 0x0043, /* R16918 - HDBASS_X3_1 */
+ [16919] = 0x6079, /* R16919 - HDBASS_X3_0 */
+ [16920] = 0x0008, /* R16920 - HDBASS_ATK_1 */
+ [16921] = 0x0000, /* R16921 - HDBASS_ATK_0 */
+ [16922] = 0x0001, /* R16922 - HDBASS_DCY_1 */
+ [16923] = 0x0000, /* R16923 - HDBASS_DCY_0 */
+ [16924] = 0x0059, /* R16924 - HDBASS_PG_1 */
+ [16925] = 0x999A, /* R16925 - HDBASS_PG_0 */
+
+ [17048] = 0x0083, /* R17408 - HPF_C_1 */
+ [17049] = 0x98AD, /* R17409 - HPF_C_0 */
+
+ [17920] = 0x007F, /* R17920 - ADCL_RETUNE_C1_1 */
+ [17921] = 0xFFFF, /* R17921 - ADCL_RETUNE_C1_0 */
+ [17922] = 0x0000, /* R17922 - ADCL_RETUNE_C2_1 */
+ [17923] = 0x0000, /* R17923 - ADCL_RETUNE_C2_0 */
+ [17924] = 0x0000, /* R17924 - ADCL_RETUNE_C3_1 */
+ [17925] = 0x0000, /* R17925 - ADCL_RETUNE_C3_0 */
+ [17926] = 0x0000, /* R17926 - ADCL_RETUNE_C4_1 */
+ [17927] = 0x0000, /* R17927 - ADCL_RETUNE_C4_0 */
+ [17928] = 0x0000, /* R17928 - ADCL_RETUNE_C5_1 */
+ [17929] = 0x0000, /* R17929 - ADCL_RETUNE_C5_0 */
+ [17930] = 0x0000, /* R17930 - ADCL_RETUNE_C6_1 */
+ [17931] = 0x0000, /* R17931 - ADCL_RETUNE_C6_0 */
+ [17932] = 0x0000, /* R17932 - ADCL_RETUNE_C7_1 */
+ [17933] = 0x0000, /* R17933 - ADCL_RETUNE_C7_0 */
+ [17934] = 0x0000, /* R17934 - ADCL_RETUNE_C8_1 */
+ [17935] = 0x0000, /* R17935 - ADCL_RETUNE_C8_0 */
+ [17936] = 0x0000, /* R17936 - ADCL_RETUNE_C9_1 */
+ [17937] = 0x0000, /* R17937 - ADCL_RETUNE_C9_0 */
+ [17938] = 0x0000, /* R17938 - ADCL_RETUNE_C10_1 */
+ [17939] = 0x0000, /* R17939 - ADCL_RETUNE_C10_0 */
+ [17940] = 0x0000, /* R17940 - ADCL_RETUNE_C11_1 */
+ [17941] = 0x0000, /* R17941 - ADCL_RETUNE_C11_0 */
+ [17942] = 0x0000, /* R17942 - ADCL_RETUNE_C12_1 */
+ [17943] = 0x0000, /* R17943 - ADCL_RETUNE_C12_0 */
+ [17944] = 0x0000, /* R17944 - ADCL_RETUNE_C13_1 */
+ [17945] = 0x0000, /* R17945 - ADCL_RETUNE_C13_0 */
+ [17946] = 0x0000, /* R17946 - ADCL_RETUNE_C14_1 */
+ [17947] = 0x0000, /* R17947 - ADCL_RETUNE_C14_0 */
+ [17948] = 0x0000, /* R17948 - ADCL_RETUNE_C15_1 */
+ [17949] = 0x0000, /* R17949 - ADCL_RETUNE_C15_0 */
+ [17950] = 0x0000, /* R17950 - ADCL_RETUNE_C16_1 */
+ [17951] = 0x0000, /* R17951 - ADCL_RETUNE_C16_0 */
+ [17952] = 0x0000, /* R17952 - ADCL_RETUNE_C17_1 */
+ [17953] = 0x0000, /* R17953 - ADCL_RETUNE_C17_0 */
+ [17954] = 0x0000, /* R17954 - ADCL_RETUNE_C18_1 */
+ [17955] = 0x0000, /* R17955 - ADCL_RETUNE_C18_0 */
+ [17956] = 0x0000, /* R17956 - ADCL_RETUNE_C19_1 */
+ [17957] = 0x0000, /* R17957 - ADCL_RETUNE_C19_0 */
+ [17958] = 0x0000, /* R17958 - ADCL_RETUNE_C20_1 */
+ [17959] = 0x0000, /* R17959 - ADCL_RETUNE_C20_0 */
+ [17960] = 0x0000, /* R17960 - ADCL_RETUNE_C21_1 */
+ [17961] = 0x0000, /* R17961 - ADCL_RETUNE_C21_0 */
+ [17962] = 0x0000, /* R17962 - ADCL_RETUNE_C22_1 */
+ [17963] = 0x0000, /* R17963 - ADCL_RETUNE_C22_0 */
+ [17964] = 0x0000, /* R17964 - ADCL_RETUNE_C23_1 */
+ [17965] = 0x0000, /* R17965 - ADCL_RETUNE_C23_0 */
+ [17966] = 0x0000, /* R17966 - ADCL_RETUNE_C24_1 */
+ [17967] = 0x0000, /* R17967 - ADCL_RETUNE_C24_0 */
+ [17968] = 0x0000, /* R17968 - ADCL_RETUNE_C25_1 */
+ [17969] = 0x0000, /* R17969 - ADCL_RETUNE_C25_0 */
+ [17970] = 0x0000, /* R17970 - ADCL_RETUNE_C26_1 */
+ [17971] = 0x0000, /* R17971 - ADCL_RETUNE_C26_0 */
+ [17972] = 0x0000, /* R17972 - ADCL_RETUNE_C27_1 */
+ [17973] = 0x0000, /* R17973 - ADCL_RETUNE_C27_0 */
+ [17974] = 0x0000, /* R17974 - ADCL_RETUNE_C28_1 */
+ [17975] = 0x0000, /* R17975 - ADCL_RETUNE_C28_0 */
+ [17976] = 0x0000, /* R17976 - ADCL_RETUNE_C29_1 */
+ [17977] = 0x0000, /* R17977 - ADCL_RETUNE_C29_0 */
+ [17978] = 0x0000, /* R17978 - ADCL_RETUNE_C30_1 */
+ [17979] = 0x0000, /* R17979 - ADCL_RETUNE_C30_0 */
+ [17980] = 0x0000, /* R17980 - ADCL_RETUNE_C31_1 */
+ [17981] = 0x0000, /* R17981 - ADCL_RETUNE_C31_0 */
+ [17982] = 0x0000, /* R17982 - ADCL_RETUNE_C32_1 */
+ [17983] = 0x0000, /* R17983 - ADCL_RETUNE_C32_0 */
+
+ [18432] = 0x0020, /* R18432 - RETUNEADC_PG2_1 */
+ [18433] = 0x0000, /* R18433 - RETUNEADC_PG2_0 */
+ [18434] = 0x0040, /* R18434 - RETUNEADC_PG_1 */
+ [18435] = 0x0000, /* R18435 - RETUNEADC_PG_0 */
+
+ [18944] = 0x007F, /* R18944 - ADCR_RETUNE_C1_1 */
+ [18945] = 0xFFFF, /* R18945 - ADCR_RETUNE_C1_0 */
+ [18946] = 0x0000, /* R18946 - ADCR_RETUNE_C2_1 */
+ [18947] = 0x0000, /* R18947 - ADCR_RETUNE_C2_0 */
+ [18948] = 0x0000, /* R18948 - ADCR_RETUNE_C3_1 */
+ [18949] = 0x0000, /* R18949 - ADCR_RETUNE_C3_0 */
+ [18950] = 0x0000, /* R18950 - ADCR_RETUNE_C4_1 */
+ [18951] = 0x0000, /* R18951 - ADCR_RETUNE_C4_0 */
+ [18952] = 0x0000, /* R18952 - ADCR_RETUNE_C5_1 */
+ [18953] = 0x0000, /* R18953 - ADCR_RETUNE_C5_0 */
+ [18954] = 0x0000, /* R18954 - ADCR_RETUNE_C6_1 */
+ [18955] = 0x0000, /* R18955 - ADCR_RETUNE_C6_0 */
+ [18956] = 0x0000, /* R18956 - ADCR_RETUNE_C7_1 */
+ [18957] = 0x0000, /* R18957 - ADCR_RETUNE_C7_0 */
+ [18958] = 0x0000, /* R18958 - ADCR_RETUNE_C8_1 */
+ [18959] = 0x0000, /* R18959 - ADCR_RETUNE_C8_0 */
+ [18960] = 0x0000, /* R18960 - ADCR_RETUNE_C9_1 */
+ [18961] = 0x0000, /* R18961 - ADCR_RETUNE_C9_0 */
+ [18962] = 0x0000, /* R18962 - ADCR_RETUNE_C10_1 */
+ [18963] = 0x0000, /* R18963 - ADCR_RETUNE_C10_0 */
+ [18964] = 0x0000, /* R18964 - ADCR_RETUNE_C11_1 */
+ [18965] = 0x0000, /* R18965 - ADCR_RETUNE_C11_0 */
+ [18966] = 0x0000, /* R18966 - ADCR_RETUNE_C12_1 */
+ [18967] = 0x0000, /* R18967 - ADCR_RETUNE_C12_0 */
+ [18968] = 0x0000, /* R18968 - ADCR_RETUNE_C13_1 */
+ [18969] = 0x0000, /* R18969 - ADCR_RETUNE_C13_0 */
+ [18970] = 0x0000, /* R18970 - ADCR_RETUNE_C14_1 */
+ [18971] = 0x0000, /* R18971 - ADCR_RETUNE_C14_0 */
+ [18972] = 0x0000, /* R18972 - ADCR_RETUNE_C15_1 */
+ [18973] = 0x0000, /* R18973 - ADCR_RETUNE_C15_0 */
+ [18974] = 0x0000, /* R18974 - ADCR_RETUNE_C16_1 */
+ [18975] = 0x0000, /* R18975 - ADCR_RETUNE_C16_0 */
+ [18976] = 0x0000, /* R18976 - ADCR_RETUNE_C17_1 */
+ [18977] = 0x0000, /* R18977 - ADCR_RETUNE_C17_0 */
+ [18978] = 0x0000, /* R18978 - ADCR_RETUNE_C18_1 */
+ [18979] = 0x0000, /* R18979 - ADCR_RETUNE_C18_0 */
+ [18980] = 0x0000, /* R18980 - ADCR_RETUNE_C19_1 */
+ [18981] = 0x0000, /* R18981 - ADCR_RETUNE_C19_0 */
+ [18982] = 0x0000, /* R18982 - ADCR_RETUNE_C20_1 */
+ [18983] = 0x0000, /* R18983 - ADCR_RETUNE_C20_0 */
+ [18984] = 0x0000, /* R18984 - ADCR_RETUNE_C21_1 */
+ [18985] = 0x0000, /* R18985 - ADCR_RETUNE_C21_0 */
+ [18986] = 0x0000, /* R18986 - ADCR_RETUNE_C22_1 */
+ [18987] = 0x0000, /* R18987 - ADCR_RETUNE_C22_0 */
+ [18988] = 0x0000, /* R18988 - ADCR_RETUNE_C23_1 */
+ [18989] = 0x0000, /* R18989 - ADCR_RETUNE_C23_0 */
+ [18990] = 0x0000, /* R18990 - ADCR_RETUNE_C24_1 */
+ [18991] = 0x0000, /* R18991 - ADCR_RETUNE_C24_0 */
+ [18992] = 0x0000, /* R18992 - ADCR_RETUNE_C25_1 */
+ [18993] = 0x0000, /* R18993 - ADCR_RETUNE_C25_0 */
+ [18994] = 0x0000, /* R18994 - ADCR_RETUNE_C26_1 */
+ [18995] = 0x0000, /* R18995 - ADCR_RETUNE_C26_0 */
+ [18996] = 0x0000, /* R18996 - ADCR_RETUNE_C27_1 */
+ [18997] = 0x0000, /* R18997 - ADCR_RETUNE_C27_0 */
+ [18998] = 0x0000, /* R18998 - ADCR_RETUNE_C28_1 */
+ [18999] = 0x0000, /* R18999 - ADCR_RETUNE_C28_0 */
+ [19000] = 0x0000, /* R19000 - ADCR_RETUNE_C29_1 */
+ [19001] = 0x0000, /* R19001 - ADCR_RETUNE_C29_0 */
+ [19002] = 0x0000, /* R19002 - ADCR_RETUNE_C30_1 */
+ [19003] = 0x0000, /* R19003 - ADCR_RETUNE_C30_0 */
+ [19004] = 0x0000, /* R19004 - ADCR_RETUNE_C31_1 */
+ [19005] = 0x0000, /* R19005 - ADCR_RETUNE_C31_0 */
+ [19006] = 0x0000, /* R19006 - ADCR_RETUNE_C32_1 */
+ [19007] = 0x0000, /* R19007 - ADCR_RETUNE_C32_0 */
+
+ [19456] = 0x007F, /* R19456 - DACL_RETUNE_C1_1 */
+ [19457] = 0xFFFF, /* R19457 - DACL_RETUNE_C1_0 */
+ [19458] = 0x0000, /* R19458 - DACL_RETUNE_C2_1 */
+ [19459] = 0x0000, /* R19459 - DACL_RETUNE_C2_0 */
+ [19460] = 0x0000, /* R19460 - DACL_RETUNE_C3_1 */
+ [19461] = 0x0000, /* R19461 - DACL_RETUNE_C3_0 */
+ [19462] = 0x0000, /* R19462 - DACL_RETUNE_C4_1 */
+ [19463] = 0x0000, /* R19463 - DACL_RETUNE_C4_0 */
+ [19464] = 0x0000, /* R19464 - DACL_RETUNE_C5_1 */
+ [19465] = 0x0000, /* R19465 - DACL_RETUNE_C5_0 */
+ [19466] = 0x0000, /* R19466 - DACL_RETUNE_C6_1 */
+ [19467] = 0x0000, /* R19467 - DACL_RETUNE_C6_0 */
+ [19468] = 0x0000, /* R19468 - DACL_RETUNE_C7_1 */
+ [19469] = 0x0000, /* R19469 - DACL_RETUNE_C7_0 */
+ [19470] = 0x0000, /* R19470 - DACL_RETUNE_C8_1 */
+ [19471] = 0x0000, /* R19471 - DACL_RETUNE_C8_0 */
+ [19472] = 0x0000, /* R19472 - DACL_RETUNE_C9_1 */
+ [19473] = 0x0000, /* R19473 - DACL_RETUNE_C9_0 */
+ [19474] = 0x0000, /* R19474 - DACL_RETUNE_C10_1 */
+ [19475] = 0x0000, /* R19475 - DACL_RETUNE_C10_0 */
+ [19476] = 0x0000, /* R19476 - DACL_RETUNE_C11_1 */
+ [19477] = 0x0000, /* R19477 - DACL_RETUNE_C11_0 */
+ [19478] = 0x0000, /* R19478 - DACL_RETUNE_C12_1 */
+ [19479] = 0x0000, /* R19479 - DACL_RETUNE_C12_0 */
+ [19480] = 0x0000, /* R19480 - DACL_RETUNE_C13_1 */
+ [19481] = 0x0000, /* R19481 - DACL_RETUNE_C13_0 */
+ [19482] = 0x0000, /* R19482 - DACL_RETUNE_C14_1 */
+ [19483] = 0x0000, /* R19483 - DACL_RETUNE_C14_0 */
+ [19484] = 0x0000, /* R19484 - DACL_RETUNE_C15_1 */
+ [19485] = 0x0000, /* R19485 - DACL_RETUNE_C15_0 */
+ [19486] = 0x0000, /* R19486 - DACL_RETUNE_C16_1 */
+ [19487] = 0x0000, /* R19487 - DACL_RETUNE_C16_0 */
+ [19488] = 0x0000, /* R19488 - DACL_RETUNE_C17_1 */
+ [19489] = 0x0000, /* R19489 - DACL_RETUNE_C17_0 */
+ [19490] = 0x0000, /* R19490 - DACL_RETUNE_C18_1 */
+ [19491] = 0x0000, /* R19491 - DACL_RETUNE_C18_0 */
+ [19492] = 0x0000, /* R19492 - DACL_RETUNE_C19_1 */
+ [19493] = 0x0000, /* R19493 - DACL_RETUNE_C19_0 */
+ [19494] = 0x0000, /* R19494 - DACL_RETUNE_C20_1 */
+ [19495] = 0x0000, /* R19495 - DACL_RETUNE_C20_0 */
+ [19496] = 0x0000, /* R19496 - DACL_RETUNE_C21_1 */
+ [19497] = 0x0000, /* R19497 - DACL_RETUNE_C21_0 */
+ [19498] = 0x0000, /* R19498 - DACL_RETUNE_C22_1 */
+ [19499] = 0x0000, /* R19499 - DACL_RETUNE_C22_0 */
+ [19500] = 0x0000, /* R19500 - DACL_RETUNE_C23_1 */
+ [19501] = 0x0000, /* R19501 - DACL_RETUNE_C23_0 */
+ [19502] = 0x0000, /* R19502 - DACL_RETUNE_C24_1 */
+ [19503] = 0x0000, /* R19503 - DACL_RETUNE_C24_0 */
+ [19504] = 0x0000, /* R19504 - DACL_RETUNE_C25_1 */
+ [19505] = 0x0000, /* R19505 - DACL_RETUNE_C25_0 */
+ [19506] = 0x0000, /* R19506 - DACL_RETUNE_C26_1 */
+ [19507] = 0x0000, /* R19507 - DACL_RETUNE_C26_0 */
+ [19508] = 0x0000, /* R19508 - DACL_RETUNE_C27_1 */
+ [19509] = 0x0000, /* R19509 - DACL_RETUNE_C27_0 */
+ [19510] = 0x0000, /* R19510 - DACL_RETUNE_C28_1 */
+ [19511] = 0x0000, /* R19511 - DACL_RETUNE_C28_0 */
+ [19512] = 0x0000, /* R19512 - DACL_RETUNE_C29_1 */
+ [19513] = 0x0000, /* R19513 - DACL_RETUNE_C29_0 */
+ [19514] = 0x0000, /* R19514 - DACL_RETUNE_C30_1 */
+ [19515] = 0x0000, /* R19515 - DACL_RETUNE_C30_0 */
+ [19516] = 0x0000, /* R19516 - DACL_RETUNE_C31_1 */
+ [19517] = 0x0000, /* R19517 - DACL_RETUNE_C31_0 */
+ [19518] = 0x0000, /* R19518 - DACL_RETUNE_C32_1 */
+ [19519] = 0x0000, /* R19519 - DACL_RETUNE_C32_0 */
+
+ [19968] = 0x0020, /* R19968 - RETUNEDAC_PG2_1 */
+ [19969] = 0x0000, /* R19969 - RETUNEDAC_PG2_0 */
+ [19970] = 0x0040, /* R19970 - RETUNEDAC_PG_1 */
+ [19971] = 0x0000, /* R19971 - RETUNEDAC_PG_0 */
+
+ [20480] = 0x007F, /* R20480 - DACR_RETUNE_C1_1 */
+ [20481] = 0xFFFF, /* R20481 - DACR_RETUNE_C1_0 */
+ [20482] = 0x0000, /* R20482 - DACR_RETUNE_C2_1 */
+ [20483] = 0x0000, /* R20483 - DACR_RETUNE_C2_0 */
+ [20484] = 0x0000, /* R20484 - DACR_RETUNE_C3_1 */
+ [20485] = 0x0000, /* R20485 - DACR_RETUNE_C3_0 */
+ [20486] = 0x0000, /* R20486 - DACR_RETUNE_C4_1 */
+ [20487] = 0x0000, /* R20487 - DACR_RETUNE_C4_0 */
+ [20488] = 0x0000, /* R20488 - DACR_RETUNE_C5_1 */
+ [20489] = 0x0000, /* R20489 - DACR_RETUNE_C5_0 */
+ [20490] = 0x0000, /* R20490 - DACR_RETUNE_C6_1 */
+ [20491] = 0x0000, /* R20491 - DACR_RETUNE_C6_0 */
+ [20492] = 0x0000, /* R20492 - DACR_RETUNE_C7_1 */
+ [20493] = 0x0000, /* R20493 - DACR_RETUNE_C7_0 */
+ [20494] = 0x0000, /* R20494 - DACR_RETUNE_C8_1 */
+ [20495] = 0x0000, /* R20495 - DACR_RETUNE_C8_0 */
+ [20496] = 0x0000, /* R20496 - DACR_RETUNE_C9_1 */
+ [20497] = 0x0000, /* R20497 - DACR_RETUNE_C9_0 */
+ [20498] = 0x0000, /* R20498 - DACR_RETUNE_C10_1 */
+ [20499] = 0x0000, /* R20499 - DACR_RETUNE_C10_0 */
+ [20500] = 0x0000, /* R20500 - DACR_RETUNE_C11_1 */
+ [20501] = 0x0000, /* R20501 - DACR_RETUNE_C11_0 */
+ [20502] = 0x0000, /* R20502 - DACR_RETUNE_C12_1 */
+ [20503] = 0x0000, /* R20503 - DACR_RETUNE_C12_0 */
+ [20504] = 0x0000, /* R20504 - DACR_RETUNE_C13_1 */
+ [20505] = 0x0000, /* R20505 - DACR_RETUNE_C13_0 */
+ [20506] = 0x0000, /* R20506 - DACR_RETUNE_C14_1 */
+ [20507] = 0x0000, /* R20507 - DACR_RETUNE_C14_0 */
+ [20508] = 0x0000, /* R20508 - DACR_RETUNE_C15_1 */
+ [20509] = 0x0000, /* R20509 - DACR_RETUNE_C15_0 */
+ [20510] = 0x0000, /* R20510 - DACR_RETUNE_C16_1 */
+ [20511] = 0x0000, /* R20511 - DACR_RETUNE_C16_0 */
+ [20512] = 0x0000, /* R20512 - DACR_RETUNE_C17_1 */
+ [20513] = 0x0000, /* R20513 - DACR_RETUNE_C17_0 */
+ [20514] = 0x0000, /* R20514 - DACR_RETUNE_C18_1 */
+ [20515] = 0x0000, /* R20515 - DACR_RETUNE_C18_0 */
+ [20516] = 0x0000, /* R20516 - DACR_RETUNE_C19_1 */
+ [20517] = 0x0000, /* R20517 - DACR_RETUNE_C19_0 */
+ [20518] = 0x0000, /* R20518 - DACR_RETUNE_C20_1 */
+ [20519] = 0x0000, /* R20519 - DACR_RETUNE_C20_0 */
+ [20520] = 0x0000, /* R20520 - DACR_RETUNE_C21_1 */
+ [20521] = 0x0000, /* R20521 - DACR_RETUNE_C21_0 */
+ [20522] = 0x0000, /* R20522 - DACR_RETUNE_C22_1 */
+ [20523] = 0x0000, /* R20523 - DACR_RETUNE_C22_0 */
+ [20524] = 0x0000, /* R20524 - DACR_RETUNE_C23_1 */
+ [20525] = 0x0000, /* R20525 - DACR_RETUNE_C23_0 */
+ [20526] = 0x0000, /* R20526 - DACR_RETUNE_C24_1 */
+ [20527] = 0x0000, /* R20527 - DACR_RETUNE_C24_0 */
+ [20528] = 0x0000, /* R20528 - DACR_RETUNE_C25_1 */
+ [20529] = 0x0000, /* R20529 - DACR_RETUNE_C25_0 */
+ [20530] = 0x0000, /* R20530 - DACR_RETUNE_C26_1 */
+ [20531] = 0x0000, /* R20531 - DACR_RETUNE_C26_0 */
+ [20532] = 0x0000, /* R20532 - DACR_RETUNE_C27_1 */
+ [20533] = 0x0000, /* R20533 - DACR_RETUNE_C27_0 */
+ [20534] = 0x0000, /* R20534 - DACR_RETUNE_C28_1 */
+ [20535] = 0x0000, /* R20535 - DACR_RETUNE_C28_0 */
+ [20536] = 0x0000, /* R20536 - DACR_RETUNE_C29_1 */
+ [20537] = 0x0000, /* R20537 - DACR_RETUNE_C29_0 */
+ [20538] = 0x0000, /* R20538 - DACR_RETUNE_C30_1 */
+ [20539] = 0x0000, /* R20539 - DACR_RETUNE_C30_0 */
+ [20540] = 0x0000, /* R20540 - DACR_RETUNE_C31_1 */
+ [20541] = 0x0000, /* R20541 - DACR_RETUNE_C31_0 */
+ [20542] = 0x0000, /* R20542 - DACR_RETUNE_C32_1 */
+ [20543] = 0x0000, /* R20543 - DACR_RETUNE_C32_0 */
+
+ [20992] = 0x008C, /* R20992 - VSS_XHD2_1 */
+ [20993] = 0x0200, /* R20993 - VSS_XHD2_0 */
+ [20994] = 0x0035, /* R20994 - VSS_XHD3_1 */
+ [20995] = 0x0700, /* R20995 - VSS_XHD3_0 */
+ [20996] = 0x003A, /* R20996 - VSS_XHN1_1 */
+ [20997] = 0x4100, /* R20997 - VSS_XHN1_0 */
+ [20998] = 0x008B, /* R20998 - VSS_XHN2_1 */
+ [20999] = 0x7D00, /* R20999 - VSS_XHN2_0 */
+ [21000] = 0x003A, /* R21000 - VSS_XHN3_1 */
+ [21001] = 0x4100, /* R21001 - VSS_XHN3_0 */
+ [21002] = 0x008C, /* R21002 - VSS_XLA_1 */
+ [21003] = 0xFEE8, /* R21003 - VSS_XLA_0 */
+ [21004] = 0x0078, /* R21004 - VSS_XLB_1 */
+ [21005] = 0x0000, /* R21005 - VSS_XLB_0 */
+ [21006] = 0x003F, /* R21006 - VSS_XLG_1 */
+ [21007] = 0xB260, /* R21007 - VSS_XLG_0 */
+ [21008] = 0x002D, /* R21008 - VSS_PG2_1 */
+ [21009] = 0x1818, /* R21009 - VSS_PG2_0 */
+ [21010] = 0x0020, /* R21010 - VSS_PG_1 */
+ [21011] = 0x0000, /* R21011 - VSS_PG_0 */
+ [21012] = 0x00F1, /* R21012 - VSS_XTD1_1 */
+ [21013] = 0x8340, /* R21013 - VSS_XTD1_0 */
+ [21014] = 0x00FB, /* R21014 - VSS_XTD2_1 */
+ [21015] = 0x8300, /* R21015 - VSS_XTD2_0 */
+ [21016] = 0x00EE, /* R21016 - VSS_XTD3_1 */
+ [21017] = 0xAEC0, /* R21017 - VSS_XTD3_0 */
+ [21018] = 0x00FB, /* R21018 - VSS_XTD4_1 */
+ [21019] = 0xAC40, /* R21019 - VSS_XTD4_0 */
+ [21020] = 0x00F1, /* R21020 - VSS_XTD5_1 */
+ [21021] = 0x7F80, /* R21021 - VSS_XTD5_0 */
+ [21022] = 0x00F4, /* R21022 - VSS_XTD6_1 */
+ [21023] = 0x3B40, /* R21023 - VSS_XTD6_0 */
+ [21024] = 0x00F5, /* R21024 - VSS_XTD7_1 */
+ [21025] = 0xFB00, /* R21025 - VSS_XTD7_0 */
+ [21026] = 0x00EA, /* R21026 - VSS_XTD8_1 */
+ [21027] = 0x10C0, /* R21027 - VSS_XTD8_0 */
+ [21028] = 0x00FC, /* R21028 - VSS_XTD9_1 */
+ [21029] = 0xC580, /* R21029 - VSS_XTD9_0 */
+ [21030] = 0x00E2, /* R21030 - VSS_XTD10_1 */
+ [21031] = 0x75C0, /* R21031 - VSS_XTD10_0 */
+ [21032] = 0x0004, /* R21032 - VSS_XTD11_1 */
+ [21033] = 0xB480, /* R21033 - VSS_XTD11_0 */
+ [21034] = 0x00D4, /* R21034 - VSS_XTD12_1 */
+ [21035] = 0xF980, /* R21035 - VSS_XTD12_0 */
+ [21036] = 0x0004, /* R21036 - VSS_XTD13_1 */
+ [21037] = 0x9140, /* R21037 - VSS_XTD13_0 */
+ [21038] = 0x00D8, /* R21038 - VSS_XTD14_1 */
+ [21039] = 0xA480, /* R21039 - VSS_XTD14_0 */
+ [21040] = 0x0002, /* R21040 - VSS_XTD15_1 */
+ [21041] = 0x3DC0, /* R21041 - VSS_XTD15_0 */
+ [21042] = 0x00CF, /* R21042 - VSS_XTD16_1 */
+ [21043] = 0x7A80, /* R21043 - VSS_XTD16_0 */
+ [21044] = 0x00DC, /* R21044 - VSS_XTD17_1 */
+ [21045] = 0x0600, /* R21045 - VSS_XTD17_0 */
+ [21046] = 0x00F2, /* R21046 - VSS_XTD18_1 */
+ [21047] = 0xDAC0, /* R21047 - VSS_XTD18_0 */
+ [21048] = 0x00BA, /* R21048 - VSS_XTD19_1 */
+ [21049] = 0xF340, /* R21049 - VSS_XTD19_0 */
+ [21050] = 0x000A, /* R21050 - VSS_XTD20_1 */
+ [21051] = 0x7940, /* R21051 - VSS_XTD20_0 */
+ [21052] = 0x001C, /* R21052 - VSS_XTD21_1 */
+ [21053] = 0x0680, /* R21053 - VSS_XTD21_0 */
+ [21054] = 0x00FD, /* R21054 - VSS_XTD22_1 */
+ [21055] = 0x2D00, /* R21055 - VSS_XTD22_0 */
+ [21056] = 0x001C, /* R21056 - VSS_XTD23_1 */
+ [21057] = 0xE840, /* R21057 - VSS_XTD23_0 */
+ [21058] = 0x000D, /* R21058 - VSS_XTD24_1 */
+ [21059] = 0xDC40, /* R21059 - VSS_XTD24_0 */
+ [21060] = 0x00FC, /* R21060 - VSS_XTD25_1 */
+ [21061] = 0x9D00, /* R21061 - VSS_XTD25_0 */
+ [21062] = 0x0009, /* R21062 - VSS_XTD26_1 */
+ [21063] = 0x5580, /* R21063 - VSS_XTD26_0 */
+ [21064] = 0x00FE, /* R21064 - VSS_XTD27_1 */
+ [21065] = 0x7E80, /* R21065 - VSS_XTD27_0 */
+ [21066] = 0x000E, /* R21066 - VSS_XTD28_1 */
+ [21067] = 0xAB40, /* R21067 - VSS_XTD28_0 */
+ [21068] = 0x00F9, /* R21068 - VSS_XTD29_1 */
+ [21069] = 0x9880, /* R21069 - VSS_XTD29_0 */
+ [21070] = 0x0009, /* R21070 - VSS_XTD30_1 */
+ [21071] = 0x87C0, /* R21071 - VSS_XTD30_0 */
+ [21072] = 0x00FD, /* R21072 - VSS_XTD31_1 */
+ [21073] = 0x2C40, /* R21073 - VSS_XTD31_0 */
+ [21074] = 0x0009, /* R21074 - VSS_XTD32_1 */
+ [21075] = 0x4800, /* R21075 - VSS_XTD32_0 */
+ [21076] = 0x0003, /* R21076 - VSS_XTS1_1 */
+ [21077] = 0x5F40, /* R21077 - VSS_XTS1_0 */
+ [21078] = 0x0000, /* R21078 - VSS_XTS2_1 */
+ [21079] = 0x8700, /* R21079 - VSS_XTS2_0 */
+ [21080] = 0x00FA, /* R21080 - VSS_XTS3_1 */
+ [21081] = 0xE4C0, /* R21081 - VSS_XTS3_0 */
+ [21082] = 0x0000, /* R21082 - VSS_XTS4_1 */
+ [21083] = 0x0B40, /* R21083 - VSS_XTS4_0 */
+ [21084] = 0x0004, /* R21084 - VSS_XTS5_1 */
+ [21085] = 0xE180, /* R21085 - VSS_XTS5_0 */
+ [21086] = 0x0001, /* R21086 - VSS_XTS6_1 */
+ [21087] = 0x1F40, /* R21087 - VSS_XTS6_0 */
+ [21088] = 0x00F8, /* R21088 - VSS_XTS7_1 */
+ [21089] = 0xB000, /* R21089 - VSS_XTS7_0 */
+ [21090] = 0x00FB, /* R21090 - VSS_XTS8_1 */
+ [21091] = 0xCBC0, /* R21091 - VSS_XTS8_0 */
+ [21092] = 0x0004, /* R21092 - VSS_XTS9_1 */
+ [21093] = 0xF380, /* R21093 - VSS_XTS9_0 */
+ [21094] = 0x0007, /* R21094 - VSS_XTS10_1 */
+ [21095] = 0xDF40, /* R21095 - VSS_XTS10_0 */
+ [21096] = 0x00FF, /* R21096 - VSS_XTS11_1 */
+ [21097] = 0x0700, /* R21097 - VSS_XTS11_0 */
+ [21098] = 0x00EF, /* R21098 - VSS_XTS12_1 */
+ [21099] = 0xD700, /* R21099 - VSS_XTS12_0 */
+ [21100] = 0x00FB, /* R21100 - VSS_XTS13_1 */
+ [21101] = 0xAF40, /* R21101 - VSS_XTS13_0 */
+ [21102] = 0x0010, /* R21102 - VSS_XTS14_1 */
+ [21103] = 0x8A80, /* R21103 - VSS_XTS14_0 */
+ [21104] = 0x0011, /* R21104 - VSS_XTS15_1 */
+ [21105] = 0x07C0, /* R21105 - VSS_XTS15_0 */
+ [21106] = 0x00E0, /* R21106 - VSS_XTS16_1 */
+ [21107] = 0x0800, /* R21107 - VSS_XTS16_0 */
+ [21108] = 0x00D2, /* R21108 - VSS_XTS17_1 */
+ [21109] = 0x7600, /* R21109 - VSS_XTS17_0 */
+ [21110] = 0x0020, /* R21110 - VSS_XTS18_1 */
+ [21111] = 0xCF40, /* R21111 - VSS_XTS18_0 */
+ [21112] = 0x0030, /* R21112 - VSS_XTS19_1 */
+ [21113] = 0x2340, /* R21113 - VSS_XTS19_0 */
+ [21114] = 0x00FD, /* R21114 - VSS_XTS20_1 */
+ [21115] = 0x69C0, /* R21115 - VSS_XTS20_0 */
+ [21116] = 0x0028, /* R21116 - VSS_XTS21_1 */
+ [21117] = 0x3500, /* R21117 - VSS_XTS21_0 */
+ [21118] = 0x0006, /* R21118 - VSS_XTS22_1 */
+ [21119] = 0x3300, /* R21119 - VSS_XTS22_0 */
+ [21120] = 0x00D9, /* R21120 - VSS_XTS23_1 */
+ [21121] = 0xF6C0, /* R21121 - VSS_XTS23_0 */
+ [21122] = 0x00F3, /* R21122 - VSS_XTS24_1 */
+ [21123] = 0x3340, /* R21123 - VSS_XTS24_0 */
+ [21124] = 0x000F, /* R21124 - VSS_XTS25_1 */
+ [21125] = 0x4200, /* R21125 - VSS_XTS25_0 */
+ [21126] = 0x0004, /* R21126 - VSS_XTS26_1 */
+ [21127] = 0x0C80, /* R21127 - VSS_XTS26_0 */
+ [21128] = 0x00FB, /* R21128 - VSS_XTS27_1 */
+ [21129] = 0x3F80, /* R21129 - VSS_XTS27_0 */
+ [21130] = 0x00F7, /* R21130 - VSS_XTS28_1 */
+ [21131] = 0x57C0, /* R21131 - VSS_XTS28_0 */
+ [21132] = 0x0003, /* R21132 - VSS_XTS29_1 */
+ [21133] = 0x5400, /* R21133 - VSS_XTS29_0 */
+ [21134] = 0x0000, /* R21134 - VSS_XTS30_1 */
+ [21135] = 0xC6C0, /* R21135 - VSS_XTS30_0 */
+ [21136] = 0x0003, /* R21136 - VSS_XTS31_1 */
+ [21137] = 0x12C0, /* R21137 - VSS_XTS31_0 */
+ [21138] = 0x00FD, /* R21138 - VSS_XTS32_1 */
+ [21139] = 0x8580, /* R21139 - VSS_XTS32_0 */
+};
+
+static const struct wm8962_reg_access {
+ u16 read;
+ u16 write;
+ u16 vol;
+} wm8962_reg_access[WM8962_MAX_REGISTER + 1] = {
+ [0] = { 0x00FF, 0x01FF, 0x0000 }, /* R0 - Left Input volume */
+ [1] = { 0xFEFF, 0x01FF, 0xFFFF }, /* R1 - Right Input volume */
+ [2] = { 0x00FF, 0x01FF, 0x0000 }, /* R2 - HPOUTL volume */
+ [3] = { 0x00FF, 0x01FF, 0x0000 }, /* R3 - HPOUTR volume */
+ [4] = { 0x07FE, 0x07FE, 0xFFFF }, /* R4 - Clocking1 */
+ [5] = { 0x007F, 0x007F, 0x0000 }, /* R5 - ADC & DAC Control 1 */
+ [6] = { 0x37ED, 0x37ED, 0x0000 }, /* R6 - ADC & DAC Control 2 */
+ [7] = { 0x1FFF, 0x1FFF, 0x0000 }, /* R7 - Audio Interface 0 */
+ [8] = { 0x0FEF, 0x0FEF, 0xFFFF }, /* R8 - Clocking2 */
+ [9] = { 0x0B9F, 0x039F, 0x0000 }, /* R9 - Audio Interface 1 */
+ [10] = { 0x00FF, 0x01FF, 0x0000 }, /* R10 - Left DAC volume */
+ [11] = { 0x00FF, 0x01FF, 0x0000 }, /* R11 - Right DAC volume */
+ [14] = { 0x07FF, 0x07FF, 0x0000 }, /* R14 - Audio Interface 2 */
+ [15] = { 0xFFFF, 0xFFFF, 0xFFFF }, /* R15 - Software Reset */
+ [17] = { 0x07FF, 0x07FF, 0x0000 }, /* R17 - ALC1 */
+ [18] = { 0xF8FF, 0x00FF, 0xFFFF }, /* R18 - ALC2 */
+ [19] = { 0x1DFF, 0x1DFF, 0x0000 }, /* R19 - ALC3 */
+ [20] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20 - Noise Gate */
+ [21] = { 0x00FF, 0x01FF, 0x0000 }, /* R21 - Left ADC volume */
+ [22] = { 0x00FF, 0x01FF, 0x0000 }, /* R22 - Right ADC volume */
+ [23] = { 0x0161, 0x0161, 0x0000 }, /* R23 - Additional control(1) */
+ [24] = { 0x0008, 0x0008, 0x0000 }, /* R24 - Additional control(2) */
+ [25] = { 0x07FE, 0x07FE, 0x0000 }, /* R25 - Pwr Mgmt (1) */
+ [26] = { 0x01FB, 0x01FB, 0x0000 }, /* R26 - Pwr Mgmt (2) */
+ [27] = { 0x0017, 0x0017, 0x0000 }, /* R27 - Additional Control (3) */
+ [28] = { 0x001C, 0x001C, 0x0000 }, /* R28 - Anti-pop */
+
+ [30] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R30 - Clocking 3 */
+ [31] = { 0x000F, 0x000F, 0x0000 }, /* R31 - Input mixer control (1) */
+ [32] = { 0x01FF, 0x01FF, 0x0000 }, /* R32 - Left input mixer volume */
+ [33] = { 0x01FF, 0x01FF, 0x0000 }, /* R33 - Right input mixer volume */
+ [34] = { 0x003F, 0x003F, 0x0000 }, /* R34 - Input mixer control (2) */
+ [35] = { 0x003F, 0x003F, 0x0000 }, /* R35 - Input bias control */
+ [37] = { 0x001F, 0x001F, 0x0000 }, /* R37 - Left input PGA control */
+ [38] = { 0x001F, 0x001F, 0x0000 }, /* R38 - Right input PGA control */
+ [40] = { 0x00FF, 0x01FF, 0x0000 }, /* R40 - SPKOUTL volume */
+ [41] = { 0x00FF, 0x01FF, 0x0000 }, /* R41 - SPKOUTR volume */
+
+ [47] = { 0x000F, 0x0000, 0x0000 }, /* R47 - Thermal Shutdown Status */
+ [48] = { 0x7EC7, 0x7E07, 0xFFFF }, /* R48 - Additional Control (4) */
+ [49] = { 0x00D3, 0x00D7, 0xFFFF }, /* R49 - Class D Control 1 */
+ [51] = { 0x0047, 0x0047, 0x0000 }, /* R51 - Class D Control 2 */
+ [56] = { 0x001E, 0x001E, 0x0000 }, /* R56 - Clocking 4 */
+ [57] = { 0x02FC, 0x02FC, 0x0000 }, /* R57 - DAC DSP Mixing (1) */
+ [58] = { 0x00FC, 0x00FC, 0x0000 }, /* R58 - DAC DSP Mixing (2) */
+ [60] = { 0x00CC, 0x00CC, 0x0000 }, /* R60 - DC Servo 0 */
+ [61] = { 0x00DD, 0x00DD, 0x0000 }, /* R61 - DC Servo 1 */
+ [64] = { 0x3F80, 0x3F80, 0x0000 }, /* R64 - DC Servo 4 */
+ [66] = { 0x0780, 0x0000, 0xFFFF }, /* R66 - DC Servo 6 */
+ [68] = { 0x0007, 0x0007, 0x0000 }, /* R68 - Analogue PGA Bias */
+ [69] = { 0x00FF, 0x00FF, 0x0000 }, /* R69 - Analogue HP 0 */
+ [71] = { 0x01FF, 0x01FF, 0x0000 }, /* R71 - Analogue HP 2 */
+ [72] = { 0x0001, 0x0001, 0x0000 }, /* R72 - Charge Pump 1 */
+ [82] = { 0x0001, 0x0001, 0x0000 }, /* R82 - Charge Pump B */
+ [87] = { 0x00A0, 0x00A0, 0x0000 }, /* R87 - Write Sequencer Control 1 */
+ [90] = { 0x007F, 0x01FF, 0x0000 }, /* R90 - Write Sequencer Control 2 */
+ [93] = { 0x03F9, 0x0000, 0x0000 }, /* R93 - Write Sequencer Control 3 */
+ [94] = { 0x0070, 0x0070, 0x0000 }, /* R94 - Control Interface */
+ [99] = { 0x000F, 0x000F, 0x0000 }, /* R99 - Mixer Enables */
+ [100] = { 0x00BF, 0x00BF, 0x0000 }, /* R100 - Headphone Mixer (1) */
+ [101] = { 0x00BF, 0x00BF, 0x0000 }, /* R101 - Headphone Mixer (2) */
+ [102] = { 0x01FF, 0x01FF, 0x0000 }, /* R102 - Headphone Mixer (3) */
+ [103] = { 0x01FF, 0x01FF, 0x0000 }, /* R103 - Headphone Mixer (4) */
+ [105] = { 0x00BF, 0x00BF, 0x0000 }, /* R105 - Speaker Mixer (1) */
+ [106] = { 0x00BF, 0x00BF, 0x0000 }, /* R106 - Speaker Mixer (2) */
+ [107] = { 0x01FF, 0x01FF, 0x0000 }, /* R107 - Speaker Mixer (3) */
+ [108] = { 0x01FF, 0x01FF, 0x0000 }, /* R108 - Speaker Mixer (4) */
+ [109] = { 0x00F0, 0x00F0, 0x0000 }, /* R109 - Speaker Mixer (5) */
+ [110] = { 0x00F7, 0x00F7, 0x0000 }, /* R110 - Beep Generator (1) */
+ [115] = { 0x001F, 0x001F, 0x0000 }, /* R115 - Oscillator Trim (3) */
+ [116] = { 0x001F, 0x001F, 0x0000 }, /* R116 - Oscillator Trim (4) */
+ [119] = { 0x00FF, 0x00FF, 0x0000 }, /* R119 - Oscillator Trim (7) */
+ [124] = { 0x0079, 0x0079, 0x0000 }, /* R124 - Analogue Clocking1 */
+ [125] = { 0x00DF, 0x00DF, 0x0000 }, /* R125 - Analogue Clocking2 */
+ [126] = { 0x000D, 0x000D, 0x0000 }, /* R126 - Analogue Clocking3 */
+ [127] = { 0x0000, 0xFFFF, 0x0000 }, /* R127 - PLL Software Reset */
+ [129] = { 0x00B0, 0x00B0, 0x0000 }, /* R129 - PLL2 */
+ [131] = { 0x0003, 0x0003, 0x0000 }, /* R131 - PLL 4 */
+ [136] = { 0x005F, 0x005F, 0x0000 }, /* R136 - PLL 9 */
+ [137] = { 0x00FF, 0x00FF, 0x0000 }, /* R137 - PLL 10 */
+ [138] = { 0x00FF, 0x00FF, 0x0000 }, /* R138 - PLL 11 */
+ [139] = { 0x00FF, 0x00FF, 0x0000 }, /* R139 - PLL 12 */
+ [140] = { 0x005F, 0x005F, 0x0000 }, /* R140 - PLL 13 */
+ [141] = { 0x00FF, 0x00FF, 0x0000 }, /* R141 - PLL 14 */
+ [142] = { 0x00FF, 0x00FF, 0x0000 }, /* R142 - PLL 15 */
+ [143] = { 0x00FF, 0x00FF, 0x0000 }, /* R143 - PLL 16 */
+ [155] = { 0x0067, 0x0067, 0x0000 }, /* R155 - FLL Control (1) */
+ [156] = { 0x01FB, 0x01FB, 0x0000 }, /* R156 - FLL Control (2) */
+ [157] = { 0x0007, 0x0007, 0x0000 }, /* R157 - FLL Control (3) */
+ [159] = { 0x007F, 0x007F, 0x0000 }, /* R159 - FLL Control (5) */
+ [160] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R160 - FLL Control (6) */
+ [161] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R161 - FLL Control (7) */
+ [162] = { 0x03FF, 0x03FF, 0x0000 }, /* R162 - FLL Control (8) */
+ [252] = { 0x0005, 0x0005, 0x0000 }, /* R252 - General test 1 */
+ [256] = { 0x000F, 0x000F, 0x0000 }, /* R256 - DF1 */
+ [257] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R257 - DF2 */
+ [258] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R258 - DF3 */
+ [259] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R259 - DF4 */
+ [260] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R260 - DF5 */
+ [261] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R261 - DF6 */
+ [262] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R262 - DF7 */
+ [264] = { 0x0003, 0x0003, 0x0000 }, /* R264 - LHPF1 */
+ [265] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R265 - LHPF2 */
+ [268] = { 0x0077, 0x0077, 0x0000 }, /* R268 - THREED1 */
+ [269] = { 0xFFFC, 0xFFFC, 0x0000 }, /* R269 - THREED2 */
+ [270] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R270 - THREED3 */
+ [271] = { 0xFFFC, 0xFFFC, 0x0000 }, /* R271 - THREED4 */
+ [276] = { 0x7FFF, 0x7FFF, 0x0000 }, /* R276 - DRC 1 */
+ [277] = { 0x1FFF, 0x1FFF, 0x0000 }, /* R277 - DRC 2 */
+ [278] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R278 - DRC 3 */
+ [279] = { 0x07FF, 0x07FF, 0x0000 }, /* R279 - DRC 4 */
+ [280] = { 0x03FF, 0x03FF, 0x0000 }, /* R280 - DRC 5 */
+ [285] = { 0x0003, 0x0003, 0x0000 }, /* R285 - Tloopback */
+ [335] = { 0x0007, 0x0007, 0x0000 }, /* R335 - EQ1 */
+ [336] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R336 - EQ2 */
+ [337] = { 0xFFC0, 0xFFC0, 0x0000 }, /* R337 - EQ3 */
+ [338] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R338 - EQ4 */
+ [339] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R339 - EQ5 */
+ [340] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R340 - EQ6 */
+ [341] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R341 - EQ7 */
+ [342] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R342 - EQ8 */
+ [343] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R343 - EQ9 */
+ [344] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R344 - EQ10 */
+ [345] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R345 - EQ11 */
+ [346] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R346 - EQ12 */
+ [347] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R347 - EQ13 */
+ [348] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R348 - EQ14 */
+ [349] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R349 - EQ15 */
+ [350] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R350 - EQ16 */
+ [351] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R351 - EQ17 */
+ [352] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R352 - EQ18 */
+ [353] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R353 - EQ19 */
+ [354] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R354 - EQ20 */
+ [355] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R355 - EQ21 */
+ [356] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R356 - EQ22 */
+ [357] = { 0xFFC0, 0xFFC0, 0x0000 }, /* R357 - EQ23 */
+ [358] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R358 - EQ24 */
+ [359] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R359 - EQ25 */
+ [360] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R360 - EQ26 */
+ [361] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R361 - EQ27 */
+ [362] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R362 - EQ28 */
+ [363] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R363 - EQ29 */
+ [364] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R364 - EQ30 */
+ [365] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R365 - EQ31 */
+ [366] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R366 - EQ32 */
+ [367] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R367 - EQ33 */
+ [368] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R368 - EQ34 */
+ [369] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R369 - EQ35 */
+ [370] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R370 - EQ36 */
+ [371] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R371 - EQ37 */
+ [372] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R372 - EQ38 */
+ [373] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R373 - EQ39 */
+ [374] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R374 - EQ40 */
+ [375] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R375 - EQ41 */
+ [513] = { 0x045F, 0x045F, 0x0000 }, /* R513 - GPIO 2 */
+ [514] = { 0x045F, 0x045F, 0x0000 }, /* R514 - GPIO 3 */
+ [516] = { 0xE75F, 0xE75F, 0x0000 }, /* R516 - GPIO 5 */
+ [517] = { 0xE75F, 0xE75F, 0x0000 }, /* R517 - GPIO 6 */
+ [560] = { 0x0030, 0x0030, 0xFFFF }, /* R560 - Interrupt Status 1 */
+ [561] = { 0xFFED, 0xFFED, 0xFFFF }, /* R561 - Interrupt Status 2 */
+ [568] = { 0x0030, 0x0030, 0x0000 }, /* R568 - Interrupt Status 1 Mask */
+ [569] = { 0xFFED, 0xFFED, 0x0000 }, /* R569 - Interrupt Status 2 Mask */
+ [576] = { 0x0001, 0x0001, 0x0000 }, /* R576 - Interrupt Control */
+ [584] = { 0x002D, 0x002D, 0x0000 }, /* R584 - IRQ Debounce */
+ [586] = { 0xC000, 0xC000, 0x0000 }, /* R586 - MICINT Source Pol */
+ [768] = { 0x0001, 0x0001, 0x0000 }, /* R768 - DSP2 Power Management */
+ [1037] = { 0x0000, 0x003F, 0x0000 }, /* R1037 - DSP2_ExecControl */
+ [4096] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4096 - Write Sequencer 0 */
+ [4097] = { 0x00FF, 0x00FF, 0x0000 }, /* R4097 - Write Sequencer 1 */
+ [4098] = { 0x070F, 0x070F, 0x0000 }, /* R4098 - Write Sequencer 2 */
+ [4099] = { 0x010F, 0x010F, 0x0000 }, /* R4099 - Write Sequencer 3 */
+ [4100] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4100 - Write Sequencer 4 */
+ [4101] = { 0x00FF, 0x00FF, 0x0000 }, /* R4101 - Write Sequencer 5 */
+ [4102] = { 0x070F, 0x070F, 0x0000 }, /* R4102 - Write Sequencer 6 */
+ [4103] = { 0x010F, 0x010F, 0x0000 }, /* R4103 - Write Sequencer 7 */
+ [4104] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4104 - Write Sequencer 8 */
+ [4105] = { 0x00FF, 0x00FF, 0x0000 }, /* R4105 - Write Sequencer 9 */
+ [4106] = { 0x070F, 0x070F, 0x0000 }, /* R4106 - Write Sequencer 10 */
+ [4107] = { 0x010F, 0x010F, 0x0000 }, /* R4107 - Write Sequencer 11 */
+ [4108] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4108 - Write Sequencer 12 */
+ [4109] = { 0x00FF, 0x00FF, 0x0000 }, /* R4109 - Write Sequencer 13 */
+ [4110] = { 0x070F, 0x070F, 0x0000 }, /* R4110 - Write Sequencer 14 */
+ [4111] = { 0x010F, 0x010F, 0x0000 }, /* R4111 - Write Sequencer 15 */
+ [4112] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4112 - Write Sequencer 16 */
+ [4113] = { 0x00FF, 0x00FF, 0x0000 }, /* R4113 - Write Sequencer 17 */
+ [4114] = { 0x070F, 0x070F, 0x0000 }, /* R4114 - Write Sequencer 18 */
+ [4115] = { 0x010F, 0x010F, 0x0000 }, /* R4115 - Write Sequencer 19 */
+ [4116] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4116 - Write Sequencer 20 */
+ [4117] = { 0x00FF, 0x00FF, 0x0000 }, /* R4117 - Write Sequencer 21 */
+ [4118] = { 0x070F, 0x070F, 0x0000 }, /* R4118 - Write Sequencer 22 */
+ [4119] = { 0x010F, 0x010F, 0x0000 }, /* R4119 - Write Sequencer 23 */
+ [4120] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4120 - Write Sequencer 24 */
+ [4121] = { 0x00FF, 0x00FF, 0x0000 }, /* R4121 - Write Sequencer 25 */
+ [4122] = { 0x070F, 0x070F, 0x0000 }, /* R4122 - Write Sequencer 26 */
+ [4123] = { 0x010F, 0x010F, 0x0000 }, /* R4123 - Write Sequencer 27 */
+ [4124] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4124 - Write Sequencer 28 */
+ [4125] = { 0x00FF, 0x00FF, 0x0000 }, /* R4125 - Write Sequencer 29 */
+ [4126] = { 0x070F, 0x070F, 0x0000 }, /* R4126 - Write Sequencer 30 */
+ [4127] = { 0x010F, 0x010F, 0x0000 }, /* R4127 - Write Sequencer 31 */
+ [4128] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4128 - Write Sequencer 32 */
+ [4129] = { 0x00FF, 0x00FF, 0x0000 }, /* R4129 - Write Sequencer 33 */
+ [4130] = { 0x070F, 0x070F, 0x0000 }, /* R4130 - Write Sequencer 34 */
+ [4131] = { 0x010F, 0x010F, 0x0000 }, /* R4131 - Write Sequencer 35 */
+ [4132] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4132 - Write Sequencer 36 */
+ [4133] = { 0x00FF, 0x00FF, 0x0000 }, /* R4133 - Write Sequencer 37 */
+ [4134] = { 0x070F, 0x070F, 0x0000 }, /* R4134 - Write Sequencer 38 */
+ [4135] = { 0x010F, 0x010F, 0x0000 }, /* R4135 - Write Sequencer 39 */
+ [4136] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4136 - Write Sequencer 40 */
+ [4137] = { 0x00FF, 0x00FF, 0x0000 }, /* R4137 - Write Sequencer 41 */
+ [4138] = { 0x070F, 0x070F, 0x0000 }, /* R4138 - Write Sequencer 42 */
+ [4139] = { 0x010F, 0x010F, 0x0000 }, /* R4139 - Write Sequencer 43 */
+ [4140] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4140 - Write Sequencer 44 */
+ [4141] = { 0x00FF, 0x00FF, 0x0000 }, /* R4141 - Write Sequencer 45 */
+ [4142] = { 0x070F, 0x070F, 0x0000 }, /* R4142 - Write Sequencer 46 */
+ [4143] = { 0x010F, 0x010F, 0x0000 }, /* R4143 - Write Sequencer 47 */
+ [4144] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4144 - Write Sequencer 48 */
+ [4145] = { 0x00FF, 0x00FF, 0x0000 }, /* R4145 - Write Sequencer 49 */
+ [4146] = { 0x070F, 0x070F, 0x0000 }, /* R4146 - Write Sequencer 50 */
+ [4147] = { 0x010F, 0x010F, 0x0000 }, /* R4147 - Write Sequencer 51 */
+ [4148] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4148 - Write Sequencer 52 */
+ [4149] = { 0x00FF, 0x00FF, 0x0000 }, /* R4149 - Write Sequencer 53 */
+ [4150] = { 0x070F, 0x070F, 0x0000 }, /* R4150 - Write Sequencer 54 */
+ [4151] = { 0x010F, 0x010F, 0x0000 }, /* R4151 - Write Sequencer 55 */
+ [4152] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4152 - Write Sequencer 56 */
+ [4153] = { 0x00FF, 0x00FF, 0x0000 }, /* R4153 - Write Sequencer 57 */
+ [4154] = { 0x070F, 0x070F, 0x0000 }, /* R4154 - Write Sequencer 58 */
+ [4155] = { 0x010F, 0x010F, 0x0000 }, /* R4155 - Write Sequencer 59 */
+ [4156] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4156 - Write Sequencer 60 */
+ [4157] = { 0x00FF, 0x00FF, 0x0000 }, /* R4157 - Write Sequencer 61 */
+ [4158] = { 0x070F, 0x070F, 0x0000 }, /* R4158 - Write Sequencer 62 */
+ [4159] = { 0x010F, 0x010F, 0x0000 }, /* R4159 - Write Sequencer 63 */
+ [4160] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4160 - Write Sequencer 64 */
+ [4161] = { 0x00FF, 0x00FF, 0x0000 }, /* R4161 - Write Sequencer 65 */
+ [4162] = { 0x070F, 0x070F, 0x0000 }, /* R4162 - Write Sequencer 66 */
+ [4163] = { 0x010F, 0x010F, 0x0000 }, /* R4163 - Write Sequencer 67 */
+ [4164] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4164 - Write Sequencer 68 */
+ [4165] = { 0x00FF, 0x00FF, 0x0000 }, /* R4165 - Write Sequencer 69 */
+ [4166] = { 0x070F, 0x070F, 0x0000 }, /* R4166 - Write Sequencer 70 */
+ [4167] = { 0x010F, 0x010F, 0x0000 }, /* R4167 - Write Sequencer 71 */
+ [4168] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4168 - Write Sequencer 72 */
+ [4169] = { 0x00FF, 0x00FF, 0x0000 }, /* R4169 - Write Sequencer 73 */
+ [4170] = { 0x070F, 0x070F, 0x0000 }, /* R4170 - Write Sequencer 74 */
+ [4171] = { 0x010F, 0x010F, 0x0000 }, /* R4171 - Write Sequencer 75 */
+ [4172] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4172 - Write Sequencer 76 */
+ [4173] = { 0x00FF, 0x00FF, 0x0000 }, /* R4173 - Write Sequencer 77 */
+ [4174] = { 0x070F, 0x070F, 0x0000 }, /* R4174 - Write Sequencer 78 */
+ [4175] = { 0x010F, 0x010F, 0x0000 }, /* R4175 - Write Sequencer 79 */
+ [4176] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4176 - Write Sequencer 80 */
+ [4177] = { 0x00FF, 0x00FF, 0x0000 }, /* R4177 - Write Sequencer 81 */
+ [4178] = { 0x070F, 0x070F, 0x0000 }, /* R4178 - Write Sequencer 82 */
+ [4179] = { 0x010F, 0x010F, 0x0000 }, /* R4179 - Write Sequencer 83 */
+ [4180] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4180 - Write Sequencer 84 */
+ [4181] = { 0x00FF, 0x00FF, 0x0000 }, /* R4181 - Write Sequencer 85 */
+ [4182] = { 0x070F, 0x070F, 0x0000 }, /* R4182 - Write Sequencer 86 */
+ [4183] = { 0x010F, 0x010F, 0x0000 }, /* R4183 - Write Sequencer 87 */
+ [4184] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4184 - Write Sequencer 88 */
+ [4185] = { 0x00FF, 0x00FF, 0x0000 }, /* R4185 - Write Sequencer 89 */
+ [4186] = { 0x070F, 0x070F, 0x0000 }, /* R4186 - Write Sequencer 90 */
+ [4187] = { 0x010F, 0x010F, 0x0000 }, /* R4187 - Write Sequencer 91 */
+ [4188] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4188 - Write Sequencer 92 */
+ [4189] = { 0x00FF, 0x00FF, 0x0000 }, /* R4189 - Write Sequencer 93 */
+ [4190] = { 0x070F, 0x070F, 0x0000 }, /* R4190 - Write Sequencer 94 */
+ [4191] = { 0x010F, 0x010F, 0x0000 }, /* R4191 - Write Sequencer 95 */
+ [4192] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4192 - Write Sequencer 96 */
+ [4193] = { 0x00FF, 0x00FF, 0x0000 }, /* R4193 - Write Sequencer 97 */
+ [4194] = { 0x070F, 0x070F, 0x0000 }, /* R4194 - Write Sequencer 98 */
+ [4195] = { 0x010F, 0x010F, 0x0000 }, /* R4195 - Write Sequencer 99 */
+ [4196] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4196 - Write Sequencer 100 */
+ [4197] = { 0x00FF, 0x00FF, 0x0000 }, /* R4197 - Write Sequencer 101 */
+ [4198] = { 0x070F, 0x070F, 0x0000 }, /* R4198 - Write Sequencer 102 */
+ [4199] = { 0x010F, 0x010F, 0x0000 }, /* R4199 - Write Sequencer 103 */
+ [4200] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4200 - Write Sequencer 104 */
+ [4201] = { 0x00FF, 0x00FF, 0x0000 }, /* R4201 - Write Sequencer 105 */
+ [4202] = { 0x070F, 0x070F, 0x0000 }, /* R4202 - Write Sequencer 106 */
+ [4203] = { 0x010F, 0x010F, 0x0000 }, /* R4203 - Write Sequencer 107 */
+ [4204] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4204 - Write Sequencer 108 */
+ [4205] = { 0x00FF, 0x00FF, 0x0000 }, /* R4205 - Write Sequencer 109 */
+ [4206] = { 0x070F, 0x070F, 0x0000 }, /* R4206 - Write Sequencer 110 */
+ [4207] = { 0x010F, 0x010F, 0x0000 }, /* R4207 - Write Sequencer 111 */
+ [4208] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4208 - Write Sequencer 112 */
+ [4209] = { 0x00FF, 0x00FF, 0x0000 }, /* R4209 - Write Sequencer 113 */
+ [4210] = { 0x070F, 0x070F, 0x0000 }, /* R4210 - Write Sequencer 114 */
+ [4211] = { 0x010F, 0x010F, 0x0000 }, /* R4211 - Write Sequencer 115 */
+ [4212] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4212 - Write Sequencer 116 */
+ [4213] = { 0x00FF, 0x00FF, 0x0000 }, /* R4213 - Write Sequencer 117 */
+ [4214] = { 0x070F, 0x070F, 0x0000 }, /* R4214 - Write Sequencer 118 */
+ [4215] = { 0x010F, 0x010F, 0x0000 }, /* R4215 - Write Sequencer 119 */
+ [4216] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4216 - Write Sequencer 120 */
+ [4217] = { 0x00FF, 0x00FF, 0x0000 }, /* R4217 - Write Sequencer 121 */
+ [4218] = { 0x070F, 0x070F, 0x0000 }, /* R4218 - Write Sequencer 122 */
+ [4219] = { 0x010F, 0x010F, 0x0000 }, /* R4219 - Write Sequencer 123 */
+ [4220] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4220 - Write Sequencer 124 */
+ [4221] = { 0x00FF, 0x00FF, 0x0000 }, /* R4221 - Write Sequencer 125 */
+ [4222] = { 0x070F, 0x070F, 0x0000 }, /* R4222 - Write Sequencer 126 */
+ [4223] = { 0x010F, 0x010F, 0x0000 }, /* R4223 - Write Sequencer 127 */
+ [4224] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4224 - Write Sequencer 128 */
+ [4225] = { 0x00FF, 0x00FF, 0x0000 }, /* R4225 - Write Sequencer 129 */
+ [4226] = { 0x070F, 0x070F, 0x0000 }, /* R4226 - Write Sequencer 130 */
+ [4227] = { 0x010F, 0x010F, 0x0000 }, /* R4227 - Write Sequencer 131 */
+ [4228] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4228 - Write Sequencer 132 */
+ [4229] = { 0x00FF, 0x00FF, 0x0000 }, /* R4229 - Write Sequencer 133 */
+ [4230] = { 0x070F, 0x070F, 0x0000 }, /* R4230 - Write Sequencer 134 */
+ [4231] = { 0x010F, 0x010F, 0x0000 }, /* R4231 - Write Sequencer 135 */
+ [4232] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4232 - Write Sequencer 136 */
+ [4233] = { 0x00FF, 0x00FF, 0x0000 }, /* R4233 - Write Sequencer 137 */
+ [4234] = { 0x070F, 0x070F, 0x0000 }, /* R4234 - Write Sequencer 138 */
+ [4235] = { 0x010F, 0x010F, 0x0000 }, /* R4235 - Write Sequencer 139 */
+ [4236] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4236 - Write Sequencer 140 */
+ [4237] = { 0x00FF, 0x00FF, 0x0000 }, /* R4237 - Write Sequencer 141 */
+ [4238] = { 0x070F, 0x070F, 0x0000 }, /* R4238 - Write Sequencer 142 */
+ [4239] = { 0x010F, 0x010F, 0x0000 }, /* R4239 - Write Sequencer 143 */
+ [4240] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4240 - Write Sequencer 144 */
+ [4241] = { 0x00FF, 0x00FF, 0x0000 }, /* R4241 - Write Sequencer 145 */
+ [4242] = { 0x070F, 0x070F, 0x0000 }, /* R4242 - Write Sequencer 146 */
+ [4243] = { 0x010F, 0x010F, 0x0000 }, /* R4243 - Write Sequencer 147 */
+ [4244] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4244 - Write Sequencer 148 */
+ [4245] = { 0x00FF, 0x00FF, 0x0000 }, /* R4245 - Write Sequencer 149 */
+ [4246] = { 0x070F, 0x070F, 0x0000 }, /* R4246 - Write Sequencer 150 */
+ [4247] = { 0x010F, 0x010F, 0x0000 }, /* R4247 - Write Sequencer 151 */
+ [4248] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4248 - Write Sequencer 152 */
+ [4249] = { 0x00FF, 0x00FF, 0x0000 }, /* R4249 - Write Sequencer 153 */
+ [4250] = { 0x070F, 0x070F, 0x0000 }, /* R4250 - Write Sequencer 154 */
+ [4251] = { 0x010F, 0x010F, 0x0000 }, /* R4251 - Write Sequencer 155 */
+ [4252] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4252 - Write Sequencer 156 */
+ [4253] = { 0x00FF, 0x00FF, 0x0000 }, /* R4253 - Write Sequencer 157 */
+ [4254] = { 0x070F, 0x070F, 0x0000 }, /* R4254 - Write Sequencer 158 */
+ [4255] = { 0x010F, 0x010F, 0x0000 }, /* R4255 - Write Sequencer 159 */
+ [4256] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4256 - Write Sequencer 160 */
+ [4257] = { 0x00FF, 0x00FF, 0x0000 }, /* R4257 - Write Sequencer 161 */
+ [4258] = { 0x070F, 0x070F, 0x0000 }, /* R4258 - Write Sequencer 162 */
+ [4259] = { 0x010F, 0x010F, 0x0000 }, /* R4259 - Write Sequencer 163 */
+ [4260] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4260 - Write Sequencer 164 */
+ [4261] = { 0x00FF, 0x00FF, 0x0000 }, /* R4261 - Write Sequencer 165 */
+ [4262] = { 0x070F, 0x070F, 0x0000 }, /* R4262 - Write Sequencer 166 */
+ [4263] = { 0x010F, 0x010F, 0x0000 }, /* R4263 - Write Sequencer 167 */
+ [4264] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4264 - Write Sequencer 168 */
+ [4265] = { 0x00FF, 0x00FF, 0x0000 }, /* R4265 - Write Sequencer 169 */
+ [4266] = { 0x070F, 0x070F, 0x0000 }, /* R4266 - Write Sequencer 170 */
+ [4267] = { 0x010F, 0x010F, 0x0000 }, /* R4267 - Write Sequencer 171 */
+ [4268] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4268 - Write Sequencer 172 */
+ [4269] = { 0x00FF, 0x00FF, 0x0000 }, /* R4269 - Write Sequencer 173 */
+ [4270] = { 0x070F, 0x070F, 0x0000 }, /* R4270 - Write Sequencer 174 */
+ [4271] = { 0x010F, 0x010F, 0x0000 }, /* R4271 - Write Sequencer 175 */
+ [4272] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4272 - Write Sequencer 176 */
+ [4273] = { 0x00FF, 0x00FF, 0x0000 }, /* R4273 - Write Sequencer 177 */
+ [4274] = { 0x070F, 0x070F, 0x0000 }, /* R4274 - Write Sequencer 178 */
+ [4275] = { 0x010F, 0x010F, 0x0000 }, /* R4275 - Write Sequencer 179 */
+ [4276] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4276 - Write Sequencer 180 */
+ [4277] = { 0x00FF, 0x00FF, 0x0000 }, /* R4277 - Write Sequencer 181 */
+ [4278] = { 0x070F, 0x070F, 0x0000 }, /* R4278 - Write Sequencer 182 */
+ [4279] = { 0x010F, 0x010F, 0x0000 }, /* R4279 - Write Sequencer 183 */
+ [4280] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4280 - Write Sequencer 184 */
+ [4281] = { 0x00FF, 0x00FF, 0x0000 }, /* R4281 - Write Sequencer 185 */
+ [4282] = { 0x070F, 0x070F, 0x0000 }, /* R4282 - Write Sequencer 186 */
+ [4283] = { 0x010F, 0x010F, 0x0000 }, /* R4283 - Write Sequencer 187 */
+ [4284] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4284 - Write Sequencer 188 */
+ [4285] = { 0x00FF, 0x00FF, 0x0000 }, /* R4285 - Write Sequencer 189 */
+ [4286] = { 0x070F, 0x070F, 0x0000 }, /* R4286 - Write Sequencer 190 */
+ [4287] = { 0x010F, 0x010F, 0x0000 }, /* R4287 - Write Sequencer 191 */
+ [4288] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4288 - Write Sequencer 192 */
+ [4289] = { 0x00FF, 0x00FF, 0x0000 }, /* R4289 - Write Sequencer 193 */
+ [4290] = { 0x070F, 0x070F, 0x0000 }, /* R4290 - Write Sequencer 194 */
+ [4291] = { 0x010F, 0x010F, 0x0000 }, /* R4291 - Write Sequencer 195 */
+ [4292] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4292 - Write Sequencer 196 */
+ [4293] = { 0x00FF, 0x00FF, 0x0000 }, /* R4293 - Write Sequencer 197 */
+ [4294] = { 0x070F, 0x070F, 0x0000 }, /* R4294 - Write Sequencer 198 */
+ [4295] = { 0x010F, 0x010F, 0x0000 }, /* R4295 - Write Sequencer 199 */
+ [4296] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4296 - Write Sequencer 200 */
+ [4297] = { 0x00FF, 0x00FF, 0x0000 }, /* R4297 - Write Sequencer 201 */
+ [4298] = { 0x070F, 0x070F, 0x0000 }, /* R4298 - Write Sequencer 202 */
+ [4299] = { 0x010F, 0x010F, 0x0000 }, /* R4299 - Write Sequencer 203 */
+ [4300] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4300 - Write Sequencer 204 */
+ [4301] = { 0x00FF, 0x00FF, 0x0000 }, /* R4301 - Write Sequencer 205 */
+ [4302] = { 0x070F, 0x070F, 0x0000 }, /* R4302 - Write Sequencer 206 */
+ [4303] = { 0x010F, 0x010F, 0x0000 }, /* R4303 - Write Sequencer 207 */
+ [4304] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4304 - Write Sequencer 208 */
+ [4305] = { 0x00FF, 0x00FF, 0x0000 }, /* R4305 - Write Sequencer 209 */
+ [4306] = { 0x070F, 0x070F, 0x0000 }, /* R4306 - Write Sequencer 210 */
+ [4307] = { 0x010F, 0x010F, 0x0000 }, /* R4307 - Write Sequencer 211 */
+ [4308] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4308 - Write Sequencer 212 */
+ [4309] = { 0x00FF, 0x00FF, 0x0000 }, /* R4309 - Write Sequencer 213 */
+ [4310] = { 0x070F, 0x070F, 0x0000 }, /* R4310 - Write Sequencer 214 */
+ [4311] = { 0x010F, 0x010F, 0x0000 }, /* R4311 - Write Sequencer 215 */
+ [4312] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4312 - Write Sequencer 216 */
+ [4313] = { 0x00FF, 0x00FF, 0x0000 }, /* R4313 - Write Sequencer 217 */
+ [4314] = { 0x070F, 0x070F, 0x0000 }, /* R4314 - Write Sequencer 218 */
+ [4315] = { 0x010F, 0x010F, 0x0000 }, /* R4315 - Write Sequencer 219 */
+ [4316] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4316 - Write Sequencer 220 */
+ [4317] = { 0x00FF, 0x00FF, 0x0000 }, /* R4317 - Write Sequencer 221 */
+ [4318] = { 0x070F, 0x070F, 0x0000 }, /* R4318 - Write Sequencer 222 */
+ [4319] = { 0x010F, 0x010F, 0x0000 }, /* R4319 - Write Sequencer 223 */
+ [4320] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4320 - Write Sequencer 224 */
+ [4321] = { 0x00FF, 0x00FF, 0x0000 }, /* R4321 - Write Sequencer 225 */
+ [4322] = { 0x070F, 0x070F, 0x0000 }, /* R4322 - Write Sequencer 226 */
+ [4323] = { 0x010F, 0x010F, 0x0000 }, /* R4323 - Write Sequencer 227 */
+ [4324] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4324 - Write Sequencer 228 */
+ [4325] = { 0x00FF, 0x00FF, 0x0000 }, /* R4325 - Write Sequencer 229 */
+ [4326] = { 0x070F, 0x070F, 0x0000 }, /* R4326 - Write Sequencer 230 */
+ [4327] = { 0x010F, 0x010F, 0x0000 }, /* R4327 - Write Sequencer 231 */
+ [4328] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4328 - Write Sequencer 232 */
+ [4329] = { 0x00FF, 0x00FF, 0x0000 }, /* R4329 - Write Sequencer 233 */
+ [4330] = { 0x070F, 0x070F, 0x0000 }, /* R4330 - Write Sequencer 234 */
+ [4331] = { 0x010F, 0x010F, 0x0000 }, /* R4331 - Write Sequencer 235 */
+ [4332] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4332 - Write Sequencer 236 */
+ [4333] = { 0x00FF, 0x00FF, 0x0000 }, /* R4333 - Write Sequencer 237 */
+ [4334] = { 0x070F, 0x070F, 0x0000 }, /* R4334 - Write Sequencer 238 */
+ [4335] = { 0x010F, 0x010F, 0x0000 }, /* R4335 - Write Sequencer 239 */
+ [4336] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4336 - Write Sequencer 240 */
+ [4337] = { 0x00FF, 0x00FF, 0x0000 }, /* R4337 - Write Sequencer 241 */
+ [4338] = { 0x070F, 0x070F, 0x0000 }, /* R4338 - Write Sequencer 242 */
+ [4339] = { 0x010F, 0x010F, 0x0000 }, /* R4339 - Write Sequencer 243 */
+ [4340] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4340 - Write Sequencer 244 */
+ [4341] = { 0x00FF, 0x00FF, 0x0000 }, /* R4341 - Write Sequencer 245 */
+ [4342] = { 0x070F, 0x070F, 0x0000 }, /* R4342 - Write Sequencer 246 */
+ [4343] = { 0x010F, 0x010F, 0x0000 }, /* R4343 - Write Sequencer 247 */
+ [4344] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4344 - Write Sequencer 248 */
+ [4345] = { 0x00FF, 0x00FF, 0x0000 }, /* R4345 - Write Sequencer 249 */
+ [4346] = { 0x070F, 0x070F, 0x0000 }, /* R4346 - Write Sequencer 250 */
+ [4347] = { 0x010F, 0x010F, 0x0000 }, /* R4347 - Write Sequencer 251 */
+ [4348] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4348 - Write Sequencer 252 */
+ [4349] = { 0x00FF, 0x00FF, 0x0000 }, /* R4349 - Write Sequencer 253 */
+ [4350] = { 0x070F, 0x070F, 0x0000 }, /* R4350 - Write Sequencer 254 */
+ [4351] = { 0x010F, 0x010F, 0x0000 }, /* R4351 - Write Sequencer 255 */
+ [4352] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4352 - Write Sequencer 256 */
+ [4353] = { 0x00FF, 0x00FF, 0x0000 }, /* R4353 - Write Sequencer 257 */
+ [4354] = { 0x070F, 0x070F, 0x0000 }, /* R4354 - Write Sequencer 258 */
+ [4355] = { 0x010F, 0x010F, 0x0000 }, /* R4355 - Write Sequencer 259 */
+ [4356] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4356 - Write Sequencer 260 */
+ [4357] = { 0x00FF, 0x00FF, 0x0000 }, /* R4357 - Write Sequencer 261 */
+ [4358] = { 0x070F, 0x070F, 0x0000 }, /* R4358 - Write Sequencer 262 */
+ [4359] = { 0x010F, 0x010F, 0x0000 }, /* R4359 - Write Sequencer 263 */
+ [4360] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4360 - Write Sequencer 264 */
+ [4361] = { 0x00FF, 0x00FF, 0x0000 }, /* R4361 - Write Sequencer 265 */
+ [4362] = { 0x070F, 0x070F, 0x0000 }, /* R4362 - Write Sequencer 266 */
+ [4363] = { 0x010F, 0x010F, 0x0000 }, /* R4363 - Write Sequencer 267 */
+ [4364] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4364 - Write Sequencer 268 */
+ [4365] = { 0x00FF, 0x00FF, 0x0000 }, /* R4365 - Write Sequencer 269 */
+ [4366] = { 0x070F, 0x070F, 0x0000 }, /* R4366 - Write Sequencer 270 */
+ [4367] = { 0x010F, 0x010F, 0x0000 }, /* R4367 - Write Sequencer 271 */
+ [4368] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4368 - Write Sequencer 272 */
+ [4369] = { 0x00FF, 0x00FF, 0x0000 }, /* R4369 - Write Sequencer 273 */
+ [4370] = { 0x070F, 0x070F, 0x0000 }, /* R4370 - Write Sequencer 274 */
+ [4371] = { 0x010F, 0x010F, 0x0000 }, /* R4371 - Write Sequencer 275 */
+ [4372] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4372 - Write Sequencer 276 */
+ [4373] = { 0x00FF, 0x00FF, 0x0000 }, /* R4373 - Write Sequencer 277 */
+ [4374] = { 0x070F, 0x070F, 0x0000 }, /* R4374 - Write Sequencer 278 */
+ [4375] = { 0x010F, 0x010F, 0x0000 }, /* R4375 - Write Sequencer 279 */
+ [4376] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4376 - Write Sequencer 280 */
+ [4377] = { 0x00FF, 0x00FF, 0x0000 }, /* R4377 - Write Sequencer 281 */
+ [4378] = { 0x070F, 0x070F, 0x0000 }, /* R4378 - Write Sequencer 282 */
+ [4379] = { 0x010F, 0x010F, 0x0000 }, /* R4379 - Write Sequencer 283 */
+ [4380] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4380 - Write Sequencer 284 */
+ [4381] = { 0x00FF, 0x00FF, 0x0000 }, /* R4381 - Write Sequencer 285 */
+ [4382] = { 0x070F, 0x070F, 0x0000 }, /* R4382 - Write Sequencer 286 */
+ [4383] = { 0x010F, 0x010F, 0x0000 }, /* R4383 - Write Sequencer 287 */
+ [4384] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4384 - Write Sequencer 288 */
+ [4385] = { 0x00FF, 0x00FF, 0x0000 }, /* R4385 - Write Sequencer 289 */
+ [4386] = { 0x070F, 0x070F, 0x0000 }, /* R4386 - Write Sequencer 290 */
+ [4387] = { 0x010F, 0x010F, 0x0000 }, /* R4387 - Write Sequencer 291 */
+ [4388] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4388 - Write Sequencer 292 */
+ [4389] = { 0x00FF, 0x00FF, 0x0000 }, /* R4389 - Write Sequencer 293 */
+ [4390] = { 0x070F, 0x070F, 0x0000 }, /* R4390 - Write Sequencer 294 */
+ [4391] = { 0x010F, 0x010F, 0x0000 }, /* R4391 - Write Sequencer 295 */
+ [4392] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4392 - Write Sequencer 296 */
+ [4393] = { 0x00FF, 0x00FF, 0x0000 }, /* R4393 - Write Sequencer 297 */
+ [4394] = { 0x070F, 0x070F, 0x0000 }, /* R4394 - Write Sequencer 298 */
+ [4395] = { 0x010F, 0x010F, 0x0000 }, /* R4395 - Write Sequencer 299 */
+ [4396] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4396 - Write Sequencer 300 */
+ [4397] = { 0x00FF, 0x00FF, 0x0000 }, /* R4397 - Write Sequencer 301 */
+ [4398] = { 0x070F, 0x070F, 0x0000 }, /* R4398 - Write Sequencer 302 */
+ [4399] = { 0x010F, 0x010F, 0x0000 }, /* R4399 - Write Sequencer 303 */
+ [4400] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4400 - Write Sequencer 304 */
+ [4401] = { 0x00FF, 0x00FF, 0x0000 }, /* R4401 - Write Sequencer 305 */
+ [4402] = { 0x070F, 0x070F, 0x0000 }, /* R4402 - Write Sequencer 306 */
+ [4403] = { 0x010F, 0x010F, 0x0000 }, /* R4403 - Write Sequencer 307 */
+ [4404] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4404 - Write Sequencer 308 */
+ [4405] = { 0x00FF, 0x00FF, 0x0000 }, /* R4405 - Write Sequencer 309 */
+ [4406] = { 0x070F, 0x070F, 0x0000 }, /* R4406 - Write Sequencer 310 */
+ [4407] = { 0x010F, 0x010F, 0x0000 }, /* R4407 - Write Sequencer 311 */
+ [4408] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4408 - Write Sequencer 312 */
+ [4409] = { 0x00FF, 0x00FF, 0x0000 }, /* R4409 - Write Sequencer 313 */
+ [4410] = { 0x070F, 0x070F, 0x0000 }, /* R4410 - Write Sequencer 314 */
+ [4411] = { 0x010F, 0x010F, 0x0000 }, /* R4411 - Write Sequencer 315 */
+ [4412] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4412 - Write Sequencer 316 */
+ [4413] = { 0x00FF, 0x00FF, 0x0000 }, /* R4413 - Write Sequencer 317 */
+ [4414] = { 0x070F, 0x070F, 0x0000 }, /* R4414 - Write Sequencer 318 */
+ [4415] = { 0x010F, 0x010F, 0x0000 }, /* R4415 - Write Sequencer 319 */
+ [4416] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4416 - Write Sequencer 320 */
+ [4417] = { 0x00FF, 0x00FF, 0x0000 }, /* R4417 - Write Sequencer 321 */
+ [4418] = { 0x070F, 0x070F, 0x0000 }, /* R4418 - Write Sequencer 322 */
+ [4419] = { 0x010F, 0x010F, 0x0000 }, /* R4419 - Write Sequencer 323 */
+ [4420] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4420 - Write Sequencer 324 */
+ [4421] = { 0x00FF, 0x00FF, 0x0000 }, /* R4421 - Write Sequencer 325 */
+ [4422] = { 0x070F, 0x070F, 0x0000 }, /* R4422 - Write Sequencer 326 */
+ [4423] = { 0x010F, 0x010F, 0x0000 }, /* R4423 - Write Sequencer 327 */
+ [4424] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4424 - Write Sequencer 328 */
+ [4425] = { 0x00FF, 0x00FF, 0x0000 }, /* R4425 - Write Sequencer 329 */
+ [4426] = { 0x070F, 0x070F, 0x0000 }, /* R4426 - Write Sequencer 330 */
+ [4427] = { 0x010F, 0x010F, 0x0000 }, /* R4427 - Write Sequencer 331 */
+ [4428] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4428 - Write Sequencer 332 */
+ [4429] = { 0x00FF, 0x00FF, 0x0000 }, /* R4429 - Write Sequencer 333 */
+ [4430] = { 0x070F, 0x070F, 0x0000 }, /* R4430 - Write Sequencer 334 */
+ [4431] = { 0x010F, 0x010F, 0x0000 }, /* R4431 - Write Sequencer 335 */
+ [4432] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4432 - Write Sequencer 336 */
+ [4433] = { 0x00FF, 0x00FF, 0x0000 }, /* R4433 - Write Sequencer 337 */
+ [4434] = { 0x070F, 0x070F, 0x0000 }, /* R4434 - Write Sequencer 338 */
+ [4435] = { 0x010F, 0x010F, 0x0000 }, /* R4435 - Write Sequencer 339 */
+ [4436] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4436 - Write Sequencer 340 */
+ [4437] = { 0x00FF, 0x00FF, 0x0000 }, /* R4437 - Write Sequencer 341 */
+ [4438] = { 0x070F, 0x070F, 0x0000 }, /* R4438 - Write Sequencer 342 */
+ [4439] = { 0x010F, 0x010F, 0x0000 }, /* R4439 - Write Sequencer 343 */
+ [4440] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4440 - Write Sequencer 344 */
+ [4441] = { 0x00FF, 0x00FF, 0x0000 }, /* R4441 - Write Sequencer 345 */
+ [4442] = { 0x070F, 0x070F, 0x0000 }, /* R4442 - Write Sequencer 346 */
+ [4443] = { 0x010F, 0x010F, 0x0000 }, /* R4443 - Write Sequencer 347 */
+ [4444] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4444 - Write Sequencer 348 */
+ [4445] = { 0x00FF, 0x00FF, 0x0000 }, /* R4445 - Write Sequencer 349 */
+ [4446] = { 0x070F, 0x070F, 0x0000 }, /* R4446 - Write Sequencer 350 */
+ [4447] = { 0x010F, 0x010F, 0x0000 }, /* R4447 - Write Sequencer 351 */
+ [4448] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4448 - Write Sequencer 352 */
+ [4449] = { 0x00FF, 0x00FF, 0x0000 }, /* R4449 - Write Sequencer 353 */
+ [4450] = { 0x070F, 0x070F, 0x0000 }, /* R4450 - Write Sequencer 354 */
+ [4451] = { 0x010F, 0x010F, 0x0000 }, /* R4451 - Write Sequencer 355 */
+ [4452] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4452 - Write Sequencer 356 */
+ [4453] = { 0x00FF, 0x00FF, 0x0000 }, /* R4453 - Write Sequencer 357 */
+ [4454] = { 0x070F, 0x070F, 0x0000 }, /* R4454 - Write Sequencer 358 */
+ [4455] = { 0x010F, 0x010F, 0x0000 }, /* R4455 - Write Sequencer 359 */
+ [4456] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4456 - Write Sequencer 360 */
+ [4457] = { 0x00FF, 0x00FF, 0x0000 }, /* R4457 - Write Sequencer 361 */
+ [4458] = { 0x070F, 0x070F, 0x0000 }, /* R4458 - Write Sequencer 362 */
+ [4459] = { 0x010F, 0x010F, 0x0000 }, /* R4459 - Write Sequencer 363 */
+ [4460] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4460 - Write Sequencer 364 */
+ [4461] = { 0x00FF, 0x00FF, 0x0000 }, /* R4461 - Write Sequencer 365 */
+ [4462] = { 0x070F, 0x070F, 0x0000 }, /* R4462 - Write Sequencer 366 */
+ [4463] = { 0x010F, 0x010F, 0x0000 }, /* R4463 - Write Sequencer 367 */
+ [4464] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4464 - Write Sequencer 368 */
+ [4465] = { 0x00FF, 0x00FF, 0x0000 }, /* R4465 - Write Sequencer 369 */
+ [4466] = { 0x070F, 0x070F, 0x0000 }, /* R4466 - Write Sequencer 370 */
+ [4467] = { 0x010F, 0x010F, 0x0000 }, /* R4467 - Write Sequencer 371 */
+ [4468] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4468 - Write Sequencer 372 */
+ [4469] = { 0x00FF, 0x00FF, 0x0000 }, /* R4469 - Write Sequencer 373 */
+ [4470] = { 0x070F, 0x070F, 0x0000 }, /* R4470 - Write Sequencer 374 */
+ [4471] = { 0x010F, 0x010F, 0x0000 }, /* R4471 - Write Sequencer 375 */
+ [4472] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4472 - Write Sequencer 376 */
+ [4473] = { 0x00FF, 0x00FF, 0x0000 }, /* R4473 - Write Sequencer 377 */
+ [4474] = { 0x070F, 0x070F, 0x0000 }, /* R4474 - Write Sequencer 378 */
+ [4475] = { 0x010F, 0x010F, 0x0000 }, /* R4475 - Write Sequencer 379 */
+ [4476] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4476 - Write Sequencer 380 */
+ [4477] = { 0x00FF, 0x00FF, 0x0000 }, /* R4477 - Write Sequencer 381 */
+ [4478] = { 0x070F, 0x070F, 0x0000 }, /* R4478 - Write Sequencer 382 */
+ [4479] = { 0x010F, 0x010F, 0x0000 }, /* R4479 - Write Sequencer 383 */
+ [4480] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4480 - Write Sequencer 384 */
+ [4481] = { 0x00FF, 0x00FF, 0x0000 }, /* R4481 - Write Sequencer 385 */
+ [4482] = { 0x070F, 0x070F, 0x0000 }, /* R4482 - Write Sequencer 386 */
+ [4483] = { 0x010F, 0x010F, 0x0000 }, /* R4483 - Write Sequencer 387 */
+ [4484] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4484 - Write Sequencer 388 */
+ [4485] = { 0x00FF, 0x00FF, 0x0000 }, /* R4485 - Write Sequencer 389 */
+ [4486] = { 0x070F, 0x070F, 0x0000 }, /* R4486 - Write Sequencer 390 */
+ [4487] = { 0x010F, 0x010F, 0x0000 }, /* R4487 - Write Sequencer 391 */
+ [4488] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4488 - Write Sequencer 392 */
+ [4489] = { 0x00FF, 0x00FF, 0x0000 }, /* R4489 - Write Sequencer 393 */
+ [4490] = { 0x070F, 0x070F, 0x0000 }, /* R4490 - Write Sequencer 394 */
+ [4491] = { 0x010F, 0x010F, 0x0000 }, /* R4491 - Write Sequencer 395 */
+ [4492] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4492 - Write Sequencer 396 */
+ [4493] = { 0x00FF, 0x00FF, 0x0000 }, /* R4493 - Write Sequencer 397 */
+ [4494] = { 0x070F, 0x070F, 0x0000 }, /* R4494 - Write Sequencer 398 */
+ [4495] = { 0x010F, 0x010F, 0x0000 }, /* R4495 - Write Sequencer 399 */
+ [4496] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4496 - Write Sequencer 400 */
+ [4497] = { 0x00FF, 0x00FF, 0x0000 }, /* R4497 - Write Sequencer 401 */
+ [4498] = { 0x070F, 0x070F, 0x0000 }, /* R4498 - Write Sequencer 402 */
+ [4499] = { 0x010F, 0x010F, 0x0000 }, /* R4499 - Write Sequencer 403 */
+ [4500] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4500 - Write Sequencer 404 */
+ [4501] = { 0x00FF, 0x00FF, 0x0000 }, /* R4501 - Write Sequencer 405 */
+ [4502] = { 0x070F, 0x070F, 0x0000 }, /* R4502 - Write Sequencer 406 */
+ [4503] = { 0x010F, 0x010F, 0x0000 }, /* R4503 - Write Sequencer 407 */
+ [4504] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4504 - Write Sequencer 408 */
+ [4505] = { 0x00FF, 0x00FF, 0x0000 }, /* R4505 - Write Sequencer 409 */
+ [4506] = { 0x070F, 0x070F, 0x0000 }, /* R4506 - Write Sequencer 410 */
+ [4507] = { 0x010F, 0x010F, 0x0000 }, /* R4507 - Write Sequencer 411 */
+ [4508] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4508 - Write Sequencer 412 */
+ [4509] = { 0x00FF, 0x00FF, 0x0000 }, /* R4509 - Write Sequencer 413 */
+ [4510] = { 0x070F, 0x070F, 0x0000 }, /* R4510 - Write Sequencer 414 */
+ [4511] = { 0x010F, 0x010F, 0x0000 }, /* R4511 - Write Sequencer 415 */
+ [4512] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4512 - Write Sequencer 416 */
+ [4513] = { 0x00FF, 0x00FF, 0x0000 }, /* R4513 - Write Sequencer 417 */
+ [4514] = { 0x070F, 0x070F, 0x0000 }, /* R4514 - Write Sequencer 418 */
+ [4515] = { 0x010F, 0x010F, 0x0000 }, /* R4515 - Write Sequencer 419 */
+ [4516] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4516 - Write Sequencer 420 */
+ [4517] = { 0x00FF, 0x00FF, 0x0000 }, /* R4517 - Write Sequencer 421 */
+ [4518] = { 0x070F, 0x070F, 0x0000 }, /* R4518 - Write Sequencer 422 */
+ [4519] = { 0x010F, 0x010F, 0x0000 }, /* R4519 - Write Sequencer 423 */
+ [4520] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4520 - Write Sequencer 424 */
+ [4521] = { 0x00FF, 0x00FF, 0x0000 }, /* R4521 - Write Sequencer 425 */
+ [4522] = { 0x070F, 0x070F, 0x0000 }, /* R4522 - Write Sequencer 426 */
+ [4523] = { 0x010F, 0x010F, 0x0000 }, /* R4523 - Write Sequencer 427 */
+ [4524] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4524 - Write Sequencer 428 */
+ [4525] = { 0x00FF, 0x00FF, 0x0000 }, /* R4525 - Write Sequencer 429 */
+ [4526] = { 0x070F, 0x070F, 0x0000 }, /* R4526 - Write Sequencer 430 */
+ [4527] = { 0x010F, 0x010F, 0x0000 }, /* R4527 - Write Sequencer 431 */
+ [4528] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4528 - Write Sequencer 432 */
+ [4529] = { 0x00FF, 0x00FF, 0x0000 }, /* R4529 - Write Sequencer 433 */
+ [4530] = { 0x070F, 0x070F, 0x0000 }, /* R4530 - Write Sequencer 434 */
+ [4531] = { 0x010F, 0x010F, 0x0000 }, /* R4531 - Write Sequencer 435 */
+ [4532] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4532 - Write Sequencer 436 */
+ [4533] = { 0x00FF, 0x00FF, 0x0000 }, /* R4533 - Write Sequencer 437 */
+ [4534] = { 0x070F, 0x070F, 0x0000 }, /* R4534 - Write Sequencer 438 */
+ [4535] = { 0x010F, 0x010F, 0x0000 }, /* R4535 - Write Sequencer 439 */
+ [4536] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4536 - Write Sequencer 440 */
+ [4537] = { 0x00FF, 0x00FF, 0x0000 }, /* R4537 - Write Sequencer 441 */
+ [4538] = { 0x070F, 0x070F, 0x0000 }, /* R4538 - Write Sequencer 442 */
+ [4539] = { 0x010F, 0x010F, 0x0000 }, /* R4539 - Write Sequencer 443 */
+ [4540] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4540 - Write Sequencer 444 */
+ [4541] = { 0x00FF, 0x00FF, 0x0000 }, /* R4541 - Write Sequencer 445 */
+ [4542] = { 0x070F, 0x070F, 0x0000 }, /* R4542 - Write Sequencer 446 */
+ [4543] = { 0x010F, 0x010F, 0x0000 }, /* R4543 - Write Sequencer 447 */
+ [4544] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4544 - Write Sequencer 448 */
+ [4545] = { 0x00FF, 0x00FF, 0x0000 }, /* R4545 - Write Sequencer 449 */
+ [4546] = { 0x070F, 0x070F, 0x0000 }, /* R4546 - Write Sequencer 450 */
+ [4547] = { 0x010F, 0x010F, 0x0000 }, /* R4547 - Write Sequencer 451 */
+ [4548] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4548 - Write Sequencer 452 */
+ [4549] = { 0x00FF, 0x00FF, 0x0000 }, /* R4549 - Write Sequencer 453 */
+ [4550] = { 0x070F, 0x070F, 0x0000 }, /* R4550 - Write Sequencer 454 */
+ [4551] = { 0x010F, 0x010F, 0x0000 }, /* R4551 - Write Sequencer 455 */
+ [4552] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4552 - Write Sequencer 456 */
+ [4553] = { 0x00FF, 0x00FF, 0x0000 }, /* R4553 - Write Sequencer 457 */
+ [4554] = { 0x070F, 0x070F, 0x0000 }, /* R4554 - Write Sequencer 458 */
+ [4555] = { 0x010F, 0x010F, 0x0000 }, /* R4555 - Write Sequencer 459 */
+ [4556] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4556 - Write Sequencer 460 */
+ [4557] = { 0x00FF, 0x00FF, 0x0000 }, /* R4557 - Write Sequencer 461 */
+ [4558] = { 0x070F, 0x070F, 0x0000 }, /* R4558 - Write Sequencer 462 */
+ [4559] = { 0x010F, 0x010F, 0x0000 }, /* R4559 - Write Sequencer 463 */
+ [4560] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4560 - Write Sequencer 464 */
+ [4561] = { 0x00FF, 0x00FF, 0x0000 }, /* R4561 - Write Sequencer 465 */
+ [4562] = { 0x070F, 0x070F, 0x0000 }, /* R4562 - Write Sequencer 466 */
+ [4563] = { 0x010F, 0x010F, 0x0000 }, /* R4563 - Write Sequencer 467 */
+ [4564] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4564 - Write Sequencer 468 */
+ [4565] = { 0x00FF, 0x00FF, 0x0000 }, /* R4565 - Write Sequencer 469 */
+ [4566] = { 0x070F, 0x070F, 0x0000 }, /* R4566 - Write Sequencer 470 */
+ [4567] = { 0x010F, 0x010F, 0x0000 }, /* R4567 - Write Sequencer 471 */
+ [4568] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4568 - Write Sequencer 472 */
+ [4569] = { 0x00FF, 0x00FF, 0x0000 }, /* R4569 - Write Sequencer 473 */
+ [4570] = { 0x070F, 0x070F, 0x0000 }, /* R4570 - Write Sequencer 474 */
+ [4571] = { 0x010F, 0x010F, 0x0000 }, /* R4571 - Write Sequencer 475 */
+ [4572] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4572 - Write Sequencer 476 */
+ [4573] = { 0x00FF, 0x00FF, 0x0000 }, /* R4573 - Write Sequencer 477 */
+ [4574] = { 0x070F, 0x070F, 0x0000 }, /* R4574 - Write Sequencer 478 */
+ [4575] = { 0x010F, 0x010F, 0x0000 }, /* R4575 - Write Sequencer 479 */
+ [4576] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4576 - Write Sequencer 480 */
+ [4577] = { 0x00FF, 0x00FF, 0x0000 }, /* R4577 - Write Sequencer 481 */
+ [4578] = { 0x070F, 0x070F, 0x0000 }, /* R4578 - Write Sequencer 482 */
+ [4579] = { 0x010F, 0x010F, 0x0000 }, /* R4579 - Write Sequencer 483 */
+ [4580] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4580 - Write Sequencer 484 */
+ [4581] = { 0x00FF, 0x00FF, 0x0000 }, /* R4581 - Write Sequencer 485 */
+ [4582] = { 0x070F, 0x070F, 0x0000 }, /* R4582 - Write Sequencer 486 */
+ [4583] = { 0x010F, 0x010F, 0x0000 }, /* R4583 - Write Sequencer 487 */
+ [4584] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4584 - Write Sequencer 488 */
+ [4585] = { 0x00FF, 0x00FF, 0x0000 }, /* R4585 - Write Sequencer 489 */
+ [4586] = { 0x070F, 0x070F, 0x0000 }, /* R4586 - Write Sequencer 490 */
+ [4587] = { 0x010F, 0x010F, 0x0000 }, /* R4587 - Write Sequencer 491 */
+ [4588] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4588 - Write Sequencer 492 */
+ [4589] = { 0x00FF, 0x00FF, 0x0000 }, /* R4589 - Write Sequencer 493 */
+ [4590] = { 0x070F, 0x070F, 0x0000 }, /* R4590 - Write Sequencer 494 */
+ [4591] = { 0x010F, 0x010F, 0x0000 }, /* R4591 - Write Sequencer 495 */
+ [4592] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4592 - Write Sequencer 496 */
+ [4593] = { 0x00FF, 0x00FF, 0x0000 }, /* R4593 - Write Sequencer 497 */
+ [4594] = { 0x070F, 0x070F, 0x0000 }, /* R4594 - Write Sequencer 498 */
+ [4595] = { 0x010F, 0x010F, 0x0000 }, /* R4595 - Write Sequencer 499 */
+ [4596] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4596 - Write Sequencer 500 */
+ [4597] = { 0x00FF, 0x00FF, 0x0000 }, /* R4597 - Write Sequencer 501 */
+ [4598] = { 0x070F, 0x070F, 0x0000 }, /* R4598 - Write Sequencer 502 */
+ [4599] = { 0x010F, 0x010F, 0x0000 }, /* R4599 - Write Sequencer 503 */
+ [4600] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4600 - Write Sequencer 504 */
+ [4601] = { 0x00FF, 0x00FF, 0x0000 }, /* R4601 - Write Sequencer 505 */
+ [4602] = { 0x070F, 0x070F, 0x0000 }, /* R4602 - Write Sequencer 506 */
+ [4603] = { 0x010F, 0x010F, 0x0000 }, /* R4603 - Write Sequencer 507 */
+ [4604] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4604 - Write Sequencer 508 */
+ [4605] = { 0x00FF, 0x00FF, 0x0000 }, /* R4605 - Write Sequencer 509 */
+ [4606] = { 0x070F, 0x070F, 0x0000 }, /* R4606 - Write Sequencer 510 */
+ [4607] = { 0x010F, 0x010F, 0x0000 }, /* R4607 - Write Sequencer 511 */
+ [8192] = { 0x03FF, 0x03FF, 0x0000 }, /* R8192 - DSP2 Instruction RAM 0 */
+ [9216] = { 0x003F, 0x003F, 0x0000 }, /* R9216 - DSP2 Address RAM 2 */
+ [9217] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R9217 - DSP2 Address RAM 1 */
+ [9218] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R9218 - DSP2 Address RAM 0 */
+ [12288] = { 0x00FF, 0x00FF, 0x0000 }, /* R12288 - DSP2 Data1 RAM 1 */
+ [12289] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R12289 - DSP2 Data1 RAM 0 */
+ [13312] = { 0x00FF, 0x00FF, 0x0000 }, /* R13312 - DSP2 Data2 RAM 1 */
+ [13313] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R13313 - DSP2 Data2 RAM 0 */
+ [14336] = { 0x00FF, 0x00FF, 0x0000 }, /* R14336 - DSP2 Data3 RAM 1 */
+ [14337] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R14337 - DSP2 Data3 RAM 0 */
+ [15360] = { 0x07FF, 0x07FF, 0x0000 }, /* R15360 - DSP2 Coeff RAM 0 */
+ [16384] = { 0x00FF, 0x00FF, 0x0000 }, /* R16384 - RETUNEADC_SHARED_COEFF_1 */
+ [16385] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16385 - RETUNEADC_SHARED_COEFF_0 */
+ [16386] = { 0x00FF, 0x00FF, 0x0000 }, /* R16386 - RETUNEDAC_SHARED_COEFF_1 */
+ [16387] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16387 - RETUNEDAC_SHARED_COEFF_0 */
+ [16388] = { 0x00FF, 0x00FF, 0x0000 }, /* R16388 - SOUNDSTAGE_ENABLES_1 */
+ [16389] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16389 - SOUNDSTAGE_ENABLES_0 */
+ [16896] = { 0x00FF, 0x00FF, 0x0000 }, /* R16896 - HDBASS_AI_1 */
+ [16897] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16897 - HDBASS_AI_0 */
+ [16898] = { 0x00FF, 0x00FF, 0x0000 }, /* R16898 - HDBASS_AR_1 */
+ [16899] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16899 - HDBASS_AR_0 */
+ [16900] = { 0x00FF, 0x00FF, 0x0000 }, /* R16900 - HDBASS_B_1 */
+ [16901] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16901 - HDBASS_B_0 */
+ [16902] = { 0x00FF, 0x00FF, 0x0000 }, /* R16902 - HDBASS_K_1 */
+ [16903] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16903 - HDBASS_K_0 */
+ [16904] = { 0x00FF, 0x00FF, 0x0000 }, /* R16904 - HDBASS_N1_1 */
+ [16905] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16905 - HDBASS_N1_0 */
+ [16906] = { 0x00FF, 0x00FF, 0x0000 }, /* R16906 - HDBASS_N2_1 */
+ [16907] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16907 - HDBASS_N2_0 */
+ [16908] = { 0x00FF, 0x00FF, 0x0000 }, /* R16908 - HDBASS_N3_1 */
+ [16909] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16909 - HDBASS_N3_0 */
+ [16910] = { 0x00FF, 0x00FF, 0x0000 }, /* R16910 - HDBASS_N4_1 */
+ [16911] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16911 - HDBASS_N4_0 */
+ [16912] = { 0x00FF, 0x00FF, 0x0000 }, /* R16912 - HDBASS_N5_1 */
+ [16913] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16913 - HDBASS_N5_0 */
+ [16914] = { 0x00FF, 0x00FF, 0x0000 }, /* R16914 - HDBASS_X1_1 */
+ [16915] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16915 - HDBASS_X1_0 */
+ [16916] = { 0x00FF, 0x00FF, 0x0000 }, /* R16916 - HDBASS_X2_1 */
+ [16917] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16917 - HDBASS_X2_0 */
+ [16918] = { 0x00FF, 0x00FF, 0x0000 }, /* R16918 - HDBASS_X3_1 */
+ [16919] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16919 - HDBASS_X3_0 */
+ [16920] = { 0x00FF, 0x00FF, 0x0000 }, /* R16920 - HDBASS_ATK_1 */
+ [16921] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16921 - HDBASS_ATK_0 */
+ [16922] = { 0x00FF, 0x00FF, 0x0000 }, /* R16922 - HDBASS_DCY_1 */
+ [16923] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16923 - HDBASS_DCY_0 */
+ [16924] = { 0x00FF, 0x00FF, 0x0000 }, /* R16924 - HDBASS_PG_1 */
+ [16925] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16925 - HDBASS_PG_0 */
+ [17408] = { 0x00FF, 0x00FF, 0x0000 }, /* R17408 - HPF_C_1 */
+ [17409] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17409 - HPF_C_0 */
+ [17920] = { 0x00FF, 0x00FF, 0x0000 }, /* R17920 - ADCL_RETUNE_C1_1 */
+ [17921] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17921 - ADCL_RETUNE_C1_0 */
+ [17922] = { 0x00FF, 0x00FF, 0x0000 }, /* R17922 - ADCL_RETUNE_C2_1 */
+ [17923] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17923 - ADCL_RETUNE_C2_0 */
+ [17924] = { 0x00FF, 0x00FF, 0x0000 }, /* R17924 - ADCL_RETUNE_C3_1 */
+ [17925] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17925 - ADCL_RETUNE_C3_0 */
+ [17926] = { 0x00FF, 0x00FF, 0x0000 }, /* R17926 - ADCL_RETUNE_C4_1 */
+ [17927] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17927 - ADCL_RETUNE_C4_0 */
+ [17928] = { 0x00FF, 0x00FF, 0x0000 }, /* R17928 - ADCL_RETUNE_C5_1 */
+ [17929] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17929 - ADCL_RETUNE_C5_0 */
+ [17930] = { 0x00FF, 0x00FF, 0x0000 }, /* R17930 - ADCL_RETUNE_C6_1 */
+ [17931] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17931 - ADCL_RETUNE_C6_0 */
+ [17932] = { 0x00FF, 0x00FF, 0x0000 }, /* R17932 - ADCL_RETUNE_C7_1 */
+ [17933] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17933 - ADCL_RETUNE_C7_0 */
+ [17934] = { 0x00FF, 0x00FF, 0x0000 }, /* R17934 - ADCL_RETUNE_C8_1 */
+ [17935] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17935 - ADCL_RETUNE_C8_0 */
+ [17936] = { 0x00FF, 0x00FF, 0x0000 }, /* R17936 - ADCL_RETUNE_C9_1 */
+ [17937] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17937 - ADCL_RETUNE_C9_0 */
+ [17938] = { 0x00FF, 0x00FF, 0x0000 }, /* R17938 - ADCL_RETUNE_C10_1 */
+ [17939] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17939 - ADCL_RETUNE_C10_0 */
+ [17940] = { 0x00FF, 0x00FF, 0x0000 }, /* R17940 - ADCL_RETUNE_C11_1 */
+ [17941] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17941 - ADCL_RETUNE_C11_0 */
+ [17942] = { 0x00FF, 0x00FF, 0x0000 }, /* R17942 - ADCL_RETUNE_C12_1 */
+ [17943] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17943 - ADCL_RETUNE_C12_0 */
+ [17944] = { 0x00FF, 0x00FF, 0x0000 }, /* R17944 - ADCL_RETUNE_C13_1 */
+ [17945] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17945 - ADCL_RETUNE_C13_0 */
+ [17946] = { 0x00FF, 0x00FF, 0x0000 }, /* R17946 - ADCL_RETUNE_C14_1 */
+ [17947] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17947 - ADCL_RETUNE_C14_0 */
+ [17948] = { 0x00FF, 0x00FF, 0x0000 }, /* R17948 - ADCL_RETUNE_C15_1 */
+ [17949] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17949 - ADCL_RETUNE_C15_0 */
+ [17950] = { 0x00FF, 0x00FF, 0x0000 }, /* R17950 - ADCL_RETUNE_C16_1 */
+ [17951] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17951 - ADCL_RETUNE_C16_0 */
+ [17952] = { 0x00FF, 0x00FF, 0x0000 }, /* R17952 - ADCL_RETUNE_C17_1 */
+ [17953] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17953 - ADCL_RETUNE_C17_0 */
+ [17954] = { 0x00FF, 0x00FF, 0x0000 }, /* R17954 - ADCL_RETUNE_C18_1 */
+ [17955] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17955 - ADCL_RETUNE_C18_0 */
+ [17956] = { 0x00FF, 0x00FF, 0x0000 }, /* R17956 - ADCL_RETUNE_C19_1 */
+ [17957] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17957 - ADCL_RETUNE_C19_0 */
+ [17958] = { 0x00FF, 0x00FF, 0x0000 }, /* R17958 - ADCL_RETUNE_C20_1 */
+ [17959] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17959 - ADCL_RETUNE_C20_0 */
+ [17960] = { 0x00FF, 0x00FF, 0x0000 }, /* R17960 - ADCL_RETUNE_C21_1 */
+ [17961] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17961 - ADCL_RETUNE_C21_0 */
+ [17962] = { 0x00FF, 0x00FF, 0x0000 }, /* R17962 - ADCL_RETUNE_C22_1 */
+ [17963] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17963 - ADCL_RETUNE_C22_0 */
+ [17964] = { 0x00FF, 0x00FF, 0x0000 }, /* R17964 - ADCL_RETUNE_C23_1 */
+ [17965] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17965 - ADCL_RETUNE_C23_0 */
+ [17966] = { 0x00FF, 0x00FF, 0x0000 }, /* R17966 - ADCL_RETUNE_C24_1 */
+ [17967] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17967 - ADCL_RETUNE_C24_0 */
+ [17968] = { 0x00FF, 0x00FF, 0x0000 }, /* R17968 - ADCL_RETUNE_C25_1 */
+ [17969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17969 - ADCL_RETUNE_C25_0 */
+ [17970] = { 0x00FF, 0x00FF, 0x0000 }, /* R17970 - ADCL_RETUNE_C26_1 */
+ [17971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17971 - ADCL_RETUNE_C26_0 */
+ [17972] = { 0x00FF, 0x00FF, 0x0000 }, /* R17972 - ADCL_RETUNE_C27_1 */
+ [17973] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17973 - ADCL_RETUNE_C27_0 */
+ [17974] = { 0x00FF, 0x00FF, 0x0000 }, /* R17974 - ADCL_RETUNE_C28_1 */
+ [17975] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17975 - ADCL_RETUNE_C28_0 */
+ [17976] = { 0x00FF, 0x00FF, 0x0000 }, /* R17976 - ADCL_RETUNE_C29_1 */
+ [17977] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17977 - ADCL_RETUNE_C29_0 */
+ [17978] = { 0x00FF, 0x00FF, 0x0000 }, /* R17978 - ADCL_RETUNE_C30_1 */
+ [17979] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17979 - ADCL_RETUNE_C30_0 */
+ [17980] = { 0x00FF, 0x00FF, 0x0000 }, /* R17980 - ADCL_RETUNE_C31_1 */
+ [17981] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17981 - ADCL_RETUNE_C31_0 */
+ [17982] = { 0x00FF, 0x00FF, 0x0000 }, /* R17982 - ADCL_RETUNE_C32_1 */
+ [17983] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17983 - ADCL_RETUNE_C32_0 */
+ [18432] = { 0x00FF, 0x00FF, 0x0000 }, /* R18432 - RETUNEADC_PG2_1 */
+ [18433] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18433 - RETUNEADC_PG2_0 */
+ [18434] = { 0x00FF, 0x00FF, 0x0000 }, /* R18434 - RETUNEADC_PG_1 */
+ [18435] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18435 - RETUNEADC_PG_0 */
+ [18944] = { 0x00FF, 0x00FF, 0x0000 }, /* R18944 - ADCR_RETUNE_C1_1 */
+ [18945] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18945 - ADCR_RETUNE_C1_0 */
+ [18946] = { 0x00FF, 0x00FF, 0x0000 }, /* R18946 - ADCR_RETUNE_C2_1 */
+ [18947] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18947 - ADCR_RETUNE_C2_0 */
+ [18948] = { 0x00FF, 0x00FF, 0x0000 }, /* R18948 - ADCR_RETUNE_C3_1 */
+ [18949] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18949 - ADCR_RETUNE_C3_0 */
+ [18950] = { 0x00FF, 0x00FF, 0x0000 }, /* R18950 - ADCR_RETUNE_C4_1 */
+ [18951] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18951 - ADCR_RETUNE_C4_0 */
+ [18952] = { 0x00FF, 0x00FF, 0x0000 }, /* R18952 - ADCR_RETUNE_C5_1 */
+ [18953] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18953 - ADCR_RETUNE_C5_0 */
+ [18954] = { 0x00FF, 0x00FF, 0x0000 }, /* R18954 - ADCR_RETUNE_C6_1 */
+ [18955] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18955 - ADCR_RETUNE_C6_0 */
+ [18956] = { 0x00FF, 0x00FF, 0x0000 }, /* R18956 - ADCR_RETUNE_C7_1 */
+ [18957] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18957 - ADCR_RETUNE_C7_0 */
+ [18958] = { 0x00FF, 0x00FF, 0x0000 }, /* R18958 - ADCR_RETUNE_C8_1 */
+ [18959] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18959 - ADCR_RETUNE_C8_0 */
+ [18960] = { 0x00FF, 0x00FF, 0x0000 }, /* R18960 - ADCR_RETUNE_C9_1 */
+ [18961] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18961 - ADCR_RETUNE_C9_0 */
+ [18962] = { 0x00FF, 0x00FF, 0x0000 }, /* R18962 - ADCR_RETUNE_C10_1 */
+ [18963] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18963 - ADCR_RETUNE_C10_0 */
+ [18964] = { 0x00FF, 0x00FF, 0x0000 }, /* R18964 - ADCR_RETUNE_C11_1 */
+ [18965] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18965 - ADCR_RETUNE_C11_0 */
+ [18966] = { 0x00FF, 0x00FF, 0x0000 }, /* R18966 - ADCR_RETUNE_C12_1 */
+ [18967] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18967 - ADCR_RETUNE_C12_0 */
+ [18968] = { 0x00FF, 0x00FF, 0x0000 }, /* R18968 - ADCR_RETUNE_C13_1 */
+ [18969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18969 - ADCR_RETUNE_C13_0 */
+ [18970] = { 0x00FF, 0x00FF, 0x0000 }, /* R18970 - ADCR_RETUNE_C14_1 */
+ [18971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18971 - ADCR_RETUNE_C14_0 */
+ [18972] = { 0x00FF, 0x00FF, 0x0000 }, /* R18972 - ADCR_RETUNE_C15_1 */
+ [18973] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18973 - ADCR_RETUNE_C15_0 */
+ [18974] = { 0x00FF, 0x00FF, 0x0000 }, /* R18974 - ADCR_RETUNE_C16_1 */
+ [18975] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18975 - ADCR_RETUNE_C16_0 */
+ [18976] = { 0x00FF, 0x00FF, 0x0000 }, /* R18976 - ADCR_RETUNE_C17_1 */
+ [18977] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18977 - ADCR_RETUNE_C17_0 */
+ [18978] = { 0x00FF, 0x00FF, 0x0000 }, /* R18978 - ADCR_RETUNE_C18_1 */
+ [18979] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18979 - ADCR_RETUNE_C18_0 */
+ [18980] = { 0x00FF, 0x00FF, 0x0000 }, /* R18980 - ADCR_RETUNE_C19_1 */
+ [18981] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18981 - ADCR_RETUNE_C19_0 */
+ [18982] = { 0x00FF, 0x00FF, 0x0000 }, /* R18982 - ADCR_RETUNE_C20_1 */
+ [18983] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18983 - ADCR_RETUNE_C20_0 */
+ [18984] = { 0x00FF, 0x00FF, 0x0000 }, /* R18984 - ADCR_RETUNE_C21_1 */
+ [18985] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18985 - ADCR_RETUNE_C21_0 */
+ [18986] = { 0x00FF, 0x00FF, 0x0000 }, /* R18986 - ADCR_RETUNE_C22_1 */
+ [18987] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18987 - ADCR_RETUNE_C22_0 */
+ [18988] = { 0x00FF, 0x00FF, 0x0000 }, /* R18988 - ADCR_RETUNE_C23_1 */
+ [18989] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18989 - ADCR_RETUNE_C23_0 */
+ [18990] = { 0x00FF, 0x00FF, 0x0000 }, /* R18990 - ADCR_RETUNE_C24_1 */
+ [18991] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18991 - ADCR_RETUNE_C24_0 */
+ [18992] = { 0x00FF, 0x00FF, 0x0000 }, /* R18992 - ADCR_RETUNE_C25_1 */
+ [18993] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18993 - ADCR_RETUNE_C25_0 */
+ [18994] = { 0x00FF, 0x00FF, 0x0000 }, /* R18994 - ADCR_RETUNE_C26_1 */
+ [18995] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18995 - ADCR_RETUNE_C26_0 */
+ [18996] = { 0x00FF, 0x00FF, 0x0000 }, /* R18996 - ADCR_RETUNE_C27_1 */
+ [18997] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18997 - ADCR_RETUNE_C27_0 */
+ [18998] = { 0x00FF, 0x00FF, 0x0000 }, /* R18998 - ADCR_RETUNE_C28_1 */
+ [18999] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18999 - ADCR_RETUNE_C28_0 */
+ [19000] = { 0x00FF, 0x00FF, 0x0000 }, /* R19000 - ADCR_RETUNE_C29_1 */
+ [19001] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19001 - ADCR_RETUNE_C29_0 */
+ [19002] = { 0x00FF, 0x00FF, 0x0000 }, /* R19002 - ADCR_RETUNE_C30_1 */
+ [19003] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19003 - ADCR_RETUNE_C30_0 */
+ [19004] = { 0x00FF, 0x00FF, 0x0000 }, /* R19004 - ADCR_RETUNE_C31_1 */
+ [19005] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19005 - ADCR_RETUNE_C31_0 */
+ [19006] = { 0x00FF, 0x00FF, 0x0000 }, /* R19006 - ADCR_RETUNE_C32_1 */
+ [19007] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19007 - ADCR_RETUNE_C32_0 */
+ [19456] = { 0x00FF, 0x00FF, 0x0000 }, /* R19456 - DACL_RETUNE_C1_1 */
+ [19457] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19457 - DACL_RETUNE_C1_0 */
+ [19458] = { 0x00FF, 0x00FF, 0x0000 }, /* R19458 - DACL_RETUNE_C2_1 */
+ [19459] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19459 - DACL_RETUNE_C2_0 */
+ [19460] = { 0x00FF, 0x00FF, 0x0000 }, /* R19460 - DACL_RETUNE_C3_1 */
+ [19461] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19461 - DACL_RETUNE_C3_0 */
+ [19462] = { 0x00FF, 0x00FF, 0x0000 }, /* R19462 - DACL_RETUNE_C4_1 */
+ [19463] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19463 - DACL_RETUNE_C4_0 */
+ [19464] = { 0x00FF, 0x00FF, 0x0000 }, /* R19464 - DACL_RETUNE_C5_1 */
+ [19465] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19465 - DACL_RETUNE_C5_0 */
+ [19466] = { 0x00FF, 0x00FF, 0x0000 }, /* R19466 - DACL_RETUNE_C6_1 */
+ [19467] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19467 - DACL_RETUNE_C6_0 */
+ [19468] = { 0x00FF, 0x00FF, 0x0000 }, /* R19468 - DACL_RETUNE_C7_1 */
+ [19469] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19469 - DACL_RETUNE_C7_0 */
+ [19470] = { 0x00FF, 0x00FF, 0x0000 }, /* R19470 - DACL_RETUNE_C8_1 */
+ [19471] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19471 - DACL_RETUNE_C8_0 */
+ [19472] = { 0x00FF, 0x00FF, 0x0000 }, /* R19472 - DACL_RETUNE_C9_1 */
+ [19473] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19473 - DACL_RETUNE_C9_0 */
+ [19474] = { 0x00FF, 0x00FF, 0x0000 }, /* R19474 - DACL_RETUNE_C10_1 */
+ [19475] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19475 - DACL_RETUNE_C10_0 */
+ [19476] = { 0x00FF, 0x00FF, 0x0000 }, /* R19476 - DACL_RETUNE_C11_1 */
+ [19477] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19477 - DACL_RETUNE_C11_0 */
+ [19478] = { 0x00FF, 0x00FF, 0x0000 }, /* R19478 - DACL_RETUNE_C12_1 */
+ [19479] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19479 - DACL_RETUNE_C12_0 */
+ [19480] = { 0x00FF, 0x00FF, 0x0000 }, /* R19480 - DACL_RETUNE_C13_1 */
+ [19481] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19481 - DACL_RETUNE_C13_0 */
+ [19482] = { 0x00FF, 0x00FF, 0x0000 }, /* R19482 - DACL_RETUNE_C14_1 */
+ [19483] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19483 - DACL_RETUNE_C14_0 */
+ [19484] = { 0x00FF, 0x00FF, 0x0000 }, /* R19484 - DACL_RETUNE_C15_1 */
+ [19485] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19485 - DACL_RETUNE_C15_0 */
+ [19486] = { 0x00FF, 0x00FF, 0x0000 }, /* R19486 - DACL_RETUNE_C16_1 */
+ [19487] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19487 - DACL_RETUNE_C16_0 */
+ [19488] = { 0x00FF, 0x00FF, 0x0000 }, /* R19488 - DACL_RETUNE_C17_1 */
+ [19489] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19489 - DACL_RETUNE_C17_0 */
+ [19490] = { 0x00FF, 0x00FF, 0x0000 }, /* R19490 - DACL_RETUNE_C18_1 */
+ [19491] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19491 - DACL_RETUNE_C18_0 */
+ [19492] = { 0x00FF, 0x00FF, 0x0000 }, /* R19492 - DACL_RETUNE_C19_1 */
+ [19493] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19493 - DACL_RETUNE_C19_0 */
+ [19494] = { 0x00FF, 0x00FF, 0x0000 }, /* R19494 - DACL_RETUNE_C20_1 */
+ [19495] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19495 - DACL_RETUNE_C20_0 */
+ [19496] = { 0x00FF, 0x00FF, 0x0000 }, /* R19496 - DACL_RETUNE_C21_1 */
+ [19497] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19497 - DACL_RETUNE_C21_0 */
+ [19498] = { 0x00FF, 0x00FF, 0x0000 }, /* R19498 - DACL_RETUNE_C22_1 */
+ [19499] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19499 - DACL_RETUNE_C22_0 */
+ [19500] = { 0x00FF, 0x00FF, 0x0000 }, /* R19500 - DACL_RETUNE_C23_1 */
+ [19501] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19501 - DACL_RETUNE_C23_0 */
+ [19502] = { 0x00FF, 0x00FF, 0x0000 }, /* R19502 - DACL_RETUNE_C24_1 */
+ [19503] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19503 - DACL_RETUNE_C24_0 */
+ [19504] = { 0x00FF, 0x00FF, 0x0000 }, /* R19504 - DACL_RETUNE_C25_1 */
+ [19505] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19505 - DACL_RETUNE_C25_0 */
+ [19506] = { 0x00FF, 0x00FF, 0x0000 }, /* R19506 - DACL_RETUNE_C26_1 */
+ [19507] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19507 - DACL_RETUNE_C26_0 */
+ [19508] = { 0x00FF, 0x00FF, 0x0000 }, /* R19508 - DACL_RETUNE_C27_1 */
+ [19509] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19509 - DACL_RETUNE_C27_0 */
+ [19510] = { 0x00FF, 0x00FF, 0x0000 }, /* R19510 - DACL_RETUNE_C28_1 */
+ [19511] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19511 - DACL_RETUNE_C28_0 */
+ [19512] = { 0x00FF, 0x00FF, 0x0000 }, /* R19512 - DACL_RETUNE_C29_1 */
+ [19513] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19513 - DACL_RETUNE_C29_0 */
+ [19514] = { 0x00FF, 0x00FF, 0x0000 }, /* R19514 - DACL_RETUNE_C30_1 */
+ [19515] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19515 - DACL_RETUNE_C30_0 */
+ [19516] = { 0x00FF, 0x00FF, 0x0000 }, /* R19516 - DACL_RETUNE_C31_1 */
+ [19517] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19517 - DACL_RETUNE_C31_0 */
+ [19518] = { 0x00FF, 0x00FF, 0x0000 }, /* R19518 - DACL_RETUNE_C32_1 */
+ [19519] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19519 - DACL_RETUNE_C32_0 */
+ [19968] = { 0x00FF, 0x00FF, 0x0000 }, /* R19968 - RETUNEDAC_PG2_1 */
+ [19969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19969 - RETUNEDAC_PG2_0 */
+ [19970] = { 0x00FF, 0x00FF, 0x0000 }, /* R19970 - RETUNEDAC_PG_1 */
+ [19971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19971 - RETUNEDAC_PG_0 */
+ [20480] = { 0x00FF, 0x00FF, 0x0000 }, /* R20480 - DACR_RETUNE_C1_1 */
+ [20481] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20481 - DACR_RETUNE_C1_0 */
+ [20482] = { 0x00FF, 0x00FF, 0x0000 }, /* R20482 - DACR_RETUNE_C2_1 */
+ [20483] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20483 - DACR_RETUNE_C2_0 */
+ [20484] = { 0x00FF, 0x00FF, 0x0000 }, /* R20484 - DACR_RETUNE_C3_1 */
+ [20485] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20485 - DACR_RETUNE_C3_0 */
+ [20486] = { 0x00FF, 0x00FF, 0x0000 }, /* R20486 - DACR_RETUNE_C4_1 */
+ [20487] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20487 - DACR_RETUNE_C4_0 */
+ [20488] = { 0x00FF, 0x00FF, 0x0000 }, /* R20488 - DACR_RETUNE_C5_1 */
+ [20489] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20489 - DACR_RETUNE_C5_0 */
+ [20490] = { 0x00FF, 0x00FF, 0x0000 }, /* R20490 - DACR_RETUNE_C6_1 */
+ [20491] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20491 - DACR_RETUNE_C6_0 */
+ [20492] = { 0x00FF, 0x00FF, 0x0000 }, /* R20492 - DACR_RETUNE_C7_1 */
+ [20493] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20493 - DACR_RETUNE_C7_0 */
+ [20494] = { 0x00FF, 0x00FF, 0x0000 }, /* R20494 - DACR_RETUNE_C8_1 */
+ [20495] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20495 - DACR_RETUNE_C8_0 */
+ [20496] = { 0x00FF, 0x00FF, 0x0000 }, /* R20496 - DACR_RETUNE_C9_1 */
+ [20497] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20497 - DACR_RETUNE_C9_0 */
+ [20498] = { 0x00FF, 0x00FF, 0x0000 }, /* R20498 - DACR_RETUNE_C10_1 */
+ [20499] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20499 - DACR_RETUNE_C10_0 */
+ [20500] = { 0x00FF, 0x00FF, 0x0000 }, /* R20500 - DACR_RETUNE_C11_1 */
+ [20501] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20501 - DACR_RETUNE_C11_0 */
+ [20502] = { 0x00FF, 0x00FF, 0x0000 }, /* R20502 - DACR_RETUNE_C12_1 */
+ [20503] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20503 - DACR_RETUNE_C12_0 */
+ [20504] = { 0x00FF, 0x00FF, 0x0000 }, /* R20504 - DACR_RETUNE_C13_1 */
+ [20505] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20505 - DACR_RETUNE_C13_0 */
+ [20506] = { 0x00FF, 0x00FF, 0x0000 }, /* R20506 - DACR_RETUNE_C14_1 */
+ [20507] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20507 - DACR_RETUNE_C14_0 */
+ [20508] = { 0x00FF, 0x00FF, 0x0000 }, /* R20508 - DACR_RETUNE_C15_1 */
+ [20509] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20509 - DACR_RETUNE_C15_0 */
+ [20510] = { 0x00FF, 0x00FF, 0x0000 }, /* R20510 - DACR_RETUNE_C16_1 */
+ [20511] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20511 - DACR_RETUNE_C16_0 */
+ [20512] = { 0x00FF, 0x00FF, 0x0000 }, /* R20512 - DACR_RETUNE_C17_1 */
+ [20513] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20513 - DACR_RETUNE_C17_0 */
+ [20514] = { 0x00FF, 0x00FF, 0x0000 }, /* R20514 - DACR_RETUNE_C18_1 */
+ [20515] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20515 - DACR_RETUNE_C18_0 */
+ [20516] = { 0x00FF, 0x00FF, 0x0000 }, /* R20516 - DACR_RETUNE_C19_1 */
+ [20517] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20517 - DACR_RETUNE_C19_0 */
+ [20518] = { 0x00FF, 0x00FF, 0x0000 }, /* R20518 - DACR_RETUNE_C20_1 */
+ [20519] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20519 - DACR_RETUNE_C20_0 */
+ [20520] = { 0x00FF, 0x00FF, 0x0000 }, /* R20520 - DACR_RETUNE_C21_1 */
+ [20521] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20521 - DACR_RETUNE_C21_0 */
+ [20522] = { 0x00FF, 0x00FF, 0x0000 }, /* R20522 - DACR_RETUNE_C22_1 */
+ [20523] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20523 - DACR_RETUNE_C22_0 */
+ [20524] = { 0x00FF, 0x00FF, 0x0000 }, /* R20524 - DACR_RETUNE_C23_1 */
+ [20525] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20525 - DACR_RETUNE_C23_0 */
+ [20526] = { 0x00FF, 0x00FF, 0x0000 }, /* R20526 - DACR_RETUNE_C24_1 */
+ [20527] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20527 - DACR_RETUNE_C24_0 */
+ [20528] = { 0x00FF, 0x00FF, 0x0000 }, /* R20528 - DACR_RETUNE_C25_1 */
+ [20529] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20529 - DACR_RETUNE_C25_0 */
+ [20530] = { 0x00FF, 0x00FF, 0x0000 }, /* R20530 - DACR_RETUNE_C26_1 */
+ [20531] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20531 - DACR_RETUNE_C26_0 */
+ [20532] = { 0x00FF, 0x00FF, 0x0000 }, /* R20532 - DACR_RETUNE_C27_1 */
+ [20533] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20533 - DACR_RETUNE_C27_0 */
+ [20534] = { 0x00FF, 0x00FF, 0x0000 }, /* R20534 - DACR_RETUNE_C28_1 */
+ [20535] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20535 - DACR_RETUNE_C28_0 */
+ [20536] = { 0x00FF, 0x00FF, 0x0000 }, /* R20536 - DACR_RETUNE_C29_1 */
+ [20537] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20537 - DACR_RETUNE_C29_0 */
+ [20538] = { 0x00FF, 0x00FF, 0x0000 }, /* R20538 - DACR_RETUNE_C30_1 */
+ [20539] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20539 - DACR_RETUNE_C30_0 */
+ [20540] = { 0x00FF, 0x00FF, 0x0000 }, /* R20540 - DACR_RETUNE_C31_1 */
+ [20541] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20541 - DACR_RETUNE_C31_0 */
+ [20542] = { 0x00FF, 0x00FF, 0x0000 }, /* R20542 - DACR_RETUNE_C32_1 */
+ [20543] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20543 - DACR_RETUNE_C32_0 */
+ [20992] = { 0x00FF, 0x00FF, 0x0000 }, /* R20992 - VSS_XHD2_1 */
+ [20993] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20993 - VSS_XHD2_0 */
+ [20994] = { 0x00FF, 0x00FF, 0x0000 }, /* R20994 - VSS_XHD3_1 */
+ [20995] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20995 - VSS_XHD3_0 */
+ [20996] = { 0x00FF, 0x00FF, 0x0000 }, /* R20996 - VSS_XHN1_1 */
+ [20997] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20997 - VSS_XHN1_0 */
+ [20998] = { 0x00FF, 0x00FF, 0x0000 }, /* R20998 - VSS_XHN2_1 */
+ [20999] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20999 - VSS_XHN2_0 */
+ [21000] = { 0x00FF, 0x00FF, 0x0000 }, /* R21000 - VSS_XHN3_1 */
+ [21001] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21001 - VSS_XHN3_0 */
+ [21002] = { 0x00FF, 0x00FF, 0x0000 }, /* R21002 - VSS_XLA_1 */
+ [21003] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21003 - VSS_XLA_0 */
+ [21004] = { 0x00FF, 0x00FF, 0x0000 }, /* R21004 - VSS_XLB_1 */
+ [21005] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21005 - VSS_XLB_0 */
+ [21006] = { 0x00FF, 0x00FF, 0x0000 }, /* R21006 - VSS_XLG_1 */
+ [21007] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21007 - VSS_XLG_0 */
+ [21008] = { 0x00FF, 0x00FF, 0x0000 }, /* R21008 - VSS_PG2_1 */
+ [21009] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21009 - VSS_PG2_0 */
+ [21010] = { 0x00FF, 0x00FF, 0x0000 }, /* R21010 - VSS_PG_1 */
+ [21011] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21011 - VSS_PG_0 */
+ [21012] = { 0x00FF, 0x00FF, 0x0000 }, /* R21012 - VSS_XTD1_1 */
+ [21013] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21013 - VSS_XTD1_0 */
+ [21014] = { 0x00FF, 0x00FF, 0x0000 }, /* R21014 - VSS_XTD2_1 */
+ [21015] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21015 - VSS_XTD2_0 */
+ [21016] = { 0x00FF, 0x00FF, 0x0000 }, /* R21016 - VSS_XTD3_1 */
+ [21017] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21017 - VSS_XTD3_0 */
+ [21018] = { 0x00FF, 0x00FF, 0x0000 }, /* R21018 - VSS_XTD4_1 */
+ [21019] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21019 - VSS_XTD4_0 */
+ [21020] = { 0x00FF, 0x00FF, 0x0000 }, /* R21020 - VSS_XTD5_1 */
+ [21021] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21021 - VSS_XTD5_0 */
+ [21022] = { 0x00FF, 0x00FF, 0x0000 }, /* R21022 - VSS_XTD6_1 */
+ [21023] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21023 - VSS_XTD6_0 */
+ [21024] = { 0x00FF, 0x00FF, 0x0000 }, /* R21024 - VSS_XTD7_1 */
+ [21025] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21025 - VSS_XTD7_0 */
+ [21026] = { 0x00FF, 0x00FF, 0x0000 }, /* R21026 - VSS_XTD8_1 */
+ [21027] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21027 - VSS_XTD8_0 */
+ [21028] = { 0x00FF, 0x00FF, 0x0000 }, /* R21028 - VSS_XTD9_1 */
+ [21029] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21029 - VSS_XTD9_0 */
+ [21030] = { 0x00FF, 0x00FF, 0x0000 }, /* R21030 - VSS_XTD10_1 */
+ [21031] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21031 - VSS_XTD10_0 */
+ [21032] = { 0x00FF, 0x00FF, 0x0000 }, /* R21032 - VSS_XTD11_1 */
+ [21033] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21033 - VSS_XTD11_0 */
+ [21034] = { 0x00FF, 0x00FF, 0x0000 }, /* R21034 - VSS_XTD12_1 */
+ [21035] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21035 - VSS_XTD12_0 */
+ [21036] = { 0x00FF, 0x00FF, 0x0000 }, /* R21036 - VSS_XTD13_1 */
+ [21037] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21037 - VSS_XTD13_0 */
+ [21038] = { 0x00FF, 0x00FF, 0x0000 }, /* R21038 - VSS_XTD14_1 */
+ [21039] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21039 - VSS_XTD14_0 */
+ [21040] = { 0x00FF, 0x00FF, 0x0000 }, /* R21040 - VSS_XTD15_1 */
+ [21041] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21041 - VSS_XTD15_0 */
+ [21042] = { 0x00FF, 0x00FF, 0x0000 }, /* R21042 - VSS_XTD16_1 */
+ [21043] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21043 - VSS_XTD16_0 */
+ [21044] = { 0x00FF, 0x00FF, 0x0000 }, /* R21044 - VSS_XTD17_1 */
+ [21045] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21045 - VSS_XTD17_0 */
+ [21046] = { 0x00FF, 0x00FF, 0x0000 }, /* R21046 - VSS_XTD18_1 */
+ [21047] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21047 - VSS_XTD18_0 */
+ [21048] = { 0x00FF, 0x00FF, 0x0000 }, /* R21048 - VSS_XTD19_1 */
+ [21049] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21049 - VSS_XTD19_0 */
+ [21050] = { 0x00FF, 0x00FF, 0x0000 }, /* R21050 - VSS_XTD20_1 */
+ [21051] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21051 - VSS_XTD20_0 */
+ [21052] = { 0x00FF, 0x00FF, 0x0000 }, /* R21052 - VSS_XTD21_1 */
+ [21053] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21053 - VSS_XTD21_0 */
+ [21054] = { 0x00FF, 0x00FF, 0x0000 }, /* R21054 - VSS_XTD22_1 */
+ [21055] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21055 - VSS_XTD22_0 */
+ [21056] = { 0x00FF, 0x00FF, 0x0000 }, /* R21056 - VSS_XTD23_1 */
+ [21057] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21057 - VSS_XTD23_0 */
+ [21058] = { 0x00FF, 0x00FF, 0x0000 }, /* R21058 - VSS_XTD24_1 */
+ [21059] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21059 - VSS_XTD24_0 */
+ [21060] = { 0x00FF, 0x00FF, 0x0000 }, /* R21060 - VSS_XTD25_1 */
+ [21061] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21061 - VSS_XTD25_0 */
+ [21062] = { 0x00FF, 0x00FF, 0x0000 }, /* R21062 - VSS_XTD26_1 */
+ [21063] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21063 - VSS_XTD26_0 */
+ [21064] = { 0x00FF, 0x00FF, 0x0000 }, /* R21064 - VSS_XTD27_1 */
+ [21065] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21065 - VSS_XTD27_0 */
+ [21066] = { 0x00FF, 0x00FF, 0x0000 }, /* R21066 - VSS_XTD28_1 */
+ [21067] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21067 - VSS_XTD28_0 */
+ [21068] = { 0x00FF, 0x00FF, 0x0000 }, /* R21068 - VSS_XTD29_1 */
+ [21069] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21069 - VSS_XTD29_0 */
+ [21070] = { 0x00FF, 0x00FF, 0x0000 }, /* R21070 - VSS_XTD30_1 */
+ [21071] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21071 - VSS_XTD30_0 */
+ [21072] = { 0x00FF, 0x00FF, 0x0000 }, /* R21072 - VSS_XTD31_1 */
+ [21073] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21073 - VSS_XTD31_0 */
+ [21074] = { 0x00FF, 0x00FF, 0x0000 }, /* R21074 - VSS_XTD32_1 */
+ [21075] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21075 - VSS_XTD32_0 */
+ [21076] = { 0x00FF, 0x00FF, 0x0000 }, /* R21076 - VSS_XTS1_1 */
+ [21077] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21077 - VSS_XTS1_0 */
+ [21078] = { 0x00FF, 0x00FF, 0x0000 }, /* R21078 - VSS_XTS2_1 */
+ [21079] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21079 - VSS_XTS2_0 */
+ [21080] = { 0x00FF, 0x00FF, 0x0000 }, /* R21080 - VSS_XTS3_1 */
+ [21081] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21081 - VSS_XTS3_0 */
+ [21082] = { 0x00FF, 0x00FF, 0x0000 }, /* R21082 - VSS_XTS4_1 */
+ [21083] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21083 - VSS_XTS4_0 */
+ [21084] = { 0x00FF, 0x00FF, 0x0000 }, /* R21084 - VSS_XTS5_1 */
+ [21085] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21085 - VSS_XTS5_0 */
+ [21086] = { 0x00FF, 0x00FF, 0x0000 }, /* R21086 - VSS_XTS6_1 */
+ [21087] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21087 - VSS_XTS6_0 */
+ [21088] = { 0x00FF, 0x00FF, 0x0000 }, /* R21088 - VSS_XTS7_1 */
+ [21089] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21089 - VSS_XTS7_0 */
+ [21090] = { 0x00FF, 0x00FF, 0x0000 }, /* R21090 - VSS_XTS8_1 */
+ [21091] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21091 - VSS_XTS8_0 */
+ [21092] = { 0x00FF, 0x00FF, 0x0000 }, /* R21092 - VSS_XTS9_1 */
+ [21093] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21093 - VSS_XTS9_0 */
+ [21094] = { 0x00FF, 0x00FF, 0x0000 }, /* R21094 - VSS_XTS10_1 */
+ [21095] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21095 - VSS_XTS10_0 */
+ [21096] = { 0x00FF, 0x00FF, 0x0000 }, /* R21096 - VSS_XTS11_1 */
+ [21097] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21097 - VSS_XTS11_0 */
+ [21098] = { 0x00FF, 0x00FF, 0x0000 }, /* R21098 - VSS_XTS12_1 */
+ [21099] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21099 - VSS_XTS12_0 */
+ [21100] = { 0x00FF, 0x00FF, 0x0000 }, /* R21100 - VSS_XTS13_1 */
+ [21101] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21101 - VSS_XTS13_0 */
+ [21102] = { 0x00FF, 0x00FF, 0x0000 }, /* R21102 - VSS_XTS14_1 */
+ [21103] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21103 - VSS_XTS14_0 */
+ [21104] = { 0x00FF, 0x00FF, 0x0000 }, /* R21104 - VSS_XTS15_1 */
+ [21105] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21105 - VSS_XTS15_0 */
+ [21106] = { 0x00FF, 0x00FF, 0x0000 }, /* R21106 - VSS_XTS16_1 */
+ [21107] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21107 - VSS_XTS16_0 */
+ [21108] = { 0x00FF, 0x00FF, 0x0000 }, /* R21108 - VSS_XTS17_1 */
+ [21109] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21109 - VSS_XTS17_0 */
+ [21110] = { 0x00FF, 0x00FF, 0x0000 }, /* R21110 - VSS_XTS18_1 */
+ [21111] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21111 - VSS_XTS18_0 */
+ [21112] = { 0x00FF, 0x00FF, 0x0000 }, /* R21112 - VSS_XTS19_1 */
+ [21113] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21113 - VSS_XTS19_0 */
+ [21114] = { 0x00FF, 0x00FF, 0x0000 }, /* R21114 - VSS_XTS20_1 */
+ [21115] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21115 - VSS_XTS20_0 */
+ [21116] = { 0x00FF, 0x00FF, 0x0000 }, /* R21116 - VSS_XTS21_1 */
+ [21117] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21117 - VSS_XTS21_0 */
+ [21118] = { 0x00FF, 0x00FF, 0x0000 }, /* R21118 - VSS_XTS22_1 */
+ [21119] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21119 - VSS_XTS22_0 */
+ [21120] = { 0x00FF, 0x00FF, 0x0000 }, /* R21120 - VSS_XTS23_1 */
+ [21121] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21121 - VSS_XTS23_0 */
+ [21122] = { 0x00FF, 0x00FF, 0x0000 }, /* R21122 - VSS_XTS24_1 */
+ [21123] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21123 - VSS_XTS24_0 */
+ [21124] = { 0x00FF, 0x00FF, 0x0000 }, /* R21124 - VSS_XTS25_1 */
+ [21125] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21125 - VSS_XTS25_0 */
+ [21126] = { 0x00FF, 0x00FF, 0x0000 }, /* R21126 - VSS_XTS26_1 */
+ [21127] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21127 - VSS_XTS26_0 */
+ [21128] = { 0x00FF, 0x00FF, 0x0000 }, /* R21128 - VSS_XTS27_1 */
+ [21129] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21129 - VSS_XTS27_0 */
+ [21130] = { 0x00FF, 0x00FF, 0x0000 }, /* R21130 - VSS_XTS28_1 */
+ [21131] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21131 - VSS_XTS28_0 */
+ [21132] = { 0x00FF, 0x00FF, 0x0000 }, /* R21132 - VSS_XTS29_1 */
+ [21133] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21133 - VSS_XTS29_0 */
+ [21134] = { 0x00FF, 0x00FF, 0x0000 }, /* R21134 - VSS_XTS30_1 */
+ [21135] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21135 - VSS_XTS30_0 */
+ [21136] = { 0x00FF, 0x00FF, 0x0000 }, /* R21136 - VSS_XTS31_1 */
+ [21137] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21137 - VSS_XTS31_0 */
+ [21138] = { 0x00FF, 0x00FF, 0x0000 }, /* R21138 - VSS_XTS32_1 */
+ [21139] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21139 - VSS_XTS32_0 */
+};
+
+static int wm8962_volatile_register(unsigned int reg)
+{
+ if (wm8962_reg_access[reg].vol)
+ return 1;
+ else
+ return 0;
+}
+
+static int wm8962_readable_register(unsigned int reg)
+{
+ if (wm8962_reg_access[reg].read)
+ return 1;
+ else
+ return 0;
+}
+
+static int wm8962_reset(struct snd_soc_codec *codec)
+{
+ return snd_soc_write(codec, WM8962_SOFTWARE_RESET, 0);
+}
+
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, -2325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(mixin_tlv, -1500, 300, 0);
+static const unsigned int mixinpga_tlv[] = {
+ TLV_DB_RANGE_HEAD(7),
+ 0, 1, TLV_DB_SCALE_ITEM(0, 600, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(1300, 1300, 0),
+ 3, 4, TLV_DB_SCALE_ITEM(1800, 200, 0),
+ 5, 5, TLV_DB_SCALE_ITEM(2400, 0, 0),
+ 6, 7, TLV_DB_SCALE_ITEM(2700, 300, 0),
+};
+static const DECLARE_TLV_DB_SCALE(beep_tlv, -9600, 600, 1);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0);
+static const DECLARE_TLV_DB_SCALE(inmix_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(hp_tlv, -700, 100, 0);
+static const unsigned int classd_tlv[] = {
+ TLV_DB_RANGE_HEAD(7),
+ 0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
+ 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
+};
+
+/* The VU bits for the headphones are in a different register to the mute
+ * bits and only take effect on the PGA if it is actually powered.
+ */
+static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = wm8962->reg_cache;
+ int ret;
+
+ /* Apply the update (if any) */
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ if (ret == 0)
+ return 0;
+
+ /* If the left PGA is enabled hit that VU bit... */
+ if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_HPOUTL_PGA_ENA)
+ return snd_soc_write(codec, WM8962_HPOUTL_VOLUME,
+ reg_cache[WM8962_HPOUTL_VOLUME]);
+
+ /* ...otherwise the right. The VU is stereo. */
+ if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_HPOUTR_PGA_ENA)
+ return snd_soc_write(codec, WM8962_HPOUTR_VOLUME,
+ reg_cache[WM8962_HPOUTR_VOLUME]);
+
+ return 0;
+}
+
+/* The VU bits for the speakers are in a different register to the mute
+ * bits and only take effect on the PGA if it is actually powered.
+ */
+static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = wm8962->reg_cache;
+ int ret;
+
+ /* Apply the update (if any) */
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ if (ret == 0)
+ return 0;
+
+ /* If the left PGA is enabled hit that VU bit... */
+ if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTL_PGA_ENA)
+ return snd_soc_write(codec, WM8962_SPKOUTL_VOLUME,
+ reg_cache[WM8962_SPKOUTL_VOLUME]);
+
+ /* ...otherwise the right. The VU is stereo. */
+ if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTR_PGA_ENA)
+ return snd_soc_write(codec, WM8962_SPKOUTR_VOLUME,
+ reg_cache[WM8962_SPKOUTR_VOLUME]);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new wm8962_snd_controls[] = {
+SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1),
+
+SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8962_LEFT_INPUT_MIXER_VOLUME, 6, 7, 0,
+ mixin_tlv),
+SOC_SINGLE_TLV("MIXINL PGA Volume", WM8962_LEFT_INPUT_MIXER_VOLUME, 3, 7, 0,
+ mixinpga_tlv),
+SOC_SINGLE_TLV("MIXINL IN3L Volume", WM8962_LEFT_INPUT_MIXER_VOLUME, 0, 7, 0,
+ mixin_tlv),
+
+SOC_SINGLE_TLV("MIXINR IN2R Volume", WM8962_RIGHT_INPUT_MIXER_VOLUME, 6, 7, 0,
+ mixin_tlv),
+SOC_SINGLE_TLV("MIXINR PGA Volume", WM8962_RIGHT_INPUT_MIXER_VOLUME, 3, 7, 0,
+ mixinpga_tlv),
+SOC_SINGLE_TLV("MIXINR IN3R Volume", WM8962_RIGHT_INPUT_MIXER_VOLUME, 0, 7, 0,
+ mixin_tlv),
+
+SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8962_LEFT_ADC_VOLUME,
+ WM8962_RIGHT_ADC_VOLUME, 1, 127, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("Capture Volume", WM8962_LEFT_INPUT_VOLUME,
+ WM8962_RIGHT_INPUT_VOLUME, 0, 63, 0, inpga_tlv),
+SOC_DOUBLE_R("Capture Switch", WM8962_LEFT_INPUT_VOLUME,
+ WM8962_RIGHT_INPUT_VOLUME, 7, 1, 1),
+SOC_DOUBLE_R("Capture ZC Switch", WM8962_LEFT_INPUT_VOLUME,
+ WM8962_RIGHT_INPUT_VOLUME, 6, 1, 1),
+
+SOC_DOUBLE_R_TLV("Sidetone Volume", WM8962_DAC_DSP_MIXING_1,
+ WM8962_DAC_DSP_MIXING_2, 4, 12, 0, st_tlv),
+
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8962_LEFT_DAC_VOLUME,
+ WM8962_RIGHT_DAC_VOLUME, 1, 127, 0, digital_tlv),
+SOC_SINGLE("DAC High Performance Switch", WM8962_ADC_DAC_CONTROL_2, 0, 1, 0),
+
+SOC_SINGLE("ADC High Performance Switch", WM8962_ADDITIONAL_CONTROL_1,
+ 5, 1, 0),
+
+SOC_SINGLE_TLV("Beep Volume", WM8962_BEEP_GENERATOR_1, 4, 15, 0, beep_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Volume", WM8962_HPOUTL_VOLUME,
+ WM8962_HPOUTR_VOLUME, 0, 127, 0, out_tlv),
+SOC_DOUBLE_EXT("Headphone Switch", WM8962_PWR_MGMT_2, 1, 0, 1, 1,
+ snd_soc_get_volsw, wm8962_put_hp_sw),
+SOC_DOUBLE_R("Headphone ZC Switch", WM8962_HPOUTL_VOLUME, WM8962_HPOUTR_VOLUME,
+ 7, 1, 0),
+SOC_DOUBLE_TLV("Headphone Aux Volume", WM8962_ANALOGUE_HP_2, 3, 6, 7, 0,
+ hp_tlv),
+
+SOC_DOUBLE_R("Headphone Mixer Switch", WM8962_HEADPHONE_MIXER_3,
+ WM8962_HEADPHONE_MIXER_4, 8, 1, 1),
+
+SOC_SINGLE_TLV("HPMIXL IN4L Volume", WM8962_HEADPHONE_MIXER_3,
+ 3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXL IN4R Volume", WM8962_HEADPHONE_MIXER_3,
+ 0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXL MIXINL Volume", WM8962_HEADPHONE_MIXER_3,
+ 7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("HPMIXL MIXINR Volume", WM8962_HEADPHONE_MIXER_3,
+ 6, 1, 1, inmix_tlv),
+
+SOC_SINGLE_TLV("HPMIXR IN4L Volume", WM8962_HEADPHONE_MIXER_4,
+ 3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXR IN4R Volume", WM8962_HEADPHONE_MIXER_4,
+ 0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXR MIXINL Volume", WM8962_HEADPHONE_MIXER_4,
+ 7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("HPMIXR MIXINR Volume", WM8962_HEADPHONE_MIXER_4,
+ 6, 1, 1, inmix_tlv),
+
+SOC_SINGLE_TLV("Speaker Boost Volume", WM8962_CLASS_D_CONTROL_2, 0, 7, 0,
+ classd_tlv),
+};
+
+static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = {
+SOC_SINGLE_TLV("Speaker Volume", WM8962_SPKOUTL_VOLUME, 0, 127, 0, out_tlv),
+SOC_SINGLE_EXT("Speaker Switch", WM8962_CLASS_D_CONTROL_1, 1, 1, 1,
+ snd_soc_get_volsw, wm8962_put_spk_sw),
+SOC_SINGLE("Speaker ZC Switch", WM8962_SPKOUTL_VOLUME, 7, 1, 0),
+
+SOC_SINGLE("Speaker Mixer Switch", WM8962_SPEAKER_MIXER_3, 8, 1, 1),
+SOC_SINGLE_TLV("Speaker Mixer IN4L Volume", WM8962_SPEAKER_MIXER_3,
+ 3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("Speaker Mixer IN4R Volume", WM8962_SPEAKER_MIXER_3,
+ 0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("Speaker Mixer MIXINL Volume", WM8962_SPEAKER_MIXER_3,
+ 7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("Speaker Mixer MIXINR Volume", WM8962_SPEAKER_MIXER_3,
+ 6, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("Speaker Mixer DACL Volume", WM8962_SPEAKER_MIXER_5,
+ 7, 1, 0, inmix_tlv),
+SOC_SINGLE_TLV("Speaker Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
+ 6, 1, 0, inmix_tlv),
+};
+
+static const struct snd_kcontrol_new wm8962_spk_stereo_controls[] = {
+SOC_DOUBLE_R_TLV("Speaker Volume", WM8962_SPKOUTL_VOLUME,
+ WM8962_SPKOUTR_VOLUME, 0, 127, 0, out_tlv),
+SOC_DOUBLE_EXT("Speaker Switch", WM8962_CLASS_D_CONTROL_1, 1, 0, 1, 1,
+ snd_soc_get_volsw, wm8962_put_spk_sw),
+SOC_DOUBLE_R("Speaker ZC Switch", WM8962_SPKOUTL_VOLUME, WM8962_SPKOUTR_VOLUME,
+ 7, 1, 0),
+
+SOC_DOUBLE_R("Speaker Mixer Switch", WM8962_SPEAKER_MIXER_3,
+ WM8962_SPEAKER_MIXER_4, 8, 1, 1),
+
+SOC_SINGLE_TLV("SPKOUTL Mixer IN4L Volume", WM8962_SPEAKER_MIXER_3,
+ 3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer IN4R Volume", WM8962_SPEAKER_MIXER_3,
+ 0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer MIXINL Volume", WM8962_SPEAKER_MIXER_3,
+ 7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer MIXINR Volume", WM8962_SPEAKER_MIXER_3,
+ 6, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer DACL Volume", WM8962_SPEAKER_MIXER_5,
+ 7, 1, 0, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
+ 6, 1, 0, inmix_tlv),
+
+SOC_SINGLE_TLV("SPKOUTR Mixer IN4L Volume", WM8962_SPEAKER_MIXER_4,
+ 3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer IN4R Volume", WM8962_SPEAKER_MIXER_4,
+ 0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer MIXINL Volume", WM8962_SPEAKER_MIXER_4,
+ 7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer MIXINR Volume", WM8962_SPEAKER_MIXER_4,
+ 6, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer DACL Volume", WM8962_SPEAKER_MIXER_5,
+ 5, 1, 0, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
+ 4, 1, 0, inmix_tlv),
+};
+
+static int sysclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ int src;
+ int fll;
+
+ src = snd_soc_read(codec, WM8962_CLOCKING2) & WM8962_SYSCLK_SRC_MASK;
+
+ switch (src) {
+ case 0: /* MCLK */
+ fll = 0;
+ break;
+ case 0x200: /* FLL */
+ fll = 1;
+ break;
+ default:
+ dev_err(codec->dev, "Unknown SYSCLK source %x\n", src);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (fll)
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+ WM8962_FLL_ENA, WM8962_FLL_ENA);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ if (fll)
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+ WM8962_FLL_ENA, 0);
+ break;
+
+ default:
+ BUG();
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ msleep(5);
+ break;
+
+ default:
+ BUG();
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ int timeout;
+ int reg;
+ int expected = (WM8962_DCS_STARTUP_DONE_HP1L |
+ WM8962_DCS_STARTUP_DONE_HP1R);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ WM8962_HP1L_ENA | WM8962_HP1R_ENA,
+ WM8962_HP1L_ENA | WM8962_HP1R_ENA);
+ udelay(20);
+
+ snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY,
+ WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY);
+
+ /* Start the DC servo */
+ snd_soc_update_bits(codec, WM8962_DC_SERVO_1,
+ WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
+ WM8962_HP1L_DCS_STARTUP |
+ WM8962_HP1R_DCS_STARTUP,
+ WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
+ WM8962_HP1L_DCS_STARTUP |
+ WM8962_HP1R_DCS_STARTUP);
+
+ /* Wait for it to complete, should be well under 100ms */
+ timeout = 0;
+ do {
+ msleep(1);
+ reg = snd_soc_read(codec, WM8962_DC_SERVO_6);
+ if (reg < 0) {
+ dev_err(codec->dev,
+ "Failed to read DCS status: %d\n",
+ reg);
+ continue;
+ }
+ dev_dbg(codec->dev, "DCS status: %x\n", reg);
+ } while (++timeout < 200 && (reg & expected) != expected);
+
+ if ((reg & expected) != expected)
+ dev_err(codec->dev, "DC servo timed out\n");
+ else
+ dev_dbg(codec->dev, "DC servo complete after %dms\n",
+ timeout);
+
+ snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ WM8962_HP1L_ENA_OUTP |
+ WM8962_HP1R_ENA_OUTP,
+ WM8962_HP1L_ENA_OUTP |
+ WM8962_HP1R_ENA_OUTP);
+ udelay(20);
+
+ snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ WM8962_HP1L_RMV_SHORT |
+ WM8962_HP1R_RMV_SHORT,
+ WM8962_HP1L_RMV_SHORT |
+ WM8962_HP1R_RMV_SHORT);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ WM8962_HP1L_RMV_SHORT |
+ WM8962_HP1R_RMV_SHORT, 0);
+
+ udelay(20);
+
+ snd_soc_update_bits(codec, WM8962_DC_SERVO_1,
+ WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
+ WM8962_HP1L_DCS_STARTUP |
+ WM8962_HP1R_DCS_STARTUP,
+ 0);
+
+ snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+ WM8962_HP1L_ENA | WM8962_HP1R_ENA |
+ WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY |
+ WM8962_HP1L_ENA_OUTP |
+ WM8962_HP1R_ENA_OUTP, 0);
+
+ break;
+
+ default:
+ BUG();
+ return -EINVAL;
+
+ }
+
+ return 0;
+}
+
+/* VU bits for the output PGAs only take effect while the PGA is powered */
+static int out_pga_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = wm8962->reg_cache;
+ int reg;
+
+ switch (w->shift) {
+ case WM8962_HPOUTR_PGA_ENA_SHIFT:
+ reg = WM8962_HPOUTR_VOLUME;
+ break;
+ case WM8962_HPOUTL_PGA_ENA_SHIFT:
+ reg = WM8962_HPOUTL_VOLUME;
+ break;
+ case WM8962_SPKOUTR_PGA_ENA_SHIFT:
+ reg = WM8962_SPKOUTR_VOLUME;
+ break;
+ case WM8962_SPKOUTL_PGA_ENA_SHIFT:
+ reg = WM8962_SPKOUTL_VOLUME;
+ break;
+ default:
+ BUG();
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ return snd_soc_write(codec, reg, reg_cache[reg]);
+ default:
+ BUG();
+ return -EINVAL;
+ }
+}
+
+static const char *st_text[] = { "None", "Right", "Left" };
+
+static const struct soc_enum str_enum =
+ SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_1, 2, 3, st_text);
+
+static const struct snd_kcontrol_new str_mux =
+ SOC_DAPM_ENUM("Right Sidetone", str_enum);
+
+static const struct soc_enum stl_enum =
+ SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_2, 2, 3, st_text);
+
+static const struct snd_kcontrol_new stl_mux =
+ SOC_DAPM_ENUM("Left Sidetone", stl_enum);
+
+static const char *outmux_text[] = { "DAC", "Mixer" };
+
+static const struct soc_enum spkoutr_enum =
+ SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_2, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new spkoutr_mux =
+ SOC_DAPM_ENUM("SPKOUTR Mux", spkoutr_enum);
+
+static const struct soc_enum spkoutl_enum =
+ SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_1, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new spkoutl_mux =
+ SOC_DAPM_ENUM("SPKOUTL Mux", spkoutl_enum);
+
+static const struct soc_enum hpoutr_enum =
+ SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_2, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new hpoutr_mux =
+ SOC_DAPM_ENUM("HPOUTR Mux", hpoutr_enum);
+
+static const struct soc_enum hpoutl_enum =
+ SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_1, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new hpoutl_mux =
+ SOC_DAPM_ENUM("HPOUTL Mux", hpoutl_enum);
+
+static const struct snd_kcontrol_new inpgal[] = {
+SOC_DAPM_SINGLE("IN1L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 3, 1, 0),
+SOC_DAPM_SINGLE("IN2L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 2, 1, 0),
+SOC_DAPM_SINGLE("IN3L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new inpgar[] = {
+SOC_DAPM_SINGLE("IN1R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 3, 1, 0),
+SOC_DAPM_SINGLE("IN2R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 2, 1, 0),
+SOC_DAPM_SINGLE("IN3R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixinl[] = {
+SOC_DAPM_SINGLE("IN2L Switch", WM8962_INPUT_MIXER_CONTROL_2, 5, 1, 0),
+SOC_DAPM_SINGLE("IN3L Switch", WM8962_INPUT_MIXER_CONTROL_2, 4, 1, 0),
+SOC_DAPM_SINGLE("PGA Switch", WM8962_INPUT_MIXER_CONTROL_2, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixinr[] = {
+SOC_DAPM_SINGLE("IN2R Switch", WM8962_INPUT_MIXER_CONTROL_2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN3R Switch", WM8962_INPUT_MIXER_CONTROL_2, 1, 1, 0),
+SOC_DAPM_SINGLE("PGA Switch", WM8962_INPUT_MIXER_CONTROL_2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new hpmixl[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_HEADPHONE_MIXER_1, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_HEADPHONE_MIXER_1, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_HEADPHONE_MIXER_1, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_HEADPHONE_MIXER_1, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_HEADPHONE_MIXER_1, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_HEADPHONE_MIXER_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new hpmixr[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_HEADPHONE_MIXER_2, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_HEADPHONE_MIXER_2, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_HEADPHONE_MIXER_2, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_HEADPHONE_MIXER_2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_HEADPHONE_MIXER_2, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_HEADPHONE_MIXER_2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new spkmixl[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_SPEAKER_MIXER_1, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_SPEAKER_MIXER_1, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_SPEAKER_MIXER_1, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_SPEAKER_MIXER_1, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_SPEAKER_MIXER_1, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_SPEAKER_MIXER_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new spkmixr[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_SPEAKER_MIXER_2, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_SPEAKER_MIXER_2, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_SPEAKER_MIXER_2, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_SPEAKER_MIXER_2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_SPEAKER_MIXER_2, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_SPEAKER_MIXER_2, 0, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8962_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+SND_SOC_DAPM_INPUT("IN4L"),
+SND_SOC_DAPM_INPUT("IN4R"),
+SND_SOC_DAPM_INPUT("Beep"),
+
+SND_SOC_DAPM_MICBIAS("MICBIAS", WM8962_PWR_MGMT_1, 1, 0),
+
+SND_SOC_DAPM_SUPPLY("Class G", WM8962_CHARGE_PUMP_B, 0, 1, NULL, 0),
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM8962_CLOCKING2, 5, 0, sysclk_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("Charge Pump", WM8962_CHARGE_PUMP_1, 0, 0, cp_event,
+ SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("INPGAL", WM8962_LEFT_INPUT_PGA_CONTROL, 4, 0,
+ inpgal, ARRAY_SIZE(inpgal)),
+SND_SOC_DAPM_MIXER("INPGAR", WM8962_RIGHT_INPUT_PGA_CONTROL, 4, 0,
+ inpgar, ARRAY_SIZE(inpgar)),
+SND_SOC_DAPM_MIXER("MIXINL", WM8962_PWR_MGMT_1, 5, 0,
+ mixinl, ARRAY_SIZE(mixinl)),
+SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0,
+ mixinr, ARRAY_SIZE(mixinr)),
+
+SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0),
+SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0),
+
+SND_SOC_DAPM_MUX("STL", SND_SOC_NOPM, 0, 0, &stl_mux),
+SND_SOC_DAPM_MUX("STR", SND_SOC_NOPM, 0, 0, &str_mux),
+
+SND_SOC_DAPM_DAC("DACL", "Playback", WM8962_PWR_MGMT_2, 8, 0),
+SND_SOC_DAPM_DAC("DACR", "Playback", WM8962_PWR_MGMT_2, 7, 0),
+
+SND_SOC_DAPM_PGA("Left Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("HPMIXL", WM8962_MIXER_ENABLES, 3, 0,
+ hpmixl, ARRAY_SIZE(hpmixl)),
+SND_SOC_DAPM_MIXER("HPMIXR", WM8962_MIXER_ENABLES, 2, 0,
+ hpmixr, ARRAY_SIZE(hpmixr)),
+
+SND_SOC_DAPM_MUX_E("HPOUTL PGA", WM8962_PWR_MGMT_2, 6, 0, &hpoutl_mux,
+ out_pga_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_MUX_E("HPOUTR PGA", WM8962_PWR_MGMT_2, 5, 0, &hpoutr_mux,
+ out_pga_event, SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA_E("HPOUT", SND_SOC_NOPM, 0, 0, NULL, 0, hp_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+};
+
+static const struct snd_soc_dapm_widget wm8962_dapm_spk_mono_widgets[] = {
+SND_SOC_DAPM_MIXER("Speaker Mixer", WM8962_MIXER_ENABLES, 1, 0,
+ spkmixl, ARRAY_SIZE(spkmixl)),
+SND_SOC_DAPM_MUX_E("Speaker PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
+ out_pga_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA("Speaker Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_OUTPUT("SPKOUT"),
+};
+
+static const struct snd_soc_dapm_widget wm8962_dapm_spk_stereo_widgets[] = {
+SND_SOC_DAPM_MIXER("SPKOUTL Mixer", WM8962_MIXER_ENABLES, 1, 0,
+ spkmixl, ARRAY_SIZE(spkmixl)),
+SND_SOC_DAPM_MIXER("SPKOUTR Mixer", WM8962_MIXER_ENABLES, 0, 0,
+ spkmixr, ARRAY_SIZE(spkmixr)),
+
+SND_SOC_DAPM_MUX_E("SPKOUTL PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
+ out_pga_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_MUX_E("SPKOUTR PGA", WM8962_PWR_MGMT_2, 3, 0, &spkoutr_mux,
+ out_pga_event, SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA("SPKOUTR Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPKOUTL Output", WM8962_CLASS_D_CONTROL_1, 6, 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("SPKOUTL"),
+SND_SOC_DAPM_OUTPUT("SPKOUTR"),
+};
+
+static const struct snd_soc_dapm_route wm8962_intercon[] = {
+ { "INPGAL", "IN1L Switch", "IN1L" },
+ { "INPGAL", "IN2L Switch", "IN2L" },
+ { "INPGAL", "IN3L Switch", "IN3L" },
+ { "INPGAL", "IN4L Switch", "IN4L" },
+
+ { "INPGAR", "IN1R Switch", "IN1R" },
+ { "INPGAR", "IN2R Switch", "IN2R" },
+ { "INPGAR", "IN3R Switch", "IN3R" },
+ { "INPGAR", "IN4R Switch", "IN4R" },
+
+ { "MIXINL", "IN2L Switch", "IN2L" },
+ { "MIXINL", "IN3L Switch", "IN3L" },
+ { "MIXINL", "PGA Switch", "INPGAL" },
+
+ { "MIXINR", "IN2R Switch", "IN2R" },
+ { "MIXINR", "IN3R Switch", "IN3R" },
+ { "MIXINR", "PGA Switch", "INPGAR" },
+
+ { "MICBIAS", NULL, "SYSCLK" },
+
+ { "ADCL", NULL, "SYSCLK" },
+ { "ADCL", NULL, "TOCLK" },
+ { "ADCL", NULL, "MIXINL" },
+
+ { "ADCR", NULL, "SYSCLK" },
+ { "ADCR", NULL, "TOCLK" },
+ { "ADCR", NULL, "MIXINR" },
+
+ { "STL", "Left", "ADCL" },
+ { "STL", "Right", "ADCR" },
+
+ { "STR", "Left", "ADCL" },
+ { "STR", "Right", "ADCR" },
+
+ { "DACL", NULL, "SYSCLK" },
+ { "DACL", NULL, "TOCLK" },
+ { "DACL", NULL, "Beep" },
+ { "DACL", NULL, "STL" },
+
+ { "DACR", NULL, "SYSCLK" },
+ { "DACR", NULL, "TOCLK" },
+ { "DACR", NULL, "Beep" },
+ { "DACR", NULL, "STR" },
+
+ { "HPMIXL", "IN4L Switch", "IN4L" },
+ { "HPMIXL", "IN4R Switch", "IN4R" },
+ { "HPMIXL", "DACL Switch", "DACL" },
+ { "HPMIXL", "DACR Switch", "DACR" },
+ { "HPMIXL", "MIXINL Switch", "MIXINL" },
+ { "HPMIXL", "MIXINR Switch", "MIXINR" },
+
+ { "HPMIXR", "IN4L Switch", "IN4L" },
+ { "HPMIXR", "IN4R Switch", "IN4R" },
+ { "HPMIXR", "DACL Switch", "DACL" },
+ { "HPMIXR", "DACR Switch", "DACR" },
+ { "HPMIXR", "MIXINL Switch", "MIXINL" },
+ { "HPMIXR", "MIXINR Switch", "MIXINR" },
+
+ { "Left Bypass", NULL, "HPMIXL" },
+ { "Left Bypass", NULL, "Class G" },
+
+ { "Right Bypass", NULL, "HPMIXR" },
+ { "Right Bypass", NULL, "Class G" },
+
+ { "HPOUTL PGA", "Mixer", "Left Bypass" },
+ { "HPOUTL PGA", "DAC", "DACL" },
+
+ { "HPOUTR PGA", "Mixer", "Right Bypass" },
+ { "HPOUTR PGA", "DAC", "DACR" },
+
+ { "HPOUT", NULL, "HPOUTL PGA" },
+ { "HPOUT", NULL, "HPOUTR PGA" },
+ { "HPOUT", NULL, "Charge Pump" },
+ { "HPOUT", NULL, "SYSCLK" },
+ { "HPOUT", NULL, "TOCLK" },
+
+ { "HPOUTL", NULL, "HPOUT" },
+ { "HPOUTR", NULL, "HPOUT" },
+};
+
+static const struct snd_soc_dapm_route wm8962_spk_mono_intercon[] = {
+ { "Speaker Mixer", "IN4L Switch", "IN4L" },
+ { "Speaker Mixer", "IN4R Switch", "IN4R" },
+ { "Speaker Mixer", "DACL Switch", "DACL" },
+ { "Speaker Mixer", "DACR Switch", "DACR" },
+ { "Speaker Mixer", "MIXINL Switch", "MIXINL" },
+ { "Speaker Mixer", "MIXINR Switch", "MIXINR" },
+
+ { "Speaker PGA", "Mixer", "Speaker Mixer" },
+ { "Speaker PGA", "DAC", "DACL" },
+
+ { "Speaker Output", NULL, "Speaker PGA" },
+ { "Speaker Output", NULL, "SYSCLK" },
+ { "Speaker Output", NULL, "TOCLK" },
+
+ { "SPKOUT", NULL, "Speaker Output" },
+};
+
+static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
+ { "SPKOUTL Mixer", "IN4L Switch", "IN4L" },
+ { "SPKOUTL Mixer", "IN4R Switch", "IN4R" },
+ { "SPKOUTL Mixer", "DACL Switch", "DACL" },
+ { "SPKOUTL Mixer", "DACR Switch", "DACR" },
+ { "SPKOUTL Mixer", "MIXINL Switch", "MIXINL" },
+ { "SPKOUTL Mixer", "MIXINR Switch", "MIXINR" },
+
+ { "SPKOUTR Mixer", "IN4L Switch", "IN4L" },
+ { "SPKOUTR Mixer", "IN4R Switch", "IN4R" },
+ { "SPKOUTR Mixer", "DACL Switch", "DACL" },
+ { "SPKOUTR Mixer", "DACR Switch", "DACR" },
+ { "SPKOUTR Mixer", "MIXINL Switch", "MIXINL" },
+ { "SPKOUTR Mixer", "MIXINR Switch", "MIXINR" },
+
+ { "SPKOUTL PGA", "Mixer", "SPKOUTL Mixer" },
+ { "SPKOUTL PGA", "DAC", "DACL" },
+
+ { "SPKOUTR PGA", "Mixer", "SPKOUTR Mixer" },
+ { "SPKOUTR PGA", "DAC", "DACR" },
+
+ { "SPKOUTL Output", NULL, "SPKOUTL PGA" },
+ { "SPKOUTL Output", NULL, "SYSCLK" },
+ { "SPKOUTL Output", NULL, "TOCLK" },
+
+ { "SPKOUTR Output", NULL, "SPKOUTR PGA" },
+ { "SPKOUTR Output", NULL, "SYSCLK" },
+ { "SPKOUTR Output", NULL, "TOCLK" },
+
+ { "SPKOUTL", NULL, "SPKOUTL Output" },
+ { "SPKOUTR", NULL, "SPKOUTR Output" },
+};
+
+static int wm8962_add_widgets(struct snd_soc_codec *codec)
+{
+ struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+
+ snd_soc_add_controls(codec, wm8962_snd_controls,
+ ARRAY_SIZE(wm8962_snd_controls));
+ if (pdata && pdata->spk_mono)
+ snd_soc_add_controls(codec, wm8962_spk_mono_controls,
+ ARRAY_SIZE(wm8962_spk_mono_controls));
+ else
+ snd_soc_add_controls(codec, wm8962_spk_stereo_controls,
+ ARRAY_SIZE(wm8962_spk_stereo_controls));
+
+
+ snd_soc_dapm_new_controls(codec, wm8962_dapm_widgets,
+ ARRAY_SIZE(wm8962_dapm_widgets));
+ if (pdata && pdata->spk_mono)
+ snd_soc_dapm_new_controls(codec, wm8962_dapm_spk_mono_widgets,
+ ARRAY_SIZE(wm8962_dapm_spk_mono_widgets));
+ else
+ snd_soc_dapm_new_controls(codec, wm8962_dapm_spk_stereo_widgets,
+ ARRAY_SIZE(wm8962_dapm_spk_stereo_widgets));
+
+ snd_soc_dapm_add_routes(codec, wm8962_intercon,
+ ARRAY_SIZE(wm8962_intercon));
+ if (pdata && pdata->spk_mono)
+ snd_soc_dapm_add_routes(codec, wm8962_spk_mono_intercon,
+ ARRAY_SIZE(wm8962_spk_mono_intercon));
+ else
+ snd_soc_dapm_add_routes(codec, wm8962_spk_stereo_intercon,
+ ARRAY_SIZE(wm8962_spk_stereo_intercon));
+
+
+ snd_soc_dapm_disable_pin(codec, "Beep");
+
+ return 0;
+}
+
+static void wm8962_sync_cache(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int i;
+
+ if (!codec->cache_sync)
+ return;
+
+ dev_dbg(codec->dev, "Syncing cache\n");
+
+ codec->cache_only = 0;
+
+ /* Sync back cached values if they're different from the
+ * hardware default.
+ */
+ for (i = 1; i < ARRAY_SIZE(wm8962->reg_cache); i++) {
+ if (i == WM8962_SOFTWARE_RESET)
+ continue;
+ if (wm8962->reg_cache[i] == wm8962_reg[i])
+ continue;
+
+ snd_soc_write(codec, i, wm8962->reg_cache[i]);
+ }
+
+ codec->cache_sync = 0;
+}
+
+/* -1 for reserved values */
+static const int bclk_divs[] = {
+ 1, -1, 2, 3, 4, -1, 6, 8, -1, 12, 16, 24, -1, 32, 32, 32
+};
+
+static void wm8962_configure_bclk(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int dspclk, i;
+ int clocking2 = 0;
+ int aif2 = 0;
+
+ if (!wm8962->bclk) {
+ dev_dbg(codec->dev, "No BCLK rate configured\n");
+ return;
+ }
+
+ dspclk = snd_soc_read(codec, WM8962_CLOCKING1);
+ if (dspclk < 0) {
+ dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk);
+ return;
+ }
+
+ dspclk = (dspclk & WM8962_DSPCLK_DIV_MASK) >> WM8962_DSPCLK_DIV_SHIFT;
+ switch (dspclk) {
+ case 0:
+ dspclk = wm8962->sysclk_rate;
+ break;
+ case 1:
+ dspclk = wm8962->sysclk_rate / 2;
+ break;
+ case 2:
+ dspclk = wm8962->sysclk_rate / 4;
+ break;
+ default:
+ dev_warn(codec->dev, "Unknown DSPCLK divisor read back\n");
+ dspclk = wm8962->sysclk;
+ }
+
+ dev_dbg(codec->dev, "DSPCLK is %dHz, BCLK %d\n", dspclk, wm8962->bclk);
+
+ /* We're expecting an exact match */
+ for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+ if (bclk_divs[i] < 0)
+ continue;
+
+ if (dspclk / bclk_divs[i] == wm8962->bclk) {
+ dev_dbg(codec->dev, "Selected BCLK_DIV %d for %dHz\n",
+ bclk_divs[i], wm8962->bclk);
+ clocking2 |= i;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(bclk_divs)) {
+ dev_err(codec->dev, "Unsupported BCLK ratio %d\n",
+ dspclk / wm8962->bclk);
+ return;
+ }
+
+ aif2 |= wm8962->bclk / wm8962->lrclk;
+ dev_dbg(codec->dev, "Selected LRCLK divisor %d for %dHz\n",
+ wm8962->bclk / wm8962->lrclk, wm8962->lrclk);
+
+ snd_soc_update_bits(codec, WM8962_CLOCKING2,
+ WM8962_BCLK_DIV_MASK, clocking2);
+ snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_2,
+ WM8962_AIF_RATE_MASK, aif2);
+}
+
+static int wm8962_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ if (level == codec->bias_level)
+ return 0;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ /* VMID 2*50k */
+ snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+ WM8962_VMID_SEL_MASK, 0x80);
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
+ wm8962->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to enable supplies: %d\n",
+ ret);
+ return ret;
+ }
+
+ wm8962_sync_cache(codec);
+
+ snd_soc_update_bits(codec, WM8962_ANTI_POP,
+ WM8962_STARTUP_BIAS_ENA |
+ WM8962_VMID_BUF_ENA,
+ WM8962_STARTUP_BIAS_ENA |
+ WM8962_VMID_BUF_ENA);
+
+ /* Bias enable at 2*50k for ramp */
+ snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+ WM8962_VMID_SEL_MASK |
+ WM8962_BIAS_ENA,
+ WM8962_BIAS_ENA | 0x180);
+
+ msleep(5);
+
+ snd_soc_update_bits(codec, WM8962_CLOCKING2,
+ WM8962_CLKREG_OVD,
+ WM8962_CLKREG_OVD);
+
+ wm8962_configure_bclk(codec);
+ }
+
+ /* VMID 2*250k */
+ snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+ WM8962_VMID_SEL_MASK, 0x100);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+ WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA, 0);
+
+ snd_soc_update_bits(codec, WM8962_ANTI_POP,
+ WM8962_STARTUP_BIAS_ENA |
+ WM8962_VMID_BUF_ENA, 0);
+
+ regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies),
+ wm8962->supplies);
+ break;
+ }
+ codec->bias_level = level;
+ return 0;
+}
+
+static const struct {
+ int rate;
+ int reg;
+} sr_vals[] = {
+ { 48000, 0 },
+ { 44100, 0 },
+ { 32000, 1 },
+ { 22050, 2 },
+ { 24000, 2 },
+ { 16000, 3 },
+ { 11025, 4 },
+ { 12000, 4 },
+ { 8000, 5 },
+ { 88200, 6 },
+ { 96000, 6 },
+};
+
+static const int sysclk_rates[] = {
+ 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536,
+};
+
+static int wm8962_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int rate = params_rate(params);
+ int i;
+ int aif0 = 0;
+ int adctl3 = 0;
+ int clocking4 = 0;
+
+ wm8962->bclk = snd_soc_params_to_bclk(params);
+ wm8962->lrclk = params_rate(params);
+
+ for (i = 0; i < ARRAY_SIZE(sr_vals); i++) {
+ if (sr_vals[i].rate == rate) {
+ adctl3 |= sr_vals[i].reg;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(sr_vals)) {
+ dev_err(codec->dev, "Unsupported rate %dHz\n", rate);
+ return -EINVAL;
+ }
+
+ if (rate % 8000 == 0)
+ adctl3 |= WM8962_SAMPLE_RATE_INT_MODE;
+
+ for (i = 0; i < ARRAY_SIZE(sysclk_rates); i++) {
+ if (sysclk_rates[i] == wm8962->sysclk_rate / rate) {
+ clocking4 |= i << WM8962_SYSCLK_RATE_SHIFT;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(sysclk_rates)) {
+ dev_err(codec->dev, "Unsupported sysclk ratio %d\n",
+ wm8962->sysclk_rate / rate);
+ return -EINVAL;
+ }
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ aif0 |= 0x40;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ aif0 |= 0x80;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ aif0 |= 0xc0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_0,
+ WM8962_WL_MASK, aif0);
+ snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_3,
+ WM8962_SAMPLE_RATE_INT_MODE |
+ WM8962_SAMPLE_RATE_MASK, adctl3);
+ snd_soc_update_bits(codec, WM8962_CLOCKING_4,
+ WM8962_SYSCLK_RATE_MASK, clocking4);
+
+ wm8962_configure_bclk(codec);
+
+ return 0;
+}
+
+static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int src;
+
+ switch (clk_id) {
+ case WM8962_SYSCLK_MCLK:
+ wm8962->sysclk = WM8962_SYSCLK_MCLK;
+ src = 0;
+ break;
+ case WM8962_SYSCLK_FLL:
+ wm8962->sysclk = WM8962_SYSCLK_FLL;
+ src = 1 << WM8962_SYSCLK_SRC_SHIFT;
+ WARN_ON(freq != wm8962->fll_fout);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_SRC_MASK,
+ src);
+
+ wm8962->sysclk_rate = freq;
+
+ return 0;
+}
+
+static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int aif0 = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ aif0 |= WM8962_LRCLK_INV;
+ case SND_SOC_DAIFMT_DSP_B:
+ aif0 |= 3;
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case SND_SOC_DAIFMT_RIGHT_J:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ aif0 |= 1;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ aif0 |= 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ aif0 |= WM8962_BCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ aif0 |= WM8962_LRCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ aif0 |= WM8962_BCLK_INV | WM8962_LRCLK_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ aif0 |= WM8962_MSTR;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_0,
+ WM8962_FMT_MASK | WM8962_BCLK_INV | WM8962_MSTR |
+ WM8962_LRCLK_INV, aif0);
+
+ return 0;
+}
+
+struct _fll_div {
+ u16 fll_fratio;
+ u16 fll_outdiv;
+ u16 fll_refclk_div;
+ u16 n;
+ u16 theta;
+ u16 lambda;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static struct {
+ unsigned int min;
+ unsigned int max;
+ u16 fll_fratio;
+ int ratio;
+} fll_fratios[] = {
+ { 0, 64000, 4, 16 },
+ { 64000, 128000, 3, 8 },
+ { 128000, 256000, 2, 4 },
+ { 256000, 1000000, 1, 2 },
+ { 1000000, 13500000, 0, 1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+ unsigned int Fout)
+{
+ unsigned int target;
+ unsigned int div;
+ unsigned int fratio, gcd_fll;
+ int i;
+
+ /* Fref must be <=13.5MHz */
+ div = 1;
+ fll_div->fll_refclk_div = 0;
+ while ((Fref / div) > 13500000) {
+ div *= 2;
+ fll_div->fll_refclk_div++;
+
+ if (div > 4) {
+ pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+ Fref);
+ return -EINVAL;
+ }
+ }
+
+ pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+ /* Apply the division for our remaining calculations */
+ Fref /= div;
+
+ /* Fvco should be 90-100MHz; don't check the upper bound */
+ div = 2;
+ while (Fout * div < 90000000) {
+ div++;
+ if (div > 64) {
+ pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+ Fout);
+ return -EINVAL;
+ }
+ }
+ target = Fout * div;
+ fll_div->fll_outdiv = div - 1;
+
+ pr_debug("FLL Fvco=%dHz\n", target);
+
+ /* Find an appropraite FLL_FRATIO and factor it out of the target */
+ for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+ if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+ fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+ fratio = fll_fratios[i].ratio;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(fll_fratios)) {
+ pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+ return -EINVAL;
+ }
+
+ fll_div->n = target / (fratio * Fref);
+
+ if (target % Fref == 0) {
+ fll_div->theta = 0;
+ fll_div->lambda = 0;
+ } else {
+ gcd_fll = gcd(target, fratio * Fref);
+
+ fll_div->theta = (target - (fll_div->n * fratio * Fref))
+ / gcd_fll;
+ fll_div->lambda = (fratio * Fref) / gcd_fll;
+ }
+
+ pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+ fll_div->n, fll_div->theta, fll_div->lambda);
+ pr_debug("FLL_FRATIO=%x FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+ fll_div->fll_fratio, fll_div->fll_outdiv,
+ fll_div->fll_refclk_div);
+
+ return 0;
+}
+
+static int wm8962_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+ unsigned int Fref, unsigned int Fout)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct _fll_div fll_div;
+ int ret;
+ int fll1 = snd_soc_read(codec, WM8962_FLL_CONTROL_1) & WM8962_FLL_ENA;
+
+ /* Any change? */
+ if (source == wm8962->fll_src && Fref == wm8962->fll_fref &&
+ Fout == wm8962->fll_fout)
+ return 0;
+
+ if (Fout == 0) {
+ dev_dbg(codec->dev, "FLL disabled\n");
+
+ wm8962->fll_fref = 0;
+ wm8962->fll_fout = 0;
+
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+ WM8962_FLL_ENA, 0);
+
+ return 0;
+ }
+
+ ret = fll_factors(&fll_div, Fref, Fout);
+ if (ret != 0)
+ return ret;
+
+ switch (fll_id) {
+ case WM8962_FLL_MCLK:
+ case WM8962_FLL_BCLK:
+ case WM8962_FLL_OSC:
+ fll1 |= (fll_id - 1) << WM8962_FLL_REFCLK_SRC_SHIFT;
+ break;
+ case WM8962_FLL_INT:
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+ WM8962_FLL_OSC_ENA, WM8962_FLL_OSC_ENA);
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_5,
+ WM8962_FLL_FRC_NCO, WM8962_FLL_FRC_NCO);
+ break;
+ default:
+ dev_err(codec->dev, "Unknown FLL source %d\n", ret);
+ return -EINVAL;
+ }
+
+ if (fll_div.theta || fll_div.lambda)
+ fll1 |= WM8962_FLL_FRAC;
+
+ /* Stop the FLL while we reconfigure */
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0);
+
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_2,
+ WM8962_FLL_OUTDIV_MASK |
+ WM8962_FLL_REFCLK_DIV_MASK,
+ (fll_div.fll_outdiv << WM8962_FLL_OUTDIV_SHIFT) |
+ (fll_div.fll_refclk_div));
+
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_3,
+ WM8962_FLL_FRATIO_MASK, fll_div.fll_fratio);
+
+ snd_soc_write(codec, WM8962_FLL_CONTROL_6, fll_div.theta);
+ snd_soc_write(codec, WM8962_FLL_CONTROL_7, fll_div.lambda);
+ snd_soc_write(codec, WM8962_FLL_CONTROL_8, fll_div.n);
+
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+ WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK |
+ WM8962_FLL_ENA, fll1);
+
+ dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+
+ wm8962->fll_fref = Fref;
+ wm8962->fll_fout = Fout;
+ wm8962->fll_src = source;
+
+ return 0;
+}
+
+static int wm8962_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int val;
+
+ if (mute)
+ val = WM8962_DAC_MUTE;
+ else
+ val = 0;
+
+ return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
+ WM8962_DAC_MUTE, val);
+}
+
+#define WM8962_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8962_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops wm8962_dai_ops = {
+ .hw_params = wm8962_hw_params,
+ .set_sysclk = wm8962_set_dai_sysclk,
+ .set_fmt = wm8962_set_dai_fmt,
+ .set_pll = wm8962_set_fll,
+ .digital_mute = wm8962_mute,
+};
+
+static struct snd_soc_dai_driver wm8962_dai = {
+ .name = "wm8962",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = WM8962_RATES,
+ .formats = WM8962_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = WM8962_RATES,
+ .formats = WM8962_FORMATS,
+ },
+ .ops = &wm8962_dai_ops,
+ .symmetric_rates = 1,
+};
+
+static void wm8962_mic_work(struct work_struct *work)
+{
+ struct wm8962_priv *wm8962 = container_of(work,
+ struct wm8962_priv,
+ mic_work.work);
+ struct snd_soc_codec *codec = wm8962->codec;
+ int status = 0;
+ int irq_pol = 0;
+ int reg;
+
+ reg = snd_soc_read(codec, WM8962_ADDITIONAL_CONTROL_4);
+
+ if (reg & WM8962_MICDET_STS) {
+ status |= SND_JACK_MICROPHONE;
+ irq_pol |= WM8962_MICD_IRQ_POL;
+ }
+
+ if (reg & WM8962_MICSHORT_STS) {
+ status |= SND_JACK_BTN_0;
+ irq_pol |= WM8962_MICSCD_IRQ_POL;
+ }
+
+ snd_soc_jack_report(wm8962->jack, status,
+ SND_JACK_MICROPHONE | SND_JACK_BTN_0);
+
+ snd_soc_update_bits(codec, WM8962_MICINT_SOURCE_POL,
+ WM8962_MICSCD_IRQ_POL |
+ WM8962_MICD_IRQ_POL, irq_pol);
+}
+
+static irqreturn_t wm8962_irq(int irq, void *data)
+{
+ struct snd_soc_codec *codec = data;
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int mask;
+ int active;
+
+ mask = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
+
+ active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
+ active &= ~mask;
+
+ if (active & WM8962_FIFOS_ERR_EINT)
+ dev_err(codec->dev, "FIFO error\n");
+
+ if (active & WM8962_TEMP_SHUT_EINT)
+ dev_crit(codec->dev, "Thermal shutdown\n");
+
+ if (active & (WM8962_MICSCD_EINT | WM8962_MICD_EINT)) {
+ dev_dbg(codec->dev, "Microphone event detected\n");
+
+ schedule_delayed_work(&wm8962->mic_work,
+ msecs_to_jiffies(250));
+ }
+
+ /* Acknowledge the interrupts */
+ snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * wm8962_mic_detect - Enable microphone detection via the WM8962 IRQ
+ *
+ * @codec: WM8962 codec
+ * @jack: jack to report detection events on
+ *
+ * Enable microphone detection via IRQ on the WM8962. If GPIOs are
+ * being used to bring out signals to the processor then only platform
+ * data configuration is needed for WM8962 and processor GPIOs should
+ * be configured using snd_soc_jack_add_gpios() instead.
+ *
+ * If no jack is supplied detection will be disabled.
+ */
+int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int irq_mask, enable;
+
+ wm8962->jack = jack;
+ if (jack) {
+ irq_mask = 0;
+ enable = WM8962_MICDET_ENA;
+ } else {
+ irq_mask = WM8962_MICD_EINT | WM8962_MICSCD_EINT;
+ enable = 0;
+ }
+
+ snd_soc_update_bits(codec, WM8962_INTERRUPT_STATUS_2_MASK,
+ WM8962_MICD_EINT | WM8962_MICSCD_EINT, irq_mask);
+ snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
+ WM8962_MICDET_ENA, enable);
+
+ /* Send an initial empty report */
+ snd_soc_jack_report(wm8962->jack, 0,
+ SND_JACK_MICROPHONE | SND_JACK_BTN_0);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8962_mic_detect);
+
+#ifdef CONFIG_PM
+static int wm8962_resume(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = codec->reg_cache;
+ int i;
+
+ /* Restore the registers */
+ for (i = 1; i < ARRAY_SIZE(wm8962->reg_cache); 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,
+};
+
+static void wm8962_beep_work(struct work_struct *work)
+{
+ struct wm8962_priv *wm8962 =
+ container_of(work, struct wm8962_priv, beep_work);
+ struct snd_soc_codec *codec = wm8962->codec;
+ int i;
+ int reg = 0;
+ int best = 0;
+
+ if (wm8962->beep_rate) {
+ for (i = 0; i < ARRAY_SIZE(beep_rates); i++) {
+ if (abs(wm8962->beep_rate - beep_rates[i]) <
+ abs(wm8962->beep_rate - beep_rates[best]))
+ best = i;
+ }
+
+ dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n",
+ beep_rates[best], wm8962->beep_rate);
+
+ reg = WM8962_BEEP_ENA | (best << WM8962_BEEP_RATE_SHIFT);
+
+ snd_soc_dapm_enable_pin(codec, "Beep");
+ } else {
+ dev_dbg(codec->dev, "Disabling beep\n");
+ snd_soc_dapm_disable_pin(codec, "Beep");
+ }
+
+ snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1,
+ WM8962_BEEP_ENA | WM8962_BEEP_RATE_MASK, reg);
+
+ snd_soc_dapm_sync(codec);
+}
+
+/* For usability define a way of injecting beep events for the device -
+ * many systems will not have a keyboard.
+ */
+static int wm8962_beep_event(struct input_dev *dev, unsigned int type,
+ unsigned int code, int hz)
+{
+ struct snd_soc_codec *codec = input_get_drvdata(dev);
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "Beep event %x %x\n", code, hz);
+
+ switch (code) {
+ case SND_BELL:
+ if (hz)
+ hz = 1000;
+ case SND_TONE:
+ break;
+ default:
+ return -1;
+ }
+
+ /* Kick the beep from a workqueue */
+ wm8962->beep_rate = hz;
+ schedule_work(&wm8962->beep_work);
+ return 0;
+}
+
+static ssize_t wm8962_beep_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
+ long int time;
+
+ strict_strtol(buf, 10, &time);
+
+ input_event(wm8962->beep, EV_SND, SND_TONE, time);
+
+ return count;
+}
+
+static DEVICE_ATTR(beep, 0200, NULL, wm8962_beep_set);
+
+static void wm8962_init_beep(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ wm8962->beep = input_allocate_device();
+ if (!wm8962->beep) {
+ dev_err(codec->dev, "Failed to allocate beep device\n");
+ return;
+ }
+
+ INIT_WORK(&wm8962->beep_work, wm8962_beep_work);
+ wm8962->beep_rate = 0;
+
+ wm8962->beep->name = "WM8962 Beep Generator";
+ wm8962->beep->phys = dev_name(codec->dev);
+ wm8962->beep->id.bustype = BUS_I2C;
+
+ wm8962->beep->evbit[0] = BIT_MASK(EV_SND);
+ wm8962->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+ wm8962->beep->event = wm8962_beep_event;
+ wm8962->beep->dev.parent = codec->dev;
+ input_set_drvdata(wm8962->beep, codec);
+
+ ret = input_register_device(wm8962->beep);
+ if (ret != 0) {
+ input_free_device(wm8962->beep);
+ wm8962->beep = NULL;
+ dev_err(codec->dev, "Failed to register beep device\n");
+ }
+
+ ret = device_create_file(codec->dev, &dev_attr_beep);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to create keyclick file: %d\n",
+ ret);
+ }
+}
+
+static void wm8962_free_beep(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+
+ device_remove_file(codec->dev, &dev_attr_beep);
+ input_unregister_device(wm8962->beep);
+ cancel_work_sync(&wm8962->beep_work);
+ wm8962->beep = NULL;
+
+ snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0);
+}
+#else
+static void wm8962_init_beep(struct snd_soc_codec *codec)
+{
+}
+
+static void wm8962_free_beep(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+static void wm8962_set_gpio_mode(struct snd_soc_codec *codec, int gpio)
+{
+ int mask = 0;
+ int val = 0;
+
+ /* Some of the GPIOs are behind MFP configuration and need to
+ * be put into GPIO mode. */
+ switch (gpio) {
+ case 2:
+ mask = WM8962_CLKOUT2_SEL_MASK;
+ val = 1 << WM8962_CLKOUT2_SEL_SHIFT;
+ break;
+ case 3:
+ mask = WM8962_CLKOUT3_SEL_MASK;
+ val = 1 << WM8962_CLKOUT3_SEL_SHIFT;
+ break;
+ default:
+ break;
+ }
+
+ if (mask)
+ snd_soc_update_bits(codec, WM8962_ANALOGUE_CLOCKING1,
+ mask, val);
+}
+
+#ifdef CONFIG_GPIOLIB
+static inline struct wm8962_priv *gpio_to_wm8962(struct gpio_chip *chip)
+{
+ return container_of(chip, struct wm8962_priv, gpio_chip);
+}
+
+static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+ struct snd_soc_codec *codec = wm8962->codec;
+
+ /* The WM8962 GPIOs aren't linearly numbered. For simplicity
+ * we export linear numbers and error out if the unsupported
+ * ones are requsted.
+ */
+ switch (offset + 1) {
+ case 2:
+ case 3:
+ case 5:
+ case 6:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ wm8962_set_gpio_mode(codec, offset + 1);
+
+ return 0;
+}
+
+static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+ struct snd_soc_codec *codec = wm8962->codec;
+
+ snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
+ WM8962_GP2_LVL, value << WM8962_GP2_LVL_SHIFT);
+}
+
+static int wm8962_gpio_direction_out(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+ struct snd_soc_codec *codec = wm8962->codec;
+ int val;
+
+ /* Force function 1 (logic output) */
+ val = (1 << WM8962_GP2_FN_SHIFT) | (value << WM8962_GP2_LVL_SHIFT);
+
+ return snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
+ WM8962_GP2_FN_MASK | WM8962_GP2_LVL, val);
+}
+
+static struct gpio_chip wm8962_template_chip = {
+ .label = "wm8962",
+ .owner = THIS_MODULE,
+ .request = wm8962_gpio_request,
+ .direction_output = wm8962_gpio_direction_out,
+ .set = wm8962_gpio_set,
+ .can_sleep = 1,
+};
+
+static void wm8962_init_gpio(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+ int ret;
+
+ wm8962->gpio_chip = wm8962_template_chip;
+ wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO;
+ wm8962->gpio_chip.dev = codec->dev;
+
+ if (pdata && pdata->gpio_base)
+ wm8962->gpio_chip.base = pdata->gpio_base;
+ else
+ wm8962->gpio_chip.base = -1;
+
+ ret = gpiochip_add(&wm8962->gpio_chip);
+ if (ret != 0)
+ dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm8962_free_gpio(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ ret = gpiochip_remove(&wm8962->gpio_chip);
+ if (ret != 0)
+ dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+}
+#else
+static void wm8962_init_gpio(struct snd_soc_codec *codec)
+{
+}
+
+static void wm8962_free_gpio(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+static int wm8962_probe(struct snd_soc_codec *codec)
+{
+ int ret;
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+ struct i2c_client *i2c = container_of(codec->dev, struct i2c_client,
+ dev);
+ int i, trigger, irq_pol;
+
+ wm8962->codec = codec;
+ INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work);
+
+ codec->cache_sync = 1;
+ codec->idle_bias_off = 1;
+
+ ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
+ wm8962->supplies[i].supply = wm8962_supply_names[i];
+
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8962->supplies),
+ wm8962->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ goto err;
+ }
+
+ wm8962->disable_nb[0].notifier_call = wm8962_regulator_event_0;
+ wm8962->disable_nb[1].notifier_call = wm8962_regulator_event_1;
+ wm8962->disable_nb[2].notifier_call = wm8962_regulator_event_2;
+ wm8962->disable_nb[3].notifier_call = wm8962_regulator_event_3;
+ wm8962->disable_nb[4].notifier_call = wm8962_regulator_event_4;
+ wm8962->disable_nb[5].notifier_call = wm8962_regulator_event_5;
+ wm8962->disable_nb[6].notifier_call = wm8962_regulator_event_6;
+ wm8962->disable_nb[7].notifier_call = wm8962_regulator_event_7;
+
+ /* This should really be moved into the regulator core */
+ for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) {
+ ret = regulator_register_notifier(wm8962->supplies[i].consumer,
+ &wm8962->disable_nb[i]);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to register regulator notifier: %d\n",
+ ret);
+ }
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
+ wm8962->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ goto err_get;
+ }
+
+ ret = snd_soc_read(codec, WM8962_SOFTWARE_RESET);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read ID register\n");
+ goto err_enable;
+ }
+ if (ret != wm8962_reg[WM8962_SOFTWARE_RESET]) {
+ dev_err(codec->dev, "Device is not a WM8962, ID %x != %x\n",
+ ret, wm8962_reg[WM8962_SOFTWARE_RESET]);
+ ret = -EINVAL;
+ goto err_enable;
+ }
+
+ ret = snd_soc_read(codec, WM8962_RIGHT_INPUT_VOLUME);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read device revision: %d\n",
+ ret);
+ goto err_enable;
+ }
+
+ dev_info(codec->dev, "customer id %x revision %c\n",
+ (ret & WM8962_CUST_ID_MASK) >> WM8962_CUST_ID_SHIFT,
+ ((ret & WM8962_CHIP_REV_MASK) >> WM8962_CHIP_REV_SHIFT)
+ + 'A');
+
+ ret = wm8962_reset(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to issue reset\n");
+ goto err_enable;
+ }
+
+ /* SYSCLK defaults to on; make sure it is off so we can safely
+ * write to registers if the device is declocked.
+ */
+ snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_ENA, 0);
+
+ regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+
+ if (pdata) {
+ /* Apply static configuration for GPIOs */
+ for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++)
+ if (pdata->gpio_init[i]) {
+ wm8962_set_gpio_mode(codec, i + 1);
+ snd_soc_write(codec, 0x200 + i,
+ pdata->gpio_init[i] & 0xffff);
+ }
+
+ /* Put the speakers into mono mode? */
+ if (pdata->spk_mono)
+ wm8962->reg_cache[WM8962_CLASS_D_CONTROL_2]
+ |= WM8962_SPK_MONO;
+
+ /* Micbias setup, detection enable and detection
+ * threasholds. */
+ if (pdata->mic_cfg)
+ snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
+ WM8962_MICDET_ENA |
+ WM8962_MICDET_THR_MASK |
+ WM8962_MICSHORT_THR_MASK |
+ WM8962_MICBIAS_LVL,
+ pdata->mic_cfg);
+ }
+
+ /* Latch volume update bits */
+ wm8962->reg_cache[WM8962_LEFT_INPUT_VOLUME] |= WM8962_IN_VU;
+ wm8962->reg_cache[WM8962_RIGHT_INPUT_VOLUME] |= WM8962_IN_VU;
+ wm8962->reg_cache[WM8962_LEFT_ADC_VOLUME] |= WM8962_ADC_VU;
+ wm8962->reg_cache[WM8962_RIGHT_ADC_VOLUME] |= WM8962_ADC_VU;
+ wm8962->reg_cache[WM8962_LEFT_DAC_VOLUME] |= WM8962_DAC_VU;
+ wm8962->reg_cache[WM8962_RIGHT_DAC_VOLUME] |= WM8962_DAC_VU;
+ wm8962->reg_cache[WM8962_SPKOUTL_VOLUME] |= WM8962_SPKOUT_VU;
+ wm8962->reg_cache[WM8962_SPKOUTR_VOLUME] |= WM8962_SPKOUT_VU;
+ wm8962->reg_cache[WM8962_HPOUTL_VOLUME] |= WM8962_HPOUT_VU;
+ wm8962->reg_cache[WM8962_HPOUTR_VOLUME] |= WM8962_HPOUT_VU;
+
+ wm8962_add_widgets(codec);
+
+ wm8962_init_beep(codec);
+ wm8962_init_gpio(codec);
+
+ if (i2c->irq) {
+ if (pdata && pdata->irq_active_low) {
+ trigger = IRQF_TRIGGER_LOW;
+ irq_pol = WM8962_IRQ_POL;
+ } else {
+ trigger = IRQF_TRIGGER_HIGH;
+ irq_pol = 0;
+ }
+
+ snd_soc_update_bits(codec, WM8962_INTERRUPT_CONTROL,
+ WM8962_IRQ_POL, irq_pol);
+
+ ret = request_threaded_irq(i2c->irq, NULL, wm8962_irq,
+ trigger | IRQF_ONESHOT,
+ "wm8962", codec);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
+ i2c->irq, ret);
+ /* Non-fatal */
+ } else {
+ /* Enable error reporting IRQs by default */
+ snd_soc_update_bits(codec,
+ WM8962_INTERRUPT_STATUS_2_MASK,
+ WM8962_TEMP_SHUT_EINT |
+ WM8962_FIFOS_ERR_EINT, 0);
+ }
+ }
+
+ return 0;
+
+err_enable:
+ regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+err_get:
+ regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+err:
+ kfree(wm8962);
+ return ret;
+}
+
+static int wm8962_remove(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct i2c_client *i2c = container_of(codec->dev, struct i2c_client,
+ dev);
+ int i;
+
+ if (i2c->irq)
+ free_irq(i2c->irq, codec);
+
+ cancel_delayed_work_sync(&wm8962->mic_work);
+
+ wm8962_free_gpio(codec);
+ wm8962_free_beep(codec);
+ for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
+ regulator_unregister_notifier(wm8962->supplies[i].consumer,
+ &wm8962->disable_nb[i]);
+ regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+
+ return 0;
+}
+
+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),
+ .reg_cache_default = wm8962_reg,
+ .volatile_register = wm8962_volatile_register,
+ .readable_register = wm8962_readable_register,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8962_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8962_priv *wm8962;
+ int ret;
+
+ wm8962 = kzalloc(sizeof(struct wm8962_priv), GFP_KERNEL);
+ if (wm8962 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm8962);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8962, &wm8962_dai, 1);
+ if (ret < 0)
+ kfree(wm8962);
+
+ return ret;
+}
+
+static __devexit int wm8962_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id wm8962_i2c_id[] = {
+ { "wm8962", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8962_i2c_id);
+
+static struct i2c_driver wm8962_i2c_driver = {
+ .driver = {
+ .name = "wm8962",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8962_i2c_probe,
+ .remove = __devexit_p(wm8962_i2c_remove),
+ .id_table = wm8962_i2c_id,
+};
+#endif
+
+static int __init wm8962_modinit(void)
+{
+ int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8962_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8962 I2C driver: %d\n",
+ ret);
+ }
+#endif
+ return 0;
+}
+module_init(wm8962_modinit);
+
+static void __exit wm8962_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8962_i2c_driver);
+#endif
+}
+module_exit(wm8962_exit);
+
+MODULE_DESCRIPTION("ASoC WM8962 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8962.h b/sound/soc/codecs/wm8962.h
new file mode 100644
index 000000000000..a1a5d5294c19
--- /dev/null
+++ b/sound/soc/codecs/wm8962.h
@@ -0,0 +1,3780 @@
+/*
+ * wm8962.h -- WM8962 ASoC driver
+ *
+ * Copyright 2010 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 _WM8962_H
+#define _WM8962_H
+
+#include <asm/types.h>
+#include <sound/soc.h>
+
+#define WM8962_SYSCLK_MCLK 1
+#define WM8962_SYSCLK_FLL 2
+#define WM8962_SYSCLK_PLL3 3
+
+#define WM8962_FLL 1
+
+#define WM8962_FLL_MCLK 1
+#define WM8962_FLL_BCLK 2
+#define WM8962_FLL_OSC 3
+#define WM8962_FLL_INT 4
+
+/*
+ * Register values.
+ */
+#define WM8962_LEFT_INPUT_VOLUME 0x00
+#define WM8962_RIGHT_INPUT_VOLUME 0x01
+#define WM8962_HPOUTL_VOLUME 0x02
+#define WM8962_HPOUTR_VOLUME 0x03
+#define WM8962_CLOCKING1 0x04
+#define WM8962_ADC_DAC_CONTROL_1 0x05
+#define WM8962_ADC_DAC_CONTROL_2 0x06
+#define WM8962_AUDIO_INTERFACE_0 0x07
+#define WM8962_CLOCKING2 0x08
+#define WM8962_AUDIO_INTERFACE_1 0x09
+#define WM8962_LEFT_DAC_VOLUME 0x0A
+#define WM8962_RIGHT_DAC_VOLUME 0x0B
+#define WM8962_AUDIO_INTERFACE_2 0x0E
+#define WM8962_SOFTWARE_RESET 0x0F
+#define WM8962_ALC1 0x11
+#define WM8962_ALC2 0x12
+#define WM8962_ALC3 0x13
+#define WM8962_NOISE_GATE 0x14
+#define WM8962_LEFT_ADC_VOLUME 0x15
+#define WM8962_RIGHT_ADC_VOLUME 0x16
+#define WM8962_ADDITIONAL_CONTROL_1 0x17
+#define WM8962_ADDITIONAL_CONTROL_2 0x18
+#define WM8962_PWR_MGMT_1 0x19
+#define WM8962_PWR_MGMT_2 0x1A
+#define WM8962_ADDITIONAL_CONTROL_3 0x1B
+#define WM8962_ANTI_POP 0x1C
+#define WM8962_CLOCKING_3 0x1E
+#define WM8962_INPUT_MIXER_CONTROL_1 0x1F
+#define WM8962_LEFT_INPUT_MIXER_VOLUME 0x20
+#define WM8962_RIGHT_INPUT_MIXER_VOLUME 0x21
+#define WM8962_INPUT_MIXER_CONTROL_2 0x22
+#define WM8962_INPUT_BIAS_CONTROL 0x23
+#define WM8962_LEFT_INPUT_PGA_CONTROL 0x25
+#define WM8962_RIGHT_INPUT_PGA_CONTROL 0x26
+#define WM8962_SPKOUTL_VOLUME 0x28
+#define WM8962_SPKOUTR_VOLUME 0x29
+#define WM8962_THERMAL_SHUTDOWN_STATUS 0x2F
+#define WM8962_ADDITIONAL_CONTROL_4 0x30
+#define WM8962_CLASS_D_CONTROL_1 0x31
+#define WM8962_CLASS_D_CONTROL_2 0x33
+#define WM8962_CLOCKING_4 0x38
+#define WM8962_DAC_DSP_MIXING_1 0x39
+#define WM8962_DAC_DSP_MIXING_2 0x3A
+#define WM8962_DC_SERVO_0 0x3C
+#define WM8962_DC_SERVO_1 0x3D
+#define WM8962_DC_SERVO_4 0x40
+#define WM8962_DC_SERVO_6 0x42
+#define WM8962_ANALOGUE_PGA_BIAS 0x44
+#define WM8962_ANALOGUE_HP_0 0x45
+#define WM8962_ANALOGUE_HP_2 0x47
+#define WM8962_CHARGE_PUMP_1 0x48
+#define WM8962_CHARGE_PUMP_B 0x52
+#define WM8962_WRITE_SEQUENCER_CONTROL_1 0x57
+#define WM8962_WRITE_SEQUENCER_CONTROL_2 0x5A
+#define WM8962_WRITE_SEQUENCER_CONTROL_3 0x5D
+#define WM8962_CONTROL_INTERFACE 0x5E
+#define WM8962_MIXER_ENABLES 0x63
+#define WM8962_HEADPHONE_MIXER_1 0x64
+#define WM8962_HEADPHONE_MIXER_2 0x65
+#define WM8962_HEADPHONE_MIXER_3 0x66
+#define WM8962_HEADPHONE_MIXER_4 0x67
+#define WM8962_SPEAKER_MIXER_1 0x69
+#define WM8962_SPEAKER_MIXER_2 0x6A
+#define WM8962_SPEAKER_MIXER_3 0x6B
+#define WM8962_SPEAKER_MIXER_4 0x6C
+#define WM8962_SPEAKER_MIXER_5 0x6D
+#define WM8962_BEEP_GENERATOR_1 0x6E
+#define WM8962_OSCILLATOR_TRIM_3 0x73
+#define WM8962_OSCILLATOR_TRIM_4 0x74
+#define WM8962_OSCILLATOR_TRIM_7 0x77
+#define WM8962_ANALOGUE_CLOCKING1 0x7C
+#define WM8962_ANALOGUE_CLOCKING2 0x7D
+#define WM8962_ANALOGUE_CLOCKING3 0x7E
+#define WM8962_PLL_SOFTWARE_RESET 0x7F
+#define WM8962_PLL2 0x81
+#define WM8962_PLL_4 0x83
+#define WM8962_PLL_9 0x88
+#define WM8962_PLL_10 0x89
+#define WM8962_PLL_11 0x8A
+#define WM8962_PLL_12 0x8B
+#define WM8962_PLL_13 0x8C
+#define WM8962_PLL_14 0x8D
+#define WM8962_PLL_15 0x8E
+#define WM8962_PLL_16 0x8F
+#define WM8962_FLL_CONTROL_1 0x9B
+#define WM8962_FLL_CONTROL_2 0x9C
+#define WM8962_FLL_CONTROL_3 0x9D
+#define WM8962_FLL_CONTROL_5 0x9F
+#define WM8962_FLL_CONTROL_6 0xA0
+#define WM8962_FLL_CONTROL_7 0xA1
+#define WM8962_FLL_CONTROL_8 0xA2
+#define WM8962_GENERAL_TEST_1 0xFC
+#define WM8962_DF1 0x100
+#define WM8962_DF2 0x101
+#define WM8962_DF3 0x102
+#define WM8962_DF4 0x103
+#define WM8962_DF5 0x104
+#define WM8962_DF6 0x105
+#define WM8962_DF7 0x106
+#define WM8962_LHPF1 0x108
+#define WM8962_LHPF2 0x109
+#define WM8962_THREED1 0x10C
+#define WM8962_THREED2 0x10D
+#define WM8962_THREED3 0x10E
+#define WM8962_THREED4 0x10F
+#define WM8962_DRC_1 0x114
+#define WM8962_DRC_2 0x115
+#define WM8962_DRC_3 0x116
+#define WM8962_DRC_4 0x117
+#define WM8962_DRC_5 0x118
+#define WM8962_TLOOPBACK 0x11D
+#define WM8962_EQ1 0x14F
+#define WM8962_EQ2 0x150
+#define WM8962_EQ3 0x151
+#define WM8962_EQ4 0x152
+#define WM8962_EQ5 0x153
+#define WM8962_EQ6 0x154
+#define WM8962_EQ7 0x155
+#define WM8962_EQ8 0x156
+#define WM8962_EQ9 0x157
+#define WM8962_EQ10 0x158
+#define WM8962_EQ11 0x159
+#define WM8962_EQ12 0x15A
+#define WM8962_EQ13 0x15B
+#define WM8962_EQ14 0x15C
+#define WM8962_EQ15 0x15D
+#define WM8962_EQ16 0x15E
+#define WM8962_EQ17 0x15F
+#define WM8962_EQ18 0x160
+#define WM8962_EQ19 0x161
+#define WM8962_EQ20 0x162
+#define WM8962_EQ21 0x163
+#define WM8962_EQ22 0x164
+#define WM8962_EQ23 0x165
+#define WM8962_EQ24 0x166
+#define WM8962_EQ25 0x167
+#define WM8962_EQ26 0x168
+#define WM8962_EQ27 0x169
+#define WM8962_EQ28 0x16A
+#define WM8962_EQ29 0x16B
+#define WM8962_EQ30 0x16C
+#define WM8962_EQ31 0x16D
+#define WM8962_EQ32 0x16E
+#define WM8962_EQ33 0x16F
+#define WM8962_EQ34 0x170
+#define WM8962_EQ35 0x171
+#define WM8962_EQ36 0x172
+#define WM8962_EQ37 0x173
+#define WM8962_EQ38 0x174
+#define WM8962_EQ39 0x175
+#define WM8962_EQ40 0x176
+#define WM8962_EQ41 0x177
+#define WM8962_GPIO_BASE 0x200
+#define WM8962_GPIO_2 0x201
+#define WM8962_GPIO_3 0x202
+#define WM8962_GPIO_5 0x204
+#define WM8962_GPIO_6 0x205
+#define WM8962_INTERRUPT_STATUS_1 0x230
+#define WM8962_INTERRUPT_STATUS_2 0x231
+#define WM8962_INTERRUPT_STATUS_1_MASK 0x238
+#define WM8962_INTERRUPT_STATUS_2_MASK 0x239
+#define WM8962_INTERRUPT_CONTROL 0x240
+#define WM8962_IRQ_DEBOUNCE 0x248
+#define WM8962_MICINT_SOURCE_POL 0x24A
+#define WM8962_DSP2_POWER_MANAGEMENT 0x300
+#define WM8962_DSP2_EXECCONTROL 0x40D
+#define WM8962_WRITE_SEQUENCER_0 0x1000
+#define WM8962_WRITE_SEQUENCER_1 0x1001
+#define WM8962_WRITE_SEQUENCER_2 0x1002
+#define WM8962_WRITE_SEQUENCER_3 0x1003
+#define WM8962_WRITE_SEQUENCER_4 0x1004
+#define WM8962_WRITE_SEQUENCER_5 0x1005
+#define WM8962_WRITE_SEQUENCER_6 0x1006
+#define WM8962_WRITE_SEQUENCER_7 0x1007
+#define WM8962_WRITE_SEQUENCER_8 0x1008
+#define WM8962_WRITE_SEQUENCER_9 0x1009
+#define WM8962_WRITE_SEQUENCER_10 0x100A
+#define WM8962_WRITE_SEQUENCER_11 0x100B
+#define WM8962_WRITE_SEQUENCER_12 0x100C
+#define WM8962_WRITE_SEQUENCER_13 0x100D
+#define WM8962_WRITE_SEQUENCER_14 0x100E
+#define WM8962_WRITE_SEQUENCER_15 0x100F
+#define WM8962_WRITE_SEQUENCER_16 0x1010
+#define WM8962_WRITE_SEQUENCER_17 0x1011
+#define WM8962_WRITE_SEQUENCER_18 0x1012
+#define WM8962_WRITE_SEQUENCER_19 0x1013
+#define WM8962_WRITE_SEQUENCER_20 0x1014
+#define WM8962_WRITE_SEQUENCER_21 0x1015
+#define WM8962_WRITE_SEQUENCER_22 0x1016
+#define WM8962_WRITE_SEQUENCER_23 0x1017
+#define WM8962_WRITE_SEQUENCER_24 0x1018
+#define WM8962_WRITE_SEQUENCER_25 0x1019
+#define WM8962_WRITE_SEQUENCER_26 0x101A
+#define WM8962_WRITE_SEQUENCER_27 0x101B
+#define WM8962_WRITE_SEQUENCER_28 0x101C
+#define WM8962_WRITE_SEQUENCER_29 0x101D
+#define WM8962_WRITE_SEQUENCER_30 0x101E
+#define WM8962_WRITE_SEQUENCER_31 0x101F
+#define WM8962_WRITE_SEQUENCER_32 0x1020
+#define WM8962_WRITE_SEQUENCER_33 0x1021
+#define WM8962_WRITE_SEQUENCER_34 0x1022
+#define WM8962_WRITE_SEQUENCER_35 0x1023
+#define WM8962_WRITE_SEQUENCER_36 0x1024
+#define WM8962_WRITE_SEQUENCER_37 0x1025
+#define WM8962_WRITE_SEQUENCER_38 0x1026
+#define WM8962_WRITE_SEQUENCER_39 0x1027
+#define WM8962_WRITE_SEQUENCER_40 0x1028
+#define WM8962_WRITE_SEQUENCER_41 0x1029
+#define WM8962_WRITE_SEQUENCER_42 0x102A
+#define WM8962_WRITE_SEQUENCER_43 0x102B
+#define WM8962_WRITE_SEQUENCER_44 0x102C
+#define WM8962_WRITE_SEQUENCER_45 0x102D
+#define WM8962_WRITE_SEQUENCER_46 0x102E
+#define WM8962_WRITE_SEQUENCER_47 0x102F
+#define WM8962_WRITE_SEQUENCER_48 0x1030
+#define WM8962_WRITE_SEQUENCER_49 0x1031
+#define WM8962_WRITE_SEQUENCER_50 0x1032
+#define WM8962_WRITE_SEQUENCER_51 0x1033
+#define WM8962_WRITE_SEQUENCER_52 0x1034
+#define WM8962_WRITE_SEQUENCER_53 0x1035
+#define WM8962_WRITE_SEQUENCER_54 0x1036
+#define WM8962_WRITE_SEQUENCER_55 0x1037
+#define WM8962_WRITE_SEQUENCER_56 0x1038
+#define WM8962_WRITE_SEQUENCER_57 0x1039
+#define WM8962_WRITE_SEQUENCER_58 0x103A
+#define WM8962_WRITE_SEQUENCER_59 0x103B
+#define WM8962_WRITE_SEQUENCER_60 0x103C
+#define WM8962_WRITE_SEQUENCER_61 0x103D
+#define WM8962_WRITE_SEQUENCER_62 0x103E
+#define WM8962_WRITE_SEQUENCER_63 0x103F
+#define WM8962_WRITE_SEQUENCER_64 0x1040
+#define WM8962_WRITE_SEQUENCER_65 0x1041
+#define WM8962_WRITE_SEQUENCER_66 0x1042
+#define WM8962_WRITE_SEQUENCER_67 0x1043
+#define WM8962_WRITE_SEQUENCER_68 0x1044
+#define WM8962_WRITE_SEQUENCER_69 0x1045
+#define WM8962_WRITE_SEQUENCER_70 0x1046
+#define WM8962_WRITE_SEQUENCER_71 0x1047
+#define WM8962_WRITE_SEQUENCER_72 0x1048
+#define WM8962_WRITE_SEQUENCER_73 0x1049
+#define WM8962_WRITE_SEQUENCER_74 0x104A
+#define WM8962_WRITE_SEQUENCER_75 0x104B
+#define WM8962_WRITE_SEQUENCER_76 0x104C
+#define WM8962_WRITE_SEQUENCER_77 0x104D
+#define WM8962_WRITE_SEQUENCER_78 0x104E
+#define WM8962_WRITE_SEQUENCER_79 0x104F
+#define WM8962_WRITE_SEQUENCER_80 0x1050
+#define WM8962_WRITE_SEQUENCER_81 0x1051
+#define WM8962_WRITE_SEQUENCER_82 0x1052
+#define WM8962_WRITE_SEQUENCER_83 0x1053
+#define WM8962_WRITE_SEQUENCER_84 0x1054
+#define WM8962_WRITE_SEQUENCER_85 0x1055
+#define WM8962_WRITE_SEQUENCER_86 0x1056
+#define WM8962_WRITE_SEQUENCER_87 0x1057
+#define WM8962_WRITE_SEQUENCER_88 0x1058
+#define WM8962_WRITE_SEQUENCER_89 0x1059
+#define WM8962_WRITE_SEQUENCER_90 0x105A
+#define WM8962_WRITE_SEQUENCER_91 0x105B
+#define WM8962_WRITE_SEQUENCER_92 0x105C
+#define WM8962_WRITE_SEQUENCER_93 0x105D
+#define WM8962_WRITE_SEQUENCER_94 0x105E
+#define WM8962_WRITE_SEQUENCER_95 0x105F
+#define WM8962_WRITE_SEQUENCER_96 0x1060
+#define WM8962_WRITE_SEQUENCER_97 0x1061
+#define WM8962_WRITE_SEQUENCER_98 0x1062
+#define WM8962_WRITE_SEQUENCER_99 0x1063
+#define WM8962_WRITE_SEQUENCER_100 0x1064
+#define WM8962_WRITE_SEQUENCER_101 0x1065
+#define WM8962_WRITE_SEQUENCER_102 0x1066
+#define WM8962_WRITE_SEQUENCER_103 0x1067
+#define WM8962_WRITE_SEQUENCER_104 0x1068
+#define WM8962_WRITE_SEQUENCER_105 0x1069
+#define WM8962_WRITE_SEQUENCER_106 0x106A
+#define WM8962_WRITE_SEQUENCER_107 0x106B
+#define WM8962_WRITE_SEQUENCER_108 0x106C
+#define WM8962_WRITE_SEQUENCER_109 0x106D
+#define WM8962_WRITE_SEQUENCER_110 0x106E
+#define WM8962_WRITE_SEQUENCER_111 0x106F
+#define WM8962_WRITE_SEQUENCER_112 0x1070
+#define WM8962_WRITE_SEQUENCER_113 0x1071
+#define WM8962_WRITE_SEQUENCER_114 0x1072
+#define WM8962_WRITE_SEQUENCER_115 0x1073
+#define WM8962_WRITE_SEQUENCER_116 0x1074
+#define WM8962_WRITE_SEQUENCER_117 0x1075
+#define WM8962_WRITE_SEQUENCER_118 0x1076
+#define WM8962_WRITE_SEQUENCER_119 0x1077
+#define WM8962_WRITE_SEQUENCER_120 0x1078
+#define WM8962_WRITE_SEQUENCER_121 0x1079
+#define WM8962_WRITE_SEQUENCER_122 0x107A
+#define WM8962_WRITE_SEQUENCER_123 0x107B
+#define WM8962_WRITE_SEQUENCER_124 0x107C
+#define WM8962_WRITE_SEQUENCER_125 0x107D
+#define WM8962_WRITE_SEQUENCER_126 0x107E
+#define WM8962_WRITE_SEQUENCER_127 0x107F
+#define WM8962_WRITE_SEQUENCER_128 0x1080
+#define WM8962_WRITE_SEQUENCER_129 0x1081
+#define WM8962_WRITE_SEQUENCER_130 0x1082
+#define WM8962_WRITE_SEQUENCER_131 0x1083
+#define WM8962_WRITE_SEQUENCER_132 0x1084
+#define WM8962_WRITE_SEQUENCER_133 0x1085
+#define WM8962_WRITE_SEQUENCER_134 0x1086
+#define WM8962_WRITE_SEQUENCER_135 0x1087
+#define WM8962_WRITE_SEQUENCER_136 0x1088
+#define WM8962_WRITE_SEQUENCER_137 0x1089
+#define WM8962_WRITE_SEQUENCER_138 0x108A
+#define WM8962_WRITE_SEQUENCER_139 0x108B
+#define WM8962_WRITE_SEQUENCER_140 0x108C
+#define WM8962_WRITE_SEQUENCER_141 0x108D
+#define WM8962_WRITE_SEQUENCER_142 0x108E
+#define WM8962_WRITE_SEQUENCER_143 0x108F
+#define WM8962_WRITE_SEQUENCER_144 0x1090
+#define WM8962_WRITE_SEQUENCER_145 0x1091
+#define WM8962_WRITE_SEQUENCER_146 0x1092
+#define WM8962_WRITE_SEQUENCER_147 0x1093
+#define WM8962_WRITE_SEQUENCER_148 0x1094
+#define WM8962_WRITE_SEQUENCER_149 0x1095
+#define WM8962_WRITE_SEQUENCER_150 0x1096
+#define WM8962_WRITE_SEQUENCER_151 0x1097
+#define WM8962_WRITE_SEQUENCER_152 0x1098
+#define WM8962_WRITE_SEQUENCER_153 0x1099
+#define WM8962_WRITE_SEQUENCER_154 0x109A
+#define WM8962_WRITE_SEQUENCER_155 0x109B
+#define WM8962_WRITE_SEQUENCER_156 0x109C
+#define WM8962_WRITE_SEQUENCER_157 0x109D
+#define WM8962_WRITE_SEQUENCER_158 0x109E
+#define WM8962_WRITE_SEQUENCER_159 0x109F
+#define WM8962_WRITE_SEQUENCER_160 0x10A0
+#define WM8962_WRITE_SEQUENCER_161 0x10A1
+#define WM8962_WRITE_SEQUENCER_162 0x10A2
+#define WM8962_WRITE_SEQUENCER_163 0x10A3
+#define WM8962_WRITE_SEQUENCER_164 0x10A4
+#define WM8962_WRITE_SEQUENCER_165 0x10A5
+#define WM8962_WRITE_SEQUENCER_166 0x10A6
+#define WM8962_WRITE_SEQUENCER_167 0x10A7
+#define WM8962_WRITE_SEQUENCER_168 0x10A8
+#define WM8962_WRITE_SEQUENCER_169 0x10A9
+#define WM8962_WRITE_SEQUENCER_170 0x10AA
+#define WM8962_WRITE_SEQUENCER_171 0x10AB
+#define WM8962_WRITE_SEQUENCER_172 0x10AC
+#define WM8962_WRITE_SEQUENCER_173 0x10AD
+#define WM8962_WRITE_SEQUENCER_174 0x10AE
+#define WM8962_WRITE_SEQUENCER_175 0x10AF
+#define WM8962_WRITE_SEQUENCER_176 0x10B0
+#define WM8962_WRITE_SEQUENCER_177 0x10B1
+#define WM8962_WRITE_SEQUENCER_178 0x10B2
+#define WM8962_WRITE_SEQUENCER_179 0x10B3
+#define WM8962_WRITE_SEQUENCER_180 0x10B4
+#define WM8962_WRITE_SEQUENCER_181 0x10B5
+#define WM8962_WRITE_SEQUENCER_182 0x10B6
+#define WM8962_WRITE_SEQUENCER_183 0x10B7
+#define WM8962_WRITE_SEQUENCER_184 0x10B8
+#define WM8962_WRITE_SEQUENCER_185 0x10B9
+#define WM8962_WRITE_SEQUENCER_186 0x10BA
+#define WM8962_WRITE_SEQUENCER_187 0x10BB
+#define WM8962_WRITE_SEQUENCER_188 0x10BC
+#define WM8962_WRITE_SEQUENCER_189 0x10BD
+#define WM8962_WRITE_SEQUENCER_190 0x10BE
+#define WM8962_WRITE_SEQUENCER_191 0x10BF
+#define WM8962_WRITE_SEQUENCER_192 0x10C0
+#define WM8962_WRITE_SEQUENCER_193 0x10C1
+#define WM8962_WRITE_SEQUENCER_194 0x10C2
+#define WM8962_WRITE_SEQUENCER_195 0x10C3
+#define WM8962_WRITE_SEQUENCER_196 0x10C4
+#define WM8962_WRITE_SEQUENCER_197 0x10C5
+#define WM8962_WRITE_SEQUENCER_198 0x10C6
+#define WM8962_WRITE_SEQUENCER_199 0x10C7
+#define WM8962_WRITE_SEQUENCER_200 0x10C8
+#define WM8962_WRITE_SEQUENCER_201 0x10C9
+#define WM8962_WRITE_SEQUENCER_202 0x10CA
+#define WM8962_WRITE_SEQUENCER_203 0x10CB
+#define WM8962_WRITE_SEQUENCER_204 0x10CC
+#define WM8962_WRITE_SEQUENCER_205 0x10CD
+#define WM8962_WRITE_SEQUENCER_206 0x10CE
+#define WM8962_WRITE_SEQUENCER_207 0x10CF
+#define WM8962_WRITE_SEQUENCER_208 0x10D0
+#define WM8962_WRITE_SEQUENCER_209 0x10D1
+#define WM8962_WRITE_SEQUENCER_210 0x10D2
+#define WM8962_WRITE_SEQUENCER_211 0x10D3
+#define WM8962_WRITE_SEQUENCER_212 0x10D4
+#define WM8962_WRITE_SEQUENCER_213 0x10D5
+#define WM8962_WRITE_SEQUENCER_214 0x10D6
+#define WM8962_WRITE_SEQUENCER_215 0x10D7
+#define WM8962_WRITE_SEQUENCER_216 0x10D8
+#define WM8962_WRITE_SEQUENCER_217 0x10D9
+#define WM8962_WRITE_SEQUENCER_218 0x10DA
+#define WM8962_WRITE_SEQUENCER_219 0x10DB
+#define WM8962_WRITE_SEQUENCER_220 0x10DC
+#define WM8962_WRITE_SEQUENCER_221 0x10DD
+#define WM8962_WRITE_SEQUENCER_222 0x10DE
+#define WM8962_WRITE_SEQUENCER_223 0x10DF
+#define WM8962_WRITE_SEQUENCER_224 0x10E0
+#define WM8962_WRITE_SEQUENCER_225 0x10E1
+#define WM8962_WRITE_SEQUENCER_226 0x10E2
+#define WM8962_WRITE_SEQUENCER_227 0x10E3
+#define WM8962_WRITE_SEQUENCER_228 0x10E4
+#define WM8962_WRITE_SEQUENCER_229 0x10E5
+#define WM8962_WRITE_SEQUENCER_230 0x10E6
+#define WM8962_WRITE_SEQUENCER_231 0x10E7
+#define WM8962_WRITE_SEQUENCER_232 0x10E8
+#define WM8962_WRITE_SEQUENCER_233 0x10E9
+#define WM8962_WRITE_SEQUENCER_234 0x10EA
+#define WM8962_WRITE_SEQUENCER_235 0x10EB
+#define WM8962_WRITE_SEQUENCER_236 0x10EC
+#define WM8962_WRITE_SEQUENCER_237 0x10ED
+#define WM8962_WRITE_SEQUENCER_238 0x10EE
+#define WM8962_WRITE_SEQUENCER_239 0x10EF
+#define WM8962_WRITE_SEQUENCER_240 0x10F0
+#define WM8962_WRITE_SEQUENCER_241 0x10F1
+#define WM8962_WRITE_SEQUENCER_242 0x10F2
+#define WM8962_WRITE_SEQUENCER_243 0x10F3
+#define WM8962_WRITE_SEQUENCER_244 0x10F4
+#define WM8962_WRITE_SEQUENCER_245 0x10F5
+#define WM8962_WRITE_SEQUENCER_246 0x10F6
+#define WM8962_WRITE_SEQUENCER_247 0x10F7
+#define WM8962_WRITE_SEQUENCER_248 0x10F8
+#define WM8962_WRITE_SEQUENCER_249 0x10F9
+#define WM8962_WRITE_SEQUENCER_250 0x10FA
+#define WM8962_WRITE_SEQUENCER_251 0x10FB
+#define WM8962_WRITE_SEQUENCER_252 0x10FC
+#define WM8962_WRITE_SEQUENCER_253 0x10FD
+#define WM8962_WRITE_SEQUENCER_254 0x10FE
+#define WM8962_WRITE_SEQUENCER_255 0x10FF
+#define WM8962_WRITE_SEQUENCER_256 0x1100
+#define WM8962_WRITE_SEQUENCER_257 0x1101
+#define WM8962_WRITE_SEQUENCER_258 0x1102
+#define WM8962_WRITE_SEQUENCER_259 0x1103
+#define WM8962_WRITE_SEQUENCER_260 0x1104
+#define WM8962_WRITE_SEQUENCER_261 0x1105
+#define WM8962_WRITE_SEQUENCER_262 0x1106
+#define WM8962_WRITE_SEQUENCER_263 0x1107
+#define WM8962_WRITE_SEQUENCER_264 0x1108
+#define WM8962_WRITE_SEQUENCER_265 0x1109
+#define WM8962_WRITE_SEQUENCER_266 0x110A
+#define WM8962_WRITE_SEQUENCER_267 0x110B
+#define WM8962_WRITE_SEQUENCER_268 0x110C
+#define WM8962_WRITE_SEQUENCER_269 0x110D
+#define WM8962_WRITE_SEQUENCER_270 0x110E
+#define WM8962_WRITE_SEQUENCER_271 0x110F
+#define WM8962_WRITE_SEQUENCER_272 0x1110
+#define WM8962_WRITE_SEQUENCER_273 0x1111
+#define WM8962_WRITE_SEQUENCER_274 0x1112
+#define WM8962_WRITE_SEQUENCER_275 0x1113
+#define WM8962_WRITE_SEQUENCER_276 0x1114
+#define WM8962_WRITE_SEQUENCER_277 0x1115
+#define WM8962_WRITE_SEQUENCER_278 0x1116
+#define WM8962_WRITE_SEQUENCER_279 0x1117
+#define WM8962_WRITE_SEQUENCER_280 0x1118
+#define WM8962_WRITE_SEQUENCER_281 0x1119
+#define WM8962_WRITE_SEQUENCER_282 0x111A
+#define WM8962_WRITE_SEQUENCER_283 0x111B
+#define WM8962_WRITE_SEQUENCER_284 0x111C
+#define WM8962_WRITE_SEQUENCER_285 0x111D
+#define WM8962_WRITE_SEQUENCER_286 0x111E
+#define WM8962_WRITE_SEQUENCER_287 0x111F
+#define WM8962_WRITE_SEQUENCER_288 0x1120
+#define WM8962_WRITE_SEQUENCER_289 0x1121
+#define WM8962_WRITE_SEQUENCER_290 0x1122
+#define WM8962_WRITE_SEQUENCER_291 0x1123
+#define WM8962_WRITE_SEQUENCER_292 0x1124
+#define WM8962_WRITE_SEQUENCER_293 0x1125
+#define WM8962_WRITE_SEQUENCER_294 0x1126
+#define WM8962_WRITE_SEQUENCER_295 0x1127
+#define WM8962_WRITE_SEQUENCER_296 0x1128
+#define WM8962_WRITE_SEQUENCER_297 0x1129
+#define WM8962_WRITE_SEQUENCER_298 0x112A
+#define WM8962_WRITE_SEQUENCER_299 0x112B
+#define WM8962_WRITE_SEQUENCER_300 0x112C
+#define WM8962_WRITE_SEQUENCER_301 0x112D
+#define WM8962_WRITE_SEQUENCER_302 0x112E
+#define WM8962_WRITE_SEQUENCER_303 0x112F
+#define WM8962_WRITE_SEQUENCER_304 0x1130
+#define WM8962_WRITE_SEQUENCER_305 0x1131
+#define WM8962_WRITE_SEQUENCER_306 0x1132
+#define WM8962_WRITE_SEQUENCER_307 0x1133
+#define WM8962_WRITE_SEQUENCER_308 0x1134
+#define WM8962_WRITE_SEQUENCER_309 0x1135
+#define WM8962_WRITE_SEQUENCER_310 0x1136
+#define WM8962_WRITE_SEQUENCER_311 0x1137
+#define WM8962_WRITE_SEQUENCER_312 0x1138
+#define WM8962_WRITE_SEQUENCER_313 0x1139
+#define WM8962_WRITE_SEQUENCER_314 0x113A
+#define WM8962_WRITE_SEQUENCER_315 0x113B
+#define WM8962_WRITE_SEQUENCER_316 0x113C
+#define WM8962_WRITE_SEQUENCER_317 0x113D
+#define WM8962_WRITE_SEQUENCER_318 0x113E
+#define WM8962_WRITE_SEQUENCER_319 0x113F
+#define WM8962_WRITE_SEQUENCER_320 0x1140
+#define WM8962_WRITE_SEQUENCER_321 0x1141
+#define WM8962_WRITE_SEQUENCER_322 0x1142
+#define WM8962_WRITE_SEQUENCER_323 0x1143
+#define WM8962_WRITE_SEQUENCER_324 0x1144
+#define WM8962_WRITE_SEQUENCER_325 0x1145
+#define WM8962_WRITE_SEQUENCER_326 0x1146
+#define WM8962_WRITE_SEQUENCER_327 0x1147
+#define WM8962_WRITE_SEQUENCER_328 0x1148
+#define WM8962_WRITE_SEQUENCER_329 0x1149
+#define WM8962_WRITE_SEQUENCER_330 0x114A
+#define WM8962_WRITE_SEQUENCER_331 0x114B
+#define WM8962_WRITE_SEQUENCER_332 0x114C
+#define WM8962_WRITE_SEQUENCER_333 0x114D
+#define WM8962_WRITE_SEQUENCER_334 0x114E
+#define WM8962_WRITE_SEQUENCER_335 0x114F
+#define WM8962_WRITE_SEQUENCER_336 0x1150
+#define WM8962_WRITE_SEQUENCER_337 0x1151
+#define WM8962_WRITE_SEQUENCER_338 0x1152
+#define WM8962_WRITE_SEQUENCER_339 0x1153
+#define WM8962_WRITE_SEQUENCER_340 0x1154
+#define WM8962_WRITE_SEQUENCER_341 0x1155
+#define WM8962_WRITE_SEQUENCER_342 0x1156
+#define WM8962_WRITE_SEQUENCER_343 0x1157
+#define WM8962_WRITE_SEQUENCER_344 0x1158
+#define WM8962_WRITE_SEQUENCER_345 0x1159
+#define WM8962_WRITE_SEQUENCER_346 0x115A
+#define WM8962_WRITE_SEQUENCER_347 0x115B
+#define WM8962_WRITE_SEQUENCER_348 0x115C
+#define WM8962_WRITE_SEQUENCER_349 0x115D
+#define WM8962_WRITE_SEQUENCER_350 0x115E
+#define WM8962_WRITE_SEQUENCER_351 0x115F
+#define WM8962_WRITE_SEQUENCER_352 0x1160
+#define WM8962_WRITE_SEQUENCER_353 0x1161
+#define WM8962_WRITE_SEQUENCER_354 0x1162
+#define WM8962_WRITE_SEQUENCER_355 0x1163
+#define WM8962_WRITE_SEQUENCER_356 0x1164
+#define WM8962_WRITE_SEQUENCER_357 0x1165
+#define WM8962_WRITE_SEQUENCER_358 0x1166
+#define WM8962_WRITE_SEQUENCER_359 0x1167
+#define WM8962_WRITE_SEQUENCER_360 0x1168
+#define WM8962_WRITE_SEQUENCER_361 0x1169
+#define WM8962_WRITE_SEQUENCER_362 0x116A
+#define WM8962_WRITE_SEQUENCER_363 0x116B
+#define WM8962_WRITE_SEQUENCER_364 0x116C
+#define WM8962_WRITE_SEQUENCER_365 0x116D
+#define WM8962_WRITE_SEQUENCER_366 0x116E
+#define WM8962_WRITE_SEQUENCER_367 0x116F
+#define WM8962_WRITE_SEQUENCER_368 0x1170
+#define WM8962_WRITE_SEQUENCER_369 0x1171
+#define WM8962_WRITE_SEQUENCER_370 0x1172
+#define WM8962_WRITE_SEQUENCER_371 0x1173
+#define WM8962_WRITE_SEQUENCER_372 0x1174
+#define WM8962_WRITE_SEQUENCER_373 0x1175
+#define WM8962_WRITE_SEQUENCER_374 0x1176
+#define WM8962_WRITE_SEQUENCER_375 0x1177
+#define WM8962_WRITE_SEQUENCER_376 0x1178
+#define WM8962_WRITE_SEQUENCER_377 0x1179
+#define WM8962_WRITE_SEQUENCER_378 0x117A
+#define WM8962_WRITE_SEQUENCER_379 0x117B
+#define WM8962_WRITE_SEQUENCER_380 0x117C
+#define WM8962_WRITE_SEQUENCER_381 0x117D
+#define WM8962_WRITE_SEQUENCER_382 0x117E
+#define WM8962_WRITE_SEQUENCER_383 0x117F
+#define WM8962_WRITE_SEQUENCER_384 0x1180
+#define WM8962_WRITE_SEQUENCER_385 0x1181
+#define WM8962_WRITE_SEQUENCER_386 0x1182
+#define WM8962_WRITE_SEQUENCER_387 0x1183
+#define WM8962_WRITE_SEQUENCER_388 0x1184
+#define WM8962_WRITE_SEQUENCER_389 0x1185
+#define WM8962_WRITE_SEQUENCER_390 0x1186
+#define WM8962_WRITE_SEQUENCER_391 0x1187
+#define WM8962_WRITE_SEQUENCER_392 0x1188
+#define WM8962_WRITE_SEQUENCER_393 0x1189
+#define WM8962_WRITE_SEQUENCER_394 0x118A
+#define WM8962_WRITE_SEQUENCER_395 0x118B
+#define WM8962_WRITE_SEQUENCER_396 0x118C
+#define WM8962_WRITE_SEQUENCER_397 0x118D
+#define WM8962_WRITE_SEQUENCER_398 0x118E
+#define WM8962_WRITE_SEQUENCER_399 0x118F
+#define WM8962_WRITE_SEQUENCER_400 0x1190
+#define WM8962_WRITE_SEQUENCER_401 0x1191
+#define WM8962_WRITE_SEQUENCER_402 0x1192
+#define WM8962_WRITE_SEQUENCER_403 0x1193
+#define WM8962_WRITE_SEQUENCER_404 0x1194
+#define WM8962_WRITE_SEQUENCER_405 0x1195
+#define WM8962_WRITE_SEQUENCER_406 0x1196
+#define WM8962_WRITE_SEQUENCER_407 0x1197
+#define WM8962_WRITE_SEQUENCER_408 0x1198
+#define WM8962_WRITE_SEQUENCER_409 0x1199
+#define WM8962_WRITE_SEQUENCER_410 0x119A
+#define WM8962_WRITE_SEQUENCER_411 0x119B
+#define WM8962_WRITE_SEQUENCER_412 0x119C
+#define WM8962_WRITE_SEQUENCER_413 0x119D
+#define WM8962_WRITE_SEQUENCER_414 0x119E
+#define WM8962_WRITE_SEQUENCER_415 0x119F
+#define WM8962_WRITE_SEQUENCER_416 0x11A0
+#define WM8962_WRITE_SEQUENCER_417 0x11A1
+#define WM8962_WRITE_SEQUENCER_418 0x11A2
+#define WM8962_WRITE_SEQUENCER_419 0x11A3
+#define WM8962_WRITE_SEQUENCER_420 0x11A4
+#define WM8962_WRITE_SEQUENCER_421 0x11A5
+#define WM8962_WRITE_SEQUENCER_422 0x11A6
+#define WM8962_WRITE_SEQUENCER_423 0x11A7
+#define WM8962_WRITE_SEQUENCER_424 0x11A8
+#define WM8962_WRITE_SEQUENCER_425 0x11A9
+#define WM8962_WRITE_SEQUENCER_426 0x11AA
+#define WM8962_WRITE_SEQUENCER_427 0x11AB
+#define WM8962_WRITE_SEQUENCER_428 0x11AC
+#define WM8962_WRITE_SEQUENCER_429 0x11AD
+#define WM8962_WRITE_SEQUENCER_430 0x11AE
+#define WM8962_WRITE_SEQUENCER_431 0x11AF
+#define WM8962_WRITE_SEQUENCER_432 0x11B0
+#define WM8962_WRITE_SEQUENCER_433 0x11B1
+#define WM8962_WRITE_SEQUENCER_434 0x11B2
+#define WM8962_WRITE_SEQUENCER_435 0x11B3
+#define WM8962_WRITE_SEQUENCER_436 0x11B4
+#define WM8962_WRITE_SEQUENCER_437 0x11B5
+#define WM8962_WRITE_SEQUENCER_438 0x11B6
+#define WM8962_WRITE_SEQUENCER_439 0x11B7
+#define WM8962_WRITE_SEQUENCER_440 0x11B8
+#define WM8962_WRITE_SEQUENCER_441 0x11B9
+#define WM8962_WRITE_SEQUENCER_442 0x11BA
+#define WM8962_WRITE_SEQUENCER_443 0x11BB
+#define WM8962_WRITE_SEQUENCER_444 0x11BC
+#define WM8962_WRITE_SEQUENCER_445 0x11BD
+#define WM8962_WRITE_SEQUENCER_446 0x11BE
+#define WM8962_WRITE_SEQUENCER_447 0x11BF
+#define WM8962_WRITE_SEQUENCER_448 0x11C0
+#define WM8962_WRITE_SEQUENCER_449 0x11C1
+#define WM8962_WRITE_SEQUENCER_450 0x11C2
+#define WM8962_WRITE_SEQUENCER_451 0x11C3
+#define WM8962_WRITE_SEQUENCER_452 0x11C4
+#define WM8962_WRITE_SEQUENCER_453 0x11C5
+#define WM8962_WRITE_SEQUENCER_454 0x11C6
+#define WM8962_WRITE_SEQUENCER_455 0x11C7
+#define WM8962_WRITE_SEQUENCER_456 0x11C8
+#define WM8962_WRITE_SEQUENCER_457 0x11C9
+#define WM8962_WRITE_SEQUENCER_458 0x11CA
+#define WM8962_WRITE_SEQUENCER_459 0x11CB
+#define WM8962_WRITE_SEQUENCER_460 0x11CC
+#define WM8962_WRITE_SEQUENCER_461 0x11CD
+#define WM8962_WRITE_SEQUENCER_462 0x11CE
+#define WM8962_WRITE_SEQUENCER_463 0x11CF
+#define WM8962_WRITE_SEQUENCER_464 0x11D0
+#define WM8962_WRITE_SEQUENCER_465 0x11D1
+#define WM8962_WRITE_SEQUENCER_466 0x11D2
+#define WM8962_WRITE_SEQUENCER_467 0x11D3
+#define WM8962_WRITE_SEQUENCER_468 0x11D4
+#define WM8962_WRITE_SEQUENCER_469 0x11D5
+#define WM8962_WRITE_SEQUENCER_470 0x11D6
+#define WM8962_WRITE_SEQUENCER_471 0x11D7
+#define WM8962_WRITE_SEQUENCER_472 0x11D8
+#define WM8962_WRITE_SEQUENCER_473 0x11D9
+#define WM8962_WRITE_SEQUENCER_474 0x11DA
+#define WM8962_WRITE_SEQUENCER_475 0x11DB
+#define WM8962_WRITE_SEQUENCER_476 0x11DC
+#define WM8962_WRITE_SEQUENCER_477 0x11DD
+#define WM8962_WRITE_SEQUENCER_478 0x11DE
+#define WM8962_WRITE_SEQUENCER_479 0x11DF
+#define WM8962_WRITE_SEQUENCER_480 0x11E0
+#define WM8962_WRITE_SEQUENCER_481 0x11E1
+#define WM8962_WRITE_SEQUENCER_482 0x11E2
+#define WM8962_WRITE_SEQUENCER_483 0x11E3
+#define WM8962_WRITE_SEQUENCER_484 0x11E4
+#define WM8962_WRITE_SEQUENCER_485 0x11E5
+#define WM8962_WRITE_SEQUENCER_486 0x11E6
+#define WM8962_WRITE_SEQUENCER_487 0x11E7
+#define WM8962_WRITE_SEQUENCER_488 0x11E8
+#define WM8962_WRITE_SEQUENCER_489 0x11E9
+#define WM8962_WRITE_SEQUENCER_490 0x11EA
+#define WM8962_WRITE_SEQUENCER_491 0x11EB
+#define WM8962_WRITE_SEQUENCER_492 0x11EC
+#define WM8962_WRITE_SEQUENCER_493 0x11ED
+#define WM8962_WRITE_SEQUENCER_494 0x11EE
+#define WM8962_WRITE_SEQUENCER_495 0x11EF
+#define WM8962_WRITE_SEQUENCER_496 0x11F0
+#define WM8962_WRITE_SEQUENCER_497 0x11F1
+#define WM8962_WRITE_SEQUENCER_498 0x11F2
+#define WM8962_WRITE_SEQUENCER_499 0x11F3
+#define WM8962_WRITE_SEQUENCER_500 0x11F4
+#define WM8962_WRITE_SEQUENCER_501 0x11F5
+#define WM8962_WRITE_SEQUENCER_502 0x11F6
+#define WM8962_WRITE_SEQUENCER_503 0x11F7
+#define WM8962_WRITE_SEQUENCER_504 0x11F8
+#define WM8962_WRITE_SEQUENCER_505 0x11F9
+#define WM8962_WRITE_SEQUENCER_506 0x11FA
+#define WM8962_WRITE_SEQUENCER_507 0x11FB
+#define WM8962_WRITE_SEQUENCER_508 0x11FC
+#define WM8962_WRITE_SEQUENCER_509 0x11FD
+#define WM8962_WRITE_SEQUENCER_510 0x11FE
+#define WM8962_WRITE_SEQUENCER_511 0x11FF
+#define WM8962_DSP2_INSTRUCTION_RAM_0 0x2000
+#define WM8962_DSP2_ADDRESS_RAM_2 0x2400
+#define WM8962_DSP2_ADDRESS_RAM_1 0x2401
+#define WM8962_DSP2_ADDRESS_RAM_0 0x2402
+#define WM8962_DSP2_DATA1_RAM_1 0x3000
+#define WM8962_DSP2_DATA1_RAM_0 0x3001
+#define WM8962_DSP2_DATA2_RAM_1 0x3400
+#define WM8962_DSP2_DATA2_RAM_0 0x3401
+#define WM8962_DSP2_DATA3_RAM_1 0x3800
+#define WM8962_DSP2_DATA3_RAM_0 0x3801
+#define WM8962_DSP2_COEFF_RAM_0 0x3C00
+#define WM8962_RETUNEADC_SHARED_COEFF_1 0x4000
+#define WM8962_RETUNEADC_SHARED_COEFF_0 0x4001
+#define WM8962_RETUNEDAC_SHARED_COEFF_1 0x4002
+#define WM8962_RETUNEDAC_SHARED_COEFF_0 0x4003
+#define WM8962_SOUNDSTAGE_ENABLES_1 0x4004
+#define WM8962_SOUNDSTAGE_ENABLES_0 0x4005
+#define WM8962_HDBASS_AI_1 0x4200
+#define WM8962_HDBASS_AI_0 0x4201
+#define WM8962_HDBASS_AR_1 0x4202
+#define WM8962_HDBASS_AR_0 0x4203
+#define WM8962_HDBASS_B_1 0x4204
+#define WM8962_HDBASS_B_0 0x4205
+#define WM8962_HDBASS_K_1 0x4206
+#define WM8962_HDBASS_K_0 0x4207
+#define WM8962_HDBASS_N1_1 0x4208
+#define WM8962_HDBASS_N1_0 0x4209
+#define WM8962_HDBASS_N2_1 0x420A
+#define WM8962_HDBASS_N2_0 0x420B
+#define WM8962_HDBASS_N3_1 0x420C
+#define WM8962_HDBASS_N3_0 0x420D
+#define WM8962_HDBASS_N4_1 0x420E
+#define WM8962_HDBASS_N4_0 0x420F
+#define WM8962_HDBASS_N5_1 0x4210
+#define WM8962_HDBASS_N5_0 0x4211
+#define WM8962_HDBASS_X1_1 0x4212
+#define WM8962_HDBASS_X1_0 0x4213
+#define WM8962_HDBASS_X2_1 0x4214
+#define WM8962_HDBASS_X2_0 0x4215
+#define WM8962_HDBASS_X3_1 0x4216
+#define WM8962_HDBASS_X3_0 0x4217
+#define WM8962_HDBASS_ATK_1 0x4218
+#define WM8962_HDBASS_ATK_0 0x4219
+#define WM8962_HDBASS_DCY_1 0x421A
+#define WM8962_HDBASS_DCY_0 0x421B
+#define WM8962_HDBASS_PG_1 0x421C
+#define WM8962_HDBASS_PG_0 0x421D
+#define WM8962_HPF_C_1 0x4400
+#define WM8962_HPF_C_0 0x4401
+#define WM8962_ADCL_RETUNE_C1_1 0x4600
+#define WM8962_ADCL_RETUNE_C1_0 0x4601
+#define WM8962_ADCL_RETUNE_C2_1 0x4602
+#define WM8962_ADCL_RETUNE_C2_0 0x4603
+#define WM8962_ADCL_RETUNE_C3_1 0x4604
+#define WM8962_ADCL_RETUNE_C3_0 0x4605
+#define WM8962_ADCL_RETUNE_C4_1 0x4606
+#define WM8962_ADCL_RETUNE_C4_0 0x4607
+#define WM8962_ADCL_RETUNE_C5_1 0x4608
+#define WM8962_ADCL_RETUNE_C5_0 0x4609
+#define WM8962_ADCL_RETUNE_C6_1 0x460A
+#define WM8962_ADCL_RETUNE_C6_0 0x460B
+#define WM8962_ADCL_RETUNE_C7_1 0x460C
+#define WM8962_ADCL_RETUNE_C7_0 0x460D
+#define WM8962_ADCL_RETUNE_C8_1 0x460E
+#define WM8962_ADCL_RETUNE_C8_0 0x460F
+#define WM8962_ADCL_RETUNE_C9_1 0x4610
+#define WM8962_ADCL_RETUNE_C9_0 0x4611
+#define WM8962_ADCL_RETUNE_C10_1 0x4612
+#define WM8962_ADCL_RETUNE_C10_0 0x4613
+#define WM8962_ADCL_RETUNE_C11_1 0x4614
+#define WM8962_ADCL_RETUNE_C11_0 0x4615
+#define WM8962_ADCL_RETUNE_C12_1 0x4616
+#define WM8962_ADCL_RETUNE_C12_0 0x4617
+#define WM8962_ADCL_RETUNE_C13_1 0x4618
+#define WM8962_ADCL_RETUNE_C13_0 0x4619
+#define WM8962_ADCL_RETUNE_C14_1 0x461A
+#define WM8962_ADCL_RETUNE_C14_0 0x461B
+#define WM8962_ADCL_RETUNE_C15_1 0x461C
+#define WM8962_ADCL_RETUNE_C15_0 0x461D
+#define WM8962_ADCL_RETUNE_C16_1 0x461E
+#define WM8962_ADCL_RETUNE_C16_0 0x461F
+#define WM8962_ADCL_RETUNE_C17_1 0x4620
+#define WM8962_ADCL_RETUNE_C17_0 0x4621
+#define WM8962_ADCL_RETUNE_C18_1 0x4622
+#define WM8962_ADCL_RETUNE_C18_0 0x4623
+#define WM8962_ADCL_RETUNE_C19_1 0x4624
+#define WM8962_ADCL_RETUNE_C19_0 0x4625
+#define WM8962_ADCL_RETUNE_C20_1 0x4626
+#define WM8962_ADCL_RETUNE_C20_0 0x4627
+#define WM8962_ADCL_RETUNE_C21_1 0x4628
+#define WM8962_ADCL_RETUNE_C21_0 0x4629
+#define WM8962_ADCL_RETUNE_C22_1 0x462A
+#define WM8962_ADCL_RETUNE_C22_0 0x462B
+#define WM8962_ADCL_RETUNE_C23_1 0x462C
+#define WM8962_ADCL_RETUNE_C23_0 0x462D
+#define WM8962_ADCL_RETUNE_C24_1 0x462E
+#define WM8962_ADCL_RETUNE_C24_0 0x462F
+#define WM8962_ADCL_RETUNE_C25_1 0x4630
+#define WM8962_ADCL_RETUNE_C25_0 0x4631
+#define WM8962_ADCL_RETUNE_C26_1 0x4632
+#define WM8962_ADCL_RETUNE_C26_0 0x4633
+#define WM8962_ADCL_RETUNE_C27_1 0x4634
+#define WM8962_ADCL_RETUNE_C27_0 0x4635
+#define WM8962_ADCL_RETUNE_C28_1 0x4636
+#define WM8962_ADCL_RETUNE_C28_0 0x4637
+#define WM8962_ADCL_RETUNE_C29_1 0x4638
+#define WM8962_ADCL_RETUNE_C29_0 0x4639
+#define WM8962_ADCL_RETUNE_C30_1 0x463A
+#define WM8962_ADCL_RETUNE_C30_0 0x463B
+#define WM8962_ADCL_RETUNE_C31_1 0x463C
+#define WM8962_ADCL_RETUNE_C31_0 0x463D
+#define WM8962_ADCL_RETUNE_C32_1 0x463E
+#define WM8962_ADCL_RETUNE_C32_0 0x463F
+#define WM8962_RETUNEADC_PG2_1 0x4800
+#define WM8962_RETUNEADC_PG2_0 0x4801
+#define WM8962_RETUNEADC_PG_1 0x4802
+#define WM8962_RETUNEADC_PG_0 0x4803
+#define WM8962_ADCR_RETUNE_C1_1 0x4A00
+#define WM8962_ADCR_RETUNE_C1_0 0x4A01
+#define WM8962_ADCR_RETUNE_C2_1 0x4A02
+#define WM8962_ADCR_RETUNE_C2_0 0x4A03
+#define WM8962_ADCR_RETUNE_C3_1 0x4A04
+#define WM8962_ADCR_RETUNE_C3_0 0x4A05
+#define WM8962_ADCR_RETUNE_C4_1 0x4A06
+#define WM8962_ADCR_RETUNE_C4_0 0x4A07
+#define WM8962_ADCR_RETUNE_C5_1 0x4A08
+#define WM8962_ADCR_RETUNE_C5_0 0x4A09
+#define WM8962_ADCR_RETUNE_C6_1 0x4A0A
+#define WM8962_ADCR_RETUNE_C6_0 0x4A0B
+#define WM8962_ADCR_RETUNE_C7_1 0x4A0C
+#define WM8962_ADCR_RETUNE_C7_0 0x4A0D
+#define WM8962_ADCR_RETUNE_C8_1 0x4A0E
+#define WM8962_ADCR_RETUNE_C8_0 0x4A0F
+#define WM8962_ADCR_RETUNE_C9_1 0x4A10
+#define WM8962_ADCR_RETUNE_C9_0 0x4A11
+#define WM8962_ADCR_RETUNE_C10_1 0x4A12
+#define WM8962_ADCR_RETUNE_C10_0 0x4A13
+#define WM8962_ADCR_RETUNE_C11_1 0x4A14
+#define WM8962_ADCR_RETUNE_C11_0 0x4A15
+#define WM8962_ADCR_RETUNE_C12_1 0x4A16
+#define WM8962_ADCR_RETUNE_C12_0 0x4A17
+#define WM8962_ADCR_RETUNE_C13_1 0x4A18
+#define WM8962_ADCR_RETUNE_C13_0 0x4A19
+#define WM8962_ADCR_RETUNE_C14_1 0x4A1A
+#define WM8962_ADCR_RETUNE_C14_0 0x4A1B
+#define WM8962_ADCR_RETUNE_C15_1 0x4A1C
+#define WM8962_ADCR_RETUNE_C15_0 0x4A1D
+#define WM8962_ADCR_RETUNE_C16_1 0x4A1E
+#define WM8962_ADCR_RETUNE_C16_0 0x4A1F
+#define WM8962_ADCR_RETUNE_C17_1 0x4A20
+#define WM8962_ADCR_RETUNE_C17_0 0x4A21
+#define WM8962_ADCR_RETUNE_C18_1 0x4A22
+#define WM8962_ADCR_RETUNE_C18_0 0x4A23
+#define WM8962_ADCR_RETUNE_C19_1 0x4A24
+#define WM8962_ADCR_RETUNE_C19_0 0x4A25
+#define WM8962_ADCR_RETUNE_C20_1 0x4A26
+#define WM8962_ADCR_RETUNE_C20_0 0x4A27
+#define WM8962_ADCR_RETUNE_C21_1 0x4A28
+#define WM8962_ADCR_RETUNE_C21_0 0x4A29
+#define WM8962_ADCR_RETUNE_C22_1 0x4A2A
+#define WM8962_ADCR_RETUNE_C22_0 0x4A2B
+#define WM8962_ADCR_RETUNE_C23_1 0x4A2C
+#define WM8962_ADCR_RETUNE_C23_0 0x4A2D
+#define WM8962_ADCR_RETUNE_C24_1 0x4A2E
+#define WM8962_ADCR_RETUNE_C24_0 0x4A2F
+#define WM8962_ADCR_RETUNE_C25_1 0x4A30
+#define WM8962_ADCR_RETUNE_C25_0 0x4A31
+#define WM8962_ADCR_RETUNE_C26_1 0x4A32
+#define WM8962_ADCR_RETUNE_C26_0 0x4A33
+#define WM8962_ADCR_RETUNE_C27_1 0x4A34
+#define WM8962_ADCR_RETUNE_C27_0 0x4A35
+#define WM8962_ADCR_RETUNE_C28_1 0x4A36
+#define WM8962_ADCR_RETUNE_C28_0 0x4A37
+#define WM8962_ADCR_RETUNE_C29_1 0x4A38
+#define WM8962_ADCR_RETUNE_C29_0 0x4A39
+#define WM8962_ADCR_RETUNE_C30_1 0x4A3A
+#define WM8962_ADCR_RETUNE_C30_0 0x4A3B
+#define WM8962_ADCR_RETUNE_C31_1 0x4A3C
+#define WM8962_ADCR_RETUNE_C31_0 0x4A3D
+#define WM8962_ADCR_RETUNE_C32_1 0x4A3E
+#define WM8962_ADCR_RETUNE_C32_0 0x4A3F
+#define WM8962_DACL_RETUNE_C1_1 0x4C00
+#define WM8962_DACL_RETUNE_C1_0 0x4C01
+#define WM8962_DACL_RETUNE_C2_1 0x4C02
+#define WM8962_DACL_RETUNE_C2_0 0x4C03
+#define WM8962_DACL_RETUNE_C3_1 0x4C04
+#define WM8962_DACL_RETUNE_C3_0 0x4C05
+#define WM8962_DACL_RETUNE_C4_1 0x4C06
+#define WM8962_DACL_RETUNE_C4_0 0x4C07
+#define WM8962_DACL_RETUNE_C5_1 0x4C08
+#define WM8962_DACL_RETUNE_C5_0 0x4C09
+#define WM8962_DACL_RETUNE_C6_1 0x4C0A
+#define WM8962_DACL_RETUNE_C6_0 0x4C0B
+#define WM8962_DACL_RETUNE_C7_1 0x4C0C
+#define WM8962_DACL_RETUNE_C7_0 0x4C0D
+#define WM8962_DACL_RETUNE_C8_1 0x4C0E
+#define WM8962_DACL_RETUNE_C8_0 0x4C0F
+#define WM8962_DACL_RETUNE_C9_1 0x4C10
+#define WM8962_DACL_RETUNE_C9_0 0x4C11
+#define WM8962_DACL_RETUNE_C10_1 0x4C12
+#define WM8962_DACL_RETUNE_C10_0 0x4C13
+#define WM8962_DACL_RETUNE_C11_1 0x4C14
+#define WM8962_DACL_RETUNE_C11_0 0x4C15
+#define WM8962_DACL_RETUNE_C12_1 0x4C16
+#define WM8962_DACL_RETUNE_C12_0 0x4C17
+#define WM8962_DACL_RETUNE_C13_1 0x4C18
+#define WM8962_DACL_RETUNE_C13_0 0x4C19
+#define WM8962_DACL_RETUNE_C14_1 0x4C1A
+#define WM8962_DACL_RETUNE_C14_0 0x4C1B
+#define WM8962_DACL_RETUNE_C15_1 0x4C1C
+#define WM8962_DACL_RETUNE_C15_0 0x4C1D
+#define WM8962_DACL_RETUNE_C16_1 0x4C1E
+#define WM8962_DACL_RETUNE_C16_0 0x4C1F
+#define WM8962_DACL_RETUNE_C17_1 0x4C20
+#define WM8962_DACL_RETUNE_C17_0 0x4C21
+#define WM8962_DACL_RETUNE_C18_1 0x4C22
+#define WM8962_DACL_RETUNE_C18_0 0x4C23
+#define WM8962_DACL_RETUNE_C19_1 0x4C24
+#define WM8962_DACL_RETUNE_C19_0 0x4C25
+#define WM8962_DACL_RETUNE_C20_1 0x4C26
+#define WM8962_DACL_RETUNE_C20_0 0x4C27
+#define WM8962_DACL_RETUNE_C21_1 0x4C28
+#define WM8962_DACL_RETUNE_C21_0 0x4C29
+#define WM8962_DACL_RETUNE_C22_1 0x4C2A
+#define WM8962_DACL_RETUNE_C22_0 0x4C2B
+#define WM8962_DACL_RETUNE_C23_1 0x4C2C
+#define WM8962_DACL_RETUNE_C23_0 0x4C2D
+#define WM8962_DACL_RETUNE_C24_1 0x4C2E
+#define WM8962_DACL_RETUNE_C24_0 0x4C2F
+#define WM8962_DACL_RETUNE_C25_1 0x4C30
+#define WM8962_DACL_RETUNE_C25_0 0x4C31
+#define WM8962_DACL_RETUNE_C26_1 0x4C32
+#define WM8962_DACL_RETUNE_C26_0 0x4C33
+#define WM8962_DACL_RETUNE_C27_1 0x4C34
+#define WM8962_DACL_RETUNE_C27_0 0x4C35
+#define WM8962_DACL_RETUNE_C28_1 0x4C36
+#define WM8962_DACL_RETUNE_C28_0 0x4C37
+#define WM8962_DACL_RETUNE_C29_1 0x4C38
+#define WM8962_DACL_RETUNE_C29_0 0x4C39
+#define WM8962_DACL_RETUNE_C30_1 0x4C3A
+#define WM8962_DACL_RETUNE_C30_0 0x4C3B
+#define WM8962_DACL_RETUNE_C31_1 0x4C3C
+#define WM8962_DACL_RETUNE_C31_0 0x4C3D
+#define WM8962_DACL_RETUNE_C32_1 0x4C3E
+#define WM8962_DACL_RETUNE_C32_0 0x4C3F
+#define WM8962_RETUNEDAC_PG2_1 0x4E00
+#define WM8962_RETUNEDAC_PG2_0 0x4E01
+#define WM8962_RETUNEDAC_PG_1 0x4E02
+#define WM8962_RETUNEDAC_PG_0 0x4E03
+#define WM8962_DACR_RETUNE_C1_1 0x5000
+#define WM8962_DACR_RETUNE_C1_0 0x5001
+#define WM8962_DACR_RETUNE_C2_1 0x5002
+#define WM8962_DACR_RETUNE_C2_0 0x5003
+#define WM8962_DACR_RETUNE_C3_1 0x5004
+#define WM8962_DACR_RETUNE_C3_0 0x5005
+#define WM8962_DACR_RETUNE_C4_1 0x5006
+#define WM8962_DACR_RETUNE_C4_0 0x5007
+#define WM8962_DACR_RETUNE_C5_1 0x5008
+#define WM8962_DACR_RETUNE_C5_0 0x5009
+#define WM8962_DACR_RETUNE_C6_1 0x500A
+#define WM8962_DACR_RETUNE_C6_0 0x500B
+#define WM8962_DACR_RETUNE_C7_1 0x500C
+#define WM8962_DACR_RETUNE_C7_0 0x500D
+#define WM8962_DACR_RETUNE_C8_1 0x500E
+#define WM8962_DACR_RETUNE_C8_0 0x500F
+#define WM8962_DACR_RETUNE_C9_1 0x5010
+#define WM8962_DACR_RETUNE_C9_0 0x5011
+#define WM8962_DACR_RETUNE_C10_1 0x5012
+#define WM8962_DACR_RETUNE_C10_0 0x5013
+#define WM8962_DACR_RETUNE_C11_1 0x5014
+#define WM8962_DACR_RETUNE_C11_0 0x5015
+#define WM8962_DACR_RETUNE_C12_1 0x5016
+#define WM8962_DACR_RETUNE_C12_0 0x5017
+#define WM8962_DACR_RETUNE_C13_1 0x5018
+#define WM8962_DACR_RETUNE_C13_0 0x5019
+#define WM8962_DACR_RETUNE_C14_1 0x501A
+#define WM8962_DACR_RETUNE_C14_0 0x501B
+#define WM8962_DACR_RETUNE_C15_1 0x501C
+#define WM8962_DACR_RETUNE_C15_0 0x501D
+#define WM8962_DACR_RETUNE_C16_1 0x501E
+#define WM8962_DACR_RETUNE_C16_0 0x501F
+#define WM8962_DACR_RETUNE_C17_1 0x5020
+#define WM8962_DACR_RETUNE_C17_0 0x5021
+#define WM8962_DACR_RETUNE_C18_1 0x5022
+#define WM8962_DACR_RETUNE_C18_0 0x5023
+#define WM8962_DACR_RETUNE_C19_1 0x5024
+#define WM8962_DACR_RETUNE_C19_0 0x5025
+#define WM8962_DACR_RETUNE_C20_1 0x5026
+#define WM8962_DACR_RETUNE_C20_0 0x5027
+#define WM8962_DACR_RETUNE_C21_1 0x5028
+#define WM8962_DACR_RETUNE_C21_0 0x5029
+#define WM8962_DACR_RETUNE_C22_1 0x502A
+#define WM8962_DACR_RETUNE_C22_0 0x502B
+#define WM8962_DACR_RETUNE_C23_1 0x502C
+#define WM8962_DACR_RETUNE_C23_0 0x502D
+#define WM8962_DACR_RETUNE_C24_1 0x502E
+#define WM8962_DACR_RETUNE_C24_0 0x502F
+#define WM8962_DACR_RETUNE_C25_1 0x5030
+#define WM8962_DACR_RETUNE_C25_0 0x5031
+#define WM8962_DACR_RETUNE_C26_1 0x5032
+#define WM8962_DACR_RETUNE_C26_0 0x5033
+#define WM8962_DACR_RETUNE_C27_1 0x5034
+#define WM8962_DACR_RETUNE_C27_0 0x5035
+#define WM8962_DACR_RETUNE_C28_1 0x5036
+#define WM8962_DACR_RETUNE_C28_0 0x5037
+#define WM8962_DACR_RETUNE_C29_1 0x5038
+#define WM8962_DACR_RETUNE_C29_0 0x5039
+#define WM8962_DACR_RETUNE_C30_1 0x503A
+#define WM8962_DACR_RETUNE_C30_0 0x503B
+#define WM8962_DACR_RETUNE_C31_1 0x503C
+#define WM8962_DACR_RETUNE_C31_0 0x503D
+#define WM8962_DACR_RETUNE_C32_1 0x503E
+#define WM8962_DACR_RETUNE_C32_0 0x503F
+#define WM8962_VSS_XHD2_1 0x5200
+#define WM8962_VSS_XHD2_0 0x5201
+#define WM8962_VSS_XHD3_1 0x5202
+#define WM8962_VSS_XHD3_0 0x5203
+#define WM8962_VSS_XHN1_1 0x5204
+#define WM8962_VSS_XHN1_0 0x5205
+#define WM8962_VSS_XHN2_1 0x5206
+#define WM8962_VSS_XHN2_0 0x5207
+#define WM8962_VSS_XHN3_1 0x5208
+#define WM8962_VSS_XHN3_0 0x5209
+#define WM8962_VSS_XLA_1 0x520A
+#define WM8962_VSS_XLA_0 0x520B
+#define WM8962_VSS_XLB_1 0x520C
+#define WM8962_VSS_XLB_0 0x520D
+#define WM8962_VSS_XLG_1 0x520E
+#define WM8962_VSS_XLG_0 0x520F
+#define WM8962_VSS_PG2_1 0x5210
+#define WM8962_VSS_PG2_0 0x5211
+#define WM8962_VSS_PG_1 0x5212
+#define WM8962_VSS_PG_0 0x5213
+#define WM8962_VSS_XTD1_1 0x5214
+#define WM8962_VSS_XTD1_0 0x5215
+#define WM8962_VSS_XTD2_1 0x5216
+#define WM8962_VSS_XTD2_0 0x5217
+#define WM8962_VSS_XTD3_1 0x5218
+#define WM8962_VSS_XTD3_0 0x5219
+#define WM8962_VSS_XTD4_1 0x521A
+#define WM8962_VSS_XTD4_0 0x521B
+#define WM8962_VSS_XTD5_1 0x521C
+#define WM8962_VSS_XTD5_0 0x521D
+#define WM8962_VSS_XTD6_1 0x521E
+#define WM8962_VSS_XTD6_0 0x521F
+#define WM8962_VSS_XTD7_1 0x5220
+#define WM8962_VSS_XTD7_0 0x5221
+#define WM8962_VSS_XTD8_1 0x5222
+#define WM8962_VSS_XTD8_0 0x5223
+#define WM8962_VSS_XTD9_1 0x5224
+#define WM8962_VSS_XTD9_0 0x5225
+#define WM8962_VSS_XTD10_1 0x5226
+#define WM8962_VSS_XTD10_0 0x5227
+#define WM8962_VSS_XTD11_1 0x5228
+#define WM8962_VSS_XTD11_0 0x5229
+#define WM8962_VSS_XTD12_1 0x522A
+#define WM8962_VSS_XTD12_0 0x522B
+#define WM8962_VSS_XTD13_1 0x522C
+#define WM8962_VSS_XTD13_0 0x522D
+#define WM8962_VSS_XTD14_1 0x522E
+#define WM8962_VSS_XTD14_0 0x522F
+#define WM8962_VSS_XTD15_1 0x5230
+#define WM8962_VSS_XTD15_0 0x5231
+#define WM8962_VSS_XTD16_1 0x5232
+#define WM8962_VSS_XTD16_0 0x5233
+#define WM8962_VSS_XTD17_1 0x5234
+#define WM8962_VSS_XTD17_0 0x5235
+#define WM8962_VSS_XTD18_1 0x5236
+#define WM8962_VSS_XTD18_0 0x5237
+#define WM8962_VSS_XTD19_1 0x5238
+#define WM8962_VSS_XTD19_0 0x5239
+#define WM8962_VSS_XTD20_1 0x523A
+#define WM8962_VSS_XTD20_0 0x523B
+#define WM8962_VSS_XTD21_1 0x523C
+#define WM8962_VSS_XTD21_0 0x523D
+#define WM8962_VSS_XTD22_1 0x523E
+#define WM8962_VSS_XTD22_0 0x523F
+#define WM8962_VSS_XTD23_1 0x5240
+#define WM8962_VSS_XTD23_0 0x5241
+#define WM8962_VSS_XTD24_1 0x5242
+#define WM8962_VSS_XTD24_0 0x5243
+#define WM8962_VSS_XTD25_1 0x5244
+#define WM8962_VSS_XTD25_0 0x5245
+#define WM8962_VSS_XTD26_1 0x5246
+#define WM8962_VSS_XTD26_0 0x5247
+#define WM8962_VSS_XTD27_1 0x5248
+#define WM8962_VSS_XTD27_0 0x5249
+#define WM8962_VSS_XTD28_1 0x524A
+#define WM8962_VSS_XTD28_0 0x524B
+#define WM8962_VSS_XTD29_1 0x524C
+#define WM8962_VSS_XTD29_0 0x524D
+#define WM8962_VSS_XTD30_1 0x524E
+#define WM8962_VSS_XTD30_0 0x524F
+#define WM8962_VSS_XTD31_1 0x5250
+#define WM8962_VSS_XTD31_0 0x5251
+#define WM8962_VSS_XTD32_1 0x5252
+#define WM8962_VSS_XTD32_0 0x5253
+#define WM8962_VSS_XTS1_1 0x5254
+#define WM8962_VSS_XTS1_0 0x5255
+#define WM8962_VSS_XTS2_1 0x5256
+#define WM8962_VSS_XTS2_0 0x5257
+#define WM8962_VSS_XTS3_1 0x5258
+#define WM8962_VSS_XTS3_0 0x5259
+#define WM8962_VSS_XTS4_1 0x525A
+#define WM8962_VSS_XTS4_0 0x525B
+#define WM8962_VSS_XTS5_1 0x525C
+#define WM8962_VSS_XTS5_0 0x525D
+#define WM8962_VSS_XTS6_1 0x525E
+#define WM8962_VSS_XTS6_0 0x525F
+#define WM8962_VSS_XTS7_1 0x5260
+#define WM8962_VSS_XTS7_0 0x5261
+#define WM8962_VSS_XTS8_1 0x5262
+#define WM8962_VSS_XTS8_0 0x5263
+#define WM8962_VSS_XTS9_1 0x5264
+#define WM8962_VSS_XTS9_0 0x5265
+#define WM8962_VSS_XTS10_1 0x5266
+#define WM8962_VSS_XTS10_0 0x5267
+#define WM8962_VSS_XTS11_1 0x5268
+#define WM8962_VSS_XTS11_0 0x5269
+#define WM8962_VSS_XTS12_1 0x526A
+#define WM8962_VSS_XTS12_0 0x526B
+#define WM8962_VSS_XTS13_1 0x526C
+#define WM8962_VSS_XTS13_0 0x526D
+#define WM8962_VSS_XTS14_1 0x526E
+#define WM8962_VSS_XTS14_0 0x526F
+#define WM8962_VSS_XTS15_1 0x5270
+#define WM8962_VSS_XTS15_0 0x5271
+#define WM8962_VSS_XTS16_1 0x5272
+#define WM8962_VSS_XTS16_0 0x5273
+#define WM8962_VSS_XTS17_1 0x5274
+#define WM8962_VSS_XTS17_0 0x5275
+#define WM8962_VSS_XTS18_1 0x5276
+#define WM8962_VSS_XTS18_0 0x5277
+#define WM8962_VSS_XTS19_1 0x5278
+#define WM8962_VSS_XTS19_0 0x5279
+#define WM8962_VSS_XTS20_1 0x527A
+#define WM8962_VSS_XTS20_0 0x527B
+#define WM8962_VSS_XTS21_1 0x527C
+#define WM8962_VSS_XTS21_0 0x527D
+#define WM8962_VSS_XTS22_1 0x527E
+#define WM8962_VSS_XTS22_0 0x527F
+#define WM8962_VSS_XTS23_1 0x5280
+#define WM8962_VSS_XTS23_0 0x5281
+#define WM8962_VSS_XTS24_1 0x5282
+#define WM8962_VSS_XTS24_0 0x5283
+#define WM8962_VSS_XTS25_1 0x5284
+#define WM8962_VSS_XTS25_0 0x5285
+#define WM8962_VSS_XTS26_1 0x5286
+#define WM8962_VSS_XTS26_0 0x5287
+#define WM8962_VSS_XTS27_1 0x5288
+#define WM8962_VSS_XTS27_0 0x5289
+#define WM8962_VSS_XTS28_1 0x528A
+#define WM8962_VSS_XTS28_0 0x528B
+#define WM8962_VSS_XTS29_1 0x528C
+#define WM8962_VSS_XTS29_0 0x528D
+#define WM8962_VSS_XTS30_1 0x528E
+#define WM8962_VSS_XTS30_0 0x528F
+#define WM8962_VSS_XTS31_1 0x5290
+#define WM8962_VSS_XTS31_0 0x5291
+#define WM8962_VSS_XTS32_1 0x5292
+#define WM8962_VSS_XTS32_0 0x5293
+
+#define WM8962_REGISTER_COUNT 1138
+#define WM8962_MAX_REGISTER 0x5293
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Left Input volume
+ */
+#define WM8962_IN_VU 0x0100 /* IN_VU */
+#define WM8962_IN_VU_MASK 0x0100 /* IN_VU */
+#define WM8962_IN_VU_SHIFT 8 /* IN_VU */
+#define WM8962_IN_VU_WIDTH 1 /* IN_VU */
+#define WM8962_INPGAL_MUTE 0x0080 /* INPGAL_MUTE */
+#define WM8962_INPGAL_MUTE_MASK 0x0080 /* INPGAL_MUTE */
+#define WM8962_INPGAL_MUTE_SHIFT 7 /* INPGAL_MUTE */
+#define WM8962_INPGAL_MUTE_WIDTH 1 /* INPGAL_MUTE */
+#define WM8962_INL_ZC 0x0040 /* INL_ZC */
+#define WM8962_INL_ZC_MASK 0x0040 /* INL_ZC */
+#define WM8962_INL_ZC_SHIFT 6 /* INL_ZC */
+#define WM8962_INL_ZC_WIDTH 1 /* INL_ZC */
+#define WM8962_INL_VOL_MASK 0x003F /* INL_VOL - [5:0] */
+#define WM8962_INL_VOL_SHIFT 0 /* INL_VOL - [5:0] */
+#define WM8962_INL_VOL_WIDTH 6 /* INL_VOL - [5:0] */
+
+/*
+ * R1 (0x01) - Right Input volume
+ */
+#define WM8962_CUST_ID_MASK 0xF000 /* CUST_ID - [15:12] */
+#define WM8962_CUST_ID_SHIFT 12 /* CUST_ID - [15:12] */
+#define WM8962_CUST_ID_WIDTH 4 /* CUST_ID - [15:12] */
+#define WM8962_CHIP_REV_MASK 0x0E00 /* CHIP_REV - [11:9] */
+#define WM8962_CHIP_REV_SHIFT 9 /* CHIP_REV - [11:9] */
+#define WM8962_CHIP_REV_WIDTH 3 /* CHIP_REV - [11:9] */
+#define WM8962_IN_VU 0x0100 /* IN_VU */
+#define WM8962_IN_VU_MASK 0x0100 /* IN_VU */
+#define WM8962_IN_VU_SHIFT 8 /* IN_VU */
+#define WM8962_IN_VU_WIDTH 1 /* IN_VU */
+#define WM8962_INPGAR_MUTE 0x0080 /* INPGAR_MUTE */
+#define WM8962_INPGAR_MUTE_MASK 0x0080 /* INPGAR_MUTE */
+#define WM8962_INPGAR_MUTE_SHIFT 7 /* INPGAR_MUTE */
+#define WM8962_INPGAR_MUTE_WIDTH 1 /* INPGAR_MUTE */
+#define WM8962_INR_ZC 0x0040 /* INR_ZC */
+#define WM8962_INR_ZC_MASK 0x0040 /* INR_ZC */
+#define WM8962_INR_ZC_SHIFT 6 /* INR_ZC */
+#define WM8962_INR_ZC_WIDTH 1 /* INR_ZC */
+#define WM8962_INR_VOL_MASK 0x003F /* INR_VOL - [5:0] */
+#define WM8962_INR_VOL_SHIFT 0 /* INR_VOL - [5:0] */
+#define WM8962_INR_VOL_WIDTH 6 /* INR_VOL - [5:0] */
+
+/*
+ * R2 (0x02) - HPOUTL volume
+ */
+#define WM8962_HPOUT_VU 0x0100 /* HPOUT_VU */
+#define WM8962_HPOUT_VU_MASK 0x0100 /* HPOUT_VU */
+#define WM8962_HPOUT_VU_SHIFT 8 /* HPOUT_VU */
+#define WM8962_HPOUT_VU_WIDTH 1 /* HPOUT_VU */
+#define WM8962_HPOUTL_ZC 0x0080 /* HPOUTL_ZC */
+#define WM8962_HPOUTL_ZC_MASK 0x0080 /* HPOUTL_ZC */
+#define WM8962_HPOUTL_ZC_SHIFT 7 /* HPOUTL_ZC */
+#define WM8962_HPOUTL_ZC_WIDTH 1 /* HPOUTL_ZC */
+#define WM8962_HPOUTL_VOL_MASK 0x007F /* HPOUTL_VOL - [6:0] */
+#define WM8962_HPOUTL_VOL_SHIFT 0 /* HPOUTL_VOL - [6:0] */
+#define WM8962_HPOUTL_VOL_WIDTH 7 /* HPOUTL_VOL - [6:0] */
+
+/*
+ * R3 (0x03) - HPOUTR volume
+ */
+#define WM8962_HPOUT_VU 0x0100 /* HPOUT_VU */
+#define WM8962_HPOUT_VU_MASK 0x0100 /* HPOUT_VU */
+#define WM8962_HPOUT_VU_SHIFT 8 /* HPOUT_VU */
+#define WM8962_HPOUT_VU_WIDTH 1 /* HPOUT_VU */
+#define WM8962_HPOUTR_ZC 0x0080 /* HPOUTR_ZC */
+#define WM8962_HPOUTR_ZC_MASK 0x0080 /* HPOUTR_ZC */
+#define WM8962_HPOUTR_ZC_SHIFT 7 /* HPOUTR_ZC */
+#define WM8962_HPOUTR_ZC_WIDTH 1 /* HPOUTR_ZC */
+#define WM8962_HPOUTR_VOL_MASK 0x007F /* HPOUTR_VOL - [6:0] */
+#define WM8962_HPOUTR_VOL_SHIFT 0 /* HPOUTR_VOL - [6:0] */
+#define WM8962_HPOUTR_VOL_WIDTH 7 /* HPOUTR_VOL - [6:0] */
+
+/*
+ * R4 (0x04) - Clocking1
+ */
+#define WM8962_DSPCLK_DIV_MASK 0x0600 /* DSPCLK_DIV - [10:9] */
+#define WM8962_DSPCLK_DIV_SHIFT 9 /* DSPCLK_DIV - [10:9] */
+#define WM8962_DSPCLK_DIV_WIDTH 2 /* DSPCLK_DIV - [10:9] */
+#define WM8962_ADCSYS_CLK_DIV_MASK 0x01C0 /* ADCSYS_CLK_DIV - [8:6] */
+#define WM8962_ADCSYS_CLK_DIV_SHIFT 6 /* ADCSYS_CLK_DIV - [8:6] */
+#define WM8962_ADCSYS_CLK_DIV_WIDTH 3 /* ADCSYS_CLK_DIV - [8:6] */
+#define WM8962_DACSYS_CLK_DIV_MASK 0x0038 /* DACSYS_CLK_DIV - [5:3] */
+#define WM8962_DACSYS_CLK_DIV_SHIFT 3 /* DACSYS_CLK_DIV - [5:3] */
+#define WM8962_DACSYS_CLK_DIV_WIDTH 3 /* DACSYS_CLK_DIV - [5:3] */
+#define WM8962_MCLKDIV_MASK 0x0006 /* MCLKDIV - [2:1] */
+#define WM8962_MCLKDIV_SHIFT 1 /* MCLKDIV - [2:1] */
+#define WM8962_MCLKDIV_WIDTH 2 /* MCLKDIV - [2:1] */
+
+/*
+ * R5 (0x05) - ADC & DAC Control 1
+ */
+#define WM8962_ADCR_DAT_INV 0x0040 /* ADCR_DAT_INV */
+#define WM8962_ADCR_DAT_INV_MASK 0x0040 /* ADCR_DAT_INV */
+#define WM8962_ADCR_DAT_INV_SHIFT 6 /* ADCR_DAT_INV */
+#define WM8962_ADCR_DAT_INV_WIDTH 1 /* ADCR_DAT_INV */
+#define WM8962_ADCL_DAT_INV 0x0020 /* ADCL_DAT_INV */
+#define WM8962_ADCL_DAT_INV_MASK 0x0020 /* ADCL_DAT_INV */
+#define WM8962_ADCL_DAT_INV_SHIFT 5 /* ADCL_DAT_INV */
+#define WM8962_ADCL_DAT_INV_WIDTH 1 /* ADCL_DAT_INV */
+#define WM8962_DAC_MUTE_RAMP 0x0010 /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE_RAMP_MASK 0x0010 /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE_RAMP_SHIFT 4 /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE_RAMP_WIDTH 1 /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE 0x0008 /* DAC_MUTE */
+#define WM8962_DAC_MUTE_MASK 0x0008 /* DAC_MUTE */
+#define WM8962_DAC_MUTE_SHIFT 3 /* DAC_MUTE */
+#define WM8962_DAC_MUTE_WIDTH 1 /* DAC_MUTE */
+#define WM8962_DAC_DEEMP_MASK 0x0006 /* DAC_DEEMP - [2:1] */
+#define WM8962_DAC_DEEMP_SHIFT 1 /* DAC_DEEMP - [2:1] */
+#define WM8962_DAC_DEEMP_WIDTH 2 /* DAC_DEEMP - [2:1] */
+#define WM8962_ADC_HPF_DIS 0x0001 /* ADC_HPF_DIS */
+#define WM8962_ADC_HPF_DIS_MASK 0x0001 /* ADC_HPF_DIS */
+#define WM8962_ADC_HPF_DIS_SHIFT 0 /* ADC_HPF_DIS */
+#define WM8962_ADC_HPF_DIS_WIDTH 1 /* ADC_HPF_DIS */
+
+/*
+ * R6 (0x06) - ADC & DAC Control 2
+ */
+#define WM8962_ADC_HPF_SR_MASK 0x3000 /* ADC_HPF_SR - [13:12] */
+#define WM8962_ADC_HPF_SR_SHIFT 12 /* ADC_HPF_SR - [13:12] */
+#define WM8962_ADC_HPF_SR_WIDTH 2 /* ADC_HPF_SR - [13:12] */
+#define WM8962_ADC_HPF_MODE 0x0400 /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_MODE_MASK 0x0400 /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_MODE_SHIFT 10 /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_MODE_WIDTH 1 /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_CUT_MASK 0x0380 /* ADC_HPF_CUT - [9:7] */
+#define WM8962_ADC_HPF_CUT_SHIFT 7 /* ADC_HPF_CUT - [9:7] */
+#define WM8962_ADC_HPF_CUT_WIDTH 3 /* ADC_HPF_CUT - [9:7] */
+#define WM8962_DACR_DAT_INV 0x0040 /* DACR_DAT_INV */
+#define WM8962_DACR_DAT_INV_MASK 0x0040 /* DACR_DAT_INV */
+#define WM8962_DACR_DAT_INV_SHIFT 6 /* DACR_DAT_INV */
+#define WM8962_DACR_DAT_INV_WIDTH 1 /* DACR_DAT_INV */
+#define WM8962_DACL_DAT_INV 0x0020 /* DACL_DAT_INV */
+#define WM8962_DACL_DAT_INV_MASK 0x0020 /* DACL_DAT_INV */
+#define WM8962_DACL_DAT_INV_SHIFT 5 /* DACL_DAT_INV */
+#define WM8962_DACL_DAT_INV_WIDTH 1 /* DACL_DAT_INV */
+#define WM8962_DAC_UNMUTE_RAMP 0x0008 /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_UNMUTE_RAMP_MASK 0x0008 /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_UNMUTE_RAMP_SHIFT 3 /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_UNMUTE_RAMP_WIDTH 1 /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_MUTERATE 0x0004 /* DAC_MUTERATE */
+#define WM8962_DAC_MUTERATE_MASK 0x0004 /* DAC_MUTERATE */
+#define WM8962_DAC_MUTERATE_SHIFT 2 /* DAC_MUTERATE */
+#define WM8962_DAC_MUTERATE_WIDTH 1 /* DAC_MUTERATE */
+#define WM8962_DAC_HP 0x0001 /* DAC_HP */
+#define WM8962_DAC_HP_MASK 0x0001 /* DAC_HP */
+#define WM8962_DAC_HP_SHIFT 0 /* DAC_HP */
+#define WM8962_DAC_HP_WIDTH 1 /* DAC_HP */
+
+/*
+ * R7 (0x07) - Audio Interface 0
+ */
+#define WM8962_AIFDAC_TDM_MODE 0x1000 /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_MODE_MASK 0x1000 /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_MODE_SHIFT 12 /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_MODE_WIDTH 1 /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_SLOT 0x0800 /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFDAC_TDM_SLOT_MASK 0x0800 /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFDAC_TDM_SLOT_SHIFT 11 /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFDAC_TDM_SLOT_WIDTH 1 /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_MODE 0x0400 /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_MODE_MASK 0x0400 /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_MODE_SHIFT 10 /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_MODE_WIDTH 1 /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_SLOT 0x0200 /* AIFADC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_SLOT_MASK 0x0200 /* AIFADC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_SLOT_SHIFT 9 /* AIFADC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_SLOT_WIDTH 1 /* AIFADC_TDM_SLOT */
+#define WM8962_ADC_LRSWAP 0x0100 /* ADC_LRSWAP */
+#define WM8962_ADC_LRSWAP_MASK 0x0100 /* ADC_LRSWAP */
+#define WM8962_ADC_LRSWAP_SHIFT 8 /* ADC_LRSWAP */
+#define WM8962_ADC_LRSWAP_WIDTH 1 /* ADC_LRSWAP */
+#define WM8962_BCLK_INV 0x0080 /* BCLK_INV */
+#define WM8962_BCLK_INV_MASK 0x0080 /* BCLK_INV */
+#define WM8962_BCLK_INV_SHIFT 7 /* BCLK_INV */
+#define WM8962_BCLK_INV_WIDTH 1 /* BCLK_INV */
+#define WM8962_MSTR 0x0040 /* MSTR */
+#define WM8962_MSTR_MASK 0x0040 /* MSTR */
+#define WM8962_MSTR_SHIFT 6 /* MSTR */
+#define WM8962_MSTR_WIDTH 1 /* MSTR */
+#define WM8962_DAC_LRSWAP 0x0020 /* DAC_LRSWAP */
+#define WM8962_DAC_LRSWAP_MASK 0x0020 /* DAC_LRSWAP */
+#define WM8962_DAC_LRSWAP_SHIFT 5 /* DAC_LRSWAP */
+#define WM8962_DAC_LRSWAP_WIDTH 1 /* DAC_LRSWAP */
+#define WM8962_LRCLK_INV 0x0010 /* LRCLK_INV */
+#define WM8962_LRCLK_INV_MASK 0x0010 /* LRCLK_INV */
+#define WM8962_LRCLK_INV_SHIFT 4 /* LRCLK_INV */
+#define WM8962_LRCLK_INV_WIDTH 1 /* LRCLK_INV */
+#define WM8962_WL_MASK 0x000C /* WL - [3:2] */
+#define WM8962_WL_SHIFT 2 /* WL - [3:2] */
+#define WM8962_WL_WIDTH 2 /* WL - [3:2] */
+#define WM8962_FMT_MASK 0x0003 /* FMT - [1:0] */
+#define WM8962_FMT_SHIFT 0 /* FMT - [1:0] */
+#define WM8962_FMT_WIDTH 2 /* FMT - [1:0] */
+
+/*
+ * R8 (0x08) - Clocking2
+ */
+#define WM8962_CLKREG_OVD 0x0800 /* CLKREG_OVD */
+#define WM8962_CLKREG_OVD_MASK 0x0800 /* CLKREG_OVD */
+#define WM8962_CLKREG_OVD_SHIFT 11 /* CLKREG_OVD */
+#define WM8962_CLKREG_OVD_WIDTH 1 /* CLKREG_OVD */
+#define WM8962_SYSCLK_SRC_MASK 0x0600 /* SYSCLK_SRC - [10:9] */
+#define WM8962_SYSCLK_SRC_SHIFT 9 /* SYSCLK_SRC - [10:9] */
+#define WM8962_SYSCLK_SRC_WIDTH 2 /* SYSCLK_SRC - [10:9] */
+#define WM8962_CLASSD_CLK_DIV_MASK 0x01C0 /* CLASSD_CLK_DIV - [8:6] */
+#define WM8962_CLASSD_CLK_DIV_SHIFT 6 /* CLASSD_CLK_DIV - [8:6] */
+#define WM8962_CLASSD_CLK_DIV_WIDTH 3 /* CLASSD_CLK_DIV - [8:6] */
+#define WM8962_SYSCLK_ENA 0x0020 /* SYSCLK_ENA */
+#define WM8962_SYSCLK_ENA_MASK 0x0020 /* SYSCLK_ENA */
+#define WM8962_SYSCLK_ENA_SHIFT 5 /* SYSCLK_ENA */
+#define WM8962_SYSCLK_ENA_WIDTH 1 /* SYSCLK_ENA */
+#define WM8962_BCLK_DIV_MASK 0x000F /* BCLK_DIV - [3:0] */
+#define WM8962_BCLK_DIV_SHIFT 0 /* BCLK_DIV - [3:0] */
+#define WM8962_BCLK_DIV_WIDTH 4 /* BCLK_DIV - [3:0] */
+
+/*
+ * R9 (0x09) - Audio Interface 1
+ */
+#define WM8962_AUTOMUTE_STS 0x0800 /* AUTOMUTE_STS */
+#define WM8962_AUTOMUTE_STS_MASK 0x0800 /* AUTOMUTE_STS */
+#define WM8962_AUTOMUTE_STS_SHIFT 11 /* AUTOMUTE_STS */
+#define WM8962_AUTOMUTE_STS_WIDTH 1 /* AUTOMUTE_STS */
+#define WM8962_DAC_AUTOMUTE_SAMPLES_MASK 0x0300 /* DAC_AUTOMUTE_SAMPLES - [9:8] */
+#define WM8962_DAC_AUTOMUTE_SAMPLES_SHIFT 8 /* DAC_AUTOMUTE_SAMPLES - [9:8] */
+#define WM8962_DAC_AUTOMUTE_SAMPLES_WIDTH 2 /* DAC_AUTOMUTE_SAMPLES - [9:8] */
+#define WM8962_DAC_AUTOMUTE 0x0080 /* DAC_AUTOMUTE */
+#define WM8962_DAC_AUTOMUTE_MASK 0x0080 /* DAC_AUTOMUTE */
+#define WM8962_DAC_AUTOMUTE_SHIFT 7 /* DAC_AUTOMUTE */
+#define WM8962_DAC_AUTOMUTE_WIDTH 1 /* DAC_AUTOMUTE */
+#define WM8962_DAC_COMP 0x0010 /* DAC_COMP */
+#define WM8962_DAC_COMP_MASK 0x0010 /* DAC_COMP */
+#define WM8962_DAC_COMP_SHIFT 4 /* DAC_COMP */
+#define WM8962_DAC_COMP_WIDTH 1 /* DAC_COMP */
+#define WM8962_DAC_COMPMODE 0x0008 /* DAC_COMPMODE */
+#define WM8962_DAC_COMPMODE_MASK 0x0008 /* DAC_COMPMODE */
+#define WM8962_DAC_COMPMODE_SHIFT 3 /* DAC_COMPMODE */
+#define WM8962_DAC_COMPMODE_WIDTH 1 /* DAC_COMPMODE */
+#define WM8962_ADC_COMP 0x0004 /* ADC_COMP */
+#define WM8962_ADC_COMP_MASK 0x0004 /* ADC_COMP */
+#define WM8962_ADC_COMP_SHIFT 2 /* ADC_COMP */
+#define WM8962_ADC_COMP_WIDTH 1 /* ADC_COMP */
+#define WM8962_ADC_COMPMODE 0x0002 /* ADC_COMPMODE */
+#define WM8962_ADC_COMPMODE_MASK 0x0002 /* ADC_COMPMODE */
+#define WM8962_ADC_COMPMODE_SHIFT 1 /* ADC_COMPMODE */
+#define WM8962_ADC_COMPMODE_WIDTH 1 /* ADC_COMPMODE */
+#define WM8962_LOOPBACK 0x0001 /* LOOPBACK */
+#define WM8962_LOOPBACK_MASK 0x0001 /* LOOPBACK */
+#define WM8962_LOOPBACK_SHIFT 0 /* LOOPBACK */
+#define WM8962_LOOPBACK_WIDTH 1 /* LOOPBACK */
+
+/*
+ * R10 (0x0A) - Left DAC volume
+ */
+#define WM8962_DAC_VU 0x0100 /* DAC_VU */
+#define WM8962_DAC_VU_MASK 0x0100 /* DAC_VU */
+#define WM8962_DAC_VU_SHIFT 8 /* DAC_VU */
+#define WM8962_DAC_VU_WIDTH 1 /* DAC_VU */
+#define WM8962_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */
+#define WM8962_DACL_VOL_SHIFT 0 /* DACL_VOL - [7:0] */
+#define WM8962_DACL_VOL_WIDTH 8 /* DACL_VOL - [7:0] */
+
+/*
+ * R11 (0x0B) - Right DAC volume
+ */
+#define WM8962_DAC_VU 0x0100 /* DAC_VU */
+#define WM8962_DAC_VU_MASK 0x0100 /* DAC_VU */
+#define WM8962_DAC_VU_SHIFT 8 /* DAC_VU */
+#define WM8962_DAC_VU_WIDTH 1 /* DAC_VU */
+#define WM8962_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */
+#define WM8962_DACR_VOL_SHIFT 0 /* DACR_VOL - [7:0] */
+#define WM8962_DACR_VOL_WIDTH 8 /* DACR_VOL - [7:0] */
+
+/*
+ * R14 (0x0E) - Audio Interface 2
+ */
+#define WM8962_AIF_RATE_MASK 0x07FF /* AIF_RATE - [10:0] */
+#define WM8962_AIF_RATE_SHIFT 0 /* AIF_RATE - [10:0] */
+#define WM8962_AIF_RATE_WIDTH 11 /* AIF_RATE - [10:0] */
+
+/*
+ * R15 (0x0F) - Software Reset
+ */
+#define WM8962_SW_RESET_MASK 0xFFFF /* SW_RESET - [15:0] */
+#define WM8962_SW_RESET_SHIFT 0 /* SW_RESET - [15:0] */
+#define WM8962_SW_RESET_WIDTH 16 /* SW_RESET - [15:0] */
+
+/*
+ * R17 (0x11) - ALC1
+ */
+#define WM8962_ALC_INACTIVE_ENA 0x0400 /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_INACTIVE_ENA_MASK 0x0400 /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_INACTIVE_ENA_SHIFT 10 /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_INACTIVE_ENA_WIDTH 1 /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_LVL_MODE 0x0200 /* ALC_LVL_MODE */
+#define WM8962_ALC_LVL_MODE_MASK 0x0200 /* ALC_LVL_MODE */
+#define WM8962_ALC_LVL_MODE_SHIFT 9 /* ALC_LVL_MODE */
+#define WM8962_ALC_LVL_MODE_WIDTH 1 /* ALC_LVL_MODE */
+#define WM8962_ALCL_ENA 0x0100 /* ALCL_ENA */
+#define WM8962_ALCL_ENA_MASK 0x0100 /* ALCL_ENA */
+#define WM8962_ALCL_ENA_SHIFT 8 /* ALCL_ENA */
+#define WM8962_ALCL_ENA_WIDTH 1 /* ALCL_ENA */
+#define WM8962_ALCR_ENA 0x0080 /* ALCR_ENA */
+#define WM8962_ALCR_ENA_MASK 0x0080 /* ALCR_ENA */
+#define WM8962_ALCR_ENA_SHIFT 7 /* ALCR_ENA */
+#define WM8962_ALCR_ENA_WIDTH 1 /* ALCR_ENA */
+#define WM8962_ALC_MAXGAIN_MASK 0x0070 /* ALC_MAXGAIN - [6:4] */
+#define WM8962_ALC_MAXGAIN_SHIFT 4 /* ALC_MAXGAIN - [6:4] */
+#define WM8962_ALC_MAXGAIN_WIDTH 3 /* ALC_MAXGAIN - [6:4] */
+#define WM8962_ALC_LVL_MASK 0x000F /* ALC_LVL - [3:0] */
+#define WM8962_ALC_LVL_SHIFT 0 /* ALC_LVL - [3:0] */
+#define WM8962_ALC_LVL_WIDTH 4 /* ALC_LVL - [3:0] */
+
+/*
+ * R18 (0x12) - ALC2
+ */
+#define WM8962_ALC_LOCK_STS 0x8000 /* ALC_LOCK_STS */
+#define WM8962_ALC_LOCK_STS_MASK 0x8000 /* ALC_LOCK_STS */
+#define WM8962_ALC_LOCK_STS_SHIFT 15 /* ALC_LOCK_STS */
+#define WM8962_ALC_LOCK_STS_WIDTH 1 /* ALC_LOCK_STS */
+#define WM8962_ALC_THRESH_STS 0x4000 /* ALC_THRESH_STS */
+#define WM8962_ALC_THRESH_STS_MASK 0x4000 /* ALC_THRESH_STS */
+#define WM8962_ALC_THRESH_STS_SHIFT 14 /* ALC_THRESH_STS */
+#define WM8962_ALC_THRESH_STS_WIDTH 1 /* ALC_THRESH_STS */
+#define WM8962_ALC_SAT_STS 0x2000 /* ALC_SAT_STS */
+#define WM8962_ALC_SAT_STS_MASK 0x2000 /* ALC_SAT_STS */
+#define WM8962_ALC_SAT_STS_SHIFT 13 /* ALC_SAT_STS */
+#define WM8962_ALC_SAT_STS_WIDTH 1 /* ALC_SAT_STS */
+#define WM8962_ALC_PKOVR_STS 0x1000 /* ALC_PKOVR_STS */
+#define WM8962_ALC_PKOVR_STS_MASK 0x1000 /* ALC_PKOVR_STS */
+#define WM8962_ALC_PKOVR_STS_SHIFT 12 /* ALC_PKOVR_STS */
+#define WM8962_ALC_PKOVR_STS_WIDTH 1 /* ALC_PKOVR_STS */
+#define WM8962_ALC_NGATE_STS 0x0800 /* ALC_NGATE_STS */
+#define WM8962_ALC_NGATE_STS_MASK 0x0800 /* ALC_NGATE_STS */
+#define WM8962_ALC_NGATE_STS_SHIFT 11 /* ALC_NGATE_STS */
+#define WM8962_ALC_NGATE_STS_WIDTH 1 /* ALC_NGATE_STS */
+#define WM8962_ALC_ZC 0x0080 /* ALC_ZC */
+#define WM8962_ALC_ZC_MASK 0x0080 /* ALC_ZC */
+#define WM8962_ALC_ZC_SHIFT 7 /* ALC_ZC */
+#define WM8962_ALC_ZC_WIDTH 1 /* ALC_ZC */
+#define WM8962_ALC_MINGAIN_MASK 0x0070 /* ALC_MINGAIN - [6:4] */
+#define WM8962_ALC_MINGAIN_SHIFT 4 /* ALC_MINGAIN - [6:4] */
+#define WM8962_ALC_MINGAIN_WIDTH 3 /* ALC_MINGAIN - [6:4] */
+#define WM8962_ALC_HLD_MASK 0x000F /* ALC_HLD - [3:0] */
+#define WM8962_ALC_HLD_SHIFT 0 /* ALC_HLD - [3:0] */
+#define WM8962_ALC_HLD_WIDTH 4 /* ALC_HLD - [3:0] */
+
+/*
+ * R19 (0x13) - ALC3
+ */
+#define WM8962_ALC_NGATE_GAIN_MASK 0x1C00 /* ALC_NGATE_GAIN - [12:10] */
+#define WM8962_ALC_NGATE_GAIN_SHIFT 10 /* ALC_NGATE_GAIN - [12:10] */
+#define WM8962_ALC_NGATE_GAIN_WIDTH 3 /* ALC_NGATE_GAIN - [12:10] */
+#define WM8962_ALC_MODE 0x0100 /* ALC_MODE */
+#define WM8962_ALC_MODE_MASK 0x0100 /* ALC_MODE */
+#define WM8962_ALC_MODE_SHIFT 8 /* ALC_MODE */
+#define WM8962_ALC_MODE_WIDTH 1 /* ALC_MODE */
+#define WM8962_ALC_DCY_MASK 0x00F0 /* ALC_DCY - [7:4] */
+#define WM8962_ALC_DCY_SHIFT 4 /* ALC_DCY - [7:4] */
+#define WM8962_ALC_DCY_WIDTH 4 /* ALC_DCY - [7:4] */
+#define WM8962_ALC_ATK_MASK 0x000F /* ALC_ATK - [3:0] */
+#define WM8962_ALC_ATK_SHIFT 0 /* ALC_ATK - [3:0] */
+#define WM8962_ALC_ATK_WIDTH 4 /* ALC_ATK - [3:0] */
+
+/*
+ * R20 (0x14) - Noise Gate
+ */
+#define WM8962_ALC_NGATE_DCY_MASK 0xF000 /* ALC_NGATE_DCY - [15:12] */
+#define WM8962_ALC_NGATE_DCY_SHIFT 12 /* ALC_NGATE_DCY - [15:12] */
+#define WM8962_ALC_NGATE_DCY_WIDTH 4 /* ALC_NGATE_DCY - [15:12] */
+#define WM8962_ALC_NGATE_ATK_MASK 0x0F00 /* ALC_NGATE_ATK - [11:8] */
+#define WM8962_ALC_NGATE_ATK_SHIFT 8 /* ALC_NGATE_ATK - [11:8] */
+#define WM8962_ALC_NGATE_ATK_WIDTH 4 /* ALC_NGATE_ATK - [11:8] */
+#define WM8962_ALC_NGATE_THR_MASK 0x00F8 /* ALC_NGATE_THR - [7:3] */
+#define WM8962_ALC_NGATE_THR_SHIFT 3 /* ALC_NGATE_THR - [7:3] */
+#define WM8962_ALC_NGATE_THR_WIDTH 5 /* ALC_NGATE_THR - [7:3] */
+#define WM8962_ALC_NGATE_MODE_MASK 0x0006 /* ALC_NGATE_MODE - [2:1] */
+#define WM8962_ALC_NGATE_MODE_SHIFT 1 /* ALC_NGATE_MODE - [2:1] */
+#define WM8962_ALC_NGATE_MODE_WIDTH 2 /* ALC_NGATE_MODE - [2:1] */
+#define WM8962_ALC_NGATE_ENA 0x0001 /* ALC_NGATE_ENA */
+#define WM8962_ALC_NGATE_ENA_MASK 0x0001 /* ALC_NGATE_ENA */
+#define WM8962_ALC_NGATE_ENA_SHIFT 0 /* ALC_NGATE_ENA */
+#define WM8962_ALC_NGATE_ENA_WIDTH 1 /* ALC_NGATE_ENA */
+
+/*
+ * R21 (0x15) - Left ADC volume
+ */
+#define WM8962_ADC_VU 0x0100 /* ADC_VU */
+#define WM8962_ADC_VU_MASK 0x0100 /* ADC_VU */
+#define WM8962_ADC_VU_SHIFT 8 /* ADC_VU */
+#define WM8962_ADC_VU_WIDTH 1 /* ADC_VU */
+#define WM8962_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */
+#define WM8962_ADCL_VOL_SHIFT 0 /* ADCL_VOL - [7:0] */
+#define WM8962_ADCL_VOL_WIDTH 8 /* ADCL_VOL - [7:0] */
+
+/*
+ * R22 (0x16) - Right ADC volume
+ */
+#define WM8962_ADC_VU 0x0100 /* ADC_VU */
+#define WM8962_ADC_VU_MASK 0x0100 /* ADC_VU */
+#define WM8962_ADC_VU_SHIFT 8 /* ADC_VU */
+#define WM8962_ADC_VU_WIDTH 1 /* ADC_VU */
+#define WM8962_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */
+#define WM8962_ADCR_VOL_SHIFT 0 /* ADCR_VOL - [7:0] */
+#define WM8962_ADCR_VOL_WIDTH 8 /* ADCR_VOL - [7:0] */
+
+/*
+ * R23 (0x17) - Additional control(1)
+ */
+#define WM8962_THERR_ACT 0x0100 /* THERR_ACT */
+#define WM8962_THERR_ACT_MASK 0x0100 /* THERR_ACT */
+#define WM8962_THERR_ACT_SHIFT 8 /* THERR_ACT */
+#define WM8962_THERR_ACT_WIDTH 1 /* THERR_ACT */
+#define WM8962_ADC_BIAS 0x0040 /* ADC_BIAS */
+#define WM8962_ADC_BIAS_MASK 0x0040 /* ADC_BIAS */
+#define WM8962_ADC_BIAS_SHIFT 6 /* ADC_BIAS */
+#define WM8962_ADC_BIAS_WIDTH 1 /* ADC_BIAS */
+#define WM8962_ADC_HP 0x0020 /* ADC_HP */
+#define WM8962_ADC_HP_MASK 0x0020 /* ADC_HP */
+#define WM8962_ADC_HP_SHIFT 5 /* ADC_HP */
+#define WM8962_ADC_HP_WIDTH 1 /* ADC_HP */
+#define WM8962_TOCLK_ENA 0x0001 /* TOCLK_ENA */
+#define WM8962_TOCLK_ENA_MASK 0x0001 /* TOCLK_ENA */
+#define WM8962_TOCLK_ENA_SHIFT 0 /* TOCLK_ENA */
+#define WM8962_TOCLK_ENA_WIDTH 1 /* TOCLK_ENA */
+
+/*
+ * R24 (0x18) - Additional control(2)
+ */
+#define WM8962_AIF_TRI 0x0008 /* AIF_TRI */
+#define WM8962_AIF_TRI_MASK 0x0008 /* AIF_TRI */
+#define WM8962_AIF_TRI_SHIFT 3 /* AIF_TRI */
+#define WM8962_AIF_TRI_WIDTH 1 /* AIF_TRI */
+
+/*
+ * R25 (0x19) - Pwr Mgmt (1)
+ */
+#define WM8962_DMIC_ENA 0x0400 /* DMIC_ENA */
+#define WM8962_DMIC_ENA_MASK 0x0400 /* DMIC_ENA */
+#define WM8962_DMIC_ENA_SHIFT 10 /* DMIC_ENA */
+#define WM8962_DMIC_ENA_WIDTH 1 /* DMIC_ENA */
+#define WM8962_OPCLK_ENA 0x0200 /* OPCLK_ENA */
+#define WM8962_OPCLK_ENA_MASK 0x0200 /* OPCLK_ENA */
+#define WM8962_OPCLK_ENA_SHIFT 9 /* OPCLK_ENA */
+#define WM8962_OPCLK_ENA_WIDTH 1 /* OPCLK_ENA */
+#define WM8962_VMID_SEL_MASK 0x0180 /* VMID_SEL - [8:7] */
+#define WM8962_VMID_SEL_SHIFT 7 /* VMID_SEL - [8:7] */
+#define WM8962_VMID_SEL_WIDTH 2 /* VMID_SEL - [8:7] */
+#define WM8962_BIAS_ENA 0x0040 /* BIAS_ENA */
+#define WM8962_BIAS_ENA_MASK 0x0040 /* BIAS_ENA */
+#define WM8962_BIAS_ENA_SHIFT 6 /* BIAS_ENA */
+#define WM8962_BIAS_ENA_WIDTH 1 /* BIAS_ENA */
+#define WM8962_INL_ENA 0x0020 /* INL_ENA */
+#define WM8962_INL_ENA_MASK 0x0020 /* INL_ENA */
+#define WM8962_INL_ENA_SHIFT 5 /* INL_ENA */
+#define WM8962_INL_ENA_WIDTH 1 /* INL_ENA */
+#define WM8962_INR_ENA 0x0010 /* INR_ENA */
+#define WM8962_INR_ENA_MASK 0x0010 /* INR_ENA */
+#define WM8962_INR_ENA_SHIFT 4 /* INR_ENA */
+#define WM8962_INR_ENA_WIDTH 1 /* INR_ENA */
+#define WM8962_ADCL_ENA 0x0008 /* ADCL_ENA */
+#define WM8962_ADCL_ENA_MASK 0x0008 /* ADCL_ENA */
+#define WM8962_ADCL_ENA_SHIFT 3 /* ADCL_ENA */
+#define WM8962_ADCL_ENA_WIDTH 1 /* ADCL_ENA */
+#define WM8962_ADCR_ENA 0x0004 /* ADCR_ENA */
+#define WM8962_ADCR_ENA_MASK 0x0004 /* ADCR_ENA */
+#define WM8962_ADCR_ENA_SHIFT 2 /* ADCR_ENA */
+#define WM8962_ADCR_ENA_WIDTH 1 /* ADCR_ENA */
+#define WM8962_MICBIAS_ENA 0x0002 /* MICBIAS_ENA */
+#define WM8962_MICBIAS_ENA_MASK 0x0002 /* MICBIAS_ENA */
+#define WM8962_MICBIAS_ENA_SHIFT 1 /* MICBIAS_ENA */
+#define WM8962_MICBIAS_ENA_WIDTH 1 /* MICBIAS_ENA */
+
+/*
+ * R26 (0x1A) - Pwr Mgmt (2)
+ */
+#define WM8962_DACL_ENA 0x0100 /* DACL_ENA */
+#define WM8962_DACL_ENA_MASK 0x0100 /* DACL_ENA */
+#define WM8962_DACL_ENA_SHIFT 8 /* DACL_ENA */
+#define WM8962_DACL_ENA_WIDTH 1 /* DACL_ENA */
+#define WM8962_DACR_ENA 0x0080 /* DACR_ENA */
+#define WM8962_DACR_ENA_MASK 0x0080 /* DACR_ENA */
+#define WM8962_DACR_ENA_SHIFT 7 /* DACR_ENA */
+#define WM8962_DACR_ENA_WIDTH 1 /* DACR_ENA */
+#define WM8962_HPOUTL_PGA_ENA 0x0040 /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTL_PGA_ENA_MASK 0x0040 /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTL_PGA_ENA_SHIFT 6 /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTL_PGA_ENA_WIDTH 1 /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA 0x0020 /* HPOUTR_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA_MASK 0x0020 /* HPOUTR_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA_SHIFT 5 /* HPOUTR_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA_WIDTH 1 /* HPOUTR_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA 0x0010 /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA_MASK 0x0010 /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA_SHIFT 4 /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA_WIDTH 1 /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA 0x0008 /* SPKOUTR_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA_MASK 0x0008 /* SPKOUTR_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA_SHIFT 3 /* SPKOUTR_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA_WIDTH 1 /* SPKOUTR_PGA_ENA */
+#define WM8962_HPOUTL_PGA_MUTE 0x0002 /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTL_PGA_MUTE_MASK 0x0002 /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTL_PGA_MUTE_SHIFT 1 /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTL_PGA_MUTE_WIDTH 1 /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE 0x0001 /* HPOUTR_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE_MASK 0x0001 /* HPOUTR_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE_SHIFT 0 /* HPOUTR_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE_WIDTH 1 /* HPOUTR_PGA_MUTE */
+
+/*
+ * R27 (0x1B) - Additional Control (3)
+ */
+#define WM8962_SAMPLE_RATE_INT_MODE 0x0010 /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_INT_MODE_MASK 0x0010 /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_INT_MODE_SHIFT 4 /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_INT_MODE_WIDTH 1 /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_MASK 0x0007 /* SAMPLE_RATE - [2:0] */
+#define WM8962_SAMPLE_RATE_SHIFT 0 /* SAMPLE_RATE - [2:0] */
+#define WM8962_SAMPLE_RATE_WIDTH 3 /* SAMPLE_RATE - [2:0] */
+
+/*
+ * R28 (0x1C) - Anti-pop
+ */
+#define WM8962_STARTUP_BIAS_ENA 0x0010 /* STARTUP_BIAS_ENA */
+#define WM8962_STARTUP_BIAS_ENA_MASK 0x0010 /* STARTUP_BIAS_ENA */
+#define WM8962_STARTUP_BIAS_ENA_SHIFT 4 /* STARTUP_BIAS_ENA */
+#define WM8962_STARTUP_BIAS_ENA_WIDTH 1 /* STARTUP_BIAS_ENA */
+#define WM8962_VMID_BUF_ENA 0x0008 /* VMID_BUF_ENA */
+#define WM8962_VMID_BUF_ENA_MASK 0x0008 /* VMID_BUF_ENA */
+#define WM8962_VMID_BUF_ENA_SHIFT 3 /* VMID_BUF_ENA */
+#define WM8962_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */
+#define WM8962_VMID_RAMP 0x0004 /* VMID_RAMP */
+#define WM8962_VMID_RAMP_MASK 0x0004 /* VMID_RAMP */
+#define WM8962_VMID_RAMP_SHIFT 2 /* VMID_RAMP */
+#define WM8962_VMID_RAMP_WIDTH 1 /* VMID_RAMP */
+
+/*
+ * R30 (0x1E) - Clocking 3
+ */
+#define WM8962_DBCLK_DIV_MASK 0xE000 /* DBCLK_DIV - [15:13] */
+#define WM8962_DBCLK_DIV_SHIFT 13 /* DBCLK_DIV - [15:13] */
+#define WM8962_DBCLK_DIV_WIDTH 3 /* DBCLK_DIV - [15:13] */
+#define WM8962_OPCLK_DIV_MASK 0x1C00 /* OPCLK_DIV - [12:10] */
+#define WM8962_OPCLK_DIV_SHIFT 10 /* OPCLK_DIV - [12:10] */
+#define WM8962_OPCLK_DIV_WIDTH 3 /* OPCLK_DIV - [12:10] */
+#define WM8962_TOCLK_DIV_MASK 0x0380 /* TOCLK_DIV - [9:7] */
+#define WM8962_TOCLK_DIV_SHIFT 7 /* TOCLK_DIV - [9:7] */
+#define WM8962_TOCLK_DIV_WIDTH 3 /* TOCLK_DIV - [9:7] */
+#define WM8962_F256KCLK_DIV_MASK 0x007E /* F256KCLK_DIV - [6:1] */
+#define WM8962_F256KCLK_DIV_SHIFT 1 /* F256KCLK_DIV - [6:1] */
+#define WM8962_F256KCLK_DIV_WIDTH 6 /* F256KCLK_DIV - [6:1] */
+
+/*
+ * R31 (0x1F) - Input mixer control (1)
+ */
+#define WM8962_MIXINL_MUTE 0x0008 /* MIXINL_MUTE */
+#define WM8962_MIXINL_MUTE_MASK 0x0008 /* MIXINL_MUTE */
+#define WM8962_MIXINL_MUTE_SHIFT 3 /* MIXINL_MUTE */
+#define WM8962_MIXINL_MUTE_WIDTH 1 /* MIXINL_MUTE */
+#define WM8962_MIXINR_MUTE 0x0004 /* MIXINR_MUTE */
+#define WM8962_MIXINR_MUTE_MASK 0x0004 /* MIXINR_MUTE */
+#define WM8962_MIXINR_MUTE_SHIFT 2 /* MIXINR_MUTE */
+#define WM8962_MIXINR_MUTE_WIDTH 1 /* MIXINR_MUTE */
+#define WM8962_MIXINL_ENA 0x0002 /* MIXINL_ENA */
+#define WM8962_MIXINL_ENA_MASK 0x0002 /* MIXINL_ENA */
+#define WM8962_MIXINL_ENA_SHIFT 1 /* MIXINL_ENA */
+#define WM8962_MIXINL_ENA_WIDTH 1 /* MIXINL_ENA */
+#define WM8962_MIXINR_ENA 0x0001 /* MIXINR_ENA */
+#define WM8962_MIXINR_ENA_MASK 0x0001 /* MIXINR_ENA */
+#define WM8962_MIXINR_ENA_SHIFT 0 /* MIXINR_ENA */
+#define WM8962_MIXINR_ENA_WIDTH 1 /* MIXINR_ENA */
+
+/*
+ * R32 (0x20) - Left input mixer volume
+ */
+#define WM8962_IN2L_MIXINL_VOL_MASK 0x01C0 /* IN2L_MIXINL_VOL - [8:6] */
+#define WM8962_IN2L_MIXINL_VOL_SHIFT 6 /* IN2L_MIXINL_VOL - [8:6] */
+#define WM8962_IN2L_MIXINL_VOL_WIDTH 3 /* IN2L_MIXINL_VOL - [8:6] */
+#define WM8962_INPGAL_MIXINL_VOL_MASK 0x0038 /* INPGAL_MIXINL_VOL - [5:3] */
+#define WM8962_INPGAL_MIXINL_VOL_SHIFT 3 /* INPGAL_MIXINL_VOL - [5:3] */
+#define WM8962_INPGAL_MIXINL_VOL_WIDTH 3 /* INPGAL_MIXINL_VOL - [5:3] */
+#define WM8962_IN3L_MIXINL_VOL_MASK 0x0007 /* IN3L_MIXINL_VOL - [2:0] */
+#define WM8962_IN3L_MIXINL_VOL_SHIFT 0 /* IN3L_MIXINL_VOL - [2:0] */
+#define WM8962_IN3L_MIXINL_VOL_WIDTH 3 /* IN3L_MIXINL_VOL - [2:0] */
+
+/*
+ * R33 (0x21) - Right input mixer volume
+ */
+#define WM8962_IN2R_MIXINR_VOL_MASK 0x01C0 /* IN2R_MIXINR_VOL - [8:6] */
+#define WM8962_IN2R_MIXINR_VOL_SHIFT 6 /* IN2R_MIXINR_VOL - [8:6] */
+#define WM8962_IN2R_MIXINR_VOL_WIDTH 3 /* IN2R_MIXINR_VOL - [8:6] */
+#define WM8962_INPGAR_MIXINR_VOL_MASK 0x0038 /* INPGAR_MIXINR_VOL - [5:3] */
+#define WM8962_INPGAR_MIXINR_VOL_SHIFT 3 /* INPGAR_MIXINR_VOL - [5:3] */
+#define WM8962_INPGAR_MIXINR_VOL_WIDTH 3 /* INPGAR_MIXINR_VOL - [5:3] */
+#define WM8962_IN3R_MIXINR_VOL_MASK 0x0007 /* IN3R_MIXINR_VOL - [2:0] */
+#define WM8962_IN3R_MIXINR_VOL_SHIFT 0 /* IN3R_MIXINR_VOL - [2:0] */
+#define WM8962_IN3R_MIXINR_VOL_WIDTH 3 /* IN3R_MIXINR_VOL - [2:0] */
+
+/*
+ * R34 (0x22) - Input mixer control (2)
+ */
+#define WM8962_IN2L_TO_MIXINL 0x0020 /* IN2L_TO_MIXINL */
+#define WM8962_IN2L_TO_MIXINL_MASK 0x0020 /* IN2L_TO_MIXINL */
+#define WM8962_IN2L_TO_MIXINL_SHIFT 5 /* IN2L_TO_MIXINL */
+#define WM8962_IN2L_TO_MIXINL_WIDTH 1 /* IN2L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL 0x0010 /* IN3L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL_MASK 0x0010 /* IN3L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL_SHIFT 4 /* IN3L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL_WIDTH 1 /* IN3L_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL 0x0008 /* INPGAL_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL_MASK 0x0008 /* INPGAL_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL_SHIFT 3 /* INPGAL_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL_WIDTH 1 /* INPGAL_TO_MIXINL */
+#define WM8962_IN2R_TO_MIXINR 0x0004 /* IN2R_TO_MIXINR */
+#define WM8962_IN2R_TO_MIXINR_MASK 0x0004 /* IN2R_TO_MIXINR */
+#define WM8962_IN2R_TO_MIXINR_SHIFT 2 /* IN2R_TO_MIXINR */
+#define WM8962_IN2R_TO_MIXINR_WIDTH 1 /* IN2R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR 0x0002 /* IN3R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR_MASK 0x0002 /* IN3R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR_SHIFT 1 /* IN3R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR_WIDTH 1 /* IN3R_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR 0x0001 /* INPGAR_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR_MASK 0x0001 /* INPGAR_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR_SHIFT 0 /* INPGAR_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR_WIDTH 1 /* INPGAR_TO_MIXINR */
+
+/*
+ * R35 (0x23) - Input bias control
+ */
+#define WM8962_MIXIN_BIAS_MASK 0x0038 /* MIXIN_BIAS - [5:3] */
+#define WM8962_MIXIN_BIAS_SHIFT 3 /* MIXIN_BIAS - [5:3] */
+#define WM8962_MIXIN_BIAS_WIDTH 3 /* MIXIN_BIAS - [5:3] */
+#define WM8962_INPGA_BIAS_MASK 0x0007 /* INPGA_BIAS - [2:0] */
+#define WM8962_INPGA_BIAS_SHIFT 0 /* INPGA_BIAS - [2:0] */
+#define WM8962_INPGA_BIAS_WIDTH 3 /* INPGA_BIAS - [2:0] */
+
+/*
+ * R37 (0x25) - Left input PGA control
+ */
+#define WM8962_INPGAL_ENA 0x0010 /* INPGAL_ENA */
+#define WM8962_INPGAL_ENA_MASK 0x0010 /* INPGAL_ENA */
+#define WM8962_INPGAL_ENA_SHIFT 4 /* INPGAL_ENA */
+#define WM8962_INPGAL_ENA_WIDTH 1 /* INPGAL_ENA */
+#define WM8962_IN1L_TO_INPGAL 0x0008 /* IN1L_TO_INPGAL */
+#define WM8962_IN1L_TO_INPGAL_MASK 0x0008 /* IN1L_TO_INPGAL */
+#define WM8962_IN1L_TO_INPGAL_SHIFT 3 /* IN1L_TO_INPGAL */
+#define WM8962_IN1L_TO_INPGAL_WIDTH 1 /* IN1L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL 0x0004 /* IN2L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL_MASK 0x0004 /* IN2L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL_SHIFT 2 /* IN2L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL_WIDTH 1 /* IN2L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL 0x0002 /* IN3L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL_MASK 0x0002 /* IN3L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL_SHIFT 1 /* IN3L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL_WIDTH 1 /* IN3L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL 0x0001 /* IN4L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL_MASK 0x0001 /* IN4L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL_SHIFT 0 /* IN4L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL_WIDTH 1 /* IN4L_TO_INPGAL */
+
+/*
+ * R38 (0x26) - Right input PGA control
+ */
+#define WM8962_INPGAR_ENA 0x0010 /* INPGAR_ENA */
+#define WM8962_INPGAR_ENA_MASK 0x0010 /* INPGAR_ENA */
+#define WM8962_INPGAR_ENA_SHIFT 4 /* INPGAR_ENA */
+#define WM8962_INPGAR_ENA_WIDTH 1 /* INPGAR_ENA */
+#define WM8962_IN1R_TO_INPGAR 0x0008 /* IN1R_TO_INPGAR */
+#define WM8962_IN1R_TO_INPGAR_MASK 0x0008 /* IN1R_TO_INPGAR */
+#define WM8962_IN1R_TO_INPGAR_SHIFT 3 /* IN1R_TO_INPGAR */
+#define WM8962_IN1R_TO_INPGAR_WIDTH 1 /* IN1R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR 0x0004 /* IN2R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR_MASK 0x0004 /* IN2R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR_SHIFT 2 /* IN2R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR_WIDTH 1 /* IN2R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR 0x0002 /* IN3R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR_MASK 0x0002 /* IN3R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR_SHIFT 1 /* IN3R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR_WIDTH 1 /* IN3R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR 0x0001 /* IN4R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR_MASK 0x0001 /* IN4R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR_SHIFT 0 /* IN4R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR_WIDTH 1 /* IN4R_TO_INPGAR */
+
+/*
+ * R40 (0x28) - SPKOUTL volume
+ */
+#define WM8962_SPKOUT_VU 0x0100 /* SPKOUT_VU */
+#define WM8962_SPKOUT_VU_MASK 0x0100 /* SPKOUT_VU */
+#define WM8962_SPKOUT_VU_SHIFT 8 /* SPKOUT_VU */
+#define WM8962_SPKOUT_VU_WIDTH 1 /* SPKOUT_VU */
+#define WM8962_SPKOUTL_ZC 0x0080 /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_ZC_MASK 0x0080 /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_ZC_SHIFT 7 /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_ZC_WIDTH 1 /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_VOL_MASK 0x007F /* SPKOUTL_VOL - [6:0] */
+#define WM8962_SPKOUTL_VOL_SHIFT 0 /* SPKOUTL_VOL - [6:0] */
+#define WM8962_SPKOUTL_VOL_WIDTH 7 /* SPKOUTL_VOL - [6:0] */
+
+/*
+ * R41 (0x29) - SPKOUTR volume
+ */
+#define WM8962_SPKOUTR_ZC 0x0080 /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_ZC_MASK 0x0080 /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_ZC_SHIFT 7 /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_ZC_WIDTH 1 /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_VOL_MASK 0x007F /* SPKOUTR_VOL - [6:0] */
+#define WM8962_SPKOUTR_VOL_SHIFT 0 /* SPKOUTR_VOL - [6:0] */
+#define WM8962_SPKOUTR_VOL_WIDTH 7 /* SPKOUTR_VOL - [6:0] */
+
+/*
+ * R47 (0x2F) - Thermal Shutdown Status
+ */
+#define WM8962_TEMP_ERR_HP 0x0008 /* TEMP_ERR_HP */
+#define WM8962_TEMP_ERR_HP_MASK 0x0008 /* TEMP_ERR_HP */
+#define WM8962_TEMP_ERR_HP_SHIFT 3 /* TEMP_ERR_HP */
+#define WM8962_TEMP_ERR_HP_WIDTH 1 /* TEMP_ERR_HP */
+#define WM8962_TEMP_WARN_HP 0x0004 /* TEMP_WARN_HP */
+#define WM8962_TEMP_WARN_HP_MASK 0x0004 /* TEMP_WARN_HP */
+#define WM8962_TEMP_WARN_HP_SHIFT 2 /* TEMP_WARN_HP */
+#define WM8962_TEMP_WARN_HP_WIDTH 1 /* TEMP_WARN_HP */
+#define WM8962_TEMP_ERR_SPK 0x0002 /* TEMP_ERR_SPK */
+#define WM8962_TEMP_ERR_SPK_MASK 0x0002 /* TEMP_ERR_SPK */
+#define WM8962_TEMP_ERR_SPK_SHIFT 1 /* TEMP_ERR_SPK */
+#define WM8962_TEMP_ERR_SPK_WIDTH 1 /* TEMP_ERR_SPK */
+#define WM8962_TEMP_WARN_SPK 0x0001 /* TEMP_WARN_SPK */
+#define WM8962_TEMP_WARN_SPK_MASK 0x0001 /* TEMP_WARN_SPK */
+#define WM8962_TEMP_WARN_SPK_SHIFT 0 /* TEMP_WARN_SPK */
+#define WM8962_TEMP_WARN_SPK_WIDTH 1 /* TEMP_WARN_SPK */
+
+/*
+ * R48 (0x30) - Additional Control (4)
+ */
+#define WM8962_MICDET_THR_MASK 0x7000 /* MICDET_THR - [14:12] */
+#define WM8962_MICDET_THR_SHIFT 12 /* MICDET_THR - [14:12] */
+#define WM8962_MICDET_THR_WIDTH 3 /* MICDET_THR - [14:12] */
+#define WM8962_MICSHORT_THR_MASK 0x0C00 /* MICSHORT_THR - [11:10] */
+#define WM8962_MICSHORT_THR_SHIFT 10 /* MICSHORT_THR - [11:10] */
+#define WM8962_MICSHORT_THR_WIDTH 2 /* MICSHORT_THR - [11:10] */
+#define WM8962_MICDET_ENA 0x0200 /* MICDET_ENA */
+#define WM8962_MICDET_ENA_MASK 0x0200 /* MICDET_ENA */
+#define WM8962_MICDET_ENA_SHIFT 9 /* MICDET_ENA */
+#define WM8962_MICDET_ENA_WIDTH 1 /* MICDET_ENA */
+#define WM8962_MICDET_STS 0x0080 /* MICDET_STS */
+#define WM8962_MICDET_STS_MASK 0x0080 /* MICDET_STS */
+#define WM8962_MICDET_STS_SHIFT 7 /* MICDET_STS */
+#define WM8962_MICDET_STS_WIDTH 1 /* MICDET_STS */
+#define WM8962_MICSHORT_STS 0x0040 /* MICSHORT_STS */
+#define WM8962_MICSHORT_STS_MASK 0x0040 /* MICSHORT_STS */
+#define WM8962_MICSHORT_STS_SHIFT 6 /* MICSHORT_STS */
+#define WM8962_MICSHORT_STS_WIDTH 1 /* MICSHORT_STS */
+#define WM8962_TEMP_ENA_HP 0x0004 /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_HP_MASK 0x0004 /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_HP_SHIFT 2 /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_HP_WIDTH 1 /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_SPK 0x0002 /* TEMP_ENA_SPK */
+#define WM8962_TEMP_ENA_SPK_MASK 0x0002 /* TEMP_ENA_SPK */
+#define WM8962_TEMP_ENA_SPK_SHIFT 1 /* TEMP_ENA_SPK */
+#define WM8962_TEMP_ENA_SPK_WIDTH 1 /* TEMP_ENA_SPK */
+#define WM8962_MICBIAS_LVL 0x0001 /* MICBIAS_LVL */
+#define WM8962_MICBIAS_LVL_MASK 0x0001 /* MICBIAS_LVL */
+#define WM8962_MICBIAS_LVL_SHIFT 0 /* MICBIAS_LVL */
+#define WM8962_MICBIAS_LVL_WIDTH 1 /* MICBIAS_LVL */
+
+/*
+ * R49 (0x31) - Class D Control 1
+ */
+#define WM8962_SPKOUTR_ENA 0x0080 /* SPKOUTR_ENA */
+#define WM8962_SPKOUTR_ENA_MASK 0x0080 /* SPKOUTR_ENA */
+#define WM8962_SPKOUTR_ENA_SHIFT 7 /* SPKOUTR_ENA */
+#define WM8962_SPKOUTR_ENA_WIDTH 1 /* SPKOUTR_ENA */
+#define WM8962_SPKOUTL_ENA 0x0040 /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_ENA_MASK 0x0040 /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_ENA_SHIFT 6 /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_ENA_WIDTH 1 /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_PGA_MUTE 0x0002 /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE_MASK 0x0002 /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE_SHIFT 1 /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE_WIDTH 1 /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE 0x0001 /* SPKOUTR_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE_MASK 0x0001 /* SPKOUTR_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE_SHIFT 0 /* SPKOUTR_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE_WIDTH 1 /* SPKOUTR_PGA_MUTE */
+
+/*
+ * R51 (0x33) - Class D Control 2
+ */
+#define WM8962_SPK_MONO 0x0040 /* SPK_MONO */
+#define WM8962_SPK_MONO_MASK 0x0040 /* SPK_MONO */
+#define WM8962_SPK_MONO_SHIFT 6 /* SPK_MONO */
+#define WM8962_SPK_MONO_WIDTH 1 /* SPK_MONO */
+#define WM8962_CLASSD_VOL_MASK 0x0007 /* CLASSD_VOL - [2:0] */
+#define WM8962_CLASSD_VOL_SHIFT 0 /* CLASSD_VOL - [2:0] */
+#define WM8962_CLASSD_VOL_WIDTH 3 /* CLASSD_VOL - [2:0] */
+
+/*
+ * R56 (0x38) - Clocking 4
+ */
+#define WM8962_SYSCLK_RATE_MASK 0x001E /* SYSCLK_RATE - [4:1] */
+#define WM8962_SYSCLK_RATE_SHIFT 1 /* SYSCLK_RATE - [4:1] */
+#define WM8962_SYSCLK_RATE_WIDTH 4 /* SYSCLK_RATE - [4:1] */
+
+/*
+ * R57 (0x39) - DAC DSP Mixing (1)
+ */
+#define WM8962_DAC_MONOMIX 0x0200 /* DAC_MONOMIX */
+#define WM8962_DAC_MONOMIX_MASK 0x0200 /* DAC_MONOMIX */
+#define WM8962_DAC_MONOMIX_SHIFT 9 /* DAC_MONOMIX */
+#define WM8962_DAC_MONOMIX_WIDTH 1 /* DAC_MONOMIX */
+#define WM8962_ADCR_DAC_SVOL_MASK 0x00F0 /* ADCR_DAC_SVOL - [7:4] */
+#define WM8962_ADCR_DAC_SVOL_SHIFT 4 /* ADCR_DAC_SVOL - [7:4] */
+#define WM8962_ADCR_DAC_SVOL_WIDTH 4 /* ADCR_DAC_SVOL - [7:4] */
+#define WM8962_ADC_TO_DACR_MASK 0x000C /* ADC_TO_DACR - [3:2] */
+#define WM8962_ADC_TO_DACR_SHIFT 2 /* ADC_TO_DACR - [3:2] */
+#define WM8962_ADC_TO_DACR_WIDTH 2 /* ADC_TO_DACR - [3:2] */
+
+/*
+ * R58 (0x3A) - DAC DSP Mixing (2)
+ */
+#define WM8962_ADCL_DAC_SVOL_MASK 0x00F0 /* ADCL_DAC_SVOL - [7:4] */
+#define WM8962_ADCL_DAC_SVOL_SHIFT 4 /* ADCL_DAC_SVOL - [7:4] */
+#define WM8962_ADCL_DAC_SVOL_WIDTH 4 /* ADCL_DAC_SVOL - [7:4] */
+#define WM8962_ADC_TO_DACL_MASK 0x000C /* ADC_TO_DACL - [3:2] */
+#define WM8962_ADC_TO_DACL_SHIFT 2 /* ADC_TO_DACL - [3:2] */
+#define WM8962_ADC_TO_DACL_WIDTH 2 /* ADC_TO_DACL - [3:2] */
+
+/*
+ * R60 (0x3C) - DC Servo 0
+ */
+#define WM8962_INL_DCS_ENA 0x0080 /* INL_DCS_ENA */
+#define WM8962_INL_DCS_ENA_MASK 0x0080 /* INL_DCS_ENA */
+#define WM8962_INL_DCS_ENA_SHIFT 7 /* INL_DCS_ENA */
+#define WM8962_INL_DCS_ENA_WIDTH 1 /* INL_DCS_ENA */
+#define WM8962_INL_DCS_STARTUP 0x0040 /* INL_DCS_STARTUP */
+#define WM8962_INL_DCS_STARTUP_MASK 0x0040 /* INL_DCS_STARTUP */
+#define WM8962_INL_DCS_STARTUP_SHIFT 6 /* INL_DCS_STARTUP */
+#define WM8962_INL_DCS_STARTUP_WIDTH 1 /* INL_DCS_STARTUP */
+#define WM8962_INR_DCS_ENA 0x0008 /* INR_DCS_ENA */
+#define WM8962_INR_DCS_ENA_MASK 0x0008 /* INR_DCS_ENA */
+#define WM8962_INR_DCS_ENA_SHIFT 3 /* INR_DCS_ENA */
+#define WM8962_INR_DCS_ENA_WIDTH 1 /* INR_DCS_ENA */
+#define WM8962_INR_DCS_STARTUP 0x0004 /* INR_DCS_STARTUP */
+#define WM8962_INR_DCS_STARTUP_MASK 0x0004 /* INR_DCS_STARTUP */
+#define WM8962_INR_DCS_STARTUP_SHIFT 2 /* INR_DCS_STARTUP */
+#define WM8962_INR_DCS_STARTUP_WIDTH 1 /* INR_DCS_STARTUP */
+
+/*
+ * R61 (0x3D) - DC Servo 1
+ */
+#define WM8962_HP1L_DCS_ENA 0x0080 /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_ENA_MASK 0x0080 /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_ENA_SHIFT 7 /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_ENA_WIDTH 1 /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_STARTUP 0x0040 /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_STARTUP_MASK 0x0040 /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_STARTUP_SHIFT 6 /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_STARTUP_WIDTH 1 /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_SYNC 0x0010 /* HP1L_DCS_SYNC */
+#define WM8962_HP1L_DCS_SYNC_MASK 0x0010 /* HP1L_DCS_SYNC */
+#define WM8962_HP1L_DCS_SYNC_SHIFT 4 /* HP1L_DCS_SYNC */
+#define WM8962_HP1L_DCS_SYNC_WIDTH 1 /* HP1L_DCS_SYNC */
+#define WM8962_HP1R_DCS_ENA 0x0008 /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_ENA_MASK 0x0008 /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_ENA_SHIFT 3 /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_ENA_WIDTH 1 /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_STARTUP 0x0004 /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_STARTUP_MASK 0x0004 /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_STARTUP_SHIFT 2 /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_STARTUP_WIDTH 1 /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_SYNC 0x0001 /* HP1R_DCS_SYNC */
+#define WM8962_HP1R_DCS_SYNC_MASK 0x0001 /* HP1R_DCS_SYNC */
+#define WM8962_HP1R_DCS_SYNC_SHIFT 0 /* HP1R_DCS_SYNC */
+#define WM8962_HP1R_DCS_SYNC_WIDTH 1 /* HP1R_DCS_SYNC */
+
+/*
+ * R64 (0x40) - DC Servo 4
+ */
+#define WM8962_HP1_DCS_SYNC_STEPS_MASK 0x3F80 /* HP1_DCS_SYNC_STEPS - [13:7] */
+#define WM8962_HP1_DCS_SYNC_STEPS_SHIFT 7 /* HP1_DCS_SYNC_STEPS - [13:7] */
+#define WM8962_HP1_DCS_SYNC_STEPS_WIDTH 7 /* HP1_DCS_SYNC_STEPS - [13:7] */
+
+/*
+ * R66 (0x42) - DC Servo 6
+ */
+#define WM8962_DCS_STARTUP_DONE_INL 0x0400 /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INL_MASK 0x0400 /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INL_SHIFT 10 /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INL_WIDTH 1 /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INR 0x0200 /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_INR_MASK 0x0200 /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_INR_SHIFT 9 /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_INR_WIDTH 1 /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_HP1L 0x0100 /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1L_MASK 0x0100 /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1L_SHIFT 8 /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1L_WIDTH 1 /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1R 0x0080 /* DCS_STARTUP_DONE_HP1R */
+#define WM8962_DCS_STARTUP_DONE_HP1R_MASK 0x0080 /* DCS_STARTUP_DONE_HP1R */
+#define WM8962_DCS_STARTUP_DONE_HP1R_SHIFT 7 /* DCS_STARTUP_DONE_HP1R */
+#define WM8962_DCS_STARTUP_DONE_HP1R_WIDTH 1 /* DCS_STARTUP_DONE_HP1R */
+
+/*
+ * R68 (0x44) - Analogue PGA Bias
+ */
+#define WM8962_HP_PGAS_BIAS_MASK 0x0007 /* HP_PGAS_BIAS - [2:0] */
+#define WM8962_HP_PGAS_BIAS_SHIFT 0 /* HP_PGAS_BIAS - [2:0] */
+#define WM8962_HP_PGAS_BIAS_WIDTH 3 /* HP_PGAS_BIAS - [2:0] */
+
+/*
+ * R69 (0x45) - Analogue HP 0
+ */
+#define WM8962_HP1L_RMV_SHORT 0x0080 /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_RMV_SHORT_MASK 0x0080 /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_RMV_SHORT_SHIFT 7 /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_RMV_SHORT_WIDTH 1 /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_ENA_OUTP 0x0040 /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_OUTP_MASK 0x0040 /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_OUTP_SHIFT 6 /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_OUTP_WIDTH 1 /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_DLY 0x0020 /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA_DLY_MASK 0x0020 /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA_DLY_SHIFT 5 /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA_DLY_WIDTH 1 /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA 0x0010 /* HP1L_ENA */
+#define WM8962_HP1L_ENA_MASK 0x0010 /* HP1L_ENA */
+#define WM8962_HP1L_ENA_SHIFT 4 /* HP1L_ENA */
+#define WM8962_HP1L_ENA_WIDTH 1 /* HP1L_ENA */
+#define WM8962_HP1R_RMV_SHORT 0x0008 /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_RMV_SHORT_MASK 0x0008 /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_RMV_SHORT_SHIFT 3 /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_RMV_SHORT_WIDTH 1 /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_ENA_OUTP 0x0004 /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_OUTP_MASK 0x0004 /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_OUTP_SHIFT 2 /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_OUTP_WIDTH 1 /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_DLY 0x0002 /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA_DLY_MASK 0x0002 /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA_DLY_SHIFT 1 /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA_DLY_WIDTH 1 /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA 0x0001 /* HP1R_ENA */
+#define WM8962_HP1R_ENA_MASK 0x0001 /* HP1R_ENA */
+#define WM8962_HP1R_ENA_SHIFT 0 /* HP1R_ENA */
+#define WM8962_HP1R_ENA_WIDTH 1 /* HP1R_ENA */
+
+/*
+ * R71 (0x47) - Analogue HP 2
+ */
+#define WM8962_HP1L_VOL_MASK 0x01C0 /* HP1L_VOL - [8:6] */
+#define WM8962_HP1L_VOL_SHIFT 6 /* HP1L_VOL - [8:6] */
+#define WM8962_HP1L_VOL_WIDTH 3 /* HP1L_VOL - [8:6] */
+#define WM8962_HP1R_VOL_MASK 0x0038 /* HP1R_VOL - [5:3] */
+#define WM8962_HP1R_VOL_SHIFT 3 /* HP1R_VOL - [5:3] */
+#define WM8962_HP1R_VOL_WIDTH 3 /* HP1R_VOL - [5:3] */
+#define WM8962_HP_BIAS_BOOST_MASK 0x0007 /* HP_BIAS_BOOST - [2:0] */
+#define WM8962_HP_BIAS_BOOST_SHIFT 0 /* HP_BIAS_BOOST - [2:0] */
+#define WM8962_HP_BIAS_BOOST_WIDTH 3 /* HP_BIAS_BOOST - [2:0] */
+
+/*
+ * R72 (0x48) - Charge Pump 1
+ */
+#define WM8962_CP_ENA 0x0001 /* CP_ENA */
+#define WM8962_CP_ENA_MASK 0x0001 /* CP_ENA */
+#define WM8962_CP_ENA_SHIFT 0 /* CP_ENA */
+#define WM8962_CP_ENA_WIDTH 1 /* CP_ENA */
+
+/*
+ * R82 (0x52) - Charge Pump B
+ */
+#define WM8962_CP_DYN_PWR 0x0001 /* CP_DYN_PWR */
+#define WM8962_CP_DYN_PWR_MASK 0x0001 /* CP_DYN_PWR */
+#define WM8962_CP_DYN_PWR_SHIFT 0 /* CP_DYN_PWR */
+#define WM8962_CP_DYN_PWR_WIDTH 1 /* CP_DYN_PWR */
+
+/*
+ * R87 (0x57) - Write Sequencer Control 1
+ */
+#define WM8962_WSEQ_AUTOSEQ_ENA 0x0080 /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_AUTOSEQ_ENA_MASK 0x0080 /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_AUTOSEQ_ENA_SHIFT 7 /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_AUTOSEQ_ENA_WIDTH 1 /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_ENA 0x0020 /* WSEQ_ENA */
+#define WM8962_WSEQ_ENA_MASK 0x0020 /* WSEQ_ENA */
+#define WM8962_WSEQ_ENA_SHIFT 5 /* WSEQ_ENA */
+#define WM8962_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */
+
+/*
+ * R90 (0x5A) - Write Sequencer Control 2
+ */
+#define WM8962_WSEQ_ABORT 0x0100 /* WSEQ_ABORT */
+#define WM8962_WSEQ_ABORT_MASK 0x0100 /* WSEQ_ABORT */
+#define WM8962_WSEQ_ABORT_SHIFT 8 /* WSEQ_ABORT */
+#define WM8962_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */
+#define WM8962_WSEQ_START 0x0080 /* WSEQ_START */
+#define WM8962_WSEQ_START_MASK 0x0080 /* WSEQ_START */
+#define WM8962_WSEQ_START_SHIFT 7 /* WSEQ_START */
+#define WM8962_WSEQ_START_WIDTH 1 /* WSEQ_START */
+#define WM8962_WSEQ_START_INDEX_MASK 0x007F /* WSEQ_START_INDEX - [6:0] */
+#define WM8962_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [6:0] */
+#define WM8962_WSEQ_START_INDEX_WIDTH 7 /* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R93 (0x5D) - Write Sequencer Control 3
+ */
+#define WM8962_WSEQ_CURRENT_INDEX_MASK 0x03F8 /* WSEQ_CURRENT_INDEX - [9:3] */
+#define WM8962_WSEQ_CURRENT_INDEX_SHIFT 3 /* WSEQ_CURRENT_INDEX - [9:3] */
+#define WM8962_WSEQ_CURRENT_INDEX_WIDTH 7 /* WSEQ_CURRENT_INDEX - [9:3] */
+#define WM8962_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */
+#define WM8962_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */
+#define WM8962_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */
+#define WM8962_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */
+
+/*
+ * R94 (0x5E) - Control Interface
+ */
+#define WM8962_SPI_CONTRD 0x0040 /* SPI_CONTRD */
+#define WM8962_SPI_CONTRD_MASK 0x0040 /* SPI_CONTRD */
+#define WM8962_SPI_CONTRD_SHIFT 6 /* SPI_CONTRD */
+#define WM8962_SPI_CONTRD_WIDTH 1 /* SPI_CONTRD */
+#define WM8962_SPI_4WIRE 0x0020 /* SPI_4WIRE */
+#define WM8962_SPI_4WIRE_MASK 0x0020 /* SPI_4WIRE */
+#define WM8962_SPI_4WIRE_SHIFT 5 /* SPI_4WIRE */
+#define WM8962_SPI_4WIRE_WIDTH 1 /* SPI_4WIRE */
+#define WM8962_SPI_CFG 0x0010 /* SPI_CFG */
+#define WM8962_SPI_CFG_MASK 0x0010 /* SPI_CFG */
+#define WM8962_SPI_CFG_SHIFT 4 /* SPI_CFG */
+#define WM8962_SPI_CFG_WIDTH 1 /* SPI_CFG */
+
+/*
+ * R99 (0x63) - Mixer Enables
+ */
+#define WM8962_HPMIXL_ENA 0x0008 /* HPMIXL_ENA */
+#define WM8962_HPMIXL_ENA_MASK 0x0008 /* HPMIXL_ENA */
+#define WM8962_HPMIXL_ENA_SHIFT 3 /* HPMIXL_ENA */
+#define WM8962_HPMIXL_ENA_WIDTH 1 /* HPMIXL_ENA */
+#define WM8962_HPMIXR_ENA 0x0004 /* HPMIXR_ENA */
+#define WM8962_HPMIXR_ENA_MASK 0x0004 /* HPMIXR_ENA */
+#define WM8962_HPMIXR_ENA_SHIFT 2 /* HPMIXR_ENA */
+#define WM8962_HPMIXR_ENA_WIDTH 1 /* HPMIXR_ENA */
+#define WM8962_SPKMIXL_ENA 0x0002 /* SPKMIXL_ENA */
+#define WM8962_SPKMIXL_ENA_MASK 0x0002 /* SPKMIXL_ENA */
+#define WM8962_SPKMIXL_ENA_SHIFT 1 /* SPKMIXL_ENA */
+#define WM8962_SPKMIXL_ENA_WIDTH 1 /* SPKMIXL_ENA */
+#define WM8962_SPKMIXR_ENA 0x0001 /* SPKMIXR_ENA */
+#define WM8962_SPKMIXR_ENA_MASK 0x0001 /* SPKMIXR_ENA */
+#define WM8962_SPKMIXR_ENA_SHIFT 0 /* SPKMIXR_ENA */
+#define WM8962_SPKMIXR_ENA_WIDTH 1 /* SPKMIXR_ENA */
+
+/*
+ * R100 (0x64) - Headphone Mixer (1)
+ */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA 0x0080 /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA_MASK 0x0080 /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA_SHIFT 7 /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA_WIDTH 1 /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_DACL_TO_HPMIXL 0x0020 /* DACL_TO_HPMIXL */
+#define WM8962_DACL_TO_HPMIXL_MASK 0x0020 /* DACL_TO_HPMIXL */
+#define WM8962_DACL_TO_HPMIXL_SHIFT 5 /* DACL_TO_HPMIXL */
+#define WM8962_DACL_TO_HPMIXL_WIDTH 1 /* DACL_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL 0x0010 /* DACR_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL_MASK 0x0010 /* DACR_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL_SHIFT 4 /* DACR_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL_WIDTH 1 /* DACR_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL 0x0008 /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL_MASK 0x0008 /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL_SHIFT 3 /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL_WIDTH 1 /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL 0x0004 /* MIXINR_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL_MASK 0x0004 /* MIXINR_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL_SHIFT 2 /* MIXINR_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL_WIDTH 1 /* MIXINR_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL 0x0002 /* IN4L_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL_MASK 0x0002 /* IN4L_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL_SHIFT 1 /* IN4L_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL_WIDTH 1 /* IN4L_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL 0x0001 /* IN4R_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL_MASK 0x0001 /* IN4R_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL_SHIFT 0 /* IN4R_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL_WIDTH 1 /* IN4R_TO_HPMIXL */
+
+/*
+ * R101 (0x65) - Headphone Mixer (2)
+ */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA 0x0080 /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA_MASK 0x0080 /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA_SHIFT 7 /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA_WIDTH 1 /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_DACL_TO_HPMIXR 0x0020 /* DACL_TO_HPMIXR */
+#define WM8962_DACL_TO_HPMIXR_MASK 0x0020 /* DACL_TO_HPMIXR */
+#define WM8962_DACL_TO_HPMIXR_SHIFT 5 /* DACL_TO_HPMIXR */
+#define WM8962_DACL_TO_HPMIXR_WIDTH 1 /* DACL_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR 0x0010 /* DACR_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR_MASK 0x0010 /* DACR_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR_SHIFT 4 /* DACR_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR_WIDTH 1 /* DACR_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR 0x0008 /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR_MASK 0x0008 /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR_SHIFT 3 /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR_WIDTH 1 /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR 0x0004 /* MIXINR_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR_MASK 0x0004 /* MIXINR_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR_SHIFT 2 /* MIXINR_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR_WIDTH 1 /* MIXINR_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR 0x0002 /* IN4L_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR_MASK 0x0002 /* IN4L_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR_SHIFT 1 /* IN4L_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR_WIDTH 1 /* IN4L_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR 0x0001 /* IN4R_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR_MASK 0x0001 /* IN4R_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR_SHIFT 0 /* IN4R_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR_WIDTH 1 /* IN4R_TO_HPMIXR */
+
+/*
+ * R102 (0x66) - Headphone Mixer (3)
+ */
+#define WM8962_HPMIXL_MUTE 0x0100 /* HPMIXL_MUTE */
+#define WM8962_HPMIXL_MUTE_MASK 0x0100 /* HPMIXL_MUTE */
+#define WM8962_HPMIXL_MUTE_SHIFT 8 /* HPMIXL_MUTE */
+#define WM8962_HPMIXL_MUTE_WIDTH 1 /* HPMIXL_MUTE */
+#define WM8962_MIXINL_HPMIXL_VOL 0x0080 /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINL_HPMIXL_VOL_MASK 0x0080 /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINL_HPMIXL_VOL_SHIFT 7 /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINL_HPMIXL_VOL_WIDTH 1 /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL 0x0040 /* MIXINR_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL_MASK 0x0040 /* MIXINR_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL_SHIFT 6 /* MIXINR_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL_WIDTH 1 /* MIXINR_HPMIXL_VOL */
+#define WM8962_IN4L_HPMIXL_VOL_MASK 0x0038 /* IN4L_HPMIXL_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXL_VOL_SHIFT 3 /* IN4L_HPMIXL_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXL_VOL_WIDTH 3 /* IN4L_HPMIXL_VOL - [5:3] */
+#define WM8962_IN4R_HPMIXL_VOL_MASK 0x0007 /* IN4R_HPMIXL_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXL_VOL_SHIFT 0 /* IN4R_HPMIXL_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXL_VOL_WIDTH 3 /* IN4R_HPMIXL_VOL - [2:0] */
+
+/*
+ * R103 (0x67) - Headphone Mixer (4)
+ */
+#define WM8962_HPMIXR_MUTE 0x0100 /* HPMIXR_MUTE */
+#define WM8962_HPMIXR_MUTE_MASK 0x0100 /* HPMIXR_MUTE */
+#define WM8962_HPMIXR_MUTE_SHIFT 8 /* HPMIXR_MUTE */
+#define WM8962_HPMIXR_MUTE_WIDTH 1 /* HPMIXR_MUTE */
+#define WM8962_MIXINL_HPMIXR_VOL 0x0080 /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINL_HPMIXR_VOL_MASK 0x0080 /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINL_HPMIXR_VOL_SHIFT 7 /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINL_HPMIXR_VOL_WIDTH 1 /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL 0x0040 /* MIXINR_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL_MASK 0x0040 /* MIXINR_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL_SHIFT 6 /* MIXINR_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL_WIDTH 1 /* MIXINR_HPMIXR_VOL */
+#define WM8962_IN4L_HPMIXR_VOL_MASK 0x0038 /* IN4L_HPMIXR_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXR_VOL_SHIFT 3 /* IN4L_HPMIXR_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXR_VOL_WIDTH 3 /* IN4L_HPMIXR_VOL - [5:3] */
+#define WM8962_IN4R_HPMIXR_VOL_MASK 0x0007 /* IN4R_HPMIXR_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXR_VOL_SHIFT 0 /* IN4R_HPMIXR_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXR_VOL_WIDTH 3 /* IN4R_HPMIXR_VOL - [2:0] */
+
+/*
+ * R105 (0x69) - Speaker Mixer (1)
+ */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA 0x0080 /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA_MASK 0x0080 /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA_SHIFT 7 /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA_WIDTH 1 /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_DACL_TO_SPKMIXL 0x0020 /* DACL_TO_SPKMIXL */
+#define WM8962_DACL_TO_SPKMIXL_MASK 0x0020 /* DACL_TO_SPKMIXL */
+#define WM8962_DACL_TO_SPKMIXL_SHIFT 5 /* DACL_TO_SPKMIXL */
+#define WM8962_DACL_TO_SPKMIXL_WIDTH 1 /* DACL_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL 0x0010 /* DACR_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL_MASK 0x0010 /* DACR_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL_SHIFT 4 /* DACR_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL_WIDTH 1 /* DACR_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL 0x0008 /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL_MASK 0x0008 /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL_SHIFT 3 /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL_WIDTH 1 /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL 0x0004 /* MIXINR_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL_MASK 0x0004 /* MIXINR_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL_SHIFT 2 /* MIXINR_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL_WIDTH 1 /* MIXINR_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL 0x0002 /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL_MASK 0x0002 /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL_SHIFT 1 /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL_WIDTH 1 /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL 0x0001 /* IN4R_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL_MASK 0x0001 /* IN4R_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL_SHIFT 0 /* IN4R_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL_WIDTH 1 /* IN4R_TO_SPKMIXL */
+
+/*
+ * R106 (0x6A) - Speaker Mixer (2)
+ */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA 0x0080 /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA_MASK 0x0080 /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA_SHIFT 7 /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA_WIDTH 1 /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_DACL_TO_SPKMIXR 0x0020 /* DACL_TO_SPKMIXR */
+#define WM8962_DACL_TO_SPKMIXR_MASK 0x0020 /* DACL_TO_SPKMIXR */
+#define WM8962_DACL_TO_SPKMIXR_SHIFT 5 /* DACL_TO_SPKMIXR */
+#define WM8962_DACL_TO_SPKMIXR_WIDTH 1 /* DACL_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR 0x0010 /* DACR_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR_MASK 0x0010 /* DACR_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR_SHIFT 4 /* DACR_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR_WIDTH 1 /* DACR_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR 0x0008 /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR_MASK 0x0008 /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR_SHIFT 3 /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR_WIDTH 1 /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR 0x0004 /* MIXINR_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR_MASK 0x0004 /* MIXINR_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR_SHIFT 2 /* MIXINR_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR_WIDTH 1 /* MIXINR_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR 0x0002 /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR_MASK 0x0002 /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR_SHIFT 1 /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR_WIDTH 1 /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR 0x0001 /* IN4R_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR_MASK 0x0001 /* IN4R_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR_SHIFT 0 /* IN4R_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR_WIDTH 1 /* IN4R_TO_SPKMIXR */
+
+/*
+ * R107 (0x6B) - Speaker Mixer (3)
+ */
+#define WM8962_SPKMIXL_MUTE 0x0100 /* SPKMIXL_MUTE */
+#define WM8962_SPKMIXL_MUTE_MASK 0x0100 /* SPKMIXL_MUTE */
+#define WM8962_SPKMIXL_MUTE_SHIFT 8 /* SPKMIXL_MUTE */
+#define WM8962_SPKMIXL_MUTE_WIDTH 1 /* SPKMIXL_MUTE */
+#define WM8962_MIXINL_SPKMIXL_VOL 0x0080 /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINL_SPKMIXL_VOL_MASK 0x0080 /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINL_SPKMIXL_VOL_SHIFT 7 /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINL_SPKMIXL_VOL_WIDTH 1 /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL 0x0040 /* MIXINR_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL_MASK 0x0040 /* MIXINR_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL_SHIFT 6 /* MIXINR_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL_WIDTH 1 /* MIXINR_SPKMIXL_VOL */
+#define WM8962_IN4L_SPKMIXL_VOL_MASK 0x0038 /* IN4L_SPKMIXL_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXL_VOL_SHIFT 3 /* IN4L_SPKMIXL_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXL_VOL_WIDTH 3 /* IN4L_SPKMIXL_VOL - [5:3] */
+#define WM8962_IN4R_SPKMIXL_VOL_MASK 0x0007 /* IN4R_SPKMIXL_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXL_VOL_SHIFT 0 /* IN4R_SPKMIXL_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXL_VOL_WIDTH 3 /* IN4R_SPKMIXL_VOL - [2:0] */
+
+/*
+ * R108 (0x6C) - Speaker Mixer (4)
+ */
+#define WM8962_SPKMIXR_MUTE 0x0100 /* SPKMIXR_MUTE */
+#define WM8962_SPKMIXR_MUTE_MASK 0x0100 /* SPKMIXR_MUTE */
+#define WM8962_SPKMIXR_MUTE_SHIFT 8 /* SPKMIXR_MUTE */
+#define WM8962_SPKMIXR_MUTE_WIDTH 1 /* SPKMIXR_MUTE */
+#define WM8962_MIXINL_SPKMIXR_VOL 0x0080 /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINL_SPKMIXR_VOL_MASK 0x0080 /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINL_SPKMIXR_VOL_SHIFT 7 /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINL_SPKMIXR_VOL_WIDTH 1 /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL 0x0040 /* MIXINR_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL_MASK 0x0040 /* MIXINR_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL_SHIFT 6 /* MIXINR_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL_WIDTH 1 /* MIXINR_SPKMIXR_VOL */
+#define WM8962_IN4L_SPKMIXR_VOL_MASK 0x0038 /* IN4L_SPKMIXR_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXR_VOL_SHIFT 3 /* IN4L_SPKMIXR_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXR_VOL_WIDTH 3 /* IN4L_SPKMIXR_VOL - [5:3] */
+#define WM8962_IN4R_SPKMIXR_VOL_MASK 0x0007 /* IN4R_SPKMIXR_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXR_VOL_SHIFT 0 /* IN4R_SPKMIXR_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXR_VOL_WIDTH 3 /* IN4R_SPKMIXR_VOL - [2:0] */
+
+/*
+ * R109 (0x6D) - Speaker Mixer (5)
+ */
+#define WM8962_DACL_SPKMIXL_VOL 0x0080 /* DACL_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXL_VOL_MASK 0x0080 /* DACL_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXL_VOL_SHIFT 7 /* DACL_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXL_VOL_WIDTH 1 /* DACL_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL 0x0040 /* DACR_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL_MASK 0x0040 /* DACR_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL_SHIFT 6 /* DACR_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL_WIDTH 1 /* DACR_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXR_VOL 0x0020 /* DACL_SPKMIXR_VOL */
+#define WM8962_DACL_SPKMIXR_VOL_MASK 0x0020 /* DACL_SPKMIXR_VOL */
+#define WM8962_DACL_SPKMIXR_VOL_SHIFT 5 /* DACL_SPKMIXR_VOL */
+#define WM8962_DACL_SPKMIXR_VOL_WIDTH 1 /* DACL_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL 0x0010 /* DACR_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL_MASK 0x0010 /* DACR_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL_SHIFT 4 /* DACR_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL_WIDTH 1 /* DACR_SPKMIXR_VOL */
+
+/*
+ * R110 (0x6E) - Beep Generator (1)
+ */
+#define WM8962_BEEP_GAIN_MASK 0x00F0 /* BEEP_GAIN - [7:4] */
+#define WM8962_BEEP_GAIN_SHIFT 4 /* BEEP_GAIN - [7:4] */
+#define WM8962_BEEP_GAIN_WIDTH 4 /* BEEP_GAIN - [7:4] */
+#define WM8962_BEEP_RATE_MASK 0x0006 /* BEEP_RATE - [2:1] */
+#define WM8962_BEEP_RATE_SHIFT 1 /* BEEP_RATE - [2:1] */
+#define WM8962_BEEP_RATE_WIDTH 2 /* BEEP_RATE - [2:1] */
+#define WM8962_BEEP_ENA 0x0001 /* BEEP_ENA */
+#define WM8962_BEEP_ENA_MASK 0x0001 /* BEEP_ENA */
+#define WM8962_BEEP_ENA_SHIFT 0 /* BEEP_ENA */
+#define WM8962_BEEP_ENA_WIDTH 1 /* BEEP_ENA */
+
+/*
+ * R115 (0x73) - Oscillator Trim (3)
+ */
+#define WM8962_OSC_TRIM_XTI_MASK 0x001F /* OSC_TRIM_XTI - [4:0] */
+#define WM8962_OSC_TRIM_XTI_SHIFT 0 /* OSC_TRIM_XTI - [4:0] */
+#define WM8962_OSC_TRIM_XTI_WIDTH 5 /* OSC_TRIM_XTI - [4:0] */
+
+/*
+ * R116 (0x74) - Oscillator Trim (4)
+ */
+#define WM8962_OSC_TRIM_XTO_MASK 0x001F /* OSC_TRIM_XTO - [4:0] */
+#define WM8962_OSC_TRIM_XTO_SHIFT 0 /* OSC_TRIM_XTO - [4:0] */
+#define WM8962_OSC_TRIM_XTO_WIDTH 5 /* OSC_TRIM_XTO - [4:0] */
+
+/*
+ * R119 (0x77) - Oscillator Trim (7)
+ */
+#define WM8962_XTO_CAP_SEL_MASK 0x00F0 /* XTO_CAP_SEL - [7:4] */
+#define WM8962_XTO_CAP_SEL_SHIFT 4 /* XTO_CAP_SEL - [7:4] */
+#define WM8962_XTO_CAP_SEL_WIDTH 4 /* XTO_CAP_SEL - [7:4] */
+#define WM8962_XTI_CAP_SEL_MASK 0x000F /* XTI_CAP_SEL - [3:0] */
+#define WM8962_XTI_CAP_SEL_SHIFT 0 /* XTI_CAP_SEL - [3:0] */
+#define WM8962_XTI_CAP_SEL_WIDTH 4 /* XTI_CAP_SEL - [3:0] */
+
+/*
+ * R124 (0x7C) - Analogue Clocking1
+ */
+#define WM8962_CLKOUT2_SEL_MASK 0x0060 /* CLKOUT2_SEL - [6:5] */
+#define WM8962_CLKOUT2_SEL_SHIFT 5 /* CLKOUT2_SEL - [6:5] */
+#define WM8962_CLKOUT2_SEL_WIDTH 2 /* CLKOUT2_SEL - [6:5] */
+#define WM8962_CLKOUT3_SEL_MASK 0x0018 /* CLKOUT3_SEL - [4:3] */
+#define WM8962_CLKOUT3_SEL_SHIFT 3 /* CLKOUT3_SEL - [4:3] */
+#define WM8962_CLKOUT3_SEL_WIDTH 2 /* CLKOUT3_SEL - [4:3] */
+#define WM8962_CLKOUT5_SEL 0x0001 /* CLKOUT5_SEL */
+#define WM8962_CLKOUT5_SEL_MASK 0x0001 /* CLKOUT5_SEL */
+#define WM8962_CLKOUT5_SEL_SHIFT 0 /* CLKOUT5_SEL */
+#define WM8962_CLKOUT5_SEL_WIDTH 1 /* CLKOUT5_SEL */
+
+/*
+ * R125 (0x7D) - Analogue Clocking2
+ */
+#define WM8962_PLL2_OUTDIV 0x0080 /* PLL2_OUTDIV */
+#define WM8962_PLL2_OUTDIV_MASK 0x0080 /* PLL2_OUTDIV */
+#define WM8962_PLL2_OUTDIV_SHIFT 7 /* PLL2_OUTDIV */
+#define WM8962_PLL2_OUTDIV_WIDTH 1 /* PLL2_OUTDIV */
+#define WM8962_PLL3_OUTDIV 0x0040 /* PLL3_OUTDIV */
+#define WM8962_PLL3_OUTDIV_MASK 0x0040 /* PLL3_OUTDIV */
+#define WM8962_PLL3_OUTDIV_SHIFT 6 /* PLL3_OUTDIV */
+#define WM8962_PLL3_OUTDIV_WIDTH 1 /* PLL3_OUTDIV */
+#define WM8962_PLL_SYSCLK_DIV_MASK 0x0018 /* PLL_SYSCLK_DIV - [4:3] */
+#define WM8962_PLL_SYSCLK_DIV_SHIFT 3 /* PLL_SYSCLK_DIV - [4:3] */
+#define WM8962_PLL_SYSCLK_DIV_WIDTH 2 /* PLL_SYSCLK_DIV - [4:3] */
+#define WM8962_CLKOUT3_DIV 0x0004 /* CLKOUT3_DIV */
+#define WM8962_CLKOUT3_DIV_MASK 0x0004 /* CLKOUT3_DIV */
+#define WM8962_CLKOUT3_DIV_SHIFT 2 /* CLKOUT3_DIV */
+#define WM8962_CLKOUT3_DIV_WIDTH 1 /* CLKOUT3_DIV */
+#define WM8962_CLKOUT2_DIV 0x0002 /* CLKOUT2_DIV */
+#define WM8962_CLKOUT2_DIV_MASK 0x0002 /* CLKOUT2_DIV */
+#define WM8962_CLKOUT2_DIV_SHIFT 1 /* CLKOUT2_DIV */
+#define WM8962_CLKOUT2_DIV_WIDTH 1 /* CLKOUT2_DIV */
+#define WM8962_CLKOUT5_DIV 0x0001 /* CLKOUT5_DIV */
+#define WM8962_CLKOUT5_DIV_MASK 0x0001 /* CLKOUT5_DIV */
+#define WM8962_CLKOUT5_DIV_SHIFT 0 /* CLKOUT5_DIV */
+#define WM8962_CLKOUT5_DIV_WIDTH 1 /* CLKOUT5_DIV */
+
+/*
+ * R126 (0x7E) - Analogue Clocking3
+ */
+#define WM8962_CLKOUT2_OE 0x0008 /* CLKOUT2_OE */
+#define WM8962_CLKOUT2_OE_MASK 0x0008 /* CLKOUT2_OE */
+#define WM8962_CLKOUT2_OE_SHIFT 3 /* CLKOUT2_OE */
+#define WM8962_CLKOUT2_OE_WIDTH 1 /* CLKOUT2_OE */
+#define WM8962_CLKOUT3_OE 0x0004 /* CLKOUT3_OE */
+#define WM8962_CLKOUT3_OE_MASK 0x0004 /* CLKOUT3_OE */
+#define WM8962_CLKOUT3_OE_SHIFT 2 /* CLKOUT3_OE */
+#define WM8962_CLKOUT3_OE_WIDTH 1 /* CLKOUT3_OE */
+#define WM8962_CLKOUT5_OE 0x0001 /* CLKOUT5_OE */
+#define WM8962_CLKOUT5_OE_MASK 0x0001 /* CLKOUT5_OE */
+#define WM8962_CLKOUT5_OE_SHIFT 0 /* CLKOUT5_OE */
+#define WM8962_CLKOUT5_OE_WIDTH 1 /* CLKOUT5_OE */
+
+/*
+ * R127 (0x7F) - PLL Software Reset
+ */
+#define WM8962_SW_RESET_PLL_MASK 0xFFFF /* SW_RESET_PLL - [15:0] */
+#define WM8962_SW_RESET_PLL_SHIFT 0 /* SW_RESET_PLL - [15:0] */
+#define WM8962_SW_RESET_PLL_WIDTH 16 /* SW_RESET_PLL - [15:0] */
+
+/*
+ * R129 (0x81) - PLL2
+ */
+#define WM8962_OSC_ENA 0x0080 /* OSC_ENA */
+#define WM8962_OSC_ENA_MASK 0x0080 /* OSC_ENA */
+#define WM8962_OSC_ENA_SHIFT 7 /* OSC_ENA */
+#define WM8962_OSC_ENA_WIDTH 1 /* OSC_ENA */
+#define WM8962_PLL2_ENA 0x0020 /* PLL2_ENA */
+#define WM8962_PLL2_ENA_MASK 0x0020 /* PLL2_ENA */
+#define WM8962_PLL2_ENA_SHIFT 5 /* PLL2_ENA */
+#define WM8962_PLL2_ENA_WIDTH 1 /* PLL2_ENA */
+#define WM8962_PLL3_ENA 0x0010 /* PLL3_ENA */
+#define WM8962_PLL3_ENA_MASK 0x0010 /* PLL3_ENA */
+#define WM8962_PLL3_ENA_SHIFT 4 /* PLL3_ENA */
+#define WM8962_PLL3_ENA_WIDTH 1 /* PLL3_ENA */
+
+/*
+ * R131 (0x83) - PLL 4
+ */
+#define WM8962_PLL_CLK_SRC 0x0002 /* PLL_CLK_SRC */
+#define WM8962_PLL_CLK_SRC_MASK 0x0002 /* PLL_CLK_SRC */
+#define WM8962_PLL_CLK_SRC_SHIFT 1 /* PLL_CLK_SRC */
+#define WM8962_PLL_CLK_SRC_WIDTH 1 /* PLL_CLK_SRC */
+#define WM8962_FLL_TO_PLL3 0x0001 /* FLL_TO_PLL3 */
+#define WM8962_FLL_TO_PLL3_MASK 0x0001 /* FLL_TO_PLL3 */
+#define WM8962_FLL_TO_PLL3_SHIFT 0 /* FLL_TO_PLL3 */
+#define WM8962_FLL_TO_PLL3_WIDTH 1 /* FLL_TO_PLL3 */
+
+/*
+ * R136 (0x88) - PLL 9
+ */
+#define WM8962_PLL2_FRAC 0x0040 /* PLL2_FRAC */
+#define WM8962_PLL2_FRAC_MASK 0x0040 /* PLL2_FRAC */
+#define WM8962_PLL2_FRAC_SHIFT 6 /* PLL2_FRAC */
+#define WM8962_PLL2_FRAC_WIDTH 1 /* PLL2_FRAC */
+#define WM8962_PLL2_N_MASK 0x001F /* PLL2_N - [4:0] */
+#define WM8962_PLL2_N_SHIFT 0 /* PLL2_N - [4:0] */
+#define WM8962_PLL2_N_WIDTH 5 /* PLL2_N - [4:0] */
+
+/*
+ * R137 (0x89) - PLL 10
+ */
+#define WM8962_PLL2_K_MASK 0x00FF /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_SHIFT 0 /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_WIDTH 8 /* PLL2_K - [7:0] */
+
+/*
+ * R138 (0x8A) - PLL 11
+ */
+#define WM8962_PLL2_K_MASK 0x00FF /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_SHIFT 0 /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_WIDTH 8 /* PLL2_K - [7:0] */
+
+/*
+ * R139 (0x8B) - PLL 12
+ */
+#define WM8962_PLL2_K_MASK 0x00FF /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_SHIFT 0 /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_WIDTH 8 /* PLL2_K - [7:0] */
+
+/*
+ * R140 (0x8C) - PLL 13
+ */
+#define WM8962_PLL3_FRAC 0x0040 /* PLL3_FRAC */
+#define WM8962_PLL3_FRAC_MASK 0x0040 /* PLL3_FRAC */
+#define WM8962_PLL3_FRAC_SHIFT 6 /* PLL3_FRAC */
+#define WM8962_PLL3_FRAC_WIDTH 1 /* PLL3_FRAC */
+#define WM8962_PLL3_N_MASK 0x001F /* PLL3_N - [4:0] */
+#define WM8962_PLL3_N_SHIFT 0 /* PLL3_N - [4:0] */
+#define WM8962_PLL3_N_WIDTH 5 /* PLL3_N - [4:0] */
+
+/*
+ * R141 (0x8D) - PLL 14
+ */
+#define WM8962_PLL3_K_MASK 0x00FF /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_SHIFT 0 /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_WIDTH 8 /* PLL3_K - [7:0] */
+
+/*
+ * R142 (0x8E) - PLL 15
+ */
+#define WM8962_PLL3_K_MASK 0x00FF /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_SHIFT 0 /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_WIDTH 8 /* PLL3_K - [7:0] */
+
+/*
+ * R143 (0x8F) - PLL 16
+ */
+#define WM8962_PLL3_K_MASK 0x00FF /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_SHIFT 0 /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_WIDTH 8 /* PLL3_K - [7:0] */
+
+/*
+ * R155 (0x9B) - FLL Control (1)
+ */
+#define WM8962_FLL_REFCLK_SRC_MASK 0x0060 /* FLL_REFCLK_SRC - [6:5] */
+#define WM8962_FLL_REFCLK_SRC_SHIFT 5 /* FLL_REFCLK_SRC - [6:5] */
+#define WM8962_FLL_REFCLK_SRC_WIDTH 2 /* FLL_REFCLK_SRC - [6:5] */
+#define WM8962_FLL_FRAC 0x0004 /* FLL_FRAC */
+#define WM8962_FLL_FRAC_MASK 0x0004 /* FLL_FRAC */
+#define WM8962_FLL_FRAC_SHIFT 2 /* FLL_FRAC */
+#define WM8962_FLL_FRAC_WIDTH 1 /* FLL_FRAC */
+#define WM8962_FLL_OSC_ENA 0x0002 /* FLL_OSC_ENA */
+#define WM8962_FLL_OSC_ENA_MASK 0x0002 /* FLL_OSC_ENA */
+#define WM8962_FLL_OSC_ENA_SHIFT 1 /* FLL_OSC_ENA */
+#define WM8962_FLL_OSC_ENA_WIDTH 1 /* FLL_OSC_ENA */
+#define WM8962_FLL_ENA 0x0001 /* FLL_ENA */
+#define WM8962_FLL_ENA_MASK 0x0001 /* FLL_ENA */
+#define WM8962_FLL_ENA_SHIFT 0 /* FLL_ENA */
+#define WM8962_FLL_ENA_WIDTH 1 /* FLL_ENA */
+
+/*
+ * R156 (0x9C) - FLL Control (2)
+ */
+#define WM8962_FLL_OUTDIV_MASK 0x01F8 /* FLL_OUTDIV - [8:3] */
+#define WM8962_FLL_OUTDIV_SHIFT 3 /* FLL_OUTDIV - [8:3] */
+#define WM8962_FLL_OUTDIV_WIDTH 6 /* FLL_OUTDIV - [8:3] */
+#define WM8962_FLL_REFCLK_DIV_MASK 0x0003 /* FLL_REFCLK_DIV - [1:0] */
+#define WM8962_FLL_REFCLK_DIV_SHIFT 0 /* FLL_REFCLK_DIV - [1:0] */
+#define WM8962_FLL_REFCLK_DIV_WIDTH 2 /* FLL_REFCLK_DIV - [1:0] */
+
+/*
+ * R157 (0x9D) - FLL Control (3)
+ */
+#define WM8962_FLL_FRATIO_MASK 0x0007 /* FLL_FRATIO - [2:0] */
+#define WM8962_FLL_FRATIO_SHIFT 0 /* FLL_FRATIO - [2:0] */
+#define WM8962_FLL_FRATIO_WIDTH 3 /* FLL_FRATIO - [2:0] */
+
+/*
+ * R159 (0x9F) - FLL Control (5)
+ */
+#define WM8962_FLL_FRC_NCO_VAL_MASK 0x007E /* FLL_FRC_NCO_VAL - [6:1] */
+#define WM8962_FLL_FRC_NCO_VAL_SHIFT 1 /* FLL_FRC_NCO_VAL - [6:1] */
+#define WM8962_FLL_FRC_NCO_VAL_WIDTH 6 /* FLL_FRC_NCO_VAL - [6:1] */
+#define WM8962_FLL_FRC_NCO 0x0001 /* FLL_FRC_NCO */
+#define WM8962_FLL_FRC_NCO_MASK 0x0001 /* FLL_FRC_NCO */
+#define WM8962_FLL_FRC_NCO_SHIFT 0 /* FLL_FRC_NCO */
+#define WM8962_FLL_FRC_NCO_WIDTH 1 /* FLL_FRC_NCO */
+
+/*
+ * R160 (0xA0) - FLL Control (6)
+ */
+#define WM8962_FLL_THETA_MASK 0xFFFF /* FLL_THETA - [15:0] */
+#define WM8962_FLL_THETA_SHIFT 0 /* FLL_THETA - [15:0] */
+#define WM8962_FLL_THETA_WIDTH 16 /* FLL_THETA - [15:0] */
+
+/*
+ * R161 (0xA1) - FLL Control (7)
+ */
+#define WM8962_FLL_LAMBDA_MASK 0xFFFF /* FLL_LAMBDA - [15:0] */
+#define WM8962_FLL_LAMBDA_SHIFT 0 /* FLL_LAMBDA - [15:0] */
+#define WM8962_FLL_LAMBDA_WIDTH 16 /* FLL_LAMBDA - [15:0] */
+
+/*
+ * R162 (0xA2) - FLL Control (8)
+ */
+#define WM8962_FLL_N_MASK 0x03FF /* FLL_N - [9:0] */
+#define WM8962_FLL_N_SHIFT 0 /* FLL_N - [9:0] */
+#define WM8962_FLL_N_WIDTH 10 /* FLL_N - [9:0] */
+
+/*
+ * R252 (0xFC) - General test 1
+ */
+#define WM8962_REG_SYNC 0x0004 /* REG_SYNC */
+#define WM8962_REG_SYNC_MASK 0x0004 /* REG_SYNC */
+#define WM8962_REG_SYNC_SHIFT 2 /* REG_SYNC */
+#define WM8962_REG_SYNC_WIDTH 1 /* REG_SYNC */
+#define WM8962_AUTO_INC 0x0001 /* AUTO_INC */
+#define WM8962_AUTO_INC_MASK 0x0001 /* AUTO_INC */
+#define WM8962_AUTO_INC_SHIFT 0 /* AUTO_INC */
+#define WM8962_AUTO_INC_WIDTH 1 /* AUTO_INC */
+
+/*
+ * R256 (0x100) - DF1
+ */
+#define WM8962_DRC_DF1_ENA 0x0008 /* DRC_DF1_ENA */
+#define WM8962_DRC_DF1_ENA_MASK 0x0008 /* DRC_DF1_ENA */
+#define WM8962_DRC_DF1_ENA_SHIFT 3 /* DRC_DF1_ENA */
+#define WM8962_DRC_DF1_ENA_WIDTH 1 /* DRC_DF1_ENA */
+#define WM8962_DF1_SHARED_COEFF 0x0004 /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_MASK 0x0004 /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_SHIFT 2 /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_WIDTH 1 /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_SEL 0x0002 /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_SHARED_COEFF_SEL_MASK 0x0002 /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_SHARED_COEFF_SEL_SHIFT 1 /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_SHARED_COEFF_SEL_WIDTH 1 /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_ENA 0x0001 /* DF1_ENA */
+#define WM8962_DF1_ENA_MASK 0x0001 /* DF1_ENA */
+#define WM8962_DF1_ENA_SHIFT 0 /* DF1_ENA */
+#define WM8962_DF1_ENA_WIDTH 1 /* DF1_ENA */
+
+/*
+ * R257 (0x101) - DF2
+ */
+#define WM8962_DF1_COEFF_L0_MASK 0xFFFF /* DF1_COEFF_L0 - [15:0] */
+#define WM8962_DF1_COEFF_L0_SHIFT 0 /* DF1_COEFF_L0 - [15:0] */
+#define WM8962_DF1_COEFF_L0_WIDTH 16 /* DF1_COEFF_L0 - [15:0] */
+
+/*
+ * R258 (0x102) - DF3
+ */
+#define WM8962_DF1_COEFF_L1_MASK 0xFFFF /* DF1_COEFF_L1 - [15:0] */
+#define WM8962_DF1_COEFF_L1_SHIFT 0 /* DF1_COEFF_L1 - [15:0] */
+#define WM8962_DF1_COEFF_L1_WIDTH 16 /* DF1_COEFF_L1 - [15:0] */
+
+/*
+ * R259 (0x103) - DF4
+ */
+#define WM8962_DF1_COEFF_L2_MASK 0xFFFF /* DF1_COEFF_L2 - [15:0] */
+#define WM8962_DF1_COEFF_L2_SHIFT 0 /* DF1_COEFF_L2 - [15:0] */
+#define WM8962_DF1_COEFF_L2_WIDTH 16 /* DF1_COEFF_L2 - [15:0] */
+
+/*
+ * R260 (0x104) - DF5
+ */
+#define WM8962_DF1_COEFF_R0_MASK 0xFFFF /* DF1_COEFF_R0 - [15:0] */
+#define WM8962_DF1_COEFF_R0_SHIFT 0 /* DF1_COEFF_R0 - [15:0] */
+#define WM8962_DF1_COEFF_R0_WIDTH 16 /* DF1_COEFF_R0 - [15:0] */
+
+/*
+ * R261 (0x105) - DF6
+ */
+#define WM8962_DF1_COEFF_R1_MASK 0xFFFF /* DF1_COEFF_R1 - [15:0] */
+#define WM8962_DF1_COEFF_R1_SHIFT 0 /* DF1_COEFF_R1 - [15:0] */
+#define WM8962_DF1_COEFF_R1_WIDTH 16 /* DF1_COEFF_R1 - [15:0] */
+
+/*
+ * R262 (0x106) - DF7
+ */
+#define WM8962_DF1_COEFF_R2_MASK 0xFFFF /* DF1_COEFF_R2 - [15:0] */
+#define WM8962_DF1_COEFF_R2_SHIFT 0 /* DF1_COEFF_R2 - [15:0] */
+#define WM8962_DF1_COEFF_R2_WIDTH 16 /* DF1_COEFF_R2 - [15:0] */
+
+/*
+ * R264 (0x108) - LHPF1
+ */
+#define WM8962_LHPF_MODE 0x0002 /* LHPF_MODE */
+#define WM8962_LHPF_MODE_MASK 0x0002 /* LHPF_MODE */
+#define WM8962_LHPF_MODE_SHIFT 1 /* LHPF_MODE */
+#define WM8962_LHPF_MODE_WIDTH 1 /* LHPF_MODE */
+#define WM8962_LHPF_ENA 0x0001 /* LHPF_ENA */
+#define WM8962_LHPF_ENA_MASK 0x0001 /* LHPF_ENA */
+#define WM8962_LHPF_ENA_SHIFT 0 /* LHPF_ENA */
+#define WM8962_LHPF_ENA_WIDTH 1 /* LHPF_ENA */
+
+/*
+ * R265 (0x109) - LHPF2
+ */
+#define WM8962_LHPF_COEFF_MASK 0xFFFF /* LHPF_COEFF - [15:0] */
+#define WM8962_LHPF_COEFF_SHIFT 0 /* LHPF_COEFF - [15:0] */
+#define WM8962_LHPF_COEFF_WIDTH 16 /* LHPF_COEFF - [15:0] */
+
+/*
+ * R268 (0x10C) - THREED1
+ */
+#define WM8962_ADC_MONOMIX 0x0040 /* ADC_MONOMIX */
+#define WM8962_ADC_MONOMIX_MASK 0x0040 /* ADC_MONOMIX */
+#define WM8962_ADC_MONOMIX_SHIFT 6 /* ADC_MONOMIX */
+#define WM8962_ADC_MONOMIX_WIDTH 1 /* ADC_MONOMIX */
+#define WM8962_THREED_SIGN_L 0x0020 /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_L_MASK 0x0020 /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_L_SHIFT 5 /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_L_WIDTH 1 /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_R 0x0010 /* THREED_SIGN_R */
+#define WM8962_THREED_SIGN_R_MASK 0x0010 /* THREED_SIGN_R */
+#define WM8962_THREED_SIGN_R_SHIFT 4 /* THREED_SIGN_R */
+#define WM8962_THREED_SIGN_R_WIDTH 1 /* THREED_SIGN_R */
+#define WM8962_THREED_LHPF_MODE 0x0004 /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_MODE_MASK 0x0004 /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_MODE_SHIFT 2 /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_MODE_WIDTH 1 /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_ENA 0x0002 /* THREED_LHPF_ENA */
+#define WM8962_THREED_LHPF_ENA_MASK 0x0002 /* THREED_LHPF_ENA */
+#define WM8962_THREED_LHPF_ENA_SHIFT 1 /* THREED_LHPF_ENA */
+#define WM8962_THREED_LHPF_ENA_WIDTH 1 /* THREED_LHPF_ENA */
+#define WM8962_THREED_ENA 0x0001 /* THREED_ENA */
+#define WM8962_THREED_ENA_MASK 0x0001 /* THREED_ENA */
+#define WM8962_THREED_ENA_SHIFT 0 /* THREED_ENA */
+#define WM8962_THREED_ENA_WIDTH 1 /* THREED_ENA */
+
+/*
+ * R269 (0x10D) - THREED2
+ */
+#define WM8962_THREED_FGAINL_MASK 0xF800 /* THREED_FGAINL - [15:11] */
+#define WM8962_THREED_FGAINL_SHIFT 11 /* THREED_FGAINL - [15:11] */
+#define WM8962_THREED_FGAINL_WIDTH 5 /* THREED_FGAINL - [15:11] */
+#define WM8962_THREED_CGAINL_MASK 0x07C0 /* THREED_CGAINL - [10:6] */
+#define WM8962_THREED_CGAINL_SHIFT 6 /* THREED_CGAINL - [10:6] */
+#define WM8962_THREED_CGAINL_WIDTH 5 /* THREED_CGAINL - [10:6] */
+#define WM8962_THREED_DELAYL_MASK 0x003C /* THREED_DELAYL - [5:2] */
+#define WM8962_THREED_DELAYL_SHIFT 2 /* THREED_DELAYL - [5:2] */
+#define WM8962_THREED_DELAYL_WIDTH 4 /* THREED_DELAYL - [5:2] */
+
+/*
+ * R270 (0x10E) - THREED3
+ */
+#define WM8962_THREED_LHPF_COEFF_MASK 0xFFFF /* THREED_LHPF_COEFF - [15:0] */
+#define WM8962_THREED_LHPF_COEFF_SHIFT 0 /* THREED_LHPF_COEFF - [15:0] */
+#define WM8962_THREED_LHPF_COEFF_WIDTH 16 /* THREED_LHPF_COEFF - [15:0] */
+
+/*
+ * R271 (0x10F) - THREED4
+ */
+#define WM8962_THREED_FGAINR_MASK 0xF800 /* THREED_FGAINR - [15:11] */
+#define WM8962_THREED_FGAINR_SHIFT 11 /* THREED_FGAINR - [15:11] */
+#define WM8962_THREED_FGAINR_WIDTH 5 /* THREED_FGAINR - [15:11] */
+#define WM8962_THREED_CGAINR_MASK 0x07C0 /* THREED_CGAINR - [10:6] */
+#define WM8962_THREED_CGAINR_SHIFT 6 /* THREED_CGAINR - [10:6] */
+#define WM8962_THREED_CGAINR_WIDTH 5 /* THREED_CGAINR - [10:6] */
+#define WM8962_THREED_DELAYR_MASK 0x003C /* THREED_DELAYR - [5:2] */
+#define WM8962_THREED_DELAYR_SHIFT 2 /* THREED_DELAYR - [5:2] */
+#define WM8962_THREED_DELAYR_WIDTH 4 /* THREED_DELAYR - [5:2] */
+
+/*
+ * R276 (0x114) - DRC 1
+ */
+#define WM8962_DRC_SIG_DET_RMS_MASK 0x7C00 /* DRC_SIG_DET_RMS - [14:10] */
+#define WM8962_DRC_SIG_DET_RMS_SHIFT 10 /* DRC_SIG_DET_RMS - [14:10] */
+#define WM8962_DRC_SIG_DET_RMS_WIDTH 5 /* DRC_SIG_DET_RMS - [14:10] */
+#define WM8962_DRC_SIG_DET_PK_MASK 0x0300 /* DRC_SIG_DET_PK - [9:8] */
+#define WM8962_DRC_SIG_DET_PK_SHIFT 8 /* DRC_SIG_DET_PK - [9:8] */
+#define WM8962_DRC_SIG_DET_PK_WIDTH 2 /* DRC_SIG_DET_PK - [9:8] */
+#define WM8962_DRC_NG_ENA 0x0080 /* DRC_NG_ENA */
+#define WM8962_DRC_NG_ENA_MASK 0x0080 /* DRC_NG_ENA */
+#define WM8962_DRC_NG_ENA_SHIFT 7 /* DRC_NG_ENA */
+#define WM8962_DRC_NG_ENA_WIDTH 1 /* DRC_NG_ENA */
+#define WM8962_DRC_SIG_DET_MODE 0x0040 /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET_MODE_MASK 0x0040 /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET_MODE_SHIFT 6 /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET_MODE_WIDTH 1 /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET 0x0020 /* DRC_SIG_DET */
+#define WM8962_DRC_SIG_DET_MASK 0x0020 /* DRC_SIG_DET */
+#define WM8962_DRC_SIG_DET_SHIFT 5 /* DRC_SIG_DET */
+#define WM8962_DRC_SIG_DET_WIDTH 1 /* DRC_SIG_DET */
+#define WM8962_DRC_KNEE2_OP_ENA 0x0010 /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_KNEE2_OP_ENA_MASK 0x0010 /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_KNEE2_OP_ENA_SHIFT 4 /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_KNEE2_OP_ENA_WIDTH 1 /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_QR 0x0008 /* DRC_QR */
+#define WM8962_DRC_QR_MASK 0x0008 /* DRC_QR */
+#define WM8962_DRC_QR_SHIFT 3 /* DRC_QR */
+#define WM8962_DRC_QR_WIDTH 1 /* DRC_QR */
+#define WM8962_DRC_ANTICLIP 0x0004 /* DRC_ANTICLIP */
+#define WM8962_DRC_ANTICLIP_MASK 0x0004 /* DRC_ANTICLIP */
+#define WM8962_DRC_ANTICLIP_SHIFT 2 /* DRC_ANTICLIP */
+#define WM8962_DRC_ANTICLIP_WIDTH 1 /* DRC_ANTICLIP */
+#define WM8962_DRC_MODE 0x0002 /* DRC_MODE */
+#define WM8962_DRC_MODE_MASK 0x0002 /* DRC_MODE */
+#define WM8962_DRC_MODE_SHIFT 1 /* DRC_MODE */
+#define WM8962_DRC_MODE_WIDTH 1 /* DRC_MODE */
+#define WM8962_DRC_ENA 0x0001 /* DRC_ENA */
+#define WM8962_DRC_ENA_MASK 0x0001 /* DRC_ENA */
+#define WM8962_DRC_ENA_SHIFT 0 /* DRC_ENA */
+#define WM8962_DRC_ENA_WIDTH 1 /* DRC_ENA */
+
+/*
+ * R277 (0x115) - DRC 2
+ */
+#define WM8962_DRC_ATK_MASK 0x1E00 /* DRC_ATK - [12:9] */
+#define WM8962_DRC_ATK_SHIFT 9 /* DRC_ATK - [12:9] */
+#define WM8962_DRC_ATK_WIDTH 4 /* DRC_ATK - [12:9] */
+#define WM8962_DRC_DCY_MASK 0x01E0 /* DRC_DCY - [8:5] */
+#define WM8962_DRC_DCY_SHIFT 5 /* DRC_DCY - [8:5] */
+#define WM8962_DRC_DCY_WIDTH 4 /* DRC_DCY - [8:5] */
+#define WM8962_DRC_MINGAIN_MASK 0x001C /* DRC_MINGAIN - [4:2] */
+#define WM8962_DRC_MINGAIN_SHIFT 2 /* DRC_MINGAIN - [4:2] */
+#define WM8962_DRC_MINGAIN_WIDTH 3 /* DRC_MINGAIN - [4:2] */
+#define WM8962_DRC_MAXGAIN_MASK 0x0003 /* DRC_MAXGAIN - [1:0] */
+#define WM8962_DRC_MAXGAIN_SHIFT 0 /* DRC_MAXGAIN - [1:0] */
+#define WM8962_DRC_MAXGAIN_WIDTH 2 /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R278 (0x116) - DRC 3
+ */
+#define WM8962_DRC_NG_MINGAIN_MASK 0xF000 /* DRC_NG_MINGAIN - [15:12] */
+#define WM8962_DRC_NG_MINGAIN_SHIFT 12 /* DRC_NG_MINGAIN - [15:12] */
+#define WM8962_DRC_NG_MINGAIN_WIDTH 4 /* DRC_NG_MINGAIN - [15:12] */
+#define WM8962_DRC_QR_THR_MASK 0x0C00 /* DRC_QR_THR - [11:10] */
+#define WM8962_DRC_QR_THR_SHIFT 10 /* DRC_QR_THR - [11:10] */
+#define WM8962_DRC_QR_THR_WIDTH 2 /* DRC_QR_THR - [11:10] */
+#define WM8962_DRC_QR_DCY_MASK 0x0300 /* DRC_QR_DCY - [9:8] */
+#define WM8962_DRC_QR_DCY_SHIFT 8 /* DRC_QR_DCY - [9:8] */
+#define WM8962_DRC_QR_DCY_WIDTH 2 /* DRC_QR_DCY - [9:8] */
+#define WM8962_DRC_NG_EXP_MASK 0x00C0 /* DRC_NG_EXP - [7:6] */
+#define WM8962_DRC_NG_EXP_SHIFT 6 /* DRC_NG_EXP - [7:6] */
+#define WM8962_DRC_NG_EXP_WIDTH 2 /* DRC_NG_EXP - [7:6] */
+#define WM8962_DRC_HI_COMP_MASK 0x0038 /* DRC_HI_COMP - [5:3] */
+#define WM8962_DRC_HI_COMP_SHIFT 3 /* DRC_HI_COMP - [5:3] */
+#define WM8962_DRC_HI_COMP_WIDTH 3 /* DRC_HI_COMP - [5:3] */
+#define WM8962_DRC_LO_COMP_MASK 0x0007 /* DRC_LO_COMP - [2:0] */
+#define WM8962_DRC_LO_COMP_SHIFT 0 /* DRC_LO_COMP - [2:0] */
+#define WM8962_DRC_LO_COMP_WIDTH 3 /* DRC_LO_COMP - [2:0] */
+
+/*
+ * R279 (0x117) - DRC 4
+ */
+#define WM8962_DRC_KNEE_IP_MASK 0x07E0 /* DRC_KNEE_IP - [10:5] */
+#define WM8962_DRC_KNEE_IP_SHIFT 5 /* DRC_KNEE_IP - [10:5] */
+#define WM8962_DRC_KNEE_IP_WIDTH 6 /* DRC_KNEE_IP - [10:5] */
+#define WM8962_DRC_KNEE_OP_MASK 0x001F /* DRC_KNEE_OP - [4:0] */
+#define WM8962_DRC_KNEE_OP_SHIFT 0 /* DRC_KNEE_OP - [4:0] */
+#define WM8962_DRC_KNEE_OP_WIDTH 5 /* DRC_KNEE_OP - [4:0] */
+
+/*
+ * R280 (0x118) - DRC 5
+ */
+#define WM8962_DRC_KNEE2_IP_MASK 0x03E0 /* DRC_KNEE2_IP - [9:5] */
+#define WM8962_DRC_KNEE2_IP_SHIFT 5 /* DRC_KNEE2_IP - [9:5] */
+#define WM8962_DRC_KNEE2_IP_WIDTH 5 /* DRC_KNEE2_IP - [9:5] */
+#define WM8962_DRC_KNEE2_OP_MASK 0x001F /* DRC_KNEE2_OP - [4:0] */
+#define WM8962_DRC_KNEE2_OP_SHIFT 0 /* DRC_KNEE2_OP - [4:0] */
+#define WM8962_DRC_KNEE2_OP_WIDTH 5 /* DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R285 (0x11D) - Tloopback
+ */
+#define WM8962_TLB_ENA 0x0002 /* TLB_ENA */
+#define WM8962_TLB_ENA_MASK 0x0002 /* TLB_ENA */
+#define WM8962_TLB_ENA_SHIFT 1 /* TLB_ENA */
+#define WM8962_TLB_ENA_WIDTH 1 /* TLB_ENA */
+#define WM8962_TLB_MODE 0x0001 /* TLB_MODE */
+#define WM8962_TLB_MODE_MASK 0x0001 /* TLB_MODE */
+#define WM8962_TLB_MODE_SHIFT 0 /* TLB_MODE */
+#define WM8962_TLB_MODE_WIDTH 1 /* TLB_MODE */
+
+/*
+ * R335 (0x14F) - EQ1
+ */
+#define WM8962_EQ_SHARED_COEFF 0x0004 /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_MASK 0x0004 /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_SHIFT 2 /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_WIDTH 1 /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_SEL 0x0002 /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_SHARED_COEFF_SEL_MASK 0x0002 /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_SHARED_COEFF_SEL_SHIFT 1 /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_SHARED_COEFF_SEL_WIDTH 1 /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_ENA 0x0001 /* EQ_ENA */
+#define WM8962_EQ_ENA_MASK 0x0001 /* EQ_ENA */
+#define WM8962_EQ_ENA_SHIFT 0 /* EQ_ENA */
+#define WM8962_EQ_ENA_WIDTH 1 /* EQ_ENA */
+
+/*
+ * R336 (0x150) - EQ2
+ */
+#define WM8962_EQL_B1_GAIN_MASK 0xF800 /* EQL_B1_GAIN - [15:11] */
+#define WM8962_EQL_B1_GAIN_SHIFT 11 /* EQL_B1_GAIN - [15:11] */
+#define WM8962_EQL_B1_GAIN_WIDTH 5 /* EQL_B1_GAIN - [15:11] */
+#define WM8962_EQL_B2_GAIN_MASK 0x07C0 /* EQL_B2_GAIN - [10:6] */
+#define WM8962_EQL_B2_GAIN_SHIFT 6 /* EQL_B2_GAIN - [10:6] */
+#define WM8962_EQL_B2_GAIN_WIDTH 5 /* EQL_B2_GAIN - [10:6] */
+#define WM8962_EQL_B3_GAIN_MASK 0x003E /* EQL_B3_GAIN - [5:1] */
+#define WM8962_EQL_B3_GAIN_SHIFT 1 /* EQL_B3_GAIN - [5:1] */
+#define WM8962_EQL_B3_GAIN_WIDTH 5 /* EQL_B3_GAIN - [5:1] */
+
+/*
+ * R337 (0x151) - EQ3
+ */
+#define WM8962_EQL_B4_GAIN_MASK 0xF800 /* EQL_B4_GAIN - [15:11] */
+#define WM8962_EQL_B4_GAIN_SHIFT 11 /* EQL_B4_GAIN - [15:11] */
+#define WM8962_EQL_B4_GAIN_WIDTH 5 /* EQL_B4_GAIN - [15:11] */
+#define WM8962_EQL_B5_GAIN_MASK 0x07C0 /* EQL_B5_GAIN - [10:6] */
+#define WM8962_EQL_B5_GAIN_SHIFT 6 /* EQL_B5_GAIN - [10:6] */
+#define WM8962_EQL_B5_GAIN_WIDTH 5 /* EQL_B5_GAIN - [10:6] */
+
+/*
+ * R338 (0x152) - EQ4
+ */
+#define WM8962_EQL_B1_A_MASK 0xFFFF /* EQL_B1_A - [15:0] */
+#define WM8962_EQL_B1_A_SHIFT 0 /* EQL_B1_A - [15:0] */
+#define WM8962_EQL_B1_A_WIDTH 16 /* EQL_B1_A - [15:0] */
+
+/*
+ * R339 (0x153) - EQ5
+ */
+#define WM8962_EQL_B1_B_MASK 0xFFFF /* EQL_B1_B - [15:0] */
+#define WM8962_EQL_B1_B_SHIFT 0 /* EQL_B1_B - [15:0] */
+#define WM8962_EQL_B1_B_WIDTH 16 /* EQL_B1_B - [15:0] */
+
+/*
+ * R340 (0x154) - EQ6
+ */
+#define WM8962_EQL_B1_PG_MASK 0xFFFF /* EQL_B1_PG - [15:0] */
+#define WM8962_EQL_B1_PG_SHIFT 0 /* EQL_B1_PG - [15:0] */
+#define WM8962_EQL_B1_PG_WIDTH 16 /* EQL_B1_PG - [15:0] */
+
+/*
+ * R341 (0x155) - EQ7
+ */
+#define WM8962_EQL_B2_A_MASK 0xFFFF /* EQL_B2_A - [15:0] */
+#define WM8962_EQL_B2_A_SHIFT 0 /* EQL_B2_A - [15:0] */
+#define WM8962_EQL_B2_A_WIDTH 16 /* EQL_B2_A - [15:0] */
+
+/*
+ * R342 (0x156) - EQ8
+ */
+#define WM8962_EQL_B2_B_MASK 0xFFFF /* EQL_B2_B - [15:0] */
+#define WM8962_EQL_B2_B_SHIFT 0 /* EQL_B2_B - [15:0] */
+#define WM8962_EQL_B2_B_WIDTH 16 /* EQL_B2_B - [15:0] */
+
+/*
+ * R343 (0x157) - EQ9
+ */
+#define WM8962_EQL_B2_C_MASK 0xFFFF /* EQL_B2_C - [15:0] */
+#define WM8962_EQL_B2_C_SHIFT 0 /* EQL_B2_C - [15:0] */
+#define WM8962_EQL_B2_C_WIDTH 16 /* EQL_B2_C - [15:0] */
+
+/*
+ * R344 (0x158) - EQ10
+ */
+#define WM8962_EQL_B2_PG_MASK 0xFFFF /* EQL_B2_PG - [15:0] */
+#define WM8962_EQL_B2_PG_SHIFT 0 /* EQL_B2_PG - [15:0] */
+#define WM8962_EQL_B2_PG_WIDTH 16 /* EQL_B2_PG - [15:0] */
+
+/*
+ * R345 (0x159) - EQ11
+ */
+#define WM8962_EQL_B3_A_MASK 0xFFFF /* EQL_B3_A - [15:0] */
+#define WM8962_EQL_B3_A_SHIFT 0 /* EQL_B3_A - [15:0] */
+#define WM8962_EQL_B3_A_WIDTH 16 /* EQL_B3_A - [15:0] */
+
+/*
+ * R346 (0x15A) - EQ12
+ */
+#define WM8962_EQL_B3_B_MASK 0xFFFF /* EQL_B3_B - [15:0] */
+#define WM8962_EQL_B3_B_SHIFT 0 /* EQL_B3_B - [15:0] */
+#define WM8962_EQL_B3_B_WIDTH 16 /* EQL_B3_B - [15:0] */
+
+/*
+ * R347 (0x15B) - EQ13
+ */
+#define WM8962_EQL_B3_C_MASK 0xFFFF /* EQL_B3_C - [15:0] */
+#define WM8962_EQL_B3_C_SHIFT 0 /* EQL_B3_C - [15:0] */
+#define WM8962_EQL_B3_C_WIDTH 16 /* EQL_B3_C - [15:0] */
+
+/*
+ * R348 (0x15C) - EQ14
+ */
+#define WM8962_EQL_B3_PG_MASK 0xFFFF /* EQL_B3_PG - [15:0] */
+#define WM8962_EQL_B3_PG_SHIFT 0 /* EQL_B3_PG - [15:0] */
+#define WM8962_EQL_B3_PG_WIDTH 16 /* EQL_B3_PG - [15:0] */
+
+/*
+ * R349 (0x15D) - EQ15
+ */
+#define WM8962_EQL_B4_A_MASK 0xFFFF /* EQL_B4_A - [15:0] */
+#define WM8962_EQL_B4_A_SHIFT 0 /* EQL_B4_A - [15:0] */
+#define WM8962_EQL_B4_A_WIDTH 16 /* EQL_B4_A - [15:0] */
+
+/*
+ * R350 (0x15E) - EQ16
+ */
+#define WM8962_EQL_B4_B_MASK 0xFFFF /* EQL_B4_B - [15:0] */
+#define WM8962_EQL_B4_B_SHIFT 0 /* EQL_B4_B - [15:0] */
+#define WM8962_EQL_B4_B_WIDTH 16 /* EQL_B4_B - [15:0] */
+
+/*
+ * R351 (0x15F) - EQ17
+ */
+#define WM8962_EQL_B4_C_MASK 0xFFFF /* EQL_B4_C - [15:0] */
+#define WM8962_EQL_B4_C_SHIFT 0 /* EQL_B4_C - [15:0] */
+#define WM8962_EQL_B4_C_WIDTH 16 /* EQL_B4_C - [15:0] */
+
+/*
+ * R352 (0x160) - EQ18
+ */
+#define WM8962_EQL_B4_PG_MASK 0xFFFF /* EQL_B4_PG - [15:0] */
+#define WM8962_EQL_B4_PG_SHIFT 0 /* EQL_B4_PG - [15:0] */
+#define WM8962_EQL_B4_PG_WIDTH 16 /* EQL_B4_PG - [15:0] */
+
+/*
+ * R353 (0x161) - EQ19
+ */
+#define WM8962_EQL_B5_A_MASK 0xFFFF /* EQL_B5_A - [15:0] */
+#define WM8962_EQL_B5_A_SHIFT 0 /* EQL_B5_A - [15:0] */
+#define WM8962_EQL_B5_A_WIDTH 16 /* EQL_B5_A - [15:0] */
+
+/*
+ * R354 (0x162) - EQ20
+ */
+#define WM8962_EQL_B5_B_MASK 0xFFFF /* EQL_B5_B - [15:0] */
+#define WM8962_EQL_B5_B_SHIFT 0 /* EQL_B5_B - [15:0] */
+#define WM8962_EQL_B5_B_WIDTH 16 /* EQL_B5_B - [15:0] */
+
+/*
+ * R355 (0x163) - EQ21
+ */
+#define WM8962_EQL_B5_PG_MASK 0xFFFF /* EQL_B5_PG - [15:0] */
+#define WM8962_EQL_B5_PG_SHIFT 0 /* EQL_B5_PG - [15:0] */
+#define WM8962_EQL_B5_PG_WIDTH 16 /* EQL_B5_PG - [15:0] */
+
+/*
+ * R356 (0x164) - EQ22
+ */
+#define WM8962_EQR_B1_GAIN_MASK 0xF800 /* EQR_B1_GAIN - [15:11] */
+#define WM8962_EQR_B1_GAIN_SHIFT 11 /* EQR_B1_GAIN - [15:11] */
+#define WM8962_EQR_B1_GAIN_WIDTH 5 /* EQR_B1_GAIN - [15:11] */
+#define WM8962_EQR_B2_GAIN_MASK 0x07C0 /* EQR_B2_GAIN - [10:6] */
+#define WM8962_EQR_B2_GAIN_SHIFT 6 /* EQR_B2_GAIN - [10:6] */
+#define WM8962_EQR_B2_GAIN_WIDTH 5 /* EQR_B2_GAIN - [10:6] */
+#define WM8962_EQR_B3_GAIN_MASK 0x003E /* EQR_B3_GAIN - [5:1] */
+#define WM8962_EQR_B3_GAIN_SHIFT 1 /* EQR_B3_GAIN - [5:1] */
+#define WM8962_EQR_B3_GAIN_WIDTH 5 /* EQR_B3_GAIN - [5:1] */
+
+/*
+ * R357 (0x165) - EQ23
+ */
+#define WM8962_EQR_B4_GAIN_MASK 0xF800 /* EQR_B4_GAIN - [15:11] */
+#define WM8962_EQR_B4_GAIN_SHIFT 11 /* EQR_B4_GAIN - [15:11] */
+#define WM8962_EQR_B4_GAIN_WIDTH 5 /* EQR_B4_GAIN - [15:11] */
+#define WM8962_EQR_B5_GAIN_MASK 0x07C0 /* EQR_B5_GAIN - [10:6] */
+#define WM8962_EQR_B5_GAIN_SHIFT 6 /* EQR_B5_GAIN - [10:6] */
+#define WM8962_EQR_B5_GAIN_WIDTH 5 /* EQR_B5_GAIN - [10:6] */
+
+/*
+ * R358 (0x166) - EQ24
+ */
+#define WM8962_EQR_B1_A_MASK 0xFFFF /* EQR_B1_A - [15:0] */
+#define WM8962_EQR_B1_A_SHIFT 0 /* EQR_B1_A - [15:0] */
+#define WM8962_EQR_B1_A_WIDTH 16 /* EQR_B1_A - [15:0] */
+
+/*
+ * R359 (0x167) - EQ25
+ */
+#define WM8962_EQR_B1_B_MASK 0xFFFF /* EQR_B1_B - [15:0] */
+#define WM8962_EQR_B1_B_SHIFT 0 /* EQR_B1_B - [15:0] */
+#define WM8962_EQR_B1_B_WIDTH 16 /* EQR_B1_B - [15:0] */
+
+/*
+ * R360 (0x168) - EQ26
+ */
+#define WM8962_EQR_B1_PG_MASK 0xFFFF /* EQR_B1_PG - [15:0] */
+#define WM8962_EQR_B1_PG_SHIFT 0 /* EQR_B1_PG - [15:0] */
+#define WM8962_EQR_B1_PG_WIDTH 16 /* EQR_B1_PG - [15:0] */
+
+/*
+ * R361 (0x169) - EQ27
+ */
+#define WM8962_EQR_B2_A_MASK 0xFFFF /* EQR_B2_A - [15:0] */
+#define WM8962_EQR_B2_A_SHIFT 0 /* EQR_B2_A - [15:0] */
+#define WM8962_EQR_B2_A_WIDTH 16 /* EQR_B2_A - [15:0] */
+
+/*
+ * R362 (0x16A) - EQ28
+ */
+#define WM8962_EQR_B2_B_MASK 0xFFFF /* EQR_B2_B - [15:0] */
+#define WM8962_EQR_B2_B_SHIFT 0 /* EQR_B2_B - [15:0] */
+#define WM8962_EQR_B2_B_WIDTH 16 /* EQR_B2_B - [15:0] */
+
+/*
+ * R363 (0x16B) - EQ29
+ */
+#define WM8962_EQR_B2_C_MASK 0xFFFF /* EQR_B2_C - [15:0] */
+#define WM8962_EQR_B2_C_SHIFT 0 /* EQR_B2_C - [15:0] */
+#define WM8962_EQR_B2_C_WIDTH 16 /* EQR_B2_C - [15:0] */
+
+/*
+ * R364 (0x16C) - EQ30
+ */
+#define WM8962_EQR_B2_PG_MASK 0xFFFF /* EQR_B2_PG - [15:0] */
+#define WM8962_EQR_B2_PG_SHIFT 0 /* EQR_B2_PG - [15:0] */
+#define WM8962_EQR_B2_PG_WIDTH 16 /* EQR_B2_PG - [15:0] */
+
+/*
+ * R365 (0x16D) - EQ31
+ */
+#define WM8962_EQR_B3_A_MASK 0xFFFF /* EQR_B3_A - [15:0] */
+#define WM8962_EQR_B3_A_SHIFT 0 /* EQR_B3_A - [15:0] */
+#define WM8962_EQR_B3_A_WIDTH 16 /* EQR_B3_A - [15:0] */
+
+/*
+ * R366 (0x16E) - EQ32
+ */
+#define WM8962_EQR_B3_B_MASK 0xFFFF /* EQR_B3_B - [15:0] */
+#define WM8962_EQR_B3_B_SHIFT 0 /* EQR_B3_B - [15:0] */
+#define WM8962_EQR_B3_B_WIDTH 16 /* EQR_B3_B - [15:0] */
+
+/*
+ * R367 (0x16F) - EQ33
+ */
+#define WM8962_EQR_B3_C_MASK 0xFFFF /* EQR_B3_C - [15:0] */
+#define WM8962_EQR_B3_C_SHIFT 0 /* EQR_B3_C - [15:0] */
+#define WM8962_EQR_B3_C_WIDTH 16 /* EQR_B3_C - [15:0] */
+
+/*
+ * R368 (0x170) - EQ34
+ */
+#define WM8962_EQR_B3_PG_MASK 0xFFFF /* EQR_B3_PG - [15:0] */
+#define WM8962_EQR_B3_PG_SHIFT 0 /* EQR_B3_PG - [15:0] */
+#define WM8962_EQR_B3_PG_WIDTH 16 /* EQR_B3_PG - [15:0] */
+
+/*
+ * R369 (0x171) - EQ35
+ */
+#define WM8962_EQR_B4_A_MASK 0xFFFF /* EQR_B4_A - [15:0] */
+#define WM8962_EQR_B4_A_SHIFT 0 /* EQR_B4_A - [15:0] */
+#define WM8962_EQR_B4_A_WIDTH 16 /* EQR_B4_A - [15:0] */
+
+/*
+ * R370 (0x172) - EQ36
+ */
+#define WM8962_EQR_B4_B_MASK 0xFFFF /* EQR_B4_B - [15:0] */
+#define WM8962_EQR_B4_B_SHIFT 0 /* EQR_B4_B - [15:0] */
+#define WM8962_EQR_B4_B_WIDTH 16 /* EQR_B4_B - [15:0] */
+
+/*
+ * R371 (0x173) - EQ37
+ */
+#define WM8962_EQR_B4_C_MASK 0xFFFF /* EQR_B4_C - [15:0] */
+#define WM8962_EQR_B4_C_SHIFT 0 /* EQR_B4_C - [15:0] */
+#define WM8962_EQR_B4_C_WIDTH 16 /* EQR_B4_C - [15:0] */
+
+/*
+ * R372 (0x174) - EQ38
+ */
+#define WM8962_EQR_B4_PG_MASK 0xFFFF /* EQR_B4_PG - [15:0] */
+#define WM8962_EQR_B4_PG_SHIFT 0 /* EQR_B4_PG - [15:0] */
+#define WM8962_EQR_B4_PG_WIDTH 16 /* EQR_B4_PG - [15:0] */
+
+/*
+ * R373 (0x175) - EQ39
+ */
+#define WM8962_EQR_B5_A_MASK 0xFFFF /* EQR_B5_A - [15:0] */
+#define WM8962_EQR_B5_A_SHIFT 0 /* EQR_B5_A - [15:0] */
+#define WM8962_EQR_B5_A_WIDTH 16 /* EQR_B5_A - [15:0] */
+
+/*
+ * R374 (0x176) - EQ40
+ */
+#define WM8962_EQR_B5_B_MASK 0xFFFF /* EQR_B5_B - [15:0] */
+#define WM8962_EQR_B5_B_SHIFT 0 /* EQR_B5_B - [15:0] */
+#define WM8962_EQR_B5_B_WIDTH 16 /* EQR_B5_B - [15:0] */
+
+/*
+ * R375 (0x177) - EQ41
+ */
+#define WM8962_EQR_B5_PG_MASK 0xFFFF /* EQR_B5_PG - [15:0] */
+#define WM8962_EQR_B5_PG_SHIFT 0 /* EQR_B5_PG - [15:0] */
+#define WM8962_EQR_B5_PG_WIDTH 16 /* EQR_B5_PG - [15:0] */
+
+/*
+ * R513 (0x201) - GPIO 2
+ */
+#define WM8962_GP2_POL 0x0400 /* GP2_POL */
+#define WM8962_GP2_POL_MASK 0x0400 /* GP2_POL */
+#define WM8962_GP2_POL_SHIFT 10 /* GP2_POL */
+#define WM8962_GP2_POL_WIDTH 1 /* GP2_POL */
+#define WM8962_GP2_LVL 0x0040 /* GP2_LVL */
+#define WM8962_GP2_LVL_MASK 0x0040 /* GP2_LVL */
+#define WM8962_GP2_LVL_SHIFT 6 /* GP2_LVL */
+#define WM8962_GP2_LVL_WIDTH 1 /* GP2_LVL */
+#define WM8962_GP2_FN_MASK 0x001F /* GP2_FN - [4:0] */
+#define WM8962_GP2_FN_SHIFT 0 /* GP2_FN - [4:0] */
+#define WM8962_GP2_FN_WIDTH 5 /* GP2_FN - [4:0] */
+
+/*
+ * R514 (0x202) - GPIO 3
+ */
+#define WM8962_GP3_POL 0x0400 /* GP3_POL */
+#define WM8962_GP3_POL_MASK 0x0400 /* GP3_POL */
+#define WM8962_GP3_POL_SHIFT 10 /* GP3_POL */
+#define WM8962_GP3_POL_WIDTH 1 /* GP3_POL */
+#define WM8962_GP3_LVL 0x0040 /* GP3_LVL */
+#define WM8962_GP3_LVL_MASK 0x0040 /* GP3_LVL */
+#define WM8962_GP3_LVL_SHIFT 6 /* GP3_LVL */
+#define WM8962_GP3_LVL_WIDTH 1 /* GP3_LVL */
+#define WM8962_GP3_FN_MASK 0x001F /* GP3_FN - [4:0] */
+#define WM8962_GP3_FN_SHIFT 0 /* GP3_FN - [4:0] */
+#define WM8962_GP3_FN_WIDTH 5 /* GP3_FN - [4:0] */
+
+/*
+ * R516 (0x204) - GPIO 5
+ */
+#define WM8962_GP5_DIR 0x8000 /* GP5_DIR */
+#define WM8962_GP5_DIR_MASK 0x8000 /* GP5_DIR */
+#define WM8962_GP5_DIR_SHIFT 15 /* GP5_DIR */
+#define WM8962_GP5_DIR_WIDTH 1 /* GP5_DIR */
+#define WM8962_GP5_PU 0x4000 /* GP5_PU */
+#define WM8962_GP5_PU_MASK 0x4000 /* GP5_PU */
+#define WM8962_GP5_PU_SHIFT 14 /* GP5_PU */
+#define WM8962_GP5_PU_WIDTH 1 /* GP5_PU */
+#define WM8962_GP5_PD 0x2000 /* GP5_PD */
+#define WM8962_GP5_PD_MASK 0x2000 /* GP5_PD */
+#define WM8962_GP5_PD_SHIFT 13 /* GP5_PD */
+#define WM8962_GP5_PD_WIDTH 1 /* GP5_PD */
+#define WM8962_GP5_POL 0x0400 /* GP5_POL */
+#define WM8962_GP5_POL_MASK 0x0400 /* GP5_POL */
+#define WM8962_GP5_POL_SHIFT 10 /* GP5_POL */
+#define WM8962_GP5_POL_WIDTH 1 /* GP5_POL */
+#define WM8962_GP5_OP_CFG 0x0200 /* GP5_OP_CFG */
+#define WM8962_GP5_OP_CFG_MASK 0x0200 /* GP5_OP_CFG */
+#define WM8962_GP5_OP_CFG_SHIFT 9 /* GP5_OP_CFG */
+#define WM8962_GP5_OP_CFG_WIDTH 1 /* GP5_OP_CFG */
+#define WM8962_GP5_DB 0x0100 /* GP5_DB */
+#define WM8962_GP5_DB_MASK 0x0100 /* GP5_DB */
+#define WM8962_GP5_DB_SHIFT 8 /* GP5_DB */
+#define WM8962_GP5_DB_WIDTH 1 /* GP5_DB */
+#define WM8962_GP5_LVL 0x0040 /* GP5_LVL */
+#define WM8962_GP5_LVL_MASK 0x0040 /* GP5_LVL */
+#define WM8962_GP5_LVL_SHIFT 6 /* GP5_LVL */
+#define WM8962_GP5_LVL_WIDTH 1 /* GP5_LVL */
+#define WM8962_GP5_FN_MASK 0x001F /* GP5_FN - [4:0] */
+#define WM8962_GP5_FN_SHIFT 0 /* GP5_FN - [4:0] */
+#define WM8962_GP5_FN_WIDTH 5 /* GP5_FN - [4:0] */
+
+/*
+ * R517 (0x205) - GPIO 6
+ */
+#define WM8962_GP6_DIR 0x8000 /* GP6_DIR */
+#define WM8962_GP6_DIR_MASK 0x8000 /* GP6_DIR */
+#define WM8962_GP6_DIR_SHIFT 15 /* GP6_DIR */
+#define WM8962_GP6_DIR_WIDTH 1 /* GP6_DIR */
+#define WM8962_GP6_PU 0x4000 /* GP6_PU */
+#define WM8962_GP6_PU_MASK 0x4000 /* GP6_PU */
+#define WM8962_GP6_PU_SHIFT 14 /* GP6_PU */
+#define WM8962_GP6_PU_WIDTH 1 /* GP6_PU */
+#define WM8962_GP6_PD 0x2000 /* GP6_PD */
+#define WM8962_GP6_PD_MASK 0x2000 /* GP6_PD */
+#define WM8962_GP6_PD_SHIFT 13 /* GP6_PD */
+#define WM8962_GP6_PD_WIDTH 1 /* GP6_PD */
+#define WM8962_GP6_POL 0x0400 /* GP6_POL */
+#define WM8962_GP6_POL_MASK 0x0400 /* GP6_POL */
+#define WM8962_GP6_POL_SHIFT 10 /* GP6_POL */
+#define WM8962_GP6_POL_WIDTH 1 /* GP6_POL */
+#define WM8962_GP6_OP_CFG 0x0200 /* GP6_OP_CFG */
+#define WM8962_GP6_OP_CFG_MASK 0x0200 /* GP6_OP_CFG */
+#define WM8962_GP6_OP_CFG_SHIFT 9 /* GP6_OP_CFG */
+#define WM8962_GP6_OP_CFG_WIDTH 1 /* GP6_OP_CFG */
+#define WM8962_GP6_DB 0x0100 /* GP6_DB */
+#define WM8962_GP6_DB_MASK 0x0100 /* GP6_DB */
+#define WM8962_GP6_DB_SHIFT 8 /* GP6_DB */
+#define WM8962_GP6_DB_WIDTH 1 /* GP6_DB */
+#define WM8962_GP6_LVL 0x0040 /* GP6_LVL */
+#define WM8962_GP6_LVL_MASK 0x0040 /* GP6_LVL */
+#define WM8962_GP6_LVL_SHIFT 6 /* GP6_LVL */
+#define WM8962_GP6_LVL_WIDTH 1 /* GP6_LVL */
+#define WM8962_GP6_FN_MASK 0x001F /* GP6_FN - [4:0] */
+#define WM8962_GP6_FN_SHIFT 0 /* GP6_FN - [4:0] */
+#define WM8962_GP6_FN_WIDTH 5 /* GP6_FN - [4:0] */
+
+/*
+ * R560 (0x230) - Interrupt Status 1
+ */
+#define WM8962_GP6_EINT 0x0020 /* GP6_EINT */
+#define WM8962_GP6_EINT_MASK 0x0020 /* GP6_EINT */
+#define WM8962_GP6_EINT_SHIFT 5 /* GP6_EINT */
+#define WM8962_GP6_EINT_WIDTH 1 /* GP6_EINT */
+#define WM8962_GP5_EINT 0x0010 /* GP5_EINT */
+#define WM8962_GP5_EINT_MASK 0x0010 /* GP5_EINT */
+#define WM8962_GP5_EINT_SHIFT 4 /* GP5_EINT */
+#define WM8962_GP5_EINT_WIDTH 1 /* GP5_EINT */
+
+/*
+ * R561 (0x231) - Interrupt Status 2
+ */
+#define WM8962_MICSCD_EINT 0x8000 /* MICSCD_EINT */
+#define WM8962_MICSCD_EINT_MASK 0x8000 /* MICSCD_EINT */
+#define WM8962_MICSCD_EINT_SHIFT 15 /* MICSCD_EINT */
+#define WM8962_MICSCD_EINT_WIDTH 1 /* MICSCD_EINT */
+#define WM8962_MICD_EINT 0x4000 /* MICD_EINT */
+#define WM8962_MICD_EINT_MASK 0x4000 /* MICD_EINT */
+#define WM8962_MICD_EINT_SHIFT 14 /* MICD_EINT */
+#define WM8962_MICD_EINT_WIDTH 1 /* MICD_EINT */
+#define WM8962_FIFOS_ERR_EINT 0x2000 /* FIFOS_ERR_EINT */
+#define WM8962_FIFOS_ERR_EINT_MASK 0x2000 /* FIFOS_ERR_EINT */
+#define WM8962_FIFOS_ERR_EINT_SHIFT 13 /* FIFOS_ERR_EINT */
+#define WM8962_FIFOS_ERR_EINT_WIDTH 1 /* FIFOS_ERR_EINT */
+#define WM8962_ALC_LOCK_EINT 0x1000 /* ALC_LOCK_EINT */
+#define WM8962_ALC_LOCK_EINT_MASK 0x1000 /* ALC_LOCK_EINT */
+#define WM8962_ALC_LOCK_EINT_SHIFT 12 /* ALC_LOCK_EINT */
+#define WM8962_ALC_LOCK_EINT_WIDTH 1 /* ALC_LOCK_EINT */
+#define WM8962_ALC_THRESH_EINT 0x0800 /* ALC_THRESH_EINT */
+#define WM8962_ALC_THRESH_EINT_MASK 0x0800 /* ALC_THRESH_EINT */
+#define WM8962_ALC_THRESH_EINT_SHIFT 11 /* ALC_THRESH_EINT */
+#define WM8962_ALC_THRESH_EINT_WIDTH 1 /* ALC_THRESH_EINT */
+#define WM8962_ALC_SAT_EINT 0x0400 /* ALC_SAT_EINT */
+#define WM8962_ALC_SAT_EINT_MASK 0x0400 /* ALC_SAT_EINT */
+#define WM8962_ALC_SAT_EINT_SHIFT 10 /* ALC_SAT_EINT */
+#define WM8962_ALC_SAT_EINT_WIDTH 1 /* ALC_SAT_EINT */
+#define WM8962_ALC_PKOVR_EINT 0x0200 /* ALC_PKOVR_EINT */
+#define WM8962_ALC_PKOVR_EINT_MASK 0x0200 /* ALC_PKOVR_EINT */
+#define WM8962_ALC_PKOVR_EINT_SHIFT 9 /* ALC_PKOVR_EINT */
+#define WM8962_ALC_PKOVR_EINT_WIDTH 1 /* ALC_PKOVR_EINT */
+#define WM8962_ALC_NGATE_EINT 0x0100 /* ALC_NGATE_EINT */
+#define WM8962_ALC_NGATE_EINT_MASK 0x0100 /* ALC_NGATE_EINT */
+#define WM8962_ALC_NGATE_EINT_SHIFT 8 /* ALC_NGATE_EINT */
+#define WM8962_ALC_NGATE_EINT_WIDTH 1 /* ALC_NGATE_EINT */
+#define WM8962_WSEQ_DONE_EINT 0x0080 /* WSEQ_DONE_EINT */
+#define WM8962_WSEQ_DONE_EINT_MASK 0x0080 /* WSEQ_DONE_EINT */
+#define WM8962_WSEQ_DONE_EINT_SHIFT 7 /* WSEQ_DONE_EINT */
+#define WM8962_WSEQ_DONE_EINT_WIDTH 1 /* WSEQ_DONE_EINT */
+#define WM8962_DRC_ACTDET_EINT 0x0040 /* DRC_ACTDET_EINT */
+#define WM8962_DRC_ACTDET_EINT_MASK 0x0040 /* DRC_ACTDET_EINT */
+#define WM8962_DRC_ACTDET_EINT_SHIFT 6 /* DRC_ACTDET_EINT */
+#define WM8962_DRC_ACTDET_EINT_WIDTH 1 /* DRC_ACTDET_EINT */
+#define WM8962_FLL_LOCK_EINT 0x0020 /* FLL_LOCK_EINT */
+#define WM8962_FLL_LOCK_EINT_MASK 0x0020 /* FLL_LOCK_EINT */
+#define WM8962_FLL_LOCK_EINT_SHIFT 5 /* FLL_LOCK_EINT */
+#define WM8962_FLL_LOCK_EINT_WIDTH 1 /* FLL_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT 0x0008 /* PLL3_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT_MASK 0x0008 /* PLL3_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT_SHIFT 3 /* PLL3_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT_WIDTH 1 /* PLL3_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT 0x0004 /* PLL2_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT_MASK 0x0004 /* PLL2_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT_SHIFT 2 /* PLL2_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT_WIDTH 1 /* PLL2_LOCK_EINT */
+#define WM8962_TEMP_SHUT_EINT 0x0001 /* TEMP_SHUT_EINT */
+#define WM8962_TEMP_SHUT_EINT_MASK 0x0001 /* TEMP_SHUT_EINT */
+#define WM8962_TEMP_SHUT_EINT_SHIFT 0 /* TEMP_SHUT_EINT */
+#define WM8962_TEMP_SHUT_EINT_WIDTH 1 /* TEMP_SHUT_EINT */
+
+/*
+ * R568 (0x238) - Interrupt Status 1 Mask
+ */
+#define WM8962_IM_GP6_EINT 0x0020 /* IM_GP6_EINT */
+#define WM8962_IM_GP6_EINT_MASK 0x0020 /* IM_GP6_EINT */
+#define WM8962_IM_GP6_EINT_SHIFT 5 /* IM_GP6_EINT */
+#define WM8962_IM_GP6_EINT_WIDTH 1 /* IM_GP6_EINT */
+#define WM8962_IM_GP5_EINT 0x0010 /* IM_GP5_EINT */
+#define WM8962_IM_GP5_EINT_MASK 0x0010 /* IM_GP5_EINT */
+#define WM8962_IM_GP5_EINT_SHIFT 4 /* IM_GP5_EINT */
+#define WM8962_IM_GP5_EINT_WIDTH 1 /* IM_GP5_EINT */
+
+/*
+ * R569 (0x239) - Interrupt Status 2 Mask
+ */
+#define WM8962_IM_MICSCD_EINT 0x8000 /* IM_MICSCD_EINT */
+#define WM8962_IM_MICSCD_EINT_MASK 0x8000 /* IM_MICSCD_EINT */
+#define WM8962_IM_MICSCD_EINT_SHIFT 15 /* IM_MICSCD_EINT */
+#define WM8962_IM_MICSCD_EINT_WIDTH 1 /* IM_MICSCD_EINT */
+#define WM8962_IM_MICD_EINT 0x4000 /* IM_MICD_EINT */
+#define WM8962_IM_MICD_EINT_MASK 0x4000 /* IM_MICD_EINT */
+#define WM8962_IM_MICD_EINT_SHIFT 14 /* IM_MICD_EINT */
+#define WM8962_IM_MICD_EINT_WIDTH 1 /* IM_MICD_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT 0x2000 /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT_MASK 0x2000 /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT_SHIFT 13 /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT_WIDTH 1 /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_ALC_LOCK_EINT 0x1000 /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_LOCK_EINT_MASK 0x1000 /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_LOCK_EINT_SHIFT 12 /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_LOCK_EINT_WIDTH 1 /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_THRESH_EINT 0x0800 /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_THRESH_EINT_MASK 0x0800 /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_THRESH_EINT_SHIFT 11 /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_THRESH_EINT_WIDTH 1 /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_SAT_EINT 0x0400 /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_SAT_EINT_MASK 0x0400 /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_SAT_EINT_SHIFT 10 /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_SAT_EINT_WIDTH 1 /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT 0x0200 /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT_MASK 0x0200 /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT_SHIFT 9 /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT_WIDTH 1 /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_NGATE_EINT 0x0100 /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_ALC_NGATE_EINT_MASK 0x0100 /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_ALC_NGATE_EINT_SHIFT 8 /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_ALC_NGATE_EINT_WIDTH 1 /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT 0x0080 /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT_MASK 0x0080 /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT_SHIFT 7 /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT_WIDTH 1 /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT 0x0040 /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT_MASK 0x0040 /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT_SHIFT 6 /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT_WIDTH 1 /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_FLL_LOCK_EINT 0x0020 /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_FLL_LOCK_EINT_MASK 0x0020 /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_FLL_LOCK_EINT_SHIFT 5 /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_FLL_LOCK_EINT_WIDTH 1 /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT 0x0008 /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT_MASK 0x0008 /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT_SHIFT 3 /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT_WIDTH 1 /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT 0x0004 /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT_MASK 0x0004 /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT_SHIFT 2 /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT_WIDTH 1 /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT 0x0001 /* IM_TEMP_SHUT_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT_MASK 0x0001 /* IM_TEMP_SHUT_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT_SHIFT 0 /* IM_TEMP_SHUT_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT_WIDTH 1 /* IM_TEMP_SHUT_EINT */
+
+/*
+ * R576 (0x240) - Interrupt Control
+ */
+#define WM8962_IRQ_POL 0x0001 /* IRQ_POL */
+#define WM8962_IRQ_POL_MASK 0x0001 /* IRQ_POL */
+#define WM8962_IRQ_POL_SHIFT 0 /* IRQ_POL */
+#define WM8962_IRQ_POL_WIDTH 1 /* IRQ_POL */
+
+/*
+ * R584 (0x248) - IRQ Debounce
+ */
+#define WM8962_FLL_LOCK_DB 0x0020 /* FLL_LOCK_DB */
+#define WM8962_FLL_LOCK_DB_MASK 0x0020 /* FLL_LOCK_DB */
+#define WM8962_FLL_LOCK_DB_SHIFT 5 /* FLL_LOCK_DB */
+#define WM8962_FLL_LOCK_DB_WIDTH 1 /* FLL_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB 0x0008 /* PLL3_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB_MASK 0x0008 /* PLL3_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB_SHIFT 3 /* PLL3_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB_WIDTH 1 /* PLL3_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB 0x0004 /* PLL2_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB_MASK 0x0004 /* PLL2_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB_SHIFT 2 /* PLL2_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB_WIDTH 1 /* PLL2_LOCK_DB */
+#define WM8962_TEMP_SHUT_DB 0x0001 /* TEMP_SHUT_DB */
+#define WM8962_TEMP_SHUT_DB_MASK 0x0001 /* TEMP_SHUT_DB */
+#define WM8962_TEMP_SHUT_DB_SHIFT 0 /* TEMP_SHUT_DB */
+#define WM8962_TEMP_SHUT_DB_WIDTH 1 /* TEMP_SHUT_DB */
+
+/*
+ * R586 (0x24A) - MICINT Source Pol
+ */
+#define WM8962_MICSCD_IRQ_POL 0x8000 /* MICSCD_IRQ_POL */
+#define WM8962_MICSCD_IRQ_POL_MASK 0x8000 /* MICSCD_IRQ_POL */
+#define WM8962_MICSCD_IRQ_POL_SHIFT 15 /* MICSCD_IRQ_POL */
+#define WM8962_MICSCD_IRQ_POL_WIDTH 1 /* MICSCD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL 0x4000 /* MICD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL_MASK 0x4000 /* MICD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL_SHIFT 14 /* MICD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL_WIDTH 1 /* MICD_IRQ_POL */
+
+/*
+ * R768 (0x300) - DSP2 Power Management
+ */
+#define WM8962_DSP2_ENA 0x0001 /* DSP2_ENA */
+#define WM8962_DSP2_ENA_MASK 0x0001 /* DSP2_ENA */
+#define WM8962_DSP2_ENA_SHIFT 0 /* DSP2_ENA */
+#define WM8962_DSP2_ENA_WIDTH 1 /* DSP2_ENA */
+
+/*
+ * R1037 (0x40D) - DSP2_ExecControl
+ */
+#define WM8962_DSP2_STOPC 0x0020 /* DSP2_STOPC */
+#define WM8962_DSP2_STOPC_MASK 0x0020 /* DSP2_STOPC */
+#define WM8962_DSP2_STOPC_SHIFT 5 /* DSP2_STOPC */
+#define WM8962_DSP2_STOPC_WIDTH 1 /* DSP2_STOPC */
+#define WM8962_DSP2_STOPS 0x0010 /* DSP2_STOPS */
+#define WM8962_DSP2_STOPS_MASK 0x0010 /* DSP2_STOPS */
+#define WM8962_DSP2_STOPS_SHIFT 4 /* DSP2_STOPS */
+#define WM8962_DSP2_STOPS_WIDTH 1 /* DSP2_STOPS */
+#define WM8962_DSP2_STOPI 0x0008 /* DSP2_STOPI */
+#define WM8962_DSP2_STOPI_MASK 0x0008 /* DSP2_STOPI */
+#define WM8962_DSP2_STOPI_SHIFT 3 /* DSP2_STOPI */
+#define WM8962_DSP2_STOPI_WIDTH 1 /* DSP2_STOPI */
+#define WM8962_DSP2_STOP 0x0004 /* DSP2_STOP */
+#define WM8962_DSP2_STOP_MASK 0x0004 /* DSP2_STOP */
+#define WM8962_DSP2_STOP_SHIFT 2 /* DSP2_STOP */
+#define WM8962_DSP2_STOP_WIDTH 1 /* DSP2_STOP */
+#define WM8962_DSP2_RUNR 0x0002 /* DSP2_RUNR */
+#define WM8962_DSP2_RUNR_MASK 0x0002 /* DSP2_RUNR */
+#define WM8962_DSP2_RUNR_SHIFT 1 /* DSP2_RUNR */
+#define WM8962_DSP2_RUNR_WIDTH 1 /* DSP2_RUNR */
+#define WM8962_DSP2_RUN 0x0001 /* DSP2_RUN */
+#define WM8962_DSP2_RUN_MASK 0x0001 /* DSP2_RUN */
+#define WM8962_DSP2_RUN_SHIFT 0 /* DSP2_RUN */
+#define WM8962_DSP2_RUN_WIDTH 1 /* DSP2_RUN */
+
+/*
+ * R8192 (0x2000) - DSP2 Instruction RAM 0
+ */
+#define WM8962_DSP2_INSTR_RAM_1024_10_9_0_MASK 0x03FF /* DSP2_INSTR_RAM_1024_10_9_0 - [9:0] */
+#define WM8962_DSP2_INSTR_RAM_1024_10_9_0_SHIFT 0 /* DSP2_INSTR_RAM_1024_10_9_0 - [9:0] */
+#define WM8962_DSP2_INSTR_RAM_1024_10_9_0_WIDTH 10 /* DSP2_INSTR_RAM_1024_10_9_0 - [9:0] */
+
+/*
+ * R9216 (0x2400) - DSP2 Address RAM 2
+ */
+#define WM8962_DSP2_ADDR_RAM_1024_38_37_32_MASK 0x003F /* DSP2_ADDR_RAM_1024_38_37_32 - [5:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_37_32_SHIFT 0 /* DSP2_ADDR_RAM_1024_38_37_32 - [5:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_37_32_WIDTH 6 /* DSP2_ADDR_RAM_1024_38_37_32 - [5:0] */
+
+/*
+ * R9217 (0x2401) - DSP2 Address RAM 1
+ */
+#define WM8962_DSP2_ADDR_RAM_1024_38_31_16_MASK 0xFFFF /* DSP2_ADDR_RAM_1024_38_31_16 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_31_16_SHIFT 0 /* DSP2_ADDR_RAM_1024_38_31_16 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_31_16_WIDTH 16 /* DSP2_ADDR_RAM_1024_38_31_16 - [15:0] */
+
+/*
+ * R9218 (0x2402) - DSP2 Address RAM 0
+ */
+#define WM8962_DSP2_ADDR_RAM_1024_38_15_0_MASK 0xFFFF /* DSP2_ADDR_RAM_1024_38_15_0 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_15_0_SHIFT 0 /* DSP2_ADDR_RAM_1024_38_15_0 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_15_0_WIDTH 16 /* DSP2_ADDR_RAM_1024_38_15_0 - [15:0] */
+
+/*
+ * R12288 (0x3000) - DSP2 Data1 RAM 1
+ */
+#define WM8962_DSP2_DATA1_RAM_384_24_23_16_MASK 0x00FF /* DSP2_DATA1_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_23_16_SHIFT 0 /* DSP2_DATA1_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_23_16_WIDTH 8 /* DSP2_DATA1_RAM_384_24_23_16 - [7:0] */
+
+/*
+ * R12289 (0x3001) - DSP2 Data1 RAM 0
+ */
+#define WM8962_DSP2_DATA1_RAM_384_24_15_0_MASK 0xFFFF /* DSP2_DATA1_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_15_0_SHIFT 0 /* DSP2_DATA1_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_15_0_WIDTH 16 /* DSP2_DATA1_RAM_384_24_15_0 - [15:0] */
+
+/*
+ * R13312 (0x3400) - DSP2 Data2 RAM 1
+ */
+#define WM8962_DSP2_DATA2_RAM_384_24_23_16_MASK 0x00FF /* DSP2_DATA2_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_23_16_SHIFT 0 /* DSP2_DATA2_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_23_16_WIDTH 8 /* DSP2_DATA2_RAM_384_24_23_16 - [7:0] */
+
+/*
+ * R13313 (0x3401) - DSP2 Data2 RAM 0
+ */
+#define WM8962_DSP2_DATA2_RAM_384_24_15_0_MASK 0xFFFF /* DSP2_DATA2_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_15_0_SHIFT 0 /* DSP2_DATA2_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_15_0_WIDTH 16 /* DSP2_DATA2_RAM_384_24_15_0 - [15:0] */
+
+/*
+ * R14336 (0x3800) - DSP2 Data3 RAM 1
+ */
+#define WM8962_DSP2_DATA3_RAM_384_24_23_16_MASK 0x00FF /* DSP2_DATA3_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_23_16_SHIFT 0 /* DSP2_DATA3_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_23_16_WIDTH 8 /* DSP2_DATA3_RAM_384_24_23_16 - [7:0] */
+
+/*
+ * R14337 (0x3801) - DSP2 Data3 RAM 0
+ */
+#define WM8962_DSP2_DATA3_RAM_384_24_15_0_MASK 0xFFFF /* DSP2_DATA3_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_15_0_SHIFT 0 /* DSP2_DATA3_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_15_0_WIDTH 16 /* DSP2_DATA3_RAM_384_24_15_0 - [15:0] */
+
+/*
+ * R15360 (0x3C00) - DSP2 Coeff RAM 0
+ */
+#define WM8962_DSP2_CMAP_RAM_384_11_10_0_MASK 0x07FF /* DSP2_CMAP_RAM_384_11_10_0 - [10:0] */
+#define WM8962_DSP2_CMAP_RAM_384_11_10_0_SHIFT 0 /* DSP2_CMAP_RAM_384_11_10_0 - [10:0] */
+#define WM8962_DSP2_CMAP_RAM_384_11_10_0_WIDTH 11 /* DSP2_CMAP_RAM_384_11_10_0 - [10:0] */
+
+/*
+ * R16384 (0x4000) - RETUNEADC_SHARED_COEFF_1
+ */
+#define WM8962_ADC_RETUNE_SCV 0x0080 /* ADC_RETUNE_SCV */
+#define WM8962_ADC_RETUNE_SCV_MASK 0x0080 /* ADC_RETUNE_SCV */
+#define WM8962_ADC_RETUNE_SCV_SHIFT 7 /* ADC_RETUNE_SCV */
+#define WM8962_ADC_RETUNE_SCV_WIDTH 1 /* ADC_RETUNE_SCV */
+#define WM8962_RETUNEADC_SHARED_COEFF_22_16_MASK 0x007F /* RETUNEADC_SHARED_COEFF_22_16 - [6:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_22_16_SHIFT 0 /* RETUNEADC_SHARED_COEFF_22_16 - [6:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_22_16_WIDTH 7 /* RETUNEADC_SHARED_COEFF_22_16 - [6:0] */
+
+/*
+ * R16385 (0x4001) - RETUNEADC_SHARED_COEFF_0
+ */
+#define WM8962_RETUNEADC_SHARED_COEFF_15_00_MASK 0xFFFF /* RETUNEADC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_15_00_SHIFT 0 /* RETUNEADC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_15_00_WIDTH 16 /* RETUNEADC_SHARED_COEFF_15_00 - [15:0] */
+
+/*
+ * R16386 (0x4002) - RETUNEDAC_SHARED_COEFF_1
+ */
+#define WM8962_DAC_RETUNE_SCV 0x0080 /* DAC_RETUNE_SCV */
+#define WM8962_DAC_RETUNE_SCV_MASK 0x0080 /* DAC_RETUNE_SCV */
+#define WM8962_DAC_RETUNE_SCV_SHIFT 7 /* DAC_RETUNE_SCV */
+#define WM8962_DAC_RETUNE_SCV_WIDTH 1 /* DAC_RETUNE_SCV */
+#define WM8962_RETUNEDAC_SHARED_COEFF_23_16_MASK 0x007F /* RETUNEDAC_SHARED_COEFF_23_16 - [6:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_23_16_SHIFT 0 /* RETUNEDAC_SHARED_COEFF_23_16 - [6:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_23_16_WIDTH 7 /* RETUNEDAC_SHARED_COEFF_23_16 - [6:0] */
+
+/*
+ * R16387 (0x4003) - RETUNEDAC_SHARED_COEFF_0
+ */
+#define WM8962_RETUNEDAC_SHARED_COEFF_15_00_MASK 0xFFFF /* RETUNEDAC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_15_00_SHIFT 0 /* RETUNEDAC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_15_00_WIDTH 16 /* RETUNEDAC_SHARED_COEFF_15_00 - [15:0] */
+
+/*
+ * R16388 (0x4004) - SOUNDSTAGE_ENABLES_1
+ */
+#define WM8962_SOUNDSTAGE_ENABLES_23_16_MASK 0x00FF /* SOUNDSTAGE_ENABLES_23_16 - [7:0] */
+#define WM8962_SOUNDSTAGE_ENABLES_23_16_SHIFT 0 /* SOUNDSTAGE_ENABLES_23_16 - [7:0] */
+#define WM8962_SOUNDSTAGE_ENABLES_23_16_WIDTH 8 /* SOUNDSTAGE_ENABLES_23_16 - [7:0] */
+
+/*
+ * R16389 (0x4005) - SOUNDSTAGE_ENABLES_0
+ */
+#define WM8962_SOUNDSTAGE_ENABLES_15_06_MASK 0xFFC0 /* SOUNDSTAGE_ENABLES_15_06 - [15:6] */
+#define WM8962_SOUNDSTAGE_ENABLES_15_06_SHIFT 6 /* SOUNDSTAGE_ENABLES_15_06 - [15:6] */
+#define WM8962_SOUNDSTAGE_ENABLES_15_06_WIDTH 10 /* SOUNDSTAGE_ENABLES_15_06 - [15:6] */
+#define WM8962_RTN_ADC_ENA 0x0020 /* RTN_ADC_ENA */
+#define WM8962_RTN_ADC_ENA_MASK 0x0020 /* RTN_ADC_ENA */
+#define WM8962_RTN_ADC_ENA_SHIFT 5 /* RTN_ADC_ENA */
+#define WM8962_RTN_ADC_ENA_WIDTH 1 /* RTN_ADC_ENA */
+#define WM8962_RTN_DAC_ENA 0x0010 /* RTN_DAC_ENA */
+#define WM8962_RTN_DAC_ENA_MASK 0x0010 /* RTN_DAC_ENA */
+#define WM8962_RTN_DAC_ENA_SHIFT 4 /* RTN_DAC_ENA */
+#define WM8962_RTN_DAC_ENA_WIDTH 1 /* RTN_DAC_ENA */
+#define WM8962_HDBASS_ENA 0x0008 /* HDBASS_ENA */
+#define WM8962_HDBASS_ENA_MASK 0x0008 /* HDBASS_ENA */
+#define WM8962_HDBASS_ENA_SHIFT 3 /* HDBASS_ENA */
+#define WM8962_HDBASS_ENA_WIDTH 1 /* HDBASS_ENA */
+#define WM8962_HPF2_ENA 0x0004 /* HPF2_ENA */
+#define WM8962_HPF2_ENA_MASK 0x0004 /* HPF2_ENA */
+#define WM8962_HPF2_ENA_SHIFT 2 /* HPF2_ENA */
+#define WM8962_HPF2_ENA_WIDTH 1 /* HPF2_ENA */
+#define WM8962_HPF1_ENA 0x0002 /* HPF1_ENA */
+#define WM8962_HPF1_ENA_MASK 0x0002 /* HPF1_ENA */
+#define WM8962_HPF1_ENA_SHIFT 1 /* HPF1_ENA */
+#define WM8962_HPF1_ENA_WIDTH 1 /* HPF1_ENA */
+#define WM8962_VSS_ENA 0x0001 /* VSS_ENA */
+#define WM8962_VSS_ENA_MASK 0x0001 /* VSS_ENA */
+#define WM8962_VSS_ENA_SHIFT 0 /* VSS_ENA */
+#define WM8962_VSS_ENA_WIDTH 1 /* VSS_ENA */
+
+int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+
+#endif
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index a99620f335d2..63f6dbf5d070 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -30,14 +30,13 @@
#include "wm8971.h"
-#define WM8971_VERSION "0.9"
-
#define WM8971_REG_COUNT 43
static struct workqueue_struct *wm8971_workq = NULL;
/* codec private data */
struct wm8971_priv {
+ enum snd_soc_control_type control_type;
unsigned int sysclk;
};
@@ -492,8 +491,7 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3;
u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0;
@@ -573,8 +571,8 @@ static struct snd_soc_dai_ops wm8971_dai_ops = {
.set_sysclk = wm8971_set_dai_sysclk,
};
-struct snd_soc_dai wm8971_dai = {
- .name = "WM8971",
+static struct snd_soc_dai_driver wm8971_dai = {
+ .name = "wm8971-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -589,7 +587,6 @@ struct snd_soc_dai wm8971_dai = {
.formats = WM8971_FORMATS,},
.ops = &wm8971_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8971_dai);
static void wm8971_work(struct work_struct *work)
{
@@ -598,19 +595,14 @@ static void wm8971_work(struct work_struct *work)
wm8971_set_bias_level(codec, codec->bias_level);
}
-static int wm8971_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8971_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8971_resume(struct platform_device *pdev)
+static int wm8971_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -639,37 +631,24 @@ static int wm8971_resume(struct platform_device *pdev)
return 0;
}
-static int wm8971_init(struct snd_soc_device *socdev,
- enum snd_soc_control_type control)
+static int wm8971_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
- int reg, ret = 0;
-
- codec->name = "WM8971";
- codec->owner = THIS_MODULE;
- codec->set_bias_level = wm8971_set_bias_level;
- codec->dai = &wm8971_dai;
- codec->reg_cache_size = ARRAY_SIZE(wm8971_reg);
- codec->num_dai = 1;
- codec->reg_cache = kmemdup(wm8971_reg, sizeof(wm8971_reg), GFP_KERNEL);
-
- if (codec->reg_cache == NULL)
- return -ENOMEM;
+ struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+ u16 reg;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8971->control_type);
if (ret < 0) {
printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
- wm8971_reset(codec);
+ INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
+ wm8971_workq = create_workqueue("wm8971");
+ if (wm8971_workq == NULL)
+ return -ENOMEM;
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "wm8971: failed to create pcms\n");
- goto err;
- }
+ wm8971_reset(codec);
/* charge output caps - set vmid to 5k for quick power up */
reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
@@ -704,40 +683,54 @@ static int wm8971_init(struct snd_soc_device *socdev,
wm8971_add_widgets(codec);
return ret;
-
-err:
- kfree(codec->reg_cache);
- return ret;
}
-/* If the i2c layer weren't so broken, we could pass this kind of data
- around */
-static struct snd_soc_device *wm8971_socdev;
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+/* power down chip */
+static int wm8971_remove(struct snd_soc_codec *codec)
+{
+ wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ if (wm8971_workq)
+ destroy_workqueue(wm8971_workq);
+ return 0;
+}
-static int wm8971_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static struct snd_soc_codec_driver soc_codec_dev_wm8971 = {
+ .probe = wm8971_probe,
+ .remove = wm8971_remove,
+ .suspend = wm8971_suspend,
+ .resume = wm8971_resume,
+ .set_bias_level = wm8971_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8971_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8971_reg,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8971_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
- struct snd_soc_device *socdev = wm8971_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct wm8971_priv *wm8971;
int ret;
- i2c_set_clientdata(i2c, codec);
+ wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL);
+ if (wm8971 == NULL)
+ return -ENOMEM;
- codec->control_data = i2c;
+ i2c_set_clientdata(i2c, wm8971);
- ret = wm8971_init(socdev, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8971, &wm8971_dai, 1);
if (ret < 0)
- pr_err("failed to initialise WM8971\n");
-
+ kfree(wm8971);
return ret;
}
-static int wm8971_i2c_remove(struct i2c_client *client)
+static __devexit int wm8971_i2c_remove(struct i2c_client *client)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -749,148 +742,34 @@ MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id);
static struct i2c_driver wm8971_i2c_driver = {
.driver = {
- .name = "WM8971 I2C Codec",
+ .name = "wm8971-codec",
.owner = THIS_MODULE,
},
- .probe = wm8971_i2c_probe,
- .remove = wm8971_i2c_remove,
+ .probe = wm8971_i2c_probe,
+ .remove = __devexit_p(wm8971_i2c_remove),
.id_table = wm8971_i2c_id,
};
-
-static int wm8971_add_i2c_device(struct platform_device *pdev,
- const struct wm8971_setup_data *setup)
-{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- int ret;
-
- ret = i2c_add_driver(&wm8971_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
- }
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "wm8971", I2C_NAME_SIZE);
-
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
-
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
- }
-
- return 0;
-
-err_driver:
- i2c_del_driver(&wm8971_i2c_driver);
- return -ENODEV;
-}
-
#endif
-static int wm8971_probe(struct platform_device *pdev)
+static int __init wm8971_modinit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct wm8971_setup_data *setup;
- struct snd_soc_codec *codec;
- struct wm8971_priv *wm8971;
int ret = 0;
-
- pr_info("WM8971 Audio Codec %s", WM8971_VERSION);
-
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL);
- if (wm8971 == NULL) {
- kfree(codec);
- return -ENOMEM;
- }
-
- snd_soc_codec_set_drvdata(codec, wm8971);
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
- wm8971_socdev = socdev;
-
- INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
- wm8971_workq = create_workqueue("wm8971");
- if (wm8971_workq == NULL) {
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
- return -ENOMEM;
- }
-
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- ret = wm8971_add_i2c_device(pdev, setup);
- }
-#endif
- /* Add other interfaces here */
-
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8971_i2c_driver);
if (ret != 0) {
- destroy_workqueue(wm8971_workq);
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
+ printk(KERN_ERR "Failed to register WM8971 I2C driver: %d\n",
+ ret);
}
-
- return ret;
-}
-
-/* power down chip */
-static int wm8971_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
- if (wm8971_workq)
- destroy_workqueue(wm8971_workq);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
- i2c_unregister_device(codec->control_data);
- i2c_del_driver(&wm8971_i2c_driver);
#endif
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8971 = {
- .probe = wm8971_probe,
- .remove = wm8971_remove,
- .suspend = wm8971_suspend,
- .resume = wm8971_resume,
-};
-
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971);
-
-static int __init wm8971_modinit(void)
-{
- return snd_soc_register_dai(&wm8971_dai);
+ return ret;
}
module_init(wm8971_modinit);
static void __exit wm8971_exit(void)
{
- snd_soc_unregister_dai(&wm8971_dai);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8971_i2c_driver);
+#endif
}
module_exit(wm8971_exit);
diff --git a/sound/soc/codecs/wm8971.h b/sound/soc/codecs/wm8971.h
index ef4f08f9f344..f31c38fddfc4 100644
--- a/sound/soc/codecs/wm8971.h
+++ b/sound/soc/codecs/wm8971.h
@@ -53,12 +53,4 @@
#define WM8971_SYSCLK 0
-struct wm8971_setup_data {
- int i2c_bus;
- unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai wm8971_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8971;
-
#endif
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 1468fe10cbbe..b4363f6d19b3 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -51,12 +51,10 @@ static const u16 wm8974_reg[WM8974_CACHEREGNUM] = {
#define WM8974_POWER1_BUFIOEN 0x04
struct wm8974_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
u16 reg_cache[WM8974_CACHEREGNUM];
};
-static struct snd_soc_codec *wm8974_codec;
-
#define wm8974_reset(c) snd_soc_write(c, WM8974_RESET, 0)
static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" };
@@ -566,8 +564,8 @@ static struct snd_soc_dai_ops wm8974_ops = {
.set_pll = wm8974_set_dai_pll,
};
-struct snd_soc_dai wm8974_dai = {
- .name = "WM8974 HiFi",
+static struct snd_soc_dai_driver wm8974_dai = {
+ .name = "wm8974-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -583,21 +581,15 @@ struct snd_soc_dai wm8974_dai = {
.ops = &wm8974_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8974_dai);
-static int wm8974_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8974_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8974_resume(struct platform_device *pdev)
+static int wm8974_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -613,156 +605,72 @@ static int wm8974_resume(struct platform_device *pdev)
return 0;
}
-static int wm8974_probe(struct platform_device *pdev)
+static int wm8974_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
int ret = 0;
- if (wm8974_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
}
- socdev->card->codec = wm8974_codec;
- codec = wm8974_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ ret = wm8974_reset(codec);
if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
+ dev_err(codec->dev, "Failed to issue reset\n");
+ return ret;
}
+ wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
snd_soc_add_controls(codec, wm8974_snd_controls,
ARRAY_SIZE(wm8974_snd_controls));
wm8974_add_widgets(codec);
return ret;
-
-pcm_err:
- return ret;
}
/* power down chip */
-static int wm8974_remove(struct platform_device *pdev)
+static int wm8974_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
+ wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_wm8974 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
.probe = wm8974_probe,
.remove = wm8974_remove,
.suspend = wm8974_suspend,
.resume = wm8974_resume,
+ .set_bias_level = wm8974_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8974_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8974_reg,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8974);
-
-static __devinit int wm8974_register(struct wm8974_priv *wm8974)
-{
- int ret;
- struct snd_soc_codec *codec = &wm8974->codec;
-
- if (wm8974_codec) {
- dev_err(codec->dev, "Another WM8974 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8974);
- codec->name = "WM8974";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8974_set_bias_level;
- codec->dai = &wm8974_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8974_CACHEREGNUM;
- codec->reg_cache = &wm8974->reg_cache;
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
- }
-
- memcpy(codec->reg_cache, wm8974_reg, sizeof(wm8974_reg));
-
- ret = wm8974_reset(codec);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
- }
-
- wm8974_dai.dev = codec->dev;
-
- wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- wm8974_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm8974_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8974);
- return ret;
-}
-
-static __devexit void wm8974_unregister(struct wm8974_priv *wm8974)
-{
- wm8974_set_bias_level(&wm8974->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8974_dai);
- snd_soc_unregister_codec(&wm8974->codec);
- kfree(wm8974);
- wm8974_codec = NULL;
-}
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8974_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8974_priv *wm8974;
- struct snd_soc_codec *codec;
+ int ret;
wm8974 = kzalloc(sizeof(struct wm8974_priv), GFP_KERNEL);
if (wm8974 == NULL)
return -ENOMEM;
- codec = &wm8974->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
i2c_set_clientdata(i2c, wm8974);
- codec->control_data = i2c;
-
- codec->dev = &i2c->dev;
- return wm8974_register(wm8974);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8974, &wm8974_dai, 1);
+ if (ret < 0)
+ kfree(wm8974);
+ return ret;
}
static __devexit int wm8974_i2c_remove(struct i2c_client *client)
{
- struct wm8974_priv *wm8974 = i2c_get_clientdata(client);
- wm8974_unregister(wm8974);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -774,23 +682,34 @@ MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id);
static struct i2c_driver wm8974_i2c_driver = {
.driver = {
- .name = "WM8974",
+ .name = "wm8974-codec",
.owner = THIS_MODULE,
},
.probe = wm8974_i2c_probe,
.remove = __devexit_p(wm8974_i2c_remove),
.id_table = wm8974_i2c_id,
};
+#endif
static int __init wm8974_modinit(void)
{
- return i2c_add_driver(&wm8974_i2c_driver);
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8974_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8974 I2C driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
}
module_init(wm8974_modinit);
static void __exit wm8974_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8974_i2c_driver);
+#endif
}
module_exit(wm8974_exit);
diff --git a/sound/soc/codecs/wm8974.h b/sound/soc/codecs/wm8974.h
index 896a7f0f3fc4..3c94e7bb55a6 100644
--- a/sound/soc/codecs/wm8974.h
+++ b/sound/soc/codecs/wm8974.h
@@ -83,7 +83,4 @@
#define WM8974_MCLKDIV_8 (6 << 5)
#define WM8974_MCLKDIV_12 (7 << 5)
-extern struct snd_soc_dai wm8974_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8974;
-
#endif
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 8a1ad778e7e3..13b979a71a7c 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -31,8 +31,6 @@
#include "wm8978.h"
-static struct snd_soc_codec *wm8978_codec;
-
/* wm8978 register cache. Note that register 0 is not included in the cache. */
static const u16 wm8978_reg[WM8978_CACHEREGNUM] = {
0x0000, 0x0000, 0x0000, 0x0000, /* 0x00...0x03 */
@@ -54,7 +52,8 @@ static const u16 wm8978_reg[WM8978_CACHEREGNUM] = {
/* codec private data */
struct wm8978_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
unsigned int f_pllout;
unsigned int f_mclk;
unsigned int f_256fs;
@@ -374,8 +373,8 @@ struct wm8978_pll_div {
#define FIXED_PLL_SIZE (1 << 24)
-static void pll_factors(struct wm8978_pll_div *pll_div, unsigned int target,
- unsigned int source)
+static void pll_factors(struct snd_soc_codec *codec,
+ struct wm8978_pll_div *pll_div, unsigned int target, unsigned int source)
{
u64 k_part;
unsigned int k, n_div, n_mod;
@@ -390,7 +389,7 @@ static void pll_factors(struct wm8978_pll_div *pll_div, unsigned int target,
}
if (n_div < 6 || n_div > 12)
- dev_warn(wm8978_codec->dev,
+ dev_warn(codec->dev,
"WM8978 N value exceeds recommended range! N = %u\n",
n_div);
@@ -505,7 +504,7 @@ static int wm8978_configure_pll(struct snd_soc_codec *codec)
dev_dbg(codec->dev, "%s: f_MCLK=%uHz, f_PLLOUT=%uHz\n", __func__,
wm8978->f_mclk, wm8978->f_pllout);
- pll_factors(&pll_div, f2, wm8978->f_mclk);
+ pll_factors(codec, &pll_div, f2, wm8978->f_mclk);
dev_dbg(codec->dev, "%s: calculated PLL N=0x%x, K=0x%x, div2=%d\n",
__func__, pll_div.n, pll_div.k, pll_div.div2);
@@ -690,8 +689,7 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
/* Word length mask = 0x60 */
u16 iface_ctl = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x60;
@@ -875,9 +873,8 @@ static struct snd_soc_dai_ops wm8978_dai_ops = {
};
/* Also supports 12kHz */
-struct snd_soc_dai wm8978_dai = {
- .name = "WM8978 HiFi",
- .id = 1,
+static struct snd_soc_dai_driver wm8978_dai = {
+ .name = "wm8978-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -894,13 +891,9 @@ struct snd_soc_dai wm8978_dai = {
},
.ops = &wm8978_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8978_dai);
-static int wm8978_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8978_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
/* Also switch PLL off */
snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0);
@@ -908,10 +901,8 @@ static int wm8978_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int wm8978_resume(struct platform_device *pdev)
+static int wm8978_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
int i;
u16 *cache = codec->reg_cache;
@@ -933,54 +924,6 @@ static int wm8978_resume(struct platform_device *pdev)
return 0;
}
-static int wm8978_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (wm8978_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8978_codec;
- codec = wm8978_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8978_snd_controls,
- ARRAY_SIZE(wm8978_snd_controls));
- wm8978_add_widgets(codec);
-
-pcm_err:
- return ret;
-}
-
-/* power down chip */
-static int wm8978_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8978 = {
- .probe = wm8978_probe,
- .remove = wm8978_remove,
- .suspend = wm8978_suspend,
- .resume = wm8978_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8978);
-
/*
* These registers contain an "update" bit - bit 8. This means, for example,
* that one can write new DAC digital volume for both channels, but only when
@@ -1000,44 +943,23 @@ static const int update_reg[] = {
WM8978_ROUT2_SPK_CONTROL,
};
-static __devinit int wm8978_register(struct wm8978_priv *wm8978)
+static int wm8978_probe(struct snd_soc_codec *codec)
{
- int ret, i;
- struct snd_soc_codec *codec = &wm8978->codec;
-
- if (wm8978_codec) {
- dev_err(codec->dev, "Another WM8978 is registered\n");
- return -EINVAL;
- }
+ struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0, i;
/*
* Set default system clock to PLL, it is more precise, this is also the
* default hardware setting
*/
wm8978->sysclk = WM8978_PLL;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8978);
- codec->name = "WM8978";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8978_set_bias_level;
- codec->dai = &wm8978_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = WM8978_CACHEREGNUM;
- codec->reg_cache = &wm8978->reg_cache;
-
+ codec->control_data = wm8978->control_data;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
- memcpy(codec->reg_cache, wm8978_reg, sizeof(wm8978_reg));
-
/*
* Set the update bit in all registers, that have one. This way all
* writes to those registers will also cause the update bit to be
@@ -1050,74 +972,61 @@ static __devinit int wm8978_register(struct wm8978_priv *wm8978)
ret = snd_soc_write(codec, WM8978_RESET, 0);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
+ return ret;
}
- wm8978_dai.dev = codec->dev;
-
wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- wm8978_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm8978_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8978_snd_controls,
+ ARRAY_SIZE(wm8978_snd_controls));
+ wm8978_add_widgets(codec);
return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- return ret;
}
-static __devexit void wm8978_unregister(struct wm8978_priv *wm8978)
+/* power down chip */
+static int wm8978_remove(struct snd_soc_codec *codec)
{
- wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8978_dai);
- snd_soc_unregister_codec(&wm8978->codec);
- wm8978_codec = NULL;
+ wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8978 = {
+ .probe = wm8978_probe,
+ .remove = wm8978_remove,
+ .suspend = wm8978_suspend,
+ .resume = wm8978_resume,
+ .set_bias_level = wm8978_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8978_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8978_reg,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- int ret;
struct wm8978_priv *wm8978;
- struct snd_soc_codec *codec;
+ int ret;
wm8978 = kzalloc(sizeof(struct wm8978_priv), GFP_KERNEL);
if (wm8978 == NULL)
return -ENOMEM;
- codec = &wm8978->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
i2c_set_clientdata(i2c, wm8978);
- codec->control_data = i2c;
-
- codec->dev = &i2c->dev;
+ wm8978->control_data = i2c;
- ret = wm8978_register(wm8978);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8978, &wm8978_dai, 1);
if (ret < 0)
kfree(wm8978);
-
return ret;
}
static __devexit int wm8978_i2c_remove(struct i2c_client *client)
{
- struct wm8978_priv *wm8978 = i2c_get_clientdata(client);
- wm8978_unregister(wm8978);
- kfree(wm8978);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1129,23 +1038,34 @@ MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id);
static struct i2c_driver wm8978_i2c_driver = {
.driver = {
- .name = "WM8978",
+ .name = "wm8978",
.owner = THIS_MODULE,
},
.probe = wm8978_i2c_probe,
.remove = __devexit_p(wm8978_i2c_remove),
.id_table = wm8978_i2c_id,
};
+#endif
static int __init wm8978_modinit(void)
{
- return i2c_add_driver(&wm8978_i2c_driver);
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8978_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8978 I2C driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
}
module_init(wm8978_modinit);
static void __exit wm8978_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8978_i2c_driver);
+#endif
}
module_exit(wm8978_exit);
diff --git a/sound/soc/codecs/wm8978.h b/sound/soc/codecs/wm8978.h
index 56ec83270917..c75525b7f154 100644
--- a/sound/soc/codecs/wm8978.h
+++ b/sound/soc/codecs/wm8978.h
@@ -80,7 +80,4 @@ enum wm8978_sysclk_src {
WM8978_MCLK
};
-extern struct snd_soc_dai wm8978_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8978;
-
#endif /* __WM8978_H__ */
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
new file mode 100644
index 000000000000..fd2e7cca1228
--- /dev/null
+++ b/sound/soc/codecs/wm8985.c
@@ -0,0 +1,1192 @@
+/*
+ * wm8985.c -- WM8985 ALSA SoC Audio driver
+ *
+ * Copyright 2010 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.
+ *
+ * TODO:
+ * o Add OUT3/OUT4 mixer controls.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8985.h"
+
+#define WM8985_NUM_SUPPLIES 4
+static const char *wm8985_supply_names[WM8985_NUM_SUPPLIES] = {
+ "DCVDD",
+ "DBVDD",
+ "AVDD1",
+ "AVDD2"
+};
+
+static const u16 wm8985_reg_defs[] = {
+ 0x0000, /* R0 - Software Reset */
+ 0x0000, /* R1 - Power management 1 */
+ 0x0000, /* R2 - Power management 2 */
+ 0x0000, /* R3 - Power management 3 */
+ 0x0050, /* R4 - Audio Interface */
+ 0x0000, /* R5 - Companding control */
+ 0x0140, /* R6 - Clock Gen control */
+ 0x0000, /* R7 - Additional control */
+ 0x0000, /* R8 - GPIO Control */
+ 0x0000, /* R9 - Jack Detect Control 1 */
+ 0x0000, /* R10 - DAC Control */
+ 0x00FF, /* R11 - Left DAC digital Vol */
+ 0x00FF, /* R12 - Right DAC digital vol */
+ 0x0000, /* R13 - Jack Detect Control 2 */
+ 0x0100, /* R14 - ADC Control */
+ 0x00FF, /* R15 - Left ADC Digital Vol */
+ 0x00FF, /* R16 - Right ADC Digital Vol */
+ 0x0000, /* R17 */
+ 0x012C, /* R18 - EQ1 - low shelf */
+ 0x002C, /* R19 - EQ2 - peak 1 */
+ 0x002C, /* R20 - EQ3 - peak 2 */
+ 0x002C, /* R21 - EQ4 - peak 3 */
+ 0x002C, /* R22 - EQ5 - high shelf */
+ 0x0000, /* R23 */
+ 0x0032, /* R24 - DAC Limiter 1 */
+ 0x0000, /* R25 - DAC Limiter 2 */
+ 0x0000, /* R26 */
+ 0x0000, /* R27 - Notch Filter 1 */
+ 0x0000, /* R28 - Notch Filter 2 */
+ 0x0000, /* R29 - Notch Filter 3 */
+ 0x0000, /* R30 - Notch Filter 4 */
+ 0x0000, /* R31 */
+ 0x0038, /* R32 - ALC control 1 */
+ 0x000B, /* R33 - ALC control 2 */
+ 0x0032, /* R34 - ALC control 3 */
+ 0x0000, /* R35 - Noise Gate */
+ 0x0008, /* R36 - PLL N */
+ 0x000C, /* R37 - PLL K 1 */
+ 0x0093, /* R38 - PLL K 2 */
+ 0x00E9, /* R39 - PLL K 3 */
+ 0x0000, /* R40 */
+ 0x0000, /* R41 - 3D control */
+ 0x0000, /* R42 - OUT4 to ADC */
+ 0x0000, /* R43 - Beep control */
+ 0x0033, /* R44 - Input ctrl */
+ 0x0010, /* R45 - Left INP PGA gain ctrl */
+ 0x0010, /* R46 - Right INP PGA gain ctrl */
+ 0x0100, /* R47 - Left ADC BOOST ctrl */
+ 0x0100, /* R48 - Right ADC BOOST ctrl */
+ 0x0002, /* R49 - Output ctrl */
+ 0x0001, /* R50 - Left mixer ctrl */
+ 0x0001, /* R51 - Right mixer ctrl */
+ 0x0039, /* R52 - LOUT1 (HP) volume ctrl */
+ 0x0039, /* R53 - ROUT1 (HP) volume ctrl */
+ 0x0039, /* R54 - LOUT2 (SPK) volume ctrl */
+ 0x0039, /* R55 - ROUT2 (SPK) volume ctrl */
+ 0x0001, /* R56 - OUT3 mixer ctrl */
+ 0x0001, /* R57 - OUT4 (MONO) mix ctrl */
+ 0x0001, /* R58 */
+ 0x0000, /* R59 */
+ 0x0004, /* R60 - OUTPUT ctrl */
+ 0x0000, /* R61 - BIAS CTRL */
+ 0x0180, /* R62 */
+ 0x0000 /* R63 */
+};
+
+/*
+ * latch bit 8 of these registers to ensure instant
+ * volume updates
+ */
+static const int volume_update_regs[] = {
+ WM8985_LEFT_DAC_DIGITAL_VOL,
+ WM8985_RIGHT_DAC_DIGITAL_VOL,
+ WM8985_LEFT_ADC_DIGITAL_VOL,
+ WM8985_RIGHT_ADC_DIGITAL_VOL,
+ WM8985_LOUT2_SPK_VOLUME_CTRL,
+ WM8985_ROUT2_SPK_VOLUME_CTRL,
+ WM8985_LOUT1_HP_VOLUME_CTRL,
+ WM8985_ROUT1_HP_VOLUME_CTRL,
+ WM8985_LEFT_INP_PGA_GAIN_CTRL,
+ WM8985_RIGHT_INP_PGA_GAIN_CTRL
+};
+
+struct wm8985_priv {
+ enum snd_soc_control_type control_type;
+ struct regulator_bulk_data supplies[WM8985_NUM_SUPPLIES];
+ unsigned int sysclk;
+ unsigned int bclk;
+};
+
+static const struct {
+ int div;
+ int ratio;
+} fs_ratios[] = {
+ { 10, 128 },
+ { 15, 192 },
+ { 20, 256 },
+ { 30, 384 },
+ { 40, 512 },
+ { 60, 768 },
+ { 80, 1024 },
+ { 120, 1536 }
+};
+
+static const int srates[] = { 48000, 32000, 24000, 16000, 12000, 8000 };
+
+static const int bclk_divs[] = {
+ 1, 2, 4, 8, 16, 32
+};
+
+static int eqmode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+static int eqmode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lim_thresh_tlv, -600, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lim_boost_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(alc_min_tlv, -1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_max_tlv, -675, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_tar_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(pga_vol_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, -1200, 300, 1);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(aux_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0);
+
+static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" };
+static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7,
+ alc_sel_text);
+
+static const char *alc_mode_text[] = { "ALC", "Limiter" };
+static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8,
+ alc_mode_text);
+
+static const char *filter_mode_text[] = { "Audio", "Application" };
+static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7,
+ filter_mode_text);
+
+static const char *eq_bw_text[] = { "Narrow", "Wide" };
+static const char *eqmode_text[] = { "Capture", "Playback" };
+static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);
+
+static const char *eq1_cutoff_text[] = {
+ "80Hz", "105Hz", "135Hz", "175Hz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5,
+ eq1_cutoff_text);
+static const char *eq2_cutoff_text[] = {
+ "230Hz", "300Hz", "385Hz", "500Hz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text);
+static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5,
+ eq2_cutoff_text);
+static const char *eq3_cutoff_text[] = {
+ "650Hz", "850Hz", "1.1kHz", "1.4kHz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text);
+static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5,
+ eq3_cutoff_text);
+static const char *eq4_cutoff_text[] = {
+ "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text);
+static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5,
+ eq4_cutoff_text);
+static const char *eq5_cutoff_text[] = {
+ "5.3kHz", "6.9kHz", "9kHz", "11.7kHz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5,
+ eq5_cutoff_text);
+
+static const char *speaker_mode_text[] = { "Class A/B", "Class D" };
+static const SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text);
+
+static const char *depth_3d_text[] = {
+ "Off",
+ "6.67%",
+ "13.3%",
+ "20%",
+ "26.7%",
+ "33.3%",
+ "40%",
+ "46.6%",
+ "53.3%",
+ "60%",
+ "66.7%",
+ "73.3%",
+ "80%",
+ "86.7%",
+ "93.3%",
+ "100%"
+};
+static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0,
+ depth_3d_text);
+
+static const struct snd_kcontrol_new wm8985_snd_controls[] = {
+ SOC_SINGLE("Digital Loopback Switch", WM8985_COMPANDING_CONTROL,
+ 0, 1, 0),
+
+ SOC_ENUM("ALC Capture Function", alc_sel),
+ SOC_SINGLE_TLV("ALC Capture Max Volume", WM8985_ALC_CONTROL_1,
+ 3, 7, 0, alc_max_tlv),
+ SOC_SINGLE_TLV("ALC Capture Min Volume", WM8985_ALC_CONTROL_1,
+ 0, 7, 0, alc_min_tlv),
+ SOC_SINGLE_TLV("ALC Capture Target Volume", WM8985_ALC_CONTROL_2,
+ 0, 15, 0, alc_tar_tlv),
+ SOC_SINGLE("ALC Capture Attack", WM8985_ALC_CONTROL_3, 0, 10, 0),
+ SOC_SINGLE("ALC Capture Hold", WM8985_ALC_CONTROL_2, 4, 10, 0),
+ SOC_SINGLE("ALC Capture Decay", WM8985_ALC_CONTROL_3, 4, 10, 0),
+ SOC_ENUM("ALC Mode", alc_mode),
+ SOC_SINGLE("ALC Capture NG Switch", WM8985_NOISE_GATE,
+ 3, 1, 0),
+ SOC_SINGLE("ALC Capture NG Threshold", WM8985_NOISE_GATE,
+ 0, 7, 1),
+
+ SOC_DOUBLE_R_TLV("Capture Volume", WM8985_LEFT_ADC_DIGITAL_VOL,
+ WM8985_RIGHT_ADC_DIGITAL_VOL, 0, 255, 0, adc_tlv),
+ SOC_DOUBLE_R("Capture PGA ZC Switch", WM8985_LEFT_INP_PGA_GAIN_CTRL,
+ WM8985_RIGHT_INP_PGA_GAIN_CTRL, 7, 1, 0),
+ SOC_DOUBLE_R_TLV("Capture PGA Volume", WM8985_LEFT_INP_PGA_GAIN_CTRL,
+ WM8985_RIGHT_INP_PGA_GAIN_CTRL, 0, 63, 0, pga_vol_tlv),
+
+ SOC_DOUBLE_R_TLV("Capture PGA Boost Volume",
+ WM8985_LEFT_ADC_BOOST_CTRL, WM8985_RIGHT_ADC_BOOST_CTRL,
+ 8, 1, 0, pga_boost_tlv),
+
+ SOC_DOUBLE("ADC Inversion Switch", WM8985_ADC_CONTROL, 0, 1, 1, 0),
+ SOC_SINGLE("ADC 128x Oversampling Switch", WM8985_ADC_CONTROL, 8, 1, 0),
+
+ SOC_DOUBLE_R_TLV("Playback Volume", WM8985_LEFT_DAC_DIGITAL_VOL,
+ WM8985_RIGHT_DAC_DIGITAL_VOL, 0, 255, 0, dac_tlv),
+
+ SOC_SINGLE("DAC Playback Limiter Switch", WM8985_DAC_LIMITER_1, 8, 1, 0),
+ SOC_SINGLE("DAC Playback Limiter Decay", WM8985_DAC_LIMITER_1, 4, 10, 0),
+ SOC_SINGLE("DAC Playback Limiter Attack", WM8985_DAC_LIMITER_1, 0, 11, 0),
+ SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8985_DAC_LIMITER_2,
+ 4, 7, 1, lim_thresh_tlv),
+ SOC_SINGLE_TLV("DAC Playback Limiter Boost Volume", WM8985_DAC_LIMITER_2,
+ 0, 12, 0, lim_boost_tlv),
+ SOC_DOUBLE("DAC Inversion Switch", WM8985_DAC_CONTROL, 0, 1, 1, 0),
+ SOC_SINGLE("DAC Auto Mute Switch", WM8985_DAC_CONTROL, 2, 1, 0),
+ SOC_SINGLE("DAC 128x Oversampling Switch", WM8985_DAC_CONTROL, 3, 1, 0),
+
+ SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8985_LOUT1_HP_VOLUME_CTRL,
+ WM8985_ROUT1_HP_VOLUME_CTRL, 0, 63, 0, out_tlv),
+ SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8985_LOUT1_HP_VOLUME_CTRL,
+ WM8985_ROUT1_HP_VOLUME_CTRL, 7, 1, 0),
+ SOC_DOUBLE_R("Headphone Switch", WM8985_LOUT1_HP_VOLUME_CTRL,
+ WM8985_ROUT1_HP_VOLUME_CTRL, 6, 1, 1),
+
+ SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8985_LOUT2_SPK_VOLUME_CTRL,
+ WM8985_ROUT2_SPK_VOLUME_CTRL, 0, 63, 0, out_tlv),
+ SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8985_LOUT2_SPK_VOLUME_CTRL,
+ WM8985_ROUT2_SPK_VOLUME_CTRL, 7, 1, 0),
+ SOC_DOUBLE_R("Speaker Switch", WM8985_LOUT2_SPK_VOLUME_CTRL,
+ WM8985_ROUT2_SPK_VOLUME_CTRL, 6, 1, 1),
+
+ SOC_SINGLE("High Pass Filter Switch", WM8985_ADC_CONTROL, 8, 1, 0),
+ SOC_ENUM("High Pass Filter Mode", filter_mode),
+ SOC_SINGLE("High Pass Filter Cutoff", WM8985_ADC_CONTROL, 4, 7, 0),
+
+ SOC_DOUBLE_R_TLV("Aux Bypass Volume",
+ WM8985_LEFT_MIXER_CTRL, WM8985_RIGHT_MIXER_CTRL, 6, 7, 0,
+ aux_tlv),
+
+ SOC_DOUBLE_R_TLV("Input PGA Bypass Volume",
+ WM8985_LEFT_MIXER_CTRL, WM8985_RIGHT_MIXER_CTRL, 2, 7, 0,
+ bypass_tlv),
+
+ SOC_ENUM_EXT("Equalizer Function", eqmode, eqmode_get, eqmode_put),
+ SOC_ENUM("EQ1 Cutoff", eq1_cutoff),
+ SOC_SINGLE_TLV("EQ1 Volume", WM8985_EQ1_LOW_SHELF, 0, 24, 1, eq_tlv),
+ SOC_ENUM("EQ2 Bandwith", eq2_bw),
+ SOC_ENUM("EQ2 Cutoff", eq2_cutoff),
+ SOC_SINGLE_TLV("EQ2 Volume", WM8985_EQ2_PEAK_1, 0, 24, 1, eq_tlv),
+ SOC_ENUM("EQ3 Bandwith", eq3_bw),
+ SOC_ENUM("EQ3 Cutoff", eq3_cutoff),
+ SOC_SINGLE_TLV("EQ3 Volume", WM8985_EQ3_PEAK_2, 0, 24, 1, eq_tlv),
+ SOC_ENUM("EQ4 Bandwith", eq4_bw),
+ SOC_ENUM("EQ4 Cutoff", eq4_cutoff),
+ SOC_SINGLE_TLV("EQ4 Volume", WM8985_EQ4_PEAK_3, 0, 24, 1, eq_tlv),
+ SOC_ENUM("EQ5 Cutoff", eq5_cutoff),
+ SOC_SINGLE_TLV("EQ5 Volume", WM8985_EQ5_HIGH_SHELF, 0, 24, 1, eq_tlv),
+
+ SOC_ENUM("3D Depth", depth_3d),
+
+ SOC_ENUM("Speaker Mode", speaker_mode)
+};
+
+static const struct snd_kcontrol_new left_out_mixer[] = {
+ SOC_DAPM_SINGLE("Line Switch", WM8985_LEFT_MIXER_CTRL, 1, 1, 0),
+ SOC_DAPM_SINGLE("Aux Switch", WM8985_LEFT_MIXER_CTRL, 5, 1, 0),
+ SOC_DAPM_SINGLE("PCM Switch", WM8985_LEFT_MIXER_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_out_mixer[] = {
+ SOC_DAPM_SINGLE("Line Switch", WM8985_RIGHT_MIXER_CTRL, 1, 1, 0),
+ SOC_DAPM_SINGLE("Aux Switch", WM8985_RIGHT_MIXER_CTRL, 5, 1, 0),
+ SOC_DAPM_SINGLE("PCM Switch", WM8985_RIGHT_MIXER_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_input_mixer[] = {
+ SOC_DAPM_SINGLE("L2 Switch", WM8985_INPUT_CTRL, 2, 1, 0),
+ SOC_DAPM_SINGLE("MicN Switch", WM8985_INPUT_CTRL, 1, 1, 0),
+ SOC_DAPM_SINGLE("MicP Switch", WM8985_INPUT_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_input_mixer[] = {
+ SOC_DAPM_SINGLE("R2 Switch", WM8985_INPUT_CTRL, 6, 1, 0),
+ SOC_DAPM_SINGLE("MicN Switch", WM8985_INPUT_CTRL, 5, 1, 0),
+ SOC_DAPM_SINGLE("MicP Switch", WM8985_INPUT_CTRL, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_boost_mixer[] = {
+ SOC_DAPM_SINGLE_TLV("L2 Volume", WM8985_LEFT_ADC_BOOST_CTRL,
+ 4, 7, 0, boost_tlv),
+ SOC_DAPM_SINGLE_TLV("AUXL Volume", WM8985_LEFT_ADC_BOOST_CTRL,
+ 0, 7, 0, boost_tlv)
+};
+
+static const struct snd_kcontrol_new right_boost_mixer[] = {
+ SOC_DAPM_SINGLE_TLV("R2 Volume", WM8985_RIGHT_ADC_BOOST_CTRL,
+ 4, 7, 0, boost_tlv),
+ SOC_DAPM_SINGLE_TLV("AUXR Volume", WM8985_RIGHT_ADC_BOOST_CTRL,
+ 0, 7, 0, boost_tlv)
+};
+
+static const struct snd_soc_dapm_widget wm8985_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8985_POWER_MANAGEMENT_3,
+ 0, 0),
+ SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8985_POWER_MANAGEMENT_3,
+ 1, 0),
+ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8985_POWER_MANAGEMENT_2,
+ 0, 0),
+ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8985_POWER_MANAGEMENT_2,
+ 1, 0),
+
+ SND_SOC_DAPM_MIXER("Left Output Mixer", WM8985_POWER_MANAGEMENT_3,
+ 2, 0, left_out_mixer, ARRAY_SIZE(left_out_mixer)),
+ SND_SOC_DAPM_MIXER("Right Output Mixer", WM8985_POWER_MANAGEMENT_3,
+ 3, 0, right_out_mixer, ARRAY_SIZE(right_out_mixer)),
+
+ SND_SOC_DAPM_MIXER("Left Input Mixer", WM8985_POWER_MANAGEMENT_2,
+ 2, 0, left_input_mixer, ARRAY_SIZE(left_input_mixer)),
+ SND_SOC_DAPM_MIXER("Right Input Mixer", WM8985_POWER_MANAGEMENT_2,
+ 3, 0, right_input_mixer, ARRAY_SIZE(right_input_mixer)),
+
+ SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8985_POWER_MANAGEMENT_2,
+ 4, 0, left_boost_mixer, ARRAY_SIZE(left_boost_mixer)),
+ SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8985_POWER_MANAGEMENT_2,
+ 5, 0, right_boost_mixer, ARRAY_SIZE(right_boost_mixer)),
+
+ SND_SOC_DAPM_PGA("Left Capture PGA", WM8985_LEFT_INP_PGA_GAIN_CTRL,
+ 6, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Capture PGA", WM8985_RIGHT_INP_PGA_GAIN_CTRL,
+ 6, 1, NULL, 0),
+
+ SND_SOC_DAPM_PGA("Left Headphone Out", WM8985_POWER_MANAGEMENT_2,
+ 7, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Headphone Out", WM8985_POWER_MANAGEMENT_2,
+ 8, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("Left Speaker Out", WM8985_POWER_MANAGEMENT_3,
+ 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Speaker Out", WM8985_POWER_MANAGEMENT_3,
+ 6, 0, NULL, 0),
+
+ SND_SOC_DAPM_MICBIAS("Mic Bias", WM8985_POWER_MANAGEMENT_1, 4, 0),
+
+ SND_SOC_DAPM_INPUT("LIN"),
+ SND_SOC_DAPM_INPUT("LIP"),
+ SND_SOC_DAPM_INPUT("RIN"),
+ SND_SOC_DAPM_INPUT("RIP"),
+ SND_SOC_DAPM_INPUT("AUXL"),
+ SND_SOC_DAPM_INPUT("AUXR"),
+ SND_SOC_DAPM_INPUT("L2"),
+ SND_SOC_DAPM_INPUT("R2"),
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+ SND_SOC_DAPM_OUTPUT("SPKL"),
+ SND_SOC_DAPM_OUTPUT("SPKR")
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ { "Right Output Mixer", "PCM Switch", "Right DAC" },
+ { "Right Output Mixer", "Aux Switch", "AUXR" },
+ { "Right Output Mixer", "Line Switch", "Right Boost Mixer" },
+
+ { "Left Output Mixer", "PCM Switch", "Left DAC" },
+ { "Left Output Mixer", "Aux Switch", "AUXL" },
+ { "Left Output Mixer", "Line Switch", "Left Boost Mixer" },
+
+ { "Right Headphone Out", NULL, "Right Output Mixer" },
+ { "HPR", NULL, "Right Headphone Out" },
+
+ { "Left Headphone Out", NULL, "Left Output Mixer" },
+ { "HPL", NULL, "Left Headphone Out" },
+
+ { "Right Speaker Out", NULL, "Right Output Mixer" },
+ { "SPKR", NULL, "Right Speaker Out" },
+
+ { "Left Speaker Out", NULL, "Left Output Mixer" },
+ { "SPKL", NULL, "Left Speaker Out" },
+
+ { "Right ADC", NULL, "Right Boost Mixer" },
+
+ { "Right Boost Mixer", "AUXR Volume", "AUXR" },
+ { "Right Boost Mixer", NULL, "Right Capture PGA" },
+ { "Right Boost Mixer", "R2 Volume", "R2" },
+
+ { "Left ADC", NULL, "Left Boost Mixer" },
+
+ { "Left Boost Mixer", "AUXL Volume", "AUXL" },
+ { "Left Boost Mixer", NULL, "Left Capture PGA" },
+ { "Left Boost Mixer", "L2 Volume", "L2" },
+
+ { "Right Capture PGA", NULL, "Right Input Mixer" },
+ { "Left Capture PGA", NULL, "Left Input Mixer" },
+
+ { "Right Input Mixer", "R2 Switch", "R2" },
+ { "Right Input Mixer", "MicN Switch", "RIN" },
+ { "Right Input Mixer", "MicP Switch", "RIP" },
+
+ { "Left Input Mixer", "L2 Switch", "L2" },
+ { "Left Input Mixer", "MicN Switch", "LIN" },
+ { "Left Input Mixer", "MicP Switch", "LIP" },
+};
+
+static int eqmode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int reg;
+
+ reg = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF);
+ if (reg & WM8985_EQ3DMODE)
+ ucontrol->value.integer.value[0] = 1;
+ else
+ ucontrol->value.integer.value[0] = 0;
+
+ return 0;
+}
+
+static int eqmode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int regpwr2, regpwr3;
+ unsigned int reg_eq;
+
+ if (ucontrol->value.integer.value[0] != 0
+ && ucontrol->value.integer.value[0] != 1)
+ return -EINVAL;
+
+ reg_eq = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF);
+ switch ((reg_eq & WM8985_EQ3DMODE) >> WM8985_EQ3DMODE_SHIFT) {
+ case 0:
+ if (!ucontrol->value.integer.value[0])
+ return 0;
+ break;
+ case 1:
+ if (ucontrol->value.integer.value[0])
+ return 0;
+ break;
+ }
+
+ regpwr2 = snd_soc_read(codec, WM8985_POWER_MANAGEMENT_2);
+ regpwr3 = snd_soc_read(codec, WM8985_POWER_MANAGEMENT_3);
+ /* disable the DACs and ADCs */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_2,
+ WM8985_ADCENR_MASK | WM8985_ADCENL_MASK, 0);
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_3,
+ WM8985_DACENR_MASK | WM8985_DACENL_MASK, 0);
+ snd_soc_update_bits(codec, WM8985_ADDITIONAL_CONTROL,
+ WM8985_M128ENB_MASK, WM8985_M128ENB);
+ /* set the desired eqmode */
+ snd_soc_update_bits(codec, WM8985_EQ1_LOW_SHELF,
+ WM8985_EQ3DMODE_MASK,
+ ucontrol->value.integer.value[0]
+ << WM8985_EQ3DMODE_SHIFT);
+ /* restore DAC/ADC configuration */
+ snd_soc_write(codec, WM8985_POWER_MANAGEMENT_2, regpwr2);
+ snd_soc_write(codec, WM8985_POWER_MANAGEMENT_3, regpwr3);
+ return 0;
+}
+
+static int wm8985_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, wm8985_dapm_widgets,
+ ARRAY_SIZE(wm8985_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, audio_map,
+ ARRAY_SIZE(audio_map));
+ return 0;
+}
+
+static int wm8985_reset(struct snd_soc_codec *codec)
+{
+ return snd_soc_write(codec, WM8985_SOFTWARE_RESET, 0x0);
+}
+
+static int wm8985_dac_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ return snd_soc_update_bits(codec, WM8985_DAC_CONTROL,
+ WM8985_SOFTMUTE_MASK,
+ !!mute << WM8985_SOFTMUTE_SHIFT);
+}
+
+static int wm8985_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec;
+ u16 format, master, bcp, lrp;
+
+ codec = dai->codec;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ format = 0x2;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ format = 0x0;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ format = 0x1;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ format = 0x3;
+ break;
+ default:
+ dev_err(dai->dev, "Unknown dai format\n");
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+ WM8985_FMT_MASK, format << WM8985_FMT_SHIFT);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ master = 1;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ master = 0;
+ break;
+ default:
+ dev_err(dai->dev, "Unknown master/slave configuration\n");
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+ WM8985_MS_MASK, master << WM8985_MS_SHIFT);
+
+ /* frame inversion is not valid for dsp modes */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ case SND_SOC_DAIFMT_NB_IF:
+ return -EINVAL;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ bcp = lrp = 0;
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ bcp = lrp = 1;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ bcp = 1;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ lrp = 1;
+ break;
+ default:
+ dev_err(dai->dev, "Unknown polarity configuration\n");
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+ WM8985_LRP_MASK, lrp << WM8985_LRP_SHIFT);
+ snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+ WM8985_BCP_MASK, bcp << WM8985_BCP_SHIFT);
+ return 0;
+}
+
+static int wm8985_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ int i;
+ struct snd_soc_codec *codec;
+ struct wm8985_priv *wm8985;
+ u16 blen, srate_idx;
+ unsigned int tmp;
+ int srate_best;
+
+ codec = dai->codec;
+ wm8985 = snd_soc_codec_get_drvdata(codec);
+
+ wm8985->bclk = snd_soc_params_to_bclk(params);
+ if ((int)wm8985->bclk < 0)
+ return wm8985->bclk;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ blen = 0x0;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ blen = 0x1;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ blen = 0x2;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ blen = 0x3;
+ break;
+ default:
+ dev_err(dai->dev, "Unsupported word length %u\n",
+ params_format(params));
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+ WM8985_WL_MASK, blen << WM8985_WL_SHIFT);
+
+ /*
+ * match to the nearest possible sample rate and rely
+ * on the array index to configure the SR register
+ */
+ srate_idx = 0;
+ srate_best = abs(srates[0] - params_rate(params));
+ for (i = 1; i < ARRAY_SIZE(srates); ++i) {
+ if (abs(srates[i] - params_rate(params)) >= srate_best)
+ continue;
+ srate_idx = i;
+ srate_best = abs(srates[i] - params_rate(params));
+ }
+
+ dev_dbg(dai->dev, "Selected SRATE = %d\n", srates[srate_idx]);
+ snd_soc_update_bits(codec, WM8985_ADDITIONAL_CONTROL,
+ WM8985_SR_MASK, srate_idx << WM8985_SR_SHIFT);
+
+ dev_dbg(dai->dev, "Target BCLK = %uHz\n", wm8985->bclk);
+ dev_dbg(dai->dev, "SYSCLK = %uHz\n", wm8985->sysclk);
+
+ for (i = 0; i < ARRAY_SIZE(fs_ratios); ++i) {
+ if (wm8985->sysclk / params_rate(params)
+ == fs_ratios[i].ratio)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(fs_ratios)) {
+ dev_err(dai->dev, "Unable to configure MCLK ratio %u/%u\n",
+ wm8985->sysclk, params_rate(params));
+ return -EINVAL;
+ }
+
+ dev_dbg(dai->dev, "MCLK ratio = %dfs\n", fs_ratios[i].ratio);
+ snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+ WM8985_MCLKDIV_MASK, i << WM8985_MCLKDIV_SHIFT);
+
+ /* select the appropriate bclk divider */
+ tmp = (wm8985->sysclk / fs_ratios[i].div) * 10;
+ for (i = 0; i < ARRAY_SIZE(bclk_divs); ++i) {
+ if (wm8985->bclk == tmp / bclk_divs[i])
+ break;
+ }
+
+ if (i == ARRAY_SIZE(bclk_divs)) {
+ dev_err(dai->dev, "No matching BCLK divider found\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(dai->dev, "BCLK div = %d\n", i);
+ snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+ WM8985_BCLKDIV_MASK, i << WM8985_BCLKDIV_SHIFT);
+ return 0;
+}
+
+struct pll_div {
+ u32 div2:1;
+ u32 n:4;
+ u32 k:24;
+};
+
+#define FIXED_PLL_SIZE ((1ULL << 24) * 10)
+static int pll_factors(struct pll_div *pll_div, unsigned int target,
+ unsigned int source)
+{
+ u64 Kpart;
+ unsigned long int K, Ndiv, Nmod;
+
+ pll_div->div2 = 0;
+ Ndiv = target / source;
+ if (Ndiv < 6) {
+ source >>= 1;
+ pll_div->div2 = 1;
+ Ndiv = target / source;
+ }
+
+ if (Ndiv < 6 || Ndiv > 12) {
+ printk(KERN_ERR "%s: WM8985 N value is not within"
+ " the recommended range: %lu\n", __func__, Ndiv);
+ return -EINVAL;
+ }
+ pll_div->n = Ndiv;
+
+ Nmod = target % source;
+ Kpart = FIXED_PLL_SIZE * (u64)Nmod;
+
+ do_div(Kpart, source);
+
+ K = Kpart & 0xffffffff;
+ if ((K % 10) >= 5)
+ K += 5;
+ K /= 10;
+ pll_div->k = K;
+
+ return 0;
+}
+
+static int wm8985_set_pll(struct snd_soc_dai *dai, int pll_id,
+ int source, unsigned int freq_in,
+ unsigned int freq_out)
+{
+ int ret;
+ struct snd_soc_codec *codec;
+ struct pll_div pll_div;
+
+ codec = dai->codec;
+ if (freq_in && freq_out) {
+ ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in);
+ if (ret)
+ return ret;
+ }
+
+ /* disable the PLL before reprogramming it */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_PLLEN_MASK, 0);
+
+ if (!freq_in || !freq_out)
+ return 0;
+
+ /* set PLLN and PRESCALE */
+ snd_soc_write(codec, WM8985_PLL_N,
+ (pll_div.div2 << WM8985_PLL_PRESCALE_SHIFT)
+ | pll_div.n);
+ /* set PLLK */
+ snd_soc_write(codec, WM8985_PLL_K_3, pll_div.k & 0x1ff);
+ snd_soc_write(codec, WM8985_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
+ snd_soc_write(codec, WM8985_PLL_K_1, (pll_div.k >> 18));
+ /* set the source of the clock to be the PLL */
+ snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+ WM8985_CLKSEL_MASK, WM8985_CLKSEL);
+ /* enable the PLL */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_PLLEN_MASK, WM8985_PLLEN);
+ return 0;
+}
+
+static int wm8985_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec;
+ struct wm8985_priv *wm8985;
+
+ codec = dai->codec;
+ wm8985 = snd_soc_codec_get_drvdata(codec);
+
+ switch (clk_id) {
+ case WM8985_CLKSRC_MCLK:
+ snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+ WM8985_CLKSEL_MASK, 0);
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_PLLEN_MASK, 0);
+ break;
+ case WM8985_CLKSRC_PLL:
+ snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+ WM8985_CLKSEL_MASK, WM8985_CLKSEL);
+ break;
+ default:
+ dev_err(dai->dev, "Unknown clock source %d\n", clk_id);
+ return -EINVAL;
+ }
+
+ wm8985->sysclk = freq;
+ return 0;
+}
+
+static void wm8985_sync_cache(struct snd_soc_codec *codec)
+{
+ short i;
+ u16 *cache;
+
+ if (!codec->cache_sync)
+ return;
+ codec->cache_only = 0;
+ /* restore cache */
+ cache = codec->reg_cache;
+ for (i = 0; i < codec->driver->reg_cache_size; i++) {
+ if (i == WM8985_SOFTWARE_RESET
+ || cache[i] == wm8985_reg_defs[i])
+ continue;
+ snd_soc_write(codec, i, cache[i]);
+ }
+ codec->cache_sync = 0;
+}
+
+static int wm8985_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ int ret;
+ struct wm8985_priv *wm8985;
+
+ wm8985 = snd_soc_codec_get_drvdata(codec);
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ /* VMID at 75k */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_VMIDSEL_MASK,
+ 1 << WM8985_VMIDSEL_SHIFT);
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
+ wm8985->supplies);
+ if (ret) {
+ dev_err(codec->dev,
+ "Failed to enable supplies: %d\n",
+ ret);
+ return ret;
+ }
+
+ wm8985_sync_cache(codec);
+
+ /* enable anti-pop features */
+ snd_soc_update_bits(codec, WM8985_OUT4_TO_ADC,
+ WM8985_POBCTRL_MASK,
+ WM8985_POBCTRL);
+ /* enable thermal shutdown */
+ snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+ WM8985_TSDEN_MASK, WM8985_TSDEN);
+ snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+ WM8985_TSOPCTRL_MASK,
+ WM8985_TSOPCTRL);
+ /* enable BIASEN */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_BIASEN_MASK, WM8985_BIASEN);
+ /* VMID at 75k */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_VMIDSEL_MASK,
+ 1 << WM8985_VMIDSEL_SHIFT);
+ msleep(500);
+ /* disable anti-pop features */
+ snd_soc_update_bits(codec, WM8985_OUT4_TO_ADC,
+ WM8985_POBCTRL_MASK, 0);
+ }
+ /* VMID at 300k */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_VMIDSEL_MASK,
+ 2 << WM8985_VMIDSEL_SHIFT);
+ break;
+ case SND_SOC_BIAS_OFF:
+ /* disable thermal shutdown */
+ snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+ WM8985_TSOPCTRL_MASK, 0);
+ snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+ WM8985_TSDEN_MASK, 0);
+ /* disable VMIDSEL and BIASEN */
+ snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+ WM8985_VMIDSEL_MASK | WM8985_BIASEN_MASK,
+ 0);
+ snd_soc_write(codec, WM8985_POWER_MANAGEMENT_1, 0);
+ snd_soc_write(codec, WM8985_POWER_MANAGEMENT_2, 0);
+ snd_soc_write(codec, WM8985_POWER_MANAGEMENT_3, 0);
+
+ codec->cache_sync = 1;
+
+ regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies),
+ wm8985->supplies);
+ break;
+ }
+
+ codec->bias_level = level;
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8985_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int wm8985_resume(struct snd_soc_codec *codec)
+{
+ wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ return 0;
+}
+#else
+#define wm8985_suspend NULL
+#define wm8985_resume NULL
+#endif
+
+static int wm8985_remove(struct snd_soc_codec *codec)
+{
+ struct wm8985_priv *wm8985;
+
+ wm8985 = snd_soc_codec_get_drvdata(codec);
+ wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
+ return 0;
+}
+
+static int wm8985_probe(struct snd_soc_codec *codec)
+{
+ size_t i;
+ struct wm8985_priv *wm8985;
+ int ret;
+ u16 *cache;
+
+ wm8985 = snd_soc_codec_get_drvdata(codec);
+
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8985->control_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm8985->supplies); i++)
+ wm8985->supplies[i].supply = wm8985_supply_names[i];
+
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8985->supplies),
+ wm8985->supplies);
+ if (ret) {
+ dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
+ wm8985->supplies);
+ if (ret) {
+ dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ goto err_reg_get;
+ }
+
+ ret = wm8985_reset(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+ goto err_reg_enable;
+ }
+
+ cache = codec->reg_cache;
+ /* latch volume update bits */
+ for (i = 0; i < ARRAY_SIZE(volume_update_regs); ++i)
+ cache[volume_update_regs[i]] |= 0x100;
+ /* enable BIASCUT */
+ cache[WM8985_BIAS_CTRL] |= WM8985_BIASCUT;
+ codec->cache_sync = 1;
+
+ snd_soc_add_controls(codec, wm8985_snd_controls,
+ ARRAY_SIZE(wm8985_snd_controls));
+ wm8985_add_widgets(codec);
+
+ wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ return 0;
+
+err_reg_enable:
+ regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
+err_reg_get:
+ regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
+ return ret;
+}
+
+static struct snd_soc_dai_ops wm8985_dai_ops = {
+ .digital_mute = wm8985_dac_mute,
+ .hw_params = wm8985_hw_params,
+ .set_fmt = wm8985_set_fmt,
+ .set_sysclk = wm8985_set_sysclk,
+ .set_pll = wm8985_set_pll
+};
+
+#define WM8985_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm8985_dai = {
+ .name = "wm8985-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = WM8985_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = WM8985_FORMATS,
+ },
+ .ops = &wm8985_dai_ops,
+ .symmetric_rates = 1
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8985 = {
+ .probe = wm8985_probe,
+ .remove = wm8985_remove,
+ .suspend = wm8985_suspend,
+ .resume = wm8985_resume,
+ .set_bias_level = wm8985_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8985_reg_defs),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8985_reg_defs
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8985_spi_probe(struct spi_device *spi)
+{
+ struct wm8985_priv *wm8985;
+ int ret;
+
+ wm8985 = kzalloc(sizeof *wm8985, GFP_KERNEL);
+ if (!wm8985)
+ return -ENOMEM;
+
+ wm8985->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8985);
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8985, &wm8985_dai, 1);
+ if (ret < 0)
+ kfree(wm8985);
+ return ret;
+}
+
+static int __devexit wm8985_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
+}
+
+static struct spi_driver wm8985_spi_driver = {
+ .driver = {
+ .name = "wm8985",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8985_spi_probe,
+ .remove = __devexit_p(wm8985_spi_remove)
+};
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8985_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8985_priv *wm8985;
+ int ret;
+
+ wm8985 = kzalloc(sizeof *wm8985, GFP_KERNEL);
+ if (!wm8985)
+ return -ENOMEM;
+
+ wm8985->control_type = SND_SOC_I2C;
+ i2c_set_clientdata(i2c, wm8985);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8985, &wm8985_dai, 1);
+ if (ret < 0)
+ kfree(wm8985);
+ return ret;
+}
+
+static __devexit int wm8985_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id wm8985_i2c_id[] = {
+ { "wm8985", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8985_i2c_id);
+
+static struct i2c_driver wm8985_i2c_driver = {
+ .driver = {
+ .name = "wm8985",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8985_i2c_probe,
+ .remove = __devexit_p(wm8985_i2c_remove),
+ .id_table = wm8985_i2c_id
+};
+#endif
+
+static int __init wm8985_modinit(void)
+{
+ int ret = 0;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8985_i2c_driver);
+ if (ret) {
+ printk(KERN_ERR "Failed to register wm8985 I2C driver: %d\n",
+ ret);
+ }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ ret = spi_register_driver(&wm8985_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8985 SPI driver: %d\n",
+ ret);
+ }
+#endif
+ return ret;
+}
+module_init(wm8985_modinit);
+
+static void __exit wm8985_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8985_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&wm8985_spi_driver);
+#endif
+}
+module_exit(wm8985_exit);
+
+MODULE_DESCRIPTION("ASoC WM8985 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8985.h b/sound/soc/codecs/wm8985.h
new file mode 100644
index 000000000000..2e71ff507638
--- /dev/null
+++ b/sound/soc/codecs/wm8985.h
@@ -0,0 +1,1045 @@
+/*
+ * wm8985.h -- WM8985 ASoC driver
+ *
+ * Copyright 2010 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.
+ */
+
+#ifndef _WM8985_H
+#define _WM8985_H
+
+#define WM8985_SOFTWARE_RESET 0x00
+#define WM8985_POWER_MANAGEMENT_1 0x01
+#define WM8985_POWER_MANAGEMENT_2 0x02
+#define WM8985_POWER_MANAGEMENT_3 0x03
+#define WM8985_AUDIO_INTERFACE 0x04
+#define WM8985_COMPANDING_CONTROL 0x05
+#define WM8985_CLOCK_GEN_CONTROL 0x06
+#define WM8985_ADDITIONAL_CONTROL 0x07
+#define WM8985_GPIO_CONTROL 0x08
+#define WM8985_JACK_DETECT_CONTROL_1 0x09
+#define WM8985_DAC_CONTROL 0x0A
+#define WM8985_LEFT_DAC_DIGITAL_VOL 0x0B
+#define WM8985_RIGHT_DAC_DIGITAL_VOL 0x0C
+#define WM8985_JACK_DETECT_CONTROL_2 0x0D
+#define WM8985_ADC_CONTROL 0x0E
+#define WM8985_LEFT_ADC_DIGITAL_VOL 0x0F
+#define WM8985_RIGHT_ADC_DIGITAL_VOL 0x10
+#define WM8985_EQ1_LOW_SHELF 0x12
+#define WM8985_EQ2_PEAK_1 0x13
+#define WM8985_EQ3_PEAK_2 0x14
+#define WM8985_EQ4_PEAK_3 0x15
+#define WM8985_EQ5_HIGH_SHELF 0x16
+#define WM8985_DAC_LIMITER_1 0x18
+#define WM8985_DAC_LIMITER_2 0x19
+#define WM8985_NOTCH_FILTER_1 0x1B
+#define WM8985_NOTCH_FILTER_2 0x1C
+#define WM8985_NOTCH_FILTER_3 0x1D
+#define WM8985_NOTCH_FILTER_4 0x1E
+#define WM8985_ALC_CONTROL_1 0x20
+#define WM8985_ALC_CONTROL_2 0x21
+#define WM8985_ALC_CONTROL_3 0x22
+#define WM8985_NOISE_GATE 0x23
+#define WM8985_PLL_N 0x24
+#define WM8985_PLL_K_1 0x25
+#define WM8985_PLL_K_2 0x26
+#define WM8985_PLL_K_3 0x27
+#define WM8985_3D_CONTROL 0x29
+#define WM8985_OUT4_TO_ADC 0x2A
+#define WM8985_BEEP_CONTROL 0x2B
+#define WM8985_INPUT_CTRL 0x2C
+#define WM8985_LEFT_INP_PGA_GAIN_CTRL 0x2D
+#define WM8985_RIGHT_INP_PGA_GAIN_CTRL 0x2E
+#define WM8985_LEFT_ADC_BOOST_CTRL 0x2F
+#define WM8985_RIGHT_ADC_BOOST_CTRL 0x30
+#define WM8985_OUTPUT_CTRL0 0x31
+#define WM8985_LEFT_MIXER_CTRL 0x32
+#define WM8985_RIGHT_MIXER_CTRL 0x33
+#define WM8985_LOUT1_HP_VOLUME_CTRL 0x34
+#define WM8985_ROUT1_HP_VOLUME_CTRL 0x35
+#define WM8985_LOUT2_SPK_VOLUME_CTRL 0x36
+#define WM8985_ROUT2_SPK_VOLUME_CTRL 0x37
+#define WM8985_OUT3_MIXER_CTRL 0x38
+#define WM8985_OUT4_MONO_MIX_CTRL 0x39
+#define WM8985_OUTPUT_CTRL1 0x3C
+#define WM8985_BIAS_CTRL 0x3D
+
+#define WM8985_REGISTER_COUNT 59
+#define WM8985_MAX_REGISTER 0x3F
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8985_SOFTWARE_RESET_MASK 0x01FF /* SOFTWARE_RESET - [8:0] */
+#define WM8985_SOFTWARE_RESET_SHIFT 0 /* SOFTWARE_RESET - [8:0] */
+#define WM8985_SOFTWARE_RESET_WIDTH 9 /* SOFTWARE_RESET - [8:0] */
+
+/*
+ * R1 (0x01) - Power management 1
+ */
+#define WM8985_OUT4MIXEN 0x0080 /* OUT4MIXEN */
+#define WM8985_OUT4MIXEN_MASK 0x0080 /* OUT4MIXEN */
+#define WM8985_OUT4MIXEN_SHIFT 7 /* OUT4MIXEN */
+#define WM8985_OUT4MIXEN_WIDTH 1 /* OUT4MIXEN */
+#define WM8985_OUT3MIXEN 0x0040 /* OUT3MIXEN */
+#define WM8985_OUT3MIXEN_MASK 0x0040 /* OUT3MIXEN */
+#define WM8985_OUT3MIXEN_SHIFT 6 /* OUT3MIXEN */
+#define WM8985_OUT3MIXEN_WIDTH 1 /* OUT3MIXEN */
+#define WM8985_PLLEN 0x0020 /* PLLEN */
+#define WM8985_PLLEN_MASK 0x0020 /* PLLEN */
+#define WM8985_PLLEN_SHIFT 5 /* PLLEN */
+#define WM8985_PLLEN_WIDTH 1 /* PLLEN */
+#define WM8985_MICBEN 0x0010 /* MICBEN */
+#define WM8985_MICBEN_MASK 0x0010 /* MICBEN */
+#define WM8985_MICBEN_SHIFT 4 /* MICBEN */
+#define WM8985_MICBEN_WIDTH 1 /* MICBEN */
+#define WM8985_BIASEN 0x0008 /* BIASEN */
+#define WM8985_BIASEN_MASK 0x0008 /* BIASEN */
+#define WM8985_BIASEN_SHIFT 3 /* BIASEN */
+#define WM8985_BIASEN_WIDTH 1 /* BIASEN */
+#define WM8985_BUFIOEN 0x0004 /* BUFIOEN */
+#define WM8985_BUFIOEN_MASK 0x0004 /* BUFIOEN */
+#define WM8985_BUFIOEN_SHIFT 2 /* BUFIOEN */
+#define WM8985_BUFIOEN_WIDTH 1 /* BUFIOEN */
+#define WM8985_VMIDSEL 0x0003 /* VMIDSEL */
+#define WM8985_VMIDSEL_MASK 0x0003 /* VMIDSEL - [1:0] */
+#define WM8985_VMIDSEL_SHIFT 0 /* VMIDSEL - [1:0] */
+#define WM8985_VMIDSEL_WIDTH 2 /* VMIDSEL - [1:0] */
+
+/*
+ * R2 (0x02) - Power management 2
+ */
+#define WM8985_ROUT1EN 0x0100 /* ROUT1EN */
+#define WM8985_ROUT1EN_MASK 0x0100 /* ROUT1EN */
+#define WM8985_ROUT1EN_SHIFT 8 /* ROUT1EN */
+#define WM8985_ROUT1EN_WIDTH 1 /* ROUT1EN */
+#define WM8985_LOUT1EN 0x0080 /* LOUT1EN */
+#define WM8985_LOUT1EN_MASK 0x0080 /* LOUT1EN */
+#define WM8985_LOUT1EN_SHIFT 7 /* LOUT1EN */
+#define WM8985_LOUT1EN_WIDTH 1 /* LOUT1EN */
+#define WM8985_SLEEP 0x0040 /* SLEEP */
+#define WM8985_SLEEP_MASK 0x0040 /* SLEEP */
+#define WM8985_SLEEP_SHIFT 6 /* SLEEP */
+#define WM8985_SLEEP_WIDTH 1 /* SLEEP */
+#define WM8985_BOOSTENR 0x0020 /* BOOSTENR */
+#define WM8985_BOOSTENR_MASK 0x0020 /* BOOSTENR */
+#define WM8985_BOOSTENR_SHIFT 5 /* BOOSTENR */
+#define WM8985_BOOSTENR_WIDTH 1 /* BOOSTENR */
+#define WM8985_BOOSTENL 0x0010 /* BOOSTENL */
+#define WM8985_BOOSTENL_MASK 0x0010 /* BOOSTENL */
+#define WM8985_BOOSTENL_SHIFT 4 /* BOOSTENL */
+#define WM8985_BOOSTENL_WIDTH 1 /* BOOSTENL */
+#define WM8985_INPGAENR 0x0008 /* INPGAENR */
+#define WM8985_INPGAENR_MASK 0x0008 /* INPGAENR */
+#define WM8985_INPGAENR_SHIFT 3 /* INPGAENR */
+#define WM8985_INPGAENR_WIDTH 1 /* INPGAENR */
+#define WM8985_INPPGAENL 0x0004 /* INPPGAENL */
+#define WM8985_INPPGAENL_MASK 0x0004 /* INPPGAENL */
+#define WM8985_INPPGAENL_SHIFT 2 /* INPPGAENL */
+#define WM8985_INPPGAENL_WIDTH 1 /* INPPGAENL */
+#define WM8985_ADCENR 0x0002 /* ADCENR */
+#define WM8985_ADCENR_MASK 0x0002 /* ADCENR */
+#define WM8985_ADCENR_SHIFT 1 /* ADCENR */
+#define WM8985_ADCENR_WIDTH 1 /* ADCENR */
+#define WM8985_ADCENL 0x0001 /* ADCENL */
+#define WM8985_ADCENL_MASK 0x0001 /* ADCENL */
+#define WM8985_ADCENL_SHIFT 0 /* ADCENL */
+#define WM8985_ADCENL_WIDTH 1 /* ADCENL */
+
+/*
+ * R3 (0x03) - Power management 3
+ */
+#define WM8985_OUT4EN 0x0100 /* OUT4EN */
+#define WM8985_OUT4EN_MASK 0x0100 /* OUT4EN */
+#define WM8985_OUT4EN_SHIFT 8 /* OUT4EN */
+#define WM8985_OUT4EN_WIDTH 1 /* OUT4EN */
+#define WM8985_OUT3EN 0x0080 /* OUT3EN */
+#define WM8985_OUT3EN_MASK 0x0080 /* OUT3EN */
+#define WM8985_OUT3EN_SHIFT 7 /* OUT3EN */
+#define WM8985_OUT3EN_WIDTH 1 /* OUT3EN */
+#define WM8985_ROUT2EN 0x0040 /* ROUT2EN */
+#define WM8985_ROUT2EN_MASK 0x0040 /* ROUT2EN */
+#define WM8985_ROUT2EN_SHIFT 6 /* ROUT2EN */
+#define WM8985_ROUT2EN_WIDTH 1 /* ROUT2EN */
+#define WM8985_LOUT2EN 0x0020 /* LOUT2EN */
+#define WM8985_LOUT2EN_MASK 0x0020 /* LOUT2EN */
+#define WM8985_LOUT2EN_SHIFT 5 /* LOUT2EN */
+#define WM8985_LOUT2EN_WIDTH 1 /* LOUT2EN */
+#define WM8985_RMIXEN 0x0008 /* RMIXEN */
+#define WM8985_RMIXEN_MASK 0x0008 /* RMIXEN */
+#define WM8985_RMIXEN_SHIFT 3 /* RMIXEN */
+#define WM8985_RMIXEN_WIDTH 1 /* RMIXEN */
+#define WM8985_LMIXEN 0x0004 /* LMIXEN */
+#define WM8985_LMIXEN_MASK 0x0004 /* LMIXEN */
+#define WM8985_LMIXEN_SHIFT 2 /* LMIXEN */
+#define WM8985_LMIXEN_WIDTH 1 /* LMIXEN */
+#define WM8985_DACENR 0x0002 /* DACENR */
+#define WM8985_DACENR_MASK 0x0002 /* DACENR */
+#define WM8985_DACENR_SHIFT 1 /* DACENR */
+#define WM8985_DACENR_WIDTH 1 /* DACENR */
+#define WM8985_DACENL 0x0001 /* DACENL */
+#define WM8985_DACENL_MASK 0x0001 /* DACENL */
+#define WM8985_DACENL_SHIFT 0 /* DACENL */
+#define WM8985_DACENL_WIDTH 1 /* DACENL */
+
+/*
+ * R4 (0x04) - Audio Interface
+ */
+#define WM8985_BCP 0x0100 /* BCP */
+#define WM8985_BCP_MASK 0x0100 /* BCP */
+#define WM8985_BCP_SHIFT 8 /* BCP */
+#define WM8985_BCP_WIDTH 1 /* BCP */
+#define WM8985_LRP 0x0080 /* LRP */
+#define WM8985_LRP_MASK 0x0080 /* LRP */
+#define WM8985_LRP_SHIFT 7 /* LRP */
+#define WM8985_LRP_WIDTH 1 /* LRP */
+#define WM8985_WL_MASK 0x0060 /* WL - [6:5] */
+#define WM8985_WL_SHIFT 5 /* WL - [6:5] */
+#define WM8985_WL_WIDTH 2 /* WL - [6:5] */
+#define WM8985_FMT_MASK 0x0018 /* FMT - [4:3] */
+#define WM8985_FMT_SHIFT 3 /* FMT - [4:3] */
+#define WM8985_FMT_WIDTH 2 /* FMT - [4:3] */
+#define WM8985_DLRSWAP 0x0004 /* DLRSWAP */
+#define WM8985_DLRSWAP_MASK 0x0004 /* DLRSWAP */
+#define WM8985_DLRSWAP_SHIFT 2 /* DLRSWAP */
+#define WM8985_DLRSWAP_WIDTH 1 /* DLRSWAP */
+#define WM8985_ALRSWAP 0x0002 /* ALRSWAP */
+#define WM8985_ALRSWAP_MASK 0x0002 /* ALRSWAP */
+#define WM8985_ALRSWAP_SHIFT 1 /* ALRSWAP */
+#define WM8985_ALRSWAP_WIDTH 1 /* ALRSWAP */
+#define WM8985_MONO 0x0001 /* MONO */
+#define WM8985_MONO_MASK 0x0001 /* MONO */
+#define WM8985_MONO_SHIFT 0 /* MONO */
+#define WM8985_MONO_WIDTH 1 /* MONO */
+
+/*
+ * R5 (0x05) - Companding control
+ */
+#define WM8985_WL8 0x0020 /* WL8 */
+#define WM8985_WL8_MASK 0x0020 /* WL8 */
+#define WM8985_WL8_SHIFT 5 /* WL8 */
+#define WM8985_WL8_WIDTH 1 /* WL8 */
+#define WM8985_DAC_COMP_MASK 0x0018 /* DAC_COMP - [4:3] */
+#define WM8985_DAC_COMP_SHIFT 3 /* DAC_COMP - [4:3] */
+#define WM8985_DAC_COMP_WIDTH 2 /* DAC_COMP - [4:3] */
+#define WM8985_ADC_COMP_MASK 0x0006 /* ADC_COMP - [2:1] */
+#define WM8985_ADC_COMP_SHIFT 1 /* ADC_COMP - [2:1] */
+#define WM8985_ADC_COMP_WIDTH 2 /* ADC_COMP - [2:1] */
+#define WM8985_LOOPBACK 0x0001 /* LOOPBACK */
+#define WM8985_LOOPBACK_MASK 0x0001 /* LOOPBACK */
+#define WM8985_LOOPBACK_SHIFT 0 /* LOOPBACK */
+#define WM8985_LOOPBACK_WIDTH 1 /* LOOPBACK */
+
+/*
+ * R6 (0x06) - Clock Gen control
+ */
+#define WM8985_CLKSEL 0x0100 /* CLKSEL */
+#define WM8985_CLKSEL_MASK 0x0100 /* CLKSEL */
+#define WM8985_CLKSEL_SHIFT 8 /* CLKSEL */
+#define WM8985_CLKSEL_WIDTH 1 /* CLKSEL */
+#define WM8985_MCLKDIV_MASK 0x00E0 /* MCLKDIV - [7:5] */
+#define WM8985_MCLKDIV_SHIFT 5 /* MCLKDIV - [7:5] */
+#define WM8985_MCLKDIV_WIDTH 3 /* MCLKDIV - [7:5] */
+#define WM8985_BCLKDIV_MASK 0x001C /* BCLKDIV - [4:2] */
+#define WM8985_BCLKDIV_SHIFT 2 /* BCLKDIV - [4:2] */
+#define WM8985_BCLKDIV_WIDTH 3 /* BCLKDIV - [4:2] */
+#define WM8985_MS 0x0001 /* MS */
+#define WM8985_MS_MASK 0x0001 /* MS */
+#define WM8985_MS_SHIFT 0 /* MS */
+#define WM8985_MS_WIDTH 1 /* MS */
+
+/*
+ * R7 (0x07) - Additional control
+ */
+#define WM8985_M128ENB 0x0100 /* M128ENB */
+#define WM8985_M128ENB_MASK 0x0100 /* M128ENB */
+#define WM8985_M128ENB_SHIFT 8 /* M128ENB */
+#define WM8985_M128ENB_WIDTH 1 /* M128ENB */
+#define WM8985_DCLKDIV_MASK 0x00F0 /* DCLKDIV - [7:4] */
+#define WM8985_DCLKDIV_SHIFT 4 /* DCLKDIV - [7:4] */
+#define WM8985_DCLKDIV_WIDTH 4 /* DCLKDIV - [7:4] */
+#define WM8985_SR_MASK 0x000E /* SR - [3:1] */
+#define WM8985_SR_SHIFT 1 /* SR - [3:1] */
+#define WM8985_SR_WIDTH 3 /* SR - [3:1] */
+#define WM8985_SLOWCLKEN 0x0001 /* SLOWCLKEN */
+#define WM8985_SLOWCLKEN_MASK 0x0001 /* SLOWCLKEN */
+#define WM8985_SLOWCLKEN_SHIFT 0 /* SLOWCLKEN */
+#define WM8985_SLOWCLKEN_WIDTH 1 /* SLOWCLKEN */
+
+/*
+ * R8 (0x08) - GPIO Control
+ */
+#define WM8985_GPIO1GP 0x0100 /* GPIO1GP */
+#define WM8985_GPIO1GP_MASK 0x0100 /* GPIO1GP */
+#define WM8985_GPIO1GP_SHIFT 8 /* GPIO1GP */
+#define WM8985_GPIO1GP_WIDTH 1 /* GPIO1GP */
+#define WM8985_GPIO1GPU 0x0080 /* GPIO1GPU */
+#define WM8985_GPIO1GPU_MASK 0x0080 /* GPIO1GPU */
+#define WM8985_GPIO1GPU_SHIFT 7 /* GPIO1GPU */
+#define WM8985_GPIO1GPU_WIDTH 1 /* GPIO1GPU */
+#define WM8985_GPIO1GPD 0x0040 /* GPIO1GPD */
+#define WM8985_GPIO1GPD_MASK 0x0040 /* GPIO1GPD */
+#define WM8985_GPIO1GPD_SHIFT 6 /* GPIO1GPD */
+#define WM8985_GPIO1GPD_WIDTH 1 /* GPIO1GPD */
+#define WM8985_GPIO1POL 0x0008 /* GPIO1POL */
+#define WM8985_GPIO1POL_MASK 0x0008 /* GPIO1POL */
+#define WM8985_GPIO1POL_SHIFT 3 /* GPIO1POL */
+#define WM8985_GPIO1POL_WIDTH 1 /* GPIO1POL */
+#define WM8985_GPIO1SEL_MASK 0x0007 /* GPIO1SEL - [2:0] */
+#define WM8985_GPIO1SEL_SHIFT 0 /* GPIO1SEL - [2:0] */
+#define WM8985_GPIO1SEL_WIDTH 3 /* GPIO1SEL - [2:0] */
+
+/*
+ * R9 (0x09) - Jack Detect Control 1
+ */
+#define WM8985_JD_EN 0x0040 /* JD_EN */
+#define WM8985_JD_EN_MASK 0x0040 /* JD_EN */
+#define WM8985_JD_EN_SHIFT 6 /* JD_EN */
+#define WM8985_JD_EN_WIDTH 1 /* JD_EN */
+#define WM8985_JD_SEL_MASK 0x0030 /* JD_SEL - [5:4] */
+#define WM8985_JD_SEL_SHIFT 4 /* JD_SEL - [5:4] */
+#define WM8985_JD_SEL_WIDTH 2 /* JD_SEL - [5:4] */
+
+/*
+ * R10 (0x0A) - DAC Control
+ */
+#define WM8985_SOFTMUTE 0x0040 /* SOFTMUTE */
+#define WM8985_SOFTMUTE_MASK 0x0040 /* SOFTMUTE */
+#define WM8985_SOFTMUTE_SHIFT 6 /* SOFTMUTE */
+#define WM8985_SOFTMUTE_WIDTH 1 /* SOFTMUTE */
+#define WM8985_DACOSR128 0x0008 /* DACOSR128 */
+#define WM8985_DACOSR128_MASK 0x0008 /* DACOSR128 */
+#define WM8985_DACOSR128_SHIFT 3 /* DACOSR128 */
+#define WM8985_DACOSR128_WIDTH 1 /* DACOSR128 */
+#define WM8985_AMUTE 0x0004 /* AMUTE */
+#define WM8985_AMUTE_MASK 0x0004 /* AMUTE */
+#define WM8985_AMUTE_SHIFT 2 /* AMUTE */
+#define WM8985_AMUTE_WIDTH 1 /* AMUTE */
+#define WM8985_DACPOLR 0x0002 /* DACPOLR */
+#define WM8985_DACPOLR_MASK 0x0002 /* DACPOLR */
+#define WM8985_DACPOLR_SHIFT 1 /* DACPOLR */
+#define WM8985_DACPOLR_WIDTH 1 /* DACPOLR */
+#define WM8985_DACPOLL 0x0001 /* DACPOLL */
+#define WM8985_DACPOLL_MASK 0x0001 /* DACPOLL */
+#define WM8985_DACPOLL_SHIFT 0 /* DACPOLL */
+#define WM8985_DACPOLL_WIDTH 1 /* DACPOLL */
+
+/*
+ * R11 (0x0B) - Left DAC digital Vol
+ */
+#define WM8985_DACVU 0x0100 /* DACVU */
+#define WM8985_DACVU_MASK 0x0100 /* DACVU */
+#define WM8985_DACVU_SHIFT 8 /* DACVU */
+#define WM8985_DACVU_WIDTH 1 /* DACVU */
+#define WM8985_DACVOLL_MASK 0x00FF /* DACVOLL - [7:0] */
+#define WM8985_DACVOLL_SHIFT 0 /* DACVOLL - [7:0] */
+#define WM8985_DACVOLL_WIDTH 8 /* DACVOLL - [7:0] */
+
+/*
+ * R12 (0x0C) - Right DAC digital vol
+ */
+#define WM8985_DACVU 0x0100 /* DACVU */
+#define WM8985_DACVU_MASK 0x0100 /* DACVU */
+#define WM8985_DACVU_SHIFT 8 /* DACVU */
+#define WM8985_DACVU_WIDTH 1 /* DACVU */
+#define WM8985_DACVOLR_MASK 0x00FF /* DACVOLR - [7:0] */
+#define WM8985_DACVOLR_SHIFT 0 /* DACVOLR - [7:0] */
+#define WM8985_DACVOLR_WIDTH 8 /* DACVOLR - [7:0] */
+
+/*
+ * R13 (0x0D) - Jack Detect Control 2
+ */
+#define WM8985_JD_EN1_MASK 0x00F0 /* JD_EN1 - [7:4] */
+#define WM8985_JD_EN1_SHIFT 4 /* JD_EN1 - [7:4] */
+#define WM8985_JD_EN1_WIDTH 4 /* JD_EN1 - [7:4] */
+#define WM8985_JD_EN0_MASK 0x000F /* JD_EN0 - [3:0] */
+#define WM8985_JD_EN0_SHIFT 0 /* JD_EN0 - [3:0] */
+#define WM8985_JD_EN0_WIDTH 4 /* JD_EN0 - [3:0] */
+
+/*
+ * R14 (0x0E) - ADC Control
+ */
+#define WM8985_HPFEN 0x0100 /* HPFEN */
+#define WM8985_HPFEN_MASK 0x0100 /* HPFEN */
+#define WM8985_HPFEN_SHIFT 8 /* HPFEN */
+#define WM8985_HPFEN_WIDTH 1 /* HPFEN */
+#define WM8985_HPFAPP 0x0080 /* HPFAPP */
+#define WM8985_HPFAPP_MASK 0x0080 /* HPFAPP */
+#define WM8985_HPFAPP_SHIFT 7 /* HPFAPP */
+#define WM8985_HPFAPP_WIDTH 1 /* HPFAPP */
+#define WM8985_HPFCUT_MASK 0x0070 /* HPFCUT - [6:4] */
+#define WM8985_HPFCUT_SHIFT 4 /* HPFCUT - [6:4] */
+#define WM8985_HPFCUT_WIDTH 3 /* HPFCUT - [6:4] */
+#define WM8985_ADCOSR128 0x0008 /* ADCOSR128 */
+#define WM8985_ADCOSR128_MASK 0x0008 /* ADCOSR128 */
+#define WM8985_ADCOSR128_SHIFT 3 /* ADCOSR128 */
+#define WM8985_ADCOSR128_WIDTH 1 /* ADCOSR128 */
+#define WM8985_ADCRPOL 0x0002 /* ADCRPOL */
+#define WM8985_ADCRPOL_MASK 0x0002 /* ADCRPOL */
+#define WM8985_ADCRPOL_SHIFT 1 /* ADCRPOL */
+#define WM8985_ADCRPOL_WIDTH 1 /* ADCRPOL */
+#define WM8985_ADCLPOL 0x0001 /* ADCLPOL */
+#define WM8985_ADCLPOL_MASK 0x0001 /* ADCLPOL */
+#define WM8985_ADCLPOL_SHIFT 0 /* ADCLPOL */
+#define WM8985_ADCLPOL_WIDTH 1 /* ADCLPOL */
+
+/*
+ * R15 (0x0F) - Left ADC Digital Vol
+ */
+#define WM8985_ADCVU 0x0100 /* ADCVU */
+#define WM8985_ADCVU_MASK 0x0100 /* ADCVU */
+#define WM8985_ADCVU_SHIFT 8 /* ADCVU */
+#define WM8985_ADCVU_WIDTH 1 /* ADCVU */
+#define WM8985_ADCVOLL_MASK 0x00FF /* ADCVOLL - [7:0] */
+#define WM8985_ADCVOLL_SHIFT 0 /* ADCVOLL - [7:0] */
+#define WM8985_ADCVOLL_WIDTH 8 /* ADCVOLL - [7:0] */
+
+/*
+ * R16 (0x10) - Right ADC Digital Vol
+ */
+#define WM8985_ADCVU 0x0100 /* ADCVU */
+#define WM8985_ADCVU_MASK 0x0100 /* ADCVU */
+#define WM8985_ADCVU_SHIFT 8 /* ADCVU */
+#define WM8985_ADCVU_WIDTH 1 /* ADCVU */
+#define WM8985_ADCVOLR_MASK 0x00FF /* ADCVOLR - [7:0] */
+#define WM8985_ADCVOLR_SHIFT 0 /* ADCVOLR - [7:0] */
+#define WM8985_ADCVOLR_WIDTH 8 /* ADCVOLR - [7:0] */
+
+/*
+ * R18 (0x12) - EQ1 - low shelf
+ */
+#define WM8985_EQ3DMODE 0x0100 /* EQ3DMODE */
+#define WM8985_EQ3DMODE_MASK 0x0100 /* EQ3DMODE */
+#define WM8985_EQ3DMODE_SHIFT 8 /* EQ3DMODE */
+#define WM8985_EQ3DMODE_WIDTH 1 /* EQ3DMODE */
+#define WM8985_EQ1C_MASK 0x0060 /* EQ1C - [6:5] */
+#define WM8985_EQ1C_SHIFT 5 /* EQ1C - [6:5] */
+#define WM8985_EQ1C_WIDTH 2 /* EQ1C - [6:5] */
+#define WM8985_EQ1G_MASK 0x001F /* EQ1G - [4:0] */
+#define WM8985_EQ1G_SHIFT 0 /* EQ1G - [4:0] */
+#define WM8985_EQ1G_WIDTH 5 /* EQ1G - [4:0] */
+
+/*
+ * R19 (0x13) - EQ2 - peak 1
+ */
+#define WM8985_EQ2BW 0x0100 /* EQ2BW */
+#define WM8985_EQ2BW_MASK 0x0100 /* EQ2BW */
+#define WM8985_EQ2BW_SHIFT 8 /* EQ2BW */
+#define WM8985_EQ2BW_WIDTH 1 /* EQ2BW */
+#define WM8985_EQ2C_MASK 0x0060 /* EQ2C - [6:5] */
+#define WM8985_EQ2C_SHIFT 5 /* EQ2C - [6:5] */
+#define WM8985_EQ2C_WIDTH 2 /* EQ2C - [6:5] */
+#define WM8985_EQ2G_MASK 0x001F /* EQ2G - [4:0] */
+#define WM8985_EQ2G_SHIFT 0 /* EQ2G - [4:0] */
+#define WM8985_EQ2G_WIDTH 5 /* EQ2G - [4:0] */
+
+/*
+ * R20 (0x14) - EQ3 - peak 2
+ */
+#define WM8985_EQ3BW 0x0100 /* EQ3BW */
+#define WM8985_EQ3BW_MASK 0x0100 /* EQ3BW */
+#define WM8985_EQ3BW_SHIFT 8 /* EQ3BW */
+#define WM8985_EQ3BW_WIDTH 1 /* EQ3BW */
+#define WM8985_EQ3C_MASK 0x0060 /* EQ3C - [6:5] */
+#define WM8985_EQ3C_SHIFT 5 /* EQ3C - [6:5] */
+#define WM8985_EQ3C_WIDTH 2 /* EQ3C - [6:5] */
+#define WM8985_EQ3G_MASK 0x001F /* EQ3G - [4:0] */
+#define WM8985_EQ3G_SHIFT 0 /* EQ3G - [4:0] */
+#define WM8985_EQ3G_WIDTH 5 /* EQ3G - [4:0] */
+
+/*
+ * R21 (0x15) - EQ4 - peak 3
+ */
+#define WM8985_EQ4BW 0x0100 /* EQ4BW */
+#define WM8985_EQ4BW_MASK 0x0100 /* EQ4BW */
+#define WM8985_EQ4BW_SHIFT 8 /* EQ4BW */
+#define WM8985_EQ4BW_WIDTH 1 /* EQ4BW */
+#define WM8985_EQ4C_MASK 0x0060 /* EQ4C - [6:5] */
+#define WM8985_EQ4C_SHIFT 5 /* EQ4C - [6:5] */
+#define WM8985_EQ4C_WIDTH 2 /* EQ4C - [6:5] */
+#define WM8985_EQ4G_MASK 0x001F /* EQ4G - [4:0] */
+#define WM8985_EQ4G_SHIFT 0 /* EQ4G - [4:0] */
+#define WM8985_EQ4G_WIDTH 5 /* EQ4G - [4:0] */
+
+/*
+ * R22 (0x16) - EQ5 - high shelf
+ */
+#define WM8985_EQ5C_MASK 0x0060 /* EQ5C - [6:5] */
+#define WM8985_EQ5C_SHIFT 5 /* EQ5C - [6:5] */
+#define WM8985_EQ5C_WIDTH 2 /* EQ5C - [6:5] */
+#define WM8985_EQ5G_MASK 0x001F /* EQ5G - [4:0] */
+#define WM8985_EQ5G_SHIFT 0 /* EQ5G - [4:0] */
+#define WM8985_EQ5G_WIDTH 5 /* EQ5G - [4:0] */
+
+/*
+ * R24 (0x18) - DAC Limiter 1
+ */
+#define WM8985_LIMEN 0x0100 /* LIMEN */
+#define WM8985_LIMEN_MASK 0x0100 /* LIMEN */
+#define WM8985_LIMEN_SHIFT 8 /* LIMEN */
+#define WM8985_LIMEN_WIDTH 1 /* LIMEN */
+#define WM8985_LIMDCY_MASK 0x00F0 /* LIMDCY - [7:4] */
+#define WM8985_LIMDCY_SHIFT 4 /* LIMDCY - [7:4] */
+#define WM8985_LIMDCY_WIDTH 4 /* LIMDCY - [7:4] */
+#define WM8985_LIMATK_MASK 0x000F /* LIMATK - [3:0] */
+#define WM8985_LIMATK_SHIFT 0 /* LIMATK - [3:0] */
+#define WM8985_LIMATK_WIDTH 4 /* LIMATK - [3:0] */
+
+/*
+ * R25 (0x19) - DAC Limiter 2
+ */
+#define WM8985_LIMLVL_MASK 0x0070 /* LIMLVL - [6:4] */
+#define WM8985_LIMLVL_SHIFT 4 /* LIMLVL - [6:4] */
+#define WM8985_LIMLVL_WIDTH 3 /* LIMLVL - [6:4] */
+#define WM8985_LIMBOOST_MASK 0x000F /* LIMBOOST - [3:0] */
+#define WM8985_LIMBOOST_SHIFT 0 /* LIMBOOST - [3:0] */
+#define WM8985_LIMBOOST_WIDTH 4 /* LIMBOOST - [3:0] */
+
+/*
+ * R27 (0x1B) - Notch Filter 1
+ */
+#define WM8985_NFU 0x0100 /* NFU */
+#define WM8985_NFU_MASK 0x0100 /* NFU */
+#define WM8985_NFU_SHIFT 8 /* NFU */
+#define WM8985_NFU_WIDTH 1 /* NFU */
+#define WM8985_NFEN 0x0080 /* NFEN */
+#define WM8985_NFEN_MASK 0x0080 /* NFEN */
+#define WM8985_NFEN_SHIFT 7 /* NFEN */
+#define WM8985_NFEN_WIDTH 1 /* NFEN */
+#define WM8985_NFA0_13_7_MASK 0x007F /* NFA0(13:7) - [6:0] */
+#define WM8985_NFA0_13_7_SHIFT 0 /* NFA0(13:7) - [6:0] */
+#define WM8985_NFA0_13_7_WIDTH 7 /* NFA0(13:7) - [6:0] */
+
+/*
+ * R28 (0x1C) - Notch Filter 2
+ */
+#define WM8985_NFU 0x0100 /* NFU */
+#define WM8985_NFU_MASK 0x0100 /* NFU */
+#define WM8985_NFU_SHIFT 8 /* NFU */
+#define WM8985_NFU_WIDTH 1 /* NFU */
+#define WM8985_NFA0_6_0_MASK 0x007F /* NFA0(6:0) - [6:0] */
+#define WM8985_NFA0_6_0_SHIFT 0 /* NFA0(6:0) - [6:0] */
+#define WM8985_NFA0_6_0_WIDTH 7 /* NFA0(6:0) - [6:0] */
+
+/*
+ * R29 (0x1D) - Notch Filter 3
+ */
+#define WM8985_NFU 0x0100 /* NFU */
+#define WM8985_NFU_MASK 0x0100 /* NFU */
+#define WM8985_NFU_SHIFT 8 /* NFU */
+#define WM8985_NFU_WIDTH 1 /* NFU */
+#define WM8985_NFA1_13_7_MASK 0x007F /* NFA1(13:7) - [6:0] */
+#define WM8985_NFA1_13_7_SHIFT 0 /* NFA1(13:7) - [6:0] */
+#define WM8985_NFA1_13_7_WIDTH 7 /* NFA1(13:7) - [6:0] */
+
+/*
+ * R30 (0x1E) - Notch Filter 4
+ */
+#define WM8985_NFU 0x0100 /* NFU */
+#define WM8985_NFU_MASK 0x0100 /* NFU */
+#define WM8985_NFU_SHIFT 8 /* NFU */
+#define WM8985_NFU_WIDTH 1 /* NFU */
+#define WM8985_NFA1_6_0_MASK 0x007F /* NFA1(6:0) - [6:0] */
+#define WM8985_NFA1_6_0_SHIFT 0 /* NFA1(6:0) - [6:0] */
+#define WM8985_NFA1_6_0_WIDTH 7 /* NFA1(6:0) - [6:0] */
+
+/*
+ * R32 (0x20) - ALC control 1
+ */
+#define WM8985_ALCSEL_MASK 0x0180 /* ALCSEL - [8:7] */
+#define WM8985_ALCSEL_SHIFT 7 /* ALCSEL - [8:7] */
+#define WM8985_ALCSEL_WIDTH 2 /* ALCSEL - [8:7] */
+#define WM8985_ALCMAX_MASK 0x0038 /* ALCMAX - [5:3] */
+#define WM8985_ALCMAX_SHIFT 3 /* ALCMAX - [5:3] */
+#define WM8985_ALCMAX_WIDTH 3 /* ALCMAX - [5:3] */
+#define WM8985_ALCMIN_MASK 0x0007 /* ALCMIN - [2:0] */
+#define WM8985_ALCMIN_SHIFT 0 /* ALCMIN - [2:0] */
+#define WM8985_ALCMIN_WIDTH 3 /* ALCMIN - [2:0] */
+
+/*
+ * R33 (0x21) - ALC control 2
+ */
+#define WM8985_ALCHLD_MASK 0x00F0 /* ALCHLD - [7:4] */
+#define WM8985_ALCHLD_SHIFT 4 /* ALCHLD - [7:4] */
+#define WM8985_ALCHLD_WIDTH 4 /* ALCHLD - [7:4] */
+#define WM8985_ALCLVL_MASK 0x000F /* ALCLVL - [3:0] */
+#define WM8985_ALCLVL_SHIFT 0 /* ALCLVL - [3:0] */
+#define WM8985_ALCLVL_WIDTH 4 /* ALCLVL - [3:0] */
+
+/*
+ * R34 (0x22) - ALC control 3
+ */
+#define WM8985_ALCMODE 0x0100 /* ALCMODE */
+#define WM8985_ALCMODE_MASK 0x0100 /* ALCMODE */
+#define WM8985_ALCMODE_SHIFT 8 /* ALCMODE */
+#define WM8985_ALCMODE_WIDTH 1 /* ALCMODE */
+#define WM8985_ALCDCY_MASK 0x00F0 /* ALCDCY - [7:4] */
+#define WM8985_ALCDCY_SHIFT 4 /* ALCDCY - [7:4] */
+#define WM8985_ALCDCY_WIDTH 4 /* ALCDCY - [7:4] */
+#define WM8985_ALCATK_MASK 0x000F /* ALCATK - [3:0] */
+#define WM8985_ALCATK_SHIFT 0 /* ALCATK - [3:0] */
+#define WM8985_ALCATK_WIDTH 4 /* ALCATK - [3:0] */
+
+/*
+ * R35 (0x23) - Noise Gate
+ */
+#define WM8985_NGEN 0x0008 /* NGEN */
+#define WM8985_NGEN_MASK 0x0008 /* NGEN */
+#define WM8985_NGEN_SHIFT 3 /* NGEN */
+#define WM8985_NGEN_WIDTH 1 /* NGEN */
+#define WM8985_NGTH_MASK 0x0007 /* NGTH - [2:0] */
+#define WM8985_NGTH_SHIFT 0 /* NGTH - [2:0] */
+#define WM8985_NGTH_WIDTH 3 /* NGTH - [2:0] */
+
+/*
+ * R36 (0x24) - PLL N
+ */
+#define WM8985_PLL_PRESCALE 0x0010 /* PLL_PRESCALE */
+#define WM8985_PLL_PRESCALE_MASK 0x0010 /* PLL_PRESCALE */
+#define WM8985_PLL_PRESCALE_SHIFT 4 /* PLL_PRESCALE */
+#define WM8985_PLL_PRESCALE_WIDTH 1 /* PLL_PRESCALE */
+#define WM8985_PLLN_MASK 0x000F /* PLLN - [3:0] */
+#define WM8985_PLLN_SHIFT 0 /* PLLN - [3:0] */
+#define WM8985_PLLN_WIDTH 4 /* PLLN - [3:0] */
+
+/*
+ * R37 (0x25) - PLL K 1
+ */
+#define WM8985_PLLK_23_18_MASK 0x003F /* PLLK(23:18) - [5:0] */
+#define WM8985_PLLK_23_18_SHIFT 0 /* PLLK(23:18) - [5:0] */
+#define WM8985_PLLK_23_18_WIDTH 6 /* PLLK(23:18) - [5:0] */
+
+/*
+ * R38 (0x26) - PLL K 2
+ */
+#define WM8985_PLLK_17_9_MASK 0x01FF /* PLLK(17:9) - [8:0] */
+#define WM8985_PLLK_17_9_SHIFT 0 /* PLLK(17:9) - [8:0] */
+#define WM8985_PLLK_17_9_WIDTH 9 /* PLLK(17:9) - [8:0] */
+
+/*
+ * R39 (0x27) - PLL K 3
+ */
+#define WM8985_PLLK_8_0_MASK 0x01FF /* PLLK(8:0) - [8:0] */
+#define WM8985_PLLK_8_0_SHIFT 0 /* PLLK(8:0) - [8:0] */
+#define WM8985_PLLK_8_0_WIDTH 9 /* PLLK(8:0) - [8:0] */
+
+/*
+ * R41 (0x29) - 3D control
+ */
+#define WM8985_DEPTH3D_MASK 0x000F /* DEPTH3D - [3:0] */
+#define WM8985_DEPTH3D_SHIFT 0 /* DEPTH3D - [3:0] */
+#define WM8985_DEPTH3D_WIDTH 4 /* DEPTH3D - [3:0] */
+
+/*
+ * R42 (0x2A) - OUT4 to ADC
+ */
+#define WM8985_OUT4_2ADCVOL_MASK 0x01C0 /* OUT4_2ADCVOL - [8:6] */
+#define WM8985_OUT4_2ADCVOL_SHIFT 6 /* OUT4_2ADCVOL - [8:6] */
+#define WM8985_OUT4_2ADCVOL_WIDTH 3 /* OUT4_2ADCVOL - [8:6] */
+#define WM8985_OUT4_2LNR 0x0020 /* OUT4_2LNR */
+#define WM8985_OUT4_2LNR_MASK 0x0020 /* OUT4_2LNR */
+#define WM8985_OUT4_2LNR_SHIFT 5 /* OUT4_2LNR */
+#define WM8985_OUT4_2LNR_WIDTH 1 /* OUT4_2LNR */
+#define WM8985_POBCTRL 0x0004 /* POBCTRL */
+#define WM8985_POBCTRL_MASK 0x0004 /* POBCTRL */
+#define WM8985_POBCTRL_SHIFT 2 /* POBCTRL */
+#define WM8985_POBCTRL_WIDTH 1 /* POBCTRL */
+#define WM8985_DELEN 0x0002 /* DELEN */
+#define WM8985_DELEN_MASK 0x0002 /* DELEN */
+#define WM8985_DELEN_SHIFT 1 /* DELEN */
+#define WM8985_DELEN_WIDTH 1 /* DELEN */
+#define WM8985_OUT1DEL 0x0001 /* OUT1DEL */
+#define WM8985_OUT1DEL_MASK 0x0001 /* OUT1DEL */
+#define WM8985_OUT1DEL_SHIFT 0 /* OUT1DEL */
+#define WM8985_OUT1DEL_WIDTH 1 /* OUT1DEL */
+
+/*
+ * R43 (0x2B) - Beep control
+ */
+#define WM8985_BYPL2RMIX 0x0100 /* BYPL2RMIX */
+#define WM8985_BYPL2RMIX_MASK 0x0100 /* BYPL2RMIX */
+#define WM8985_BYPL2RMIX_SHIFT 8 /* BYPL2RMIX */
+#define WM8985_BYPL2RMIX_WIDTH 1 /* BYPL2RMIX */
+#define WM8985_BYPR2LMIX 0x0080 /* BYPR2LMIX */
+#define WM8985_BYPR2LMIX_MASK 0x0080 /* BYPR2LMIX */
+#define WM8985_BYPR2LMIX_SHIFT 7 /* BYPR2LMIX */
+#define WM8985_BYPR2LMIX_WIDTH 1 /* BYPR2LMIX */
+#define WM8985_MUTERPGA2INV 0x0020 /* MUTERPGA2INV */
+#define WM8985_MUTERPGA2INV_MASK 0x0020 /* MUTERPGA2INV */
+#define WM8985_MUTERPGA2INV_SHIFT 5 /* MUTERPGA2INV */
+#define WM8985_MUTERPGA2INV_WIDTH 1 /* MUTERPGA2INV */
+#define WM8985_INVROUT2 0x0010 /* INVROUT2 */
+#define WM8985_INVROUT2_MASK 0x0010 /* INVROUT2 */
+#define WM8985_INVROUT2_SHIFT 4 /* INVROUT2 */
+#define WM8985_INVROUT2_WIDTH 1 /* INVROUT2 */
+#define WM8985_BEEPVOL_MASK 0x000E /* BEEPVOL - [3:1] */
+#define WM8985_BEEPVOL_SHIFT 1 /* BEEPVOL - [3:1] */
+#define WM8985_BEEPVOL_WIDTH 3 /* BEEPVOL - [3:1] */
+#define WM8985_BEEPEN 0x0001 /* BEEPEN */
+#define WM8985_BEEPEN_MASK 0x0001 /* BEEPEN */
+#define WM8985_BEEPEN_SHIFT 0 /* BEEPEN */
+#define WM8985_BEEPEN_WIDTH 1 /* BEEPEN */
+
+/*
+ * R44 (0x2C) - Input ctrl
+ */
+#define WM8985_MBVSEL 0x0100 /* MBVSEL */
+#define WM8985_MBVSEL_MASK 0x0100 /* MBVSEL */
+#define WM8985_MBVSEL_SHIFT 8 /* MBVSEL */
+#define WM8985_MBVSEL_WIDTH 1 /* MBVSEL */
+#define WM8985_R2_2INPPGA 0x0040 /* R2_2INPPGA */
+#define WM8985_R2_2INPPGA_MASK 0x0040 /* R2_2INPPGA */
+#define WM8985_R2_2INPPGA_SHIFT 6 /* R2_2INPPGA */
+#define WM8985_R2_2INPPGA_WIDTH 1 /* R2_2INPPGA */
+#define WM8985_RIN2INPPGA 0x0020 /* RIN2INPPGA */
+#define WM8985_RIN2INPPGA_MASK 0x0020 /* RIN2INPPGA */
+#define WM8985_RIN2INPPGA_SHIFT 5 /* RIN2INPPGA */
+#define WM8985_RIN2INPPGA_WIDTH 1 /* RIN2INPPGA */
+#define WM8985_RIP2INPPGA 0x0010 /* RIP2INPPGA */
+#define WM8985_RIP2INPPGA_MASK 0x0010 /* RIP2INPPGA */
+#define WM8985_RIP2INPPGA_SHIFT 4 /* RIP2INPPGA */
+#define WM8985_RIP2INPPGA_WIDTH 1 /* RIP2INPPGA */
+#define WM8985_L2_2INPPGA 0x0004 /* L2_2INPPGA */
+#define WM8985_L2_2INPPGA_MASK 0x0004 /* L2_2INPPGA */
+#define WM8985_L2_2INPPGA_SHIFT 2 /* L2_2INPPGA */
+#define WM8985_L2_2INPPGA_WIDTH 1 /* L2_2INPPGA */
+#define WM8985_LIN2INPPGA 0x0002 /* LIN2INPPGA */
+#define WM8985_LIN2INPPGA_MASK 0x0002 /* LIN2INPPGA */
+#define WM8985_LIN2INPPGA_SHIFT 1 /* LIN2INPPGA */
+#define WM8985_LIN2INPPGA_WIDTH 1 /* LIN2INPPGA */
+#define WM8985_LIP2INPPGA 0x0001 /* LIP2INPPGA */
+#define WM8985_LIP2INPPGA_MASK 0x0001 /* LIP2INPPGA */
+#define WM8985_LIP2INPPGA_SHIFT 0 /* LIP2INPPGA */
+#define WM8985_LIP2INPPGA_WIDTH 1 /* LIP2INPPGA */
+
+/*
+ * R45 (0x2D) - Left INP PGA gain ctrl
+ */
+#define WM8985_INPGAVU 0x0100 /* INPGAVU */
+#define WM8985_INPGAVU_MASK 0x0100 /* INPGAVU */
+#define WM8985_INPGAVU_SHIFT 8 /* INPGAVU */
+#define WM8985_INPGAVU_WIDTH 1 /* INPGAVU */
+#define WM8985_INPPGAZCL 0x0080 /* INPPGAZCL */
+#define WM8985_INPPGAZCL_MASK 0x0080 /* INPPGAZCL */
+#define WM8985_INPPGAZCL_SHIFT 7 /* INPPGAZCL */
+#define WM8985_INPPGAZCL_WIDTH 1 /* INPPGAZCL */
+#define WM8985_INPPGAMUTEL 0x0040 /* INPPGAMUTEL */
+#define WM8985_INPPGAMUTEL_MASK 0x0040 /* INPPGAMUTEL */
+#define WM8985_INPPGAMUTEL_SHIFT 6 /* INPPGAMUTEL */
+#define WM8985_INPPGAMUTEL_WIDTH 1 /* INPPGAMUTEL */
+#define WM8985_INPPGAVOLL_MASK 0x003F /* INPPGAVOLL - [5:0] */
+#define WM8985_INPPGAVOLL_SHIFT 0 /* INPPGAVOLL - [5:0] */
+#define WM8985_INPPGAVOLL_WIDTH 6 /* INPPGAVOLL - [5:0] */
+
+/*
+ * R46 (0x2E) - Right INP PGA gain ctrl
+ */
+#define WM8985_INPGAVU 0x0100 /* INPGAVU */
+#define WM8985_INPGAVU_MASK 0x0100 /* INPGAVU */
+#define WM8985_INPGAVU_SHIFT 8 /* INPGAVU */
+#define WM8985_INPGAVU_WIDTH 1 /* INPGAVU */
+#define WM8985_INPPGAZCR 0x0080 /* INPPGAZCR */
+#define WM8985_INPPGAZCR_MASK 0x0080 /* INPPGAZCR */
+#define WM8985_INPPGAZCR_SHIFT 7 /* INPPGAZCR */
+#define WM8985_INPPGAZCR_WIDTH 1 /* INPPGAZCR */
+#define WM8985_INPPGAMUTER 0x0040 /* INPPGAMUTER */
+#define WM8985_INPPGAMUTER_MASK 0x0040 /* INPPGAMUTER */
+#define WM8985_INPPGAMUTER_SHIFT 6 /* INPPGAMUTER */
+#define WM8985_INPPGAMUTER_WIDTH 1 /* INPPGAMUTER */
+#define WM8985_INPPGAVOLR_MASK 0x003F /* INPPGAVOLR - [5:0] */
+#define WM8985_INPPGAVOLR_SHIFT 0 /* INPPGAVOLR - [5:0] */
+#define WM8985_INPPGAVOLR_WIDTH 6 /* INPPGAVOLR - [5:0] */
+
+/*
+ * R47 (0x2F) - Left ADC BOOST ctrl
+ */
+#define WM8985_PGABOOSTL 0x0100 /* PGABOOSTL */
+#define WM8985_PGABOOSTL_MASK 0x0100 /* PGABOOSTL */
+#define WM8985_PGABOOSTL_SHIFT 8 /* PGABOOSTL */
+#define WM8985_PGABOOSTL_WIDTH 1 /* PGABOOSTL */
+#define WM8985_L2_2BOOSTVOL_MASK 0x0070 /* L2_2BOOSTVOL - [6:4] */
+#define WM8985_L2_2BOOSTVOL_SHIFT 4 /* L2_2BOOSTVOL - [6:4] */
+#define WM8985_L2_2BOOSTVOL_WIDTH 3 /* L2_2BOOSTVOL - [6:4] */
+#define WM8985_AUXL2BOOSTVOL_MASK 0x0007 /* AUXL2BOOSTVOL - [2:0] */
+#define WM8985_AUXL2BOOSTVOL_SHIFT 0 /* AUXL2BOOSTVOL - [2:0] */
+#define WM8985_AUXL2BOOSTVOL_WIDTH 3 /* AUXL2BOOSTVOL - [2:0] */
+
+/*
+ * R48 (0x30) - Right ADC BOOST ctrl
+ */
+#define WM8985_PGABOOSTR 0x0100 /* PGABOOSTR */
+#define WM8985_PGABOOSTR_MASK 0x0100 /* PGABOOSTR */
+#define WM8985_PGABOOSTR_SHIFT 8 /* PGABOOSTR */
+#define WM8985_PGABOOSTR_WIDTH 1 /* PGABOOSTR */
+#define WM8985_R2_2BOOSTVOL_MASK 0x0070 /* R2_2BOOSTVOL - [6:4] */
+#define WM8985_R2_2BOOSTVOL_SHIFT 4 /* R2_2BOOSTVOL - [6:4] */
+#define WM8985_R2_2BOOSTVOL_WIDTH 3 /* R2_2BOOSTVOL - [6:4] */
+#define WM8985_AUXR2BOOSTVOL_MASK 0x0007 /* AUXR2BOOSTVOL - [2:0] */
+#define WM8985_AUXR2BOOSTVOL_SHIFT 0 /* AUXR2BOOSTVOL - [2:0] */
+#define WM8985_AUXR2BOOSTVOL_WIDTH 3 /* AUXR2BOOSTVOL - [2:0] */
+
+/*
+ * R49 (0x31) - Output ctrl
+ */
+#define WM8985_DACL2RMIX 0x0040 /* DACL2RMIX */
+#define WM8985_DACL2RMIX_MASK 0x0040 /* DACL2RMIX */
+#define WM8985_DACL2RMIX_SHIFT 6 /* DACL2RMIX */
+#define WM8985_DACL2RMIX_WIDTH 1 /* DACL2RMIX */
+#define WM8985_DACR2LMIX 0x0020 /* DACR2LMIX */
+#define WM8985_DACR2LMIX_MASK 0x0020 /* DACR2LMIX */
+#define WM8985_DACR2LMIX_SHIFT 5 /* DACR2LMIX */
+#define WM8985_DACR2LMIX_WIDTH 1 /* DACR2LMIX */
+#define WM8985_OUT4BOOST 0x0010 /* OUT4BOOST */
+#define WM8985_OUT4BOOST_MASK 0x0010 /* OUT4BOOST */
+#define WM8985_OUT4BOOST_SHIFT 4 /* OUT4BOOST */
+#define WM8985_OUT4BOOST_WIDTH 1 /* OUT4BOOST */
+#define WM8985_OUT3BOOST 0x0008 /* OUT3BOOST */
+#define WM8985_OUT3BOOST_MASK 0x0008 /* OUT3BOOST */
+#define WM8985_OUT3BOOST_SHIFT 3 /* OUT3BOOST */
+#define WM8985_OUT3BOOST_WIDTH 1 /* OUT3BOOST */
+#define WM8985_TSOPCTRL 0x0004 /* TSOPCTRL */
+#define WM8985_TSOPCTRL_MASK 0x0004 /* TSOPCTRL */
+#define WM8985_TSOPCTRL_SHIFT 2 /* TSOPCTRL */
+#define WM8985_TSOPCTRL_WIDTH 1 /* TSOPCTRL */
+#define WM8985_TSDEN 0x0002 /* TSDEN */
+#define WM8985_TSDEN_MASK 0x0002 /* TSDEN */
+#define WM8985_TSDEN_SHIFT 1 /* TSDEN */
+#define WM8985_TSDEN_WIDTH 1 /* TSDEN */
+#define WM8985_VROI 0x0001 /* VROI */
+#define WM8985_VROI_MASK 0x0001 /* VROI */
+#define WM8985_VROI_SHIFT 0 /* VROI */
+#define WM8985_VROI_WIDTH 1 /* VROI */
+
+/*
+ * R50 (0x32) - Left mixer ctrl
+ */
+#define WM8985_AUXLMIXVOL_MASK 0x01C0 /* AUXLMIXVOL - [8:6] */
+#define WM8985_AUXLMIXVOL_SHIFT 6 /* AUXLMIXVOL - [8:6] */
+#define WM8985_AUXLMIXVOL_WIDTH 3 /* AUXLMIXVOL - [8:6] */
+#define WM8985_AUXL2LMIX 0x0020 /* AUXL2LMIX */
+#define WM8985_AUXL2LMIX_MASK 0x0020 /* AUXL2LMIX */
+#define WM8985_AUXL2LMIX_SHIFT 5 /* AUXL2LMIX */
+#define WM8985_AUXL2LMIX_WIDTH 1 /* AUXL2LMIX */
+#define WM8985_BYPLMIXVOL_MASK 0x001C /* BYPLMIXVOL - [4:2] */
+#define WM8985_BYPLMIXVOL_SHIFT 2 /* BYPLMIXVOL - [4:2] */
+#define WM8985_BYPLMIXVOL_WIDTH 3 /* BYPLMIXVOL - [4:2] */
+#define WM8985_BYPL2LMIX 0x0002 /* BYPL2LMIX */
+#define WM8985_BYPL2LMIX_MASK 0x0002 /* BYPL2LMIX */
+#define WM8985_BYPL2LMIX_SHIFT 1 /* BYPL2LMIX */
+#define WM8985_BYPL2LMIX_WIDTH 1 /* BYPL2LMIX */
+#define WM8985_DACL2LMIX 0x0001 /* DACL2LMIX */
+#define WM8985_DACL2LMIX_MASK 0x0001 /* DACL2LMIX */
+#define WM8985_DACL2LMIX_SHIFT 0 /* DACL2LMIX */
+#define WM8985_DACL2LMIX_WIDTH 1 /* DACL2LMIX */
+
+/*
+ * R51 (0x33) - Right mixer ctrl
+ */
+#define WM8985_AUXRMIXVOL_MASK 0x01C0 /* AUXRMIXVOL - [8:6] */
+#define WM8985_AUXRMIXVOL_SHIFT 6 /* AUXRMIXVOL - [8:6] */
+#define WM8985_AUXRMIXVOL_WIDTH 3 /* AUXRMIXVOL - [8:6] */
+#define WM8985_AUXR2RMIX 0x0020 /* AUXR2RMIX */
+#define WM8985_AUXR2RMIX_MASK 0x0020 /* AUXR2RMIX */
+#define WM8985_AUXR2RMIX_SHIFT 5 /* AUXR2RMIX */
+#define WM8985_AUXR2RMIX_WIDTH 1 /* AUXR2RMIX */
+#define WM8985_BYPRMIXVOL_MASK 0x001C /* BYPRMIXVOL - [4:2] */
+#define WM8985_BYPRMIXVOL_SHIFT 2 /* BYPRMIXVOL - [4:2] */
+#define WM8985_BYPRMIXVOL_WIDTH 3 /* BYPRMIXVOL - [4:2] */
+#define WM8985_BYPR2RMIX 0x0002 /* BYPR2RMIX */
+#define WM8985_BYPR2RMIX_MASK 0x0002 /* BYPR2RMIX */
+#define WM8985_BYPR2RMIX_SHIFT 1 /* BYPR2RMIX */
+#define WM8985_BYPR2RMIX_WIDTH 1 /* BYPR2RMIX */
+#define WM8985_DACR2RMIX 0x0001 /* DACR2RMIX */
+#define WM8985_DACR2RMIX_MASK 0x0001 /* DACR2RMIX */
+#define WM8985_DACR2RMIX_SHIFT 0 /* DACR2RMIX */
+#define WM8985_DACR2RMIX_WIDTH 1 /* DACR2RMIX */
+
+/*
+ * R52 (0x34) - LOUT1 (HP) volume ctrl
+ */
+#define WM8985_OUT1VU 0x0100 /* OUT1VU */
+#define WM8985_OUT1VU_MASK 0x0100 /* OUT1VU */
+#define WM8985_OUT1VU_SHIFT 8 /* OUT1VU */
+#define WM8985_OUT1VU_WIDTH 1 /* OUT1VU */
+#define WM8985_LOUT1ZC 0x0080 /* LOUT1ZC */
+#define WM8985_LOUT1ZC_MASK 0x0080 /* LOUT1ZC */
+#define WM8985_LOUT1ZC_SHIFT 7 /* LOUT1ZC */
+#define WM8985_LOUT1ZC_WIDTH 1 /* LOUT1ZC */
+#define WM8985_LOUT1MUTE 0x0040 /* LOUT1MUTE */
+#define WM8985_LOUT1MUTE_MASK 0x0040 /* LOUT1MUTE */
+#define WM8985_LOUT1MUTE_SHIFT 6 /* LOUT1MUTE */
+#define WM8985_LOUT1MUTE_WIDTH 1 /* LOUT1MUTE */
+#define WM8985_LOUT1VOL_MASK 0x003F /* LOUT1VOL - [5:0] */
+#define WM8985_LOUT1VOL_SHIFT 0 /* LOUT1VOL - [5:0] */
+#define WM8985_LOUT1VOL_WIDTH 6 /* LOUT1VOL - [5:0] */
+
+/*
+ * R53 (0x35) - ROUT1 (HP) volume ctrl
+ */
+#define WM8985_OUT1VU 0x0100 /* OUT1VU */
+#define WM8985_OUT1VU_MASK 0x0100 /* OUT1VU */
+#define WM8985_OUT1VU_SHIFT 8 /* OUT1VU */
+#define WM8985_OUT1VU_WIDTH 1 /* OUT1VU */
+#define WM8985_ROUT1ZC 0x0080 /* ROUT1ZC */
+#define WM8985_ROUT1ZC_MASK 0x0080 /* ROUT1ZC */
+#define WM8985_ROUT1ZC_SHIFT 7 /* ROUT1ZC */
+#define WM8985_ROUT1ZC_WIDTH 1 /* ROUT1ZC */
+#define WM8985_ROUT1MUTE 0x0040 /* ROUT1MUTE */
+#define WM8985_ROUT1MUTE_MASK 0x0040 /* ROUT1MUTE */
+#define WM8985_ROUT1MUTE_SHIFT 6 /* ROUT1MUTE */
+#define WM8985_ROUT1MUTE_WIDTH 1 /* ROUT1MUTE */
+#define WM8985_ROUT1VOL_MASK 0x003F /* ROUT1VOL - [5:0] */
+#define WM8985_ROUT1VOL_SHIFT 0 /* ROUT1VOL - [5:0] */
+#define WM8985_ROUT1VOL_WIDTH 6 /* ROUT1VOL - [5:0] */
+
+/*
+ * R54 (0x36) - LOUT2 (SPK) volume ctrl
+ */
+#define WM8985_OUT2VU 0x0100 /* OUT2VU */
+#define WM8985_OUT2VU_MASK 0x0100 /* OUT2VU */
+#define WM8985_OUT2VU_SHIFT 8 /* OUT2VU */
+#define WM8985_OUT2VU_WIDTH 1 /* OUT2VU */
+#define WM8985_LOUT2ZC 0x0080 /* LOUT2ZC */
+#define WM8985_LOUT2ZC_MASK 0x0080 /* LOUT2ZC */
+#define WM8985_LOUT2ZC_SHIFT 7 /* LOUT2ZC */
+#define WM8985_LOUT2ZC_WIDTH 1 /* LOUT2ZC */
+#define WM8985_LOUT2MUTE 0x0040 /* LOUT2MUTE */
+#define WM8985_LOUT2MUTE_MASK 0x0040 /* LOUT2MUTE */
+#define WM8985_LOUT2MUTE_SHIFT 6 /* LOUT2MUTE */
+#define WM8985_LOUT2MUTE_WIDTH 1 /* LOUT2MUTE */
+#define WM8985_LOUT2VOL_MASK 0x003F /* LOUT2VOL - [5:0] */
+#define WM8985_LOUT2VOL_SHIFT 0 /* LOUT2VOL - [5:0] */
+#define WM8985_LOUT2VOL_WIDTH 6 /* LOUT2VOL - [5:0] */
+
+/*
+ * R55 (0x37) - ROUT2 (SPK) volume ctrl
+ */
+#define WM8985_OUT2VU 0x0100 /* OUT2VU */
+#define WM8985_OUT2VU_MASK 0x0100 /* OUT2VU */
+#define WM8985_OUT2VU_SHIFT 8 /* OUT2VU */
+#define WM8985_OUT2VU_WIDTH 1 /* OUT2VU */
+#define WM8985_ROUT2ZC 0x0080 /* ROUT2ZC */
+#define WM8985_ROUT2ZC_MASK 0x0080 /* ROUT2ZC */
+#define WM8985_ROUT2ZC_SHIFT 7 /* ROUT2ZC */
+#define WM8985_ROUT2ZC_WIDTH 1 /* ROUT2ZC */
+#define WM8985_ROUT2MUTE 0x0040 /* ROUT2MUTE */
+#define WM8985_ROUT2MUTE_MASK 0x0040 /* ROUT2MUTE */
+#define WM8985_ROUT2MUTE_SHIFT 6 /* ROUT2MUTE */
+#define WM8985_ROUT2MUTE_WIDTH 1 /* ROUT2MUTE */
+#define WM8985_ROUT2VOL_MASK 0x003F /* ROUT2VOL - [5:0] */
+#define WM8985_ROUT2VOL_SHIFT 0 /* ROUT2VOL - [5:0] */
+#define WM8985_ROUT2VOL_WIDTH 6 /* ROUT2VOL - [5:0] */
+
+/*
+ * R56 (0x38) - OUT3 mixer ctrl
+ */
+#define WM8985_OUT3MUTE 0x0040 /* OUT3MUTE */
+#define WM8985_OUT3MUTE_MASK 0x0040 /* OUT3MUTE */
+#define WM8985_OUT3MUTE_SHIFT 6 /* OUT3MUTE */
+#define WM8985_OUT3MUTE_WIDTH 1 /* OUT3MUTE */
+#define WM8985_OUT4_2OUT3 0x0008 /* OUT4_2OUT3 */
+#define WM8985_OUT4_2OUT3_MASK 0x0008 /* OUT4_2OUT3 */
+#define WM8985_OUT4_2OUT3_SHIFT 3 /* OUT4_2OUT3 */
+#define WM8985_OUT4_2OUT3_WIDTH 1 /* OUT4_2OUT3 */
+#define WM8985_BYPL2OUT3 0x0004 /* BYPL2OUT3 */
+#define WM8985_BYPL2OUT3_MASK 0x0004 /* BYPL2OUT3 */
+#define WM8985_BYPL2OUT3_SHIFT 2 /* BYPL2OUT3 */
+#define WM8985_BYPL2OUT3_WIDTH 1 /* BYPL2OUT3 */
+#define WM8985_LMIX2OUT3 0x0002 /* LMIX2OUT3 */
+#define WM8985_LMIX2OUT3_MASK 0x0002 /* LMIX2OUT3 */
+#define WM8985_LMIX2OUT3_SHIFT 1 /* LMIX2OUT3 */
+#define WM8985_LMIX2OUT3_WIDTH 1 /* LMIX2OUT3 */
+#define WM8985_LDAC2OUT3 0x0001 /* LDAC2OUT3 */
+#define WM8985_LDAC2OUT3_MASK 0x0001 /* LDAC2OUT3 */
+#define WM8985_LDAC2OUT3_SHIFT 0 /* LDAC2OUT3 */
+#define WM8985_LDAC2OUT3_WIDTH 1 /* LDAC2OUT3 */
+
+/*
+ * R57 (0x39) - OUT4 (MONO) mix ctrl
+ */
+#define WM8985_OUT3_2OUT4 0x0080 /* OUT3_2OUT4 */
+#define WM8985_OUT3_2OUT4_MASK 0x0080 /* OUT3_2OUT4 */
+#define WM8985_OUT3_2OUT4_SHIFT 7 /* OUT3_2OUT4 */
+#define WM8985_OUT3_2OUT4_WIDTH 1 /* OUT3_2OUT4 */
+#define WM8985_OUT4MUTE 0x0040 /* OUT4MUTE */
+#define WM8985_OUT4MUTE_MASK 0x0040 /* OUT4MUTE */
+#define WM8985_OUT4MUTE_SHIFT 6 /* OUT4MUTE */
+#define WM8985_OUT4MUTE_WIDTH 1 /* OUT4MUTE */
+#define WM8985_OUT4ATTN 0x0020 /* OUT4ATTN */
+#define WM8985_OUT4ATTN_MASK 0x0020 /* OUT4ATTN */
+#define WM8985_OUT4ATTN_SHIFT 5 /* OUT4ATTN */
+#define WM8985_OUT4ATTN_WIDTH 1 /* OUT4ATTN */
+#define WM8985_LMIX2OUT4 0x0010 /* LMIX2OUT4 */
+#define WM8985_LMIX2OUT4_MASK 0x0010 /* LMIX2OUT4 */
+#define WM8985_LMIX2OUT4_SHIFT 4 /* LMIX2OUT4 */
+#define WM8985_LMIX2OUT4_WIDTH 1 /* LMIX2OUT4 */
+#define WM8985_LDAC2OUT4 0x0008 /* LDAC2OUT4 */
+#define WM8985_LDAC2OUT4_MASK 0x0008 /* LDAC2OUT4 */
+#define WM8985_LDAC2OUT4_SHIFT 3 /* LDAC2OUT4 */
+#define WM8985_LDAC2OUT4_WIDTH 1 /* LDAC2OUT4 */
+#define WM8985_BYPR2OUT4 0x0004 /* BYPR2OUT4 */
+#define WM8985_BYPR2OUT4_MASK 0x0004 /* BYPR2OUT4 */
+#define WM8985_BYPR2OUT4_SHIFT 2 /* BYPR2OUT4 */
+#define WM8985_BYPR2OUT4_WIDTH 1 /* BYPR2OUT4 */
+#define WM8985_RMIX2OUT4 0x0002 /* RMIX2OUT4 */
+#define WM8985_RMIX2OUT4_MASK 0x0002 /* RMIX2OUT4 */
+#define WM8985_RMIX2OUT4_SHIFT 1 /* RMIX2OUT4 */
+#define WM8985_RMIX2OUT4_WIDTH 1 /* RMIX2OUT4 */
+#define WM8985_RDAC2OUT4 0x0001 /* RDAC2OUT4 */
+#define WM8985_RDAC2OUT4_MASK 0x0001 /* RDAC2OUT4 */
+#define WM8985_RDAC2OUT4_SHIFT 0 /* RDAC2OUT4 */
+#define WM8985_RDAC2OUT4_WIDTH 1 /* RDAC2OUT4 */
+
+/*
+ * R60 (0x3C) - OUTPUT ctrl
+ */
+#define WM8985_VIDBUFFTST_MASK 0x01E0 /* VIDBUFFTST - [8:5] */
+#define WM8985_VIDBUFFTST_SHIFT 5 /* VIDBUFFTST - [8:5] */
+#define WM8985_VIDBUFFTST_WIDTH 4 /* VIDBUFFTST - [8:5] */
+#define WM8985_HPTOG 0x0008 /* HPTOG */
+#define WM8985_HPTOG_MASK 0x0008 /* HPTOG */
+#define WM8985_HPTOG_SHIFT 3 /* HPTOG */
+#define WM8985_HPTOG_WIDTH 1 /* HPTOG */
+
+/*
+ * R61 (0x3D) - BIAS CTRL
+ */
+#define WM8985_BIASCUT 0x0100 /* BIASCUT */
+#define WM8985_BIASCUT_MASK 0x0100 /* BIASCUT */
+#define WM8985_BIASCUT_SHIFT 8 /* BIASCUT */
+#define WM8985_BIASCUT_WIDTH 1 /* BIASCUT */
+#define WM8985_HALFIPBIAS 0x0080 /* HALFIPBIAS */
+#define WM8985_HALFIPBIAS_MASK 0x0080 /* HALFIPBIAS */
+#define WM8985_HALFIPBIAS_SHIFT 7 /* HALFIPBIAS */
+#define WM8985_HALFIPBIAS_WIDTH 1 /* HALFIPBIAS */
+#define WM8985_VBBIASTST_MASK 0x0060 /* VBBIASTST - [6:5] */
+#define WM8985_VBBIASTST_SHIFT 5 /* VBBIASTST - [6:5] */
+#define WM8985_VBBIASTST_WIDTH 2 /* VBBIASTST - [6:5] */
+#define WM8985_BUFBIAS_MASK 0x0018 /* BUFBIAS - [4:3] */
+#define WM8985_BUFBIAS_SHIFT 3 /* BUFBIAS - [4:3] */
+#define WM8985_BUFBIAS_WIDTH 2 /* BUFBIAS - [4:3] */
+#define WM8985_ADCBIAS_MASK 0x0006 /* ADCBIAS - [2:1] */
+#define WM8985_ADCBIAS_SHIFT 1 /* ADCBIAS - [2:1] */
+#define WM8985_ADCBIAS_WIDTH 2 /* ADCBIAS - [2:1] */
+#define WM8985_HALFOPBIAS 0x0001 /* HALFOPBIAS */
+#define WM8985_HALFOPBIAS_MASK 0x0001 /* HALFOPBIAS */
+#define WM8985_HALFOPBIAS_SHIFT 0 /* HALFOPBIAS */
+#define WM8985_HALFOPBIAS_WIDTH 1 /* HALFOPBIAS */
+
+enum clk_src {
+ WM8985_CLKSRC_MCLK,
+ WM8985_CLKSRC_PLL
+};
+
+#define WM8985_PLL 0
+
+#endif
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index 19ad590ca0b3..d7f259711970 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -52,7 +52,7 @@ static const u16 wm8988_reg[] = {
/* codec private data */
struct wm8988_priv {
unsigned int sysclk;
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
struct snd_pcm_hw_constraint_list *sysclk_constraints;
u16 reg_cache[WM8988_NUM_REG];
};
@@ -608,8 +608,7 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8988_IFACE) & 0x1f3;
u16 srate = snd_soc_read(codec, WM8988_SRATE) & 0x180;
@@ -711,8 +710,8 @@ static struct snd_soc_dai_ops wm8988_ops = {
.digital_mute = wm8988_mute,
};
-struct snd_soc_dai wm8988_dai = {
- .name = "WM8988",
+static struct snd_soc_dai_driver wm8988_dai = {
+ .name = "wm8988-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -730,21 +729,15 @@ struct snd_soc_dai wm8988_dai = {
.ops = &wm8988_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8988_dai);
-static int wm8988_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8988_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8988_resume(struct platform_device *pdev)
+static int wm8988_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -763,99 +756,22 @@ static int wm8988_resume(struct platform_device *pdev)
return 0;
}
-static struct snd_soc_codec *wm8988_codec;
-
-static int wm8988_probe(struct platform_device *pdev)
+static int wm8988_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
+ struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
-
- if (wm8988_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8988_codec;
- codec = wm8988_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
- }
-
- snd_soc_add_controls(codec, wm8988_snd_controls,
- ARRAY_SIZE(wm8988_snd_controls));
- snd_soc_dapm_new_controls(codec, wm8988_dapm_widgets,
- ARRAY_SIZE(wm8988_dapm_widgets));
- snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-
- return ret;
-
-pcm_err:
- return ret;
-}
-
-static int wm8988_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8988 = {
- .probe = wm8988_probe,
- .remove = wm8988_remove,
- .suspend = wm8988_suspend,
- .resume = wm8988_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8988);
-
-static int wm8988_register(struct wm8988_priv *wm8988,
- enum snd_soc_control_type control)
-{
- struct snd_soc_codec *codec = &wm8988->codec;
- int ret;
u16 reg;
- if (wm8988_codec) {
- dev_err(codec->dev, "Another WM8988 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm8988);
- codec->name = "WM8988";
- codec->owner = THIS_MODULE;
- codec->dai = &wm8988_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache);
- codec->reg_cache = &wm8988->reg_cache;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8988_set_bias_level;
-
- memcpy(codec->reg_cache, wm8988_reg,
- sizeof(wm8988_reg));
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8988->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
+ return ret;
}
ret = wm8988_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
+ return ret;
}
/* set the update bits (we always update left then right) */
@@ -870,139 +786,132 @@ static int wm8988_register(struct wm8988_priv *wm8988,
reg = snd_soc_read(codec, WM8988_RINVOL);
snd_soc_write(codec, WM8988_RINVOL, reg | 0x0100);
- wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY);
-
- wm8988_dai.dev = codec->dev;
-
- wm8988_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
+ wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- ret = snd_soc_register_dai(&wm8988_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+ snd_soc_add_controls(codec, wm8988_snd_controls,
+ ARRAY_SIZE(wm8988_snd_controls));
+ snd_soc_dapm_new_controls(codec, wm8988_dapm_widgets,
+ ARRAY_SIZE(wm8988_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm8988);
- return ret;
}
-static void wm8988_unregister(struct wm8988_priv *wm8988)
+static int wm8988_remove(struct snd_soc_codec *codec)
{
- wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm8988_dai);
- snd_soc_unregister_codec(&wm8988->codec);
- kfree(wm8988);
- wm8988_codec = NULL;
+ wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static int wm8988_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static struct snd_soc_codec_driver soc_codec_dev_wm8988 = {
+ .probe = wm8988_probe,
+ .remove = wm8988_remove,
+ .suspend = wm8988_suspend,
+ .resume = wm8988_resume,
+ .set_bias_level = wm8988_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8988_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8988_reg,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8988_spi_probe(struct spi_device *spi)
{
struct wm8988_priv *wm8988;
- struct snd_soc_codec *codec;
+ int ret;
wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL);
if (wm8988 == NULL)
return -ENOMEM;
- codec = &wm8988->codec;
-
- i2c_set_clientdata(i2c, wm8988);
- codec->control_data = i2c;
-
- codec->dev = &i2c->dev;
+ wm8988->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8988);
- return wm8988_register(wm8988, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8988, &wm8988_dai, 1);
+ if (ret < 0)
+ kfree(wm8988);
+ return ret;
}
-static int wm8988_i2c_remove(struct i2c_client *client)
+static int __devexit wm8988_spi_remove(struct spi_device *spi)
{
- struct wm8988_priv *wm8988 = i2c_get_clientdata(client);
- wm8988_unregister(wm8988);
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
return 0;
}
-static const struct i2c_device_id wm8988_i2c_id[] = {
- { "wm8988", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id);
-
-static struct i2c_driver wm8988_i2c_driver = {
+static struct spi_driver wm8988_spi_driver = {
.driver = {
- .name = "WM8988",
- .owner = THIS_MODULE,
+ .name = "wm8988-codec",
+ .owner = THIS_MODULE,
},
- .probe = wm8988_i2c_probe,
- .remove = wm8988_i2c_remove,
- .id_table = wm8988_i2c_id,
+ .probe = wm8988_spi_probe,
+ .remove = __devexit_p(wm8988_spi_remove),
};
-#endif
+#endif /* CONFIG_SPI_MASTER */
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8988_spi_probe(struct spi_device *spi)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8988_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
struct wm8988_priv *wm8988;
- struct snd_soc_codec *codec;
+ int ret;
wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL);
if (wm8988 == NULL)
return -ENOMEM;
- codec = &wm8988->codec;
- codec->control_data = spi;
- codec->dev = &spi->dev;
-
- dev_set_drvdata(&spi->dev, wm8988);
+ i2c_set_clientdata(i2c, wm8988);
+ wm8988->control_type = SND_SOC_I2C;
- return wm8988_register(wm8988, SND_SOC_SPI);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8988, &wm8988_dai, 1);
+ if (ret < 0)
+ kfree(wm8988);
+ return ret;
}
-static int __devexit wm8988_spi_remove(struct spi_device *spi)
+static __devexit int wm8988_i2c_remove(struct i2c_client *client)
{
- struct wm8988_priv *wm8988 = dev_get_drvdata(&spi->dev);
-
- wm8988_unregister(wm8988);
-
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
-static struct spi_driver wm8988_spi_driver = {
+static const struct i2c_device_id wm8988_i2c_id[] = {
+ { "wm8988", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id);
+
+static struct i2c_driver wm8988_i2c_driver = {
.driver = {
- .name = "wm8988",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
+ .name = "wm8988-codec",
+ .owner = THIS_MODULE,
},
- .probe = wm8988_spi_probe,
- .remove = __devexit_p(wm8988_spi_remove),
+ .probe = wm8988_i2c_probe,
+ .remove = __devexit_p(wm8988_i2c_remove),
+ .id_table = wm8988_i2c_id,
};
#endif
static int __init wm8988_modinit(void)
{
- int ret;
-
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8988_i2c_driver);
- if (ret != 0)
- pr_err("WM8988: Unable to register I2C driver: %d\n", ret);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8988 I2C driver: %d\n",
+ ret);
+ }
#endif
#if defined(CONFIG_SPI_MASTER)
ret = spi_register_driver(&wm8988_spi_driver);
- if (ret != 0)
- pr_err("WM8988: Unable to register SPI driver: %d\n", ret);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8988 SPI driver: %d\n",
+ ret);
+ }
#endif
return ret;
}
diff --git a/sound/soc/codecs/wm8988.h b/sound/soc/codecs/wm8988.h
index 4552d37fdd41..5c04024e5f9f 100644
--- a/sound/soc/codecs/wm8988.h
+++ b/sound/soc/codecs/wm8988.h
@@ -54,7 +54,4 @@
#define WM8988_SYSCLK 0
-extern struct snd_soc_dai wm8988_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8988;
-
#endif
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index dd8d909788c1..264828e4e67c 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -32,6 +32,7 @@
/* codec private data */
struct wm8990_priv {
+ enum snd_soc_control_type control_type;
unsigned int sysclk;
unsigned int pcmclk;
};
@@ -1114,8 +1115,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
audio1 &= ~WM8990_AIF_WL_MASK;
@@ -1293,10 +1293,9 @@ static struct snd_soc_dai_ops wm8990_dai_ops = {
.set_sysclk = wm8990_set_dai_sysclk,
};
-struct snd_soc_dai wm8990_dai = {
+static struct snd_soc_dai_driver wm8990_dai = {
/* ADC/DAC on primary */
- .name = "WM8990 ADC/DAC Primary",
- .id = 1,
+ .name = "wm8990-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -1311,21 +1310,15 @@ struct snd_soc_dai wm8990_dai = {
.formats = WM8990_FORMATS,},
.ops = &wm8990_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm8990_dai);
-static int wm8990_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8990_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8990_resume(struct platform_device *pdev)
+static int wm8990_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -1347,40 +1340,20 @@ static int wm8990_resume(struct platform_device *pdev)
* initialise the WM8990 driver
* register the mixer and dsp interfaces with the kernel
*/
-static int wm8990_init(struct snd_soc_device *socdev)
+static int wm8990_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
+ int ret;
u16 reg;
- int ret = 0;
-
- codec->name = "WM8990";
- codec->owner = THIS_MODULE;
- codec->set_bias_level = wm8990_set_bias_level;
- codec->dai = &wm8990_dai;
- codec->num_dai = 2;
- codec->reg_cache_size = ARRAY_SIZE(wm8990_reg);
- codec->reg_cache = kmemdup(wm8990_reg, sizeof(wm8990_reg), GFP_KERNEL);
-
- if (codec->reg_cache == NULL)
- return -ENOMEM;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret < 0) {
printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret);
- goto pcm_err;
+ return ret;
}
wm8990_reset(codec);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "wm8990: failed to create pcms\n");
- goto pcm_err;
- }
-
/* charge output caps */
- codec->bias_level = SND_SOC_BIAS_OFF;
wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
reg = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_4);
@@ -1400,47 +1373,51 @@ static int wm8990_init(struct snd_soc_device *socdev)
ARRAY_SIZE(wm8990_snd_controls));
wm8990_add_widgets(codec);
- return ret;
+ return 0;
+}
-pcm_err:
- kfree(codec->reg_cache);
- return ret;
+/* power down chip */
+static int wm8990_remove(struct snd_soc_codec *codec)
+{
+ wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
}
-/* If the i2c layer weren't so broken, we could pass this kind of data
- around */
-static struct snd_soc_device *wm8990_socdev;
+static struct snd_soc_codec_driver soc_codec_dev_wm8990 = {
+ .probe = wm8990_probe,
+ .remove = wm8990_remove,
+ .suspend = wm8990_suspend,
+ .resume = wm8990_resume,
+ .set_bias_level = wm8990_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8990_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8990_reg,
+};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-/*
- * WM891 2 wire address is determined by GPIO5
- * state during powerup.
- * low = 0x34
- * high = 0x36
- */
-
-static int wm8990_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static __devinit int wm8990_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
- struct snd_soc_device *socdev = wm8990_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct wm8990_priv *wm8990;
int ret;
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
+ wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL);
+ if (wm8990 == NULL)
+ return -ENOMEM;
- ret = wm8990_init(socdev);
- if (ret < 0)
- pr_err("failed to initialise WM8990\n");
+ i2c_set_clientdata(i2c, wm8990);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8990, &wm8990_dai, 1);
+ if (ret < 0)
+ kfree(wm8990);
return ret;
}
-static int wm8990_i2c_remove(struct i2c_client *client)
+static __devexit int wm8990_i2c_remove(struct i2c_client *client)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1452,134 +1429,34 @@ MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id);
static struct i2c_driver wm8990_i2c_driver = {
.driver = {
- .name = "WM8990 I2C Codec",
+ .name = "wm8990-codec",
.owner = THIS_MODULE,
},
.probe = wm8990_i2c_probe,
- .remove = wm8990_i2c_remove,
+ .remove = __devexit_p(wm8990_i2c_remove),
.id_table = wm8990_i2c_id,
};
-
-static int wm8990_add_i2c_device(struct platform_device *pdev,
- const struct wm8990_setup_data *setup)
-{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- int ret;
-
- ret = i2c_add_driver(&wm8990_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
- }
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "wm8990", I2C_NAME_SIZE);
-
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
-
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
- }
-
- return 0;
-
-err_driver:
- i2c_del_driver(&wm8990_i2c_driver);
- return -ENODEV;
-}
#endif
-static int wm8990_probe(struct platform_device *pdev)
+static int __init wm8990_modinit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct wm8990_setup_data *setup;
- struct snd_soc_codec *codec;
- struct wm8990_priv *wm8990;
- int ret;
-
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL);
- if (wm8990 == NULL) {
- kfree(codec);
- return -ENOMEM;
- }
-
- snd_soc_codec_set_drvdata(codec, wm8990);
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
- wm8990_socdev = socdev;
-
- ret = -ENODEV;
-
+ int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- codec->hw_write = (hw_write_t)i2c_master_send;
- ret = wm8990_add_i2c_device(pdev, setup);
- }
-#endif
-
+ ret = i2c_add_driver(&wm8990_i2c_driver);
if (ret != 0) {
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
+ printk(KERN_ERR "Failed to register wm8990 I2C driver: %d\n",
+ ret);
}
+#endif
return ret;
}
+module_init(wm8990_modinit);
-/* power down chip */
-static int wm8990_remove(struct platform_device *pdev)
+static void __exit wm8990_exit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_unregister_device(codec->control_data);
i2c_del_driver(&wm8990_i2c_driver);
#endif
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8990 = {
- .probe = wm8990_probe,
- .remove = wm8990_remove,
- .suspend = wm8990_suspend,
- .resume = wm8990_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990);
-
-static int __init wm8990_modinit(void)
-{
- return snd_soc_register_dai(&wm8990_dai);
-}
-module_init(wm8990_modinit);
-
-static void __exit wm8990_exit(void)
-{
- snd_soc_unregister_dai(&wm8990_dai);
}
module_exit(wm8990_exit);
diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h
index 7114ddc88b4b..77c98a4bfe9c 100644
--- a/sound/soc/codecs/wm8990.h
+++ b/sound/soc/codecs/wm8990.h
@@ -826,18 +826,10 @@
#define WM8990_INMIXR_PWR_BIT 2
#define WM8990_AINRMUX_PWR_BIT 3
-struct wm8990_setup_data {
- unsigned i2c_bus;
- unsigned short i2c_address;
-};
-
#define WM8990_MCLK_DIV 0
#define WM8990_DACCLK_DIV 1
#define WM8990_ADCCLK_DIV 2
#define WM8990_BCLK_DIV 3
-extern struct snd_soc_dai wm8990_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8990;
-
#endif /* __WM8990REGISTERDEFS_H__ */
/*------------------------------ END OF FILE ---------------------------------*/
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index d8d300c6175f..589e3fa24734 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -229,7 +229,7 @@ struct wm8993_priv {
u16 reg_cache[WM8993_REGISTER_COUNT];
struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES];
struct wm8993_platform_data pdata;
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
int master;
int sysclk_source;
int tdm_slots;
@@ -367,10 +367,9 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
return 0;
}
-static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
unsigned int Fref, unsigned int Fout)
{
- struct snd_soc_codec *codec = dai->codec;
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
u16 reg1, reg4, reg5;
struct _fll_div fll_div;
@@ -456,6 +455,12 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
return 0;
}
+static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+ unsigned int Fref, unsigned int Fout)
+{
+ return _wm8993_set_fll(dai->codec, fll_id, source, Fref, Fout);
+}
+
static int configure_clock(struct snd_soc_codec *codec)
{
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
@@ -1394,8 +1399,8 @@ static struct snd_soc_dai_ops wm8993_ops = {
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
-struct snd_soc_dai wm8993_dai = {
- .name = "WM8993",
+static struct snd_soc_dai_driver wm8993_dai = {
+ .name = "wm8993-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -1413,32 +1418,81 @@ struct snd_soc_dai wm8993_dai = {
.ops = &wm8993_ops,
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8993_dai);
-
-static struct snd_soc_codec *wm8993_codec;
-static int wm8993_probe(struct platform_device *pdev)
+static int wm8993_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct wm8993_priv *wm8993;
- int ret = 0;
+ struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
+ int ret, i, val;
+
+ wm8993->hubs_data.hp_startup_mode = 1;
+ wm8993->hubs_data.dcs_codes = -2;
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++)
+ wm8993->supplies[i].supply = wm8993_supply_names[i];
- if (!wm8993_codec) {
- dev_err(&pdev->dev, "I2C device not yet probed\n");
- goto err;
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8993->supplies),
+ wm8993->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
}
- socdev->card->codec = wm8993_codec;
- codec = wm8993_codec;
- wm8993 = snd_soc_codec_get_drvdata(codec);
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
+ wm8993->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ goto err_get;
+ }
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms\n");
- goto err;
+ val = snd_soc_read(codec, WM8993_SOFTWARE_RESET);
+ if (val != wm8993_reg_defaults[WM8993_SOFTWARE_RESET]) {
+ dev_err(codec->dev, "Invalid ID register value %x\n", val);
+ ret = -EINVAL;
+ goto err_enable;
}
+ ret = snd_soc_write(codec, WM8993_SOFTWARE_RESET, 0xffff);
+ if (ret != 0)
+ goto err_enable;
+
+ codec->cache_only = 1;
+
+ /* By default we're using the output mixers */
+ wm8993->class_w_users = 2;
+
+ /* Latch volume update bits and default ZC on */
+ snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
+ WM8993_DAC_VU, WM8993_DAC_VU);
+ snd_soc_update_bits(codec, WM8993_RIGHT_ADC_DIGITAL_VOLUME,
+ WM8993_ADC_VU, WM8993_ADC_VU);
+
+ /* Manualy manage the HPOUT sequencing for independent stereo
+ * control. */
+ snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
+ WM8993_HPOUT1_AUTO_PU, 0);
+
+ /* Use automatic clock configuration */
+ snd_soc_update_bits(codec, WM8993_CLOCKING_4, WM8993_SR_MODE, 0);
+
+ wm_hubs_handle_analogue_pdata(codec, wm8993->pdata.lineout1_diff,
+ wm8993->pdata.lineout2_diff,
+ wm8993->pdata.lineout1fb,
+ wm8993->pdata.lineout2fb,
+ wm8993->pdata.jd_scthr,
+ wm8993->pdata.jd_thr,
+ wm8993->pdata.micbias1_lvl,
+ wm8993->pdata.micbias2_lvl);
+
+ ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ if (ret != 0)
+ goto err_enable;
+
snd_soc_add_controls(codec, wm8993_snd_controls,
ARRAY_SIZE(wm8993_snd_controls));
if (wm8993->pdata.num_retune_configs != 0) {
@@ -1457,36 +1511,36 @@ static int wm8993_probe(struct platform_device *pdev)
wm_hubs_add_analogue_routes(codec, wm8993->pdata.lineout1_diff,
wm8993->pdata.lineout2_diff);
- return ret;
+ return 0;
-err:
+err_enable:
+ regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
+err_get:
+ regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
return ret;
}
-static int wm8993_remove(struct platform_device *pdev)
+static int wm8993_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
+ struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
+ wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
return 0;
}
#ifdef CONFIG_PM
-static int wm8993_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8993_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
int fll_fout = wm8993->fll_fout;
int fll_fref = wm8993->fll_fref;
int ret;
/* Stop the FLL in an orderly fashion */
- ret = wm8993_set_fll(codec->dai, 0, 0, 0, 0);
+ ret = _wm8993_set_fll(codec, 0, 0, 0, 0);
if (ret != 0) {
- dev_err(&pdev->dev, "Failed to stop FLL\n");
+ dev_err(codec->dev, "Failed to stop FLL\n");
return ret;
}
@@ -1498,10 +1552,8 @@ static int wm8993_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int wm8993_resume(struct platform_device *pdev)
+static int wm8993_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
int ret;
@@ -1515,7 +1567,7 @@ static int wm8993_resume(struct platform_device *pdev)
wm8993->fll_fref = 0;
wm8993->fll_fout = 0;
- ret = wm8993_set_fll(codec->dai, 0, wm8993->fll_src,
+ ret = _wm8993_set_fll(codec, 0, wm8993->fll_src,
fll_fref, fll_fout);
if (ret != 0)
dev_err(codec->dev, "Failed to restart FLL\n");
@@ -1528,162 +1580,42 @@ static int wm8993_resume(struct platform_device *pdev)
#define wm8993_resume NULL
#endif
-struct snd_soc_codec_device soc_codec_dev_wm8993 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm8993 = {
.probe = wm8993_probe,
.remove = wm8993_remove,
.suspend = wm8993_suspend,
.resume = wm8993_resume,
+ .set_bias_level = wm8993_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm8993_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8993_reg_defaults,
+ .volatile_register = wm8993_volatile,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8993);
-static int wm8993_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8993_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
struct wm8993_priv *wm8993;
- struct snd_soc_codec *codec;
- unsigned int val;
int ret;
- int i;
-
- if (wm8993_codec) {
- dev_err(&i2c->dev, "A WM8993 is already registered\n");
- return -EINVAL;
- }
wm8993 = kzalloc(sizeof(struct wm8993_priv), GFP_KERNEL);
if (wm8993 == NULL)
return -ENOMEM;
- codec = &wm8993->codec;
- if (i2c->dev.platform_data)
- memcpy(&wm8993->pdata, i2c->dev.platform_data,
- sizeof(wm8993->pdata));
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->name = "WM8993";
- codec->volatile_register = wm8993_volatile;
- codec->reg_cache = wm8993->reg_cache;
- codec->reg_cache_size = ARRAY_SIZE(wm8993->reg_cache);
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8993_set_bias_level;
- codec->dai = &wm8993_dai;
- codec->num_dai = 1;
- snd_soc_codec_set_drvdata(codec, wm8993);
-
- wm8993->hubs_data.hp_startup_mode = 1;
- wm8993->hubs_data.dcs_codes = -2;
-
- memcpy(wm8993->reg_cache, wm8993_reg_defaults,
- sizeof(wm8993->reg_cache));
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
- }
-
i2c_set_clientdata(i2c, wm8993);
- codec->control_data = i2c;
- wm8993_codec = codec;
-
- codec->dev = &i2c->dev;
-
- for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++)
- wm8993->supplies[i].supply = wm8993_supply_names[i];
-
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8993->supplies),
- wm8993->supplies);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err;
- }
-
- ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
- wm8993->supplies);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
- goto err_get;
- }
-
- val = snd_soc_read(codec, WM8993_SOFTWARE_RESET);
- if (val != wm8993_reg_defaults[WM8993_SOFTWARE_RESET]) {
- dev_err(codec->dev, "Invalid ID register value %x\n", val);
- ret = -EINVAL;
- goto err_enable;
- }
-
- ret = snd_soc_write(codec, WM8993_SOFTWARE_RESET, 0xffff);
- if (ret != 0)
- goto err_enable;
-
- codec->cache_only = 1;
-
- /* By default we're using the output mixers */
- wm8993->class_w_users = 2;
-
- /* Latch volume update bits and default ZC on */
- snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
- WM8993_DAC_VU, WM8993_DAC_VU);
- snd_soc_update_bits(codec, WM8993_RIGHT_ADC_DIGITAL_VOLUME,
- WM8993_ADC_VU, WM8993_ADC_VU);
- /* Manualy manage the HPOUT sequencing for independent stereo
- * control. */
- snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
- WM8993_HPOUT1_AUTO_PU, 0);
-
- /* Use automatic clock configuration */
- snd_soc_update_bits(codec, WM8993_CLOCKING_4, WM8993_SR_MODE, 0);
-
- wm_hubs_handle_analogue_pdata(codec, wm8993->pdata.lineout1_diff,
- wm8993->pdata.lineout2_diff,
- wm8993->pdata.lineout1fb,
- wm8993->pdata.lineout2fb,
- wm8993->pdata.jd_scthr,
- wm8993->pdata.jd_thr,
- wm8993->pdata.micbias1_lvl,
- wm8993->pdata.micbias2_lvl);
-
- ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- if (ret != 0)
- goto err_enable;
-
- wm8993_dai.dev = codec->dev;
-
- ret = snd_soc_register_dai(&wm8993_dai);
- if (ret != 0)
- goto err_bias;
-
- ret = snd_soc_register_codec(codec);
-
- return 0;
-
-err_bias:
- wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
-err_enable:
- regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
-err_get:
- regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
-err:
- wm8993_codec = NULL;
- kfree(wm8993);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8993, &wm8993_dai, 1);
+ if (ret < 0)
+ kfree(wm8993);
return ret;
}
-static int wm8993_i2c_remove(struct i2c_client *client)
+static __devexit int wm8993_i2c_remove(struct i2c_client *client)
{
- struct wm8993_priv *wm8993 = i2c_get_clientdata(client);
-
- snd_soc_unregister_codec(&wm8993->codec);
- snd_soc_unregister_dai(&wm8993_dai);
-
- wm8993_set_bias_level(&wm8993->codec, SND_SOC_BIAS_OFF);
- regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
- kfree(wm8993);
-
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1695,30 +1627,34 @@ MODULE_DEVICE_TABLE(i2c, wm8993_i2c_id);
static struct i2c_driver wm8993_i2c_driver = {
.driver = {
- .name = "WM8993",
+ .name = "wm8993-codec",
.owner = THIS_MODULE,
},
- .probe = wm8993_i2c_probe,
- .remove = wm8993_i2c_remove,
+ .probe = wm8993_i2c_probe,
+ .remove = __devexit_p(wm8993_i2c_remove),
.id_table = wm8993_i2c_id,
};
-
+#endif
static int __init wm8993_modinit(void)
{
- int ret;
-
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8993_i2c_driver);
- if (ret != 0)
- pr_err("WM8993: Unable to register I2C driver: %d\n", ret);
-
+ if (ret != 0) {
+ pr_err("WM8993: Unable to register I2C driver: %d\n",
+ ret);
+ }
+#endif
return ret;
}
module_init(wm8993_modinit);
static void __exit wm8993_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8993_i2c_driver);
+#endif
}
module_exit(wm8993_exit);
diff --git a/sound/soc/codecs/wm8993.h b/sound/soc/codecs/wm8993.h
index 30e71ca88dad..2184617b9611 100644
--- a/sound/soc/codecs/wm8993.h
+++ b/sound/soc/codecs/wm8993.h
@@ -1,9 +1,6 @@
#ifndef WM8993_H
#define WM8993_H
-extern struct snd_soc_dai wm8993_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8993;
-
#define WM8993_SYSCLK_MCLK 1
#define WM8993_SYSCLK_FLL 2
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 522249d5c2b4..0db59c3aa5d4 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -36,9 +36,6 @@
#include "wm8994.h"
#include "wm_hubs.h"
-static struct snd_soc_codec *wm8994_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8994;
-
struct fll_config {
int src;
int in;
@@ -71,7 +68,9 @@ struct wm8994_micdet {
/* codec private data */
struct wm8994_priv {
struct wm_hubs_data hubs;
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
+ struct snd_soc_codec *codec;
u16 reg_cache[WM8994_REG_CACHE_SIZE + 1];
int sysclk[2];
int sysclk_rate[2];
@@ -99,1581 +98,1580 @@ struct wm8994_priv {
struct wm8994_pdata *pdata;
};
-static struct {
- unsigned short readable; /* Mask of readable bits */
- unsigned short writable; /* Mask of writable bits */
- unsigned short vol; /* Mask of volatile bits */
+static const struct {
+ unsigned short readable; /* Mask of readable bits */
+ unsigned short writable; /* Mask of writable bits */
} access_masks[] = {
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R0 - Software Reset */
- { 0x3B37, 0x3B37, 0x0000 }, /* R1 - Power Management (1) */
- { 0x6BF0, 0x6BF0, 0x0000 }, /* R2 - Power Management (2) */
- { 0x3FF0, 0x3FF0, 0x0000 }, /* R3 - Power Management (3) */
- { 0x3F3F, 0x3F3F, 0x0000 }, /* R4 - Power Management (4) */
- { 0x3F0F, 0x3F0F, 0x0000 }, /* R5 - Power Management (5) */
- { 0x003F, 0x003F, 0x0000 }, /* R6 - Power Management (6) */
- { 0x0000, 0x0000, 0x0000 }, /* R7 */
- { 0x0000, 0x0000, 0x0000 }, /* R8 */
- { 0x0000, 0x0000, 0x0000 }, /* R9 */
- { 0x0000, 0x0000, 0x0000 }, /* R10 */
- { 0x0000, 0x0000, 0x0000 }, /* R11 */
- { 0x0000, 0x0000, 0x0000 }, /* R12 */
- { 0x0000, 0x0000, 0x0000 }, /* R13 */
- { 0x0000, 0x0000, 0x0000 }, /* R14 */
- { 0x0000, 0x0000, 0x0000 }, /* R15 */
- { 0x0000, 0x0000, 0x0000 }, /* R16 */
- { 0x0000, 0x0000, 0x0000 }, /* R17 */
- { 0x0000, 0x0000, 0x0000 }, /* R18 */
- { 0x0000, 0x0000, 0x0000 }, /* R19 */
- { 0x0000, 0x0000, 0x0000 }, /* R20 */
- { 0x01C0, 0x01C0, 0x0000 }, /* R21 - Input Mixer (1) */
- { 0x0000, 0x0000, 0x0000 }, /* R22 */
- { 0x0000, 0x0000, 0x0000 }, /* R23 */
- { 0x00DF, 0x01DF, 0x0000 }, /* R24 - Left Line Input 1&2 Volume */
- { 0x00DF, 0x01DF, 0x0000 }, /* R25 - Left Line Input 3&4 Volume */
- { 0x00DF, 0x01DF, 0x0000 }, /* R26 - Right Line Input 1&2 Volume */
- { 0x00DF, 0x01DF, 0x0000 }, /* R27 - Right Line Input 3&4 Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R28 - Left Output Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R29 - Right Output Volume */
- { 0x0077, 0x0077, 0x0000 }, /* R30 - Line Outputs Volume */
- { 0x0030, 0x0030, 0x0000 }, /* R31 - HPOUT2 Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R32 - Left OPGA Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R33 - Right OPGA Volume */
- { 0x007F, 0x007F, 0x0000 }, /* R34 - SPKMIXL Attenuation */
- { 0x017F, 0x017F, 0x0000 }, /* R35 - SPKMIXR Attenuation */
- { 0x003F, 0x003F, 0x0000 }, /* R36 - SPKOUT Mixers */
- { 0x003F, 0x003F, 0x0000 }, /* R37 - ClassD */
- { 0x00FF, 0x01FF, 0x0000 }, /* R38 - Speaker Volume Left */
- { 0x00FF, 0x01FF, 0x0000 }, /* R39 - Speaker Volume Right */
- { 0x00FF, 0x00FF, 0x0000 }, /* R40 - Input Mixer (2) */
- { 0x01B7, 0x01B7, 0x0000 }, /* R41 - Input Mixer (3) */
- { 0x01B7, 0x01B7, 0x0000 }, /* R42 - Input Mixer (4) */
- { 0x01C7, 0x01C7, 0x0000 }, /* R43 - Input Mixer (5) */
- { 0x01C7, 0x01C7, 0x0000 }, /* R44 - Input Mixer (6) */
- { 0x01FF, 0x01FF, 0x0000 }, /* R45 - Output Mixer (1) */
- { 0x01FF, 0x01FF, 0x0000 }, /* R46 - Output Mixer (2) */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R47 - Output Mixer (3) */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R48 - Output Mixer (4) */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R49 - Output Mixer (5) */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R50 - Output Mixer (6) */
- { 0x0038, 0x0038, 0x0000 }, /* R51 - HPOUT2 Mixer */
- { 0x0077, 0x0077, 0x0000 }, /* R52 - Line Mixer (1) */
- { 0x0077, 0x0077, 0x0000 }, /* R53 - Line Mixer (2) */
- { 0x03FF, 0x03FF, 0x0000 }, /* R54 - Speaker Mixer */
- { 0x00C1, 0x00C1, 0x0000 }, /* R55 - Additional Control */
- { 0x00F0, 0x00F0, 0x0000 }, /* R56 - AntiPOP (1) */
- { 0x01EF, 0x01EF, 0x0000 }, /* R57 - AntiPOP (2) */
- { 0x00FF, 0x00FF, 0x0000 }, /* R58 - MICBIAS */
- { 0x000F, 0x000F, 0x0000 }, /* R59 - LDO 1 */
- { 0x0007, 0x0007, 0x0000 }, /* R60 - LDO 2 */
- { 0x0000, 0x0000, 0x0000 }, /* R61 */
- { 0x0000, 0x0000, 0x0000 }, /* R62 */
- { 0x0000, 0x0000, 0x0000 }, /* R63 */
- { 0x0000, 0x0000, 0x0000 }, /* R64 */
- { 0x0000, 0x0000, 0x0000 }, /* R65 */
- { 0x0000, 0x0000, 0x0000 }, /* R66 */
- { 0x0000, 0x0000, 0x0000 }, /* R67 */
- { 0x0000, 0x0000, 0x0000 }, /* R68 */
- { 0x0000, 0x0000, 0x0000 }, /* R69 */
- { 0x0000, 0x0000, 0x0000 }, /* R70 */
- { 0x0000, 0x0000, 0x0000 }, /* R71 */
- { 0x0000, 0x0000, 0x0000 }, /* R72 */
- { 0x0000, 0x0000, 0x0000 }, /* R73 */
- { 0x0000, 0x0000, 0x0000 }, /* R74 */
- { 0x0000, 0x0000, 0x0000 }, /* R75 */
- { 0x8000, 0x8000, 0x0000 }, /* R76 - Charge Pump (1) */
- { 0x0000, 0x0000, 0x0000 }, /* R77 */
- { 0x0000, 0x0000, 0x0000 }, /* R78 */
- { 0x0000, 0x0000, 0x0000 }, /* R79 */
- { 0x0000, 0x0000, 0x0000 }, /* R80 */
- { 0x0301, 0x0301, 0x0000 }, /* R81 - Class W (1) */
- { 0x0000, 0x0000, 0x0000 }, /* R82 */
- { 0x0000, 0x0000, 0x0000 }, /* R83 */
- { 0x333F, 0x333F, 0x0000 }, /* R84 - DC Servo (1) */
- { 0x0FEF, 0x0FEF, 0x0000 }, /* R85 - DC Servo (2) */
- { 0x0000, 0x0000, 0x0000 }, /* R86 */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R87 - DC Servo (4) */
- { 0x0333, 0x0000, 0x0000 }, /* R88 - DC Servo Readback */
- { 0x0000, 0x0000, 0x0000 }, /* R89 */
- { 0x0000, 0x0000, 0x0000 }, /* R90 */
- { 0x0000, 0x0000, 0x0000 }, /* R91 */
- { 0x0000, 0x0000, 0x0000 }, /* R92 */
- { 0x0000, 0x0000, 0x0000 }, /* R93 */
- { 0x0000, 0x0000, 0x0000 }, /* R94 */
- { 0x0000, 0x0000, 0x0000 }, /* R95 */
- { 0x00EE, 0x00EE, 0x0000 }, /* R96 - Analogue HP (1) */
- { 0x0000, 0x0000, 0x0000 }, /* R97 */
- { 0x0000, 0x0000, 0x0000 }, /* R98 */
- { 0x0000, 0x0000, 0x0000 }, /* R99 */
- { 0x0000, 0x0000, 0x0000 }, /* R100 */
- { 0x0000, 0x0000, 0x0000 }, /* R101 */
- { 0x0000, 0x0000, 0x0000 }, /* R102 */
- { 0x0000, 0x0000, 0x0000 }, /* R103 */
- { 0x0000, 0x0000, 0x0000 }, /* R104 */
- { 0x0000, 0x0000, 0x0000 }, /* R105 */
- { 0x0000, 0x0000, 0x0000 }, /* R106 */
- { 0x0000, 0x0000, 0x0000 }, /* R107 */
- { 0x0000, 0x0000, 0x0000 }, /* R108 */
- { 0x0000, 0x0000, 0x0000 }, /* R109 */
- { 0x0000, 0x0000, 0x0000 }, /* R110 */
- { 0x0000, 0x0000, 0x0000 }, /* R111 */
- { 0x0000, 0x0000, 0x0000 }, /* R112 */
- { 0x0000, 0x0000, 0x0000 }, /* R113 */
- { 0x0000, 0x0000, 0x0000 }, /* R114 */
- { 0x0000, 0x0000, 0x0000 }, /* R115 */
- { 0x0000, 0x0000, 0x0000 }, /* R116 */
- { 0x0000, 0x0000, 0x0000 }, /* R117 */
- { 0x0000, 0x0000, 0x0000 }, /* R118 */
- { 0x0000, 0x0000, 0x0000 }, /* R119 */
- { 0x0000, 0x0000, 0x0000 }, /* R120 */
- { 0x0000, 0x0000, 0x0000 }, /* R121 */
- { 0x0000, 0x0000, 0x0000 }, /* R122 */
- { 0x0000, 0x0000, 0x0000 }, /* R123 */
- { 0x0000, 0x0000, 0x0000 }, /* R124 */
- { 0x0000, 0x0000, 0x0000 }, /* R125 */
- { 0x0000, 0x0000, 0x0000 }, /* R126 */
- { 0x0000, 0x0000, 0x0000 }, /* R127 */
- { 0x0000, 0x0000, 0x0000 }, /* R128 */
- { 0x0000, 0x0000, 0x0000 }, /* R129 */
- { 0x0000, 0x0000, 0x0000 }, /* R130 */
- { 0x0000, 0x0000, 0x0000 }, /* R131 */
- { 0x0000, 0x0000, 0x0000 }, /* R132 */
- { 0x0000, 0x0000, 0x0000 }, /* R133 */
- { 0x0000, 0x0000, 0x0000 }, /* R134 */
- { 0x0000, 0x0000, 0x0000 }, /* R135 */
- { 0x0000, 0x0000, 0x0000 }, /* R136 */
- { 0x0000, 0x0000, 0x0000 }, /* R137 */
- { 0x0000, 0x0000, 0x0000 }, /* R138 */
- { 0x0000, 0x0000, 0x0000 }, /* R139 */
- { 0x0000, 0x0000, 0x0000 }, /* R140 */
- { 0x0000, 0x0000, 0x0000 }, /* R141 */
- { 0x0000, 0x0000, 0x0000 }, /* R142 */
- { 0x0000, 0x0000, 0x0000 }, /* R143 */
- { 0x0000, 0x0000, 0x0000 }, /* R144 */
- { 0x0000, 0x0000, 0x0000 }, /* R145 */
- { 0x0000, 0x0000, 0x0000 }, /* R146 */
- { 0x0000, 0x0000, 0x0000 }, /* R147 */
- { 0x0000, 0x0000, 0x0000 }, /* R148 */
- { 0x0000, 0x0000, 0x0000 }, /* R149 */
- { 0x0000, 0x0000, 0x0000 }, /* R150 */
- { 0x0000, 0x0000, 0x0000 }, /* R151 */
- { 0x0000, 0x0000, 0x0000 }, /* R152 */
- { 0x0000, 0x0000, 0x0000 }, /* R153 */
- { 0x0000, 0x0000, 0x0000 }, /* R154 */
- { 0x0000, 0x0000, 0x0000 }, /* R155 */
- { 0x0000, 0x0000, 0x0000 }, /* R156 */
- { 0x0000, 0x0000, 0x0000 }, /* R157 */
- { 0x0000, 0x0000, 0x0000 }, /* R158 */
- { 0x0000, 0x0000, 0x0000 }, /* R159 */
- { 0x0000, 0x0000, 0x0000 }, /* R160 */
- { 0x0000, 0x0000, 0x0000 }, /* R161 */
- { 0x0000, 0x0000, 0x0000 }, /* R162 */
- { 0x0000, 0x0000, 0x0000 }, /* R163 */
- { 0x0000, 0x0000, 0x0000 }, /* R164 */
- { 0x0000, 0x0000, 0x0000 }, /* R165 */
- { 0x0000, 0x0000, 0x0000 }, /* R166 */
- { 0x0000, 0x0000, 0x0000 }, /* R167 */
- { 0x0000, 0x0000, 0x0000 }, /* R168 */
- { 0x0000, 0x0000, 0x0000 }, /* R169 */
- { 0x0000, 0x0000, 0x0000 }, /* R170 */
- { 0x0000, 0x0000, 0x0000 }, /* R171 */
- { 0x0000, 0x0000, 0x0000 }, /* R172 */
- { 0x0000, 0x0000, 0x0000 }, /* R173 */
- { 0x0000, 0x0000, 0x0000 }, /* R174 */
- { 0x0000, 0x0000, 0x0000 }, /* R175 */
- { 0x0000, 0x0000, 0x0000 }, /* R176 */
- { 0x0000, 0x0000, 0x0000 }, /* R177 */
- { 0x0000, 0x0000, 0x0000 }, /* R178 */
- { 0x0000, 0x0000, 0x0000 }, /* R179 */
- { 0x0000, 0x0000, 0x0000 }, /* R180 */
- { 0x0000, 0x0000, 0x0000 }, /* R181 */
- { 0x0000, 0x0000, 0x0000 }, /* R182 */
- { 0x0000, 0x0000, 0x0000 }, /* R183 */
- { 0x0000, 0x0000, 0x0000 }, /* R184 */
- { 0x0000, 0x0000, 0x0000 }, /* R185 */
- { 0x0000, 0x0000, 0x0000 }, /* R186 */
- { 0x0000, 0x0000, 0x0000 }, /* R187 */
- { 0x0000, 0x0000, 0x0000 }, /* R188 */
- { 0x0000, 0x0000, 0x0000 }, /* R189 */
- { 0x0000, 0x0000, 0x0000 }, /* R190 */
- { 0x0000, 0x0000, 0x0000 }, /* R191 */
- { 0x0000, 0x0000, 0x0000 }, /* R192 */
- { 0x0000, 0x0000, 0x0000 }, /* R193 */
- { 0x0000, 0x0000, 0x0000 }, /* R194 */
- { 0x0000, 0x0000, 0x0000 }, /* R195 */
- { 0x0000, 0x0000, 0x0000 }, /* R196 */
- { 0x0000, 0x0000, 0x0000 }, /* R197 */
- { 0x0000, 0x0000, 0x0000 }, /* R198 */
- { 0x0000, 0x0000, 0x0000 }, /* R199 */
- { 0x0000, 0x0000, 0x0000 }, /* R200 */
- { 0x0000, 0x0000, 0x0000 }, /* R201 */
- { 0x0000, 0x0000, 0x0000 }, /* R202 */
- { 0x0000, 0x0000, 0x0000 }, /* R203 */
- { 0x0000, 0x0000, 0x0000 }, /* R204 */
- { 0x0000, 0x0000, 0x0000 }, /* R205 */
- { 0x0000, 0x0000, 0x0000 }, /* R206 */
- { 0x0000, 0x0000, 0x0000 }, /* R207 */
- { 0x0000, 0x0000, 0x0000 }, /* R208 */
- { 0x0000, 0x0000, 0x0000 }, /* R209 */
- { 0x0000, 0x0000, 0x0000 }, /* R210 */
- { 0x0000, 0x0000, 0x0000 }, /* R211 */
- { 0x0000, 0x0000, 0x0000 }, /* R212 */
- { 0x0000, 0x0000, 0x0000 }, /* R213 */
- { 0x0000, 0x0000, 0x0000 }, /* R214 */
- { 0x0000, 0x0000, 0x0000 }, /* R215 */
- { 0x0000, 0x0000, 0x0000 }, /* R216 */
- { 0x0000, 0x0000, 0x0000 }, /* R217 */
- { 0x0000, 0x0000, 0x0000 }, /* R218 */
- { 0x0000, 0x0000, 0x0000 }, /* R219 */
- { 0x0000, 0x0000, 0x0000 }, /* R220 */
- { 0x0000, 0x0000, 0x0000 }, /* R221 */
- { 0x0000, 0x0000, 0x0000 }, /* R222 */
- { 0x0000, 0x0000, 0x0000 }, /* R223 */
- { 0x0000, 0x0000, 0x0000 }, /* R224 */
- { 0x0000, 0x0000, 0x0000 }, /* R225 */
- { 0x0000, 0x0000, 0x0000 }, /* R226 */
- { 0x0000, 0x0000, 0x0000 }, /* R227 */
- { 0x0000, 0x0000, 0x0000 }, /* R228 */
- { 0x0000, 0x0000, 0x0000 }, /* R229 */
- { 0x0000, 0x0000, 0x0000 }, /* R230 */
- { 0x0000, 0x0000, 0x0000 }, /* R231 */
- { 0x0000, 0x0000, 0x0000 }, /* R232 */
- { 0x0000, 0x0000, 0x0000 }, /* R233 */
- { 0x0000, 0x0000, 0x0000 }, /* R234 */
- { 0x0000, 0x0000, 0x0000 }, /* R235 */
- { 0x0000, 0x0000, 0x0000 }, /* R236 */
- { 0x0000, 0x0000, 0x0000 }, /* R237 */
- { 0x0000, 0x0000, 0x0000 }, /* R238 */
- { 0x0000, 0x0000, 0x0000 }, /* R239 */
- { 0x0000, 0x0000, 0x0000 }, /* R240 */
- { 0x0000, 0x0000, 0x0000 }, /* R241 */
- { 0x0000, 0x0000, 0x0000 }, /* R242 */
- { 0x0000, 0x0000, 0x0000 }, /* R243 */
- { 0x0000, 0x0000, 0x0000 }, /* R244 */
- { 0x0000, 0x0000, 0x0000 }, /* R245 */
- { 0x0000, 0x0000, 0x0000 }, /* R246 */
- { 0x0000, 0x0000, 0x0000 }, /* R247 */
- { 0x0000, 0x0000, 0x0000 }, /* R248 */
- { 0x0000, 0x0000, 0x0000 }, /* R249 */
- { 0x0000, 0x0000, 0x0000 }, /* R250 */
- { 0x0000, 0x0000, 0x0000 }, /* R251 */
- { 0x0000, 0x0000, 0x0000 }, /* R252 */
- { 0x0000, 0x0000, 0x0000 }, /* R253 */
- { 0x0000, 0x0000, 0x0000 }, /* R254 */
- { 0x0000, 0x0000, 0x0000 }, /* R255 */
- { 0x000F, 0x0000, 0x0000 }, /* R256 - Chip Revision */
- { 0x0074, 0x0074, 0x0000 }, /* R257 - Control Interface */
- { 0x0000, 0x0000, 0x0000 }, /* R258 */
- { 0x0000, 0x0000, 0x0000 }, /* R259 */
- { 0x0000, 0x0000, 0x0000 }, /* R260 */
- { 0x0000, 0x0000, 0x0000 }, /* R261 */
- { 0x0000, 0x0000, 0x0000 }, /* R262 */
- { 0x0000, 0x0000, 0x0000 }, /* R263 */
- { 0x0000, 0x0000, 0x0000 }, /* R264 */
- { 0x0000, 0x0000, 0x0000 }, /* R265 */
- { 0x0000, 0x0000, 0x0000 }, /* R266 */
- { 0x0000, 0x0000, 0x0000 }, /* R267 */
- { 0x0000, 0x0000, 0x0000 }, /* R268 */
- { 0x0000, 0x0000, 0x0000 }, /* R269 */
- { 0x0000, 0x0000, 0x0000 }, /* R270 */
- { 0x0000, 0x0000, 0x0000 }, /* R271 */
- { 0x807F, 0x837F, 0x0000 }, /* R272 - Write Sequencer Ctrl (1) */
- { 0x017F, 0x0000, 0x0000 }, /* R273 - Write Sequencer Ctrl (2) */
- { 0x0000, 0x0000, 0x0000 }, /* R274 */
- { 0x0000, 0x0000, 0x0000 }, /* R275 */
- { 0x0000, 0x0000, 0x0000 }, /* R276 */
- { 0x0000, 0x0000, 0x0000 }, /* R277 */
- { 0x0000, 0x0000, 0x0000 }, /* R278 */
- { 0x0000, 0x0000, 0x0000 }, /* R279 */
- { 0x0000, 0x0000, 0x0000 }, /* R280 */
- { 0x0000, 0x0000, 0x0000 }, /* R281 */
- { 0x0000, 0x0000, 0x0000 }, /* R282 */
- { 0x0000, 0x0000, 0x0000 }, /* R283 */
- { 0x0000, 0x0000, 0x0000 }, /* R284 */
- { 0x0000, 0x0000, 0x0000 }, /* R285 */
- { 0x0000, 0x0000, 0x0000 }, /* R286 */
- { 0x0000, 0x0000, 0x0000 }, /* R287 */
- { 0x0000, 0x0000, 0x0000 }, /* R288 */
- { 0x0000, 0x0000, 0x0000 }, /* R289 */
- { 0x0000, 0x0000, 0x0000 }, /* R290 */
- { 0x0000, 0x0000, 0x0000 }, /* R291 */
- { 0x0000, 0x0000, 0x0000 }, /* R292 */
- { 0x0000, 0x0000, 0x0000 }, /* R293 */
- { 0x0000, 0x0000, 0x0000 }, /* R294 */
- { 0x0000, 0x0000, 0x0000 }, /* R295 */
- { 0x0000, 0x0000, 0x0000 }, /* R296 */
- { 0x0000, 0x0000, 0x0000 }, /* R297 */
- { 0x0000, 0x0000, 0x0000 }, /* R298 */
- { 0x0000, 0x0000, 0x0000 }, /* R299 */
- { 0x0000, 0x0000, 0x0000 }, /* R300 */
- { 0x0000, 0x0000, 0x0000 }, /* R301 */
- { 0x0000, 0x0000, 0x0000 }, /* R302 */
- { 0x0000, 0x0000, 0x0000 }, /* R303 */
- { 0x0000, 0x0000, 0x0000 }, /* R304 */
- { 0x0000, 0x0000, 0x0000 }, /* R305 */
- { 0x0000, 0x0000, 0x0000 }, /* R306 */
- { 0x0000, 0x0000, 0x0000 }, /* R307 */
- { 0x0000, 0x0000, 0x0000 }, /* R308 */
- { 0x0000, 0x0000, 0x0000 }, /* R309 */
- { 0x0000, 0x0000, 0x0000 }, /* R310 */
- { 0x0000, 0x0000, 0x0000 }, /* R311 */
- { 0x0000, 0x0000, 0x0000 }, /* R312 */
- { 0x0000, 0x0000, 0x0000 }, /* R313 */
- { 0x0000, 0x0000, 0x0000 }, /* R314 */
- { 0x0000, 0x0000, 0x0000 }, /* R315 */
- { 0x0000, 0x0000, 0x0000 }, /* R316 */
- { 0x0000, 0x0000, 0x0000 }, /* R317 */
- { 0x0000, 0x0000, 0x0000 }, /* R318 */
- { 0x0000, 0x0000, 0x0000 }, /* R319 */
- { 0x0000, 0x0000, 0x0000 }, /* R320 */
- { 0x0000, 0x0000, 0x0000 }, /* R321 */
- { 0x0000, 0x0000, 0x0000 }, /* R322 */
- { 0x0000, 0x0000, 0x0000 }, /* R323 */
- { 0x0000, 0x0000, 0x0000 }, /* R324 */
- { 0x0000, 0x0000, 0x0000 }, /* R325 */
- { 0x0000, 0x0000, 0x0000 }, /* R326 */
- { 0x0000, 0x0000, 0x0000 }, /* R327 */
- { 0x0000, 0x0000, 0x0000 }, /* R328 */
- { 0x0000, 0x0000, 0x0000 }, /* R329 */
- { 0x0000, 0x0000, 0x0000 }, /* R330 */
- { 0x0000, 0x0000, 0x0000 }, /* R331 */
- { 0x0000, 0x0000, 0x0000 }, /* R332 */
- { 0x0000, 0x0000, 0x0000 }, /* R333 */
- { 0x0000, 0x0000, 0x0000 }, /* R334 */
- { 0x0000, 0x0000, 0x0000 }, /* R335 */
- { 0x0000, 0x0000, 0x0000 }, /* R336 */
- { 0x0000, 0x0000, 0x0000 }, /* R337 */
- { 0x0000, 0x0000, 0x0000 }, /* R338 */
- { 0x0000, 0x0000, 0x0000 }, /* R339 */
- { 0x0000, 0x0000, 0x0000 }, /* R340 */
- { 0x0000, 0x0000, 0x0000 }, /* R341 */
- { 0x0000, 0x0000, 0x0000 }, /* R342 */
- { 0x0000, 0x0000, 0x0000 }, /* R343 */
- { 0x0000, 0x0000, 0x0000 }, /* R344 */
- { 0x0000, 0x0000, 0x0000 }, /* R345 */
- { 0x0000, 0x0000, 0x0000 }, /* R346 */
- { 0x0000, 0x0000, 0x0000 }, /* R347 */
- { 0x0000, 0x0000, 0x0000 }, /* R348 */
- { 0x0000, 0x0000, 0x0000 }, /* R349 */
- { 0x0000, 0x0000, 0x0000 }, /* R350 */
- { 0x0000, 0x0000, 0x0000 }, /* R351 */
- { 0x0000, 0x0000, 0x0000 }, /* R352 */
- { 0x0000, 0x0000, 0x0000 }, /* R353 */
- { 0x0000, 0x0000, 0x0000 }, /* R354 */
- { 0x0000, 0x0000, 0x0000 }, /* R355 */
- { 0x0000, 0x0000, 0x0000 }, /* R356 */
- { 0x0000, 0x0000, 0x0000 }, /* R357 */
- { 0x0000, 0x0000, 0x0000 }, /* R358 */
- { 0x0000, 0x0000, 0x0000 }, /* R359 */
- { 0x0000, 0x0000, 0x0000 }, /* R360 */
- { 0x0000, 0x0000, 0x0000 }, /* R361 */
- { 0x0000, 0x0000, 0x0000 }, /* R362 */
- { 0x0000, 0x0000, 0x0000 }, /* R363 */
- { 0x0000, 0x0000, 0x0000 }, /* R364 */
- { 0x0000, 0x0000, 0x0000 }, /* R365 */
- { 0x0000, 0x0000, 0x0000 }, /* R366 */
- { 0x0000, 0x0000, 0x0000 }, /* R367 */
- { 0x0000, 0x0000, 0x0000 }, /* R368 */
- { 0x0000, 0x0000, 0x0000 }, /* R369 */
- { 0x0000, 0x0000, 0x0000 }, /* R370 */
- { 0x0000, 0x0000, 0x0000 }, /* R371 */
- { 0x0000, 0x0000, 0x0000 }, /* R372 */
- { 0x0000, 0x0000, 0x0000 }, /* R373 */
- { 0x0000, 0x0000, 0x0000 }, /* R374 */
- { 0x0000, 0x0000, 0x0000 }, /* R375 */
- { 0x0000, 0x0000, 0x0000 }, /* R376 */
- { 0x0000, 0x0000, 0x0000 }, /* R377 */
- { 0x0000, 0x0000, 0x0000 }, /* R378 */
- { 0x0000, 0x0000, 0x0000 }, /* R379 */
- { 0x0000, 0x0000, 0x0000 }, /* R380 */
- { 0x0000, 0x0000, 0x0000 }, /* R381 */
- { 0x0000, 0x0000, 0x0000 }, /* R382 */
- { 0x0000, 0x0000, 0x0000 }, /* R383 */
- { 0x0000, 0x0000, 0x0000 }, /* R384 */
- { 0x0000, 0x0000, 0x0000 }, /* R385 */
- { 0x0000, 0x0000, 0x0000 }, /* R386 */
- { 0x0000, 0x0000, 0x0000 }, /* R387 */
- { 0x0000, 0x0000, 0x0000 }, /* R388 */
- { 0x0000, 0x0000, 0x0000 }, /* R389 */
- { 0x0000, 0x0000, 0x0000 }, /* R390 */
- { 0x0000, 0x0000, 0x0000 }, /* R391 */
- { 0x0000, 0x0000, 0x0000 }, /* R392 */
- { 0x0000, 0x0000, 0x0000 }, /* R393 */
- { 0x0000, 0x0000, 0x0000 }, /* R394 */
- { 0x0000, 0x0000, 0x0000 }, /* R395 */
- { 0x0000, 0x0000, 0x0000 }, /* R396 */
- { 0x0000, 0x0000, 0x0000 }, /* R397 */
- { 0x0000, 0x0000, 0x0000 }, /* R398 */
- { 0x0000, 0x0000, 0x0000 }, /* R399 */
- { 0x0000, 0x0000, 0x0000 }, /* R400 */
- { 0x0000, 0x0000, 0x0000 }, /* R401 */
- { 0x0000, 0x0000, 0x0000 }, /* R402 */
- { 0x0000, 0x0000, 0x0000 }, /* R403 */
- { 0x0000, 0x0000, 0x0000 }, /* R404 */
- { 0x0000, 0x0000, 0x0000 }, /* R405 */
- { 0x0000, 0x0000, 0x0000 }, /* R406 */
- { 0x0000, 0x0000, 0x0000 }, /* R407 */
- { 0x0000, 0x0000, 0x0000 }, /* R408 */
- { 0x0000, 0x0000, 0x0000 }, /* R409 */
- { 0x0000, 0x0000, 0x0000 }, /* R410 */
- { 0x0000, 0x0000, 0x0000 }, /* R411 */
- { 0x0000, 0x0000, 0x0000 }, /* R412 */
- { 0x0000, 0x0000, 0x0000 }, /* R413 */
- { 0x0000, 0x0000, 0x0000 }, /* R414 */
- { 0x0000, 0x0000, 0x0000 }, /* R415 */
- { 0x0000, 0x0000, 0x0000 }, /* R416 */
- { 0x0000, 0x0000, 0x0000 }, /* R417 */
- { 0x0000, 0x0000, 0x0000 }, /* R418 */
- { 0x0000, 0x0000, 0x0000 }, /* R419 */
- { 0x0000, 0x0000, 0x0000 }, /* R420 */
- { 0x0000, 0x0000, 0x0000 }, /* R421 */
- { 0x0000, 0x0000, 0x0000 }, /* R422 */
- { 0x0000, 0x0000, 0x0000 }, /* R423 */
- { 0x0000, 0x0000, 0x0000 }, /* R424 */
- { 0x0000, 0x0000, 0x0000 }, /* R425 */
- { 0x0000, 0x0000, 0x0000 }, /* R426 */
- { 0x0000, 0x0000, 0x0000 }, /* R427 */
- { 0x0000, 0x0000, 0x0000 }, /* R428 */
- { 0x0000, 0x0000, 0x0000 }, /* R429 */
- { 0x0000, 0x0000, 0x0000 }, /* R430 */
- { 0x0000, 0x0000, 0x0000 }, /* R431 */
- { 0x0000, 0x0000, 0x0000 }, /* R432 */
- { 0x0000, 0x0000, 0x0000 }, /* R433 */
- { 0x0000, 0x0000, 0x0000 }, /* R434 */
- { 0x0000, 0x0000, 0x0000 }, /* R435 */
- { 0x0000, 0x0000, 0x0000 }, /* R436 */
- { 0x0000, 0x0000, 0x0000 }, /* R437 */
- { 0x0000, 0x0000, 0x0000 }, /* R438 */
- { 0x0000, 0x0000, 0x0000 }, /* R439 */
- { 0x0000, 0x0000, 0x0000 }, /* R440 */
- { 0x0000, 0x0000, 0x0000 }, /* R441 */
- { 0x0000, 0x0000, 0x0000 }, /* R442 */
- { 0x0000, 0x0000, 0x0000 }, /* R443 */
- { 0x0000, 0x0000, 0x0000 }, /* R444 */
- { 0x0000, 0x0000, 0x0000 }, /* R445 */
- { 0x0000, 0x0000, 0x0000 }, /* R446 */
- { 0x0000, 0x0000, 0x0000 }, /* R447 */
- { 0x0000, 0x0000, 0x0000 }, /* R448 */
- { 0x0000, 0x0000, 0x0000 }, /* R449 */
- { 0x0000, 0x0000, 0x0000 }, /* R450 */
- { 0x0000, 0x0000, 0x0000 }, /* R451 */
- { 0x0000, 0x0000, 0x0000 }, /* R452 */
- { 0x0000, 0x0000, 0x0000 }, /* R453 */
- { 0x0000, 0x0000, 0x0000 }, /* R454 */
- { 0x0000, 0x0000, 0x0000 }, /* R455 */
- { 0x0000, 0x0000, 0x0000 }, /* R456 */
- { 0x0000, 0x0000, 0x0000 }, /* R457 */
- { 0x0000, 0x0000, 0x0000 }, /* R458 */
- { 0x0000, 0x0000, 0x0000 }, /* R459 */
- { 0x0000, 0x0000, 0x0000 }, /* R460 */
- { 0x0000, 0x0000, 0x0000 }, /* R461 */
- { 0x0000, 0x0000, 0x0000 }, /* R462 */
- { 0x0000, 0x0000, 0x0000 }, /* R463 */
- { 0x0000, 0x0000, 0x0000 }, /* R464 */
- { 0x0000, 0x0000, 0x0000 }, /* R465 */
- { 0x0000, 0x0000, 0x0000 }, /* R466 */
- { 0x0000, 0x0000, 0x0000 }, /* R467 */
- { 0x0000, 0x0000, 0x0000 }, /* R468 */
- { 0x0000, 0x0000, 0x0000 }, /* R469 */
- { 0x0000, 0x0000, 0x0000 }, /* R470 */
- { 0x0000, 0x0000, 0x0000 }, /* R471 */
- { 0x0000, 0x0000, 0x0000 }, /* R472 */
- { 0x0000, 0x0000, 0x0000 }, /* R473 */
- { 0x0000, 0x0000, 0x0000 }, /* R474 */
- { 0x0000, 0x0000, 0x0000 }, /* R475 */
- { 0x0000, 0x0000, 0x0000 }, /* R476 */
- { 0x0000, 0x0000, 0x0000 }, /* R477 */
- { 0x0000, 0x0000, 0x0000 }, /* R478 */
- { 0x0000, 0x0000, 0x0000 }, /* R479 */
- { 0x0000, 0x0000, 0x0000 }, /* R480 */
- { 0x0000, 0x0000, 0x0000 }, /* R481 */
- { 0x0000, 0x0000, 0x0000 }, /* R482 */
- { 0x0000, 0x0000, 0x0000 }, /* R483 */
- { 0x0000, 0x0000, 0x0000 }, /* R484 */
- { 0x0000, 0x0000, 0x0000 }, /* R485 */
- { 0x0000, 0x0000, 0x0000 }, /* R486 */
- { 0x0000, 0x0000, 0x0000 }, /* R487 */
- { 0x0000, 0x0000, 0x0000 }, /* R488 */
- { 0x0000, 0x0000, 0x0000 }, /* R489 */
- { 0x0000, 0x0000, 0x0000 }, /* R490 */
- { 0x0000, 0x0000, 0x0000 }, /* R491 */
- { 0x0000, 0x0000, 0x0000 }, /* R492 */
- { 0x0000, 0x0000, 0x0000 }, /* R493 */
- { 0x0000, 0x0000, 0x0000 }, /* R494 */
- { 0x0000, 0x0000, 0x0000 }, /* R495 */
- { 0x0000, 0x0000, 0x0000 }, /* R496 */
- { 0x0000, 0x0000, 0x0000 }, /* R497 */
- { 0x0000, 0x0000, 0x0000 }, /* R498 */
- { 0x0000, 0x0000, 0x0000 }, /* R499 */
- { 0x0000, 0x0000, 0x0000 }, /* R500 */
- { 0x0000, 0x0000, 0x0000 }, /* R501 */
- { 0x0000, 0x0000, 0x0000 }, /* R502 */
- { 0x0000, 0x0000, 0x0000 }, /* R503 */
- { 0x0000, 0x0000, 0x0000 }, /* R504 */
- { 0x0000, 0x0000, 0x0000 }, /* R505 */
- { 0x0000, 0x0000, 0x0000 }, /* R506 */
- { 0x0000, 0x0000, 0x0000 }, /* R507 */
- { 0x0000, 0x0000, 0x0000 }, /* R508 */
- { 0x0000, 0x0000, 0x0000 }, /* R509 */
- { 0x0000, 0x0000, 0x0000 }, /* R510 */
- { 0x0000, 0x0000, 0x0000 }, /* R511 */
- { 0x001F, 0x001F, 0x0000 }, /* R512 - AIF1 Clocking (1) */
- { 0x003F, 0x003F, 0x0000 }, /* R513 - AIF1 Clocking (2) */
- { 0x0000, 0x0000, 0x0000 }, /* R514 */
- { 0x0000, 0x0000, 0x0000 }, /* R515 */
- { 0x001F, 0x001F, 0x0000 }, /* R516 - AIF2 Clocking (1) */
- { 0x003F, 0x003F, 0x0000 }, /* R517 - AIF2 Clocking (2) */
- { 0x0000, 0x0000, 0x0000 }, /* R518 */
- { 0x0000, 0x0000, 0x0000 }, /* R519 */
- { 0x001F, 0x001F, 0x0000 }, /* R520 - Clocking (1) */
- { 0x0777, 0x0777, 0x0000 }, /* R521 - Clocking (2) */
- { 0x0000, 0x0000, 0x0000 }, /* R522 */
- { 0x0000, 0x0000, 0x0000 }, /* R523 */
- { 0x0000, 0x0000, 0x0000 }, /* R524 */
- { 0x0000, 0x0000, 0x0000 }, /* R525 */
- { 0x0000, 0x0000, 0x0000 }, /* R526 */
- { 0x0000, 0x0000, 0x0000 }, /* R527 */
- { 0x00FF, 0x00FF, 0x0000 }, /* R528 - AIF1 Rate */
- { 0x00FF, 0x00FF, 0x0000 }, /* R529 - AIF2 Rate */
- { 0x000F, 0x0000, 0x0000 }, /* R530 - Rate Status */
- { 0x0000, 0x0000, 0x0000 }, /* R531 */
- { 0x0000, 0x0000, 0x0000 }, /* R532 */
- { 0x0000, 0x0000, 0x0000 }, /* R533 */
- { 0x0000, 0x0000, 0x0000 }, /* R534 */
- { 0x0000, 0x0000, 0x0000 }, /* R535 */
- { 0x0000, 0x0000, 0x0000 }, /* R536 */
- { 0x0000, 0x0000, 0x0000 }, /* R537 */
- { 0x0000, 0x0000, 0x0000 }, /* R538 */
- { 0x0000, 0x0000, 0x0000 }, /* R539 */
- { 0x0000, 0x0000, 0x0000 }, /* R540 */
- { 0x0000, 0x0000, 0x0000 }, /* R541 */
- { 0x0000, 0x0000, 0x0000 }, /* R542 */
- { 0x0000, 0x0000, 0x0000 }, /* R543 */
- { 0x0007, 0x0007, 0x0000 }, /* R544 - FLL1 Control (1) */
- { 0x3F77, 0x3F77, 0x0000 }, /* R545 - FLL1 Control (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R546 - FLL1 Control (3) */
- { 0x7FEF, 0x7FEF, 0x0000 }, /* R547 - FLL1 Control (4) */
- { 0x1FDB, 0x1FDB, 0x0000 }, /* R548 - FLL1 Control (5) */
- { 0x0000, 0x0000, 0x0000 }, /* R549 */
- { 0x0000, 0x0000, 0x0000 }, /* R550 */
- { 0x0000, 0x0000, 0x0000 }, /* R551 */
- { 0x0000, 0x0000, 0x0000 }, /* R552 */
- { 0x0000, 0x0000, 0x0000 }, /* R553 */
- { 0x0000, 0x0000, 0x0000 }, /* R554 */
- { 0x0000, 0x0000, 0x0000 }, /* R555 */
- { 0x0000, 0x0000, 0x0000 }, /* R556 */
- { 0x0000, 0x0000, 0x0000 }, /* R557 */
- { 0x0000, 0x0000, 0x0000 }, /* R558 */
- { 0x0000, 0x0000, 0x0000 }, /* R559 */
- { 0x0000, 0x0000, 0x0000 }, /* R560 */
- { 0x0000, 0x0000, 0x0000 }, /* R561 */
- { 0x0000, 0x0000, 0x0000 }, /* R562 */
- { 0x0000, 0x0000, 0x0000 }, /* R563 */
- { 0x0000, 0x0000, 0x0000 }, /* R564 */
- { 0x0000, 0x0000, 0x0000 }, /* R565 */
- { 0x0000, 0x0000, 0x0000 }, /* R566 */
- { 0x0000, 0x0000, 0x0000 }, /* R567 */
- { 0x0000, 0x0000, 0x0000 }, /* R568 */
- { 0x0000, 0x0000, 0x0000 }, /* R569 */
- { 0x0000, 0x0000, 0x0000 }, /* R570 */
- { 0x0000, 0x0000, 0x0000 }, /* R571 */
- { 0x0000, 0x0000, 0x0000 }, /* R572 */
- { 0x0000, 0x0000, 0x0000 }, /* R573 */
- { 0x0000, 0x0000, 0x0000 }, /* R574 */
- { 0x0000, 0x0000, 0x0000 }, /* R575 */
- { 0x0007, 0x0007, 0x0000 }, /* R576 - FLL2 Control (1) */
- { 0x3F77, 0x3F77, 0x0000 }, /* R577 - FLL2 Control (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R578 - FLL2 Control (3) */
- { 0x7FEF, 0x7FEF, 0x0000 }, /* R579 - FLL2 Control (4) */
- { 0x1FDB, 0x1FDB, 0x0000 }, /* R580 - FLL2 Control (5) */
- { 0x0000, 0x0000, 0x0000 }, /* R581 */
- { 0x0000, 0x0000, 0x0000 }, /* R582 */
- { 0x0000, 0x0000, 0x0000 }, /* R583 */
- { 0x0000, 0x0000, 0x0000 }, /* R584 */
- { 0x0000, 0x0000, 0x0000 }, /* R585 */
- { 0x0000, 0x0000, 0x0000 }, /* R586 */
- { 0x0000, 0x0000, 0x0000 }, /* R587 */
- { 0x0000, 0x0000, 0x0000 }, /* R588 */
- { 0x0000, 0x0000, 0x0000 }, /* R589 */
- { 0x0000, 0x0000, 0x0000 }, /* R590 */
- { 0x0000, 0x0000, 0x0000 }, /* R591 */
- { 0x0000, 0x0000, 0x0000 }, /* R592 */
- { 0x0000, 0x0000, 0x0000 }, /* R593 */
- { 0x0000, 0x0000, 0x0000 }, /* R594 */
- { 0x0000, 0x0000, 0x0000 }, /* R595 */
- { 0x0000, 0x0000, 0x0000 }, /* R596 */
- { 0x0000, 0x0000, 0x0000 }, /* R597 */
- { 0x0000, 0x0000, 0x0000 }, /* R598 */
- { 0x0000, 0x0000, 0x0000 }, /* R599 */
- { 0x0000, 0x0000, 0x0000 }, /* R600 */
- { 0x0000, 0x0000, 0x0000 }, /* R601 */
- { 0x0000, 0x0000, 0x0000 }, /* R602 */
- { 0x0000, 0x0000, 0x0000 }, /* R603 */
- { 0x0000, 0x0000, 0x0000 }, /* R604 */
- { 0x0000, 0x0000, 0x0000 }, /* R605 */
- { 0x0000, 0x0000, 0x0000 }, /* R606 */
- { 0x0000, 0x0000, 0x0000 }, /* R607 */
- { 0x0000, 0x0000, 0x0000 }, /* R608 */
- { 0x0000, 0x0000, 0x0000 }, /* R609 */
- { 0x0000, 0x0000, 0x0000 }, /* R610 */
- { 0x0000, 0x0000, 0x0000 }, /* R611 */
- { 0x0000, 0x0000, 0x0000 }, /* R612 */
- { 0x0000, 0x0000, 0x0000 }, /* R613 */
- { 0x0000, 0x0000, 0x0000 }, /* R614 */
- { 0x0000, 0x0000, 0x0000 }, /* R615 */
- { 0x0000, 0x0000, 0x0000 }, /* R616 */
- { 0x0000, 0x0000, 0x0000 }, /* R617 */
- { 0x0000, 0x0000, 0x0000 }, /* R618 */
- { 0x0000, 0x0000, 0x0000 }, /* R619 */
- { 0x0000, 0x0000, 0x0000 }, /* R620 */
- { 0x0000, 0x0000, 0x0000 }, /* R621 */
- { 0x0000, 0x0000, 0x0000 }, /* R622 */
- { 0x0000, 0x0000, 0x0000 }, /* R623 */
- { 0x0000, 0x0000, 0x0000 }, /* R624 */
- { 0x0000, 0x0000, 0x0000 }, /* R625 */
- { 0x0000, 0x0000, 0x0000 }, /* R626 */
- { 0x0000, 0x0000, 0x0000 }, /* R627 */
- { 0x0000, 0x0000, 0x0000 }, /* R628 */
- { 0x0000, 0x0000, 0x0000 }, /* R629 */
- { 0x0000, 0x0000, 0x0000 }, /* R630 */
- { 0x0000, 0x0000, 0x0000 }, /* R631 */
- { 0x0000, 0x0000, 0x0000 }, /* R632 */
- { 0x0000, 0x0000, 0x0000 }, /* R633 */
- { 0x0000, 0x0000, 0x0000 }, /* R634 */
- { 0x0000, 0x0000, 0x0000 }, /* R635 */
- { 0x0000, 0x0000, 0x0000 }, /* R636 */
- { 0x0000, 0x0000, 0x0000 }, /* R637 */
- { 0x0000, 0x0000, 0x0000 }, /* R638 */
- { 0x0000, 0x0000, 0x0000 }, /* R639 */
- { 0x0000, 0x0000, 0x0000 }, /* R640 */
- { 0x0000, 0x0000, 0x0000 }, /* R641 */
- { 0x0000, 0x0000, 0x0000 }, /* R642 */
- { 0x0000, 0x0000, 0x0000 }, /* R643 */
- { 0x0000, 0x0000, 0x0000 }, /* R644 */
- { 0x0000, 0x0000, 0x0000 }, /* R645 */
- { 0x0000, 0x0000, 0x0000 }, /* R646 */
- { 0x0000, 0x0000, 0x0000 }, /* R647 */
- { 0x0000, 0x0000, 0x0000 }, /* R648 */
- { 0x0000, 0x0000, 0x0000 }, /* R649 */
- { 0x0000, 0x0000, 0x0000 }, /* R650 */
- { 0x0000, 0x0000, 0x0000 }, /* R651 */
- { 0x0000, 0x0000, 0x0000 }, /* R652 */
- { 0x0000, 0x0000, 0x0000 }, /* R653 */
- { 0x0000, 0x0000, 0x0000 }, /* R654 */
- { 0x0000, 0x0000, 0x0000 }, /* R655 */
- { 0x0000, 0x0000, 0x0000 }, /* R656 */
- { 0x0000, 0x0000, 0x0000 }, /* R657 */
- { 0x0000, 0x0000, 0x0000 }, /* R658 */
- { 0x0000, 0x0000, 0x0000 }, /* R659 */
- { 0x0000, 0x0000, 0x0000 }, /* R660 */
- { 0x0000, 0x0000, 0x0000 }, /* R661 */
- { 0x0000, 0x0000, 0x0000 }, /* R662 */
- { 0x0000, 0x0000, 0x0000 }, /* R663 */
- { 0x0000, 0x0000, 0x0000 }, /* R664 */
- { 0x0000, 0x0000, 0x0000 }, /* R665 */
- { 0x0000, 0x0000, 0x0000 }, /* R666 */
- { 0x0000, 0x0000, 0x0000 }, /* R667 */
- { 0x0000, 0x0000, 0x0000 }, /* R668 */
- { 0x0000, 0x0000, 0x0000 }, /* R669 */
- { 0x0000, 0x0000, 0x0000 }, /* R670 */
- { 0x0000, 0x0000, 0x0000 }, /* R671 */
- { 0x0000, 0x0000, 0x0000 }, /* R672 */
- { 0x0000, 0x0000, 0x0000 }, /* R673 */
- { 0x0000, 0x0000, 0x0000 }, /* R674 */
- { 0x0000, 0x0000, 0x0000 }, /* R675 */
- { 0x0000, 0x0000, 0x0000 }, /* R676 */
- { 0x0000, 0x0000, 0x0000 }, /* R677 */
- { 0x0000, 0x0000, 0x0000 }, /* R678 */
- { 0x0000, 0x0000, 0x0000 }, /* R679 */
- { 0x0000, 0x0000, 0x0000 }, /* R680 */
- { 0x0000, 0x0000, 0x0000 }, /* R681 */
- { 0x0000, 0x0000, 0x0000 }, /* R682 */
- { 0x0000, 0x0000, 0x0000 }, /* R683 */
- { 0x0000, 0x0000, 0x0000 }, /* R684 */
- { 0x0000, 0x0000, 0x0000 }, /* R685 */
- { 0x0000, 0x0000, 0x0000 }, /* R686 */
- { 0x0000, 0x0000, 0x0000 }, /* R687 */
- { 0x0000, 0x0000, 0x0000 }, /* R688 */
- { 0x0000, 0x0000, 0x0000 }, /* R689 */
- { 0x0000, 0x0000, 0x0000 }, /* R690 */
- { 0x0000, 0x0000, 0x0000 }, /* R691 */
- { 0x0000, 0x0000, 0x0000 }, /* R692 */
- { 0x0000, 0x0000, 0x0000 }, /* R693 */
- { 0x0000, 0x0000, 0x0000 }, /* R694 */
- { 0x0000, 0x0000, 0x0000 }, /* R695 */
- { 0x0000, 0x0000, 0x0000 }, /* R696 */
- { 0x0000, 0x0000, 0x0000 }, /* R697 */
- { 0x0000, 0x0000, 0x0000 }, /* R698 */
- { 0x0000, 0x0000, 0x0000 }, /* R699 */
- { 0x0000, 0x0000, 0x0000 }, /* R700 */
- { 0x0000, 0x0000, 0x0000 }, /* R701 */
- { 0x0000, 0x0000, 0x0000 }, /* R702 */
- { 0x0000, 0x0000, 0x0000 }, /* R703 */
- { 0x0000, 0x0000, 0x0000 }, /* R704 */
- { 0x0000, 0x0000, 0x0000 }, /* R705 */
- { 0x0000, 0x0000, 0x0000 }, /* R706 */
- { 0x0000, 0x0000, 0x0000 }, /* R707 */
- { 0x0000, 0x0000, 0x0000 }, /* R708 */
- { 0x0000, 0x0000, 0x0000 }, /* R709 */
- { 0x0000, 0x0000, 0x0000 }, /* R710 */
- { 0x0000, 0x0000, 0x0000 }, /* R711 */
- { 0x0000, 0x0000, 0x0000 }, /* R712 */
- { 0x0000, 0x0000, 0x0000 }, /* R713 */
- { 0x0000, 0x0000, 0x0000 }, /* R714 */
- { 0x0000, 0x0000, 0x0000 }, /* R715 */
- { 0x0000, 0x0000, 0x0000 }, /* R716 */
- { 0x0000, 0x0000, 0x0000 }, /* R717 */
- { 0x0000, 0x0000, 0x0000 }, /* R718 */
- { 0x0000, 0x0000, 0x0000 }, /* R719 */
- { 0x0000, 0x0000, 0x0000 }, /* R720 */
- { 0x0000, 0x0000, 0x0000 }, /* R721 */
- { 0x0000, 0x0000, 0x0000 }, /* R722 */
- { 0x0000, 0x0000, 0x0000 }, /* R723 */
- { 0x0000, 0x0000, 0x0000 }, /* R724 */
- { 0x0000, 0x0000, 0x0000 }, /* R725 */
- { 0x0000, 0x0000, 0x0000 }, /* R726 */
- { 0x0000, 0x0000, 0x0000 }, /* R727 */
- { 0x0000, 0x0000, 0x0000 }, /* R728 */
- { 0x0000, 0x0000, 0x0000 }, /* R729 */
- { 0x0000, 0x0000, 0x0000 }, /* R730 */
- { 0x0000, 0x0000, 0x0000 }, /* R731 */
- { 0x0000, 0x0000, 0x0000 }, /* R732 */
- { 0x0000, 0x0000, 0x0000 }, /* R733 */
- { 0x0000, 0x0000, 0x0000 }, /* R734 */
- { 0x0000, 0x0000, 0x0000 }, /* R735 */
- { 0x0000, 0x0000, 0x0000 }, /* R736 */
- { 0x0000, 0x0000, 0x0000 }, /* R737 */
- { 0x0000, 0x0000, 0x0000 }, /* R738 */
- { 0x0000, 0x0000, 0x0000 }, /* R739 */
- { 0x0000, 0x0000, 0x0000 }, /* R740 */
- { 0x0000, 0x0000, 0x0000 }, /* R741 */
- { 0x0000, 0x0000, 0x0000 }, /* R742 */
- { 0x0000, 0x0000, 0x0000 }, /* R743 */
- { 0x0000, 0x0000, 0x0000 }, /* R744 */
- { 0x0000, 0x0000, 0x0000 }, /* R745 */
- { 0x0000, 0x0000, 0x0000 }, /* R746 */
- { 0x0000, 0x0000, 0x0000 }, /* R747 */
- { 0x0000, 0x0000, 0x0000 }, /* R748 */
- { 0x0000, 0x0000, 0x0000 }, /* R749 */
- { 0x0000, 0x0000, 0x0000 }, /* R750 */
- { 0x0000, 0x0000, 0x0000 }, /* R751 */
- { 0x0000, 0x0000, 0x0000 }, /* R752 */
- { 0x0000, 0x0000, 0x0000 }, /* R753 */
- { 0x0000, 0x0000, 0x0000 }, /* R754 */
- { 0x0000, 0x0000, 0x0000 }, /* R755 */
- { 0x0000, 0x0000, 0x0000 }, /* R756 */
- { 0x0000, 0x0000, 0x0000 }, /* R757 */
- { 0x0000, 0x0000, 0x0000 }, /* R758 */
- { 0x0000, 0x0000, 0x0000 }, /* R759 */
- { 0x0000, 0x0000, 0x0000 }, /* R760 */
- { 0x0000, 0x0000, 0x0000 }, /* R761 */
- { 0x0000, 0x0000, 0x0000 }, /* R762 */
- { 0x0000, 0x0000, 0x0000 }, /* R763 */
- { 0x0000, 0x0000, 0x0000 }, /* R764 */
- { 0x0000, 0x0000, 0x0000 }, /* R765 */
- { 0x0000, 0x0000, 0x0000 }, /* R766 */
- { 0x0000, 0x0000, 0x0000 }, /* R767 */
- { 0xE1F8, 0xE1F8, 0x0000 }, /* R768 - AIF1 Control (1) */
- { 0xCD1F, 0xCD1F, 0x0000 }, /* R769 - AIF1 Control (2) */
- { 0xF000, 0xF000, 0x0000 }, /* R770 - AIF1 Master/Slave */
- { 0x01F0, 0x01F0, 0x0000 }, /* R771 - AIF1 BCLK */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R772 - AIF1ADC LRCLK */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R773 - AIF1DAC LRCLK */
- { 0x0003, 0x0003, 0x0000 }, /* R774 - AIF1DAC Data */
- { 0x0003, 0x0003, 0x0000 }, /* R775 - AIF1ADC Data */
- { 0x0000, 0x0000, 0x0000 }, /* R776 */
- { 0x0000, 0x0000, 0x0000 }, /* R777 */
- { 0x0000, 0x0000, 0x0000 }, /* R778 */
- { 0x0000, 0x0000, 0x0000 }, /* R779 */
- { 0x0000, 0x0000, 0x0000 }, /* R780 */
- { 0x0000, 0x0000, 0x0000 }, /* R781 */
- { 0x0000, 0x0000, 0x0000 }, /* R782 */
- { 0x0000, 0x0000, 0x0000 }, /* R783 */
- { 0xF1F8, 0xF1F8, 0x0000 }, /* R784 - AIF2 Control (1) */
- { 0xFD1F, 0xFD1F, 0x0000 }, /* R785 - AIF2 Control (2) */
- { 0xF000, 0xF000, 0x0000 }, /* R786 - AIF2 Master/Slave */
- { 0x01F0, 0x01F0, 0x0000 }, /* R787 - AIF2 BCLK */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R788 - AIF2ADC LRCLK */
- { 0x0FFF, 0x0FFF, 0x0000 }, /* R789 - AIF2DAC LRCLK */
- { 0x0003, 0x0003, 0x0000 }, /* R790 - AIF2DAC Data */
- { 0x0003, 0x0003, 0x0000 }, /* R791 - AIF2ADC Data */
- { 0x0000, 0x0000, 0x0000 }, /* R792 */
- { 0x0000, 0x0000, 0x0000 }, /* R793 */
- { 0x0000, 0x0000, 0x0000 }, /* R794 */
- { 0x0000, 0x0000, 0x0000 }, /* R795 */
- { 0x0000, 0x0000, 0x0000 }, /* R796 */
- { 0x0000, 0x0000, 0x0000 }, /* R797 */
- { 0x0000, 0x0000, 0x0000 }, /* R798 */
- { 0x0000, 0x0000, 0x0000 }, /* R799 */
- { 0x0000, 0x0000, 0x0000 }, /* R800 */
- { 0x0000, 0x0000, 0x0000 }, /* R801 */
- { 0x0000, 0x0000, 0x0000 }, /* R802 */
- { 0x0000, 0x0000, 0x0000 }, /* R803 */
- { 0x0000, 0x0000, 0x0000 }, /* R804 */
- { 0x0000, 0x0000, 0x0000 }, /* R805 */
- { 0x0000, 0x0000, 0x0000 }, /* R806 */
- { 0x0000, 0x0000, 0x0000 }, /* R807 */
- { 0x0000, 0x0000, 0x0000 }, /* R808 */
- { 0x0000, 0x0000, 0x0000 }, /* R809 */
- { 0x0000, 0x0000, 0x0000 }, /* R810 */
- { 0x0000, 0x0000, 0x0000 }, /* R811 */
- { 0x0000, 0x0000, 0x0000 }, /* R812 */
- { 0x0000, 0x0000, 0x0000 }, /* R813 */
- { 0x0000, 0x0000, 0x0000 }, /* R814 */
- { 0x0000, 0x0000, 0x0000 }, /* R815 */
- { 0x0000, 0x0000, 0x0000 }, /* R816 */
- { 0x0000, 0x0000, 0x0000 }, /* R817 */
- { 0x0000, 0x0000, 0x0000 }, /* R818 */
- { 0x0000, 0x0000, 0x0000 }, /* R819 */
- { 0x0000, 0x0000, 0x0000 }, /* R820 */
- { 0x0000, 0x0000, 0x0000 }, /* R821 */
- { 0x0000, 0x0000, 0x0000 }, /* R822 */
- { 0x0000, 0x0000, 0x0000 }, /* R823 */
- { 0x0000, 0x0000, 0x0000 }, /* R824 */
- { 0x0000, 0x0000, 0x0000 }, /* R825 */
- { 0x0000, 0x0000, 0x0000 }, /* R826 */
- { 0x0000, 0x0000, 0x0000 }, /* R827 */
- { 0x0000, 0x0000, 0x0000 }, /* R828 */
- { 0x0000, 0x0000, 0x0000 }, /* R829 */
- { 0x0000, 0x0000, 0x0000 }, /* R830 */
- { 0x0000, 0x0000, 0x0000 }, /* R831 */
- { 0x0000, 0x0000, 0x0000 }, /* R832 */
- { 0x0000, 0x0000, 0x0000 }, /* R833 */
- { 0x0000, 0x0000, 0x0000 }, /* R834 */
- { 0x0000, 0x0000, 0x0000 }, /* R835 */
- { 0x0000, 0x0000, 0x0000 }, /* R836 */
- { 0x0000, 0x0000, 0x0000 }, /* R837 */
- { 0x0000, 0x0000, 0x0000 }, /* R838 */
- { 0x0000, 0x0000, 0x0000 }, /* R839 */
- { 0x0000, 0x0000, 0x0000 }, /* R840 */
- { 0x0000, 0x0000, 0x0000 }, /* R841 */
- { 0x0000, 0x0000, 0x0000 }, /* R842 */
- { 0x0000, 0x0000, 0x0000 }, /* R843 */
- { 0x0000, 0x0000, 0x0000 }, /* R844 */
- { 0x0000, 0x0000, 0x0000 }, /* R845 */
- { 0x0000, 0x0000, 0x0000 }, /* R846 */
- { 0x0000, 0x0000, 0x0000 }, /* R847 */
- { 0x0000, 0x0000, 0x0000 }, /* R848 */
- { 0x0000, 0x0000, 0x0000 }, /* R849 */
- { 0x0000, 0x0000, 0x0000 }, /* R850 */
- { 0x0000, 0x0000, 0x0000 }, /* R851 */
- { 0x0000, 0x0000, 0x0000 }, /* R852 */
- { 0x0000, 0x0000, 0x0000 }, /* R853 */
- { 0x0000, 0x0000, 0x0000 }, /* R854 */
- { 0x0000, 0x0000, 0x0000 }, /* R855 */
- { 0x0000, 0x0000, 0x0000 }, /* R856 */
- { 0x0000, 0x0000, 0x0000 }, /* R857 */
- { 0x0000, 0x0000, 0x0000 }, /* R858 */
- { 0x0000, 0x0000, 0x0000 }, /* R859 */
- { 0x0000, 0x0000, 0x0000 }, /* R860 */
- { 0x0000, 0x0000, 0x0000 }, /* R861 */
- { 0x0000, 0x0000, 0x0000 }, /* R862 */
- { 0x0000, 0x0000, 0x0000 }, /* R863 */
- { 0x0000, 0x0000, 0x0000 }, /* R864 */
- { 0x0000, 0x0000, 0x0000 }, /* R865 */
- { 0x0000, 0x0000, 0x0000 }, /* R866 */
- { 0x0000, 0x0000, 0x0000 }, /* R867 */
- { 0x0000, 0x0000, 0x0000 }, /* R868 */
- { 0x0000, 0x0000, 0x0000 }, /* R869 */
- { 0x0000, 0x0000, 0x0000 }, /* R870 */
- { 0x0000, 0x0000, 0x0000 }, /* R871 */
- { 0x0000, 0x0000, 0x0000 }, /* R872 */
- { 0x0000, 0x0000, 0x0000 }, /* R873 */
- { 0x0000, 0x0000, 0x0000 }, /* R874 */
- { 0x0000, 0x0000, 0x0000 }, /* R875 */
- { 0x0000, 0x0000, 0x0000 }, /* R876 */
- { 0x0000, 0x0000, 0x0000 }, /* R877 */
- { 0x0000, 0x0000, 0x0000 }, /* R878 */
- { 0x0000, 0x0000, 0x0000 }, /* R879 */
- { 0x0000, 0x0000, 0x0000 }, /* R880 */
- { 0x0000, 0x0000, 0x0000 }, /* R881 */
- { 0x0000, 0x0000, 0x0000 }, /* R882 */
- { 0x0000, 0x0000, 0x0000 }, /* R883 */
- { 0x0000, 0x0000, 0x0000 }, /* R884 */
- { 0x0000, 0x0000, 0x0000 }, /* R885 */
- { 0x0000, 0x0000, 0x0000 }, /* R886 */
- { 0x0000, 0x0000, 0x0000 }, /* R887 */
- { 0x0000, 0x0000, 0x0000 }, /* R888 */
- { 0x0000, 0x0000, 0x0000 }, /* R889 */
- { 0x0000, 0x0000, 0x0000 }, /* R890 */
- { 0x0000, 0x0000, 0x0000 }, /* R891 */
- { 0x0000, 0x0000, 0x0000 }, /* R892 */
- { 0x0000, 0x0000, 0x0000 }, /* R893 */
- { 0x0000, 0x0000, 0x0000 }, /* R894 */
- { 0x0000, 0x0000, 0x0000 }, /* R895 */
- { 0x0000, 0x0000, 0x0000 }, /* R896 */
- { 0x0000, 0x0000, 0x0000 }, /* R897 */
- { 0x0000, 0x0000, 0x0000 }, /* R898 */
- { 0x0000, 0x0000, 0x0000 }, /* R899 */
- { 0x0000, 0x0000, 0x0000 }, /* R900 */
- { 0x0000, 0x0000, 0x0000 }, /* R901 */
- { 0x0000, 0x0000, 0x0000 }, /* R902 */
- { 0x0000, 0x0000, 0x0000 }, /* R903 */
- { 0x0000, 0x0000, 0x0000 }, /* R904 */
- { 0x0000, 0x0000, 0x0000 }, /* R905 */
- { 0x0000, 0x0000, 0x0000 }, /* R906 */
- { 0x0000, 0x0000, 0x0000 }, /* R907 */
- { 0x0000, 0x0000, 0x0000 }, /* R908 */
- { 0x0000, 0x0000, 0x0000 }, /* R909 */
- { 0x0000, 0x0000, 0x0000 }, /* R910 */
- { 0x0000, 0x0000, 0x0000 }, /* R911 */
- { 0x0000, 0x0000, 0x0000 }, /* R912 */
- { 0x0000, 0x0000, 0x0000 }, /* R913 */
- { 0x0000, 0x0000, 0x0000 }, /* R914 */
- { 0x0000, 0x0000, 0x0000 }, /* R915 */
- { 0x0000, 0x0000, 0x0000 }, /* R916 */
- { 0x0000, 0x0000, 0x0000 }, /* R917 */
- { 0x0000, 0x0000, 0x0000 }, /* R918 */
- { 0x0000, 0x0000, 0x0000 }, /* R919 */
- { 0x0000, 0x0000, 0x0000 }, /* R920 */
- { 0x0000, 0x0000, 0x0000 }, /* R921 */
- { 0x0000, 0x0000, 0x0000 }, /* R922 */
- { 0x0000, 0x0000, 0x0000 }, /* R923 */
- { 0x0000, 0x0000, 0x0000 }, /* R924 */
- { 0x0000, 0x0000, 0x0000 }, /* R925 */
- { 0x0000, 0x0000, 0x0000 }, /* R926 */
- { 0x0000, 0x0000, 0x0000 }, /* R927 */
- { 0x0000, 0x0000, 0x0000 }, /* R928 */
- { 0x0000, 0x0000, 0x0000 }, /* R929 */
- { 0x0000, 0x0000, 0x0000 }, /* R930 */
- { 0x0000, 0x0000, 0x0000 }, /* R931 */
- { 0x0000, 0x0000, 0x0000 }, /* R932 */
- { 0x0000, 0x0000, 0x0000 }, /* R933 */
- { 0x0000, 0x0000, 0x0000 }, /* R934 */
- { 0x0000, 0x0000, 0x0000 }, /* R935 */
- { 0x0000, 0x0000, 0x0000 }, /* R936 */
- { 0x0000, 0x0000, 0x0000 }, /* R937 */
- { 0x0000, 0x0000, 0x0000 }, /* R938 */
- { 0x0000, 0x0000, 0x0000 }, /* R939 */
- { 0x0000, 0x0000, 0x0000 }, /* R940 */
- { 0x0000, 0x0000, 0x0000 }, /* R941 */
- { 0x0000, 0x0000, 0x0000 }, /* R942 */
- { 0x0000, 0x0000, 0x0000 }, /* R943 */
- { 0x0000, 0x0000, 0x0000 }, /* R944 */
- { 0x0000, 0x0000, 0x0000 }, /* R945 */
- { 0x0000, 0x0000, 0x0000 }, /* R946 */
- { 0x0000, 0x0000, 0x0000 }, /* R947 */
- { 0x0000, 0x0000, 0x0000 }, /* R948 */
- { 0x0000, 0x0000, 0x0000 }, /* R949 */
- { 0x0000, 0x0000, 0x0000 }, /* R950 */
- { 0x0000, 0x0000, 0x0000 }, /* R951 */
- { 0x0000, 0x0000, 0x0000 }, /* R952 */
- { 0x0000, 0x0000, 0x0000 }, /* R953 */
- { 0x0000, 0x0000, 0x0000 }, /* R954 */
- { 0x0000, 0x0000, 0x0000 }, /* R955 */
- { 0x0000, 0x0000, 0x0000 }, /* R956 */
- { 0x0000, 0x0000, 0x0000 }, /* R957 */
- { 0x0000, 0x0000, 0x0000 }, /* R958 */
- { 0x0000, 0x0000, 0x0000 }, /* R959 */
- { 0x0000, 0x0000, 0x0000 }, /* R960 */
- { 0x0000, 0x0000, 0x0000 }, /* R961 */
- { 0x0000, 0x0000, 0x0000 }, /* R962 */
- { 0x0000, 0x0000, 0x0000 }, /* R963 */
- { 0x0000, 0x0000, 0x0000 }, /* R964 */
- { 0x0000, 0x0000, 0x0000 }, /* R965 */
- { 0x0000, 0x0000, 0x0000 }, /* R966 */
- { 0x0000, 0x0000, 0x0000 }, /* R967 */
- { 0x0000, 0x0000, 0x0000 }, /* R968 */
- { 0x0000, 0x0000, 0x0000 }, /* R969 */
- { 0x0000, 0x0000, 0x0000 }, /* R970 */
- { 0x0000, 0x0000, 0x0000 }, /* R971 */
- { 0x0000, 0x0000, 0x0000 }, /* R972 */
- { 0x0000, 0x0000, 0x0000 }, /* R973 */
- { 0x0000, 0x0000, 0x0000 }, /* R974 */
- { 0x0000, 0x0000, 0x0000 }, /* R975 */
- { 0x0000, 0x0000, 0x0000 }, /* R976 */
- { 0x0000, 0x0000, 0x0000 }, /* R977 */
- { 0x0000, 0x0000, 0x0000 }, /* R978 */
- { 0x0000, 0x0000, 0x0000 }, /* R979 */
- { 0x0000, 0x0000, 0x0000 }, /* R980 */
- { 0x0000, 0x0000, 0x0000 }, /* R981 */
- { 0x0000, 0x0000, 0x0000 }, /* R982 */
- { 0x0000, 0x0000, 0x0000 }, /* R983 */
- { 0x0000, 0x0000, 0x0000 }, /* R984 */
- { 0x0000, 0x0000, 0x0000 }, /* R985 */
- { 0x0000, 0x0000, 0x0000 }, /* R986 */
- { 0x0000, 0x0000, 0x0000 }, /* R987 */
- { 0x0000, 0x0000, 0x0000 }, /* R988 */
- { 0x0000, 0x0000, 0x0000 }, /* R989 */
- { 0x0000, 0x0000, 0x0000 }, /* R990 */
- { 0x0000, 0x0000, 0x0000 }, /* R991 */
- { 0x0000, 0x0000, 0x0000 }, /* R992 */
- { 0x0000, 0x0000, 0x0000 }, /* R993 */
- { 0x0000, 0x0000, 0x0000 }, /* R994 */
- { 0x0000, 0x0000, 0x0000 }, /* R995 */
- { 0x0000, 0x0000, 0x0000 }, /* R996 */
- { 0x0000, 0x0000, 0x0000 }, /* R997 */
- { 0x0000, 0x0000, 0x0000 }, /* R998 */
- { 0x0000, 0x0000, 0x0000 }, /* R999 */
- { 0x0000, 0x0000, 0x0000 }, /* R1000 */
- { 0x0000, 0x0000, 0x0000 }, /* R1001 */
- { 0x0000, 0x0000, 0x0000 }, /* R1002 */
- { 0x0000, 0x0000, 0x0000 }, /* R1003 */
- { 0x0000, 0x0000, 0x0000 }, /* R1004 */
- { 0x0000, 0x0000, 0x0000 }, /* R1005 */
- { 0x0000, 0x0000, 0x0000 }, /* R1006 */
- { 0x0000, 0x0000, 0x0000 }, /* R1007 */
- { 0x0000, 0x0000, 0x0000 }, /* R1008 */
- { 0x0000, 0x0000, 0x0000 }, /* R1009 */
- { 0x0000, 0x0000, 0x0000 }, /* R1010 */
- { 0x0000, 0x0000, 0x0000 }, /* R1011 */
- { 0x0000, 0x0000, 0x0000 }, /* R1012 */
- { 0x0000, 0x0000, 0x0000 }, /* R1013 */
- { 0x0000, 0x0000, 0x0000 }, /* R1014 */
- { 0x0000, 0x0000, 0x0000 }, /* R1015 */
- { 0x0000, 0x0000, 0x0000 }, /* R1016 */
- { 0x0000, 0x0000, 0x0000 }, /* R1017 */
- { 0x0000, 0x0000, 0x0000 }, /* R1018 */
- { 0x0000, 0x0000, 0x0000 }, /* R1019 */
- { 0x0000, 0x0000, 0x0000 }, /* R1020 */
- { 0x0000, 0x0000, 0x0000 }, /* R1021 */
- { 0x0000, 0x0000, 0x0000 }, /* R1022 */
- { 0x0000, 0x0000, 0x0000 }, /* R1023 */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1024 - AIF1 ADC1 Left Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1025 - AIF1 ADC1 Right Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1026 - AIF1 DAC1 Left Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1027 - AIF1 DAC1 Right Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1028 - AIF1 ADC2 Left Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1029 - AIF1 ADC2 Right Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1030 - AIF1 DAC2 Left Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1031 - AIF1 DAC2 Right Volume */
- { 0x0000, 0x0000, 0x0000 }, /* R1032 */
- { 0x0000, 0x0000, 0x0000 }, /* R1033 */
- { 0x0000, 0x0000, 0x0000 }, /* R1034 */
- { 0x0000, 0x0000, 0x0000 }, /* R1035 */
- { 0x0000, 0x0000, 0x0000 }, /* R1036 */
- { 0x0000, 0x0000, 0x0000 }, /* R1037 */
- { 0x0000, 0x0000, 0x0000 }, /* R1038 */
- { 0x0000, 0x0000, 0x0000 }, /* R1039 */
- { 0xF800, 0xF800, 0x0000 }, /* R1040 - AIF1 ADC1 Filters */
- { 0x7800, 0x7800, 0x0000 }, /* R1041 - AIF1 ADC2 Filters */
- { 0x0000, 0x0000, 0x0000 }, /* R1042 */
- { 0x0000, 0x0000, 0x0000 }, /* R1043 */
- { 0x0000, 0x0000, 0x0000 }, /* R1044 */
- { 0x0000, 0x0000, 0x0000 }, /* R1045 */
- { 0x0000, 0x0000, 0x0000 }, /* R1046 */
- { 0x0000, 0x0000, 0x0000 }, /* R1047 */
- { 0x0000, 0x0000, 0x0000 }, /* R1048 */
- { 0x0000, 0x0000, 0x0000 }, /* R1049 */
- { 0x0000, 0x0000, 0x0000 }, /* R1050 */
- { 0x0000, 0x0000, 0x0000 }, /* R1051 */
- { 0x0000, 0x0000, 0x0000 }, /* R1052 */
- { 0x0000, 0x0000, 0x0000 }, /* R1053 */
- { 0x0000, 0x0000, 0x0000 }, /* R1054 */
- { 0x0000, 0x0000, 0x0000 }, /* R1055 */
- { 0x02B6, 0x02B6, 0x0000 }, /* R1056 - AIF1 DAC1 Filters (1) */
- { 0x3F00, 0x3F00, 0x0000 }, /* R1057 - AIF1 DAC1 Filters (2) */
- { 0x02B6, 0x02B6, 0x0000 }, /* R1058 - AIF1 DAC2 Filters (1) */
- { 0x3F00, 0x3F00, 0x0000 }, /* R1059 - AIF1 DAC2 Filters (2) */
- { 0x0000, 0x0000, 0x0000 }, /* R1060 */
- { 0x0000, 0x0000, 0x0000 }, /* R1061 */
- { 0x0000, 0x0000, 0x0000 }, /* R1062 */
- { 0x0000, 0x0000, 0x0000 }, /* R1063 */
- { 0x0000, 0x0000, 0x0000 }, /* R1064 */
- { 0x0000, 0x0000, 0x0000 }, /* R1065 */
- { 0x0000, 0x0000, 0x0000 }, /* R1066 */
- { 0x0000, 0x0000, 0x0000 }, /* R1067 */
- { 0x0000, 0x0000, 0x0000 }, /* R1068 */
- { 0x0000, 0x0000, 0x0000 }, /* R1069 */
- { 0x0000, 0x0000, 0x0000 }, /* R1070 */
- { 0x0000, 0x0000, 0x0000 }, /* R1071 */
- { 0x0000, 0x0000, 0x0000 }, /* R1072 */
- { 0x0000, 0x0000, 0x0000 }, /* R1073 */
- { 0x0000, 0x0000, 0x0000 }, /* R1074 */
- { 0x0000, 0x0000, 0x0000 }, /* R1075 */
- { 0x0000, 0x0000, 0x0000 }, /* R1076 */
- { 0x0000, 0x0000, 0x0000 }, /* R1077 */
- { 0x0000, 0x0000, 0x0000 }, /* R1078 */
- { 0x0000, 0x0000, 0x0000 }, /* R1079 */
- { 0x0000, 0x0000, 0x0000 }, /* R1080 */
- { 0x0000, 0x0000, 0x0000 }, /* R1081 */
- { 0x0000, 0x0000, 0x0000 }, /* R1082 */
- { 0x0000, 0x0000, 0x0000 }, /* R1083 */
- { 0x0000, 0x0000, 0x0000 }, /* R1084 */
- { 0x0000, 0x0000, 0x0000 }, /* R1085 */
- { 0x0000, 0x0000, 0x0000 }, /* R1086 */
- { 0x0000, 0x0000, 0x0000 }, /* R1087 */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1088 - AIF1 DRC1 (1) */
- { 0x1FFF, 0x1FFF, 0x0000 }, /* R1089 - AIF1 DRC1 (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1090 - AIF1 DRC1 (3) */
- { 0x07FF, 0x07FF, 0x0000 }, /* R1091 - AIF1 DRC1 (4) */
- { 0x03FF, 0x03FF, 0x0000 }, /* R1092 - AIF1 DRC1 (5) */
- { 0x0000, 0x0000, 0x0000 }, /* R1093 */
- { 0x0000, 0x0000, 0x0000 }, /* R1094 */
- { 0x0000, 0x0000, 0x0000 }, /* R1095 */
- { 0x0000, 0x0000, 0x0000 }, /* R1096 */
- { 0x0000, 0x0000, 0x0000 }, /* R1097 */
- { 0x0000, 0x0000, 0x0000 }, /* R1098 */
- { 0x0000, 0x0000, 0x0000 }, /* R1099 */
- { 0x0000, 0x0000, 0x0000 }, /* R1100 */
- { 0x0000, 0x0000, 0x0000 }, /* R1101 */
- { 0x0000, 0x0000, 0x0000 }, /* R1102 */
- { 0x0000, 0x0000, 0x0000 }, /* R1103 */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1104 - AIF1 DRC2 (1) */
- { 0x1FFF, 0x1FFF, 0x0000 }, /* R1105 - AIF1 DRC2 (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1106 - AIF1 DRC2 (3) */
- { 0x07FF, 0x07FF, 0x0000 }, /* R1107 - AIF1 DRC2 (4) */
- { 0x03FF, 0x03FF, 0x0000 }, /* R1108 - AIF1 DRC2 (5) */
- { 0x0000, 0x0000, 0x0000 }, /* R1109 */
- { 0x0000, 0x0000, 0x0000 }, /* R1110 */
- { 0x0000, 0x0000, 0x0000 }, /* R1111 */
- { 0x0000, 0x0000, 0x0000 }, /* R1112 */
- { 0x0000, 0x0000, 0x0000 }, /* R1113 */
- { 0x0000, 0x0000, 0x0000 }, /* R1114 */
- { 0x0000, 0x0000, 0x0000 }, /* R1115 */
- { 0x0000, 0x0000, 0x0000 }, /* R1116 */
- { 0x0000, 0x0000, 0x0000 }, /* R1117 */
- { 0x0000, 0x0000, 0x0000 }, /* R1118 */
- { 0x0000, 0x0000, 0x0000 }, /* R1119 */
- { 0x0000, 0x0000, 0x0000 }, /* R1120 */
- { 0x0000, 0x0000, 0x0000 }, /* R1121 */
- { 0x0000, 0x0000, 0x0000 }, /* R1122 */
- { 0x0000, 0x0000, 0x0000 }, /* R1123 */
- { 0x0000, 0x0000, 0x0000 }, /* R1124 */
- { 0x0000, 0x0000, 0x0000 }, /* R1125 */
- { 0x0000, 0x0000, 0x0000 }, /* R1126 */
- { 0x0000, 0x0000, 0x0000 }, /* R1127 */
- { 0x0000, 0x0000, 0x0000 }, /* R1128 */
- { 0x0000, 0x0000, 0x0000 }, /* R1129 */
- { 0x0000, 0x0000, 0x0000 }, /* R1130 */
- { 0x0000, 0x0000, 0x0000 }, /* R1131 */
- { 0x0000, 0x0000, 0x0000 }, /* R1132 */
- { 0x0000, 0x0000, 0x0000 }, /* R1133 */
- { 0x0000, 0x0000, 0x0000 }, /* R1134 */
- { 0x0000, 0x0000, 0x0000 }, /* R1135 */
- { 0x0000, 0x0000, 0x0000 }, /* R1136 */
- { 0x0000, 0x0000, 0x0000 }, /* R1137 */
- { 0x0000, 0x0000, 0x0000 }, /* R1138 */
- { 0x0000, 0x0000, 0x0000 }, /* R1139 */
- { 0x0000, 0x0000, 0x0000 }, /* R1140 */
- { 0x0000, 0x0000, 0x0000 }, /* R1141 */
- { 0x0000, 0x0000, 0x0000 }, /* R1142 */
- { 0x0000, 0x0000, 0x0000 }, /* R1143 */
- { 0x0000, 0x0000, 0x0000 }, /* R1144 */
- { 0x0000, 0x0000, 0x0000 }, /* R1145 */
- { 0x0000, 0x0000, 0x0000 }, /* R1146 */
- { 0x0000, 0x0000, 0x0000 }, /* R1147 */
- { 0x0000, 0x0000, 0x0000 }, /* R1148 */
- { 0x0000, 0x0000, 0x0000 }, /* R1149 */
- { 0x0000, 0x0000, 0x0000 }, /* R1150 */
- { 0x0000, 0x0000, 0x0000 }, /* R1151 */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1152 - AIF1 DAC1 EQ Gains (1) */
- { 0xFFC0, 0xFFC0, 0x0000 }, /* R1153 - AIF1 DAC1 EQ Gains (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1154 - AIF1 DAC1 EQ Band 1 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1155 - AIF1 DAC1 EQ Band 1 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1156 - AIF1 DAC1 EQ Band 1 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1157 - AIF1 DAC1 EQ Band 2 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1158 - AIF1 DAC1 EQ Band 2 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1159 - AIF1 DAC1 EQ Band 2 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1160 - AIF1 DAC1 EQ Band 2 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1161 - AIF1 DAC1 EQ Band 3 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1162 - AIF1 DAC1 EQ Band 3 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1163 - AIF1 DAC1 EQ Band 3 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1164 - AIF1 DAC1 EQ Band 3 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1165 - AIF1 DAC1 EQ Band 4 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1166 - AIF1 DAC1 EQ Band 4 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1167 - AIF1 DAC1 EQ Band 4 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1168 - AIF1 DAC1 EQ Band 4 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1169 - AIF1 DAC1 EQ Band 5 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1170 - AIF1 DAC1 EQ Band 5 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1171 - AIF1 DAC1 EQ Band 5 PG */
- { 0x0000, 0x0000, 0x0000 }, /* R1172 */
- { 0x0000, 0x0000, 0x0000 }, /* R1173 */
- { 0x0000, 0x0000, 0x0000 }, /* R1174 */
- { 0x0000, 0x0000, 0x0000 }, /* R1175 */
- { 0x0000, 0x0000, 0x0000 }, /* R1176 */
- { 0x0000, 0x0000, 0x0000 }, /* R1177 */
- { 0x0000, 0x0000, 0x0000 }, /* R1178 */
- { 0x0000, 0x0000, 0x0000 }, /* R1179 */
- { 0x0000, 0x0000, 0x0000 }, /* R1180 */
- { 0x0000, 0x0000, 0x0000 }, /* R1181 */
- { 0x0000, 0x0000, 0x0000 }, /* R1182 */
- { 0x0000, 0x0000, 0x0000 }, /* R1183 */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1184 - AIF1 DAC2 EQ Gains (1) */
- { 0xFFC0, 0xFFC0, 0x0000 }, /* R1185 - AIF1 DAC2 EQ Gains (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1186 - AIF1 DAC2 EQ Band 1 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1187 - AIF1 DAC2 EQ Band 1 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1188 - AIF1 DAC2 EQ Band 1 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1189 - AIF1 DAC2 EQ Band 2 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1190 - AIF1 DAC2 EQ Band 2 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1191 - AIF1 DAC2 EQ Band 2 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1192 - AIF1 DAC2 EQ Band 2 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1193 - AIF1 DAC2 EQ Band 3 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1194 - AIF1 DAC2 EQ Band 3 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1195 - AIF1 DAC2 EQ Band 3 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1196 - AIF1 DAC2 EQ Band 3 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1197 - AIF1 DAC2 EQ Band 4 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1198 - AIF1 DAC2 EQ Band 4 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1199 - AIF1 DAC2 EQ Band 4 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1200 - AIF1 DAC2 EQ Band 4 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1201 - AIF1 DAC2 EQ Band 5 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1202 - AIF1 DAC2 EQ Band 5 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1203 - AIF1 DAC2 EQ Band 5 PG */
- { 0x0000, 0x0000, 0x0000 }, /* R1204 */
- { 0x0000, 0x0000, 0x0000 }, /* R1205 */
- { 0x0000, 0x0000, 0x0000 }, /* R1206 */
- { 0x0000, 0x0000, 0x0000 }, /* R1207 */
- { 0x0000, 0x0000, 0x0000 }, /* R1208 */
- { 0x0000, 0x0000, 0x0000 }, /* R1209 */
- { 0x0000, 0x0000, 0x0000 }, /* R1210 */
- { 0x0000, 0x0000, 0x0000 }, /* R1211 */
- { 0x0000, 0x0000, 0x0000 }, /* R1212 */
- { 0x0000, 0x0000, 0x0000 }, /* R1213 */
- { 0x0000, 0x0000, 0x0000 }, /* R1214 */
- { 0x0000, 0x0000, 0x0000 }, /* R1215 */
- { 0x0000, 0x0000, 0x0000 }, /* R1216 */
- { 0x0000, 0x0000, 0x0000 }, /* R1217 */
- { 0x0000, 0x0000, 0x0000 }, /* R1218 */
- { 0x0000, 0x0000, 0x0000 }, /* R1219 */
- { 0x0000, 0x0000, 0x0000 }, /* R1220 */
- { 0x0000, 0x0000, 0x0000 }, /* R1221 */
- { 0x0000, 0x0000, 0x0000 }, /* R1222 */
- { 0x0000, 0x0000, 0x0000 }, /* R1223 */
- { 0x0000, 0x0000, 0x0000 }, /* R1224 */
- { 0x0000, 0x0000, 0x0000 }, /* R1225 */
- { 0x0000, 0x0000, 0x0000 }, /* R1226 */
- { 0x0000, 0x0000, 0x0000 }, /* R1227 */
- { 0x0000, 0x0000, 0x0000 }, /* R1228 */
- { 0x0000, 0x0000, 0x0000 }, /* R1229 */
- { 0x0000, 0x0000, 0x0000 }, /* R1230 */
- { 0x0000, 0x0000, 0x0000 }, /* R1231 */
- { 0x0000, 0x0000, 0x0000 }, /* R1232 */
- { 0x0000, 0x0000, 0x0000 }, /* R1233 */
- { 0x0000, 0x0000, 0x0000 }, /* R1234 */
- { 0x0000, 0x0000, 0x0000 }, /* R1235 */
- { 0x0000, 0x0000, 0x0000 }, /* R1236 */
- { 0x0000, 0x0000, 0x0000 }, /* R1237 */
- { 0x0000, 0x0000, 0x0000 }, /* R1238 */
- { 0x0000, 0x0000, 0x0000 }, /* R1239 */
- { 0x0000, 0x0000, 0x0000 }, /* R1240 */
- { 0x0000, 0x0000, 0x0000 }, /* R1241 */
- { 0x0000, 0x0000, 0x0000 }, /* R1242 */
- { 0x0000, 0x0000, 0x0000 }, /* R1243 */
- { 0x0000, 0x0000, 0x0000 }, /* R1244 */
- { 0x0000, 0x0000, 0x0000 }, /* R1245 */
- { 0x0000, 0x0000, 0x0000 }, /* R1246 */
- { 0x0000, 0x0000, 0x0000 }, /* R1247 */
- { 0x0000, 0x0000, 0x0000 }, /* R1248 */
- { 0x0000, 0x0000, 0x0000 }, /* R1249 */
- { 0x0000, 0x0000, 0x0000 }, /* R1250 */
- { 0x0000, 0x0000, 0x0000 }, /* R1251 */
- { 0x0000, 0x0000, 0x0000 }, /* R1252 */
- { 0x0000, 0x0000, 0x0000 }, /* R1253 */
- { 0x0000, 0x0000, 0x0000 }, /* R1254 */
- { 0x0000, 0x0000, 0x0000 }, /* R1255 */
- { 0x0000, 0x0000, 0x0000 }, /* R1256 */
- { 0x0000, 0x0000, 0x0000 }, /* R1257 */
- { 0x0000, 0x0000, 0x0000 }, /* R1258 */
- { 0x0000, 0x0000, 0x0000 }, /* R1259 */
- { 0x0000, 0x0000, 0x0000 }, /* R1260 */
- { 0x0000, 0x0000, 0x0000 }, /* R1261 */
- { 0x0000, 0x0000, 0x0000 }, /* R1262 */
- { 0x0000, 0x0000, 0x0000 }, /* R1263 */
- { 0x0000, 0x0000, 0x0000 }, /* R1264 */
- { 0x0000, 0x0000, 0x0000 }, /* R1265 */
- { 0x0000, 0x0000, 0x0000 }, /* R1266 */
- { 0x0000, 0x0000, 0x0000 }, /* R1267 */
- { 0x0000, 0x0000, 0x0000 }, /* R1268 */
- { 0x0000, 0x0000, 0x0000 }, /* R1269 */
- { 0x0000, 0x0000, 0x0000 }, /* R1270 */
- { 0x0000, 0x0000, 0x0000 }, /* R1271 */
- { 0x0000, 0x0000, 0x0000 }, /* R1272 */
- { 0x0000, 0x0000, 0x0000 }, /* R1273 */
- { 0x0000, 0x0000, 0x0000 }, /* R1274 */
- { 0x0000, 0x0000, 0x0000 }, /* R1275 */
- { 0x0000, 0x0000, 0x0000 }, /* R1276 */
- { 0x0000, 0x0000, 0x0000 }, /* R1277 */
- { 0x0000, 0x0000, 0x0000 }, /* R1278 */
- { 0x0000, 0x0000, 0x0000 }, /* R1279 */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1280 - AIF2 ADC Left Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1281 - AIF2 ADC Right Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1282 - AIF2 DAC Left Volume */
- { 0x00FF, 0x01FF, 0x0000 }, /* R1283 - AIF2 DAC Right Volume */
- { 0x0000, 0x0000, 0x0000 }, /* R1284 */
- { 0x0000, 0x0000, 0x0000 }, /* R1285 */
- { 0x0000, 0x0000, 0x0000 }, /* R1286 */
- { 0x0000, 0x0000, 0x0000 }, /* R1287 */
- { 0x0000, 0x0000, 0x0000 }, /* R1288 */
- { 0x0000, 0x0000, 0x0000 }, /* R1289 */
- { 0x0000, 0x0000, 0x0000 }, /* R1290 */
- { 0x0000, 0x0000, 0x0000 }, /* R1291 */
- { 0x0000, 0x0000, 0x0000 }, /* R1292 */
- { 0x0000, 0x0000, 0x0000 }, /* R1293 */
- { 0x0000, 0x0000, 0x0000 }, /* R1294 */
- { 0x0000, 0x0000, 0x0000 }, /* R1295 */
- { 0xF800, 0xF800, 0x0000 }, /* R1296 - AIF2 ADC Filters */
- { 0x0000, 0x0000, 0x0000 }, /* R1297 */
- { 0x0000, 0x0000, 0x0000 }, /* R1298 */
- { 0x0000, 0x0000, 0x0000 }, /* R1299 */
- { 0x0000, 0x0000, 0x0000 }, /* R1300 */
- { 0x0000, 0x0000, 0x0000 }, /* R1301 */
- { 0x0000, 0x0000, 0x0000 }, /* R1302 */
- { 0x0000, 0x0000, 0x0000 }, /* R1303 */
- { 0x0000, 0x0000, 0x0000 }, /* R1304 */
- { 0x0000, 0x0000, 0x0000 }, /* R1305 */
- { 0x0000, 0x0000, 0x0000 }, /* R1306 */
- { 0x0000, 0x0000, 0x0000 }, /* R1307 */
- { 0x0000, 0x0000, 0x0000 }, /* R1308 */
- { 0x0000, 0x0000, 0x0000 }, /* R1309 */
- { 0x0000, 0x0000, 0x0000 }, /* R1310 */
- { 0x0000, 0x0000, 0x0000 }, /* R1311 */
- { 0x02B6, 0x02B6, 0x0000 }, /* R1312 - AIF2 DAC Filters (1) */
- { 0x3F00, 0x3F00, 0x0000 }, /* R1313 - AIF2 DAC Filters (2) */
- { 0x0000, 0x0000, 0x0000 }, /* R1314 */
- { 0x0000, 0x0000, 0x0000 }, /* R1315 */
- { 0x0000, 0x0000, 0x0000 }, /* R1316 */
- { 0x0000, 0x0000, 0x0000 }, /* R1317 */
- { 0x0000, 0x0000, 0x0000 }, /* R1318 */
- { 0x0000, 0x0000, 0x0000 }, /* R1319 */
- { 0x0000, 0x0000, 0x0000 }, /* R1320 */
- { 0x0000, 0x0000, 0x0000 }, /* R1321 */
- { 0x0000, 0x0000, 0x0000 }, /* R1322 */
- { 0x0000, 0x0000, 0x0000 }, /* R1323 */
- { 0x0000, 0x0000, 0x0000 }, /* R1324 */
- { 0x0000, 0x0000, 0x0000 }, /* R1325 */
- { 0x0000, 0x0000, 0x0000 }, /* R1326 */
- { 0x0000, 0x0000, 0x0000 }, /* R1327 */
- { 0x0000, 0x0000, 0x0000 }, /* R1328 */
- { 0x0000, 0x0000, 0x0000 }, /* R1329 */
- { 0x0000, 0x0000, 0x0000 }, /* R1330 */
- { 0x0000, 0x0000, 0x0000 }, /* R1331 */
- { 0x0000, 0x0000, 0x0000 }, /* R1332 */
- { 0x0000, 0x0000, 0x0000 }, /* R1333 */
- { 0x0000, 0x0000, 0x0000 }, /* R1334 */
- { 0x0000, 0x0000, 0x0000 }, /* R1335 */
- { 0x0000, 0x0000, 0x0000 }, /* R1336 */
- { 0x0000, 0x0000, 0x0000 }, /* R1337 */
- { 0x0000, 0x0000, 0x0000 }, /* R1338 */
- { 0x0000, 0x0000, 0x0000 }, /* R1339 */
- { 0x0000, 0x0000, 0x0000 }, /* R1340 */
- { 0x0000, 0x0000, 0x0000 }, /* R1341 */
- { 0x0000, 0x0000, 0x0000 }, /* R1342 */
- { 0x0000, 0x0000, 0x0000 }, /* R1343 */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1344 - AIF2 DRC (1) */
- { 0x1FFF, 0x1FFF, 0x0000 }, /* R1345 - AIF2 DRC (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1346 - AIF2 DRC (3) */
- { 0x07FF, 0x07FF, 0x0000 }, /* R1347 - AIF2 DRC (4) */
- { 0x03FF, 0x03FF, 0x0000 }, /* R1348 - AIF2 DRC (5) */
- { 0x0000, 0x0000, 0x0000 }, /* R1349 */
- { 0x0000, 0x0000, 0x0000 }, /* R1350 */
- { 0x0000, 0x0000, 0x0000 }, /* R1351 */
- { 0x0000, 0x0000, 0x0000 }, /* R1352 */
- { 0x0000, 0x0000, 0x0000 }, /* R1353 */
- { 0x0000, 0x0000, 0x0000 }, /* R1354 */
- { 0x0000, 0x0000, 0x0000 }, /* R1355 */
- { 0x0000, 0x0000, 0x0000 }, /* R1356 */
- { 0x0000, 0x0000, 0x0000 }, /* R1357 */
- { 0x0000, 0x0000, 0x0000 }, /* R1358 */
- { 0x0000, 0x0000, 0x0000 }, /* R1359 */
- { 0x0000, 0x0000, 0x0000 }, /* R1360 */
- { 0x0000, 0x0000, 0x0000 }, /* R1361 */
- { 0x0000, 0x0000, 0x0000 }, /* R1362 */
- { 0x0000, 0x0000, 0x0000 }, /* R1363 */
- { 0x0000, 0x0000, 0x0000 }, /* R1364 */
- { 0x0000, 0x0000, 0x0000 }, /* R1365 */
- { 0x0000, 0x0000, 0x0000 }, /* R1366 */
- { 0x0000, 0x0000, 0x0000 }, /* R1367 */
- { 0x0000, 0x0000, 0x0000 }, /* R1368 */
- { 0x0000, 0x0000, 0x0000 }, /* R1369 */
- { 0x0000, 0x0000, 0x0000 }, /* R1370 */
- { 0x0000, 0x0000, 0x0000 }, /* R1371 */
- { 0x0000, 0x0000, 0x0000 }, /* R1372 */
- { 0x0000, 0x0000, 0x0000 }, /* R1373 */
- { 0x0000, 0x0000, 0x0000 }, /* R1374 */
- { 0x0000, 0x0000, 0x0000 }, /* R1375 */
- { 0x0000, 0x0000, 0x0000 }, /* R1376 */
- { 0x0000, 0x0000, 0x0000 }, /* R1377 */
- { 0x0000, 0x0000, 0x0000 }, /* R1378 */
- { 0x0000, 0x0000, 0x0000 }, /* R1379 */
- { 0x0000, 0x0000, 0x0000 }, /* R1380 */
- { 0x0000, 0x0000, 0x0000 }, /* R1381 */
- { 0x0000, 0x0000, 0x0000 }, /* R1382 */
- { 0x0000, 0x0000, 0x0000 }, /* R1383 */
- { 0x0000, 0x0000, 0x0000 }, /* R1384 */
- { 0x0000, 0x0000, 0x0000 }, /* R1385 */
- { 0x0000, 0x0000, 0x0000 }, /* R1386 */
- { 0x0000, 0x0000, 0x0000 }, /* R1387 */
- { 0x0000, 0x0000, 0x0000 }, /* R1388 */
- { 0x0000, 0x0000, 0x0000 }, /* R1389 */
- { 0x0000, 0x0000, 0x0000 }, /* R1390 */
- { 0x0000, 0x0000, 0x0000 }, /* R1391 */
- { 0x0000, 0x0000, 0x0000 }, /* R1392 */
- { 0x0000, 0x0000, 0x0000 }, /* R1393 */
- { 0x0000, 0x0000, 0x0000 }, /* R1394 */
- { 0x0000, 0x0000, 0x0000 }, /* R1395 */
- { 0x0000, 0x0000, 0x0000 }, /* R1396 */
- { 0x0000, 0x0000, 0x0000 }, /* R1397 */
- { 0x0000, 0x0000, 0x0000 }, /* R1398 */
- { 0x0000, 0x0000, 0x0000 }, /* R1399 */
- { 0x0000, 0x0000, 0x0000 }, /* R1400 */
- { 0x0000, 0x0000, 0x0000 }, /* R1401 */
- { 0x0000, 0x0000, 0x0000 }, /* R1402 */
- { 0x0000, 0x0000, 0x0000 }, /* R1403 */
- { 0x0000, 0x0000, 0x0000 }, /* R1404 */
- { 0x0000, 0x0000, 0x0000 }, /* R1405 */
- { 0x0000, 0x0000, 0x0000 }, /* R1406 */
- { 0x0000, 0x0000, 0x0000 }, /* R1407 */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1408 - AIF2 EQ Gains (1) */
- { 0xFFC0, 0xFFC0, 0x0000 }, /* R1409 - AIF2 EQ Gains (2) */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1410 - AIF2 EQ Band 1 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1411 - AIF2 EQ Band 1 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1412 - AIF2 EQ Band 1 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1413 - AIF2 EQ Band 2 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1414 - AIF2 EQ Band 2 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1415 - AIF2 EQ Band 2 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1416 - AIF2 EQ Band 2 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1417 - AIF2 EQ Band 3 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1418 - AIF2 EQ Band 3 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1419 - AIF2 EQ Band 3 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1420 - AIF2 EQ Band 3 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1421 - AIF2 EQ Band 4 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1422 - AIF2 EQ Band 4 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1423 - AIF2 EQ Band 4 C */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1424 - AIF2 EQ Band 4 PG */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1425 - AIF2 EQ Band 5 A */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1426 - AIF2 EQ Band 5 B */
- { 0xFFFF, 0xFFFF, 0x0000 }, /* R1427 - AIF2 EQ Band 5 PG */
- { 0x0000, 0x0000, 0x0000 }, /* R1428 */
- { 0x0000, 0x0000, 0x0000 }, /* R1429 */
- { 0x0000, 0x0000, 0x0000 }, /* R1430 */
- { 0x0000, 0x0000, 0x0000 }, /* R1431 */
- { 0x0000, 0x0000, 0x0000 }, /* R1432 */
- { 0x0000, 0x0000, 0x0000 }, /* R1433 */
- { 0x0000, 0x0000, 0x0000 }, /* R1434 */
- { 0x0000, 0x0000, 0x0000 }, /* R1435 */
- { 0x0000, 0x0000, 0x0000 }, /* R1436 */
- { 0x0000, 0x0000, 0x0000 }, /* R1437 */
- { 0x0000, 0x0000, 0x0000 }, /* R1438 */
- { 0x0000, 0x0000, 0x0000 }, /* R1439 */
- { 0x0000, 0x0000, 0x0000 }, /* R1440 */
- { 0x0000, 0x0000, 0x0000 }, /* R1441 */
- { 0x0000, 0x0000, 0x0000 }, /* R1442 */
- { 0x0000, 0x0000, 0x0000 }, /* R1443 */
- { 0x0000, 0x0000, 0x0000 }, /* R1444 */
- { 0x0000, 0x0000, 0x0000 }, /* R1445 */
- { 0x0000, 0x0000, 0x0000 }, /* R1446 */
- { 0x0000, 0x0000, 0x0000 }, /* R1447 */
- { 0x0000, 0x0000, 0x0000 }, /* R1448 */
- { 0x0000, 0x0000, 0x0000 }, /* R1449 */
- { 0x0000, 0x0000, 0x0000 }, /* R1450 */
- { 0x0000, 0x0000, 0x0000 }, /* R1451 */
- { 0x0000, 0x0000, 0x0000 }, /* R1452 */
- { 0x0000, 0x0000, 0x0000 }, /* R1453 */
- { 0x0000, 0x0000, 0x0000 }, /* R1454 */
- { 0x0000, 0x0000, 0x0000 }, /* R1455 */
- { 0x0000, 0x0000, 0x0000 }, /* R1456 */
- { 0x0000, 0x0000, 0x0000 }, /* R1457 */
- { 0x0000, 0x0000, 0x0000 }, /* R1458 */
- { 0x0000, 0x0000, 0x0000 }, /* R1459 */
- { 0x0000, 0x0000, 0x0000 }, /* R1460 */
- { 0x0000, 0x0000, 0x0000 }, /* R1461 */
- { 0x0000, 0x0000, 0x0000 }, /* R1462 */
- { 0x0000, 0x0000, 0x0000 }, /* R1463 */
- { 0x0000, 0x0000, 0x0000 }, /* R1464 */
- { 0x0000, 0x0000, 0x0000 }, /* R1465 */
- { 0x0000, 0x0000, 0x0000 }, /* R1466 */
- { 0x0000, 0x0000, 0x0000 }, /* R1467 */
- { 0x0000, 0x0000, 0x0000 }, /* R1468 */
- { 0x0000, 0x0000, 0x0000 }, /* R1469 */
- { 0x0000, 0x0000, 0x0000 }, /* R1470 */
- { 0x0000, 0x0000, 0x0000 }, /* R1471 */
- { 0x0000, 0x0000, 0x0000 }, /* R1472 */
- { 0x0000, 0x0000, 0x0000 }, /* R1473 */
- { 0x0000, 0x0000, 0x0000 }, /* R1474 */
- { 0x0000, 0x0000, 0x0000 }, /* R1475 */
- { 0x0000, 0x0000, 0x0000 }, /* R1476 */
- { 0x0000, 0x0000, 0x0000 }, /* R1477 */
- { 0x0000, 0x0000, 0x0000 }, /* R1478 */
- { 0x0000, 0x0000, 0x0000 }, /* R1479 */
- { 0x0000, 0x0000, 0x0000 }, /* R1480 */
- { 0x0000, 0x0000, 0x0000 }, /* R1481 */
- { 0x0000, 0x0000, 0x0000 }, /* R1482 */
- { 0x0000, 0x0000, 0x0000 }, /* R1483 */
- { 0x0000, 0x0000, 0x0000 }, /* R1484 */
- { 0x0000, 0x0000, 0x0000 }, /* R1485 */
- { 0x0000, 0x0000, 0x0000 }, /* R1486 */
- { 0x0000, 0x0000, 0x0000 }, /* R1487 */
- { 0x0000, 0x0000, 0x0000 }, /* R1488 */
- { 0x0000, 0x0000, 0x0000 }, /* R1489 */
- { 0x0000, 0x0000, 0x0000 }, /* R1490 */
- { 0x0000, 0x0000, 0x0000 }, /* R1491 */
- { 0x0000, 0x0000, 0x0000 }, /* R1492 */
- { 0x0000, 0x0000, 0x0000 }, /* R1493 */
- { 0x0000, 0x0000, 0x0000 }, /* R1494 */
- { 0x0000, 0x0000, 0x0000 }, /* R1495 */
- { 0x0000, 0x0000, 0x0000 }, /* R1496 */
- { 0x0000, 0x0000, 0x0000 }, /* R1497 */
- { 0x0000, 0x0000, 0x0000 }, /* R1498 */
- { 0x0000, 0x0000, 0x0000 }, /* R1499 */
- { 0x0000, 0x0000, 0x0000 }, /* R1500 */
- { 0x0000, 0x0000, 0x0000 }, /* R1501 */
- { 0x0000, 0x0000, 0x0000 }, /* R1502 */
- { 0x0000, 0x0000, 0x0000 }, /* R1503 */
- { 0x0000, 0x0000, 0x0000 }, /* R1504 */
- { 0x0000, 0x0000, 0x0000 }, /* R1505 */
- { 0x0000, 0x0000, 0x0000 }, /* R1506 */
- { 0x0000, 0x0000, 0x0000 }, /* R1507 */
- { 0x0000, 0x0000, 0x0000 }, /* R1508 */
- { 0x0000, 0x0000, 0x0000 }, /* R1509 */
- { 0x0000, 0x0000, 0x0000 }, /* R1510 */
- { 0x0000, 0x0000, 0x0000 }, /* R1511 */
- { 0x0000, 0x0000, 0x0000 }, /* R1512 */
- { 0x0000, 0x0000, 0x0000 }, /* R1513 */
- { 0x0000, 0x0000, 0x0000 }, /* R1514 */
- { 0x0000, 0x0000, 0x0000 }, /* R1515 */
- { 0x0000, 0x0000, 0x0000 }, /* R1516 */
- { 0x0000, 0x0000, 0x0000 }, /* R1517 */
- { 0x0000, 0x0000, 0x0000 }, /* R1518 */
- { 0x0000, 0x0000, 0x0000 }, /* R1519 */
- { 0x0000, 0x0000, 0x0000 }, /* R1520 */
- { 0x0000, 0x0000, 0x0000 }, /* R1521 */
- { 0x0000, 0x0000, 0x0000 }, /* R1522 */
- { 0x0000, 0x0000, 0x0000 }, /* R1523 */
- { 0x0000, 0x0000, 0x0000 }, /* R1524 */
- { 0x0000, 0x0000, 0x0000 }, /* R1525 */
- { 0x0000, 0x0000, 0x0000 }, /* R1526 */
- { 0x0000, 0x0000, 0x0000 }, /* R1527 */
- { 0x0000, 0x0000, 0x0000 }, /* R1528 */
- { 0x0000, 0x0000, 0x0000 }, /* R1529 */
- { 0x0000, 0x0000, 0x0000 }, /* R1530 */
- { 0x0000, 0x0000, 0x0000 }, /* R1531 */
- { 0x0000, 0x0000, 0x0000 }, /* R1532 */
- { 0x0000, 0x0000, 0x0000 }, /* R1533 */
- { 0x0000, 0x0000, 0x0000 }, /* R1534 */
- { 0x0000, 0x0000, 0x0000 }, /* R1535 */
- { 0x01EF, 0x01EF, 0x0000 }, /* R1536 - DAC1 Mixer Volumes */
- { 0x0037, 0x0037, 0x0000 }, /* R1537 - DAC1 Left Mixer Routing */
- { 0x0037, 0x0037, 0x0000 }, /* R1538 - DAC1 Right Mixer Routing */
- { 0x01EF, 0x01EF, 0x0000 }, /* R1539 - DAC2 Mixer Volumes */
- { 0x0037, 0x0037, 0x0000 }, /* R1540 - DAC2 Left Mixer Routing */
- { 0x0037, 0x0037, 0x0000 }, /* R1541 - DAC2 Right Mixer Routing */
- { 0x0003, 0x0003, 0x0000 }, /* R1542 - AIF1 ADC1 Left Mixer Routing */
- { 0x0003, 0x0003, 0x0000 }, /* R1543 - AIF1 ADC1 Right Mixer Routing */
- { 0x0003, 0x0003, 0x0000 }, /* R1544 - AIF1 ADC2 Left Mixer Routing */
- { 0x0003, 0x0003, 0x0000 }, /* R1545 - AIF1 ADC2 Right mixer Routing */
- { 0x0000, 0x0000, 0x0000 }, /* R1546 */
- { 0x0000, 0x0000, 0x0000 }, /* R1547 */
- { 0x0000, 0x0000, 0x0000 }, /* R1548 */
- { 0x0000, 0x0000, 0x0000 }, /* R1549 */
- { 0x0000, 0x0000, 0x0000 }, /* R1550 */
- { 0x0000, 0x0000, 0x0000 }, /* R1551 */
- { 0x02FF, 0x03FF, 0x0000 }, /* R1552 - DAC1 Left Volume */
- { 0x02FF, 0x03FF, 0x0000 }, /* R1553 - DAC1 Right Volume */
- { 0x02FF, 0x03FF, 0x0000 }, /* R1554 - DAC2 Left Volume */
- { 0x02FF, 0x03FF, 0x0000 }, /* R1555 - DAC2 Right Volume */
- { 0x0003, 0x0003, 0x0000 }, /* R1556 - DAC Softmute */
- { 0x0000, 0x0000, 0x0000 }, /* R1557 */
- { 0x0000, 0x0000, 0x0000 }, /* R1558 */
- { 0x0000, 0x0000, 0x0000 }, /* R1559 */
- { 0x0000, 0x0000, 0x0000 }, /* R1560 */
- { 0x0000, 0x0000, 0x0000 }, /* R1561 */
- { 0x0000, 0x0000, 0x0000 }, /* R1562 */
- { 0x0000, 0x0000, 0x0000 }, /* R1563 */
- { 0x0000, 0x0000, 0x0000 }, /* R1564 */
- { 0x0000, 0x0000, 0x0000 }, /* R1565 */
- { 0x0000, 0x0000, 0x0000 }, /* R1566 */
- { 0x0000, 0x0000, 0x0000 }, /* R1567 */
- { 0x0003, 0x0003, 0x0000 }, /* R1568 - Oversampling */
- { 0x03C3, 0x03C3, 0x0000 }, /* R1569 - Sidetone */
+ { 0xFFFF, 0xFFFF }, /* R0 - Software Reset */
+ { 0x3B37, 0x3B37 }, /* R1 - Power Management (1) */
+ { 0x6BF0, 0x6BF0 }, /* R2 - Power Management (2) */
+ { 0x3FF0, 0x3FF0 }, /* R3 - Power Management (3) */
+ { 0x3F3F, 0x3F3F }, /* R4 - Power Management (4) */
+ { 0x3F0F, 0x3F0F }, /* R5 - Power Management (5) */
+ { 0x003F, 0x003F }, /* R6 - Power Management (6) */
+ { 0x0000, 0x0000 }, /* R7 */
+ { 0x0000, 0x0000 }, /* R8 */
+ { 0x0000, 0x0000 }, /* R9 */
+ { 0x0000, 0x0000 }, /* R10 */
+ { 0x0000, 0x0000 }, /* R11 */
+ { 0x0000, 0x0000 }, /* R12 */
+ { 0x0000, 0x0000 }, /* R13 */
+ { 0x0000, 0x0000 }, /* R14 */
+ { 0x0000, 0x0000 }, /* R15 */
+ { 0x0000, 0x0000 }, /* R16 */
+ { 0x0000, 0x0000 }, /* R17 */
+ { 0x0000, 0x0000 }, /* R18 */
+ { 0x0000, 0x0000 }, /* R19 */
+ { 0x0000, 0x0000 }, /* R20 */
+ { 0x01C0, 0x01C0 }, /* R21 - Input Mixer (1) */
+ { 0x0000, 0x0000 }, /* R22 */
+ { 0x0000, 0x0000 }, /* R23 */
+ { 0x00DF, 0x01DF }, /* R24 - Left Line Input 1&2 Volume */
+ { 0x00DF, 0x01DF }, /* R25 - Left Line Input 3&4 Volume */
+ { 0x00DF, 0x01DF }, /* R26 - Right Line Input 1&2 Volume */
+ { 0x00DF, 0x01DF }, /* R27 - Right Line Input 3&4 Volume */
+ { 0x00FF, 0x01FF }, /* R28 - Left Output Volume */
+ { 0x00FF, 0x01FF }, /* R29 - Right Output Volume */
+ { 0x0077, 0x0077 }, /* R30 - Line Outputs Volume */
+ { 0x0030, 0x0030 }, /* R31 - HPOUT2 Volume */
+ { 0x00FF, 0x01FF }, /* R32 - Left OPGA Volume */
+ { 0x00FF, 0x01FF }, /* R33 - Right OPGA Volume */
+ { 0x007F, 0x007F }, /* R34 - SPKMIXL Attenuation */
+ { 0x017F, 0x017F }, /* R35 - SPKMIXR Attenuation */
+ { 0x003F, 0x003F }, /* R36 - SPKOUT Mixers */
+ { 0x003F, 0x003F }, /* R37 - ClassD */
+ { 0x00FF, 0x01FF }, /* R38 - Speaker Volume Left */
+ { 0x00FF, 0x01FF }, /* R39 - Speaker Volume Right */
+ { 0x00FF, 0x00FF }, /* R40 - Input Mixer (2) */
+ { 0x01B7, 0x01B7 }, /* R41 - Input Mixer (3) */
+ { 0x01B7, 0x01B7 }, /* R42 - Input Mixer (4) */
+ { 0x01C7, 0x01C7 }, /* R43 - Input Mixer (5) */
+ { 0x01C7, 0x01C7 }, /* R44 - Input Mixer (6) */
+ { 0x01FF, 0x01FF }, /* R45 - Output Mixer (1) */
+ { 0x01FF, 0x01FF }, /* R46 - Output Mixer (2) */
+ { 0x0FFF, 0x0FFF }, /* R47 - Output Mixer (3) */
+ { 0x0FFF, 0x0FFF }, /* R48 - Output Mixer (4) */
+ { 0x0FFF, 0x0FFF }, /* R49 - Output Mixer (5) */
+ { 0x0FFF, 0x0FFF }, /* R50 - Output Mixer (6) */
+ { 0x0038, 0x0038 }, /* R51 - HPOUT2 Mixer */
+ { 0x0077, 0x0077 }, /* R52 - Line Mixer (1) */
+ { 0x0077, 0x0077 }, /* R53 - Line Mixer (2) */
+ { 0x03FF, 0x03FF }, /* R54 - Speaker Mixer */
+ { 0x00C1, 0x00C1 }, /* R55 - Additional Control */
+ { 0x00F0, 0x00F0 }, /* R56 - AntiPOP (1) */
+ { 0x01EF, 0x01EF }, /* R57 - AntiPOP (2) */
+ { 0x00FF, 0x00FF }, /* R58 - MICBIAS */
+ { 0x000F, 0x000F }, /* R59 - LDO 1 */
+ { 0x0007, 0x0007 }, /* R60 - LDO 2 */
+ { 0x0000, 0x0000 }, /* R61 */
+ { 0x0000, 0x0000 }, /* R62 */
+ { 0x0000, 0x0000 }, /* R63 */
+ { 0x0000, 0x0000 }, /* R64 */
+ { 0x0000, 0x0000 }, /* R65 */
+ { 0x0000, 0x0000 }, /* R66 */
+ { 0x0000, 0x0000 }, /* R67 */
+ { 0x0000, 0x0000 }, /* R68 */
+ { 0x0000, 0x0000 }, /* R69 */
+ { 0x0000, 0x0000 }, /* R70 */
+ { 0x0000, 0x0000 }, /* R71 */
+ { 0x0000, 0x0000 }, /* R72 */
+ { 0x0000, 0x0000 }, /* R73 */
+ { 0x0000, 0x0000 }, /* R74 */
+ { 0x0000, 0x0000 }, /* R75 */
+ { 0x8000, 0x8000 }, /* R76 - Charge Pump (1) */
+ { 0x0000, 0x0000 }, /* R77 */
+ { 0x0000, 0x0000 }, /* R78 */
+ { 0x0000, 0x0000 }, /* R79 */
+ { 0x0000, 0x0000 }, /* R80 */
+ { 0x0301, 0x0301 }, /* R81 - Class W (1) */
+ { 0x0000, 0x0000 }, /* R82 */
+ { 0x0000, 0x0000 }, /* R83 */
+ { 0x333F, 0x333F }, /* R84 - DC Servo (1) */
+ { 0x0FEF, 0x0FEF }, /* R85 - DC Servo (2) */
+ { 0x0000, 0x0000 }, /* R86 */
+ { 0xFFFF, 0xFFFF }, /* R87 - DC Servo (4) */
+ { 0x0333, 0x0000 }, /* R88 - DC Servo Readback */
+ { 0x0000, 0x0000 }, /* R89 */
+ { 0x0000, 0x0000 }, /* R90 */
+ { 0x0000, 0x0000 }, /* R91 */
+ { 0x0000, 0x0000 }, /* R92 */
+ { 0x0000, 0x0000 }, /* R93 */
+ { 0x0000, 0x0000 }, /* R94 */
+ { 0x0000, 0x0000 }, /* R95 */
+ { 0x00EE, 0x00EE }, /* R96 - Analogue HP (1) */
+ { 0x0000, 0x0000 }, /* R97 */
+ { 0x0000, 0x0000 }, /* R98 */
+ { 0x0000, 0x0000 }, /* R99 */
+ { 0x0000, 0x0000 }, /* R100 */
+ { 0x0000, 0x0000 }, /* R101 */
+ { 0x0000, 0x0000 }, /* R102 */
+ { 0x0000, 0x0000 }, /* R103 */
+ { 0x0000, 0x0000 }, /* R104 */
+ { 0x0000, 0x0000 }, /* R105 */
+ { 0x0000, 0x0000 }, /* R106 */
+ { 0x0000, 0x0000 }, /* R107 */
+ { 0x0000, 0x0000 }, /* R108 */
+ { 0x0000, 0x0000 }, /* R109 */
+ { 0x0000, 0x0000 }, /* R110 */
+ { 0x0000, 0x0000 }, /* R111 */
+ { 0x0000, 0x0000 }, /* R112 */
+ { 0x0000, 0x0000 }, /* R113 */
+ { 0x0000, 0x0000 }, /* R114 */
+ { 0x0000, 0x0000 }, /* R115 */
+ { 0x0000, 0x0000 }, /* R116 */
+ { 0x0000, 0x0000 }, /* R117 */
+ { 0x0000, 0x0000 }, /* R118 */
+ { 0x0000, 0x0000 }, /* R119 */
+ { 0x0000, 0x0000 }, /* R120 */
+ { 0x0000, 0x0000 }, /* R121 */
+ { 0x0000, 0x0000 }, /* R122 */
+ { 0x0000, 0x0000 }, /* R123 */
+ { 0x0000, 0x0000 }, /* R124 */
+ { 0x0000, 0x0000 }, /* R125 */
+ { 0x0000, 0x0000 }, /* R126 */
+ { 0x0000, 0x0000 }, /* R127 */
+ { 0x0000, 0x0000 }, /* R128 */
+ { 0x0000, 0x0000 }, /* R129 */
+ { 0x0000, 0x0000 }, /* R130 */
+ { 0x0000, 0x0000 }, /* R131 */
+ { 0x0000, 0x0000 }, /* R132 */
+ { 0x0000, 0x0000 }, /* R133 */
+ { 0x0000, 0x0000 }, /* R134 */
+ { 0x0000, 0x0000 }, /* R135 */
+ { 0x0000, 0x0000 }, /* R136 */
+ { 0x0000, 0x0000 }, /* R137 */
+ { 0x0000, 0x0000 }, /* R138 */
+ { 0x0000, 0x0000 }, /* R139 */
+ { 0x0000, 0x0000 }, /* R140 */
+ { 0x0000, 0x0000 }, /* R141 */
+ { 0x0000, 0x0000 }, /* R142 */
+ { 0x0000, 0x0000 }, /* R143 */
+ { 0x0000, 0x0000 }, /* R144 */
+ { 0x0000, 0x0000 }, /* R145 */
+ { 0x0000, 0x0000 }, /* R146 */
+ { 0x0000, 0x0000 }, /* R147 */
+ { 0x0000, 0x0000 }, /* R148 */
+ { 0x0000, 0x0000 }, /* R149 */
+ { 0x0000, 0x0000 }, /* R150 */
+ { 0x0000, 0x0000 }, /* R151 */
+ { 0x0000, 0x0000 }, /* R152 */
+ { 0x0000, 0x0000 }, /* R153 */
+ { 0x0000, 0x0000 }, /* R154 */
+ { 0x0000, 0x0000 }, /* R155 */
+ { 0x0000, 0x0000 }, /* R156 */
+ { 0x0000, 0x0000 }, /* R157 */
+ { 0x0000, 0x0000 }, /* R158 */
+ { 0x0000, 0x0000 }, /* R159 */
+ { 0x0000, 0x0000 }, /* R160 */
+ { 0x0000, 0x0000 }, /* R161 */
+ { 0x0000, 0x0000 }, /* R162 */
+ { 0x0000, 0x0000 }, /* R163 */
+ { 0x0000, 0x0000 }, /* R164 */
+ { 0x0000, 0x0000 }, /* R165 */
+ { 0x0000, 0x0000 }, /* R166 */
+ { 0x0000, 0x0000 }, /* R167 */
+ { 0x0000, 0x0000 }, /* R168 */
+ { 0x0000, 0x0000 }, /* R169 */
+ { 0x0000, 0x0000 }, /* R170 */
+ { 0x0000, 0x0000 }, /* R171 */
+ { 0x0000, 0x0000 }, /* R172 */
+ { 0x0000, 0x0000 }, /* R173 */
+ { 0x0000, 0x0000 }, /* R174 */
+ { 0x0000, 0x0000 }, /* R175 */
+ { 0x0000, 0x0000 }, /* R176 */
+ { 0x0000, 0x0000 }, /* R177 */
+ { 0x0000, 0x0000 }, /* R178 */
+ { 0x0000, 0x0000 }, /* R179 */
+ { 0x0000, 0x0000 }, /* R180 */
+ { 0x0000, 0x0000 }, /* R181 */
+ { 0x0000, 0x0000 }, /* R182 */
+ { 0x0000, 0x0000 }, /* R183 */
+ { 0x0000, 0x0000 }, /* R184 */
+ { 0x0000, 0x0000 }, /* R185 */
+ { 0x0000, 0x0000 }, /* R186 */
+ { 0x0000, 0x0000 }, /* R187 */
+ { 0x0000, 0x0000 }, /* R188 */
+ { 0x0000, 0x0000 }, /* R189 */
+ { 0x0000, 0x0000 }, /* R190 */
+ { 0x0000, 0x0000 }, /* R191 */
+ { 0x0000, 0x0000 }, /* R192 */
+ { 0x0000, 0x0000 }, /* R193 */
+ { 0x0000, 0x0000 }, /* R194 */
+ { 0x0000, 0x0000 }, /* R195 */
+ { 0x0000, 0x0000 }, /* R196 */
+ { 0x0000, 0x0000 }, /* R197 */
+ { 0x0000, 0x0000 }, /* R198 */
+ { 0x0000, 0x0000 }, /* R199 */
+ { 0x0000, 0x0000 }, /* R200 */
+ { 0x0000, 0x0000 }, /* R201 */
+ { 0x0000, 0x0000 }, /* R202 */
+ { 0x0000, 0x0000 }, /* R203 */
+ { 0x0000, 0x0000 }, /* R204 */
+ { 0x0000, 0x0000 }, /* R205 */
+ { 0x0000, 0x0000 }, /* R206 */
+ { 0x0000, 0x0000 }, /* R207 */
+ { 0x0000, 0x0000 }, /* R208 */
+ { 0x0000, 0x0000 }, /* R209 */
+ { 0x0000, 0x0000 }, /* R210 */
+ { 0x0000, 0x0000 }, /* R211 */
+ { 0x0000, 0x0000 }, /* R212 */
+ { 0x0000, 0x0000 }, /* R213 */
+ { 0x0000, 0x0000 }, /* R214 */
+ { 0x0000, 0x0000 }, /* R215 */
+ { 0x0000, 0x0000 }, /* R216 */
+ { 0x0000, 0x0000 }, /* R217 */
+ { 0x0000, 0x0000 }, /* R218 */
+ { 0x0000, 0x0000 }, /* R219 */
+ { 0x0000, 0x0000 }, /* R220 */
+ { 0x0000, 0x0000 }, /* R221 */
+ { 0x0000, 0x0000 }, /* R222 */
+ { 0x0000, 0x0000 }, /* R223 */
+ { 0x0000, 0x0000 }, /* R224 */
+ { 0x0000, 0x0000 }, /* R225 */
+ { 0x0000, 0x0000 }, /* R226 */
+ { 0x0000, 0x0000 }, /* R227 */
+ { 0x0000, 0x0000 }, /* R228 */
+ { 0x0000, 0x0000 }, /* R229 */
+ { 0x0000, 0x0000 }, /* R230 */
+ { 0x0000, 0x0000 }, /* R231 */
+ { 0x0000, 0x0000 }, /* R232 */
+ { 0x0000, 0x0000 }, /* R233 */
+ { 0x0000, 0x0000 }, /* R234 */
+ { 0x0000, 0x0000 }, /* R235 */
+ { 0x0000, 0x0000 }, /* R236 */
+ { 0x0000, 0x0000 }, /* R237 */
+ { 0x0000, 0x0000 }, /* R238 */
+ { 0x0000, 0x0000 }, /* R239 */
+ { 0x0000, 0x0000 }, /* R240 */
+ { 0x0000, 0x0000 }, /* R241 */
+ { 0x0000, 0x0000 }, /* R242 */
+ { 0x0000, 0x0000 }, /* R243 */
+ { 0x0000, 0x0000 }, /* R244 */
+ { 0x0000, 0x0000 }, /* R245 */
+ { 0x0000, 0x0000 }, /* R246 */
+ { 0x0000, 0x0000 }, /* R247 */
+ { 0x0000, 0x0000 }, /* R248 */
+ { 0x0000, 0x0000 }, /* R249 */
+ { 0x0000, 0x0000 }, /* R250 */
+ { 0x0000, 0x0000 }, /* R251 */
+ { 0x0000, 0x0000 }, /* R252 */
+ { 0x0000, 0x0000 }, /* R253 */
+ { 0x0000, 0x0000 }, /* R254 */
+ { 0x0000, 0x0000 }, /* R255 */
+ { 0x000F, 0x0000 }, /* R256 - Chip Revision */
+ { 0x0074, 0x0074 }, /* R257 - Control Interface */
+ { 0x0000, 0x0000 }, /* R258 */
+ { 0x0000, 0x0000 }, /* R259 */
+ { 0x0000, 0x0000 }, /* R260 */
+ { 0x0000, 0x0000 }, /* R261 */
+ { 0x0000, 0x0000 }, /* R262 */
+ { 0x0000, 0x0000 }, /* R263 */
+ { 0x0000, 0x0000 }, /* R264 */
+ { 0x0000, 0x0000 }, /* R265 */
+ { 0x0000, 0x0000 }, /* R266 */
+ { 0x0000, 0x0000 }, /* R267 */
+ { 0x0000, 0x0000 }, /* R268 */
+ { 0x0000, 0x0000 }, /* R269 */
+ { 0x0000, 0x0000 }, /* R270 */
+ { 0x0000, 0x0000 }, /* R271 */
+ { 0x807F, 0x837F }, /* R272 - Write Sequencer Ctrl (1) */
+ { 0x017F, 0x0000 }, /* R273 - Write Sequencer Ctrl (2) */
+ { 0x0000, 0x0000 }, /* R274 */
+ { 0x0000, 0x0000 }, /* R275 */
+ { 0x0000, 0x0000 }, /* R276 */
+ { 0x0000, 0x0000 }, /* R277 */
+ { 0x0000, 0x0000 }, /* R278 */
+ { 0x0000, 0x0000 }, /* R279 */
+ { 0x0000, 0x0000 }, /* R280 */
+ { 0x0000, 0x0000 }, /* R281 */
+ { 0x0000, 0x0000 }, /* R282 */
+ { 0x0000, 0x0000 }, /* R283 */
+ { 0x0000, 0x0000 }, /* R284 */
+ { 0x0000, 0x0000 }, /* R285 */
+ { 0x0000, 0x0000 }, /* R286 */
+ { 0x0000, 0x0000 }, /* R287 */
+ { 0x0000, 0x0000 }, /* R288 */
+ { 0x0000, 0x0000 }, /* R289 */
+ { 0x0000, 0x0000 }, /* R290 */
+ { 0x0000, 0x0000 }, /* R291 */
+ { 0x0000, 0x0000 }, /* R292 */
+ { 0x0000, 0x0000 }, /* R293 */
+ { 0x0000, 0x0000 }, /* R294 */
+ { 0x0000, 0x0000 }, /* R295 */
+ { 0x0000, 0x0000 }, /* R296 */
+ { 0x0000, 0x0000 }, /* R297 */
+ { 0x0000, 0x0000 }, /* R298 */
+ { 0x0000, 0x0000 }, /* R299 */
+ { 0x0000, 0x0000 }, /* R300 */
+ { 0x0000, 0x0000 }, /* R301 */
+ { 0x0000, 0x0000 }, /* R302 */
+ { 0x0000, 0x0000 }, /* R303 */
+ { 0x0000, 0x0000 }, /* R304 */
+ { 0x0000, 0x0000 }, /* R305 */
+ { 0x0000, 0x0000 }, /* R306 */
+ { 0x0000, 0x0000 }, /* R307 */
+ { 0x0000, 0x0000 }, /* R308 */
+ { 0x0000, 0x0000 }, /* R309 */
+ { 0x0000, 0x0000 }, /* R310 */
+ { 0x0000, 0x0000 }, /* R311 */
+ { 0x0000, 0x0000 }, /* R312 */
+ { 0x0000, 0x0000 }, /* R313 */
+ { 0x0000, 0x0000 }, /* R314 */
+ { 0x0000, 0x0000 }, /* R315 */
+ { 0x0000, 0x0000 }, /* R316 */
+ { 0x0000, 0x0000 }, /* R317 */
+ { 0x0000, 0x0000 }, /* R318 */
+ { 0x0000, 0x0000 }, /* R319 */
+ { 0x0000, 0x0000 }, /* R320 */
+ { 0x0000, 0x0000 }, /* R321 */
+ { 0x0000, 0x0000 }, /* R322 */
+ { 0x0000, 0x0000 }, /* R323 */
+ { 0x0000, 0x0000 }, /* R324 */
+ { 0x0000, 0x0000 }, /* R325 */
+ { 0x0000, 0x0000 }, /* R326 */
+ { 0x0000, 0x0000 }, /* R327 */
+ { 0x0000, 0x0000 }, /* R328 */
+ { 0x0000, 0x0000 }, /* R329 */
+ { 0x0000, 0x0000 }, /* R330 */
+ { 0x0000, 0x0000 }, /* R331 */
+ { 0x0000, 0x0000 }, /* R332 */
+ { 0x0000, 0x0000 }, /* R333 */
+ { 0x0000, 0x0000 }, /* R334 */
+ { 0x0000, 0x0000 }, /* R335 */
+ { 0x0000, 0x0000 }, /* R336 */
+ { 0x0000, 0x0000 }, /* R337 */
+ { 0x0000, 0x0000 }, /* R338 */
+ { 0x0000, 0x0000 }, /* R339 */
+ { 0x0000, 0x0000 }, /* R340 */
+ { 0x0000, 0x0000 }, /* R341 */
+ { 0x0000, 0x0000 }, /* R342 */
+ { 0x0000, 0x0000 }, /* R343 */
+ { 0x0000, 0x0000 }, /* R344 */
+ { 0x0000, 0x0000 }, /* R345 */
+ { 0x0000, 0x0000 }, /* R346 */
+ { 0x0000, 0x0000 }, /* R347 */
+ { 0x0000, 0x0000 }, /* R348 */
+ { 0x0000, 0x0000 }, /* R349 */
+ { 0x0000, 0x0000 }, /* R350 */
+ { 0x0000, 0x0000 }, /* R351 */
+ { 0x0000, 0x0000 }, /* R352 */
+ { 0x0000, 0x0000 }, /* R353 */
+ { 0x0000, 0x0000 }, /* R354 */
+ { 0x0000, 0x0000 }, /* R355 */
+ { 0x0000, 0x0000 }, /* R356 */
+ { 0x0000, 0x0000 }, /* R357 */
+ { 0x0000, 0x0000 }, /* R358 */
+ { 0x0000, 0x0000 }, /* R359 */
+ { 0x0000, 0x0000 }, /* R360 */
+ { 0x0000, 0x0000 }, /* R361 */
+ { 0x0000, 0x0000 }, /* R362 */
+ { 0x0000, 0x0000 }, /* R363 */
+ { 0x0000, 0x0000 }, /* R364 */
+ { 0x0000, 0x0000 }, /* R365 */
+ { 0x0000, 0x0000 }, /* R366 */
+ { 0x0000, 0x0000 }, /* R367 */
+ { 0x0000, 0x0000 }, /* R368 */
+ { 0x0000, 0x0000 }, /* R369 */
+ { 0x0000, 0x0000 }, /* R370 */
+ { 0x0000, 0x0000 }, /* R371 */
+ { 0x0000, 0x0000 }, /* R372 */
+ { 0x0000, 0x0000 }, /* R373 */
+ { 0x0000, 0x0000 }, /* R374 */
+ { 0x0000, 0x0000 }, /* R375 */
+ { 0x0000, 0x0000 }, /* R376 */
+ { 0x0000, 0x0000 }, /* R377 */
+ { 0x0000, 0x0000 }, /* R378 */
+ { 0x0000, 0x0000 }, /* R379 */
+ { 0x0000, 0x0000 }, /* R380 */
+ { 0x0000, 0x0000 }, /* R381 */
+ { 0x0000, 0x0000 }, /* R382 */
+ { 0x0000, 0x0000 }, /* R383 */
+ { 0x0000, 0x0000 }, /* R384 */
+ { 0x0000, 0x0000 }, /* R385 */
+ { 0x0000, 0x0000 }, /* R386 */
+ { 0x0000, 0x0000 }, /* R387 */
+ { 0x0000, 0x0000 }, /* R388 */
+ { 0x0000, 0x0000 }, /* R389 */
+ { 0x0000, 0x0000 }, /* R390 */
+ { 0x0000, 0x0000 }, /* R391 */
+ { 0x0000, 0x0000 }, /* R392 */
+ { 0x0000, 0x0000 }, /* R393 */
+ { 0x0000, 0x0000 }, /* R394 */
+ { 0x0000, 0x0000 }, /* R395 */
+ { 0x0000, 0x0000 }, /* R396 */
+ { 0x0000, 0x0000 }, /* R397 */
+ { 0x0000, 0x0000 }, /* R398 */
+ { 0x0000, 0x0000 }, /* R399 */
+ { 0x0000, 0x0000 }, /* R400 */
+ { 0x0000, 0x0000 }, /* R401 */
+ { 0x0000, 0x0000 }, /* R402 */
+ { 0x0000, 0x0000 }, /* R403 */
+ { 0x0000, 0x0000 }, /* R404 */
+ { 0x0000, 0x0000 }, /* R405 */
+ { 0x0000, 0x0000 }, /* R406 */
+ { 0x0000, 0x0000 }, /* R407 */
+ { 0x0000, 0x0000 }, /* R408 */
+ { 0x0000, 0x0000 }, /* R409 */
+ { 0x0000, 0x0000 }, /* R410 */
+ { 0x0000, 0x0000 }, /* R411 */
+ { 0x0000, 0x0000 }, /* R412 */
+ { 0x0000, 0x0000 }, /* R413 */
+ { 0x0000, 0x0000 }, /* R414 */
+ { 0x0000, 0x0000 }, /* R415 */
+ { 0x0000, 0x0000 }, /* R416 */
+ { 0x0000, 0x0000 }, /* R417 */
+ { 0x0000, 0x0000 }, /* R418 */
+ { 0x0000, 0x0000 }, /* R419 */
+ { 0x0000, 0x0000 }, /* R420 */
+ { 0x0000, 0x0000 }, /* R421 */
+ { 0x0000, 0x0000 }, /* R422 */
+ { 0x0000, 0x0000 }, /* R423 */
+ { 0x0000, 0x0000 }, /* R424 */
+ { 0x0000, 0x0000 }, /* R425 */
+ { 0x0000, 0x0000 }, /* R426 */
+ { 0x0000, 0x0000 }, /* R427 */
+ { 0x0000, 0x0000 }, /* R428 */
+ { 0x0000, 0x0000 }, /* R429 */
+ { 0x0000, 0x0000 }, /* R430 */
+ { 0x0000, 0x0000 }, /* R431 */
+ { 0x0000, 0x0000 }, /* R432 */
+ { 0x0000, 0x0000 }, /* R433 */
+ { 0x0000, 0x0000 }, /* R434 */
+ { 0x0000, 0x0000 }, /* R435 */
+ { 0x0000, 0x0000 }, /* R436 */
+ { 0x0000, 0x0000 }, /* R437 */
+ { 0x0000, 0x0000 }, /* R438 */
+ { 0x0000, 0x0000 }, /* R439 */
+ { 0x0000, 0x0000 }, /* R440 */
+ { 0x0000, 0x0000 }, /* R441 */
+ { 0x0000, 0x0000 }, /* R442 */
+ { 0x0000, 0x0000 }, /* R443 */
+ { 0x0000, 0x0000 }, /* R444 */
+ { 0x0000, 0x0000 }, /* R445 */
+ { 0x0000, 0x0000 }, /* R446 */
+ { 0x0000, 0x0000 }, /* R447 */
+ { 0x0000, 0x0000 }, /* R448 */
+ { 0x0000, 0x0000 }, /* R449 */
+ { 0x0000, 0x0000 }, /* R450 */
+ { 0x0000, 0x0000 }, /* R451 */
+ { 0x0000, 0x0000 }, /* R452 */
+ { 0x0000, 0x0000 }, /* R453 */
+ { 0x0000, 0x0000 }, /* R454 */
+ { 0x0000, 0x0000 }, /* R455 */
+ { 0x0000, 0x0000 }, /* R456 */
+ { 0x0000, 0x0000 }, /* R457 */
+ { 0x0000, 0x0000 }, /* R458 */
+ { 0x0000, 0x0000 }, /* R459 */
+ { 0x0000, 0x0000 }, /* R460 */
+ { 0x0000, 0x0000 }, /* R461 */
+ { 0x0000, 0x0000 }, /* R462 */
+ { 0x0000, 0x0000 }, /* R463 */
+ { 0x0000, 0x0000 }, /* R464 */
+ { 0x0000, 0x0000 }, /* R465 */
+ { 0x0000, 0x0000 }, /* R466 */
+ { 0x0000, 0x0000 }, /* R467 */
+ { 0x0000, 0x0000 }, /* R468 */
+ { 0x0000, 0x0000 }, /* R469 */
+ { 0x0000, 0x0000 }, /* R470 */
+ { 0x0000, 0x0000 }, /* R471 */
+ { 0x0000, 0x0000 }, /* R472 */
+ { 0x0000, 0x0000 }, /* R473 */
+ { 0x0000, 0x0000 }, /* R474 */
+ { 0x0000, 0x0000 }, /* R475 */
+ { 0x0000, 0x0000 }, /* R476 */
+ { 0x0000, 0x0000 }, /* R477 */
+ { 0x0000, 0x0000 }, /* R478 */
+ { 0x0000, 0x0000 }, /* R479 */
+ { 0x0000, 0x0000 }, /* R480 */
+ { 0x0000, 0x0000 }, /* R481 */
+ { 0x0000, 0x0000 }, /* R482 */
+ { 0x0000, 0x0000 }, /* R483 */
+ { 0x0000, 0x0000 }, /* R484 */
+ { 0x0000, 0x0000 }, /* R485 */
+ { 0x0000, 0x0000 }, /* R486 */
+ { 0x0000, 0x0000 }, /* R487 */
+ { 0x0000, 0x0000 }, /* R488 */
+ { 0x0000, 0x0000 }, /* R489 */
+ { 0x0000, 0x0000 }, /* R490 */
+ { 0x0000, 0x0000 }, /* R491 */
+ { 0x0000, 0x0000 }, /* R492 */
+ { 0x0000, 0x0000 }, /* R493 */
+ { 0x0000, 0x0000 }, /* R494 */
+ { 0x0000, 0x0000 }, /* R495 */
+ { 0x0000, 0x0000 }, /* R496 */
+ { 0x0000, 0x0000 }, /* R497 */
+ { 0x0000, 0x0000 }, /* R498 */
+ { 0x0000, 0x0000 }, /* R499 */
+ { 0x0000, 0x0000 }, /* R500 */
+ { 0x0000, 0x0000 }, /* R501 */
+ { 0x0000, 0x0000 }, /* R502 */
+ { 0x0000, 0x0000 }, /* R503 */
+ { 0x0000, 0x0000 }, /* R504 */
+ { 0x0000, 0x0000 }, /* R505 */
+ { 0x0000, 0x0000 }, /* R506 */
+ { 0x0000, 0x0000 }, /* R507 */
+ { 0x0000, 0x0000 }, /* R508 */
+ { 0x0000, 0x0000 }, /* R509 */
+ { 0x0000, 0x0000 }, /* R510 */
+ { 0x0000, 0x0000 }, /* R511 */
+ { 0x001F, 0x001F }, /* R512 - AIF1 Clocking (1) */
+ { 0x003F, 0x003F }, /* R513 - AIF1 Clocking (2) */
+ { 0x0000, 0x0000 }, /* R514 */
+ { 0x0000, 0x0000 }, /* R515 */
+ { 0x001F, 0x001F }, /* R516 - AIF2 Clocking (1) */
+ { 0x003F, 0x003F }, /* R517 - AIF2 Clocking (2) */
+ { 0x0000, 0x0000 }, /* R518 */
+ { 0x0000, 0x0000 }, /* R519 */
+ { 0x001F, 0x001F }, /* R520 - Clocking (1) */
+ { 0x0777, 0x0777 }, /* R521 - Clocking (2) */
+ { 0x0000, 0x0000 }, /* R522 */
+ { 0x0000, 0x0000 }, /* R523 */
+ { 0x0000, 0x0000 }, /* R524 */
+ { 0x0000, 0x0000 }, /* R525 */
+ { 0x0000, 0x0000 }, /* R526 */
+ { 0x0000, 0x0000 }, /* R527 */
+ { 0x00FF, 0x00FF }, /* R528 - AIF1 Rate */
+ { 0x00FF, 0x00FF }, /* R529 - AIF2 Rate */
+ { 0x000F, 0x0000 }, /* R530 - Rate Status */
+ { 0x0000, 0x0000 }, /* R531 */
+ { 0x0000, 0x0000 }, /* R532 */
+ { 0x0000, 0x0000 }, /* R533 */
+ { 0x0000, 0x0000 }, /* R534 */
+ { 0x0000, 0x0000 }, /* R535 */
+ { 0x0000, 0x0000 }, /* R536 */
+ { 0x0000, 0x0000 }, /* R537 */
+ { 0x0000, 0x0000 }, /* R538 */
+ { 0x0000, 0x0000 }, /* R539 */
+ { 0x0000, 0x0000 }, /* R540 */
+ { 0x0000, 0x0000 }, /* R541 */
+ { 0x0000, 0x0000 }, /* R542 */
+ { 0x0000, 0x0000 }, /* R543 */
+ { 0x0007, 0x0007 }, /* R544 - FLL1 Control (1) */
+ { 0x3F77, 0x3F77 }, /* R545 - FLL1 Control (2) */
+ { 0xFFFF, 0xFFFF }, /* R546 - FLL1 Control (3) */
+ { 0x7FEF, 0x7FEF }, /* R547 - FLL1 Control (4) */
+ { 0x1FDB, 0x1FDB }, /* R548 - FLL1 Control (5) */
+ { 0x0000, 0x0000 }, /* R549 */
+ { 0x0000, 0x0000 }, /* R550 */
+ { 0x0000, 0x0000 }, /* R551 */
+ { 0x0000, 0x0000 }, /* R552 */
+ { 0x0000, 0x0000 }, /* R553 */
+ { 0x0000, 0x0000 }, /* R554 */
+ { 0x0000, 0x0000 }, /* R555 */
+ { 0x0000, 0x0000 }, /* R556 */
+ { 0x0000, 0x0000 }, /* R557 */
+ { 0x0000, 0x0000 }, /* R558 */
+ { 0x0000, 0x0000 }, /* R559 */
+ { 0x0000, 0x0000 }, /* R560 */
+ { 0x0000, 0x0000 }, /* R561 */
+ { 0x0000, 0x0000 }, /* R562 */
+ { 0x0000, 0x0000 }, /* R563 */
+ { 0x0000, 0x0000 }, /* R564 */
+ { 0x0000, 0x0000 }, /* R565 */
+ { 0x0000, 0x0000 }, /* R566 */
+ { 0x0000, 0x0000 }, /* R567 */
+ { 0x0000, 0x0000 }, /* R568 */
+ { 0x0000, 0x0000 }, /* R569 */
+ { 0x0000, 0x0000 }, /* R570 */
+ { 0x0000, 0x0000 }, /* R571 */
+ { 0x0000, 0x0000 }, /* R572 */
+ { 0x0000, 0x0000 }, /* R573 */
+ { 0x0000, 0x0000 }, /* R574 */
+ { 0x0000, 0x0000 }, /* R575 */
+ { 0x0007, 0x0007 }, /* R576 - FLL2 Control (1) */
+ { 0x3F77, 0x3F77 }, /* R577 - FLL2 Control (2) */
+ { 0xFFFF, 0xFFFF }, /* R578 - FLL2 Control (3) */
+ { 0x7FEF, 0x7FEF }, /* R579 - FLL2 Control (4) */
+ { 0x1FDB, 0x1FDB }, /* R580 - FLL2 Control (5) */
+ { 0x0000, 0x0000 }, /* R581 */
+ { 0x0000, 0x0000 }, /* R582 */
+ { 0x0000, 0x0000 }, /* R583 */
+ { 0x0000, 0x0000 }, /* R584 */
+ { 0x0000, 0x0000 }, /* R585 */
+ { 0x0000, 0x0000 }, /* R586 */
+ { 0x0000, 0x0000 }, /* R587 */
+ { 0x0000, 0x0000 }, /* R588 */
+ { 0x0000, 0x0000 }, /* R589 */
+ { 0x0000, 0x0000 }, /* R590 */
+ { 0x0000, 0x0000 }, /* R591 */
+ { 0x0000, 0x0000 }, /* R592 */
+ { 0x0000, 0x0000 }, /* R593 */
+ { 0x0000, 0x0000 }, /* R594 */
+ { 0x0000, 0x0000 }, /* R595 */
+ { 0x0000, 0x0000 }, /* R596 */
+ { 0x0000, 0x0000 }, /* R597 */
+ { 0x0000, 0x0000 }, /* R598 */
+ { 0x0000, 0x0000 }, /* R599 */
+ { 0x0000, 0x0000 }, /* R600 */
+ { 0x0000, 0x0000 }, /* R601 */
+ { 0x0000, 0x0000 }, /* R602 */
+ { 0x0000, 0x0000 }, /* R603 */
+ { 0x0000, 0x0000 }, /* R604 */
+ { 0x0000, 0x0000 }, /* R605 */
+ { 0x0000, 0x0000 }, /* R606 */
+ { 0x0000, 0x0000 }, /* R607 */
+ { 0x0000, 0x0000 }, /* R608 */
+ { 0x0000, 0x0000 }, /* R609 */
+ { 0x0000, 0x0000 }, /* R610 */
+ { 0x0000, 0x0000 }, /* R611 */
+ { 0x0000, 0x0000 }, /* R612 */
+ { 0x0000, 0x0000 }, /* R613 */
+ { 0x0000, 0x0000 }, /* R614 */
+ { 0x0000, 0x0000 }, /* R615 */
+ { 0x0000, 0x0000 }, /* R616 */
+ { 0x0000, 0x0000 }, /* R617 */
+ { 0x0000, 0x0000 }, /* R618 */
+ { 0x0000, 0x0000 }, /* R619 */
+ { 0x0000, 0x0000 }, /* R620 */
+ { 0x0000, 0x0000 }, /* R621 */
+ { 0x0000, 0x0000 }, /* R622 */
+ { 0x0000, 0x0000 }, /* R623 */
+ { 0x0000, 0x0000 }, /* R624 */
+ { 0x0000, 0x0000 }, /* R625 */
+ { 0x0000, 0x0000 }, /* R626 */
+ { 0x0000, 0x0000 }, /* R627 */
+ { 0x0000, 0x0000 }, /* R628 */
+ { 0x0000, 0x0000 }, /* R629 */
+ { 0x0000, 0x0000 }, /* R630 */
+ { 0x0000, 0x0000 }, /* R631 */
+ { 0x0000, 0x0000 }, /* R632 */
+ { 0x0000, 0x0000 }, /* R633 */
+ { 0x0000, 0x0000 }, /* R634 */
+ { 0x0000, 0x0000 }, /* R635 */
+ { 0x0000, 0x0000 }, /* R636 */
+ { 0x0000, 0x0000 }, /* R637 */
+ { 0x0000, 0x0000 }, /* R638 */
+ { 0x0000, 0x0000 }, /* R639 */
+ { 0x0000, 0x0000 }, /* R640 */
+ { 0x0000, 0x0000 }, /* R641 */
+ { 0x0000, 0x0000 }, /* R642 */
+ { 0x0000, 0x0000 }, /* R643 */
+ { 0x0000, 0x0000 }, /* R644 */
+ { 0x0000, 0x0000 }, /* R645 */
+ { 0x0000, 0x0000 }, /* R646 */
+ { 0x0000, 0x0000 }, /* R647 */
+ { 0x0000, 0x0000 }, /* R648 */
+ { 0x0000, 0x0000 }, /* R649 */
+ { 0x0000, 0x0000 }, /* R650 */
+ { 0x0000, 0x0000 }, /* R651 */
+ { 0x0000, 0x0000 }, /* R652 */
+ { 0x0000, 0x0000 }, /* R653 */
+ { 0x0000, 0x0000 }, /* R654 */
+ { 0x0000, 0x0000 }, /* R655 */
+ { 0x0000, 0x0000 }, /* R656 */
+ { 0x0000, 0x0000 }, /* R657 */
+ { 0x0000, 0x0000 }, /* R658 */
+ { 0x0000, 0x0000 }, /* R659 */
+ { 0x0000, 0x0000 }, /* R660 */
+ { 0x0000, 0x0000 }, /* R661 */
+ { 0x0000, 0x0000 }, /* R662 */
+ { 0x0000, 0x0000 }, /* R663 */
+ { 0x0000, 0x0000 }, /* R664 */
+ { 0x0000, 0x0000 }, /* R665 */
+ { 0x0000, 0x0000 }, /* R666 */
+ { 0x0000, 0x0000 }, /* R667 */
+ { 0x0000, 0x0000 }, /* R668 */
+ { 0x0000, 0x0000 }, /* R669 */
+ { 0x0000, 0x0000 }, /* R670 */
+ { 0x0000, 0x0000 }, /* R671 */
+ { 0x0000, 0x0000 }, /* R672 */
+ { 0x0000, 0x0000 }, /* R673 */
+ { 0x0000, 0x0000 }, /* R674 */
+ { 0x0000, 0x0000 }, /* R675 */
+ { 0x0000, 0x0000 }, /* R676 */
+ { 0x0000, 0x0000 }, /* R677 */
+ { 0x0000, 0x0000 }, /* R678 */
+ { 0x0000, 0x0000 }, /* R679 */
+ { 0x0000, 0x0000 }, /* R680 */
+ { 0x0000, 0x0000 }, /* R681 */
+ { 0x0000, 0x0000 }, /* R682 */
+ { 0x0000, 0x0000 }, /* R683 */
+ { 0x0000, 0x0000 }, /* R684 */
+ { 0x0000, 0x0000 }, /* R685 */
+ { 0x0000, 0x0000 }, /* R686 */
+ { 0x0000, 0x0000 }, /* R687 */
+ { 0x0000, 0x0000 }, /* R688 */
+ { 0x0000, 0x0000 }, /* R689 */
+ { 0x0000, 0x0000 }, /* R690 */
+ { 0x0000, 0x0000 }, /* R691 */
+ { 0x0000, 0x0000 }, /* R692 */
+ { 0x0000, 0x0000 }, /* R693 */
+ { 0x0000, 0x0000 }, /* R694 */
+ { 0x0000, 0x0000 }, /* R695 */
+ { 0x0000, 0x0000 }, /* R696 */
+ { 0x0000, 0x0000 }, /* R697 */
+ { 0x0000, 0x0000 }, /* R698 */
+ { 0x0000, 0x0000 }, /* R699 */
+ { 0x0000, 0x0000 }, /* R700 */
+ { 0x0000, 0x0000 }, /* R701 */
+ { 0x0000, 0x0000 }, /* R702 */
+ { 0x0000, 0x0000 }, /* R703 */
+ { 0x0000, 0x0000 }, /* R704 */
+ { 0x0000, 0x0000 }, /* R705 */
+ { 0x0000, 0x0000 }, /* R706 */
+ { 0x0000, 0x0000 }, /* R707 */
+ { 0x0000, 0x0000 }, /* R708 */
+ { 0x0000, 0x0000 }, /* R709 */
+ { 0x0000, 0x0000 }, /* R710 */
+ { 0x0000, 0x0000 }, /* R711 */
+ { 0x0000, 0x0000 }, /* R712 */
+ { 0x0000, 0x0000 }, /* R713 */
+ { 0x0000, 0x0000 }, /* R714 */
+ { 0x0000, 0x0000 }, /* R715 */
+ { 0x0000, 0x0000 }, /* R716 */
+ { 0x0000, 0x0000 }, /* R717 */
+ { 0x0000, 0x0000 }, /* R718 */
+ { 0x0000, 0x0000 }, /* R719 */
+ { 0x0000, 0x0000 }, /* R720 */
+ { 0x0000, 0x0000 }, /* R721 */
+ { 0x0000, 0x0000 }, /* R722 */
+ { 0x0000, 0x0000 }, /* R723 */
+ { 0x0000, 0x0000 }, /* R724 */
+ { 0x0000, 0x0000 }, /* R725 */
+ { 0x0000, 0x0000 }, /* R726 */
+ { 0x0000, 0x0000 }, /* R727 */
+ { 0x0000, 0x0000 }, /* R728 */
+ { 0x0000, 0x0000 }, /* R729 */
+ { 0x0000, 0x0000 }, /* R730 */
+ { 0x0000, 0x0000 }, /* R731 */
+ { 0x0000, 0x0000 }, /* R732 */
+ { 0x0000, 0x0000 }, /* R733 */
+ { 0x0000, 0x0000 }, /* R734 */
+ { 0x0000, 0x0000 }, /* R735 */
+ { 0x0000, 0x0000 }, /* R736 */
+ { 0x0000, 0x0000 }, /* R737 */
+ { 0x0000, 0x0000 }, /* R738 */
+ { 0x0000, 0x0000 }, /* R739 */
+ { 0x0000, 0x0000 }, /* R740 */
+ { 0x0000, 0x0000 }, /* R741 */
+ { 0x0000, 0x0000 }, /* R742 */
+ { 0x0000, 0x0000 }, /* R743 */
+ { 0x0000, 0x0000 }, /* R744 */
+ { 0x0000, 0x0000 }, /* R745 */
+ { 0x0000, 0x0000 }, /* R746 */
+ { 0x0000, 0x0000 }, /* R747 */
+ { 0x0000, 0x0000 }, /* R748 */
+ { 0x0000, 0x0000 }, /* R749 */
+ { 0x0000, 0x0000 }, /* R750 */
+ { 0x0000, 0x0000 }, /* R751 */
+ { 0x0000, 0x0000 }, /* R752 */
+ { 0x0000, 0x0000 }, /* R753 */
+ { 0x0000, 0x0000 }, /* R754 */
+ { 0x0000, 0x0000 }, /* R755 */
+ { 0x0000, 0x0000 }, /* R756 */
+ { 0x0000, 0x0000 }, /* R757 */
+ { 0x0000, 0x0000 }, /* R758 */
+ { 0x0000, 0x0000 }, /* R759 */
+ { 0x0000, 0x0000 }, /* R760 */
+ { 0x0000, 0x0000 }, /* R761 */
+ { 0x0000, 0x0000 }, /* R762 */
+ { 0x0000, 0x0000 }, /* R763 */
+ { 0x0000, 0x0000 }, /* R764 */
+ { 0x0000, 0x0000 }, /* R765 */
+ { 0x0000, 0x0000 }, /* R766 */
+ { 0x0000, 0x0000 }, /* R767 */
+ { 0xE1F8, 0xE1F8 }, /* R768 - AIF1 Control (1) */
+ { 0xCD1F, 0xCD1F }, /* R769 - AIF1 Control (2) */
+ { 0xF000, 0xF000 }, /* R770 - AIF1 Master/Slave */
+ { 0x01F0, 0x01F0 }, /* R771 - AIF1 BCLK */
+ { 0x0FFF, 0x0FFF }, /* R772 - AIF1ADC LRCLK */
+ { 0x0FFF, 0x0FFF }, /* R773 - AIF1DAC LRCLK */
+ { 0x0003, 0x0003 }, /* R774 - AIF1DAC Data */
+ { 0x0003, 0x0003 }, /* R775 - AIF1ADC Data */
+ { 0x0000, 0x0000 }, /* R776 */
+ { 0x0000, 0x0000 }, /* R777 */
+ { 0x0000, 0x0000 }, /* R778 */
+ { 0x0000, 0x0000 }, /* R779 */
+ { 0x0000, 0x0000 }, /* R780 */
+ { 0x0000, 0x0000 }, /* R781 */
+ { 0x0000, 0x0000 }, /* R782 */
+ { 0x0000, 0x0000 }, /* R783 */
+ { 0xF1F8, 0xF1F8 }, /* R784 - AIF2 Control (1) */
+ { 0xFD1F, 0xFD1F }, /* R785 - AIF2 Control (2) */
+ { 0xF000, 0xF000 }, /* R786 - AIF2 Master/Slave */
+ { 0x01F0, 0x01F0 }, /* R787 - AIF2 BCLK */
+ { 0x0FFF, 0x0FFF }, /* R788 - AIF2ADC LRCLK */
+ { 0x0FFF, 0x0FFF }, /* R789 - AIF2DAC LRCLK */
+ { 0x0003, 0x0003 }, /* R790 - AIF2DAC Data */
+ { 0x0003, 0x0003 }, /* R791 - AIF2ADC Data */
+ { 0x0000, 0x0000 }, /* R792 */
+ { 0x0000, 0x0000 }, /* R793 */
+ { 0x0000, 0x0000 }, /* R794 */
+ { 0x0000, 0x0000 }, /* R795 */
+ { 0x0000, 0x0000 }, /* R796 */
+ { 0x0000, 0x0000 }, /* R797 */
+ { 0x0000, 0x0000 }, /* R798 */
+ { 0x0000, 0x0000 }, /* R799 */
+ { 0x0000, 0x0000 }, /* R800 */
+ { 0x0000, 0x0000 }, /* R801 */
+ { 0x0000, 0x0000 }, /* R802 */
+ { 0x0000, 0x0000 }, /* R803 */
+ { 0x0000, 0x0000 }, /* R804 */
+ { 0x0000, 0x0000 }, /* R805 */
+ { 0x0000, 0x0000 }, /* R806 */
+ { 0x0000, 0x0000 }, /* R807 */
+ { 0x0000, 0x0000 }, /* R808 */
+ { 0x0000, 0x0000 }, /* R809 */
+ { 0x0000, 0x0000 }, /* R810 */
+ { 0x0000, 0x0000 }, /* R811 */
+ { 0x0000, 0x0000 }, /* R812 */
+ { 0x0000, 0x0000 }, /* R813 */
+ { 0x0000, 0x0000 }, /* R814 */
+ { 0x0000, 0x0000 }, /* R815 */
+ { 0x0000, 0x0000 }, /* R816 */
+ { 0x0000, 0x0000 }, /* R817 */
+ { 0x0000, 0x0000 }, /* R818 */
+ { 0x0000, 0x0000 }, /* R819 */
+ { 0x0000, 0x0000 }, /* R820 */
+ { 0x0000, 0x0000 }, /* R821 */
+ { 0x0000, 0x0000 }, /* R822 */
+ { 0x0000, 0x0000 }, /* R823 */
+ { 0x0000, 0x0000 }, /* R824 */
+ { 0x0000, 0x0000 }, /* R825 */
+ { 0x0000, 0x0000 }, /* R826 */
+ { 0x0000, 0x0000 }, /* R827 */
+ { 0x0000, 0x0000 }, /* R828 */
+ { 0x0000, 0x0000 }, /* R829 */
+ { 0x0000, 0x0000 }, /* R830 */
+ { 0x0000, 0x0000 }, /* R831 */
+ { 0x0000, 0x0000 }, /* R832 */
+ { 0x0000, 0x0000 }, /* R833 */
+ { 0x0000, 0x0000 }, /* R834 */
+ { 0x0000, 0x0000 }, /* R835 */
+ { 0x0000, 0x0000 }, /* R836 */
+ { 0x0000, 0x0000 }, /* R837 */
+ { 0x0000, 0x0000 }, /* R838 */
+ { 0x0000, 0x0000 }, /* R839 */
+ { 0x0000, 0x0000 }, /* R840 */
+ { 0x0000, 0x0000 }, /* R841 */
+ { 0x0000, 0x0000 }, /* R842 */
+ { 0x0000, 0x0000 }, /* R843 */
+ { 0x0000, 0x0000 }, /* R844 */
+ { 0x0000, 0x0000 }, /* R845 */
+ { 0x0000, 0x0000 }, /* R846 */
+ { 0x0000, 0x0000 }, /* R847 */
+ { 0x0000, 0x0000 }, /* R848 */
+ { 0x0000, 0x0000 }, /* R849 */
+ { 0x0000, 0x0000 }, /* R850 */
+ { 0x0000, 0x0000 }, /* R851 */
+ { 0x0000, 0x0000 }, /* R852 */
+ { 0x0000, 0x0000 }, /* R853 */
+ { 0x0000, 0x0000 }, /* R854 */
+ { 0x0000, 0x0000 }, /* R855 */
+ { 0x0000, 0x0000 }, /* R856 */
+ { 0x0000, 0x0000 }, /* R857 */
+ { 0x0000, 0x0000 }, /* R858 */
+ { 0x0000, 0x0000 }, /* R859 */
+ { 0x0000, 0x0000 }, /* R860 */
+ { 0x0000, 0x0000 }, /* R861 */
+ { 0x0000, 0x0000 }, /* R862 */
+ { 0x0000, 0x0000 }, /* R863 */
+ { 0x0000, 0x0000 }, /* R864 */
+ { 0x0000, 0x0000 }, /* R865 */
+ { 0x0000, 0x0000 }, /* R866 */
+ { 0x0000, 0x0000 }, /* R867 */
+ { 0x0000, 0x0000 }, /* R868 */
+ { 0x0000, 0x0000 }, /* R869 */
+ { 0x0000, 0x0000 }, /* R870 */
+ { 0x0000, 0x0000 }, /* R871 */
+ { 0x0000, 0x0000 }, /* R872 */
+ { 0x0000, 0x0000 }, /* R873 */
+ { 0x0000, 0x0000 }, /* R874 */
+ { 0x0000, 0x0000 }, /* R875 */
+ { 0x0000, 0x0000 }, /* R876 */
+ { 0x0000, 0x0000 }, /* R877 */
+ { 0x0000, 0x0000 }, /* R878 */
+ { 0x0000, 0x0000 }, /* R879 */
+ { 0x0000, 0x0000 }, /* R880 */
+ { 0x0000, 0x0000 }, /* R881 */
+ { 0x0000, 0x0000 }, /* R882 */
+ { 0x0000, 0x0000 }, /* R883 */
+ { 0x0000, 0x0000 }, /* R884 */
+ { 0x0000, 0x0000 }, /* R885 */
+ { 0x0000, 0x0000 }, /* R886 */
+ { 0x0000, 0x0000 }, /* R887 */
+ { 0x0000, 0x0000 }, /* R888 */
+ { 0x0000, 0x0000 }, /* R889 */
+ { 0x0000, 0x0000 }, /* R890 */
+ { 0x0000, 0x0000 }, /* R891 */
+ { 0x0000, 0x0000 }, /* R892 */
+ { 0x0000, 0x0000 }, /* R893 */
+ { 0x0000, 0x0000 }, /* R894 */
+ { 0x0000, 0x0000 }, /* R895 */
+ { 0x0000, 0x0000 }, /* R896 */
+ { 0x0000, 0x0000 }, /* R897 */
+ { 0x0000, 0x0000 }, /* R898 */
+ { 0x0000, 0x0000 }, /* R899 */
+ { 0x0000, 0x0000 }, /* R900 */
+ { 0x0000, 0x0000 }, /* R901 */
+ { 0x0000, 0x0000 }, /* R902 */
+ { 0x0000, 0x0000 }, /* R903 */
+ { 0x0000, 0x0000 }, /* R904 */
+ { 0x0000, 0x0000 }, /* R905 */
+ { 0x0000, 0x0000 }, /* R906 */
+ { 0x0000, 0x0000 }, /* R907 */
+ { 0x0000, 0x0000 }, /* R908 */
+ { 0x0000, 0x0000 }, /* R909 */
+ { 0x0000, 0x0000 }, /* R910 */
+ { 0x0000, 0x0000 }, /* R911 */
+ { 0x0000, 0x0000 }, /* R912 */
+ { 0x0000, 0x0000 }, /* R913 */
+ { 0x0000, 0x0000 }, /* R914 */
+ { 0x0000, 0x0000 }, /* R915 */
+ { 0x0000, 0x0000 }, /* R916 */
+ { 0x0000, 0x0000 }, /* R917 */
+ { 0x0000, 0x0000 }, /* R918 */
+ { 0x0000, 0x0000 }, /* R919 */
+ { 0x0000, 0x0000 }, /* R920 */
+ { 0x0000, 0x0000 }, /* R921 */
+ { 0x0000, 0x0000 }, /* R922 */
+ { 0x0000, 0x0000 }, /* R923 */
+ { 0x0000, 0x0000 }, /* R924 */
+ { 0x0000, 0x0000 }, /* R925 */
+ { 0x0000, 0x0000 }, /* R926 */
+ { 0x0000, 0x0000 }, /* R927 */
+ { 0x0000, 0x0000 }, /* R928 */
+ { 0x0000, 0x0000 }, /* R929 */
+ { 0x0000, 0x0000 }, /* R930 */
+ { 0x0000, 0x0000 }, /* R931 */
+ { 0x0000, 0x0000 }, /* R932 */
+ { 0x0000, 0x0000 }, /* R933 */
+ { 0x0000, 0x0000 }, /* R934 */
+ { 0x0000, 0x0000 }, /* R935 */
+ { 0x0000, 0x0000 }, /* R936 */
+ { 0x0000, 0x0000 }, /* R937 */
+ { 0x0000, 0x0000 }, /* R938 */
+ { 0x0000, 0x0000 }, /* R939 */
+ { 0x0000, 0x0000 }, /* R940 */
+ { 0x0000, 0x0000 }, /* R941 */
+ { 0x0000, 0x0000 }, /* R942 */
+ { 0x0000, 0x0000 }, /* R943 */
+ { 0x0000, 0x0000 }, /* R944 */
+ { 0x0000, 0x0000 }, /* R945 */
+ { 0x0000, 0x0000 }, /* R946 */
+ { 0x0000, 0x0000 }, /* R947 */
+ { 0x0000, 0x0000 }, /* R948 */
+ { 0x0000, 0x0000 }, /* R949 */
+ { 0x0000, 0x0000 }, /* R950 */
+ { 0x0000, 0x0000 }, /* R951 */
+ { 0x0000, 0x0000 }, /* R952 */
+ { 0x0000, 0x0000 }, /* R953 */
+ { 0x0000, 0x0000 }, /* R954 */
+ { 0x0000, 0x0000 }, /* R955 */
+ { 0x0000, 0x0000 }, /* R956 */
+ { 0x0000, 0x0000 }, /* R957 */
+ { 0x0000, 0x0000 }, /* R958 */
+ { 0x0000, 0x0000 }, /* R959 */
+ { 0x0000, 0x0000 }, /* R960 */
+ { 0x0000, 0x0000 }, /* R961 */
+ { 0x0000, 0x0000 }, /* R962 */
+ { 0x0000, 0x0000 }, /* R963 */
+ { 0x0000, 0x0000 }, /* R964 */
+ { 0x0000, 0x0000 }, /* R965 */
+ { 0x0000, 0x0000 }, /* R966 */
+ { 0x0000, 0x0000 }, /* R967 */
+ { 0x0000, 0x0000 }, /* R968 */
+ { 0x0000, 0x0000 }, /* R969 */
+ { 0x0000, 0x0000 }, /* R970 */
+ { 0x0000, 0x0000 }, /* R971 */
+ { 0x0000, 0x0000 }, /* R972 */
+ { 0x0000, 0x0000 }, /* R973 */
+ { 0x0000, 0x0000 }, /* R974 */
+ { 0x0000, 0x0000 }, /* R975 */
+ { 0x0000, 0x0000 }, /* R976 */
+ { 0x0000, 0x0000 }, /* R977 */
+ { 0x0000, 0x0000 }, /* R978 */
+ { 0x0000, 0x0000 }, /* R979 */
+ { 0x0000, 0x0000 }, /* R980 */
+ { 0x0000, 0x0000 }, /* R981 */
+ { 0x0000, 0x0000 }, /* R982 */
+ { 0x0000, 0x0000 }, /* R983 */
+ { 0x0000, 0x0000 }, /* R984 */
+ { 0x0000, 0x0000 }, /* R985 */
+ { 0x0000, 0x0000 }, /* R986 */
+ { 0x0000, 0x0000 }, /* R987 */
+ { 0x0000, 0x0000 }, /* R988 */
+ { 0x0000, 0x0000 }, /* R989 */
+ { 0x0000, 0x0000 }, /* R990 */
+ { 0x0000, 0x0000 }, /* R991 */
+ { 0x0000, 0x0000 }, /* R992 */
+ { 0x0000, 0x0000 }, /* R993 */
+ { 0x0000, 0x0000 }, /* R994 */
+ { 0x0000, 0x0000 }, /* R995 */
+ { 0x0000, 0x0000 }, /* R996 */
+ { 0x0000, 0x0000 }, /* R997 */
+ { 0x0000, 0x0000 }, /* R998 */
+ { 0x0000, 0x0000 }, /* R999 */
+ { 0x0000, 0x0000 }, /* R1000 */
+ { 0x0000, 0x0000 }, /* R1001 */
+ { 0x0000, 0x0000 }, /* R1002 */
+ { 0x0000, 0x0000 }, /* R1003 */
+ { 0x0000, 0x0000 }, /* R1004 */
+ { 0x0000, 0x0000 }, /* R1005 */
+ { 0x0000, 0x0000 }, /* R1006 */
+ { 0x0000, 0x0000 }, /* R1007 */
+ { 0x0000, 0x0000 }, /* R1008 */
+ { 0x0000, 0x0000 }, /* R1009 */
+ { 0x0000, 0x0000 }, /* R1010 */
+ { 0x0000, 0x0000 }, /* R1011 */
+ { 0x0000, 0x0000 }, /* R1012 */
+ { 0x0000, 0x0000 }, /* R1013 */
+ { 0x0000, 0x0000 }, /* R1014 */
+ { 0x0000, 0x0000 }, /* R1015 */
+ { 0x0000, 0x0000 }, /* R1016 */
+ { 0x0000, 0x0000 }, /* R1017 */
+ { 0x0000, 0x0000 }, /* R1018 */
+ { 0x0000, 0x0000 }, /* R1019 */
+ { 0x0000, 0x0000 }, /* R1020 */
+ { 0x0000, 0x0000 }, /* R1021 */
+ { 0x0000, 0x0000 }, /* R1022 */
+ { 0x0000, 0x0000 }, /* R1023 */
+ { 0x00FF, 0x01FF }, /* R1024 - AIF1 ADC1 Left Volume */
+ { 0x00FF, 0x01FF }, /* R1025 - AIF1 ADC1 Right Volume */
+ { 0x00FF, 0x01FF }, /* R1026 - AIF1 DAC1 Left Volume */
+ { 0x00FF, 0x01FF }, /* R1027 - AIF1 DAC1 Right Volume */
+ { 0x00FF, 0x01FF }, /* R1028 - AIF1 ADC2 Left Volume */
+ { 0x00FF, 0x01FF }, /* R1029 - AIF1 ADC2 Right Volume */
+ { 0x00FF, 0x01FF }, /* R1030 - AIF1 DAC2 Left Volume */
+ { 0x00FF, 0x01FF }, /* R1031 - AIF1 DAC2 Right Volume */
+ { 0x0000, 0x0000 }, /* R1032 */
+ { 0x0000, 0x0000 }, /* R1033 */
+ { 0x0000, 0x0000 }, /* R1034 */
+ { 0x0000, 0x0000 }, /* R1035 */
+ { 0x0000, 0x0000 }, /* R1036 */
+ { 0x0000, 0x0000 }, /* R1037 */
+ { 0x0000, 0x0000 }, /* R1038 */
+ { 0x0000, 0x0000 }, /* R1039 */
+ { 0xF800, 0xF800 }, /* R1040 - AIF1 ADC1 Filters */
+ { 0x7800, 0x7800 }, /* R1041 - AIF1 ADC2 Filters */
+ { 0x0000, 0x0000 }, /* R1042 */
+ { 0x0000, 0x0000 }, /* R1043 */
+ { 0x0000, 0x0000 }, /* R1044 */
+ { 0x0000, 0x0000 }, /* R1045 */
+ { 0x0000, 0x0000 }, /* R1046 */
+ { 0x0000, 0x0000 }, /* R1047 */
+ { 0x0000, 0x0000 }, /* R1048 */
+ { 0x0000, 0x0000 }, /* R1049 */
+ { 0x0000, 0x0000 }, /* R1050 */
+ { 0x0000, 0x0000 }, /* R1051 */
+ { 0x0000, 0x0000 }, /* R1052 */
+ { 0x0000, 0x0000 }, /* R1053 */
+ { 0x0000, 0x0000 }, /* R1054 */
+ { 0x0000, 0x0000 }, /* R1055 */
+ { 0x02B6, 0x02B6 }, /* R1056 - AIF1 DAC1 Filters (1) */
+ { 0x3F00, 0x3F00 }, /* R1057 - AIF1 DAC1 Filters (2) */
+ { 0x02B6, 0x02B6 }, /* R1058 - AIF1 DAC2 Filters (1) */
+ { 0x3F00, 0x3F00 }, /* R1059 - AIF1 DAC2 Filters (2) */
+ { 0x0000, 0x0000 }, /* R1060 */
+ { 0x0000, 0x0000 }, /* R1061 */
+ { 0x0000, 0x0000 }, /* R1062 */
+ { 0x0000, 0x0000 }, /* R1063 */
+ { 0x0000, 0x0000 }, /* R1064 */
+ { 0x0000, 0x0000 }, /* R1065 */
+ { 0x0000, 0x0000 }, /* R1066 */
+ { 0x0000, 0x0000 }, /* R1067 */
+ { 0x0000, 0x0000 }, /* R1068 */
+ { 0x0000, 0x0000 }, /* R1069 */
+ { 0x0000, 0x0000 }, /* R1070 */
+ { 0x0000, 0x0000 }, /* R1071 */
+ { 0x0000, 0x0000 }, /* R1072 */
+ { 0x0000, 0x0000 }, /* R1073 */
+ { 0x0000, 0x0000 }, /* R1074 */
+ { 0x0000, 0x0000 }, /* R1075 */
+ { 0x0000, 0x0000 }, /* R1076 */
+ { 0x0000, 0x0000 }, /* R1077 */
+ { 0x0000, 0x0000 }, /* R1078 */
+ { 0x0000, 0x0000 }, /* R1079 */
+ { 0x0000, 0x0000 }, /* R1080 */
+ { 0x0000, 0x0000 }, /* R1081 */
+ { 0x0000, 0x0000 }, /* R1082 */
+ { 0x0000, 0x0000 }, /* R1083 */
+ { 0x0000, 0x0000 }, /* R1084 */
+ { 0x0000, 0x0000 }, /* R1085 */
+ { 0x0000, 0x0000 }, /* R1086 */
+ { 0x0000, 0x0000 }, /* R1087 */
+ { 0xFFFF, 0xFFFF }, /* R1088 - AIF1 DRC1 (1) */
+ { 0x1FFF, 0x1FFF }, /* R1089 - AIF1 DRC1 (2) */
+ { 0xFFFF, 0xFFFF }, /* R1090 - AIF1 DRC1 (3) */
+ { 0x07FF, 0x07FF }, /* R1091 - AIF1 DRC1 (4) */
+ { 0x03FF, 0x03FF }, /* R1092 - AIF1 DRC1 (5) */
+ { 0x0000, 0x0000 }, /* R1093 */
+ { 0x0000, 0x0000 }, /* R1094 */
+ { 0x0000, 0x0000 }, /* R1095 */
+ { 0x0000, 0x0000 }, /* R1096 */
+ { 0x0000, 0x0000 }, /* R1097 */
+ { 0x0000, 0x0000 }, /* R1098 */
+ { 0x0000, 0x0000 }, /* R1099 */
+ { 0x0000, 0x0000 }, /* R1100 */
+ { 0x0000, 0x0000 }, /* R1101 */
+ { 0x0000, 0x0000 }, /* R1102 */
+ { 0x0000, 0x0000 }, /* R1103 */
+ { 0xFFFF, 0xFFFF }, /* R1104 - AIF1 DRC2 (1) */
+ { 0x1FFF, 0x1FFF }, /* R1105 - AIF1 DRC2 (2) */
+ { 0xFFFF, 0xFFFF }, /* R1106 - AIF1 DRC2 (3) */
+ { 0x07FF, 0x07FF }, /* R1107 - AIF1 DRC2 (4) */
+ { 0x03FF, 0x03FF }, /* R1108 - AIF1 DRC2 (5) */
+ { 0x0000, 0x0000 }, /* R1109 */
+ { 0x0000, 0x0000 }, /* R1110 */
+ { 0x0000, 0x0000 }, /* R1111 */
+ { 0x0000, 0x0000 }, /* R1112 */
+ { 0x0000, 0x0000 }, /* R1113 */
+ { 0x0000, 0x0000 }, /* R1114 */
+ { 0x0000, 0x0000 }, /* R1115 */
+ { 0x0000, 0x0000 }, /* R1116 */
+ { 0x0000, 0x0000 }, /* R1117 */
+ { 0x0000, 0x0000 }, /* R1118 */
+ { 0x0000, 0x0000 }, /* R1119 */
+ { 0x0000, 0x0000 }, /* R1120 */
+ { 0x0000, 0x0000 }, /* R1121 */
+ { 0x0000, 0x0000 }, /* R1122 */
+ { 0x0000, 0x0000 }, /* R1123 */
+ { 0x0000, 0x0000 }, /* R1124 */
+ { 0x0000, 0x0000 }, /* R1125 */
+ { 0x0000, 0x0000 }, /* R1126 */
+ { 0x0000, 0x0000 }, /* R1127 */
+ { 0x0000, 0x0000 }, /* R1128 */
+ { 0x0000, 0x0000 }, /* R1129 */
+ { 0x0000, 0x0000 }, /* R1130 */
+ { 0x0000, 0x0000 }, /* R1131 */
+ { 0x0000, 0x0000 }, /* R1132 */
+ { 0x0000, 0x0000 }, /* R1133 */
+ { 0x0000, 0x0000 }, /* R1134 */
+ { 0x0000, 0x0000 }, /* R1135 */
+ { 0x0000, 0x0000 }, /* R1136 */
+ { 0x0000, 0x0000 }, /* R1137 */
+ { 0x0000, 0x0000 }, /* R1138 */
+ { 0x0000, 0x0000 }, /* R1139 */
+ { 0x0000, 0x0000 }, /* R1140 */
+ { 0x0000, 0x0000 }, /* R1141 */
+ { 0x0000, 0x0000 }, /* R1142 */
+ { 0x0000, 0x0000 }, /* R1143 */
+ { 0x0000, 0x0000 }, /* R1144 */
+ { 0x0000, 0x0000 }, /* R1145 */
+ { 0x0000, 0x0000 }, /* R1146 */
+ { 0x0000, 0x0000 }, /* R1147 */
+ { 0x0000, 0x0000 }, /* R1148 */
+ { 0x0000, 0x0000 }, /* R1149 */
+ { 0x0000, 0x0000 }, /* R1150 */
+ { 0x0000, 0x0000 }, /* R1151 */
+ { 0xFFFF, 0xFFFF }, /* R1152 - AIF1 DAC1 EQ Gains (1) */
+ { 0xFFC0, 0xFFC0 }, /* R1153 - AIF1 DAC1 EQ Gains (2) */
+ { 0xFFFF, 0xFFFF }, /* R1154 - AIF1 DAC1 EQ Band 1 A */
+ { 0xFFFF, 0xFFFF }, /* R1155 - AIF1 DAC1 EQ Band 1 B */
+ { 0xFFFF, 0xFFFF }, /* R1156 - AIF1 DAC1 EQ Band 1 PG */
+ { 0xFFFF, 0xFFFF }, /* R1157 - AIF1 DAC1 EQ Band 2 A */
+ { 0xFFFF, 0xFFFF }, /* R1158 - AIF1 DAC1 EQ Band 2 B */
+ { 0xFFFF, 0xFFFF }, /* R1159 - AIF1 DAC1 EQ Band 2 C */
+ { 0xFFFF, 0xFFFF }, /* R1160 - AIF1 DAC1 EQ Band 2 PG */
+ { 0xFFFF, 0xFFFF }, /* R1161 - AIF1 DAC1 EQ Band 3 A */
+ { 0xFFFF, 0xFFFF }, /* R1162 - AIF1 DAC1 EQ Band 3 B */
+ { 0xFFFF, 0xFFFF }, /* R1163 - AIF1 DAC1 EQ Band 3 C */
+ { 0xFFFF, 0xFFFF }, /* R1164 - AIF1 DAC1 EQ Band 3 PG */
+ { 0xFFFF, 0xFFFF }, /* R1165 - AIF1 DAC1 EQ Band 4 A */
+ { 0xFFFF, 0xFFFF }, /* R1166 - AIF1 DAC1 EQ Band 4 B */
+ { 0xFFFF, 0xFFFF }, /* R1167 - AIF1 DAC1 EQ Band 4 C */
+ { 0xFFFF, 0xFFFF }, /* R1168 - AIF1 DAC1 EQ Band 4 PG */
+ { 0xFFFF, 0xFFFF }, /* R1169 - AIF1 DAC1 EQ Band 5 A */
+ { 0xFFFF, 0xFFFF }, /* R1170 - AIF1 DAC1 EQ Band 5 B */
+ { 0xFFFF, 0xFFFF }, /* R1171 - AIF1 DAC1 EQ Band 5 PG */
+ { 0x0000, 0x0000 }, /* R1172 */
+ { 0x0000, 0x0000 }, /* R1173 */
+ { 0x0000, 0x0000 }, /* R1174 */
+ { 0x0000, 0x0000 }, /* R1175 */
+ { 0x0000, 0x0000 }, /* R1176 */
+ { 0x0000, 0x0000 }, /* R1177 */
+ { 0x0000, 0x0000 }, /* R1178 */
+ { 0x0000, 0x0000 }, /* R1179 */
+ { 0x0000, 0x0000 }, /* R1180 */
+ { 0x0000, 0x0000 }, /* R1181 */
+ { 0x0000, 0x0000 }, /* R1182 */
+ { 0x0000, 0x0000 }, /* R1183 */
+ { 0xFFFF, 0xFFFF }, /* R1184 - AIF1 DAC2 EQ Gains (1) */
+ { 0xFFC0, 0xFFC0 }, /* R1185 - AIF1 DAC2 EQ Gains (2) */
+ { 0xFFFF, 0xFFFF }, /* R1186 - AIF1 DAC2 EQ Band 1 A */
+ { 0xFFFF, 0xFFFF }, /* R1187 - AIF1 DAC2 EQ Band 1 B */
+ { 0xFFFF, 0xFFFF }, /* R1188 - AIF1 DAC2 EQ Band 1 PG */
+ { 0xFFFF, 0xFFFF }, /* R1189 - AIF1 DAC2 EQ Band 2 A */
+ { 0xFFFF, 0xFFFF }, /* R1190 - AIF1 DAC2 EQ Band 2 B */
+ { 0xFFFF, 0xFFFF }, /* R1191 - AIF1 DAC2 EQ Band 2 C */
+ { 0xFFFF, 0xFFFF }, /* R1192 - AIF1 DAC2 EQ Band 2 PG */
+ { 0xFFFF, 0xFFFF }, /* R1193 - AIF1 DAC2 EQ Band 3 A */
+ { 0xFFFF, 0xFFFF }, /* R1194 - AIF1 DAC2 EQ Band 3 B */
+ { 0xFFFF, 0xFFFF }, /* R1195 - AIF1 DAC2 EQ Band 3 C */
+ { 0xFFFF, 0xFFFF }, /* R1196 - AIF1 DAC2 EQ Band 3 PG */
+ { 0xFFFF, 0xFFFF }, /* R1197 - AIF1 DAC2 EQ Band 4 A */
+ { 0xFFFF, 0xFFFF }, /* R1198 - AIF1 DAC2 EQ Band 4 B */
+ { 0xFFFF, 0xFFFF }, /* R1199 - AIF1 DAC2 EQ Band 4 C */
+ { 0xFFFF, 0xFFFF }, /* R1200 - AIF1 DAC2 EQ Band 4 PG */
+ { 0xFFFF, 0xFFFF }, /* R1201 - AIF1 DAC2 EQ Band 5 A */
+ { 0xFFFF, 0xFFFF }, /* R1202 - AIF1 DAC2 EQ Band 5 B */
+ { 0xFFFF, 0xFFFF }, /* R1203 - AIF1 DAC2 EQ Band 5 PG */
+ { 0x0000, 0x0000 }, /* R1204 */
+ { 0x0000, 0x0000 }, /* R1205 */
+ { 0x0000, 0x0000 }, /* R1206 */
+ { 0x0000, 0x0000 }, /* R1207 */
+ { 0x0000, 0x0000 }, /* R1208 */
+ { 0x0000, 0x0000 }, /* R1209 */
+ { 0x0000, 0x0000 }, /* R1210 */
+ { 0x0000, 0x0000 }, /* R1211 */
+ { 0x0000, 0x0000 }, /* R1212 */
+ { 0x0000, 0x0000 }, /* R1213 */
+ { 0x0000, 0x0000 }, /* R1214 */
+ { 0x0000, 0x0000 }, /* R1215 */
+ { 0x0000, 0x0000 }, /* R1216 */
+ { 0x0000, 0x0000 }, /* R1217 */
+ { 0x0000, 0x0000 }, /* R1218 */
+ { 0x0000, 0x0000 }, /* R1219 */
+ { 0x0000, 0x0000 }, /* R1220 */
+ { 0x0000, 0x0000 }, /* R1221 */
+ { 0x0000, 0x0000 }, /* R1222 */
+ { 0x0000, 0x0000 }, /* R1223 */
+ { 0x0000, 0x0000 }, /* R1224 */
+ { 0x0000, 0x0000 }, /* R1225 */
+ { 0x0000, 0x0000 }, /* R1226 */
+ { 0x0000, 0x0000 }, /* R1227 */
+ { 0x0000, 0x0000 }, /* R1228 */
+ { 0x0000, 0x0000 }, /* R1229 */
+ { 0x0000, 0x0000 }, /* R1230 */
+ { 0x0000, 0x0000 }, /* R1231 */
+ { 0x0000, 0x0000 }, /* R1232 */
+ { 0x0000, 0x0000 }, /* R1233 */
+ { 0x0000, 0x0000 }, /* R1234 */
+ { 0x0000, 0x0000 }, /* R1235 */
+ { 0x0000, 0x0000 }, /* R1236 */
+ { 0x0000, 0x0000 }, /* R1237 */
+ { 0x0000, 0x0000 }, /* R1238 */
+ { 0x0000, 0x0000 }, /* R1239 */
+ { 0x0000, 0x0000 }, /* R1240 */
+ { 0x0000, 0x0000 }, /* R1241 */
+ { 0x0000, 0x0000 }, /* R1242 */
+ { 0x0000, 0x0000 }, /* R1243 */
+ { 0x0000, 0x0000 }, /* R1244 */
+ { 0x0000, 0x0000 }, /* R1245 */
+ { 0x0000, 0x0000 }, /* R1246 */
+ { 0x0000, 0x0000 }, /* R1247 */
+ { 0x0000, 0x0000 }, /* R1248 */
+ { 0x0000, 0x0000 }, /* R1249 */
+ { 0x0000, 0x0000 }, /* R1250 */
+ { 0x0000, 0x0000 }, /* R1251 */
+ { 0x0000, 0x0000 }, /* R1252 */
+ { 0x0000, 0x0000 }, /* R1253 */
+ { 0x0000, 0x0000 }, /* R1254 */
+ { 0x0000, 0x0000 }, /* R1255 */
+ { 0x0000, 0x0000 }, /* R1256 */
+ { 0x0000, 0x0000 }, /* R1257 */
+ { 0x0000, 0x0000 }, /* R1258 */
+ { 0x0000, 0x0000 }, /* R1259 */
+ { 0x0000, 0x0000 }, /* R1260 */
+ { 0x0000, 0x0000 }, /* R1261 */
+ { 0x0000, 0x0000 }, /* R1262 */
+ { 0x0000, 0x0000 }, /* R1263 */
+ { 0x0000, 0x0000 }, /* R1264 */
+ { 0x0000, 0x0000 }, /* R1265 */
+ { 0x0000, 0x0000 }, /* R1266 */
+ { 0x0000, 0x0000 }, /* R1267 */
+ { 0x0000, 0x0000 }, /* R1268 */
+ { 0x0000, 0x0000 }, /* R1269 */
+ { 0x0000, 0x0000 }, /* R1270 */
+ { 0x0000, 0x0000 }, /* R1271 */
+ { 0x0000, 0x0000 }, /* R1272 */
+ { 0x0000, 0x0000 }, /* R1273 */
+ { 0x0000, 0x0000 }, /* R1274 */
+ { 0x0000, 0x0000 }, /* R1275 */
+ { 0x0000, 0x0000 }, /* R1276 */
+ { 0x0000, 0x0000 }, /* R1277 */
+ { 0x0000, 0x0000 }, /* R1278 */
+ { 0x0000, 0x0000 }, /* R1279 */
+ { 0x00FF, 0x01FF }, /* R1280 - AIF2 ADC Left Volume */
+ { 0x00FF, 0x01FF }, /* R1281 - AIF2 ADC Right Volume */
+ { 0x00FF, 0x01FF }, /* R1282 - AIF2 DAC Left Volume */
+ { 0x00FF, 0x01FF }, /* R1283 - AIF2 DAC Right Volume */
+ { 0x0000, 0x0000 }, /* R1284 */
+ { 0x0000, 0x0000 }, /* R1285 */
+ { 0x0000, 0x0000 }, /* R1286 */
+ { 0x0000, 0x0000 }, /* R1287 */
+ { 0x0000, 0x0000 }, /* R1288 */
+ { 0x0000, 0x0000 }, /* R1289 */
+ { 0x0000, 0x0000 }, /* R1290 */
+ { 0x0000, 0x0000 }, /* R1291 */
+ { 0x0000, 0x0000 }, /* R1292 */
+ { 0x0000, 0x0000 }, /* R1293 */
+ { 0x0000, 0x0000 }, /* R1294 */
+ { 0x0000, 0x0000 }, /* R1295 */
+ { 0xF800, 0xF800 }, /* R1296 - AIF2 ADC Filters */
+ { 0x0000, 0x0000 }, /* R1297 */
+ { 0x0000, 0x0000 }, /* R1298 */
+ { 0x0000, 0x0000 }, /* R1299 */
+ { 0x0000, 0x0000 }, /* R1300 */
+ { 0x0000, 0x0000 }, /* R1301 */
+ { 0x0000, 0x0000 }, /* R1302 */
+ { 0x0000, 0x0000 }, /* R1303 */
+ { 0x0000, 0x0000 }, /* R1304 */
+ { 0x0000, 0x0000 }, /* R1305 */
+ { 0x0000, 0x0000 }, /* R1306 */
+ { 0x0000, 0x0000 }, /* R1307 */
+ { 0x0000, 0x0000 }, /* R1308 */
+ { 0x0000, 0x0000 }, /* R1309 */
+ { 0x0000, 0x0000 }, /* R1310 */
+ { 0x0000, 0x0000 }, /* R1311 */
+ { 0x02B6, 0x02B6 }, /* R1312 - AIF2 DAC Filters (1) */
+ { 0x3F00, 0x3F00 }, /* R1313 - AIF2 DAC Filters (2) */
+ { 0x0000, 0x0000 }, /* R1314 */
+ { 0x0000, 0x0000 }, /* R1315 */
+ { 0x0000, 0x0000 }, /* R1316 */
+ { 0x0000, 0x0000 }, /* R1317 */
+ { 0x0000, 0x0000 }, /* R1318 */
+ { 0x0000, 0x0000 }, /* R1319 */
+ { 0x0000, 0x0000 }, /* R1320 */
+ { 0x0000, 0x0000 }, /* R1321 */
+ { 0x0000, 0x0000 }, /* R1322 */
+ { 0x0000, 0x0000 }, /* R1323 */
+ { 0x0000, 0x0000 }, /* R1324 */
+ { 0x0000, 0x0000 }, /* R1325 */
+ { 0x0000, 0x0000 }, /* R1326 */
+ { 0x0000, 0x0000 }, /* R1327 */
+ { 0x0000, 0x0000 }, /* R1328 */
+ { 0x0000, 0x0000 }, /* R1329 */
+ { 0x0000, 0x0000 }, /* R1330 */
+ { 0x0000, 0x0000 }, /* R1331 */
+ { 0x0000, 0x0000 }, /* R1332 */
+ { 0x0000, 0x0000 }, /* R1333 */
+ { 0x0000, 0x0000 }, /* R1334 */
+ { 0x0000, 0x0000 }, /* R1335 */
+ { 0x0000, 0x0000 }, /* R1336 */
+ { 0x0000, 0x0000 }, /* R1337 */
+ { 0x0000, 0x0000 }, /* R1338 */
+ { 0x0000, 0x0000 }, /* R1339 */
+ { 0x0000, 0x0000 }, /* R1340 */
+ { 0x0000, 0x0000 }, /* R1341 */
+ { 0x0000, 0x0000 }, /* R1342 */
+ { 0x0000, 0x0000 }, /* R1343 */
+ { 0xFFFF, 0xFFFF }, /* R1344 - AIF2 DRC (1) */
+ { 0x1FFF, 0x1FFF }, /* R1345 - AIF2 DRC (2) */
+ { 0xFFFF, 0xFFFF }, /* R1346 - AIF2 DRC (3) */
+ { 0x07FF, 0x07FF }, /* R1347 - AIF2 DRC (4) */
+ { 0x03FF, 0x03FF }, /* R1348 - AIF2 DRC (5) */
+ { 0x0000, 0x0000 }, /* R1349 */
+ { 0x0000, 0x0000 }, /* R1350 */
+ { 0x0000, 0x0000 }, /* R1351 */
+ { 0x0000, 0x0000 }, /* R1352 */
+ { 0x0000, 0x0000 }, /* R1353 */
+ { 0x0000, 0x0000 }, /* R1354 */
+ { 0x0000, 0x0000 }, /* R1355 */
+ { 0x0000, 0x0000 }, /* R1356 */
+ { 0x0000, 0x0000 }, /* R1357 */
+ { 0x0000, 0x0000 }, /* R1358 */
+ { 0x0000, 0x0000 }, /* R1359 */
+ { 0x0000, 0x0000 }, /* R1360 */
+ { 0x0000, 0x0000 }, /* R1361 */
+ { 0x0000, 0x0000 }, /* R1362 */
+ { 0x0000, 0x0000 }, /* R1363 */
+ { 0x0000, 0x0000 }, /* R1364 */
+ { 0x0000, 0x0000 }, /* R1365 */
+ { 0x0000, 0x0000 }, /* R1366 */
+ { 0x0000, 0x0000 }, /* R1367 */
+ { 0x0000, 0x0000 }, /* R1368 */
+ { 0x0000, 0x0000 }, /* R1369 */
+ { 0x0000, 0x0000 }, /* R1370 */
+ { 0x0000, 0x0000 }, /* R1371 */
+ { 0x0000, 0x0000 }, /* R1372 */
+ { 0x0000, 0x0000 }, /* R1373 */
+ { 0x0000, 0x0000 }, /* R1374 */
+ { 0x0000, 0x0000 }, /* R1375 */
+ { 0x0000, 0x0000 }, /* R1376 */
+ { 0x0000, 0x0000 }, /* R1377 */
+ { 0x0000, 0x0000 }, /* R1378 */
+ { 0x0000, 0x0000 }, /* R1379 */
+ { 0x0000, 0x0000 }, /* R1380 */
+ { 0x0000, 0x0000 }, /* R1381 */
+ { 0x0000, 0x0000 }, /* R1382 */
+ { 0x0000, 0x0000 }, /* R1383 */
+ { 0x0000, 0x0000 }, /* R1384 */
+ { 0x0000, 0x0000 }, /* R1385 */
+ { 0x0000, 0x0000 }, /* R1386 */
+ { 0x0000, 0x0000 }, /* R1387 */
+ { 0x0000, 0x0000 }, /* R1388 */
+ { 0x0000, 0x0000 }, /* R1389 */
+ { 0x0000, 0x0000 }, /* R1390 */
+ { 0x0000, 0x0000 }, /* R1391 */
+ { 0x0000, 0x0000 }, /* R1392 */
+ { 0x0000, 0x0000 }, /* R1393 */
+ { 0x0000, 0x0000 }, /* R1394 */
+ { 0x0000, 0x0000 }, /* R1395 */
+ { 0x0000, 0x0000 }, /* R1396 */
+ { 0x0000, 0x0000 }, /* R1397 */
+ { 0x0000, 0x0000 }, /* R1398 */
+ { 0x0000, 0x0000 }, /* R1399 */
+ { 0x0000, 0x0000 }, /* R1400 */
+ { 0x0000, 0x0000 }, /* R1401 */
+ { 0x0000, 0x0000 }, /* R1402 */
+ { 0x0000, 0x0000 }, /* R1403 */
+ { 0x0000, 0x0000 }, /* R1404 */
+ { 0x0000, 0x0000 }, /* R1405 */
+ { 0x0000, 0x0000 }, /* R1406 */
+ { 0x0000, 0x0000 }, /* R1407 */
+ { 0xFFFF, 0xFFFF }, /* R1408 - AIF2 EQ Gains (1) */
+ { 0xFFC0, 0xFFC0 }, /* R1409 - AIF2 EQ Gains (2) */
+ { 0xFFFF, 0xFFFF }, /* R1410 - AIF2 EQ Band 1 A */
+ { 0xFFFF, 0xFFFF }, /* R1411 - AIF2 EQ Band 1 B */
+ { 0xFFFF, 0xFFFF }, /* R1412 - AIF2 EQ Band 1 PG */
+ { 0xFFFF, 0xFFFF }, /* R1413 - AIF2 EQ Band 2 A */
+ { 0xFFFF, 0xFFFF }, /* R1414 - AIF2 EQ Band 2 B */
+ { 0xFFFF, 0xFFFF }, /* R1415 - AIF2 EQ Band 2 C */
+ { 0xFFFF, 0xFFFF }, /* R1416 - AIF2 EQ Band 2 PG */
+ { 0xFFFF, 0xFFFF }, /* R1417 - AIF2 EQ Band 3 A */
+ { 0xFFFF, 0xFFFF }, /* R1418 - AIF2 EQ Band 3 B */
+ { 0xFFFF, 0xFFFF }, /* R1419 - AIF2 EQ Band 3 C */
+ { 0xFFFF, 0xFFFF }, /* R1420 - AIF2 EQ Band 3 PG */
+ { 0xFFFF, 0xFFFF }, /* R1421 - AIF2 EQ Band 4 A */
+ { 0xFFFF, 0xFFFF }, /* R1422 - AIF2 EQ Band 4 B */
+ { 0xFFFF, 0xFFFF }, /* R1423 - AIF2 EQ Band 4 C */
+ { 0xFFFF, 0xFFFF }, /* R1424 - AIF2 EQ Band 4 PG */
+ { 0xFFFF, 0xFFFF }, /* R1425 - AIF2 EQ Band 5 A */
+ { 0xFFFF, 0xFFFF }, /* R1426 - AIF2 EQ Band 5 B */
+ { 0xFFFF, 0xFFFF }, /* R1427 - AIF2 EQ Band 5 PG */
+ { 0x0000, 0x0000 }, /* R1428 */
+ { 0x0000, 0x0000 }, /* R1429 */
+ { 0x0000, 0x0000 }, /* R1430 */
+ { 0x0000, 0x0000 }, /* R1431 */
+ { 0x0000, 0x0000 }, /* R1432 */
+ { 0x0000, 0x0000 }, /* R1433 */
+ { 0x0000, 0x0000 }, /* R1434 */
+ { 0x0000, 0x0000 }, /* R1435 */
+ { 0x0000, 0x0000 }, /* R1436 */
+ { 0x0000, 0x0000 }, /* R1437 */
+ { 0x0000, 0x0000 }, /* R1438 */
+ { 0x0000, 0x0000 }, /* R1439 */
+ { 0x0000, 0x0000 }, /* R1440 */
+ { 0x0000, 0x0000 }, /* R1441 */
+ { 0x0000, 0x0000 }, /* R1442 */
+ { 0x0000, 0x0000 }, /* R1443 */
+ { 0x0000, 0x0000 }, /* R1444 */
+ { 0x0000, 0x0000 }, /* R1445 */
+ { 0x0000, 0x0000 }, /* R1446 */
+ { 0x0000, 0x0000 }, /* R1447 */
+ { 0x0000, 0x0000 }, /* R1448 */
+ { 0x0000, 0x0000 }, /* R1449 */
+ { 0x0000, 0x0000 }, /* R1450 */
+ { 0x0000, 0x0000 }, /* R1451 */
+ { 0x0000, 0x0000 }, /* R1452 */
+ { 0x0000, 0x0000 }, /* R1453 */
+ { 0x0000, 0x0000 }, /* R1454 */
+ { 0x0000, 0x0000 }, /* R1455 */
+ { 0x0000, 0x0000 }, /* R1456 */
+ { 0x0000, 0x0000 }, /* R1457 */
+ { 0x0000, 0x0000 }, /* R1458 */
+ { 0x0000, 0x0000 }, /* R1459 */
+ { 0x0000, 0x0000 }, /* R1460 */
+ { 0x0000, 0x0000 }, /* R1461 */
+ { 0x0000, 0x0000 }, /* R1462 */
+ { 0x0000, 0x0000 }, /* R1463 */
+ { 0x0000, 0x0000 }, /* R1464 */
+ { 0x0000, 0x0000 }, /* R1465 */
+ { 0x0000, 0x0000 }, /* R1466 */
+ { 0x0000, 0x0000 }, /* R1467 */
+ { 0x0000, 0x0000 }, /* R1468 */
+ { 0x0000, 0x0000 }, /* R1469 */
+ { 0x0000, 0x0000 }, /* R1470 */
+ { 0x0000, 0x0000 }, /* R1471 */
+ { 0x0000, 0x0000 }, /* R1472 */
+ { 0x0000, 0x0000 }, /* R1473 */
+ { 0x0000, 0x0000 }, /* R1474 */
+ { 0x0000, 0x0000 }, /* R1475 */
+ { 0x0000, 0x0000 }, /* R1476 */
+ { 0x0000, 0x0000 }, /* R1477 */
+ { 0x0000, 0x0000 }, /* R1478 */
+ { 0x0000, 0x0000 }, /* R1479 */
+ { 0x0000, 0x0000 }, /* R1480 */
+ { 0x0000, 0x0000 }, /* R1481 */
+ { 0x0000, 0x0000 }, /* R1482 */
+ { 0x0000, 0x0000 }, /* R1483 */
+ { 0x0000, 0x0000 }, /* R1484 */
+ { 0x0000, 0x0000 }, /* R1485 */
+ { 0x0000, 0x0000 }, /* R1486 */
+ { 0x0000, 0x0000 }, /* R1487 */
+ { 0x0000, 0x0000 }, /* R1488 */
+ { 0x0000, 0x0000 }, /* R1489 */
+ { 0x0000, 0x0000 }, /* R1490 */
+ { 0x0000, 0x0000 }, /* R1491 */
+ { 0x0000, 0x0000 }, /* R1492 */
+ { 0x0000, 0x0000 }, /* R1493 */
+ { 0x0000, 0x0000 }, /* R1494 */
+ { 0x0000, 0x0000 }, /* R1495 */
+ { 0x0000, 0x0000 }, /* R1496 */
+ { 0x0000, 0x0000 }, /* R1497 */
+ { 0x0000, 0x0000 }, /* R1498 */
+ { 0x0000, 0x0000 }, /* R1499 */
+ { 0x0000, 0x0000 }, /* R1500 */
+ { 0x0000, 0x0000 }, /* R1501 */
+ { 0x0000, 0x0000 }, /* R1502 */
+ { 0x0000, 0x0000 }, /* R1503 */
+ { 0x0000, 0x0000 }, /* R1504 */
+ { 0x0000, 0x0000 }, /* R1505 */
+ { 0x0000, 0x0000 }, /* R1506 */
+ { 0x0000, 0x0000 }, /* R1507 */
+ { 0x0000, 0x0000 }, /* R1508 */
+ { 0x0000, 0x0000 }, /* R1509 */
+ { 0x0000, 0x0000 }, /* R1510 */
+ { 0x0000, 0x0000 }, /* R1511 */
+ { 0x0000, 0x0000 }, /* R1512 */
+ { 0x0000, 0x0000 }, /* R1513 */
+ { 0x0000, 0x0000 }, /* R1514 */
+ { 0x0000, 0x0000 }, /* R1515 */
+ { 0x0000, 0x0000 }, /* R1516 */
+ { 0x0000, 0x0000 }, /* R1517 */
+ { 0x0000, 0x0000 }, /* R1518 */
+ { 0x0000, 0x0000 }, /* R1519 */
+ { 0x0000, 0x0000 }, /* R1520 */
+ { 0x0000, 0x0000 }, /* R1521 */
+ { 0x0000, 0x0000 }, /* R1522 */
+ { 0x0000, 0x0000 }, /* R1523 */
+ { 0x0000, 0x0000 }, /* R1524 */
+ { 0x0000, 0x0000 }, /* R1525 */
+ { 0x0000, 0x0000 }, /* R1526 */
+ { 0x0000, 0x0000 }, /* R1527 */
+ { 0x0000, 0x0000 }, /* R1528 */
+ { 0x0000, 0x0000 }, /* R1529 */
+ { 0x0000, 0x0000 }, /* R1530 */
+ { 0x0000, 0x0000 }, /* R1531 */
+ { 0x0000, 0x0000 }, /* R1532 */
+ { 0x0000, 0x0000 }, /* R1533 */
+ { 0x0000, 0x0000 }, /* R1534 */
+ { 0x0000, 0x0000 }, /* R1535 */
+ { 0x01EF, 0x01EF }, /* R1536 - DAC1 Mixer Volumes */
+ { 0x0037, 0x0037 }, /* R1537 - DAC1 Left Mixer Routing */
+ { 0x0037, 0x0037 }, /* R1538 - DAC1 Right Mixer Routing */
+ { 0x01EF, 0x01EF }, /* R1539 - DAC2 Mixer Volumes */
+ { 0x0037, 0x0037 }, /* R1540 - DAC2 Left Mixer Routing */
+ { 0x0037, 0x0037 }, /* R1541 - DAC2 Right Mixer Routing */
+ { 0x0003, 0x0003 }, /* R1542 - AIF1 ADC1 Left Mixer Routing */
+ { 0x0003, 0x0003 }, /* R1543 - AIF1 ADC1 Right Mixer Routing */
+ { 0x0003, 0x0003 }, /* R1544 - AIF1 ADC2 Left Mixer Routing */
+ { 0x0003, 0x0003 }, /* R1545 - AIF1 ADC2 Right mixer Routing */
+ { 0x0000, 0x0000 }, /* R1546 */
+ { 0x0000, 0x0000 }, /* R1547 */
+ { 0x0000, 0x0000 }, /* R1548 */
+ { 0x0000, 0x0000 }, /* R1549 */
+ { 0x0000, 0x0000 }, /* R1550 */
+ { 0x0000, 0x0000 }, /* R1551 */
+ { 0x02FF, 0x03FF }, /* R1552 - DAC1 Left Volume */
+ { 0x02FF, 0x03FF }, /* R1553 - DAC1 Right Volume */
+ { 0x02FF, 0x03FF }, /* R1554 - DAC2 Left Volume */
+ { 0x02FF, 0x03FF }, /* R1555 - DAC2 Right Volume */
+ { 0x0003, 0x0003 }, /* R1556 - DAC Softmute */
+ { 0x0000, 0x0000 }, /* R1557 */
+ { 0x0000, 0x0000 }, /* R1558 */
+ { 0x0000, 0x0000 }, /* R1559 */
+ { 0x0000, 0x0000 }, /* R1560 */
+ { 0x0000, 0x0000 }, /* R1561 */
+ { 0x0000, 0x0000 }, /* R1562 */
+ { 0x0000, 0x0000 }, /* R1563 */
+ { 0x0000, 0x0000 }, /* R1564 */
+ { 0x0000, 0x0000 }, /* R1565 */
+ { 0x0000, 0x0000 }, /* R1566 */
+ { 0x0000, 0x0000 }, /* R1567 */
+ { 0x0003, 0x0003 }, /* R1568 - Oversampling */
+ { 0x03C3, 0x03C3 }, /* R1569 - Sidetone */
};
static int wm8994_readable(unsigned int reg)
@@ -1902,8 +1900,6 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
return snd_soc_put_volsw(kcontrol, ucontrol);
}
-
-
static void wm8994_set_drc(struct snd_soc_codec *codec, int drc)
{
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
@@ -1942,7 +1938,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+ struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_pdata *pdata = wm8994->pdata;
int drc = wm8994_get_drc(kcontrol->id.name);
int value = ucontrol->value.integer.value[0];
@@ -2045,7 +2041,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+ struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_pdata *pdata = wm8994->pdata;
int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
int value = ucontrol->value.integer.value[0];
@@ -2067,7 +2063,7 @@ static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+ struct wm8994_priv *wm8994 =snd_soc_codec_get_drvdata(codec);
int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block];
@@ -2075,6 +2071,22 @@ static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
return 0;
}
+static const char *aifdac_src_text[] = {
+ "Left", "Right"
+};
+
+static const struct soc_enum aif1dacl_src =
+ SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 15, 2, aifdac_src_text);
+
+static const struct soc_enum aif1dacr_src =
+ SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 14, 2, aifdac_src_text);
+
+static const struct soc_enum aif2dacl_src =
+ SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 15, 2, aifdac_src_text);
+
+static const struct soc_enum aif2dacr_src =
+ SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 14, 2, aifdac_src_text);
+
static const struct snd_kcontrol_new wm8994_snd_controls[] = {
SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
WM8994_AIF1_ADC1_RIGHT_VOLUME,
@@ -2086,6 +2098,11 @@ SOC_DOUBLE_R_TLV("AIF2ADC Volume", WM8994_AIF2_ADC_LEFT_VOLUME,
WM8994_AIF2_ADC_RIGHT_VOLUME,
1, 119, 0, digital_tlv),
+SOC_ENUM("AIF1DACL Source", aif1dacl_src),
+SOC_ENUM("AIF1DACR Source", aif1dacr_src),
+SOC_ENUM("AIF2DACL Source", aif1dacl_src),
+SOC_ENUM("AIF2DACR Source", aif1dacr_src),
+
SOC_DOUBLE_R_TLV("AIF1DAC1 Volume", WM8994_AIF1_DAC1_LEFT_VOLUME,
WM8994_AIF1_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8994_AIF1_DAC2_LEFT_VOLUME,
@@ -2881,10 +2898,9 @@ static int wm8994_get_fll_config(struct fll_div *fll,
return 0;
}
-static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
+static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
unsigned int freq_in, unsigned int freq_out)
{
- struct snd_soc_codec *codec = dai->codec;
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
int reg_offset, ret;
struct fll_div fll;
@@ -2995,8 +3011,15 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
return 0;
}
+
static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
+static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ return _wm8994_set_fll(dai->codec, id, src, freq_in, freq_out);
+}
+
static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
@@ -3313,20 +3336,24 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
bclk_reg = WM8994_AIF1_BCLK;
rate_reg = WM8994_AIF1_RATE;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
- wm8994->lrclk_shared[0])
+ wm8994->lrclk_shared[0]) {
lrclk_reg = WM8994_AIF1DAC_LRCLK;
- else
+ } else {
lrclk_reg = WM8994_AIF1ADC_LRCLK;
+ dev_dbg(codec->dev, "AIF1 using split LRCLK\n");
+ }
break;
case 2:
aif1_reg = WM8994_AIF2_CONTROL_1;
bclk_reg = WM8994_AIF2_BCLK;
rate_reg = WM8994_AIF2_RATE;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
- wm8994->lrclk_shared[1])
+ wm8994->lrclk_shared[1]) {
lrclk_reg = WM8994_AIF2DAC_LRCLK;
- else
+ } else {
lrclk_reg = WM8994_AIF2ADC_LRCLK;
+ dev_dbg(codec->dev, "AIF2 using split LRCLK\n");
+ }
break;
default:
return -EINVAL;
@@ -3491,7 +3518,7 @@ static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
#define WM8994_RATES SNDRV_PCM_RATE_8000_96000
#define WM8994_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
- SNDRV_PCM_FMTBIT_S24_LE)
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
.set_sysclk = wm8994_set_dai_sysclk,
@@ -3515,9 +3542,9 @@ static struct snd_soc_dai_ops wm8994_aif3_dai_ops = {
.set_tristate = wm8994_set_tristate,
};
-struct snd_soc_dai wm8994_dai[] = {
+static struct snd_soc_dai_driver wm8994_dai[] = {
{
- .name = "WM8994 AIF1",
+ .name = "wm8994-aif1",
.id = 1,
.playback = {
.stream_name = "AIF1 Playback",
@@ -3536,7 +3563,7 @@ struct snd_soc_dai wm8994_dai[] = {
.ops = &wm8994_aif1_dai_ops,
},
{
- .name = "WM8994 AIF2",
+ .name = "wm8994-aif2",
.id = 2,
.playback = {
.stream_name = "AIF2 Playback",
@@ -3555,7 +3582,7 @@ struct snd_soc_dai wm8994_dai[] = {
.ops = &wm8994_aif2_dai_ops,
},
{
- .name = "WM8994 AIF3",
+ .name = "wm8994-aif3",
.id = 3,
.playback = {
.stream_name = "AIF3 Playback",
@@ -3574,20 +3601,17 @@ struct snd_soc_dai wm8994_dai[] = {
.ops = &wm8994_aif3_dai_ops,
}
};
-EXPORT_SYMBOL_GPL(wm8994_dai);
#ifdef CONFIG_PM
-static int wm8994_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
int i, ret;
for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
sizeof(struct fll_config));
- ret = wm8994_set_fll(&codec->dai[0], i + 1, 0, 0, 0);
+ ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0);
if (ret < 0)
dev_warn(codec->dev, "Failed to stop FLL%d: %d\n",
i + 1, ret);
@@ -3598,10 +3622,8 @@ static int wm8994_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int wm8994_resume(struct platform_device *pdev)
+static int wm8994_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
u16 *reg_cache = codec->reg_cache;
int i, ret;
@@ -3630,7 +3652,7 @@ static int wm8994_resume(struct platform_device *pdev)
if (!wm8994->fll_suspend[i].out)
continue;
- ret = wm8994_set_fll(&codec->dai[0], i + 1,
+ ret = _wm8994_set_fll(codec, i + 1,
wm8994->fll_suspend[i].src,
wm8994->fll_suspend[i].in,
wm8994->fll_suspend[i].out);
@@ -3648,7 +3670,7 @@ static int wm8994_resume(struct platform_device *pdev)
static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
{
- struct snd_soc_codec *codec = &wm8994->codec;
+ struct snd_soc_codec *codec = wm8994->codec;
struct wm8994_pdata *pdata = wm8994->pdata;
struct snd_kcontrol_new controls[] = {
SOC_ENUM_EXT("AIF1.1 EQ Mode",
@@ -3706,16 +3728,16 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts;
wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts;
- ret = snd_soc_add_controls(&wm8994->codec, controls,
+ ret = snd_soc_add_controls(wm8994->codec, controls,
ARRAY_SIZE(controls));
if (ret != 0)
- dev_err(wm8994->codec.dev,
+ dev_err(wm8994->codec->dev,
"Failed to add ReTune Mobile controls: %d\n", ret);
}
static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
{
- struct snd_soc_codec *codec = &wm8994->codec;
+ struct snd_soc_codec *codec = wm8994->codec;
struct wm8994_pdata *pdata = wm8994->pdata;
int ret, i;
@@ -3747,7 +3769,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
wm8994->drc_texts = kmalloc(sizeof(char *)
* pdata->num_drc_cfgs, GFP_KERNEL);
if (!wm8994->drc_texts) {
- dev_err(wm8994->codec.dev,
+ dev_err(wm8994->codec->dev,
"Failed to allocate %d DRC config texts\n",
pdata->num_drc_cfgs);
return;
@@ -3759,10 +3781,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
wm8994->drc_enum.max = pdata->num_drc_cfgs;
wm8994->drc_enum.texts = wm8994->drc_texts;
- ret = snd_soc_add_controls(&wm8994->codec, controls,
+ ret = snd_soc_add_controls(wm8994->codec, controls,
ARRAY_SIZE(controls));
if (ret != 0)
- dev_err(wm8994->codec.dev,
+ dev_err(wm8994->codec->dev,
"Failed to add DRC mode controls: %d\n", ret);
for (i = 0; i < WM8994_NUM_DRC; i++)
@@ -3775,62 +3797,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
if (pdata->num_retune_mobile_cfgs)
wm8994_handle_retune_mobile_pdata(wm8994);
else
- snd_soc_add_controls(&wm8994->codec, wm8994_eq_controls,
+ snd_soc_add_controls(wm8994->codec, wm8994_eq_controls,
ARRAY_SIZE(wm8994_eq_controls));
}
-static int wm8994_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
-
- if (wm8994_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
- }
-
- socdev->card->codec = wm8994_codec;
- codec = wm8994_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- return ret;
- }
-
- wm8994_handle_pdata(snd_soc_codec_get_drvdata(codec));
-
- wm_hubs_add_analogue_controls(codec);
- snd_soc_add_controls(codec, wm8994_snd_controls,
- ARRAY_SIZE(wm8994_snd_controls));
- snd_soc_dapm_new_controls(codec, wm8994_dapm_widgets,
- ARRAY_SIZE(wm8994_dapm_widgets));
- wm_hubs_add_analogue_routes(codec, 0, 0);
- snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
-
- return 0;
-}
-
-static int wm8994_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8994 = {
- .probe = wm8994_probe,
- .remove = wm8994_remove,
- .suspend = wm8994_suspend,
- .resume = wm8994_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994);
-
/**
* wm8994_mic_detect - Enable microphone detection via the WM8994 IRQ
*
@@ -3842,7 +3812,7 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994);
*
* Enable microphone detection via IRQ on the WM8994. If GPIOs are
* being used to bring out signals to the processor then only platform
- * data configuration is needed for WM8903 and processor GPIOs should
+ * data configuration is needed for WM8994 and processor GPIOs should
* be configured using snd_soc_jack_add_gpios() instead.
*
* Configuration of detection levels is available via the micbias1_lvl
@@ -3889,7 +3859,7 @@ EXPORT_SYMBOL_GPL(wm8994_mic_detect);
static irqreturn_t wm8994_mic_irq(int irq, void *data)
{
struct wm8994_priv *priv = data;
- struct snd_soc_codec *codec = &priv->codec;
+ struct snd_soc_codec *codec = priv->codec;
int reg;
int report;
@@ -3921,46 +3891,20 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static int wm8994_codec_probe(struct platform_device *pdev)
+static int wm8994_codec_probe(struct snd_soc_codec *codec)
{
- int ret;
struct wm8994_priv *wm8994;
- struct snd_soc_codec *codec;
- int i;
+ int ret, i;
- if (wm8994_codec) {
- dev_err(&pdev->dev, "Another WM8994 is registered\n");
- return -EINVAL;
- }
+ codec->control_data = dev_get_drvdata(codec->dev->parent);
wm8994 = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL);
- if (!wm8994) {
- dev_err(&pdev->dev, "Failed to allocate private data\n");
+ if (wm8994 == NULL)
return -ENOMEM;
- }
-
- codec = &wm8994->codec;
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
snd_soc_codec_set_drvdata(codec, wm8994);
- codec->control_data = dev_get_drvdata(pdev->dev.parent);
- codec->name = "WM8994";
- codec->owner = THIS_MODULE;
- codec->read = wm8994_read;
- codec->write = wm8994_write;
- codec->readable_register = wm8994_readable;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm8994_set_bias_level;
- codec->dai = &wm8994_dai[0];
- codec->num_dai = 3;
- codec->reg_cache_size = WM8994_MAX_REGISTER;
- codec->reg_cache = &wm8994->reg_cache;
- codec->dev = &pdev->dev;
-
- wm8994->pdata = pdev->dev.parent->platform_data;
+
+ wm8994->pdata = dev_get_platdata(codec->dev->parent);
+ wm8994->codec = codec;
/* Fill the cache with physical values we inherited; don't reset */
ret = wm8994_bulk_read(codec->control_data, 0,
@@ -3996,25 +3940,25 @@ static int wm8994_codec_probe(struct platform_device *pdev)
ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_DET,
wm8994_mic_irq, "Mic 1 detect", wm8994);
if (ret != 0)
- dev_warn(&pdev->dev,
+ dev_warn(codec->dev,
"Failed to request Mic1 detect IRQ: %d\n", ret);
ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT,
wm8994_mic_irq, "Mic 1 short", wm8994);
if (ret != 0)
- dev_warn(&pdev->dev,
+ dev_warn(codec->dev,
"Failed to request Mic1 short IRQ: %d\n", ret);
ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_DET,
wm8994_mic_irq, "Mic 2 detect", wm8994);
if (ret != 0)
- dev_warn(&pdev->dev,
+ dev_warn(codec->dev,
"Failed to request Mic2 detect IRQ: %d\n", ret);
ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT,
wm8994_mic_irq, "Mic 2 short", wm8994);
if (ret != 0)
- dev_warn(&pdev->dev,
+ dev_warn(codec->dev,
"Failed to request Mic2 short IRQ: %d\n", ret);
/* Remember if AIFnLRCLK is configured as a GPIO. This should be
@@ -4045,13 +3989,8 @@ static int wm8994_codec_probe(struct platform_device *pdev)
wm8994->lrclk_shared[1] = 0;
}
- for (i = 0; i < ARRAY_SIZE(wm8994_dai); i++)
- wm8994_dai[i].dev = codec->dev;
-
wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- wm8994_codec = codec;
-
/* Latch volume updates (right only; we always do left then right). */
snd_soc_update_bits(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME,
WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU);
@@ -4088,24 +4027,18 @@ static int wm8994_codec_probe(struct platform_device *pdev)
wm8994_update_class_w(codec);
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err_irq;
- }
-
- ret = snd_soc_register_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
- goto err_codec;
- }
+ wm8994_handle_pdata(wm8994);
- platform_set_drvdata(pdev, wm8994);
+ wm_hubs_add_analogue_controls(codec);
+ snd_soc_add_controls(codec, wm8994_snd_controls,
+ ARRAY_SIZE(wm8994_snd_controls));
+ snd_soc_dapm_new_controls(codec, wm8994_dapm_widgets,
+ ARRAY_SIZE(wm8994_dapm_widgets));
+ wm_hubs_add_analogue_routes(codec, 0, 0);
+ snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
return 0;
-err_codec:
- snd_soc_unregister_codec(codec);
err_irq:
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
@@ -4116,31 +4049,50 @@ err:
return ret;
}
-static int __devexit wm8994_codec_remove(struct platform_device *pdev)
+static int wm8994_codec_remove(struct snd_soc_codec *codec)
{
- struct wm8994_priv *wm8994 = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = &wm8994->codec;
+ struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai));
- snd_soc_unregister_codec(&wm8994->codec);
+
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994);
kfree(wm8994);
- wm8994_codec = NULL;
return 0;
}
+static struct snd_soc_codec_driver soc_codec_dev_wm8994 = {
+ .probe = wm8994_codec_probe,
+ .remove = wm8994_codec_remove,
+ .suspend = wm8994_suspend,
+ .resume = wm8994_resume,
+ .read = wm8994_read,
+ .write = wm8994_write,
+ .set_bias_level = wm8994_set_bias_level,
+};
+
+static int __devinit wm8994_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994,
+ wm8994_dai, ARRAY_SIZE(wm8994_dai));
+}
+
+static int __devexit wm8994_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
static struct platform_driver wm8994_codec_driver = {
.driver = {
.name = "wm8994-codec",
.owner = THIS_MODULE,
},
- .probe = wm8994_codec_probe,
- .remove = __devexit_p(wm8994_codec_remove),
+ .probe = wm8994_probe,
+ .remove = __devexit_p(wm8994_remove),
};
static __init int wm8994_init(void)
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index 2e0ca67a8df7..d8dce260c430 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -11,9 +11,6 @@
#include <sound/soc.h>
-extern struct snd_soc_codec_device soc_codec_dev_wm8994;
-extern struct snd_soc_dai wm8994_dai[];
-
/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
#define WM8994_SYSCLK_MCLK1 1
#define WM8994_SYSCLK_MCLK2 2
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 76b37ff6c264..ecc7c37180c7 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -156,7 +156,8 @@ static struct {
};
struct wm9081_priv {
- struct snd_soc_codec codec;
+ enum snd_soc_control_type control_type;
+ void *control_data;
u16 reg_cache[WM9081_MAX_REGISTER + 1];
int sysclk_source;
int mclk_rate;
@@ -1212,8 +1213,8 @@ static struct snd_soc_dai_ops wm9081_dai_ops = {
/* We report two channels because the CODEC processes a stereo signal, even
* though it is only capable of handling a mono output.
*/
-struct snd_soc_dai wm9081_dai = {
- .name = "WM9081",
+static struct snd_soc_dai_driver wm9081_dai = {
+ .name = "wm9081-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
@@ -1223,34 +1224,42 @@ struct snd_soc_dai wm9081_dai = {
},
.ops = &wm9081_dai_ops,
};
-EXPORT_SYMBOL_GPL(wm9081_dai);
-
-static struct snd_soc_codec *wm9081_codec;
-
-static int wm9081_probe(struct platform_device *pdev)
+static int wm9081_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- struct wm9081_priv *wm9081;
- int ret = 0;
+ struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+ u16 reg;
- if (wm9081_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
+ codec->control_data = wm9081->control_data;
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm9081->control_type);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
}
- socdev->card->codec = wm9081_codec;
- codec = wm9081_codec;
- wm9081 = snd_soc_codec_get_drvdata(codec);
+ reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET);
+ if (reg != 0x9081) {
+ dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg);
+ ret = -EINVAL;
+ return ret;
+ }
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ ret = wm9081_reset(codec);
if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
+ dev_err(codec->dev, "Failed to issue reset\n");
+ return ret;
}
+ wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ /* Enable zero cross by default */
+ reg = snd_soc_read(codec, WM9081_ANALOGUE_LINEOUT);
+ snd_soc_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC);
+ reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_PGA);
+ snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA,
+ reg | WM9081_SPKPGAZC);
+
snd_soc_add_controls(codec, wm9081_snd_controls,
ARRAY_SIZE(wm9081_snd_controls));
if (!wm9081->retune) {
@@ -1265,40 +1274,28 @@ static int wm9081_probe(struct platform_device *pdev)
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
return ret;
-
-pcm_err:
- return ret;
}
-static int wm9081_remove(struct platform_device *pdev)
+static int wm9081_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
+ wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
#ifdef CONFIG_PM
-static int wm9081_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm9081_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm9081_resume(struct platform_device *pdev)
+static int wm9081_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
u16 *reg_cache = codec->reg_cache;
int i;
- for (i = 0; i < codec->reg_cache_size; i++) {
+ for (i = 0; i < codec->driver->reg_cache_size; i++) {
if (i == WM9081_SOFTWARE_RESET)
continue;
@@ -1314,133 +1311,43 @@ static int wm9081_resume(struct platform_device *pdev)
#define wm9081_resume NULL
#endif
-struct snd_soc_codec_device soc_codec_dev_wm9081 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9081 = {
.probe = wm9081_probe,
.remove = wm9081_remove,
.suspend = wm9081_suspend,
.resume = wm9081_resume,
+ .set_bias_level = wm9081_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm9081_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm9081_reg_defaults,
+ .volatile_register = wm9081_volatile_register,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9081);
-
-static int wm9081_register(struct wm9081_priv *wm9081,
- enum snd_soc_control_type control)
-{
- struct snd_soc_codec *codec = &wm9081->codec;
- int ret;
- u16 reg;
-
- if (wm9081_codec) {
- dev_err(codec->dev, "Another WM9081 is registered\n");
- ret = -EINVAL;
- goto err;
- }
-
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- snd_soc_codec_set_drvdata(codec, wm9081);
- codec->name = "WM9081";
- codec->owner = THIS_MODULE;
- codec->dai = &wm9081_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm9081->reg_cache);
- codec->reg_cache = &wm9081->reg_cache;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm9081_set_bias_level;
- codec->volatile_register = wm9081_volatile_register;
-
- memcpy(codec->reg_cache, wm9081_reg_defaults,
- sizeof(wm9081_reg_defaults));
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
- }
-
- reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET);
- if (reg != 0x9081) {
- dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg);
- ret = -EINVAL;
- goto err;
- }
-
- ret = wm9081_reset(codec);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to issue reset\n");
- goto err;
- }
-
- wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- /* Enable zero cross by default */
- reg = snd_soc_read(codec, WM9081_ANALOGUE_LINEOUT);
- snd_soc_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC);
- reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_PGA);
- snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA,
- reg | WM9081_SPKPGAZC);
-
- wm9081_dai.dev = codec->dev;
-
- wm9081_codec = codec;
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- ret = snd_soc_register_dai(&wm9081_dai);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
-
- return 0;
-
-err_codec:
- snd_soc_unregister_codec(codec);
-err:
- kfree(wm9081);
- return ret;
-}
-
-static void wm9081_unregister(struct wm9081_priv *wm9081)
-{
- wm9081_set_bias_level(&wm9081->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_dai(&wm9081_dai);
- snd_soc_unregister_codec(&wm9081->codec);
- kfree(wm9081);
- wm9081_codec = NULL;
-}
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm9081_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm9081_priv *wm9081;
- struct snd_soc_codec *codec;
+ int ret;
wm9081 = kzalloc(sizeof(struct wm9081_priv), GFP_KERNEL);
if (wm9081 == NULL)
return -ENOMEM;
- codec = &wm9081->codec;
- codec->hw_write = (hw_write_t)i2c_master_send;
- wm9081->retune = i2c->dev.platform_data;
-
i2c_set_clientdata(i2c, wm9081);
- codec->control_data = i2c;
-
- codec->dev = &i2c->dev;
+ wm9081->control_data = i2c;
- return wm9081_register(wm9081, SND_SOC_I2C);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm9081, &wm9081_dai, 1);
+ if (ret < 0)
+ kfree(wm9081);
+ return ret;
}
static __devexit int wm9081_i2c_remove(struct i2c_client *client)
{
- struct wm9081_priv *wm9081 = i2c_get_clientdata(client);
- wm9081_unregister(wm9081);
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
return 0;
}
@@ -1452,31 +1359,34 @@ MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id);
static struct i2c_driver wm9081_i2c_driver = {
.driver = {
- .name = "wm9081",
+ .name = "wm9081-codec",
.owner = THIS_MODULE,
},
.probe = wm9081_i2c_probe,
.remove = __devexit_p(wm9081_i2c_remove),
.id_table = wm9081_i2c_id,
};
+#endif
static int __init wm9081_modinit(void)
{
- int ret;
-
+ int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm9081_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register WM9081 I2C driver: %d\n",
ret);
}
-
+#endif
return ret;
}
module_init(wm9081_modinit);
static void __exit wm9081_exit(void)
{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm9081_i2c_driver);
+#endif
}
module_exit(wm9081_exit);
diff --git a/sound/soc/codecs/wm9081.h b/sound/soc/codecs/wm9081.h
index 42d3bc757021..871cccb066dc 100644
--- a/sound/soc/codecs/wm9081.h
+++ b/sound/soc/codecs/wm9081.h
@@ -15,9 +15,6 @@
#include <sound/soc.h>
-extern struct snd_soc_dai wm9081_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm9081;
-
/*
* SYSCLK sources
*/
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
index 1592250daec0..99c046ba46bb 100644
--- a/sound/soc/codecs/wm9090.c
+++ b/sound/soc/codecs/wm9090.c
@@ -34,8 +34,6 @@
#include "wm9090.h"
-static struct snd_soc_codec *wm9090_codec;
-
static const u16 wm9090_reg_defaults[] = {
0x9093, /* R0 - Software Reset */
0x0006, /* R1 - Power Management (1) */
@@ -142,15 +140,10 @@ static const u16 wm9090_reg_defaults[] = {
/* This struct is used to save the context */
struct wm9090_priv {
- /* We're not really registering as a CODEC since ASoC core
- * does not yet support multiple CODECs but having the CODEC
- * structure means we can reuse some of the ASoC core
- * features.
- */
- struct snd_soc_codec codec;
struct mutex mutex;
u16 reg_cache[WM9090_MAX_REGISTER + 1];
struct wm9090_platform_data pdata;
+ void *control_data;
};
static int wm9090_volatile(unsigned int reg)
@@ -523,7 +516,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) {
/* Restore the register cache */
- for (i = 1; i < codec->reg_cache_size; i++) {
+ for (i = 1; i < codec->driver->reg_cache_size; i++) {
if (reg_cache[i] == wm9090_reg_defaults[i])
continue;
if (wm9090_volatile(i))
@@ -556,51 +549,67 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static int wm9090_probe(struct platform_device *pdev)
+static int wm9090_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
- int ret = 0;
+ struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec);
+ int ret;
- if (wm9090_codec == NULL) {
- dev_err(&pdev->dev, "Codec device not registered\n");
- return -ENODEV;
+ codec->control_data = wm9090->control_data;
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
}
- socdev->card->codec = wm9090_codec;
- codec = wm9090_codec;
-
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- dev_err(codec->dev, "failed to create pcms: %d\n", ret);
- goto pcm_err;
+ ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET);
+ if (ret < 0)
+ return ret;
+ if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) {
+ dev_err(codec->dev, "Device is not a WM9090, ID=%x\n", ret);
+ return -EINVAL;
}
+ ret = snd_soc_write(codec, WM9090_SOFTWARE_RESET, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Configure some defaults; they will be written out when we
+ * bring the bias up.
+ */
+ wm9090->reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU
+ | WM9090_IN1A_ZC;
+ wm9090->reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU
+ | WM9090_IN1B_ZC;
+ wm9090->reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU
+ | WM9090_IN2A_ZC;
+ wm9090->reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU
+ | WM9090_IN2B_ZC;
+ wm9090->reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |=
+ WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC;
+ wm9090->reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |=
+ WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC;
+ wm9090->reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |=
+ WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC;
+
+ wm9090->reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA;
+
+ wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
wm9090_add_controls(codec);
return 0;
-
-pcm_err:
- return ret;
}
#ifdef CONFIG_PM
-static int wm9090_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm9090_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm9090_resume(struct platform_device *pdev)
+static int wm9090_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -610,29 +619,29 @@ static int wm9090_resume(struct platform_device *pdev)
#define wm9090_resume NULL
#endif
-static int wm9090_remove(struct platform_device *pdev)
+static int wm9090_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
+ wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_wm9090 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9090 = {
.probe = wm9090_probe,
.remove = wm9090_remove,
.suspend = wm9090_suspend,
.resume = wm9090_resume,
+ .set_bias_level = wm9090_set_bias_level,
+ .reg_cache_size = (WM9090_MAX_REGISTER + 1),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm9090_reg_defaults,
+ .volatile_register = wm9090_volatile,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9090);
static int wm9090_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm9090_priv *wm9090;
- struct snd_soc_codec *codec;
int ret;
wm9090 = kzalloc(sizeof(*wm9090), GFP_KERNEL);
@@ -640,102 +649,28 @@ static int wm9090_i2c_probe(struct i2c_client *i2c,
dev_err(&i2c->dev, "Can not allocate memory\n");
return -ENOMEM;
}
- codec = &wm9090->codec;
if (i2c->dev.platform_data)
memcpy(&wm9090->pdata, i2c->dev.platform_data,
sizeof(wm9090->pdata));
- wm9090_codec = codec;
-
i2c_set_clientdata(i2c, wm9090);
+ wm9090->control_data = i2c;
+ mutex_init(&wm9090->mutex);
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
- codec->control_data = i2c;
- snd_soc_codec_set_drvdata(codec, wm9090);
- codec->dev = &i2c->dev;
- codec->name = "WM9090";
- codec->owner = THIS_MODULE;
- codec->bias_level = SND_SOC_BIAS_OFF;
- codec->set_bias_level = wm9090_set_bias_level,
- codec->reg_cache_size = WM9090_MAX_REGISTER + 1;
- codec->reg_cache = &wm9090->reg_cache;
- codec->volatile_register = wm9090_volatile;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
- }
-
- memcpy(&wm9090->reg_cache, wm9090_reg_defaults,
- sizeof(wm9090->reg_cache));
-
- ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET);
- if (ret < 0)
- goto err;
- if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) {
- dev_err(&i2c->dev, "Device is not a WM9090, ID=%x\n", ret);
- ret = -EINVAL;
- goto err;
- }
-
- ret = snd_soc_write(codec, WM9090_SOFTWARE_RESET, 0);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm9090, NULL, 0);
if (ret < 0)
- goto err;
-
- /* Configure some defaults; they will be written out when we
- * bring the bias up.
- */
- wm9090->reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU
- | WM9090_IN1A_ZC;
- wm9090->reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU
- | WM9090_IN1B_ZC;
- wm9090->reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU
- | WM9090_IN2A_ZC;
- wm9090->reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU
- | WM9090_IN2B_ZC;
- wm9090->reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |=
- WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC;
- wm9090->reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |=
- WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC;
- wm9090->reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |=
- WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC;
-
- wm9090->reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA;
-
- wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- ret = snd_soc_register_codec(codec);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
- goto err_bias;
- }
-
- return 0;
-
-err_bias:
- wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
-err:
- kfree(wm9090);
- i2c_set_clientdata(i2c, NULL);
- wm9090_codec = NULL;
-
+ kfree(wm9090);
return ret;
}
-static int wm9090_i2c_remove(struct i2c_client *i2c)
+static int __devexit wm9090_i2c_remove(struct i2c_client *i2c)
{
struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c);
- struct snd_soc_codec *codec = &wm9090->codec;
- snd_soc_unregister_codec(codec);
- wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ snd_soc_unregister_codec(&i2c->dev);
kfree(wm9090);
- wm9090_codec = NULL;
return 0;
}
@@ -748,7 +683,7 @@ MODULE_DEVICE_TABLE(i2c, wm9090_id);
static struct i2c_driver wm9090_i2c_driver = {
.driver = {
- .name = "wm9090",
+ .name = "wm9090-codec",
.owner = THIS_MODULE,
},
.probe = wm9090_i2c_probe,
diff --git a/sound/soc/codecs/wm9090.h b/sound/soc/codecs/wm9090.h
index b08eab932a5b..29b9d9fc70b4 100644
--- a/sound/soc/codecs/wm9090.h
+++ b/sound/soc/codecs/wm9090.h
@@ -23,8 +23,6 @@
#ifndef __WM9090_H
#define __WM9090_H
-extern struct snd_soc_codec_device soc_codec_dev_wm9090;
-
/*
* Register values.
*/
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index 8793341849d1..a144acda751c 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -248,8 +248,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
int reg;
u16 vra;
@@ -273,9 +272,9 @@ static struct snd_soc_dai_ops wm9705_dai_ops = {
.prepare = ac97_prepare,
};
-struct snd_soc_dai wm9705_dai[] = {
+static struct snd_soc_dai_driver wm9705_dai[] = {
{
- .name = "AC97 HiFi",
+ .name = "wm9705-hifi",
.ac97_control = 1,
.playback = {
.stream_name = "HiFi Playback",
@@ -294,7 +293,7 @@ struct snd_soc_dai wm9705_dai[] = {
.ops = &wm9705_dai_ops,
},
{
- .name = "AC97 Aux",
+ .name = "wm9705-aux",
.playback = {
.stream_name = "Aux Playback",
.channels_min = 1,
@@ -304,7 +303,6 @@ struct snd_soc_dai wm9705_dai[] = {
},
}
};
-EXPORT_SYMBOL_GPL(wm9705_dai);
static int wm9705_reset(struct snd_soc_codec *codec)
{
@@ -318,20 +316,15 @@ static int wm9705_reset(struct snd_soc_codec *codec)
}
#ifdef CONFIG_PM
-static int wm9705_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+static int wm9705_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
soc_ac97_ops.write(codec->ac97, AC97_POWERDOWN, 0xffff);
return 0;
}
-static int wm9705_soc_resume(struct platform_device *pdev)
+static int wm9705_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i, ret;
u16 *cache = codec->reg_cache;
@@ -352,49 +345,18 @@ static int wm9705_soc_resume(struct platform_device *pdev)
#define wm9705_soc_resume NULL
#endif
-static int wm9705_soc_probe(struct platform_device *pdev)
+static int wm9705_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
int ret = 0;
printk(KERN_INFO "WM9705 SoC Audio Codec\n");
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
- GFP_KERNEL);
- if (socdev->card->codec == NULL)
- return -ENOMEM;
- codec = socdev->card->codec;
- mutex_init(&codec->mutex);
-
- codec->reg_cache = kmemdup(wm9705_reg, sizeof(wm9705_reg), GFP_KERNEL);
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto cache_err;
- }
- codec->reg_cache_size = sizeof(wm9705_reg);
- codec->reg_cache_step = 2;
-
- codec->name = "WM9705";
- codec->owner = THIS_MODULE;
- codec->dai = wm9705_dai;
- codec->num_dai = ARRAY_SIZE(wm9705_dai);
- codec->write = ac97_write;
- codec->read = ac97_read;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
if (ret < 0) {
printk(KERN_ERR "wm9705: failed to register AC97 codec\n");
- goto codec_err;
+ return ret;
}
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0)
- goto pcm_err;
-
ret = wm9705_reset(codec);
if (ret)
goto reset_err;
@@ -406,40 +368,62 @@ static int wm9705_soc_probe(struct platform_device *pdev)
return 0;
reset_err:
- snd_soc_free_pcms(socdev);
-pcm_err:
snd_soc_free_ac97_codec(codec);
-codec_err:
- kfree(codec->reg_cache);
-cache_err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
return ret;
}
-static int wm9705_soc_remove(struct platform_device *pdev)
+static int wm9705_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec == NULL)
- return 0;
-
- snd_soc_dapm_free(socdev);
- snd_soc_free_pcms(socdev);
snd_soc_free_ac97_codec(codec);
- kfree(codec->reg_cache);
- kfree(codec);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_wm9705 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
.probe = wm9705_soc_probe,
.remove = wm9705_soc_remove,
.suspend = wm9705_soc_suspend,
.resume = wm9705_soc_resume,
+ .read = ac97_read,
+ .write = ac97_write,
+ .reg_cache_size = ARRAY_SIZE(wm9705_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_step = 2,
+ .reg_cache_default = wm9705_reg,
+};
+
+static __devinit int wm9705_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_wm9705, wm9705_dai, ARRAY_SIZE(wm9705_dai));
+}
+
+static int __devexit wm9705_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver wm9705_codec_driver = {
+ .driver = {
+ .name = "wm9705-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = wm9705_probe,
+ .remove = __devexit_p(wm9705_remove),
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9705);
+
+static int __init wm9705_init(void)
+{
+ return platform_driver_register(&wm9705_codec_driver);
+}
+module_init(wm9705_init);
+
+static void __exit wm9705_exit(void)
+{
+ platform_driver_unregister(&wm9705_codec_driver);
+}
+module_exit(wm9705_exit);
MODULE_DESCRIPTION("ASoC WM9705 driver");
MODULE_AUTHOR("Ian Molton");
diff --git a/sound/soc/codecs/wm9705.h b/sound/soc/codecs/wm9705.h
index d380f110f9e2..23ea9ce47359 100644
--- a/sound/soc/codecs/wm9705.h
+++ b/sound/soc/codecs/wm9705.h
@@ -8,7 +8,4 @@
#define WM9705_DAI_AC97_HIFI 0
#define WM9705_DAI_AC97_AUX 1
-extern struct snd_soc_dai wm9705_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_wm9705;
-
#endif
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 28790a2ffe8d..d2f224d62744 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -478,8 +478,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec =rtd->codec;
int reg;
u16 vra;
@@ -499,8 +498,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream,
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
u16 vra, xsle;
vra = ac97_read(codec, AC97_EXTENDED_STATUS);
@@ -526,9 +524,9 @@ static struct snd_soc_dai_ops wm9712_dai_ops_aux = {
.prepare = ac97_aux_prepare,
};
-struct snd_soc_dai wm9712_dai[] = {
+static struct snd_soc_dai_driver wm9712_dai[] = {
{
- .name = "AC97 HiFi",
+ .name = "wm9712-hifi",
.ac97_control = 1,
.playback = {
.stream_name = "HiFi Playback",
@@ -545,7 +543,7 @@ struct snd_soc_dai wm9712_dai[] = {
.ops = &wm9712_dai_ops_hifi,
},
{
- .name = "AC97 Aux",
+ .name = "wm9712-aux",
.playback = {
.stream_name = "Aux Playback",
.channels_min = 1,
@@ -555,7 +553,6 @@ struct snd_soc_dai wm9712_dai[] = {
.ops = &wm9712_dai_ops_aux,
}
};
-EXPORT_SYMBOL_GPL(wm9712_dai);
static int wm9712_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
@@ -597,20 +594,15 @@ err:
return -EIO;
}
-static int wm9712_soc_suspend(struct platform_device *pdev,
+static int wm9712_soc_suspend(struct snd_soc_codec *codec,
pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm9712_soc_resume(struct platform_device *pdev)
+static int wm9712_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
int i, ret;
u16 *cache = codec->reg_cache;
@@ -635,51 +627,18 @@ static int wm9712_soc_resume(struct platform_device *pdev)
return ret;
}
-static int wm9712_soc_probe(struct platform_device *pdev)
+static int wm9712_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
int ret = 0;
printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION);
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
- GFP_KERNEL);
- if (socdev->card->codec == NULL)
- return -ENOMEM;
- codec = socdev->card->codec;
- mutex_init(&codec->mutex);
-
- codec->reg_cache = kmemdup(wm9712_reg, sizeof(wm9712_reg), GFP_KERNEL);
-
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto cache_err;
- }
- codec->reg_cache_size = sizeof(wm9712_reg);
- codec->reg_cache_step = 2;
-
- codec->name = "WM9712";
- codec->owner = THIS_MODULE;
- codec->dai = wm9712_dai;
- codec->num_dai = ARRAY_SIZE(wm9712_dai);
- codec->write = ac97_write;
- codec->read = ac97_read;
- codec->set_bias_level = wm9712_set_bias_level;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
-
ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
if (ret < 0) {
printk(KERN_ERR "wm9712: failed to register AC97 codec\n");
- goto codec_err;
+ return ret;
}
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0)
- goto pcm_err;
-
ret = wm9712_reset(codec, 0);
if (ret < 0) {
printk(KERN_ERR "Failed to reset WM9712: AC97 link error\n");
@@ -697,42 +656,63 @@ static int wm9712_soc_probe(struct platform_device *pdev)
return 0;
reset_err:
- snd_soc_free_pcms(socdev);
-pcm_err:
snd_soc_free_ac97_codec(codec);
-
-codec_err:
- kfree(codec->reg_cache);
-
-cache_err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
return ret;
}
-static int wm9712_soc_remove(struct platform_device *pdev)
+static int wm9712_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec == NULL)
- return 0;
-
- snd_soc_dapm_free(socdev);
- snd_soc_free_pcms(socdev);
snd_soc_free_ac97_codec(codec);
- kfree(codec->reg_cache);
- kfree(codec);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_wm9712 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9712 = {
.probe = wm9712_soc_probe,
.remove = wm9712_soc_remove,
.suspend = wm9712_soc_suspend,
.resume = wm9712_soc_resume,
+ .read = ac97_read,
+ .write = ac97_write,
+ .set_bias_level = wm9712_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm9712_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_step = 2,
+ .reg_cache_default = wm9712_reg,
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9712);
+
+static __devinit int wm9712_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai));
+}
+
+static int __devexit wm9712_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver wm9712_codec_driver = {
+ .driver = {
+ .name = "wm9712-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = wm9712_probe,
+ .remove = __devexit_p(wm9712_remove),
+};
+
+static int __init wm9712_init(void)
+{
+ return platform_driver_register(&wm9712_codec_driver);
+}
+module_init(wm9712_init);
+
+static void __exit wm9712_exit(void)
+{
+ platform_driver_unregister(&wm9712_codec_driver);
+}
+module_exit(wm9712_exit);
MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver");
MODULE_AUTHOR("Liam Girdwood");
diff --git a/sound/soc/codecs/wm9712.h b/sound/soc/codecs/wm9712.h
index d29e8a18ca6d..fb69c3aa4ed0 100644
--- a/sound/soc/codecs/wm9712.h
+++ b/sound/soc/codecs/wm9712.h
@@ -8,7 +8,4 @@
#define WM9712_DAI_AC97_HIFI 0
#define WM9712_DAI_AC97_AUX 1
-extern struct snd_soc_dai wm9712_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_wm9712;
-
#endif
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 34e0c91092fa..7da13b07a53d 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -1057,9 +1057,9 @@ static struct snd_soc_dai_ops wm9713_dai_ops_voice = {
.set_tristate = wm9713_set_dai_tristate,
};
-struct snd_soc_dai wm9713_dai[] = {
+static struct snd_soc_dai_driver wm9713_dai[] = {
{
- .name = "AC97 HiFi",
+ .name = "wm9713-hifi",
.ac97_control = 1,
.playback = {
.stream_name = "HiFi Playback",
@@ -1076,7 +1076,7 @@ struct snd_soc_dai wm9713_dai[] = {
.ops = &wm9713_dai_ops_hifi,
},
{
- .name = "AC97 Aux",
+ .name = "wm9713-aux",
.playback = {
.stream_name = "Aux Playback",
.channels_min = 1,
@@ -1086,7 +1086,7 @@ struct snd_soc_dai wm9713_dai[] = {
.ops = &wm9713_dai_ops_aux,
},
{
- .name = "WM9713 Voice",
+ .name = "wm9713-voice",
.playback = {
.stream_name = "Voice Playback",
.channels_min = 1,
@@ -1103,7 +1103,6 @@ struct snd_soc_dai wm9713_dai[] = {
.symmetric_rates = 1,
},
};
-EXPORT_SYMBOL_GPL(wm9713_dai);
int wm9713_reset(struct snd_soc_codec *codec, int try_warm)
{
@@ -1152,11 +1151,9 @@ static int wm9713_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static int wm9713_soc_suspend(struct platform_device *pdev,
+static int wm9713_soc_suspend(struct snd_soc_codec *codec,
pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
u16 reg;
/* Disable everything except touchpanel - that will be handled
@@ -1171,10 +1168,8 @@ static int wm9713_soc_suspend(struct platform_device *pdev,
return 0;
}
-static int wm9713_soc_resume(struct platform_device *pdev)
+static int wm9713_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
int i, ret;
u16 *cache = codec->reg_cache;
@@ -1204,53 +1199,20 @@ static int wm9713_soc_resume(struct platform_device *pdev)
return ret;
}
-static int wm9713_soc_probe(struct platform_device *pdev)
+static int wm9713_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec;
+ struct wm9713_priv *wm9713;
int ret = 0, reg;
- socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
- GFP_KERNEL);
- if (socdev->card->codec == NULL)
+ wm9713 = kzalloc(sizeof(struct wm9713_priv), GFP_KERNEL);
+ if (wm9713 == NULL)
return -ENOMEM;
- codec = socdev->card->codec;
- mutex_init(&codec->mutex);
-
- codec->reg_cache = kmemdup(wm9713_reg, sizeof(wm9713_reg), GFP_KERNEL);
- if (codec->reg_cache == NULL) {
- ret = -ENOMEM;
- goto cache_err;
- }
- codec->reg_cache_size = sizeof(wm9713_reg);
- codec->reg_cache_step = 2;
-
- snd_soc_codec_set_drvdata(codec, kzalloc(sizeof(struct wm9713_priv),
- GFP_KERNEL));
- if (snd_soc_codec_get_drvdata(codec) == NULL) {
- ret = -ENOMEM;
- goto priv_err;
- }
-
- codec->name = "WM9713";
- codec->owner = THIS_MODULE;
- codec->dai = wm9713_dai;
- codec->num_dai = ARRAY_SIZE(wm9713_dai);
- codec->write = ac97_write;
- codec->read = ac97_read;
- codec->set_bias_level = wm9713_set_bias_level;
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
+ snd_soc_codec_set_drvdata(codec, wm9713);
ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
if (ret < 0)
goto codec_err;
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0)
- goto pcm_err;
-
/* do a cold reset for the controller and then try
* a warm reset followed by an optional cold reset for codec */
wm9713_reset(codec, 0);
@@ -1273,46 +1235,67 @@ static int wm9713_soc_probe(struct platform_device *pdev)
return 0;
reset_err:
- snd_soc_free_pcms(socdev);
-pcm_err:
snd_soc_free_ac97_codec(codec);
-
codec_err:
- kfree(snd_soc_codec_get_drvdata(codec));
-
-priv_err:
- kfree(codec->reg_cache);
-
-cache_err:
- kfree(socdev->card->codec);
- socdev->card->codec = NULL;
+ kfree(wm9713);
return ret;
}
-static int wm9713_soc_remove(struct platform_device *pdev)
+static int wm9713_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec == NULL)
- return 0;
-
- snd_soc_dapm_free(socdev);
- snd_soc_free_pcms(socdev);
+ struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
snd_soc_free_ac97_codec(codec);
- kfree(snd_soc_codec_get_drvdata(codec));
- kfree(codec->reg_cache);
- kfree(codec);
+ kfree(wm9713);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_wm9713 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9713 = {
.probe = wm9713_soc_probe,
.remove = wm9713_soc_remove,
.suspend = wm9713_soc_suspend,
.resume = wm9713_soc_resume,
+ .read = ac97_read,
+ .write = ac97_write,
+ .set_bias_level = wm9713_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(wm9713_reg),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_step = 2,
+ .reg_cache_default = wm9713_reg,
+};
+
+static __devinit int wm9713_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai));
+}
+
+static int __devexit wm9713_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver wm9713_codec_driver = {
+ .driver = {
+ .name = "wm9713-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = wm9713_probe,
+ .remove = __devexit_p(wm9713_remove),
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9713);
+
+static int __init wm9713_init(void)
+{
+ return platform_driver_register(&wm9713_codec_driver);
+}
+module_init(wm9713_init);
+
+static void __exit wm9713_exit(void)
+{
+ platform_driver_unregister(&wm9713_codec_driver);
+}
+module_exit(wm9713_exit);
MODULE_DESCRIPTION("ASoC WM9713/WM9714 driver");
MODULE_AUTHOR("Liam Girdwood");
diff --git a/sound/soc/codecs/wm9713.h b/sound/soc/codecs/wm9713.h
index 63b8d81756e3..793da863a03d 100644
--- a/sound/soc/codecs/wm9713.h
+++ b/sound/soc/codecs/wm9713.h
@@ -45,9 +45,6 @@
#define WM9713_DAI_AC97_AUX 1
#define WM9713_DAI_PCM_VOICE 2
-extern struct snd_soc_codec_device soc_codec_dev_wm9713;
-extern struct snd_soc_dai wm9713_dai[3];
-
int wm9713_reset(struct snd_soc_codec *codec, int try_warm);
#endif
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 97f74d6a33e6..2b07b17a6b2d 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -28,12 +28,9 @@
#include <mach/mux.h>
#include "../codecs/tlv320aic3x.h"
-#include "../codecs/cq93vc.h"
-#include "../codecs/spdif_transciever.h"
#include "davinci-pcm.h"
#include "davinci-i2s.h"
#include "davinci-mcasp.h"
-#include "davinci-vcif.h"
#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF)
@@ -41,8 +38,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0;
unsigned sysclk;
@@ -87,7 +84,7 @@ static int evm_spdif_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
/* set cpu DAI configuration */
return snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
@@ -132,8 +129,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
};
/* Logic for a aic3x as connected on a davinci-evm */
-static int evm_aic3x_init(struct snd_soc_codec *codec)
+static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
/* Add davinci-evm specific widgets */
snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
ARRAY_SIZE(aic3x_dapm_widgets));
@@ -161,8 +160,10 @@ static int evm_aic3x_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link evm_dai = {
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
- .cpu_dai = &davinci_i2s_dai,
- .codec_dai = &aic3x_dai,
+ .cpu_dai_name = "davinci-mcasp.0",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .codec_name = "tlv320aic3x-codec.0-001a",
+ .platform_name = "davinci-pcm-audio",
.init = evm_aic3x_init,
.ops = &evm_ops,
};
@@ -171,40 +172,49 @@ static struct snd_soc_dai_link dm365_evm_dai = {
#ifdef CONFIG_SND_DM365_AIC3X_CODEC
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
- .cpu_dai = &davinci_i2s_dai,
- .codec_dai = &aic3x_dai,
+ .cpu_dai_name = "davinci-i2s",
+ .codec_dai_name = "tlv320aic3x-hifi",
.init = evm_aic3x_init,
+ .codec_name = "tlv320aic3x-codec.0-001a",
.ops = &evm_ops,
#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
.name = "Voice Codec - CQ93VC",
.stream_name = "CQ93",
- .cpu_dai = &davinci_vcif_dai,
- .codec_dai = &cq93vc_dai,
+ .cpu_dai_name = "davinci-vcif",
+ .codec_dai_name = "cq93vc-hifi",
+ .codec_name = "cq93vc-codec",
#endif
+ .platform_name = "davinci-pcm-audio",
};
static struct snd_soc_dai_link dm6467_evm_dai[] = {
{
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
- .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI],
- .codec_dai = &aic3x_dai,
+ .cpu_dai_name= "davinci-mcasp.0",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .platform_name ="davinci-pcm-audio",
+ .codec_name = "tlv320aic3x-codec.0-001a",
.init = evm_aic3x_init,
.ops = &evm_ops,
},
{
.name = "McASP",
.stream_name = "spdif",
- .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_DIT_DAI],
- .codec_dai = &dit_stub_dai,
+ .cpu_dai_name= "davinci-mcasp.1",
+ .codec_dai_name = "dit-hifi",
+ .codec_name = "spdif_dit",
+ .platform_name = "davinci-pcm-audio",
.ops = &evm_spdif_ops,
},
};
static struct snd_soc_dai_link da8xx_evm_dai = {
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
- .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI],
- .codec_dai = &aic3x_dai,
+ .cpu_dai_name= "davinci-mcasp.0",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .codec_name = "tlv320aic3x-codec.0-001a",
+ .platform_name = "davinci-pcm-audio",
.init = evm_aic3x_init,
.ops = &evm_ops,
};
@@ -212,7 +222,6 @@ static struct snd_soc_dai_link da8xx_evm_dai = {
/* davinci dm6446, dm355 evm audio machine driver */
static struct snd_soc_card snd_soc_card_evm = {
.name = "DaVinci EVM",
- .platform = &davinci_soc_platform,
.dai_link = &evm_dai,
.num_links = 1,
};
@@ -220,16 +229,13 @@ static struct snd_soc_card snd_soc_card_evm = {
/* davinci dm365 evm audio machine driver */
static struct snd_soc_card dm365_snd_soc_card_evm = {
.name = "DaVinci DM365 EVM",
- .platform = &davinci_soc_platform,
.dai_link = &dm365_evm_dai,
.num_links = 1,
};
-
/* davinci dm6467 evm audio machine driver */
static struct snd_soc_card dm6467_snd_soc_card_evm = {
.name = "DaVinci DM6467 EVM",
- .platform = &davinci_soc_platform,
.dai_link = dm6467_evm_dai,
.num_links = ARRAY_SIZE(dm6467_evm_dai),
};
@@ -237,82 +243,40 @@ static struct snd_soc_card dm6467_snd_soc_card_evm = {
static struct snd_soc_card da830_snd_soc_card = {
.name = "DA830/OMAP-L137 EVM",
.dai_link = &da8xx_evm_dai,
- .platform = &davinci_soc_platform,
.num_links = 1,
};
static struct snd_soc_card da850_snd_soc_card = {
.name = "DA850/OMAP-L138 EVM",
.dai_link = &da8xx_evm_dai,
- .platform = &davinci_soc_platform,
.num_links = 1,
};
-static struct aic3x_setup_data aic3x_setup;
-
-/* evm audio subsystem */
-static struct snd_soc_device evm_snd_devdata = {
- .card = &snd_soc_card_evm,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &aic3x_setup,
-};
-
-/* evm audio subsystem */
-static struct snd_soc_device dm365_evm_snd_devdata = {
- .card = &dm365_snd_soc_card_evm,
-#ifdef CONFIG_SND_DM365_AIC3X_CODEC
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &aic3x_setup,
-#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
- .codec_dev = &soc_codec_dev_cq93vc,
-#endif
-};
-
-/* evm audio subsystem */
-static struct snd_soc_device dm6467_evm_snd_devdata = {
- .card = &dm6467_snd_soc_card_evm,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &aic3x_setup,
-};
-
-/* evm audio subsystem */
-static struct snd_soc_device da830_evm_snd_devdata = {
- .card = &da830_snd_soc_card,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &aic3x_setup,
-};
-
-static struct snd_soc_device da850_evm_snd_devdata = {
- .card = &da850_snd_soc_card,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &aic3x_setup,
-};
-
static struct platform_device *evm_snd_device;
static int __init evm_init(void)
{
- struct snd_soc_device *evm_snd_dev_data;
+ struct snd_soc_card *evm_snd_dev_data;
int index;
int ret;
if (machine_is_davinci_evm()) {
- evm_snd_dev_data = &evm_snd_devdata;
+ evm_snd_dev_data = &snd_soc_card_evm;
index = 0;
} else if (machine_is_davinci_dm355_evm()) {
- evm_snd_dev_data = &evm_snd_devdata;
+ evm_snd_dev_data = &snd_soc_card_evm;
index = 1;
} else if (machine_is_davinci_dm365_evm()) {
- evm_snd_dev_data = &dm365_evm_snd_devdata;
+ evm_snd_dev_data = &dm365_snd_soc_card_evm;
index = 0;
} else if (machine_is_davinci_dm6467_evm()) {
- evm_snd_dev_data = &dm6467_evm_snd_devdata;
+ evm_snd_dev_data = &dm6467_snd_soc_card_evm;
index = 0;
} else if (machine_is_davinci_da830_evm()) {
- evm_snd_dev_data = &da830_evm_snd_devdata;
+ evm_snd_dev_data = &da830_snd_soc_card;
index = 1;
} else if (machine_is_davinci_da850_evm()) {
- evm_snd_dev_data = &da850_evm_snd_devdata;
+ evm_snd_dev_data = &da850_snd_soc_card;
index = 0;
} else
return -EINVAL;
@@ -322,7 +286,6 @@ static int __init evm_init(void)
return -ENOMEM;
platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
- evm_snd_dev_data->dev = &evm_snd_device->dev;
ret = platform_device_add(evm_snd_device);
if (ret)
platform_device_put(evm_snd_device);
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index 9e8932abf158..d46b545d41f4 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -183,8 +183,7 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_platform *platform = socdev->card->platform;
+ struct snd_soc_platform *platform = rtd->platform;
int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
u32 spcr;
u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST;
@@ -205,8 +204,8 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
if (playback) {
/* Stop the DMA to avoid data loss */
/* while the transmitter is out of reset to handle XSYNCERR */
- if (platform->pcm_ops->trigger) {
- int ret = platform->pcm_ops->trigger(substream,
+ if (platform->driver->ops->trigger) {
+ int ret = platform->driver->ops->trigger(substream,
SNDRV_PCM_TRIGGER_STOP);
if (ret < 0)
printk(KERN_DEBUG "Playback DMA stop failed\n");
@@ -227,8 +226,8 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
toggle_clock(dev, playback);
/* Restart the DMA */
- if (platform->pcm_ops->trigger) {
- int ret = platform->pcm_ops->trigger(substream,
+ if (platform->driver->ops->trigger) {
+ int ret = platform->driver->ops->trigger(substream,
SNDRV_PCM_TRIGGER_START);
if (ret < 0)
printk(KERN_DEBUG "Playback DMA start failed\n");
@@ -263,7 +262,7 @@ static void davinci_mcbsp_stop(struct davinci_mcbsp_dev *dev, int playback)
static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
+ struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
unsigned int pcr;
unsigned int srgr;
/* Attention srgr is updated by hw_params! */
@@ -404,7 +403,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div)
{
- struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
+ struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
if (div_id != DAVINCI_MCBSP_CLKGDV)
return -ENODEV;
@@ -417,7 +416,7 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct davinci_mcbsp_dev *dev = dai->private_data;
+ struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
struct davinci_pcm_dma_params *dma_params =
&dev->dma_params[substream->stream];
struct snd_interval *i = NULL;
@@ -427,6 +426,9 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
snd_pcm_format_t fmt;
unsigned element_cnt = 1;
+ dai->capture_dma_data = dev->dma_params;
+ dai->playback_dma_data = dev->dma_params;
+
/* general line settings */
spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
@@ -569,24 +571,18 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
static int davinci_i2s_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct davinci_mcbsp_dev *dev = dai->private_data;
+ struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
davinci_mcbsp_stop(dev, playback);
- if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) {
- /* codec is master */
- davinci_mcbsp_start(dev, substream);
- }
return 0;
}
static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct davinci_mcbsp_dev *dev = dai->private_data;
+ struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
int ret = 0;
int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
- if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0)
- return 0; /* return if codec is master */
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -608,7 +604,7 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct davinci_mcbsp_dev *dev = dai->private_data;
+ struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
davinci_mcbsp_stop(dev, playback);
}
@@ -625,9 +621,7 @@ static struct snd_soc_dai_ops davinci_i2s_dai_ops = {
};
-struct snd_soc_dai davinci_i2s_dai = {
- .name = "davinci-i2s",
- .id = 0,
+static struct snd_soc_dai_driver davinci_i2s_dai = {
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -641,7 +635,6 @@ struct snd_soc_dai davinci_i2s_dai = {
.ops = &davinci_i2s_dai_ops,
};
-EXPORT_SYMBOL_GPL(davinci_i2s_dai);
static int davinci_i2s_probe(struct platform_device *pdev)
{
@@ -720,10 +713,9 @@ static int davinci_i2s_probe(struct platform_device *pdev)
dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
dev->dev = &pdev->dev;
- davinci_i2s_dai.private_data = dev;
- davinci_i2s_dai.capture.dma_data = dev->dma_params;
- davinci_i2s_dai.playback.dma_data = dev->dma_params;
- ret = snd_soc_register_dai(&davinci_i2s_dai);
+ dev_set_drvdata(&pdev->dev, dev);
+
+ ret = snd_soc_register_dai(&pdev->dev, &davinci_i2s_dai);
if (ret != 0)
goto err_free_mem;
@@ -739,10 +731,10 @@ err_release_region:
static int davinci_i2s_remove(struct platform_device *pdev)
{
- struct davinci_mcbsp_dev *dev = davinci_i2s_dai.private_data;
+ struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
struct resource *mem;
- snd_soc_unregister_dai(&davinci_i2s_dai);
+ snd_soc_unregister_dai(&pdev->dev);
clk_disable(dev->clk);
clk_put(dev->clk);
dev->clk = NULL;
@@ -757,7 +749,7 @@ static struct platform_driver davinci_mcbsp_driver = {
.probe = davinci_i2s_probe,
.remove = davinci_i2s_remove,
.driver = {
- .name = "davinci-asp",
+ .name = "davinci-i2s",
.owner = THIS_MODULE,
},
};
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/davinci/davinci-i2s.h
index 0b1e77b8c279..48dac3e2521a 100644
--- a/sound/soc/davinci/davinci-i2s.h
+++ b/sound/soc/davinci/davinci-i2s.h
@@ -17,6 +17,4 @@ enum davinci_mcbsp_div {
DAVINCI_MCBSP_CLKGDV, /* Sample rate generator divider */
};
-extern struct snd_soc_dai davinci_i2s_dai;
-
#endif
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index b24720894af6..86918ee12419 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -422,7 +422,7 @@ static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream)
static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct davinci_audio_dev *dev = cpu_dai->private_data;
+ struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
void __iomem *base = dev->base;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -709,12 +709,15 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct davinci_audio_dev *dev = cpu_dai->private_data;
+ struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
struct davinci_pcm_dma_params *dma_params =
&dev->dma_params[substream->stream];
int word_length;
u8 fifo_level;
+ cpu_dai->capture_dma_data = dev->dma_params;
+ cpu_dai->playback_dma_data = dev->dma_params;
+
davinci_hw_common_param(dev, substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
fifo_level = dev->txnumevt;
@@ -761,8 +764,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct davinci_audio_dev *dev = rtd->dai->cpu_dai->private_data;
+ struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
int ret = 0;
switch (cmd) {
@@ -804,10 +806,9 @@ static struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
};
-struct snd_soc_dai davinci_mcasp_dai[] = {
+static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
{
- .name = "davinci-i2s",
- .id = 0,
+ .name = "davinci-mcasp.0",
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -828,8 +829,7 @@ struct snd_soc_dai davinci_mcasp_dai[] = {
},
{
- .name = "davinci-dit",
- .id = 1,
+ "davinci-mcasp.1",
.playback = {
.channels_min = 1,
.channels_max = 384,
@@ -840,7 +840,6 @@ struct snd_soc_dai davinci_mcasp_dai[] = {
},
};
-EXPORT_SYMBOL_GPL(davinci_mcasp_dai);
static int davinci_mcasp_probe(struct platform_device *pdev)
{
@@ -899,6 +898,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
+ ret = -ENODEV;
goto err_release_region;
}
@@ -913,15 +913,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
+ ret = -ENODEV;
goto err_release_region;
}
dma_data->channel = res->start;
- davinci_mcasp_dai[pdata->op_mode].private_data = dev;
- davinci_mcasp_dai[pdata->op_mode].capture.dma_data = dev->dma_params;
- davinci_mcasp_dai[pdata->op_mode].playback.dma_data = dev->dma_params;
- davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev;
- ret = snd_soc_register_dai(&davinci_mcasp_dai[pdata->op_mode]);
+ dev_set_drvdata(&pdev->dev, dev);
+ ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]);
if (ret != 0)
goto err_release_region;
@@ -937,12 +935,10 @@ err_release_data:
static int davinci_mcasp_remove(struct platform_device *pdev)
{
- struct snd_platform_data *pdata = pdev->dev.platform_data;
- struct davinci_audio_dev *dev;
+ struct davinci_audio_dev *dev = dev_get_drvdata(&pdev->dev);
struct resource *mem;
- snd_soc_unregister_dai(&davinci_mcasp_dai[pdata->op_mode]);
- dev = davinci_mcasp_dai[pdata->op_mode].private_data;
+ snd_soc_unregister_dai(&pdev->dev);
clk_disable(dev->clk);
clk_put(dev->clk);
dev->clk = NULL;
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h
index e755b5121ec7..4681acc63606 100644
--- a/sound/soc/davinci/davinci-mcasp.h
+++ b/sound/soc/davinci/davinci-mcasp.h
@@ -22,8 +22,6 @@
#include <mach/asp.h>
#include "davinci-pcm.h"
-extern struct snd_soc_dai davinci_mcasp_dai[];
-
#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_96000
#define DAVINCI_MCASP_I2S_DAI 0
#define DAVINCI_MCASP_DIT_DAI 1
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index a7124116d2e0..9d35b8c1a624 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -653,7 +653,7 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream)
struct davinci_pcm_dma_params *pa;
struct davinci_pcm_dma_params *params;
- pa = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ pa = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
if (!pa)
return -ENODEV;
params = &pa[substream->stream];
@@ -821,7 +821,7 @@ static int davinci_pcm_new(struct snd_card *card,
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = 0xffffffff;
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = davinci_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK,
pcm_hardware_playback.buffer_bytes_max);
@@ -829,7 +829,7 @@ static int davinci_pcm_new(struct snd_card *card,
return ret;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = davinci_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE,
pcm_hardware_capture.buffer_bytes_max);
@@ -840,25 +840,44 @@ static int davinci_pcm_new(struct snd_card *card,
return 0;
}
-struct snd_soc_platform davinci_soc_platform = {
- .name = "davinci-audio",
- .pcm_ops = &davinci_pcm_ops,
+static struct snd_soc_platform_driver davinci_soc_platform = {
+ .ops = &davinci_pcm_ops,
.pcm_new = davinci_pcm_new,
.pcm_free = davinci_pcm_free,
};
-EXPORT_SYMBOL_GPL(davinci_soc_platform);
-static int __init davinci_soc_platform_init(void)
+static int __devinit davinci_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&davinci_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &davinci_soc_platform);
}
-module_init(davinci_soc_platform_init);
-static void __exit davinci_soc_platform_exit(void)
+static int __devexit davinci_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&davinci_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver davinci_pcm_driver = {
+ .driver = {
+ .name = "davinci-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = davinci_soc_platform_probe,
+ .remove = __devexit_p(davinci_soc_platform_remove),
+};
+
+static int __init snd_davinci_pcm_init(void)
+{
+ return platform_driver_register(&davinci_pcm_driver);
+}
+module_init(snd_davinci_pcm_init);
+
+static void __exit snd_davinci_pcm_exit(void)
+{
+ platform_driver_unregister(&davinci_pcm_driver);
}
-module_exit(davinci_soc_platform_exit);
+module_exit(snd_davinci_pcm_exit);
MODULE_AUTHOR("Vladimir Barinov");
MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
index b799a02333d8..c0d6c9be4b4d 100644
--- a/sound/soc/davinci/davinci-pcm.h
+++ b/sound/soc/davinci/davinci-pcm.h
@@ -28,7 +28,4 @@ struct davinci_pcm_dma_params {
unsigned int fifo_level;
};
-
-extern struct snd_soc_platform davinci_soc_platform;
-
#endif
diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c
index 40eccfe9e358..009b6521a1bf 100644
--- a/sound/soc/davinci/davinci-sffsdr.c
+++ b/sound/soc/davinci/davinci-sffsdr.c
@@ -29,7 +29,6 @@
#include <asm/plat-sffsdr/sffsdr-fpga.h>
#endif
-#include <mach/mcbsp.h>
#include <mach/edma.h>
#include "../codecs/pcm3008.h"
@@ -48,7 +47,7 @@ static int sffsdr_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int fs;
int ret = 0;
@@ -85,15 +84,16 @@ static struct snd_soc_ops sffsdr_ops = {
static struct snd_soc_dai_link sffsdr_dai = {
.name = "PCM3008", /* Codec name */
.stream_name = "PCM3008 HiFi",
- .cpu_dai = &davinci_i2s_dai,
- .codec_dai = &pcm3008_dai,
+ .cpu_dai_name = "davinci-asp.0",
+ .codec_dai_name = "pcm3008-hifi",
+ .codec_name = "pcm3008-codec",
+ .platform_name = "davinci-pcm-audio",
.ops = &sffsdr_ops,
};
/* davinci-sffsdr audio machine driver */
static struct snd_soc_card snd_soc_sffsdr = {
.name = "DaVinci SFFSDR",
- .platform = &davinci_soc_platform,
.dai_link = &sffsdr_dai,
.num_links = 1,
};
@@ -106,11 +106,12 @@ static struct pcm3008_setup_data sffsdr_pcm3008_setup = {
.pdda_pin = GPIO(38),
};
-/* sffsdr audio subsystem */
-static struct snd_soc_device sffsdr_snd_devdata = {
- .card = &snd_soc_sffsdr,
- .codec_dev = &soc_codec_dev_pcm3008,
- .codec_data = &sffsdr_pcm3008_setup,
+struct platform_device pcm3008_codec = {
+ .name = "pcm3008-codec",
+ .id = 0,
+ .dev = {
+ .platform_data = &sffsdr_pcm3008_setup,
+ },
};
static struct resource sffsdr_snd_resources[] = {
@@ -135,14 +136,15 @@ static int __init sffsdr_init(void)
if (!machine_is_sffsdr())
return -EINVAL;
+ platform_device_register(&pcm3008_codec);
+
sffsdr_snd_device = platform_device_alloc("soc-audio", 0);
if (!sffsdr_snd_device) {
printk(KERN_ERR "platform device allocation failed\n");
return -ENOMEM;
}
- platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata);
- sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev;
+ platform_set_drvdata(sffsdr_snd_device, &snd_soc_sffsdr);
platform_device_add_data(sffsdr_snd_device, &sffsdr_snd_data,
sizeof(sffsdr_snd_data));
@@ -150,7 +152,7 @@ static int __init sffsdr_init(void)
sffsdr_snd_resources,
ARRAY_SIZE(sffsdr_snd_resources));
if (ret) {
- printk(KERN_ERR "platform device add ressources failed\n");
+ printk(KERN_ERR "platform device add resources failed\n");
goto error;
}
@@ -168,6 +170,7 @@ error:
static void __exit sffsdr_exit(void)
{
platform_device_unregister(sffsdr_snd_device);
+ platform_device_unregister(&pcm3008_codec);
}
module_init(sffsdr_init);
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c
index 48678533da7a..ea232f6a2c21 100644
--- a/sound/soc/davinci/davinci-vcif.c
+++ b/sound/soc/davinci/davinci-vcif.c
@@ -36,7 +36,6 @@
#include "davinci-pcm.h"
#include "davinci-i2s.h"
-#include "davinci-vcif.h"
#define MOD_REG_BIT(val, mask, set) do { \
if (set) { \
@@ -55,7 +54,7 @@ static void davinci_vcif_start(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct davinci_vcif_dev *davinci_vcif_dev =
- rtd->dai->cpu_dai->private_data;
+ snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
u32 w;
@@ -74,7 +73,7 @@ static void davinci_vcif_stop(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct davinci_vcif_dev *davinci_vcif_dev =
- rtd->dai->cpu_dai->private_data;
+ snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
u32 w;
@@ -92,12 +91,15 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct davinci_vcif_dev *davinci_vcif_dev = dai->private_data;
+ struct davinci_vcif_dev *davinci_vcif_dev = snd_soc_dai_get_drvdata(dai);
struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
struct davinci_pcm_dma_params *dma_params =
&davinci_vcif_dev->dma_params[substream->stream];
u32 w;
+ dai->capture_dma_data = davinci_vcif_dev->dma_params;
+ dai->playback_dma_data = davinci_vcif_dev->dma_params;
+
/* Restart the codec before setup */
davinci_vcif_stop(substream);
davinci_vcif_start(substream);
@@ -179,8 +181,7 @@ static struct snd_soc_dai_ops davinci_vcif_dai_ops = {
.hw_params = davinci_vcif_hw_params,
};
-struct snd_soc_dai davinci_vcif_dai = {
- .name = "davinci-vcif",
+static struct snd_soc_dai_driver davinci_vcif_dai = {
.playback = {
.channels_min = 1,
.channels_max = 2,
@@ -194,7 +195,6 @@ struct snd_soc_dai davinci_vcif_dai = {
.ops = &davinci_vcif_dai_ops,
};
-EXPORT_SYMBOL_GPL(davinci_vcif_dai);
static int davinci_vcif_probe(struct platform_device *pdev)
{
@@ -222,12 +222,9 @@ static int davinci_vcif_probe(struct platform_device *pdev)
davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr =
davinci_vc->davinci_vcif.dma_rx_addr;
- davinci_vcif_dai.dev = &pdev->dev;
- davinci_vcif_dai.capture.dma_data = davinci_vcif_dev->dma_params;
- davinci_vcif_dai.playback.dma_data = davinci_vcif_dev->dma_params;
- davinci_vcif_dai.private_data = davinci_vcif_dev;
+ dev_set_drvdata(&pdev->dev, davinci_vcif_dev);
- ret = snd_soc_register_dai(&davinci_vcif_dai);
+ ret = snd_soc_register_dai(&pdev->dev, &davinci_vcif_dai);
if (ret != 0) {
dev_err(&pdev->dev, "could not register dai\n");
goto fail;
@@ -243,7 +240,7 @@ fail:
static int davinci_vcif_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&davinci_vcif_dai);
+ snd_soc_unregister_dai(&pdev->dev);
return 0;
}
@@ -252,7 +249,7 @@ static struct platform_driver davinci_vcif_driver = {
.probe = davinci_vcif_probe,
.remove = davinci_vcif_remove,
.driver = {
- .name = "davinci_vcif",
+ .name = "davinci-vcif",
.owner = THIS_MODULE,
},
};
diff --git a/sound/soc/davinci/davinci-vcif.h b/sound/soc/davinci/davinci-vcif.h
deleted file mode 100644
index 571c9948724f..000000000000
--- a/sound/soc/davinci/davinci-vcif.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * ALSA SoC Voice Codec Interface for TI DAVINCI processor
- *
- * Copyright (C) 2010 Texas Instruments.
- *
- * Author: Miguel Aguilar <miguel.aguilar@ridgerun.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 _DAVINCI_VCIF_H
-#define _DAVINCI_VCIF_H
-
-extern struct snd_soc_dai davinci_vcif_dai;
-
-#endif
diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/ep93xx/Kconfig
index f617f560f46b..57429041189c 100644
--- a/sound/soc/ep93xx/Kconfig
+++ b/sound/soc/ep93xx/Kconfig
@@ -3,11 +3,16 @@ config SND_EP93XX_SOC
depends on ARCH_EP93XX && SND_SOC
help
Say Y or M if you want to add support for codecs attached to
- the EP93xx I2S interface.
+ the EP93xx I2S or AC97 interfaces.
config SND_EP93XX_SOC_I2S
tristate
+config SND_EP93XX_SOC_AC97
+ tristate
+ select AC97_BUS
+ select SND_SOC_AC97_BUS
+
config SND_EP93XX_SOC_SNAPPERCL15
tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
@@ -16,3 +21,12 @@ config SND_EP93XX_SOC_SNAPPERCL15
help
Say Y or M here if you want to add support for I2S audio on the
Bluewater Systems Snapper CL15 module.
+
+config SND_EP93XX_SOC_SIMONE
+ tristate "SoC Audio support for Simplemachines Sim.One board"
+ depends on SND_EP93XX_SOC && MACH_SIM_ONE
+ select SND_EP93XX_SOC_AC97
+ select SND_SOC_AC97_CODEC
+ help
+ Say Y or M here if you want to add support for AC97 audio on the
+ Simplemachines Sim.One board.
diff --git a/sound/soc/ep93xx/Makefile b/sound/soc/ep93xx/Makefile
index 272e60f57b9a..8e7977fb6b7d 100644
--- a/sound/soc/ep93xx/Makefile
+++ b/sound/soc/ep93xx/Makefile
@@ -1,11 +1,15 @@
# EP93xx Platform Support
snd-soc-ep93xx-objs := ep93xx-pcm.o
snd-soc-ep93xx-i2s-objs := ep93xx-i2s.o
+snd-soc-ep93xx-ac97-objs := ep93xx-ac97.o
obj-$(CONFIG_SND_EP93XX_SOC) += snd-soc-ep93xx.o
obj-$(CONFIG_SND_EP93XX_SOC_I2S) += snd-soc-ep93xx-i2s.o
+obj-$(CONFIG_SND_EP93XX_SOC_AC97) += snd-soc-ep93xx-ac97.o
# EP93XX Machine Support
snd-soc-snappercl15-objs := snappercl15.o
+snd-soc-simone-objs := simone.o
obj-$(CONFIG_SND_EP93XX_SOC_SNAPPERCL15) += snd-soc-snappercl15.o
+obj-$(CONFIG_SND_EP93XX_SOC_SIMONE) += snd-soc-simone.o
diff --git a/sound/soc/ep93xx/ep93xx-ac97.c b/sound/soc/ep93xx/ep93xx-ac97.c
new file mode 100644
index 000000000000..68a0bae1208a
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-ac97.c
@@ -0,0 +1,468 @@
+/*
+ * ASoC driver for Cirrus Logic EP93xx AC97 controller.
+ *
+ * Copyright (c) 2010 Mika Westerberg
+ *
+ * Based on s3c-ac97 ASoC driver by Jaswinder Singh.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/ac97_codec.h>
+#include <sound/soc.h>
+
+#include <mach/dma.h>
+#include "ep93xx-pcm.h"
+
+/*
+ * Per channel (1-4) registers.
+ */
+#define AC97CH(n) (((n) - 1) * 0x20)
+
+#define AC97DR(n) (AC97CH(n) + 0x0000)
+
+#define AC97RXCR(n) (AC97CH(n) + 0x0004)
+#define AC97RXCR_REN BIT(0)
+#define AC97RXCR_RX3 BIT(3)
+#define AC97RXCR_RX4 BIT(4)
+#define AC97RXCR_CM BIT(15)
+
+#define AC97TXCR(n) (AC97CH(n) + 0x0008)
+#define AC97TXCR_TEN BIT(0)
+#define AC97TXCR_TX3 BIT(3)
+#define AC97TXCR_TX4 BIT(4)
+#define AC97TXCR_CM BIT(15)
+
+#define AC97SR(n) (AC97CH(n) + 0x000c)
+#define AC97SR_TXFE BIT(1)
+#define AC97SR_TXUE BIT(6)
+
+#define AC97RISR(n) (AC97CH(n) + 0x0010)
+#define AC97ISR(n) (AC97CH(n) + 0x0014)
+#define AC97IE(n) (AC97CH(n) + 0x0018)
+
+/*
+ * Global AC97 controller registers.
+ */
+#define AC97S1DATA 0x0080
+#define AC97S2DATA 0x0084
+#define AC97S12DATA 0x0088
+
+#define AC97RGIS 0x008c
+#define AC97GIS 0x0090
+#define AC97IM 0x0094
+/*
+ * Common bits for RGIS, GIS and IM registers.
+ */
+#define AC97_SLOT2RXVALID BIT(1)
+#define AC97_CODECREADY BIT(5)
+#define AC97_SLOT2TXCOMPLETE BIT(6)
+
+#define AC97EOI 0x0098
+#define AC97EOI_WINT BIT(0)
+#define AC97EOI_CODECREADY BIT(1)
+
+#define AC97GCR 0x009c
+#define AC97GCR_AC97IFE BIT(0)
+
+#define AC97RESET 0x00a0
+#define AC97RESET_TIMEDRESET BIT(0)
+
+#define AC97SYNC 0x00a4
+#define AC97SYNC_TIMEDSYNC BIT(0)
+
+#define AC97_TIMEOUT msecs_to_jiffies(5)
+
+/**
+ * struct ep93xx_ac97_info - EP93xx AC97 controller info structure
+ * @lock: mutex serializing access to the bus (slot 1 & 2 ops)
+ * @dev: pointer to the platform device dev structure
+ * @mem: physical memory resource for the registers
+ * @regs: mapped AC97 controller registers
+ * @irq: AC97 interrupt number
+ * @done: bus ops wait here for an interrupt
+ */
+struct ep93xx_ac97_info {
+ struct mutex lock;
+ struct device *dev;
+ struct resource *mem;
+ void __iomem *regs;
+ int irq;
+ struct completion done;
+};
+
+/* currently ALSA only supports a single AC97 device */
+static struct ep93xx_ac97_info *ep93xx_ac97_info;
+
+static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = {
+ .name = "ac97-pcm-out",
+ .dma_port = EP93XX_DMA_M2P_PORT_AAC1,
+};
+
+static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = {
+ .name = "ac97-pcm-in",
+ .dma_port = EP93XX_DMA_M2P_PORT_AAC1,
+};
+
+static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info,
+ unsigned reg)
+{
+ return __raw_readl(info->regs + reg);
+}
+
+static inline void ep93xx_ac97_write_reg(struct ep93xx_ac97_info *info,
+ unsigned reg, unsigned val)
+{
+ __raw_writel(val, info->regs + reg);
+}
+
+static unsigned short ep93xx_ac97_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+ unsigned short val;
+
+ mutex_lock(&info->lock);
+
+ ep93xx_ac97_write_reg(info, AC97S1DATA, reg);
+ ep93xx_ac97_write_reg(info, AC97IM, AC97_SLOT2RXVALID);
+ if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT)) {
+ dev_warn(info->dev, "timeout reading register %x\n", reg);
+ mutex_unlock(&info->lock);
+ return -ETIMEDOUT;
+ }
+ val = (unsigned short)ep93xx_ac97_read_reg(info, AC97S2DATA);
+
+ mutex_unlock(&info->lock);
+ return val;
+}
+
+static void ep93xx_ac97_write(struct snd_ac97 *ac97,
+ unsigned short reg,
+ unsigned short val)
+{
+ struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+
+ mutex_lock(&info->lock);
+
+ /*
+ * Writes to the codec need to be done so that slot 2 is filled in
+ * before slot 1.
+ */
+ ep93xx_ac97_write_reg(info, AC97S2DATA, val);
+ ep93xx_ac97_write_reg(info, AC97S1DATA, reg);
+
+ ep93xx_ac97_write_reg(info, AC97IM, AC97_SLOT2TXCOMPLETE);
+ if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
+ dev_warn(info->dev, "timeout writing register %x\n", reg);
+
+ mutex_unlock(&info->lock);
+}
+
+static void ep93xx_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+ struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+
+ mutex_lock(&info->lock);
+
+ /*
+ * We are assuming that before this functions gets called, the codec
+ * BIT_CLK is stopped by forcing the codec into powerdown mode. We can
+ * control the SYNC signal directly via AC97SYNC register. Using
+ * TIMEDSYNC the controller will keep the SYNC high > 1us.
+ */
+ ep93xx_ac97_write_reg(info, AC97SYNC, AC97SYNC_TIMEDSYNC);
+ ep93xx_ac97_write_reg(info, AC97IM, AC97_CODECREADY);
+ if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
+ dev_warn(info->dev, "codec warm reset timeout\n");
+
+ mutex_unlock(&info->lock);
+}
+
+static void ep93xx_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+ struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+
+ mutex_lock(&info->lock);
+
+ /*
+ * For doing cold reset, we disable the AC97 controller interface, clear
+ * WINT and CODECREADY bits, and finally enable the interface again.
+ */
+ ep93xx_ac97_write_reg(info, AC97GCR, 0);
+ ep93xx_ac97_write_reg(info, AC97EOI, AC97EOI_CODECREADY | AC97EOI_WINT);
+ ep93xx_ac97_write_reg(info, AC97GCR, AC97GCR_AC97IFE);
+
+ /*
+ * Now, assert the reset and wait for the codec to become ready.
+ */
+ ep93xx_ac97_write_reg(info, AC97RESET, AC97RESET_TIMEDRESET);
+ ep93xx_ac97_write_reg(info, AC97IM, AC97_CODECREADY);
+ if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
+ dev_warn(info->dev, "codec cold reset timeout\n");
+
+ /*
+ * Give the codec some time to come fully out from the reset. This way
+ * we ensure that the subsequent reads/writes will work.
+ */
+ usleep_range(15000, 20000);
+
+ mutex_unlock(&info->lock);
+}
+
+static irqreturn_t ep93xx_ac97_interrupt(int irq, void *dev_id)
+{
+ struct ep93xx_ac97_info *info = dev_id;
+ unsigned status, mask;
+
+ /*
+ * Just mask out the interrupt and wake up the waiting thread.
+ * Interrupts are cleared via reading/writing to slot 1 & 2 registers by
+ * the waiting thread.
+ */
+ status = ep93xx_ac97_read_reg(info, AC97GIS);
+ mask = ep93xx_ac97_read_reg(info, AC97IM);
+ mask &= ~status;
+ ep93xx_ac97_write_reg(info, AC97IM, mask);
+
+ complete(&info->done);
+ return IRQ_HANDLED;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+ .read = ep93xx_ac97_read,
+ .write = ep93xx_ac97_write,
+ .reset = ep93xx_ac97_cold_reset,
+ .warm_reset = ep93xx_ac97_warm_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct ep93xx_ac97_info *info = snd_soc_dai_get_drvdata(dai);
+ unsigned v = 0;
+
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /*
+ * Enable compact mode, TX slots 3 & 4, and the TX FIFO
+ * itself.
+ */
+ v |= AC97TXCR_CM;
+ v |= AC97TXCR_TX3 | AC97TXCR_TX4;
+ v |= AC97TXCR_TEN;
+ ep93xx_ac97_write_reg(info, AC97TXCR(1), v);
+ } else {
+ /*
+ * Enable compact mode, RX slots 3 & 4, and the RX FIFO
+ * itself.
+ */
+ v |= AC97RXCR_CM;
+ v |= AC97RXCR_RX3 | AC97RXCR_RX4;
+ v |= AC97RXCR_REN;
+ ep93xx_ac97_write_reg(info, AC97RXCR(1), v);
+ }
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /*
+ * As per Cirrus EP93xx errata described below:
+ *
+ * http://www.cirrus.com/en/pubs/errata/ER667E2B.pdf
+ *
+ * we will wait for the TX FIFO to be empty before
+ * clearing the TEN bit.
+ */
+ unsigned long timeout = jiffies + AC97_TIMEOUT;
+
+ do {
+ v = ep93xx_ac97_read_reg(info, AC97SR(1));
+ if (time_after(jiffies, timeout)) {
+ dev_warn(info->dev, "TX timeout\n");
+ break;
+ }
+ } while (!(v & (AC97SR_TXFE | AC97SR_TXUE)));
+
+ /* disable the TX FIFO */
+ ep93xx_ac97_write_reg(info, AC97TXCR(1), 0);
+ } else {
+ /* disable the RX FIFO */
+ ep93xx_ac97_write_reg(info, AC97RXCR(1), 0);
+ }
+ break;
+
+ default:
+ dev_warn(info->dev, "unknown command %d\n", cmd);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ep93xx_ac97_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct ep93xx_pcm_dma_params *dma_data;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_data = &ep93xx_ac97_pcm_out;
+ else
+ dma_data = &ep93xx_ac97_pcm_in;
+
+ snd_soc_dai_set_dma_data(dai, substream, dma_data);
+ return 0;
+}
+
+static struct snd_soc_dai_ops ep93xx_ac97_dai_ops = {
+ .startup = ep93xx_ac97_startup,
+ .trigger = ep93xx_ac97_trigger,
+};
+
+struct snd_soc_dai_driver ep93xx_ac97_dai = {
+ .name = "ep93xx-ac97",
+ .id = 0,
+ .ac97_control = 1,
+ .playback = {
+ .stream_name = "AC97 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "AC97 Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &ep93xx_ac97_dai_ops,
+};
+
+static int __devinit ep93xx_ac97_probe(struct platform_device *pdev)
+{
+ struct ep93xx_ac97_info *info;
+ int ret;
+
+ info = kzalloc(sizeof(struct ep93xx_ac97_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, info);
+
+ mutex_init(&info->lock);
+ init_completion(&info->done);
+ info->dev = &pdev->dev;
+
+ info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!info->mem) {
+ ret = -ENXIO;
+ goto fail_free_info;
+ }
+
+ info->irq = platform_get_irq(pdev, 0);
+ if (!info->irq) {
+ ret = -ENXIO;
+ goto fail_free_info;
+ }
+
+ if (!request_mem_region(info->mem->start, resource_size(info->mem),
+ pdev->name)) {
+ ret = -EBUSY;
+ goto fail_free_info;
+ }
+
+ info->regs = ioremap(info->mem->start, resource_size(info->mem));
+ if (!info->regs) {
+ ret = -ENOMEM;
+ goto fail_release_mem;
+ }
+
+ ret = request_irq(info->irq, ep93xx_ac97_interrupt, IRQF_TRIGGER_HIGH,
+ pdev->name, info);
+ if (ret)
+ goto fail_unmap_mem;
+
+ ep93xx_ac97_info = info;
+ platform_set_drvdata(pdev, info);
+
+ ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai);
+ if (ret)
+ goto fail_free_irq;
+
+ return 0;
+
+fail_free_irq:
+ platform_set_drvdata(pdev, NULL);
+ free_irq(info->irq, info);
+fail_unmap_mem:
+ iounmap(info->regs);
+fail_release_mem:
+ release_mem_region(info->mem->start, resource_size(info->mem));
+fail_free_info:
+ kfree(info);
+
+ return ret;
+}
+
+static int __devexit ep93xx_ac97_remove(struct platform_device *pdev)
+{
+ struct ep93xx_ac97_info *info = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_dai(&pdev->dev);
+
+ /* disable the AC97 controller */
+ ep93xx_ac97_write_reg(info, AC97GCR, 0);
+
+ free_irq(info->irq, info);
+ iounmap(info->regs);
+ release_mem_region(info->mem->start, resource_size(info->mem));
+ platform_set_drvdata(pdev, NULL);
+ kfree(info);
+
+ return 0;
+}
+
+static struct platform_driver ep93xx_ac97_driver = {
+ .probe = ep93xx_ac97_probe,
+ .remove = __devexit_p(ep93xx_ac97_remove),
+ .driver = {
+ .name = "ep93xx-ac97",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ep93xx_ac97_init(void)
+{
+ return platform_driver_register(&ep93xx_ac97_driver);
+}
+module_init(ep93xx_ac97_init);
+
+static void __exit ep93xx_ac97_exit(void)
+{
+ platform_driver_unregister(&ep93xx_ac97_driver);
+}
+module_exit(ep93xx_ac97_exit);
+
+MODULE_DESCRIPTION("EP93xx AC97 ASoC Driver");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-ac97");
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c
index 00b946632184..4f4873359613 100644
--- a/sound/soc/ep93xx/ep93xx-i2s.c
+++ b/sound/soc/ep93xx/ep93xx-i2s.c
@@ -31,7 +31,6 @@
#include <mach/dma.h>
#include "ep93xx-pcm.h"
-#include "ep93xx-i2s.h"
#define EP93XX_I2S_TXCLKCFG 0x00
#define EP93XX_I2S_RXCLKCFG 0x04
@@ -145,8 +144,8 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
snd_soc_dai_set_dma_data(cpu_dai, substream,
&info->dma_params[substream->stream]);
@@ -156,8 +155,7 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
ep93xx_i2s_disable(info, substream->stream);
}
@@ -165,7 +163,7 @@ static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct ep93xx_i2s_info *info = cpu_dai->private_data;
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai);
unsigned int clk_cfg, lin_ctrl;
clk_cfg = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG);
@@ -242,9 +240,7 @@ static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct ep93xx_i2s_info *info = cpu_dai->private_data;
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
unsigned word_len, div, sdiv, lrdiv;
int found = 0, err;
@@ -302,7 +298,7 @@ out:
static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
unsigned int freq, int dir)
{
- struct ep93xx_i2s_info *info = cpu_dai->private_data;
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai);
if (dir == SND_SOC_CLOCK_IN || clk_id != 0)
return -EINVAL;
@@ -313,7 +309,7 @@ static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
#ifdef CONFIG_PM
static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
{
- struct ep93xx_i2s_info *info = dai->private_data;
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
if (!dai->active)
return;
@@ -324,7 +320,7 @@ static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
{
- struct ep93xx_i2s_info *info = dai->private_data;
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
if (!dai->active)
return;
@@ -349,9 +345,7 @@ static struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
-struct snd_soc_dai ep93xx_i2s_dai = {
- .name = "ep93xx-i2s",
- .id = 0,
+static struct snd_soc_dai_driver ep93xx_i2s_dai = {
.symmetric_rates= 1,
.suspend = ep93xx_i2s_suspend,
.resume = ep93xx_i2s_resume,
@@ -369,7 +363,6 @@ struct snd_soc_dai ep93xx_i2s_dai = {
},
.ops = &ep93xx_i2s_dai_ops,
};
-EXPORT_SYMBOL_GPL(ep93xx_i2s_dai);
static int ep93xx_i2s_probe(struct platform_device *pdev)
{
@@ -383,8 +376,7 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
goto fail;
}
- ep93xx_i2s_dai.dev = &pdev->dev;
- ep93xx_i2s_dai.private_data = info;
+ dev_set_drvdata(&pdev->dev, info);
info->dma_params = ep93xx_i2s_dma_params;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -424,7 +416,7 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
goto fail_put_sclk;
}
- err = snd_soc_register_dai(&ep93xx_i2s_dai);
+ err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
if (err)
goto fail_put_lrclk;
@@ -447,9 +439,9 @@ fail:
static int __devexit ep93xx_i2s_remove(struct platform_device *pdev)
{
- struct ep93xx_i2s_info *info = ep93xx_i2s_dai.private_data;
+ struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
- snd_soc_unregister_dai(&ep93xx_i2s_dai);
+ snd_soc_unregister_dai(&pdev->dev);
clk_put(info->lrclk);
clk_put(info->sclk);
clk_put(info->mclk);
diff --git a/sound/soc/ep93xx/ep93xx-i2s.h b/sound/soc/ep93xx/ep93xx-i2s.h
deleted file mode 100644
index 3bd4ebfaa1de..000000000000
--- a/sound/soc/ep93xx/ep93xx-i2s.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * linux/sound/soc/ep93xx-i2s.h
- * EP93xx I2S driver
- *
- * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.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 _EP93XX_SND_SOC_I2S_H
-#define _EP93XX_SND_SOC_I2S_H
-
-extern struct snd_soc_dai ep93xx_i2s_dai;
-
-#endif /* _EP93XX_SND_SOC_I2S_H */
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c
index 4ba938400791..2f121ddbe4bb 100644
--- a/sound/soc/ep93xx/ep93xx-pcm.c
+++ b/sound/soc/ep93xx/ep93xx-pcm.c
@@ -95,7 +95,7 @@ static void ep93xx_pcm_buffer_finished(void *cookie,
static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *soc_rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = soc_rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = soc_rtd->cpu_dai;
struct ep93xx_pcm_dma_params *dma_params;
struct ep93xx_runtime_data *rtd;
int ret;
@@ -276,14 +276,14 @@ static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = 0xffffffff;
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
return ret;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -293,22 +293,41 @@ static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
return 0;
}
-struct snd_soc_platform ep93xx_soc_platform = {
- .name = "ep93xx-audio",
- .pcm_ops = &ep93xx_pcm_ops,
+static struct snd_soc_platform_driver ep93xx_soc_platform = {
+ .ops = &ep93xx_pcm_ops,
.pcm_new = &ep93xx_pcm_new,
.pcm_free = &ep93xx_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(ep93xx_soc_platform);
+
+static int __devinit ep93xx_soc_platform_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_platform(&pdev->dev, &ep93xx_soc_platform);
+}
+
+static int __devexit ep93xx_soc_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver ep93xx_pcm_driver = {
+ .driver = {
+ .name = "ep93xx-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = ep93xx_soc_platform_probe,
+ .remove = __devexit_p(ep93xx_soc_platform_remove),
+};
static int __init ep93xx_soc_platform_init(void)
{
- return snd_soc_register_platform(&ep93xx_soc_platform);
+ return platform_driver_register(&ep93xx_pcm_driver);
}
static void __exit ep93xx_soc_platform_exit(void)
{
- snd_soc_unregister_platform(&ep93xx_soc_platform);
+ platform_driver_unregister(&ep93xx_pcm_driver);
}
module_init(ep93xx_soc_platform_init);
diff --git a/sound/soc/ep93xx/ep93xx-pcm.h b/sound/soc/ep93xx/ep93xx-pcm.h
index 4ffdd3f62fe9..111e1121ecb8 100644
--- a/sound/soc/ep93xx/ep93xx-pcm.h
+++ b/sound/soc/ep93xx/ep93xx-pcm.h
@@ -17,6 +17,4 @@ struct ep93xx_pcm_dma_params {
int dma_port;
};
-extern struct snd_soc_platform ep93xx_soc_platform;
-
#endif /* _EP93XX_SND_SOC_PCM_H */
diff --git a/sound/soc/ep93xx/simone.c b/sound/soc/ep93xx/simone.c
new file mode 100644
index 000000000000..4b0d19913728
--- /dev/null
+++ b/sound/soc/ep93xx/simone.c
@@ -0,0 +1,89 @@
+/*
+ * simone.c -- ASoC audio for Simplemachines Sim.One board
+ *
+ * Copyright (c) 2010 Mika Westerberg
+ *
+ * Based on snappercl15 machine driver by Ryan Mallon.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+
+#include "ep93xx-pcm.h"
+
+static struct snd_soc_dai_link simone_dai = {
+ .name = "AC97",
+ .stream_name = "AC97 HiFi",
+ .cpu_dai_name = "ep93xx-ac97",
+ .codec_dai_name = "ac97-hifi",
+ .codec_name = "ac97-codec",
+ .platform_name = "ep93xx-pcm-audio",
+};
+
+static struct snd_soc_card snd_soc_simone = {
+ .name = "Sim.One",
+ .dai_link = &simone_dai,
+ .num_links = 1,
+};
+
+static struct platform_device *simone_snd_ac97_device;
+static struct platform_device *simone_snd_device;
+
+static int __init simone_init(void)
+{
+ int ret;
+
+ if (!machine_is_sim_one())
+ return -ENODEV;
+
+ simone_snd_ac97_device = platform_device_alloc("ac97-codec", -1);
+ if (!simone_snd_ac97_device)
+ return -ENOMEM;
+
+ ret = platform_device_add(simone_snd_ac97_device);
+ if (ret)
+ goto fail;
+
+ simone_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!simone_snd_device) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ platform_set_drvdata(simone_snd_device, &snd_soc_simone);
+ ret = platform_device_add(simone_snd_device);
+ if (ret) {
+ platform_device_put(simone_snd_device);
+ goto fail;
+ }
+
+ return ret;
+
+fail:
+ platform_device_put(simone_snd_ac97_device);
+ return ret;
+}
+module_init(simone_init);
+
+static void __exit simone_exit(void)
+{
+ platform_device_unregister(simone_snd_device);
+ platform_device_unregister(simone_snd_ac97_device);
+}
+module_exit(simone_exit);
+
+MODULE_DESCRIPTION("ALSA SoC Simplemachines Sim.One");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ep93xx/snappercl15.c b/sound/soc/ep93xx/snappercl15.c
index 64955340ff75..28ab5ff772ac 100644
--- a/sound/soc/ep93xx/snappercl15.c
+++ b/sound/soc/ep93xx/snappercl15.c
@@ -22,7 +22,6 @@
#include "../codecs/tlv320aic23.h"
#include "ep93xx-pcm.h"
-#include "ep93xx-i2s.h"
#define CODEC_CLOCK 5644800
@@ -30,8 +29,8 @@ static int snappercl15_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int err;
err = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
@@ -77,8 +76,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"MICIN", NULL, "Mic Jack"},
};
-static int snappercl15_tlv320aic23_init(struct snd_soc_codec *codec)
+static int snappercl15_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
ARRAY_SIZE(tlv320aic23_dapm_widgets));
@@ -89,24 +90,20 @@ static int snappercl15_tlv320aic23_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link snappercl15_dai = {
.name = "tlv320aic23",
.stream_name = "AIC23",
- .cpu_dai = &ep93xx_i2s_dai,
- .codec_dai = &tlv320aic23_dai,
+ .cpu_dai_name = "ep93xx-i2s",
+ .codec_dai_name = "tlv320aic23-hifi",
+ .codec_name = "tlv320aic23-codec.0-001a",
+ .platform_name = "ep93xx-pcm-audio",
.init = snappercl15_tlv320aic23_init,
.ops = &snappercl15_ops,
};
static struct snd_soc_card snd_soc_snappercl15 = {
.name = "Snapper CL15",
- .platform = &ep93xx_soc_platform,
.dai_link = &snappercl15_dai,
.num_links = 1,
};
-static struct snd_soc_device snappercl15_snd_devdata = {
- .card = &snd_soc_snappercl15,
- .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
static struct platform_device *snappercl15_snd_device;
static int __init snappercl15_init(void)
@@ -126,8 +123,7 @@ static int __init snappercl15_init(void)
if (!snappercl15_snd_device)
return -ENOMEM;
- platform_set_drvdata(snappercl15_snd_device, &snappercl15_snd_devdata);
- snappercl15_snd_devdata.dev = &snappercl15_snd_device->dev;
+ platform_set_drvdata(snappercl15_snd_device, &snd_soc_snappercl15);
ret = platform_device_add(snappercl15_snd_device);
if (ret)
platform_device_put(snappercl15_snd_device);
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 8cb65ccad35f..d754d34d68a6 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,27 +1,36 @@
-config SND_SOC_OF_SIMPLE
- tristate
-
config SND_MPC52xx_DMA
tristate
-# ASoC platform support for the Freescale MPC8610 SOC. This compiles drivers
-# for the SSI and the Elo DMA controller. You will still need to select
-# a platform driver and a codec driver.
-config SND_SOC_MPC8610
+# ASoC platform support for the Freescale PowerPC SOCs that have an SSI and
+# an Elo DMA controller, such as the MPC8610 and P1022. You will still need to
+# select a platform driver and a codec driver.
+config SND_SOC_POWERPC_SSI
tristate
- depends on MPC8610
+ depends on FSL_SOC
config SND_SOC_MPC8610_HPCD
tristate "ALSA SoC support for the Freescale MPC8610 HPCD board"
# I2C is necessary for the CS4270 driver
depends on MPC8610_HPCD && I2C
- select SND_SOC_MPC8610
+ select SND_SOC_POWERPC_SSI
select SND_SOC_CS4270
select SND_SOC_CS4270_VD33_ERRATA
default y if MPC8610_HPCD
help
Say Y if you want to enable audio on the Freescale MPC8610 HPCD.
+config SND_SOC_P1022_DS
+ tristate "ALSA SoC support for the Freescale P1022 DS board"
+ # I2C is necessary for the WM8776 driver
+ depends on P1022_DS && I2C
+ select SND_SOC_POWERPC_SSI
+ select SND_SOC_WM8776
+ default y if P1022_DS
+ help
+ Say Y if you want to enable audio on the Freescale P1022 DS board.
+ This will also include the Wolfson Microelectronics WM8776 codec
+ driver.
+
config SND_SOC_MPC5200_I2S
tristate "Freescale MPC5200 PSC in I2S mode driver"
depends on PPC_MPC52xx && PPC_BESTCOMM
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index a83a73967ec6..b4a38c0ac58c 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -1,14 +1,15 @@
-# Simple machine driver that extracts configuration from the OF device tree
-obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o
-
# MPC8610 HPCD Machine Support
snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o
obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o
-# MPC8610 Platform Support
+# P1022 DS Machine Support
+snd-soc-p1022-ds-objs := p1022_ds.o
+obj-$(CONFIG_SND_SOC_P1022_DS) += snd-soc-p1022-ds.o
+
+# Freescale PowerPC SSI/DMA Platform Support
snd-soc-fsl-ssi-objs := fsl_ssi.o
snd-soc-fsl-dma-objs := fsl_dma.o
-obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
+obj-$(CONFIG_SND_SOC_POWERPC_SSI) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
# MPC5200 Platform Support
obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c
index 1a5b8e0d6a34..53251e6b5bd5 100644
--- a/sound/soc/fsl/efika-audio-fabric.c
+++ b/sound/soc/fsl/efika-audio-fabric.c
@@ -24,7 +24,6 @@
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
-#include <sound/soc-of-simple.h>
#include "mpc5200_dma.h"
#include "mpc5200_psc_ac97.h"
@@ -32,21 +31,24 @@
#define DRV_NAME "efika-audio-fabric"
-static struct snd_soc_device device;
static struct snd_soc_card card;
static struct snd_soc_dai_link efika_fabric_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 Analog",
- .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_ANALOG],
- .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+ .codec_dai_name = "stac9766-hifi-analog",
+ .cpu_dai_name = "mpc5200-psc-ac97.0",
+ .platform_name = "mpc5200-pcm-audio",
+ .codec_name = "stac9766-codec",
},
{
.name = "AC97",
.stream_name = "AC97 IEC958",
- .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_DIGITAL],
- .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+ .codec_dai_name = "stac9766-hifi-IEC958",
+ .cpu_dai_name = "mpc5200-psc-ac97.1",
+ .platform_name = "mpc5200-pcm-audio",
+ .codec_name = "stac9766-codec",
},
};
@@ -58,13 +60,10 @@ static __init int efika_fabric_init(void)
if (!of_machine_is_compatible("bplan,efika"))
return -ENODEV;
- card.platform = &mpc5200_audio_dma_platform;
card.name = "Efika";
card.dai_link = efika_fabric_dai;
card.num_links = ARRAY_SIZE(efika_fabric_dai);
- device.card = &card;
- device.codec_dev = &soc_codec_dev_stac9766;
pdev = platform_device_alloc("soc-audio", 1);
if (!pdev) {
@@ -72,8 +71,7 @@ static __init int efika_fabric_init(void)
return -ENODEV;
}
- platform_set_drvdata(pdev, &device);
- device.dev = &pdev->dev;
+ platform_set_drvdata(pdev, &card);
rc = platform_device_add(pdev);
if (rc) {
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 410c7496a18d..4cf98c03af22 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -3,10 +3,11 @@
*
* Author: Timur Tabi <timur@freescale.com>
*
- * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed
- * under the terms of the GNU General Public License version 2. This
- * program is licensed "as is" without any warranty of any kind, whether
- * express or implied.
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
*
* This driver implements ASoC support for the Elo DMA controller, which is
* the DMA controller on Freescale 83xx, 85xx, and 86xx SOCs. In ALSA terms,
@@ -20,6 +21,9 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/gfp.h>
+#include <linux/of_platform.h>
+#include <linux/list.h>
+#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -29,6 +33,7 @@
#include <asm/io.h>
#include "fsl_dma.h"
+#include "fsl_ssi.h" /* For the offset of stx0 and srx0 */
/*
* The formats that the DMA controller supports, which is anything
@@ -52,26 +57,16 @@
#define FSLDMA_PCM_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
SNDRV_PCM_RATE_CONTINUOUS)
-/* DMA global data. This structure is used by fsl_dma_open() to determine
- * which DMA channels to assign to a substream. Unfortunately, ASoC V1 does
- * not allow the machine driver to provide this information to the PCM
- * driver in advance, and there's no way to differentiate between the two
- * DMA controllers. So for now, this driver only supports one SSI device
- * using two DMA channels. We cannot support multiple DMA devices.
- *
- * ssi_stx_phys: bus address of SSI STX register
- * ssi_srx_phys: bus address of SSI SRX register
- * dma_channel: pointer to the DMA channel's registers
- * irq: IRQ for this DMA channel
- * assigned: set to 1 if that DMA channel is assigned to a substream
- */
-static struct {
+struct dma_object {
+ struct snd_soc_platform_driver dai;
dma_addr_t ssi_stx_phys;
dma_addr_t ssi_srx_phys;
- struct ccsr_dma_channel __iomem *dma_channel[2];
- unsigned int irq[2];
- unsigned int assigned[2];
-} dma_global_data;
+ unsigned int ssi_fifo_depth;
+ struct ccsr_dma_channel __iomem *channel;
+ unsigned int irq;
+ bool assigned;
+ char path[1];
+};
/*
* The number of DMA links to use. Two is the bare minimum, but if you
@@ -88,8 +83,6 @@ static struct {
* structure.
*
* @link[]: array of link descriptors
- * @controller_id: which DMA controller (0, 1, ...)
- * @channel_id: which DMA channel on the controller (0, 1, 2, ...)
* @dma_channel: pointer to the DMA channel's registers
* @irq: IRQ for this DMA channel
* @substream: pointer to the substream object, needed by the ISR
@@ -104,12 +97,11 @@ static struct {
*/
struct fsl_dma_private {
struct fsl_dma_link_descriptor link[NUM_DMA_LINKS];
- unsigned int controller_id;
- unsigned int channel_id;
struct ccsr_dma_channel __iomem *dma_channel;
unsigned int irq;
struct snd_pcm_substream *substream;
dma_addr_t ssi_sxx_phys;
+ unsigned int ssi_fifo_depth;
dma_addr_t ld_buf_phys;
unsigned int current_link;
dma_addr_t dma_buf_phys;
@@ -185,13 +177,23 @@ static void fsl_dma_update_pointers(struct fsl_dma_private *dma_private)
struct fsl_dma_link_descriptor *link =
&dma_private->link[dma_private->current_link];
- /* Update our link descriptors to point to the next period */
- if (dma_private->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- link->source_addr =
- cpu_to_be32(dma_private->dma_buf_next);
- else
- link->dest_addr =
- cpu_to_be32(dma_private->dma_buf_next);
+ /* Update our link descriptors to point to the next period. On a 36-bit
+ * system, we also need to update the ESAD bits. We also set (keep) the
+ * snoop bits. See the comments in fsl_dma_hw_params() about snooping.
+ */
+ if (dma_private->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ link->source_addr = cpu_to_be32(dma_private->dma_buf_next);
+#ifdef CONFIG_PHYS_64BIT
+ link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+ upper_32_bits(dma_private->dma_buf_next));
+#endif
+ } else {
+ link->dest_addr = cpu_to_be32(dma_private->dma_buf_next);
+#ifdef CONFIG_PHYS_64BIT
+ link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+ upper_32_bits(dma_private->dma_buf_next));
+#endif
+ }
/* Update our variables for next time */
dma_private->dma_buf_next += dma_private->period_size;
@@ -212,6 +214,9 @@ static void fsl_dma_update_pointers(struct fsl_dma_private *dma_private)
static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
{
struct fsl_dma_private *dma_private = dev_id;
+ struct snd_pcm_substream *substream = dma_private->substream;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct device *dev = rtd->platform->dev;
struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
irqreturn_t ret = IRQ_NONE;
u32 sr, sr2 = 0;
@@ -222,11 +227,8 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
sr = in_be32(&dma_channel->sr);
if (sr & CCSR_DMA_SR_TE) {
- dev_err(dma_private->substream->pcm->card->dev,
- "DMA transmit error (controller=%u channel=%u irq=%u\n",
- dma_private->controller_id,
- dma_private->channel_id, irq);
- fsl_dma_abort_stream(dma_private->substream);
+ dev_err(dev, "dma transmit error\n");
+ fsl_dma_abort_stream(substream);
sr2 |= CCSR_DMA_SR_TE;
ret = IRQ_HANDLED;
}
@@ -235,11 +237,8 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
ret = IRQ_HANDLED;
if (sr & CCSR_DMA_SR_PE) {
- dev_err(dma_private->substream->pcm->card->dev,
- "DMA%u programming error (channel=%u irq=%u)\n",
- dma_private->controller_id,
- dma_private->channel_id, irq);
- fsl_dma_abort_stream(dma_private->substream);
+ dev_err(dev, "dma programming error\n");
+ fsl_dma_abort_stream(substream);
sr2 |= CCSR_DMA_SR_PE;
ret = IRQ_HANDLED;
}
@@ -253,8 +252,6 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
ret = IRQ_HANDLED;
if (sr & CCSR_DMA_SR_EOSI) {
- struct snd_pcm_substream *substream = dma_private->substream;
-
/* Tell ALSA we completed a period. */
snd_pcm_period_elapsed(substream);
@@ -288,11 +285,19 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
* This function is called when the codec driver calls snd_soc_new_pcms(),
* once for each .dai_link in the machine driver's snd_soc_card
* structure.
+ *
+ * snd_dma_alloc_pages() is just a front-end to dma_alloc_coherent(), which
+ * (currently) always allocates the DMA buffer in lowmem, even if GFP_HIGHMEM
+ * is specified. Therefore, any DMA buffers we allocate will always be in low
+ * memory, but we support for 36-bit physical addresses anyway.
+ *
+ * Regardless of where the memory is actually allocated, since the device can
+ * technically DMA to any 36-bit address, we do need to set the DMA mask to 36.
*/
static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
struct snd_pcm *pcm)
{
- static u64 fsl_dma_dmamask = DMA_BIT_MASK(32);
+ static u64 fsl_dma_dmamask = DMA_BIT_MASK(36);
int ret;
if (!card->dev->dma_mask)
@@ -301,25 +306,29 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = fsl_dma_dmamask;
- ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
- fsl_dma_hardware.buffer_bytes_max,
- &pcm->streams[0].substream->dma_buffer);
- if (ret) {
- dev_err(card->dev,
- "Can't allocate playback DMA buffer (size=%u)\n",
- fsl_dma_hardware.buffer_bytes_max);
- return -ENOMEM;
+ /* Some codecs have separate DAIs for playback and capture, so we
+ * should allocate a DMA buffer only for the streams that are valid.
+ */
+
+ if (dai->driver->playback.channels_min) {
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
+ fsl_dma_hardware.buffer_bytes_max,
+ &pcm->streams[0].substream->dma_buffer);
+ if (ret) {
+ dev_err(card->dev, "can't alloc playback dma buffer\n");
+ return ret;
+ }
}
- ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
- fsl_dma_hardware.buffer_bytes_max,
- &pcm->streams[1].substream->dma_buffer);
- if (ret) {
- snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
- dev_err(card->dev,
- "Can't allocate capture DMA buffer (size=%u)\n",
- fsl_dma_hardware.buffer_bytes_max);
- return -ENOMEM;
+ if (dai->driver->capture.channels_min) {
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
+ fsl_dma_hardware.buffer_bytes_max,
+ &pcm->streams[1].substream->dma_buffer);
+ if (ret) {
+ snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
+ dev_err(card->dev, "can't alloc capture dma buffer\n");
+ return ret;
+ }
}
return 0;
@@ -390,6 +399,10 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
static int fsl_dma_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct device *dev = rtd->platform->dev;
+ struct dma_object *dma =
+ container_of(rtd->platform->driver, struct dma_object, dai);
struct fsl_dma_private *dma_private;
struct ccsr_dma_channel __iomem *dma_channel;
dma_addr_t ld_buf_phys;
@@ -407,52 +420,45 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0) {
- dev_err(substream->pcm->card->dev, "invalid buffer size\n");
+ dev_err(dev, "invalid buffer size\n");
return ret;
}
channel = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
- if (dma_global_data.assigned[channel]) {
- dev_err(substream->pcm->card->dev,
- "DMA channel already assigned\n");
+ if (dma->assigned) {
+ dev_err(dev, "dma channel already assigned\n");
return -EBUSY;
}
- dma_private = dma_alloc_coherent(substream->pcm->card->dev,
- sizeof(struct fsl_dma_private), &ld_buf_phys, GFP_KERNEL);
+ dma_private = dma_alloc_coherent(dev, sizeof(struct fsl_dma_private),
+ &ld_buf_phys, GFP_KERNEL);
if (!dma_private) {
- dev_err(substream->pcm->card->dev,
- "can't allocate DMA private data\n");
+ dev_err(dev, "can't allocate dma private data\n");
return -ENOMEM;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dma_private->ssi_sxx_phys = dma_global_data.ssi_stx_phys;
+ dma_private->ssi_sxx_phys = dma->ssi_stx_phys;
else
- dma_private->ssi_sxx_phys = dma_global_data.ssi_srx_phys;
+ dma_private->ssi_sxx_phys = dma->ssi_srx_phys;
- dma_private->dma_channel = dma_global_data.dma_channel[channel];
- dma_private->irq = dma_global_data.irq[channel];
+ dma_private->ssi_fifo_depth = dma->ssi_fifo_depth;
+ dma_private->dma_channel = dma->channel;
+ dma_private->irq = dma->irq;
dma_private->substream = substream;
dma_private->ld_buf_phys = ld_buf_phys;
dma_private->dma_buf_phys = substream->dma_buffer.addr;
- /* We only support one DMA controller for now */
- dma_private->controller_id = 0;
- dma_private->channel_id = channel;
-
ret = request_irq(dma_private->irq, fsl_dma_isr, 0, "DMA", dma_private);
if (ret) {
- dev_err(substream->pcm->card->dev,
- "can't register ISR for IRQ %u (ret=%i)\n",
+ dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
dma_private->irq, ret);
- dma_free_coherent(substream->pcm->card->dev,
- sizeof(struct fsl_dma_private),
+ dma_free_coherent(dev, sizeof(struct fsl_dma_private),
dma_private, dma_private->ld_buf_phys);
return ret;
}
- dma_global_data.assigned[channel] = 1;
+ dma->assigned = 1;
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware);
@@ -546,13 +552,15 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_dma_private *dma_private = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct device *dev = rtd->platform->dev;
/* Number of bits per sample */
- unsigned int sample_size =
+ unsigned int sample_bits =
snd_pcm_format_physical_width(params_format(hw_params));
/* Number of bytes per frame */
- unsigned int frame_size = 2 * (sample_size / 8);
+ unsigned int sample_bytes = sample_bits / 8;
/* Bus address of SSI STX register */
dma_addr_t ssi_sxx_phys = dma_private->ssi_sxx_phys;
@@ -592,7 +600,7 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
* that offset here. While we're at it, also tell the DMA controller
* how much data to transfer per sample.
*/
- switch (sample_size) {
+ switch (sample_bits) {
case 8:
mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1;
ssi_sxx_phys += 3;
@@ -606,23 +614,42 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
break;
default:
/* We should never get here */
- dev_err(substream->pcm->card->dev,
- "unsupported sample size %u\n", sample_size);
+ dev_err(dev, "unsupported sample size %u\n", sample_bits);
return -EINVAL;
}
/*
- * BWC should always be a multiple of the frame size. BWC determines
- * how many bytes are sent/received before the DMA controller checks the
- * SSI to see if it needs to stop. For playback, the transmit FIFO can
- * hold three frames, so we want to send two frames at a time. For
- * capture, the receive FIFO is triggered when it contains one frame, so
- * we want to receive one frame at a time.
+ * BWC determines how many bytes are sent/received before the DMA
+ * controller checks the SSI to see if it needs to stop. BWC should
+ * always be a multiple of the frame size, so that we always transmit
+ * whole frames. Each frame occupies two slots in the FIFO. The
+ * parameter for CCSR_DMA_MR_BWC() is rounded down the next power of two
+ * (MR[BWC] can only represent even powers of two).
+ *
+ * To simplify the process, we set BWC to the largest value that is
+ * less than or equal to the FIFO watermark. For playback, this ensures
+ * that we transfer the maximum amount without overrunning the FIFO.
+ * For capture, this ensures that we transfer the maximum amount without
+ * underrunning the FIFO.
+ *
+ * f = SSI FIFO depth
+ * w = SSI watermark value (which equals f - 2)
+ * b = DMA bandwidth count (in bytes)
+ * s = sample size (in bytes, which equals frame_size * 2)
+ *
+ * For playback, we never transmit more than the transmit FIFO
+ * watermark, otherwise we might write more data than the FIFO can hold.
+ * The watermark is equal to the FIFO depth minus two.
+ *
+ * For capture, two equations must hold:
+ * w > f - (b / s)
+ * w >= b / s
+ *
+ * So, b > 2 * s, but b must also be <= s * w. To simplify, we set
+ * b = s * w, which is equal to
+ * (dma_private->ssi_fifo_depth - 2) * sample_bytes.
*/
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- mr |= CCSR_DMA_MR_BWC(2 * frame_size);
- else
- mr |= CCSR_DMA_MR_BWC(frame_size);
+ mr |= CCSR_DMA_MR_BWC((dma_private->ssi_fifo_depth - 2) * sample_bytes);
out_be32(&dma_channel->mr, mr);
@@ -631,12 +658,7 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
link->count = cpu_to_be32(period_size);
- /* Even though the DMA controller supports 36-bit addressing,
- * for simplicity we allow only 32-bit addresses for the audio
- * buffer itself. This was enforced in fsl_dma_new() with the
- * DMA mask.
- *
- * The snoop bit tells the DMA controller whether it should tell
+ /* The snoop bit tells the DMA controller whether it should tell
* the ECM to snoop during a read or write to an address. For
* audio, we use DMA to transfer data between memory and an I/O
* device (the SSI's STX0 or SRX0 register). Snooping is only
@@ -651,20 +673,24 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
* flush out the data for the previous period. So if you
* increased period_bytes_min to a large enough size, you might
* get more performance by not snooping, and you'll still be
- * okay.
+ * okay. You'll need to update fsl_dma_update_pointers() also.
*/
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
link->source_addr = cpu_to_be32(temp_addr);
- link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+ link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+ upper_32_bits(temp_addr));
link->dest_addr = cpu_to_be32(ssi_sxx_phys);
- link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP);
+ link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP |
+ upper_32_bits(ssi_sxx_phys));
} else {
link->source_addr = cpu_to_be32(ssi_sxx_phys);
- link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP);
+ link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP |
+ upper_32_bits(ssi_sxx_phys));
link->dest_addr = cpu_to_be32(temp_addr);
- link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+ link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+ upper_32_bits(temp_addr));
}
temp_addr += period_size;
@@ -689,14 +715,29 @@ static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_dma_private *dma_private = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct device *dev = rtd->platform->dev;
struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
dma_addr_t position;
snd_pcm_uframes_t frames;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ /* Obtain the current DMA pointer, but don't read the ESAD bits if we
+ * only have 32-bit DMA addresses. This function is typically called
+ * in interrupt context, so we need to optimize it.
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
position = in_be32(&dma_channel->sar);
- else
+#ifdef CONFIG_PHYS_64BIT
+ position |= (u64)(in_be32(&dma_channel->satr) &
+ CCSR_DMA_ATR_ESAD_MASK) << 32;
+#endif
+ } else {
position = in_be32(&dma_channel->dar);
+#ifdef CONFIG_PHYS_64BIT
+ position |= (u64)(in_be32(&dma_channel->datr) &
+ CCSR_DMA_ATR_ESAD_MASK) << 32;
+#endif
+ }
/*
* When capture is started, the SSI immediately starts to fill its FIFO.
@@ -710,8 +751,7 @@ static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream)
if ((position < dma_private->dma_buf_phys) ||
(position > dma_private->dma_buf_end)) {
- dev_err(substream->pcm->card->dev,
- "dma pointer is out of range, halting stream\n");
+ dev_err(dev, "dma pointer is out of range, halting stream\n");
return SNDRV_PCM_POS_XRUN;
}
@@ -772,26 +812,28 @@ static int fsl_dma_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_dma_private *dma_private = runtime->private_data;
- int dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct device *dev = rtd->platform->dev;
+ struct dma_object *dma =
+ container_of(rtd->platform->driver, struct dma_object, dai);
if (dma_private) {
if (dma_private->irq)
free_irq(dma_private->irq, dma_private);
if (dma_private->ld_buf_phys) {
- dma_unmap_single(substream->pcm->card->dev,
- dma_private->ld_buf_phys,
- sizeof(dma_private->link), DMA_TO_DEVICE);
+ dma_unmap_single(dev, dma_private->ld_buf_phys,
+ sizeof(dma_private->link),
+ DMA_TO_DEVICE);
}
/* Deallocate the fsl_dma_private structure */
- dma_free_coherent(substream->pcm->card->dev,
- sizeof(struct fsl_dma_private),
- dma_private, dma_private->ld_buf_phys);
+ dma_free_coherent(dev, sizeof(struct fsl_dma_private),
+ dma_private, dma_private->ld_buf_phys);
substream->runtime->private_data = NULL;
}
- dma_global_data.assigned[dir] = 0;
+ dma->assigned = 0;
return 0;
}
@@ -814,6 +856,37 @@ static void fsl_dma_free_dma_buffers(struct snd_pcm *pcm)
}
}
+/**
+ * find_ssi_node -- returns the SSI node that points to his DMA channel node
+ *
+ * Although this DMA driver attempts to operate independently of the other
+ * devices, it still needs to determine some information about the SSI device
+ * that it's working with. Unfortunately, the device tree does not contain
+ * a pointer from the DMA channel node to the SSI node -- the pointer goes the
+ * other way. So we need to scan the device tree for SSI nodes until we find
+ * the one that points to the given DMA channel node. It's ugly, but at least
+ * it's contained in this one function.
+ */
+static struct device_node *find_ssi_node(struct device_node *dma_channel_np)
+{
+ struct device_node *ssi_np, *np;
+
+ for_each_compatible_node(ssi_np, NULL, "fsl,mpc8610-ssi") {
+ /* Check each DMA phandle to see if it points to us. We
+ * assume that device_node pointers are a valid comparison.
+ */
+ np = of_parse_phandle(ssi_np, "fsl,playback-dma", 0);
+ if (np == dma_channel_np)
+ return ssi_np;
+
+ np = of_parse_phandle(ssi_np, "fsl,capture-dma", 0);
+ if (np == dma_channel_np)
+ return ssi_np;
+ }
+
+ return NULL;
+}
+
static struct snd_pcm_ops fsl_dma_ops = {
.open = fsl_dma_open,
.close = fsl_dma_close,
@@ -823,59 +896,114 @@ static struct snd_pcm_ops fsl_dma_ops = {
.pointer = fsl_dma_pointer,
};
-struct snd_soc_platform fsl_soc_platform = {
- .name = "fsl-dma",
- .pcm_ops = &fsl_dma_ops,
- .pcm_new = fsl_dma_new,
- .pcm_free = fsl_dma_free_dma_buffers,
-};
-EXPORT_SYMBOL_GPL(fsl_soc_platform);
+static int __devinit fsl_soc_dma_probe(struct platform_device *pdev,
+ const struct of_device_id *match)
+ {
+ struct dma_object *dma;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *ssi_np;
+ struct resource res;
+ const uint32_t *iprop;
+ int ret;
-/**
- * fsl_dma_configure: store the DMA parameters from the fabric driver.
- *
- * This function is called by the ASoC fabric driver to give us the DMA and
- * SSI channel information.
- *
- * Unfortunately, ASoC V1 does make it possible to determine the DMA/SSI
- * data when a substream is created, so for now we need to store this data
- * into a global variable. This means that we can only support one DMA
- * controller, and hence only one SSI.
- */
-int fsl_dma_configure(struct fsl_dma_info *dma_info)
+ /* Find the SSI node that points to us. */
+ ssi_np = find_ssi_node(np);
+ if (!ssi_np) {
+ dev_err(&pdev->dev, "cannot find parent SSI node\n");
+ return -ENODEV;
+ }
+
+ ret = of_address_to_resource(ssi_np, 0, &res);
+ if (ret) {
+ dev_err(&pdev->dev, "could not determine resources for %s\n",
+ ssi_np->full_name);
+ of_node_put(ssi_np);
+ return ret;
+ }
+
+ dma = kzalloc(sizeof(*dma) + strlen(np->full_name), GFP_KERNEL);
+ if (!dma) {
+ dev_err(&pdev->dev, "could not allocate dma object\n");
+ of_node_put(ssi_np);
+ return -ENOMEM;
+ }
+
+ strcpy(dma->path, np->full_name);
+ dma->dai.ops = &fsl_dma_ops;
+ dma->dai.pcm_new = fsl_dma_new;
+ dma->dai.pcm_free = fsl_dma_free_dma_buffers;
+
+ /* Store the SSI-specific information that we need */
+ dma->ssi_stx_phys = res.start + offsetof(struct ccsr_ssi, stx0);
+ dma->ssi_srx_phys = res.start + offsetof(struct ccsr_ssi, srx0);
+
+ iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL);
+ if (iprop)
+ dma->ssi_fifo_depth = *iprop;
+ else
+ /* Older 8610 DTs didn't have the fifo-depth property */
+ dma->ssi_fifo_depth = 8;
+
+ of_node_put(ssi_np);
+
+ ret = snd_soc_register_platform(&pdev->dev, &dma->dai);
+ if (ret) {
+ dev_err(&pdev->dev, "could not register platform\n");
+ kfree(dma);
+ return ret;
+ }
+
+ dma->channel = of_iomap(np, 0);
+ dma->irq = irq_of_parse_and_map(np, 0);
+
+ dev_set_drvdata(&pdev->dev, dma);
+
+ return 0;
+}
+
+static int __devexit fsl_soc_dma_remove(struct platform_device *pdev)
{
- static int initialized;
+ struct dma_object *dma = dev_get_drvdata(&pdev->dev);
- /* We only support one DMA controller for now */
- if (initialized)
- return 0;
+ snd_soc_unregister_platform(&pdev->dev);
+ iounmap(dma->channel);
+ irq_dispose_mapping(dma->irq);
+ kfree(dma);
- dma_global_data.ssi_stx_phys = dma_info->ssi_stx_phys;
- dma_global_data.ssi_srx_phys = dma_info->ssi_srx_phys;
- dma_global_data.dma_channel[0] = dma_info->dma_channel[0];
- dma_global_data.dma_channel[1] = dma_info->dma_channel[1];
- dma_global_data.irq[0] = dma_info->dma_irq[0];
- dma_global_data.irq[1] = dma_info->dma_irq[1];
- dma_global_data.assigned[0] = 0;
- dma_global_data.assigned[1] = 0;
-
- initialized = 1;
- return 1;
+ return 0;
}
-EXPORT_SYMBOL_GPL(fsl_dma_configure);
-static int __init fsl_soc_platform_init(void)
+static const struct of_device_id fsl_soc_dma_ids[] = {
+ { .compatible = "fsl,ssi-dma-channel", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_soc_dma_ids);
+
+static struct of_platform_driver fsl_soc_dma_driver = {
+ .driver = {
+ .name = "fsl-pcm-audio",
+ .owner = THIS_MODULE,
+ .of_match_table = fsl_soc_dma_ids,
+ },
+ .probe = fsl_soc_dma_probe,
+ .remove = __devexit_p(fsl_soc_dma_remove),
+};
+
+static int __init fsl_soc_dma_init(void)
{
- return snd_soc_register_platform(&fsl_soc_platform);
+ pr_info("Freescale Elo DMA ASoC PCM Driver\n");
+
+ return of_register_platform_driver(&fsl_soc_dma_driver);
}
-module_init(fsl_soc_platform_init);
-static void __exit fsl_soc_platform_exit(void)
+static void __exit fsl_soc_dma_exit(void)
{
- snd_soc_unregister_platform(&fsl_soc_platform);
+ of_unregister_platform_driver(&fsl_soc_dma_driver);
}
-module_exit(fsl_soc_platform_exit);
+
+module_init(fsl_soc_dma_init);
+module_exit(fsl_soc_dma_exit);
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
-MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM module");
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_dma.h b/sound/soc/fsl/fsl_dma.h
index 385d4a42603c..78fee97e8036 100644
--- a/sound/soc/fsl/fsl_dma.h
+++ b/sound/soc/fsl/fsl_dma.h
@@ -126,24 +126,4 @@ struct fsl_dma_link_descriptor {
u8 res[4]; /* Reserved */
} __attribute__ ((aligned(32), packed));
-/* DMA information needed to create a snd_soc_dai object
- *
- * ssi_stx_phys: bus address of SSI STX register to use
- * ssi_srx_phys: bus address of SSI SRX register to use
- * dma[0]: points to the DMA channel to use for playback
- * dma[1]: points to the DMA channel to use for capture
- * dma_irq[0]: IRQ of the DMA channel to use for playback
- * dma_irq[1]: IRQ of the DMA channel to use for capture
- */
-struct fsl_dma_info {
- dma_addr_t ssi_stx_phys;
- dma_addr_t ssi_srx_phys;
- struct ccsr_dma_channel __iomem *dma_channel[2];
- unsigned int dma_irq[2];
-};
-
-extern struct snd_soc_platform fsl_soc_platform;
-
-int fsl_dma_configure(struct fsl_dma_info *dma_info);
-
#endif
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 762c1b8e8e4e..4cc167a7aeb8 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -3,10 +3,11 @@
*
* Author: Timur Tabi <timur@freescale.com>
*
- * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed
- * under the terms of the GNU General Public License version 2. This
- * program is licensed "as is" without any warranty of any kind, whether
- * express or implied.
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
*/
#include <linux/init.h>
@@ -15,6 +16,7 @@
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/of_platform.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -22,8 +24,6 @@
#include <sound/initval.h>
#include <sound/soc.h>
-#include <asm/immap_86xx.h>
-
#include "fsl_ssi.h"
/**
@@ -71,33 +71,32 @@
/**
* fsl_ssi_private: per-SSI private data
*
- * @name: short name for this device ("SSI0", "SSI1", etc)
* @ssi: pointer to the SSI's registers
* @ssi_phys: physical address of the SSI registers
* @irq: IRQ of this SSI
* @first_stream: pointer to the stream that was opened first
* @second_stream: pointer to second stream
- * @dev: struct device pointer
* @playback: the number of playback streams opened
* @capture: the number of capture streams opened
* @asynchronous: 0=synchronous mode, 1=asynchronous mode
* @cpu_dai: the CPU DAI for this device
* @dev_attr: the sysfs device attribute structure
* @stats: SSI statistics
+ * @name: name for this device
*/
struct fsl_ssi_private {
- char name[8];
struct ccsr_ssi __iomem *ssi;
dma_addr_t ssi_phys;
unsigned int irq;
struct snd_pcm_substream *first_stream;
struct snd_pcm_substream *second_stream;
- struct device *dev;
unsigned int playback;
unsigned int capture;
int asynchronous;
- struct snd_soc_dai cpu_dai;
+ unsigned int fifo_depth;
+ struct snd_soc_dai_driver cpu_dai_drv;
struct device_attribute dev_attr;
+ struct platform_device *pdev;
struct {
unsigned int rfrc;
@@ -122,6 +121,8 @@ struct fsl_ssi_private {
unsigned int tfe1;
unsigned int tfe0;
} stats;
+
+ char name[1];
};
/**
@@ -280,7 +281,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+ struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
/*
* If this is the first stream opened, then request the IRQ
@@ -290,6 +291,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
int ret;
+ /* The 'name' should not have any slashes in it. */
ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0,
ssi_private->name, ssi_private);
if (ret < 0) {
@@ -336,11 +338,20 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
/*
* Set the watermark for transmit FIFI 0 and receive FIFO 0. We
- * don't use FIFO 1. Since the SSI only supports stereo, the
- * watermark should never be an odd number.
+ * don't use FIFO 1. We program the transmit water to signal a
+ * DMA transfer if there are only two (or fewer) elements left
+ * in the FIFO. Two elements equals one frame (left channel,
+ * right channel). This value, however, depends on the depth of
+ * the transmit buffer.
+ *
+ * We program the receive FIFO to notify us if at least two
+ * elements (one frame) have been written to the FIFO. We could
+ * make this value larger (and maybe we should), but this way
+ * data will be written to memory as soon as it's available.
*/
out_be32(&ssi->sfcsr,
- CCSR_SSI_SFCSR_TFWM0(6) | CCSR_SSI_SFCSR_RFWM0(2));
+ CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) |
+ CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2));
/*
* We keep the SSI disabled because if we enable it, then the
@@ -422,7 +433,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai)
{
- struct fsl_ssi_private *ssi_private = cpu_dai->private_data;
+ struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
if (substream == ssi_private->first_stream) {
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
@@ -458,7 +469,7 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+ struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
switch (cmd) {
@@ -497,7 +508,7 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+ struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
ssi_private->playback--;
@@ -523,56 +534,15 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
}
}
-/**
- * fsl_ssi_set_sysclk: set the clock frequency and direction
- *
- * This function is called by the machine driver to tell us what the clock
- * frequency and direction are.
- *
- * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN),
- * and we don't care about the frequency. Return an error if the direction
- * is not SND_SOC_CLOCK_IN.
- *
- * @clk_id: reserved, should be zero
- * @freq: the frequency of the given clock ID, currently ignored
- * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master)
- */
-static int fsl_ssi_set_sysclk(struct snd_soc_dai *cpu_dai,
- int clk_id, unsigned int freq, int dir)
-{
-
- return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
-}
-
-/**
- * fsl_ssi_set_fmt: set the serial format.
- *
- * This function is called by the machine driver to tell us what serial
- * format to use.
- *
- * Currently, we only support I2S mode. Return an error if the format is
- * not SND_SOC_DAIFMT_I2S.
- *
- * @format: one of SND_SOC_DAIFMT_xxx
- */
-static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
-{
- return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
-}
-
-/**
- * fsl_ssi_dai_template: template CPU DAI for the SSI
- */
static struct snd_soc_dai_ops fsl_ssi_dai_ops = {
.startup = fsl_ssi_startup,
.hw_params = fsl_ssi_hw_params,
.shutdown = fsl_ssi_shutdown,
.trigger = fsl_ssi_trigger,
- .set_sysclk = fsl_ssi_set_sysclk,
- .set_fmt = fsl_ssi_set_fmt,
};
-static struct snd_soc_dai fsl_ssi_dai_template = {
+/* Template for the CPU dai driver structure */
+static struct snd_soc_dai_driver fsl_ssi_dai_template = {
.playback = {
/* The SSI does not support monaural audio. */
.channels_min = 2,
@@ -640,95 +610,195 @@ static ssize_t fsl_sysfs_ssi_show(struct device *dev,
}
/**
- * fsl_ssi_create_dai: create a snd_soc_dai structure
- *
- * This function is called by the machine driver to create a snd_soc_dai
- * structure. The function creates an ssi_private object, which contains
- * the snd_soc_dai. It also creates the sysfs statistics device.
+ * Make every character in a string lower-case
*/
-struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
+static void make_lowercase(char *s)
+{
+ char *p = s;
+ char c;
+
+ while ((c = *p)) {
+ if ((c >= 'A') && (c <= 'Z'))
+ *p = c + ('a' - 'A');
+ p++;
+ }
+}
+
+static int __devinit fsl_ssi_probe(struct platform_device *pdev,
+ const struct of_device_id *match)
{
- struct snd_soc_dai *fsl_ssi_dai;
struct fsl_ssi_private *ssi_private;
int ret = 0;
- struct device_attribute *dev_attr;
+ struct device_attribute *dev_attr = NULL;
+ struct device_node *np = pdev->dev.of_node;
+ const char *p, *sprop;
+ const uint32_t *iprop;
+ struct resource res;
+ char name[64];
+
+ /* SSIs that are not connected on the board should have a
+ * status = "disabled"
+ * property in their device tree nodes.
+ */
+ if (!of_device_is_available(np))
+ return -ENODEV;
+
+ /* Check for a codec-handle property. */
+ if (!of_get_property(np, "codec-handle", NULL)) {
+ dev_err(&pdev->dev, "missing codec-handle property\n");
+ return -ENODEV;
+ }
- ssi_private = kzalloc(sizeof(struct fsl_ssi_private), GFP_KERNEL);
+ /* We only support the SSI in "I2S Slave" mode */
+ sprop = of_get_property(np, "fsl,mode", NULL);
+ if (!sprop || strcmp(sprop, "i2s-slave")) {
+ dev_notice(&pdev->dev, "mode %s is unsupported\n", sprop);
+ return -ENODEV;
+ }
+
+ /* The DAI name is the last part of the full name of the node. */
+ p = strrchr(np->full_name, '/') + 1;
+ ssi_private = kzalloc(sizeof(struct fsl_ssi_private) + strlen(p),
+ GFP_KERNEL);
if (!ssi_private) {
- dev_err(ssi_info->dev, "could not allocate DAI object\n");
- return NULL;
+ dev_err(&pdev->dev, "could not allocate DAI object\n");
+ return -ENOMEM;
}
- memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template,
- sizeof(struct snd_soc_dai));
- fsl_ssi_dai = &ssi_private->cpu_dai;
- dev_attr = &ssi_private->dev_attr;
+ strcpy(ssi_private->name, p);
- sprintf(ssi_private->name, "ssi%u", (u8) ssi_info->id);
- ssi_private->ssi = ssi_info->ssi;
- ssi_private->ssi_phys = ssi_info->ssi_phys;
- ssi_private->irq = ssi_info->irq;
- ssi_private->dev = ssi_info->dev;
- ssi_private->asynchronous = ssi_info->asynchronous;
+ /* Initialize this copy of the CPU DAI driver structure */
+ memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
+ sizeof(fsl_ssi_dai_template));
+ ssi_private->cpu_dai_drv.name = ssi_private->name;
- dev_set_drvdata(ssi_private->dev, fsl_ssi_dai);
+ /* Get the addresses and IRQ */
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret) {
+ dev_err(&pdev->dev, "could not determine device resources\n");
+ kfree(ssi_private);
+ return ret;
+ }
+ ssi_private->ssi = ioremap(res.start, 1 + res.end - res.start);
+ ssi_private->ssi_phys = res.start;
+ ssi_private->irq = irq_of_parse_and_map(np, 0);
+
+ /* Are the RX and the TX clocks locked? */
+ if (of_find_property(np, "fsl,ssi-asynchronous", NULL))
+ ssi_private->asynchronous = 1;
+ else
+ ssi_private->cpu_dai_drv.symmetric_rates = 1;
+
+ /* Determine the FIFO depth. */
+ iprop = of_get_property(np, "fsl,fifo-depth", NULL);
+ if (iprop)
+ ssi_private->fifo_depth = *iprop;
+ else
+ /* Older 8610 DTs didn't have the fifo-depth property */
+ ssi_private->fifo_depth = 8;
/* Initialize the the device_attribute structure */
- dev_attr->attr.name = "ssi-stats";
+ dev_attr = &ssi_private->dev_attr;
+ dev_attr->attr.name = "statistics";
dev_attr->attr.mode = S_IRUGO;
dev_attr->show = fsl_sysfs_ssi_show;
- ret = device_create_file(ssi_private->dev, dev_attr);
+ ret = device_create_file(&pdev->dev, dev_attr);
if (ret) {
- dev_err(ssi_info->dev, "could not create sysfs %s file\n",
+ dev_err(&pdev->dev, "could not create sysfs %s file\n",
ssi_private->dev_attr.attr.name);
- kfree(fsl_ssi_dai);
- return NULL;
+ goto error;
}
- fsl_ssi_dai->private_data = ssi_private;
- fsl_ssi_dai->name = ssi_private->name;
- fsl_ssi_dai->id = ssi_info->id;
- fsl_ssi_dai->dev = ssi_info->dev;
- fsl_ssi_dai->symmetric_rates = 1;
+ /* Register with ASoC */
+ dev_set_drvdata(&pdev->dev, ssi_private);
+
+ ret = snd_soc_register_dai(&pdev->dev, &ssi_private->cpu_dai_drv);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
+ goto error;
+ }
- ret = snd_soc_register_dai(fsl_ssi_dai);
- if (ret != 0) {
- dev_err(ssi_info->dev, "failed to register DAI: %d\n", ret);
- kfree(fsl_ssi_dai);
- return NULL;
+ /* Trigger the machine driver's probe function. The platform driver
+ * name of the machine driver is taken from the /model property of the
+ * device tree. We also pass the address of the CPU DAI driver
+ * structure.
+ */
+ sprop = of_get_property(of_find_node_by_path("/"), "model", NULL);
+ /* Sometimes the model name has a "fsl," prefix, so we strip that. */
+ p = strrchr(sprop, ',');
+ if (p)
+ sprop = p + 1;
+ snprintf(name, sizeof(name), "snd-soc-%s", sprop);
+ make_lowercase(name);
+
+ ssi_private->pdev =
+ platform_device_register_data(&pdev->dev, name, 0, NULL, 0);
+ if (IS_ERR(ssi_private->pdev)) {
+ ret = PTR_ERR(ssi_private->pdev);
+ dev_err(&pdev->dev, "failed to register platform: %d\n", ret);
+ goto error;
}
- return fsl_ssi_dai;
+ return 0;
+
+error:
+ snd_soc_unregister_dai(&pdev->dev);
+ dev_set_drvdata(&pdev->dev, NULL);
+ if (dev_attr)
+ device_remove_file(&pdev->dev, dev_attr);
+ irq_dispose_mapping(ssi_private->irq);
+ iounmap(ssi_private->ssi);
+ kfree(ssi_private);
+
+ return ret;
}
-EXPORT_SYMBOL_GPL(fsl_ssi_create_dai);
-/**
- * fsl_ssi_destroy_dai: destroy the snd_soc_dai object
- *
- * This function undoes the operations of fsl_ssi_create_dai()
- */
-void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai)
+static int fsl_ssi_remove(struct platform_device *pdev)
{
- struct fsl_ssi_private *ssi_private =
- container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai);
-
- device_remove_file(ssi_private->dev, &ssi_private->dev_attr);
+ struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
- snd_soc_unregister_dai(&ssi_private->cpu_dai);
+ platform_device_unregister(ssi_private->pdev);
+ snd_soc_unregister_dai(&pdev->dev);
+ device_remove_file(&pdev->dev, &ssi_private->dev_attr);
kfree(ssi_private);
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai);
+
+static const struct of_device_id fsl_ssi_ids[] = {
+ { .compatible = "fsl,mpc8610-ssi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
+
+static struct of_platform_driver fsl_ssi_driver = {
+ .driver = {
+ .name = "fsl-ssi-dai",
+ .owner = THIS_MODULE,
+ .of_match_table = fsl_ssi_ids,
+ },
+ .probe = fsl_ssi_probe,
+ .remove = fsl_ssi_remove,
+};
static int __init fsl_ssi_init(void)
{
printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n");
- return 0;
+ return of_register_platform_driver(&fsl_ssi_driver);
}
+
+static void __exit fsl_ssi_exit(void)
+{
+ of_unregister_platform_driver(&fsl_ssi_driver);
+}
+
module_init(fsl_ssi_init);
+module_exit(fsl_ssi_exit);
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
index eade01feaab6..217300029b5b 100644
--- a/sound/soc/fsl/fsl_ssi.h
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -196,31 +196,5 @@ struct ccsr_ssi {
#define CCSR_SSI_SOR_WAIT(x) (((x) & 3) << CCSR_SSI_SOR_WAIT_SHIFT)
#define CCSR_SSI_SOR_SYNRST 0x00000001
-/* Instantiation data for an SSI interface
- *
- * This structure contains all the information that the the SSI driver needs
- * to instantiate an SSI interface with ALSA. The machine driver should
- * create this structure, fill it in, call fsl_ssi_create_dai(), and then
- * delete the structure.
- *
- * id: which SSI this is (0, 1, etc. )
- * ssi: pointer to the SSI's registers
- * ssi_phys: physical address of the SSI registers
- * irq: IRQ of this SSI
- * dev: struct device, used to create the sysfs statistics file
- * asynchronous: 0=synchronous mode, 1=asynchronous mode
-*/
-struct fsl_ssi_info {
- unsigned int id;
- struct ccsr_ssi __iomem *ssi;
- dma_addr_t ssi_phys;
- unsigned int irq;
- struct device *dev;
- int asynchronous;
-};
-
-struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info);
-void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai);
-
#endif
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 3dcd1469f283..dce6b551cd78 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -9,6 +9,8 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
#include <sound/soc.h>
@@ -107,7 +109,7 @@ static int psc_dma_hw_free(struct snd_pcm_substream *substream)
static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct snd_pcm_runtime *runtime = substream->runtime;
struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
@@ -212,7 +214,7 @@ static int psc_dma_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct psc_dma_stream *s;
int rc;
@@ -239,7 +241,7 @@ static int psc_dma_open(struct snd_pcm_substream *substream)
static int psc_dma_close(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct psc_dma_stream *s;
dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream);
@@ -264,7 +266,7 @@ static snd_pcm_uframes_t
psc_dma_pointer(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct psc_dma_stream *s;
dma_addr_t count;
@@ -302,11 +304,11 @@ static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
struct snd_pcm *pcm)
{
struct snd_soc_pcm_runtime *rtd = pcm->private_data;
- struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
size_t size = psc_dma_hardware.buffer_bytes_max;
int rc = 0;
- dev_dbg(rtd->socdev->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
+ dev_dbg(rtd->platform->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
card, dai, pcm);
if (!card->dev->dma_mask)
@@ -328,8 +330,8 @@ static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
goto capture_alloc_err;
}
- if (rtd->socdev->card->codec->ac97)
- rtd->socdev->card->codec->ac97->private_data = psc_dma;
+ if (rtd->codec->ac97)
+ rtd->codec->ac97->private_data = psc_dma;
return 0;
@@ -349,7 +351,7 @@ static void psc_dma_free(struct snd_pcm *pcm)
struct snd_pcm_substream *substream;
int stream;
- dev_dbg(rtd->socdev->dev, "psc_dma_free(pcm=%p)\n", pcm);
+ dev_dbg(rtd->platform->dev, "psc_dma_free(pcm=%p)\n", pcm);
for (stream = 0; stream < 2; stream++) {
substream = pcm->streams[stream].substream;
@@ -361,15 +363,14 @@ static void psc_dma_free(struct snd_pcm *pcm)
}
}
-struct snd_soc_platform mpc5200_audio_dma_platform = {
- .name = "mpc5200-psc-audio",
- .pcm_ops = &psc_dma_ops,
+static struct snd_soc_platform_driver mpc5200_audio_dma_platform = {
+ .ops = &psc_dma_ops,
.pcm_new = &psc_dma_new,
.pcm_free = &psc_dma_free,
};
-EXPORT_SYMBOL_GPL(mpc5200_audio_dma_platform);
-int mpc5200_audio_dma_create(struct platform_device *op)
+static int mpc5200_hpcd_probe(struct of_device *op,
+ const struct of_device_id *match)
{
phys_addr_t fifo;
struct psc_dma *psc_dma;
@@ -475,7 +476,7 @@ int mpc5200_audio_dma_create(struct platform_device *op)
dev_set_drvdata(&op->dev, psc_dma);
/* Tell the ASoC OF helpers about it */
- return snd_soc_register_platform(&mpc5200_audio_dma_platform);
+ return snd_soc_register_platform(&op->dev, &mpc5200_audio_dma_platform);
out_irq:
free_irq(psc_dma->irq, psc_dma);
free_irq(psc_dma->capture.irq, &psc_dma->capture);
@@ -486,15 +487,14 @@ out_unmap:
iounmap(regs);
return ret;
}
-EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);
-int mpc5200_audio_dma_destroy(struct platform_device *op)
+static int mpc5200_hpcd_remove(struct of_device *op)
{
struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);
dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n");
- snd_soc_unregister_platform(&mpc5200_audio_dma_platform);
+ snd_soc_unregister_platform(&op->dev);
bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);
bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);
@@ -510,7 +510,35 @@ int mpc5200_audio_dma_destroy(struct platform_device *op)
return 0;
}
-EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy);
+
+static struct of_device_id mpc5200_hpcd_match[] = {
+ {
+ .compatible = "fsl,mpc5200-pcm",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mpc5200_hpcd_match);
+
+static struct of_platform_driver mpc5200_hpcd_of_driver = {
+ .owner = THIS_MODULE,
+ .name = "mpc5200-pcm-audio",
+ .match_table = mpc5200_hpcd_match,
+ .probe = mpc5200_hpcd_probe,
+ .remove = mpc5200_hpcd_remove,
+};
+
+static int __init mpc5200_hpcd_init(void)
+{
+ return of_register_platform_driver(&mpc5200_hpcd_of_driver);
+}
+
+static void __exit mpc5200_hpcd_exit(void)
+{
+ of_unregister_platform_driver(&mpc5200_hpcd_of_driver);
+}
+
+module_init(mpc5200_hpcd_init);
+module_exit(mpc5200_hpcd_exit);
MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h
index ca99586f2ad9..a3c0cd5382fb 100644
--- a/sound/soc/fsl/mpc5200_dma.h
+++ b/sound/soc/fsl/mpc5200_dma.h
@@ -81,9 +81,4 @@ to_psc_dma_stream(struct snd_pcm_substream *substream, struct psc_dma *psc_dma)
return &psc_dma->playback;
}
-int mpc5200_audio_dma_create(struct platform_device *op);
-int mpc5200_audio_dma_destroy(struct platform_device *op);
-
-extern struct snd_soc_platform mpc5200_audio_dma_platform;
-
#endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index a9560235daee..40acc8e2b1ca 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -143,7 +143,7 @@ static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct psc_dma *psc_dma = cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
@@ -166,7 +166,7 @@ static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct psc_dma *psc_dma = cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
dev_dbg(psc_dma->dev, "%s(substream=%p)\n", __func__, substream);
@@ -181,8 +181,7 @@ static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(dai);
struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
switch (cmd) {
@@ -207,10 +206,9 @@ static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
-static int psc_ac97_probe(struct platform_device *pdev,
- struct snd_soc_dai *cpu_dai)
+static int psc_ac97_probe(struct snd_soc_dai *cpu_dai)
{
- struct psc_dma *psc_dma = cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
/* Go */
@@ -237,9 +235,8 @@ static struct snd_soc_dai_ops psc_ac97_digital_ops = {
.hw_params = psc_ac97_hw_digital_params,
};
-struct snd_soc_dai psc_ac97_dai[] = {
+static struct snd_soc_dai_driver psc_ac97_dai[] = {
{
- .name = "AC97",
.ac97_control = 1,
.probe = psc_ac97_probe,
.playback = {
@@ -257,7 +254,6 @@ struct snd_soc_dai psc_ac97_dai[] = {
.ops = &psc_ac97_analog_ops,
},
{
- .name = "SPDIF",
.ac97_control = 1,
.playback = {
.channels_min = 1,
@@ -268,7 +264,6 @@ struct snd_soc_dai psc_ac97_dai[] = {
},
.ops = &psc_ac97_digital_ops,
} };
-EXPORT_SYMBOL_GPL(psc_ac97_dai);
@@ -280,18 +275,11 @@ EXPORT_SYMBOL_GPL(psc_ac97_dai);
static int __devinit psc_ac97_of_probe(struct platform_device *op,
const struct of_device_id *match)
{
- int rc, i;
+ int rc;
struct snd_ac97 ac97;
struct mpc52xx_psc __iomem *regs;
- rc = mpc5200_audio_dma_create(op);
- if (rc != 0)
- return rc;
-
- for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
- psc_ac97_dai[i].dev = &op->dev;
-
- rc = snd_soc_register_dais(psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
+ rc = snd_soc_register_dais(&op->dev, psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
if (rc != 0) {
dev_err(&op->dev, "Failed to register DAI\n");
return rc;
@@ -301,9 +289,6 @@ static int __devinit psc_ac97_of_probe(struct platform_device *op,
regs = psc_dma->psc_regs;
ac97.private_data = psc_dma;
- for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
- psc_ac97_dai[i].private_data = psc_dma;
-
psc_dma->imr = 0;
out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
@@ -319,7 +304,8 @@ static int __devinit psc_ac97_of_probe(struct platform_device *op,
static int __devexit psc_ac97_of_remove(struct platform_device *op)
{
- return mpc5200_audio_dma_destroy(op);
+ snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai));
+ return 0;
}
/* Match table for of_platform binding */
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.h b/sound/soc/fsl/mpc5200_psc_ac97.h
index 4bc18c35c369..e881e784b270 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.h
+++ b/sound/soc/fsl/mpc5200_psc_ac97.h
@@ -7,8 +7,6 @@
#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
#define __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
-extern struct snd_soc_dai psc_ac97_dai[];
-
#define MPC5200_AC97_NORMAL 0
#define MPC5200_AC97_SPDIF 1
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 534f04cb15d7..74ffed41340f 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -40,7 +40,7 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
u32 mode;
dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
@@ -88,7 +88,7 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
- struct psc_dma *psc_dma = cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
dev_dbg(psc_dma->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n",
cpu_dai, dir);
return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
@@ -107,7 +107,7 @@ static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
*/
static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
{
- struct psc_dma *psc_dma = cpu_dai->private_data;
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
dev_dbg(psc_dma->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n",
cpu_dai, format);
return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
@@ -129,8 +129,7 @@ static struct snd_soc_dai_ops psc_i2s_dai_ops = {
.set_fmt = psc_i2s_set_fmt,
};
-struct snd_soc_dai psc_i2s_dai[] = {{
- .name = "I2S",
+static struct snd_soc_dai_driver psc_i2s_dai[] = {{
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -145,7 +144,6 @@ struct snd_soc_dai psc_i2s_dai[] = {{
},
.ops = &psc_i2s_dai_ops,
} };
-EXPORT_SYMBOL_GPL(psc_i2s_dai);
/* ---------------------------------------------------------------------
* OF platform bus binding code:
@@ -159,11 +157,7 @@ static int __devinit psc_i2s_of_probe(struct platform_device *op,
struct psc_dma *psc_dma;
struct mpc52xx_psc __iomem *regs;
- rc = mpc5200_audio_dma_create(op);
- if (rc != 0)
- return rc;
-
- rc = snd_soc_register_dais(psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
+ rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
if (rc != 0) {
pr_err("Failed to register DAI\n");
return 0;
@@ -207,7 +201,8 @@ static int __devinit psc_i2s_of_probe(struct platform_device *op,
static int __devexit psc_i2s_of_remove(struct platform_device *op)
{
- return mpc5200_audio_dma_destroy(op);
+ snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai));
+ return 0;
}
/* Match table for of_platform binding */
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 3b13b8d65262..0d7dcf1e4863 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -1,85 +1,97 @@
/**
- * Freescale MPC8610HPCD ALSA SoC Fabric driver
+ * Freescale MPC8610HPCD ALSA SoC Machine driver
*
* Author: Timur Tabi <timur@freescale.com>
*
- * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed
- * under the terms of the GNU General Public License version 2. This
- * program is licensed "as is" without any warranty of any kind, whether
- * express or implied.
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
*/
-#include <linux/slab.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/of_device.h>
-#include <linux/of_platform.h>
+#include <linux/slab.h>
#include <sound/soc.h>
-#include <asm/immap_86xx.h>
+#include <asm/fsl_guts.h>
-#include "../codecs/cs4270.h"
#include "fsl_dma.h"
#include "fsl_ssi.h"
+/* There's only one global utilities register */
+static phys_addr_t guts_phys;
+
+#define DAI_NAME_SIZE 32
+
/**
- * mpc8610_hpcd_data: fabric-specific ASoC device data
+ * mpc8610_hpcd_data: machine-specific ASoC device data
*
* This structure contains data for a single sound platform device on an
* MPC8610 HPCD. Some of the data is taken from the device tree.
*/
struct mpc8610_hpcd_data {
- struct snd_soc_device sound_devdata;
- struct snd_soc_dai_link dai;
- struct snd_soc_card machine;
+ struct snd_soc_dai_link dai[2];
+ struct snd_soc_card card;
unsigned int dai_format;
unsigned int codec_clk_direction;
unsigned int cpu_clk_direction;
unsigned int clk_frequency;
- struct ccsr_guts __iomem *guts;
- struct ccsr_ssi __iomem *ssi;
- unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */
- unsigned int ssi_irq;
- unsigned int dma_id; /* 0 = DMA1, 1 = DMA2, etc */
- unsigned int dma_irq[2];
- struct ccsr_dma_channel __iomem *dma[2];
+ unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */
+ unsigned int dma_id[2]; /* 0 = DMA1, 1 = DMA2, etc */
unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
+ char codec_dai_name[DAI_NAME_SIZE];
+ char codec_name[DAI_NAME_SIZE];
+ char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
};
/**
* mpc8610_hpcd_machine_probe: initialize the board
*
- * This function is called when platform_device_add() is called. It is used
- * to initialize the board-specific hardware.
+ * This function is used to initialize the board-specific hardware.
*
* Here we program the DMACR and PMUXCR registers.
*/
static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device)
{
+ struct snd_soc_card *card = platform_get_drvdata(sound_device);
struct mpc8610_hpcd_data *machine_data =
- sound_device->dev.platform_data;
+ container_of(card, struct mpc8610_hpcd_data, card);
+ struct ccsr_guts_86xx __iomem *guts;
- /* Program the signal routing between the SSI and the DMA */
- guts_set_dmacr(machine_data->guts, machine_data->dma_id,
- machine_data->dma_channel_id[0], CCSR_GUTS_DMACR_DEV_SSI);
- guts_set_dmacr(machine_data->guts, machine_data->dma_id,
- machine_data->dma_channel_id[1], CCSR_GUTS_DMACR_DEV_SSI);
+ guts = ioremap(guts_phys, sizeof(struct ccsr_guts_86xx));
+ if (!guts) {
+ dev_err(card->dev, "could not map global utilities\n");
+ return -ENOMEM;
+ }
- guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id,
- machine_data->dma_channel_id[0], 0);
- guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id,
- machine_data->dma_channel_id[1], 0);
+ /* Program the signal routing between the SSI and the DMA */
+ guts_set_dmacr(guts, machine_data->dma_id[0],
+ machine_data->dma_channel_id[0],
+ CCSR_GUTS_DMACR_DEV_SSI);
+ guts_set_dmacr(guts, machine_data->dma_id[1],
+ machine_data->dma_channel_id[1],
+ CCSR_GUTS_DMACR_DEV_SSI);
+
+ guts_set_pmuxcr_dma(guts, machine_data->dma_id[0],
+ machine_data->dma_channel_id[0], 0);
+ guts_set_pmuxcr_dma(guts, machine_data->dma_id[1],
+ machine_data->dma_channel_id[1], 0);
switch (machine_data->ssi_id) {
case 0:
- clrsetbits_be32(&machine_data->guts->pmuxcr,
+ clrsetbits_be32(&guts->pmuxcr,
CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_SSI);
break;
case 1:
- clrsetbits_be32(&machine_data->guts->pmuxcr,
+ clrsetbits_be32(&guts->pmuxcr,
CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_SSI);
break;
}
+ iounmap(guts);
+
return 0;
}
@@ -93,38 +105,15 @@ static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device)
static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
struct mpc8610_hpcd_data *machine_data =
- rtd->socdev->dev->platform_data;
+ container_of(rtd->card, struct mpc8610_hpcd_data, card);
+ struct device *dev = rtd->card->dev;
int ret = 0;
- /* Tell the CPU driver what the serial protocol is. */
- ret = snd_soc_dai_set_fmt(cpu_dai, machine_data->dai_format);
- if (ret < 0) {
- dev_err(substream->pcm->card->dev,
- "could not set CPU driver audio format\n");
- return ret;
- }
-
/* Tell the codec driver what the serial protocol is. */
- ret = snd_soc_dai_set_fmt(codec_dai, machine_data->dai_format);
+ ret = snd_soc_dai_set_fmt(rtd->codec_dai, machine_data->dai_format);
if (ret < 0) {
- dev_err(substream->pcm->card->dev,
- "could not set codec driver audio format\n");
- return ret;
- }
-
- /*
- * Tell the CPU driver what the clock frequency is, and whether it's a
- * slave or master.
- */
- ret = snd_soc_dai_set_sysclk(cpu_dai, 0,
- machine_data->clk_frequency,
- machine_data->cpu_clk_direction);
- if (ret < 0) {
- dev_err(substream->pcm->card->dev,
- "could not set CPU driver clock parameters\n");
+ dev_err(dev, "could not set codec driver audio format\n");
return ret;
}
@@ -132,12 +121,11 @@ static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
* Tell the codec driver what the MCLK frequency is, and whether it's
* a slave or master.
*/
- ret = snd_soc_dai_set_sysclk(codec_dai, 0,
- machine_data->clk_frequency,
- machine_data->codec_clk_direction);
+ ret = snd_soc_dai_set_sysclk(rtd->codec_dai, 0,
+ machine_data->clk_frequency,
+ machine_data->codec_clk_direction);
if (ret < 0) {
- dev_err(substream->pcm->card->dev,
- "could not set codec driver clock params\n");
+ dev_err(dev, "could not set codec driver clock params\n");
return ret;
}
@@ -150,116 +138,255 @@ static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
* This function is called to remove the sound device for one SSI. We
* de-program the DMACR and PMUXCR register.
*/
-int mpc8610_hpcd_machine_remove(struct platform_device *sound_device)
+static int mpc8610_hpcd_machine_remove(struct platform_device *sound_device)
{
+ struct snd_soc_card *card = platform_get_drvdata(sound_device);
struct mpc8610_hpcd_data *machine_data =
- sound_device->dev.platform_data;
+ container_of(card, struct mpc8610_hpcd_data, card);
+ struct ccsr_guts_86xx __iomem *guts;
+
+ guts = ioremap(guts_phys, sizeof(struct ccsr_guts_86xx));
+ if (!guts) {
+ dev_err(card->dev, "could not map global utilities\n");
+ return -ENOMEM;
+ }
/* Restore the signal routing */
- guts_set_dmacr(machine_data->guts, machine_data->dma_id,
- machine_data->dma_channel_id[0], 0);
- guts_set_dmacr(machine_data->guts, machine_data->dma_id,
- machine_data->dma_channel_id[1], 0);
+ guts_set_dmacr(guts, machine_data->dma_id[0],
+ machine_data->dma_channel_id[0], 0);
+ guts_set_dmacr(guts, machine_data->dma_id[1],
+ machine_data->dma_channel_id[1], 0);
switch (machine_data->ssi_id) {
case 0:
- clrsetbits_be32(&machine_data->guts->pmuxcr,
+ clrsetbits_be32(&guts->pmuxcr,
CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_LA);
break;
case 1:
- clrsetbits_be32(&machine_data->guts->pmuxcr,
+ clrsetbits_be32(&guts->pmuxcr,
CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_LA);
break;
}
+ iounmap(guts);
+
return 0;
}
/**
- * mpc8610_hpcd_ops: ASoC fabric driver operations
+ * mpc8610_hpcd_ops: ASoC machine driver operations
*/
static struct snd_soc_ops mpc8610_hpcd_ops = {
.startup = mpc8610_hpcd_startup,
};
/**
- * mpc8610_hpcd_probe: OF probe function for the fabric driver
+ * get_node_by_phandle_name - get a node by its phandle name
*
- * This function gets called when an SSI node is found in the device tree.
+ * This function takes a node, the name of a property in that node, and a
+ * compatible string. Assuming the property is a phandle to another node,
+ * it returns that node, (optionally) if that node is compatible.
*
- * Although this is a fabric driver, the SSI node is the "master" node with
- * respect to audio hardware connections. Therefore, we create a new ASoC
- * device for each new SSI node that has a codec attached.
+ * If the property is not a phandle, or the node it points to is not compatible
+ * with the specific string, then NULL is returned.
+ */
+static struct device_node *get_node_by_phandle_name(struct device_node *np,
+ const char *name,
+ const char *compatible)
+{
+ const phandle *ph;
+ int len;
+
+ ph = of_get_property(np, name, &len);
+ if (!ph || (len != sizeof(phandle)))
+ return NULL;
+
+ np = of_find_node_by_phandle(*ph);
+ if (!np)
+ return NULL;
+
+ if (compatible && !of_device_is_compatible(np, compatible)) {
+ of_node_put(np);
+ return NULL;
+ }
+
+ return np;
+}
+
+/**
+ * get_parent_cell_index -- return the cell-index of the parent of a node
+ *
+ * Return the value of the cell-index property of the parent of the given
+ * node. This is used for DMA channel nodes that need to know the DMA ID
+ * of the controller they are on.
+ */
+static int get_parent_cell_index(struct device_node *np)
+{
+ struct device_node *parent = of_get_parent(np);
+ const u32 *iprop;
+
+ if (!parent)
+ return -1;
+
+ iprop = of_get_property(parent, "cell-index", NULL);
+ of_node_put(parent);
+
+ if (!iprop)
+ return -1;
+
+ return *iprop;
+}
+
+/**
+ * codec_node_dev_name - determine the dev_name for a codec node
*
- * FIXME: Currently, we only support one DMA controller, so if there are
- * multiple SSI nodes with codecs, only the first will be supported.
+ * This function determines the dev_name for an I2C node. This is the name
+ * that would be returned by dev_name() if this device_node were part of a
+ * 'struct device' It's ugly and hackish, but it works.
*
- * FIXME: Even if we did support multiple DMA controllers, we have no
- * mechanism for assigning DMA controllers and channels to the individual
- * SSI devices. We also probably aren't compatible with the generic Elo DMA
- * device driver.
+ * The dev_name for such devices include the bus number and I2C address. For
+ * example, "cs4270-codec.0-004f".
*/
-static int mpc8610_hpcd_probe(struct platform_device *ofdev,
- const struct of_device_id *match)
+static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
{
- struct device_node *np = ofdev->dev.of_node;
- struct device_node *codec_np = NULL;
- struct device_node *guts_np = NULL;
- struct device_node *dma_np = NULL;
- struct device_node *dma_channel_np = NULL;
- const phandle *codec_ph;
- const char *sprop;
const u32 *iprop;
+ int bus, addr;
+ char temp[DAI_NAME_SIZE];
+
+ of_modalias_node(np, temp, DAI_NAME_SIZE);
+
+ iprop = of_get_property(np, "reg", NULL);
+ if (!iprop)
+ return -EINVAL;
+
+ addr = *iprop;
+
+ bus = get_parent_cell_index(np);
+ if (bus < 0)
+ return bus;
+
+ snprintf(buf, len, "%s-codec.%u-%04x", temp, bus, addr);
+
+ return 0;
+}
+
+static int get_dma_channel(struct device_node *ssi_np,
+ const char *compatible,
+ struct snd_soc_dai_link *dai,
+ unsigned int *dma_channel_id,
+ unsigned int *dma_id)
+{
struct resource res;
+ struct device_node *dma_channel_np;
+ const u32 *iprop;
+ int ret;
+
+ dma_channel_np = get_node_by_phandle_name(ssi_np, compatible,
+ "fsl,ssi-dma-channel");
+ if (!dma_channel_np)
+ return -EINVAL;
+
+ /* Determine the dev_name for the device_node. This code mimics the
+ * behavior of of_device_make_bus_id(). We need this because ASoC uses
+ * the dev_name() of the device to match the platform (DMA) device with
+ * the CPU (SSI) device. It's all ugly and hackish, but it works (for
+ * now).
+ *
+ * dai->platform name should already point to an allocated buffer.
+ */
+ ret = of_address_to_resource(dma_channel_np, 0, &res);
+ if (ret)
+ return ret;
+ snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
+ (unsigned long long) res.start, dma_channel_np->name);
+
+ iprop = of_get_property(dma_channel_np, "cell-index", NULL);
+ if (!iprop) {
+ of_node_put(dma_channel_np);
+ return -EINVAL;
+ }
+
+ *dma_channel_id = *iprop;
+ *dma_id = get_parent_cell_index(dma_channel_np);
+ of_node_put(dma_channel_np);
+
+ return 0;
+}
+
+/**
+ * mpc8610_hpcd_probe: platform probe function for the machine driver
+ *
+ * Although this is a machine driver, the SSI node is the "master" node with
+ * respect to audio hardware connections. Therefore, we create a new ASoC
+ * device for each new SSI node that has a codec attached.
+ */
+static int mpc8610_hpcd_probe(struct platform_device *pdev)
+{
+ struct device *dev = pdev->dev.parent;
+ /* ssi_pdev is the platform device for the SSI node that probed us */
+ struct platform_device *ssi_pdev =
+ container_of(dev, struct platform_device, dev);
+ struct device_node *np = ssi_pdev->dev.of_node;
+ struct device_node *codec_np = NULL;
struct platform_device *sound_device = NULL;
struct mpc8610_hpcd_data *machine_data;
- struct fsl_ssi_info ssi_info;
- struct fsl_dma_info dma_info;
int ret = -ENODEV;
- unsigned int playback_dma_channel;
- unsigned int capture_dma_channel;
+ const char *sprop;
+ const u32 *iprop;
+
+ /* We are only interested in SSIs with a codec phandle in them,
+ * so let's make sure this SSI has one. The MPC8610 HPCD only
+ * knows about the CS4270 codec, so reject anything else.
+ */
+ codec_np = get_node_by_phandle_name(np, "codec-handle",
+ "cirrus,cs4270");
+ if (!codec_np) {
+ dev_err(dev, "invalid codec node\n");
+ return -EINVAL;
+ }
machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL);
if (!machine_data)
return -ENOMEM;
- memset(&ssi_info, 0, sizeof(ssi_info));
- memset(&dma_info, 0, sizeof(dma_info));
+ machine_data->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
+ machine_data->dai[0].ops = &mpc8610_hpcd_ops;
- ssi_info.dev = &ofdev->dev;
-
- /*
- * We are only interested in SSIs with a codec phandle in them, so let's
- * make sure this SSI has one.
- */
- codec_ph = of_get_property(np, "codec-handle", NULL);
- if (!codec_ph)
+ /* Determine the codec name, it will be used as the codec DAI name */
+ ret = codec_node_dev_name(codec_np, machine_data->codec_name,
+ DAI_NAME_SIZE);
+ if (ret) {
+ dev_err(&pdev->dev, "invalid codec node %s\n",
+ codec_np->full_name);
+ ret = -EINVAL;
goto error;
+ }
+ machine_data->dai[0].codec_name = machine_data->codec_name;
- codec_np = of_find_node_by_phandle(*codec_ph);
- if (!codec_np)
- goto error;
+ /* The DAI name from the codec (snd_soc_dai_driver.name) */
+ machine_data->dai[0].codec_dai_name = "cs4270-hifi";
- /* The MPC8610 HPCD only knows about the CS4270 codec, so reject
- anything else. */
- if (!of_device_is_compatible(codec_np, "cirrus,cs4270"))
- goto error;
+ /* We register two DAIs per SSI, one for playback and the other for
+ * capture. Currently, we only support codecs that have one DAI for
+ * both playback and capture.
+ */
+ memcpy(&machine_data->dai[1], &machine_data->dai[0],
+ sizeof(struct snd_soc_dai_link));
/* Get the device ID */
iprop = of_get_property(np, "cell-index", NULL);
if (!iprop) {
- dev_err(&ofdev->dev, "cell-index property not found\n");
+ dev_err(&pdev->dev, "cell-index property not found\n");
ret = -EINVAL;
goto error;
}
machine_data->ssi_id = *iprop;
- ssi_info.id = *iprop;
/* Get the serial format and clock direction. */
sprop = of_get_property(np, "fsl,mode", NULL);
if (!sprop) {
- dev_err(&ofdev->dev, "fsl,mode property not found\n");
+ dev_err(&pdev->dev, "fsl,mode property not found\n");
ret = -EINVAL;
goto error;
}
@@ -269,15 +396,14 @@ static int mpc8610_hpcd_probe(struct platform_device *ofdev,
machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
- /*
- * In i2s-slave mode, the codec has its own clock source, so we
+ /* In i2s-slave mode, the codec has its own clock source, so we
* need to get the frequency from the device tree and pass it to
* the codec driver.
*/
iprop = of_get_property(codec_np, "clock-frequency", NULL);
if (!iprop || !*iprop) {
- dev_err(&ofdev->dev, "codec bus-frequency property "
- "is missing or invalid\n");
+ dev_err(&pdev->dev, "codec bus-frequency "
+ "property is missing or invalid\n");
ret = -EINVAL;
goto error;
}
@@ -311,317 +437,153 @@ static int mpc8610_hpcd_probe(struct platform_device *ofdev,
machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
} else {
- dev_err(&ofdev->dev,
- "unrecognized fsl,mode property \"%s\"\n", sprop);
+ dev_err(&pdev->dev,
+ "unrecognized fsl,mode property '%s'\n", sprop);
ret = -EINVAL;
goto error;
}
if (!machine_data->clk_frequency) {
- dev_err(&ofdev->dev, "unknown clock frequency\n");
+ dev_err(&pdev->dev, "unknown clock frequency\n");
ret = -EINVAL;
goto error;
}
- /* Read the SSI information from the device tree */
- ret = of_address_to_resource(np, 0, &res);
+ /* Find the playback DMA channel to use. */
+ machine_data->dai[0].platform_name = machine_data->platform_name[0];
+ ret = get_dma_channel(np, "fsl,playback-dma", &machine_data->dai[0],
+ &machine_data->dma_channel_id[0],
+ &machine_data->dma_id[0]);
if (ret) {
- dev_err(&ofdev->dev, "could not obtain SSI address\n");
- goto error;
- }
- if (!res.start) {
- dev_err(&ofdev->dev, "invalid SSI address\n");
- goto error;
- }
- ssi_info.ssi_phys = res.start;
-
- machine_data->ssi = ioremap(ssi_info.ssi_phys, sizeof(struct ccsr_ssi));
- if (!machine_data->ssi) {
- dev_err(&ofdev->dev, "could not map SSI address %x\n",
- ssi_info.ssi_phys);
- ret = -EINVAL;
- goto error;
- }
- ssi_info.ssi = machine_data->ssi;
-
-
- /* Get the IRQ of the SSI */
- machine_data->ssi_irq = irq_of_parse_and_map(np, 0);
- if (!machine_data->ssi_irq) {
- dev_err(&ofdev->dev, "could not get SSI IRQ\n");
- ret = -EINVAL;
- goto error;
- }
- ssi_info.irq = machine_data->ssi_irq;
-
- /* Do we want to use asynchronous mode? */
- ssi_info.asynchronous =
- of_find_property(np, "fsl,ssi-asynchronous", NULL) ? 1 : 0;
- if (ssi_info.asynchronous)
- dev_info(&ofdev->dev, "using asynchronous mode\n");
-
- /* Map the global utilities registers. */
- guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
- if (!guts_np) {
- dev_err(&ofdev->dev, "could not obtain address of GUTS\n");
- ret = -EINVAL;
- goto error;
- }
- machine_data->guts = of_iomap(guts_np, 0);
- of_node_put(guts_np);
- if (!machine_data->guts) {
- dev_err(&ofdev->dev, "could not map GUTS\n");
- ret = -EINVAL;
- goto error;
- }
-
- /* Find the DMA channels to use. Both SSIs need to use the same DMA
- * controller, so let's use DMA#1.
- */
- for_each_compatible_node(dma_np, NULL, "fsl,mpc8610-dma") {
- iprop = of_get_property(dma_np, "cell-index", NULL);
- if (iprop && (*iprop == 0)) {
- of_node_put(dma_np);
- break;
- }
- }
- if (!dma_np) {
- dev_err(&ofdev->dev, "could not find DMA node\n");
- ret = -EINVAL;
- goto error;
- }
- machine_data->dma_id = *iprop;
-
- /* SSI1 needs to use DMA Channels 0 and 1, and SSI2 needs to use DMA
- * channels 2 and 3. This is just how the MPC8610 is wired
- * internally.
- */
- playback_dma_channel = (machine_data->ssi_id == 0) ? 0 : 2;
- capture_dma_channel = (machine_data->ssi_id == 0) ? 1 : 3;
-
- /*
- * Find the DMA channels to use.
- */
- while ((dma_channel_np = of_get_next_child(dma_np, dma_channel_np))) {
- iprop = of_get_property(dma_channel_np, "cell-index", NULL);
- if (iprop && (*iprop == playback_dma_channel)) {
- /* dma_channel[0] and dma_irq[0] are for playback */
- dma_info.dma_channel[0] = of_iomap(dma_channel_np, 0);
- dma_info.dma_irq[0] =
- irq_of_parse_and_map(dma_channel_np, 0);
- machine_data->dma_channel_id[0] = *iprop;
- continue;
- }
- if (iprop && (*iprop == capture_dma_channel)) {
- /* dma_channel[1] and dma_irq[1] are for capture */
- dma_info.dma_channel[1] = of_iomap(dma_channel_np, 0);
- dma_info.dma_irq[1] =
- irq_of_parse_and_map(dma_channel_np, 0);
- machine_data->dma_channel_id[1] = *iprop;
- continue;
- }
- }
- if (!dma_info.dma_channel[0] || !dma_info.dma_channel[1] ||
- !dma_info.dma_irq[0] || !dma_info.dma_irq[1]) {
- dev_err(&ofdev->dev, "could not find DMA channels\n");
- ret = -EINVAL;
+ dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
goto error;
}
- dma_info.ssi_stx_phys = ssi_info.ssi_phys +
- offsetof(struct ccsr_ssi, stx0);
- dma_info.ssi_srx_phys = ssi_info.ssi_phys +
- offsetof(struct ccsr_ssi, srx0);
-
- /* We have the DMA information, so tell the DMA driver what it is */
- if (!fsl_dma_configure(&dma_info)) {
- dev_err(&ofdev->dev, "could not instantiate DMA device\n");
- ret = -EBUSY;
+ /* Find the capture DMA channel to use. */
+ machine_data->dai[1].platform_name = machine_data->platform_name[1];
+ ret = get_dma_channel(np, "fsl,capture-dma", &machine_data->dai[1],
+ &machine_data->dma_channel_id[1],
+ &machine_data->dma_id[1]);
+ if (ret) {
+ dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
goto error;
}
- /*
- * Initialize our DAI data structure. We should probably get this
- * information from the device tree.
- */
- machine_data->dai.name = "CS4270";
- machine_data->dai.stream_name = "CS4270";
-
- machine_data->dai.cpu_dai = fsl_ssi_create_dai(&ssi_info);
- machine_data->dai.codec_dai = &cs4270_dai; /* The codec_dai we want */
- machine_data->dai.ops = &mpc8610_hpcd_ops;
+ /* Initialize our DAI data structure. */
+ machine_data->dai[0].stream_name = "playback";
+ machine_data->dai[1].stream_name = "capture";
+ machine_data->dai[0].name = machine_data->dai[0].stream_name;
+ machine_data->dai[1].name = machine_data->dai[1].stream_name;
- machine_data->machine.probe = mpc8610_hpcd_machine_probe;
- machine_data->machine.remove = mpc8610_hpcd_machine_remove;
- machine_data->machine.name = "MPC8610 HPCD";
- machine_data->machine.num_links = 1;
- machine_data->machine.dai_link = &machine_data->dai;
+ machine_data->card.probe = mpc8610_hpcd_machine_probe;
+ machine_data->card.remove = mpc8610_hpcd_machine_remove;
+ machine_data->card.name = pdev->name; /* The platform driver name */
+ machine_data->card.num_links = 2;
+ machine_data->card.dai_link = machine_data->dai;
/* Allocate a new audio platform device structure */
sound_device = platform_device_alloc("soc-audio", -1);
if (!sound_device) {
- dev_err(&ofdev->dev, "platform device allocation failed\n");
+ dev_err(&pdev->dev, "platform device alloc failed\n");
ret = -ENOMEM;
goto error;
}
- machine_data->sound_devdata.card = &machine_data->machine;
- machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270;
- machine_data->machine.platform = &fsl_soc_platform;
-
- sound_device->dev.platform_data = machine_data;
-
+ /* Associate the card data with the sound device */
+ platform_set_drvdata(sound_device, &machine_data->card);
- /* Set the platform device and ASoC device to point to each other */
- platform_set_drvdata(sound_device, &machine_data->sound_devdata);
-
- machine_data->sound_devdata.dev = &sound_device->dev;
-
-
- /* Tell ASoC to probe us. This will call mpc8610_hpcd_machine.probe(),
- if it exists. */
+ /* Register with ASoC */
ret = platform_device_add(sound_device);
-
if (ret) {
- dev_err(&ofdev->dev, "platform device add failed\n");
+ dev_err(&pdev->dev, "platform device add failed\n");
goto error;
}
- dev_set_drvdata(&ofdev->dev, sound_device);
+ of_node_put(codec_np);
return 0;
error:
of_node_put(codec_np);
- of_node_put(guts_np);
- of_node_put(dma_np);
- of_node_put(dma_channel_np);
if (sound_device)
platform_device_unregister(sound_device);
- if (machine_data->dai.cpu_dai)
- fsl_ssi_destroy_dai(machine_data->dai.cpu_dai);
-
- if (ssi_info.ssi)
- iounmap(ssi_info.ssi);
-
- if (ssi_info.irq)
- irq_dispose_mapping(ssi_info.irq);
-
- if (dma_info.dma_channel[0])
- iounmap(dma_info.dma_channel[0]);
-
- if (dma_info.dma_channel[1])
- iounmap(dma_info.dma_channel[1]);
-
- if (dma_info.dma_irq[0])
- irq_dispose_mapping(dma_info.dma_irq[0]);
-
- if (dma_info.dma_irq[1])
- irq_dispose_mapping(dma_info.dma_irq[1]);
-
- if (machine_data->guts)
- iounmap(machine_data->guts);
-
kfree(machine_data);
return ret;
}
/**
- * mpc8610_hpcd_remove: remove the OF device
+ * mpc8610_hpcd_remove: remove the platform device
*
- * This function is called when the OF device is removed.
+ * This function is called when the platform device is removed.
*/
-static int mpc8610_hpcd_remove(struct platform_device *ofdev)
+static int __devexit mpc8610_hpcd_remove(struct platform_device *pdev)
{
- struct platform_device *sound_device = dev_get_drvdata(&ofdev->dev);
+ struct platform_device *sound_device = dev_get_drvdata(&pdev->dev);
+ struct snd_soc_card *card = platform_get_drvdata(sound_device);
struct mpc8610_hpcd_data *machine_data =
- sound_device->dev.platform_data;
+ container_of(card, struct mpc8610_hpcd_data, card);
platform_device_unregister(sound_device);
- if (machine_data->dai.cpu_dai)
- fsl_ssi_destroy_dai(machine_data->dai.cpu_dai);
-
- if (machine_data->ssi)
- iounmap(machine_data->ssi);
-
- if (machine_data->dma[0])
- iounmap(machine_data->dma[0]);
-
- if (machine_data->dma[1])
- iounmap(machine_data->dma[1]);
-
- if (machine_data->dma_irq[0])
- irq_dispose_mapping(machine_data->dma_irq[0]);
-
- if (machine_data->dma_irq[1])
- irq_dispose_mapping(machine_data->dma_irq[1]);
-
- if (machine_data->guts)
- iounmap(machine_data->guts);
-
kfree(machine_data);
sound_device->dev.platform_data = NULL;
- dev_set_drvdata(&ofdev->dev, NULL);
+ dev_set_drvdata(&pdev->dev, NULL);
return 0;
}
-static struct of_device_id mpc8610_hpcd_match[] = {
- {
- .compatible = "fsl,mpc8610-ssi",
- },
- {}
-};
-MODULE_DEVICE_TABLE(of, mpc8610_hpcd_match);
-
-static struct of_platform_driver mpc8610_hpcd_of_driver = {
+static struct platform_driver mpc8610_hpcd_driver = {
+ .probe = mpc8610_hpcd_probe,
+ .remove = __devexit_p(mpc8610_hpcd_remove),
.driver = {
- .name = "mpc8610_hpcd",
+ /* The name must match the 'model' property in the device tree,
+ * in lowercase letters.
+ */
+ .name = "snd-soc-mpc8610hpcd",
.owner = THIS_MODULE,
- .of_match_table = mpc8610_hpcd_match,
},
- .probe = mpc8610_hpcd_probe,
- .remove = mpc8610_hpcd_remove,
};
/**
- * mpc8610_hpcd_init: fabric driver initialization.
+ * mpc8610_hpcd_init: machine driver initialization.
*
* This function is called when this module is loaded.
*/
static int __init mpc8610_hpcd_init(void)
{
- int ret;
-
- printk(KERN_INFO "Freescale MPC8610 HPCD ALSA SoC fabric driver\n");
+ struct device_node *guts_np;
+ struct resource res;
- ret = of_register_platform_driver(&mpc8610_hpcd_of_driver);
+ pr_info("Freescale MPC8610 HPCD ALSA SoC machine driver\n");
- if (ret)
- printk(KERN_ERR
- "mpc8610-hpcd: failed to register platform driver\n");
+ /* Get the physical address of the global utilities registers */
+ guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
+ if (of_address_to_resource(guts_np, 0, &res)) {
+ pr_err("mpc8610-hpcd: missing/invalid global utilities node\n");
+ return -EINVAL;
+ }
+ guts_phys = res.start;
- return ret;
+ return platform_driver_register(&mpc8610_hpcd_driver);
}
/**
- * mpc8610_hpcd_exit: fabric driver exit
+ * mpc8610_hpcd_exit: machine driver exit
*
* This function is called when this driver is unloaded.
*/
static void __exit mpc8610_hpcd_exit(void)
{
- of_unregister_platform_driver(&mpc8610_hpcd_of_driver);
+ platform_driver_unregister(&mpc8610_hpcd_driver);
}
module_init(mpc8610_hpcd_init);
module_exit(mpc8610_hpcd_exit);
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
-MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC fabric driver");
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC machine driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
new file mode 100644
index 000000000000..63b9eaa1ebc2
--- /dev/null
+++ b/sound/soc/fsl/p1022_ds.c
@@ -0,0 +1,591 @@
+/**
+ * Freescale P1022DS ALSA SoC Machine driver
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <asm/fsl_guts.h>
+
+#include "fsl_dma.h"
+#include "fsl_ssi.h"
+
+/* P1022-specific PMUXCR and DMUXCR bit definitions */
+
+#define CCSR_GUTS_PMUXCR_UART0_I2C1_MASK 0x0001c000
+#define CCSR_GUTS_PMUXCR_UART0_I2C1_UART0_SSI 0x00010000
+#define CCSR_GUTS_PMUXCR_UART0_I2C1_SSI 0x00018000
+
+#define CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK 0x00000c00
+#define CCSR_GUTS_PMUXCR_SSI_DMA_TDM_SSI 0x00000000
+
+#define CCSR_GUTS_DMUXCR_PAD 1 /* DMA controller/channel set to pad */
+#define CCSR_GUTS_DMUXCR_SSI 2 /* DMA controller/channel set to SSI */
+
+/*
+ * Set the DMACR register in the GUTS
+ *
+ * The DMACR register determines the source of initiated transfers for each
+ * channel on each DMA controller. Rather than have a bunch of repetitive
+ * macros for the bit patterns, we just have a function that calculates
+ * them.
+ *
+ * guts: Pointer to GUTS structure
+ * co: The DMA controller (0 or 1)
+ * ch: The channel on the DMA controller (0, 1, 2, or 3)
+ * device: The device to set as the target (CCSR_GUTS_DMUXCR_xxx)
+ */
+static inline void guts_set_dmuxcr(struct ccsr_guts_85xx __iomem *guts,
+ unsigned int co, unsigned int ch, unsigned int device)
+{
+ unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
+
+ clrsetbits_be32(&guts->dmuxcr, 3 << shift, device << shift);
+}
+
+/* There's only one global utilities register */
+static phys_addr_t guts_phys;
+
+#define DAI_NAME_SIZE 32
+
+/**
+ * machine_data: machine-specific ASoC device data
+ *
+ * This structure contains data for a single sound platform device on an
+ * P1022 DS. Some of the data is taken from the device tree.
+ */
+struct machine_data {
+ struct snd_soc_dai_link dai[2];
+ struct snd_soc_card card;
+ unsigned int dai_format;
+ unsigned int codec_clk_direction;
+ unsigned int cpu_clk_direction;
+ unsigned int clk_frequency;
+ unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */
+ unsigned int dma_id[2]; /* 0 = DMA1, 1 = DMA2, etc */
+ unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
+ char codec_name[DAI_NAME_SIZE];
+ char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
+};
+
+/**
+ * p1022_ds_machine_probe: initialize the board
+ *
+ * This function is used to initialize the board-specific hardware.
+ *
+ * Here we program the DMACR and PMUXCR registers.
+ */
+static int p1022_ds_machine_probe(struct platform_device *sound_device)
+{
+ struct snd_soc_card *card = platform_get_drvdata(sound_device);
+ struct machine_data *mdata =
+ container_of(card, struct machine_data, card);
+ struct ccsr_guts_85xx __iomem *guts;
+
+ guts = ioremap(guts_phys, sizeof(struct ccsr_guts_85xx));
+ if (!guts) {
+ dev_err(card->dev, "could not map global utilities\n");
+ return -ENOMEM;
+ }
+
+ /* Enable SSI Tx signal */
+ clrsetbits_be32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_UART0_I2C1_MASK,
+ CCSR_GUTS_PMUXCR_UART0_I2C1_UART0_SSI);
+
+ /* Enable SSI Rx signal */
+ clrsetbits_be32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK,
+ CCSR_GUTS_PMUXCR_SSI_DMA_TDM_SSI);
+
+ /* Enable DMA Channel for SSI */
+ guts_set_dmuxcr(guts, mdata->dma_id[0], mdata->dma_channel_id[0],
+ CCSR_GUTS_DMUXCR_SSI);
+
+ guts_set_dmuxcr(guts, mdata->dma_id[1], mdata->dma_channel_id[1],
+ CCSR_GUTS_DMUXCR_SSI);
+
+ iounmap(guts);
+
+ return 0;
+}
+
+/**
+ * p1022_ds_startup: program the board with various hardware parameters
+ *
+ * This function takes board-specific information, like clock frequencies
+ * and serial data formats, and passes that information to the codec and
+ * transport drivers.
+ */
+static int p1022_ds_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct machine_data *mdata =
+ container_of(rtd->card, struct machine_data, card);
+ struct device *dev = rtd->card->dev;
+ int ret = 0;
+
+ /* Tell the codec driver what the serial protocol is. */
+ ret = snd_soc_dai_set_fmt(rtd->codec_dai, mdata->dai_format);
+ if (ret < 0) {
+ dev_err(dev, "could not set codec driver audio format\n");
+ return ret;
+ }
+
+ /*
+ * Tell the codec driver what the MCLK frequency is, and whether it's
+ * a slave or master.
+ */
+ ret = snd_soc_dai_set_sysclk(rtd->codec_dai, 0, mdata->clk_frequency,
+ mdata->codec_clk_direction);
+ if (ret < 0) {
+ dev_err(dev, "could not set codec driver clock params\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * p1022_ds_machine_remove: Remove the sound device
+ *
+ * This function is called to remove the sound device for one SSI. We
+ * de-program the DMACR and PMUXCR register.
+ */
+static int p1022_ds_machine_remove(struct platform_device *sound_device)
+{
+ struct snd_soc_card *card = platform_get_drvdata(sound_device);
+ struct machine_data *mdata =
+ container_of(card, struct machine_data, card);
+ struct ccsr_guts_85xx __iomem *guts;
+
+ guts = ioremap(guts_phys, sizeof(struct ccsr_guts_85xx));
+ if (!guts) {
+ dev_err(card->dev, "could not map global utilities\n");
+ return -ENOMEM;
+ }
+
+ /* Restore the signal routing */
+ clrbits32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_UART0_I2C1_MASK);
+ clrbits32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK);
+ guts_set_dmuxcr(guts, mdata->dma_id[0], mdata->dma_channel_id[0], 0);
+ guts_set_dmuxcr(guts, mdata->dma_id[1], mdata->dma_channel_id[1], 0);
+
+ iounmap(guts);
+
+ return 0;
+}
+
+/**
+ * p1022_ds_ops: ASoC machine driver operations
+ */
+static struct snd_soc_ops p1022_ds_ops = {
+ .startup = p1022_ds_startup,
+};
+
+/**
+ * get_node_by_phandle_name - get a node by its phandle name
+ *
+ * This function takes a node, the name of a property in that node, and a
+ * compatible string. Assuming the property is a phandle to another node,
+ * it returns that node, (optionally) if that node is compatible.
+ *
+ * If the property is not a phandle, or the node it points to is not compatible
+ * with the specific string, then NULL is returned.
+ */
+static struct device_node *get_node_by_phandle_name(struct device_node *np,
+ const char *name, const char *compatible)
+{
+ np = of_parse_phandle(np, name, 0);
+ if (!np)
+ return NULL;
+
+ if (!of_device_is_compatible(np, compatible)) {
+ of_node_put(np);
+ return NULL;
+ }
+
+ return np;
+}
+
+/**
+ * get_parent_cell_index -- return the cell-index of the parent of a node
+ *
+ * Return the value of the cell-index property of the parent of the given
+ * node. This is used for DMA channel nodes that need to know the DMA ID
+ * of the controller they are on.
+ */
+static int get_parent_cell_index(struct device_node *np)
+{
+ struct device_node *parent = of_get_parent(np);
+ const u32 *iprop;
+ int ret = -1;
+
+ if (!parent)
+ return -1;
+
+ iprop = of_get_property(parent, "cell-index", NULL);
+ if (iprop)
+ ret = *iprop;
+
+ of_node_put(parent);
+
+ return ret;
+}
+
+/**
+ * codec_node_dev_name - determine the dev_name for a codec node
+ *
+ * This function determines the dev_name for an I2C node. This is the name
+ * that would be returned by dev_name() if this device_node were part of a
+ * 'struct device' It's ugly and hackish, but it works.
+ *
+ * The dev_name for such devices include the bus number and I2C address. For
+ * example, "cs4270-codec.0-004f".
+ */
+static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
+{
+ const u32 *iprop;
+ int bus, addr;
+ char temp[DAI_NAME_SIZE];
+
+ of_modalias_node(np, temp, DAI_NAME_SIZE);
+
+ iprop = of_get_property(np, "reg", NULL);
+ if (!iprop)
+ return -EINVAL;
+
+ addr = *iprop;
+
+ bus = get_parent_cell_index(np);
+ if (bus < 0)
+ return bus;
+
+ snprintf(buf, len, "%s-codec.%u-%04x", temp, bus, addr);
+
+ return 0;
+}
+
+static int get_dma_channel(struct device_node *ssi_np,
+ const char *compatible,
+ struct snd_soc_dai_link *dai,
+ unsigned int *dma_channel_id,
+ unsigned int *dma_id)
+{
+ struct resource res;
+ struct device_node *dma_channel_np;
+ const u32 *iprop;
+ int ret;
+
+ dma_channel_np = get_node_by_phandle_name(ssi_np, compatible,
+ "fsl,ssi-dma-channel");
+ if (!dma_channel_np)
+ return -EINVAL;
+
+ /* Determine the dev_name for the device_node. This code mimics the
+ * behavior of of_device_make_bus_id(). We need this because ASoC uses
+ * the dev_name() of the device to match the platform (DMA) device with
+ * the CPU (SSI) device. It's all ugly and hackish, but it works (for
+ * now).
+ *
+ * dai->platform name should already point to an allocated buffer.
+ */
+ ret = of_address_to_resource(dma_channel_np, 0, &res);
+ if (ret)
+ return ret;
+ snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
+ (unsigned long long) res.start, dma_channel_np->name);
+
+ iprop = of_get_property(dma_channel_np, "cell-index", NULL);
+ if (!iprop) {
+ of_node_put(dma_channel_np);
+ return -EINVAL;
+ }
+
+ *dma_channel_id = *iprop;
+ *dma_id = get_parent_cell_index(dma_channel_np);
+ of_node_put(dma_channel_np);
+
+ return 0;
+}
+
+/**
+ * p1022_ds_probe: platform probe function for the machine driver
+ *
+ * Although this is a machine driver, the SSI node is the "master" node with
+ * respect to audio hardware connections. Therefore, we create a new ASoC
+ * device for each new SSI node that has a codec attached.
+ */
+static int p1022_ds_probe(struct platform_device *pdev)
+{
+ struct device *dev = pdev->dev.parent;
+ /* ssi_pdev is the platform device for the SSI node that probed us */
+ struct platform_device *ssi_pdev =
+ container_of(dev, struct platform_device, dev);
+ struct device_node *np = ssi_pdev->dev.of_node;
+ struct device_node *codec_np = NULL;
+ struct platform_device *sound_device = NULL;
+ struct machine_data *mdata;
+ int ret = -ENODEV;
+ const char *sprop;
+ const u32 *iprop;
+
+ /* Find the codec node for this SSI. */
+ codec_np = of_parse_phandle(np, "codec-handle", 0);
+ if (!codec_np) {
+ dev_err(dev, "could not find codec node\n");
+ return -EINVAL;
+ }
+
+ mdata = kzalloc(sizeof(struct machine_data), GFP_KERNEL);
+ if (!mdata) {
+ ret = -ENOMEM;
+ goto error_put;
+ }
+
+ mdata->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
+ mdata->dai[0].ops = &p1022_ds_ops;
+
+ /* Determine the codec name, it will be used as the codec DAI name */
+ ret = codec_node_dev_name(codec_np, mdata->codec_name, DAI_NAME_SIZE);
+ if (ret) {
+ dev_err(&pdev->dev, "invalid codec node %s\n",
+ codec_np->full_name);
+ ret = -EINVAL;
+ goto error;
+ }
+ mdata->dai[0].codec_name = mdata->codec_name;
+
+ /* We register two DAIs per SSI, one for playback and the other for
+ * capture. We support codecs that have separate DAIs for both playback
+ * and capture.
+ */
+ memcpy(&mdata->dai[1], &mdata->dai[0], sizeof(struct snd_soc_dai_link));
+
+ /* The DAI names from the codec (snd_soc_dai_driver.name) */
+ mdata->dai[0].codec_dai_name = "wm8776-hifi-playback";
+ mdata->dai[1].codec_dai_name = "wm8776-hifi-capture";
+
+ /* Get the device ID */
+ iprop = of_get_property(np, "cell-index", NULL);
+ if (!iprop) {
+ dev_err(&pdev->dev, "cell-index property not found\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ mdata->ssi_id = *iprop;
+
+ /* Get the serial format and clock direction. */
+ sprop = of_get_property(np, "fsl,mode", NULL);
+ if (!sprop) {
+ dev_err(&pdev->dev, "fsl,mode property not found\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (strcasecmp(sprop, "i2s-slave") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_I2S;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+
+ /* In i2s-slave mode, the codec has its own clock source, so we
+ * need to get the frequency from the device tree and pass it to
+ * the codec driver.
+ */
+ iprop = of_get_property(codec_np, "clock-frequency", NULL);
+ if (!iprop || !*iprop) {
+ dev_err(&pdev->dev, "codec bus-frequency "
+ "property is missing or invalid\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ mdata->clk_frequency = *iprop;
+ } else if (strcasecmp(sprop, "i2s-master") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_I2S;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+ } else if (strcasecmp(sprop, "lj-slave") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_LEFT_J;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+ } else if (strcasecmp(sprop, "lj-master") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_LEFT_J;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+ } else if (strcasecmp(sprop, "rj-slave") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+ } else if (strcasecmp(sprop, "rj-master") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+ } else if (strcasecmp(sprop, "ac97-slave") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_AC97;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+ } else if (strcasecmp(sprop, "ac97-master") == 0) {
+ mdata->dai_format = SND_SOC_DAIFMT_AC97;
+ mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+ mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+ } else {
+ dev_err(&pdev->dev,
+ "unrecognized fsl,mode property '%s'\n", sprop);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!mdata->clk_frequency) {
+ dev_err(&pdev->dev, "unknown clock frequency\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Find the playback DMA channel to use. */
+ mdata->dai[0].platform_name = mdata->platform_name[0];
+ ret = get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0],
+ &mdata->dma_channel_id[0],
+ &mdata->dma_id[0]);
+ if (ret) {
+ dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
+ goto error;
+ }
+
+ /* Find the capture DMA channel to use. */
+ mdata->dai[1].platform_name = mdata->platform_name[1];
+ ret = get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1],
+ &mdata->dma_channel_id[1],
+ &mdata->dma_id[1]);
+ if (ret) {
+ dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
+ goto error;
+ }
+
+ /* Initialize our DAI data structure. */
+ mdata->dai[0].stream_name = "playback";
+ mdata->dai[1].stream_name = "capture";
+ mdata->dai[0].name = mdata->dai[0].stream_name;
+ mdata->dai[1].name = mdata->dai[1].stream_name;
+
+ mdata->card.probe = p1022_ds_machine_probe;
+ mdata->card.remove = p1022_ds_machine_remove;
+ mdata->card.name = pdev->name; /* The platform driver name */
+ mdata->card.num_links = 2;
+ mdata->card.dai_link = mdata->dai;
+
+ /* Allocate a new audio platform device structure */
+ sound_device = platform_device_alloc("soc-audio", -1);
+ if (!sound_device) {
+ dev_err(&pdev->dev, "platform device alloc failed\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /* Associate the card data with the sound device */
+ platform_set_drvdata(sound_device, &mdata->card);
+
+ /* Register with ASoC */
+ ret = platform_device_add(sound_device);
+ if (ret) {
+ dev_err(&pdev->dev, "platform device add failed\n");
+ goto error;
+ }
+
+ of_node_put(codec_np);
+
+ return 0;
+
+error:
+ if (sound_device)
+ platform_device_unregister(sound_device);
+
+ kfree(mdata);
+error_put:
+ of_node_put(codec_np);
+ return ret;
+}
+
+/**
+ * p1022_ds_remove: remove the platform device
+ *
+ * This function is called when the platform device is removed.
+ */
+static int __devexit p1022_ds_remove(struct platform_device *pdev)
+{
+ struct platform_device *sound_device = dev_get_drvdata(&pdev->dev);
+ struct snd_soc_card *card = platform_get_drvdata(sound_device);
+ struct machine_data *mdata =
+ container_of(card, struct machine_data, card);
+
+ platform_device_unregister(sound_device);
+
+ kfree(mdata);
+ sound_device->dev.platform_data = NULL;
+
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver p1022_ds_driver = {
+ .probe = p1022_ds_probe,
+ .remove = __devexit_p(p1022_ds_remove),
+ .driver = {
+ /* The name must match the 'model' property in the device tree,
+ * in lowercase letters, but only the part after that last
+ * comma. This is because some model properties have a "fsl,"
+ * prefix.
+ */
+ .name = "snd-soc-p1022",
+ .owner = THIS_MODULE,
+ },
+};
+
+/**
+ * p1022_ds_init: machine driver initialization.
+ *
+ * This function is called when this module is loaded.
+ */
+static int __init p1022_ds_init(void)
+{
+ struct device_node *guts_np;
+ struct resource res;
+
+ pr_info("Freescale P1022 DS ALSA SoC machine driver\n");
+
+ /* Get the physical address of the global utilities registers */
+ guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+ if (of_address_to_resource(guts_np, 0, &res)) {
+ pr_err("p1022-ds: missing/invalid global utilities node\n");
+ return -EINVAL;
+ }
+ guts_phys = res.start;
+ of_node_put(guts_np);
+
+ return platform_driver_register(&p1022_ds_driver);
+}
+
+/**
+ * p1022_ds_exit: machine driver exit
+ *
+ * This function is called when this driver is unloaded.
+ */
+static void __exit p1022_ds_exit(void)
+{
+ platform_driver_unregister(&p1022_ds_driver);
+}
+
+module_init(p1022_ds_init);
+module_exit(p1022_ds_exit);
+
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_DESCRIPTION("Freescale P1022 DS ALSA SoC machine driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c
index 6644cba7cbf2..25f27ec1dd6e 100644
--- a/sound/soc/fsl/pcm030-audio-fabric.c
+++ b/sound/soc/fsl/pcm030-audio-fabric.c
@@ -24,7 +24,6 @@
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
-#include <sound/soc-of-simple.h>
#include "mpc5200_dma.h"
#include "mpc5200_psc_ac97.h"
@@ -32,21 +31,24 @@
#define DRV_NAME "pcm030-audio-fabric"
-static struct snd_soc_device device;
static struct snd_soc_card card;
static struct snd_soc_dai_link pcm030_fabric_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 Analog",
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
- .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+ .codec_dai_name = "wm9712-hifi",
+ .cpu_dai_name = "mpc5200-psc-ac97.0",
+ .platform_name = "mpc5200-pcm-audio",
+ .codec_name = "wm9712-codec",
},
{
.name = "AC97",
.stream_name = "AC97 IEC958",
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
- .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+ .codec_dai_name = "wm9712-aux",
+ .cpu_dai_name = "mpc5200-psc-ac97.1",
+ .platform_name = "mpc5200-pcm-audio",
+ .codec_name = "wm9712-codec",
},
};
@@ -58,22 +60,18 @@ static __init int pcm030_fabric_init(void)
if (!of_machine_is_compatible("phytec,pcm030"))
return -ENODEV;
- card.platform = &mpc5200_audio_dma_platform;
+
card.name = "pcm030";
card.dai_link = pcm030_fabric_dai;
card.num_links = ARRAY_SIZE(pcm030_fabric_dai);
- device.card = &card;
- device.codec_dev = &soc_codec_dev_wm9712;
-
pdev = platform_device_alloc("soc-audio", 1);
if (!pdev) {
pr_err("pcm030_fabric_init: platform_device_alloc() failed\n");
return -ENODEV;
}
- platform_set_drvdata(pdev, &device);
- device.dev = &pdev->dev;
+ platform_set_drvdata(pdev, &card);
rc = platform_device_add(pdev);
if (rc) {
diff --git a/sound/soc/fsl/soc-of-simple.c b/sound/soc/fsl/soc-of-simple.c
deleted file mode 100644
index 3bc13fd89096..000000000000
--- a/sound/soc/fsl/soc-of-simple.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * OF helpers for ALSA SoC Layer
- *
- * Copyright (C) 2008, Secret Lab Technologies Ltd.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/bitops.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-of-simple.h>
-#include <sound/initval.h>
-
-MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("ALSA SoC OpenFirmware bindings");
-
-static DEFINE_MUTEX(of_snd_soc_mutex);
-static LIST_HEAD(of_snd_soc_device_list);
-static int of_snd_soc_next_index;
-
-struct of_snd_soc_device {
- int id;
- struct list_head list;
- struct snd_soc_device device;
- struct snd_soc_card card;
- struct snd_soc_dai_link dai_link;
- struct platform_device *pdev;
- struct device_node *platform_node;
- struct device_node *codec_node;
-};
-
-static struct snd_soc_ops of_snd_soc_ops = {
-};
-
-static struct of_snd_soc_device *
-of_snd_soc_get_device(struct device_node *codec_node)
-{
- struct of_snd_soc_device *of_soc;
-
- list_for_each_entry(of_soc, &of_snd_soc_device_list, list) {
- if (of_soc->codec_node == codec_node)
- return of_soc;
- }
-
- of_soc = kzalloc(sizeof(struct of_snd_soc_device), GFP_KERNEL);
- if (!of_soc)
- return NULL;
-
- /* Initialize the structure and add it to the global list */
- of_soc->codec_node = codec_node;
- of_soc->id = of_snd_soc_next_index++;
- of_soc->card.dai_link = &of_soc->dai_link;
- of_soc->card.num_links = 1;
- of_soc->device.card = &of_soc->card;
- of_soc->dai_link.ops = &of_snd_soc_ops;
- list_add(&of_soc->list, &of_snd_soc_device_list);
-
- return of_soc;
-}
-
-static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc)
-{
- struct platform_device *pdev;
- int rc;
-
- /* Only register the device if both the codec and platform have
- * been registered */
- if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
- return;
-
- pr_info("platform<-->codec match achieved; registering machine\n");
-
- pdev = platform_device_alloc("soc-audio", of_soc->id);
- if (!pdev) {
- pr_err("of_soc: platform_device_alloc() failed\n");
- return;
- }
-
- pdev->dev.platform_data = of_soc;
- platform_set_drvdata(pdev, &of_soc->device);
- of_soc->device.dev = &pdev->dev;
-
- /* The ASoC device is complete; register it */
- rc = platform_device_add(pdev);
- if (rc) {
- pr_err("of_soc: platform_device_add() failed\n");
- return;
- }
-
-}
-
-int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
- void *codec_data, struct snd_soc_dai *dai,
- struct device_node *node)
-{
- struct of_snd_soc_device *of_soc;
- int rc = 0;
-
- pr_info("registering ASoC codec driver: %s\n", node->full_name);
-
- mutex_lock(&of_snd_soc_mutex);
- of_soc = of_snd_soc_get_device(node);
- if (!of_soc) {
- rc = -ENOMEM;
- goto out;
- }
-
- /* Store the codec data */
- of_soc->device.codec_data = codec_data;
- of_soc->device.codec_dev = codec_dev;
- of_soc->dai_link.name = (char *)node->name;
- of_soc->dai_link.stream_name = (char *)node->name;
- of_soc->dai_link.codec_dai = dai;
-
- /* Now try to register the SoC device */
- of_snd_soc_register_device(of_soc);
-
- out:
- mutex_unlock(&of_snd_soc_mutex);
- return rc;
-}
-EXPORT_SYMBOL_GPL(of_snd_soc_register_codec);
-
-int of_snd_soc_register_platform(struct snd_soc_platform *platform,
- struct device_node *node,
- struct snd_soc_dai *cpu_dai)
-{
- struct of_snd_soc_device *of_soc;
- struct device_node *codec_node;
- const phandle *handle;
- int len, rc = 0;
-
- pr_info("registering ASoC platform driver: %s\n", node->full_name);
-
- handle = of_get_property(node, "codec-handle", &len);
- if (!handle || len < sizeof(handle))
- return -ENODEV;
- codec_node = of_find_node_by_phandle(*handle);
- if (!codec_node)
- return -ENODEV;
- pr_info("looking for codec: %s\n", codec_node->full_name);
-
- mutex_lock(&of_snd_soc_mutex);
- of_soc = of_snd_soc_get_device(codec_node);
- if (!of_soc) {
- rc = -ENOMEM;
- goto out;
- }
-
- of_soc->platform_node = node;
- of_soc->dai_link.cpu_dai = cpu_dai;
- of_soc->card.platform = platform;
- of_soc->card.name = of_soc->dai_link.cpu_dai->name;
-
- /* Now try to register the SoC device */
- of_snd_soc_register_device(of_soc);
-
- out:
- mutex_unlock(&of_snd_soc_mutex);
- return rc;
-}
-EXPORT_SYMBOL_GPL(of_snd_soc_register_platform);
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index 687c76fc0839..642270a635ea 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -8,12 +8,24 @@ menuconfig SND_IMX_SOC
Say Y or M if you want to add support for codecs attached to
the i.MX SSI interface.
+
if SND_IMX_SOC
+config SND_MXC_SOC_SSI
+ tristate
+
+config SND_MXC_SOC_FIQ
+ tristate
+
+config SND_MXC_SOC_MX2
+ tristate
+
config SND_MXC_SOC_WM1133_EV1
tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted"
depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
select SND_SOC_WM8350
+ select SND_MXC_SOC_SSI
+ select SND_MXC_SOC_FIQ
help
Enable support for audio on the i.MX31ADS with the WM1133-EV1
PMIC board with WM8835x fitted.
@@ -22,6 +34,8 @@ config SND_SOC_PHYCORE_AC97
tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
depends on MACH_PCM043 || MACH_PCA100
select SND_SOC_WM9712
+ select SND_MXC_SOC_SSI
+ select SND_MXC_SOC_FIQ
help
Say Y if you want to add support for SoC audio on Phytec phyCORE
and phyCARD boards in AC97 mode
@@ -32,6 +46,8 @@ config SND_SOC_EUKREA_TLV320
|| MACH_EUKREA_MBIMXSD25_BASEBOARD \
|| MACH_EUKREA_MBIMXSD35_BASEBOARD
select SND_SOC_TLV320AIC23
+ select SND_MXC_SOC_SSI
+ select SND_MXC_SOC_FIQ
help
Enable I2S based access to the TLV320AIC23B codec attached
to the SSI interface
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
index 7bc57baf2b0e..b67fc02a4ecc 100644
--- a/sound/soc/imx/Makefile
+++ b/sound/soc/imx/Makefile
@@ -1,11 +1,11 @@
# i.MX Platform Support
-snd-soc-imx-objs := imx-ssi.o imx-pcm-fiq.o
-
-ifdef CONFIG_MACH_MX27
-snd-soc-imx-objs += imx-pcm-dma-mx2.o
-endif
+snd-soc-imx-objs := imx-ssi.o
+snd-soc-imx-fiq-objs := imx-pcm-fiq.o
+snd-soc-imx-mx2-objs := imx-pcm-dma-mx2.o
obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o
+obj-$(CONFIG_SND_MXC_SOC_FIQ) += snd-soc-imx-fiq.o
+obj-$(CONFIG_SND_MXC_SOC_MX2) += snd-soc-imx-mx2.o
# i.MX Machine Support
snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/imx/eukrea-tlv320.c
index f15dfbdc47ee..b59675257ce5 100644
--- a/sound/soc/imx/eukrea-tlv320.c
+++ b/sound/soc/imx/eukrea-tlv320.c
@@ -79,22 +79,19 @@ static struct snd_soc_ops eukrea_tlv320_snd_ops = {
static struct snd_soc_dai_link eukrea_tlv320_dai = {
.name = "tlv320aic23",
.stream_name = "TLV320AIC23",
- .codec_dai = &tlv320aic23_dai,
+ .codec_dai = "tlv320aic23-hifi",
+ .platform_name = "imx-pcm-audio.0",
+ .codec_name = "tlv320aic23-codec.0-001a",
+ .cpu_dai = "imx-ssi.0",
.ops = &eukrea_tlv320_snd_ops,
};
static struct snd_soc_card eukrea_tlv320 = {
.name = "cpuimx-audio",
- .platform = &imx_soc_platform,
.dai_link = &eukrea_tlv320_dai,
.num_links = 1,
};
-static struct snd_soc_device eukrea_tlv320_snd_devdata = {
- .card = &eukrea_tlv320,
- .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
static struct platform_device *eukrea_tlv320_snd_device;
static int __init eukrea_tlv320_init(void)
@@ -110,10 +107,7 @@ static int __init eukrea_tlv320_init(void)
if (!eukrea_tlv320_snd_device)
return -ENOMEM;
- eukrea_tlv320_dai.cpu_dai = &imx_ssi_pcm_dai[0];
-
- platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320_snd_devdata);
- eukrea_tlv320_snd_devdata.dev = &eukrea_tlv320_snd_device->dev;
+ platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320);
ret = platform_device_add(eukrea_tlv320_snd_device);
if (ret) {
diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c
index 0a595da4811d..fd493ee1428e 100644
--- a/sound/soc/imx/imx-pcm-dma-mx2.c
+++ b/sound/soc/imx/imx-pcm-dma-mx2.c
@@ -103,7 +103,7 @@ static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream)
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
int ret;
- dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH);
if (iprtd->dma < 0) {
@@ -213,7 +213,7 @@ static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
int err;
- dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
iprtd->substream = substream;
iprtd->buf = (unsigned int *)substream->dma_buffer.area;
@@ -318,19 +318,42 @@ static struct snd_pcm_ops imx_pcm_ops = {
.mmap = snd_imx_pcm_mmap,
};
-static struct snd_soc_platform imx_soc_platform_dma = {
- .name = "imx-audio",
- .pcm_ops = &imx_pcm_ops,
+static struct snd_soc_platform_driver imx_soc_platform_mx2 = {
+ .ops = &imx_pcm_ops,
.pcm_new = imx_pcm_new,
.pcm_free = imx_pcm_free,
};
-struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev,
- struct imx_ssi *ssi)
+static int __devinit imx_soc_platform_probe(struct platform_device *pdev)
{
- ssi->dma_params_tx.burstsize = DMA_TXFIFO_BURST;
- ssi->dma_params_rx.burstsize = DMA_RXFIFO_BURST;
+ return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2);
+}
+
+static int __devexit imx_soc_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver imx_pcm_driver = {
+ .driver = {
+ .name = "imx-pcm-audio",
+ .owner = THIS_MODULE,
+ },
- return &imx_soc_platform_dma;
+ .probe = imx_soc_platform_probe,
+ .remove = __devexit_p(imx_soc_platform_remove),
+};
+
+static int __init snd_imx_pcm_init(void)
+{
+ return platform_driver_register(&imx_pcm_driver);
+}
+module_init(snd_imx_pcm_init);
+
+static void __exit snd_imx_pcm_exit(void)
+{
+ platform_driver_unregister(&imx_pcm_driver);
}
+module_exit(snd_imx_pcm_exit);
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c
index b2bf27282cd2..413b78da248f 100644
--- a/sound/soc/imx/imx-pcm-fiq.c
+++ b/sound/soc/imx/imx-pcm-fiq.c
@@ -236,6 +236,8 @@ static struct snd_pcm_ops imx_pcm_ops = {
.mmap = snd_imx_pcm_mmap,
};
+static int ssi_irq = 0;
+
static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
struct snd_pcm *pcm)
{
@@ -245,7 +247,7 @@ static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
if (ret)
return ret;
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
struct snd_pcm_substream *substream =
pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
@@ -253,7 +255,7 @@ static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
imx_ssi_fiq_tx_buffer = (unsigned long)buf->area;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
struct snd_pcm_substream *substream =
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
@@ -267,24 +269,32 @@ static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
return 0;
}
-static struct snd_soc_platform imx_soc_platform_fiq = {
- .pcm_ops = &imx_pcm_ops,
+static void imx_pcm_fiq_free(struct snd_pcm *pcm)
+{
+ mxc_set_irq_fiq(ssi_irq, 0);
+ release_fiq(&fh);
+ imx_pcm_free(pcm);
+}
+
+static struct snd_soc_platform_driver imx_soc_platform_fiq = {
+ .ops = &imx_pcm_ops,
.pcm_new = imx_pcm_fiq_new,
- .pcm_free = imx_pcm_free,
+ .pcm_free = imx_pcm_fiq_free,
};
-struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
- struct imx_ssi *ssi)
+static int __devinit imx_soc_platform_probe(struct platform_device *pdev)
{
- int ret = 0;
+ struct imx_ssi *ssi = platform_get_drvdata(pdev);
+ int ret;
ret = claim_fiq(&fh);
if (ret) {
dev_err(&pdev->dev, "failed to claim fiq: %d", ret);
- return ERR_PTR(ret);
+ return ret;
}
mxc_set_irq_fiq(ssi->irq, 1);
+ ssi_irq = ssi->irq;
imx_pcm_fiq = ssi->irq;
@@ -293,13 +303,43 @@ struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
ssi->dma_params_tx.burstsize = 4;
ssi->dma_params_rx.burstsize = 6;
- return &imx_soc_platform_fiq;
+ ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq);
+ if (ret)
+ goto failed_register;
+
+ return 0;
+
+failed_register:
+ mxc_set_irq_fiq(ssi_irq, 0);
+ release_fiq(&fh);
+
+ return ret;
}
-void imx_ssi_fiq_exit(struct platform_device *pdev,
- struct imx_ssi *ssi)
+static int __devexit imx_soc_platform_remove(struct platform_device *pdev)
{
- mxc_set_irq_fiq(ssi->irq, 0);
- release_fiq(&fh);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
+static struct platform_driver imx_pcm_driver = {
+ .driver = {
+ .name = "imx-fiq-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = imx_soc_platform_probe,
+ .remove = __devexit_p(imx_soc_platform_remove),
+};
+
+static int __init snd_imx_pcm_init(void)
+{
+ return platform_driver_register(&imx_pcm_driver);
+}
+module_init(snd_imx_pcm_init);
+
+static void __exit snd_imx_pcm_exit(void)
+{
+ platform_driver_unregister(&imx_pcm_driver);
+}
+module_exit(snd_imx_pcm_exit);
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index c81da05a4f11..d4bd345b0a8d 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -61,7 +61,7 @@
static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
{
- struct imx_ssi *ssi = cpu_dai->private_data;
+ struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
u32 sccr;
sccr = readl(ssi->base + SSI_STCCR);
@@ -86,7 +86,7 @@ static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
*/
static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
- struct imx_ssi *ssi = cpu_dai->private_data;
+ struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
u32 strcr = 0, scr;
scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
@@ -164,7 +164,7 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
- struct imx_ssi *ssi = cpu_dai->private_data;
+ struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
u32 scr;
scr = readl(ssi->base + SSI_SCR);
@@ -192,7 +192,7 @@ static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div)
{
- struct imx_ssi *ssi = cpu_dai->private_data;
+ struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
u32 stccr, srccr;
stccr = readl(ssi->base + SSI_STCCR);
@@ -241,7 +241,7 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct imx_ssi *ssi = cpu_dai->private_data;
+ struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
struct imx_pcm_dma_params *dma_data;
u32 reg, sccr;
@@ -282,9 +282,7 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct imx_ssi *ssi = cpu_dai->private_data;
+ struct imx_ssi *ssi = snd_soc_dai_get_drvdata(dai);
unsigned int sier_bits, sier;
unsigned int scr;
@@ -353,22 +351,6 @@ static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
.trigger = imx_ssi_trigger,
};
-static struct snd_soc_dai imx_ssi_dai = {
- .playback = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_96000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .capture = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_96000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .ops = &imx_ssi_pcm_dai_ops,
-};
-
int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
@@ -384,6 +366,7 @@ int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
runtime->dma_bytes);
return ret;
}
+EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap);
static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
{
@@ -415,14 +398,14 @@ int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
card->dev->dma_mask = &imx_pcm_dmamask;
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = imx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = imx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -432,6 +415,7 @@ int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
out:
return ret;
}
+EXPORT_SYMBOL_GPL(imx_pcm_new);
void imx_pcm_free(struct snd_pcm *pcm)
{
@@ -453,14 +437,40 @@ void imx_pcm_free(struct snd_pcm *pcm)
buf->area = NULL;
}
}
+EXPORT_SYMBOL_GPL(imx_pcm_free);
-struct snd_soc_platform imx_soc_platform = {
- .name = "imx-audio",
+static struct snd_soc_dai_driver imx_ssi_dai = {
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &imx_ssi_pcm_dai_ops,
};
-EXPORT_SYMBOL_GPL(imx_soc_platform);
-static struct snd_soc_dai imx_ac97_dai = {
- .name = "AC97",
+static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
+{
+ struct imx_ssi *ssi = dev_get_drvdata(dai->dev);
+ uint32_t val;
+
+ snd_soc_dai_set_drvdata(dai, ssi);
+
+ val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
+ SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
+ writel(val, ssi->base + SSI_SFCSR);
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver imx_ac97_dai = {
+ .probe = imx_ssi_dai_probe,
.ac97_control = 1,
.playback = {
.stream_name = "AC97 Playback",
@@ -580,25 +590,18 @@ struct snd_ac97_bus_ops soc_ac97_ops = {
};
EXPORT_SYMBOL_GPL(soc_ac97_ops);
-struct snd_soc_dai imx_ssi_pcm_dai[2];
-EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai);
-
static int imx_ssi_probe(struct platform_device *pdev)
{
struct resource *res;
struct imx_ssi *ssi;
struct imx_ssi_platform_data *pdata = pdev->dev.platform_data;
- struct snd_soc_platform *platform;
int ret = 0;
- unsigned int val;
- struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id];
-
- if (dai->id >= ARRAY_SIZE(imx_ssi_pcm_dai))
- return -EINVAL;
+ struct snd_soc_dai_driver *dai;
ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
if (!ssi)
return -ENOMEM;
+ dev_set_drvdata(&pdev->dev, ssi);
if (pdata) {
ssi->ac97_reset = pdata->ac97_reset;
@@ -643,9 +646,9 @@ static int imx_ssi_probe(struct platform_device *pdev)
}
ac97_ssi = ssi;
setup_channel_to_ac97(ssi);
- memcpy(dai, &imx_ac97_dai, sizeof(imx_ac97_dai));
+ dai = &imx_ac97_dai;
} else
- memcpy(dai, &imx_ssi_dai, sizeof(imx_ssi_dai));
+ dai = &imx_ssi_dai;
writel(0x0, ssi->base + SSI_SIER);
@@ -660,37 +663,36 @@ static int imx_ssi_probe(struct platform_device *pdev)
if (res)
ssi->dma_params_rx.dma = res->start;
- dai->id = pdev->id;
- dai->dev = &pdev->dev;
- dai->name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id);
- dai->private_data = ssi;
-
if ((cpu_is_mx27() || cpu_is_mx21()) &&
!(ssi->flags & IMX_SSI_USE_AC97) &&
(ssi->flags & IMX_SSI_DMA)) {
ssi->flags |= IMX_SSI_DMA;
- platform = imx_ssi_dma_mx2_init(pdev, ssi);
- } else
- platform = imx_ssi_fiq_init(pdev, ssi);
-
- imx_soc_platform.pcm_ops = platform->pcm_ops;
- imx_soc_platform.pcm_new = platform->pcm_new;
- imx_soc_platform.pcm_free = platform->pcm_free;
+ }
- val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
- SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
- writel(val, ssi->base + SSI_SFCSR);
+ platform_set_drvdata(pdev, ssi);
- ret = snd_soc_register_dai(dai);
+ ret = snd_soc_register_dai(&pdev->dev, dai);
if (ret) {
dev_err(&pdev->dev, "register DAI failed\n");
goto failed_register;
}
- platform_set_drvdata(pdev, ssi);
+ ssi->soc_platform_pdev = platform_device_alloc("imx-fiq-pcm-audio", pdev->id);
+ if (!ssi->soc_platform_pdev)
+ goto failed_pdev_alloc;
+ platform_set_drvdata(ssi->soc_platform_pdev, ssi);
+ ret = platform_device_add(ssi->soc_platform_pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add platform device\n");
+ goto failed_pdev_add;
+ }
return 0;
+failed_pdev_add:
+ platform_device_put(ssi->soc_platform_pdev);
+failed_pdev_alloc:
+ snd_soc_unregister_dai(&pdev->dev);
failed_register:
failed_ac97:
iounmap(ssi->base);
@@ -709,16 +711,15 @@ static int __devexit imx_ssi_remove(struct platform_device *pdev)
{
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct imx_ssi *ssi = platform_get_drvdata(pdev);
- struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id];
- snd_soc_unregister_dai(dai);
+ platform_device_del(ssi->soc_platform_pdev);
+ platform_device_put(ssi->soc_platform_pdev);
+
+ snd_soc_unregister_dai(&pdev->dev);
if (ssi->flags & IMX_SSI_USE_AC97)
ac97_ssi = NULL;
- if (!(ssi->flags & IMX_SSI_DMA))
- imx_ssi_fiq_exit(pdev, ssi);
-
iounmap(ssi->base);
release_mem_region(res->start, resource_size(res));
clk_disable(ssi->clk);
@@ -733,34 +734,19 @@ static struct platform_driver imx_ssi_driver = {
.remove = __devexit_p(imx_ssi_remove),
.driver = {
- .name = DRV_NAME,
+ .name = "imx-ssi",
.owner = THIS_MODULE,
},
};
static int __init imx_ssi_init(void)
{
- int ret;
-
- ret = snd_soc_register_platform(&imx_soc_platform);
- if (ret) {
- pr_err("failed to register soc platform: %d\n", ret);
- return ret;
- }
-
- ret = platform_driver_register(&imx_ssi_driver);
- if (ret) {
- snd_soc_unregister_platform(&imx_soc_platform);
- return ret;
- }
-
- return 0;
+ return platform_driver_register(&imx_ssi_driver);
}
static void __exit imx_ssi_exit(void)
{
platform_driver_unregister(&imx_ssi_driver);
- snd_soc_unregister_platform(&imx_soc_platform);
}
module_init(imx_ssi_init);
diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h
index 55f26ebcd8c2..53b780d9b2b0 100644
--- a/sound/soc/imx/imx-ssi.h
+++ b/sound/soc/imx/imx-ssi.h
@@ -183,9 +183,6 @@
#define IMX_SSI_RX_DIV_PSR 4
#define IMX_SSI_RX_DIV_PM 5
-extern struct snd_soc_dai imx_ssi_pcm_dai[2];
-extern struct snd_soc_platform imx_soc_platform;
-
#define DRV_NAME "imx-ssi"
struct imx_pcm_dma_params {
@@ -197,7 +194,7 @@ struct imx_pcm_dma_params {
struct imx_ssi {
struct platform_device *ac97_dev;
- struct snd_soc_device imx_ac97;
+ struct snd_soc_dai *imx_ac97;
struct clk *clk;
void __iomem *base;
int irq;
@@ -213,6 +210,8 @@ struct imx_ssi {
struct imx_pcm_dma_params dma_params_tx;
int enabled;
+
+ struct platform_device *soc_platform_pdev;
};
struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/imx/phycore-ac97.c
index a8307d55c70e..6a65dd705519 100644
--- a/sound/soc/imx/phycore-ac97.c
+++ b/sound/soc/imx/phycore-ac97.c
@@ -32,23 +32,20 @@ static struct snd_soc_dai_link imx_phycore_dai_ac97[] = {
{
.name = "HiFi",
.stream_name = "HiFi",
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+ .codec_dai_name = "wm9712-hifi",
+ .codec_name = "wm9712-codec",
+ .cpu_dai_name = "imx-ssi.0",
+ .platform_name = "imx-fiq-pcm-audio.0",
.ops = &imx_phycore_hifi_ops,
},
};
static struct snd_soc_card imx_phycore = {
.name = "PhyCORE-audio",
- .platform = &imx_soc_platform,
.dai_link = imx_phycore_dai_ac97,
.num_links = ARRAY_SIZE(imx_phycore_dai_ac97),
};
-static struct snd_soc_device imx_phycore_snd_devdata = {
- .card = &imx_phycore,
- .codec_dev = &soc_codec_dev_wm9712,
-};
-
static struct platform_device *imx_phycore_snd_device;
static int __init imx_phycore_init(void)
@@ -63,10 +60,12 @@ static int __init imx_phycore_init(void)
if (!imx_phycore_snd_device)
return -ENOMEM;
- imx_phycore_dai_ac97[0].cpu_dai = &imx_ssi_pcm_dai[0];
+ platform_set_drvdata(imx_phycore_snd_device, &imx_phycore);
+ ret = platform_device_add(imx_phycore_snd_device);
- platform_set_drvdata(imx_phycore_snd_device, &imx_phycore_snd_devdata);
- imx_phycore_snd_devdata.dev = &imx_phycore_snd_device->dev;
+ imx_phycore_snd_device = platform_device_alloc("wm9712-codec", -1);
+ if (!imx_phycore_snd_device)
+ return -ENOMEM;
ret = platform_device_add(imx_phycore_snd_device);
if (ret) {
diff --git a/sound/soc/imx/wm1133-ev1.c b/sound/soc/imx/wm1133-ev1.c
index a6e7d9497639..30fdb15065be 100644
--- a/sound/soc/imx/wm1133-ev1.c
+++ b/sound/soc/imx/wm1133-ev1.c
@@ -82,8 +82,8 @@ static int wm1133_ev1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int i, found = 0;
snd_pcm_format_t format = params_format(params);
unsigned int rate = params_rate(params);
@@ -210,9 +210,9 @@ static struct snd_soc_jack_pin mic_jack_pins[] = {
{ .pin = "Mic2 Jack", .mask = SND_JACK_MICROPHONE },
};
-static int wm1133_ev1_init(struct snd_soc_codec *codec)
+static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_card *card = codec->socdev->card;
+ struct snd_soc_codec *codec = rtd->codec;
snd_soc_dapm_new_controls(codec, wm1133_ev1_widgets,
ARRAY_SIZE(wm1133_ev1_widgets));
@@ -221,13 +221,13 @@ static int wm1133_ev1_init(struct snd_soc_codec *codec)
ARRAY_SIZE(wm1133_ev1_map));
/* Headphone jack detection */
- snd_soc_jack_new(card, "Headphone", SND_JACK_HEADPHONE, &hp_jack);
+ snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack);
snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
hp_jack_pins);
wm8350_hp_jack_detect(codec, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE);
/* Microphone jack detection */
- snd_soc_jack_new(card, "Microphone",
+ snd_soc_jack_new(codec, "Microphone",
SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack);
snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
mic_jack_pins);
@@ -243,8 +243,10 @@ static int wm1133_ev1_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link wm1133_ev1_dai = {
.name = "WM1133-EV1",
.stream_name = "Audio",
- .cpu_dai = &imx_ssi_pcm_dai[0],
- .codec_dai = &wm8350_dai,
+ .cpu_dai_name = "imx-ssi.0",
+ .codec_dai_name = "wm8350-hifi",
+ .platform_name = "imx-fiq-pcm-audio.0",
+ .codec_name = "wm8350-codec.0-0x1a",
.init = wm1133_ev1_init,
.ops = &wm1133_ev1_ops,
.symmetric_rates = 1,
@@ -252,16 +254,10 @@ static struct snd_soc_dai_link wm1133_ev1_dai = {
static struct snd_soc_card wm1133_ev1 = {
.name = "WM1133-EV1",
- .platform = &imx_soc_platform,
.dai_link = &wm1133_ev1_dai,
.num_links = 1,
};
-static struct snd_soc_device wm1133_ev1_snd_devdata = {
- .card = &wm1133_ev1,
- .codec_dev = &soc_codec_dev_wm8350,
-};
-
static struct platform_device *wm1133_ev1_snd_device;
static int __init wm1133_ev1_audio_init(void)
@@ -286,8 +282,7 @@ static int __init wm1133_ev1_audio_init(void)
if (!wm1133_ev1_snd_device)
return -ENOMEM;
- platform_set_drvdata(wm1133_ev1_snd_device, &wm1133_ev1_snd_devdata);
- wm1133_ev1_snd_devdata.dev = &wm1133_ev1_snd_device->dev;
+ platform_set_drvdata(wm1133_ev1_snd_device, &wm1133_ev1);
ret = platform_device_add(wm1133_ev1_snd_device);
if (ret)
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index eb518f0c5e01..f3cffd183401 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -106,15 +106,10 @@ static inline void jz4740_i2s_write(const struct jz4740_i2s *i2s,
writel(value, i2s->base + reg);
}
-static inline struct jz4740_i2s *jz4740_dai_to_i2s(struct snd_soc_dai *dai)
-{
- return dai->private_data;
-}
-
static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t conf, ctrl;
if (dai->active)
@@ -136,7 +131,7 @@ static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t conf;
if (!dai->active)
@@ -152,7 +147,7 @@ static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t ctrl;
uint32_t mask;
@@ -186,7 +181,7 @@ static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t format = 0;
uint32_t conf;
@@ -238,7 +233,7 @@ static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
enum jz4740_dma_width dma_width;
struct jz4740_pcm_config *pcm_config;
unsigned int sample_size;
@@ -288,7 +283,7 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
struct clk *parent;
int ret = 0;
@@ -312,7 +307,7 @@ static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
static int jz4740_i2s_suspend(struct snd_soc_dai *dai)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t conf;
if (dai->active) {
@@ -330,7 +325,7 @@ static int jz4740_i2s_suspend(struct snd_soc_dai *dai)
static int jz4740_i2s_resume(struct snd_soc_dai *dai)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t conf;
clk_enable(i2s->clk_aic);
@@ -346,11 +341,38 @@ static int jz4740_i2s_resume(struct snd_soc_dai *dai)
return 0;
}
-static int jz4740_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai)
+static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
{
- struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct jz4740_dma_config *dma_config;
+
+ /* Playback */
+ dma_config = &i2s->pcm_config_playback.dma_config;
+ dma_config->src_width = JZ4740_DMA_WIDTH_32BIT,
+ dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
+ dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT;
+ dma_config->flags = JZ4740_DMA_SRC_AUTOINC;
+ dma_config->mode = JZ4740_DMA_MODE_SINGLE;
+ i2s->pcm_config_playback.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
+
+ /* Capture */
+ dma_config = &i2s->pcm_config_capture.dma_config;
+ dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT,
+ dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
+ dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE;
+ dma_config->flags = JZ4740_DMA_DST_AUTOINC;
+ dma_config->mode = JZ4740_DMA_MODE_SINGLE;
+ i2s->pcm_config_capture.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
+}
+
+static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t conf;
+ clk_enable(i2s->clk_aic);
+
+ jz4740_i2c_init_pcm_config(i2s);
+
conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
(8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
@@ -363,6 +385,14 @@ static int jz4740_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *da
return 0;
}
+static int jz4740_i2s_dai_remove(struct snd_soc_dai *dai)
+{
+ struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ clk_disable(i2s->clk_aic);
+ return 0;
+}
+
static struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
.startup = jz4740_i2s_startup,
.shutdown = jz4740_i2s_shutdown,
@@ -375,9 +405,9 @@ static struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
#define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_S16_LE)
-struct snd_soc_dai jz4740_i2s_dai = {
- .name = "jz4740-i2s",
- .probe = jz4740_i2s_probe,
+static struct snd_soc_dai_driver jz4740_i2s_dai = {
+ .probe = jz4740_i2s_dai_probe,
+ .remove = jz4740_i2s_dai_remove,
.playback = {
.channels_min = 1,
.channels_max = 2,
@@ -395,30 +425,6 @@ struct snd_soc_dai jz4740_i2s_dai = {
.suspend = jz4740_i2s_suspend,
.resume = jz4740_i2s_resume,
};
-EXPORT_SYMBOL_GPL(jz4740_i2s_dai);
-
-static void __devinit jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
-{
- struct jz4740_dma_config *dma_config;
-
- /* Playback */
- dma_config = &i2s->pcm_config_playback.dma_config;
- dma_config->src_width = JZ4740_DMA_WIDTH_32BIT,
- dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
- dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT;
- dma_config->flags = JZ4740_DMA_SRC_AUTOINC;
- dma_config->mode = JZ4740_DMA_MODE_SINGLE;
- i2s->pcm_config_playback.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
-
- /* Capture */
- dma_config = &i2s->pcm_config_capture.dma_config;
- dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT,
- dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
- dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE;
- dma_config->flags = JZ4740_DMA_DST_AUTOINC;
- dma_config->mode = JZ4740_DMA_MODE_SINGLE;
- i2s->pcm_config_capture.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
-}
static int __devinit jz4740_i2s_dev_probe(struct platform_device *pdev)
{
@@ -463,24 +469,17 @@ static int __devinit jz4740_i2s_dev_probe(struct platform_device *pdev)
goto err_clk_put_aic;
}
- clk_enable(i2s->clk_aic);
-
- jz4740_i2c_init_pcm_config(i2s);
-
- jz4740_i2s_dai.private_data = i2s;
- ret = snd_soc_register_dai(&jz4740_i2s_dai);
+ platform_set_drvdata(pdev, i2s);
+ ret = snd_soc_register_dai(&pdev->dev, &jz4740_i2s_dai);
if (ret) {
dev_err(&pdev->dev, "Failed to register DAI\n");
goto err_clk_put_i2s;
}
- platform_set_drvdata(pdev, i2s);
-
return 0;
err_clk_put_i2s:
- clk_disable(i2s->clk_aic);
clk_put(i2s->clk_i2s);
err_clk_put_aic:
clk_put(i2s->clk_aic);
@@ -498,9 +497,8 @@ static int __devexit jz4740_i2s_dev_remove(struct platform_device *pdev)
{
struct jz4740_i2s *i2s = platform_get_drvdata(pdev);
- snd_soc_unregister_dai(&jz4740_i2s_dai);
+ snd_soc_unregister_dai(&pdev->dev);
- clk_disable(i2s->clk_aic);
clk_put(i2s->clk_i2s);
clk_put(i2s->clk_aic);
diff --git a/sound/soc/jz4740/jz4740-i2s.h b/sound/soc/jz4740/jz4740-i2s.h
index da22ed88a589..5e49339d8b93 100644
--- a/sound/soc/jz4740/jz4740-i2s.h
+++ b/sound/soc/jz4740/jz4740-i2s.h
@@ -13,6 +13,4 @@
#define JZ4740_I2S_BIT_CLK 0
-extern struct snd_soc_dai jz4740_i2s_dai;
-
#endif
diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c
index ee68d850c8dd..fb1483f7c966 100644
--- a/sound/soc/jz4740/jz4740-pcm.c
+++ b/sound/soc/jz4740/jz4740-pcm.c
@@ -109,7 +109,7 @@ static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct jz4740_pcm_config *config;
- config = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ config = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
if (!config)
return 0;
@@ -310,14 +310,14 @@ int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = jz4740_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto err;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = jz4740_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -328,22 +328,20 @@ err:
return ret;
}
-struct snd_soc_platform jz4740_soc_platform = {
- .name = "jz4740-pcm",
- .pcm_ops = &jz4740_pcm_ops,
+static struct snd_soc_platform_driver jz4740_soc_platform = {
+ .ops = &jz4740_pcm_ops,
.pcm_new = jz4740_pcm_new,
.pcm_free = jz4740_pcm_free,
};
-EXPORT_SYMBOL_GPL(jz4740_soc_platform);
static int __devinit jz4740_pcm_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&jz4740_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &jz4740_soc_platform);
}
static int __devexit jz4740_pcm_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&jz4740_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
return 0;
}
@@ -351,7 +349,7 @@ static struct platform_driver jz4740_pcm_driver = {
.probe = jz4740_pcm_probe,
.remove = __devexit_p(jz4740_pcm_remove),
.driver = {
- .name = "jz4740-pcm",
+ .name = "jz4740-pcm-audio",
.owner = THIS_MODULE,
},
};
diff --git a/sound/soc/jz4740/jz4740-pcm.h b/sound/soc/jz4740/jz4740-pcm.h
index e3f221e2779c..1220cbb4382c 100644
--- a/sound/soc/jz4740/jz4740-pcm.h
+++ b/sound/soc/jz4740/jz4740-pcm.h
@@ -11,8 +11,6 @@
#include <linux/dma-mapping.h>
#include <asm/mach-jz4740/dma.h>
-/* platform data */
-extern struct snd_soc_platform jz4740_soc_platform;
struct jz4740_pcm_config {
struct jz4740_dma_config dma_config;
diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c
index f15f4918f15f..ef1a99e6a3bd 100644
--- a/sound/soc/jz4740/qi_lb60.c
+++ b/sound/soc/jz4740/qi_lb60.c
@@ -22,11 +22,6 @@
#include <sound/soc-dapm.h>
#include <linux/gpio.h>
-#include "../codecs/jz4740.h"
-#include "jz4740-pcm.h"
-#include "jz4740-i2s.h"
-
-
#define QI_LB60_SND_GPIO JZ_GPIO_PORTB(29)
#define QI_LB60_AMP_GPIO JZ_GPIO_PORTD(4)
@@ -60,10 +55,11 @@ static const struct snd_soc_dapm_route qi_lb60_routes[] = {
SND_SOC_DAIFMT_NB_NF | \
SND_SOC_DAIFMT_CBM_CFM)
-static int qi_lb60_codec_init(struct snd_soc_codec *codec)
+static int qi_lb60_codec_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
- struct snd_soc_dai *cpu_dai = codec->socdev->card->dai_link->cpu_dai;
snd_soc_dapm_nc_pin(codec, "LIN");
snd_soc_dapm_nc_pin(codec, "RIN");
@@ -84,8 +80,10 @@ static int qi_lb60_codec_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link qi_lb60_dai = {
.name = "jz4740",
.stream_name = "jz4740",
- .cpu_dai = &jz4740_i2s_dai,
- .codec_dai = &jz4740_codec_dai,
+ .cpu_dai_name = "jz4740-i2s",
+ .platform_name = "jz4740-pcm-audio",
+ .codec_dai_name = "jz4740-hifi",
+ .codec_name = "jz4740-codec",
.init = qi_lb60_codec_init,
};
@@ -93,12 +91,6 @@ static struct snd_soc_card qi_lb60 = {
.name = "QI LB60",
.dai_link = &qi_lb60_dai,
.num_links = 1,
- .platform = &jz4740_soc_platform,
-};
-
-static struct snd_soc_device qi_lb60_snd_devdata = {
- .card = &qi_lb60,
- .codec_dev = &soc_codec_dev_jz4740_codec,
};
static struct platform_device *qi_lb60_snd_device;
@@ -129,8 +121,7 @@ static int __init qi_lb60_init(void)
gpio_direction_output(QI_LB60_SND_GPIO, 0);
gpio_direction_output(QI_LB60_AMP_GPIO, 0);
- platform_set_drvdata(qi_lb60_snd_device, &qi_lb60_snd_devdata);
- qi_lb60_snd_devdata.dev = &qi_lb60_snd_device->dev;
+ platform_set_drvdata(qi_lb60_snd_device, &qi_lb60);
ret = platform_device_add(qi_lb60_snd_device);
if (ret) {
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index a30205be3e2b..0fd6a630db01 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -2,6 +2,7 @@
* kirkwood-dma.c
*
* (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.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
@@ -18,7 +19,6 @@
#include <linux/dma-mapping.h>
#include <linux/mbus.h>
#include <sound/soc.h>
-#include "kirkwood-dma.h"
#include "kirkwood.h"
#define KIRKWOOD_RATES \
@@ -123,9 +123,10 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
int err;
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+ struct snd_soc_platform *platform = soc_runtime->platform;
+ struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
struct kirkwood_dma_data *priv;
- struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+ struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform);
unsigned long addr;
priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
@@ -151,7 +152,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
if (err < 0)
return err;
- if (soc_runtime->dai->cpu_dai->private_data == NULL) {
+ if (prdata == NULL) {
prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL);
if (prdata == NULL)
return -ENOMEM;
@@ -165,7 +166,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
return -EBUSY;
}
- soc_runtime->dai->cpu_dai->private_data = prdata;
+ snd_soc_platform_set_drvdata(platform, prdata);
/*
* Enable Error interrupts. We're only ack'ing them but
@@ -191,8 +192,9 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
static int kirkwood_dma_close(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
- struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+ struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
+ struct snd_soc_platform *platform = soc_runtime->platform;
+ struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform);
struct kirkwood_dma_data *priv;
priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
@@ -209,7 +211,7 @@ static int kirkwood_dma_close(struct snd_pcm_substream *substream)
writel(0, priv->io + KIRKWOOD_ERR_MASK);
free_irq(priv->irq, prdata);
kfree(prdata);
- soc_runtime->dai->cpu_dai->private_data = NULL;
+ snd_soc_platform_set_drvdata(platform, NULL);
}
return 0;
@@ -236,7 +238,7 @@ static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
struct kirkwood_dma_data *priv;
unsigned long size, count;
@@ -265,7 +267,7 @@ static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
*substream)
{
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
struct kirkwood_dma_data *priv;
snd_pcm_uframes_t count;
@@ -320,14 +322,14 @@ static int kirkwood_dma_new(struct snd_card *card,
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = 0xffffffff;
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = kirkwood_dma_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
return ret;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = kirkwood_dma_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -357,27 +359,46 @@ static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm)
}
}
-struct snd_soc_platform kirkwood_soc_platform = {
- .name = "kirkwood-dma",
- .pcm_ops = &kirkwood_dma_ops,
+static struct snd_soc_platform_driver kirkwood_soc_platform = {
+ .ops = &kirkwood_dma_ops,
.pcm_new = kirkwood_dma_new,
.pcm_free = kirkwood_dma_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(kirkwood_soc_platform);
-static int __init kirkwood_soc_platform_init(void)
+static int __devinit kirkwood_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&kirkwood_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform);
}
-module_init(kirkwood_soc_platform_init);
-static void __exit kirkwood_soc_platform_exit(void)
+static int __devexit kirkwood_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&kirkwood_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_exit(kirkwood_soc_platform_exit);
-MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+static struct platform_driver kirkwood_pcm_driver = {
+ .driver = {
+ .name = "kirkwood-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = kirkwood_soc_platform_probe,
+ .remove = __devexit_p(kirkwood_soc_platform_remove),
+};
+
+static int __init kirkwood_pcm_init(void)
+{
+ return platform_driver_register(&kirkwood_pcm_driver);
+}
+module_init(kirkwood_pcm_init);
+
+static void __exit kirkwood_pcm_exit(void)
+{
+ platform_driver_unregister(&kirkwood_pcm_driver);
+}
+module_exit(kirkwood_pcm_exit);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
MODULE_LICENSE("GPL");
-
+MODULE_ALIAS("platform:kirkwood-pcm-audio");
diff --git a/sound/soc/kirkwood/kirkwood-dma.h b/sound/soc/kirkwood/kirkwood-dma.h
deleted file mode 100644
index ba4454cd34f1..000000000000
--- a/sound/soc/kirkwood/kirkwood-dma.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * kirkwood-dma.h
- *
- * (c) 2010 Arnaud Patard <apatard@mandriva.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#ifndef _KIRKWOOD_DMA_H
-#define _KIRKWOOD_DMA_H
-
-extern struct snd_soc_platform kirkwood_soc_platform;
-
-#endif
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index 981ffc2a13c8..a33fc51f363b 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -2,6 +2,7 @@
* kirkwood-i2s.c
*
* (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.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
@@ -20,7 +21,6 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <plat/audio.h>
-#include "kirkwood-i2s.h"
#include "kirkwood.h"
#define DRV_NAME "kirkwood-i2s"
@@ -33,13 +33,10 @@
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
-
-struct snd_soc_dai kirkwood_i2s_dai;
-static struct kirkwood_dma_data *priv;
-
static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
+ struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai);
unsigned long mask;
unsigned long value;
@@ -101,10 +98,20 @@ static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
} while (value == 0);
}
+static int kirkwood_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_set_dma_data(dai, substream, priv);
+ return 0;
+}
+
static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
+ struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
unsigned int i2s_reg, reg;
unsigned long i2s_value, value;
@@ -171,6 +178,7 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
+ struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
unsigned long value;
/*
@@ -244,6 +252,7 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
+ struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
unsigned long value;
value = readl(priv->io + KIRKWOOD_RECCTL);
@@ -323,9 +332,9 @@ static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
-static int kirkwood_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int kirkwood_i2s_probe(struct snd_soc_dai *dai)
{
+ struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
unsigned long value;
unsigned int reg_data;
@@ -359,21 +368,20 @@ static int kirkwood_i2s_probe(struct platform_device *pdev,
}
-static void kirkwood_i2s_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int kirkwood_i2s_remove(struct snd_soc_dai *dai)
{
+ return 0;
}
static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
+ .startup = kirkwood_i2s_startup,
.trigger = kirkwood_i2s_trigger,
.hw_params = kirkwood_i2s_hw_params,
.set_fmt = kirkwood_i2s_set_fmt,
};
-struct snd_soc_dai kirkwood_i2s_dai = {
- .name = DRV_NAME,
- .id = 0,
+static struct snd_soc_dai_driver kirkwood_i2s_dai = {
.probe = kirkwood_i2s_probe,
.remove = kirkwood_i2s_remove,
.playback = {
@@ -388,13 +396,13 @@ struct snd_soc_dai kirkwood_i2s_dai = {
.formats = KIRKWOOD_I2S_FORMATS,},
.ops = &kirkwood_i2s_dai_ops,
};
-EXPORT_SYMBOL_GPL(kirkwood_i2s_dai);
static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
{
struct resource *mem;
struct kirkwood_asoc_platform_data *data =
pdev->dev.platform_data;
+ struct kirkwood_dma_data *priv;
int err;
priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL);
@@ -403,6 +411,7 @@ static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
err = -ENOMEM;
goto error;
}
+ dev_set_drvdata(&pdev->dev, priv);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
@@ -441,10 +450,7 @@ static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
priv->dram = data->dram;
priv->burst = data->burst;
- kirkwood_i2s_dai.capture.dma_data = priv;
- kirkwood_i2s_dai.playback.dma_data = priv;
-
- return snd_soc_register_dai(&kirkwood_i2s_dai);
+ return snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai);
err_ioremap:
iounmap(priv->io);
@@ -458,12 +464,13 @@ error:
static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
{
- if (priv) {
- iounmap(priv->io);
- release_mem_region(priv->mem->start, SZ_16K);
- kfree(priv);
- }
- snd_soc_unregister_dai(&kirkwood_i2s_dai);
+ struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
+
+ snd_soc_unregister_dai(&pdev->dev);
+ iounmap(priv->io);
+ release_mem_region(priv->mem->start, SZ_16K);
+ kfree(priv);
+
return 0;
}
@@ -489,7 +496,7 @@ static void __exit kirkwood_i2s_exit(void)
module_exit(kirkwood_i2s_exit);
/* Module information */
-MODULE_AUTHOR("Arnaud Patard, <apatard@mandriva.com>");
+MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:kirkwood-i2s");
diff --git a/sound/soc/kirkwood/kirkwood-i2s.h b/sound/soc/kirkwood/kirkwood-i2s.h
deleted file mode 100644
index c5595c616d7a..000000000000
--- a/sound/soc/kirkwood/kirkwood-i2s.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * kirkwood-i2s.h
- *
- * (c) 2010 Arnaud Patard <apatard@mandriva.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#ifndef _KIRKWOOD_I2S_H
-#define _KIRKWOOD_I2S_H
-
-extern struct snd_soc_dai kirkwood_i2s_dai;
-
-#endif
diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c
index 0353d06bc41a..9d7c81e921f1 100644
--- a/sound/soc/kirkwood/kirkwood-openrd.c
+++ b/sound/soc/kirkwood/kirkwood-openrd.c
@@ -2,6 +2,7 @@
* kirkwood-openrd.c
*
* (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.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
@@ -18,16 +19,14 @@
#include <mach/kirkwood.h>
#include <plat/audio.h>
#include <asm/mach-types.h>
-#include "kirkwood-i2s.h"
-#include "kirkwood-dma.h"
#include "../codecs/cs42l51.h"
static int openrd_client_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
unsigned int freq, fmt;
@@ -66,8 +65,10 @@ static struct snd_soc_dai_link openrd_client_dai[] = {
{
.name = "CS42L51",
.stream_name = "CS42L51 HiFi",
- .cpu_dai = &kirkwood_i2s_dai,
- .codec_dai = &cs42l51_dai,
+ .cpu_dai_name = "kirkwood-i2s",
+ .platform_name = "kirkwood-pcm-audio",
+ .codec_dai_name = "cs42l51-hifi",
+ .codec_name = "cs42l51-codec.0-004a",
.ops = &openrd_client_ops,
},
};
@@ -75,16 +76,10 @@ static struct snd_soc_dai_link openrd_client_dai[] = {
static struct snd_soc_card openrd_client = {
.name = "OpenRD Client",
- .platform = &kirkwood_soc_platform,
.dai_link = openrd_client_dai,
.num_links = ARRAY_SIZE(openrd_client_dai),
};
-static struct snd_soc_device openrd_client_snd_devdata = {
- .card = &openrd_client,
- .codec_dev = &soc_codec_device_cs42l51,
-};
-
static struct platform_device *openrd_client_snd_device;
static int __init openrd_client_init(void)
@@ -99,8 +94,7 @@ static int __init openrd_client_init(void)
return -ENOMEM;
platform_set_drvdata(openrd_client_snd_device,
- &openrd_client_snd_devdata);
- openrd_client_snd_devdata.dev = &openrd_client_snd_device->dev;
+ &openrd_client);
ret = platform_device_add(openrd_client_snd_device);
if (ret) {
@@ -120,7 +114,7 @@ module_init(openrd_client_init);
module_exit(openrd_client_exit);
/* Module information */
-MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
MODULE_DESCRIPTION("ALSA SoC OpenRD Client");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:soc-audio");
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c
index caa7c901bc2e..293dc748797c 100644
--- a/sound/soc/nuc900/nuc900-ac97.c
+++ b/sound/soc/nuc900/nuc900-ac97.c
@@ -20,7 +20,6 @@
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/soc.h>
-#include <linux/device.h>
#include <linux/clk.h>
#include <mach/mfp.h>
@@ -297,8 +296,7 @@ static struct snd_soc_dai_ops nuc900_ac97_dai_ops = {
.trigger = nuc900_ac97_trigger,
};
-struct snd_soc_dai nuc900_ac97_dai = {
- .name = "nuc900-ac97",
+static struct snd_soc_dai_driver nuc900_ac97_dai = {
.probe = nuc900_ac97_probe,
.remove = nuc900_ac97_remove,
.ac97_control = 1,
@@ -316,7 +314,6 @@ struct snd_soc_dai nuc900_ac97_dai = {
},
.ops = &nuc900_ac97_dai_ops,
}
-EXPORT_SYMBOL_GPL(nuc900_ac97_dai);
static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)
{
@@ -365,9 +362,7 @@ static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)
nuc900_ac97_data = nuc900_audio;
- nuc900_audio->dev = nuc900_ac97_dai.dev = &pdev->dev;
-
- ret = snd_soc_register_dai(&nuc900_ac97_dai);
+ ret = snd_soc_register_dai(&pdev->dev, &nuc900_ac97_dai);
if (ret)
goto out3;
@@ -390,7 +385,7 @@ out0:
static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&nuc900_ac97_dai);
+ snd_soc_unregister_dai(&pdev->dev);
clk_put(nuc900_ac97_data->clk);
iounmap(nuc900_ac97_data->mmio);
@@ -404,7 +399,7 @@ static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev)
static struct platform_driver nuc900_ac97_driver = {
.driver = {
- .name = "nuc900-audio",
+ .name = "nuc900-ac97",
.owner = THIS_MODULE,
},
.probe = nuc900_ac97_drvprobe,
diff --git a/sound/soc/nuc900/nuc900-audio.c b/sound/soc/nuc900/nuc900-audio.c
index 72e6f518f7b2..161f5b667d7b 100644
--- a/sound/soc/nuc900/nuc900-audio.c
+++ b/sound/soc/nuc900/nuc900-audio.c
@@ -20,26 +20,21 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include "../codecs/ac97.h"
#include "nuc900-audio.h"
static struct snd_soc_dai_link nuc900evb_ac97_dai = {
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &nuc900_ac97_dai,
- .codec_dai = &ac97_dai,
+ .cpu_dai_name = "nuc900-ac97",
+ .codec_dai_name = "ac97-hifi",
+ .codec_name = "ac97-codec",
+ .platform_name = "nuc900-pcm-audio",
};
static struct snd_soc_card nuc900evb_audio_machine = {
.name = "NUC900EVB_AC97",
.dai_link = &nuc900evb_ac97_dai,
.num_links = 1,
- .platform = &nuc900_soc_platform,
-};
-
-static struct snd_soc_device nuc900evb_ac97_devdata = {
- .card = &nuc900evb_audio_machine,
- .codec_dev = &soc_codec_dev_ac97,
};
static struct platform_device *nuc900evb_asoc_dev;
@@ -54,9 +49,8 @@ static int __init nuc900evb_audio_init(void)
goto out;
/* nuc900 board audio device */
- platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_ac97_devdata);
+ platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_audio_machine);
- nuc900evb_ac97_devdata.dev = &nuc900evb_asoc_dev->dev;
ret = platform_device_add(nuc900evb_asoc_dev);
if (ret) {
diff --git a/sound/soc/nuc900/nuc900-audio.h b/sound/soc/nuc900/nuc900-audio.h
index 3038f519729f..aeed8ead2b2b 100644
--- a/sound/soc/nuc900/nuc900-audio.h
+++ b/sound/soc/nuc900/nuc900-audio.h
@@ -110,8 +110,4 @@ struct nuc900_audio {
};
-extern struct nuc900_audio *nuc900_ac97_data;
-extern struct snd_soc_dai nuc900_ac97_dai;
-extern struct snd_soc_platform nuc900_soc_platform;
-
#endif /*end _NUC900_AUDIO_H */
diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c
index e81e803b3a63..195d1ac94771 100644
--- a/sound/soc/nuc900/nuc900-pcm.c
+++ b/sound/soc/nuc900/nuc900-pcm.c
@@ -328,26 +328,44 @@ static int nuc900_dma_new(struct snd_card *card,
return 0;
}
-struct snd_soc_platform nuc900_soc_platform = {
- .name = "nuc900-dma",
- .pcm_ops = &nuc900_dma_ops,
+static struct snd_soc_platform_driver nuc900_soc_platform = {
+ .ops = &nuc900_dma_ops,
.pcm_new = nuc900_dma_new,
.pcm_free = nuc900_dma_free_dma_buffers,
}
-EXPORT_SYMBOL_GPL(nuc900_soc_platform);
-static int __init nuc900_soc_platform_init(void)
+static int __devinit nuc900_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&nuc900_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &nuc900_soc_platform);
}
-static void __exit nuc900_soc_platform_exit(void)
+static int __devexit nuc900_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&nuc900_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_init(nuc900_soc_platform_init);
-module_exit(nuc900_soc_platform_exit);
+static struct platform_driver nuc900_pcm_driver = {
+ .driver = {
+ .name = "nuc900-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = nuc900_soc_platform_probe,
+ .remove = __devexit_p(nuc900_soc_platform_remove),
+};
+
+static int __init nuc900_pcm_init(void)
+{
+ return platform_driver_register(&nuc900_pcm_driver);
+}
+module_init(nuc900_pcm_init);
+
+static void __exit nuc900_pcm_exit(void)
+{
+ platform_driver_unregister(&nuc900_pcm_driver);
+}
+module_exit(nuc900_pcm_exit);
MODULE_AUTHOR("Wan ZongShun, <mcuos.com@gmail.com>");
MODULE_DESCRIPTION("nuc900 Audio DMA module");
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
index 135901b2ea11..979dd508305f 100644
--- a/sound/soc/omap/am3517evm.c
+++ b/sound/soc/omap/am3517evm.c
@@ -40,8 +40,8 @@ static int am3517evm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -111,8 +111,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"MICIN", NULL, "Mic In"},
};
-static int am3517evm_aic23_init(struct snd_soc_codec *codec)
+static int am3517evm_aic23_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
/* Add am3517-evm specific widgets */
snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
ARRAY_SIZE(tlv320aic23_dapm_widgets));
@@ -134,8 +136,10 @@ static int am3517evm_aic23_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link am3517evm_dai = {
.name = "TLV320AIC23",
.stream_name = "AIC23",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &tlv320aic23_dai,
+ .cpu_dai_name ="omap-mcbsp-dai.0",
+ .codec_dai_name = "tlv320aic23-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "tlv320aic23-codec",
.init = am3517evm_aic23_init,
.ops = &am3517evm_ops,
};
@@ -143,27 +147,18 @@ static struct snd_soc_dai_link am3517evm_dai = {
/* Audio machine driver */
static struct snd_soc_card snd_soc_am3517evm = {
.name = "am3517evm",
- .platform = &omap_soc_platform,
.dai_link = &am3517evm_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device am3517evm_snd_devdata = {
- .card = &snd_soc_am3517evm,
- .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
static struct platform_device *am3517evm_snd_device;
static int __init am3517evm_soc_init(void)
{
int ret;
- if (!machine_is_omap3517evm()) {
- pr_err("Not OMAP3517 / AM3517 EVM!\n");
+ if (!machine_is_omap3517evm())
return -ENODEV;
- }
pr_info("OMAP3517 / AM3517 EVM SoC init\n");
am3517evm_snd_device = platform_device_alloc("soc-audio", -1);
@@ -172,9 +167,7 @@ static int __init am3517evm_soc_init(void)
return -ENOMEM;
}
- platform_set_drvdata(am3517evm_snd_device, &am3517evm_snd_devdata);
- am3517evm_snd_devdata.dev = &am3517evm_snd_device->dev;
- *(unsigned int *)am3517evm_dai.cpu_dai->private_data = 0; /* McBSP1 */
+ platform_set_drvdata(am3517evm_snd_device, &snd_soc_am3517evm);
ret = platform_device_add(am3517evm_snd_device);
if (ret)
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index b0f618e44840..438146addbb8 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -99,7 +99,7 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
int pin, changed = 0;
/* Refuse any mode changes if we are not able to control the codec. */
- if (!codec->control_data)
+ if (!codec->hw_write)
return -EUNATCH;
if (ucontrol->value.enumerated.item[0] >= control->max)
@@ -268,10 +268,32 @@ static void cx81801_timeout(unsigned long data)
ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC, 0);
}
+/*
+ * Used for passing a codec structure pointer
+ * from the board initialization code to the tty line discipline.
+ */
+static struct snd_soc_codec *cx20442_codec;
+
/* Line discipline .open() */
static int cx81801_open(struct tty_struct *tty)
{
- return v253_ops.open(tty);
+ int ret;
+
+ if (!cx20442_codec)
+ return -ENODEV;
+
+ /*
+ * Pass the codec structure pointer for use by other ldisc callbacks,
+ * both the card and the codec specific parts.
+ */
+ tty->disc_data = cx20442_codec;
+
+ ret = v253_ops.open(tty);
+
+ if (ret < 0)
+ tty->disc_data = NULL;
+
+ return ret;
}
/* Line discipline .close() */
@@ -281,11 +303,14 @@ static void cx81801_close(struct tty_struct *tty)
del_timer_sync(&cx81801_timer);
- v253_ops.close(tty);
-
/* Prevent the hook switch from further changing the DAPM pins */
INIT_LIST_HEAD(&ams_delta_hook_switch.pins);
+ if (!codec)
+ return;
+
+ v253_ops.close(tty);
+
/* Revert back to default audio input/output constellation */
snd_soc_dapm_disable_pin(codec, "Mouthpiece");
snd_soc_dapm_enable_pin(codec, "Earpiece");
@@ -310,7 +335,10 @@ static void cx81801_receive(struct tty_struct *tty,
const unsigned char *c;
int apply, ret;
- if (!codec->control_data) {
+ if (!codec)
+ return;
+
+ if (!codec->hw_write) {
/* First modem response, complete setup procedure */
/* Initialize timer used for config pulse generation */
@@ -323,7 +351,7 @@ static void cx81801_receive(struct tty_struct *tty,
ARRAY_SIZE(ams_delta_hook_switch_pins),
ams_delta_hook_switch_pins);
if (ret)
- dev_warn(codec->socdev->card->dev,
+ dev_warn(codec->dev,
"Failed to link hook switch to DAPM pins, "
"will continue with hook switch unlinked.\n");
@@ -383,7 +411,7 @@ static int ams_delta_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
/* Set cpu DAI configuration */
- return snd_soc_dai_set_fmt(rtd->dai->cpu_dai,
+ return snd_soc_dai_set_fmt(rtd->cpu_dai,
SND_SOC_DAIFMT_DSP_A |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM);
@@ -398,7 +426,7 @@ static struct snd_soc_ops ams_delta_ops = {
static int ams_delta_set_bias_level(struct snd_soc_card *card,
enum snd_soc_bias_level level)
{
- struct snd_soc_codec *codec = card->codec;
+ struct snd_soc_codec *codec = card->rtd->codec;
switch (level) {
case SND_SOC_BIAS_ON:
@@ -461,18 +489,22 @@ static void ams_delta_shutdown(struct snd_pcm_substream *substream)
* Card initialization
*/
-static int ams_delta_cx20442_init(struct snd_soc_codec *codec)
+static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *codec_dai = codec->dai;
- struct snd_soc_card *card = codec->socdev->card;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_card *card = rtd->card;
int ret;
/* Codec is ready, now add/activate board specific controls */
+ /* Store a pointer to the codec structure for tty ldisc use */
+ cx20442_codec = codec;
+
/* Set up digital mute if not provided by the codec */
- if (!codec_dai->ops) {
- codec_dai->ops = &ams_delta_dai_ops;
- } else if (!codec_dai->ops->digital_mute) {
- codec_dai->ops->digital_mute = ams_delta_digital_mute;
+ if (!codec_dai->driver->ops) {
+ codec_dai->driver->ops = &ams_delta_dai_ops;
+ } else if (!codec_dai->driver->ops->digital_mute) {
+ codec_dai->driver->ops->digital_mute = ams_delta_digital_mute;
} else {
ams_delta_ops.startup = ams_delta_startup;
ams_delta_ops.shutdown = ams_delta_shutdown;
@@ -483,7 +515,7 @@ static int ams_delta_cx20442_init(struct snd_soc_codec *codec)
/* Add hook switch - can be used to control the codec from userspace
* even if line discipline fails */
- ret = snd_soc_jack_new(card, "hook_switch",
+ ret = snd_soc_jack_new(rtd->codec, "hook_switch",
SND_JACK_HEADSET, &ams_delta_hook_switch);
if (ret)
dev_warn(card->dev,
@@ -551,27 +583,22 @@ static int ams_delta_cx20442_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link ams_delta_dai_link = {
.name = "CX20442",
.stream_name = "CX20442",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &cx20442_dai,
+ .cpu_dai_name ="omap-mcbsp-dai.0",
+ .codec_dai_name = "cx20442-voice",
.init = ams_delta_cx20442_init,
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "cx20442-codec",
.ops = &ams_delta_ops,
};
/* Audio card driver */
static struct snd_soc_card ams_delta_audio_card = {
.name = "AMS_DELTA",
- .platform = &omap_soc_platform,
.dai_link = &ams_delta_dai_link,
.num_links = 1,
.set_bias_level = ams_delta_set_bias_level,
};
-/* Audio subsystem */
-static struct snd_soc_device ams_delta_snd_soc_device = {
- .card = &ams_delta_audio_card,
- .codec_dev = &cx20442_codec_dev,
-};
-
/* Module init/exit */
static struct platform_device *ams_delta_audio_platform_device;
static struct platform_device *cx20442_platform_device;
@@ -589,9 +616,7 @@ static int __init ams_delta_module_init(void)
return -ENOMEM;
platform_set_drvdata(ams_delta_audio_platform_device,
- &ams_delta_snd_soc_device);
- ams_delta_snd_soc_device.dev = &ams_delta_audio_platform_device->dev;
- *(unsigned int *)ams_delta_dai_link.cpu_dai->private_data = OMAP_MCBSP1;
+ &ams_delta_audio_card);
ret = platform_device_add(ams_delta_audio_platform_device);
if (ret)
@@ -601,8 +626,8 @@ static int __init ams_delta_module_init(void)
* Codec platform device could be registered from elsewhere (board?),
* but I do it here as it makes sense only if used with the card.
*/
- cx20442_platform_device = platform_device_register_simple("cx20442",
- -1, NULL, 0);
+ cx20442_platform_device =
+ platform_device_register_simple("cx20442-codec", -1, NULL, 0);
return 0;
err:
platform_device_put(ams_delta_audio_platform_device);
@@ -612,19 +637,6 @@ module_init(ams_delta_module_init);
static void __exit ams_delta_module_exit(void)
{
- struct snd_soc_codec *codec;
- struct tty_struct *tty;
-
- if (ams_delta_audio_card.codec) {
- codec = ams_delta_audio_card.codec;
-
- if (codec->control_data) {
- tty = codec->control_data;
-
- tty_hangup(tty);
- }
- }
-
if (tty_unregister_ldisc(N_V253) != 0)
dev_warn(&ams_delta_audio_platform_device->dev,
"failed to unregister V253 line discipline\n");
diff --git a/sound/soc/omap/igep0020.c b/sound/soc/omap/igep0020.c
index 3583c429f9be..fd3a40f309c8 100644
--- a/sound/soc/omap/igep0020.c
+++ b/sound/soc/omap/igep0020.c
@@ -33,14 +33,13 @@
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
static int igep2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -82,35 +81,28 @@ static struct snd_soc_ops igep2_ops = {
static struct snd_soc_dai_link igep2_dai = {
.name = "TWL4030",
.stream_name = "TWL4030",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.ops = &igep2_ops,
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_card_igep2 = {
.name = "igep2",
- .platform = &omap_soc_platform,
.dai_link = &igep2_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device igep2_snd_devdata = {
- .card = &snd_soc_card_igep2,
- .codec_dev = &soc_codec_dev_twl4030,
-};
-
static struct platform_device *igep2_snd_device;
static int __init igep2_soc_init(void)
{
int ret;
- if (!machine_is_igep0020()) {
- pr_debug("Not IGEP v2!\n");
+ if (!machine_is_igep0020())
return -ENODEV;
- }
printk(KERN_INFO "IGEP v2 SoC init\n");
igep2_snd_device = platform_device_alloc("soc-audio", -1);
@@ -119,9 +111,7 @@ static int __init igep2_soc_init(void)
return -ENOMEM;
}
- platform_set_drvdata(igep2_snd_device, &igep2_snd_devdata);
- igep2_snd_devdata.dev = &igep2_snd_device->dev;
- *(unsigned int *)igep2_dai.cpu_dai->private_data = 1; /* McBSP2 */
+ platform_set_drvdata(igep2_snd_device, &snd_soc_card_igep2);
ret = platform_device_add(igep2_snd_device);
if (ret)
diff --git a/sound/soc/omap/mcpdm.c b/sound/soc/omap/mcpdm.c
index 90b8bf71c893..928f03707451 100644
--- a/sound/soc/omap/mcpdm.c
+++ b/sound/soc/omap/mcpdm.c
@@ -402,7 +402,7 @@ int omap_mcpdm_set_offset(int offset1, int offset2)
return 0;
}
-static int __devinit omap_mcpdm_probe(struct platform_device *pdev)
+int __devinit omap_mcpdm_probe(struct platform_device *pdev)
{
struct resource *res;
int ret = 0;
@@ -449,7 +449,7 @@ exit:
return ret;
}
-static int __devexit omap_mcpdm_remove(struct platform_device *pdev)
+int __devexit omap_mcpdm_remove(struct platform_device *pdev)
{
struct omap_mcpdm *mcpdm_ptr = platform_get_drvdata(pdev);
@@ -468,18 +468,3 @@ static int __devexit omap_mcpdm_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_driver omap_mcpdm_driver = {
- .probe = omap_mcpdm_probe,
- .remove = __devexit_p(omap_mcpdm_remove),
- .driver = {
- .name = "omap-mcpdm",
- },
-};
-
-static struct platform_device *omap_mcpdm_device;
-
-static int __init omap_mcpdm_init(void)
-{
- return platform_driver_register(&omap_mcpdm_driver);
-}
-arch_initcall(omap_mcpdm_init);
diff --git a/sound/soc/omap/mcpdm.h b/sound/soc/omap/mcpdm.h
index 7bb326ef0886..df3e16fb51f3 100644
--- a/sound/soc/omap/mcpdm.h
+++ b/sound/soc/omap/mcpdm.h
@@ -149,3 +149,5 @@ extern int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink);
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);
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 08e09d72790f..a3b6d897ad84 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -97,7 +97,7 @@ static int n810_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
@@ -115,8 +115,8 @@ static int n810_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int err;
/* Set codec DAI configuration */
@@ -271,8 +271,9 @@ static const struct snd_kcontrol_new aic33_n810_controls[] = {
n810_get_input, n810_set_input),
};
-static int n810_aic33_init(struct snd_soc_codec *codec)
+static int n810_aic33_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* Not connected */
@@ -307,8 +308,10 @@ static int n810_aic33_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link n810_dai = {
.name = "TLV320AIC33",
.stream_name = "AIC33",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &aic3x_dai,
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "tlv320aic3x-codec.2-0018",
+ .codec_dai_name = "tlv320aic3x-hifi",
.init = n810_aic33_init,
.ops = &n810_ops,
};
@@ -316,33 +319,12 @@ static struct snd_soc_dai_link n810_dai = {
/* Audio machine driver */
static struct snd_soc_card snd_soc_n810 = {
.name = "N810",
- .platform = &omap_soc_platform,
.dai_link = &n810_dai,
.num_links = 1,
};
-/* Audio private data */
-static struct aic3x_setup_data n810_aic33_setup = {
- .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
- .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device n810_snd_devdata = {
- .card = &snd_soc_n810,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &n810_aic33_setup,
-};
-
static struct platform_device *n810_snd_device;
-/* temporary i2c device creation until this can be moved into the machine
- * support file.
-*/
-static struct i2c_board_info i2c_device[] = {
- { I2C_BOARD_INFO("tlv320aic3x", 0x1b), }
-};
-
static int __init n810_soc_init(void)
{
int err;
@@ -351,15 +333,11 @@ static int __init n810_soc_init(void)
if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax()))
return -ENODEV;
- i2c_register_board_info(1, i2c_device, ARRAY_SIZE(i2c_device));
-
n810_snd_device = platform_device_alloc("soc-audio", -1);
if (!n810_snd_device)
return -ENOMEM;
- platform_set_drvdata(n810_snd_device, &n810_snd_devdata);
- n810_snd_devdata.dev = &n810_snd_device->dev;
- *(unsigned int *)n810_dai.cpu_dai->private_data = 1; /* McBSP2 */
+ platform_set_drvdata(n810_snd_device, &snd_soc_n810);
err = platform_device_add(n810_snd_device);
if (err)
goto err1;
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 86f213905e2c..d211c9fa5a91 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -31,7 +31,6 @@
#include <sound/initval.h>
#include <sound/soc.h>
-#include <plat/control.h>
#include <plat/dma.h>
#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
@@ -62,8 +61,6 @@ struct omap_mcbsp_data {
int wlen;
};
-#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id)
-
static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
/*
@@ -153,13 +150,13 @@ static const unsigned long omap34xx_mcbsp_port[][2] = {};
static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
struct omap_pcm_dma_data *dma_data;
int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
int words;
- dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
/* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
@@ -203,11 +200,9 @@ static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
}
static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
int bus_id = mcbsp_data->bus_id;
int err = 0;
@@ -249,11 +244,9 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
}
static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
if (!cpu_dai->active) {
omap_mcbsp_free(mcbsp_data->bus_id);
@@ -262,11 +255,9 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
}
static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
switch (cmd) {
@@ -295,8 +286,8 @@ static snd_pcm_sframes_t omap_mcbsp_dai_delay(
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
u16 fifo_use;
snd_pcm_sframes_t delay;
@@ -317,11 +308,9 @@ static snd_pcm_sframes_t omap_mcbsp_dai_delay(
static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
struct omap_pcm_dma_data *dma_data;
int dma, bus_id = mcbsp_data->bus_id;
@@ -496,7 +485,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
unsigned int temp_fmt = fmt;
@@ -596,7 +585,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div)
{
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
if (div_id != OMAP_MCBSP_CLKGDV)
@@ -608,101 +597,22 @@ static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
return 0;
}
-static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
- int clk_id)
-{
- int sel_bit;
- u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1;
-
- if (cpu_class_is_omap1()) {
- /* OMAP1's can use only external source clock */
- if (unlikely(clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK))
- return -EINVAL;
- else
- return 0;
- }
-
- if (cpu_is_omap2420() && mcbsp_data->bus_id > 1)
- return -EINVAL;
-
- if (cpu_is_omap343x())
- reg_devconf1 = OMAP343X_CONTROL_DEVCONF1;
-
- switch (mcbsp_data->bus_id) {
- case 0:
- reg = OMAP2_CONTROL_DEVCONF0;
- sel_bit = 2;
- break;
- case 1:
- reg = OMAP2_CONTROL_DEVCONF0;
- sel_bit = 6;
- break;
- case 2:
- reg = reg_devconf1;
- sel_bit = 0;
- break;
- case 3:
- reg = reg_devconf1;
- sel_bit = 2;
- break;
- case 4:
- reg = reg_devconf1;
- sel_bit = 4;
- break;
- default:
- return -EINVAL;
- }
-
- if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK)
- omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg);
- else
- omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg);
-
- return 0;
-}
-
-static int omap_mcbsp_dai_set_rcvr_src(struct omap_mcbsp_data *mcbsp_data,
- int clk_id)
-{
- int sel_bit, set = 0;
- u16 reg = OMAP2_CONTROL_DEVCONF0;
-
- if (cpu_class_is_omap1())
- return -EINVAL; /* TODO: Can this be implemented for OMAP1? */
- if (mcbsp_data->bus_id != 0)
- return -EINVAL;
-
- switch (clk_id) {
- case OMAP_MCBSP_CLKR_SRC_CLKX:
- set = 1;
- case OMAP_MCBSP_CLKR_SRC_CLKR:
- sel_bit = 3;
- break;
- case OMAP_MCBSP_FSR_SRC_FSX:
- set = 1;
- case OMAP_MCBSP_FSR_SRC_FSR:
- sel_bit = 4;
- break;
- default:
- return -EINVAL;
- }
-
- if (set)
- omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg);
- else
- omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg);
-
- return 0;
-}
-
static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq,
int dir)
{
- struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
int err = 0;
+ /* 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 ||
+ clk_id == OMAP_MCBSP_FSR_SRC_FSR ||
+ clk_id == OMAP_MCBSP_FSR_SRC_FSX)
+ if (cpu_class_is_omap1() || mcbsp_data->bus_id != 0)
+ return -EINVAL;
+
mcbsp_data->in_freq = freq;
switch (clk_id) {
@@ -710,8 +620,20 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
regs->srgr2 |= CLKSM;
break;
case OMAP_MCBSP_SYSCLK_CLKS_FCLK:
+ if (cpu_class_is_omap1()) {
+ err = -EINVAL;
+ break;
+ }
+ err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id,
+ MCBSP_CLKS_PRCM_SRC);
+ break;
case OMAP_MCBSP_SYSCLK_CLKS_EXT:
- err = omap_mcbsp_dai_set_clks_src(mcbsp_data, clk_id);
+ if (cpu_class_is_omap1()) {
+ err = 0;
+ break;
+ }
+ err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id,
+ MCBSP_CLKS_PAD_SRC);
break;
case OMAP_MCBSP_SYSCLK_CLKX_EXT:
@@ -720,11 +642,18 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
regs->pcr0 |= SCLKME;
break;
+
case OMAP_MCBSP_CLKR_SRC_CLKR:
+ omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKR);
+ break;
case OMAP_MCBSP_CLKR_SRC_CLKX:
+ omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKX);
+ break;
case OMAP_MCBSP_FSR_SRC_FSR:
+ omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSR);
+ break;
case OMAP_MCBSP_FSR_SRC_FSX:
- err = omap_mcbsp_dai_set_rcvr_src(mcbsp_data, clk_id);
+ omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSX);
break;
default:
err = -ENODEV;
@@ -733,7 +662,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
return err;
}
-static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
+static struct snd_soc_dai_ops mcbsp_dai_ops = {
.startup = omap_mcbsp_dai_startup,
.shutdown = omap_mcbsp_dai_shutdown,
.trigger = omap_mcbsp_dai_trigger,
@@ -744,43 +673,32 @@ static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
.set_sysclk = omap_mcbsp_dai_set_dai_sysclk,
};
-#define OMAP_MCBSP_DAI_BUILDER(link_id) \
-{ \
- .name = "omap-mcbsp-dai-"#link_id, \
- .id = (link_id), \
- .playback = { \
- .channels_min = 1, \
- .channels_max = 16, \
- .rates = OMAP_MCBSP_RATES, \
- .formats = SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S32_LE, \
- }, \
- .capture = { \
- .channels_min = 1, \
- .channels_max = 16, \
- .rates = OMAP_MCBSP_RATES, \
- .formats = SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S32_LE, \
- }, \
- .ops = &omap_mcbsp_dai_ops, \
- .private_data = &mcbsp_data[(link_id)].bus_id, \
+static int mcbsp_dai_probe(struct snd_soc_dai *dai)
+{
+ mcbsp_data[dai->id].bus_id = dai->id;
+ snd_soc_dai_set_drvdata(dai, &mcbsp_data[dai->id].bus_id);
+ return 0;
}
-struct snd_soc_dai omap_mcbsp_dai[] = {
- OMAP_MCBSP_DAI_BUILDER(0),
- OMAP_MCBSP_DAI_BUILDER(1),
-#if NUM_LINKS >= 3
- OMAP_MCBSP_DAI_BUILDER(2),
-#endif
-#if NUM_LINKS == 5
- OMAP_MCBSP_DAI_BUILDER(3),
- OMAP_MCBSP_DAI_BUILDER(4),
-#endif
+static struct snd_soc_dai_driver omap_mcbsp_dai =
+{
+ .probe = mcbsp_dai_probe,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = OMAP_MCBSP_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = OMAP_MCBSP_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mcbsp_dai_ops,
};
-EXPORT_SYMBOL_GPL(omap_mcbsp_dai);
-
-int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
+static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct soc_mixer_control *mc =
@@ -910,16 +828,36 @@ int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id)
}
EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
+static __devinit int asoc_mcbsp_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai);
+}
+
+static int __devexit asoc_mcbsp_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver asoc_mcbsp_driver = {
+ .driver = {
+ .name = "omap-mcbsp-dai",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = asoc_mcbsp_probe,
+ .remove = __devexit_p(asoc_mcbsp_remove),
+};
+
static int __init snd_omap_mcbsp_init(void)
{
- return snd_soc_register_dais(omap_mcbsp_dai,
- ARRAY_SIZE(omap_mcbsp_dai));
+ return platform_driver_register(&asoc_mcbsp_driver);
}
module_init(snd_omap_mcbsp_init);
static void __exit snd_omap_mcbsp_exit(void)
{
- snd_soc_unregister_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai));
+ platform_driver_unregister(&asoc_mcbsp_driver);
}
module_exit(snd_omap_mcbsp_exit);
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index 6c363e5f4387..ffdcc5abb7b9 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -55,8 +55,6 @@ enum omap_mcbsp_div {
#define NUM_LINKS 5
#endif
-extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS];
-
int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id);
#endif
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index b7f4f7e015f3..bed09c27e44c 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -32,11 +32,9 @@
#include <sound/initval.h>
#include <sound/soc.h>
-#include <plat/control.h>
#include <plat/dma.h>
#include <plat/mcbsp.h>
#include "mcpdm.h"
-#include "omap-mcpdm.h"
#include "omap-pcm.h"
struct omap_mcpdm_data {
@@ -89,11 +87,9 @@ static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
int err = 0;
- if (!cpu_dai->active)
+ if (!dai->active)
err = omap_mcpdm_request();
return err;
@@ -102,19 +98,14 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-
- if (!cpu_dai->active)
+ if (!dai->active)
omap_mcpdm_free();
}
static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
+ struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
int stream = substream->stream;
int err = 0;
@@ -143,14 +134,12 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
+ struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
int stream = substream->stream;
int channels, err, link_mask = 0;
- snd_soc_dai_set_dma_data(cpu_dai, substream,
+ snd_soc_dai_set_dma_data(dai, substream,
&omap_mcpdm_dai_dma_params[stream]);
channels = params_channels(params);
@@ -189,9 +178,7 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
+ struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
int stream = substream->stream;
int err;
@@ -215,9 +202,14 @@ static struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
#define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
#define OMAP_MCPDM_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
-struct snd_soc_dai omap_mcpdm_dai = {
- .name = "omap-mcpdm",
- .id = -1,
+static int omap_mcpdm_dai_probe(struct snd_soc_dai *dai)
+{
+ snd_soc_dai_set_drvdata(dai, &mcpdm_data);
+ return 0;
+}
+
+static struct snd_soc_dai_driver omap_mcpdm_dai = {
+ .probe = omap_mcpdm_dai_probe,
.playback = {
.channels_min = 1,
.channels_max = 4,
@@ -231,19 +223,47 @@ struct snd_soc_dai omap_mcpdm_dai = {
.formats = OMAP_MCPDM_FORMATS,
},
.ops = &omap_mcpdm_dai_ops,
- .private_data = &mcpdm_data,
};
-EXPORT_SYMBOL_GPL(omap_mcpdm_dai);
+
+static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = omap_mcpdm_probe(pdev);
+ if (ret < 0)
+ return ret;
+ ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
+ if (ret < 0)
+ omap_mcpdm_remove(pdev);
+ return ret;
+}
+
+static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ omap_mcpdm_remove(pdev);
+ return 0;
+}
+
+static struct platform_driver asoc_mcpdm_driver = {
+ .driver = {
+ .name = "omap-mcpdm-dai",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = asoc_mcpdm_probe,
+ .remove = __devexit_p(asoc_mcpdm_remove),
+};
static int __init snd_omap_mcpdm_init(void)
{
- return snd_soc_register_dai(&omap_mcpdm_dai);
+ return platform_driver_register(&asoc_mcpdm_driver);
}
module_init(snd_omap_mcpdm_init);
static void __exit snd_omap_mcpdm_exit(void)
{
- snd_soc_unregister_dai(&omap_mcpdm_dai);
+ platform_driver_unregister(&asoc_mcpdm_driver);
}
module_exit(snd_omap_mcpdm_exit);
diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/omap/omap-mcpdm.h
deleted file mode 100644
index 73b80d559345..000000000000
--- a/sound/soc/omap/omap-mcpdm.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * omap-mcpdm.h
- *
- * Copyright (C) 2009 Texas Instruments
- *
- * Contact: Misael Lopez Cruz <x0052729@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., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __OMAP_MCPDM_H__
-#define __OMAP_MCPDM_H__
-
-extern struct snd_soc_dai omap_mcpdm_dai;
-
-#endif /* End of __OMAP_MCPDM_H__ */
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 1e521904ea64..8caeb8d305c3 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -101,9 +101,10 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct omap_runtime_data *prtd = runtime->private_data;
struct omap_pcm_dma_data *dma_data;
+
int err = 0;
- dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
/* return if this is a bufferless transfer e.g.
* codec <--> BT codec or GSM modem -- lg FIXME */
@@ -374,14 +375,14 @@ static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(64);
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = omap_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = omap_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -392,25 +393,45 @@ out:
return ret;
}
-struct snd_soc_platform omap_soc_platform = {
- .name = "omap-pcm-audio",
- .pcm_ops = &omap_pcm_ops,
+static struct snd_soc_platform_driver omap_soc_platform = {
+ .ops = &omap_pcm_ops,
.pcm_new = omap_pcm_new,
.pcm_free = omap_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(omap_soc_platform);
-static int __init omap_soc_platform_init(void)
+static __devinit int omap_pcm_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_platform(&pdev->dev,
+ &omap_soc_platform);
+}
+
+static int __devexit omap_pcm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver omap_pcm_driver = {
+ .driver = {
+ .name = "omap-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = omap_pcm_probe,
+ .remove = __devexit_p(omap_pcm_remove),
+};
+
+static int __init snd_omap_pcm_init(void)
{
- return snd_soc_register_platform(&omap_soc_platform);
+ return platform_driver_register(&omap_pcm_driver);
}
-module_init(omap_soc_platform_init);
+module_init(snd_omap_pcm_init);
-static void __exit omap_soc_platform_exit(void)
+static void __exit snd_omap_pcm_exit(void)
{
- snd_soc_unregister_platform(&omap_soc_platform);
+ platform_driver_unregister(&omap_pcm_driver);
}
-module_exit(omap_soc_platform_exit);
+module_exit(snd_omap_pcm_exit);
MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
MODULE_DESCRIPTION("OMAP PCM DMA module");
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
index b19975d26907..fea0515331fb 100644
--- a/sound/soc/omap/omap-pcm.h
+++ b/sound/soc/omap/omap-pcm.h
@@ -35,6 +35,4 @@ struct omap_pcm_dma_data {
int packet_size; /* packet size only in PACKET mode */
};
-extern struct snd_soc_platform omap_soc_platform;
-
#endif
diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c
index c7adea38274c..cf3fc8a675b5 100644
--- a/sound/soc/omap/omap2evm.c
+++ b/sound/soc/omap/omap2evm.c
@@ -35,15 +35,13 @@
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
static int omap2evm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -85,35 +83,28 @@ static struct snd_soc_ops omap2evm_ops = {
static struct snd_soc_dai_link omap2evm_dai = {
.name = "TWL4030",
.stream_name = "TWL4030",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.ops = &omap2evm_ops,
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_omap2evm = {
.name = "omap2evm",
- .platform = &omap_soc_platform,
.dai_link = &omap2evm_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device omap2evm_snd_devdata = {
- .card = &snd_soc_omap2evm,
- .codec_dev = &soc_codec_dev_twl4030,
-};
-
static struct platform_device *omap2evm_snd_device;
static int __init omap2evm_soc_init(void)
{
int ret;
- if (!machine_is_omap2evm()) {
- pr_debug("Not omap2evm!\n");
+ if (!machine_is_omap2evm())
return -ENODEV;
- }
printk(KERN_INFO "omap2evm SoC init\n");
omap2evm_snd_device = platform_device_alloc("soc-audio", -1);
@@ -122,9 +113,7 @@ static int __init omap2evm_soc_init(void)
return -ENOMEM;
}
- platform_set_drvdata(omap2evm_snd_device, &omap2evm_snd_devdata);
- omap2evm_snd_devdata.dev = &omap2evm_snd_device->dev;
- *(unsigned int *)omap2evm_dai.cpu_dai->private_data = 1; /* McBSP2 */
+ platform_set_drvdata(omap2evm_snd_device, &snd_soc_omap2evm);
ret = platform_device_add(omap2evm_snd_device);
if (ret)
diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c
index 240e0975dd6a..e56832b0c444 100644
--- a/sound/soc/omap/omap3beagle.c
+++ b/sound/soc/omap/omap3beagle.c
@@ -33,14 +33,13 @@
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
static int omap3beagle_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int fmt;
int ret;
@@ -92,35 +91,29 @@ static struct snd_soc_ops omap3beagle_ops = {
static struct snd_soc_dai_link omap3beagle_dai = {
.name = "TWL4030",
.stream_name = "TWL4030",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .platform_name = "omap-pcm-audio",
+ .codec_dai_name = "twl4030-hifi",
+ .codec_name = "twl4030-codec",
.ops = &omap3beagle_ops,
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_omap3beagle = {
.name = "omap3beagle",
- .platform = &omap_soc_platform,
+ .owner = THIS_MODULE,
.dai_link = &omap3beagle_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device omap3beagle_snd_devdata = {
- .card = &snd_soc_omap3beagle,
- .codec_dev = &soc_codec_dev_twl4030,
-};
-
static struct platform_device *omap3beagle_snd_device;
static int __init omap3beagle_soc_init(void)
{
int ret;
- if (!(machine_is_omap3_beagle() || machine_is_devkit8000())) {
- pr_debug("Not OMAP3 Beagle or Devkit8000!\n");
+ if (!(machine_is_omap3_beagle() || machine_is_devkit8000()))
return -ENODEV;
- }
pr_info("OMAP3 Beagle/Devkit8000 SoC init\n");
omap3beagle_snd_device = platform_device_alloc("soc-audio", -1);
@@ -129,9 +122,7 @@ static int __init omap3beagle_soc_init(void)
return -ENOMEM;
}
- platform_set_drvdata(omap3beagle_snd_device, &omap3beagle_snd_devdata);
- omap3beagle_snd_devdata.dev = &omap3beagle_snd_device->dev;
- *(unsigned int *)omap3beagle_dai.cpu_dai->private_data = 1; /* McBSP2 */
+ platform_set_drvdata(omap3beagle_snd_device, &snd_soc_omap3beagle);
ret = platform_device_add(omap3beagle_snd_device);
if (ret)
diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
index dfcb344092e4..810f1e36da21 100644
--- a/sound/soc/omap/omap3evm.c
+++ b/sound/soc/omap/omap3evm.c
@@ -31,14 +31,13 @@
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
static int omap3evm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -80,42 +79,28 @@ static struct snd_soc_ops omap3evm_ops = {
static struct snd_soc_dai_link omap3evm_dai = {
.name = "TWL4030",
.stream_name = "TWL4030",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.ops = &omap3evm_ops,
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_omap3evm = {
.name = "omap3evm",
- .platform = &omap_soc_platform,
.dai_link = &omap3evm_dai,
.num_links = 1,
};
-/* twl4030 setup */
-static struct twl4030_setup_data twl4030_setup = {
- .ramp_delay_value = 4,
- .sysclk = 26000,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device omap3evm_snd_devdata = {
- .card = &snd_soc_omap3evm,
- .codec_dev = &soc_codec_dev_twl4030,
- .codec_data = &twl4030_setup,
-};
-
static struct platform_device *omap3evm_snd_device;
static int __init omap3evm_soc_init(void)
{
int ret;
- if (!machine_is_omap3evm()) {
- pr_err("Not OMAP3 EVM!\n");
+ if (!machine_is_omap3evm())
return -ENODEV;
- }
pr_info("OMAP3 EVM SoC init\n");
omap3evm_snd_device = platform_device_alloc("soc-audio", -1);
@@ -124,10 +109,7 @@ static int __init omap3evm_soc_init(void)
return -ENOMEM;
}
- platform_set_drvdata(omap3evm_snd_device, &omap3evm_snd_devdata);
- omap3evm_snd_devdata.dev = &omap3evm_snd_device->dev;
- *(unsigned int *)omap3evm_dai.cpu_dai->private_data = 1;
-
+ platform_set_drvdata(omap3evm_snd_device, &snd_soc_omap3evm);
ret = platform_device_add(omap3evm_snd_device);
if (ret)
goto err1;
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index 9eecac135bbb..dbd9d96b5f92 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -31,10 +31,10 @@
#include <sound/soc-dapm.h>
#include <asm/mach-types.h>
+#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
#define OMAP3_PANDORA_DAC_POWER_GPIO 118
#define OMAP3_PANDORA_AMP_POWER_GPIO 14
@@ -47,8 +47,8 @@ static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS;
int ret;
@@ -167,8 +167,9 @@ static const struct snd_soc_dapm_route omap3pandora_in_map[] = {
{"Mic Bias 2", NULL, "Mic (external)"},
};
-static int omap3pandora_out_init(struct snd_soc_codec *codec)
+static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int ret;
/* All TWL4030 output pins are floating */
@@ -194,8 +195,9 @@ static int omap3pandora_out_init(struct snd_soc_codec *codec)
return snd_soc_dapm_sync(codec);
}
-static int omap3pandora_in_init(struct snd_soc_codec *codec)
+static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int ret;
/* Not comnnected */
@@ -224,15 +226,19 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
{
.name = "PCM1773",
.stream_name = "HiFi Out",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.ops = &omap3pandora_ops,
.init = omap3pandora_out_init,
}, {
.name = "TWL4030",
.stream_name = "Line/Mic In",
- .cpu_dai = &omap_mcbsp_dai[1],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.3",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.ops = &omap3pandora_ops,
.init = omap3pandora_in_init,
}
@@ -241,17 +247,10 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
/* SoC card */
static struct snd_soc_card snd_soc_card_omap3pandora = {
.name = "omap3pandora",
- .platform = &omap_soc_platform,
.dai_link = omap3pandora_dai,
.num_links = ARRAY_SIZE(omap3pandora_dai),
};
-/* Audio subsystem */
-static struct snd_soc_device omap3pandora_snd_data = {
- .card = &snd_soc_card_omap3pandora,
- .codec_dev = &soc_codec_dev_twl4030,
-};
-
static struct platform_device *omap3pandora_snd_device;
static int __init omap3pandora_soc_init(void)
@@ -294,10 +293,7 @@ static int __init omap3pandora_soc_init(void)
goto fail1;
}
- platform_set_drvdata(omap3pandora_snd_device, &omap3pandora_snd_data);
- omap3pandora_snd_data.dev = &omap3pandora_snd_device->dev;
- *(unsigned int *)omap_mcbsp_dai[0].private_data = 1; /* McBSP2 */
- *(unsigned int *)omap_mcbsp_dai[1].private_data = 3; /* McBSP4 */
+ platform_set_drvdata(omap3pandora_snd_device, &snd_soc_card_omap3pandora);
ret = platform_device_add(omap3pandora_snd_device);
if (ret) {
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index 498ca2e03519..f0e662556428 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -55,8 +55,8 @@ static int osk_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int err;
/* Set codec DAI configuration */
@@ -113,8 +113,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"MICIN", NULL, "Mic Jack"},
};
-static int osk_tlv320aic23_init(struct snd_soc_codec *codec)
+static int osk_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
/* Add osk5912 specific widgets */
snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
@@ -136,8 +137,10 @@ static int osk_tlv320aic23_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link osk_dai = {
.name = "TLV320AIC23",
.stream_name = "AIC23",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &tlv320aic23_dai,
+ .cpu_dai_name = "omap-mcbsp-dai.0",
+ .codec_dai_name = "tlv320aic23-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "tlv320aic23-codec",
.init = osk_tlv320aic23_init,
.ops = &osk_ops,
};
@@ -145,17 +148,10 @@ static struct snd_soc_dai_link osk_dai = {
/* Audio machine driver */
static struct snd_soc_card snd_soc_card_osk = {
.name = "OSK5912",
- .platform = &omap_soc_platform,
.dai_link = &osk_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device osk_snd_devdata = {
- .card = &snd_soc_card_osk,
- .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
static struct platform_device *osk_snd_device;
static int __init osk_soc_init(void)
@@ -171,9 +167,7 @@ static int __init osk_soc_init(void)
if (!osk_snd_device)
return -ENOMEM;
- platform_set_drvdata(osk_snd_device, &osk_snd_devdata);
- osk_snd_devdata.dev = &osk_snd_device->dev;
- *(unsigned int *)osk_dai.cpu_dai->private_data = 0; /* McBSP1 */
+ platform_set_drvdata(osk_snd_device, &snd_soc_card_osk);
err = platform_device_add(osk_snd_device);
if (err)
goto err1;
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
index c25f5276ad6f..e95a607937de 100644
--- a/sound/soc/omap/overo.c
+++ b/sound/soc/omap/overo.c
@@ -33,14 +33,13 @@
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
static int overo_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -82,25 +81,20 @@ static struct snd_soc_ops overo_ops = {
static struct snd_soc_dai_link overo_dai = {
.name = "TWL4030",
.stream_name = "TWL4030",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.ops = &overo_ops,
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_card_overo = {
.name = "overo",
- .platform = &omap_soc_platform,
.dai_link = &overo_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device overo_snd_devdata = {
- .card = &snd_soc_card_overo,
- .codec_dev = &soc_codec_dev_twl4030,
-};
-
static struct platform_device *overo_snd_device;
static int __init overo_soc_init(void)
@@ -119,9 +113,7 @@ static int __init overo_soc_init(void)
return -ENOMEM;
}
- platform_set_drvdata(overo_snd_device, &overo_snd_devdata);
- overo_snd_devdata.dev = &overo_snd_device->dev;
- *(unsigned int *)overo_dai.cpu_dai->private_data = 1; /* McBSP2 */
+ platform_set_drvdata(overo_snd_device, &snd_soc_card_overo);
ret = platform_device_add(overo_snd_device);
if (ret)
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 88052d29617f..04b5723bf89b 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -31,6 +31,7 @@
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include <plat/mcbsp.h>
#include <asm/mach-types.h>
@@ -76,7 +77,7 @@ static int rx51_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
@@ -89,8 +90,8 @@ static int rx51_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int err;
/* Set codec DAI configuration */
@@ -145,9 +146,9 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
if (SND_SOC_DAPM_EVENT_ON(event))
- gpio_set_value(RX51_SPEAKER_AMP_TWL_GPIO, 1);
+ gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 1);
else
- gpio_set_value(RX51_SPEAKER_AMP_TWL_GPIO, 0);
+ gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 0);
return 0;
}
@@ -240,9 +241,9 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = {
rx51_get_jack, rx51_set_jack),
};
-static int rx51_aic34_init(struct snd_soc_codec *codec)
+static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_card *card = codec->socdev->card;
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* Set up NC codec pins */
@@ -266,7 +267,7 @@ static int rx51_aic34_init(struct snd_soc_codec *codec)
snd_soc_dapm_sync(codec);
/* AV jack detection */
- err = snd_soc_jack_new(card, "AV Jack",
+ err = snd_soc_jack_new(codec, "AV Jack",
SND_JACK_VIDEOOUT, &rx51_av_jack);
if (err)
return err;
@@ -282,32 +283,20 @@ static struct snd_soc_dai_link rx51_dai[] = {
{
.name = "TLV320AIC34",
.stream_name = "AIC34",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &aic3x_dai,
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "tlv320aic3x-codec.2-0018",
.init = rx51_aic34_init,
.ops = &rx51_ops,
},
};
-/* Audio private data */
-static struct aic3x_setup_data rx51_aic34_setup = {
- .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
- .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
-};
-
/* Audio card */
static struct snd_soc_card rx51_sound_card = {
.name = "RX-51",
.dai_link = rx51_dai,
.num_links = ARRAY_SIZE(rx51_dai),
- .platform = &omap_soc_platform,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device rx51_snd_devdata = {
- .card = &rx51_sound_card,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &rx51_aic34_setup,
};
static struct platform_device *rx51_snd_device;
@@ -330,9 +319,7 @@ static int __init rx51_soc_init(void)
goto err1;
}
- platform_set_drvdata(rx51_snd_device, &rx51_snd_devdata);
- rx51_snd_devdata.dev = &rx51_snd_device->dev;
- *(unsigned int *)rx51_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
+ platform_set_drvdata(rx51_snd_device, &rx51_sound_card);
err = platform_device_add(rx51_snd_device);
if (err)
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 3c85c0f92823..07fbcf7d2411 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -36,9 +36,11 @@
#include <mach/gpio.h>
#include <plat/mcbsp.h>
+/* Register descriptions for twl4030 codec part */
+#include <linux/mfd/twl4030-codec.h>
+
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
/* TWL4030 PMBR1 Register */
#define TWL4030_INTBR_PMBR1 0x0D
@@ -51,8 +53,8 @@ static int sdp3430_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -94,8 +96,8 @@ static int sdp3430_hw_voice_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -186,8 +188,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Headset Stereophone", NULL, "HSOR"},
};
-static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
+static int sdp3430_twl4030_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int ret;
/* Add SDP3430 specific widgets */
@@ -225,7 +228,7 @@ static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
return ret;
/* Headset jack detection */
- ret = snd_soc_jack_new(&snd_soc_sdp3430, "Headset Jack",
+ ret = snd_soc_jack_new(codec, "Headset Jack",
SND_JACK_HEADSET, &hs_jack);
if (ret)
return ret;
@@ -241,14 +244,15 @@ static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
return ret;
}
-static int sdp3430_twl4030_voice_init(struct snd_soc_codec *codec)
+static int sdp3430_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
unsigned short reg;
/* Enable voice interface */
- reg = codec->read(codec, TWL4030_REG_VOICE_IF);
+ reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF);
reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
- codec->write(codec, TWL4030_REG_VOICE_IF, reg);
+ codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg);
return 0;
}
@@ -259,16 +263,20 @@ static struct snd_soc_dai_link sdp3430_dai[] = {
{
.name = "TWL4030 I2S",
.stream_name = "TWL4030 Audio",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.init = sdp3430_twl4030_init,
.ops = &sdp3430_ops,
},
{
.name = "TWL4030 PCM",
.stream_name = "TWL4030 Voice",
- .cpu_dai = &omap_mcbsp_dai[1],
- .codec_dai = &twl4030_dai[TWL4030_DAI_VOICE],
+ .cpu_dai_name = "omap-mcbsp-dai.2",
+ .codec_dai_name = "twl4030-voice",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.init = sdp3430_twl4030_voice_init,
.ops = &sdp3430_voice_ops,
},
@@ -277,25 +285,10 @@ static struct snd_soc_dai_link sdp3430_dai[] = {
/* Audio machine driver */
static struct snd_soc_card snd_soc_sdp3430 = {
.name = "SDP3430",
- .platform = &omap_soc_platform,
.dai_link = sdp3430_dai,
.num_links = ARRAY_SIZE(sdp3430_dai),
};
-/* twl4030 setup */
-static struct twl4030_setup_data twl4030_setup = {
- .ramp_delay_value = 3,
- .sysclk = 26000,
- .hs_extmute = 1,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device sdp3430_snd_devdata = {
- .card = &snd_soc_sdp3430,
- .codec_dev = &soc_codec_dev_twl4030,
- .codec_data = &twl4030_setup,
-};
-
static struct platform_device *sdp3430_snd_device;
static int __init sdp3430_soc_init(void)
@@ -303,10 +296,8 @@ static int __init sdp3430_soc_init(void)
int ret;
u8 pin_mux;
- if (!machine_is_omap_3430sdp()) {
- pr_debug("Not SDP3430!\n");
+ if (!machine_is_omap_3430sdp())
return -ENODEV;
- }
printk(KERN_INFO "SDP3430 SoC init\n");
sdp3430_snd_device = platform_device_alloc("soc-audio", -1);
@@ -315,10 +306,7 @@ static int __init sdp3430_soc_init(void)
return -ENOMEM;
}
- platform_set_drvdata(sdp3430_snd_device, &sdp3430_snd_devdata);
- sdp3430_snd_devdata.dev = &sdp3430_snd_device->dev;
- *(unsigned int *)sdp3430_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
- *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
+ platform_set_drvdata(sdp3430_snd_device, &snd_soc_sdp3430);
/* Set TWL4030 GPIO6 as EXTMUTE signal */
twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux,
diff --git a/sound/soc/omap/sdp4430.c b/sound/soc/omap/sdp4430.c
index 4ebbde6b565f..4b4463db6ba0 100644
--- a/sound/soc/omap/sdp4430.c
+++ b/sound/soc/omap/sdp4430.c
@@ -31,7 +31,6 @@
#include <plat/mux.h>
#include "mcpdm.h"
-#include "omap-mcpdm.h"
#include "omap-pcm.h"
#include "../codecs/twl6040.h"
@@ -41,7 +40,7 @@ static int sdp4430_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int clk_id, freq;
int ret;
@@ -60,6 +59,7 @@ static int sdp4430_hw_params(struct snd_pcm_substream *substream,
printk(KERN_ERR "can't set codec system clock\n");
return ret;
}
+ return ret;
}
static struct snd_soc_ops sdp4430_ops = {
@@ -126,8 +126,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Earphone Spk", NULL, "EP"},
};
-static int sdp4430_twl6040_init(struct snd_soc_codec *codec)
+static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int ret;
/* Add SDP4430 specific controls */
@@ -164,8 +165,10 @@ static int sdp4430_twl6040_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link sdp4430_dai = {
.name = "TWL6040",
.stream_name = "TWL6040",
- .cpu_dai = &omap_mcpdm_dai,
- .codec_dai = &twl6040_dai,
+ .cpu_dai_name ="omap-mcpdm-dai",
+ .codec_dai_name = "twl6040-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl6040-codec",
.init = sdp4430_twl6040_init,
.ops = &sdp4430_ops,
};
@@ -173,27 +176,18 @@ static struct snd_soc_dai_link sdp4430_dai = {
/* Audio machine driver */
static struct snd_soc_card snd_soc_sdp4430 = {
.name = "SDP4430",
- .platform = &omap_soc_platform,
.dai_link = &sdp4430_dai,
.num_links = 1,
};
-/* Audio subsystem */
-static struct snd_soc_device sdp4430_snd_devdata = {
- .card = &snd_soc_sdp4430,
- .codec_dev = &soc_codec_dev_twl6040,
-};
-
static struct platform_device *sdp4430_snd_device;
static int __init sdp4430_soc_init(void)
{
int ret;
- if (!machine_is_omap_4430sdp()) {
- pr_debug("Not SDP4430!\n");
+ if (!machine_is_omap_4430sdp())
return -ENODEV;
- }
printk(KERN_INFO "SDP4430 SoC init\n");
sdp4430_snd_device = platform_device_alloc("soc-audio", -1);
@@ -202,8 +196,7 @@ static int __init sdp4430_soc_init(void)
return -ENOMEM;
}
- platform_set_drvdata(sdp4430_snd_device, &sdp4430_snd_devdata);
- sdp4430_snd_devdata.dev = &sdp4430_snd_device->dev;
+ platform_set_drvdata(sdp4430_snd_device, &snd_soc_sdp4430);
ret = platform_device_add(sdp4430_snd_device);
if (ret)
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index 50a94ee76ecc..718031eeac34 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -29,21 +29,23 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
+#include <mach/board-zoom.h>
#include <plat/mcbsp.h>
+/* Register descriptions for twl4030 codec part */
+#include <linux/mfd/twl4030-codec.h>
+
#include "omap-mcbsp.h"
#include "omap-pcm.h"
-#include "../codecs/twl4030.h"
#define ZOOM2_HEADSET_MUX_GPIO (OMAP_MAX_GPIO_LINES + 15)
-#define ZOOM2_HEADSET_EXTMUTE_GPIO 153
static int zoom2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -85,8 +87,8 @@ static int zoom2_hw_voice_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -157,8 +159,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Aux In", NULL, "AUXR"},
};
-static int zoom2_twl4030_init(struct snd_soc_codec *codec)
+static int zoom2_twl4030_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int ret;
/* Add Zoom2 specific widgets */
@@ -192,14 +195,15 @@ static int zoom2_twl4030_init(struct snd_soc_codec *codec)
return ret;
}
-static int zoom2_twl4030_voice_init(struct snd_soc_codec *codec)
+static int zoom2_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
unsigned short reg;
/* Enable voice interface */
- reg = codec->read(codec, TWL4030_REG_VOICE_IF);
+ reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF);
reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
- codec->write(codec, TWL4030_REG_VOICE_IF, reg);
+ codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg);
return 0;
}
@@ -209,16 +213,20 @@ static struct snd_soc_dai_link zoom2_dai[] = {
{
.name = "TWL4030 I2S",
.stream_name = "TWL4030 Audio",
- .cpu_dai = &omap_mcbsp_dai[0],
- .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .codec_dai_name = "twl4030-hifi",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.init = zoom2_twl4030_init,
.ops = &zoom2_ops,
},
{
.name = "TWL4030 PCM",
.stream_name = "TWL4030 Voice",
- .cpu_dai = &omap_mcbsp_dai[1],
- .codec_dai = &twl4030_dai[TWL4030_DAI_VOICE],
+ .cpu_dai_name = "omap-mcbsp-dai.2",
+ .codec_dai_name = "twl4030-voice",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "twl4030-codec",
.init = zoom2_twl4030_voice_init,
.ops = &zoom2_voice_ops,
},
@@ -227,42 +235,18 @@ static struct snd_soc_dai_link zoom2_dai[] = {
/* Audio machine driver */
static struct snd_soc_card snd_soc_zoom2 = {
.name = "Zoom2",
- .platform = &omap_soc_platform,
.dai_link = zoom2_dai,
.num_links = ARRAY_SIZE(zoom2_dai),
};
-/* EXTMUTE callback function */
-void zoom2_set_hs_extmute(int mute)
-{
- gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
-}
-
-/* twl4030 setup */
-static struct twl4030_setup_data twl4030_setup = {
- .ramp_delay_value = 3, /* 161 ms */
- .sysclk = 26000,
- .hs_extmute = 1,
- .set_hs_extmute = zoom2_set_hs_extmute,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device zoom2_snd_devdata = {
- .card = &snd_soc_zoom2,
- .codec_dev = &soc_codec_dev_twl4030,
- .codec_data = &twl4030_setup,
-};
-
static struct platform_device *zoom2_snd_device;
static int __init zoom2_soc_init(void)
{
int ret;
- if (!machine_is_omap_zoom2()) {
- pr_debug("Not Zoom2!\n");
+ if (!machine_is_omap_zoom2())
return -ENODEV;
- }
printk(KERN_INFO "Zoom2 SoC init\n");
zoom2_snd_device = platform_device_alloc("soc-audio", -1);
@@ -271,11 +255,7 @@ static int __init zoom2_soc_init(void)
return -ENOMEM;
}
- platform_set_drvdata(zoom2_snd_device, &zoom2_snd_devdata);
- zoom2_snd_devdata.dev = &zoom2_snd_device->dev;
- *(unsigned int *)zoom2_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
- *(unsigned int *)zoom2_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
-
+ platform_set_drvdata(zoom2_snd_device, &snd_soc_zoom2);
ret = platform_device_add(zoom2_snd_device);
if (ret)
goto err1;
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index e30c8325f35e..37f191bbfdd9 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -117,6 +117,24 @@ config SND_PXA2XX_SOC_PALM27X
Say Y if you want to add support for SoC audio on
Palm T|X, T5, E2 or LifeDrive handheld computer.
+config SND_SOC_SAARB
+ tristate "SoC Audio support for Marvell Saarb"
+ depends on SND_PXA2XX_SOC && MACH_SAARB
+ select SND_PXA_SOC_SSP
+ select SND_SOC_88PM860X
+ help
+ Say Y if you want to add support for SoC audio on the
+ Marvell Saarb reference platform.
+
+config SND_SOC_TAVOREVB3
+ tristate "SoC Audio support for Marvell Tavor EVB3"
+ depends on SND_PXA2XX_SOC && MACH_TAVOREVB3
+ select SND_PXA_SOC_SSP
+ select SND_SOC_88PM860X
+ help
+ Say Y if you want to add support for SoC audio on the
+ Marvell Saarb reference platform.
+
config SND_SOC_ZYLONITE
tristate "SoC Audio support for Marvell Zylonite"
depends on SND_PXA2XX_SOC && MACH_ZYLONITE
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index caa03d8f4789..07660165ec8d 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -19,6 +19,8 @@ snd-soc-e800-objs := e800_wm9712.o
snd-soc-spitz-objs := spitz.o
snd-soc-em-x270-objs := em-x270.o
snd-soc-palm27x-objs := palm27x.o
+snd-soc-saarb-objs := saarb.o
+snd-soc-tavorevb3-objs := tavorevb3.o
snd-soc-zylonite-objs := zylonite.o
snd-soc-magician-objs := magician.o
snd-soc-mioa701-objs := mioa701_wm9713.o
@@ -38,6 +40,8 @@ obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
+obj-$(CONFIG_SND_SOC_SAARB) += snd-soc-saarb.o
+obj-$(CONFIG_SND_SOC_TAVOREVB3) += snd-soc-tavorevb3.o
obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index fefe1a57f31a..97e9423615c9 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -30,7 +30,6 @@
#include <mach/audio.h>
#include "../codecs/wm8731.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-i2s.h"
#define CORGI_HP 0
@@ -99,7 +98,7 @@ static void corgi_ext_control(struct snd_soc_codec *codec)
static int corgi_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* check the jack status at stream startup */
corgi_ext_control(codec);
@@ -118,8 +117,8 @@ static int corgi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret = 0;
@@ -150,7 +149,7 @@ static int corgi_hw_params(struct snd_pcm_substream *substream,
return ret;
/* set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk,
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
@@ -272,8 +271,9 @@ static const struct snd_kcontrol_new wm8731_corgi_controls[] = {
/*
* Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
*/
-static int corgi_wm8731_init(struct snd_soc_codec *codec)
+static int corgi_wm8731_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
snd_soc_dapm_nc_pin(codec, "LLINEIN");
@@ -300,8 +300,10 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link corgi_dai = {
.name = "WM8731",
.stream_name = "WM8731",
- .cpu_dai = &pxa_i2s_dai,
- .codec_dai = &wm8731_dai,
+ .cpu_dai_name = "pxa-is2-dai",
+ .codec_dai_name = "wm8731-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm8731-codec-0.001a",
.init = corgi_wm8731_init,
.ops = &corgi_ops,
};
@@ -309,17 +311,10 @@ static struct snd_soc_dai_link corgi_dai = {
/* corgi audio machine driver */
static struct snd_soc_card snd_soc_corgi = {
.name = "Corgi",
- .platform = &pxa2xx_soc_platform,
.dai_link = &corgi_dai,
.num_links = 1,
};
-/* corgi audio subsystem */
-static struct snd_soc_device corgi_snd_devdata = {
- .card = &snd_soc_corgi,
- .codec_dev = &soc_codec_dev_wm8731,
-};
-
static struct platform_device *corgi_snd_device;
static int __init corgi_init(void)
@@ -334,8 +329,7 @@ static int __init corgi_init(void)
if (!corgi_snd_device)
return -ENOMEM;
- platform_set_drvdata(corgi_snd_device, &corgi_snd_devdata);
- corgi_snd_devdata.dev = &corgi_snd_device->dev;
+ platform_set_drvdata(corgi_snd_device, &snd_soc_corgi);
ret = platform_device_add(corgi_snd_device);
if (ret)
diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c
index 7cd2f89d7b10..c82cedb602fd 100644
--- a/sound/soc/pxa/e740_wm9705.c
+++ b/sound/soc/pxa/e740_wm9705.c
@@ -24,7 +24,6 @@
#include <asm/mach-types.h>
#include "../codecs/wm9705.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
@@ -90,8 +89,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Mic Amp", NULL, "Mic (Internal)"},
};
-static int e740_ac97_init(struct snd_soc_codec *codec)
+static int e740_ac97_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_nc_pin(codec, "HPOUTL");
snd_soc_dapm_nc_pin(codec, "HPOUTR");
snd_soc_dapm_nc_pin(codec, "PHONE");
@@ -116,30 +117,28 @@ static struct snd_soc_dai_link e740_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI],
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_dai_name = "wm9705-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9705-codec",
.init = e740_ac97_init,
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX],
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_dai_name = "wm9705-aux",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9705-codec",
},
};
static struct snd_soc_card e740 = {
.name = "Toshiba e740",
- .platform = &pxa2xx_soc_platform,
.dai_link = e740_dai,
.num_links = ARRAY_SIZE(e740_dai),
};
-static struct snd_soc_device e740_snd_devdata = {
- .card = &e740,
- .codec_dev = &soc_codec_dev_wm9705,
-};
-
static struct platform_device *e740_snd_device;
static int __init e740_init(void)
@@ -178,8 +177,7 @@ static int __init e740_init(void)
goto free_apwr_gpio;
}
- platform_set_drvdata(e740_snd_device, &e740_snd_devdata);
- e740_snd_devdata.dev = &e740_snd_device->dev;
+ platform_set_drvdata(e740_snd_device, &e740);
ret = platform_device_add(e740_snd_device);
if (!ret)
@@ -200,6 +198,9 @@ free_mic_amp_gpio:
static void __exit e740_exit(void)
{
platform_device_unregister(e740_snd_device);
+ gpio_free(GPIO_E740_WM9705_nAVDD2);
+ gpio_free(GPIO_E740_AMP_ON);
+ gpio_free(GPIO_E740_MIC_ON);
}
module_init(e740_init);
diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c
index 8dceccc5e059..4c143803a75e 100644
--- a/sound/soc/pxa/e750_wm9705.c
+++ b/sound/soc/pxa/e750_wm9705.c
@@ -24,7 +24,6 @@
#include <asm/mach-types.h>
#include "../codecs/wm9705.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
static int e750_spk_amp_event(struct snd_soc_dapm_widget *w,
@@ -72,8 +71,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"MIC1", NULL, "Mic (Internal)"},
};
-static int e750_ac97_init(struct snd_soc_codec *codec)
+static int e750_ac97_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_nc_pin(codec, "LOUT");
snd_soc_dapm_nc_pin(codec, "ROUT");
snd_soc_dapm_nc_pin(codec, "PHONE");
@@ -98,31 +99,29 @@ static struct snd_soc_dai_link e750_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI],
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_dai_name = "wm9705-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9705-codec",
.init = e750_ac97_init,
/* use ops to check startup state */
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX],
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_dai_name ="wm9705-aux",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9705-codec",
},
};
static struct snd_soc_card e750 = {
.name = "Toshiba e750",
- .platform = &pxa2xx_soc_platform,
.dai_link = e750_dai,
.num_links = ARRAY_SIZE(e750_dai),
};
-static struct snd_soc_device e750_snd_devdata = {
- .card = &e750,
- .codec_dev = &soc_codec_dev_wm9705,
-};
-
static struct platform_device *e750_snd_device;
static int __init e750_init(void)
@@ -154,8 +153,7 @@ static int __init e750_init(void)
goto free_spk_amp_gpio;
}
- platform_set_drvdata(e750_snd_device, &e750_snd_devdata);
- e750_snd_devdata.dev = &e750_snd_device->dev;
+ platform_set_drvdata(e750_snd_device, &e750);
ret = platform_device_add(e750_snd_device);
if (!ret)
diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c
index bc019cdce429..d42e5fe832c5 100644
--- a/sound/soc/pxa/e800_wm9712.c
+++ b/sound/soc/pxa/e800_wm9712.c
@@ -23,7 +23,6 @@
#include <mach/eseries-gpio.h>
#include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
static int e800_spk_amp_event(struct snd_soc_dapm_widget *w,
@@ -73,8 +72,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"MIC2", NULL, "Mic (Internal2)"},
};
-static int e800_ac97_init(struct snd_soc_codec *codec)
+static int e800_ac97_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_new_controls(codec, e800_dapm_widgets,
ARRAY_SIZE(e800_dapm_widgets));
@@ -88,30 +89,28 @@ static struct snd_soc_dai_link e800_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_dai_name = "wm9712-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9712-codec",
.init = e800_ac97_init,
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_dai_name ="wm9712-aux",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9712-codec",
},
};
static struct snd_soc_card e800 = {
.name = "Toshiba e800",
- .platform = &pxa2xx_soc_platform,
.dai_link = e800_dai,
.num_links = ARRAY_SIZE(e800_dai),
};
-static struct snd_soc_device e800_snd_devdata = {
- .card = &e800,
- .codec_dev = &soc_codec_dev_wm9712,
-};
-
static struct platform_device *e800_snd_device;
static int __init e800_init(void)
@@ -141,8 +140,7 @@ static int __init e800_init(void)
if (!e800_snd_device)
return -ENOMEM;
- platform_set_drvdata(e800_snd_device, &e800_snd_devdata);
- e800_snd_devdata.dev = &e800_snd_device->dev;
+ platform_set_drvdata(e800_snd_device, &e800);
ret = platform_device_add(e800_snd_device);
if (!ret)
diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c
index f4756e4025fd..eadf9d351a04 100644
--- a/sound/soc/pxa/em-x270.c
+++ b/sound/soc/pxa/em-x270.c
@@ -32,36 +32,33 @@
#include <mach/audio.h>
#include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
static struct snd_soc_dai_link em_x270_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_dai_name = "wm9712-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9712-codec",
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_dai_name ="wm9712-aux",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9712-codec",
},
};
static struct snd_soc_card em_x270 = {
.name = "EM-X270",
- .platform = &pxa2xx_soc_platform,
.dai_link = em_x270_dai,
.num_links = ARRAY_SIZE(em_x270_dai),
};
-static struct snd_soc_device em_x270_snd_devdata = {
- .card = &em_x270,
- .codec_dev = &soc_codec_dev_wm9712,
-};
-
static struct platform_device *em_x270_snd_device;
static int __init em_x270_init(void)
@@ -76,8 +73,7 @@ static int __init em_x270_init(void)
if (!em_x270_snd_device)
return -ENOMEM;
- platform_set_drvdata(em_x270_snd_device, &em_x270_snd_devdata);
- em_x270_snd_devdata.dev = &em_x270_snd_device->dev;
+ platform_set_drvdata(em_x270_snd_device, &em_x270);
ret = platform_device_add(em_x270_snd_device);
if (ret)
diff --git a/sound/soc/pxa/imote2.c b/sound/soc/pxa/imote2.c
index 405587a01160..154fc6f23438 100644
--- a/sound/soc/pxa/imote2.c
+++ b/sound/soc/pxa/imote2.c
@@ -6,14 +6,13 @@
#include "../codecs/wm8940.h"
#include "pxa2xx-i2s.h"
-#include "pxa2xx-pcm.h"
static int imote2_asoc_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret;
@@ -64,23 +63,19 @@ static struct snd_soc_ops imote2_asoc_ops = {
static struct snd_soc_dai_link imote2_dai = {
.name = "WM8940",
.stream_name = "WM8940",
- .cpu_dai = &pxa_i2s_dai,
- .codec_dai = &wm8940_dai,
+ .cpu_dai_name = "pxa2xx-i2s",
+ .codec_dai_name = "wm8940-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm8940-codec.0-0034",
.ops = &imote2_asoc_ops,
};
static struct snd_soc_card snd_soc_imote2 = {
.name = "Imote2",
- .platform = &pxa2xx_soc_platform,
.dai_link = &imote2_dai,
.num_links = 1,
};
-static struct snd_soc_device imote2_snd_devdata = {
- .card = &snd_soc_imote2,
- .codec_dev = &soc_codec_dev_wm8940,
-};
-
static struct platform_device *imote2_snd_device;
static int __init imote2_asoc_init(void)
@@ -93,8 +88,7 @@ static int __init imote2_asoc_init(void)
if (!imote2_snd_device)
return -ENOMEM;
- platform_set_drvdata(imote2_snd_device, &imote2_snd_devdata);
- imote2_snd_devdata.dev = &imote2_snd_device->dev;
+ platform_set_drvdata(imote2_snd_device, &snd_soc_imote2);
ret = platform_device_add(imote2_snd_device);
if (ret)
platform_device_put(imote2_snd_device);
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index 4c8d99a8d386..b8207ced4072 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -32,7 +32,6 @@
#include <mach/magician.h>
#include <asm/mach-types.h>
#include "../codecs/uda1380.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-i2s.h"
#include "pxa-ssp.h"
@@ -71,7 +70,7 @@ static void magician_ext_control(struct snd_soc_codec *codec)
static int magician_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* check the jack status at stream startup */
magician_ext_control(codec);
@@ -86,8 +85,8 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int acps, acds, width, rate;
unsigned int div4 = PXA_SSP_CLK_SCDB_4;
int ret = 0;
@@ -227,8 +226,8 @@ static int magician_capture_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0;
/* set codec DAI configuration */
@@ -393,8 +392,9 @@ static const struct snd_kcontrol_new uda1380_magician_controls[] = {
/*
* Logic for a uda1380 as connected on a HTC Magician
*/
-static int magician_uda1380_init(struct snd_soc_codec *codec)
+static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* NC codec pins */
@@ -427,16 +427,20 @@ static struct snd_soc_dai_link magician_dai[] = {
{
.name = "uda1380",
.stream_name = "UDA1380 Playback",
- .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP1],
- .codec_dai = &uda1380_dai[UDA1380_DAI_PLAYBACK],
+ .cpu_dai_name = "pxa-ssp-dai.0",
+ .codec_dai_name = "uda1380-hifi-playback",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "uda1380-codec.0-0018",
.init = magician_uda1380_init,
.ops = &magician_playback_ops,
},
{
.name = "uda1380",
.stream_name = "UDA1380 Capture",
- .cpu_dai = &pxa_i2s_dai,
- .codec_dai = &uda1380_dai[UDA1380_DAI_CAPTURE],
+ .cpu_dai_name = "pxa2xx-i2s",
+ .codec_dai_name = "uda1380-hifi-capture",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "uda1380-codec.0-0018",
.ops = &magician_capture_ops,
}
};
@@ -446,13 +450,7 @@ static struct snd_soc_card snd_soc_card_magician = {
.name = "Magician",
.dai_link = magician_dai,
.num_links = ARRAY_SIZE(magician_dai),
- .platform = &pxa2xx_soc_platform,
-};
-/* magician audio subsystem */
-static struct snd_soc_device magician_snd_devdata = {
- .card = &snd_soc_card_magician,
- .codec_dev = &soc_codec_dev_uda1380,
};
static struct platform_device *magician_snd_device;
@@ -514,8 +512,7 @@ static int __init magician_init(void)
goto err_pdev;
}
- platform_set_drvdata(magician_snd_device, &magician_snd_devdata);
- magician_snd_devdata.dev = &magician_snd_device->dev;
+ platform_set_drvdata(magician_snd_device, &snd_soc_card_magician);
ret = platform_device_add(magician_snd_device);
if (ret) {
platform_device_put(magician_snd_device);
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
index 19eda8bbfdaf..f284cc54bc80 100644
--- a/sound/soc/pxa/mioa701_wm9713.c
+++ b/sound/soc/pxa/mioa701_wm9713.c
@@ -54,7 +54,6 @@
#include <sound/initval.h>
#include <sound/ac97_codec.h>
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
#include "../codecs/wm9713.h"
@@ -128,8 +127,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Rear Speaker", NULL, "SPKR"},
};
-static int mioa701_wm9713_init(struct snd_soc_codec *codec)
+static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
unsigned short reg;
/* Add mioa701 specific widgets */
@@ -139,12 +139,12 @@ static int mioa701_wm9713_init(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, ARRAY_AND_SIZE(audio_map));
/* Prepare GPIO8 for rear speaker amplifier */
- reg = codec->read(codec, AC97_GPIO_CFG);
- codec->write(codec, AC97_GPIO_CFG, reg | 0x0100);
+ reg = codec->driver->read(codec, AC97_GPIO_CFG);
+ codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100);
/* Prepare MIC input */
- reg = codec->read(codec, AC97_3D_CONTROL);
- codec->write(codec, AC97_3D_CONTROL, reg | 0xc000);
+ reg = codec->driver->read(codec, AC97_3D_CONTROL);
+ codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000);
snd_soc_dapm_enable_pin(codec, "Front Speaker");
snd_soc_dapm_enable_pin(codec, "Rear Speaker");
@@ -162,32 +162,30 @@ static struct snd_soc_dai_link mioa701_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_dai_name = "wm9713-hifi",
+ .codec_name = "wm9713-codec",
.init = mioa701_wm9713_init,
+ .platform_name = "pxa-pcm-audio",
.ops = &mioa701_ops,
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX],
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_dai_name ="wm9713-aux",
+ .codec_name = "wm9713-codec",
+ .platform_name = "pxa-pcm-audio",
.ops = &mioa701_ops,
},
};
static struct snd_soc_card mioa701 = {
.name = "MioA701",
- .platform = &pxa2xx_soc_platform,
.dai_link = mioa701_dai,
.num_links = ARRAY_SIZE(mioa701_dai),
};
-static struct snd_soc_device mioa701_snd_devdata = {
- .card = &mioa701,
- .codec_dev = &soc_codec_dev_wm9713,
-};
-
static struct platform_device *mioa701_snd_device;
static int mioa701_wm9713_probe(struct platform_device *pdev)
@@ -205,8 +203,7 @@ static int mioa701_wm9713_probe(struct platform_device *pdev)
if (!mioa701_snd_device)
return -ENOMEM;
- platform_set_drvdata(mioa701_snd_device, &mioa701_snd_devdata);
- mioa701_snd_devdata.dev = &mioa701_snd_device->dev;
+ platform_set_drvdata(mioa701_snd_device, &mioa701);
ret = platform_device_add(mioa701_snd_device);
if (!ret)
diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c
index 1f96e3227be5..13f6d485d571 100644
--- a/sound/soc/pxa/palm27x.c
+++ b/sound/soc/pxa/palm27x.c
@@ -29,7 +29,6 @@
#include <mach/palmasoc.h>
#include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
static struct snd_soc_jack hs_jack;
@@ -75,8 +74,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
static struct snd_soc_card palm27x_asoc;
-static int palm27x_ac97_init(struct snd_soc_codec *codec)
+static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* add palm27x specific widgets */
@@ -112,7 +112,7 @@ static int palm27x_ac97_init(struct snd_soc_codec *codec)
return err;
/* Jack detection API stuff */
- err = snd_soc_jack_new(&palm27x_asoc, "Headphone Jack",
+ err = snd_soc_jack_new(codec, "Headphone Jack",
SND_JACK_HEADPHONE, &hs_jack);
if (err)
return err;
@@ -132,30 +132,28 @@ static struct snd_soc_dai_link palm27x_dai[] = {
{
.name = "AC97 HiFi",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_dai_name = "wm9712-hifi",
+ .codec_name = "wm9712-codec",
+ .platform_name = "pxa-pcm-audio",
.init = palm27x_ac97_init,
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_dai_name = "wm9712-aux",
+ .codec_name = "wm9712-codec",
+ .platform_name = "pxa-pcm-audio",
},
};
static struct snd_soc_card palm27x_asoc = {
.name = "Palm/PXA27x",
- .platform = &pxa2xx_soc_platform,
.dai_link = palm27x_dai,
.num_links = ARRAY_SIZE(palm27x_dai),
};
-static struct snd_soc_device palm27x_snd_devdata = {
- .card = &palm27x_asoc,
- .codec_dev = &soc_codec_dev_wm9712,
-};
-
static struct platform_device *palm27x_snd_device;
static int palm27x_asoc_probe(struct platform_device *pdev)
@@ -178,8 +176,7 @@ static int palm27x_asoc_probe(struct platform_device *pdev)
if (!palm27x_snd_device)
return -ENOMEM;
- platform_set_drvdata(palm27x_snd_device, &palm27x_snd_devdata);
- palm27x_snd_devdata.dev = &palm27x_snd_device->dev;
+ platform_set_drvdata(palm27x_snd_device, &palm27x_asoc);
ret = platform_device_add(palm27x_snd_device);
if (ret != 0)
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index c5f36e0eab58..af84ee9c5e11 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -31,7 +31,6 @@
#include <mach/audio.h>
#include "../codecs/wm8731.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-i2s.h"
#define POODLE_HP 1
@@ -76,7 +75,7 @@ static void poodle_ext_control(struct snd_soc_codec *codec)
static int poodle_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* check the jack status at stream startup */
poodle_ext_control(codec);
@@ -97,8 +96,8 @@ static int poodle_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret = 0;
@@ -129,7 +128,7 @@ static int poodle_hw_params(struct snd_pcm_substream *substream,
return ret;
/* set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk,
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
@@ -237,8 +236,9 @@ static const struct snd_kcontrol_new wm8731_poodle_controls[] = {
/*
* Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
*/
-static int poodle_wm8731_init(struct snd_soc_codec *codec)
+static int poodle_wm8731_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
snd_soc_dapm_nc_pin(codec, "LLINEIN");
@@ -266,8 +266,10 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link poodle_dai = {
.name = "WM8731",
.stream_name = "WM8731",
- .cpu_dai = &pxa_i2s_dai,
- .codec_dai = &wm8731_dai,
+ .cpu_dai_name = "pxa2xx-i2s",
+ .codec_dai_name = "wm8731-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm8731-codec.0-001a",
.init = poodle_wm8731_init,
.ops = &poodle_ops,
};
@@ -275,15 +277,9 @@ static struct snd_soc_dai_link poodle_dai = {
/* poodle audio machine driver */
static struct snd_soc_card snd_soc_poodle = {
.name = "Poodle",
- .platform = &pxa2xx_soc_platform,
.dai_link = &poodle_dai,
.num_links = 1,
-};
-
-/* poodle audio subsystem */
-static struct snd_soc_device poodle_snd_devdata = {
- .card = &snd_soc_poodle,
- .codec_dev = &soc_codec_dev_wm8731,
+ .owner = THIS_MODULE,
};
static struct platform_device *poodle_snd_device;
@@ -307,8 +303,7 @@ static int __init poodle_init(void)
if (!poodle_snd_device)
return -ENOMEM;
- platform_set_drvdata(poodle_snd_device, &poodle_snd_devdata);
- poodle_snd_devdata.dev = &poodle_snd_device->dev;
+ platform_set_drvdata(poodle_snd_device, &snd_soc_poodle);
ret = platform_device_add(poodle_snd_device);
if (ret)
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index a1fd23e0e3d0..b439eee462cb 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -35,7 +35,7 @@
#include <mach/audio.h>
#include <plat/ssp.h>
-#include "pxa2xx-pcm.h"
+#include "../../arm/pxa2xx-pcm.h"
#include "pxa-ssp.h"
/*
@@ -108,11 +108,9 @@ pxa_ssp_get_dma_params(struct ssp_device *ssp, int width4, int out)
}
static int pxa_ssp_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
int ret = 0;
@@ -128,11 +126,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
}
static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
if (!cpu_dai->active) {
@@ -148,7 +144,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
if (!cpu_dai->active)
@@ -166,7 +162,7 @@ static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai)
static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
uint32_t sssr = SSSR_ROR | SSSR_TUR | SSSR_BCE;
@@ -230,7 +226,7 @@ static u32 pxa_ssp_get_scr(struct ssp_device *ssp)
static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
int val;
@@ -287,7 +283,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
int val;
@@ -338,7 +334,7 @@ static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
int source, unsigned int freq_in, unsigned int freq_out)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
u32 ssacd = pxa_ssp_read_reg(ssp, SSACD) & ~0x70;
@@ -407,7 +403,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
u32 sscr0;
@@ -442,7 +438,7 @@ static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai,
int tristate)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
u32 sscr1;
@@ -464,11 +460,9 @@ static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai,
static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
- u32 sscr0;
- u32 sscr1;
- u32 sspsp;
+ u32 sscr0, sscr1, sspsp, scfr;
/* check if we need to change anything at all */
if (priv->dai_fmt == fmt)
@@ -483,16 +477,16 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
/* reset port settings */
sscr0 = pxa_ssp_read_reg(ssp, SSCR0) &
- (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
+ ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
sspsp = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
- sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
+ sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR | SSCR1_SCFR;
break;
case SND_SOC_DAIFMT_CBM_CFS:
- sscr1 |= SSCR1_SCLKDIR;
+ sscr1 |= SSCR1_SCLKDIR | SSCR1_SCFR;
break;
case SND_SOC_DAIFMT_CBS_CFS:
break;
@@ -538,6 +532,17 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
pxa_ssp_write_reg(ssp, SSCR1, sscr1);
pxa_ssp_write_reg(ssp, SSPSP, sspsp);
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ scfr = pxa_ssp_read_reg(ssp, SSCR1) | SSCR1_SCFR;
+ pxa_ssp_write_reg(ssp, SSCR1, scfr);
+
+ while (pxa_ssp_read_reg(ssp, SSSR) & SSSR_BSY)
+ cpu_relax();
+ break;
+ }
+
dump_registers(ssp);
/* Since we are configuring the timings for the format by hand
@@ -555,11 +560,9 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
*/
static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
int chn = params_channels(params);
u32 sscr0;
@@ -568,7 +571,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
int ttsa = pxa_ssp_read_reg(ssp, SSTSA) & 0xf;
struct pxa2xx_pcm_dma_params *dma_data;
- dma_data = snd_soc_dai_get_dma_data(dai, substream);
+ dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
/* generate correct DMA params */
kfree(dma_data);
@@ -581,7 +584,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
((chn == 2) && (ttsa != 1)) || (width == 32),
substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
- snd_soc_dai_set_dma_data(dai, substream, dma_data);
+ snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
/* we can only change the settings if the port is not in use */
if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
@@ -589,10 +592,8 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
/* clear selected SSP bits */
sscr0 = pxa_ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS);
- pxa_ssp_write_reg(ssp, SSCR0, sscr0);
/* bit size */
- sscr0 = pxa_ssp_read_reg(ssp, SSCR0);
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
#ifdef CONFIG_PXA3xx
@@ -668,12 +669,10 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
}
static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
int ret = 0;
- struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
int val;
@@ -729,8 +728,7 @@ static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
return ret;
}
-static int pxa_ssp_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int pxa_ssp_probe(struct snd_soc_dai *dai)
{
struct ssp_priv *priv;
int ret;
@@ -746,7 +744,7 @@ static int pxa_ssp_probe(struct platform_device *pdev,
}
priv->dai_fmt = (unsigned int) -1;
- dai->private_data = priv;
+ snd_soc_dai_set_drvdata(dai, priv);
return 0;
@@ -755,11 +753,13 @@ err_priv:
return ret;
}
-static void pxa_ssp_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int pxa_ssp_remove(struct snd_soc_dai *dai)
{
- struct ssp_priv *priv = dai->private_data;
+ struct ssp_priv *priv = snd_soc_dai_get_drvdata(dai);
+
pxa_ssp_free(priv->ssp);
+ kfree(priv);
+ return 0;
}
#define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
@@ -784,10 +784,7 @@ static struct snd_soc_dai_ops pxa_ssp_dai_ops = {
.set_tristate = pxa_ssp_set_dai_tristate,
};
-struct snd_soc_dai pxa_ssp_dai[] = {
- {
- .name = "pxa2xx-ssp1",
- .id = 0,
+static struct snd_soc_dai_driver pxa_ssp_dai = {
.probe = pxa_ssp_probe,
.remove = pxa_ssp_remove,
.suspend = pxa_ssp_suspend,
@@ -805,81 +802,38 @@ struct snd_soc_dai pxa_ssp_dai[] = {
.formats = PXA_SSP_FORMATS,
},
.ops = &pxa_ssp_dai_ops,
+};
+
+static __devinit int asoc_ssp_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &pxa_ssp_dai);
+}
+
+static int __devexit asoc_ssp_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver asoc_ssp_driver = {
+ .driver = {
+ .name = "pxa-ssp-dai",
+ .owner = THIS_MODULE,
},
- { .name = "pxa2xx-ssp2",
- .id = 1,
- .probe = pxa_ssp_probe,
- .remove = pxa_ssp_remove,
- .suspend = pxa_ssp_suspend,
- .resume = pxa_ssp_resume,
- .playback = {
- .channels_min = 1,
- .channels_max = 8,
- .rates = PXA_SSP_RATES,
- .formats = PXA_SSP_FORMATS,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 8,
- .rates = PXA_SSP_RATES,
- .formats = PXA_SSP_FORMATS,
- },
- .ops = &pxa_ssp_dai_ops,
- },
- {
- .name = "pxa2xx-ssp3",
- .id = 2,
- .probe = pxa_ssp_probe,
- .remove = pxa_ssp_remove,
- .suspend = pxa_ssp_suspend,
- .resume = pxa_ssp_resume,
- .playback = {
- .channels_min = 1,
- .channels_max = 8,
- .rates = PXA_SSP_RATES,
- .formats = PXA_SSP_FORMATS,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 8,
- .rates = PXA_SSP_RATES,
- .formats = PXA_SSP_FORMATS,
- },
- .ops = &pxa_ssp_dai_ops,
- },
- {
- .name = "pxa2xx-ssp4",
- .id = 3,
- .probe = pxa_ssp_probe,
- .remove = pxa_ssp_remove,
- .suspend = pxa_ssp_suspend,
- .resume = pxa_ssp_resume,
- .playback = {
- .channels_min = 1,
- .channels_max = 8,
- .rates = PXA_SSP_RATES,
- .formats = PXA_SSP_FORMATS,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 8,
- .rates = PXA_SSP_RATES,
- .formats = PXA_SSP_FORMATS,
- },
- .ops = &pxa_ssp_dai_ops,
- },
+
+ .probe = asoc_ssp_probe,
+ .remove = __devexit_p(asoc_ssp_remove),
};
-EXPORT_SYMBOL_GPL(pxa_ssp_dai);
static int __init pxa_ssp_init(void)
{
- return snd_soc_register_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai));
+ return platform_driver_register(&asoc_ssp_driver);
}
module_init(pxa_ssp_init);
static void __exit pxa_ssp_exit(void)
{
- snd_soc_unregister_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai));
+ platform_driver_unregister(&asoc_ssp_driver);
}
module_exit(pxa_ssp_exit);
diff --git a/sound/soc/pxa/pxa-ssp.h b/sound/soc/pxa/pxa-ssp.h
index 91deadd55675..bc79da221c0d 100644
--- a/sound/soc/pxa/pxa-ssp.h
+++ b/sound/soc/pxa/pxa-ssp.h
@@ -42,6 +42,4 @@
#define PXA_SSP_PLL_OUT 0
-extern struct snd_soc_dai pxa_ssp_dai[4];
-
#endif
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index d314115e3dd7..ac51c6d25c42 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -24,7 +24,6 @@
#include <mach/dma.h>
#include <mach/audio.h>
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
@@ -104,24 +103,21 @@ static int pxa2xx_ac97_resume(struct snd_soc_dai *dai)
#define pxa2xx_ac97_resume NULL
#endif
-static int pxa2xx_ac97_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int pxa2xx_ac97_probe(struct snd_soc_dai *dai)
{
return pxa2xx_ac97_hw_probe(to_platform_device(dai->dev));
}
-static void pxa2xx_ac97_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int pxa2xx_ac97_remove(struct snd_soc_dai *dai)
{
pxa2xx_ac97_hw_remove(to_platform_device(dai->dev));
+ return 0;
}
static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
struct pxa2xx_pcm_dma_params *dma_data;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -136,10 +132,8 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
struct pxa2xx_pcm_dma_params *dma_data;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -154,11 +148,8 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream,
static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
return -ENODEV;
else
@@ -188,10 +179,9 @@ static struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = {
* There is only 1 physical AC97 interface for pxa2xx, but it
* has extra fifo's that can be used for aux DACs and ADCs.
*/
-struct snd_soc_dai pxa_ac97_dai[] = {
+static struct snd_soc_dai_driver pxa_ac97_dai[] = {
{
.name = "pxa2xx-ac97",
- .id = 0,
.ac97_control = 1,
.probe = pxa2xx_ac97_probe,
.remove = pxa2xx_ac97_remove,
@@ -213,7 +203,6 @@ struct snd_soc_dai pxa_ac97_dai[] = {
},
{
.name = "pxa2xx-ac97-aux",
- .id = 1,
.ac97_control = 1,
.playback = {
.stream_name = "AC97 Aux Playback",
@@ -231,7 +220,6 @@ struct snd_soc_dai pxa_ac97_dai[] = {
},
{
.name = "pxa2xx-ac97-mic",
- .id = 2,
.ac97_control = 1,
.capture = {
.stream_name = "AC97 Mic Capture",
@@ -243,36 +231,26 @@ struct snd_soc_dai pxa_ac97_dai[] = {
},
};
-EXPORT_SYMBOL_GPL(pxa_ac97_dai);
EXPORT_SYMBOL_GPL(soc_ac97_ops);
-static int __devinit pxa2xx_ac97_dev_probe(struct platform_device *pdev)
+static __devinit int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
{
- int i;
- pxa2xx_audio_ops_t *pdata = pdev->dev.platform_data;
-
- if (pdev->id >= 0) {
+ if (pdev->id != -1) {
dev_err(&pdev->dev, "PXA2xx has only one AC97 port.\n");
return -ENXIO;
}
- for (i = 0; i < ARRAY_SIZE(pxa_ac97_dai); i++) {
- pxa_ac97_dai[i].dev = &pdev->dev;
- if (pdata && pdata->codec_pdata[0])
- pxa_ac97_dai[i].ac97_pdata = pdata->codec_pdata[0];
- }
-
/* Punt most of the init to the SoC probe; we may need the machine
* driver to do interesting things with the clocking to get us up
* and running.
*/
- return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
+ return snd_soc_register_dais(&pdev->dev, pxa_ac97_dai,
+ ARRAY_SIZE(pxa_ac97_dai));
}
static int __devexit pxa2xx_ac97_dev_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
-
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(pxa_ac97_dai));
return 0;
}
diff --git a/sound/soc/pxa/pxa2xx-ac97.h b/sound/soc/pxa/pxa2xx-ac97.h
index e390de8edcd4..eda891e6f31b 100644
--- a/sound/soc/pxa/pxa2xx-ac97.h
+++ b/sound/soc/pxa/pxa2xx-ac97.h
@@ -14,8 +14,6 @@
#define PXA2XX_DAI_AC97_AUX 1
#define PXA2XX_DAI_AC97_MIC 2
-extern struct snd_soc_dai pxa_ac97_dai[3];
-
/* platform data */
extern struct snd_ac97_bus_ops pxa2xx_ac97_ops;
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index c1a5275721e4..11be5952a506 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -27,7 +27,6 @@
#include <mach/dma.h>
#include <mach/audio.h>
-#include "pxa2xx-pcm.h"
#include "pxa2xx-i2s.h"
/*
@@ -80,6 +79,7 @@ struct pxa_i2s_port {
};
static struct pxa_i2s_port pxa_i2s;
static struct clk *clk_i2s;
+static int clk_ena = 0;
static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
.name = "I2S PCM Stereo out",
@@ -101,7 +101,7 @@ static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
if (IS_ERR(clk_i2s))
return PTR_ERR(clk_i2s);
@@ -162,13 +162,11 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
struct pxa2xx_pcm_dma_params *dma_data;
BUG_ON(IS_ERR(clk_i2s));
clk_enable(clk_i2s);
- dai->private_data = dai;
+ clk_ena = 1;
pxa_i2s_wait();
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -176,7 +174,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
else
dma_data = &pxa2xx_i2s_pcm_stereo_in;
- snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+ snd_soc_dai_set_dma_data(dai, substream, dma_data);
/* is port used by another stream */
if (!(SACR0 & SACR0_ENB)) {
@@ -259,9 +257,9 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) {
SACR0 &= ~SACR0_ENB;
pxa_i2s_wait();
- if (dai->private_data != NULL) {
+ if (clk_ena) {
clk_disable(clk_i2s);
- dai->private_data = NULL;
+ clk_ena = 0;
}
}
}
@@ -300,6 +298,35 @@ static int pxa2xx_i2s_resume(struct snd_soc_dai *dai)
#define pxa2xx_i2s_resume NULL
#endif
+static int pxa2xx_i2s_probe(struct snd_soc_dai *dai)
+{
+ clk_i2s = clk_get(dai->dev, "I2SCLK");
+ if (IS_ERR(clk_i2s))
+ return PTR_ERR(clk_i2s);
+
+ /*
+ * PXA Developer's Manual:
+ * If SACR0[ENB] is toggled in the middle of a normal operation,
+ * the SACR0[RST] bit must also be set and cleared to reset all
+ * I2S controller registers.
+ */
+ SACR0 = SACR0_RST;
+ SACR0 = 0;
+ /* Make sure RPL and REC are disabled */
+ SACR1 = SACR1_DRPL | SACR1_DREC;
+ /* Along with FIFO servicing */
+ SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
+
+ return 0;
+}
+
+static int pxa2xx_i2s_remove(struct snd_soc_dai *dai)
+{
+ clk_put(clk_i2s);
+ clk_i2s = ERR_PTR(-ENOENT);
+ return 0;
+}
+
#define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
@@ -313,9 +340,9 @@ static struct snd_soc_dai_ops pxa_i2s_dai_ops = {
.set_sysclk = pxa2xx_i2s_set_dai_sysclk,
};
-struct snd_soc_dai pxa_i2s_dai = {
- .name = "pxa2xx-i2s",
- .id = 0,
+static struct snd_soc_dai_driver pxa_i2s_dai = {
+ .probe = pxa2xx_i2s_probe,
+ .remove = pxa2xx_i2s_remove,
.suspend = pxa2xx_i2s_suspend,
.resume = pxa2xx_i2s_resume,
.playback = {
@@ -332,49 +359,20 @@ struct snd_soc_dai pxa_i2s_dai = {
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(pxa_i2s_dai);
-
-static int pxa2xx_i2s_probe(struct platform_device *dev)
+static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
{
- int ret;
-
- clk_i2s = clk_get(&dev->dev, "I2SCLK");
- if (IS_ERR(clk_i2s))
- return PTR_ERR(clk_i2s);
-
- pxa_i2s_dai.dev = &dev->dev;
- pxa_i2s_dai.private_data = NULL;
- ret = snd_soc_register_dai(&pxa_i2s_dai);
- if (ret != 0)
- clk_put(clk_i2s);
-
- /*
- * PXA Developer's Manual:
- * If SACR0[ENB] is toggled in the middle of a normal operation,
- * the SACR0[RST] bit must also be set and cleared to reset all
- * I2S controller registers.
- */
- SACR0 = SACR0_RST;
- SACR0 = 0;
- /* Make sure RPL and REC are disabled */
- SACR1 = SACR1_DRPL | SACR1_DREC;
- /* Along with FIFO servicing */
- SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
-
- return ret;
+ return snd_soc_register_dai(&pdev->dev, &pxa_i2s_dai);
}
-static int __devexit pxa2xx_i2s_remove(struct platform_device *dev)
+static int __devexit pxa2xx_i2s_drv_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&pxa_i2s_dai);
- clk_put(clk_i2s);
- clk_i2s = ERR_PTR(-ENOENT);
+ snd_soc_unregister_dai(&pdev->dev);
return 0;
}
static struct platform_driver pxa2xx_i2s_driver = {
- .probe = pxa2xx_i2s_probe,
- .remove = __devexit_p(pxa2xx_i2s_remove),
+ .probe = pxa2xx_i2s_drv_probe,
+ .remove = __devexit_p(pxa2xx_i2s_drv_remove),
.driver = {
.name = "pxa2xx-i2s",
@@ -400,3 +398,4 @@ module_exit(pxa2xx_i2s_exit);
MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-i2s");
diff --git a/sound/soc/pxa/pxa2xx-i2s.h b/sound/soc/pxa/pxa2xx-i2s.h
index e2def441153e..070f3c6059fe 100644
--- a/sound/soc/pxa/pxa2xx-i2s.h
+++ b/sound/soc/pxa/pxa2xx-i2s.h
@@ -15,6 +15,4 @@
/* I2S clock */
#define PXA2XX_I2S_SYSCLK 0
-extern struct snd_soc_dai pxa_i2s_dai;
-
#endif
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index adc7e6f15f93..02fb66416ddc 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -16,7 +16,6 @@
#include <sound/soc.h>
#include <sound/pxa2xx-lib.h>
-#include "pxa2xx-pcm.h"
#include "../../arm/pxa2xx-pcm.h"
static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
@@ -28,7 +27,7 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
struct pxa2xx_pcm_dma_params *dma;
int ret;
- dma = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
/* return if this is a bufferless transfer e.g.
* codec <--> BT codec or GSM modem -- lg FIXME */
@@ -95,14 +94,14 @@ static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -112,25 +111,44 @@ static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
return ret;
}
-struct snd_soc_platform pxa2xx_soc_platform = {
- .name = "pxa2xx-audio",
- .pcm_ops = &pxa2xx_pcm_ops,
+static struct snd_soc_platform_driver pxa2xx_soc_platform = {
+ .ops = &pxa2xx_pcm_ops,
.pcm_new = pxa2xx_soc_pcm_new,
.pcm_free = pxa2xx_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(pxa2xx_soc_platform);
-static int __init pxa2xx_soc_platform_init(void)
+static int __devinit pxa2xx_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&pxa2xx_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &pxa2xx_soc_platform);
}
-module_init(pxa2xx_soc_platform_init);
-static void __exit pxa2xx_soc_platform_exit(void)
+static int __devexit pxa2xx_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&pxa2xx_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver pxa_pcm_driver = {
+ .driver = {
+ .name = "pxa-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = pxa2xx_soc_platform_probe,
+ .remove = __devexit_p(pxa2xx_soc_platform_remove),
+};
+
+static int __init snd_pxa_pcm_init(void)
+{
+ return platform_driver_register(&pxa_pcm_driver);
+}
+module_init(snd_pxa_pcm_init);
+
+static void __exit snd_pxa_pcm_exit(void)
+{
+ platform_driver_unregister(&pxa_pcm_driver);
}
-module_exit(pxa2xx_soc_platform_exit);
+module_exit(snd_pxa_pcm_exit);
MODULE_AUTHOR("Nicolas Pitre");
MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
diff --git a/sound/soc/pxa/pxa2xx-pcm.h b/sound/soc/pxa/pxa2xx-pcm.h
deleted file mode 100644
index 60c3b20aeeb4..000000000000
--- a/sound/soc/pxa/pxa2xx-pcm.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * linux/sound/arm/pxa2xx-pcm.h -- ALSA PCM interface for the Intel PXA2xx chip
- *
- * Author: Nicolas Pitre
- * Created: Nov 30, 2004
- * Copyright: MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _PXA2XX_PCM_H
-#define _PXA2XX_PCM_H
-
-/* platform data */
-extern struct snd_soc_platform pxa2xx_soc_platform;
-
-#endif
diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c
index 7e3f41696c41..2cda82bc5d2e 100644
--- a/sound/soc/pxa/raumfeld.c
+++ b/sound/soc/pxa/raumfeld.c
@@ -26,9 +26,6 @@
#include <asm/mach-types.h>
-#include "../codecs/cs4270.h"
-#include "../codecs/ak4104.h"
-#include "pxa2xx-pcm.h"
#include "pxa-ssp.h"
#define GPIO_SPDIF_RESET (38)
@@ -71,7 +68,7 @@ static void raumfeld_enable_audio(bool en)
static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
/* set freq to 0 to enable all possible codec sample rates */
return snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
@@ -80,7 +77,7 @@ static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
static void raumfeld_cs4270_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
/* set freq to 0 to enable all possible codec sample rates */
snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
@@ -90,8 +87,8 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int fmt, clk = 0;
int ret = 0;
@@ -167,32 +164,14 @@ static int raumfeld_line_resume(struct platform_device *pdev)
return 0;
}
-static struct snd_soc_dai_link raumfeld_line_dai = {
- .name = "CS4270",
- .stream_name = "CS4270",
- .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP1],
- .codec_dai = &cs4270_dai,
- .ops = &raumfeld_cs4270_ops,
-};
-
-static struct snd_soc_card snd_soc_line_raumfeld = {
- .name = "Raumfeld analog",
- .platform = &pxa2xx_soc_platform,
- .dai_link = &raumfeld_line_dai,
- .suspend_post = raumfeld_line_suspend,
- .resume_pre = raumfeld_line_resume,
- .num_links = 1,
-};
-
-
/* AK4104 */
static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int fmt, ret = 0, clk = 0;
switch (params_rate(params)) {
@@ -247,34 +226,35 @@ static struct snd_soc_ops raumfeld_ak4104_ops = {
.hw_params = raumfeld_ak4104_hw_params,
};
-static struct snd_soc_dai_link raumfeld_spdif_dai = {
+static struct snd_soc_dai_link raumfeld_dai[] = {
+{
.name = "ak4104",
.stream_name = "Playback",
- .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP2],
- .codec_dai = &ak4104_dai,
+ .cpu_dai_name = "pxa-ssp-dai.1",
+ .codec_dai_name = "ak4104-hifi",
+ .platform_name = "pxa-pcm-audio",
.ops = &raumfeld_ak4104_ops,
-};
-
-static struct snd_soc_card snd_soc_spdif_raumfeld = {
- .name = "Raumfeld S/PDIF",
- .platform = &pxa2xx_soc_platform,
- .dai_link = &raumfeld_spdif_dai,
- .num_links = 1
-};
-
-/* raumfeld_audio audio subsystem */
-static struct snd_soc_device raumfeld_line_devdata = {
- .card = &snd_soc_line_raumfeld,
- .codec_dev = &soc_codec_device_cs4270,
-};
+ .codec_name = "ak4104-codec.0",
+},
+{
+ .name = "CS4270",
+ .stream_name = "CS4270",
+ .cpu_dai_name = "pxa-ssp-dai.0",
+ .platform_name = "pxa-pcm-audio",
+ .codec_dai_name = "cs4270-hifi",
+ .codec_name = "cs4270-codec.0-0048",
+ .ops = &raumfeld_cs4270_ops,
+},};
-static struct snd_soc_device raumfeld_spdif_devdata = {
- .card = &snd_soc_spdif_raumfeld,
- .codec_dev = &soc_codec_device_ak4104,
+static struct snd_soc_card snd_soc_raumfeld = {
+ .name = "Raumfeld",
+ .dai_link = raumfeld_dai,
+ .suspend_post = raumfeld_line_suspend,
+ .resume_pre = raumfeld_line_resume,
+ .num_links = ARRAY_SIZE(raumfeld_dai),
};
-static struct platform_device *raumfeld_audio_line_device;
-static struct platform_device *raumfeld_audio_spdif_device;
+static struct platform_device *raumfeld_audio_device;
static int __init raumfeld_audio_init(void)
{
@@ -292,38 +272,19 @@ static int __init raumfeld_audio_init(void)
set_max9485_clk(MAX9485_MCLK_FREQ_122880);
- /* LINE */
- raumfeld_audio_line_device = platform_device_alloc("soc-audio", 0);
- if (!raumfeld_audio_line_device)
+ /* Register LINE and SPDIF */
+ raumfeld_audio_device = platform_device_alloc("soc-audio", 0);
+ if (!raumfeld_audio_device)
return -ENOMEM;
- platform_set_drvdata(raumfeld_audio_line_device,
- &raumfeld_line_devdata);
- raumfeld_line_devdata.dev = &raumfeld_audio_line_device->dev;
- ret = platform_device_add(raumfeld_audio_line_device);
- if (ret)
- platform_device_put(raumfeld_audio_line_device);
+ platform_set_drvdata(raumfeld_audio_device,
+ &snd_soc_raumfeld);
+ ret = platform_device_add(raumfeld_audio_device);
/* no S/PDIF on Speakers */
if (machine_is_raumfeld_speaker())
return ret;
- /* S/PDIF */
- raumfeld_audio_spdif_device = platform_device_alloc("soc-audio", 1);
- if (!raumfeld_audio_spdif_device) {
- platform_device_put(raumfeld_audio_line_device);
- return -ENOMEM;
- }
-
- platform_set_drvdata(raumfeld_audio_spdif_device,
- &raumfeld_spdif_devdata);
- raumfeld_spdif_devdata.dev = &raumfeld_audio_spdif_device->dev;
- ret = platform_device_add(raumfeld_audio_spdif_device);
- if (ret) {
- platform_device_put(raumfeld_audio_line_device);
- platform_device_put(raumfeld_audio_spdif_device);
- }
-
raumfeld_enable_audio(true);
return ret;
@@ -333,10 +294,7 @@ static void __exit raumfeld_audio_exit(void)
{
raumfeld_enable_audio(false);
- platform_device_unregister(raumfeld_audio_line_device);
-
- if (machine_is_raumfeld_connector())
- platform_device_unregister(raumfeld_audio_spdif_device);
+ platform_device_unregister(raumfeld_audio_device);
i2c_unregister_device(max9486_client);
diff --git a/sound/soc/pxa/saarb.c b/sound/soc/pxa/saarb.c
new file mode 100644
index 000000000000..d63cb474b4e1
--- /dev/null
+++ b/sound/soc/pxa/saarb.c
@@ -0,0 +1,200 @@
+/*
+ * saarb.c -- SoC audio for saarb
+ *
+ * Copyright (C) 2010 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/88pm860x-codec.h"
+#include "pxa-ssp.h"
+
+static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd);
+
+static struct platform_device *saarb_snd_device;
+
+static struct snd_soc_jack hs_jack, mic_jack;
+
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+ { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, },
+};
+
+static struct snd_soc_jack_pin mic_jack_pins[] = {
+ { .pin = "Headset Mic 2", .mask = SND_JACK_MICROPHONE, },
+};
+
+/* saarb machine dapm widgets */
+static const struct snd_soc_dapm_widget saarb_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Stereophone", NULL),
+ SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
+ SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
+ SND_SOC_DAPM_SPK("Ext Speaker", NULL),
+ SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
+};
+
+/* saarb machine audio map */
+static const struct snd_soc_dapm_route audio_map[] = {
+ {"Headset Stereophone", NULL, "HS1"},
+ {"Headset Stereophone", NULL, "HS2"},
+
+ {"Ext Speaker", NULL, "LSP"},
+ {"Ext Speaker", NULL, "LSN"},
+
+ {"Lineout Out 1", NULL, "LINEOUT1"},
+ {"Lineout Out 2", NULL, "LINEOUT2"},
+
+ {"MIC1P", NULL, "Mic1 Bias"},
+ {"MIC1N", NULL, "Mic1 Bias"},
+ {"Mic1 Bias", NULL, "Ext Mic 1"},
+
+ {"MIC2P", NULL, "Mic1 Bias"},
+ {"MIC2N", NULL, "Mic1 Bias"},
+ {"Mic1 Bias", NULL, "Headset Mic 2"},
+
+ {"MIC3P", NULL, "Mic3 Bias"},
+ {"MIC3N", NULL, "Mic3 Bias"},
+ {"Mic3 Bias", NULL, "Ext Mic 3"},
+};
+
+static int saarb_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int width = snd_pcm_format_physical_width(params_format(params));
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0,
+ PM860X_CLK_DIR_OUT);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width);
+
+ return ret;
+}
+
+static struct snd_soc_ops saarb_i2s_ops = {
+ .hw_params = saarb_i2s_hw_params,
+};
+
+static struct snd_soc_dai_link saarb_dai[] = {
+ {
+ .name = "88PM860x I2S",
+ .stream_name = "I2S Audio",
+ .cpu_dai_name = "pxa-ssp-dai.1",
+ .codec_dai_name = "88pm860x-i2s",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "88pm860x-codec",
+ .init = saarb_pm860x_init,
+ .ops = &saarb_i2s_ops,
+ },
+};
+
+static struct snd_soc_card snd_soc_card_saarb = {
+ .name = "Saarb",
+ .dai_link = saarb_dai,
+ .num_links = ARRAY_SIZE(saarb_dai),
+};
+
+static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int ret;
+
+ snd_soc_dapm_new_controls(codec, saarb_dapm_widgets,
+ ARRAY_SIZE(saarb_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ /* connected pins */
+ snd_soc_dapm_enable_pin(codec, "Ext Speaker");
+ snd_soc_dapm_enable_pin(codec, "Ext Mic 1");
+ snd_soc_dapm_enable_pin(codec, "Ext Mic 3");
+ snd_soc_dapm_disable_pin(codec, "Headset Mic 2");
+ snd_soc_dapm_disable_pin(codec, "Headset Stereophone");
+
+ ret = snd_soc_dapm_sync(codec);
+ if (ret)
+ return ret;
+
+ /* Headset jack detection */
+ snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
+ | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
+ &hs_jack);
+ snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+ hs_jack_pins);
+ snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
+ &mic_jack);
+ snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
+ mic_jack_pins);
+
+ /* headphone, microphone detection & headset short detection */
+ pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
+ SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
+ pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
+ return 0;
+}
+
+static int __init saarb_init(void)
+{
+ int ret;
+
+ if (!machine_is_saarb())
+ return -ENODEV;
+ saarb_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!saarb_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(saarb_snd_device, &snd_soc_card_saarb);
+
+ ret = platform_device_add(saarb_snd_device);
+ if (ret)
+ platform_device_put(saarb_snd_device);
+
+ return ret;
+}
+
+static void __exit saarb_exit(void)
+{
+ platform_device_unregister(saarb_snd_device);
+}
+
+module_init(saarb_init);
+module_exit(saarb_exit);
+
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("ALSA SoC 88PM860x Saarb");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index d256f5f313b5..f470f360f4dd 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -28,7 +28,6 @@
#include <asm/mach-types.h>
#include <mach/spitz.h>
#include "../codecs/wm8750.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-i2s.h"
#define SPITZ_HP 0
@@ -107,7 +106,7 @@ static void spitz_ext_control(struct snd_soc_codec *codec)
static int spitz_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->codec;
/* check the jack status at stream startup */
spitz_ext_control(codec);
@@ -118,8 +117,8 @@ static int spitz_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret = 0;
@@ -274,8 +273,9 @@ static const struct snd_kcontrol_new wm8750_spitz_controls[] = {
/*
* Logic for a wm8750 as connected on a Sharp SL-Cxx00 Device
*/
-static int spitz_wm8750_init(struct snd_soc_codec *codec)
+static int spitz_wm8750_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* NC codec pins */
@@ -308,8 +308,10 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link spitz_dai = {
.name = "wm8750",
.stream_name = "WM8750",
- .cpu_dai = &pxa_i2s_dai,
- .codec_dai = &wm8750_dai,
+ .cpu_dai_name = "pxa-is2",
+ .codec_dai_name = "wm8750-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm8750-codec.0-001a",
.init = spitz_wm8750_init,
.ops = &spitz_ops,
};
@@ -317,17 +319,10 @@ static struct snd_soc_dai_link spitz_dai = {
/* spitz audio machine driver */
static struct snd_soc_card snd_soc_spitz = {
.name = "Spitz",
- .platform = &pxa2xx_soc_platform,
.dai_link = &spitz_dai,
.num_links = 1,
};
-/* spitz audio subsystem */
-static struct snd_soc_device spitz_snd_devdata = {
- .card = &snd_soc_spitz,
- .codec_dev = &soc_codec_dev_wm8750,
-};
-
static struct platform_device *spitz_snd_device;
static int __init spitz_init(void)
@@ -341,8 +336,7 @@ static int __init spitz_init(void)
if (!spitz_snd_device)
return -ENOMEM;
- platform_set_drvdata(spitz_snd_device, &spitz_snd_devdata);
- spitz_snd_devdata.dev = &spitz_snd_device->dev;
+ platform_set_drvdata(spitz_snd_device, &snd_soc_spitz);
ret = platform_device_add(spitz_snd_device);
if (ret)
diff --git a/sound/soc/pxa/tavorevb3.c b/sound/soc/pxa/tavorevb3.c
new file mode 100644
index 000000000000..248c283fc4df
--- /dev/null
+++ b/sound/soc/pxa/tavorevb3.c
@@ -0,0 +1,200 @@
+/*
+ * tavorevb3.c -- SoC audio for Tavor EVB3
+ *
+ * Copyright (C) 2010 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/88pm860x-codec.h"
+#include "pxa-ssp.h"
+
+static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd);
+
+static struct platform_device *evb3_snd_device;
+
+static struct snd_soc_jack hs_jack, mic_jack;
+
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+ { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, },
+};
+
+static struct snd_soc_jack_pin mic_jack_pins[] = {
+ { .pin = "Headset Mic 2", .mask = SND_JACK_MICROPHONE, },
+};
+
+/* tavorevb3 machine dapm widgets */
+static const struct snd_soc_dapm_widget evb3_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+ SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
+ SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
+ SND_SOC_DAPM_SPK("Ext Speaker", NULL),
+ SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic 2", NULL),
+ SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
+};
+
+/* tavorevb3 machine audio map */
+static const struct snd_soc_dapm_route audio_map[] = {
+ {"Headset Stereophone", NULL, "HS1"},
+ {"Headset Stereophone", NULL, "HS2"},
+
+ {"Ext Speaker", NULL, "LSP"},
+ {"Ext Speaker", NULL, "LSN"},
+
+ {"Lineout Out 1", NULL, "LINEOUT1"},
+ {"Lineout Out 2", NULL, "LINEOUT2"},
+
+ {"MIC1P", NULL, "Mic1 Bias"},
+ {"MIC1N", NULL, "Mic1 Bias"},
+ {"Mic1 Bias", NULL, "Ext Mic 1"},
+
+ {"MIC2P", NULL, "Mic1 Bias"},
+ {"MIC2N", NULL, "Mic1 Bias"},
+ {"Mic1 Bias", NULL, "Headset Mic 2"},
+
+ {"MIC3P", NULL, "Mic3 Bias"},
+ {"MIC3N", NULL, "Mic3 Bias"},
+ {"Mic3 Bias", NULL, "Ext Mic 3"},
+};
+
+static int evb3_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int width = snd_pcm_format_physical_width(params_format(params));
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0,
+ PM860X_CLK_DIR_OUT);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width);
+ return ret;
+}
+
+static struct snd_soc_ops evb3_i2s_ops = {
+ .hw_params = evb3_i2s_hw_params,
+};
+
+static struct snd_soc_dai_link evb3_dai[] = {
+ {
+ .name = "88PM860x I2S",
+ .stream_name = "I2S Audio",
+ .cpu_dai_name = "pxa-ssp-dai.1",
+ .codec_dai_name = "88pm860x-i2s",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "88pm860x-codec",
+ .init = evb3_pm860x_init,
+ .ops = &evb3_i2s_ops,
+ },
+};
+
+static struct snd_soc_card snd_soc_card_evb3 = {
+ .name = "Tavor EVB3",
+ .dai_link = evb3_dai,
+ .num_links = ARRAY_SIZE(evb3_dai),
+};
+
+static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int ret;
+
+ snd_soc_dapm_new_controls(codec, evb3_dapm_widgets,
+ ARRAY_SIZE(evb3_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ /* connected pins */
+ snd_soc_dapm_enable_pin(codec, "Ext Speaker");
+ snd_soc_dapm_enable_pin(codec, "Ext Mic 1");
+ snd_soc_dapm_enable_pin(codec, "Ext Mic 3");
+ snd_soc_dapm_disable_pin(codec, "Headset Mic 2");
+ snd_soc_dapm_disable_pin(codec, "Headset Stereophone");
+
+ ret = snd_soc_dapm_sync(codec);
+ if (ret)
+ return ret;
+
+ /* Headset jack detection */
+ snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
+ | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
+ &hs_jack);
+ snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+ hs_jack_pins);
+ snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
+ &mic_jack);
+ snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
+ mic_jack_pins);
+
+ /* headphone, microphone detection & headset short detection */
+ pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
+ SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
+ pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
+ return 0;
+}
+
+static int __init tavorevb3_init(void)
+{
+ int ret;
+
+ if (!machine_is_tavorevb3())
+ return -ENODEV;
+ evb3_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!evb3_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(evb3_snd_device, &snd_soc_card_evb3);
+
+ ret = platform_device_add(evb3_snd_device);
+ if (ret)
+ platform_device_put(evb3_snd_device);
+
+ return ret;
+}
+
+static void __exit tavorevb3_exit(void)
+{
+ platform_device_unregister(evb3_snd_device);
+}
+
+module_init(tavorevb3_init);
+module_exit(tavorevb3_exit);
+
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("ALSA SoC 88PM860x Tavor EVB3");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index dbbd3e9d1637..a3bfb2e8b70f 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -33,7 +33,6 @@
#include <mach/audio.h>
#include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
static struct snd_soc_card tosa;
@@ -80,7 +79,7 @@ static void tosa_ext_control(struct snd_soc_codec *codec)
static int tosa_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct snd_soc_codec *codec = rtd->card->codec;
/* check the jack status at stream startup */
tosa_ext_control(codec);
@@ -184,8 +183,9 @@ static const struct snd_kcontrol_new tosa_controls[] = {
tosa_set_spk),
};
-static int tosa_ac97_init(struct snd_soc_codec *codec)
+static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
snd_soc_dapm_nc_pin(codec, "OUT3");
@@ -212,16 +212,20 @@ static struct snd_soc_dai_link tosa_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_dai_name = "wm9712-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9712-codec",
.init = tosa_ac97_init,
.ops = &tosa_ops,
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_dai_name = "wm9712-aux",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm9712-codec",
.ops = &tosa_ops,
},
};
@@ -248,18 +252,12 @@ static int tosa_remove(struct platform_device *dev)
static struct snd_soc_card tosa = {
.name = "Tosa",
- .platform = &pxa2xx_soc_platform,
.dai_link = tosa_dai,
.num_links = ARRAY_SIZE(tosa_dai),
.probe = tosa_probe,
.remove = tosa_remove,
};
-static struct snd_soc_device tosa_snd_devdata = {
- .card = &tosa,
- .codec_dev = &soc_codec_dev_wm9712,
-};
-
static struct platform_device *tosa_snd_device;
static int __init tosa_init(void)
@@ -275,8 +273,7 @@ static int __init tosa_init(void)
goto err_alloc;
}
- platform_set_drvdata(tosa_snd_device, &tosa_snd_devdata);
- tosa_snd_devdata.dev = &tosa_snd_device->dev;
+ platform_set_drvdata(tosa_snd_device, &tosa);
ret = platform_device_add(tosa_snd_device);
if (!ret)
diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c
index 4e4d2fa8ddc5..4cc841b44182 100644
--- a/sound/soc/pxa/z2.c
+++ b/sound/soc/pxa/z2.c
@@ -30,7 +30,6 @@
#include <mach/z2.h>
#include "../codecs/wm8750.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-i2s.h"
static struct snd_soc_card snd_soc_z2;
@@ -39,8 +38,8 @@ static int z2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret = 0;
@@ -138,8 +137,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
/*
* Logic for a wm8750 as connected on a Z2 Device
*/
-static int z2_wm8750_init(struct snd_soc_codec *codec)
+static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int ret;
/* NC codec pins */
@@ -160,7 +160,7 @@ static int z2_wm8750_init(struct snd_soc_codec *codec)
goto err;
/* Jack detection API stuff */
- ret = snd_soc_jack_new(&snd_soc_z2, "Headset Jack", SND_JACK_HEADSET,
+ ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
&hs_jack);
if (ret)
goto err;
@@ -189,8 +189,10 @@ static struct snd_soc_ops z2_ops = {
static struct snd_soc_dai_link z2_dai = {
.name = "wm8750",
.stream_name = "WM8750",
- .cpu_dai = &pxa_i2s_dai,
- .codec_dai = &wm8750_dai,
+ .cpu_dai_name = "pxa2xx-i2s",
+ .codec_dai_name = "wm8750-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm8750-codec.0-001a",
.init = z2_wm8750_init,
.ops = &z2_ops,
};
@@ -198,17 +200,10 @@ static struct snd_soc_dai_link z2_dai = {
/* z2 audio machine driver */
static struct snd_soc_card snd_soc_z2 = {
.name = "Z2",
- .platform = &pxa2xx_soc_platform,
.dai_link = &z2_dai,
.num_links = 1,
};
-/* z2 audio subsystem */
-static struct snd_soc_device z2_snd_devdata = {
- .card = &snd_soc_z2,
- .codec_dev = &soc_codec_dev_wm8750,
-};
-
static struct platform_device *z2_snd_device;
static int __init z2_init(void)
@@ -222,8 +217,7 @@ static int __init z2_init(void)
if (!z2_snd_device)
return -ENOMEM;
- platform_set_drvdata(z2_snd_device, &z2_snd_devdata);
- z2_snd_devdata.dev = &z2_snd_device->dev;
+ platform_set_drvdata(z2_snd_device, &snd_soc_z2);
ret = platform_device_add(z2_snd_device);
if (ret)
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c
index dd678ae24398..d27e05af7759 100644
--- a/sound/soc/pxa/zylonite.c
+++ b/sound/soc/pxa/zylonite.c
@@ -23,7 +23,6 @@
#include <sound/soc-dapm.h>
#include "../codecs/wm9713.h"
-#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
#include "pxa-ssp.h"
@@ -71,10 +70,12 @@ static const struct snd_soc_dapm_route audio_map[] = {
{ "Multiactor", NULL, "SPKR" },
};
-static int zylonite_wm9713_init(struct snd_soc_codec *codec)
+static int zylonite_wm9713_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
if (clk_pout)
- snd_soc_dai_set_pll(&codec->dai[0], 0, 0,
+ snd_soc_dai_set_pll(rtd->codec_dai, 0, 0,
clk_get_rate(pout), 0);
snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets,
@@ -94,8 +95,8 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0;
unsigned int wm9713_div = 0;
int ret = 0;
@@ -163,21 +164,27 @@ static struct snd_soc_dai_link zylonite_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
- .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+ .codec_name = "wm9713-codec",
+ .platform_name = "pxa-pcm-audio",
+ .cpu_dai_name = "pxa-ac97.0",
+ .codec_name = "wm9713-hifi",
.init = zylonite_wm9713_init,
},
{
.name = "AC97 Aux",
.stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX],
+ .codec_name = "wm9713-codec",
+ .platform_name = "pxa-pcm-audio",
+ .cpu_dai_name = "pxa-ac97.1",
+ .codec_name = "wm9713-aux",
},
{
.name = "WM9713 Voice",
.stream_name = "WM9713 Voice",
- .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP3],
- .codec_dai = &wm9713_dai[WM9713_DAI_PCM_VOICE],
+ .codec_name = "wm9713-codec",
+ .platform_name = "pxa-pcm-audio",
+ .cpu_dai_name = "pxa-ssp-dai.2",
+ .codec_name = "wm9713-voice",
.ops = &zylonite_voice_ops,
},
};
@@ -248,14 +255,9 @@ static struct snd_soc_card zylonite = {
.remove = &zylonite_remove,
.suspend_post = &zylonite_suspend_post,
.resume_pre = &zylonite_resume_pre,
- .platform = &pxa2xx_soc_platform,
.dai_link = zylonite_dai,
.num_links = ARRAY_SIZE(zylonite_dai),
-};
-
-static struct snd_soc_device zylonite_snd_ac97_devdata = {
- .card = &zylonite,
- .codec_dev = &soc_codec_dev_wm9713,
+ .owner = THIS_MODULE,
};
static struct platform_device *zylonite_snd_ac97_device;
@@ -268,9 +270,7 @@ static int __init zylonite_init(void)
if (!zylonite_snd_ac97_device)
return -ENOMEM;
- platform_set_drvdata(zylonite_snd_ac97_device,
- &zylonite_snd_ac97_devdata);
- zylonite_snd_ac97_devdata.dev = &zylonite_snd_ac97_device->dev;
+ platform_set_drvdata(zylonite_snd_ac97_device, &zylonite);
ret = platform_device_add(zylonite_snd_ac97_device);
if (ret != 0)
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 213963ac3c28..8a6b53ccd203 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -36,6 +36,10 @@ config SND_S3C_SOC_AC97
tristate
select SND_SOC_AC97_BUS
+config SND_S5P_SOC_SPDIF
+ tristate
+ select SND_SOC_SPDIF
+
config SND_S3C24XX_SOC_NEO1973_WM8753
tristate "SoC I2S Audio support for NEO1973 - WM8753"
depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01
@@ -118,6 +122,14 @@ config SND_S3C24XX_SOC_SIMTEC_HERMES
select SND_SOC_TLV320AIC3X
select SND_S3C24XX_SOC_SIMTEC
+config SND_S3C24XX_SOC_RX1950_UDA1380
+ tristate "Audio support for the HP iPAQ RX1950"
+ depends on SND_S3C24XX_SOC && MACH_RX1950
+ select SND_S3C24XX_SOC_I2S
+ select SND_SOC_UDA1380
+ help
+ This driver provides audio support for HP iPAQ RX1950 PDA.
+
config SND_SOC_SMDK_WM9713
tristate "SoC AC97 Audio support for SMDK with WM9713"
depends on SND_S3C24XX_SOC && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
@@ -131,3 +143,28 @@ config SND_S3C64XX_SOC_SMARTQ
depends on SND_S3C24XX_SOC && MACH_SMARTQ
select SND_S3C64XX_SOC_I2S
select SND_SOC_WM8750
+
+config SND_S5PC110_SOC_AQUILA_WM8994
+ tristate "SoC I2S Audio support for AQUILA - WM8994"
+ depends on SND_S3C24XX_SOC && MACH_AQUILA
+ select SND_S3C64XX_SOC_I2S_V4
+ select SND_SOC_WM8994
+ help
+ Say Y if you want to add support for SoC audio on aquila
+ with the WM8994.
+
+config SND_S5PV210_SOC_GONI_WM8994
+ tristate "SoC I2S Audio support for GONI - WM8994"
+ depends on SND_S3C24XX_SOC && MACH_GONI
+ select SND_S3C64XX_SOC_I2S_V4
+ select SND_SOC_WM8994
+ help
+ Say Y if you want to add support for SoC audio on goni
+ with the WM8994.
+
+config SND_SOC_SMDK_SPDIF
+ tristate "SoC S/PDIF Audio support for SMDK"
+ depends on SND_S3C24XX_SOC && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210)
+ select SND_S5P_SOC_SPDIF
+ help
+ Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 50172c385d90..ee8f41d6df99 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -7,6 +7,7 @@ snd-soc-s3c-ac97-objs := s3c-ac97.o
snd-soc-s3c64xx-i2s-v4-objs := s3c64xx-i2s-v4.o
snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
snd-soc-s3c-pcm-objs := s3c-pcm.o
+snd-soc-samsung-spdif-objs := spdif.o
obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
@@ -16,6 +17,7 @@ obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
obj-$(CONFIG_SND_S3C64XX_SOC_I2S_V4) += snd-soc-s3c64xx-i2s-v4.o
obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-s3c-pcm.o
+obj-$(CONFIG_SND_S5P_SOC_SPDIF) += snd-soc-samsung-spdif.o
# S3C24XX Machine Support
snd-soc-jive-wm8750-objs := jive_wm8750.o
@@ -27,9 +29,13 @@ snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o
snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
+snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
snd-soc-smdk-wm9713-objs := smdk_wm9713.o
snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
+snd-soc-aquila-wm8994-objs := aquila_wm8994.o
+snd-soc-goni-wm8994-objs := goni_wm8994.o
+snd-soc-smdk-spdif-objs := smdk_spdif.o
obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -40,6 +46,10 @@ obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
+obj-$(CONFIG_SND_S3C24XX_SOC_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o
obj-$(CONFIG_SND_S3C64XX_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
+obj-$(CONFIG_SND_S5PC110_SOC_AQUILA_WM8994) += snd-soc-aquila-wm8994.o
+obj-$(CONFIG_SND_S5PV210_SOC_GONI_WM8994) += snd-soc-goni-wm8994.o
+obj-$(CONFIG_SND_SOC_SMDK_SPDIF) += snd-soc-smdk-spdif.o
diff --git a/sound/soc/s3c24xx/aquila_wm8994.c b/sound/soc/s3c24xx/aquila_wm8994.c
new file mode 100644
index 000000000000..235d1973f7d0
--- /dev/null
+++ b/sound/soc/s3c24xx/aquila_wm8994.c
@@ -0,0 +1,295 @@
+/*
+ * aquila_wm8994.c
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Chanwoo Choi <cw00.choi@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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/gpio.h>
+#include <mach/regs-clock.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include "../codecs/wm8994.h"
+#include "s3c-dma.h"
+#include "s3c64xx-i2s.h"
+
+static struct snd_soc_card aquila;
+static struct platform_device *aquila_snd_device;
+
+/* 3.5 pie jack */
+static struct snd_soc_jack jack;
+
+/* 3.5 pie jack detection DAPM pins */
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ }, {
+ .pin = "Headset Stereophone",
+ .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
+ SND_JACK_AVOUT,
+ },
+};
+
+/* 3.5 pie jack detection gpios */
+static struct snd_soc_jack_gpio jack_gpios[] = {
+ {
+ .gpio = S5PV210_GPH0(6),
+ .name = "DET_3.5",
+ .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+ SND_JACK_AVOUT,
+ .debounce_time = 200,
+ },
+};
+
+static const struct snd_soc_dapm_widget aquila_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+ SND_SOC_DAPM_SPK("Ext Rcv", NULL),
+ SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Main Mic", NULL),
+ SND_SOC_DAPM_MIC("2nd Mic", NULL),
+ SND_SOC_DAPM_LINE("Radio In", NULL),
+};
+
+static const struct snd_soc_dapm_route aquila_dapm_routes[] = {
+ {"Ext Spk", NULL, "SPKOUTLP"},
+ {"Ext Spk", NULL, "SPKOUTLN"},
+
+ {"Ext Rcv", NULL, "HPOUT2N"},
+ {"Ext Rcv", NULL, "HPOUT2P"},
+
+ {"Headset Stereophone", NULL, "HPOUT1L"},
+ {"Headset Stereophone", NULL, "HPOUT1R"},
+
+ {"IN1RN", NULL, "Headset Mic"},
+ {"IN1RP", NULL, "Headset Mic"},
+
+ {"IN1RN", NULL, "2nd Mic"},
+ {"IN1RP", NULL, "2nd Mic"},
+
+ {"IN1LN", NULL, "Main Mic"},
+ {"IN1LP", NULL, "Main Mic"},
+
+ {"IN2LN", NULL, "Radio In"},
+ {"IN2RN", NULL, "Radio In"},
+};
+
+static int aquila_wm8994_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int ret;
+
+ /* add aquila specific widgets */
+ snd_soc_dapm_new_controls(codec, aquila_dapm_widgets,
+ ARRAY_SIZE(aquila_dapm_widgets));
+
+ /* set up aquila specific audio routes */
+ snd_soc_dapm_add_routes(codec, aquila_dapm_routes,
+ ARRAY_SIZE(aquila_dapm_routes));
+
+ /* set endpoints to not connected */
+ snd_soc_dapm_nc_pin(codec, "IN2LP:VXRN");
+ snd_soc_dapm_nc_pin(codec, "IN2RP:VXRP");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT1N");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT1P");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT2N");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT2P");
+ snd_soc_dapm_nc_pin(codec, "SPKOUTRN");
+ snd_soc_dapm_nc_pin(codec, "SPKOUTRP");
+
+ snd_soc_dapm_sync(codec);
+
+ /* Headset jack detection */
+ ret = snd_soc_jack_new(&aquila, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
+ &jack);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int aquila_hifi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned int pll_out = 24000000;
+ int ret = 0;
+
+ /* set the cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the cpu system clock */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
+ 0, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec FLL */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
+ params_rate(params) * 256);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
+ params_rate(params) * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops aquila_hifi_ops = {
+ .hw_params = aquila_hifi_hw_params,
+};
+
+static int aquila_voice_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ unsigned int pll_out = 24000000;
+ int ret = 0;
+
+ if (params_rate(params) != 8000)
+ return -EINVAL;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
+ SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec FLL */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
+ params_rate(params) * 256);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
+ params_rate(params) * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver voice_dai = {
+ .name = "aquila-voice-dai",
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_ops aquila_voice_ops = {
+ .hw_params = aquila_voice_hw_params,
+};
+
+static struct snd_soc_dai_link aquila_dai[] = {
+{
+ .name = "WM8994",
+ .stream_name = "WM8994 HiFi",
+ .cpu_dai_name = "s3c64xx-i2s-v4",
+ .codec_dai_name = "wm8994-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8994-codec.0-0x1a",
+ .init = aquila_wm8994_init,
+ .ops = &aquila_hifi_ops,
+}, {
+ .name = "WM8994 Voice",
+ .stream_name = "Voice",
+ .cpu_dai_name = "aquila-voice-dai",
+ .codec_dai_name = "wm8994-voice",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8994-codec.0-0x1a",
+ .ops = &aquila_voice_ops,
+},
+};
+
+static struct snd_soc_card aquila = {
+ .name = "aquila",
+ .dai_link = aquila_dai,
+ .num_links = ARRAY_SIZE(aquila_dai),
+};
+
+static int __init aquila_init(void)
+{
+ int ret;
+
+ if (!machine_is_aquila())
+ return -ENODEV;
+
+ aquila_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!aquila_snd_device)
+ return -ENOMEM;
+
+ /* register voice DAI here */
+ ret = snd_soc_register_dai(&aquila_snd_device->dev, &voice_dai);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(aquila_snd_device, &aquila);
+ ret = platform_device_add(aquila_snd_device);
+
+ if (ret)
+ platform_device_put(aquila_snd_device);
+
+ return ret;
+}
+
+static void __exit aquila_exit(void)
+{
+ platform_device_unregister(aquila_snd_device);
+}
+
+module_init(aquila_init);
+module_exit(aquila_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("ALSA SoC WM8994 Aquila(S5PC110)");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/goni_wm8994.c b/sound/soc/s3c24xx/goni_wm8994.c
new file mode 100644
index 000000000000..694f702cc8e2
--- /dev/null
+++ b/sound/soc/s3c24xx/goni_wm8994.c
@@ -0,0 +1,298 @@
+/*
+ * goni_wm8994.c
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Chanwoo Choi <cw00.choi@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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/gpio.h>
+#include <mach/regs-clock.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include "../codecs/wm8994.h"
+#include "s3c-dma.h"
+#include "s3c64xx-i2s.h"
+
+static struct snd_soc_card goni;
+static struct platform_device *goni_snd_device;
+
+/* 3.5 pie jack */
+static struct snd_soc_jack jack;
+
+/* 3.5 pie jack detection DAPM pins */
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ }, {
+ .pin = "Headset Stereophone",
+ .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
+ SND_JACK_AVOUT,
+ },
+};
+
+/* 3.5 pie jack detection gpios */
+static struct snd_soc_jack_gpio jack_gpios[] = {
+ {
+ .gpio = S5PV210_GPH0(6),
+ .name = "DET_3.5",
+ .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+ SND_JACK_AVOUT,
+ .debounce_time = 200,
+ },
+};
+
+static const struct snd_soc_dapm_widget goni_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Ext Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Ext Right Spk", NULL),
+ SND_SOC_DAPM_SPK("Ext Rcv", NULL),
+ SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Main Mic", NULL),
+ SND_SOC_DAPM_MIC("2nd Mic", NULL),
+ SND_SOC_DAPM_LINE("Radio In", NULL),
+};
+
+static const struct snd_soc_dapm_route goni_dapm_routes[] = {
+ {"Ext Left Spk", NULL, "SPKOUTLP"},
+ {"Ext Left Spk", NULL, "SPKOUTLN"},
+
+ {"Ext Right Spk", NULL, "SPKOUTRP"},
+ {"Ext Right Spk", NULL, "SPKOUTRN"},
+
+ {"Ext Rcv", NULL, "HPOUT2N"},
+ {"Ext Rcv", NULL, "HPOUT2P"},
+
+ {"Headset Stereophone", NULL, "HPOUT1L"},
+ {"Headset Stereophone", NULL, "HPOUT1R"},
+
+ {"IN1RN", NULL, "Headset Mic"},
+ {"IN1RP", NULL, "Headset Mic"},
+
+ {"IN1RN", NULL, "2nd Mic"},
+ {"IN1RP", NULL, "2nd Mic"},
+
+ {"IN1LN", NULL, "Main Mic"},
+ {"IN1LP", NULL, "Main Mic"},
+
+ {"IN2LN", NULL, "Radio In"},
+ {"IN2RN", NULL, "Radio In"},
+};
+
+static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int ret;
+
+ /* add goni specific widgets */
+ snd_soc_dapm_new_controls(codec, goni_dapm_widgets,
+ ARRAY_SIZE(goni_dapm_widgets));
+
+ /* set up goni specific audio routes */
+ snd_soc_dapm_add_routes(codec, goni_dapm_routes,
+ ARRAY_SIZE(goni_dapm_routes));
+
+ /* set endpoints to not connected */
+ snd_soc_dapm_nc_pin(codec, "IN2LP:VXRN");
+ snd_soc_dapm_nc_pin(codec, "IN2RP:VXRP");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT1N");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT1P");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT2N");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT2P");
+
+ snd_soc_dapm_sync(codec);
+
+ /* Headset jack detection */
+ ret = snd_soc_jack_new(&goni, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
+ &jack);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int goni_hifi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned int pll_out = 24000000;
+ int ret = 0;
+
+ /* set the cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the cpu system clock */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
+ 0, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec FLL */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
+ params_rate(params) * 256);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
+ params_rate(params) * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops goni_hifi_ops = {
+ .hw_params = goni_hifi_hw_params,
+};
+
+static int goni_voice_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ unsigned int pll_out = 24000000;
+ int ret = 0;
+
+ if (params_rate(params) != 8000)
+ return -EINVAL;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
+ SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec FLL */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
+ params_rate(params) * 256);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
+ params_rate(params) * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver voice_dai = {
+ .name = "goni-voice-dai",
+ .id = 0,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_ops goni_voice_ops = {
+ .hw_params = goni_voice_hw_params,
+};
+
+static struct snd_soc_dai_link goni_dai[] = {
+{
+ .name = "WM8994",
+ .stream_name = "WM8994 HiFi",
+ .cpu_dai_name = "s3c64xx-i2s-v4",
+ .codec_dai_name = "wm8994-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8994-codec.0-0x1a",
+ .init = goni_wm8994_init,
+ .ops = &goni_hifi_ops,
+}, {
+ .name = "WM8994 Voice",
+ .stream_name = "Voice",
+ .cpu_dai_name = "goni-voice-dai",
+ .codec_dai_name = "wm8994-voice",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8994-codec.0-0x1a",
+ .ops = &goni_voice_ops,
+},
+};
+
+static struct snd_soc_card goni = {
+ .name = "goni",
+ .dai_link = goni_dai,
+ .num_links = ARRAY_SIZE(goni_dai),
+};
+
+static int __init goni_init(void)
+{
+ int ret;
+
+ if (!machine_is_goni())
+ return -ENODEV;
+
+ goni_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!goni_snd_device)
+ return -ENOMEM;
+
+ /* register voice DAI here */
+ ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(goni_snd_device, &goni);
+ ret = platform_device_add(goni_snd_device);
+
+ if (ret)
+ platform_device_put(goni_snd_device);
+
+ return ret;
+}
+
+static void __exit goni_exit(void)
+{
+ platform_device_unregister(goni_snd_device);
+}
+
+module_init(goni_init);
+module_exit(goni_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("ALSA SoC WM8994 GONI(S5PV210)");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c
index 8c108b121c10..49605cd83947 100644
--- a/sound/soc/s3c24xx/jive_wm8750.c
+++ b/sound/soc/s3c24xx/jive_wm8750.c
@@ -49,8 +49,8 @@ static int jive_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct s3c_i2sv2_rate_calc div;
unsigned int clk = 0;
int ret = 0;
@@ -108,8 +108,9 @@ static struct snd_soc_ops jive_ops = {
.hw_params = jive_hw_params,
};
-static int jive_wm8750_init(struct snd_soc_codec *codec)
+static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* These endpoints are not being used. */
@@ -138,8 +139,10 @@ static int jive_wm8750_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link jive_dai = {
.name = "wm8750",
.stream_name = "WM8750",
- .cpu_dai = &s3c2412_i2s_dai,
- .codec_dai = &wm8750_dai,
+ .cpu_dai_name = "s3c2412-i2s",
+ .codec_dai_name = "wm8750-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8750-codec.0-0x1a",
.init = jive_wm8750_init,
.ops = &jive_ops,
};
@@ -147,17 +150,10 @@ static struct snd_soc_dai_link jive_dai = {
/* jive audio machine driver */
static struct snd_soc_card snd_soc_machine_jive = {
.name = "Jive",
- .platform = &s3c24xx_soc_platform,
.dai_link = &jive_dai,
.num_links = 1,
};
-/* jive audio subsystem */
-static struct snd_soc_device jive_snd_devdata = {
- .card = &snd_soc_machine_jive,
- .codec_dev = &soc_codec_dev_wm8750,
-};
-
static struct platform_device *jive_snd_device;
static int __init jive_init(void)
@@ -173,8 +169,7 @@ static int __init jive_init(void)
if (!jive_snd_device)
return -ENOMEM;
- platform_set_drvdata(jive_snd_device, &jive_snd_devdata);
- jive_snd_devdata.dev = &jive_snd_device->dev;
+ platform_set_drvdata(jive_snd_device, &snd_soc_machine_jive);
ret = platform_device_add(jive_snd_device);
if (ret)
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c
index ffa954fe6931..abe64abe8c84 100644
--- a/sound/soc/s3c24xx/ln2440sbc_alc650.c
+++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c
@@ -23,7 +23,6 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include "../codecs/ac97.h"
#include "s3c-dma.h"
#include "s3c-ac97.h"
@@ -33,23 +32,19 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
- .codec_dai = &ac97_dai,
+ .cpu_dai_name = "s3c-ac97",
+ .codec_dai_name = "ac97-hifi",
+ .codec_name = "ac97-codec",
+ .platform_name = "s3c24xx-pcm-audio",
},
};
static struct snd_soc_card ln2440sbc = {
.name = "LN2440SBC",
- .platform = &s3c24xx_soc_platform,
.dai_link = ln2440sbc_dai,
.num_links = ARRAY_SIZE(ln2440sbc_dai),
};
-static struct snd_soc_device ln2440sbc_snd_ac97_devdata = {
- .card = &ln2440sbc,
- .codec_dev = &soc_codec_dev_ac97,
-};
-
static struct platform_device *ln2440sbc_snd_ac97_device;
static int __init ln2440sbc_init(void)
@@ -60,9 +55,7 @@ static int __init ln2440sbc_init(void)
if (!ln2440sbc_snd_ac97_device)
return -ENOMEM;
- platform_set_drvdata(ln2440sbc_snd_ac97_device,
- &ln2440sbc_snd_ac97_devdata);
- ln2440sbc_snd_ac97_devdata.dev = &ln2440sbc_snd_ac97_device->dev;
+ platform_set_drvdata(ln2440sbc_snd_ac97_device, &ln2440sbc);
ret = platform_device_add(ln2440sbc_snd_ac97_device);
if (ret)
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
index 209c25994c7e..e97bdf150a03 100644
--- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
@@ -41,8 +41,8 @@ static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, bclk = 0;
int ret = 0;
unsigned long iis_clkrate;
@@ -130,7 +130,7 @@ static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream,
static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
/* disable the PLL */
return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
@@ -149,7 +149,7 @@ static int neo1973_gta02_voice_hw_params(
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int pcmdiv = 0;
int ret = 0;
unsigned long iis_clkrate;
@@ -182,7 +182,7 @@ static int neo1973_gta02_voice_hw_params(
if (ret < 0)
return ret;
- /* configue and enable PLL for 12.288MHz output */
+ /* configure and enable PLL for 12.288MHz output */
ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
iis_clkrate / 4, 12288000);
if (ret < 0)
@@ -194,7 +194,7 @@ static int neo1973_gta02_voice_hw_params(
static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
/* disable the PLL */
return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
@@ -262,7 +262,7 @@ static int lm4853_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k,
int event)
{
- gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(value));
+ gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event));
return 0;
}
@@ -330,8 +330,9 @@ static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = {
* This is an example machine initialisation for a wm8753 connected to a
* neo1973 GTA02.
*/
-static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
+static int neo1973_gta02_wm8753_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* set up NC codec pins */
@@ -378,9 +379,8 @@ static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
/*
* BT Codec DAI
*/
-static struct snd_soc_dai bt_dai = {
- .name = "Bluetooth",
- .id = 0,
+static struct snd_soc_dai_driver bt_dai = {
+ .name = "bluetooth-dai",
.playback = {
.channels_min = 1,
.channels_max = 1,
@@ -397,32 +397,30 @@ static struct snd_soc_dai_link neo1973_gta02_dai[] = {
{ /* Hifi Playback - for similatious use with voice below */
.name = "WM8753",
.stream_name = "WM8753 HiFi",
- .cpu_dai = &s3c24xx_i2s_dai,
- .codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "wm8753-hifi",
.init = neo1973_gta02_wm8753_init,
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8753-codec.0-0x1a",
.ops = &neo1973_gta02_hifi_ops,
},
{ /* Voice via BT */
.name = "Bluetooth",
.stream_name = "Voice",
- .cpu_dai = &bt_dai,
- .codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
+ .cpu_dai_name = "bluetooth-dai",
+ .codec_dai_name = "wm8753-voice",
.ops = &neo1973_gta02_voice_ops,
+ .codec_name = "wm8753-codec.0-0x1a",
+ .platform_name = "s3c24xx-pcm-audio",
},
};
static struct snd_soc_card neo1973_gta02 = {
.name = "neo1973-gta02",
- .platform = &s3c24xx_soc_platform,
.dai_link = neo1973_gta02_dai,
.num_links = ARRAY_SIZE(neo1973_gta02_dai),
};
-static struct snd_soc_device neo1973_gta02_snd_devdata = {
- .card = &neo1973_gta02,
- .codec_dev = &soc_codec_dev_wm8753,
-};
-
static struct platform_device *neo1973_gta02_snd_device;
static int __init neo1973_gta02_init(void)
@@ -435,18 +433,18 @@ static int __init neo1973_gta02_init(void)
return -ENODEV;
}
- /* register bluetooth DAI here */
- ret = snd_soc_register_dai(&bt_dai);
- if (ret)
- return ret;
-
neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1);
if (!neo1973_gta02_snd_device)
return -ENOMEM;
- platform_set_drvdata(neo1973_gta02_snd_device,
- &neo1973_gta02_snd_devdata);
- neo1973_gta02_snd_devdata.dev = &neo1973_gta02_snd_device->dev;
+ /* register bluetooth DAI here */
+ ret = snd_soc_register_dai(&neo1973_gta02_snd_device->dev, -1, &bt_dai);
+ if (ret) {
+ platform_device_put(neo1973_gta02_snd_device);
+ return ret;
+ }
+
+ platform_set_drvdata(neo1973_gta02_snd_device, &neo1973_gta02);
ret = platform_device_add(neo1973_gta02_snd_device);
if (ret) {
@@ -461,7 +459,7 @@ static int __init neo1973_gta02_init(void)
goto err_unregister_device;
}
- ret = gpio_direction_output(GTA02_GPIO_AMP_HP_IN, 1);
+ ret = gpio_direction_output(GTA02_GPIO_HP_IN, 1);
if (ret) {
pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_HP_IN);
goto err_free_gpio_hp_in;
@@ -493,7 +491,7 @@ module_init(neo1973_gta02_init);
static void __exit neo1973_gta02_exit(void)
{
- snd_soc_unregister_dai(&bt_dai);
+ snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev, -1);
platform_device_unregister(neo1973_gta02_snd_device);
gpio_free(GTA02_GPIO_HP_IN);
gpio_free(GTA02_GPIO_AMP_SHUT);
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 0cb4f86f6d1e..f4f2ee731f01 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -57,8 +57,8 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, bclk = 0;
int ret = 0;
unsigned long iis_clkrate;
@@ -147,7 +147,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
pr_debug("Entered %s\n", __func__);
@@ -167,7 +167,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int pcmdiv = 0;
int ret = 0;
unsigned long iis_clkrate;
@@ -201,7 +201,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- /* configue and enable PLL for 12.288MHz output */
+ /* configure and enable PLL for 12.288MHz output */
ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
iis_clkrate / 4, 12288000);
if (ret < 0)
@@ -213,7 +213,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
pr_debug("Entered %s\n", __func__);
@@ -499,8 +499,9 @@ static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
* neo1973 II. It is missing logic to detect hp/mic insertions and logic
* to re-route the audio in such an event.
*/
-static int neo1973_wm8753_init(struct snd_soc_codec *codec)
+static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
pr_debug("Entered %s\n", __func__);
@@ -538,8 +539,7 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec)
* BT Codec DAI
*/
static struct snd_soc_dai bt_dai = {
- .name = "Bluetooth",
- .id = 0,
+ .name = "bluetooth-dai",
.playback = {
.channels_min = 1,
.channels_max = 1,
@@ -556,32 +556,30 @@ static struct snd_soc_dai_link neo1973_dai[] = {
{ /* Hifi Playback - for similatious use with voice below */
.name = "WM8753",
.stream_name = "WM8753 HiFi",
- .cpu_dai = &s3c24xx_i2s_dai,
- .codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+ .platform_name = "s3c24xx-pcm-audio",
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "wm8753-hifi",
+ .codec_name = "wm8753-codec.0-0x1a",
.init = neo1973_wm8753_init,
.ops = &neo1973_hifi_ops,
},
{ /* Voice via BT */
.name = "Bluetooth",
.stream_name = "Voice",
- .cpu_dai = &bt_dai,
- .codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
+ .platform_name = "s3c24xx-pcm-audio",
+ .cpu_dai_name = "bluetooth-dai",
+ .codec_dai_name = "wm8753-voice",
+ .codec_name = "wm8753-codec.0-0x1a",
.ops = &neo1973_voice_ops,
},
};
static struct snd_soc_card neo1973 = {
.name = "neo1973",
- .platform = &s3c24xx_soc_platform,
.dai_link = neo1973_dai,
.num_links = ARRAY_SIZE(neo1973_dai),
};
-static struct snd_soc_device neo1973_snd_devdata = {
- .card = &neo1973,
- .codec_dev = &soc_codec_dev_wm8753,
-};
-
static int lm4857_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -673,8 +671,7 @@ static int __init neo1973_init(void)
if (!neo1973_snd_device)
return -ENOMEM;
- platform_set_drvdata(neo1973_snd_device, &neo1973_snd_devdata);
- neo1973_snd_devdata.dev = &neo1973_snd_device->dev;
+ platform_set_drvdata(neo1973_snd_device, &neo1973);
ret = platform_device_add(neo1973_snd_device);
if (ret) {
diff --git a/sound/soc/s3c24xx/rx1950_uda1380.c b/sound/soc/s3c24xx/rx1950_uda1380.c
new file mode 100644
index 000000000000..ffd5cf2fb0a9
--- /dev/null
+++ b/sound/soc/s3c24xx/rx1950_uda1380.c
@@ -0,0 +1,333 @@
+/*
+ * rx1950.c -- ALSA Soc Audio Layer
+ *
+ * Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ * Based on smdk2440.c and magician.c
+ *
+ * Authors: Graeme Gregory graeme.gregory@wolfsonmicro.com
+ * Philipp Zabel <philipp.zabel@gmail.com>
+ * Denis Grigoriev <dgreenday@gmail.com>
+ * Vasily Khoruzhick <anarsoul@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 (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/uda1380.h>
+#include <sound/jack.h>
+
+#include <plat/regs-iis.h>
+
+#include <mach/regs-clock.h>
+
+#include <asm/mach-types.h>
+
+#include "s3c-dma.h"
+#include "s3c24xx-i2s.h"
+#include "../codecs/uda1380.h"
+
+static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd);
+static int rx1950_startup(struct snd_pcm_substream *substream);
+static int rx1950_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params);
+static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+
+static unsigned int rates[] = {
+ 16000,
+ 44100,
+ 48000,
+ 88200,
+};
+
+static struct snd_pcm_hw_constraint_list hw_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static struct snd_soc_jack hp_jack;
+
+static struct snd_soc_jack_pin hp_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Speaker",
+ .mask = SND_JACK_HEADPHONE,
+ .invert = 1,
+ },
+};
+
+static struct snd_soc_jack_gpio hp_jack_gpios[] = {
+ [0] = {
+ .gpio = S3C2410_GPG(12),
+ .name = "hp-gpio",
+ .report = SND_JACK_HEADPHONE,
+ .invert = 1,
+ .debounce_time = 200,
+ },
+};
+
+static struct snd_soc_ops rx1950_ops = {
+ .startup = rx1950_startup,
+ .hw_params = rx1950_hw_params,
+};
+
+/* s3c24xx digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link rx1950_uda1380_dai[] = {
+ {
+ .name = "uda1380",
+ .stream_name = "UDA1380 Duplex",
+ .cpu_dai_name = "s3c24xx-iis",
+ .codec_dai_name = "uda1380-hifi",
+ .init = rx1950_uda1380_init,
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "uda1380-codec.0-001a",
+ .ops = &rx1950_ops,
+ },
+};
+
+static struct snd_soc_card rx1950_asoc = {
+ .name = "rx1950",
+ .dai_link = rx1950_uda1380_dai,
+ .num_links = ARRAY_SIZE(rx1950_uda1380_dai),
+};
+
+/* rx1950 machine dapm widgets */
+static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("Speaker", rx1950_spk_power),
+};
+
+/* rx1950 machine audio_map */
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* headphone connected to VOUTLHP, VOUTRHP */
+ {"Headphone Jack", NULL, "VOUTLHP"},
+ {"Headphone Jack", NULL, "VOUTRHP"},
+
+ /* ext speaker connected to VOUTL, VOUTR */
+ {"Speaker", NULL, "VOUTL"},
+ {"Speaker", NULL, "VOUTR"},
+
+ /* mic is connected to VINM */
+ {"VINM", NULL, "Mic Jack"},
+};
+
+static struct platform_device *s3c24xx_snd_device;
+static struct clk *xtal;
+
+static int rx1950_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ runtime->hw.rate_min = hw_rates.list[0];
+ runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1];
+ runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
+
+ return snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &hw_rates);
+}
+
+static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ gpio_set_value(S3C2410_GPA(1), 1);
+ else
+ gpio_set_value(S3C2410_GPA(1), 0);
+
+ return 0;
+}
+
+static int rx1950_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int div;
+ int ret;
+ unsigned int rate = params_rate(params);
+ int clk_source, fs_mode;
+
+ switch (rate) {
+ case 16000:
+ case 48000:
+ clk_source = S3C24XX_CLKSRC_PCLK;
+ fs_mode = S3C2410_IISMOD_256FS;
+ div = s3c24xx_i2s_get_clockrate() / (256 * rate);
+ if (s3c24xx_i2s_get_clockrate() % (256 * rate) > (128 * rate))
+ div++;
+ break;
+ case 44100:
+ case 88200:
+ clk_source = S3C24XX_CLKSRC_MPLL;
+ fs_mode = S3C2410_IISMOD_256FS;
+ div = clk_get_rate(xtal) / (256 * rate);
+ if (clk_get_rate(xtal) % (256 * rate) > (128 * rate))
+ div++;
+ break;
+ default:
+ printk(KERN_ERR "%s: rate %d is not supported\n",
+ __func__, rate);
+ return -EINVAL;
+ }
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* select clock source */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source, rate,
+ SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ return ret;
+
+ /* set MCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+ S3C2410_IISMOD_384FS);
+ if (ret < 0)
+ return ret;
+
+ /* set BCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
+ S3C2410_IISMOD_32FS);
+ if (ret < 0)
+ return ret;
+
+ /* set prescaler division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+ S3C24XX_PRESCALE(div, div));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int err;
+
+ /* Add rx1950 specific widgets */
+ err = snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets,
+ ARRAY_SIZE(uda1380_dapm_widgets));
+
+ if (err)
+ return err;
+
+ /* Set up rx1950 specific audio path audio_mapnects */
+ err = snd_soc_dapm_add_routes(codec, audio_map,
+ ARRAY_SIZE(audio_map));
+
+ if (err)
+ return err;
+
+ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+ snd_soc_dapm_enable_pin(codec, "Speaker");
+
+ snd_soc_dapm_sync(codec);
+
+ snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
+ &hp_jack);
+
+ snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
+ hp_jack_pins);
+
+ snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+ hp_jack_gpios);
+
+ return 0;
+}
+
+static int __init rx1950_init(void)
+{
+ int ret;
+
+ if (!machine_is_rx1950())
+ return -ENODEV;
+
+ /* configure some gpios */
+ ret = gpio_request(S3C2410_GPA(1), "speaker-power");
+ if (ret)
+ goto err_gpio;
+
+ ret = gpio_direction_output(S3C2410_GPA(1), 0);
+ if (ret)
+ goto err_gpio_conf;
+
+ s3c24xx_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!s3c24xx_snd_device) {
+ ret = -ENOMEM;
+ goto err_plat_alloc;
+ }
+
+ platform_set_drvdata(s3c24xx_snd_device, &rx1950_asoc);
+ ret = platform_device_add(s3c24xx_snd_device);
+
+ if (ret) {
+ platform_device_put(s3c24xx_snd_device);
+ goto err_plat_add;
+ }
+
+ xtal = clk_get(&s3c24xx_snd_device->dev, "xtal");
+
+ if (IS_ERR(xtal)) {
+ ret = PTR_ERR(xtal);
+ platform_device_unregister(s3c24xx_snd_device);
+ goto err_clk;
+ }
+
+ return 0;
+
+err_clk:
+err_plat_add:
+err_plat_alloc:
+err_gpio_conf:
+ gpio_free(S3C2410_GPA(1));
+
+err_gpio:
+ return ret;
+}
+
+static void __exit rx1950_exit(void)
+{
+ platform_device_unregister(s3c24xx_snd_device);
+ snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+ hp_jack_gpios);
+ clk_put(xtal);
+ gpio_free(S3C2410_GPA(1));
+}
+
+module_init(rx1950_init);
+module_exit(rx1950_exit);
+
+/* Module information */
+MODULE_AUTHOR("Vasily Khoruzhick");
+MODULE_DESCRIPTION("ALSA SoC RX1950");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c-ac97.c b/sound/soc/s3c24xx/s3c-ac97.c
index 31f6d45b6384..f891eb79b575 100644
--- a/sound/soc/s3c24xx/s3c-ac97.c
+++ b/sound/soc/s3c24xx/s3c-ac97.c
@@ -89,7 +89,7 @@ static void s3c_ac97_activate(struct snd_ac97 *ac97)
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
- printk(KERN_ERR "AC97: Unable to activate!");
+ pr_err("AC97: Unable to activate!");
}
static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
@@ -115,14 +115,15 @@ static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
- printk(KERN_ERR "AC97: Unable to read!");
+ pr_err("AC97: Unable to read!");
stat = readl(s3c_ac97.regs + S3C_AC97_STAT);
addr = (stat >> 16) & 0x7f;
data = (stat & 0xffff);
if (addr != reg)
- printk(KERN_ERR "s3c-ac97: req addr = %02x, rep addr = %02x\n", reg, addr);
+ pr_err("s3c-ac97: req addr = %02x, rep addr = %02x\n",
+ reg, addr);
mutex_unlock(&s3c_ac97.lock);
@@ -151,7 +152,7 @@ static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
- printk(KERN_ERR "AC97: Unable to write!");
+ pr_err("AC97: Unable to write!");
ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
@@ -162,6 +163,7 @@ static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
static void s3c_ac97_cold_reset(struct snd_ac97 *ac97)
{
+ pr_debug("AC97: Cold reset\n");
writel(S3C_AC97_GLBCTRL_COLDRESET,
s3c_ac97.regs + S3C_AC97_GLBCTRL);
msleep(1);
@@ -178,6 +180,8 @@ static void s3c_ac97_warm_reset(struct snd_ac97 *ac97)
if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
return; /* Return if already active */
+ pr_debug("AC97: Warm reset\n");
+
writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL);
msleep(1);
@@ -222,7 +226,7 @@ static int s3c_ac97_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct s3c_dma_params *dma_data;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -241,7 +245,7 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
u32 ac_glbctrl;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
@@ -277,7 +281,7 @@ static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
return -ENODEV;
@@ -293,7 +297,7 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
u32 ac_glbctrl;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK;
@@ -328,10 +332,9 @@ static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
.trigger = s3c_ac97_mic_trigger,
};
-struct snd_soc_dai s3c_ac97_dai[] = {
+static struct snd_soc_dai_driver s3c_ac97_dai[] = {
[S3C_AC97_DAI_PCM] = {
.name = "s3c-ac97",
- .id = S3C_AC97_DAI_PCM,
.ac97_control = 1,
.playback = {
.stream_name = "AC97 Playback",
@@ -349,7 +352,6 @@ struct snd_soc_dai s3c_ac97_dai[] = {
},
[S3C_AC97_DAI_MIC] = {
.name = "s3c-ac97-mic",
- .id = S3C_AC97_DAI_MIC,
.ac97_control = 1,
.capture = {
.stream_name = "AC97 Mic Capture",
@@ -360,7 +362,6 @@ struct snd_soc_dai s3c_ac97_dai[] = {
.ops = &s3c_ac97_mic_dai_ops,
},
};
-EXPORT_SYMBOL_GPL(s3c_ac97_dai);
static __devinit int s3c_ac97_probe(struct platform_device *pdev)
{
@@ -445,14 +446,12 @@ static __devinit int s3c_ac97_probe(struct platform_device *pdev)
ret = request_irq(irq_res->start, s3c_ac97_irq,
IRQF_DISABLED, "AC97", NULL);
if (ret < 0) {
- printk(KERN_ERR "s3c-ac97: interrupt request failed.\n");
+ dev_err(&pdev->dev, "s3c-ac97: interrupt request failed.\n");
goto err4;
}
- s3c_ac97_dai[S3C_AC97_DAI_PCM].dev = &pdev->dev;
- s3c_ac97_dai[S3C_AC97_DAI_MIC].dev = &pdev->dev;
-
- ret = snd_soc_register_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
+ ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai,
+ ARRAY_SIZE(s3c_ac97_dai));
if (ret)
goto err5;
@@ -476,7 +475,7 @@ static __devexit int s3c_ac97_remove(struct platform_device *pdev)
{
struct resource *mem_res, *irq_res;
- snd_soc_unregister_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (irq_res)
@@ -518,3 +517,4 @@ module_exit(s3c_ac97_exit);
MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c-ac97");
diff --git a/sound/soc/s3c24xx/s3c-ac97.h b/sound/soc/s3c24xx/s3c-ac97.h
index 278198379def..5dcedd07fdbb 100644
--- a/sound/soc/s3c24xx/s3c-ac97.h
+++ b/sound/soc/s3c24xx/s3c-ac97.h
@@ -18,6 +18,4 @@
#define S3C_AC97_DAI_PCM 0
#define S3C_AC97_DAI_MIC 1
-extern struct snd_soc_dai s3c_ac97_dai[];
-
#endif /* __S3C_AC97_H_ */
diff --git a/sound/soc/s3c24xx/s3c-dma.c b/sound/soc/s3c24xx/s3c-dma.c
index f1b1bc4bacfb..243f79bf43bb 100644
--- a/sound/soc/s3c24xx/s3c-dma.c
+++ b/sound/soc/s3c24xx/s3c-dma.c
@@ -146,7 +146,7 @@ static int s3c_dma_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
unsigned long totbytes = params_buffer_bytes(params);
struct s3c_dma_params *dma =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
int ret = 0;
@@ -440,14 +440,14 @@ static int s3c_dma_new(struct snd_card *card,
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = 0xffffffff;
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = s3c_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = s3c_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -457,26 +457,46 @@ static int s3c_dma_new(struct snd_card *card,
return ret;
}
-struct snd_soc_platform s3c24xx_soc_platform = {
- .name = "s3c24xx-audio",
- .pcm_ops = &s3c_dma_ops,
+static struct snd_soc_platform_driver s3c24xx_soc_platform = {
+ .ops = &s3c_dma_ops,
.pcm_new = s3c_dma_new,
.pcm_free = s3c_dma_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(s3c24xx_soc_platform);
-static int __init s3c24xx_soc_platform_init(void)
+static int __devinit s3c24xx_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&s3c24xx_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &s3c24xx_soc_platform);
}
-module_init(s3c24xx_soc_platform_init);
-static void __exit s3c24xx_soc_platform_exit(void)
+static int __devexit s3c24xx_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&s3c24xx_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver s3c24xx_pcm_driver = {
+ .driver = {
+ .name = "s3c24xx-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = s3c24xx_soc_platform_probe,
+ .remove = __devexit_p(s3c24xx_soc_platform_remove),
+};
+
+static int __init snd_s3c24xx_pcm_init(void)
+{
+ return platform_driver_register(&s3c24xx_pcm_driver);
+}
+module_init(snd_s3c24xx_pcm_init);
+
+static void __exit snd_s3c24xx_pcm_exit(void)
+{
+ platform_driver_unregister(&s3c24xx_pcm_driver);
}
-module_exit(s3c24xx_soc_platform_exit);
+module_exit(snd_s3c24xx_pcm_exit);
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_DESCRIPTION("Samsung S3C Audio DMA module");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c24xx-pcm-audio");
diff --git a/sound/soc/s3c24xx/s3c-dma.h b/sound/soc/s3c24xx/s3c-dma.h
index 69bb6bf6fc1c..748c07d7c075 100644
--- a/sound/soc/s3c24xx/s3c-dma.h
+++ b/sound/soc/s3c24xx/s3c-dma.h
@@ -25,7 +25,6 @@ struct s3c_dma_params {
#define S3C24XX_DAI_I2S 0
/* platform data */
-extern struct snd_soc_platform s3c24xx_soc_platform;
extern struct snd_ac97_bus_ops s3c24xx_ac97_ops;
#endif
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
index 64376b2aac73..b3866d5b19e9 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -49,7 +49,7 @@
static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
{
- return cpu_dai->private_data;
+ return snd_soc_dai_get_drvdata(cpu_dai);
}
#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
@@ -307,11 +307,9 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
- struct snd_soc_dai *socdai)
+ struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai_link *dai = rtd->dai;
- struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai);
+ struct s3c_i2sv2_info *i2s = to_info(dai);
struct s3c_dma_params *dma_data;
u32 iismod;
@@ -322,7 +320,7 @@ static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
else
dma_data = i2s->dma_capture;
- snd_soc_dai_set_dma_data(dai->cpu_dai, substream, dma_data);
+ snd_soc_dai_set_dma_data(dai, substream, dma_data);
/* Working copies of register */
iismod = readl(i2s->regs + S3C2412_IISMOD);
@@ -396,12 +394,12 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c_i2sv2_info *i2s = to_info(rtd->dai->cpu_dai);
+ struct s3c_i2sv2_info *i2s = to_info(rtd->cpu_dai);
int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
unsigned long irqs;
int ret = 0;
struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
pr_debug("Entered %s\n", __func__);
@@ -640,36 +638,17 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
}
EXPORT_SYMBOL_GPL(s3c_i2sv2_iis_calc_rate);
-int s3c_i2sv2_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai,
+int s3c_i2sv2_probe(struct snd_soc_dai *dai,
struct s3c_i2sv2_info *i2s,
unsigned long base)
{
- struct device *dev = &pdev->dev;
+ struct device *dev = dai->dev;
unsigned int iismod;
i2s->dev = dev;
/* record our i2s structure for later use in the callbacks */
- dai->private_data = i2s;
-
- if (!base) {
- struct resource *res = platform_get_resource(pdev,
- IORESOURCE_MEM,
- 0);
- if (!res) {
- dev_err(dev, "Unable to get register resource\n");
- return -ENXIO;
- }
-
- if (!request_mem_region(res->start, resource_size(res),
- "s3c64xx-i2s-v4")) {
- dev_err(dev, "Unable to request register region\n");
- return -EBUSY;
- }
-
- base = res->start;
- }
+ snd_soc_dai_set_drvdata(dai, i2s);
i2s->regs = ioremap(base, 0x100);
if (i2s->regs == NULL) {
@@ -752,9 +731,10 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
#define s3c2412_i2s_resume NULL
#endif
-int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
+int s3c_i2sv2_register_dai(struct device *dev, int id,
+ struct snd_soc_dai_driver *drv)
{
- struct snd_soc_dai_ops *ops = dai->ops;
+ struct snd_soc_dai_ops *ops = drv->ops;
ops->trigger = s3c2412_i2s_trigger;
if (!ops->hw_params)
@@ -767,10 +747,10 @@ int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
if (!ops->delay)
ops->delay = s3c2412_i2s_delay;
- dai->suspend = s3c2412_i2s_suspend;
- dai->resume = s3c2412_i2s_resume;
+ drv->suspend = s3c2412_i2s_suspend;
+ drv->resume = s3c2412_i2s_resume;
- return snd_soc_register_dai(dai);
+ return snd_soc_register_dai(dev, drv);
}
EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h
index 766f43a13d8b..d45830151484 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.h
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.h
@@ -66,6 +66,8 @@ struct s3c_i2sv2_info {
u32 suspend_iismod;
u32 suspend_iiscon;
u32 suspend_iispsr;
+
+ unsigned long base;
};
extern struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai);
@@ -81,23 +83,24 @@ extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
/**
* s3c_i2sv2_probe - probe for i2s device helper
- * @pdev: The platform device supplied to the original probe.
* @dai: The ASoC DAI structure supplied to the original probe.
* @i2s: Our local i2s structure to fill in.
* @base: The base address for the registers.
*/
-extern int s3c_i2sv2_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai,
+extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
struct s3c_i2sv2_info *i2s,
unsigned long base);
/**
* s3c_i2sv2_register_dai - register dai with soc core
- * @dai: The snd_soc_dai structure to register
+ * @dev: DAI device
+ * @id: DAI ID
+ * @drv: The driver structure to register
*
* Fill in any missing fields and then register the given dai with the
* soc core.
*/
-extern int s3c_i2sv2_register_dai(struct snd_soc_dai *dai);
+extern int s3c_i2sv2_register_dai(struct device *dev, int id,
+ struct snd_soc_dai_driver *drv);
#endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
diff --git a/sound/soc/s3c24xx/s3c-pcm.c b/sound/soc/s3c24xx/s3c-pcm.c
index 326f0a9e7e30..2e020e1b4eab 100644
--- a/sound/soc/s3c24xx/s3c-pcm.c
+++ b/sound/soc/s3c24xx/s3c-pcm.c
@@ -64,11 +64,6 @@ static struct s3c_dma_params s3c_pcm_stereo_in[] = {
static struct s3c_pcm_info s3c_pcm[2];
-static inline struct s3c_pcm_info *to_info(struct snd_soc_dai *cpu_dai)
-{
- return cpu_dai->private_data;
-}
-
static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
{
void __iomem *regs = pcm->regs;
@@ -83,7 +78,7 @@ static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
ctl |= S3C_PCM_CTL_TXDMA_EN;
ctl |= S3C_PCM_CTL_TXFIFO_EN;
ctl |= S3C_PCM_CTL_ENABLE;
- ctl |= (0x20<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
+ ctl |= (0x4<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
} else {
ctl &= ~S3C_PCM_CTL_TXDMA_EN;
@@ -107,11 +102,14 @@ static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
ctl = readl(regs + S3C_PCM_CTL);
clkctl = readl(regs + S3C_PCM_CLKCTL);
+ ctl &= ~(S3C_PCM_CTL_RXDIPSTICK_MASK
+ << S3C_PCM_CTL_RXDIPSTICK_SHIFT);
if (on) {
ctl |= S3C_PCM_CTL_RXDMA_EN;
ctl |= S3C_PCM_CTL_RXFIFO_EN;
ctl |= S3C_PCM_CTL_ENABLE;
+ ctl |= (0x20<<S3C_PCM_CTL_RXDIPSTICK_SHIFT);
clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
} else {
ctl &= ~S3C_PCM_CTL_RXDMA_EN;
@@ -132,7 +130,7 @@ static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c_pcm_info *pcm = to_info(rtd->dai->cpu_dai);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
unsigned long flags;
dev_dbg(pcm->dev, "Entered %s\n", __func__);
@@ -176,8 +174,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *socdai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai_link *dai = rtd->dai;
- struct s3c_pcm_info *pcm = to_info(dai->cpu_dai);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct s3c_dma_params *dma_data;
void __iomem *regs = pcm->regs;
struct clk *clk;
@@ -192,7 +189,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
else
dma_data = pcm->dma_capture;
- snd_soc_dai_set_dma_data(dai->cpu_dai, substream, dma_data);
+ snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
/* Strictly check for sample size */
switch (params_format(params)) {
@@ -242,7 +239,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct s3c_pcm_info *pcm = to_info(cpu_dai);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
void __iomem *regs = pcm->regs;
unsigned long flags;
int ret = 0;
@@ -313,7 +310,7 @@ exit:
static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div)
{
- struct s3c_pcm_info *pcm = to_info(cpu_dai);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
switch (div_id) {
case S3C_PCM_SCLK_PER_FS:
@@ -330,7 +327,7 @@ static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
- struct s3c_pcm_info *pcm = to_info(cpu_dai);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
void __iomem *regs = pcm->regs;
u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
@@ -366,10 +363,7 @@ static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000
-#define S3C_PCM_DECLARE(n) \
-{ \
- .name = "samsung-pcm", \
- .id = (n), \
+#define S3C_PCM_DAI_DECLARE \
.symmetric_rates = 1, \
.ops = &s3c_pcm_dai_ops, \
.playback = { \
@@ -383,19 +377,23 @@ static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
.channels_max = 2, \
.rates = S3C_PCM_RATES, \
.formats = SNDRV_PCM_FMTBIT_S16_LE, \
- }, \
-}
+ }
-struct snd_soc_dai s3c_pcm_dai[] = {
- S3C_PCM_DECLARE(0),
- S3C_PCM_DECLARE(1),
+struct snd_soc_dai_driver s3c_pcm_dai[] = {
+ [0] = {
+ .name = "samsung-pcm.0",
+ S3C_PCM_DAI_DECLARE,
+ },
+ [1] = {
+ .name = "samsung-pcm.1",
+ S3C_PCM_DAI_DECLARE,
+ },
};
EXPORT_SYMBOL_GPL(s3c_pcm_dai);
static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
{
struct s3c_pcm_info *pcm;
- struct snd_soc_dai *dai;
struct resource *mem_res, *dmatx_res, *dmarx_res;
struct s3c_audio_pdata *pcm_pdata;
int ret;
@@ -437,9 +435,6 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
spin_lock_init(&pcm->lock);
- dai = &s3c_pcm_dai[pdev->id];
- dai->dev = &pdev->dev;
-
/* Default is 128fs */
pcm->sclk_per_fs = 128;
@@ -452,7 +447,7 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
clk_enable(pcm->cclk);
/* record our pcm structure for later use in the callbacks */
- dai->private_data = pcm;
+ dev_set_drvdata(&pdev->dev, pcm);
if (!request_mem_region(mem_res->start,
resource_size(mem_res), "samsung-pcm")) {
@@ -476,7 +471,7 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
}
clk_enable(pcm->pclk);
- ret = snd_soc_register_dai(dai);
+ ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
if (ret != 0) {
dev_err(&pdev->dev, "failed to get pcm_clock\n");
goto err5;
@@ -514,6 +509,8 @@ static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev)
struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
struct resource *mem_res;
+ snd_soc_unregister_dai(&pdev->dev);
+
iounmap(pcm->regs);
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -552,3 +549,4 @@ module_exit(s3c_pcm_exit);
MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
MODULE_DESCRIPTION("S3C PCM Controller Driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-pcm");
diff --git a/sound/soc/s3c24xx/s3c-pcm.h b/sound/soc/s3c24xx/s3c-pcm.h
index 69ff9971692f..f60baa19387d 100644
--- a/sound/soc/s3c24xx/s3c-pcm.h
+++ b/sound/soc/s3c24xx/s3c-pcm.h
@@ -22,7 +22,8 @@
/* PCM_CTL Bit-Fields */
#define S3C_PCM_CTL_TXDIPSTICK_MASK (0x3f)
#define S3C_PCM_CTL_TXDIPSTICK_SHIFT (13)
-#define S3C_PCM_CTL_RXDIPSTICK_MSK (0x3f<<7)
+#define S3C_PCM_CTL_RXDIPSTICK_MASK (0x3f)
+#define S3C_PCM_CTL_RXDIPSTICK_SHIFT (7)
#define S3C_PCM_CTL_TXDMA_EN (0x1<<6)
#define S3C_PCM_CTL_RXDMA_EN (0x1<<5)
#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1<<4)
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
index 709adef9d043..4a861cfa52c5 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.c
+++ b/sound/soc/s3c24xx/s3c2412-i2s.c
@@ -65,26 +65,20 @@ static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
static struct s3c_i2sv2_info s3c2412_i2s;
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
-{
- return cpu_dai->private_data;
-}
-
-static int s3c2412_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
{
int ret;
pr_debug("Entered %s\n", __func__);
- ret = s3c_i2sv2_probe(pdev, dai, &s3c2412_i2s, S3C2410_PA_IIS);
+ ret = s3c_i2sv2_probe(dai, &s3c2412_i2s, S3C2410_PA_IIS);
if (ret)
return ret;
s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in;
s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out;
- s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk");
+ s3c2412_i2s.iis_cclk = clk_get(dai->dev, "i2sclk");
if (s3c2412_i2s.iis_cclk == NULL) {
pr_err("failed to get i2sclk clock\n");
iounmap(s3c2412_i2s.regs);
@@ -108,11 +102,20 @@ static int s3c2412_i2s_probe(struct platform_device *pdev,
return 0;
}
+static int s3c2412_i2s_remove(struct snd_soc_dai *dai)
+{
+ clk_disable(s3c2412_i2s.iis_cclk);
+ clk_put(s3c2412_i2s.iis_cclk);
+ iounmap(s3c2412_i2s.regs);
+
+ return 0;
+}
+
static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+ struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
struct s3c_dma_params *dma_data;
u32 iismod;
@@ -152,10 +155,9 @@ static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
.hw_params = s3c2412_i2s_hw_params,
};
-struct snd_soc_dai s3c2412_i2s_dai = {
- .name = "s3c2412-i2s",
- .id = 0,
+static struct snd_soc_dai_driver s3c2412_i2s_dai = {
.probe = s3c2412_i2s_probe,
+ .remove = s3c2412_i2s_remove,
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -170,17 +172,36 @@ struct snd_soc_dai s3c2412_i2s_dai = {
},
.ops = &s3c2412_i2s_dai_ops,
};
-EXPORT_SYMBOL_GPL(s3c2412_i2s_dai);
+
+static __devinit int s3c2412_iis_dev_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &s3c2412_i2s_dai);
+}
+
+static __devexit int s3c2412_iis_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver s3c2412_iis_driver = {
+ .probe = s3c2412_iis_dev_probe,
+ .remove = s3c2412_iis_dev_remove,
+ .driver = {
+ .name = "s3c2412-iis",
+ .owner = THIS_MODULE,
+ },
+};
static int __init s3c2412_i2s_init(void)
{
- return s3c_i2sv2_register_dai(&s3c2412_i2s_dai);
+ return platform_driver_register(&s3c2412_iis_driver);
}
module_init(s3c2412_i2s_init);
static void __exit s3c2412_i2s_exit(void)
{
- snd_soc_unregister_dai(&s3c2412_i2s_dai);
+ platform_driver_unregister(&s3c2412_iis_driver);
}
module_exit(s3c2412_i2s_exit);
@@ -188,3 +209,4 @@ module_exit(s3c2412_i2s_exit);
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c2412-iis");
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h
index 0b5686b4d5c3..01a0471ac65c 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.h
+++ b/sound/soc/s3c24xx/s3c2412-i2s.h
@@ -24,6 +24,4 @@
#define S3C2412_CLKSRC_PCLK S3C_I2SV2_CLKSRC_PCLK
#define S3C2412_CLKSRC_I2SCLK S3C_I2SV2_CLKSRC_AUDIOBUS
-extern struct snd_soc_dai s3c2412_i2s_dai;
-
#endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
index c3ac890a3986..e060daaa458f 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c
@@ -252,7 +252,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
else
dma_data = &s3c24xx_i2s_pcm_stereo_in;
- snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream, dma_data);
+ snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
/* Working copies of register */
iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
@@ -280,9 +280,8 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
int ret = 0;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(dai, substream);
pr_debug("Entered %s\n", __func__);
@@ -387,8 +386,7 @@ u32 s3c24xx_i2s_get_clockrate(void)
}
EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
-static int s3c24xx_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
{
pr_debug("Entered %s\n", __func__);
@@ -396,7 +394,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev,
if (s3c24xx_i2s.regs == NULL)
return -ENXIO;
- s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis");
+ s3c24xx_i2s.iis_clk = clk_get(dai->dev, "iis");
if (s3c24xx_i2s.iis_clk == NULL) {
pr_err("failed to get iis_clock\n");
iounmap(s3c24xx_i2s.regs);
@@ -465,9 +463,7 @@ static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
.set_sysclk = s3c24xx_i2s_set_sysclk,
};
-struct snd_soc_dai s3c24xx_i2s_dai = {
- .name = "s3c24xx-i2s",
- .id = 0,
+static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
.probe = s3c24xx_i2s_probe,
.suspend = s3c24xx_i2s_suspend,
.resume = s3c24xx_i2s_resume,
@@ -483,17 +479,36 @@ struct snd_soc_dai s3c24xx_i2s_dai = {
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
.ops = &s3c24xx_i2s_dai_ops,
};
-EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai);
+
+static __devinit int s3c24xx_iis_dev_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai);
+}
+
+static __devexit int s3c24xx_iis_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver s3c24xx_iis_driver = {
+ .probe = s3c24xx_iis_dev_probe,
+ .remove = s3c24xx_iis_dev_remove,
+ .driver = {
+ .name = "s3c24xx-iis",
+ .owner = THIS_MODULE,
+ },
+};
static int __init s3c24xx_i2s_init(void)
{
- return snd_soc_register_dai(&s3c24xx_i2s_dai);
+ return platform_driver_register(&s3c24xx_iis_driver);
}
module_init(s3c24xx_i2s_init);
static void __exit s3c24xx_i2s_exit(void)
{
- snd_soc_unregister_dai(&s3c24xx_i2s_dai);
+ platform_driver_unregister(&s3c24xx_iis_driver);
}
module_exit(s3c24xx_i2s_exit);
@@ -501,3 +516,4 @@ module_exit(s3c24xx_i2s_exit);
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_DESCRIPTION("s3c24xx I2S SoC Interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c24xx-iis");
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.h b/sound/soc/s3c24xx/s3c24xx-i2s.h
index 726d91cf4e1c..f9ca04edacb7 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.h
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.h
@@ -32,6 +32,4 @@
u32 s3c24xx_i2s_get_clockrate(void);
-extern struct snd_soc_dai s3c24xx_i2s_dai;
-
#endif /*S3C24XXI2S_H_*/
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c
index 4984754f3298..c4c111442010 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec.c
@@ -139,8 +139,10 @@ static const struct snd_kcontrol_new amp_unmute_controls[] = {
speaker_unmute_get, speaker_unmute_put),
};
-void simtec_audio_init(struct snd_soc_codec *codec)
+void simtec_audio_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
if (pdata->amp_gpio > 0) {
pr_debug("%s: adding amp routes\n", __func__);
@@ -170,8 +172,8 @@ static int simtec_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set the CODEC as the bus clock master, I2S */
@@ -319,12 +321,12 @@ EXPORT_SYMBOL_GPL(simtec_audio_pmops);
#endif
int __devinit simtec_audio_core_probe(struct platform_device *pdev,
- struct snd_soc_device *socdev)
+ struct snd_soc_card *card)
{
struct platform_device *snd_dev;
int ret;
- socdev->card->dai_link->ops = &simtec_snd_ops;
+ card->dai_link->ops = &simtec_snd_ops;
pdata = pdev->dev.platform_data;
if (!pdata) {
@@ -353,8 +355,7 @@ int __devinit simtec_audio_core_probe(struct platform_device *pdev,
goto err_gpio;
}
- platform_set_drvdata(snd_dev, socdev);
- socdev->dev = &snd_dev->dev;
+ platform_set_drvdata(snd_dev, card);
ret = platform_device_add(snd_dev);
if (ret) {
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.h b/sound/soc/s3c24xx/s3c24xx_simtec.h
index e18faee30cce..e63d5ff9c41f 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec.h
+++ b/sound/soc/s3c24xx/s3c24xx_simtec.h
@@ -7,10 +7,10 @@
* published by the Free Software Foundation.
*/
-extern void simtec_audio_init(struct snd_soc_codec *codec);
+extern void simtec_audio_init(struct snd_soc_pcm_runtime *rtd);
extern int simtec_audio_core_probe(struct platform_device *pdev,
- struct snd_soc_device *socdev);
+ struct snd_soc_card *card);
extern int simtec_audio_remove(struct platform_device *pdev);
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
index bdf8951af8e3..f88453735ae2 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
@@ -73,8 +73,10 @@ static const struct snd_soc_dapm_route base_map[] = {
* Attach our controls and configure the necessary codec
* mappings for our sound card instance.
*/
-static int simtec_hermes_init(struct snd_soc_codec *codec)
+static int simtec_hermes_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_new_controls(codec, dapm_widgets,
ARRAY_SIZE(dapm_widgets));
@@ -85,42 +87,33 @@ static int simtec_hermes_init(struct snd_soc_codec *codec)
snd_soc_dapm_enable_pin(codec, "Line Out");
snd_soc_dapm_enable_pin(codec, "Mic Jack");
- simtec_audio_init(codec);
+ simtec_audio_init(rtd);
snd_soc_dapm_sync(codec);
return 0;
}
-static struct aic3x_setup_data codec_setup = {
-};
-
static struct snd_soc_dai_link simtec_dai_aic33 = {
.name = "tlv320aic33",
.stream_name = "TLV320AIC33",
- .cpu_dai = &s3c24xx_i2s_dai,
- .codec_dai = &aic3x_dai,
+ .codec_name = "tlv320aic3x-codec.0-0x1a",
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
.init = simtec_hermes_init,
};
/* simtec audio machine driver */
static struct snd_soc_card snd_soc_machine_simtec_aic33 = {
.name = "Simtec-Hermes",
- .platform = &s3c24xx_soc_platform,
.dai_link = &simtec_dai_aic33,
.num_links = 1,
};
-/* simtec audio subsystem */
-static struct snd_soc_device simtec_snd_devdata_aic33 = {
- .card = &snd_soc_machine_simtec_aic33,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &codec_setup,
-};
-
static int __devinit simtec_audio_hermes_probe(struct platform_device *pd)
{
dev_info(&pd->dev, "probing....\n");
- return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic33);
+ return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic33);
}
static struct platform_driver simtec_audio_hermes_platdrv = {
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
index 185c0acb5ce6..c0967593510d 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
@@ -62,8 +62,10 @@ static const struct snd_soc_dapm_route base_map[] = {
* Attach our controls and configure the necessary codec
* mappings for our sound card instance.
*/
-static int simtec_tlv320aic23_init(struct snd_soc_codec *codec)
+static int simtec_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_new_controls(codec, dapm_widgets,
ARRAY_SIZE(dapm_widgets));
@@ -74,7 +76,7 @@ static int simtec_tlv320aic23_init(struct snd_soc_codec *codec)
snd_soc_dapm_enable_pin(codec, "Line Out");
snd_soc_dapm_enable_pin(codec, "Mic Jack");
- simtec_audio_init(codec);
+ simtec_audio_init(rtd);
snd_soc_dapm_sync(codec);
return 0;
@@ -83,28 +85,23 @@ static int simtec_tlv320aic23_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link simtec_dai_aic23 = {
.name = "tlv320aic23",
.stream_name = "TLV320AIC23",
- .cpu_dai = &s3c24xx_i2s_dai,
- .codec_dai = &tlv320aic23_dai,
+ .codec_name = "tlv320aic3x-codec.0-0x1a",
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
.init = simtec_tlv320aic23_init,
};
/* simtec audio machine driver */
static struct snd_soc_card snd_soc_machine_simtec_aic23 = {
.name = "Simtec",
- .platform = &s3c24xx_soc_platform,
.dai_link = &simtec_dai_aic23,
.num_links = 1,
};
-/* simtec audio subsystem */
-static struct snd_soc_device simtec_snd_devdata_aic23 = {
- .card = &snd_soc_machine_simtec_aic23,
- .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd)
{
- return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic23);
+ return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic23);
}
static struct platform_driver simtec_audio_tlv320aic23_platdrv = {
diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c
index 052d59659c29..bd48ffbde880 100644
--- a/sound/soc/s3c24xx/s3c24xx_uda134x.c
+++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c
@@ -133,8 +133,8 @@ static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret = 0;
int clk_source, fs_mode;
@@ -227,14 +227,15 @@ static struct snd_soc_ops s3c24xx_uda134x_ops = {
static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
.name = "UDA134X",
.stream_name = "UDA134X",
- .codec_dai = &uda134x_dai,
- .cpu_dai = &s3c24xx_i2s_dai,
+ .codec_name = "uda134x-hifi",
+ .codec_dai_name = "uda134x-hifi",
+ .cpu_dai_name = "s3c24xx-i2s",
.ops = &s3c24xx_uda134x_ops,
+ .platform_name = "s3c24xx-pcm-audio",
};
static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
.name = "S3C24XX_UDA134X",
- .platform = &s3c24xx_soc_platform,
.dai_link = &s3c24xx_uda134x_dai_link,
.num_links = 1,
};
@@ -256,6 +257,7 @@ static void setmode(int v)
gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0);
}
+/* FIXME - This must be codec platform data but in which board file ?? */
static struct uda134x_platform_data s3c24xx_uda134x = {
.l3 = {
.setdat = setdat,
@@ -270,12 +272,6 @@ static struct uda134x_platform_data s3c24xx_uda134x = {
},
};
-static struct snd_soc_device s3c24xx_uda134x_snd_devdata = {
- .card = &snd_soc_s3c24xx_uda134x,
- .codec_dev = &soc_codec_dev_uda134x,
- .codec_data = &s3c24xx_uda134x,
-};
-
static int s3c24xx_uda134x_setup_pin(int pin, char *fun)
{
if (gpio_request(pin, "s3c24xx_uda134x") < 0) {
@@ -325,8 +321,7 @@ static int s3c24xx_uda134x_probe(struct platform_device *pdev)
}
platform_set_drvdata(s3c24xx_uda134x_snd_device,
- &s3c24xx_uda134x_snd_devdata);
- s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device->dev;
+ &snd_soc_s3c24xx_uda134x);
ret = platform_device_add(s3c24xx_uda134x_snd_device);
if (ret) {
printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s-v4.c b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
index 06db130030a1..a9628472ebfe 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
@@ -16,9 +16,7 @@
#include <sound/soc.h>
#include <sound/pcm_params.h>
-#include <mach/gpio-bank-c.h>
-#include <mach/gpio-bank-h.h>
-#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
#include <mach/map.h>
#include <mach/dma.h>
@@ -39,34 +37,23 @@ static struct s3c_dma_params s3c64xx_i2sv4_pcm_stereo_out;
static struct s3c_dma_params s3c64xx_i2sv4_pcm_stereo_in;
static struct s3c_i2sv2_info s3c64xx_i2sv4;
-struct snd_soc_dai s3c64xx_i2s_v4_dai;
-EXPORT_SYMBOL_GPL(s3c64xx_i2s_v4_dai);
-
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+static int s3c64xx_i2sv4_probe(struct snd_soc_dai *dai)
{
- return cpu_dai->private_data;
-}
+ struct s3c_i2sv2_info *i2s = &s3c64xx_i2sv4;
+ int ret = 0;
-static int s3c64xx_i2sv4_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
-{
- /* configure GPIO for i2s port */
- s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C64XX_GPC4_I2S_V40_DO0);
- s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C64XX_GPC5_I2S_V40_DO1);
- s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C64XX_GPC7_I2S_V40_DO2);
- s3c_gpio_cfgpin(S3C64XX_GPH(6), S3C64XX_GPH6_I2S_V40_BCLK);
- s3c_gpio_cfgpin(S3C64XX_GPH(7), S3C64XX_GPH7_I2S_V40_CDCLK);
- s3c_gpio_cfgpin(S3C64XX_GPH(8), S3C64XX_GPH8_I2S_V40_LRCLK);
- s3c_gpio_cfgpin(S3C64XX_GPH(9), S3C64XX_GPH9_I2S_V40_DI);
+ snd_soc_dai_set_drvdata(dai, i2s);
- return 0;
+ ret = s3c_i2sv2_probe(dai, i2s, i2s->base);
+
+ return ret;
}
static int s3c_i2sv4_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+ struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
struct s3c_dma_params *dma_data;
u32 iismod;
@@ -104,51 +91,79 @@ static struct snd_soc_dai_ops s3c64xx_i2sv4_dai_ops = {
.hw_params = s3c_i2sv4_hw_params,
};
+static struct snd_soc_dai_driver s3c64xx_i2s_v4_dai = {
+ .symmetric_rates = 1,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,
+ },
+ .probe = s3c64xx_i2sv4_probe,
+ .ops = &s3c64xx_i2sv4_dai_ops,
+};
+
static __devinit int s3c64xx_i2sv4_dev_probe(struct platform_device *pdev)
{
+ struct s3c_audio_pdata *i2s_pdata;
struct s3c_i2sv2_info *i2s;
- struct snd_soc_dai *dai;
+ struct resource *res;
int ret;
i2s = &s3c64xx_i2sv4;
- dai = &s3c64xx_i2s_v4_dai;
-
- if (dai->dev) {
- dev_dbg(dai->dev, "%s: \
- I2Sv4 instance already registered!\n", __func__);
- return -EBUSY;
- }
-
- dai->dev = &pdev->dev;
- dai->name = "s3c64xx-i2s-v4";
- dai->id = 0;
- dai->symmetric_rates = 1;
- dai->playback.channels_min = 2;
- dai->playback.channels_max = 2;
- dai->playback.rates = S3C64XX_I2S_RATES;
- dai->playback.formats = S3C64XX_I2S_FMTS;
- dai->capture.channels_min = 2;
- dai->capture.channels_max = 2;
- dai->capture.rates = S3C64XX_I2S_RATES;
- dai->capture.formats = S3C64XX_I2S_FMTS;
- dai->probe = s3c64xx_i2sv4_probe;
- dai->ops = &s3c64xx_i2sv4_dai_ops;
i2s->feature |= S3C_FEATURE_CDCLKCON;
i2s->dma_capture = &s3c64xx_i2sv4_pcm_stereo_in;
i2s->dma_playback = &s3c64xx_i2sv4_pcm_stereo_out;
- i2s->dma_capture->channel = DMACH_HSI_I2SV40_RX;
- i2s->dma_capture->dma_addr = S3C64XX_PA_IISV4 + S3C2412_IISRXD;
- i2s->dma_playback->channel = DMACH_HSI_I2SV40_TX;
- i2s->dma_playback->dma_addr = S3C64XX_PA_IISV4 + S3C2412_IISTXD;
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
+ return -ENXIO;
+ }
+ i2s->dma_playback->channel = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
+ return -ENXIO;
+ }
+ i2s->dma_capture->channel = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
+ return -ENXIO;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res),
+ "s3c64xx-i2s-v4")) {
+ dev_err(&pdev->dev, "Unable to request SFR region\n");
+ return -EBUSY;
+ }
+ i2s->dma_capture->dma_addr = res->start + S3C2412_IISRXD;
+ i2s->dma_playback->dma_addr = res->start + S3C2412_IISTXD;
i2s->dma_capture->client = &s3c64xx_dma_client_in;
i2s->dma_capture->dma_size = 4;
i2s->dma_playback->client = &s3c64xx_dma_client_out;
i2s->dma_playback->dma_size = 4;
+ i2s->base = res->start;
+
+ i2s_pdata = pdev->dev.platform_data;
+ if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure gpio\n");
+ return -EINVAL;
+ }
+
i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
if (IS_ERR(i2s->iis_cclk)) {
dev_err(&pdev->dev, "failed to get audio-bus\n");
@@ -158,19 +173,13 @@ static __devinit int s3c64xx_i2sv4_dev_probe(struct platform_device *pdev)
clk_enable(i2s->iis_cclk);
- ret = s3c_i2sv2_probe(pdev, dai, i2s, 0);
- if (ret)
- goto err_clk;
-
- ret = s3c_i2sv2_register_dai(dai);
+ ret = s3c_i2sv2_register_dai(&pdev->dev, pdev->id, &s3c64xx_i2s_v4_dai);
if (ret != 0)
goto err_i2sv2;
return 0;
err_i2sv2:
- /* Not implemented for I2Sv2 core yet */
-err_clk:
clk_put(i2s->iis_cclk);
err:
return ret;
@@ -178,7 +187,18 @@ err:
static __devexit int s3c64xx_i2sv4_dev_remove(struct platform_device *pdev)
{
- dev_err(&pdev->dev, "Device removal not yet supported\n");
+ struct s3c_i2sv2_info *i2s = &s3c64xx_i2sv4;
+ struct resource *res;
+
+ snd_soc_unregister_dai(&pdev->dev);
+ clk_put(i2s->iis_cclk);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+ else
+ dev_warn(&pdev->dev, "Unable to get I2S SFR address\n");
+
return 0;
}
@@ -207,3 +227,4 @@ module_exit(s3c64xx_i2sv4_exit);
MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
MODULE_DESCRIPTION("S3C64XX I2Sv4 SoC Interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c64xx-iis-v4");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
index 1d85cb85a7d2..ae7acb6c4f1d 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.c
@@ -12,15 +12,15 @@
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/io.h>
+#include <linux/slab.h>
#include <sound/soc.h>
-#include <mach/gpio-bank-d.h>
-#include <mach/gpio-bank-e.h>
-#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
#include <mach/map.h>
#include <mach/dma.h>
@@ -46,45 +46,107 @@ static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[MAX_I2SV3];
static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[MAX_I2SV3];
static struct s3c_i2sv2_info s3c64xx_i2s[MAX_I2SV3];
-struct snd_soc_dai s3c64xx_i2s_dai[MAX_I2SV3];
-EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai);
-
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai)
{
- return cpu_dai->private_data;
+ struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(dai);
+ u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
+
+ if (iismod & S3C2412_IISMOD_IMS_SYSMUX)
+ return i2s->iis_cclk;
+ else
+ return i2s->iis_pclk;
}
+EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock);
-static int s3c64xx_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int s3c64xx_i2s_probe(struct snd_soc_dai *dai)
{
- /* configure GPIO for i2s port */
- switch (dai->id) {
- case 0:
- s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK);
- s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK);
- s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_I2S0_LRCLK);
- s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_I2S0_DI);
- s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_I2S0_D0);
- break;
- case 1:
- s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_I2S1_CLK);
- s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_I2S1_CDCLK);
- s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
- s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
- s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
+ struct s3c_i2sv2_info *i2s;
+ int ret;
+
+ if (dai->id >= MAX_I2SV3) {
+ dev_err(dai->dev, "id %d out of range\n", dai->id);
+ return -EINVAL;
+ }
+
+ i2s = &s3c64xx_i2s[dai->id];
+ snd_soc_dai_set_drvdata(dai, i2s);
+
+ i2s->iis_cclk = clk_get(dai->dev, "audio-bus");
+ if (IS_ERR(i2s->iis_cclk)) {
+ dev_err(dai->dev, "failed to get audio-bus\n");
+ ret = PTR_ERR(i2s->iis_cclk);
+ goto err;
}
+ clk_enable(i2s->iis_cclk);
+
+ ret = s3c_i2sv2_probe(dai, i2s, i2s->base);
+ if (ret)
+ goto err_clk;
+
return 0;
+
+err_clk:
+ clk_disable(i2s->iis_cclk);
+ clk_put(i2s->iis_cclk);
+err:
+ kfree(i2s);
+ return ret;
}
+static int s3c64xx_i2s_remove(struct snd_soc_dai *dai)
+{
+ struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(dai);
+
+ clk_disable(i2s->iis_cclk);
+ clk_put(i2s->iis_cclk);
+ kfree(i2s);
+ return 0;
+}
static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops;
+static struct snd_soc_dai_driver s3c64xx_i2s_dai[MAX_I2SV3] = {
+{
+ .name = "s3c64xx-i2s-0",
+ .probe = s3c64xx_i2s_probe,
+ .remove = s3c64xx_i2s_remove,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,},
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,},
+ .ops = &s3c64xx_i2s_dai_ops,
+ .symmetric_rates = 1,
+}, {
+ .name = "s3c64xx-i2s-1",
+ .probe = s3c64xx_i2s_probe,
+ .remove = s3c64xx_i2s_remove,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,},
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,},
+ .ops = &s3c64xx_i2s_dai_ops,
+ .symmetric_rates = 1,
+},};
+
static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
{
+ struct s3c_audio_pdata *i2s_pdata;
struct s3c_i2sv2_info *i2s;
- struct snd_soc_dai *dai;
- int ret;
+ struct resource *res;
+ int i, ret;
if (pdev->id >= MAX_I2SV3) {
dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
@@ -92,74 +154,63 @@ static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
}
i2s = &s3c64xx_i2s[pdev->id];
- dai = &s3c64xx_i2s_dai[pdev->id];
- dai->dev = &pdev->dev;
- dai->name = "s3c64xx-i2s";
- dai->id = pdev->id;
- dai->symmetric_rates = 1;
- dai->playback.channels_min = 2;
- dai->playback.channels_max = 2;
- dai->playback.rates = S3C64XX_I2S_RATES;
- dai->playback.formats = S3C64XX_I2S_FMTS;
- dai->capture.channels_min = 2;
- dai->capture.channels_max = 2;
- dai->capture.rates = S3C64XX_I2S_RATES;
- dai->capture.formats = S3C64XX_I2S_FMTS;
- dai->probe = s3c64xx_i2s_probe;
- dai->ops = &s3c64xx_i2s_dai_ops;
-
- i2s->feature |= S3C_FEATURE_CDCLKCON;
i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
- if (pdev->id == 0) {
- i2s->dma_capture->channel = DMACH_I2S0_IN;
- i2s->dma_capture->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD;
- i2s->dma_playback->channel = DMACH_I2S0_OUT;
- i2s->dma_playback->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD;
- } else {
- i2s->dma_capture->channel = DMACH_I2S1_IN;
- i2s->dma_capture->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD;
- i2s->dma_playback->channel = DMACH_I2S1_OUT;
- i2s->dma_playback->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD;
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
+ return -ENXIO;
+ }
+ i2s->dma_playback->channel = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
+ return -ENXIO;
+ }
+ i2s->dma_capture->channel = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
+ return -ENXIO;
}
+ if (!request_mem_region(res->start, resource_size(res),
+ "s3c64xx-i2s")) {
+ dev_err(&pdev->dev, "Unable to request SFR region\n");
+ return -EBUSY;
+ }
+ i2s->base = res->start;
+
+ i2s_pdata = pdev->dev.platform_data;
+ if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure gpio\n");
+ return -EINVAL;
+ }
+ i2s->dma_capture->dma_addr = res->start + S3C2412_IISRXD;
+ i2s->dma_playback->dma_addr = res->start + S3C2412_IISTXD;
+
i2s->dma_capture->client = &s3c64xx_dma_client_in;
i2s->dma_capture->dma_size = 4;
i2s->dma_playback->client = &s3c64xx_dma_client_out;
i2s->dma_playback->dma_size = 4;
- i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
- if (IS_ERR(i2s->iis_cclk)) {
- dev_err(&pdev->dev, "failed to get audio-bus\n");
- ret = PTR_ERR(i2s->iis_cclk);
- goto err;
+ for (i = 0; i < ARRAY_SIZE(s3c64xx_i2s_dai); i++) {
+ ret = s3c_i2sv2_register_dai(&pdev->dev, i,
+ &s3c64xx_i2s_dai[i]);
+ if (ret != 0)
+ return ret;
}
- clk_enable(i2s->iis_cclk);
-
- ret = s3c_i2sv2_probe(pdev, dai, i2s, 0);
- if (ret)
- goto err_clk;
-
- ret = s3c_i2sv2_register_dai(dai);
- if (ret != 0)
- goto err_i2sv2;
-
return 0;
-
-err_i2sv2:
- /* Not implemented for I2Sv2 core yet */
-err_clk:
- clk_put(i2s->iis_cclk);
-err:
- return ret;
}
static __devexit int s3c64xx_iis_dev_remove(struct platform_device *pdev)
{
- dev_err(&pdev->dev, "Device removal not yet supported\n");
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c64xx_i2s_dai));
return 0;
}
@@ -188,3 +239,4 @@ module_exit(s3c64xx_i2s_exit);
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_DESCRIPTION("S3C64XX I2S SoC Interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c64xx-iis");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h
index 7a40f43d1d51..de4075d26f0c 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.h
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.h
@@ -36,7 +36,6 @@ struct clk;
(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE)
-extern struct snd_soc_dai s3c64xx_i2s_dai[];
-extern struct snd_soc_dai s3c64xx_i2s_v4_dai;
+struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai);
#endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */
diff --git a/sound/soc/s3c24xx/smartq_wm8987.c b/sound/soc/s3c24xx/smartq_wm8987.c
index b480348140b0..dd20ca7f4681 100644
--- a/sound/soc/s3c24xx/smartq_wm8987.c
+++ b/sound/soc/s3c24xx/smartq_wm8987.c
@@ -211,8 +211,10 @@ static struct snd_soc_dai_link smartq_dai[] = {
{
.name = "wm8987",
.stream_name = "SmartQ Hi-Fi",
- .cpu_dai = &s3c64xx_i2s_dai[0],
- .codec_dai = &wm8750_dai,
+ .cpu_dai_name = "s3c64xx-i2s.0",
+ .codec_dai_name = "wm8750-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8750-codec.0-0x1a",
.init = smartq_wm8987_init,
.ops = &smartq_hifi_ops,
},
@@ -220,16 +222,10 @@ static struct snd_soc_dai_link smartq_dai[] = {
static struct snd_soc_card snd_soc_smartq = {
.name = "SmartQ",
- .platform = &s3c24xx_soc_platform,
.dai_link = smartq_dai,
.num_links = ARRAY_SIZE(smartq_dai),
};
-static struct snd_soc_device smartq_snd_devdata = {
- .card = &snd_soc_smartq,
- .codec_dev = &soc_codec_dev_wm8750,
-};
-
static struct platform_device *smartq_snd_device;
static int __init smartq_init(void)
@@ -245,8 +241,7 @@ static int __init smartq_init(void)
if (!smartq_snd_device)
return -ENOMEM;
- platform_set_drvdata(smartq_snd_device, &smartq_snd_devdata);
- smartq_snd_devdata.dev = &smartq_snd_device->dev;
+ platform_set_drvdata(smartq_snd_device, &snd_soc_smartq);
ret = platform_device_add(smartq_snd_device);
if (ret) {
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
index 362258835e8d..4613288c2772 100644
--- a/sound/soc/s3c24xx/smdk2443_wm9710.c
+++ b/sound/soc/s3c24xx/smdk2443_wm9710.c
@@ -19,7 +19,6 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include "../codecs/ac97.h"
#include "s3c-dma.h"
#include "s3c-ac97.h"
@@ -29,23 +28,19 @@ static struct snd_soc_dai_link smdk2443_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
- .codec_dai = &ac97_dai,
+ .cpu_dai_name = "s3c-ac97",
+ .codec_dai_name = "ac97-hifi",
+ .codec_name = "ac97-codec",
+ .platform_name = "s3c24xx-pcm-audio",
},
};
static struct snd_soc_card smdk2443 = {
.name = "SMDK2443",
- .platform = &s3c24xx_soc_platform,
.dai_link = smdk2443_dai,
.num_links = ARRAY_SIZE(smdk2443_dai),
};
-static struct snd_soc_device smdk2443_snd_ac97_devdata = {
- .card = &smdk2443,
- .codec_dev = &soc_codec_dev_ac97,
-};
-
static struct platform_device *smdk2443_snd_ac97_device;
static int __init smdk2443_init(void)
@@ -56,9 +51,7 @@ static int __init smdk2443_init(void)
if (!smdk2443_snd_ac97_device)
return -ENOMEM;
- platform_set_drvdata(smdk2443_snd_ac97_device,
- &smdk2443_snd_ac97_devdata);
- smdk2443_snd_ac97_devdata.dev = &smdk2443_snd_ac97_device->dev;
+ platform_set_drvdata(smdk2443_snd_ac97_device, &smdk2443);
ret = platform_device_add(smdk2443_snd_ac97_device);
if (ret)
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
index 07e8e51d10d6..052e499b68d1 100644
--- a/sound/soc/s3c24xx/smdk64xx_wm8580.c
+++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c
@@ -22,6 +22,12 @@
#include "s3c-dma.h"
#include "s3c64xx-i2s.h"
+/*
+ * Default CFG switch settings to use this driver:
+ *
+ * SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On
+ */
+
/* SMDK64XX has a 12MHZ crystal attached to WM8580 */
#define SMDK64XX_WM8580_FREQ 12000000
@@ -29,8 +35,8 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int pll_out;
int bfs, rfs, ret;
@@ -107,14 +113,13 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- /* Explicitly set WM8580-DAC to source from MCLK */
- ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_DAC_CLKSEL,
- WM8580_CLKSRC_MCLK);
+ ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
+ SMDK64XX_WM8580_FREQ, pll_out);
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
- SMDK64XX_WM8580_FREQ, pll_out);
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
+ pll_out, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
@@ -138,9 +143,9 @@ static struct snd_soc_ops smdk64xx_ops = {
/* SMDK64xx Playback widgets */
static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
- SND_SOC_DAPM_HP("Front-L/R", NULL),
- SND_SOC_DAPM_HP("Center/Sub", NULL),
- SND_SOC_DAPM_HP("Rear-L/R", NULL),
+ SND_SOC_DAPM_HP("Front", NULL),
+ SND_SOC_DAPM_HP("Center+Sub", NULL),
+ SND_SOC_DAPM_HP("Rear", NULL),
};
/* SMDK64xx Capture widgets */
@@ -162,20 +167,22 @@ static const struct snd_soc_dapm_route audio_map_tx[] = {
/* SMDK-PAIFRX connections */
static const struct snd_soc_dapm_route audio_map_rx[] = {
/* Front Left/Right are fed VOUT1L/R */
- {"Front-L/R", NULL, "VOUT1L"},
- {"Front-L/R", NULL, "VOUT1R"},
+ {"Front", NULL, "VOUT1L"},
+ {"Front", NULL, "VOUT1R"},
/* Center/Sub are fed VOUT2L/R */
- {"Center/Sub", NULL, "VOUT2L"},
- {"Center/Sub", NULL, "VOUT2R"},
+ {"Center+Sub", NULL, "VOUT2L"},
+ {"Center+Sub", NULL, "VOUT2R"},
/* Rear Left/Right are fed VOUT3L/R */
- {"Rear-L/R", NULL, "VOUT3L"},
- {"Rear-L/R", NULL, "VOUT3R"},
+ {"Rear", NULL, "VOUT3L"},
+ {"Rear", NULL, "VOUT3R"},
};
-static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec)
+static int smdk64xx_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
/* Add smdk64xx specific Capture widgets */
snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt,
ARRAY_SIZE(wm8580_dapm_widgets_cpt));
@@ -194,8 +201,10 @@ static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec)
return 0;
}
-static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec)
+static int smdk64xx_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
/* Add smdk64xx specific Playback widgets */
snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk,
ARRAY_SIZE(wm8580_dapm_widgets_pbk));
@@ -213,33 +222,31 @@ static struct snd_soc_dai_link smdk64xx_dai[] = {
{ /* Primary Playback i/f */
.name = "WM8580 PAIF RX",
.stream_name = "Playback",
- .cpu_dai = &s3c64xx_i2s_v4_dai,
- .codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX],
+ .cpu_dai_name = "s3c64xx-iis-v4",
+ .codec_dai_name = "wm8580-hifi-playback",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8580-codec.0-001b",
.init = smdk64xx_wm8580_init_paifrx,
.ops = &smdk64xx_ops,
},
{ /* Primary Capture i/f */
.name = "WM8580 PAIF TX",
.stream_name = "Capture",
- .cpu_dai = &s3c64xx_i2s_v4_dai,
- .codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX],
+ .cpu_dai_name = "s3c64xx-iis-v4",
+ .codec_dai_name = "wm8580-hifi-capture",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8580-codec.0-001b",
.init = smdk64xx_wm8580_init_paiftx,
.ops = &smdk64xx_ops,
},
};
static struct snd_soc_card smdk64xx = {
- .name = "smdk64xx",
- .platform = &s3c24xx_soc_platform,
+ .name = "SMDK64xx 5.1",
.dai_link = smdk64xx_dai,
.num_links = ARRAY_SIZE(smdk64xx_dai),
};
-static struct snd_soc_device smdk64xx_snd_devdata = {
- .card = &smdk64xx,
- .codec_dev = &soc_codec_dev_wm8580,
-};
-
static struct platform_device *smdk64xx_snd_device;
static int __init smdk64xx_audio_init(void)
@@ -250,8 +257,7 @@ static int __init smdk64xx_audio_init(void)
if (!smdk64xx_snd_device)
return -ENOMEM;
- platform_set_drvdata(smdk64xx_snd_device, &smdk64xx_snd_devdata);
- smdk64xx_snd_devdata.dev = &smdk64xx_snd_device->dev;
+ platform_set_drvdata(smdk64xx_snd_device, &smdk64xx);
ret = platform_device_add(smdk64xx_snd_device);
if (ret)
diff --git a/sound/soc/s3c24xx/smdk_spdif.c b/sound/soc/s3c24xx/smdk_spdif.c
new file mode 100644
index 000000000000..f31d22ad7c88
--- /dev/null
+++ b/sound/soc/s3c24xx/smdk_spdif.c
@@ -0,0 +1,223 @@
+/*
+ * smdk_spdif.c -- S/PDIF audio for SMDK
+ *
+ * Copyright 2010 Samsung Electronics Co. Ltd.
+ *
+ * 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/device.h>
+#include <linux/clk.h>
+
+#include <plat/devs.h>
+
+#include <sound/soc.h>
+
+#include "s3c-dma.h"
+#include "spdif.h"
+
+/* Audio clock settings are belonged to board specific part. Every
+ * board can set audio source clock setting which is matched with H/W
+ * like this function-'set_audio_clock_heirachy'.
+ */
+static int set_audio_clock_heirachy(struct platform_device *pdev)
+{
+ struct clk *fout_epll, *mout_epll, *sclk_audio0, *sclk_spdif;
+ int ret;
+
+ fout_epll = clk_get(NULL, "fout_epll");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_WARNING "%s: Cannot find fout_epll.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mout_epll = clk_get(NULL, "mout_epll");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_WARNING "%s: Cannot find mout_epll.\n",
+ __func__);
+ ret = -EINVAL;
+ goto out1;
+ }
+
+ sclk_audio0 = clk_get(&pdev->dev, "sclk_audio");
+ if (IS_ERR(sclk_audio0)) {
+ printk(KERN_WARNING "%s: Cannot find sclk_audio.\n",
+ __func__);
+ ret = -EINVAL;
+ goto out2;
+ }
+
+ sclk_spdif = clk_get(NULL, "sclk_spdif");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_WARNING "%s: Cannot find sclk_spdif.\n",
+ __func__);
+ ret = -EINVAL;
+ goto out3;
+ }
+
+ /* Set audio clock heirachy for S/PDIF */
+ clk_set_parent(mout_epll, fout_epll);
+ clk_set_parent(sclk_audio0, mout_epll);
+ clk_set_parent(sclk_spdif, sclk_audio0);
+
+ clk_put(sclk_spdif);
+out3:
+ clk_put(sclk_audio0);
+out2:
+ clk_put(mout_epll);
+out1:
+ clk_put(fout_epll);
+
+ return ret;
+}
+
+/* We should haved to set clock directly on this part because of clock
+ * scheme of Samsudng SoCs did not support to set rates from abstrct
+ * clock of it's heirachy.
+ */
+static int set_audio_clock_rate(unsigned long epll_rate,
+ unsigned long audio_rate)
+{
+ struct clk *fout_epll, *sclk_spdif;
+
+ fout_epll = clk_get(NULL, "fout_epll");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_ERR "%s: failed to get fout_epll\n", __func__);
+ return -ENOENT;
+ }
+
+ clk_set_rate(fout_epll, epll_rate);
+ clk_put(fout_epll);
+
+ sclk_spdif = clk_get(NULL, "sclk_spdif");
+ if (IS_ERR(sclk_spdif)) {
+ printk(KERN_ERR "%s: failed to get sclk_spdif\n", __func__);
+ return -ENOENT;
+ }
+
+ clk_set_rate(sclk_spdif, audio_rate);
+ clk_put(sclk_spdif);
+
+ return 0;
+}
+
+static int smdk_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned long pll_out, rclk_rate;
+ int ret, ratio;
+
+ switch (params_rate(params)) {
+ case 44100:
+ pll_out = 45158400;
+ break;
+ case 32000:
+ case 48000:
+ case 96000:
+ pll_out = 49152000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Setting ratio to 512fs helps to use S/PDIF with HDMI without
+ * modify S/PDIF ASoC machine driver.
+ */
+ ratio = 512;
+ rclk_rate = params_rate(params) * ratio;
+
+ /* Set audio source clock rates */
+ ret = set_audio_clock_rate(pll_out, rclk_rate);
+ if (ret < 0)
+ return ret;
+
+ /* Set S/PDIF uses internal source clock */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
+ rclk_rate, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static struct snd_soc_ops smdk_spdif_ops = {
+ .hw_params = smdk_hw_params,
+};
+
+static struct snd_soc_card smdk;
+
+static struct snd_soc_dai_link smdk_dai = {
+ .name = "S/PDIF",
+ .stream_name = "S/PDIF PCM Playback",
+ .platform_name = "s3c24xx-pcm-audio",
+ .cpu_dai_name = "samsung-spdif",
+ .codec_dai_name = "dit-hifi",
+ .codec_name = "spdif-dit",
+ .ops = &smdk_spdif_ops,
+};
+
+static struct snd_soc_card smdk = {
+ .name = "SMDK-S/PDIF",
+ .dai_link = &smdk_dai,
+ .num_links = 1,
+};
+
+static struct platform_device *smdk_snd_spdif_dit_device;
+static struct platform_device *smdk_snd_spdif_device;
+
+static int __init smdk_init(void)
+{
+ int ret;
+
+ smdk_snd_spdif_dit_device = platform_device_alloc("spdif-dit", -1);
+ if (!smdk_snd_spdif_dit_device)
+ return -ENOMEM;
+
+ ret = platform_device_add(smdk_snd_spdif_dit_device);
+ if (ret)
+ goto err2;
+
+ smdk_snd_spdif_device = platform_device_alloc("soc-audio", -1);
+ if (!smdk_snd_spdif_device) {
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ platform_set_drvdata(smdk_snd_spdif_device, &smdk);
+
+ ret = platform_device_add(smdk_snd_spdif_device);
+ if (ret)
+ goto err1;
+
+ /* Set audio clock heirachy manually */
+ ret = set_audio_clock_heirachy(smdk_snd_spdif_device);
+ if (ret)
+ goto err1;
+
+ return 0;
+err1:
+ platform_device_put(smdk_snd_spdif_device);
+err2:
+ platform_device_put(smdk_snd_spdif_dit_device);
+ return ret;
+}
+
+static void __exit smdk_exit(void)
+{
+ platform_device_unregister(smdk_snd_spdif_device);
+}
+
+module_init(smdk_init);
+module_exit(smdk_exit);
+
+MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
+MODULE_DESCRIPTION("ALSA SoC SMDK+S/PDIF");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c
index 5527b9e88c98..33ba8fdbcf07 100644
--- a/sound/soc/s3c24xx/smdk_wm9713.c
+++ b/sound/soc/s3c24xx/smdk_wm9713.c
@@ -15,7 +15,6 @@
#include <linux/device.h>
#include <sound/soc.h>
-#include "../codecs/wm9713.h"
#include "s3c-dma.h"
#include "s3c-ac97.h"
@@ -46,46 +45,57 @@ static struct snd_soc_card smdk;
static struct snd_soc_dai_link smdk_dai = {
.name = "AC97",
.stream_name = "AC97 PCM",
- .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
- .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+ .platform_name = "s3c24xx-pcm-audio",
+ .cpu_dai_name = "s3c-ac97",
+ .codec_dai_name = "wm9713-hifi",
+ .codec_name = "wm9713-codec",
};
static struct snd_soc_card smdk = {
- .name = "SMDK",
- .platform = &s3c24xx_soc_platform,
+ .name = "SMDK WM9713",
.dai_link = &smdk_dai,
.num_links = 1,
};
-static struct snd_soc_device smdk_snd_ac97_devdata = {
- .card = &smdk,
- .codec_dev = &soc_codec_dev_wm9713,
-};
-
+static struct platform_device *smdk_snd_wm9713_device;
static struct platform_device *smdk_snd_ac97_device;
static int __init smdk_init(void)
{
int ret;
- smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
- if (!smdk_snd_ac97_device)
+ smdk_snd_wm9713_device = platform_device_alloc("wm9713-codec", -1);
+ if (!smdk_snd_wm9713_device)
return -ENOMEM;
- platform_set_drvdata(smdk_snd_ac97_device,
- &smdk_snd_ac97_devdata);
- smdk_snd_ac97_devdata.dev = &smdk_snd_ac97_device->dev;
+ ret = platform_device_add(smdk_snd_wm9713_device);
+ if (ret)
+ goto err;
+
+ smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+ if (!smdk_snd_ac97_device) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ platform_set_drvdata(smdk_snd_ac97_device, &smdk);
ret = platform_device_add(smdk_snd_ac97_device);
- if (ret)
+ if (ret) {
platform_device_put(smdk_snd_ac97_device);
+ goto err;
+ }
+ return 0;
+err:
+ platform_device_put(smdk_snd_wm9713_device);
return ret;
}
static void __exit smdk_exit(void)
{
platform_device_unregister(smdk_snd_ac97_device);
+ platform_device_unregister(smdk_snd_wm9713_device);
}
module_init(smdk_init);
diff --git a/sound/soc/s3c24xx/spdif.c b/sound/soc/s3c24xx/spdif.c
new file mode 100644
index 000000000000..ce554e9cabcc
--- /dev/null
+++ b/sound/soc/s3c24xx/spdif.c
@@ -0,0 +1,501 @@
+/* sound/soc/s3c24xx/spdif.c
+ *
+ * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ * http://www.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/clk.h>
+#include <linux/io.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <plat/audio.h>
+#include <mach/dma.h>
+
+#include "s3c-dma.h"
+#include "spdif.h"
+
+/* Registers */
+#define CLKCON 0x00
+#define CON 0x04
+#define BSTAS 0x08
+#define CSTAS 0x0C
+#define DATA_OUTBUF 0x10
+#define DCNT 0x14
+#define BSTAS_S 0x18
+#define DCNT_S 0x1C
+
+#define CLKCTL_MASK 0x7
+#define CLKCTL_MCLK_EXT (0x1 << 2)
+#define CLKCTL_PWR_ON (0x1 << 0)
+
+#define CON_MASK 0x3ffffff
+#define CON_FIFO_TH_SHIFT 19
+#define CON_FIFO_TH_MASK (0x7 << 19)
+#define CON_USERDATA_23RDBIT (0x1 << 12)
+
+#define CON_SW_RESET (0x1 << 5)
+
+#define CON_MCLKDIV_MASK (0x3 << 3)
+#define CON_MCLKDIV_256FS (0x0 << 3)
+#define CON_MCLKDIV_384FS (0x1 << 3)
+#define CON_MCLKDIV_512FS (0x2 << 3)
+
+#define CON_PCM_MASK (0x3 << 1)
+#define CON_PCM_16BIT (0x0 << 1)
+#define CON_PCM_20BIT (0x1 << 1)
+#define CON_PCM_24BIT (0x2 << 1)
+
+#define CON_PCM_DATA (0x1 << 0)
+
+#define CSTAS_MASK 0x3fffffff
+#define CSTAS_SAMP_FREQ_MASK (0xF << 24)
+#define CSTAS_SAMP_FREQ_44 (0x0 << 24)
+#define CSTAS_SAMP_FREQ_48 (0x2 << 24)
+#define CSTAS_SAMP_FREQ_32 (0x3 << 24)
+#define CSTAS_SAMP_FREQ_96 (0xA << 24)
+
+#define CSTAS_CATEGORY_MASK (0xFF << 8)
+#define CSTAS_CATEGORY_CODE_CDP (0x01 << 8)
+
+#define CSTAS_NO_COPYRIGHT (0x1 << 2)
+
+/**
+ * struct samsung_spdif_info - Samsung S/PDIF Controller information
+ * @lock: Spin lock for S/PDIF.
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device register block.
+ * @clk_rate: Current clock rate for calcurate ratio.
+ * @pclk: The peri-clock pointer for spdif master operation.
+ * @sclk: The source clock pointer for making sync signals.
+ * @save_clkcon: Backup clkcon reg. in suspend.
+ * @save_con: Backup con reg. in suspend.
+ * @save_cstas: Backup cstas reg. in suspend.
+ * @dma_playback: DMA information for playback channel.
+ */
+struct samsung_spdif_info {
+ spinlock_t lock;
+ struct device *dev;
+ void __iomem *regs;
+ unsigned long clk_rate;
+ struct clk *pclk;
+ struct clk *sclk;
+ u32 saved_clkcon;
+ u32 saved_con;
+ u32 saved_cstas;
+ struct s3c_dma_params *dma_playback;
+};
+
+static struct s3c2410_dma_client spdif_dma_client_out = {
+ .name = "S/PDIF Stereo out",
+};
+
+static struct s3c_dma_params spdif_stereo_out;
+static struct samsung_spdif_info spdif_info;
+
+static inline struct samsung_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+ return snd_soc_dai_get_drvdata(cpu_dai);
+}
+
+static void spdif_snd_txctrl(struct samsung_spdif_info *spdif, int on)
+{
+ void __iomem *regs = spdif->regs;
+ u32 clkcon;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+ if (on)
+ writel(clkcon | CLKCTL_PWR_ON, regs + CLKCON);
+ else
+ writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
+}
+
+static int spdif_set_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct samsung_spdif_info *spdif = to_info(cpu_dai);
+ u32 clkcon;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ clkcon = readl(spdif->regs + CLKCON);
+
+ if (clk_id == SND_SOC_SPDIF_INT_MCLK)
+ clkcon &= ~CLKCTL_MCLK_EXT;
+ else
+ clkcon |= CLKCTL_MCLK_EXT;
+
+ writel(clkcon, spdif->regs + CLKCON);
+
+ spdif->clk_rate = freq;
+
+ return 0;
+}
+
+static int spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+ unsigned long flags;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ spin_lock_irqsave(&spdif->lock, flags);
+ spdif_snd_txctrl(spdif, 1);
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ spin_lock_irqsave(&spdif->lock, flags);
+ spdif_snd_txctrl(spdif, 0);
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int spdif_sysclk_ratios[] = {
+ 512, 384, 256,
+};
+
+static int spdif_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *socdai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+ void __iomem *regs = spdif->regs;
+ struct s3c_dma_params *dma_data;
+ u32 con, clkcon, cstas;
+ unsigned long flags;
+ int i, ratio;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_data = spdif->dma_playback;
+ else {
+ dev_err(spdif->dev, "Capture is not supported\n");
+ return -EINVAL;
+ }
+
+ snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
+
+ spin_lock_irqsave(&spdif->lock, flags);
+
+ con = readl(regs + CON) & CON_MASK;
+ cstas = readl(regs + CSTAS) & CSTAS_MASK;
+ clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+
+ con &= ~CON_FIFO_TH_MASK;
+ con |= (0x7 << CON_FIFO_TH_SHIFT);
+ con |= CON_USERDATA_23RDBIT;
+ con |= CON_PCM_DATA;
+
+ con &= ~CON_PCM_MASK;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ con |= CON_PCM_16BIT;
+ break;
+ default:
+ dev_err(spdif->dev, "Unsupported data size.\n");
+ goto err;
+ }
+
+ ratio = spdif->clk_rate / params_rate(params);
+ for (i = 0; i < ARRAY_SIZE(spdif_sysclk_ratios); i++)
+ if (ratio == spdif_sysclk_ratios[i])
+ break;
+ if (i == ARRAY_SIZE(spdif_sysclk_ratios)) {
+ dev_err(spdif->dev, "Invalid clock ratio %ld/%d\n",
+ spdif->clk_rate, params_rate(params));
+ goto err;
+ }
+
+ con &= ~CON_MCLKDIV_MASK;
+ switch (ratio) {
+ case 256:
+ con |= CON_MCLKDIV_256FS;
+ break;
+ case 384:
+ con |= CON_MCLKDIV_384FS;
+ break;
+ case 512:
+ con |= CON_MCLKDIV_512FS;
+ break;
+ }
+
+ cstas &= ~CSTAS_SAMP_FREQ_MASK;
+ switch (params_rate(params)) {
+ case 44100:
+ cstas |= CSTAS_SAMP_FREQ_44;
+ break;
+ case 48000:
+ cstas |= CSTAS_SAMP_FREQ_48;
+ break;
+ case 32000:
+ cstas |= CSTAS_SAMP_FREQ_32;
+ break;
+ case 96000:
+ cstas |= CSTAS_SAMP_FREQ_96;
+ break;
+ default:
+ dev_err(spdif->dev, "Invalid sampling rate %d\n",
+ params_rate(params));
+ goto err;
+ }
+
+ cstas &= ~CSTAS_CATEGORY_MASK;
+ cstas |= CSTAS_CATEGORY_CODE_CDP;
+ cstas |= CSTAS_NO_COPYRIGHT;
+
+ writel(con, regs + CON);
+ writel(cstas, regs + CSTAS);
+ writel(clkcon, regs + CLKCON);
+
+ spin_unlock_irqrestore(&spdif->lock, flags);
+
+ return 0;
+err:
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ return -EINVAL;
+}
+
+static void spdif_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+ void __iomem *regs = spdif->regs;
+ u32 con, clkcon;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ con = readl(regs + CON) & CON_MASK;
+ clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+
+ writel(con | CON_SW_RESET, regs + CON);
+ cpu_relax();
+
+ writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
+}
+
+#ifdef CONFIG_PM
+static int spdif_suspend(struct snd_soc_dai *cpu_dai)
+{
+ struct samsung_spdif_info *spdif = to_info(cpu_dai);
+ u32 con = spdif->saved_con;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ spdif->saved_clkcon = readl(spdif->regs + CLKCON) & CLKCTL_MASK;
+ spdif->saved_con = readl(spdif->regs + CON) & CON_MASK;
+ spdif->saved_cstas = readl(spdif->regs + CSTAS) & CSTAS_MASK;
+
+ writel(con | CON_SW_RESET, spdif->regs + CON);
+ cpu_relax();
+
+ return 0;
+}
+
+static int spdif_resume(struct snd_soc_dai *cpu_dai)
+{
+ struct samsung_spdif_info *spdif = to_info(cpu_dai);
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ writel(spdif->saved_clkcon, spdif->regs + CLKCON);
+ writel(spdif->saved_con, spdif->regs + CON);
+ writel(spdif->saved_cstas, spdif->regs + CSTAS);
+
+ return 0;
+}
+#else
+#define spdif_suspend NULL
+#define spdif_resume NULL
+#endif
+
+static struct snd_soc_dai_ops spdif_dai_ops = {
+ .set_sysclk = spdif_set_sysclk,
+ .trigger = spdif_trigger,
+ .hw_params = spdif_hw_params,
+ .shutdown = spdif_shutdown,
+};
+
+struct snd_soc_dai_driver samsung_spdif_dai = {
+ .name = "samsung-spdif",
+ .playback = {
+ .stream_name = "S/PDIF Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = (SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_96000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+ .ops = &spdif_dai_ops,
+ .suspend = spdif_suspend,
+ .resume = spdif_resume,
+};
+
+static __devinit int spdif_probe(struct platform_device *pdev)
+{
+ struct s3c_audio_pdata *spdif_pdata;
+ struct resource *mem_res, *dma_res;
+ struct samsung_spdif_info *spdif;
+ int ret;
+
+ spdif_pdata = pdev->dev.platform_data;
+
+ dev_dbg(&pdev->dev, "Entered %s\n", __func__);
+
+ dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dma_res) {
+ dev_err(&pdev->dev, "Unable to get dma resource.\n");
+ return -ENXIO;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Unable to get register resource.\n");
+ return -ENXIO;
+ }
+
+ if (spdif_pdata && spdif_pdata->cfg_gpio
+ && spdif_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure GPIO pins\n");
+ return -EINVAL;
+ }
+
+ spdif = &spdif_info;
+ spdif->dev = &pdev->dev;
+
+ spin_lock_init(&spdif->lock);
+
+ spdif->pclk = clk_get(&pdev->dev, "spdif");
+ if (IS_ERR(spdif->pclk)) {
+ dev_err(&pdev->dev, "failed to get peri-clock\n");
+ ret = -ENOENT;
+ goto err0;
+ }
+ clk_enable(spdif->pclk);
+
+ spdif->sclk = clk_get(&pdev->dev, "sclk_spdif");
+ if (IS_ERR(spdif->sclk)) {
+ dev_err(&pdev->dev, "failed to get internal source clock\n");
+ ret = -ENOENT;
+ goto err1;
+ }
+ clk_enable(spdif->sclk);
+
+ /* Request S/PDIF Register's memory region */
+ if (!request_mem_region(mem_res->start,
+ resource_size(mem_res), "samsung-spdif")) {
+ dev_err(&pdev->dev, "Unable to request register region\n");
+ ret = -EBUSY;
+ goto err2;
+ }
+
+ spdif->regs = ioremap(mem_res->start, 0x100);
+ if (spdif->regs == NULL) {
+ dev_err(&pdev->dev, "Cannot ioremap registers\n");
+ ret = -ENXIO;
+ goto err3;
+ }
+
+ dev_set_drvdata(&pdev->dev, spdif);
+
+ ret = snd_soc_register_dai(&pdev->dev, &samsung_spdif_dai);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "fail to register dai\n");
+ goto err4;
+ }
+
+ spdif_stereo_out.dma_size = 2;
+ spdif_stereo_out.client = &spdif_dma_client_out;
+ spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
+ spdif_stereo_out.channel = dma_res->start;
+
+ spdif->dma_playback = &spdif_stereo_out;
+
+ return 0;
+
+err4:
+ iounmap(spdif->regs);
+err3:
+ release_mem_region(mem_res->start, resource_size(mem_res));
+err2:
+ clk_disable(spdif->sclk);
+ clk_put(spdif->sclk);
+err1:
+ clk_disable(spdif->pclk);
+ clk_put(spdif->pclk);
+err0:
+ return ret;
+}
+
+static __devexit int spdif_remove(struct platform_device *pdev)
+{
+ struct samsung_spdif_info *spdif = &spdif_info;
+ struct resource *mem_res;
+
+ snd_soc_unregister_dai(&pdev->dev);
+
+ iounmap(spdif->regs);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (mem_res)
+ release_mem_region(mem_res->start, resource_size(mem_res));
+
+ clk_disable(spdif->sclk);
+ clk_put(spdif->sclk);
+ clk_disable(spdif->pclk);
+ clk_put(spdif->pclk);
+
+ return 0;
+}
+
+static struct platform_driver samsung_spdif_driver = {
+ .probe = spdif_probe,
+ .remove = spdif_remove,
+ .driver = {
+ .name = "samsung-spdif",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init spdif_init(void)
+{
+ return platform_driver_register(&samsung_spdif_driver);
+}
+module_init(spdif_init);
+
+static void __exit spdif_exit(void)
+{
+ platform_driver_unregister(&samsung_spdif_driver);
+}
+module_exit(spdif_exit);
+
+MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
+MODULE_DESCRIPTION("Samsung S/PDIF Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-spdif");
diff --git a/sound/soc/s3c24xx/spdif.h b/sound/soc/s3c24xx/spdif.h
new file mode 100644
index 000000000000..3ed55592710f
--- /dev/null
+++ b/sound/soc/s3c24xx/spdif.h
@@ -0,0 +1,19 @@
+/* sound/soc/s3c24xx/spdif.h
+ *
+ * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ * http://www.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 __SND_SOC_SAMSUNG_SPDIF_H
+#define __SND_SOC_SAMSUNG_SPDIF_H __FILE__
+
+#define SND_SOC_SPDIF_INT_MCLK 0
+#define SND_SOC_SPDIF_EXT_MCLK 1
+
+#endif /* __SND_SOC_SAMSUNG_SPDIF_H */
diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c
index 59e3fa7bcb05..8778faa174a6 100644
--- a/sound/soc/s6000/s6000-i2s.c
+++ b/sound/soc/s6000/s6000-i2s.c
@@ -140,7 +140,7 @@ static void s6000_i2s_stop_channel(struct s6000_i2s_dev *dev, int channel)
static void s6000_i2s_start(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data;
+ struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
int channel;
channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
@@ -152,7 +152,7 @@ static void s6000_i2s_start(struct snd_pcm_substream *substream)
static void s6000_i2s_stop(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data;
+ struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
int channel;
channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
@@ -194,7 +194,7 @@ static unsigned int s6000_i2s_int_sources(struct s6000_i2s_dev *dev)
static unsigned int s6000_i2s_check_xrun(struct snd_soc_dai *cpu_dai)
{
- struct s6000_i2s_dev *dev = cpu_dai->private_data;
+ struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
unsigned int errors;
unsigned int ret;
@@ -232,7 +232,7 @@ static void s6000_i2s_wait_disabled(struct s6000_i2s_dev *dev)
static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct s6000_i2s_dev *dev = cpu_dai->private_data;
+ struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
u32 w;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -273,7 +273,7 @@ static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
static int s6000_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
{
- struct s6000_i2s_dev *dev = dai->private_data;
+ struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
if (!div || (div & 1) || div > (S6_I2S_DIV_MASK + 1) * 2)
return -EINVAL;
@@ -287,7 +287,7 @@ static int s6000_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct s6000_i2s_dev *dev = dai->private_data;
+ struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
int interf;
u32 w = 0;
@@ -326,15 +326,17 @@ static int s6000_i2s_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int s6000_i2s_dai_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int s6000_i2s_dai_probe(struct snd_soc_dai *dai)
{
- struct s6000_i2s_dev *dev = dai->private_data;
- struct s6000_snd_platform_data *pdata = pdev->dev.platform_data;
+ struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+ struct s6000_snd_platform_data *pdata = dai->dev->platform_data;
if (!pdata)
return -EINVAL;
+ dai->capture_dma_data = &dev->dma_params;
+ dai->playback_dma_data = &dev->dma_params;
+
dev->wide = pdata->wide;
dev->channel_in = pdata->channel_in;
dev->channel_out = pdata->channel_out;
@@ -352,10 +354,10 @@ static int s6000_i2s_dai_probe(struct platform_device *pdev,
dev->channel_in = 0;
dev->channel_out = 1;
- dai->capture.channels_min = 2 * dev->lines_in;
- dai->capture.channels_max = dai->capture.channels_min;
- dai->playback.channels_min = 2 * dev->lines_out;
- dai->playback.channels_max = dai->playback.channels_min;
+ dai->driver->capture.channels_min = 2 * dev->lines_in;
+ dai->driver->capture.channels_max = dai->driver->capture.channels_min;
+ dai->driver->playback.channels_min = 2 * dev->lines_out;
+ dai->driver->playback.channels_max = dai->driver->playback.channels_min;
for (i = 0; i < dev->lines_out; i++)
s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_OUT);
@@ -372,10 +374,10 @@ static int s6000_i2s_dai_probe(struct platform_device *pdev,
if (dev->lines_in > 1 || dev->lines_out > 1)
return -EINVAL;
- dai->capture.channels_min = 2 * dev->lines_in;
- dai->capture.channels_max = 8 * dev->lines_in;
- dai->playback.channels_min = 2 * dev->lines_out;
- dai->playback.channels_max = 8 * dev->lines_out;
+ dai->driver->capture.channels_min = 2 * dev->lines_in;
+ dai->driver->capture.channels_max = 8 * dev->lines_in;
+ dai->driver->playback.channels_min = 2 * dev->lines_out;
+ dai->driver->playback.channels_max = 8 * dev->lines_out;
if (dev->lines_in)
cfg[dev->channel_in] = S6_I2S_IN;
@@ -413,9 +415,7 @@ static struct snd_soc_dai_ops s6000_i2s_dai_ops = {
.hw_params = s6000_i2s_hw_params,
};
-struct snd_soc_dai s6000_i2s_dai = {
- .name = "s6000-i2s",
- .id = 0,
+static struct snd_soc_dai_driver s6000_i2s_dai = {
.probe = s6000_i2s_dai_probe,
.playback = {
.channels_min = 2,
@@ -435,7 +435,6 @@ struct snd_soc_dai s6000_i2s_dai = {
},
.ops = &s6000_i2s_dai_ops,
}
-EXPORT_SYMBOL_GPL(s6000_i2s_dai);
static int __devinit s6000_i2s_probe(struct platform_device *pdev)
{
@@ -513,11 +512,7 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto err_release_dma2;
}
-
- s6000_i2s_dai.dev = &pdev->dev;
- s6000_i2s_dai.private_data = dev;
- s6000_i2s_dai.capture.dma_data = &dev->dma_params;
- s6000_i2s_dai.playback.dma_data = &dev->dma_params;
+ dev_set_drvdata(&pdev->dev, dev);
dev->sifbase = sifmem->start;
dev->scbbase = mmio;
@@ -548,7 +543,7 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
S6_I2S_INT_UNDERRUN |
S6_I2S_INT_OVERRUN);
- ret = snd_soc_register_dai(&s6000_i2s_dai);
+ ret = snd_soc_register_dai(&pdev->dev, &s6000_i2s_dai);
if (ret)
goto err_release_dev;
@@ -573,17 +568,16 @@ err_release_none:
static void __devexit s6000_i2s_remove(struct platform_device *pdev)
{
- struct s6000_i2s_dev *dev = s6000_i2s_dai.private_data;
+ struct s6000_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
struct resource *region;
void __iomem *mmio = dev->scbbase;
- snd_soc_unregister_dai(&s6000_i2s_dai);
+ snd_soc_unregister_dai(&pdev->dev);
s6000_i2s_stop_channel(dev, 0);
s6000_i2s_stop_channel(dev, 1);
s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0);
- s6000_i2s_dai.private_data = 0;
kfree(dev);
region = platform_get_resource(pdev, IORESOURCE_DMA, 0);
diff --git a/sound/soc/s6000/s6000-i2s.h b/sound/soc/s6000/s6000-i2s.h
index 2375fdfe6dba..86aa1921c89e 100644
--- a/sound/soc/s6000/s6000-i2s.h
+++ b/sound/soc/s6000/s6000-i2s.h
@@ -12,8 +12,6 @@
#ifndef _S6000_I2S_H
#define _S6000_I2S_H
-extern struct snd_soc_dai s6000_i2s_dai;
-
struct s6000_snd_platform_data {
int lines_in;
int lines_out;
diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c
index 9c7f7f00cebb..271fd222bf19 100644
--- a/sound/soc/s6000/s6000-pcm.c
+++ b/sound/soc/s6000/s6000-pcm.c
@@ -65,7 +65,7 @@ static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream)
dma_addr_t dma_pos;
dma_addr_t src, dst;
- par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
period_size = snd_pcm_lib_period_bytes(substream);
dma_offset = prtd->period * period_size;
@@ -103,23 +103,25 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data)
{
struct snd_pcm *pcm = data;
struct snd_soc_pcm_runtime *runtime = pcm->private_data;
- struct s6000_pcm_dma_params *params =
- snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
struct s6000_runtime_data *prtd;
unsigned int has_xrun;
int i, ret = IRQ_NONE;
- u32 channel[2] = {
- [SNDRV_PCM_STREAM_PLAYBACK] = params->dma_out,
- [SNDRV_PCM_STREAM_CAPTURE] = params->dma_in
- };
-
- has_xrun = params->check_xrun(runtime->dai->cpu_dai);
- for (i = 0; i < ARRAY_SIZE(channel); ++i) {
+ for (i = 0; i < 2; ++i) {
struct snd_pcm_substream *substream = pcm->streams[i].substream;
+ struct s6000_pcm_dma_params *params =
+ snd_soc_dai_get_dma_data(runtime->cpu_dai, substream);
+ u32 channel;
unsigned int pending;
- if (!channel[i])
+ if (substream == SNDRV_PCM_STREAM_PLAYBACK)
+ channel = params->dma_out;
+ else
+ channel = params->dma_in;
+
+ has_xrun = params->check_xrun(runtime->cpu_dai);
+
+ if (!channel)
continue;
if (unlikely(has_xrun & (1 << i)) &&
@@ -130,8 +132,8 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data)
ret = IRQ_HANDLED;
}
- pending = s6dmac_int_sources(DMA_MASK_DMAC(channel[i]),
- DMA_INDEX_CHNL(channel[i]));
+ pending = s6dmac_int_sources(DMA_MASK_DMAC(channel),
+ DMA_INDEX_CHNL(channel));
if (pending & 1) {
ret = IRQ_HANDLED;
@@ -139,10 +141,10 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data)
snd_pcm_running(substream))) {
snd_pcm_period_elapsed(substream);
dev_dbg(pcm->dev, "period elapsed %x %x\n",
- s6dmac_cur_src(DMA_MASK_DMAC(channel[i]),
- DMA_INDEX_CHNL(channel[i])),
- s6dmac_cur_dst(DMA_MASK_DMAC(channel[i]),
- DMA_INDEX_CHNL(channel[i])));
+ s6dmac_cur_src(DMA_MASK_DMAC(channel),
+ DMA_INDEX_CHNL(channel)),
+ s6dmac_cur_dst(DMA_MASK_DMAC(channel),
+ DMA_INDEX_CHNL(channel)));
prtd = substream->runtime->private_data;
spin_lock(&prtd->lock);
s6000_pcm_enqueue_dma(substream);
@@ -154,16 +156,16 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data)
if (pending & (1 << 3))
printk(KERN_WARNING
"s6000-pcm: DMA %x Underflow\n",
- channel[i]);
+ channel);
if (pending & (1 << 4))
printk(KERN_WARNING
"s6000-pcm: DMA %x Overflow\n",
- channel[i]);
+ channel);
if (pending & 0x1e0)
printk(KERN_WARNING
"s6000-pcm: DMA %x Master Error "
"(mask %x)\n",
- channel[i], pending >> 5);
+ channel, pending >> 5);
}
}
@@ -180,7 +182,7 @@ static int s6000_pcm_start(struct snd_pcm_substream *substream)
int srcinc;
u32 dma;
- par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
spin_lock_irqsave(&prtd->lock, flags);
@@ -221,7 +223,7 @@ static int s6000_pcm_stop(struct snd_pcm_substream *substream)
unsigned long flags;
u32 channel;
- par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
channel = par->dma_out;
@@ -246,7 +248,7 @@ static int s6000_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
struct s6000_pcm_dma_params *par;
int ret;
- par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
ret = par->trigger(substream, cmd, 0);
if (ret < 0)
@@ -291,7 +293,7 @@ static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream)
unsigned int offset;
dma_addr_t count;
- par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
spin_lock_irqsave(&prtd->lock, flags);
@@ -321,7 +323,7 @@ static int s6000_pcm_open(struct snd_pcm_substream *substream)
struct s6000_runtime_data *prtd;
int ret;
- par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
snd_soc_set_runtime_hwparams(substream, &s6000_pcm_hardware);
ret = snd_pcm_hw_constraint_step(runtime, 0,
@@ -385,7 +387,7 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
if (par->same_rate) {
spin_lock(&par->lock);
@@ -407,7 +409,7 @@ static int s6000_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
struct s6000_pcm_dma_params *par =
- snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
spin_lock(&par->lock);
par->in_use &= ~(1 << substream->stream);
@@ -433,7 +435,7 @@ static void s6000_pcm_free(struct snd_pcm *pcm)
{
struct snd_soc_pcm_runtime *runtime = pcm->private_data;
struct s6000_pcm_dma_params *params =
- snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(runtime->cpu_dai, pcm->streams[0].substream);
free_irq(params->irq, pcm);
snd_pcm_lib_preallocate_free_for_all(pcm);
@@ -448,7 +450,8 @@ static int s6000_pcm_new(struct snd_card *card,
struct s6000_pcm_dma_params *params;
int res;
- params = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+ params = snd_soc_dai_get_dma_data(runtime->cpu_dai,
+ pcm->streams[0].substream);
if (!card->dev->dma_mask)
card->dev->dma_mask = &s6000_pcm_dmamask;
@@ -490,25 +493,44 @@ static int s6000_pcm_new(struct snd_card *card,
return 0;
}
-struct snd_soc_platform s6000_soc_platform = {
- .name = "s6000-audio",
- .pcm_ops = &s6000_pcm_ops,
+static struct snd_soc_platform_driver s6000_soc_platform = {
+ .ops = &s6000_pcm_ops,
.pcm_new = s6000_pcm_new,
.pcm_free = s6000_pcm_free,
};
-EXPORT_SYMBOL_GPL(s6000_soc_platform);
-static int __init s6000_pcm_init(void)
+static int __devinit s6000_soc_platform_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_platform(&pdev->dev, &s6000_soc_platform);
+}
+
+static int __devexit s6000_soc_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver s6000_pcm_driver = {
+ .driver = {
+ .name = "s6000-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = s6000_soc_platform_probe,
+ .remove = __devexit_p(s6000_soc_platform_remove),
+};
+
+static int __init snd_s6000_pcm_init(void)
{
- return snd_soc_register_platform(&s6000_soc_platform);
+ return platform_driver_register(&s6000_pcm_driver);
}
-module_init(s6000_pcm_init);
+module_init(snd_s6000_pcm_init);
-static void __exit s6000_pcm_exit(void)
+static void __exit snd_s6000_pcm_exit(void)
{
- snd_soc_unregister_platform(&s6000_soc_platform);
+ platform_driver_unregister(&s6000_pcm_driver);
}
-module_exit(s6000_pcm_exit);
+module_exit(snd_s6000_pcm_exit);
MODULE_AUTHOR("Daniel Gloeckner");
MODULE_DESCRIPTION("Stretch s6000 family PCM DMA module");
diff --git a/sound/soc/s6000/s6000-pcm.h b/sound/soc/s6000/s6000-pcm.h
index 96f23f6f52bf..09d9b883e58b 100644
--- a/sound/soc/s6000/s6000-pcm.h
+++ b/sound/soc/s6000/s6000-pcm.h
@@ -30,6 +30,4 @@ struct s6000_pcm_dma_params {
int rate;
};
-extern struct snd_soc_platform s6000_soc_platform;
-
#endif
diff --git a/sound/soc/s6000/s6105-ipcam.c b/sound/soc/s6000/s6105-ipcam.c
index c1b40ac22c05..96c05e137538 100644
--- a/sound/soc/s6000/s6105-ipcam.c
+++ b/sound/soc/s6000/s6105-ipcam.c
@@ -32,8 +32,8 @@ static int s6105_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0;
/* set codec DAI configuration */
@@ -134,8 +134,10 @@ static const struct snd_kcontrol_new audio_out_mux = {
};
/* Logic for a aic3x as connected on the s6105 ip camera ref design */
-static int s6105_aic3x_init(struct snd_soc_codec *codec)
+static int s6105_aic3x_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
/* Add s6105 specific widgets */
snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
ARRAY_SIZE(aic3x_dapm_widgets));
@@ -165,7 +167,7 @@ static int s6105_aic3x_init(struct snd_soc_codec *codec)
snd_soc_dapm_sync(codec);
- snd_ctl_add(codec->card, snd_ctl_new1(&audio_out_mux, codec));
+ snd_ctl_add(codec->snd_card, snd_ctl_new1(&audio_out_mux, codec));
return 0;
}
@@ -174,8 +176,10 @@ static int s6105_aic3x_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link s6105_dai = {
.name = "TLV320AIC31",
.stream_name = "AIC31",
- .cpu_dai = &s6000_i2s_dai,
- .codec_dai = &aic3x_dai,
+ .cpu_dai_name = "s6000-i2s",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .platform_name = "s6000-pcm-audio",
+ .codec_name = "tlv320aic3x-codec.0-001a",
.init = s6105_aic3x_init,
.ops = &s6105_ops,
};
@@ -183,22 +187,10 @@ static struct snd_soc_dai_link s6105_dai = {
/* s6105 audio machine driver */
static struct snd_soc_card snd_soc_card_s6105 = {
.name = "Stretch IP Camera",
- .platform = &s6000_soc_platform,
.dai_link = &s6105_dai,
.num_links = 1,
};
-/* s6105 audio private data */
-static struct aic3x_setup_data s6105_aic3x_setup = {
-};
-
-/* s6105 audio subsystem */
-static struct snd_soc_device s6105_snd_devdata = {
- .card = &snd_soc_card_s6105,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &s6105_aic3x_setup,
-};
-
static struct s6000_snd_platform_data __initdata s6105_snd_data = {
.wide = 0,
.channel_in = 0,
@@ -227,8 +219,7 @@ static int __init s6105_init(void)
if (!s6105_snd_device)
return -ENOMEM;
- platform_set_drvdata(s6105_snd_device, &s6105_snd_devdata);
- s6105_snd_devdata.dev = &s6105_snd_device->dev;
+ platform_set_drvdata(s6105_snd_device, &snd_soc_card_s6105);
platform_device_add_data(s6105_snd_device, &s6105_snd_data,
sizeof(s6105_snd_data));
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 52d7e8ed9c1f..7f0a496e07ce 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -47,7 +47,7 @@ config SND_SH7760_AC97
AC97 unit of the SH7760.
config SND_FSI_AK4642
- bool "FSI-AK4642 sound support"
+ tristate "FSI-AK4642 sound support"
depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE
select SND_SOC_AK4642
help
@@ -55,13 +55,20 @@ config SND_FSI_AK4642
FSI - AK4642 unit
config SND_FSI_DA7210
- bool "FSI-DA7210 sound support"
+ tristate "FSI-DA7210 sound support"
depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE
select SND_SOC_DA7210
help
This option enables generic sound support for the
FSI - DA7210 unit
+config SND_FSI_HDMI
+ tristate "FSI-HDMI sound support"
+ depends on SND_SOC_SH4_FSI && FB_SH_MOBILE_HDMI
+ help
+ This option enables generic sound support for the
+ FSI - HDMI unit
+
config SND_SIU_MIGOR
tristate "SIU sound support on Migo-R"
depends on SH_MIGOR
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile
index 8a5a19293bda..94476d4c0fd5 100644
--- a/sound/soc/sh/Makefile
+++ b/sound/soc/sh/Makefile
@@ -16,9 +16,11 @@ obj-$(CONFIG_SND_SOC_SH4_SIU) += snd-soc-siu.o
snd-soc-sh7760-ac97-objs := sh7760-ac97.o
snd-soc-fsi-ak4642-objs := fsi-ak4642.o
snd-soc-fsi-da7210-objs := fsi-da7210.o
+snd-soc-fsi-hdmi-objs := fsi-hdmi.o
snd-soc-migor-objs := migor.o
obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o
obj-$(CONFIG_SND_FSI_AK4642) += snd-soc-fsi-ak4642.o
obj-$(CONFIG_SND_FSI_DA7210) += snd-soc-fsi-da7210.o
+obj-$(CONFIG_SND_FSI_HDMI) += snd-soc-fsi-hdmi.o
obj-$(CONFIG_SND_SIU_MIGOR) += snd-soc-migor.o
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
index 0d8bdf07729c..c326d29992fe 100644
--- a/sound/soc/sh/dma-sh7760.c
+++ b/sound/soc/sh/dma-sh7760.c
@@ -137,7 +137,7 @@ static void camelot_rxdma(void *data)
static int camelot_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
int ret, dmairq;
@@ -150,7 +150,7 @@ static int camelot_pcm_open(struct snd_pcm_substream *substream)
ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam);
if (unlikely(ret)) {
pr_debug("audio unit %d irqs already taken!\n",
- rtd->dai->cpu_dai->id);
+ rtd->cpu_dai->id);
return -EBUSY;
}
(void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam);
@@ -159,7 +159,7 @@ static int camelot_pcm_open(struct snd_pcm_substream *substream)
ret = dmabrg_request_irq(dmairq, camelot_txdma, cam);
if (unlikely(ret)) {
pr_debug("audio unit %d irqs already taken!\n",
- rtd->dai->cpu_dai->id);
+ rtd->cpu_dai->id);
return -EBUSY;
}
(void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam);
@@ -170,7 +170,7 @@ static int camelot_pcm_open(struct snd_pcm_substream *substream)
static int camelot_pcm_close(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
int dmairq;
@@ -191,7 +191,7 @@ static int camelot_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
int ret;
@@ -219,7 +219,7 @@ static int camelot_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
pr_debug("PCM data: addr 0x%08ulx len %d\n",
(u32)runtime->dma_addr, runtime->dma_bytes);
@@ -266,7 +266,7 @@ static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam)
static int camelot_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
switch (cmd) {
@@ -293,7 +293,7 @@ static snd_pcm_uframes_t camelot_pos(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
unsigned long pos;
@@ -342,25 +342,44 @@ static int camelot_pcm_new(struct snd_card *card,
return 0;
}
-struct snd_soc_platform sh7760_soc_platform = {
- .name = "sh7760-pcm",
+static struct snd_soc_platform sh7760_soc_platform = {
.pcm_ops = &camelot_pcm_ops,
.pcm_new = camelot_pcm_new,
.pcm_free = camelot_pcm_free,
};
-EXPORT_SYMBOL_GPL(sh7760_soc_platform);
-static int __init sh7760_soc_platform_init(void)
+static int __devinit sh7760_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&sh7760_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &sh7760_soc_platform);
}
-module_init(sh7760_soc_platform_init);
-static void __exit sh7760_soc_platform_exit(void)
+static int __devexit sh7760_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&sh7760_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver sh7760_pcm_driver = {
+ .driver = {
+ .name = "sh7760-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = sh7760_soc_platform_probe,
+ .remove = __devexit_p(sh7760_soc_platform_remove),
+};
+
+static int __init snd_sh7760_pcm_init(void)
+{
+ return platform_driver_register(&sh7760_pcm_driver);
+}
+module_init(snd_sh7760_pcm_init);
+
+static void __exit snd_sh7760_pcm_exit(void)
+{
+ platform_driver_unregister(&sh7760_pcm_driver);
}
-module_exit(sh7760_soc_platform_exit);
+module_exit(snd_sh7760_pcm_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c
index dad575a22622..d96602de71de 100644
--- a/sound/soc/sh/fsi-ak4642.c
+++ b/sound/soc/sh/fsi-ak4642.c
@@ -11,17 +11,17 @@
#include <linux/platform_device.h>
#include <sound/sh_fsi.h>
-#include <../sound/soc/codecs/ak4642.h>
-static int fsi_ak4642_dai_init(struct snd_soc_codec *codec)
+static int fsi_ak4642_dai_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_dai *dai = rtd->codec_dai;
int ret;
- ret = snd_soc_dai_set_fmt(&ak4642_dai, SND_SOC_DAIFMT_CBM_CFM);
+ ret = snd_soc_dai_set_fmt(dai, SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_sysclk(&ak4642_dai, 0, 11289600, 0);
+ ret = snd_soc_dai_set_sysclk(dai, 0, 11289600, 0);
return ret;
}
@@ -29,24 +29,25 @@ static int fsi_ak4642_dai_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link fsi_dai_link = {
.name = "AK4642",
.stream_name = "AK4642",
- .cpu_dai = &fsi_soc_dai[FSI_PORT_A],
- .codec_dai = &ak4642_dai,
+ .cpu_dai_name = "fsia-dai", /* fsi A */
+ .codec_dai_name = "ak4642-hifi",
+#ifdef CONFIG_MACH_AP4EVB
+ .platform_name = "sh_fsi2",
+ .codec_name = "ak4642-codec.0-0013",
+#else
+ .platform_name = "sh_fsi.0",
+ .codec_name = "ak4642-codec.0-0012",
+#endif
.init = fsi_ak4642_dai_init,
.ops = NULL,
};
static struct snd_soc_card fsi_soc_card = {
- .name = "FSI",
- .platform = &fsi_soc_platform,
+ .name = "FSI (AK4642)",
.dai_link = &fsi_dai_link,
.num_links = 1,
};
-static struct snd_soc_device fsi_snd_devdata = {
- .card = &fsi_soc_card,
- .codec_dev = &soc_codec_dev_ak4642,
-};
-
static struct platform_device *fsi_snd_device;
static int __init fsi_ak4642_init(void)
@@ -57,9 +58,7 @@ static int __init fsi_ak4642_init(void)
if (!fsi_snd_device)
goto out;
- platform_set_drvdata(fsi_snd_device,
- &fsi_snd_devdata);
- fsi_snd_devdata.dev = &fsi_snd_device->dev;
+ platform_set_drvdata(fsi_snd_device, &fsi_soc_card);
ret = platform_device_add(fsi_snd_device);
if (ret)
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c
index 121bbb07bb03..a6adb6e43250 100644
--- a/sound/soc/sh/fsi-da7210.c
+++ b/sound/soc/sh/fsi-da7210.c
@@ -12,11 +12,12 @@
#include <linux/platform_device.h>
#include <sound/sh_fsi.h>
-#include "../codecs/da7210.h"
-static int fsi_da7210_init(struct snd_soc_codec *codec)
+static int fsi_da7210_init(struct snd_soc_pcm_runtime *rtd)
{
- return snd_soc_dai_set_fmt(&da7210_dai,
+ struct snd_soc_dai *dai = rtd->codec_dai;
+
+ return snd_soc_dai_set_fmt(dai,
SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM);
}
@@ -24,23 +25,19 @@ static int fsi_da7210_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link fsi_da7210_dai = {
.name = "DA7210",
.stream_name = "DA7210",
- .cpu_dai = &fsi_soc_dai[FSI_PORT_B],
- .codec_dai = &da7210_dai,
+ .cpu_dai_name = "fsib-dai", /* FSI B */
+ .codec_dai_name = "da7210-hifi",
+ .platform_name = "sh_fsi.0",
+ .codec_name = "da7210-codec.0-001a",
.init = fsi_da7210_init,
};
static struct snd_soc_card fsi_soc_card = {
- .name = "FSI",
- .platform = &fsi_soc_platform,
+ .name = "FSI (DA7210)",
.dai_link = &fsi_da7210_dai,
.num_links = 1,
};
-static struct snd_soc_device fsi_da7210_snd_devdata = {
- .card = &fsi_soc_card,
- .codec_dev = &soc_codec_dev_da7210,
-};
-
static struct platform_device *fsi_da7210_snd_device;
static int __init fsi_da7210_sound_init(void)
@@ -51,8 +48,7 @@ static int __init fsi_da7210_sound_init(void)
if (!fsi_da7210_snd_device)
return -ENOMEM;
- platform_set_drvdata(fsi_da7210_snd_device, &fsi_da7210_snd_devdata);
- fsi_da7210_snd_devdata.dev = &fsi_da7210_snd_device->dev;
+ platform_set_drvdata(fsi_da7210_snd_device, &fsi_soc_card);
ret = platform_device_add(fsi_da7210_snd_device);
if (ret)
platform_device_put(fsi_da7210_snd_device);
diff --git a/sound/soc/sh/fsi-hdmi.c b/sound/soc/sh/fsi-hdmi.c
new file mode 100644
index 000000000000..a52dd8ec71d3
--- /dev/null
+++ b/sound/soc/sh/fsi-hdmi.c
@@ -0,0 +1,60 @@
+/*
+ * FSI - HDMI sound support
+ *
+ * Copyright (C) 2010 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * 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 <sound/sh_fsi.h>
+
+static struct snd_soc_dai_link fsi_dai_link = {
+ .name = "HDMI",
+ .stream_name = "HDMI",
+ .cpu_dai_name = "fsib-dai", /* fsi B */
+ .codec_dai_name = "sh_mobile_hdmi-hifi",
+ .platform_name = "sh_fsi2",
+ .codec_name = "sh-mobile-hdmi",
+};
+
+static struct snd_soc_card fsi_soc_card = {
+ .name = "FSI (SH MOBILE HDMI)",
+ .dai_link = &fsi_dai_link,
+ .num_links = 1,
+};
+
+static struct platform_device *fsi_snd_device;
+
+static int __init fsi_hdmi_init(void)
+{
+ int ret = -ENOMEM;
+
+ fsi_snd_device = platform_device_alloc("soc-audio", FSI_PORT_B);
+ if (!fsi_snd_device)
+ goto out;
+
+ platform_set_drvdata(fsi_snd_device, &fsi_soc_card);
+ ret = platform_device_add(fsi_snd_device);
+
+ if (ret)
+ platform_device_put(fsi_snd_device);
+
+out:
+ return ret;
+}
+
+static void __exit fsi_hdmi_exit(void)
+{
+ platform_device_unregister(fsi_snd_device);
+}
+
+module_init(fsi_hdmi_init);
+module_exit(fsi_hdmi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic SH4 FSI-HDMI sound card");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 58c6bec642de..507e709f2807 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -80,11 +80,12 @@
#define B_CLK 0x00000010
#define A_CLK 0x00000001
-/* INT_ST */
-#define INT_B_IN (1 << 12)
-#define INT_B_OUT (1 << 8)
-#define INT_A_IN (1 << 4)
-#define INT_A_OUT (1 << 0)
+/* IO SHIFT / MACRO */
+#define BI_SHIFT 12
+#define BO_SHIFT 8
+#define AI_SHIFT 4
+#define AO_SHIFT 0
+#define AB_IO(param, shift) (param << shift)
/* SOFT_RST */
#define PBSR (1 << 12) /* Port B Software Reset */
@@ -93,33 +94,43 @@
#define FSISR (1 << 0) /* Software Reset */
/* FIFO_SZ */
-#define OUT_SZ_MASK 0x7
-#define BO_SZ_SHIFT 8
-#define AO_SZ_SHIFT 0
+#define FIFO_SZ_MASK 0x7
#define FSI_RATES SNDRV_PCM_RATE_8000_96000
#define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
-/************************************************************************
+/*
+ * FSI driver use below type name for variable
+ *
+ * xxx_len : data length
+ * xxx_width : data width
+ * xxx_offset : data offset
+ * xxx_num : number of data
+ */
+
+/*
+ * struct
+ */
+struct fsi_stream {
+ struct snd_pcm_substream *substream;
- struct
+ int fifo_max_num;
+ int chan_num;
+ int buff_offset;
+ int buff_len;
+ int period_len;
+ int period_num;
+};
-************************************************************************/
struct fsi_priv {
void __iomem *base;
- struct snd_pcm_substream *substream;
struct fsi_master *master;
- int fifo_max;
- int chan;
-
- int byte_offset;
- int period_len;
- int buffer_len;
- int periods;
+ struct fsi_stream playback;
+ struct fsi_stream capture;
u32 mst_ctrl;
};
@@ -142,13 +153,10 @@ struct fsi_master {
spinlock_t lock;
};
-/************************************************************************
-
-
- basic read write function
-
+/*
+ * basic read write function
+ */
-************************************************************************/
static void __fsi_reg_write(u32 reg, u32 data)
{
/* valid data area is 24bit */
@@ -251,13 +259,10 @@ static void fsi_master_mask_set(struct fsi_master *master,
spin_unlock_irqrestore(&master->lock, flags);
}
-/************************************************************************
-
-
- basic function
-
+/*
+ * basic function
+ */
-************************************************************************/
static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
{
return fsi->master;
@@ -271,16 +276,19 @@ static int fsi_is_port_a(struct fsi_priv *fsi)
static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai_link *machine = rtd->dai;
- return machine->cpu_dai;
+ return rtd->cpu_dai;
}
static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream)
{
struct snd_soc_dai *dai = fsi_get_dai(substream);
+ struct fsi_master *master = snd_soc_dai_get_drvdata(dai);
- return dai->private_data;
+ if (dai->id == 0)
+ return &master->fsia;
+ else
+ return &master->fsib;
}
static u32 fsi_get_info_flags(struct fsi_priv *fsi)
@@ -292,6 +300,22 @@ static u32 fsi_get_info_flags(struct fsi_priv *fsi)
master->info->portb_flags;
}
+static inline int fsi_stream_is_play(int stream)
+{
+ return stream == SNDRV_PCM_STREAM_PLAYBACK;
+}
+
+static inline int fsi_is_play(struct snd_pcm_substream *substream)
+{
+ return fsi_stream_is_play(substream->stream);
+}
+
+static inline struct fsi_stream *fsi_get_stream(struct fsi_priv *fsi,
+ int is_play)
+{
+ return is_play ? &fsi->playback : &fsi->capture;
+}
+
static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play)
{
u32 mode;
@@ -307,63 +331,144 @@ static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play)
return (mode & flags) != mode;
}
-static u32 fsi_port_ab_io_bit(struct fsi_priv *fsi, int is_play)
+static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play)
{
int is_porta = fsi_is_port_a(fsi);
- u32 data;
+ u32 shift;
if (is_porta)
- data = is_play ? (1 << 0) : (1 << 4);
+ shift = is_play ? AO_SHIFT : AI_SHIFT;
else
- data = is_play ? (1 << 8) : (1 << 12);
+ shift = is_play ? BO_SHIFT : BI_SHIFT;
- return data;
+ return shift;
}
static void fsi_stream_push(struct fsi_priv *fsi,
+ int is_play,
struct snd_pcm_substream *substream,
u32 buffer_len,
u32 period_len)
{
- fsi->substream = substream;
- fsi->buffer_len = buffer_len;
- fsi->period_len = period_len;
- fsi->byte_offset = 0;
- fsi->periods = 0;
+ struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+
+ io->substream = substream;
+ io->buff_len = buffer_len;
+ io->buff_offset = 0;
+ io->period_len = period_len;
+ io->period_num = 0;
}
-static void fsi_stream_pop(struct fsi_priv *fsi)
+static void fsi_stream_pop(struct fsi_priv *fsi, int is_play)
{
- fsi->substream = NULL;
- fsi->buffer_len = 0;
- fsi->period_len = 0;
- fsi->byte_offset = 0;
- fsi->periods = 0;
+ struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+
+ io->substream = NULL;
+ io->buff_len = 0;
+ io->buff_offset = 0;
+ io->period_len = 0;
+ io->period_num = 0;
}
-static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play)
+static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play)
{
u32 status;
u32 reg = is_play ? DOFF_ST : DIFF_ST;
- int residue;
+ struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+ int data_num;
status = fsi_reg_read(fsi, reg);
- residue = 0x1ff & (status >> 8);
- residue *= fsi->chan;
+ data_num = 0x1ff & (status >> 8);
+ data_num *= io->chan_num;
+
+ return data_num;
+}
+
+static int fsi_len2num(int len, int width)
+{
+ return len / width;
+}
+
+#define fsi_num2offset(a, b) fsi_num2len(a, b)
+static int fsi_num2len(int num, int width)
+{
+ return num * width;
+}
+
+static int fsi_get_frame_width(struct fsi_priv *fsi, int is_play)
+{
+ struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+ struct snd_pcm_substream *substream = io->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ return frames_to_bytes(runtime, 1) / io->chan_num;
+}
+
+/*
+ * dma function
+ */
+
+static u8 *fsi_dma_get_area(struct fsi_priv *fsi, int stream)
+{
+ int is_play = fsi_stream_is_play(stream);
+ struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+
+ return io->substream->runtime->dma_area + io->buff_offset;
+}
+
+static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num)
+{
+ u16 *start;
+ int i;
+
+ start = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK);
+
+ for (i = 0; i < num; i++)
+ fsi_reg_write(fsi, DODT, ((u32)*(start + i) << 8));
+}
+
+static void fsi_dma_soft_pop16(struct fsi_priv *fsi, int num)
+{
+ u16 *start;
+ int i;
- return residue;
+ start = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE);
+
+
+ for (i = 0; i < num; i++)
+ *(start + i) = (u16)(fsi_reg_read(fsi, DIDT) >> 8);
}
-/************************************************************************
+static void fsi_dma_soft_push32(struct fsi_priv *fsi, int num)
+{
+ u32 *start;
+ int i;
+
+ start = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK);
+
+
+ for (i = 0; i < num; i++)
+ fsi_reg_write(fsi, DODT, *(start + i));
+}
+static void fsi_dma_soft_pop32(struct fsi_priv *fsi, int num)
+{
+ u32 *start;
+ int i;
- irq function
+ start = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE);
+ for (i = 0; i < num; i++)
+ *(start + i) = fsi_reg_read(fsi, DIDT);
+}
+
+/*
+ * irq function
+ */
-************************************************************************/
static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
{
- u32 data = fsi_port_ab_io_bit(fsi, is_play);
+ u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play));
struct fsi_master *master = fsi_get_master(fsi);
fsi_master_mask_set(master, master->core->imsk, data, data);
@@ -372,7 +477,7 @@ static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
{
- u32 data = fsi_port_ab_io_bit(fsi, is_play);
+ u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play));
struct fsi_master *master = fsi_get_master(fsi);
fsi_master_mask_set(master, master->core->imsk, data, 0);
@@ -394,20 +499,18 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi)
u32 data = 0;
struct fsi_master *master = fsi_get_master(fsi);
- data |= fsi_port_ab_io_bit(fsi, 0);
- data |= fsi_port_ab_io_bit(fsi, 1);
+ data |= AB_IO(1, fsi_get_port_shift(fsi, 0));
+ data |= AB_IO(1, fsi_get_port_shift(fsi, 1));
/* clear interrupt factor */
fsi_master_mask_set(master, master->core->int_st, data, 0);
}
-/************************************************************************
-
-
- SPDIF master clock function
-
-These functions are used later FSI2
-************************************************************************/
+/*
+ * SPDIF master clock function
+ *
+ * These functions are used later FSI2
+ */
static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
{
struct fsi_master *master = fsi_get_master(fsi);
@@ -424,13 +527,10 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
fsi_master_mask_set(master, fsi->mst_ctrl, val, 0);
}
-/************************************************************************
-
-
- ctrl function
-
+/*
+ * ctrl function
+ */
-************************************************************************/
static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable)
{
u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4);
@@ -447,14 +547,15 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
struct snd_soc_dai *dai)
{
struct fsi_master *master = fsi_get_master(fsi);
+ struct fsi_stream *io = fsi_get_stream(fsi, is_play);
u32 ctrl, shift, i;
/* get on-chip RAM capacity */
shift = fsi_master_read(master, FIFO_SZ);
- shift >>= fsi_is_port_a(fsi) ? AO_SZ_SHIFT : BO_SZ_SHIFT;
- shift &= OUT_SZ_MASK;
- fsi->fifo_max = 256 << shift;
- dev_dbg(dai->dev, "fifo = %d words\n", fsi->fifo_max);
+ shift >>= fsi_get_port_shift(fsi, is_play);
+ shift &= FIFO_SZ_MASK;
+ io->fifo_max_num = 256 << shift;
+ dev_dbg(dai->dev, "fifo = %d words\n", io->fifo_max_num);
/*
* The maximum number of sample data varies depending
@@ -475,9 +576,10 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
* 7 channels: 32 ( 32 x 7 = 224)
* 8 channels: 32 ( 32 x 8 = 256)
*/
- for (i = 1; i < fsi->chan; i <<= 1)
- fsi->fifo_max >>= 1;
- dev_dbg(dai->dev, "%d channel %d store\n", fsi->chan, fsi->fifo_max);
+ for (i = 1; i < io->chan_num; i <<= 1)
+ io->fifo_max_num >>= 1;
+ dev_dbg(dai->dev, "%d channel %d store\n",
+ io->chan_num, io->fifo_max_num);
ctrl = is_play ? DOFF_CTL : DIFF_CTL;
@@ -500,84 +602,114 @@ static void fsi_soft_all_reset(struct fsi_master *master)
mdelay(10);
}
-/* playback interrupt */
-static int fsi_data_push(struct fsi_priv *fsi, int startup)
+static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int startup, int stream)
{
struct snd_pcm_runtime *runtime;
struct snd_pcm_substream *substream = NULL;
- u32 status;
- int send;
- int fifo_free;
- int width;
- u8 *start;
- int i, over_period;
+ int is_play = fsi_stream_is_play(stream);
+ struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+ u32 status_reg = is_play ? DOFF_ST : DIFF_ST;
+ int data_residue_num;
+ int data_num;
+ int data_num_max;
+ int ch_width;
+ int over_period;
+ void (*fn)(struct fsi_priv *fsi, int size);
if (!fsi ||
- !fsi->substream ||
- !fsi->substream->runtime)
+ !io->substream ||
+ !io->substream->runtime)
return -EINVAL;
over_period = 0;
- substream = fsi->substream;
+ substream = io->substream;
runtime = substream->runtime;
/* FSI FIFO has limit.
* So, this driver can not send periods data at a time
*/
- if (fsi->byte_offset >=
- fsi->period_len * (fsi->periods + 1)) {
+ if (io->buff_offset >=
+ fsi_num2offset(io->period_num + 1, io->period_len)) {
over_period = 1;
- fsi->periods = (fsi->periods + 1) % runtime->periods;
+ io->period_num = (io->period_num + 1) % runtime->periods;
- if (0 == fsi->periods)
- fsi->byte_offset = 0;
+ if (0 == io->period_num)
+ io->buff_offset = 0;
}
/* get 1 channel data width */
- width = frames_to_bytes(runtime, 1) / fsi->chan;
-
- /* get send size for alsa */
- send = (fsi->buffer_len - fsi->byte_offset) / width;
-
- /* get FIFO free size */
- fifo_free = (fsi->fifo_max * fsi->chan) - fsi_get_fifo_residue(fsi, 1);
-
- /* size check */
- if (fifo_free < send)
- send = fifo_free;
+ ch_width = fsi_get_frame_width(fsi, is_play);
+
+ /* get residue data number of alsa */
+ data_residue_num = fsi_len2num(io->buff_len - io->buff_offset,
+ ch_width);
+
+ if (is_play) {
+ /*
+ * for play-back
+ *
+ * data_num_max : number of FSI fifo free space
+ * data_num : number of ALSA residue data
+ */
+ data_num_max = io->fifo_max_num * io->chan_num;
+ data_num_max -= fsi_get_fifo_data_num(fsi, is_play);
+
+ data_num = data_residue_num;
+
+ switch (ch_width) {
+ case 2:
+ fn = fsi_dma_soft_push16;
+ break;
+ case 4:
+ fn = fsi_dma_soft_push32;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ /*
+ * for capture
+ *
+ * data_num_max : number of ALSA free space
+ * data_num : number of data in FSI fifo
+ */
+ data_num_max = data_residue_num;
+ data_num = fsi_get_fifo_data_num(fsi, is_play);
+
+ switch (ch_width) {
+ case 2:
+ fn = fsi_dma_soft_pop16;
+ break;
+ case 4:
+ fn = fsi_dma_soft_pop32;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
- start = runtime->dma_area;
- start += fsi->byte_offset;
+ data_num = min(data_num, data_num_max);
- switch (width) {
- case 2:
- for (i = 0; i < send; i++)
- fsi_reg_write(fsi, DODT,
- ((u32)*((u16 *)start + i) << 8));
- break;
- case 4:
- for (i = 0; i < send; i++)
- fsi_reg_write(fsi, DODT, *((u32 *)start + i));
- break;
- default:
- return -EINVAL;
- }
+ fn(fsi, data_num);
- fsi->byte_offset += send * width;
+ /* update buff_offset */
+ io->buff_offset += fsi_num2offset(data_num, ch_width);
- status = fsi_reg_read(fsi, DOFF_ST);
+ /* check fifo status */
if (!startup) {
struct snd_soc_dai *dai = fsi_get_dai(substream);
+ u32 status = fsi_reg_read(fsi, status_reg);
if (status & ERR_OVER)
dev_err(dai->dev, "over run\n");
if (status & ERR_UNDER)
dev_err(dai->dev, "under run\n");
}
- fsi_reg_write(fsi, DOFF_ST, 0);
+ fsi_reg_write(fsi, status_reg, 0);
- fsi_irq_enable(fsi, 1);
+ /* re-enable irq */
+ fsi_irq_enable(fsi, is_play);
if (over_period)
snd_pcm_period_elapsed(substream);
@@ -587,85 +719,12 @@ static int fsi_data_push(struct fsi_priv *fsi, int startup)
static int fsi_data_pop(struct fsi_priv *fsi, int startup)
{
- struct snd_pcm_runtime *runtime;
- struct snd_pcm_substream *substream = NULL;
- u32 status;
- int free;
- int fifo_fill;
- int width;
- u8 *start;
- int i, over_period;
-
- if (!fsi ||
- !fsi->substream ||
- !fsi->substream->runtime)
- return -EINVAL;
-
- over_period = 0;
- substream = fsi->substream;
- runtime = substream->runtime;
-
- /* FSI FIFO has limit.
- * So, this driver can not send periods data at a time
- */
- if (fsi->byte_offset >=
- fsi->period_len * (fsi->periods + 1)) {
-
- over_period = 1;
- fsi->periods = (fsi->periods + 1) % runtime->periods;
-
- if (0 == fsi->periods)
- fsi->byte_offset = 0;
- }
-
- /* get 1 channel data width */
- width = frames_to_bytes(runtime, 1) / fsi->chan;
-
- /* get free space for alsa */
- free = (fsi->buffer_len - fsi->byte_offset) / width;
-
- /* get recv size */
- fifo_fill = fsi_get_fifo_residue(fsi, 0);
-
- if (free < fifo_fill)
- fifo_fill = free;
-
- start = runtime->dma_area;
- start += fsi->byte_offset;
-
- switch (width) {
- case 2:
- for (i = 0; i < fifo_fill; i++)
- *((u16 *)start + i) =
- (u16)(fsi_reg_read(fsi, DIDT) >> 8);
- break;
- case 4:
- for (i = 0; i < fifo_fill; i++)
- *((u32 *)start + i) = fsi_reg_read(fsi, DIDT);
- break;
- default:
- return -EINVAL;
- }
-
- fsi->byte_offset += fifo_fill * width;
-
- status = fsi_reg_read(fsi, DIFF_ST);
- if (!startup) {
- struct snd_soc_dai *dai = fsi_get_dai(substream);
-
- if (status & ERR_OVER)
- dev_err(dai->dev, "over run\n");
- if (status & ERR_UNDER)
- dev_err(dai->dev, "under run\n");
- }
- fsi_reg_write(fsi, DIFF_ST, 0);
-
- fsi_irq_enable(fsi, 0);
-
- if (over_period)
- snd_pcm_period_elapsed(substream);
+ return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_CAPTURE);
+}
- return 0;
+static int fsi_data_push(struct fsi_priv *fsi, int startup)
+{
+ return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_PLAYBACK);
}
static irqreturn_t fsi_interrupt(int irq, void *data)
@@ -677,13 +736,13 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
fsi_master_mask_set(master, SOFT_RST, IR, 0);
fsi_master_mask_set(master, SOFT_RST, IR, IR);
- if (int_st & INT_A_OUT)
+ if (int_st & AB_IO(1, AO_SHIFT))
fsi_data_push(&master->fsia, 0);
- if (int_st & INT_B_OUT)
+ if (int_st & AB_IO(1, BO_SHIFT))
fsi_data_push(&master->fsib, 0);
- if (int_st & INT_A_IN)
+ if (int_st & AB_IO(1, AI_SHIFT))
fsi_data_pop(&master->fsia, 0);
- if (int_st & INT_B_IN)
+ if (int_st & AB_IO(1, BI_SHIFT))
fsi_data_pop(&master->fsib, 0);
fsi_irq_clear_all_status(master);
@@ -691,25 +750,24 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
-/************************************************************************
-
-
- dai ops
-
+/*
+ * dai ops
+ */
-************************************************************************/
static int fsi_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct fsi_priv *fsi = fsi_get_priv(substream);
- u32 flags = fsi_get_info_flags(fsi);
struct fsi_master *master = fsi_get_master(fsi);
+ struct fsi_stream *io;
+ u32 flags = fsi_get_info_flags(fsi);
u32 fmt;
u32 reg;
u32 data;
- int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ int is_play = fsi_is_play(substream);
int is_master;
- int ret = 0;
+
+ io = fsi_get_stream(fsi, is_play);
pm_runtime_get_sync(dai->dev);
@@ -741,29 +799,29 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
switch (fmt) {
case SH_FSI_FMT_MONO:
data = CR_MONO;
- fsi->chan = 1;
+ io->chan_num = 1;
break;
case SH_FSI_FMT_MONO_DELAY:
data = CR_MONO_D;
- fsi->chan = 1;
+ io->chan_num = 1;
break;
case SH_FSI_FMT_PCM:
data = CR_PCM;
- fsi->chan = 2;
+ io->chan_num = 2;
break;
case SH_FSI_FMT_I2S:
data = CR_I2S;
- fsi->chan = 2;
+ io->chan_num = 2;
break;
case SH_FSI_FMT_TDM:
- fsi->chan = is_play ?
+ io->chan_num = is_play ?
SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
- data = CR_TDM | (fsi->chan - 1);
+ data = CR_TDM | (io->chan_num - 1);
break;
case SH_FSI_FMT_TDM_DELAY:
- fsi->chan = is_play ?
+ io->chan_num = is_play ?
SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
- data = CR_TDM_D | (fsi->chan - 1);
+ data = CR_TDM_D | (io->chan_num - 1);
break;
case SH_FSI_FMT_SPDIF:
if (master->core->ver < 2) {
@@ -771,7 +829,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
return -EINVAL;
}
data = CR_SPDIF;
- fsi->chan = 2;
+ io->chan_num = 2;
fsi_spdif_clk_ctrl(fsi, 1);
fsi_reg_mask_set(fsi, OUT_SEL, 0x0010, 0x0010);
break;
@@ -788,14 +846,14 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
/* fifo init */
fsi_fifo_init(fsi, is_play, dai);
- return ret;
+ return 0;
}
static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct fsi_priv *fsi = fsi_get_priv(substream);
- int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ int is_play = fsi_is_play(substream);
fsi_irq_disable(fsi, is_play);
fsi_clk_ctrl(fsi, 0);
@@ -808,19 +866,19 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
{
struct fsi_priv *fsi = fsi_get_priv(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ int is_play = fsi_is_play(substream);
int ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- fsi_stream_push(fsi, substream,
+ fsi_stream_push(fsi, is_play, substream,
frames_to_bytes(runtime, runtime->buffer_size),
frames_to_bytes(runtime, runtime->period_size));
ret = is_play ? fsi_data_push(fsi, 1) : fsi_data_pop(fsi, 1);
break;
case SNDRV_PCM_TRIGGER_STOP:
fsi_irq_disable(fsi, is_play);
- fsi_stream_pop(fsi);
+ fsi_stream_pop(fsi, is_play);
break;
}
@@ -835,7 +893,7 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
struct fsi_master *master = fsi_get_master(fsi);
int (*set_rate)(int is_porta, int rate) = master->info->set_rate;
int fsi_ver = master->core->ver;
- int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ int is_play = fsi_is_play(substream);
int ret;
/* if slave mode, set_rate is not needed */
@@ -916,13 +974,10 @@ static struct snd_soc_dai_ops fsi_dai_ops = {
.hw_params = fsi_dai_hw_params,
};
-/************************************************************************
-
-
- pcm ops
-
+/*
+ * pcm ops
+ */
-************************************************************************/
static struct snd_pcm_hardware fsi_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
@@ -971,9 +1026,10 @@ static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsi_priv *fsi = fsi_get_priv(substream);
+ struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream));
long location;
- location = (fsi->byte_offset - 1);
+ location = (io->buff_offset - 1);
if (location < 0)
location = 0;
@@ -988,13 +1044,10 @@ static struct snd_pcm_ops fsi_pcm_ops = {
.pointer = fsi_pointer,
};
-/************************************************************************
-
-
- snd_soc_platform
-
+/*
+ * snd_soc_platform
+ */
-************************************************************************/
#define PREALLOC_BUFFER (32 * 1024)
#define PREALLOC_BUFFER_MAX (32 * 1024)
@@ -1018,17 +1071,13 @@ static int fsi_pcm_new(struct snd_card *card,
PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
}
-/************************************************************************
-
-
- alsa struct
-
+/*
+ * alsa struct
+ */
-************************************************************************/
-struct snd_soc_dai fsi_soc_dai[] = {
+static struct snd_soc_dai_driver fsi_soc_dai[] = {
{
- .name = "FSIA",
- .id = 0,
+ .name = "fsia-dai",
.playback = {
.rates = FSI_RATES,
.formats = FSI_FMTS,
@@ -1044,8 +1093,7 @@ struct snd_soc_dai fsi_soc_dai[] = {
.ops = &fsi_dai_ops,
},
{
- .name = "FSIB",
- .id = 1,
+ .name = "fsib-dai",
.playback = {
.rates = FSI_RATES,
.formats = FSI_FMTS,
@@ -1061,23 +1109,17 @@ struct snd_soc_dai fsi_soc_dai[] = {
.ops = &fsi_dai_ops,
},
};
-EXPORT_SYMBOL_GPL(fsi_soc_dai);
-struct snd_soc_platform fsi_soc_platform = {
- .name = "fsi-pcm",
- .pcm_ops = &fsi_pcm_ops,
+static struct snd_soc_platform_driver fsi_soc_platform = {
+ .ops = &fsi_pcm_ops,
.pcm_new = fsi_pcm_new,
.pcm_free = fsi_pcm_free,
};
-EXPORT_SYMBOL_GPL(fsi_soc_platform);
-
-/************************************************************************
-
-
- platform function
+/*
+ * platform function
+ */
-************************************************************************/
static int fsi_probe(struct platform_device *pdev)
{
struct fsi_master *master;
@@ -1132,11 +1174,7 @@ static int fsi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_resume(&pdev->dev);
-
- fsi_soc_dai[0].dev = &pdev->dev;
- fsi_soc_dai[0].private_data = &master->fsia;
- fsi_soc_dai[1].dev = &pdev->dev;
- fsi_soc_dai[1].private_data = &master->fsib;
+ dev_set_drvdata(&pdev->dev, master);
fsi_soft_all_reset(master);
@@ -1147,13 +1185,13 @@ static int fsi_probe(struct platform_device *pdev)
goto exit_iounmap;
}
- ret = snd_soc_register_platform(&fsi_soc_platform);
+ ret = snd_soc_register_platform(&pdev->dev, &fsi_soc_platform);
if (ret < 0) {
dev_err(&pdev->dev, "cannot snd soc register\n");
goto exit_free_irq;
}
- return snd_soc_register_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
+ return snd_soc_register_dais(&pdev->dev, fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
exit_free_irq:
free_irq(irq, master);
@@ -1171,10 +1209,10 @@ static int fsi_remove(struct platform_device *pdev)
{
struct fsi_master *master;
- master = fsi_get_master(fsi_soc_dai[0].private_data);
+ master = dev_get_drvdata(&pdev->dev);
- snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
- snd_soc_unregister_platform(&fsi_soc_platform);
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai));
+ snd_soc_unregister_platform(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -1183,11 +1221,6 @@ static int fsi_remove(struct platform_device *pdev)
iounmap(master->base);
kfree(master);
- fsi_soc_dai[0].dev = NULL;
- fsi_soc_dai[0].private_data = NULL;
- fsi_soc_dai[1].dev = NULL;
- fsi_soc_dai[1].private_data = NULL;
-
return 0;
}
@@ -1229,11 +1262,13 @@ static struct fsi_core fsi2_core = {
static struct platform_device_id fsi_id_table[] = {
{ "sh_fsi", (kernel_ulong_t)&fsi1_core },
{ "sh_fsi2", (kernel_ulong_t)&fsi2_core },
+ {},
};
+MODULE_DEVICE_TABLE(platform, fsi_id_table);
static struct platform_driver fsi_driver = {
.driver = {
- .name = "sh_fsi",
+ .name = "fsi-pcm-audio",
.pm = &fsi_pm_ops,
},
.probe = fsi_probe,
@@ -1250,6 +1285,7 @@ static void __exit fsi_mobile_exit(void)
{
platform_driver_unregister(&fsi_driver);
}
+
module_init(fsi_mobile_init);
module_exit(fsi_mobile_exit);
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
index 41db75af3c69..c87e3ff28a0a 100644
--- a/sound/soc/sh/hac.c
+++ b/sound/soc/sh/hac.c
@@ -239,8 +239,7 @@ static int hac_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct hac_priv *hac = &hac_cpu_data[rtd->dai->cpu_dai->id];
+ struct hac_priv *hac = &hac_cpu_data[dai->id];
int d = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
switch (params->msbits) {
@@ -271,10 +270,9 @@ static struct snd_soc_dai_ops hac_dai_ops = {
.hw_params = hac_hw_params,
};
-struct snd_soc_dai sh4_hac_dai[] = {
+static struct snd_soc_dai_driver sh4_hac_dai[] = {
{
- .name = "HAC0",
- .id = 0,
+ .name = "hac-dai.0",
.ac97_control = 1,
.playback = {
.rates = AC97_RATES,
@@ -292,8 +290,7 @@ struct snd_soc_dai sh4_hac_dai[] = {
},
#ifdef CONFIG_CPU_SUBTYPE_SH7760
{
- .name = "HAC1",
- .ac97_control = 1,
+ .name = "hac-dai.1",
.id = 1,
.playback = {
.rates = AC97_RATES,
@@ -312,19 +309,40 @@ struct snd_soc_dai sh4_hac_dai[] = {
},
#endif
};
-EXPORT_SYMBOL_GPL(sh4_hac_dai);
-static int __init sh4_hac_init(void)
+static int __devinit hac_soc_platform_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dais(&pdev->dev, sh4_hac_dai,
+ ARRAY_SIZE(sh4_hac_dai));
+}
+
+static int __devexit hac_soc_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_hac_dai));
+ return 0;
+}
+
+static struct platform_driver hac_pcm_driver = {
+ .driver = {
+ .name = "hac-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = hac_soc_platform_probe,
+ .remove = __devexit_p(hac_soc_platform_remove),
+};
+
+static int __init sh4_hac_pcm_init(void)
{
- return snd_soc_register_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
+ return platform_driver_register(&hac_pcm_driver);
}
-module_init(sh4_hac_init);
+module_init(sh4_hac_pcm_init);
-static void __exit sh4_hac_exit(void)
+static void __exit sh4_hac_pcm_exit(void)
{
- snd_soc_unregister_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
+ platform_driver_unregister(&hac_pcm_driver);
}
-module_exit(sh4_hac_exit);
+module_exit(sh4_hac_pcm_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c
index 87e2b7fcbf17..ac6c49ce6fdf 100644
--- a/sound/soc/sh/migor.c
+++ b/sound/soc/sh/migor.c
@@ -51,7 +51,7 @@ static int migor_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
unsigned int rate = params_rate(params);
@@ -69,7 +69,7 @@ static int migor_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_fmt(rtd->dai->cpu_dai, SND_SOC_DAIFMT_NB_IF |
+ ret = snd_soc_dai_set_fmt(rtd->cpu_dai, SND_SOC_DAIFMT_NB_IF |
SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0)
return ret;
@@ -82,7 +82,7 @@ static int migor_hw_params(struct snd_pcm_substream *substream,
clk_set_rate(&siumckb_clk, codec_freq);
dev_dbg(codec_dai->dev, "%s: configure %luHz\n", __func__, codec_freq);
- ret = snd_soc_dai_set_sysclk(rtd->dai->cpu_dai, SIU_CLKB_EXT,
+ ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, SIU_CLKB_EXT,
codec_freq / 2, SND_SOC_CLOCK_IN);
if (!ret)
@@ -94,7 +94,7 @@ static int migor_hw_params(struct snd_pcm_substream *substream,
static int migor_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
if (use_count) {
use_count--;
@@ -137,8 +137,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
{ "Mic Bias", NULL, "External Microphone" },
};
-static int migor_dai_init(struct snd_soc_codec *codec)
+static int migor_dai_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_new_controls(codec, migor_dapm_widgets,
ARRAY_SIZE(migor_dapm_widgets));
@@ -151,8 +153,10 @@ static int migor_dai_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link migor_dai = {
.name = "wm8978",
.stream_name = "WM8978",
- .cpu_dai = &siu_i2s_dai,
- .codec_dai = &wm8978_dai,
+ .cpu_dai_name = "siu-i2s-dai",
+ .codec_dai_name = "wm8978-hifi",
+ .platform_name = "siu-pcm-audio",
+ .codec_name = "wm8978.0-001a",
.ops = &migor_dai_ops,
.init = migor_dai_init,
};
@@ -160,17 +164,10 @@ static struct snd_soc_dai_link migor_dai = {
/* migor audio machine driver */
static struct snd_soc_card snd_soc_migor = {
.name = "Migo-R",
- .platform = &siu_platform,
.dai_link = &migor_dai,
.num_links = 1,
};
-/* migor audio subsystem */
-static struct snd_soc_device migor_snd_devdata = {
- .card = &snd_soc_migor,
- .codec_dev = &soc_codec_dev_wm8978,
-};
-
static struct platform_device *migor_snd_device;
static int __init migor_init(void)
@@ -195,9 +192,7 @@ static int __init migor_init(void)
goto epdevalloc;
}
- platform_set_drvdata(migor_snd_device, &migor_snd_devdata);
-
- migor_snd_devdata.dev = &migor_snd_device->dev;
+ platform_set_drvdata(migor_snd_device, &snd_soc_migor);
ret = platform_device_add(migor_snd_device);
if (ret)
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c
index ce7f95b59de3..b897f7b96d89 100644
--- a/sound/soc/sh/sh7760-ac97.c
+++ b/sound/soc/sh/sh7760-ac97.c
@@ -15,41 +15,35 @@
#include <sound/soc-dapm.h>
#include <asm/io.h>
-#include "../codecs/ac97.h"
-
#define IPSEL 0xFE400034
/* platform specific structs can be declared here */
-extern struct snd_soc_dai sh4_hac_dai[2];
-extern struct snd_soc_platform sh7760_soc_platform;
+extern struct snd_soc_dai_driver sh4_hac_dai[2];
+extern struct snd_soc_platform_driver sh7760_soc_platform;
-static int machine_init(struct snd_soc_codec *codec)
+static int machine_init(struct snd_soc_pcm_runtime *rtd)
{
- snd_soc_dapm_sync(codec);
+ snd_soc_dapm_sync(rtd->codec);
return 0;
}
static struct snd_soc_dai_link sh7760_ac97_dai = {
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &sh4_hac_dai[0], /* HAC0 */
- .codec_dai = &ac97_dai,
+ .cpu_dai_name = "hac-dai.0", /* HAC0 */
+ .codec_dai_name = "ac97-hifi",
+ .platform_name = "sh7760-pcm-audio",
+ .codec_name = "ac97-codec",
.init = machine_init,
.ops = NULL,
};
static struct snd_soc_card sh7760_ac97_soc_machine = {
.name = "SH7760 AC97",
- .platform = &sh7760_soc_platform,
.dai_link = &sh7760_ac97_dai,
.num_links = 1,
};
-static struct snd_soc_device sh7760_ac97_snd_devdata = {
- .card = &sh7760_ac97_soc_machine,
- .codec_dev = &soc_codec_dev_ac97,
-};
-
static struct platform_device *sh7760_ac97_snd_device;
static int __init sh7760_ac97_init(void)
@@ -67,8 +61,7 @@ static int __init sh7760_ac97_init(void)
goto out;
platform_set_drvdata(sh7760_ac97_snd_device,
- &sh7760_ac97_snd_devdata);
- sh7760_ac97_snd_devdata.dev = &sh7760_ac97_snd_device->dev;
+ &sh7760_ac97_soc_machine);
ret = platform_device_add(sh7760_ac97_snd_device);
if (ret)
diff --git a/sound/soc/sh/siu.h b/sound/soc/sh/siu.h
index 492b1cae24cc..9f4dcb921ff0 100644
--- a/sound/soc/sh/siu.h
+++ b/sound/soc/sh/siu.h
@@ -98,7 +98,9 @@ enum {
SIU_CLKB_EXT
};
+struct device;
struct siu_info {
+ struct device *dev;
int port_id;
u32 __iomem *pram;
u32 __iomem *xram;
@@ -181,8 +183,8 @@ static inline u32 siu_read32(u32 __iomem *addr)
#define SIU_BRGBSEL (0x108 / sizeof(u32))
#define SIU_BRRB (0x10c / sizeof(u32))
-extern struct snd_soc_platform siu_platform;
-extern struct snd_soc_dai siu_i2s_dai;
+extern struct snd_soc_platform_driver siu_platform;
+extern struct siu_info *siu_i2s_data;
int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card);
void siu_free_port(struct siu_port *port_info);
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c
index eeed5edd722b..af53b64d8af2 100644
--- a/sound/soc/sh/siu_dai.c
+++ b/sound/soc/sh/siu_dai.c
@@ -71,6 +71,8 @@ struct port_flag {
struct format_flag capture;
};
+struct siu_info *siu_i2s_data;
+
static struct port_flag siu_flags[SIU_PORT_NUM] = {
[SIU_PORT_A] = {
.playback = {
@@ -104,13 +106,13 @@ static struct port_flag siu_flags[SIU_PORT_NUM] = {
static void siu_dai_start(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
/* Turn on SIU clock */
- pm_runtime_get_sync(siu_i2s_dai.dev);
+ pm_runtime_get_sync(info->dev);
/* Issue software reset to siu */
siu_write32(base + SIU_SRCTL, 0);
@@ -148,21 +150,21 @@ static void siu_dai_start(struct siu_port *port_info)
siu_write32(base + SIU_SBDVCB, port_info->capture.volume);
}
-static void siu_dai_stop(void)
+static void siu_dai_stop(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
/* SIU software reset */
siu_write32(base + SIU_SRCTL, 0);
/* Turn off SIU clock */
- pm_runtime_put_sync(siu_i2s_dai.dev);
+ pm_runtime_put_sync(info->dev);
}
static void siu_dai_spbAselect(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct siu_firmware *fw = &info->fw;
u32 *ydef = fw->yram0;
u32 idx;
@@ -187,7 +189,7 @@ static void siu_dai_spbAselect(struct siu_port *port_info)
static void siu_dai_spbBselect(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct siu_firmware *fw = &info->fw;
u32 *ydef = fw->yram0;
u32 idx;
@@ -207,7 +209,7 @@ static void siu_dai_spbBselect(struct siu_port *port_info)
static void siu_dai_open(struct siu_stream *siu_stream)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
u32 srctl, ifctl;
@@ -238,7 +240,7 @@ static void siu_dai_open(struct siu_stream *siu_stream)
*/
static void siu_dai_pcmdatapack(struct siu_stream *siu_stream)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
u32 dpak;
@@ -258,7 +260,7 @@ static void siu_dai_pcmdatapack(struct siu_stream *siu_stream)
static int siu_dai_spbstart(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
struct siu_firmware *fw = &info->fw;
u32 *ydef = fw->yram0;
@@ -323,7 +325,7 @@ static int siu_dai_spbstart(struct siu_port *port_info)
static void siu_dai_spbstop(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
siu_write32(base + SIU_SBACTIV, 0);
@@ -402,7 +404,7 @@ static int siu_dai_put_volume(struct snd_kcontrol *kctrl,
{
struct siu_port *port_info = snd_kcontrol_chip(kctrl);
struct device *dev = port_info->pcm->card->dev;
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
u32 new_vol;
u32 cur_vol;
@@ -510,7 +512,7 @@ void siu_free_port(struct siu_port *port_info)
static int siu_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = snd_soc_dai_get_drvdata(dai);
struct snd_pcm_runtime *rt = substream->runtime;
struct siu_port *port_info = siu_port_info(substream);
int ret;
@@ -532,7 +534,7 @@ static int siu_dai_startup(struct snd_pcm_substream *substream,
static void siu_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = snd_soc_dai_get_drvdata(dai);
struct siu_port *port_info = siu_port_info(substream);
dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
@@ -548,7 +550,7 @@ static void siu_dai_shutdown(struct snd_pcm_substream *substream,
/* during stmread or stmwrite ? */
BUG_ON(port_info->playback.rw_flg || port_info->capture.rw_flg);
siu_dai_spbstop(port_info);
- siu_dai_stop();
+ siu_dai_stop(port_info);
}
}
@@ -556,7 +558,7 @@ static void siu_dai_shutdown(struct snd_pcm_substream *substream,
static int siu_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = snd_soc_dai_get_drvdata(dai);
struct snd_pcm_runtime *rt = substream->runtime;
struct siu_port *port_info = siu_port_info(substream);
struct siu_stream *siu_stream;
@@ -605,7 +607,7 @@ fail:
static int siu_dai_set_fmt(struct snd_soc_dai *dai,
unsigned int fmt)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = snd_soc_dai_get_drvdata(dai);
u32 __iomem *base = info->reg;
u32 ifctl;
@@ -671,21 +673,37 @@ static int siu_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
return -EINVAL;
}
- siu_clk = clk_get(siu_i2s_dai.dev, siu_name);
- if (IS_ERR(siu_clk))
+ siu_clk = clk_get(dai->dev, siu_name);
+ if (IS_ERR(siu_clk)) {
+ dev_err(dai->dev, "%s: cannot get a SIU clock: %ld\n", __func__,
+ PTR_ERR(siu_clk));
return PTR_ERR(siu_clk);
+ }
+
+ parent_clk = clk_get(dai->dev, parent_name);
+ if (IS_ERR(parent_clk)) {
+ ret = PTR_ERR(parent_clk);
+ dev_err(dai->dev, "cannot get a SIU clock parent: %d\n", ret);
+ goto epclkget;
+ }
- parent_clk = clk_get(siu_i2s_dai.dev, parent_name);
- if (!IS_ERR(parent_clk)) {
- ret = clk_set_parent(siu_clk, parent_clk);
- if (!ret)
- clk_set_rate(siu_clk, freq);
- clk_put(parent_clk);
+ ret = clk_set_parent(siu_clk, parent_clk);
+ if (ret < 0) {
+ dev_err(dai->dev, "cannot reparent the SIU clock: %d\n", ret);
+ goto eclksetp;
}
+ ret = clk_set_rate(siu_clk, freq);
+ if (ret < 0)
+ dev_err(dai->dev, "cannot set SIU clock rate: %d\n", ret);
+
+ /* TODO: when clkdev gets reference counting we'll move these to siu_dai_shutdown() */
+eclksetp:
+ clk_put(parent_clk);
+epclkget:
clk_put(siu_clk);
- return 0;
+ return ret;
}
static struct snd_soc_dai_ops siu_dai_ops = {
@@ -696,9 +714,8 @@ static struct snd_soc_dai_ops siu_dai_ops = {
.set_fmt = siu_dai_set_fmt,
};
-struct snd_soc_dai siu_i2s_dai = {
- .name = "sh-siu",
- .id = 0,
+static struct snd_soc_dai_driver siu_i2s_dai = {
+ .name = "siu-i2s-dai",
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -713,7 +730,6 @@ struct snd_soc_dai siu_i2s_dai = {
},
.ops = &siu_dai_ops,
};
-EXPORT_SYMBOL_GPL(siu_i2s_dai);
static int __devinit siu_probe(struct platform_device *pdev)
{
@@ -725,6 +741,8 @@ static int __devinit siu_probe(struct platform_device *pdev)
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
+ siu_i2s_data = info;
+ info->dev = &pdev->dev;
ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev);
if (ret)
@@ -767,14 +785,14 @@ static int __devinit siu_probe(struct platform_device *pdev)
if (!info->reg)
goto emapreg;
- siu_i2s_dai.dev = &pdev->dev;
- siu_i2s_dai.private_data = info;
+ dev_set_drvdata(&pdev->dev, info);
- ret = snd_soc_register_dais(&siu_i2s_dai, 1);
+ /* register using ARRAY version so we can keep dai name */
+ ret = snd_soc_register_dais(&pdev->dev, &siu_i2s_dai, 1);
if (ret < 0)
goto edaiinit;
- ret = snd_soc_register_platform(&siu_platform);
+ ret = snd_soc_register_platform(&pdev->dev, &siu_platform);
if (ret < 0)
goto esocregp;
@@ -783,7 +801,7 @@ static int __devinit siu_probe(struct platform_device *pdev)
return ret;
esocregp:
- snd_soc_unregister_dais(&siu_i2s_dai, 1);
+ snd_soc_unregister_dai(&pdev->dev);
edaiinit:
iounmap(info->reg);
emapreg:
@@ -804,13 +822,13 @@ ereqfw:
static int __devexit siu_remove(struct platform_device *pdev)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = dev_get_drvdata(&pdev->dev);
struct resource *res;
pm_runtime_disable(&pdev->dev);
- snd_soc_unregister_platform(&siu_platform);
- snd_soc_unregister_dais(&siu_i2s_dai, 1);
+ snd_soc_unregister_platform(&pdev->dev);
+ snd_soc_unregister_dai(&pdev->dev);
iounmap(info->reg);
iounmap(info->yram);
@@ -826,7 +844,8 @@ static int __devexit siu_remove(struct platform_device *pdev)
static struct platform_driver siu_driver = {
.driver = {
- .name = "sh_siu",
+ .owner = THIS_MODULE,
+ .name = "siu-pcm-audio",
},
.probe = siu_probe,
.remove = __devexit_p(siu_remove),
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
index 36170be15aa7..ed29c9e1ed4e 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/sh/siu_pcm.c
@@ -48,7 +48,7 @@ struct siu_port *siu_ports[SIU_PORT_NUM];
/* transfersize is number of u32 dma transfers per period */
static int siu_pcm_stmwrite_stop(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
struct siu_stream *siu_stream = &port_info->playback;
u32 stfifo;
@@ -114,7 +114,7 @@ static void siu_dma_tx_complete(void *arg)
static int siu_pcm_wr_set(struct siu_port *port_info,
dma_addr_t buff, u32 size)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
struct siu_stream *siu_stream = &port_info->playback;
struct snd_pcm_substream *substream = siu_stream->substream;
@@ -127,6 +127,7 @@ static int siu_pcm_wr_set(struct siu_port *port_info,
sg_init_table(&sg, 1);
sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
size, offset_in_page(buff));
+ sg_dma_len(&sg) = size;
sg_dma_address(&sg) = buff;
desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
@@ -161,7 +162,7 @@ static int siu_pcm_wr_set(struct siu_port *port_info,
static int siu_pcm_rd_set(struct siu_port *port_info,
dma_addr_t buff, size_t size)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
struct siu_stream *siu_stream = &port_info->capture;
struct snd_pcm_substream *substream = siu_stream->substream;
@@ -176,6 +177,7 @@ static int siu_pcm_rd_set(struct siu_port *port_info,
sg_init_table(&sg, 1);
sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
size, offset_in_page(buff));
+ sg_dma_len(&sg) = size;
sg_dma_address(&sg) = buff;
desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
@@ -270,7 +272,7 @@ static int siu_pcm_stmread_start(struct siu_port *port_info)
static int siu_pcm_stmread_stop(struct siu_port *port_info)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
struct siu_stream *siu_stream = &port_info->capture;
struct device *dev = siu_stream->substream->pcm->card->dev;
@@ -294,7 +296,7 @@ static int siu_pcm_stmread_stop(struct siu_port *port_info)
static int siu_pcm_hw_params(struct snd_pcm_substream *ss,
struct snd_pcm_hw_params *hw_params)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct device *dev = ss->pcm->card->dev;
int ret;
@@ -309,7 +311,7 @@ static int siu_pcm_hw_params(struct snd_pcm_substream *ss,
static int siu_pcm_hw_free(struct snd_pcm_substream *ss)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct siu_port *port_info = siu_port_info(ss);
struct device *dev = ss->pcm->card->dev;
struct siu_stream *siu_stream;
@@ -340,11 +342,12 @@ static bool filter(struct dma_chan *chan, void *slave)
static int siu_pcm_open(struct snd_pcm_substream *ss)
{
/* Playback / Capture */
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct snd_soc_pcm_runtime *rtd = ss->private_data;
+ struct siu_platform *pdata = rtd->platform->dev->platform_data;
+ struct siu_info *info = siu_i2s_data;
struct siu_port *port_info = siu_port_info(ss);
struct siu_stream *siu_stream;
u32 port = info->port_id;
- struct siu_platform *pdata = siu_i2s_dai.dev->platform_data;
struct device *dev = ss->pcm->card->dev;
dma_cap_mask_t mask;
struct sh_dmae_slave *param;
@@ -381,7 +384,7 @@ static int siu_pcm_open(struct snd_pcm_substream *ss)
static int siu_pcm_close(struct snd_pcm_substream *ss)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct device *dev = ss->pcm->card->dev;
struct siu_port *port_info = siu_port_info(ss);
struct siu_stream *siu_stream;
@@ -403,7 +406,7 @@ static int siu_pcm_close(struct snd_pcm_substream *ss)
static int siu_pcm_prepare(struct snd_pcm_substream *ss)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct siu_port *port_info = siu_port_info(ss);
struct device *dev = ss->pcm->card->dev;
struct snd_pcm_runtime *rt = ss->runtime;
@@ -449,7 +452,7 @@ static int siu_pcm_prepare(struct snd_pcm_substream *ss)
static int siu_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
{
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct device *dev = ss->pcm->card->dev;
struct siu_port *port_info = siu_port_info(ss);
int ret;
@@ -492,7 +495,7 @@ static int siu_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
static snd_pcm_uframes_t siu_pcm_pointer_dma(struct snd_pcm_substream *ss)
{
struct device *dev = ss->pcm->card->dev;
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
u32 __iomem *base = info->reg;
struct siu_port *port_info = siu_port_info(ss);
struct snd_pcm_runtime *rt = ss->runtime;
@@ -528,7 +531,7 @@ static int siu_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
struct snd_pcm *pcm)
{
/* card->dev == socdev->dev, see snd_soc_new_pcms() */
- struct siu_info *info = siu_i2s_dai.private_data;
+ struct siu_info *info = siu_i2s_data;
struct platform_device *pdev = to_platform_device(card->dev);
int ret;
int i;
@@ -605,9 +608,8 @@ static struct snd_pcm_ops siu_pcm_ops = {
.pointer = siu_pcm_pointer_dma,
};
-struct snd_soc_platform siu_platform = {
- .name = "siu-audio",
- .pcm_ops = &siu_pcm_ops,
+struct snd_soc_platform_driver siu_platform = {
+ .ops = &siu_pcm_ops,
.pcm_new = siu_pcm_new,
.pcm_free = siu_pcm_free,
};
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
index b378096cadb1..40bbdf1591dc 100644
--- a/sound/soc/sh/ssi.c
+++ b/sound/soc/sh/ssi.c
@@ -92,8 +92,7 @@ struct ssi_priv {
static int ssi_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+ struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
if (ssi->inuse) {
pr_debug("ssi: already in use!\n");
return -EBUSY;
@@ -105,8 +104,7 @@ static int ssi_startup(struct snd_pcm_substream *substream,
static void ssi_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+ struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
ssi->inuse = 0;
}
@@ -114,8 +112,7 @@ static void ssi_shutdown(struct snd_pcm_substream *substream,
static int ssi_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+ struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -135,8 +132,7 @@ static int ssi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+ struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
unsigned long ssicr = SSIREG(SSICR);
unsigned int bits, channels, swl, recv, i;
@@ -346,10 +342,9 @@ static struct snd_soc_dai_ops ssi_dai_ops = {
.set_fmt = ssi_set_fmt,
};
-struct snd_soc_dai sh4_ssi_dai[] = {
+struct snd_soc_dai_driver sh4_ssi_dai[] = {
{
- .name = "SSI0",
- .id = 0,
+ .name = "ssi-dai.0",
.playback = {
.rates = SSI_RATES,
.formats = SSI_FMTS,
@@ -366,8 +361,7 @@ struct snd_soc_dai sh4_ssi_dai[] = {
},
#ifdef CONFIG_CPU_SUBTYPE_SH7760
{
- .name = "SSI1",
- .id = 1,
+ .name = "ssi-dai.1",
.playback = {
.rates = SSI_RATES,
.formats = SSI_FMTS,
@@ -384,19 +378,40 @@ struct snd_soc_dai sh4_ssi_dai[] = {
},
#endif
};
-EXPORT_SYMBOL_GPL(sh4_ssi_dai);
-static int __init sh4_ssi_init(void)
+static int __devinit sh4_soc_dai_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dais(&pdev->dev, sh4_ssi_dai,
+ ARRAY_SIZE(sh4_ssi_dai));
+}
+
+static int __devexit sh4_soc_dai_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev, ARRAY_SIZE(sh4_ssi_dai));
+ return 0;
+}
+
+static struct platform_driver sh4_ssi_driver = {
+ .driver = {
+ .name = "sh4-ssi-dai",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = sh4_soc_dai_probe,
+ .remove = __devexit_p(sh4_soc_dai_remove),
+};
+
+static int __init snd_sh4_ssi_init(void)
{
- return snd_soc_register_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai));
+ return platform_driver_register(&sh4_ssi_driver);
}
-module_init(sh4_ssi_init);
+module_init(snd_sh4_ssi_init);
-static void __exit sh4_ssi_exit(void)
+static void __exit snd_sh4_ssi_exit(void)
{
- snd_soc_unregister_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai));
+ platform_driver_unregister(&sh4_ssi_driver);
}
-module_exit(sh4_ssi_exit);
+module_exit(snd_sh4_ssi_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index f6b0d2829ea9..d214f02cbb65 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -19,8 +19,15 @@ static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
- if (reg >= codec->reg_cache_size)
- return -1;
+
+ if (reg >= codec->driver->reg_cache_size ||
+ snd_soc_codec_volatile_register(codec, reg)) {
+ if (codec->cache_only)
+ return -1;
+
+ return codec->hw_read(codec, reg);
+ }
+
return cache[reg];
}
@@ -31,13 +38,12 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
u8 data[2];
int ret;
- BUG_ON(codec->volatile_register);
-
data[0] = (reg << 4) | ((value >> 8) & 0x000f);
data[1] = value & 0x00ff;
- if (reg < codec->reg_cache_size)
- cache[reg] = value;
+ if (!snd_soc_codec_volatile_register(codec, reg) &&
+ reg < codec->driver->reg_cache_size)
+ cache[reg] = value;
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -89,8 +95,15 @@ static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
- if (reg >= codec->reg_cache_size)
- return -1;
+
+ if (reg >= codec->driver->reg_cache_size ||
+ snd_soc_codec_volatile_register(codec, reg)) {
+ if (codec->cache_only)
+ return -1;
+
+ return codec->hw_read(codec, reg);
+ }
+
return cache[reg];
}
@@ -101,13 +114,12 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
u8 data[2];
int ret;
- BUG_ON(codec->volatile_register);
-
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
- if (reg < codec->reg_cache_size)
- cache[reg] = value;
+ if (!snd_soc_codec_volatile_register(codec, reg) &&
+ reg < codec->driver->reg_cache_size)
+ cache[reg] = value;
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -161,14 +173,13 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
u8 *cache = codec->reg_cache;
u8 data[2];
- BUG_ON(codec->volatile_register);
-
reg &= 0xff;
data[0] = reg;
data[1] = value & 0xff;
- if (reg < codec->reg_cache_size)
- cache[reg] = value;
+ if (!snd_soc_codec_volatile_register(codec, reg) &&
+ reg < codec->driver->reg_cache_size)
+ cache[reg] = value;
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -187,12 +198,49 @@ static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
unsigned int reg)
{
u8 *cache = codec->reg_cache;
+
reg &= 0xff;
- if (reg >= codec->reg_cache_size)
- return -1;
+ if (reg >= codec->driver->reg_cache_size ||
+ snd_soc_codec_volatile_register(codec, reg)) {
+ if (codec->cache_only)
+ return -1;
+
+ return codec->hw_read(codec, reg);
+ }
+
return cache[reg];
}
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_8_8_spi_write(void *control_data, const char *data,
+ int len)
+{
+ struct spi_device *spi = control_data;
+ struct spi_transfer t;
+ struct spi_message m;
+ u8 msg[2];
+
+ if (len <= 0)
+ return 0;
+
+ msg[0] = data[0];
+ msg[1] = data[1];
+
+ spi_message_init(&m);
+ memset(&t, 0, (sizeof t));
+
+ t.tx_buf = &msg[0];
+ t.len = len;
+
+ spi_message_add_tail(&t, &m);
+ spi_sync(spi, &m);
+
+ return len;
+}
+#else
+#define snd_soc_8_8_spi_write NULL
+#endif
+
static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
@@ -203,9 +251,9 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
data[1] = (value >> 8) & 0xff;
data[2] = value & 0xff;
- if (!snd_soc_codec_volatile_register(codec, reg)
- && reg < codec->reg_cache_size)
- reg_cache[reg] = value;
+ if (!snd_soc_codec_volatile_register(codec, reg) &&
+ reg < codec->driver->reg_cache_size)
+ reg_cache[reg] = value;
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -225,10 +273,10 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
{
u16 *cache = codec->reg_cache;
- if (reg >= codec->reg_cache_size ||
+ if (reg >= codec->driver->reg_cache_size ||
snd_soc_codec_volatile_register(codec, reg)) {
if (codec->cache_only)
- return -EINVAL;
+ return -1;
return codec->hw_read(codec, reg);
} else {
@@ -236,6 +284,37 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
}
}
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_8_16_spi_write(void *control_data, const char *data,
+ int len)
+{
+ struct spi_device *spi = control_data;
+ struct spi_transfer t;
+ struct spi_message m;
+ u8 msg[3];
+
+ if (len <= 0)
+ return 0;
+
+ msg[0] = data[0];
+ msg[1] = data[1];
+ msg[2] = data[2];
+
+ spi_message_init(&m);
+ memset(&t, 0, (sizeof t));
+
+ t.tx_buf = &msg[0];
+ t.len = len;
+
+ spi_message_add_tail(&t, &m);
+ spi_sync(spi, &m);
+
+ return len;
+}
+#else
+#define snd_soc_8_16_spi_write NULL
+#endif
+
#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
unsigned int r)
@@ -344,8 +423,14 @@ static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
u8 *cache = codec->reg_cache;
reg &= 0xff;
- if (reg >= codec->reg_cache_size)
- return -1;
+ if (reg >= codec->driver->reg_cache_size ||
+ snd_soc_codec_volatile_register(codec, reg)) {
+ if (codec->cache_only)
+ return -1;
+
+ return codec->hw_read(codec, reg);
+ }
+
return cache[reg];
}
@@ -356,15 +441,14 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
u8 data[3];
int ret;
- BUG_ON(codec->volatile_register);
-
data[0] = (reg >> 8) & 0xff;
data[1] = reg & 0xff;
data[2] = value;
reg &= 0xff;
- if (reg < codec->reg_cache_size)
- cache[reg] = value;
+ if (!snd_soc_codec_volatile_register(codec, reg) &&
+ reg < codec->driver->reg_cache_size)
+ cache[reg] = value;
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -452,10 +536,10 @@ static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
{
u16 *cache = codec->reg_cache;
- if (reg >= codec->reg_cache_size ||
+ if (reg >= codec->driver->reg_cache_size ||
snd_soc_codec_volatile_register(codec, reg)) {
if (codec->cache_only)
- return -EINVAL;
+ return -1;
return codec->hw_read(codec, reg);
}
@@ -475,8 +559,9 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
data[2] = (value >> 8) & 0xff;
data[3] = value & 0xff;
- if (reg < codec->reg_cache_size)
- cache[reg] = value;
+ if (!snd_soc_codec_volatile_register(codec, reg) &&
+ reg < codec->driver->reg_cache_size)
+ cache[reg] = value;
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -494,6 +579,38 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
return -EIO;
}
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_16_16_spi_write(void *control_data, const char *data,
+ int len)
+{
+ struct spi_device *spi = control_data;
+ struct spi_transfer t;
+ struct spi_message m;
+ u8 msg[4];
+
+ if (len <= 0)
+ return 0;
+
+ msg[0] = data[0];
+ msg[1] = data[1];
+ msg[2] = data[2];
+ msg[3] = data[3];
+
+ spi_message_init(&m);
+ memset(&t, 0, (sizeof t));
+
+ t.tx_buf = &msg[0];
+ t.len = len;
+
+ spi_message_add_tail(&t, &m);
+ spi_sync(spi, &m);
+
+ return len;
+}
+#else
+#define snd_soc_16_16_spi_write NULL
+#endif
+
static struct {
int addr_bits;
int data_bits;
@@ -516,11 +633,13 @@ static struct {
.addr_bits = 8, .data_bits = 8,
.write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
.i2c_read = snd_soc_8_8_read_i2c,
+ .spi_write = snd_soc_8_8_spi_write,
},
{
.addr_bits = 8, .data_bits = 16,
.write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
.i2c_read = snd_soc_8_16_read_i2c,
+ .spi_write = snd_soc_8_16_spi_write,
},
{
.addr_bits = 16, .data_bits = 8,
@@ -532,6 +651,7 @@ static struct {
.addr_bits = 16, .data_bits = 16,
.write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
.i2c_read = snd_soc_16_16_read_i2c,
+ .spi_write = snd_soc_16_16_spi_write,
},
};
@@ -572,8 +692,8 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
return -EINVAL;
}
- codec->write = io_types[i].write;
- codec->read = io_types[i].read;
+ codec->driver->write = io_types[i].write;
+ codec->driver->read = io_types[i].read;
switch (control) {
case SND_SOC_CUSTOM:
@@ -585,11 +705,19 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
#endif
if (io_types[i].i2c_read)
codec->hw_read = io_types[i].i2c_read;
+
+ codec->control_data = container_of(codec->dev,
+ struct i2c_client,
+ dev);
break;
case SND_SOC_SPI:
if (io_types[i].spi_write)
codec->hw_write = io_types[i].spi_write;
+
+ codec->control_data = container_of(codec->dev,
+ struct spi_device,
+ dev);
break;
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 4057d35343bb..1c8f3f507f54 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3,6 +3,8 @@
*
* Copyright 2005 Wolfson Microelectronics PLC.
* Copyright 2005 Openedhand Ltd.
+ * Copyright (C) 2010 Slimlogic Ltd.
+ * Copyright (C) 2010 Texas Instruments Inc.
*
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
* with code, comments and ideas from :-
@@ -37,6 +39,8 @@
#include <sound/soc-dapm.h>
#include <sound/initval.h>
+#define NAME_SIZE 32
+
static DEFINE_MUTEX(pcm_mutex);
static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
@@ -52,6 +56,7 @@ static LIST_HEAD(codec_list);
static int snd_soc_register_card(struct snd_soc_card *card);
static int snd_soc_unregister_card(struct snd_soc_card *card);
+static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
/*
* This is a timeout to do a DAPM powerdown after a stream is closed().
@@ -86,30 +91,30 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
{
int ret, i, step = 1, count = 0;
- if (!codec->reg_cache_size)
+ if (!codec->driver->reg_cache_size)
return 0;
- if (codec->reg_cache_step)
- step = codec->reg_cache_step;
+ if (codec->driver->reg_cache_step)
+ step = codec->driver->reg_cache_step;
count += sprintf(buf, "%s registers\n", codec->name);
- for (i = 0; i < codec->reg_cache_size; i += step) {
- if (codec->readable_register && !codec->readable_register(i))
+ for (i = 0; i < codec->driver->reg_cache_size; i += step) {
+ if (codec->driver->readable_register && !codec->driver->readable_register(i))
continue;
count += sprintf(buf + count, "%2x: ", i);
if (count >= PAGE_SIZE - 1)
break;
- if (codec->display_register) {
- count += codec->display_register(codec, buf + count,
+ if (codec->driver->display_register) {
+ count += codec->driver->display_register(codec, buf + count,
PAGE_SIZE - count, i);
} else {
/* If the read fails it's almost certainly due to
* the register being volatile and the device being
* powered off.
*/
- ret = codec->read(codec, i);
+ ret = codec->driver->read(codec, i);
if (ret >= 0)
count += snprintf(buf + count,
PAGE_SIZE - count,
@@ -137,8 +142,10 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
static ssize_t codec_reg_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct snd_soc_device *devdata = dev_get_drvdata(dev);
- return soc_codec_reg_show(devdata->card->codec, buf);
+ struct snd_soc_pcm_runtime *rtd =
+ container_of(dev, struct snd_soc_pcm_runtime, dev);
+
+ return soc_codec_reg_show(rtd->codec, buf);
}
static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
@@ -146,20 +153,20 @@ static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
static ssize_t pmdown_time_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct snd_soc_device *socdev = dev_get_drvdata(dev);
- struct snd_soc_card *card = socdev->card;
+ struct snd_soc_pcm_runtime *rtd =
+ container_of(dev, struct snd_soc_pcm_runtime, dev);
- return sprintf(buf, "%ld\n", card->pmdown_time);
+ return sprintf(buf, "%ld\n", rtd->pmdown_time);
}
static ssize_t pmdown_time_set(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct snd_soc_device *socdev = dev_get_drvdata(dev);
- struct snd_soc_card *card = socdev->card;
+ struct snd_soc_pcm_runtime *rtd =
+ container_of(dev, struct snd_soc_pcm_runtime, dev);
- strict_strtol(buf, 10, &card->pmdown_time);
+ strict_strtol(buf, 10, &rtd->pmdown_time);
return count;
}
@@ -203,19 +210,19 @@ static ssize_t codec_reg_write_file(struct file *file,
return -EFAULT;
buf[buf_size] = 0;
- if (codec->reg_cache_step)
- step = codec->reg_cache_step;
+ if (codec->driver->reg_cache_step)
+ step = codec->driver->reg_cache_step;
while (*start == ' ')
start++;
reg = simple_strtoul(start, &start, 16);
- if ((reg >= codec->reg_cache_size) || (reg % step))
+ if ((reg >= codec->driver->reg_cache_size) || (reg % step))
return -EINVAL;
while (*start == ' ')
start++;
if (strict_strtoul(start, 16, &value))
return -EINVAL;
- codec->write(codec, reg, value);
+ codec->driver->write(codec, reg, value);
return buf_size;
}
@@ -228,16 +235,7 @@ static const struct file_operations codec_reg_fops = {
static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
{
- char codec_root[128];
-
- if (codec->dev)
- snprintf(codec_root, sizeof(codec_root),
- "%s.%s", codec->name, dev_name(codec->dev));
- else
- snprintf(codec_root, sizeof(codec_root),
- "%s", codec->name);
-
- codec->debugfs_codec_root = debugfs_create_dir(codec_root,
+ codec->debugfs_codec_root = debugfs_create_dir(codec->name ,
debugfs_root);
if (!codec->debugfs_codec_root) {
printk(KERN_WARNING
@@ -273,6 +271,106 @@ static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
debugfs_remove_recursive(codec->debugfs_codec_root);
}
+static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ ssize_t len, ret = 0;
+ struct snd_soc_codec *codec;
+
+ if (!buf)
+ return -ENOMEM;
+
+ list_for_each_entry(codec, &codec_list, list) {
+ len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
+ codec->name);
+ if (len >= 0)
+ ret += len;
+ if (ret > PAGE_SIZE) {
+ ret = PAGE_SIZE;
+ break;
+ }
+ }
+
+ if (ret >= 0)
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static const struct file_operations codec_list_fops = {
+ .read = codec_list_read_file,
+ .llseek = default_llseek,/* read accesses f_pos */
+};
+
+static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ ssize_t len, ret = 0;
+ struct snd_soc_dai *dai;
+
+ if (!buf)
+ return -ENOMEM;
+
+ list_for_each_entry(dai, &dai_list, list) {
+ len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name);
+ if (len >= 0)
+ ret += len;
+ if (ret > PAGE_SIZE) {
+ ret = PAGE_SIZE;
+ break;
+ }
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static const struct file_operations dai_list_fops = {
+ .read = dai_list_read_file,
+ .llseek = default_llseek,/* read accesses f_pos */
+};
+
+static ssize_t platform_list_read_file(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ ssize_t len, ret = 0;
+ struct snd_soc_platform *platform;
+
+ if (!buf)
+ return -ENOMEM;
+
+ list_for_each_entry(platform, &platform_list, list) {
+ len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
+ platform->name);
+ if (len >= 0)
+ ret += len;
+ if (ret > PAGE_SIZE) {
+ ret = PAGE_SIZE;
+ break;
+ }
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static const struct file_operations platform_list_fops = {
+ .read = platform_list_read_file,
+ .llseek = default_llseek,/* read accesses f_pos */
+};
+
#else
static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
@@ -306,7 +404,7 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec)
codec->ac97->dev.release = soc_ac97_device_release;
dev_set_name(&codec->ac97->dev, "%d-%d:%s",
- codec->card->number, 0, codec->name);
+ codec->card->snd_card->number, 0, codec->name);
err = device_register(&codec->ac97->dev);
if (err < 0) {
snd_printk(KERN_ERR "Can't register ac97 bus\n");
@@ -320,24 +418,21 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec)
static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
- if (codec_dai->symmetric_rates || cpu_dai->symmetric_rates ||
- machine->symmetric_rates) {
- dev_dbg(card->dev, "Symmetry forces %dHz rate\n",
- machine->rate);
+ if (codec_dai->driver->symmetric_rates || cpu_dai->driver->symmetric_rates ||
+ rtd->dai_link->symmetric_rates) {
+ dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n",
+ rtd->rate);
ret = snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_RATE,
- machine->rate,
- machine->rate);
+ rtd->rate,
+ rtd->rate);
if (ret < 0) {
- dev_err(card->dev,
+ dev_err(&rtd->dev,
"Unable to apply rate symmetry constraint: %d\n", ret);
return ret;
}
@@ -354,20 +449,19 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
static int soc_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_card *card = socdev->card;
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
+ struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
int ret = 0;
mutex_lock(&pcm_mutex);
/* startup the audio subsystem */
- if (cpu_dai->ops->startup) {
- ret = cpu_dai->ops->startup(substream, cpu_dai);
+ if (cpu_dai->driver->ops->startup) {
+ ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: can't open interface %s\n",
cpu_dai->name);
@@ -375,16 +469,16 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
}
}
- if (platform->pcm_ops->open) {
- ret = platform->pcm_ops->open(substream);
+ if (platform->driver->ops->open) {
+ ret = platform->driver->ops->open(substream);
if (ret < 0) {
printk(KERN_ERR "asoc: can't open platform %s\n", platform->name);
goto platform_err;
}
}
- if (codec_dai->ops->startup) {
- ret = codec_dai->ops->startup(substream, codec_dai);
+ if (codec_dai->driver->ops->startup) {
+ ret = codec_dai->driver->ops->startup(substream, codec_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: can't open codec %s\n",
codec_dai->name);
@@ -392,10 +486,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
}
}
- if (machine->ops && machine->ops->startup) {
- ret = machine->ops->startup(substream);
+ if (rtd->dai_link->ops && rtd->dai_link->ops->startup) {
+ ret = rtd->dai_link->ops->startup(substream);
if (ret < 0) {
- printk(KERN_ERR "asoc: %s startup failed\n", machine->name);
+ printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name);
goto machine_err;
}
}
@@ -403,50 +497,50 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
/* Check that the codec and cpu DAI's are compatible */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
runtime->hw.rate_min =
- max(codec_dai->playback.rate_min,
- cpu_dai->playback.rate_min);
+ max(codec_dai_drv->playback.rate_min,
+ cpu_dai_drv->playback.rate_min);
runtime->hw.rate_max =
- min(codec_dai->playback.rate_max,
- cpu_dai->playback.rate_max);
+ min(codec_dai_drv->playback.rate_max,
+ cpu_dai_drv->playback.rate_max);
runtime->hw.channels_min =
- max(codec_dai->playback.channels_min,
- cpu_dai->playback.channels_min);
+ max(codec_dai_drv->playback.channels_min,
+ cpu_dai_drv->playback.channels_min);
runtime->hw.channels_max =
- min(codec_dai->playback.channels_max,
- cpu_dai->playback.channels_max);
+ min(codec_dai_drv->playback.channels_max,
+ cpu_dai_drv->playback.channels_max);
runtime->hw.formats =
- codec_dai->playback.formats & cpu_dai->playback.formats;
+ codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats;
runtime->hw.rates =
- codec_dai->playback.rates & cpu_dai->playback.rates;
- if (codec_dai->playback.rates
+ codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates;
+ if (codec_dai_drv->playback.rates
& (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
- runtime->hw.rates |= cpu_dai->playback.rates;
- if (cpu_dai->playback.rates
+ runtime->hw.rates |= cpu_dai_drv->playback.rates;
+ if (cpu_dai_drv->playback.rates
& (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
- runtime->hw.rates |= codec_dai->playback.rates;
+ runtime->hw.rates |= codec_dai_drv->playback.rates;
} else {
runtime->hw.rate_min =
- max(codec_dai->capture.rate_min,
- cpu_dai->capture.rate_min);
+ max(codec_dai_drv->capture.rate_min,
+ cpu_dai_drv->capture.rate_min);
runtime->hw.rate_max =
- min(codec_dai->capture.rate_max,
- cpu_dai->capture.rate_max);
+ min(codec_dai_drv->capture.rate_max,
+ cpu_dai_drv->capture.rate_max);
runtime->hw.channels_min =
- max(codec_dai->capture.channels_min,
- cpu_dai->capture.channels_min);
+ max(codec_dai_drv->capture.channels_min,
+ cpu_dai_drv->capture.channels_min);
runtime->hw.channels_max =
- min(codec_dai->capture.channels_max,
- cpu_dai->capture.channels_max);
+ min(codec_dai_drv->capture.channels_max,
+ cpu_dai_drv->capture.channels_max);
runtime->hw.formats =
- codec_dai->capture.formats & cpu_dai->capture.formats;
+ codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats;
runtime->hw.rates =
- codec_dai->capture.rates & cpu_dai->capture.rates;
- if (codec_dai->capture.rates
+ codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates;
+ if (codec_dai_drv->capture.rates
& (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
- runtime->hw.rates |= cpu_dai->capture.rates;
- if (cpu_dai->capture.rates
+ runtime->hw.rates |= cpu_dai_drv->capture.rates;
+ if (cpu_dai_drv->capture.rates
& (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
- runtime->hw.rates |= codec_dai->capture.rates;
+ runtime->hw.rates |= codec_dai_drv->capture.rates;
}
snd_pcm_limit_hw_rates(runtime);
@@ -462,7 +556,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
}
if (!runtime->hw.channels_min || !runtime->hw.channels_max) {
printk(KERN_ERR "asoc: %s <-> %s No matching channels\n",
- codec_dai->name, cpu_dai->name);
+ codec_dai->name, cpu_dai->name);
goto config_err;
}
@@ -473,7 +567,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
goto config_err;
}
- pr_debug("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name);
+ pr_debug("asoc: %s <-> %s info:\n",
+ codec_dai->name, cpu_dai->name);
pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates);
pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
runtime->hw.channels_max);
@@ -481,33 +576,33 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
runtime->hw.rate_max);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- cpu_dai->playback.active++;
- codec_dai->playback.active++;
+ cpu_dai->playback_active++;
+ codec_dai->playback_active++;
} else {
- cpu_dai->capture.active++;
- codec_dai->capture.active++;
+ cpu_dai->capture_active++;
+ codec_dai->capture_active++;
}
cpu_dai->active++;
codec_dai->active++;
- card->codec->active++;
+ rtd->codec->active++;
mutex_unlock(&pcm_mutex);
return 0;
config_err:
- if (machine->ops && machine->ops->shutdown)
- machine->ops->shutdown(substream);
+ if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
+ rtd->dai_link->ops->shutdown(substream);
machine_err:
- if (codec_dai->ops->shutdown)
- codec_dai->ops->shutdown(substream, codec_dai);
+ if (codec_dai->driver->ops->shutdown)
+ codec_dai->driver->ops->shutdown(substream, codec_dai);
codec_dai_err:
- if (platform->pcm_ops->close)
- platform->pcm_ops->close(substream);
+ if (platform->driver->ops->close)
+ platform->driver->ops->close(substream);
platform_err:
- if (cpu_dai->ops->shutdown)
- cpu_dai->ops->shutdown(substream, cpu_dai);
+ if (cpu_dai->driver->ops->shutdown)
+ cpu_dai->driver->ops->shutdown(substream, cpu_dai);
out:
mutex_unlock(&pcm_mutex);
return ret;
@@ -520,29 +615,25 @@ out:
*/
static void close_delayed_work(struct work_struct *work)
{
- struct snd_soc_card *card = container_of(work, struct snd_soc_card,
- delayed_work.work);
- struct snd_soc_codec *codec = card->codec;
- struct snd_soc_dai *codec_dai;
- int i;
+ struct snd_soc_pcm_runtime *rtd =
+ container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
mutex_lock(&pcm_mutex);
- for (i = 0; i < codec->num_dai; i++) {
- codec_dai = &codec->dai[i];
-
- pr_debug("pop wq checking: %s status: %s waiting: %s\n",
- codec_dai->playback.stream_name,
- codec_dai->playback.active ? "active" : "inactive",
- codec_dai->pop_wait ? "yes" : "no");
-
- /* are we waiting on this codec DAI stream */
- if (codec_dai->pop_wait == 1) {
- codec_dai->pop_wait = 0;
- snd_soc_dapm_stream_event(codec,
- codec_dai->playback.stream_name,
- SND_SOC_DAPM_STREAM_STOP);
- }
+
+ pr_debug("pop wq checking: %s status: %s waiting: %s\n",
+ codec_dai->driver->playback.stream_name,
+ codec_dai->playback_active ? "active" : "inactive",
+ codec_dai->pop_wait ? "yes" : "no");
+
+ /* are we waiting on this codec DAI stream */
+ if (codec_dai->pop_wait == 1) {
+ codec_dai->pop_wait = 0;
+ snd_soc_dapm_stream_event(rtd,
+ codec_dai->driver->playback.stream_name,
+ SND_SOC_DAPM_STREAM_STOP);
}
+
mutex_unlock(&pcm_mutex);
}
@@ -554,22 +645,19 @@ static void close_delayed_work(struct work_struct *work)
static int soc_codec_close(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
- struct snd_soc_codec *codec = card->codec;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = rtd->codec;
mutex_lock(&pcm_mutex);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- cpu_dai->playback.active--;
- codec_dai->playback.active--;
+ cpu_dai->playback_active--;
+ codec_dai->playback_active--;
} else {
- cpu_dai->capture.active--;
- codec_dai->capture.active--;
+ cpu_dai->capture_active--;
+ codec_dai->capture_active--;
}
cpu_dai->active--;
@@ -582,27 +670,28 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
snd_soc_dai_digital_mute(codec_dai, 1);
- if (cpu_dai->ops->shutdown)
- cpu_dai->ops->shutdown(substream, cpu_dai);
+ if (cpu_dai->driver->ops->shutdown)
+ cpu_dai->driver->ops->shutdown(substream, cpu_dai);
- if (codec_dai->ops->shutdown)
- codec_dai->ops->shutdown(substream, codec_dai);
+ if (codec_dai->driver->ops->shutdown)
+ codec_dai->driver->ops->shutdown(substream, codec_dai);
- if (machine->ops && machine->ops->shutdown)
- machine->ops->shutdown(substream);
+ if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
+ rtd->dai_link->ops->shutdown(substream);
- if (platform->pcm_ops->close)
- platform->pcm_ops->close(substream);
+ if (platform->driver->ops->close)
+ platform->driver->ops->close(substream);
+ cpu_dai->runtime = NULL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
/* start delayed pop wq here for playback streams */
codec_dai->pop_wait = 1;
- schedule_delayed_work(&card->delayed_work,
- msecs_to_jiffies(card->pmdown_time));
+ schedule_delayed_work(&rtd->delayed_work,
+ msecs_to_jiffies(rtd->pmdown_time));
} else {
/* capture streams can be powered down now */
- snd_soc_dapm_stream_event(codec,
- codec_dai->capture.stream_name,
+ snd_soc_dapm_stream_event(rtd,
+ codec_dai->driver->capture.stream_name,
SND_SOC_DAPM_STREAM_STOP);
}
@@ -618,43 +707,39 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
static int soc_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
- struct snd_soc_codec *codec = card->codec;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret = 0;
mutex_lock(&pcm_mutex);
- if (machine->ops && machine->ops->prepare) {
- ret = machine->ops->prepare(substream);
+ if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) {
+ ret = rtd->dai_link->ops->prepare(substream);
if (ret < 0) {
printk(KERN_ERR "asoc: machine prepare error\n");
goto out;
}
}
- if (platform->pcm_ops->prepare) {
- ret = platform->pcm_ops->prepare(substream);
+ if (platform->driver->ops->prepare) {
+ ret = platform->driver->ops->prepare(substream);
if (ret < 0) {
printk(KERN_ERR "asoc: platform prepare error\n");
goto out;
}
}
- if (codec_dai->ops->prepare) {
- ret = codec_dai->ops->prepare(substream, codec_dai);
+ if (codec_dai->driver->ops->prepare) {
+ ret = codec_dai->driver->ops->prepare(substream, codec_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: codec DAI prepare error\n");
goto out;
}
}
- if (cpu_dai->ops->prepare) {
- ret = cpu_dai->ops->prepare(substream, cpu_dai);
+ if (cpu_dai->driver->ops->prepare) {
+ ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: cpu DAI prepare error\n");
goto out;
@@ -665,16 +750,16 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
codec_dai->pop_wait) {
codec_dai->pop_wait = 0;
- cancel_delayed_work(&card->delayed_work);
+ cancel_delayed_work(&rtd->delayed_work);
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- snd_soc_dapm_stream_event(codec,
- codec_dai->playback.stream_name,
+ snd_soc_dapm_stream_event(rtd,
+ codec_dai->driver->playback.stream_name,
SND_SOC_DAPM_STREAM_START);
else
- snd_soc_dapm_stream_event(codec,
- codec_dai->capture.stream_name,
+ snd_soc_dapm_stream_event(rtd,
+ codec_dai->driver->capture.stream_name,
SND_SOC_DAPM_STREAM_START);
snd_soc_dai_digital_mute(codec_dai, 0);
@@ -693,26 +778,23 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret = 0;
mutex_lock(&pcm_mutex);
- if (machine->ops && machine->ops->hw_params) {
- ret = machine->ops->hw_params(substream, params);
+ if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
+ ret = rtd->dai_link->ops->hw_params(substream, params);
if (ret < 0) {
printk(KERN_ERR "asoc: machine hw_params failed\n");
goto out;
}
}
- if (codec_dai->ops->hw_params) {
- ret = codec_dai->ops->hw_params(substream, params, codec_dai);
+ if (codec_dai->driver->ops->hw_params) {
+ ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: can't set codec %s hw params\n",
codec_dai->name);
@@ -720,8 +802,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
}
}
- if (cpu_dai->ops->hw_params) {
- ret = cpu_dai->ops->hw_params(substream, params, cpu_dai);
+ if (cpu_dai->driver->ops->hw_params) {
+ ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: interface %s hw params failed\n",
cpu_dai->name);
@@ -729,8 +811,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
}
}
- if (platform->pcm_ops->hw_params) {
- ret = platform->pcm_ops->hw_params(substream, params);
+ if (platform->driver->ops->hw_params) {
+ ret = platform->driver->ops->hw_params(substream, params);
if (ret < 0) {
printk(KERN_ERR "asoc: platform %s hw params failed\n",
platform->name);
@@ -738,23 +820,23 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
}
}
- machine->rate = params_rate(params);
+ rtd->rate = params_rate(params);
out:
mutex_unlock(&pcm_mutex);
return ret;
platform_err:
- if (cpu_dai->ops->hw_free)
- cpu_dai->ops->hw_free(substream, cpu_dai);
+ if (cpu_dai->driver->ops->hw_free)
+ cpu_dai->driver->ops->hw_free(substream, cpu_dai);
interface_err:
- if (codec_dai->ops->hw_free)
- codec_dai->ops->hw_free(substream, codec_dai);
+ if (codec_dai->driver->ops->hw_free)
+ codec_dai->driver->ops->hw_free(substream, codec_dai);
codec_err:
- if (machine->ops && machine->ops->hw_free)
- machine->ops->hw_free(substream);
+ if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
+ rtd->dai_link->ops->hw_free(substream);
mutex_unlock(&pcm_mutex);
return ret;
@@ -766,13 +848,10 @@ codec_err:
static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
- struct snd_soc_codec *codec = card->codec;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = rtd->codec;
mutex_lock(&pcm_mutex);
@@ -781,19 +860,19 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
snd_soc_dai_digital_mute(codec_dai, 1);
/* free any machine hw params */
- if (machine->ops && machine->ops->hw_free)
- machine->ops->hw_free(substream);
+ if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
+ rtd->dai_link->ops->hw_free(substream);
/* free any DMA resources */
- if (platform->pcm_ops->hw_free)
- platform->pcm_ops->hw_free(substream);
+ if (platform->driver->ops->hw_free)
+ platform->driver->ops->hw_free(substream);
/* now free hw params for the DAI's */
- if (codec_dai->ops->hw_free)
- codec_dai->ops->hw_free(substream, codec_dai);
+ if (codec_dai->driver->ops->hw_free)
+ codec_dai->driver->ops->hw_free(substream, codec_dai);
- if (cpu_dai->ops->hw_free)
- cpu_dai->ops->hw_free(substream, cpu_dai);
+ if (cpu_dai->driver->ops->hw_free)
+ cpu_dai->driver->ops->hw_free(substream, cpu_dai);
mutex_unlock(&pcm_mutex);
return 0;
@@ -802,28 +881,25 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_card *card= socdev->card;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
- if (codec_dai->ops->trigger) {
- ret = codec_dai->ops->trigger(substream, cmd, codec_dai);
+ if (codec_dai->driver->ops->trigger) {
+ ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
if (ret < 0)
return ret;
}
- if (platform->pcm_ops->trigger) {
- ret = platform->pcm_ops->trigger(substream, cmd);
+ if (platform->driver->ops->trigger) {
+ ret = platform->driver->ops->trigger(substream, cmd);
if (ret < 0)
return ret;
}
- if (cpu_dai->ops->trigger) {
- ret = cpu_dai->ops->trigger(substream, cmd, cpu_dai);
+ if (cpu_dai->driver->ops->trigger) {
+ ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
if (ret < 0)
return ret;
}
@@ -838,27 +914,24 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_dai *cpu_dai = machine->cpu_dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t offset = 0;
snd_pcm_sframes_t delay = 0;
- if (platform->pcm_ops->pointer)
- offset = platform->pcm_ops->pointer(substream);
+ if (platform->driver->ops->pointer)
+ offset = platform->driver->ops->pointer(substream);
- if (cpu_dai->ops->delay)
- delay += cpu_dai->ops->delay(substream, cpu_dai);
+ if (cpu_dai->driver->ops->delay)
+ delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
- if (codec_dai->ops->delay)
- delay += codec_dai->ops->delay(substream, codec_dai);
+ if (codec_dai->driver->ops->delay)
+ delay += codec_dai->driver->ops->delay(substream, codec_dai);
- if (platform->delay)
- delay += platform->delay(substream, codec_dai);
+ if (platform->driver->delay)
+ delay += platform->driver->delay(substream, codec_dai);
runtime->delay = delay;
@@ -881,104 +954,111 @@ static struct snd_pcm_ops soc_pcm_ops = {
static int soc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
- struct snd_soc_codec *codec = card->codec;
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
int i;
/* If the initialization of this soc device failed, there is no codec
* associated with it. Just bail out in this case.
*/
- if (!codec)
+ if (list_empty(&card->codec_dev_list))
return 0;
/* Due to the resume being scheduled into a workqueue we could
* suspend before that's finished - wait for it to complete.
*/
- snd_power_lock(codec->card);
- snd_power_wait(codec->card, SNDRV_CTL_POWER_D0);
- snd_power_unlock(codec->card);
+ snd_power_lock(card->snd_card);
+ snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0);
+ snd_power_unlock(card->snd_card);
/* we're going to block userspace touching us until resume completes */
- snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot);
+ snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
/* mute any active DAC's */
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *dai = card->rtd[i].codec_dai;
+ struct snd_soc_dai_driver *drv = dai->driver;
- if (card->dai_link[i].ignore_suspend)
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (dai->ops->digital_mute && dai->playback.active)
- dai->ops->digital_mute(dai, 1);
+ if (drv->ops->digital_mute && dai->playback_active)
+ drv->ops->digital_mute(dai, 1);
}
/* suspend all pcms */
- for (i = 0; i < card->num_links; i++) {
- if (card->dai_link[i].ignore_suspend)
+ for (i = 0; i < card->num_rtd; i++) {
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- snd_pcm_suspend_all(card->dai_link[i].pcm);
+ snd_pcm_suspend_all(card->rtd[i].pcm);
}
if (card->suspend_pre)
card->suspend_pre(pdev, PMSG_SUSPEND);
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+ struct snd_soc_platform *platform = card->rtd[i].platform;
- if (card->dai_link[i].ignore_suspend)
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (cpu_dai->suspend && !cpu_dai->ac97_control)
- cpu_dai->suspend(cpu_dai);
- if (platform->suspend)
- platform->suspend(&card->dai_link[i]);
+ if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control)
+ cpu_dai->driver->suspend(cpu_dai);
+ if (platform->driver->suspend && !platform->suspended) {
+ platform->driver->suspend(cpu_dai);
+ platform->suspended = 1;
+ }
}
/* close any waiting streams and save state */
- run_delayed_work(&card->delayed_work);
- codec->suspend_bias_level = codec->bias_level;
+ for (i = 0; i < card->num_rtd; i++) {
+ run_delayed_work(&card->rtd[i].delayed_work);
+ card->rtd[i].codec->suspend_bias_level = card->rtd[i].codec->bias_level;
+ }
- for (i = 0; i < codec->num_dai; i++) {
- char *stream = codec->dai[i].playback.stream_name;
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
- if (card->dai_link[i].ignore_suspend)
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (stream != NULL)
- snd_soc_dapm_stream_event(codec, stream,
+ if (driver->playback.stream_name != NULL)
+ snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
SND_SOC_DAPM_STREAM_SUSPEND);
- stream = codec->dai[i].capture.stream_name;
- if (stream != NULL)
- snd_soc_dapm_stream_event(codec, stream,
+
+ if (driver->capture.stream_name != NULL)
+ snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
SND_SOC_DAPM_STREAM_SUSPEND);
}
- /* If there are paths active then the CODEC will be held with
- * bias _ON and should not be suspended. */
- if (codec_dev->suspend) {
- switch (codec->bias_level) {
- case SND_SOC_BIAS_STANDBY:
- case SND_SOC_BIAS_OFF:
- codec_dev->suspend(pdev, PMSG_SUSPEND);
- break;
- default:
- dev_dbg(socdev->dev, "CODEC is on over suspend\n");
- break;
+ /* suspend all CODECs */
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_codec *codec = card->rtd[i].codec;
+ /* If there are paths active then the CODEC will be held with
+ * bias _ON and should not be suspended. */
+ if (!codec->suspended && codec->driver->suspend) {
+ switch (codec->bias_level) {
+ case SND_SOC_BIAS_STANDBY:
+ case SND_SOC_BIAS_OFF:
+ codec->driver->suspend(codec, PMSG_SUSPEND);
+ codec->suspended = 1;
+ break;
+ default:
+ dev_dbg(codec->dev, "CODEC is on over suspend\n");
+ break;
+ }
}
}
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
- if (card->dai_link[i].ignore_suspend)
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (cpu_dai->suspend && cpu_dai->ac97_control)
- cpu_dai->suspend(cpu_dai);
+ if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control)
+ cpu_dai->driver->suspend(cpu_dai);
}
if (card->suspend_post)
@@ -992,127 +1072,127 @@ static int soc_suspend(struct device *dev)
*/
static void soc_resume_deferred(struct work_struct *work)
{
- struct snd_soc_card *card = container_of(work,
- struct snd_soc_card,
- deferred_resume_work);
- struct snd_soc_device *socdev = card->socdev;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
- struct snd_soc_codec *codec = card->codec;
- struct platform_device *pdev = to_platform_device(socdev->dev);
+ struct snd_soc_card *card =
+ container_of(work, struct snd_soc_card, deferred_resume_work);
+ struct platform_device *pdev = to_platform_device(card->dev);
int i;
/* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
* so userspace apps are blocked from touching us
*/
- dev_dbg(socdev->dev, "starting resume work\n");
+ dev_dbg(card->dev, "starting resume work\n");
/* Bring us up into D2 so that DAPM starts enabling things */
- snd_power_change_state(codec->card, SNDRV_CTL_POWER_D2);
+ snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2);
if (card->resume_pre)
card->resume_pre(pdev);
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+ /* resume AC97 DAIs */
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
- if (card->dai_link[i].ignore_suspend)
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (cpu_dai->resume && cpu_dai->ac97_control)
- cpu_dai->resume(cpu_dai);
- }
-
- /* If the CODEC was idle over suspend then it will have been
- * left with bias OFF or STANDBY and suspended so we must now
- * resume. Otherwise the suspend was suppressed.
- */
- if (codec_dev->resume) {
- switch (codec->bias_level) {
- case SND_SOC_BIAS_STANDBY:
- case SND_SOC_BIAS_OFF:
- codec_dev->resume(pdev);
- break;
- default:
- dev_dbg(socdev->dev, "CODEC was on over suspend\n");
- break;
+ if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control)
+ cpu_dai->driver->resume(cpu_dai);
+ }
+
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_codec *codec = card->rtd[i].codec;
+ /* If the CODEC was idle over suspend then it will have been
+ * left with bias OFF or STANDBY and suspended so we must now
+ * resume. Otherwise the suspend was suppressed.
+ */
+ if (codec->driver->resume && codec->suspended) {
+ switch (codec->bias_level) {
+ case SND_SOC_BIAS_STANDBY:
+ case SND_SOC_BIAS_OFF:
+ codec->driver->resume(codec);
+ codec->suspended = 0;
+ break;
+ default:
+ dev_dbg(codec->dev, "CODEC was on over suspend\n");
+ break;
+ }
}
}
- for (i = 0; i < codec->num_dai; i++) {
- char *stream = codec->dai[i].playback.stream_name;
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
- if (card->dai_link[i].ignore_suspend)
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (stream != NULL)
- snd_soc_dapm_stream_event(codec, stream,
+ if (driver->playback.stream_name != NULL)
+ snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
SND_SOC_DAPM_STREAM_RESUME);
- stream = codec->dai[i].capture.stream_name;
- if (stream != NULL)
- snd_soc_dapm_stream_event(codec, stream,
+
+ if (driver->capture.stream_name != NULL)
+ snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
SND_SOC_DAPM_STREAM_RESUME);
}
/* unmute any active DACs */
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *dai = card->rtd[i].codec_dai;
+ struct snd_soc_dai_driver *drv = dai->driver;
- if (card->dai_link[i].ignore_suspend)
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (dai->ops->digital_mute && dai->playback.active)
- dai->ops->digital_mute(dai, 0);
+ if (drv->ops->digital_mute && dai->playback_active)
+ drv->ops->digital_mute(dai, 0);
}
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+ struct snd_soc_platform *platform = card->rtd[i].platform;
- if (card->dai_link[i].ignore_suspend)
+ if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (cpu_dai->resume && !cpu_dai->ac97_control)
- cpu_dai->resume(cpu_dai);
- if (platform->resume)
- platform->resume(&card->dai_link[i]);
+ if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control)
+ cpu_dai->driver->resume(cpu_dai);
+ if (platform->driver->resume && platform->suspended) {
+ platform->driver->resume(cpu_dai);
+ platform->suspended = 0;
+ }
}
if (card->resume_post)
card->resume_post(pdev);
- dev_dbg(socdev->dev, "resume work completed\n");
+ dev_dbg(card->dev, "resume work completed\n");
/* userspace can access us now we are back as we were before */
- snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0);
+ snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
}
/* powers up audio subsystem after a suspend */
static int soc_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_dai *cpu_dai = card->dai_link[0].cpu_dai;
-
- /* If the initialization of this soc device failed, there is no codec
- * associated with it. Just bail out in this case.
- */
- if (!card->codec)
- return 0;
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ int i;
/* AC97 devices might have other drivers hanging off them so
* need to resume immediately. Other drivers don't have that
* problem and may take a substantial amount of time to resume
* due to I/O costs and anti-pop so handle them out of line.
*/
- if (cpu_dai->ac97_control) {
- dev_dbg(socdev->dev, "Resuming AC97 immediately\n");
- soc_resume_deferred(&card->deferred_resume_work);
- } else {
- dev_dbg(socdev->dev, "Scheduling resume work\n");
- if (!schedule_work(&card->deferred_resume_work))
- dev_err(socdev->dev, "resume work item may be lost\n");
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+ if (cpu_dai->driver->ac97_control) {
+ dev_dbg(dev, "Resuming AC97 immediately\n");
+ soc_resume_deferred(&card->deferred_resume_work);
+ } else {
+ dev_dbg(dev, "Scheduling resume work\n");
+ if (!schedule_work(&card->deferred_resume_work))
+ dev_err(dev, "resume work item may be lost\n");
+ }
}
return 0;
@@ -1125,198 +1205,440 @@ static int soc_resume(struct device *dev)
static struct snd_soc_dai_ops null_dai_ops = {
};
-static void snd_soc_instantiate_card(struct snd_soc_card *card)
+static int soc_bind_dai_link(struct snd_soc_card *card, int num)
{
- struct platform_device *pdev = container_of(card->dev,
- struct platform_device,
- dev);
- struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev;
+ struct snd_soc_dai_link *dai_link = &card->dai_link[num];
+ struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
struct snd_soc_codec *codec;
struct snd_soc_platform *platform;
- struct snd_soc_dai *dai;
- int i, found, ret, ac97;
+ struct snd_soc_dai *codec_dai, *cpu_dai;
- if (card->instantiated)
- return;
+ if (rtd->complete)
+ return 1;
+ dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num);
- found = 0;
- list_for_each_entry(platform, &platform_list, list)
- if (card->platform == platform) {
- found = 1;
- break;
+ /* do we already have the CPU DAI for this link ? */
+ if (rtd->cpu_dai) {
+ goto find_codec;
+ }
+ /* no, then find CPU DAI from registered DAIs*/
+ list_for_each_entry(cpu_dai, &dai_list, list) {
+ if (!strcmp(cpu_dai->name, dai_link->cpu_dai_name)) {
+
+ if (!try_module_get(cpu_dai->dev->driver->owner))
+ return -ENODEV;
+
+ rtd->cpu_dai = cpu_dai;
+ goto find_codec;
}
- if (!found) {
- dev_dbg(card->dev, "Platform %s not registered\n",
- card->platform->name);
- return;
}
+ dev_dbg(card->dev, "CPU DAI %s not registered\n",
+ dai_link->cpu_dai_name);
- ac97 = 0;
- for (i = 0; i < card->num_links; i++) {
- found = 0;
- list_for_each_entry(dai, &dai_list, list)
- if (card->dai_link[i].cpu_dai == dai) {
- found = 1;
- break;
+find_codec:
+ /* do we already have the CODEC for this link ? */
+ if (rtd->codec) {
+ goto find_platform;
+ }
+
+ /* no, then find CODEC from registered CODECs*/
+ list_for_each_entry(codec, &codec_list, list) {
+ if (!strcmp(codec->name, dai_link->codec_name)) {
+ rtd->codec = codec;
+
+ if (!try_module_get(codec->dev->driver->owner))
+ return -ENODEV;
+
+ /* CODEC found, so find CODEC DAI from registered DAIs from this CODEC*/
+ list_for_each_entry(codec_dai, &dai_list, list) {
+ if (codec->dev == codec_dai->dev &&
+ !strcmp(codec_dai->name, dai_link->codec_dai_name)) {
+ rtd->codec_dai = codec_dai;
+ goto find_platform;
+ }
}
- if (!found) {
- dev_dbg(card->dev, "DAI %s not registered\n",
- card->dai_link[i].cpu_dai->name);
- return;
+ dev_dbg(card->dev, "CODEC DAI %s not registered\n",
+ dai_link->codec_dai_name);
+
+ goto find_platform;
}
+ }
+ dev_dbg(card->dev, "CODEC %s not registered\n",
+ dai_link->codec_name);
- if (card->dai_link[i].cpu_dai->ac97_control)
- ac97 = 1;
+find_platform:
+ /* do we already have the CODEC DAI for this link ? */
+ if (rtd->platform) {
+ goto out;
}
+ /* no, then find CPU DAI from registered DAIs*/
+ list_for_each_entry(platform, &platform_list, list) {
+ if (!strcmp(platform->name, dai_link->platform_name)) {
- for (i = 0; i < card->num_links; i++) {
- if (!card->dai_link[i].codec_dai->ops)
- card->dai_link[i].codec_dai->ops = &null_dai_ops;
+ if (!try_module_get(platform->dev->driver->owner))
+ return -ENODEV;
+
+ rtd->platform = platform;
+ goto out;
+ }
}
- /* If we have AC97 in the system then don't wait for the
- * codec. This will need revisiting if we have to handle
- * systems with mixed AC97 and non-AC97 parts. Only check for
- * DAIs currently; we can't do this per link since some AC97
- * codecs have non-AC97 DAIs.
- */
- if (!ac97)
- for (i = 0; i < card->num_links; i++) {
- found = 0;
- list_for_each_entry(dai, &dai_list, list)
- if (card->dai_link[i].codec_dai == dai) {
- found = 1;
- break;
- }
- if (!found) {
- dev_dbg(card->dev, "DAI %s not registered\n",
- card->dai_link[i].codec_dai->name);
- return;
- }
+ dev_dbg(card->dev, "platform %s not registered\n",
+ dai_link->platform_name);
+ return 0;
+
+out:
+ /* mark rtd as complete if we found all 4 of our client devices */
+ if (rtd->codec && rtd->codec_dai && rtd->platform && rtd->cpu_dai) {
+ rtd->complete = 1;
+ card->num_rtd++;
+ }
+ return 1;
+}
+
+static void soc_remove_dai_link(struct snd_soc_card *card, int num)
+{
+ struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
+ int err;
+
+ /* unregister the rtd device */
+ if (rtd->dev_registered) {
+ device_remove_file(&rtd->dev, &dev_attr_pmdown_time);
+ device_unregister(&rtd->dev);
+ rtd->dev_registered = 0;
+ }
+
+ /* remove the CODEC DAI */
+ if (codec_dai && codec_dai->probed) {
+ if (codec_dai->driver->remove) {
+ err = codec_dai->driver->remove(codec_dai);
+ if (err < 0)
+ printk(KERN_ERR "asoc: failed to remove %s\n", codec_dai->name);
}
+ codec_dai->probed = 0;
+ list_del(&codec_dai->card_list);
+ }
- /* Note that we do not current check for codec components */
+ /* remove the platform */
+ if (platform && platform->probed) {
+ if (platform->driver->remove) {
+ err = platform->driver->remove(platform);
+ if (err < 0)
+ printk(KERN_ERR "asoc: failed to remove %s\n", platform->name);
+ }
+ platform->probed = 0;
+ list_del(&platform->card_list);
+ module_put(platform->dev->driver->owner);
+ }
- dev_dbg(card->dev, "All components present, instantiating\n");
+ /* remove the CODEC */
+ if (codec && codec->probed) {
+ if (codec->driver->remove) {
+ err = codec->driver->remove(codec);
+ if (err < 0)
+ printk(KERN_ERR "asoc: failed to remove %s\n", codec->name);
+ }
- /* Found everything, bring it up */
- card->pmdown_time = pmdown_time;
+ /* Make sure all DAPM widgets are freed */
+ snd_soc_dapm_free(codec);
- if (card->probe) {
- ret = card->probe(pdev);
- if (ret < 0)
- return;
+ soc_cleanup_codec_debugfs(codec);
+ device_remove_file(&rtd->dev, &dev_attr_codec_reg);
+ codec->probed = 0;
+ list_del(&codec->card_list);
+ module_put(codec->dev->driver->owner);
}
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
- if (cpu_dai->probe) {
- ret = cpu_dai->probe(pdev, cpu_dai);
- if (ret < 0)
- goto cpu_dai_err;
+ /* remove the cpu_dai */
+ if (cpu_dai && cpu_dai->probed) {
+ if (cpu_dai->driver->remove) {
+ err = cpu_dai->driver->remove(cpu_dai);
+ if (err < 0)
+ printk(KERN_ERR "asoc: failed to remove %s\n", cpu_dai->name);
}
+ cpu_dai->probed = 0;
+ list_del(&cpu_dai->card_list);
+ module_put(cpu_dai->dev->driver->owner);
}
+}
- if (codec_dev->probe) {
- ret = codec_dev->probe(pdev);
- if (ret < 0)
- goto cpu_dai_err;
+static void rtd_release(struct device *dev) {}
+
+static int soc_probe_dai_link(struct snd_soc_card *card, int num)
+{
+ struct snd_soc_dai_link *dai_link = &card->dai_link[num];
+ struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
+ int ret;
+
+ dev_dbg(card->dev, "probe %s dai link %d\n", card->name, num);
+
+ /* config components */
+ codec_dai->codec = codec;
+ codec->card = card;
+ cpu_dai->platform = platform;
+ rtd->card = card;
+ rtd->dev.parent = card->dev;
+ codec_dai->card = card;
+ cpu_dai->card = card;
+
+ /* set default power off timeout */
+ rtd->pmdown_time = pmdown_time;
+
+ /* probe the cpu_dai */
+ if (!cpu_dai->probed) {
+ if (cpu_dai->driver->probe) {
+ ret = cpu_dai->driver->probe(cpu_dai);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to probe CPU DAI %s\n",
+ cpu_dai->name);
+ return ret;
+ }
+ }
+ cpu_dai->probed = 1;
+ /* mark cpu_dai as probed and add to card cpu_dai list */
+ list_add(&cpu_dai->card_list, &card->dai_dev_list);
}
- codec = card->codec;
- if (platform->probe) {
- ret = platform->probe(pdev);
- if (ret < 0)
- goto platform_err;
+ /* probe the CODEC */
+ if (!codec->probed) {
+ if (codec->driver->probe) {
+ ret = codec->driver->probe(codec);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to probe CODEC %s\n",
+ codec->name);
+ return ret;
+ }
+ }
+
+ soc_init_codec_debugfs(codec);
+
+ /* mark codec as probed and add to card codec list */
+ codec->probed = 1;
+ list_add(&codec->card_list, &card->codec_dev_list);
}
- /* DAPM stream work */
- INIT_DELAYED_WORK(&card->delayed_work, close_delayed_work);
-#ifdef CONFIG_PM
- /* deferred resume work */
- INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
-#endif
+ /* probe the platform */
+ if (!platform->probed) {
+ if (platform->driver->probe) {
+ ret = platform->driver->probe(platform);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to probe platform %s\n",
+ platform->name);
+ return ret;
+ }
+ }
+ /* mark platform as probed and add to card platform list */
+ platform->probed = 1;
+ list_add(&platform->card_list, &card->platform_dev_list);
+ }
- for (i = 0; i < card->num_links; i++) {
- if (card->dai_link[i].init) {
- ret = card->dai_link[i].init(codec);
+ /* probe the CODEC DAI */
+ if (!codec_dai->probed) {
+ if (codec_dai->driver->probe) {
+ ret = codec_dai->driver->probe(codec_dai);
if (ret < 0) {
- printk(KERN_ERR "asoc: failed to init %s\n",
- card->dai_link[i].stream_name);
- continue;
+ printk(KERN_ERR "asoc: failed to probe CODEC DAI %s\n",
+ codec_dai->name);
+ return ret;
}
}
- if (card->dai_link[i].codec_dai->ac97_control)
- ac97 = 1;
+
+ /* mark cpu_dai as probed and add to card cpu_dai list */
+ codec_dai->probed = 1;
+ list_add(&codec_dai->card_list, &card->dai_dev_list);
}
- snprintf(codec->card->shortname, sizeof(codec->card->shortname),
- "%s", card->name);
- snprintf(codec->card->longname, sizeof(codec->card->longname),
- "%s (%s)", card->name, codec->name);
+ /* DAPM dai link stream work */
+ INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
+
+ /* now that all clients have probed, initialise the DAI link */
+ if (dai_link->init) {
+ ret = dai_link->init(rtd);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to init %s\n", dai_link->stream_name);
+ return ret;
+ }
+ }
/* Make sure all DAPM widgets are instantiated */
snd_soc_dapm_new_widgets(codec);
+ snd_soc_dapm_sync(codec);
- ret = snd_card_register(codec->card);
+ /* register the rtd device */
+ rtd->dev.release = rtd_release;
+ rtd->dev.init_name = dai_link->name;
+ ret = device_register(&rtd->dev);
if (ret < 0) {
- printk(KERN_ERR "asoc: failed to register soundcard for %s\n",
- codec->name);
- goto card_err;
+ printk(KERN_ERR "asoc: failed to register DAI runtime device %d\n", ret);
+ return ret;
}
- mutex_lock(&codec->mutex);
+ rtd->dev_registered = 1;
+ ret = device_create_file(&rtd->dev, &dev_attr_pmdown_time);
+ if (ret < 0)
+ printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n");
+
+ /* add DAPM sysfs entries for this codec */
+ ret = snd_soc_dapm_sys_add(&rtd->dev);
+ if (ret < 0)
+ printk(KERN_WARNING "asoc: failed to add codec dapm sysfs entries\n");
+
+ /* add codec sysfs entries */
+ ret = device_create_file(&rtd->dev, &dev_attr_codec_reg);
+ if (ret < 0)
+ printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
+
+ /* create the pcm */
+ ret = soc_new_pcm(rtd, num);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: can't create pcm %s\n", dai_link->stream_name);
+ return ret;
+ }
+
+ /* add platform data for AC97 devices */
+ if (rtd->codec_dai->driver->ac97_control)
+ snd_ac97_dev_add_pdata(codec->ac97, rtd->cpu_dai->ac97_pdata);
+
+ return 0;
+}
+
#ifdef CONFIG_SND_SOC_AC97_BUS
+static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+
/* Only instantiate AC97 if not already done by the adaptor
* for the generic AC97 subsystem.
*/
- if (ac97 && strcmp(codec->name, "AC97") != 0) {
- ret = soc_ac97_dev_register(codec);
+ if (rtd->codec_dai->driver->ac97_control && !rtd->codec->ac97_registered) {
+ /*
+ * It is possible that the AC97 device is already registered to
+ * the device subsystem. This happens when the device is created
+ * via snd_ac97_mixer(). Currently only SoC codec that does so
+ * is the generic AC97 glue but others migh emerge.
+ *
+ * In those cases we don't try to register the device again.
+ */
+ if (!rtd->codec->ac97_created)
+ return 0;
+
+ ret = soc_ac97_dev_register(rtd->codec);
if (ret < 0) {
printk(KERN_ERR "asoc: AC97 device register failed\n");
- snd_card_free(codec->card);
- mutex_unlock(&codec->mutex);
- goto card_err;
+ return ret;
}
+
+ rtd->codec->ac97_registered = 1;
+ }
+ return 0;
+}
+
+static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec)
+{
+ if (codec->ac97_registered) {
+ soc_ac97_dev_unregister(codec);
+ codec->ac97_registered = 0;
}
+}
#endif
- ret = snd_soc_dapm_sys_add(card->socdev->dev);
- if (ret < 0)
- printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n");
+static void snd_soc_instantiate_card(struct snd_soc_card *card)
+{
+ struct platform_device *pdev = to_platform_device(card->dev);
+ int ret, i;
- ret = device_create_file(card->socdev->dev, &dev_attr_pmdown_time);
- if (ret < 0)
- printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n");
+ mutex_lock(&card->mutex);
- ret = device_create_file(card->socdev->dev, &dev_attr_codec_reg);
- if (ret < 0)
- printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
+ if (card->instantiated) {
+ mutex_unlock(&card->mutex);
+ return;
+ }
- soc_init_codec_debugfs(codec);
- mutex_unlock(&codec->mutex);
+ /* bind DAIs */
+ for (i = 0; i < card->num_links; i++)
+ soc_bind_dai_link(card, i);
- card->instantiated = 1;
+ /* bind completed ? */
+ if (card->num_rtd != card->num_links) {
+ mutex_unlock(&card->mutex);
+ return;
+ }
- return;
+ /* card bind complete so register a sound card */
+ ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ card->owner, 0, &card->snd_card);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: can't create sound card for card %s\n",
+ card->name);
+ mutex_unlock(&card->mutex);
+ return;
+ }
+ card->snd_card->dev = card->dev;
-card_err:
- if (platform->remove)
- platform->remove(pdev);
+#ifdef CONFIG_PM
+ /* deferred resume work */
+ INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
+#endif
-platform_err:
- if (codec_dev->remove)
- codec_dev->remove(pdev);
+ /* initialise the sound card only once */
+ if (card->probe) {
+ ret = card->probe(pdev);
+ if (ret < 0)
+ goto card_probe_error;
+ }
-cpu_dai_err:
- for (i--; i >= 0; i--) {
- struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
- if (cpu_dai->remove)
- cpu_dai->remove(pdev, cpu_dai);
+ for (i = 0; i < card->num_links; i++) {
+ ret = soc_probe_dai_link(card, i);
+ if (ret < 0) {
+ pr_err("asoc: failed to instantiate card %s: %d\n",
+ card->name, ret);
+ goto probe_dai_err;
+ }
}
+ snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
+ "%s", card->name);
+ snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
+ "%s", card->name);
+
+ ret = snd_card_register(card->snd_card);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name);
+ goto probe_dai_err;
+ }
+
+#ifdef CONFIG_SND_SOC_AC97_BUS
+ /* register any AC97 codecs */
+ for (i = 0; i < card->num_rtd; i++) {
+ ret = soc_register_ac97_dai_link(&card->rtd[i]);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name);
+ goto probe_dai_err;
+ }
+ }
+#endif
+
+ card->instantiated = 1;
+ mutex_unlock(&card->mutex);
+ return;
+
+probe_dai_err:
+ for (i = 0; i < card->num_links; i++)
+ soc_remove_dai_link(card, i);
+
+card_probe_error:
if (card->remove)
card->remove(pdev);
+
+ snd_card_free(card->snd_card);
+
+ mutex_unlock(&card->mutex);
}
/*
@@ -1333,15 +1655,15 @@ static void snd_soc_instantiate_cards(void)
/* probes a new socdev */
static int soc_probe(struct platform_device *pdev)
{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
int ret = 0;
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
-
- /* Bodge while we push things out of socdev */
- card->socdev = socdev;
/* Bodge while we unpick instantiation */
card->dev = &pdev->dev;
+ INIT_LIST_HEAD(&card->dai_dev_list);
+ INIT_LIST_HEAD(&card->codec_dev_list);
+ INIT_LIST_HEAD(&card->platform_dev_list);
+
ret = snd_soc_register_card(card);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to register card\n");
@@ -1354,50 +1676,49 @@ static int soc_probe(struct platform_device *pdev)
/* removes a socdev */
static int soc_remove(struct platform_device *pdev)
{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
int i;
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
- if (card->instantiated) {
- run_delayed_work(&card->delayed_work);
-
- if (platform->remove)
- platform->remove(pdev);
+ if (card->instantiated) {
- if (codec_dev->remove)
- codec_dev->remove(pdev);
-
- for (i = 0; i < card->num_links; i++) {
- struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
- if (cpu_dai->remove)
- cpu_dai->remove(pdev, cpu_dai);
+ /* make sure any delayed work runs */
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+ run_delayed_work(&rtd->delayed_work);
}
+ /* remove and free each DAI */
+ for (i = 0; i < card->num_rtd; i++)
+ soc_remove_dai_link(card, i);
+
+ /* remove the card */
if (card->remove)
card->remove(pdev);
- }
+ kfree(card->rtd);
+ snd_card_free(card->snd_card);
+ }
snd_soc_unregister_card(card);
-
return 0;
}
static int soc_poweroff(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ int i;
if (!card->instantiated)
return 0;
/* Flush out pmdown_time work - we actually do want to run it
* now, we're shutting down so no imminent restart. */
- run_delayed_work(&card->delayed_work);
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+ run_delayed_work(&rtd->delayed_work);
+ }
- snd_soc_dapm_shutdown(socdev);
+ snd_soc_dapm_shutdown(card);
return 0;
}
@@ -1420,53 +1741,42 @@ static struct platform_driver soc_driver = {
};
/* create a new pcm */
-static int soc_new_pcm(struct snd_soc_device *socdev,
- struct snd_soc_dai_link *dai_link, int num)
-{
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_codec *codec = card->codec;
- struct snd_soc_platform *platform = card->platform;
- struct snd_soc_dai *codec_dai = dai_link->codec_dai;
- struct snd_soc_dai *cpu_dai = dai_link->cpu_dai;
- struct snd_soc_pcm_runtime *rtd;
+static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_pcm *pcm;
char new_name[64];
int ret = 0, playback = 0, capture = 0;
- rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL);
- if (rtd == NULL)
- return -ENOMEM;
-
- rtd->dai = dai_link;
- rtd->socdev = socdev;
- codec_dai->codec = card->codec;
-
/* check client and interface hw capabilities */
snprintf(new_name, sizeof(new_name), "%s %s-%d",
- dai_link->stream_name, codec_dai->name, num);
+ rtd->dai_link->stream_name, codec_dai->name, num);
- if (codec_dai->playback.channels_min)
+ if (codec_dai->driver->playback.channels_min)
playback = 1;
- if (codec_dai->capture.channels_min)
+ if (codec_dai->driver->capture.channels_min)
capture = 1;
- ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback,
- capture, &pcm);
+ dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name);
+ ret = snd_pcm_new(rtd->card->snd_card, new_name,
+ num, playback, capture, &pcm);
if (ret < 0) {
- printk(KERN_ERR "asoc: can't create pcm for codec %s\n",
- codec->name);
- kfree(rtd);
+ printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
return ret;
}
- dai_link->pcm = pcm;
+ rtd->pcm = pcm;
pcm->private_data = rtd;
- soc_pcm_ops.mmap = platform->pcm_ops->mmap;
- soc_pcm_ops.ioctl = platform->pcm_ops->ioctl;
- soc_pcm_ops.copy = platform->pcm_ops->copy;
- soc_pcm_ops.silence = platform->pcm_ops->silence;
- soc_pcm_ops.ack = platform->pcm_ops->ack;
- soc_pcm_ops.page = platform->pcm_ops->page;
+ soc_pcm_ops.mmap = platform->driver->ops->mmap;
+ soc_pcm_ops.pointer = platform->driver->ops->pointer;
+ soc_pcm_ops.ioctl = platform->driver->ops->ioctl;
+ soc_pcm_ops.copy = platform->driver->ops->copy;
+ soc_pcm_ops.silence = platform->driver->ops->silence;
+ soc_pcm_ops.ack = platform->driver->ops->ack;
+ soc_pcm_ops.page = platform->driver->ops->page;
if (playback)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
@@ -1474,14 +1784,13 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
if (capture)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
- ret = platform->pcm_new(codec->card, codec_dai, pcm);
+ ret = platform->driver->pcm_new(rtd->card->snd_card, codec_dai, pcm);
if (ret < 0) {
printk(KERN_ERR "asoc: platform pcm constructor failed\n");
- kfree(rtd);
return ret;
}
- pcm->private_free = platform->pcm_free;
+ pcm->private_free = platform->driver->pcm_free;
printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
cpu_dai->name);
return ret;
@@ -1497,8 +1806,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
*/
int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg)
{
- if (codec->volatile_register)
- return codec->volatile_register(reg);
+ if (codec->driver->volatile_register)
+ return codec->driver->volatile_register(reg);
else
return 0;
}
@@ -1533,7 +1842,13 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
codec->ac97->bus->ops = ops;
codec->ac97->num = num;
- codec->dev = &codec->ac97->dev;
+
+ /*
+ * Mark the AC97 device to be created by us. This way we ensure that the
+ * device will be registered with the device subsystem later on.
+ */
+ codec->ac97_created = 1;
+
mutex_unlock(&codec->mutex);
return 0;
}
@@ -1548,9 +1863,13 @@ EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
{
mutex_lock(&codec->mutex);
+#ifdef CONFIG_SND_SOC_AC97_BUS
+ soc_unregister_ac97_dai_link(codec);
+#endif
kfree(codec->ac97->bus);
kfree(codec->ac97);
codec->ac97 = NULL;
+ codec->ac97_created = 0;
mutex_unlock(&codec->mutex);
}
EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
@@ -1634,95 +1953,6 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
EXPORT_SYMBOL_GPL(snd_soc_test_bits);
/**
- * snd_soc_new_pcms - create new sound card and pcms
- * @socdev: the SoC audio device
- * @idx: ALSA card index
- * @xid: card identification
- *
- * Create a new sound card based upon the codec and interface pcms.
- *
- * Returns 0 for success, else error.
- */
-int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
-{
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_codec *codec = card->codec;
- int ret, i;
-
- mutex_lock(&codec->mutex);
-
- /* register a sound card */
- ret = snd_card_create(idx, xid, codec->owner, 0, &codec->card);
- if (ret < 0) {
- printk(KERN_ERR "asoc: can't create sound card for codec %s\n",
- codec->name);
- mutex_unlock(&codec->mutex);
- return ret;
- }
-
- codec->socdev = socdev;
- codec->card->dev = socdev->dev;
- codec->card->private_data = codec;
- strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver));
-
- /* create the pcms */
- for (i = 0; i < card->num_links; i++) {
- ret = soc_new_pcm(socdev, &card->dai_link[i], i);
- if (ret < 0) {
- printk(KERN_ERR "asoc: can't create pcm %s\n",
- card->dai_link[i].stream_name);
- mutex_unlock(&codec->mutex);
- return ret;
- }
- /* Check for codec->ac97 to handle the ac97.c fun */
- if (card->dai_link[i].codec_dai->ac97_control && codec->ac97) {
- snd_ac97_dev_add_pdata(codec->ac97,
- card->dai_link[i].cpu_dai->ac97_pdata);
- }
- }
-
- mutex_unlock(&codec->mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_new_pcms);
-
-/**
- * snd_soc_free_pcms - free sound card and pcms
- * @socdev: the SoC audio device
- *
- * Frees sound card and pcms associated with the socdev.
- * Also unregister the codec if it is an AC97 device.
- */
-void snd_soc_free_pcms(struct snd_soc_device *socdev)
-{
- struct snd_soc_codec *codec = socdev->card->codec;
-#ifdef CONFIG_SND_SOC_AC97_BUS
- struct snd_soc_dai *codec_dai;
- int i;
-#endif
-
- mutex_lock(&codec->mutex);
- soc_cleanup_codec_debugfs(codec);
-#ifdef CONFIG_SND_SOC_AC97_BUS
- for (i = 0; i < codec->num_dai; i++) {
- codec_dai = &codec->dai[i];
- if (codec_dai->ac97_control && codec->ac97 &&
- strcmp(codec->name, "AC97") != 0) {
- soc_ac97_dev_unregister(codec);
- goto free_card;
- }
- }
-free_card:
-#endif
-
- if (codec->card)
- snd_card_free(codec->card);
- device_remove_file(socdev->dev, &dev_attr_codec_reg);
- mutex_unlock(&codec->mutex);
-}
-EXPORT_SYMBOL_GPL(snd_soc_free_pcms);
-
-/**
* snd_soc_set_runtime_hwparams - set the runtime hardware parameters
* @substream: the pcm substream
* @hw: the hardware parameters
@@ -1783,15 +2013,15 @@ EXPORT_SYMBOL_GPL(snd_soc_cnew);
int snd_soc_add_controls(struct snd_soc_codec *codec,
const struct snd_kcontrol_new *controls, int num_controls)
{
- struct snd_card *card = codec->card;
+ struct snd_card *card = codec->card->snd_card;
int err, i;
for (i = 0; i < num_controls; i++) {
const struct snd_kcontrol_new *control = &controls[i];
err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL));
if (err < 0) {
- dev_err(codec->dev, "%s: Failed to add %s\n",
- codec->name, control->name);
+ dev_err(codec->dev, "%s: Failed to add %s: %d\n",
+ codec->name, control->name, err);
return err;
}
}
@@ -2338,7 +2568,7 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
int snd_soc_limit_volume(struct snd_soc_codec *codec,
const char *name, int max)
{
- struct snd_card *card = codec->card;
+ struct snd_card *card = codec->card->snd_card;
struct snd_kcontrol *kctl;
struct soc_mixer_control *mc;
int found = 0;
@@ -2470,8 +2700,8 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
- if (dai->ops && dai->ops->set_sysclk)
- return dai->ops->set_sysclk(dai, clk_id, freq, dir);
+ if (dai->driver && dai->driver->ops->set_sysclk)
+ return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
else
return -EINVAL;
}
@@ -2490,8 +2720,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
int div_id, int div)
{
- if (dai->ops && dai->ops->set_clkdiv)
- return dai->ops->set_clkdiv(dai, div_id, div);
+ if (dai->driver && dai->driver->ops->set_clkdiv)
+ return dai->driver->ops->set_clkdiv(dai, div_id, div);
else
return -EINVAL;
}
@@ -2510,8 +2740,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
unsigned int freq_in, unsigned int freq_out)
{
- if (dai->ops && dai->ops->set_pll)
- return dai->ops->set_pll(dai, pll_id, source,
+ if (dai->driver && dai->driver->ops->set_pll)
+ return dai->driver->ops->set_pll(dai, pll_id, source,
freq_in, freq_out);
else
return -EINVAL;
@@ -2527,8 +2757,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
*/
int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
- if (dai->ops && dai->ops->set_fmt)
- return dai->ops->set_fmt(dai, fmt);
+ if (dai->driver && dai->driver->ops->set_fmt)
+ return dai->driver->ops->set_fmt(dai, fmt);
else
return -EINVAL;
}
@@ -2548,8 +2778,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
{
- if (dai->ops && dai->ops->set_tdm_slot)
- return dai->ops->set_tdm_slot(dai, tx_mask, rx_mask,
+ if (dai->driver && dai->driver->ops->set_tdm_slot)
+ return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
slots, slot_width);
else
return -EINVAL;
@@ -2572,8 +2802,8 @@ int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
unsigned int tx_num, unsigned int *tx_slot,
unsigned int rx_num, unsigned int *rx_slot)
{
- if (dai->ops && dai->ops->set_channel_map)
- return dai->ops->set_channel_map(dai, tx_num, tx_slot,
+ if (dai->driver && dai->driver->ops->set_channel_map)
+ return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
rx_num, rx_slot);
else
return -EINVAL;
@@ -2589,8 +2819,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
*/
int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
{
- if (dai->ops && dai->ops->set_tristate)
- return dai->ops->set_tristate(dai, tristate);
+ if (dai->driver && dai->driver->ops->set_tristate)
+ return dai->driver->ops->set_tristate(dai, tristate);
else
return -EINVAL;
}
@@ -2605,8 +2835,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
*/
int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute)
{
- if (dai->ops && dai->ops->digital_mute)
- return dai->ops->digital_mute(dai, mute);
+ if (dai->driver && dai->driver->ops->digital_mute)
+ return dai->driver->ops->digital_mute(dai, mute);
else
return -EINVAL;
}
@@ -2623,11 +2853,22 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
*/
static int snd_soc_register_card(struct snd_soc_card *card)
{
+ int i;
+
if (!card->name || !card->dev)
return -EINVAL;
+ card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * card->num_links,
+ GFP_KERNEL);
+ if (card->rtd == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < card->num_links; i++)
+ card->rtd[i].dai_link = &card->dai_link[i];
+
INIT_LIST_HEAD(&card->list);
card->instantiated = 0;
+ mutex_init(&card->mutex);
mutex_lock(&client_mutex);
list_add(&card->list, &card_list);
@@ -2653,30 +2894,97 @@ static int snd_soc_unregister_card(struct snd_soc_card *card)
mutex_lock(&client_mutex);
list_del(&card->list);
mutex_unlock(&client_mutex);
-
dev_dbg(card->dev, "Unregistered card '%s'\n", card->name);
return 0;
}
+/*
+ * Simplify DAI link configuration by removing ".-1" from device names
+ * and sanitizing names.
+ */
+static inline char *fmt_single_name(struct device *dev, int *id)
+{
+ char *found, name[NAME_SIZE];
+ int id1, id2;
+
+ if (dev_name(dev) == NULL)
+ return NULL;
+
+ strncpy(name, dev_name(dev), NAME_SIZE);
+
+ /* are we a "%s.%d" name (platform and SPI components) */
+ found = strstr(name, dev->driver->name);
+ if (found) {
+ /* get ID */
+ if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) {
+
+ /* discard ID from name if ID == -1 */
+ if (*id == -1)
+ found[strlen(dev->driver->name)] = '\0';
+ }
+
+ } else {
+ /* I2C component devices are named "bus-addr" */
+ if (sscanf(name, "%x-%x", &id1, &id2) == 2) {
+ char tmp[NAME_SIZE];
+
+ /* create unique ID number from I2C addr and bus */
+ *id = ((id1 & 0xffff) << 16) + id2;
+
+ /* sanitize component name for DAI link creation */
+ snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name);
+ strncpy(name, tmp, NAME_SIZE);
+ } else
+ *id = 0;
+ }
+
+ return kstrdup(name, GFP_KERNEL);
+}
+
+/*
+ * Simplify DAI link naming for single devices with multiple DAIs by removing
+ * any ".-1" and using the DAI name (instead of device name).
+ */
+static inline char *fmt_multiple_name(struct device *dev,
+ struct snd_soc_dai_driver *dai_drv)
+{
+ if (dai_drv->name == NULL) {
+ printk(KERN_ERR "asoc: error - multiple DAI %s registered with no name\n",
+ dev_name(dev));
+ return NULL;
+ }
+
+ return kstrdup(dai_drv->name, GFP_KERNEL);
+}
+
/**
* snd_soc_register_dai - Register a DAI with the ASoC core
*
* @dai: DAI to register
*/
-int snd_soc_register_dai(struct snd_soc_dai *dai)
+int snd_soc_register_dai(struct device *dev,
+ struct snd_soc_dai_driver *dai_drv)
{
- if (!dai->name)
- return -EINVAL;
+ struct snd_soc_dai *dai;
+
+ dev_dbg(dev, "dai register %s\n", dev_name(dev));
- /* The device should become mandatory over time */
- if (!dai->dev)
- printk(KERN_WARNING "No device for DAI %s\n", dai->name);
+ dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
+ if (dai == NULL)
+ return -ENOMEM;
- if (!dai->ops)
- dai->ops = &null_dai_ops;
+ /* create DAI component name */
+ dai->name = fmt_single_name(dev, &dai->id);
+ if (dai->name == NULL) {
+ kfree(dai);
+ return -ENOMEM;
+ }
- INIT_LIST_HEAD(&dai->list);
+ dai->dev = dev;
+ dai->driver = dai_drv;
+ if (!dai->driver->ops)
+ dai->driver->ops = &null_dai_ops;
mutex_lock(&client_mutex);
list_add(&dai->list, &dai_list);
@@ -2694,13 +3002,24 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dai);
*
* @dai: DAI to unregister
*/
-void snd_soc_unregister_dai(struct snd_soc_dai *dai)
+void snd_soc_unregister_dai(struct device *dev)
{
+ struct snd_soc_dai *dai;
+
+ list_for_each_entry(dai, &dai_list, list) {
+ if (dev == dai->dev)
+ goto found;
+ }
+ return;
+
+found:
mutex_lock(&client_mutex);
list_del(&dai->list);
mutex_unlock(&client_mutex);
pr_debug("Unregistered DAI '%s'\n", dai->name);
+ kfree(dai->name);
+ kfree(dai);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
@@ -2710,21 +3029,50 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
* @dai: Array of DAIs to register
* @count: Number of DAIs
*/
-int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count)
+int snd_soc_register_dais(struct device *dev,
+ struct snd_soc_dai_driver *dai_drv, size_t count)
{
- int i, ret;
+ struct snd_soc_dai *dai;
+ int i, ret = 0;
+
+ dev_dbg(dev, "dai register %s #%Zu\n", dev_name(dev), count);
for (i = 0; i < count; i++) {
- ret = snd_soc_register_dai(&dai[i]);
- if (ret != 0)
+
+ dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
+ if (dai == NULL)
+ return -ENOMEM;
+
+ /* create DAI component name */
+ dai->name = fmt_multiple_name(dev, &dai_drv[i]);
+ if (dai->name == NULL) {
+ kfree(dai);
+ ret = -EINVAL;
goto err;
+ }
+
+ dai->dev = dev;
+ dai->driver = &dai_drv[i];
+ if (dai->driver->id)
+ dai->id = dai->driver->id;
+ else
+ dai->id = i;
+ if (!dai->driver->ops)
+ dai->driver->ops = &null_dai_ops;
+
+ mutex_lock(&client_mutex);
+ list_add(&dai->list, &dai_list);
+ mutex_unlock(&client_mutex);
+
+ pr_debug("Registered DAI '%s'\n", dai->name);
}
+ snd_soc_instantiate_cards();
return 0;
err:
for (i--; i >= 0; i--)
- snd_soc_unregister_dai(&dai[i]);
+ snd_soc_unregister_dai(dev);
return ret;
}
@@ -2736,12 +3084,12 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dais);
* @dai: Array of DAIs to unregister
* @count: Number of DAIs
*/
-void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count)
+void snd_soc_unregister_dais(struct device *dev, size_t count)
{
int i;
for (i = 0; i < count; i++)
- snd_soc_unregister_dai(&dai[i]);
+ snd_soc_unregister_dai(dev);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
@@ -2750,12 +3098,26 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
*
* @platform: platform to register
*/
-int snd_soc_register_platform(struct snd_soc_platform *platform)
+int snd_soc_register_platform(struct device *dev,
+ struct snd_soc_platform_driver *platform_drv)
{
- if (!platform->name)
- return -EINVAL;
+ struct snd_soc_platform *platform;
+
+ dev_dbg(dev, "platform register %s\n", dev_name(dev));
- INIT_LIST_HEAD(&platform->list);
+ platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
+ if (platform == NULL)
+ return -ENOMEM;
+
+ /* create platform component name */
+ platform->name = fmt_single_name(dev, &platform->id);
+ if (platform->name == NULL) {
+ kfree(platform);
+ return -ENOMEM;
+ }
+
+ platform->dev = dev;
+ platform->driver = platform_drv;
mutex_lock(&client_mutex);
list_add(&platform->list, &platform_list);
@@ -2773,13 +3135,24 @@ EXPORT_SYMBOL_GPL(snd_soc_register_platform);
*
* @platform: platform to unregister
*/
-void snd_soc_unregister_platform(struct snd_soc_platform *platform)
+void snd_soc_unregister_platform(struct device *dev)
{
+ struct snd_soc_platform *platform;
+
+ list_for_each_entry(platform, &platform_list, list) {
+ if (dev == platform->dev)
+ goto found;
+ }
+ return;
+
+found:
mutex_lock(&client_mutex);
list_del(&platform->list);
mutex_unlock(&client_mutex);
pr_debug("Unregistered platform '%s'\n", platform->name);
+ kfree(platform->name);
+ kfree(platform);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
@@ -2821,22 +3194,61 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream)
*
* @codec: codec to register
*/
-int snd_soc_register_codec(struct snd_soc_codec *codec)
+int snd_soc_register_codec(struct device *dev,
+ struct snd_soc_codec_driver *codec_drv,
+ struct snd_soc_dai_driver *dai_drv, int num_dai)
{
- int i;
+ struct snd_soc_codec *codec;
+ int ret, i;
- if (!codec->name)
- return -EINVAL;
+ dev_dbg(dev, "codec register %s\n", dev_name(dev));
+
+ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (codec == NULL)
+ return -ENOMEM;
+
+ /* create CODEC component name */
+ codec->name = fmt_single_name(dev, &codec->id);
+ if (codec->name == NULL) {
+ kfree(codec);
+ return -ENOMEM;
+ }
- /* The device should become mandatory over time */
- if (!codec->dev)
- printk(KERN_WARNING "No device for codec %s\n", codec->name);
+ /* allocate CODEC register cache */
+ if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
- INIT_LIST_HEAD(&codec->list);
+ if (codec_drv->reg_cache_default)
+ codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
+ codec_drv->reg_cache_size * codec_drv->reg_word_size, GFP_KERNEL);
+ else
+ codec->reg_cache = kzalloc(codec_drv->reg_cache_size *
+ codec_drv->reg_word_size, GFP_KERNEL);
- for (i = 0; i < codec->num_dai; i++) {
- fixup_codec_formats(&codec->dai[i].playback);
- fixup_codec_formats(&codec->dai[i].capture);
+ if (codec->reg_cache == NULL) {
+ kfree(codec->name);
+ kfree(codec);
+ return -ENOMEM;
+ }
+ }
+
+ codec->dev = dev;
+ codec->driver = codec_drv;
+ codec->bias_level = SND_SOC_BIAS_OFF;
+ codec->num_dai = num_dai;
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ for (i = 0; i < num_dai; i++) {
+ fixup_codec_formats(&dai_drv[i].playback);
+ fixup_codec_formats(&dai_drv[i].capture);
+ }
+
+ /* register any DAIs */
+ if (num_dai) {
+ ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+ if (ret < 0)
+ goto error;
}
mutex_lock(&client_mutex);
@@ -2845,8 +3257,17 @@ int snd_soc_register_codec(struct snd_soc_codec *codec)
mutex_unlock(&client_mutex);
pr_debug("Registered codec '%s'\n", codec->name);
-
return 0;
+
+error:
+ for (i--; i >= 0; i--)
+ snd_soc_unregister_dai(dev);
+
+ if (codec->reg_cache)
+ kfree(codec->reg_cache);
+ kfree(codec->name);
+ kfree(codec);
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_register_codec);
@@ -2855,13 +3276,32 @@ EXPORT_SYMBOL_GPL(snd_soc_register_codec);
*
* @codec: codec to unregister
*/
-void snd_soc_unregister_codec(struct snd_soc_codec *codec)
+void snd_soc_unregister_codec(struct device *dev)
{
+ struct snd_soc_codec *codec;
+ int i;
+
+ list_for_each_entry(codec, &codec_list, list) {
+ if (dev == codec->dev)
+ goto found;
+ }
+ return;
+
+found:
+ if (codec->num_dai)
+ for (i = 0; i < codec->num_dai; i++)
+ snd_soc_unregister_dai(dev);
+
mutex_lock(&client_mutex);
list_del(&codec->list);
mutex_unlock(&client_mutex);
pr_debug("Unregistered codec '%s'\n", codec->name);
+
+ if (codec->reg_cache)
+ kfree(codec->reg_cache);
+ kfree(codec->name);
+ kfree(codec);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
@@ -2874,10 +3314,23 @@ static int __init snd_soc_init(void)
"ASoC: Failed to create debugfs directory\n");
debugfs_root = NULL;
}
+
+ if (!debugfs_create_file("codecs", 0444, debugfs_root, NULL,
+ &codec_list_fops))
+ pr_warn("ASoC: Failed to create CODEC list debugfs file\n");
+
+ if (!debugfs_create_file("dais", 0444, debugfs_root, NULL,
+ &dai_list_fops))
+ pr_warn("ASoC: Failed to create DAI list debugfs file\n");
+
+ if (!debugfs_create_file("platforms", 0444, debugfs_root, NULL,
+ &platform_list_fops))
+ pr_warn("ASoC: Failed to create platform list debugfs file\n");
#endif
return platform_driver_register(&soc_driver);
}
+module_init(snd_soc_init);
static void __exit snd_soc_exit(void)
{
@@ -2886,8 +3339,6 @@ static void __exit snd_soc_exit(void)
#endif
platform_driver_unregister(&soc_driver);
}
-
-module_init(snd_soc_init);
module_exit(snd_soc_exit);
/* Module information */
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 72a53d0a41e9..7d85c6496afa 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -112,43 +112,41 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
/**
* snd_soc_dapm_set_bias_level - set the bias level for the system
- * @socdev: audio device
+ * @card: audio device
* @level: level to configure
*
* Configure the bias (power) levels for the SoC audio device.
*
* Returns 0 for success else error.
*/
-static int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
- enum snd_soc_bias_level level)
+static int snd_soc_dapm_set_bias_level(struct snd_soc_card *card,
+ struct snd_soc_codec *codec, enum snd_soc_bias_level level)
{
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_codec *codec = socdev->card->codec;
int ret = 0;
switch (level) {
case SND_SOC_BIAS_ON:
- dev_dbg(socdev->dev, "Setting full bias\n");
+ dev_dbg(codec->dev, "Setting full bias\n");
break;
case SND_SOC_BIAS_PREPARE:
- dev_dbg(socdev->dev, "Setting bias prepare\n");
+ dev_dbg(codec->dev, "Setting bias prepare\n");
break;
case SND_SOC_BIAS_STANDBY:
- dev_dbg(socdev->dev, "Setting standby bias\n");
+ dev_dbg(codec->dev, "Setting standby bias\n");
break;
case SND_SOC_BIAS_OFF:
- dev_dbg(socdev->dev, "Setting bias off\n");
+ dev_dbg(codec->dev, "Setting bias off\n");
break;
default:
- dev_err(socdev->dev, "Setting invalid bias %d\n", level);
+ dev_err(codec->dev, "Setting invalid bias %d\n", level);
return -EINVAL;
}
- if (card->set_bias_level)
+ if (card && card->set_bias_level)
ret = card->set_bias_level(card, level);
if (ret == 0) {
- if (codec->set_bias_level)
- ret = codec->set_bias_level(codec, level);
+ if (codec->driver->set_bias_level)
+ ret = codec->driver->set_bias_level(codec, level);
else
codec->bias_level = level;
}
@@ -370,7 +368,7 @@ static int dapm_new_mixer(struct snd_soc_codec *codec,
path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
path->long_name);
- ret = snd_ctl_add(codec->card, path->kcontrol);
+ ret = snd_ctl_add(codec->card->snd_card, path->kcontrol);
if (ret < 0) {
printk(KERN_ERR "asoc: failed to add dapm kcontrol %s: %d\n",
path->long_name,
@@ -398,7 +396,7 @@ static int dapm_new_mux(struct snd_soc_codec *codec,
}
kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
- ret = snd_ctl_add(codec->card, kcontrol);
+ ret = snd_ctl_add(codec->card->snd_card, kcontrol);
if (ret < 0)
goto err;
@@ -437,9 +435,9 @@ static inline void dapm_clear_walk(struct snd_soc_codec *codec)
*/
static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
{
- struct snd_soc_codec *codec = widget->codec;
+ int level = snd_power_get_state(widget->codec->card->snd_card);
- switch (snd_power_get_state(codec->card)) {
+ switch (level) {
case SNDRV_CTL_POWER_D3hot:
case SNDRV_CTL_POWER_D3cold:
if (widget->ignore_suspend)
@@ -893,7 +891,7 @@ static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list,
*/
static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
{
- struct snd_soc_device *socdev = codec->socdev;
+ struct snd_soc_card *card = codec->card;
struct snd_soc_dapm_widget *w;
LIST_HEAD(up_list);
LIST_HEAD(down_list);
@@ -966,7 +964,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
}
if (sys_power && codec->bias_level == SND_SOC_BIAS_OFF) {
- ret = snd_soc_dapm_set_bias_level(socdev,
+ ret = snd_soc_dapm_set_bias_level(card, codec,
SND_SOC_BIAS_STANDBY);
if (ret != 0)
pr_err("Failed to turn on bias: %d\n", ret);
@@ -975,8 +973,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
/* If we're changing to all on or all off then prepare */
if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) ||
(!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) {
- ret = snd_soc_dapm_set_bias_level(socdev,
- SND_SOC_BIAS_PREPARE);
+ ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_PREPARE);
if (ret != 0)
pr_err("Failed to prepare bias: %d\n", ret);
}
@@ -989,8 +986,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
/* If we just powered the last thing off drop to standby bias */
if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) {
- ret = snd_soc_dapm_set_bias_level(socdev,
- SND_SOC_BIAS_STANDBY);
+ ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_STANDBY);
if (ret != 0)
pr_err("Failed to apply standby bias: %d\n", ret);
}
@@ -998,15 +994,14 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
/* If we're in standby and can support bias off then do that */
if (codec->bias_level == SND_SOC_BIAS_STANDBY &&
codec->idle_bias_off) {
- ret = snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF);
+ ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_OFF);
if (ret != 0)
pr_err("Failed to turn off bias: %d\n", ret);
}
/* If we just powered up then move to active bias */
if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) {
- ret = snd_soc_dapm_set_bias_level(socdev,
- SND_SOC_BIAS_ON);
+ ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_ON);
if (ret != 0)
pr_err("Failed to apply active bias: %d\n", ret);
}
@@ -1189,8 +1184,9 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
static ssize_t dapm_widget_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct snd_soc_device *devdata = dev_get_drvdata(dev);
- struct snd_soc_codec *codec = devdata->card->codec;
+ struct snd_soc_pcm_runtime *rtd =
+ container_of(dev, struct snd_soc_pcm_runtime, dev);
+ struct snd_soc_codec *codec =rtd->codec;
struct snd_soc_dapm_widget *w;
int count = 0;
char *state = "not set";
@@ -1999,9 +1995,10 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
*
* Returns 0 for success else error.
*/
-int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
- char *stream, int event)
+int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
+ const char *stream, int event)
{
+ struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_widget *w;
if (stream == NULL)
@@ -2169,25 +2166,19 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
/**
* snd_soc_dapm_free - free dapm resources
- * @socdev: SoC device
+ * @card: SoC device
*
* Free all dapm widgets and resources.
*/
-void snd_soc_dapm_free(struct snd_soc_device *socdev)
+void snd_soc_dapm_free(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
-
- snd_soc_dapm_sys_remove(socdev->dev);
+ snd_soc_dapm_sys_remove(codec->dev);
dapm_free_widgets(codec);
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
-/*
- * snd_soc_dapm_shutdown - callback for system shutdown
- */
-void snd_soc_dapm_shutdown(struct snd_soc_device *socdev)
+static void soc_dapm_shutdown_codec(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
struct snd_soc_dapm_widget *w;
LIST_HEAD(down_list);
int powerdown = 0;
@@ -2204,12 +2195,23 @@ void snd_soc_dapm_shutdown(struct snd_soc_device *socdev)
* standby.
*/
if (powerdown) {
- snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE);
+ snd_soc_dapm_set_bias_level(NULL, codec, SND_SOC_BIAS_PREPARE);
dapm_seq_run(codec, &down_list, 0, dapm_down_seq);
- snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_set_bias_level(NULL, codec, SND_SOC_BIAS_STANDBY);
}
+}
+
+/*
+ * snd_soc_dapm_shutdown - callback for system shutdown
+ */
+void snd_soc_dapm_shutdown(struct snd_soc_card *card)
+{
+ struct snd_soc_codec *codec;
+
+ list_for_each_entry(codec, &card->codec_dev_list, list)
+ soc_dapm_shutdown_codec(codec);
- snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_OFF);
}
/* Module information */
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 29159e1781d0..8a0a9205b1e7 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -32,14 +32,14 @@
* Returns zero if successful, or a negative error code on failure.
* On success jack will be initialised.
*/
-int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
+int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
struct snd_soc_jack *jack)
{
- jack->card = card;
+ jack->codec = codec;
INIT_LIST_HEAD(&jack->pins);
BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier);
- return snd_jack_new(card->codec->card, id, type, &jack->jack);
+ return snd_jack_new(codec->card->snd_card, id, type, &jack->jack);
}
EXPORT_SYMBOL_GPL(snd_soc_jack_new);
@@ -67,7 +67,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
if (!jack)
return;
- codec = jack->card->codec;
+ codec = jack->codec;
mutex_lock(&codec->mutex);
@@ -188,9 +188,6 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
int enable;
int report;
- if (gpio->debounce_time > 0)
- mdelay(gpio->debounce_time);
-
enable = gpio_get_value(gpio->gpio);
if (gpio->invert)
enable = !enable;
@@ -211,7 +208,8 @@ static irqreturn_t gpio_handler(int irq, void *data)
{
struct snd_soc_jack_gpio *gpio = data;
- schedule_work(&gpio->work);
+ schedule_delayed_work(&gpio->work,
+ msecs_to_jiffies(gpio->debounce_time));
return IRQ_HANDLED;
}
@@ -221,7 +219,7 @@ static void gpio_work(struct work_struct *work)
{
struct snd_soc_jack_gpio *gpio;
- gpio = container_of(work, struct snd_soc_jack_gpio, work);
+ gpio = container_of(work, struct snd_soc_jack_gpio, work.work);
snd_soc_jack_gpio_detect(gpio);
}
@@ -262,13 +260,13 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
if (ret)
goto err;
- INIT_WORK(&gpios[i].work, gpio_work);
+ INIT_DELAYED_WORK(&gpios[i].work, gpio_work);
gpios[i].jack = jack;
ret = request_irq(gpio_to_irq(gpios[i].gpio),
gpio_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- jack->card->dev->driver->name,
+ jack->codec->dev->driver->name,
&gpios[i]);
if (ret)
goto err;
@@ -312,6 +310,7 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
gpio_unexport(gpios[i].gpio);
#endif
free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]);
+ cancel_delayed_work_sync(&gpios[i].work);
gpio_free(gpios[i].gpio);
gpios[i].jack = NULL;
}
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c
index 0ec20b68e8cb..743d07b82c06 100644
--- a/sound/soc/txx9/txx9aclc-ac97.c
+++ b/sound/soc/txx9/txx9aclc-ac97.c
@@ -36,13 +36,11 @@
static DECLARE_WAIT_QUEUE_HEAD(ac97_waitq);
-/* REVISIT: How to find txx9aclc_soc_device from snd_ac97? */
-static struct txx9aclc_soc_device *txx9aclc_soc_dev;
+/* REVISIT: How to find txx9aclc_drvdata from snd_ac97? */
+static struct txx9aclc_plat_drvdata *txx9aclc_drvdata;
-static int txx9aclc_regready(struct txx9aclc_soc_device *dev)
+static int txx9aclc_regready(struct txx9aclc_plat_drvdata *drvdata)
{
- struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
-
return __raw_readl(drvdata->base + ACINTSTS) & ACINT_REGACCRDY;
}
@@ -50,8 +48,7 @@ static int txx9aclc_regready(struct txx9aclc_soc_device *dev)
static unsigned short txx9aclc_ac97_read(struct snd_ac97 *ac97,
unsigned short reg)
{
- struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
- struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+ struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
void __iomem *base = drvdata->base;
u32 dat;
@@ -61,15 +58,15 @@ static unsigned short txx9aclc_ac97_read(struct snd_ac97 *ac97,
dat = (reg << ACREGACC_REG_SHIFT) | ACREGACC_READ;
__raw_writel(dat, base + ACREGACC);
__raw_writel(ACINT_REGACCRDY, base + ACINTEN);
- if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) {
+ if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(txx9aclc_drvdata), HZ)) {
__raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
- dev_err(dev->soc_dev.dev, "ac97 read timeout (reg %#x)\n", reg);
+ printk(KERN_ERR "ac97 read timeout (reg %#x)\n", reg);
dat = 0xffff;
goto done;
}
dat = __raw_readl(base + ACREGACC);
if (((dat >> ACREGACC_REG_SHIFT) & 0xff) != reg) {
- dev_err(dev->soc_dev.dev, "reg mismatch %x with %x\n",
+ printk(KERN_ERR "reg mismatch %x with %x\n",
dat, reg);
dat = 0xffff;
goto done;
@@ -84,16 +81,15 @@ done:
static void txx9aclc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
unsigned short val)
{
- struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
- struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+ struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
void __iomem *base = drvdata->base;
__raw_writel(((reg | (ac97->num << 7)) << ACREGACC_REG_SHIFT) |
(val << ACREGACC_DAT_SHIFT),
base + ACREGACC);
__raw_writel(ACINT_REGACCRDY, base + ACINTEN);
- if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) {
- dev_err(dev->soc_dev.dev,
+ if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(txx9aclc_drvdata), HZ)) {
+ printk(KERN_ERR
"ac97 write timeout (reg %#x)\n", reg);
}
__raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
@@ -101,8 +97,7 @@ static void txx9aclc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
static void txx9aclc_ac97_cold_reset(struct snd_ac97 *ac97)
{
- struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
- struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+ struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
void __iomem *base = drvdata->base;
u32 ready = ACINT_CODECRDY(ac97->num) | ACINT_REGACCRDY;
@@ -141,31 +136,23 @@ static irqreturn_t txx9aclc_ac97_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int txx9aclc_ac97_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int txx9aclc_ac97_probe(struct snd_soc_dai *dai)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct txx9aclc_soc_device *dev =
- container_of(socdev, struct txx9aclc_soc_device, soc_dev);
-
- dev->aclc_pdev = to_platform_device(dai->dev);
- txx9aclc_soc_dev = dev;
+ txx9aclc_drvdata = snd_soc_dai_get_drvdata(dai);
return 0;
}
-static void txx9aclc_ac97_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int txx9aclc_ac97_remove(struct snd_soc_dai *dai)
{
- struct platform_device *aclc_pdev = to_platform_device(dai->dev);
- struct txx9aclc_plat_drvdata *drvdata = platform_get_drvdata(aclc_pdev);
+ struct txx9aclc_plat_drvdata *drvdata = snd_soc_dai_get_drvdata(dai);
/* disable AC-link */
__raw_writel(ACCTL_ENLINK, drvdata->base + ACCTLDIS);
- txx9aclc_soc_dev = NULL;
+ txx9aclc_drvdata = NULL;
+ return 0;
}
-struct snd_soc_dai txx9aclc_ac97_dai = {
- .name = "txx9aclc_ac97",
+static struct snd_soc_dai_driver txx9aclc_ac97_dai = {
.ac97_control = 1,
.probe = txx9aclc_ac97_probe,
.remove = txx9aclc_ac97_remove,
@@ -182,7 +169,6 @@ struct snd_soc_dai txx9aclc_ac97_dai = {
.channels_max = 2,
},
};
-EXPORT_SYMBOL_GPL(txx9aclc_ac97_dai);
static int __devinit txx9aclc_ac97_dev_probe(struct platform_device *pdev)
{
@@ -219,13 +205,12 @@ static int __devinit txx9aclc_ac97_dev_probe(struct platform_device *pdev)
if (err < 0)
return err;
- txx9aclc_ac97_dai.dev = &pdev->dev;
- return snd_soc_register_dai(&txx9aclc_ac97_dai);
+ return snd_soc_register_dai(&pdev->dev, &txx9aclc_ac97_dai);
}
static int __devexit txx9aclc_ac97_dev_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&txx9aclc_ac97_dai);
+ snd_soc_unregister_dai(&pdev->dev);
return 0;
}
diff --git a/sound/soc/txx9/txx9aclc-generic.c b/sound/soc/txx9/txx9aclc-generic.c
index 95b17f731aec..6770e7166be4 100644
--- a/sound/soc/txx9/txx9aclc-generic.c
+++ b/sound/soc/txx9/txx9aclc-generic.c
@@ -19,54 +19,44 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
-#include "../codecs/ac97.h"
#include "txx9aclc.h"
static struct snd_soc_dai_link txx9aclc_generic_dai = {
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &txx9aclc_ac97_dai,
- .codec_dai = &ac97_dai,
+ .cpu_dai_name = "txx9aclc-ac97",
+ .codec_dai_name = "ac97-hifi",
+ .platform_name = "txx9aclc-pcm-audio",
+ .codec_name = "ac97-codec",
};
static struct snd_soc_card txx9aclc_generic_card = {
.name = "Generic TXx9 ACLC Audio",
- .platform = &txx9aclc_soc_platform,
.dai_link = &txx9aclc_generic_dai,
.num_links = 1,
};
-static struct txx9aclc_soc_device txx9aclc_generic_soc_device = {
- .soc_dev = {
- .card = &txx9aclc_generic_card,
- .codec_dev = &soc_codec_dev_ac97,
- },
-};
+static struct platform_device *soc_pdev;
static int __init txx9aclc_generic_probe(struct platform_device *pdev)
{
- struct txx9aclc_soc_device *dev = &txx9aclc_generic_soc_device;
- struct platform_device *soc_pdev;
int ret;
soc_pdev = platform_device_alloc("soc-audio", -1);
if (!soc_pdev)
return -ENOMEM;
- platform_set_drvdata(soc_pdev, &dev->soc_dev);
- dev->soc_dev.dev = &soc_pdev->dev;
+ platform_set_drvdata(soc_pdev, &txx9aclc_generic_card);
ret = platform_device_add(soc_pdev);
if (ret) {
platform_device_put(soc_pdev);
return ret;
}
- platform_set_drvdata(pdev, soc_pdev);
+
return 0;
}
static int __exit txx9aclc_generic_remove(struct platform_device *pdev)
{
- struct platform_device *soc_pdev = platform_get_drvdata(pdev);
-
platform_device_unregister(soc_pdev);
return 0;
}
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
index 0e3452303ea6..f4aa4e03c888 100644
--- a/sound/soc/txx9/txx9aclc.c
+++ b/sound/soc/txx9/txx9aclc.c
@@ -22,6 +22,16 @@
#include <sound/soc.h>
#include "txx9aclc.h"
+static struct txx9aclc_soc_device {
+ struct txx9aclc_dmadata dmadata[2];
+} txx9aclc_soc_device;
+
+/* REVISIT: How to find txx9aclc_drvdata from snd_ac97? */
+static struct txx9aclc_plat_drvdata *txx9aclc_drvdata;
+
+static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
+ struct txx9aclc_dmadata *dmadata);
+
static const struct snd_pcm_hardware txx9aclc_pcm_hardware = {
/*
* REVISIT: SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID
@@ -46,7 +56,6 @@ static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- struct snd_soc_device *socdev = rtd->socdev;
struct snd_pcm_runtime *runtime = substream->runtime;
struct txx9aclc_dmadata *dmadata = runtime->private_data;
int ret;
@@ -55,13 +64,13 @@ static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- dev_dbg(socdev->dev,
+ dev_dbg(rtd->platform->dev,
"runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd "
"runtime->min_align %ld\n",
(unsigned long)runtime->dma_area,
(unsigned long)runtime->dma_addr, runtime->dma_bytes,
runtime->min_align);
- dev_dbg(socdev->dev,
+ dev_dbg(rtd->platform->dev,
"periods %d period_bytes %d stream %d\n",
params_periods(params), params_period_bytes(params),
substream->stream);
@@ -152,11 +161,7 @@ static void txx9aclc_dma_tasklet(unsigned long data)
spin_lock_irqsave(&dmadata->dma_lock, flags);
if (dmadata->frag_count < 0) {
- struct txx9aclc_soc_device *dev =
- container_of(dmadata, struct txx9aclc_soc_device,
- dmadata[substream->stream]);
- struct txx9aclc_plat_drvdata *drvdata =
- txx9aclc_get_plat_drvdata(dev);
+ struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
void __iomem *base = drvdata->base;
spin_unlock_irqrestore(&dmadata->dma_lock, flags);
@@ -202,10 +207,7 @@ static void txx9aclc_dma_tasklet(unsigned long data)
static int txx9aclc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct txx9aclc_soc_device *dev =
- container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev);
- struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+ struct txx9aclc_plat_drvdata *drvdata =txx9aclc_drvdata;
void __iomem *base = drvdata->base;
unsigned long flags;
int ret = 0;
@@ -244,9 +246,7 @@ txx9aclc_pcm_pointer(struct snd_pcm_substream *substream)
static int txx9aclc_pcm_open(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct txx9aclc_soc_device *dev =
- container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev);
+ struct txx9aclc_soc_device *dev = &txx9aclc_soc_device;
struct txx9aclc_dmadata *dmadata = &dev->dmadata[substream->stream];
int ret;
@@ -291,8 +291,38 @@ static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm)
static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
struct snd_pcm *pcm)
{
+ struct platform_device *pdev = to_platform_device(dai->platform->dev);
+ struct txx9aclc_soc_device *dev;
+ struct resource *r;
+ int i;
+ int ret;
+
+ /* at this point onwards the AC97 component has probed and this will be valid */
+ dev = snd_soc_dai_get_drvdata(dai);
+
+ dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK;
+ dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE;
+ for (i = 0; i < 2; i++) {
+ r = platform_get_resource(pdev, IORESOURCE_DMA, i);
+ if (!r) {
+ ret = -EBUSY;
+ goto exit;
+ }
+ dev->dmadata[i].dma_res = r;
+ ret = txx9aclc_dma_init(dev, &dev->dmadata[i]);
+ if (ret)
+ goto exit;
+ }
return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
card->dev, 64 * 1024, 4 * 1024 * 1024);
+
+exit:
+ for (i = 0; i < 2; i++) {
+ if (dev->dmadata[i].dma_chan)
+ dma_release_channel(dev->dmadata[i].dma_chan);
+ dev->dmadata[i].dma_chan = NULL;
+ }
+ return ret;
}
static bool filter(struct dma_chan *chan, void *param)
@@ -314,7 +344,7 @@ static bool filter(struct dma_chan *chan, void *param)
static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
struct txx9aclc_dmadata *dmadata)
{
- struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+ struct txx9aclc_plat_drvdata *drvdata =txx9aclc_drvdata;
struct txx9dmac_slave *ds = &dmadata->dma_slave;
dma_cap_mask_t mask;
@@ -334,7 +364,7 @@ static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
dma_cap_set(DMA_SLAVE, mask);
dmadata->dma_chan = dma_request_channel(mask, filter, dmadata);
if (!dmadata->dma_chan) {
- dev_err(dev->soc_dev.dev,
+ printk(KERN_ERR
"DMA channel for %s is not available\n",
dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK ?
"playback" : "capture");
@@ -345,45 +375,16 @@ static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
return 0;
}
-static int txx9aclc_pcm_probe(struct platform_device *pdev)
+static int txx9aclc_pcm_probe(struct snd_soc_platform *platform)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct txx9aclc_soc_device *dev =
- container_of(socdev, struct txx9aclc_soc_device, soc_dev);
- struct resource *r;
- int i;
- int ret;
-
- dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK;
- dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE;
- for (i = 0; i < 2; i++) {
- r = platform_get_resource(dev->aclc_pdev, IORESOURCE_DMA, i);
- if (!r) {
- ret = -EBUSY;
- goto exit;
- }
- dev->dmadata[i].dma_res = r;
- ret = txx9aclc_dma_init(dev, &dev->dmadata[i]);
- if (ret)
- goto exit;
- }
+ snd_soc_platform_set_drvdata(platform, &txx9aclc_soc_device);
return 0;
-
-exit:
- for (i = 0; i < 2; i++) {
- if (dev->dmadata[i].dma_chan)
- dma_release_channel(dev->dmadata[i].dma_chan);
- dev->dmadata[i].dma_chan = NULL;
- }
- return ret;
}
-static int txx9aclc_pcm_remove(struct platform_device *pdev)
+static int txx9aclc_pcm_remove(struct snd_soc_platform *platform)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct txx9aclc_soc_device *dev =
- container_of(socdev, struct txx9aclc_soc_device, soc_dev);
- struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+ struct txx9aclc_soc_device *dev = snd_soc_platform_get_drvdata(platform);
+ struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
void __iomem *base = drvdata->base;
int i;
@@ -406,28 +407,46 @@ static int txx9aclc_pcm_remove(struct platform_device *pdev)
return 0;
}
-struct snd_soc_platform txx9aclc_soc_platform = {
- .name = "txx9aclc-audio",
+static struct snd_soc_platform_driver txx9aclc_soc_platform = {
.probe = txx9aclc_pcm_probe,
.remove = txx9aclc_pcm_remove,
- .pcm_ops = &txx9aclc_pcm_ops,
+ .ops = &txx9aclc_pcm_ops,
.pcm_new = txx9aclc_pcm_new,
.pcm_free = txx9aclc_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(txx9aclc_soc_platform);
-static int __init txx9aclc_soc_platform_init(void)
+static int __devinit txx9aclc_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&txx9aclc_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &txx9aclc_soc_platform);
}
-static void __exit txx9aclc_soc_platform_exit(void)
+static int __devexit txx9aclc_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&txx9aclc_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
}
-module_init(txx9aclc_soc_platform_init);
-module_exit(txx9aclc_soc_platform_exit);
+static struct platform_driver txx9aclc_pcm_driver = {
+ .driver = {
+ .name = "txx9aclc-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = txx9aclc_soc_platform_probe,
+ .remove = __devexit_p(txx9aclc_soc_platform_remove),
+};
+
+static int __init snd_txx9aclc_pcm_init(void)
+{
+ return platform_driver_register(&txx9aclc_pcm_driver);
+}
+module_init(snd_txx9aclc_pcm_init);
+
+static void __exit snd_txx9aclc_pcm_exit(void)
+{
+ platform_driver_unregister(&txx9aclc_pcm_driver);
+}
+module_exit(snd_txx9aclc_pcm_exit);
MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver");
diff --git a/sound/soc/txx9/txx9aclc.h b/sound/soc/txx9/txx9aclc.h
index 6769aab41b33..9c2de84fec3b 100644
--- a/sound/soc/txx9/txx9aclc.h
+++ b/sound/soc/txx9/txx9aclc.h
@@ -65,19 +65,10 @@ struct txx9aclc_plat_drvdata {
u64 physbase;
};
-struct txx9aclc_soc_device {
- struct snd_soc_device soc_dev;
- struct platform_device *aclc_pdev; /* for ioresources, drvdata */
- struct txx9aclc_dmadata dmadata[2];
-};
-
static inline struct txx9aclc_plat_drvdata *txx9aclc_get_plat_drvdata(
- struct txx9aclc_soc_device *sdev)
+ struct snd_soc_dai *dai)
{
- return platform_get_drvdata(sdev->aclc_pdev);
+ return dev_get_drvdata(dai->dev);
}
-extern struct snd_soc_platform txx9aclc_soc_platform;
-extern struct snd_soc_dai txx9aclc_ac97_dai;
-
#endif /* __TXX9ACLC_H */
diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c
index ff0b2a8fd25b..5ae1eae9f6db 100644
--- a/sound/synth/emux/emux_hwdep.c
+++ b/sound/synth/emux/emux_hwdep.c
@@ -128,6 +128,9 @@ snd_emux_init_hwdep(struct snd_emux *emu)
strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME);
hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE;
hw->ops.ioctl = snd_emux_hwdep_ioctl;
+ /* The ioctl parameter types are compatible between 32- and
+ * 64-bit architectures, so use the same function. */
+ hw->ops.ioctl_compat = snd_emux_hwdep_ioctl;
hw->exclusive = 1;
hw->private_data = emu;
if ((err = snd_card_register(emu->card)) < 0)
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index 44d6d2ec964f..112984f4080f 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -65,6 +65,7 @@ config SND_USB_CAIAQ
* Native Instruments Guitar Rig Session I/O
* Native Instruments Guitar Rig mobile
* Native Instruments Traktor Kontrol X1
+ * Native Instruments Traktor Kontrol S4
To compile this driver as a module, choose M here: the module
will be called snd-usb-caiaq.
@@ -82,6 +83,7 @@ config SND_USB_CAIAQ_INPUT
* Native Instruments Kore Controller
* Native Instruments Kore Controller 2
* Native Instruments Audio Kontrol 1
+ * Native Instruments Traktor Kontrol S4
config SND_USB_US122L
tristate "Tascam US-122L USB driver"
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index 4328cad6c3a2..68b97477577b 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -111,7 +111,7 @@ static int stream_start(struct snd_usb_caiaqdev *dev)
memset(dev->sub_capture, 0, sizeof(dev->sub_capture));
dev->input_panic = 0;
dev->output_panic = 0;
- dev->first_packet = 1;
+ dev->first_packet = 4;
dev->streaming = 1;
dev->warned = 0;
@@ -169,7 +169,7 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)
}
static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub,
- struct snd_pcm_hw_params *hw_params)
+ struct snd_pcm_hw_params *hw_params)
{
debug("%s(%p)\n", __func__, sub);
return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params));
@@ -189,7 +189,7 @@ static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub)
#endif
static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100,
- 48000, 64000, 88200, 96000, 176400, 192000 };
+ 48000, 64000, 88200, 96000, 176400, 192000 };
static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
{
@@ -201,12 +201,39 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
debug("%s(%p)\n", __func__, substream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- dev->period_out_count[index] = BYTES_PER_SAMPLE + 1;
- dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1;
+ int out_pos;
+
+ switch (dev->spec.data_alignment) {
+ case 0:
+ case 2:
+ out_pos = BYTES_PER_SAMPLE + 1;
+ break;
+ case 3:
+ default:
+ out_pos = 0;
+ break;
+ }
+
+ dev->period_out_count[index] = out_pos;
+ dev->audio_out_buf_pos[index] = out_pos;
} else {
- int in_pos = (dev->spec.data_alignment == 2) ? 0 : 2;
- dev->period_in_count[index] = BYTES_PER_SAMPLE + in_pos;
- dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE + in_pos;
+ int in_pos;
+
+ switch (dev->spec.data_alignment) {
+ case 0:
+ in_pos = BYTES_PER_SAMPLE + 2;
+ break;
+ case 2:
+ in_pos = BYTES_PER_SAMPLE;
+ break;
+ case 3:
+ default:
+ in_pos = 0;
+ break;
+ }
+
+ dev->period_in_count[index] = in_pos;
+ dev->audio_in_buf_pos[index] = in_pos;
}
if (dev->streaming)
@@ -221,7 +248,7 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
snd_pcm_limit_hw_rates(runtime);
bytes_per_sample = BYTES_PER_SAMPLE;
- if (dev->spec.data_alignment == 2)
+ if (dev->spec.data_alignment >= 2)
bytes_per_sample++;
bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE)
@@ -253,6 +280,8 @@ static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd)
{
struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub);
+ debug("%s(%p) cmd %d\n", __func__, sub, cmd);
+
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -402,6 +431,61 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev,
}
}
+static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,
+ const struct urb *urb,
+ const struct usb_iso_packet_descriptor *iso)
+{
+ unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
+ int stream, i;
+
+ /* paranoia check */
+ if (iso->actual_length % (BYTES_PER_SAMPLE_USB * CHANNELS_PER_STREAM))
+ return;
+
+ for (i = 0; i < iso->actual_length;) {
+ for (stream = 0; stream < dev->n_streams; stream++) {
+ struct snd_pcm_substream *sub = dev->sub_capture[stream];
+ char *audio_buf = NULL;
+ int c, n, sz = 0;
+
+ if (sub && !dev->input_panic) {
+ struct snd_pcm_runtime *rt = sub->runtime;
+ audio_buf = rt->dma_area;
+ sz = frames_to_bytes(rt, rt->buffer_size);
+ }
+
+ for (c = 0; c < CHANNELS_PER_STREAM; c++) {
+ /* 3 audio data bytes, followed by 1 check byte */
+ if (audio_buf) {
+ for (n = 0; n < BYTES_PER_SAMPLE; n++) {
+ audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i+n];
+
+ if (dev->audio_in_buf_pos[stream] == sz)
+ dev->audio_in_buf_pos[stream] = 0;
+ }
+
+ dev->period_in_count[stream] += BYTES_PER_SAMPLE;
+ }
+
+ i += BYTES_PER_SAMPLE;
+
+ if (usb_buf[i] != ((stream << 1) | c) &&
+ !dev->first_packet) {
+ if (!dev->input_panic)
+ printk(" EXPECTED: %02x got %02x, c %d, stream %d, i %d\n",
+ ((stream << 1) | c), usb_buf[i], c, stream, i);
+ dev->input_panic = 1;
+ }
+
+ i++;
+ }
+ }
+ }
+
+ if (dev->first_packet > 0)
+ dev->first_packet--;
+}
+
static void read_in_urb(struct snd_usb_caiaqdev *dev,
const struct urb *urb,
const struct usb_iso_packet_descriptor *iso)
@@ -419,6 +503,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev,
case 2:
read_in_urb_mode2(dev, urb, iso);
break;
+ case 3:
+ read_in_urb_mode3(dev, urb, iso);
+ break;
}
if ((dev->input_panic || dev->output_panic) && !dev->warned) {
@@ -429,9 +516,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev,
}
}
-static void fill_out_urb(struct snd_usb_caiaqdev *dev,
- struct urb *urb,
- const struct usb_iso_packet_descriptor *iso)
+static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev,
+ struct urb *urb,
+ const struct usb_iso_packet_descriptor *iso)
{
unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
struct snd_pcm_substream *sub;
@@ -457,9 +544,67 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev,
/* fill in the check bytes */
if (dev->spec.data_alignment == 2 &&
i % (dev->n_streams * BYTES_PER_SAMPLE_USB) ==
- (dev->n_streams * CHANNELS_PER_STREAM))
- for (stream = 0; stream < dev->n_streams; stream++, i++)
- usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i);
+ (dev->n_streams * CHANNELS_PER_STREAM))
+ for (stream = 0; stream < dev->n_streams; stream++, i++)
+ usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i);
+ }
+}
+
+static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,
+ struct urb *urb,
+ const struct usb_iso_packet_descriptor *iso)
+{
+ unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
+ int stream, i;
+
+ for (i = 0; i < iso->length;) {
+ for (stream = 0; stream < dev->n_streams; stream++) {
+ struct snd_pcm_substream *sub = dev->sub_playback[stream];
+ char *audio_buf = NULL;
+ int c, n, sz = 0;
+
+ if (sub) {
+ struct snd_pcm_runtime *rt = sub->runtime;
+ audio_buf = rt->dma_area;
+ sz = frames_to_bytes(rt, rt->buffer_size);
+ }
+
+ for (c = 0; c < CHANNELS_PER_STREAM; c++) {
+ for (n = 0; n < BYTES_PER_SAMPLE; n++) {
+ if (audio_buf) {
+ usb_buf[i+n] = audio_buf[dev->audio_out_buf_pos[stream]++];
+
+ if (dev->audio_out_buf_pos[stream] == sz)
+ dev->audio_out_buf_pos[stream] = 0;
+ } else {
+ usb_buf[i+n] = 0;
+ }
+ }
+
+ if (audio_buf)
+ dev->period_out_count[stream] += BYTES_PER_SAMPLE;
+
+ i += BYTES_PER_SAMPLE;
+
+ /* fill in the check byte pattern */
+ usb_buf[i++] = (stream << 1) | c;
+ }
+ }
+ }
+}
+
+static inline void fill_out_urb(struct snd_usb_caiaqdev *dev,
+ struct urb *urb,
+ const struct usb_iso_packet_descriptor *iso)
+{
+ switch (dev->spec.data_alignment) {
+ case 0:
+ case 2:
+ fill_out_urb_mode_0(dev, urb, iso);
+ break;
+ case 3:
+ fill_out_urb_mode_3(dev, urb, iso);
+ break;
}
}
diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c
index 91c804cd2782..00e5d0a469e1 100644
--- a/sound/usb/caiaq/control.c
+++ b/sound/usb/caiaq/control.c
@@ -55,6 +55,10 @@ static int control_info(struct snd_kcontrol *kcontrol,
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
maxval = 127;
break;
+
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+ maxval = 31;
+ break;
}
if (is_intval) {
@@ -93,6 +97,7 @@ static int control_put(struct snd_kcontrol *kcontrol,
struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
int pos = kcontrol->private_value;
+ int v = ucontrol->value.integer.value[0];
unsigned char cmd = EP1_CMD_WRITE_IO;
if (dev->chip.usb_id ==
@@ -100,12 +105,27 @@ static int control_put(struct snd_kcontrol *kcontrol,
cmd = EP1_CMD_DIMM_LEDS;
if (pos & CNT_INTVAL) {
- dev->control_state[pos & ~CNT_INTVAL]
- = ucontrol->value.integer.value[0];
- snd_usb_caiaq_send_command(dev, cmd,
- dev->control_state, sizeof(dev->control_state));
+ int i = pos & ~CNT_INTVAL;
+
+ dev->control_state[i] = v;
+
+ if (dev->chip.usb_id ==
+ USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4)) {
+ int actual_len;
+
+ dev->ep8_out_buf[0] = i;
+ dev->ep8_out_buf[1] = v;
+
+ usb_bulk_msg(dev->chip.dev,
+ usb_sndbulkpipe(dev->chip.dev, 8),
+ dev->ep8_out_buf, sizeof(dev->ep8_out_buf),
+ &actual_len, 200);
+ } else {
+ snd_usb_caiaq_send_command(dev, cmd,
+ dev->control_state, sizeof(dev->control_state));
+ }
} else {
- if (ucontrol->value.integer.value[0])
+ if (v)
dev->control_state[pos / 8] |= 1 << (pos % 8);
else
dev->control_state[pos / 8] &= ~(1 << (pos % 8));
@@ -296,6 +316,179 @@ static struct caiaq_controller kontrolx1_controller[] = {
{ "LED Deck B: SYNC", 8 | CNT_INTVAL },
};
+static struct caiaq_controller kontrols4_controller[] = {
+ { "LED: Master: Quant", 10 | CNT_INTVAL },
+ { "LED: Master: Headphone", 11 | CNT_INTVAL },
+ { "LED: Master: Master", 12 | CNT_INTVAL },
+ { "LED: Master: Snap", 14 | CNT_INTVAL },
+ { "LED: Master: Warning", 15 | CNT_INTVAL },
+ { "LED: Master: Master button", 112 | CNT_INTVAL },
+ { "LED: Master: Snap button", 113 | CNT_INTVAL },
+ { "LED: Master: Rec", 118 | CNT_INTVAL },
+ { "LED: Master: Size", 119 | CNT_INTVAL },
+ { "LED: Master: Quant button", 120 | CNT_INTVAL },
+ { "LED: Master: Browser button", 121 | CNT_INTVAL },
+ { "LED: Master: Play button", 126 | CNT_INTVAL },
+ { "LED: Master: Undo button", 127 | CNT_INTVAL },
+
+ { "LED: Channel A: >", 4 | CNT_INTVAL },
+ { "LED: Channel A: <", 5 | CNT_INTVAL },
+ { "LED: Channel A: Meter 1", 97 | CNT_INTVAL },
+ { "LED: Channel A: Meter 2", 98 | CNT_INTVAL },
+ { "LED: Channel A: Meter 3", 99 | CNT_INTVAL },
+ { "LED: Channel A: Meter 4", 100 | CNT_INTVAL },
+ { "LED: Channel A: Meter 5", 101 | CNT_INTVAL },
+ { "LED: Channel A: Meter 6", 102 | CNT_INTVAL },
+ { "LED: Channel A: Meter clip", 103 | CNT_INTVAL },
+ { "LED: Channel A: Active", 114 | CNT_INTVAL },
+ { "LED: Channel A: Cue", 116 | CNT_INTVAL },
+ { "LED: Channel A: FX1", 149 | CNT_INTVAL },
+ { "LED: Channel A: FX2", 148 | CNT_INTVAL },
+
+ { "LED: Channel B: >", 2 | CNT_INTVAL },
+ { "LED: Channel B: <", 3 | CNT_INTVAL },
+ { "LED: Channel B: Meter 1", 89 | CNT_INTVAL },
+ { "LED: Channel B: Meter 2", 90 | CNT_INTVAL },
+ { "LED: Channel B: Meter 3", 91 | CNT_INTVAL },
+ { "LED: Channel B: Meter 4", 92 | CNT_INTVAL },
+ { "LED: Channel B: Meter 5", 93 | CNT_INTVAL },
+ { "LED: Channel B: Meter 6", 94 | CNT_INTVAL },
+ { "LED: Channel B: Meter clip", 95 | CNT_INTVAL },
+ { "LED: Channel B: Active", 122 | CNT_INTVAL },
+ { "LED: Channel B: Cue", 125 | CNT_INTVAL },
+ { "LED: Channel B: FX1", 147 | CNT_INTVAL },
+ { "LED: Channel B: FX2", 146 | CNT_INTVAL },
+
+ { "LED: Channel C: >", 6 | CNT_INTVAL },
+ { "LED: Channel C: <", 7 | CNT_INTVAL },
+ { "LED: Channel C: Meter 1", 105 | CNT_INTVAL },
+ { "LED: Channel C: Meter 2", 106 | CNT_INTVAL },
+ { "LED: Channel C: Meter 3", 107 | CNT_INTVAL },
+ { "LED: Channel C: Meter 4", 108 | CNT_INTVAL },
+ { "LED: Channel C: Meter 5", 109 | CNT_INTVAL },
+ { "LED: Channel C: Meter 6", 110 | CNT_INTVAL },
+ { "LED: Channel C: Meter clip", 111 | CNT_INTVAL },
+ { "LED: Channel C: Active", 115 | CNT_INTVAL },
+ { "LED: Channel C: Cue", 117 | CNT_INTVAL },
+ { "LED: Channel C: FX1", 151 | CNT_INTVAL },
+ { "LED: Channel C: FX2", 150 | CNT_INTVAL },
+
+ { "LED: Channel D: >", 0 | CNT_INTVAL },
+ { "LED: Channel D: <", 1 | CNT_INTVAL },
+ { "LED: Channel D: Meter 1", 81 | CNT_INTVAL },
+ { "LED: Channel D: Meter 2", 82 | CNT_INTVAL },
+ { "LED: Channel D: Meter 3", 83 | CNT_INTVAL },
+ { "LED: Channel D: Meter 4", 84 | CNT_INTVAL },
+ { "LED: Channel D: Meter 5", 85 | CNT_INTVAL },
+ { "LED: Channel D: Meter 6", 86 | CNT_INTVAL },
+ { "LED: Channel D: Meter clip", 87 | CNT_INTVAL },
+ { "LED: Channel D: Active", 123 | CNT_INTVAL },
+ { "LED: Channel D: Cue", 124 | CNT_INTVAL },
+ { "LED: Channel D: FX1", 145 | CNT_INTVAL },
+ { "LED: Channel D: FX2", 144 | CNT_INTVAL },
+
+ { "LED: Deck A: 1 (blue)", 22 | CNT_INTVAL },
+ { "LED: Deck A: 1 (green)", 23 | CNT_INTVAL },
+ { "LED: Deck A: 2 (blue)", 20 | CNT_INTVAL },
+ { "LED: Deck A: 2 (green)", 21 | CNT_INTVAL },
+ { "LED: Deck A: 3 (blue)", 18 | CNT_INTVAL },
+ { "LED: Deck A: 3 (green)", 19 | CNT_INTVAL },
+ { "LED: Deck A: 4 (blue)", 16 | CNT_INTVAL },
+ { "LED: Deck A: 4 (green)", 17 | CNT_INTVAL },
+ { "LED: Deck A: Load", 44 | CNT_INTVAL },
+ { "LED: Deck A: Deck C button", 45 | CNT_INTVAL },
+ { "LED: Deck A: In", 47 | CNT_INTVAL },
+ { "LED: Deck A: Out", 46 | CNT_INTVAL },
+ { "LED: Deck A: Shift", 24 | CNT_INTVAL },
+ { "LED: Deck A: Sync", 27 | CNT_INTVAL },
+ { "LED: Deck A: Cue", 26 | CNT_INTVAL },
+ { "LED: Deck A: Play", 25 | CNT_INTVAL },
+ { "LED: Deck A: Tempo up", 33 | CNT_INTVAL },
+ { "LED: Deck A: Tempo down", 32 | CNT_INTVAL },
+ { "LED: Deck A: Master", 34 | CNT_INTVAL },
+ { "LED: Deck A: Keylock", 35 | CNT_INTVAL },
+ { "LED: Deck A: Deck A", 37 | CNT_INTVAL },
+ { "LED: Deck A: Deck C", 36 | CNT_INTVAL },
+ { "LED: Deck A: Samples", 38 | CNT_INTVAL },
+ { "LED: Deck A: On Air", 39 | CNT_INTVAL },
+ { "LED: Deck A: Sample 1", 31 | CNT_INTVAL },
+ { "LED: Deck A: Sample 2", 30 | CNT_INTVAL },
+ { "LED: Deck A: Sample 3", 29 | CNT_INTVAL },
+ { "LED: Deck A: Sample 4", 28 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - A", 55 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - B", 54 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - C", 53 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - D", 52 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - E", 51 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - F", 50 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - G", 49 | CNT_INTVAL },
+ { "LED: Deck A: Digit 1 - dot", 48 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - A", 63 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - B", 62 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - C", 61 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - D", 60 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - E", 59 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - F", 58 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - G", 57 | CNT_INTVAL },
+ { "LED: Deck A: Digit 2 - dot", 56 | CNT_INTVAL },
+
+ { "LED: Deck B: 1 (blue)", 78 | CNT_INTVAL },
+ { "LED: Deck B: 1 (green)", 79 | CNT_INTVAL },
+ { "LED: Deck B: 2 (blue)", 76 | CNT_INTVAL },
+ { "LED: Deck B: 2 (green)", 77 | CNT_INTVAL },
+ { "LED: Deck B: 3 (blue)", 74 | CNT_INTVAL },
+ { "LED: Deck B: 3 (green)", 75 | CNT_INTVAL },
+ { "LED: Deck B: 4 (blue)", 72 | CNT_INTVAL },
+ { "LED: Deck B: 4 (green)", 73 | CNT_INTVAL },
+ { "LED: Deck B: Load", 180 | CNT_INTVAL },
+ { "LED: Deck B: Deck D button", 181 | CNT_INTVAL },
+ { "LED: Deck B: In", 183 | CNT_INTVAL },
+ { "LED: Deck B: Out", 182 | CNT_INTVAL },
+ { "LED: Deck B: Shift", 64 | CNT_INTVAL },
+ { "LED: Deck B: Sync", 67 | CNT_INTVAL },
+ { "LED: Deck B: Cue", 66 | CNT_INTVAL },
+ { "LED: Deck B: Play", 65 | CNT_INTVAL },
+ { "LED: Deck B: Tempo up", 185 | CNT_INTVAL },
+ { "LED: Deck B: Tempo down", 184 | CNT_INTVAL },
+ { "LED: Deck B: Master", 186 | CNT_INTVAL },
+ { "LED: Deck B: Keylock", 187 | CNT_INTVAL },
+ { "LED: Deck B: Deck B", 189 | CNT_INTVAL },
+ { "LED: Deck B: Deck D", 188 | CNT_INTVAL },
+ { "LED: Deck B: Samples", 190 | CNT_INTVAL },
+ { "LED: Deck B: On Air", 191 | CNT_INTVAL },
+ { "LED: Deck B: Sample 1", 71 | CNT_INTVAL },
+ { "LED: Deck B: Sample 2", 70 | CNT_INTVAL },
+ { "LED: Deck B: Sample 3", 69 | CNT_INTVAL },
+ { "LED: Deck B: Sample 4", 68 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - A", 175 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - B", 174 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - C", 173 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - D", 172 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - E", 171 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - F", 170 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - G", 169 | CNT_INTVAL },
+ { "LED: Deck B: Digit 1 - dot", 168 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - A", 167 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - B", 166 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - C", 165 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - D", 164 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - E", 163 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - F", 162 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - G", 161 | CNT_INTVAL },
+ { "LED: Deck B: Digit 2 - dot", 160 | CNT_INTVAL },
+
+ { "LED: FX1: dry/wet", 153 | CNT_INTVAL },
+ { "LED: FX1: 1", 154 | CNT_INTVAL },
+ { "LED: FX1: 2", 155 | CNT_INTVAL },
+ { "LED: FX1: 3", 156 | CNT_INTVAL },
+ { "LED: FX1: Mode", 157 | CNT_INTVAL },
+ { "LED: FX2: dry/wet", 129 | CNT_INTVAL },
+ { "LED: FX2: 1", 130 | CNT_INTVAL },
+ { "LED: FX2: 2", 131 | CNT_INTVAL },
+ { "LED: FX2: 3", 132 | CNT_INTVAL },
+ { "LED: FX2: Mode", 133 | CNT_INTVAL },
+};
+
static int __devinit add_controls(struct caiaq_controller *c, int num,
struct snd_usb_caiaqdev *dev)
{
@@ -354,6 +547,11 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev)
ret = add_controls(kontrolx1_controller,
ARRAY_SIZE(kontrolx1_controller), dev);
break;
+
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+ ret = add_controls(kontrols4_controller,
+ ARRAY_SIZE(kontrols4_controller), dev);
+ break;
}
return ret;
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index cdfb856bddd2..6480c3283c05 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -36,7 +36,7 @@
#include "input.h"
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.21");
+MODULE_DESCRIPTION("caiaq USB audio");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
"{Native Instruments, RigKontrol3},"
@@ -48,7 +48,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
"{Native Instruments, Audio 8 DJ},"
"{Native Instruments, Session I/O},"
"{Native Instruments, GuitarRig mobile}"
- "{Native Instruments, Traktor Kontrol X1}");
+ "{Native Instruments, Traktor Kontrol X1}"
+ "{Native Instruments, Traktor Kontrol S4}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
@@ -134,6 +135,11 @@ static struct usb_device_id snd_usb_id_table[] = {
.idVendor = USB_VID_NATIVEINSTRUMENTS,
.idProduct = USB_PID_TRAKTORKONTROLX1
},
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = USB_VID_NATIVEINSTRUMENTS,
+ .idProduct = USB_PID_TRAKTORKONTROLS4
+ },
{ /* terminator */ }
};
diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h
index f1117ecc84fd..e3d8a3efb35b 100644
--- a/sound/usb/caiaq/device.h
+++ b/sound/usb/caiaq/device.h
@@ -16,6 +16,7 @@
#define USB_PID_SESSIONIO 0x1915
#define USB_PID_GUITARRIGMOBILE 0x0d8d
#define USB_PID_TRAKTORKONTROLX1 0x2305
+#define USB_PID_TRAKTORKONTROLS4 0xbaff
#define EP1_BUFSIZE 64
#define EP4_BUFSIZE 512
@@ -99,13 +100,14 @@ struct snd_usb_caiaqdev {
struct snd_pcm_substream *sub_capture[MAX_STREAMS];
/* Controls */
- unsigned char control_state[64];
+ unsigned char control_state[256];
+ unsigned char ep8_out_buf[2];
/* Linux input */
#ifdef CONFIG_SND_USB_CAIAQ_INPUT
struct input_dev *input_dev;
char phys[64]; /* physical device path */
- unsigned short keycode[64];
+ unsigned short keycode[128];
struct urb *ep4_in_urb;
unsigned char ep4_in_buf[EP4_BUFSIZE];
#endif
diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c
index dcb620796d9e..4432ef7a70a9 100644
--- a/sound/usb/caiaq/input.c
+++ b/sound/usb/caiaq/input.c
@@ -67,7 +67,12 @@ static unsigned short keycode_kore[] = {
KEY_BRL_DOT5
};
-#define KONTROLX1_INPUTS 40
+#define KONTROLX1_INPUTS (40)
+#define KONTROLS4_BUTTONS (12 * 8)
+#define KONTROLS4_AXIS (46)
+
+#define KONTROLS4_BUTTON(X) ((X) + BTN_MISC)
+#define KONTROLS4_ABS(X) ((X) + ABS_HAT0X)
#define DEG90 (range / 2)
#define DEG180 (range)
@@ -139,6 +144,13 @@ static unsigned int decode_erp(unsigned char a, unsigned char b)
#undef HIGH_PEAK
#undef LOW_PEAK
+static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *dev,
+ int axis, const unsigned char *buf,
+ int offset)
+{
+ input_report_abs(dev->input_dev, axis,
+ (buf[offset * 2] << 8) | buf[offset * 2 + 1]);
+}
static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
const unsigned char *buf,
@@ -148,36 +160,30 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
- input_report_abs(input_dev, ABS_X, (buf[4] << 8) | buf[5]);
- input_report_abs(input_dev, ABS_Y, (buf[0] << 8) | buf[1]);
- input_report_abs(input_dev, ABS_Z, (buf[2] << 8) | buf[3]);
- input_sync(input_dev);
+ snd_caiaq_input_report_abs(dev, ABS_X, buf, 2);
+ snd_caiaq_input_report_abs(dev, ABS_Y, buf, 0);
+ snd_caiaq_input_report_abs(dev, ABS_Z, buf, 1);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
- input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]);
- input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]);
- input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]);
- input_sync(input_dev);
- break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
- input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]);
- input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]);
- input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]);
- input_sync(input_dev);
+ snd_caiaq_input_report_abs(dev, ABS_X, buf, 0);
+ snd_caiaq_input_report_abs(dev, ABS_Y, buf, 1);
+ snd_caiaq_input_report_abs(dev, ABS_Z, buf, 2);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
- input_report_abs(input_dev, ABS_HAT0X, (buf[8] << 8) | buf[9]);
- input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8) | buf[5]);
- input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]);
- input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8) | buf[3]);
- input_report_abs(input_dev, ABS_HAT2X, (buf[14] << 8) | buf[15]);
- input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8) | buf[1]);
- input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]);
- input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8) | buf[7]);
- input_sync(input_dev);
+ snd_caiaq_input_report_abs(dev, ABS_HAT0X, buf, 4);
+ snd_caiaq_input_report_abs(dev, ABS_HAT0Y, buf, 2);
+ snd_caiaq_input_report_abs(dev, ABS_HAT1X, buf, 6);
+ snd_caiaq_input_report_abs(dev, ABS_HAT1Y, buf, 1);
+ snd_caiaq_input_report_abs(dev, ABS_HAT2X, buf, 7);
+ snd_caiaq_input_report_abs(dev, ABS_HAT2Y, buf, 0);
+ snd_caiaq_input_report_abs(dev, ABS_HAT3X, buf, 5);
+ snd_caiaq_input_report_abs(dev, ABS_HAT3Y, buf, 3);
break;
}
+
+ input_sync(input_dev);
}
static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,
@@ -250,6 +256,150 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
input_sync(input_dev);
}
+#define TKS4_MSGBLOCK_SIZE 16
+
+static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev,
+ const unsigned char *buf,
+ unsigned int len)
+{
+ while (len) {
+ unsigned int i, block_id = (buf[0] << 8) | buf[1];
+
+ switch (block_id) {
+ case 0:
+ /* buttons */
+ for (i = 0; i < KONTROLS4_BUTTONS; i++)
+ input_report_key(dev->input_dev, KONTROLS4_BUTTON(i),
+ (buf[4 + (i / 8)] >> (i % 8)) & 1);
+ break;
+
+ case 1:
+ /* left wheel */
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(36), buf[9] | ((buf[8] & 0x3) << 8));
+ /* right wheel */
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(37), buf[13] | ((buf[12] & 0x3) << 8));
+
+ /* rotary encoders */
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(38), buf[3] & 0xf);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(39), buf[4] >> 4);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(40), buf[4] & 0xf);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(41), buf[5] >> 4);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(42), buf[5] & 0xf);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(43), buf[6] >> 4);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(44), buf[6] & 0xf);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(45), buf[7] >> 4);
+ input_report_abs(dev->input_dev, KONTROLS4_ABS(46), buf[7] & 0xf);
+
+ break;
+ case 2:
+ /* Volume Fader Channel D */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(0), buf, 1);
+ /* Volume Fader Channel B */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(1), buf, 2);
+ /* Volume Fader Channel A */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(2), buf, 3);
+ /* Volume Fader Channel C */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(3), buf, 4);
+ /* Loop Volume */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(4), buf, 6);
+ /* Crossfader */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(7), buf, 7);
+
+ break;
+
+ case 3:
+ /* Tempo Fader R */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(6), buf, 3);
+ /* Tempo Fader L */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(5), buf, 4);
+ /* Mic Volume */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(8), buf, 6);
+ /* Cue Mix */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(9), buf, 7);
+
+ break;
+
+ case 4:
+ /* Wheel distance sensor L */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(10), buf, 1);
+ /* Wheel distance sensor R */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(11), buf, 2);
+ /* Channel D EQ - Filter */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(12), buf, 3);
+ /* Channel D EQ - Low */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(13), buf, 4);
+ /* Channel D EQ - Mid */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(14), buf, 5);
+ /* Channel D EQ - Hi */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(15), buf, 6);
+ /* FX2 - dry/wet */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(16), buf, 7);
+
+ break;
+
+ case 5:
+ /* FX2 - 1 */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(17), buf, 1);
+ /* FX2 - 2 */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(18), buf, 2);
+ /* FX2 - 3 */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(19), buf, 3);
+ /* Channel B EQ - Filter */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(20), buf, 4);
+ /* Channel B EQ - Low */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(21), buf, 5);
+ /* Channel B EQ - Mid */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(22), buf, 6);
+ /* Channel B EQ - Hi */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(23), buf, 7);
+
+ break;
+
+ case 6:
+ /* Channel A EQ - Filter */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(24), buf, 1);
+ /* Channel A EQ - Low */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(25), buf, 2);
+ /* Channel A EQ - Mid */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(26), buf, 3);
+ /* Channel A EQ - Hi */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(27), buf, 4);
+ /* Channel C EQ - Filter */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(28), buf, 5);
+ /* Channel C EQ - Low */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(29), buf, 6);
+ /* Channel C EQ - Mid */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(30), buf, 7);
+
+ break;
+
+ case 7:
+ /* Channel C EQ - Hi */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(31), buf, 1);
+ /* FX1 - wet/dry */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(32), buf, 2);
+ /* FX1 - 1 */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(33), buf, 3);
+ /* FX1 - 2 */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(34), buf, 4);
+ /* FX1 - 3 */
+ snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(35), buf, 5);
+
+ break;
+
+ default:
+ debug("%s(): bogus block (id %d)\n",
+ __func__, block_id);
+ return;
+ }
+
+ len -= TKS4_MSGBLOCK_SIZE;
+ buf += TKS4_MSGBLOCK_SIZE;
+ }
+
+ input_sync(dev->input_dev);
+}
+
static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
{
struct snd_usb_caiaqdev *dev = urb->context;
@@ -259,11 +409,11 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
if (urb->status || !dev || urb != dev->ep4_in_urb)
return;
- if (urb->actual_length < 24)
- goto requeue;
-
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ if (urb->actual_length < 24)
+ goto requeue;
+
if (buf[0] & 0x3)
snd_caiaq_input_read_io(dev, buf + 1, 7);
@@ -271,6 +421,10 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
snd_caiaq_input_read_analog(dev, buf + 8, 16);
break;
+
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+ snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length);
+ break;
}
requeue:
@@ -289,6 +443,7 @@ static int snd_usb_caiaq_input_open(struct input_dev *idev)
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0)
return -EIO;
break;
@@ -306,6 +461,7 @@ static void snd_usb_caiaq_input_close(struct input_dev *idev)
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
usb_kill_urb(dev->ep4_in_urb);
break;
}
@@ -456,6 +612,46 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
break;
+
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+ input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLS4_BUTTONS);
+ for (i = 0; i < KONTROLS4_BUTTONS; i++)
+ dev->keycode[i] = KONTROLS4_BUTTON(i);
+ input->keycodemax = KONTROLS4_BUTTONS;
+
+ for (i = 0; i < KONTROLS4_AXIS; i++) {
+ int axis = KONTROLS4_ABS(i);
+ input->absbit[BIT_WORD(axis)] |= BIT_MASK(axis);
+ }
+
+ /* 36 analog potentiometers and faders */
+ for (i = 0; i < 36; i++)
+ input_set_abs_params(input, KONTROLS4_ABS(i), 0, 0xfff, 0, 10);
+
+ /* 2 encoder wheels */
+ input_set_abs_params(input, KONTROLS4_ABS(36), 0, 0x3ff, 0, 1);
+ input_set_abs_params(input, KONTROLS4_ABS(37), 0, 0x3ff, 0, 1);
+
+ /* 9 rotary encoders */
+ for (i = 0; i < 9; i++)
+ input_set_abs_params(input, KONTROLS4_ABS(38+i), 0, 0xf, 0, 1);
+
+ dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->ep4_in_urb) {
+ ret = -ENOMEM;
+ goto exit_free_idev;
+ }
+
+ usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev,
+ usb_rcvbulkpipe(usb_dev, 0x4),
+ dev->ep4_in_buf, EP4_BUFSIZE,
+ snd_usb_caiaq_ep4_reply_dispatch, dev);
+
+ snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
+
+ break;
+
default:
/* no input methods supported on this device */
goto exit_free_idev;
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 4eabafa5b037..800f7cb4f251 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -300,9 +300,13 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
*rchip = NULL;
- if (snd_usb_get_speed(dev) != USB_SPEED_LOW &&
- snd_usb_get_speed(dev) != USB_SPEED_FULL &&
- snd_usb_get_speed(dev) != USB_SPEED_HIGH) {
+ switch (snd_usb_get_speed(dev)) {
+ case USB_SPEED_LOW:
+ case USB_SPEED_FULL:
+ case USB_SPEED_HIGH:
+ case USB_SPEED_SUPER:
+ break;
+ default:
snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev));
return -ENXIO;
}
@@ -378,11 +382,22 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
if (len < sizeof(card->longname))
usb_make_path(dev, card->longname + len, sizeof(card->longname) - len);
- strlcat(card->longname,
- snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" :
- snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" :
- ", high speed",
- sizeof(card->longname));
+ switch (snd_usb_get_speed(dev)) {
+ case USB_SPEED_LOW:
+ strlcat(card->longname, ", low speed", sizeof(card->longname));
+ break;
+ case USB_SPEED_FULL:
+ strlcat(card->longname, ", full speed", sizeof(card->longname));
+ break;
+ case USB_SPEED_HIGH:
+ strlcat(card->longname, ", high speed", sizeof(card->longname));
+ break;
+ case USB_SPEED_SUPER:
+ strlcat(card->longname, ", super speed", sizeof(card->longname));
+ break;
+ default:
+ break;
+ }
snd_usb_audio_create_proc(chip);
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 1febf2f23754..ae4251d5abf7 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -62,12 +62,14 @@ struct snd_usb_substream {
unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */
unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */
unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */
+ int freqshift; /* how much to shift the feedback value to get Q16.16 */
unsigned int freqmax; /* maximum sampling rate, used for buffer management */
unsigned int phase; /* phase accumulator */
unsigned int maxpacksize; /* max packet size in bytes */
unsigned int maxframesize; /* max packet size in frames */
unsigned int curpacksize; /* current packet size in bytes (for capture) */
unsigned int curframesize; /* current packet size in frames (for capture) */
+ unsigned int syncmaxsize; /* sync endpoint packet size */
unsigned int fill_max: 1; /* fill max packet size always */
unsigned int txfr_quirk:1; /* allow sub-frame alignment */
unsigned int fmt_type; /* USB audio format type (1-3) */
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index ef0a07e34844..b0ef9f501896 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -405,8 +405,6 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
break;
case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
- case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra 8 */
- case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
/* doesn't set the sample rate attribute, but supports it */
fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE;
break;
diff --git a/sound/usb/helper.c b/sound/usb/helper.c
index d48d6f8f6ac9..f280c1903c25 100644
--- a/sound/usb/helper.c
+++ b/sound/usb/helper.c
@@ -103,11 +103,16 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
struct usb_host_interface *alts)
{
- if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH &&
- get_endpoint(alts, 0)->bInterval >= 1 &&
- get_endpoint(alts, 0)->bInterval <= 4)
- return get_endpoint(alts, 0)->bInterval - 1;
- else
- return 0;
+ switch (snd_usb_get_speed(chip->dev)) {
+ case USB_SPEED_HIGH:
+ case USB_SPEED_SUPER:
+ if (get_endpoint(alts, 0)->bInterval >= 1 &&
+ get_endpoint(alts, 0)->bInterval <= 4)
+ return get_endpoint(alts, 0)->bInterval - 1;
+ break;
+ default:
+ break;
+ }
+ return 0;
}
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index b9c2bc65f51a..25bce7e5b1af 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -784,7 +784,7 @@ static struct usb_protocol_ops snd_usbmidi_novation_ops = {
};
/*
- * "raw" protocol: used by the MOTU FastLane.
+ * "raw" protocol: just move raw MIDI bytes from/to the endpoint
*/
static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint* ep,
@@ -834,7 +834,14 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep,
if (!ep->ports[0].active)
return;
- count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2;
+ switch (snd_usb_get_speed(ep->umidi->dev)) {
+ case USB_SPEED_HIGH:
+ case USB_SPEED_SUPER:
+ count = 1;
+ break;
+ default:
+ count = 2;
+ }
count = snd_rawmidi_transmit(ep->ports[0].substream,
urb->transfer_buffer,
count);
@@ -2115,7 +2122,7 @@ int snd_usbmidi_create(struct snd_card *card,
umidi->usb_protocol_ops = &snd_usbmidi_novation_ops;
err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
break;
- case QUIRK_MIDI_FASTLANE:
+ case QUIRK_MIDI_RAW_BYTES:
umidi->usb_protocol_ops = &snd_usbmidi_raw_ops;
/*
* Interface 1 contains isochronous endpoints, but with the same
@@ -2126,7 +2133,8 @@ int snd_usbmidi_create(struct snd_card *card,
* interface 0, so we have to make sure that the USB core looks
* again at interface 0 by calling usb_set_interface() on it.
*/
- usb_set_interface(umidi->dev, 0, 0);
+ if (umidi->usb_id == USB_ID(0x07fd, 0x0001)) /* MOTU Fastlane */
+ usb_set_interface(umidi->dev, 0, 0);
err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
break;
case QUIRK_MIDI_EMAGIC:
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 3ed3901369ce..f2d74d654b3c 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -759,8 +759,6 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
*/
static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
{
- struct snd_usb_audio *chip = cval->mixer->chip;
-
/* for failsafe */
cval->min = default_min;
cval->max = cval->min + 1;
@@ -783,7 +781,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n",
- cval->id, snd_usb_ctrl_intf(chip), cval->control, cval->id);
+ cval->id, snd_usb_ctrl_intf(cval->mixer->chip), cval->control, cval->id);
return -EINVAL;
}
if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) {
@@ -1642,9 +1640,10 @@ static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = cval->max;
- if ((int)uinfo->value.enumerated.item >= cval->max)
+ if (uinfo->value.enumerated.item >= cval->max)
uinfo->value.enumerated.item = cval->max - 1;
- strcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item]);
+ strlcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item],
+ sizeof(uinfo->value.enumerated.name));
return 0;
}
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index e7df1e5e3f2e..7dae05d8783e 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -60,6 +60,7 @@ static const struct rc_config {
{ USB_ID(0x041e, 0x3000), 0, 1, 2, 1, 18, 0x0013 }, /* Extigy */
{ USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */
{ USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */
+ { USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi */
{ USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */
};
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 3b5135c93062..cff3a3c465d7 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -237,6 +237,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
subs->datainterval = fmt->datainterval;
subs->syncpipe = subs->syncinterval = 0;
subs->maxpacksize = fmt->maxpacksize;
+ subs->syncmaxsize = 0;
subs->fill_max = 0;
/* we need a sync pipe in async OUT or adaptive IN mode */
@@ -283,6 +284,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1;
else
subs->syncinterval = 3;
+ subs->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize);
}
/* always fill max packet size */
@@ -466,7 +468,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs,
return 0;
}
/* check whether the period time is >= the data packet interval */
- if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) {
+ if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) {
ptime = 125 * (1 << fp->datainterval);
if (ptime > pt->max || (ptime == pt->max && pt->openmax)) {
hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max);
@@ -734,7 +736,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
}
param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME;
- if (snd_usb_get_speed(subs->dev) != USB_SPEED_HIGH)
+ if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
/* full speed devices have fixed data packet interval */
ptmin = 1000;
if (ptmin == 1000)
diff --git a/sound/usb/proc.c b/sound/usb/proc.c
index f5e3f356b95f..961c9a250686 100644
--- a/sound/usb/proc.c
+++ b/sound/usb/proc.c
@@ -107,7 +107,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
}
snd_iprintf(buffer, "\n");
}
- if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
+ if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
snd_iprintf(buffer, " Data packet interval: %d us\n",
125 * (1 << fp->datainterval));
// snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize);
@@ -132,6 +132,11 @@ static void proc_dump_substream_status(struct snd_usb_substream *subs, struct sn
? get_full_speed_hz(subs->freqm)
: get_high_speed_hz(subs->freqm),
subs->freqm >> 16, subs->freqm & 0xffff);
+ if (subs->freqshift != INT_MIN)
+ snd_iprintf(buffer, " Feedback Format = %d.%d\n",
+ (subs->syncmaxsize > 3 ? 32 : 24)
+ - (16 - subs->freqshift),
+ 16 - subs->freqshift);
} else {
snd_iprintf(buffer, " Status: Stop\n");
}
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 2e8003f98fca..ad7079d1676c 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -240,9 +240,21 @@ YAMAHA_DEVICE(0x104f, NULL),
YAMAHA_DEVICE(0x1050, NULL),
YAMAHA_DEVICE(0x1051, NULL),
YAMAHA_DEVICE(0x1052, NULL),
+YAMAHA_INTERFACE(0x1053, 0, NULL),
+YAMAHA_INTERFACE(0x1054, 0, NULL),
+YAMAHA_DEVICE(0x1055, NULL),
+YAMAHA_DEVICE(0x1056, NULL),
+YAMAHA_DEVICE(0x1057, NULL),
+YAMAHA_DEVICE(0x1058, NULL),
+YAMAHA_DEVICE(0x1059, NULL),
+YAMAHA_DEVICE(0x105a, NULL),
+YAMAHA_DEVICE(0x105b, NULL),
+YAMAHA_DEVICE(0x105c, NULL),
+YAMAHA_DEVICE(0x105d, NULL),
YAMAHA_DEVICE(0x2000, "DGP-7"),
YAMAHA_DEVICE(0x2001, "DGP-5"),
YAMAHA_DEVICE(0x2002, NULL),
+YAMAHA_DEVICE(0x2003, NULL),
YAMAHA_DEVICE(0x5000, "CS1D"),
YAMAHA_DEVICE(0x5001, "DSP1D"),
YAMAHA_DEVICE(0x5002, "DME32"),
@@ -1136,11 +1148,34 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
+ /* has ID 0x0066 when not in "Advanced Driver" mode */
+ USB_DEVICE(0x0582, 0x0064),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ /* .vendor_name = "EDIROL", */
+ /* .product_name = "PCR-1", */
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
+{
/* has ID 0x0067 when not in "Advanced Driver" mode */
USB_DEVICE(0x0582, 0x0065),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "EDIROL",
- .product_name = "PCR-1",
+ /* .vendor_name = "EDIROL", */
+ /* .product_name = "PCR-1", */
.ifnum = 0,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const struct snd_usb_midi_endpoint_info) {
@@ -1525,6 +1560,50 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
+{
+ /* has ID 0x0110 when not in Advanced Driver mode */
+ USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ /* .vendor_name = "Roland", */
+ /* .product_name = "A-PRO", */
+ .ifnum = 1,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const struct snd_usb_midi_endpoint_info) {
+ .out_cables = 0x0003,
+ .in_cables = 0x0007
+ }
+ }
+},
+{
+ USB_DEVICE(0x0582, 0x0113),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ /* .vendor_name = "BOSS", */
+ /* .product_name = "ME-25", */
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const struct snd_usb_midi_endpoint_info) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
/* Guillemot devices */
{
@@ -1830,7 +1909,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
USB_DEVICE(0x0763, 0x2080),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
/* .vendor_name = "M-Audio", */
- /* .product_name = "Fast Track Ultra 8", */
+ /* .product_name = "Fast Track Ultra", */
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_COMPOSITE,
.data = & (const struct snd_usb_audio_quirk[]) {
@@ -1840,11 +1919,51 @@ YAMAHA_DEVICE(0x7010, "UB99"),
},
{
.ifnum = 1,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = & (const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 1,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .endpoint = 0x01,
+ .ep_attr = 0x09,
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 44100,
+ .rate_max = 96000,
+ .nr_rates = 4,
+ .rate_table = (unsigned int[]) {
+ 44100, 48000, 88200, 96000
+ }
+ }
},
{
.ifnum = 2,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = & (const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 2,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .endpoint = 0x81,
+ .ep_attr = 0x05,
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 44100,
+ .rate_max = 96000,
+ .nr_rates = 4,
+ .rate_table = (unsigned int[]) {
+ 44100, 48000, 88200, 96000
+ }
+ }
},
/* interface 3 (MIDI) is standard compliant */
{
@@ -1867,11 +1986,51 @@ YAMAHA_DEVICE(0x7010, "UB99"),
},
{
.ifnum = 1,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = & (const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 1,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .endpoint = 0x01,
+ .ep_attr = 0x09,
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 44100,
+ .rate_max = 96000,
+ .nr_rates = 4,
+ .rate_table = (unsigned int[]) {
+ 44100, 48000, 88200, 96000
+ }
+ }
},
{
.ifnum = 2,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = & (const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 2,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .endpoint = 0x81,
+ .ep_attr = 0x05,
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 44100,
+ .rate_max = 96000,
+ .nr_rates = 4,
+ .rate_table = (unsigned int[]) {
+ 44100, 48000, 88200, 96000
+ }
+ }
},
/* interface 3 (MIDI) is standard compliant */
{
@@ -1919,7 +2078,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.data = & (const struct snd_usb_audio_quirk[]) {
{
.ifnum = 0,
- .type = QUIRK_MIDI_FASTLANE
+ .type = QUIRK_MIDI_RAW_BYTES
},
{
.ifnum = 1,
@@ -2068,6 +2227,15 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
+ USB_DEVICE(0x1235, 0x000e),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ /* .vendor_name = "Novation", */
+ /* .product_name = "Launchpad", */
+ .ifnum = 0,
+ .type = QUIRK_MIDI_RAW_BYTES
+ }
+},
+{
USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
.vendor_name = "Novation",
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 9a9da09586a5..cf8bf088394b 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -287,7 +287,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
[QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
[QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,
[QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
- [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk,
+ [QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk,
[QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
[QUIRK_MIDI_CME] = create_any_midi_quirk,
[QUIRK_MIDI_AKAI] = create_any_midi_quirk,
diff --git a/sound/usb/urb.c b/sound/usb/urb.c
index de607d4411ac..e184349aee83 100644
--- a/sound/usb/urb.c
+++ b/sound/usb/urb.c
@@ -225,6 +225,7 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
else
subs->freqn = get_usb_high_speed_rate(rate);
subs->freqm = subs->freqn;
+ subs->freqshift = INT_MIN;
/* calculate max. frequency */
if (subs->maxpacksize) {
/* whatever fits into a max. size packet */
@@ -244,7 +245,7 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
else
subs->curpacksize = maxsize;
- if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
+ if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
packs_per_ms = 8 >> subs->datainterval;
else
packs_per_ms = 1;
@@ -513,11 +514,10 @@ static int retire_paused_capture_urb(struct snd_usb_substream *subs,
/*
- * prepare urb for full speed playback sync pipe
+ * prepare urb for playback sync pipe
*
* set up the offset and length to receive the current frequency.
*/
-
static int prepare_playback_sync_urb(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
@@ -525,103 +525,78 @@ static int prepare_playback_sync_urb(struct snd_usb_substream *subs,
struct snd_urb_ctx *ctx = urb->context;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
- urb->iso_frame_desc[0].length = 3;
+ urb->iso_frame_desc[0].length = min(4u, ctx->subs->syncmaxsize);
urb->iso_frame_desc[0].offset = 0;
return 0;
}
/*
- * prepare urb for high speed playback sync pipe
+ * process after playback sync complete
*
- * set up the offset and length to receive the current frequency.
- */
-
-static int prepare_playback_sync_urb_hs(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- struct snd_urb_ctx *ctx = urb->context;
-
- urb->dev = ctx->subs->dev; /* we need to set this at each time */
- urb->iso_frame_desc[0].length = 4;
- urb->iso_frame_desc[0].offset = 0;
- return 0;
-}
-
-/*
- * process after full speed playback sync complete
- *
- * retrieve the current 10.14 frequency from pipe, and set it.
- * the value is referred in prepare_playback_urb().
+ * Full speed devices report feedback values in 10.14 format as samples per
+ * frame, high speed devices in 16.16 format as samples per microframe.
+ * Because the Audio Class 1 spec was written before USB 2.0, many high speed
+ * devices use a wrong interpretation, some others use an entirely different
+ * format. Therefore, we cannot predict what format any particular device uses
+ * and must detect it automatically.
*/
static int retire_playback_sync_urb(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
{
unsigned int f;
+ int shift;
unsigned long flags;
- if (urb->iso_frame_desc[0].status == 0 &&
- urb->iso_frame_desc[0].actual_length == 3) {
- f = combine_triple((u8*)urb->transfer_buffer) << 2;
- if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) {
- spin_lock_irqsave(&subs->lock, flags);
- subs->freqm = f;
- spin_unlock_irqrestore(&subs->lock, flags);
- }
- }
-
- return 0;
-}
+ if (urb->iso_frame_desc[0].status != 0 ||
+ urb->iso_frame_desc[0].actual_length < 3)
+ return 0;
-/*
- * process after high speed playback sync complete
- *
- * retrieve the current 12.13 frequency from pipe, and set it.
- * the value is referred in prepare_playback_urb().
- */
-static int retire_playback_sync_urb_hs(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- unsigned int f;
- unsigned long flags;
+ f = le32_to_cpup(urb->transfer_buffer);
+ if (urb->iso_frame_desc[0].actual_length == 3)
+ f &= 0x00ffffff;
+ else
+ f &= 0x0fffffff;
+ if (f == 0)
+ return 0;
- if (urb->iso_frame_desc[0].status == 0 &&
- urb->iso_frame_desc[0].actual_length == 4) {
- f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff;
- if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) {
- spin_lock_irqsave(&subs->lock, flags);
- subs->freqm = f;
- spin_unlock_irqrestore(&subs->lock, flags);
+ if (unlikely(subs->freqshift == INT_MIN)) {
+ /*
+ * The first time we see a feedback value, determine its format
+ * by shifting it left or right until it matches the nominal
+ * frequency value. This assumes that the feedback does not
+ * differ from the nominal value more than +50% or -25%.
+ */
+ shift = 0;
+ while (f < subs->freqn - subs->freqn / 4) {
+ f <<= 1;
+ shift++;
+ }
+ while (f > subs->freqn + subs->freqn / 2) {
+ f >>= 1;
+ shift--;
}
+ subs->freqshift = shift;
}
+ else if (subs->freqshift >= 0)
+ f <<= subs->freqshift;
+ else
+ f >>= -subs->freqshift;
- return 0;
-}
-
-/*
- * process after E-Mu 0202/0404/Tracker Pre high speed playback sync complete
- *
- * These devices return the number of samples per packet instead of the number
- * of samples per microframe.
- */
-static int retire_playback_sync_urb_hs_emu(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- unsigned int f;
- unsigned long flags;
-
- if (urb->iso_frame_desc[0].status == 0 &&
- urb->iso_frame_desc[0].actual_length == 4) {
- f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff;
- f >>= subs->datainterval;
- if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) {
- spin_lock_irqsave(&subs->lock, flags);
- subs->freqm = f;
- spin_unlock_irqrestore(&subs->lock, flags);
- }
+ if (likely(f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax)) {
+ /*
+ * If the frequency looks valid, set it.
+ * This value is referred to in prepare_playback_urb().
+ */
+ spin_lock_irqsave(&subs->lock, flags);
+ subs->freqm = f;
+ spin_unlock_irqrestore(&subs->lock, flags);
+ } else {
+ /*
+ * Out of range; maybe the shift value is wrong.
+ * Reset it so that we autodetect again the next time.
+ */
+ subs->freqshift = INT_MIN;
}
return 0;
@@ -878,21 +853,6 @@ static struct snd_urb_ops audio_urb_ops[2] = {
},
};
-static struct snd_urb_ops audio_urb_ops_high_speed[2] = {
- {
- .prepare = prepare_nodata_playback_urb,
- .retire = retire_playback_urb,
- .prepare_sync = prepare_playback_sync_urb_hs,
- .retire_sync = retire_playback_sync_urb_hs,
- },
- {
- .prepare = prepare_capture_urb,
- .retire = retire_capture_urb,
- .prepare_sync = prepare_capture_sync_urb_hs,
- .retire_sync = retire_capture_sync_urb,
- },
-};
-
/*
* initialize the substream instance.
*/
@@ -909,23 +869,9 @@ void snd_usb_init_substream(struct snd_usb_stream *as,
subs->direction = stream;
subs->dev = as->chip->dev;
subs->txfr_quirk = as->chip->txfr_quirk;
- if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) {
- subs->ops = audio_urb_ops[stream];
- } else {
- subs->ops = audio_urb_ops_high_speed[stream];
- switch (as->chip->usb_id) {
- case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */
- case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */
- case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */
- subs->ops.retire_sync = retire_playback_sync_urb_hs_emu;
- break;
- case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra 8 */
- case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
- subs->ops.prepare_sync = prepare_playback_sync_urb;
- subs->ops.retire_sync = retire_playback_sync_urb;
- break;
- }
- }
+ subs->ops = audio_urb_ops[stream];
+ if (snd_usb_get_speed(subs->dev) >= USB_SPEED_HIGH)
+ subs->ops.prepare_sync = prepare_capture_sync_urb_hs;
snd_usb_set_pcm_ops(as->pcm, stream);
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 24d3319cc34d..db3eb21627ee 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -70,7 +70,7 @@ enum quirk_type {
QUIRK_MIDI_YAMAHA,
QUIRK_MIDI_MIDIMAN,
QUIRK_MIDI_NOVATION,
- QUIRK_MIDI_FASTLANE,
+ QUIRK_MIDI_RAW_BYTES,
QUIRK_MIDI_EMAGIC,
QUIRK_MIDI_CME,
QUIRK_MIDI_AKAI,
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index 2a528e56afd5..287ef73b1237 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -36,9 +36,9 @@
plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the
cost of easier triggered i.e. aeolus xruns (128 or 256frames,
2periods works but is useless cause of crackling).
-
+
This is a first "proof of concept" implementation.
- Later, funcionalities should migrate to more apropriate places:
+ Later, functionalities should migrate to more apropriate places:
Userland:
- The jackd could mmap its float-pcm buffers directly from alsa-lib.
- alsa-lib could provide power of 2 period sized shaping combined with int/float
@@ -54,7 +54,7 @@
#include <linux/gfp.h>
#include "usbusx2yaudio.c"
-#if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) && USX2Y_NRPACKS == 1)
+#if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1
#include <sound/hwdep.h>
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index 43e3dd284b90..399751befeed 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -15,6 +15,23 @@ DESCRIPTION
This command displays the symbolic event types which can be selected in the
various perf commands with the -e option.
+EVENT MODIFIERS
+---------------
+
+Events can optionally have a modifer by appending a colon and one or
+more modifiers. Modifiers allow the user to restrict when events are
+counted with 'u' for user-space, 'k' for kernel, 'h' for hypervisor.
+
+The 'p' modifier can be used for specifying how precise the instruction
+address should be. The 'p' modifier is currently only implemented for
+Intel PEBS and can be specified multiple times:
+ 0 - SAMPLE_IP can have arbitrary skid
+ 1 - SAMPLE_IP must have constant skid
+ 2 - SAMPLE_IP requested to have 0 skid
+ 3 - SAMPLE_IP must have 0 skid
+
+The PEBS implementation now supports up to 2.
+
RAW HARDWARE EVENT DESCRIPTOR
-----------------------------
Even when an event is not available in a symbolic form within perf right now,
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 27d52dae5a43..62de1b7f4e76 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -16,7 +16,9 @@ or
or
'perf probe' --list
or
-'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
+'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
+or
+'perf probe' [options] --vars='PROBEPOINT'
DESCRIPTION
-----------
@@ -31,6 +33,11 @@ OPTIONS
--vmlinux=PATH::
Specify vmlinux path which has debuginfo (Dwarf binary).
+-m::
+--module=MODNAME::
+ Specify module name in which perf-probe searches probe points
+ or lines.
+
-s::
--source=PATH::
Specify path to kernel source.
@@ -57,6 +64,15 @@ OPTIONS
Show source code lines which can be probed. This needs an argument
which specifies a range of the source code. (see LINE SYNTAX for detail)
+-V::
+--vars=::
+ Show available local variables at given probe point. The argument
+ syntax is same as PROBE SYNTAX, but NO ARGs.
+
+--externs::
+ (Only for --vars) Show external defined variables in addition to local
+ variables.
+
-f::
--force::
Forcibly add events with existing name.
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 3ee27dccfde9..a91f9f9e6e5c 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -83,6 +83,10 @@ OPTIONS
--call-graph::
Do call-graph (stack chain/backtrace) recording.
+-q::
+--quiet::
+ Don't print any message, useful for scripting.
+
-v::
--verbose::
Be more verbose (show counter open errors, etc).
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 199d5e19554f..2e000c068cc5 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -50,14 +50,17 @@ static struct {
bool list_events;
bool force_add;
bool show_lines;
+ bool show_vars;
+ bool show_ext_vars;
+ bool mod_events;
int nevents;
struct perf_probe_event events[MAX_PROBES];
struct strlist *dellist;
struct line_range line_range;
+ const char *target_module;
int max_probe_points;
} params;
-
/* Parse an event definition. Note that any error must die. */
static int parse_probe_event(const char *str)
{
@@ -92,6 +95,7 @@ static int parse_probe_event_argv(int argc, const char **argv)
len = 0;
for (i = 0; i < argc; i++)
len += sprintf(&buf[len], "%s ", argv[i]);
+ params.mod_events = true;
ret = parse_probe_event(buf);
free(buf);
return ret;
@@ -100,9 +104,10 @@ static int parse_probe_event_argv(int argc, const char **argv)
static int opt_add_probe_event(const struct option *opt __used,
const char *str, int unset __used)
{
- if (str)
+ if (str) {
+ params.mod_events = true;
return parse_probe_event(str);
- else
+ } else
return 0;
}
@@ -110,6 +115,7 @@ static int opt_del_probe_event(const struct option *opt __used,
const char *str, int unset __used)
{
if (str) {
+ params.mod_events = true;
if (!params.dellist)
params.dellist = strlist__new(true, NULL);
strlist__add(params.dellist, str);
@@ -130,6 +136,25 @@ static int opt_show_lines(const struct option *opt __used,
return ret;
}
+
+static int opt_show_vars(const struct option *opt __used,
+ const char *str, int unset __used)
+{
+ struct perf_probe_event *pev = &params.events[params.nevents];
+ int ret;
+
+ if (!str)
+ return 0;
+
+ ret = parse_probe_event(str);
+ if (!ret && pev->nargs != 0) {
+ pr_err(" Error: '--vars' doesn't accept arguments.\n");
+ return -EINVAL;
+ }
+ params.show_vars = true;
+
+ return ret;
+}
#endif
static const char * const probe_usage[] = {
@@ -138,7 +163,8 @@ static const char * const probe_usage[] = {
"perf probe [<options>] --del '[GROUP:]EVENT' ...",
"perf probe --list",
#ifdef DWARF_SUPPORT
- "perf probe --line 'LINEDESC'",
+ "perf probe [<options>] --line 'LINEDESC'",
+ "perf probe [<options>] --vars 'PROBEPOINT'",
#endif
NULL
};
@@ -180,10 +206,17 @@ static const struct option options[] = {
OPT_CALLBACK('L', "line", NULL,
"FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
"Show source code lines.", opt_show_lines),
+ OPT_CALLBACK('V', "vars", NULL,
+ "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT",
+ "Show accessible variables on PROBEDEF", opt_show_vars),
+ OPT_BOOLEAN('\0', "externs", &params.show_ext_vars,
+ "Show external variables too (with --vars only)"),
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
"file", "vmlinux pathname"),
OPT_STRING('s', "source", &symbol_conf.source_prefix,
"directory", "path to kernel source"),
+ OPT_STRING('m', "module", &params.target_module,
+ "modname", "target module name"),
#endif
OPT__DRY_RUN(&probe_event_dry_run),
OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
@@ -217,7 +250,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
usage_with_options(probe_usage, options);
if (params.list_events) {
- if (params.nevents != 0 || params.dellist) {
+ if (params.mod_events) {
pr_err(" Error: Don't use --list with --add/--del.\n");
usage_with_options(probe_usage, options);
}
@@ -225,6 +258,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
pr_err(" Error: Don't use --list with --line.\n");
usage_with_options(probe_usage, options);
}
+ if (params.show_vars) {
+ pr_err(" Error: Don't use --list with --vars.\n");
+ usage_with_options(probe_usage, options);
+ }
ret = show_perf_probe_events();
if (ret < 0)
pr_err(" Error: Failed to show event list. (%d)\n",
@@ -234,17 +271,35 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
#ifdef DWARF_SUPPORT
if (params.show_lines) {
- if (params.nevents != 0 || params.dellist) {
- pr_warning(" Error: Don't use --line with"
- " --add/--del.\n");
+ if (params.mod_events) {
+ pr_err(" Error: Don't use --line with"
+ " --add/--del.\n");
+ usage_with_options(probe_usage, options);
+ }
+ if (params.show_vars) {
+ pr_err(" Error: Don't use --line with --vars.\n");
usage_with_options(probe_usage, options);
}
- ret = show_line_range(&params.line_range);
+ ret = show_line_range(&params.line_range, params.target_module);
if (ret < 0)
pr_err(" Error: Failed to show lines. (%d)\n", ret);
return ret;
}
+ if (params.show_vars) {
+ if (params.mod_events) {
+ pr_err(" Error: Don't use --vars with"
+ " --add/--del.\n");
+ usage_with_options(probe_usage, options);
+ }
+ ret = show_available_vars(params.events, params.nevents,
+ params.max_probe_points,
+ params.target_module,
+ params.show_ext_vars);
+ if (ret < 0)
+ pr_err(" Error: Failed to show vars. (%d)\n", ret);
+ return ret;
+ }
#endif
if (params.dellist) {
@@ -258,8 +313,9 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
if (params.nevents) {
ret = add_perf_probe_events(params.events, params.nevents,
- params.force_add,
- params.max_probe_points);
+ params.max_probe_points,
+ params.target_module,
+ params.force_add);
if (ret < 0) {
pr_err(" Error: Failed to add events. (%d)\n", ret);
return ret;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index ff77b805de71..4e75583ddd6d 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -353,7 +353,7 @@ try_again:
}
if (read(fd[nr_cpu][counter][thread_index], &read_data, sizeof(read_data)) == -1) {
- perror("Unable to read perf file descriptor\n");
+ perror("Unable to read perf file descriptor");
exit(-1);
}
@@ -626,7 +626,7 @@ static int __cmd_record(int argc, const char **argv)
nr_cpus = read_cpu_map(cpu_list);
if (nr_cpus < 1) {
- perror("failed to collect number of CPUs\n");
+ perror("failed to collect number of CPUs");
return -1;
}
@@ -761,6 +761,9 @@ static int __cmd_record(int argc, const char **argv)
}
}
+ if (quiet)
+ return 0;
+
fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
/*
@@ -820,6 +823,7 @@ static const struct option options[] = {
"do call-graph (stack chain/backtrace) recording"),
OPT_INCR('v', "verbose", &verbose,
"be more verbose (show counter open errors, etc)"),
+ OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
OPT_BOOLEAN('s', "stat", &inherit_stat,
"per thread counts"),
OPT_BOOLEAN('d', "data", &sample_address,
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 40a6a2992d15..2f8df45c4dcb 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -46,9 +46,6 @@ static struct scripting_ops *scripting_ops;
static void setup_scripting(void)
{
- /* make sure PERF_EXEC_PATH is set for scripts */
- perf_set_argv_exec_path(perf_exec_path());
-
setup_perl_scripting();
setup_python_scripting();
@@ -285,7 +282,7 @@ static int parse_scriptname(const struct option *opt __used,
script++;
} else {
script = str;
- ext = strchr(script, '.');
+ ext = strrchr(script, '.');
if (!ext) {
fprintf(stderr, "invalid script extension");
return -1;
@@ -593,6 +590,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
suffix = REPORT_SUFFIX;
}
+ /* make sure PERF_EXEC_PATH is set for scripts */
+ perf_set_argv_exec_path(perf_exec_path());
+
if (!suffix && argc >= 2 && strncmp(argv[1], "-", strlen("-")) != 0) {
char *record_script_path, *report_script_path;
int live_pipe[2];
@@ -625,12 +625,13 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
dup2(live_pipe[1], 1);
close(live_pipe[0]);
- __argv = malloc(5 * sizeof(const char *));
+ __argv = malloc(6 * sizeof(const char *));
__argv[0] = "/bin/sh";
__argv[1] = record_script_path;
- __argv[2] = "-o";
- __argv[3] = "-";
- __argv[4] = NULL;
+ __argv[2] = "-q";
+ __argv[3] = "-o";
+ __argv[4] = "-";
+ __argv[5] = NULL;
execvp("/bin/sh", (char **)__argv);
exit(-1);
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-report b/tools/perf/scripts/perl/bin/failed-syscalls-report
index e3a5e55d54ff..4028d92dc4ae 100644
--- a/tools/perf/scripts/perl/bin/failed-syscalls-report
+++ b/tools/perf/scripts/perl/bin/failed-syscalls-report
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
shift
fi
fi
-perf trace $@ -s ~/libexec/perf-core/scripts/perl/failed-syscalls.pl $comm
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/failed-syscalls.pl $comm
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-report b/tools/perf/scripts/perl/bin/rw-by-file-report
index d83070b7eeb5..ba25f4d41fb0 100644
--- a/tools/perf/scripts/perl/bin/rw-by-file-report
+++ b/tools/perf/scripts/perl/bin/rw-by-file-report
@@ -7,7 +7,7 @@ if [ $# -lt 1 ] ; then
fi
comm=$1
shift
-perf trace $@ -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl $comm
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/rw-by-file.pl $comm
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-report b/tools/perf/scripts/perl/bin/rw-by-pid-report
index 7ef46983f62f..641a3f5d085c 100644
--- a/tools/perf/scripts/perl/bin/rw-by-pid-report
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-report
@@ -1,6 +1,6 @@
#!/bin/bash
# description: system-wide r/w activity
-perf trace $@ -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/rw-by-pid.pl
diff --git a/tools/perf/scripts/perl/bin/rwtop-report b/tools/perf/scripts/perl/bin/rwtop-report
index 93e698cd3f38..4918dba77021 100644
--- a/tools/perf/scripts/perl/bin/rwtop-report
+++ b/tools/perf/scripts/perl/bin/rwtop-report
@@ -17,7 +17,7 @@ if [ "$n_args" -gt 0 ] ; then
interval=$1
shift
fi
-perf trace $@ -s ~/libexec/perf-core/scripts/perl/rwtop.pl $interval
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/rwtop.pl $interval
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-report b/tools/perf/scripts/perl/bin/wakeup-latency-report
index a0d898f9ca1d..49052ebcb632 100644
--- a/tools/perf/scripts/perl/bin/wakeup-latency-report
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-report
@@ -1,6 +1,6 @@
#!/bin/bash
# description: system-wide min/max/avg wakeup latency
-perf trace $@ -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/wakeup-latency.pl
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report
index 35081132ef97..df0c65f4ca93 100644
--- a/tools/perf/scripts/perl/bin/workqueue-stats-report
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-report
@@ -1,6 +1,6 @@
#!/bin/bash
# description: workqueue stats (ins/exe/create/destroy)
-perf trace $@ -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/workqueue-stats.pl
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
index 9689bc0acd9f..13cc02b5893a 100644
--- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
@@ -6,6 +6,14 @@
# Public License ("GPL") version 2 as published by the Free Software
# Foundation.
+import errno, os
+
+FUTEX_WAIT = 0
+FUTEX_WAKE = 1
+FUTEX_PRIVATE_FLAG = 128
+FUTEX_CLOCK_REALTIME = 256
+FUTEX_CMD_MASK = ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
+
NSECS_PER_SEC = 1000000000
def avg(total, n):
@@ -24,5 +32,55 @@ def nsecs_str(nsecs):
str = "%5u.%09u" % (nsecs_secs(nsecs), nsecs_nsecs(nsecs)),
return str
+def add_stats(dict, key, value):
+ if not dict.has_key(key):
+ dict[key] = (value, value, value, 1)
+ else:
+ min, max, avg, count = dict[key]
+ if value < min:
+ min = value
+ if value > max:
+ max = value
+ avg = (avg + value) / 2
+ dict[key] = (min, max, avg, count + 1)
+
def clear_term():
print("\x1b[H\x1b[2J")
+
+audit_package_warned = False
+
+try:
+ import audit
+ machine_to_id = {
+ 'x86_64': audit.MACH_86_64,
+ 'alpha' : audit.MACH_ALPHA,
+ 'ia64' : audit.MACH_IA64,
+ 'ppc' : audit.MACH_PPC,
+ 'ppc64' : audit.MACH_PPC64,
+ 's390' : audit.MACH_S390,
+ 's390x' : audit.MACH_S390X,
+ 'i386' : audit.MACH_X86,
+ 'i586' : audit.MACH_X86,
+ 'i686' : audit.MACH_X86,
+ }
+ try:
+ machine_to_id['armeb'] = audit.MACH_ARMEB
+ except:
+ pass
+ machine_id = machine_to_id[os.uname()[4]]
+except:
+ if not audit_package_warned:
+ audit_package_warned = True
+ print "Install the audit-libs-python package to get syscall names"
+
+def syscall_name(id):
+ try:
+ return audit.audit_syscall_to_name(id, machine_id)
+ except:
+ return str(id)
+
+def strerror(nr):
+ try:
+ return errno.errorcode[abs(nr)]
+ except:
+ return "Unknown %d errno" % nr
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
index 30293545fcc2..03587021463d 100644
--- a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
+++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
shift
fi
fi
-perf trace $@ -s ~/libexec/perf-core/scripts/python/failed-syscalls-by-pid.py $comm
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/failed-syscalls-by-pid.py $comm
diff --git a/tools/perf/scripts/python/bin/futex-contention-record b/tools/perf/scripts/python/bin/futex-contention-record
new file mode 100644
index 000000000000..5ecbb433caf4
--- /dev/null
+++ b/tools/perf/scripts/python/bin/futex-contention-record
@@ -0,0 +1,2 @@
+#!/bin/bash
+perf record -a -e syscalls:sys_enter_futex -e syscalls:sys_exit_futex $@
diff --git a/tools/perf/scripts/python/bin/futex-contention-report b/tools/perf/scripts/python/bin/futex-contention-report
new file mode 100644
index 000000000000..c8268138fb7e
--- /dev/null
+++ b/tools/perf/scripts/python/bin/futex-contention-report
@@ -0,0 +1,4 @@
+#!/bin/bash
+# description: futext contention measurement
+
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/futex-contention.py
diff --git a/tools/perf/scripts/python/bin/netdev-times-report b/tools/perf/scripts/python/bin/netdev-times-report
index c3d0a638123d..4ad361b31249 100644
--- a/tools/perf/scripts/python/bin/netdev-times-report
+++ b/tools/perf/scripts/python/bin/netdev-times-report
@@ -2,4 +2,4 @@
# description: display a process of packet and processing time
# args: [tx] [rx] [dev=] [debug]
-perf trace -s ~/libexec/perf-core/scripts/python/netdev-times.py $@
+perf trace -s "$PERF_EXEC_PATH"/scripts/python/netdev-times.py $@
diff --git a/tools/perf/scripts/python/bin/sched-migration-report b/tools/perf/scripts/python/bin/sched-migration-report
index 61d05f72e443..df1791f07c24 100644
--- a/tools/perf/scripts/python/bin/sched-migration-report
+++ b/tools/perf/scripts/python/bin/sched-migration-report
@@ -1,3 +1,3 @@
#!/bin/bash
# description: sched migration overview
-perf trace $@ -s ~/libexec/perf-core/scripts/python/sched-migration.py
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/sched-migration.py
diff --git a/tools/perf/scripts/python/bin/sctop-report b/tools/perf/scripts/python/bin/sctop-report
index b01c842ae7b4..36b409c05e50 100644
--- a/tools/perf/scripts/python/bin/sctop-report
+++ b/tools/perf/scripts/python/bin/sctop-report
@@ -21,4 +21,4 @@ elif [ "$n_args" -gt 0 ] ; then
interval=$1
shift
fi
-perf trace $@ -s ~/libexec/perf-core/scripts/python/sctop.py $comm $interval
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/sctop.py $comm $interval
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-report b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report
index 9e9d8ddd72ce..4eb88c9fc83c 100644
--- a/tools/perf/scripts/python/bin/syscall-counts-by-pid-report
+++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
shift
fi
fi
-perf trace $@ -s ~/libexec/perf-core/scripts/python/syscall-counts-by-pid.py $comm
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/syscall-counts-by-pid.py $comm
diff --git a/tools/perf/scripts/python/bin/syscall-counts-report b/tools/perf/scripts/python/bin/syscall-counts-report
index dc076b618796..cb2f9c5cf17e 100644
--- a/tools/perf/scripts/python/bin/syscall-counts-report
+++ b/tools/perf/scripts/python/bin/syscall-counts-report
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
shift
fi
fi
-perf trace $@ -s ~/libexec/perf-core/scripts/python/syscall-counts.py $comm
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/syscall-counts.py $comm
diff --git a/tools/perf/scripts/python/failed-syscalls-by-pid.py b/tools/perf/scripts/python/failed-syscalls-by-pid.py
index 0ca02278fe69..acd7848717b3 100644
--- a/tools/perf/scripts/python/failed-syscalls-by-pid.py
+++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py
@@ -13,21 +13,26 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \
from perf_trace_context import *
from Core import *
+from Util import *
-usage = "perf trace -s syscall-counts-by-pid.py [comm]\n";
+usage = "perf trace -s syscall-counts-by-pid.py [comm|pid]\n";
for_comm = None
+for_pid = None
if len(sys.argv) > 2:
sys.exit(usage)
if len(sys.argv) > 1:
- for_comm = sys.argv[1]
+ try:
+ for_pid = int(sys.argv[1])
+ except:
+ for_comm = sys.argv[1]
syscalls = autodict()
def trace_begin():
- pass
+ print "Press control+C to stop and show the summary"
def trace_end():
print_error_totals()
@@ -35,9 +40,9 @@ def trace_end():
def raw_syscalls__sys_exit(event_name, context, common_cpu,
common_secs, common_nsecs, common_pid, common_comm,
id, ret):
- if for_comm is not None:
- if common_comm != for_comm:
- return
+ if (for_comm and common_comm != for_comm) or \
+ (for_pid and common_pid != for_pid ):
+ return
if ret < 0:
try:
@@ -62,7 +67,7 @@ def print_error_totals():
print "\n%s [%d]\n" % (comm, pid),
id_keys = syscalls[comm][pid].keys()
for id in id_keys:
- print " syscall: %-16d\n" % (id),
+ print " syscall: %-16s\n" % syscall_name(id),
ret_keys = syscalls[comm][pid][id].keys()
for ret, val in sorted(syscalls[comm][pid][id].iteritems(), key = lambda(k, v): (v, k), reverse = True):
- print " err = %-20d %10d\n" % (ret, val),
+ print " err = %-20s %10d\n" % (strerror(ret), val),
diff --git a/tools/perf/scripts/python/futex-contention.py b/tools/perf/scripts/python/futex-contention.py
new file mode 100644
index 000000000000..11e70a388d41
--- /dev/null
+++ b/tools/perf/scripts/python/futex-contention.py
@@ -0,0 +1,50 @@
+# futex contention
+# (c) 2010, Arnaldo Carvalho de Melo <acme@redhat.com>
+# Licensed under the terms of the GNU GPL License version 2
+#
+# Translation of:
+#
+# http://sourceware.org/systemtap/wiki/WSFutexContention
+#
+# to perf python scripting.
+#
+# Measures futex contention
+
+import os, sys
+sys.path.append(os.environ['PERF_EXEC_PATH'] + '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
+from Util import *
+
+process_names = {}
+thread_thislock = {}
+thread_blocktime = {}
+
+lock_waits = {} # long-lived stats on (tid,lock) blockage elapsed time
+process_names = {} # long-lived pid-to-execname mapping
+
+def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm,
+ nr, uaddr, op, val, utime, uaddr2, val3):
+ cmd = op & FUTEX_CMD_MASK
+ if cmd != FUTEX_WAIT:
+ return # we don't care about originators of WAKE events
+
+ process_names[tid] = comm
+ thread_thislock[tid] = uaddr
+ thread_blocktime[tid] = nsecs(s, ns)
+
+def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm,
+ nr, ret):
+ if thread_blocktime.has_key(tid):
+ elapsed = nsecs(s, ns) - thread_blocktime[tid]
+ add_stats(lock_waits, (tid, thread_thislock[tid]), elapsed)
+ del thread_blocktime[tid]
+ del thread_thislock[tid]
+
+def trace_begin():
+ print "Press control+C to stop and show the summary"
+
+def trace_end():
+ for (tid, lock) in lock_waits:
+ min, max, avg, count = lock_waits[tid, lock]
+ print "%s[%d] lock %x contended %d times, %d avg ns" % \
+ (process_names[tid], tid, lock, count, avg)
+
diff --git a/tools/perf/scripts/python/sctop.py b/tools/perf/scripts/python/sctop.py
index 6cafad40c296..7a6ec2c7d8ab 100644
--- a/tools/perf/scripts/python/sctop.py
+++ b/tools/perf/scripts/python/sctop.py
@@ -8,10 +8,7 @@
# will be refreshed every [interval] seconds. The default interval is
# 3 seconds.
-import thread
-import time
-import os
-import sys
+import os, sys, thread, time
sys.path.append(os.environ['PERF_EXEC_PATH'] + \
'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
@@ -20,7 +17,7 @@ from perf_trace_context import *
from Core import *
from Util import *
-usage = "perf trace -s syscall-counts.py [comm] [interval]\n";
+usage = "perf trace -s sctop.py [comm] [interval]\n";
for_comm = None
default_interval = 3
@@ -71,7 +68,7 @@ def print_syscall_totals(interval):
for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
reverse = True):
try:
- print "%-40d %10d\n" % (id, val),
+ print "%-40s %10d\n" % (syscall_name(id), val),
except TypeError:
pass
syscalls.clear()
diff --git a/tools/perf/scripts/python/syscall-counts-by-pid.py b/tools/perf/scripts/python/syscall-counts-by-pid.py
index af722d6a4b3f..d1ee3ec10cf2 100644
--- a/tools/perf/scripts/python/syscall-counts-by-pid.py
+++ b/tools/perf/scripts/python/syscall-counts-by-pid.py
@@ -5,29 +5,33 @@
# Displays system-wide system call totals, broken down by syscall.
# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
-import os
-import sys
+import os, sys
sys.path.append(os.environ['PERF_EXEC_PATH'] + \
'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
from perf_trace_context import *
from Core import *
+from Util import syscall_name
usage = "perf trace -s syscall-counts-by-pid.py [comm]\n";
for_comm = None
+for_pid = None
if len(sys.argv) > 2:
sys.exit(usage)
if len(sys.argv) > 1:
- for_comm = sys.argv[1]
+ try:
+ for_pid = int(sys.argv[1])
+ except:
+ for_comm = sys.argv[1]
syscalls = autodict()
def trace_begin():
- pass
+ print "Press control+C to stop and show the summary"
def trace_end():
print_syscall_totals()
@@ -35,9 +39,10 @@ def trace_end():
def raw_syscalls__sys_enter(event_name, context, common_cpu,
common_secs, common_nsecs, common_pid, common_comm,
id, args):
- if for_comm is not None:
- if common_comm != for_comm:
- return
+
+ if (for_comm and common_comm != for_comm) or \
+ (for_pid and common_pid != for_pid ):
+ return
try:
syscalls[common_comm][common_pid][id] += 1
except TypeError:
@@ -61,4 +66,4 @@ def print_syscall_totals():
id_keys = syscalls[comm][pid].keys()
for id, val in sorted(syscalls[comm][pid].iteritems(), \
key = lambda(k, v): (v, k), reverse = True):
- print " %-38d %10d\n" % (id, val),
+ print " %-38s %10d\n" % (syscall_name(id), val),
diff --git a/tools/perf/scripts/python/syscall-counts.py b/tools/perf/scripts/python/syscall-counts.py
index f977e85ff049..ea183dc82d29 100644
--- a/tools/perf/scripts/python/syscall-counts.py
+++ b/tools/perf/scripts/python/syscall-counts.py
@@ -13,6 +13,7 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \
from perf_trace_context import *
from Core import *
+from Util import syscall_name
usage = "perf trace -s syscall-counts.py [comm]\n";
@@ -27,7 +28,7 @@ if len(sys.argv) > 1:
syscalls = autodict()
def trace_begin():
- pass
+ print "Press control+C to stop and show the summary"
def trace_end():
print_syscall_totals()
@@ -55,4 +56,4 @@ def print_syscall_totals():
for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
reverse = True):
- print "%-40d %10d\n" % (id, val),
+ print "%-40s %10d\n" % (syscall_name(id), val),
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index f9c7e3ad1aa7..c8d81b00089d 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -12,8 +12,8 @@
#include "debug.h"
#include "util.h"
-int verbose = 0;
-bool dump_trace = false;
+int verbose;
+bool dump_trace = false, quiet = false;
int eprintf(int level, const char *fmt, ...)
{
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 7a17ee061bcb..7b514082bbaf 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -6,7 +6,7 @@
#include "event.h"
extern int verbose;
-extern bool dump_trace;
+extern bool quiet, dump_trace;
int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
void trace_event(event_t *event);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 78575796d5f3..b397c0383728 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -215,6 +215,16 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *self,
return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter);
}
+static inline
+struct symbol *machine__find_kernel_function_by_name(struct machine *self,
+ const char *name,
+ struct map **mapp,
+ symbol_filter_t filter)
+{
+ return map_groups__find_function_by_name(&self->kmaps, name, mapp,
+ filter);
+}
+
int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
int verbose, FILE *fp);
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index fcc16e4349df..3b6a5297bf16 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -74,10 +74,9 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
static struct machine machine;
-/* Initialize symbol maps and path of vmlinux */
+/* Initialize symbol maps and path of vmlinux/modules */
static int init_vmlinux(void)
{
- struct dso *kernel;
int ret;
symbol_conf.sort_by_name = true;
@@ -91,33 +90,61 @@ static int init_vmlinux(void)
goto out;
}
- ret = machine__init(&machine, "/", 0);
+ ret = machine__init(&machine, "", HOST_KERNEL_ID);
if (ret < 0)
goto out;
- kernel = dso__new_kernel(symbol_conf.vmlinux_name);
- if (kernel == NULL)
- die("Failed to create kernel dso.");
-
- ret = __machine__create_kernel_maps(&machine, kernel);
- if (ret < 0)
- pr_debug("Failed to create kernel maps.\n");
-
+ if (machine__create_kernel_maps(&machine) < 0) {
+ pr_debug("machine__create_kernel_maps ");
+ goto out;
+ }
out:
if (ret < 0)
pr_warning("Failed to init vmlinux path.\n");
return ret;
}
+static struct symbol *__find_kernel_function_by_name(const char *name,
+ struct map **mapp)
+{
+ return machine__find_kernel_function_by_name(&machine, name, mapp,
+ NULL);
+}
+
+const char *kernel_get_module_path(const char *module)
+{
+ struct dso *dso;
+
+ if (module) {
+ list_for_each_entry(dso, &machine.kernel_dsos, node) {
+ if (strncmp(dso->short_name + 1, module,
+ dso->short_name_len - 2) == 0)
+ goto found;
+ }
+ pr_debug("Failed to find module %s.\n", module);
+ return NULL;
+ } else {
+ dso = machine.vmlinux_maps[MAP__FUNCTION]->dso;
+ if (dso__load_vmlinux_path(dso,
+ machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
+ pr_debug("Failed to load kernel map.\n");
+ return NULL;
+ }
+ }
+found:
+ return dso->long_name;
+}
+
#ifdef DWARF_SUPPORT
-static int open_vmlinux(void)
+static int open_vmlinux(const char *module)
{
- if (map__load(machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
- pr_debug("Failed to load kernel map.\n");
- return -EINVAL;
+ const char *path = kernel_get_module_path(module);
+ if (!path) {
+ pr_err("Failed to find path of %s module", module ?: "kernel");
+ return -ENOENT;
}
- pr_debug("Try to open %s\n", machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name);
- return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
+ pr_debug("Try to open %s\n", path);
+ return open(path, O_RDONLY);
}
/*
@@ -125,20 +152,19 @@ static int open_vmlinux(void)
* Currently only handles kprobes.
*/
static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
- struct perf_probe_point *pp)
+ struct perf_probe_point *pp)
{
struct symbol *sym;
- int fd, ret = -ENOENT;
+ struct map *map;
+ u64 addr;
+ int ret = -ENOENT;
- sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
- tp->symbol, NULL);
+ sym = __find_kernel_function_by_name(tp->symbol, &map);
if (sym) {
- fd = open_vmlinux();
- if (fd >= 0) {
- ret = find_perf_probe_point(fd,
- sym->start + tp->offset, pp);
- close(fd);
- }
+ addr = map->unmap_ip(map, sym->start + tp->offset);
+ pr_debug("try to find %s+%ld@%llx\n", tp->symbol,
+ tp->offset, addr);
+ ret = find_perf_probe_point((unsigned long)addr, pp);
}
if (ret <= 0) {
pr_debug("Failed to find corresponding probes from "
@@ -156,12 +182,12 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
/* Try to find perf_probe_event with debuginfo */
static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
struct probe_trace_event **tevs,
- int max_tevs)
+ int max_tevs, const char *module)
{
bool need_dwarf = perf_probe_event_need_dwarf(pev);
int fd, ntevs;
- fd = open_vmlinux();
+ fd = open_vmlinux(module);
if (fd < 0) {
if (need_dwarf) {
pr_warning("Failed to open debuginfo file.\n");
@@ -300,7 +326,7 @@ error:
* Show line-range always requires debuginfo to find source file and
* line number.
*/
-int show_line_range(struct line_range *lr)
+int show_line_range(struct line_range *lr, const char *module)
{
int l = 1;
struct line_node *ln;
@@ -313,7 +339,7 @@ int show_line_range(struct line_range *lr)
if (ret < 0)
return ret;
- fd = open_vmlinux();
+ fd = open_vmlinux(module);
if (fd < 0) {
pr_warning("Failed to open debuginfo file.\n");
return fd;
@@ -378,11 +404,84 @@ end:
return ret;
}
+static int show_available_vars_at(int fd, struct perf_probe_event *pev,
+ int max_vls, bool externs)
+{
+ char *buf;
+ int ret, i;
+ struct str_node *node;
+ struct variable_list *vls = NULL, *vl;
+
+ buf = synthesize_perf_probe_point(&pev->point);
+ if (!buf)
+ return -EINVAL;
+ pr_debug("Searching variables at %s\n", buf);
+
+ ret = find_available_vars_at(fd, pev, &vls, max_vls, externs);
+ if (ret > 0) {
+ /* Some variables were found */
+ fprintf(stdout, "Available variables at %s\n", buf);
+ for (i = 0; i < ret; i++) {
+ vl = &vls[i];
+ /*
+ * A probe point might be converted to
+ * several trace points.
+ */
+ fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
+ vl->point.offset);
+ free(vl->point.symbol);
+ if (vl->vars) {
+ strlist__for_each(node, vl->vars)
+ fprintf(stdout, "\t\t%s\n", node->s);
+ strlist__delete(vl->vars);
+ } else
+ fprintf(stdout, "(No variables)\n");
+ }
+ free(vls);
+ } else
+ pr_err("Failed to find variables at %s (%d)\n", buf, ret);
+
+ free(buf);
+ return ret;
+}
+
+/* Show available variables on given probe point */
+int show_available_vars(struct perf_probe_event *pevs, int npevs,
+ int max_vls, const char *module, bool externs)
+{
+ int i, fd, ret = 0;
+
+ ret = init_vmlinux();
+ if (ret < 0)
+ return ret;
+
+ fd = open_vmlinux(module);
+ if (fd < 0) {
+ pr_warning("Failed to open debuginfo file.\n");
+ return fd;
+ }
+
+ setup_pager();
+
+ for (i = 0; i < npevs && ret >= 0; i++)
+ ret = show_available_vars_at(fd, &pevs[i], max_vls, externs);
+
+ close(fd);
+ return ret;
+}
+
#else /* !DWARF_SUPPORT */
static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
- struct perf_probe_point *pp)
+ struct perf_probe_point *pp)
{
+ struct symbol *sym;
+
+ sym = __find_kernel_function_by_name(tp->symbol, NULL);
+ if (!sym) {
+ pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
+ return -ENOENT;
+ }
pp->function = strdup(tp->symbol);
if (pp->function == NULL)
return -ENOMEM;
@@ -394,7 +493,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
struct probe_trace_event **tevs __unused,
- int max_tevs __unused)
+ int max_tevs __unused, const char *mod __unused)
{
if (perf_probe_event_need_dwarf(pev)) {
pr_warning("Debuginfo-analysis is not supported.\n");
@@ -403,12 +502,19 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
return 0;
}
-int show_line_range(struct line_range *lr __unused)
+int show_line_range(struct line_range *lr __unused, const char *module __unused)
{
pr_warning("Debuginfo-analysis is not supported.\n");
return -ENOSYS;
}
+int show_available_vars(struct perf_probe_event *pevs __unused,
+ int npevs __unused, int max_vls __unused,
+ const char *module __unused, bool externs __unused)
+{
+ pr_warning("Debuginfo-analysis is not supported.\n");
+ return -ENOSYS;
+}
#endif
int parse_line_range_desc(const char *arg, struct line_range *lr)
@@ -1087,7 +1193,7 @@ error:
}
static int convert_to_perf_probe_event(struct probe_trace_event *tev,
- struct perf_probe_event *pev)
+ struct perf_probe_event *pev)
{
char buf[64] = "";
int i, ret;
@@ -1516,14 +1622,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
static int convert_to_probe_trace_events(struct perf_probe_event *pev,
struct probe_trace_event **tevs,
- int max_tevs)
+ int max_tevs, const char *module)
{
struct symbol *sym;
int ret = 0, i;
struct probe_trace_event *tev;
/* Convert perf_probe_event with debuginfo */
- ret = try_to_find_probe_trace_events(pev, tevs, max_tevs);
+ ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);
if (ret != 0)
return ret;
@@ -1572,8 +1678,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
}
/* Currently just checking function name from symbol map */
- sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
- tev->point.symbol, NULL);
+ sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
if (!sym) {
pr_warning("Kernel symbol \'%s\' not found.\n",
tev->point.symbol);
@@ -1596,7 +1701,7 @@ struct __event_package {
};
int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
- bool force_add, int max_tevs)
+ int max_tevs, const char *module, bool force_add)
{
int i, j, ret;
struct __event_package *pkgs;
@@ -1617,7 +1722,9 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
pkgs[i].pev = &pevs[i];
/* Convert with or without debuginfo */
ret = convert_to_probe_trace_events(pkgs[i].pev,
- &pkgs[i].tevs, max_tevs);
+ &pkgs[i].tevs,
+ max_tevs,
+ module);
if (ret < 0)
goto end;
pkgs[i].ntevs = ret;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 5af39243a25b..5accbedfea37 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -90,6 +90,12 @@ struct line_range {
struct list_head line_list; /* Visible lines */
};
+/* List of variables */
+struct variable_list {
+ struct probe_trace_point point; /* Actual probepoint */
+ struct strlist *vars; /* Available variables */
+};
+
/* Command string to events */
extern int parse_perf_probe_command(const char *cmd,
struct perf_probe_event *pev);
@@ -109,12 +115,18 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev);
/* Command string to line-range */
extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
+/* Internal use: Return kernel/module path */
+extern const char *kernel_get_module_path(const char *module);
extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
- bool force_add, int max_probe_points);
+ int max_probe_points, const char *module,
+ bool force_add);
extern int del_perf_probe_events(struct strlist *dellist);
extern int show_perf_probe_events(void);
-extern int show_line_range(struct line_range *lr);
+extern int show_line_range(struct line_range *lr, const char *module);
+extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
+ int max_probe_points, const char *module,
+ bool externs);
/* Maximum index number of event-name postfix */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 32b81f707ff5..3991d73d1cff 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -116,6 +116,101 @@ static void line_list__free(struct list_head *head)
}
}
+/* Dwarf FL wrappers */
+
+static int __linux_kernel_find_elf(Dwfl_Module *mod,
+ void **userdata,
+ const char *module_name,
+ Dwarf_Addr base,
+ char **file_name, Elf **elfp)
+{
+ int fd;
+ const char *path = kernel_get_module_path(module_name);
+
+ if (path) {
+ fd = open(path, O_RDONLY);
+ if (fd >= 0) {
+ *file_name = strdup(path);
+ return fd;
+ }
+ }
+ /* If failed, try to call standard method */
+ return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
+ file_name, elfp);
+}
+
+static char *debuginfo_path; /* Currently dummy */
+
+static const Dwfl_Callbacks offline_callbacks = {
+ .find_debuginfo = dwfl_standard_find_debuginfo,
+ .debuginfo_path = &debuginfo_path,
+
+ .section_address = dwfl_offline_section_address,
+
+ /* We use this table for core files too. */
+ .find_elf = dwfl_build_id_find_elf,
+};
+
+static const Dwfl_Callbacks kernel_callbacks = {
+ .find_debuginfo = dwfl_standard_find_debuginfo,
+ .debuginfo_path = &debuginfo_path,
+
+ .find_elf = __linux_kernel_find_elf,
+ .section_address = dwfl_linux_kernel_module_section_address,
+};
+
+/* Get a Dwarf from offline image */
+static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias)
+{
+ Dwfl_Module *mod;
+ Dwarf *dbg = NULL;
+
+ if (!dwflp)
+ return NULL;
+
+ *dwflp = dwfl_begin(&offline_callbacks);
+ if (!*dwflp)
+ return NULL;
+
+ mod = dwfl_report_offline(*dwflp, "", "", fd);
+ if (!mod)
+ goto error;
+
+ dbg = dwfl_module_getdwarf(mod, bias);
+ if (!dbg) {
+error:
+ dwfl_end(*dwflp);
+ *dwflp = NULL;
+ }
+ return dbg;
+}
+
+/* Get a Dwarf from live kernel image */
+static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,
+ Dwarf_Addr *bias)
+{
+ Dwarf *dbg;
+
+ if (!dwflp)
+ return NULL;
+
+ *dwflp = dwfl_begin(&kernel_callbacks);
+ if (!*dwflp)
+ return NULL;
+
+ /* Load the kernel dwarves: Don't care the result here */
+ dwfl_linux_kernel_report_kernel(*dwflp);
+ dwfl_linux_kernel_report_modules(*dwflp);
+
+ dbg = dwfl_addrdwarf(*dwflp, addr, bias);
+ /* Here, check whether we could get a real dwarf */
+ if (!dbg) {
+ dwfl_end(*dwflp);
+ *dwflp = NULL;
+ }
+ return dbg;
+}
+
/* Dwarf wrappers */
/* Find the realpath of the target file. */
@@ -160,26 +255,44 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
return name ? (strcmp(tname, name) == 0) : false;
}
-/* Get type die, but skip qualifiers and typedef */
-static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
+/* Get type die */
+static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
{
Dwarf_Attribute attr;
+
+ if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
+ dwarf_formref_die(&attr, die_mem))
+ return die_mem;
+ else
+ return NULL;
+}
+
+/* Get a type die, but skip qualifiers */
+static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
+{
int tag;
do {
- if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL ||
- dwarf_formref_die(&attr, die_mem) == NULL)
- return NULL;
-
- tag = dwarf_tag(die_mem);
- vr_die = die_mem;
+ vr_die = die_get_type(vr_die, die_mem);
+ if (!vr_die)
+ break;
+ tag = dwarf_tag(vr_die);
} while (tag == DW_TAG_const_type ||
tag == DW_TAG_restrict_type ||
tag == DW_TAG_volatile_type ||
- tag == DW_TAG_shared_type ||
- tag == DW_TAG_typedef);
+ tag == DW_TAG_shared_type);
+
+ return vr_die;
+}
- return die_mem;
+/* Get a type die, but skip qualifiers and typedef */
+static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
+{
+ do {
+ vr_die = __die_get_real_type(vr_die, die_mem);
+ } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
+
+ return vr_die;
}
static bool die_is_signed_type(Dwarf_Die *tp_die)
@@ -320,25 +433,35 @@ static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
}
+struct __find_variable_param {
+ const char *name;
+ Dwarf_Addr addr;
+};
+
static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
{
- const char *name = data;
+ struct __find_variable_param *fvp = data;
int tag;
tag = dwarf_tag(die_mem);
if ((tag == DW_TAG_formal_parameter ||
tag == DW_TAG_variable) &&
- die_compare_name(die_mem, name))
+ die_compare_name(die_mem, fvp->name))
return DIE_FIND_CB_FOUND;
- return DIE_FIND_CB_CONTINUE;
+ if (dwarf_haspc(die_mem, fvp->addr))
+ return DIE_FIND_CB_CONTINUE;
+ else
+ return DIE_FIND_CB_SIBLING;
}
-/* Find a variable called 'name' */
-static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
- Dwarf_Die *die_mem)
+/* Find a variable called 'name' at given address */
+static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
+ Dwarf_Addr addr, Dwarf_Die *die_mem)
{
- return die_find_child(sp_die, __die_find_variable_cb, (void *)name,
+ struct __find_variable_param fvp = { .name = name, .addr = addr};
+
+ return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
die_mem);
}
@@ -361,6 +484,60 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
die_mem);
}
+/* Get the name of given variable DIE */
+static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
+{
+ Dwarf_Die type;
+ int tag, ret, ret2;
+ const char *tmp = "";
+
+ if (__die_get_real_type(vr_die, &type) == NULL)
+ return -ENOENT;
+
+ tag = dwarf_tag(&type);
+ if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
+ tmp = "*";
+ else if (tag == DW_TAG_subroutine_type) {
+ /* Function pointer */
+ ret = snprintf(buf, len, "(function_type)");
+ return (ret >= len) ? -E2BIG : ret;
+ } else {
+ if (!dwarf_diename(&type))
+ return -ENOENT;
+ if (tag == DW_TAG_union_type)
+ tmp = "union ";
+ else if (tag == DW_TAG_structure_type)
+ tmp = "struct ";
+ /* Write a base name */
+ ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
+ return (ret >= len) ? -E2BIG : ret;
+ }
+ ret = die_get_typename(&type, buf, len);
+ if (ret > 0) {
+ ret2 = snprintf(buf + ret, len - ret, "%s", tmp);
+ ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
+ }
+ return ret;
+}
+
+/* Get the name and type of given variable DIE, stored as "type\tname" */
+static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)
+{
+ int ret, ret2;
+
+ ret = die_get_typename(vr_die, buf, len);
+ if (ret < 0) {
+ pr_debug("Failed to get type, make it unknown.\n");
+ ret = snprintf(buf, len, "(unknown_type)");
+ }
+ if (ret > 0) {
+ ret2 = snprintf(buf + ret, len - ret, "\t%s",
+ dwarf_diename(vr_die));
+ ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
+ }
+ return ret;
+}
+
/*
* Probe finder related functions
*/
@@ -374,8 +551,13 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
return ref;
}
-/* Show a location */
-static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
+/*
+ * Convert a location into trace_arg.
+ * If tvar == NULL, this just checks variable can be converted.
+ */
+static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
+ Dwarf_Op *fb_ops,
+ struct probe_trace_arg *tvar)
{
Dwarf_Attribute attr;
Dwarf_Op *op;
@@ -384,20 +566,23 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
Dwarf_Word offs = 0;
bool ref = false;
const char *regs;
- struct probe_trace_arg *tvar = pf->tvar;
int ret;
+ if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
+ goto static_var;
+
/* TODO: handle more than 1 exprs */
if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
- dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 ||
+ dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 ||
nops == 0) {
/* TODO: Support const_value */
- pr_err("Failed to find the location of %s at this address.\n"
- " Perhaps, it has been optimized out.\n", pf->pvar->var);
return -ENOENT;
}
if (op->atom == DW_OP_addr) {
+static_var:
+ if (!tvar)
+ return 0;
/* Static variables on memory (not stack), make @varname */
ret = strlen(dwarf_diename(vr_die));
tvar->value = zalloc(ret + 2);
@@ -412,14 +597,11 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
/* If this is based on frame buffer, set the offset */
if (op->atom == DW_OP_fbreg) {
- if (pf->fb_ops == NULL) {
- pr_warning("The attribute of frame base is not "
- "supported.\n");
+ if (fb_ops == NULL)
return -ENOTSUP;
- }
ref = true;
offs = op->number;
- op = &pf->fb_ops[0];
+ op = &fb_ops[0];
}
if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
@@ -435,13 +617,18 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
} else if (op->atom == DW_OP_regx) {
regn = op->number;
} else {
- pr_warning("DW_OP %x is not supported.\n", op->atom);
+ pr_debug("DW_OP %x is not supported.\n", op->atom);
return -ENOTSUP;
}
+ if (!tvar)
+ return 0;
+
regs = get_arch_regstr(regn);
if (!regs) {
- pr_warning("Mapping for DWARF register number %u missing on this architecture.", regn);
+ /* This should be a bug in DWARF or this tool */
+ pr_warning("Mapping for DWARF register number %u "
+ "missing on this architecture.", regn);
return -ERANGE;
}
@@ -666,8 +853,14 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
pr_debug("Converting variable %s into trace event.\n",
dwarf_diename(vr_die));
- ret = convert_variable_location(vr_die, pf);
- if (ret == 0 && pf->pvar->field) {
+ ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
+ pf->tvar);
+ if (ret == -ENOENT)
+ pr_err("Failed to find the location of %s at this address.\n"
+ " Perhaps, it has been optimized out.\n", pf->pvar->var);
+ else if (ret == -ENOTSUP)
+ pr_err("Sorry, we don't support this variable location yet.\n");
+ else if (pf->pvar->field) {
ret = convert_variable_fields(vr_die, pf->pvar->var,
pf->pvar->field, &pf->tvar->ref,
&die_mem);
@@ -722,56 +915,39 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
pr_debug("Searching '%s' variable in context.\n",
pf->pvar->var);
/* Search child die for local variables and parameters. */
- if (die_find_variable(sp_die, pf->pvar->var, &vr_die))
+ if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die))
ret = convert_variable(&vr_die, pf);
else {
/* Search upper class */
nscopes = dwarf_getscopes_die(sp_die, &scopes);
- if (nscopes > 0) {
- ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var,
- 0, NULL, 0, 0, &vr_die);
- if (ret >= 0)
+ while (nscopes-- > 1) {
+ pr_debug("Searching variables in %s\n",
+ dwarf_diename(&scopes[nscopes]));
+ /* We should check this scope, so give dummy address */
+ if (die_find_variable_at(&scopes[nscopes],
+ pf->pvar->var, 0,
+ &vr_die)) {
ret = convert_variable(&vr_die, pf);
- else
- ret = -ENOENT;
+ goto found;
+ }
+ }
+ if (scopes)
free(scopes);
- } else
- ret = -ENOENT;
+ ret = -ENOENT;
}
+found:
if (ret < 0)
pr_warning("Failed to find '%s' in this function.\n",
pf->pvar->var);
return ret;
}
-/* Show a probe point to output buffer */
-static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
+/* Convert subprogram DIE to trace point */
+static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
+ bool retprobe, struct probe_trace_point *tp)
{
- struct probe_trace_event *tev;
Dwarf_Addr eaddr;
- Dwarf_Die die_mem;
const char *name;
- int ret, i;
- Dwarf_Attribute fb_attr;
- size_t nops;
-
- if (pf->ntevs == pf->max_tevs) {
- pr_warning("Too many( > %d) probe point found.\n",
- pf->max_tevs);
- return -ERANGE;
- }
- tev = &pf->tevs[pf->ntevs++];
-
- /* If no real subprogram, find a real one */
- if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
- sp_die = die_find_real_subprogram(&pf->cu_die,
- pf->addr, &die_mem);
- if (!sp_die) {
- pr_warning("Failed to find probe point in any "
- "functions.\n");
- return -ENOENT;
- }
- }
/* Copy the name of probe point */
name = dwarf_diename(sp_die);
@@ -781,26 +957,45 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
dwarf_diename(sp_die));
return -ENOENT;
}
- tev->point.symbol = strdup(name);
- if (tev->point.symbol == NULL)
+ tp->symbol = strdup(name);
+ if (tp->symbol == NULL)
return -ENOMEM;
- tev->point.offset = (unsigned long)(pf->addr - eaddr);
+ tp->offset = (unsigned long)(paddr - eaddr);
} else
/* This function has no name. */
- tev->point.offset = (unsigned long)pf->addr;
+ tp->offset = (unsigned long)paddr;
/* Return probe must be on the head of a subprogram */
- if (pf->pev->point.retprobe) {
- if (tev->point.offset != 0) {
+ if (retprobe) {
+ if (eaddr != paddr) {
pr_warning("Return probe must be on the head of"
" a real function\n");
return -EINVAL;
}
- tev->point.retprobe = true;
+ tp->retprobe = true;
}
- pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
- tev->point.offset);
+ return 0;
+}
+
+/* Call probe_finder callback with real subprogram DIE */
+static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
+{
+ Dwarf_Die die_mem;
+ Dwarf_Attribute fb_attr;
+ size_t nops;
+ int ret;
+
+ /* If no real subprogram, find a real one */
+ if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
+ sp_die = die_find_real_subprogram(&pf->cu_die,
+ pf->addr, &die_mem);
+ if (!sp_die) {
+ pr_warning("Failed to find probe point in any "
+ "functions.\n");
+ return -ENOENT;
+ }
+ }
/* Get the frame base attribute/ops */
dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
@@ -820,22 +1015,13 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
#endif
}
- /* Find each argument */
- tev->nargs = pf->pev->nargs;
- tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
- if (tev->args == NULL)
- return -ENOMEM;
- for (i = 0; i < pf->pev->nargs; i++) {
- pf->pvar = &pf->pev->args[i];
- pf->tvar = &tev->args[i];
- ret = find_variable(sp_die, pf);
- if (ret != 0)
- return ret;
- }
+ /* Call finder's callback handler */
+ ret = pf->callback(sp_die, pf);
/* *pf->fb_ops will be cached in libdw. Don't free it. */
pf->fb_ops = NULL;
- return 0;
+
+ return ret;
}
/* Find probe point from its line number */
@@ -871,7 +1057,7 @@ static int find_probe_point_by_line(struct probe_finder *pf)
(int)i, lineno, (uintmax_t)addr);
pf->addr = addr;
- ret = convert_probe_point(NULL, pf);
+ ret = call_probe_finder(NULL, pf);
/* Continuing, because target line might be inlined. */
}
return ret;
@@ -984,7 +1170,7 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
(int)i, lineno, (unsigned long long)addr);
pf->addr = addr;
- ret = convert_probe_point(sp_die, pf);
+ ret = call_probe_finder(sp_die, pf);
/* Continuing, because target line might be inlined. */
}
/* TODO: deallocate lines, but how? */
@@ -1019,7 +1205,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
pr_debug("found inline addr: 0x%jx\n",
(uintmax_t)pf->addr);
- param->retval = convert_probe_point(in_die, pf);
+ param->retval = call_probe_finder(in_die, pf);
if (param->retval < 0)
return DWARF_CB_ABORT;
}
@@ -1057,7 +1243,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
}
pf->addr += pp->offset;
/* TODO: Check the address in this function */
- param->retval = convert_probe_point(sp_die, pf);
+ param->retval = call_probe_finder(sp_die, pf);
}
} else {
struct dwarf_callback_param _param = {.data = (void *)pf,
@@ -1079,90 +1265,276 @@ static int find_probe_point_by_func(struct probe_finder *pf)
return _param.retval;
}
-/* Find probe_trace_events specified by perf_probe_event from debuginfo */
-int find_probe_trace_events(int fd, struct perf_probe_event *pev,
- struct probe_trace_event **tevs, int max_tevs)
+/* Find probe points from debuginfo */
+static int find_probes(int fd, struct probe_finder *pf)
{
- struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs};
- struct perf_probe_point *pp = &pev->point;
+ struct perf_probe_point *pp = &pf->pev->point;
Dwarf_Off off, noff;
size_t cuhl;
Dwarf_Die *diep;
- Dwarf *dbg;
+ Dwarf *dbg = NULL;
+ Dwfl *dwfl;
+ Dwarf_Addr bias; /* Currently ignored */
int ret = 0;
- pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
- if (pf.tevs == NULL)
- return -ENOMEM;
- *tevs = pf.tevs;
- pf.ntevs = 0;
-
- dbg = dwarf_begin(fd, DWARF_C_READ);
+ dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
if (!dbg) {
pr_warning("No dwarf info found in the vmlinux - "
"please rebuild with CONFIG_DEBUG_INFO=y.\n");
- free(pf.tevs);
- *tevs = NULL;
return -EBADF;
}
#if _ELFUTILS_PREREQ(0, 142)
/* Get the call frame information from this dwarf */
- pf.cfi = dwarf_getcfi(dbg);
+ pf->cfi = dwarf_getcfi(dbg);
#endif
off = 0;
- line_list__init(&pf.lcache);
+ line_list__init(&pf->lcache);
/* Loop on CUs (Compilation Unit) */
while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) &&
ret >= 0) {
/* Get the DIE(Debugging Information Entry) of this CU */
- diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
+ diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);
if (!diep)
continue;
/* Check if target file is included. */
if (pp->file)
- pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
+ pf->fname = cu_find_realpath(&pf->cu_die, pp->file);
else
- pf.fname = NULL;
+ pf->fname = NULL;
- if (!pp->file || pf.fname) {
+ if (!pp->file || pf->fname) {
if (pp->function)
- ret = find_probe_point_by_func(&pf);
+ ret = find_probe_point_by_func(pf);
else if (pp->lazy_line)
- ret = find_probe_point_lazy(NULL, &pf);
+ ret = find_probe_point_lazy(NULL, pf);
else {
- pf.lno = pp->line;
- ret = find_probe_point_by_line(&pf);
+ pf->lno = pp->line;
+ ret = find_probe_point_by_line(pf);
}
}
off = noff;
}
- line_list__free(&pf.lcache);
- dwarf_end(dbg);
+ line_list__free(&pf->lcache);
+ if (dwfl)
+ dwfl_end(dwfl);
- return (ret < 0) ? ret : pf.ntevs;
+ return ret;
+}
+
+/* Add a found probe point into trace event list */
+static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
+{
+ struct trace_event_finder *tf =
+ container_of(pf, struct trace_event_finder, pf);
+ struct probe_trace_event *tev;
+ int ret, i;
+
+ /* Check number of tevs */
+ if (tf->ntevs == tf->max_tevs) {
+ pr_warning("Too many( > %d) probe point found.\n",
+ tf->max_tevs);
+ return -ERANGE;
+ }
+ tev = &tf->tevs[tf->ntevs++];
+
+ ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
+ &tev->point);
+ if (ret < 0)
+ return ret;
+
+ pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
+ tev->point.offset);
+
+ /* Find each argument */
+ tev->nargs = pf->pev->nargs;
+ tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
+ if (tev->args == NULL)
+ return -ENOMEM;
+ for (i = 0; i < pf->pev->nargs; i++) {
+ pf->pvar = &pf->pev->args[i];
+ pf->tvar = &tev->args[i];
+ ret = find_variable(sp_die, pf);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Find probe_trace_events specified by perf_probe_event from debuginfo */
+int find_probe_trace_events(int fd, struct perf_probe_event *pev,
+ struct probe_trace_event **tevs, int max_tevs)
+{
+ struct trace_event_finder tf = {
+ .pf = {.pev = pev, .callback = add_probe_trace_event},
+ .max_tevs = max_tevs};
+ int ret;
+
+ /* Allocate result tevs array */
+ *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
+ if (*tevs == NULL)
+ return -ENOMEM;
+
+ tf.tevs = *tevs;
+ tf.ntevs = 0;
+
+ ret = find_probes(fd, &tf.pf);
+ if (ret < 0) {
+ free(*tevs);
+ *tevs = NULL;
+ return ret;
+ }
+
+ return (ret < 0) ? ret : tf.ntevs;
+}
+
+#define MAX_VAR_LEN 64
+
+/* Collect available variables in this scope */
+static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
+{
+ struct available_var_finder *af = data;
+ struct variable_list *vl;
+ char buf[MAX_VAR_LEN];
+ int tag, ret;
+
+ vl = &af->vls[af->nvls - 1];
+
+ tag = dwarf_tag(die_mem);
+ if (tag == DW_TAG_formal_parameter ||
+ tag == DW_TAG_variable) {
+ ret = convert_variable_location(die_mem, af->pf.addr,
+ af->pf.fb_ops, NULL);
+ if (ret == 0) {
+ ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
+ pr_debug2("Add new var: %s\n", buf);
+ if (ret > 0)
+ strlist__add(vl->vars, buf);
+ }
+ }
+
+ if (af->child && dwarf_haspc(die_mem, af->pf.addr))
+ return DIE_FIND_CB_CONTINUE;
+ else
+ return DIE_FIND_CB_SIBLING;
+}
+
+/* Add a found vars into available variables list */
+static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
+{
+ struct available_var_finder *af =
+ container_of(pf, struct available_var_finder, pf);
+ struct variable_list *vl;
+ Dwarf_Die die_mem, *scopes = NULL;
+ int ret, nscopes;
+
+ /* Check number of tevs */
+ if (af->nvls == af->max_vls) {
+ pr_warning("Too many( > %d) probe point found.\n", af->max_vls);
+ return -ERANGE;
+ }
+ vl = &af->vls[af->nvls++];
+
+ ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
+ &vl->point);
+ if (ret < 0)
+ return ret;
+
+ pr_debug("Probe point found: %s+%lu\n", vl->point.symbol,
+ vl->point.offset);
+
+ /* Find local variables */
+ vl->vars = strlist__new(true, NULL);
+ if (vl->vars == NULL)
+ return -ENOMEM;
+ af->child = true;
+ die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem);
+
+ /* Find external variables */
+ if (!af->externs)
+ goto out;
+ /* Don't need to search child DIE for externs. */
+ af->child = false;
+ nscopes = dwarf_getscopes_die(sp_die, &scopes);
+ while (nscopes-- > 1)
+ die_find_child(&scopes[nscopes], collect_variables_cb,
+ (void *)af, &die_mem);
+ if (scopes)
+ free(scopes);
+
+out:
+ if (strlist__empty(vl->vars)) {
+ strlist__delete(vl->vars);
+ vl->vars = NULL;
+ }
+
+ return ret;
+}
+
+/* Find available variables at given probe point */
+int find_available_vars_at(int fd, struct perf_probe_event *pev,
+ struct variable_list **vls, int max_vls,
+ bool externs)
+{
+ struct available_var_finder af = {
+ .pf = {.pev = pev, .callback = add_available_vars},
+ .max_vls = max_vls, .externs = externs};
+ int ret;
+
+ /* Allocate result vls array */
+ *vls = zalloc(sizeof(struct variable_list) * max_vls);
+ if (*vls == NULL)
+ return -ENOMEM;
+
+ af.vls = *vls;
+ af.nvls = 0;
+
+ ret = find_probes(fd, &af.pf);
+ if (ret < 0) {
+ /* Free vlist for error */
+ while (af.nvls--) {
+ if (af.vls[af.nvls].point.symbol)
+ free(af.vls[af.nvls].point.symbol);
+ if (af.vls[af.nvls].vars)
+ strlist__delete(af.vls[af.nvls].vars);
+ }
+ free(af.vls);
+ *vls = NULL;
+ return ret;
+ }
+
+ return (ret < 0) ? ret : af.nvls;
}
/* Reverse search */
-int find_perf_probe_point(int fd, unsigned long addr,
- struct perf_probe_point *ppt)
+int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
{
Dwarf_Die cudie, spdie, indie;
- Dwarf *dbg;
+ Dwarf *dbg = NULL;
+ Dwfl *dwfl = NULL;
Dwarf_Line *line;
- Dwarf_Addr laddr, eaddr;
+ Dwarf_Addr laddr, eaddr, bias = 0;
const char *tmp;
int lineno, ret = 0;
bool found = false;
- dbg = dwarf_begin(fd, DWARF_C_READ);
- if (!dbg)
- return -EBADF;
+ /* Open the live linux kernel */
+ dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
+ if (!dbg) {
+ pr_warning("No dwarf info found in the vmlinux - "
+ "please rebuild with CONFIG_DEBUG_INFO=y.\n");
+ ret = -EINVAL;
+ goto end;
+ }
+ /* Adjust address with bias */
+ addr += bias;
/* Find cu die */
- if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) {
+ if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) {
+ pr_warning("No CU DIE is found at %lx\n", addr);
ret = -EINVAL;
goto end;
}
@@ -1225,7 +1597,8 @@ found:
}
end:
- dwarf_end(dbg);
+ if (dwfl)
+ dwfl_end(dwfl);
if (ret >= 0)
ret = found ? 1 : 0;
return ret;
@@ -1358,6 +1731,9 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
struct line_finder *lf = param->data;
struct line_range *lr = lf->lr;
+ pr_debug("find (%llx) %s\n",
+ (unsigned long long)dwarf_dieoffset(sp_die),
+ dwarf_diename(sp_die));
if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
die_compare_name(sp_die, lr->function)) {
lf->fname = dwarf_decl_file(sp_die);
@@ -1401,10 +1777,12 @@ int find_line_range(int fd, struct line_range *lr)
Dwarf_Off off = 0, noff;
size_t cuhl;
Dwarf_Die *diep;
- Dwarf *dbg;
+ Dwarf *dbg = NULL;
+ Dwfl *dwfl;
+ Dwarf_Addr bias; /* Currently ignored */
const char *comp_dir;
- dbg = dwarf_begin(fd, DWARF_C_READ);
+ dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
if (!dbg) {
pr_warning("No dwarf info found in the vmlinux - "
"please rebuild with CONFIG_DEBUG_INFO=y.\n");
@@ -1450,8 +1828,7 @@ int find_line_range(int fd, struct line_range *lr)
}
pr_debug("path: %s\n", lr->path);
- dwarf_end(dbg);
-
+ dwfl_end(dwfl);
return (ret < 0) ? ret : lf.found;
}
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 4507d519f183..bba69d455699 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -22,20 +22,27 @@ extern int find_probe_trace_events(int fd, struct perf_probe_event *pev,
int max_tevs);
/* Find a perf_probe_point from debuginfo */
-extern int find_perf_probe_point(int fd, unsigned long addr,
+extern int find_perf_probe_point(unsigned long addr,
struct perf_probe_point *ppt);
+/* Find a line range */
extern int find_line_range(int fd, struct line_range *lr);
+/* Find available variables */
+extern int find_available_vars_at(int fd, struct perf_probe_event *pev,
+ struct variable_list **vls, int max_points,
+ bool externs);
+
#include <dwarf.h>
#include <libdw.h>
+#include <libdwfl.h>
#include <version.h>
struct probe_finder {
struct perf_probe_event *pev; /* Target probe event */
- struct probe_trace_event *tevs; /* Result trace events */
- int ntevs; /* Number of trace events */
- int max_tevs; /* Max number of trace events */
+
+ /* Callback when a probe point is found */
+ int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf);
/* For function searching */
int lno; /* Line number */
@@ -53,6 +60,22 @@ struct probe_finder {
struct probe_trace_arg *tvar; /* Current result variable */
};
+struct trace_event_finder {
+ struct probe_finder pf;
+ struct probe_trace_event *tevs; /* Found trace events */
+ int ntevs; /* Number of trace events */
+ int max_tevs; /* Max number of trace events */
+};
+
+struct available_var_finder {
+ struct probe_finder pf;
+ struct variable_list *vls; /* Found variable lists */
+ int nvls; /* Number of variable lists */
+ int max_vls; /* Max no. of variable lists */
+ bool externs; /* Find external vars too */
+ bool child; /* Search child scopes */
+};
+
struct line_finder {
struct line_range *lr; /* Target line range */
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c
index 6d0df809a2ed..8bc010edca25 100644
--- a/tools/perf/util/ui/browser.c
+++ b/tools/perf/util/ui/browser.c
@@ -1,4 +1,3 @@
-#include <slang.h>
#include "libslang.h"
#include <linux/compiler.h>
#include <linux/list.h>
diff --git a/usr/Kconfig b/usr/Kconfig
index e2721f5a3504..c2c7fe2f717d 100644
--- a/usr/Kconfig
+++ b/usr/Kconfig
@@ -144,7 +144,7 @@ config INITRAMFS_COMPRESSION_LZO
depends on RD_LZO
help
Its compression ratio is the poorest among the four. The kernel
- size is about about 10% bigger than gzip; however its speed
+ size is about 10% bigger than gzip; however its speed
(both compression and decompression) is the fastest.
endchoice
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index 369e38010ad5..8edca9141b78 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -17,7 +17,7 @@
* Authors:
* Yaozu (Eddie) Dong <Eddie.dong@intel.com>
*
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
*/
#include <linux/kvm_host.h>
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 60e5e4612b0b..5225052aebc1 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -5,7 +5,7 @@
* machines without emulation or binary translation.
*
* Copyright (C) 2006 Qumranet, Inc.
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
*
* Authors:
* Avi Kivity <avi@qumranet.com>
@@ -705,14 +705,12 @@ skip_lpage:
if (r)
goto out_free;
-#ifdef CONFIG_DMAR
/* map the pages in iommu page table */
if (npages) {
r = kvm_iommu_map_pages(kvm, &new);
if (r)
goto out_free;
}
-#endif
r = -ENOMEM;
slots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
@@ -927,35 +925,46 @@ int memslot_id(struct kvm *kvm, gfn_t gfn)
return memslot - slots->memslots;
}
-static unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, gfn_t gfn)
-{
- return slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE;
-}
-
-unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
+static unsigned long gfn_to_hva_many(struct kvm *kvm, gfn_t gfn,
+ gfn_t *nr_pages)
{
struct kvm_memory_slot *slot;
slot = gfn_to_memslot(kvm, gfn);
if (!slot || slot->flags & KVM_MEMSLOT_INVALID)
return bad_hva();
+
+ if (nr_pages)
+ *nr_pages = slot->npages - (gfn - slot->base_gfn);
+
return gfn_to_hva_memslot(slot, gfn);
}
+
+unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
+{
+ return gfn_to_hva_many(kvm, gfn, NULL);
+}
EXPORT_SYMBOL_GPL(gfn_to_hva);
-static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr)
+static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr, bool atomic)
{
struct page *page[1];
int npages;
pfn_t pfn;
- might_sleep();
-
- npages = get_user_pages_fast(addr, 1, 1, page);
+ if (atomic)
+ npages = __get_user_pages_fast(addr, 1, 1, page);
+ else {
+ might_sleep();
+ npages = get_user_pages_fast(addr, 1, 1, page);
+ }
if (unlikely(npages != 1)) {
struct vm_area_struct *vma;
+ if (atomic)
+ goto return_fault_page;
+
down_read(&current->mm->mmap_sem);
if (is_hwpoison_address(addr)) {
up_read(&current->mm->mmap_sem);
@@ -968,6 +977,7 @@ static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr)
if (vma == NULL || addr < vma->vm_start ||
!(vma->vm_flags & VM_PFNMAP)) {
up_read(&current->mm->mmap_sem);
+return_fault_page:
get_page(fault_page);
return page_to_pfn(fault_page);
}
@@ -981,7 +991,13 @@ static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr)
return pfn;
}
-pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn)
+pfn_t hva_to_pfn_atomic(struct kvm *kvm, unsigned long addr)
+{
+ return hva_to_pfn(kvm, addr, true);
+}
+EXPORT_SYMBOL_GPL(hva_to_pfn_atomic);
+
+static pfn_t __gfn_to_pfn(struct kvm *kvm, gfn_t gfn, bool atomic)
{
unsigned long addr;
@@ -991,7 +1007,18 @@ pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn)
return page_to_pfn(bad_page);
}
- return hva_to_pfn(kvm, addr);
+ return hva_to_pfn(kvm, addr, atomic);
+}
+
+pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn)
+{
+ return __gfn_to_pfn(kvm, gfn, true);
+}
+EXPORT_SYMBOL_GPL(gfn_to_pfn_atomic);
+
+pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn)
+{
+ return __gfn_to_pfn(kvm, gfn, false);
}
EXPORT_SYMBOL_GPL(gfn_to_pfn);
@@ -999,9 +1026,26 @@ pfn_t gfn_to_pfn_memslot(struct kvm *kvm,
struct kvm_memory_slot *slot, gfn_t gfn)
{
unsigned long addr = gfn_to_hva_memslot(slot, gfn);
- return hva_to_pfn(kvm, addr);
+ return hva_to_pfn(kvm, addr, false);
}
+int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages,
+ int nr_pages)
+{
+ unsigned long addr;
+ gfn_t entry;
+
+ addr = gfn_to_hva_many(kvm, gfn, &entry);
+ if (kvm_is_error_hva(addr))
+ return -1;
+
+ if (entry < nr_pages)
+ return 0;
+
+ return __get_user_pages_fast(addr, nr_pages, 1, pages);
+}
+EXPORT_SYMBOL_GPL(gfn_to_page_many_atomic);
+
struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
{
pfn_t pfn;
@@ -1964,7 +2008,9 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
case CPU_STARTING:
printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n",
cpu);
+ spin_lock(&kvm_lock);
hardware_enable(NULL);
+ spin_unlock(&kvm_lock);
break;
}
return NOTIFY_OK;
@@ -1977,7 +2023,7 @@ asmlinkage void kvm_handle_fault_on_reboot(void)
/* spin while reset goes on */
local_irq_enable();
while (true)
- ;
+ cpu_relax();
}
/* Fault while not rebooting. We want the trace. */
BUG();
@@ -2171,8 +2217,10 @@ static int kvm_suspend(struct sys_device *dev, pm_message_t state)
static int kvm_resume(struct sys_device *dev)
{
- if (kvm_usage_count)
+ if (kvm_usage_count) {
+ WARN_ON(spin_is_locked(&kvm_lock));
hardware_enable(NULL);
+ }
return 0;
}